summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format87
-rw-r--r--.gitignore43
-rw-r--r--.travis.yml57
-rw-r--r--.ycm_extra_conf.py118
-rw-r--r--CMakeLists.txt136
-rw-r--r--ChangeLog175
-rw-r--r--Dockerfile5
-rw-r--r--GNUmakefile1292
-rw-r--r--GPL879
-rw-r--r--Makefile2925
-rw-r--r--README.md165
-rw-r--r--assets/armour/bsuit.armour19
-rw-r--r--assets/armour/helmet.armour19
-rw-r--r--assets/armour/larmour.armour95
-rw-r--r--assets/configs/buildables/acid_tube.cfg5
-rw-r--r--assets/configs/buildables/arm.cfg5
-rw-r--r--assets/configs/buildables/barricade.cfg5
-rw-r--r--assets/configs/buildables/booster.cfg5
-rw-r--r--assets/configs/buildables/dcc.cfg5
-rw-r--r--assets/configs/buildables/eggpod.cfg5
-rw-r--r--assets/configs/buildables/hive.cfg5
-rw-r--r--assets/configs/buildables/hovel.cfg5
-rw-r--r--assets/configs/buildables/medistat.cfg5
-rw-r--r--assets/configs/buildables/mgturret.cfg7
-rw-r--r--assets/configs/buildables/overmind.cfg5
-rw-r--r--assets/configs/buildables/reactor.cfg5
-rw-r--r--assets/configs/buildables/repeater.cfg5
-rw-r--r--assets/configs/buildables/telenode.cfg5
-rw-r--r--assets/configs/buildables/tesla.cfg5
-rw-r--r--assets/configs/buildables/trapper.cfg5
-rw-r--r--assets/configs/classes/builder.cfg17
-rw-r--r--assets/configs/classes/builderupg.cfg17
-rw-r--r--assets/configs/classes/human_base.cfg17
-rw-r--r--assets/configs/classes/human_bsuit.cfg17
-rw-r--r--assets/configs/classes/level0.cfg17
-rw-r--r--assets/configs/classes/level1.cfg17
-rw-r--r--assets/configs/classes/level1upg.cfg17
-rw-r--r--assets/configs/classes/level2.cfg17
-rw-r--r--assets/configs/classes/level2upg.cfg17
-rw-r--r--assets/configs/classes/level3.cfg17
-rw-r--r--assets/configs/classes/level3upg.cfg17
-rw-r--r--assets/configs/classes/level4.cfg17
-rw-r--r--assets/configs/classes/spectator.cfg17
-rw-r--r--assets/models/buildables/acid_tube/animation.cfg15
-rw-r--r--assets/models/buildables/barricade/animation.cfg17
-rw-r--r--assets/models/buildables/medistat/animation.cfg18
-rw-r--r--assets/models/buildables/mgturret/animation.cfg15
-rw-r--r--assets/models/buildables/repeater/animation.cfg15
-rw-r--r--assets/models/buildables/tesla/animation.cfg15
-rw-r--r--assets/models/generic/sphere.md3bin0 -> 27748 bytes
-rw-r--r--assets/models/generic/sphericalCone240.md3bin0 -> 22012 bytes
-rw-r--r--assets/models/generic/sphericalCone64.md3bin0 -> 38172 bytes
-rw-r--r--assets/models/players/human_base/locdamage.cfg60
-rw-r--r--assets/models/players/human_bsuit/locdamage.cfg29
-rw-r--r--assets/models/players/level1/animation.cfg48
-rw-r--r--assets/models/weapons/abuild/weapon.cfg11
-rw-r--r--assets/models/weapons/abuildupg/weapon.cfg19
-rw-r--r--assets/models/weapons/grenade/weapon.cfg13
-rw-r--r--assets/models/weapons/lcannon/weapon.cfg33
-rw-r--r--assets/models/weapons/level0/weapon.cfg9
-rw-r--r--assets/models/weapons/level1/weapon.cfg11
-rw-r--r--assets/models/weapons/level1upg/weapon.cfg17
-rw-r--r--assets/models/weapons/level2/weapon.cfg11
-rw-r--r--assets/models/weapons/level2upg/weapon.cfg18
-rw-r--r--assets/models/weapons/level3/weapon.cfg16
-rw-r--r--assets/models/weapons/level3upg/weapon.cfg28
-rw-r--r--assets/models/weapons/level4/weapon.cfg11
-rw-r--r--assets/models/weapons/mdriver/weapon.cfg12
-rw-r--r--assets/models/weapons/prifle/weapon.cfg17
-rw-r--r--assets/models/weapons/psaw/weapon.cfg13
-rw-r--r--assets/music/Tremulous Heartbeat.midbin0 -> 1800 bytes
-rw-r--r--assets/scripts/binary.shader16394
-rw-r--r--assets/scripts/core.shader209
-rw-r--r--assets/scripts/crosshairs.shader96
-rw-r--r--assets/scripts/mdriver.trail10
-rw-r--r--assets/scripts/misc.particle378
-rw-r--r--assets/scripts/ui.shader19
-rw-r--r--assets/scripts/weapons.particle890
-rw-r--r--assets/scripts/weapons.shader93
-rw-r--r--assets/sound/buildables/barricade/sound.cfg14
-rw-r--r--assets/ui/assets/alien/buildstat.cfg (renamed from ui/assets/alien/buildstat.cfg)6
-rw-r--r--assets/ui/assets/console1.tgabin0 -> 121118 bytes
-rw-r--r--assets/ui/assets/console2.jpgbin0 -> 36364 bytes
-rw-r--r--assets/ui/assets/human/buildstat.cfg (renamed from ui/assets/human/buildstat.cfg)6
-rw-r--r--assets/ui/connect.menu14
-rw-r--r--assets/ui/createfavorite.menu115
-rw-r--r--assets/ui/createserver.menu499
-rw-r--r--assets/ui/demo.menu108
-rw-r--r--assets/ui/demo_error.menu101
-rw-r--r--assets/ui/download.menu167
-rw-r--r--assets/ui/drop.menu122
-rw-r--r--assets/ui/error.menu102
-rw-r--r--assets/ui/findplayer.menu173
-rw-r--r--assets/ui/folders.menu121
-rw-r--r--assets/ui/help.txt135
-rw-r--r--assets/ui/hud.txt12
-rw-r--r--assets/ui/ingame.menu (renamed from ui/ingame.menu)85
-rw-r--r--assets/ui/ingame.txt (renamed from ui/ingame.txt)5
-rw-r--r--assets/ui/ingame_game.menu862
-rw-r--r--assets/ui/ingame_help.menu88
-rw-r--r--assets/ui/ingame_leave.menu209
-rw-r--r--assets/ui/ingame_options.menu2577
-rw-r--r--assets/ui/install_update.menu145
-rw-r--r--assets/ui/joinserver.menu769
-rw-r--r--assets/ui/loading.menu223
-rw-r--r--assets/ui/main.menu228
-rw-r--r--assets/ui/menu_bool.h10
-rw-r--r--assets/ui/menudef.h225
-rw-r--r--assets/ui/menus.txt24
-rw-r--r--assets/ui/mod.menu108
-rw-r--r--assets/ui/news.menu102
-rw-r--r--assets/ui/options.menu310
-rw-r--r--assets/ui/password.menu85
-rw-r--r--assets/ui/quit.menu99
-rw-r--r--assets/ui/quitcredit.menu (renamed from ui/quitcredit.menu)172
-rw-r--r--assets/ui/say.menu180
-rw-r--r--assets/ui/serverinfo.menu112
-rw-r--r--assets/ui/teamscore.menu386
-rw-r--r--assets/ui/tremulous.txt (renamed from ui/tremulous.txt)17
-rw-r--r--assets/ui/tremulous_alien_builder_hud.menu42
-rw-r--r--assets/ui/tremulous_alien_common_hud.h257
-rw-r--r--assets/ui/tremulous_alien_general_hud.menu30
-rw-r--r--assets/ui/tremulous_alienbuild.menu136
-rw-r--r--assets/ui/tremulous_alienclass.menu157
-rw-r--r--assets/ui/tremulous_aliendialogs.menu97
-rw-r--r--assets/ui/tremulous_alienupgrade.menu136
-rw-r--r--assets/ui/tremulous_common_hud.h247
-rw-r--r--assets/ui/tremulous_default_hud.menu37
-rw-r--r--assets/ui/tremulous_dialogs.menu98
-rw-r--r--assets/ui/tremulous_human_hud.menu379
-rw-r--r--assets/ui/tremulous_humanarmoury.menu189
-rw-r--r--assets/ui/tremulous_humanbuild.menu135
-rw-r--r--assets/ui/tremulous_humandialogs.menu98
-rw-r--r--assets/ui/tremulous_humanitem.menu157
-rw-r--r--assets/ui/tremulous_spectator_hud.menu52
-rw-r--r--assets/ui/tremulous_teamselect.menu136
-rw-r--r--assets/ui/tremulous_voicecmd.menu140
-rw-r--r--cmake/AddQVM.cmake73
-rw-r--r--cmake/SDL2.cmake13
-rw-r--r--cmake/build_dir17
-rw-r--r--cmake/debug_cflags4
-rw-r--r--code_of_conduct.md71
-rw-r--r--docs/Features.md93
-rw-r--r--docs/LuaScripting.md13
-rw-r--r--docs/ParticleSystem.md160
-rw-r--r--docs/PlayerVars.md15
-rw-r--r--docs/TrailSystem.md44
-rw-r--r--docs/VoiceCommands.md40
-rw-r--r--docs/opengl2-readme.md604
-rw-r--r--external/AL/AL/VERSION5
-rw-r--r--external/AL/AL/al.h656
-rw-r--r--external/AL/AL/alc.h237
-rw-r--r--external/AL/AL/alext.h355
-rw-r--r--external/AL/AL/efx-creative.h3
-rw-r--r--external/AL/AL/efx-presets.h402
-rw-r--r--external/AL/AL/efx.h761
-rw-r--r--external/SDL2/CMakeLists.txt6
-rw-r--r--external/SDL2/include/SDL.h132
-rw-r--r--external/SDL2/include/SDL_assert.h289
-rw-r--r--external/SDL2/include/SDL_atomic.h268
-rw-r--r--external/SDL2/include/SDL_audio.h605
-rw-r--r--external/SDL2/include/SDL_bits.h97
-rw-r--r--external/SDL2/include/SDL_blendmode.h63
-rw-r--r--external/SDL2/include/SDL_clipboard.h71
-rw-r--r--external/SDL2/include/SDL_config.h55
-rw-r--r--external/SDL2/include/SDL_config.h.cmake419
-rw-r--r--external/SDL2/include/SDL_config.h.in359
-rw-r--r--external/SDL2/include/SDL_config_android.h145
-rw-r--r--external/SDL2/include/SDL_config_iphoneos.h162
-rw-r--r--external/SDL2/include/SDL_config_macosx.h188
-rw-r--r--external/SDL2/include/SDL_config_minimal.h81
-rw-r--r--external/SDL2/include/SDL_config_pandora.h127
-rw-r--r--external/SDL2/include/SDL_config_psp.h143
-rw-r--r--external/SDL2/include/SDL_config_windows.h221
-rw-r--r--external/SDL2/include/SDL_config_winrt.h214
-rw-r--r--external/SDL2/include/SDL_config_wiz.h120
-rw-r--r--external/SDL2/include/SDL_copying.h20
-rw-r--r--external/SDL2/include/SDL_cpuinfo.h161
-rw-r--r--external/SDL2/include/SDL_egl.h1673
-rw-r--r--external/SDL2/include/SDL_endian.h239
-rw-r--r--external/SDL2/include/SDL_error.h76
-rw-r--r--external/SDL2/include/SDL_events.h750
-rw-r--r--external/SDL2/include/SDL_filesystem.h136
-rw-r--r--external/SDL2/include/SDL_gamecontroller.h323
-rw-r--r--external/SDL2/include/SDL_gesture.h87
-rw-r--r--external/SDL2/include/SDL_haptic.h1223
-rw-r--r--external/SDL2/include/SDL_hints.h711
-rw-r--r--external/SDL2/include/SDL_joystick.h273
-rw-r--r--external/SDL2/include/SDL_keyboard.h217
-rw-r--r--external/SDL2/include/SDL_keycode.h341
-rw-r--r--external/SDL2/include/SDL_loadso.h81
-rw-r--r--external/SDL2/include/SDL_log.h211
-rw-r--r--external/SDL2/include/SDL_main.h161
-rw-r--r--external/SDL2/include/SDL_messagebox.h144
-rw-r--r--external/SDL2/include/SDL_mouse.h300
-rw-r--r--external/SDL2/include/SDL_mutex.h251
-rw-r--r--external/SDL2/include/SDL_name.h33
-rw-r--r--external/SDL2/include/SDL_opengl.h2176
-rw-r--r--external/SDL2/include/SDL_opengl_glext.h11177
-rw-r--r--external/SDL2/include/SDL_opengles.h38
-rw-r--r--external/SDL2/include/SDL_opengles2.h50
-rw-r--r--external/SDL2/include/SDL_opengles2_gl2.h621
-rw-r--r--external/SDL2/include/SDL_opengles2_gl2ext.h2050
-rw-r--r--external/SDL2/include/SDL_opengles2_gl2platform.h30
-rw-r--r--external/SDL2/include/SDL_opengles2_khrplatform.h282
-rw-r--r--external/SDL2/include/SDL_pixels.h454
-rw-r--r--external/SDL2/include/SDL_platform.h181
-rw-r--r--external/SDL2/include/SDL_power.h75
-rw-r--r--external/SDL2/include/SDL_quit.h58
-rw-r--r--external/SDL2/include/SDL_rect.h148
-rw-r--r--external/SDL2/include/SDL_render.h880
-rw-r--r--external/SDL2/include/SDL_revision.h2
-rw-r--r--external/SDL2/include/SDL_rwops.h231
-rw-r--r--external/SDL2/include/SDL_scancode.h401
-rw-r--r--external/SDL2/include/SDL_shape.h143
-rw-r--r--external/SDL2/include/SDL_stdinc.h527
-rw-r--r--external/SDL2/include/SDL_surface.h503
-rw-r--r--external/SDL2/include/SDL_system.h216
-rw-r--r--external/SDL2/include/SDL_syswm.h301
-rw-r--r--external/SDL2/include/SDL_test.h68
-rw-r--r--external/SDL2/include/SDL_test_assert.h105
-rw-r--r--external/SDL2/include/SDL_test_common.h188
-rw-r--r--external/SDL2/include/SDL_test_compare.h69
-rw-r--r--external/SDL2/include/SDL_test_crc32.h124
-rw-r--r--external/SDL2/include/SDL_test_font.h76
-rw-r--r--external/SDL2/include/SDL_test_fuzzer.h384
-rw-r--r--external/SDL2/include/SDL_test_harness.h123
-rw-r--r--external/SDL2/include/SDL_test_images.h78
-rw-r--r--external/SDL2/include/SDL_test_log.h67
-rw-r--r--external/SDL2/include/SDL_test_md5.h129
-rw-r--r--external/SDL2/include/SDL_test_random.h115
-rw-r--r--external/SDL2/include/SDL_thread.h287
-rw-r--r--external/SDL2/include/SDL_timer.h115
-rw-r--r--external/SDL2/include/SDL_touch.h86
-rw-r--r--external/SDL2/include/SDL_types.h29
-rw-r--r--external/SDL2/include/SDL_version.h162
-rw-r--r--external/SDL2/include/SDL_video.h1103
-rw-r--r--external/SDL2/include/begin_code.h146
-rw-r--r--external/SDL2/include/close_code.h37
-rw-r--r--external/SDL2/libs/Darwin/libSDL2-2.0.0.dylibbin0 -> 3939940 bytes
-rw-r--r--external/SDL2/libs/Darwin/libSDL2main.abin0 -> 8516 bytes
-rw-r--r--external/jpeg-8c/CMakeLists.txt60
-rw-r--r--external/jpeg-8c/README326
-rw-r--r--external/jpeg-8c/ioquake3-changes.diff683
-rw-r--r--external/jpeg-8c/jaricom.c153
-rw-r--r--external/jpeg-8c/jcapimin.c288
-rw-r--r--external/jpeg-8c/jcapistd.c161
-rw-r--r--external/jpeg-8c/jcarith.c934
-rw-r--r--external/jpeg-8c/jccoefct.c453
-rw-r--r--external/jpeg-8c/jccolor.c459
-rw-r--r--external/jpeg-8c/jcdctmgr.c482
-rw-r--r--external/jpeg-8c/jchuff.c1576
-rw-r--r--external/jpeg-8c/jcinit.c65
-rw-r--r--external/jpeg-8c/jcmainct.c293
-rw-r--r--external/jpeg-8c/jcmarker.c682
-rw-r--r--external/jpeg-8c/jcmaster.c858
-rw-r--r--external/jpeg-8c/jcomapi.c106
-rw-r--r--external/jpeg-8c/jconfig.h60
-rw-r--r--external/jpeg-8c/jcparam.c632
-rw-r--r--external/jpeg-8c/jcprepct.c358
-rw-r--r--external/jpeg-8c/jcsample.c545
-rw-r--r--external/jpeg-8c/jctrans.c382
-rw-r--r--external/jpeg-8c/jdapimin.c396
-rw-r--r--external/jpeg-8c/jdapistd.c275
-rw-r--r--external/jpeg-8c/jdarith.c772
-rw-r--r--external/jpeg-8c/jdatadst.c267
-rw-r--r--external/jpeg-8c/jdatasrc.c274
-rw-r--r--external/jpeg-8c/jdcoefct.c736
-rw-r--r--external/jpeg-8c/jdcolor.c396
-rw-r--r--external/jpeg-8c/jdct.h393
-rw-r--r--external/jpeg-8c/jddctmgr.c384
-rw-r--r--external/jpeg-8c/jdhuff.c1541
-rw-r--r--external/jpeg-8c/jdinput.c661
-rw-r--r--external/jpeg-8c/jdmainct.c512
-rw-r--r--external/jpeg-8c/jdmarker.c1406
-rw-r--r--external/jpeg-8c/jdmaster.c533
-rw-r--r--external/jpeg-8c/jdmerge.c400
-rw-r--r--external/jpeg-8c/jdpostct.c290
-rw-r--r--external/jpeg-8c/jdsample.c361
-rw-r--r--external/jpeg-8c/jdtrans.c140
-rw-r--r--external/jpeg-8c/jerror.c254
-rw-r--r--external/jpeg-8c/jerror.h304
-rw-r--r--external/jpeg-8c/jfdctflt.c174
-rw-r--r--external/jpeg-8c/jfdctfst.c230
-rw-r--r--external/jpeg-8c/jfdctint.c4348
-rw-r--r--external/jpeg-8c/jidctflt.c235
-rw-r--r--external/jpeg-8c/jidctfst.c368
-rw-r--r--external/jpeg-8c/jidctint.c5137
-rw-r--r--external/jpeg-8c/jinclude.h91
-rw-r--r--external/jpeg-8c/jmemmgr.c1118
-rw-r--r--external/jpeg-8c/jmemnobs.c109
-rw-r--r--external/jpeg-8c/jmemsys.h198
-rw-r--r--external/jpeg-8c/jmorecfg.h371
-rw-r--r--external/jpeg-8c/jpegint.h407
-rw-r--r--external/jpeg-8c/jpeglib.h1160
-rw-r--r--external/jpeg-8c/jquant1.c856
-rw-r--r--external/jpeg-8c/jquant2.c1310
-rw-r--r--external/jpeg-8c/jutils.c231
-rw-r--r--external/jpeg-8c/jversion.h14
-rw-r--r--external/libcurl-7.35.0/CMakeLists.txt1
-rw-r--r--external/libcurl-7.35.0/curl/curl.h2296
-rw-r--r--external/libcurl-7.35.0/curl/curlbuild.h587
-rw-r--r--external/libcurl-7.35.0/curl/curlrules.h262
-rw-r--r--external/libcurl-7.35.0/curl/curlver.h69
-rw-r--r--external/libcurl-7.35.0/curl/easy.h102
-rw-r--r--external/libcurl-7.35.0/curl/mprintf.h81
-rw-r--r--external/libcurl-7.35.0/curl/multi.h399
-rw-r--r--external/libcurl-7.35.0/curl/stdcheaders.h33
-rw-r--r--external/libcurl-7.35.0/curl/typecheck-gcc.h610
-rw-r--r--external/libogg-1.3.2/CMakeLists.txt10
-rw-r--r--external/libogg-1.3.2/include/ogg/config_types.h25
-rw-r--r--external/libogg-1.3.2/include/ogg/ogg.h210
-rw-r--r--external/libogg-1.3.2/include/ogg/os_types.h147
-rw-r--r--external/libogg-1.3.2/src/bitwise.c1088
-rw-r--r--external/libogg-1.3.2/src/framing.c2111
-rw-r--r--external/libs/macosx/CMakeLists.txt28
-rw-r--r--external/libs/macosx/libSDL2-2.0.0.dylibbin0 -> 3939940 bytes
-rw-r--r--external/libs/macosx/libSDL2main.abin0 -> 8516 bytes
-rw-r--r--external/libs/win32/SDL.dllbin0 -> 1592921 bytes
-rw-r--r--external/libs/win32/SDL2.dllbin0 -> 950272 bytes
-rw-r--r--external/libs/win32/libSDL.abin0 -> 1531146 bytes
-rw-r--r--external/libs/win32/libSDL2.abin0 -> 6157810 bytes
-rw-r--r--external/libs/win32/libSDL2.dll.abin0 -> 356240 bytes
-rw-r--r--external/libs/win32/libSDL2main.abin0 -> 8808 bytes
-rw-r--r--external/libs/win32/libcurl.abin0 -> 385192 bytes
-rw-r--r--external/libs/win64/SDL264.dllbin0 -> 1117696 bytes
-rw-r--r--external/libs/win64/SDL64.dllbin0 -> 1894504 bytes
-rw-r--r--external/libs/win64/libSDL264.abin0 -> 7810478 bytes
-rw-r--r--external/libs/win64/libSDL264.dll.abin0 -> 349446 bytes
-rw-r--r--external/libs/win64/libSDL264main.abin0 -> 11074 bytes
-rw-r--r--external/libs/win64/libSDL64.abin0 -> 1829790 bytes
-rw-r--r--external/libs/win64/libSDL64main.abin0 -> 17118 bytes
-rw-r--r--external/libs/win64/libcurl.abin0 -> 417936 bytes
-rw-r--r--external/libvorbis-1.3.5/CMakeLists.txt82
-rw-r--r--external/libvorbis-1.3.5/include/vorbis/codec.h243
-rw-r--r--external/libvorbis-1.3.5/include/vorbis/vorbisenc.h436
-rw-r--r--external/libvorbis-1.3.5/include/vorbis/vorbisfile.h206
-rw-r--r--external/libvorbis-1.3.5/lib/analysis.c120
-rw-r--r--external/libvorbis-1.3.5/lib/backends.h144
-rw-r--r--external/libvorbis-1.3.5/lib/bitrate.c253
-rw-r--r--external/libvorbis-1.3.5/lib/bitrate.h59
-rw-r--r--external/libvorbis-1.3.5/lib/block.c1047
-rw-r--r--external/libvorbis-1.3.5/lib/books/coupled/res_books_51.h12274
-rw-r--r--external/libvorbis-1.3.5/lib/books/coupled/res_books_stereo.h15783
-rw-r--r--external/libvorbis-1.3.5/lib/books/floor/floor_books.h1547
-rw-r--r--external/libvorbis-1.3.5/lib/books/uncoupled/res_books_uncoupled.h7758
-rw-r--r--external/libvorbis-1.3.5/lib/codebook.c490
-rw-r--r--external/libvorbis-1.3.5/lib/codebook.h118
-rw-r--r--external/libvorbis-1.3.5/lib/codec_internal.h167
-rw-r--r--external/libvorbis-1.3.5/lib/envelope.c375
-rw-r--r--external/libvorbis-1.3.5/lib/envelope.h80
-rw-r--r--external/libvorbis-1.3.5/lib/floor0.c224
-rw-r--r--external/libvorbis-1.3.5/lib/floor1.c1087
-rw-r--r--external/libvorbis-1.3.5/lib/highlevel.h58
-rw-r--r--external/libvorbis-1.3.5/lib/info.c673
-rw-r--r--external/libvorbis-1.3.5/lib/lookup.c94
-rw-r--r--external/libvorbis-1.3.5/lib/lookup.h32
-rw-r--r--external/libvorbis-1.3.5/lib/lookup_data.h192
-rw-r--r--external/libvorbis-1.3.5/lib/lpc.c160
-rw-r--r--external/libvorbis-1.3.5/lib/lpc.h29
-rw-r--r--external/libvorbis-1.3.5/lib/lsp.c454
-rw-r--r--external/libvorbis-1.3.5/lib/lsp.h28
-rw-r--r--external/libvorbis-1.3.5/lib/mapping0.c810
-rw-r--r--external/libvorbis-1.3.5/lib/masking.h785
-rw-r--r--external/libvorbis-1.3.5/lib/mdct.c563
-rw-r--r--external/libvorbis-1.3.5/lib/mdct.h71
-rw-r--r--external/libvorbis-1.3.5/lib/misc.h58
-rw-r--r--external/libvorbis-1.3.5/lib/modes/floor_all.h260
-rw-r--r--external/libvorbis-1.3.5/lib/modes/psych_11.h51
-rw-r--r--external/libvorbis-1.3.5/lib/modes/psych_16.h133
-rw-r--r--external/libvorbis-1.3.5/lib/modes/psych_44.h642
-rw-r--r--external/libvorbis-1.3.5/lib/modes/psych_8.h101
-rw-r--r--external/libvorbis-1.3.5/lib/modes/residue_16.h163
-rw-r--r--external/libvorbis-1.3.5/lib/modes/residue_44.h292
-rw-r--r--external/libvorbis-1.3.5/lib/modes/residue_44p51.h451
-rw-r--r--external/libvorbis-1.3.5/lib/modes/residue_44u.h318
-rw-r--r--external/libvorbis-1.3.5/lib/modes/residue_8.h109
-rw-r--r--external/libvorbis-1.3.5/lib/modes/setup_11.h143
-rw-r--r--external/libvorbis-1.3.5/lib/modes/setup_16.h153
-rw-r--r--external/libvorbis-1.3.5/lib/modes/setup_22.h128
-rw-r--r--external/libvorbis-1.3.5/lib/modes/setup_32.h132
-rw-r--r--external/libvorbis-1.3.5/lib/modes/setup_44.h117
-rw-r--r--external/libvorbis-1.3.5/lib/modes/setup_44p51.h74
-rw-r--r--external/libvorbis-1.3.5/lib/modes/setup_44u.h74
-rw-r--r--external/libvorbis-1.3.5/lib/modes/setup_8.h149
-rw-r--r--external/libvorbis-1.3.5/lib/modes/setup_X.h225
-rw-r--r--external/libvorbis-1.3.5/lib/os.h191
-rw-r--r--external/libvorbis-1.3.5/lib/psy.c1206
-rw-r--r--external/libvorbis-1.3.5/lib/psy.h154
-rw-r--r--external/libvorbis-1.3.5/lib/registry.c45
-rw-r--r--external/libvorbis-1.3.5/lib/registry.h32
-rw-r--r--external/libvorbis-1.3.5/lib/res0.c890
-rw-r--r--external/libvorbis-1.3.5/lib/scales.h90
-rw-r--r--external/libvorbis-1.3.5/lib/sharedbook.c586
-rw-r--r--external/libvorbis-1.3.5/lib/smallft.c1255
-rw-r--r--external/libvorbis-1.3.5/lib/smallft.h34
-rw-r--r--external/libvorbis-1.3.5/lib/synthesis.c180
-rw-r--r--external/libvorbis-1.3.5/lib/vorbisenc.c1224
-rw-r--r--external/libvorbis-1.3.5/lib/vorbisfile.c2425
-rw-r--r--external/libvorbis-1.3.5/lib/window.c2136
-rw-r--r--external/libvorbis-1.3.5/lib/window.h26
-rw-r--r--external/lua-5.3.3/CMakeLists.txt55
-rw-r--r--external/lua-5.3.3/README6
-rw-r--r--external/lua-5.3.3/include/lauxlib.h256
-rw-r--r--external/lua-5.3.3/include/lua.h486
-rw-r--r--external/lua-5.3.3/include/lua.hpp9
-rw-r--r--external/lua-5.3.3/include/luaconf.h767
-rw-r--r--external/lua-5.3.3/include/lualib.h58
-rw-r--r--external/lua-5.3.3/src/lapi.c1298
-rw-r--r--external/lua-5.3.3/src/lapi.h24
-rw-r--r--external/lua-5.3.3/src/lauxlib.c1035
-rw-r--r--external/lua-5.3.3/src/lauxlib.h257
-rw-r--r--external/lua-5.3.3/src/lbaselib.c500
-rw-r--r--external/lua-5.3.3/src/lbitlib.c233
-rw-r--r--external/lua-5.3.3/src/lcode.c1199
-rw-r--r--external/lua-5.3.3/src/lcode.h88
-rw-r--r--external/lua-5.3.3/src/lcorolib.c168
-rw-r--r--external/lua-5.3.3/src/lctype.c55
-rw-r--r--external/lua-5.3.3/src/lctype.h95
-rw-r--r--external/lua-5.3.3/src/ldblib.c456
-rw-r--r--external/lua-5.3.3/src/ldebug.c679
-rw-r--r--external/lua-5.3.3/src/ldebug.h39
-rw-r--r--external/lua-5.3.3/src/ldo.c800
-rw-r--r--external/lua-5.3.3/src/ldo.h58
-rw-r--r--external/lua-5.3.3/src/ldump.c215
-rw-r--r--external/lua-5.3.3/src/lfunc.c151
-rw-r--r--external/lua-5.3.3/src/lfunc.h61
-rw-r--r--external/lua-5.3.3/src/lgc.c1176
-rw-r--r--external/lua-5.3.3/src/lgc.h147
-rw-r--r--external/lua-5.3.3/src/linit.c68
-rw-r--r--external/lua-5.3.3/src/liolib.c768
-rw-r--r--external/lua-5.3.3/src/llex.c565
-rw-r--r--external/lua-5.3.3/src/llex.h85
-rw-r--r--external/lua-5.3.3/src/llimits.h323
-rw-r--r--external/lua-5.3.3/src/lmathlib.c407
-rw-r--r--external/lua-5.3.3/src/lmem.c100
-rw-r--r--external/lua-5.3.3/src/lmem.h69
-rw-r--r--external/lua-5.3.3/src/loadlib.c787
-rw-r--r--external/lua-5.3.3/src/lobject.c521
-rw-r--r--external/lua-5.3.3/src/lobject.h549
-rw-r--r--external/lua-5.3.3/src/lopcodes.c124
-rw-r--r--external/lua-5.3.3/src/lopcodes.h295
-rw-r--r--external/lua-5.3.3/src/loslib.c403
-rw-r--r--external/lua-5.3.3/src/lparser.c1652
-rw-r--r--external/lua-5.3.3/src/lparser.h133
-rw-r--r--external/lua-5.3.3/src/lprefix.h45
-rw-r--r--external/lua-5.3.3/src/lstate.c347
-rw-r--r--external/lua-5.3.3/src/lstate.h234
-rw-r--r--external/lua-5.3.3/src/lstring.c248
-rw-r--r--external/lua-5.3.3/src/lstring.h49
-rw-r--r--external/lua-5.3.3/src/lstrlib.c1582
-rw-r--r--external/lua-5.3.3/src/ltable.c669
-rw-r--r--external/lua-5.3.3/src/ltable.h58
-rw-r--r--external/lua-5.3.3/src/ltablib.c450
-rw-r--r--external/lua-5.3.3/src/ltm.c165
-rw-r--r--external/lua-5.3.3/src/ltm.h76
-rw-r--r--external/lua-5.3.3/src/lua.c609
-rw-r--r--external/lua-5.3.3/src/lua.h486
-rw-r--r--external/lua-5.3.3/src/lua.hpp9
-rw-r--r--external/lua-5.3.3/src/luac.c449
-rw-r--r--external/lua-5.3.3/src/luaconf.h767
-rw-r--r--external/lua-5.3.3/src/lualib.h58
-rw-r--r--external/lua-5.3.3/src/lundump.c279
-rw-r--r--external/lua-5.3.3/src/lundump.h32
-rw-r--r--external/lua-5.3.3/src/lutf8lib.c256
-rw-r--r--external/lua-5.3.3/src/lvm.c1322
-rw-r--r--external/lua-5.3.3/src/lvm.h113
-rw-r--r--external/lua-5.3.3/src/lzio.c68
-rw-r--r--external/lua-5.3.3/src/lzio.h66
-rw-r--r--external/nettle-3.3/CMakeLists.txt38
-rw-r--r--external/nettle-3.3/nettle/bignum-random-prime.c533
-rw-r--r--external/nettle-3.3/nettle/bignum-random.c96
-rw-r--r--external/nettle-3.3/nettle/bignum.c186
-rw-r--r--external/nettle-3.3/nettle/bignum.h140
-rw-r--r--external/nettle-3.3/nettle/buffer-init.c48
-rw-r--r--external/nettle-3.3/nettle/buffer.c142
-rw-r--r--external/nettle-3.3/nettle/buffer.h106
-rw-r--r--external/nettle-3.3/nettle/gmp-glue.c326
-rw-r--r--external/nettle-3.3/nettle/gmp-glue.h164
-rw-r--r--external/nettle-3.3/nettle/macros.h245
-rw-r--r--external/nettle-3.3/nettle/mini-gmp.c4386
-rw-r--r--external/nettle-3.3/nettle/mini-gmp.h294
-rw-r--r--external/nettle-3.3/nettle/nettle-internal.h92
-rw-r--r--external/nettle-3.3/nettle/nettle-meta.h230
-rw-r--r--external/nettle-3.3/nettle/nettle-stdint.h6
-rw-r--r--external/nettle-3.3/nettle/nettle-types.h110
-rw-r--r--external/nettle-3.3/nettle/nettle-write.h58
-rw-r--r--external/nettle-3.3/nettle/pkcs1-rsa-sha256.c120
-rw-r--r--external/nettle-3.3/nettle/pkcs1.c73
-rw-r--r--external/nettle-3.3/nettle/pkcs1.h114
-rw-r--r--external/nettle-3.3/nettle/realloc.c69
-rw-r--r--external/nettle-3.3/nettle/realloc.h48
-rw-r--r--external/nettle-3.3/nettle/rsa-keygen.c212
-rw-r--r--external/nettle-3.3/nettle/rsa-sha256-sign.c77
-rw-r--r--external/nettle-3.3/nettle/rsa-sha256-verify.c79
-rw-r--r--external/nettle-3.3/nettle/rsa-sign.c144
-rw-r--r--external/nettle-3.3/nettle/rsa-verify.c64
-rw-r--r--external/nettle-3.3/nettle/rsa.c86
-rw-r--r--external/nettle-3.3/nettle/rsa.h355
-rw-r--r--external/nettle-3.3/nettle/rsa2sexp.c59
-rw-r--r--external/nettle-3.3/nettle/sexp-format.c348
-rw-r--r--external/nettle-3.3/nettle/sexp.c399
-rw-r--r--external/nettle-3.3/nettle/sexp.h213
-rw-r--r--external/nettle-3.3/nettle/sexp2bignum.c60
-rw-r--r--external/nettle-3.3/nettle/sexp2rsa.c115
-rw-r--r--external/nettle-3.3/nettle/sha2.h206
-rw-r--r--external/nettle-3.3/nettle/sha256-compress.c199
-rw-r--r--external/nettle-3.3/nettle/sha256.c162
-rw-r--r--external/nettle-3.3/nettle/version.h58
-rw-r--r--external/nettle-3.3/nettle/write-be32.c77
-rw-r--r--external/opus-1.1.4/CMakeLists.txt230
-rw-r--r--external/opus-1.1.4/celt/CMakeLists.txt59
-rw-r--r--external/opus-1.1.4/celt/_kiss_fft_guts.h182
-rw-r--r--external/opus-1.1.4/celt/arch.h252
-rw-r--r--external/opus-1.1.4/celt/arm/arm2gnu.pl353
-rw-r--r--external/opus-1.1.4/celt/arm/arm_celt_map.c143
-rw-r--r--external/opus-1.1.4/celt/arm/armcpu.c185
-rw-r--r--external/opus-1.1.4/celt/arm/armcpu.h77
-rw-r--r--external/opus-1.1.4/celt/arm/armopts.s.in37
-rw-r--r--external/opus-1.1.4/celt/arm/celt_ne10_fft.c174
-rw-r--r--external/opus-1.1.4/celt/arm/celt_ne10_mdct.c258
-rw-r--r--external/opus-1.1.4/celt/arm/celt_neon_intr.c311
-rw-r--r--external/opus-1.1.4/celt/arm/celt_pitch_xcorr_arm-gnu.S551
-rw-r--r--external/opus-1.1.4/celt/arm/celt_pitch_xcorr_arm.s547
-rw-r--r--external/opus-1.1.4/celt/arm/fft_arm.h72
-rw-r--r--external/opus-1.1.4/celt/arm/fixed_arm64.h35
-rw-r--r--external/opus-1.1.4/celt/arm/fixed_armv4.h80
-rw-r--r--external/opus-1.1.4/celt/arm/fixed_armv5e.h151
-rw-r--r--external/opus-1.1.4/celt/arm/kiss_fft_armv4.h121
-rw-r--r--external/opus-1.1.4/celt/arm/kiss_fft_armv5e.h118
-rw-r--r--external/opus-1.1.4/celt/arm/mdct_arm.h60
-rw-r--r--external/opus-1.1.4/celt/arm/pitch_arm.h126
-rw-r--r--external/opus-1.1.4/celt/bands.c1529
-rw-r--r--external/opus-1.1.4/celt/bands.h120
-rw-r--r--external/opus-1.1.4/celt/celt.c299
-rw-r--r--external/opus-1.1.4/celt/celt.h229
-rw-r--r--external/opus-1.1.4/celt/celt_decoder.c1248
-rw-r--r--external/opus-1.1.4/celt/celt_encoder.c2410
-rw-r--r--external/opus-1.1.4/celt/celt_lpc.c314
-rw-r--r--external/opus-1.1.4/celt/celt_lpc.h67
-rw-r--r--external/opus-1.1.4/celt/cpu_support.h70
-rw-r--r--external/opus-1.1.4/celt/cwrs.c715
-rw-r--r--external/opus-1.1.4/celt/cwrs.h48
-rw-r--r--external/opus-1.1.4/celt/ecintrin.h87
-rw-r--r--external/opus-1.1.4/celt/entcode.c153
-rw-r--r--external/opus-1.1.4/celt/entcode.h152
-rw-r--r--external/opus-1.1.4/celt/entdec.c245
-rw-r--r--external/opus-1.1.4/celt/entdec.h100
-rw-r--r--external/opus-1.1.4/celt/entenc.c294
-rw-r--r--external/opus-1.1.4/celt/entenc.h110
-rw-r--r--external/opus-1.1.4/celt/fixed_debug.h784
-rw-r--r--external/opus-1.1.4/celt/fixed_generic.h167
-rw-r--r--external/opus-1.1.4/celt/float_cast.h140
-rw-r--r--external/opus-1.1.4/celt/kiss_fft.c604
-rw-r--r--external/opus-1.1.4/celt/kiss_fft.h200
-rw-r--r--external/opus-1.1.4/celt/laplace.c134
-rw-r--r--external/opus-1.1.4/celt/laplace.h48
-rw-r--r--external/opus-1.1.4/celt/mathops.c208
-rw-r--r--external/opus-1.1.4/celt/mathops.h258
-rw-r--r--external/opus-1.1.4/celt/mdct.c343
-rw-r--r--external/opus-1.1.4/celt/mdct.h112
-rw-r--r--external/opus-1.1.4/celt/mfrngcod.h48
-rw-r--r--external/opus-1.1.4/celt/mips/celt_mipsr1.h151
-rw-r--r--external/opus-1.1.4/celt/mips/fixed_generic_mipsr1.h126
-rw-r--r--external/opus-1.1.4/celt/mips/kiss_fft_mipsr1.h167
-rw-r--r--external/opus-1.1.4/celt/mips/mdct_mipsr1.h288
-rw-r--r--external/opus-1.1.4/celt/mips/pitch_mipsr1.h161
-rw-r--r--external/opus-1.1.4/celt/mips/vq_mipsr1.h125
-rw-r--r--external/opus-1.1.4/celt/modes.c442
-rw-r--r--external/opus-1.1.4/celt/modes.h75
-rw-r--r--external/opus-1.1.4/celt/opus_custom_demo.c210
-rw-r--r--external/opus-1.1.4/celt/os_support.h92
-rw-r--r--external/opus-1.1.4/celt/pitch.c557
-rw-r--r--external/opus-1.1.4/celt/pitch.h200
-rw-r--r--external/opus-1.1.4/celt/quant_bands.c556
-rw-r--r--external/opus-1.1.4/celt/quant_bands.h66
-rw-r--r--external/opus-1.1.4/celt/rate.c639
-rw-r--r--external/opus-1.1.4/celt/rate.h101
-rw-r--r--external/opus-1.1.4/celt/stack_alloc.h184
-rw-r--r--external/opus-1.1.4/celt/static_modes_fixed.h892
-rw-r--r--external/opus-1.1.4/celt/static_modes_fixed_arm_ne10.h388
-rw-r--r--external/opus-1.1.4/celt/static_modes_float.h888
-rw-r--r--external/opus-1.1.4/celt/static_modes_float_arm_ne10.h404
-rw-r--r--external/opus-1.1.4/celt/vq.c408
-rw-r--r--external/opus-1.1.4/celt/vq.h75
-rw-r--r--external/opus-1.1.4/celt/x86/celt_lpc_sse.c132
-rw-r--r--external/opus-1.1.4/celt/x86/celt_lpc_sse.h68
-rw-r--r--external/opus-1.1.4/celt/x86/pitch_sse.c185
-rw-r--r--external/opus-1.1.4/celt/x86/pitch_sse.h192
-rw-r--r--external/opus-1.1.4/celt/x86/pitch_sse2.c95
-rw-r--r--external/opus-1.1.4/celt/x86/pitch_sse4_1.c195
-rw-r--r--external/opus-1.1.4/celt/x86/x86_celt_map.c155
-rw-r--r--external/opus-1.1.4/celt/x86/x86cpu.c157
-rw-r--r--external/opus-1.1.4/celt/x86/x86cpu.h93
-rw-r--r--external/opus-1.1.4/include/CMakeLists.txt2
-rw-r--r--external/opus-1.1.4/include/opus.h981
-rw-r--r--external/opus-1.1.4/include/opus_custom.h342
-rw-r--r--external/opus-1.1.4/include/opus_defines.h753
-rw-r--r--external/opus-1.1.4/include/opus_multistream.h660
-rw-r--r--external/opus-1.1.4/include/opus_types.h159
-rw-r--r--external/opus-1.1.4/silk/A2NLSF.c267
-rw-r--r--external/opus-1.1.4/silk/API.h134
-rw-r--r--external/opus-1.1.4/silk/CMakeLists.txt113
-rw-r--r--external/opus-1.1.4/silk/CNG.c184
-rw-r--r--external/opus-1.1.4/silk/HP_variable_cutoff.c77
-rw-r--r--external/opus-1.1.4/silk/Inlines.h188
-rw-r--r--external/opus-1.1.4/silk/LPC_analysis_filter.c108
-rw-r--r--external/opus-1.1.4/silk/LPC_inv_pred_gain.c154
-rw-r--r--external/opus-1.1.4/silk/LP_variable_cutoff.c135
-rw-r--r--external/opus-1.1.4/silk/MacroCount.h718
-rw-r--r--external/opus-1.1.4/silk/MacroDebug.h952
-rw-r--r--external/opus-1.1.4/silk/NLSF2A.c178
-rw-r--r--external/opus-1.1.4/silk/NLSF_VQ.c68
-rw-r--r--external/opus-1.1.4/silk/NLSF_VQ_weights_laroia.c80
-rw-r--r--external/opus-1.1.4/silk/NLSF_decode.c101
-rw-r--r--external/opus-1.1.4/silk/NLSF_del_dec_quant.c217
-rw-r--r--external/opus-1.1.4/silk/NLSF_encode.c137
-rw-r--r--external/opus-1.1.4/silk/NLSF_stabilize.c142
-rw-r--r--external/opus-1.1.4/silk/NLSF_unpack.c55
-rw-r--r--external/opus-1.1.4/silk/NSQ.c429
-rw-r--r--external/opus-1.1.4/silk/NSQ.h101
-rw-r--r--external/opus-1.1.4/silk/NSQ_del_dec.c716
-rw-r--r--external/opus-1.1.4/silk/PLC.c446
-rw-r--r--external/opus-1.1.4/silk/PLC.h62
-rw-r--r--external/opus-1.1.4/silk/SigProc_FIX.h615
-rw-r--r--external/opus-1.1.4/silk/VAD.c362
-rw-r--r--external/opus-1.1.4/silk/VQ_WMat_EC.c120
-rw-r--r--external/opus-1.1.4/silk/ana_filt_bank_1.c74
-rw-r--r--external/opus-1.1.4/silk/arm/NSQ_neon.c112
-rw-r--r--external/opus-1.1.4/silk/arm/NSQ_neon.h113
-rw-r--r--external/opus-1.1.4/silk/arm/SigProc_FIX_armv4.h47
-rw-r--r--external/opus-1.1.4/silk/arm/SigProc_FIX_armv5e.h61
-rw-r--r--external/opus-1.1.4/silk/arm/arm_silk_map.c55
-rw-r--r--external/opus-1.1.4/silk/arm/macros_arm64.h39
-rw-r--r--external/opus-1.1.4/silk/arm/macros_armv4.h103
-rw-r--r--external/opus-1.1.4/silk/arm/macros_armv5e.h213
-rw-r--r--external/opus-1.1.4/silk/biquad_alt.c78
-rw-r--r--external/opus-1.1.4/silk/bwexpander.c51
-rw-r--r--external/opus-1.1.4/silk/bwexpander_32.c50
-rw-r--r--external/opus-1.1.4/silk/check_control_input.c106
-rw-r--r--external/opus-1.1.4/silk/code_signs.c115
-rw-r--r--external/opus-1.1.4/silk/control.h142
-rw-r--r--external/opus-1.1.4/silk/control_SNR.c76
-rw-r--r--external/opus-1.1.4/silk/control_audio_bandwidth.c126
-rw-r--r--external/opus-1.1.4/silk/control_codec.c428
-rw-r--r--external/opus-1.1.4/silk/debug.c170
-rw-r--r--external/opus-1.1.4/silk/debug.h279
-rw-r--r--external/opus-1.1.4/silk/dec_API.c419
-rw-r--r--external/opus-1.1.4/silk/decode_core.c239
-rw-r--r--external/opus-1.1.4/silk/decode_frame.c129
-rw-r--r--external/opus-1.1.4/silk/decode_indices.c151
-rw-r--r--external/opus-1.1.4/silk/decode_parameters.c115
-rw-r--r--external/opus-1.1.4/silk/decode_pitch.c77
-rw-r--r--external/opus-1.1.4/silk/decode_pulses.c115
-rw-r--r--external/opus-1.1.4/silk/decoder_set_fs.c108
-rw-r--r--external/opus-1.1.4/silk/define.h235
-rw-r--r--external/opus-1.1.4/silk/enc_API.c563
-rw-r--r--external/opus-1.1.4/silk/encode_indices.c181
-rw-r--r--external/opus-1.1.4/silk/encode_pulses.c206
-rw-r--r--external/opus-1.1.4/silk/errors.h98
-rw-r--r--external/opus-1.1.4/silk/fixed/CMakeLists.txt42
-rw-r--r--external/opus-1.1.4/silk/fixed/LTP_analysis_filter_FIX.c85
-rw-r--r--external/opus-1.1.4/silk/fixed/LTP_scale_ctrl_FIX.c53
-rw-r--r--external/opus-1.1.4/silk/fixed/apply_sine_window_FIX.c101
-rw-r--r--external/opus-1.1.4/silk/fixed/autocorr_FIX.c48
-rw-r--r--external/opus-1.1.4/silk/fixed/burg_modified_FIX.c279
-rw-r--r--external/opus-1.1.4/silk/fixed/corrMatrix_FIX.c156
-rw-r--r--external/opus-1.1.4/silk/fixed/encode_frame_FIX.c385
-rw-r--r--external/opus-1.1.4/silk/fixed/find_LPC_FIX.c151
-rw-r--r--external/opus-1.1.4/silk/fixed/find_LTP_FIX.c244
-rw-r--r--external/opus-1.1.4/silk/fixed/find_pitch_lags_FIX.c145
-rw-r--r--external/opus-1.1.4/silk/fixed/find_pred_coefs_FIX.c147
-rw-r--r--external/opus-1.1.4/silk/fixed/k2a_FIX.c53
-rw-r--r--external/opus-1.1.4/silk/fixed/k2a_Q16_FIX.c53
-rw-r--r--external/opus-1.1.4/silk/fixed/main_FIX.h257
-rw-r--r--external/opus-1.1.4/silk/fixed/noise_shape_analysis_FIX.c445
-rw-r--r--external/opus-1.1.4/silk/fixed/pitch_analysis_core_FIX.c744
-rw-r--r--external/opus-1.1.4/silk/fixed/prefilter_FIX.c209
-rw-r--r--external/opus-1.1.4/silk/fixed/process_gains_FIX.c117
-rw-r--r--external/opus-1.1.4/silk/fixed/regularize_correlations_FIX.c47
-rw-r--r--external/opus-1.1.4/silk/fixed/residual_energy16_FIX.c103
-rw-r--r--external/opus-1.1.4/silk/fixed/residual_energy_FIX.c97
-rw-r--r--external/opus-1.1.4/silk/fixed/schur64_FIX.c92
-rw-r--r--external/opus-1.1.4/silk/fixed/schur_FIX.c106
-rw-r--r--external/opus-1.1.4/silk/fixed/solve_LS_FIX.c249
-rw-r--r--external/opus-1.1.4/silk/fixed/structs_FIX.h133
-rw-r--r--external/opus-1.1.4/silk/fixed/vector_ops_FIX.c96
-rw-r--r--external/opus-1.1.4/silk/fixed/warped_autocorrelation_FIX.c88
-rw-r--r--external/opus-1.1.4/silk/float/CMakeLists.txt48
-rw-r--r--external/opus-1.1.4/silk/float/LPC_analysis_filter_FLP.c249
-rw-r--r--external/opus-1.1.4/silk/float/LPC_inv_pred_gain_FLP.c76
-rw-r--r--external/opus-1.1.4/silk/float/LTP_analysis_filter_FLP.c75
-rw-r--r--external/opus-1.1.4/silk/float/LTP_scale_ctrl_FLP.c52
-rw-r--r--external/opus-1.1.4/silk/float/SigProc_FLP.h204
-rw-r--r--external/opus-1.1.4/silk/float/apply_sine_window_FLP.c81
-rw-r--r--external/opus-1.1.4/silk/float/autocorrelation_FLP.c52
-rw-r--r--external/opus-1.1.4/silk/float/burg_modified_FLP.c186
-rw-r--r--external/opus-1.1.4/silk/float/bwexpander_FLP.c49
-rw-r--r--external/opus-1.1.4/silk/float/corrMatrix_FLP.c93
-rw-r--r--external/opus-1.1.4/silk/float/encode_frame_FLP.c372
-rw-r--r--external/opus-1.1.4/silk/float/energy_FLP.c60
-rw-r--r--external/opus-1.1.4/silk/float/find_LPC_FLP.c104
-rw-r--r--external/opus-1.1.4/silk/float/find_LTP_FLP.c132
-rw-r--r--external/opus-1.1.4/silk/float/find_pitch_lags_FLP.c132
-rw-r--r--external/opus-1.1.4/silk/float/find_pred_coefs_FLP.c118
-rw-r--r--external/opus-1.1.4/silk/float/inner_product_FLP.c60
-rw-r--r--external/opus-1.1.4/silk/float/k2a_FLP.c53
-rw-r--r--external/opus-1.1.4/silk/float/levinsondurbin_FLP.c81
-rw-r--r--external/opus-1.1.4/silk/float/main_FLP.h313
-rw-r--r--external/opus-1.1.4/silk/float/noise_shape_analysis_FLP.c365
-rw-r--r--external/opus-1.1.4/silk/float/pitch_analysis_core_FLP.c630
-rw-r--r--external/opus-1.1.4/silk/float/prefilter_FLP.c206
-rw-r--r--external/opus-1.1.4/silk/float/process_gains_FLP.c103
-rw-r--r--external/opus-1.1.4/silk/float/regularize_correlations_FLP.c48
-rw-r--r--external/opus-1.1.4/silk/float/residual_energy_FLP.c117
-rw-r--r--external/opus-1.1.4/silk/float/scale_copy_vector_FLP.c57
-rw-r--r--external/opus-1.1.4/silk/float/scale_vector_FLP.c56
-rw-r--r--external/opus-1.1.4/silk/float/schur_FLP.c70
-rw-r--r--external/opus-1.1.4/silk/float/solve_LS_FLP.c207
-rw-r--r--external/opus-1.1.4/silk/float/sort_FLP.c83
-rw-r--r--external/opus-1.1.4/silk/float/structs_FLP.h132
-rw-r--r--external/opus-1.1.4/silk/float/warped_autocorrelation_FLP.c73
-rw-r--r--external/opus-1.1.4/silk/float/wrappers_FLP.c202
-rw-r--r--external/opus-1.1.4/silk/gain_quant.c141
-rw-r--r--external/opus-1.1.4/silk/init_decoder.c56
-rw-r--r--external/opus-1.1.4/silk/init_encoder.c64
-rw-r--r--external/opus-1.1.4/silk/inner_prod_aligned.c47
-rw-r--r--external/opus-1.1.4/silk/interpolate.c51
-rw-r--r--external/opus-1.1.4/silk/lin2log.c46
-rw-r--r--external/opus-1.1.4/silk/log2lin.c58
-rw-r--r--external/opus-1.1.4/silk/macros.h159
-rw-r--r--external/opus-1.1.4/silk/main.h471
-rw-r--r--external/opus-1.1.4/silk/mips/NSQ_del_dec_mipsr1.h409
-rw-r--r--external/opus-1.1.4/silk/mips/macros_mipsr1.h92
-rw-r--r--external/opus-1.1.4/silk/mips/sigproc_fix_mipsr1.h65
-rw-r--r--external/opus-1.1.4/silk/pitch_est_defines.h88
-rw-r--r--external/opus-1.1.4/silk/pitch_est_tables.c99
-rw-r--r--external/opus-1.1.4/silk/process_NLSFs.c107
-rw-r--r--external/opus-1.1.4/silk/quant_LTP_gains.c129
-rw-r--r--external/opus-1.1.4/silk/resampler.c215
-rw-r--r--external/opus-1.1.4/silk/resampler_down2.c74
-rw-r--r--external/opus-1.1.4/silk/resampler_down2_3.c103
-rw-r--r--external/opus-1.1.4/silk/resampler_private.h88
-rw-r--r--external/opus-1.1.4/silk/resampler_private_AR2.c55
-rw-r--r--external/opus-1.1.4/silk/resampler_private_IIR_FIR.c107
-rw-r--r--external/opus-1.1.4/silk/resampler_private_down_FIR.c194
-rw-r--r--external/opus-1.1.4/silk/resampler_private_up2_HQ.c113
-rw-r--r--external/opus-1.1.4/silk/resampler_rom.c96
-rw-r--r--external/opus-1.1.4/silk/resampler_rom.h68
-rw-r--r--external/opus-1.1.4/silk/resampler_structs.h60
-rw-r--r--external/opus-1.1.4/silk/shell_coder.c151
-rw-r--r--external/opus-1.1.4/silk/sigm_Q15.c76
-rw-r--r--external/opus-1.1.4/silk/sort.c154
-rw-r--r--external/opus-1.1.4/silk/stereo_LR_to_MS.c229
-rw-r--r--external/opus-1.1.4/silk/stereo_MS_to_LR.c85
-rw-r--r--external/opus-1.1.4/silk/stereo_decode_pred.c73
-rw-r--r--external/opus-1.1.4/silk/stereo_encode_pred.c62
-rw-r--r--external/opus-1.1.4/silk/stereo_find_predictor.c79
-rw-r--r--external/opus-1.1.4/silk/stereo_quant_pred.c73
-rw-r--r--external/opus-1.1.4/silk/structs.h327
-rw-r--r--external/opus-1.1.4/silk/sum_sqr_shift.c86
-rw-r--r--external/opus-1.1.4/silk/table_LSF_cos.c70
-rw-r--r--external/opus-1.1.4/silk/tables.h122
-rw-r--r--external/opus-1.1.4/silk/tables_LTP.c296
-rw-r--r--external/opus-1.1.4/silk/tables_NLSF_CB_NB_MB.c159
-rw-r--r--external/opus-1.1.4/silk/tables_NLSF_CB_WB.c198
-rw-r--r--external/opus-1.1.4/silk/tables_gain.c63
-rw-r--r--external/opus-1.1.4/silk/tables_other.c138
-rw-r--r--external/opus-1.1.4/silk/tables_pitch_lag.c69
-rw-r--r--external/opus-1.1.4/silk/tables_pulses_per_block.c264
-rw-r--r--external/opus-1.1.4/silk/tuning_parameters.h171
-rw-r--r--external/opus-1.1.4/silk/typedef.h78
-rw-r--r--external/opus-1.1.4/silk/x86/NSQ_del_dec_sse.c857
-rw-r--r--external/opus-1.1.4/silk/x86/NSQ_sse.c720
-rw-r--r--external/opus-1.1.4/silk/x86/SigProc_FIX_sse.h94
-rw-r--r--external/opus-1.1.4/silk/x86/VAD_sse.c277
-rw-r--r--external/opus-1.1.4/silk/x86/VQ_WMat_EC_sse.c142
-rw-r--r--external/opus-1.1.4/silk/x86/main_sse.h277
-rw-r--r--external/opus-1.1.4/silk/x86/x86_silk_map.c174
-rw-r--r--external/opus-1.1.4/src/CMakeLists.txt40
-rw-r--r--external/opus-1.1.4/src/analysis.c672
-rw-r--r--external/opus-1.1.4/src/analysis.h103
-rw-r--r--external/opus-1.1.4/src/mlp.c145
-rw-r--r--external/opus-1.1.4/src/mlp.h43
-rw-r--r--external/opus-1.1.4/src/mlp_data.c109
-rw-r--r--external/opus-1.1.4/src/opus.c356
-rw-r--r--external/opus-1.1.4/src/opus_decoder.c981
-rw-r--r--external/opus-1.1.4/src/opus_encoder.c2536
-rw-r--r--external/opus-1.1.4/src/opus_multistream.c92
-rw-r--r--external/opus-1.1.4/src/opus_multistream_decoder.c537
-rw-r--r--external/opus-1.1.4/src/opus_multistream_encoder.c1351
-rw-r--r--external/opus-1.1.4/src/opus_private.h134
-rw-r--r--external/opus-1.1.4/src/repacketizer.c348
-rw-r--r--external/opus-1.1.4/src/tansig_table.h45
-rw-r--r--external/opusfile-0.8/CMakeLists.txt24
-rw-r--r--external/opusfile-0.8/include/opusfile.h2157
-rw-r--r--external/opusfile-0.8/src/http.c3465
-rw-r--r--external/opusfile-0.8/src/info.c758
-rw-r--r--external/opusfile-0.8/src/internal.c42
-rw-r--r--external/opusfile-0.8/src/internal.h254
-rw-r--r--external/opusfile-0.8/src/opusfile.c3266
-rw-r--r--external/opusfile-0.8/src/stream.c366
-rw-r--r--external/opusfile-0.8/src/wincerts.c171
-rw-r--r--external/opusfile-0.8/src/winerrno.h90
-rw-r--r--external/rapidjson/rapidjson.h31
-rw-r--r--external/rapidjson/rapidjson/allocators.h271
-rw-r--r--external/rapidjson/rapidjson/document.h2592
-rw-r--r--external/rapidjson/rapidjson/encodedstream.h299
-rw-r--r--external/rapidjson/rapidjson/encodings.h716
-rw-r--r--external/rapidjson/rapidjson/error/en.h74
-rw-r--r--external/rapidjson/rapidjson/error/error.h155
-rw-r--r--external/rapidjson/rapidjson/filereadstream.h99
-rw-r--r--external/rapidjson/rapidjson/filewritestream.h104
-rw-r--r--external/rapidjson/rapidjson/fwd.h151
-rw-r--r--external/rapidjson/rapidjson/internal/biginteger.h290
-rw-r--r--external/rapidjson/rapidjson/internal/diyfp.h258
-rw-r--r--external/rapidjson/rapidjson/internal/dtoa.h245
-rw-r--r--external/rapidjson/rapidjson/internal/ieee754.h78
-rw-r--r--external/rapidjson/rapidjson/internal/itoa.h304
-rw-r--r--external/rapidjson/rapidjson/internal/meta.h181
-rw-r--r--external/rapidjson/rapidjson/internal/pow10.h55
-rw-r--r--external/rapidjson/rapidjson/internal/regex.h731
-rw-r--r--external/rapidjson/rapidjson/internal/stack.h230
-rw-r--r--external/rapidjson/rapidjson/internal/strfunc.h58
-rw-r--r--external/rapidjson/rapidjson/internal/strtod.h269
-rw-r--r--external/rapidjson/rapidjson/internal/swap.h46
-rw-r--r--external/rapidjson/rapidjson/istreamwrapper.h115
-rw-r--r--external/rapidjson/rapidjson/memorybuffer.h70
-rw-r--r--external/rapidjson/rapidjson/memorystream.h71
-rw-r--r--external/rapidjson/rapidjson/msinttypes/inttypes.h316
-rw-r--r--external/rapidjson/rapidjson/msinttypes/stdint.h300
-rw-r--r--external/rapidjson/rapidjson/ostreamwrapper.h81
-rw-r--r--external/rapidjson/rapidjson/pointer.h1358
-rw-r--r--external/rapidjson/rapidjson/prettywriter.h275
-rw-r--r--external/rapidjson/rapidjson/rapidjson.h615
-rw-r--r--external/rapidjson/rapidjson/reader.h1865
-rw-r--r--external/rapidjson/rapidjson/schema.h2024
-rw-r--r--external/rapidjson/rapidjson/stream.h179
-rw-r--r--external/rapidjson/rapidjson/stringbuffer.h121
-rw-r--r--external/rapidjson/rapidjson/writer.h624
-rw-r--r--external/restclient/CMakeLists.txt10
-rw-r--r--external/restclient/LICENSE20
-rw-r--r--external/restclient/README.md7
-rw-r--r--external/restclient/connection.cpp363
-rw-r--r--external/restclient/helpers.cpp96
-rw-r--r--external/restclient/restclient.cpp118
-rw-r--r--external/restclient/restclient/connection.h169
-rw-r--r--external/restclient/restclient/helpers.h74
-rw-r--r--external/restclient/restclient/restclient.h63
-rw-r--r--external/restclient/restclient/version.h4
-rw-r--r--external/semver/.gitignore2
-rw-r--r--external/semver/.gitmodules6
-rw-r--r--external/semver/.travis.yml93
-rw-r--r--external/semver/CMakeLists.txt100
-rw-r--r--external/semver/LICENSE21
-rw-r--r--external/semver/README.md12
-rw-r--r--external/semver/appveyor.yml35
-rw-r--r--external/semver/install_libcxx.sh13
-rw-r--r--external/semver/src/include/semantic_version.h189
-rw-r--r--external/semver/src/lib/CMakeLists.txt1
-rw-r--r--external/semver/src/lib/semantic_version_v1.cpp286
-rw-r--r--external/semver/src/lib/semantic_version_v2.cpp272
-rw-r--r--external/semver/src/quickcheck/CMakeLists.txt29
-rw-r--r--external/semver/src/quickcheck/Main.hibin0 -> 3353 bytes
-rw-r--r--external/semver/src/quickcheck/Main.hs80
-rw-r--r--external/semver/src/quickcheck/Main.obin0 -> 35952 bytes
-rw-r--r--external/semver/src/quickcheck/Semver.hsc87
-rw-r--r--external/semver/src/quickcheck/semantic_version_ffi.cpp58
-rw-r--r--external/semver/src/quickcheck/semantic_version_ffi.h27
-rw-r--r--external/semver/src/test/CMakeLists.txt3
-rw-r--r--external/semver/src/test/main.cpp297
-rw-r--r--external/sol/CMakeLists.txt4
-rw-r--r--external/sol/sol.hpp13353
-rw-r--r--external/zlib/CMakeLists.txt17
-rw-r--r--external/zlib/adler32.c149
-rw-r--r--external/zlib/crc32.c423
-rw-r--r--external/zlib/crc32.h441
-rw-r--r--external/zlib/inffast.c317
-rw-r--r--external/zlib/inffast.h11
-rw-r--r--external/zlib/inffixed.h94
-rw-r--r--external/zlib/inflate.c1368
-rw-r--r--external/zlib/inflate.h115
-rw-r--r--external/zlib/inftrees.c329
-rw-r--r--external/zlib/inftrees.h55
-rw-r--r--external/zlib/zconf.h332
-rw-r--r--external/zlib/zlib.h1357
-rw-r--r--external/zlib/zutil.c318
-rw-r--r--external/zlib/zutil.h269
-rw-r--r--make-macosx-app.sh345
-rw-r--r--misc/SLA-dmg.sh73
-rw-r--r--misc/Tremulous.icnsbin0 -> 78419 bytes
-rw-r--r--misc/docker-build.sh12
-rw-r--r--misc/download-paks.sh52
-rw-r--r--misc/entities.def1707
-rw-r--r--misc/last-merged-ioq3-revision1
-rw-r--r--misc/make-macosx-ub.sh94
-rw-r--r--misc/make-macosx.sh77
-rw-r--r--misc/manual.lyx8376
-rw-r--r--misc/merge-grangerhub-into-trem.sh109
-rw-r--r--misc/merge-ioq3-into-trem.sh112
-rw-r--r--misc/msvc/tremulous.sln21
-rw-r--r--misc/msvc/tremulous.vcproj65
-rw-r--r--misc/server.cfg39
-rw-r--r--misc/travis-ci-build.sh19
-rw-r--r--misc/tremulous-banner.jpgbin0 -> 40385 bytes
-rw-r--r--misc/tremulous.icobin0 -> 198 bytes
-rw-r--r--misc/tremulous.xpm90
-rw-r--r--scripts/README.md52
-rw-r--r--scripts/binds.lua77
-rw-r--r--scripts/granger/lib/init.lua5
-rw-r--r--scripts/granger/lib/os.lua222
-rw-r--r--scripts/granger/lib/path.lua137
-rw-r--r--scripts/granger/lib/string.lua50
-rw-r--r--scripts/granger/lib/table.lua181
-rw-r--r--scripts/granger/main.lua63
-rw-r--r--scripts/granger/util.lua28
-rw-r--r--scripts/http.lua40
-rw-r--r--scripts/inspect.lua218
-rw-r--r--scripts/sample-httpjson-client.lua37
-rw-r--r--scripts/test-nettle.lua24
-rw-r--r--src/asm/matha.s55
-rw-r--r--src/asm/qasm-inline.h41
-rw-r--r--src/asm/qasm.h39
-rw-r--r--src/asm/snapvector.asm91
-rw-r--r--src/asm/snapvector.c75
-rw-r--r--src/asm/snd_mixa.s217
-rw-r--r--src/asm/vm_x86_64.asm59
-rw-r--r--src/cgame/CMakeLists.txt83
-rw-r--r--src/cgame/binaryshader.h42
-rw-r--r--src/cgame/cg_animation.c13
-rw-r--r--src/cgame/cg_animmapobj.c15
-rw-r--r--src/cgame/cg_attachment.c9
-rw-r--r--src/cgame/cg_buildable.c410
-rw-r--r--src/cgame/cg_consolecmds.c293
-rw-r--r--src/cgame/cg_draw.c2941
-rw-r--r--src/cgame/cg_drawtools.c107
-rw-r--r--src/cgame/cg_ents.c226
-rw-r--r--src/cgame/cg_event.c474
-rw-r--r--src/cgame/cg_local.h463
-rw-r--r--src/cgame/cg_main.c837
-rw-r--r--src/cgame/cg_marks.c11
-rw-r--r--src/cgame/cg_mem.c202
-rw-r--r--src/cgame/cg_particles.c737
-rw-r--r--src/cgame/cg_players.c416
-rw-r--r--src/cgame/cg_playerstate.c34
-rw-r--r--src/cgame/cg_predict.c51
-rw-r--r--src/cgame/cg_ptr.c81
-rw-r--r--src/cgame/cg_public.h413
-rw-r--r--src/cgame/cg_rangemarker.c399
-rw-r--r--src/cgame/cg_scanner.c165
-rw-r--r--src/cgame/cg_servercmds.c1235
-rw-r--r--src/cgame/cg_snapshot.c20
-rw-r--r--src/cgame/cg_syscalls.asm4
-rw-r--r--src/cgame/cg_syscalls.c54
-rw-r--r--src/cgame/cg_syscalls_11.asm3
-rw-r--r--src/cgame/cg_trails.c61
-rw-r--r--src/cgame/cg_tutorial.c280
-rw-r--r--src/cgame/cg_view.c563
-rw-r--r--src/cgame/cg_weapons.c657
-rw-r--r--src/client/CMakeLists.txt209
-rw-r--r--src/client/cl_avi.cpp664
-rw-r--r--src/client/cl_cgame.cpp1172
-rw-r--r--src/client/cl_cin.cpp1937
-rw-r--r--src/client/cl_console.cpp877
-rw-r--r--src/client/cl_curl.cpp364
-rw-r--r--src/client/cl_curl.h101
-rw-r--r--src/client/cl_input.cpp1194
-rw-r--r--src/client/cl_keys.cpp1665
-rw-r--r--src/client/cl_main.cpp5083
-rw-r--r--src/client/cl_net_chan.cpp190
-rw-r--r--src/client/cl_parse.cpp961
-rw-r--r--src/client/cl_rest.cpp117
-rw-r--r--src/client/cl_rest.h18
-rw-r--r--src/client/cl_scrn.cpp588
-rw-r--r--src/client/cl_ui.cpp1269
-rw-r--r--src/client/cl_updates.cpp476
-rw-r--r--src/client/cl_updates.h8
-rw-r--r--src/client/client.h716
-rw-r--r--src/client/keycodes.h42
-rw-r--r--src/client/keys.h66
-rw-r--r--src/client/libmumblelink.cpp190
-rw-r--r--src/client/libmumblelink.h41
-rw-r--r--src/client/qal.cpp337
-rw-r--r--src/client/qal.h252
-rw-r--r--src/client/snd_adpcm.cpp329
-rw-r--r--src/client/snd_codec.cpp239
-rw-r--r--src/client/snd_codec.h109
-rw-r--r--src/client/snd_codec_ogg.cpp479
-rw-r--r--src/client/snd_codec_opus.cpp452
-rw-r--r--src/client/snd_codec_wav.cpp293
-rw-r--r--src/client/snd_dma.cpp1644
-rw-r--r--src/client/snd_local.h267
-rw-r--r--src/client/snd_main.cpp566
-rw-r--r--src/client/snd_mem.cpp297
-rw-r--r--src/client/snd_mix.cpp792
-rw-r--r--src/client/snd_openal.cpp2737
-rw-r--r--src/client/snd_public.h88
-rw-r--r--src/client/snd_wavelet.cpp252
-rw-r--r--src/game/CMakeLists.txt70
-rw-r--r--src/game/bg_alloc.c (renamed from src/game/g_mem.c)138
-rw-r--r--src/game/bg_lib.c1390
-rw-r--r--src/game/bg_lib.h52
-rw-r--r--src/game/bg_local.h16
-rw-r--r--src/game/bg_misc.c4714
-rw-r--r--src/game/bg_pmove.c1164
-rw-r--r--src/game/bg_public.h912
-rw-r--r--src/game/bg_shared.h0
-rw-r--r--src/game/bg_slidemove.c38
-rw-r--r--src/game/bg_voice.c653
-rw-r--r--src/game/g_active.c1329
-rw-r--r--src/game/g_admin.c9006
-rw-r--r--src/game/g_admin.h314
-rw-r--r--src/game/g_buildable.c4821
-rw-r--r--src/game/g_client.c1428
-rw-r--r--src/game/g_cmds.c6080
-rw-r--r--src/game/g_combat.c1479
-rw-r--r--src/game/g_local.h1011
-rw-r--r--src/game/g_main.c1808
-rw-r--r--src/game/g_maprotation.c1538
-rw-r--r--src/game/g_misc.c60
-rw-r--r--src/game/g_missile.c266
-rw-r--r--src/game/g_mover.c453
-rw-r--r--src/game/g_namelog.c128
-rw-r--r--src/game/g_physics.c42
-rw-r--r--src/game/g_playermodel.c193
-rw-r--r--src/game/g_ptr.c143
-rw-r--r--src/game/g_public.h342
-rw-r--r--src/game/g_session.c68
-rw-r--r--src/game/g_spawn.c366
-rw-r--r--src/game/g_svcmds.c898
-rw-r--r--src/game/g_syscalls.asm3
-rw-r--r--src/game/g_syscalls.c47
-rw-r--r--src/game/g_target.c109
-rw-r--r--src/game/g_team.c457
-rw-r--r--src/game/g_trigger.c193
-rw-r--r--src/game/g_utils.c464
-rw-r--r--src/game/g_weapon.c1158
-rw-r--r--src/game/g_weapondrop.c199
-rw-r--r--src/game/tremulous.h424
-rw-r--r--src/granger/COPYING622
-rw-r--r--src/granger/Dockerfile4
-rw-r--r--src/granger/README.md139
-rw-r--r--src/granger/appveyor.yml32
-rw-r--r--src/granger/misc/docker-build.sh7
-rw-r--r--src/granger/src/CMakeLists.txt60
-rw-r--r--src/granger/src/getopt.h653
-rw-r--r--src/granger/src/lnettlelib.c181
-rw-r--r--src/granger/src/lnettlelib.h25
-rw-r--r--src/granger/src/lua/CMakeLists.txt57
-rw-r--r--src/granger/src/main.c97
-rw-r--r--src/granger/src/nettle/CMakeLists.txt23
-rw-r--r--src/granger/src/nettle/macros.h245
-rw-r--r--src/granger/src/nettle/md5-compress.c174
-rw-r--r--src/granger/src/nettle/md5.c93
-rw-r--r--src/granger/src/nettle/md5.h86
-rw-r--r--src/granger/src/nettle/nettle-stdint.h6
-rw-r--r--src/granger/src/nettle/nettle-types.h110
-rw-r--r--src/granger/src/nettle/nettle-write.h58
-rw-r--r--src/granger/src/nettle/sha2.h206
-rw-r--r--src/granger/src/nettle/sha256-compress.c199
-rw-r--r--src/granger/src/nettle/sha256.c162
-rw-r--r--src/granger/src/nettle/version.h58
-rw-r--r--src/granger/src/nettle/write-be32.c77
-rw-r--r--src/granger/src/nettle/write-le32.c69
-rw-r--r--src/granger/src/premake/CMakeLists.txt32
-rw-r--r--src/granger/src/premake/os_access.c58
-rw-r--r--src/granger/src/premake/os_chdir.c32
-rw-r--r--src/granger/src/premake/os_copyfile.c34
-rw-r--r--src/granger/src/premake/os_elevate.c240
-rw-r--r--src/granger/src/premake/os_getcwd.c36
-rw-r--r--src/granger/src/premake/os_is64bit.c30
-rw-r--r--src/granger/src/premake/os_isdir.c34
-rw-r--r--src/granger/src/premake/os_isfile.c30
-rw-r--r--src/granger/src/premake/os_match.c181
-rw-r--r--src/granger/src/premake/os_mkdir.c33
-rw-r--r--src/granger/src/premake/os_pathsearch.c84
-rw-r--r--src/granger/src/premake/os_rmdir.c33
-rw-r--r--src/granger/src/premake/os_stat.c46
-rw-r--r--src/granger/src/premake/path_getabsolute.c102
-rw-r--r--src/granger/src/premake/path_getrelative.c80
-rw-r--r--src/granger/src/premake/path_isabsolute.c27
-rw-r--r--src/granger/src/premake/path_join.c58
-rw-r--r--src/granger/src/premake/path_normalize.c77
-rw-r--r--src/granger/src/premake/path_translate.c61
-rw-r--r--src/granger/src/premake/premake.c171
-rw-r--r--src/granger/src/premake/premake.h90
-rw-r--r--src/granger/src/premake/string_endswith.c28
-rw-r--r--src/granger/src/strvec.c156
-rw-r--r--src/granger/src/strvec.h36
-rw-r--r--src/granger/test/main.lua11
-rw-r--r--src/granger/test/test-nettle.lua33
-rw-r--r--src/granger/test/test-os-access.lua17
-rw-r--r--src/null/null_client.cpp95
-rw-r--r--src/null/null_glimp.cpp63
-rw-r--r--src/null/null_input.cpp37
-rw-r--r--src/null/null_main.cpp83
-rw-r--r--src/null/null_net.cpp55
-rw-r--r--src/null/null_snddma.cpp62
-rw-r--r--src/qcommon/CMakeLists.txt54
-rw-r--r--src/qcommon/alternatePlayerstate.h75
-rw-r--r--src/qcommon/cdefs.h79
-rw-r--r--src/qcommon/cm_load.cpp1022
-rw-r--r--src/qcommon/cm_local.h225
-rw-r--r--src/qcommon/cm_patch.cpp1801
-rw-r--r--src/qcommon/cm_patch.h105
-rw-r--r--src/qcommon/cm_polylib.cpp737
-rw-r--r--src/qcommon/cm_polylib.h74
-rw-r--r--src/qcommon/cm_public.h79
-rw-r--r--src/qcommon/cm_test.cpp526
-rw-r--r--src/qcommon/cm_trace.cpp1801
-rw-r--r--src/qcommon/cmd.cpp941
-rw-r--r--src/qcommon/cmd.h115
-rw-r--r--src/qcommon/common.cpp3662
-rw-r--r--src/qcommon/crypto.cpp92
-rw-r--r--src/qcommon/crypto.h45
-rw-r--r--src/qcommon/cvar.cpp1498
-rw-r--r--src/qcommon/cvar.h199
-rw-r--r--src/qcommon/files.cpp3986
-rw-r--r--src/qcommon/files.h286
-rw-r--r--src/qcommon/huffman.cpp558
-rw-r--r--src/qcommon/huffman.h59
-rw-r--r--src/qcommon/ioapi.cpp373
-rw-r--r--src/qcommon/ioapi.h173
-rw-r--r--src/qcommon/json.h353
-rw-r--r--src/qcommon/md4.cpp202
-rw-r--r--src/qcommon/md4.h6
-rw-r--r--src/qcommon/md5.cpp312
-rw-r--r--src/qcommon/msg.cpp2248
-rw-r--r--src/qcommon/msg.h79
-rw-r--r--src/qcommon/net.h145
-rw-r--r--src/qcommon/net_chan.cpp697
-rw-r--r--src/qcommon/net_ip.cpp1842
-rw-r--r--src/qcommon/parse.cpp3725
-rw-r--r--src/qcommon/puff.cpp759
-rw-r--r--src/qcommon/puff.h43
-rw-r--r--src/qcommon/q3_lauxlib.cpp46
-rw-r--r--src/qcommon/q3_lauxlib.h46
-rw-r--r--src/qcommon/q_math.c610
-rw-r--r--src/qcommon/q_platform.h112
-rw-r--r--src/qcommon/q_shared.c634
-rw-r--r--src/qcommon/q_shared.h761
-rw-r--r--src/qcommon/qcommon.h413
-rw-r--r--src/qcommon/qfiles.h634
-rw-r--r--src/qcommon/surfaceflags.h21
-rw-r--r--src/qcommon/unzip.cpp1951
-rw-r--r--src/qcommon/unzip.h321
-rw-r--r--src/qcommon/vm.cpp1020
-rw-r--r--src/qcommon/vm.h67
-rw-r--r--src/qcommon/vm_interpreted.cpp904
-rw-r--r--src/qcommon/vm_local.h204
-rw-r--r--src/qcommon/vm_x86.cpp1840
-rw-r--r--src/renderercommon/CMakeLists.txt77
-rw-r--r--src/renderercommon/iqm.h131
-rw-r--r--src/renderercommon/qgl.h570
-rw-r--r--src/renderercommon/tr_common.h166
-rw-r--r--src/renderercommon/tr_font.cpp562
-rw-r--r--src/renderercommon/tr_image_bmp.cpp240
-rw-r--r--src/renderercommon/tr_image_jpg.cpp479
-rw-r--r--src/renderercommon/tr_image_pcx.cpp177
-rw-r--r--src/renderercommon/tr_image_png.cpp2486
-rw-r--r--src/renderercommon/tr_image_tga.cpp317
-rw-r--r--src/renderercommon/tr_noise.cpp93
-rw-r--r--src/renderercommon/tr_public.h199
-rw-r--r--src/renderercommon/tr_types.h (renamed from src/renderer/tr_types.h)92
-rw-r--r--src/renderergl1/CMakeLists.txt67
-rw-r--r--src/renderergl1/tr_animation.cpp523
-rw-r--r--src/renderergl1/tr_backend.cpp1163
-rw-r--r--src/renderergl1/tr_bsp.cpp1869
-rw-r--r--src/renderergl1/tr_cmds.cpp601
-rw-r--r--src/renderergl1/tr_curve.cpp627
-rw-r--r--src/renderergl1/tr_flares.cpp540
-rw-r--r--src/renderergl1/tr_image.cpp1680
-rw-r--r--src/renderergl1/tr_init.cpp1299
-rw-r--r--src/renderergl1/tr_light.cpp402
-rw-r--r--src/renderergl1/tr_local.h1603
-rw-r--r--src/renderergl1/tr_main.cpp1394
-rw-r--r--src/renderergl1/tr_marks.cpp459
-rw-r--r--src/renderergl1/tr_mesh.cpp413
-rw-r--r--src/renderergl1/tr_model.cpp1120
-rw-r--r--src/renderergl1/tr_model_iqm.cpp1187
-rw-r--r--src/renderergl1/tr_scene.cpp413
-rw-r--r--src/renderergl1/tr_shade.cpp1522
-rw-r--r--src/renderergl1/tr_shade_calc.cpp1212
-rw-r--r--src/renderergl1/tr_shader.cpp3158
-rw-r--r--src/renderergl1/tr_shadows.cpp327
-rw-r--r--src/renderergl1/tr_sky.cpp796
-rw-r--r--src/renderergl1/tr_subs.cpp50
-rw-r--r--src/renderergl1/tr_surface.cpp1239
-rw-r--r--src/renderergl1/tr_world.cpp670
-rw-r--r--src/renderergl2/CMakeLists.txt146
-rw-r--r--src/renderergl2/glsl/bokeh_fp.glsl70
-rw-r--r--src/renderergl2/glsl/bokeh_vp.glsl13
-rw-r--r--src/renderergl2/glsl/calclevels4x_fp.glsl60
-rw-r--r--src/renderergl2/glsl/calclevels4x_vp.glsl13
-rw-r--r--src/renderergl2/glsl/depthblur_fp.glsl82
-rw-r--r--src/renderergl2/glsl/depthblur_vp.glsl16
-rw-r--r--src/renderergl2/glsl/dlight_fp.glsl32
-rw-r--r--src/renderergl2/glsl/dlight_vp.glsl92
-rw-r--r--src/renderergl2/glsl/down4x_fp.glsl34
-rw-r--r--src/renderergl2/glsl/down4x_vp.glsl13
-rw-r--r--src/renderergl2/glsl/fogpass_fp.glsl9
-rw-r--r--src/renderergl2/glsl/fogpass_vp.glsl117
-rw-r--r--src/renderergl2/glsl/generic_fp.glsl33
-rw-r--r--src/renderergl2/glsl/generic_vp.glsl239
-rw-r--r--src/renderergl2/glsl/lightall_fp.glsl429
-rw-r--r--src/renderergl2/glsl/lightall_vp.glsl246
-rw-r--r--src/renderergl2/glsl/pshadow_fp.glsl78
-rw-r--r--src/renderergl2/glsl/pshadow_vp.glsl15
-rw-r--r--src/renderergl2/glsl/shadowfill_fp.glsl41
-rw-r--r--src/renderergl2/glsl/shadowfill_vp.glsl89
-rw-r--r--src/renderergl2/glsl/shadowmask_fp.glsl143
-rw-r--r--src/renderergl2/glsl/shadowmask_vp.glsl18
-rw-r--r--src/renderergl2/glsl/ssao_fp.glsl86
-rw-r--r--src/renderergl2/glsl/ssao_vp.glsl12
-rw-r--r--src/renderergl2/glsl/texturecolor_fp.glsl10
-rw-r--r--src/renderergl2/glsl/texturecolor_vp.glsl13
-rw-r--r--src/renderergl2/glsl/tonemap_fp.glsl57
-rw-r--r--src/renderergl2/glsl/tonemap_vp.glsl27
-rw-r--r--src/renderergl2/tr_animation.cpp525
-rw-r--r--src/renderergl2/tr_backend.cpp1817
-rw-r--r--src/renderergl2/tr_bsp.cpp3046
-rw-r--r--src/renderergl2/tr_cmds.cpp672
-rw-r--r--src/renderergl2/tr_curve.cpp741
-rw-r--r--src/renderergl2/tr_dsa.cpp287
-rw-r--r--src/renderergl2/tr_dsa.h80
-rw-r--r--src/renderergl2/tr_extensions.cpp279
-rw-r--r--src/renderergl2/tr_extramath.cpp248
-rw-r--r--src/renderergl2/tr_extramath.h104
-rw-r--r--src/renderergl2/tr_extratypes.h40
-rw-r--r--src/renderergl2/tr_fbo.cpp659
-rw-r--r--src/renderergl2/tr_fbo.h66
-rw-r--r--src/renderergl2/tr_flares.cpp554
-rw-r--r--src/renderergl2/tr_glsl.cpp1470
-rw-r--r--src/renderergl2/tr_image.cpp3235
-rw-r--r--src/renderergl2/tr_image_dds.cpp499
-rw-r--r--src/renderergl2/tr_init.cpp1534
-rw-r--r--src/renderergl2/tr_light.cpp513
-rw-r--r--src/renderergl2/tr_local.h2422
-rw-r--r--src/renderergl2/tr_main.cpp2669
-rw-r--r--src/renderergl2/tr_marks.cpp472
-rw-r--r--src/renderergl2/tr_mesh.cpp418
-rw-r--r--src/renderergl2/tr_model.cpp1419
-rw-r--r--src/renderergl2/tr_model_iqm.cpp1196
-rw-r--r--src/renderergl2/tr_postprocess.cpp484
-rw-r--r--src/renderergl2/tr_postprocess.h34
-rw-r--r--src/renderergl2/tr_scene.cpp575
-rw-r--r--src/renderergl2/tr_shade.cpp1634
-rw-r--r--src/renderergl2/tr_shade_calc.cpp843
-rw-r--r--src/renderergl2/tr_shader.cpp3891
-rw-r--r--src/renderergl2/tr_shadows.cpp327
-rw-r--r--src/renderergl2/tr_sky.cpp904
-rw-r--r--src/renderergl2/tr_subs.cpp49
-rw-r--r--src/renderergl2/tr_surface.cpp1320
-rw-r--r--src/renderergl2/tr_vbo.cpp945
-rw-r--r--src/renderergl2/tr_world.cpp811
-rw-r--r--src/script/CMakeLists.txt35
-rw-r--r--src/script/bind.h107
-rw-r--r--src/script/client.h54
-rw-r--r--src/script/cmd.h50
-rw-r--r--src/script/cvar.h146
-rw-r--r--src/script/http_client.h65
-rw-r--r--src/script/lnettlelib.c94
-rw-r--r--src/script/lnettlelib.h15
-rw-r--r--src/script/nettle.h41
-rw-r--r--src/script/rapidjson.h52
-rw-r--r--src/script/rapidjson/LICENSE19
-rw-r--r--src/script/rapidjson/document.cpp194
-rw-r--r--src/script/rapidjson/file.hpp21
-rw-r--r--src/script/rapidjson/luax.hpp82
-rw-r--r--src/script/rapidjson/rapidjson.cpp414
-rw-r--r--src/script/rapidjson/schema.cpp116
-rw-r--r--src/script/rapidjson/userdata.hpp112
-rw-r--r--src/script/rapidjson/values.cpp108
-rw-r--r--src/script/rapidjson/values.hpp245
-rw-r--r--src/sdl/CMakeLists.txt8
-rw-r--r--src/sdl/sdl_gamma.cpp100
-rw-r--r--src/sdl/sdl_glimp.cpp935
-rw-r--r--src/sdl/sdl_icon.h138
-rw-r--r--src/sdl/sdl_input.cpp1336
-rw-r--r--src/sdl/sdl_snd.cpp298
-rw-r--r--src/server/CMakeLists.txt114
-rw-r--r--src/server/server.h529
-rw-r--r--src/server/sv_admin.cpp0
-rw-r--r--src/server/sv_admin.h61
-rw-r--r--src/server/sv_ccmds.cpp441
-rw-r--r--src/server/sv_client.cpp1949
-rw-r--r--src/server/sv_game.cpp602
-rw-r--r--src/server/sv_init.cpp1004
-rw-r--r--src/server/sv_main.cpp1551
-rw-r--r--src/server/sv_net_chan.cpp259
-rw-r--r--src/server/sv_snapshot.cpp749
-rw-r--r--src/server/sv_world.cpp745
-rw-r--r--src/sys/CMakeLists.txt15
-rw-r--r--src/sys/con_log.cpp132
-rw-r--r--src/sys/con_passive.cpp72
-rw-r--r--src/sys/con_tty.cpp552
-rw-r--r--src/sys/con_win32.cpp558
-rw-r--r--src/sys/dialog.h40
-rw-r--r--src/sys/sys_loadlib.h57
-rw-r--r--src/sys/sys_local.h58
-rw-r--r--src/sys/sys_main.cpp798
-rw-r--r--src/sys/sys_osx.mm103
-rw-r--r--src/sys/sys_shared.h111
-rw-r--r--src/sys/sys_unix.cpp1006
-rw-r--r--src/sys/sys_win32.cpp842
-rw-r--r--src/sys/sys_win32_default_homepath.cpp52
-rw-r--r--src/sys/win_resource.h46
-rw-r--r--src/sys/win_resource.rc72
-rw-r--r--src/tools/CMakeLists.txt145
-rw-r--r--src/tools/asm/cmdlib.c9
-rw-r--r--src/tools/asm/cmdlib.h9
-rw-r--r--src/tools/asm/mathlib.h9
-rw-r--r--src/tools/asm/opstrings.h11
-rw-r--r--src/tools/asm/q3asm.c17
-rw-r--r--src/tools/asm/qfiles.h480
-rw-r--r--src/tools/lcc/cpp/cpp.c621
-rw-r--r--src/tools/lcc/cpp/include.c268
-rw-r--r--src/tools/lcc/cpp/unix.c215
-rw-r--r--src/tools/lcc/etc/bytecode.c2
-rw-r--r--src/tools/lcc/etc/lcc.c1465
-rw-r--r--src/tools/lcc/lburg/gram.c72
-rw-r--r--src/tools/lcc/lburg/gram.y1
-rw-r--r--src/tools/lcc/src/dag.c1494
-rw-r--r--src/ui/CMakeLists.txt67
-rw-r--r--src/ui/menudef.h363
-rw-r--r--src/ui/ui_atoms.c620
-rw-r--r--src/ui/ui_gameinfo.c482
-rw-r--r--src/ui/ui_local.h1455
-rw-r--r--src/ui/ui_main.c9532
-rw-r--r--src/ui/ui_players.c1369
-rw-r--r--src/ui/ui_public.h303
-rw-r--r--src/ui/ui_shared.c11444
-rw-r--r--src/ui/ui_shared.h681
-rw-r--r--src/ui/ui_syscalls.asm3
-rw-r--r--src/ui/ui_syscalls.c413
-rw-r--r--src/ui/ui_syscalls_11.asm2
-rw-r--r--ui/assets/alien/buildstat/frame.tgabin1724 -> 0 bytes
-rw-r--r--ui/assets/alien/buildstat/mark.tgabin14180 -> 0 bytes
-rw-r--r--ui/assets/alien/buildstat/nopower.tgabin21285 -> 0 bytes
-rw-r--r--ui/assets/alien/buildstat/overlay.tgabin25069 -> 0 bytes
-rw-r--r--ui/assets/human/buildstat/frame.tgabin1724 -> 0 bytes
-rw-r--r--ui/assets/human/buildstat/mark.tgabin14180 -> 0 bytes
-rw-r--r--ui/assets/human/buildstat/nopower.tgabin19244 -> 0 bytes
-rw-r--r--ui/drop.menu126
-rw-r--r--ui/ingame_game.menu3206
-rw-r--r--ui/ingame_options.menu2180
-rw-r--r--ui/joinserver.menu687
-rw-r--r--ui/main.menu163
-rw-r--r--ui/menudef.h363
-rw-r--r--ui/menus.txt20
-rw-r--r--ui/options.menu287
-rw-r--r--ui/say.menu91
-rw-r--r--ui/teamscore.menu305
-rw-r--r--ui/tremulous_alien_builder_hud.menu371
-rw-r--r--ui/tremulous_alien_general_hud.menu360
-rw-r--r--ui/tremulous_default_hud.menu165
-rw-r--r--ui/tremulous_human_hud.menu462
1357 files changed, 534555 insertions, 59534 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..9f8db6d
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,87 @@
+# vim:ft=yaml
+Language: Cpp
+AccessModifierOffset: -4
+AlignAfterOpenBracket: DontAlign
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: true
+AlignOperands: true
+AlignTrailingComments: false
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: false
+ AfterControlStatement: true
+ AfterEnum: false
+ AfterFunction: true
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: true
+ BeforeElse: true
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit: 120
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: true
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeCategories:
+ - Regex: '^<.*\.h>'
+ Priority: 1
+ - Regex: '^<.*'
+ Priority: 2
+ - Regex: '.*'
+ Priority: 3
+IndentCaseLabels: true
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: false
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Left
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Auto
+TabWidth: 8
+UseTab: Never
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..85b97a9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,43 @@
+build
+Makefile.local
+*.swp
+*tags
+misc/patches
+misc/last-merged-ioq3-revision.temp
+*~
+
+# OS X
+####################
+.Spotlight-V100/
+.Trashes/
+._*
+.AppleDouble
+.DS_Store
+.LSOverride
+Icon?
+
+# Xcode
+####################
+*.mode1v3
+*.mode2v3
+*.pbxuser
+*.perspectivev3
+*.user
+*.xcuserstate
+*.moved-aside
+*~.nib
+.idea/
+DerivedData/
+project.xcworkspace/
+xcuserdata/
+profile
+!default.pbxuser
+!default.mode1v3
+!default.mode2v3
+!default.perspectivev3
+
+# Microsoft Visual Studio
+####################
+*.sdf
+*.opensdf
+*.suo
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..b420d8b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,57 @@
+language: cpp
+sudo: required
+dist: trusty
+services:
+- docker
+git:
+ depth: 5
+notifications:
+ slack:
+ secure: iS767Cc5C6lnDADvTqt5aypq4XaVWvgqJsdWTV1ia6E8tGxzbf/jRtRkKQkzEFrnN7xjc/q93/Gd1kcJFwyq0vA0eeX8GhnlJx1mPxktgeguNiKzCaiBmyLiixpwy/yClHdvrmv/mnR4PbkaG4tYBod6n4BpnaQQNqL3V0ie25rF4PJtpos+QQmQzCxzEU8nXm9f54pYVfVX5v9rkz0vmltX7GceYayvcMHipBCaoYDJNQqVAGr0jt+wfw93BFHsOb+EQBCB4Gw5MRNfiDeYRjrI6SXkPeb6S0R7c7fOGnk68hDI1j9Yp1i+VRpxbKRGwEeWHXhI6A7XeUenSdDvIZp/42nubdmQcXjeCLk6NRGflWPpwk5Evy74csN12hjE+cGfQpI9/oKnufly15+8BQL+PUGtaFa8rU2UfevdK32IpMeOeY5XbH6KQ4OXLAzW5211tZZaL0BTZp2TEdTskgtSDuyq3oNDAkWxH9BQYtWbAVqRgPu1nl5oXj9IG+q2UI1QG0JuKQ9hduFlyQ8NSCXVcQOQwpzW3CDAMSUl2Pe00/djgi6sdHu3i3ur9HEnrniwskl+VElUXPJYmA82U1UVF6NFhySS64y3QRdHNXNs7iQBTywbjSRSVW6YQB4bW8JY2ykyaJEjpXtXSumEYFjLvRFhU0cZDU4lqiO7ZlA=
+ irc:
+ - ircs://chat.freenode.net:7070#grangerhub
+ email:
+ on_success: change
+ on_failure: change
+matrix:
+ include:
+ - os: linux
+ env: PLATFORM=linux
+ before_install:
+ - docker pull grangerhub/tremulous13:latest
+ - docker run -e PLATFORM -v $(pwd):/usr/src grangerhub/tremulous13:latest ./misc/docker-build.sh
+ script:
+ - true
+ - os: linux
+ env: PLATFORM=mingw32
+ before_install:
+ - docker pull grangerhub/tremulous13:latest
+ - docker run -e PLATFORM -v $(pwd):/usr/src grangerhub/tremulous13:latest ./misc/docker-build.sh
+ script:
+ - true
+ - os: linux
+ env: PLATFORM=mingw32 ARCH=x86
+ before_install:
+ - docker pull grangerhub/tremulous13:latest
+ - docker run -e ARCH -e PLATFORM -v $(pwd):/usr/src grangerhub/tremulous13:latest
+ ./misc/docker-build.sh
+ script:
+ - true
+ - os: osx
+ osx_image: xcode8
+ compiler: clang
+ env: ARCH=x86_64
+ before_install:
+ - rm -rf build
+ script:
+ - "./misc/travis-ci-build.sh"
+deploy:
+ provider: releases
+ skip_cleanup: true
+ api_key:
+ secure: "jtNUkZL1TK3nD1LfWi5kypaL2WzUHxM/N72AcwKTmvieQ/3iwL8gRDFOhfWKFkNcyuCsEBw+c2KlpgfNGVNZYJgZrQ3Ozvnno5yN+V8Pb4ODEFU0Ps4EHSY7gsdF6bBdp3ooqsCsg8BkGfIggFsV+R9oKOyWWH1/N1jPWhf8ioWD+mMaAh5ZOsyQIECtSKAKMu9/hikVkdDuNsIAiaiJhYvP8rli5fYrZ4sVJih3YgeJj42i2iLeeWXmOmYNF7T5ywuBpaUjQJBEo83MilglTF0UOb471ADU2Gz3SMrnNCOdqDZLQaBL+QVrrgJUvXy5A92nxkY16mJaIvdDEOeIzWwgWVLoKyil6AFW5bR7lp2YW+/4I6zYEkGrpUaiZ+S1lgvm3CwVgwhg3rVuCi0qrI/7j/ImS9ORmz9DGbVgtg+y7mZnUIcEWX4jRDbbYWYIc/1fN+fGt73+41h0HS5of7d31yH6AyxB8/DlkuoKZIVHiErD0J3ZUkdVJOwhPFiPKViYR/07KEvafhkZkcffZh7arIesFB++4Kmglapb/awHJRh4lhfKd16IiCGjjfof8MDKSkmqAdXUsdCRcPu1Q0/cJaO3TRiTS6M0skrBUeIOOYsV0AdWM1Fy7dTySEEYlqZXnkiD98MG7CwobkWXmeVZHEzOJh2fDtv2w2ojoDI="
+ file_glob: true
+ file: build/*.zip
+ on:
+ repo: GrangerHub/tremulous
+ tags: true
diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py
new file mode 100644
index 0000000..0d255af
--- /dev/null
+++ b/.ycm_extra_conf.py
@@ -0,0 +1,118 @@
+# This file is NOT licensed under the GPLv3, which is the license for the rest
+# of YouCompleteMe.
+# For more information, please refer to <http://unlicense.org/>
+
+import os
+import sys
+import ycm_core
+
+def log(msg):
+ filename = "/Users/viroemer/extra.txt"
+ with open(filename, 'a') as f:
+ f.write('%s\n' % msg)
+
+
+source_root = os.path.dirname( os.path.abspath( __file__ ) )
+build_root = os.path.join( source_root, 'build' )
+
+# These are the compilation flags that will be used in case there's no
+# compilation database set (by default, one is not set).
+# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
+#flags = [
+# '-x', 'c++',
+# '--std=c++14',
+#
+# '-Weverything',
+# '-Wall',
+# '-Wextra',
+# '-Werror',
+# '-pedantic',
+# '-isystem', '/usr/include',
+# '-isystem', '/usr/local/include',
+# '-isystem', '/usr/local/opt/openssl/include',
+# '-UNDEBUG'
+#]
+
+if os.path.exists(os.path.join(build_root, 'compile_commands.json')):
+ print("Hello world")
+ database = ycm_core.CompilationDatabase(build_root)
+else:
+ database = None
+
+SOURCE_EXTENSIONS = [ '.cpp', '.cc', '.h', '.hpp' ]
+
+def DirectoryOfThisScript():
+ return os.path.dirname( os.path.abspath( __file__ ) )
+
+
+def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
+ if not working_directory:
+ return list( flags )
+ new_flags = []
+ make_next_absolute = False
+ path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
+ for flag in flags:
+ new_flag = flag
+
+ if make_next_absolute:
+ make_next_absolute = False
+ if not flag.startswith( '/' ):
+ new_flag = os.path.join( working_directory, flag )
+
+ for path_flag in path_flags:
+ if flag == path_flag:
+ make_next_absolute = True
+ break
+
+ if flag.startswith( path_flag ):
+ path = flag[ len( path_flag ): ]
+ new_flag = path_flag + os.path.join( working_directory, path )
+ break
+
+ if new_flag:
+ new_flags.append( new_flag )
+ return new_flags
+
+
+def IsHeaderFile( filename ):
+ extension = os.path.splitext( filename )[ 1 ]
+ return extension in [ '.h' ]
+
+
+def GetCompilationInfoForFile( filename ):
+ # The compilation_commands.json file generated by CMake does not have entries
+ # for header files. So we do our best by asking the db for flags for a
+ # corresponding source file, if any. If one exists, the flags for that file
+ # should be good enough.
+ if IsHeaderFile( filename ):
+ basename = os.path.splitext( filename )[ 0 ]
+ for extension in SOURCE_EXTENSIONS:
+ replacement_file = basename + extension
+ if os.path.exists( replacement_file ):
+
+ compilation_info = database.GetCompilationInfoForFile( replacement_file )
+ if compilation_info.compiler_flags_:
+ return compilation_info
+ return None
+ return database.GetCompilationInfoForFile( filename )
+
+def FlagsForFile( filename, **kwargs ):
+ if database:
+ # Bear in mind that compilation_info.compiler_flags_ does NOT return a
+ # python list, but a "list-like" StringVec object
+ compilation_info = GetCompilationInfoForFile( filename )
+ if not compilation_info:
+ return None
+
+ final_flags = MakeRelativePathsInFlagsAbsolute(
+ compilation_info.compiler_flags_,
+ compilation_info.compiler_working_dir_ )
+
+ else:
+ relative_to = DirectoryOfThisScript()
+ final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
+
+ return {
+ 'flags': final_flags,
+ 'do_cache': True
+ }
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..1890031
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,136 @@
+
+# M""""""""M dP #
+# Mmmm mmmM 88 #
+# MMMM MMMM 88d888b. .d8888b. 88d8b.d8b. dP dP 88 .d8888b. dP dP .d8888b. #
+# MMMM MMMM 88' `88 88ooood8 88'`88'`88 88 88 88 88' `88 88 88 Y8ooooo. #
+# MMMM MMMM 88 88. ... 88 88 88 88. .88 88 88. .88 88. .88 88 #
+# MMMM MMMM dP `88888P' dP dP dP `88888P' dP `88888P' `88888P' `88888P' #
+# MMMMMMMMMM #
+
+
+cmake_minimum_required(VERSION 3.5)
+project(Tremulous C CXX)
+
+set(CMAKE_CXX_FLAGS -std=c++1y)
+set(CMAKE_C_FLAGS -std=gnu99)
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+endif()
+
+# XXX This one doesn't work yet
+option(USE_RENDERER_DLOPEN "" ON)
+
+# These are not used at the moment
+if (APPLE OR WIN32)
+ option(USE_INTERNAL_SDL2 "" ON)
+else ()
+ option(USE_INTERNAL_SDL2 "" OFF)
+endif()
+
+option(USE_INTERNAL_JPEG "" ON)
+option(USE_OPENAL "" ON)
+option(USE_OPENAL_DLOPEN "" ON)
+option(USE_VOIP "" OFF)
+option(USE_MUMBLE "" OFF)
+option(USE_CODEC_OPUS "" ON)
+option(USE_RESTCLIENT "" ON)
+
+include(${CMAKE_SOURCE_DIR}/cmake/build_dir)
+include(${CMAKE_SOURCE_DIR}/cmake/debug_cflags)
+
+# builtins
+add_subdirectory(external/SDL2)
+add_subdirectory(external/lua-5.3.3)
+add_subdirectory(external/nettle-3.3)
+add_subdirectory(external/zlib)
+add_subdirectory(external/jpeg-8c)
+add_subdirectory(external/restclient)
+
+# audio
+add_subdirectory(external/opus-1.1.4)
+add_subdirectory(external/opusfile-0.8)
+add_subdirectory(external/libogg-1.3.2)
+add_subdirectory(external/libvorbis-1.3.5)
+
+# engine
+add_subdirectory(src/script)
+add_subdirectory(src/renderercommon)
+add_subdirectory(src/renderergl1)
+add_subdirectory(src/renderergl2)
+
+# . .
+# ___ | ` ___ , __ _/_
+# .' ` | | .' ` |' `. |
+# | | | |----' | | |
+# `._.' /\__ / `.___, / | \__/
+#
+
+add_subdirectory(src/client)
+
+# ____ ___ .___ _ __ ___ .___
+# ( .' ` / \ | / .' ` / \
+# `--. |----' | ' ` / |----' | '
+# \___.' `.___, / \/ `.___, /
+#
+
+add_subdirectory(src/server)
+
+# ___
+# .' \ .___ ___ , __ ___. ___ .___
+# | / \ / ` |' `. .' ` .' ` / \
+# | _ | ' | | | | | | |----' | '
+# `.___| / `.__/| / | `---| `.___, /
+# \___/
+
+if(BUILD_GRANGER)
+ add_subdirectory(src/granger/src)
+endif(BUILD_GRANGER)
+
+# _______ ___ ___ _______ __ __
+# | | | | | | .----.-----.--------.-----.|__| |.-----.----.
+# | - _| | | | | __| _ | | _ || | || -__| _|
+# |_______|\_____/|__|_|__| |____|_____|__|__|__| __||__|__||_____|__|
+# |__|
+# TODO: DO NOT build unless building a QVM
+
+add_subdirectory(src/tools)
+
+#
+# , . `
+# | | |
+# | | |
+# `._/| /
+#
+
+add_subdirectory(src/ui)
+
+# ___. ___ , _ , _ ___
+# .' ` / ` |' `|' `. .' `
+# | | | | | | | |----'
+# `---| `.__/| / ' / `.___,
+# \___/
+#
+
+add_subdirectory(src/game)
+
+# ___ ___. ___ , _ , _ ___
+# .' ` .' ` / ` |' `|' `. .' `
+# | | | | | | | | |----'
+# `._.' `---| `.__/| / ' / `.___,
+# \___/
+#
+
+add_subdirectory(src/cgame)
+
+# _____) ____ ___)
+# / (, / / /)
+# / ___ __ _ __ _ _ __ /---/ (/_ _ ______
+# / / ) / (_(_(_/ (_(_/__(/_/ (_) / (__(_(_/_) o (__(_) // (_
+# (____ / .-/ (_/
+# (_/
+
+# Author: Victor Roemer wtfbbqhax, <victor@badsec.org>.
+# Date: Sat Nov 5 06:49:08 2016
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..9518bd1
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,175 @@
+1.1.0
+-----
+
+ Feature/balance changes
+ -----------------------
+ * Quick fullscreen changes
+ * Fancy autocompletion
+ * Client now sleeps when inactive
+ * Persistent console history
+ * Increase boost time to 30 seconds from 20 seconds
+ * Lcannon now has a minimum charge value
+ * Flamer damage down to 20 from 31
+ * Zap repeat rate down to 1500ms from 2000ms
+ * Knockback from pouncing now 3 times as strong
+ * Demo state now displayed from cgame
+ * AVI video capture
+ * cl_autoRecordDemo
+ * Master server, based on dpmaster
+ * Changed defaults for r_picmip and r_textureMode
+ * Chat sounds differ depending on team
+ * New collision type, for improved light flares
+ * New pain blend effect
+ * Reduced Dragoon pounce range to 64 from 96
+ * Dragoon pounce now incurs 400ms wait before other weapons may be used
+ * Trapper cost down to 8 from 10
+ * Hovel is now free, but only one can be built
+ * Teslagen damage up to 9 from 7
+ * Non locational damage does not apply locational armour anymore; instead it
+ averages the armour regions together
+ * Added target_alien_win and target_human_win
+ * Added worldspawn keys to disable specific game elements
+ * 3D particles
+ * Brass ejections now done via particle system
+ * static_tranform particle move type
+ * thirdPersonOnly particle and trail system property
+ * Abstract attachment system
+ * Scriptable trails system
+
+ Bug fixes/development issues
+ ----------------------------
+ * Fix to a server memory leak
+ * Fix to a server 100% CPU bug
+ * Delete key on *nix fixed
+ * Fixed lcannon charge storage exploit
+ * Fixed psaw/cgun inappropriate effects bug
+ * Maps on create server menu now sorted by name
+ * Fixed death by poison MOD s/antitox/medkit/
+ * Fixed Marauders momentarily disappearing when wall jumping
+ * Fixed a potential crash bug involving the use of generic1
+ * Fixed being able to build multiple coincident repeaters if there is no reactor
+ * Fixed incorrect message when invoking "buy ammo" with an energy weapon and no
+ reactor present
+ * Fixed invoking "reload" during a weapon reload causing an unnecessary reload
+ * Fixed aliens having the wrong blood colour when shot with a las gun
+ * Fixed hovel causing invisible builders
+
+1.0.2
+-----
+
+ Feature/balance changes
+ -----------------------
+ * Extended STATS report to include the times when stages change
+ * Increased Tesla damage frequency
+ * Marginally increased Tesla damage
+ * Teslas now produce exaggerated knockback effect
+ * Hives now buildable on walls
+ * Boosters no longer restore Dragoon spitballs
+ * Dragoon spitballs now affected by gravity
+ * Dragoon pounce attack damage reduced to 100 from 160
+ * Removed jump pad code (and associated media loading)
+ * Removed loading of some Q3 cruft
+ * Corpses timeout in 20 seconds instead of 60
+
+ Bug fixes/development issues
+ ----------------------------
+ * Fixed a silly bug with using the reactor/repeater
+ * Spilled events attached to temporary entities are now reattached
+ to their original entities, fixing the missing flame bug
+ * Fixed "suicide god" bug
+ * Fixed bug where zap ignores armour
+ * Fixed missing particle systems when follow-spectating
+ * Fixed potential bug involving dodgy pointer arithmetic in
+ CG_LoadClientInfo
+ * Cleaned up logic in CG_AddPlayerWeapon
+ * MASK_SHOT traces no longer collide with corpses
+ * Improved robustness of spawn validation, fixing the bug on transit
+ * A crapload of whitespace fixes
+
+1.0.1
+-----
+
+ Feature/balance changes
+ -----------------------
+ * cg_debugParticles >= 1 now prints to the console when particle
+ systems are parsed and registered
+ * Reverted walk/run animation switching back to cmd.buttons instead
+ of basing it on speed
+ * Added option for changing whether or not the wallwalk control is a
+ toggle or not
+ * Weapon now drops momentarily when reloading
+ * The stage kill counters are now incremented for structure kills if
+ players did more then 50% of the total damage
+ * Removed the mp3 decoder from the source
+ * Marauder lightning now requires aim, does damage over time and
+ chains to other entities
+ * Implemented the Medkit -- a means for a human to restore health
+ and cure poison in the field
+ * "Disable Build Warnings" replaced with "Disable Warning
+ Dialogs" and improved
+ * Sped spectator move speed up
+ * Implemented "step down" physics for all characters; no more
+ jumping down stairs
+ * Increased frequency with which the Acid Tube deals damage
+ * Tyrant can no longer charge up forever and must pass a specific
+ minimum charge level
+ * Implemented command queueing for commands sent to clients in order
+ to prevent overflows even sv_floodProtect is off, but not by
+ dropping commands
+ * Added LOS check to creep slowing
+ * Overmind now only complains if there are 0 spawns
+ * Spawns can no longer be built when there is no Overmind/Reactor
+ * The spawn closest to the point of death is chosen preferably if
+ available
+ * Evolving no longer restores all health
+ * "give weapons" and "give ammo" cheats removed
+ * When selling the battery pack, max ammo is given
+ * Added stage information to the end of game stats
+ * Reduced Dragoon spitball damage from 120 to 110
+ * Reduced Tyrant claw damage from 120 to 100
+ * Reduced Tyrant charge damage from 160 to 110
+ * Increased Barricade regeneration rate from 12 to 14
+ * Increased Overmind health from 500 to 750
+ * Decreased Overmind regeneration rate from 10 to 6
+ * Doubled Blaster speed from 700 to 1400
+ * Reduced Painsaw damage from 18 to 15
+ * Reduced Painsaw range from 48.0 to 40.0
+ * Reduced Grenade price from 300 to 200
+ * Reduced Shotgun repeat rate from 1200 to 1000
+ * Increased Shotgun damage from 6 to 7
+ * Increased Mass driver damage from 35 to 38
+ * Increased Chaingun damage from 5 to 6
+ * Reduced Flamer repeat rate from 300 to 200
+ * Extended Flamer range
+ * Increased ammo on all human weapons
+ * Reduced splashdamage on MG Turrets
+
+
+ Bug fixes/development issues
+ ----------------------------
+ * Hacked around trap_LinkEntity to allow missiles to have a bounding
+ box displayed
+ * Fixed "Server command overflow" bug for clients that should time
+ out
+ * Fixed a bug where only live clients would have their scores logged
+ at the end of the game
+ * Reworked how weapon changes are performed, fixing bugs in the
+ process
+ * Fixed the issue where the Mac qvm JIT compiler would not compile
+ Tremulous
+ * Reimplemented how buildables play damage sounds to not use the
+ event system
+ * Reworked the ammo/clips packing system to remove the confusion of
+ concepts
+ * Disabled client side ET_MISSILE collision
+ * G_RadiusSelectiveDamage no longer applies locational damage
+ * Moved some speed adjustment code into prediction; should prevent
+ some prediction misses
+ * Wrapped all calls to trap_SendServerCommand in order to circumvent
+ the q3amsgboom.cfg exploit
+ * Fixed restoration of energy weapons bug
+ * Fixed a bug where locational damage could sometimes scale damage
+ to 0
+ * Added G_ClosestEnt
+ * Moved build directory from tremulous to tremulous-dev
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..d3e3bd4
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,5 @@
+FROM ubuntu:bionic
+WORKDIR /usr/src
+ENV DEBIAN_FRONTEND=noninteractive
+RUN apt update -y
+RUN apt install -y curl cmake libgl1-mesa-dev libsdl2-dev libcurl4-openssl-dev libopenal-dev libfreetype6-dev mingw-w64 g++-mingw-w64 g++-multilib git zip vim-nox rsync
diff --git a/GNUmakefile b/GNUmakefile
deleted file mode 100644
index ee68145..0000000
--- a/GNUmakefile
+++ /dev/null
@@ -1,1292 +0,0 @@
-#
-# Tremulous Makefile
-#
-# GNU Make required
-#
-
-COMPILE_PLATFORM=$(shell uname | sed -e 's/_.*//' | tr '[:upper:]' '[:lower:]' | sed -e 's/\//_/g')
-COMPILE_ARCH=$(shell uname -m | sed -e 's/i.86/x86/' | sed -e 's/^arm.*/arm/')
-
-ifeq ($(COMPILE_PLATFORM),sunos)
- # Solaris uname and GNU uname differ
- COMPILE_ARCH=$(shell uname -p | sed -e 's/i.86/x86/')
-endif
-
-ifndef BUILD_GAME_SO
- BUILD_GAME_SO = 0
-endif
-ifndef BUILD_GAME_QVM
- BUILD_GAME_QVM = 1
-endif
-ifndef BUILD_GAME_QVM_11
- BUILD_GAME_QVM_11= 1
-endif
-ifndef BUILD_ONLY_GAME
- BUILD_ONLY_GAME = 0
-endif
-ifndef BUILD_ONLY_CGUI
- BUILD_ONLY_CGUI = 0
-endif
-
-#############################################################################
-#
-# If you require a different configuration from the defaults below, create a
-# new file named "Makefile.local" in the same directory as this file and define
-# your parameters there. This allows you to change configuration without
-# causing problems with keeping up to date with the repository.
-#
-#############################################################################
--include GNUmakefile.local
-
-include $(SETTINGS_MAKEFILES)
-
-ifeq ($(COMPILE_PLATFORM),cygwin)
- PLATFORM=mingw32
-endif
-
-ifndef PLATFORM
-PLATFORM=$(COMPILE_PLATFORM)
-endif
-export PLATFORM
-
-ifeq ($(COMPILE_ARCH),i86pc)
- COMPILE_ARCH=x86
-endif
-
-ifeq ($(COMPILE_ARCH),amd64)
- COMPILE_ARCH=x86_64
-endif
-ifeq ($(COMPILE_ARCH),x64)
- COMPILE_ARCH=x86_64
-endif
-
-ifeq ($(COMPILE_ARCH),powerpc)
- COMPILE_ARCH=ppc
-endif
-ifeq ($(COMPILE_ARCH),powerpc64)
- COMPILE_ARCH=ppc64
-endif
-
-ifeq ($(COMPILE_ARCH),axp)
- COMPILE_ARCH=alpha
-endif
-
-ifndef ARCH
-ARCH=$(COMPILE_ARCH)
-endif
-export ARCH
-
-ifneq ($(PLATFORM),$(COMPILE_PLATFORM))
- CROSS_COMPILING=1
-else
- CROSS_COMPILING=0
-
- ifneq ($(ARCH),$(COMPILE_ARCH))
- CROSS_COMPILING=1
- endif
-endif
-export CROSS_COMPILING
-
-ifndef VERSION
-VERSION=aa
-endif
-
-ifndef CLIENTBIN
-CLIENTBIN=tremulous
-endif
-
-ifndef BASEGAME
-BASEGAME=slacker
-endif
-
-ifndef BASEGAME_CFLAGS
-BASEGAME_CFLAGS=
-endif
-
-ifndef COPYDIR
-COPYDIR="/usr/local/games/tremulous"
-endif
-
-ifndef COPYBINDIR
-COPYBINDIR=$(COPYDIR)
-endif
-
-ifndef MOUNT_DIR
-MOUNT_DIR=src
-endif
-
-ifndef ASSETS_DIR
-ASSETS_DIR=assets
-endif
-
-ifndef BUILD_DIR
-BUILD_DIR=bld
-endif
-
-ifndef TEMPDIR
-TEMPDIR=/tmp
-endif
-
-ifndef DEBUG_CFLAGS
-DEBUG_CFLAGS=-g -O0
-endif
-
-#############################################################################
-
-BD=$(BUILD_DIR) # /debug-$(PLATFORM)-$(ARCH)
-BR=$(BUILD_DIR) # /release-$(PLATFORM)-$(ARCH)
-CDIR=$(MOUNT_DIR)/client
-SDIR=$(MOUNT_DIR)/server
-CMDIR=$(MOUNT_DIR)/qcommon
-GDIR=$(MOUNT_DIR)/game
-CGDIR=$(MOUNT_DIR)/cgame
-NDIR=$(MOUNT_DIR)/null
-UIDIR=$(MOUNT_DIR)/ui
-Q3ASMDIR=$(MOUNT_DIR)/tools/asm
-LBURGDIR=$(MOUNT_DIR)/tools/lcc/lburg
-Q3CPPDIR=$(MOUNT_DIR)/tools/lcc/cpp
-Q3LCCETCDIR=$(MOUNT_DIR)/tools/lcc/etc
-Q3LCCSRCDIR=$(MOUNT_DIR)/tools/lcc/src
-TEMPDIR=/tmp
-
-# Add git version info
-USE_GIT=
-ifeq ($(wildcard .git),.git)
- GIT_REV=$(shell git describe --tag)
- ifneq ($(GIT_REV),)
- VERSION:=$(GIT_REV)
- USE_GIT=1
- endif
-endif
-
-#############################################################################
-# SETUP AND BUILD -- LINUX
-#############################################################################
-
-## Defaults
-LIB=lib
-
-INSTALL=install
-MKDIR=mkdir
-
-ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu"))
-
- ifeq ($(ARCH),x86_64)
- LIB=lib64
- else
- ifeq ($(ARCH),ppc64)
- LIB=lib64
- else
- ifeq ($(ARCH),s390x)
- LIB=lib64
- endif
- endif
- endif
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -pipe -DUSE_ICON
-
- OPTIMIZEVM = -O3 -funroll-loops -fomit-frame-pointer
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
-
- ifeq ($(ARCH),x86_64)
- OPTIMIZEVM = -O3 -fomit-frame-pointer -funroll-loops \
- -falign-functions=2 -fstrength-reduce
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
- HAVE_VM_COMPILED = true
- else
- ifeq ($(ARCH),x86)
- OPTIMIZEVM = -O3 -march=i586 -fomit-frame-pointer \
- -funroll-loops -falign-functions=2 -fstrength-reduce
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
- HAVE_VM_COMPILED=true
- else
- ifeq ($(ARCH),ppc)
- BASE_CFLAGS += -maltivec
- HAVE_VM_COMPILED=true
- endif
- ifeq ($(ARCH),ppc64)
- BASE_CFLAGS += -maltivec
- HAVE_VM_COMPILED=true
- endif
- ifeq ($(ARCH),sparc)
- OPTIMIZE += -mtune=ultrasparc3 -mv8plus
- OPTIMIZEVM += -mtune=ultrasparc3 -mv8plus
- HAVE_VM_COMPILED=true
- endif
- ifeq ($(ARCH),alpha)
- # According to http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=410555
- # -ffast-math will cause the client to die with SIGFPE on Alpha
- OPTIMIZE = $(OPTIMIZEVM)
- endif
- endif
- endif
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC -fvisibility=hidden
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- THREAD_LIBS=-lpthread
- LIBS=-ldl -lm
-
- ifeq ($(ARCH),x86)
- # linux32 make ...
- BASE_CFLAGS += -m32
- else
- ifeq ($(ARCH),ppc64)
- BASE_CFLAGS += -m64
- endif
- endif
-else # ifeq Linux
-
-#############################################################################
-# SETUP AND BUILD -- MAC OS X
-#############################################################################
-
-ifeq ($(PLATFORM),darwin)
- HAVE_VM_COMPILED=true
- LIBS = -framework Cocoa
- OPTIMIZEVM=
-
- BASE_CFLAGS = -Wall -Wimplicit -Wstrict-prototypes -mmacosx-version-min=10.5 \
- -DMAC_OS_X_VERSION_MIN_REQUIRED=1050
-
- ifeq ($(ARCH),ppc)
- BASE_CFLAGS += -arch ppc -faltivec
- OPTIMIZEVM += -O3
- endif
- ifeq ($(ARCH),ppc64)
- BASE_CFLAGS += -arch ppc64 -faltivec
- endif
- ifeq ($(ARCH),x86)
- OPTIMIZEVM += -mfpmath=387+sse
- # x86 vm will crash without -mstackrealign since MMX instructions will be
- # used no matter what and they corrupt the frame pointer in VM calls
- BASE_CFLAGS += -arch i386 -m32 -mstackrealign
- endif
- ifeq ($(ARCH),x86_64)
- OPTIMIZEVM += -arch x86_64 -mfpmath=sse -msse2
- endif
-
- # When compiling on OSX for OSX, we're not cross compiling as far as the
- # Makefile is concerned, as target architecture is specified as a compiler
- # argument
- ifeq ($(COMPILE_PLATFORM),darwin)
- CROSS_COMPILING=0
- endif
-
-
- ifeq ($(CROSS_COMPILING),1)
- ifeq ($(ARCH),x86_64)
- CC=x86_64-apple-darwin13-cc
- RANLIB=x86_64-apple-darwin13-ranlib
- else
- ifeq ($(ARCH),x86)
- CC=i386-apple-darwin13-cc
- RANLIB=i386-apple-darwin13-ranlib
- else
- $(error Architecture $(ARCH) is not supported when cross compiling)
- endif
- endif
- else
- TOOLS_CFLAGS += -DMACOS_X
- endif
-
- BASE_CFLAGS += -fno-strict-aliasing -DMACOS_X -fno-common -pipe
-
- BASE_CFLAGS += -D_THREAD_SAFE=1
-
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
-
- SHLIBEXT=dylib
- SHLIBCFLAGS=-fPIC -fno-common
- SHLIBLDFLAGS=-dynamiclib $(LDFLAGS) -Wl,-U,_com_altivec
-
- NOTSHLIBCFLAGS=-mdynamic-no-pic
-
-else # ifeq darwin
-
-
-#############################################################################
-# SETUP AND BUILD -- MINGW32
-#############################################################################
-
-ifeq ($(PLATFORM),mingw32)
-
- ifeq ($(CROSS_COMPILING),1)
- # If CC is already set to something generic, we probably want to use
- # something more specific
- ifneq ($(findstring $(strip $(CC)),cc gcc),)
- CC=
- endif
-
- # We need to figure out the correct gcc and windres
- ifeq ($(ARCH),x86_64)
- MINGW_PREFIXES=amd64-mingw32msvc x86_64-w64-mingw32
- endif
- ifeq ($(ARCH),x86)
- MINGW_PREFIXES=i586-mingw32msvc i686-w64-mingw32
- endif
-
- ifndef CC
- CC=$(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), \
- $(call bin_path, $(MINGW_PREFIX)-gcc)))
- endif
- else
- # Some MinGW installations define CC to cc, but don't actually provide cc,
- # so check that CC points to a real binary and use gcc if it doesn't
- ifeq ($(call bin_path, $(CC)),)
- CC=gcc
- endif
- endif
-
- ifeq ($(CC),)
- $(error Cannot find a suitable cross compiler for $(PLATFORM))
- endif
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -DUSE_ICON
-
- # In the absence of wspiapi.h, require Windows XP or later
- ifeq ($(shell test -e $(CMDIR)/wspiapi.h; echo $$?),1)
- BASE_CFLAGS += -DWINVER=0x501
- endif
-
- ifeq ($(ARCH),x86_64)
- OPTIMIZEVM = -O3 -fno-omit-frame-pointer \
- -funroll-loops -falign-functions=2 -fstrength-reduce
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
- HAVE_VM_COMPILED = true
- endif
- ifeq ($(ARCH),x86)
- OPTIMIZEVM = -O3 -march=i586 -fno-omit-frame-pointer \
- -funroll-loops -falign-functions=2 -fstrength-reduce
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
- HAVE_VM_COMPILED = true
- endif
-
- SHLIBEXT=dll
- SHLIBCFLAGS=
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- ifeq ($(CROSS_COMPILING),0)
- TOOLS_BINEXT=.exe
- endif
-
- ifeq ($(COMPILE_PLATFORM),cygwin)
- TOOLS_BINEXT=.exe
- TOOLS_CC=$(CC)
- endif
-
- LIBS= -lws2_32 -lwinmm -lpsapi
-
- ifeq ($(ARCH),x86)
- # build 32bit
- BASE_CFLAGS += -m32
- else
- BASE_CFLAGS += -m64
- endif
-
-else # ifeq mingw32
-
-#############################################################################
-# SETUP AND BUILD -- FREEBSD
-#############################################################################
-
-ifeq ($(PLATFORM),freebsd)
-
- # flags
- BASE_CFLAGS = -Wall -fno-strict-aliasing -DUSE_ICON
- HAVE_VM_COMPILED = true
-
- OPTIMIZEVM = -O3 -funroll-loops -fomit-frame-pointer
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- # don't need -ldl (FreeBSD)
- LIBS=-lm
-
- # cross-compiling tweaks
- ifeq ($(ARCH),x86)
- ifeq ($(CROSS_COMPILING),1)
- BASE_CFLAGS += -m32
- endif
- endif
- ifeq ($(ARCH),x86_64)
- ifeq ($(CROSS_COMPILING),1)
- BASE_CFLAGS += -m64
- endif
- endif
-else # ifeq freebsd
-
-#############################################################################
-# SETUP AND BUILD -- OPENBSD
-#############################################################################
-
-ifeq ($(PLATFORM),openbsd)
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -pipe -DUSE_ICON -DMAP_ANONYMOUS=MAP_ANON
-
- OPTIMIZEVM = -O3 -funroll-loops -fomit-frame-pointer
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
-
- ifeq ($(ARCH),x86_64)
- OPTIMIZEVM = -O3 -fomit-frame-pointer -funroll-loops \
- -falign-functions=2 -fstrength-reduce
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
- HAVE_VM_COMPILED = true
- else
- ifeq ($(ARCH),x86)
- OPTIMIZEVM = -O3 -march=i586 -fomit-frame-pointer \
- -funroll-loops -falign-functions=2 -fstrength-reduce
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
- HAVE_VM_COMPILED=true
- else
- ifeq ($(ARCH),ppc)
- BASE_CFLAGS += -maltivec
- HAVE_VM_COMPILED=true
- endif
- ifeq ($(ARCH),ppc64)
- BASE_CFLAGS += -maltivec
- HAVE_VM_COMPILED=true
- endif
- ifeq ($(ARCH),sparc64)
- OPTIMIZE += -mtune=ultrasparc3 -mv8plus
- OPTIMIZEVM += -mtune=ultrasparc3 -mv8plus
- HAVE_VM_COMPILED=true
- endif
- ifeq ($(ARCH),alpha)
- # According to http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=410555
- # -ffast-math will cause the client to die with SIGFPE on Alpha
- OPTIMIZE = $(OPTIMIZEVM)
- endif
- endif
- endif
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- THREAD_LIBS=-lpthread
- LIBS=-lm
-else # ifeq openbsd
-
-#############################################################################
-# SETUP AND BUILD -- NETBSD
-#############################################################################
-
-ifeq ($(PLATFORM),netbsd)
-
- LIBS=-lm
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
- THREAD_LIBS=-lpthread
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes
-
- ifeq ($(ARCH),x86)
- HAVE_VM_COMPILED=true
- endif
-else # ifeq netbsd
-
-#############################################################################
-# SETUP AND BUILD -- IRIX
-#############################################################################
-
-ifeq ($(PLATFORM),irix64)
-
- ARCH=mips
-
- CC = c99
- MKDIR = mkdir -p
-
- BASE_CFLAGS=-Dstricmp=strcasecmp -Xcpluscomm -woff 1185 \
- -I. -I$(ROOT)/usr/include
- OPTIMIZE = -O3
-
- SHLIBEXT=so
- SHLIBCFLAGS=
- SHLIBLDFLAGS=-shared
-
- LIBS=-ldl -lm -lgen
-else # ifeq IRIX
-
-#############################################################################
-# SETUP AND BUILD -- SunOS
-#############################################################################
-
-ifeq ($(PLATFORM),sunos)
-
- CC=gcc
- INSTALL=ginstall
- MKDIR=gmkdir
- COPYDIR="/usr/local/share/games/tremulous"
-
- ifneq ($(ARCH),x86)
- ifneq ($(ARCH),sparc)
- $(error arch $(ARCH) is currently not supported)
- endif
- endif
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -pipe -DUSE_ICON
-
- OPTIMIZEVM = -O3 -funroll-loops
-
- ifeq ($(ARCH),sparc)
- OPTIMIZEVM += -O3 \
- -fstrength-reduce -falign-functions=2 \
- -mtune=ultrasparc3 -mv8plus -mno-faster-structs
- HAVE_VM_COMPILED=true
- else
- ifeq ($(ARCH),x86)
- OPTIMIZEVM += -march=i586 -fomit-frame-pointer \
- -falign-functions=2 -fstrength-reduce
- HAVE_VM_COMPILED=true
- BASE_CFLAGS += -m32
- endif
- endif
-
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- THREAD_LIBS=-lpthread
- LIBS=-lsocket -lnsl -ldl -lm
-else # ifeq sunos
-
-#############################################################################
-# SETUP AND BUILD -- GENERIC
-#############################################################################
- BASE_CFLAGS=
- OPTIMIZE = -O3
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared
-
-endif #Linux
-endif #darwin
-endif #mingw32
-endif #FreeBSD
-endif #OpenBSD
-endif #NetBSD
-endif #IRIX
-endif #SunOS
-
-ifndef CC
- CC=gcc
-endif
-
-ifndef RANLIB
- RANLIB=ranlib
-endif
-
-ifneq ($(HAVE_VM_COMPILED),true)
- BASE_CFLAGS += -DNO_VM_COMPILED
- BUILD_GAME_QVM=0
-endif
-
-TARGETS =
-
-ifndef FULLBINEXT
- FULLBINEXT=$(BINEXT)
-endif
-
-ifndef SHLIBNAME
- SHLIBNAME=.$(SHLIBEXT)
-endif
-
-ifneq ($(BUILD_GAME_SO),0)
- ifeq ($(BUILD_ONLY_GAME),1)
- TARGETS += \
- $(B)/out/$(BASEGAME)/game$(SHLIBNAME)
- else
- ifeq ($(BUILD_ONLY_CGUI),1)
- TARGETS += \
- $(B)/out/$(BASEGAME)/cgame$(SHLIBNAME) \
- $(B)/out/$(BASEGAME)/ui$(SHLIBNAME)
- else
- TARGETS += \
- $(B)/out/$(BASEGAME)/cgame$(SHLIBNAME) \
- $(B)/out/$(BASEGAME)/game$(SHLIBNAME) \
- $(B)/out/$(BASEGAME)/ui$(SHLIBNAME)
- endif
- endif
-endif
-
-ifneq ($(BUILD_GAME_QVM),0)
- ifeq ($(BUILD_ONLY_GAME),1)
- TARGETS += \
- $(B)/out/$(BASEGAME)/vm/game.qvm
- else
- ifeq ($(BUILD_ONLY_CGUI),1)
- TARGETS += \
- $(B)/out/$(BASEGAME)/vm/cgame.qvm \
- $(B)/out/$(BASEGAME)/vm/ui.qvm \
- $(B)/out/$(BASEGAME)/vms-gpp1-$(VERSION).pk3
- else
- TARGETS += \
- $(B)/out/$(BASEGAME)/vm/cgame.qvm \
- $(B)/out/$(BASEGAME)/vm/game.qvm \
- $(B)/out/$(BASEGAME)/vm/ui.qvm \
- $(B)/out/$(BASEGAME)/vms-gpp1-$(VERSION).pk3
- endif
- endif
-endif
-
-ifneq ($(BUILD_GAME_QVM_11),0)
- ifneq ($(BUILD_ONLY_GAME),1)
- TARGETS += \
- $(B)/out/$(BASEGAME)_11/vm/cgame.qvm \
- $(B)/out/$(BASEGAME)_11/vm/ui.qvm \
- $(B)/out/$(BASEGAME)_11/vms-1.1.0-$(VERSION).pk3
- endif
-endif
-
-ifeq ("$(CC)", $(findstring "$(CC)", "clang" "clang++"))
- BASE_CFLAGS += -Qunused-arguments
-endif
-
-ifdef DEFAULT_BASEDIR
- BASE_CFLAGS += -DDEFAULT_BASEDIR=\\\"$(DEFAULT_BASEDIR)\\\"
-endif
-
-ifeq ($(GENERATE_DEPENDENCIES),1)
- DEPEND_CFLAGS = -MMD
-else
- DEPEND_CFLAGS =
-endif
-
-ifeq ($(NO_STRIP),1)
- STRIP_FLAG =
-else
- STRIP_FLAG = -s
-endif
-
-BASE_CFLAGS += -DPRODUCT_VERSION=\\\"$(VERSION)\\\"
-
-ifeq ($(V),1)
-echo_cmd=@:
-Q=
-else
-echo_cmd=@echo
-Q=@
-endif
-
-ifeq ($(GENERATE_DEPENDENCIES),1)
- DO_QVM_DEP=cat $(@:%.o=%.d) | sed -e 's/\.o/\.asm/g' >> $(@:%.o=%.d)
-endif
-
-define DO_SHLIB_CC
-$(echo_cmd) "SHLIB_CC $<"
-$(Q)$(CC) $(BASEGAME_CFLAGS) $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_GAME_CC
-$(echo_cmd) "GAME_CC $<"
-$(Q)$(CC) $(BASEGAME_CFLAGS) -DGAME $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_CGAME_CC
-$(echo_cmd) "CGAME_CC $<"
-$(Q)$(CC) $(BASEGAME_CFLAGS) -DCGAME $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_UI_CC
-$(echo_cmd) "UI_CC $<"
-$(Q)$(CC) $(BASEGAME_CFLAGS) -DUI $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_AS
-$(echo_cmd) "AS $<"
-$(Q)$(CC) $(CFLAGS) $(OPTIMIZE) -x assembler-with-cpp -o $@ -c $<
-endef
-
-
-#############################################################################
-# MAIN TARGETS
-#############################################################################
-
-default: release
-all: debug release
-
-debug:
- @$(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(BASE_CFLAGS) $(DEPEND_CFLAGS)" \
- OPTIMIZE="$(DEBUG_CFLAGS)" OPTIMIZEVM="$(DEBUG_CFLAGS)" V=$(V)
-
-release:
- @$(MAKE) targets B=$(BR) CFLAGS="$(CFLAGS) $(BASE_CFLAGS) $(DEPEND_CFLAGS)" \
- OPTIMIZE="-DNDEBUG $(OPTIMIZE)" OPTIMIZEVM="-DNDEBUG $(OPTIMIZEVM)" V=$(V)
-
-ifneq ($(call bin_path, tput),)
- TERM_COLUMNS=$(shell echo $$((`tput cols`-4)))
-else
- TERM_COLUMNS=76
-endif
-
-NAKED_TARGETS=$(shell echo $(TARGETS) | sed -e "s!$(B)/!!g")
-
-print_list=@for i in $(1); \
- do \
- echo " $$i"; \
- done
-
-ifneq ($(call bin_path, fmt),)
- print_wrapped=@echo $(1) | fmt -w $(TERM_COLUMNS) | sed -e "s/^\(.*\)$$/ \1/"
-else
- print_wrapped=$(print_list)
-endif
-
-# Create the build directories, check libraries and print out
-# an informational message, then start building
-targets: makedirs
- @echo ""
- @echo "Building in $(B):"
- @echo " PLATFORM: $(PLATFORM)"
- @echo " ARCH: $(ARCH)"
- @echo " VERSION: $(VERSION)"
- @echo " COMPILE_PLATFORM: $(COMPILE_PLATFORM)"
- @echo " COMPILE_ARCH: $(COMPILE_ARCH)"
- @echo " CC: $(CC)"
- @echo ""
- @echo " CFLAGS:"
- $(call print_wrapped, $(CFLAGS) $(OPTIMIZE))
- @echo ""
- @echo " LDFLAGS:"
- $(call print_wrapped, $(LDFLAGS))
- @echo ""
- @echo " LIBS:"
- $(call print_wrapped, $(LIBS))
- @echo ""
- @echo " Output:"
- $(call print_list, $(NAKED_TARGETS))
- @echo ""
-ifneq ($(TARGETS),)
- ifndef DEBUG_MAKEFILE
- @$(MAKE) $(TARGETS) V=$(V)
- endif
-endif
-
-makedirs:
- @if [ ! -d $(BUILD_DIR) ];then $(MKDIR) $(BUILD_DIR);fi
- @if [ ! -d $(B) ];then $(MKDIR) $(B);fi
- @if [ ! -d $(B)/cgame ];then $(MKDIR) $(B)/cgame;fi
- @if [ ! -d $(B)/game ];then $(MKDIR) $(B)/game;fi
- @if [ ! -d $(B)/ui ];then $(MKDIR) $(B)/ui;fi
- @if [ ! -d $(B)/qcommon ];then $(MKDIR) $(B)/qcommon;fi
- @if [ ! -d $(B)/11 ];then $(MKDIR) $(B)/11;fi
- @if [ ! -d $(B)/11/cgame ];then $(MKDIR) $(B)/11/cgame;fi
- @if [ ! -d $(B)/11/ui ];then $(MKDIR) $(B)/11/ui;fi
- @if [ ! -d $(B)/out ];then $(MKDIR) $(B)/out;fi
- @if [ ! -d $(B)/out/$(BASEGAME) ];then $(MKDIR) $(B)/out/$(BASEGAME);fi
- @if [ ! -d $(B)/out/$(BASEGAME)/vm ];then $(MKDIR) $(B)/out/$(BASEGAME)/vm;fi
- @if [ ! -d $(B)/out/$(BASEGAME)_11 ];then $(MKDIR) $(B)/out/$(BASEGAME)_11;fi
- @if [ ! -d $(B)/out/$(BASEGAME)_11/vm ];then $(MKDIR) $(B)/out/$(BASEGAME)_11/vm;fi
- @if [ ! -d $(B)/tools ];then $(MKDIR) $(B)/tools;fi
- @if [ ! -d $(B)/tools/asm ];then $(MKDIR) $(B)/tools/asm;fi
- @if [ ! -d $(B)/tools/etc ];then $(MKDIR) $(B)/tools/etc;fi
- @if [ ! -d $(B)/tools/rcc ];then $(MKDIR) $(B)/tools/rcc;fi
- @if [ ! -d $(B)/tools/cpp ];then $(MKDIR) $(B)/tools/cpp;fi
- @if [ ! -d $(B)/tools/lburg ];then $(MKDIR) $(B)/tools/lburg;fi
-
-#############################################################################
-# QVM BUILD TOOLS
-#############################################################################
-
-ifndef TOOLS_CC
- # A compiler which probably produces native binaries
- TOOLS_CC=$(CC)
-endif
-
-TOOLS_OPTIMIZE = -g -Wall -fno-strict-aliasing
-TOOLS_CFLAGS += $(TOOLS_OPTIMIZE) \
- -DTEMPDIR=\"$(TEMPDIR)\" -DSYSTEM=\"\" \
- -I$(Q3LCCSRCDIR) \
- -I$(LBURGDIR)
-TOOLS_LIBS =
-TOOLS_LDFLAGS =
-
-ifeq ($(GENERATE_DEPENDENCIES),1)
- TOOLS_CFLAGS += -MMD
-endif
-
-define DO_TOOLS_CC
-$(echo_cmd) "TOOLS_CC $<"
-$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) -o $@ -c $<
-endef
-
-define DO_TOOLS_CC_DAGCHECK
-$(echo_cmd) "TOOLS_CC_DAGCHECK $<"
-$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) -Wno-unused -o $@ -c $<
-endef
-
-LBURG = $(B)/tools/lburg/lburg$(TOOLS_BINEXT)
-DAGCHECK_C = $(B)/tools/rcc/dagcheck.c
-Q3RCC = $(B)/tools/q3rcc$(TOOLS_BINEXT)
-Q3CPP = $(B)/tools/q3cpp$(TOOLS_BINEXT)
-Q3LCC = $(B)/tools/q3lcc$(TOOLS_BINEXT)
-Q3ASM = $(B)/tools/q3asm$(TOOLS_BINEXT)
-
-LBURGOBJ= \
- $(B)/tools/lburg/lburg.o \
- $(B)/tools/lburg/gram.o
-
-$(B)/tools/lburg/%.o: $(LBURGDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(LBURG): $(LBURGOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-Q3RCCOBJ = \
- $(B)/tools/rcc/alloc.o \
- $(B)/tools/rcc/bind.o \
- $(B)/tools/rcc/bytecode.o \
- $(B)/tools/rcc/dag.o \
- $(B)/tools/rcc/dagcheck.o \
- $(B)/tools/rcc/decl.o \
- $(B)/tools/rcc/enode.o \
- $(B)/tools/rcc/error.o \
- $(B)/tools/rcc/event.o \
- $(B)/tools/rcc/expr.o \
- $(B)/tools/rcc/gen.o \
- $(B)/tools/rcc/init.o \
- $(B)/tools/rcc/inits.o \
- $(B)/tools/rcc/input.o \
- $(B)/tools/rcc/lex.o \
- $(B)/tools/rcc/list.o \
- $(B)/tools/rcc/main.o \
- $(B)/tools/rcc/null.o \
- $(B)/tools/rcc/output.o \
- $(B)/tools/rcc/prof.o \
- $(B)/tools/rcc/profio.o \
- $(B)/tools/rcc/simp.o \
- $(B)/tools/rcc/stmt.o \
- $(B)/tools/rcc/string.o \
- $(B)/tools/rcc/sym.o \
- $(B)/tools/rcc/symbolic.o \
- $(B)/tools/rcc/trace.o \
- $(B)/tools/rcc/tree.o \
- $(B)/tools/rcc/types.o
-
-$(DAGCHECK_C): $(LBURG) $(Q3LCCSRCDIR)/dagcheck.md
- $(echo_cmd) "LBURG $(Q3LCCSRCDIR)/dagcheck.md"
- $(Q)$(LBURG) $(Q3LCCSRCDIR)/dagcheck.md $@
-
-$(B)/tools/rcc/dagcheck.o: $(DAGCHECK_C)
- $(DO_TOOLS_CC_DAGCHECK)
-
-$(B)/tools/rcc/%.o: $(Q3LCCSRCDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3RCC): $(Q3RCCOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-Q3CPPOBJ = \
- $(B)/tools/cpp/cpp.o \
- $(B)/tools/cpp/lex.o \
- $(B)/tools/cpp/nlist.o \
- $(B)/tools/cpp/tokens.o \
- $(B)/tools/cpp/macro.o \
- $(B)/tools/cpp/eval.o \
- $(B)/tools/cpp/include.o \
- $(B)/tools/cpp/hideset.o \
- $(B)/tools/cpp/getopt.o \
- $(B)/tools/cpp/unix.o
-
-$(B)/tools/cpp/%.o: $(Q3CPPDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3CPP): $(Q3CPPOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-Q3LCCOBJ = \
- $(B)/tools/etc/lcc.o \
- $(B)/tools/etc/bytecode.o
-
-$(B)/tools/etc/%.o: $(Q3LCCETCDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3LCC): $(Q3LCCOBJ) $(Q3RCC) $(Q3CPP)
- $(echo_cmd) "LD $@"
- $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $(Q3LCCOBJ) $(TOOLS_LIBS)
-
-define DO_Q3LCC
-$(echo_cmd) "Q3LCC $<"
-$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -o $@ $<
-endef
-
-define DO_CGAME_Q3LCC
-$(echo_cmd) "CGAME_Q3LCC $<"
-$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DCGAME -o $@ $<
-endef
-
-define DO_CGAME_Q3LCC_11
-$(echo_cmd) "CGAME_Q3LCC_11 $<"
-$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DCGAME -DMODULE_INTERFACE_11 -o $@ $<
-endef
-
-define DO_GAME_Q3LCC
-$(echo_cmd) "GAME_Q3LCC $<"
-$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DGAME -o $@ $<
-endef
-
-define DO_UI_Q3LCC
-$(echo_cmd) "UI_Q3LCC $<"
-$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DUI -o $@ $<
-endef
-
-define DO_UI_Q3LCC_11
-$(echo_cmd) "UI_Q3LCC_11 $<"
-$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DUI -DMODULE_INTERFACE_11 -o $@ $<
-endef
-
-
-Q3ASMOBJ = \
- $(B)/tools/asm/q3asm.o \
- $(B)/tools/asm/cmdlib.o
-
-$(B)/tools/asm/%.o: $(Q3ASMDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3ASM): $(Q3ASMOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-
-#############################################################################
-## TREMULOUS CGAME
-#############################################################################
-
-CGOBJ_ = \
- $(B)/cgame/cg_main.o \
- $(B)/cgame/bg_misc.o \
- $(B)/cgame/bg_pmove.o \
- $(B)/cgame/bg_slidemove.o \
- $(B)/cgame/cg_consolecmds.o \
- $(B)/cgame/cg_buildable.o \
- $(B)/cgame/cg_animation.o \
- $(B)/cgame/cg_animmapobj.o \
- $(B)/cgame/cg_draw.o \
- $(B)/cgame/cg_drawtools.o \
- $(B)/cgame/cg_ents.o \
- $(B)/cgame/cg_event.o \
- $(B)/cgame/cg_marks.o \
- $(B)/cgame/cg_players.o \
- $(B)/cgame/cg_playerstate.o \
- $(B)/cgame/cg_predict.o \
- $(B)/cgame/cg_servercmds.o \
- $(B)/cgame/cg_snapshot.o \
- $(B)/cgame/cg_view.o \
- $(B)/cgame/cg_weapons.o \
- $(B)/cgame/cg_mem.o \
- $(B)/cgame/cg_scanner.o \
- $(B)/cgame/cg_attachment.o \
- $(B)/cgame/cg_trails.o \
- $(B)/cgame/cg_particles.o \
- $(B)/cgame/cg_ptr.o \
- $(B)/cgame/cg_tutorial.o \
- $(B)/cgame/ui_shared.o \
- \
- $(B)/qcommon/q_math.o \
- $(B)/qcommon/q_shared.o
-
-CGOBJ11_ = \
- $(B)/11/cgame/cg_main.o \
- $(B)/cgame/bg_misc.o \
- $(B)/cgame/bg_pmove.o \
- $(B)/cgame/bg_slidemove.o \
- $(B)/cgame/cg_consolecmds.o \
- $(B)/cgame/cg_buildable.o \
- $(B)/cgame/cg_animation.o \
- $(B)/cgame/cg_animmapobj.o \
- $(B)/cgame/cg_draw.o \
- $(B)/cgame/cg_drawtools.o \
- $(B)/cgame/cg_ents.o \
- $(B)/cgame/cg_event.o \
- $(B)/cgame/cg_marks.o \
- $(B)/cgame/cg_players.o \
- $(B)/cgame/cg_playerstate.o \
- $(B)/cgame/cg_predict.o \
- $(B)/11/cgame/cg_servercmds.o \
- $(B)/11/cgame/cg_snapshot.o \
- $(B)/cgame/cg_view.o \
- $(B)/cgame/cg_weapons.o \
- $(B)/cgame/cg_mem.o \
- $(B)/cgame/cg_scanner.o \
- $(B)/cgame/cg_attachment.o \
- $(B)/cgame/cg_trails.o \
- $(B)/cgame/cg_particles.o \
- $(B)/cgame/cg_ptr.o \
- $(B)/cgame/cg_tutorial.o \
- $(B)/cgame/ui_shared.o \
- \
- $(B)/qcommon/q_math.o \
- $(B)/qcommon/q_shared.o
-
-CGOBJ = $(CGOBJ_) $(B)/cgame/cg_syscalls.o
-CGVMOBJ = $(CGOBJ_:%.o=%.asm) $(B)/cgame/bg_lib.asm
-CGVMOBJ11 = $(CGOBJ11_:%.o=%.asm) $(B)/cgame/bg_lib.asm
-
-$(B)/out/$(BASEGAME)/cgame$(SHLIBNAME): $(CGOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(CGOBJ)
-
-$(B)/out/$(BASEGAME)/vm/cgame.qvm: $(CGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(CGVMOBJ) $(CGDIR)/cg_syscalls.asm
-
-$(B)/out/$(BASEGAME)_11/vm/cgame.qvm: $(CGVMOBJ11) $(CGDIR)/cg_syscalls_11.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(CGVMOBJ11) $(CGDIR)/cg_syscalls_11.asm
-
-
-
-#############################################################################
-## TREMULOUS GAME
-#############################################################################
-
-GOBJ_ = \
- $(B)/game/g_main.o \
- $(B)/game/bg_misc.o \
- $(B)/game/bg_pmove.o \
- $(B)/game/bg_slidemove.o \
- $(B)/game/g_mem.o \
- $(B)/game/g_active.o \
- $(B)/game/g_client.o \
- $(B)/game/g_cmds.o \
- $(B)/game/g_combat.o \
- $(B)/game/g_physics.o \
- $(B)/game/g_buildable.o \
- $(B)/game/g_misc.o \
- $(B)/game/g_missile.o \
- $(B)/game/g_mover.o \
- $(B)/game/g_session.o \
- $(B)/game/g_spawn.o \
- $(B)/game/g_svcmds.o \
- $(B)/game/g_target.o \
- $(B)/game/g_team.o \
- $(B)/game/g_trigger.o \
- $(B)/game/g_utils.o \
- $(B)/game/g_maprotation.o \
- $(B)/game/g_ptr.o \
- $(B)/game/g_weapon.o \
- $(B)/game/g_admin.o \
- \
- $(B)/qcommon/q_math.o \
- $(B)/qcommon/q_shared.o
-
-GOBJ = $(GOBJ_) $(B)/game/g_syscalls.o
-GVMOBJ = $(GOBJ_:%.o=%.asm) $(B)/game/bg_lib.asm
-
-$(B)/out/$(BASEGAME)/game$(SHLIBNAME): $(GOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GOBJ)
-
-$(B)/out/$(BASEGAME)/vm/game.qvm: $(GVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(GVMOBJ) $(GDIR)/g_syscalls.asm
-
-
-
-#############################################################################
-## TREMULOUS UI
-#############################################################################
-
-UIOBJ_ = \
- $(B)/ui/ui_main.o \
- $(B)/ui/ui_atoms.o \
- $(B)/ui/ui_players.o \
- $(B)/ui/ui_shared.o \
- $(B)/ui/ui_gameinfo.o \
- \
- $(B)/ui/bg_misc.o \
- $(B)/qcommon/q_math.o \
- $(B)/qcommon/q_shared.o
-
-UIOBJ11_ = \
- $(B)/11/ui/ui_main.o \
- $(B)/ui/ui_atoms.o \
- $(B)/ui/ui_players.o \
- $(B)/ui/ui_shared.o \
- $(B)/ui/ui_gameinfo.o \
- \
- $(B)/ui/bg_misc.o \
- $(B)/qcommon/q_math.o \
- $(B)/qcommon/q_shared.o
-
-UIOBJ = $(UIOBJ_) $(B)/ui/ui_syscalls.o
-UIVMOBJ = $(UIOBJ_:%.o=%.asm) $(B)/ui/bg_lib.asm
-UIVMOBJ11 = $(UIOBJ11_:%.o=%.asm) $(B)/ui/bg_lib.asm
-
-$(B)/out/$(BASEGAME)/ui$(SHLIBNAME): $(UIOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(UIOBJ)
-
-$(B)/out/$(BASEGAME)/vm/ui.qvm: $(UIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(UIVMOBJ) $(UIDIR)/ui_syscalls.asm
-
-$(B)/out/$(BASEGAME)_11/vm/ui.qvm: $(UIVMOBJ11) $(UIDIR)/ui_syscalls_11.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(UIVMOBJ11) $(UIDIR)/ui_syscalls_11.asm
-
-
-#############################################################################
-## QVM Package
-#############################################################################
-
-ifeq ($(BUILD_ONLY_CGUI),0)
- $(B)/out/$(BASEGAME)/vms-gpp1-$(VERSION).pk3: $(B)/out/$(BASEGAME)/vm/ui.qvm $(B)/out/$(BASEGAME)/vm/cgame.qvm $(B)/out/$(BASEGAME)/vm/game.qvm
- @(cd $(B)/out/$(BASEGAME) && zip -r vms-gpp1-$(VERSION).pk3 vm/)
- else
- $(B)/out/$(BASEGAME)/vms-gpp1-$(VERSION).pk3: $(B)/out/$(BASEGAME)/vm/ui.qvm $(B)/out/$(BASEGAME)/vm/cgame.qvm
- @(cd $(B)/out/$(BASEGAME) && zip -r vms-gpp1-$(VERSION).pk3 vm/)
-endif
-
-$(B)/out/$(BASEGAME)_11/vms-1.1.0-$(VERSION).pk3: $(B)/out/$(BASEGAME)_11/vm/ui.qvm $(B)/out/$(BASEGAME)_11/vm/cgame.qvm
- @(cd $(B)/out/$(BASEGAME)_11 && zip -r vms-1.1.0-$(VERSION).pk3 vm/)
-
-#############################################################################
-## Assets Package
-#############################################################################
-
-$(B)/out/$(BASEGAME)/data-$(VERSION).pk3: $(ASSETS_DIR)/ui/main.menu
- @(cd $(ASSETS_DIR) && zip -r data-$(VERSION).pk3 *)
- @mv $(ASSETS_DIR)/data-$(VERSION).pk3 $(B)/out/$(BASEGAME)
-
-#############################################################################
-## GAME MODULE RULES
-#############################################################################
-
-$(B)/cgame/bg_%.o: $(GDIR)/bg_%.c
- $(DO_CGAME_CC)
-
-$(B)/cgame/ui_%.o: $(UIDIR)/ui_%.c
- $(DO_CGAME_CC)
-
-$(B)/cgame/%.o: $(CGDIR)/%.c
- $(DO_CGAME_CC)
-
-$(B)/cgame/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC)
-
-$(B)/cgame/ui_%.asm: $(UIDIR)/ui_%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC)
-
-$(B)/cgame/%.asm: $(CGDIR)/%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC)
-
-$(B)/11/cgame/%.asm: $(CGDIR)/%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC_11)
-
-
-$(B)/game/%.o: $(GDIR)/%.c
- $(DO_GAME_CC)
-
-$(B)/game/%.asm: $(GDIR)/%.c $(Q3LCC)
- $(DO_GAME_Q3LCC)
-
-
-$(B)/ui/bg_%.o: $(GDIR)/bg_%.c
- $(DO_UI_CC)
-
-$(B)/ui/%.o: $(UIDIR)/%.c
- $(DO_UI_CC)
-
-$(B)/ui/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
- $(DO_UI_Q3LCC)
-
-$(B)/ui/%.asm: $(UIDIR)/%.c $(Q3LCC)
- $(DO_UI_Q3LCC)
-
-$(B)/11/ui/%.asm: $(UIDIR)/%.c $(Q3LCC)
- $(DO_UI_Q3LCC_11)
-
-
-$(B)/qcommon/%.o: $(CMDIR)/%.c
- $(DO_SHLIB_CC)
-
-$(B)/qcommon/%.asm: $(CMDIR)/%.c $(Q3LCC)
- $(DO_Q3LCC)
-
-
-#############################################################################
-# MISC
-#############################################################################
-
-OBJ = $(GOBJ) $(CGOBJ) $(UIOBJ) $(CGOBJ11) $(UIOBJ11) \
- $(GVMOBJ) $(CGVMOBJ) $(UIVMOBJ) $(CGVMOBJ11) $(UIVMOBJ11)
-TOOLSOBJ = $(LBURGOBJ) $(Q3CPPOBJ) $(Q3RCCOBJ) $(Q3LCCOBJ) $(Q3ASMOBJ)
-STRINGOBJ = $(Q3R2STRINGOBJ)
-
-clean: clean-debug clean-release
- @$(MAKE) -C $(MASTERDIR) clean
-
-clean-debug:
- @$(MAKE) clean2 B=$(BD)
-
-clean-release:
- @$(MAKE) clean2 B=$(BR)
-
-clean2:
- @echo "CLEAN $(B)"
- @rm -f $(OBJ)
- @rm -f $(OBJ_D_FILES)
- @rm -f $(STRINGOBJ)
- @rm -f $(TARGETS)
-
-toolsclean: toolsclean-debug toolsclean-release
-
-toolsclean-debug:
- @$(MAKE) toolsclean2 B=$(BD)
-
-toolsclean-release:
- @$(MAKE) toolsclean2 B=$(BR)
-
-toolsclean2:
- @echo "TOOLS_CLEAN $(B)"
- @rm -f $(TOOLSOBJ)
- @rm -f $(TOOLSOBJ_D_FILES)
- @rm -f $(LBURG) $(DAGCHECK_C) $(Q3RCC) $(Q3CPP) $(Q3LCC) $(Q3ASM)
-
-distclean: clean toolsclean
- @rm -rf $(BUILD_DIR)
-
-dist:
- git archive --format zip --output $(CLIENTBIN)-$(VERSION).zip HEAD
-
-#############################################################################
-# DEPENDENCIES
-#############################################################################
-
-ifneq ($(B),)
- OBJ_D_FILES=$(filter %.d,$(OBJ:%.o=%.d))
- TOOLSOBJ_D_FILES=$(filter %.d,$(TOOLSOBJ:%.o=%.d))
- -include $(OBJ_D_FILES) $(TOOLSOBJ_D_FILES)
-endif
-
-.PHONY: all clean clean2 clean-debug clean-release copyfiles \
- debug default dist distclean makedirs \
- release targets \
- toolsclean toolsclean2 toolsclean-debug toolsclean-release \
- $(OBJ_D_FILES) $(TOOLSOBJ_D_FILES)
-
-# If the target name contains "clean", don't do a parallel build
-ifneq ($(findstring clean, $(MAKECMDGOALS)),)
-.NOTPARALLEL:
-endif
diff --git a/GPL b/GPL
index 050f1e6..f755e7e 100644
--- a/GPL
+++ b/GPL
@@ -1,281 +1,622 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
+GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+ Preamble
+
+The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
your programs, too.
- When we speak of free software, we are referring to freedom, not
+When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+The precise terms and conditions for copying, distribution and
modification follow.
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
+ TERMS AND CONDITIONS
+
+0. Definitions.
+
+"This License" refers to version 3 of the GNU General Public License.
+
+"Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+"The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+1. Source Code.
+
+The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+The Corresponding Source for a work in source code form is that
+same work.
+
+2. Basic Permissions.
+
+All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+a) The work must carry prominent notices stating that you modified
+it, and giving a relevant date.
+
+b) The work must carry prominent notices stating that it is
+released under this License and any conditions added under section
+7. This requirement modifies the requirement in section 4 to
+"keep intact all notices".
+
+c) You must license the entire work, as a whole, under this
+License to anyone who comes into possession of a copy. This
+License will therefore apply, along with any applicable section 7
+additional terms, to the whole of the work, and all its parts,
+regardless of how they are packaged. This License gives no
+permission to license the work in any other way, but it does not
+invalidate such permission if you have separately received it.
+
+d) If the work has interactive user interfaces, each must display
+Appropriate Legal Notices; however, if the Program has interactive
+interfaces that do not display Appropriate Legal Notices, your
+work need not make them do so.
+
+A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+a) Convey the object code in, or embodied in, a physical product
+(including a physical distribution medium), accompanied by the
+Corresponding Source fixed on a durable physical medium
+customarily used for software interchange.
+
+b) Convey the object code in, or embodied in, a physical product
+(including a physical distribution medium), accompanied by a
+written offer, valid for at least three years and valid for as
+long as you offer spare parts or customer support for that product
+model, to give anyone who possesses the object code either (1) a
+copy of the Corresponding Source for all the software in the
+product that is covered by this License, on a durable physical
+medium customarily used for software interchange, for a price no
+more than your reasonable cost of physically performing this
+conveying of source, or (2) access to copy the
+Corresponding Source from a network server at no charge.
+
+c) Convey individual copies of the object code with a copy of the
+written offer to provide the Corresponding Source. This
+alternative is allowed only occasionally and noncommercially, and
+only if you received the object code with such an offer, in accord
+with subsection 6b.
+
+d) Convey the object code by offering access from a designated
+place (gratis or for a charge), and offer equivalent access to the
+Corresponding Source in the same way through the same place at no
+further charge. You need not require recipients to copy the
+Corresponding Source along with the object code. If the place to
+copy the object code is a network server, the Corresponding Source
+may be on a different server (operated by you or a third party)
+that supports equivalent copying facilities, provided you maintain
+clear directions next to the object code saying where to find the
+Corresponding Source. Regardless of what server hosts the
+Corresponding Source, you remain obligated to ensure that it is
+available for as long as needed to satisfy these requirements.
+
+e) Convey the object code using peer-to-peer transmission, provided
+you inform other peers where the object code and Corresponding
+Source of the work are being offered to the general public at no
+charge under subsection 6d.
+
+A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+"Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+7. Additional Terms.
+
+"Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+a) Disclaiming warranty or limiting liability differently from the
+terms of sections 15 and 16 of this License; or
+
+b) Requiring preservation of specified reasonable legal notices or
+author attributions in that material or in the Appropriate Legal
+Notices displayed by works containing it; or
+
+c) Prohibiting misrepresentation of the origin of that material, or
+requiring that modified versions of such material be marked in
+reasonable ways as different from the original version; or
+
+d) Limiting the use for publicity purposes of names of licensors or
+authors of the material; or
+
+e) Declining to grant rights under trademark law for use of some
+trade names, trademarks, or service marks; or
+
+f) Requiring indemnification of licensors and authors of that
+material by anyone who conveys the material (or modified versions of
+it) with contractual assumptions of liability to the recipient, for
+any liability that these contractual assumptions directly impose on
+those licensors and authors.
+
+All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+8. Termination.
+
+You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+11. Patents.
+
+A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
this License.
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
+Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+13. Use with the GNU Affero General Public License.
+
+Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
+Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1b501f4
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2925 @@
+#
+# Tremulous Makefile
+#
+# GNU Make required
+#
+COMPILE_PLATFORM=$(shell uname | sed -e 's/_.*//' | tr '[:upper:]' '[:lower:]' | sed -e 's/\//_/g')
+COMPILE_ARCH=$(shell uname -m | sed -e 's/i.86/x86/' | sed -e 's/^arm.*/arm/')
+
+ifeq ($(COMPILE_PLATFORM),sunos)
+ # Solaris uname and GNU uname differ
+ COMPILE_ARCH=$(shell uname -p | sed -e 's/i.86/x86/')
+endif
+
+ifeq ($(COMPILE_PLATFORM),linux)
+ ifeq ($(COMPILE_ARCH),arm)
+ # Get full arch name
+ COMPILE_ARCH=$(shell file /bin/true | sed -e 's/^.*ld-linux-\(arm.*\)\.so.*/\1/')
+ endif
+endif
+
+ifndef BUILD_STANDALONE
+ BUILD_STANDALONE =
+endif
+ifndef BUILD_CLIENT
+ BUILD_CLIENT =
+endif
+ifndef BUILD_SERVER
+ BUILD_SERVER =
+endif
+ifndef BUILD_GRANGER
+ BUILD_GRANGER =
+endif
+ifndef BUILD_GAME_SO
+ BUILD_GAME_SO =
+endif
+ifndef BUILD_GAME_QVM
+ BUILD_GAME_QVM =
+endif
+ifndef BUILD_GAME_QVM_11
+ BUILD_GAME_QVM_11 =
+endif
+ifndef BUILD_RENDERER_OPENGL2
+ BUILD_RENDERER_OPENGL2=
+endif
+
+#############################################################################
+#
+# If you require a different configuration from the defaults below, create a
+# new file named "Makefile.local" in the same directory as this file and define
+# your parameters there. This allows you to change configuration without
+# causing problems with keeping up to date with the repository.
+#
+#############################################################################
+-include Makefile.local
+
+ifeq ($(COMPILE_PLATFORM),cygwin)
+ PLATFORM=mingw32
+endif
+
+ifndef PLATFORM
+PLATFORM=$(COMPILE_PLATFORM)
+endif
+export PLATFORM
+
+ifeq ($(PLATFORM),mingw32)
+ MINGW=1
+endif
+ifeq ($(PLATFORM),mingw64)
+ MINGW=1
+endif
+
+ifeq ($(COMPILE_ARCH),i86pc)
+ COMPILE_ARCH=x86
+endif
+
+ifeq ($(COMPILE_ARCH),amd64)
+ COMPILE_ARCH=x86_64
+endif
+ifeq ($(COMPILE_ARCH),x64)
+ COMPILE_ARCH=x86_64
+endif
+
+ifeq ($(COMPILE_ARCH),powerpc)
+ COMPILE_ARCH=ppc
+endif
+ifeq ($(COMPILE_ARCH),powerpc64)
+ COMPILE_ARCH=ppc64
+endif
+
+ifeq ($(COMPILE_ARCH),axp)
+ COMPILE_ARCH=alpha
+endif
+
+ifndef ARCH
+ARCH=$(COMPILE_ARCH)
+endif
+export ARCH
+
+ifneq ($(PLATFORM),$(COMPILE_PLATFORM))
+ CROSS_COMPILING=1
+else
+ CROSS_COMPILING=0
+
+ ifneq ($(ARCH),$(COMPILE_ARCH))
+ CROSS_COMPILING=1
+ endif
+endif
+export CROSS_COMPILING
+
+ifndef VERSION
+VERSION=1.3.0
+endif
+
+ifndef CLIENTBIN
+CLIENTBIN=tremulous
+endif
+
+ifndef SERVERBIN
+SERVERBIN=tremded
+endif
+
+ifndef BASEGAME
+BASEGAME=gpp
+endif
+
+BASEGAME_CFLAGS=-I../../${MOUNT_DIR}
+
+ifndef COPYDIR
+COPYDIR="/usr/local/games/tremulous"
+endif
+
+ifndef COPYBINDIR
+COPYBINDIR=$(COPYDIR)
+endif
+
+ifndef MOUNT_DIR
+MOUNT_DIR=src
+endif
+
+ifndef EXTERNAL_DIR
+EXTERNAL_DIR=external
+endif
+
+ifndef ASSETS_DIR
+ASSETS_DIR=assets
+endif
+
+ifndef BUILD_DIR
+BUILD_DIR=build
+endif
+
+ifndef TEMPDIR
+TEMPDIR=/tmp
+endif
+
+ifndef GENERATE_DEPENDENCIES
+GENERATE_DEPENDENCIES=1
+endif
+
+ifndef USE_OPENAL
+USE_OPENAL=1
+endif
+
+ifndef USE_OPENAL_DLOPEN
+USE_OPENAL_DLOPEN=1
+endif
+
+ifndef USE_RESTCLIENT
+USE_RESTCLIENT=1
+USE_CURL=1
+USE_CURL_DLOPEN=0
+endif
+
+ifndef USE_CURL
+USE_CURL=1
+endif
+
+ifndef USE_CURL_DLOPEN
+ ifdef MINGW
+ USE_CURL_DLOPEN=0
+ else
+ USE_CURL_DLOPEN=1
+ endif
+endif
+
+ifndef USE_CODEC_VORBIS
+USE_CODEC_VORBIS=1
+endif
+
+ifndef USE_CODEC_OPUS
+USE_CODEC_OPUS=1
+endif
+
+ifndef USE_MUMBLE
+USE_MUMBLE=0
+endif
+
+ifndef USE_VOIP
+USE_VOIP=0
+endif
+
+ifndef USE_FREETYPE
+USE_FREETYPE=0
+endif
+
+ifndef USE_INTERNAL_LIBS
+USE_INTERNAL_LIBS=1
+endif
+
+ifndef USE_INTERNAL_OGG
+USE_INTERNAL_OGG=$(USE_INTERNAL_LIBS)
+endif
+
+ifndef USE_INTERNAL_VORBIS
+USE_INTERNAL_VORBIS=$(USE_INTERNAL_LIBS)
+endif
+
+ifndef USE_INTERNAL_OPUS
+USE_INTERNAL_OPUS=$(USE_INTERNAL_LIBS)
+endif
+
+ifndef USE_INTERNAL_ZLIB
+USE_INTERNAL_ZLIB=$(USE_INTERNAL_LIBS)
+endif
+
+ifndef USE_INTERNAL_JPEG
+USE_INTERNAL_JPEG=$(USE_INTERNAL_LIBS)
+endif
+
+ifndef USE_INTERNAL_LUA
+USE_INTERNAL_LUA=$(USE_INTERNAL_LIBS)
+endif
+
+ifndef USE_LOCAL_HEADERS
+USE_LOCAL_HEADERS=$(USE_INTERNAL_LIBS)
+endif
+
+ifndef USE_RENDERER_DLOPEN
+USE_RENDERER_DLOPEN=1
+endif
+
+ifndef USE_YACC
+USE_YACC=0
+endif
+
+ifndef DEBUG_CFLAGS
+DEBUG_CFLAGS=-ggdb -O0
+endif
+
+ifndef BASE_CFLAGS
+ BASE_CFLAGS=-fno-strict-aliasing
+endif
+
+#############################################################################
+
+BD=$(BUILD_DIR)/debug-$(PLATFORM)-$(ARCH)
+BR=$(BUILD_DIR)/release-$(PLATFORM)-$(ARCH)
+
+CDIR=$(MOUNT_DIR)/client
+SDIR=$(MOUNT_DIR)/server
+RCOMMONDIR=$(MOUNT_DIR)/renderercommon
+RGL1DIR=$(MOUNT_DIR)/renderergl1
+RGL2DIR=$(MOUNT_DIR)/renderergl2
+CMDIR=$(MOUNT_DIR)/qcommon
+SDLDIR=$(MOUNT_DIR)/sdl
+ASMDIR=$(MOUNT_DIR)/asm
+SYSDIR=$(MOUNT_DIR)/sys
+SCRIPTDIR=$(MOUNT_DIR)/script
+GDIR=$(MOUNT_DIR)/game
+CGDIR=$(MOUNT_DIR)/cgame
+NDIR=$(MOUNT_DIR)/null
+UIDIR=$(MOUNT_DIR)/ui
+GRANGERDIR=$(MOUNT_DIR)/granger/src
+JPDIR=$(EXTERNAL_DIR)/jpeg-8c
+OGGDIR=$(EXTERNAL_DIR)/libogg-1.3.2
+VORBISDIR=$(EXTERNAL_DIR)/libvorbis-1.3.5
+OPUSDIR=$(EXTERNAL_DIR)/opus-1.1.4
+OPUSFILEDIR=$(EXTERNAL_DIR)/opusfile-0.8
+ZDIR=$(EXTERNAL_DIR)/zlib
+LUADIR=$(EXTERNAL_DIR)/lua-5.3.3/src
+RESTDIR=$(EXTERNAL_DIR)/restclient
+NETTLEDIR=$(EXTERNAL_DIR)/nettle-3.3
+SEMVERDIR=$(EXTERNAL_DIR)/semver
+LUA_RAPIDJSONDIR=$(MOUNT_DIR)/script/rapidjson
+Q3ASMDIR=$(MOUNT_DIR)/tools/asm
+LBURGDIR=$(MOUNT_DIR)/tools/lcc/lburg
+Q3CPPDIR=$(MOUNT_DIR)/tools/lcc/cpp
+Q3LCCETCDIR=$(MOUNT_DIR)/tools/lcc/etc
+Q3LCCSRCDIR=$(MOUNT_DIR)/tools/lcc/src
+SDLHDIR=$(EXTERNAL_DIR)/SDL2
+CURLHDIR=$(EXTERNAL_DIR)/libcurl-7.35.0
+ALHDIR=$(EXTERNAL_DIR)/AL
+LIBSDIR=$(EXTERNAL_DIR)/libs
+TEMPDIR=/tmp
+
+bin_path=$(shell which $(1) 2> /dev/null)
+
+# We won't need this if we only build the server
+ifneq ($(BUILD_CLIENT),0)
+ # set PKG_CONFIG_PATH to influence this, e.g.
+ # PKG_CONFIG_PATH=/opt/cross/i386-mingw32msvc/lib/pkgconfig
+ ifneq ($(call bin_path, pkg-config),)
+ CURL_CFLAGS ?= $(shell pkg-config --silence-errors --cflags libcurl)
+ CURL_LIBS ?= $(shell pkg-config --silence-errors --libs libcurl)
+ OPENAL_CFLAGS ?= $(shell pkg-config --silence-errors --cflags openal)
+ OPENAL_LIBS ?= $(shell pkg-config --silence-errors --libs openal)
+ SDL_CFLAGS ?= $(shell pkg-config --silence-errors --cflags sdl2|sed 's/-Dmain=SDL_main//')
+ SDL_LIBS ?= $(shell pkg-config --silence-errors --libs sdl2)
+ else
+ # assume they're in the system default paths (no -I or -L needed)
+ CURL_LIBS ?= -lcurl
+ OPENAL_LIBS ?= -lopenal
+ endif
+ # Use sdl2-config if all else fails
+ ifeq ($(SDL_CFLAGS),)
+ ifneq ($(call bin_path, sdl2-config),)
+ SDL_CFLAGS ?= $(shell sdl2-config --cflags)
+ SDL_LIBS ?= $(shell sdl2-config --libs)
+ endif
+ endif
+endif
+
+# Add git version info
+USE_GIT=
+ifeq ($(wildcard .git),.git)
+ GIT_REV=$(shell git describe --tag)
+ ifneq ($(GIT_REV),)
+ VERSION:=$(GIT_REV)
+ USE_GIT=1
+ endif
+endif
+
+
+#############################################################################
+# SETUP AND BUILD -- LINUX
+#############################################################################
+
+INSTALL=install
+MKDIR=mkdir
+EXTRA_FILES=
+CLIENT_EXTRA_FILES=
+
+ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu"))
+ BASE_CFLAGS += -DUSE_ICON
+ CLIENT_CFLAGS += $(SDL_CFLAGS)
+
+ OPTIMIZEVM = -O3
+ OPTIMIZE = $(OPTIMIZEVM) -ffast-math
+
+ ifeq ($(ARCH),x86_64)
+ OPTIMIZEVM = -O3
+ OPTIMIZE = $(OPTIMIZEVM) -ffast-math -msse2
+ HAVE_VM_COMPILED = true
+ else
+ ifeq ($(ARCH),x86)
+ OPTIMIZEVM = -O3
+ OPTIMIZE = $(OPTIMIZEVM) -ffast-math -msse2 -mfpmath=387+sse
+ HAVE_VM_COMPILED=true
+ else
+ ifeq ($(ARCH),ppc)
+ BASE_CFLAGS += -maltivec
+ HAVE_VM_COMPILED=true
+ endif
+ ifeq ($(ARCH),ppc64)
+ BASE_CFLAGS += -maltivec
+ HAVE_VM_COMPILED=true
+ endif
+ ifeq ($(ARCH),sparc)
+ OPTIMIZE += -mtune=ultrasparc3 -mv8plus
+ OPTIMIZEVM += -mtune=ultrasparc3 -mv8plus
+ HAVE_VM_COMPILED=true
+ endif
+ ifeq ($(ARCH),alpha)
+ # According to http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=410555
+ # -ffast-math will cause the client to die with SIGFPE on Alpha
+ OPTIMIZE = $(OPTIMIZEVM)
+ endif
+ ifeq ($(ARCH),armhf)
+ BASE_CFLAGS += -D__armhf__
+ endif
+ endif
+ endif
+
+ SHLIBEXT=so
+ SHLIBCFLAGS=-fPIC -fvisibility=hidden
+ SHLIBLDFLAGS=-shared
+ #$(LDFLAGS)
+
+ THREAD_LIBS=-lpthread
+ LIBS=-ldl -lm
+ GRANGER_LIBS=-lm -ldl
+
+ CLIENT_LIBS=$(SDL_LIBS)
+ RENDERER_LIBS = $(SDL_LIBS) -lGL
+
+ ifeq ($(USE_OPENAL),1)
+ ifneq ($(USE_OPENAL_DLOPEN),1)
+ CLIENT_LIBS += $(THREAD_LIBS) $(OPENAL_LIBS)
+ endif
+ endif
+
+ ifeq ($(USE_CURL),1)
+ CLIENT_CFLAGS += $(CURL_CFLAGS)
+ ifneq ($(USE_CURL_DLOPEN),1)
+ CLIENT_LIBS += $(CURL_LIBS)
+ endif
+ endif
+
+ ifeq ($(USE_MUMBLE),1)
+ CLIENT_LIBS += -lrt
+ endif
+
+ ifeq ($(ARCH),x86)
+ # linux32 make ...
+ BASE_CFLAGS += -m32
+ else
+ ifeq ($(ARCH),ppc64)
+ BASE_CFLAGS += -m64
+ endif
+ endif
+else # ifeq Linux
+
+#############################################################################
+# SETUP AND BUILD -- MAC OS X
+#############################################################################
+
+ifeq ($(PLATFORM),darwin)
+ HAVE_VM_COMPILED=true
+ LIBS = -framework Cocoa
+ CLIENT_LIBS=
+ RENDERER_LIBS=
+ OPTIMIZEVM=
+ #CXXFLAGS+=-stdlib=libc++
+
+ # FIXME This is probably bad idea to comment this out
+ #BASE_CFLAGS += -mmacosx-version-min=10.7 -DMAC_OS_X_VERSION_MIN_REQUIRED=1070
+
+ GRANGER_LIBS = -framework Cocoa -framework Security
+
+ ifeq ($(USE_RESTCLIENT),1)
+ CLIENT_LIBS += -framework Security
+ endif
+
+ ifeq ($(ARCH),ppc)
+ BASE_CFLAGS += -arch ppc -faltivec
+ OPTIMIZEVM += -O3
+ endif
+ ifeq ($(ARCH),ppc64)
+ BASE_CFLAGS += -arch ppc64 -faltivec
+ endif
+ ifeq ($(ARCH),x86)
+ OPTIMIZEVM += -mfpmath=387+sse
+ # x86 vm will crash without -mstackrealign since MMX instructions will be
+ # used no matter what and they corrupt the frame pointer in VM calls
+ BASE_CFLAGS += -arch i386 -m32 -mstackrealign
+ endif
+ ifeq ($(ARCH),x86_64)
+ OPTIMIZEVM += -arch x86_64 -mfpmath=sse -msse2
+ endif
+
+ # When compiling on OSX for OSX, we're not cross compiling as far as the
+ # Makefile is concerned, as target architecture is specified as a compiler
+ # argument
+ ifeq ($(COMPILE_PLATFORM),darwin)
+ CROSS_COMPILING=0
+ endif
+
+ ifeq ($(CROSS_COMPILING),1)
+ ifeq ($(ARCH),x86_64)
+ CC=x86_64-apple-darwin13-cc
+ RANLIB=x86_64-apple-darwin13-ranlib
+ else
+ ifeq ($(ARCH),x86)
+ CC=i386-apple-darwin13-cc
+ RANLIB=i386-apple-darwin13-ranlib
+ else
+ $(error Architecture $(ARCH) is not supported when cross compiling)
+ endif
+ endif
+ endif
+
+ BASE_CFLAGS += -fno-strict-aliasing -fno-common
+
+ ifeq ($(USE_OPENAL),1)
+ ifneq ($(USE_OPENAL_DLOPEN),1)
+ CLIENT_LIBS += -framework OpenAL
+ endif
+ endif
+
+ ifeq ($(USE_CURL),1)
+ CLIENT_CFLAGS += $(CURL_CFLAGS)
+ ifneq ($(USE_CURL_DLOPEN),1)
+ CLIENT_LIBS += $(CURL_LIBS)
+ endif
+ endif
+
+ BASE_CFLAGS += -D_THREAD_SAFE=1
+
+ # FIXME: It is not possible to build using system SDL2 framework
+ # 1. IF you try, this Makefile will still drop libSDL-2.0.0.dylib into the builddir
+ # 2. Debugger warns that you have 2- which one will be used is undefined
+ ifeq ($(USE_LOCAL_HEADERS),1)
+ BASE_CFLAGS += -I$(SDLHDIR)/include -I$(CURLHDIR) -I$(ALHDIR)
+ endif
+
+ # We copy sdlmain before ranlib'ing it so that subversion doesn't think
+ # the file has been modified by each build.
+ LIBSDLMAIN=$(B)/libSDL2main.a
+ LIBSDLMAINSRC=$(LIBSDIR)/macosx/libSDL2main.a
+ CLIENT_LIBS += -framework IOKit \
+ $(LIBSDIR)/macosx/libSDL2-2.0.0.dylib
+ RENDERER_LIBS += -framework OpenGL $(LIBSDIR)/macosx/libSDL2-2.0.0.dylib
+ CLIENT_EXTRA_FILES += $(LIBSDIR)/macosx/libSDL2-2.0.0.dylib
+
+ OPTIMIZE = $(OPTIMIZEVM) -ffast-math
+
+ SHLIBEXT=dylib
+ SHLIBCFLAGS=-fPIC -fno-common
+ #SHLIBLDFLAGS=-dynamiclib $(LDFLAGS) -Wl,-U,_com_altivec
+ SHLIBLDFLAGS=-dynamiclib -Wl,-U,_com_altivec
+
+ NOTSHLIBCFLAGS=-mdynamic-no-pic
+
+else # ifeq darwin
+
+
+#############################################################################
+# SETUP AND BUILD -- MINGW32
+#############################################################################
+
+ifdef MINGW
+
+ ifeq ($(CROSS_COMPILING),1)
+ # If CC is already set to something generic, we probably want to use
+ # something more specific
+ ifneq ($(findstring $(strip $(CC)),cc gcc),)
+ CC=
+ endif
+ ifneq ($(findstring $(strip $(CXX)),c++ g++),)
+ CXX=
+ endif
+
+ # We need to figure out the correct gcc and windres
+ ifeq ($(ARCH),x86_64)
+ MINGW_PREFIXES=x86_64-w64-mingw32
+ endif
+ ifeq ($(ARCH),x86)
+ MINGW_PREFIXES=i686-w64-mingw32
+ endif
+
+ ifndef CC
+ CC=$(firstword $(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), $(call bin_path, $(MINGW_PREFIX)-gcc))))
+ endif
+ ifndef CXX
+ CXX=$(firstword $(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), $(call bin_path, $(MINGW_PREFIX)-g++))))
+ endif
+
+ ifndef WINDRES
+ WINDRES=$(firstword $(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), $(call bin_path, $(MINGW_PREFIX)-windres))))
+ endif
+ else
+ # Some MinGW installations define CC to cc, but don't actually provide cc,
+ # so check that CC points to a real binary and use gcc if it doesn't
+ ifeq ($(call bin_path, $(CC)),)
+ CC=gcc
+ endif
+
+ ifeq ($(call bin_path, $(CXX)),)
+ CXX=g++
+ endif
+
+ ifndef WINDRES
+ WINDRES=windres
+ endif
+ endif
+
+ ifeq ($(CC),)
+ $(error Cannot find a suitable cross compiler for $(PLATFORM) CC)
+ endif
+ ifeq ($(CXX),)
+ $(error Cannot find a suitable cross compiler for $(PLATFORM) CXX)
+ endif
+
+ CFLAGS += -static -static-libgcc -static-libstdc++
+ CXXFLAGS += -static -static-libgcc -static-libstdc++
+ LDFLAGS += -static -static-libgcc -static-libstdc++
+ GRANGER_CFLAGS = -D_CRT_SECURE_NO_WARNINGS
+
+ BASE_CFLAGS += -DUSE_ICON
+
+ # In the absence of wspiapi.h, require Windows XP or later
+ ifeq ($(shell test -e $(CMDIR)/wspiapi.h; echo $$?),1)
+ # FIXIT-L Update WINVER=_WIN32_WINNT_WIN7 (see https://msdn.microsoft.com/en-us/library/6sehtctf.aspx)
+ BASE_CFLAGS += -DWINVER=0x501
+ endif
+
+ ifeq ($(USE_OPENAL),1)
+ CLIENT_CFLAGS += $(OPENAL_CFLAGS)
+ ifneq ($(USE_OPENAL_DLOPEN),1)
+ CLIENT_LDFLAGS += $(OPENAL_LDFLAGS)
+ endif
+ ifeq ($(USE_LOCAL_HEADERS),1)
+ CLIENT_CFLAGS += -I$(ALHDIR)
+ endif
+ endif
+
+ ifeq ($(ARCH),x86_64)
+ OPTIMIZEVM = -O3
+ OPTIMIZE = $(OPTIMIZEVM) -ffast-math -msse2
+ HAVE_VM_COMPILED = true
+ BASE_CFLAGS += -m64
+ endif
+
+ ifeq ($(ARCH),x86)
+ OPTIMIZEVM = -O3
+ OPTIMIZE = $(OPTIMIZEVM) -ffast-math -msse2 -mfpmath=387+sse
+ HAVE_VM_COMPILED = true
+ BASE_CFLAGS += -m32
+ endif
+
+ SHLIBEXT=dll
+ SHLIBCFLAGS=
+ #SHLIBLDFLAGS=-shared $(LDFLAGS)
+ SHLIBLDFLAGS=-shared
+
+ BINEXT=.exe
+
+ ifeq ($(CROSS_COMPILING),0)
+ TOOLS_BINEXT=.exe
+ endif
+
+ ifeq ($(COMPILE_PLATFORM),cygwin)
+ TOOLS_BINEXT=.exe
+ TOOLS_CC=$(CC)
+ endif
+
+ LIBS= -lws2_32 -lwinmm -lpsapi
+ # clang 3.4 doesn't support this
+ ifneq ("$(CC)", $(findstring "$(CC)", "clang" "clang++"))
+ CLIENT_LDFLAGS += -mwindows
+ endif
+ CLIENT_LIBS = -lgdi32 -lole32
+ RENDERER_LIBS = -lgdi32 -lole32 -lopengl32
+
+ ifeq ($(USE_FREETYPE),1)
+ FREETYPE_CFLAGS = -Ifreetype2
+ endif
+
+ ifeq ($(USE_CURL),1)
+ ifneq ($(USE_CURL_DLOPEN),1)
+ ifeq ($(USE_LOCAL_HEADERS),1)
+ CLIENT_CFLAGS += -DCURL_STATICLIB -I$(CURLHDIR)
+ ifeq ($(ARCH),x86_64)
+ CLIENT_LIBS += $(LIBSDIR)/win64/libcurl.a
+ else
+ CLIENT_LIBS += $(LIBSDIR)/win32/libcurl.a
+ endif
+ else
+ CLIENT_CFLAGS += $(CURL_CFLAGS)
+ CLIENT_LIBS += $(CURL_LIBS)
+ endif
+ endif
+ endif
+
+ # libmingw32 must be linked before libSDLmain
+ CLIENT_LIBS += -lmingw32
+ RENDERER_LIBS += -lmingw32
+
+ ifeq ($(USE_LOCAL_HEADERS),1)
+ CLIENT_CFLAGS += -I$(SDLHDIR)/include
+ ifeq ($(ARCH), x86)
+ CLIENT_LIBS += $(LIBSDIR)/win32/libSDL2main.a $(LIBSDIR)/win32/libSDL2.dll.a
+ RENDERER_LIBS += $(LIBSDIR)/win32/libSDL2main.a $(LIBSDIR)/win32/libSDL2.dll.a
+ SDLDLL=SDL2.dll
+ CLIENT_EXTRA_FILES += $(LIBSDIR)/win32/SDL2.dll
+ else
+ CLIENT_LIBS += $(LIBSDIR)/win64/libSDL264main.a $(LIBSDIR)/win64/libSDL264.dll.a
+ RENDERER_LIBS += $(LIBSDIR)/win64/libSDL264main.a $(LIBSDIR)/win64/libSDL264.dll.a
+ SDLDLL=SDL264.dll
+ CLIENT_EXTRA_FILES += $(LIBSDIR)/win64/SDL264.dll
+ endif
+ else
+ CLIENT_CFLAGS += $(SDL_CFLAGS)
+ CLIENT_LIBS += $(SDL_LIBS)
+ RENDERER_LIBS += $(SDL_LIBS)
+ SDLDLL=SDL2.dll
+ endif
+
+else # ifdef MINGW
+
+#############################################################################
+# SETUP AND BUILD -- FREEBSD
+#############################################################################
+
+ifeq ($(PLATFORM),freebsd)
+
+ # flags
+ BASE_CFLAGS = $(shell env MACHINE_ARCH=$(ARCH) make -f /dev/null -VCFLAGS) \
+ -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes -DUSE_ICON -DMAP_ANONYMOUS=MAP_ANON
+ CLIENT_CFLAGS += $(SDL_CFLAGS)
+ HAVE_VM_COMPILED = true
+
+ OPTIMIZEVM = -O3
+ OPTIMIZE = $(OPTIMIZEVM) -ffast-math
+
+ SHLIBEXT=so
+ SHLIBCFLAGS=-fPIC
+ #SHLIBLDFLAGS=-shared $(LDFLAGS)
+ SHLIBLDFLAGS=-shared
+
+ THREAD_LIBS=-lpthread
+ # don't need -ldl (FreeBSD)
+ LIBS=-lm
+ GRANGER_LIBS = -lm
+
+ CLIENT_LIBS =
+
+ CLIENT_LIBS += $(SDL_LIBS)
+ RENDERER_LIBS = $(SDL_LIBS) -lGL
+
+ # optional features/libraries
+ ifeq ($(USE_OPENAL),1)
+ ifeq ($(USE_OPENAL_DLOPEN),1)
+ CLIENT_LIBS += $(THREAD_LIBS) $(OPENAL_LIBS)
+ endif
+ endif
+
+ ifeq ($(USE_CURL),1)
+ CLIENT_CFLAGS += $(CURL_CFLAGS)
+ ifeq ($(USE_CURL_DLOPEN),1)
+ CLIENT_LIBS += $(CURL_LIBS)
+ endif
+ endif
+
+ # cross-compiling tweaks
+ ifeq ($(ARCH),x86)
+ ifeq ($(CROSS_COMPILING),1)
+ BASE_CFLAGS += -m32
+ endif
+ endif
+ ifeq ($(ARCH),x86_64)
+ ifeq ($(CROSS_COMPILING),1)
+ BASE_CFLAGS += -m64
+ endif
+ endif
+else # ifeq freebsd
+
+#############################################################################
+# SETUP AND BUILD -- GENERIC
+#############################################################################
+ BASE_CFLAGS=
+ OPTIMIZE = -O3
+
+ SHLIBEXT=so
+ SHLIBCFLAGS=-fPIC
+ SHLIBLDFLAGS=-shared
+
+endif #Linux
+endif #darwin
+endif #MINGW
+endif #FreeBSD
+
+ifndef CC
+ CC=gcc
+endif
+
+ifndef RANLIB
+ RANLIB=ranlib
+endif
+
+ifneq ($(HAVE_VM_COMPILED),true)
+ BASE_CFLAGS += -DNO_VM_COMPILED
+ BUILD_GAME_QVM=0
+endif
+
+TARGETS =
+
+ifndef FULLBINEXT
+ FULLBINEXT=$(BINEXT)
+endif
+
+ifndef SHLIBNAME
+ SHLIBNAME=.$(SHLIBEXT)
+endif
+
+ifneq ($(BUILD_SERVER),0)
+ TARGETS += $(B)/$(SERVERBIN)$(FULLBINEXT)
+endif
+
+ifneq ($(BUILD_CLIENT),0)
+ ifneq ($(USE_RENDERER_DLOPEN),0)
+ TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT) $(B)/renderer_opengl1$(SHLIBNAME)
+ ifneq ($(BUILD_RENDERER_OPENGL2),0)
+ TARGETS += $(B)/renderer_opengl2$(SHLIBNAME)
+ endif
+ else
+ TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT)
+ ifneq ($(BUILD_RENDERER_OPENGL2),0)
+ TARGETS += $(B)/$(CLIENTBIN)_opengl2$(FULLBINEXT)
+ endif
+ endif
+endif
+
+ifneq ($(BUILD_GAME_SO),0)
+ TARGETS += \
+ $(B)/$(BASEGAME)/cgame$(SHLIBNAME) \
+ $(B)/$(BASEGAME)/game$(SHLIBNAME) \
+ $(B)/$(BASEGAME)/ui$(SHLIBNAME)
+endif
+
+ifneq ($(BUILD_GAME_QVM),0)
+ TARGETS += \
+ $(B)/$(BASEGAME)/vm/cgame.qvm \
+ $(B)/$(BASEGAME)/vm/game.qvm \
+ $(B)/$(BASEGAME)/vm/ui.qvm \
+ $(B)/$(BASEGAME)/vms-gpp-$(VERSION).pk3
+endif
+
+ifneq ($(BUILD_GAME_QVM_11),0)
+ TARGETS += \
+ $(B)/$(BASEGAME)_11/vm/cgame.qvm \
+ $(B)/$(BASEGAME)_11/vm/ui.qvm \
+ $(B)/$(BASEGAME)_11/vms-1.1.0-$(VERSION).pk3
+endif
+
+ifneq ($(BUILD_DATA_PK3),0)
+ TARGETS += \
+ $(B)/$(BASEGAME)/data-$(VERSION).pk3
+endif
+
+ifeq ($(USE_OPENAL),1)
+ CLIENT_CFLAGS += -DUSE_OPENAL
+ ifeq ($(USE_OPENAL_DLOPEN),1)
+ CLIENT_CFLAGS += -DUSE_OPENAL_DLOPEN
+ endif
+endif
+
+ifeq ($(USE_CURL),1)
+ CLIENT_CFLAGS += -DUSE_CURL
+ ifeq ($(USE_CURL_DLOPEN),1)
+ CLIENT_CFLAGS += -DUSE_CURL_DLOPEN
+ endif
+endif
+
+ifeq ($(USE_VOIP),1)
+ CLIENT_CFLAGS += -DUSE_VOIP
+ SERVER_CFLAGS += -DUSE_VOIP
+ NEED_OPUS=1
+endif
+
+ifeq ($(USE_CODEC_OPUS),1)
+ CLIENT_CFLAGS += -DUSE_CODEC_OPUS
+ NEED_OPUS=1
+endif
+
+ifeq ($(NEED_OPUS),1)
+ ifeq ($(USE_INTERNAL_OPUS),1)
+ OPUS_CFLAGS = -DOPUS_BUILD -DHAVE_LRINTF -DFLOATING_POINT -DFLOAT_APPROX -DUSE_ALLOCA -D __OPTIMIZE__ \
+ -I$(OPUSDIR)/include -I$(OPUSDIR)/celt -I$(OPUSDIR)/silk \
+ -I$(OPUSDIR)/silk/float -I$(OPUSFILEDIR)/include
+ else
+ OPUS_CFLAGS ?= $(shell pkg-config --silence-errors --cflags opusfile opus || true)
+ OPUS_LIBS ?= $(shell pkg-config --silence-errors --libs opusfile opus || echo -lopusfile -lopus)
+ endif
+ CLIENT_CFLAGS += $(OPUS_CFLAGS)
+ CLIENT_LIBS += $(OPUS_LIBS)
+ NEED_OGG=1
+endif
+
+ifeq ($(USE_CODEC_VORBIS),1)
+ CLIENT_CFLAGS += -DUSE_CODEC_VORBIS
+ ifeq ($(USE_INTERNAL_VORBIS),1)
+ CLIENT_CFLAGS += -I$(VORBISDIR)/include -I$(VORBISDIR)/lib
+ else
+ VORBIS_CFLAGS ?= $(shell pkg-config --silence-errors --cflags vorbisfile vorbis || true)
+ VORBIS_LIBS ?= $(shell pkg-config --silence-errors --libs vorbisfile vorbis || echo -lvorbisfile -lvorbis)
+ endif
+ CLIENT_CFLAGS += $(VORBIS_CFLAGS)
+ CLIENT_LIBS += $(VORBIS_LIBS)
+ NEED_OGG=1
+endif
+
+#-bbq
+ifeq ($(USE_RESTCLIENT),1)
+ CLIENT_CFLAGS += -DUSE_RESTCLIENT -I$(RESTDIR)
+endif
+
+ifeq ($(NEED_OGG),1)
+ ifeq ($(USE_INTERNAL_OGG),1)
+ OGG_CFLAGS = -I$(OGGDIR)/include
+ else
+ OGG_CFLAGS ?= $(shell pkg-config --silence-errors --cflags ogg || true)
+ OGG_LIBS ?= $(shell pkg-config --silence-errors --libs ogg || echo -logg)
+ endif
+ CLIENT_CFLAGS += $(OGG_CFLAGS)
+ CLIENT_LIBS += $(OGG_LIBS)
+endif
+
+ifeq ($(USE_RENDERER_DLOPEN),1)
+ CLIENT_CFLAGS += -DUSE_RENDERER_DLOPEN
+endif
+
+ifeq ($(USE_MUMBLE),1)
+ CLIENT_CFLAGS += -DUSE_MUMBLE
+endif
+
+ifeq ($(USE_INTERNAL_ZLIB),1)
+ ZLIB_CFLAGS = -DNO_GZIP -I$(ZDIR)
+else
+ ZLIB_CFLAGS ?= $(shell pkg-config --silence-errors --cflags zlib || true)
+ ZLIB_LIBS ?= $(shell pkg-config --silence-errors --libs zlib || echo -lz)
+endif
+BASE_CFLAGS += $(ZLIB_CFLAGS)
+LIBS += $(ZLIB_LIBS)
+
+ifeq ($(USE_INTERNAL_JPEG),1)
+ BASE_CFLAGS += -DUSE_INTERNAL_JPEG
+ BASE_CFLAGS += -I$(JPDIR)
+else
+ # IJG libjpeg doesn't have pkg-config, but libjpeg-turbo uses libjpeg.pc;
+ # we fall back to hard-coded answers if libjpeg.pc is unavailable
+ JPEG_CFLAGS ?= $(shell pkg-config --silence-errors --cflags libjpeg || true)
+ JPEG_LIBS ?= $(shell pkg-config --silence-errors --libs libjpeg || echo -ljpeg)
+ BASE_CFLAGS += $(JPEG_CFLAGS)
+ RENDERER_LIBS += $(JPEG_LIBS)
+endif
+
+ifeq ($(USE_FREETYPE),1)
+ FREETYPE_CFLAGS ?= $(shell pkg-config --silence-errors --cflags freetype2 || true)
+ FREETYPE_LIBS ?= $(shell pkg-config --silence-errors --libs freetype2 || echo -lfreetype)
+
+ BASE_CFLAGS += -DBUILD_FREETYPE $(FREETYPE_CFLAGS)
+ RENDERER_LIBS += $(FREETYPE_LIBS)
+endif
+
+ifeq ("$(CC)", $(findstring "$(CC)", "clang" "clang++"))
+ BASE_CFLAGS += -Qunused-arguments
+endif
+
+ifdef DEFAULT_BASEDIR
+ BASE_CFLAGS += -DDEFAULT_BASEDIR=\\\"$(DEFAULT_BASEDIR)\\\"
+endif
+
+ifeq ($(USE_LOCAL_HEADERS),1)
+ BASE_CFLAGS += -DUSE_LOCAL_HEADERS
+endif
+
+ifeq ($(BUILD_STANDALONE),1)
+ BASE_CFLAGS += -DSTANDALONE
+endif
+
+ifeq ($(GENERATE_DEPENDENCIES),1)
+ DEPEND_CFLAGS = -MMD
+else
+ DEPEND_CFLAGS =
+endif
+
+ifeq ($(NO_STRIP),1)
+ STRIP_FLAG =
+else
+ STRIP_FLAG = -s
+endif
+
+BASE_CFLAGS += -DPRODUCT_VERSION=\\\"$(VERSION)\\\"
+
+ifeq ($(V),1)
+echo_cmd=@:
+Q=
+else
+echo_cmd=@echo
+Q=@
+endif
+
+EXEC_CC = $(CC) ${1} -o ${2} -c ${3}
+EXEC_CXX = $(CXX) -std=c++1y ${CXXFLAGS} ${1} -o ${2} -c ${3}
+
+# TREMULOUS CLIENT
+CC_FLAGS=${NOTSHLIBCFLAGS} ${CFLAGS} ${CLIENT_CFLAGS} ${OPTIMIZE}
+define DO_CC
+$(echo_cmd) "CC $<"
+$(Q)$(call EXEC_CC,-std=gnu99 ${CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CC,tremulous,${CC_FLAGS},$@,$<)
+endef
+
+define DO_CXX
+$(echo_cmd) "CXX $<"
+$(Q)$(call EXEC_CXX,${CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CXX,tremulous,${CC_FLAGS},$@,$<)
+endef
+
+##########################################
+# Renderers
+##########################################
+# Common Rendering Code
+define DO_RENDERER_COMMON_CC
+$(echo_cmd) "RENDERER_COMMON_CC $<"
+$(Q)$(call EXEC_CC,${REF_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CC,renderer_common,${REF_CC_FLAGS},$@,$<)
+endef
+define DO_RENDERER_COMMON_CXX
+$(echo_cmd) "RENDERER_COMMON_CXX $<"
+$(Q)$(call EXEC_CXX,${REF_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CXX,renderer_common,${REF_CC_FLAGS},$@,$<)
+endef
+##########################################
+# Renderers
+##########################################
+# OpenGL 1 Renderer
+REF_CC_FLAGS=${SHLIBCFLAGS} ${CFLAGS} ${CLIENT_CFLAGS} ${OPTIMIZE}
+define DO_RENDERERGL1_CC
+$(echo_cmd) "GL1_RENDERER_CC $<"
+$(Q)$(call EXEC_CC,${REF_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CC,opengl1,${REF_CC_FLAGS},$@,$<)
+endef
+define DO_RENDERERGL1_CXX
+$(echo_cmd) "GL1_RENDERER_CXX $<"
+$(Q)$(call EXEC_CXX,${REF_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CXX,opengl1,${REF_CC_FLAGS},$@,$<)
+endef
+##########################################
+# Renderers
+##########################################
+# OpenGL 2 Renderer
+define DO_RENDERERGL2_CC
+$(echo_cmd) "GL2_RENDERER_CC $<"
+$(Q)$(call EXEC_CC,${REF_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CC,opengl2,${REF_CC_FLAGS},$@,$<)
+endef
+define DO_RENDERERGL2_CXX
+$(echo_cmd) "RENDERERGL2_CXX $<"
+$(Q)$(call EXEC_CXX,${REF_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CXX,opengl2,${REF_CC_FLAGS},$@,$<)
+endef
+
+define DO_REF_STR
+$(echo_cmd) "REF_STR $<"
+$(Q)rm -f $@
+$(Q)echo "const char *fallbackShader_$(notdir $(basename $<)) =" >> $@
+$(Q)cat $< | sed 's/^/\"/;s/$$/\\n\"/' >> $@
+mkdir -p $(B)/glsl
+cp $@ $(B)/glsl/
+$(Q)echo ";" >> $@
+endef
+
+ifeq ($(GENERATE_DEPENDENCIES),1)
+ DO_QVM_DEP=cat $(@:%.o=%.d) | sed -e 's/\.o/\.asm/g' >> $(@:%.o=%.d)
+endif
+
+SHLIB_CC_FLAGS=${BASEGAME_CFLAGS} ${SHLIBCFLAGS} ${CFLAGS} ${OPTIMIZEVM}
+define DO_SHLIB_CC
+$(echo_cmd) "SHLIB_CC $<"
+$(Q)$(call EXEC_CC,${SHLIB_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CC,qcommon,${SHLIB_CC_FLAGS},$@,$<)
+$(Q)$(DO_QVM_DEP)
+endef
+
+GAME_CC_FLAGS=${BASEGAME_CFLAGS} ${SHLIBCFLAGS} ${CFLAGS} ${OPTIMIZEVM}
+define DO_GAME_CC
+$(echo_cmd) "GAME_CC $<"
+$(Q)$(call EXEC_CC,-DGAME ${GAME_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CC,game,-DGAME ${GAME_CC_FLAGS},$@,$<)
+$(Q)$(DO_QVM_DEP)
+endef
+
+define DO_CGAME_CC
+$(echo_cmd) "CGAME_CC $<"
+$(Q)$(call EXEC_CC,-DCGAME ${GAME_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CC,cgame,-DCGAME ${GAME_CC_FLAGS},$@,$<)
+$(Q)$(DO_QVM_DEP)
+endef
+
+define DO_UI_CC
+$(echo_cmd) "UI_CC $<"
+$(Q)$(call EXEC_CC,-DUI ${GAME_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CC,ui,-DUI ${GAME_CC_FLAGS},$@,$<)
+$(Q)$(DO_QVM_DEP)
+endef
+
+AS_FLAGS=${CFLAGS} ${OPTIMIZE} -x assembler-with-cpp
+define DO_AS
+$(echo_cmd) "AS $<"
+$(Q)$(call EXEC_CC,${AS_FLAGS},'$@','$<')
+$(Q)$(call LOG_CC,tremulous,${AS_FLAGS},$@,$<)
+endef
+
+define DO_DED_AS
+$(echo_cmd) "AS $<"
+$(Q)$(call EXEC_CC,${AS_FLAGS},'$@','$<')
+$(Q)$(call LOG_CC,tremded,${AS_FLAGS},$@,$<)
+endef
+
+DED_CC_FLAGS=-DDEDICATED ${NOTSHLIBCFLAGS} ${CFLAGS} ${SERVER_CFLAGS} ${OPTIMIZE}
+define DO_DED_CC
+$(echo_cmd) "DED_CC $<"
+$(Q)$(call EXEC_CC,-std=gnu99 ${DED_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CC,tremded,${DED_CC_FLAGS},$@,$<)
+endef
+
+define DO_DED_CXX
+$(echo_cmd) "DED_CXX $<"
+$(Q)$(call EXEC_CXX,${DED_CC_FLAGS},'$@','$<')
+$(Q)$(call LOG_CXX,tremded,${DED_CC_FLAGS},$@,$<)
+endef
+
+define DO_WINDRES
+$(echo_cmd) "WINDRES $<"
+$(Q)$(WINDRES) -i $< -o $@
+endef
+
+
+#############################################################################
+# MAIN TARGETS
+#############################################################################
+
+default: release
+all: debug release
+
+debug:
+ @$(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(BASE_CFLAGS) $(DEPEND_CFLAGS)" \
+ CXXFLAGS="$(BASE_CFLAGS) $(CXXFLAGS)" \
+ OPTIMIZE="$(DEBUG_CFLAGS)" OPTIMIZEVM="$(DEBUG_CFLAGS)" \
+ CLIENT_CFLAGS="$(CLIENT_CFLAGS)" SERVER_CFLAGS="$(SERVER_CFLAGS)" V=$(V)
+release:
+ @$(MAKE) targets B=$(BR) CFLAGS="$(CFLAGS) $(BASE_CFLAGS) $(DEPEND_CFLAGS)" \
+ CXXFLAGS="$(BASE_CFLAGS) $(CXXFLAGS)" \
+ OPTIMIZE="-DNDEBUG $(OPTIMIZE)" OPTIMIZEVM="-DNDEBUG $(OPTIMIZEVM)" \
+ CLIENT_CFLAGS="$(CLIENT_CFLAGS)" SERVER_CFLAGS="$(SERVER_CFLAGS)" V=$(V)
+
+ifneq ($(call bin_path, tput),)
+ TERM_COLUMNS=$(shell if c=`tput cols`; then echo $$(($$c-4)); else echo 76; fi)
+else
+ TERM_COLUMNS=76
+endif
+
+define ADD_COPY_TARGET
+TARGETS += $2
+$2: $1
+ $(echo_cmd) "CP $$<"
+ @cp $1 $2
+endef
+
+# These functions allow us to generate rules for copying a list of files
+# into the base directory of the build; this is useful for bundling libs,
+# README files or whatever else
+define GENERATE_COPY_TARGETS
+$(foreach FILE,$1, \
+ $(eval $(call ADD_COPY_TARGET, \
+ $(FILE), \
+ $(addprefix $(B)/,$(notdir $(FILE))))))
+endef
+
+$(call GENERATE_COPY_TARGETS,$(EXTRA_FILES))
+
+ifneq ($(BUILD_CLIENT),0)
+ $(call GENERATE_COPY_TARGETS,$(CLIENT_EXTRA_FILES))
+endif
+
+NAKED_TARGETS=$(shell echo $(TARGETS) | sed -e "s!$(B)/!!g")
+
+print_list=-@for i in $(1); \
+ do \
+ echo " $$i"; \
+ done
+
+ifneq ($(call bin_path, fmt),)
+ print_wrapped=@echo $(1) | fmt -w $(TERM_COLUMNS) | sed -e "s/^\(.*\)$$/ \1/"
+else
+ print_wrapped=$(print_list)
+endif
+
+#$(B)/compile_commands.json: $(B)/compile_commands.txt
+# sed -i -e "$$ ! s/}/},/" $<
+# echo '[' >$@
+# cat $< >>$@
+# echo ']' >>$@
+
+# Create the build directories, check libraries and print out
+# an informational message, then start building
+targets: makedirs
+ @echo ""
+ @echo "Building in $(B):"
+ @echo " PLATFORM: $(PLATFORM)"
+ @echo " ARCH: $(ARCH)"
+ @echo " VERSION: $(VERSION)"
+ @echo " COMPILE_PLATFORM: $(COMPILE_PLATFORM)"
+ @echo " COMPILE_ARCH: $(COMPILE_ARCH)"
+ @echo " CC: $(CC)"
+ @echo " CXX: $(CXX)"
+ @echo " TOOLS_CC $(TOOLS_CC)"
+ifeq ($(PLATFORM),mingw32)
+ @echo " WINDRES: $(WINDRES)"
+endif
+ @echo ""
+ @echo " CFLAGS:"
+ $(call print_wrapped, $(CFLAGS) $(OPTIMIZE))
+ @echo ""
+ @echo " CXXFLAGS:"
+ $(call print_wrapped, $(CXXFLAGS) $(OPTIMIZE))
+ @echo ""
+ @echo " CLIENT_CFLAGS:"
+ $(call print_wrapped, $(CLIENT_CFLAGS))
+ @echo ""
+ @echo " CLIENT_CXXFLAGS:"
+ $(call print_wrapped, $(CLIENT_CXXFLAGS))
+ @echo ""
+ @echo " SERVER_CFLAGS:"
+ $(call print_wrapped, $(SERVER_CFLAGS))
+ @echo ""
+ @echo " SERVER_CXXFLAGS:"
+ $(call print_wrapped, $(SERVER_CXXFLAGS))
+ @echo ""
+ @echo " LDFLAGS:"
+ $(call print_wrapped, $(LDFLAGS))
+ @echo ""
+ @echo " LIBS:"
+ $(call print_wrapped, $(LIBS))
+ @echo ""
+ @echo " CLIENT_LIBS:"
+ $(call print_wrapped, $(CLIENT_LIBS))
+ @echo ""
+ @echo " Output:"
+ $(call print_list, $(NAKED_TARGETS))
+ @echo ""
+ @$(MAKE) $(TARGETS) $(B).zip V=$(V)
+
+$(B).zip: $(TARGETS)
+ifeq ($(PLATFORM),darwin)
+ @("./make-macosx-app.sh" release $(ARCH); if [ "$$?" -eq 0 ] && [ -d "$(B)/Tremulous.app" ]; then rm -f $@; cd $(B) && zip --symlinks -r9 ../../$@ GPL COPYING CC `find "Tremulous.app" -print | sed -e "s!$(B)/!!g"`; else rm -f $@; cd $(B) && zip -r9 ../../$@ $(NAKED_TARGETS); fi)
+else
+ @rm -f $@
+ @(cd $(B) && zip -r9 ../../$@ $(NAKED_TARGETS))
+endif
+
+makedirs:
+ @if [ ! -d $(BUILD_DIR) ];then $(MKDIR) $(BUILD_DIR);fi
+ @if [ ! -d $(B) ];then $(MKDIR) $(B);fi
+ @if [ ! -d $(B)/lua ]; then $(MKDIR) $(B)/lua;fi
+ @if [ ! -d $(B)/script ]; then $(MKDIR) $(B)/script;fi
+ @if [ ! -d $(B)/script/rapidjson ]; then $(MKDIR) $(B)/script/rapidjson;fi
+ @if [ ! -d $(B)/nettle ]; then $(MKDIR) $(B)/nettle;fi
+ @if [ ! -d $(B)/semver ]; then $(MKDIR) $(B)/semver;fi
+ @if [ ! -d $(B)/client ];then $(MKDIR) $(B)/client;fi
+ @if [ ! -d $(B)/client/opus ];then $(MKDIR) $(B)/client/opus;fi
+ @if [ ! -d $(B)/client/vorbis ];then $(MKDIR) $(B)/client/vorbis;fi
+ @if [ ! -d $(B)/client/restclient ];then $(MKDIR) $(B)/client/restclient;fi
+ @if [ ! -d $(B)/ded ];then $(MKDIR) $(B)/ded;fi
+ @if [ ! -d $(B)/renderercommon ];then $(MKDIR) $(B)/renderercommon;fi
+ @if [ ! -d $(B)/renderergl1 ];then $(MKDIR) $(B)/renderergl1;fi
+ @if [ ! -d $(B)/renderergl2 ];then $(MKDIR) $(B)/renderergl2;fi
+ @if [ ! -d $(B)/renderergl2/glsl ];then $(MKDIR) $(B)/renderergl2/glsl;fi
+ @if [ ! -d $(B)/$(BASEGAME) ];then $(MKDIR) $(B)/$(BASEGAME);fi
+ @if [ ! -d $(B)/$(BASEGAME)/cgame ];then $(MKDIR) $(B)/$(BASEGAME)/cgame;fi
+ @if [ ! -d $(B)/$(BASEGAME)/game ];then $(MKDIR) $(B)/$(BASEGAME)/game;fi
+ @if [ ! -d $(B)/$(BASEGAME)/ui ];then $(MKDIR) $(B)/$(BASEGAME)/ui;fi
+ @if [ ! -d $(B)/$(BASEGAME)/qcommon ];then $(MKDIR) $(B)/$(BASEGAME)/qcommon;fi
+ @if [ ! -d $(B)/$(BASEGAME)/11 ];then $(MKDIR) $(B)/$(BASEGAME)/11;fi
+ @if [ ! -d $(B)/$(BASEGAME)/11/cgame ];then $(MKDIR) $(B)/$(BASEGAME)/11/cgame;fi
+ @if [ ! -d $(B)/$(BASEGAME)/11/ui ];then $(MKDIR) $(B)/$(BASEGAME)/11/ui;fi
+ @if [ ! -d $(B)/$(BASEGAME)/vm ];then $(MKDIR) $(B)/$(BASEGAME)/vm;fi
+ @if [ ! -d $(B)/$(BASEGAME)_11 ];then $(MKDIR) $(B)/$(BASEGAME)_11;fi
+ @if [ ! -d $(B)/$(BASEGAME)_11/vm ];then $(MKDIR) $(B)/$(BASEGAME)_11/vm;fi
+ @if [ ! -d $(B)/granger.dir ];then $(MKDIR) $(B)/granger.dir;fi
+ @if [ ! -d $(B)/granger.dir/src ];then $(MKDIR) $(B)/granger.dir/src;fi
+ @if [ ! -d $(B)/granger.dir/src/lua ];then $(MKDIR) $(B)/granger.dir/src/lua;fi
+ @if [ ! -d $(B)/granger.dir/src/premake ];then $(MKDIR) $(B)/granger.dir/src/premake;fi
+ @if [ ! -d $(B)/granger.dir/src/nettle ];then $(MKDIR) $(B)/granger.dir/src/nettle;fi
+ @if [ ! -d $(B)/tools ];then $(MKDIR) $(B)/tools;fi
+ @if [ ! -d $(B)/tools/asm ];then $(MKDIR) $(B)/tools/asm;fi
+ @if [ ! -d $(B)/tools/etc ];then $(MKDIR) $(B)/tools/etc;fi
+ @if [ ! -d $(B)/tools/rcc ];then $(MKDIR) $(B)/tools/rcc;fi
+ @if [ ! -d $(B)/tools/cpp ];then $(MKDIR) $(B)/tools/cpp;fi
+ @if [ ! -d $(B)/tools/lburg ];then $(MKDIR) $(B)/tools/lburg;fi
+
+#############################################################################
+# QVM BUILD TOOLS
+#############################################################################
+
+ifndef TOOLS_CC
+ # A compiler which probably produces native binaries
+ TOOLS_CC = gcc
+ #$(CC)
+endif
+
+ifndef YACC
+ YACC = yacc
+endif
+
+TOOLS_OPTIMIZE = -g -Wall -fno-strict-aliasing
+TOOLS_CFLAGS += $(TOOLS_OPTIMIZE) \
+ -DTEMPDIR=\"$(TEMPDIR)\" -DSYSTEM=\"\" \
+ -I$(MOUNT_DIR) \
+ -I$(Q3LCCSRCDIR) \
+ -I$(LBURGDIR)
+TOOLS_LIBS =
+TOOLS_LDFLAGS =
+
+ifeq ($(GENERATE_DEPENDENCIES),1)
+ TOOLS_CFLAGS += -MMD
+endif
+
+define DO_YACC
+$(echo_cmd) "YACC $<"
+$(Q)$(YACC) $<
+$(Q)mv -f y.tab.c $@
+endef
+
+define DO_TOOLS_CC
+$(echo_cmd) "TOOLS_CC $<"
+$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) -o $@ -c $<
+endef
+
+define DO_TOOLS_CC_DAGCHECK
+$(echo_cmd) "TOOLS_CC_DAGCHECK $<"
+$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) -Wno-unused -o $@ -c $<
+endef
+
+LBURG = $(B)/tools/lburg/lburg$(TOOLS_BINEXT)
+DAGCHECK_C = $(B)/tools/rcc/dagcheck.c
+Q3RCC = $(B)/tools/q3rcc$(TOOLS_BINEXT)
+Q3CPP = $(B)/tools/q3cpp$(TOOLS_BINEXT)
+Q3LCC = $(B)/tools/q3lcc$(TOOLS_BINEXT)
+Q3ASM = $(B)/tools/q3asm$(TOOLS_BINEXT)
+
+LBURGOBJ= \
+ $(B)/tools/lburg/lburg.o \
+ $(B)/tools/lburg/gram.o
+
+# override GNU Make built-in rule for converting gram.y to gram.c
+%.c: %.y
+ifeq ($(USE_YACC),1)
+ $(DO_YACC)
+endif
+
+$(B)/tools/lburg/%.o: $(LBURGDIR)/%.c
+ $(DO_TOOLS_CC)
+
+$(LBURG): $(LBURGOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(TOOLS_CC) -std=gnu99 $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
+
+Q3RCCOBJ = \
+ $(B)/tools/rcc/alloc.o \
+ $(B)/tools/rcc/bind.o \
+ $(B)/tools/rcc/bytecode.o \
+ $(B)/tools/rcc/dag.o \
+ $(B)/tools/rcc/dagcheck.o \
+ $(B)/tools/rcc/decl.o \
+ $(B)/tools/rcc/enode.o \
+ $(B)/tools/rcc/error.o \
+ $(B)/tools/rcc/event.o \
+ $(B)/tools/rcc/expr.o \
+ $(B)/tools/rcc/gen.o \
+ $(B)/tools/rcc/init.o \
+ $(B)/tools/rcc/inits.o \
+ $(B)/tools/rcc/input.o \
+ $(B)/tools/rcc/lex.o \
+ $(B)/tools/rcc/list.o \
+ $(B)/tools/rcc/main.o \
+ $(B)/tools/rcc/null.o \
+ $(B)/tools/rcc/output.o \
+ $(B)/tools/rcc/prof.o \
+ $(B)/tools/rcc/profio.o \
+ $(B)/tools/rcc/simp.o \
+ $(B)/tools/rcc/stmt.o \
+ $(B)/tools/rcc/string.o \
+ $(B)/tools/rcc/sym.o \
+ $(B)/tools/rcc/symbolic.o \
+ $(B)/tools/rcc/trace.o \
+ $(B)/tools/rcc/tree.o \
+ $(B)/tools/rcc/types.o
+
+$(DAGCHECK_C): $(LBURG) $(Q3LCCSRCDIR)/dagcheck.md
+ $(echo_cmd) "LBURG $(Q3LCCSRCDIR)/dagcheck.md"
+ $(Q)$(LBURG) $(Q3LCCSRCDIR)/dagcheck.md $@
+
+$(B)/tools/rcc/dagcheck.o: $(DAGCHECK_C)
+ $(DO_TOOLS_CC_DAGCHECK)
+
+$(B)/tools/rcc/%.o: $(Q3LCCSRCDIR)/%.c
+ $(DO_TOOLS_CC)
+
+$(Q3RCC): $(Q3RCCOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
+
+Q3CPPOBJ = \
+ $(B)/tools/cpp/cpp.o \
+ $(B)/tools/cpp/lex.o \
+ $(B)/tools/cpp/nlist.o \
+ $(B)/tools/cpp/tokens.o \
+ $(B)/tools/cpp/macro.o \
+ $(B)/tools/cpp/eval.o \
+ $(B)/tools/cpp/include.o \
+ $(B)/tools/cpp/hideset.o \
+ $(B)/tools/cpp/getopt.o \
+ $(B)/tools/cpp/unix.o
+
+$(B)/tools/cpp/%.o: $(Q3CPPDIR)/%.c
+ $(DO_TOOLS_CC)
+
+$(Q3CPP): $(Q3CPPOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
+
+Q3LCCOBJ = \
+ $(B)/tools/etc/lcc.o \
+ $(B)/tools/etc/bytecode.o
+
+$(B)/tools/etc/%.o: $(Q3LCCETCDIR)/%.c
+ $(DO_TOOLS_CC)
+
+$(Q3LCC): $(Q3LCCOBJ) $(Q3RCC) $(Q3CPP)
+ $(echo_cmd) "LD $@"
+ $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $(Q3LCCOBJ) $(TOOLS_LIBS)
+
+define DO_Q3LCC
+$(echo_cmd) "Q3LCC $<"
+$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -o $@ $<
+endef
+
+define DO_CGAME_Q3LCC
+$(echo_cmd) "CGAME_Q3LCC $<"
+$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DCGAME -o $@ $<
+endef
+
+define DO_GAME_Q3LCC
+$(echo_cmd) "GAME_Q3LCC $<"
+$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DGAME -o $@ $<
+endef
+
+define DO_UI_Q3LCC
+$(echo_cmd) "UI_Q3LCC $<"
+$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DUI -o $@ $<
+endef
+
+define DO_CGAME_Q3LCC_11
+$(echo_cmd) "CGAME_Q3LCC_11 $<"
+$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DMODULE_INTERFACE_11 -DCGAME -o $@ $<
+endef
+
+define DO_UI_Q3LCC_11
+$(echo_cmd) "UI_Q3LCC_11 $<"
+$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DMODULE_INTERFACE_11 -DUI -o $@ $<
+endef
+
+Q3ASMOBJ = \
+ $(B)/tools/asm/q3asm.o \
+ $(B)/tools/asm/cmdlib.o
+
+$(B)/tools/asm/%.o: $(Q3ASMDIR)/%.c
+ $(DO_TOOLS_CC)
+
+$(Q3ASM): $(Q3ASMOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
+
+#############################################################################
+# GRANGER
+#############################################################################
+
+ifeq ($(ARCH),x86_64)
+ ARCHFLAG=-m64
+else
+ifeq ($(ARCH),x86)
+ ARCHFLAG=-m32
+endif
+endif
+
+GRANGER_CFLAGS += $(ARCHFLAG) -fPIC -fpic $(LUACFLAGS)
+
+ifeq ($(PLATFORM),darwin)
+GRANGER_CFLAGS += -DLUA_USE_MACOSX
+else
+ifeq ($(PLATFORM),linux)
+GRANGER_CFLAGS += -DLUA_USE_LINUX
+endif
+endif
+
+GRANGEROBJ = \
+ $(B)/granger.dir/src/lnettlelib.o \
+ $(B)/granger.dir/src/main.o \
+ $(B)/granger.dir/src/strvec.o \
+ $(B)/granger.dir/src/lua/lapi.o \
+ $(B)/granger.dir/src/lua/lauxlib.o \
+ $(B)/granger.dir/src/lua/lbaselib.o \
+ $(B)/granger.dir/src/lua/lbitlib.o \
+ $(B)/granger.dir/src/lua/lcode.o \
+ $(B)/granger.dir/src/lua/lcorolib.o \
+ $(B)/granger.dir/src/lua/lctype.o \
+ $(B)/granger.dir/src/lua/ldblib.o \
+ $(B)/granger.dir/src/lua/ldebug.o \
+ $(B)/granger.dir/src/lua/ldo.o \
+ $(B)/granger.dir/src/lua/ldump.o \
+ $(B)/granger.dir/src/lua/lfunc.o \
+ $(B)/granger.dir/src/lua/lgc.o \
+ $(B)/granger.dir/src/lua/linit.o \
+ $(B)/granger.dir/src/lua/liolib.o \
+ $(B)/granger.dir/src/lua/llex.o \
+ $(B)/granger.dir/src/lua/lmathlib.o \
+ $(B)/granger.dir/src/lua/lmem.o \
+ $(B)/granger.dir/src/lua/loadlib.o \
+ $(B)/granger.dir/src/lua/lobject.o \
+ $(B)/granger.dir/src/lua/lopcodes.o \
+ $(B)/granger.dir/src/lua/loslib.o \
+ $(B)/granger.dir/src/lua/lparser.o \
+ $(B)/granger.dir/src/lua/lstate.o \
+ $(B)/granger.dir/src/lua/lstring.o \
+ $(B)/granger.dir/src/lua/lstrlib.o \
+ $(B)/granger.dir/src/lua/ltable.o \
+ $(B)/granger.dir/src/lua/ltablib.o \
+ $(B)/granger.dir/src/lua/ltm.o \
+ $(B)/granger.dir/src/lua/lundump.o \
+ $(B)/granger.dir/src/lua/lutf8lib.o \
+ $(B)/granger.dir/src/lua/lvm.o \
+ $(B)/granger.dir/src/lua/lzio.o \
+ $(B)/granger.dir/src/premake/os_access.o \
+ $(B)/granger.dir/src/premake/os_chdir.o \
+ $(B)/granger.dir/src/premake/os_copyfile.o \
+ $(B)/granger.dir/src/premake/os_elevate.o \
+ $(B)/granger.dir/src/premake/os_getcwd.o \
+ $(B)/granger.dir/src/premake/os_is64bit.o \
+ $(B)/granger.dir/src/premake/os_isdir.o \
+ $(B)/granger.dir/src/premake/os_isfile.o \
+ $(B)/granger.dir/src/premake/os_match.o \
+ $(B)/granger.dir/src/premake/os_mkdir.o \
+ $(B)/granger.dir/src/premake/os_pathsearch.o \
+ $(B)/granger.dir/src/premake/os_rmdir.o \
+ $(B)/granger.dir/src/premake/os_stat.o \
+ $(B)/granger.dir/src/premake/path_getabsolute.o \
+ $(B)/granger.dir/src/premake/path_getrelative.o \
+ $(B)/granger.dir/src/premake/path_isabsolute.o \
+ $(B)/granger.dir/src/premake/path_join.o \
+ $(B)/granger.dir/src/premake/path_normalize.o \
+ $(B)/granger.dir/src/premake/path_translate.o \
+ $(B)/granger.dir/src/premake/premake.o \
+ $(B)/granger.dir/src/premake/string_endswith.o \
+ $(B)/granger.dir/src/nettle/md5-compress.o \
+ $(B)/granger.dir/src/nettle/md5.o \
+ $(B)/granger.dir/src/nettle/sha256-compress.o \
+ $(B)/granger.dir/src/nettle/sha256.o \
+ $(B)/granger.dir/src/nettle/write-be32.o \
+ $(B)/granger.dir/src/nettle/write-le32.o
+
+define DO_GRANGER_CC
+ $(echo_cmd) "GRANGER_CC $<"
+ $(Q)$(call EXEC_CC,-std=gnu99 -DGRANGER ${GRANGER_CFLAGS} ${OPTIMIZE},'$@','$<')
+ $(Q)$(call LOG_CC,granger,-std=gnu99 ${GRANGER_CFLAGS} ${OPTIMIZE},$@,$<)
+endef
+
+ define DO_GRANGER_CPP
+ $(echo_cmd) "GRANGER_CC $<"
+ $(Q)$(call EXEC_CC,-std=gnu99 -DGRANGER ${GRANGER_CFLAGS} ${OPTIMIZE},'$@','$<')
+ $(Q)$(call LOG_CC,granger,-std=gnu99 ${GRANGER_CFLAGS} ${OPTIMIZE},$@,$<)
+endef
+
+$(B)/granger.dir/src/lua/%.o: $(LUADIR)/%.c
+ $(DO_GRANGER_CC)
+
+$(B)/granger.dir/src/premake/%.o: $(GRANGERDIR)/premake/%.c
+ $(DO_GRANGER_CC)
+
+$(B)/granger.dir/src/nettle/%.o: $(GRANGERDIR)/nettle/%.c
+ $(DO_GRANGER_CC)
+
+$(B)/granger.dir/src/%.o: $(GRANGERDIR)/%.c
+ $(DO_GRANGER_CC)
+
+$(B)/granger.dir/src/%.o: $(GRANGERDIR)/%.cpp
+ $(DO_GRANGER_CPP)
+
+$(B)/granger$(FULLBINEXT): $(GRANGEROBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(GRANGEROBJ) $(GRANGER_LIBS)
+
+ifneq ($(BUILD_GRANGER),0)
+TARGETS += $(B)/granger$(FULLBINEXT)
+endif
+
+$(B)/scripts:
+ rsync -rupE --exclude=".*" scripts $(B)
+
+TARGETS += $(B)/scripts
+
+$(B)/GPL:
+ rsync GPL $(B)
+$(B)/COPYING:
+ rsync COPYING $(B)
+$(B)/CC:
+ rsync CC $(B)
+
+TARGETS += $(B)/GPL $(B)/COPYING $(B)/CC
+
+#############################################################################
+# LUA
+#############################################################################
+
+#LUACFLAGS=-Wall -Wextra -fPIC -fpic
+LUACFLAGS= $(ARCHFLAG) -fPIC -fpic
+
+ifeq ($(PLATFORM),darwin)
+LUACFLAGS += -DLUA_USE_MACOSX
+else
+ifeq ($(PLATFORM),linux)
+LUACFLAGS += -DLUA_USE_LINUX
+endif
+endif
+
+LUAOBJ = \
+ $(B)/lua/lapi.o \
+ $(B)/lua/lcode.o \
+ $(B)/lua/lctype.o \
+ $(B)/lua/ldebug.o \
+ $(B)/lua/ldo.o \
+ $(B)/lua/ldump.o \
+ $(B)/lua/lfunc.o \
+ $(B)/lua/lgc.o \
+ $(B)/lua/llex.o \
+ $(B)/lua/lmem.o \
+ $(B)/lua/lobject.o \
+ $(B)/lua/lopcodes.o \
+ $(B)/lua/lparser.o \
+ $(B)/lua/lstate.o \
+ $(B)/lua/lstring.o \
+ $(B)/lua/ltable.o \
+ $(B)/lua/ltm.o \
+ $(B)/lua/lundump.o \
+ $(B)/lua/lvm.o \
+ $(B)/lua/lzio.o \
+ $(B)/lua/lauxlib.o \
+ $(B)/lua/lbaselib.o \
+ $(B)/lua/lbitlib.o \
+ $(B)/lua/lcorolib.o \
+ $(B)/lua/ldblib.o \
+ $(B)/lua/liolib.o \
+ $(B)/lua/lmathlib.o \
+ $(B)/lua/loslib.o \
+ $(B)/lua/lstrlib.o \
+ $(B)/lua/ltablib.o \
+ $(B)/lua/lutf8lib.o \
+ $(B)/lua/loadlib.o \
+ $(B)/lua/linit.o
+
+define DO_LUA_CC
+ $(echo_cmd) "LUA_CC $<"
+ $(Q)$(call EXEC_CC,${LUACFLAGS} ${OPTIMIZE},'$@','$<')
+ $(Q)$(call LOG_CC,lua,${LUACFLAGS} ${OPTIMIZE},$@,$<)
+endef
+
+LUACFLAGS += -I$(EXTERNAL_DIR)/lua-5.3.3/include -I$(EXTERNAL_DIR)/sol
+CFLAGS += $(LUACFLAGS)
+CXXFLAGS += $(LUACFLAGS)
+
+$(B)/lua/%.o: $(LUADIR)/%.c
+ $(DO_LUA_CC)
+
+#############################################################################
+# Script API
+# FIXME Disabled for the time being
+#############################################################################
+
+SCRIPT_INCLUDES=-I$(MOUNT_DIR) -I$(EXTERNAL_DIR)/rapidjson -I$(EXTERNAL_DIR)/sol -I$(EXTERNAL_DIR)/nettle-3.3
+define DO_SCRIPT_CXX
+ $(echo_cmd) "SCRIPT_CXX $<"
+ $(Q)$(call EXEC_CXX,${NOTSHLIBCFLAGS} ${SCRIPT_INCLUDES} ${LUACFLAGS} ${OPTIMIZE},'$@','$<')
+ $(Q)$(call LOG_CXX,script,${NOTSHLIBCFLAGS} ${SCRIPT_INCLUDES} ${LUACFLAGS} ${OPTIMIZE},'$@','$<')
+endef
+
+define DO_SCRIPT_CC
+ $(echo_cmd) "SCRIPT_CC $<"
+ $(Q)$(call EXEC_CC,${NOTSHLIBCFLAGS} ${SCRIPT_INCLUDES} ${LUACFLAGS} ${OPTIMIZE},'$@','$<')
+ $(Q)$(call LOG_CC,script,${NOTSHLIBCFLAGS} ${SCRIPT_INCLUDES} ${LUACFLAGS} ${OPTIMIZE},'$@','$<')
+endef
+
+SCRIPTOBJ = \
+ $(B)/script/lnettlelib.o \
+ $(B)/script/rapidjson/document.o \
+ $(B)/script/rapidjson/rapidjson.o \
+ $(B)/script/rapidjson/schema.o \
+ $(B)/script/rapidjson/values.o
+
+CFLAGS += -I${LUA_RAPIDJSONDIR} -I${SCRIPT_INCLUDES}
+
+$(B)/script/%.o: $(SCRIPTDIR)/%.c
+ $(DO_SCRIPT_CC)
+
+$(B)/script/rapidjson/%.o: $(LUA_RAPIDJSONDIR)/%.cpp
+ $(DO_SCRIPT_CXX)
+
+#############################################################################
+# Nettle
+#############################################################################
+
+NETTLECFLAGS=$(ARCHFLAG) -fPIC -fpic
+
+define DO_NETTLE_CC
+ $(echo_cmd) "NETTLE_CC $<"
+ $(Q)$(call EXEC_CC,${NETTLECFLAGS},'$@','$<')
+ $(Q)$(call LOG_CC,nettle,${NETTLECFLAGS},'$@','$<')
+endef
+
+NETTLEOBJ = \
+ $(B)/nettle/bignum.o \
+ $(B)/nettle/bignum-random.o \
+ $(B)/nettle/bignum-random-prime.o \
+ $(B)/nettle/buffer.o \
+ $(B)/nettle/buffer-init.o \
+ $(B)/nettle/gmp-glue.o \
+ $(B)/nettle/mini-gmp.o \
+ $(B)/nettle/pkcs1.o \
+ $(B)/nettle/pkcs1-rsa-sha256.o \
+ $(B)/nettle/realloc.o \
+ $(B)/nettle/rsa.o \
+ $(B)/nettle/rsa2sexp.o \
+ $(B)/nettle/rsa-keygen.o \
+ $(B)/nettle/rsa-sha256-sign.o \
+ $(B)/nettle/rsa-sha256-verify.o \
+ $(B)/nettle/rsa-sign.o \
+ $(B)/nettle/rsa-verify.o \
+ $(B)/nettle/sexp.o \
+ $(B)/nettle/sexp-format.o \
+ $(B)/nettle/sexp2bignum.o \
+ $(B)/nettle/sexp2rsa.o \
+ $(B)/nettle/sha256-compress.o \
+ $(B)/nettle/sha256.o \
+ $(B)/nettle/write-be32.o
+
+CFLAGS += -I$(NETTLEDIR)
+
+$(B)/nettle/%.o: $(NETTLEDIR)/nettle/%.c
+ $(DO_NETTLE_CC)
+
+#############################################################################
+# Semver
+#############################################################################
+
+SEMVERCFLAGS=$(ARCHFLAG) -fPIC -fpic -I$(SEMVERDIR)/src/include
+
+define DO_SEMVER_CXX
+ $(echo_cmd) "SEMVER_CC $<"
+ $(CXX) -std=c++1y ${CXXFLAGS} ${SEMVERCFLAGS} -o $@ -c $<
+endef
+
+SEMVEROBJ = \
+ $(B)/semver/semantic_version_v1.o \
+ $(B)/semver/semantic_version_v2.o
+
+CFLAGS += -I$(SEMVERDIR)/src/include
+
+$(B)/semver/%.o: $(SEMVERDIR)/src/lib/%.cpp
+ $(DO_SEMVER_CXX)
+
+#############################################################################
+# CLIENT/SERVER
+#############################################################################
+
+# FIXME: This should be CLIENT_INCLUDES and SERVER_INCLUDES to differentiate
+# from GRANGER_INCLUDES etc.
+CFLAGS += -I$(MOUNT_DIR)
+
+Q3OBJ = \
+ $(B)/client/cl_cgame.o \
+ $(B)/client/cl_cin.o \
+ $(B)/client/cl_console.o \
+ $(B)/client/cl_input.o \
+ $(B)/client/cl_keys.o \
+ $(B)/client/cl_main.o \
+ $(B)/client/cl_net_chan.o \
+ $(B)/client/cl_parse.o \
+ $(B)/client/cl_scrn.o \
+ $(B)/client/cl_ui.o \
+ $(B)/client/cl_updates.o \
+ $(B)/client/cl_rest.o \
+ $(B)/client/cl_avi.o \
+ \
+ $(B)/client/q3_lauxlib.o \
+ \
+ $(B)/client/cm_load.o \
+ $(B)/client/cm_patch.o \
+ $(B)/client/cm_polylib.o \
+ $(B)/client/cm_test.o \
+ $(B)/client/cm_trace.o \
+ \
+ $(B)/client/cmd.o \
+ $(B)/client/common.o \
+ $(B)/client/crypto.o \
+ $(B)/client/cvar.o \
+ $(B)/client/files.o \
+ $(B)/client/md4.o \
+ $(B)/client/md5.o \
+ $(B)/client/msg.o \
+ $(B)/client/net_chan.o \
+ $(B)/client/net_ip.o \
+ $(B)/client/huffman.o \
+ $(B)/client/parse.o \
+ \
+ $(B)/client/snd_adpcm.o \
+ $(B)/client/snd_dma.o \
+ $(B)/client/snd_mem.o \
+ $(B)/client/snd_mix.o \
+ $(B)/client/snd_wavelet.o \
+ \
+ $(B)/client/snd_main.o \
+ $(B)/client/snd_codec.o \
+ $(B)/client/snd_codec_wav.o \
+ $(B)/client/snd_codec_ogg.o \
+ $(B)/client/snd_codec_opus.o \
+ \
+ $(B)/client/qal.o \
+ $(B)/client/snd_openal.o \
+ \
+ $(B)/client/cl_curl.o \
+ \
+ $(B)/client/sv_ccmds.o \
+ $(B)/client/sv_client.o \
+ $(B)/client/sv_game.o \
+ $(B)/client/sv_init.o \
+ $(B)/client/sv_main.o \
+ $(B)/client/sv_net_chan.o \
+ $(B)/client/sv_snapshot.o \
+ $(B)/client/sv_world.o \
+ \
+ $(B)/client/q_math.o \
+ $(B)/client/q_shared.o \
+ \
+ $(B)/client/unzip.o \
+ $(B)/client/ioapi.o \
+ $(B)/client/puff.o \
+ $(B)/client/vm.o \
+ $(B)/client/vm_interpreted.o \
+ \
+ \
+ $(B)/client/sdl_input.o \
+ $(B)/client/sdl_snd.o \
+ \
+ $(B)/client/con_log.o \
+ $(B)/client/sys_main.o
+
+ifdef MINGW
+ Q3OBJ += \
+ $(B)/client/con_passive.o
+else
+ Q3OBJ += \
+ $(B)/client/con_tty.o
+endif
+
+Q3OBJ += $(LUAOBJ) $(SCRIPTOBJ) $(NETTLEOBJ) $(SEMVEROBJ)
+
+Q3R2OBJ = \
+ $(B)/renderergl2/tr_animation.o \
+ $(B)/renderergl2/tr_backend.o \
+ $(B)/renderergl2/tr_bsp.o \
+ $(B)/renderergl2/tr_cmds.o \
+ $(B)/renderergl2/tr_curve.o \
+ $(B)/renderergl2/tr_dsa.o \
+ $(B)/renderergl2/tr_extramath.o \
+ $(B)/renderergl2/tr_extensions.o \
+ $(B)/renderergl2/tr_fbo.o \
+ $(B)/renderergl2/tr_flares.o \
+ $(B)/renderergl2/tr_font.o \
+ $(B)/renderergl2/tr_glsl.o \
+ $(B)/renderergl2/tr_image.o \
+ $(B)/renderergl2/tr_image_bmp.o \
+ $(B)/renderergl2/tr_image_jpg.o \
+ $(B)/renderergl2/tr_image_pcx.o \
+ $(B)/renderergl2/tr_image_png.o \
+ $(B)/renderergl2/tr_image_tga.o \
+ $(B)/renderergl2/tr_image_dds.o \
+ $(B)/renderergl2/tr_init.o \
+ $(B)/renderergl2/tr_light.o \
+ $(B)/renderergl2/tr_main.o \
+ $(B)/renderergl2/tr_marks.o \
+ $(B)/renderergl2/tr_mesh.o \
+ $(B)/renderergl2/tr_model.o \
+ $(B)/renderergl2/tr_model_iqm.o \
+ $(B)/renderergl2/tr_noise.o \
+ $(B)/renderergl2/tr_postprocess.o \
+ $(B)/renderergl2/tr_scene.o \
+ $(B)/renderergl2/tr_shade.o \
+ $(B)/renderergl2/tr_shade_calc.o \
+ $(B)/renderergl2/tr_shader.o \
+ $(B)/renderergl2/tr_shadows.o \
+ $(B)/renderergl2/tr_sky.o \
+ $(B)/renderergl2/tr_surface.o \
+ $(B)/renderergl2/tr_vbo.o \
+ $(B)/renderergl2/tr_world.o \
+ \
+ $(B)/renderercommon/sdl_gamma.o \
+ $(B)/renderercommon/sdl_glimp.o
+
+ifneq ($(USE_RENDERER_DLOPEN), 0)
+ Q3R2OBJ += \
+ $(B)/renderergl1/q_shared.o \
+ $(B)/renderergl1/puff.o \
+ $(B)/renderergl1/q_math.o \
+ $(B)/renderergl1/tr_subs.o
+endif
+
+Q3R2STRINGOBJ = \
+ $(B)/renderergl2/glsl/bokeh_fp.o \
+ $(B)/renderergl2/glsl/bokeh_vp.o \
+ $(B)/renderergl2/glsl/calclevels4x_fp.o \
+ $(B)/renderergl2/glsl/calclevels4x_vp.o \
+ $(B)/renderergl2/glsl/depthblur_fp.o \
+ $(B)/renderergl2/glsl/depthblur_vp.o \
+ $(B)/renderergl2/glsl/dlight_fp.o \
+ $(B)/renderergl2/glsl/dlight_vp.o \
+ $(B)/renderergl2/glsl/down4x_fp.o \
+ $(B)/renderergl2/glsl/down4x_vp.o \
+ $(B)/renderergl2/glsl/fogpass_fp.o \
+ $(B)/renderergl2/glsl/fogpass_vp.o \
+ $(B)/renderergl2/glsl/generic_fp.o \
+ $(B)/renderergl2/glsl/generic_vp.o \
+ $(B)/renderergl2/glsl/lightall_fp.o \
+ $(B)/renderergl2/glsl/lightall_vp.o \
+ $(B)/renderergl2/glsl/pshadow_fp.o \
+ $(B)/renderergl2/glsl/pshadow_vp.o \
+ $(B)/renderergl2/glsl/shadowfill_fp.o \
+ $(B)/renderergl2/glsl/shadowfill_vp.o \
+ $(B)/renderergl2/glsl/shadowmask_fp.o \
+ $(B)/renderergl2/glsl/shadowmask_vp.o \
+ $(B)/renderergl2/glsl/ssao_fp.o \
+ $(B)/renderergl2/glsl/ssao_vp.o \
+ $(B)/renderergl2/glsl/texturecolor_fp.o \
+ $(B)/renderergl2/glsl/texturecolor_vp.o \
+ $(B)/renderergl2/glsl/tonemap_fp.o \
+ $(B)/renderergl2/glsl/tonemap_vp.o
+
+# GL1
+
+Q3ROBJ = \
+ $(B)/renderergl1/tr_animation.o \
+ $(B)/renderergl1/tr_backend.o \
+ $(B)/renderergl1/tr_bsp.o \
+ $(B)/renderergl1/tr_cmds.o \
+ $(B)/renderergl1/tr_curve.o \
+ $(B)/renderergl1/tr_flares.o \
+ $(B)/renderergl1/tr_font.o \
+ $(B)/renderergl1/tr_image.o \
+ $(B)/renderergl1/tr_image_bmp.o \
+ $(B)/renderergl1/tr_image_jpg.o \
+ $(B)/renderergl1/tr_image_pcx.o \
+ $(B)/renderergl1/tr_image_png.o \
+ $(B)/renderergl1/tr_image_tga.o \
+ $(B)/renderergl1/tr_init.o \
+ $(B)/renderergl1/tr_light.o \
+ $(B)/renderergl1/tr_main.o \
+ $(B)/renderergl1/tr_marks.o \
+ $(B)/renderergl1/tr_mesh.o \
+ $(B)/renderergl1/tr_model.o \
+ $(B)/renderergl1/tr_model_iqm.o \
+ $(B)/renderergl1/tr_noise.o \
+ $(B)/renderergl1/tr_scene.o \
+ $(B)/renderergl1/tr_shade.o \
+ $(B)/renderergl1/tr_shade_calc.o \
+ $(B)/renderergl1/tr_shader.o \
+ $(B)/renderergl1/tr_shadows.o \
+ $(B)/renderergl1/tr_sky.o \
+ $(B)/renderergl1/tr_surface.o \
+ $(B)/renderergl1/tr_world.o \
+ \
+ $(B)/renderercommon/sdl_gamma.o \
+ $(B)/renderercommon/sdl_glimp.o
+
+ifneq ($(USE_RENDERER_DLOPEN), 0)
+ Q3ROBJ += \
+ $(B)/renderergl1/q_shared.o \
+ $(B)/renderergl1/puff.o \
+ $(B)/renderergl1/q_math.o \
+ $(B)/renderergl1/tr_subs.o
+endif
+
+ifneq ($(USE_INTERNAL_JPEG),0)
+ JPGOBJ = \
+ $(B)/renderercommon/jaricom.o \
+ $(B)/renderercommon/jcapimin.o \
+ $(B)/renderercommon/jcapistd.o \
+ $(B)/renderercommon/jcarith.o \
+ $(B)/renderercommon/jccoefct.o \
+ $(B)/renderercommon/jccolor.o \
+ $(B)/renderercommon/jcdctmgr.o \
+ $(B)/renderercommon/jchuff.o \
+ $(B)/renderercommon/jcinit.o \
+ $(B)/renderercommon/jcmainct.o \
+ $(B)/renderercommon/jcmarker.o \
+ $(B)/renderercommon/jcmaster.o \
+ $(B)/renderercommon/jcomapi.o \
+ $(B)/renderercommon/jcparam.o \
+ $(B)/renderercommon/jcprepct.o \
+ $(B)/renderercommon/jcsample.o \
+ $(B)/renderercommon/jctrans.o \
+ $(B)/renderercommon/jdapimin.o \
+ $(B)/renderercommon/jdapistd.o \
+ $(B)/renderercommon/jdarith.o \
+ $(B)/renderercommon/jdatadst.o \
+ $(B)/renderercommon/jdatasrc.o \
+ $(B)/renderercommon/jdcoefct.o \
+ $(B)/renderercommon/jdcolor.o \
+ $(B)/renderercommon/jddctmgr.o \
+ $(B)/renderercommon/jdhuff.o \
+ $(B)/renderercommon/jdinput.o \
+ $(B)/renderercommon/jdmainct.o \
+ $(B)/renderercommon/jdmarker.o \
+ $(B)/renderercommon/jdmaster.o \
+ $(B)/renderercommon/jdmerge.o \
+ $(B)/renderercommon/jdpostct.o \
+ $(B)/renderercommon/jdsample.o \
+ $(B)/renderercommon/jdtrans.o \
+ $(B)/renderercommon/jerror.o \
+ $(B)/renderercommon/jfdctflt.o \
+ $(B)/renderercommon/jfdctfst.o \
+ $(B)/renderercommon/jfdctint.o \
+ $(B)/renderercommon/jidctflt.o \
+ $(B)/renderercommon/jidctfst.o \
+ $(B)/renderercommon/jidctint.o \
+ $(B)/renderercommon/jmemmgr.o \
+ $(B)/renderercommon/jmemnobs.o \
+ $(B)/renderercommon/jquant1.o \
+ $(B)/renderercommon/jquant2.o \
+ $(B)/renderercommon/jutils.o
+endif
+
+ifeq ($(ARCH),x86)
+ Q3OBJ += \
+ $(B)/client/snd_mixa.o \
+ $(B)/client/matha.o \
+ $(B)/client/snapvector.o
+endif
+ifeq ($(ARCH),x86_64)
+ Q3OBJ += \
+ $(B)/client/snapvector.o
+endif
+
+ifeq ($(NEED_OPUS),1)
+ifeq ($(USE_INTERNAL_OPUS),1)
+Q3OBJ += \
+ $(B)/client/opus/analysis.o \
+ $(B)/client/opus/mlp.o \
+ $(B)/client/opus/mlp_data.o \
+ $(B)/client/opus/opus.o \
+ $(B)/client/opus/opus_decoder.o \
+ $(B)/client/opus/opus_encoder.o \
+ $(B)/client/opus/opus_multistream.o \
+ $(B)/client/opus/opus_multistream_encoder.o \
+ $(B)/client/opus/opus_multistream_decoder.o \
+ $(B)/client/opus/repacketizer.o \
+ \
+ $(B)/client/opus/bands.o \
+ $(B)/client/opus/celt.o \
+ $(B)/client/opus/cwrs.o \
+ $(B)/client/opus/entcode.o \
+ $(B)/client/opus/entdec.o \
+ $(B)/client/opus/entenc.o \
+ $(B)/client/opus/kiss_fft.o \
+ $(B)/client/opus/laplace.o \
+ $(B)/client/opus/mathops.o \
+ $(B)/client/opus/mdct.o \
+ $(B)/client/opus/modes.o \
+ $(B)/client/opus/pitch.o \
+ $(B)/client/opus/celt_encoder.o \
+ $(B)/client/opus/celt_decoder.o \
+ $(B)/client/opus/celt_lpc.o \
+ $(B)/client/opus/quant_bands.o \
+ $(B)/client/opus/rate.o \
+ $(B)/client/opus/vq.o \
+ \
+ $(B)/client/opus/CNG.o \
+ $(B)/client/opus/code_signs.o \
+ $(B)/client/opus/init_decoder.o \
+ $(B)/client/opus/decode_core.o \
+ $(B)/client/opus/decode_frame.o \
+ $(B)/client/opus/decode_parameters.o \
+ $(B)/client/opus/decode_indices.o \
+ $(B)/client/opus/decode_pulses.o \
+ $(B)/client/opus/decoder_set_fs.o \
+ $(B)/client/opus/dec_API.o \
+ $(B)/client/opus/enc_API.o \
+ $(B)/client/opus/encode_indices.o \
+ $(B)/client/opus/encode_pulses.o \
+ $(B)/client/opus/gain_quant.o \
+ $(B)/client/opus/interpolate.o \
+ $(B)/client/opus/LP_variable_cutoff.o \
+ $(B)/client/opus/NLSF_decode.o \
+ $(B)/client/opus/NSQ.o \
+ $(B)/client/opus/NSQ_del_dec.o \
+ $(B)/client/opus/PLC.o \
+ $(B)/client/opus/shell_coder.o \
+ $(B)/client/opus/tables_gain.o \
+ $(B)/client/opus/tables_LTP.o \
+ $(B)/client/opus/tables_NLSF_CB_NB_MB.o \
+ $(B)/client/opus/tables_NLSF_CB_WB.o \
+ $(B)/client/opus/tables_other.o \
+ $(B)/client/opus/tables_pitch_lag.o \
+ $(B)/client/opus/tables_pulses_per_block.o \
+ $(B)/client/opus/VAD.o \
+ $(B)/client/opus/control_audio_bandwidth.o \
+ $(B)/client/opus/quant_LTP_gains.o \
+ $(B)/client/opus/VQ_WMat_EC.o \
+ $(B)/client/opus/HP_variable_cutoff.o \
+ $(B)/client/opus/NLSF_encode.o \
+ $(B)/client/opus/NLSF_VQ.o \
+ $(B)/client/opus/NLSF_unpack.o \
+ $(B)/client/opus/NLSF_del_dec_quant.o \
+ $(B)/client/opus/process_NLSFs.o \
+ $(B)/client/opus/stereo_LR_to_MS.o \
+ $(B)/client/opus/stereo_MS_to_LR.o \
+ $(B)/client/opus/check_control_input.o \
+ $(B)/client/opus/control_SNR.o \
+ $(B)/client/opus/init_encoder.o \
+ $(B)/client/opus/control_codec.o \
+ $(B)/client/opus/A2NLSF.o \
+ $(B)/client/opus/ana_filt_bank_1.o \
+ $(B)/client/opus/biquad_alt.o \
+ $(B)/client/opus/bwexpander_32.o \
+ $(B)/client/opus/bwexpander.o \
+ $(B)/client/opus/debug.o \
+ $(B)/client/opus/decode_pitch.o \
+ $(B)/client/opus/inner_prod_aligned.o \
+ $(B)/client/opus/lin2log.o \
+ $(B)/client/opus/log2lin.o \
+ $(B)/client/opus/LPC_analysis_filter.o \
+ $(B)/client/opus/LPC_inv_pred_gain.o \
+ $(B)/client/opus/table_LSF_cos.o \
+ $(B)/client/opus/NLSF2A.o \
+ $(B)/client/opus/NLSF_stabilize.o \
+ $(B)/client/opus/NLSF_VQ_weights_laroia.o \
+ $(B)/client/opus/pitch_est_tables.o \
+ $(B)/client/opus/resampler.o \
+ $(B)/client/opus/resampler_down2_3.o \
+ $(B)/client/opus/resampler_down2.o \
+ $(B)/client/opus/resampler_private_AR2.o \
+ $(B)/client/opus/resampler_private_down_FIR.o \
+ $(B)/client/opus/resampler_private_IIR_FIR.o \
+ $(B)/client/opus/resampler_private_up2_HQ.o \
+ $(B)/client/opus/resampler_rom.o \
+ $(B)/client/opus/sigm_Q15.o \
+ $(B)/client/opus/sort.o \
+ $(B)/client/opus/sum_sqr_shift.o \
+ $(B)/client/opus/stereo_decode_pred.o \
+ $(B)/client/opus/stereo_encode_pred.o \
+ $(B)/client/opus/stereo_find_predictor.o \
+ $(B)/client/opus/stereo_quant_pred.o \
+ \
+ $(B)/client/opus/apply_sine_window_FLP.o \
+ $(B)/client/opus/corrMatrix_FLP.o \
+ $(B)/client/opus/encode_frame_FLP.o \
+ $(B)/client/opus/find_LPC_FLP.o \
+ $(B)/client/opus/find_LTP_FLP.o \
+ $(B)/client/opus/find_pitch_lags_FLP.o \
+ $(B)/client/opus/find_pred_coefs_FLP.o \
+ $(B)/client/opus/LPC_analysis_filter_FLP.o \
+ $(B)/client/opus/LTP_analysis_filter_FLP.o \
+ $(B)/client/opus/LTP_scale_ctrl_FLP.o \
+ $(B)/client/opus/noise_shape_analysis_FLP.o \
+ $(B)/client/opus/prefilter_FLP.o \
+ $(B)/client/opus/process_gains_FLP.o \
+ $(B)/client/opus/regularize_correlations_FLP.o \
+ $(B)/client/opus/residual_energy_FLP.o \
+ $(B)/client/opus/solve_LS_FLP.o \
+ $(B)/client/opus/warped_autocorrelation_FLP.o \
+ $(B)/client/opus/wrappers_FLP.o \
+ $(B)/client/opus/autocorrelation_FLP.o \
+ $(B)/client/opus/burg_modified_FLP.o \
+ $(B)/client/opus/bwexpander_FLP.o \
+ $(B)/client/opus/energy_FLP.o \
+ $(B)/client/opus/inner_product_FLP.o \
+ $(B)/client/opus/k2a_FLP.o \
+ $(B)/client/opus/levinsondurbin_FLP.o \
+ $(B)/client/opus/LPC_inv_pred_gain_FLP.o \
+ $(B)/client/opus/pitch_analysis_core_FLP.o \
+ $(B)/client/opus/scale_copy_vector_FLP.o \
+ $(B)/client/opus/scale_vector_FLP.o \
+ $(B)/client/opus/schur_FLP.o \
+ $(B)/client/opus/sort_FLP.o \
+ \
+ $(B)/client/http.o \
+ $(B)/client/info.o \
+ $(B)/client/internal.o \
+ $(B)/client/opusfile.o \
+ $(B)/client/stream.o \
+ $(B)/client/wincerts.o
+endif
+endif
+
+ifeq ($(NEED_OGG),1)
+ifeq ($(USE_INTERNAL_OGG),1)
+Q3OBJ += \
+ $(B)/client/bitwise.o \
+ $(B)/client/framing.o
+endif
+endif
+
+ifeq ($(USE_CODEC_VORBIS),1)
+ifeq ($(USE_INTERNAL_VORBIS),1)
+Q3OBJ += \
+ $(B)/client/vorbis/analysis.o \
+ $(B)/client/vorbis/bitrate.o \
+ $(B)/client/vorbis/block.o \
+ $(B)/client/vorbis/codebook.o \
+ $(B)/client/vorbis/envelope.o \
+ $(B)/client/vorbis/floor0.o \
+ $(B)/client/vorbis/floor1.o \
+ $(B)/client/vorbis/info.o \
+ $(B)/client/vorbis/lookup.o \
+ $(B)/client/vorbis/lpc.o \
+ $(B)/client/vorbis/lsp.o \
+ $(B)/client/vorbis/mapping0.o \
+ $(B)/client/vorbis/mdct.o \
+ $(B)/client/vorbis/psy.o \
+ $(B)/client/vorbis/registry.o \
+ $(B)/client/vorbis/res0.o \
+ $(B)/client/vorbis/smallft.o \
+ $(B)/client/vorbis/sharedbook.o \
+ $(B)/client/vorbis/synthesis.o \
+ $(B)/client/vorbis/vorbisfile.o \
+ $(B)/client/vorbis/window.o
+endif
+endif
+
+ifeq ($(USE_INTERNAL_ZLIB),1)
+Q3OBJ += \
+ $(B)/client/adler32.o \
+ $(B)/client/crc32.o \
+ $(B)/client/inffast.o \
+ $(B)/client/inflate.o \
+ $(B)/client/inftrees.o \
+ $(B)/client/zutil.o
+endif
+
+#-bbq
+ifeq ($(USE_RESTCLIENT),1)
+ Q3OBJ += \
+ $(B)/client/restclient/connection.o \
+ $(B)/client/restclient/helpers.o \
+ $(B)/client/restclient/restclient.o
+endif
+
+ifeq ($(HAVE_VM_COMPILED),true)
+ ifneq ($(findstring $(ARCH),x86 x86_64),)
+ Q3OBJ += $(B)/client/vm_x86.o
+ endif
+ ifneq ($(findstring $(ARCH),ppc ppc64),)
+ Q3OBJ += $(B)/client/vm_powerpc.o $(B)/client/vm_powerpc_asm.o
+ endif
+ ifeq ($(ARCH),sparc)
+ Q3OBJ += $(B)/client/vm_sparc.o
+ endif
+endif
+
+ifdef MINGW
+ Q3OBJ += \
+ $(B)/client/win_resource.o \
+ $(B)/client/sys_win32.o \
+ $(B)/client/sys_win32_default_homepath.o
+else
+ Q3OBJ += \
+ $(B)/client/sys_unix.o
+endif
+
+ifeq ($(PLATFORM),darwin)
+ Q3OBJ += \
+ $(B)/client/sys_osx.o
+endif
+
+ifeq ($(USE_MUMBLE),1)
+ Q3OBJ += \
+ $(B)/client/libmumblelink.o
+endif
+
+ifneq ($(USE_RENDERER_DLOPEN),0)
+$(B)/$(CLIENTBIN)$(FULLBINEXT): $(Q3OBJ) $(LIBSDLMAIN)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CXX) -std=c++1y $(CXXFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(Q3OBJ) \
+ $(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS) -o $@
+
+$(B)/renderer_opengl1$(SHLIBNAME): $(Q3ROBJ) $(JPGOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CXX) $(SHLIBLDFLAGS) -o $@ $(Q3ROBJ) $(JPGOBJ) \
+ $(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LDFLAGS)
+
+$(B)/renderer_opengl2$(SHLIBNAME): $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CXX) $(SHLIBLDFLAGS) -o $@ $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) \
+ $(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LDFLAGS)
+else
+$(B)/$(CLIENTBIN)$(FULLBINEXT): $(Q3OBJ) $(Q3ROBJ) $(JPGOBJ) $(LIBSDLMAIN)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CXX) -std=c++1y $(CXXFLAGS) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \
+ -o $@ $(Q3OBJ) $(Q3ROBJ) $(JPGOBJ) \
+ $(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS)
+
+$(B)/$(CLIENTBIN)_opengl2$(FULLBINEXT): $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) $(LIBSDLMAIN)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CXX) -std=c++1y $(CXXFLAGS) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \
+ -o $@ $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) \
+ $(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS)
+endif
+
+ifneq ($(strip $(LIBSDLMAIN)),)
+ifneq ($(strip $(LIBSDLMAINSRC)),)
+$(LIBSDLMAIN) : $(LIBSDLMAINSRC)
+ cp $< $@
+ $(RANLIB) $@
+endif
+endif
+
+
+
+#############################################################################
+# DEDICATED SERVER
+#############################################################################
+
+Q3DOBJ = \
+ $(B)/ded/sv_client.o \
+ $(B)/ded/sv_ccmds.o \
+ $(B)/ded/sv_game.o \
+ $(B)/ded/sv_init.o \
+ $(B)/ded/sv_main.o \
+ $(B)/ded/sv_net_chan.o \
+ $(B)/ded/sv_snapshot.o \
+ $(B)/ded/sv_world.o \
+ \
+ $(B)/ded/q3_lauxlib.o \
+ \
+ $(B)/ded/cm_load.o \
+ $(B)/ded/cm_patch.o \
+ $(B)/ded/cm_polylib.o \
+ $(B)/ded/cm_test.o \
+ $(B)/ded/cm_trace.o \
+ $(B)/ded/cmd.o \
+ $(B)/ded/common.o \
+ $(B)/ded/crypto.o \
+ $(B)/ded/cvar.o \
+ $(B)/ded/files.o \
+ $(B)/ded/md4.o \
+ $(B)/ded/msg.o \
+ $(B)/ded/net_chan.o \
+ $(B)/ded/net_ip.o \
+ $(B)/ded/huffman.o \
+ $(B)/ded/parse.o \
+ \
+ $(B)/ded/q_math.o \
+ $(B)/ded/q_shared.o \
+ \
+ $(B)/ded/unzip.o \
+ $(B)/ded/ioapi.o \
+ $(B)/ded/vm.o \
+ $(B)/ded/vm_interpreted.o \
+ \
+ $(B)/ded/null_client.o \
+ $(B)/ded/null_input.o \
+ $(B)/ded/null_snddma.o \
+ \
+ $(B)/ded/con_log.o \
+ $(B)/ded/sys_main.o
+
+ifeq ($(ARCH),x86)
+ Q3DOBJ += \
+ $(B)/ded/matha.o \
+ $(B)/ded/snapvector.o
+endif
+ifeq ($(ARCH),x86_64)
+ Q3DOBJ += \
+ $(B)/ded/snapvector.o
+endif
+
+Q3DOBJ += $(LUAOBJ) $(SCRIPTOBJ) $(NETTLEOBJ)
+
+ifeq ($(USE_INTERNAL_ZLIB),1)
+Q3DOBJ += \
+ $(B)/ded/adler32.o \
+ $(B)/ded/crc32.o \
+ $(B)/ded/inffast.o \
+ $(B)/ded/inflate.o \
+ $(B)/ded/inftrees.o \
+ $(B)/ded/zutil.o
+endif
+
+ifeq ($(HAVE_VM_COMPILED),true)
+ ifneq ($(findstring $(ARCH),x86 x86_64),)
+ Q3DOBJ += \
+ $(B)/ded/vm_x86.o
+ endif
+ ifneq ($(findstring $(ARCH),ppc ppc64),)
+ Q3DOBJ += $(B)/ded/vm_powerpc.o $(B)/ded/vm_powerpc_asm.o
+ endif
+ ifeq ($(ARCH),sparc)
+ Q3DOBJ += $(B)/ded/vm_sparc.o
+ endif
+endif
+
+ifdef MINGW
+ Q3DOBJ += \
+ $(B)/ded/win_resource.o \
+ $(B)/ded/sys_win32.o \
+ $(B)/ded/sys_win32_default_homepath.o \
+ $(B)/ded/con_win32.o
+else
+ Q3DOBJ += \
+ $(B)/ded/sys_unix.o \
+ $(B)/ded/con_tty.o
+endif
+
+ifeq ($(PLATFORM),darwin)
+ Q3DOBJ += \
+ $(B)/ded/sys_osx.o
+endif
+
+$(B)/$(SERVERBIN)$(FULLBINEXT): $(Q3DOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(Q3DOBJ) $(LIBS)
+
+#############################################################################
+## TREMULOUS CGAME
+#############################################################################
+
+CGOBJ_ = \
+ $(B)/$(BASEGAME)/cgame/cg_main.o \
+ $(B)/$(BASEGAME)/cgame/bg_misc.o \
+ $(B)/$(BASEGAME)/cgame/bg_pmove.o \
+ $(B)/$(BASEGAME)/cgame/bg_slidemove.o \
+ $(B)/$(BASEGAME)/cgame/bg_lib.o \
+ $(B)/$(BASEGAME)/cgame/bg_alloc.o \
+ $(B)/$(BASEGAME)/cgame/bg_voice.o \
+ $(B)/$(BASEGAME)/cgame/cg_consolecmds.o \
+ $(B)/$(BASEGAME)/cgame/cg_buildable.o \
+ $(B)/$(BASEGAME)/cgame/cg_animation.o \
+ $(B)/$(BASEGAME)/cgame/cg_animmapobj.o \
+ $(B)/$(BASEGAME)/cgame/cg_draw.o \
+ $(B)/$(BASEGAME)/cgame/cg_drawtools.o \
+ $(B)/$(BASEGAME)/cgame/cg_ents.o \
+ $(B)/$(BASEGAME)/cgame/cg_event.o \
+ $(B)/$(BASEGAME)/cgame/cg_marks.o \
+ $(B)/$(BASEGAME)/cgame/cg_players.o \
+ $(B)/$(BASEGAME)/cgame/cg_playerstate.o \
+ $(B)/$(BASEGAME)/cgame/cg_predict.o \
+ $(B)/$(BASEGAME)/cgame/cg_servercmds.o \
+ $(B)/$(BASEGAME)/cgame/cg_snapshot.o \
+ $(B)/$(BASEGAME)/cgame/cg_view.o \
+ $(B)/$(BASEGAME)/cgame/cg_weapons.o \
+ $(B)/$(BASEGAME)/cgame/cg_scanner.o \
+ $(B)/$(BASEGAME)/cgame/cg_attachment.o \
+ $(B)/$(BASEGAME)/cgame/cg_trails.o \
+ $(B)/$(BASEGAME)/cgame/cg_particles.o \
+ $(B)/$(BASEGAME)/cgame/cg_tutorial.o \
+ $(B)/$(BASEGAME)/cgame/cg_rangemarker.o \
+ $(B)/$(BASEGAME)/cgame/ui_shared.o \
+ \
+ $(B)/$(BASEGAME)/qcommon/q_math.o \
+ $(B)/$(BASEGAME)/qcommon/q_shared.o
+
+CGOBJ = $(CGOBJ_) $(B)/$(BASEGAME)/cgame/cg_syscalls.o
+CGVMOBJ = $(CGOBJ_:%.o=%.asm)
+
+$(B)/$(BASEGAME)/cgame$(SHLIBNAME): $(CGOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(SHLIBLDFLAGS) $(LDFLAGS) -o $@ $(CGOBJ)
+
+$(B)/$(BASEGAME)/vm/cgame.qvm: $(CGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM)
+ $(echo_cmd) "Q3ASM $@"
+ $(Q)$(Q3ASM) -o $@ $(CGVMOBJ) $(CGDIR)/cg_syscalls.asm
+
+#############################################################################
+## TREMULOUS CGAME (1.1 COMPATIBLE)
+#############################################################################
+
+CGOBJ11_ = \
+ $(B)/$(BASEGAME)/11/cgame/cg_main.o \
+ $(B)/$(BASEGAME)/cgame/bg_misc.o \
+ $(B)/$(BASEGAME)/cgame/bg_pmove.o \
+ $(B)/$(BASEGAME)/cgame/bg_slidemove.o \
+ $(B)/$(BASEGAME)/cgame/bg_lib.o \
+ $(B)/$(BASEGAME)/cgame/bg_alloc.o \
+ $(B)/$(BASEGAME)/cgame/bg_voice.o \
+ $(B)/$(BASEGAME)/11/cgame/cg_consolecmds.o \
+ $(B)/$(BASEGAME)/cgame/cg_buildable.o \
+ $(B)/$(BASEGAME)/cgame/cg_animation.o \
+ $(B)/$(BASEGAME)/cgame/cg_animmapobj.o \
+ $(B)/$(BASEGAME)/cgame/cg_draw.o \
+ $(B)/$(BASEGAME)/cgame/cg_drawtools.o \
+ $(B)/$(BASEGAME)/cgame/cg_ents.o \
+ $(B)/$(BASEGAME)/cgame/cg_event.o \
+ $(B)/$(BASEGAME)/cgame/cg_marks.o \
+ $(B)/$(BASEGAME)/cgame/cg_players.o \
+ $(B)/$(BASEGAME)/cgame/cg_playerstate.o \
+ $(B)/$(BASEGAME)/cgame/cg_predict.o \
+ $(B)/$(BASEGAME)/11/cgame/cg_servercmds.o \
+ $(B)/$(BASEGAME)/11/cgame/cg_snapshot.o \
+ $(B)/$(BASEGAME)/cgame/cg_view.o \
+ $(B)/$(BASEGAME)/cgame/cg_weapons.o \
+ $(B)/$(BASEGAME)/cgame/cg_scanner.o \
+ $(B)/$(BASEGAME)/cgame/cg_attachment.o \
+ $(B)/$(BASEGAME)/cgame/cg_trails.o \
+ $(B)/$(BASEGAME)/cgame/cg_particles.o \
+ $(B)/$(BASEGAME)/cgame/cg_tutorial.o \
+ $(B)/$(BASEGAME)/cgame/cg_rangemarker.o \
+ $(B)/$(BASEGAME)/cgame/ui_shared.o \
+ \
+ $(B)/$(BASEGAME)/qcommon/q_math.o \
+ $(B)/$(BASEGAME)/qcommon/q_shared.o
+
+CGVMOBJ11 = $(CGOBJ11_:%.o=%.asm)
+
+$(B)/$(BASEGAME)_11/vm/cgame.qvm: $(CGVMOBJ11) $(CGDIR)/cg_syscalls_11.asm $(Q3ASM)
+ $(echo_cmd) "Q3ASM_11 $@"
+ $(Q)$(Q3ASM) -o $@ $(CGVMOBJ11) $(CGDIR)/cg_syscalls_11.asm
+
+#############################################################################
+## TREMULOUS GAME
+#############################################################################
+
+GOBJ_ = \
+ $(B)/$(BASEGAME)/game/g_main.o \
+ $(B)/$(BASEGAME)/game/bg_misc.o \
+ $(B)/$(BASEGAME)/game/bg_pmove.o \
+ $(B)/$(BASEGAME)/game/bg_slidemove.o \
+ $(B)/$(BASEGAME)/game/bg_lib.o \
+ $(B)/$(BASEGAME)/game/bg_alloc.o \
+ $(B)/$(BASEGAME)/game/bg_voice.o \
+ $(B)/$(BASEGAME)/game/g_active.o \
+ $(B)/$(BASEGAME)/game/g_client.o \
+ $(B)/$(BASEGAME)/game/g_cmds.o \
+ $(B)/$(BASEGAME)/game/g_combat.o \
+ $(B)/$(BASEGAME)/game/g_physics.o \
+ $(B)/$(BASEGAME)/game/g_buildable.o \
+ $(B)/$(BASEGAME)/game/g_misc.o \
+ $(B)/$(BASEGAME)/game/g_missile.o \
+ $(B)/$(BASEGAME)/game/g_mover.o \
+ $(B)/$(BASEGAME)/game/g_session.o \
+ $(B)/$(BASEGAME)/game/g_spawn.o \
+ $(B)/$(BASEGAME)/game/g_svcmds.o \
+ $(B)/$(BASEGAME)/game/g_target.o \
+ $(B)/$(BASEGAME)/game/g_team.o \
+ $(B)/$(BASEGAME)/game/g_trigger.o \
+ $(B)/$(BASEGAME)/game/g_utils.o \
+ $(B)/$(BASEGAME)/game/g_maprotation.o \
+ $(B)/$(BASEGAME)/game/g_playermodel.o \
+ $(B)/$(BASEGAME)/game/g_weapon.o \
+ $(B)/$(BASEGAME)/game/g_weapondrop.o \
+ $(B)/$(BASEGAME)/game/g_admin.o \
+ $(B)/$(BASEGAME)/game/g_namelog.o \
+ \
+ $(B)/$(BASEGAME)/qcommon/q_math.o \
+ $(B)/$(BASEGAME)/qcommon/q_shared.o
+
+GOBJ = $(GOBJ_) $(B)/$(BASEGAME)/game/g_syscalls.o
+GVMOBJ = $(GOBJ_:%.o=%.asm)
+
+$(B)/$(BASEGAME)/game$(SHLIBNAME): $(GOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(SHLIBLDFLAGS) $(LDFLAGS) -o $@ $(GOBJ)
+
+$(B)/$(BASEGAME)/vm/game.qvm: $(GVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM)
+ $(echo_cmd) "Q3ASM $@"
+ $(Q)$(Q3ASM) -o $@ $(GVMOBJ) $(GDIR)/g_syscalls.asm
+
+
+
+#############################################################################
+## TREMULOUS UI
+#############################################################################
+
+UIOBJ_ = \
+ $(B)/$(BASEGAME)/ui/ui_main.o \
+ $(B)/$(BASEGAME)/ui/ui_atoms.o \
+ $(B)/$(BASEGAME)/ui/ui_shared.o \
+ $(B)/$(BASEGAME)/ui/ui_gameinfo.o \
+ \
+ $(B)/$(BASEGAME)/ui/bg_alloc.o \
+ $(B)/$(BASEGAME)/ui/bg_voice.o \
+ $(B)/$(BASEGAME)/ui/bg_misc.o \
+ $(B)/$(BASEGAME)/ui/bg_lib.o \
+ $(B)/$(BASEGAME)/qcommon/q_math.o \
+ $(B)/$(BASEGAME)/qcommon/q_shared.o
+
+UIOBJ = $(UIOBJ_) $(B)/$(BASEGAME)/ui/ui_syscalls.o
+UIVMOBJ = $(UIOBJ_:%.o=%.asm)
+
+$(B)/$(BASEGAME)/ui$(SHLIBNAME): $(UIOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) -I${ASSETS_DIR}/ui $(SHLIBLDFLAGS) $(LDFLAGS) -o $@ $(UIOBJ)
+
+$(B)/$(BASEGAME)/vm/ui.qvm: $(UIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM)
+ $(echo_cmd) "Q3ASM $@"
+ $(Q)$(Q3ASM) -o $@ $(UIVMOBJ) $(UIDIR)/ui_syscalls.asm
+
+#############################################################################
+## TREMULOUS UI (1.1 compatibility)
+#############################################################################
+
+UIOBJ11_ = \
+ $(B)/$(BASEGAME)/11/ui/ui_main.o \
+ $(B)/$(BASEGAME)/ui/ui_atoms.o \
+ $(B)/$(BASEGAME)/ui/ui_shared.o \
+ $(B)/$(BASEGAME)/ui/ui_gameinfo.o \
+ \
+ $(B)/$(BASEGAME)/ui/bg_alloc.o \
+ $(B)/$(BASEGAME)/ui/bg_voice.o \
+ $(B)/$(BASEGAME)/ui/bg_misc.o \
+ $(B)/$(BASEGAME)/ui/bg_lib.o \
+ $(B)/$(BASEGAME)/qcommon/q_math.o \
+ $(B)/$(BASEGAME)/qcommon/q_shared.o
+UIVMOBJ11 = $(UIOBJ11_:%.o=%.asm)
+
+# XXX no dynamic library?
+
+$(B)/$(BASEGAME)_11/vm/ui.qvm: $(UIVMOBJ11) $(UIDIR)/ui_syscalls_11.asm $(Q3ASM)
+ $(echo_cmd) "Q3ASM $@"
+ $(Q)$(Q3ASM) -o $@ $(UIVMOBJ11) $(UIDIR)/ui_syscalls_11.asm
+
+#############################################################################
+## QVM Package
+#############################################################################
+
+$(B)/$(BASEGAME)/vms-gpp-$(VERSION).pk3: $(B)/$(BASEGAME)/vm/ui.qvm $(B)/$(BASEGAME)/vm/cgame.qvm $(B)/$(BASEGAME)/vm/game.qvm
+ @(cd $(B)/$(BASEGAME) && zip -r vms-$(VERSION).pk3 vm/)
+
+$(B)/$(BASEGAME)_11/vms-1.1.0-$(VERSION).pk3: $(B)/$(BASEGAME)_11/vm/ui.qvm $(B)/$(BASEGAME)_11/vm/cgame.qvm
+ @(cd $(B)/$(BASEGAME)_11 && zip -r vms-$(VERSION).pk3 vm/)
+
+
+#############################################################################
+## Assets Package
+#############################################################################
+
+$(B)/$(BASEGAME)/data-$(VERSION).pk3: $(ASSETS_DIR)/ui/main.menu
+ @(cd $(ASSETS_DIR) && zip -r data-$(VERSION).pk3 *)
+ @mv $(ASSETS_DIR)/data-$(VERSION).pk3 $(B)/$(BASEGAME)
+
+#############################################################################
+## CLIENT/SERVER RULES
+#############################################################################
+
+$(B)/client/%.o: $(ASMDIR)/%.s
+ $(DO_AS)
+
+# k8 so inline assembler knows about SSE
+$(B)/client/%.o: $(ASMDIR)/%.c
+ $(DO_CC) -march=k8
+
+$(B)/client/%.o: $(CDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(SDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(CMDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(CDIR)/%.cpp
+ $(DO_CXX)
+
+$(B)/client/%.o: $(SDIR)/%.cpp
+ $(DO_CXX)
+
+$(B)/client/%.o: $(CMDIR)/%.cpp
+ $(DO_CXX)
+
+$(B)/client/%.o: $(OGGDIR)/src/%.c
+ $(DO_CC)
+
+$(B)/client/vorbis/%.o: $(VORBISDIR)/lib/%.c
+ $(DO_CC)
+
+$(B)/client/opus/%.o: $(OPUSDIR)/src/%.c
+ $(DO_CC)
+
+$(B)/client/opus/%.o: $(OPUSDIR)/celt/%.c
+ $(DO_CC)
+
+$(B)/client/opus/%.o: $(OPUSDIR)/silk/%.c
+ $(DO_CC)
+
+$(B)/client/opus/%.o: $(OPUSDIR)/silk/float/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(OPUSFILEDIR)/src/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(ZDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(SDLDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(SDLDIR)/%.cpp
+ $(DO_CXX)
+
+$(B)/client/%.o: $(SYSDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(SYSDIR)/%.cpp
+ $(DO_CXX)
+
+$(B)/client/%.o: $(SYSDIR)/%.mm
+ $(DO_CXX)
+
+#-wtf
+$(B)/client/restclient/%.o: $(RESTDIR)/%.cpp
+ $(DO_CXX)
+
+$(B)/client/%.o: $(SYSDIR)/%.rc
+ $(DO_WINDRES)
+
+### GL1
+
+$(B)/renderercommon/%.o: $(SDLDIR)/%.c
+ $(DO_RENDERER_COMMON_CC)
+$(B)/renderercommon/%.o: $(SDLDIR)/%.cpp
+ $(DO_RENDERER_COMMON_CXX)
+$(B)/renderercommon/%.o: $(JPDIR)/%.c
+ $(DO_RENDERER_COMMON_CC)
+
+$(B)/renderergl1/%.o: $(RCOMMONDIR)/%.c
+ $(DO_RENDERER_COMMON_CC)
+$(B)/renderergl1/%.o: $(RCOMMONDIR)/%.cpp
+ $(DO_RENDERER_COMMON_CXX)
+$(B)/renderergl1/%.o: $(RGL1DIR)/%.c
+ $(DO_RENDERERGL1_CC)
+$(B)/renderergl1/%.o: $(RGL1DIR)/%.cpp
+ $(DO_RENDERERGL1_CXX)
+$(B)/renderergl1/%.o: $(CMDIR)/%.c
+ $(DO_RENDERERGL1_CC)
+$(B)/renderergl1/%.o: $(CMDIR)/%.cpp
+ $(DO_RENDERERGL1_CXX)
+
+### GL2
+
+$(B)/renderergl2/glsl/%.c: $(RGL2DIR)/glsl/%.glsl
+ $(DO_REF_STR)
+$(B)/renderergl2/glsl/%.o: $(B)/renderergl2/glsl/%.c
+ $(DO_RENDERERGL2_CC)
+$(B)/renderergl2/%.o: $(RCOMMONDIR)/%.c
+ $(DO_RENDERER_COMMON_CC)
+$(B)/renderergl2/%.o: $(RGL2DIR)/%.c
+ $(DO_RENDERERGL2_CC)
+$(B)/renderergl2/%.o: $(RCOMMONDIR)/%.cpp
+ $(DO_RENDERER_COMMON_CXX)
+$(B)/renderergl2/%.o: $(RGL2DIR)/%.cpp
+ $(DO_RENDERERGL2_CXX)
+
+$(B)/ded/%.o: $(ASMDIR)/%.s
+ $(DO_DED_AS)
+
+# k8 so inline assembler knows about SSE
+$(B)/ded/%.o: $(ASMDIR)/%.c
+ $(DO_DED_CC) -march=k8
+
+$(B)/ded/%.o: $(SDIR)/%.c
+ $(DO_DED_CC)
+
+$(B)/ded/%.o: $(SDIR)/%.cpp
+ $(DO_DED_CXX)
+
+$(B)/ded/%.o: $(CMDIR)/%.c
+ $(DO_DED_CC)
+
+$(B)/ded/%.o: $(CMDIR)/%.cpp
+ $(DO_DED_CXX)
+
+$(B)/ded/%.o: $(ZDIR)/%.c
+ $(DO_DED_CC)
+
+$(B)/ded/%.o: $(SYSDIR)/%.c
+ $(DO_DED_CC)
+
+$(B)/ded/%.o: $(SYSDIR)/%.cpp
+ $(DO_DED_CXX)
+
+$(B)/ded/%.o: $(SYSDIR)/%.mm
+ $(DO_DED_CXX)
+
+$(B)/ded/%.o: $(SYSDIR)/%.rc
+ $(DO_WINDRES)
+
+$(B)/ded/%.o: $(NDIR)/%.c
+ $(DO_DED_CC)
+
+$(B)/ded/%.o: $(NDIR)/%.cpp
+ $(DO_DED_CXX)
+
+# Extra dependencies to ensure the git version is incorporated
+ifeq ($(USE_GIT),1)
+ $(B)/client/cl_console.o : .git/index
+ $(B)/client/common.o : .git/index
+ $(B)/ded/common.o : .git/index
+endif
+
+
+#############################################################################
+## GAME MODULE RULES
+#############################################################################
+
+# CGAME
+$(B)/$(BASEGAME)/cgame/bg_%.o: $(GDIR)/bg_%.c
+ $(DO_CGAME_CC)
+
+$(B)/$(BASEGAME)/cgame/ui_%.o: $(UIDIR)/ui_%.c
+ $(DO_CGAME_CC)
+
+$(B)/$(BASEGAME)/cgame/%.o: $(CGDIR)/%.c
+ $(DO_CGAME_CC)
+
+$(B)/$(BASEGAME)/cgame/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
+ $(DO_CGAME_Q3LCC)
+
+$(B)/$(BASEGAME)/cgame/ui_%.asm: $(UIDIR)/ui_%.c $(Q3LCC)
+ $(DO_CGAME_Q3LCC)
+
+$(B)/$(BASEGAME)/cgame/%.asm: $(CGDIR)/%.c $(Q3LCC)
+ $(DO_CGAME_Q3LCC)
+
+# CGAME (1.1 COMPATIBLE)
+#$(B)/$(BASEGAME)_11/cgame/bg_%.o: $(GDIR)/bg_%.c
+# $(DO_CGAME_CC_11)
+#
+#$(B)/$(BASEGAME)_11/cgame/ui_%.o: $(UIDIR)/ui_%.c
+# $(DO_CGAME_CC_11)
+#
+#$(B)/$(BASEGAME)_11/cgame/%.o: $(CGDIR)/%.c
+# $(DO_CGAME_CC_11)
+
+$(B)/$(BASEGAME)/11/cgame/%.asm: $(CGDIR)/%.c $(Q3LCC)
+ $(DO_CGAME_Q3LCC_11)
+
+# GAME
+$(B)/$(BASEGAME)/game/%.o: $(GDIR)/%.c
+ $(DO_GAME_CC)
+
+$(B)/$(BASEGAME)/game/%.asm: $(GDIR)/%.c $(Q3LCC)
+ $(DO_GAME_Q3LCC)
+
+# UI
+$(B)/$(BASEGAME)/ui/bg_%.o: $(GDIR)/bg_%.c
+ $(DO_UI_CC)
+
+$(B)/$(BASEGAME)/ui/%.o: $(UIDIR)/%.c
+ $(DO_UI_CC)
+
+$(B)/$(BASEGAME)/ui/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
+ $(DO_UI_Q3LCC)
+
+$(B)/$(BASEGAME)/ui/%.asm: $(UIDIR)/%.c $(Q3LCC)
+ $(DO_UI_Q3LCC)
+
+# UI (1.1 COMPATIBLE)
+$(B)/$(BASEGAME)/11/ui/%.asm: $(UIDIR)/%.c $(Q3LCC)
+ $(DO_UI_Q3LCC_11)
+
+$(B)/$(BASEGAME)/qcommon/%.o: $(CMDIR)/%.c
+ $(DO_SHLIB_CC)
+
+$(B)/$(BASEGAME)/qcommon/%.asm: $(CMDIR)/%.c $(Q3LCC)
+ $(DO_Q3LCC)
+
+
+#############################################################################
+# MISC
+#############################################################################
+
+OBJ = $(Q3OBJ) $(Q3ROBJ) $(Q3R2OBJ) $(Q3DOBJ) $(JPGOBJ) \
+ $(GOBJ) $(CGOBJ) $(UIOBJ) $(LUAOBJ) $(SCRIPTOBJ) $(NETTLEOBJ) \
+ $(GVMOBJ) $(CGVMOBJ) $(UIVMOBJ) $(GRANGEROBJ)
+TOOLSOBJ = $(LBURGOBJ) $(Q3CPPOBJ) $(Q3RCCOBJ) $(Q3LCCOBJ) $(Q3ASMOBJ)
+STRINGOBJ = $(Q3R2STRINGOBJ)
+
+clean: clean-debug clean-release
+ @rm -f $(B)/compile_commands.json $(B)/compile_commands.txt $(B)/compile_commands.txt-e
+
+clean-debug:
+ @$(MAKE) clean2 B=$(BD)
+
+clean-release:
+ @$(MAKE) clean2 B=$(BR)
+
+clean2:
+ @echo "CLEAN $(B)"
+ @rm -rf $(B)/scripts
+ @rm -f $(OBJ)
+ @rm -f $(OBJ_D_FILES)
+ @rm -f $(STRINGOBJ)
+ @rm -f $(TARGETS)
+
+toolsclean: toolsclean-debug toolsclean-release
+
+toolsclean-debug:
+ @$(MAKE) toolsclean2 B=$(BD)
+
+toolsclean-release:
+ @$(MAKE) toolsclean2 B=$(BR)
+
+toolsclean2:
+ @echo "TOOLS_CLEAN $(B)"
+ @rm -f $(TOOLSOBJ)
+ @rm -f $(TOOLSOBJ_D_FILES)
+ @rm -f $(LBURG) $(DAGCHECK_C) $(Q3RCC) $(Q3CPP) $(Q3LCC) $(Q3ASM)
+
+distclean: clean toolsclean
+ @rm -rf $(BUILD_DIR)
+
+dist:
+ git archive --format zip --output $(CLIENTBIN)-$(VERSION).zip HEAD
+
+#############################################################################
+# DEPENDENCIES
+#############################################################################
+
+ifneq ($(B),)
+ OBJ_D_FILES=$(filter %.d,$(OBJ:%.o=%.d))
+ TOOLSOBJ_D_FILES=$(filter %.d,$(TOOLSOBJ:%.o=%.d))
+ -include $(OBJ_D_FILES) $(TOOLSOBJ_D_FILES)
+endif
+
+.PHONY: all clean clean2 clean-debug clean-release \
+ debug default dist distclean makedirs release targets \
+ toolsclean toolsclean2 toolsclean-debug toolsclean-release \
+ $(OBJ_D_FILES) $(TOOLSOBJ_D_FILES) $(B)/scripts \
+ $(B)/$(BASEGAME)/data-$(VERSION).pk3 \
+ $(B)/$(BASEGAME)_11/vms-$(VERSION).pk3 \
+ $(B)/$(BASEGAME)/vms-$(VERSION).pk3 \
+ $(B).zip
+
+# If the target name contains "clean", don't do a parallel build
+ifneq ($(findstring clean, $(MAKECMDGOALS)),)
+.NOTPARALLEL:
+endif
diff --git a/README.md b/README.md
index cc274b0..aff2f03 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,158 @@
-Multiprotocol-AA-QVM
-==========================
-
-This file is packaged with source, binaries, and/or assets for the
-multiprotocol AA QVM.
-
-Please visit the AA website and forum at https://aatremulous.ml \ No newline at end of file
+![Wtfbbqhax/Tremulous/tremulous-banner.jpg](misc/tremulous-banner.jpg)
+
+[![Travis branch](https://travis-ci.org/GrangerHub/tremulous.svg?branch=master)](https://travis-ci.org/GrangerHub/tremulous)
+[![Coverity Scan](https://img.shields.io/coverity/scan/9866.svg?maxAge=3600)](https://scan.coverity.com/projects/wtfbbqhax-tremulous)
+
+# How to Install from GrangerHub's Release Page
+
+You can install the latest released binaries from GrangerHub's release page,
+following these steps:
+
+* Download the most recent .zip file for your platform from https://github.com/GrangerHub/tremulous/releases
+ - The 64 bit Windows release would be named release-mingw32-x86_64.zip
+ - The 64 bit Linux release would be named release-linux-x86_64.zip
+ - The 64 bit Mac OS X release would be named release-darwin-x86_64.zip
+* Unzip the release .zip anywhere
+* Run the tremulous.exe from the unzipped release directory.
+ - When you run the tremulous.exe binary for the first time, it may go through a bootstrap (download needed assets, generate an RSA key) process which may take a few minutes.
+* You can simply continue to run the new client from wherever the unzipped release folder is, or you could optionally replace your old Tremulous binaries with the binaries in the unzipped release directory, but make sure that you copy all of the contents of the unzipped release directory to where ever you move the released binaries to. **_Backup your existing Tremulous if you intend on replacing the binaries._**
+
+# Building from Source
+
+## Dependencies
+
+If you want to build against system libraries, the following packages are necessary:
+
+### Linux:
+
+* GCC/G++ (version 6+ is recommend)
+* CMake (Optional)
+* CURL (for downloading assets)
+* rsync (for asset management)
+* Zip (the tool not the library)
+* Libgl1-mesa
+* LibSDL2
+* LibCURL4
+* LibOpenAL
+* Libfreetype6
+* Lua 5.2
+
+On Ubuntu Yakkety (specifically) you can install all the packages necessary with the following:
+
+```
+apt install -y cmake libgl1-mesa-dev libsdl2-dev libcurl4-openssl-dev libopenal-dev libfreetype6-dev mingw-w64 g++-mingw-w64 g++-multilib git zip vim-nox curl rsync
+
+```
+
+### Mingw32 (win32 cross compile)
+
+Mingw32 requires `USE_INTERNAL_LIBS=1`
+
+* Mingw-w64
+* g++-mingw-w64
+
+Currently there is no native Windows build setup, all builds are cross compiled on Linux.
+
+### OSX
+
+TBD
+
+## How to Install from the Source Code
+
+For Linux and Mac OS X builds, follow these steps.
+
+```bash
+git clone https://github.com/GrangerHub/tremulous.git
+cd tremulous
+make
+# cd build/release-darwin-x86_64/
+# cd build/release-linux-x86_64/
+./tremulous
+```
+
+# How to build for Win64
+
+Windows binaries can be built on non-Unix environments using a Docker container.
+Click [here](https://www.docker.com/) to learn more about Docker.
+
+Note that on Windows, you have to clone this Git repository with Unix line endings
+because the build system is still in Unix environment:
+
+```bash
+git clone -c core.eol=lf ...
+```
+(WARNING: Be careful to not commit back library files from this clone since their line-endings may change)
+
+To build the Tremulous binaries do:
+
+```bash
+docker run -t -i -e PLATFORM=mingw32 -v $(pwd):/usr/src grangerhub/tremulous13:latest ./misc/docker-build.sh
+```
+
+On Windows, make sure in the Docker Desktop settings that the drive you have the source
+code is selected under "Shared Drives". Then replace `$(pwd)` with the actual folder where the
+source resides (e.g. `"C:\Users\...\tremulous"`).
+
+To run:
+
+```bash
+cd build/release-mingw32-x86_64/
+./tremulous.exe
+```
+
+(use backslashes `\` if you are using Command Prompt).
+
+## Troubleshooting issues with running on Windows
+
+- If you cannot select the high-resolution display modes inside the game, check Windows
+Compatibility Settings under the Properties menu when you right-click the
+Tremulous executable. Select "Change high DPI settings" and check the
+"Override high DPI scaling behavior. Scaling performed by: Application".
+- If your FPS is low, make sure you are running the game when plugged into
+power (as opposed to laptop battery).
+
+# Where do I get the assets?
+
+The Tremulous client binary by default will attempt to retrieve the assets automatically (Known as the Pk3 bootstrap).
+However, sometimes this does not work as expected.
+
+If you need to download the assets yourself; they are available here:
+
+https://github.com/wtfbbqhax/tremulous-data
+
+Or you can checkout the entire repository:
+
+```bash
+git clone https://github.com/wtfbbqhax/tremulous-data.git
+```
+
+Copy the contents of the assets folder as a new `base/` folder in the release location.
+
+# About Lua
+
+This branch integrates Lua into the Tremulous runtime. This is a base branch for additional Lua api development to branch from.
+
+# About Transform
+
+This code allows customizing human player models with arbitray quake3 thirdparty md3-%.pk3's.
+
+This adds the admin command `/transform [name|slot#] [modelname] <skin>` which is an admin abusive command to
+force player model chanes.
+
+This also includes voice menus branch
+
+
+# Console Cvars
+
+* New Cvar `scr_useShader` enable/disable use of the console shader vs color controls below.
+ - (0, 1) default 1 (enabled)
+* New Cvar `scr_height` control console height.
+ - 100: (e.g., 100%) Default
+* New Cvar `scr_colorRed` console background red amount.
+ - (0.0f - 1.0f) default 0.0f
+* New Cvar `scr_colorGreen` console background green amount.
+ - (0.0f - 1.0f) default 0.0f
+* New Cvar `scr_colorBlue` console background blue amount.
+ - (0.0f - 1.0f) default 0.0f
+* New Cvar `scr_colorAlpha` console transparency.
+ - (0.0f - 1.0f) default 0.8f
diff --git a/assets/armour/bsuit.armour b/assets/armour/bsuit.armour
new file mode 100644
index 0000000..c05a09d
--- /dev/null
+++ b/assets/armour/bsuit.armour
@@ -0,0 +1,19 @@
+
+{
+ name "bsuit body"
+ minHeight 0.0
+ maxHeight 0.8
+ minAngle 0
+ maxAngle 360
+ modifier 0.2
+}
+
+{
+ name "bsuit head"
+ minHeight 0.8
+ maxHeight 1.0
+ minAngle 0
+ maxAngle 360
+ modifier 0.27
+}
+
diff --git a/assets/armour/helmet.armour b/assets/armour/helmet.armour
new file mode 100644
index 0000000..f595bf2
--- /dev/null
+++ b/assets/armour/helmet.armour
@@ -0,0 +1,19 @@
+
+{
+ name "helmet"
+ minHeight 0.8
+ maxHeight 1.0
+ minAngle 0
+ maxAngle 360
+ modifier 0.4
+}
+
+{
+ name "helmet crouch"
+ minHeight 0.7
+ maxHeight 1.0
+ minAngle 0
+ maxAngle 360
+ modifier 0.4
+ crouch
+}
diff --git a/assets/armour/larmour.armour b/assets/armour/larmour.armour
new file mode 100644
index 0000000..5e313fa
--- /dev/null
+++ b/assets/armour/larmour.armour
@@ -0,0 +1,95 @@
+
+{
+ name "larmour chest"
+ minHeight 0.5
+ maxHeight 0.8
+ minAngle 310
+ maxAngle 50
+ modifier 0.35
+}
+
+{
+ name "larmour left arm"
+ minHeight 0.5
+ maxHeight 0.8
+ minAngle 50
+ maxAngle 130
+ modifier 0.3
+}
+
+{
+ name "larmour back"
+ minHeight 0.5
+ maxHeight 0.8
+ minAngle 130
+ maxAngle 230
+ modifier 0.4
+}
+
+{
+ name "larmour right arm"
+ minHeight 0.5
+ maxHeight 0.8
+ minAngle 230
+ maxAngle 310
+ modifier 0.3
+}
+
+{
+ name "larmour legs"
+ minHeight 0.0
+ maxHeight 0.5
+ minAngle 0
+ maxAngle 360
+ modifier 0.3
+}
+
+{
+ name "larmour chest crouch"
+ minHeight 0.3
+ maxHeight 0.7
+ minAngle 310
+ maxAngle 50
+ modifier 0.35
+ crouch
+}
+
+{
+ name "larmour left arm crouch"
+ minHeight 0.3
+ maxHeight 0.7
+ minAngle 50
+ maxAngle 130
+ modifier 0.3
+ crouch
+}
+
+{
+ name "larmour back crouch"
+ minHeight 0.3
+ maxHeight 0.7
+ minAngle 130
+ maxAngle 230
+ modifier 0.4
+ crouch
+}
+
+{
+ name "larmour right arm crouch"
+ minHeight 0.3
+ maxHeight 0.7
+ minAngle 230
+ maxAngle 310
+ modifier 0.3
+ crouch
+}
+
+{
+ name "larmour legs crouch"
+ minHeight 0.0
+ maxHeight 0.3
+ minAngle 0
+ maxAngle 360
+ modifier 0.3
+ crouch
+}
diff --git a/assets/configs/buildables/acid_tube.cfg b/assets/configs/buildables/acid_tube.cfg
new file mode 100644
index 0000000..e44ed48
--- /dev/null
+++ b/assets/configs/buildables/acid_tube.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/acid_tube/acid_tube.md3
+modelScale 0.6
+mins -15 -15 -15
+maxs 15 15 15
+zOffset -8.5
diff --git a/assets/configs/buildables/arm.cfg b/assets/configs/buildables/arm.cfg
new file mode 100644
index 0000000..3e45fc2
--- /dev/null
+++ b/assets/configs/buildables/arm.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/arm/arm.md3
+modelScale 1.0
+mins -40 -40 -13
+maxs 40 40 50
+zOffset -2.0
diff --git a/assets/configs/buildables/barricade.cfg b/assets/configs/buildables/barricade.cfg
new file mode 100644
index 0000000..5614647
--- /dev/null
+++ b/assets/configs/buildables/barricade.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/barricade/barricade.md3
+modelScale 1.0
+mins -35 -35 -15
+maxs 35 35 60
+zOffset 0
diff --git a/assets/configs/buildables/booster.cfg b/assets/configs/buildables/booster.cfg
new file mode 100644
index 0000000..b0903df
--- /dev/null
+++ b/assets/configs/buildables/booster.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/booster/booster.md3
+modelScale 1.0
+mins -26 -26 -9
+maxs 26 26 9
+zOffset 0
diff --git a/assets/configs/buildables/dcc.cfg b/assets/configs/buildables/dcc.cfg
new file mode 100644
index 0000000..932e302
--- /dev/null
+++ b/assets/configs/buildables/dcc.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/dcc/dcc.md3
+modelScale 1.0
+mins -35 -35 -13
+maxs 35 35 47
+zOffset 0
diff --git a/assets/configs/buildables/eggpod.cfg b/assets/configs/buildables/eggpod.cfg
new file mode 100644
index 0000000..71cb6c7
--- /dev/null
+++ b/assets/configs/buildables/eggpod.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/eggpod/eggpod.md3
+modelScale 1.0
+mins -15 -15 -15
+maxs 15 15 15
+zOffset 0
diff --git a/assets/configs/buildables/hive.cfg b/assets/configs/buildables/hive.cfg
new file mode 100644
index 0000000..bd427a2
--- /dev/null
+++ b/assets/configs/buildables/hive.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/hive/hive.md3
+modelScale 1.0
+mins -20 -20 -20
+maxs 20 20 20
+zOffset -10
diff --git a/assets/configs/buildables/hovel.cfg b/assets/configs/buildables/hovel.cfg
new file mode 100644
index 0000000..5e2922c
--- /dev/null
+++ b/assets/configs/buildables/hovel.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/hovel/hovel.md3
+modelScale 1.0
+mins -50 -50 -20
+maxs 50 50 20
+zOffset 0
diff --git a/assets/configs/buildables/medistat.cfg b/assets/configs/buildables/medistat.cfg
new file mode 100644
index 0000000..179a052
--- /dev/null
+++ b/assets/configs/buildables/medistat.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/medistat/medistat.md3
+modelScale 1.0
+mins -35 -35 -7
+maxs 35 35 4
+zOffset 0
diff --git a/assets/configs/buildables/mgturret.cfg b/assets/configs/buildables/mgturret.cfg
new file mode 100644
index 0000000..83a2309
--- /dev/null
+++ b/assets/configs/buildables/mgturret.cfg
@@ -0,0 +1,7 @@
+model 0 models/buildables/mgturret/turret_base.md3
+model 1 models/buildables/mgturret/turret_barrel.md3
+model 2 models/buildables/mgturret/turret_top.md3
+modelScale 1.0
+mins -25 -25 -20
+maxs 25 25 20
+zOffset 0
diff --git a/assets/configs/buildables/overmind.cfg b/assets/configs/buildables/overmind.cfg
new file mode 100644
index 0000000..f9baca5
--- /dev/null
+++ b/assets/configs/buildables/overmind.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/overmind/overmind.md3
+modelScale 1.0
+mins -45 -45 -15
+maxs 45 45 95
+zOffset 0
diff --git a/assets/configs/buildables/reactor.cfg b/assets/configs/buildables/reactor.cfg
new file mode 100644
index 0000000..d724c44
--- /dev/null
+++ b/assets/configs/buildables/reactor.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/reactor/reactor.md3
+mins -41 -41 -15
+maxs 41 41 95
+zOffset -2.0
+modelScale 0.85
diff --git a/assets/configs/buildables/repeater.cfg b/assets/configs/buildables/repeater.cfg
new file mode 100644
index 0000000..eec2824
--- /dev/null
+++ b/assets/configs/buildables/repeater.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/repeater/repeater.md3
+modelScale 1.0
+mins -15 -15 -15
+maxs 15 15 25
+zOffset 0
diff --git a/assets/configs/buildables/telenode.cfg b/assets/configs/buildables/telenode.cfg
new file mode 100644
index 0000000..173a92f
--- /dev/null
+++ b/assets/configs/buildables/telenode.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/telenode/telenode.md3
+modelScale 1.0
+mins -40 -40 -4
+maxs 40 40 6
+zOffset 0
diff --git a/assets/configs/buildables/tesla.cfg b/assets/configs/buildables/tesla.cfg
new file mode 100644
index 0000000..36d1e33
--- /dev/null
+++ b/assets/configs/buildables/tesla.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/tesla/tesla.md3
+modelScale 1.0
+mins -22 -22 -40
+maxs 22 22 40
+zOffset 0
diff --git a/assets/configs/buildables/trapper.cfg b/assets/configs/buildables/trapper.cfg
new file mode 100644
index 0000000..0c3f0d0
--- /dev/null
+++ b/assets/configs/buildables/trapper.cfg
@@ -0,0 +1,5 @@
+model 0 models/buildables/trapper/trapper.md3
+modelScale 1.0
+mins -15 -15 -15
+maxs 15 15 15
+zOffset 0
diff --git a/assets/configs/classes/builder.cfg b/assets/configs/classes/builder.cfg
new file mode 100644
index 0000000..dd1d665
--- /dev/null
+++ b/assets/configs/classes/builder.cfg
@@ -0,0 +1,17 @@
+name "Granger"
+model builder
+modelScale 1.0
+skin default
+shadowScale 1.0
+hud alien_builder_hud
+
+mins -20 -20 -20
+maxs 20 20 20
+crouchMaxs 20 20 20
+deadMins -20 -20 -4
+deadMaxs 20 20 4
+zOffset 0.0
+
+viewheight 0
+crouchViewheight 0
+shoulderOffsets -8 15 13
diff --git a/assets/configs/classes/builderupg.cfg b/assets/configs/classes/builderupg.cfg
new file mode 100644
index 0000000..e1b73fc
--- /dev/null
+++ b/assets/configs/classes/builderupg.cfg
@@ -0,0 +1,17 @@
+name "Advanced Granger"
+model builder
+modelScale 1.0
+skin advanced
+shadowScale 1.0
+hud alien_builder_hud
+
+mins -20 -20 -20
+maxs 20 20 20
+crouchMaxs 20 20 20
+deadMins -20 -20 -4
+deadMaxs 20 20 4
+zOffset 0.0
+
+viewheight 0
+crouchViewheight 0
+shoulderOffsets -8 15 13
diff --git a/assets/configs/classes/human_base.cfg b/assets/configs/classes/human_base.cfg
new file mode 100644
index 0000000..6749bad
--- /dev/null
+++ b/assets/configs/classes/human_base.cfg
@@ -0,0 +1,17 @@
+name "Human Base"
+model human_base
+modelScale 1.0
+skin default
+shadowScale 1.0
+hud human_hud
+
+mins -15 -15 -24
+maxs 15 15 32
+crouchMaxs 15 15 16
+deadMins -15 -15 -4
+deadMaxs 15 15 4
+zOffset -2.0
+
+viewheight 24
+crouchViewheight 7
+shoulderOffsets -10 15 0
diff --git a/assets/configs/classes/human_bsuit.cfg b/assets/configs/classes/human_bsuit.cfg
new file mode 100644
index 0000000..0cdca1e
--- /dev/null
+++ b/assets/configs/classes/human_bsuit.cfg
@@ -0,0 +1,17 @@
+name "Human Battlesuit"
+model human_bsuit
+modelScale 1.0
+skin default
+shadowScale 1.0
+hud human_hud
+
+mins -15 -15 -38
+maxs 15 15 38
+crouchMaxs 15 15 38
+deadMins -15 -15 -4
+deadMaxs 15 15 4
+zOffset -16.0
+
+viewheight 29
+crouchViewheight 29
+shoulderOffsets -30 25 -2
diff --git a/assets/configs/classes/level0.cfg b/assets/configs/classes/level0.cfg
new file mode 100644
index 0000000..1497918
--- /dev/null
+++ b/assets/configs/classes/level0.cfg
@@ -0,0 +1,17 @@
+name "Dretch"
+model level0
+modelScale 1.2
+skin default
+shadowScale 0.5
+hud alien_general_hud
+
+mins -15 -15 -15
+maxs 15 15 15
+crouchMaxs 15 15 15
+deadMins -15 -15 -15
+deadMaxs 15 15 15
+zOffset -5.0
+
+viewheight 0
+crouchViewheight 0
+shoulderOffsets -5 0 17
diff --git a/assets/configs/classes/level1.cfg b/assets/configs/classes/level1.cfg
new file mode 100644
index 0000000..3add57e
--- /dev/null
+++ b/assets/configs/classes/level1.cfg
@@ -0,0 +1,17 @@
+name "Basilisk"
+model level1
+modelScale 1.0
+skin default
+shadowScale 1.0
+hud alien_general_hud
+
+mins -18 -18 -18
+maxs 18 18 18
+crouchMaxs 18 18 18
+deadMins -18 -18 -4
+deadMaxs 18 18 4
+zOffset 0.0
+
+viewheight 0
+crouchViewheight 0
+shoulderOffsets -10 0 18
diff --git a/assets/configs/classes/level1upg.cfg b/assets/configs/classes/level1upg.cfg
new file mode 100644
index 0000000..28a4beb
--- /dev/null
+++ b/assets/configs/classes/level1upg.cfg
@@ -0,0 +1,17 @@
+name "Advanced Basilisk"
+model level1
+modelScale 1.1666
+skin upgrade
+shadowScale 1.0
+hud alien_general_hud
+
+mins -21 -21 -21
+maxs 21 21 21
+crouchMaxs 21 21 21
+deadMins -21 -21 -4.666
+deadMaxs 21 21 4.666
+zOffset 0.0
+
+viewheight 0
+crouchViewheight 0
+shoulderOffsets -10 0 18
diff --git a/assets/configs/classes/level2.cfg b/assets/configs/classes/level2.cfg
new file mode 100644
index 0000000..73fc4ab
--- /dev/null
+++ b/assets/configs/classes/level2.cfg
@@ -0,0 +1,17 @@
+name "Marauder"
+model level2
+modelScale 1.0
+skin default
+shadowScale 1.0
+hud alien_general_hud
+
+mins -23 -23 -22
+maxs 23 23 14
+crouchMaxs 23 23 14
+deadMins -23 -23 -4
+deadMaxs 23 23 4
+zOffset 0.0
+
+viewheight 8
+crouchViewheight 8
+shoulderOffsets 0 12 5
diff --git a/assets/configs/classes/level2upg.cfg b/assets/configs/classes/level2upg.cfg
new file mode 100644
index 0000000..3ef853f
--- /dev/null
+++ b/assets/configs/classes/level2upg.cfg
@@ -0,0 +1,17 @@
+name "Advanced Marauder"
+model level2
+modelScale 1.1
+skin adv
+shadowScale 1.0
+hud alien_general_hud
+
+mins -25 -25 -24
+maxs 25 25 16
+crouchMaxs 25 25 16
+deadMins -25 -25 -4
+deadMaxs 25 25 4
+zOffset 0.0
+
+viewheight 10
+crouchViewheight 10
+shoulderOffsets 0 12 5
diff --git a/assets/configs/classes/level3.cfg b/assets/configs/classes/level3.cfg
new file mode 100644
index 0000000..6073201
--- /dev/null
+++ b/assets/configs/classes/level3.cfg
@@ -0,0 +1,17 @@
+name "Dragoon"
+model level3
+modelScale 1.0
+skin default
+shadowScale 1.0
+hud alien_general_hud
+
+mins -26 -26 -23
+maxs 26 26 32
+crouchMaxs 26 26 32
+deadMins -26 -26 -4
+deadMaxs 26 26 4
+zOffset 0.0
+
+viewheight 24
+crouchViewheight 24
+shoulderOffsets -10 15 8
diff --git a/assets/configs/classes/level3upg.cfg b/assets/configs/classes/level3upg.cfg
new file mode 100644
index 0000000..e0e7455
--- /dev/null
+++ b/assets/configs/classes/level3upg.cfg
@@ -0,0 +1,17 @@
+name "Advanced Dragoon"
+model level3
+modelScale 1.15
+skin adv
+shadowScale 1.0
+hud alien_general_hud
+
+mins -29 -29 -29
+maxs 29 29 37
+crouchMaxs 29 29 38
+deadMins -29 -29 -4
+deadMaxs 29 29 4
+zOffset 0.0
+
+viewheight 27
+crouchViewheight 27
+shoulderOffsets -10 17 12
diff --git a/assets/configs/classes/level4.cfg b/assets/configs/classes/level4.cfg
new file mode 100644
index 0000000..ad8482e
--- /dev/null
+++ b/assets/configs/classes/level4.cfg
@@ -0,0 +1,17 @@
+name "Tyrant"
+model level4
+modelScale 1.0
+skin default
+shadowScale 2.0
+hud alien_general_hud
+
+mins -32 -32 -22
+maxs 32 32 70
+crouchMaxs 32 32 70
+deadMins -32 -32 -34
+deadMaxs 32 32 34
+zOffset 0.0
+
+viewheight 64
+crouchViewheight 64
+shoulderOffsets -20 -25 30
diff --git a/assets/configs/classes/spectator.cfg b/assets/configs/classes/spectator.cfg
new file mode 100644
index 0000000..b1fd1e7
--- /dev/null
+++ b/assets/configs/classes/spectator.cfg
@@ -0,0 +1,17 @@
+name "Spectator"
+model ""
+modelScale 1.0
+skin ""
+shadowScale 1.0
+hud spectator_hud
+
+mins -15 -15 -15
+maxs 15 15 15
+crouchMaxs 15 15 15
+deadMins -15 -15 -15
+deadMaxs 15 15 15
+zOffset 0.0
+
+viewheight 0
+crouchViewheight 0
+shoulderOffsets 0 0 0
diff --git a/assets/models/buildables/acid_tube/animation.cfg b/assets/models/buildables/acid_tube/animation.cfg
new file mode 100644
index 0000000..19f616e
--- /dev/null
+++ b/assets/models/buildables/acid_tube/animation.cfg
@@ -0,0 +1,15 @@
+//acid tube
+0 12 0 24 // CONSTRUCT1
+0 12 0 24 // CONSTRUCT2
+12 1 0 24 // IDLE1
+0 0 0 0 // IDLE2
+0 0 0 0 // IDLE3
+13 19 0 24 // ATTACK1
+0 0 0 1 // ATTACK2
+0 0 0 1 // SPAWN1
+0 0 0 1 // SPAWN2
+12 8 0 12 // PAIN1
+0 0 0 1 // PAIN2
+0 -12 0 16 // DESTROY
+12 0 0 12 // DESTROY2
+0 1 1 1 // DESTROYED
diff --git a/assets/models/buildables/barricade/animation.cfg b/assets/models/buildables/barricade/animation.cfg
new file mode 100644
index 0000000..b4703ea
--- /dev/null
+++ b/assets/models/buildables/barricade/animation.cfg
@@ -0,0 +1,17 @@
+//barricade
+0 12 0 24 // CONSTRUCT1
+0 12 0 24 // CONSTRUCT1
+12 1 1 24 // IDLE1
+0 0 0 24 // IDLE2
+0 0 0 0 // IDLE3
+39 9 0 48 // ATTACK1 (shrink)
+39 -9 0 48 // ATTACK2 (unshrink)
+0 0 0 0 // SPAWN1
+0 0 0 0 // SPAWN2
+12 12 0 24 // PAIN1
+48 1 0 24 // PAIN2
+36 12 0 24 // DESTROY
+0 0 0 0 // DESTROY2
+48 1 1 1 // DEAD
+
+//12 frames for each pain, 6 going down 6 going up
diff --git a/assets/models/buildables/medistat/animation.cfg b/assets/models/buildables/medistat/animation.cfg
new file mode 100644
index 0000000..5a5ab0f
--- /dev/null
+++ b/assets/models/buildables/medistat/animation.cfg
@@ -0,0 +1,18 @@
+//medistation
+0 8 0 24 // CONSTRUCT
+0 8 0 24 // CONSTRUCT
+8 19 19 12 // IDLE
+32 1 1 1 // IDLE2-HEAL
+0 1 1 1 // IDLE3-NOPOWER
+27 6 0 24 // ATTACK1-HEAL
+0 0 0 0 // ATTACK2
+0 0 0 0 // SPAWN1
+0 0 0 0 // SPAWN2
+0 0 0 0 // PAIN1
+0 0 0 0 // PAIN2
+33 1 0 5 // DESTROY
+0 0 0 0 // DESTROY2
+33 1 1 1 // DEAD
+
+//attack is the heal activate
+//idle2 is the heal idle
diff --git a/assets/models/buildables/mgturret/animation.cfg b/assets/models/buildables/mgturret/animation.cfg
new file mode 100644
index 0000000..7b80fb7
--- /dev/null
+++ b/assets/models/buildables/mgturret/animation.cfg
@@ -0,0 +1,15 @@
+//mgturret
+0 1 0 1 // CONSTRUCT1
+0 1 0 1 // CONSTRUCT1
+0 1 1 1 // IDLE1
+0 1 1 1 // IDLE2
+0 1 1 1 // IDLE3-NOPOWER
+1 1 0 10 // ATTACK1
+0 1 0 0 // ATTACK2
+0 1 0 0 // SPAWN1
+0 1 0 0 // SPAWN2
+0 1 0 0 // PAIN1
+0 1 0 0 // PAIN2
+0 1 0 1 // DESTROY1
+0 1 0 0 // DESTROY2
+0 1 1 1 // DEAD
diff --git a/assets/models/buildables/repeater/animation.cfg b/assets/models/buildables/repeater/animation.cfg
new file mode 100644
index 0000000..fdfdb65
--- /dev/null
+++ b/assets/models/buildables/repeater/animation.cfg
@@ -0,0 +1,15 @@
+//repeater
+0 12 0 24 // CONSTRUCT1
+0 12 0 24 // CONSTRUCT1
+12 24 24 36 // IDLE1
+0 0 0 0 // IDLE2
+12 24 24 6 // IDLE3-NOPOWER
+0 0 0 0 // ATTACK1
+0 0 0 0 // ATTACK2
+0 0 0 0 // SPAWN1
+0 0 0 0 // SPAWN2
+0 0 0 0 // PAIN1
+0 0 0 0 // PAIN2
+37 1 0 5 // DESTROY
+0 0 0 0 // DESTROY2
+37 1 1 1 // DEAD
diff --git a/assets/models/buildables/tesla/animation.cfg b/assets/models/buildables/tesla/animation.cfg
new file mode 100644
index 0000000..2c3f1d9
--- /dev/null
+++ b/assets/models/buildables/tesla/animation.cfg
@@ -0,0 +1,15 @@
+// tesla
+0 8 0 12 // CONSTRUCT1
+0 8 0 12 // CONSTRUCT1
+8 24 24 24 // IDLE1
+0 0 0 0 // IDLE2
+32 1 1 1 // IDLE3-NOPOWER
+0 0 0 0 // ATTACK1
+0 0 0 0 // ATTACK2
+0 0 0 0 // SPAWN1
+0 0 0 0 // SPAWN2
+0 0 0 0 // PAIN1
+0 0 0 0 // PAIN2
+32 2 0 12 // DESTROY1
+0 0 0 0 // DESTROY2
+34 1 1 1 // DESTROYED
diff --git a/assets/models/generic/sphere.md3 b/assets/models/generic/sphere.md3
new file mode 100644
index 0000000..54482d6
--- /dev/null
+++ b/assets/models/generic/sphere.md3
Binary files differ
diff --git a/assets/models/generic/sphericalCone240.md3 b/assets/models/generic/sphericalCone240.md3
new file mode 100644
index 0000000..2b187da
--- /dev/null
+++ b/assets/models/generic/sphericalCone240.md3
Binary files differ
diff --git a/assets/models/generic/sphericalCone64.md3 b/assets/models/generic/sphericalCone64.md3
new file mode 100644
index 0000000..f0518fd
--- /dev/null
+++ b/assets/models/generic/sphericalCone64.md3
Binary files differ
diff --git a/assets/models/players/human_base/locdamage.cfg b/assets/models/players/human_base/locdamage.cfg
new file mode 100644
index 0000000..3beeb16
--- /dev/null
+++ b/assets/models/players/human_base/locdamage.cfg
@@ -0,0 +1,60 @@
+// These regions must cover the entire body and cannot overlap otherwise
+// the non-locational damage calculation will not be correct!
+
+{
+ name "legs"
+ minHeight 0.0
+ maxHeight 0.5
+ minAngle 0
+ maxAngle 360
+ modifier 0.5
+}
+
+{
+ name "torso"
+ minHeight 0.5
+ maxHeight 0.8
+ minAngle 0
+ maxAngle 360
+ modifier 1.0
+}
+
+{
+ name "head"
+ minHeight 0.8
+ maxHeight 1.0
+ minAngle 0
+ maxAngle 360
+ modifier 1.5
+}
+
+{
+ name "legs crouch"
+ minHeight 0.0
+ maxHeight 0.3
+ minAngle 0
+ maxAngle 360
+ modifier 0.5
+ crouch
+}
+
+{
+ name "torso crouch"
+ minHeight 0.3
+ maxHeight 0.7
+ minAngle 0
+ maxAngle 360
+ modifier 1.0
+ crouch
+}
+
+{
+ name "head crouch"
+ minHeight 0.7
+ maxHeight 1.0
+ minAngle 0
+ maxAngle 360
+ modifier 1.5
+ crouch
+}
+
diff --git a/assets/models/players/human_bsuit/locdamage.cfg b/assets/models/players/human_bsuit/locdamage.cfg
new file mode 100644
index 0000000..a2ed6d9
--- /dev/null
+++ b/assets/models/players/human_bsuit/locdamage.cfg
@@ -0,0 +1,29 @@
+// These regions must cover the entire body and cannot overlap otherwise
+// the non-locational damage calculation will not be correct!
+
+{
+ name "legs"
+ minHeight 0.0
+ maxHeight 0.5
+ minAngle 0
+ maxAngle 360
+ modifier 0.5
+}
+
+{
+ name "torso"
+ minHeight 0.5
+ maxHeight 0.8
+ minAngle 0
+ maxAngle 360
+ modifier 1.0
+}
+
+{
+ name "head"
+ minHeight 0.8
+ maxHeight 1.0
+ minAngle 0
+ maxAngle 360
+ modifier 1.5
+}
diff --git a/assets/models/players/level1/animation.cfg b/assets/models/players/level1/animation.cfg
new file mode 100644
index 0000000..1c474f9
--- /dev/null
+++ b/assets/models/players/level1/animation.cfg
@@ -0,0 +1,48 @@
+// animation config file
+// Tremulous: level1 alien
+
+sex n
+
+// first frame, num frames, looping frames, frames per second
+
+footsteps none
+
+nonsegmented
+
+0 40 40 30 //NSPA_STAND
+
+41 141 0 60 //NSPA_GESTURE
+
+182 31 31 30 //NSPA_WALK
+182 31 31 60 //NSPA_RUN
+182 -31 31 60 //NSPA_RUNBACK
+
+0 0 0 30 //NSPA_CHARGE
+
+213 31 31 60 //NSPA_RUNLEFT
+213 31 31 30 //NSPA_WALKLEFT
+244 31 31 60 //NSPA_RUNRIGHT
+244 31 31 30 //NSPA_WALKRIGHT
+
+182 31 31 30 //NSPA_SWIM
+
+275 41 20 30 //NSPA_JUMP
+316 20 0 30 //NSPA_LAND
+275 41 20 30 //NSPA_JUMPBACK
+316 20 0 30 //NSPA_LANDBACK
+
+182 31 31 30 //NSPA_TURN
+
+336 31 0 30 //NSPA_ATTACK1
+336 31 0 30 //NSPA_ATTACK2
+336 31 0 30 //NSPA_ATTACK3
+
+367 11 0 30 //NSPA_PAIN1
+367 11 0 30 //NSPA_PAIN2
+
+378 41 0 30 //NSPA_DEATH1
+418 1 0 30 //NSPA_DEAD1
+378 41 0 30 //NSPA_DEATH2
+418 1 0 30 //NSPA_DEAD2
+378 41 0 30 //NSPA_DEATH3
+418 1 0 30 //NSPA_DEAD3
diff --git a/assets/models/weapons/abuild/weapon.cfg b/assets/models/weapons/abuild/weapon.cfg
new file mode 100644
index 0000000..46cfdaa
--- /dev/null
+++ b/assets/models/weapons/abuild/weapon.cfg
@@ -0,0 +1,11 @@
+disableIn3rdPerson
+crosshair 15 gfx/2d/crosshair-alien_s
+
+icon icons/icona_builder
+
+secondary
+{
+ flashSound 0 models/weapons/abuildupg/flash0.wav
+ impactFleshSound 0 models/weapons/abuildupg/impactflesh0.wav
+ alwaysImpact
+}
diff --git a/assets/models/weapons/abuildupg/weapon.cfg b/assets/models/weapons/abuildupg/weapon.cfg
new file mode 100644
index 0000000..0646359
--- /dev/null
+++ b/assets/models/weapons/abuildupg/weapon.cfg
@@ -0,0 +1,19 @@
+disableIn3rdPerson
+crosshair 15 gfx/2d/crosshair-alien_s
+
+icon icons/icona_builder
+
+secondary
+{
+ flashSound 0 models/weapons/abuildupg/flash0.wav
+ impactFleshSound 0 models/weapons/abuildupg/impactflesh0.wav
+ alwaysImpact
+}
+
+tertiary
+{
+ missileModel models/weapons/level3upg/missile.md3
+
+ impactMark 64 creep
+ impactSound 0 sound/misc/organic_bounce.wav
+}
diff --git a/assets/models/weapons/grenade/weapon.cfg b/assets/models/weapons/grenade/weapon.cfg
new file mode 100644
index 0000000..8ba230e
--- /dev/null
+++ b/assets/models/weapons/grenade/weapon.cfg
@@ -0,0 +1,13 @@
+weaponModel models/weapons/grenade/grenade.md3
+icon icons/iconw_nade
+
+primary
+{
+ missileModel models/weapons/grenade/grenade.md3
+ missileAnimates 0 20 20 0
+
+ impactMark 64 gfx/marks/bullet_mrk
+ impactParticleSystem models/weapons/grenade/impactPS
+
+ impactSound 0 models/weapons/grenade/impact0.wav
+}
diff --git a/assets/models/weapons/lcannon/weapon.cfg b/assets/models/weapons/lcannon/weapon.cfg
new file mode 100644
index 0000000..be3ae30
--- /dev/null
+++ b/assets/models/weapons/lcannon/weapon.cfg
@@ -0,0 +1,33 @@
+weaponModel models/weapons/lcannon/lcannon.md3
+icon icons/iconw_lucifer
+crosshair 48 gfx/2d/crosshair-lcannon_s
+idleSound models/weapons/lcannon/idle.wav
+
+primary
+{
+ missileSprite 16 gfx/lcannon/primary
+ missileSpriteCharge 0.25
+ missileSound models/weapons/lcannon/missle.wav
+ missileParticleSystem models/weapons/lcannon/missilePS
+
+ flashDlightColor 1.0 1.0 0.0
+ flashSound 0 models/weapons/lcannon/flash0.wav
+
+ impactMark 32 gfx/marks/bullet_mrk
+ impactSound 0 models/weapons/lcannon/impact0.wav
+ impactParticleSystem models/weapons/lcannon/impactPS
+}
+
+secondary
+{
+ missileSprite 16 gfx/lcannon/primary
+ missileSound models/weapons/lcannon/missle.wav
+ missileParticleSystem models/weapons/lcannon/secondaryMissilePS
+
+ flashDlightColor 1.0 1.0 0.0
+ flashSound 0 models/weapons/lcannon/flash0.wav
+
+ impactMark 8 gfx/marks/bullet_mrk
+ impactSound 0 models/weapons/lcannon/impact0.wav
+ impactParticleSystem models/weapons/lcannon/secondaryImpactPS
+}
diff --git a/assets/models/weapons/level0/weapon.cfg b/assets/models/weapons/level0/weapon.cfg
new file mode 100644
index 0000000..2e52551
--- /dev/null
+++ b/assets/models/weapons/level0/weapon.cfg
@@ -0,0 +1,9 @@
+disableIn3rdPerson
+crosshair 15 gfx/2d/crosshair-alien_s
+
+icon icons/icona_lev0
+
+primary
+{
+ flashSound 0 models/weapons/level0/flash0.wav
+}
diff --git a/assets/models/weapons/level1/weapon.cfg b/assets/models/weapons/level1/weapon.cfg
new file mode 100644
index 0000000..5932283
--- /dev/null
+++ b/assets/models/weapons/level1/weapon.cfg
@@ -0,0 +1,11 @@
+disableIn3rdPerson
+crosshair 15 gfx/2d/crosshair-alien_s
+
+icon icons/icona_lev1
+
+primary
+{
+ flashSound 0 models/weapons/level1/flash0.wav
+ impactFleshSound 0 models/weapons/level1/impactflesh0.wav
+ alwaysImpact
+}
diff --git a/assets/models/weapons/level1upg/weapon.cfg b/assets/models/weapons/level1upg/weapon.cfg
new file mode 100644
index 0000000..5b60e8c
--- /dev/null
+++ b/assets/models/weapons/level1upg/weapon.cfg
@@ -0,0 +1,17 @@
+disableIn3rdPerson
+crosshair 15 gfx/2d/crosshair-alien_s
+
+icon icons/icona_lev1
+
+primary
+{
+ flashSound 0 models/weapons/level1/flash0.wav
+ impactFleshSound 0 models/weapons/level1/impactflesh0.wav
+ alwaysImpact
+}
+
+secondary
+{
+ flashSound 0 models/weapons/level1upg/gas.wav
+ muzzleParticleSystem models/weapons/level1upg/muzzlePS
+}
diff --git a/assets/models/weapons/level2/weapon.cfg b/assets/models/weapons/level2/weapon.cfg
new file mode 100644
index 0000000..927a731
--- /dev/null
+++ b/assets/models/weapons/level2/weapon.cfg
@@ -0,0 +1,11 @@
+disableIn3rdPerson
+crosshair 15 gfx/2d/crosshair-alien_s
+
+icon icons/icona_lev2
+
+primary
+{
+ flashSound 0 models/weapons/level2/flash0.wav
+ impactFleshSound 0 models/weapons/level2/impactflesh0.wav
+ alwaysImpact
+}
diff --git a/assets/models/weapons/level2upg/weapon.cfg b/assets/models/weapons/level2upg/weapon.cfg
new file mode 100644
index 0000000..7a1f26c
--- /dev/null
+++ b/assets/models/weapons/level2upg/weapon.cfg
@@ -0,0 +1,18 @@
+disableIn3rdPerson
+
+icon icons/icona_lev2
+crosshair 15 gfx/2d/crosshair-alien_s
+
+primary
+{
+ flashSound 0 models/weapons/level2/flash0.wav
+ impactFleshSound 0 models/weapons/level2/impactflesh0.wav
+ alwaysImpact
+}
+
+secondary
+{
+ flashSound 0 models/weapons/level2upg/electric.wav
+
+ impactMark 24 gfx/marks/plasma_mrk
+}
diff --git a/assets/models/weapons/level3/weapon.cfg b/assets/models/weapons/level3/weapon.cfg
new file mode 100644
index 0000000..faa2c18
--- /dev/null
+++ b/assets/models/weapons/level3/weapon.cfg
@@ -0,0 +1,16 @@
+disableIn3rdPerson
+crosshair 15 gfx/2d/crosshair-alien_s
+
+icon icons/icona_lev3
+
+primary
+{
+ flashSound 0 models/weapons/level3/flash0.wav
+ impactFleshSound 0 models/weapons/level3/impactflesh0.wav
+ alwaysImpact
+}
+
+secondary
+{
+ flashSound 0 models/weapons/level3/pounce.wav
+}
diff --git a/assets/models/weapons/level3upg/weapon.cfg b/assets/models/weapons/level3upg/weapon.cfg
new file mode 100644
index 0000000..51192f7
--- /dev/null
+++ b/assets/models/weapons/level3upg/weapon.cfg
@@ -0,0 +1,28 @@
+disableIn3rdPerson
+
+icon icons/icona_lev3
+crosshair 15 gfx/2d/crosshair-alien_s
+
+primary
+{
+ flashSound 0 models/weapons/level3/flash0.wav
+ impactFleshSound 0 models/weapons/level3/impactflesh0.wav
+ alwaysImpact
+}
+
+secondary
+{
+ flashSound 0 models/weapons/level3/pounce.wav
+}
+
+tertiary
+{
+ flashSound 0 models/weapons/level3upg/flash0.wav
+
+ missileModel models/weapons/level3upg/missile.md3
+ missileSound models/weapons/level3upg/missile.wav
+
+ impactMark 30 gfx/marks/bullet_mrk
+ impactSound 0 models/weapons/rifle/ricochet0.wav
+ impactParticleSystem models/weapons/level3upg/impactPS
+}
diff --git a/assets/models/weapons/level4/weapon.cfg b/assets/models/weapons/level4/weapon.cfg
new file mode 100644
index 0000000..b890af1
--- /dev/null
+++ b/assets/models/weapons/level4/weapon.cfg
@@ -0,0 +1,11 @@
+disableIn3rdPerson
+crosshair 15 gfx/2d/crosshair-alien_s
+
+icon icons/icona_lev4
+
+primary
+{
+ flashSound 0 models/weapons/level4/flash0.wav
+ impactFleshSound 0 models/weapons/level4/impactflesh0.wav
+ alwaysImpact
+}
diff --git a/assets/models/weapons/mdriver/weapon.cfg b/assets/models/weapons/mdriver/weapon.cfg
new file mode 100644
index 0000000..938e7ae
--- /dev/null
+++ b/assets/models/weapons/mdriver/weapon.cfg
@@ -0,0 +1,12 @@
+weaponModel models/weapons/mdriver/mdriver.md3
+icon icons/iconw_driver
+crosshair 24 gfx/2d/crosshair-mdriver_s
+
+primary
+{
+ flashDlightColor 0.0 1.0 0.0
+ flashSound 0 models/weapons/mdriver/flash0.wav
+
+ impactMark 6 gfx/marks/bullet_mrk
+ impactParticleSystem models/weapons/mdriver/impactPS
+}
diff --git a/assets/models/weapons/prifle/weapon.cfg b/assets/models/weapons/prifle/weapon.cfg
new file mode 100644
index 0000000..ca99f4f
--- /dev/null
+++ b/assets/models/weapons/prifle/weapon.cfg
@@ -0,0 +1,17 @@
+weaponModel models/weapons/prifle/prifle.md3
+icon icons/iconw_pulse
+crosshair 24 gfx/2d/crosshair-prifle_s
+
+primary
+{
+ missileSprite 3 gfx/prifle/red_blob
+ missileTrailSystem models/weapons/prifle/missileTS
+
+ flashDlightColor 1.0 0.0 0.0
+ flashSound 0 models/weapons/prifle/flash0.wav
+
+ impactMark 16 gfx/marks/bullet_mrk
+ impactParticleSystem models/weapons/prifle/impactPS
+ impactSound 0 models/weapons/prifle/impact0.wav
+ alwaysImpact
+}
diff --git a/assets/models/weapons/psaw/weapon.cfg b/assets/models/weapons/psaw/weapon.cfg
new file mode 100644
index 0000000..7b87940
--- /dev/null
+++ b/assets/models/weapons/psaw/weapon.cfg
@@ -0,0 +1,13 @@
+weaponModel models/weapons/psaw/psaw.md3
+icon icons/iconw_saw
+idleSound models/weapons/psaw/idle.wav
+crosshair 24 gfx/2d/crosshair-psaw
+
+primary
+{
+ flashDlightColor 1.0 1.0 1.0
+ firingSound models/weapons/psaw/firing.wav
+
+ impactParticleSystem models/weapons/psaw/impactPS
+ alwaysImpact
+} \ No newline at end of file
diff --git a/assets/music/Tremulous Heartbeat.mid b/assets/music/Tremulous Heartbeat.mid
new file mode 100644
index 0000000..ebf78f9
--- /dev/null
+++ b/assets/music/Tremulous Heartbeat.mid
Binary files differ
diff --git a/assets/scripts/binary.shader b/assets/scripts/binary.shader
new file mode 100644
index 0000000..ee5e625
--- /dev/null
+++ b/assets/scripts/binary.shader
@@ -0,0 +1,16394 @@
+gfx/binary/alpha1
+{
+ sort 15.5
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+// ============== 000 ==============
+
+gfx/binary/000_F1
+{
+ sort 15.5001
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/000_F2
+{
+ sort 15.5002
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/000_F3
+{
+ sort 15.5003
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/000_B1
+{
+ sort 15.5004
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/000_B2
+{
+ sort 15.5005
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/000_B3
+{
+ sort 15.5006
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 001 ==============
+
+gfx/binary/001_F1
+{
+ sort 15.5007
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/001_F2
+{
+ sort 15.5008
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/001_F3
+{
+ sort 15.5009
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/001_B1
+{
+ sort 15.5010
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/001_B2
+{
+ sort 15.5011
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/001_B3
+{
+ sort 15.5012
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 002 ==============
+
+gfx/binary/002_F1
+{
+ sort 15.5013
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/002_F2
+{
+ sort 15.5014
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/002_F3
+{
+ sort 15.5015
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/002_B1
+{
+ sort 15.5016
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/002_B2
+{
+ sort 15.5017
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/002_B3
+{
+ sort 15.5018
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 003 ==============
+
+gfx/binary/003_F1
+{
+ sort 15.5019
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/003_F2
+{
+ sort 15.5020
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/003_F3
+{
+ sort 15.5021
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/003_B1
+{
+ sort 15.5022
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/003_B2
+{
+ sort 15.5023
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/003_B3
+{
+ sort 15.5024
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 004 ==============
+
+gfx/binary/004_F1
+{
+ sort 15.5025
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/004_F2
+{
+ sort 15.5026
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/004_F3
+{
+ sort 15.5027
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/004_B1
+{
+ sort 15.5028
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/004_B2
+{
+ sort 15.5029
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/004_B3
+{
+ sort 15.5030
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 005 ==============
+
+gfx/binary/005_F1
+{
+ sort 15.5031
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/005_F2
+{
+ sort 15.5032
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/005_F3
+{
+ sort 15.5033
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/005_B1
+{
+ sort 15.5034
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/005_B2
+{
+ sort 15.5035
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/005_B3
+{
+ sort 15.5036
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 006 ==============
+
+gfx/binary/006_F1
+{
+ sort 15.5037
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/006_F2
+{
+ sort 15.5038
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/006_F3
+{
+ sort 15.5039
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/006_B1
+{
+ sort 15.5040
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/006_B2
+{
+ sort 15.5041
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/006_B3
+{
+ sort 15.5042
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 007 ==============
+
+gfx/binary/007_F1
+{
+ sort 15.5043
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/007_F2
+{
+ sort 15.5044
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/007_F3
+{
+ sort 15.5045
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/007_B1
+{
+ sort 15.5046
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/007_B2
+{
+ sort 15.5047
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/007_B3
+{
+ sort 15.5048
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 008 ==============
+
+gfx/binary/008_F1
+{
+ sort 15.5049
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/008_F2
+{
+ sort 15.5050
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/008_F3
+{
+ sort 15.5051
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/008_B1
+{
+ sort 15.5052
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/008_B2
+{
+ sort 15.5053
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/008_B3
+{
+ sort 15.5054
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 009 ==============
+
+gfx/binary/009_F1
+{
+ sort 15.5055
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/009_F2
+{
+ sort 15.5056
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/009_F3
+{
+ sort 15.5057
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/009_B1
+{
+ sort 15.5058
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/009_B2
+{
+ sort 15.5059
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/009_B3
+{
+ sort 15.5060
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 010 ==============
+
+gfx/binary/010_F1
+{
+ sort 15.5061
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/010_F2
+{
+ sort 15.5062
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/010_F3
+{
+ sort 15.5063
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/010_B1
+{
+ sort 15.5064
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/010_B2
+{
+ sort 15.5065
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/010_B3
+{
+ sort 15.5066
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 011 ==============
+
+gfx/binary/011_F1
+{
+ sort 15.5067
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/011_F2
+{
+ sort 15.5068
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/011_F3
+{
+ sort 15.5069
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/011_B1
+{
+ sort 15.5070
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/011_B2
+{
+ sort 15.5071
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/011_B3
+{
+ sort 15.5072
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 012 ==============
+
+gfx/binary/012_F1
+{
+ sort 15.5073
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/012_F2
+{
+ sort 15.5074
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/012_F3
+{
+ sort 15.5075
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/012_B1
+{
+ sort 15.5076
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/012_B2
+{
+ sort 15.5077
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/012_B3
+{
+ sort 15.5078
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 013 ==============
+
+gfx/binary/013_F1
+{
+ sort 15.5079
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/013_F2
+{
+ sort 15.5080
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/013_F3
+{
+ sort 15.5081
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/013_B1
+{
+ sort 15.5082
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/013_B2
+{
+ sort 15.5083
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/013_B3
+{
+ sort 15.5084
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 014 ==============
+
+gfx/binary/014_F1
+{
+ sort 15.5085
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/014_F2
+{
+ sort 15.5086
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/014_F3
+{
+ sort 15.5087
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/014_B1
+{
+ sort 15.5088
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/014_B2
+{
+ sort 15.5089
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/014_B3
+{
+ sort 15.5090
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 015 ==============
+
+gfx/binary/015_F1
+{
+ sort 15.5091
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/015_F2
+{
+ sort 15.5092
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/015_F3
+{
+ sort 15.5093
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/015_B1
+{
+ sort 15.5094
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/015_B2
+{
+ sort 15.5095
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/015_B3
+{
+ sort 15.5096
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 016 ==============
+
+gfx/binary/016_F1
+{
+ sort 15.5097
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/016_F2
+{
+ sort 15.5098
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/016_F3
+{
+ sort 15.5099
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/016_B1
+{
+ sort 15.5100
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/016_B2
+{
+ sort 15.5101
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/016_B3
+{
+ sort 15.5102
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 017 ==============
+
+gfx/binary/017_F1
+{
+ sort 15.5103
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/017_F2
+{
+ sort 15.5104
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/017_F3
+{
+ sort 15.5105
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/017_B1
+{
+ sort 15.5106
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/017_B2
+{
+ sort 15.5107
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/017_B3
+{
+ sort 15.5108
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 018 ==============
+
+gfx/binary/018_F1
+{
+ sort 15.5109
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/018_F2
+{
+ sort 15.5110
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/018_F3
+{
+ sort 15.5111
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/018_B1
+{
+ sort 15.5112
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/018_B2
+{
+ sort 15.5113
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/018_B3
+{
+ sort 15.5114
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 019 ==============
+
+gfx/binary/019_F1
+{
+ sort 15.5115
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/019_F2
+{
+ sort 15.5116
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/019_F3
+{
+ sort 15.5117
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/019_B1
+{
+ sort 15.5118
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/019_B2
+{
+ sort 15.5119
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/019_B3
+{
+ sort 15.5120
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 020 ==============
+
+gfx/binary/020_F1
+{
+ sort 15.5121
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/020_F2
+{
+ sort 15.5122
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/020_F3
+{
+ sort 15.5123
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/020_B1
+{
+ sort 15.5124
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/020_B2
+{
+ sort 15.5125
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/020_B3
+{
+ sort 15.5126
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 021 ==============
+
+gfx/binary/021_F1
+{
+ sort 15.5127
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/021_F2
+{
+ sort 15.5128
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/021_F3
+{
+ sort 15.5129
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/021_B1
+{
+ sort 15.5130
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/021_B2
+{
+ sort 15.5131
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/021_B3
+{
+ sort 15.5132
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 022 ==============
+
+gfx/binary/022_F1
+{
+ sort 15.5133
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/022_F2
+{
+ sort 15.5134
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/022_F3
+{
+ sort 15.5135
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/022_B1
+{
+ sort 15.5136
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/022_B2
+{
+ sort 15.5137
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/022_B3
+{
+ sort 15.5138
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 023 ==============
+
+gfx/binary/023_F1
+{
+ sort 15.5139
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/023_F2
+{
+ sort 15.5140
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/023_F3
+{
+ sort 15.5141
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/023_B1
+{
+ sort 15.5142
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/023_B2
+{
+ sort 15.5143
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/023_B3
+{
+ sort 15.5144
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 024 ==============
+
+gfx/binary/024_F1
+{
+ sort 15.5145
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/024_F2
+{
+ sort 15.5146
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/024_F3
+{
+ sort 15.5147
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/024_B1
+{
+ sort 15.5148
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/024_B2
+{
+ sort 15.5149
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/024_B3
+{
+ sort 15.5150
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 025 ==============
+
+gfx/binary/025_F1
+{
+ sort 15.5151
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/025_F2
+{
+ sort 15.5152
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/025_F3
+{
+ sort 15.5153
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/025_B1
+{
+ sort 15.5154
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/025_B2
+{
+ sort 15.5155
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/025_B3
+{
+ sort 15.5156
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 026 ==============
+
+gfx/binary/026_F1
+{
+ sort 15.5157
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/026_F2
+{
+ sort 15.5158
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/026_F3
+{
+ sort 15.5159
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/026_B1
+{
+ sort 15.5160
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/026_B2
+{
+ sort 15.5161
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/026_B3
+{
+ sort 15.5162
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 027 ==============
+
+gfx/binary/027_F1
+{
+ sort 15.5163
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/027_F2
+{
+ sort 15.5164
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/027_F3
+{
+ sort 15.5165
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/027_B1
+{
+ sort 15.5166
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/027_B2
+{
+ sort 15.5167
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/027_B3
+{
+ sort 15.5168
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 028 ==============
+
+gfx/binary/028_F1
+{
+ sort 15.5169
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/028_F2
+{
+ sort 15.5170
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/028_F3
+{
+ sort 15.5171
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/028_B1
+{
+ sort 15.5172
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/028_B2
+{
+ sort 15.5173
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/028_B3
+{
+ sort 15.5174
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 029 ==============
+
+gfx/binary/029_F1
+{
+ sort 15.5175
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/029_F2
+{
+ sort 15.5176
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/029_F3
+{
+ sort 15.5177
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/029_B1
+{
+ sort 15.5178
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/029_B2
+{
+ sort 15.5179
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/029_B3
+{
+ sort 15.5180
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 030 ==============
+
+gfx/binary/030_F1
+{
+ sort 15.5181
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/030_F2
+{
+ sort 15.5182
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/030_F3
+{
+ sort 15.5183
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/030_B1
+{
+ sort 15.5184
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/030_B2
+{
+ sort 15.5185
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/030_B3
+{
+ sort 15.5186
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 031 ==============
+
+gfx/binary/031_F1
+{
+ sort 15.5187
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/031_F2
+{
+ sort 15.5188
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/031_F3
+{
+ sort 15.5189
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/031_B1
+{
+ sort 15.5190
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/031_B2
+{
+ sort 15.5191
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/031_B3
+{
+ sort 15.5192
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 032 ==============
+
+gfx/binary/032_F1
+{
+ sort 15.5193
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/032_F2
+{
+ sort 15.5194
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/032_F3
+{
+ sort 15.5195
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/032_B1
+{
+ sort 15.5196
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/032_B2
+{
+ sort 15.5197
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/032_B3
+{
+ sort 15.5198
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 033 ==============
+
+gfx/binary/033_F1
+{
+ sort 15.5199
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/033_F2
+{
+ sort 15.5200
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/033_F3
+{
+ sort 15.5201
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/033_B1
+{
+ sort 15.5202
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/033_B2
+{
+ sort 15.5203
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/033_B3
+{
+ sort 15.5204
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 034 ==============
+
+gfx/binary/034_F1
+{
+ sort 15.5205
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/034_F2
+{
+ sort 15.5206
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/034_F3
+{
+ sort 15.5207
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/034_B1
+{
+ sort 15.5208
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/034_B2
+{
+ sort 15.5209
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/034_B3
+{
+ sort 15.5210
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 035 ==============
+
+gfx/binary/035_F1
+{
+ sort 15.5211
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/035_F2
+{
+ sort 15.5212
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/035_F3
+{
+ sort 15.5213
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/035_B1
+{
+ sort 15.5214
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/035_B2
+{
+ sort 15.5215
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/035_B3
+{
+ sort 15.5216
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 036 ==============
+
+gfx/binary/036_F1
+{
+ sort 15.5217
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/036_F2
+{
+ sort 15.5218
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/036_F3
+{
+ sort 15.5219
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/036_B1
+{
+ sort 15.5220
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/036_B2
+{
+ sort 15.5221
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/036_B3
+{
+ sort 15.5222
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 037 ==============
+
+gfx/binary/037_F1
+{
+ sort 15.5223
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/037_F2
+{
+ sort 15.5224
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/037_F3
+{
+ sort 15.5225
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/037_B1
+{
+ sort 15.5226
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/037_B2
+{
+ sort 15.5227
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/037_B3
+{
+ sort 15.5228
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 038 ==============
+
+gfx/binary/038_F1
+{
+ sort 15.5229
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/038_F2
+{
+ sort 15.5230
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/038_F3
+{
+ sort 15.5231
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/038_B1
+{
+ sort 15.5232
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/038_B2
+{
+ sort 15.5233
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/038_B3
+{
+ sort 15.5234
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 039 ==============
+
+gfx/binary/039_F1
+{
+ sort 15.5235
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/039_F2
+{
+ sort 15.5236
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/039_F3
+{
+ sort 15.5237
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/039_B1
+{
+ sort 15.5238
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/039_B2
+{
+ sort 15.5239
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/039_B3
+{
+ sort 15.5240
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 040 ==============
+
+gfx/binary/040_F1
+{
+ sort 15.5241
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/040_F2
+{
+ sort 15.5242
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/040_F3
+{
+ sort 15.5243
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/040_B1
+{
+ sort 15.5244
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/040_B2
+{
+ sort 15.5245
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/040_B3
+{
+ sort 15.5246
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 041 ==============
+
+gfx/binary/041_F1
+{
+ sort 15.5247
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/041_F2
+{
+ sort 15.5248
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/041_F3
+{
+ sort 15.5249
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/041_B1
+{
+ sort 15.5250
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/041_B2
+{
+ sort 15.5251
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/041_B3
+{
+ sort 15.5252
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 042 ==============
+
+gfx/binary/042_F1
+{
+ sort 15.5253
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/042_F2
+{
+ sort 15.5254
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/042_F3
+{
+ sort 15.5255
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/042_B1
+{
+ sort 15.5256
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/042_B2
+{
+ sort 15.5257
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/042_B3
+{
+ sort 15.5258
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 043 ==============
+
+gfx/binary/043_F1
+{
+ sort 15.5259
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/043_F2
+{
+ sort 15.5260
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/043_F3
+{
+ sort 15.5261
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/043_B1
+{
+ sort 15.5262
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/043_B2
+{
+ sort 15.5263
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/043_B3
+{
+ sort 15.5264
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 044 ==============
+
+gfx/binary/044_F1
+{
+ sort 15.5265
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/044_F2
+{
+ sort 15.5266
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/044_F3
+{
+ sort 15.5267
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/044_B1
+{
+ sort 15.5268
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/044_B2
+{
+ sort 15.5269
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/044_B3
+{
+ sort 15.5270
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 045 ==============
+
+gfx/binary/045_F1
+{
+ sort 15.5271
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/045_F2
+{
+ sort 15.5272
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/045_F3
+{
+ sort 15.5273
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/045_B1
+{
+ sort 15.5274
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/045_B2
+{
+ sort 15.5275
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/045_B3
+{
+ sort 15.5276
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 046 ==============
+
+gfx/binary/046_F1
+{
+ sort 15.5277
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/046_F2
+{
+ sort 15.5278
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/046_F3
+{
+ sort 15.5279
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/046_B1
+{
+ sort 15.5280
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/046_B2
+{
+ sort 15.5281
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/046_B3
+{
+ sort 15.5282
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 047 ==============
+
+gfx/binary/047_F1
+{
+ sort 15.5283
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/047_F2
+{
+ sort 15.5284
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/047_F3
+{
+ sort 15.5285
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/047_B1
+{
+ sort 15.5286
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/047_B2
+{
+ sort 15.5287
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/047_B3
+{
+ sort 15.5288
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 048 ==============
+
+gfx/binary/048_F1
+{
+ sort 15.5289
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/048_F2
+{
+ sort 15.5290
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/048_F3
+{
+ sort 15.5291
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/048_B1
+{
+ sort 15.5292
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/048_B2
+{
+ sort 15.5293
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/048_B3
+{
+ sort 15.5294
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 049 ==============
+
+gfx/binary/049_F1
+{
+ sort 15.5295
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/049_F2
+{
+ sort 15.5296
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/049_F3
+{
+ sort 15.5297
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/049_B1
+{
+ sort 15.5298
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/049_B2
+{
+ sort 15.5299
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/049_B3
+{
+ sort 15.5300
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 050 ==============
+
+gfx/binary/050_F1
+{
+ sort 15.5301
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/050_F2
+{
+ sort 15.5302
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/050_F3
+{
+ sort 15.5303
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/050_B1
+{
+ sort 15.5304
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/050_B2
+{
+ sort 15.5305
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/050_B3
+{
+ sort 15.5306
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 051 ==============
+
+gfx/binary/051_F1
+{
+ sort 15.5307
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/051_F2
+{
+ sort 15.5308
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/051_F3
+{
+ sort 15.5309
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/051_B1
+{
+ sort 15.5310
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/051_B2
+{
+ sort 15.5311
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/051_B3
+{
+ sort 15.5312
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 052 ==============
+
+gfx/binary/052_F1
+{
+ sort 15.5313
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/052_F2
+{
+ sort 15.5314
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/052_F3
+{
+ sort 15.5315
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/052_B1
+{
+ sort 15.5316
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/052_B2
+{
+ sort 15.5317
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/052_B3
+{
+ sort 15.5318
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 053 ==============
+
+gfx/binary/053_F1
+{
+ sort 15.5319
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/053_F2
+{
+ sort 15.5320
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/053_F3
+{
+ sort 15.5321
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/053_B1
+{
+ sort 15.5322
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/053_B2
+{
+ sort 15.5323
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/053_B3
+{
+ sort 15.5324
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 054 ==============
+
+gfx/binary/054_F1
+{
+ sort 15.5325
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/054_F2
+{
+ sort 15.5326
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/054_F3
+{
+ sort 15.5327
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/054_B1
+{
+ sort 15.5328
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/054_B2
+{
+ sort 15.5329
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/054_B3
+{
+ sort 15.5330
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 055 ==============
+
+gfx/binary/055_F1
+{
+ sort 15.5331
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/055_F2
+{
+ sort 15.5332
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/055_F3
+{
+ sort 15.5333
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/055_B1
+{
+ sort 15.5334
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/055_B2
+{
+ sort 15.5335
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/055_B3
+{
+ sort 15.5336
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 056 ==============
+
+gfx/binary/056_F1
+{
+ sort 15.5337
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/056_F2
+{
+ sort 15.5338
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/056_F3
+{
+ sort 15.5339
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/056_B1
+{
+ sort 15.5340
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/056_B2
+{
+ sort 15.5341
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/056_B3
+{
+ sort 15.5342
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 057 ==============
+
+gfx/binary/057_F1
+{
+ sort 15.5343
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/057_F2
+{
+ sort 15.5344
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/057_F3
+{
+ sort 15.5345
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/057_B1
+{
+ sort 15.5346
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/057_B2
+{
+ sort 15.5347
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/057_B3
+{
+ sort 15.5348
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 058 ==============
+
+gfx/binary/058_F1
+{
+ sort 15.5349
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/058_F2
+{
+ sort 15.5350
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/058_F3
+{
+ sort 15.5351
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/058_B1
+{
+ sort 15.5352
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/058_B2
+{
+ sort 15.5353
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/058_B3
+{
+ sort 15.5354
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 059 ==============
+
+gfx/binary/059_F1
+{
+ sort 15.5355
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/059_F2
+{
+ sort 15.5356
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/059_F3
+{
+ sort 15.5357
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/059_B1
+{
+ sort 15.5358
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/059_B2
+{
+ sort 15.5359
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/059_B3
+{
+ sort 15.5360
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 060 ==============
+
+gfx/binary/060_F1
+{
+ sort 15.5361
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/060_F2
+{
+ sort 15.5362
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/060_F3
+{
+ sort 15.5363
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/060_B1
+{
+ sort 15.5364
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/060_B2
+{
+ sort 15.5365
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/060_B3
+{
+ sort 15.5366
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 061 ==============
+
+gfx/binary/061_F1
+{
+ sort 15.5367
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/061_F2
+{
+ sort 15.5368
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/061_F3
+{
+ sort 15.5369
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/061_B1
+{
+ sort 15.5370
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/061_B2
+{
+ sort 15.5371
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/061_B3
+{
+ sort 15.5372
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 062 ==============
+
+gfx/binary/062_F1
+{
+ sort 15.5373
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/062_F2
+{
+ sort 15.5374
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/062_F3
+{
+ sort 15.5375
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/062_B1
+{
+ sort 15.5376
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/062_B2
+{
+ sort 15.5377
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/062_B3
+{
+ sort 15.5378
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 063 ==============
+
+gfx/binary/063_F1
+{
+ sort 15.5379
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/063_F2
+{
+ sort 15.5380
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/063_F3
+{
+ sort 15.5381
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/063_B1
+{
+ sort 15.5382
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/063_B2
+{
+ sort 15.5383
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/063_B3
+{
+ sort 15.5384
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 064 ==============
+
+gfx/binary/064_F1
+{
+ sort 15.5385
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/064_F2
+{
+ sort 15.5386
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/064_F3
+{
+ sort 15.5387
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/064_B1
+{
+ sort 15.5388
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/064_B2
+{
+ sort 15.5389
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/064_B3
+{
+ sort 15.5390
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 065 ==============
+
+gfx/binary/065_F1
+{
+ sort 15.5391
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/065_F2
+{
+ sort 15.5392
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/065_F3
+{
+ sort 15.5393
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/065_B1
+{
+ sort 15.5394
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/065_B2
+{
+ sort 15.5395
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/065_B3
+{
+ sort 15.5396
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 066 ==============
+
+gfx/binary/066_F1
+{
+ sort 15.5397
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/066_F2
+{
+ sort 15.5398
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/066_F3
+{
+ sort 15.5399
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/066_B1
+{
+ sort 15.5400
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/066_B2
+{
+ sort 15.5401
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/066_B3
+{
+ sort 15.5402
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 067 ==============
+
+gfx/binary/067_F1
+{
+ sort 15.5403
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/067_F2
+{
+ sort 15.5404
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/067_F3
+{
+ sort 15.5405
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/067_B1
+{
+ sort 15.5406
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/067_B2
+{
+ sort 15.5407
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/067_B3
+{
+ sort 15.5408
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 068 ==============
+
+gfx/binary/068_F1
+{
+ sort 15.5409
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/068_F2
+{
+ sort 15.5410
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/068_F3
+{
+ sort 15.5411
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/068_B1
+{
+ sort 15.5412
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/068_B2
+{
+ sort 15.5413
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/068_B3
+{
+ sort 15.5414
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 069 ==============
+
+gfx/binary/069_F1
+{
+ sort 15.5415
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/069_F2
+{
+ sort 15.5416
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/069_F3
+{
+ sort 15.5417
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/069_B1
+{
+ sort 15.5418
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/069_B2
+{
+ sort 15.5419
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/069_B3
+{
+ sort 15.5420
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 070 ==============
+
+gfx/binary/070_F1
+{
+ sort 15.5421
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/070_F2
+{
+ sort 15.5422
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/070_F3
+{
+ sort 15.5423
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/070_B1
+{
+ sort 15.5424
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/070_B2
+{
+ sort 15.5425
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/070_B3
+{
+ sort 15.5426
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 071 ==============
+
+gfx/binary/071_F1
+{
+ sort 15.5427
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/071_F2
+{
+ sort 15.5428
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/071_F3
+{
+ sort 15.5429
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/071_B1
+{
+ sort 15.5430
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/071_B2
+{
+ sort 15.5431
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/071_B3
+{
+ sort 15.5432
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 072 ==============
+
+gfx/binary/072_F1
+{
+ sort 15.5433
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/072_F2
+{
+ sort 15.5434
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/072_F3
+{
+ sort 15.5435
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/072_B1
+{
+ sort 15.5436
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/072_B2
+{
+ sort 15.5437
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/072_B3
+{
+ sort 15.5438
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 073 ==============
+
+gfx/binary/073_F1
+{
+ sort 15.5439
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/073_F2
+{
+ sort 15.5440
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/073_F3
+{
+ sort 15.5441
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/073_B1
+{
+ sort 15.5442
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/073_B2
+{
+ sort 15.5443
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/073_B3
+{
+ sort 15.5444
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 074 ==============
+
+gfx/binary/074_F1
+{
+ sort 15.5445
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/074_F2
+{
+ sort 15.5446
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/074_F3
+{
+ sort 15.5447
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/074_B1
+{
+ sort 15.5448
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/074_B2
+{
+ sort 15.5449
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/074_B3
+{
+ sort 15.5450
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 075 ==============
+
+gfx/binary/075_F1
+{
+ sort 15.5451
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/075_F2
+{
+ sort 15.5452
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/075_F3
+{
+ sort 15.5453
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/075_B1
+{
+ sort 15.5454
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/075_B2
+{
+ sort 15.5455
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/075_B3
+{
+ sort 15.5456
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 076 ==============
+
+gfx/binary/076_F1
+{
+ sort 15.5457
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/076_F2
+{
+ sort 15.5458
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/076_F3
+{
+ sort 15.5459
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/076_B1
+{
+ sort 15.5460
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/076_B2
+{
+ sort 15.5461
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/076_B3
+{
+ sort 15.5462
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 077 ==============
+
+gfx/binary/077_F1
+{
+ sort 15.5463
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/077_F2
+{
+ sort 15.5464
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/077_F3
+{
+ sort 15.5465
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/077_B1
+{
+ sort 15.5466
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/077_B2
+{
+ sort 15.5467
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/077_B3
+{
+ sort 15.5468
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 078 ==============
+
+gfx/binary/078_F1
+{
+ sort 15.5469
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/078_F2
+{
+ sort 15.5470
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/078_F3
+{
+ sort 15.5471
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/078_B1
+{
+ sort 15.5472
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/078_B2
+{
+ sort 15.5473
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/078_B3
+{
+ sort 15.5474
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 079 ==============
+
+gfx/binary/079_F1
+{
+ sort 15.5475
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/079_F2
+{
+ sort 15.5476
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/079_F3
+{
+ sort 15.5477
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/079_B1
+{
+ sort 15.5478
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/079_B2
+{
+ sort 15.5479
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/079_B3
+{
+ sort 15.5480
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 080 ==============
+
+gfx/binary/080_F1
+{
+ sort 15.5481
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/080_F2
+{
+ sort 15.5482
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/080_F3
+{
+ sort 15.5483
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/080_B1
+{
+ sort 15.5484
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/080_B2
+{
+ sort 15.5485
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/080_B3
+{
+ sort 15.5486
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 081 ==============
+
+gfx/binary/081_F1
+{
+ sort 15.5487
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/081_F2
+{
+ sort 15.5488
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/081_F3
+{
+ sort 15.5489
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/081_B1
+{
+ sort 15.5490
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/081_B2
+{
+ sort 15.5491
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/081_B3
+{
+ sort 15.5492
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 082 ==============
+
+gfx/binary/082_F1
+{
+ sort 15.5493
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/082_F2
+{
+ sort 15.5494
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/082_F3
+{
+ sort 15.5495
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/082_B1
+{
+ sort 15.5496
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/082_B2
+{
+ sort 15.5497
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/082_B3
+{
+ sort 15.5498
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 083 ==============
+
+gfx/binary/083_F1
+{
+ sort 15.5499
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/083_F2
+{
+ sort 15.5500
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/083_F3
+{
+ sort 15.5501
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/083_B1
+{
+ sort 15.5502
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/083_B2
+{
+ sort 15.5503
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/083_B3
+{
+ sort 15.5504
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 084 ==============
+
+gfx/binary/084_F1
+{
+ sort 15.5505
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/084_F2
+{
+ sort 15.5506
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/084_F3
+{
+ sort 15.5507
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/084_B1
+{
+ sort 15.5508
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/084_B2
+{
+ sort 15.5509
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/084_B3
+{
+ sort 15.5510
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 085 ==============
+
+gfx/binary/085_F1
+{
+ sort 15.5511
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/085_F2
+{
+ sort 15.5512
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/085_F3
+{
+ sort 15.5513
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/085_B1
+{
+ sort 15.5514
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/085_B2
+{
+ sort 15.5515
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/085_B3
+{
+ sort 15.5516
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 086 ==============
+
+gfx/binary/086_F1
+{
+ sort 15.5517
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/086_F2
+{
+ sort 15.5518
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/086_F3
+{
+ sort 15.5519
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/086_B1
+{
+ sort 15.5520
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/086_B2
+{
+ sort 15.5521
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/086_B3
+{
+ sort 15.5522
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 087 ==============
+
+gfx/binary/087_F1
+{
+ sort 15.5523
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/087_F2
+{
+ sort 15.5524
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/087_F3
+{
+ sort 15.5525
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/087_B1
+{
+ sort 15.5526
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/087_B2
+{
+ sort 15.5527
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/087_B3
+{
+ sort 15.5528
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 088 ==============
+
+gfx/binary/088_F1
+{
+ sort 15.5529
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/088_F2
+{
+ sort 15.5530
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/088_F3
+{
+ sort 15.5531
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/088_B1
+{
+ sort 15.5532
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/088_B2
+{
+ sort 15.5533
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/088_B3
+{
+ sort 15.5534
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 089 ==============
+
+gfx/binary/089_F1
+{
+ sort 15.5535
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/089_F2
+{
+ sort 15.5536
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/089_F3
+{
+ sort 15.5537
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/089_B1
+{
+ sort 15.5538
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/089_B2
+{
+ sort 15.5539
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/089_B3
+{
+ sort 15.5540
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 090 ==============
+
+gfx/binary/090_F1
+{
+ sort 15.5541
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/090_F2
+{
+ sort 15.5542
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/090_F3
+{
+ sort 15.5543
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/090_B1
+{
+ sort 15.5544
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/090_B2
+{
+ sort 15.5545
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/090_B3
+{
+ sort 15.5546
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 091 ==============
+
+gfx/binary/091_F1
+{
+ sort 15.5547
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/091_F2
+{
+ sort 15.5548
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/091_F3
+{
+ sort 15.5549
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/091_B1
+{
+ sort 15.5550
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/091_B2
+{
+ sort 15.5551
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/091_B3
+{
+ sort 15.5552
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 092 ==============
+
+gfx/binary/092_F1
+{
+ sort 15.5553
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/092_F2
+{
+ sort 15.5554
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/092_F3
+{
+ sort 15.5555
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/092_B1
+{
+ sort 15.5556
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/092_B2
+{
+ sort 15.5557
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/092_B3
+{
+ sort 15.5558
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 093 ==============
+
+gfx/binary/093_F1
+{
+ sort 15.5559
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/093_F2
+{
+ sort 15.5560
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/093_F3
+{
+ sort 15.5561
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/093_B1
+{
+ sort 15.5562
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/093_B2
+{
+ sort 15.5563
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/093_B3
+{
+ sort 15.5564
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 094 ==============
+
+gfx/binary/094_F1
+{
+ sort 15.5565
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/094_F2
+{
+ sort 15.5566
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/094_F3
+{
+ sort 15.5567
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/094_B1
+{
+ sort 15.5568
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/094_B2
+{
+ sort 15.5569
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/094_B3
+{
+ sort 15.5570
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 095 ==============
+
+gfx/binary/095_F1
+{
+ sort 15.5571
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/095_F2
+{
+ sort 15.5572
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/095_F3
+{
+ sort 15.5573
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/095_B1
+{
+ sort 15.5574
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/095_B2
+{
+ sort 15.5575
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/095_B3
+{
+ sort 15.5576
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 096 ==============
+
+gfx/binary/096_F1
+{
+ sort 15.5577
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/096_F2
+{
+ sort 15.5578
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/096_F3
+{
+ sort 15.5579
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/096_B1
+{
+ sort 15.5580
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/096_B2
+{
+ sort 15.5581
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/096_B3
+{
+ sort 15.5582
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 097 ==============
+
+gfx/binary/097_F1
+{
+ sort 15.5583
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/097_F2
+{
+ sort 15.5584
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/097_F3
+{
+ sort 15.5585
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/097_B1
+{
+ sort 15.5586
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/097_B2
+{
+ sort 15.5587
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/097_B3
+{
+ sort 15.5588
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 098 ==============
+
+gfx/binary/098_F1
+{
+ sort 15.5589
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/098_F2
+{
+ sort 15.5590
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/098_F3
+{
+ sort 15.5591
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/098_B1
+{
+ sort 15.5592
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/098_B2
+{
+ sort 15.5593
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/098_B3
+{
+ sort 15.5594
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 099 ==============
+
+gfx/binary/099_F1
+{
+ sort 15.5595
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/099_F2
+{
+ sort 15.5596
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/099_F3
+{
+ sort 15.5597
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/099_B1
+{
+ sort 15.5598
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/099_B2
+{
+ sort 15.5599
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/099_B3
+{
+ sort 15.5600
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 100 ==============
+
+gfx/binary/100_F1
+{
+ sort 15.5601
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/100_F2
+{
+ sort 15.5602
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/100_F3
+{
+ sort 15.5603
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/100_B1
+{
+ sort 15.5604
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/100_B2
+{
+ sort 15.5605
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/100_B3
+{
+ sort 15.5606
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 101 ==============
+
+gfx/binary/101_F1
+{
+ sort 15.5607
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/101_F2
+{
+ sort 15.5608
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/101_F3
+{
+ sort 15.5609
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/101_B1
+{
+ sort 15.5610
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/101_B2
+{
+ sort 15.5611
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/101_B3
+{
+ sort 15.5612
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 102 ==============
+
+gfx/binary/102_F1
+{
+ sort 15.5613
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/102_F2
+{
+ sort 15.5614
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/102_F3
+{
+ sort 15.5615
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/102_B1
+{
+ sort 15.5616
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/102_B2
+{
+ sort 15.5617
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/102_B3
+{
+ sort 15.5618
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 103 ==============
+
+gfx/binary/103_F1
+{
+ sort 15.5619
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/103_F2
+{
+ sort 15.5620
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/103_F3
+{
+ sort 15.5621
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/103_B1
+{
+ sort 15.5622
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/103_B2
+{
+ sort 15.5623
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/103_B3
+{
+ sort 15.5624
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 104 ==============
+
+gfx/binary/104_F1
+{
+ sort 15.5625
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/104_F2
+{
+ sort 15.5626
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/104_F3
+{
+ sort 15.5627
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/104_B1
+{
+ sort 15.5628
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/104_B2
+{
+ sort 15.5629
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/104_B3
+{
+ sort 15.5630
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 105 ==============
+
+gfx/binary/105_F1
+{
+ sort 15.5631
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/105_F2
+{
+ sort 15.5632
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/105_F3
+{
+ sort 15.5633
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/105_B1
+{
+ sort 15.5634
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/105_B2
+{
+ sort 15.5635
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/105_B3
+{
+ sort 15.5636
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 106 ==============
+
+gfx/binary/106_F1
+{
+ sort 15.5637
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/106_F2
+{
+ sort 15.5638
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/106_F3
+{
+ sort 15.5639
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/106_B1
+{
+ sort 15.5640
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/106_B2
+{
+ sort 15.5641
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/106_B3
+{
+ sort 15.5642
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 107 ==============
+
+gfx/binary/107_F1
+{
+ sort 15.5643
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/107_F2
+{
+ sort 15.5644
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/107_F3
+{
+ sort 15.5645
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/107_B1
+{
+ sort 15.5646
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/107_B2
+{
+ sort 15.5647
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/107_B3
+{
+ sort 15.5648
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 108 ==============
+
+gfx/binary/108_F1
+{
+ sort 15.5649
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/108_F2
+{
+ sort 15.5650
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/108_F3
+{
+ sort 15.5651
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/108_B1
+{
+ sort 15.5652
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/108_B2
+{
+ sort 15.5653
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/108_B3
+{
+ sort 15.5654
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 109 ==============
+
+gfx/binary/109_F1
+{
+ sort 15.5655
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/109_F2
+{
+ sort 15.5656
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/109_F3
+{
+ sort 15.5657
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/109_B1
+{
+ sort 15.5658
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/109_B2
+{
+ sort 15.5659
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/109_B3
+{
+ sort 15.5660
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 110 ==============
+
+gfx/binary/110_F1
+{
+ sort 15.5661
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/110_F2
+{
+ sort 15.5662
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/110_F3
+{
+ sort 15.5663
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/110_B1
+{
+ sort 15.5664
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/110_B2
+{
+ sort 15.5665
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/110_B3
+{
+ sort 15.5666
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 111 ==============
+
+gfx/binary/111_F1
+{
+ sort 15.5667
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/111_F2
+{
+ sort 15.5668
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/111_F3
+{
+ sort 15.5669
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/111_B1
+{
+ sort 15.5670
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/111_B2
+{
+ sort 15.5671
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/111_B3
+{
+ sort 15.5672
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 112 ==============
+
+gfx/binary/112_F1
+{
+ sort 15.5673
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/112_F2
+{
+ sort 15.5674
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/112_F3
+{
+ sort 15.5675
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/112_B1
+{
+ sort 15.5676
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/112_B2
+{
+ sort 15.5677
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/112_B3
+{
+ sort 15.5678
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 113 ==============
+
+gfx/binary/113_F1
+{
+ sort 15.5679
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/113_F2
+{
+ sort 15.5680
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/113_F3
+{
+ sort 15.5681
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/113_B1
+{
+ sort 15.5682
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/113_B2
+{
+ sort 15.5683
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/113_B3
+{
+ sort 15.5684
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 114 ==============
+
+gfx/binary/114_F1
+{
+ sort 15.5685
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/114_F2
+{
+ sort 15.5686
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/114_F3
+{
+ sort 15.5687
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/114_B1
+{
+ sort 15.5688
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/114_B2
+{
+ sort 15.5689
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/114_B3
+{
+ sort 15.5690
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 115 ==============
+
+gfx/binary/115_F1
+{
+ sort 15.5691
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/115_F2
+{
+ sort 15.5692
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/115_F3
+{
+ sort 15.5693
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/115_B1
+{
+ sort 15.5694
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/115_B2
+{
+ sort 15.5695
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/115_B3
+{
+ sort 15.5696
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 116 ==============
+
+gfx/binary/116_F1
+{
+ sort 15.5697
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/116_F2
+{
+ sort 15.5698
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/116_F3
+{
+ sort 15.5699
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/116_B1
+{
+ sort 15.5700
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/116_B2
+{
+ sort 15.5701
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/116_B3
+{
+ sort 15.5702
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 117 ==============
+
+gfx/binary/117_F1
+{
+ sort 15.5703
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/117_F2
+{
+ sort 15.5704
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/117_F3
+{
+ sort 15.5705
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/117_B1
+{
+ sort 15.5706
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/117_B2
+{
+ sort 15.5707
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/117_B3
+{
+ sort 15.5708
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 118 ==============
+
+gfx/binary/118_F1
+{
+ sort 15.5709
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/118_F2
+{
+ sort 15.5710
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/118_F3
+{
+ sort 15.5711
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/118_B1
+{
+ sort 15.5712
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/118_B2
+{
+ sort 15.5713
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/118_B3
+{
+ sort 15.5714
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 119 ==============
+
+gfx/binary/119_F1
+{
+ sort 15.5715
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/119_F2
+{
+ sort 15.5716
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/119_F3
+{
+ sort 15.5717
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/119_B1
+{
+ sort 15.5718
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/119_B2
+{
+ sort 15.5719
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/119_B3
+{
+ sort 15.5720
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 120 ==============
+
+gfx/binary/120_F1
+{
+ sort 15.5721
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/120_F2
+{
+ sort 15.5722
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/120_F3
+{
+ sort 15.5723
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/120_B1
+{
+ sort 15.5724
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/120_B2
+{
+ sort 15.5725
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/120_B3
+{
+ sort 15.5726
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 121 ==============
+
+gfx/binary/121_F1
+{
+ sort 15.5727
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/121_F2
+{
+ sort 15.5728
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/121_F3
+{
+ sort 15.5729
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/121_B1
+{
+ sort 15.5730
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/121_B2
+{
+ sort 15.5731
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/121_B3
+{
+ sort 15.5732
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 122 ==============
+
+gfx/binary/122_F1
+{
+ sort 15.5733
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/122_F2
+{
+ sort 15.5734
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/122_F3
+{
+ sort 15.5735
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/122_B1
+{
+ sort 15.5736
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/122_B2
+{
+ sort 15.5737
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/122_B3
+{
+ sort 15.5738
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 123 ==============
+
+gfx/binary/123_F1
+{
+ sort 15.5739
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/123_F2
+{
+ sort 15.5740
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/123_F3
+{
+ sort 15.5741
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/123_B1
+{
+ sort 15.5742
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/123_B2
+{
+ sort 15.5743
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/123_B3
+{
+ sort 15.5744
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 124 ==============
+
+gfx/binary/124_F1
+{
+ sort 15.5745
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/124_F2
+{
+ sort 15.5746
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/124_F3
+{
+ sort 15.5747
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/124_B1
+{
+ sort 15.5748
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/124_B2
+{
+ sort 15.5749
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/124_B3
+{
+ sort 15.5750
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 125 ==============
+
+gfx/binary/125_F1
+{
+ sort 15.5751
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/125_F2
+{
+ sort 15.5752
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/125_F3
+{
+ sort 15.5753
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/125_B1
+{
+ sort 15.5754
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/125_B2
+{
+ sort 15.5755
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/125_B3
+{
+ sort 15.5756
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 126 ==============
+
+gfx/binary/126_F1
+{
+ sort 15.5757
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/126_F2
+{
+ sort 15.5758
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/126_F3
+{
+ sort 15.5759
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/126_B1
+{
+ sort 15.5760
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/126_B2
+{
+ sort 15.5761
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/126_B3
+{
+ sort 15.5762
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 127 ==============
+
+gfx/binary/127_F1
+{
+ sort 15.5763
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/127_F2
+{
+ sort 15.5764
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/127_F3
+{
+ sort 15.5765
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/127_B1
+{
+ sort 15.5766
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/127_B2
+{
+ sort 15.5767
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/127_B3
+{
+ sort 15.5768
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 128 ==============
+
+gfx/binary/128_F1
+{
+ sort 15.5769
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/128_F2
+{
+ sort 15.5770
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/128_F3
+{
+ sort 15.5771
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/128_B1
+{
+ sort 15.5772
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/128_B2
+{
+ sort 15.5773
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/128_B3
+{
+ sort 15.5774
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 129 ==============
+
+gfx/binary/129_F1
+{
+ sort 15.5775
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/129_F2
+{
+ sort 15.5776
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/129_F3
+{
+ sort 15.5777
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/129_B1
+{
+ sort 15.5778
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/129_B2
+{
+ sort 15.5779
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/129_B3
+{
+ sort 15.5780
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 130 ==============
+
+gfx/binary/130_F1
+{
+ sort 15.5781
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/130_F2
+{
+ sort 15.5782
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/130_F3
+{
+ sort 15.5783
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/130_B1
+{
+ sort 15.5784
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/130_B2
+{
+ sort 15.5785
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/130_B3
+{
+ sort 15.5786
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 131 ==============
+
+gfx/binary/131_F1
+{
+ sort 15.5787
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/131_F2
+{
+ sort 15.5788
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/131_F3
+{
+ sort 15.5789
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/131_B1
+{
+ sort 15.5790
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/131_B2
+{
+ sort 15.5791
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/131_B3
+{
+ sort 15.5792
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 132 ==============
+
+gfx/binary/132_F1
+{
+ sort 15.5793
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/132_F2
+{
+ sort 15.5794
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/132_F3
+{
+ sort 15.5795
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/132_B1
+{
+ sort 15.5796
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/132_B2
+{
+ sort 15.5797
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/132_B3
+{
+ sort 15.5798
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 133 ==============
+
+gfx/binary/133_F1
+{
+ sort 15.5799
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/133_F2
+{
+ sort 15.5800
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/133_F3
+{
+ sort 15.5801
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/133_B1
+{
+ sort 15.5802
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/133_B2
+{
+ sort 15.5803
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/133_B3
+{
+ sort 15.5804
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 134 ==============
+
+gfx/binary/134_F1
+{
+ sort 15.5805
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/134_F2
+{
+ sort 15.5806
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/134_F3
+{
+ sort 15.5807
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/134_B1
+{
+ sort 15.5808
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/134_B2
+{
+ sort 15.5809
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/134_B3
+{
+ sort 15.5810
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 135 ==============
+
+gfx/binary/135_F1
+{
+ sort 15.5811
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/135_F2
+{
+ sort 15.5812
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/135_F3
+{
+ sort 15.5813
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/135_B1
+{
+ sort 15.5814
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/135_B2
+{
+ sort 15.5815
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/135_B3
+{
+ sort 15.5816
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 136 ==============
+
+gfx/binary/136_F1
+{
+ sort 15.5817
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/136_F2
+{
+ sort 15.5818
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/136_F3
+{
+ sort 15.5819
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/136_B1
+{
+ sort 15.5820
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/136_B2
+{
+ sort 15.5821
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/136_B3
+{
+ sort 15.5822
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 137 ==============
+
+gfx/binary/137_F1
+{
+ sort 15.5823
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/137_F2
+{
+ sort 15.5824
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/137_F3
+{
+ sort 15.5825
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/137_B1
+{
+ sort 15.5826
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/137_B2
+{
+ sort 15.5827
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/137_B3
+{
+ sort 15.5828
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 138 ==============
+
+gfx/binary/138_F1
+{
+ sort 15.5829
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/138_F2
+{
+ sort 15.5830
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/138_F3
+{
+ sort 15.5831
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/138_B1
+{
+ sort 15.5832
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/138_B2
+{
+ sort 15.5833
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/138_B3
+{
+ sort 15.5834
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 139 ==============
+
+gfx/binary/139_F1
+{
+ sort 15.5835
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/139_F2
+{
+ sort 15.5836
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/139_F3
+{
+ sort 15.5837
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/139_B1
+{
+ sort 15.5838
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/139_B2
+{
+ sort 15.5839
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/139_B3
+{
+ sort 15.5840
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 140 ==============
+
+gfx/binary/140_F1
+{
+ sort 15.5841
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/140_F2
+{
+ sort 15.5842
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/140_F3
+{
+ sort 15.5843
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/140_B1
+{
+ sort 15.5844
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/140_B2
+{
+ sort 15.5845
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/140_B3
+{
+ sort 15.5846
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 141 ==============
+
+gfx/binary/141_F1
+{
+ sort 15.5847
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/141_F2
+{
+ sort 15.5848
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/141_F3
+{
+ sort 15.5849
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/141_B1
+{
+ sort 15.5850
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/141_B2
+{
+ sort 15.5851
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/141_B3
+{
+ sort 15.5852
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 142 ==============
+
+gfx/binary/142_F1
+{
+ sort 15.5853
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/142_F2
+{
+ sort 15.5854
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/142_F3
+{
+ sort 15.5855
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/142_B1
+{
+ sort 15.5856
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/142_B2
+{
+ sort 15.5857
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/142_B3
+{
+ sort 15.5858
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 143 ==============
+
+gfx/binary/143_F1
+{
+ sort 15.5859
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/143_F2
+{
+ sort 15.5860
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/143_F3
+{
+ sort 15.5861
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/143_B1
+{
+ sort 15.5862
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/143_B2
+{
+ sort 15.5863
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/143_B3
+{
+ sort 15.5864
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 144 ==============
+
+gfx/binary/144_F1
+{
+ sort 15.5865
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/144_F2
+{
+ sort 15.5866
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/144_F3
+{
+ sort 15.5867
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/144_B1
+{
+ sort 15.5868
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/144_B2
+{
+ sort 15.5869
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/144_B3
+{
+ sort 15.5870
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 145 ==============
+
+gfx/binary/145_F1
+{
+ sort 15.5871
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/145_F2
+{
+ sort 15.5872
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/145_F3
+{
+ sort 15.5873
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/145_B1
+{
+ sort 15.5874
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/145_B2
+{
+ sort 15.5875
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/145_B3
+{
+ sort 15.5876
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 146 ==============
+
+gfx/binary/146_F1
+{
+ sort 15.5877
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/146_F2
+{
+ sort 15.5878
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/146_F3
+{
+ sort 15.5879
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/146_B1
+{
+ sort 15.5880
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/146_B2
+{
+ sort 15.5881
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/146_B3
+{
+ sort 15.5882
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 147 ==============
+
+gfx/binary/147_F1
+{
+ sort 15.5883
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/147_F2
+{
+ sort 15.5884
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/147_F3
+{
+ sort 15.5885
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/147_B1
+{
+ sort 15.5886
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/147_B2
+{
+ sort 15.5887
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/147_B3
+{
+ sort 15.5888
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 148 ==============
+
+gfx/binary/148_F1
+{
+ sort 15.5889
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/148_F2
+{
+ sort 15.5890
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/148_F3
+{
+ sort 15.5891
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/148_B1
+{
+ sort 15.5892
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/148_B2
+{
+ sort 15.5893
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/148_B3
+{
+ sort 15.5894
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 149 ==============
+
+gfx/binary/149_F1
+{
+ sort 15.5895
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/149_F2
+{
+ sort 15.5896
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/149_F3
+{
+ sort 15.5897
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/149_B1
+{
+ sort 15.5898
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/149_B2
+{
+ sort 15.5899
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/149_B3
+{
+ sort 15.5900
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 150 ==============
+
+gfx/binary/150_F1
+{
+ sort 15.5901
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/150_F2
+{
+ sort 15.5902
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/150_F3
+{
+ sort 15.5903
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/150_B1
+{
+ sort 15.5904
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/150_B2
+{
+ sort 15.5905
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/150_B3
+{
+ sort 15.5906
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 151 ==============
+
+gfx/binary/151_F1
+{
+ sort 15.5907
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/151_F2
+{
+ sort 15.5908
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/151_F3
+{
+ sort 15.5909
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/151_B1
+{
+ sort 15.5910
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/151_B2
+{
+ sort 15.5911
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/151_B3
+{
+ sort 15.5912
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 152 ==============
+
+gfx/binary/152_F1
+{
+ sort 15.5913
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/152_F2
+{
+ sort 15.5914
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/152_F3
+{
+ sort 15.5915
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/152_B1
+{
+ sort 15.5916
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/152_B2
+{
+ sort 15.5917
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/152_B3
+{
+ sort 15.5918
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 153 ==============
+
+gfx/binary/153_F1
+{
+ sort 15.5919
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/153_F2
+{
+ sort 15.5920
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/153_F3
+{
+ sort 15.5921
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/153_B1
+{
+ sort 15.5922
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/153_B2
+{
+ sort 15.5923
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/153_B3
+{
+ sort 15.5924
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 154 ==============
+
+gfx/binary/154_F1
+{
+ sort 15.5925
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/154_F2
+{
+ sort 15.5926
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/154_F3
+{
+ sort 15.5927
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/154_B1
+{
+ sort 15.5928
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/154_B2
+{
+ sort 15.5929
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/154_B3
+{
+ sort 15.5930
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 155 ==============
+
+gfx/binary/155_F1
+{
+ sort 15.5931
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/155_F2
+{
+ sort 15.5932
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/155_F3
+{
+ sort 15.5933
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/155_B1
+{
+ sort 15.5934
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/155_B2
+{
+ sort 15.5935
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/155_B3
+{
+ sort 15.5936
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 156 ==============
+
+gfx/binary/156_F1
+{
+ sort 15.5937
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/156_F2
+{
+ sort 15.5938
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/156_F3
+{
+ sort 15.5939
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/156_B1
+{
+ sort 15.5940
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/156_B2
+{
+ sort 15.5941
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/156_B3
+{
+ sort 15.5942
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 157 ==============
+
+gfx/binary/157_F1
+{
+ sort 15.5943
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/157_F2
+{
+ sort 15.5944
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/157_F3
+{
+ sort 15.5945
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/157_B1
+{
+ sort 15.5946
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/157_B2
+{
+ sort 15.5947
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/157_B3
+{
+ sort 15.5948
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 158 ==============
+
+gfx/binary/158_F1
+{
+ sort 15.5949
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/158_F2
+{
+ sort 15.5950
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/158_F3
+{
+ sort 15.5951
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/158_B1
+{
+ sort 15.5952
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/158_B2
+{
+ sort 15.5953
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/158_B3
+{
+ sort 15.5954
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 159 ==============
+
+gfx/binary/159_F1
+{
+ sort 15.5955
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/159_F2
+{
+ sort 15.5956
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/159_F3
+{
+ sort 15.5957
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/159_B1
+{
+ sort 15.5958
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/159_B2
+{
+ sort 15.5959
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/159_B3
+{
+ sort 15.5960
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 160 ==============
+
+gfx/binary/160_F1
+{
+ sort 15.5961
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/160_F2
+{
+ sort 15.5962
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/160_F3
+{
+ sort 15.5963
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/160_B1
+{
+ sort 15.5964
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/160_B2
+{
+ sort 15.5965
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/160_B3
+{
+ sort 15.5966
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 161 ==============
+
+gfx/binary/161_F1
+{
+ sort 15.5967
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/161_F2
+{
+ sort 15.5968
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/161_F3
+{
+ sort 15.5969
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/161_B1
+{
+ sort 15.5970
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/161_B2
+{
+ sort 15.5971
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/161_B3
+{
+ sort 15.5972
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 162 ==============
+
+gfx/binary/162_F1
+{
+ sort 15.5973
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/162_F2
+{
+ sort 15.5974
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/162_F3
+{
+ sort 15.5975
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/162_B1
+{
+ sort 15.5976
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/162_B2
+{
+ sort 15.5977
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/162_B3
+{
+ sort 15.5978
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 163 ==============
+
+gfx/binary/163_F1
+{
+ sort 15.5979
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/163_F2
+{
+ sort 15.5980
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/163_F3
+{
+ sort 15.5981
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/163_B1
+{
+ sort 15.5982
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/163_B2
+{
+ sort 15.5983
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/163_B3
+{
+ sort 15.5984
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 164 ==============
+
+gfx/binary/164_F1
+{
+ sort 15.5985
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/164_F2
+{
+ sort 15.5986
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/164_F3
+{
+ sort 15.5987
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/164_B1
+{
+ sort 15.5988
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/164_B2
+{
+ sort 15.5989
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/164_B3
+{
+ sort 15.5990
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 165 ==============
+
+gfx/binary/165_F1
+{
+ sort 15.5991
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/165_F2
+{
+ sort 15.5992
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/165_F3
+{
+ sort 15.5993
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/165_B1
+{
+ sort 15.5994
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/165_B2
+{
+ sort 15.5995
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/165_B3
+{
+ sort 15.5996
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 166 ==============
+
+gfx/binary/166_F1
+{
+ sort 15.5997
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/166_F2
+{
+ sort 15.5998
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/166_F3
+{
+ sort 15.5999
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/166_B1
+{
+ sort 15.6000
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/166_B2
+{
+ sort 15.6001
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/166_B3
+{
+ sort 15.6002
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 167 ==============
+
+gfx/binary/167_F1
+{
+ sort 15.6003
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/167_F2
+{
+ sort 15.6004
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/167_F3
+{
+ sort 15.6005
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/167_B1
+{
+ sort 15.6006
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/167_B2
+{
+ sort 15.6007
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/167_B3
+{
+ sort 15.6008
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 168 ==============
+
+gfx/binary/168_F1
+{
+ sort 15.6009
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/168_F2
+{
+ sort 15.6010
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/168_F3
+{
+ sort 15.6011
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/168_B1
+{
+ sort 15.6012
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/168_B2
+{
+ sort 15.6013
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/168_B3
+{
+ sort 15.6014
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 169 ==============
+
+gfx/binary/169_F1
+{
+ sort 15.6015
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/169_F2
+{
+ sort 15.6016
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/169_F3
+{
+ sort 15.6017
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/169_B1
+{
+ sort 15.6018
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/169_B2
+{
+ sort 15.6019
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/169_B3
+{
+ sort 15.6020
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 170 ==============
+
+gfx/binary/170_F1
+{
+ sort 15.6021
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/170_F2
+{
+ sort 15.6022
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/170_F3
+{
+ sort 15.6023
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/170_B1
+{
+ sort 15.6024
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/170_B2
+{
+ sort 15.6025
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/170_B3
+{
+ sort 15.6026
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 171 ==============
+
+gfx/binary/171_F1
+{
+ sort 15.6027
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/171_F2
+{
+ sort 15.6028
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/171_F3
+{
+ sort 15.6029
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/171_B1
+{
+ sort 15.6030
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/171_B2
+{
+ sort 15.6031
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/171_B3
+{
+ sort 15.6032
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 172 ==============
+
+gfx/binary/172_F1
+{
+ sort 15.6033
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/172_F2
+{
+ sort 15.6034
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/172_F3
+{
+ sort 15.6035
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/172_B1
+{
+ sort 15.6036
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/172_B2
+{
+ sort 15.6037
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/172_B3
+{
+ sort 15.6038
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 173 ==============
+
+gfx/binary/173_F1
+{
+ sort 15.6039
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/173_F2
+{
+ sort 15.6040
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/173_F3
+{
+ sort 15.6041
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/173_B1
+{
+ sort 15.6042
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/173_B2
+{
+ sort 15.6043
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/173_B3
+{
+ sort 15.6044
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 174 ==============
+
+gfx/binary/174_F1
+{
+ sort 15.6045
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/174_F2
+{
+ sort 15.6046
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/174_F3
+{
+ sort 15.6047
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/174_B1
+{
+ sort 15.6048
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/174_B2
+{
+ sort 15.6049
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/174_B3
+{
+ sort 15.6050
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 175 ==============
+
+gfx/binary/175_F1
+{
+ sort 15.6051
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/175_F2
+{
+ sort 15.6052
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/175_F3
+{
+ sort 15.6053
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/175_B1
+{
+ sort 15.6054
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/175_B2
+{
+ sort 15.6055
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/175_B3
+{
+ sort 15.6056
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 176 ==============
+
+gfx/binary/176_F1
+{
+ sort 15.6057
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/176_F2
+{
+ sort 15.6058
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/176_F3
+{
+ sort 15.6059
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/176_B1
+{
+ sort 15.6060
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/176_B2
+{
+ sort 15.6061
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/176_B3
+{
+ sort 15.6062
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 177 ==============
+
+gfx/binary/177_F1
+{
+ sort 15.6063
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/177_F2
+{
+ sort 15.6064
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/177_F3
+{
+ sort 15.6065
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/177_B1
+{
+ sort 15.6066
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/177_B2
+{
+ sort 15.6067
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/177_B3
+{
+ sort 15.6068
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 178 ==============
+
+gfx/binary/178_F1
+{
+ sort 15.6069
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/178_F2
+{
+ sort 15.6070
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/178_F3
+{
+ sort 15.6071
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/178_B1
+{
+ sort 15.6072
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/178_B2
+{
+ sort 15.6073
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/178_B3
+{
+ sort 15.6074
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 179 ==============
+
+gfx/binary/179_F1
+{
+ sort 15.6075
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/179_F2
+{
+ sort 15.6076
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/179_F3
+{
+ sort 15.6077
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/179_B1
+{
+ sort 15.6078
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/179_B2
+{
+ sort 15.6079
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/179_B3
+{
+ sort 15.6080
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 180 ==============
+
+gfx/binary/180_F1
+{
+ sort 15.6081
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/180_F2
+{
+ sort 15.6082
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/180_F3
+{
+ sort 15.6083
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/180_B1
+{
+ sort 15.6084
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/180_B2
+{
+ sort 15.6085
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/180_B3
+{
+ sort 15.6086
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 181 ==============
+
+gfx/binary/181_F1
+{
+ sort 15.6087
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/181_F2
+{
+ sort 15.6088
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/181_F3
+{
+ sort 15.6089
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/181_B1
+{
+ sort 15.6090
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/181_B2
+{
+ sort 15.6091
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/181_B3
+{
+ sort 15.6092
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 182 ==============
+
+gfx/binary/182_F1
+{
+ sort 15.6093
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/182_F2
+{
+ sort 15.6094
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/182_F3
+{
+ sort 15.6095
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/182_B1
+{
+ sort 15.6096
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/182_B2
+{
+ sort 15.6097
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/182_B3
+{
+ sort 15.6098
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 183 ==============
+
+gfx/binary/183_F1
+{
+ sort 15.6099
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/183_F2
+{
+ sort 15.6100
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/183_F3
+{
+ sort 15.6101
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/183_B1
+{
+ sort 15.6102
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/183_B2
+{
+ sort 15.6103
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/183_B3
+{
+ sort 15.6104
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 184 ==============
+
+gfx/binary/184_F1
+{
+ sort 15.6105
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/184_F2
+{
+ sort 15.6106
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/184_F3
+{
+ sort 15.6107
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/184_B1
+{
+ sort 15.6108
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/184_B2
+{
+ sort 15.6109
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/184_B3
+{
+ sort 15.6110
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 185 ==============
+
+gfx/binary/185_F1
+{
+ sort 15.6111
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/185_F2
+{
+ sort 15.6112
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/185_F3
+{
+ sort 15.6113
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/185_B1
+{
+ sort 15.6114
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/185_B2
+{
+ sort 15.6115
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/185_B3
+{
+ sort 15.6116
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 186 ==============
+
+gfx/binary/186_F1
+{
+ sort 15.6117
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/186_F2
+{
+ sort 15.6118
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/186_F3
+{
+ sort 15.6119
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/186_B1
+{
+ sort 15.6120
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/186_B2
+{
+ sort 15.6121
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/186_B3
+{
+ sort 15.6122
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 187 ==============
+
+gfx/binary/187_F1
+{
+ sort 15.6123
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/187_F2
+{
+ sort 15.6124
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/187_F3
+{
+ sort 15.6125
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/187_B1
+{
+ sort 15.6126
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/187_B2
+{
+ sort 15.6127
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/187_B3
+{
+ sort 15.6128
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 188 ==============
+
+gfx/binary/188_F1
+{
+ sort 15.6129
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/188_F2
+{
+ sort 15.6130
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/188_F3
+{
+ sort 15.6131
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/188_B1
+{
+ sort 15.6132
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/188_B2
+{
+ sort 15.6133
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/188_B3
+{
+ sort 15.6134
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 189 ==============
+
+gfx/binary/189_F1
+{
+ sort 15.6135
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/189_F2
+{
+ sort 15.6136
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/189_F3
+{
+ sort 15.6137
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/189_B1
+{
+ sort 15.6138
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/189_B2
+{
+ sort 15.6139
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/189_B3
+{
+ sort 15.6140
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 190 ==============
+
+gfx/binary/190_F1
+{
+ sort 15.6141
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/190_F2
+{
+ sort 15.6142
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/190_F3
+{
+ sort 15.6143
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/190_B1
+{
+ sort 15.6144
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/190_B2
+{
+ sort 15.6145
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/190_B3
+{
+ sort 15.6146
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 191 ==============
+
+gfx/binary/191_F1
+{
+ sort 15.6147
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/191_F2
+{
+ sort 15.6148
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/191_F3
+{
+ sort 15.6149
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/191_B1
+{
+ sort 15.6150
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/191_B2
+{
+ sort 15.6151
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/191_B3
+{
+ sort 15.6152
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 192 ==============
+
+gfx/binary/192_F1
+{
+ sort 15.6153
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/192_F2
+{
+ sort 15.6154
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/192_F3
+{
+ sort 15.6155
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/192_B1
+{
+ sort 15.6156
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/192_B2
+{
+ sort 15.6157
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/192_B3
+{
+ sort 15.6158
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 193 ==============
+
+gfx/binary/193_F1
+{
+ sort 15.6159
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/193_F2
+{
+ sort 15.6160
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/193_F3
+{
+ sort 15.6161
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/193_B1
+{
+ sort 15.6162
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/193_B2
+{
+ sort 15.6163
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/193_B3
+{
+ sort 15.6164
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 194 ==============
+
+gfx/binary/194_F1
+{
+ sort 15.6165
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/194_F2
+{
+ sort 15.6166
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/194_F3
+{
+ sort 15.6167
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/194_B1
+{
+ sort 15.6168
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/194_B2
+{
+ sort 15.6169
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/194_B3
+{
+ sort 15.6170
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 195 ==============
+
+gfx/binary/195_F1
+{
+ sort 15.6171
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/195_F2
+{
+ sort 15.6172
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/195_F3
+{
+ sort 15.6173
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/195_B1
+{
+ sort 15.6174
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/195_B2
+{
+ sort 15.6175
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/195_B3
+{
+ sort 15.6176
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 196 ==============
+
+gfx/binary/196_F1
+{
+ sort 15.6177
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/196_F2
+{
+ sort 15.6178
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/196_F3
+{
+ sort 15.6179
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/196_B1
+{
+ sort 15.6180
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/196_B2
+{
+ sort 15.6181
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/196_B3
+{
+ sort 15.6182
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 197 ==============
+
+gfx/binary/197_F1
+{
+ sort 15.6183
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/197_F2
+{
+ sort 15.6184
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/197_F3
+{
+ sort 15.6185
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/197_B1
+{
+ sort 15.6186
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/197_B2
+{
+ sort 15.6187
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/197_B3
+{
+ sort 15.6188
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 198 ==============
+
+gfx/binary/198_F1
+{
+ sort 15.6189
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/198_F2
+{
+ sort 15.6190
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/198_F3
+{
+ sort 15.6191
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/198_B1
+{
+ sort 15.6192
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/198_B2
+{
+ sort 15.6193
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/198_B3
+{
+ sort 15.6194
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 199 ==============
+
+gfx/binary/199_F1
+{
+ sort 15.6195
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/199_F2
+{
+ sort 15.6196
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/199_F3
+{
+ sort 15.6197
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/199_B1
+{
+ sort 15.6198
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/199_B2
+{
+ sort 15.6199
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/199_B3
+{
+ sort 15.6200
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 200 ==============
+
+gfx/binary/200_F1
+{
+ sort 15.6201
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/200_F2
+{
+ sort 15.6202
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/200_F3
+{
+ sort 15.6203
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/200_B1
+{
+ sort 15.6204
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/200_B2
+{
+ sort 15.6205
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/200_B3
+{
+ sort 15.6206
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 201 ==============
+
+gfx/binary/201_F1
+{
+ sort 15.6207
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/201_F2
+{
+ sort 15.6208
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/201_F3
+{
+ sort 15.6209
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/201_B1
+{
+ sort 15.6210
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/201_B2
+{
+ sort 15.6211
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/201_B3
+{
+ sort 15.6212
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 202 ==============
+
+gfx/binary/202_F1
+{
+ sort 15.6213
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/202_F2
+{
+ sort 15.6214
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/202_F3
+{
+ sort 15.6215
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/202_B1
+{
+ sort 15.6216
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/202_B2
+{
+ sort 15.6217
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/202_B3
+{
+ sort 15.6218
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 203 ==============
+
+gfx/binary/203_F1
+{
+ sort 15.6219
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/203_F2
+{
+ sort 15.6220
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/203_F3
+{
+ sort 15.6221
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/203_B1
+{
+ sort 15.6222
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/203_B2
+{
+ sort 15.6223
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/203_B3
+{
+ sort 15.6224
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 204 ==============
+
+gfx/binary/204_F1
+{
+ sort 15.6225
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/204_F2
+{
+ sort 15.6226
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/204_F3
+{
+ sort 15.6227
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/204_B1
+{
+ sort 15.6228
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/204_B2
+{
+ sort 15.6229
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/204_B3
+{
+ sort 15.6230
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 205 ==============
+
+gfx/binary/205_F1
+{
+ sort 15.6231
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/205_F2
+{
+ sort 15.6232
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/205_F3
+{
+ sort 15.6233
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/205_B1
+{
+ sort 15.6234
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/205_B2
+{
+ sort 15.6235
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/205_B3
+{
+ sort 15.6236
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 206 ==============
+
+gfx/binary/206_F1
+{
+ sort 15.6237
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/206_F2
+{
+ sort 15.6238
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/206_F3
+{
+ sort 15.6239
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/206_B1
+{
+ sort 15.6240
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/206_B2
+{
+ sort 15.6241
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/206_B3
+{
+ sort 15.6242
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 207 ==============
+
+gfx/binary/207_F1
+{
+ sort 15.6243
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/207_F2
+{
+ sort 15.6244
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/207_F3
+{
+ sort 15.6245
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/207_B1
+{
+ sort 15.6246
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/207_B2
+{
+ sort 15.6247
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/207_B3
+{
+ sort 15.6248
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 208 ==============
+
+gfx/binary/208_F1
+{
+ sort 15.6249
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/208_F2
+{
+ sort 15.6250
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/208_F3
+{
+ sort 15.6251
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/208_B1
+{
+ sort 15.6252
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/208_B2
+{
+ sort 15.6253
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/208_B3
+{
+ sort 15.6254
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 209 ==============
+
+gfx/binary/209_F1
+{
+ sort 15.6255
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/209_F2
+{
+ sort 15.6256
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/209_F3
+{
+ sort 15.6257
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/209_B1
+{
+ sort 15.6258
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/209_B2
+{
+ sort 15.6259
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/209_B3
+{
+ sort 15.6260
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 210 ==============
+
+gfx/binary/210_F1
+{
+ sort 15.6261
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/210_F2
+{
+ sort 15.6262
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/210_F3
+{
+ sort 15.6263
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/210_B1
+{
+ sort 15.6264
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/210_B2
+{
+ sort 15.6265
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/210_B3
+{
+ sort 15.6266
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 211 ==============
+
+gfx/binary/211_F1
+{
+ sort 15.6267
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/211_F2
+{
+ sort 15.6268
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/211_F3
+{
+ sort 15.6269
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/211_B1
+{
+ sort 15.6270
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/211_B2
+{
+ sort 15.6271
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/211_B3
+{
+ sort 15.6272
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 212 ==============
+
+gfx/binary/212_F1
+{
+ sort 15.6273
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/212_F2
+{
+ sort 15.6274
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/212_F3
+{
+ sort 15.6275
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/212_B1
+{
+ sort 15.6276
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/212_B2
+{
+ sort 15.6277
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/212_B3
+{
+ sort 15.6278
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 213 ==============
+
+gfx/binary/213_F1
+{
+ sort 15.6279
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/213_F2
+{
+ sort 15.6280
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/213_F3
+{
+ sort 15.6281
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/213_B1
+{
+ sort 15.6282
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/213_B2
+{
+ sort 15.6283
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/213_B3
+{
+ sort 15.6284
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 214 ==============
+
+gfx/binary/214_F1
+{
+ sort 15.6285
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/214_F2
+{
+ sort 15.6286
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/214_F3
+{
+ sort 15.6287
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/214_B1
+{
+ sort 15.6288
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/214_B2
+{
+ sort 15.6289
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/214_B3
+{
+ sort 15.6290
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 215 ==============
+
+gfx/binary/215_F1
+{
+ sort 15.6291
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/215_F2
+{
+ sort 15.6292
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/215_F3
+{
+ sort 15.6293
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/215_B1
+{
+ sort 15.6294
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/215_B2
+{
+ sort 15.6295
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/215_B3
+{
+ sort 15.6296
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 216 ==============
+
+gfx/binary/216_F1
+{
+ sort 15.6297
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/216_F2
+{
+ sort 15.6298
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/216_F3
+{
+ sort 15.6299
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/216_B1
+{
+ sort 15.6300
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/216_B2
+{
+ sort 15.6301
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/216_B3
+{
+ sort 15.6302
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 217 ==============
+
+gfx/binary/217_F1
+{
+ sort 15.6303
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/217_F2
+{
+ sort 15.6304
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/217_F3
+{
+ sort 15.6305
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/217_B1
+{
+ sort 15.6306
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/217_B2
+{
+ sort 15.6307
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/217_B3
+{
+ sort 15.6308
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 218 ==============
+
+gfx/binary/218_F1
+{
+ sort 15.6309
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/218_F2
+{
+ sort 15.6310
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/218_F3
+{
+ sort 15.6311
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/218_B1
+{
+ sort 15.6312
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/218_B2
+{
+ sort 15.6313
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/218_B3
+{
+ sort 15.6314
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 219 ==============
+
+gfx/binary/219_F1
+{
+ sort 15.6315
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/219_F2
+{
+ sort 15.6316
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/219_F3
+{
+ sort 15.6317
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/219_B1
+{
+ sort 15.6318
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/219_B2
+{
+ sort 15.6319
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/219_B3
+{
+ sort 15.6320
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 220 ==============
+
+gfx/binary/220_F1
+{
+ sort 15.6321
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/220_F2
+{
+ sort 15.6322
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/220_F3
+{
+ sort 15.6323
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/220_B1
+{
+ sort 15.6324
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/220_B2
+{
+ sort 15.6325
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/220_B3
+{
+ sort 15.6326
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 221 ==============
+
+gfx/binary/221_F1
+{
+ sort 15.6327
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/221_F2
+{
+ sort 15.6328
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/221_F3
+{
+ sort 15.6329
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/221_B1
+{
+ sort 15.6330
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/221_B2
+{
+ sort 15.6331
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/221_B3
+{
+ sort 15.6332
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 222 ==============
+
+gfx/binary/222_F1
+{
+ sort 15.6333
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/222_F2
+{
+ sort 15.6334
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/222_F3
+{
+ sort 15.6335
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/222_B1
+{
+ sort 15.6336
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/222_B2
+{
+ sort 15.6337
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/222_B3
+{
+ sort 15.6338
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 223 ==============
+
+gfx/binary/223_F1
+{
+ sort 15.6339
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/223_F2
+{
+ sort 15.6340
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/223_F3
+{
+ sort 15.6341
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/223_B1
+{
+ sort 15.6342
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/223_B2
+{
+ sort 15.6343
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/223_B3
+{
+ sort 15.6344
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 224 ==============
+
+gfx/binary/224_F1
+{
+ sort 15.6345
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/224_F2
+{
+ sort 15.6346
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/224_F3
+{
+ sort 15.6347
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/224_B1
+{
+ sort 15.6348
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/224_B2
+{
+ sort 15.6349
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/224_B3
+{
+ sort 15.6350
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 225 ==============
+
+gfx/binary/225_F1
+{
+ sort 15.6351
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/225_F2
+{
+ sort 15.6352
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/225_F3
+{
+ sort 15.6353
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/225_B1
+{
+ sort 15.6354
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/225_B2
+{
+ sort 15.6355
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/225_B3
+{
+ sort 15.6356
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 226 ==============
+
+gfx/binary/226_F1
+{
+ sort 15.6357
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/226_F2
+{
+ sort 15.6358
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/226_F3
+{
+ sort 15.6359
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/226_B1
+{
+ sort 15.6360
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/226_B2
+{
+ sort 15.6361
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/226_B3
+{
+ sort 15.6362
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 227 ==============
+
+gfx/binary/227_F1
+{
+ sort 15.6363
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/227_F2
+{
+ sort 15.6364
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/227_F3
+{
+ sort 15.6365
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/227_B1
+{
+ sort 15.6366
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/227_B2
+{
+ sort 15.6367
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/227_B3
+{
+ sort 15.6368
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 228 ==============
+
+gfx/binary/228_F1
+{
+ sort 15.6369
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/228_F2
+{
+ sort 15.6370
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/228_F3
+{
+ sort 15.6371
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/228_B1
+{
+ sort 15.6372
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/228_B2
+{
+ sort 15.6373
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/228_B3
+{
+ sort 15.6374
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 229 ==============
+
+gfx/binary/229_F1
+{
+ sort 15.6375
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/229_F2
+{
+ sort 15.6376
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/229_F3
+{
+ sort 15.6377
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/229_B1
+{
+ sort 15.6378
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/229_B2
+{
+ sort 15.6379
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/229_B3
+{
+ sort 15.6380
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 230 ==============
+
+gfx/binary/230_F1
+{
+ sort 15.6381
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/230_F2
+{
+ sort 15.6382
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/230_F3
+{
+ sort 15.6383
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/230_B1
+{
+ sort 15.6384
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/230_B2
+{
+ sort 15.6385
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/230_B3
+{
+ sort 15.6386
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 231 ==============
+
+gfx/binary/231_F1
+{
+ sort 15.6387
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/231_F2
+{
+ sort 15.6388
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/231_F3
+{
+ sort 15.6389
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/231_B1
+{
+ sort 15.6390
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/231_B2
+{
+ sort 15.6391
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/231_B3
+{
+ sort 15.6392
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 232 ==============
+
+gfx/binary/232_F1
+{
+ sort 15.6393
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/232_F2
+{
+ sort 15.6394
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/232_F3
+{
+ sort 15.6395
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/232_B1
+{
+ sort 15.6396
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/232_B2
+{
+ sort 15.6397
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/232_B3
+{
+ sort 15.6398
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 233 ==============
+
+gfx/binary/233_F1
+{
+ sort 15.6399
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/233_F2
+{
+ sort 15.6400
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/233_F3
+{
+ sort 15.6401
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/233_B1
+{
+ sort 15.6402
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/233_B2
+{
+ sort 15.6403
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/233_B3
+{
+ sort 15.6404
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 234 ==============
+
+gfx/binary/234_F1
+{
+ sort 15.6405
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/234_F2
+{
+ sort 15.6406
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/234_F3
+{
+ sort 15.6407
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/234_B1
+{
+ sort 15.6408
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/234_B2
+{
+ sort 15.6409
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/234_B3
+{
+ sort 15.6410
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 235 ==============
+
+gfx/binary/235_F1
+{
+ sort 15.6411
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/235_F2
+{
+ sort 15.6412
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/235_F3
+{
+ sort 15.6413
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/235_B1
+{
+ sort 15.6414
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/235_B2
+{
+ sort 15.6415
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/235_B3
+{
+ sort 15.6416
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 236 ==============
+
+gfx/binary/236_F1
+{
+ sort 15.6417
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/236_F2
+{
+ sort 15.6418
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/236_F3
+{
+ sort 15.6419
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/236_B1
+{
+ sort 15.6420
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/236_B2
+{
+ sort 15.6421
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/236_B3
+{
+ sort 15.6422
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 237 ==============
+
+gfx/binary/237_F1
+{
+ sort 15.6423
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/237_F2
+{
+ sort 15.6424
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/237_F3
+{
+ sort 15.6425
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/237_B1
+{
+ sort 15.6426
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/237_B2
+{
+ sort 15.6427
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/237_B3
+{
+ sort 15.6428
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 238 ==============
+
+gfx/binary/238_F1
+{
+ sort 15.6429
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/238_F2
+{
+ sort 15.6430
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/238_F3
+{
+ sort 15.6431
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/238_B1
+{
+ sort 15.6432
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/238_B2
+{
+ sort 15.6433
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/238_B3
+{
+ sort 15.6434
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 239 ==============
+
+gfx/binary/239_F1
+{
+ sort 15.6435
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/239_F2
+{
+ sort 15.6436
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/239_F3
+{
+ sort 15.6437
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/239_B1
+{
+ sort 15.6438
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/239_B2
+{
+ sort 15.6439
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/239_B3
+{
+ sort 15.6440
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 240 ==============
+
+gfx/binary/240_F1
+{
+ sort 15.6441
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/240_F2
+{
+ sort 15.6442
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/240_F3
+{
+ sort 15.6443
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/240_B1
+{
+ sort 15.6444
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/240_B2
+{
+ sort 15.6445
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/240_B3
+{
+ sort 15.6446
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 241 ==============
+
+gfx/binary/241_F1
+{
+ sort 15.6447
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/241_F2
+{
+ sort 15.6448
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/241_F3
+{
+ sort 15.6449
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/241_B1
+{
+ sort 15.6450
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/241_B2
+{
+ sort 15.6451
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/241_B3
+{
+ sort 15.6452
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 242 ==============
+
+gfx/binary/242_F1
+{
+ sort 15.6453
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/242_F2
+{
+ sort 15.6454
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/242_F3
+{
+ sort 15.6455
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/242_B1
+{
+ sort 15.6456
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/242_B2
+{
+ sort 15.6457
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/242_B3
+{
+ sort 15.6458
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 243 ==============
+
+gfx/binary/243_F1
+{
+ sort 15.6459
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/243_F2
+{
+ sort 15.6460
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/243_F3
+{
+ sort 15.6461
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/243_B1
+{
+ sort 15.6462
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/243_B2
+{
+ sort 15.6463
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/243_B3
+{
+ sort 15.6464
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 244 ==============
+
+gfx/binary/244_F1
+{
+ sort 15.6465
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/244_F2
+{
+ sort 15.6466
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/244_F3
+{
+ sort 15.6467
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/244_B1
+{
+ sort 15.6468
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/244_B2
+{
+ sort 15.6469
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/244_B3
+{
+ sort 15.6470
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 245 ==============
+
+gfx/binary/245_F1
+{
+ sort 15.6471
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/245_F2
+{
+ sort 15.6472
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/245_F3
+{
+ sort 15.6473
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/245_B1
+{
+ sort 15.6474
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/245_B2
+{
+ sort 15.6475
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/245_B3
+{
+ sort 15.6476
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 246 ==============
+
+gfx/binary/246_F1
+{
+ sort 15.6477
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/246_F2
+{
+ sort 15.6478
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/246_F3
+{
+ sort 15.6479
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/246_B1
+{
+ sort 15.6480
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/246_B2
+{
+ sort 15.6481
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/246_B3
+{
+ sort 15.6482
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 247 ==============
+
+gfx/binary/247_F1
+{
+ sort 15.6483
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/247_F2
+{
+ sort 15.6484
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/247_F3
+{
+ sort 15.6485
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/247_B1
+{
+ sort 15.6486
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/247_B2
+{
+ sort 15.6487
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/247_B3
+{
+ sort 15.6488
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 248 ==============
+
+gfx/binary/248_F1
+{
+ sort 15.6489
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/248_F2
+{
+ sort 15.6490
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/248_F3
+{
+ sort 15.6491
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/248_B1
+{
+ sort 15.6492
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/248_B2
+{
+ sort 15.6493
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/248_B3
+{
+ sort 15.6494
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 249 ==============
+
+gfx/binary/249_F1
+{
+ sort 15.6495
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/249_F2
+{
+ sort 15.6496
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/249_F3
+{
+ sort 15.6497
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/249_B1
+{
+ sort 15.6498
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/249_B2
+{
+ sort 15.6499
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/249_B3
+{
+ sort 15.6500
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 250 ==============
+
+gfx/binary/250_F1
+{
+ sort 15.6501
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/250_F2
+{
+ sort 15.6502
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/250_F3
+{
+ sort 15.6503
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/250_B1
+{
+ sort 15.6504
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/250_B2
+{
+ sort 15.6505
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/250_B3
+{
+ sort 15.6506
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 251 ==============
+
+gfx/binary/251_F1
+{
+ sort 15.6507
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/251_F2
+{
+ sort 15.6508
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/251_F3
+{
+ sort 15.6509
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/251_B1
+{
+ sort 15.6510
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/251_B2
+{
+ sort 15.6511
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/251_B3
+{
+ sort 15.6512
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 252 ==============
+
+gfx/binary/252_F1
+{
+ sort 15.6513
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/252_F2
+{
+ sort 15.6514
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/252_F3
+{
+ sort 15.6515
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/252_B1
+{
+ sort 15.6516
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/252_B2
+{
+ sort 15.6517
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/252_B3
+{
+ sort 15.6518
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 253 ==============
+
+gfx/binary/253_F1
+{
+ sort 15.6519
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/253_F2
+{
+ sort 15.6520
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/253_F3
+{
+ sort 15.6521
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/253_B1
+{
+ sort 15.6522
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/253_B2
+{
+ sort 15.6523
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/253_B3
+{
+ sort 15.6524
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 254 ==============
+
+gfx/binary/254_F1
+{
+ sort 15.6525
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/254_F2
+{
+ sort 15.6526
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/254_F3
+{
+ sort 15.6527
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/254_B1
+{
+ sort 15.6528
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/254_B2
+{
+ sort 15.6529
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/254_B3
+{
+ sort 15.6530
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+// ============== 255 ==============
+
+gfx/binary/255_F1
+{
+ sort 15.6531
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/255_F2
+{
+ sort 15.6532
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/255_F3
+{
+ sort 15.6533
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
+gfx/binary/255_B1
+{
+ sort 15.6534
+ cull back
+ {
+ map $whiteimage
+ alphaGen const 0.0
+ blendFunc GL_DST_COLOR GL_ZERO
+ }
+}
+
+gfx/binary/255_B2
+{
+ sort 15.6535
+ cull back
+ {
+ map $whiteimage
+ rgbGen const ( 0.0 0.0 0.0 )
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/binary/255_B3
+{
+ sort 15.6536
+ {
+ map $whiteimage
+ rgbGen exactVertex
+ blendFunc GL_ONE_MINUS_DST_ALPHA GL_ONE
+ }
+}
+
diff --git a/assets/scripts/core.shader b/assets/scripts/core.shader
new file mode 100644
index 0000000..a640d9b
--- /dev/null
+++ b/assets/scripts/core.shader
@@ -0,0 +1,209 @@
+// the REGION shader is generated by the map editor on temporary
+// brushes around a selected area for testing parts of maps
+textures/REGION
+{
+ surfaceparm nolightmap
+}
+
+white
+{
+ {
+ map $whiteimage
+ blendfunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+
+outline
+{
+ cull none
+ nopicmip
+ nomipmaps
+ {
+ map gfx/2d/outline.tga
+ blendfunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+
+console
+{
+ nopicmip
+ nomipmaps
+ {
+ map ui/assets/console1.tga
+ blendFunc GL_ONE GL_ZERO
+ tcMod scroll .02 0
+ tcmod scale 4 1
+ }
+ {
+ map ui/assets/console2.jpg
+ blendFunc add
+ tcMod turb 0 .1 0 .1
+ tcMod scale 4 1
+ tcmod scroll 0.2 .1
+ }
+}
+
+gfx/misc/detail
+{
+ nopicmip
+ {
+ map gfx/misc/detail.jpg
+ blendFunc GL_DST_COLOR GL_SRC_COLOR
+ rgbgen identity
+ }
+}
+
+// The console font
+gfx/2d/bigchars
+{
+ nopicmip
+ nomipmaps
+ {
+ map gfx/2d/bigchars.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+
+gfx/2d/cursor
+{
+ nopicmip
+ nomipmaps
+ {
+ map gfx/2d/cursor.tga
+ }
+}
+
+// projectionShadow is used for cheap squashed model shadows
+projectionShadow
+{
+ polygonOffset
+ deformVertexes projectionShadow
+ {
+ map $whiteimage
+ blendFunc GL_ONE GL_ZERO
+ rgbGen wave square 0 0 0 0
+ }
+}
+
+// blinked on top of lagometer when connection is interrupted
+gfx/2d/net
+{
+ nopicmip
+ {
+ map gfx/2d/net.jpg
+ }
+}
+
+//===============================================================
+
+gfx/2d/numbers/zero_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/zero_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+gfx/2d/numbers/one_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/one_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+gfx/2d/numbers/two_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/two_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+gfx/2d/numbers/three_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/three_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+gfx/2d/numbers/four_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/four_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+gfx/2d/numbers/five_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/five_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+gfx/2d/numbers/six_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/six_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+gfx/2d/numbers/seven_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/seven_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+gfx/2d/numbers/eight_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/eight_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+gfx/2d/numbers/nine_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/nine_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+gfx/2d/numbers/minus_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/minus_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+gfx/2d/numbers/infinity_32b
+{
+ nopicmip
+ {
+ map gfx/2d/numbers/infinity_32b.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
diff --git a/assets/scripts/crosshairs.shader b/assets/scripts/crosshairs.shader
new file mode 100644
index 0000000..278a296
--- /dev/null
+++ b/assets/scripts/crosshairs.shader
@@ -0,0 +1,96 @@
+gfx/2d/crosshair-alien_s
+{
+ nopicmip
+ {
+ map gfx/2d/crosshair-alien.tga
+ blendfunc blend
+ rgbGen vertex
+ }
+}
+
+gfx/2d/crosshair-rifle_s
+{
+ nopicmip
+ {
+ map gfx/2d/crosshair-rifle.tga
+ blendfunc blend
+ rgbGen vertex
+ }
+}
+
+gfx/2d/crosshair-prifle_s
+{
+ nopicmip
+ {
+ map gfx/2d/crosshair-prifle.tga
+ blendfunc blend
+ rgbGen vertex
+ }
+}
+
+gfx/2d/crosshair-chaingun_s
+{
+ nopicmip
+ {
+ map gfx/2d/crosshair-chaingun.tga
+ blendfunc blend
+ rgbGen vertex
+ }
+}
+
+gfx/2d/crosshair-mdriver_s
+{
+ nopicmip
+ {
+ map gfx/2d/crosshair-mdriver.tga
+ blendfunc blend
+ rgbGen vertex
+ }
+}
+
+gfx/2d/crosshair-lcannon_s
+{
+ nopicmip
+ {
+ map gfx/2d/crosshair-lcannon.tga
+ blendfunc blend
+ rgbGen vertex
+ }
+}
+
+gfx/2d/crosshair-lgun_s
+{
+ nopicmip
+ {
+ map gfx/2d/crosshair-lgun.tga
+ blendfunc blend
+ rgbGen vertex
+ }
+}
+
+gfx/2d/crosshair-flamer_s
+{
+ nopicmip
+ {
+ clampmap gfx/2d/crosshair-flamer1.tga
+ blendfunc blend
+ tcmod rotate 5
+ rgbGen vertex
+ }
+ {
+ clampmap gfx/2d/crosshair-flamer1.tga
+ blendfunc blend
+ tcmod rotate -5
+ rgbGen vertex
+ }
+}
+
+gfx/2d/crosshair-psaw
+{
+ nopicmip
+ {
+ map gfx/2d/crosshair-psaw.tga
+ blendfunc blend
+ rgbGen vertex
+ }
+} \ No newline at end of file
diff --git a/assets/scripts/mdriver.trail b/assets/scripts/mdriver.trail
new file mode 100644
index 0000000..b1545e6
--- /dev/null
+++ b/assets/scripts/mdriver.trail
@@ -0,0 +1,10 @@
+models/weapons/mdriver/fireTS
+{
+ beam
+ {
+ shader gfx/mdriver/trail
+ width 3.0 3.0
+ textureType stretch 0.94 0.03
+ }
+ lifeTime 70
+}
diff --git a/assets/scripts/misc.particle b/assets/scripts/misc.particle
new file mode 100644
index 0000000..40f3cc0
--- /dev/null
+++ b/assets/scripts/misc.particle
@@ -0,0 +1,378 @@
+firstPersonPoisonCloudPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/sprites/poisoncloud
+
+ displacement 0 0 0 ~32.0
+
+ parentVelocityFraction 1.0
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 16
+ velocity 0 0 1 ~0
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 300
+ acceleration 0 0 1 0
+
+ radius 0 10.0 40.0
+ alpha 0 0.5 0.0
+ rotation 0 ~360 -
+ bounce 0.5
+
+ lifeTime 1000
+ }
+
+ count 400
+ delay 0
+ period 20 - ~0%
+ }
+}
+
+poisonCloudedPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/sprites/poisoncloud
+
+ displacement 0 0 0 ~6.0
+
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 60
+ velocity 0 0 0 ~50
+
+ radius 0 4.0 12.0
+ alpha 0 0.25 0.0
+ rotation 0 ~360 -
+
+ lifeTime 800
+ }
+
+ count 100
+ delay 0
+ period 50 200 ~0%
+ }
+}
+
+
+alienEvolvePS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/sprites/green_acid
+
+ displacement 0 0 0 ~0
+
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 150~75%
+ velocity 0 0 1 ~50
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 800
+ acceleration 0 0 -1 0
+
+ radius 0 5.0 30.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+ bounce 0.2
+
+ lifeTime 1000
+ }
+
+ count 30
+ delay 0
+ period 5 - ~0%
+ }
+}
+
+alienBleedPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/damage/blood.tga
+ displacement 0 0 0 0
+
+ velocityType normal
+
+ velocityDir linear
+
+ velocityMagnitude 15
+ velocity 0 0 0 ~35
+
+ accelerationType static
+ accelerationDir linear
+ acceleration 0 0 -1 ~5
+ accelerationMagnitude 25
+
+ radius 0 5 8
+ alpha 250 .85 0
+ rotation 0 ~-15 ~15
+ bounce 0.0
+ color 0 { 1.0 1.0 0.6 } -
+
+ lifeTime 400~100
+ }
+
+ particle
+ {
+ shader sync gfx/damage/blood.tga
+ displacement 0 0 0 0
+
+ velocityType normal
+
+ velocityDir linear
+
+ velocityMagnitude 15
+ velocity 0 0 0 ~35
+
+ accelerationType static
+ accelerationDir linear
+ acceleration 0 0 -1 ~5
+ accelerationMagnitude 25
+
+ radius 0 5 8
+ alpha 250 .85 0
+ rotation 0 ~165 ~195
+ bounce 0.0
+ color 0 { 1.0 1.0 0.6 } -
+
+ lifeTime 400~100
+ }
+
+ count 2
+ delay 0
+ period 0 - 0
+ }
+
+ thirdPersonOnly
+}
+
+alienBuildableBleedPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/damage/blood.tga
+ displacement 0 0 0 0
+
+ velocityType normal
+
+ velocityDir linear
+
+ velocityMagnitude 15
+ velocity 0 0 0 ~35
+
+ accelerationType static
+ accelerationDir linear
+ acceleration 0 0 -1 ~5
+ accelerationMagnitude 25
+
+ radius 0 5 8
+ alpha 250 .85 0
+ rotation 0 ~-15 ~15
+ bounce 0.0
+ color 0 { 1.0 1.0 0.6 } -
+
+ lifeTime 400~100
+ }
+
+ particle
+ {
+ shader sync gfx/damage/blood.tga
+ displacement 0 0 0 0
+
+ velocityType normal
+
+ velocityDir linear
+
+ velocityMagnitude 15
+ velocity 0 0 0 ~35
+
+ accelerationType static
+ accelerationDir linear
+ acceleration 0 0 -1 ~5
+ accelerationMagnitude 25
+
+ radius 0 5 8
+ alpha 250 .85 0
+ rotation 0 ~165 ~195
+ bounce 0.0
+ color 0 { 1.0 1.0 0.6 } -
+
+ lifeTime 400~100
+ }
+
+ count 2
+ delay 0
+ period 0 - 0
+ }
+}
+
+
+humanBleedPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/damage/blood.tga
+ displacement 0 0 0 0
+
+ velocityType normal
+
+ velocityDir linear
+
+ velocityMagnitude 15
+ velocity 0 0 0 ~35
+
+ accelerationType static
+ accelerationDir linear
+ acceleration 0 0 -1 ~5
+ accelerationMagnitude 25
+
+ radius 0 5 8
+ alpha 250 .75 0
+ rotation 0 ~-15 ~15
+ bounce 0.0
+ color 0 { 0.8 0.2 0.2 } -
+
+ lifeTime 400~100
+ }
+
+ particle
+ {
+ shader sync gfx/damage/blood.tga
+ displacement 0 0 0 0
+
+ velocityType normal
+
+ velocityDir linear
+
+ velocityMagnitude 15
+ velocity 0 0 0 ~35
+
+ accelerationType static
+ accelerationDir linear
+ acceleration 0 0 -1 ~5
+ accelerationMagnitude 25
+
+ radius 0 5 8
+ alpha 250 .75 0
+ rotation 0 ~-15 ~15
+ bounce 0.0
+ color 0 { 0.8 0.2 0.2 } -
+
+ lifeTime 400~100
+ }
+
+ count 2
+ delay 0
+ period 0 - 0
+ }
+
+ thirdPersonOnly
+}
+
+humanBuildableBleedPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync flame3 flame4 flame5 flame6 flame7 flame8 flame9 flame10 flame11 flame12 flame13 flame14 flame15 flame16 flame17 flame18 flame19 flame20 flame21 flame22 flame23 flame24 flame25
+ displacement 0 0 0 0
+
+ velocityType normal
+
+ velocityDir linear
+
+ velocityMagnitude 15
+ velocity 0 0 0 ~35
+
+ accelerationType static
+ accelerationDir linear
+ acceleration 0 0 -1 ~5
+ accelerationMagnitude 25
+
+ radius 0 5 8
+ alpha 250 .75 0
+ rotation 0 ~-15 ~15
+ bounce 0.0
+ color 0 { 0.8 0.2 0.2 } -
+
+ lifeTime 200~50
+ }
+
+ particle
+ {
+ shader sync flame3 flame4 flame5 flame6 flame7 flame8 flame9 flame10 flame11 flame12 flame13 flame14 flame15 flame16 flame17 flame18 flame19 flame20 flame21 flame22 flame23 flame24 flame25
+ displacement 0 0 0 0
+
+ velocityType normal
+
+ velocityDir linear
+
+ velocityMagnitude 15
+ velocity 0 0 0 ~35
+
+ accelerationType static
+ accelerationDir linear
+ acceleration 0 0 -1 ~5
+ accelerationMagnitude 25
+
+ radius 0 5 8
+ alpha 250 .75 0
+ rotation 0 ~-15 ~15
+ bounce 0.0
+ color 0 { 0.8 0.2 0.2 } -
+
+ lifeTime 200~50
+ }
+
+ count 2
+ delay 0
+ period 0 - 0
+ }
+
+
+}
+
+disconnectPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/sprites/bubble
+ displacement 0 0 0 ~60
+
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 15
+ velocity 0 0 1 ~90
+
+ radius 0 24 32
+ alpha 0 1.0 -
+
+ lifeTime 1000~300
+ }
+
+ count 3
+ delay 0
+ period 0 - 0
+ }
+}
diff --git a/assets/scripts/ui.shader b/assets/scripts/ui.shader
new file mode 100644
index 0000000..a99d4f7
--- /dev/null
+++ b/assets/scripts/ui.shader
@@ -0,0 +1,19 @@
+ui/assets/neutral/squad_h
+{
+ nopicmip
+ {
+ map ui/assets/neutral/squad_h.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
+
+ui/assets/neutral/squad_v
+{
+ nopicmip
+ {
+ map ui/assets/neutral/squad_v.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbgen vertex
+ }
+}
diff --git a/assets/scripts/weapons.particle b/assets/scripts/weapons.particle
new file mode 100644
index 0000000..5851fc6
--- /dev/null
+++ b/assets/scripts/weapons.particle
@@ -0,0 +1,890 @@
+models/weapons/hive/missilePS
+{
+ ejector
+ {
+ particle
+ {
+ shader 20 models/weapons/hive/sprite1.tga models/weapons/hive/sprite2.tga
+
+ displacement 0 0 0 ~4.0
+
+ parentVelocityFraction 0.5
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 100
+ velocity 0 0 1 ~180
+
+ accelerationType cent
+ accelerationDir point
+ accelerationMagnitude 2000
+
+ rotation 0 -20.0~40.0 -20.0~40.0
+ radius 0 2.0 2.0
+ alpha 0 1.0 0.0
+ bounce 0.5
+
+ lifeTime 4000
+ }
+
+ count infinite
+ delay 0
+ period 100 - ~0%
+ }
+}
+
+models/weapons/rifle/impactPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/rifle/verysmallrock
+
+ displacement 0 0 0 ~4.0
+
+ velocityType normal
+ velocityDir linear
+ velocityMagnitude 100
+ velocity 0 0 0 ~20
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 600
+ acceleration 0 0 -1 0
+
+ radius 0 1.0 1.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+ bounce 0.0
+
+ lifeTime 350
+ }
+
+ count 0~2
+ delay ~100
+ period 0 - ~0%
+ }
+
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/sprites/smoke
+
+ displacement 0 0 0 ~1.0
+ normalDisplacement 3.0
+
+ velocityType normal
+ velocityDir linear
+ velocityMagnitude 20
+ velocity 0 0 0 0
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 300
+ acceleration 0 0 1 0
+
+ radius 0 4.0 6.0
+ alpha 0 0.5 0.0
+ rotation 0 ~360 -
+ bounce 0.0
+
+ lifeTime 250
+ }
+
+ count 1
+ delay 0
+ period 0 - ~0%
+ }
+
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/blaster/orange_particle
+
+ normalDisplacement 3.0
+
+ velocityType normal
+ velocityDir linear
+ velocityMagnitude 200
+ velocity 0 0 0 ~160
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 600
+ acceleration 0 0 -1 0
+
+ radius 0 3.0 0.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+ bounce 0.0
+
+ lifeTime 200
+ }
+
+ count 0~1
+ delay 0
+ period 0 - ~0%
+ }
+}
+
+models/weapons/rifle/muzzlePS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/sprites/smoke
+
+ displacement 0 0 0 ~0.0
+
+ parentVelocityFraction 0.9
+
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 20
+ velocity 0 0 0 0
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 300
+ acceleration 0 0 1 0
+
+ radius 0 2.0 4.0
+ alpha 0 0.4 0.0
+ rotation 0 ~360 -
+ bounce 0.0
+
+ lifeTime 200
+ }
+
+ count 1
+ delay 0
+ period 0 - ~0%
+ }
+
+ ejector
+ {
+ particle
+ {
+ model models/weapons/shells/rifle-shell.md3
+
+ displacement -5 -3 0 ~0.0
+
+ parentVelocityFraction 0.85
+
+ velocityType static_transform
+ velocityDir linear
+ velocityMagnitude 200
+ velocity 0 -1 3 ~10
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 800
+ acceleration 0 0 -1 0
+
+ radius 0 1.0 -
+ bounce 0.5
+
+ lifeTime 5000
+ }
+
+ count 1
+ delay 0
+ period 0 - ~0%
+ }
+}
+
+models/weapons/shotgun/muzzlePS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/sprites/smoke
+
+ displacement 0 0 0 ~0.0
+
+ parentVelocityFraction 0.9
+
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 20
+ velocity 0 0 0 0
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 300
+ acceleration 0 0 1 0
+
+ radius 0 2.0 4.0
+ alpha 0 0.4 0.0
+ rotation 0 ~360 -
+ bounce 0.0
+
+ lifeTime 200
+ }
+
+ count 1
+ delay 0
+ period 0 - ~0%
+ }
+
+ ejector
+ {
+ particle
+ {
+ model models/weapons/shells/shotgun-shell.md3
+
+ displacement -5 -3 0 ~0.0
+
+ parentVelocityFraction 0.85
+
+ velocityType static_transform
+ velocityDir linear
+ velocityMagnitude 200
+ velocity 0 -1 3 ~10
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 800
+ acceleration 0 0 -1 0
+
+ radius 0 1.0 -
+ bounce 0.5
+
+ lifeTime 5000
+ }
+
+ count 1
+ delay 0
+ period 0 - ~0%
+ }
+}
+
+models/weapons/chaingun/muzzlePS
+{
+ ejector
+ {
+ particle
+ {
+ model models/weapons/shells/rifle-shell.md3
+
+ displacement -5 -3 0 ~0.0
+
+ parentVelocityFraction 0.85
+
+ velocityType static_transform
+ velocityDir linear
+ velocityMagnitude 200
+ velocity 0 -1 3 ~10
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 800
+ acceleration 0 0 -1 0
+
+ radius 0 1.0 -
+ bounce 0.5
+
+ lifeTime 5000
+ }
+
+ count 1
+ delay 0
+ period 0 - ~0%
+ }
+}
+
+models/weapons/flamer/muzzlePS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync flame3 flame4 flame5 flame6 flame7 flame8 flame9 flame10 flame11 flame12 flame13 flame14 flame15 flame16 flame17 flame18 flame19 flame20 flame21 flame22 flame23 flame24 flame25
+ displacement 0 0 0 ~0.0
+
+ parentVelocityFraction 0.65
+
+ velocityType cent
+ velocityDir linear
+ velocityMagnitude 500
+ velocity 0 0 0 ~0
+
+ physicsRadius 15
+
+ radius 0 4.0 40.0
+ alpha 0 1.0 1.0
+ rotation 0 ~360 -
+ bounce 0.1
+
+ lifeTime 800
+ }
+
+ count infinite
+ delay 0
+ period 15 - ~0%
+ }
+}
+
+models/weapons/level1upg/muzzlePS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/sprites/poisoncloud
+
+ displacement 0 0 0 ~0.0
+
+ parentVelocityFraction 1.0
+
+ velocityType cent
+ velocityDir linear
+ velocityMagnitude 80
+ velocity 0 0 0 ~50
+
+ radius 0 10.0 25.0
+ alpha 0 0.5 0.0
+ rotation 0 ~360 -
+ bounce 1.0
+
+ lifeTime 800
+ }
+
+ count 20
+ delay 0
+ period 40 - ~0%
+ }
+}
+
+models/weapons/blaster/missilePS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/blaster/orange_particle
+
+ displacement 0 0 0 ~2.0
+
+ parentVelocityFraction 0.5
+
+ radius 0 1.5 0.0
+ alpha 0 1.0 0.0
+ bounce 0.01
+
+ lifeTime 400
+ }
+
+ count infinite
+ delay 0
+ period 10 - ~0%
+ }
+}
+
+models/weapons/prifle/impactPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/prifle/red_blob
+
+ radius 0 3.0 6.0
+ alpha 70 1.0 0.0
+ rotation 0 ~360 -
+
+ lifeTime 140
+ }
+
+ count 1
+ delay 0
+ period 0 - ~0%
+ }
+}
+
+models/weapons/prifle/missilePS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/prifle/red_blob
+
+ parentVelocityFraction 0.8
+
+ radius 0 2.0 1.5
+ alpha 0 0.8 0.0
+ bounce 0.01
+
+ lifeTime 400
+ }
+
+ count infinite
+ delay 0
+ period 10 - ~0%
+ }
+}
+
+models/weapons/mdriver/impactPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/mdriver/green_particle
+
+ displacement 0 0 0 ~2.0
+
+ normalDisplacement 10.0
+
+ velocityType normal
+ velocityDir linear
+ velocityMagnitude 400
+ velocity 0 0 0 ~80
+
+ accelerationType normal
+ accelerationDir linear
+ accelerationMagnitude 200
+ acceleration 0 0 1 ~360
+
+ radius 0 6.0 4.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+ bounce 0.5
+
+ lifeTime 1000
+ }
+
+ count 10
+ delay 0
+ period 0 - ~0%
+ }
+}
+
+models/weapons/lcannon/missilePS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/blaster/orange_particle
+
+ displacement 0 0 0 ~3.0
+
+ parentVelocityFraction 1.0
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 120
+ velocity 0 0 1 ~360
+
+ radius 0 1.0 5.0
+ alpha 0 1.0 0.0
+ bounce 0.1
+
+ lifeTime 1000
+ }
+
+ count infinite
+ delay 0
+ period 50 - ~0%
+ }
+}
+
+models/weapons/lcannon/secondaryMissilePS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/blaster/orange_particle
+
+ displacement 0 0 0 ~3.0
+
+ parentVelocityFraction 0.5
+
+ radius 0 2.0 0.0
+ alpha 0 1.0 0.0
+ bounce 0.1
+
+ lifeTime 400
+ }
+
+ count infinite
+ delay 0
+ period 25 - ~0%
+ }
+}
+
+models/weapons/lcannon/impactPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/blaster/orange_particle
+
+ radius 0 8.0 16.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+
+ scaleWithCharge 0.10
+
+ lifeTime 250
+ }
+
+ count 1
+ delay 0
+ period 0 - ~0%
+ }
+
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/blaster/orange_particle
+
+ displacement 0 0 0 ~2.0
+
+ normalDisplacement 10.0
+
+ velocityType normal
+ velocityDir linear
+ velocityMagnitude 200
+ velocity 0 0 0 ~160
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 300
+ acceleration 0 0 -1 0
+
+ radius 0 1.0 5.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+ bounce 0.8
+
+ lifeTime 2000~1000
+ }
+
+ count 30
+ delay 0
+ period 0 - ~0%
+ }
+
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/lcannon/primary
+
+ displacement 0 0 0 ~10.0
+
+ normalDisplacement 15.0
+
+ velocityType normal
+ velocityDir linear
+ velocityMagnitude 100
+ velocity 0 0 0 ~160
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 150
+ acceleration 0 0 -1 0
+
+ radius 0 1.0 0.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+ bounce 1.0
+
+ scaleWithCharge 0.10
+
+ lifeTime 1000~1000
+ }
+
+ count 6
+ delay 0
+ period 0 - ~0%
+ }
+}
+
+models/weapons/lcannon/secondaryImpactPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/blaster/orange_particle
+
+ radius 0 8.0 16.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+
+ lifeTime 250
+ }
+
+ count 1
+ delay 0
+ period 0 - ~0%
+ }
+
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/blaster/orange_particle
+
+ displacement 0 0 0 ~2.0
+
+ normalDisplacement 10.0
+
+ velocityType normal
+ velocityDir linear
+ velocityMagnitude 150
+ velocity 0 0 0 ~160
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 300
+ acceleration 0 0 -1 0
+
+ radius 0 1.0 5.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+ bounce 0.8
+
+ lifeTime 2000~1000
+ }
+
+ count 10
+ delay 0
+ period 0 - ~0%
+ }
+}
+
+models/weapons/psaw/impactPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/psaw/blue_particle
+
+ displacement 0 0 0 ~2.0
+
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 100
+ velocity 0 0 -1 ~25
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 800
+ acceleration 0 0 -1 ~10
+
+ radius 0 1.0~2.0 3.0~2.0
+ alpha 0 1.0 1.0
+ rotation 0 ~360 -
+ bounce 0.5
+
+ lifeTime 1000
+ }
+
+ count 3
+ delay 0
+ period 0 - ~0%
+ }
+}
+
+models/weapons/lasgun/impactPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/lasgun/purple_particle
+
+ displacement 0 0 0 ~2.0
+ normalDisplacement 7.0
+
+ velocityType normal
+ velocityDir linear
+ velocityMagnitude 100
+ velocity 0 0 0 ~90
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 600
+ acceleration 0 0 -1 ~10
+
+ radius 0 3.0~2.0 0.0
+ alpha 0 1.0 1.0
+ rotation 0 ~360 -
+ bounce 0.5
+
+ lifeTime 500
+ }
+
+ count 3
+ delay 0
+ period 0 - ~0%
+ }
+}
+
+models/weapons/grenade/impactTrailPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync flame3 flame4 flame5 flame6 flame7 flame8 flame9 flame10 flame11 flame12 flame13 flame14 flame15 flame16 flame17 flame18 flame19 flame20 flame21 flame22 flame23 flame24 flame25
+
+ displacement 0 0 0 ~0
+
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 30
+ velocity 0 0 -1 ~0
+
+ radius 0 30.0 10.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+ bounce 0
+
+ lifeTime 500
+ }
+
+ count 5
+ delay 0
+ period 40 - 0
+ }
+}
+
+models/weapons/grenade/impactPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync flame3 flame4 flame5 flame6 flame7 flame8 flame9 flame10 flame11 flame12 flame13 flame14 flame15 flame16 flame17 flame18 flame19 flame20 flame21 flame22 flame23 flame24 flame25
+
+ displacement 0 0 11 ~0
+
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 200~75%
+ velocity 0 0 1 ~10
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 300
+ acceleration 0 0 -1 0
+
+ radius 0 10.0 40.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+ bounce 0
+
+ lifeTime 500
+
+ childSystem models/weapons/grenade/impactTrailPS
+ }
+
+ count 5
+ delay 0
+ period 10 - ~0%
+ }
+
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/grenade/flare_01
+
+ displacement 0 0 8 ~0
+
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 10~50%
+ velocity 0 0 1 ~60
+
+ radius 0 100.0 200.0
+ alpha 250 1.0 0.0
+ rotation 0 ~360 -
+ bounce 0.0
+
+ lifeTime 300
+ }
+
+ count 1
+ delay 0
+ period 10 - ~0%
+ }
+
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/sprites/spark
+
+ displacement 0 0 8 ~0
+
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 700~3%
+ velocity 0 0 1 ~180
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 800
+ acceleration 0 0 1 0
+
+ radius 0 10.0 2.0
+ alpha 0 1.0 0.0
+ rotation 0 ~360 -
+ bounce 0
+
+ lifeTime 300
+ }
+
+ count 150
+ delay 0
+ period 0 - ~0%
+ }
+}
+
+models/weapons/level3upg/impactPS
+{
+ ejector
+ {
+ particle
+ {
+ shader sync gfx/level3upg/barb_splash
+
+ displacement 0 0 0 ~8
+
+ velocityType normal
+ velocityDir linear
+ velocityMagnitude 800
+ velocity 0 0 1 ~80
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 800
+ acceleration 0 0 -1 0
+
+ radius 0 3.0~2.0 0.0
+ alpha 0 1.0 1.0
+ rotation 0 ~360 -
+ bounce 0.4~100%
+
+ lifeTime 175
+ }
+
+ count 12
+ delay 0
+ period 0 - ~0%
+ }
+}
diff --git a/assets/scripts/weapons.shader b/assets/scripts/weapons.shader
new file mode 100644
index 0000000..960aecb
--- /dev/null
+++ b/assets/scripts/weapons.shader
@@ -0,0 +1,93 @@
+gfx/blaster/orange_particle
+{
+ cull disable
+ {
+ map gfx/blaster/orange_particle.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ alphaGen vertex
+ rgbGen vertex
+ }
+}
+
+gfx/mdriver/green_particle
+{
+ cull disable
+ {
+ map gfx/mdriver/green_particle.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbGen vertex
+ alphaGen vertex
+ }
+}
+
+gfx/mdriver/trail
+{
+ nomipmaps
+ cull disable
+ {
+ map gfx/mdriver/trail.tga
+ blendFunc blend
+ }
+}
+
+gfx/psaw/blue_particle
+{
+ cull disable
+ {
+ map gfx/psaw/blue_particle.jpg
+ blendFunc GL_ONE GL_ONE
+ alphaGen vertex
+ rgbGen vertex
+ }
+}
+
+gfx/rifle/verysmallrock
+{
+ cull disable
+ {
+ map gfx/rifle/verysmallrock.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ alphaGen vertex
+ rgbGen vertex
+ }
+}
+
+gfx/prifle/red_blob
+{
+ cull disable
+ {
+ map gfx/prifle/red_blob.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ alphaGen vertex
+ }
+}
+
+gfx/prifle/red_streak
+{
+ nomipmaps
+ cull disable
+ {
+ map gfx/prifle/red_streak.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ alphaGen vertex
+ }
+}
+
+gfx/lcannon/primary
+{
+ cull disable
+ {
+ animmap 24 gfx/lcannon/primary_1.jpg gfx/lcannon/primary_2.jpg gfx/lcannon/primary_3.jpg gfx/lcannon/primary_4.jpg
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/lasgun/purple_particle
+{
+ cull disable
+ {
+ map gfx/lasgun/purple_particle.tga
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
diff --git a/assets/sound/buildables/barricade/sound.cfg b/assets/sound/buildables/barricade/sound.cfg
new file mode 100644
index 0000000..caa49e4
--- /dev/null
+++ b/assets/sound/buildables/barricade/sound.cfg
@@ -0,0 +1,14 @@
+1 0 //construct1.wav
+0 0 //construct2.wav
+0 0 //idle1.wav
+0 0 //idle2.wav
+0 0 //idle3.wav
+1 0 //attack1.wav
+1 0 //attack2.wav
+0 0 //spawn1.wav
+0 0 //spawn2.wav
+1 0 //pain1.wav
+1 0 //pain2.wav
+0 0 //destroy1.wav
+0 0 //destroy2.wav
+0 0 //destroyed.wav
diff --git a/ui/assets/alien/buildstat.cfg b/assets/ui/assets/alien/buildstat.cfg
index 1114302..318d401 100644
--- a/ui/assets/alien/buildstat.cfg
+++ b/assets/ui/assets/alien/buildstat.cfg
@@ -8,7 +8,7 @@ frameShader "ui/assets/alien/buildstat/frame"
frameWidth 150
frameHeight 30
-healthPadding 2
+healthPadding 2
healthSevereColor 0.24 0.02 0.02 1
healthHighColor 0.32 0.04 0.04 1
healthElevatedColor 0.40 0.06 0.06 1
@@ -20,12 +20,12 @@ overlayShader "ui/assets/alien/buildstat/overlay"
overlayWidth 156
overlayHeight 36
-// PERCENT of frameHeight to use for top/bottom margin of icons/text
+// PERCENT of frameHeight to use for top/bottom margin of icons/text
// value is for total of top and bottom margins
// valid values between 0.0 and 1.0
verticalMargin 0.5
-// number of CHARS worth of space that should be used for left/right margins
+// number of CHARS worth of space that should be used for left/right margins
// value is for one side only
// char width is determined by frameHeight and verticalMargin
horizontalMargin 1.0
diff --git a/assets/ui/assets/console1.tga b/assets/ui/assets/console1.tga
new file mode 100644
index 0000000..2d8d418
--- /dev/null
+++ b/assets/ui/assets/console1.tga
Binary files differ
diff --git a/assets/ui/assets/console2.jpg b/assets/ui/assets/console2.jpg
new file mode 100644
index 0000000..8c051fd
--- /dev/null
+++ b/assets/ui/assets/console2.jpg
Binary files differ
diff --git a/ui/assets/human/buildstat.cfg b/assets/ui/assets/human/buildstat.cfg
index 9c192de..c66b618 100644
--- a/ui/assets/human/buildstat.cfg
+++ b/assets/ui/assets/human/buildstat.cfg
@@ -8,7 +8,7 @@ frameShader "ui/assets/human/buildstat/frame"
frameWidth 150
frameHeight 30
-healthPadding 2
+healthPadding 2
// Homeworld Security Advisory System
healthSevereColor 0.83 0.03 0.02 1
@@ -22,12 +22,12 @@ overlayShader ""
overlayWidth 160
overlayHeight 40
-// PERCENT of frameHeight to use for top/bottom margin of icons/text
+// PERCENT of frameHeight to use for top/bottom margin of icons/text
// value is for total of top and bottom margins
// valid values between 0.0 and 1.0
verticalMargin 0.5
-// number of CHARS worth of space that should be used for left/right margins
+// number of CHARS worth of space that should be used for left/right margins
// value is for one side only
// char width is determined by frameHeight and verticalMargin
horizontalMargin 1.0
diff --git a/assets/ui/connect.menu b/assets/ui/connect.menu
new file mode 100644
index 0000000..108e33c
--- /dev/null
+++ b/assets/ui/connect.menu
@@ -0,0 +1,14 @@
+#include "ui/menudef.h"
+
+{
+ menuDef
+ {
+ name "Connect"
+ background "gfx/2d/load_screen"
+ rect 0 0 640 480
+ fullScreen MENU_FALSE
+ visible MENU_FALSE
+ style WINDOW_STYLE_SHADER
+ aspectBias ASPECT_NONE
+ }
+}
diff --git a/assets/ui/createfavorite.menu b/assets/ui/createfavorite.menu
new file mode 100644
index 0000000..c66ecff
--- /dev/null
+++ b/assets/ui/createfavorite.menu
@@ -0,0 +1,115 @@
+#include "ui/menudef.h"
+
+{
+ \\ CREATE FAVORITE POPUP MENU \\
+
+#define BUTT_W 45
+#define BUTT_H 35
+#define BORDER 10
+#define INPUT_H 20
+#define W 250
+#define H ((3*BORDER)+(2*INPUT_H)+BUTT_H)
+
+ menuDef
+ {
+ name "createfavorite_popmenu"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onESC
+ {
+ close createfavorite_popmenu
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ // ENTER NAME AND ADDRESS //
+
+ itemDef
+ {
+ name nameEntry
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ maxchars 40
+ text "Name:"
+ textscale .4
+ cvar "ui_favoriteName"
+ rect BORDER BORDER (W-(2*BORDER)) INPUT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name addressEntry
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ maxchars 40
+ text "Address:"
+ textscale .4
+ cvar "ui_favoriteAddress"
+ rect BORDER ((2*BORDER)+INPUT_H) (W-(2*BORDER)) INPUT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name yes
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect (W-(2*BUTT_W)) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript CreateFavorite;
+ close createfavorite_popmenu
+ }
+ }
+
+ itemDef
+ {
+ name yes
+ text "Cancel"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect (W-BUTT_W) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close createfavorite_popmenu
+ }
+ }
+ }
+}
diff --git a/assets/ui/createserver.menu b/assets/ui/createserver.menu
new file mode 100644
index 0000000..f64ba1d
--- /dev/null
+++ b/assets/ui/createserver.menu
@@ -0,0 +1,499 @@
+#include "ui/menudef.h"
+
+{
+ \\ Server Creation \\
+
+#define W 640
+#define H 480
+#define BORDER 10
+
+#define PREVIEW_W 300
+#define PREVIEW_H 225
+#define PREVIEW_X BORDER
+#define PREVIEW_Y BORDER
+
+#define BC_W (W-(2*BORDER))
+#define BC_H 50
+#define BC_X BORDER
+#define BC_Y (H-(BC_H+BORDER))
+#define ARROW_W 50
+#define ARROW_H BC_H
+
+#define MAPS_W PREVIEW_W
+#define MAPS_H (H-((4*BORDER)+PREVIEW_H+BC_H))
+#define MAPS_X BORDER
+#define MAPS_Y ((2*BORDER)+PREVIEW_H)
+
+#define OPTIONS_W (W-((3*BORDER)+PREVIEW_W))
+#define OPTIONS_H (H-((3*BORDER)+BC_H))
+#define OPTIONS_X ((2*BORDER)+PREVIEW_W)
+#define OPTIONS_Y BORDER
+#define ELEM_OFF_Y 20
+#define ELEM_OFF_X -135
+#define ELEM_H 21
+
+ menuDef
+ {
+ name "createserver"
+ visible MENU_FALSE
+ fullscreen MENU_TRUE
+ rect 0 0 W H
+ focusColor 1 .75 0 1
+ outOfBoundsClick
+ style WINDOW_STYLE_EMPTY
+ aspectBias ASPECT_NONE
+
+ onOpen
+ {
+ uiScript loadArenas;
+ hide accept_alt;
+ show accept;
+ hide back_alt;
+ show back
+ }
+
+ onEsc
+ {
+ close createserver
+ }
+
+ itemDef
+ {
+ name background
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ // map selection
+
+ itemDef
+ {
+ name mappreview
+ style WINDOW_STYLE_EMPTY
+ ownerdraw UI_SELECTEDMAPPREVIEW
+ rect PREVIEW_X PREVIEW_Y PREVIEW_W PREVIEW_H
+ border WINDOW_BORDER_FULL
+ bordercolor .5 .5 .5 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name maplist
+ rect MAPS_X MAPS_Y MAPS_W MAPS_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_MAPS
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 1
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ columns 1
+ 2 190 ALIGN_LEFT
+ }
+
+
+ // SETTINGS //
+
+ itemDef
+ {
+ name window
+ rect OPTIONS_X OPTIONS_Y OPTIONS_W OPTIONS_H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_EDITFIELD
+ text "Host Name:"
+ cvar "sv_hostname"
+ maxChars 40
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(0*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name normal
+ type ITEM_TYPE_NUMERICFIELD
+ text "Time Limit:"
+ cvar "timelimit"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(1*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ maxchars 4
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_NUMERICFIELD
+ text "Maximum Players:"
+ cvar "sv_maxclients"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(2*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ maxchars 4
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_YESNO
+ text "Require Password:"
+ cvar "g_needpassword"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(3*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav"
+ }
+ }
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_EDITFIELD
+ text "Password:"
+ cvar "g_password"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(4*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ maxchars 10
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+
+
+ itemDef
+ {
+ name normal
+ type ITEM_TYPE_YESNO
+ text "Pure Server:"
+ cvar "sv_pure"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(6*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav"
+ }
+ }
+
+ itemDef
+ {
+ name normal
+ type ITEM_TYPE_MULTI
+ text "Dedicated:"
+ // dedicated is a special cvar in that as soon as it is set,
+ // the game goes to console only so the ui catches this one specifically
+ cvar "ui_dedicated"
+ cvarFloatList { "No" 0 "LAN" 1 "Internet" 2 }
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(7*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav"
+ }
+ }
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_YESNO
+ text "Auto Download:"
+ cvar "sv_allowdownload"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(8*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav"
+ }
+ }
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_YESNO
+ text "Enable Voting:"
+ cvar "g_allowvote"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(9*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav"
+ }
+ }
+
+
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_NUMERICFIELD
+ text "Minimum Ping:"
+ cvar "sv_minping"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(11*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ maxchars 4
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_NUMERICFIELD
+ text "Maximum Ping:"
+ cvar "sv_maxping"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(12*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ maxchars 4
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_YESNO
+ text "Synchronous Client:"
+ cvar "g_synchronousclients"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(13*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav"
+ }
+ }
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_NUMERICFIELD
+ text "Max Rate:"
+ cvar "sv_maxrate"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(14*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ maxchars 4
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_NUMERICFIELD
+ text "Zombie Time:"
+ cvar "sv_zombietime"
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(15*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ maxchars 4
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name expert
+ type ITEM_TYPE_NUMERICFIELD
+ text "Reconnect Limit:"
+ cvar "sv_reconnectlimit"
+ maxchars 4
+ rect (OPTIONS_X+BORDER) (OPTIONS_Y+ELEM_OFF_Y+(16*ELEM_H)) (OPTIONS_W-(2*BORDER)) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx ELEM_OFF_X
+ textscale .36
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+
+
+ // BACK BAR //
+
+ itemDef
+ {
+ name back
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/backarrow.tga"
+ rect BC_X BC_Y ARROW_H ARROW_W
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu4.wav";
+ close createserver
+ }
+
+ mouseEnter
+ {
+ hide back;
+ show back_alt
+ }
+ }
+
+ itemDef
+ {
+ name back_alt
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/backarrow_alt.tga"
+ rect BC_X BC_Y ARROW_H ARROW_W
+ aspectBias ALIGN_LEFT
+ backcolor 0 0 0 0
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ type ITEM_TYPE_BUTTON
+
+ text "Back"
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx ARROW_W
+ textscale .6
+
+ mouseExit
+ {
+ hide back_alt;
+ show back
+ }
+
+ action
+ {
+ play "sound/misc/menu4.wav";
+ close createserver
+ }
+ }
+
+
+
+
+ itemDef
+ {
+ name accept
+ style WINDOW_STYLE_SHADER
+ rect ((BC_X+BC_W)-ARROW_W) BC_Y ARROW_H ARROW_W
+ aspectBias ALIGN_RIGHT
+ background "ui/assets/forwardarrow.tga"
+ backcolor 0 0 0 0
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ mouseEnter
+ {
+ hide accept;
+ show accept_alt
+ }
+
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript StartServer
+ }
+ }
+
+ itemDef
+ {
+ name accept_alt
+ style WINDOW_STYLE_SHADER
+ rect ((BC_X+BC_W)-ARROW_W) BC_Y ARROW_H ARROW_W
+ aspectBias ALIGN_RIGHT
+ background "ui/assets/forwardarrow_alt.tga"
+ backcolor 0 0 0 0
+ type ITEM_TYPE_BUTTON
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+
+ text "Create"
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx -ARROW_W
+ textscale .6
+
+ mouseExit
+ {
+ hide accept_alt;
+ show accept
+ }
+
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript StartServer
+ }
+ }
+ }
+}
diff --git a/assets/ui/demo.menu b/assets/ui/demo.menu
new file mode 100644
index 0000000..bec3a05
--- /dev/null
+++ b/assets/ui/demo.menu
@@ -0,0 +1,108 @@
+#include "ui/menudef.h"
+
+{
+ \\ DEMO \\
+
+#define W 300
+#define H 240
+#define BUTT_W 45
+#define BUTT_H 35
+#define BORDER 10
+
+ menuDef
+ {
+ name "demo"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onEsc
+ {
+ close demo
+ }
+ onOpen
+ {
+ uiScript loadDemos
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name demolist
+ rect BORDER BORDER (W-(2*BORDER)) (H-(BUTT_H+BORDER))
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .25
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_DEMOS
+ textalign 3
+ textaligny 14
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ doubleClick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript RunDemo
+ }
+ }
+
+ itemDef
+ {
+ name play
+ text "Play"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect (W-(2*BUTT_W)) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close demo;
+ uiScript RunDemo
+ }
+ }
+
+ itemDef
+ {
+ name cancel
+ text "Cancel"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect (W-BUTT_W) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ close demo
+ }
+ }
+ }
+}
diff --git a/assets/ui/demo_error.menu b/assets/ui/demo_error.menu
new file mode 100644
index 0000000..1427a28
--- /dev/null
+++ b/assets/ui/demo_error.menu
@@ -0,0 +1,101 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 320
+#define H 320
+#define BORDER 10
+
+#define BUTT_H 25
+#define BUTT_W 65
+
+#define INFO_W (W-(2*BORDER))
+#define INFO_H (H-((4*BORDER)+(2*BUTT_H)))
+#define INFO_X BORDER
+#define INFO_Y ((2*BORDER)+BUTT_H)
+
+ menuDef
+ {
+ name "demo_error_popmenu"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onClose { uiScript clearDemoError }
+ onESC
+ {
+ play "sound/misc/menu1.wav";
+ close demo_error_popmenu;
+ open demo
+ }
+
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name dropinfo
+ rect BORDER BORDER INFO_W BUTT_H
+ type ITEM_TYPE_TEXT
+ text "Error"
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name dropinfo
+ rect INFO_X INFO_Y INFO_W INFO_H
+ type ITEM_TYPE_TEXT
+ style WINDOW_STYLE_FILLED
+ wrapped
+ cvar "com_demoErrorMessage"
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .33
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name exit
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ backcolor .37 .1 .1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close demo_error_popmenu
+ open demo
+ }
+ }
+ }
+}
diff --git a/assets/ui/download.menu b/assets/ui/download.menu
new file mode 100644
index 0000000..dc8247f
--- /dev/null
+++ b/assets/ui/download.menu
@@ -0,0 +1,167 @@
+#include "ui/menudef.h"
+
+{
+ \\ DOWNLOAD \\
+
+ menuDef
+ {
+ name "download_popmenu"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect 158 80 320 320
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onClose { }
+ onOpen
+ {
+ uiScript loadServerInfo;
+ }
+ onESC
+ {
+ play "sound/misc/menu1.wav";
+ close download_popmenu;
+ uiScript downloadIgnore;
+ }
+
+ itemDef
+ {
+ name window
+ rect 10 15 300 320
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name downloadinfo
+ rect 0 50 320 20
+ type ITEM_TYPE_TEXT
+ text "Download"
+ textalign ALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_SHADOWEDMORE
+ textscale .333
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name downloadinfo
+ rect 60 80 200 270
+ type ITEM_TYPE_TEXT
+ style WINDOW_STYLE_FILLED
+ textstyle ITEM_TEXTSTYLE_SHADOWED
+ wrapped
+ cvar "com_downloadPromptText"
+ textalign ALIGN_CENTER
+ textvalign VALIGN_TOP
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ decoration
+ }
+
+
+ // BUTTON //
+
+
+ itemDef
+ {
+ name curl
+ text "Download from website"
+ textscale .25
+ group grpControlbutton
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect 60 250 200 15
+ textalign ALIGN_CENTER
+ forecolor 1 1 1 1
+ backcolor .37 .1 .1 1
+ visible MENU_TRUE
+ cvarTest "ui_serverinfo_allowdl"
+ showCvar { 1 5 9 13 }
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close download_popmenu;
+ uiScript downloadCURL;
+ }
+ }
+
+ itemDef
+ {
+ name udp
+ text "Download from server"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ group grpControlbutton
+ style WINDOW_STYLE_EMPTY
+ rect 60 265 200 15
+ textalign ALIGN_CENTER
+ forecolor 1 1 1 1
+ backcolor .37 .1 .1 1
+ visible MENU_TRUE
+ cvarTest "ui_serverinfo_allowdl"
+ showCvar { 1 3 9 11 }
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close download_popmenu;
+ uiScript downloadUDP;
+ }
+ }
+
+ itemDef
+ {
+ name ignore
+ text "Ignore"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ group grpControlbutton
+ style WINDOW_STYLE_EMPTY
+ rect 60 280 200 15
+ textalign ALIGN_CENTER
+ forecolor 1 1 1 1
+ backcolor .37 .1 .1 1
+ visible MENU_TRUE
+ cvarTest "sv_pure"
+ hideCvar { 1 }
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close download_popmenu;
+ uiScript downloadIgnore;
+ }
+ }
+
+ itemDef
+ {
+ name disconnect
+ text "Disconnect"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ group grpControlbutton
+ style WINDOW_STYLE_EMPTY
+ rect 60 295 200 15
+ textalign ALIGN_CENTER
+ forecolor 1 1 1 1
+ backcolor .37 .1 .1 1
+ visible 1
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close download_popmenu;
+ exec "disconnect";
+ }
+ }
+ }
+}
diff --git a/assets/ui/drop.menu b/assets/ui/drop.menu
new file mode 100644
index 0000000..162a019
--- /dev/null
+++ b/assets/ui/drop.menu
@@ -0,0 +1,122 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 320
+#define H 320
+#define BORDER 10
+
+#define BUTT_H 25
+#define BUTT_W 65
+
+#define INFO_W (W-(2*BORDER))
+#define INFO_H (H-((4*BORDER)+(2*BUTT_H)))
+#define INFO_X BORDER
+#define INFO_Y ((2*BORDER)+BUTT_H)
+
+ menuDef
+ {
+ name "drop_popmenu"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onClose { uiScript clearError }
+ onESC
+ {
+ play "sound/misc/menu1.wav";
+ close drop_popmenu;
+ open main
+ }
+
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name dropinfo
+ rect BORDER BORDER INFO_W BUTT_H
+ type ITEM_TYPE_TEXT
+ text "Disconnected"
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name dropinfo
+ rect INFO_X INFO_Y INFO_W INFO_H
+ type ITEM_TYPE_TEXT
+ style WINDOW_STYLE_FILLED
+ wrapped
+ cvar "com_errorMessage"
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .33
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name exit
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ rect (W-((2*BORDER)+(2*BUTT_W))) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ backcolor .37 .1 .1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close drop_popmenu
+ }
+ }
+
+ itemDef
+ {
+ name reconnect
+ text "Reconnect"
+ type ITEM_TYPE_BUTTON
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ backcolor .37 .1 .1 1
+ visible MENU_TRUE
+ action
+ {
+ close drop_popmenu;
+ exec "reconnect";
+ }
+ }
+ }
+}
+
+
diff --git a/assets/ui/error.menu b/assets/ui/error.menu
new file mode 100644
index 0000000..2c54d2d
--- /dev/null
+++ b/assets/ui/error.menu
@@ -0,0 +1,102 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 320
+#define H 320
+#define BORDER 10
+
+#define BUTT_H 25
+#define BUTT_W 65
+
+#define INFO_W (W-(2*BORDER))
+#define INFO_H (H-((4*BORDER)+(2*BUTT_H)))
+#define INFO_X BORDER
+#define INFO_Y ((2*BORDER)+BUTT_H)
+
+ menuDef
+ {
+ name "error_popmenu"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onClose { uiScript clearError }
+ onESC
+ {
+ play "sound/misc/menu1.wav";
+ close error_popmenu;
+ open main
+ }
+
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name dropinfo
+ rect BORDER BORDER INFO_W BUTT_H
+ type ITEM_TYPE_TEXT
+ text "Error"
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name dropinfo
+ rect INFO_X INFO_Y INFO_W INFO_H
+ type ITEM_TYPE_TEXT
+ style WINDOW_STYLE_FILLED
+ wrapped
+ cvar "com_errorMessage"
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .33
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name exit
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ backcolor .37 .1 .1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close error_popmenu
+ }
+ }
+ }
+}
+
+
diff --git a/assets/ui/findplayer.menu b/assets/ui/findplayer.menu
new file mode 100644
index 0000000..09d715a
--- /dev/null
+++ b/assets/ui/findplayer.menu
@@ -0,0 +1,173 @@
+#include "ui/menudef.h"
+
+{
+ \\ FIND PLAYER POPUP MENU \\
+
+#define W 400
+#define H 400
+#define BUTT_W 45
+#define BUTT_H 35
+#define BORDER 10
+#define LIST_W (W-(2*BORDER))
+#define LIST_DW (LIST_W-40)
+#define LEFT_C 0.13
+#define RIGHT_C 0.61
+#define SEARCH_H 30
+#define SERVERS_H 105
+
+ menuDef
+ {
+ name "findplayer_popmenu"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onClose { }
+ onOpen
+ {
+ uiScript FindPlayer
+ }
+
+ onESC
+ {
+ close findplayer_popmenu
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name namefield
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Name:"
+ cvar "ui_findplayer"
+ maxChars 20
+ rect BORDER BORDER (W-((2*BORDER)+BUTT_W)) SEARCH_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textscale .3
+ outlinecolor .2 .2 .2 .5
+ backcolor 0 0 0 0
+ forecolor 1 1 1 1
+ border WINDOW_BORDER_NONE
+ bordercolor 0 0 0 0
+ action { ui_script FindPlayer }
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name search
+ text "Search"
+ textscale .25
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) BORDER BUTT_W SEARCH_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ ui_script FindPlayer
+ }
+ }
+
+
+ itemDef
+ {
+ name serverNameList
+ rect BORDER ((2*BORDER)+SEARCH_H) LIST_W SERVERS_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 16
+ textscale .25
+ outlinecolor .2 .2 .2 .5
+ border WINDOW_BORDER_FULL
+ bordersize 1
+ bordercolor .5 .5 .5 1
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_FINDPLAYER
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name serverInfoList
+ rect BORDER ((3*BORDER)+SEARCH_H+SERVERS_H) LIST_W (H-(SEARCH_H+SERVERS_H+BUTT_H+(3*BORDER)))
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 16
+ textscale .25
+ border WINDOW_BORDER_FULL
+ bordersize 1
+ bordercolor .5 .5 .5 1
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_SERVERSTATUS
+ notselectable
+ visible MENU_TRUE
+ columns 4
+ 0 ((2*LEFT_C)*LIST_DW) ALIGN_LEFT
+ (LEFT_C*LIST_DW) (LEFT_C*LIST_DW) ALIGN_LEFT
+ ((2*LEFT_C)*LIST_DW) (LEFT_C*LIST_DW) ALIGN_LEFT
+ ((1-RIGHT_C)*LIST_DW) (RIGHT_C*LIST_DW) ALIGN_LEFT
+ }
+
+ // BUTTON //
+
+ itemDef
+ {
+ name join
+ text "Join"
+ textscale .25
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(2*BUTT_W)) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action { ui_script FoundPlayerJoinServer }
+ }
+
+ itemDef
+ {
+ name close
+ text "Close"
+ textscale .25
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-BUTT_W) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close findplayer_popmenu
+ }
+ }
+ }
+}
+
+
diff --git a/assets/ui/folders.menu b/assets/ui/folders.menu
new file mode 100644
index 0000000..176f3d6
--- /dev/null
+++ b/assets/ui/folders.menu
@@ -0,0 +1,121 @@
+#include "ui/menudef.h"
+
+{
+ \\ FOR OPENING FOLDERS IN A DEFAULT FILE MANAGER \\
+
+#define X 0
+#define Y 20
+#define W 250
+#define H ((10*(ELEM_H+ELEM_GAP))+120)
+#define TOFF_X (0-(W/2))
+#define ELEM_H 16
+#define ELEM_GAP 4
+#define BUTT_W 35
+#define BUTT_H 35
+#define BORDER 10
+#define RESCOMBO_OFF 8
+
+ menuDef
+ {
+ name "browse_folders"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onEsc
+ {
+ play "sound/misc/menu1.wav";
+ close browse_folders
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+
+ itemDef
+ {
+ text "Browse Homepath"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect X Y W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ exec browseHomepath
+ }
+ }
+
+ itemDef
+ {
+ text "Browse Demos Folder"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect X (Y+(BUTT_H+ELEM_GAP)) W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ exec browseDemos
+ }
+ }
+
+ itemDef
+ {
+ text "Browse Screen Shots Folder"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect X (Y+(2*(BUTT_H+ELEM_GAP))) W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ exec browseScreenShots
+ }
+ }
+
+ itemDef
+ {
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect (W-BUTT_W) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close browse_folders
+ }
+ }
+ }
+}
diff --git a/assets/ui/help.txt b/assets/ui/help.txt
new file mode 100644
index 0000000..bd4c6a3
--- /dev/null
+++ b/assets/ui/help.txt
@@ -0,0 +1,135 @@
+{
+ "^3Welcome^7"
+ {
+ "In this section you will find a summary of major changes since 1.1. It is "
+ "not a complete list. In general, all things have been tweaked for balance in "
+ "some way.\n\n"
+ "We hope you enjoy playing. Your support gives us valuable data and "
+ "feedback as we work to bring you Tremulous 1.2. Please report all bugs. Thank "
+ "you."
+ }
+ "Alien Healing"
+ {
+ "The most important change for Alien players to know is that their healing "
+ "rate is slower away from creep. To counter this, healing near Boosters "
+ "and Basilisks is greatly accelerated.\n\n"
+ "Watch the health cross icon on your "
+ "HUD to see what your healing rate is. If the icon glows, you are on "
+ "creep. If you are near a booster or basilisk, you will see two "
+ "(2X healing) or four (3X healing) barbs around the health cross."
+ }
+ "Build-point Changes"
+ {
+ "Structures destroyed by enemy players will not immediately become available "
+ "for reuse, but instead enter a queue. Build points will gradually leave the "
+ "queue to become available again, at a rate proportional to the amount of "
+ "points in the queue.\n\n Repeaters can be built at any stage and come with 20 "
+ "BP that can only be used nearby to facilitate making small outposts. Aliens "
+ "do not have a structure that provides additional buildpoints, but they have 150 "
+ "overall BP to compensate."
+ }
+ "Marked Deconstruction"
+ {
+ "The deconstruction method has changed. Buildables are no longer instantly "
+ "deconstructed. Instead, a deconstruct mark appears on the health bar. "
+ "Go ahead and build a new buildable somewhere else and the old one will "
+ "be removed automatically. Buildables that are about to be removed by "
+ "constructing the selected buildable glow red."
+ }
+ "Alien Buildables"
+ {
+ "Nearly useless in 1.1, Barricades now have more health, are cheaper to "
+ "build, and will shrink to allow Aliens to pass over them. Acid tubes "
+ "will fire from behind barricades, providing a formidable defense. "
+ "Experiment with blocking off hallways and building staged defenses, but "
+ "keep in mind that low ceilings will prevent Tyrants from returning inside "
+ "the base. Hives are also much improved to become worth building in stage 3."
+ }
+ "Human Buildables"
+ {
+ "Turrets now have a small spin up delay before firing, but they have "
+ "increased range and damage output.\n\n"
+ "To protect against small Aliens getting inside "
+ "the base, build Tesla Generators at Stage 3. Tesla Generators no longer "
+ "require the Defense Computer to function. Instead, the Defense Computer "
+ "will automatically repair Human buildables. Tesla Generators can fire "
+ "over turrets. "
+ }
+ "Human Weapons"
+ {
+ "Most of the human projeciles have a small volume now, making them more "
+ "effective against smaller targets.\n"
+ "The Lucifer Cannon projectile can be fired faster but now takes longer "
+ "to charge. You will be able to hear your teammates overcharge "
+ "their Lucifer Cannon.\n"
+ "The Flamer projectile now gains more of the velocity of its wielder, "
+ "making it easier to chase down aliens without burning yourself to a "
+ "crisp. Other weapons also have smaller changes."
+ }
+ "Lag Correction"
+ {
+ "While the Tremulous implementation of Neil Toronto's unlagged is "
+ "becoming widely accepted, we also implement client-side improvements "
+ "not possible in 1.1 servers. For those who insist on leading their "
+ "attacks, setting cg_unlagged to 0 will disable backward reconcilliation "
+ "on your hitscan weapons."
+ }
+ "Sprint"
+ {
+ "The sprint bind has changed from \"boost\" to \"+button8\"; you can bind it "
+ "in the options menu or in the console (\\bind shift +button8). Now, instead "
+ "of tapping the button while moving to start sprinting, just hold it down "
+ "and let go to stop. Alternately, you can change this to a toggle behavior "
+ "with cg_sprintToggle. \n\n"
+ }
+ "Dodge"
+ {
+ "Humans also have a new movement ability: dodge. You can bind it in the "
+ "options menu or the console (\\bind shift +button6). When strafing or "
+ "walking backwards, press the dodge key to make a quick, low jump. You "
+ "can bind this to the same key as sprint in the console with \\bind shift "
+ "\"+button8; +button6\""
+ }
+ "Headshots"
+ {
+ "Headshots on unarmored humans only cause 150% damage. Battlesuit and "
+ "helmet protection have been reduced so headshot damage remains the same."
+ }
+ "Dretch"
+ {
+ "Dretches are slightly faster and can now damage any human structure while it "
+ "is still building, but can no longer damage turrets and teslas that "
+ "have been completed."
+ }
+ "Basilisk"
+ {
+ "Basilisks provide regeneration boosting auras to nearby teammates: 2x "
+ "from regular and 3x from advanced basilisks. Their footsteps are also "
+ "silent for greater stealth."
+ }
+ "Marauder"
+ {
+ "The Adv. Marauder's electric shock damage is no longer split between its "
+ "targets, making it more effective against large groups of humans and "
+ "buildables. Targets are now chosen slightly differently: instead of "
+ "each new chain section originating from the previous target, it will "
+ "originate from the first target."
+ }
+ "Dragoon"
+ {
+ "Advanced dragoons are now available at stage 2. Both dragoons have the "
+ "range of their chomp attacks lowered, but their pounce attacks are much "
+ "more useful. Try to use pounce to pin a human to the wall before chomping."
+ }
+ "Tyrant"
+ {
+ "The Tyrant is now a weaker class as its health has been lowered and "
+ "turret damage is greater. To counter this, Tyrants can charge for longer "
+ "periods of time, hit targets multiple times in a single charge, "
+ "and crush any Humans they land on top of. Trample charge does not "
+ "instantly release when full but can be held for two seconds. Trample "
+ "attacks on a human pinned against a wall are VERY powerful. Use this to "
+ "your advantage. The Tyrant's healing aura has been removed; find a "
+ "booster or a basilisk to heal faster."
+ }
+}
diff --git a/assets/ui/hud.txt b/assets/ui/hud.txt
new file mode 100644
index 0000000..be9fa8b
--- /dev/null
+++ b/assets/ui/hud.txt
@@ -0,0 +1,12 @@
+// hud menu defs
+//
+{
+ loadMenu { "ui/tremulous_human_hud.menu" }
+ loadMenu { "ui/tremulous_alien_builder_hud.menu" }
+ loadMenu { "ui/tremulous_alien_general_hud.menu" }
+ loadMenu { "ui/tremulous_default_hud.menu" }
+ loadMenu { "ui/tremulous_spectator_hud.menu" }
+
+ loadMenu { "ui/teamscore.menu" }
+ loadMenu { "ui/loading.menu" }
+}
diff --git a/ui/ingame.menu b/assets/ui/ingame.menu
index 13bd1f3..808287e 100644
--- a/ui/ingame.menu
+++ b/assets/ui/ingame.menu
@@ -1,72 +1,81 @@
#include "ui/menudef.h"
{
+
+#define BUTT_BAR_X 25
+#define BUTT_BAR_Y 0
+#define BUTT_BAR_W 250
+#define BUTT_BAR_H 56
+#define BUTT_W (BUTT_BAR_W/4)
+#define BUTT_H BUTT_BAR_H
+#define BUTT_TEXT_S 20
+
assetGlobalDef
{
font "fonts/font" 26 // font
smallFont "fonts/smallfont" 20 // font
bigFont "fonts/bigfont" 34 // font
- cursor "ui/assets/3_cursor3" // cursor
+ cursor "ui/assets/3_cursor3" // cursor
gradientBar "ui/assets/gradientbar2.tga" // gradient bar
itemFocusSound "sound/misc/menu2.wav" // sound for item getting focus (via keyboard or mouse )
-
+
fadeClamp 1.0 // sets the fadeup alpha
fadeCycle 1 // how often fade happens in milliseconds
fadeAmount 0.1 // amount to adjust alpha per cycle
shadowColor 0.1 0.1 0.1 0.25 // shadow color
}
-
+
\\ INGAME MENU \\
- menuDef
+ menuDef
{
name "ingame"
style WINDOW_STYLE_FILLED
- visible 0
+ visible MENU_FALSE
fullScreen 0
outOfBoundsClick // this closes the window if it gets a click out of the rectangle
- rect 0 0 640 48
+ rect 0 0 1280 56
focusColor 1 .75 0 1
disableColor .5 .5 .5 1
backColor 0 0 0 1
+ aspectBias ALIGN_LEFT
onEsc
{
close ingame;
}
-
+
itemDef
{
name splashmodel
- rect 0 -10 640 66
+ rect 0 -10 640 66
type ITEM_TYPE_MODEL
style WINDOW_STYLE_FILLED
asset_model "models/splash/splash_screen.md3"
model_fovx 32.0
model_fovy 3.8
model_angle 180
- visible 1
+ visible MENU_TRUE
decoration
backcolor 0 0 0 1
}
itemdef
{
- name game
- text "Game"
- rect 35 6 65 40
+ name game
+ text "Game"
+ rect BUTT_BAR_X BUTT_BAR_Y BUTT_W BUTT_H
type ITEM_TYPE_BUTTON
style WINDOW_STYLE_EMPTY
- textalign ITEM_ALIGN_CENTER
- textalignx 32
- textaligny 28
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
textscale .4
forecolor 1 1 1 1
- visible 1
+ visible MENU_TRUE
action
{
- play "sound/misc/menu1.wav";
+ play "sound/misc/menu1.wav";
open ingame_game
}
}
@@ -77,16 +86,15 @@
text "Options"
type ITEM_TYPE_BUTTON
style WINDOW_STYLE_EMPTY
- rect 100 6 70 40
- textalign ITEM_ALIGN_CENTER
- textalignx 35
- textaligny 28
+ rect (BUTT_BAR_X+BUTT_W) BUTT_BAR_Y BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
textscale .4
forecolor 1 1 1 1
- visible 1
+ visible MENU_TRUE
action
{
- play "sound/misc/menu1.wav";
+ play "sound/misc/menu1.wav";
open ingame_options
}
}
@@ -94,20 +102,37 @@
itemDef
{
name leave
+ text "Help"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (BUTT_BAR_X+(2*BUTT_W)) BUTT_BAR_Y BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open ingame_help
+ }
+ }
+
+ itemDef
+ {
+ name leave
text "Exit"
type ITEM_TYPE_BUTTON
style WINDOW_STYLE_EMPTY
- //rect 220 6 50 40
- rect 170 6 50 40
- textalign ITEM_ALIGN_CENTER
- textalignx 25
- textaligny 28
+ rect (BUTT_BAR_X+(3*BUTT_W)) BUTT_BAR_Y BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
textscale .4
forecolor 1 1 1 1
- visible 1
+ visible MENU_TRUE
action
{
- play "sound/misc/menu1.wav";
+ play "sound/misc/menu1.wav";
open ingame_leave
}
}
diff --git a/ui/ingame.txt b/assets/ui/ingame.txt
index 185ce97..2caf449 100644
--- a/ui/ingame.txt
+++ b/assets/ui/ingame.txt
@@ -1,8 +1,9 @@
// menu defs
-//
-{
+//
+{
loadMenu { "ui/ingame.menu" }
loadMenu { "ui/ingame_game.menu" }
loadMenu { "ui/ingame_options.menu" }
loadMenu { "ui/ingame_leave.menu" }
+ loadMenu { "ui/ingame_help.menu" }
}
diff --git a/assets/ui/ingame_game.menu b/assets/ui/ingame_game.menu
new file mode 100644
index 0000000..d7d7dd6
--- /dev/null
+++ b/assets/ui/ingame_game.menu
@@ -0,0 +1,862 @@
+#include "ui/menudef.h"
+
+{
+ \\ INGAME GAME BOX \\
+
+#define W 320
+#define H 310
+#define X 10
+#define Y 60
+#define BORDER 10
+
+#define TOPBUTT_W 80
+#define TOPBUTT_H 30
+
+#define SIDEBUTT_W 50
+#define SIDEBUTT_H 25
+
+#define MAP_X (SIDEBUTT_W+BORDER)
+#define MAP_Y ((2*BORDER)+TOPBUTT_H)
+#define MAP_W 124
+#define MAP_H 93
+#define MAPLIST_X MAP_X
+#define MAPLIST_Y ((3*BORDER)+TOPBUTT_H+MAP_H)
+#define MAPLIST_W (W-((2*BORDER)+SIDEBUTT_W))
+#define MAPLIST_H (H-((4*BORDER)+MAP_H+TOPBUTT_H))
+#define MAPBUTT_X (MAP_X+MAP_W+BORDER)
+#define MAPBUTT_Y MAP_Y
+#define MAPBUTT_W (W-(MAPBUTT_X+BORDER))
+#define MAPBUTT_H 20
+
+#define PBUTT_X MAP_X
+#define PBUTT_Y (H-((2*PBUTT_H)+BORDER))
+#define PBUTT_W (W-((2*BORDER)+SIDEBUTT_W))
+#define PBUTT_H 45
+#define PLIST_X PBUTT_X
+#define PLIST_Y ((2*BORDER)+TOPBUTT_H)
+#define PLIST_W PBUTT_W
+#define PLIST_H ((H-((4*BORDER)+(2*PBUTT_H)+TOPBUTT_H)))
+
+#define PLAYER_C 0.7
+#define IGN_C 0.15
+#define IGNY_C 0.15
+#define IGNHEAD_H 15
+#define IGNHEAD_Y ((2*BORDER)+TOPBUTT_H)
+#define IGNBUTT_W ((W-(2*BORDER))/2)
+#define IGNBUTT_H 25
+#define IGNBUTT_X BORDER
+#define IGNBUTT_Y (H-(BORDER+IGNBUTT_H))
+#define IGNORE_W (W-(2*BORDER))
+#define IGNORE_W2 ((W-(2*BORDER))-15)
+#define IGNORE_H (H-((4*BORDER)+TOPBUTT_H+IGNHEAD_H+IGNBUTT_H))
+#define IGNORE_X BORDER
+#define IGNORE_Y ((2*BORDER)+TOPBUTT_H+IGNHEAD_H)
+#define IGNORE_TOFF 5
+
+#define INFO_Y ((2*BORDER)+TOPBUTT_H+10)
+#define INFOELEM_H 15
+#define INFO_OFF (0-(W-90))
+
+ menuDef
+ {
+ name "ingame_game"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ outOfBoundsClick // this closes the window if it gets a click out of the rectangle
+ rect X Y W H
+ focusColor 1 .75 0 1
+ aspectBias ALIGN_LEFT
+ onopen
+ {
+ uiScript InitIgnoreList;
+ uiScript loadArenas;
+ uiScript loadServerInfo;
+ hide gameGrp;
+ show vote;
+ show mapvote;
+
+ setitemcolor voteBtn forecolor 0.2 0.2 0.2 1.0;
+ setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ //Section menus
+ itemDef
+ {
+ name voteBtn
+ text "Vote"
+ group menuGrp
+ style WINDOW_STYLE_EMPTY
+ rect (W-((3*TOPBUTT_W)+BORDER)) BORDER TOPBUTT_W TOPBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .35
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide gameGrp;
+ show vote;
+ show mapvote;
+
+ setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor voteBtn forecolor 0.2 0.2 0.2 1.0;
+ setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0
+ }
+ }
+
+ itemDef
+ {
+ name ignoreBtn
+ text "Ignore"
+ group menuGrp
+ style WINDOW_STYLE_EMPTY
+ rect (W-((2*TOPBUTT_W)+BORDER)) BORDER TOPBUTT_W TOPBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .35
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide gameGrp;
+ show ignore;
+
+ setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor voteBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor ignoreBtn forecolor 0.2 0.2 0.2 1.0
+ }
+ }
+
+ itemDef
+ {
+ name infoBtn
+ text "Info"
+ group menuGrp
+ style WINDOW_STYLE_EMPTY
+ rect (W-((1*TOPBUTT_W)+BORDER)) BORDER TOPBUTT_W TOPBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .35
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide gameGrp;
+ show info;
+
+ setitemcolor infoBtn forecolor 0.2 0.2 0.2 1.0;
+ setitemcolor voteBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0
+ }
+ }
+
+
+//////// VOTE
+
+ //Vote menu
+ itemDef
+ {
+ name vote
+ text "Map"
+ group gameGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide gameGrp;
+ show mapvote;
+ show vote;
+ }
+ }
+
+ itemDef
+ {
+ name vote
+ text "Players"
+ group gameGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H+SIDEBUTT_H) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide gameGrp;
+ show playervote;
+ show reasonfield;
+ show vote;
+ }
+ }
+
+ itemDef
+ {
+ name vote
+ text "Team"
+ group gameGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H+(2*SIDEBUTT_H)) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide gameGrp;
+ show teamvote;
+ show reasonfield;
+ show vote;
+ }
+ }
+
+ itemDef
+ {
+ name reasonfield
+ group gameGrp
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Reason:"
+ cvar "ui_reason"
+ maxChars 50
+ rect PBUTT_X (PBUTT_Y+PBUTT_H) PBUTT_W PBUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textscale .25
+ outlinecolor .2 .2 .2 .5
+ backcolor 0 0 0 0
+ forecolor 1 1 1 1
+ border WINDOW_BORDER_NONE
+ bordercolor 0 0 0 0
+ visible MENU_FALSE
+ }
+
+///// Map Vote
+ itemDef
+ {
+ name mapvote
+ group gameGrp
+ style WINDOW_STYLE_EMPTY
+ ownerdraw UI_SELECTEDMAPPREVIEW
+ rect MAP_X MAP_Y MAP_W MAP_H
+ border WINDOW_BORDER_FULL
+ bordercolor .5 .5 .5 .5
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name mapvote
+ group gameGrp
+ rect MAPLIST_X MAPLIST_Y MAPLIST_W MAPLIST_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 15
+ textscale .225
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_MAPS
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_FALSE
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript voteMap;
+ uiScript closeingame
+ }
+ }
+
+ itemDef
+ {
+ name mapvote
+ group gameGrp
+ text "Load Selected Map"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect MAPBUTT_X MAPBUTT_Y MAPBUTT_W MAPBUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript voteMap;
+ uiScript closeingame
+ }
+ }
+
+ itemDef
+ {
+ name mapvote
+ group gameGrp
+ text "Load Selected Map Next"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect MAPBUTT_X (MAPBUTT_Y+MAPBUTT_H) MAPBUTT_W MAPBUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript voteNextMap;
+ uiScript closeingame
+ }
+ }
+
+ itemDef
+ {
+ name mapvote
+ group gameGrp
+ text "Restart Current Map"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect MAPBUTT_X (MAPBUTT_Y+(2*MAPBUTT_H)) MAPBUTT_W MAPBUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ exec "cmd callvote map_restart";
+ uiScript closeingame
+ }
+ }
+
+ itemDef
+ {
+ name mapvote
+ group gameGrp
+ text "Begin Sudden Death"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect MAPBUTT_X (MAPBUTT_Y+(3*MAPBUTT_H)) MAPBUTT_W MAPBUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ exec "cmd callvote sudden_death";
+ uiScript closeingame
+ }
+ }
+
+ itemDef
+ {
+ name mapvote
+ group gameGrp
+ text "End Match In Draw"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect MAPBUTT_X (MAPBUTT_Y+(4*MAPBUTT_H)) MAPBUTT_W MAPBUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ exec "cmd callvote draw";
+ uiScript closeingame
+ }
+ }
+
+///// Player Vote
+ itemDef
+ {
+ name playervote
+ group gameGrp
+ rect PLIST_X PLIST_Y PLIST_W PLIST_H
+ style WINDOW_STYLE_EMPTY
+ type ITEM_TYPE_LISTBOX
+ elementwidth 120
+ elementheight 15
+ textscale .225
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_PLAYER_LIST
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name playervote
+ group gameGrp
+ text "Mute Player"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect PBUTT_X PBUTT_Y (PBUTT_W/2) PBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript voteMute;
+ uiScript closeingame
+ }
+ }
+
+ itemDef
+ {
+ name playervote
+ group gameGrp
+ text "Un-Mute Player"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect (PBUTT_X+(PBUTT_W/2)) PBUTT_Y (PBUTT_W/2) PBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript voteUnMute;
+ uiScript closeingame
+ }
+ }
+
+ itemDef
+ {
+ name playervote
+ group gameGrp
+ text "Kick Player"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect PBUTT_X (PBUTT_Y+(PBUTT_H/2)) PBUTT_W PBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript voteKick;
+ uiScript closeingame
+ }
+ }
+
+
+///// Team Vote
+ itemDef
+ {
+ name teamvote
+ group gameGrp
+ rect PLIST_X PLIST_Y PLIST_W PLIST_H
+ style WINDOW_STYLE_EMPTY
+ type ITEM_TYPE_LISTBOX
+ elementwidth 120
+ elementheight 15
+ textscale .225
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_TEAM_LIST
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name teamvote
+ group gameGrp
+ text "Kick Teammate"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect PBUTT_X PBUTT_Y (PBUTT_W/2) PBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript voteTeamKick;
+ uiScript closeingame
+ }
+ }
+
+ itemDef
+ {
+ name teamvote
+ group gameGrp
+ text "Deny Building For Teammate"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect (PBUTT_X+(PBUTT_W/2)) PBUTT_Y (PBUTT_W/2) PBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript voteTeamDenyBuild;
+ uiScript closeingame
+ }
+ }
+
+ itemDef
+ {
+ name teamvote
+ group gameGrp
+ text "Allow Building For Teammate"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect 110 215 150 20
+ rect PBUTT_X (PBUTT_Y+(PBUTT_H/2)) (PBUTT_W/2) PBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript voteTeamAllowBuild;
+ uiScript closeingame
+ }
+ }
+
+ itemDef
+ {
+ name teamvote
+ group gameGrp
+ text "Admit Defeat"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect (PBUTT_X+(PBUTT_W/2)) (PBUTT_Y+(PBUTT_H/2)) (PBUTT_W/2) PBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ exec "cmd callteamvote admitdefeat";
+ uiScript closeingame
+ }
+ }
+
+//////// IGNORE
+ itemDef
+ {
+ name ignore
+ group gameGrp
+ rect IGNORE_X IGNHEAD_Y (PLAYER_C*IGNORE_W2) IGNHEAD_H
+ text "Player Name"
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx IGNORE_TOFF
+ visible MENU_FALSE
+ type ITEM_TYPE_TEXT
+ textscale .225
+ }
+ itemDef
+ {
+ name ignore
+ group gameGrp
+ rect (IGNORE_X+(PLAYER_C*IGNORE_W2)) IGNHEAD_Y (IGN_C*IGNORE_W2) IGNHEAD_H
+ text "Ignored"
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ visible MENU_FALSE
+ type ITEM_TYPE_TEXT
+ textscale .225
+ }
+ itemDef
+ {
+ name ignore
+ group gameGrp
+ rect (IGNORE_X+((PLAYER_C+IGN_C)*IGNORE_W2)) IGNHEAD_Y (IGNY_C*IGNORE_W2) IGNHEAD_H
+ text "Ignoring You"
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ visible MENU_FALSE
+ type ITEM_TYPE_TEXT
+ textscale .225
+ }
+ itemDef
+ {
+ name ignore
+ group gameGrp
+ rect IGNORE_X IGNORE_Y IGNORE_W IGNORE_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 16
+ textscale .225
+ border WINDOW_BORDER_FULL
+ bordersize 1
+ bordercolor .5 .5 .5 1
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_IGNORE_LIST
+ visible MENU_FALSE
+ columns 3
+ IGNORE_TOFF ((PLAYER_C*IGNORE_W)-(3*IGNORE_TOFF)) ALIGN_LEFT
+ (IGNORE_TOFF+((PLAYER_C)*IGNORE_W)) ((IGN_C*IGNORE_W)-(3*IGNORE_TOFF)) ALIGN_CENTER
+ (IGNORE_TOFF+((PLAYER_C+IGN_C)*IGNORE_W)) ((IGNY_C*IGNORE_W)-(3*IGNORE_TOFF)) ALIGN_CENTER
+ doubleClick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript ToggleIgnore
+ }
+ }
+
+ itemDef
+ {
+ name ignore
+ text "Ignore Player"
+ group gameGrp
+ style WINDOW_STYLE_EMPTY
+ rect IGNBUTT_X IGNBUTT_Y IGNBUTT_W IGNBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript IgnorePlayer
+ }
+ }
+
+ itemDef
+ {
+ name ignore
+ text "Stop Ignoring Player"
+ group gameGrp
+ style WINDOW_STYLE_EMPTY
+ rect (IGNBUTT_X+IGNBUTT_W) IGNBUTT_Y IGNBUTT_W IGNBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript UnIgnorePlayer
+ }
+ }
+
+//////// INFO
+
+ itemDef
+ {
+ name info
+ group gameGrp
+ rect 0 (INFO_Y+(0*INFOELEM_H)) W INFOELEM_H
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Server Name:"
+ cvar ui_serverinfo_hostname
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx INFO_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ }
+
+ itemDef
+ {
+ name info
+ group gameGrp
+ rect 0 (INFO_Y+(1*INFOELEM_H)) W INFOELEM_H
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Time Limit:"
+ cvar ui_serverinfo_timelimit
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx INFO_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ }
+
+ itemDef
+ {
+ name info
+ group gameGrp
+ rect 0 (INFO_Y+(2*INFOELEM_H)) W INFOELEM_H
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Sudden Death Time:"
+ cvar ui_serverinfo_sd
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx INFO_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ }
+
+ itemDef
+ {
+ name info
+ group gameGrp
+ rect 0 (INFO_Y+(3*INFOELEM_H)) W INFOELEM_H
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Max Clients:"
+ cvar ui_serverinfo_maxclients
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx INFO_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ }
+
+ itemDef
+ {
+ name info
+ group gameGrp
+ rect 0 (INFO_Y+(4*INFOELEM_H)) W INFOELEM_H
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Map Name:"
+ cvar ui_serverinfo_mapname
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx INFO_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ }
+
+ itemDef
+ {
+ name info
+ group gameGrp
+ rect 0 (INFO_Y+(5*INFOELEM_H)) W INFOELEM_H
+ type ITEM_TYPE_YESNO
+ style WINDOW_STYLE_EMPTY
+ text "Lag Correction:"
+ cvar ui_serverinfo_unlagged
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx INFO_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ }
+
+ itemDef
+ {
+ name info
+ group gameGrp
+ rect 0 (INFO_Y+(6*INFOELEM_H)) W INFOELEM_H
+ type ITEM_TYPE_YESNO
+ style WINDOW_STYLE_EMPTY
+ text "Friendly Fire:"
+ textalign ALIGN_RIGHT
+ cvar ui_serverinfo_friendlyFire
+ textvalign VALIGN_CENTER
+ textalignx INFO_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ }
+
+ itemDef
+ {
+ name info
+ group gameGrp
+ rect 0 (INFO_Y+(7*INFOELEM_H)) W INFOELEM_H
+ type ITEM_TYPE_YESNO
+ style WINDOW_STYLE_EMPTY
+ text "Buildable Friendly Fire:"
+ cvar ui_serverinfo_friendlyBuildableFire
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx INFO_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ }
+
+ itemDef
+ {
+ name info
+ group gameGrp
+ rect 0 (INFO_Y+(8*INFOELEM_H)) W INFOELEM_H
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Version:"
+ cvar ui_serverinfo_version
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx INFO_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ }
+ }
+}
diff --git a/assets/ui/ingame_help.menu b/assets/ui/ingame_help.menu
new file mode 100644
index 0000000..4c8065b
--- /dev/null
+++ b/assets/ui/ingame_help.menu
@@ -0,0 +1,88 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 420
+#define H 290
+#define X 10
+#define Y 60
+#define BORDER 10
+
+#define LIST_W 140
+#define LIST_H (H-(2*BORDER))
+#define LIST_X BORDER
+#define LIST_Y BORDER
+
+#define INFO_W (W-((3*BORDER)+LIST_W))
+#define INFO_H (H-(2*BORDER))
+#define INFO_X ((2*BORDER)+LIST_W)
+#define INFO_Y BORDER
+#define INFO_TOFF 6
+
+ menuDef
+ {
+ name "ingame_help"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ outOfBoundsClick // this closes the window if it gets a click out of the rectangle
+ rect X Y W H
+ focusColor 1 .75 0 1
+ aspectBias ALIGN_LEFT
+ onOpen {
+ setFocus list;
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name "list"
+ rect LIST_X LIST_Y LIST_W LIST_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_HELP_LIST
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name infopane
+ ownerdraw UI_HELPINFOPANE
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ textscale .33
+ textalign ALIGN_LEFT
+ textvalign VALIGN_TOP
+ textalignx INFO_TOFF
+ textaligny INFO_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ visible MENU_TRUE
+ decoration
+ }
+ }
+}
diff --git a/assets/ui/ingame_leave.menu b/assets/ui/ingame_leave.menu
new file mode 100644
index 0000000..d07e3ce
--- /dev/null
+++ b/assets/ui/ingame_leave.menu
@@ -0,0 +1,209 @@
+#include "ui/menudef.h"
+
+{
+ \\ INGAME_LEAVE MENU \\
+
+#define X 160
+#define Y 60
+#define W 120
+#define H 100
+
+#define L1_X 0
+#define L1_Y (H/6)
+#define L1_W W
+#define L1_H (H/3)
+#define L2_X 0
+#define L2_Y (H/2)
+#define L2_W W
+#define L2_H (H/3)
+
+ menuDef
+ {
+ name "ingame_leave"
+ visible MENU_TRUE
+ fullScreen 0
+ outOfBoundsClick // this closes the window if it gets a click out of the rectangle
+ rect X Y W H
+ focusColor 1 .75 0 1
+ aspectBias ALIGN_LEFT
+ onOpen
+ {
+ show grpMenu;
+ hide grpConfirm
+ }
+
+ itemDef
+ {
+ name leave
+ style WINDOW_STYLE_FILLED
+ rect 0 0 W H
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name leave
+ type ITEM_TYPE_BUTTON
+ text "Main Menu"
+ group grpMenu
+ style WINDOW_STYLE_EMPTY
+ rect L1_X L1_Y L1_W L1_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide grpMenu;
+ show leaveConfirm
+ }
+ }
+
+ itemDef
+ {
+ name leave
+ group grpMenu
+ type ITEM_TYPE_BUTTON
+ text "Quit"
+ style WINDOW_STYLE_EMPTY
+ rect L2_X L2_Y L2_W L2_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide grpMenu;
+ show quitConfirm
+ }
+ }
+
+
+ // CONFIRMS //
+
+
+ itemDef
+ {
+ name leaveConfirm
+ type ITEM_TYPE_TEXT
+ text "Return To Main Menu?"
+ group grpConfirm
+ style WINDOW_STYLE_EMPTY
+ rect L1_X L1_Y L1_W L1_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .25
+ decoration
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name leaveConfirm
+ text "Yes"
+ group grpConfirm
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect L2_X L2_Y (L2_W/2) L2_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript leave
+ }
+ }
+
+ itemDef
+ {
+ name leaveConfirm
+ text "No"
+ group grpConfirm
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect (L2_X+(L2_W/2)) L2_Y (L2_W/2) L2_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ hide grpConfirm;
+ show grpMenu
+ }
+ }
+
+ itemDef
+ {
+ name quitConfirm
+ type ITEM_TYPE_TEXT
+ text "Want To Quit Game?"
+ group grpConfirm
+ style WINDOW_STYLE_EMPTY
+ rect L1_X L1_Y L1_W L1_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ decoration
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name quitConfirm
+ text "Yes"
+ group grpConfirm
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect L2_X L2_Y (L2_W/2) L2_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript quit
+ }
+ }
+
+ itemDef
+ {
+ name quitConfirm
+ text "No"
+ group grpConfirm
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect (L2_X+(L2_W/2)) L2_Y (L2_W/2) L2_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ hide grpConfirm;
+ show grpMenu
+ }
+ }
+ }
+}
diff --git a/assets/ui/ingame_options.menu b/assets/ui/ingame_options.menu
new file mode 100644
index 0000000..d3e7880
--- /dev/null
+++ b/assets/ui/ingame_options.menu
@@ -0,0 +1,2577 @@
+#include "ui/menudef.h"
+
+{
+ \\ INGAME OPTIONS BOX \\
+
+#define W 320
+#define H 290
+#define X 10
+#define Y 60
+#define BORDER 10
+
+#define TOPBUTT_W ((W-(2*BORDER))/4)
+#define TOPBUTT_H 30
+
+#define CONTENT_X BORDER
+#define CONTENT_Y ((1.5*BORDER)+TOPBUTT_H)
+#define CONTENT_W (W-(2*BORDER))
+#define CONTENT_OFF (0-(CONTENT_W/2))
+
+#define SIDEBUTT_W 65
+#define SIDEBUTT_H 25
+#define SCONTENT_X (SIDEBUTT_W+BORDER)
+#define SCONTENT_Y CONTENT_Y
+#define SCONTENT_W (W-(SIDEBUTT_W+(2*BORDER)))
+#define SCONTENT_OFF (0-(SCONTENT_W/2))
+
+#define RESCOMBO_OFF 8
+
+#define ELEM_H 16
+
+ menuDef
+ {
+ name "ingame_options"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ outOfBoundsClick // this closes the window if it gets a click out of the rectangle
+ rect X Y W H
+ focusColor 1 .75 0 1
+ aspectBias ALIGN_LEFT
+ onopen
+ {
+ hide optionsGrp;
+ show player;
+
+ setitemcolor playerBtn forecolor 0.2 0.2 0.2 1.0;
+ setitemcolor hudBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor controlsBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor systemBtn forecolor 1.0 1.0 1.0 1.0
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ //Section menus
+ itemDef
+ {
+ name PlayerBtn
+ text "Player"
+ group menuGrp
+ style WINDOW_STYLE_EMPTY
+ rect (W-((4*TOPBUTT_W)+BORDER)) BORDER TOPBUTT_W TOPBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .35
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show player;
+
+ setitemcolor playerBtn forecolor 0.2 0.2 0.2 1.0;
+ setitemcolor hudBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor controlsBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor systemBtn forecolor 1.0 1.0 1.0 1.0
+ }
+ }
+ itemDef
+ {
+ name hudBtn
+ text "HUD"
+ group menuGrp
+ style WINDOW_STYLE_EMPTY
+ rect (W-((3*TOPBUTT_W)+BORDER)) BORDER TOPBUTT_W TOPBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .35
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show hud;
+
+ setitemcolor playerBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor hudBtn forecolor 0.2 0.2 0.2 1.0;
+ setitemcolor controlsBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor systemBtn forecolor 1.0 1.0 1.0 1.0
+ }
+ }
+
+ itemDef
+ {
+ name controlsBtn
+ text "Controls"
+ group menuGrp
+ style WINDOW_STYLE_EMPTY
+ rect (W-((2*TOPBUTT_W)+BORDER)) BORDER TOPBUTT_W TOPBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .35
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show controls;
+ show look;
+
+ setitemcolor playerBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor hudBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor controlsBtn forecolor 0.2 0.2 0.2 1.0;
+ setitemcolor systemBtn forecolor 1.0 1.0 1.0 1.0
+ }
+ }
+
+ itemDef
+ {
+ name systemBtn
+ text "System"
+ group menuGrp
+ style WINDOW_STYLE_EMPTY
+ rect (W-((1*TOPBUTT_W)+BORDER)) BORDER TOPBUTT_W TOPBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .35
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show system;
+ show ghardware;
+
+ setitemcolor playerBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor hudBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor controlsBtn forecolor 1.0 1.0 1.0 1.0;
+ setitemcolor systemBtn forecolor 0.2 0.2 0.2 1.0
+ }
+ }
+
+//////// PLAYER
+
+ itemDef
+ {
+ name player
+ group optionsGrp
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Name:"
+ cvar "name"
+ maxchars 40
+ rect CONTENT_X (CONTENT_Y+(0*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name player
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Taunts Sounds Off:"
+ cvar "cg_noTaunt"
+ rect CONTENT_X (CONTENT_Y+(1*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name player
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Team Chats Only:"
+ cvar "cg_teamChatsOnly"
+ rect CONTENT_X (CONTENT_Y+(2*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name player
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Sticky Spectate:"
+ cvar "cg_stickySpec"
+ rect CONTENT_X (CONTENT_Y+(3*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name player
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Tutorial Mode:"
+ cvar "cg_tutorial"
+ rect CONTENT_X (CONTENT_Y+(4*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name player
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Disable Warning Dialogs:"
+ cvar "cg_disableWarningDialogs"
+ cvarFloatList { "No" 0 "Print to Console" 1 "Yes" 2 }
+ rect CONTENT_X (CONTENT_Y+(5*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name player
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Static Death Cam:"
+ cvar "cg_staticDeathCam"
+ rect CONTENT_X (CONTENT_Y+(6*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+//////// HUD
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Show Clock:"
+ cvar "cg_drawClock"
+ cvarFloatList { "No" 0 "12 Hour" 1 "24 Hour" 2 }
+ rect CONTENT_X (CONTENT_Y+(0*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Show Crosshair:"
+ cvar "cg_drawCrosshair"
+ cvarFloatList { "Never" 0 "Ranged Weapons Only" 1 "Always" 2 }
+ rect CONTENT_X (CONTENT_Y+(1*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Crosshair Size:"
+ cvar "cg_crosshairSize"
+ cvarFloatList { "Normal" 1 "Small" 0.75 "Tiny" 0.5 "Huge" 1.25 }
+ rect CONTENT_X (CONTENT_Y+(2*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Show Charge Bar:"
+ cvar "cg_drawChargeBar"
+ rect CONTENT_X (CONTENT_Y+(3*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Show Lag-o-meter:"
+ cvar "cg_lagometer"
+ rect CONTENT_X (CONTENT_Y+(4*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Show Team Overlay:"
+ cvar "cg_drawTeamOverlay"
+ cvarFloatList { "Off" 0 "All Teammates" 1 "Support Teammates" 2 "Nearby Teammates" 3 }
+ rect CONTENT_X (CONTENT_Y+(5*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Sort Team Overlay:"
+ cvar "cg_teamOverlaySortMode"
+ cvarFloatList { "None" 0 "Score" 1 "Weapon/Class" 2 }
+ rect CONTENT_X (CONTENT_Y+(6*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Show Gun:"
+ cvar "cg_drawGun"
+ rect CONTENT_X (CONTENT_Y+(7*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Show Speed:"
+ cvar "cg_drawspeed"
+ cvarFloatList { "No" 0 "Text" 1 "Graph" 2 "Text + Graph" 3 "Text No-Z" 5 "Graph No-Z" 6 "Text + Graph No-Z" 7 }
+ rect CONTENT_X (CONTENT_Y+(8*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Show FPS:"
+ cvar "cg_drawFPS"
+ rect CONTENT_X (CONTENT_Y+(9*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Show Timer:"
+ cvar "cg_drawTimer"
+ rect CONTENT_X (CONTENT_Y+(10*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name hud
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Show Demo State:"
+ cvar "cg_drawDemoState"
+ rect CONTENT_X (CONTENT_Y+(11*ELEM_H)) CONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx CONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+//////// CONTROLS
+
+ //Controls menu
+ itemDef
+ {
+ name controls
+ text "Look"
+ group optionsGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H+(0*SIDEBUTT_H)) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show controls;
+ show look
+ }
+ }
+
+//////// LOOK
+
+ itemDef
+ {
+ name look
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Lookup:"
+ cvar "+lookup"
+ rect SCONTENT_X (SCONTENT_Y+(0*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name look
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Look Down:"
+ cvar "+lookdown"
+ rect SCONTENT_X (SCONTENT_Y+(1*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name look
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Mouse Look:"
+ cvar "+mlook"
+ rect SCONTENT_X (SCONTENT_Y+(2*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name look
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Centerview:"
+ cvar "centerview"
+ rect SCONTENT_X (SCONTENT_Y+(3*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name look
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Free Look:"
+ cvar "cl_freelook"
+ rect SCONTENT_X (SCONTENT_Y+(4*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name look
+ group optionsGrp
+ type ITEM_TYPE_SLIDER
+ text "Mouse Sensitivity:"
+ cvarfloat "sensitivity" 5 1 30
+ rect SCONTENT_X (SCONTENT_Y+(5*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name look
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Invert Mouse:"
+ cvar "ui_mousePitch"
+ rect SCONTENT_X (SCONTENT_Y+(6*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript update ui_mousePitch
+ }
+ }
+
+ itemDef
+ {
+ name look
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Smooth Mouse:"
+ cvar "m_filter"
+ rect SCONTENT_X (SCONTENT_Y+(7*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name look
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Auto Wallwalk Pitching:"
+ cvar "cg_wwFollow"
+ rect SCONTENT_X (SCONTENT_Y+(8*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+//////// MOVE
+
+ itemDef
+ {
+ name controls
+ text "Move"
+ group optionsGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H+(1*SIDEBUTT_H)) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show controls;
+ show move
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Sprint Toggles:"
+ cvar "cg_sprintToggle"
+ rect SCONTENT_X (SCONTENT_Y+(0*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Wallwalk Control Toggles:"
+ cvar "cg_wwToggle"
+ rect SCONTENT_X (SCONTENT_Y+(1*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Wallwalking Speed:"
+ cvar "cg_wwSmoothTime"
+ cvarFloatList { "Medium" 300 "Fast" 150 "Instant" 0 "Slow" 600 }
+ rect SCONTENT_X (SCONTENT_Y+(2*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Run / Walk:"
+ cvar "+speed"
+ rect SCONTENT_X (SCONTENT_Y+(3*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Dodge:"
+ cvar "+button6"
+ rect SCONTENT_X (SCONTENT_Y+(4*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Sprint:"
+ cvar "+button8"
+ rect SCONTENT_X (SCONTENT_Y+(5*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Forward:"
+ cvar "+forward"
+ rect SCONTENT_X (SCONTENT_Y+(6*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Backpedal:"
+ cvar "+back"
+ rect SCONTENT_X (SCONTENT_Y+(7*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Move Left:"
+ cvar "+moveleft"
+ rect SCONTENT_X (SCONTENT_Y+(8*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Move Right:"
+ cvar "+moveright"
+ rect SCONTENT_X (SCONTENT_Y+(9*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Jump:"
+ cvar "+moveup"
+ rect SCONTENT_X (SCONTENT_Y+(10*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Crouch:"
+ cvar "+movedown"
+ rect SCONTENT_X (SCONTENT_Y+(11*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Turn Left:"
+ cvar "+left"
+ rect SCONTENT_X (SCONTENT_Y+(12*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Turn Right:"
+ cvar "+right"
+ rect SCONTENT_X (SCONTENT_Y+(13*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name move
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Strafe:"
+ cvar "+strafe"
+ rect SCONTENT_X (SCONTENT_Y+(14*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+
+
+//////// UPGRADES
+
+ itemDef
+ {
+ name controls
+ text "Upgrades"
+ group optionsGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H+(2*SIDEBUTT_H)) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show controls;
+ show upgrades
+ }
+ }
+
+ itemDef
+ {
+ name upgrades
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Primary Attack:"
+ cvar "+attack"
+ rect SCONTENT_X (SCONTENT_Y+(0*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name upgrades
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Secondary Attack:"
+ cvar "+button5"
+ rect SCONTENT_X (SCONTENT_Y+(1*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name upgrades
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Previous Upgrade:"
+ cvar "weapprev"
+ rect SCONTENT_X (SCONTENT_Y+(2*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name upgrades
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Next Upgrade:"
+ cvar "weapnext"
+ rect SCONTENT_X (SCONTENT_Y+(3*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name upgrades
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Activate Upgrade:"
+ cvar "+button2"
+ rect SCONTENT_X (SCONTENT_Y+(4*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name upgrades
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Reload:"
+ cvar "reload"
+ rect SCONTENT_X (SCONTENT_Y+(5*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name upgrades
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Buy Ammo:"
+ cvar "buy ammo"
+ rect SCONTENT_X (SCONTENT_Y+(6*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name upgrades
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Use Medkit:"
+ cvar "itemact medkit"
+ rect SCONTENT_X (SCONTENT_Y+(7*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+//////// MISC
+
+ itemDef
+ {
+ name controls
+ text "Misc"
+ group optionsGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H+(3*SIDEBUTT_H)) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show controls;
+ show misc
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Show Scores:"
+ cvar "+scores"
+ rect SCONTENT_X (SCONTENT_Y+(0*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Scroll Scores Up:"
+ cvar "scoresUp"
+ rect SCONTENT_X (SCONTENT_Y+(1*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Scroll Scores Down:"
+ cvar "scoresDown"
+ rect SCONTENT_X (SCONTENT_Y+(2*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Use Structure/Evolve:"
+ cvar "+button7"
+ rect SCONTENT_X (SCONTENT_Y+(3*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Deconstruct Structure:"
+ cvar "deconstruct"
+ rect SCONTENT_X (SCONTENT_Y+(4*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Gesture:"
+ cvar "+button3"
+ rect SCONTENT_X (SCONTENT_Y+(5*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Chat:"
+ cvar "messagemode"
+ rect SCONTENT_X (SCONTENT_Y+(6*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Team Chat:"
+ cvar "messagemode2"
+ rect SCONTENT_X (SCONTENT_Y+(7*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Vote Yes:"
+ cvar "vote yes"
+ rect SCONTENT_X (SCONTENT_Y+(8*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Vote No:"
+ cvar "vote no"
+ rect SCONTENT_X (SCONTENT_Y+(9*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Team Vote Yes:"
+ cvar "teamvote yes"
+ rect SCONTENT_X (SCONTENT_Y+(10*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Team Vote No:"
+ cvar "teamvote no"
+ rect SCONTENT_X (SCONTENT_Y+(11*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Screenshot:"
+ cvar "screenshotJPEG"
+ rect SCONTENT_X (SCONTENT_Y+(12*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name misc
+ group optionsGrp
+ type ITEM_TYPE_BIND
+ text "Ready To Play:"
+ cvar "ready"
+ rect SCONTENT_X (SCONTENT_Y+(13*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+//////// SYSTEM
+
+ //System menu
+ itemDef
+ {
+ name system
+ text "GFX Hardware"
+ group optionsGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H+(0*SIDEBUTT_H)) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show system;
+ show ghardware
+ }
+ }
+
+//////// GFX HARDWARE
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Quality:"
+ cvar "ui_glCustom"
+ cvarFloatList { "High Quality" 0 "Normal" 1 "Fast" 2 "Fastest" 3 "Custom" 4 }
+ rect SCONTENT_X (SCONTENT_Y+(0*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript update "ui_glCustom"
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "GL Extensions:"
+ cvar "r_allowExtensions"
+ rect SCONTENT_X (SCONTENT_Y+(1*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript glCuston
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_TEXT
+ text "Video Mode:"
+ rect SCONTENT_X (SCONTENT_Y+(2*ELEM_H)) (SCONTENT_W/2) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ rect (SCONTENT_X+(SCONTENT_W/2)+RESCOMBO_OFF) (SCONTENT_Y+(2*ELEM_H)) ((SCONTENT_W/2)-(2*RESCOMBO_OFF)) ELEM_H
+ type ITEM_TYPE_COMBOBOX
+ style WINDOW_STYLE_FILLED
+ elementwidth ((SCONTENT_W/2)-(2*BORDER))
+ elementheight ELEM_H
+ dropitems 5
+ textscale .25
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_RESOLUTIONS
+ border WINDOW_BORDER_FULL
+ borderColor 0.5 0.5 0.5 1
+ forecolor 1 1 1 1
+ backcolor 0 0 0 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Color Depth:"
+ cvar "r_colorbits"
+ cvarFloatList { "Default" 0 "16 bit" 16 "32 bit" 32 }
+ rect SCONTENT_X (SCONTENT_Y+(3*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript glCustom;
+ uiScript update "r_colorbits"
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Fullscreen:"
+ cvar "r_fullscreen"
+ rect SCONTENT_X (SCONTENT_Y+(4*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript glCustom
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Lighting:"
+ cvar "r_vertexlight"
+ cvarFloatList { "Light Map (high)" 0 "Vertex (low)" 1 }
+ rect SCONTENT_X (SCONTENT_Y+(5*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript glCustom
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Geometric Detail:"
+ cvar "r_lodbias"
+ cvarFloatList { "High" 0 "Medium" 1 "Low" 2 }
+ rect SCONTENT_X (SCONTENT_Y+(6*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript glCustom;
+ uiScript update "r_lodbias"
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Texture Detail:"
+ cvar "r_picmip"
+ cvarFloatList { "Low" 2 "Normal" 1 "High" 0 }
+ rect SCONTENT_X (SCONTENT_Y+(7*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript glCustom
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Texture Quality:"
+ cvar "r_texturebits"
+ cvarFloatList { "Default" 0 "16 bit" 16 "32 bit" 32 }
+ rect SCONTENT_X (SCONTENT_Y+(8*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Texture Filter:"
+ cvar "r_texturemode"
+ cvarStrList { "Bilinear", "GL_LINEAR_MIPMAP_NEAREST", "Trilinear", "GL_LINEAR_MIPMAP_LINEAR" }
+ rect SCONTENT_X (SCONTENT_Y+(9*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript glCustom
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Anisotropic Filtering:"
+ cvar "r_ext_texture_filter_anisotropic"
+ rect SCONTENT_X (SCONTENT_Y+(10*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript glCustom
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Compress Textures:"
+ cvar "r_ext_compressed_textures "
+ rect SCONTENT_X (SCONTENT_Y+(11*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript glCustom
+ }
+ }
+
+ itemDef
+ {
+ name ghardware
+ group optionsGrp
+ type ITEM_TYPE_BUTTON
+ text "APPLY"
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect SCONTENT_X (SCONTENT_Y+(13*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ exec "vid_restart"
+ }
+ }
+
+//////// GFX SOFTWARE
+
+ itemDef
+ {
+ name system
+ text "GFX Software"
+ group optionsGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H+(1*SIDEBUTT_H)) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show system;
+ show gsoftware
+ }
+ }
+
+ itemDef
+ {
+ name gsoftware
+ group optionsGrp
+ type ITEM_TYPE_SLIDER
+ text "Brightness:"
+ cvarfloat "r_gamma" 1 .5 2
+ rect SCONTENT_X (SCONTENT_Y+(0*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name gsoftware
+ group optionsGrp
+ type ITEM_TYPE_SLIDER
+ text "Screen Size:"
+ cvarfloat "cg_viewsize" 100 30 100
+ rect SCONTENT_X (SCONTENT_Y+(1*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name gsoftware
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Marks On Walls:"
+ cvar "cg_marks"
+ rect SCONTENT_X (SCONTENT_Y+(2*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name gsoftware
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Dynamic Lights:"
+ cvar "r_dynamiclight"
+ rect SCONTENT_X (SCONTENT_Y+(3*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name gsoftware
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Draw Gun:"
+ cvar "cg_drawGun"
+ rect SCONTENT_X (SCONTENT_Y+(4*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name gsoftware
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Low Quality Sky:"
+ cvar "r_fastsky"
+ rect SCONTENT_X (SCONTENT_Y+(5*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name gsoftware
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Sync Every Frame:"
+ cvar "r_finish"
+ rect SCONTENT_X (SCONTENT_Y+(6*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name gsoftware
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "In Game Videos:"
+ cvar "r_inGameVideo"
+ rect SCONTENT_X (SCONTENT_Y+(7*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name gsoftware
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Depth Sort Particles:"
+ cvar "cg_depthSortParticles"
+ rect SCONTENT_X (SCONTENT_Y+(8*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name gsoftware
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Particle Physics:"
+ cvar "cg_bounceParticles"
+ cvarFloatList { "Low Quality" 0 "High Quality" 1 }
+ rect SCONTENT_X (SCONTENT_Y+(9*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name gsoftware
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Light Flares:"
+ cvar "cg_lightFlare"
+ cvarFloatList { "Off" 0 "No Fade" 1 "Timed Fade" 2 "Real Fade" 3 }
+ rect SCONTENT_X (SCONTENT_Y+(10*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+//////// GL INFO
+
+ itemDef
+ {
+ name system
+ text "OpenGL Info"
+ group optionsGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H+(2*SIDEBUTT_H)) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show system;
+ show glinfo
+ }
+ }
+
+ itemDef
+ {
+ name glinfo
+ group optionsGrp
+ rect SCONTENT_X SCONTENT_Y SCONTENT_W (H-(SCONTENT_Y+BORDER))
+ ownerdraw UI_GLINFO
+ textscale .25
+ textalign ALIGN_LEFT
+ textvalign VALIGN_TOP
+ textalignx 4
+ textaligny 4
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ }
+
+//////// NET & SOUND
+
+ itemDef
+ {
+ name system
+ text "Net & Sound"
+ group optionsGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H+(3*SIDEBUTT_H)) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show system;
+ show netsound
+ }
+ }
+
+ itemDef
+ {
+ name netsound
+ group optionsGrp
+ style WINDOW_STYLE_FILLED
+ type ITEM_TYPE_TEXT
+ text "Sound"
+ rect SCONTENT_X (SCONTENT_Y+(0*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name netsound
+ group optionsGrp
+ type ITEM_TYPE_SLIDER
+ text "Effects Volume:"
+ cvarfloat "s_volume" 0.7 0 1
+ rect SCONTENT_X (SCONTENT_Y+(1*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name netsound
+ group optionsGrp
+ type ITEM_TYPE_SLIDER
+ text "Music Volume:"
+ cvarfloat "s_musicvolume" 0.25 0 1
+ rect SCONTENT_X (SCONTENT_Y+(2*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name netsound
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "OpenAL:"
+ cvar "s_useOpenAL"
+ rect SCONTENT_X (SCONTENT_Y+(3*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name netsound
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Sound Quality:"
+ cvar "s_khz"
+ cvarFloatList { "44 khz (very high)" 44 "22 khz (high)" 22 "11 khz (low)" 11 }
+ rect SCONTENT_X (SCONTENT_Y+(4*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name netsound
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Doppler Sound:"
+ cvar "s_doppler"
+ rect SCONTENT_X (SCONTENT_Y+(5*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name netsound
+ group optionsGrp
+ style WINDOW_STYLE_FILLED
+ type ITEM_TYPE_TEXT
+ text "Network"
+ rect SCONTENT_X (SCONTENT_Y+(7*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ decoration
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name netsound
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Net Data Rate:"
+ cvar "rate"
+ cvarFloatList { "<=28.8k" 2500 "33.6k" 3000 "56k" 4000 "ISDN" 5000 "LAN/CABLE/xDSl" 25000 }
+ rect SCONTENT_X (SCONTENT_Y+(8*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name netsound
+ group optionsGrp
+ type ITEM_TYPE_BUTTON
+ text "APPLY"
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect SCONTENT_X (SCONTENT_Y+(10*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ exec "snd_restart"
+ }
+ }
+
+//////// RANGE MARKERS
+
+ itemDef
+ {
+ name system
+ text "Range Markers"
+ group optionsGrp
+ style WINDOW_STYLE_EMPTY
+ rect 0 ((2*BORDER)+TOPBUTT_H+(4*SIDEBUTT_H)) SIDEBUTT_W SIDEBUTT_H
+ type ITEM_TYPE_BUTTON
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ hide optionsGrp;
+ show system;
+ show rangemarkers
+ }
+ }
+
+ itemDef
+ {
+ name rangemarkers
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Draw Surface:"
+ cvar "cg_rangeMarkerDrawSurface"
+ rect SCONTENT_X (SCONTENT_Y+(0*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name rangemarkers
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Draw Intersection:"
+ cvar "cg_rangeMarkerDrawIntersection"
+ rect SCONTENT_X (SCONTENT_Y+(1*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name rangemarkers
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Draw Frontline:"
+ cvar "cg_rangeMarkerDrawFrontline"
+ rect SCONTENT_X (SCONTENT_Y+(2*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name rangemarkers
+ group optionsGrp
+ type ITEM_TYPE_SLIDER
+ text "Surface Opacity:"
+ cvarfloat "cg_rangeMarkerSurfaceOpacity" 0.08 0.035 0.3
+ rect SCONTENT_X (SCONTENT_Y+(3*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name rangemarkers
+ group optionsGrp
+ type ITEM_TYPE_SLIDER
+ text "Line Opacity:"
+ cvarfloat "cg_rangeMarkerLineOpacity" 0.4 0.075 1
+ rect SCONTENT_X (SCONTENT_Y+(4*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name rangemarkers
+ group optionsGrp
+ type ITEM_TYPE_SLIDER
+ text "Line Thickness:"
+ cvarfloat "cg_rangeMarkerLineThickness" 4.0 1 11
+ rect SCONTENT_X (SCONTENT_Y+(5*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ }
+
+ itemDef
+ {
+ name rangemarkers
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Range Marker for Blueprint:"
+ cvar "cg_rangeMarkerForBlueprint"
+ rect SCONTENT_X (SCONTENT_Y+(6*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name rangemarkers
+ group optionsGrp
+ type ITEM_TYPE_MULTI
+ text "Range Markers for:"
+ cvar "cg_rangeMarkerBuildableTypes"
+ cvarStrList { "No Buildables", "",
+ "All Buildables", "all",
+ "Support Buildables", "support",
+ "Offensive Buildables", "offensive",
+ "Alien Buildables", "alien",
+ "Human Buildables", "human",
+ "Alien Support Buildables", "aliensupport",
+ "Human Support Buildables", "humansupport",
+ "Offensive Alien Buildables", "alienoffensive",
+ "Offensive Human Buildables", "humanoffensive" }
+ rect SCONTENT_X (SCONTENT_Y+(7*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name rangemarkers
+ group optionsGrp
+ type ITEM_TYPE_SLIDER
+ text "Binary Shader Screen Scale:"
+ cvarfloat "cg_binaryShaderScreenScale" 1.0 0 1
+ rect SCONTENT_X (SCONTENT_Y+(8*ELEM_H)) SCONTENT_W ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx SCONTENT_OFF
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ }
+ }
+}
diff --git a/assets/ui/install_update.menu b/assets/ui/install_update.menu
new file mode 100644
index 0000000..8c81133
--- /dev/null
+++ b/assets/ui/install_update.menu
@@ -0,0 +1,145 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 450
+#define H 300
+#define BORDER 10
+
+#define LIST_W 140
+#define LIST_H (H-(2*BORDER))
+#define LIST_X BORDER
+#define LIST_Y BORDER
+
+#define BUTT_H 25
+#define BUTT_W 45
+
+#define INFO_W (W-((2*BORDER)+LIST_W))
+#define INFO_H (H-((3*BORDER)+BUTT_H))
+#define INFO_X BORDER
+#define INFO_Y BORDER
+#define INFO_TOFF 6
+
+#define AU_ACT_NIL 0
+#define AU_ACT_GET 1
+#define AU_ACT_RUN 2
+
+ menuDef
+ {
+ name "install_update"
+ visible MENU_TRUE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ popup
+ onOpen
+ {
+ uiScript checkForUpdate;
+ }
+ onESC
+ {
+ play "sound/misc/menu1.wav";
+ close install_update
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 .75
+ visible MENU_TRUE
+ decoration
+ border WINDOW_BORDER_KCGRADIENT
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+
+ itemDef
+ {
+ name github_release
+ rect 10 10 (W-10) (INFO_H-10)
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 16
+ textscale .33
+ border WINDOW_BORDER_NONE
+ bordersize 1
+ bordercolor .5 .5 .5 1
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_GITHUB_RELEASE
+ notselectable
+ visible MENU_TRUE
+ }
+
+// itemDef
+// {
+// name OKCancel
+// text "Download"
+// type ITEM_TYPE_BUTTON
+// style WINDOW_STYLE_EMPTY
+// rect (W-((2*BORDER)+(2*BUTT_W))) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+// textalign ALIGN_CENTER
+// textvalign VALIGN_CENTER
+// textscale .4
+// forecolor 1 1 1 1
+// backcolor .5 0 0 .25
+// visible MENU_TRUE
+// cvarTest "ui_autoupdate_action"
+// showCvar { AU_ACT_GET }
+// action
+// {
+// play "sound/misc/menu1.wav";
+// uiScript DownloadUpdate;
+// close install_update
+// }
+// }
+//
+// itemDef
+// {
+// name OKCancel
+// text "Install"
+// type ITEM_TYPE_BUTTON
+// style WINDOW_STYLE_EMPTY
+// rect (W-((2*BORDER)+(2*BUTT_W))) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+// textalign ALIGN_CENTER
+// textvalign VALIGN_CENTER
+// textscale .4
+// forecolor 1 1 1 1
+// backcolor .5 0 0 .25
+// visible MENU_TRUE
+// cvarTest "ui_autoupdate_action"
+// showCvar { AU_ACT_RUN }
+// action
+// {
+// play "sound/misc/menu1.wav";
+// uiScript InstallUpdate;
+// close install_update
+// }
+// }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "Ok"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ close install_update
+ }
+ }
+ }
+}
diff --git a/assets/ui/joinserver.menu b/assets/ui/joinserver.menu
new file mode 100644
index 0000000..ad3e04d
--- /dev/null
+++ b/assets/ui/joinserver.menu
@@ -0,0 +1,769 @@
+#include "ui/menudef.h"
+
+{
+
+ \\ Server Join \\
+
+#define W 640
+#define H 480
+#define BORDER 10
+
+#define PREVIEW_W 112
+#define PREVIEW_H 84
+#define TOP_W (W-((2*BORDER)+PREVIEW_W))
+#define TOP_H PREVIEW_H
+#define TOP_X BORDER
+#define TOP_Y BORDER
+#define TOPBUTT_W (TOP_W/3)
+#define TOPBUTT_H (TOP_H/2)
+#define TOP_TOFF_X 20
+#define TOP_TOFF_Y 0
+
+#define BCJ_W (W-(2*BORDER))
+#define BCJ_H 50
+#define BCJ_X BORDER
+#define BCJ_Y (H-(BCJ_H+BORDER))
+#define ARROW_W 50
+#define ARROW_H BCJ_H
+
+#define BOT_W (W-(2*BORDER))
+#define BOT_H 45
+#define BOT_X BORDER
+#define BOT_Y (BCJ_Y-BOT_H)
+#define BOTBUTT_W (BOT_W/5)
+#define BOTBUTT_H BOT_H
+
+#define SERVER_C 0.45
+#define GAME_C 0.15
+#define MAP_C 0.2
+#define PLAYERS_C 0.1
+#define PING_C 0.1
+#define LIST_W (W-(2*BORDER))
+#define LIST_H (H-((3*BORDER)+TOP_H+BOT_H+BCJ_H))
+#define LIST_X BORDER
+#define LIST_Y ((2*BORDER)+TOP_H)
+#define LIST_TOFF 5
+#define HEADFOOT_H 25
+
+ menuDef
+ {
+ name "joinserver"
+ visible MENU_FALSE
+ fullscreen MENU_TRUE
+ rect 0 0 W H
+ focusColor 1 .75 0 1
+ outOfBoundsClick
+ style WINDOW_STYLE_EMPTY
+ aspectBias ASPECT_NONE
+ onOpen
+ {
+ uiScript InitServerList 3;
+ hide accept_alt;
+ show accept;
+ hide back_alt;
+ show back;
+ uiScript UpdateFilter
+ }
+
+ onEsc { uiScript closeJoin }
+
+ itemDef
+ {
+ name background
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+ }
+
+
+ // VIEW OPTIONS //
+
+ itemDef
+ {
+ name gametypefield
+ text "Source:"
+ style WINDOW_STYLE_EMPTY
+ ownerdraw UI_NETSOURCE
+ rect TOP_X TOP_Y TOPBUTT_W TOPBUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx TOP_TOFF_X
+ textaligny TOP_TOFF_Y
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 .5 .5 .5
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav"
+ }
+ }
+
+ // BUTTONS //
+
+ itemDef
+ {
+ name refreshSource
+ text "Get New List"
+ type ITEM_TYPE_BUTTON
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ rect (TOP_X+TOPBUTT_W) TOP_Y TOPBUTT_W TOPBUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx TOP_TOFF_X
+ textaligny TOP_TOFF_Y
+ backcolor .5 .5 .5 .5
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript RefreshServers
+ }
+ }
+
+ itemDef
+ {
+ name refreshFilter
+ text "Refresh List"
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ type ITEM_TYPE_BUTTON
+ rect (TOP_X+(2*TOPBUTT_W)) TOP_Y TOPBUTT_W TOPBUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx TOP_TOFF_X
+ textaligny TOP_TOFF_Y
+ backcolor .5 .5 .5 .5
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript RefreshFilter
+ }
+ }
+
+ itemDef
+ {
+ name viewEmpty
+ style WINDOW_STYLE_EMPTY
+ type ITEM_TYPE_YESNO
+ text "View Empty:"
+ cvar "ui_browserShowEmpty"
+ textscale .4
+ rect TOP_X (TOP_Y+TOPBUTT_H) TOPBUTT_W TOPBUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx TOP_TOFF_X
+ textaligny TOP_TOFF_Y
+ forecolor 1 1 1 1
+ backcolor .5 .5 .5 .5
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript RefreshFilter
+ }
+ }
+
+ itemDef
+ {
+ name viewFull
+ style WINDOW_STYLE_EMPTY
+ type ITEM_TYPE_YESNO
+ text "View Full:"
+ cvar "ui_browserShowFull"
+ textscale .4
+ rect (TOP_X+TOPBUTT_W) (TOP_Y+TOPBUTT_H) TOPBUTT_W TOPBUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx TOP_TOFF_X
+ textaligny TOP_TOFF_Y
+ forecolor 1 1 1 1
+ backcolor .5 .5 .5 .5
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript RefreshFilter
+ }
+ }
+
+ // LEGEND //
+
+ itemDef
+ {
+ name legend
+ type ITEM_TYPE_TEXT
+ text "[official] = Official Server\n[featured] = Featured Server"
+ style WINDOW_STYLE_EMPTY
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ textscale .25
+ wrapped
+ rect (TOP_X+(2*TOPBUTT_W)) (TOP_Y+TOPBUTT_H) (TOPBUTT_W) (TOPBUTT_H)
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx TOP_TOFF_X
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ // MAP PREVIEW //
+
+ itemDef
+ {
+ name mappreview
+ style WINDOW_STYLE_EMPTY
+ ownerdraw UI_NETMAPPREVIEW
+ rect (W-(PREVIEW_W+BORDER)) BORDER PREVIEW_W PREVIEW_H
+ border WINDOW_BORDER_FULL
+ bordercolor .5 .5 .5 1
+ visible MENU_TRUE
+ }
+
+
+ // COLUMNS //
+
+ itemDef
+ {
+ name server
+ group grpTabs
+ text "Server Name"
+ type ITEM_TYPE_BUTTON
+ textscale .33
+ style WINDOW_STYLE_FILLED
+ rect LIST_X LIST_Y (SERVER_C*LIST_W) HEADFOOT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx LIST_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 1
+ forecolor 1 1 1 1
+ backcolor 0 0 0 0
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript ServerSort 0;
+
+ setitemcolor grpColumn backcolor 0 0 0 0;
+ setitemcolor grpTabs backcolor 0 0 0 0;
+ setitemcolor server backcolor 0.3 1 1 0.3;
+ setitemcolor serverColumn backcolor 0.2 0.6 0.6 0.1;
+ }
+ }
+
+ itemDef
+ {
+ name serverColumn
+ group grpColumn
+ rect LIST_X (LIST_Y+HEADFOOT_H) (SERVER_C*LIST_W) (LIST_H-(2*HEADFOOT_H))
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ backcolor 0 0 0 0
+ bordersize 1
+ bordercolor .5 .5 .5 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name game
+ group grpTabs
+ type ITEM_TYPE_BUTTON
+ text "Game Type"
+ textscale .33
+ style WINDOW_STYLE_FILLED
+ rect (LIST_X+(SERVER_C*LIST_W)) LIST_Y (GAME_C*LIST_W) HEADFOOT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx LIST_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 1
+ forecolor 1 1 1 1
+ backcolor 0 0 0 0
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript ServerSort 1;
+
+ setitemcolor grpColumn backcolor 0 0 0 0;
+ setitemcolor grpTabs backcolor 0 0 0 0;
+ setitemcolor game backcolor 0.3 1 1 0.3;
+ setitemcolor gameColumn backcolor 0.2 0.6 0.6 0.1;
+ }
+ }
+
+ itemDef
+ {
+ name gameColumn
+ group grpColumn
+ rect (LIST_X+(SERVER_C*LIST_W)) (LIST_Y+HEADFOOT_H) (GAME_C*LIST_W) (LIST_H-(2*HEADFOOT_H))
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ backcolor 0 0 0 0
+ bordersize 1
+ bordercolor .5 .5 .5 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name map
+ group grpTabs
+ type ITEM_TYPE_BUTTON
+ text "Map Name"
+ textscale .33
+ style WINDOW_STYLE_FILLED
+ rect (LIST_X+((SERVER_C+GAME_C)*LIST_W)) LIST_Y (MAP_C*LIST_W) HEADFOOT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx LIST_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 1
+ forecolor 1 1 1 1
+ backcolor 0 0 0 0
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript ServerSort 2;
+
+ setitemcolor grpColumn backcolor 0 0 0 0;
+ setitemcolor grpTabs backcolor 0 0 0 0;
+ setitemcolor map backcolor 0.3 1 1 0.3;
+ setitemcolor mapColumn backcolor 0.2 0.6 0.6 0.1;
+ }
+ }
+
+ itemDef
+ {
+ name mapColumn
+ group grpColumn
+ rect (LIST_X+((SERVER_C+GAME_C)*LIST_W)) (LIST_Y+HEADFOOT_H) (MAP_C*LIST_W) (LIST_H-(2*HEADFOOT_H))
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ backcolor 0 0 0 0
+ bordersize 1
+ bordercolor .5 .5 .5 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name players
+ group grpTabs
+ text "Players"
+ type ITEM_TYPE_BUTTON
+ textscale .33
+ style WINDOW_STYLE_FILLED
+ rect (LIST_X+((SERVER_C+GAME_C+MAP_C)*LIST_W)) LIST_Y (PLAYERS_C*LIST_W) HEADFOOT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx LIST_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 1
+ forecolor 1 1 1 1
+ backcolor 0 0 0 0
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript ServerSort 3;
+
+ setitemcolor grpColumn backcolor 0 0 0 0;
+ setitemcolor grpTabs backcolor 0 0 0 0;
+ setitemcolor players backcolor 0.3 1 1 0.3;
+ setitemcolor playerColumn backcolor 0.2 0.6 0.6 0.1;
+ }
+ }
+
+ itemDef
+ {
+ name playerColumn
+ group grpColumn
+ rect (LIST_X+((SERVER_C+GAME_C+MAP_C)*LIST_W)) (LIST_Y+HEADFOOT_H) (PLAYERS_C*LIST_W) (LIST_H-(2*HEADFOOT_H))
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ backcolor 0 0 0 0
+ bordersize 1
+ bordercolor .5 .5 .5 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name Ping
+ group grpTabs
+ text "Ping"
+ type ITEM_TYPE_BUTTON
+ textscale .33
+ style WINDOW_STYLE_FILLED
+ rect (LIST_X+((SERVER_C+GAME_C+MAP_C+PLAYERS_C)*LIST_W)) LIST_Y (PING_C*LIST_W) HEADFOOT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx LIST_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 1
+ forecolor 1 1 1 1
+ backcolor 0.3 1 1 0.3
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript ServerSort 4;
+
+ setitemcolor grpColumn backcolor 0 0 0 0;
+ setitemcolor grpTabs backcolor 0 0 0 0;
+ setitemcolor ping backcolor 0.3 1 1 0.3;
+ setitemcolor pingColumn backcolor 0.2 0.6 0.6 0.1;
+ }
+ }
+
+ itemDef
+ {
+ name pingColumn
+ group grpColumn
+ rect (LIST_X+((SERVER_C+GAME_C+MAP_C+PLAYERS_C)*LIST_W)) (LIST_Y+HEADFOOT_H) (PING_C*LIST_W) (LIST_H-(2*HEADFOOT_H))
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ backcolor 0.2 0.6 0.6 0.1
+ bordersize 1
+ bordercolor .5 .5 .5 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ // SERVER LIST //
+
+ itemDef
+ {
+ name serverlist
+ rect LIST_X (LIST_Y+HEADFOOT_H) LIST_W (LIST_H-(2*HEADFOOT_H))
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_SERVERS
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 1
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.3 0.3 0.4
+ visible MENU_TRUE
+ columns 5
+ LIST_TOFF ((SERVER_C*LIST_W)-(3*LIST_TOFF)) ALIGN_LEFT
+ (LIST_TOFF+((SERVER_C)*LIST_W)) ((GAME_C*LIST_W)-(3*LIST_TOFF)) ALIGN_LEFT
+ (LIST_TOFF+((SERVER_C+GAME_C)*LIST_W)) ((MAP_C*LIST_W)-(3*LIST_TOFF)) ALIGN_LEFT
+ (LIST_TOFF+((SERVER_C+GAME_C+MAP_C)*LIST_W)) ((PLAYERS_C*LIST_W)-(3*LIST_TOFF)) ALIGN_LEFT
+ (LIST_TOFF+((SERVER_C+GAME_C+MAP_C+PLAYERS_C)*LIST_W)) ((PING_C*LIST_W)-(3*LIST_TOFF)) ALIGN_LEFT
+
+ doubleClick { uiScript JoinServer }
+ }
+
+
+ // DATE AND MESSAGE OF THE DAY //
+
+ itemDef
+ {
+ name refreshdate
+ ownerdraw UI_SERVERREFRESHDATE
+ textscale .33
+ rect LIST_X (LIST_Y+(LIST_H-HEADFOOT_H)) (LIST_W/2) HEADFOOT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx LIST_TOFF
+ forecolor 1 1 1 1
+ border WINDOW_BORDER_FULL
+ bordercolor .5 .5 .5 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name messageoftheday
+ ownerdraw UI_SERVERMOTD
+ textscale .33
+ rect (LIST_X+(LIST_W/2)) (LIST_Y+(LIST_H-HEADFOOT_H)) (LIST_W/2) HEADFOOT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx LIST_TOFF
+ forecolor 1 1 1 1
+ border WINDOW_BORDER_FULL
+ bordercolor .5 .5 .5 1
+ visible MENU_TRUE
+ decoration
+ }
+
+
+ // BOTTOM BUTTONS //
+
+ itemDef
+ {
+ name password
+ text "Set Password"
+ type ITEM_TYPE_BUTTON
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ rect BOT_X BOT_Y BOTBUTT_W BOTBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open password_popmenu
+ }
+ }
+
+ itemDef
+ {
+ name createFavorite
+ text "Create Favorite"
+ type ITEM_TYPE_BUTTON
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ rect (BOT_X+BOTBUTT_W) BOT_Y BOTBUTT_W BOTBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open createfavorite_popmenu
+ }
+ }
+
+ itemDef
+ {
+ name addFavorite
+ text "Add Favorite"
+ type ITEM_TYPE_BUTTON
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ ownerdrawFlag UI_SHOW_NOTFAVORITESERVERS
+ rect (BOT_X+(2*BOTBUTT_W)) BOT_Y BOTBUTT_W BOTBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript addFavorite
+ }
+ }
+
+ itemDef
+ {
+ name delfavorite
+ text "Delete Favorite"
+ type ITEM_TYPE_BUTTON
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ ownerdrawFlag UI_SHOW_FAVORITESERVERS
+ rect (BOT_X+(2*BOTBUTT_W)) BOT_Y BOTBUTT_W BOTBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript DeleteFavorite;
+ uiScript UpdateFilter
+ }
+ }
+
+ itemDef
+ {
+ name serverinfo
+ text "Server Info"
+ type ITEM_TYPE_BUTTON
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ rect (BOT_X+(3*BOTBUTT_W)) BOT_Y BOTBUTT_W BOTBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open serverinfo_popmenu
+ }
+ }
+
+ itemDef
+ {
+ name findplayer
+ text "Find a Friend"
+ type ITEM_TYPE_BUTTON
+ textscale .4
+ style WINDOW_STYLE_EMPTY
+ rect (BOT_X+(4*BOTBUTT_W)) BOT_Y BOTBUTT_W BOTBUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open findplayer_popmenu
+ }
+ }
+
+
+
+ // BACK CREATE JOIN //
+
+ itemDef
+ {
+ name createServer
+ text "Create Server"
+ textscale .5
+ style WINDOW_STYLE_EMPTY
+ type ITEM_TYPE_BUTTON
+ rect (BCJ_X+ARROW_W) BCJ_Y (BCJ_W-(2*ARROW_W)) BCJ_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open createserver
+ }
+ }
+
+
+ itemDef
+ {
+ name back
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/backarrow.tga"
+ rect BCJ_X BCJ_Y ARROW_H ARROW_W
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu4.wav";
+ close joinserver
+ }
+
+ mouseEnter
+ {
+ hide back;
+ show back_alt
+ }
+ }
+
+ itemDef
+ {
+ name back_alt
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/backarrow_alt.tga"
+ rect BCJ_X BCJ_Y ARROW_H ARROW_W
+ aspectBias ALIGN_LEFT
+ backcolor 0 0 0 0
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+ type ITEM_TYPE_BUTTON
+
+ text "Back"
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx ARROW_W
+ textscale .6
+
+ mouseExit
+ {
+ hide back_alt;
+ show back
+ }
+
+ action
+ {
+ play "sound/misc/menu4.wav";
+ close joinserver
+ }
+ }
+
+
+
+
+ itemDef
+ {
+ name accept
+ style WINDOW_STYLE_SHADER
+ rect ((BCJ_X+BCJ_W)-ARROW_W) BCJ_Y ARROW_H ARROW_W
+ aspectBias ALIGN_RIGHT
+ background "ui/assets/forwardarrow.tga"
+ backcolor 0 0 0 0
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ mouseEnter
+ {
+ hide accept;
+ show accept_alt
+ }
+
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript JoinServer
+ }
+ }
+
+ itemDef
+ {
+ name accept_alt
+ style WINDOW_STYLE_SHADER
+ rect ((BCJ_X+BCJ_W)-ARROW_W) BCJ_Y ARROW_H ARROW_W
+ aspectBias ALIGN_RIGHT
+ background "ui/assets/forwardarrow_alt.tga"
+ backcolor 0 0 0 0
+ type ITEM_TYPE_BUTTON
+ forecolor 1 1 1 1
+ visible MENU_FALSE
+
+ text "Join"
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx -ARROW_W
+ textscale .6
+
+ mouseExit
+ {
+ hide accept_alt;
+ show accept
+ }
+
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript JoinServer
+ }
+ }
+ }
+}
diff --git a/assets/ui/loading.menu b/assets/ui/loading.menu
new file mode 100644
index 0000000..b877ce9
--- /dev/null
+++ b/assets/ui/loading.menu
@@ -0,0 +1,223 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 640
+#define H 480
+#define BORDER 10
+
+#define SHOT_W 320
+#define SHOT_H 240
+#define SHOT_X (W-(BORDER+SHOT_W))
+#define SHOT_Y BORDER
+
+#define INFO_X BORDER
+#define INFO_W (W-((3*BORDER)+SHOT_W))
+#define LEVEL_Y BORDER
+#define LEVEL_H 30
+#define HOST_Y (LEVEL_H+(2*BORDER))
+#define HOST_H 30
+#define MOTD_Y (LEVEL_H+HOST_H+(3*BORDER))
+#define MOTD_H ((BORDER+SHOT_H)-MOTD_Y)
+
+#define MAIN_W (W-(2*BORDER))
+#define LABEL_W 180
+#define LABEL_X (W-(LABEL_W+BORDER))
+#define BAR_H ((H-((6*BORDER)+SHOT_H))/4)
+#define BAR_W (MAIN_W-(LABEL_W+BORDER))
+#define BAR_X BORDER
+#define MEDIA_Y (H-((4*BORDER)+(4*BAR_H)))
+#define BUILD_Y (H-((3*BORDER)+(3*BAR_H)))
+#define CHAR_Y (H-((2*BORDER)+(2*BAR_H)))
+#define OVER_Y (H-(BORDER+BAR_H))
+
+ assetGlobalDef
+ {
+ cursor "ui/assets/3_cursor3" // cursor
+ gradientBar "ui/assets/gradientbar2.tga" // gradient bar
+ fadeClamp 1.0 // sets the fadeup alpha
+ fadeCycle 1 // how often fade happens in milliseconds
+ fadeAmount 0.1 // amount to adjust alpha per cycle
+
+ shadowX 5 // x amount for shadow offset
+ shadowY 5 // y amount for shadow offset
+ shadowColor 0.1 0.1 0.1 0.25 // shadow color
+
+ font "fonts/font" 26 // font
+ smallFont "fonts/smallfont" 20 // font
+ bigFont "fonts/bigfont" 34 // font
+ }
+
+ menuDef
+ {
+ name "Loading"
+ rect 0 0 W H
+ fullScreen MENU_TRUE
+ aspectBias ASPECT_NONE
+
+ itemDef
+ {
+ name background
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name "levelname"
+ rect INFO_X LEVEL_Y INFO_W LEVEL_H
+ visible MENU_TRUE
+ decoration
+ forecolor 1 1 1 1
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ textscale 0.4
+ ownerdraw CG_LOAD_LEVELNAME
+ }
+
+ itemDef
+ {
+ name "hostname"
+ rect INFO_X HOST_Y INFO_W HOST_H
+ visible MENU_TRUE
+ decoration
+ forecolor 1 1 1 1
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ textscale 0.4
+ ownerdraw CG_LOAD_HOSTNAME
+ }
+
+ itemDef
+ {
+ name "motd"
+ rect INFO_X MOTD_Y INFO_W MOTD_H
+ visible MENU_TRUE
+ decoration
+ forecolor 1 1 1 1
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ textscale 0.4
+ ownerdraw CG_LOAD_MOTD
+ }
+
+ itemDef
+ {
+ name "levelshot"
+ rect SHOT_X SHOT_Y SHOT_W SHOT_H
+ visible MENU_TRUE
+ decoration
+ forecolor 1 1 1 1
+ ownerdraw CG_LOAD_LEVELSHOT
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name "media"
+ rect BAR_X MEDIA_Y BAR_W BAR_H
+ visible MENU_TRUE
+ decoration
+ forecolor 0.0 0.8 1 1
+ ownerdraw CG_LOAD_MEDIA
+ textalign ALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_NEON
+ textscale 0.5
+ borderSize 1.0
+ }
+
+ itemDef
+ {
+ name "medialabel"
+ style WINDOW_STYLE_EMPTY
+ textscale 0.6
+ rect LABEL_X MEDIA_Y LABEL_W BAR_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ forecolor 0.0 0.8 1 1
+ visible MENU_TRUE
+ decoration
+ ownerdraw CG_LOAD_MEDIA_LABEL
+ }
+
+ itemDef
+ {
+ name "buildables"
+ rect 20 340 380 30
+ rect BAR_X BUILD_Y BAR_W BAR_H
+ visible MENU_TRUE
+ decoration
+ forecolor 0.0 0.8 1 1
+ ownerdraw CG_LOAD_BUILDABLES
+ textalign ALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_NEON
+ textscale 0.5
+ borderSize 1.0
+ }
+
+ itemDef
+ {
+ name "buildableslabel"
+ style WINDOW_STYLE_EMPTY
+ textscale 0.6
+ rect LABEL_X BUILD_Y LABEL_W BAR_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ forecolor 0.0 0.8 1 1
+ visible MENU_TRUE
+ decoration
+ ownerdraw CG_LOAD_BUILDABLES_LABEL
+ }
+
+ itemDef
+ {
+ name "charmodel"
+ rect BAR_X CHAR_Y BAR_W BAR_H
+ visible MENU_TRUE
+ decoration
+ forecolor 0.0 0.8 1 1
+ ownerdraw CG_LOAD_CHARMODEL
+ textalign ALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_NEON
+ textscale 0.5
+ borderSize 1.0
+ }
+
+ itemDef
+ {
+ name "charmodellabel"
+ style WINDOW_STYLE_EMPTY
+ textscale 0.6
+ rect LABEL_X CHAR_Y LABEL_W BAR_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ forecolor 0.0 0.8 1 1
+ visible MENU_TRUE
+ decoration
+ ownerdraw CG_LOAD_CHARMODEL_LABEL
+ }
+
+ itemDef
+ {
+ name "overall"
+ rect BAR_X OVER_Y MAIN_W BAR_H
+ visible MENU_TRUE
+ decoration
+ forecolor 0.0 0.8 1 1
+ ownerdraw CG_LOAD_OVERALL
+ textalign ALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_NEON
+ textscale 0.5
+ borderSize 1.0
+ }
+ }
+}
diff --git a/assets/ui/main.menu b/assets/ui/main.menu
new file mode 100644
index 0000000..fddc0d9
--- /dev/null
+++ b/assets/ui/main.menu
@@ -0,0 +1,228 @@
+// vim:ft=menu
+#include "ui/menudef.h"
+#include "ui/menu_bool.h"
+
+{
+ assetGlobalDef
+ {
+ font "fonts/font" 26// font
+ smallFont "fonts/smallfont" 20// font
+ bigFont "fonts/bigfont" 34// font
+ cursor "ui/assets/3_cursor3" // cursor
+ gradientBar "ui/assets/gradientbar2.tga" // gradient bar
+ itemFocusSound "sound/misc/menu2.wav" // sound for item getting focus (via keyboard or mouse )
+
+ fadeClamp 1.0 // sets the fadeup alpha
+ fadeCycle 1 // how often fade happens in milliseconds
+ fadeAmount 0.1 // amount to adjust alpha per cycle
+
+ //shadowColor 0.1 0.1 0.1 0.25 // shadow color
+ shadowColor 0.1 0.1 0.1 0.80 // shadow color
+ }
+
+ menuDef
+ {
+ name main
+ fullscreen true
+ rect 0 0 640 480// Size and position of the menu
+ visible true // Visible on open
+ focuscolor 1 .75 0 1// Menu focus color for text and items
+ background "ui/assets/mainmenu.jpg"
+ aspectbias ASPECT_NONE
+
+ onOpen
+ {
+ uiScript stopRefresh
+ playlooped "sound/ui/heartbeat.wav"
+ }
+
+ onESC
+ {
+ open quit_popmenu
+ }
+
+ itemDef
+ {
+ name splashmodel
+ rect 0 0 640 480
+ type ITEM_TYPE_MODEL
+ style WINDOW_STYLE_EMPTY
+ asset_model "models/splash/splash_screen.md3"
+ model_fovx 32.0
+ model_fovy 24.0
+ model_angle 180
+ visible MENU_TRUE
+ decoration
+ }
+
+#define X (472)
+#define Y (20)
+#define W (128)
+#define ELEM_H (20)
+
+ itemDef
+ {
+ name mainmenu
+ text "Play"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ rect X Y W ELEM_H
+ textalign ALIGN_RIGHT
+ textscale .416
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open joinserver
+ }
+ }
+
+ itemDef
+ {
+ name mainmenu
+ text "News"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ textscale .416
+ rect X (Y+(1*ELEM_H)) W ELEM_H
+ textalign ALIGN_RIGHT
+ backcolor 0 0 0 0
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open news_menu
+ }
+ }
+
+ itemDef
+ {
+ name mainmenu
+ text "Options"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ textscale .416
+ rect X (Y+(2*ELEM_H)) W ELEM_H
+ textalign ALIGN_RIGHT
+ backcolor 0 0 0 0
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open simple_options
+ }
+ }
+
+ itemDef
+ {
+ name mainmenu
+ text "Demos"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ textscale .416
+ rect X (Y+(3*ELEM_H)) W ELEM_H
+ textalign ALIGN_RIGHT
+ backcolor 0 0 0 0
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open demo
+ }
+ }
+
+ itemDef
+ {
+ name browse_for_folders
+ text "Browse Folders"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ rect X (Y+(4*ELEM_H)) W ELEM_H
+ textscale .416
+ textalign ALIGN_RIGHT
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open browse_folders
+ }
+ }
+
+ itemDef
+ {
+ name check_for_updates
+ text "Check for Updates"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ rect X (Y+(5*ELEM_H)) W ELEM_H
+ textscale .416
+ textalign ALIGN_RIGHT
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open install_update
+ }
+ }
+
+ itemDef
+ {
+ name mainmenu
+ text "Quit"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ rect X (Y+(6*ELEM_H)) W ELEM_H
+ textscale .416
+ textalign ALIGN_RIGHT
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ open quit_popmenu
+ }
+ }
+
+ itemDef
+ {
+ name copyright
+ type ITEM_TYPE_TEXT
+ text "Copyright (C) 2015-2019 GrangerHub"
+ style WINDOW_STYLE_EMPTY
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ textscale .30
+ rect 0 405 640 30
+ textalign ALIGN_CENTER
+ forecolor .75 .75 .75 .75
+ visible MENU_TRUE
+ decoration
+ }
+ itemDef
+ {
+ name copyright
+ type ITEM_TYPE_TEXT
+ text "Copyright (C) 2005-2009 darklegion development"
+ style WINDOW_STYLE_EMPTY
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ textscale .30
+ rect 0 420 640 30
+ textalign ALIGN_CENTER
+ forecolor .75 .75 .75 .75
+ visible MENU_TRUE
+ decoration
+ }
+ }
+}
diff --git a/assets/ui/menu_bool.h b/assets/ui/menu_bool.h
new file mode 100644
index 0000000..38d1562
--- /dev/null
+++ b/assets/ui/menu_bool.h
@@ -0,0 +1,10 @@
+// Victor Roemer (wtfbbqhax), <victor@badsec.org>.
+#ifndef MENU_BOOL_H
+#define MENU_BOOL_H
+
+enum {
+ false,
+ true
+};
+
+#endif
diff --git a/assets/ui/menudef.h b/assets/ui/menudef.h
new file mode 100644
index 0000000..f83ba53
--- /dev/null
+++ b/assets/ui/menudef.h
@@ -0,0 +1,225 @@
+#ifndef MENUDEF_H
+#define MENUDEF_H
+
+enum
+{
+ ITEM_TYPE_ANY = -1, // invalid type
+ ITEM_TYPE_NONE, // no specified type
+ ITEM_TYPE_TEXT, // simple text
+ ITEM_TYPE_BUTTON, // button, basically text with a border
+ ITEM_TYPE_RADIOBUTTON, // toggle button, may be grouped
+ ITEM_TYPE_CHECKBOX, // check box
+ ITEM_TYPE_EDITFIELD, // editable text, associated with a cvar
+ ITEM_TYPE_SAYFIELD, // the chat field
+ ITEM_TYPE_CYCLE, // cycling list
+ ITEM_TYPE_LISTBOX, // scrollable list
+ ITEM_TYPE_COMBOBOX, // drop down scrollable list
+ ITEM_TYPE_MODEL, // model
+ ITEM_TYPE_OWNERDRAW, // owner draw, has an associated ownerdraw number
+ ITEM_TYPE_NUMERICFIELD, // editable text, associated with a cvar
+ ITEM_TYPE_SLIDER, // mouse speed, volume, etc.
+ ITEM_TYPE_YESNO, // boolean cvar setting
+ ITEM_TYPE_MULTI, // multiple list setting, enumerated
+ ITEM_TYPE_BIND // keyboard control configuration
+};
+
+#define ALIGN_LEFT 0 // left alignment
+#define ALIGN_CENTER 1 // center alignment
+#define ALIGN_RIGHT 2 // right alignment
+#define ASPECT_NONE 3 // no aspect compensation
+#define ALIGN_NONE 4
+
+enum
+{
+ VALIGN_BOTTOM, // bottom alignment
+ VALIGN_CENTER, // center alignment
+ VALIGN_TOP, // top alignment
+ VALIGN_NONE
+};
+
+enum
+{
+ ITEM_TEXTSTYLE_NORMAL, // normal text
+ ITEM_TEXTSTYLE_BLINK, // fast blinking
+ ITEM_TEXTSTYLE_PULSE, // slow pulsing
+ ITEM_TEXTSTYLE_SHADOWED, // drop shadow (need a color for this)
+ ITEM_TEXTSTYLE_OUTLINED, // apparently unimplemented
+ ITEM_TEXTSTYLE_OUTLINESHADOWED, // apparently unimplemented
+ ITEM_TEXTSTYLE_SHADOWEDMORE, // drop shadow (need a color for this)
+ ITEM_TEXTSTYLE_NEON // glow (need a color for this)
+};
+
+enum
+{
+ WINDOW_BORDER_NONE, // no border
+ WINDOW_BORDER_FULL, // full border based on border color (single pixel)
+ WINDOW_BORDER_HORZ, // horizontal borders only
+ WINDOW_BORDER_VERT, // vertical borders only
+ WINDOW_BORDER_KCGRADIENT // horizontal border using the gradient bars
+};
+
+enum
+{
+ WINDOW_STYLE_EMPTY, // no background
+ WINDOW_STYLE_FILLED, // filled with background color
+ WINDOW_STYLE_GRADIENT, // gradient bar based on background color
+ WINDOW_STYLE_SHADER, // use background shader
+ WINDOW_STYLE_TEAMCOLOR, // team color
+ WINDOW_STYLE_CINEMATIC // cinematic
+};
+
+#define MENU_TRUE 1 // uh.. true
+#define MENU_FALSE 0 // and false
+
+enum
+{
+ HUD_VERTICAL,
+ HUD_HORIZONTAL
+};
+
+// list box element types
+enum
+{
+ LISTBOX_TEXT,
+ LISTBOX_IMAGE
+};
+
+// list feeders
+enum
+{
+ FEEDER_SERVERS, // servers
+ FEEDER_MAPS, // all maps available, in graphic format
+ FEEDER_ALIENTEAM_LIST, // alien team members
+ FEEDER_HUMANTEAM_LIST, // human team members
+ FEEDER_TEAM_LIST, // team members for team voting
+ FEEDER_PLAYER_LIST, // players
+ FEEDER_NEWS, // news
+ FEEDER_MODS, // list of available mods
+ FEEDER_DEMOS, // list of available demo files
+ FEEDER_SERVERSTATUS, // server status
+ FEEDER_FINDPLAYER, // find player
+ FEEDER_CINEMATICS, // cinematics
+
+ FEEDER_TREMTEAMS, // teams
+ FEEDER_TREMALIENCLASSES, // alien classes
+ FEEDER_TREMHUMANITEMS, // human items
+ FEEDER_TREMHUMANARMOURYBUY, // human buy
+ FEEDER_TREMHUMANARMOURYSELL, // human sell
+ FEEDER_TREMALIENUPGRADE, // alien upgrade
+ FEEDER_TREMALIENBUILD, // alien buildables
+ FEEDER_TREMHUMANBUILD, // human buildables
+ FEEDER_IGNORE_LIST, // ignored players
+ FEEDER_HELP_LIST, // help topics
+ FEEDER_RESOLUTIONS, // display resolutions
+ FEEDER_TREMVOICECMD, // voice commands
+ FEEDER_GITHUB_RELEASE // latest update info
+};
+
+// display flags
+#define UI_SHOW_FAVORITESERVERS 0x00000001
+#define UI_SHOW_NOTFAVORITESERVERS 0x00000002
+
+#define UI_SHOW_VOTEACTIVE 0x00000004
+#define UI_SHOW_CANVOTE 0x00000008
+#define UI_SHOW_TEAMVOTEACTIVE 0x00000010
+#define UI_SHOW_CANTEAMVOTE 0x00000020
+
+#define UI_SHOW_NOTSPECTATING 0x00000040
+
+// owner draw types
+enum
+{
+ CG_PLAYER_HEALTH,
+ CG_PLAYER_HEALTH_CROSS,
+ CG_PLAYER_AMMO_VALUE,
+ CG_PLAYER_CLIPS_VALUE,
+ CG_PLAYER_BUILD_TIMER,
+ CG_PLAYER_CREDITS_VALUE,
+ CG_PLAYER_CREDITS_VALUE_NOPAD,
+ CG_PLAYER_STAMINA,
+ CG_PLAYER_STAMINA_1,
+ CG_PLAYER_STAMINA_2,
+ CG_PLAYER_STAMINA_3,
+ CG_PLAYER_STAMINA_4,
+ CG_PLAYER_STAMINA_BOLT,
+ CG_PLAYER_BOOST_BOLT,
+ CG_PLAYER_CLIPS_RING,
+ CG_PLAYER_BUILD_TIMER_RING,
+ CG_PLAYER_SELECT,
+ CG_PLAYER_SELECTTEXT,
+ CG_PLAYER_WEAPONICON,
+ CG_PLAYER_WALLCLIMBING,
+ CG_PLAYER_BOOSTED,
+ CG_PLAYER_POISON_BARBS,
+ CG_PLAYER_ALIEN_SENSE,
+ CG_PLAYER_HUMAN_SCANNER,
+ CG_PLAYER_USABLE_BUILDABLE,
+ CG_PLAYER_CHARGE_BAR_BG,
+ CG_PLAYER_CHARGE_BAR,
+ CG_PLAYER_CROSSHAIR,
+ CG_PLAYER_LOCATION,
+ CG_TEAMOVERLAY,
+ CG_PLAYER_CREDITS_FRACTION,
+
+ CG_KILLER,
+ CG_SPECTATORS,
+ CG_FOLLOW,
+
+// loading screen
+ CG_LOAD_LEVELSHOT,
+ CG_LOAD_MEDIA,
+ CG_LOAD_MEDIA_LABEL,
+ CG_LOAD_BUILDABLES,
+ CG_LOAD_BUILDABLES_LABEL,
+ CG_LOAD_CHARMODEL,
+ CG_LOAD_CHARMODEL_LABEL,
+ CG_LOAD_OVERALL,
+ CG_LOAD_LEVELNAME,
+ CG_LOAD_MOTD,
+ CG_LOAD_HOSTNAME,
+
+ CG_FPS,
+ CG_FPS_FIXED,
+ CG_TIMER,
+ CG_TIMER_MINS,
+ CG_TIMER_SECS,
+ CG_SNAPSHOT,
+ CG_LAGOMETER,
+ CG_SPEEDOMETER,
+ CG_PLAYER_CROSSHAIRNAMES,
+ CG_STAGE_REPORT_TEXT,
+ CG_ALIENS_SCORE_LABEL,
+ CG_HUMANS_SCORE_LABEL,
+ CG_DEMO_PLAYBACK,
+ CG_DEMO_RECORDING,
+
+ CG_CONSOLE,
+ CG_TUTORIAL,
+ CG_CLOCK,
+ CG_KILLFEED,
+ CG_PLAYER_THZ_SCANNER,
+
+ UI_NETSOURCE,
+ UI_NETMAPPREVIEW,
+ UI_NETMAPCINEMATIC,
+ UI_SERVERREFRESHDATE,
+ UI_SERVERMOTD,
+ UI_GLINFO,
+ UI_KEYBINDSTATUS,
+ UI_SELECTEDMAPPREVIEW,
+ UI_SELECTEDMAPNAME,
+
+ UI_TEAMINFOPANE,
+ UI_ACLASSINFOPANE,
+ UI_AUPGRADEINFOPANE,
+ UI_HITEMINFOPANE,
+ UI_HBUYINFOPANE,
+ UI_HSELLINFOPANE,
+ UI_ABUILDINFOPANE,
+ UI_HBUILDINFOPANE,
+ UI_HELPINFOPANE,
+
+ UI_VOICECMDINFOPANE
+};
+
+#endif
diff --git a/assets/ui/menus.txt b/assets/ui/menus.txt
new file mode 100644
index 0000000..067006c
--- /dev/null
+++ b/assets/ui/menus.txt
@@ -0,0 +1,24 @@
+// menu defs
+//
+{
+ loadMenu { "ui/main.menu" }
+ loadMenu { "ui/news.menu" }
+ loadMenu { "ui/joinserver.menu" }
+ loadMenu { "ui/options.menu" }
+ loadMenu { "ui/createserver.menu" }
+ loadMenu { "ui/mod.menu" }
+ loadMenu { "ui/demo_error.menu" }
+ loadMenu { "ui/demo.menu" }
+ loadMenu { "ui/connect.menu" }
+ loadMenu { "ui/password.menu" }
+ loadMenu { "ui/quit.menu" }
+ loadMenu { "ui/error.menu" }
+ loadMenu { "ui/download.menu" }
+ loadMenu { "ui/drop.menu" }
+ loadMenu { "ui/serverinfo.menu" }
+ loadMenu { "ui/findplayer.menu" }
+ loadMenu { "ui/quitcredit.menu" }
+ loadMenu { "ui/createfavorite.menu" }
+ loadMenu { "ui/install_update.menu" }
+ loadMenu { "ui/folders.menu" }
+}
diff --git a/assets/ui/mod.menu b/assets/ui/mod.menu
new file mode 100644
index 0000000..38bee62
--- /dev/null
+++ b/assets/ui/mod.menu
@@ -0,0 +1,108 @@
+#include "ui/menudef.h"
+
+{
+ \\ MOD \\
+
+#define W 300
+#define H 240
+#define BUTT_W 45
+#define BUTT_H 35
+#define BORDER 10
+
+ menuDef
+ {
+ name "mod"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onEsc
+ {
+ close mod
+ }
+ onOpen
+ {
+ uiScript loadMods
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name modlist
+ rect BORDER BORDER (W-(2*BORDER)) (H-(BUTT_H+BORDER))
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .25
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_MODS
+ textalign 3
+ textaligny 14
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ doubleClick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript RunMod
+ }
+ }
+
+ itemDef
+ {
+ name load
+ text "Load"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect (W-(2*BUTT_W)) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close mod;
+ uiScript RunMod
+ }
+ }
+
+ itemDef
+ {
+ name cancel
+ text "Cancel"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect (W-BUTT_W) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ close mod
+ }
+ }
+ }
+}
diff --git a/assets/ui/news.menu b/assets/ui/news.menu
new file mode 100644
index 0000000..99d8d68
--- /dev/null
+++ b/assets/ui/news.menu
@@ -0,0 +1,102 @@
+#include "ui/menudef.h"
+
+{
+ \\ NEWS POPUP MENU \\
+
+#define W 400
+#define H 400
+#define BUTT_W 45
+#define BUTT_H 35
+#define TITLE_H 35
+#define BORDER 10
+#define LIST_W (W-(2*BORDER))
+
+ menuDef
+ {
+ name "news_menu"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onClose { }
+ onOpen { uiScript getNews }
+ onESC
+ {
+ close news_menu
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name title
+ type ITEM_TYPE_TEXT
+ text "Tremulous News"
+ style WINDOW_STYLE_EMPTY
+ textscale .5
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ rect BORDER BORDER LIST_W TITLE_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ decoration
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name newslistbox
+ rect BORDER ((2*BORDER)+TITLE_H) LIST_W (H-((TITLE_H+BUTT_H)+(2*BORDER)))
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 16
+ textscale .25
+ border WINDOW_BORDER_FULL
+ bordersize 1
+ bordercolor .5 .5 .5 1
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_NEWS
+ notselectable
+ visible MENU_TRUE
+ }
+
+ // BUTTON //
+
+ itemDef
+ {
+ name close
+ text "Close"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect (W-BUTT_W) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close news_menu
+ }
+ }
+ }
+}
+
+
diff --git a/assets/ui/options.menu b/assets/ui/options.menu
new file mode 100644
index 0000000..6427f6c
--- /dev/null
+++ b/assets/ui/options.menu
@@ -0,0 +1,310 @@
+#include "ui/menudef.h"
+
+{
+ \\ FRONT END OPTIONS BOX \\
+
+#define X 0
+#define Y 20
+#define W 250
+#define H ((10*(ELEM_H+ELEM_GAP))+120)
+#define TOFF_X (0-(W/2))
+#define ELEM_H 16
+#define ELEM_GAP 4
+#define BUTT_W 35
+#define BUTT_H 35
+#define BORDER 10
+#define RESCOMBO_OFF 8
+
+ menuDef
+ {
+ name "simple_options"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onEsc
+ {
+ play "sound/misc/menu1.wav";
+ close simple_options
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+
+
+ itemDef
+ {
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Name:"
+ cvar "name"
+ maxchars 26
+ rect X Y W ELEM_H
+ textalign ALIGN_RIGHT
+ textalignx TOFF_X
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_MULTI
+ text "Renderer:"
+ cvar "cl_renderer"
+ cvarStrList { "OpenGL 1", "opengl1",
+ "OpenGL 2", "opengl2" }
+ rect X (Y+(ELEM_H+ELEM_GAP)) W ELEM_H
+ textalign ALIGN_RIGHT
+ textalignx TOFF_X
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ text "Video Mode:"
+ rect X (Y+(2*(ELEM_H+ELEM_GAP))) (W/2) ELEM_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ rect ((W/2)+RESCOMBO_OFF) (Y+(2*(ELEM_H+ELEM_GAP))) ((W/2)-(2*BORDER)) ELEM_H
+ type ITEM_TYPE_COMBOBOX
+ style WINDOW_STYLE_FILLED
+ elementwidth ((W/2)-(2*BORDER))
+ elementheight ELEM_H
+ dropitems 5
+ textscale .25
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_RESOLUTIONS
+ border WINDOW_BORDER_FULL
+ borderColor 0.5 0.5 0.5 1
+ forecolor 1 1 1 1
+ backcolor 0 0 0 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_SLIDER
+ text "Video Brightness:"
+ cvarfloat "r_gamma" 1 .5 2
+ rect X (Y+(3*(ELEM_H+ELEM_GAP))) W ELEM_H
+ textalign ALIGN_RIGHT
+ textalignx TOFF_X
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+
+
+ itemDef
+ {
+ type ITEM_TYPE_SLIDER
+ text "Effects Volume:"
+ cvarfloat "s_volume" 0.7 0 1
+ rect X (Y+(4*(ELEM_H+ELEM_GAP))) W ELEM_H
+ textalign ALIGN_RIGHT
+ textalignx TOFF_X
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_SLIDER
+ text "Music Volume:"
+ cvarfloat "s_musicvolume" 0.25 0 1
+ rect X (Y+(5*(ELEM_H+ELEM_GAP))) W ELEM_H
+ textalign ALIGN_RIGHT
+ textalignx TOFF_X
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_YESNO
+ text "OpenAL Sound:"
+ cvar "s_useOpenAL"
+ rect X (Y+(6*(ELEM_H+ELEM_GAP))) W ELEM_H
+ textalign ALIGN_RIGHT
+ textalignx TOFF_X
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+
+
+ itemDef
+ {
+ type ITEM_TYPE_SLIDER
+ text "Mouse Sensitivity:"
+ cvarfloat "sensitivity" 5 1 30
+ rect X (Y+(7*(ELEM_H+ELEM_GAP))) W ELEM_H
+ textalign ALIGN_RIGHT
+ textalignx TOFF_X
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_YESNO
+ text "Invert Mouse:"
+ cvar "ui_mousePitch"
+ rect X (Y+(8*(ELEM_H+ELEM_GAP))) W ELEM_H
+ textalign ALIGN_RIGHT
+ textalignx TOFF_X
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript update ui_mousePitch
+ }
+ }
+
+
+
+ itemDef
+ {
+ type ITEM_TYPE_MULTI
+ text "Network Connection:"
+ cvar "rate"
+ cvarFloatList { "<=28.8k" 2500 "33.6k" 3000 "56k" 4000 "ISDN" 5000 "LAN/CABLE/xDSL" 25000 }
+ rect X (Y+(9*(ELEM_H+ELEM_GAP))) W ELEM_H
+ textalign ALIGN_RIGHT
+ textalignx TOFF_X
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_YESNO
+ text "Allow Auto Download:"
+ cvar "cl_allowDownload"
+ rect X (Y+(10*(ELEM_H+ELEM_GAP))) W ELEM_H
+ textalign ALIGN_RIGHT
+ textalignx TOFF_X
+ textvalign VALIGN_CENTER
+ textscale .25
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ text "For further options please use the in-game options menu"
+ type ITEM_TYPE_TEXT
+ style WINDOW_STYLE_EMPTY
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ textscale .25
+ rect 0 (H-60) W 10
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ decoration
+ }
+
+
+ itemDef
+ {
+ text "APPLY"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect (W-(2*BUTT_W)) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ exec "snd_restart" // includes vid_restart
+ }
+ }
+
+ itemDef
+ {
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect (W-BUTT_W) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close simple_options
+ }
+ }
+ }
+}
diff --git a/assets/ui/password.menu b/assets/ui/password.menu
new file mode 100644
index 0000000..d6ac4cd
--- /dev/null
+++ b/assets/ui/password.menu
@@ -0,0 +1,85 @@
+#include "ui/menudef.h"
+
+{
+ \\ PASSWORD POPUP MENU \\
+
+#define BUTT_W 45
+#define BUTT_H 35
+#define BORDER 10
+#define INPUT_H 20
+#define W 250
+#define H ((2*BORDER)+INPUT_H+BUTT_H)
+
+ menuDef
+ {
+ name "password_popmenu"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+
+ onOpen
+ {
+ setfocus passwordEntry
+ }
+
+ onESC
+ {
+ close password_popmenu
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ // PASSWORD //
+
+ itemDef
+ {
+ name passwordEntry
+ type ITEM_TYPE_EDITFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Password:"
+ maxChars 40
+ textscale .4
+ cvar "password"
+ rect BORDER BORDER (W-(2*BORDER)) INPUT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name yes
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect (W-BUTT_W) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close password_popmenu
+ }
+ }
+ }
+}
diff --git a/assets/ui/quit.menu b/assets/ui/quit.menu
new file mode 100644
index 0000000..0bd2e90
--- /dev/null
+++ b/assets/ui/quit.menu
@@ -0,0 +1,99 @@
+#include "ui/menudef.h"
+
+{
+ \\ QUIT POPUP MENU \\
+
+#define W 120
+#define H 120
+
+ menuDef
+ {
+ name "quit_popmenu"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onESC
+ {
+ play "sound/misc/menu1.wav";
+ close quit_popmenu
+ }
+
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+
+ // QUIT //
+
+ itemDef
+ {
+ name confirm
+ type ITEM_TYPE_TEXT
+ text "Quit Tremulous?"
+ style WINDOW_STYLE_EMPTY
+ textscale .3
+ textstyle WINDOW_STYLE_SHADER
+ rect 0 0 W ((2*H)/3)
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ decoration
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ }
+
+
+ itemDef
+ {
+ name yes
+ text "YES"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect 0 (H/3) (W/2) ((2*H)/3)
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu4.wav";
+ open quitCredit
+ }
+ }
+
+
+ itemDef
+ {
+ name no
+ text "NO"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ rect (W/2) (H/3) (W/2) ((2*H)/3)
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close quit_popmenu
+ }
+ }
+ }
+}
+
+
diff --git a/ui/quitcredit.menu b/assets/ui/quitcredit.menu
index 679d6a8..14a8f4f 100644
--- a/ui/quitcredit.menu
+++ b/assets/ui/quitcredit.menu
@@ -6,12 +6,13 @@
menuDef
{
name "quitCredit"
- visible 0
- fullscreen 1
+ visible MENU_FALSE
+ fullscreen MENU_TRUE
rect 0 0 640 480
focusColor 1 .75 0 1
- style 1
- border 0
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_NONE
+ aspectBias ASPECT_NONE
onEsc
{
uiScript "quit"
@@ -23,7 +24,7 @@
style WINDOW_STYLE_SHADER
rect 0 0 640 480
type ITEM_TYPE_BUTTON
- visible 1
+ visible MENU_TRUE
backcolor 0 0 0 1
background "ui/assets/credits_splash.jpg"
action
@@ -32,15 +33,15 @@
uiScript "quit"
}
}
-
+
itemDef
{
name topstripe
style WINDOW_STYLE_FILLED
rect -5 -5 645 64
- visible 1
+ visible MENU_TRUE
backcolor 0 0 0 1
-
+
border WINDOW_BORDER_FULL
borderSize 1.5
borderColor 1 0 0 1
@@ -51,9 +52,9 @@
name bottomstripe
style WINDOW_STYLE_FILLED
rect -5 416 645 485
- visible 1
+ visible MENU_TRUE
backcolor 0 0 0 1
-
+
border WINDOW_BORDER_FULL
borderSize 1.5
borderColor 1 0 0 1
@@ -65,34 +66,32 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 320 48 1 1
- textalign ITEM_ALIGN_CENTER
- textalignx 0
- textaligny 0
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_CENTER
textscale 0.75
textstyle ITEM_TEXTSTYLE_NORMAL
text "CREDITS"
forecolor 1 1 1 1
backcolor 1 0 0 1
visible 1
- decoration
+ decoration
}
-
+
itemDef
{
name "credit1left"
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 10 96 1 1
- textalign ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_LEFT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Tim 'Timbo' Angus"
forecolor 1 1 1 1
backcolor 1 0 0 1
visible 1
- decoration
+ decoration
}
itemDef
{
@@ -100,16 +99,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 630 96 1 1
- textalign ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_RIGHT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Programming and Direction"
forecolor 1 1 1 1
backcolor 0 1 0 1
visible 1
- decoration
+ decoration
}
itemDef
@@ -118,16 +116,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 10 128 1 1
- textalign ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_LEFT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Nick 'jex' Jansens"
forecolor 1 1 1 1
backcolor 1 0 0 1
visible 1
- decoration
+ decoration
}
itemDef
{
@@ -135,16 +132,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 630 128 1 1
- textalign ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_RIGHT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Mapping, texturing and 2D artwork"
forecolor 1 1 1 1
backcolor 0 1 0 1
visible 1
- decoration
+ decoration
}
itemDef
@@ -153,16 +149,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 10 160 1 1
- textalign ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_LEFT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Robin 'OverFlow' Marshall"
forecolor 1 1 1 1
backcolor 1 0 0 1
visible 1
- decoration
+ decoration
}
itemDef
{
@@ -170,16 +165,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 630 160 1 1
- textalign ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_RIGHT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Modelling, animation and mapping"
forecolor 1 1 1 1
backcolor 0 1 0 1
visible 1
- decoration
+ decoration
}
itemDef
@@ -188,16 +182,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 10 192 1 1
- textalign ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_LEFT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Jan 'Stannum' van der Weg"
forecolor 1 1 1 1
backcolor 1 0 0 1
visible 1
- decoration
+ decoration
}
itemDef
{
@@ -205,16 +198,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 630 192 1 1
- textalign ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_RIGHT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Texturing and mapping"
forecolor 1 1 1 1
backcolor 0 1 0 1
visible 1
- decoration
+ decoration
}
itemDef
@@ -223,16 +215,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 10 224 1 1
- textalign ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_LEFT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Mike 'Veda' McInerney"
forecolor 1 1 1 1
backcolor 1 0 0 1
visible 1
- decoration
+ decoration
}
itemDef
{
@@ -240,16 +231,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 630 224 1 1
- textalign ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_RIGHT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Modelling, animation and texturing"
forecolor 1 1 1 1
backcolor 0 1 0 1
visible 1
- decoration
+ decoration
}
itemDef
@@ -258,16 +248,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 10 256 1 1
- textalign ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_LEFT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Gordon 'Godmil' Miller"
forecolor 1 1 1 1
backcolor 1 0 0 1
visible 1
- decoration
+ decoration
}
itemDef
{
@@ -275,16 +264,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 630 256 1 1
- textalign ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_RIGHT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Mapping"
forecolor 1 1 1 1
backcolor 0 1 0 1
visible 1
- decoration
+ decoration
}
itemDef
@@ -293,16 +281,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 10 288 1 1
- textalign ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_LEFT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "'Who-[Soup]'"
forecolor 1 1 1 1
backcolor 1 0 0 1
visible 1
- decoration
+ decoration
}
itemDef
{
@@ -310,16 +297,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 630 288 1 1
- textalign ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_RIGHT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Mapping"
forecolor 1 1 1 1
backcolor 0 1 0 1
visible 1
- decoration
+ decoration
}
itemDef
@@ -328,16 +314,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 10 320 1 1
- textalign ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_LEFT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Tristan 'jhrx' Blease"
forecolor 1 1 1 1
backcolor 1 0 0 1
visible 1
- decoration
+ decoration
}
itemDef
{
@@ -345,16 +330,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 630 320 1 1
- textalign ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_RIGHT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Mapping"
forecolor 1 1 1 1
backcolor 0 1 0 1
visible 1
- decoration
+ decoration
}
itemDef
@@ -363,16 +347,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 10 352 1 1
- textalign ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_LEFT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Paul 'MoP' Greveson"
forecolor 1 1 1 1
backcolor 1 0 0 1
visible 1
- decoration
+ decoration
}
itemDef
{
@@ -380,34 +363,32 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 630 352 1 1
- textalign ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_RIGHT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Modelling and texturing"
forecolor 1 1 1 1
backcolor 0 1 0 1
visible 1
- decoration
+ decoration
}
-
+
itemDef
{
name "credit10left"
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 10 384 1 1
- textalign ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_LEFT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Chris 'Dolby' McCarthy"
forecolor 1 1 1 1
backcolor 1 0 0 1
visible 1
- decoration
+ decoration
}
itemDef
{
@@ -415,16 +396,15 @@
group grpidcredit
style WINDOW_STYLE_EMPTY
rect 630 384 1 1
- textalign ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 10
+ type ITEM_TYPE_TEXT
+ textalign ALIGN_RIGHT
textscale 0.50
textstyle ITEM_TEXTSTYLE_NORMAL
text "Sound"
forecolor 1 1 1 1
backcolor 0 1 0 1
visible 1
- decoration
+ decoration
}
}
}
diff --git a/assets/ui/say.menu b/assets/ui/say.menu
new file mode 100644
index 0000000..2bd3015
--- /dev/null
+++ b/assets/ui/say.menu
@@ -0,0 +1,180 @@
+#include "ui/menudef.h"
+#include "ui/menu_bool.h"
+
+{
+
+#define BORDER 10
+
+#define X BORDER
+#define Y BORDER
+#define W (600-(2*BORDER))
+#define H (480-(2*BORDER))
+
+ // Say to All
+ menuDef
+ {
+ name say
+ fullScreen false
+ visible false
+ rect X Y W H
+ aspectBias ALIGN_LEFT
+ focusColor 1 1 1 1
+ style WINDOW_STYLE_EMPTY
+ onOpen
+ {
+ setfocus say_field;
+ }
+
+ itemDef
+ {
+ name say_field
+ type ITEM_TYPE_SAYFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Say:"
+ cvar "ui_sayBuffer"
+ maxchars 128
+ rect 0 0 W H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_SHADOWED
+ textscale .4
+ forecolor 0.93 0.93 0.92 1
+ visible true
+ onCharEntry
+ {
+ uiScript SayKeyDown;
+ }
+ onTextEntry
+ {
+ uiScript Say;
+ close say;
+ }
+ }
+ }
+
+ // Say to Team
+ menuDef
+ {
+ name say_team
+ fullScreen false
+ visible false
+ rect X Y W H
+ aspectBias ALIGN_LEFT
+ focusColor 1 1 1 1
+ style WINDOW_STYLE_EMPTY
+ onOpen
+ {
+ setfocus say_field
+ }
+
+ itemDef
+ {
+ name say_field
+ type ITEM_TYPE_SAYFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Say to team:"
+ cvar "ui_sayBuffer"
+ maxchars 128
+ rect 0 0 W H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_SHADOWED
+ textscale .4
+ forecolor 0.93 0.93 0.92 1
+ visible true
+ onCharEntry
+ {
+ uiScript SayKeyDown;
+ }
+ onTextEntry
+ {
+ uiScript Say;
+ close say_team;
+ }
+ }
+ }
+
+ // Command
+ menuDef
+ {
+ name say_command
+ fullScreen false
+ visible false
+ rect X Y W H
+ aspectBias ALIGN_LEFT
+ focusColor 1 1 1 1
+ style WINDOW_STYLE_EMPTY
+ onOpen
+ {
+ setfocus say_field
+ }
+
+ itemDef
+ {
+ name say_field
+ type ITEM_TYPE_SAYFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Command:"
+ cvar "ui_sayBuffer"
+ maxchars 128
+ rect 0 0 W H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_SHADOWED
+ textscale .4
+ forecolor 0.93 0.93 0.92 1
+ visible true
+ onCharEntry
+ {
+ uiScript SayKeyDown;
+ }
+ onTextEntry
+ {
+ uiScript Say;
+ close say_command;
+ }
+ }
+ }
+
+ // Say to Admins
+ menuDef
+ {
+ name say_admin
+ fullScreen false
+ visible false
+ rect X Y W H
+ aspectBias ALIGN_LEFT
+ focusColor 1 1 1 1
+ style WINDOW_STYLE_EMPTY
+ onOpen
+ {
+ setfocus say_field
+ }
+
+ itemDef
+ {
+ name say_field
+ type ITEM_TYPE_SAYFIELD
+ style WINDOW_STYLE_EMPTY
+ text "Say to admins:"
+ cvar "ui_sayBuffer"
+ maxchars 128
+ rect 0 0 W H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textstyle ITEM_TEXTSTYLE_SHADOWED
+ textscale .4
+ forecolor 0.93 0.93 0.92 1
+ visible true
+ onCharEntry
+ {
+ uiScript SayKeyDown;
+ }
+ onTextEntry
+ {
+ uiScript Say;
+ close say_admin;
+ }
+ }
+ }
+}
diff --git a/assets/ui/serverinfo.menu b/assets/ui/serverinfo.menu
new file mode 100644
index 0000000..596712c
--- /dev/null
+++ b/assets/ui/serverinfo.menu
@@ -0,0 +1,112 @@
+#include "ui/menudef.h"
+
+{
+ \\ SERVER INFO POPUP MENU \\
+
+#define W 400
+#define H 300
+#define BUTT_W 45
+#define BUTT_H 35
+#define BORDER 10
+#define LIST_W (W-(2*BORDER))
+#define LIST_DW (LIST_W-40)
+#define LEFT_C 0.13
+#define RIGHT_C 0.61
+
+ menuDef
+ {
+ name "serverinfo_popmenu"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ popup
+ onClose { }
+ onOpen { uiScript ServerStatus }
+ onESC
+ {
+ close serverinfo_popmenu
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name serverinfo
+ rect BORDER BORDER LIST_W (H-(BUTT_H+BORDER))
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 16
+ textscale .25
+ border WINDOW_BORDER_FULL
+ bordersize 1
+ bordercolor .5 .5 .5 1
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_SERVERSTATUS
+ notselectable
+ visible MENU_TRUE
+ columns 4
+ 0 ((2*LEFT_C)*LIST_DW) ALIGN_LEFT
+ (LEFT_C*LIST_DW) (LEFT_C*LIST_DW) ALIGN_LEFT
+ ((2*LEFT_C)*LIST_DW) (LEFT_C*LIST_DW) ALIGN_LEFT
+ ((1-RIGHT_C)*LIST_DW) (RIGHT_C*LIST_DW) ALIGN_LEFT
+ }
+
+ // BUTTON //
+
+ itemDef
+ {
+ name refresh
+ text "Refresh"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect (W-(2*BUTT_W)) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript ServerStatus
+ }
+ }
+
+ itemDef
+ {
+ name close
+ text "Close"
+ type ITEM_TYPE_BUTTON
+ textscale .25
+ style WINDOW_STYLE_EMPTY
+ rect (W-BUTT_W) (H-BUTT_H) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ forecolor 1 1 1 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close serverinfo_popmenu
+ }
+ }
+ }
+}
+
+
diff --git a/assets/ui/teamscore.menu b/assets/ui/teamscore.menu
new file mode 100644
index 0000000..65893a0
--- /dev/null
+++ b/assets/ui/teamscore.menu
@@ -0,0 +1,386 @@
+#include "ui/menudef.h"
+
+{
+ \\ score_menu \\
+
+#define W 500
+#define H 338
+#define BORDER 10
+
+#define TOFF 10
+#define SPEC_W 75
+#define BAR_H 30
+
+#define LLIST_L 0
+#define LLIST_R (W/2)
+#define RLIST_L (W/2)
+#define RLIST_R W
+
+ menuDef
+ {
+ name "teamscore_menu"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_EMPTY
+
+ // TEAM NAME //
+
+ itemDef
+ {
+ name teamNameWindow
+ rect 0 0 W BAR_H
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ bordercolor .5 .5 .5 1
+ forecolor 1 1 1 1
+ backcolor 0 0 0 .8
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name alienteamname
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx TOFF
+ textscale 0.4
+ rect 0 0 (W/3) BAR_H
+ forecolor 1 1 1 1
+ decoration
+ visible MENU_TRUE
+ ownerdraw CG_ALIENS_SCORE_LABEL
+ }
+
+ itemDef
+ {
+ name stagereport
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale 0.33
+ rect (W/3) 0 (W/3) BAR_H
+ forecolor 1 1 1 1
+ decoration
+ visible MENU_TRUE
+ ownerdraw CG_STAGE_REPORT_TEXT
+ }
+
+ itemDef
+ {
+ name humanteamname
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textalignx -TOFF
+ textscale 0.4
+ rect ((2*W)/3) 0 (W/3) BAR_H
+ forecolor 1 1 1 1
+ decoration
+ visible MENU_TRUE
+ ownerdraw CG_HUMANS_SCORE_LABEL
+ }
+
+ // TEAM BARS //
+
+ itemDef
+ {
+ name leftteambar
+ rect 0 (BAR_H+BORDER) (W/2) BAR_H
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ bordercolor .5 .5 .5 1
+ forecolor 1 1 1 1
+ backcolor 0 0 0 .8
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name rightteambar
+ rect (W/2) (BAR_H+BORDER) (W/2) BAR_H
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ bordercolor .5 .5 .5 1
+ forecolor 1 1 1 1
+ backcolor 0 0 0 .8
+ visible MENU_TRUE
+ decoration
+ }
+
+
+ // TEAM HEADINGS //
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ text "Status"
+ textscale .33
+ style WINDOW_STYLE_EMPTY
+ rect (LLIST_L+10) (BAR_H+BORDER) 1 BAR_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ backcolor 0 0 0 0
+ forecolor 1 .75 0 1
+ decoration
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ text "Name"
+ textscale .33
+ style WINDOW_STYLE_EMPTY
+ rect (LLIST_L+50) (BAR_H+BORDER) 1 BAR_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ backcolor 0 0 0 0
+ forecolor 1 .75 0 1
+ decoration
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ text "Score"
+ textscale .33
+ style WINDOW_STYLE_EMPTY
+ rect (LLIST_R-95) (BAR_H+BORDER) 1 BAR_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ backcolor 0 0 0 0
+ forecolor 1 .75 0 1
+ decoration
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ text "Time"
+ textscale .33
+ style WINDOW_STYLE_EMPTY
+ rect (LLIST_R-55) (BAR_H+BORDER) 1 BAR_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ backcolor 0 0 0 0
+ forecolor 1 .75 0 1
+ decoration
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ text "Ping"
+ textscale .33
+ style WINDOW_STYLE_EMPTY
+ rect (LLIST_R-15) (BAR_H+BORDER) 1 BAR_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ backcolor 0 0 0 0
+ forecolor 1 .75 0 1
+ decoration
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ text "Status"
+ textscale .33
+ style WINDOW_STYLE_EMPTY
+ rect (RLIST_L+10) (BAR_H+BORDER) 1 BAR_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ backcolor 0 0 0 0
+ forecolor 1 .75 0 1
+ decoration
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ text "Name"
+ textscale .33
+ style WINDOW_STYLE_EMPTY
+ rect (RLIST_L+50) (BAR_H+BORDER) 1 BAR_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ backcolor 0 0 0 0
+ forecolor 1 .75 0 1
+ decoration
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ text "Score"
+ textscale .33
+ style WINDOW_STYLE_EMPTY
+ rect (RLIST_R-95) (BAR_H+BORDER) 1 BAR_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ backcolor 0 0 0 0
+ forecolor 1 .75 0 1
+ decoration
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ text "Time"
+ textscale .33
+ style WINDOW_STYLE_EMPTY
+ rect (RLIST_R-55) (BAR_H+BORDER) 1 BAR_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ backcolor 0 0 0 0
+ forecolor 1 .75 0 1
+ decoration
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ text "Ping"
+ textscale .33
+ style WINDOW_STYLE_EMPTY
+ rect (RLIST_R-15) (BAR_H+BORDER) 1 BAR_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ backcolor 0 0 0 0
+ forecolor 1 .75 0 1
+ decoration
+ visible MENU_TRUE
+ }
+
+ itemDef
+ {
+ name leftlist
+ rect 0 ((2*BAR_H)+BORDER) (W/2) (H-((3*BAR_H)+(2*BORDER)))
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 .6
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ bordercolor .5 .5 .5 1
+ forecolor .75 .75 .75 1
+ visible MENU_TRUE
+ type ITEM_TYPE_LISTBOX
+ elementwidth 135
+ elementheight 16
+ textscale .25
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_ALIENTEAM_LIST
+ notselectable
+ noscrollbar
+ columns 7
+ 5 15 ALIGN_LEFT
+ 21 15 ALIGN_LEFT
+ 7 30 ALIGN_LEFT
+ 45 ((W/2)-170) ALIGN_LEFT
+ ((W/2)-120) 20 ALIGN_RIGHT
+ ((W/2)-80) 20 ALIGN_RIGHT
+ ((W/2)-40) 20 ALIGN_RIGHT
+ }
+
+ itemDef
+ {
+ name rightlist
+ rect (W/2) ((2*BAR_H)+BORDER) (W/2) (H-((3*BAR_H)+(2*BORDER)))
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 .6
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ bordercolor .5 .5 .5 1
+ forecolor .75 .75 .75 1
+ visible MENU_TRUE
+ type ITEM_TYPE_LISTBOX
+ elementwidth 135
+ elementheight 16
+ textscale .25
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_HUMANTEAM_LIST
+ notselectable
+ noscrollbar
+ columns 7
+ 5 15 ALIGN_LEFT
+ 21 15 ALIGN_LEFT
+ 7 30 ALIGN_LEFT
+ 45 ((W/2)-170) ALIGN_LEFT
+ ((W/2)-120) 20 ALIGN_RIGHT
+ ((W/2)-80) 20 ALIGN_RIGHT
+ ((W/2)-40) 20 ALIGN_RIGHT
+ }
+
+ // spectators //
+
+ itemDef
+ {
+ name window
+ rect 0 (H-BAR_H) W BAR_H
+ style WINDOW_STYLE_FILLED
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ bordercolor .5 .5 .5 1
+ backcolor 0 0 0 .8
+ textscale .33
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ type ITEM_TYPE_TEXT
+ name window
+ text "Spectating:"
+ rect 0 (H-BAR_H) SPEC_W BAR_H
+ style WINDOW_STYLE_FILLED
+ forecolor 1 1 1 1
+ textscale .33
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textalignx TOFF
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name window
+ rect SPEC_W (H-BAR_H) (W-SPEC_W) BAR_H
+ style WINDOW_STYLE_FILLED
+ forecolor 1 1 1 1
+ textscale .33
+ textvalign VALIGN_CENTER
+ visible MENU_TRUE
+ ownerdraw CG_SPECTATORS
+ decoration
+ }
+
+ itemDef
+ {
+ name winner
+ type ITEM_TYPE_TEXT
+ rect (W/2) (H+BAR_H) 0 0
+ style WINDOW_STYLE_EMPTY
+ forecolor 1 1 1 1
+ textscale 0.5
+ textalign ALIGN_CENTER
+ textvalign VALIGN_TOP
+ visible MENU_TRUE
+ cvar "ui_winner"
+ decoration
+ }
+ }
+}
diff --git a/ui/tremulous.txt b/assets/ui/tremulous.txt
index 4e094ad..fbeb47d 100644
--- a/ui/tremulous.txt
+++ b/assets/ui/tremulous.txt
@@ -1,21 +1,20 @@
// menu defs
-//
-{
+//
+{
loadMenu { "ui/tremulous_teamselect.menu" }
loadMenu { "ui/tremulous_alienclass.menu" }
loadMenu { "ui/tremulous_humanitem.menu" }
-
+
loadMenu { "ui/tremulous_alienbuild.menu" }
loadMenu { "ui/tremulous_humanbuild.menu" }
-
+
loadMenu { "ui/tremulous_humanarmoury.menu" }
-
+
+ loadMenu { "ui/tremulous_dialogs.menu" }
loadMenu { "ui/tremulous_humandialogs.menu" }
loadMenu { "ui/tremulous_aliendialogs.menu" }
-
- loadMenu { "ui/tremulous_alienupgrade.menu" }
-
- loadMenu { "ui/ptrc.menu" }
+ loadMenu { "ui/tremulous_alienupgrade.menu" }
+ loadMenu { "ui/tremulous_voicecmd.menu" }
loadMenu { "ui/say.menu" }
}
diff --git a/assets/ui/tremulous_alien_builder_hud.menu b/assets/ui/tremulous_alien_builder_hud.menu
new file mode 100644
index 0000000..b532264
--- /dev/null
+++ b/assets/ui/tremulous_alien_builder_hud.menu
@@ -0,0 +1,42 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 640
+#define H 480
+
+ menuDef
+ {
+ name "alien_builder_hud"
+ fullScreen MENU_FALSE
+ visible MENU_TRUE
+ rect 0 0 W H
+ aspectBias ASPECT_NONE
+
+#include "ui/tremulous_alien_common_hud.h"
+
+ //BUILD TIMER
+ itemDef
+ {
+ name "buildtimer"
+ rect 567 410 25 25
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor 1.0 0.0 0.0 .5
+ ownerdraw CG_PLAYER_BUILD_TIMER
+ }
+
+ //BUILD POINTS
+ itemDef
+ {
+ name "build-points"
+ rect 493.5 421.5 60 15
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor 1.0 0.0 0.0 1.0
+ ownerdraw CG_PLAYER_AMMO_VALUE
+ }
+ }
+}
diff --git a/assets/ui/tremulous_alien_common_hud.h b/assets/ui/tremulous_alien_common_hud.h
new file mode 100644
index 0000000..c77c9f7
--- /dev/null
+++ b/assets/ui/tremulous_alien_common_hud.h
@@ -0,0 +1,257 @@
+#define COMMON_HUD_R 1.0
+#define COMMON_HUD_G 0.0
+#define COMMON_HUD_B 0.0
+#include "ui/tremulous_common_hud.h"
+
+//////////////////
+//STATIC OBJECTS//
+//////////////////
+
+//LEFT RING CIRCLE
+itemDef
+{
+ name "left-ring-circle"
+ rect 47.5 410 25 25
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/neutral/circle.tga"
+}
+
+//LEFT ARM
+itemDef
+{
+ name "left-arm"
+ rect 77 404.75 104 52.5
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/alien/left-arm.tga"
+}
+
+//LEFT ARM CIRCLE
+itemDef
+{
+ name "left-arm-circle"
+ rect 150 417.5 25 25
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/neutral/circle.tga"
+}
+
+//RIGHT RING CIRCLE
+itemDef
+{
+ name "right-ring-circle"
+ rect 567 410 25 25
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/neutral/circle.tga"
+}
+
+//RIGHT ARM
+itemDef
+{
+ name "right-arm"
+ rect 459 404.75 104 52.5
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/alien/right-arm.tga"
+}
+
+///////////////////
+//DYNAMIC OBJECTS//
+///////////////////
+
+//BOLT
+itemDef
+{
+ name "bolt"
+ rect 52.5 412.5 15 20
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.8
+ backcolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ background "ui/assets/alien/bolt.tga"
+ ownerdraw CG_PLAYER_BOOST_BOLT
+}
+
+//CROSS
+itemDef
+{
+ name "cross"
+ rect 150 417.5 25 25
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.5
+ ownerdraw CG_PLAYER_HEALTH_CROSS
+}
+
+//LEFT RING
+itemDef
+{
+ name "left-ring"
+ rect 7.25 369.5 90.5 106
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.8
+ backcolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ background "ui/assets/alien/left-ring.tga"
+ ownerdraw CG_PLAYER_BOOSTED
+}
+
+//LEFT SPIKES
+itemDef
+{
+ name "left-spikes"
+ rect 18.5 381 59 83
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 1.0
+ backcolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ background "ui/assets/alien/left-spikes.tga"
+ ownerdraw CG_PLAYER_WALLCLIMBING
+}
+
+//RIGHT RING
+itemDef
+{
+ name "right-ring"
+ rect 542.25 369.5 90.5 106
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.8
+ backcolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ background "ui/assets/alien/right-ring.tga"
+ ownerdraw CG_PLAYER_BOOSTED
+}
+
+//RIGHT SPIKES
+itemDef
+{
+ name "right-spikes"
+ rect 562.5 381 59 83
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 1.0
+ backcolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ background "ui/assets/alien/right-spikes.tga"
+ ownerdraw CG_PLAYER_WALLCLIMBING
+}
+
+//HEALTH
+itemDef
+{
+ name "health"
+ rect 78.5 421.5 60 15
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B .5
+ ownerdraw CG_PLAYER_HEALTH
+}
+
+//ALIEN CLASS ICON
+itemDef
+{
+ name "alien-icon"
+ rect 465 417.5 25 25
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.6
+ ownerdraw CG_PLAYER_WEAPONICON
+}
+
+//ORGANS
+itemDef
+{
+ name "organs"
+ rect 570 416 15 15
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 1
+ ownerdraw CG_PLAYER_CREDITS_VALUE_NOPAD
+}
+
+//CREDITS FRACTION
+itemDef
+{
+ name "credits-background"
+ rect 567 410 25 25
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ background "ui/assets/neutral/circle.tga"
+ ownerdraw CG_PLAYER_CREDITS_FRACTION
+}
+
+//ALIENSENSE
+itemDef
+{
+ name "aliensense"
+ rect 20 20 600 400
+ visible MENU_TRUE
+ decoration
+ ownerdraw CG_PLAYER_ALIEN_SENSE
+}
+
+//CHARGE BAR
+itemDef
+{
+ name "charge"
+ rect 292 426 56 8
+ aspectBias ALIGN_CENTER
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.5
+ ownerdraw CG_PLAYER_CHARGE_BAR
+ background "ui/assets/neutral/charge_cap_h.tga"
+}
+
+//CHARGE BAR BG
+itemDef
+{
+ name "chargebg"
+ rect 288 422 64 16
+ aspectBias ALIGN_CENTER
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ ownerdraw CG_PLAYER_CHARGE_BAR_BG
+ background "ui/assets/neutral/charge_bg_h.tga"
+}
+
+//TEAM OVERLAY
+itemDef
+{
+ name "teamoverlay"
+ rect BORDER 175 200 128
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.75
+ textscale 0.85
+ ownerdraw CG_TEAMOVERLAY
+}
diff --git a/assets/ui/tremulous_alien_general_hud.menu b/assets/ui/tremulous_alien_general_hud.menu
new file mode 100644
index 0000000..df1352d
--- /dev/null
+++ b/assets/ui/tremulous_alien_general_hud.menu
@@ -0,0 +1,30 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 640
+#define H 480
+
+ menuDef
+ {
+ name "alien_general_hud"
+ fullScreen MENU_FALSE
+ visible MENU_TRUE
+ rect 0 0 W H
+ aspectBias ASPECT_NONE
+
+#include "ui/tremulous_alien_common_hud.h"
+
+ //BLOB
+ itemDef
+ {
+ name "blob"
+ rect 497 419 52 18
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ forecolor 1.0 0.0 0.0 0.5
+ background "ui/assets/alien/tremublob.tga"
+ ownerdraw CG_PLAYER_POISON_BARBS
+ }
+ }
+}
diff --git a/assets/ui/tremulous_alienbuild.menu b/assets/ui/tremulous_alienbuild.menu
new file mode 100644
index 0000000..127b769
--- /dev/null
+++ b/assets/ui/tremulous_alienbuild.menu
@@ -0,0 +1,136 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 450
+#define H 250
+#define BORDER 10
+
+#define LIST_W 140
+#define LIST_H (H-(2*BORDER))
+#define LIST_X BORDER
+#define LIST_Y BORDER
+
+#define BUTT_H 25
+#define BUTT_W 45
+
+#define INFO_W (W-((3*BORDER)+LIST_W))
+#define INFO_H (H-((3*BORDER)+BUTT_H))
+#define INFO_X ((2*BORDER)+LIST_W)
+#define INFO_Y BORDER
+#define INFO_TOFF 6
+
+ menuDef
+ {
+ name "tremulous_alienbuild"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ popup
+ onOpen { uiScript LoadAlienBuilds; setFocus list }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name "list"
+ rect LIST_X LIST_Y LIST_W LIST_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_TREMALIENBUILD
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript BuildAlienBuildable;
+ close tremulous_alienbuild
+ }
+ }
+
+ itemDef
+ {
+ name infopane
+ ownerdraw UI_ABUILDINFOPANE
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ textscale .33
+ textalign ALIGN_LEFT
+ textvalign VALIGN_TOP
+ textalignx INFO_TOFF
+ textaligny INFO_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-((2*BORDER)+(2*BUTT_W))) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript BuildAlienBuildable;
+ close tremulous_alienbuild
+ }
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "Cancel"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ close tremulous_alienbuild
+ }
+ }
+ }
+}
diff --git a/assets/ui/tremulous_alienclass.menu b/assets/ui/tremulous_alienclass.menu
new file mode 100644
index 0000000..441e27f
--- /dev/null
+++ b/assets/ui/tremulous_alienclass.menu
@@ -0,0 +1,157 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 450
+#define H 250
+#define BORDER 10
+
+#define LIST_W 140
+#define LIST_H (H-(2*BORDER))
+#define LIST_X BORDER
+#define LIST_Y BORDER
+
+#define BUTT_H 25
+#define BUTT_W 45
+
+#define INFO_W (W-((3*BORDER)+LIST_W))
+#define INFO_H (H-((3*BORDER)+BUTT_H))
+#define INFO_X ((2*BORDER)+LIST_W)
+#define INFO_Y BORDER
+#define INFO_TOFF 6
+
+ menuDef
+ {
+ name "tremulous_alienclass"
+ visible MENU_TRUE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ popup
+ onOpen { uiScript LoadAlienClasses; setFocus list }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name "list"
+ rect LIST_X LIST_Y LIST_W LIST_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_TREMALIENCLASSES
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript SpawnAsAlienClass;
+ close tremulous_alienclass
+ }
+ }
+
+ itemDef
+ {
+ name infopane
+ ownerdraw UI_ACLASSINFOPANE
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ textscale .33
+ textalign ALIGN_LEFT
+ textvalign VALIGN_TOP
+ textalignx INFO_TOFF
+ textaligny INFO_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name "Back"
+ text "< Back"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect ((2*BORDER)+LIST_W) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu4.wav";
+ close tremulous_alienclass;
+ open tremulous_teamselect
+ }
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-((2*BORDER)+(2*BUTT_W))) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript SpawnAsAlienClass;
+ close tremulous_alienclass
+ }
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "Cancel"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ close tremulous_alienclass
+ }
+ }
+ }
+}
diff --git a/assets/ui/tremulous_aliendialogs.menu b/assets/ui/tremulous_aliendialogs.menu
new file mode 100644
index 0000000..921d2c8
--- /dev/null
+++ b/assets/ui/tremulous_aliendialogs.menu
@@ -0,0 +1,97 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 280
+#define H 190
+#define BORDER 10
+
+#define BUTT_H 25
+#define BUTT_W 45
+
+#define INFO_W (W-(2*BORDER))
+#define INFO_H (H-((4*BORDER)+(2*BUTT_H)))
+#define INFO_X BORDER
+#define INFO_Y ((2*BORDER)+BUTT_H)
+
+ menuDef
+ {
+ name "tremulous_alien_dialog"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_EMPTY
+ popup
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name alien_dialog
+ text "Error"
+ type ITEM_TYPE_TEXT
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect BORDER BORDER INFO_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name alien_dialog
+ type ITEM_TYPE_TEXT
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ cvar "ui_dialog"
+ wrapped
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .33
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name alien_dialog
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close tremulous_alien_dialog
+ }
+ }
+ }
+}
diff --git a/assets/ui/tremulous_alienupgrade.menu b/assets/ui/tremulous_alienupgrade.menu
new file mode 100644
index 0000000..2ef7bcb
--- /dev/null
+++ b/assets/ui/tremulous_alienupgrade.menu
@@ -0,0 +1,136 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 450
+#define H 250
+#define BORDER 10
+
+#define LIST_W 140
+#define LIST_H (H-(2*BORDER))
+#define LIST_X BORDER
+#define LIST_Y BORDER
+
+#define BUTT_H 25
+#define BUTT_W 45
+
+#define INFO_W (W-((3*BORDER)+LIST_W))
+#define INFO_H (H-((3*BORDER)+BUTT_H))
+#define INFO_X ((2*BORDER)+LIST_W)
+#define INFO_Y BORDER
+#define INFO_TOFF 6
+
+ menuDef
+ {
+ name "tremulous_alienupgrade"
+ visible MENU_TRUE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ popup
+ onOpen { uiScript LoadAlienUpgrades; setFocus list }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name "list"
+ rect LIST_X LIST_Y LIST_W LIST_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_TREMALIENUPGRADE
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript UpgradeToNewClass;
+ close tremulous_alienupgrade
+ }
+ }
+
+ itemDef
+ {
+ name infopane
+ ownerdraw UI_AUPGRADEINFOPANE
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ textscale .33
+ textalign ALIGN_LEFT
+ textvalign VALIGN_TOP
+ textalignx INFO_TOFF
+ textaligny INFO_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-((2*BORDER)+(2*BUTT_W))) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript UpgradeToNewClass;
+ close tremulous_alienupgrade
+ }
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "Cancel"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ close tremulous_alienupgrade
+ }
+ }
+ }
+}
diff --git a/assets/ui/tremulous_common_hud.h b/assets/ui/tremulous_common_hud.h
new file mode 100644
index 0000000..4fb857b
--- /dev/null
+++ b/assets/ui/tremulous_common_hud.h
@@ -0,0 +1,247 @@
+#define BORDER 10
+
+#define STAT_W 45
+#define STAT_H 22
+#define STAT_X (W-(BORDER+STAT_W))
+
+#define CONSOLE_W (W-((3*BORDER)+STAT_W))
+#define CONSOLE_H 180
+#define MAIN_W (W-(2*BORDER))
+
+//#define TUTORIAL_X (W-(BORDER*MAIN_W))
+#define TUTORIAL_X 320
+
+#define KILLFEED_X (BORDER)
+#define KILLFEED_Y (410)
+
+//CONSOLE
+itemDef
+{
+ name "console"
+ rect BORDER BORDER CONSOLE_W CONSOLE_H
+ aspectBias ALIGN_LEFT
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor 0.93 0.93 0.92 1
+ textalign ALIGN_LEFT
+ textvalign VALIGN_TOP
+ textscale 0.35
+ textstyle ITEM_TEXTSTYLE_SHADOWED
+ ownerdraw CG_CONSOLE
+}
+
+//TUTORIAL
+itemDef
+{
+ name "tutorial"
+ rect TUTORIAL_X 275 MAIN_W 130
+ aspectBias ALIGN_LEFT
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor 1 1 1 0.35
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textscale 0.3
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ ownerdraw CG_TUTORIAL
+}
+
+//FPS
+itemDef
+{
+ name "fps"
+ rect STAT_X BORDER STAT_W STAT_H
+ aspectBias ALIGN_RIGHT
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 1
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale 0.3
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ ownerdraw CG_FPS
+}
+
+//TIMER
+itemDef
+{
+ name "timer"
+ rect STAT_X ((2*BORDER)+STAT_H) STAT_W STAT_H
+ aspectBias ALIGN_RIGHT
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 1
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale 0.3
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ ownerdraw CG_TIMER
+}
+
+//LAGOMETER
+itemDef
+{
+ name "lagometer"
+ rect STAT_X ((3*BORDER)+(2*STAT_H)) STAT_W STAT_H
+ aspectBias ALIGN_RIGHT
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 1
+ textscale 0.3
+ ownerdraw CG_LAGOMETER
+}
+
+//SPEEDOMETER
+itemDef
+{
+ name "speedometer"
+ rect (320-(STAT_W/2)) 350 STAT_W STAT_H
+ aspectBias ALIGN_CENTER
+ type ITEM_TYPE_OWNERDRAW
+ ownerdraw CG_SPEEDOMETER
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ backColor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ foreColor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.8
+ textscale 0.3
+}
+
+//CLOCK
+itemDef
+{
+ name "clock"
+ rect STAT_X ((4*BORDER)+(3*STAT_H)) STAT_W STAT_H
+ aspectBias ALIGN_RIGHT
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 1
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale 0.3
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ ownerdraw CG_CLOCK
+}
+
+//LOCATION
+itemDef
+{
+ name "location"
+ rect (STAT_X-75) ((5*BORDER)+(4*STAT_H)) (STAT_W+75) STAT_H
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor 1 1 1 1
+ textalign ALIGN_RIGHT
+ textscale 0.3
+ ownerdraw CG_PLAYER_LOCATION
+}
+
+//DEMO STATE
+itemDef
+{
+ name "demoRecording"
+ rect (STAT_X+(STAT_W-32)) ((8*BORDER)+(4*STAT_H)) 32 32
+ aspectBias ALIGN_RIGHT
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor 1 0 0 1
+ textscale 0.3
+ ownerdraw CG_DEMO_RECORDING
+ background "ui/assets/neutral/circle.tga"
+}
+itemDef
+{
+ name "demoPlayback"
+ rect (STAT_X+(STAT_W-32)) ((8*BORDER)+(4*STAT_H)) 32 32
+ aspectBias ALIGN_RIGHT
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor 1 1 1 1
+ textscale 0.3
+ ownerdraw CG_DEMO_PLAYBACK
+ background "ui/assets/forwardarrow.tga"
+}
+
+//SNAPSHOT
+itemDef
+{
+ name "snapshot"
+ rect BORDER (H-(BORDER+STAT_H)) MAIN_W STAT_H
+ aspectBias ALIGN_LEFT
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 1
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textscale 0.4
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ ownerdraw CG_SNAPSHOT
+}
+
+//PLAYER NAME
+itemDef
+{
+ name "playername"
+ rect 200 275 240 25
+ aspectBias ALIGN_CENTER
+ visible MENU_TRUE
+ decoration
+ textScale .5
+ ownerdraw CG_PLAYER_CROSSHAIRNAMES
+ textstyle ITEM_TEXTSTYLE_SHADOWED
+}
+
+//CROSSHAIR
+itemDef
+{
+ name "crosshair"
+ visible MENU_TRUE
+ decoration
+ rect 320 240 0 0
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B .35
+ ownerdraw CG_PLAYER_CROSSHAIR
+}
+
+//SPECTATOR TEXT
+itemDef
+{
+ name "followtext"
+ rect 200 375 240 25
+ foreColor 1 1 1 1
+ aspectBias ALIGN_CENTER
+ textalign ALIGN_CENTER
+ textvalign VALIGN_TOP
+ visible MENU_TRUE
+ decoration
+ textScale .7
+ textStyle ITEM_TEXTSTYLE_SHADOWED
+ ownerdraw CG_FOLLOW
+}
+
+//KILLFEED
+itemDef
+{
+ name "killfeed"
+ rect KILLFEED_X KILLFEED_Y 0 0
+ aspectBias ALIGN_LEFT
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 1
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textscale 0.3
+ textstyle ITEM_TEXTSTYLE_SHADOWED
+ ownerdraw CG_KILLFEED
+}
+
diff --git a/assets/ui/tremulous_default_hud.menu b/assets/ui/tremulous_default_hud.menu
new file mode 100644
index 0000000..8d1034b
--- /dev/null
+++ b/assets/ui/tremulous_default_hud.menu
@@ -0,0 +1,37 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 640
+#define H 480
+
+ menuDef
+ {
+ name "default_hud"
+ fullScreen MENU_FALSE
+ visible MENU_TRUE
+ rect 0 0 W H
+ aspectBias ASPECT_NONE
+
+#define COMMON_HUD_R 1.0
+#define COMMON_HUD_G 1.0
+#define COMMON_HUD_B 1.0
+#include "ui/tremulous_common_hud.h"
+
+ //SPECTATOR TEXT
+ itemDef
+ {
+ name "spectatortext"
+ text "SPECTATOR"
+ rect 200 415 240 25
+ foreColor 1 1 1 1
+ aspectBias ALIGN_CENTER
+ textalign ALIGN_CENTER
+ textvalign VALIGN_TOP
+ visible MENU_TRUE
+ decoration
+ textScale .7
+ textStyle ITEM_TEXTSTYLE_SHADOWED
+ }
+ }
+}
diff --git a/assets/ui/tremulous_dialogs.menu b/assets/ui/tremulous_dialogs.menu
new file mode 100644
index 0000000..63109dc
--- /dev/null
+++ b/assets/ui/tremulous_dialogs.menu
@@ -0,0 +1,98 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 280
+#define H 190
+#define BORDER 10
+
+#define BUTT_H 25
+#define BUTT_W 45
+
+#define INFO_W (W-(2*BORDER))
+#define INFO_H (H-((4*BORDER)+(2*BUTT_H)))
+#define INFO_X BORDER
+#define INFO_Y ((2*BORDER)+BUTT_H)
+#define INFO_TOFF 6
+
+ menuDef
+ {
+ name "tremulous_default_dialog"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_EMPTY
+ popup
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name default_dialog
+ text "Error"
+ type ITEM_TYPE_TEXT
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect BORDER BORDER INFO_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name default_dialog
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ type ITEM_TYPE_TEXT
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ cvar "ui_dialog"
+ wrapped
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .33
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name default_dialog
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close tremulous_default_dialog
+ }
+ }
+ }
+}
diff --git a/assets/ui/tremulous_human_hud.menu b/assets/ui/tremulous_human_hud.menu
new file mode 100644
index 0000000..f2b4ca9
--- /dev/null
+++ b/assets/ui/tremulous_human_hud.menu
@@ -0,0 +1,379 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 640
+#define H 480
+
+ menuDef
+ {
+ name "human_hud"
+ fullScreen MENU_FALSE
+ visible MENU_TRUE
+ rect 0 0 W H
+ aspectBias ASPECT_NONE
+
+#define COMMON_HUD_R 0.0
+#define COMMON_HUD_G 0.8
+#define COMMON_HUD_B 1.0
+#include "ui/tremulous_common_hud.h"
+
+ //////////////////
+ //STATIC OBJECTS//
+ //////////////////
+
+ //LEFT CIRCLE
+ itemDef
+ {
+ name "left-circle"
+ rect 35 417.5 25 25
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/neutral/circle.tga"
+ }
+
+ //LEFT ARM
+ itemDef
+ {
+ name "left-arm"
+ rect 68.25 420 94.5 35
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/human/left-arm.tga"
+ }
+
+ //CREDITS LABEL
+ itemDef
+ {
+ name "credits-label"
+ rect 508 403 7 7.5
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.5
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/human/credits.tga"
+ }
+
+ //RIGHT CIRCLE
+ itemDef
+ {
+ name "right-circle"
+ rect 580 417.5 25 25
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/neutral/circle.tga"
+ }
+
+ //RIGHT ARM
+ itemDef
+ {
+ name "right-arm"
+ rect 477.25 420 94.5 35
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/human/right-arm.tga"
+ }
+
+ //RIGHT CAP
+ itemDef
+ {
+ name "right-cap"
+ rect 500 400 80 15
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/human/right-cap.tga"
+ }
+
+ ///////////////////
+ //DYNAMIC OBJECTS//
+ ///////////////////
+
+ //BOLT
+ itemDef
+ {
+ name "bolt"
+ rect 40 420 15 20
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.8
+ backColor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ background "ui/assets/human/bolt.tga"
+ ownerdraw CG_PLAYER_STAMINA_BOLT
+ }
+
+ //CROSS
+ itemDef
+ {
+ name "cross"
+ rect 132.5 425 25 25
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.5
+ ownerdraw CG_PLAYER_HEALTH_CROSS
+ }
+
+ //STAMINA 1
+ itemDef
+ {
+ name "stamina1"
+ rect 34.5 403.5 9 11.5
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.8
+ backColor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ background "ui/assets/human/stamina1.tga"
+ ownerdraw CG_PLAYER_STAMINA_1
+ }
+
+ //STAMINA 2
+ itemDef
+ {
+ name "stamina2"
+ rect 24 410.75 11.5 10.5
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.8
+ backColor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ background "ui/assets/human/stamina2.tga"
+ ownerdraw CG_PLAYER_STAMINA_2
+ }
+
+ //STAMINA 3
+ itemDef
+ {
+ name "stamina3"
+ rect 20.75 423.5 10.5 7
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.8
+ backColor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ background "ui/assets/human/stamina3.tga"
+ ownerdraw CG_PLAYER_STAMINA_3
+ }
+
+ //STAMINA 4
+ itemDef
+ {
+ name "stamina4"
+ rect 21 402.5 54 55
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.8
+ backColor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ background "ui/assets/human/stamina4.tga"
+ ownerdraw CG_PLAYER_STAMINA_4
+ }
+
+ //RING
+ itemDef
+ {
+ name "ring"
+ //rect 20 402.5 55 55 // Guide for Stamina alignment
+ rect 565 402.5 55 55
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.5
+ backColor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.2
+ background "ui/assets/human/ring.tga"
+ ownerdraw CG_PLAYER_CLIPS_RING
+ }
+
+ //CREDITS
+ itemDef
+ {
+ name "credits"
+ rect 515 402 45 11.25
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.5
+ ownerdraw CG_PLAYER_CREDITS_VALUE
+ }
+
+ //HEALTH
+ itemDef
+ {
+ name "health"
+ rect 67 430 60 15
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B .5
+ ownerdraw CG_PLAYER_HEALTH
+ }
+
+ //WEAPON ICON
+ itemDef
+ {
+ name "weapon"
+ rect 482.5 425 25 25
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.5
+ ownerdraw CG_PLAYER_WEAPONICON
+ }
+
+ //WEAPON SELECT TEXT
+ itemDef
+ {
+ name "selecttext"
+ rect 200 300 240 25
+ aspectBias ALIGN_CENTER
+ visible MENU_TRUE
+ decoration
+ textScale .5
+ ownerdraw CG_PLAYER_SELECTTEXT
+ textstyle ITEM_TEXTSTYLE_SHADOWED
+ }
+
+ //AMMO
+ itemDef
+ {
+ name "ammo"
+ rect 507 430 53 15
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B .5
+ ownerdraw CG_PLAYER_AMMO_VALUE
+ }
+
+ //CLIPS
+ itemDef
+ {
+ name "clips"
+ rect 538 423 60 15
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B .5
+ ownerdraw CG_PLAYER_CLIPS_VALUE
+ }
+
+ //BUILD TIMER
+ itemDef
+ {
+ name "buildtimer"
+ rect 580 417.5 25 25
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B .5
+ ownerdraw CG_PLAYER_BUILD_TIMER
+ }
+
+ //USABLE
+ itemDef
+ {
+ name "usable"
+ rect 307.5 380 25 25
+ aspectBias ALIGN_CENTER
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B .5
+ background "ui/assets/neutral/use.tga"
+ ownerdraw CG_PLAYER_USABLE_BUILDABLE
+ }
+
+ //SCANNER
+ itemDef
+ {
+ name "scanner"
+ rect 164 340 312 72
+ aspectBias ALIGN_CENTER
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B .5
+ background "ui/assets/human/scanner.tga"
+ ownerdraw CG_PLAYER_HUMAN_SCANNER
+ }
+
+ //INVENTORY
+ itemDef
+ {
+ name "inventory"
+ rect 182.5 425 275 25
+ aspectBias ALIGN_CENTER
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.5
+ ownerdraw CG_PLAYER_SELECT
+ }
+
+ //CHARGE BAR
+ itemDef
+ {
+ name "charge"
+ rect 510 384 56 8
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.5
+ ownerdraw CG_PLAYER_CHARGE_BAR
+ background "ui/assets/neutral/charge_cap_h.tga"
+ }
+
+ //CHARGE BAR BG
+ itemDef
+ {
+ name "chargebg"
+ rect 506 380 64 16
+ aspectBias ALIGN_RIGHT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ ownerdraw CG_PLAYER_CHARGE_BAR_BG
+ background "ui/assets/neutral/charge_bg_h.tga"
+ }
+
+ //SELECTED
+ itemDef
+ {
+ name "selected"
+ rect 306 424 27 27
+ aspectBias ALIGN_CENTER
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/neutral/selected.tga"
+ }
+
+ //TEAM OVERLAY
+ itemDef
+ {
+ name "teamoverlay"
+ rect BORDER 175 200 128
+ style WINDOW_STYLE_EMPTY
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.75
+ textscale 0.85
+ ownerdraw CG_TEAMOVERLAY
+ }
+ }
+}
diff --git a/assets/ui/tremulous_humanarmoury.menu b/assets/ui/tremulous_humanarmoury.menu
new file mode 100644
index 0000000..2df829f
--- /dev/null
+++ b/assets/ui/tremulous_humanarmoury.menu
@@ -0,0 +1,189 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 550
+#define H 250
+#define BORDER 10
+#define LIST_W 140
+#define LIST_H (H-(2*BORDER))
+#define LIST_LX BORDER
+#define LIST_LY BORDER
+#define LIST_RX (W-(BORDER+LIST_W))
+#define LIST_RY BORDER
+
+#define BUTT_H 25
+#define BUTT_Y (H-(BORDER+BUTT_H))
+
+#define INFO_W (W-((4*BORDER)+(2*LIST_W)))
+#define INFO_H (H-((3*BORDER)+BUTT_H))
+#define INFO_X ((2*BORDER)+LIST_W)
+#define INFO_Y BORDER
+#define INFO_TOFF 6
+
+#define BUTT_X INFO_X
+#define BUTT_W (INFO_W/3)
+
+ menuDef
+ {
+ name "tremulous_humanarmoury"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ popup
+ onOpen
+ {
+ uiScript LoadHumanArmouryBuys;
+ uiScript LoadHumanArmourySells;
+ setFocus list
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name "buylist"
+ rect LIST_LX LIST_LY LIST_W LIST_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_TREMHUMANARMOURYBUY
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ resetonfeederchange
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript BuyFromArmoury;
+ }
+ }
+
+ itemDef
+ {
+ name "selllist"
+ rect LIST_RX LIST_RY LIST_W LIST_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_TREMHUMANARMOURYSELL
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ resetonfeederchange
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript SellToArmoury;
+ }
+ }
+
+ itemDef
+ {
+ name infopane
+ ownerdraw UI_HBUYINFOPANE
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ textscale .33
+ textalign ALIGN_LEFT
+ textvalign VALIGN_TOP
+ textalignx INFO_TOFF
+ textaligny INFO_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name "Buy"
+ text "Buy >"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect BUTT_X BUTT_Y BUTT_W BUTT_H
+ textalign ALIGN_LEFT
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript BuyFromArmoury;
+ }
+ }
+
+ itemDef
+ {
+ name "Close"
+ text "Close"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (BUTT_X+BUTT_W) BUTT_Y BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu4.wav";
+ close tremulous_humanarmoury
+ }
+ }
+
+ itemDef
+ {
+ name "Sell"
+ text "< Sell"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (BUTT_X+(2*BUTT_W)) BUTT_Y BUTT_W BUTT_H
+ textalign ALIGN_RIGHT
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript SellToArmoury;
+ }
+ }
+ }
+}
diff --git a/assets/ui/tremulous_humanbuild.menu b/assets/ui/tremulous_humanbuild.menu
new file mode 100644
index 0000000..572957b
--- /dev/null
+++ b/assets/ui/tremulous_humanbuild.menu
@@ -0,0 +1,135 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 450
+#define H 250
+#define BORDER 10
+
+#define LIST_W 140
+#define LIST_H (H-(2*BORDER))
+#define LIST_X BORDER
+#define LIST_Y BORDER
+
+#define BUTT_H 25
+#define BUTT_W 45
+
+#define INFO_W (W-((3*BORDER)+LIST_W))
+#define INFO_H (H-((3*BORDER)+BUTT_H))
+#define INFO_X ((2*BORDER)+LIST_W)
+#define INFO_Y BORDER
+#define INFO_TOFF 6
+
+ menuDef
+ {
+ name "tremulous_humanbuild"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ popup
+ onOpen { uiScript LoadHumanBuilds; setFocus list }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name "list"
+ rect LIST_X LIST_Y LIST_W LIST_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_TREMHUMANBUILD
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript BuildHumanBuildable;
+ close tremulous_humanbuild
+ }
+ }
+
+ itemDef
+ {
+ name infopane
+ ownerdraw UI_HBUILDINFOPANE
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ textscale .33
+ textalign ALIGN_LEFT
+ textvalign VALIGN_TOP
+ textalignx INFO_TOFF
+ textaligny INFO_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-((2*BORDER)+(2*BUTT_W))) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript BuildHumanBuildable;
+ close tremulous_humanbuild
+ }
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "Cancel"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ close tremulous_humanbuild
+ }
+ }
+ }
+}
diff --git a/assets/ui/tremulous_humandialogs.menu b/assets/ui/tremulous_humandialogs.menu
new file mode 100644
index 0000000..96ba08a
--- /dev/null
+++ b/assets/ui/tremulous_humandialogs.menu
@@ -0,0 +1,98 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 280
+#define H 190
+#define BORDER 10
+
+#define BUTT_H 25
+#define BUTT_W 45
+
+#define INFO_W (W-(2*BORDER))
+#define INFO_H (H-((4*BORDER)+(2*BUTT_H)))
+#define INFO_X BORDER
+#define INFO_Y ((2*BORDER)+BUTT_H)
+#define INFO_TOFF 6
+
+ menuDef
+ {
+ name "tremulous_human_dialog"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_EMPTY
+ popup
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name human_dialog
+ text "Error"
+ type ITEM_TYPE_TEXT
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect BORDER BORDER INFO_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name human_dialog
+ type ITEM_TYPE_TEXT
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ cvar "ui_dialog"
+ wrapped
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .33
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name human_dialog
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ close tremulous_human_dialog
+ }
+ }
+ }
+}
diff --git a/assets/ui/tremulous_humanitem.menu b/assets/ui/tremulous_humanitem.menu
new file mode 100644
index 0000000..551334b
--- /dev/null
+++ b/assets/ui/tremulous_humanitem.menu
@@ -0,0 +1,157 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 450
+#define H 250
+#define BORDER 10
+
+#define LIST_W 140
+#define LIST_H (H-(2*BORDER))
+#define LIST_X BORDER
+#define LIST_Y BORDER
+
+#define BUTT_H 25
+#define BUTT_W 45
+
+#define INFO_W (W-((3*BORDER)+LIST_W))
+#define INFO_H (H-((3*BORDER)+BUTT_H))
+#define INFO_X ((2*BORDER)+LIST_W)
+#define INFO_Y BORDER
+#define INFO_TOFF 6
+
+ menuDef
+ {
+ name "tremulous_humanitem"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ popup
+ onOpen { uiScript LoadHumanItems; setFocus list }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name "list"
+ rect LIST_X LIST_Y LIST_W LIST_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_TREMHUMANITEMS
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript SpawnWithHumanItem;
+ close tremulous_humanitem
+ }
+ }
+
+ itemDef
+ {
+ name infopane
+ ownerdraw UI_HITEMINFOPANE
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ textscale .33
+ textalign ALIGN_LEFT
+ textvalign VALIGN_TOP
+ textalignx INFO_TOFF
+ textaligny INFO_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name "Back"
+ text "< Back"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect ((2*BORDER)+LIST_W) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu4.wav";
+ close tremulous_humanitem;
+ open tremulous_teamselect
+ }
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-((2*BORDER)+(2*BUTT_W))) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript SpawnWithHumanItem;
+ close tremulous_humanitem
+ }
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "Cancel"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ close tremulous_humanitem
+ }
+ }
+ }
+}
diff --git a/assets/ui/tremulous_spectator_hud.menu b/assets/ui/tremulous_spectator_hud.menu
new file mode 100644
index 0000000..b4a5ff1
--- /dev/null
+++ b/assets/ui/tremulous_spectator_hud.menu
@@ -0,0 +1,52 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 640
+#define H 480
+
+ menuDef
+ {
+ name "spectator_hud"
+ fullScreen MENU_FALSE
+ visible MENU_TRUE
+ rect 0 0 W H
+ aspectBias ASPECT_NONE
+
+#define COMMON_HUD_R 1.0
+#define COMMON_HUD_G 1.0
+#define COMMON_HUD_B 1.0
+#include "ui/tremulous_common_hud.h"
+
+ //////////////////
+ //STATIC OBJECTS//
+ //////////////////
+
+ //LEFT CIRCLE
+ itemDef
+ {
+ name "left-circle"
+ rect 35 417.5 25 25
+ aspectBias ALIGN_LEFT
+ visible MENU_TRUE
+ decoration
+ forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B 0.25
+ style WINDOW_STYLE_SHADER
+ background "ui/assets/neutral/circle.tga"
+ }
+
+ //THZ SCANNER
+ itemDef
+ {
+ name "thzscanner"
+ //rect 10 125 200 200 // Original placement in thz
+ rect 440 220 200 200
+ aspectBias ALIGN_CENTER
+ visible MENU_TRUE
+ decoration
+ //forecolor COMMON_HUD_R COMMON_HUD_G COMMON_HUD_B .5
+ background "ui/assets/human/scanner.tga"
+ ownerdraw CG_PLAYER_THZ_SCANNER
+ }
+ }
+}
diff --git a/assets/ui/tremulous_teamselect.menu b/assets/ui/tremulous_teamselect.menu
new file mode 100644
index 0000000..7051274
--- /dev/null
+++ b/assets/ui/tremulous_teamselect.menu
@@ -0,0 +1,136 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 450
+#define H 250
+#define BORDER 10
+
+#define LIST_W 140
+#define LIST_H (H-(2*BORDER))
+#define LIST_X BORDER
+#define LIST_Y BORDER
+
+#define BUTT_H 25
+#define BUTT_W 45
+
+#define INFO_W (W-((3*BORDER)+LIST_W))
+#define INFO_H (H-((3*BORDER)+BUTT_H))
+#define INFO_X ((2*BORDER)+LIST_W)
+#define INFO_Y BORDER
+#define INFO_TOFF 6
+
+ menuDef
+ {
+ name "tremulous_teamselect"
+ visible MENU_FALSE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ popup
+ onOpen { uiScript LoadTeams; setFocus list }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 1
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name "list"
+ rect LIST_X LIST_Y LIST_W LIST_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_TREMTEAMS
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript JoinTeam;
+ close tremulous_teamselect
+ }
+ }
+
+ itemDef
+ {
+ name infopane
+ ownerdraw UI_TEAMINFOPANE
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ textscale .33
+ textalign ALIGN_LEFT
+ textvalign VALIGN_TOP
+ textalignx INFO_TOFF
+ textaligny INFO_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 1
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-((2*BORDER)+(2*BUTT_W))) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript JoinTeam;
+ close tremulous_teamselect
+ }
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "Cancel"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ close tremulous_teamselect
+ }
+ }
+ }
+}
diff --git a/assets/ui/tremulous_voicecmd.menu b/assets/ui/tremulous_voicecmd.menu
new file mode 100644
index 0000000..1b5ac8b
--- /dev/null
+++ b/assets/ui/tremulous_voicecmd.menu
@@ -0,0 +1,140 @@
+#include "ui/menudef.h"
+
+{
+
+#define W 450
+#define H 300
+#define BORDER 10
+
+#define LIST_W 140
+#define LIST_H (H-(2*BORDER))
+#define LIST_X BORDER
+#define LIST_Y BORDER
+
+#define BUTT_H 25
+#define BUTT_W 45
+
+#define INFO_W (W-((3*BORDER)+LIST_W))
+#define INFO_H (H-((3*BORDER)+BUTT_H))
+#define INFO_X ((2*BORDER)+LIST_W)
+#define INFO_Y BORDER
+#define INFO_TOFF 6
+
+ menuDef
+ {
+ name "tremulous_voicecmd"
+ visible MENU_TRUE
+ fullscreen MENU_FALSE
+ outOfBoundsClick
+ rect (320-(W/2)) (240-(H/2)) W H
+ focusColor 1 .75 0 1
+ style WINDOW_STYLE_FILLED
+ popup
+ onOpen
+ {
+ uiScript LoadVoiceCmds;
+ setFocus list
+ }
+
+ itemDef
+ {
+ name window
+ rect 0 0 W H
+ style WINDOW_STYLE_FILLED
+ backcolor 0 0 0 .75
+ visible MENU_TRUE
+ decoration
+
+ border WINDOW_BORDER_FULL
+ borderSize 1.0
+ borderColor 0.5 0.5 0.5 1
+ }
+
+ itemDef
+ {
+ name "list"
+ rect LIST_X LIST_Y LIST_W LIST_H
+ type ITEM_TYPE_LISTBOX
+ style WINDOW_STYLE_EMPTY
+ elementwidth 120
+ elementheight 20
+ textscale .33
+ elementtype LISTBOX_TEXT
+ feeder FEEDER_TREMVOICECMD
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 .75
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ doubleclick
+ {
+ play "sound/misc/menu1.wav";
+ uiScript ExecuteVoiceCmd;
+ close tremulous_voicecmd
+ }
+ }
+
+ itemDef
+ {
+ name infopane
+ ownerdraw UI_VOICECMDINFOPANE
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ style WINDOW_STYLE_EMPTY
+ rect INFO_X INFO_Y INFO_W INFO_H
+ textscale .33
+ textalign ALIGN_LEFT
+ textvalign VALIGN_TOP
+ textalignx INFO_TOFF
+ textaligny INFO_TOFF
+ border WINDOW_BORDER_FULL
+ bordercolor 0.5 0.5 0.5 0.5
+ forecolor 1 1 1 1
+ backcolor 0.2 0.2 0.2 .75
+ outlinecolor 0.1 0.1 0.1 0.5
+ visible MENU_TRUE
+ decoration
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "OK"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-((2*BORDER)+(2*BUTT_W))) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu1.wav";
+ uiScript ExecuteVoiceCmd;
+ close tremulous_voicecmd
+ }
+ }
+
+ itemDef
+ {
+ name "OKCancel"
+ text "Cancel"
+ type ITEM_TYPE_BUTTON
+ style WINDOW_STYLE_EMPTY
+ rect (W-(BORDER+BUTT_W)) (H-(BORDER+BUTT_H)) BUTT_W BUTT_H
+ textalign ALIGN_CENTER
+ textvalign VALIGN_CENTER
+ textscale .4
+ forecolor 1 1 1 1
+ backcolor .5 0 0 .25
+ visible MENU_TRUE
+ action
+ {
+ play "sound/misc/menu3.wav";
+ close tremulous_voicecmd
+ }
+ }
+ }
+}
diff --git a/cmake/AddQVM.cmake b/cmake/AddQVM.cmake
new file mode 100644
index 0000000..84de0c7
--- /dev/null
+++ b/cmake/AddQVM.cmake
@@ -0,0 +1,73 @@
+
+include(CMakeParseArguments)
+
+set(QVM_TOOLS_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/qvm_tools)
+set(Q3CPP_BINARY ${QVM_TOOLS_DIR}/q3cpp )
+set(Q3RCC_BINARY ${QVM_TOOLS_DIR}/q3rcc )
+set(Q3LCC_BINARY ${QVM_TOOLS_DIR}/q3lcc )
+set(Q3ASM_BINARY ${QVM_TOOLS_DIR}/q3asm )
+
+set(QVM_DEPS ${Q3ASM_BINARY} ${Q3CPP_BINARY} ${Q3LCC_BINARY} ${Q3RCC_BINARY})
+
+macro(QVM_COMPILE_ASM defs outfile infile)
+ add_custom_command(
+ OUTPUT ${outfile}
+ COMMAND ${Q3LCC_BINARY}
+ ARGS ${ADD_QVM_D} -o ${outfile} ${infile}
+ DEPENDS ${QVM_DEPS}
+ )
+ set_source_files_properties(${outfile} PROPERTIES GENERATED TRUE)
+endmacro()
+
+macro(ADD_QVM Name)
+ cmake_parse_arguments(ADD_QVM "" "" "" ${ARGN})
+
+ #message( "QVM: ${Name}" )
+
+ string(TOUPPER ${Name} UPNAME)
+ set(defs "-DVMS -D${UPNAME}")
+
+ #message( "DEFINITIONS ${defs}" )
+
+ foreach(srcfile ${ADD_QVM_UNPARSED_ARGUMENTS})
+ #message( "> ${srcfile}" )
+
+ get_filename_component(ext ${srcfile} EXT)
+ if ("${ext}" STREQUAL ".asm")
+ set(outfile ${CMAKE_CURRENT_SOURCE_DIR}/${srcfile})
+ # Add asm files directly
+ list(APPEND srcs ${outfile})
+ endif()
+
+ if ("${ext}" STREQUAL ".c")
+ get_filename_component(outfile ${srcfile} NAME_WE)
+ set(outfile ${outfile}.asm)
+ # compile C code into asm
+ qvm_compile_asm(${defs} ${outfile} ${CMAKE_CURRENT_SOURCE_DIR}/${srcfile})
+ # add asm to list
+ list(APPEND srcs ${outfile})
+ endif()
+
+ if ("${ext}" STREQUAL ".h")
+ # XXX: Ignore headers??
+ endif()
+ endforeach()
+
+ #message("SOURCES <${srcs}>")
+
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${Name}.qvm
+ COMMAND ${Q3ASM_BINARY}
+ ARGS -o ${Name}.qvm ${srcs}
+ DEPENDS ${Q3ASM_BINARY} ${srcs}
+ )
+ add_custom_target(${Name}.qvm DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${Name}.qvm)
+endmacro()
+#
+#============================================================
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(QVM
+ REQUIRED_VARS Q3LCC_BINARY Q3ASM_BINARY
+ )
diff --git a/cmake/SDL2.cmake b/cmake/SDL2.cmake
new file mode 100644
index 0000000..a18a3a5
--- /dev/null
+++ b/cmake/SDL2.cmake
@@ -0,0 +1,13 @@
+if(USE_INTERNAL_SDL2)
+ set(SDL2_DEFINES "-DUSE_LOCAL_HEADERS=1")
+ set(SDL2_PREFIX "${CMAKE_SOURCE_DIR}/external/SDL2")
+ set(SDL2_INCLUDE_DIRS "${SDL2_PREFIX}/include")
+ set(SDL2_LIBRARIES "-L${SDL2_PREFIX}/libs/${CMAKE_SYSTEM_NAME} -lSDL2-2.0.0")
+else(USE_INTERNAL_SDL2)
+ set(SDL2_PREFIX "/usr")
+ if(APPLE)
+ set(SDL2_PREFIX "/usr/local")
+ endif(APPLE)
+ set(SDL2_INCLUDE_DIRS "${SDL2_PREFIX}/include/SDL2")
+ set(SDL2_LIBRARIES "-L${SDL2_PREFIX} -lSDL2")
+endif(USE_INTERNAL_SDL2)
diff --git a/cmake/build_dir b/cmake/build_dir
new file mode 100644
index 0000000..b86b288
--- /dev/null
+++ b/cmake/build_dir
@@ -0,0 +1,17 @@
+# vim:ft=cmake
+
+if (NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release)
+endif()
+
+set(CMAKE_OSX_ARCHITECTURES ${CMAKE_SYSTEM_PROCESSOR})
+
+string( TOLOWER "${CMAKE_BUILD_TYPE}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}"
+ BUILD_ASSETS_DIR)
+
+set(CMAKE_BINARY_DIR ${CMAKE_BINARY_DIR}/${BUILD_ASSETS_DIR})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+#set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BUILD_ASSETS_DIR})
+#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BUILD_ASSETS_DIR})
+
diff --git a/cmake/debug_cflags b/cmake/debug_cflags
new file mode 100644
index 0000000..d383256
--- /dev/null
+++ b/cmake/debug_cflags
@@ -0,0 +1,4 @@
+# vim:ft=cmake
+set(DEBUG_FLAGS "-O0 -g3 -fsanitize=address -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/misc/blacklist.txt -fno-omit-frame-pointer")
+set(CMAKE_C_FLAGS_DEBUG ${DEBUG_FLAGS})
+set(CMAKE_CXX_FLAGS_DEBUG ${DEBUG_FLAGS})
diff --git a/code_of_conduct.md b/code_of_conduct.md
new file mode 100644
index 0000000..93a7a34
--- /dev/null
+++ b/code_of_conduct.md
@@ -0,0 +1,71 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+nationality, personal appearance, race, religion, or sexual identity and
+orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project maintainer at victor@badsec.org. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
+available at http://contributor-covenant.org/version/1/4/
diff --git a/docs/Features.md b/docs/Features.md
new file mode 100644
index 0000000..1c228da
--- /dev/null
+++ b/docs/Features.md
@@ -0,0 +1,93 @@
+# Windows, Linux and OSX
+
+The GrangerHub Tremulous engine is supported on Windows, Linux and OSX. Builds
+are automaticly produced by our CI/CD system.
+
+# CI/CD
+
+The Tremulous engine is supported by a CI/CD (Continuous Integration/Continous
+Delivery) using TravisCI and Github. Each time commits are pushed to the github
+repository, TravisCI will verify that each of the MacOSX, Linux and Windows builds
+are successful. Releases are generated automatically anytime a tag is pushed to
+the repository; TravisCI will then package the build with the assets and push
+the build artifacts to the Github releases page. Upon completion a notification
+is sent to the GrangerHub Slack.
+
+Hilights:
+* TravisCI
+* Automated builds
+* Automated release generation
+
+TODO:
+* Add Appveyor
+* Reenable Coverity scans
+
+# CMake support
+
+A CMake system exists to build Tremulous on Linux and OSX. The CMake setup also
+supports building QVM's using the in-tree QVM toolchain.
+
+TODO:
+* Windows
+* Appveyor Windows builds
+
+
+# C++14
+
+The engine has been modernized to compile at the C++14 standard. This was originally
+done to simplify supporting Lua using the SOL2 Library, however this conversion has
+also resulted in a significantly improved stability due to better memory initialization.
+It's worth noting that the renderer's have not been converted to C++14 as we currently
+piggyback off ioquake3's renderer's (maintained by SmileTheory).
+
+# Lua
+
+The engine has an embedded Lua runtime and several API's are exposed from the engine,
+including:
+
+* Cvars
+* Binds
+* Passing commands to server
+* Nettle (Crypto library)
+* HTTP Client/Restful
+* JSON (rapidjson)
+
+# Multi-protocol
+
+Support for Tremulous 1.1.0, Tremulous 1.2.0 (GPP) and the never released version from
+DarkLegion's master branch are supported. A client can connect to any of those protocols.
+A server can simultaneously serve to all those protocols. QVM version detection on the client
+which magically determines the correct interface required for a QVM.
+
+This work is thanks to `/dev/humancontroller`.
+
+# Auto-update
+
+Autoupdates are not fully functional, problems with the minizip implementation require additional
+work to work.
+
+Users can however check the latests updates from the main menu in the client, which queries the
+GrangerHub github for the latest release.
+
+TODO:
+ * Lua library for ZIP files that preserves executable permissions
+
+# Restful HTTP Client
+
+An HTTP Rest API is provided to both C++ and Lua interfaces.
+
+
+# JSON Support
+
+JSON support is provided via the lovely RapidJSON project. An interfaces is provided for both
+C++ and Lua.
+
+# Filesystem Stability
+
+The filesystem has been refactored to be stable from startup. It is not possible for a server to
+clobber the default QVM/UI.
+
+FIXME:
+ * Currently breaks mod loading support from the client main menu.
+
+
diff --git a/docs/LuaScripting.md b/docs/LuaScripting.md
new file mode 100644
index 0000000..4bde0d8
--- /dev/null
+++ b/docs/LuaScripting.md
@@ -0,0 +1,13 @@
+# Lua Scripting
+
+Purpose:
+Documentation regarding the Lua API's in depth. lua/README.md is for jumpping
+in _head first!_. What is possible, and maybe some "Shipping" scripts that might be
+released.
+
+This file should be the reference/bible to the Lua runtime API. More boring, answers
+questions, doesn't tell many jokes etc..
+
+
+TODO: All of it
+
diff --git a/docs/ParticleSystem.md b/docs/ParticleSystem.md
new file mode 100644
index 0000000..e93843f
--- /dev/null
+++ b/docs/ParticleSystem.md
@@ -0,0 +1,160 @@
+
+# Tremulous Particle System
+
+Files matching the pattern `scripts/*.particle` are loaded as particle system description files.
+Each `.particle` file can contain an arbitrary number of discrete particle systems, much like a `.shader` file can house many shaders.
+A particle system is declared by a name followed by curly braces within which the functionality of the particle system is defined.
+
+For example:
+
+```
+aShinyNewParticleSystem { }
+```
+
+Inside the particle system declaration are placed UP TO *four* particle ejectors.
+Ejectors are identified by the keyword ejector and curly braces:
+
+```
+aShinyNewParticleSystem
+{
+ ejector { }
+
+ ejector { }
+
+ thirdPersonOnly
+}
+```
+
+The `thirdPersonOnly` keyword may be used to specify that the particle system is not visible from the first person if it relates to that client.
+
+The role of the particle ejector is to create some number of new particles at a defined rate.
+ These attributes are controlled by the following parameters:
+
+- count `<number>|infinite` - the number of particles this ejector will spawn.
+- delay `<msec>` - the delay in msec before the ejector starts spawning.
+- period `<initial> <final> <variance>` - the period between particle ejections.
+
+It is perfectly acceptable to have an initial period of zero.
+In this case the number of particles specified by the count keyword will be ejected at once.
+It is not permissible to have count infinite and a period of zero for obvious reasons.
+
+At ejection time each ejector creates up to four new particles based on templates.
+These are specified in the ejector section using the particle keyword:
+
+```
+aShinyNewParticleSystem
+{
+ ejector
+ {
+ particle { }
+
+ particle { }
+
+ count 50
+ delay 0
+ period 0 - 0
+ }
+}
+```
+
+Each particle template has a number of attributes:
+
+- `shader <fps>|sync <shader1 <shader2> ... <shaderN>` - this specifies the shaders to use for the particle. The frame rate can be set to a static rate or the sync parameter can be used in which case the frame rate will be synchronised to the lifetime of the particle such that the first frame is displayed on birth and the last frame is displayed immediately before death.
+- `model <model1> <model2> ... <modelN>` - use one of the specified models as the particle. This cannot be used in conjunction with the shader keyword.
+- `modelAnmation <firstFrame> <numFrames> <loopFrames> <fps>|sync` - animation parameters to use when model particles are employed.
+- `displacement <x> <y> <z> <variance>` - a static displacement about the attachment point. The variance parameter specifies a random displacement in all axes.
+- `normalDisplacement <displacement>` - for particle systems that have their normal set (impact particle systems for example) this specifies the magnitude of a displacement along the normal.
+- `velocityType static|static_transform|tag|cent|normal` - this specifies how the particle will compute its initial velocity. `static` means it is specified statically in the `.particle` file, `static_transform` means the same, except that it is transformed by the orientation matrix of what it is attached to, `tag` means the velocity is in the direction of the tag it is attached to, `cent` means the velocity is in the direction of the cent it is attached to and `normal` means the velocity is in the direction of the particle system normal.
+- `velocityDir linear|point` - this specifies whether the initial velocity is computed as a simple direction or as the direction towards a secondary point (defined by `velocityPoint` or dynamically through `velocityType cent`).
+- `velocity <x> <y> <z> <variance>` - for when `velocityType static` is present this specifies the direction. The variance here is specified in degrees e.g. `~5` - up to 5 degrees deviation.
+- `velocityMagnitude <magnitude>` - the magnitude of the velocity.
+- `velocityPoint <x> <y> <z> <variance>` - for when `velocityType static` and `velocityDir point` are present this specifies the point to move towards.
+- `parentVelocityFraction <fraction>` - for when the particle system is attached to a cent this specifies the fraction of the cent’s velocity that is added to the particle’s velocity.
+- `accelerationType static|static_transform|tag|cent|normal` - this specifies how the particle will compute its acceleration. `static` means it is specified statically in the `.particle` file, `static_transform` means the same, except that it is transformed by the orientation matrix of what it is attached to, `tag` means the acceleration is in the direction of the tag it is attached to, `cent` means the acceleration is in the direction of the cent it is attached to and `normal` means the acceleration is in the direction of the particle system normal.
+- `accelerationDir linear|point` - this specifies whether the acceleration is computed as a simple direction or as the direction towards a secondary point (defined by `accelerationPoint` or dynamically through `accelerationType cent`).
+- `acceleration <x> <y> <z> <variance>` - for when accelerationType static is present this specifies the direction. The variance here is specified in degrees e.g. `~5` - up to 5 degrees deviation.
+- `accelerationMagnitude <magnitude>` - the magnitude of the acceleration.
+- `accelerationPoint <x> <y> <z> <variance>` - for when accelerationType static and accelerationDir point are present this specifies the point to move towards.
+- `bounce <fraction>|cull` - the fraction of velocity that is refiected when a particle collides. If this is set to `0.0` the particle won't collide. When cull is used particles are culled as soon as they collide with objects.
+- `bounceMark <count> <radius> <shader>` - make a mark at each bounce point for up to `<count>` bounces.
+- `bounceSound <count> <sound>` - make a sound at each bounce point for up to `<count>` bounces.
+- `dynamicLight <delayRadius> <initialRadius> <finalRadius> { <r> <g> <b> }` - attach a dynamic light to this particle.
+- `color <delay> { <ir> <ig> <ib> } { <fr> <fg> <fb> }` - color the particle where `<i.>` refers to the initial color component and `<f.>` refers to the final color component.
+- `overdrawProtection` - cull particles that occupy a large amount of screen space.
+- `realLight` - light particles using the lightgrid instead of fullbright.
+- `cullOnStartSolid` - cull particles that are spawned inside brushes.
+- `radius <delay> <initial> <final>` - the radius of the particle throughout its lifetime. The delay parameter specifies the time in msec before radius scaling begins. The initial and final parameters specify the radii of the particle in quake units.
+- `alpha <delay> <initial> <final>` - the alpha of the particle throughout its lifetime. The delay parameter specifies the time in msec before alpha scaling begins. The initial and final parameters specify the alpha of the particle where `1.0` is totally opaque and `0.0` is totally transparent.
+- `rotation <delay> <initial> <final>` - the rotation of the particle throughout its lifetime. The delay parameter specifies the time in msec before the rotation begins. The initial and final parameters specify the rotation of the particle in degrees.
+- `lifeTime <time>` - the lifetime of the particle.
+- `childSystem <particle system>` - specifies a particle system to attach to this particle.
+- `childTrailSystem <trail system>` - specifies a trail system to attach to this particle.
+- `onDeathSystem <particle system>` - specifies a particle system to spawn at the point where this particle died.
+- `physicsRadius` - ???
+- `scaleWithCharge` - ???
+
+Except for vector components, shader fps ... and `period <initial><final> <variance>`, every value can be specified with a random variance.
+The syntax for this is as follows:
+
+```
+ [value][variance[%]]
+```
+So the following forms are possible, where random is a random number between `0.0` and `1.0` inclusive:
+
+```
+ 5.0 // 5.0
+
+ 5.0~8.0 // 5.0 + ( random * 8.0 )
+
+ 5.0~200% // 5.0 + ( random * 5.0 * 200% )
+
+ ~7.0 // random * 7.0
+```
+
+This allows for relatively fiexible randomisation of most of the particle’s parameters. For parameters taking an initial and final value, specifying the final value as '`-`' will result in a final value the same as the initial value.
+
+For the purposes of map based particle systems using `misc_particle_system` it is safe to ignore `velocityType` and `accelerationType tag|cent|normal`, `normalDisplacement` and `parentVelocityFraction` altogether.
+
+Of course, it is not necessary to specify every parameter documented here for every particle system.
+If a parameter is not included it will usually default to zero.
+C/C++ style comments can be used throughout.
+There are an enormous number of possible combinations of particle systems parameters and as such it is impractical to test them all.
+For this reason it is possible that certain permutations do not behave as expected or wrongly.
+In this case you may have discovered a bug - let us know.
+Having said this when you’re having problems with a particle system make sure you scroll up the console and check that it compiled OK, I’ve written the parser to be very intolerant of error.
+
+Here is an example particle system:
+
+```
+aShinyNewParticleSystem
+{
+ ejector
+ {
+ particle
+ {
+ shader sync shader1 shader2
+
+ velocityType static
+ velocityDir linear
+ velocityMagnitude 200
+ velocity 0 0 1 ~30
+
+ accelerationType static
+ accelerationDir linear
+ accelerationMagnitude 50
+ acceleration 0 0 1 ~0
+
+ radius 0 10.0 50.0
+ alpha 0 1.0 1.0
+ rotation 0 ~360 -
+ bounce 0.4
+
+ lifeTime 1500
+ }
+
+ count 50
+ delay 0
+ period 0 - 0
+ }
+}
+```
diff --git a/docs/PlayerVars.md b/docs/PlayerVars.md
new file mode 100644
index 0000000..b2ec8d2
--- /dev/null
+++ b/docs/PlayerVars.md
@@ -0,0 +1,15 @@
+## Player Vars
+
+* `player_hp` - Your current HP
+* `player_maxhp` - The maximum HP for your class
+* `player_credits` - The number of credits/evos you currently hold
+* `player_score` - Your current score on the board
+* `player_attackername` - Name of the player who last attacked you
+* `player_crosshairname` - Name of the player in your crosshairs
+
+## Team Vars
+
+* `team_bp` - Your teams remaining available build points
+* `team_kns` - Number of kills till your team advances to the next stage
+* `team_teamname` - Human readable of your team name (i.e., "humans", "aliens" or "spectator")
+* `team_stage` - Your teams current stage (1, 2 or 3. 0 for spectators)
diff --git a/docs/TrailSystem.md b/docs/TrailSystem.md
new file mode 100644
index 0000000..a8b0257
--- /dev/null
+++ b/docs/TrailSystem.md
@@ -0,0 +1,44 @@
+# Trail System
+
+Note that as of Tremulous 1.1.0 there is no way to trigger a trail system with map entities.
+However, a trail system can be attached to a Particle System with the `childTrailSystem` key.
+
+Files matching the pattern `scripts/*.trail` are loaded as trail system description files.
+Each `.trail` file can contain an arbitrary number of discrete trail systems, much like a `.shader` file can house many shaders.
+A trail system is declared by a name followed by curly braces within which the functionality of the trail system is defined. For example:
+
+```
+ aShinyNewTrailSystem { }
+```
+
+Inside the particle system declaration are placed up to four trail beams. Beams are identified by the keyword beam and curly braces:
+
+```
+ aShinyNewTrailSystem
+ {
+
+ beam { }
+
+ beam { }
+
+ thirdPersonOnly
+ }
+```
+
+The `thirdPersonOnly` keyword may be used to specify that the trail system is not visible from the first person if it relates to that client.
+
+A trail beam describes the appearance of one element of the trail system:
+
+- `shader <shader>` - the shader to use to texture this beam.
+- `segments <number>` - the number of quads that make up the beam.
+- `width <frontWidth> <backWidth>` - the width of the beam at the front and back.
+- `alpha <frontAlpha> <backAlpha>` - the alpha of the beam at the front and back.
+- `color { <fr> <fg> <fb> } { <br> <bg> <bb> }` - the color of the beam at the front and back.
+- `segmentTime <time>` - how long a single segment lasts when the trail is only attached at one end.
+- `fadeOutTime <time>` - how long this beam takes to fade away.
+- `textureType [stretch <frontTC> <backTC>][repeat [front|back] <repeatLength>]` - how to texture the beam. `stretch` causes the texture to be stretched from the front to the back using the specified texture coordinates. `repeat` causes the texture to be repeated over a specified length either from the front or the back.
+- `model <model1> <model2> ... <modelN>` - use one of the specified models as the particle. This cannot be used in conjunction with the shader keyword.
+- `modelAnmation <firstFrame> <numFrames> <loopFrames> <fps>sync` - animation parameters to use when model particles are employed.
+- `realLight` - light particles using the lightgrid instead of fullbright.
+- `jitter <magnitude> <period>` - this specifies a random jitter of the position of each beam node by magnitude every period.
+- `jitterAttachments` - if this is specified the end points of the beam are jittered as well as the intervening nodes.
diff --git a/docs/VoiceCommands.md b/docs/VoiceCommands.md
new file mode 100644
index 0000000..71aac37
--- /dev/null
+++ b/docs/VoiceCommands.md
@@ -0,0 +1,40 @@
+# Tremulous Voice Commands
+
+Files matching the pattern `voice/*.voice` are loaded automatically as "voices".
+Each `.voice` file can contain an arbitrary number of voice commands.
+
+The most important voice is the `default` or `default.voice`.
+Every player by default is assigned the `default` voice.
+
+A player can change they're voice by setting the `voice` userinfo cvar.
+
+```
+/setu voice bender
+```
+
+## Voice File Format
+
+```
+hailking
+{
+ "sound/player/ash/voice/aod-hailking.wav"
+ {
+ team 2
+ class 1
+ weapon 1
+ text "Hail to the king"
+ enthusiasm 0
+ }
+}
+```
+
+- "hailking" is the voice command. (i.e., `/vsay "hailking"`). Note that the maximum command length is 16 characters.
+- "sound/player/ash/voice/aod-hailking.wav" is the 1st "track".
+- "team" corresponds to the `team_t` enum in `bg_public.h`.
+- "class" corresponds to the `class_t` enum in `bg_public.h`.
+- "weapon" corresponds to the `weapon_t` enum in `bg_public.h`.
+- "text" is the text that will appear in chat when the voice command is issued.
+- "enthusiasm" needs to be tested
+
+
+I think "text" is the only *required* field.
diff --git a/docs/opengl2-readme.md b/docs/opengl2-readme.md
new file mode 100644
index 0000000..1b1db20
--- /dev/null
+++ b/docs/opengl2-readme.md
@@ -0,0 +1,604 @@
+# OpenGL2
+<insert ascii art here>
+
+OpenGL2 is an alternate renderer for ioquake3. It aims to implement modern
+features and technologies into the id tech 3 engine, but without sacrificing
+compatibility with existing Quake 3 mods.
+
+
+-------------------------------------------------------------------------------
+ FEATURES
+-------------------------------------------------------------------------------
+
+ - Compatible with most vanilla Quake 3 mods.
+ - HDR Rendering, and support for HDR lightmaps
+ - Tone mapping and auto-exposure.
+ - Cascaded shadow maps.
+ - Multisample anti-aliasing.
+ - Texture upsampling.
+ - Advanced materials support.
+ - Advanced shading and specular methods.
+ - RGTC and BPTC texture compression support.
+ - Screen-space ambient occlusion.
+
+
+-------------------------------------------------------------------------------
+ INSTALLATION
+-------------------------------------------------------------------------------
+
+For *nix:
+
+1. This should be identical to installing ioq3. Check their README for more
+ details.
+
+
+For Win32:
+
+1. Have a Quake 3 install, fully patched.
+
+2. Copy the following files into Quake 3's install directory:
+
+ ioquake3.x86.exe
+ renderer_opengl1_x86.dll
+ renderer_opengl2_x86.dll
+
+ These can be found in build/release-mingw32-x86 after compiling, or bug
+ someone to release binaries.
+
+
+-------------------------------------------------------------------------------
+ RUNNING
+-------------------------------------------------------------------------------
+
+1. Start ioquake3. (ioquake3.x86.exe on Win32)
+
+2. Open the console (the default key is tilde ~) and type
+`/cl_renderer opengl2` and press enter
+`/vid_restart` then press enter again.
+
+3. Enjoy.
+
+
+-------------------------------------------------------------------------------
+ CVARS
+-------------------------------------------------------------------------------
+
+Cvars for simple rendering features:
+
+* `r_ext_compressed_textures` - Automatically compress textures.
+ 0 - No texture compression. (default)
+ 1 - DXT/RGTC texture compression if
+ supported.
+ 2 - BPTC texture compression if supported.
+
+* `r_ext_framebuffer_multisample` - Multisample Anti-aliasing.
+ 0 - None. (default)
+ 1-16 - Some.
+ 17+ - Too much!
+
+* `r_ssao` - Enable screen-space ambient occlusion.
+ Currently eats framerate and has some
+ visible artifacts.
+ 0 - No. (default)
+ 1 - Yes.
+
+Cvars for HDR and tonemapping:
+
+ * `r_hdr` - Do scene rendering in a framebuffer with
+ high dynamic range. (Less banding, and
+ exposure changes look much better)
+ 0 - No.
+ 1 - Yes. (default)
+
+* `r_cameraExposure` - Cheat. Alter brightness, in powers of two.
+ -2 - 4x as dark.
+ 0 - Normal. (default)
+ 0.5 - Sqrt(2)x as bright.
+ 2 - 4x as bright.
+
+* `r_postProcess` - Enable post-processing.
+ 0 - No.
+ 1 - Yes. (default)
+
+* `r_toneMap` - Enable tone mapping. Requires
+ r_hdr and r_postProcess.
+ 0 - No.
+ 1 - Yes. (default)
+
+* `r_forceToneMap` - Cheat. Override built-in and map tonemap settings and use cvars r_forceToneMapAvg, r_forceToneMapMin, and r_forceToneMapMax.
+ 0 - No. (default)
+ 1 - Yes.
+
+* `r_forceToneMapAvg` - Cheat. Map average scene luminance to this
+ value, in powers of two. Requires
+ r_forceToneMap.
+ -2.0 - Dark.
+ -1.0 - Kinda dark. (default).
+ 2.0 - Too bright.
+
+* `r_forceToneMapMin` - Cheat. After mapping average, luminance
+ below this level is mapped to black.
+ Requires r_forceToneMap.
+ -5 - Not noticeable.
+ -3.25 - Normal. (default)
+ 0.0 - Too dark.
+
+* `r_forceToneMapMin` - Cheat. After mapping average, luminance
+ above this level is mapped to white.
+ Requires r_forceToneMap.
+ 0.0 - Too bright.
+ 1.0 - Normal. (default).
+ 2.0 - Washed out.
+
+* `r_autoExposure` - Do automatic exposure based on scene
+ brightness. Hardcoded to -2 to 2 on maps
+ that don't specify otherwise. Requires
+ r_hdr, r_postprocess, and r_toneMap.
+ 0 - No.
+ 1 - Yes. (default)
+
+* `r_forceAutoExposure` - Cheat. Override built-in and map auto
+ exposure settings and use cvars
+ r_forceAutoExposureMin and
+ r_forceAutoExposureMax.
+ 0 - No. (default)
+ 1 - Yes.
+
+* `r_forceAutoExposureMin` - Cheat. Set minimum exposure to this value,
+ in powers of two. Requires
+ r_forceAutoExpsure.
+ -3.0 - Dimmer.
+ -2.0 - Normal. (default)
+ -1.0 - Brighter.
+
+* `r_forceAutoExposureMax` - Cheat. Set maximum exposure to this value,
+ in powers of two. Requires
+ r_forceAutoExpsure.
+ 1.0 - Dimmer.
+ 2.0 - Normal. (default)
+ 3.0 - Brighter.
+
+Cvars for advanced material usage:
+
+* `r_normalMapping` - Enable normal maps for materials that
+ support it.
+ 0 - No.
+ 1 - Yes. (default)
+
+* `r_specularMapping` - Enable specular maps for materials that
+ support it.
+ 0 - No.
+ 1 - Yes. (default)
+
+* `r_deluxeMapping` - Enable deluxe mapping. (Map is compiled
+ with light directions.) Even if the map
+ doesn't have deluxe mapping compiled in,
+ an approximation based on the lightgrid
+ will be used.
+ 0 - No.
+ 1 - Yes. (default)
+
+* `r_parallaxMapping` - Enable parallax mapping for materials that
+ support it.
+ 0 - No. (default)
+ 1 - Use parallax occlusion mapping.
+ 2 - Use relief mapping. (slower)
+
+* `r_baseSpecular` - Set the specular reflectance of materials
+ which don't include a specular map or
+ use the specularReflectance keyword.
+ 0 - No.
+ 0.04 - Realistic. (default)
+ 1.0 - Ack.
+
+* `r_baseGloss` - Set the glossiness of materials which don't
+ include a specular map or use the
+ specularExponent keyword.
+ 0 - Rough.
+ 0.3 - Default.
+ 1.0 - Shiny.
+
+* `r_baseNormalX` - Set the scale of the X values from normal
+ maps when the normalScale keyword is not
+ used.
+ -1 - Flip X.
+ 0 - Ignore X.
+ 1 - Normal X. (default)
+ 2 - Double X.
+
+* `r_baseNormalY` - Set the scale of the Y values from normal
+ maps when the normalScale keyword is not
+ used.
+ -1 - Flip Y.
+ 0 - Ignore Y.
+ 1 - Normal Y. (default)
+ 2 - Double Y.
+
+* `r_baseParallax` - Sets the scale of the parallax effect for
+ materials when the parallaxDepth keyword
+ is not used.
+ 0 - No depth.
+ 0.01 - Pretty smooth.
+ 0.05 - Standard depth. (default)
+ 0.1 - Looks broken.
+
+* `r_pbr` - Enable physically based rendering.
+ Experimental, will not look correct without
+ assets meant for it.
+ 0 - No. (default)
+ 1 - Yes.
+
+Cvars for image interpolation and generation:
+
+* `r_imageUpsample` - Use interpolation to artifically increase
+ the resolution of all textures. Looks good
+ in certain circumstances.
+ 0 - No. (default)
+ 1 - 2x size.
+ 2 - 4x size.
+ 3 - 8x size, etc
+
+* `r_imageUpsampleMaxSize` - Maximum texture size when upsampling
+ textures.
+ 1024 - Default.
+ 2048 - Really nice.
+ 4096 - Really slow.
+ 8192 - Crash.
+
+* `r_imageUpsampleType` - Type of interpolation when upsampling
+ textures.
+ 0 - None. (probably broken)
+ 1 - Bad but fast (default,
+ FCBI without second derivatives)
+ 2 - Okay but slow (normal FCBI)
+
+* `r_genNormalMaps` - Naively generate normal maps for all
+ textures.
+ 0 - Don't. (default)
+ 1 - Do.
+
+Cvars for the sunlight and cascaded shadow maps:
+
+* `r_forceSun` - Cheat. Force sunlight and shadows, using sun position from sky material.
+ 0 - Don't. (default)
+ 1 - Do.
+ 2 - Sunrise, sunset.
+
+* `r_forceSunLightScale` - Cheat. Scale sun brightness by this factor
+ when r_forceSun 1.
+ 1.0 - Default
+
+* `r_forceSunAmbientScale` - Cheat. Scale sun ambient brightness by this factor when r_forceSun 1. 0.5 - Default
+
+* `r_sunShadows` - Enable sunlight and cascaded shadow maps for
+ it on maps that support it.
+ 0 - No.
+ 1 - Yes. (default)
+
+* `r_sunlightMode` - Specify the method used to add sunlight to
+ the scene.
+ 0 - No.
+ 1 - Multiply lit areas by light scale, and
+ shadowed areas by ambient scale.
+ (default)
+ 2 - Add light. Looks better, but is slower
+ and doesn't integrate well with existing
+ maps.
+
+* `r_shadowFilter` - Enable filtering shadows for a smoother
+ look.
+ 0 - No.
+ 1 - Some. (default)
+ 2 - Much.
+
+* `r_shadowMapSize` - Size of each cascaded shadow map.
+ 256 - 256x256, ugly, probably shouldn't
+ go below this.
+ 512 - 512x512, passable.
+ 1024 - 1024x1024, good. (default)
+ 2048 - 2048x2048, extreme.
+ 4096 - 4096x4096, indistinguishable from
+ 2048.
+
+Cvars that you probably don't care about or shouldn't mess with:
+
+* `r_depthPrepass` - Do a depth-only pass before rendering.
+ Speeds up rendering in cases where advanced
+ features are used. Required for
+ r_sunShadows.
+ 0 - No.
+ 1 - Yes. (default)
+
+* `r_mergeLightmaps` - Merge the small (128x128) lightmaps into
+ 2 or fewer giant (4096x4096) lightmaps.
+ Easy speedup.
+ 0 - Don't.
+ 1 - Do. (default)
+
+* `r_shadowCascadeZNear` - Near plane for shadow cascade frustums.
+ 4 - Default.
+
+* `r_shadowCascadeZFar` - Far plane for shadow cascade frustums.
+ 3072 - Default.
+
+* `r_shadowCascadeZBias` - Z-bias for shadow cascade frustums.
+ -256 - Default.
+
+Cvars that have broken bits:
+
+* `r_dlightMode` - Change how dynamic lights look.
+ 0 - Quake 3 style dlights, fake
+ brightening. (default)
+ 1 - Actual lighting, no shadows.
+ 2 - Light and shadows. (broken)
+
+* `r_pshadowDist` - Virtual camera distance when creating shadowmaps for projected shadows. Deprecated.
+
+* `cg_shadows` - Old shadow code. Deprecated.
+
+
+-------------------------------------------------------------------------------
+ MATERIALS
+-------------------------------------------------------------------------------
+
+OpenGL2 supports .mtr files, which are basically the same as .shader files, and
+are located in the same place, but override existing .shader files if they
+exist. This is to allow maps and mods to use the new material features without
+breaking the map when using the old renderer.
+
+Here's an example of a material stored in one, showing off some new features:
+
+ textures/abandon/grass
+ {
+ qer_editorimage textures/abandon/grass.jpg
+ {
+ map textures/abandon/grass3_256_d.jpg
+ rgbgen identity
+ }
+ {
+ stage normalparallaxmap
+ map textures/abandon/grass3_1024_n.png
+ normalScale 1 1
+ parallaxDepth 0.05
+ }
+ {
+ stage specularmap
+ map textures/abandon/grass3_256_s.png
+ specularReflectance 0.12
+ specularExponent 16
+ }
+ {
+ map $lightmap
+ blendfunc GL_DST_COLOR GL_ZERO
+ }
+ }
+
+The first thing to notice is that this is basically the same as old Quake 3
+shader files. The next thing to notice are the new keywords. Here is what
+they mean:
+
+ `stage <type>`
+ - State how this imagemap will be used by OpenGL2:
+ diffuseMap - Standard, same as no stage entry
+ normalMap - Image will be used as a normal map
+ normalParallaxMap - Image will be used as a normal map with
+ alpha treated as height for parallax mapping
+ specularMap - Image will be used as a specular map with
+ alpha treated as shininess.
+
+ `specularReflectance <value>`
+ - State how metallic this material is. Metals typically have a high
+ specular and a low diffuse, so this is typically high for them, and low
+ for other materials, such as plastic. For typical values for various
+ materials, see http://refractiveindex.info , pick a material, then scroll
+ down to the reflection calculator and look up its reflectance. Default
+ is 0.04, since most materials aren't metallic.
+
+ `specularExponent <value>`
+ - State how shiny this material is. Note that this is modulated by the
+ alpha channel of the specular map, so if it were set to 16, and the alpha
+ channel of the specular map was set to 0.5, then the shininess would be
+ set to 8. Default 256.
+
+ `normalScale <x> <y>`
+ - State the X and Y scales of the normal map. This is useful for increasing
+ or decreasing the "strength" of the normal map, or entering negative values
+ to flip the X and/or Y values. Default 1 1.
+
+ `parallaxDepth <value>`
+ - State the maximum depth of the parallax map. This is a fairly sensitive
+ value, and I recommend the default or lower. Default 0.05.
+
+An important note is that normal and specular maps influence the diffuse map
+declared before them, so materials like this are possible:
+
+ textures/terrain/grass
+ {
+ qer_editorimage textures/terrain/grass.jpg
+
+ {
+ map textures/terrain/rock.jpg
+ }
+ {
+ stage normalparallaxmap
+ map textures/terrain/rock_n.png
+ }
+ {
+ stage specularmap
+ map textures/terrain/rock_s.jpg
+ }
+ {
+ map textures/terrain/grass.jpg
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ alphaGen vertex
+ }
+ {
+ stage normalparallaxmap
+ map textures/terrain/grass_n.png
+ }
+ {
+ stage specularmap
+ map textures/terrain/grass_s.png
+ specularReflectance 0.12
+ }
+ {
+ map $lightmap
+ blendfunc GL_DST_COLOR GL_ZERO
+ }
+ }
+
+Though note due to the complexity of lighting, dynamic light (including
+sunlight with cascaded shadow maps) currently only works 100% on materials like
+this, where the second diffuse map doesn't have its own alpha, and only
+uses vertex alpha. YMMV.
+
+Another addition to materials is working normal/specular maps on vertex lit
+surfaces. To enable this, make your material look like this:
+
+ textures/vehicles/car
+ {
+ qer_editorimage textures/vehicles/car.jpg
+
+ {
+ map textures/vehicles/car.jpg
+ rgbGen vertexLit
+ }
+ {
+ stage normalparallaxmap
+ map textures/vehicles/car_n.jpg
+ }
+ {
+ stage specularmap
+ map textures/vehicles/car_s.jpg
+ }
+ }
+
+Note the new keyword, 'vertexLit' after rgbGen. This is analogous to
+'rgbGen vertex', except a light direction will be determined from the lightgrid
+and used with the normal and specular maps. 'exactVertexLit' exists as well,
+and is the equivalent for 'exactVertex'.
+
+
+-------------------------------------------------------------------------------
+ DYNAMIC SUNLIGHT AND CASCADED SHADOW MAPS
+-------------------------------------------------------------------------------
+
+This adds a new keyword to sky materials, q3gl2_sun. The syntax is:
+
+ q3gl2_sun <red> <green> <blue> <intensity> <degrees> <elevation> <shadowScale>
+
+Note the first six parameters are the same as in q3map_sun or q3map_sunExt,
+and the last two indicate scaling factors for the map brightness and an ambient
+light of the same color as the sun.
+
+There are currently two ways to use this in your own (and other people's) maps.
+
+ 1. Create your map as normal, set r_sunlightMode to 1, and add a
+ 'q3gl2_sun' line after your 'q3map_sun' line in your sky material, like
+ so:
+
+ textures/skies/bluesky
+ {
+ qer_editorimage textures/skies/bluesky.jpg
+
+ surfaceparm nomarks
+ surfaceparm noimpact
+ surfaceparm nolightmap
+ surfaceparm sky
+ q3map_sunExt 240 238 200 100 195 35 3 16
+ q3gl2_sun 240 238 200 50 195 35 0.2
+ q3map_skylight 50 16
+ q3map_lightimage $whiteimage
+
+ skyparms env/bluesky - -
+ }
+
+ The advantages with this method are that your map will continue to work
+ with the old renderer with the sunlight baked into the lightmap, and it
+ can be used with existing maps without recompilation. The downside is
+ artifacts like doubled shadows and uneven shadow edges.
+
+ 2. Set r_sunlightMode to 2 and use 'q3gl2_sun' instead of 'q3map_sun' or
+ 'q3map_sunExt', like so:
+
+ textures/skies/bluesky
+ {
+ qer_editorimage textures/skies/bluesky.jpg
+
+ surfaceparm nomarks
+ surfaceparm noimpact
+ surfaceparm nolightmap
+ surfaceparm sky
+ q3gl2_sun 240 238 200 50 195 35 0.2
+ q3map_skylight 50 16
+ q3map_lightimage $whiteimage
+
+ skyparms env/bluesky - -
+ }
+
+ The advantages with this method are that you don't get the artifacts that
+ characterize the other method, and your map compiles a lot faster without
+ the sunlight bouncing calculations. The downsides are that your map will
+ not display properly with the old renderer, and you lose the bounced light
+ that compiling the map with q3map_sun* in it would have.
+
+
+-------------------------------------------------------------------------------
+ TONE MAPPING AND AUTO EXPOSURE
+-------------------------------------------------------------------------------
+
+This adds a new keyword to sky materials, q3gl2_tonemap. The syntax is:
+
+ q3gl2_tonemap <toneMapMin> <toneMapAvg> <toneMapMax> <autoExposureMin> <autoExposureMax>
+
+Each of these settings corresponds to a matching cvar, so you can view and
+adjust the effect before settling on fixed settings.
+
+
+-------------------------------------------------------------------------------
+ THANKS
+-------------------------------------------------------------------------------
+
+I'd like to take this part of the readme to thank the numerous people who
+contributed thoughts, ideas, and whole swaths of code to this project.
+
+ - Id Software, for creating Quake 3 and releasing its source code under a
+ GPL license, without which this project would not be possible.
+
+ - Zachary 'Zakk' Slater, Thilo Schulz, Tim Angus, and the rest of the
+ ioquake3 team and contributors, for improving massively upon the raw Quake
+ 3 source, and accepting my and gimhael's modular renderer patch.
+
+ - Robert 'Tr3B' Beckebans and the other contributors to XReaL, for letting me
+ liberally copy code from you. :)
+
+ - Andrew 'Black Monk' Prosnik, Andrei 'Makro' Drexler, Tomi 'T.T.I.' Isoaho,
+ Richard 'JBravo' Allen, Walter 'Johnny Rocket' Somol, and the rest of the
+ Boomstick Studios, for contributing code, feature requests, and testing.
+
+ - Yoshiharu Gotanda, Tatsuya Shoji, and the rest of tri-Ace's R&D Department,
+ for creating the tri-Ace shading equations and posting their derivations in
+ simple English.
+
+ - Matthias 'gimhael' Bentrup, for random ideas and bits of code.
+
+ - Evan 'megatog615' Goers, for testing, ideas, and bugging me just enough
+ that I'd write documentation. :)
+
+ - The folks at #ioquake3, who don't seem to mind when I suddenly drop a
+ screenshot and insist on talking about it. :)
+
+ - And lots of various other random people, who posted on forums, blogs, and
+ Wikipedia, who helped in small but numerous ways.
+
+If I missed you in this section, feel free to drop me a line and I'll add you.
+
+
+-------------------------------------------------------------------------------
+ CONTACT
+-------------------------------------------------------------------------------
+
+My name is James Canete, and I wrote most of this readme. Also, a renderer.
+
+If you wish to get in touch with me, try my GMail at use.less01 (you should be
+able to solve this), or look for SmileTheory in #ioquake3 on irc.freenode.net.
diff --git a/external/AL/AL/VERSION b/external/AL/AL/VERSION
new file mode 100644
index 0000000..eb4f04d
--- /dev/null
+++ b/external/AL/AL/VERSION
@@ -0,0 +1,5 @@
+This file identifies the version of the AL headers in this directory. If you
+change or update the AL headers in any way, please make sure you also update
+this file.
+
+openal-soft-1.15.1
diff --git a/external/AL/AL/al.h b/external/AL/AL/al.h
new file mode 100644
index 0000000..413b383
--- /dev/null
+++ b/external/AL/AL/al.h
@@ -0,0 +1,656 @@
+#ifndef AL_AL_H
+#define AL_AL_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef AL_API
+ #if defined(AL_LIBTYPE_STATIC)
+ #define AL_API
+ #elif defined(_WIN32)
+ #define AL_API __declspec(dllimport)
+ #else
+ #define AL_API extern
+ #endif
+#endif
+
+#if defined(_WIN32)
+ #define AL_APIENTRY __cdecl
+#else
+ #define AL_APIENTRY
+#endif
+
+
+/** Deprecated macro. */
+#define OPENAL
+#define ALAPI AL_API
+#define ALAPIENTRY AL_APIENTRY
+#define AL_INVALID (-1)
+#define AL_ILLEGAL_ENUM AL_INVALID_ENUM
+#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
+
+/** Supported AL version. */
+#define AL_VERSION_1_0
+#define AL_VERSION_1_1
+
+/** 8-bit boolean */
+typedef char ALboolean;
+
+/** character */
+typedef char ALchar;
+
+/** signed 8-bit 2's complement integer */
+typedef signed char ALbyte;
+
+/** unsigned 8-bit integer */
+typedef unsigned char ALubyte;
+
+/** signed 16-bit 2's complement integer */
+typedef short ALshort;
+
+/** unsigned 16-bit integer */
+typedef unsigned short ALushort;
+
+/** signed 32-bit 2's complement integer */
+typedef int ALint;
+
+/** unsigned 32-bit integer */
+typedef unsigned int ALuint;
+
+/** non-negative 32-bit binary integer size */
+typedef int ALsizei;
+
+/** enumerated 32-bit value */
+typedef int ALenum;
+
+/** 32-bit IEEE754 floating-point */
+typedef float ALfloat;
+
+/** 64-bit IEEE754 floating-point */
+typedef double ALdouble;
+
+/** void type (for opaque pointers only) */
+typedef void ALvoid;
+
+
+/* Enumerant values begin at column 50. No tabs. */
+
+/** "no distance model" or "no buffer" */
+#define AL_NONE 0
+
+/** Boolean False. */
+#define AL_FALSE 0
+
+/** Boolean True. */
+#define AL_TRUE 1
+
+
+/**
+ * Relative source.
+ * Type: ALboolean
+ * Range: [AL_TRUE, AL_FALSE]
+ * Default: AL_FALSE
+ *
+ * Specifies if the Source has relative coordinates.
+ */
+#define AL_SOURCE_RELATIVE 0x202
+
+
+/**
+ * Inner cone angle, in degrees.
+ * Type: ALint, ALfloat
+ * Range: [0 - 360]
+ * Default: 360
+ *
+ * The angle covered by the inner cone, where the source will not attenuate.
+ */
+#define AL_CONE_INNER_ANGLE 0x1001
+
+/**
+ * Outer cone angle, in degrees.
+ * Range: [0 - 360]
+ * Default: 360
+ *
+ * The angle covered by the outer cone, where the source will be fully
+ * attenuated.
+ */
+#define AL_CONE_OUTER_ANGLE 0x1002
+
+/**
+ * Source pitch.
+ * Type: ALfloat
+ * Range: [0.5 - 2.0]
+ * Default: 1.0
+ *
+ * A multiplier for the frequency (sample rate) of the source's buffer.
+ */
+#define AL_PITCH 0x1003
+
+/**
+ * Source or listener position.
+ * Type: ALfloat[3], ALint[3]
+ * Default: {0, 0, 0}
+ *
+ * The source or listener location in three dimensional space.
+ *
+ * OpenAL, like OpenGL, uses a right handed coordinate system, where in a
+ * frontal default view X (thumb) points right, Y points up (index finger), and
+ * Z points towards the viewer/camera (middle finger).
+ *
+ * To switch from a left handed coordinate system, flip the sign on the Z
+ * coordinate.
+ */
+#define AL_POSITION 0x1004
+
+/**
+ * Source direction.
+ * Type: ALfloat[3], ALint[3]
+ * Default: {0, 0, 0}
+ *
+ * Specifies the current direction in local space.
+ * A zero-length vector specifies an omni-directional source (cone is ignored).
+ */
+#define AL_DIRECTION 0x1005
+
+/**
+ * Source or listener velocity.
+ * Type: ALfloat[3], ALint[3]
+ * Default: {0, 0, 0}
+ *
+ * Specifies the current velocity in local space.
+ */
+#define AL_VELOCITY 0x1006
+
+/**
+ * Source looping.
+ * Type: ALboolean
+ * Range: [AL_TRUE, AL_FALSE]
+ * Default: AL_FALSE
+ *
+ * Specifies whether source is looping.
+ */
+#define AL_LOOPING 0x1007
+
+/**
+ * Source buffer.
+ * Type: ALuint
+ * Range: any valid Buffer.
+ *
+ * Specifies the buffer to provide sound samples.
+ */
+#define AL_BUFFER 0x1009
+
+/**
+ * Source or listener gain.
+ * Type: ALfloat
+ * Range: [0.0 - ]
+ *
+ * A value of 1.0 means unattenuated. Each division by 2 equals an attenuation
+ * of about -6dB. Each multiplicaton by 2 equals an amplification of about
+ * +6dB.
+ *
+ * A value of 0.0 is meaningless with respect to a logarithmic scale; it is
+ * silent.
+ */
+#define AL_GAIN 0x100A
+
+/**
+ * Minimum source gain.
+ * Type: ALfloat
+ * Range: [0.0 - 1.0]
+ *
+ * The minimum gain allowed for a source, after distance and cone attenation is
+ * applied (if applicable).
+ */
+#define AL_MIN_GAIN 0x100D
+
+/**
+ * Maximum source gain.
+ * Type: ALfloat
+ * Range: [0.0 - 1.0]
+ *
+ * The maximum gain allowed for a source, after distance and cone attenation is
+ * applied (if applicable).
+ */
+#define AL_MAX_GAIN 0x100E
+
+/**
+ * Listener orientation.
+ * Type: ALfloat[6]
+ * Default: {0.0, 0.0, -1.0, 0.0, 1.0, 0.0}
+ *
+ * Effectively two three dimensional vectors. The first vector is the front (or
+ * "at") and the second is the top (or "up").
+ *
+ * Both vectors are in local space.
+ */
+#define AL_ORIENTATION 0x100F
+
+/**
+ * Source state (query only).
+ * Type: ALint
+ * Range: [AL_INITIAL, AL_PLAYING, AL_PAUSED, AL_STOPPED]
+ */
+#define AL_SOURCE_STATE 0x1010
+
+/** Source state value. */
+#define AL_INITIAL 0x1011
+#define AL_PLAYING 0x1012
+#define AL_PAUSED 0x1013
+#define AL_STOPPED 0x1014
+
+/**
+ * Source Buffer Queue size (query only).
+ * Type: ALint
+ *
+ * The number of buffers queued using alSourceQueueBuffers, minus the buffers
+ * removed with alSourceUnqueueBuffers.
+ */
+#define AL_BUFFERS_QUEUED 0x1015
+
+/**
+ * Source Buffer Queue processed count (query only).
+ * Type: ALint
+ *
+ * The number of queued buffers that have been fully processed, and can be
+ * removed with alSourceUnqueueBuffers.
+ *
+ * Looping sources will never fully process buffers because they will be set to
+ * play again for when the source loops.
+ */
+#define AL_BUFFERS_PROCESSED 0x1016
+
+/**
+ * Source reference distance.
+ * Type: ALfloat
+ * Range: [0.0 - ]
+ * Default: 1.0
+ *
+ * The distance in units that no attenuation occurs.
+ *
+ * At 0.0, no distance attenuation ever occurs on non-linear attenuation models.
+ */
+#define AL_REFERENCE_DISTANCE 0x1020
+
+/**
+ * Source rolloff factor.
+ * Type: ALfloat
+ * Range: [0.0 - ]
+ * Default: 1.0
+ *
+ * Multiplier to exaggerate or diminish distance attenuation.
+ *
+ * At 0.0, no distance attenuation ever occurs.
+ */
+#define AL_ROLLOFF_FACTOR 0x1021
+
+/**
+ * Outer cone gain.
+ * Type: ALfloat
+ * Range: [0.0 - 1.0]
+ * Default: 0.0
+ *
+ * The gain attenuation applied when the listener is outside of the source's
+ * outer cone.
+ */
+#define AL_CONE_OUTER_GAIN 0x1022
+
+/**
+ * Source maximum distance.
+ * Type: ALfloat
+ * Range: [0.0 - ]
+ * Default: +inf
+ *
+ * The distance above which the source is not attenuated any further with a
+ * clamped distance model, or where attenuation reaches 0.0 gain for linear
+ * distance models with a default rolloff factor.
+ */
+#define AL_MAX_DISTANCE 0x1023
+
+/** Source buffer position, in seconds */
+#define AL_SEC_OFFSET 0x1024
+/** Source buffer position, in sample frames */
+#define AL_SAMPLE_OFFSET 0x1025
+/** Source buffer position, in bytes */
+#define AL_BYTE_OFFSET 0x1026
+
+/**
+ * Source type (query only).
+ * Type: ALint
+ * Range: [AL_STATIC, AL_STREAMING, AL_UNDETERMINED]
+ *
+ * A Source is Static if a Buffer has been attached using AL_BUFFER.
+ *
+ * A Source is Streaming if one or more Buffers have been attached using
+ * alSourceQueueBuffers.
+ *
+ * A Source is Undetermined when it has the NULL buffer attached using
+ * AL_BUFFER.
+ */
+#define AL_SOURCE_TYPE 0x1027
+
+/** Source type value. */
+#define AL_STATIC 0x1028
+#define AL_STREAMING 0x1029
+#define AL_UNDETERMINED 0x1030
+
+/** Buffer format specifier. */
+#define AL_FORMAT_MONO8 0x1100
+#define AL_FORMAT_MONO16 0x1101
+#define AL_FORMAT_STEREO8 0x1102
+#define AL_FORMAT_STEREO16 0x1103
+
+/** Buffer frequency (query only). */
+#define AL_FREQUENCY 0x2001
+/** Buffer bits per sample (query only). */
+#define AL_BITS 0x2002
+/** Buffer channel count (query only). */
+#define AL_CHANNELS 0x2003
+/** Buffer data size (query only). */
+#define AL_SIZE 0x2004
+
+/**
+ * Buffer state.
+ *
+ * Not for public use.
+ */
+#define AL_UNUSED 0x2010
+#define AL_PENDING 0x2011
+#define AL_PROCESSED 0x2012
+
+
+/** No error. */
+#define AL_NO_ERROR 0
+
+/** Invalid name paramater passed to AL call. */
+#define AL_INVALID_NAME 0xA001
+
+/** Invalid enum parameter passed to AL call. */
+#define AL_INVALID_ENUM 0xA002
+
+/** Invalid value parameter passed to AL call. */
+#define AL_INVALID_VALUE 0xA003
+
+/** Illegal AL call. */
+#define AL_INVALID_OPERATION 0xA004
+
+/** Not enough memory. */
+#define AL_OUT_OF_MEMORY 0xA005
+
+
+/** Context string: Vendor ID. */
+#define AL_VENDOR 0xB001
+/** Context string: Version. */
+#define AL_VERSION 0xB002
+/** Context string: Renderer ID. */
+#define AL_RENDERER 0xB003
+/** Context string: Space-separated extension list. */
+#define AL_EXTENSIONS 0xB004
+
+
+/**
+ * Doppler scale.
+ * Type: ALfloat
+ * Range: [0.0 - ]
+ * Default: 1.0
+ *
+ * Scale for source and listener velocities.
+ */
+#define AL_DOPPLER_FACTOR 0xC000
+AL_API void AL_APIENTRY alDopplerFactor(ALfloat value);
+
+/**
+ * Doppler velocity (deprecated).
+ *
+ * A multiplier applied to the Speed of Sound.
+ */
+#define AL_DOPPLER_VELOCITY 0xC001
+AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value);
+
+/**
+ * Speed of Sound, in units per second.
+ * Type: ALfloat
+ * Range: [0.0001 - ]
+ * Default: 343.3
+ *
+ * The speed at which sound waves are assumed to travel, when calculating the
+ * doppler effect.
+ */
+#define AL_SPEED_OF_SOUND 0xC003
+AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value);
+
+/**
+ * Distance attenuation model.
+ * Type: ALint
+ * Range: [AL_NONE, AL_INVERSE_DISTANCE, AL_INVERSE_DISTANCE_CLAMPED,
+ * AL_LINEAR_DISTANCE, AL_LINEAR_DISTANCE_CLAMPED,
+ * AL_EXPONENT_DISTANCE, AL_EXPONENT_DISTANCE_CLAMPED]
+ * Default: AL_INVERSE_DISTANCE_CLAMPED
+ *
+ * The model by which sources attenuate with distance.
+ *
+ * None - No distance attenuation.
+ * Inverse - Doubling the distance halves the source gain.
+ * Linear - Linear gain scaling between the reference and max distances.
+ * Exponent - Exponential gain dropoff.
+ *
+ * Clamped variations work like the non-clamped counterparts, except the
+ * distance calculated is clamped between the reference and max distances.
+ */
+#define AL_DISTANCE_MODEL 0xD000
+AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel);
+
+/** Distance model value. */
+#define AL_INVERSE_DISTANCE 0xD001
+#define AL_INVERSE_DISTANCE_CLAMPED 0xD002
+#define AL_LINEAR_DISTANCE 0xD003
+#define AL_LINEAR_DISTANCE_CLAMPED 0xD004
+#define AL_EXPONENT_DISTANCE 0xD005
+#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006
+
+/** Renderer State management. */
+AL_API void AL_APIENTRY alEnable(ALenum capability);
+AL_API void AL_APIENTRY alDisable(ALenum capability);
+AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability);
+
+/** State retrieval. */
+AL_API const ALchar* AL_APIENTRY alGetString(ALenum param);
+AL_API void AL_APIENTRY alGetBooleanv(ALenum param, ALboolean *values);
+AL_API void AL_APIENTRY alGetIntegerv(ALenum param, ALint *values);
+AL_API void AL_APIENTRY alGetFloatv(ALenum param, ALfloat *values);
+AL_API void AL_APIENTRY alGetDoublev(ALenum param, ALdouble *values);
+AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum param);
+AL_API ALint AL_APIENTRY alGetInteger(ALenum param);
+AL_API ALfloat AL_APIENTRY alGetFloat(ALenum param);
+AL_API ALdouble AL_APIENTRY alGetDouble(ALenum param);
+
+/**
+ * Error retrieval.
+ *
+ * Obtain the first error generated in the AL context since the last check.
+ */
+AL_API ALenum AL_APIENTRY alGetError(void);
+
+/**
+ * Extension support.
+ *
+ * Query for the presence of an extension, and obtain any appropriate function
+ * pointers and enum values.
+ */
+AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extname);
+AL_API void* AL_APIENTRY alGetProcAddress(const ALchar *fname);
+AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *ename);
+
+
+/** Set Listener parameters */
+AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value);
+AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values);
+AL_API void AL_APIENTRY alListeneri(ALenum param, ALint value);
+AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3);
+AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values);
+
+/** Get Listener parameters */
+AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value);
+AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values);
+AL_API void AL_APIENTRY alGetListeneri(ALenum param, ALint *value);
+AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3);
+AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint *values);
+
+
+/** Create Source objects. */
+AL_API void AL_APIENTRY alGenSources(ALsizei n, ALuint *sources);
+/** Delete Source objects. */
+AL_API void AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources);
+/** Verify a handle is a valid Source. */
+AL_API ALboolean AL_APIENTRY alIsSource(ALuint source);
+
+/** Set Source parameters. */
+AL_API void AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value);
+AL_API void AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+AL_API void AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values);
+AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value);
+AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3);
+AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values);
+
+/** Get Source parameters. */
+AL_API void AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value);
+AL_API void AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+AL_API void AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values);
+AL_API void AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value);
+AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3);
+AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values);
+
+
+/** Play, replay, or resume (if paused) a list of Sources */
+AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources);
+/** Stop a list of Sources */
+AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources);
+/** Rewind a list of Sources */
+AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources);
+/** Pause a list of Sources */
+AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources);
+
+/** Play, replay, or resume a Source */
+AL_API void AL_APIENTRY alSourcePlay(ALuint source);
+/** Stop a Source */
+AL_API void AL_APIENTRY alSourceStop(ALuint source);
+/** Rewind a Source (set playback postiton to beginning) */
+AL_API void AL_APIENTRY alSourceRewind(ALuint source);
+/** Pause a Source */
+AL_API void AL_APIENTRY alSourcePause(ALuint source);
+
+/** Queue buffers onto a source */
+AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers);
+/** Unqueue processed buffers from a source */
+AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers);
+
+
+/** Create Buffer objects */
+AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers);
+/** Delete Buffer objects */
+AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers);
+/** Verify a handle is a valid Buffer */
+AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer);
+
+/** Specifies the data to be copied into a buffer */
+AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq);
+
+/** Set Buffer parameters, */
+AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value);
+AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values);
+AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value);
+AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3);
+AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values);
+
+/** Get Buffer parameters. */
+AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value);
+AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values);
+AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value);
+AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3);
+AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values);
+
+/** Pointer-to-function type, useful for dynamically getting AL entry points. */
+typedef void (AL_APIENTRY *LPALENABLE)(ALenum capability);
+typedef void (AL_APIENTRY *LPALDISABLE)(ALenum capability);
+typedef ALboolean (AL_APIENTRY *LPALISENABLED)(ALenum capability);
+typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)(ALenum param);
+typedef void (AL_APIENTRY *LPALGETBOOLEANV)(ALenum param, ALboolean *values);
+typedef void (AL_APIENTRY *LPALGETINTEGERV)(ALenum param, ALint *values);
+typedef void (AL_APIENTRY *LPALGETFLOATV)(ALenum param, ALfloat *values);
+typedef void (AL_APIENTRY *LPALGETDOUBLEV)(ALenum param, ALdouble *values);
+typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)(ALenum param);
+typedef ALint (AL_APIENTRY *LPALGETINTEGER)(ALenum param);
+typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)(ALenum param);
+typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)(ALenum param);
+typedef ALenum (AL_APIENTRY *LPALGETERROR)(void);
+typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar *extname);
+typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)(const ALchar *fname);
+typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)(const ALchar *ename);
+typedef void (AL_APIENTRY *LPALLISTENERF)(ALenum param, ALfloat value);
+typedef void (AL_APIENTRY *LPALLISTENER3F)(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+typedef void (AL_APIENTRY *LPALLISTENERFV)(ALenum param, const ALfloat *values);
+typedef void (AL_APIENTRY *LPALLISTENERI)(ALenum param, ALint value);
+typedef void (AL_APIENTRY *LPALLISTENER3I)(ALenum param, ALint value1, ALint value2, ALint value3);
+typedef void (AL_APIENTRY *LPALLISTENERIV)(ALenum param, const ALint *values);
+typedef void (AL_APIENTRY *LPALGETLISTENERF)(ALenum param, ALfloat *value);
+typedef void (AL_APIENTRY *LPALGETLISTENER3F)(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+typedef void (AL_APIENTRY *LPALGETLISTENERFV)(ALenum param, ALfloat *values);
+typedef void (AL_APIENTRY *LPALGETLISTENERI)(ALenum param, ALint *value);
+typedef void (AL_APIENTRY *LPALGETLISTENER3I)(ALenum param, ALint *value1, ALint *value2, ALint *value3);
+typedef void (AL_APIENTRY *LPALGETLISTENERIV)(ALenum param, ALint *values);
+typedef void (AL_APIENTRY *LPALGENSOURCES)(ALsizei n, ALuint *sources);
+typedef void (AL_APIENTRY *LPALDELETESOURCES)(ALsizei n, const ALuint *sources);
+typedef ALboolean (AL_APIENTRY *LPALISSOURCE)(ALuint source);
+typedef void (AL_APIENTRY *LPALSOURCEF)(ALuint source, ALenum param, ALfloat value);
+typedef void (AL_APIENTRY *LPALSOURCE3F)(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+typedef void (AL_APIENTRY *LPALSOURCEFV)(ALuint source, ALenum param, const ALfloat *values);
+typedef void (AL_APIENTRY *LPALSOURCEI)(ALuint source, ALenum param, ALint value);
+typedef void (AL_APIENTRY *LPALSOURCE3I)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3);
+typedef void (AL_APIENTRY *LPALSOURCEIV)(ALuint source, ALenum param, const ALint *values);
+typedef void (AL_APIENTRY *LPALGETSOURCEF)(ALuint source, ALenum param, ALfloat *value);
+typedef void (AL_APIENTRY *LPALGETSOURCE3F)(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+typedef void (AL_APIENTRY *LPALGETSOURCEFV)(ALuint source, ALenum param, ALfloat *values);
+typedef void (AL_APIENTRY *LPALGETSOURCEI)(ALuint source, ALenum param, ALint *value);
+typedef void (AL_APIENTRY *LPALGETSOURCE3I)(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3);
+typedef void (AL_APIENTRY *LPALGETSOURCEIV)(ALuint source, ALenum param, ALint *values);
+typedef void (AL_APIENTRY *LPALSOURCEPLAYV)(ALsizei n, const ALuint *sources);
+typedef void (AL_APIENTRY *LPALSOURCESTOPV)(ALsizei n, const ALuint *sources);
+typedef void (AL_APIENTRY *LPALSOURCEREWINDV)(ALsizei n, const ALuint *sources);
+typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)(ALsizei n, const ALuint *sources);
+typedef void (AL_APIENTRY *LPALSOURCEPLAY)(ALuint source);
+typedef void (AL_APIENTRY *LPALSOURCESTOP)(ALuint source);
+typedef void (AL_APIENTRY *LPALSOURCEREWIND)(ALuint source);
+typedef void (AL_APIENTRY *LPALSOURCEPAUSE)(ALuint source);
+typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint source, ALsizei nb, const ALuint *buffers);
+typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALsizei nb, ALuint *buffers);
+typedef void (AL_APIENTRY *LPALGENBUFFERS)(ALsizei n, ALuint *buffers);
+typedef void (AL_APIENTRY *LPALDELETEBUFFERS)(ALsizei n, const ALuint *buffers);
+typedef ALboolean (AL_APIENTRY *LPALISBUFFER)(ALuint buffer);
+typedef void (AL_APIENTRY *LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq);
+typedef void (AL_APIENTRY *LPALBUFFERF)(ALuint buffer, ALenum param, ALfloat value);
+typedef void (AL_APIENTRY *LPALBUFFER3F)(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+typedef void (AL_APIENTRY *LPALBUFFERFV)(ALuint buffer, ALenum param, const ALfloat *values);
+typedef void (AL_APIENTRY *LPALBUFFERI)(ALuint buffer, ALenum param, ALint value);
+typedef void (AL_APIENTRY *LPALBUFFER3I)(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3);
+typedef void (AL_APIENTRY *LPALBUFFERIV)(ALuint buffer, ALenum param, const ALint *values);
+typedef void (AL_APIENTRY *LPALGETBUFFERF)(ALuint buffer, ALenum param, ALfloat *value);
+typedef void (AL_APIENTRY *LPALGETBUFFER3F)(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+typedef void (AL_APIENTRY *LPALGETBUFFERFV)(ALuint buffer, ALenum param, ALfloat *values);
+typedef void (AL_APIENTRY *LPALGETBUFFERI)(ALuint buffer, ALenum param, ALint *value);
+typedef void (AL_APIENTRY *LPALGETBUFFER3I)(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3);
+typedef void (AL_APIENTRY *LPALGETBUFFERIV)(ALuint buffer, ALenum param, ALint *values);
+typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)(ALfloat value);
+typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)(ALfloat value);
+typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)(ALfloat value);
+typedef void (AL_APIENTRY *LPALDISTANCEMODEL)(ALenum distanceModel);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+#endif /* AL_AL_H */
diff --git a/external/AL/AL/alc.h b/external/AL/AL/alc.h
new file mode 100644
index 0000000..294e8b3
--- /dev/null
+++ b/external/AL/AL/alc.h
@@ -0,0 +1,237 @@
+#ifndef AL_ALC_H
+#define AL_ALC_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef ALC_API
+ #if defined(AL_LIBTYPE_STATIC)
+ #define ALC_API
+ #elif defined(_WIN32)
+ #define ALC_API __declspec(dllimport)
+ #else
+ #define ALC_API extern
+ #endif
+#endif
+
+#if defined(_WIN32)
+ #define ALC_APIENTRY __cdecl
+#else
+ #define ALC_APIENTRY
+#endif
+
+
+/** Deprecated macro. */
+#define ALCAPI ALC_API
+#define ALCAPIENTRY ALC_APIENTRY
+#define ALC_INVALID 0
+
+/** Supported ALC version? */
+#define ALC_VERSION_0_1 1
+
+/** Opaque device handle */
+typedef struct ALCdevice_struct ALCdevice;
+/** Opaque context handle */
+typedef struct ALCcontext_struct ALCcontext;
+
+/** 8-bit boolean */
+typedef char ALCboolean;
+
+/** character */
+typedef char ALCchar;
+
+/** signed 8-bit 2's complement integer */
+typedef signed char ALCbyte;
+
+/** unsigned 8-bit integer */
+typedef unsigned char ALCubyte;
+
+/** signed 16-bit 2's complement integer */
+typedef short ALCshort;
+
+/** unsigned 16-bit integer */
+typedef unsigned short ALCushort;
+
+/** signed 32-bit 2's complement integer */
+typedef int ALCint;
+
+/** unsigned 32-bit integer */
+typedef unsigned int ALCuint;
+
+/** non-negative 32-bit binary integer size */
+typedef int ALCsizei;
+
+/** enumerated 32-bit value */
+typedef int ALCenum;
+
+/** 32-bit IEEE754 floating-point */
+typedef float ALCfloat;
+
+/** 64-bit IEEE754 floating-point */
+typedef double ALCdouble;
+
+/** void type (for opaque pointers only) */
+typedef void ALCvoid;
+
+
+/* Enumerant values begin at column 50. No tabs. */
+
+/** Boolean False. */
+#define ALC_FALSE 0
+
+/** Boolean True. */
+#define ALC_TRUE 1
+
+/** Context attribute: <int> Hz. */
+#define ALC_FREQUENCY 0x1007
+
+/** Context attribute: <int> Hz. */
+#define ALC_REFRESH 0x1008
+
+/** Context attribute: AL_TRUE or AL_FALSE. */
+#define ALC_SYNC 0x1009
+
+/** Context attribute: <int> requested Mono (3D) Sources. */
+#define ALC_MONO_SOURCES 0x1010
+
+/** Context attribute: <int> requested Stereo Sources. */
+#define ALC_STEREO_SOURCES 0x1011
+
+/** No error. */
+#define ALC_NO_ERROR 0
+
+/** Invalid device handle. */
+#define ALC_INVALID_DEVICE 0xA001
+
+/** Invalid context handle. */
+#define ALC_INVALID_CONTEXT 0xA002
+
+/** Invalid enum parameter passed to an ALC call. */
+#define ALC_INVALID_ENUM 0xA003
+
+/** Invalid value parameter passed to an ALC call. */
+#define ALC_INVALID_VALUE 0xA004
+
+/** Out of memory. */
+#define ALC_OUT_OF_MEMORY 0xA005
+
+
+/** Runtime ALC version. */
+#define ALC_MAJOR_VERSION 0x1000
+#define ALC_MINOR_VERSION 0x1001
+
+/** Context attribute list properties. */
+#define ALC_ATTRIBUTES_SIZE 0x1002
+#define ALC_ALL_ATTRIBUTES 0x1003
+
+/** String for the default device specifier. */
+#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004
+/**
+ * String for the given device's specifier.
+ *
+ * If device handle is NULL, it is instead a null-char separated list of
+ * strings of known device specifiers (list ends with an empty string).
+ */
+#define ALC_DEVICE_SPECIFIER 0x1005
+/** String for space-separated list of ALC extensions. */
+#define ALC_EXTENSIONS 0x1006
+
+
+/** Capture extension */
+#define ALC_EXT_CAPTURE 1
+/**
+ * String for the given capture device's specifier.
+ *
+ * If device handle is NULL, it is instead a null-char separated list of
+ * strings of known capture device specifiers (list ends with an empty string).
+ */
+#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310
+/** String for the default capture device specifier. */
+#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311
+/** Number of sample frames available for capture. */
+#define ALC_CAPTURE_SAMPLES 0x312
+
+
+/** Enumerate All extension */
+#define ALC_ENUMERATE_ALL_EXT 1
+/** String for the default extended device specifier. */
+#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
+/**
+ * String for the given extended device's specifier.
+ *
+ * If device handle is NULL, it is instead a null-char separated list of
+ * strings of known extended device specifiers (list ends with an empty string).
+ */
+#define ALC_ALL_DEVICES_SPECIFIER 0x1013
+
+
+/** Context management. */
+ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint* attrlist);
+ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context);
+ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context);
+ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context);
+ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context);
+ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void);
+ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context);
+
+/** Device management. */
+ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename);
+ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device);
+
+
+/**
+ * Error support.
+ *
+ * Obtain the most recent Device error.
+ */
+ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device);
+
+/**
+ * Extension support.
+ *
+ * Query for the presence of an extension, and obtain any appropriate
+ * function pointers and enum values.
+ */
+ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname);
+ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname);
+ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname);
+
+/** Query function. */
+ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param);
+ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values);
+
+/** Capture function. */
+ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize);
+ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device);
+ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device);
+ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device);
+ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
+
+/** Pointer-to-function type, useful for dynamically getting ALC entry points. */
+typedef ALCcontext* (ALC_APIENTRY *LPALCCREATECONTEXT)(ALCdevice *device, const ALCint *attrlist);
+typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)(ALCcontext *context);
+typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)(ALCcontext *context);
+typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)(ALCcontext *context);
+typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)(ALCcontext *context);
+typedef ALCcontext* (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)(void);
+typedef ALCdevice* (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)(ALCcontext *context);
+typedef ALCdevice* (ALC_APIENTRY *LPALCOPENDEVICE)(const ALCchar *devicename);
+typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)(ALCdevice *device);
+typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)(ALCdevice *device);
+typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname);
+typedef void* (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname);
+typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname);
+typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)(ALCdevice *device, ALCenum param);
+typedef void (ALC_APIENTRY *LPALCGETINTEGERV)(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values);
+typedef ALCdevice* (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize);
+typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)(ALCdevice *device);
+typedef void (ALC_APIENTRY *LPALCCAPTURESTART)(ALCdevice *device);
+typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)(ALCdevice *device);
+typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* AL_ALC_H */
diff --git a/external/AL/AL/alext.h b/external/AL/AL/alext.h
new file mode 100644
index 0000000..0447f2b
--- /dev/null
+++ b/external/AL/AL/alext.h
@@ -0,0 +1,355 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2008 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef AL_ALEXT_H
+#define AL_ALEXT_H
+
+#include <stddef.h>
+/* Define int64_t and uint64_t types */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+#elif defined(_WIN32) && defined(__GNUC__)
+#include <stdint.h>
+#elif defined(_WIN32)
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+/* Fallback if nothing above works */
+#include <inttypes.h>
+#endif
+
+#include "alc.h"
+#include "al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef AL_LOKI_IMA_ADPCM_format
+#define AL_LOKI_IMA_ADPCM_format 1
+#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000
+#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001
+#endif
+
+#ifndef AL_LOKI_WAVE_format
+#define AL_LOKI_WAVE_format 1
+#define AL_FORMAT_WAVE_EXT 0x10002
+#endif
+
+#ifndef AL_EXT_vorbis
+#define AL_EXT_vorbis 1
+#define AL_FORMAT_VORBIS_EXT 0x10003
+#endif
+
+#ifndef AL_LOKI_quadriphonic
+#define AL_LOKI_quadriphonic 1
+#define AL_FORMAT_QUAD8_LOKI 0x10004
+#define AL_FORMAT_QUAD16_LOKI 0x10005
+#endif
+
+#ifndef AL_EXT_float32
+#define AL_EXT_float32 1
+#define AL_FORMAT_MONO_FLOAT32 0x10010
+#define AL_FORMAT_STEREO_FLOAT32 0x10011
+#endif
+
+#ifndef AL_EXT_double
+#define AL_EXT_double 1
+#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012
+#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013
+#endif
+
+#ifndef AL_EXT_MULAW
+#define AL_EXT_MULAW 1
+#define AL_FORMAT_MONO_MULAW_EXT 0x10014
+#define AL_FORMAT_STEREO_MULAW_EXT 0x10015
+#endif
+
+#ifndef AL_EXT_ALAW
+#define AL_EXT_ALAW 1
+#define AL_FORMAT_MONO_ALAW_EXT 0x10016
+#define AL_FORMAT_STEREO_ALAW_EXT 0x10017
+#endif
+
+#ifndef ALC_LOKI_audio_channel
+#define ALC_LOKI_audio_channel 1
+#define ALC_CHAN_MAIN_LOKI 0x500001
+#define ALC_CHAN_PCM_LOKI 0x500002
+#define ALC_CHAN_CD_LOKI 0x500003
+#endif
+
+#ifndef AL_EXT_MCFORMATS
+#define AL_EXT_MCFORMATS 1
+#define AL_FORMAT_QUAD8 0x1204
+#define AL_FORMAT_QUAD16 0x1205
+#define AL_FORMAT_QUAD32 0x1206
+#define AL_FORMAT_REAR8 0x1207
+#define AL_FORMAT_REAR16 0x1208
+#define AL_FORMAT_REAR32 0x1209
+#define AL_FORMAT_51CHN8 0x120A
+#define AL_FORMAT_51CHN16 0x120B
+#define AL_FORMAT_51CHN32 0x120C
+#define AL_FORMAT_61CHN8 0x120D
+#define AL_FORMAT_61CHN16 0x120E
+#define AL_FORMAT_61CHN32 0x120F
+#define AL_FORMAT_71CHN8 0x1210
+#define AL_FORMAT_71CHN16 0x1211
+#define AL_FORMAT_71CHN32 0x1212
+#endif
+
+#ifndef AL_EXT_MULAW_MCFORMATS
+#define AL_EXT_MULAW_MCFORMATS 1
+#define AL_FORMAT_MONO_MULAW 0x10014
+#define AL_FORMAT_STEREO_MULAW 0x10015
+#define AL_FORMAT_QUAD_MULAW 0x10021
+#define AL_FORMAT_REAR_MULAW 0x10022
+#define AL_FORMAT_51CHN_MULAW 0x10023
+#define AL_FORMAT_61CHN_MULAW 0x10024
+#define AL_FORMAT_71CHN_MULAW 0x10025
+#endif
+
+#ifndef AL_EXT_IMA4
+#define AL_EXT_IMA4 1
+#define AL_FORMAT_MONO_IMA4 0x1300
+#define AL_FORMAT_STEREO_IMA4 0x1301
+#endif
+
+#ifndef AL_EXT_STATIC_BUFFER
+#define AL_EXT_STATIC_BUFFER 1
+typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq);
+#endif
+#endif
+
+#ifndef ALC_EXT_EFX
+#define ALC_EXT_EFX 1
+#include "efx.h"
+#endif
+
+#ifndef ALC_EXT_disconnect
+#define ALC_EXT_disconnect 1
+#define ALC_CONNECTED 0x313
+#endif
+
+#ifndef ALC_EXT_thread_local_context
+#define ALC_EXT_thread_local_context 1
+typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context);
+typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context);
+ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void);
+#endif
+#endif
+
+#ifndef AL_EXT_source_distance_model
+#define AL_EXT_source_distance_model 1
+#define AL_SOURCE_DISTANCE_MODEL 0x200
+#endif
+
+#ifndef AL_SOFT_buffer_sub_data
+#define AL_SOFT_buffer_sub_data 1
+#define AL_BYTE_RW_OFFSETS_SOFT 0x1031
+#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032
+typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length);
+#endif
+#endif
+
+#ifndef AL_SOFT_loop_points
+#define AL_SOFT_loop_points 1
+#define AL_LOOP_POINTS_SOFT 0x2015
+#endif
+
+#ifndef AL_EXT_FOLDBACK
+#define AL_EXT_FOLDBACK 1
+#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK"
+#define AL_FOLDBACK_EVENT_BLOCK 0x4112
+#define AL_FOLDBACK_EVENT_START 0x4111
+#define AL_FOLDBACK_EVENT_STOP 0x4113
+#define AL_FOLDBACK_MODE_MONO 0x4101
+#define AL_FOLDBACK_MODE_STEREO 0x4102
+typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei);
+typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK);
+typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback);
+AL_API void AL_APIENTRY alRequestFoldbackStop(void);
+#endif
+#endif
+
+#ifndef ALC_EXT_DEDICATED
+#define ALC_EXT_DEDICATED 1
+#define AL_DEDICATED_GAIN 0x0001
+#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001
+#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000
+#endif
+
+#ifndef AL_SOFT_buffer_samples
+#define AL_SOFT_buffer_samples 1
+/* Channel configurations */
+#define AL_MONO_SOFT 0x1500
+#define AL_STEREO_SOFT 0x1501
+#define AL_REAR_SOFT 0x1502
+#define AL_QUAD_SOFT 0x1503
+#define AL_5POINT1_SOFT 0x1504
+#define AL_6POINT1_SOFT 0x1505
+#define AL_7POINT1_SOFT 0x1506
+
+/* Sample types */
+#define AL_BYTE_SOFT 0x1400
+#define AL_UNSIGNED_BYTE_SOFT 0x1401
+#define AL_SHORT_SOFT 0x1402
+#define AL_UNSIGNED_SHORT_SOFT 0x1403
+#define AL_INT_SOFT 0x1404
+#define AL_UNSIGNED_INT_SOFT 0x1405
+#define AL_FLOAT_SOFT 0x1406
+#define AL_DOUBLE_SOFT 0x1407
+#define AL_BYTE3_SOFT 0x1408
+#define AL_UNSIGNED_BYTE3_SOFT 0x1409
+
+/* Storage formats */
+#define AL_MONO8_SOFT 0x1100
+#define AL_MONO16_SOFT 0x1101
+#define AL_MONO32F_SOFT 0x10010
+#define AL_STEREO8_SOFT 0x1102
+#define AL_STEREO16_SOFT 0x1103
+#define AL_STEREO32F_SOFT 0x10011
+#define AL_QUAD8_SOFT 0x1204
+#define AL_QUAD16_SOFT 0x1205
+#define AL_QUAD32F_SOFT 0x1206
+#define AL_REAR8_SOFT 0x1207
+#define AL_REAR16_SOFT 0x1208
+#define AL_REAR32F_SOFT 0x1209
+#define AL_5POINT1_8_SOFT 0x120A
+#define AL_5POINT1_16_SOFT 0x120B
+#define AL_5POINT1_32F_SOFT 0x120C
+#define AL_6POINT1_8_SOFT 0x120D
+#define AL_6POINT1_16_SOFT 0x120E
+#define AL_6POINT1_32F_SOFT 0x120F
+#define AL_7POINT1_8_SOFT 0x1210
+#define AL_7POINT1_16_SOFT 0x1211
+#define AL_7POINT1_32F_SOFT 0x1212
+
+/* Buffer attributes */
+#define AL_INTERNAL_FORMAT_SOFT 0x2008
+#define AL_BYTE_LENGTH_SOFT 0x2009
+#define AL_SAMPLE_LENGTH_SOFT 0x200A
+#define AL_SEC_LENGTH_SOFT 0x200B
+
+typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*);
+typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*);
+typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*);
+typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data);
+AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data);
+AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data);
+AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format);
+#endif
+#endif
+
+#ifndef AL_SOFT_direct_channels
+#define AL_SOFT_direct_channels 1
+#define AL_DIRECT_CHANNELS_SOFT 0x1033
+#endif
+
+#ifndef ALC_SOFT_loopback
+#define ALC_SOFT_loopback 1
+#define ALC_FORMAT_CHANNELS_SOFT 0x1990
+#define ALC_FORMAT_TYPE_SOFT 0x1991
+
+/* Sample types */
+#define ALC_BYTE_SOFT 0x1400
+#define ALC_UNSIGNED_BYTE_SOFT 0x1401
+#define ALC_SHORT_SOFT 0x1402
+#define ALC_UNSIGNED_SHORT_SOFT 0x1403
+#define ALC_INT_SOFT 0x1404
+#define ALC_UNSIGNED_INT_SOFT 0x1405
+#define ALC_FLOAT_SOFT 0x1406
+
+/* Channel configurations */
+#define ALC_MONO_SOFT 0x1500
+#define ALC_STEREO_SOFT 0x1501
+#define ALC_QUAD_SOFT 0x1503
+#define ALC_5POINT1_SOFT 0x1504
+#define ALC_6POINT1_SOFT 0x1505
+#define ALC_7POINT1_SOFT 0x1506
+
+typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*);
+typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum);
+typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName);
+ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type);
+ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
+#endif
+#endif
+
+#ifndef AL_EXT_STEREO_ANGLES
+#define AL_EXT_STEREO_ANGLES 1
+#define AL_STEREO_ANGLES 0x1030
+#endif
+
+#ifndef AL_EXT_SOURCE_RADIUS
+#define AL_EXT_SOURCE_RADIUS 1
+#define AL_SOURCE_RADIUS 0x1031
+#endif
+
+#ifndef AL_SOFT_source_latency
+#define AL_SOFT_source_latency 1
+#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200
+#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201
+typedef int64_t ALint64SOFT;
+typedef uint64_t ALuint64SOFT;
+typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble);
+typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble);
+typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*);
+typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*);
+typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*);
+typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*);
+typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT);
+typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT);
+typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*);
+typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*);
+typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*);
+typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value);
+AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3);
+AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values);
+AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value);
+AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3);
+AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values);
+AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value);
+AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3);
+AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values);
+AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value);
+AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3);
+AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values);
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/AL/AL/efx-creative.h b/external/AL/AL/efx-creative.h
new file mode 100644
index 0000000..0a04c98
--- /dev/null
+++ b/external/AL/AL/efx-creative.h
@@ -0,0 +1,3 @@
+/* The tokens that would be defined here are already defined in efx.h. This
+ * empty file is here to provide compatibility with Windows-based projects
+ * that would include it. */
diff --git a/external/AL/AL/efx-presets.h b/external/AL/AL/efx-presets.h
new file mode 100644
index 0000000..86dcbda
--- /dev/null
+++ b/external/AL/AL/efx-presets.h
@@ -0,0 +1,402 @@
+/* Reverb presets for EFX */
+
+#ifndef EFX_PRESETS_H
+#define EFX_PRESETS_H
+
+#ifndef EFXEAXREVERBPROPERTIES_DEFINED
+#define EFXEAXREVERBPROPERTIES_DEFINED
+typedef struct {
+ float flDensity;
+ float flDiffusion;
+ float flGain;
+ float flGainHF;
+ float flGainLF;
+ float flDecayTime;
+ float flDecayHFRatio;
+ float flDecayLFRatio;
+ float flReflectionsGain;
+ float flReflectionsDelay;
+ float flReflectionsPan[3];
+ float flLateReverbGain;
+ float flLateReverbDelay;
+ float flLateReverbPan[3];
+ float flEchoTime;
+ float flEchoDepth;
+ float flModulationTime;
+ float flModulationDepth;
+ float flAirAbsorptionGainHF;
+ float flHFReference;
+ float flLFReference;
+ float flRoomRolloffFactor;
+ int iDecayHFLimit;
+} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES;
+#endif
+
+/* Default Presets */
+
+#define EFX_REVERB_PRESET_GENERIC \
+ { 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PADDEDCELL \
+ { 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ROOM \
+ { 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_BATHROOM \
+ { 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_LIVINGROOM \
+ { 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_STONEROOM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_AUDITORIUM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CONCERTHALL \
+ { 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CAVE \
+ { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_ARENA \
+ { 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_HANGAR \
+ { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CARPETEDHALLWAY \
+ { 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_HALLWAY \
+ { 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_STONECORRIDOR \
+ { 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ALLEY \
+ { 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FOREST \
+ { 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CITY \
+ { 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_MOUNTAINS \
+ { 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_QUARRY \
+ { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PLAIN \
+ { 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PARKINGLOT \
+ { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_SEWERPIPE \
+ { 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_UNDERWATER \
+ { 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DRUGGED \
+ { 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_DIZZY \
+ { 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_PSYCHOTIC \
+ { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+/* Castle Presets */
+
+#define EFX_REVERB_PRESET_CASTLE_SMALLROOM \
+ { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 1.2200f, 0.8300f, 0.3100f, 0.8913f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE \
+ { 1.0000f, 0.8900f, 0.3162f, 0.3162f, 0.1000f, 2.3200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_MEDIUMROOM \
+ { 1.0000f, 0.9300f, 0.3162f, 0.2818f, 0.1000f, 2.0400f, 0.8300f, 0.4600f, 0.6310f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1550f, 0.0300f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_LARGEROOM \
+ { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.1259f, 2.5300f, 0.8300f, 0.5000f, 0.4467f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1850f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_LONGPASSAGE \
+ { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 3.4200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_HALL \
+ { 1.0000f, 0.8100f, 0.3162f, 0.2818f, 0.1778f, 3.1400f, 0.7900f, 0.6200f, 0.1778f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_CUPBOARD \
+ { 1.0000f, 0.8900f, 0.3162f, 0.2818f, 0.1000f, 0.6700f, 0.8700f, 0.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 3.5481f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_COURTYARD \
+ { 1.0000f, 0.4200f, 0.3162f, 0.4467f, 0.1995f, 2.1300f, 0.6100f, 0.2300f, 0.2239f, 0.1600f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3700f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_CASTLE_ALCOVE \
+ { 1.0000f, 0.8900f, 0.3162f, 0.5012f, 0.1000f, 1.6400f, 0.8700f, 0.3100f, 1.0000f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+/* Factory Presets */
+
+#define EFX_REVERB_PRESET_FACTORY_SMALLROOM \
+ { 0.3645f, 0.8200f, 0.3162f, 0.7943f, 0.5012f, 1.7200f, 0.6500f, 1.3100f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.1190f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE \
+ { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 2.5300f, 0.6500f, 1.3100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_MEDIUMROOM \
+ { 0.4287f, 0.8200f, 0.2512f, 0.7943f, 0.5012f, 2.7600f, 0.6500f, 1.3100f, 0.2818f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1740f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_LARGEROOM \
+ { 0.4287f, 0.7500f, 0.2512f, 0.7079f, 0.6310f, 4.2400f, 0.5100f, 1.3100f, 0.1778f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2310f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_LONGPASSAGE \
+ { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 4.0600f, 0.6500f, 1.3100f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_HALL \
+ { 0.4287f, 0.7500f, 0.3162f, 0.7079f, 0.6310f, 7.4300f, 0.5100f, 1.3100f, 0.0631f, 0.0730f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_CUPBOARD \
+ { 0.3071f, 0.6300f, 0.2512f, 0.7943f, 0.5012f, 0.4900f, 0.6500f, 1.3100f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.1070f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_COURTYARD \
+ { 0.3071f, 0.5700f, 0.3162f, 0.3162f, 0.6310f, 2.3200f, 0.2900f, 0.5600f, 0.2239f, 0.1400f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2900f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_ALCOVE \
+ { 0.3645f, 0.5900f, 0.2512f, 0.7943f, 0.5012f, 3.1400f, 0.6500f, 1.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1140f, 0.1000f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+/* Ice Palace Presets */
+
+#define EFX_REVERB_PRESET_ICEPALACE_SMALLROOM \
+ { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 1.5100f, 1.5300f, 0.2700f, 0.8913f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1640f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_SHORTPASSAGE \
+ { 1.0000f, 0.7500f, 0.3162f, 0.5623f, 0.2818f, 1.7900f, 1.4600f, 0.2800f, 0.5012f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_MEDIUMROOM \
+ { 1.0000f, 0.8700f, 0.3162f, 0.5623f, 0.4467f, 2.2200f, 1.5300f, 0.3200f, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_LARGEROOM \
+ { 1.0000f, 0.8100f, 0.3162f, 0.5623f, 0.4467f, 3.1400f, 1.5300f, 0.3200f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_LONGPASSAGE \
+ { 1.0000f, 0.7700f, 0.3162f, 0.5623f, 0.3981f, 3.0100f, 1.4600f, 0.2800f, 0.7943f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.0400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_HALL \
+ { 1.0000f, 0.7600f, 0.3162f, 0.4467f, 0.5623f, 5.4900f, 1.5300f, 0.3800f, 0.1122f, 0.0540f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0520f, { 0.0000f, 0.0000f, 0.0000f }, 0.2260f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_CUPBOARD \
+ { 1.0000f, 0.8300f, 0.3162f, 0.5012f, 0.2239f, 0.7600f, 1.5300f, 0.2600f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1430f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_COURTYARD \
+ { 1.0000f, 0.5900f, 0.3162f, 0.2818f, 0.3162f, 2.0400f, 1.2000f, 0.3800f, 0.3162f, 0.1730f, { 0.0000f, 0.0000f, 0.0000f }, 0.3162f, 0.0430f, { 0.0000f, 0.0000f, 0.0000f }, 0.2350f, 0.4800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_ALCOVE \
+ { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 2.7600f, 1.4600f, 0.2800f, 1.1220f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1610f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+/* Space Station Presets */
+
+#define EFX_REVERB_PRESET_SPACESTATION_SMALLROOM \
+ { 0.2109f, 0.7000f, 0.3162f, 0.7079f, 0.8913f, 1.7200f, 0.8200f, 0.5500f, 0.7943f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 0.1880f, 0.2600f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE \
+ { 0.2109f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 3.5700f, 0.5000f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1720f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM \
+ { 0.2109f, 0.7500f, 0.3162f, 0.6310f, 0.8913f, 3.0100f, 0.5000f, 0.5500f, 0.3981f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2090f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_LARGEROOM \
+ { 0.3645f, 0.8100f, 0.3162f, 0.6310f, 0.8913f, 3.8900f, 0.3800f, 0.6100f, 0.3162f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2330f, 0.2800f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE \
+ { 0.4287f, 0.8200f, 0.3162f, 0.6310f, 0.8913f, 4.6200f, 0.6200f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_HALL \
+ { 0.4287f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 7.1100f, 0.3800f, 0.6100f, 0.1778f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2500f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_CUPBOARD \
+ { 0.1715f, 0.5600f, 0.3162f, 0.7079f, 0.8913f, 0.7900f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1810f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_ALCOVE \
+ { 0.2109f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.1600f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1920f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+/* Wooden Galleon Presets */
+
+#define EFX_REVERB_PRESET_WOODEN_SMALLROOM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1122f, 0.3162f, 0.7900f, 0.3200f, 0.8700f, 1.0000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.7500f, 0.5000f, 0.8700f, 0.8913f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_MEDIUMROOM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.2818f, 1.4700f, 0.4200f, 0.8200f, 0.8913f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_LARGEROOM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.2818f, 2.6500f, 0.3300f, 0.8200f, 0.8913f, 0.0660f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_LONGPASSAGE \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.3162f, 1.9900f, 0.4000f, 0.7900f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4467f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_HALL \
+ { 1.0000f, 1.0000f, 0.3162f, 0.0794f, 0.2818f, 3.4500f, 0.3000f, 0.8200f, 0.8913f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_CUPBOARD \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1413f, 0.3162f, 0.5600f, 0.4600f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_COURTYARD \
+ { 1.0000f, 0.6500f, 0.3162f, 0.0794f, 0.3162f, 1.7900f, 0.3500f, 0.7900f, 0.5623f, 0.1230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_ALCOVE \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.2200f, 0.6200f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+/* Sports Presets */
+
+#define EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.4467f, 0.7943f, 6.2600f, 0.5100f, 1.1000f, 0.0631f, 0.1830f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPORT_SQUASHCOURT \
+ { 1.0000f, 0.7500f, 0.3162f, 0.3162f, 0.7943f, 2.2200f, 0.9100f, 1.1600f, 0.4467f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1260f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPORT_SMALLSWIMMINGPOOL \
+ { 1.0000f, 0.7000f, 0.3162f, 0.7943f, 0.8913f, 2.7600f, 1.2500f, 1.1400f, 0.6310f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_SPORT_LARGESWIMMINGPOOL \
+ { 1.0000f, 0.8200f, 0.3162f, 0.7943f, 1.0000f, 5.4900f, 1.3100f, 1.1400f, 0.4467f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2220f, 0.5500f, 1.1590f, 0.2100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_SPORT_GYMNASIUM \
+ { 1.0000f, 0.8100f, 0.3162f, 0.4467f, 0.8913f, 3.1400f, 1.0600f, 1.3500f, 0.3981f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0450f, { 0.0000f, 0.0000f, 0.0000f }, 0.1460f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPORT_FULLSTADIUM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.0708f, 0.7943f, 5.2500f, 0.1700f, 0.8000f, 0.1000f, 0.1880f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPORT_STADIUMTANNOY \
+ { 1.0000f, 0.7800f, 0.3162f, 0.5623f, 0.5012f, 2.5300f, 0.8800f, 0.6800f, 0.2818f, 0.2300f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+/* Prefab Presets */
+
+#define EFX_REVERB_PRESET_PREFAB_WORKSHOP \
+ { 0.4287f, 1.0000f, 0.3162f, 0.1413f, 0.3981f, 0.7600f, 1.0000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_PREFAB_SCHOOLROOM \
+ { 0.4022f, 0.6900f, 0.3162f, 0.6310f, 0.5012f, 0.9800f, 0.4500f, 0.1800f, 1.4125f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PREFAB_PRACTISEROOM \
+ { 0.4022f, 0.8700f, 0.3162f, 0.3981f, 0.5012f, 1.1200f, 0.5600f, 0.1800f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PREFAB_OUTHOUSE \
+ { 1.0000f, 0.8200f, 0.3162f, 0.1122f, 0.1585f, 1.3800f, 0.3800f, 0.3500f, 0.8913f, 0.0240f, { 0.0000f, 0.0000f, -0.0000f }, 0.6310f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.1210f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_PREFAB_CARAVAN \
+ { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.1259f, 0.4300f, 1.5000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+/* Dome and Pipe Presets */
+
+#define EFX_REVERB_PRESET_DOME_TOMB \
+ { 1.0000f, 0.7900f, 0.3162f, 0.3548f, 0.2239f, 4.1800f, 0.2100f, 0.1000f, 0.3868f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 1.6788f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_PIPE_SMALL \
+ { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 5.0400f, 0.1000f, 0.1000f, 0.5012f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 2.5119f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DOME_SAINTPAULS \
+ { 1.0000f, 0.8700f, 0.3162f, 0.3548f, 0.2239f, 10.4800f, 0.1900f, 0.1000f, 0.1778f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0420f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PIPE_LONGTHIN \
+ { 0.2560f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 9.2100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_PIPE_LARGE \
+ { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 8.4500f, 0.1000f, 0.1000f, 0.3981f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PIPE_RESONANT \
+ { 0.1373f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 6.8100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
+
+/* Outdoors Presets */
+
+#define EFX_REVERB_PRESET_OUTDOORS_BACKYARD \
+ { 1.0000f, 0.4500f, 0.3162f, 0.2512f, 0.5012f, 1.1200f, 0.3400f, 0.4600f, 0.4467f, 0.0690f, { 0.0000f, 0.0000f, -0.0000f }, 0.7079f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS \
+ { 1.0000f, 0.0000f, 0.3162f, 0.0112f, 0.6310f, 2.1300f, 0.2100f, 0.4600f, 0.1778f, 0.3000f, { 0.0000f, 0.0000f, -0.0000f }, 0.4467f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON \
+ { 1.0000f, 0.7400f, 0.3162f, 0.1778f, 0.6310f, 3.8900f, 0.2100f, 0.4600f, 0.3162f, 0.2230f, { 0.0000f, 0.0000f, -0.0000f }, 0.3548f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_OUTDOORS_CREEK \
+ { 1.0000f, 0.3500f, 0.3162f, 0.1778f, 0.5012f, 2.1300f, 0.2100f, 0.4600f, 0.3981f, 0.1150f, { 0.0000f, 0.0000f, -0.0000f }, 0.1995f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_OUTDOORS_VALLEY \
+ { 1.0000f, 0.2800f, 0.3162f, 0.0282f, 0.1585f, 2.8800f, 0.2600f, 0.3500f, 0.1413f, 0.2630f, { 0.0000f, 0.0000f, -0.0000f }, 0.3981f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
+
+/* Mood Presets */
+
+#define EFX_REVERB_PRESET_MOOD_HEAVEN \
+ { 1.0000f, 0.9400f, 0.3162f, 0.7943f, 0.4467f, 5.0400f, 1.1200f, 0.5600f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0800f, 2.7420f, 0.0500f, 0.9977f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_MOOD_HELL \
+ { 1.0000f, 0.5700f, 0.3162f, 0.3548f, 0.4467f, 3.5700f, 0.4900f, 2.0000f, 0.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1100f, 0.0400f, 2.1090f, 0.5200f, 0.9943f, 5000.0000f, 139.5000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_MOOD_MEMORY \
+ { 1.0000f, 0.8500f, 0.3162f, 0.6310f, 0.3548f, 4.0600f, 0.8200f, 0.5600f, 0.0398f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.4740f, 0.4500f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+/* Driving Presets */
+
+#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \
+ { 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \
+ { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_DRIVING_INCAR_RACER \
+ { 0.0832f, 0.8000f, 0.3162f, 1.0000f, 0.7943f, 0.1700f, 2.0000f, 0.4100f, 1.7783f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS \
+ { 0.0832f, 0.8000f, 0.3162f, 0.6310f, 1.0000f, 0.1700f, 0.7500f, 0.4100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY \
+ { 0.2560f, 1.0000f, 0.3162f, 0.1000f, 0.5012f, 0.1300f, 0.4100f, 0.4600f, 0.7943f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND \
+ { 1.0000f, 1.0000f, 0.3162f, 0.2818f, 0.6310f, 3.0100f, 1.3700f, 1.2800f, 0.3548f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.1778f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND \
+ { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 0.7943f, 4.6200f, 1.7500f, 1.4000f, 0.2082f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_DRIVING_TUNNEL \
+ { 1.0000f, 0.8100f, 0.3162f, 0.3981f, 0.8913f, 3.4200f, 0.9400f, 1.3100f, 0.7079f, 0.0510f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.0500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 155.3000f, 0.0000f, 0x1 }
+
+/* City Presets */
+
+#define EFX_REVERB_PRESET_CITY_STREETS \
+ { 1.0000f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.7900f, 1.1200f, 0.9100f, 0.2818f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 0.1995f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CITY_SUBWAY \
+ { 1.0000f, 0.7400f, 0.3162f, 0.7079f, 0.8913f, 3.0100f, 1.2300f, 0.9100f, 0.7079f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CITY_MUSEUM \
+ { 1.0000f, 0.8200f, 0.3162f, 0.1778f, 0.1778f, 3.2800f, 1.4000f, 0.5700f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_CITY_LIBRARY \
+ { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.0891f, 2.7600f, 0.8900f, 0.4100f, 0.3548f, 0.0290f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_CITY_UNDERPASS \
+ { 1.0000f, 0.8200f, 0.3162f, 0.4467f, 0.8913f, 3.5700f, 1.1200f, 0.9100f, 0.3981f, 0.0590f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1400f, 0.2500f, 0.0000f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CITY_ABANDONED \
+ { 1.0000f, 0.6900f, 0.3162f, 0.7943f, 0.8913f, 3.2800f, 1.1700f, 0.9100f, 0.4467f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9966f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+/* Misc. Presets */
+
+#define EFX_REVERB_PRESET_DUSTYROOM \
+ { 0.3645f, 0.5600f, 0.3162f, 0.7943f, 0.7079f, 1.7900f, 0.3800f, 0.2100f, 0.5012f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0060f, { 0.0000f, 0.0000f, 0.0000f }, 0.2020f, 0.0500f, 0.2500f, 0.0000f, 0.9886f, 13046.0000f, 163.3000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CHAPEL \
+ { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 1.0000f, 4.6200f, 0.6400f, 1.2300f, 0.4467f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.1100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SMALLWATERROOM \
+ { 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#endif /* EFX_PRESETS_H */
diff --git a/external/AL/AL/efx.h b/external/AL/AL/efx.h
new file mode 100644
index 0000000..5776698
--- /dev/null
+++ b/external/AL/AL/efx.h
@@ -0,0 +1,761 @@
+#ifndef AL_EFX_H
+#define AL_EFX_H
+
+
+#include "alc.h"
+#include "al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ALC_EXT_EFX_NAME "ALC_EXT_EFX"
+
+#define ALC_EFX_MAJOR_VERSION 0x20001
+#define ALC_EFX_MINOR_VERSION 0x20002
+#define ALC_MAX_AUXILIARY_SENDS 0x20003
+
+
+/* Listener properties. */
+#define AL_METERS_PER_UNIT 0x20004
+
+/* Source properties. */
+#define AL_DIRECT_FILTER 0x20005
+#define AL_AUXILIARY_SEND_FILTER 0x20006
+#define AL_AIR_ABSORPTION_FACTOR 0x20007
+#define AL_ROOM_ROLLOFF_FACTOR 0x20008
+#define AL_CONE_OUTER_GAINHF 0x20009
+#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A
+#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B
+#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C
+
+
+/* Effect properties. */
+
+/* Reverb effect parameters */
+#define AL_REVERB_DENSITY 0x0001
+#define AL_REVERB_DIFFUSION 0x0002
+#define AL_REVERB_GAIN 0x0003
+#define AL_REVERB_GAINHF 0x0004
+#define AL_REVERB_DECAY_TIME 0x0005
+#define AL_REVERB_DECAY_HFRATIO 0x0006
+#define AL_REVERB_REFLECTIONS_GAIN 0x0007
+#define AL_REVERB_REFLECTIONS_DELAY 0x0008
+#define AL_REVERB_LATE_REVERB_GAIN 0x0009
+#define AL_REVERB_LATE_REVERB_DELAY 0x000A
+#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B
+#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C
+#define AL_REVERB_DECAY_HFLIMIT 0x000D
+
+/* EAX Reverb effect parameters */
+#define AL_EAXREVERB_DENSITY 0x0001
+#define AL_EAXREVERB_DIFFUSION 0x0002
+#define AL_EAXREVERB_GAIN 0x0003
+#define AL_EAXREVERB_GAINHF 0x0004
+#define AL_EAXREVERB_GAINLF 0x0005
+#define AL_EAXREVERB_DECAY_TIME 0x0006
+#define AL_EAXREVERB_DECAY_HFRATIO 0x0007
+#define AL_EAXREVERB_DECAY_LFRATIO 0x0008
+#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009
+#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A
+#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B
+#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C
+#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D
+#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E
+#define AL_EAXREVERB_ECHO_TIME 0x000F
+#define AL_EAXREVERB_ECHO_DEPTH 0x0010
+#define AL_EAXREVERB_MODULATION_TIME 0x0011
+#define AL_EAXREVERB_MODULATION_DEPTH 0x0012
+#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013
+#define AL_EAXREVERB_HFREFERENCE 0x0014
+#define AL_EAXREVERB_LFREFERENCE 0x0015
+#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016
+#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017
+
+/* Chorus effect parameters */
+#define AL_CHORUS_WAVEFORM 0x0001
+#define AL_CHORUS_PHASE 0x0002
+#define AL_CHORUS_RATE 0x0003
+#define AL_CHORUS_DEPTH 0x0004
+#define AL_CHORUS_FEEDBACK 0x0005
+#define AL_CHORUS_DELAY 0x0006
+
+/* Distortion effect parameters */
+#define AL_DISTORTION_EDGE 0x0001
+#define AL_DISTORTION_GAIN 0x0002
+#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003
+#define AL_DISTORTION_EQCENTER 0x0004
+#define AL_DISTORTION_EQBANDWIDTH 0x0005
+
+/* Echo effect parameters */
+#define AL_ECHO_DELAY 0x0001
+#define AL_ECHO_LRDELAY 0x0002
+#define AL_ECHO_DAMPING 0x0003
+#define AL_ECHO_FEEDBACK 0x0004
+#define AL_ECHO_SPREAD 0x0005
+
+/* Flanger effect parameters */
+#define AL_FLANGER_WAVEFORM 0x0001
+#define AL_FLANGER_PHASE 0x0002
+#define AL_FLANGER_RATE 0x0003
+#define AL_FLANGER_DEPTH 0x0004
+#define AL_FLANGER_FEEDBACK 0x0005
+#define AL_FLANGER_DELAY 0x0006
+
+/* Frequency shifter effect parameters */
+#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001
+#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002
+#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003
+
+/* Vocal morpher effect parameters */
+#define AL_VOCAL_MORPHER_PHONEMEA 0x0001
+#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002
+#define AL_VOCAL_MORPHER_PHONEMEB 0x0003
+#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004
+#define AL_VOCAL_MORPHER_WAVEFORM 0x0005
+#define AL_VOCAL_MORPHER_RATE 0x0006
+
+/* Pitchshifter effect parameters */
+#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001
+#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002
+
+/* Ringmodulator effect parameters */
+#define AL_RING_MODULATOR_FREQUENCY 0x0001
+#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002
+#define AL_RING_MODULATOR_WAVEFORM 0x0003
+
+/* Autowah effect parameters */
+#define AL_AUTOWAH_ATTACK_TIME 0x0001
+#define AL_AUTOWAH_RELEASE_TIME 0x0002
+#define AL_AUTOWAH_RESONANCE 0x0003
+#define AL_AUTOWAH_PEAK_GAIN 0x0004
+
+/* Compressor effect parameters */
+#define AL_COMPRESSOR_ONOFF 0x0001
+
+/* Equalizer effect parameters */
+#define AL_EQUALIZER_LOW_GAIN 0x0001
+#define AL_EQUALIZER_LOW_CUTOFF 0x0002
+#define AL_EQUALIZER_MID1_GAIN 0x0003
+#define AL_EQUALIZER_MID1_CENTER 0x0004
+#define AL_EQUALIZER_MID1_WIDTH 0x0005
+#define AL_EQUALIZER_MID2_GAIN 0x0006
+#define AL_EQUALIZER_MID2_CENTER 0x0007
+#define AL_EQUALIZER_MID2_WIDTH 0x0008
+#define AL_EQUALIZER_HIGH_GAIN 0x0009
+#define AL_EQUALIZER_HIGH_CUTOFF 0x000A
+
+/* Effect type */
+#define AL_EFFECT_FIRST_PARAMETER 0x0000
+#define AL_EFFECT_LAST_PARAMETER 0x8000
+#define AL_EFFECT_TYPE 0x8001
+
+/* Effect types, used with the AL_EFFECT_TYPE property */
+#define AL_EFFECT_NULL 0x0000
+#define AL_EFFECT_REVERB 0x0001
+#define AL_EFFECT_CHORUS 0x0002
+#define AL_EFFECT_DISTORTION 0x0003
+#define AL_EFFECT_ECHO 0x0004
+#define AL_EFFECT_FLANGER 0x0005
+#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006
+#define AL_EFFECT_VOCAL_MORPHER 0x0007
+#define AL_EFFECT_PITCH_SHIFTER 0x0008
+#define AL_EFFECT_RING_MODULATOR 0x0009
+#define AL_EFFECT_AUTOWAH 0x000A
+#define AL_EFFECT_COMPRESSOR 0x000B
+#define AL_EFFECT_EQUALIZER 0x000C
+#define AL_EFFECT_EAXREVERB 0x8000
+
+/* Auxiliary Effect Slot properties. */
+#define AL_EFFECTSLOT_EFFECT 0x0001
+#define AL_EFFECTSLOT_GAIN 0x0002
+#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003
+
+/* NULL Auxiliary Slot ID to disable a source send. */
+#define AL_EFFECTSLOT_NULL 0x0000
+
+
+/* Filter properties. */
+
+/* Lowpass filter parameters */
+#define AL_LOWPASS_GAIN 0x0001
+#define AL_LOWPASS_GAINHF 0x0002
+
+/* Highpass filter parameters */
+#define AL_HIGHPASS_GAIN 0x0001
+#define AL_HIGHPASS_GAINLF 0x0002
+
+/* Bandpass filter parameters */
+#define AL_BANDPASS_GAIN 0x0001
+#define AL_BANDPASS_GAINLF 0x0002
+#define AL_BANDPASS_GAINHF 0x0003
+
+/* Filter type */
+#define AL_FILTER_FIRST_PARAMETER 0x0000
+#define AL_FILTER_LAST_PARAMETER 0x8000
+#define AL_FILTER_TYPE 0x8001
+
+/* Filter types, used with the AL_FILTER_TYPE property */
+#define AL_FILTER_NULL 0x0000
+#define AL_FILTER_LOWPASS 0x0001
+#define AL_FILTER_HIGHPASS 0x0002
+#define AL_FILTER_BANDPASS 0x0003
+
+
+/* Effect object function types. */
+typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint);
+typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*);
+typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*);
+typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*);
+
+/* Filter object function types. */
+typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint);
+typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*);
+typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*);
+typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*);
+
+/* Auxiliary Effect Slot object function types. */
+typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*);
+
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
+AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects);
+AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect);
+AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues);
+AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
+
+AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
+AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters);
+AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter);
+AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues);
+AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
+
+AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
+AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots);
+AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
+#endif
+
+/* Filter ranges and defaults. */
+
+/* Lowpass filter */
+#define AL_LOWPASS_MIN_GAIN (0.0f)
+#define AL_LOWPASS_MAX_GAIN (1.0f)
+#define AL_LOWPASS_DEFAULT_GAIN (1.0f)
+
+#define AL_LOWPASS_MIN_GAINHF (0.0f)
+#define AL_LOWPASS_MAX_GAINHF (1.0f)
+#define AL_LOWPASS_DEFAULT_GAINHF (1.0f)
+
+/* Highpass filter */
+#define AL_HIGHPASS_MIN_GAIN (0.0f)
+#define AL_HIGHPASS_MAX_GAIN (1.0f)
+#define AL_HIGHPASS_DEFAULT_GAIN (1.0f)
+
+#define AL_HIGHPASS_MIN_GAINLF (0.0f)
+#define AL_HIGHPASS_MAX_GAINLF (1.0f)
+#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f)
+
+/* Bandpass filter */
+#define AL_BANDPASS_MIN_GAIN (0.0f)
+#define AL_BANDPASS_MAX_GAIN (1.0f)
+#define AL_BANDPASS_DEFAULT_GAIN (1.0f)
+
+#define AL_BANDPASS_MIN_GAINHF (0.0f)
+#define AL_BANDPASS_MAX_GAINHF (1.0f)
+#define AL_BANDPASS_DEFAULT_GAINHF (1.0f)
+
+#define AL_BANDPASS_MIN_GAINLF (0.0f)
+#define AL_BANDPASS_MAX_GAINLF (1.0f)
+#define AL_BANDPASS_DEFAULT_GAINLF (1.0f)
+
+
+/* Effect parameter ranges and defaults. */
+
+/* Standard reverb effect */
+#define AL_REVERB_MIN_DENSITY (0.0f)
+#define AL_REVERB_MAX_DENSITY (1.0f)
+#define AL_REVERB_DEFAULT_DENSITY (1.0f)
+
+#define AL_REVERB_MIN_DIFFUSION (0.0f)
+#define AL_REVERB_MAX_DIFFUSION (1.0f)
+#define AL_REVERB_DEFAULT_DIFFUSION (1.0f)
+
+#define AL_REVERB_MIN_GAIN (0.0f)
+#define AL_REVERB_MAX_GAIN (1.0f)
+#define AL_REVERB_DEFAULT_GAIN (0.32f)
+
+#define AL_REVERB_MIN_GAINHF (0.0f)
+#define AL_REVERB_MAX_GAINHF (1.0f)
+#define AL_REVERB_DEFAULT_GAINHF (0.89f)
+
+#define AL_REVERB_MIN_DECAY_TIME (0.1f)
+#define AL_REVERB_MAX_DECAY_TIME (20.0f)
+#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f)
+
+#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f)
+#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f)
+#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f)
+
+#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f)
+#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f)
+#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
+
+#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f)
+#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f)
+#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
+
+#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f)
+#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f)
+#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
+
+#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f)
+#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f)
+#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
+
+#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
+#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
+#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
+
+#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
+#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
+#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
+
+#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE
+#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE
+#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE
+
+/* EAX reverb effect */
+#define AL_EAXREVERB_MIN_DENSITY (0.0f)
+#define AL_EAXREVERB_MAX_DENSITY (1.0f)
+#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f)
+
+#define AL_EAXREVERB_MIN_DIFFUSION (0.0f)
+#define AL_EAXREVERB_MAX_DIFFUSION (1.0f)
+#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f)
+
+#define AL_EAXREVERB_MIN_GAIN (0.0f)
+#define AL_EAXREVERB_MAX_GAIN (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAIN (0.32f)
+
+#define AL_EAXREVERB_MIN_GAINHF (0.0f)
+#define AL_EAXREVERB_MAX_GAINHF (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f)
+
+#define AL_EAXREVERB_MIN_GAINLF (0.0f)
+#define AL_EAXREVERB_MAX_GAINLF (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f)
+
+#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f)
+
+#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f)
+
+#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f)
+
+#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f)
+#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f)
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
+
+#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f)
+#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f)
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
+
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f)
+
+#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f)
+#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f)
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
+
+#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f)
+#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f)
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
+
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f)
+
+#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f)
+#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f)
+#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f)
+
+#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f)
+#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f)
+#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f)
+
+#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f)
+#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f)
+#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f)
+
+#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f)
+#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f)
+#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f)
+
+#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
+#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
+#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
+
+#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f)
+#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f)
+#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f)
+
+#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f)
+#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f)
+#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f)
+
+#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
+#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
+#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
+
+#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE
+#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE
+#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE
+
+/* Chorus effect */
+#define AL_CHORUS_WAVEFORM_SINUSOID (0)
+#define AL_CHORUS_WAVEFORM_TRIANGLE (1)
+
+#define AL_CHORUS_MIN_WAVEFORM (0)
+#define AL_CHORUS_MAX_WAVEFORM (1)
+#define AL_CHORUS_DEFAULT_WAVEFORM (1)
+
+#define AL_CHORUS_MIN_PHASE (-180)
+#define AL_CHORUS_MAX_PHASE (180)
+#define AL_CHORUS_DEFAULT_PHASE (90)
+
+#define AL_CHORUS_MIN_RATE (0.0f)
+#define AL_CHORUS_MAX_RATE (10.0f)
+#define AL_CHORUS_DEFAULT_RATE (1.1f)
+
+#define AL_CHORUS_MIN_DEPTH (0.0f)
+#define AL_CHORUS_MAX_DEPTH (1.0f)
+#define AL_CHORUS_DEFAULT_DEPTH (0.1f)
+
+#define AL_CHORUS_MIN_FEEDBACK (-1.0f)
+#define AL_CHORUS_MAX_FEEDBACK (1.0f)
+#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f)
+
+#define AL_CHORUS_MIN_DELAY (0.0f)
+#define AL_CHORUS_MAX_DELAY (0.016f)
+#define AL_CHORUS_DEFAULT_DELAY (0.016f)
+
+/* Distortion effect */
+#define AL_DISTORTION_MIN_EDGE (0.0f)
+#define AL_DISTORTION_MAX_EDGE (1.0f)
+#define AL_DISTORTION_DEFAULT_EDGE (0.2f)
+
+#define AL_DISTORTION_MIN_GAIN (0.01f)
+#define AL_DISTORTION_MAX_GAIN (1.0f)
+#define AL_DISTORTION_DEFAULT_GAIN (0.05f)
+
+#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f)
+#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f)
+#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f)
+
+#define AL_DISTORTION_MIN_EQCENTER (80.0f)
+#define AL_DISTORTION_MAX_EQCENTER (24000.0f)
+#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f)
+
+#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f)
+#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f)
+#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f)
+
+/* Echo effect */
+#define AL_ECHO_MIN_DELAY (0.0f)
+#define AL_ECHO_MAX_DELAY (0.207f)
+#define AL_ECHO_DEFAULT_DELAY (0.1f)
+
+#define AL_ECHO_MIN_LRDELAY (0.0f)
+#define AL_ECHO_MAX_LRDELAY (0.404f)
+#define AL_ECHO_DEFAULT_LRDELAY (0.1f)
+
+#define AL_ECHO_MIN_DAMPING (0.0f)
+#define AL_ECHO_MAX_DAMPING (0.99f)
+#define AL_ECHO_DEFAULT_DAMPING (0.5f)
+
+#define AL_ECHO_MIN_FEEDBACK (0.0f)
+#define AL_ECHO_MAX_FEEDBACK (1.0f)
+#define AL_ECHO_DEFAULT_FEEDBACK (0.5f)
+
+#define AL_ECHO_MIN_SPREAD (-1.0f)
+#define AL_ECHO_MAX_SPREAD (1.0f)
+#define AL_ECHO_DEFAULT_SPREAD (-1.0f)
+
+/* Flanger effect */
+#define AL_FLANGER_WAVEFORM_SINUSOID (0)
+#define AL_FLANGER_WAVEFORM_TRIANGLE (1)
+
+#define AL_FLANGER_MIN_WAVEFORM (0)
+#define AL_FLANGER_MAX_WAVEFORM (1)
+#define AL_FLANGER_DEFAULT_WAVEFORM (1)
+
+#define AL_FLANGER_MIN_PHASE (-180)
+#define AL_FLANGER_MAX_PHASE (180)
+#define AL_FLANGER_DEFAULT_PHASE (0)
+
+#define AL_FLANGER_MIN_RATE (0.0f)
+#define AL_FLANGER_MAX_RATE (10.0f)
+#define AL_FLANGER_DEFAULT_RATE (0.27f)
+
+#define AL_FLANGER_MIN_DEPTH (0.0f)
+#define AL_FLANGER_MAX_DEPTH (1.0f)
+#define AL_FLANGER_DEFAULT_DEPTH (1.0f)
+
+#define AL_FLANGER_MIN_FEEDBACK (-1.0f)
+#define AL_FLANGER_MAX_FEEDBACK (1.0f)
+#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f)
+
+#define AL_FLANGER_MIN_DELAY (0.0f)
+#define AL_FLANGER_MAX_DELAY (0.004f)
+#define AL_FLANGER_DEFAULT_DELAY (0.002f)
+
+/* Frequency shifter effect */
+#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f)
+#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f)
+
+#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0)
+#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0)
+
+#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0)
+#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1)
+#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2)
+
+#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0)
+#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0)
+
+/* Vocal morpher effect */
+#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0)
+
+#define AL_VOCAL_MORPHER_PHONEME_A (0)
+#define AL_VOCAL_MORPHER_PHONEME_E (1)
+#define AL_VOCAL_MORPHER_PHONEME_I (2)
+#define AL_VOCAL_MORPHER_PHONEME_O (3)
+#define AL_VOCAL_MORPHER_PHONEME_U (4)
+#define AL_VOCAL_MORPHER_PHONEME_AA (5)
+#define AL_VOCAL_MORPHER_PHONEME_AE (6)
+#define AL_VOCAL_MORPHER_PHONEME_AH (7)
+#define AL_VOCAL_MORPHER_PHONEME_AO (8)
+#define AL_VOCAL_MORPHER_PHONEME_EH (9)
+#define AL_VOCAL_MORPHER_PHONEME_ER (10)
+#define AL_VOCAL_MORPHER_PHONEME_IH (11)
+#define AL_VOCAL_MORPHER_PHONEME_IY (12)
+#define AL_VOCAL_MORPHER_PHONEME_UH (13)
+#define AL_VOCAL_MORPHER_PHONEME_UW (14)
+#define AL_VOCAL_MORPHER_PHONEME_B (15)
+#define AL_VOCAL_MORPHER_PHONEME_D (16)
+#define AL_VOCAL_MORPHER_PHONEME_F (17)
+#define AL_VOCAL_MORPHER_PHONEME_G (18)
+#define AL_VOCAL_MORPHER_PHONEME_J (19)
+#define AL_VOCAL_MORPHER_PHONEME_K (20)
+#define AL_VOCAL_MORPHER_PHONEME_L (21)
+#define AL_VOCAL_MORPHER_PHONEME_M (22)
+#define AL_VOCAL_MORPHER_PHONEME_N (23)
+#define AL_VOCAL_MORPHER_PHONEME_P (24)
+#define AL_VOCAL_MORPHER_PHONEME_R (25)
+#define AL_VOCAL_MORPHER_PHONEME_S (26)
+#define AL_VOCAL_MORPHER_PHONEME_T (27)
+#define AL_VOCAL_MORPHER_PHONEME_V (28)
+#define AL_VOCAL_MORPHER_PHONEME_Z (29)
+
+#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0)
+#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1)
+#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2)
+
+#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0)
+#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2)
+#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0)
+
+#define AL_VOCAL_MORPHER_MIN_RATE (0.0f)
+#define AL_VOCAL_MORPHER_MAX_RATE (10.0f)
+#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f)
+
+/* Pitch shifter effect */
+#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12)
+#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12)
+#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12)
+
+#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50)
+#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50)
+#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0)
+
+/* Ring modulator effect */
+#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f)
+#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f)
+#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f)
+
+#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f)
+#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f)
+#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f)
+
+#define AL_RING_MODULATOR_SINUSOID (0)
+#define AL_RING_MODULATOR_SAWTOOTH (1)
+#define AL_RING_MODULATOR_SQUARE (2)
+
+#define AL_RING_MODULATOR_MIN_WAVEFORM (0)
+#define AL_RING_MODULATOR_MAX_WAVEFORM (2)
+#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0)
+
+/* Autowah effect */
+#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f)
+#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f)
+#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f)
+
+#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f)
+#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f)
+#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f)
+
+#define AL_AUTOWAH_MIN_RESONANCE (2.0f)
+#define AL_AUTOWAH_MAX_RESONANCE (1000.0f)
+#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f)
+
+#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f)
+#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f)
+#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f)
+
+/* Compressor effect */
+#define AL_COMPRESSOR_MIN_ONOFF (0)
+#define AL_COMPRESSOR_MAX_ONOFF (1)
+#define AL_COMPRESSOR_DEFAULT_ONOFF (1)
+
+/* Equalizer effect */
+#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f)
+#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f)
+#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f)
+
+#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f)
+#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f)
+#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f)
+
+#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f)
+#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f)
+#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f)
+
+#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f)
+#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f)
+#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f)
+
+#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f)
+#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f)
+#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f)
+
+#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f)
+#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f)
+#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f)
+
+
+/* Source parameter value ranges and defaults. */
+#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f)
+#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f)
+#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f)
+
+#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
+#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
+#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
+
+#define AL_MIN_CONE_OUTER_GAINHF (0.0f)
+#define AL_MAX_CONE_OUTER_GAINHF (1.0f)
+#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f)
+
+#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE
+#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE
+#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE
+
+#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE
+#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE
+#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE
+
+#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE
+#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
+#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
+
+
+/* Listener parameter value ranges and defaults. */
+#define AL_MIN_METERS_PER_UNIT FLT_MIN
+#define AL_MAX_METERS_PER_UNIT FLT_MAX
+#define AL_DEFAULT_METERS_PER_UNIT (1.0f)
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* AL_EFX_H */
diff --git a/external/SDL2/CMakeLists.txt b/external/SDL2/CMakeLists.txt
new file mode 100644
index 0000000..33b4d39
--- /dev/null
+++ b/external/SDL2/CMakeLists.txt
@@ -0,0 +1,6 @@
+#add_custom_command(
+# TARGET tremulous POST_BUILD
+# #OUTPUT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libSDL2-2.0.0.dylib
+# COMMAND ${CMAKE_COMMAND}
+# ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/libs/Darwin/libSDL2.dylib ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libSDL2-2.0.0.dylib
+# )
diff --git a/external/SDL2/include/SDL.h b/external/SDL2/include/SDL.h
new file mode 100644
index 0000000..7647b51
--- /dev/null
+++ b/external/SDL2/include/SDL.h
@@ -0,0 +1,132 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL.h
+ *
+ * Main include header for the SDL library
+ */
+
+
+#ifndef _SDL_H
+#define _SDL_H
+
+#include "SDL_main.h"
+#include "SDL_stdinc.h"
+#include "SDL_assert.h"
+#include "SDL_atomic.h"
+#include "SDL_audio.h"
+#include "SDL_clipboard.h"
+#include "SDL_cpuinfo.h"
+#include "SDL_endian.h"
+#include "SDL_error.h"
+#include "SDL_events.h"
+#include "SDL_filesystem.h"
+#include "SDL_joystick.h"
+#include "SDL_gamecontroller.h"
+#include "SDL_haptic.h"
+#include "SDL_hints.h"
+#include "SDL_loadso.h"
+#include "SDL_log.h"
+#include "SDL_messagebox.h"
+#include "SDL_mutex.h"
+#include "SDL_power.h"
+#include "SDL_render.h"
+#include "SDL_rwops.h"
+#include "SDL_system.h"
+#include "SDL_thread.h"
+#include "SDL_timer.h"
+#include "SDL_version.h"
+#include "SDL_video.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* As of version 0.5, SDL is loaded dynamically into the application */
+
+/**
+ * \name SDL_INIT_*
+ *
+ * These are the flags which may be passed to SDL_Init(). You should
+ * specify the subsystems which you will be using in your application.
+ */
+/* @{ */
+#define SDL_INIT_TIMER 0x00000001
+#define SDL_INIT_AUDIO 0x00000010
+#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
+#define SDL_INIT_JOYSTICK 0x00000200 /**< SDL_INIT_JOYSTICK implies SDL_INIT_EVENTS */
+#define SDL_INIT_HAPTIC 0x00001000
+#define SDL_INIT_GAMECONTROLLER 0x00002000 /**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */
+#define SDL_INIT_EVENTS 0x00004000
+#define SDL_INIT_NOPARACHUTE 0x00100000 /**< compatibility; this flag is ignored. */
+#define SDL_INIT_EVERYTHING ( \
+ SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | \
+ SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER \
+ )
+/* @} */
+
+/**
+ * This function initializes the subsystems specified by \c flags
+ */
+extern DECLSPEC int SDLCALL SDL_Init(Uint32 flags);
+
+/**
+ * This function initializes specific SDL subsystems
+ *
+ * Subsystem initialization is ref-counted, you must call
+ * SDL_QuitSubSystem for each SDL_InitSubSystem to correctly
+ * shutdown a subsystem manually (or call SDL_Quit to force shutdown).
+ * If a subsystem is already loaded then this call will
+ * increase the ref-count and return.
+ */
+extern DECLSPEC int SDLCALL SDL_InitSubSystem(Uint32 flags);
+
+/**
+ * This function cleans up specific SDL subsystems
+ */
+extern DECLSPEC void SDLCALL SDL_QuitSubSystem(Uint32 flags);
+
+/**
+ * This function returns a mask of the specified subsystems which have
+ * previously been initialized.
+ *
+ * If \c flags is 0, it returns a mask of all initialized subsystems.
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_WasInit(Uint32 flags);
+
+/**
+ * This function cleans up all initialized subsystems. You should
+ * call it upon all exit conditions.
+ */
+extern DECLSPEC void SDLCALL SDL_Quit(void);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_H */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_assert.h b/external/SDL2/include/SDL_assert.h
new file mode 100644
index 0000000..402981f
--- /dev/null
+++ b/external/SDL2/include/SDL_assert.h
@@ -0,0 +1,289 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_assert_h
+#define _SDL_assert_h
+
+#include "SDL_config.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SDL_ASSERT_LEVEL
+#ifdef SDL_DEFAULT_ASSERT_LEVEL
+#define SDL_ASSERT_LEVEL SDL_DEFAULT_ASSERT_LEVEL
+#elif defined(_DEBUG) || defined(DEBUG) || \
+ (defined(__GNUC__) && !defined(__OPTIMIZE__))
+#define SDL_ASSERT_LEVEL 2
+#else
+#define SDL_ASSERT_LEVEL 1
+#endif
+#endif /* SDL_ASSERT_LEVEL */
+
+/*
+These are macros and not first class functions so that the debugger breaks
+on the assertion line and not in some random guts of SDL, and so each
+assert can have unique static variables associated with it.
+*/
+
+#if defined(_MSC_VER)
+/* Don't include intrin.h here because it contains C++ code */
+ extern void __cdecl __debugbreak(void);
+ #define SDL_TriggerBreakpoint() __debugbreak()
+#elif (!defined(__NACL__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
+ #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
+#elif defined(HAVE_SIGNAL_H)
+ #include <signal.h>
+ #define SDL_TriggerBreakpoint() raise(SIGTRAP)
+#else
+ /* How do we trigger breakpoints on this platform? */
+ #define SDL_TriggerBreakpoint()
+#endif
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */
+# define SDL_FUNCTION __func__
+#elif ((__GNUC__ >= 2) || defined(_MSC_VER))
+# define SDL_FUNCTION __FUNCTION__
+#else
+# define SDL_FUNCTION "???"
+#endif
+#define SDL_FILE __FILE__
+#define SDL_LINE __LINE__
+
+/*
+sizeof (x) makes the compiler still parse the expression even without
+assertions enabled, so the code is always checked at compile time, but
+doesn't actually generate code for it, so there are no side effects or
+expensive checks at run time, just the constant size of what x WOULD be,
+which presumably gets optimized out as unused.
+This also solves the problem of...
+
+ int somevalue = blah();
+ SDL_assert(somevalue == 1);
+
+...which would cause compiles to complain that somevalue is unused if we
+disable assertions.
+*/
+
+/* "while (0,0)" fools Microsoft's compiler's /W4 warning level into thinking
+ this condition isn't constant. And looks like an owl's face! */
+#ifdef _MSC_VER /* stupid /W4 warnings. */
+#define SDL_NULL_WHILE_LOOP_CONDITION (0,0)
+#else
+#define SDL_NULL_WHILE_LOOP_CONDITION (0)
+#endif
+
+#define SDL_disabled_assert(condition) \
+ do { (void) sizeof ((condition)); } while (SDL_NULL_WHILE_LOOP_CONDITION)
+
+typedef enum
+{
+ SDL_ASSERTION_RETRY, /**< Retry the assert immediately. */
+ SDL_ASSERTION_BREAK, /**< Make the debugger trigger a breakpoint. */
+ SDL_ASSERTION_ABORT, /**< Terminate the program. */
+ SDL_ASSERTION_IGNORE, /**< Ignore the assert. */
+ SDL_ASSERTION_ALWAYS_IGNORE /**< Ignore the assert from now on. */
+} SDL_AssertState;
+
+typedef struct SDL_AssertData
+{
+ int always_ignore;
+ unsigned int trigger_count;
+ const char *condition;
+ const char *filename;
+ int linenum;
+ const char *function;
+ const struct SDL_AssertData *next;
+} SDL_AssertData;
+
+#if (SDL_ASSERT_LEVEL > 0)
+
+/* Never call this directly. Use the SDL_assert* macros. */
+extern DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *,
+ const char *,
+ const char *, int)
+#if defined(__clang__)
+#if __has_feature(attribute_analyzer_noreturn)
+/* this tells Clang's static analysis that we're a custom assert function,
+ and that the analyzer should assume the condition was always true past this
+ SDL_assert test. */
+ __attribute__((analyzer_noreturn))
+#endif
+#endif
+;
+
+/* the do {} while(0) avoids dangling else problems:
+ if (x) SDL_assert(y); else blah();
+ ... without the do/while, the "else" could attach to this macro's "if".
+ We try to handle just the minimum we need here in a macro...the loop,
+ the static vars, and break points. The heavy lifting is handled in
+ SDL_ReportAssertion(), in SDL_assert.c.
+*/
+#define SDL_enabled_assert(condition) \
+ do { \
+ while ( !(condition) ) { \
+ static struct SDL_AssertData sdl_assert_data = { \
+ 0, 0, #condition, 0, 0, 0, 0 \
+ }; \
+ const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \
+ if (sdl_assert_state == SDL_ASSERTION_RETRY) { \
+ continue; /* go again. */ \
+ } else if (sdl_assert_state == SDL_ASSERTION_BREAK) { \
+ SDL_TriggerBreakpoint(); \
+ } \
+ break; /* not retrying. */ \
+ } \
+ } while (SDL_NULL_WHILE_LOOP_CONDITION)
+
+#endif /* enabled assertions support code */
+
+/* Enable various levels of assertions. */
+#if SDL_ASSERT_LEVEL == 0 /* assertions disabled */
+# define SDL_assert(condition) SDL_disabled_assert(condition)
+# define SDL_assert_release(condition) SDL_disabled_assert(condition)
+# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
+#elif SDL_ASSERT_LEVEL == 1 /* release settings. */
+# define SDL_assert(condition) SDL_disabled_assert(condition)
+# define SDL_assert_release(condition) SDL_enabled_assert(condition)
+# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
+#elif SDL_ASSERT_LEVEL == 2 /* normal settings. */
+# define SDL_assert(condition) SDL_enabled_assert(condition)
+# define SDL_assert_release(condition) SDL_enabled_assert(condition)
+# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
+#elif SDL_ASSERT_LEVEL == 3 /* paranoid settings. */
+# define SDL_assert(condition) SDL_enabled_assert(condition)
+# define SDL_assert_release(condition) SDL_enabled_assert(condition)
+# define SDL_assert_paranoid(condition) SDL_enabled_assert(condition)
+#else
+# error Unknown assertion level.
+#endif
+
+/* this assertion is never disabled at any level. */
+#define SDL_assert_always(condition) SDL_enabled_assert(condition)
+
+
+typedef SDL_AssertState (SDLCALL *SDL_AssertionHandler)(
+ const SDL_AssertData* data, void* userdata);
+
+/**
+ * \brief Set an application-defined assertion handler.
+ *
+ * This allows an app to show its own assertion UI and/or force the
+ * response to an assertion failure. If the app doesn't provide this, SDL
+ * will try to do the right thing, popping up a system-specific GUI dialog,
+ * and probably minimizing any fullscreen windows.
+ *
+ * This callback may fire from any thread, but it runs wrapped in a mutex, so
+ * it will only fire from one thread at a time.
+ *
+ * Setting the callback to NULL restores SDL's original internal handler.
+ *
+ * This callback is NOT reset to SDL's internal handler upon SDL_Quit()!
+ *
+ * \return SDL_AssertState value of how to handle the assertion failure.
+ *
+ * \param handler Callback function, called when an assertion fails.
+ * \param userdata A pointer passed to the callback as-is.
+ */
+extern DECLSPEC void SDLCALL SDL_SetAssertionHandler(
+ SDL_AssertionHandler handler,
+ void *userdata);
+
+/**
+ * \brief Get the default assertion handler.
+ *
+ * This returns the function pointer that is called by default when an
+ * assertion is triggered. This is an internal function provided by SDL,
+ * that is used for assertions when SDL_SetAssertionHandler() hasn't been
+ * used to provide a different function.
+ *
+ * \return The default SDL_AssertionHandler that is called when an assert triggers.
+ */
+extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetDefaultAssertionHandler(void);
+
+/**
+ * \brief Get the current assertion handler.
+ *
+ * This returns the function pointer that is called when an assertion is
+ * triggered. This is either the value last passed to
+ * SDL_SetAssertionHandler(), or if no application-specified function is
+ * set, is equivalent to calling SDL_GetDefaultAssertionHandler().
+ *
+ * \param puserdata Pointer to a void*, which will store the "userdata"
+ * pointer that was passed to SDL_SetAssertionHandler().
+ * This value will always be NULL for the default handler.
+ * If you don't care about this data, it is safe to pass
+ * a NULL pointer to this function to ignore it.
+ * \return The SDL_AssertionHandler that is called when an assert triggers.
+ */
+extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetAssertionHandler(void **puserdata);
+
+/**
+ * \brief Get a list of all assertion failures.
+ *
+ * Get all assertions triggered since last call to SDL_ResetAssertionReport(),
+ * or the start of the program.
+ *
+ * The proper way to examine this data looks something like this:
+ *
+ * <code>
+ * const SDL_AssertData *item = SDL_GetAssertionReport();
+ * while (item) {
+ * printf("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\n",
+ * item->condition, item->function, item->filename,
+ * item->linenum, item->trigger_count,
+ * item->always_ignore ? "yes" : "no");
+ * item = item->next;
+ * }
+ * </code>
+ *
+ * \return List of all assertions.
+ * \sa SDL_ResetAssertionReport
+ */
+extern DECLSPEC const SDL_AssertData * SDLCALL SDL_GetAssertionReport(void);
+
+/**
+ * \brief Reset the list of all assertion failures.
+ *
+ * Reset list of all assertions triggered.
+ *
+ * \sa SDL_GetAssertionReport
+ */
+extern DECLSPEC void SDLCALL SDL_ResetAssertionReport(void);
+
+
+/* these had wrong naming conventions until 2.0.4. Please update your app! */
+#define SDL_assert_state SDL_AssertState
+#define SDL_assert_data SDL_AssertData
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_assert_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_atomic.h b/external/SDL2/include/SDL_atomic.h
new file mode 100644
index 0000000..56aa81d
--- /dev/null
+++ b/external/SDL2/include/SDL_atomic.h
@@ -0,0 +1,268 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_atomic.h
+ *
+ * Atomic operations.
+ *
+ * IMPORTANT:
+ * If you are not an expert in concurrent lockless programming, you should
+ * only be using the atomic lock and reference counting functions in this
+ * file. In all other cases you should be protecting your data structures
+ * with full mutexes.
+ *
+ * The list of "safe" functions to use are:
+ * SDL_AtomicLock()
+ * SDL_AtomicUnlock()
+ * SDL_AtomicIncRef()
+ * SDL_AtomicDecRef()
+ *
+ * Seriously, here be dragons!
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * You can find out a little more about lockless programming and the
+ * subtle issues that can arise here:
+ * http://msdn.microsoft.com/en-us/library/ee418650%28v=vs.85%29.aspx
+ *
+ * There's also lots of good information here:
+ * http://www.1024cores.net/home/lock-free-algorithms
+ * http://preshing.com/
+ *
+ * These operations may or may not actually be implemented using
+ * processor specific atomic operations. When possible they are
+ * implemented as true processor specific atomic operations. When that
+ * is not possible the are implemented using locks that *do* use the
+ * available atomic operations.
+ *
+ * All of the atomic operations that modify memory are full memory barriers.
+ */
+
+#ifndef _SDL_atomic_h_
+#define _SDL_atomic_h_
+
+#include "SDL_stdinc.h"
+#include "SDL_platform.h"
+
+#include "begin_code.h"
+
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \name SDL AtomicLock
+ *
+ * The atomic locks are efficient spinlocks using CPU instructions,
+ * but are vulnerable to starvation and can spin forever if a thread
+ * holding a lock has been terminated. For this reason you should
+ * minimize the code executed inside an atomic lock and never do
+ * expensive things like API or system calls while holding them.
+ *
+ * The atomic locks are not safe to lock recursively.
+ *
+ * Porting Note:
+ * The spin lock functions and type are required and can not be
+ * emulated because they are used in the atomic emulation code.
+ */
+/* @{ */
+
+typedef int SDL_SpinLock;
+
+/**
+ * \brief Try to lock a spin lock by setting it to a non-zero value.
+ *
+ * \param lock Points to the lock.
+ *
+ * \return SDL_TRUE if the lock succeeded, SDL_FALSE if the lock is already held.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_AtomicTryLock(SDL_SpinLock *lock);
+
+/**
+ * \brief Lock a spin lock by setting it to a non-zero value.
+ *
+ * \param lock Points to the lock.
+ */
+extern DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock);
+
+/**
+ * \brief Unlock a spin lock by setting it to 0. Always returns immediately
+ *
+ * \param lock Points to the lock.
+ */
+extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock);
+
+/* @} *//* SDL AtomicLock */
+
+
+/**
+ * The compiler barrier prevents the compiler from reordering
+ * reads and writes to globally visible variables across the call.
+ */
+#if defined(_MSC_VER) && (_MSC_VER > 1200)
+void _ReadWriteBarrier(void);
+#pragma intrinsic(_ReadWriteBarrier)
+#define SDL_CompilerBarrier() _ReadWriteBarrier()
+#elif (defined(__GNUC__) && !defined(__EMSCRIPTEN__)) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
+/* This is correct for all CPUs when using GCC or Solaris Studio 12.1+. */
+#define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory")
+#else
+#define SDL_CompilerBarrier() \
+{ SDL_SpinLock _tmp = 0; SDL_AtomicLock(&_tmp); SDL_AtomicUnlock(&_tmp); }
+#endif
+
+/**
+ * Memory barriers are designed to prevent reads and writes from being
+ * reordered by the compiler and being seen out of order on multi-core CPUs.
+ *
+ * A typical pattern would be for thread A to write some data and a flag,
+ * and for thread B to read the flag and get the data. In this case you
+ * would insert a release barrier between writing the data and the flag,
+ * guaranteeing that the data write completes no later than the flag is
+ * written, and you would insert an acquire barrier between reading the
+ * flag and reading the data, to ensure that all the reads associated
+ * with the flag have completed.
+ *
+ * In this pattern you should always see a release barrier paired with
+ * an acquire barrier and you should gate the data reads/writes with a
+ * single flag variable.
+ *
+ * For more information on these semantics, take a look at the blog post:
+ * http://preshing.com/20120913/acquire-and-release-semantics
+ */
+#if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
+#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("lwsync" : : : "memory")
+#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("lwsync" : : : "memory")
+#elif defined(__GNUC__) && defined(__arm__)
+#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
+#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
+#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
+#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
+#ifdef __thumb__
+/* The mcr instruction isn't available in thumb mode, use real functions */
+extern DECLSPEC void SDLCALL SDL_MemoryBarrierRelease();
+extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquire();
+#else
+#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
+#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
+#endif /* __thumb__ */
+#else
+#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("" : : : "memory")
+#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("" : : : "memory")
+#endif /* __GNUC__ && __arm__ */
+#else
+#if (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
+/* This is correct for all CPUs on Solaris when using Solaris Studio 12.1+. */
+#include <mbarrier.h>
+#define SDL_MemoryBarrierRelease() __machine_rel_barrier()
+#define SDL_MemoryBarrierAcquire() __machine_acq_barrier()
+#else
+/* This is correct for the x86 and x64 CPUs, and we'll expand this over time. */
+#define SDL_MemoryBarrierRelease() SDL_CompilerBarrier()
+#define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier()
+#endif
+#endif
+
+/**
+ * \brief A type representing an atomic integer value. It is a struct
+ * so people don't accidentally use numeric operations on it.
+ */
+typedef struct { int value; } SDL_atomic_t;
+
+/**
+ * \brief Set an atomic variable to a new value if it is currently an old value.
+ *
+ * \return SDL_TRUE if the atomic variable was set, SDL_FALSE otherwise.
+ *
+ * \note If you don't know what this function is for, you shouldn't use it!
+*/
+extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);
+
+/**
+ * \brief Set an atomic variable to a value.
+ *
+ * \return The previous value of the atomic variable.
+ */
+extern DECLSPEC int SDLCALL SDL_AtomicSet(SDL_atomic_t *a, int v);
+
+/**
+ * \brief Get the value of an atomic variable
+ */
+extern DECLSPEC int SDLCALL SDL_AtomicGet(SDL_atomic_t *a);
+
+/**
+ * \brief Add to an atomic variable.
+ *
+ * \return The previous value of the atomic variable.
+ *
+ * \note This same style can be used for any number operation
+ */
+extern DECLSPEC int SDLCALL SDL_AtomicAdd(SDL_atomic_t *a, int v);
+
+/**
+ * \brief Increment an atomic variable used as a reference count.
+ */
+#ifndef SDL_AtomicIncRef
+#define SDL_AtomicIncRef(a) SDL_AtomicAdd(a, 1)
+#endif
+
+/**
+ * \brief Decrement an atomic variable used as a reference count.
+ *
+ * \return SDL_TRUE if the variable reached zero after decrementing,
+ * SDL_FALSE otherwise
+ */
+#ifndef SDL_AtomicDecRef
+#define SDL_AtomicDecRef(a) (SDL_AtomicAdd(a, -1) == 1)
+#endif
+
+/**
+ * \brief Set a pointer to a new value if it is currently an old value.
+ *
+ * \return SDL_TRUE if the pointer was set, SDL_FALSE otherwise.
+ *
+ * \note If you don't know what this function is for, you shouldn't use it!
+*/
+extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void **a, void *oldval, void *newval);
+
+/**
+ * \brief Set a pointer to a value atomically.
+ *
+ * \return The previous value of the pointer.
+ */
+extern DECLSPEC void* SDLCALL SDL_AtomicSetPtr(void **a, void* v);
+
+/**
+ * \brief Get the value of a pointer atomically.
+ */
+extern DECLSPEC void* SDLCALL SDL_AtomicGetPtr(void **a);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+
+#include "close_code.h"
+
+#endif /* _SDL_atomic_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_audio.h b/external/SDL2/include/SDL_audio.h
new file mode 100644
index 0000000..4f65521
--- /dev/null
+++ b/external/SDL2/include/SDL_audio.h
@@ -0,0 +1,605 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_audio.h
+ *
+ * Access to the raw audio mixing buffer for the SDL library.
+ */
+
+#ifndef _SDL_audio_h
+#define _SDL_audio_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_endian.h"
+#include "SDL_mutex.h"
+#include "SDL_thread.h"
+#include "SDL_rwops.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Audio format flags.
+ *
+ * These are what the 16 bits in SDL_AudioFormat currently mean...
+ * (Unspecified bits are always zero).
+ *
+ * \verbatim
+ ++-----------------------sample is signed if set
+ ||
+ || ++-----------sample is bigendian if set
+ || ||
+ || || ++---sample is float if set
+ || || ||
+ || || || +---sample bit size---+
+ || || || | |
+ 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
+ \endverbatim
+ *
+ * There are macros in SDL 2.0 and later to query these bits.
+ */
+typedef Uint16 SDL_AudioFormat;
+
+/**
+ * \name Audio flags
+ */
+/* @{ */
+
+#define SDL_AUDIO_MASK_BITSIZE (0xFF)
+#define SDL_AUDIO_MASK_DATATYPE (1<<8)
+#define SDL_AUDIO_MASK_ENDIAN (1<<12)
+#define SDL_AUDIO_MASK_SIGNED (1<<15)
+#define SDL_AUDIO_BITSIZE(x) (x & SDL_AUDIO_MASK_BITSIZE)
+#define SDL_AUDIO_ISFLOAT(x) (x & SDL_AUDIO_MASK_DATATYPE)
+#define SDL_AUDIO_ISBIGENDIAN(x) (x & SDL_AUDIO_MASK_ENDIAN)
+#define SDL_AUDIO_ISSIGNED(x) (x & SDL_AUDIO_MASK_SIGNED)
+#define SDL_AUDIO_ISINT(x) (!SDL_AUDIO_ISFLOAT(x))
+#define SDL_AUDIO_ISLITTLEENDIAN(x) (!SDL_AUDIO_ISBIGENDIAN(x))
+#define SDL_AUDIO_ISUNSIGNED(x) (!SDL_AUDIO_ISSIGNED(x))
+
+/**
+ * \name Audio format flags
+ *
+ * Defaults to LSB byte order.
+ */
+/* @{ */
+#define AUDIO_U8 0x0008 /**< Unsigned 8-bit samples */
+#define AUDIO_S8 0x8008 /**< Signed 8-bit samples */
+#define AUDIO_U16LSB 0x0010 /**< Unsigned 16-bit samples */
+#define AUDIO_S16LSB 0x8010 /**< Signed 16-bit samples */
+#define AUDIO_U16MSB 0x1010 /**< As above, but big-endian byte order */
+#define AUDIO_S16MSB 0x9010 /**< As above, but big-endian byte order */
+#define AUDIO_U16 AUDIO_U16LSB
+#define AUDIO_S16 AUDIO_S16LSB
+/* @} */
+
+/**
+ * \name int32 support
+ */
+/* @{ */
+#define AUDIO_S32LSB 0x8020 /**< 32-bit integer samples */
+#define AUDIO_S32MSB 0x9020 /**< As above, but big-endian byte order */
+#define AUDIO_S32 AUDIO_S32LSB
+/* @} */
+
+/**
+ * \name float32 support
+ */
+/* @{ */
+#define AUDIO_F32LSB 0x8120 /**< 32-bit floating point samples */
+#define AUDIO_F32MSB 0x9120 /**< As above, but big-endian byte order */
+#define AUDIO_F32 AUDIO_F32LSB
+/* @} */
+
+/**
+ * \name Native audio byte ordering
+ */
+/* @{ */
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+#define AUDIO_U16SYS AUDIO_U16LSB
+#define AUDIO_S16SYS AUDIO_S16LSB
+#define AUDIO_S32SYS AUDIO_S32LSB
+#define AUDIO_F32SYS AUDIO_F32LSB
+#else
+#define AUDIO_U16SYS AUDIO_U16MSB
+#define AUDIO_S16SYS AUDIO_S16MSB
+#define AUDIO_S32SYS AUDIO_S32MSB
+#define AUDIO_F32SYS AUDIO_F32MSB
+#endif
+/* @} */
+
+/**
+ * \name Allow change flags
+ *
+ * Which audio format changes are allowed when opening a device.
+ */
+/* @{ */
+#define SDL_AUDIO_ALLOW_FREQUENCY_CHANGE 0x00000001
+#define SDL_AUDIO_ALLOW_FORMAT_CHANGE 0x00000002
+#define SDL_AUDIO_ALLOW_CHANNELS_CHANGE 0x00000004
+#define SDL_AUDIO_ALLOW_ANY_CHANGE (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE)
+/* @} */
+
+/* @} *//* Audio flags */
+
+/**
+ * This function is called when the audio device needs more data.
+ *
+ * \param userdata An application-specific parameter saved in
+ * the SDL_AudioSpec structure
+ * \param stream A pointer to the audio data buffer.
+ * \param len The length of that buffer in bytes.
+ *
+ * Once the callback returns, the buffer will no longer be valid.
+ * Stereo samples are stored in a LRLRLR ordering.
+ *
+ * You can choose to avoid callbacks and use SDL_QueueAudio() instead, if
+ * you like. Just open your audio device with a NULL callback.
+ */
+typedef void (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 * stream,
+ int len);
+
+/**
+ * The calculated values in this structure are calculated by SDL_OpenAudio().
+ */
+typedef struct SDL_AudioSpec
+{
+ int freq; /**< DSP frequency -- samples per second */
+ SDL_AudioFormat format; /**< Audio data format */
+ Uint8 channels; /**< Number of channels: 1 mono, 2 stereo */
+ Uint8 silence; /**< Audio buffer silence value (calculated) */
+ Uint16 samples; /**< Audio buffer size in samples (power of 2) */
+ Uint16 padding; /**< Necessary for some compile environments */
+ Uint32 size; /**< Audio buffer size in bytes (calculated) */
+ SDL_AudioCallback callback; /**< Callback that feeds the audio device (NULL to use SDL_QueueAudio()). */
+ void *userdata; /**< Userdata passed to callback (ignored for NULL callbacks). */
+} SDL_AudioSpec;
+
+
+struct SDL_AudioCVT;
+typedef void (SDLCALL * SDL_AudioFilter) (struct SDL_AudioCVT * cvt,
+ SDL_AudioFormat format);
+
+/**
+ * A structure to hold a set of audio conversion filters and buffers.
+ */
+#ifdef __GNUC__
+/* This structure is 84 bytes on 32-bit architectures, make sure GCC doesn't
+ pad it out to 88 bytes to guarantee ABI compatibility between compilers.
+ vvv
+ The next time we rev the ABI, make sure to size the ints and add padding.
+*/
+#define SDL_AUDIOCVT_PACKED __attribute__((packed))
+#else
+#define SDL_AUDIOCVT_PACKED
+#endif
+/* */
+typedef struct SDL_AudioCVT
+{
+ int needed; /**< Set to 1 if conversion possible */
+ SDL_AudioFormat src_format; /**< Source audio format */
+ SDL_AudioFormat dst_format; /**< Target audio format */
+ double rate_incr; /**< Rate conversion increment */
+ Uint8 *buf; /**< Buffer to hold entire audio data */
+ int len; /**< Length of original audio buffer */
+ int len_cvt; /**< Length of converted audio buffer */
+ int len_mult; /**< buffer must be len*len_mult big */
+ double len_ratio; /**< Given len, final size is len*len_ratio */
+ SDL_AudioFilter filters[10]; /**< Filter list */
+ int filter_index; /**< Current audio conversion function */
+} SDL_AUDIOCVT_PACKED SDL_AudioCVT;
+
+
+/* Function prototypes */
+
+/**
+ * \name Driver discovery functions
+ *
+ * These functions return the list of built in audio drivers, in the
+ * order that they are normally initialized by default.
+ */
+/* @{ */
+extern DECLSPEC int SDLCALL SDL_GetNumAudioDrivers(void);
+extern DECLSPEC const char *SDLCALL SDL_GetAudioDriver(int index);
+/* @} */
+
+/**
+ * \name Initialization and cleanup
+ *
+ * \internal These functions are used internally, and should not be used unless
+ * you have a specific need to specify the audio driver you want to
+ * use. You should normally use SDL_Init() or SDL_InitSubSystem().
+ */
+/* @{ */
+extern DECLSPEC int SDLCALL SDL_AudioInit(const char *driver_name);
+extern DECLSPEC void SDLCALL SDL_AudioQuit(void);
+/* @} */
+
+/**
+ * This function returns the name of the current audio driver, or NULL
+ * if no driver has been initialized.
+ */
+extern DECLSPEC const char *SDLCALL SDL_GetCurrentAudioDriver(void);
+
+/**
+ * This function opens the audio device with the desired parameters, and
+ * returns 0 if successful, placing the actual hardware parameters in the
+ * structure pointed to by \c obtained. If \c obtained is NULL, the audio
+ * data passed to the callback function will be guaranteed to be in the
+ * requested format, and will be automatically converted to the hardware
+ * audio format if necessary. This function returns -1 if it failed
+ * to open the audio device, or couldn't set up the audio thread.
+ *
+ * When filling in the desired audio spec structure,
+ * - \c desired->freq should be the desired audio frequency in samples-per-
+ * second.
+ * - \c desired->format should be the desired audio format.
+ * - \c desired->samples is the desired size of the audio buffer, in
+ * samples. This number should be a power of two, and may be adjusted by
+ * the audio driver to a value more suitable for the hardware. Good values
+ * seem to range between 512 and 8096 inclusive, depending on the
+ * application and CPU speed. Smaller values yield faster response time,
+ * but can lead to underflow if the application is doing heavy processing
+ * and cannot fill the audio buffer in time. A stereo sample consists of
+ * both right and left channels in LR ordering.
+ * Note that the number of samples is directly related to time by the
+ * following formula: \code ms = (samples*1000)/freq \endcode
+ * - \c desired->size is the size in bytes of the audio buffer, and is
+ * calculated by SDL_OpenAudio().
+ * - \c desired->silence is the value used to set the buffer to silence,
+ * and is calculated by SDL_OpenAudio().
+ * - \c desired->callback should be set to a function that will be called
+ * when the audio device is ready for more data. It is passed a pointer
+ * to the audio buffer, and the length in bytes of the audio buffer.
+ * This function usually runs in a separate thread, and so you should
+ * protect data structures that it accesses by calling SDL_LockAudio()
+ * and SDL_UnlockAudio() in your code. Alternately, you may pass a NULL
+ * pointer here, and call SDL_QueueAudio() with some frequency, to queue
+ * more audio samples to be played.
+ * - \c desired->userdata is passed as the first parameter to your callback
+ * function. If you passed a NULL callback, this value is ignored.
+ *
+ * The audio device starts out playing silence when it's opened, and should
+ * be enabled for playing by calling \c SDL_PauseAudio(0) when you are ready
+ * for your audio callback function to be called. Since the audio driver
+ * may modify the requested size of the audio buffer, you should allocate
+ * any local mixing buffers after you open the audio device.
+ */
+extern DECLSPEC int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired,
+ SDL_AudioSpec * obtained);
+
+/**
+ * SDL Audio Device IDs.
+ *
+ * A successful call to SDL_OpenAudio() is always device id 1, and legacy
+ * SDL audio APIs assume you want this device ID. SDL_OpenAudioDevice() calls
+ * always returns devices >= 2 on success. The legacy calls are good both
+ * for backwards compatibility and when you don't care about multiple,
+ * specific, or capture devices.
+ */
+typedef Uint32 SDL_AudioDeviceID;
+
+/**
+ * Get the number of available devices exposed by the current driver.
+ * Only valid after a successfully initializing the audio subsystem.
+ * Returns -1 if an explicit list of devices can't be determined; this is
+ * not an error. For example, if SDL is set up to talk to a remote audio
+ * server, it can't list every one available on the Internet, but it will
+ * still allow a specific host to be specified to SDL_OpenAudioDevice().
+ *
+ * In many common cases, when this function returns a value <= 0, it can still
+ * successfully open the default device (NULL for first argument of
+ * SDL_OpenAudioDevice()).
+ */
+extern DECLSPEC int SDLCALL SDL_GetNumAudioDevices(int iscapture);
+
+/**
+ * Get the human-readable name of a specific audio device.
+ * Must be a value between 0 and (number of audio devices-1).
+ * Only valid after a successfully initializing the audio subsystem.
+ * The values returned by this function reflect the latest call to
+ * SDL_GetNumAudioDevices(); recall that function to redetect available
+ * hardware.
+ *
+ * The string returned by this function is UTF-8 encoded, read-only, and
+ * managed internally. You are not to free it. If you need to keep the
+ * string for any length of time, you should make your own copy of it, as it
+ * will be invalid next time any of several other SDL functions is called.
+ */
+extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index,
+ int iscapture);
+
+
+/**
+ * Open a specific audio device. Passing in a device name of NULL requests
+ * the most reasonable default (and is equivalent to calling SDL_OpenAudio()).
+ *
+ * The device name is a UTF-8 string reported by SDL_GetAudioDeviceName(), but
+ * some drivers allow arbitrary and driver-specific strings, such as a
+ * hostname/IP address for a remote audio server, or a filename in the
+ * diskaudio driver.
+ *
+ * \return 0 on error, a valid device ID that is >= 2 on success.
+ *
+ * SDL_OpenAudio(), unlike this function, always acts on device ID 1.
+ */
+extern DECLSPEC SDL_AudioDeviceID SDLCALL SDL_OpenAudioDevice(const char
+ *device,
+ int iscapture,
+ const
+ SDL_AudioSpec *
+ desired,
+ SDL_AudioSpec *
+ obtained,
+ int
+ allowed_changes);
+
+
+
+/**
+ * \name Audio state
+ *
+ * Get the current audio state.
+ */
+/* @{ */
+typedef enum
+{
+ SDL_AUDIO_STOPPED = 0,
+ SDL_AUDIO_PLAYING,
+ SDL_AUDIO_PAUSED
+} SDL_AudioStatus;
+extern DECLSPEC SDL_AudioStatus SDLCALL SDL_GetAudioStatus(void);
+
+extern DECLSPEC SDL_AudioStatus SDLCALL
+SDL_GetAudioDeviceStatus(SDL_AudioDeviceID dev);
+/* @} *//* Audio State */
+
+/**
+ * \name Pause audio functions
+ *
+ * These functions pause and unpause the audio callback processing.
+ * They should be called with a parameter of 0 after opening the audio
+ * device to start playing sound. This is so you can safely initialize
+ * data for your callback function after opening the audio device.
+ * Silence will be written to the audio device during the pause.
+ */
+/* @{ */
+extern DECLSPEC void SDLCALL SDL_PauseAudio(int pause_on);
+extern DECLSPEC void SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev,
+ int pause_on);
+/* @} *//* Pause audio functions */
+
+/**
+ * This function loads a WAVE from the data source, automatically freeing
+ * that source if \c freesrc is non-zero. For example, to load a WAVE file,
+ * you could do:
+ * \code
+ * SDL_LoadWAV_RW(SDL_RWFromFile("sample.wav", "rb"), 1, ...);
+ * \endcode
+ *
+ * If this function succeeds, it returns the given SDL_AudioSpec,
+ * filled with the audio data format of the wave data, and sets
+ * \c *audio_buf to a malloc()'d buffer containing the audio data,
+ * and sets \c *audio_len to the length of that audio buffer, in bytes.
+ * You need to free the audio buffer with SDL_FreeWAV() when you are
+ * done with it.
+ *
+ * This function returns NULL and sets the SDL error message if the
+ * wave file cannot be opened, uses an unknown data format, or is
+ * corrupt. Currently raw and MS-ADPCM WAVE files are supported.
+ */
+extern DECLSPEC SDL_AudioSpec *SDLCALL SDL_LoadWAV_RW(SDL_RWops * src,
+ int freesrc,
+ SDL_AudioSpec * spec,
+ Uint8 ** audio_buf,
+ Uint32 * audio_len);
+
+/**
+ * Loads a WAV from a file.
+ * Compatibility convenience function.
+ */
+#define SDL_LoadWAV(file, spec, audio_buf, audio_len) \
+ SDL_LoadWAV_RW(SDL_RWFromFile(file, "rb"),1, spec,audio_buf,audio_len)
+
+/**
+ * This function frees data previously allocated with SDL_LoadWAV_RW()
+ */
+extern DECLSPEC void SDLCALL SDL_FreeWAV(Uint8 * audio_buf);
+
+/**
+ * This function takes a source format and rate and a destination format
+ * and rate, and initializes the \c cvt structure with information needed
+ * by SDL_ConvertAudio() to convert a buffer of audio data from one format
+ * to the other.
+ *
+ * \return -1 if the format conversion is not supported, 0 if there's
+ * no conversion needed, or 1 if the audio filter is set up.
+ */
+extern DECLSPEC int SDLCALL SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
+ SDL_AudioFormat src_format,
+ Uint8 src_channels,
+ int src_rate,
+ SDL_AudioFormat dst_format,
+ Uint8 dst_channels,
+ int dst_rate);
+
+/**
+ * Once you have initialized the \c cvt structure using SDL_BuildAudioCVT(),
+ * created an audio buffer \c cvt->buf, and filled it with \c cvt->len bytes of
+ * audio data in the source format, this function will convert it in-place
+ * to the desired format.
+ *
+ * The data conversion may expand the size of the audio data, so the buffer
+ * \c cvt->buf should be allocated after the \c cvt structure is initialized by
+ * SDL_BuildAudioCVT(), and should be \c cvt->len*cvt->len_mult bytes long.
+ */
+extern DECLSPEC int SDLCALL SDL_ConvertAudio(SDL_AudioCVT * cvt);
+
+#define SDL_MIX_MAXVOLUME 128
+/**
+ * This takes two audio buffers of the playing audio format and mixes
+ * them, performing addition, volume adjustment, and overflow clipping.
+ * The volume ranges from 0 - 128, and should be set to ::SDL_MIX_MAXVOLUME
+ * for full audio volume. Note this does not change hardware volume.
+ * This is provided for convenience -- you can mix your own audio data.
+ */
+extern DECLSPEC void SDLCALL SDL_MixAudio(Uint8 * dst, const Uint8 * src,
+ Uint32 len, int volume);
+
+/**
+ * This works like SDL_MixAudio(), but you specify the audio format instead of
+ * using the format of audio device 1. Thus it can be used when no audio
+ * device is open at all.
+ */
+extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst,
+ const Uint8 * src,
+ SDL_AudioFormat format,
+ Uint32 len, int volume);
+
+/**
+ * Queue more audio on non-callback devices.
+ *
+ * SDL offers two ways to feed audio to the device: you can either supply a
+ * callback that SDL triggers with some frequency to obtain more audio
+ * (pull method), or you can supply no callback, and then SDL will expect
+ * you to supply data at regular intervals (push method) with this function.
+ *
+ * There are no limits on the amount of data you can queue, short of
+ * exhaustion of address space. Queued data will drain to the device as
+ * necessary without further intervention from you. If the device needs
+ * audio but there is not enough queued, it will play silence to make up
+ * the difference. This means you will have skips in your audio playback
+ * if you aren't routinely queueing sufficient data.
+ *
+ * This function copies the supplied data, so you are safe to free it when
+ * the function returns. This function is thread-safe, but queueing to the
+ * same device from two threads at once does not promise which buffer will
+ * be queued first.
+ *
+ * You may not queue audio on a device that is using an application-supplied
+ * callback; doing so returns an error. You have to use the audio callback
+ * or queue audio with this function, but not both.
+ *
+ * You should not call SDL_LockAudio() on the device before queueing; SDL
+ * handles locking internally for this function.
+ *
+ * \param dev The device ID to which we will queue audio.
+ * \param data The data to queue to the device for later playback.
+ * \param len The number of bytes (not samples!) to which (data) points.
+ * \return zero on success, -1 on error.
+ *
+ * \sa SDL_GetQueuedAudioSize
+ * \sa SDL_ClearQueuedAudio
+ */
+extern DECLSPEC int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID dev, const void *data, Uint32 len);
+
+/**
+ * Get the number of bytes of still-queued audio.
+ *
+ * This is the number of bytes that have been queued for playback with
+ * SDL_QueueAudio(), but have not yet been sent to the hardware.
+ *
+ * Once we've sent it to the hardware, this function can not decide the exact
+ * byte boundary of what has been played. It's possible that we just gave the
+ * hardware several kilobytes right before you called this function, but it
+ * hasn't played any of it yet, or maybe half of it, etc.
+ *
+ * You may not queue audio on a device that is using an application-supplied
+ * callback; calling this function on such a device always returns 0.
+ * You have to use the audio callback or queue audio with SDL_QueueAudio(),
+ * but not both.
+ *
+ * You should not call SDL_LockAudio() on the device before querying; SDL
+ * handles locking internally for this function.
+ *
+ * \param dev The device ID of which we will query queued audio size.
+ * \return Number of bytes (not samples!) of queued audio.
+ *
+ * \sa SDL_QueueAudio
+ * \sa SDL_ClearQueuedAudio
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev);
+
+/**
+ * Drop any queued audio data waiting to be sent to the hardware.
+ *
+ * Immediately after this call, SDL_GetQueuedAudioSize() will return 0 and
+ * the hardware will start playing silence if more audio isn't queued.
+ *
+ * This will not prevent playback of queued audio that's already been sent
+ * to the hardware, as we can not undo that, so expect there to be some
+ * fraction of a second of audio that might still be heard. This can be
+ * useful if you want to, say, drop any pending music during a level change
+ * in your game.
+ *
+ * You may not queue audio on a device that is using an application-supplied
+ * callback; calling this function on such a device is always a no-op.
+ * You have to use the audio callback or queue audio with SDL_QueueAudio(),
+ * but not both.
+ *
+ * You should not call SDL_LockAudio() on the device before clearing the
+ * queue; SDL handles locking internally for this function.
+ *
+ * This function always succeeds and thus returns void.
+ *
+ * \param dev The device ID of which to clear the audio queue.
+ *
+ * \sa SDL_QueueAudio
+ * \sa SDL_GetQueuedAudioSize
+ */
+extern DECLSPEC void SDLCALL SDL_ClearQueuedAudio(SDL_AudioDeviceID dev);
+
+
+/**
+ * \name Audio lock functions
+ *
+ * The lock manipulated by these functions protects the callback function.
+ * During a SDL_LockAudio()/SDL_UnlockAudio() pair, you can be guaranteed that
+ * the callback function is not running. Do not call these from the callback
+ * function or you will cause deadlock.
+ */
+/* @{ */
+extern DECLSPEC void SDLCALL SDL_LockAudio(void);
+extern DECLSPEC void SDLCALL SDL_LockAudioDevice(SDL_AudioDeviceID dev);
+extern DECLSPEC void SDLCALL SDL_UnlockAudio(void);
+extern DECLSPEC void SDLCALL SDL_UnlockAudioDevice(SDL_AudioDeviceID dev);
+/* @} *//* Audio lock functions */
+
+/**
+ * This function shuts down audio processing and closes the audio device.
+ */
+extern DECLSPEC void SDLCALL SDL_CloseAudio(void);
+extern DECLSPEC void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID dev);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_audio_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_bits.h b/external/SDL2/include/SDL_bits.h
new file mode 100644
index 0000000..528da2e
--- /dev/null
+++ b/external/SDL2/include/SDL_bits.h
@@ -0,0 +1,97 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_bits.h
+ *
+ * Functions for fiddling with bits and bitmasks.
+ */
+
+#ifndef _SDL_bits_h
+#define _SDL_bits_h
+
+#include "SDL_stdinc.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file SDL_bits.h
+ */
+
+/**
+ * Get the index of the most significant bit. Result is undefined when called
+ * with 0. This operation can also be stated as "count leading zeroes" and
+ * "log base 2".
+ *
+ * \return Index of the most significant bit, or -1 if the value is 0.
+ */
+SDL_FORCE_INLINE int
+SDL_MostSignificantBitIndex32(Uint32 x)
+{
+#if defined(__GNUC__) && __GNUC__ >= 4
+ /* Count Leading Zeroes builtin in GCC.
+ * http://gcc.gnu.org/onlinedocs/gcc-4.3.4/gcc/Other-Builtins.html
+ */
+ if (x == 0) {
+ return -1;
+ }
+ return 31 - __builtin_clz(x);
+#else
+ /* Based off of Bit Twiddling Hacks by Sean Eron Anderson
+ * <seander@cs.stanford.edu>, released in the public domain.
+ * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
+ */
+ const Uint32 b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
+ const int S[] = {1, 2, 4, 8, 16};
+
+ int msbIndex = 0;
+ int i;
+
+ if (x == 0) {
+ return -1;
+ }
+
+ for (i = 4; i >= 0; i--)
+ {
+ if (x & b[i])
+ {
+ x >>= S[i];
+ msbIndex |= S[i];
+ }
+ }
+
+ return msbIndex;
+#endif
+}
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_bits_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_blendmode.h b/external/SDL2/include/SDL_blendmode.h
new file mode 100644
index 0000000..56d8ad6
--- /dev/null
+++ b/external/SDL2/include/SDL_blendmode.h
@@ -0,0 +1,63 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_blendmode.h
+ *
+ * Header file declaring the SDL_BlendMode enumeration
+ */
+
+#ifndef _SDL_blendmode_h
+#define _SDL_blendmode_h
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief The blend mode used in SDL_RenderCopy() and drawing operations.
+ */
+typedef enum
+{
+ SDL_BLENDMODE_NONE = 0x00000000, /**< no blending
+ dstRGBA = srcRGBA */
+ SDL_BLENDMODE_BLEND = 0x00000001, /**< alpha blending
+ dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
+ dstA = srcA + (dstA * (1-srcA)) */
+ SDL_BLENDMODE_ADD = 0x00000002, /**< additive blending
+ dstRGB = (srcRGB * srcA) + dstRGB
+ dstA = dstA */
+ SDL_BLENDMODE_MOD = 0x00000004 /**< color modulate
+ dstRGB = srcRGB * dstRGB
+ dstA = dstA */
+} SDL_BlendMode;
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_blendmode_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_clipboard.h b/external/SDL2/include/SDL_clipboard.h
new file mode 100644
index 0000000..a5556f2
--- /dev/null
+++ b/external/SDL2/include/SDL_clipboard.h
@@ -0,0 +1,71 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_clipboard.h
+ *
+ * Include file for SDL clipboard handling
+ */
+
+#ifndef _SDL_clipboard_h
+#define _SDL_clipboard_h
+
+#include "SDL_stdinc.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Function prototypes */
+
+/**
+ * \brief Put UTF-8 text into the clipboard
+ *
+ * \sa SDL_GetClipboardText()
+ */
+extern DECLSPEC int SDLCALL SDL_SetClipboardText(const char *text);
+
+/**
+ * \brief Get UTF-8 text from the clipboard, which must be freed with SDL_free()
+ *
+ * \sa SDL_SetClipboardText()
+ */
+extern DECLSPEC char * SDLCALL SDL_GetClipboardText(void);
+
+/**
+ * \brief Returns a flag indicating whether the clipboard exists and contains a text string that is non-empty
+ *
+ * \sa SDL_GetClipboardText()
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasClipboardText(void);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_clipboard_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_config.h b/external/SDL2/include/SDL_config.h
new file mode 100644
index 0000000..4270c78
--- /dev/null
+++ b/external/SDL2/include/SDL_config.h
@@ -0,0 +1,55 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_h
+#define _SDL_config_h
+
+#include "SDL_platform.h"
+
+/**
+ * \file SDL_config.h
+ */
+
+/* Add any platform that doesn't build using the configure system. */
+#ifdef USING_PREMAKE_CONFIG_H
+#include "SDL_config_premake.h"
+#elif defined(__WIN32__)
+#include "SDL_config_windows.h"
+#elif defined(__WINRT__)
+#include "SDL_config_winrt.h"
+#elif defined(__MACOSX__)
+#include "SDL_config_macosx.h"
+#elif defined(__IPHONEOS__)
+#include "SDL_config_iphoneos.h"
+#elif defined(__ANDROID__)
+#include "SDL_config_android.h"
+#elif defined(__PSP__)
+#include "SDL_config_psp.h"
+#else
+/* This is a minimal configuration just to get SDL running on new platforms */
+#include "SDL_config_minimal.h"
+#endif /* platform config */
+
+#ifdef USING_GENERATED_CONFIG_H
+#error Wrong SDL_config.h, check your include path?
+#endif
+
+#endif /* _SDL_config_h */
diff --git a/external/SDL2/include/SDL_config.h.cmake b/external/SDL2/include/SDL_config.h.cmake
new file mode 100644
index 0000000..44173a0
--- /dev/null
+++ b/external/SDL2/include/SDL_config.h.cmake
@@ -0,0 +1,419 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_h
+#define _SDL_config_h
+
+/**
+ * \file SDL_config.h.in
+ *
+ * This is a set of defines to configure the SDL features
+ */
+
+/* General platform specific identifiers */
+#include "SDL_platform.h"
+
+/* C language features */
+#cmakedefine const @HAVE_CONST@
+#cmakedefine inline @HAVE_INLINE@
+#cmakedefine volatile @HAVE_VOLATILE@
+
+/* C datatypes */
+/* Define SIZEOF_VOIDP for 64/32 architectures */
+#ifdef __LP64__
+#define SIZEOF_VOIDP 8
+#else
+#define SIZEOF_VOIDP 4
+#endif
+
+#cmakedefine HAVE_GCC_ATOMICS @HAVE_GCC_ATOMICS@
+#cmakedefine HAVE_GCC_SYNC_LOCK_TEST_AND_SET @HAVE_GCC_SYNC_LOCK_TEST_AND_SET@
+
+#cmakedefine HAVE_D3D_H @HAVE_D3D_H@
+#cmakedefine HAVE_D3D11_H @HAVE_D3D11_H@
+#cmakedefine HAVE_DDRAW_H @HAVE_DDRAW_H@
+#cmakedefine HAVE_DSOUND_H @HAVE_DSOUND_H@
+#cmakedefine HAVE_DINPUT_H @HAVE_DINPUT_H@
+#cmakedefine HAVE_XAUDIO2_H @HAVE_XAUDIO2_H@
+#cmakedefine HAVE_XINPUT_H @HAVE_XINPUT_H@
+#cmakedefine HAVE_DXGI_H @HAVE_DXGI_H@
+
+/* Comment this if you want to build without any C library requirements */
+#cmakedefine HAVE_LIBC 1
+#if HAVE_LIBC
+
+/* Useful headers */
+#cmakedefine HAVE_ALLOCA_H 1
+#cmakedefine HAVE_SYS_TYPES_H 1
+#cmakedefine HAVE_STDIO_H 1
+#cmakedefine STDC_HEADERS 1
+#cmakedefine HAVE_STDLIB_H 1
+#cmakedefine HAVE_STDARG_H 1
+#cmakedefine HAVE_MALLOC_H 1
+#cmakedefine HAVE_MEMORY_H 1
+#cmakedefine HAVE_STRING_H 1
+#cmakedefine HAVE_STRINGS_H 1
+#cmakedefine HAVE_INTTYPES_H 1
+#cmakedefine HAVE_STDINT_H 1
+#cmakedefine HAVE_CTYPE_H 1
+#cmakedefine HAVE_MATH_H 1
+#cmakedefine HAVE_ICONV_H 1
+#cmakedefine HAVE_SIGNAL_H 1
+#cmakedefine HAVE_ALTIVEC_H 1
+#cmakedefine HAVE_PTHREAD_NP_H 1
+#cmakedefine HAVE_LIBUDEV_H 1
+#cmakedefine HAVE_DBUS_DBUS_H 1
+
+/* C library functions */
+#cmakedefine HAVE_MALLOC 1
+#cmakedefine HAVE_CALLOC 1
+#cmakedefine HAVE_REALLOC 1
+#cmakedefine HAVE_FREE 1
+#cmakedefine HAVE_ALLOCA 1
+#ifndef __WIN32__ /* Don't use C runtime versions of these on Windows */
+#cmakedefine HAVE_GETENV 1
+#cmakedefine HAVE_SETENV 1
+#cmakedefine HAVE_PUTENV 1
+#cmakedefine HAVE_UNSETENV 1
+#endif
+#cmakedefine HAVE_QSORT 1
+#cmakedefine HAVE_ABS 1
+#cmakedefine HAVE_BCOPY 1
+#cmakedefine HAVE_MEMSET 1
+#cmakedefine HAVE_MEMCPY 1
+#cmakedefine HAVE_MEMMOVE 1
+#cmakedefine HAVE_MEMCMP 1
+#cmakedefine HAVE_STRLEN 1
+#cmakedefine HAVE_STRLCPY 1
+#cmakedefine HAVE_STRLCAT 1
+#cmakedefine HAVE_STRDUP 1
+#cmakedefine HAVE__STRREV 1
+#cmakedefine HAVE__STRUPR 1
+#cmakedefine HAVE__STRLWR 1
+#cmakedefine HAVE_INDEX 1
+#cmakedefine HAVE_RINDEX 1
+#cmakedefine HAVE_STRCHR 1
+#cmakedefine HAVE_STRRCHR 1
+#cmakedefine HAVE_STRSTR 1
+#cmakedefine HAVE_ITOA 1
+#cmakedefine HAVE__LTOA 1
+#cmakedefine HAVE__UITOA 1
+#cmakedefine HAVE__ULTOA 1
+#cmakedefine HAVE_STRTOL 1
+#cmakedefine HAVE_STRTOUL 1
+#cmakedefine HAVE__I64TOA 1
+#cmakedefine HAVE__UI64TOA 1
+#cmakedefine HAVE_STRTOLL 1
+#cmakedefine HAVE_STRTOULL 1
+#cmakedefine HAVE_STRTOD 1
+#cmakedefine HAVE_ATOI 1
+#cmakedefine HAVE_ATOF 1
+#cmakedefine HAVE_STRCMP 1
+#cmakedefine HAVE_STRNCMP 1
+#cmakedefine HAVE__STRICMP 1
+#cmakedefine HAVE_STRCASECMP 1
+#cmakedefine HAVE__STRNICMP 1
+#cmakedefine HAVE_STRNCASECMP 1
+#cmakedefine HAVE_VSSCANF 1
+#cmakedefine HAVE_VSNPRINTF 1
+#cmakedefine HAVE_M_PI 1
+#cmakedefine HAVE_ATAN 1
+#cmakedefine HAVE_ATAN2 1
+#cmakedefine HAVE_ACOS 1
+#cmakedefine HAVE_ASIN 1
+#cmakedefine HAVE_CEIL 1
+#cmakedefine HAVE_COPYSIGN 1
+#cmakedefine HAVE_COS 1
+#cmakedefine HAVE_COSF 1
+#cmakedefine HAVE_FABS 1
+#cmakedefine HAVE_FLOOR 1
+#cmakedefine HAVE_LOG 1
+#cmakedefine HAVE_POW 1
+#cmakedefine HAVE_SCALBN 1
+#cmakedefine HAVE_SIN 1
+#cmakedefine HAVE_SINF 1
+#cmakedefine HAVE_SQRT 1
+#cmakedefine HAVE_SQRTF 1
+#cmakedefine HAVE_TAN 1
+#cmakedefine HAVE_TANF 1
+#cmakedefine HAVE_FSEEKO 1
+#cmakedefine HAVE_FSEEKO64 1
+#cmakedefine HAVE_SIGACTION 1
+#cmakedefine HAVE_SA_SIGACTION 1
+#cmakedefine HAVE_SETJMP 1
+#cmakedefine HAVE_NANOSLEEP 1
+#cmakedefine HAVE_SYSCONF 1
+#cmakedefine HAVE_SYSCTLBYNAME 1
+#cmakedefine HAVE_CLOCK_GETTIME 1
+#cmakedefine HAVE_GETPAGESIZE 1
+#cmakedefine HAVE_MPROTECT 1
+#cmakedefine HAVE_ICONV 1
+#cmakedefine HAVE_PTHREAD_SETNAME_NP 1
+#cmakedefine HAVE_PTHREAD_SET_NAME_NP 1
+#cmakedefine HAVE_SEM_TIMEDWAIT 1
+#elif __WIN32__
+#cmakedefine HAVE_STDARG_H 1
+#cmakedefine HAVE_STDDEF_H 1
+#else
+/* We may need some replacement for stdarg.h here */
+#include <stdarg.h>
+#endif /* HAVE_LIBC */
+
+/* SDL internal assertion support */
+#cmakedefine SDL_DEFAULT_ASSERT_LEVEL @SDL_DEFAULT_ASSERT_LEVEL@
+
+/* Allow disabling of core subsystems */
+#cmakedefine SDL_ATOMIC_DISABLED @SDL_ATOMIC_DISABLED@
+#cmakedefine SDL_AUDIO_DISABLED @SDL_AUDIO_DISABLED@
+#cmakedefine SDL_CPUINFO_DISABLED @SDL_CPUINFO_DISABLED@
+#cmakedefine SDL_EVENTS_DISABLED @SDL_EVENTS_DISABLED@
+#cmakedefine SDL_FILE_DISABLED @SDL_FILE_DISABLED@
+#cmakedefine SDL_JOYSTICK_DISABLED @SDL_JOYSTICK_DISABLED@
+#cmakedefine SDL_HAPTIC_DISABLED @SDL_HAPTIC_DISABLED@
+#cmakedefine SDL_LOADSO_DISABLED @SDL_LOADSO_DISABLED@
+#cmakedefine SDL_RENDER_DISABLED @SDL_RENDER_DISABLED@
+#cmakedefine SDL_THREADS_DISABLED @SDL_THREADS_DISABLED@
+#cmakedefine SDL_TIMERS_DISABLED @SDL_TIMERS_DISABLED@
+#cmakedefine SDL_VIDEO_DISABLED @SDL_VIDEO_DISABLED@
+#cmakedefine SDL_POWER_DISABLED @SDL_POWER_DISABLED@
+#cmakedefine SDL_FILESYSTEM_DISABLED @SDL_FILESYSTEM_DISABLED@
+
+/* Enable various audio drivers */
+#cmakedefine SDL_AUDIO_DRIVER_ANDROID @SDL_AUDIO_DRIVER_ANDROID@
+#cmakedefine SDL_AUDIO_DRIVER_ALSA @SDL_AUDIO_DRIVER_ALSA@
+#cmakedefine SDL_AUDIO_DRIVER_ALSA_DYNAMIC @SDL_AUDIO_DRIVER_ALSA_DYNAMIC@
+#cmakedefine SDL_AUDIO_DRIVER_ARTS @SDL_AUDIO_DRIVER_ARTS@
+#cmakedefine SDL_AUDIO_DRIVER_ARTS_DYNAMIC @SDL_AUDIO_DRIVER_ARTS_DYNAMIC@
+#cmakedefine SDL_AUDIO_DRIVER_PULSEAUDIO @SDL_AUDIO_DRIVER_PULSEAUDIO@
+#cmakedefine SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC @SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC@
+#cmakedefine SDL_AUDIO_DRIVER_HAIKU @SDL_AUDIO_DRIVER_HAIKU@
+#cmakedefine SDL_AUDIO_DRIVER_BSD @SDL_AUDIO_DRIVER_BSD@
+#cmakedefine SDL_AUDIO_DRIVER_COREAUDIO @SDL_AUDIO_DRIVER_COREAUDIO@
+#cmakedefine SDL_AUDIO_DRIVER_DISK @SDL_AUDIO_DRIVER_DISK@
+#cmakedefine SDL_AUDIO_DRIVER_DUMMY @SDL_AUDIO_DRIVER_DUMMY@
+#cmakedefine SDL_AUDIO_DRIVER_XAUDIO2 @SDL_AUDIO_DRIVER_XAUDIO2@
+#cmakedefine SDL_AUDIO_DRIVER_DSOUND @SDL_AUDIO_DRIVER_DSOUND@
+#cmakedefine SDL_AUDIO_DRIVER_ESD @SDL_AUDIO_DRIVER_ESD@
+#cmakedefine SDL_AUDIO_DRIVER_ESD_DYNAMIC @SDL_AUDIO_DRIVER_ESD_DYNAMIC@
+#cmakedefine SDL_AUDIO_DRIVER_NAS @SDL_AUDIO_DRIVER_NAS@
+#cmakedefine SDL_AUDIO_DRIVER_NAS_DYNAMIC @SDL_AUDIO_DRIVER_NAS_DYNAMIC@
+#cmakedefine SDL_AUDIO_DRIVER_SNDIO @SDL_AUDIO_DRIVER_SNDIO@
+#cmakedefine SDL_AUDIO_DRIVER_SNDIO_DYNAMIC @SDL_AUDIO_DRIVER_SNDIO_DYNAMIC@
+#cmakedefine SDL_AUDIO_DRIVER_OSS @SDL_AUDIO_DRIVER_OSS@
+#cmakedefine SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H @SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H@
+#cmakedefine SDL_AUDIO_DRIVER_PAUDIO @SDL_AUDIO_DRIVER_PAUDIO@
+#cmakedefine SDL_AUDIO_DRIVER_QSA @SDL_AUDIO_DRIVER_QSA@
+#cmakedefine SDL_AUDIO_DRIVER_SUNAUDIO @SDL_AUDIO_DRIVER_SUNAUDIO@
+#cmakedefine SDL_AUDIO_DRIVER_WINMM @SDL_AUDIO_DRIVER_WINMM@
+#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND @SDL_AUDIO_DRIVER_FUSIONSOUND@
+#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC @SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC@
+#cmakedefine SDL_AUDIO_DRIVER_EMSCRIPTEN @SDL_AUDIO_DRIVER_EMSCRIPTEN@
+
+/* Enable various input drivers */
+#cmakedefine SDL_INPUT_LINUXEV @SDL_INPUT_LINUXEV@
+#cmakedefine SDL_INPUT_LINUXKD @SDL_INPUT_LINUXKD@
+#cmakedefine SDL_INPUT_TSLIB @SDL_INPUT_TSLIB@
+#cmakedefine SDL_JOYSTICK_ANDROID @SDL_JOYSTICK_ANDROID@
+#cmakedefine SDL_JOYSTICK_HAIKU @SDL_JOYSTICK_HAIKU@
+#cmakedefine SDL_JOYSTICK_DINPUT @SDL_JOYSTICK_DINPUT@
+#cmakedefine SDL_JOYSTICK_XINPUT @SDL_JOYSTICK_XINPUT@
+#cmakedefine SDL_JOYSTICK_DUMMY @SDL_JOYSTICK_DUMMY@
+#cmakedefine SDL_JOYSTICK_IOKIT @SDL_JOYSTICK_IOKIT@
+#cmakedefine SDL_JOYSTICK_MFI @SDL_JOYSTICK_MFI@
+#cmakedefine SDL_JOYSTICK_LINUX @SDL_JOYSTICK_LINUX@
+#cmakedefine SDL_JOYSTICK_WINMM @SDL_JOYSTICK_WINMM@
+#cmakedefine SDL_JOYSTICK_USBHID @SDL_JOYSTICK_USBHID@
+#cmakedefine SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H @SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H@
+#cmakedefine SDL_JOYSTICK_EMSCRIPTEN @SDL_JOYSTICK_EMSCRIPTEN@
+#cmakedefine SDL_HAPTIC_DUMMY @SDL_HAPTIC_DUMMY@
+#cmakedefine SDL_HAPTIC_LINUX @SDL_HAPTIC_LINUX@
+#cmakedefine SDL_HAPTIC_IOKIT @SDL_HAPTIC_IOKIT@
+#cmakedefine SDL_HAPTIC_DINPUT @SDL_HAPTIC_DINPUT@
+#cmakedefine SDL_HAPTIC_XINPUT @SDL_HAPTIC_XINPUT@
+
+/* Enable various shared object loading systems */
+#cmakedefine SDL_LOADSO_HAIKU @SDL_LOADSO_HAIKU@
+#cmakedefine SDL_LOADSO_DLOPEN @SDL_LOADSO_DLOPEN@
+#cmakedefine SDL_LOADSO_DUMMY @SDL_LOADSO_DUMMY@
+#cmakedefine SDL_LOADSO_LDG @SDL_LOADSO_LDG@
+#cmakedefine SDL_LOADSO_WINDOWS @SDL_LOADSO_WINDOWS@
+
+/* Enable various threading systems */
+#cmakedefine SDL_THREAD_PTHREAD @SDL_THREAD_PTHREAD@
+#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX@
+#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP@
+#cmakedefine SDL_THREAD_WINDOWS @SDL_THREAD_WINDOWS@
+
+/* Enable various timer systems */
+#cmakedefine SDL_TIMER_HAIKU @SDL_TIMER_HAIKU@
+#cmakedefine SDL_TIMER_DUMMY @SDL_TIMER_DUMMY@
+#cmakedefine SDL_TIMER_UNIX @SDL_TIMER_UNIX@
+#cmakedefine SDL_TIMER_WINDOWS @SDL_TIMER_WINDOWS@
+#cmakedefine SDL_TIMER_WINCE @SDL_TIMER_WINCE@
+
+/* Enable various video drivers */
+#cmakedefine SDL_VIDEO_DRIVER_ANDROID @SDL_VIDEO_DRIVER_ANDROID@
+#cmakedefine SDL_VIDEO_DRIVER_HAIKU @SDL_VIDEO_DRIVER_HAIKU@
+#cmakedefine SDL_VIDEO_DRIVER_COCOA @SDL_VIDEO_DRIVER_COCOA@
+#cmakedefine SDL_VIDEO_DRIVER_DIRECTFB @SDL_VIDEO_DRIVER_DIRECTFB@
+#cmakedefine SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC @SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC@
+#cmakedefine SDL_VIDEO_DRIVER_DUMMY @SDL_VIDEO_DRIVER_DUMMY@
+#cmakedefine SDL_VIDEO_DRIVER_WINDOWS @SDL_VIDEO_DRIVER_WINDOWS@
+#cmakedefine SDL_VIDEO_DRIVER_WAYLAND @SDL_VIDEO_DRIVER_WAYLAND@
+#cmakedefine SDL_VIDEO_DRIVER_RPI @SDL_VIDEO_DRIVER_RPI@
+#cmakedefine SDL_VIDEO_DRIVER_VIVANTE @SDL_VIDEO_DRIVER_VIVANTE@
+#cmakedefine SDL_VIDEO_DRIVER_VIVANTE_VDK @SDL_VIDEO_DRIVER_VIVANTE_VDK@
+
+#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH @SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH@
+#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC@
+#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL@
+#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR@
+#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON@
+
+#cmakedefine SDL_VIDEO_DRIVER_MIR @SDL_VIDEO_DRIVER_MIR@
+#cmakedefine SDL_VIDEO_DRIVER_MIR_DYNAMIC @SDL_VIDEO_DRIVER_MIR_DYNAMIC@
+#cmakedefine SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON @SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON@
+#cmakedefine SDL_VIDEO_DRIVER_EMSCRIPTEN @SDL_VIDEO_DRIVER_EMSCRIPTEN@
+#cmakedefine SDL_VIDEO_DRIVER_X11 @SDL_VIDEO_DRIVER_X11@
+#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC @SDL_VIDEO_DRIVER_X11_DYNAMIC@
+#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT @SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT@
+#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR@
+#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA @SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA@
+#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 @SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2@
+#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR@
+#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS @SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS@
+#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE @SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE@
+#cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR @SDL_VIDEO_DRIVER_X11_XCURSOR@
+#cmakedefine SDL_VIDEO_DRIVER_X11_XDBE @SDL_VIDEO_DRIVER_X11_XDBE@
+#cmakedefine SDL_VIDEO_DRIVER_X11_XINERAMA @SDL_VIDEO_DRIVER_X11_XINERAMA@
+#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2 @SDL_VIDEO_DRIVER_X11_XINPUT2@
+#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH @SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH@
+#cmakedefine SDL_VIDEO_DRIVER_X11_XRANDR @SDL_VIDEO_DRIVER_X11_XRANDR@
+#cmakedefine SDL_VIDEO_DRIVER_X11_XSCRNSAVER @SDL_VIDEO_DRIVER_X11_XSCRNSAVER@
+#cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE @SDL_VIDEO_DRIVER_X11_XSHAPE@
+#cmakedefine SDL_VIDEO_DRIVER_X11_XVIDMODE @SDL_VIDEO_DRIVER_X11_XVIDMODE@
+#cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS @SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS@
+#cmakedefine SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY @SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY@
+#cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM @SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM@
+
+#cmakedefine SDL_VIDEO_RENDER_D3D @SDL_VIDEO_RENDER_D3D@
+#cmakedefine SDL_VIDEO_RENDER_D3D11 @SDL_VIDEO_RENDER_D3D11@
+#cmakedefine SDL_VIDEO_RENDER_OGL @SDL_VIDEO_RENDER_OGL@
+#cmakedefine SDL_VIDEO_RENDER_OGL_ES @SDL_VIDEO_RENDER_OGL_ES@
+#cmakedefine SDL_VIDEO_RENDER_OGL_ES2 @SDL_VIDEO_RENDER_OGL_ES2@
+#cmakedefine SDL_VIDEO_RENDER_DIRECTFB @SDL_VIDEO_RENDER_DIRECTFB@
+
+/* Enable OpenGL support */
+#cmakedefine SDL_VIDEO_OPENGL @SDL_VIDEO_OPENGL@
+#cmakedefine SDL_VIDEO_OPENGL_ES @SDL_VIDEO_OPENGL_ES@
+#cmakedefine SDL_VIDEO_OPENGL_ES2 @SDL_VIDEO_OPENGL_ES2@
+#cmakedefine SDL_VIDEO_OPENGL_BGL @SDL_VIDEO_OPENGL_BGL@
+#cmakedefine SDL_VIDEO_OPENGL_CGL @SDL_VIDEO_OPENGL_CGL@
+#cmakedefine SDL_VIDEO_OPENGL_GLX @SDL_VIDEO_OPENGL_GLX@
+#cmakedefine SDL_VIDEO_OPENGL_WGL @SDL_VIDEO_OPENGL_WGL@
+#cmakedefine SDL_VIDEO_OPENGL_EGL @SDL_VIDEO_OPENGL_EGL@
+#cmakedefine SDL_VIDEO_OPENGL_OSMESA @SDL_VIDEO_OPENGL_OSMESA@
+#cmakedefine SDL_VIDEO_OPENGL_OSMESA_DYNAMIC @SDL_VIDEO_OPENGL_OSMESA_DYNAMIC@
+
+/* Enable system power support */
+#cmakedefine SDL_POWER_ANDROID @SDL_POWER_ANDROID@
+#cmakedefine SDL_POWER_LINUX @SDL_POWER_LINUX@
+#cmakedefine SDL_POWER_WINDOWS @SDL_POWER_WINDOWS@
+#cmakedefine SDL_POWER_MACOSX @SDL_POWER_MACOSX@
+#cmakedefine SDL_POWER_HAIKU @SDL_POWER_HAIKU@
+#cmakedefine SDL_POWER_EMSCRIPTEN @SDL_POWER_EMSCRIPTEN@
+#cmakedefine SDL_POWER_HARDWIRED @SDL_POWER_HARDWIRED@
+
+/* Enable system filesystem support */
+#cmakedefine SDL_FILESYSTEM_ANDROID @SDL_FILESYSTEM_ANDROID@
+#cmakedefine SDL_FILESYSTEM_HAIKU @SDL_FILESYSTEM_HAIKU@
+#cmakedefine SDL_FILESYSTEM_COCOA @SDL_FILESYSTEM_COCOA@
+#cmakedefine SDL_FILESYSTEM_DUMMY @SDL_FILESYSTEM_DUMMY@
+#cmakedefine SDL_FILESYSTEM_UNIX @SDL_FILESYSTEM_UNIX@
+#cmakedefine SDL_FILESYSTEM_WINDOWS @SDL_FILESYSTEM_WINDOWS@
+#cmakedefine SDL_FILESYSTEM_EMSCRIPTEN @SDL_FILESYSTEM_EMSCRIPTEN@
+
+/* Enable assembly routines */
+#cmakedefine SDL_ASSEMBLY_ROUTINES @SDL_ASSEMBLY_ROUTINES@
+#cmakedefine SDL_ALTIVEC_BLITTERS @SDL_ALTIVEC_BLITTERS@
+
+
+/* Platform specific definitions */
+#if !defined(__WIN32__)
+# if !defined(_STDINT_H_) && !defined(_STDINT_H) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H)
+typedef unsigned int size_t;
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef signed long long int64_t;
+typedef unsigned long long uint64_t;
+typedef unsigned long uintptr_t;
+# endif /* if (stdint.h isn't available) */
+#else /* __WIN32__ */
+# if !defined(_STDINT_H_) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H)
+# if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
+#define HAVE_STDINT_H 1
+# elif defined(_MSC_VER)
+typedef signed __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef signed __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef signed __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+# ifndef _UINTPTR_T_DEFINED
+# ifdef _WIN64
+typedef unsigned __int64 uintptr_t;
+# else
+typedef unsigned int uintptr_t;
+# endif
+#define _UINTPTR_T_DEFINED
+# endif
+/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
+# if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
+#define DWORD_PTR DWORD
+# endif
+# if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
+#define LONG_PTR LONG
+# endif
+# else /* !__GNUC__ && !_MSC_VER */
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef signed long long int64_t;
+typedef unsigned long long uint64_t;
+# ifndef _SIZE_T_DEFINED_
+#define _SIZE_T_DEFINED_
+typedef unsigned int size_t;
+# endif
+typedef unsigned int uintptr_t;
+# endif /* __GNUC__ || _MSC_VER */
+# endif /* !_STDINT_H_ && !HAVE_STDINT_H */
+#endif /* __WIN32__ */
+
+#endif /* _SDL_config_h */
diff --git a/external/SDL2/include/SDL_config.h.in b/external/SDL2/include/SDL_config.h.in
new file mode 100644
index 0000000..2071be4
--- /dev/null
+++ b/external/SDL2/include/SDL_config.h.in
@@ -0,0 +1,359 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_h
+#define _SDL_config_h
+
+/**
+ * \file SDL_config.h.in
+ *
+ * This is a set of defines to configure the SDL features
+ */
+
+/* General platform specific identifiers */
+#include "SDL_platform.h"
+
+/* Make sure that this isn't included by Visual C++ */
+#ifdef _MSC_VER
+#error You should run hg revert SDL_config.h
+#endif
+
+/* C language features */
+#undef const
+#undef inline
+#undef volatile
+
+/* C datatypes */
+#ifdef __LP64__
+#define SIZEOF_VOIDP 8
+#else
+#define SIZEOF_VOIDP 4
+#endif
+#undef HAVE_GCC_ATOMICS
+#undef HAVE_GCC_SYNC_LOCK_TEST_AND_SET
+
+#undef HAVE_DDRAW_H
+#undef HAVE_DINPUT_H
+#undef HAVE_DSOUND_H
+#undef HAVE_DXGI_H
+#undef HAVE_XINPUT_H
+
+/* Comment this if you want to build without any C library requirements */
+#undef HAVE_LIBC
+#if HAVE_LIBC
+
+/* Useful headers */
+#undef HAVE_ALLOCA_H
+#undef HAVE_SYS_TYPES_H
+#undef HAVE_STDIO_H
+#undef STDC_HEADERS
+#undef HAVE_STDLIB_H
+#undef HAVE_STDARG_H
+#undef HAVE_MALLOC_H
+#undef HAVE_MEMORY_H
+#undef HAVE_STRING_H
+#undef HAVE_STRINGS_H
+#undef HAVE_INTTYPES_H
+#undef HAVE_STDINT_H
+#undef HAVE_CTYPE_H
+#undef HAVE_MATH_H
+#undef HAVE_ICONV_H
+#undef HAVE_SIGNAL_H
+#undef HAVE_ALTIVEC_H
+#undef HAVE_PTHREAD_NP_H
+#undef HAVE_LIBUDEV_H
+#undef HAVE_DBUS_DBUS_H
+#undef HAVE_IBUS_IBUS_H
+
+/* C library functions */
+#undef HAVE_MALLOC
+#undef HAVE_CALLOC
+#undef HAVE_REALLOC
+#undef HAVE_FREE
+#undef HAVE_ALLOCA
+#ifndef __WIN32__ /* Don't use C runtime versions of these on Windows */
+#undef HAVE_GETENV
+#undef HAVE_SETENV
+#undef HAVE_PUTENV
+#undef HAVE_UNSETENV
+#endif
+#undef HAVE_QSORT
+#undef HAVE_ABS
+#undef HAVE_BCOPY
+#undef HAVE_MEMSET
+#undef HAVE_MEMCPY
+#undef HAVE_MEMMOVE
+#undef HAVE_MEMCMP
+#undef HAVE_STRLEN
+#undef HAVE_STRLCPY
+#undef HAVE_STRLCAT
+#undef HAVE_STRDUP
+#undef HAVE__STRREV
+#undef HAVE__STRUPR
+#undef HAVE__STRLWR
+#undef HAVE_INDEX
+#undef HAVE_RINDEX
+#undef HAVE_STRCHR
+#undef HAVE_STRRCHR
+#undef HAVE_STRSTR
+#undef HAVE_ITOA
+#undef HAVE__LTOA
+#undef HAVE__UITOA
+#undef HAVE__ULTOA
+#undef HAVE_STRTOL
+#undef HAVE_STRTOUL
+#undef HAVE__I64TOA
+#undef HAVE__UI64TOA
+#undef HAVE_STRTOLL
+#undef HAVE_STRTOULL
+#undef HAVE_STRTOD
+#undef HAVE_ATOI
+#undef HAVE_ATOF
+#undef HAVE_STRCMP
+#undef HAVE_STRNCMP
+#undef HAVE__STRICMP
+#undef HAVE_STRCASECMP
+#undef HAVE__STRNICMP
+#undef HAVE_STRNCASECMP
+#undef HAVE_SSCANF
+#undef HAVE_VSSCANF
+#undef HAVE_SNPRINTF
+#undef HAVE_VSNPRINTF
+#undef HAVE_M_PI
+#undef HAVE_ATAN
+#undef HAVE_ATAN2
+#undef HAVE_ACOS
+#undef HAVE_ASIN
+#undef HAVE_CEIL
+#undef HAVE_COPYSIGN
+#undef HAVE_COS
+#undef HAVE_COSF
+#undef HAVE_FABS
+#undef HAVE_FLOOR
+#undef HAVE_LOG
+#undef HAVE_POW
+#undef HAVE_SCALBN
+#undef HAVE_SIN
+#undef HAVE_SINF
+#undef HAVE_SQRT
+#undef HAVE_SQRTF
+#undef HAVE_TAN
+#undef HAVE_TANF
+#undef HAVE_FSEEKO
+#undef HAVE_FSEEKO64
+#undef HAVE_SIGACTION
+#undef HAVE_SA_SIGACTION
+#undef HAVE_SETJMP
+#undef HAVE_NANOSLEEP
+#undef HAVE_SYSCONF
+#undef HAVE_SYSCTLBYNAME
+#undef HAVE_CLOCK_GETTIME
+#undef HAVE_GETPAGESIZE
+#undef HAVE_MPROTECT
+#undef HAVE_ICONV
+#undef HAVE_PTHREAD_SETNAME_NP
+#undef HAVE_PTHREAD_SET_NAME_NP
+#undef HAVE_SEM_TIMEDWAIT
+
+#else
+#define HAVE_STDARG_H 1
+#define HAVE_STDDEF_H 1
+#define HAVE_STDINT_H 1
+#endif /* HAVE_LIBC */
+
+/* SDL internal assertion support */
+#undef SDL_DEFAULT_ASSERT_LEVEL
+
+/* Allow disabling of core subsystems */
+#undef SDL_ATOMIC_DISABLED
+#undef SDL_AUDIO_DISABLED
+#undef SDL_CPUINFO_DISABLED
+#undef SDL_EVENTS_DISABLED
+#undef SDL_FILE_DISABLED
+#undef SDL_JOYSTICK_DISABLED
+#undef SDL_HAPTIC_DISABLED
+#undef SDL_LOADSO_DISABLED
+#undef SDL_RENDER_DISABLED
+#undef SDL_THREADS_DISABLED
+#undef SDL_TIMERS_DISABLED
+#undef SDL_VIDEO_DISABLED
+#undef SDL_POWER_DISABLED
+#undef SDL_FILESYSTEM_DISABLED
+
+/* Enable various audio drivers */
+#undef SDL_AUDIO_DRIVER_ALSA
+#undef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
+#undef SDL_AUDIO_DRIVER_ARTS
+#undef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
+#undef SDL_AUDIO_DRIVER_PULSEAUDIO
+#undef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
+#undef SDL_AUDIO_DRIVER_HAIKU
+#undef SDL_AUDIO_DRIVER_BSD
+#undef SDL_AUDIO_DRIVER_COREAUDIO
+#undef SDL_AUDIO_DRIVER_DISK
+#undef SDL_AUDIO_DRIVER_DUMMY
+#undef SDL_AUDIO_DRIVER_ANDROID
+#undef SDL_AUDIO_DRIVER_XAUDIO2
+#undef SDL_AUDIO_DRIVER_DSOUND
+#undef SDL_AUDIO_DRIVER_ESD
+#undef SDL_AUDIO_DRIVER_ESD_DYNAMIC
+#undef SDL_AUDIO_DRIVER_NACL
+#undef SDL_AUDIO_DRIVER_NAS
+#undef SDL_AUDIO_DRIVER_NAS_DYNAMIC
+#undef SDL_AUDIO_DRIVER_SNDIO
+#undef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
+#undef SDL_AUDIO_DRIVER_OSS
+#undef SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
+#undef SDL_AUDIO_DRIVER_PAUDIO
+#undef SDL_AUDIO_DRIVER_QSA
+#undef SDL_AUDIO_DRIVER_SUNAUDIO
+#undef SDL_AUDIO_DRIVER_WINMM
+#undef SDL_AUDIO_DRIVER_FUSIONSOUND
+#undef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
+#undef SDL_AUDIO_DRIVER_EMSCRIPTEN
+
+/* Enable various input drivers */
+#undef SDL_INPUT_LINUXEV
+#undef SDL_INPUT_LINUXKD
+#undef SDL_INPUT_TSLIB
+#undef SDL_JOYSTICK_HAIKU
+#undef SDL_JOYSTICK_DINPUT
+#undef SDL_JOYSTICK_XINPUT
+#undef SDL_JOYSTICK_DUMMY
+#undef SDL_JOYSTICK_IOKIT
+#undef SDL_JOYSTICK_LINUX
+#undef SDL_JOYSTICK_ANDROID
+#undef SDL_JOYSTICK_WINMM
+#undef SDL_JOYSTICK_USBHID
+#undef SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
+#undef SDL_JOYSTICK_EMSCRIPTEN
+#undef SDL_HAPTIC_DUMMY
+#undef SDL_HAPTIC_LINUX
+#undef SDL_HAPTIC_IOKIT
+#undef SDL_HAPTIC_DINPUT
+#undef SDL_HAPTIC_XINPUT
+
+/* Enable various shared object loading systems */
+#undef SDL_LOADSO_HAIKU
+#undef SDL_LOADSO_DLOPEN
+#undef SDL_LOADSO_DUMMY
+#undef SDL_LOADSO_LDG
+#undef SDL_LOADSO_WINDOWS
+
+/* Enable various threading systems */
+#undef SDL_THREAD_PTHREAD
+#undef SDL_THREAD_PTHREAD_RECURSIVE_MUTEX
+#undef SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP
+#undef SDL_THREAD_WINDOWS
+
+/* Enable various timer systems */
+#undef SDL_TIMER_HAIKU
+#undef SDL_TIMER_DUMMY
+#undef SDL_TIMER_UNIX
+#undef SDL_TIMER_WINDOWS
+
+/* Enable various video drivers */
+#undef SDL_VIDEO_DRIVER_HAIKU
+#undef SDL_VIDEO_DRIVER_COCOA
+#undef SDL_VIDEO_DRIVER_DIRECTFB
+#undef SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC
+#undef SDL_VIDEO_DRIVER_DUMMY
+#undef SDL_VIDEO_DRIVER_WINDOWS
+#undef SDL_VIDEO_DRIVER_WAYLAND
+#undef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
+#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
+#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
+#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
+#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
+#undef SDL_VIDEO_DRIVER_MIR
+#undef SDL_VIDEO_DRIVER_MIR_DYNAMIC
+#undef SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON
+#undef SDL_VIDEO_DRIVER_X11
+#undef SDL_VIDEO_DRIVER_RPI
+#undef SDL_VIDEO_DRIVER_ANDROID
+#undef SDL_VIDEO_DRIVER_EMSCRIPTEN
+#undef SDL_VIDEO_DRIVER_X11_DYNAMIC
+#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT
+#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR
+#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA
+#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2
+#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR
+#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS
+#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE
+#undef SDL_VIDEO_DRIVER_X11_XCURSOR
+#undef SDL_VIDEO_DRIVER_X11_XDBE
+#undef SDL_VIDEO_DRIVER_X11_XINERAMA
+#undef SDL_VIDEO_DRIVER_X11_XINPUT2
+#undef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
+#undef SDL_VIDEO_DRIVER_X11_XRANDR
+#undef SDL_VIDEO_DRIVER_X11_XSCRNSAVER
+#undef SDL_VIDEO_DRIVER_X11_XSHAPE
+#undef SDL_VIDEO_DRIVER_X11_XVIDMODE
+#undef SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
+#undef SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY
+#undef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
+#undef SDL_VIDEO_DRIVER_NACL
+#undef SDL_VIDEO_DRIVER_VIVANTE
+#undef SDL_VIDEO_DRIVER_VIVANTE_VDK
+
+#undef SDL_VIDEO_RENDER_D3D
+#undef SDL_VIDEO_RENDER_D3D11
+#undef SDL_VIDEO_RENDER_OGL
+#undef SDL_VIDEO_RENDER_OGL_ES
+#undef SDL_VIDEO_RENDER_OGL_ES2
+#undef SDL_VIDEO_RENDER_DIRECTFB
+
+/* Enable OpenGL support */
+#undef SDL_VIDEO_OPENGL
+#undef SDL_VIDEO_OPENGL_ES
+#undef SDL_VIDEO_OPENGL_ES2
+#undef SDL_VIDEO_OPENGL_BGL
+#undef SDL_VIDEO_OPENGL_CGL
+#undef SDL_VIDEO_OPENGL_EGL
+#undef SDL_VIDEO_OPENGL_GLX
+#undef SDL_VIDEO_OPENGL_WGL
+#undef SDL_VIDEO_OPENGL_OSMESA
+#undef SDL_VIDEO_OPENGL_OSMESA_DYNAMIC
+
+/* Enable system power support */
+#undef SDL_POWER_LINUX
+#undef SDL_POWER_WINDOWS
+#undef SDL_POWER_MACOSX
+#undef SDL_POWER_HAIKU
+#undef SDL_POWER_ANDROID
+#undef SDL_POWER_EMSCRIPTEN
+#undef SDL_POWER_HARDWIRED
+
+/* Enable system filesystem support */
+#undef SDL_FILESYSTEM_HAIKU
+#undef SDL_FILESYSTEM_COCOA
+#undef SDL_FILESYSTEM_DUMMY
+#undef SDL_FILESYSTEM_UNIX
+#undef SDL_FILESYSTEM_WINDOWS
+#undef SDL_FILESYSTEM_NACL
+#undef SDL_FILESYSTEM_ANDROID
+#undef SDL_FILESYSTEM_EMSCRIPTEN
+
+/* Enable assembly routines */
+#undef SDL_ASSEMBLY_ROUTINES
+#undef SDL_ALTIVEC_BLITTERS
+
+#endif /* _SDL_config_h */
diff --git a/external/SDL2/include/SDL_config_android.h b/external/SDL2/include/SDL_config_android.h
new file mode 100644
index 0000000..a388ba8
--- /dev/null
+++ b/external/SDL2/include/SDL_config_android.h
@@ -0,0 +1,145 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_android_h
+#define _SDL_config_android_h
+
+#include "SDL_platform.h"
+
+/**
+ * \file SDL_config_android.h
+ *
+ * This is a configuration that can be used to build SDL for Android
+ */
+
+#include <stdarg.h>
+
+#define HAVE_GCC_ATOMICS 1
+
+#define HAVE_ALLOCA_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_STDIO_H 1
+#define STDC_HEADERS 1
+#define HAVE_STRING_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_CTYPE_H 1
+#define HAVE_MATH_H 1
+
+/* C library functions */
+#define HAVE_MALLOC 1
+#define HAVE_CALLOC 1
+#define HAVE_REALLOC 1
+#define HAVE_FREE 1
+#define HAVE_ALLOCA 1
+#define HAVE_GETENV 1
+#define HAVE_SETENV 1
+#define HAVE_PUTENV 1
+#define HAVE_SETENV 1
+#define HAVE_UNSETENV 1
+#define HAVE_QSORT 1
+#define HAVE_ABS 1
+#define HAVE_BCOPY 1
+#define HAVE_MEMSET 1
+#define HAVE_MEMCPY 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMCMP 1
+#define HAVE_STRLEN 1
+#define HAVE_STRLCPY 1
+#define HAVE_STRLCAT 1
+#define HAVE_STRDUP 1
+#define HAVE_STRCHR 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRSTR 1
+#define HAVE_STRTOL 1
+#define HAVE_STRTOUL 1
+#define HAVE_STRTOLL 1
+#define HAVE_STRTOULL 1
+#define HAVE_STRTOD 1
+#define HAVE_ATOI 1
+#define HAVE_STRCMP 1
+#define HAVE_STRNCMP 1
+#define HAVE_STRCASECMP 1
+#define HAVE_STRNCASECMP 1
+#define HAVE_VSSCANF 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_M_PI 1
+#define HAVE_ATAN 1
+#define HAVE_ATAN2 1
+#define HAVE_ACOS 1
+#define HAVE_ASIN 1
+#define HAVE_CEIL 1
+#define HAVE_COPYSIGN 1
+#define HAVE_COS 1
+#define HAVE_COSF 1
+#define HAVE_FABS 1
+#define HAVE_FLOOR 1
+#define HAVE_LOG 1
+#define HAVE_POW 1
+#define HAVE_SCALBN 1
+#define HAVE_SIN 1
+#define HAVE_SINF 1
+#define HAVE_SQRT 1
+#define HAVE_SQRTF 1
+#define HAVE_TAN 1
+#define HAVE_TANF 1
+#define HAVE_SETJMP 1
+#define HAVE_NANOSLEEP 1
+#define HAVE_SYSCONF 1
+#define HAVE_CLOCK_GETTIME 1
+
+#define SIZEOF_VOIDP 4
+
+/* Enable various audio drivers */
+#define SDL_AUDIO_DRIVER_ANDROID 1
+#define SDL_AUDIO_DRIVER_DUMMY 1
+
+/* Enable various input drivers */
+#define SDL_JOYSTICK_ANDROID 1
+#define SDL_HAPTIC_DUMMY 1
+
+/* Enable various shared object loading systems */
+#define SDL_LOADSO_DLOPEN 1
+
+/* Enable various threading systems */
+#define SDL_THREAD_PTHREAD 1
+#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1
+
+/* Enable various timer systems */
+#define SDL_TIMER_UNIX 1
+
+/* Enable various video drivers */
+#define SDL_VIDEO_DRIVER_ANDROID 1
+
+/* Enable OpenGL ES */
+#define SDL_VIDEO_OPENGL_ES 1
+#define SDL_VIDEO_OPENGL_ES2 1
+#define SDL_VIDEO_OPENGL_EGL 1
+#define SDL_VIDEO_RENDER_OGL_ES 1
+#define SDL_VIDEO_RENDER_OGL_ES2 1
+
+/* Enable system power support */
+#define SDL_POWER_ANDROID 1
+
+/* Enable the filesystem driver */
+#define SDL_FILESYSTEM_ANDROID 1
+
+#endif /* _SDL_config_android_h */
diff --git a/external/SDL2/include/SDL_config_iphoneos.h b/external/SDL2/include/SDL_config_iphoneos.h
new file mode 100644
index 0000000..304c892
--- /dev/null
+++ b/external/SDL2/include/SDL_config_iphoneos.h
@@ -0,0 +1,162 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_iphoneos_h
+#define _SDL_config_iphoneos_h
+
+#include "SDL_platform.h"
+
+#ifdef __LP64__
+#define SIZEOF_VOIDP 8
+#else
+#define SIZEOF_VOIDP 4
+#endif
+
+#define HAVE_GCC_ATOMICS 1
+
+#define HAVE_ALLOCA_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_STDIO_H 1
+#define STDC_HEADERS 1
+#define HAVE_STRING_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_CTYPE_H 1
+#define HAVE_MATH_H 1
+#define HAVE_SIGNAL_H 1
+
+/* C library functions */
+#define HAVE_MALLOC 1
+#define HAVE_CALLOC 1
+#define HAVE_REALLOC 1
+#define HAVE_FREE 1
+#define HAVE_ALLOCA 1
+#define HAVE_GETENV 1
+#define HAVE_SETENV 1
+#define HAVE_PUTENV 1
+#define HAVE_SETENV 1
+#define HAVE_UNSETENV 1
+#define HAVE_QSORT 1
+#define HAVE_ABS 1
+#define HAVE_BCOPY 1
+#define HAVE_MEMSET 1
+#define HAVE_MEMCPY 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMCMP 1
+#define HAVE_STRLEN 1
+#define HAVE_STRLCPY 1
+#define HAVE_STRLCAT 1
+#define HAVE_STRDUP 1
+#define HAVE_STRCHR 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRSTR 1
+#define HAVE_STRTOL 1
+#define HAVE_STRTOUL 1
+#define HAVE_STRTOLL 1
+#define HAVE_STRTOULL 1
+#define HAVE_STRTOD 1
+#define HAVE_ATOI 1
+#define HAVE_ATOF 1
+#define HAVE_STRCMP 1
+#define HAVE_STRNCMP 1
+#define HAVE_STRCASECMP 1
+#define HAVE_STRNCASECMP 1
+#define HAVE_VSSCANF 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_M_PI 1
+#define HAVE_ATAN 1
+#define HAVE_ATAN2 1
+#define HAVE_ACOS 1
+#define HAVE_ASIN 1
+#define HAVE_CEIL 1
+#define HAVE_COPYSIGN 1
+#define HAVE_COS 1
+#define HAVE_COSF 1
+#define HAVE_FABS 1
+#define HAVE_FLOOR 1
+#define HAVE_LOG 1
+#define HAVE_POW 1
+#define HAVE_SCALBN 1
+#define HAVE_SIN 1
+#define HAVE_SINF 1
+#define HAVE_SQRT 1
+#define HAVE_SQRTF 1
+#define HAVE_TAN 1
+#define HAVE_TANF 1
+#define HAVE_SIGACTION 1
+#define HAVE_SETJMP 1
+#define HAVE_NANOSLEEP 1
+#define HAVE_SYSCONF 1
+#define HAVE_SYSCTLBYNAME 1
+
+/* enable iPhone version of Core Audio driver */
+#define SDL_AUDIO_DRIVER_COREAUDIO 1
+/* Enable the dummy audio driver (src/audio/dummy/\*.c) */
+#define SDL_AUDIO_DRIVER_DUMMY 1
+
+/* Enable the stub haptic driver (src/haptic/dummy/\*.c) */
+#define SDL_HAPTIC_DUMMY 1
+
+/* Enable MFi joystick support */
+#define SDL_JOYSTICK_MFI 1
+
+/* Enable Unix style SO loading */
+/* Technically this works, but violates the iOS dev agreement prior to iOS 8 */
+/* #define SDL_LOADSO_DLOPEN 1 */
+
+/* Enable the stub shared object loader (src/loadso/dummy/\*.c) */
+#define SDL_LOADSO_DISABLED 1
+
+/* Enable various threading systems */
+#define SDL_THREAD_PTHREAD 1
+#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1
+
+/* Enable various timer systems */
+#define SDL_TIMER_UNIX 1
+
+/* Supported video drivers */
+#define SDL_VIDEO_DRIVER_UIKIT 1
+#define SDL_VIDEO_DRIVER_DUMMY 1
+
+/* enable OpenGL ES */
+#define SDL_VIDEO_OPENGL_ES2 1
+#define SDL_VIDEO_OPENGL_ES 1
+#define SDL_VIDEO_RENDER_OGL_ES 1
+#define SDL_VIDEO_RENDER_OGL_ES2 1
+
+/* Enable system power support */
+#define SDL_POWER_UIKIT 1
+
+/* enable iPhone keyboard support */
+#define SDL_IPHONE_KEYBOARD 1
+
+/* enable iOS extended launch screen */
+#define SDL_IPHONE_LAUNCHSCREEN 1
+
+/* Set max recognized G-force from accelerometer
+ See src/joystick/uikit/SDL_sysjoystick.m for notes on why this is needed
+ */
+#define SDL_IPHONE_MAX_GFORCE 5.0
+
+/* enable filesystem support */
+#define SDL_FILESYSTEM_COCOA 1
+
+#endif /* _SDL_config_iphoneos_h */
diff --git a/external/SDL2/include/SDL_config_macosx.h b/external/SDL2/include/SDL_config_macosx.h
new file mode 100644
index 0000000..5c8b7e0
--- /dev/null
+++ b/external/SDL2/include/SDL_config_macosx.h
@@ -0,0 +1,188 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_macosx_h
+#define _SDL_config_macosx_h
+
+#include "SDL_platform.h"
+
+/* This gets us MAC_OS_X_VERSION_MIN_REQUIRED... */
+#include <AvailabilityMacros.h>
+
+/* This is a set of defines to configure the SDL features */
+
+#ifdef __LP64__
+ #define SIZEOF_VOIDP 8
+#else
+ #define SIZEOF_VOIDP 4
+#endif
+
+/* Useful headers */
+#define HAVE_ALLOCA_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_STDIO_H 1
+#define STDC_HEADERS 1
+#define HAVE_STRING_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_CTYPE_H 1
+#define HAVE_MATH_H 1
+#define HAVE_SIGNAL_H 1
+
+/* C library functions */
+#define HAVE_MALLOC 1
+#define HAVE_CALLOC 1
+#define HAVE_REALLOC 1
+#define HAVE_FREE 1
+#define HAVE_ALLOCA 1
+#define HAVE_GETENV 1
+#define HAVE_SETENV 1
+#define HAVE_PUTENV 1
+#define HAVE_UNSETENV 1
+#define HAVE_QSORT 1
+#define HAVE_ABS 1
+#define HAVE_BCOPY 1
+#define HAVE_MEMSET 1
+#define HAVE_MEMCPY 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMCMP 1
+#define HAVE_STRLEN 1
+#define HAVE_STRLCPY 1
+#define HAVE_STRLCAT 1
+#define HAVE_STRDUP 1
+#define HAVE_STRCHR 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRSTR 1
+#define HAVE_STRTOL 1
+#define HAVE_STRTOUL 1
+#define HAVE_STRTOLL 1
+#define HAVE_STRTOULL 1
+#define HAVE_STRTOD 1
+#define HAVE_ATOI 1
+#define HAVE_ATOF 1
+#define HAVE_STRCMP 1
+#define HAVE_STRNCMP 1
+#define HAVE_STRCASECMP 1
+#define HAVE_STRNCASECMP 1
+#define HAVE_VSSCANF 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_CEIL 1
+#define HAVE_COPYSIGN 1
+#define HAVE_COS 1
+#define HAVE_COSF 1
+#define HAVE_FABS 1
+#define HAVE_FLOOR 1
+#define HAVE_LOG 1
+#define HAVE_POW 1
+#define HAVE_SCALBN 1
+#define HAVE_SIN 1
+#define HAVE_SINF 1
+#define HAVE_SQRT 1
+#define HAVE_SQRTF 1
+#define HAVE_TAN 1
+#define HAVE_TANF 1
+#define HAVE_SIGACTION 1
+#define HAVE_SETJMP 1
+#define HAVE_NANOSLEEP 1
+#define HAVE_SYSCONF 1
+#define HAVE_SYSCTLBYNAME 1
+#define HAVE_ATAN 1
+#define HAVE_ATAN2 1
+#define HAVE_ACOS 1
+#define HAVE_ASIN 1
+
+/* Enable various audio drivers */
+#define SDL_AUDIO_DRIVER_COREAUDIO 1
+#define SDL_AUDIO_DRIVER_DISK 1
+#define SDL_AUDIO_DRIVER_DUMMY 1
+
+/* Enable various input drivers */
+#define SDL_JOYSTICK_IOKIT 1
+#define SDL_HAPTIC_IOKIT 1
+
+/* Enable various shared object loading systems */
+#define SDL_LOADSO_DLOPEN 1
+
+/* Enable various threading systems */
+#define SDL_THREAD_PTHREAD 1
+#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1
+
+/* Enable various timer systems */
+#define SDL_TIMER_UNIX 1
+
+/* Enable various video drivers */
+#define SDL_VIDEO_DRIVER_COCOA 1
+#define SDL_VIDEO_DRIVER_DUMMY 1
+#undef SDL_VIDEO_DRIVER_X11
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC "/usr/X11R6/lib/libX11.6.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT "/usr/X11R6/lib/libXext.6.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA "/usr/X11R6/lib/libXinerama.1.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 "/usr/X11R6/lib/libXi.6.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "/usr/X11R6/lib/libXrandr.2.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS "/usr/X11R6/lib/libXss.1.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE "/usr/X11R6/lib/libXxf86vm.1.dylib"
+#define SDL_VIDEO_DRIVER_X11_XDBE 1
+#define SDL_VIDEO_DRIVER_X11_XINERAMA 1
+#define SDL_VIDEO_DRIVER_X11_XRANDR 1
+#define SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1
+#define SDL_VIDEO_DRIVER_X11_XSHAPE 1
+#define SDL_VIDEO_DRIVER_X11_XVIDMODE 1
+#define SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM 1
+
+#ifdef MAC_OS_X_VERSION_10_8
+/*
+ * No matter the versions targeted, this is the 10.8 or later SDK, so you have
+ * to use the external Xquartz, which is a more modern Xlib. Previous SDKs
+ * used an older Xlib.
+ */
+#define SDL_VIDEO_DRIVER_X11_XINPUT2 1
+#define SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1
+#define SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY 1
+#endif
+
+#ifndef SDL_VIDEO_RENDER_OGL
+#define SDL_VIDEO_RENDER_OGL 1
+#endif
+
+/* Enable OpenGL support */
+#ifndef SDL_VIDEO_OPENGL
+#define SDL_VIDEO_OPENGL 1
+#endif
+#ifndef SDL_VIDEO_OPENGL_CGL
+#define SDL_VIDEO_OPENGL_CGL 1
+#endif
+#ifndef SDL_VIDEO_OPENGL_GLX
+#define SDL_VIDEO_OPENGL_GLX 1
+#endif
+
+/* Enable system power support */
+#define SDL_POWER_MACOSX 1
+
+/* enable filesystem support */
+#define SDL_FILESYSTEM_COCOA 1
+
+/* Enable assembly routines */
+#define SDL_ASSEMBLY_ROUTINES 1
+#ifdef __ppc__
+#define SDL_ALTIVEC_BLITTERS 1
+#endif
+
+#endif /* _SDL_config_macosx_h */
diff --git a/external/SDL2/include/SDL_config_minimal.h b/external/SDL2/include/SDL_config_minimal.h
new file mode 100644
index 0000000..3c9d09a
--- /dev/null
+++ b/external/SDL2/include/SDL_config_minimal.h
@@ -0,0 +1,81 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_minimal_h
+#define _SDL_config_minimal_h
+
+#include "SDL_platform.h"
+
+/**
+ * \file SDL_config_minimal.h
+ *
+ * This is the minimal configuration that can be used to build SDL.
+ */
+
+#define HAVE_STDARG_H 1
+#define HAVE_STDDEF_H 1
+
+/* Most everything except Visual Studio 2008 and earlier has stdint.h now */
+#if defined(_MSC_VER) && (_MSC_VER < 1600)
+/* Here are some reasonable defaults */
+typedef unsigned int size_t;
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef signed long long int64_t;
+typedef unsigned long long uint64_t;
+typedef unsigned long uintptr_t;
+#else
+#define HAVE_STDINT_H 1
+#endif /* Visual Studio 2008 */
+
+#ifdef __GNUC__
+#define HAVE_GCC_SYNC_LOCK_TEST_AND_SET 1
+#endif
+
+/* Enable the dummy audio driver (src/audio/dummy/\*.c) */
+#define SDL_AUDIO_DRIVER_DUMMY 1
+
+/* Enable the stub joystick driver (src/joystick/dummy/\*.c) */
+#define SDL_JOYSTICK_DISABLED 1
+
+/* Enable the stub haptic driver (src/haptic/dummy/\*.c) */
+#define SDL_HAPTIC_DISABLED 1
+
+/* Enable the stub shared object loader (src/loadso/dummy/\*.c) */
+#define SDL_LOADSO_DISABLED 1
+
+/* Enable the stub thread support (src/thread/generic/\*.c) */
+#define SDL_THREADS_DISABLED 1
+
+/* Enable the stub timer support (src/timer/dummy/\*.c) */
+#define SDL_TIMERS_DISABLED 1
+
+/* Enable the dummy video driver (src/video/dummy/\*.c) */
+#define SDL_VIDEO_DRIVER_DUMMY 1
+
+/* Enable the dummy filesystem driver (src/filesystem/dummy/\*.c) */
+#define SDL_FILESYSTEM_DUMMY 1
+
+#endif /* _SDL_config_minimal_h */
diff --git a/external/SDL2/include/SDL_config_pandora.h b/external/SDL2/include/SDL_config_pandora.h
new file mode 100644
index 0000000..7b51e57
--- /dev/null
+++ b/external/SDL2/include/SDL_config_pandora.h
@@ -0,0 +1,127 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_h
+#define _SDL_config_h
+
+/* This is a set of defines to configure the SDL features */
+
+/* General platform specific identifiers */
+#include "SDL_platform.h"
+
+#ifdef __LP64__
+#define SIZEOF_VOIDP 8
+#else
+#define SIZEOF_VOIDP 4
+#endif
+
+#define SDL_BYTEORDER 1234
+
+#define HAVE_ALLOCA_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_STDIO_H 1
+#define STDC_HEADERS 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STDARG_H 1
+#define HAVE_MALLOC_H 1
+#define HAVE_MEMORY_H 1
+#define HAVE_STRING_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_CTYPE_H 1
+#define HAVE_MATH_H 1
+#define HAVE_ICONV_H 1
+#define HAVE_SIGNAL_H 1
+#define HAVE_MALLOC 1
+#define HAVE_CALLOC 1
+#define HAVE_REALLOC 1
+#define HAVE_FREE 1
+#define HAVE_ALLOCA 1
+#define HAVE_GETENV 1
+#define HAVE_SETENV 1
+#define HAVE_PUTENV 1
+#define HAVE_UNSETENV 1
+#define HAVE_QSORT 1
+#define HAVE_ABS 1
+#define HAVE_BCOPY 1
+#define HAVE_MEMSET 1
+#define HAVE_MEMCPY 1
+#define HAVE_MEMMOVE 1
+#define HAVE_STRLEN 1
+#define HAVE_STRDUP 1
+#define HAVE_STRCHR 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRSTR 1
+#define HAVE_STRTOL 1
+#define HAVE_STRTOUL 1
+#define HAVE_STRTOLL 1
+#define HAVE_STRTOULL 1
+#define HAVE_ATOI 1
+#define HAVE_ATOF 1
+#define HAVE_STRCMP 1
+#define HAVE_STRNCMP 1
+#define HAVE_STRCASECMP 1
+#define HAVE_STRNCASECMP 1
+#define HAVE_VSSCANF 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_M_PI 1
+#define HAVE_CEIL 1
+#define HAVE_COPYSIGN 1
+#define HAVE_COS 1
+#define HAVE_COSF 1
+#define HAVE_FABS 1
+#define HAVE_FLOOR 1
+#define HAVE_LOG 1
+#define HAVE_SCALBN 1
+#define HAVE_SIN 1
+#define HAVE_SINF 1
+#define HAVE_SQRT 1
+#define HAVE_SQRTF 1
+#define HAVE_TAN 1
+#define HAVE_TANF 1
+#define HAVE_SIGACTION 1
+#define HAVE_SETJMP 1
+#define HAVE_NANOSLEEP 1
+
+#define SDL_AUDIO_DRIVER_DUMMY 1
+#define SDL_AUDIO_DRIVER_OSS 1
+
+#define SDL_INPUT_LINUXEV 1
+#define SDL_INPUT_TSLIB 1
+#define SDL_JOYSTICK_LINUX 1
+#define SDL_HAPTIC_LINUX 1
+
+#define SDL_LOADSO_DLOPEN 1
+
+#define SDL_THREAD_PTHREAD 1
+#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP 1
+
+#define SDL_TIMER_UNIX 1
+#define SDL_FILESYSTEM_UNIX 1
+
+#define SDL_VIDEO_DRIVER_DUMMY 1
+#define SDL_VIDEO_DRIVER_X11 1
+#define SDL_VIDEO_DRIVER_PANDORA 1
+#define SDL_VIDEO_RENDER_OGL_ES 1
+#define SDL_VIDEO_OPENGL_ES 1
+
+#endif /* _SDL_config_h */
diff --git a/external/SDL2/include/SDL_config_psp.h b/external/SDL2/include/SDL_config_psp.h
new file mode 100644
index 0000000..a6e4960
--- /dev/null
+++ b/external/SDL2/include/SDL_config_psp.h
@@ -0,0 +1,143 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_psp_h
+#define _SDL_config_psp_h
+
+#include "SDL_platform.h"
+
+
+
+#ifdef __GNUC__
+#define HAVE_GCC_SYNC_LOCK_TEST_AND_SET 1
+#endif
+
+#define HAVE_GCC_ATOMICS 1
+
+#define HAVE_ALLOCA_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_STDIO_H 1
+#define STDC_HEADERS 1
+#define HAVE_STRING_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_CTYPE_H 1
+#define HAVE_MATH_H 1
+#define HAVE_SIGNAL_H 1
+
+/* C library functions */
+#define HAVE_MALLOC 1
+#define HAVE_CALLOC 1
+#define HAVE_REALLOC 1
+#define HAVE_FREE 1
+#define HAVE_ALLOCA 1
+#define HAVE_GETENV 1
+#define HAVE_SETENV 1
+#define HAVE_PUTENV 1
+#define HAVE_SETENV 1
+#define HAVE_UNSETENV 1
+#define HAVE_QSORT 1
+#define HAVE_ABS 1
+#define HAVE_BCOPY 1
+#define HAVE_MEMSET 1
+#define HAVE_MEMCPY 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMCMP 1
+#define HAVE_STRLEN 1
+#define HAVE_STRLCPY 1
+#define HAVE_STRLCAT 1
+#define HAVE_STRDUP 1
+#define HAVE_STRCHR 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRSTR 1
+#define HAVE_STRTOL 1
+#define HAVE_STRTOUL 1
+#define HAVE_STRTOLL 1
+#define HAVE_STRTOULL 1
+#define HAVE_STRTOD 1
+#define HAVE_ATOI 1
+#define HAVE_ATOF 1
+#define HAVE_STRCMP 1
+#define HAVE_STRNCMP 1
+#define HAVE_STRCASECMP 1
+#define HAVE_STRNCASECMP 1
+#define HAVE_VSSCANF 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_M_PI 1
+#define HAVE_ATAN 1
+#define HAVE_ATAN2 1
+#define HAVE_ACOS 1
+#define HAVE_ASIN 1
+#define HAVE_CEIL 1
+#define HAVE_COPYSIGN 1
+#define HAVE_COS 1
+#define HAVE_COSF 1
+#define HAVE_FABS 1
+#define HAVE_FLOOR 1
+#define HAVE_LOG 1
+#define HAVE_POW 1
+#define HAVE_SCALBN 1
+#define HAVE_SIN 1
+#define HAVE_SINF 1
+#define HAVE_SQRT 1
+#define HAVE_SQRTF 1
+#define HAVE_TAN 1
+#define HAVE_TANF 1
+#define HAVE_SETJMP 1
+#define HAVE_NANOSLEEP 1
+/* #define HAVE_SYSCONF 1 */
+/* #define HAVE_SIGACTION 1 */
+
+
+/* PSP isn't that sophisticated */
+#define LACKS_SYS_MMAN_H 1
+
+/* Enable the stub thread support (src/thread/psp/\*.c) */
+#define SDL_THREAD_PSP 1
+
+/* Enable the stub timer support (src/timer/psp/\*.c) */
+#define SDL_TIMERS_PSP 1
+
+/* Enable the stub joystick driver (src/joystick/psp/\*.c) */
+#define SDL_JOYSTICK_PSP 1
+
+/* Enable the stub audio driver (src/audio/psp/\*.c) */
+#define SDL_AUDIO_DRIVER_PSP 1
+
+/* PSP video dirver */
+#define SDL_VIDEO_DRIVER_PSP 1
+
+/* PSP render dirver */
+#define SDL_VIDEO_RENDER_PSP 1
+
+#define SDL_POWER_PSP 1
+
+/* !!! FIXME: what does PSP do for filesystem stuff? */
+#define SDL_FILESYSTEM_DUMMY 1
+
+/* PSP doesn't have haptic device (src/haptic/dummy/\*.c) */
+#define SDL_HAPTIC_DISABLED 1
+
+/* PSP can't load shared object (src/loadso/dummy/\*.c) */
+#define SDL_LOADSO_DISABLED 1
+
+
+#endif /* _SDL_config_psp_h */
diff --git a/external/SDL2/include/SDL_config_windows.h b/external/SDL2/include/SDL_config_windows.h
new file mode 100644
index 0000000..890986c
--- /dev/null
+++ b/external/SDL2/include/SDL_config_windows.h
@@ -0,0 +1,221 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_windows_h
+#define _SDL_config_windows_h
+
+#include "SDL_platform.h"
+
+/* This is a set of defines to configure the SDL features */
+
+#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
+#if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
+#define HAVE_STDINT_H 1
+#elif defined(_MSC_VER)
+typedef signed __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef signed __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef signed __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#ifndef _UINTPTR_T_DEFINED
+#ifdef _WIN64
+typedef unsigned __int64 uintptr_t;
+#else
+typedef unsigned int uintptr_t;
+#endif
+#define _UINTPTR_T_DEFINED
+#endif
+/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
+#if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
+#define DWORD_PTR DWORD
+#endif
+#if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
+#define LONG_PTR LONG
+#endif
+#else /* !__GNUC__ && !_MSC_VER */
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef signed long long int64_t;
+typedef unsigned long long uint64_t;
+#ifndef _SIZE_T_DEFINED_
+#define _SIZE_T_DEFINED_
+typedef unsigned int size_t;
+#endif
+typedef unsigned int uintptr_t;
+#endif /* __GNUC__ || _MSC_VER */
+#endif /* !_STDINT_H_ && !HAVE_STDINT_H */
+
+#ifdef _WIN64
+# define SIZEOF_VOIDP 8
+#else
+# define SIZEOF_VOIDP 4
+#endif
+
+#define HAVE_DDRAW_H 1
+#define HAVE_DINPUT_H 1
+#define HAVE_DSOUND_H 1
+#define HAVE_DXGI_H 1
+#define HAVE_XINPUT_H 1
+
+/* This is disabled by default to avoid C runtime dependencies and manifest requirements */
+#ifdef HAVE_LIBC
+/* Useful headers */
+#define HAVE_STDIO_H 1
+#define STDC_HEADERS 1
+#define HAVE_STRING_H 1
+#define HAVE_CTYPE_H 1
+#define HAVE_MATH_H 1
+#define HAVE_SIGNAL_H 1
+
+/* C library functions */
+#define HAVE_MALLOC 1
+#define HAVE_CALLOC 1
+#define HAVE_REALLOC 1
+#define HAVE_FREE 1
+#define HAVE_ALLOCA 1
+#define HAVE_QSORT 1
+#define HAVE_ABS 1
+#define HAVE_MEMSET 1
+#define HAVE_MEMCPY 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMCMP 1
+#define HAVE_STRLEN 1
+#define HAVE__STRREV 1
+#define HAVE__STRUPR 1
+#define HAVE__STRLWR 1
+#define HAVE_STRCHR 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRSTR 1
+#define HAVE__LTOA 1
+#define HAVE__ULTOA 1
+#define HAVE_STRTOL 1
+#define HAVE_STRTOUL 1
+#define HAVE_STRTOD 1
+#define HAVE_ATOI 1
+#define HAVE_ATOF 1
+#define HAVE_STRCMP 1
+#define HAVE_STRNCMP 1
+#define HAVE__STRICMP 1
+#define HAVE__STRNICMP 1
+#define HAVE_ATAN 1
+#define HAVE_ATAN2 1
+#define HAVE_ACOS 1
+#define HAVE_ASIN 1
+#define HAVE_CEIL 1
+#define HAVE_COS 1
+#define HAVE_COSF 1
+#define HAVE_FABS 1
+#define HAVE_FLOOR 1
+#define HAVE_LOG 1
+#define HAVE_POW 1
+#define HAVE_SIN 1
+#define HAVE_SINF 1
+#define HAVE_SQRT 1
+#define HAVE_SQRTF 1
+#define HAVE_TAN 1
+#define HAVE_TANF 1
+#if _MSC_VER >= 1800
+#define HAVE_STRTOLL 1
+#define HAVE_VSSCANF 1
+#define HAVE_COPYSIGN 1
+#define HAVE_SCALBN 1
+#endif
+#if !defined(_MSC_VER) || defined(_USE_MATH_DEFINES)
+#define HAVE_M_PI 1
+#endif
+#else
+#define HAVE_STDARG_H 1
+#define HAVE_STDDEF_H 1
+#endif
+
+/* Enable various audio drivers */
+#define SDL_AUDIO_DRIVER_DSOUND 1
+#define SDL_AUDIO_DRIVER_XAUDIO2 1
+#define SDL_AUDIO_DRIVER_WINMM 1
+#define SDL_AUDIO_DRIVER_DISK 1
+#define SDL_AUDIO_DRIVER_DUMMY 1
+
+/* Enable various input drivers */
+#define SDL_JOYSTICK_DINPUT 1
+#define SDL_JOYSTICK_XINPUT 1
+#define SDL_HAPTIC_DINPUT 1
+#define SDL_HAPTIC_XINPUT 1
+
+/* Enable various shared object loading systems */
+#define SDL_LOADSO_WINDOWS 1
+
+/* Enable various threading systems */
+#define SDL_THREAD_WINDOWS 1
+
+/* Enable various timer systems */
+#define SDL_TIMER_WINDOWS 1
+
+/* Enable various video drivers */
+#define SDL_VIDEO_DRIVER_DUMMY 1
+#define SDL_VIDEO_DRIVER_WINDOWS 1
+
+#ifndef SDL_VIDEO_RENDER_D3D
+#define SDL_VIDEO_RENDER_D3D 1
+#endif
+#ifndef SDL_VIDEO_RENDER_D3D11
+#define SDL_VIDEO_RENDER_D3D11 0
+#endif
+
+/* Enable OpenGL support */
+#ifndef SDL_VIDEO_OPENGL
+#define SDL_VIDEO_OPENGL 1
+#endif
+#ifndef SDL_VIDEO_OPENGL_WGL
+#define SDL_VIDEO_OPENGL_WGL 1
+#endif
+#ifndef SDL_VIDEO_RENDER_OGL
+#define SDL_VIDEO_RENDER_OGL 1
+#endif
+#ifndef SDL_VIDEO_RENDER_OGL_ES2
+#define SDL_VIDEO_RENDER_OGL_ES2 1
+#endif
+#ifndef SDL_VIDEO_OPENGL_ES2
+#define SDL_VIDEO_OPENGL_ES2 1
+#endif
+#ifndef SDL_VIDEO_OPENGL_EGL
+#define SDL_VIDEO_OPENGL_EGL 1
+#endif
+
+
+/* Enable system power support */
+#define SDL_POWER_WINDOWS 1
+
+/* Enable filesystem support */
+#define SDL_FILESYSTEM_WINDOWS 1
+
+/* Enable assembly routines (Win64 doesn't have inline asm) */
+#ifndef _WIN64
+#define SDL_ASSEMBLY_ROUTINES 1
+#endif
+
+#endif /* _SDL_config_windows_h */
diff --git a/external/SDL2/include/SDL_config_winrt.h b/external/SDL2/include/SDL_config_winrt.h
new file mode 100644
index 0000000..e392f77
--- /dev/null
+++ b/external/SDL2/include/SDL_config_winrt.h
@@ -0,0 +1,214 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_winrt_h
+#define _SDL_config_winrt_h
+
+#include "SDL_platform.h"
+
+/* Make sure the Windows SDK's NTDDI_VERSION macro gets defined. This is used
+ by SDL to determine which version of the Windows SDK is being used.
+*/
+#include <sdkddkver.h>
+
+/* Define possibly-undefined NTDDI values (used when compiling SDL against
+ older versions of the Windows SDK.
+*/
+#ifndef NTDDI_WINBLUE
+#define NTDDI_WINBLUE 0x06030000
+#endif
+#ifndef NTDDI_WIN10
+#define NTDDI_WIN10 0x0A000000
+#endif
+
+/* This is a set of defines to configure the SDL features */
+
+#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
+#if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
+#define HAVE_STDINT_H 1
+#elif defined(_MSC_VER)
+typedef signed __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef signed __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef signed __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#ifndef _UINTPTR_T_DEFINED
+#ifdef _WIN64
+typedef unsigned __int64 uintptr_t;
+#else
+typedef unsigned int uintptr_t;
+#endif
+#define _UINTPTR_T_DEFINED
+#endif
+/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
+#if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
+#define DWORD_PTR DWORD
+#endif
+#if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
+#define LONG_PTR LONG
+#endif
+#else /* !__GNUC__ && !_MSC_VER */
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef signed long long int64_t;
+typedef unsigned long long uint64_t;
+#ifndef _SIZE_T_DEFINED_
+#define _SIZE_T_DEFINED_
+typedef unsigned int size_t;
+#endif
+typedef unsigned int uintptr_t;
+#endif /* __GNUC__ || _MSC_VER */
+#endif /* !_STDINT_H_ && !HAVE_STDINT_H */
+
+#ifdef _WIN64
+# define SIZEOF_VOIDP 8
+#else
+# define SIZEOF_VOIDP 4
+#endif
+
+/* Useful headers */
+#define HAVE_DXGI_H 1
+#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+#define HAVE_XINPUT_H 1
+#endif
+#define HAVE_LIBC 1
+#define HAVE_STDIO_H 1
+#define STDC_HEADERS 1
+#define HAVE_STRING_H 1
+#define HAVE_CTYPE_H 1
+#define HAVE_MATH_H 1
+#define HAVE_FLOAT_H 1
+#define HAVE_SIGNAL_H 1
+
+/* C library functions */
+#define HAVE_MALLOC 1
+#define HAVE_CALLOC 1
+#define HAVE_REALLOC 1
+#define HAVE_FREE 1
+#define HAVE_ALLOCA 1
+#define HAVE_QSORT 1
+#define HAVE_ABS 1
+#define HAVE_MEMSET 1
+#define HAVE_MEMCPY 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMCMP 1
+#define HAVE_STRLEN 1
+#define HAVE__STRREV 1
+#define HAVE__STRUPR 1
+//#define HAVE__STRLWR 1 // TODO, WinRT: consider using _strlwr_s instead
+#define HAVE_STRCHR 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRSTR 1
+//#define HAVE_ITOA 1 // TODO, WinRT: consider using _itoa_s instead
+//#define HAVE__LTOA 1 // TODO, WinRT: consider using _ltoa_s instead
+//#define HAVE__ULTOA 1 // TODO, WinRT: consider using _ultoa_s instead
+#define HAVE_STRTOL 1
+#define HAVE_STRTOUL 1
+//#define HAVE_STRTOLL 1
+#define HAVE_STRTOD 1
+#define HAVE_ATOI 1
+#define HAVE_ATOF 1
+#define HAVE_STRCMP 1
+#define HAVE_STRNCMP 1
+#define HAVE__STRICMP 1
+#define HAVE__STRNICMP 1
+#define HAVE_VSNPRINTF 1
+//#define HAVE_SSCANF 1 // TODO, WinRT: consider using sscanf_s instead
+#define HAVE_M_PI 1
+#define HAVE_ATAN 1
+#define HAVE_ATAN2 1
+#define HAVE_CEIL 1
+#define HAVE__COPYSIGN 1
+#define HAVE_COS 1
+#define HAVE_COSF 1
+#define HAVE_FABS 1
+#define HAVE_FLOOR 1
+#define HAVE_LOG 1
+#define HAVE_POW 1
+//#define HAVE_SCALBN 1
+#define HAVE__SCALB 1
+#define HAVE_SIN 1
+#define HAVE_SINF 1
+#define HAVE_SQRT 1
+#define HAVE_SQRTF 1
+#define HAVE_TAN 1
+#define HAVE_TANF 1
+#define HAVE__FSEEKI64 1
+
+/* Enable various audio drivers */
+#define SDL_AUDIO_DRIVER_XAUDIO2 1
+#define SDL_AUDIO_DRIVER_DISK 1
+#define SDL_AUDIO_DRIVER_DUMMY 1
+
+/* Enable various input drivers */
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+#define SDL_JOYSTICK_DISABLED 1
+#define SDL_HAPTIC_DISABLED 1
+#else
+#define SDL_JOYSTICK_XINPUT 1
+#define SDL_HAPTIC_XINPUT 1
+#endif
+
+/* Enable various shared object loading systems */
+#define SDL_LOADSO_WINDOWS 1
+
+/* Enable various threading systems */
+#if (NTDDI_VERSION >= NTDDI_WINBLUE)
+#define SDL_THREAD_WINDOWS 1
+#else
+/* WinRT on Windows 8.0 and Windows Phone 8.0 don't support CreateThread() */
+#define SDL_THREAD_STDCPP 1
+#endif
+
+/* Enable various timer systems */
+#define SDL_TIMER_WINDOWS 1
+
+/* Enable various video drivers */
+#define SDL_VIDEO_DRIVER_WINRT 1
+#define SDL_VIDEO_DRIVER_DUMMY 1
+
+/* Enable OpenGL ES 2.0 (via a modified ANGLE library) */
+#define SDL_VIDEO_OPENGL_ES2 1
+#define SDL_VIDEO_OPENGL_EGL 1
+
+/* Enable appropriate renderer(s) */
+#define SDL_VIDEO_RENDER_D3D11 1
+
+#if SDL_VIDEO_OPENGL_ES2
+#define SDL_VIDEO_RENDER_OGL_ES2 1
+#endif
+
+/* Enable system power support */
+#define SDL_POWER_WINRT 1
+
+/* Enable assembly routines (Win64 doesn't have inline asm) */
+#ifndef _WIN64
+#define SDL_ASSEMBLY_ROUTINES 1
+#endif
+
+#endif /* _SDL_config_winrt_h */
diff --git a/external/SDL2/include/SDL_config_wiz.h b/external/SDL2/include/SDL_config_wiz.h
new file mode 100644
index 0000000..e090a1a
--- /dev/null
+++ b/external/SDL2/include/SDL_config_wiz.h
@@ -0,0 +1,120 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_config_h
+#define _SDL_config_h
+
+/* This is a set of defines to configure the SDL features */
+
+/* General platform specific identifiers */
+#include "SDL_platform.h"
+
+#define SDL_BYTEORDER 1234
+
+#define HAVE_ALLOCA_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_STDIO_H 1
+#define STDC_HEADERS 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STDARG_H 1
+#define HAVE_MALLOC_H 1
+#define HAVE_MEMORY_H 1
+#define HAVE_STRING_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_CTYPE_H 1
+#define HAVE_MATH_H 1
+#define HAVE_ICONV_H 1
+#define HAVE_SIGNAL_H 1
+#define HAVE_MALLOC 1
+#define HAVE_CALLOC 1
+#define HAVE_REALLOC 1
+#define HAVE_FREE 1
+#define HAVE_ALLOCA 1
+#define HAVE_GETENV 1
+#define HAVE_SETENV 1
+#define HAVE_PUTENV 1
+#define HAVE_UNSETENV 1
+#define HAVE_QSORT 1
+#define HAVE_ABS 1
+#define HAVE_BCOPY 1
+#define HAVE_MEMSET 1
+#define HAVE_MEMCPY 1
+#define HAVE_MEMMOVE 1
+#define HAVE_STRLEN 1
+#define HAVE_STRDUP 1
+#define HAVE_STRCHR 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRSTR 1
+#define HAVE_STRTOL 1
+#define HAVE_STRTOUL 1
+#define HAVE_STRTOLL 1
+#define HAVE_STRTOULL 1
+#define HAVE_ATOI 1
+#define HAVE_ATOF 1
+#define HAVE_STRCMP 1
+#define HAVE_STRNCMP 1
+#define HAVE_STRCASECMP 1
+#define HAVE_STRNCASECMP 1
+#define HAVE_VSSCANF 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_M_PI 1
+#define HAVE_CEIL 1
+#define HAVE_COPYSIGN 1
+#define HAVE_COS 1
+#define HAVE_COSF 1
+#define HAVE_FABS 1
+#define HAVE_FLOOR 1
+#define HAVE_LOG 1
+#define HAVE_SCALBN 1
+#define HAVE_SIN 1
+#define HAVE_SINF 1
+#define HAVE_SQRT 1
+#define HAVE_SQRTF 1
+#define HAVE_TAN 1
+#define HAVE_TANF 1
+#define HAVE_SIGACTION 1
+#define HAVE_SETJMP 1
+#define HAVE_NANOSLEEP 1
+#define HAVE_POW 1
+
+#define SDL_AUDIO_DRIVER_DUMMY 1
+#define SDL_AUDIO_DRIVER_OSS 1
+
+#define SDL_INPUT_LINUXEV 1
+#define SDL_INPUT_TSLIB 1
+#define SDL_JOYSTICK_LINUX 1
+#define SDL_HAPTIC_LINUX 1
+
+#define SDL_LOADSO_DLOPEN 1
+
+#define SDL_THREAD_PTHREAD 1
+#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP 1
+
+#define SDL_TIMER_UNIX 1
+
+#define SDL_VIDEO_DRIVER_DUMMY 1
+#define SDL_VIDEO_DRIVER_PANDORA 1
+#define SDL_VIDEO_RENDER_OGL_ES 1
+#define SDL_VIDEO_OPENGL_ES 1
+
+#endif /* _SDL_config_h */
diff --git a/external/SDL2/include/SDL_copying.h b/external/SDL2/include/SDL_copying.h
new file mode 100644
index 0000000..212da0e
--- /dev/null
+++ b/external/SDL2/include/SDL_copying.h
@@ -0,0 +1,20 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
diff --git a/external/SDL2/include/SDL_cpuinfo.h b/external/SDL2/include/SDL_cpuinfo.h
new file mode 100644
index 0000000..d0ba47b
--- /dev/null
+++ b/external/SDL2/include/SDL_cpuinfo.h
@@ -0,0 +1,161 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_cpuinfo.h
+ *
+ * CPU feature detection for SDL.
+ */
+
+#ifndef _SDL_cpuinfo_h
+#define _SDL_cpuinfo_h
+
+#include "SDL_stdinc.h"
+
+/* Need to do this here because intrin.h has C++ code in it */
+/* Visual Studio 2005 has a bug where intrin.h conflicts with winnt.h */
+#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (defined(_M_IX86) || defined(_M_X64))
+#include <intrin.h>
+#ifndef _WIN64
+#define __MMX__
+#define __3dNOW__
+#endif
+#define __SSE__
+#define __SSE2__
+#elif defined(__MINGW64_VERSION_MAJOR)
+#include <intrin.h>
+#else
+#ifdef __ALTIVEC__
+#if HAVE_ALTIVEC_H && !defined(__APPLE_ALTIVEC__)
+#include <altivec.h>
+#undef pixel
+#endif
+#endif
+#ifdef __MMX__
+#include <mmintrin.h>
+#endif
+#ifdef __3dNOW__
+#include <mm3dnow.h>
+#endif
+#ifdef __SSE__
+#include <xmmintrin.h>
+#endif
+#ifdef __SSE2__
+#include <emmintrin.h>
+#endif
+#endif
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This is a guess for the cacheline size used for padding.
+ * Most x86 processors have a 64 byte cache line.
+ * The 64-bit PowerPC processors have a 128 byte cache line.
+ * We'll use the larger value to be generally safe.
+ */
+#define SDL_CACHELINE_SIZE 128
+
+/**
+ * This function returns the number of CPU cores available.
+ */
+extern DECLSPEC int SDLCALL SDL_GetCPUCount(void);
+
+/**
+ * This function returns the L1 cache line size of the CPU
+ *
+ * This is useful for determining multi-threaded structure padding
+ * or SIMD prefetch sizes.
+ */
+extern DECLSPEC int SDLCALL SDL_GetCPUCacheLineSize(void);
+
+/**
+ * This function returns true if the CPU has the RDTSC instruction.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasRDTSC(void);
+
+/**
+ * This function returns true if the CPU has AltiVec features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasAltiVec(void);
+
+/**
+ * This function returns true if the CPU has MMX features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasMMX(void);
+
+/**
+ * This function returns true if the CPU has 3DNow! features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_Has3DNow(void);
+
+/**
+ * This function returns true if the CPU has SSE features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE(void);
+
+/**
+ * This function returns true if the CPU has SSE2 features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE2(void);
+
+/**
+ * This function returns true if the CPU has SSE3 features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE3(void);
+
+/**
+ * This function returns true if the CPU has SSE4.1 features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE41(void);
+
+/**
+ * This function returns true if the CPU has SSE4.2 features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE42(void);
+
+/**
+ * This function returns true if the CPU has AVX features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX(void);
+
+/**
+ * This function returns true if the CPU has AVX2 features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX2(void);
+
+/**
+ * This function returns the amount of RAM configured in the system, in MB.
+ */
+extern DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_cpuinfo_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_egl.h b/external/SDL2/include/SDL_egl.h
new file mode 100644
index 0000000..bea2a6c
--- /dev/null
+++ b/external/SDL2/include/SDL_egl.h
@@ -0,0 +1,1673 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_egl.h
+ *
+ * This is a simple file to encapsulate the EGL API headers.
+ */
+#ifndef _MSC_VER
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#else /* _MSC_VER */
+
+/* EGL headers for Visual Studio */
+
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Khronos platform-specific types and definitions.
+*
+* $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $
+*
+* Adopters may modify this file to suit their platform. Adopters are
+* encouraged to submit platform specific modifications to the Khronos
+* group so that they can be included in future versions of this file.
+* Please submit changes by sending them to the public Khronos Bugzilla
+* (http://khronos.org/bugzilla) by filing a bug against product
+* "Khronos (general)" component "Registry".
+*
+* A predefined template which fills in some of the bug fields can be
+* reached using http://tinyurl.com/khrplatform-h-bugreport, but you
+* must create a Bugzilla login first.
+*
+*
+* See the Implementer's Guidelines for information about where this file
+* should be located on your system and for more details of its use:
+* http://www.khronos.org/registry/implementers_guide.pdf
+*
+* This file should be included as
+* #include <KHR/khrplatform.h>
+* by Khronos client API header files that use its types and defines.
+*
+* The types in khrplatform.h should only be used to define API-specific types.
+*
+* Types defined in khrplatform.h:
+* khronos_int8_t signed 8 bit
+* khronos_uint8_t unsigned 8 bit
+* khronos_int16_t signed 16 bit
+* khronos_uint16_t unsigned 16 bit
+* khronos_int32_t signed 32 bit
+* khronos_uint32_t unsigned 32 bit
+* khronos_int64_t signed 64 bit
+* khronos_uint64_t unsigned 64 bit
+* khronos_intptr_t signed same number of bits as a pointer
+* khronos_uintptr_t unsigned same number of bits as a pointer
+* khronos_ssize_t signed size
+* khronos_usize_t unsigned size
+* khronos_float_t signed 32 bit floating point
+* khronos_time_ns_t unsigned 64 bit time in nanoseconds
+* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+* nanoseconds
+* khronos_stime_nanoseconds_t signed time interval in nanoseconds
+* khronos_boolean_enum_t enumerated boolean type. This should
+* only be used as a base type when a client API's boolean type is
+* an enum. Client APIs which use an integer or other type for
+* booleans cannot use this as the base type for their boolean.
+*
+* Tokens defined in khrplatform.h:
+*
+* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
+*
+* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+*
+* Calling convention macros defined in this file:
+* KHRONOS_APICALL
+* KHRONOS_APIENTRY
+* KHRONOS_APIATTRIBUTES
+*
+* These may be used in function prototypes as:
+*
+* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+* int arg1,
+* int arg2) KHRONOS_APIATTRIBUTES;
+*/
+
+/*-------------------------------------------------------------------------
+* Definition of KHRONOS_APICALL
+*-------------------------------------------------------------------------
+* This precedes the return type of the function in the function prototype.
+*/
+#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
+# define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+# define KHRONOS_APICALL IMPORT_C
+#else
+# define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+* Definition of KHRONOS_APIENTRY
+*-------------------------------------------------------------------------
+* This follows the return type of the function and precedes the function
+* name in the function prototype.
+*/
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
+/* Win32 but not WinCE */
+# define KHRONOS_APIENTRY __stdcall
+#else
+# define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+* Definition of KHRONOS_APIATTRIBUTES
+*-------------------------------------------------------------------------
+* This follows the closing parenthesis of the function prototype arguments.
+*/
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+* basic type definitions
+*-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+* Using <stdint.h>
+*/
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+* Using <inttypes.h>
+*/
+#include <inttypes.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+* Win32
+*/
+typedef __int32 khronos_int32_t;
+typedef unsigned __int32 khronos_uint32_t;
+typedef __int64 khronos_int64_t;
+typedef unsigned __int64 khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+* Sun or Digital
+*/
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int khronos_int64_t;
+typedef unsigned long int khronos_uint64_t;
+#else
+typedef long long int khronos_int64_t;
+typedef unsigned long long int khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif 0
+
+/*
+* Hypothetical platform with no float or int64 support
+*/
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64 0
+#define KHRONOS_SUPPORT_FLOAT 0
+
+#else
+
+/*
+* Generic fallback
+*/
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#endif
+
+
+/*
+* Types that are (so far) the same on all platforms
+*/
+typedef signed char khronos_int8_t;
+typedef unsigned char khronos_uint8_t;
+typedef signed short int khronos_int16_t;
+typedef unsigned short int khronos_uint16_t;
+
+/*
+* Types that differ between LLP64 and LP64 architectures - in LLP64,
+* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
+* to be the only LLP64 architecture in current use.
+*/
+#ifdef _WIN64
+typedef signed long long int khronos_intptr_t;
+typedef unsigned long long int khronos_uintptr_t;
+typedef signed long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
+typedef signed long int khronos_intptr_t;
+typedef unsigned long int khronos_uintptr_t;
+typedef signed long int khronos_ssize_t;
+typedef unsigned long int khronos_usize_t;
+#endif
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+* Float type
+*/
+typedef float khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+*
+* These types can be used to represent a time interval in nanoseconds or
+* an absolute Unadjusted System Time. Unadjusted System Time is the number
+* of nanoseconds since some arbitrary system event (e.g. since the last
+* time the system booted). The Unadjusted System Time is an unsigned
+* 64 bit value that wraps back to 0 every 584 years. Time intervals
+* may be either signed or unsigned.
+*/
+typedef khronos_uint64_t khronos_utime_nanoseconds_t;
+typedef khronos_int64_t khronos_stime_nanoseconds_t;
+#endif
+
+/*
+* Dummy value used to pad enum types to 32 bits.
+*/
+#ifndef KHRONOS_MAX_ENUM
+#define KHRONOS_MAX_ENUM 0x7FFFFFFF
+#endif
+
+/*
+* Enumerated boolean type
+*
+* Values other than zero should be considered to be true. Therefore
+* comparisons should not be made against KHRONOS_TRUE.
+*/
+typedef enum {
+ KHRONOS_FALSE = 0,
+ KHRONOS_TRUE = 1,
+ KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
+} khronos_boolean_enum_t;
+
+#endif /* __khrplatform_h_ */
+
+
+#ifndef __eglplatform_h_
+#define __eglplatform_h_
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Platform-specific types and definitions for egl.h
+* $Revision: 12306 $ on $Date: 2010-08-25 09:51:28 -0700 (Wed, 25 Aug 2010) $
+*
+* Adopters may modify khrplatform.h and this file to suit their platform.
+* You are encouraged to submit all modifications to the Khronos group so that
+* they can be included in future versions of this file. Please submit changes
+* by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+* by filing a bug against product "EGL" component "Registry".
+*/
+
+/*#include <KHR/khrplatform.h>*/
+
+/* Macros used in EGL function prototype declarations.
+*
+* EGL functions should be prototyped as:
+*
+* EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
+* typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
+*
+* KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
+*/
+
+#ifndef EGLAPI
+#define EGLAPI KHRONOS_APICALL
+#endif
+
+#ifndef EGLAPIENTRY
+#define EGLAPIENTRY KHRONOS_APIENTRY
+#endif
+#define EGLAPIENTRYP EGLAPIENTRY*
+
+/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
+* are aliases of window-system-dependent types, such as X Display * or
+* Windows Device Context. They must be defined in platform-specific
+* code below. The EGL-prefixed versions of Native*Type are the same
+* types, renamed in EGL 1.3 so all types in the API start with "EGL".
+*
+* Khronos STRONGLY RECOMMENDS that you use the default definitions
+* provided below, since these changes affect both binary and source
+* portability of applications using EGL running on different EGL
+* implementations.
+*/
+
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+
+#if __WINRT__
+#include <Unknwn.h>
+typedef IUnknown * EGLNativeWindowType;
+typedef IUnknown * EGLNativePixmapType;
+typedef IUnknown * EGLNativeDisplayType;
+#else
+typedef HDC EGLNativeDisplayType;
+typedef HBITMAP EGLNativePixmapType;
+typedef HWND EGLNativeWindowType;
+#endif
+
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
+
+typedef int EGLNativeDisplayType;
+typedef void *EGLNativeWindowType;
+typedef void *EGLNativePixmapType;
+
+#elif defined(WL_EGL_PLATFORM)
+
+typedef struct wl_display *EGLNativeDisplayType;
+typedef struct wl_egl_pixmap *EGLNativePixmapType;
+typedef struct wl_egl_window *EGLNativeWindowType;
+
+#elif defined(__GBM__)
+
+typedef struct gbm_device *EGLNativeDisplayType;
+typedef struct gbm_bo *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
+#elif defined(__ANDROID__) /* Android */
+
+struct ANativeWindow;
+struct egl_native_pixmap_t;
+
+typedef struct ANativeWindow *EGLNativeWindowType;
+typedef struct egl_native_pixmap_t *EGLNativePixmapType;
+typedef void *EGLNativeDisplayType;
+
+#elif defined(MIR_EGL_PLATFORM)
+
+#include <mir_toolkit/mir_client_library.h>
+typedef MirEGLNativeDisplayType EGLNativeDisplayType;
+typedef void *EGLNativePixmapType;
+typedef MirEGLNativeWindowType EGLNativeWindowType;
+
+#elif defined(__unix__)
+
+#ifdef MESA_EGL_NO_X11_HEADERS
+
+typedef void *EGLNativeDisplayType;
+typedef khronos_uintptr_t EGLNativePixmapType;
+typedef khronos_uintptr_t EGLNativeWindowType;
+
+#else
+
+/* X11 (tentative) */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef Display *EGLNativeDisplayType;
+typedef Pixmap EGLNativePixmapType;
+typedef Window EGLNativeWindowType;
+
+#endif /* MESA_EGL_NO_X11_HEADERS */
+
+#else
+#error "Platform not recognized"
+#endif
+
+/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
+typedef EGLNativeDisplayType NativeDisplayType;
+typedef EGLNativePixmapType NativePixmapType;
+typedef EGLNativeWindowType NativeWindowType;
+
+
+/* Define EGLint. This must be a signed integral type large enough to contain
+* all legal attribute names and values passed into and out of EGL, whether
+* their type is boolean, bitmask, enumerant (symbolic constant), integer,
+* handle, or other. While in general a 32-bit integer will suffice, if
+* handles are 64 bit types, then EGLint should be defined as a signed 64-bit
+* integer type.
+*/
+typedef khronos_int32_t EGLint;
+
+#endif /* __eglplatform_h */
+
+#ifndef __egl_h_
+#define __egl_h_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2013-2015 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+/*
+** This header is generated from the Khronos OpenGL / OpenGL ES XML
+** API Registry. The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** http://www.opengl.org/registry/
+**
+** Khronos $Revision: 31566 $ on $Date: 2015-06-23 08:48:48 -0700 (Tue, 23 Jun 2015) $
+*/
+
+/*#include <EGL/eglplatform.h>*/
+
+/* Generated on date 20150623 */
+
+/* Generated C header for:
+ * API: egl
+ * Versions considered: .*
+ * Versions emitted: .*
+ * Default extensions included: None
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef EGL_VERSION_1_0
+#define EGL_VERSION_1_0 1
+typedef unsigned int EGLBoolean;
+typedef void *EGLDisplay;
+typedef void *EGLConfig;
+typedef void *EGLSurface;
+typedef void *EGLContext;
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BAD_ACCESS 0x3002
+#define EGL_BAD_ALLOC 0x3003
+#define EGL_BAD_ATTRIBUTE 0x3004
+#define EGL_BAD_CONFIG 0x3005
+#define EGL_BAD_CONTEXT 0x3006
+#define EGL_BAD_CURRENT_SURFACE 0x3007
+#define EGL_BAD_DISPLAY 0x3008
+#define EGL_BAD_MATCH 0x3009
+#define EGL_BAD_NATIVE_PIXMAP 0x300A
+#define EGL_BAD_NATIVE_WINDOW 0x300B
+#define EGL_BAD_PARAMETER 0x300C
+#define EGL_BAD_SURFACE 0x300D
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_BUFFER_SIZE 0x3020
+#define EGL_CONFIG_CAVEAT 0x3027
+#define EGL_CONFIG_ID 0x3028
+#define EGL_CORE_NATIVE_ENGINE 0x305B
+#define EGL_DEPTH_SIZE 0x3025
+#define EGL_DONT_CARE ((EGLint)-1)
+#define EGL_DRAW 0x3059
+#define EGL_EXTENSIONS 0x3055
+#define EGL_FALSE 0
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_HEIGHT 0x3056
+#define EGL_LARGEST_PBUFFER 0x3058
+#define EGL_LEVEL 0x3029
+#define EGL_MAX_PBUFFER_HEIGHT 0x302A
+#define EGL_MAX_PBUFFER_PIXELS 0x302B
+#define EGL_MAX_PBUFFER_WIDTH 0x302C
+#define EGL_NATIVE_RENDERABLE 0x302D
+#define EGL_NATIVE_VISUAL_ID 0x302E
+#define EGL_NATIVE_VISUAL_TYPE 0x302F
+#define EGL_NONE 0x3038
+#define EGL_NON_CONFORMANT_CONFIG 0x3051
+#define EGL_NOT_INITIALIZED 0x3001
+#define EGL_NO_CONTEXT ((EGLContext)0)
+#define EGL_NO_DISPLAY ((EGLDisplay)0)
+#define EGL_NO_SURFACE ((EGLSurface)0)
+#define EGL_PBUFFER_BIT 0x0001
+#define EGL_PIXMAP_BIT 0x0002
+#define EGL_READ 0x305A
+#define EGL_RED_SIZE 0x3024
+#define EGL_SAMPLES 0x3031
+#define EGL_SAMPLE_BUFFERS 0x3032
+#define EGL_SLOW_CONFIG 0x3050
+#define EGL_STENCIL_SIZE 0x3026
+#define EGL_SUCCESS 0x3000
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
+#define EGL_TRANSPARENT_RED_VALUE 0x3037
+#define EGL_TRANSPARENT_RGB 0x3052
+#define EGL_TRANSPARENT_TYPE 0x3034
+#define EGL_TRUE 1
+#define EGL_VENDOR 0x3053
+#define EGL_VERSION 0x3054
+#define EGL_WIDTH 0x3057
+#define EGL_WINDOW_BIT 0x0004
+EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
+EGLAPI EGLContext EGLAPIENTRY eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext (EGLDisplay dpy, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface (EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay (void);
+EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface (EGLint readdraw);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay (EGLNativeDisplayType display_id);
+EGLAPI EGLint EGLAPIENTRY eglGetError (void);
+EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress (const char *procname);
+EGLAPI EGLBoolean EGLAPIENTRY eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
+EGLAPI const char *EGLAPIENTRY eglQueryString (EGLDisplay dpy, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers (EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglTerminate (EGLDisplay dpy);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL (void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative (EGLint engine);
+#endif /* EGL_VERSION_1_0 */
+
+#ifndef EGL_VERSION_1_1
+#define EGL_VERSION_1_1 1
+#define EGL_BACK_BUFFER 0x3084
+#define EGL_BIND_TO_TEXTURE_RGB 0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
+#define EGL_CONTEXT_LOST 0x300E
+#define EGL_MIN_SWAP_INTERVAL 0x303B
+#define EGL_MAX_SWAP_INTERVAL 0x303C
+#define EGL_MIPMAP_TEXTURE 0x3082
+#define EGL_MIPMAP_LEVEL 0x3083
+#define EGL_NO_TEXTURE 0x305C
+#define EGL_TEXTURE_2D 0x305F
+#define EGL_TEXTURE_FORMAT 0x3080
+#define EGL_TEXTURE_RGB 0x305D
+#define EGL_TEXTURE_RGBA 0x305E
+#define EGL_TEXTURE_TARGET 0x3081
+EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval (EGLDisplay dpy, EGLint interval);
+#endif /* EGL_VERSION_1_1 */
+
+#ifndef EGL_VERSION_1_2
+#define EGL_VERSION_1_2 1
+typedef unsigned int EGLenum;
+typedef void *EGLClientBuffer;
+#define EGL_ALPHA_FORMAT 0x3088
+#define EGL_ALPHA_FORMAT_NONPRE 0x308B
+#define EGL_ALPHA_FORMAT_PRE 0x308C
+#define EGL_ALPHA_MASK_SIZE 0x303E
+#define EGL_BUFFER_PRESERVED 0x3094
+#define EGL_BUFFER_DESTROYED 0x3095
+#define EGL_CLIENT_APIS 0x308D
+#define EGL_COLORSPACE 0x3087
+#define EGL_COLORSPACE_sRGB 0x3089
+#define EGL_COLORSPACE_LINEAR 0x308A
+#define EGL_COLOR_BUFFER_TYPE 0x303F
+#define EGL_CONTEXT_CLIENT_TYPE 0x3097
+#define EGL_DISPLAY_SCALING 10000
+#define EGL_HORIZONTAL_RESOLUTION 0x3090
+#define EGL_LUMINANCE_BUFFER 0x308F
+#define EGL_LUMINANCE_SIZE 0x303D
+#define EGL_OPENGL_ES_BIT 0x0001
+#define EGL_OPENVG_BIT 0x0002
+#define EGL_OPENGL_ES_API 0x30A0
+#define EGL_OPENVG_API 0x30A1
+#define EGL_OPENVG_IMAGE 0x3096
+#define EGL_PIXEL_ASPECT_RATIO 0x3092
+#define EGL_RENDERABLE_TYPE 0x3040
+#define EGL_RENDER_BUFFER 0x3086
+#define EGL_RGB_BUFFER 0x308E
+#define EGL_SINGLE_BUFFER 0x3085
+#define EGL_SWAP_BEHAVIOR 0x3093
+#define EGL_UNKNOWN ((EGLint)-1)
+#define EGL_VERTICAL_RESOLUTION 0x3091
+EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI (EGLenum api);
+EGLAPI EGLenum EGLAPIENTRY eglQueryAPI (void);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread (void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient (void);
+#endif /* EGL_VERSION_1_2 */
+
+#ifndef EGL_VERSION_1_3
+#define EGL_VERSION_1_3 1
+#define EGL_CONFORMANT 0x3042
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+#define EGL_MATCH_NATIVE_PIXMAP 0x3041
+#define EGL_OPENGL_ES2_BIT 0x0004
+#define EGL_VG_ALPHA_FORMAT 0x3088
+#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B
+#define EGL_VG_ALPHA_FORMAT_PRE 0x308C
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040
+#define EGL_VG_COLORSPACE 0x3087
+#define EGL_VG_COLORSPACE_sRGB 0x3089
+#define EGL_VG_COLORSPACE_LINEAR 0x308A
+#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020
+#endif /* EGL_VERSION_1_3 */
+
+#ifndef EGL_VERSION_1_4
+#define EGL_VERSION_1_4 1
+#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
+#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
+#define EGL_MULTISAMPLE_RESOLVE 0x3099
+#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A
+#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B
+#define EGL_OPENGL_API 0x30A2
+#define EGL_OPENGL_BIT 0x0008
+#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
+EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void);
+#endif /* EGL_VERSION_1_4 */
+
+#ifndef EGL_VERSION_1_5
+#define EGL_VERSION_1_5 1
+typedef void *EGLSync;
+typedef intptr_t EGLAttrib;
+typedef khronos_utime_nanoseconds_t EGLTime;
+typedef void *EGLImage;
+#define EGL_CONTEXT_MAJOR_VERSION 0x3098
+#define EGL_CONTEXT_MINOR_VERSION 0x30FB
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
+#define EGL_NO_RESET_NOTIFICATION 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
+#define EGL_OPENGL_ES3_BIT 0x00000040
+#define EGL_CL_EVENT_HANDLE 0x309C
+#define EGL_SYNC_CL_EVENT 0x30FE
+#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0
+#define EGL_SYNC_TYPE 0x30F7
+#define EGL_SYNC_STATUS 0x30F1
+#define EGL_SYNC_CONDITION 0x30F8
+#define EGL_SIGNALED 0x30F2
+#define EGL_UNSIGNALED 0x30F3
+#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001
+#define EGL_FOREVER 0xFFFFFFFFFFFFFFFFull
+#define EGL_TIMEOUT_EXPIRED 0x30F5
+#define EGL_CONDITION_SATISFIED 0x30F6
+#define EGL_NO_SYNC ((EGLSync)0)
+#define EGL_SYNC_FENCE 0x30F9
+#define EGL_GL_COLORSPACE 0x309D
+#define EGL_GL_COLORSPACE_SRGB 0x3089
+#define EGL_GL_COLORSPACE_LINEAR 0x308A
+#define EGL_GL_RENDERBUFFER 0x30B9
+#define EGL_GL_TEXTURE_2D 0x30B1
+#define EGL_GL_TEXTURE_LEVEL 0x30BC
+#define EGL_GL_TEXTURE_3D 0x30B2
+#define EGL_GL_TEXTURE_ZOFFSET 0x30BD
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
+#define EGL_IMAGE_PRESERVED 0x30D2
+#define EGL_NO_IMAGE ((EGLImage)0)
+EGLAPI EGLSync EGLAPIENTRY eglCreateSync (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySync (EGLDisplay dpy, EGLSync sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttrib (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
+EGLAPI EGLImage EGLAPIENTRY eglCreateImage (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImage (EGLDisplay dpy, EGLImage image);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplay (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurface (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags);
+#endif /* EGL_VERSION_1_5 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __egl_h_ */
+
+
+
+#ifndef __eglext_h_
+#define __eglext_h_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2013-2015 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+/*
+** This header is generated from the Khronos OpenGL / OpenGL ES XML
+** API Registry. The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** http://www.opengl.org/registry/
+**
+** Khronos $Revision: 31566 $ on $Date: 2015-06-23 08:48:48 -0700 (Tue, 23 Jun 2015) $
+*/
+
+/*#include <EGL/eglplatform.h>*/
+
+#define EGL_EGLEXT_VERSION 20150623
+
+/* Generated C header for:
+ * API: egl
+ * Versions considered: .*
+ * Versions emitted: _nomatch_^
+ * Default extensions included: egl
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef EGL_KHR_cl_event
+#define EGL_KHR_cl_event 1
+#define EGL_CL_EVENT_HANDLE_KHR 0x309C
+#define EGL_SYNC_CL_EVENT_KHR 0x30FE
+#define EGL_SYNC_CL_EVENT_COMPLETE_KHR 0x30FF
+#endif /* EGL_KHR_cl_event */
+
+#ifndef EGL_KHR_cl_event2
+#define EGL_KHR_cl_event2 1
+typedef void *EGLSyncKHR;
+typedef intptr_t EGLAttribKHR;
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNC64KHRPROC) (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSync64KHR (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
+#endif
+#endif /* EGL_KHR_cl_event2 */
+
+#ifndef EGL_KHR_client_get_all_proc_addresses
+#define EGL_KHR_client_get_all_proc_addresses 1
+#endif /* EGL_KHR_client_get_all_proc_addresses */
+
+#ifndef EGL_KHR_config_attribs
+#define EGL_KHR_config_attribs 1
+#define EGL_CONFORMANT_KHR 0x3042
+#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040
+#endif /* EGL_KHR_config_attribs */
+
+#ifndef EGL_KHR_create_context
+#define EGL_KHR_create_context 1
+#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
+#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
+#define EGL_CONTEXT_FLAGS_KHR 0x30FC
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD
+#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF
+#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
+#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
+#endif /* EGL_KHR_create_context */
+
+#ifndef EGL_KHR_create_context_no_error
+#define EGL_KHR_create_context_no_error 1
+#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3
+#endif /* EGL_KHR_create_context_no_error */
+
+#ifndef EGL_KHR_fence_sync
+#define EGL_KHR_fence_sync 1
+typedef khronos_utime_nanoseconds_t EGLTimeKHR;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0
+#define EGL_SYNC_CONDITION_KHR 0x30F8
+#define EGL_SYNC_FENCE_KHR 0x30F9
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR (EGLDisplay dpy, EGLSyncKHR sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_fence_sync */
+
+#ifndef EGL_KHR_get_all_proc_addresses
+#define EGL_KHR_get_all_proc_addresses 1
+#endif /* EGL_KHR_get_all_proc_addresses */
+
+#ifndef EGL_KHR_gl_colorspace
+#define EGL_KHR_gl_colorspace 1
+#define EGL_GL_COLORSPACE_KHR 0x309D
+#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
+#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A
+#endif /* EGL_KHR_gl_colorspace */
+
+#ifndef EGL_KHR_gl_renderbuffer_image
+#define EGL_KHR_gl_renderbuffer_image 1
+#define EGL_GL_RENDERBUFFER_KHR 0x30B9
+#endif /* EGL_KHR_gl_renderbuffer_image */
+
+#ifndef EGL_KHR_gl_texture_2D_image
+#define EGL_KHR_gl_texture_2D_image 1
+#define EGL_GL_TEXTURE_2D_KHR 0x30B1
+#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC
+#endif /* EGL_KHR_gl_texture_2D_image */
+
+#ifndef EGL_KHR_gl_texture_3D_image
+#define EGL_KHR_gl_texture_3D_image 1
+#define EGL_GL_TEXTURE_3D_KHR 0x30B2
+#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD
+#endif /* EGL_KHR_gl_texture_3D_image */
+
+#ifndef EGL_KHR_gl_texture_cubemap_image
+#define EGL_KHR_gl_texture_cubemap_image 1
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8
+#endif /* EGL_KHR_gl_texture_cubemap_image */
+
+#ifndef EGL_KHR_image
+#define EGL_KHR_image 1
+typedef void *EGLImageKHR;
+#define EGL_NATIVE_PIXMAP_KHR 0x30B0
+#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0)
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
+#endif
+#endif /* EGL_KHR_image */
+
+#ifndef EGL_KHR_image_base
+#define EGL_KHR_image_base 1
+#define EGL_IMAGE_PRESERVED_KHR 0x30D2
+#endif /* EGL_KHR_image_base */
+
+#ifndef EGL_KHR_image_pixmap
+#define EGL_KHR_image_pixmap 1
+#endif /* EGL_KHR_image_pixmap */
+
+#ifndef EGL_KHR_lock_surface
+#define EGL_KHR_lock_surface 1
+#define EGL_READ_SURFACE_BIT_KHR 0x0001
+#define EGL_WRITE_SURFACE_BIT_KHR 0x0002
+#define EGL_LOCK_SURFACE_BIT_KHR 0x0080
+#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100
+#define EGL_MATCH_FORMAT_KHR 0x3043
+#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0
+#define EGL_FORMAT_RGB_565_KHR 0x30C1
+#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2
+#define EGL_FORMAT_RGBA_8888_KHR 0x30C3
+#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4
+#define EGL_LOCK_USAGE_HINT_KHR 0x30C5
+#define EGL_BITMAP_POINTER_KHR 0x30C6
+#define EGL_BITMAP_PITCH_KHR 0x30C7
+#define EGL_BITMAP_ORIGIN_KHR 0x30C8
+#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9
+#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA
+#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB
+#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC
+#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD
+#define EGL_LOWER_LEFT_KHR 0x30CE
+#define EGL_UPPER_LEFT_KHR 0x30CF
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay dpy, EGLSurface surface);
+#endif
+#endif /* EGL_KHR_lock_surface */
+
+#ifndef EGL_KHR_lock_surface2
+#define EGL_KHR_lock_surface2 1
+#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110
+#endif /* EGL_KHR_lock_surface2 */
+
+#ifndef EGL_KHR_lock_surface3
+#define EGL_KHR_lock_surface3 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACE64KHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface64KHR (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
+#endif
+#endif /* EGL_KHR_lock_surface3 */
+
+#ifndef EGL_KHR_partial_update
+#define EGL_KHR_partial_update 1
+#define EGL_BUFFER_AGE_KHR 0x313D
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETDAMAGEREGIONKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSetDamageRegionKHR (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_KHR_partial_update */
+
+#ifndef EGL_KHR_platform_android
+#define EGL_KHR_platform_android 1
+#define EGL_PLATFORM_ANDROID_KHR 0x3141
+#endif /* EGL_KHR_platform_android */
+
+#ifndef EGL_KHR_platform_gbm
+#define EGL_KHR_platform_gbm 1
+#define EGL_PLATFORM_GBM_KHR 0x31D7
+#endif /* EGL_KHR_platform_gbm */
+
+#ifndef EGL_KHR_platform_wayland
+#define EGL_KHR_platform_wayland 1
+#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
+#endif /* EGL_KHR_platform_wayland */
+
+#ifndef EGL_KHR_platform_x11
+#define EGL_KHR_platform_x11 1
+#define EGL_PLATFORM_X11_KHR 0x31D5
+#define EGL_PLATFORM_X11_SCREEN_KHR 0x31D6
+#endif /* EGL_KHR_platform_x11 */
+
+#ifndef EGL_KHR_reusable_sync
+#define EGL_KHR_reusable_sync 1
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_STATUS_KHR 0x30F1
+#define EGL_SIGNALED_KHR 0x30F2
+#define EGL_UNSIGNALED_KHR 0x30F3
+#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5
+#define EGL_CONDITION_SATISFIED_KHR 0x30F6
+#define EGL_SYNC_TYPE_KHR 0x30F7
+#define EGL_SYNC_REUSABLE_KHR 0x30FA
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001
+#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull
+#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0)
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_reusable_sync */
+
+#ifndef EGL_KHR_stream
+#define EGL_KHR_stream 1
+typedef void *EGLStreamKHR;
+typedef khronos_uint64_t EGLuint64KHR;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_NO_STREAM_KHR ((EGLStreamKHR)0)
+#define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210
+#define EGL_PRODUCER_FRAME_KHR 0x3212
+#define EGL_CONSUMER_FRAME_KHR 0x3213
+#define EGL_STREAM_STATE_KHR 0x3214
+#define EGL_STREAM_STATE_CREATED_KHR 0x3215
+#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216
+#define EGL_STREAM_STATE_EMPTY_KHR 0x3217
+#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218
+#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219
+#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A
+#define EGL_BAD_STREAM_KHR 0x321B
+#define EGL_BAD_STATE_KHR 0x321C
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMKHRPROC) (EGLDisplay dpy, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMU64KHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamKHR (EGLDisplay dpy, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyStreamKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_stream */
+
+#ifndef EGL_KHR_stream_consumer_gltexture
+#define EGL_KHR_stream_consumer_gltexture 1
+#ifdef EGL_KHR_stream
+#define EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseKHR (EGLDisplay dpy, EGLStreamKHR stream);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_consumer_gltexture */
+
+#ifndef EGL_KHR_stream_cross_process_fd
+#define EGL_KHR_stream_cross_process_fd 1
+typedef int EGLNativeFileDescriptorKHR;
+#ifdef EGL_KHR_stream
+#define EGL_NO_FILE_DESCRIPTOR_KHR ((EGLNativeFileDescriptorKHR)(-1))
+typedef EGLNativeFileDescriptorKHR (EGLAPIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLNativeFileDescriptorKHR EGLAPIENTRY eglGetStreamFileDescriptorKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamFromFileDescriptorKHR (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_cross_process_fd */
+
+#ifndef EGL_KHR_stream_fifo
+#define EGL_KHR_stream_fifo 1
+#ifdef EGL_KHR_stream
+#define EGL_STREAM_FIFO_LENGTH_KHR 0x31FC
+#define EGL_STREAM_TIME_NOW_KHR 0x31FD
+#define EGL_STREAM_TIME_CONSUMER_KHR 0x31FE
+#define EGL_STREAM_TIME_PRODUCER_KHR 0x31FF
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMTIMEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamTimeKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_fifo */
+
+#ifndef EGL_KHR_stream_producer_aldatalocator
+#define EGL_KHR_stream_producer_aldatalocator 1
+#ifdef EGL_KHR_stream
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_producer_aldatalocator */
+
+#ifndef EGL_KHR_stream_producer_eglsurface
+#define EGL_KHR_stream_producer_eglsurface 1
+#ifdef EGL_KHR_stream
+#define EGL_STREAM_BIT_KHR 0x0800
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC) (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSurface EGLAPIENTRY eglCreateStreamProducerSurfaceKHR (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_producer_eglsurface */
+
+#ifndef EGL_KHR_surfaceless_context
+#define EGL_KHR_surfaceless_context 1
+#endif /* EGL_KHR_surfaceless_context */
+
+#ifndef EGL_KHR_swap_buffers_with_damage
+#define EGL_KHR_swap_buffers_with_damage 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageKHR (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_KHR_swap_buffers_with_damage */
+
+#ifndef EGL_KHR_vg_parent_image
+#define EGL_KHR_vg_parent_image 1
+#define EGL_VG_PARENT_IMAGE_KHR 0x30BA
+#endif /* EGL_KHR_vg_parent_image */
+
+#ifndef EGL_KHR_wait_sync
+#define EGL_KHR_wait_sync 1
+typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#endif
+#endif /* EGL_KHR_wait_sync */
+
+#ifndef EGL_ANDROID_blob_cache
+#define EGL_ANDROID_blob_cache 1
+typedef khronos_ssize_t EGLsizeiANDROID;
+typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);
+typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);
+typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC) (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+#endif
+#endif /* EGL_ANDROID_blob_cache */
+
+#ifndef EGL_ANDROID_framebuffer_target
+#define EGL_ANDROID_framebuffer_target 1
+#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147
+#endif /* EGL_ANDROID_framebuffer_target */
+
+#ifndef EGL_ANDROID_image_native_buffer
+#define EGL_ANDROID_image_native_buffer 1
+#define EGL_NATIVE_BUFFER_ANDROID 0x3140
+#endif /* EGL_ANDROID_image_native_buffer */
+
+#ifndef EGL_ANDROID_native_fence_sync
+#define EGL_ANDROID_native_fence_sync 1
+#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144
+#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145
+#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146
+#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1
+typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID (EGLDisplay dpy, EGLSyncKHR sync);
+#endif
+#endif /* EGL_ANDROID_native_fence_sync */
+
+#ifndef EGL_ANDROID_recordable
+#define EGL_ANDROID_recordable 1
+#define EGL_RECORDABLE_ANDROID 0x3142
+#endif /* EGL_ANDROID_recordable */
+
+#ifndef EGL_ANGLE_d3d_share_handle_client_buffer
+#define EGL_ANGLE_d3d_share_handle_client_buffer 1
+#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
+#endif /* EGL_ANGLE_d3d_share_handle_client_buffer */
+
+#ifndef EGL_ANGLE_device_d3d
+#define EGL_ANGLE_device_d3d 1
+#define EGL_D3D9_DEVICE_ANGLE 0x33A0
+#define EGL_D3D11_DEVICE_ANGLE 0x33A1
+#endif /* EGL_ANGLE_device_d3d */
+
+#ifndef EGL_ANGLE_query_surface_pointer
+#define EGL_ANGLE_query_surface_pointer 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#endif
+#endif /* EGL_ANGLE_query_surface_pointer */
+
+#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle
+#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1
+#endif /* EGL_ANGLE_surface_d3d_texture_2d_share_handle */
+
+#ifndef EGL_ANGLE_window_fixed_size
+#define EGL_ANGLE_window_fixed_size 1
+#define EGL_FIXED_SIZE_ANGLE 0x3201
+#endif /* EGL_ANGLE_window_fixed_size */
+
+#ifndef EGL_ARM_pixmap_multisample_discard
+#define EGL_ARM_pixmap_multisample_discard 1
+#define EGL_DISCARD_SAMPLES_ARM 0x3286
+#endif /* EGL_ARM_pixmap_multisample_discard */
+
+#ifndef EGL_EXT_buffer_age
+#define EGL_EXT_buffer_age 1
+#define EGL_BUFFER_AGE_EXT 0x313D
+#endif /* EGL_EXT_buffer_age */
+
+#ifndef EGL_EXT_client_extensions
+#define EGL_EXT_client_extensions 1
+#endif /* EGL_EXT_client_extensions */
+
+#ifndef EGL_EXT_create_context_robustness
+#define EGL_EXT_create_context_robustness 1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
+#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF
+#endif /* EGL_EXT_create_context_robustness */
+
+#ifndef EGL_EXT_device_base
+#define EGL_EXT_device_base 1
+typedef void *EGLDeviceEXT;
+#define EGL_NO_DEVICE_EXT ((EGLDeviceEXT)(0))
+#define EGL_BAD_DEVICE_EXT 0x322B
+#define EGL_DEVICE_EXT 0x322C
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICEATTRIBEXTPROC) (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYDEVICESTRINGEXTPROC) (EGLDeviceEXT device, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICESEXTPROC) (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBEXTPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDeviceAttribEXT (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryDeviceStringEXT (EGLDeviceEXT device, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDevicesEXT (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribEXT (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#endif
+#endif /* EGL_EXT_device_base */
+
+#ifndef EGL_EXT_device_drm
+#define EGL_EXT_device_drm 1
+#define EGL_DRM_DEVICE_FILE_EXT 0x3233
+#endif /* EGL_EXT_device_drm */
+
+#ifndef EGL_EXT_device_enumeration
+#define EGL_EXT_device_enumeration 1
+#endif /* EGL_EXT_device_enumeration */
+
+#ifndef EGL_EXT_device_openwf
+#define EGL_EXT_device_openwf 1
+#define EGL_OPENWF_DEVICE_ID_EXT 0x3237
+#endif /* EGL_EXT_device_openwf */
+
+#ifndef EGL_EXT_device_query
+#define EGL_EXT_device_query 1
+#endif /* EGL_EXT_device_query */
+
+#ifndef EGL_EXT_image_dma_buf_import
+#define EGL_EXT_image_dma_buf_import 1
+#define EGL_LINUX_DMA_BUF_EXT 0x3270
+#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
+#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
+#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
+#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
+#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
+#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
+#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
+#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
+#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
+#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
+#define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B
+#define EGL_SAMPLE_RANGE_HINT_EXT 0x327C
+#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D
+#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E
+#define EGL_ITU_REC601_EXT 0x327F
+#define EGL_ITU_REC709_EXT 0x3280
+#define EGL_ITU_REC2020_EXT 0x3281
+#define EGL_YUV_FULL_RANGE_EXT 0x3282
+#define EGL_YUV_NARROW_RANGE_EXT 0x3283
+#define EGL_YUV_CHROMA_SITING_0_EXT 0x3284
+#define EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285
+#endif /* EGL_EXT_image_dma_buf_import */
+
+#ifndef EGL_EXT_multiview_window
+#define EGL_EXT_multiview_window 1
+#define EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134
+#endif /* EGL_EXT_multiview_window */
+
+#ifndef EGL_EXT_output_base
+#define EGL_EXT_output_base 1
+typedef void *EGLOutputLayerEXT;
+typedef void *EGLOutputPortEXT;
+#define EGL_NO_OUTPUT_LAYER_EXT ((EGLOutputLayerEXT)0)
+#define EGL_NO_OUTPUT_PORT_EXT ((EGLOutputPortEXT)0)
+#define EGL_BAD_OUTPUT_LAYER_EXT 0x322D
+#define EGL_BAD_OUTPUT_PORT_EXT 0x322E
+#define EGL_SWAP_INTERVAL_EXT 0x322F
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETOUTPUTLAYERSEXTPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputLayerEXT *layers, EGLint max_layers, EGLint *num_layers);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETOUTPUTPORTSEXTPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputPortEXT *ports, EGLint max_ports, EGLint *num_ports);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLOUTPUTPORTATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint name);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglGetOutputLayersEXT (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputLayerEXT *layers, EGLint max_layers, EGLint *num_layers);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetOutputPortsEXT (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputPortEXT *ports, EGLint max_ports, EGLint *num_ports);
+EGLAPI EGLBoolean EGLAPIENTRY eglOutputLayerAttribEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryOutputLayerAttribEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryOutputLayerStringEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglOutputPortAttribEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryOutputPortAttribEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryOutputPortStringEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint name);
+#endif
+#endif /* EGL_EXT_output_base */
+
+#ifndef EGL_EXT_output_drm
+#define EGL_EXT_output_drm 1
+#define EGL_DRM_CRTC_EXT 0x3234
+#define EGL_DRM_PLANE_EXT 0x3235
+#define EGL_DRM_CONNECTOR_EXT 0x3236
+#endif /* EGL_EXT_output_drm */
+
+#ifndef EGL_EXT_output_openwf
+#define EGL_EXT_output_openwf 1
+#define EGL_OPENWF_PIPELINE_ID_EXT 0x3238
+#define EGL_OPENWF_PORT_ID_EXT 0x3239
+#endif /* EGL_EXT_output_openwf */
+
+#ifndef EGL_EXT_platform_base
+#define EGL_EXT_platform_base 1
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT (EGLenum platform, void *native_display, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
+#endif
+#endif /* EGL_EXT_platform_base */
+
+#ifndef EGL_EXT_platform_device
+#define EGL_EXT_platform_device 1
+#define EGL_PLATFORM_DEVICE_EXT 0x313F
+#endif /* EGL_EXT_platform_device */
+
+#ifndef EGL_EXT_platform_wayland
+#define EGL_EXT_platform_wayland 1
+#define EGL_PLATFORM_WAYLAND_EXT 0x31D8
+#endif /* EGL_EXT_platform_wayland */
+
+#ifndef EGL_EXT_platform_x11
+#define EGL_EXT_platform_x11 1
+#define EGL_PLATFORM_X11_EXT 0x31D5
+#define EGL_PLATFORM_X11_SCREEN_EXT 0x31D6
+#endif /* EGL_EXT_platform_x11 */
+
+#ifndef EGL_EXT_protected_surface
+#define EGL_EXT_protected_surface 1
+#define EGL_PROTECTED_CONTENT_EXT 0x32C0
+#endif /* EGL_EXT_protected_surface */
+
+#ifndef EGL_EXT_stream_consumer_egloutput
+#define EGL_EXT_stream_consumer_egloutput 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMEROUTPUTEXTPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerOutputEXT (EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer);
+#endif
+#endif /* EGL_EXT_stream_consumer_egloutput */
+
+#ifndef EGL_EXT_swap_buffers_with_damage
+#define EGL_EXT_swap_buffers_with_damage 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageEXT (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_EXT_swap_buffers_with_damage */
+
+#ifndef EGL_EXT_yuv_surface
+#define EGL_EXT_yuv_surface 1
+#define EGL_YUV_ORDER_EXT 0x3301
+#define EGL_YUV_NUMBER_OF_PLANES_EXT 0x3311
+#define EGL_YUV_SUBSAMPLE_EXT 0x3312
+#define EGL_YUV_DEPTH_RANGE_EXT 0x3317
+#define EGL_YUV_CSC_STANDARD_EXT 0x330A
+#define EGL_YUV_PLANE_BPP_EXT 0x331A
+#define EGL_YUV_BUFFER_EXT 0x3300
+#define EGL_YUV_ORDER_YUV_EXT 0x3302
+#define EGL_YUV_ORDER_YVU_EXT 0x3303
+#define EGL_YUV_ORDER_YUYV_EXT 0x3304
+#define EGL_YUV_ORDER_UYVY_EXT 0x3305
+#define EGL_YUV_ORDER_YVYU_EXT 0x3306
+#define EGL_YUV_ORDER_VYUY_EXT 0x3307
+#define EGL_YUV_ORDER_AYUV_EXT 0x3308
+#define EGL_YUV_SUBSAMPLE_4_2_0_EXT 0x3313
+#define EGL_YUV_SUBSAMPLE_4_2_2_EXT 0x3314
+#define EGL_YUV_SUBSAMPLE_4_4_4_EXT 0x3315
+#define EGL_YUV_DEPTH_RANGE_LIMITED_EXT 0x3318
+#define EGL_YUV_DEPTH_RANGE_FULL_EXT 0x3319
+#define EGL_YUV_CSC_STANDARD_601_EXT 0x330B
+#define EGL_YUV_CSC_STANDARD_709_EXT 0x330C
+#define EGL_YUV_CSC_STANDARD_2020_EXT 0x330D
+#define EGL_YUV_PLANE_BPP_0_EXT 0x331B
+#define EGL_YUV_PLANE_BPP_8_EXT 0x331C
+#define EGL_YUV_PLANE_BPP_10_EXT 0x331D
+#endif /* EGL_EXT_yuv_surface */
+
+#ifndef EGL_HI_clientpixmap
+#define EGL_HI_clientpixmap 1
+struct EGLClientPixmapHI {
+ void *pData;
+ EGLint iWidth;
+ EGLint iHeight;
+ EGLint iStride;
+};
+#define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
+#endif
+#endif /* EGL_HI_clientpixmap */
+
+#ifndef EGL_HI_colorformats
+#define EGL_HI_colorformats 1
+#define EGL_COLOR_FORMAT_HI 0x8F70
+#define EGL_COLOR_RGB_HI 0x8F71
+#define EGL_COLOR_RGBA_HI 0x8F72
+#define EGL_COLOR_ARGB_HI 0x8F73
+#endif /* EGL_HI_colorformats */
+
+#ifndef EGL_IMG_context_priority
+#define EGL_IMG_context_priority 1
+#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100
+#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101
+#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102
+#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
+#endif /* EGL_IMG_context_priority */
+
+#ifndef EGL_MESA_drm_image
+#define EGL_MESA_drm_image 1
+#define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0
+#define EGL_DRM_BUFFER_USE_MESA 0x31D1
+#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2
+#define EGL_DRM_BUFFER_MESA 0x31D3
+#define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4
+#define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001
+#define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateDRMImageMESA (EGLDisplay dpy, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDRMImageMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#endif
+#endif /* EGL_MESA_drm_image */
+
+#ifndef EGL_MESA_image_dma_buf_export
+#define EGL_MESA_image_dma_buf_export 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC) (EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, EGLuint64KHR *modifiers);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDMABUFIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, int *fds, EGLint *strides, EGLint *offsets);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageQueryMESA (EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, EGLuint64KHR *modifiers);
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageMESA (EGLDisplay dpy, EGLImageKHR image, int *fds, EGLint *strides, EGLint *offsets);
+#endif
+#endif /* EGL_MESA_image_dma_buf_export */
+
+#ifndef EGL_MESA_platform_gbm
+#define EGL_MESA_platform_gbm 1
+#define EGL_PLATFORM_GBM_MESA 0x31D7
+#endif /* EGL_MESA_platform_gbm */
+
+#ifndef EGL_NOK_swap_region
+#define EGL_NOK_swap_region 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGIONNOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegionNOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#endif
+#endif /* EGL_NOK_swap_region */
+
+#ifndef EGL_NOK_swap_region2
+#define EGL_NOK_swap_region2 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGION2NOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegion2NOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#endif
+#endif /* EGL_NOK_swap_region2 */
+
+#ifndef EGL_NOK_texture_from_pixmap
+#define EGL_NOK_texture_from_pixmap 1
+#define EGL_Y_INVERTED_NOK 0x307F
+#endif /* EGL_NOK_texture_from_pixmap */
+
+#ifndef EGL_NV_3dvision_surface
+#define EGL_NV_3dvision_surface 1
+#define EGL_AUTO_STEREO_NV 0x3136
+#endif /* EGL_NV_3dvision_surface */
+
+#ifndef EGL_NV_coverage_sample
+#define EGL_NV_coverage_sample 1
+#define EGL_COVERAGE_BUFFERS_NV 0x30E0
+#define EGL_COVERAGE_SAMPLES_NV 0x30E1
+#endif /* EGL_NV_coverage_sample */
+
+#ifndef EGL_NV_coverage_sample_resolve
+#define EGL_NV_coverage_sample_resolve 1
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131
+#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133
+#endif /* EGL_NV_coverage_sample_resolve */
+
+#ifndef EGL_NV_cuda_event
+#define EGL_NV_cuda_event 1
+#define EGL_CUDA_EVENT_HANDLE_NV 0x323B
+#define EGL_SYNC_CUDA_EVENT_NV 0x323C
+#define EGL_SYNC_CUDA_EVENT_COMPLETE_NV 0x323D
+#endif /* EGL_NV_cuda_event */
+
+#ifndef EGL_NV_depth_nonlinear
+#define EGL_NV_depth_nonlinear 1
+#define EGL_DEPTH_ENCODING_NV 0x30E2
+#define EGL_DEPTH_ENCODING_NONE_NV 0
+#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3
+#endif /* EGL_NV_depth_nonlinear */
+
+#ifndef EGL_NV_device_cuda
+#define EGL_NV_device_cuda 1
+#define EGL_CUDA_DEVICE_NV 0x323A
+#endif /* EGL_NV_device_cuda */
+
+#ifndef EGL_NV_native_query
+#define EGL_NV_native_query 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEDISPLAYNVPROC) (EGLDisplay dpy, EGLNativeDisplayType *display_id);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEWINDOWNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEPIXMAPNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeDisplayNV (EGLDisplay dpy, EGLNativeDisplayType *display_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeWindowNV (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativePixmapNV (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
+#endif
+#endif /* EGL_NV_native_query */
+
+#ifndef EGL_NV_post_convert_rounding
+#define EGL_NV_post_convert_rounding 1
+#endif /* EGL_NV_post_convert_rounding */
+
+#ifndef EGL_NV_post_sub_buffer
+#define EGL_NV_post_sub_buffer 1
+#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#endif
+#endif /* EGL_NV_post_sub_buffer */
+
+#ifndef EGL_NV_stream_sync
+#define EGL_NV_stream_sync 1
+#define EGL_SYNC_NEW_FRAME_NV 0x321F
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESTREAMSYNCNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateStreamSyncNV (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
+#endif
+#endif /* EGL_NV_stream_sync */
+
+#ifndef EGL_NV_sync
+#define EGL_NV_sync 1
+typedef void *EGLSyncNV;
+typedef khronos_utime_nanoseconds_t EGLTimeNV;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6
+#define EGL_SYNC_STATUS_NV 0x30E7
+#define EGL_SIGNALED_NV 0x30E8
+#define EGL_UNSIGNALED_NV 0x30E9
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001
+#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull
+#define EGL_ALREADY_SIGNALED_NV 0x30EA
+#define EGL_TIMEOUT_EXPIRED_NV 0x30EB
+#define EGL_CONDITION_SATISFIED_NV 0x30EC
+#define EGL_SYNC_TYPE_NV 0x30ED
+#define EGL_SYNC_CONDITION_NV 0x30EE
+#define EGL_SYNC_FENCE_NV 0x30EF
+#define EGL_NO_SYNC_NV ((EGLSyncNV)0)
+typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncNV EGLAPIENTRY eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncNV (EGLSyncNV sync);
+EGLAPI EGLBoolean EGLAPIENTRY eglFenceNV (EGLSyncNV sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncNV (EGLSyncNV sync, EGLenum mode);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_NV_sync */
+
+#ifndef EGL_NV_system_time
+#define EGL_NV_system_time 1
+typedef khronos_utime_nanoseconds_t EGLuint64NV;
+#ifdef KHRONOS_SUPPORT_INT64
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) (void);
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV (void);
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV (void);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_NV_system_time */
+
+#ifndef EGL_TIZEN_image_native_buffer
+#define EGL_TIZEN_image_native_buffer 1
+#define EGL_NATIVE_BUFFER_TIZEN 0x32A0
+#endif /* EGL_TIZEN_image_native_buffer */
+
+#ifndef EGL_TIZEN_image_native_surface
+#define EGL_TIZEN_image_native_surface 1
+#define EGL_NATIVE_SURFACE_TIZEN 0x32A1
+#endif /* EGL_TIZEN_image_native_surface */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __eglext_h_ */
+
+
+#endif /* _MSC_VER */
diff --git a/external/SDL2/include/SDL_endian.h b/external/SDL2/include/SDL_endian.h
new file mode 100644
index 0000000..9100b10
--- /dev/null
+++ b/external/SDL2/include/SDL_endian.h
@@ -0,0 +1,239 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_endian.h
+ *
+ * Functions for reading and writing endian-specific values
+ */
+
+#ifndef _SDL_endian_h
+#define _SDL_endian_h
+
+#include "SDL_stdinc.h"
+
+/**
+ * \name The two types of endianness
+ */
+/* @{ */
+#define SDL_LIL_ENDIAN 1234
+#define SDL_BIG_ENDIAN 4321
+/* @} */
+
+#ifndef SDL_BYTEORDER /* Not defined in SDL_config.h? */
+#ifdef __linux__
+#include <endian.h>
+#define SDL_BYTEORDER __BYTE_ORDER
+#else /* __linux__ */
+#if defined(__hppa__) || \
+ defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
+ (defined(__MIPS__) && defined(__MISPEB__)) || \
+ defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \
+ defined(__sparc__)
+#define SDL_BYTEORDER SDL_BIG_ENDIAN
+#else
+#define SDL_BYTEORDER SDL_LIL_ENDIAN
+#endif
+#endif /* __linux__ */
+#endif /* !SDL_BYTEORDER */
+
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file SDL_endian.h
+ */
+#if defined(__GNUC__) && defined(__i386__) && \
+ !(__GNUC__ == 2 && __GNUC_MINOR__ == 95 /* broken gcc version */)
+SDL_FORCE_INLINE Uint16
+SDL_Swap16(Uint16 x)
+{
+ __asm__("xchgb %b0,%h0": "=q"(x):"0"(x));
+ return x;
+}
+#elif defined(__GNUC__) && defined(__x86_64__)
+SDL_FORCE_INLINE Uint16
+SDL_Swap16(Uint16 x)
+{
+ __asm__("xchgb %b0,%h0": "=Q"(x):"0"(x));
+ return x;
+}
+#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
+SDL_FORCE_INLINE Uint16
+SDL_Swap16(Uint16 x)
+{
+ int result;
+
+ __asm__("rlwimi %0,%2,8,16,23": "=&r"(result):"0"(x >> 8), "r"(x));
+ return (Uint16)result;
+}
+#elif defined(__GNUC__) && (defined(__M68000__) || defined(__M68020__)) && !defined(__mcoldfire__)
+SDL_FORCE_INLINE Uint16
+SDL_Swap16(Uint16 x)
+{
+ __asm__("rorw #8,%0": "=d"(x): "0"(x):"cc");
+ return x;
+}
+#else
+SDL_FORCE_INLINE Uint16
+SDL_Swap16(Uint16 x)
+{
+ return SDL_static_cast(Uint16, ((x << 8) | (x >> 8)));
+}
+#endif
+
+#if defined(__GNUC__) && defined(__i386__)
+SDL_FORCE_INLINE Uint32
+SDL_Swap32(Uint32 x)
+{
+ __asm__("bswap %0": "=r"(x):"0"(x));
+ return x;
+}
+#elif defined(__GNUC__) && defined(__x86_64__)
+SDL_FORCE_INLINE Uint32
+SDL_Swap32(Uint32 x)
+{
+ __asm__("bswapl %0": "=r"(x):"0"(x));
+ return x;
+}
+#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
+SDL_FORCE_INLINE Uint32
+SDL_Swap32(Uint32 x)
+{
+ Uint32 result;
+
+ __asm__("rlwimi %0,%2,24,16,23": "=&r"(result):"0"(x >> 24), "r"(x));
+ __asm__("rlwimi %0,%2,8,8,15": "=&r"(result):"0"(result), "r"(x));
+ __asm__("rlwimi %0,%2,24,0,7": "=&r"(result):"0"(result), "r"(x));
+ return result;
+}
+#elif defined(__GNUC__) && (defined(__M68000__) || defined(__M68020__)) && !defined(__mcoldfire__)
+SDL_FORCE_INLINE Uint32
+SDL_Swap32(Uint32 x)
+{
+ __asm__("rorw #8,%0\n\tswap %0\n\trorw #8,%0": "=d"(x): "0"(x):"cc");
+ return x;
+}
+#else
+SDL_FORCE_INLINE Uint32
+SDL_Swap32(Uint32 x)
+{
+ return SDL_static_cast(Uint32, ((x << 24) | ((x << 8) & 0x00FF0000) |
+ ((x >> 8) & 0x0000FF00) | (x >> 24)));
+}
+#endif
+
+#if defined(__GNUC__) && defined(__i386__)
+SDL_FORCE_INLINE Uint64
+SDL_Swap64(Uint64 x)
+{
+ union
+ {
+ struct
+ {
+ Uint32 a, b;
+ } s;
+ Uint64 u;
+ } v;
+ v.u = x;
+ __asm__("bswapl %0 ; bswapl %1 ; xchgl %0,%1": "=r"(v.s.a), "=r"(v.s.b):"0"(v.s.a),
+ "1"(v.s.
+ b));
+ return v.u;
+}
+#elif defined(__GNUC__) && defined(__x86_64__)
+SDL_FORCE_INLINE Uint64
+SDL_Swap64(Uint64 x)
+{
+ __asm__("bswapq %0": "=r"(x):"0"(x));
+ return x;
+}
+#else
+SDL_FORCE_INLINE Uint64
+SDL_Swap64(Uint64 x)
+{
+ Uint32 hi, lo;
+
+ /* Separate into high and low 32-bit values and swap them */
+ lo = SDL_static_cast(Uint32, x & 0xFFFFFFFF);
+ x >>= 32;
+ hi = SDL_static_cast(Uint32, x & 0xFFFFFFFF);
+ x = SDL_Swap32(lo);
+ x <<= 32;
+ x |= SDL_Swap32(hi);
+ return (x);
+}
+#endif
+
+
+SDL_FORCE_INLINE float
+SDL_SwapFloat(float x)
+{
+ union
+ {
+ float f;
+ Uint32 ui32;
+ } swapper;
+ swapper.f = x;
+ swapper.ui32 = SDL_Swap32(swapper.ui32);
+ return swapper.f;
+}
+
+
+/**
+ * \name Swap to native
+ * Byteswap item from the specified endianness to the native endianness.
+ */
+/* @{ */
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+#define SDL_SwapLE16(X) (X)
+#define SDL_SwapLE32(X) (X)
+#define SDL_SwapLE64(X) (X)
+#define SDL_SwapFloatLE(X) (X)
+#define SDL_SwapBE16(X) SDL_Swap16(X)
+#define SDL_SwapBE32(X) SDL_Swap32(X)
+#define SDL_SwapBE64(X) SDL_Swap64(X)
+#define SDL_SwapFloatBE(X) SDL_SwapFloat(X)
+#else
+#define SDL_SwapLE16(X) SDL_Swap16(X)
+#define SDL_SwapLE32(X) SDL_Swap32(X)
+#define SDL_SwapLE64(X) SDL_Swap64(X)
+#define SDL_SwapFloatLE(X) SDL_SwapFloat(X)
+#define SDL_SwapBE16(X) (X)
+#define SDL_SwapBE32(X) (X)
+#define SDL_SwapBE64(X) (X)
+#define SDL_SwapFloatBE(X) (X)
+#endif
+/* @} *//* Swap to native */
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_endian_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_error.h b/external/SDL2/include/SDL_error.h
new file mode 100644
index 0000000..2f3b4b5
--- /dev/null
+++ b/external/SDL2/include/SDL_error.h
@@ -0,0 +1,76 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_error.h
+ *
+ * Simple error message routines for SDL.
+ */
+
+#ifndef _SDL_error_h
+#define _SDL_error_h
+
+#include "SDL_stdinc.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Public functions */
+/* SDL_SetError() unconditionally returns -1. */
+extern DECLSPEC int SDLCALL SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(1);
+extern DECLSPEC const char *SDLCALL SDL_GetError(void);
+extern DECLSPEC void SDLCALL SDL_ClearError(void);
+
+/**
+ * \name Internal error functions
+ *
+ * \internal
+ * Private error reporting function - used internally.
+ */
+/* @{ */
+#define SDL_OutOfMemory() SDL_Error(SDL_ENOMEM)
+#define SDL_Unsupported() SDL_Error(SDL_UNSUPPORTED)
+#define SDL_InvalidParamError(param) SDL_SetError("Parameter '%s' is invalid", (param))
+typedef enum
+{
+ SDL_ENOMEM,
+ SDL_EFREAD,
+ SDL_EFWRITE,
+ SDL_EFSEEK,
+ SDL_UNSUPPORTED,
+ SDL_LASTERROR
+} SDL_errorcode;
+/* SDL_Error() unconditionally returns -1. */
+extern DECLSPEC int SDLCALL SDL_Error(SDL_errorcode code);
+/* @} *//* Internal error functions */
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_error_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_events.h b/external/SDL2/include/SDL_events.h
new file mode 100644
index 0000000..1437f4c
--- /dev/null
+++ b/external/SDL2/include/SDL_events.h
@@ -0,0 +1,750 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_events.h
+ *
+ * Include file for SDL event handling.
+ */
+
+#ifndef _SDL_events_h
+#define _SDL_events_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_video.h"
+#include "SDL_keyboard.h"
+#include "SDL_mouse.h"
+#include "SDL_joystick.h"
+#include "SDL_gamecontroller.h"
+#include "SDL_quit.h"
+#include "SDL_gesture.h"
+#include "SDL_touch.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* General keyboard/mouse state definitions */
+#define SDL_RELEASED 0
+#define SDL_PRESSED 1
+
+/**
+ * \brief The types of events that can be delivered.
+ */
+typedef enum
+{
+ SDL_FIRSTEVENT = 0, /**< Unused (do not remove) */
+
+ /* Application events */
+ SDL_QUIT = 0x100, /**< User-requested quit */
+
+ /* These application events have special meaning on iOS, see README-ios.md for details */
+ SDL_APP_TERMINATING, /**< The application is being terminated by the OS
+ Called on iOS in applicationWillTerminate()
+ Called on Android in onDestroy()
+ */
+ SDL_APP_LOWMEMORY, /**< The application is low on memory, free memory if possible.
+ Called on iOS in applicationDidReceiveMemoryWarning()
+ Called on Android in onLowMemory()
+ */
+ SDL_APP_WILLENTERBACKGROUND, /**< The application is about to enter the background
+ Called on iOS in applicationWillResignActive()
+ Called on Android in onPause()
+ */
+ SDL_APP_DIDENTERBACKGROUND, /**< The application did enter the background and may not get CPU for some time
+ Called on iOS in applicationDidEnterBackground()
+ Called on Android in onPause()
+ */
+ SDL_APP_WILLENTERFOREGROUND, /**< The application is about to enter the foreground
+ Called on iOS in applicationWillEnterForeground()
+ Called on Android in onResume()
+ */
+ SDL_APP_DIDENTERFOREGROUND, /**< The application is now interactive
+ Called on iOS in applicationDidBecomeActive()
+ Called on Android in onResume()
+ */
+
+ /* Window events */
+ SDL_WINDOWEVENT = 0x200, /**< Window state change */
+ SDL_SYSWMEVENT, /**< System specific event */
+
+ /* Keyboard events */
+ SDL_KEYDOWN = 0x300, /**< Key pressed */
+ SDL_KEYUP, /**< Key released */
+ SDL_TEXTEDITING, /**< Keyboard text editing (composition) */
+ SDL_TEXTINPUT, /**< Keyboard text input */
+ SDL_KEYMAPCHANGED, /**< Keymap changed due to a system event such as an
+ input language or keyboard layout change.
+ */
+
+ /* Mouse events */
+ SDL_MOUSEMOTION = 0x400, /**< Mouse moved */
+ SDL_MOUSEBUTTONDOWN, /**< Mouse button pressed */
+ SDL_MOUSEBUTTONUP, /**< Mouse button released */
+ SDL_MOUSEWHEEL, /**< Mouse wheel motion */
+
+ /* Joystick events */
+ SDL_JOYAXISMOTION = 0x600, /**< Joystick axis motion */
+ SDL_JOYBALLMOTION, /**< Joystick trackball motion */
+ SDL_JOYHATMOTION, /**< Joystick hat position change */
+ SDL_JOYBUTTONDOWN, /**< Joystick button pressed */
+ SDL_JOYBUTTONUP, /**< Joystick button released */
+ SDL_JOYDEVICEADDED, /**< A new joystick has been inserted into the system */
+ SDL_JOYDEVICEREMOVED, /**< An opened joystick has been removed */
+
+ /* Game controller events */
+ SDL_CONTROLLERAXISMOTION = 0x650, /**< Game controller axis motion */
+ SDL_CONTROLLERBUTTONDOWN, /**< Game controller button pressed */
+ SDL_CONTROLLERBUTTONUP, /**< Game controller button released */
+ SDL_CONTROLLERDEVICEADDED, /**< A new Game controller has been inserted into the system */
+ SDL_CONTROLLERDEVICEREMOVED, /**< An opened Game controller has been removed */
+ SDL_CONTROLLERDEVICEREMAPPED, /**< The controller mapping was updated */
+
+ /* Touch events */
+ SDL_FINGERDOWN = 0x700,
+ SDL_FINGERUP,
+ SDL_FINGERMOTION,
+
+ /* Gesture events */
+ SDL_DOLLARGESTURE = 0x800,
+ SDL_DOLLARRECORD,
+ SDL_MULTIGESTURE,
+
+ /* Clipboard events */
+ SDL_CLIPBOARDUPDATE = 0x900, /**< The clipboard changed */
+
+ /* Drag and drop events */
+ SDL_DROPFILE = 0x1000, /**< The system requests a file open */
+
+ /* Audio hotplug events */
+ SDL_AUDIODEVICEADDED = 0x1100, /**< A new audio device is available */
+ SDL_AUDIODEVICEREMOVED, /**< An audio device has been removed. */
+
+ /* Render events */
+ SDL_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */
+ SDL_RENDER_DEVICE_RESET, /**< The device has been reset and all textures need to be recreated */
+
+ /** Events ::SDL_USEREVENT through ::SDL_LASTEVENT are for your use,
+ * and should be allocated with SDL_RegisterEvents()
+ */
+ SDL_USEREVENT = 0x8000,
+
+ /**
+ * This last event is only for bounding internal arrays
+ */
+ SDL_LASTEVENT = 0xFFFF
+} SDL_EventType;
+
+/**
+ * \brief Fields shared by every event
+ */
+typedef struct SDL_CommonEvent
+{
+ Uint32 type;
+ Uint32 timestamp;
+} SDL_CommonEvent;
+
+/**
+ * \brief Window state change event data (event.window.*)
+ */
+typedef struct SDL_WindowEvent
+{
+ Uint32 type; /**< ::SDL_WINDOWEVENT */
+ Uint32 timestamp;
+ Uint32 windowID; /**< The associated window */
+ Uint8 event; /**< ::SDL_WindowEventID */
+ Uint8 padding1;
+ Uint8 padding2;
+ Uint8 padding3;
+ Sint32 data1; /**< event dependent data */
+ Sint32 data2; /**< event dependent data */
+} SDL_WindowEvent;
+
+/**
+ * \brief Keyboard button event structure (event.key.*)
+ */
+typedef struct SDL_KeyboardEvent
+{
+ Uint32 type; /**< ::SDL_KEYDOWN or ::SDL_KEYUP */
+ Uint32 timestamp;
+ Uint32 windowID; /**< The window with keyboard focus, if any */
+ Uint8 state; /**< ::SDL_PRESSED or ::SDL_RELEASED */
+ Uint8 repeat; /**< Non-zero if this is a key repeat */
+ Uint8 padding2;
+ Uint8 padding3;
+ SDL_Keysym keysym; /**< The key that was pressed or released */
+} SDL_KeyboardEvent;
+
+#define SDL_TEXTEDITINGEVENT_TEXT_SIZE (32)
+/**
+ * \brief Keyboard text editing event structure (event.edit.*)
+ */
+typedef struct SDL_TextEditingEvent
+{
+ Uint32 type; /**< ::SDL_TEXTEDITING */
+ Uint32 timestamp;
+ Uint32 windowID; /**< The window with keyboard focus, if any */
+ char text[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; /**< The editing text */
+ Sint32 start; /**< The start cursor of selected editing text */
+ Sint32 length; /**< The length of selected editing text */
+} SDL_TextEditingEvent;
+
+
+#define SDL_TEXTINPUTEVENT_TEXT_SIZE (32)
+/**
+ * \brief Keyboard text input event structure (event.text.*)
+ */
+typedef struct SDL_TextInputEvent
+{
+ Uint32 type; /**< ::SDL_TEXTINPUT */
+ Uint32 timestamp;
+ Uint32 windowID; /**< The window with keyboard focus, if any */
+ char text[SDL_TEXTINPUTEVENT_TEXT_SIZE]; /**< The input text */
+} SDL_TextInputEvent;
+
+/**
+ * \brief Mouse motion event structure (event.motion.*)
+ */
+typedef struct SDL_MouseMotionEvent
+{
+ Uint32 type; /**< ::SDL_MOUSEMOTION */
+ Uint32 timestamp;
+ Uint32 windowID; /**< The window with mouse focus, if any */
+ Uint32 which; /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
+ Uint32 state; /**< The current button state */
+ Sint32 x; /**< X coordinate, relative to window */
+ Sint32 y; /**< Y coordinate, relative to window */
+ Sint32 xrel; /**< The relative motion in the X direction */
+ Sint32 yrel; /**< The relative motion in the Y direction */
+} SDL_MouseMotionEvent;
+
+/**
+ * \brief Mouse button event structure (event.button.*)
+ */
+typedef struct SDL_MouseButtonEvent
+{
+ Uint32 type; /**< ::SDL_MOUSEBUTTONDOWN or ::SDL_MOUSEBUTTONUP */
+ Uint32 timestamp;
+ Uint32 windowID; /**< The window with mouse focus, if any */
+ Uint32 which; /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
+ Uint8 button; /**< The mouse button index */
+ Uint8 state; /**< ::SDL_PRESSED or ::SDL_RELEASED */
+ Uint8 clicks; /**< 1 for single-click, 2 for double-click, etc. */
+ Uint8 padding1;
+ Sint32 x; /**< X coordinate, relative to window */
+ Sint32 y; /**< Y coordinate, relative to window */
+} SDL_MouseButtonEvent;
+
+/**
+ * \brief Mouse wheel event structure (event.wheel.*)
+ */
+typedef struct SDL_MouseWheelEvent
+{
+ Uint32 type; /**< ::SDL_MOUSEWHEEL */
+ Uint32 timestamp;
+ Uint32 windowID; /**< The window with mouse focus, if any */
+ Uint32 which; /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
+ Sint32 x; /**< The amount scrolled horizontally, positive to the right and negative to the left */
+ Sint32 y; /**< The amount scrolled vertically, positive away from the user and negative toward the user */
+ Uint32 direction; /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */
+} SDL_MouseWheelEvent;
+
+/**
+ * \brief Joystick axis motion event structure (event.jaxis.*)
+ */
+typedef struct SDL_JoyAxisEvent
+{
+ Uint32 type; /**< ::SDL_JOYAXISMOTION */
+ Uint32 timestamp;
+ SDL_JoystickID which; /**< The joystick instance id */
+ Uint8 axis; /**< The joystick axis index */
+ Uint8 padding1;
+ Uint8 padding2;
+ Uint8 padding3;
+ Sint16 value; /**< The axis value (range: -32768 to 32767) */
+ Uint16 padding4;
+} SDL_JoyAxisEvent;
+
+/**
+ * \brief Joystick trackball motion event structure (event.jball.*)
+ */
+typedef struct SDL_JoyBallEvent
+{
+ Uint32 type; /**< ::SDL_JOYBALLMOTION */
+ Uint32 timestamp;
+ SDL_JoystickID which; /**< The joystick instance id */
+ Uint8 ball; /**< The joystick trackball index */
+ Uint8 padding1;
+ Uint8 padding2;
+ Uint8 padding3;
+ Sint16 xrel; /**< The relative motion in the X direction */
+ Sint16 yrel; /**< The relative motion in the Y direction */
+} SDL_JoyBallEvent;
+
+/**
+ * \brief Joystick hat position change event structure (event.jhat.*)
+ */
+typedef struct SDL_JoyHatEvent
+{
+ Uint32 type; /**< ::SDL_JOYHATMOTION */
+ Uint32 timestamp;
+ SDL_JoystickID which; /**< The joystick instance id */
+ Uint8 hat; /**< The joystick hat index */
+ Uint8 value; /**< The hat position value.
+ * \sa ::SDL_HAT_LEFTUP ::SDL_HAT_UP ::SDL_HAT_RIGHTUP
+ * \sa ::SDL_HAT_LEFT ::SDL_HAT_CENTERED ::SDL_HAT_RIGHT
+ * \sa ::SDL_HAT_LEFTDOWN ::SDL_HAT_DOWN ::SDL_HAT_RIGHTDOWN
+ *
+ * Note that zero means the POV is centered.
+ */
+ Uint8 padding1;
+ Uint8 padding2;
+} SDL_JoyHatEvent;
+
+/**
+ * \brief Joystick button event structure (event.jbutton.*)
+ */
+typedef struct SDL_JoyButtonEvent
+{
+ Uint32 type; /**< ::SDL_JOYBUTTONDOWN or ::SDL_JOYBUTTONUP */
+ Uint32 timestamp;
+ SDL_JoystickID which; /**< The joystick instance id */
+ Uint8 button; /**< The joystick button index */
+ Uint8 state; /**< ::SDL_PRESSED or ::SDL_RELEASED */
+ Uint8 padding1;
+ Uint8 padding2;
+} SDL_JoyButtonEvent;
+
+/**
+ * \brief Joystick device event structure (event.jdevice.*)
+ */
+typedef struct SDL_JoyDeviceEvent
+{
+ Uint32 type; /**< ::SDL_JOYDEVICEADDED or ::SDL_JOYDEVICEREMOVED */
+ Uint32 timestamp;
+ Sint32 which; /**< The joystick device index for the ADDED event, instance id for the REMOVED event */
+} SDL_JoyDeviceEvent;
+
+
+/**
+ * \brief Game controller axis motion event structure (event.caxis.*)
+ */
+typedef struct SDL_ControllerAxisEvent
+{
+ Uint32 type; /**< ::SDL_CONTROLLERAXISMOTION */
+ Uint32 timestamp;
+ SDL_JoystickID which; /**< The joystick instance id */
+ Uint8 axis; /**< The controller axis (SDL_GameControllerAxis) */
+ Uint8 padding1;
+ Uint8 padding2;
+ Uint8 padding3;
+ Sint16 value; /**< The axis value (range: -32768 to 32767) */
+ Uint16 padding4;
+} SDL_ControllerAxisEvent;
+
+
+/**
+ * \brief Game controller button event structure (event.cbutton.*)
+ */
+typedef struct SDL_ControllerButtonEvent
+{
+ Uint32 type; /**< ::SDL_CONTROLLERBUTTONDOWN or ::SDL_CONTROLLERBUTTONUP */
+ Uint32 timestamp;
+ SDL_JoystickID which; /**< The joystick instance id */
+ Uint8 button; /**< The controller button (SDL_GameControllerButton) */
+ Uint8 state; /**< ::SDL_PRESSED or ::SDL_RELEASED */
+ Uint8 padding1;
+ Uint8 padding2;
+} SDL_ControllerButtonEvent;
+
+
+/**
+ * \brief Controller device event structure (event.cdevice.*)
+ */
+typedef struct SDL_ControllerDeviceEvent
+{
+ Uint32 type; /**< ::SDL_CONTROLLERDEVICEADDED, ::SDL_CONTROLLERDEVICEREMOVED, or ::SDL_CONTROLLERDEVICEREMAPPED */
+ Uint32 timestamp;
+ Sint32 which; /**< The joystick device index for the ADDED event, instance id for the REMOVED or REMAPPED event */
+} SDL_ControllerDeviceEvent;
+
+/**
+ * \brief Audio device event structure (event.adevice.*)
+ */
+typedef struct SDL_AudioDeviceEvent
+{
+ Uint32 type; /**< ::SDL_AUDIODEVICEADDED, or ::SDL_AUDIODEVICEREMOVED */
+ Uint32 timestamp;
+ Uint32 which; /**< The audio device index for the ADDED event (valid until next SDL_GetNumAudioDevices() call), SDL_AudioDeviceID for the REMOVED event */
+ Uint8 iscapture; /**< zero if an output device, non-zero if a capture device. */
+ Uint8 padding1;
+ Uint8 padding2;
+ Uint8 padding3;
+} SDL_AudioDeviceEvent;
+
+
+/**
+ * \brief Touch finger event structure (event.tfinger.*)
+ */
+typedef struct SDL_TouchFingerEvent
+{
+ Uint32 type; /**< ::SDL_FINGERMOTION or ::SDL_FINGERDOWN or ::SDL_FINGERUP */
+ Uint32 timestamp;
+ SDL_TouchID touchId; /**< The touch device id */
+ SDL_FingerID fingerId;
+ float x; /**< Normalized in the range 0...1 */
+ float y; /**< Normalized in the range 0...1 */
+ float dx; /**< Normalized in the range -1...1 */
+ float dy; /**< Normalized in the range -1...1 */
+ float pressure; /**< Normalized in the range 0...1 */
+} SDL_TouchFingerEvent;
+
+
+/**
+ * \brief Multiple Finger Gesture Event (event.mgesture.*)
+ */
+typedef struct SDL_MultiGestureEvent
+{
+ Uint32 type; /**< ::SDL_MULTIGESTURE */
+ Uint32 timestamp;
+ SDL_TouchID touchId; /**< The touch device index */
+ float dTheta;
+ float dDist;
+ float x;
+ float y;
+ Uint16 numFingers;
+ Uint16 padding;
+} SDL_MultiGestureEvent;
+
+
+/**
+ * \brief Dollar Gesture Event (event.dgesture.*)
+ */
+typedef struct SDL_DollarGestureEvent
+{
+ Uint32 type; /**< ::SDL_DOLLARGESTURE or ::SDL_DOLLARRECORD */
+ Uint32 timestamp;
+ SDL_TouchID touchId; /**< The touch device id */
+ SDL_GestureID gestureId;
+ Uint32 numFingers;
+ float error;
+ float x; /**< Normalized center of gesture */
+ float y; /**< Normalized center of gesture */
+} SDL_DollarGestureEvent;
+
+
+/**
+ * \brief An event used to request a file open by the system (event.drop.*)
+ * This event is enabled by default, you can disable it with SDL_EventState().
+ * \note If this event is enabled, you must free the filename in the event.
+ */
+typedef struct SDL_DropEvent
+{
+ Uint32 type; /**< ::SDL_DROPFILE */
+ Uint32 timestamp;
+ char *file; /**< The file name, which should be freed with SDL_free() */
+} SDL_DropEvent;
+
+
+/**
+ * \brief The "quit requested" event
+ */
+typedef struct SDL_QuitEvent
+{
+ Uint32 type; /**< ::SDL_QUIT */
+ Uint32 timestamp;
+} SDL_QuitEvent;
+
+/**
+ * \brief OS Specific event
+ */
+typedef struct SDL_OSEvent
+{
+ Uint32 type; /**< ::SDL_QUIT */
+ Uint32 timestamp;
+} SDL_OSEvent;
+
+/**
+ * \brief A user-defined event type (event.user.*)
+ */
+typedef struct SDL_UserEvent
+{
+ Uint32 type; /**< ::SDL_USEREVENT through ::SDL_LASTEVENT-1 */
+ Uint32 timestamp;
+ Uint32 windowID; /**< The associated window if any */
+ Sint32 code; /**< User defined event code */
+ void *data1; /**< User defined data pointer */
+ void *data2; /**< User defined data pointer */
+} SDL_UserEvent;
+
+
+struct SDL_SysWMmsg;
+typedef struct SDL_SysWMmsg SDL_SysWMmsg;
+
+/**
+ * \brief A video driver dependent system event (event.syswm.*)
+ * This event is disabled by default, you can enable it with SDL_EventState()
+ *
+ * \note If you want to use this event, you should include SDL_syswm.h.
+ */
+typedef struct SDL_SysWMEvent
+{
+ Uint32 type; /**< ::SDL_SYSWMEVENT */
+ Uint32 timestamp;
+ SDL_SysWMmsg *msg; /**< driver dependent data, defined in SDL_syswm.h */
+} SDL_SysWMEvent;
+
+/**
+ * \brief General event structure
+ */
+typedef union SDL_Event
+{
+ Uint32 type; /**< Event type, shared with all events */
+ SDL_CommonEvent common; /**< Common event data */
+ SDL_WindowEvent window; /**< Window event data */
+ SDL_KeyboardEvent key; /**< Keyboard event data */
+ SDL_TextEditingEvent edit; /**< Text editing event data */
+ SDL_TextInputEvent text; /**< Text input event data */
+ SDL_MouseMotionEvent motion; /**< Mouse motion event data */
+ SDL_MouseButtonEvent button; /**< Mouse button event data */
+ SDL_MouseWheelEvent wheel; /**< Mouse wheel event data */
+ SDL_JoyAxisEvent jaxis; /**< Joystick axis event data */
+ SDL_JoyBallEvent jball; /**< Joystick ball event data */
+ SDL_JoyHatEvent jhat; /**< Joystick hat event data */
+ SDL_JoyButtonEvent jbutton; /**< Joystick button event data */
+ SDL_JoyDeviceEvent jdevice; /**< Joystick device change event data */
+ SDL_ControllerAxisEvent caxis; /**< Game Controller axis event data */
+ SDL_ControllerButtonEvent cbutton; /**< Game Controller button event data */
+ SDL_ControllerDeviceEvent cdevice; /**< Game Controller device event data */
+ SDL_AudioDeviceEvent adevice; /**< Audio device event data */
+ SDL_QuitEvent quit; /**< Quit request event data */
+ SDL_UserEvent user; /**< Custom event data */
+ SDL_SysWMEvent syswm; /**< System dependent window event data */
+ SDL_TouchFingerEvent tfinger; /**< Touch finger event data */
+ SDL_MultiGestureEvent mgesture; /**< Gesture event data */
+ SDL_DollarGestureEvent dgesture; /**< Gesture event data */
+ SDL_DropEvent drop; /**< Drag and drop event data */
+
+ /* This is necessary for ABI compatibility between Visual C++ and GCC
+ Visual C++ will respect the push pack pragma and use 52 bytes for
+ this structure, and GCC will use the alignment of the largest datatype
+ within the union, which is 8 bytes.
+
+ So... we'll add padding to force the size to be 56 bytes for both.
+ */
+ Uint8 padding[56];
+} SDL_Event;
+
+
+/* Function prototypes */
+
+/**
+ * Pumps the event loop, gathering events from the input devices.
+ *
+ * This function updates the event queue and internal input device state.
+ *
+ * This should only be run in the thread that sets the video mode.
+ */
+extern DECLSPEC void SDLCALL SDL_PumpEvents(void);
+
+/* @{ */
+typedef enum
+{
+ SDL_ADDEVENT,
+ SDL_PEEKEVENT,
+ SDL_GETEVENT
+} SDL_eventaction;
+
+/**
+ * Checks the event queue for messages and optionally returns them.
+ *
+ * If \c action is ::SDL_ADDEVENT, up to \c numevents events will be added to
+ * the back of the event queue.
+ *
+ * If \c action is ::SDL_PEEKEVENT, up to \c numevents events at the front
+ * of the event queue, within the specified minimum and maximum type,
+ * will be returned and will not be removed from the queue.
+ *
+ * If \c action is ::SDL_GETEVENT, up to \c numevents events at the front
+ * of the event queue, within the specified minimum and maximum type,
+ * will be returned and will be removed from the queue.
+ *
+ * \return The number of events actually stored, or -1 if there was an error.
+ *
+ * This function is thread-safe.
+ */
+extern DECLSPEC int SDLCALL SDL_PeepEvents(SDL_Event * events, int numevents,
+ SDL_eventaction action,
+ Uint32 minType, Uint32 maxType);
+/* @} */
+
+/**
+ * Checks to see if certain event types are in the event queue.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasEvent(Uint32 type);
+extern DECLSPEC SDL_bool SDLCALL SDL_HasEvents(Uint32 minType, Uint32 maxType);
+
+/**
+ * This function clears events from the event queue
+ * This function only affects currently queued events. If you want to make
+ * sure that all pending OS events are flushed, you can call SDL_PumpEvents()
+ * on the main thread immediately before the flush call.
+ */
+extern DECLSPEC void SDLCALL SDL_FlushEvent(Uint32 type);
+extern DECLSPEC void SDLCALL SDL_FlushEvents(Uint32 minType, Uint32 maxType);
+
+/**
+ * \brief Polls for currently pending events.
+ *
+ * \return 1 if there are any pending events, or 0 if there are none available.
+ *
+ * \param event If not NULL, the next event is removed from the queue and
+ * stored in that area.
+ */
+extern DECLSPEC int SDLCALL SDL_PollEvent(SDL_Event * event);
+
+/**
+ * \brief Waits indefinitely for the next available event.
+ *
+ * \return 1, or 0 if there was an error while waiting for events.
+ *
+ * \param event If not NULL, the next event is removed from the queue and
+ * stored in that area.
+ */
+extern DECLSPEC int SDLCALL SDL_WaitEvent(SDL_Event * event);
+
+/**
+ * \brief Waits until the specified timeout (in milliseconds) for the next
+ * available event.
+ *
+ * \return 1, or 0 if there was an error while waiting for events.
+ *
+ * \param event If not NULL, the next event is removed from the queue and
+ * stored in that area.
+ * \param timeout The timeout (in milliseconds) to wait for next event.
+ */
+extern DECLSPEC int SDLCALL SDL_WaitEventTimeout(SDL_Event * event,
+ int timeout);
+
+/**
+ * \brief Add an event to the event queue.
+ *
+ * \return 1 on success, 0 if the event was filtered, or -1 if the event queue
+ * was full or there was some other error.
+ */
+extern DECLSPEC int SDLCALL SDL_PushEvent(SDL_Event * event);
+
+typedef int (SDLCALL * SDL_EventFilter) (void *userdata, SDL_Event * event);
+
+/**
+ * Sets up a filter to process all events before they change internal state and
+ * are posted to the internal event queue.
+ *
+ * The filter is prototyped as:
+ * \code
+ * int SDL_EventFilter(void *userdata, SDL_Event * event);
+ * \endcode
+ *
+ * If the filter returns 1, then the event will be added to the internal queue.
+ * If it returns 0, then the event will be dropped from the queue, but the
+ * internal state will still be updated. This allows selective filtering of
+ * dynamically arriving events.
+ *
+ * \warning Be very careful of what you do in the event filter function, as
+ * it may run in a different thread!
+ *
+ * There is one caveat when dealing with the ::SDL_QuitEvent event type. The
+ * event filter is only called when the window manager desires to close the
+ * application window. If the event filter returns 1, then the window will
+ * be closed, otherwise the window will remain open if possible.
+ *
+ * If the quit event is generated by an interrupt signal, it will bypass the
+ * internal queue and be delivered to the application at the next event poll.
+ */
+extern DECLSPEC void SDLCALL SDL_SetEventFilter(SDL_EventFilter filter,
+ void *userdata);
+
+/**
+ * Return the current event filter - can be used to "chain" filters.
+ * If there is no event filter set, this function returns SDL_FALSE.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_GetEventFilter(SDL_EventFilter * filter,
+ void **userdata);
+
+/**
+ * Add a function which is called when an event is added to the queue.
+ */
+extern DECLSPEC void SDLCALL SDL_AddEventWatch(SDL_EventFilter filter,
+ void *userdata);
+
+/**
+ * Remove an event watch function added with SDL_AddEventWatch()
+ */
+extern DECLSPEC void SDLCALL SDL_DelEventWatch(SDL_EventFilter filter,
+ void *userdata);
+
+/**
+ * Run the filter function on the current event queue, removing any
+ * events for which the filter returns 0.
+ */
+extern DECLSPEC void SDLCALL SDL_FilterEvents(SDL_EventFilter filter,
+ void *userdata);
+
+/* @{ */
+#define SDL_QUERY -1
+#define SDL_IGNORE 0
+#define SDL_DISABLE 0
+#define SDL_ENABLE 1
+
+/**
+ * This function allows you to set the state of processing certain events.
+ * - If \c state is set to ::SDL_IGNORE, that event will be automatically
+ * dropped from the event queue and will not event be filtered.
+ * - If \c state is set to ::SDL_ENABLE, that event will be processed
+ * normally.
+ * - If \c state is set to ::SDL_QUERY, SDL_EventState() will return the
+ * current processing state of the specified event.
+ */
+extern DECLSPEC Uint8 SDLCALL SDL_EventState(Uint32 type, int state);
+/* @} */
+#define SDL_GetEventState(type) SDL_EventState(type, SDL_QUERY)
+
+/**
+ * This function allocates a set of user-defined events, and returns
+ * the beginning event number for that set of events.
+ *
+ * If there aren't enough user-defined events left, this function
+ * returns (Uint32)-1
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_RegisterEvents(int numevents);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_events_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_filesystem.h b/external/SDL2/include/SDL_filesystem.h
new file mode 100644
index 0000000..02999ed
--- /dev/null
+++ b/external/SDL2/include/SDL_filesystem.h
@@ -0,0 +1,136 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_filesystem.h
+ *
+ * \brief Include file for filesystem SDL API functions
+ */
+
+#ifndef _SDL_filesystem_h
+#define _SDL_filesystem_h
+
+#include "SDL_stdinc.h"
+
+#include "begin_code.h"
+
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Get the path where the application resides.
+ *
+ * Get the "base path". This is the directory where the application was run
+ * from, which is probably the installation directory, and may or may not
+ * be the process's current working directory.
+ *
+ * This returns an absolute path in UTF-8 encoding, and is guaranteed to
+ * end with a path separator ('\\' on Windows, '/' most other places).
+ *
+ * The pointer returned by this function is owned by you. Please call
+ * SDL_free() on the pointer when you are done with it, or it will be a
+ * memory leak. This is not necessarily a fast call, though, so you should
+ * call this once near startup and save the string if you need it.
+ *
+ * Some platforms can't determine the application's path, and on other
+ * platforms, this might be meaningless. In such cases, this function will
+ * return NULL.
+ *
+ * \return String of base dir in UTF-8 encoding, or NULL on error.
+ *
+ * \sa SDL_GetPrefPath
+ */
+extern DECLSPEC char *SDLCALL SDL_GetBasePath(void);
+
+/**
+ * \brief Get the user-and-app-specific path where files can be written.
+ *
+ * Get the "pref dir". This is meant to be where users can write personal
+ * files (preferences and save games, etc) that are specific to your
+ * application. This directory is unique per user, per application.
+ *
+ * This function will decide the appropriate location in the native filesystem,
+ * create the directory if necessary, and return a string of the absolute
+ * path to the directory in UTF-8 encoding.
+ *
+ * On Windows, the string might look like:
+ * "C:\\Users\\bob\\AppData\\Roaming\\My Company\\My Program Name\\"
+ *
+ * On Linux, the string might look like:
+ * "/home/bob/.local/share/My Program Name/"
+ *
+ * On Mac OS X, the string might look like:
+ * "/Users/bob/Library/Application Support/My Program Name/"
+ *
+ * (etc.)
+ *
+ * You specify the name of your organization (if it's not a real organization,
+ * your name or an Internet domain you own might do) and the name of your
+ * application. These should be untranslated proper names.
+ *
+ * Both the org and app strings may become part of a directory name, so
+ * please follow these rules:
+ *
+ * - Try to use the same org string (including case-sensitivity) for
+ * all your applications that use this function.
+ * - Always use a unique app string for each one, and make sure it never
+ * changes for an app once you've decided on it.
+ * - Unicode characters are legal, as long as it's UTF-8 encoded, but...
+ * - ...only use letters, numbers, and spaces. Avoid punctuation like
+ * "Game Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient.
+ *
+ * This returns an absolute path in UTF-8 encoding, and is guaranteed to
+ * end with a path separator ('\\' on Windows, '/' most other places).
+ *
+ * The pointer returned by this function is owned by you. Please call
+ * SDL_free() on the pointer when you are done with it, or it will be a
+ * memory leak. This is not necessarily a fast call, though, so you should
+ * call this once near startup and save the string if you need it.
+ *
+ * You should assume the path returned by this function is the only safe
+ * place to write files (and that SDL_GetBasePath(), while it might be
+ * writable, or even the parent of the returned path, aren't where you
+ * should be writing things).
+ *
+ * Some platforms can't determine the pref path, and on other
+ * platforms, this might be meaningless. In such cases, this function will
+ * return NULL.
+ *
+ * \param org The name of your organization.
+ * \param app The name of your application.
+ * \return UTF-8 string of user dir in platform-dependent notation. NULL
+ * if there's a problem (creating directory failed, etc).
+ *
+ * \sa SDL_GetBasePath
+ */
+extern DECLSPEC char *SDLCALL SDL_GetPrefPath(const char *org, const char *app);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_filesystem_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_gamecontroller.h b/external/SDL2/include/SDL_gamecontroller.h
new file mode 100644
index 0000000..42087ee
--- /dev/null
+++ b/external/SDL2/include/SDL_gamecontroller.h
@@ -0,0 +1,323 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_gamecontroller.h
+ *
+ * Include file for SDL game controller event handling
+ */
+
+#ifndef _SDL_gamecontroller_h
+#define _SDL_gamecontroller_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_rwops.h"
+#include "SDL_joystick.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file SDL_gamecontroller.h
+ *
+ * In order to use these functions, SDL_Init() must have been called
+ * with the ::SDL_INIT_GAMECONTROLLER flag. This causes SDL to scan the system
+ * for game controllers, and load appropriate drivers.
+ *
+ * If you would like to receive controller updates while the application
+ * is in the background, you should set the following hint before calling
+ * SDL_Init(): SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS
+ */
+
+/* The gamecontroller structure used to identify an SDL game controller */
+struct _SDL_GameController;
+typedef struct _SDL_GameController SDL_GameController;
+
+
+typedef enum
+{
+ SDL_CONTROLLER_BINDTYPE_NONE = 0,
+ SDL_CONTROLLER_BINDTYPE_BUTTON,
+ SDL_CONTROLLER_BINDTYPE_AXIS,
+ SDL_CONTROLLER_BINDTYPE_HAT
+} SDL_GameControllerBindType;
+
+/**
+ * Get the SDL joystick layer binding for this controller button/axis mapping
+ */
+typedef struct SDL_GameControllerButtonBind
+{
+ SDL_GameControllerBindType bindType;
+ union
+ {
+ int button;
+ int axis;
+ struct {
+ int hat;
+ int hat_mask;
+ } hat;
+ } value;
+
+} SDL_GameControllerButtonBind;
+
+
+/**
+ * To count the number of game controllers in the system for the following:
+ * int nJoysticks = SDL_NumJoysticks();
+ * int nGameControllers = 0;
+ * for ( int i = 0; i < nJoysticks; i++ ) {
+ * if ( SDL_IsGameController(i) ) {
+ * nGameControllers++;
+ * }
+ * }
+ *
+ * Using the SDL_HINT_GAMECONTROLLERCONFIG hint or the SDL_GameControllerAddMapping you can add support for controllers SDL is unaware of or cause an existing controller to have a different binding. The format is:
+ * guid,name,mappings
+ *
+ * Where GUID is the string value from SDL_JoystickGetGUIDString(), name is the human readable string for the device and mappings are controller mappings to joystick ones.
+ * Under Windows there is a reserved GUID of "xinput" that covers any XInput devices.
+ * The mapping format for joystick is:
+ * bX - a joystick button, index X
+ * hX.Y - hat X with value Y
+ * aX - axis X of the joystick
+ * Buttons can be used as a controller axis and vice versa.
+ *
+ * This string shows an example of a valid mapping for a controller
+ * "341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7",
+ *
+ */
+
+/**
+ * Load a set of mappings from a seekable SDL data stream (memory or file), filtered by the current SDL_GetPlatform()
+ * A community sourced database of controllers is available at https://raw.github.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt
+ *
+ * If \c freerw is non-zero, the stream will be closed after being read.
+ *
+ * \return number of mappings added, -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerAddMappingsFromRW( SDL_RWops * rw, int freerw );
+
+/**
+ * Load a set of mappings from a file, filtered by the current SDL_GetPlatform()
+ *
+ * Convenience macro.
+ */
+#define SDL_GameControllerAddMappingsFromFile(file) SDL_GameControllerAddMappingsFromRW(SDL_RWFromFile(file, "rb"), 1)
+
+/**
+ * Add or update an existing mapping configuration
+ *
+ * \return 1 if mapping is added, 0 if updated, -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerAddMapping( const char* mappingString );
+
+/**
+ * Get a mapping string for a GUID
+ *
+ * \return the mapping string. Must be freed with SDL_free. Returns NULL if no mapping is available
+ */
+extern DECLSPEC char * SDLCALL SDL_GameControllerMappingForGUID( SDL_JoystickGUID guid );
+
+/**
+ * Get a mapping string for an open GameController
+ *
+ * \return the mapping string. Must be freed with SDL_free. Returns NULL if no mapping is available
+ */
+extern DECLSPEC char * SDLCALL SDL_GameControllerMapping( SDL_GameController * gamecontroller );
+
+/**
+ * Is the joystick on this index supported by the game controller interface?
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsGameController(int joystick_index);
+
+
+/**
+ * Get the implementation dependent name of a game controller.
+ * This can be called before any controllers are opened.
+ * If no name can be found, this function returns NULL.
+ */
+extern DECLSPEC const char *SDLCALL SDL_GameControllerNameForIndex(int joystick_index);
+
+/**
+ * Open a game controller for use.
+ * The index passed as an argument refers to the N'th game controller on the system.
+ * This index is not the value which will identify this controller in future
+ * controller events. The joystick's instance id (::SDL_JoystickID) will be
+ * used there instead.
+ *
+ * \return A controller identifier, or NULL if an error occurred.
+ */
+extern DECLSPEC SDL_GameController *SDLCALL SDL_GameControllerOpen(int joystick_index);
+
+/**
+ * Return the SDL_GameController associated with an instance id.
+ */
+extern DECLSPEC SDL_GameController *SDLCALL SDL_GameControllerFromInstanceID(SDL_JoystickID joyid);
+
+/**
+ * Return the name for this currently opened controller
+ */
+extern DECLSPEC const char *SDLCALL SDL_GameControllerName(SDL_GameController *gamecontroller);
+
+/**
+ * Returns SDL_TRUE if the controller has been opened and currently connected,
+ * or SDL_FALSE if it has not.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_GameControllerGetAttached(SDL_GameController *gamecontroller);
+
+/**
+ * Get the underlying joystick object used by a controller
+ */
+extern DECLSPEC SDL_Joystick *SDLCALL SDL_GameControllerGetJoystick(SDL_GameController *gamecontroller);
+
+/**
+ * Enable/disable controller event polling.
+ *
+ * If controller events are disabled, you must call SDL_GameControllerUpdate()
+ * yourself and check the state of the controller when you want controller
+ * information.
+ *
+ * The state can be one of ::SDL_QUERY, ::SDL_ENABLE or ::SDL_IGNORE.
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerEventState(int state);
+
+/**
+ * Update the current state of the open game controllers.
+ *
+ * This is called automatically by the event loop if any game controller
+ * events are enabled.
+ */
+extern DECLSPEC void SDLCALL SDL_GameControllerUpdate(void);
+
+
+/**
+ * The list of axes available from a controller
+ */
+typedef enum
+{
+ SDL_CONTROLLER_AXIS_INVALID = -1,
+ SDL_CONTROLLER_AXIS_LEFTX,
+ SDL_CONTROLLER_AXIS_LEFTY,
+ SDL_CONTROLLER_AXIS_RIGHTX,
+ SDL_CONTROLLER_AXIS_RIGHTY,
+ SDL_CONTROLLER_AXIS_TRIGGERLEFT,
+ SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
+ SDL_CONTROLLER_AXIS_MAX
+} SDL_GameControllerAxis;
+
+/**
+ * turn this string into a axis mapping
+ */
+extern DECLSPEC SDL_GameControllerAxis SDLCALL SDL_GameControllerGetAxisFromString(const char *pchString);
+
+/**
+ * turn this axis enum into a string mapping
+ */
+extern DECLSPEC const char* SDLCALL SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis);
+
+/**
+ * Get the SDL joystick layer binding for this controller button mapping
+ */
+extern DECLSPEC SDL_GameControllerButtonBind SDLCALL
+SDL_GameControllerGetBindForAxis(SDL_GameController *gamecontroller,
+ SDL_GameControllerAxis axis);
+
+/**
+ * Get the current state of an axis control on a game controller.
+ *
+ * The state is a value ranging from -32768 to 32767 (except for the triggers,
+ * which range from 0 to 32767).
+ *
+ * The axis indices start at index 0.
+ */
+extern DECLSPEC Sint16 SDLCALL
+SDL_GameControllerGetAxis(SDL_GameController *gamecontroller,
+ SDL_GameControllerAxis axis);
+
+/**
+ * The list of buttons available from a controller
+ */
+typedef enum
+{
+ SDL_CONTROLLER_BUTTON_INVALID = -1,
+ SDL_CONTROLLER_BUTTON_A,
+ SDL_CONTROLLER_BUTTON_B,
+ SDL_CONTROLLER_BUTTON_X,
+ SDL_CONTROLLER_BUTTON_Y,
+ SDL_CONTROLLER_BUTTON_BACK,
+ SDL_CONTROLLER_BUTTON_GUIDE,
+ SDL_CONTROLLER_BUTTON_START,
+ SDL_CONTROLLER_BUTTON_LEFTSTICK,
+ SDL_CONTROLLER_BUTTON_RIGHTSTICK,
+ SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
+ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
+ SDL_CONTROLLER_BUTTON_DPAD_UP,
+ SDL_CONTROLLER_BUTTON_DPAD_DOWN,
+ SDL_CONTROLLER_BUTTON_DPAD_LEFT,
+ SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
+ SDL_CONTROLLER_BUTTON_MAX
+} SDL_GameControllerButton;
+
+/**
+ * turn this string into a button mapping
+ */
+extern DECLSPEC SDL_GameControllerButton SDLCALL SDL_GameControllerGetButtonFromString(const char *pchString);
+
+/**
+ * turn this button enum into a string mapping
+ */
+extern DECLSPEC const char* SDLCALL SDL_GameControllerGetStringForButton(SDL_GameControllerButton button);
+
+/**
+ * Get the SDL joystick layer binding for this controller button mapping
+ */
+extern DECLSPEC SDL_GameControllerButtonBind SDLCALL
+SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller,
+ SDL_GameControllerButton button);
+
+
+/**
+ * Get the current state of a button on a game controller.
+ *
+ * The button indices start at index 0.
+ */
+extern DECLSPEC Uint8 SDLCALL SDL_GameControllerGetButton(SDL_GameController *gamecontroller,
+ SDL_GameControllerButton button);
+
+/**
+ * Close a controller previously opened with SDL_GameControllerOpen().
+ */
+extern DECLSPEC void SDLCALL SDL_GameControllerClose(SDL_GameController *gamecontroller);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_gamecontroller_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_gesture.h b/external/SDL2/include/SDL_gesture.h
new file mode 100644
index 0000000..3c29ca7
--- /dev/null
+++ b/external/SDL2/include/SDL_gesture.h
@@ -0,0 +1,87 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_gesture.h
+ *
+ * Include file for SDL gesture event handling.
+ */
+
+#ifndef _SDL_gesture_h
+#define _SDL_gesture_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_video.h"
+
+#include "SDL_touch.h"
+
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef Sint64 SDL_GestureID;
+
+/* Function prototypes */
+
+/**
+ * \brief Begin Recording a gesture on the specified touch, or all touches (-1)
+ *
+ *
+ */
+extern DECLSPEC int SDLCALL SDL_RecordGesture(SDL_TouchID touchId);
+
+
+/**
+ * \brief Save all currently loaded Dollar Gesture templates
+ *
+ *
+ */
+extern DECLSPEC int SDLCALL SDL_SaveAllDollarTemplates(SDL_RWops *dst);
+
+/**
+ * \brief Save a currently loaded Dollar Gesture template
+ *
+ *
+ */
+extern DECLSPEC int SDLCALL SDL_SaveDollarTemplate(SDL_GestureID gestureId,SDL_RWops *dst);
+
+
+/**
+ * \brief Load Dollar Gesture templates from a file
+ *
+ *
+ */
+extern DECLSPEC int SDLCALL SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_gesture_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_haptic.h b/external/SDL2/include/SDL_haptic.h
new file mode 100644
index 0000000..b36d78b
--- /dev/null
+++ b/external/SDL2/include/SDL_haptic.h
@@ -0,0 +1,1223 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_haptic.h
+ *
+ * \brief The SDL Haptic subsystem allows you to control haptic (force feedback)
+ * devices.
+ *
+ * The basic usage is as follows:
+ * - Initialize the Subsystem (::SDL_INIT_HAPTIC).
+ * - Open a Haptic Device.
+ * - SDL_HapticOpen() to open from index.
+ * - SDL_HapticOpenFromJoystick() to open from an existing joystick.
+ * - Create an effect (::SDL_HapticEffect).
+ * - Upload the effect with SDL_HapticNewEffect().
+ * - Run the effect with SDL_HapticRunEffect().
+ * - (optional) Free the effect with SDL_HapticDestroyEffect().
+ * - Close the haptic device with SDL_HapticClose().
+ *
+ * \par Simple rumble example:
+ * \code
+ * SDL_Haptic *haptic;
+ *
+ * // Open the device
+ * haptic = SDL_HapticOpen( 0 );
+ * if (haptic == NULL)
+ * return -1;
+ *
+ * // Initialize simple rumble
+ * if (SDL_HapticRumbleInit( haptic ) != 0)
+ * return -1;
+ *
+ * // Play effect at 50% strength for 2 seconds
+ * if (SDL_HapticRumblePlay( haptic, 0.5, 2000 ) != 0)
+ * return -1;
+ * SDL_Delay( 2000 );
+ *
+ * // Clean up
+ * SDL_HapticClose( haptic );
+ * \endcode
+ *
+ * \par Complete example:
+ * \code
+ * int test_haptic( SDL_Joystick * joystick ) {
+ * SDL_Haptic *haptic;
+ * SDL_HapticEffect effect;
+ * int effect_id;
+ *
+ * // Open the device
+ * haptic = SDL_HapticOpenFromJoystick( joystick );
+ * if (haptic == NULL) return -1; // Most likely joystick isn't haptic
+ *
+ * // See if it can do sine waves
+ * if ((SDL_HapticQuery(haptic) & SDL_HAPTIC_SINE)==0) {
+ * SDL_HapticClose(haptic); // No sine effect
+ * return -1;
+ * }
+ *
+ * // Create the effect
+ * memset( &effect, 0, sizeof(SDL_HapticEffect) ); // 0 is safe default
+ * effect.type = SDL_HAPTIC_SINE;
+ * effect.periodic.direction.type = SDL_HAPTIC_POLAR; // Polar coordinates
+ * effect.periodic.direction.dir[0] = 18000; // Force comes from south
+ * effect.periodic.period = 1000; // 1000 ms
+ * effect.periodic.magnitude = 20000; // 20000/32767 strength
+ * effect.periodic.length = 5000; // 5 seconds long
+ * effect.periodic.attack_length = 1000; // Takes 1 second to get max strength
+ * effect.periodic.fade_length = 1000; // Takes 1 second to fade away
+ *
+ * // Upload the effect
+ * effect_id = SDL_HapticNewEffect( haptic, &effect );
+ *
+ * // Test the effect
+ * SDL_HapticRunEffect( haptic, effect_id, 1 );
+ * SDL_Delay( 5000); // Wait for the effect to finish
+ *
+ * // We destroy the effect, although closing the device also does this
+ * SDL_HapticDestroyEffect( haptic, effect_id );
+ *
+ * // Close the device
+ * SDL_HapticClose(haptic);
+ *
+ * return 0; // Success
+ * }
+ * \endcode
+ */
+
+#ifndef _SDL_haptic_h
+#define _SDL_haptic_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_joystick.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * \typedef SDL_Haptic
+ *
+ * \brief The haptic structure used to identify an SDL haptic.
+ *
+ * \sa SDL_HapticOpen
+ * \sa SDL_HapticOpenFromJoystick
+ * \sa SDL_HapticClose
+ */
+struct _SDL_Haptic;
+typedef struct _SDL_Haptic SDL_Haptic;
+
+
+/**
+ * \name Haptic features
+ *
+ * Different haptic features a device can have.
+ */
+/* @{ */
+
+/**
+ * \name Haptic effects
+ */
+/* @{ */
+
+/**
+ * \brief Constant effect supported.
+ *
+ * Constant haptic effect.
+ *
+ * \sa SDL_HapticCondition
+ */
+#define SDL_HAPTIC_CONSTANT (1<<0)
+
+/**
+ * \brief Sine wave effect supported.
+ *
+ * Periodic haptic effect that simulates sine waves.
+ *
+ * \sa SDL_HapticPeriodic
+ */
+#define SDL_HAPTIC_SINE (1<<1)
+
+/**
+ * \brief Left/Right effect supported.
+ *
+ * Haptic effect for direct control over high/low frequency motors.
+ *
+ * \sa SDL_HapticLeftRight
+ * \warning this value was SDL_HAPTIC_SQUARE right before 2.0.0 shipped. Sorry,
+ * we ran out of bits, and this is important for XInput devices.
+ */
+#define SDL_HAPTIC_LEFTRIGHT (1<<2)
+
+/* !!! FIXME: put this back when we have more bits in 2.1 */
+/* #define SDL_HAPTIC_SQUARE (1<<2) */
+
+/**
+ * \brief Triangle wave effect supported.
+ *
+ * Periodic haptic effect that simulates triangular waves.
+ *
+ * \sa SDL_HapticPeriodic
+ */
+#define SDL_HAPTIC_TRIANGLE (1<<3)
+
+/**
+ * \brief Sawtoothup wave effect supported.
+ *
+ * Periodic haptic effect that simulates saw tooth up waves.
+ *
+ * \sa SDL_HapticPeriodic
+ */
+#define SDL_HAPTIC_SAWTOOTHUP (1<<4)
+
+/**
+ * \brief Sawtoothdown wave effect supported.
+ *
+ * Periodic haptic effect that simulates saw tooth down waves.
+ *
+ * \sa SDL_HapticPeriodic
+ */
+#define SDL_HAPTIC_SAWTOOTHDOWN (1<<5)
+
+/**
+ * \brief Ramp effect supported.
+ *
+ * Ramp haptic effect.
+ *
+ * \sa SDL_HapticRamp
+ */
+#define SDL_HAPTIC_RAMP (1<<6)
+
+/**
+ * \brief Spring effect supported - uses axes position.
+ *
+ * Condition haptic effect that simulates a spring. Effect is based on the
+ * axes position.
+ *
+ * \sa SDL_HapticCondition
+ */
+#define SDL_HAPTIC_SPRING (1<<7)
+
+/**
+ * \brief Damper effect supported - uses axes velocity.
+ *
+ * Condition haptic effect that simulates dampening. Effect is based on the
+ * axes velocity.
+ *
+ * \sa SDL_HapticCondition
+ */
+#define SDL_HAPTIC_DAMPER (1<<8)
+
+/**
+ * \brief Inertia effect supported - uses axes acceleration.
+ *
+ * Condition haptic effect that simulates inertia. Effect is based on the axes
+ * acceleration.
+ *
+ * \sa SDL_HapticCondition
+ */
+#define SDL_HAPTIC_INERTIA (1<<9)
+
+/**
+ * \brief Friction effect supported - uses axes movement.
+ *
+ * Condition haptic effect that simulates friction. Effect is based on the
+ * axes movement.
+ *
+ * \sa SDL_HapticCondition
+ */
+#define SDL_HAPTIC_FRICTION (1<<10)
+
+/**
+ * \brief Custom effect is supported.
+ *
+ * User defined custom haptic effect.
+ */
+#define SDL_HAPTIC_CUSTOM (1<<11)
+
+/* @} *//* Haptic effects */
+
+/* These last few are features the device has, not effects */
+
+/**
+ * \brief Device can set global gain.
+ *
+ * Device supports setting the global gain.
+ *
+ * \sa SDL_HapticSetGain
+ */
+#define SDL_HAPTIC_GAIN (1<<12)
+
+/**
+ * \brief Device can set autocenter.
+ *
+ * Device supports setting autocenter.
+ *
+ * \sa SDL_HapticSetAutocenter
+ */
+#define SDL_HAPTIC_AUTOCENTER (1<<13)
+
+/**
+ * \brief Device can be queried for effect status.
+ *
+ * Device can be queried for effect status.
+ *
+ * \sa SDL_HapticGetEffectStatus
+ */
+#define SDL_HAPTIC_STATUS (1<<14)
+
+/**
+ * \brief Device can be paused.
+ *
+ * \sa SDL_HapticPause
+ * \sa SDL_HapticUnpause
+ */
+#define SDL_HAPTIC_PAUSE (1<<15)
+
+
+/**
+ * \name Direction encodings
+ */
+/* @{ */
+
+/**
+ * \brief Uses polar coordinates for the direction.
+ *
+ * \sa SDL_HapticDirection
+ */
+#define SDL_HAPTIC_POLAR 0
+
+/**
+ * \brief Uses cartesian coordinates for the direction.
+ *
+ * \sa SDL_HapticDirection
+ */
+#define SDL_HAPTIC_CARTESIAN 1
+
+/**
+ * \brief Uses spherical coordinates for the direction.
+ *
+ * \sa SDL_HapticDirection
+ */
+#define SDL_HAPTIC_SPHERICAL 2
+
+/* @} *//* Direction encodings */
+
+/* @} *//* Haptic features */
+
+/*
+ * Misc defines.
+ */
+
+/**
+ * \brief Used to play a device an infinite number of times.
+ *
+ * \sa SDL_HapticRunEffect
+ */
+#define SDL_HAPTIC_INFINITY 4294967295U
+
+
+/**
+ * \brief Structure that represents a haptic direction.
+ *
+ * This is the direction where the force comes from,
+ * instead of the direction in which the force is exerted.
+ *
+ * Directions can be specified by:
+ * - ::SDL_HAPTIC_POLAR : Specified by polar coordinates.
+ * - ::SDL_HAPTIC_CARTESIAN : Specified by cartesian coordinates.
+ * - ::SDL_HAPTIC_SPHERICAL : Specified by spherical coordinates.
+ *
+ * Cardinal directions of the haptic device are relative to the positioning
+ * of the device. North is considered to be away from the user.
+ *
+ * The following diagram represents the cardinal directions:
+ * \verbatim
+ .--.
+ |__| .-------.
+ |=.| |.-----.|
+ |--| || ||
+ | | |'-----'|
+ |__|~')_____('
+ [ COMPUTER ]
+
+
+ North (0,-1)
+ ^
+ |
+ |
+ (-1,0) West <----[ HAPTIC ]----> East (1,0)
+ |
+ |
+ v
+ South (0,1)
+
+
+ [ USER ]
+ \|||/
+ (o o)
+ ---ooO-(_)-Ooo---
+ \endverbatim
+ *
+ * If type is ::SDL_HAPTIC_POLAR, direction is encoded by hundredths of a
+ * degree starting north and turning clockwise. ::SDL_HAPTIC_POLAR only uses
+ * the first \c dir parameter. The cardinal directions would be:
+ * - North: 0 (0 degrees)
+ * - East: 9000 (90 degrees)
+ * - South: 18000 (180 degrees)
+ * - West: 27000 (270 degrees)
+ *
+ * If type is ::SDL_HAPTIC_CARTESIAN, direction is encoded by three positions
+ * (X axis, Y axis and Z axis (with 3 axes)). ::SDL_HAPTIC_CARTESIAN uses
+ * the first three \c dir parameters. The cardinal directions would be:
+ * - North: 0,-1, 0
+ * - East: 1, 0, 0
+ * - South: 0, 1, 0
+ * - West: -1, 0, 0
+ *
+ * The Z axis represents the height of the effect if supported, otherwise
+ * it's unused. In cartesian encoding (1, 2) would be the same as (2, 4), you
+ * can use any multiple you want, only the direction matters.
+ *
+ * If type is ::SDL_HAPTIC_SPHERICAL, direction is encoded by two rotations.
+ * The first two \c dir parameters are used. The \c dir parameters are as
+ * follows (all values are in hundredths of degrees):
+ * - Degrees from (1, 0) rotated towards (0, 1).
+ * - Degrees towards (0, 0, 1) (device needs at least 3 axes).
+ *
+ *
+ * Example of force coming from the south with all encodings (force coming
+ * from the south means the user will have to pull the stick to counteract):
+ * \code
+ * SDL_HapticDirection direction;
+ *
+ * // Cartesian directions
+ * direction.type = SDL_HAPTIC_CARTESIAN; // Using cartesian direction encoding.
+ * direction.dir[0] = 0; // X position
+ * direction.dir[1] = 1; // Y position
+ * // Assuming the device has 2 axes, we don't need to specify third parameter.
+ *
+ * // Polar directions
+ * direction.type = SDL_HAPTIC_POLAR; // We'll be using polar direction encoding.
+ * direction.dir[0] = 18000; // Polar only uses first parameter
+ *
+ * // Spherical coordinates
+ * direction.type = SDL_HAPTIC_SPHERICAL; // Spherical encoding
+ * direction.dir[0] = 9000; // Since we only have two axes we don't need more parameters.
+ * \endcode
+ *
+ * \sa SDL_HAPTIC_POLAR
+ * \sa SDL_HAPTIC_CARTESIAN
+ * \sa SDL_HAPTIC_SPHERICAL
+ * \sa SDL_HapticEffect
+ * \sa SDL_HapticNumAxes
+ */
+typedef struct SDL_HapticDirection
+{
+ Uint8 type; /**< The type of encoding. */
+ Sint32 dir[3]; /**< The encoded direction. */
+} SDL_HapticDirection;
+
+
+/**
+ * \brief A structure containing a template for a Constant effect.
+ *
+ * The struct is exclusive to the ::SDL_HAPTIC_CONSTANT effect.
+ *
+ * A constant effect applies a constant force in the specified direction
+ * to the joystick.
+ *
+ * \sa SDL_HAPTIC_CONSTANT
+ * \sa SDL_HapticEffect
+ */
+typedef struct SDL_HapticConstant
+{
+ /* Header */
+ Uint16 type; /**< ::SDL_HAPTIC_CONSTANT */
+ SDL_HapticDirection direction; /**< Direction of the effect. */
+
+ /* Replay */
+ Uint32 length; /**< Duration of the effect. */
+ Uint16 delay; /**< Delay before starting the effect. */
+
+ /* Trigger */
+ Uint16 button; /**< Button that triggers the effect. */
+ Uint16 interval; /**< How soon it can be triggered again after button. */
+
+ /* Constant */
+ Sint16 level; /**< Strength of the constant effect. */
+
+ /* Envelope */
+ Uint16 attack_length; /**< Duration of the attack. */
+ Uint16 attack_level; /**< Level at the start of the attack. */
+ Uint16 fade_length; /**< Duration of the fade. */
+ Uint16 fade_level; /**< Level at the end of the fade. */
+} SDL_HapticConstant;
+
+/**
+ * \brief A structure containing a template for a Periodic effect.
+ *
+ * The struct handles the following effects:
+ * - ::SDL_HAPTIC_SINE
+ * - ::SDL_HAPTIC_LEFTRIGHT
+ * - ::SDL_HAPTIC_TRIANGLE
+ * - ::SDL_HAPTIC_SAWTOOTHUP
+ * - ::SDL_HAPTIC_SAWTOOTHDOWN
+ *
+ * A periodic effect consists in a wave-shaped effect that repeats itself
+ * over time. The type determines the shape of the wave and the parameters
+ * determine the dimensions of the wave.
+ *
+ * Phase is given by hundredth of a degree meaning that giving the phase a value
+ * of 9000 will displace it 25% of its period. Here are sample values:
+ * - 0: No phase displacement.
+ * - 9000: Displaced 25% of its period.
+ * - 18000: Displaced 50% of its period.
+ * - 27000: Displaced 75% of its period.
+ * - 36000: Displaced 100% of its period, same as 0, but 0 is preferred.
+ *
+ * Examples:
+ * \verbatim
+ SDL_HAPTIC_SINE
+ __ __ __ __
+ / \ / \ / \ /
+ / \__/ \__/ \__/
+
+ SDL_HAPTIC_SQUARE
+ __ __ __ __ __
+ | | | | | | | | | |
+ | |__| |__| |__| |__| |
+
+ SDL_HAPTIC_TRIANGLE
+ /\ /\ /\ /\ /\
+ / \ / \ / \ / \ /
+ / \/ \/ \/ \/
+
+ SDL_HAPTIC_SAWTOOTHUP
+ /| /| /| /| /| /| /|
+ / | / | / | / | / | / | / |
+ / |/ |/ |/ |/ |/ |/ |
+
+ SDL_HAPTIC_SAWTOOTHDOWN
+ \ |\ |\ |\ |\ |\ |\ |
+ \ | \ | \ | \ | \ | \ | \ |
+ \| \| \| \| \| \| \|
+ \endverbatim
+ *
+ * \sa SDL_HAPTIC_SINE
+ * \sa SDL_HAPTIC_LEFTRIGHT
+ * \sa SDL_HAPTIC_TRIANGLE
+ * \sa SDL_HAPTIC_SAWTOOTHUP
+ * \sa SDL_HAPTIC_SAWTOOTHDOWN
+ * \sa SDL_HapticEffect
+ */
+typedef struct SDL_HapticPeriodic
+{
+ /* Header */
+ Uint16 type; /**< ::SDL_HAPTIC_SINE, ::SDL_HAPTIC_LEFTRIGHT,
+ ::SDL_HAPTIC_TRIANGLE, ::SDL_HAPTIC_SAWTOOTHUP or
+ ::SDL_HAPTIC_SAWTOOTHDOWN */
+ SDL_HapticDirection direction; /**< Direction of the effect. */
+
+ /* Replay */
+ Uint32 length; /**< Duration of the effect. */
+ Uint16 delay; /**< Delay before starting the effect. */
+
+ /* Trigger */
+ Uint16 button; /**< Button that triggers the effect. */
+ Uint16 interval; /**< How soon it can be triggered again after button. */
+
+ /* Periodic */
+ Uint16 period; /**< Period of the wave. */
+ Sint16 magnitude; /**< Peak value; if negative, equivalent to 180 degrees extra phase shift. */
+ Sint16 offset; /**< Mean value of the wave. */
+ Uint16 phase; /**< Positive phase shift given by hundredth of a degree. */
+
+ /* Envelope */
+ Uint16 attack_length; /**< Duration of the attack. */
+ Uint16 attack_level; /**< Level at the start of the attack. */
+ Uint16 fade_length; /**< Duration of the fade. */
+ Uint16 fade_level; /**< Level at the end of the fade. */
+} SDL_HapticPeriodic;
+
+/**
+ * \brief A structure containing a template for a Condition effect.
+ *
+ * The struct handles the following effects:
+ * - ::SDL_HAPTIC_SPRING: Effect based on axes position.
+ * - ::SDL_HAPTIC_DAMPER: Effect based on axes velocity.
+ * - ::SDL_HAPTIC_INERTIA: Effect based on axes acceleration.
+ * - ::SDL_HAPTIC_FRICTION: Effect based on axes movement.
+ *
+ * Direction is handled by condition internals instead of a direction member.
+ * The condition effect specific members have three parameters. The first
+ * refers to the X axis, the second refers to the Y axis and the third
+ * refers to the Z axis. The right terms refer to the positive side of the
+ * axis and the left terms refer to the negative side of the axis. Please
+ * refer to the ::SDL_HapticDirection diagram for which side is positive and
+ * which is negative.
+ *
+ * \sa SDL_HapticDirection
+ * \sa SDL_HAPTIC_SPRING
+ * \sa SDL_HAPTIC_DAMPER
+ * \sa SDL_HAPTIC_INERTIA
+ * \sa SDL_HAPTIC_FRICTION
+ * \sa SDL_HapticEffect
+ */
+typedef struct SDL_HapticCondition
+{
+ /* Header */
+ Uint16 type; /**< ::SDL_HAPTIC_SPRING, ::SDL_HAPTIC_DAMPER,
+ ::SDL_HAPTIC_INERTIA or ::SDL_HAPTIC_FRICTION */
+ SDL_HapticDirection direction; /**< Direction of the effect - Not used ATM. */
+
+ /* Replay */
+ Uint32 length; /**< Duration of the effect. */
+ Uint16 delay; /**< Delay before starting the effect. */
+
+ /* Trigger */
+ Uint16 button; /**< Button that triggers the effect. */
+ Uint16 interval; /**< How soon it can be triggered again after button. */
+
+ /* Condition */
+ Uint16 right_sat[3]; /**< Level when joystick is to the positive side; max 0xFFFF. */
+ Uint16 left_sat[3]; /**< Level when joystick is to the negative side; max 0xFFFF. */
+ Sint16 right_coeff[3]; /**< How fast to increase the force towards the positive side. */
+ Sint16 left_coeff[3]; /**< How fast to increase the force towards the negative side. */
+ Uint16 deadband[3]; /**< Size of the dead zone; max 0xFFFF: whole axis-range when 0-centered. */
+ Sint16 center[3]; /**< Position of the dead zone. */
+} SDL_HapticCondition;
+
+/**
+ * \brief A structure containing a template for a Ramp effect.
+ *
+ * This struct is exclusively for the ::SDL_HAPTIC_RAMP effect.
+ *
+ * The ramp effect starts at start strength and ends at end strength.
+ * It augments in linear fashion. If you use attack and fade with a ramp
+ * the effects get added to the ramp effect making the effect become
+ * quadratic instead of linear.
+ *
+ * \sa SDL_HAPTIC_RAMP
+ * \sa SDL_HapticEffect
+ */
+typedef struct SDL_HapticRamp
+{
+ /* Header */
+ Uint16 type; /**< ::SDL_HAPTIC_RAMP */
+ SDL_HapticDirection direction; /**< Direction of the effect. */
+
+ /* Replay */
+ Uint32 length; /**< Duration of the effect. */
+ Uint16 delay; /**< Delay before starting the effect. */
+
+ /* Trigger */
+ Uint16 button; /**< Button that triggers the effect. */
+ Uint16 interval; /**< How soon it can be triggered again after button. */
+
+ /* Ramp */
+ Sint16 start; /**< Beginning strength level. */
+ Sint16 end; /**< Ending strength level. */
+
+ /* Envelope */
+ Uint16 attack_length; /**< Duration of the attack. */
+ Uint16 attack_level; /**< Level at the start of the attack. */
+ Uint16 fade_length; /**< Duration of the fade. */
+ Uint16 fade_level; /**< Level at the end of the fade. */
+} SDL_HapticRamp;
+
+/**
+ * \brief A structure containing a template for a Left/Right effect.
+ *
+ * This struct is exclusively for the ::SDL_HAPTIC_LEFTRIGHT effect.
+ *
+ * The Left/Right effect is used to explicitly control the large and small
+ * motors, commonly found in modern game controllers. One motor is high
+ * frequency, the other is low frequency.
+ *
+ * \sa SDL_HAPTIC_LEFTRIGHT
+ * \sa SDL_HapticEffect
+ */
+typedef struct SDL_HapticLeftRight
+{
+ /* Header */
+ Uint16 type; /**< ::SDL_HAPTIC_LEFTRIGHT */
+
+ /* Replay */
+ Uint32 length; /**< Duration of the effect. */
+
+ /* Rumble */
+ Uint16 large_magnitude; /**< Control of the large controller motor. */
+ Uint16 small_magnitude; /**< Control of the small controller motor. */
+} SDL_HapticLeftRight;
+
+/**
+ * \brief A structure containing a template for the ::SDL_HAPTIC_CUSTOM effect.
+ *
+ * A custom force feedback effect is much like a periodic effect, where the
+ * application can define its exact shape. You will have to allocate the
+ * data yourself. Data should consist of channels * samples Uint16 samples.
+ *
+ * If channels is one, the effect is rotated using the defined direction.
+ * Otherwise it uses the samples in data for the different axes.
+ *
+ * \sa SDL_HAPTIC_CUSTOM
+ * \sa SDL_HapticEffect
+ */
+typedef struct SDL_HapticCustom
+{
+ /* Header */
+ Uint16 type; /**< ::SDL_HAPTIC_CUSTOM */
+ SDL_HapticDirection direction; /**< Direction of the effect. */
+
+ /* Replay */
+ Uint32 length; /**< Duration of the effect. */
+ Uint16 delay; /**< Delay before starting the effect. */
+
+ /* Trigger */
+ Uint16 button; /**< Button that triggers the effect. */
+ Uint16 interval; /**< How soon it can be triggered again after button. */
+
+ /* Custom */
+ Uint8 channels; /**< Axes to use, minimum of one. */
+ Uint16 period; /**< Sample periods. */
+ Uint16 samples; /**< Amount of samples. */
+ Uint16 *data; /**< Should contain channels*samples items. */
+
+ /* Envelope */
+ Uint16 attack_length; /**< Duration of the attack. */
+ Uint16 attack_level; /**< Level at the start of the attack. */
+ Uint16 fade_length; /**< Duration of the fade. */
+ Uint16 fade_level; /**< Level at the end of the fade. */
+} SDL_HapticCustom;
+
+/**
+ * \brief The generic template for any haptic effect.
+ *
+ * All values max at 32767 (0x7FFF). Signed values also can be negative.
+ * Time values unless specified otherwise are in milliseconds.
+ *
+ * You can also pass ::SDL_HAPTIC_INFINITY to length instead of a 0-32767
+ * value. Neither delay, interval, attack_length nor fade_length support
+ * ::SDL_HAPTIC_INFINITY. Fade will also not be used since effect never ends.
+ *
+ * Additionally, the ::SDL_HAPTIC_RAMP effect does not support a duration of
+ * ::SDL_HAPTIC_INFINITY.
+ *
+ * Button triggers may not be supported on all devices, it is advised to not
+ * use them if possible. Buttons start at index 1 instead of index 0 like
+ * the joystick.
+ *
+ * If both attack_length and fade_level are 0, the envelope is not used,
+ * otherwise both values are used.
+ *
+ * Common parts:
+ * \code
+ * // Replay - All effects have this
+ * Uint32 length; // Duration of effect (ms).
+ * Uint16 delay; // Delay before starting effect.
+ *
+ * // Trigger - All effects have this
+ * Uint16 button; // Button that triggers effect.
+ * Uint16 interval; // How soon before effect can be triggered again.
+ *
+ * // Envelope - All effects except condition effects have this
+ * Uint16 attack_length; // Duration of the attack (ms).
+ * Uint16 attack_level; // Level at the start of the attack.
+ * Uint16 fade_length; // Duration of the fade out (ms).
+ * Uint16 fade_level; // Level at the end of the fade.
+ * \endcode
+ *
+ *
+ * Here we have an example of a constant effect evolution in time:
+ * \verbatim
+ Strength
+ ^
+ |
+ | effect level --> _________________
+ | / \
+ | / \
+ | / \
+ | / \
+ | attack_level --> | \
+ | | | <--- fade_level
+ |
+ +--------------------------------------------------> Time
+ [--] [---]
+ attack_length fade_length
+
+ [------------------][-----------------------]
+ delay length
+ \endverbatim
+ *
+ * Note either the attack_level or the fade_level may be above the actual
+ * effect level.
+ *
+ * \sa SDL_HapticConstant
+ * \sa SDL_HapticPeriodic
+ * \sa SDL_HapticCondition
+ * \sa SDL_HapticRamp
+ * \sa SDL_HapticLeftRight
+ * \sa SDL_HapticCustom
+ */
+typedef union SDL_HapticEffect
+{
+ /* Common for all force feedback effects */
+ Uint16 type; /**< Effect type. */
+ SDL_HapticConstant constant; /**< Constant effect. */
+ SDL_HapticPeriodic periodic; /**< Periodic effect. */
+ SDL_HapticCondition condition; /**< Condition effect. */
+ SDL_HapticRamp ramp; /**< Ramp effect. */
+ SDL_HapticLeftRight leftright; /**< Left/Right effect. */
+ SDL_HapticCustom custom; /**< Custom effect. */
+} SDL_HapticEffect;
+
+
+/* Function prototypes */
+/**
+ * \brief Count the number of haptic devices attached to the system.
+ *
+ * \return Number of haptic devices detected on the system.
+ */
+extern DECLSPEC int SDLCALL SDL_NumHaptics(void);
+
+/**
+ * \brief Get the implementation dependent name of a Haptic device.
+ *
+ * This can be called before any joysticks are opened.
+ * If no name can be found, this function returns NULL.
+ *
+ * \param device_index Index of the device to get its name.
+ * \return Name of the device or NULL on error.
+ *
+ * \sa SDL_NumHaptics
+ */
+extern DECLSPEC const char *SDLCALL SDL_HapticName(int device_index);
+
+/**
+ * \brief Opens a Haptic device for usage.
+ *
+ * The index passed as an argument refers to the N'th Haptic device on this
+ * system.
+ *
+ * When opening a haptic device, its gain will be set to maximum and
+ * autocenter will be disabled. To modify these values use
+ * SDL_HapticSetGain() and SDL_HapticSetAutocenter().
+ *
+ * \param device_index Index of the device to open.
+ * \return Device identifier or NULL on error.
+ *
+ * \sa SDL_HapticIndex
+ * \sa SDL_HapticOpenFromMouse
+ * \sa SDL_HapticOpenFromJoystick
+ * \sa SDL_HapticClose
+ * \sa SDL_HapticSetGain
+ * \sa SDL_HapticSetAutocenter
+ * \sa SDL_HapticPause
+ * \sa SDL_HapticStopAll
+ */
+extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpen(int device_index);
+
+/**
+ * \brief Checks if the haptic device at index has been opened.
+ *
+ * \param device_index Index to check to see if it has been opened.
+ * \return 1 if it has been opened or 0 if it hasn't.
+ *
+ * \sa SDL_HapticOpen
+ * \sa SDL_HapticIndex
+ */
+extern DECLSPEC int SDLCALL SDL_HapticOpened(int device_index);
+
+/**
+ * \brief Gets the index of a haptic device.
+ *
+ * \param haptic Haptic device to get the index of.
+ * \return The index of the haptic device or -1 on error.
+ *
+ * \sa SDL_HapticOpen
+ * \sa SDL_HapticOpened
+ */
+extern DECLSPEC int SDLCALL SDL_HapticIndex(SDL_Haptic * haptic);
+
+/**
+ * \brief Gets whether or not the current mouse has haptic capabilities.
+ *
+ * \return SDL_TRUE if the mouse is haptic, SDL_FALSE if it isn't.
+ *
+ * \sa SDL_HapticOpenFromMouse
+ */
+extern DECLSPEC int SDLCALL SDL_MouseIsHaptic(void);
+
+/**
+ * \brief Tries to open a haptic device from the current mouse.
+ *
+ * \return The haptic device identifier or NULL on error.
+ *
+ * \sa SDL_MouseIsHaptic
+ * \sa SDL_HapticOpen
+ */
+extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpenFromMouse(void);
+
+/**
+ * \brief Checks to see if a joystick has haptic features.
+ *
+ * \param joystick Joystick to test for haptic capabilities.
+ * \return 1 if the joystick is haptic, 0 if it isn't
+ * or -1 if an error ocurred.
+ *
+ * \sa SDL_HapticOpenFromJoystick
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickIsHaptic(SDL_Joystick * joystick);
+
+/**
+ * \brief Opens a Haptic device for usage from a Joystick device.
+ *
+ * You must still close the haptic device separately. It will not be closed
+ * with the joystick.
+ *
+ * When opening from a joystick you should first close the haptic device before
+ * closing the joystick device. If not, on some implementations the haptic
+ * device will also get unallocated and you'll be unable to use force feedback
+ * on that device.
+ *
+ * \param joystick Joystick to create a haptic device from.
+ * \return A valid haptic device identifier on success or NULL on error.
+ *
+ * \sa SDL_HapticOpen
+ * \sa SDL_HapticClose
+ */
+extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpenFromJoystick(SDL_Joystick *
+ joystick);
+
+/**
+ * \brief Closes a Haptic device previously opened with SDL_HapticOpen().
+ *
+ * \param haptic Haptic device to close.
+ */
+extern DECLSPEC void SDLCALL SDL_HapticClose(SDL_Haptic * haptic);
+
+/**
+ * \brief Returns the number of effects a haptic device can store.
+ *
+ * On some platforms this isn't fully supported, and therefore is an
+ * approximation. Always check to see if your created effect was actually
+ * created and do not rely solely on SDL_HapticNumEffects().
+ *
+ * \param haptic The haptic device to query effect max.
+ * \return The number of effects the haptic device can store or
+ * -1 on error.
+ *
+ * \sa SDL_HapticNumEffectsPlaying
+ * \sa SDL_HapticQuery
+ */
+extern DECLSPEC int SDLCALL SDL_HapticNumEffects(SDL_Haptic * haptic);
+
+/**
+ * \brief Returns the number of effects a haptic device can play at the same
+ * time.
+ *
+ * This is not supported on all platforms, but will always return a value.
+ * Added here for the sake of completeness.
+ *
+ * \param haptic The haptic device to query maximum playing effects.
+ * \return The number of effects the haptic device can play at the same time
+ * or -1 on error.
+ *
+ * \sa SDL_HapticNumEffects
+ * \sa SDL_HapticQuery
+ */
+extern DECLSPEC int SDLCALL SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic);
+
+/**
+ * \brief Gets the haptic device's supported features in bitwise manner.
+ *
+ * Example:
+ * \code
+ * if (SDL_HapticQuery(haptic) & SDL_HAPTIC_CONSTANT) {
+ * printf("We have constant haptic effect!");
+ * }
+ * \endcode
+ *
+ * \param haptic The haptic device to query.
+ * \return Haptic features in bitwise manner (OR'd).
+ *
+ * \sa SDL_HapticNumEffects
+ * \sa SDL_HapticEffectSupported
+ */
+extern DECLSPEC unsigned int SDLCALL SDL_HapticQuery(SDL_Haptic * haptic);
+
+
+/**
+ * \brief Gets the number of haptic axes the device has.
+ *
+ * \sa SDL_HapticDirection
+ */
+extern DECLSPEC int SDLCALL SDL_HapticNumAxes(SDL_Haptic * haptic);
+
+/**
+ * \brief Checks to see if effect is supported by haptic.
+ *
+ * \param haptic Haptic device to check on.
+ * \param effect Effect to check to see if it is supported.
+ * \return SDL_TRUE if effect is supported, SDL_FALSE if it isn't or -1 on error.
+ *
+ * \sa SDL_HapticQuery
+ * \sa SDL_HapticNewEffect
+ */
+extern DECLSPEC int SDLCALL SDL_HapticEffectSupported(SDL_Haptic * haptic,
+ SDL_HapticEffect *
+ effect);
+
+/**
+ * \brief Creates a new haptic effect on the device.
+ *
+ * \param haptic Haptic device to create the effect on.
+ * \param effect Properties of the effect to create.
+ * \return The id of the effect on success or -1 on error.
+ *
+ * \sa SDL_HapticUpdateEffect
+ * \sa SDL_HapticRunEffect
+ * \sa SDL_HapticDestroyEffect
+ */
+extern DECLSPEC int SDLCALL SDL_HapticNewEffect(SDL_Haptic * haptic,
+ SDL_HapticEffect * effect);
+
+/**
+ * \brief Updates the properties of an effect.
+ *
+ * Can be used dynamically, although behaviour when dynamically changing
+ * direction may be strange. Specifically the effect may reupload itself
+ * and start playing from the start. You cannot change the type either when
+ * running SDL_HapticUpdateEffect().
+ *
+ * \param haptic Haptic device that has the effect.
+ * \param effect Effect to update.
+ * \param data New effect properties to use.
+ * \return 0 on success or -1 on error.
+ *
+ * \sa SDL_HapticNewEffect
+ * \sa SDL_HapticRunEffect
+ * \sa SDL_HapticDestroyEffect
+ */
+extern DECLSPEC int SDLCALL SDL_HapticUpdateEffect(SDL_Haptic * haptic,
+ int effect,
+ SDL_HapticEffect * data);
+
+/**
+ * \brief Runs the haptic effect on its associated haptic device.
+ *
+ * If iterations are ::SDL_HAPTIC_INFINITY, it'll run the effect over and over
+ * repeating the envelope (attack and fade) every time. If you only want the
+ * effect to last forever, set ::SDL_HAPTIC_INFINITY in the effect's length
+ * parameter.
+ *
+ * \param haptic Haptic device to run the effect on.
+ * \param effect Identifier of the haptic effect to run.
+ * \param iterations Number of iterations to run the effect. Use
+ * ::SDL_HAPTIC_INFINITY for infinity.
+ * \return 0 on success or -1 on error.
+ *
+ * \sa SDL_HapticStopEffect
+ * \sa SDL_HapticDestroyEffect
+ * \sa SDL_HapticGetEffectStatus
+ */
+extern DECLSPEC int SDLCALL SDL_HapticRunEffect(SDL_Haptic * haptic,
+ int effect,
+ Uint32 iterations);
+
+/**
+ * \brief Stops the haptic effect on its associated haptic device.
+ *
+ * \param haptic Haptic device to stop the effect on.
+ * \param effect Identifier of the effect to stop.
+ * \return 0 on success or -1 on error.
+ *
+ * \sa SDL_HapticRunEffect
+ * \sa SDL_HapticDestroyEffect
+ */
+extern DECLSPEC int SDLCALL SDL_HapticStopEffect(SDL_Haptic * haptic,
+ int effect);
+
+/**
+ * \brief Destroys a haptic effect on the device.
+ *
+ * This will stop the effect if it's running. Effects are automatically
+ * destroyed when the device is closed.
+ *
+ * \param haptic Device to destroy the effect on.
+ * \param effect Identifier of the effect to destroy.
+ *
+ * \sa SDL_HapticNewEffect
+ */
+extern DECLSPEC void SDLCALL SDL_HapticDestroyEffect(SDL_Haptic * haptic,
+ int effect);
+
+/**
+ * \brief Gets the status of the current effect on the haptic device.
+ *
+ * Device must support the ::SDL_HAPTIC_STATUS feature.
+ *
+ * \param haptic Haptic device to query the effect status on.
+ * \param effect Identifier of the effect to query its status.
+ * \return 0 if it isn't playing, 1 if it is playing or -1 on error.
+ *
+ * \sa SDL_HapticRunEffect
+ * \sa SDL_HapticStopEffect
+ */
+extern DECLSPEC int SDLCALL SDL_HapticGetEffectStatus(SDL_Haptic * haptic,
+ int effect);
+
+/**
+ * \brief Sets the global gain of the device.
+ *
+ * Device must support the ::SDL_HAPTIC_GAIN feature.
+ *
+ * The user may specify the maximum gain by setting the environment variable
+ * SDL_HAPTIC_GAIN_MAX which should be between 0 and 100. All calls to
+ * SDL_HapticSetGain() will scale linearly using SDL_HAPTIC_GAIN_MAX as the
+ * maximum.
+ *
+ * \param haptic Haptic device to set the gain on.
+ * \param gain Value to set the gain to, should be between 0 and 100.
+ * \return 0 on success or -1 on error.
+ *
+ * \sa SDL_HapticQuery
+ */
+extern DECLSPEC int SDLCALL SDL_HapticSetGain(SDL_Haptic * haptic, int gain);
+
+/**
+ * \brief Sets the global autocenter of the device.
+ *
+ * Autocenter should be between 0 and 100. Setting it to 0 will disable
+ * autocentering.
+ *
+ * Device must support the ::SDL_HAPTIC_AUTOCENTER feature.
+ *
+ * \param haptic Haptic device to set autocentering on.
+ * \param autocenter Value to set autocenter to, 0 disables autocentering.
+ * \return 0 on success or -1 on error.
+ *
+ * \sa SDL_HapticQuery
+ */
+extern DECLSPEC int SDLCALL SDL_HapticSetAutocenter(SDL_Haptic * haptic,
+ int autocenter);
+
+/**
+ * \brief Pauses a haptic device.
+ *
+ * Device must support the ::SDL_HAPTIC_PAUSE feature. Call
+ * SDL_HapticUnpause() to resume playback.
+ *
+ * Do not modify the effects nor add new ones while the device is paused.
+ * That can cause all sorts of weird errors.
+ *
+ * \param haptic Haptic device to pause.
+ * \return 0 on success or -1 on error.
+ *
+ * \sa SDL_HapticUnpause
+ */
+extern DECLSPEC int SDLCALL SDL_HapticPause(SDL_Haptic * haptic);
+
+/**
+ * \brief Unpauses a haptic device.
+ *
+ * Call to unpause after SDL_HapticPause().
+ *
+ * \param haptic Haptic device to unpause.
+ * \return 0 on success or -1 on error.
+ *
+ * \sa SDL_HapticPause
+ */
+extern DECLSPEC int SDLCALL SDL_HapticUnpause(SDL_Haptic * haptic);
+
+/**
+ * \brief Stops all the currently playing effects on a haptic device.
+ *
+ * \param haptic Haptic device to stop.
+ * \return 0 on success or -1 on error.
+ */
+extern DECLSPEC int SDLCALL SDL_HapticStopAll(SDL_Haptic * haptic);
+
+/**
+ * \brief Checks to see if rumble is supported on a haptic device.
+ *
+ * \param haptic Haptic device to check to see if it supports rumble.
+ * \return SDL_TRUE if effect is supported, SDL_FALSE if it isn't or -1 on error.
+ *
+ * \sa SDL_HapticRumbleInit
+ * \sa SDL_HapticRumblePlay
+ * \sa SDL_HapticRumbleStop
+ */
+extern DECLSPEC int SDLCALL SDL_HapticRumbleSupported(SDL_Haptic * haptic);
+
+/**
+ * \brief Initializes the haptic device for simple rumble playback.
+ *
+ * \param haptic Haptic device to initialize for simple rumble playback.
+ * \return 0 on success or -1 on error.
+ *
+ * \sa SDL_HapticOpen
+ * \sa SDL_HapticRumbleSupported
+ * \sa SDL_HapticRumblePlay
+ * \sa SDL_HapticRumbleStop
+ */
+extern DECLSPEC int SDLCALL SDL_HapticRumbleInit(SDL_Haptic * haptic);
+
+/**
+ * \brief Runs simple rumble on a haptic device
+ *
+ * \param haptic Haptic device to play rumble effect on.
+ * \param strength Strength of the rumble to play as a 0-1 float value.
+ * \param length Length of the rumble to play in milliseconds.
+ * \return 0 on success or -1 on error.
+ *
+ * \sa SDL_HapticRumbleSupported
+ * \sa SDL_HapticRumbleInit
+ * \sa SDL_HapticRumbleStop
+ */
+extern DECLSPEC int SDLCALL SDL_HapticRumblePlay(SDL_Haptic * haptic, float strength, Uint32 length );
+
+/**
+ * \brief Stops the simple rumble on a haptic device.
+ *
+ * \param haptic Haptic to stop the rumble on.
+ * \return 0 on success or -1 on error.
+ *
+ * \sa SDL_HapticRumbleSupported
+ * \sa SDL_HapticRumbleInit
+ * \sa SDL_HapticRumblePlay
+ */
+extern DECLSPEC int SDLCALL SDL_HapticRumbleStop(SDL_Haptic * haptic);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_haptic_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_hints.h b/external/SDL2/include/SDL_hints.h
new file mode 100644
index 0000000..3bd5435
--- /dev/null
+++ b/external/SDL2/include/SDL_hints.h
@@ -0,0 +1,711 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_hints.h
+ *
+ * Official documentation for SDL configuration variables
+ *
+ * This file contains functions to set and get configuration hints,
+ * as well as listing each of them alphabetically.
+ *
+ * The convention for naming hints is SDL_HINT_X, where "SDL_X" is
+ * the environment variable that can be used to override the default.
+ *
+ * In general these hints are just that - they may or may not be
+ * supported or applicable on any given platform, but they provide
+ * a way for an application or user to give the library a hint as
+ * to how they would like the library to work.
+ */
+
+#ifndef _SDL_hints_h
+#define _SDL_hints_h
+
+#include "SDL_stdinc.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief A variable controlling how 3D acceleration is used to accelerate the SDL screen surface.
+ *
+ * SDL can try to accelerate the SDL screen surface by using streaming
+ * textures with a 3D rendering engine. This variable controls whether and
+ * how this is done.
+ *
+ * This variable can be set to the following values:
+ * "0" - Disable 3D acceleration
+ * "1" - Enable 3D acceleration, using the default renderer.
+ * "X" - Enable 3D acceleration, using X where X is one of the valid rendering drivers. (e.g. "direct3d", "opengl", etc.)
+ *
+ * By default SDL tries to make a best guess for each platform whether
+ * to use acceleration or not.
+ */
+#define SDL_HINT_FRAMEBUFFER_ACCELERATION "SDL_FRAMEBUFFER_ACCELERATION"
+
+/**
+ * \brief A variable specifying which render driver to use.
+ *
+ * If the application doesn't pick a specific renderer to use, this variable
+ * specifies the name of the preferred renderer. If the preferred renderer
+ * can't be initialized, the normal default renderer is used.
+ *
+ * This variable is case insensitive and can be set to the following values:
+ * "direct3d"
+ * "opengl"
+ * "opengles2"
+ * "opengles"
+ * "software"
+ *
+ * The default varies by platform, but it's the first one in the list that
+ * is available on the current platform.
+ */
+#define SDL_HINT_RENDER_DRIVER "SDL_RENDER_DRIVER"
+
+/**
+ * \brief A variable controlling whether the OpenGL render driver uses shaders if they are available.
+ *
+ * This variable can be set to the following values:
+ * "0" - Disable shaders
+ * "1" - Enable shaders
+ *
+ * By default shaders are used if OpenGL supports them.
+ */
+#define SDL_HINT_RENDER_OPENGL_SHADERS "SDL_RENDER_OPENGL_SHADERS"
+
+/**
+ * \brief A variable controlling whether the Direct3D device is initialized for thread-safe operations.
+ *
+ * This variable can be set to the following values:
+ * "0" - Thread-safety is not enabled (faster)
+ * "1" - Thread-safety is enabled
+ *
+ * By default the Direct3D device is created with thread-safety disabled.
+ */
+#define SDL_HINT_RENDER_DIRECT3D_THREADSAFE "SDL_RENDER_DIRECT3D_THREADSAFE"
+
+/**
+ * \brief A variable controlling whether to enable Direct3D 11+'s Debug Layer.
+ *
+ * This variable does not have any effect on the Direct3D 9 based renderer.
+ *
+ * This variable can be set to the following values:
+ * "0" - Disable Debug Layer use
+ * "1" - Enable Debug Layer use
+ *
+ * By default, SDL does not use Direct3D Debug Layer.
+ */
+#define SDL_HINT_RENDER_DIRECT3D11_DEBUG "SDL_RENDER_DIRECT3D11_DEBUG"
+
+/**
+ * \brief A variable controlling the scaling quality
+ *
+ * This variable can be set to the following values:
+ * "0" or "nearest" - Nearest pixel sampling
+ * "1" or "linear" - Linear filtering (supported by OpenGL and Direct3D)
+ * "2" or "best" - Currently this is the same as "linear"
+ *
+ * By default nearest pixel sampling is used
+ */
+#define SDL_HINT_RENDER_SCALE_QUALITY "SDL_RENDER_SCALE_QUALITY"
+
+/**
+ * \brief A variable controlling whether updates to the SDL screen surface should be synchronized with the vertical refresh, to avoid tearing.
+ *
+ * This variable can be set to the following values:
+ * "0" - Disable vsync
+ * "1" - Enable vsync
+ *
+ * By default SDL does not sync screen surface updates with vertical refresh.
+ */
+#define SDL_HINT_RENDER_VSYNC "SDL_RENDER_VSYNC"
+
+/**
+ * \brief A variable controlling whether the screensaver is enabled.
+ *
+ * This variable can be set to the following values:
+ * "0" - Disable screensaver
+ * "1" - Enable screensaver
+ *
+ * By default SDL will disable the screensaver.
+ */
+#define SDL_HINT_VIDEO_ALLOW_SCREENSAVER "SDL_VIDEO_ALLOW_SCREENSAVER"
+
+/**
+ * \brief A variable controlling whether the X11 VidMode extension should be used.
+ *
+ * This variable can be set to the following values:
+ * "0" - Disable XVidMode
+ * "1" - Enable XVidMode
+ *
+ * By default SDL will use XVidMode if it is available.
+ */
+#define SDL_HINT_VIDEO_X11_XVIDMODE "SDL_VIDEO_X11_XVIDMODE"
+
+/**
+ * \brief A variable controlling whether the X11 Xinerama extension should be used.
+ *
+ * This variable can be set to the following values:
+ * "0" - Disable Xinerama
+ * "1" - Enable Xinerama
+ *
+ * By default SDL will use Xinerama if it is available.
+ */
+#define SDL_HINT_VIDEO_X11_XINERAMA "SDL_VIDEO_X11_XINERAMA"
+
+/**
+ * \brief A variable controlling whether the X11 XRandR extension should be used.
+ *
+ * This variable can be set to the following values:
+ * "0" - Disable XRandR
+ * "1" - Enable XRandR
+ *
+ * By default SDL will not use XRandR because of window manager issues.
+ */
+#define SDL_HINT_VIDEO_X11_XRANDR "SDL_VIDEO_X11_XRANDR"
+
+/**
+ * \brief A variable controlling whether the X11 _NET_WM_PING protocol should be supported.
+ *
+ * This variable can be set to the following values:
+ * "0" - Disable _NET_WM_PING
+ * "1" - Enable _NET_WM_PING
+ *
+ * By default SDL will use _NET_WM_PING, but for applications that know they
+ * will not always be able to respond to ping requests in a timely manner they can
+ * turn it off to avoid the window manager thinking the app is hung.
+ * The hint is checked in CreateWindow.
+ */
+#define SDL_HINT_VIDEO_X11_NET_WM_PING "SDL_VIDEO_X11_NET_WM_PING"
+
+/**
+ * \brief A variable controlling whether the window frame and title bar are interactive when the cursor is hidden
+ *
+ * This variable can be set to the following values:
+ * "0" - The window frame is not interactive when the cursor is hidden (no move, resize, etc)
+ * "1" - The window frame is interactive when the cursor is hidden
+ *
+ * By default SDL will allow interaction with the window frame when the cursor is hidden
+ */
+#define SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN "SDL_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN"
+
+/**
+ * \brief A variable controlling whether the windows message loop is processed by SDL
+ *
+ * This variable can be set to the following values:
+ * "0" - The window message loop is not run
+ * "1" - The window message loop is processed in SDL_PumpEvents()
+ *
+ * By default SDL will process the windows message loop
+ */
+#define SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP "SDL_WINDOWS_ENABLE_MESSAGELOOP"
+
+/**
+ * \brief A variable controlling whether grabbing input grabs the keyboard
+ *
+ * This variable can be set to the following values:
+ * "0" - Grab will affect only the mouse
+ * "1" - Grab will affect mouse and keyboard
+ *
+ * By default SDL will not grab the keyboard so system shortcuts still work.
+ */
+#define SDL_HINT_GRAB_KEYBOARD "SDL_GRAB_KEYBOARD"
+
+/**
+* \brief A variable controlling whether relative mouse mode is implemented using mouse warping
+*
+* This variable can be set to the following values:
+* "0" - Relative mouse mode uses raw input
+* "1" - Relative mouse mode uses mouse warping
+*
+* By default SDL will use raw input for relative mouse mode
+*/
+#define SDL_HINT_MOUSE_RELATIVE_MODE_WARP "SDL_MOUSE_RELATIVE_MODE_WARP"
+
+/**
+ * \brief Minimize your SDL_Window if it loses key focus when in fullscreen mode. Defaults to true.
+ *
+ */
+#define SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS "SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS"
+
+/**
+ * \brief A variable controlling whether the idle timer is disabled on iOS.
+ *
+ * When an iOS app does not receive touches for some time, the screen is
+ * dimmed automatically. For games where the accelerometer is the only input
+ * this is problematic. This functionality can be disabled by setting this
+ * hint.
+ *
+ * As of SDL 2.0.4, SDL_EnableScreenSaver and SDL_DisableScreenSaver accomplish
+ * the same thing on iOS. They should be preferred over this hint.
+ *
+ * This variable can be set to the following values:
+ * "0" - Enable idle timer
+ * "1" - Disable idle timer
+ */
+#define SDL_HINT_IDLE_TIMER_DISABLED "SDL_IOS_IDLE_TIMER_DISABLED"
+
+/**
+ * \brief A variable controlling which orientations are allowed on iOS.
+ *
+ * In some circumstances it is necessary to be able to explicitly control
+ * which UI orientations are allowed.
+ *
+ * This variable is a space delimited list of the following values:
+ * "LandscapeLeft", "LandscapeRight", "Portrait" "PortraitUpsideDown"
+ */
+#define SDL_HINT_ORIENTATIONS "SDL_IOS_ORIENTATIONS"
+
+/**
+ * \brief A variable controlling whether the Android / iOS built-in
+ * accelerometer should be listed as a joystick device, rather than listing
+ * actual joysticks only.
+ *
+ * This variable can be set to the following values:
+ * "0" - List only real joysticks and accept input from them
+ * "1" - List real joysticks along with the accelerometer as if it were a 3 axis joystick (the default).
+ */
+#define SDL_HINT_ACCELEROMETER_AS_JOYSTICK "SDL_ACCELEROMETER_AS_JOYSTICK"
+
+
+/**
+ * \brief A variable that lets you disable the detection and use of Xinput gamepad devices
+ *
+ * The variable can be set to the following values:
+ * "0" - Disable XInput detection (only uses direct input)
+ * "1" - Enable XInput detection (the default)
+ */
+#define SDL_HINT_XINPUT_ENABLED "SDL_XINPUT_ENABLED"
+
+
+/**
+ * \brief A variable that causes SDL to use the old axis and button mapping for XInput devices.
+ *
+ * This hint is for backwards compatibility only and will be removed in SDL 2.1
+ *
+ * The default value is "0". This hint must be set before SDL_Init()
+ */
+#define SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING "SDL_XINPUT_USE_OLD_JOYSTICK_MAPPING"
+
+
+/**
+ * \brief A variable that lets you manually hint extra gamecontroller db entries
+ *
+ * The variable should be newline delimited rows of gamecontroller config data, see SDL_gamecontroller.h
+ *
+ * This hint must be set before calling SDL_Init(SDL_INIT_GAMECONTROLLER)
+ * You can update mappings after the system is initialized with SDL_GameControllerMappingForGUID() and SDL_GameControllerAddMapping()
+ */
+#define SDL_HINT_GAMECONTROLLERCONFIG "SDL_GAMECONTROLLERCONFIG"
+
+
+/**
+ * \brief A variable that lets you enable joystick (and gamecontroller) events even when your app is in the background.
+ *
+ * The variable can be set to the following values:
+ * "0" - Disable joystick & gamecontroller input events when the
+ * application is in the background.
+ * "1" - Enable joystick & gamecontroller input events when the
+ * application is in the background.
+ *
+ * The default value is "0". This hint may be set at any time.
+ */
+#define SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"
+
+
+/**
+ * \brief If set to "0" then never set the top most bit on a SDL Window, even if the video mode expects it.
+ * This is a debugging aid for developers and not expected to be used by end users. The default is "1"
+ *
+ * This variable can be set to the following values:
+ * "0" - don't allow topmost
+ * "1" - allow topmost
+ */
+#define SDL_HINT_ALLOW_TOPMOST "SDL_ALLOW_TOPMOST"
+
+
+/**
+ * \brief A variable that controls the timer resolution, in milliseconds.
+ *
+ * The higher resolution the timer, the more frequently the CPU services
+ * timer interrupts, and the more precise delays are, but this takes up
+ * power and CPU time. This hint is only used on Windows 7 and earlier.
+ *
+ * See this blog post for more information:
+ * http://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/
+ *
+ * If this variable is set to "0", the system timer resolution is not set.
+ *
+ * The default value is "1". This hint may be set at any time.
+ */
+#define SDL_HINT_TIMER_RESOLUTION "SDL_TIMER_RESOLUTION"
+
+
+
+/**
+* \brief A string specifying SDL's threads stack size in bytes or "0" for the backend's default size
+*
+* Use this hint in case you need to set SDL's threads stack size to other than the default.
+* This is specially useful if you build SDL against a non glibc libc library (such as musl) which
+* provides a relatively small default thread stack size (a few kilobytes versus the default 8MB glibc uses).
+* Support for this hint is currently available only in the pthread backend.
+*/
+#define SDL_HINT_THREAD_STACK_SIZE "SDL_THREAD_STACK_SIZE"
+
+/**
+ * \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac and iOS)
+ */
+#define SDL_HINT_VIDEO_HIGHDPI_DISABLED "SDL_VIDEO_HIGHDPI_DISABLED"
+
+/**
+ * \brief A variable that determines whether ctrl+click should generate a right-click event on Mac
+ *
+ * If present, holding ctrl while left clicking will generate a right click
+ * event when on Mac.
+ */
+#define SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK "SDL_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK"
+
+/**
+* \brief A variable specifying which shader compiler to preload when using the Chrome ANGLE binaries
+*
+* SDL has EGL and OpenGL ES2 support on Windows via the ANGLE project. It
+* can use two different sets of binaries, those compiled by the user from source
+* or those provided by the Chrome browser. In the later case, these binaries require
+* that SDL loads a DLL providing the shader compiler.
+*
+* This variable can be set to the following values:
+* "d3dcompiler_46.dll" - default, best for Vista or later.
+* "d3dcompiler_43.dll" - for XP support.
+* "none" - do not load any library, useful if you compiled ANGLE from source and included the compiler in your binaries.
+*
+*/
+#define SDL_HINT_VIDEO_WIN_D3DCOMPILER "SDL_VIDEO_WIN_D3DCOMPILER"
+
+/**
+* \brief A variable that is the address of another SDL_Window* (as a hex string formatted with "%p").
+*
+* If this hint is set before SDL_CreateWindowFrom() and the SDL_Window* it is set to has
+* SDL_WINDOW_OPENGL set (and running on WGL only, currently), then two things will occur on the newly
+* created SDL_Window:
+*
+* 1. Its pixel format will be set to the same pixel format as this SDL_Window. This is
+* needed for example when sharing an OpenGL context across multiple windows.
+*
+* 2. The flag SDL_WINDOW_OPENGL will be set on the new window so it can be used for
+* OpenGL rendering.
+*
+* This variable can be set to the following values:
+* The address (as a string "%p") of the SDL_Window* that new windows created with SDL_CreateWindowFrom() should
+* share a pixel format with.
+*/
+#define SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT "SDL_VIDEO_WINDOW_SHARE_PIXEL_FORMAT"
+
+/**
+ * \brief A URL to a WinRT app's privacy policy
+ *
+ * All network-enabled WinRT apps must make a privacy policy available to its
+ * users. On Windows 8, 8.1, and RT, Microsoft mandates that this policy be
+ * be available in the Windows Settings charm, as accessed from within the app.
+ * SDL provides code to add a URL-based link there, which can point to the app's
+ * privacy policy.
+ *
+ * To setup a URL to an app's privacy policy, set SDL_HINT_WINRT_PRIVACY_POLICY_URL
+ * before calling any SDL_Init functions. The contents of the hint should
+ * be a valid URL. For example, "http://www.example.com".
+ *
+ * The default value is "", which will prevent SDL from adding a privacy policy
+ * link to the Settings charm. This hint should only be set during app init.
+ *
+ * The label text of an app's "Privacy Policy" link may be customized via another
+ * hint, SDL_HINT_WINRT_PRIVACY_POLICY_LABEL.
+ *
+ * Please note that on Windows Phone, Microsoft does not provide standard UI
+ * for displaying a privacy policy link, and as such, SDL_HINT_WINRT_PRIVACY_POLICY_URL
+ * will not get used on that platform. Network-enabled phone apps should display
+ * their privacy policy through some other, in-app means.
+ */
+#define SDL_HINT_WINRT_PRIVACY_POLICY_URL "SDL_WINRT_PRIVACY_POLICY_URL"
+
+/** \brief Label text for a WinRT app's privacy policy link
+ *
+ * Network-enabled WinRT apps must include a privacy policy. On Windows 8, 8.1, and RT,
+ * Microsoft mandates that this policy be available via the Windows Settings charm.
+ * SDL provides code to add a link there, with its label text being set via the
+ * optional hint, SDL_HINT_WINRT_PRIVACY_POLICY_LABEL.
+ *
+ * Please note that a privacy policy's contents are not set via this hint. A separate
+ * hint, SDL_HINT_WINRT_PRIVACY_POLICY_URL, is used to link to the actual text of the
+ * policy.
+ *
+ * The contents of this hint should be encoded as a UTF8 string.
+ *
+ * The default value is "Privacy Policy". This hint should only be set during app
+ * initialization, preferably before any calls to SDL_Init.
+ *
+ * For additional information on linking to a privacy policy, see the documentation for
+ * SDL_HINT_WINRT_PRIVACY_POLICY_URL.
+ */
+#define SDL_HINT_WINRT_PRIVACY_POLICY_LABEL "SDL_WINRT_PRIVACY_POLICY_LABEL"
+
+/** \brief Allows back-button-press events on Windows Phone to be marked as handled
+ *
+ * Windows Phone devices typically feature a Back button. When pressed,
+ * the OS will emit back-button-press events, which apps are expected to
+ * handle in an appropriate manner. If apps do not explicitly mark these
+ * events as 'Handled', then the OS will invoke its default behavior for
+ * unhandled back-button-press events, which on Windows Phone 8 and 8.1 is to
+ * terminate the app (and attempt to switch to the previous app, or to the
+ * device's home screen).
+ *
+ * Setting the SDL_HINT_WINRT_HANDLE_BACK_BUTTON hint to "1" will cause SDL
+ * to mark back-button-press events as Handled, if and when one is sent to
+ * the app.
+ *
+ * Internally, Windows Phone sends back button events as parameters to
+ * special back-button-press callback functions. Apps that need to respond
+ * to back-button-press events are expected to register one or more
+ * callback functions for such, shortly after being launched (during the
+ * app's initialization phase). After the back button is pressed, the OS
+ * will invoke these callbacks. If the app's callback(s) do not explicitly
+ * mark the event as handled by the time they return, or if the app never
+ * registers one of these callback, the OS will consider the event
+ * un-handled, and it will apply its default back button behavior (terminate
+ * the app).
+ *
+ * SDL registers its own back-button-press callback with the Windows Phone
+ * OS. This callback will emit a pair of SDL key-press events (SDL_KEYDOWN
+ * and SDL_KEYUP), each with a scancode of SDL_SCANCODE_AC_BACK, after which
+ * it will check the contents of the hint, SDL_HINT_WINRT_HANDLE_BACK_BUTTON.
+ * If the hint's value is set to "1", the back button event's Handled
+ * property will get set to 'true'. If the hint's value is set to something
+ * else, or if it is unset, SDL will leave the event's Handled property
+ * alone. (By default, the OS sets this property to 'false', to note.)
+ *
+ * SDL apps can either set SDL_HINT_WINRT_HANDLE_BACK_BUTTON well before a
+ * back button is pressed, or can set it in direct-response to a back button
+ * being pressed.
+ *
+ * In order to get notified when a back button is pressed, SDL apps should
+ * register a callback function with SDL_AddEventWatch(), and have it listen
+ * for SDL_KEYDOWN events that have a scancode of SDL_SCANCODE_AC_BACK.
+ * (Alternatively, SDL_KEYUP events can be listened-for. Listening for
+ * either event type is suitable.) Any value of SDL_HINT_WINRT_HANDLE_BACK_BUTTON
+ * set by such a callback, will be applied to the OS' current
+ * back-button-press event.
+ *
+ * More details on back button behavior in Windows Phone apps can be found
+ * at the following page, on Microsoft's developer site:
+ * http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj247550(v=vs.105).aspx
+ */
+#define SDL_HINT_WINRT_HANDLE_BACK_BUTTON "SDL_WINRT_HANDLE_BACK_BUTTON"
+
+/**
+ * \brief A variable that dictates policy for fullscreen Spaces on Mac OS X.
+ *
+ * This hint only applies to Mac OS X.
+ *
+ * The variable can be set to the following values:
+ * "0" - Disable Spaces support (FULLSCREEN_DESKTOP won't use them and
+ * SDL_WINDOW_RESIZABLE windows won't offer the "fullscreen"
+ * button on their titlebars).
+ * "1" - Enable Spaces support (FULLSCREEN_DESKTOP will use them and
+ * SDL_WINDOW_RESIZABLE windows will offer the "fullscreen"
+ * button on their titlebars).
+ *
+ * The default value is "1". Spaces are disabled regardless of this hint if
+ * the OS isn't at least Mac OS X Lion (10.7). This hint must be set before
+ * any windows are created.
+ */
+#define SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES "SDL_VIDEO_MAC_FULLSCREEN_SPACES"
+
+/**
+* \brief When set don't force the SDL app to become a foreground process
+*
+* This hint only applies to Mac OS X.
+*
+*/
+#define SDL_HINT_MAC_BACKGROUND_APP "SDL_MAC_BACKGROUND_APP"
+
+/**
+ * \brief Android APK expansion main file version. Should be a string number like "1", "2" etc.
+ *
+ * Must be set together with SDL_HINT_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION.
+ *
+ * If both hints were set then SDL_RWFromFile() will look into expansion files
+ * after a given relative path was not found in the internal storage and assets.
+ *
+ * By default this hint is not set and the APK expansion files are not searched.
+ */
+#define SDL_HINT_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION "SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION"
+
+/**
+ * \brief Android APK expansion patch file version. Should be a string number like "1", "2" etc.
+ *
+ * Must be set together with SDL_HINT_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION.
+ *
+ * If both hints were set then SDL_RWFromFile() will look into expansion files
+ * after a given relative path was not found in the internal storage and assets.
+ *
+ * By default this hint is not set and the APK expansion files are not searched.
+ */
+#define SDL_HINT_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION "SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION"
+
+/**
+ * \brief A variable to control whether certain IMEs should handle text editing internally instead of sending SDL_TEXTEDITING events.
+ *
+ * The variable can be set to the following values:
+ * "0" - SDL_TEXTEDITING events are sent, and it is the application's
+ * responsibility to render the text from these events and
+ * differentiate it somehow from committed text. (default)
+ * "1" - If supported by the IME then SDL_TEXTEDITING events are not sent,
+ * and text that is being composed will be rendered in its own UI.
+ */
+#define SDL_HINT_IME_INTERNAL_EDITING "SDL_IME_INTERNAL_EDITING"
+
+ /**
+ * \brief A variable to control whether mouse and touch events are to be treated together or separately
+ *
+ * The variable can be set to the following values:
+ * "0" - Mouse events will be handled as touch events, and touch will raise fake mouse
+ * events. This is the behaviour of SDL <= 2.0.3. (default)
+ * "1" - Mouse events will be handled separately from pure touch events.
+ *
+ * The value of this hint is used at runtime, so it can be changed at any time.
+ */
+#define SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH"
+
+/**
+ * \brief override the binding element for keyboard inputs for Emscripten builds
+ *
+ * This hint only applies to the emscripten platform
+ *
+ * The variable can be one of
+ * "#window" - The javascript window object (this is the default)
+ * "#document" - The javascript document object
+ * "#screen" - the javascript window.screen object
+ * "#canvas" - the WebGL canvas element
+ * any other string without a leading # sign applies to the element on the page with that ID.
+ */
+#define SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT "SDL_EMSCRIPTEN_KEYBOARD_ELEMENT"
+
+/**
+ * \brief Tell SDL not to catch the SIGINT or SIGTERM signals.
+ *
+ * This hint only applies to Unix-like platforms.
+ *
+ * The variable can be set to the following values:
+ * "0" - SDL will install a SIGINT and SIGTERM handler, and when it
+ * catches a signal, convert it into an SDL_QUIT event.
+ * "1" - SDL will not install a signal handler at all.
+ */
+#define SDL_HINT_NO_SIGNAL_HANDLERS "SDL_NO_SIGNAL_HANDLERS"
+
+/**
+ * \brief Tell SDL not to generate window-close events for Alt+F4 on Windows.
+ *
+ * The variable can be set to the following values:
+ * "0" - SDL will generate a window-close event when it sees Alt+F4.
+ * "1" - SDL will only do normal key handling for Alt+F4.
+ */
+#define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 "SDL_WINDOWS_NO_CLOSE_ON_ALT_F4"
+
+/**
+ * \brief An enumeration of hint priorities
+ */
+typedef enum
+{
+ SDL_HINT_DEFAULT,
+ SDL_HINT_NORMAL,
+ SDL_HINT_OVERRIDE
+} SDL_HintPriority;
+
+
+/**
+ * \brief Set a hint with a specific priority
+ *
+ * The priority controls the behavior when setting a hint that already
+ * has a value. Hints will replace existing hints of their priority and
+ * lower. Environment variables are considered to have override priority.
+ *
+ * \return SDL_TRUE if the hint was set, SDL_FALSE otherwise
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_SetHintWithPriority(const char *name,
+ const char *value,
+ SDL_HintPriority priority);
+
+/**
+ * \brief Set a hint with normal priority
+ *
+ * \return SDL_TRUE if the hint was set, SDL_FALSE otherwise
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_SetHint(const char *name,
+ const char *value);
+
+/**
+ * \brief Get a hint
+ *
+ * \return The string value of a hint variable.
+ */
+extern DECLSPEC const char * SDLCALL SDL_GetHint(const char *name);
+
+/**
+ * \brief Add a function to watch a particular hint
+ *
+ * \param name The hint to watch
+ * \param callback The function to call when the hint value changes
+ * \param userdata A pointer to pass to the callback function
+ */
+typedef void (*SDL_HintCallback)(void *userdata, const char *name, const char *oldValue, const char *newValue);
+extern DECLSPEC void SDLCALL SDL_AddHintCallback(const char *name,
+ SDL_HintCallback callback,
+ void *userdata);
+
+/**
+ * \brief Remove a function watching a particular hint
+ *
+ * \param name The hint being watched
+ * \param callback The function being called when the hint value changes
+ * \param userdata A pointer being passed to the callback function
+ */
+extern DECLSPEC void SDLCALL SDL_DelHintCallback(const char *name,
+ SDL_HintCallback callback,
+ void *userdata);
+
+/**
+ * \brief Clear all hints
+ *
+ * This function is called during SDL_Quit() to free stored hints.
+ */
+extern DECLSPEC void SDLCALL SDL_ClearHints(void);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_hints_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_joystick.h b/external/SDL2/include/SDL_joystick.h
new file mode 100644
index 0000000..266f3b3
--- /dev/null
+++ b/external/SDL2/include/SDL_joystick.h
@@ -0,0 +1,273 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_joystick.h
+ *
+ * Include file for SDL joystick event handling
+ *
+ * The term "device_index" identifies currently plugged in joystick devices between 0 and SDL_NumJoysticks, with the exact joystick
+ * behind a device_index changing as joysticks are plugged and unplugged.
+ *
+ * The term "instance_id" is the current instantiation of a joystick device in the system, if the joystick is removed and then re-inserted
+ * then it will get a new instance_id, instance_id's are monotonically increasing identifiers of a joystick plugged in.
+ *
+ * The term JoystickGUID is a stable 128-bit identifier for a joystick device that does not change over time, it identifies class of
+ * the device (a X360 wired controller for example). This identifier is platform dependent.
+ *
+ *
+ */
+
+#ifndef _SDL_joystick_h
+#define _SDL_joystick_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file SDL_joystick.h
+ *
+ * In order to use these functions, SDL_Init() must have been called
+ * with the ::SDL_INIT_JOYSTICK flag. This causes SDL to scan the system
+ * for joysticks, and load appropriate drivers.
+ *
+ * If you would like to receive joystick updates while the application
+ * is in the background, you should set the following hint before calling
+ * SDL_Init(): SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS
+ */
+
+/* The joystick structure used to identify an SDL joystick */
+struct _SDL_Joystick;
+typedef struct _SDL_Joystick SDL_Joystick;
+
+/* A structure that encodes the stable unique id for a joystick device */
+typedef struct {
+ Uint8 data[16];
+} SDL_JoystickGUID;
+
+typedef Sint32 SDL_JoystickID;
+
+typedef enum
+{
+ SDL_JOYSTICK_POWER_UNKNOWN = -1,
+ SDL_JOYSTICK_POWER_EMPTY,
+ SDL_JOYSTICK_POWER_LOW,
+ SDL_JOYSTICK_POWER_MEDIUM,
+ SDL_JOYSTICK_POWER_FULL,
+ SDL_JOYSTICK_POWER_WIRED,
+ SDL_JOYSTICK_POWER_MAX
+} SDL_JoystickPowerLevel;
+
+/* Function prototypes */
+/**
+ * Count the number of joysticks attached to the system right now
+ */
+extern DECLSPEC int SDLCALL SDL_NumJoysticks(void);
+
+/**
+ * Get the implementation dependent name of a joystick.
+ * This can be called before any joysticks are opened.
+ * If no name can be found, this function returns NULL.
+ */
+extern DECLSPEC const char *SDLCALL SDL_JoystickNameForIndex(int device_index);
+
+/**
+ * Open a joystick for use.
+ * The index passed as an argument refers to the N'th joystick on the system.
+ * This index is not the value which will identify this joystick in future
+ * joystick events. The joystick's instance id (::SDL_JoystickID) will be used
+ * there instead.
+ *
+ * \return A joystick identifier, or NULL if an error occurred.
+ */
+extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickOpen(int device_index);
+
+/**
+ * Return the SDL_Joystick associated with an instance id.
+ */
+extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickFromInstanceID(SDL_JoystickID joyid);
+
+/**
+ * Return the name for this currently opened joystick.
+ * If no name can be found, this function returns NULL.
+ */
+extern DECLSPEC const char *SDLCALL SDL_JoystickName(SDL_Joystick * joystick);
+
+/**
+ * Return the GUID for the joystick at this index
+ */
+extern DECLSPEC SDL_JoystickGUID SDLCALL SDL_JoystickGetDeviceGUID(int device_index);
+
+/**
+ * Return the GUID for this opened joystick
+ */
+extern DECLSPEC SDL_JoystickGUID SDLCALL SDL_JoystickGetGUID(SDL_Joystick * joystick);
+
+/**
+ * Return a string representation for this guid. pszGUID must point to at least 33 bytes
+ * (32 for the string plus a NULL terminator).
+ */
+extern DECLSPEC void SDLCALL SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID);
+
+/**
+ * convert a string into a joystick formatted guid
+ */
+extern DECLSPEC SDL_JoystickGUID SDLCALL SDL_JoystickGetGUIDFromString(const char *pchGUID);
+
+/**
+ * Returns SDL_TRUE if the joystick has been opened and currently connected, or SDL_FALSE if it has not.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_JoystickGetAttached(SDL_Joystick * joystick);
+
+/**
+ * Get the instance ID of an opened joystick or -1 if the joystick is invalid.
+ */
+extern DECLSPEC SDL_JoystickID SDLCALL SDL_JoystickInstanceID(SDL_Joystick * joystick);
+
+/**
+ * Get the number of general axis controls on a joystick.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickNumAxes(SDL_Joystick * joystick);
+
+/**
+ * Get the number of trackballs on a joystick.
+ *
+ * Joystick trackballs have only relative motion events associated
+ * with them and their state cannot be polled.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickNumBalls(SDL_Joystick * joystick);
+
+/**
+ * Get the number of POV hats on a joystick.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickNumHats(SDL_Joystick * joystick);
+
+/**
+ * Get the number of buttons on a joystick.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickNumButtons(SDL_Joystick * joystick);
+
+/**
+ * Update the current state of the open joysticks.
+ *
+ * This is called automatically by the event loop if any joystick
+ * events are enabled.
+ */
+extern DECLSPEC void SDLCALL SDL_JoystickUpdate(void);
+
+/**
+ * Enable/disable joystick event polling.
+ *
+ * If joystick events are disabled, you must call SDL_JoystickUpdate()
+ * yourself and check the state of the joystick when you want joystick
+ * information.
+ *
+ * The state can be one of ::SDL_QUERY, ::SDL_ENABLE or ::SDL_IGNORE.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickEventState(int state);
+
+/**
+ * Get the current state of an axis control on a joystick.
+ *
+ * The state is a value ranging from -32768 to 32767.
+ *
+ * The axis indices start at index 0.
+ */
+extern DECLSPEC Sint16 SDLCALL SDL_JoystickGetAxis(SDL_Joystick * joystick,
+ int axis);
+
+/**
+ * \name Hat positions
+ */
+/* @{ */
+#define SDL_HAT_CENTERED 0x00
+#define SDL_HAT_UP 0x01
+#define SDL_HAT_RIGHT 0x02
+#define SDL_HAT_DOWN 0x04
+#define SDL_HAT_LEFT 0x08
+#define SDL_HAT_RIGHTUP (SDL_HAT_RIGHT|SDL_HAT_UP)
+#define SDL_HAT_RIGHTDOWN (SDL_HAT_RIGHT|SDL_HAT_DOWN)
+#define SDL_HAT_LEFTUP (SDL_HAT_LEFT|SDL_HAT_UP)
+#define SDL_HAT_LEFTDOWN (SDL_HAT_LEFT|SDL_HAT_DOWN)
+/* @} */
+
+/**
+ * Get the current state of a POV hat on a joystick.
+ *
+ * The hat indices start at index 0.
+ *
+ * \return The return value is one of the following positions:
+ * - ::SDL_HAT_CENTERED
+ * - ::SDL_HAT_UP
+ * - ::SDL_HAT_RIGHT
+ * - ::SDL_HAT_DOWN
+ * - ::SDL_HAT_LEFT
+ * - ::SDL_HAT_RIGHTUP
+ * - ::SDL_HAT_RIGHTDOWN
+ * - ::SDL_HAT_LEFTUP
+ * - ::SDL_HAT_LEFTDOWN
+ */
+extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetHat(SDL_Joystick * joystick,
+ int hat);
+
+/**
+ * Get the ball axis change since the last poll.
+ *
+ * \return 0, or -1 if you passed it invalid parameters.
+ *
+ * The ball indices start at index 0.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickGetBall(SDL_Joystick * joystick,
+ int ball, int *dx, int *dy);
+
+/**
+ * Get the current state of a button on a joystick.
+ *
+ * The button indices start at index 0.
+ */
+extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick,
+ int button);
+
+/**
+ * Close a joystick previously opened with SDL_JoystickOpen().
+ */
+extern DECLSPEC void SDLCALL SDL_JoystickClose(SDL_Joystick * joystick);
+
+/**
+ * Return the battery level of this joystick
+ */
+extern DECLSPEC SDL_JoystickPowerLevel SDLCALL SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_joystick_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_keyboard.h b/external/SDL2/include/SDL_keyboard.h
new file mode 100644
index 0000000..bbba0f0
--- /dev/null
+++ b/external/SDL2/include/SDL_keyboard.h
@@ -0,0 +1,217 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_keyboard.h
+ *
+ * Include file for SDL keyboard event handling
+ */
+
+#ifndef _SDL_keyboard_h
+#define _SDL_keyboard_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_keycode.h"
+#include "SDL_video.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief The SDL keysym structure, used in key events.
+ *
+ * \note If you are looking for translated character input, see the ::SDL_TEXTINPUT event.
+ */
+typedef struct SDL_Keysym
+{
+ SDL_Scancode scancode; /**< SDL physical key code - see ::SDL_Scancode for details */
+ SDL_Keycode sym; /**< SDL virtual key code - see ::SDL_Keycode for details */
+ Uint16 mod; /**< current key modifiers */
+ Uint32 unused;
+} SDL_Keysym;
+
+/* Function prototypes */
+
+/**
+ * \brief Get the window which currently has keyboard focus.
+ */
+extern DECLSPEC SDL_Window * SDLCALL SDL_GetKeyboardFocus(void);
+
+/**
+ * \brief Get a snapshot of the current state of the keyboard.
+ *
+ * \param numkeys if non-NULL, receives the length of the returned array.
+ *
+ * \return An array of key states. Indexes into this array are obtained by using ::SDL_Scancode values.
+ *
+ * \b Example:
+ * \code
+ * const Uint8 *state = SDL_GetKeyboardState(NULL);
+ * if ( state[SDL_SCANCODE_RETURN] ) {
+ * printf("<RETURN> is pressed.\n");
+ * }
+ * \endcode
+ */
+extern DECLSPEC const Uint8 *SDLCALL SDL_GetKeyboardState(int *numkeys);
+
+/**
+ * \brief Get the current key modifier state for the keyboard.
+ */
+extern DECLSPEC SDL_Keymod SDLCALL SDL_GetModState(void);
+
+/**
+ * \brief Set the current key modifier state for the keyboard.
+ *
+ * \note This does not change the keyboard state, only the key modifier flags.
+ */
+extern DECLSPEC void SDLCALL SDL_SetModState(SDL_Keymod modstate);
+
+/**
+ * \brief Get the key code corresponding to the given scancode according
+ * to the current keyboard layout.
+ *
+ * See ::SDL_Keycode for details.
+ *
+ * \sa SDL_GetKeyName()
+ */
+extern DECLSPEC SDL_Keycode SDLCALL SDL_GetKeyFromScancode(SDL_Scancode scancode);
+
+/**
+ * \brief Get the scancode corresponding to the given key code according to the
+ * current keyboard layout.
+ *
+ * See ::SDL_Scancode for details.
+ *
+ * \sa SDL_GetScancodeName()
+ */
+extern DECLSPEC SDL_Scancode SDLCALL SDL_GetScancodeFromKey(SDL_Keycode key);
+
+/**
+ * \brief Get a human-readable name for a scancode.
+ *
+ * \return A pointer to the name for the scancode.
+ * If the scancode doesn't have a name, this function returns
+ * an empty string ("").
+ *
+ * \sa SDL_Scancode
+ */
+extern DECLSPEC const char *SDLCALL SDL_GetScancodeName(SDL_Scancode scancode);
+
+/**
+ * \brief Get a scancode from a human-readable name
+ *
+ * \return scancode, or SDL_SCANCODE_UNKNOWN if the name wasn't recognized
+ *
+ * \sa SDL_Scancode
+ */
+extern DECLSPEC SDL_Scancode SDLCALL SDL_GetScancodeFromName(const char *name);
+
+/**
+ * \brief Get a human-readable name for a key.
+ *
+ * \return A pointer to a UTF-8 string that stays valid at least until the next
+ * call to this function. If you need it around any longer, you must
+ * copy it. If the key doesn't have a name, this function returns an
+ * empty string ("").
+ *
+ * \sa SDL_Key
+ */
+extern DECLSPEC const char *SDLCALL SDL_GetKeyName(SDL_Keycode key);
+
+/**
+ * \brief Get a key code from a human-readable name
+ *
+ * \return key code, or SDLK_UNKNOWN if the name wasn't recognized
+ *
+ * \sa SDL_Keycode
+ */
+extern DECLSPEC SDL_Keycode SDLCALL SDL_GetKeyFromName(const char *name);
+
+/**
+ * \brief Start accepting Unicode text input events.
+ * This function will show the on-screen keyboard if supported.
+ *
+ * \sa SDL_StopTextInput()
+ * \sa SDL_SetTextInputRect()
+ * \sa SDL_HasScreenKeyboardSupport()
+ */
+extern DECLSPEC void SDLCALL SDL_StartTextInput(void);
+
+/**
+ * \brief Return whether or not Unicode text input events are enabled.
+ *
+ * \sa SDL_StartTextInput()
+ * \sa SDL_StopTextInput()
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsTextInputActive(void);
+
+/**
+ * \brief Stop receiving any text input events.
+ * This function will hide the on-screen keyboard if supported.
+ *
+ * \sa SDL_StartTextInput()
+ * \sa SDL_HasScreenKeyboardSupport()
+ */
+extern DECLSPEC void SDLCALL SDL_StopTextInput(void);
+
+/**
+ * \brief Set the rectangle used to type Unicode text inputs.
+ * This is used as a hint for IME and on-screen keyboard placement.
+ *
+ * \sa SDL_StartTextInput()
+ */
+extern DECLSPEC void SDLCALL SDL_SetTextInputRect(SDL_Rect *rect);
+
+/**
+ * \brief Returns whether the platform has some screen keyboard support.
+ *
+ * \return SDL_TRUE if some keyboard support is available else SDL_FALSE.
+ *
+ * \note Not all screen keyboard functions are supported on all platforms.
+ *
+ * \sa SDL_IsScreenKeyboardShown()
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasScreenKeyboardSupport(void);
+
+/**
+ * \brief Returns whether the screen keyboard is shown for given window.
+ *
+ * \param window The window for which screen keyboard should be queried.
+ *
+ * \return SDL_TRUE if screen keyboard is shown else SDL_FALSE.
+ *
+ * \sa SDL_HasScreenKeyboardSupport()
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsScreenKeyboardShown(SDL_Window *window);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_keyboard_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_keycode.h b/external/SDL2/include/SDL_keycode.h
new file mode 100644
index 0000000..7be9635
--- /dev/null
+++ b/external/SDL2/include/SDL_keycode.h
@@ -0,0 +1,341 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_keycode.h
+ *
+ * Defines constants which identify keyboard keys and modifiers.
+ */
+
+#ifndef _SDL_keycode_h
+#define _SDL_keycode_h
+
+#include "SDL_stdinc.h"
+#include "SDL_scancode.h"
+
+/**
+ * \brief The SDL virtual key representation.
+ *
+ * Values of this type are used to represent keyboard keys using the current
+ * layout of the keyboard. These values include Unicode values representing
+ * the unmodified character that would be generated by pressing the key, or
+ * an SDLK_* constant for those keys that do not generate characters.
+ */
+typedef Sint32 SDL_Keycode;
+
+#define SDLK_SCANCODE_MASK (1<<30)
+#define SDL_SCANCODE_TO_KEYCODE(X) (X | SDLK_SCANCODE_MASK)
+
+enum
+{
+ SDLK_UNKNOWN = 0,
+
+ SDLK_RETURN = '\r',
+ SDLK_ESCAPE = '\033',
+ SDLK_BACKSPACE = '\b',
+ SDLK_TAB = '\t',
+ SDLK_SPACE = ' ',
+ SDLK_EXCLAIM = '!',
+ SDLK_QUOTEDBL = '"',
+ SDLK_HASH = '#',
+ SDLK_PERCENT = '%',
+ SDLK_DOLLAR = '$',
+ SDLK_AMPERSAND = '&',
+ SDLK_QUOTE = '\'',
+ SDLK_LEFTPAREN = '(',
+ SDLK_RIGHTPAREN = ')',
+ SDLK_ASTERISK = '*',
+ SDLK_PLUS = '+',
+ SDLK_COMMA = ',',
+ SDLK_MINUS = '-',
+ SDLK_PERIOD = '.',
+ SDLK_SLASH = '/',
+ SDLK_0 = '0',
+ SDLK_1 = '1',
+ SDLK_2 = '2',
+ SDLK_3 = '3',
+ SDLK_4 = '4',
+ SDLK_5 = '5',
+ SDLK_6 = '6',
+ SDLK_7 = '7',
+ SDLK_8 = '8',
+ SDLK_9 = '9',
+ SDLK_COLON = ':',
+ SDLK_SEMICOLON = ';',
+ SDLK_LESS = '<',
+ SDLK_EQUALS = '=',
+ SDLK_GREATER = '>',
+ SDLK_QUESTION = '?',
+ SDLK_AT = '@',
+ /*
+ Skip uppercase letters
+ */
+ SDLK_LEFTBRACKET = '[',
+ SDLK_BACKSLASH = '\\',
+ SDLK_RIGHTBRACKET = ']',
+ SDLK_CARET = '^',
+ SDLK_UNDERSCORE = '_',
+ SDLK_BACKQUOTE = '`',
+ SDLK_a = 'a',
+ SDLK_b = 'b',
+ SDLK_c = 'c',
+ SDLK_d = 'd',
+ SDLK_e = 'e',
+ SDLK_f = 'f',
+ SDLK_g = 'g',
+ SDLK_h = 'h',
+ SDLK_i = 'i',
+ SDLK_j = 'j',
+ SDLK_k = 'k',
+ SDLK_l = 'l',
+ SDLK_m = 'm',
+ SDLK_n = 'n',
+ SDLK_o = 'o',
+ SDLK_p = 'p',
+ SDLK_q = 'q',
+ SDLK_r = 'r',
+ SDLK_s = 's',
+ SDLK_t = 't',
+ SDLK_u = 'u',
+ SDLK_v = 'v',
+ SDLK_w = 'w',
+ SDLK_x = 'x',
+ SDLK_y = 'y',
+ SDLK_z = 'z',
+
+ SDLK_CAPSLOCK = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CAPSLOCK),
+
+ SDLK_F1 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F1),
+ SDLK_F2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F2),
+ SDLK_F3 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F3),
+ SDLK_F4 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F4),
+ SDLK_F5 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F5),
+ SDLK_F6 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F6),
+ SDLK_F7 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F7),
+ SDLK_F8 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F8),
+ SDLK_F9 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F9),
+ SDLK_F10 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F10),
+ SDLK_F11 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F11),
+ SDLK_F12 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F12),
+
+ SDLK_PRINTSCREEN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PRINTSCREEN),
+ SDLK_SCROLLLOCK = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SCROLLLOCK),
+ SDLK_PAUSE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAUSE),
+ SDLK_INSERT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_INSERT),
+ SDLK_HOME = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_HOME),
+ SDLK_PAGEUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEUP),
+ SDLK_DELETE = '\177',
+ SDLK_END = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_END),
+ SDLK_PAGEDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEDOWN),
+ SDLK_RIGHT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RIGHT),
+ SDLK_LEFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LEFT),
+ SDLK_DOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DOWN),
+ SDLK_UP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_UP),
+
+ SDLK_NUMLOCKCLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_NUMLOCKCLEAR),
+ SDLK_KP_DIVIDE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DIVIDE),
+ SDLK_KP_MULTIPLY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MULTIPLY),
+ SDLK_KP_MINUS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MINUS),
+ SDLK_KP_PLUS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PLUS),
+ SDLK_KP_ENTER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_ENTER),
+ SDLK_KP_1 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_1),
+ SDLK_KP_2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_2),
+ SDLK_KP_3 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_3),
+ SDLK_KP_4 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_4),
+ SDLK_KP_5 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_5),
+ SDLK_KP_6 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_6),
+ SDLK_KP_7 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_7),
+ SDLK_KP_8 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_8),
+ SDLK_KP_9 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_9),
+ SDLK_KP_0 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_0),
+ SDLK_KP_PERIOD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PERIOD),
+
+ SDLK_APPLICATION = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_APPLICATION),
+ SDLK_POWER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_POWER),
+ SDLK_KP_EQUALS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EQUALS),
+ SDLK_F13 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F13),
+ SDLK_F14 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F14),
+ SDLK_F15 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F15),
+ SDLK_F16 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F16),
+ SDLK_F17 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F17),
+ SDLK_F18 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F18),
+ SDLK_F19 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F19),
+ SDLK_F20 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F20),
+ SDLK_F21 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F21),
+ SDLK_F22 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F22),
+ SDLK_F23 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F23),
+ SDLK_F24 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F24),
+ SDLK_EXECUTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EXECUTE),
+ SDLK_HELP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_HELP),
+ SDLK_MENU = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MENU),
+ SDLK_SELECT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SELECT),
+ SDLK_STOP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_STOP),
+ SDLK_AGAIN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AGAIN),
+ SDLK_UNDO = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_UNDO),
+ SDLK_CUT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CUT),
+ SDLK_COPY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_COPY),
+ SDLK_PASTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PASTE),
+ SDLK_FIND = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_FIND),
+ SDLK_MUTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MUTE),
+ SDLK_VOLUMEUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_VOLUMEUP),
+ SDLK_VOLUMEDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_VOLUMEDOWN),
+ SDLK_KP_COMMA = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_COMMA),
+ SDLK_KP_EQUALSAS400 =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EQUALSAS400),
+
+ SDLK_ALTERASE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_ALTERASE),
+ SDLK_SYSREQ = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SYSREQ),
+ SDLK_CANCEL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CANCEL),
+ SDLK_CLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CLEAR),
+ SDLK_PRIOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PRIOR),
+ SDLK_RETURN2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RETURN2),
+ SDLK_SEPARATOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SEPARATOR),
+ SDLK_OUT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_OUT),
+ SDLK_OPER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_OPER),
+ SDLK_CLEARAGAIN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CLEARAGAIN),
+ SDLK_CRSEL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CRSEL),
+ SDLK_EXSEL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EXSEL),
+
+ SDLK_KP_00 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_00),
+ SDLK_KP_000 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_000),
+ SDLK_THOUSANDSSEPARATOR =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_THOUSANDSSEPARATOR),
+ SDLK_DECIMALSEPARATOR =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DECIMALSEPARATOR),
+ SDLK_CURRENCYUNIT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CURRENCYUNIT),
+ SDLK_CURRENCYSUBUNIT =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CURRENCYSUBUNIT),
+ SDLK_KP_LEFTPAREN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LEFTPAREN),
+ SDLK_KP_RIGHTPAREN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_RIGHTPAREN),
+ SDLK_KP_LEFTBRACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LEFTBRACE),
+ SDLK_KP_RIGHTBRACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_RIGHTBRACE),
+ SDLK_KP_TAB = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_TAB),
+ SDLK_KP_BACKSPACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_BACKSPACE),
+ SDLK_KP_A = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_A),
+ SDLK_KP_B = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_B),
+ SDLK_KP_C = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_C),
+ SDLK_KP_D = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_D),
+ SDLK_KP_E = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_E),
+ SDLK_KP_F = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_F),
+ SDLK_KP_XOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_XOR),
+ SDLK_KP_POWER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_POWER),
+ SDLK_KP_PERCENT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PERCENT),
+ SDLK_KP_LESS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LESS),
+ SDLK_KP_GREATER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_GREATER),
+ SDLK_KP_AMPERSAND = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_AMPERSAND),
+ SDLK_KP_DBLAMPERSAND =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DBLAMPERSAND),
+ SDLK_KP_VERTICALBAR =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_VERTICALBAR),
+ SDLK_KP_DBLVERTICALBAR =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DBLVERTICALBAR),
+ SDLK_KP_COLON = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_COLON),
+ SDLK_KP_HASH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_HASH),
+ SDLK_KP_SPACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_SPACE),
+ SDLK_KP_AT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_AT),
+ SDLK_KP_EXCLAM = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EXCLAM),
+ SDLK_KP_MEMSTORE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMSTORE),
+ SDLK_KP_MEMRECALL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMRECALL),
+ SDLK_KP_MEMCLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMCLEAR),
+ SDLK_KP_MEMADD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMADD),
+ SDLK_KP_MEMSUBTRACT =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMSUBTRACT),
+ SDLK_KP_MEMMULTIPLY =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMMULTIPLY),
+ SDLK_KP_MEMDIVIDE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMDIVIDE),
+ SDLK_KP_PLUSMINUS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PLUSMINUS),
+ SDLK_KP_CLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_CLEAR),
+ SDLK_KP_CLEARENTRY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_CLEARENTRY),
+ SDLK_KP_BINARY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_BINARY),
+ SDLK_KP_OCTAL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_OCTAL),
+ SDLK_KP_DECIMAL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DECIMAL),
+ SDLK_KP_HEXADECIMAL =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_HEXADECIMAL),
+
+ SDLK_LCTRL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LCTRL),
+ SDLK_LSHIFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LSHIFT),
+ SDLK_LALT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LALT),
+ SDLK_LGUI = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LGUI),
+ SDLK_RCTRL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RCTRL),
+ SDLK_RSHIFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RSHIFT),
+ SDLK_RALT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RALT),
+ SDLK_RGUI = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RGUI),
+
+ SDLK_MODE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MODE),
+
+ SDLK_AUDIONEXT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIONEXT),
+ SDLK_AUDIOPREV = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOPREV),
+ SDLK_AUDIOSTOP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOSTOP),
+ SDLK_AUDIOPLAY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOPLAY),
+ SDLK_AUDIOMUTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOMUTE),
+ SDLK_MEDIASELECT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIASELECT),
+ SDLK_WWW = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_WWW),
+ SDLK_MAIL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MAIL),
+ SDLK_CALCULATOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CALCULATOR),
+ SDLK_COMPUTER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_COMPUTER),
+ SDLK_AC_SEARCH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_SEARCH),
+ SDLK_AC_HOME = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_HOME),
+ SDLK_AC_BACK = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_BACK),
+ SDLK_AC_FORWARD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_FORWARD),
+ SDLK_AC_STOP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_STOP),
+ SDLK_AC_REFRESH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_REFRESH),
+ SDLK_AC_BOOKMARKS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_BOOKMARKS),
+
+ SDLK_BRIGHTNESSDOWN =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_BRIGHTNESSDOWN),
+ SDLK_BRIGHTNESSUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_BRIGHTNESSUP),
+ SDLK_DISPLAYSWITCH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DISPLAYSWITCH),
+ SDLK_KBDILLUMTOGGLE =
+ SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KBDILLUMTOGGLE),
+ SDLK_KBDILLUMDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KBDILLUMDOWN),
+ SDLK_KBDILLUMUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KBDILLUMUP),
+ SDLK_EJECT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EJECT),
+ SDLK_SLEEP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SLEEP)
+};
+
+/**
+ * \brief Enumeration of valid key mods (possibly OR'd together).
+ */
+typedef enum
+{
+ KMOD_NONE = 0x0000,
+ KMOD_LSHIFT = 0x0001,
+ KMOD_RSHIFT = 0x0002,
+ KMOD_LCTRL = 0x0040,
+ KMOD_RCTRL = 0x0080,
+ KMOD_LALT = 0x0100,
+ KMOD_RALT = 0x0200,
+ KMOD_LGUI = 0x0400,
+ KMOD_RGUI = 0x0800,
+ KMOD_NUM = 0x1000,
+ KMOD_CAPS = 0x2000,
+ KMOD_MODE = 0x4000,
+ KMOD_RESERVED = 0x8000
+} SDL_Keymod;
+
+#define KMOD_CTRL (KMOD_LCTRL|KMOD_RCTRL)
+#define KMOD_SHIFT (KMOD_LSHIFT|KMOD_RSHIFT)
+#define KMOD_ALT (KMOD_LALT|KMOD_RALT)
+#define KMOD_GUI (KMOD_LGUI|KMOD_RGUI)
+
+#endif /* _SDL_keycode_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_loadso.h b/external/SDL2/include/SDL_loadso.h
new file mode 100644
index 0000000..3d540bd
--- /dev/null
+++ b/external/SDL2/include/SDL_loadso.h
@@ -0,0 +1,81 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_loadso.h
+ *
+ * System dependent library loading routines
+ *
+ * Some things to keep in mind:
+ * \li These functions only work on C function names. Other languages may
+ * have name mangling and intrinsic language support that varies from
+ * compiler to compiler.
+ * \li Make sure you declare your function pointers with the same calling
+ * convention as the actual library function. Your code will crash
+ * mysteriously if you do not do this.
+ * \li Avoid namespace collisions. If you load a symbol from the library,
+ * it is not defined whether or not it goes into the global symbol
+ * namespace for the application. If it does and it conflicts with
+ * symbols in your code or other shared libraries, you will not get
+ * the results you expect. :)
+ */
+
+#ifndef _SDL_loadso_h
+#define _SDL_loadso_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This function dynamically loads a shared object and returns a pointer
+ * to the object handle (or NULL if there was an error).
+ * The 'sofile' parameter is a system dependent name of the object file.
+ */
+extern DECLSPEC void *SDLCALL SDL_LoadObject(const char *sofile);
+
+/**
+ * Given an object handle, this function looks up the address of the
+ * named function in the shared object and returns it. This address
+ * is no longer valid after calling SDL_UnloadObject().
+ */
+extern DECLSPEC void *SDLCALL SDL_LoadFunction(void *handle,
+ const char *name);
+
+/**
+ * Unload a shared object from memory.
+ */
+extern DECLSPEC void SDLCALL SDL_UnloadObject(void *handle);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_loadso_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_log.h b/external/SDL2/include/SDL_log.h
new file mode 100644
index 0000000..09be110
--- /dev/null
+++ b/external/SDL2/include/SDL_log.h
@@ -0,0 +1,211 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_log.h
+ *
+ * Simple log messages with categories and priorities.
+ *
+ * By default logs are quiet, but if you're debugging SDL you might want:
+ *
+ * SDL_LogSetAllPriority(SDL_LOG_PRIORITY_WARN);
+ *
+ * Here's where the messages go on different platforms:
+ * Windows: debug output stream
+ * Android: log output
+ * Others: standard error output (stderr)
+ */
+
+#ifndef _SDL_log_h
+#define _SDL_log_h
+
+#include "SDL_stdinc.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * \brief The maximum size of a log message
+ *
+ * Messages longer than the maximum size will be truncated
+ */
+#define SDL_MAX_LOG_MESSAGE 4096
+
+/**
+ * \brief The predefined log categories
+ *
+ * By default the application category is enabled at the INFO level,
+ * the assert category is enabled at the WARN level, test is enabled
+ * at the VERBOSE level and all other categories are enabled at the
+ * CRITICAL level.
+ */
+enum
+{
+ SDL_LOG_CATEGORY_APPLICATION,
+ SDL_LOG_CATEGORY_ERROR,
+ SDL_LOG_CATEGORY_ASSERT,
+ SDL_LOG_CATEGORY_SYSTEM,
+ SDL_LOG_CATEGORY_AUDIO,
+ SDL_LOG_CATEGORY_VIDEO,
+ SDL_LOG_CATEGORY_RENDER,
+ SDL_LOG_CATEGORY_INPUT,
+ SDL_LOG_CATEGORY_TEST,
+
+ /* Reserved for future SDL library use */
+ SDL_LOG_CATEGORY_RESERVED1,
+ SDL_LOG_CATEGORY_RESERVED2,
+ SDL_LOG_CATEGORY_RESERVED3,
+ SDL_LOG_CATEGORY_RESERVED4,
+ SDL_LOG_CATEGORY_RESERVED5,
+ SDL_LOG_CATEGORY_RESERVED6,
+ SDL_LOG_CATEGORY_RESERVED7,
+ SDL_LOG_CATEGORY_RESERVED8,
+ SDL_LOG_CATEGORY_RESERVED9,
+ SDL_LOG_CATEGORY_RESERVED10,
+
+ /* Beyond this point is reserved for application use, e.g.
+ enum {
+ MYAPP_CATEGORY_AWESOME1 = SDL_LOG_CATEGORY_CUSTOM,
+ MYAPP_CATEGORY_AWESOME2,
+ MYAPP_CATEGORY_AWESOME3,
+ ...
+ };
+ */
+ SDL_LOG_CATEGORY_CUSTOM
+};
+
+/**
+ * \brief The predefined log priorities
+ */
+typedef enum
+{
+ SDL_LOG_PRIORITY_VERBOSE = 1,
+ SDL_LOG_PRIORITY_DEBUG,
+ SDL_LOG_PRIORITY_INFO,
+ SDL_LOG_PRIORITY_WARN,
+ SDL_LOG_PRIORITY_ERROR,
+ SDL_LOG_PRIORITY_CRITICAL,
+ SDL_NUM_LOG_PRIORITIES
+} SDL_LogPriority;
+
+
+/**
+ * \brief Set the priority of all log categories
+ */
+extern DECLSPEC void SDLCALL SDL_LogSetAllPriority(SDL_LogPriority priority);
+
+/**
+ * \brief Set the priority of a particular log category
+ */
+extern DECLSPEC void SDLCALL SDL_LogSetPriority(int category,
+ SDL_LogPriority priority);
+
+/**
+ * \brief Get the priority of a particular log category
+ */
+extern DECLSPEC SDL_LogPriority SDLCALL SDL_LogGetPriority(int category);
+
+/**
+ * \brief Reset all priorities to default.
+ *
+ * \note This is called in SDL_Quit().
+ */
+extern DECLSPEC void SDLCALL SDL_LogResetPriorities(void);
+
+/**
+ * \brief Log a message with SDL_LOG_CATEGORY_APPLICATION and SDL_LOG_PRIORITY_INFO
+ */
+extern DECLSPEC void SDLCALL SDL_Log(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(1);
+
+/**
+ * \brief Log a message with SDL_LOG_PRIORITY_VERBOSE
+ */
+extern DECLSPEC void SDLCALL SDL_LogVerbose(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(2);
+
+/**
+ * \brief Log a message with SDL_LOG_PRIORITY_DEBUG
+ */
+extern DECLSPEC void SDLCALL SDL_LogDebug(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(2);
+
+/**
+ * \brief Log a message with SDL_LOG_PRIORITY_INFO
+ */
+extern DECLSPEC void SDLCALL SDL_LogInfo(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(2);
+
+/**
+ * \brief Log a message with SDL_LOG_PRIORITY_WARN
+ */
+extern DECLSPEC void SDLCALL SDL_LogWarn(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(2);
+
+/**
+ * \brief Log a message with SDL_LOG_PRIORITY_ERROR
+ */
+extern DECLSPEC void SDLCALL SDL_LogError(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(2);
+
+/**
+ * \brief Log a message with SDL_LOG_PRIORITY_CRITICAL
+ */
+extern DECLSPEC void SDLCALL SDL_LogCritical(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(2);
+
+/**
+ * \brief Log a message with the specified category and priority.
+ */
+extern DECLSPEC void SDLCALL SDL_LogMessage(int category,
+ SDL_LogPriority priority,
+ SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(3);
+
+/**
+ * \brief Log a message with the specified category and priority.
+ */
+extern DECLSPEC void SDLCALL SDL_LogMessageV(int category,
+ SDL_LogPriority priority,
+ const char *fmt, va_list ap);
+
+/**
+ * \brief The prototype for the log output function
+ */
+typedef void (*SDL_LogOutputFunction)(void *userdata, int category, SDL_LogPriority priority, const char *message);
+
+/**
+ * \brief Get the current log output function.
+ */
+extern DECLSPEC void SDLCALL SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata);
+
+/**
+ * \brief This function allows you to replace the default log output
+ * function with one of your own.
+ */
+extern DECLSPEC void SDLCALL SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_log_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_main.h b/external/SDL2/include/SDL_main.h
new file mode 100644
index 0000000..9ce3754
--- /dev/null
+++ b/external/SDL2/include/SDL_main.h
@@ -0,0 +1,161 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_main_h
+#define _SDL_main_h
+
+#include "SDL_stdinc.h"
+
+/**
+ * \file SDL_main.h
+ *
+ * Redefine main() on some platforms so that it is called by SDL.
+ */
+
+#ifndef SDL_MAIN_HANDLED
+#if defined(__WIN32__)
+/* On Windows SDL provides WinMain(), which parses the command line and passes
+ the arguments to your main function.
+
+ If you provide your own WinMain(), you may define SDL_MAIN_HANDLED
+ */
+#define SDL_MAIN_AVAILABLE
+
+#elif defined(__WINRT__)
+/* On WinRT, SDL provides a main function that initializes CoreApplication,
+ creating an instance of IFrameworkView in the process.
+
+ Please note that #include'ing SDL_main.h is not enough to get a main()
+ function working. In non-XAML apps, the file,
+ src/main/winrt/SDL_WinRT_main_NonXAML.cpp, or a copy of it, must be compiled
+ into the app itself. In XAML apps, the function, SDL_WinRTRunApp must be
+ called, with a pointer to the Direct3D-hosted XAML control passed in.
+*/
+#define SDL_MAIN_NEEDED
+
+#elif defined(__IPHONEOS__)
+/* On iOS SDL provides a main function that creates an application delegate
+ and starts the iOS application run loop.
+
+ See src/video/uikit/SDL_uikitappdelegate.m for more details.
+ */
+#define SDL_MAIN_NEEDED
+
+#elif defined(__ANDROID__)
+/* On Android SDL provides a Java class in SDLActivity.java that is the
+ main activity entry point.
+
+ See README-android.txt for more details on extending that class.
+ */
+#define SDL_MAIN_NEEDED
+
+#elif defined(__NACL__)
+/* On NACL we use ppapi_simple to set up the application helper code,
+ then wait for the first PSE_INSTANCE_DIDCHANGEVIEW event before
+ starting the user main function.
+ All user code is run in a separate thread by ppapi_simple, thus
+ allowing for blocking io to take place via nacl_io
+*/
+#define SDL_MAIN_NEEDED
+
+#endif
+#endif /* SDL_MAIN_HANDLED */
+
+#ifdef __cplusplus
+#define C_LINKAGE "C"
+#else
+#define C_LINKAGE
+#endif /* __cplusplus */
+
+/**
+ * \file SDL_main.h
+ *
+ * The application's main() function must be called with C linkage,
+ * and should be declared like this:
+ * \code
+ * #ifdef __cplusplus
+ * extern "C"
+ * #endif
+ * int main(int argc, char *argv[])
+ * {
+ * }
+ * \endcode
+ */
+
+#if defined(SDL_MAIN_NEEDED) || defined(SDL_MAIN_AVAILABLE)
+#define main SDL_main
+#endif
+
+/**
+ * The prototype for the application's main() function
+ */
+extern C_LINKAGE int SDL_main(int argc, char *argv[]);
+
+
+#include "begin_code.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This is called by the real SDL main function to let the rest of the
+ * library know that initialization was done properly.
+ *
+ * Calling this yourself without knowing what you're doing can cause
+ * crashes and hard to diagnose problems with your application.
+ */
+extern DECLSPEC void SDLCALL SDL_SetMainReady(void);
+
+#ifdef __WIN32__
+
+/**
+ * This can be called to set the application class at startup
+ */
+extern DECLSPEC int SDLCALL SDL_RegisterApp(char *name, Uint32 style,
+ void *hInst);
+extern DECLSPEC void SDLCALL SDL_UnregisterApp(void);
+
+#endif /* __WIN32__ */
+
+
+#ifdef __WINRT__
+
+/**
+ * \brief Initializes and launches an SDL/WinRT application.
+ *
+ * \param mainFunction The SDL app's C-style main().
+ * \param reserved Reserved for future use; should be NULL
+ * \return 0 on success, -1 on failure. On failure, use SDL_GetError to retrieve more
+ * information on the failure.
+ */
+extern DECLSPEC int SDLCALL SDL_WinRTRunApp(int (*mainFunction)(int, char **), void * reserved);
+
+#endif /* __WINRT__ */
+
+
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_main_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_messagebox.h b/external/SDL2/include/SDL_messagebox.h
new file mode 100644
index 0000000..ec370db
--- /dev/null
+++ b/external/SDL2/include/SDL_messagebox.h
@@ -0,0 +1,144 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_messagebox_h
+#define _SDL_messagebox_h
+
+#include "SDL_stdinc.h"
+#include "SDL_video.h" /* For SDL_Window */
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief SDL_MessageBox flags. If supported will display warning icon, etc.
+ */
+typedef enum
+{
+ SDL_MESSAGEBOX_ERROR = 0x00000010, /**< error dialog */
+ SDL_MESSAGEBOX_WARNING = 0x00000020, /**< warning dialog */
+ SDL_MESSAGEBOX_INFORMATION = 0x00000040 /**< informational dialog */
+} SDL_MessageBoxFlags;
+
+/**
+ * \brief Flags for SDL_MessageBoxButtonData.
+ */
+typedef enum
+{
+ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT = 0x00000001, /**< Marks the default button when return is hit */
+ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT = 0x00000002 /**< Marks the default button when escape is hit */
+} SDL_MessageBoxButtonFlags;
+
+/**
+ * \brief Individual button data.
+ */
+typedef struct
+{
+ Uint32 flags; /**< ::SDL_MessageBoxButtonFlags */
+ int buttonid; /**< User defined button id (value returned via SDL_ShowMessageBox) */
+ const char * text; /**< The UTF-8 button text */
+} SDL_MessageBoxButtonData;
+
+/**
+ * \brief RGB value used in a message box color scheme
+ */
+typedef struct
+{
+ Uint8 r, g, b;
+} SDL_MessageBoxColor;
+
+typedef enum
+{
+ SDL_MESSAGEBOX_COLOR_BACKGROUND,
+ SDL_MESSAGEBOX_COLOR_TEXT,
+ SDL_MESSAGEBOX_COLOR_BUTTON_BORDER,
+ SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND,
+ SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED,
+ SDL_MESSAGEBOX_COLOR_MAX
+} SDL_MessageBoxColorType;
+
+/**
+ * \brief A set of colors to use for message box dialogs
+ */
+typedef struct
+{
+ SDL_MessageBoxColor colors[SDL_MESSAGEBOX_COLOR_MAX];
+} SDL_MessageBoxColorScheme;
+
+/**
+ * \brief MessageBox structure containing title, text, window, etc.
+ */
+typedef struct
+{
+ Uint32 flags; /**< ::SDL_MessageBoxFlags */
+ SDL_Window *window; /**< Parent window, can be NULL */
+ const char *title; /**< UTF-8 title */
+ const char *message; /**< UTF-8 message text */
+
+ int numbuttons;
+ const SDL_MessageBoxButtonData *buttons;
+
+ const SDL_MessageBoxColorScheme *colorScheme; /**< ::SDL_MessageBoxColorScheme, can be NULL to use system settings */
+} SDL_MessageBoxData;
+
+/**
+ * \brief Create a modal message box.
+ *
+ * \param messageboxdata The SDL_MessageBoxData structure with title, text, etc.
+ * \param buttonid The pointer to which user id of hit button should be copied.
+ *
+ * \return -1 on error, otherwise 0 and buttonid contains user id of button
+ * hit or -1 if dialog was closed.
+ *
+ * \note This function should be called on the thread that created the parent
+ * window, or on the main thread if the messagebox has no parent. It will
+ * block execution of that thread until the user clicks a button or
+ * closes the messagebox.
+ */
+extern DECLSPEC int SDLCALL SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
+
+/**
+ * \brief Create a simple modal message box
+ *
+ * \param flags ::SDL_MessageBoxFlags
+ * \param title UTF-8 title text
+ * \param message UTF-8 message text
+ * \param window The parent window, or NULL for no parent
+ *
+ * \return 0 on success, -1 on error
+ *
+ * \sa SDL_ShowMessageBox
+ */
+extern DECLSPEC int SDLCALL SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_messagebox_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_mouse.h b/external/SDL2/include/SDL_mouse.h
new file mode 100644
index 0000000..ea9622f
--- /dev/null
+++ b/external/SDL2/include/SDL_mouse.h
@@ -0,0 +1,300 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_mouse.h
+ *
+ * Include file for SDL mouse event handling.
+ */
+
+#ifndef _SDL_mouse_h
+#define _SDL_mouse_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_video.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct SDL_Cursor SDL_Cursor; /* Implementation dependent */
+
+/**
+ * \brief Cursor types for SDL_CreateSystemCursor.
+ */
+typedef enum
+{
+ SDL_SYSTEM_CURSOR_ARROW, /**< Arrow */
+ SDL_SYSTEM_CURSOR_IBEAM, /**< I-beam */
+ SDL_SYSTEM_CURSOR_WAIT, /**< Wait */
+ SDL_SYSTEM_CURSOR_CROSSHAIR, /**< Crosshair */
+ SDL_SYSTEM_CURSOR_WAITARROW, /**< Small wait cursor (or Wait if not available) */
+ SDL_SYSTEM_CURSOR_SIZENWSE, /**< Double arrow pointing northwest and southeast */
+ SDL_SYSTEM_CURSOR_SIZENESW, /**< Double arrow pointing northeast and southwest */
+ SDL_SYSTEM_CURSOR_SIZEWE, /**< Double arrow pointing west and east */
+ SDL_SYSTEM_CURSOR_SIZENS, /**< Double arrow pointing north and south */
+ SDL_SYSTEM_CURSOR_SIZEALL, /**< Four pointed arrow pointing north, south, east, and west */
+ SDL_SYSTEM_CURSOR_NO, /**< Slashed circle or crossbones */
+ SDL_SYSTEM_CURSOR_HAND, /**< Hand */
+ SDL_NUM_SYSTEM_CURSORS
+} SDL_SystemCursor;
+
+/**
+ * \brief Scroll direction types for the Scroll event
+ */
+typedef enum
+{
+ SDL_MOUSEWHEEL_NORMAL, /**< The scroll direction is normal */
+ SDL_MOUSEWHEEL_FLIPPED /**< The scroll direction is flipped / natural */
+} SDL_MouseWheelDirection;
+
+/* Function prototypes */
+
+/**
+ * \brief Get the window which currently has mouse focus.
+ */
+extern DECLSPEC SDL_Window * SDLCALL SDL_GetMouseFocus(void);
+
+/**
+ * \brief Retrieve the current state of the mouse.
+ *
+ * The current button state is returned as a button bitmask, which can
+ * be tested using the SDL_BUTTON(X) macros, and x and y are set to the
+ * mouse cursor position relative to the focus window for the currently
+ * selected mouse. You can pass NULL for either x or y.
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_GetMouseState(int *x, int *y);
+
+/**
+ * \brief Get the current state of the mouse, in relation to the desktop
+ *
+ * This works just like SDL_GetMouseState(), but the coordinates will be
+ * reported relative to the top-left of the desktop. This can be useful if
+ * you need to track the mouse outside of a specific window and
+ * SDL_CaptureMouse() doesn't fit your needs. For example, it could be
+ * useful if you need to track the mouse while dragging a window, where
+ * coordinates relative to a window might not be in sync at all times.
+ *
+ * \note SDL_GetMouseState() returns the mouse position as SDL understands
+ * it from the last pump of the event queue. This function, however,
+ * queries the OS for the current mouse position, and as such, might
+ * be a slightly less efficient function. Unless you know what you're
+ * doing and have a good reason to use this function, you probably want
+ * SDL_GetMouseState() instead.
+ *
+ * \param x Returns the current X coord, relative to the desktop. Can be NULL.
+ * \param y Returns the current Y coord, relative to the desktop. Can be NULL.
+ * \return The current button state as a bitmask, which can be tested using the SDL_BUTTON(X) macros.
+ *
+ * \sa SDL_GetMouseState
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_GetGlobalMouseState(int *x, int *y);
+
+/**
+ * \brief Retrieve the relative state of the mouse.
+ *
+ * The current button state is returned as a button bitmask, which can
+ * be tested using the SDL_BUTTON(X) macros, and x and y are set to the
+ * mouse deltas since the last call to SDL_GetRelativeMouseState().
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_GetRelativeMouseState(int *x, int *y);
+
+/**
+ * \brief Moves the mouse to the given position within the window.
+ *
+ * \param window The window to move the mouse into, or NULL for the current mouse focus
+ * \param x The x coordinate within the window
+ * \param y The y coordinate within the window
+ *
+ * \note This function generates a mouse motion event
+ */
+extern DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window * window,
+ int x, int y);
+
+/**
+ * \brief Moves the mouse to the given position in global screen space.
+ *
+ * \param x The x coordinate
+ * \param y The y coordinate
+ * \return 0 on success, -1 on error (usually: unsupported by a platform).
+ *
+ * \note This function generates a mouse motion event
+ */
+extern DECLSPEC int SDLCALL SDL_WarpMouseGlobal(int x, int y);
+
+/**
+ * \brief Set relative mouse mode.
+ *
+ * \param enabled Whether or not to enable relative mode
+ *
+ * \return 0 on success, or -1 if relative mode is not supported.
+ *
+ * While the mouse is in relative mode, the cursor is hidden, and the
+ * driver will try to report continuous motion in the current window.
+ * Only relative motion events will be delivered, the mouse position
+ * will not change.
+ *
+ * \note This function will flush any pending mouse motion.
+ *
+ * \sa SDL_GetRelativeMouseMode()
+ */
+extern DECLSPEC int SDLCALL SDL_SetRelativeMouseMode(SDL_bool enabled);
+
+/**
+ * \brief Capture the mouse, to track input outside an SDL window.
+ *
+ * \param enabled Whether or not to enable capturing
+ *
+ * Capturing enables your app to obtain mouse events globally, instead of
+ * just within your window. Not all video targets support this function.
+ * When capturing is enabled, the current window will get all mouse events,
+ * but unlike relative mode, no change is made to the cursor and it is
+ * not restrained to your window.
+ *
+ * This function may also deny mouse input to other windows--both those in
+ * your application and others on the system--so you should use this
+ * function sparingly, and in small bursts. For example, you might want to
+ * track the mouse while the user is dragging something, until the user
+ * releases a mouse button. It is not recommended that you capture the mouse
+ * for long periods of time, such as the entire time your app is running.
+ *
+ * While captured, mouse events still report coordinates relative to the
+ * current (foreground) window, but those coordinates may be outside the
+ * bounds of the window (including negative values). Capturing is only
+ * allowed for the foreground window. If the window loses focus while
+ * capturing, the capture will be disabled automatically.
+ *
+ * While capturing is enabled, the current window will have the
+ * SDL_WINDOW_MOUSE_CAPTURE flag set.
+ *
+ * \return 0 on success, or -1 if not supported.
+ */
+extern DECLSPEC int SDLCALL SDL_CaptureMouse(SDL_bool enabled);
+
+/**
+ * \brief Query whether relative mouse mode is enabled.
+ *
+ * \sa SDL_SetRelativeMouseMode()
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_GetRelativeMouseMode(void);
+
+/**
+ * \brief Create a cursor, using the specified bitmap data and
+ * mask (in MSB format).
+ *
+ * The cursor width must be a multiple of 8 bits.
+ *
+ * The cursor is created in black and white according to the following:
+ * <table>
+ * <tr><td> data </td><td> mask </td><td> resulting pixel on screen </td></tr>
+ * <tr><td> 0 </td><td> 1 </td><td> White </td></tr>
+ * <tr><td> 1 </td><td> 1 </td><td> Black </td></tr>
+ * <tr><td> 0 </td><td> 0 </td><td> Transparent </td></tr>
+ * <tr><td> 1 </td><td> 0 </td><td> Inverted color if possible, black
+ * if not. </td></tr>
+ * </table>
+ *
+ * \sa SDL_FreeCursor()
+ */
+extern DECLSPEC SDL_Cursor *SDLCALL SDL_CreateCursor(const Uint8 * data,
+ const Uint8 * mask,
+ int w, int h, int hot_x,
+ int hot_y);
+
+/**
+ * \brief Create a color cursor.
+ *
+ * \sa SDL_FreeCursor()
+ */
+extern DECLSPEC SDL_Cursor *SDLCALL SDL_CreateColorCursor(SDL_Surface *surface,
+ int hot_x,
+ int hot_y);
+
+/**
+ * \brief Create a system cursor.
+ *
+ * \sa SDL_FreeCursor()
+ */
+extern DECLSPEC SDL_Cursor *SDLCALL SDL_CreateSystemCursor(SDL_SystemCursor id);
+
+/**
+ * \brief Set the active cursor.
+ */
+extern DECLSPEC void SDLCALL SDL_SetCursor(SDL_Cursor * cursor);
+
+/**
+ * \brief Return the active cursor.
+ */
+extern DECLSPEC SDL_Cursor *SDLCALL SDL_GetCursor(void);
+
+/**
+ * \brief Return the default cursor.
+ */
+extern DECLSPEC SDL_Cursor *SDLCALL SDL_GetDefaultCursor(void);
+
+/**
+ * \brief Frees a cursor created with SDL_CreateCursor().
+ *
+ * \sa SDL_CreateCursor()
+ */
+extern DECLSPEC void SDLCALL SDL_FreeCursor(SDL_Cursor * cursor);
+
+/**
+ * \brief Toggle whether or not the cursor is shown.
+ *
+ * \param toggle 1 to show the cursor, 0 to hide it, -1 to query the current
+ * state.
+ *
+ * \return 1 if the cursor is shown, or 0 if the cursor is hidden.
+ */
+extern DECLSPEC int SDLCALL SDL_ShowCursor(int toggle);
+
+/**
+ * Used as a mask when testing buttons in buttonstate.
+ * - Button 1: Left mouse button
+ * - Button 2: Middle mouse button
+ * - Button 3: Right mouse button
+ */
+#define SDL_BUTTON(X) (1 << ((X)-1))
+#define SDL_BUTTON_LEFT 1
+#define SDL_BUTTON_MIDDLE 2
+#define SDL_BUTTON_RIGHT 3
+#define SDL_BUTTON_X1 4
+#define SDL_BUTTON_X2 5
+#define SDL_BUTTON_LMASK SDL_BUTTON(SDL_BUTTON_LEFT)
+#define SDL_BUTTON_MMASK SDL_BUTTON(SDL_BUTTON_MIDDLE)
+#define SDL_BUTTON_RMASK SDL_BUTTON(SDL_BUTTON_RIGHT)
+#define SDL_BUTTON_X1MASK SDL_BUTTON(SDL_BUTTON_X1)
+#define SDL_BUTTON_X2MASK SDL_BUTTON(SDL_BUTTON_X2)
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_mouse_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_mutex.h b/external/SDL2/include/SDL_mutex.h
new file mode 100644
index 0000000..b7e3973
--- /dev/null
+++ b/external/SDL2/include/SDL_mutex.h
@@ -0,0 +1,251 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_mutex_h
+#define _SDL_mutex_h
+
+/**
+ * \file SDL_mutex.h
+ *
+ * Functions to provide thread synchronization primitives.
+ */
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Synchronization functions which can time out return this value
+ * if they time out.
+ */
+#define SDL_MUTEX_TIMEDOUT 1
+
+/**
+ * This is the timeout value which corresponds to never time out.
+ */
+#define SDL_MUTEX_MAXWAIT (~(Uint32)0)
+
+
+/**
+ * \name Mutex functions
+ */
+/* @{ */
+
+/* The SDL mutex structure, defined in SDL_sysmutex.c */
+struct SDL_mutex;
+typedef struct SDL_mutex SDL_mutex;
+
+/**
+ * Create a mutex, initialized unlocked.
+ */
+extern DECLSPEC SDL_mutex *SDLCALL SDL_CreateMutex(void);
+
+/**
+ * Lock the mutex.
+ *
+ * \return 0, or -1 on error.
+ */
+#define SDL_mutexP(m) SDL_LockMutex(m)
+extern DECLSPEC int SDLCALL SDL_LockMutex(SDL_mutex * mutex);
+
+/**
+ * Try to lock the mutex
+ *
+ * \return 0, SDL_MUTEX_TIMEDOUT, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_TryLockMutex(SDL_mutex * mutex);
+
+/**
+ * Unlock the mutex.
+ *
+ * \return 0, or -1 on error.
+ *
+ * \warning It is an error to unlock a mutex that has not been locked by
+ * the current thread, and doing so results in undefined behavior.
+ */
+#define SDL_mutexV(m) SDL_UnlockMutex(m)
+extern DECLSPEC int SDLCALL SDL_UnlockMutex(SDL_mutex * mutex);
+
+/**
+ * Destroy a mutex.
+ */
+extern DECLSPEC void SDLCALL SDL_DestroyMutex(SDL_mutex * mutex);
+
+/* @} *//* Mutex functions */
+
+
+/**
+ * \name Semaphore functions
+ */
+/* @{ */
+
+/* The SDL semaphore structure, defined in SDL_syssem.c */
+struct SDL_semaphore;
+typedef struct SDL_semaphore SDL_sem;
+
+/**
+ * Create a semaphore, initialized with value, returns NULL on failure.
+ */
+extern DECLSPEC SDL_sem *SDLCALL SDL_CreateSemaphore(Uint32 initial_value);
+
+/**
+ * Destroy a semaphore.
+ */
+extern DECLSPEC void SDLCALL SDL_DestroySemaphore(SDL_sem * sem);
+
+/**
+ * This function suspends the calling thread until the semaphore pointed
+ * to by \c sem has a positive count. It then atomically decreases the
+ * semaphore count.
+ */
+extern DECLSPEC int SDLCALL SDL_SemWait(SDL_sem * sem);
+
+/**
+ * Non-blocking variant of SDL_SemWait().
+ *
+ * \return 0 if the wait succeeds, ::SDL_MUTEX_TIMEDOUT if the wait would
+ * block, and -1 on error.
+ */
+extern DECLSPEC int SDLCALL SDL_SemTryWait(SDL_sem * sem);
+
+/**
+ * Variant of SDL_SemWait() with a timeout in milliseconds.
+ *
+ * \return 0 if the wait succeeds, ::SDL_MUTEX_TIMEDOUT if the wait does not
+ * succeed in the allotted time, and -1 on error.
+ *
+ * \warning On some platforms this function is implemented by looping with a
+ * delay of 1 ms, and so should be avoided if possible.
+ */
+extern DECLSPEC int SDLCALL SDL_SemWaitTimeout(SDL_sem * sem, Uint32 ms);
+
+/**
+ * Atomically increases the semaphore's count (not blocking).
+ *
+ * \return 0, or -1 on error.
+ */
+extern DECLSPEC int SDLCALL SDL_SemPost(SDL_sem * sem);
+
+/**
+ * Returns the current count of the semaphore.
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_SemValue(SDL_sem * sem);
+
+/* @} *//* Semaphore functions */
+
+
+/**
+ * \name Condition variable functions
+ */
+/* @{ */
+
+/* The SDL condition variable structure, defined in SDL_syscond.c */
+struct SDL_cond;
+typedef struct SDL_cond SDL_cond;
+
+/**
+ * Create a condition variable.
+ *
+ * Typical use of condition variables:
+ *
+ * Thread A:
+ * SDL_LockMutex(lock);
+ * while ( ! condition ) {
+ * SDL_CondWait(cond, lock);
+ * }
+ * SDL_UnlockMutex(lock);
+ *
+ * Thread B:
+ * SDL_LockMutex(lock);
+ * ...
+ * condition = true;
+ * ...
+ * SDL_CondSignal(cond);
+ * SDL_UnlockMutex(lock);
+ *
+ * There is some discussion whether to signal the condition variable
+ * with the mutex locked or not. There is some potential performance
+ * benefit to unlocking first on some platforms, but there are some
+ * potential race conditions depending on how your code is structured.
+ *
+ * In general it's safer to signal the condition variable while the
+ * mutex is locked.
+ */
+extern DECLSPEC SDL_cond *SDLCALL SDL_CreateCond(void);
+
+/**
+ * Destroy a condition variable.
+ */
+extern DECLSPEC void SDLCALL SDL_DestroyCond(SDL_cond * cond);
+
+/**
+ * Restart one of the threads that are waiting on the condition variable.
+ *
+ * \return 0 or -1 on error.
+ */
+extern DECLSPEC int SDLCALL SDL_CondSignal(SDL_cond * cond);
+
+/**
+ * Restart all threads that are waiting on the condition variable.
+ *
+ * \return 0 or -1 on error.
+ */
+extern DECLSPEC int SDLCALL SDL_CondBroadcast(SDL_cond * cond);
+
+/**
+ * Wait on the condition variable, unlocking the provided mutex.
+ *
+ * \warning The mutex must be locked before entering this function!
+ *
+ * The mutex is re-locked once the condition variable is signaled.
+ *
+ * \return 0 when it is signaled, or -1 on error.
+ */
+extern DECLSPEC int SDLCALL SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex);
+
+/**
+ * Waits for at most \c ms milliseconds, and returns 0 if the condition
+ * variable is signaled, ::SDL_MUTEX_TIMEDOUT if the condition is not
+ * signaled in the allotted time, and -1 on error.
+ *
+ * \warning On some platforms this function is implemented by looping with a
+ * delay of 1 ms, and so should be avoided if possible.
+ */
+extern DECLSPEC int SDLCALL SDL_CondWaitTimeout(SDL_cond * cond,
+ SDL_mutex * mutex, Uint32 ms);
+
+/* @} *//* Condition variable functions */
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_mutex_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_name.h b/external/SDL2/include/SDL_name.h
new file mode 100644
index 0000000..06cd4a5
--- /dev/null
+++ b/external/SDL2/include/SDL_name.h
@@ -0,0 +1,33 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDLname_h_
+#define _SDLname_h_
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define NeedFunctionPrototypes 1
+#endif
+
+#define SDL_NAME(X) SDL_##X
+
+#endif /* _SDLname_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_opengl.h b/external/SDL2/include/SDL_opengl.h
new file mode 100644
index 0000000..780919b
--- /dev/null
+++ b/external/SDL2/include/SDL_opengl.h
@@ -0,0 +1,2176 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_opengl.h
+ *
+ * This is a simple file to encapsulate the OpenGL API headers.
+ */
+
+/**
+ * \def NO_SDL_GLEXT
+ *
+ * Define this if you have your own version of glext.h and want to disable the
+ * version included in SDL_opengl.h.
+ */
+
+#ifndef _SDL_opengl_h
+#define _SDL_opengl_h
+
+#include "SDL_config.h"
+
+#ifndef __IPHONEOS__ /* No OpenGL on iOS. */
+
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef __gl_h_
+#define __gl_h_
+
+#if defined(USE_MGL_NAMESPACE)
+#include "gl_mangle.h"
+#endif
+
+
+/**********************************************************************
+ * Begin system-specific stuff.
+ */
+
+#if defined(_WIN32) && !defined(__WIN32__) && !defined(__CYGWIN__)
+#define __WIN32__
+#endif
+
+#if defined(__WIN32__) && !defined(__CYGWIN__)
+# if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(BUILD_GL32) /* tag specify we're building mesa as a DLL */
+# define GLAPI __declspec(dllexport)
+# elif (defined(_MSC_VER) || defined(__MINGW32__)) && defined(_DLL) /* tag specifying we're building for DLL runtime support */
+# define GLAPI __declspec(dllimport)
+# else /* for use with static link lib build of Win32 edition only */
+# define GLAPI extern
+# endif /* _STATIC_MESA support */
+# if defined(__MINGW32__) && defined(GL_NO_STDCALL) || defined(UNDER_CE) /* The generated DLLs by MingW with STDCALL are not compatible with the ones done by Microsoft's compilers */
+# define GLAPIENTRY
+# else
+# define GLAPIENTRY __stdcall
+# endif
+#elif defined(__CYGWIN__) && defined(USE_OPENGL32) /* use native windows opengl32 */
+# define GLAPI extern
+# define GLAPIENTRY __stdcall
+#elif (defined(__GNUC__) && __GNUC__ >= 4) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
+# define GLAPI __attribute__((visibility("default")))
+# define GLAPIENTRY
+#endif /* WIN32 && !CYGWIN */
+
+/*
+ * WINDOWS: Include windows.h here to define APIENTRY.
+ * It is also useful when applications include this file by
+ * including only glut.h, since glut.h depends on windows.h.
+ * Applications needing to include windows.h with parms other
+ * than "WIN32_LEAN_AND_MEAN" may include windows.h before
+ * glut.h or gl.h.
+ */
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__)
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#ifndef NOMINMAX /* don't define min() and max(). */
+#define NOMINMAX
+#endif
+#include <windows.h>
+#endif
+
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+
+#ifndef GLAPIENTRY
+#define GLAPIENTRY
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY GLAPIENTRY
+#endif
+
+/* "P" suffix to be used for a pointer to a function */
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+
+#ifndef GLAPIENTRYP
+#define GLAPIENTRYP GLAPIENTRY *
+#endif
+
+#if defined(PRAGMA_EXPORT_SUPPORTED)
+#pragma export on
+#endif
+
+/*
+ * End system-specific stuff.
+ **********************************************************************/
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#define GL_VERSION_1_1 1
+#define GL_VERSION_1_2 1
+#define GL_VERSION_1_3 1
+#define GL_ARB_imaging 1
+
+
+/*
+ * Datatypes
+ */
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef void GLvoid;
+typedef signed char GLbyte; /* 1-byte signed */
+typedef short GLshort; /* 2-byte signed */
+typedef int GLint; /* 4-byte signed */
+typedef unsigned char GLubyte; /* 1-byte unsigned */
+typedef unsigned short GLushort; /* 2-byte unsigned */
+typedef unsigned int GLuint; /* 4-byte unsigned */
+typedef int GLsizei; /* 4-byte signed */
+typedef float GLfloat; /* single precision float */
+typedef float GLclampf; /* single precision float in [0,1] */
+typedef double GLdouble; /* double precision float */
+typedef double GLclampd; /* double precision float in [0,1] */
+
+
+
+/*
+ * Constants
+ */
+
+/* Boolean values */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* Data types */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_2_BYTES 0x1407
+#define GL_3_BYTES 0x1408
+#define GL_4_BYTES 0x1409
+#define GL_DOUBLE 0x140A
+
+/* Primitives */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+#define GL_QUADS 0x0007
+#define GL_QUAD_STRIP 0x0008
+#define GL_POLYGON 0x0009
+
+/* Vertex Arrays */
+#define GL_VERTEX_ARRAY 0x8074
+#define GL_NORMAL_ARRAY 0x8075
+#define GL_COLOR_ARRAY 0x8076
+#define GL_INDEX_ARRAY 0x8077
+#define GL_TEXTURE_COORD_ARRAY 0x8078
+#define GL_EDGE_FLAG_ARRAY 0x8079
+#define GL_VERTEX_ARRAY_SIZE 0x807A
+#define GL_VERTEX_ARRAY_TYPE 0x807B
+#define GL_VERTEX_ARRAY_STRIDE 0x807C
+#define GL_NORMAL_ARRAY_TYPE 0x807E
+#define GL_NORMAL_ARRAY_STRIDE 0x807F
+#define GL_COLOR_ARRAY_SIZE 0x8081
+#define GL_COLOR_ARRAY_TYPE 0x8082
+#define GL_COLOR_ARRAY_STRIDE 0x8083
+#define GL_INDEX_ARRAY_TYPE 0x8085
+#define GL_INDEX_ARRAY_STRIDE 0x8086
+#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A
+#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C
+#define GL_VERTEX_ARRAY_POINTER 0x808E
+#define GL_NORMAL_ARRAY_POINTER 0x808F
+#define GL_COLOR_ARRAY_POINTER 0x8090
+#define GL_INDEX_ARRAY_POINTER 0x8091
+#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092
+#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093
+#define GL_V2F 0x2A20
+#define GL_V3F 0x2A21
+#define GL_C4UB_V2F 0x2A22
+#define GL_C4UB_V3F 0x2A23
+#define GL_C3F_V3F 0x2A24
+#define GL_N3F_V3F 0x2A25
+#define GL_C4F_N3F_V3F 0x2A26
+#define GL_T2F_V3F 0x2A27
+#define GL_T4F_V4F 0x2A28
+#define GL_T2F_C4UB_V3F 0x2A29
+#define GL_T2F_C3F_V3F 0x2A2A
+#define GL_T2F_N3F_V3F 0x2A2B
+#define GL_T2F_C4F_N3F_V3F 0x2A2C
+#define GL_T4F_C4F_N3F_V4F 0x2A2D
+
+/* Matrix Mode */
+#define GL_MATRIX_MODE 0x0BA0
+#define GL_MODELVIEW 0x1700
+#define GL_PROJECTION 0x1701
+#define GL_TEXTURE 0x1702
+
+/* Points */
+#define GL_POINT_SMOOTH 0x0B10
+#define GL_POINT_SIZE 0x0B11
+#define GL_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_POINT_SIZE_RANGE 0x0B12
+
+/* Lines */
+#define GL_LINE_SMOOTH 0x0B20
+#define GL_LINE_STIPPLE 0x0B24
+#define GL_LINE_STIPPLE_PATTERN 0x0B25
+#define GL_LINE_STIPPLE_REPEAT 0x0B26
+#define GL_LINE_WIDTH 0x0B21
+#define GL_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_LINE_WIDTH_RANGE 0x0B22
+
+/* Polygons */
+#define GL_POINT 0x1B00
+#define GL_LINE 0x1B01
+#define GL_FILL 0x1B02
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_POLYGON_MODE 0x0B40
+#define GL_POLYGON_SMOOTH 0x0B41
+#define GL_POLYGON_STIPPLE 0x0B42
+#define GL_EDGE_FLAG 0x0B43
+#define GL_CULL_FACE 0x0B44
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+#define GL_POLYGON_OFFSET_POINT 0x2A01
+#define GL_POLYGON_OFFSET_LINE 0x2A02
+#define GL_POLYGON_OFFSET_FILL 0x8037
+
+/* Display Lists */
+#define GL_COMPILE 0x1300
+#define GL_COMPILE_AND_EXECUTE 0x1301
+#define GL_LIST_BASE 0x0B32
+#define GL_LIST_INDEX 0x0B33
+#define GL_LIST_MODE 0x0B30
+
+/* Depth buffer */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+#define GL_DEPTH_TEST 0x0B71
+#define GL_DEPTH_BITS 0x0D56
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_COMPONENT 0x1902
+
+/* Lighting */
+#define GL_LIGHTING 0x0B50
+#define GL_LIGHT0 0x4000
+#define GL_LIGHT1 0x4001
+#define GL_LIGHT2 0x4002
+#define GL_LIGHT3 0x4003
+#define GL_LIGHT4 0x4004
+#define GL_LIGHT5 0x4005
+#define GL_LIGHT6 0x4006
+#define GL_LIGHT7 0x4007
+#define GL_SPOT_EXPONENT 0x1205
+#define GL_SPOT_CUTOFF 0x1206
+#define GL_CONSTANT_ATTENUATION 0x1207
+#define GL_LINEAR_ATTENUATION 0x1208
+#define GL_QUADRATIC_ATTENUATION 0x1209
+#define GL_AMBIENT 0x1200
+#define GL_DIFFUSE 0x1201
+#define GL_SPECULAR 0x1202
+#define GL_SHININESS 0x1601
+#define GL_EMISSION 0x1600
+#define GL_POSITION 0x1203
+#define GL_SPOT_DIRECTION 0x1204
+#define GL_AMBIENT_AND_DIFFUSE 0x1602
+#define GL_COLOR_INDEXES 0x1603
+#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52
+#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51
+#define GL_LIGHT_MODEL_AMBIENT 0x0B53
+#define GL_FRONT_AND_BACK 0x0408
+#define GL_SHADE_MODEL 0x0B54
+#define GL_FLAT 0x1D00
+#define GL_SMOOTH 0x1D01
+#define GL_COLOR_MATERIAL 0x0B57
+#define GL_COLOR_MATERIAL_FACE 0x0B55
+#define GL_COLOR_MATERIAL_PARAMETER 0x0B56
+#define GL_NORMALIZE 0x0BA1
+
+/* User clipping planes */
+#define GL_CLIP_PLANE0 0x3000
+#define GL_CLIP_PLANE1 0x3001
+#define GL_CLIP_PLANE2 0x3002
+#define GL_CLIP_PLANE3 0x3003
+#define GL_CLIP_PLANE4 0x3004
+#define GL_CLIP_PLANE5 0x3005
+
+/* Accumulation buffer */
+#define GL_ACCUM_RED_BITS 0x0D58
+#define GL_ACCUM_GREEN_BITS 0x0D59
+#define GL_ACCUM_BLUE_BITS 0x0D5A
+#define GL_ACCUM_ALPHA_BITS 0x0D5B
+#define GL_ACCUM_CLEAR_VALUE 0x0B80
+#define GL_ACCUM 0x0100
+#define GL_ADD 0x0104
+#define GL_LOAD 0x0101
+#define GL_MULT 0x0103
+#define GL_RETURN 0x0102
+
+/* Alpha testing */
+#define GL_ALPHA_TEST 0x0BC0
+#define GL_ALPHA_TEST_REF 0x0BC2
+#define GL_ALPHA_TEST_FUNC 0x0BC1
+
+/* Blending */
+#define GL_BLEND 0x0BE2
+#define GL_BLEND_SRC 0x0BE1
+#define GL_BLEND_DST 0x0BE0
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+
+/* Render Mode */
+#define GL_FEEDBACK 0x1C01
+#define GL_RENDER 0x1C00
+#define GL_SELECT 0x1C02
+
+/* Feedback */
+#define GL_2D 0x0600
+#define GL_3D 0x0601
+#define GL_3D_COLOR 0x0602
+#define GL_3D_COLOR_TEXTURE 0x0603
+#define GL_4D_COLOR_TEXTURE 0x0604
+#define GL_POINT_TOKEN 0x0701
+#define GL_LINE_TOKEN 0x0702
+#define GL_LINE_RESET_TOKEN 0x0707
+#define GL_POLYGON_TOKEN 0x0703
+#define GL_BITMAP_TOKEN 0x0704
+#define GL_DRAW_PIXEL_TOKEN 0x0705
+#define GL_COPY_PIXEL_TOKEN 0x0706
+#define GL_PASS_THROUGH_TOKEN 0x0700
+#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0
+#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1
+#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2
+
+/* Selection */
+#define GL_SELECTION_BUFFER_POINTER 0x0DF3
+#define GL_SELECTION_BUFFER_SIZE 0x0DF4
+
+/* Fog */
+#define GL_FOG 0x0B60
+#define GL_FOG_MODE 0x0B65
+#define GL_FOG_DENSITY 0x0B62
+#define GL_FOG_COLOR 0x0B66
+#define GL_FOG_INDEX 0x0B61
+#define GL_FOG_START 0x0B63
+#define GL_FOG_END 0x0B64
+#define GL_LINEAR 0x2601
+#define GL_EXP 0x0800
+#define GL_EXP2 0x0801
+
+/* Logic Ops */
+#define GL_LOGIC_OP 0x0BF1
+#define GL_INDEX_LOGIC_OP 0x0BF1
+#define GL_COLOR_LOGIC_OP 0x0BF2
+#define GL_LOGIC_OP_MODE 0x0BF0
+#define GL_CLEAR 0x1500
+#define GL_SET 0x150F
+#define GL_COPY 0x1503
+#define GL_COPY_INVERTED 0x150C
+#define GL_NOOP 0x1505
+#define GL_INVERT 0x150A
+#define GL_AND 0x1501
+#define GL_NAND 0x150E
+#define GL_OR 0x1507
+#define GL_NOR 0x1508
+#define GL_XOR 0x1506
+#define GL_EQUIV 0x1509
+#define GL_AND_REVERSE 0x1502
+#define GL_AND_INVERTED 0x1504
+#define GL_OR_REVERSE 0x150B
+#define GL_OR_INVERTED 0x150D
+
+/* Stencil */
+#define GL_STENCIL_BITS 0x0D57
+#define GL_STENCIL_TEST 0x0B90
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STENCIL_INDEX 0x1901
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+
+/* Buffers, Pixel Drawing/Reading */
+#define GL_NONE 0
+#define GL_LEFT 0x0406
+#define GL_RIGHT 0x0407
+/*GL_FRONT 0x0404 */
+/*GL_BACK 0x0405 */
+/*GL_FRONT_AND_BACK 0x0408 */
+#define GL_FRONT_LEFT 0x0400
+#define GL_FRONT_RIGHT 0x0401
+#define GL_BACK_LEFT 0x0402
+#define GL_BACK_RIGHT 0x0403
+#define GL_AUX0 0x0409
+#define GL_AUX1 0x040A
+#define GL_AUX2 0x040B
+#define GL_AUX3 0x040C
+#define GL_COLOR_INDEX 0x1900
+#define GL_RED 0x1903
+#define GL_GREEN 0x1904
+#define GL_BLUE 0x1905
+#define GL_ALPHA 0x1906
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+#define GL_ALPHA_BITS 0x0D55
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_INDEX_BITS 0x0D51
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_AUX_BUFFERS 0x0C00
+#define GL_READ_BUFFER 0x0C02
+#define GL_DRAW_BUFFER 0x0C01
+#define GL_DOUBLEBUFFER 0x0C32
+#define GL_STEREO 0x0C33
+#define GL_BITMAP 0x1A00
+#define GL_COLOR 0x1800
+#define GL_DEPTH 0x1801
+#define GL_STENCIL 0x1802
+#define GL_DITHER 0x0BD0
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+
+/* Implementation limits */
+#define GL_MAX_LIST_NESTING 0x0B31
+#define GL_MAX_EVAL_ORDER 0x0D30
+#define GL_MAX_LIGHTS 0x0D31
+#define GL_MAX_CLIP_PLANES 0x0D32
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_PIXEL_MAP_TABLE 0x0D34
+#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35
+#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36
+#define GL_MAX_NAME_STACK_DEPTH 0x0D37
+#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38
+#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B
+
+/* Gets */
+#define GL_ATTRIB_STACK_DEPTH 0x0BB0
+#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_CURRENT_INDEX 0x0B01
+#define GL_CURRENT_COLOR 0x0B00
+#define GL_CURRENT_NORMAL 0x0B02
+#define GL_CURRENT_RASTER_COLOR 0x0B04
+#define GL_CURRENT_RASTER_DISTANCE 0x0B09
+#define GL_CURRENT_RASTER_INDEX 0x0B05
+#define GL_CURRENT_RASTER_POSITION 0x0B07
+#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06
+#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08
+#define GL_CURRENT_TEXTURE_COORDS 0x0B03
+#define GL_INDEX_CLEAR_VALUE 0x0C20
+#define GL_INDEX_MODE 0x0C30
+#define GL_INDEX_WRITEMASK 0x0C21
+#define GL_MODELVIEW_MATRIX 0x0BA6
+#define GL_MODELVIEW_STACK_DEPTH 0x0BA3
+#define GL_NAME_STACK_DEPTH 0x0D70
+#define GL_PROJECTION_MATRIX 0x0BA7
+#define GL_PROJECTION_STACK_DEPTH 0x0BA4
+#define GL_RENDER_MODE 0x0C40
+#define GL_RGBA_MODE 0x0C31
+#define GL_TEXTURE_MATRIX 0x0BA8
+#define GL_TEXTURE_STACK_DEPTH 0x0BA5
+#define GL_VIEWPORT 0x0BA2
+
+/* Evaluators */
+#define GL_AUTO_NORMAL 0x0D80
+#define GL_MAP1_COLOR_4 0x0D90
+#define GL_MAP1_INDEX 0x0D91
+#define GL_MAP1_NORMAL 0x0D92
+#define GL_MAP1_TEXTURE_COORD_1 0x0D93
+#define GL_MAP1_TEXTURE_COORD_2 0x0D94
+#define GL_MAP1_TEXTURE_COORD_3 0x0D95
+#define GL_MAP1_TEXTURE_COORD_4 0x0D96
+#define GL_MAP1_VERTEX_3 0x0D97
+#define GL_MAP1_VERTEX_4 0x0D98
+#define GL_MAP2_COLOR_4 0x0DB0
+#define GL_MAP2_INDEX 0x0DB1
+#define GL_MAP2_NORMAL 0x0DB2
+#define GL_MAP2_TEXTURE_COORD_1 0x0DB3
+#define GL_MAP2_TEXTURE_COORD_2 0x0DB4
+#define GL_MAP2_TEXTURE_COORD_3 0x0DB5
+#define GL_MAP2_TEXTURE_COORD_4 0x0DB6
+#define GL_MAP2_VERTEX_3 0x0DB7
+#define GL_MAP2_VERTEX_4 0x0DB8
+#define GL_MAP1_GRID_DOMAIN 0x0DD0
+#define GL_MAP1_GRID_SEGMENTS 0x0DD1
+#define GL_MAP2_GRID_DOMAIN 0x0DD2
+#define GL_MAP2_GRID_SEGMENTS 0x0DD3
+#define GL_COEFF 0x0A00
+#define GL_ORDER 0x0A01
+#define GL_DOMAIN 0x0A02
+
+/* Hints */
+#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50
+#define GL_POINT_SMOOTH_HINT 0x0C51
+#define GL_LINE_SMOOTH_HINT 0x0C52
+#define GL_POLYGON_SMOOTH_HINT 0x0C53
+#define GL_FOG_HINT 0x0C54
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* Scissor box */
+#define GL_SCISSOR_BOX 0x0C10
+#define GL_SCISSOR_TEST 0x0C11
+
+/* Pixel Mode / Transfer */
+#define GL_MAP_COLOR 0x0D10
+#define GL_MAP_STENCIL 0x0D11
+#define GL_INDEX_SHIFT 0x0D12
+#define GL_INDEX_OFFSET 0x0D13
+#define GL_RED_SCALE 0x0D14
+#define GL_RED_BIAS 0x0D15
+#define GL_GREEN_SCALE 0x0D18
+#define GL_GREEN_BIAS 0x0D19
+#define GL_BLUE_SCALE 0x0D1A
+#define GL_BLUE_BIAS 0x0D1B
+#define GL_ALPHA_SCALE 0x0D1C
+#define GL_ALPHA_BIAS 0x0D1D
+#define GL_DEPTH_SCALE 0x0D1E
+#define GL_DEPTH_BIAS 0x0D1F
+#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1
+#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0
+#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2
+#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3
+#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4
+#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5
+#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6
+#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7
+#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8
+#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9
+#define GL_PIXEL_MAP_S_TO_S 0x0C71
+#define GL_PIXEL_MAP_I_TO_I 0x0C70
+#define GL_PIXEL_MAP_I_TO_R 0x0C72
+#define GL_PIXEL_MAP_I_TO_G 0x0C73
+#define GL_PIXEL_MAP_I_TO_B 0x0C74
+#define GL_PIXEL_MAP_I_TO_A 0x0C75
+#define GL_PIXEL_MAP_R_TO_R 0x0C76
+#define GL_PIXEL_MAP_G_TO_G 0x0C77
+#define GL_PIXEL_MAP_B_TO_B 0x0C78
+#define GL_PIXEL_MAP_A_TO_A 0x0C79
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_PACK_LSB_FIRST 0x0D01
+#define GL_PACK_ROW_LENGTH 0x0D02
+#define GL_PACK_SKIP_PIXELS 0x0D04
+#define GL_PACK_SKIP_ROWS 0x0D03
+#define GL_PACK_SWAP_BYTES 0x0D00
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_UNPACK_LSB_FIRST 0x0CF1
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GL_UNPACK_SKIP_PIXELS 0x0CF4
+#define GL_UNPACK_SKIP_ROWS 0x0CF3
+#define GL_UNPACK_SWAP_BYTES 0x0CF0
+#define GL_ZOOM_X 0x0D16
+#define GL_ZOOM_Y 0x0D17
+
+/* Texture mapping */
+#define GL_TEXTURE_ENV 0x2300
+#define GL_TEXTURE_ENV_MODE 0x2200
+#define GL_TEXTURE_1D 0x0DE0
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_ENV_COLOR 0x2201
+#define GL_TEXTURE_GEN_S 0x0C60
+#define GL_TEXTURE_GEN_T 0x0C61
+#define GL_TEXTURE_GEN_R 0x0C62
+#define GL_TEXTURE_GEN_Q 0x0C63
+#define GL_TEXTURE_GEN_MODE 0x2500
+#define GL_TEXTURE_BORDER_COLOR 0x1004
+#define GL_TEXTURE_WIDTH 0x1000
+#define GL_TEXTURE_HEIGHT 0x1001
+#define GL_TEXTURE_BORDER 0x1005
+#define GL_TEXTURE_COMPONENTS 0x1003
+#define GL_TEXTURE_RED_SIZE 0x805C
+#define GL_TEXTURE_GREEN_SIZE 0x805D
+#define GL_TEXTURE_BLUE_SIZE 0x805E
+#define GL_TEXTURE_ALPHA_SIZE 0x805F
+#define GL_TEXTURE_LUMINANCE_SIZE 0x8060
+#define GL_TEXTURE_INTENSITY_SIZE 0x8061
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+#define GL_OBJECT_LINEAR 0x2401
+#define GL_OBJECT_PLANE 0x2501
+#define GL_EYE_LINEAR 0x2400
+#define GL_EYE_PLANE 0x2502
+#define GL_SPHERE_MAP 0x2402
+#define GL_DECAL 0x2101
+#define GL_MODULATE 0x2100
+#define GL_NEAREST 0x2600
+#define GL_REPEAT 0x2901
+#define GL_CLAMP 0x2900
+#define GL_S 0x2000
+#define GL_T 0x2001
+#define GL_R 0x2002
+#define GL_Q 0x2003
+
+/* Utility */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* Errors */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_STACK_OVERFLOW 0x0503
+#define GL_STACK_UNDERFLOW 0x0504
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* glPush/PopAttrib bits */
+#define GL_CURRENT_BIT 0x00000001
+#define GL_POINT_BIT 0x00000002
+#define GL_LINE_BIT 0x00000004
+#define GL_POLYGON_BIT 0x00000008
+#define GL_POLYGON_STIPPLE_BIT 0x00000010
+#define GL_PIXEL_MODE_BIT 0x00000020
+#define GL_LIGHTING_BIT 0x00000040
+#define GL_FOG_BIT 0x00000080
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_ACCUM_BUFFER_BIT 0x00000200
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_VIEWPORT_BIT 0x00000800
+#define GL_TRANSFORM_BIT 0x00001000
+#define GL_ENABLE_BIT 0x00002000
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_HINT_BIT 0x00008000
+#define GL_EVAL_BIT 0x00010000
+#define GL_LIST_BIT 0x00020000
+#define GL_TEXTURE_BIT 0x00040000
+#define GL_SCISSOR_BIT 0x00080000
+#define GL_ALL_ATTRIB_BITS 0x000FFFFF
+
+
+/* OpenGL 1.1 */
+#define GL_PROXY_TEXTURE_1D 0x8063
+#define GL_PROXY_TEXTURE_2D 0x8064
+#define GL_TEXTURE_PRIORITY 0x8066
+#define GL_TEXTURE_RESIDENT 0x8067
+#define GL_TEXTURE_BINDING_1D 0x8068
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_TEXTURE_INTERNAL_FORMAT 0x1003
+#define GL_ALPHA4 0x803B
+#define GL_ALPHA8 0x803C
+#define GL_ALPHA12 0x803D
+#define GL_ALPHA16 0x803E
+#define GL_LUMINANCE4 0x803F
+#define GL_LUMINANCE8 0x8040
+#define GL_LUMINANCE12 0x8041
+#define GL_LUMINANCE16 0x8042
+#define GL_LUMINANCE4_ALPHA4 0x8043
+#define GL_LUMINANCE6_ALPHA2 0x8044
+#define GL_LUMINANCE8_ALPHA8 0x8045
+#define GL_LUMINANCE12_ALPHA4 0x8046
+#define GL_LUMINANCE12_ALPHA12 0x8047
+#define GL_LUMINANCE16_ALPHA16 0x8048
+#define GL_INTENSITY 0x8049
+#define GL_INTENSITY4 0x804A
+#define GL_INTENSITY8 0x804B
+#define GL_INTENSITY12 0x804C
+#define GL_INTENSITY16 0x804D
+#define GL_R3_G3_B2 0x2A10
+#define GL_RGB4 0x804F
+#define GL_RGB5 0x8050
+#define GL_RGB8 0x8051
+#define GL_RGB10 0x8052
+#define GL_RGB12 0x8053
+#define GL_RGB16 0x8054
+#define GL_RGBA2 0x8055
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGBA8 0x8058
+#define GL_RGB10_A2 0x8059
+#define GL_RGBA12 0x805A
+#define GL_RGBA16 0x805B
+#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001
+#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002
+#define GL_ALL_CLIENT_ATTRIB_BITS 0xFFFFFFFF
+#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF
+
+
+
+/*
+ * Miscellaneous
+ */
+
+GLAPI void GLAPIENTRY glClearIndex( GLfloat c );
+
+GLAPI void GLAPIENTRY glClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
+
+GLAPI void GLAPIENTRY glClear( GLbitfield mask );
+
+GLAPI void GLAPIENTRY glIndexMask( GLuint mask );
+
+GLAPI void GLAPIENTRY glColorMask( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha );
+
+GLAPI void GLAPIENTRY glAlphaFunc( GLenum func, GLclampf ref );
+
+GLAPI void GLAPIENTRY glBlendFunc( GLenum sfactor, GLenum dfactor );
+
+GLAPI void GLAPIENTRY glLogicOp( GLenum opcode );
+
+GLAPI void GLAPIENTRY glCullFace( GLenum mode );
+
+GLAPI void GLAPIENTRY glFrontFace( GLenum mode );
+
+GLAPI void GLAPIENTRY glPointSize( GLfloat size );
+
+GLAPI void GLAPIENTRY glLineWidth( GLfloat width );
+
+GLAPI void GLAPIENTRY glLineStipple( GLint factor, GLushort pattern );
+
+GLAPI void GLAPIENTRY glPolygonMode( GLenum face, GLenum mode );
+
+GLAPI void GLAPIENTRY glPolygonOffset( GLfloat factor, GLfloat units );
+
+GLAPI void GLAPIENTRY glPolygonStipple( const GLubyte *mask );
+
+GLAPI void GLAPIENTRY glGetPolygonStipple( GLubyte *mask );
+
+GLAPI void GLAPIENTRY glEdgeFlag( GLboolean flag );
+
+GLAPI void GLAPIENTRY glEdgeFlagv( const GLboolean *flag );
+
+GLAPI void GLAPIENTRY glScissor( GLint x, GLint y, GLsizei width, GLsizei height);
+
+GLAPI void GLAPIENTRY glClipPlane( GLenum plane, const GLdouble *equation );
+
+GLAPI void GLAPIENTRY glGetClipPlane( GLenum plane, GLdouble *equation );
+
+GLAPI void GLAPIENTRY glDrawBuffer( GLenum mode );
+
+GLAPI void GLAPIENTRY glReadBuffer( GLenum mode );
+
+GLAPI void GLAPIENTRY glEnable( GLenum cap );
+
+GLAPI void GLAPIENTRY glDisable( GLenum cap );
+
+GLAPI GLboolean GLAPIENTRY glIsEnabled( GLenum cap );
+
+
+GLAPI void GLAPIENTRY glEnableClientState( GLenum cap ); /* 1.1 */
+
+GLAPI void GLAPIENTRY glDisableClientState( GLenum cap ); /* 1.1 */
+
+
+GLAPI void GLAPIENTRY glGetBooleanv( GLenum pname, GLboolean *params );
+
+GLAPI void GLAPIENTRY glGetDoublev( GLenum pname, GLdouble *params );
+
+GLAPI void GLAPIENTRY glGetFloatv( GLenum pname, GLfloat *params );
+
+GLAPI void GLAPIENTRY glGetIntegerv( GLenum pname, GLint *params );
+
+
+GLAPI void GLAPIENTRY glPushAttrib( GLbitfield mask );
+
+GLAPI void GLAPIENTRY glPopAttrib( void );
+
+
+GLAPI void GLAPIENTRY glPushClientAttrib( GLbitfield mask ); /* 1.1 */
+
+GLAPI void GLAPIENTRY glPopClientAttrib( void ); /* 1.1 */
+
+
+GLAPI GLint GLAPIENTRY glRenderMode( GLenum mode );
+
+GLAPI GLenum GLAPIENTRY glGetError( void );
+
+GLAPI const GLubyte * GLAPIENTRY glGetString( GLenum name );
+
+GLAPI void GLAPIENTRY glFinish( void );
+
+GLAPI void GLAPIENTRY glFlush( void );
+
+GLAPI void GLAPIENTRY glHint( GLenum target, GLenum mode );
+
+
+/*
+ * Depth Buffer
+ */
+
+GLAPI void GLAPIENTRY glClearDepth( GLclampd depth );
+
+GLAPI void GLAPIENTRY glDepthFunc( GLenum func );
+
+GLAPI void GLAPIENTRY glDepthMask( GLboolean flag );
+
+GLAPI void GLAPIENTRY glDepthRange( GLclampd near_val, GLclampd far_val );
+
+
+/*
+ * Accumulation Buffer
+ */
+
+GLAPI void GLAPIENTRY glClearAccum( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha );
+
+GLAPI void GLAPIENTRY glAccum( GLenum op, GLfloat value );
+
+
+/*
+ * Transformation
+ */
+
+GLAPI void GLAPIENTRY glMatrixMode( GLenum mode );
+
+GLAPI void GLAPIENTRY glOrtho( GLdouble left, GLdouble right,
+ GLdouble bottom, GLdouble top,
+ GLdouble near_val, GLdouble far_val );
+
+GLAPI void GLAPIENTRY glFrustum( GLdouble left, GLdouble right,
+ GLdouble bottom, GLdouble top,
+ GLdouble near_val, GLdouble far_val );
+
+GLAPI void GLAPIENTRY glViewport( GLint x, GLint y,
+ GLsizei width, GLsizei height );
+
+GLAPI void GLAPIENTRY glPushMatrix( void );
+
+GLAPI void GLAPIENTRY glPopMatrix( void );
+
+GLAPI void GLAPIENTRY glLoadIdentity( void );
+
+GLAPI void GLAPIENTRY glLoadMatrixd( const GLdouble *m );
+GLAPI void GLAPIENTRY glLoadMatrixf( const GLfloat *m );
+
+GLAPI void GLAPIENTRY glMultMatrixd( const GLdouble *m );
+GLAPI void GLAPIENTRY glMultMatrixf( const GLfloat *m );
+
+GLAPI void GLAPIENTRY glRotated( GLdouble angle,
+ GLdouble x, GLdouble y, GLdouble z );
+GLAPI void GLAPIENTRY glRotatef( GLfloat angle,
+ GLfloat x, GLfloat y, GLfloat z );
+
+GLAPI void GLAPIENTRY glScaled( GLdouble x, GLdouble y, GLdouble z );
+GLAPI void GLAPIENTRY glScalef( GLfloat x, GLfloat y, GLfloat z );
+
+GLAPI void GLAPIENTRY glTranslated( GLdouble x, GLdouble y, GLdouble z );
+GLAPI void GLAPIENTRY glTranslatef( GLfloat x, GLfloat y, GLfloat z );
+
+
+/*
+ * Display Lists
+ */
+
+GLAPI GLboolean GLAPIENTRY glIsList( GLuint list );
+
+GLAPI void GLAPIENTRY glDeleteLists( GLuint list, GLsizei range );
+
+GLAPI GLuint GLAPIENTRY glGenLists( GLsizei range );
+
+GLAPI void GLAPIENTRY glNewList( GLuint list, GLenum mode );
+
+GLAPI void GLAPIENTRY glEndList( void );
+
+GLAPI void GLAPIENTRY glCallList( GLuint list );
+
+GLAPI void GLAPIENTRY glCallLists( GLsizei n, GLenum type,
+ const GLvoid *lists );
+
+GLAPI void GLAPIENTRY glListBase( GLuint base );
+
+
+/*
+ * Drawing Functions
+ */
+
+GLAPI void GLAPIENTRY glBegin( GLenum mode );
+
+GLAPI void GLAPIENTRY glEnd( void );
+
+
+GLAPI void GLAPIENTRY glVertex2d( GLdouble x, GLdouble y );
+GLAPI void GLAPIENTRY glVertex2f( GLfloat x, GLfloat y );
+GLAPI void GLAPIENTRY glVertex2i( GLint x, GLint y );
+GLAPI void GLAPIENTRY glVertex2s( GLshort x, GLshort y );
+
+GLAPI void GLAPIENTRY glVertex3d( GLdouble x, GLdouble y, GLdouble z );
+GLAPI void GLAPIENTRY glVertex3f( GLfloat x, GLfloat y, GLfloat z );
+GLAPI void GLAPIENTRY glVertex3i( GLint x, GLint y, GLint z );
+GLAPI void GLAPIENTRY glVertex3s( GLshort x, GLshort y, GLshort z );
+
+GLAPI void GLAPIENTRY glVertex4d( GLdouble x, GLdouble y, GLdouble z, GLdouble w );
+GLAPI void GLAPIENTRY glVertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w );
+GLAPI void GLAPIENTRY glVertex4i( GLint x, GLint y, GLint z, GLint w );
+GLAPI void GLAPIENTRY glVertex4s( GLshort x, GLshort y, GLshort z, GLshort w );
+
+GLAPI void GLAPIENTRY glVertex2dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glVertex2fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glVertex2iv( const GLint *v );
+GLAPI void GLAPIENTRY glVertex2sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glVertex3dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glVertex3fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glVertex3iv( const GLint *v );
+GLAPI void GLAPIENTRY glVertex3sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glVertex4dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glVertex4fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glVertex4iv( const GLint *v );
+GLAPI void GLAPIENTRY glVertex4sv( const GLshort *v );
+
+
+GLAPI void GLAPIENTRY glNormal3b( GLbyte nx, GLbyte ny, GLbyte nz );
+GLAPI void GLAPIENTRY glNormal3d( GLdouble nx, GLdouble ny, GLdouble nz );
+GLAPI void GLAPIENTRY glNormal3f( GLfloat nx, GLfloat ny, GLfloat nz );
+GLAPI void GLAPIENTRY glNormal3i( GLint nx, GLint ny, GLint nz );
+GLAPI void GLAPIENTRY glNormal3s( GLshort nx, GLshort ny, GLshort nz );
+
+GLAPI void GLAPIENTRY glNormal3bv( const GLbyte *v );
+GLAPI void GLAPIENTRY glNormal3dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glNormal3fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glNormal3iv( const GLint *v );
+GLAPI void GLAPIENTRY glNormal3sv( const GLshort *v );
+
+
+GLAPI void GLAPIENTRY glIndexd( GLdouble c );
+GLAPI void GLAPIENTRY glIndexf( GLfloat c );
+GLAPI void GLAPIENTRY glIndexi( GLint c );
+GLAPI void GLAPIENTRY glIndexs( GLshort c );
+GLAPI void GLAPIENTRY glIndexub( GLubyte c ); /* 1.1 */
+
+GLAPI void GLAPIENTRY glIndexdv( const GLdouble *c );
+GLAPI void GLAPIENTRY glIndexfv( const GLfloat *c );
+GLAPI void GLAPIENTRY glIndexiv( const GLint *c );
+GLAPI void GLAPIENTRY glIndexsv( const GLshort *c );
+GLAPI void GLAPIENTRY glIndexubv( const GLubyte *c ); /* 1.1 */
+
+GLAPI void GLAPIENTRY glColor3b( GLbyte red, GLbyte green, GLbyte blue );
+GLAPI void GLAPIENTRY glColor3d( GLdouble red, GLdouble green, GLdouble blue );
+GLAPI void GLAPIENTRY glColor3f( GLfloat red, GLfloat green, GLfloat blue );
+GLAPI void GLAPIENTRY glColor3i( GLint red, GLint green, GLint blue );
+GLAPI void GLAPIENTRY glColor3s( GLshort red, GLshort green, GLshort blue );
+GLAPI void GLAPIENTRY glColor3ub( GLubyte red, GLubyte green, GLubyte blue );
+GLAPI void GLAPIENTRY glColor3ui( GLuint red, GLuint green, GLuint blue );
+GLAPI void GLAPIENTRY glColor3us( GLushort red, GLushort green, GLushort blue );
+
+GLAPI void GLAPIENTRY glColor4b( GLbyte red, GLbyte green,
+ GLbyte blue, GLbyte alpha );
+GLAPI void GLAPIENTRY glColor4d( GLdouble red, GLdouble green,
+ GLdouble blue, GLdouble alpha );
+GLAPI void GLAPIENTRY glColor4f( GLfloat red, GLfloat green,
+ GLfloat blue, GLfloat alpha );
+GLAPI void GLAPIENTRY glColor4i( GLint red, GLint green,
+ GLint blue, GLint alpha );
+GLAPI void GLAPIENTRY glColor4s( GLshort red, GLshort green,
+ GLshort blue, GLshort alpha );
+GLAPI void GLAPIENTRY glColor4ub( GLubyte red, GLubyte green,
+ GLubyte blue, GLubyte alpha );
+GLAPI void GLAPIENTRY glColor4ui( GLuint red, GLuint green,
+ GLuint blue, GLuint alpha );
+GLAPI void GLAPIENTRY glColor4us( GLushort red, GLushort green,
+ GLushort blue, GLushort alpha );
+
+
+GLAPI void GLAPIENTRY glColor3bv( const GLbyte *v );
+GLAPI void GLAPIENTRY glColor3dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glColor3fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glColor3iv( const GLint *v );
+GLAPI void GLAPIENTRY glColor3sv( const GLshort *v );
+GLAPI void GLAPIENTRY glColor3ubv( const GLubyte *v );
+GLAPI void GLAPIENTRY glColor3uiv( const GLuint *v );
+GLAPI void GLAPIENTRY glColor3usv( const GLushort *v );
+
+GLAPI void GLAPIENTRY glColor4bv( const GLbyte *v );
+GLAPI void GLAPIENTRY glColor4dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glColor4fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glColor4iv( const GLint *v );
+GLAPI void GLAPIENTRY glColor4sv( const GLshort *v );
+GLAPI void GLAPIENTRY glColor4ubv( const GLubyte *v );
+GLAPI void GLAPIENTRY glColor4uiv( const GLuint *v );
+GLAPI void GLAPIENTRY glColor4usv( const GLushort *v );
+
+
+GLAPI void GLAPIENTRY glTexCoord1d( GLdouble s );
+GLAPI void GLAPIENTRY glTexCoord1f( GLfloat s );
+GLAPI void GLAPIENTRY glTexCoord1i( GLint s );
+GLAPI void GLAPIENTRY glTexCoord1s( GLshort s );
+
+GLAPI void GLAPIENTRY glTexCoord2d( GLdouble s, GLdouble t );
+GLAPI void GLAPIENTRY glTexCoord2f( GLfloat s, GLfloat t );
+GLAPI void GLAPIENTRY glTexCoord2i( GLint s, GLint t );
+GLAPI void GLAPIENTRY glTexCoord2s( GLshort s, GLshort t );
+
+GLAPI void GLAPIENTRY glTexCoord3d( GLdouble s, GLdouble t, GLdouble r );
+GLAPI void GLAPIENTRY glTexCoord3f( GLfloat s, GLfloat t, GLfloat r );
+GLAPI void GLAPIENTRY glTexCoord3i( GLint s, GLint t, GLint r );
+GLAPI void GLAPIENTRY glTexCoord3s( GLshort s, GLshort t, GLshort r );
+
+GLAPI void GLAPIENTRY glTexCoord4d( GLdouble s, GLdouble t, GLdouble r, GLdouble q );
+GLAPI void GLAPIENTRY glTexCoord4f( GLfloat s, GLfloat t, GLfloat r, GLfloat q );
+GLAPI void GLAPIENTRY glTexCoord4i( GLint s, GLint t, GLint r, GLint q );
+GLAPI void GLAPIENTRY glTexCoord4s( GLshort s, GLshort t, GLshort r, GLshort q );
+
+GLAPI void GLAPIENTRY glTexCoord1dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glTexCoord1fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glTexCoord1iv( const GLint *v );
+GLAPI void GLAPIENTRY glTexCoord1sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glTexCoord2dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glTexCoord2fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glTexCoord2iv( const GLint *v );
+GLAPI void GLAPIENTRY glTexCoord2sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glTexCoord3dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glTexCoord3fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glTexCoord3iv( const GLint *v );
+GLAPI void GLAPIENTRY glTexCoord3sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glTexCoord4dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glTexCoord4fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glTexCoord4iv( const GLint *v );
+GLAPI void GLAPIENTRY glTexCoord4sv( const GLshort *v );
+
+
+GLAPI void GLAPIENTRY glRasterPos2d( GLdouble x, GLdouble y );
+GLAPI void GLAPIENTRY glRasterPos2f( GLfloat x, GLfloat y );
+GLAPI void GLAPIENTRY glRasterPos2i( GLint x, GLint y );
+GLAPI void GLAPIENTRY glRasterPos2s( GLshort x, GLshort y );
+
+GLAPI void GLAPIENTRY glRasterPos3d( GLdouble x, GLdouble y, GLdouble z );
+GLAPI void GLAPIENTRY glRasterPos3f( GLfloat x, GLfloat y, GLfloat z );
+GLAPI void GLAPIENTRY glRasterPos3i( GLint x, GLint y, GLint z );
+GLAPI void GLAPIENTRY glRasterPos3s( GLshort x, GLshort y, GLshort z );
+
+GLAPI void GLAPIENTRY glRasterPos4d( GLdouble x, GLdouble y, GLdouble z, GLdouble w );
+GLAPI void GLAPIENTRY glRasterPos4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w );
+GLAPI void GLAPIENTRY glRasterPos4i( GLint x, GLint y, GLint z, GLint w );
+GLAPI void GLAPIENTRY glRasterPos4s( GLshort x, GLshort y, GLshort z, GLshort w );
+
+GLAPI void GLAPIENTRY glRasterPos2dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glRasterPos2fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glRasterPos2iv( const GLint *v );
+GLAPI void GLAPIENTRY glRasterPos2sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glRasterPos3dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glRasterPos3fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glRasterPos3iv( const GLint *v );
+GLAPI void GLAPIENTRY glRasterPos3sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glRasterPos4dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glRasterPos4fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glRasterPos4iv( const GLint *v );
+GLAPI void GLAPIENTRY glRasterPos4sv( const GLshort *v );
+
+
+GLAPI void GLAPIENTRY glRectd( GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2 );
+GLAPI void GLAPIENTRY glRectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 );
+GLAPI void GLAPIENTRY glRecti( GLint x1, GLint y1, GLint x2, GLint y2 );
+GLAPI void GLAPIENTRY glRects( GLshort x1, GLshort y1, GLshort x2, GLshort y2 );
+
+
+GLAPI void GLAPIENTRY glRectdv( const GLdouble *v1, const GLdouble *v2 );
+GLAPI void GLAPIENTRY glRectfv( const GLfloat *v1, const GLfloat *v2 );
+GLAPI void GLAPIENTRY glRectiv( const GLint *v1, const GLint *v2 );
+GLAPI void GLAPIENTRY glRectsv( const GLshort *v1, const GLshort *v2 );
+
+
+/*
+ * Vertex Arrays (1.1)
+ */
+
+GLAPI void GLAPIENTRY glVertexPointer( GLint size, GLenum type,
+ GLsizei stride, const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glNormalPointer( GLenum type, GLsizei stride,
+ const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glColorPointer( GLint size, GLenum type,
+ GLsizei stride, const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glIndexPointer( GLenum type, GLsizei stride,
+ const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glTexCoordPointer( GLint size, GLenum type,
+ GLsizei stride, const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glEdgeFlagPointer( GLsizei stride, const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glGetPointerv( GLenum pname, GLvoid **params );
+
+GLAPI void GLAPIENTRY glArrayElement( GLint i );
+
+GLAPI void GLAPIENTRY glDrawArrays( GLenum mode, GLint first, GLsizei count );
+
+GLAPI void GLAPIENTRY glDrawElements( GLenum mode, GLsizei count,
+ GLenum type, const GLvoid *indices );
+
+GLAPI void GLAPIENTRY glInterleavedArrays( GLenum format, GLsizei stride,
+ const GLvoid *pointer );
+
+/*
+ * Lighting
+ */
+
+GLAPI void GLAPIENTRY glShadeModel( GLenum mode );
+
+GLAPI void GLAPIENTRY glLightf( GLenum light, GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glLighti( GLenum light, GLenum pname, GLint param );
+GLAPI void GLAPIENTRY glLightfv( GLenum light, GLenum pname,
+ const GLfloat *params );
+GLAPI void GLAPIENTRY glLightiv( GLenum light, GLenum pname,
+ const GLint *params );
+
+GLAPI void GLAPIENTRY glGetLightfv( GLenum light, GLenum pname,
+ GLfloat *params );
+GLAPI void GLAPIENTRY glGetLightiv( GLenum light, GLenum pname,
+ GLint *params );
+
+GLAPI void GLAPIENTRY glLightModelf( GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glLightModeli( GLenum pname, GLint param );
+GLAPI void GLAPIENTRY glLightModelfv( GLenum pname, const GLfloat *params );
+GLAPI void GLAPIENTRY glLightModeliv( GLenum pname, const GLint *params );
+
+GLAPI void GLAPIENTRY glMaterialf( GLenum face, GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glMateriali( GLenum face, GLenum pname, GLint param );
+GLAPI void GLAPIENTRY glMaterialfv( GLenum face, GLenum pname, const GLfloat *params );
+GLAPI void GLAPIENTRY glMaterialiv( GLenum face, GLenum pname, const GLint *params );
+
+GLAPI void GLAPIENTRY glGetMaterialfv( GLenum face, GLenum pname, GLfloat *params );
+GLAPI void GLAPIENTRY glGetMaterialiv( GLenum face, GLenum pname, GLint *params );
+
+GLAPI void GLAPIENTRY glColorMaterial( GLenum face, GLenum mode );
+
+
+/*
+ * Raster functions
+ */
+
+GLAPI void GLAPIENTRY glPixelZoom( GLfloat xfactor, GLfloat yfactor );
+
+GLAPI void GLAPIENTRY glPixelStoref( GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glPixelStorei( GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glPixelTransferf( GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glPixelTransferi( GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glPixelMapfv( GLenum map, GLsizei mapsize,
+ const GLfloat *values );
+GLAPI void GLAPIENTRY glPixelMapuiv( GLenum map, GLsizei mapsize,
+ const GLuint *values );
+GLAPI void GLAPIENTRY glPixelMapusv( GLenum map, GLsizei mapsize,
+ const GLushort *values );
+
+GLAPI void GLAPIENTRY glGetPixelMapfv( GLenum map, GLfloat *values );
+GLAPI void GLAPIENTRY glGetPixelMapuiv( GLenum map, GLuint *values );
+GLAPI void GLAPIENTRY glGetPixelMapusv( GLenum map, GLushort *values );
+
+GLAPI void GLAPIENTRY glBitmap( GLsizei width, GLsizei height,
+ GLfloat xorig, GLfloat yorig,
+ GLfloat xmove, GLfloat ymove,
+ const GLubyte *bitmap );
+
+GLAPI void GLAPIENTRY glReadPixels( GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ GLvoid *pixels );
+
+GLAPI void GLAPIENTRY glDrawPixels( GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const GLvoid *pixels );
+
+GLAPI void GLAPIENTRY glCopyPixels( GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum type );
+
+/*
+ * Stenciling
+ */
+
+GLAPI void GLAPIENTRY glStencilFunc( GLenum func, GLint ref, GLuint mask );
+
+GLAPI void GLAPIENTRY glStencilMask( GLuint mask );
+
+GLAPI void GLAPIENTRY glStencilOp( GLenum fail, GLenum zfail, GLenum zpass );
+
+GLAPI void GLAPIENTRY glClearStencil( GLint s );
+
+
+
+/*
+ * Texture mapping
+ */
+
+GLAPI void GLAPIENTRY glTexGend( GLenum coord, GLenum pname, GLdouble param );
+GLAPI void GLAPIENTRY glTexGenf( GLenum coord, GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glTexGeni( GLenum coord, GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glTexGendv( GLenum coord, GLenum pname, const GLdouble *params );
+GLAPI void GLAPIENTRY glTexGenfv( GLenum coord, GLenum pname, const GLfloat *params );
+GLAPI void GLAPIENTRY glTexGeniv( GLenum coord, GLenum pname, const GLint *params );
+
+GLAPI void GLAPIENTRY glGetTexGendv( GLenum coord, GLenum pname, GLdouble *params );
+GLAPI void GLAPIENTRY glGetTexGenfv( GLenum coord, GLenum pname, GLfloat *params );
+GLAPI void GLAPIENTRY glGetTexGeniv( GLenum coord, GLenum pname, GLint *params );
+
+
+GLAPI void GLAPIENTRY glTexEnvf( GLenum target, GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glTexEnvi( GLenum target, GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glTexEnvfv( GLenum target, GLenum pname, const GLfloat *params );
+GLAPI void GLAPIENTRY glTexEnviv( GLenum target, GLenum pname, const GLint *params );
+
+GLAPI void GLAPIENTRY glGetTexEnvfv( GLenum target, GLenum pname, GLfloat *params );
+GLAPI void GLAPIENTRY glGetTexEnviv( GLenum target, GLenum pname, GLint *params );
+
+
+GLAPI void GLAPIENTRY glTexParameterf( GLenum target, GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glTexParameteri( GLenum target, GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glTexParameterfv( GLenum target, GLenum pname,
+ const GLfloat *params );
+GLAPI void GLAPIENTRY glTexParameteriv( GLenum target, GLenum pname,
+ const GLint *params );
+
+GLAPI void GLAPIENTRY glGetTexParameterfv( GLenum target,
+ GLenum pname, GLfloat *params);
+GLAPI void GLAPIENTRY glGetTexParameteriv( GLenum target,
+ GLenum pname, GLint *params );
+
+GLAPI void GLAPIENTRY glGetTexLevelParameterfv( GLenum target, GLint level,
+ GLenum pname, GLfloat *params );
+GLAPI void GLAPIENTRY glGetTexLevelParameteriv( GLenum target, GLint level,
+ GLenum pname, GLint *params );
+
+
+GLAPI void GLAPIENTRY glTexImage1D( GLenum target, GLint level,
+ GLint internalFormat,
+ GLsizei width, GLint border,
+ GLenum format, GLenum type,
+ const GLvoid *pixels );
+
+GLAPI void GLAPIENTRY glTexImage2D( GLenum target, GLint level,
+ GLint internalFormat,
+ GLsizei width, GLsizei height,
+ GLint border, GLenum format, GLenum type,
+ const GLvoid *pixels );
+
+GLAPI void GLAPIENTRY glGetTexImage( GLenum target, GLint level,
+ GLenum format, GLenum type,
+ GLvoid *pixels );
+
+
+/* 1.1 functions */
+
+GLAPI void GLAPIENTRY glGenTextures( GLsizei n, GLuint *textures );
+
+GLAPI void GLAPIENTRY glDeleteTextures( GLsizei n, const GLuint *textures);
+
+GLAPI void GLAPIENTRY glBindTexture( GLenum target, GLuint texture );
+
+GLAPI void GLAPIENTRY glPrioritizeTextures( GLsizei n,
+ const GLuint *textures,
+ const GLclampf *priorities );
+
+GLAPI GLboolean GLAPIENTRY glAreTexturesResident( GLsizei n,
+ const GLuint *textures,
+ GLboolean *residences );
+
+GLAPI GLboolean GLAPIENTRY glIsTexture( GLuint texture );
+
+
+GLAPI void GLAPIENTRY glTexSubImage1D( GLenum target, GLint level,
+ GLint xoffset,
+ GLsizei width, GLenum format,
+ GLenum type, const GLvoid *pixels );
+
+
+GLAPI void GLAPIENTRY glTexSubImage2D( GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const GLvoid *pixels );
+
+
+GLAPI void GLAPIENTRY glCopyTexImage1D( GLenum target, GLint level,
+ GLenum internalformat,
+ GLint x, GLint y,
+ GLsizei width, GLint border );
+
+
+GLAPI void GLAPIENTRY glCopyTexImage2D( GLenum target, GLint level,
+ GLenum internalformat,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLint border );
+
+
+GLAPI void GLAPIENTRY glCopyTexSubImage1D( GLenum target, GLint level,
+ GLint xoffset, GLint x, GLint y,
+ GLsizei width );
+
+
+GLAPI void GLAPIENTRY glCopyTexSubImage2D( GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height );
+
+
+/*
+ * Evaluators
+ */
+
+GLAPI void GLAPIENTRY glMap1d( GLenum target, GLdouble u1, GLdouble u2,
+ GLint stride,
+ GLint order, const GLdouble *points );
+GLAPI void GLAPIENTRY glMap1f( GLenum target, GLfloat u1, GLfloat u2,
+ GLint stride,
+ GLint order, const GLfloat *points );
+
+GLAPI void GLAPIENTRY glMap2d( GLenum target,
+ GLdouble u1, GLdouble u2, GLint ustride, GLint uorder,
+ GLdouble v1, GLdouble v2, GLint vstride, GLint vorder,
+ const GLdouble *points );
+GLAPI void GLAPIENTRY glMap2f( GLenum target,
+ GLfloat u1, GLfloat u2, GLint ustride, GLint uorder,
+ GLfloat v1, GLfloat v2, GLint vstride, GLint vorder,
+ const GLfloat *points );
+
+GLAPI void GLAPIENTRY glGetMapdv( GLenum target, GLenum query, GLdouble *v );
+GLAPI void GLAPIENTRY glGetMapfv( GLenum target, GLenum query, GLfloat *v );
+GLAPI void GLAPIENTRY glGetMapiv( GLenum target, GLenum query, GLint *v );
+
+GLAPI void GLAPIENTRY glEvalCoord1d( GLdouble u );
+GLAPI void GLAPIENTRY glEvalCoord1f( GLfloat u );
+
+GLAPI void GLAPIENTRY glEvalCoord1dv( const GLdouble *u );
+GLAPI void GLAPIENTRY glEvalCoord1fv( const GLfloat *u );
+
+GLAPI void GLAPIENTRY glEvalCoord2d( GLdouble u, GLdouble v );
+GLAPI void GLAPIENTRY glEvalCoord2f( GLfloat u, GLfloat v );
+
+GLAPI void GLAPIENTRY glEvalCoord2dv( const GLdouble *u );
+GLAPI void GLAPIENTRY glEvalCoord2fv( const GLfloat *u );
+
+GLAPI void GLAPIENTRY glMapGrid1d( GLint un, GLdouble u1, GLdouble u2 );
+GLAPI void GLAPIENTRY glMapGrid1f( GLint un, GLfloat u1, GLfloat u2 );
+
+GLAPI void GLAPIENTRY glMapGrid2d( GLint un, GLdouble u1, GLdouble u2,
+ GLint vn, GLdouble v1, GLdouble v2 );
+GLAPI void GLAPIENTRY glMapGrid2f( GLint un, GLfloat u1, GLfloat u2,
+ GLint vn, GLfloat v1, GLfloat v2 );
+
+GLAPI void GLAPIENTRY glEvalPoint1( GLint i );
+
+GLAPI void GLAPIENTRY glEvalPoint2( GLint i, GLint j );
+
+GLAPI void GLAPIENTRY glEvalMesh1( GLenum mode, GLint i1, GLint i2 );
+
+GLAPI void GLAPIENTRY glEvalMesh2( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 );
+
+
+/*
+ * Fog
+ */
+
+GLAPI void GLAPIENTRY glFogf( GLenum pname, GLfloat param );
+
+GLAPI void GLAPIENTRY glFogi( GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glFogfv( GLenum pname, const GLfloat *params );
+
+GLAPI void GLAPIENTRY glFogiv( GLenum pname, const GLint *params );
+
+
+/*
+ * Selection and Feedback
+ */
+
+GLAPI void GLAPIENTRY glFeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer );
+
+GLAPI void GLAPIENTRY glPassThrough( GLfloat token );
+
+GLAPI void GLAPIENTRY glSelectBuffer( GLsizei size, GLuint *buffer );
+
+GLAPI void GLAPIENTRY glInitNames( void );
+
+GLAPI void GLAPIENTRY glLoadName( GLuint name );
+
+GLAPI void GLAPIENTRY glPushName( GLuint name );
+
+GLAPI void GLAPIENTRY glPopName( void );
+
+
+
+/*
+ * OpenGL 1.2
+ */
+
+#define GL_RESCALE_NORMAL 0x803A
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_MAX_ELEMENTS_VERTICES 0x80E8
+#define GL_MAX_ELEMENTS_INDICES 0x80E9
+#define GL_BGR 0x80E0
+#define GL_BGRA 0x80E1
+#define GL_UNSIGNED_BYTE_3_3_2 0x8032
+#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#define GL_UNSIGNED_INT_8_8_8_8 0x8035
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#define GL_UNSIGNED_INT_10_10_10_2 0x8036
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8
+#define GL_SINGLE_COLOR 0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR 0x81FA
+#define GL_TEXTURE_MIN_LOD 0x813A
+#define GL_TEXTURE_MAX_LOD 0x813B
+#define GL_TEXTURE_BASE_LEVEL 0x813C
+#define GL_TEXTURE_MAX_LEVEL 0x813D
+#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_PACK_SKIP_IMAGES 0x806B
+#define GL_PACK_IMAGE_HEIGHT 0x806C
+#define GL_UNPACK_SKIP_IMAGES 0x806D
+#define GL_UNPACK_IMAGE_HEIGHT 0x806E
+#define GL_TEXTURE_3D 0x806F
+#define GL_PROXY_TEXTURE_3D 0x8070
+#define GL_TEXTURE_DEPTH 0x8071
+#define GL_TEXTURE_WRAP_R 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE 0x8073
+#define GL_TEXTURE_BINDING_3D 0x806A
+
+GLAPI void GLAPIENTRY glDrawRangeElements( GLenum mode, GLuint start,
+ GLuint end, GLsizei count, GLenum type, const GLvoid *indices );
+
+GLAPI void GLAPIENTRY glTexImage3D( GLenum target, GLint level,
+ GLint internalFormat,
+ GLsizei width, GLsizei height,
+ GLsizei depth, GLint border,
+ GLenum format, GLenum type,
+ const GLvoid *pixels );
+
+GLAPI void GLAPIENTRY glTexSubImage3D( GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLint zoffset, GLsizei width,
+ GLsizei height, GLsizei depth,
+ GLenum format,
+ GLenum type, const GLvoid *pixels);
+
+GLAPI void GLAPIENTRY glCopyTexSubImage3D( GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLint zoffset, GLint x,
+ GLint y, GLsizei width,
+ GLsizei height );
+
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+
+
+/*
+ * GL_ARB_imaging
+ */
+
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_COLOR_TABLE 0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2
+#define GL_PROXY_COLOR_TABLE 0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5
+#define GL_COLOR_TABLE_SCALE 0x80D6
+#define GL_COLOR_TABLE_BIAS 0x80D7
+#define GL_COLOR_TABLE_FORMAT 0x80D8
+#define GL_COLOR_TABLE_WIDTH 0x80D9
+#define GL_COLOR_TABLE_RED_SIZE 0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE 0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE 0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF
+#define GL_CONVOLUTION_1D 0x8010
+#define GL_CONVOLUTION_2D 0x8011
+#define GL_SEPARABLE_2D 0x8012
+#define GL_CONVOLUTION_BORDER_MODE 0x8013
+#define GL_CONVOLUTION_FILTER_SCALE 0x8014
+#define GL_CONVOLUTION_FILTER_BIAS 0x8015
+#define GL_REDUCE 0x8016
+#define GL_CONVOLUTION_FORMAT 0x8017
+#define GL_CONVOLUTION_WIDTH 0x8018
+#define GL_CONVOLUTION_HEIGHT 0x8019
+#define GL_MAX_CONVOLUTION_WIDTH 0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT 0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE 0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS 0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023
+#define GL_CONSTANT_BORDER 0x8151
+#define GL_REPLICATE_BORDER 0x8153
+#define GL_CONVOLUTION_BORDER_COLOR 0x8154
+#define GL_COLOR_MATRIX 0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB
+#define GL_HISTOGRAM 0x8024
+#define GL_PROXY_HISTOGRAM 0x8025
+#define GL_HISTOGRAM_WIDTH 0x8026
+#define GL_HISTOGRAM_FORMAT 0x8027
+#define GL_HISTOGRAM_RED_SIZE 0x8028
+#define GL_HISTOGRAM_GREEN_SIZE 0x8029
+#define GL_HISTOGRAM_BLUE_SIZE 0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE 0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C
+#define GL_HISTOGRAM_SINK 0x802D
+#define GL_MINMAX 0x802E
+#define GL_MINMAX_FORMAT 0x802F
+#define GL_MINMAX_SINK 0x8030
+#define GL_TABLE_TOO_LARGE 0x8031
+#define GL_BLEND_EQUATION 0x8009
+#define GL_MIN 0x8007
+#define GL_MAX 0x8008
+#define GL_FUNC_ADD 0x8006
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+#define GL_BLEND_COLOR 0x8005
+
+
+GLAPI void GLAPIENTRY glColorTable( GLenum target, GLenum internalformat,
+ GLsizei width, GLenum format,
+ GLenum type, const GLvoid *table );
+
+GLAPI void GLAPIENTRY glColorSubTable( GLenum target,
+ GLsizei start, GLsizei count,
+ GLenum format, GLenum type,
+ const GLvoid *data );
+
+GLAPI void GLAPIENTRY glColorTableParameteriv(GLenum target, GLenum pname,
+ const GLint *params);
+
+GLAPI void GLAPIENTRY glColorTableParameterfv(GLenum target, GLenum pname,
+ const GLfloat *params);
+
+GLAPI void GLAPIENTRY glCopyColorSubTable( GLenum target, GLsizei start,
+ GLint x, GLint y, GLsizei width );
+
+GLAPI void GLAPIENTRY glCopyColorTable( GLenum target, GLenum internalformat,
+ GLint x, GLint y, GLsizei width );
+
+GLAPI void GLAPIENTRY glGetColorTable( GLenum target, GLenum format,
+ GLenum type, GLvoid *table );
+
+GLAPI void GLAPIENTRY glGetColorTableParameterfv( GLenum target, GLenum pname,
+ GLfloat *params );
+
+GLAPI void GLAPIENTRY glGetColorTableParameteriv( GLenum target, GLenum pname,
+ GLint *params );
+
+GLAPI void GLAPIENTRY glBlendEquation( GLenum mode );
+
+GLAPI void GLAPIENTRY glBlendColor( GLclampf red, GLclampf green,
+ GLclampf blue, GLclampf alpha );
+
+GLAPI void GLAPIENTRY glHistogram( GLenum target, GLsizei width,
+ GLenum internalformat, GLboolean sink );
+
+GLAPI void GLAPIENTRY glResetHistogram( GLenum target );
+
+GLAPI void GLAPIENTRY glGetHistogram( GLenum target, GLboolean reset,
+ GLenum format, GLenum type,
+ GLvoid *values );
+
+GLAPI void GLAPIENTRY glGetHistogramParameterfv( GLenum target, GLenum pname,
+ GLfloat *params );
+
+GLAPI void GLAPIENTRY glGetHistogramParameteriv( GLenum target, GLenum pname,
+ GLint *params );
+
+GLAPI void GLAPIENTRY glMinmax( GLenum target, GLenum internalformat,
+ GLboolean sink );
+
+GLAPI void GLAPIENTRY glResetMinmax( GLenum target );
+
+GLAPI void GLAPIENTRY glGetMinmax( GLenum target, GLboolean reset,
+ GLenum format, GLenum types,
+ GLvoid *values );
+
+GLAPI void GLAPIENTRY glGetMinmaxParameterfv( GLenum target, GLenum pname,
+ GLfloat *params );
+
+GLAPI void GLAPIENTRY glGetMinmaxParameteriv( GLenum target, GLenum pname,
+ GLint *params );
+
+GLAPI void GLAPIENTRY glConvolutionFilter1D( GLenum target,
+ GLenum internalformat, GLsizei width, GLenum format, GLenum type,
+ const GLvoid *image );
+
+GLAPI void GLAPIENTRY glConvolutionFilter2D( GLenum target,
+ GLenum internalformat, GLsizei width, GLsizei height, GLenum format,
+ GLenum type, const GLvoid *image );
+
+GLAPI void GLAPIENTRY glConvolutionParameterf( GLenum target, GLenum pname,
+ GLfloat params );
+
+GLAPI void GLAPIENTRY glConvolutionParameterfv( GLenum target, GLenum pname,
+ const GLfloat *params );
+
+GLAPI void GLAPIENTRY glConvolutionParameteri( GLenum target, GLenum pname,
+ GLint params );
+
+GLAPI void GLAPIENTRY glConvolutionParameteriv( GLenum target, GLenum pname,
+ const GLint *params );
+
+GLAPI void GLAPIENTRY glCopyConvolutionFilter1D( GLenum target,
+ GLenum internalformat, GLint x, GLint y, GLsizei width );
+
+GLAPI void GLAPIENTRY glCopyConvolutionFilter2D( GLenum target,
+ GLenum internalformat, GLint x, GLint y, GLsizei width,
+ GLsizei height);
+
+GLAPI void GLAPIENTRY glGetConvolutionFilter( GLenum target, GLenum format,
+ GLenum type, GLvoid *image );
+
+GLAPI void GLAPIENTRY glGetConvolutionParameterfv( GLenum target, GLenum pname,
+ GLfloat *params );
+
+GLAPI void GLAPIENTRY glGetConvolutionParameteriv( GLenum target, GLenum pname,
+ GLint *params );
+
+GLAPI void GLAPIENTRY glSeparableFilter2D( GLenum target,
+ GLenum internalformat, GLsizei width, GLsizei height, GLenum format,
+ GLenum type, const GLvoid *row, const GLvoid *column );
+
+GLAPI void GLAPIENTRY glGetSeparableFilter( GLenum target, GLenum format,
+ GLenum type, GLvoid *row, GLvoid *column, GLvoid *span );
+
+
+
+
+/*
+ * OpenGL 1.3
+ */
+
+/* multitexture */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1
+#define GL_MAX_TEXTURE_UNITS 0x84E2
+/* texture_cube_map */
+#define GL_NORMAL_MAP 0x8511
+#define GL_REFLECTION_MAP 0x8512
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+/* texture_compression */
+#define GL_COMPRESSED_ALPHA 0x84E9
+#define GL_COMPRESSED_LUMINANCE 0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB
+#define GL_COMPRESSED_INTENSITY 0x84EC
+#define GL_COMPRESSED_RGB 0x84ED
+#define GL_COMPRESSED_RGBA 0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT 0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0
+#define GL_TEXTURE_COMPRESSED 0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+/* multisample */
+#define GL_MULTISAMPLE 0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
+#define GL_SAMPLE_COVERAGE 0x80A0
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+#define GL_MULTISAMPLE_BIT 0x20000000
+/* transpose_matrix */
+#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6
+/* texture_env_combine */
+#define GL_COMBINE 0x8570
+#define GL_COMBINE_RGB 0x8571
+#define GL_COMBINE_ALPHA 0x8572
+#define GL_SOURCE0_RGB 0x8580
+#define GL_SOURCE1_RGB 0x8581
+#define GL_SOURCE2_RGB 0x8582
+#define GL_SOURCE0_ALPHA 0x8588
+#define GL_SOURCE1_ALPHA 0x8589
+#define GL_SOURCE2_ALPHA 0x858A
+#define GL_OPERAND0_RGB 0x8590
+#define GL_OPERAND1_RGB 0x8591
+#define GL_OPERAND2_RGB 0x8592
+#define GL_OPERAND0_ALPHA 0x8598
+#define GL_OPERAND1_ALPHA 0x8599
+#define GL_OPERAND2_ALPHA 0x859A
+#define GL_RGB_SCALE 0x8573
+#define GL_ADD_SIGNED 0x8574
+#define GL_INTERPOLATE 0x8575
+#define GL_SUBTRACT 0x84E7
+#define GL_CONSTANT 0x8576
+#define GL_PRIMARY_COLOR 0x8577
+#define GL_PREVIOUS 0x8578
+/* texture_env_dot3 */
+#define GL_DOT3_RGB 0x86AE
+#define GL_DOT3_RGBA 0x86AF
+/* texture_border_clamp */
+#define GL_CLAMP_TO_BORDER 0x812D
+
+GLAPI void GLAPIENTRY glActiveTexture( GLenum texture );
+
+GLAPI void GLAPIENTRY glClientActiveTexture( GLenum texture );
+
+GLAPI void GLAPIENTRY glCompressedTexImage1D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glCompressedTexImage2D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glCompressedTexImage3D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glCompressedTexSubImage1D( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glCompressedTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glCompressedTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glGetCompressedTexImage( GLenum target, GLint lod, GLvoid *img );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1d( GLenum target, GLdouble s );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1dv( GLenum target, const GLdouble *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1f( GLenum target, GLfloat s );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1fv( GLenum target, const GLfloat *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1i( GLenum target, GLint s );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1iv( GLenum target, const GLint *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1s( GLenum target, GLshort s );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1sv( GLenum target, const GLshort *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2d( GLenum target, GLdouble s, GLdouble t );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2dv( GLenum target, const GLdouble *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2f( GLenum target, GLfloat s, GLfloat t );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2fv( GLenum target, const GLfloat *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2i( GLenum target, GLint s, GLint t );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2iv( GLenum target, const GLint *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2s( GLenum target, GLshort s, GLshort t );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2sv( GLenum target, const GLshort *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3d( GLenum target, GLdouble s, GLdouble t, GLdouble r );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3dv( GLenum target, const GLdouble *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3f( GLenum target, GLfloat s, GLfloat t, GLfloat r );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3fv( GLenum target, const GLfloat *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3i( GLenum target, GLint s, GLint t, GLint r );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3iv( GLenum target, const GLint *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3s( GLenum target, GLshort s, GLshort t, GLshort r );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3sv( GLenum target, const GLshort *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4d( GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4dv( GLenum target, const GLdouble *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4f( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4fv( GLenum target, const GLfloat *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4i( GLenum target, GLint s, GLint t, GLint r, GLint q );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4iv( GLenum target, const GLint *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4s( GLenum target, GLshort s, GLshort t, GLshort r, GLshort q );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4sv( GLenum target, const GLshort *v );
+
+
+GLAPI void GLAPIENTRY glLoadTransposeMatrixd( const GLdouble m[16] );
+
+GLAPI void GLAPIENTRY glLoadTransposeMatrixf( const GLfloat m[16] );
+
+GLAPI void GLAPIENTRY glMultTransposeMatrixd( const GLdouble m[16] );
+
+GLAPI void GLAPIENTRY glMultTransposeMatrixf( const GLfloat m[16] );
+
+GLAPI void GLAPIENTRY glSampleCoverage( GLclampf value, GLboolean invert );
+
+
+typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img);
+
+
+
+/*
+ * GL_ARB_multitexture (ARB extension 1 and OpenGL 1.2.1)
+ */
+#ifndef GL_ARB_multitexture
+#define GL_ARB_multitexture 1
+
+#define GL_TEXTURE0_ARB 0x84C0
+#define GL_TEXTURE1_ARB 0x84C1
+#define GL_TEXTURE2_ARB 0x84C2
+#define GL_TEXTURE3_ARB 0x84C3
+#define GL_TEXTURE4_ARB 0x84C4
+#define GL_TEXTURE5_ARB 0x84C5
+#define GL_TEXTURE6_ARB 0x84C6
+#define GL_TEXTURE7_ARB 0x84C7
+#define GL_TEXTURE8_ARB 0x84C8
+#define GL_TEXTURE9_ARB 0x84C9
+#define GL_TEXTURE10_ARB 0x84CA
+#define GL_TEXTURE11_ARB 0x84CB
+#define GL_TEXTURE12_ARB 0x84CC
+#define GL_TEXTURE13_ARB 0x84CD
+#define GL_TEXTURE14_ARB 0x84CE
+#define GL_TEXTURE15_ARB 0x84CF
+#define GL_TEXTURE16_ARB 0x84D0
+#define GL_TEXTURE17_ARB 0x84D1
+#define GL_TEXTURE18_ARB 0x84D2
+#define GL_TEXTURE19_ARB 0x84D3
+#define GL_TEXTURE20_ARB 0x84D4
+#define GL_TEXTURE21_ARB 0x84D5
+#define GL_TEXTURE22_ARB 0x84D6
+#define GL_TEXTURE23_ARB 0x84D7
+#define GL_TEXTURE24_ARB 0x84D8
+#define GL_TEXTURE25_ARB 0x84D9
+#define GL_TEXTURE26_ARB 0x84DA
+#define GL_TEXTURE27_ARB 0x84DB
+#define GL_TEXTURE28_ARB 0x84DC
+#define GL_TEXTURE29_ARB 0x84DD
+#define GL_TEXTURE30_ARB 0x84DE
+#define GL_TEXTURE31_ARB 0x84DF
+#define GL_ACTIVE_TEXTURE_ARB 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1
+#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2
+
+GLAPI void GLAPIENTRY glActiveTextureARB(GLenum texture);
+GLAPI void GLAPIENTRY glClientActiveTextureARB(GLenum texture);
+GLAPI void GLAPIENTRY glMultiTexCoord1dARB(GLenum target, GLdouble s);
+GLAPI void GLAPIENTRY glMultiTexCoord1dvARB(GLenum target, const GLdouble *v);
+GLAPI void GLAPIENTRY glMultiTexCoord1fARB(GLenum target, GLfloat s);
+GLAPI void GLAPIENTRY glMultiTexCoord1fvARB(GLenum target, const GLfloat *v);
+GLAPI void GLAPIENTRY glMultiTexCoord1iARB(GLenum target, GLint s);
+GLAPI void GLAPIENTRY glMultiTexCoord1ivARB(GLenum target, const GLint *v);
+GLAPI void GLAPIENTRY glMultiTexCoord1sARB(GLenum target, GLshort s);
+GLAPI void GLAPIENTRY glMultiTexCoord1svARB(GLenum target, const GLshort *v);
+GLAPI void GLAPIENTRY glMultiTexCoord2dARB(GLenum target, GLdouble s, GLdouble t);
+GLAPI void GLAPIENTRY glMultiTexCoord2dvARB(GLenum target, const GLdouble *v);
+GLAPI void GLAPIENTRY glMultiTexCoord2fARB(GLenum target, GLfloat s, GLfloat t);
+GLAPI void GLAPIENTRY glMultiTexCoord2fvARB(GLenum target, const GLfloat *v);
+GLAPI void GLAPIENTRY glMultiTexCoord2iARB(GLenum target, GLint s, GLint t);
+GLAPI void GLAPIENTRY glMultiTexCoord2ivARB(GLenum target, const GLint *v);
+GLAPI void GLAPIENTRY glMultiTexCoord2sARB(GLenum target, GLshort s, GLshort t);
+GLAPI void GLAPIENTRY glMultiTexCoord2svARB(GLenum target, const GLshort *v);
+GLAPI void GLAPIENTRY glMultiTexCoord3dARB(GLenum target, GLdouble s, GLdouble t, GLdouble r);
+GLAPI void GLAPIENTRY glMultiTexCoord3dvARB(GLenum target, const GLdouble *v);
+GLAPI void GLAPIENTRY glMultiTexCoord3fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r);
+GLAPI void GLAPIENTRY glMultiTexCoord3fvARB(GLenum target, const GLfloat *v);
+GLAPI void GLAPIENTRY glMultiTexCoord3iARB(GLenum target, GLint s, GLint t, GLint r);
+GLAPI void GLAPIENTRY glMultiTexCoord3ivARB(GLenum target, const GLint *v);
+GLAPI void GLAPIENTRY glMultiTexCoord3sARB(GLenum target, GLshort s, GLshort t, GLshort r);
+GLAPI void GLAPIENTRY glMultiTexCoord3svARB(GLenum target, const GLshort *v);
+GLAPI void GLAPIENTRY glMultiTexCoord4dARB(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+GLAPI void GLAPIENTRY glMultiTexCoord4dvARB(GLenum target, const GLdouble *v);
+GLAPI void GLAPIENTRY glMultiTexCoord4fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+GLAPI void GLAPIENTRY glMultiTexCoord4fvARB(GLenum target, const GLfloat *v);
+GLAPI void GLAPIENTRY glMultiTexCoord4iARB(GLenum target, GLint s, GLint t, GLint r, GLint q);
+GLAPI void GLAPIENTRY glMultiTexCoord4ivARB(GLenum target, const GLint *v);
+GLAPI void GLAPIENTRY glMultiTexCoord4sARB(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+GLAPI void GLAPIENTRY glMultiTexCoord4svARB(GLenum target, const GLshort *v);
+
+typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+
+#endif /* GL_ARB_multitexture */
+
+
+
+/*
+ * Define this token if you want "old-style" header file behaviour (extensions
+ * defined in gl.h). Otherwise, extensions will be included from glext.h.
+ */
+#if !defined(NO_SDL_GLEXT) && !defined(GL_GLEXT_LEGACY)
+#include "SDL_opengl_glext.h"
+#endif /* GL_GLEXT_LEGACY */
+
+
+
+/*
+ * ???. GL_MESA_packed_depth_stencil
+ * XXX obsolete
+ */
+#ifndef GL_MESA_packed_depth_stencil
+#define GL_MESA_packed_depth_stencil 1
+
+#define GL_DEPTH_STENCIL_MESA 0x8750
+#define GL_UNSIGNED_INT_24_8_MESA 0x8751
+#define GL_UNSIGNED_INT_8_24_REV_MESA 0x8752
+#define GL_UNSIGNED_SHORT_15_1_MESA 0x8753
+#define GL_UNSIGNED_SHORT_1_15_REV_MESA 0x8754
+
+#endif /* GL_MESA_packed_depth_stencil */
+
+
+#ifndef GL_ATI_blend_equation_separate
+#define GL_ATI_blend_equation_separate 1
+
+#define GL_ALPHA_BLEND_EQUATION_ATI 0x883D
+
+GLAPI void GLAPIENTRY glBlendEquationSeparateATI( GLenum modeRGB, GLenum modeA );
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEATIPROC) (GLenum modeRGB, GLenum modeA);
+
+#endif /* GL_ATI_blend_equation_separate */
+
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GLAPI void APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+
+/**
+ ** NOTE!!!!! If you add new functions to this file, or update
+ ** glext.h be sure to regenerate the gl_mangle.h file. See comments
+ ** in that file for details.
+ **/
+
+
+
+/**********************************************************************
+ * Begin system-specific stuff
+ */
+#if defined(PRAGMA_EXPORT_SUPPORTED)
+#pragma export off
+#endif
+
+/*
+ * End system-specific stuff
+ **********************************************************************/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl_h_ */
+
+#endif /* !__IPHONEOS__ */
+
+#endif /* _SDL_opengl_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_opengl_glext.h b/external/SDL2/include/SDL_opengl_glext.h
new file mode 100644
index 0000000..cd3869f
--- /dev/null
+++ b/external/SDL2/include/SDL_opengl_glext.h
@@ -0,0 +1,11177 @@
+#ifndef __glext_h_
+#define __glext_h_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2013-2014 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+/*
+** This header is generated from the Khronos OpenGL / OpenGL ES XML
+** API Registry. The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** http://www.opengl.org/registry/
+**
+** Khronos $Revision: 26745 $ on $Date: 2014-05-21 03:12:26 -0700 (Wed, 21 May 2014) $
+*/
+
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+
+#define GL_GLEXT_VERSION 20140521
+
+/* Generated C header for:
+ * API: gl
+ * Profile: compatibility
+ * Versions considered: .*
+ * Versions emitted: 1\.[2-9]|[234]\.[0-9]
+ * Default extensions included: gl
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef GL_VERSION_1_2
+#define GL_VERSION_1_2 1
+#define GL_UNSIGNED_BYTE_3_3_2 0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_INT_8_8_8_8 0x8035
+#define GL_UNSIGNED_INT_10_10_10_2 0x8036
+#define GL_TEXTURE_BINDING_3D 0x806A
+#define GL_PACK_SKIP_IMAGES 0x806B
+#define GL_PACK_IMAGE_HEIGHT 0x806C
+#define GL_UNPACK_SKIP_IMAGES 0x806D
+#define GL_UNPACK_IMAGE_HEIGHT 0x806E
+#define GL_TEXTURE_3D 0x806F
+#define GL_PROXY_TEXTURE_3D 0x8070
+#define GL_TEXTURE_DEPTH 0x8071
+#define GL_TEXTURE_WRAP_R 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE 0x8073
+#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#define GL_BGR 0x80E0
+#define GL_BGRA 0x80E1
+#define GL_MAX_ELEMENTS_VERTICES 0x80E8
+#define GL_MAX_ELEMENTS_INDICES 0x80E9
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_TEXTURE_MIN_LOD 0x813A
+#define GL_TEXTURE_MAX_LOD 0x813B
+#define GL_TEXTURE_BASE_LEVEL 0x813C
+#define GL_TEXTURE_MAX_LEVEL 0x813D
+#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_RESCALE_NORMAL 0x803A
+#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8
+#define GL_SINGLE_COLOR 0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR 0x81FA
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+#endif /* GL_VERSION_1_2 */
+
+#ifndef GL_VERSION_1_3
+#define GL_VERSION_1_3 1
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+#define GL_MULTISAMPLE 0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
+#define GL_SAMPLE_COVERAGE 0x80A0
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+#define GL_COMPRESSED_RGB 0x84ED
+#define GL_COMPRESSED_RGBA 0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT 0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0
+#define GL_TEXTURE_COMPRESSED 0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+#define GL_CLAMP_TO_BORDER 0x812D
+#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1
+#define GL_MAX_TEXTURE_UNITS 0x84E2
+#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6
+#define GL_MULTISAMPLE_BIT 0x20000000
+#define GL_NORMAL_MAP 0x8511
+#define GL_REFLECTION_MAP 0x8512
+#define GL_COMPRESSED_ALPHA 0x84E9
+#define GL_COMPRESSED_LUMINANCE 0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB
+#define GL_COMPRESSED_INTENSITY 0x84EC
+#define GL_COMBINE 0x8570
+#define GL_COMBINE_RGB 0x8571
+#define GL_COMBINE_ALPHA 0x8572
+#define GL_SOURCE0_RGB 0x8580
+#define GL_SOURCE1_RGB 0x8581
+#define GL_SOURCE2_RGB 0x8582
+#define GL_SOURCE0_ALPHA 0x8588
+#define GL_SOURCE1_ALPHA 0x8589
+#define GL_SOURCE2_ALPHA 0x858A
+#define GL_OPERAND0_RGB 0x8590
+#define GL_OPERAND1_RGB 0x8591
+#define GL_OPERAND2_RGB 0x8592
+#define GL_OPERAND0_ALPHA 0x8598
+#define GL_OPERAND1_ALPHA 0x8599
+#define GL_OPERAND2_ALPHA 0x859A
+#define GL_RGB_SCALE 0x8573
+#define GL_ADD_SIGNED 0x8574
+#define GL_INTERPOLATE 0x8575
+#define GL_SUBTRACT 0x84E7
+#define GL_CONSTANT 0x8576
+#define GL_PRIMARY_COLOR 0x8577
+#define GL_PREVIOUS 0x8578
+#define GL_DOT3_RGB 0x86AE
+#define GL_DOT3_RGBA 0x86AF
+typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTexture (GLenum texture);
+GLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert);
+GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, void *img);
+GLAPI void APIENTRY glClientActiveTexture (GLenum texture);
+GLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s);
+GLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord1f (GLenum target, GLfloat s);
+GLAPI void APIENTRY glMultiTexCoord1fv (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord1i (GLenum target, GLint s);
+GLAPI void APIENTRY glMultiTexCoord1iv (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord1s (GLenum target, GLshort s);
+GLAPI void APIENTRY glMultiTexCoord1sv (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t);
+GLAPI void APIENTRY glMultiTexCoord2dv (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t);
+GLAPI void APIENTRY glMultiTexCoord2fv (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord2i (GLenum target, GLint s, GLint t);
+GLAPI void APIENTRY glMultiTexCoord2iv (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord2s (GLenum target, GLshort s, GLshort t);
+GLAPI void APIENTRY glMultiTexCoord2sv (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+GLAPI void APIENTRY glMultiTexCoord3dv (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+GLAPI void APIENTRY glMultiTexCoord3fv (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r);
+GLAPI void APIENTRY glMultiTexCoord3iv (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r);
+GLAPI void APIENTRY glMultiTexCoord3sv (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+GLAPI void APIENTRY glMultiTexCoord4dv (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+GLAPI void APIENTRY glMultiTexCoord4fv (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q);
+GLAPI void APIENTRY glMultiTexCoord4iv (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+GLAPI void APIENTRY glMultiTexCoord4sv (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *m);
+GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *m);
+GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *m);
+GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m);
+#endif
+#endif /* GL_VERSION_1_3 */
+
+#ifndef GL_VERSION_1_4
+#define GL_VERSION_1_4 1
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_DEPTH_COMPONENT24 0x81A6
+#define GL_DEPTH_COMPONENT32 0x81A7
+#define GL_MIRRORED_REPEAT 0x8370
+#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
+#define GL_TEXTURE_LOD_BIAS 0x8501
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+#define GL_TEXTURE_DEPTH_SIZE 0x884A
+#define GL_TEXTURE_COMPARE_MODE 0x884C
+#define GL_TEXTURE_COMPARE_FUNC 0x884D
+#define GL_POINT_SIZE_MIN 0x8126
+#define GL_POINT_SIZE_MAX 0x8127
+#define GL_POINT_DISTANCE_ATTENUATION 0x8129
+#define GL_GENERATE_MIPMAP 0x8191
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+#define GL_FOG_COORDINATE_SOURCE 0x8450
+#define GL_FOG_COORDINATE 0x8451
+#define GL_FRAGMENT_DEPTH 0x8452
+#define GL_CURRENT_FOG_COORDINATE 0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456
+#define GL_FOG_COORDINATE_ARRAY 0x8457
+#define GL_COLOR_SUM 0x8458
+#define GL_CURRENT_SECONDARY_COLOR 0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D
+#define GL_SECONDARY_COLOR_ARRAY 0x845E
+#define GL_TEXTURE_FILTER_CONTROL 0x8500
+#define GL_DEPTH_TEXTURE_MODE 0x884B
+#define GL_COMPARE_R_TO_TEXTURE 0x884E
+#define GL_FUNC_ADD 0x8006
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+#define GL_MIN 0x8007
+#define GL_MAX 0x8008
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
+GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);
+GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param);
+GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params);
+GLAPI void APIENTRY glFogCoordf (GLfloat coord);
+GLAPI void APIENTRY glFogCoordfv (const GLfloat *coord);
+GLAPI void APIENTRY glFogCoordd (GLdouble coord);
+GLAPI void APIENTRY glFogCoorddv (const GLdouble *coord);
+GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue);
+GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v);
+GLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue);
+GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *v);
+GLAPI void APIENTRY glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue);
+GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *v);
+GLAPI void APIENTRY glSecondaryColor3i (GLint red, GLint green, GLint blue);
+GLAPI void APIENTRY glSecondaryColor3iv (const GLint *v);
+GLAPI void APIENTRY glSecondaryColor3s (GLshort red, GLshort green, GLshort blue);
+GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *v);
+GLAPI void APIENTRY glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue);
+GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *v);
+GLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue);
+GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v);
+GLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue);
+GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v);
+GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y);
+GLAPI void APIENTRY glWindowPos2dv (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y);
+GLAPI void APIENTRY glWindowPos2fv (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos2i (GLint x, GLint y);
+GLAPI void APIENTRY glWindowPos2iv (const GLint *v);
+GLAPI void APIENTRY glWindowPos2s (GLshort x, GLshort y);
+GLAPI void APIENTRY glWindowPos2sv (const GLshort *v);
+GLAPI void APIENTRY glWindowPos3d (GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glWindowPos3dv (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos3f (GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glWindowPos3fv (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glWindowPos3iv (const GLint *v);
+GLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glWindowPos3sv (const GLshort *v);
+GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GLAPI void APIENTRY glBlendEquation (GLenum mode);
+#endif
+#endif /* GL_VERSION_1_4 */
+
+#ifndef GL_VERSION_1_5
+#define GL_VERSION_1_5 1
+#include <stddef.h>
+#ifdef __MACOSX__
+typedef long GLsizeiptr;
+typedef long GLintptr;
+#else
+typedef ptrdiff_t GLsizeiptr;
+typedef ptrdiff_t GLintptr;
+#endif
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+#define GL_QUERY_COUNTER_BITS 0x8864
+#define GL_CURRENT_QUERY 0x8865
+#define GL_QUERY_RESULT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE 0x8867
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#define GL_READ_ONLY 0x88B8
+#define GL_WRITE_ONLY 0x88B9
+#define GL_READ_WRITE 0x88BA
+#define GL_BUFFER_ACCESS 0x88BB
+#define GL_BUFFER_MAPPED 0x88BC
+#define GL_BUFFER_MAP_POINTER 0x88BD
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STREAM_READ 0x88E1
+#define GL_STREAM_COPY 0x88E2
+#define GL_STATIC_DRAW 0x88E4
+#define GL_STATIC_READ 0x88E5
+#define GL_STATIC_COPY 0x88E6
+#define GL_DYNAMIC_DRAW 0x88E8
+#define GL_DYNAMIC_READ 0x88E9
+#define GL_DYNAMIC_COPY 0x88EA
+#define GL_SAMPLES_PASSED 0x8914
+#define GL_SRC1_ALPHA 0x8589
+#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E
+#define GL_FOG_COORD_SRC 0x8450
+#define GL_FOG_COORD 0x8451
+#define GL_CURRENT_FOG_COORD 0x8453
+#define GL_FOG_COORD_ARRAY_TYPE 0x8454
+#define GL_FOG_COORD_ARRAY_STRIDE 0x8455
+#define GL_FOG_COORD_ARRAY_POINTER 0x8456
+#define GL_FOG_COORD_ARRAY 0x8457
+#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D
+#define GL_SRC0_RGB 0x8580
+#define GL_SRC1_RGB 0x8581
+#define GL_SRC2_RGB 0x8582
+#define GL_SRC0_ALPHA 0x8588
+#define GL_SRC2_ALPHA 0x858A
+typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data);
+typedef void *(APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids);
+GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids);
+GLAPI GLboolean APIENTRY glIsQuery (GLuint id);
+GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id);
+GLAPI void APIENTRY glEndQuery (GLenum target);
+GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
+GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
+GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer);
+GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
+GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
+GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, void *data);
+GLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access);
+GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target);
+GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params);
+#endif
+#endif /* GL_VERSION_1_5 */
+
+#ifndef GL_VERSION_2_0
+#define GL_VERSION_2_0 1
+typedef char GLchar;
+#define GL_BLEND_EQUATION_RGB 0x8009
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_MAX_DRAW_BUFFERS 0x8824
+#define GL_DRAW_BUFFER0 0x8825
+#define GL_DRAW_BUFFER1 0x8826
+#define GL_DRAW_BUFFER2 0x8827
+#define GL_DRAW_BUFFER3 0x8828
+#define GL_DRAW_BUFFER4 0x8829
+#define GL_DRAW_BUFFER5 0x882A
+#define GL_DRAW_BUFFER6 0x882B
+#define GL_DRAW_BUFFER7 0x882C
+#define GL_DRAW_BUFFER8 0x882D
+#define GL_DRAW_BUFFER9 0x882E
+#define GL_DRAW_BUFFER10 0x882F
+#define GL_DRAW_BUFFER11 0x8830
+#define GL_DRAW_BUFFER12 0x8831
+#define GL_DRAW_BUFFER13 0x8832
+#define GL_DRAW_BUFFER14 0x8833
+#define GL_DRAW_BUFFER15 0x8834
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
+#define GL_MAX_VARYING_FLOATS 0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_1D 0x8B5D
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_3D 0x8B5F
+#define GL_SAMPLER_CUBE 0x8B60
+#define GL_SAMPLER_1D_SHADOW 0x8B61
+#define GL_SAMPLER_2D_SHADOW 0x8B62
+#define GL_DELETE_STATUS 0x8B80
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0
+#define GL_LOWER_LEFT 0x8CA1
+#define GL_UPPER_LEFT 0x8CA2
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643
+#define GL_POINT_SPRITE 0x8861
+#define GL_COORD_REPLACE 0x8862
+#define GL_MAX_TEXTURE_COORDS 0x8871
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask);
+typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);
+typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);
+typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
+typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);
+typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
+typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs);
+GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader);
+GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name);
+GLAPI void APIENTRY glCompileShader (GLuint shader);
+GLAPI GLuint APIENTRY glCreateProgram (void);
+GLAPI GLuint APIENTRY glCreateShader (GLenum type);
+GLAPI void APIENTRY glDeleteProgram (GLuint program);
+GLAPI void APIENTRY glDeleteShader (GLuint shader);
+GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader);
+GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index);
+GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index);
+GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);
+GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
+GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params);
+GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer);
+GLAPI GLboolean APIENTRY glIsProgram (GLuint program);
+GLAPI GLboolean APIENTRY glIsShader (GLuint shader);
+GLAPI void APIENTRY glLinkProgram (GLuint program);
+GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
+GLAPI void APIENTRY glUseProgram (GLuint program);
+GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0);
+GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1);
+GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLAPI void APIENTRY glUniform1i (GLint location, GLint v0);
+GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1);
+GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2);
+GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glValidateProgram (GLuint program);
+GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x);
+GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x);
+GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x);
+GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y);
+GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y);
+GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_VERSION_2_0 */
+
+#ifndef GL_VERSION_2_1
+#define GL_VERSION_2_1 1
+#define GL_PIXEL_PACK_BUFFER 0x88EB
+#define GL_PIXEL_UNPACK_BUFFER 0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
+#define GL_FLOAT_MAT2x3 0x8B65
+#define GL_FLOAT_MAT2x4 0x8B66
+#define GL_FLOAT_MAT3x2 0x8B67
+#define GL_FLOAT_MAT3x4 0x8B68
+#define GL_FLOAT_MAT4x2 0x8B69
+#define GL_FLOAT_MAT4x3 0x8B6A
+#define GL_SRGB 0x8C40
+#define GL_SRGB8 0x8C41
+#define GL_SRGB_ALPHA 0x8C42
+#define GL_SRGB8_ALPHA8 0x8C43
+#define GL_COMPRESSED_SRGB 0x8C48
+#define GL_COMPRESSED_SRGB_ALPHA 0x8C49
+#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F
+#define GL_SLUMINANCE_ALPHA 0x8C44
+#define GL_SLUMINANCE8_ALPHA8 0x8C45
+#define GL_SLUMINANCE 0x8C46
+#define GL_SLUMINANCE8 0x8C47
+#define GL_COMPRESSED_SLUMINANCE 0x8C4A
+#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+#endif
+#endif /* GL_VERSION_2_1 */
+
+#ifndef GL_VERSION_3_0
+#define GL_VERSION_3_0 1
+typedef unsigned short GLhalf;
+#define GL_COMPARE_REF_TO_TEXTURE 0x884E
+#define GL_CLIP_DISTANCE0 0x3000
+#define GL_CLIP_DISTANCE1 0x3001
+#define GL_CLIP_DISTANCE2 0x3002
+#define GL_CLIP_DISTANCE3 0x3003
+#define GL_CLIP_DISTANCE4 0x3004
+#define GL_CLIP_DISTANCE5 0x3005
+#define GL_CLIP_DISTANCE6 0x3006
+#define GL_CLIP_DISTANCE7 0x3007
+#define GL_MAX_CLIP_DISTANCES 0x0D32
+#define GL_MAJOR_VERSION 0x821B
+#define GL_MINOR_VERSION 0x821C
+#define GL_NUM_EXTENSIONS 0x821D
+#define GL_CONTEXT_FLAGS 0x821E
+#define GL_COMPRESSED_RED 0x8225
+#define GL_COMPRESSED_RG 0x8226
+#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
+#define GL_RGBA32F 0x8814
+#define GL_RGB32F 0x8815
+#define GL_RGBA16F 0x881A
+#define GL_RGB16F 0x881B
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD
+#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
+#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904
+#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905
+#define GL_CLAMP_READ_COLOR 0x891C
+#define GL_FIXED_ONLY 0x891D
+#define GL_MAX_VARYING_COMPONENTS 0x8B4B
+#define GL_TEXTURE_1D_ARRAY 0x8C18
+#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19
+#define GL_TEXTURE_2D_ARRAY 0x8C1A
+#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B
+#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C
+#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
+#define GL_R11F_G11F_B10F 0x8C3A
+#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
+#define GL_RGB9_E5 0x8C3D
+#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
+#define GL_TEXTURE_SHARED_SIZE 0x8C3F
+#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
+#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
+#define GL_PRIMITIVES_GENERATED 0x8C87
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
+#define GL_RASTERIZER_DISCARD 0x8C89
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
+#define GL_INTERLEAVED_ATTRIBS 0x8C8C
+#define GL_SEPARATE_ATTRIBS 0x8C8D
+#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
+#define GL_RGBA32UI 0x8D70
+#define GL_RGB32UI 0x8D71
+#define GL_RGBA16UI 0x8D76
+#define GL_RGB16UI 0x8D77
+#define GL_RGBA8UI 0x8D7C
+#define GL_RGB8UI 0x8D7D
+#define GL_RGBA32I 0x8D82
+#define GL_RGB32I 0x8D83
+#define GL_RGBA16I 0x8D88
+#define GL_RGB16I 0x8D89
+#define GL_RGBA8I 0x8D8E
+#define GL_RGB8I 0x8D8F
+#define GL_RED_INTEGER 0x8D94
+#define GL_GREEN_INTEGER 0x8D95
+#define GL_BLUE_INTEGER 0x8D96
+#define GL_RGB_INTEGER 0x8D98
+#define GL_RGBA_INTEGER 0x8D99
+#define GL_BGR_INTEGER 0x8D9A
+#define GL_BGRA_INTEGER 0x8D9B
+#define GL_SAMPLER_1D_ARRAY 0x8DC0
+#define GL_SAMPLER_2D_ARRAY 0x8DC1
+#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3
+#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
+#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
+#define GL_UNSIGNED_INT_VEC2 0x8DC6
+#define GL_UNSIGNED_INT_VEC3 0x8DC7
+#define GL_UNSIGNED_INT_VEC4 0x8DC8
+#define GL_INT_SAMPLER_1D 0x8DC9
+#define GL_INT_SAMPLER_2D 0x8DCA
+#define GL_INT_SAMPLER_3D 0x8DCB
+#define GL_INT_SAMPLER_CUBE 0x8DCC
+#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE
+#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
+#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1
+#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
+#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
+#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
+#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
+#define GL_QUERY_WAIT 0x8E13
+#define GL_QUERY_NO_WAIT 0x8E14
+#define GL_QUERY_BY_REGION_WAIT 0x8E15
+#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16
+#define GL_BUFFER_ACCESS_FLAGS 0x911F
+#define GL_BUFFER_MAP_LENGTH 0x9120
+#define GL_BUFFER_MAP_OFFSET 0x9121
+#define GL_DEPTH_COMPONENT32F 0x8CAC
+#define GL_DEPTH32F_STENCIL8 0x8CAD
+#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
+#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
+#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
+#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
+#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
+#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
+#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
+#define GL_FRAMEBUFFER_DEFAULT 0x8218
+#define GL_FRAMEBUFFER_UNDEFINED 0x8219
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+#define GL_DEPTH_STENCIL 0x84F9
+#define GL_UNSIGNED_INT_24_8 0x84FA
+#define GL_DEPTH24_STENCIL8 0x88F0
+#define GL_TEXTURE_STENCIL_SIZE 0x88F1
+#define GL_TEXTURE_RED_TYPE 0x8C10
+#define GL_TEXTURE_GREEN_TYPE 0x8C11
+#define GL_TEXTURE_BLUE_TYPE 0x8C12
+#define GL_TEXTURE_ALPHA_TYPE 0x8C13
+#define GL_TEXTURE_DEPTH_TYPE 0x8C16
+#define GL_UNSIGNED_NORMALIZED 0x8C17
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
+#define GL_RENDERBUFFER_SAMPLES 0x8CAB
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_COLOR_ATTACHMENT1 0x8CE1
+#define GL_COLOR_ATTACHMENT2 0x8CE2
+#define GL_COLOR_ATTACHMENT3 0x8CE3
+#define GL_COLOR_ATTACHMENT4 0x8CE4
+#define GL_COLOR_ATTACHMENT5 0x8CE5
+#define GL_COLOR_ATTACHMENT6 0x8CE6
+#define GL_COLOR_ATTACHMENT7 0x8CE7
+#define GL_COLOR_ATTACHMENT8 0x8CE8
+#define GL_COLOR_ATTACHMENT9 0x8CE9
+#define GL_COLOR_ATTACHMENT10 0x8CEA
+#define GL_COLOR_ATTACHMENT11 0x8CEB
+#define GL_COLOR_ATTACHMENT12 0x8CEC
+#define GL_COLOR_ATTACHMENT13 0x8CED
+#define GL_COLOR_ATTACHMENT14 0x8CEE
+#define GL_COLOR_ATTACHMENT15 0x8CEF
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_STENCIL_INDEX1 0x8D46
+#define GL_STENCIL_INDEX4 0x8D47
+#define GL_STENCIL_INDEX8 0x8D48
+#define GL_STENCIL_INDEX16 0x8D49
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
+#define GL_MAX_SAMPLES 0x8D57
+#define GL_INDEX 0x8222
+#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14
+#define GL_TEXTURE_INTENSITY_TYPE 0x8C15
+#define GL_FRAMEBUFFER_SRGB 0x8DB9
+#define GL_HALF_FLOAT 0x140B
+#define GL_MAP_READ_BIT 0x0001
+#define GL_MAP_WRITE_BIT 0x0002
+#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
+#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
+#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
+#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
+#define GL_COMPRESSED_RED_RGTC1 0x8DBB
+#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
+#define GL_COMPRESSED_RG_RGTC2 0x8DBD
+#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
+#define GL_RG 0x8227
+#define GL_RG_INTEGER 0x8228
+#define GL_R8 0x8229
+#define GL_R16 0x822A
+#define GL_RG8 0x822B
+#define GL_RG16 0x822C
+#define GL_R16F 0x822D
+#define GL_R32F 0x822E
+#define GL_RG16F 0x822F
+#define GL_RG32F 0x8230
+#define GL_R8I 0x8231
+#define GL_R8UI 0x8232
+#define GL_R16I 0x8233
+#define GL_R16UI 0x8234
+#define GL_R32I 0x8235
+#define GL_R32UI 0x8236
+#define GL_RG8I 0x8237
+#define GL_RG8UI 0x8238
+#define GL_RG16I 0x8239
+#define GL_RG16UI 0x823A
+#define GL_RG32I 0x823B
+#define GL_RG32UI 0x823C
+#define GL_VERTEX_ARRAY_BINDING 0x85B5
+#define GL_CLAMP_VERTEX_COLOR 0x891A
+#define GL_CLAMP_FRAGMENT_COLOR 0x891B
+#define GL_ALPHA_INTEGER 0x8D97
+typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
+typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index);
+typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode);
+typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void);
+typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp);
+typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode);
+typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params);
+typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value);
+typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value);
+typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);
+typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer);
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer);
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers);
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers);
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void *(APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
+typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
+typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
+typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data);
+GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data);
+GLAPI void APIENTRY glEnablei (GLenum target, GLuint index);
+GLAPI void APIENTRY glDisablei (GLenum target, GLuint index);
+GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index);
+GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode);
+GLAPI void APIENTRY glEndTransformFeedback (void);
+GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer);
+GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
+GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp);
+GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode);
+GLAPI void APIENTRY glEndConditionalRender (void);
+GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x);
+GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y);
+GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x);
+GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y);
+GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z);
+GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params);
+GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name);
+GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0);
+GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1);
+GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2);
+GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params);
+GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value);
+GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value);
+GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value);
+GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index);
+GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers);
+GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers);
+GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer);
+GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers);
+GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers);
+GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target);
+GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGenerateMipmap (GLenum target);
+GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GLAPI void *APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length);
+GLAPI void APIENTRY glBindVertexArray (GLuint array);
+GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays);
+GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays);
+GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array);
+#endif
+#endif /* GL_VERSION_3_0 */
+
+#ifndef GL_VERSION_3_1
+#define GL_VERSION_3_1 1
+#define GL_SAMPLER_2D_RECT 0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64
+#define GL_SAMPLER_BUFFER 0x8DC2
+#define GL_INT_SAMPLER_2D_RECT 0x8DCD
+#define GL_INT_SAMPLER_BUFFER 0x8DD0
+#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8
+#define GL_TEXTURE_BUFFER 0x8C2A
+#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B
+#define GL_TEXTURE_BINDING_BUFFER 0x8C2C
+#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D
+#define GL_TEXTURE_RECTANGLE 0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8
+#define GL_R8_SNORM 0x8F94
+#define GL_RG8_SNORM 0x8F95
+#define GL_RGB8_SNORM 0x8F96
+#define GL_RGBA8_SNORM 0x8F97
+#define GL_R16_SNORM 0x8F98
+#define GL_RG16_SNORM 0x8F99
+#define GL_RGB16_SNORM 0x8F9A
+#define GL_RGBA16_SNORM 0x8F9B
+#define GL_SIGNED_NORMALIZED 0x8F9C
+#define GL_PRIMITIVE_RESTART 0x8F9D
+#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E
+#define GL_COPY_READ_BUFFER 0x8F36
+#define GL_COPY_WRITE_BUFFER 0x8F37
+#define GL_UNIFORM_BUFFER 0x8A11
+#define GL_UNIFORM_BUFFER_BINDING 0x8A28
+#define GL_UNIFORM_BUFFER_START 0x8A29
+#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
+#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
+#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
+#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
+#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
+#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
+#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
+#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
+#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
+#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
+#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
+#define GL_UNIFORM_TYPE 0x8A37
+#define GL_UNIFORM_SIZE 0x8A38
+#define GL_UNIFORM_NAME_LENGTH 0x8A39
+#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
+#define GL_UNIFORM_OFFSET 0x8A3B
+#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
+#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
+#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
+#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
+#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
+#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
+#define GL_INVALID_INDEX 0xFFFFFFFFu
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
+typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);
+typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);
+typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
+GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
+GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer);
+GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index);
+GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);
+GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);
+GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName);
+GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);
+GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+#endif
+#endif /* GL_VERSION_3_1 */
+
+#ifndef GL_VERSION_3_2
+#define GL_VERSION_3_2 1
+typedef struct __GLsync *GLsync;
+#ifndef GLEXT_64_TYPES_DEFINED
+/* This code block is duplicated in glxext.h, so must be protected */
+#define GLEXT_64_TYPES_DEFINED
+/* Define int32_t, int64_t, and uint64_t types for UST/MSC */
+/* (as used in the GL_EXT_timer_query extension). */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+#elif defined(__sun__) || defined(__digital__)
+#include <inttypes.h>
+#if defined(__STDC__)
+#if defined(__arch64__) || defined(_LP64)
+typedef long int int64_t;
+typedef unsigned long int uint64_t;
+#else
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#endif /* __arch64__ */
+#endif /* __STDC__ */
+#elif defined( __VMS ) || defined(__sgi)
+#include <inttypes.h>
+#elif defined(__SCO__) || defined(__USLC__)
+#include <stdint.h>
+#elif defined(__UNIXOS2__) || defined(__SOL64__)
+typedef long int int32_t;
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#elif defined(_WIN32) && defined(__GNUC__)
+#include <stdint.h>
+#elif defined(_WIN32)
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+/* Fallback if nothing above works */
+#include <inttypes.h>
+#endif
+#endif
+typedef uint64_t GLuint64;
+typedef int64_t GLint64;
+#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
+#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define GL_LINES_ADJACENCY 0x000A
+#define GL_LINE_STRIP_ADJACENCY 0x000B
+#define GL_TRIANGLES_ADJACENCY 0x000C
+#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D
+#define GL_PROGRAM_POINT_SIZE 0x8642
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8
+#define GL_GEOMETRY_SHADER 0x8DD9
+#define GL_GEOMETRY_VERTICES_OUT 0x8916
+#define GL_GEOMETRY_INPUT_TYPE 0x8917
+#define GL_GEOMETRY_OUTPUT_TYPE 0x8918
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
+#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
+#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123
+#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124
+#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
+#define GL_CONTEXT_PROFILE_MASK 0x9126
+#define GL_DEPTH_CLAMP 0x864F
+#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C
+#define GL_FIRST_VERTEX_CONVENTION 0x8E4D
+#define GL_LAST_VERTEX_CONVENTION 0x8E4E
+#define GL_PROVOKING_VERTEX 0x8E4F
+#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
+#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
+#define GL_OBJECT_TYPE 0x9112
+#define GL_SYNC_CONDITION 0x9113
+#define GL_SYNC_STATUS 0x9114
+#define GL_SYNC_FLAGS 0x9115
+#define GL_SYNC_FENCE 0x9116
+#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
+#define GL_UNSIGNALED 0x9118
+#define GL_SIGNALED 0x9119
+#define GL_ALREADY_SIGNALED 0x911A
+#define GL_TIMEOUT_EXPIRED 0x911B
+#define GL_CONDITION_SATISFIED 0x911C
+#define GL_WAIT_FAILED 0x911D
+#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull
+#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
+#define GL_SAMPLE_POSITION 0x8E50
+#define GL_SAMPLE_MASK 0x8E51
+#define GL_SAMPLE_MASK_VALUE 0x8E52
+#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59
+#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101
+#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105
+#define GL_TEXTURE_SAMPLES 0x9106
+#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107
+#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
+#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
+#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B
+#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
+#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E
+#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F
+#define GL_MAX_INTEGER_SAMPLES 0x9110
+typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);
+typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode);
+typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags);
+typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync);
+typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync);
+typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data);
+typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val);
+typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
+GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);
+GLAPI void APIENTRY glProvokingVertex (GLenum mode);
+GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags);
+GLAPI GLboolean APIENTRY glIsSync (GLsync sync);
+GLAPI void APIENTRY glDeleteSync (GLsync sync);
+GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout);
+GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout);
+GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *data);
+GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data);
+GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params);
+GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level);
+GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val);
+GLAPI void APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask);
+#endif
+#endif /* GL_VERSION_3_2 */
+
+#ifndef GL_VERSION_3_3
+#define GL_VERSION_3_3 1
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
+#define GL_SRC1_COLOR 0x88F9
+#define GL_ONE_MINUS_SRC1_COLOR 0x88FA
+#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
+#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC
+#define GL_ANY_SAMPLES_PASSED 0x8C2F
+#define GL_SAMPLER_BINDING 0x8919
+#define GL_RGB10_A2UI 0x906F
+#define GL_TEXTURE_SWIZZLE_R 0x8E42
+#define GL_TEXTURE_SWIZZLE_G 0x8E43
+#define GL_TEXTURE_SWIZZLE_B 0x8E44
+#define GL_TEXTURE_SWIZZLE_A 0x8E45
+#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
+#define GL_TIME_ELAPSED 0x88BF
+#define GL_TIMESTAMP 0x8E28
+#define GL_INT_2_10_10_10_REV 0x8D9F
+typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers);
+typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers);
+typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler);
+typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param);
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value);
+typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color);
+typedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color);
+typedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color);
+typedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
+GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers);
+GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers);
+GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler);
+GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler);
+GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param);
+GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param);
+GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param);
+GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param);
+GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param);
+GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target);
+GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params);
+GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params);
+GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor);
+GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value);
+GLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value);
+GLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value);
+GLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value);
+GLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value);
+GLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value);
+GLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords);
+GLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords);
+GLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords);
+GLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords);
+GLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords);
+GLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords);
+GLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords);
+GLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords);
+GLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords);
+GLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color);
+GLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color);
+GLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color);
+GLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color);
+GLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color);
+GLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color);
+#endif
+#endif /* GL_VERSION_3_3 */
+
+#ifndef GL_VERSION_4_0
+#define GL_VERSION_4_0 1
+#define GL_SAMPLE_SHADING 0x8C36
+#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37
+#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E
+#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F
+#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A
+#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B
+#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C
+#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D
+#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F
+#define GL_DRAW_INDIRECT_BUFFER 0x8F3F
+#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43
+#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F
+#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A
+#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B
+#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C
+#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D
+#define GL_MAX_VERTEX_STREAMS 0x8E71
+#define GL_DOUBLE_VEC2 0x8FFC
+#define GL_DOUBLE_VEC3 0x8FFD
+#define GL_DOUBLE_VEC4 0x8FFE
+#define GL_DOUBLE_MAT2 0x8F46
+#define GL_DOUBLE_MAT3 0x8F47
+#define GL_DOUBLE_MAT4 0x8F48
+#define GL_DOUBLE_MAT2x3 0x8F49
+#define GL_DOUBLE_MAT2x4 0x8F4A
+#define GL_DOUBLE_MAT3x2 0x8F4B
+#define GL_DOUBLE_MAT3x4 0x8F4C
+#define GL_DOUBLE_MAT4x2 0x8F4D
+#define GL_DOUBLE_MAT4x3 0x8F4E
+#define GL_ACTIVE_SUBROUTINES 0x8DE5
+#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6
+#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47
+#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48
+#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49
+#define GL_MAX_SUBROUTINES 0x8DE7
+#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8
+#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A
+#define GL_COMPATIBLE_SUBROUTINES 0x8E4B
+#define GL_PATCHES 0x000E
+#define GL_PATCH_VERTICES 0x8E72
+#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
+#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74
+#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75
+#define GL_TESS_GEN_MODE 0x8E76
+#define GL_TESS_GEN_SPACING 0x8E77
+#define GL_TESS_GEN_VERTEX_ORDER 0x8E78
+#define GL_TESS_GEN_POINT_MODE 0x8E79
+#define GL_ISOLINES 0x8E7A
+#define GL_FRACTIONAL_ODD 0x8E7B
+#define GL_FRACTIONAL_EVEN 0x8E7C
+#define GL_MAX_PATCH_VERTICES 0x8E7D
+#define GL_MAX_TESS_GEN_LEVEL 0x8E7E
+#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F
+#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80
+#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81
+#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82
+#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83
+#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84
+#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85
+#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86
+#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89
+#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A
+#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C
+#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D
+#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E
+#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1
+#define GL_TESS_EVALUATION_SHADER 0x8E87
+#define GL_TESS_CONTROL_SHADER 0x8E88
+#define GL_TRANSFORM_FEEDBACK 0x8E22
+#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23
+#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24
+#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25
+#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70
+typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect);
+typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x);
+typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params);
+typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name);
+typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);
+typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
+typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices);
+typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values);
+typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value);
+typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values);
+typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids);
+typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void);
+typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void);
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id);
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream);
+typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMinSampleShading (GLfloat value);
+GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode);
+GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst);
+GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect);
+GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect);
+GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x);
+GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params);
+GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name);
+GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name);
+GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);
+GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
+GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
+GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices);
+GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params);
+GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values);
+GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value);
+GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values);
+GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id);
+GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids);
+GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids);
+GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id);
+GLAPI void APIENTRY glPauseTransformFeedback (void);
+GLAPI void APIENTRY glResumeTransformFeedback (void);
+GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id);
+GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream);
+GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id);
+GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index);
+GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params);
+#endif
+#endif /* GL_VERSION_4_0 */
+
+#ifndef GL_VERSION_4_1
+#define GL_VERSION_4_1 1
+#define GL_FIXED 0x140C
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+#define GL_SHADER_COMPILER 0x8DFA
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_RGB565 0x8D62
+#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257
+#define GL_PROGRAM_BINARY_LENGTH 0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
+#define GL_PROGRAM_BINARY_FORMATS 0x87FF
+#define GL_VERTEX_SHADER_BIT 0x00000001
+#define GL_FRAGMENT_SHADER_BIT 0x00000002
+#define GL_GEOMETRY_SHADER_BIT 0x00000004
+#define GL_TESS_CONTROL_SHADER_BIT 0x00000008
+#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010
+#define GL_ALL_SHADER_BITS 0xFFFFFFFF
+#define GL_PROGRAM_SEPARABLE 0x8258
+#define GL_ACTIVE_PROGRAM 0x8259
+#define GL_PROGRAM_PIPELINE_BINDING 0x825A
+#define GL_MAX_VIEWPORTS 0x825B
+#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C
+#define GL_VIEWPORT_BOUNDS_RANGE 0x825D
+#define GL_LAYER_PROVOKING_VERTEX 0x825E
+#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F
+#define GL_UNDEFINED_VERTEX 0x8260
+typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void);
+typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);
+typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);
+typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f);
+typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d);
+typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program);
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings);
+typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines);
+typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline);
+typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline);
+typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v);
+typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f);
+typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReleaseShaderCompiler (void);
+GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);
+GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);
+GLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f);
+GLAPI void APIENTRY glClearDepthf (GLfloat d);
+GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
+GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value);
+GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program);
+GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program);
+GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings);
+GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline);
+GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines);
+GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines);
+GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline);
+GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params);
+GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0);
+GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0);
+GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0);
+GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0);
+GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1);
+GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1);
+GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1);
+GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1);
+GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);
+GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);
+GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline);
+GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x);
+GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v);
+GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLdouble n, GLdouble f);
+GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data);
+GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data);
+#endif
+#endif /* GL_VERSION_4_1 */
+
+#ifndef GL_VERSION_4_2
+#define GL_VERSION_4_2 1
+#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127
+#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128
+#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129
+#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A
+#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B
+#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C
+#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D
+#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E
+#define GL_NUM_SAMPLE_COUNTS 0x9380
+#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC
+#define GL_ATOMIC_COUNTER_BUFFER 0x92C0
+#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1
+#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2
+#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3
+#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB
+#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0
+#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1
+#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6
+#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC
+#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9
+#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA
+#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB
+#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
+#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
+#define GL_UNIFORM_BARRIER_BIT 0x00000004
+#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+#define GL_COMMAND_BARRIER_BIT 0x00000040
+#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
+#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
+#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
+#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
+#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
+#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
+#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
+#define GL_MAX_IMAGE_UNITS 0x8F38
+#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39
+#define GL_IMAGE_BINDING_NAME 0x8F3A
+#define GL_IMAGE_BINDING_LEVEL 0x8F3B
+#define GL_IMAGE_BINDING_LAYERED 0x8F3C
+#define GL_IMAGE_BINDING_LAYER 0x8F3D
+#define GL_IMAGE_BINDING_ACCESS 0x8F3E
+#define GL_IMAGE_1D 0x904C
+#define GL_IMAGE_2D 0x904D
+#define GL_IMAGE_3D 0x904E
+#define GL_IMAGE_2D_RECT 0x904F
+#define GL_IMAGE_CUBE 0x9050
+#define GL_IMAGE_BUFFER 0x9051
+#define GL_IMAGE_1D_ARRAY 0x9052
+#define GL_IMAGE_2D_ARRAY 0x9053
+#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
+#define GL_IMAGE_2D_MULTISAMPLE 0x9055
+#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056
+#define GL_INT_IMAGE_1D 0x9057
+#define GL_INT_IMAGE_2D 0x9058
+#define GL_INT_IMAGE_3D 0x9059
+#define GL_INT_IMAGE_2D_RECT 0x905A
+#define GL_INT_IMAGE_CUBE 0x905B
+#define GL_INT_IMAGE_BUFFER 0x905C
+#define GL_INT_IMAGE_1D_ARRAY 0x905D
+#define GL_INT_IMAGE_2D_ARRAY 0x905E
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
+#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060
+#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
+#define GL_UNSIGNED_INT_IMAGE_1D 0x9062
+#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
+#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
+#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065
+#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
+#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
+#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
+#define GL_MAX_IMAGE_SAMPLES 0x906D
+#define GL_IMAGE_BINDING_FORMAT 0x906E
+#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9
+#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA
+#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB
+#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC
+#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD
+#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE
+#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF
+#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
+#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
+#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
+#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
+#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
+typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
+typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers);
+typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount);
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
+GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
+GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
+GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
+GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
+GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers);
+GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei instancecount);
+GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);
+#endif
+#endif /* GL_VERSION_4_2 */
+
+#ifndef GL_VERSION_4_3
+#define GL_VERSION_4_3 1
+typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9
+#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E
+#define GL_COMPRESSED_RGB8_ETC2 0x9274
+#define GL_COMPRESSED_SRGB8_ETC2 0x9275
+#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
+#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
+#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
+#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
+#define GL_COMPRESSED_R11_EAC 0x9270
+#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
+#define GL_COMPRESSED_RG11_EAC 0x9272
+#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
+#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
+#define GL_MAX_ELEMENT_INDEX 0x8D6B
+#define GL_COMPUTE_SHADER 0x91B9
+#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB
+#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC
+#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD
+#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262
+#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263
+#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264
+#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265
+#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266
+#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB
+#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE
+#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF
+#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED
+#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE
+#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
+#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
+#define GL_DEBUG_SOURCE_API 0x8246
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
+#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
+#define GL_DEBUG_SOURCE_APPLICATION 0x824A
+#define GL_DEBUG_SOURCE_OTHER 0x824B
+#define GL_DEBUG_TYPE_ERROR 0x824C
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
+#define GL_DEBUG_TYPE_PORTABILITY 0x824F
+#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
+#define GL_DEBUG_TYPE_OTHER 0x8251
+#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
+#define GL_DEBUG_LOGGED_MESSAGES 0x9145
+#define GL_DEBUG_SEVERITY_HIGH 0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
+#define GL_DEBUG_SEVERITY_LOW 0x9148
+#define GL_DEBUG_TYPE_MARKER 0x8268
+#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
+#define GL_DEBUG_TYPE_POP_GROUP 0x826A
+#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
+#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
+#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
+#define GL_BUFFER 0x82E0
+#define GL_SHADER 0x82E1
+#define GL_PROGRAM 0x82E2
+#define GL_QUERY 0x82E3
+#define GL_PROGRAM_PIPELINE 0x82E4
+#define GL_SAMPLER 0x82E6
+#define GL_MAX_LABEL_LENGTH 0x82E8
+#define GL_DEBUG_OUTPUT 0x92E0
+#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
+#define GL_MAX_UNIFORM_LOCATIONS 0x826E
+#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310
+#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311
+#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312
+#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313
+#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314
+#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315
+#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316
+#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317
+#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318
+#define GL_INTERNALFORMAT_SUPPORTED 0x826F
+#define GL_INTERNALFORMAT_PREFERRED 0x8270
+#define GL_INTERNALFORMAT_RED_SIZE 0x8271
+#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272
+#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273
+#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274
+#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275
+#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276
+#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277
+#define GL_INTERNALFORMAT_RED_TYPE 0x8278
+#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279
+#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A
+#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B
+#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C
+#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D
+#define GL_MAX_WIDTH 0x827E
+#define GL_MAX_HEIGHT 0x827F
+#define GL_MAX_DEPTH 0x8280
+#define GL_MAX_LAYERS 0x8281
+#define GL_MAX_COMBINED_DIMENSIONS 0x8282
+#define GL_COLOR_COMPONENTS 0x8283
+#define GL_DEPTH_COMPONENTS 0x8284
+#define GL_STENCIL_COMPONENTS 0x8285
+#define GL_COLOR_RENDERABLE 0x8286
+#define GL_DEPTH_RENDERABLE 0x8287
+#define GL_STENCIL_RENDERABLE 0x8288
+#define GL_FRAMEBUFFER_RENDERABLE 0x8289
+#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A
+#define GL_FRAMEBUFFER_BLEND 0x828B
+#define GL_READ_PIXELS 0x828C
+#define GL_READ_PIXELS_FORMAT 0x828D
+#define GL_READ_PIXELS_TYPE 0x828E
+#define GL_TEXTURE_IMAGE_FORMAT 0x828F
+#define GL_TEXTURE_IMAGE_TYPE 0x8290
+#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291
+#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292
+#define GL_MIPMAP 0x8293
+#define GL_MANUAL_GENERATE_MIPMAP 0x8294
+#define GL_AUTO_GENERATE_MIPMAP 0x8295
+#define GL_COLOR_ENCODING 0x8296
+#define GL_SRGB_READ 0x8297
+#define GL_SRGB_WRITE 0x8298
+#define GL_FILTER 0x829A
+#define GL_VERTEX_TEXTURE 0x829B
+#define GL_TESS_CONTROL_TEXTURE 0x829C
+#define GL_TESS_EVALUATION_TEXTURE 0x829D
+#define GL_GEOMETRY_TEXTURE 0x829E
+#define GL_FRAGMENT_TEXTURE 0x829F
+#define GL_COMPUTE_TEXTURE 0x82A0
+#define GL_TEXTURE_SHADOW 0x82A1
+#define GL_TEXTURE_GATHER 0x82A2
+#define GL_TEXTURE_GATHER_SHADOW 0x82A3
+#define GL_SHADER_IMAGE_LOAD 0x82A4
+#define GL_SHADER_IMAGE_STORE 0x82A5
+#define GL_SHADER_IMAGE_ATOMIC 0x82A6
+#define GL_IMAGE_TEXEL_SIZE 0x82A7
+#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8
+#define GL_IMAGE_PIXEL_FORMAT 0x82A9
+#define GL_IMAGE_PIXEL_TYPE 0x82AA
+#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC
+#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD
+#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE
+#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF
+#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1
+#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2
+#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3
+#define GL_CLEAR_BUFFER 0x82B4
+#define GL_TEXTURE_VIEW 0x82B5
+#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6
+#define GL_FULL_SUPPORT 0x82B7
+#define GL_CAVEAT_SUPPORT 0x82B8
+#define GL_IMAGE_CLASS_4_X_32 0x82B9
+#define GL_IMAGE_CLASS_2_X_32 0x82BA
+#define GL_IMAGE_CLASS_1_X_32 0x82BB
+#define GL_IMAGE_CLASS_4_X_16 0x82BC
+#define GL_IMAGE_CLASS_2_X_16 0x82BD
+#define GL_IMAGE_CLASS_1_X_16 0x82BE
+#define GL_IMAGE_CLASS_4_X_8 0x82BF
+#define GL_IMAGE_CLASS_2_X_8 0x82C0
+#define GL_IMAGE_CLASS_1_X_8 0x82C1
+#define GL_IMAGE_CLASS_11_11_10 0x82C2
+#define GL_IMAGE_CLASS_10_10_10_2 0x82C3
+#define GL_VIEW_CLASS_128_BITS 0x82C4
+#define GL_VIEW_CLASS_96_BITS 0x82C5
+#define GL_VIEW_CLASS_64_BITS 0x82C6
+#define GL_VIEW_CLASS_48_BITS 0x82C7
+#define GL_VIEW_CLASS_32_BITS 0x82C8
+#define GL_VIEW_CLASS_24_BITS 0x82C9
+#define GL_VIEW_CLASS_16_BITS 0x82CA
+#define GL_VIEW_CLASS_8_BITS 0x82CB
+#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC
+#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD
+#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE
+#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF
+#define GL_VIEW_CLASS_RGTC1_RED 0x82D0
+#define GL_VIEW_CLASS_RGTC2_RG 0x82D1
+#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2
+#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3
+#define GL_UNIFORM 0x92E1
+#define GL_UNIFORM_BLOCK 0x92E2
+#define GL_PROGRAM_INPUT 0x92E3
+#define GL_PROGRAM_OUTPUT 0x92E4
+#define GL_BUFFER_VARIABLE 0x92E5
+#define GL_SHADER_STORAGE_BLOCK 0x92E6
+#define GL_VERTEX_SUBROUTINE 0x92E8
+#define GL_TESS_CONTROL_SUBROUTINE 0x92E9
+#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA
+#define GL_GEOMETRY_SUBROUTINE 0x92EB
+#define GL_FRAGMENT_SUBROUTINE 0x92EC
+#define GL_COMPUTE_SUBROUTINE 0x92ED
+#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE
+#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF
+#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0
+#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1
+#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2
+#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3
+#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4
+#define GL_ACTIVE_RESOURCES 0x92F5
+#define GL_MAX_NAME_LENGTH 0x92F6
+#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7
+#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8
+#define GL_NAME_LENGTH 0x92F9
+#define GL_TYPE 0x92FA
+#define GL_ARRAY_SIZE 0x92FB
+#define GL_OFFSET 0x92FC
+#define GL_BLOCK_INDEX 0x92FD
+#define GL_ARRAY_STRIDE 0x92FE
+#define GL_MATRIX_STRIDE 0x92FF
+#define GL_IS_ROW_MAJOR 0x9300
+#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301
+#define GL_BUFFER_BINDING 0x9302
+#define GL_BUFFER_DATA_SIZE 0x9303
+#define GL_NUM_ACTIVE_VARIABLES 0x9304
+#define GL_ACTIVE_VARIABLES 0x9305
+#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306
+#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307
+#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308
+#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309
+#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A
+#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B
+#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C
+#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D
+#define GL_LOCATION 0x930E
+#define GL_LOCATION_INDEX 0x930F
+#define GL_IS_PER_PATCH 0x92E7
+#define GL_SHADER_STORAGE_BUFFER 0x90D2
+#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3
+#define GL_SHADER_STORAGE_BUFFER_START 0x90D4
+#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5
+#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6
+#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7
+#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8
+#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9
+#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA
+#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB
+#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC
+#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD
+#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE
+#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF
+#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
+#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39
+#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA
+#define GL_TEXTURE_BUFFER_OFFSET 0x919D
+#define GL_TEXTURE_BUFFER_SIZE 0x919E
+#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F
+#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB
+#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC
+#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD
+#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE
+#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF
+#define GL_VERTEX_ATTRIB_BINDING 0x82D4
+#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5
+#define GL_VERTEX_BINDING_DIVISOR 0x82D6
+#define GL_VERTEX_BINDING_OFFSET 0x82D7
+#define GL_VERTEX_BINDING_STRIDE 0x82D8
+#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9
+#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA
+#define GL_VERTEX_BINDING_BUFFER 0x8F4F
+#define GL_DISPLAY_LIST 0x82E7
+typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
+typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect);
+typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params);
+typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);
+typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params);
+typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
+typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params);
+typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);
+typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
+typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
+typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex);
+typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);
+typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void);
+typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label);
+typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glClearBufferData (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glClearBufferSubData (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
+GLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect);
+GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+GLAPI void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params);
+GLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
+GLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level);
+GLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length);
+GLAPI void APIENTRY glInvalidateBufferData (GLuint buffer);
+GLAPI void APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+GLAPI void APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glMultiDrawArraysIndirect (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
+GLAPI void APIENTRY glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
+GLAPI void APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params);
+GLAPI GLuint APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name);
+GLAPI void APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
+GLAPI void APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params);
+GLAPI GLint APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name);
+GLAPI GLint APIENTRY glGetProgramResourceLocationIndex (GLuint program, GLenum programInterface, const GLchar *name);
+GLAPI void APIENTRY glShaderStorageBlockBinding (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
+GLAPI void APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glTextureView (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
+GLAPI void APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+GLAPI void APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexAttribLFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex);
+GLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor);
+GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam);
+GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+GLAPI void APIENTRY glPopDebugGroup (void);
+GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+GLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+GLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label);
+GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+#endif /* GL_VERSION_4_3 */
+
+#ifndef GL_VERSION_4_4
+#define GL_VERSION_4_4 1
+#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5
+#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221
+#define GL_TEXTURE_BUFFER_BINDING 0x8C2A
+#define GL_MAP_PERSISTENT_BIT 0x0040
+#define GL_MAP_COHERENT_BIT 0x0080
+#define GL_DYNAMIC_STORAGE_BIT 0x0100
+#define GL_CLIENT_STORAGE_BIT 0x0200
+#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000
+#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F
+#define GL_BUFFER_STORAGE_FLAGS 0x8220
+#define GL_CLEAR_TEXTURE 0x9365
+#define GL_LOCATION_COMPONENT 0x934A
+#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B
+#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C
+#define GL_QUERY_BUFFER 0x9192
+#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000
+#define GL_QUERY_BUFFER_BINDING 0x9193
+#define GL_QUERY_RESULT_NO_WAIT 0x9194
+#define GL_MIRROR_CLAMP_TO_EDGE 0x8743
+typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
+typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);
+typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
+typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers);
+typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
+typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBufferStorage (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
+GLAPI void APIENTRY glClearTexImage (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glClearTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glBindBuffersBase (GLenum target, GLuint first, GLsizei count, const GLuint *buffers);
+GLAPI void APIENTRY glBindBuffersRange (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);
+GLAPI void APIENTRY glBindTextures (GLuint first, GLsizei count, const GLuint *textures);
+GLAPI void APIENTRY glBindSamplers (GLuint first, GLsizei count, const GLuint *samplers);
+GLAPI void APIENTRY glBindImageTextures (GLuint first, GLsizei count, const GLuint *textures);
+GLAPI void APIENTRY glBindVertexBuffers (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
+#endif
+#endif /* GL_VERSION_4_4 */
+
+#ifndef GL_ARB_ES2_compatibility
+#define GL_ARB_ES2_compatibility 1
+#endif /* GL_ARB_ES2_compatibility */
+
+#ifndef GL_ARB_ES3_compatibility
+#define GL_ARB_ES3_compatibility 1
+#endif /* GL_ARB_ES3_compatibility */
+
+#ifndef GL_ARB_arrays_of_arrays
+#define GL_ARB_arrays_of_arrays 1
+#endif /* GL_ARB_arrays_of_arrays */
+
+#ifndef GL_ARB_base_instance
+#define GL_ARB_base_instance 1
+#endif /* GL_ARB_base_instance */
+
+#ifndef GL_ARB_bindless_texture
+#define GL_ARB_bindless_texture 1
+typedef uint64_t GLuint64EXT;
+#define GL_UNSIGNED_INT64_ARB 0x140F
+typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC) (GLuint texture);
+typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler);
+typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle);
+typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
+typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access);
+typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value);
+typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);
+typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint64 APIENTRY glGetTextureHandleARB (GLuint texture);
+GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleARB (GLuint texture, GLuint sampler);
+GLAPI void APIENTRY glMakeTextureHandleResidentARB (GLuint64 handle);
+GLAPI void APIENTRY glMakeTextureHandleNonResidentARB (GLuint64 handle);
+GLAPI GLuint64 APIENTRY glGetImageHandleARB (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
+GLAPI void APIENTRY glMakeImageHandleResidentARB (GLuint64 handle, GLenum access);
+GLAPI void APIENTRY glMakeImageHandleNonResidentARB (GLuint64 handle);
+GLAPI void APIENTRY glUniformHandleui64ARB (GLint location, GLuint64 value);
+GLAPI void APIENTRY glUniformHandleui64vARB (GLint location, GLsizei count, const GLuint64 *value);
+GLAPI void APIENTRY glProgramUniformHandleui64ARB (GLuint program, GLint location, GLuint64 value);
+GLAPI void APIENTRY glProgramUniformHandleui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+GLAPI GLboolean APIENTRY glIsTextureHandleResidentARB (GLuint64 handle);
+GLAPI GLboolean APIENTRY glIsImageHandleResidentARB (GLuint64 handle);
+GLAPI void APIENTRY glVertexAttribL1ui64ARB (GLuint index, GLuint64EXT x);
+GLAPI void APIENTRY glVertexAttribL1ui64vARB (GLuint index, const GLuint64EXT *v);
+GLAPI void APIENTRY glGetVertexAttribLui64vARB (GLuint index, GLenum pname, GLuint64EXT *params);
+#endif
+#endif /* GL_ARB_bindless_texture */
+
+#ifndef GL_ARB_blend_func_extended
+#define GL_ARB_blend_func_extended 1
+#endif /* GL_ARB_blend_func_extended */
+
+#ifndef GL_ARB_buffer_storage
+#define GL_ARB_buffer_storage 1
+#endif /* GL_ARB_buffer_storage */
+
+#ifndef GL_ARB_cl_event
+#define GL_ARB_cl_event 1
+struct _cl_context;
+struct _cl_event;
+#define GL_SYNC_CL_EVENT_ARB 0x8240
+#define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241
+typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, struct _cl_event *event, GLbitfield flags);
+#endif
+#endif /* GL_ARB_cl_event */
+
+#ifndef GL_ARB_clear_buffer_object
+#define GL_ARB_clear_buffer_object 1
+#endif /* GL_ARB_clear_buffer_object */
+
+#ifndef GL_ARB_clear_texture
+#define GL_ARB_clear_texture 1
+#endif /* GL_ARB_clear_texture */
+
+#ifndef GL_ARB_color_buffer_float
+#define GL_ARB_color_buffer_float 1
+#define GL_RGBA_FLOAT_MODE_ARB 0x8820
+#define GL_CLAMP_VERTEX_COLOR_ARB 0x891A
+#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B
+#define GL_CLAMP_READ_COLOR_ARB 0x891C
+#define GL_FIXED_ONLY_ARB 0x891D
+typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp);
+#endif
+#endif /* GL_ARB_color_buffer_float */
+
+#ifndef GL_ARB_compatibility
+#define GL_ARB_compatibility 1
+#endif /* GL_ARB_compatibility */
+
+#ifndef GL_ARB_compressed_texture_pixel_storage
+#define GL_ARB_compressed_texture_pixel_storage 1
+#endif /* GL_ARB_compressed_texture_pixel_storage */
+
+#ifndef GL_ARB_compute_shader
+#define GL_ARB_compute_shader 1
+#define GL_COMPUTE_SHADER_BIT 0x00000020
+#endif /* GL_ARB_compute_shader */
+
+#ifndef GL_ARB_compute_variable_group_size
+#define GL_ARB_compute_variable_group_size 1
+#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344
+#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB
+#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345
+#define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF
+typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z);
+#endif
+#endif /* GL_ARB_compute_variable_group_size */
+
+#ifndef GL_ARB_conservative_depth
+#define GL_ARB_conservative_depth 1
+#endif /* GL_ARB_conservative_depth */
+
+#ifndef GL_ARB_copy_buffer
+#define GL_ARB_copy_buffer 1
+#define GL_COPY_READ_BUFFER_BINDING 0x8F36
+#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37
+#endif /* GL_ARB_copy_buffer */
+
+#ifndef GL_ARB_copy_image
+#define GL_ARB_copy_image 1
+#endif /* GL_ARB_copy_image */
+
+#ifndef GL_ARB_debug_output
+#define GL_ARB_debug_output 1
+typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243
+#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245
+#define GL_DEBUG_SOURCE_API_ARB 0x8246
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247
+#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249
+#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A
+#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B
+#define GL_DEBUG_TYPE_ERROR_ARB 0x824C
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E
+#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F
+#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250
+#define GL_DEBUG_TYPE_OTHER_ARB 0x8251
+#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144
+#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145
+#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147
+#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam);
+typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const void *userParam);
+GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+#endif
+#endif /* GL_ARB_debug_output */
+
+#ifndef GL_ARB_depth_buffer_float
+#define GL_ARB_depth_buffer_float 1
+#endif /* GL_ARB_depth_buffer_float */
+
+#ifndef GL_ARB_depth_clamp
+#define GL_ARB_depth_clamp 1
+#endif /* GL_ARB_depth_clamp */
+
+#ifndef GL_ARB_depth_texture
+#define GL_ARB_depth_texture 1
+#define GL_DEPTH_COMPONENT16_ARB 0x81A5
+#define GL_DEPTH_COMPONENT24_ARB 0x81A6
+#define GL_DEPTH_COMPONENT32_ARB 0x81A7
+#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A
+#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B
+#endif /* GL_ARB_depth_texture */
+
+#ifndef GL_ARB_draw_buffers
+#define GL_ARB_draw_buffers 1
+#define GL_MAX_DRAW_BUFFERS_ARB 0x8824
+#define GL_DRAW_BUFFER0_ARB 0x8825
+#define GL_DRAW_BUFFER1_ARB 0x8826
+#define GL_DRAW_BUFFER2_ARB 0x8827
+#define GL_DRAW_BUFFER3_ARB 0x8828
+#define GL_DRAW_BUFFER4_ARB 0x8829
+#define GL_DRAW_BUFFER5_ARB 0x882A
+#define GL_DRAW_BUFFER6_ARB 0x882B
+#define GL_DRAW_BUFFER7_ARB 0x882C
+#define GL_DRAW_BUFFER8_ARB 0x882D
+#define GL_DRAW_BUFFER9_ARB 0x882E
+#define GL_DRAW_BUFFER10_ARB 0x882F
+#define GL_DRAW_BUFFER11_ARB 0x8830
+#define GL_DRAW_BUFFER12_ARB 0x8831
+#define GL_DRAW_BUFFER13_ARB 0x8832
+#define GL_DRAW_BUFFER14_ARB 0x8833
+#define GL_DRAW_BUFFER15_ARB 0x8834
+typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersARB (GLsizei n, const GLenum *bufs);
+#endif
+#endif /* GL_ARB_draw_buffers */
+
+#ifndef GL_ARB_draw_buffers_blend
+#define GL_ARB_draw_buffers_blend 1
+typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode);
+GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst);
+GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+#endif
+#endif /* GL_ARB_draw_buffers_blend */
+
+#ifndef GL_ARB_draw_elements_base_vertex
+#define GL_ARB_draw_elements_base_vertex 1
+#endif /* GL_ARB_draw_elements_base_vertex */
+
+#ifndef GL_ARB_draw_indirect
+#define GL_ARB_draw_indirect 1
+#endif /* GL_ARB_draw_indirect */
+
+#ifndef GL_ARB_draw_instanced
+#define GL_ARB_draw_instanced 1
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+#endif
+#endif /* GL_ARB_draw_instanced */
+
+#ifndef GL_ARB_enhanced_layouts
+#define GL_ARB_enhanced_layouts 1
+#endif /* GL_ARB_enhanced_layouts */
+
+#ifndef GL_ARB_explicit_attrib_location
+#define GL_ARB_explicit_attrib_location 1
+#endif /* GL_ARB_explicit_attrib_location */
+
+#ifndef GL_ARB_explicit_uniform_location
+#define GL_ARB_explicit_uniform_location 1
+#endif /* GL_ARB_explicit_uniform_location */
+
+#ifndef GL_ARB_fragment_coord_conventions
+#define GL_ARB_fragment_coord_conventions 1
+#endif /* GL_ARB_fragment_coord_conventions */
+
+#ifndef GL_ARB_fragment_layer_viewport
+#define GL_ARB_fragment_layer_viewport 1
+#endif /* GL_ARB_fragment_layer_viewport */
+
+#ifndef GL_ARB_fragment_program
+#define GL_ARB_fragment_program 1
+#define GL_FRAGMENT_PROGRAM_ARB 0x8804
+#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875
+#define GL_PROGRAM_LENGTH_ARB 0x8627
+#define GL_PROGRAM_FORMAT_ARB 0x8876
+#define GL_PROGRAM_BINDING_ARB 0x8677
+#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0
+#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1
+#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2
+#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3
+#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4
+#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5
+#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6
+#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7
+#define GL_PROGRAM_PARAMETERS_ARB 0x88A8
+#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9
+#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA
+#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB
+#define GL_PROGRAM_ATTRIBS_ARB 0x88AC
+#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD
+#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE
+#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF
+#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4
+#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5
+#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6
+#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805
+#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806
+#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807
+#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808
+#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809
+#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A
+#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B
+#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C
+#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D
+#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E
+#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F
+#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810
+#define GL_PROGRAM_STRING_ARB 0x8628
+#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B
+#define GL_CURRENT_MATRIX_ARB 0x8641
+#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7
+#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640
+#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F
+#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E
+#define GL_MAX_TEXTURE_COORDS_ARB 0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872
+#define GL_PROGRAM_ERROR_STRING_ARB 0x8874
+#define GL_MATRIX0_ARB 0x88C0
+#define GL_MATRIX1_ARB 0x88C1
+#define GL_MATRIX2_ARB 0x88C2
+#define GL_MATRIX3_ARB 0x88C3
+#define GL_MATRIX4_ARB 0x88C4
+#define GL_MATRIX5_ARB 0x88C5
+#define GL_MATRIX6_ARB 0x88C6
+#define GL_MATRIX7_ARB 0x88C7
+#define GL_MATRIX8_ARB 0x88C8
+#define GL_MATRIX9_ARB 0x88C9
+#define GL_MATRIX10_ARB 0x88CA
+#define GL_MATRIX11_ARB 0x88CB
+#define GL_MATRIX12_ARB 0x88CC
+#define GL_MATRIX13_ARB 0x88CD
+#define GL_MATRIX14_ARB 0x88CE
+#define GL_MATRIX15_ARB 0x88CF
+#define GL_MATRIX16_ARB 0x88D0
+#define GL_MATRIX17_ARB 0x88D1
+#define GL_MATRIX18_ARB 0x88D2
+#define GL_MATRIX19_ARB 0x88D3
+#define GL_MATRIX20_ARB 0x88D4
+#define GL_MATRIX21_ARB 0x88D5
+#define GL_MATRIX22_ARB 0x88D6
+#define GL_MATRIX23_ARB 0x88D7
+#define GL_MATRIX24_ARB 0x88D8
+#define GL_MATRIX25_ARB 0x88D9
+#define GL_MATRIX26_ARB 0x88DA
+#define GL_MATRIX27_ARB 0x88DB
+#define GL_MATRIX28_ARB 0x88DC
+#define GL_MATRIX29_ARB 0x88DD
+#define GL_MATRIX30_ARB 0x88DE
+#define GL_MATRIX31_ARB 0x88DF
+typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string);
+typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const void *string);
+GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program);
+GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs);
+GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs);
+GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params);
+GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params);
+GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params);
+GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params);
+GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params);
+GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params);
+GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params);
+GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params);
+GLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, void *string);
+GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program);
+#endif
+#endif /* GL_ARB_fragment_program */
+
+#ifndef GL_ARB_fragment_program_shadow
+#define GL_ARB_fragment_program_shadow 1
+#endif /* GL_ARB_fragment_program_shadow */
+
+#ifndef GL_ARB_fragment_shader
+#define GL_ARB_fragment_shader 1
+#define GL_FRAGMENT_SHADER_ARB 0x8B30
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
+#endif /* GL_ARB_fragment_shader */
+
+#ifndef GL_ARB_framebuffer_no_attachments
+#define GL_ARB_framebuffer_no_attachments 1
+#endif /* GL_ARB_framebuffer_no_attachments */
+
+#ifndef GL_ARB_framebuffer_object
+#define GL_ARB_framebuffer_object 1
+#endif /* GL_ARB_framebuffer_object */
+
+#ifndef GL_ARB_framebuffer_sRGB
+#define GL_ARB_framebuffer_sRGB 1
+#endif /* GL_ARB_framebuffer_sRGB */
+
+#ifndef GL_KHR_context_flush_control
+#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB
+#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC
+#endif /* GL_KHR_context_flush_control */
+
+#ifndef GL_ARB_geometry_shader4
+#define GL_ARB_geometry_shader4 1
+#define GL_LINES_ADJACENCY_ARB 0x000A
+#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B
+#define GL_TRIANGLES_ADJACENCY_ARB 0x000C
+#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D
+#define GL_PROGRAM_POINT_SIZE_ARB 0x8642
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9
+#define GL_GEOMETRY_SHADER_ARB 0x8DD9
+#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA
+#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB
+#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC
+#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD
+#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value);
+GLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
+#endif
+#endif /* GL_ARB_geometry_shader4 */
+
+#ifndef GL_ARB_get_program_binary
+#define GL_ARB_get_program_binary 1
+#endif /* GL_ARB_get_program_binary */
+
+#ifndef GL_ARB_gpu_shader5
+#define GL_ARB_gpu_shader5 1
+#endif /* GL_ARB_gpu_shader5 */
+
+#ifndef GL_ARB_gpu_shader_fp64
+#define GL_ARB_gpu_shader_fp64 1
+#endif /* GL_ARB_gpu_shader_fp64 */
+
+#ifndef GL_ARB_half_float_pixel
+#define GL_ARB_half_float_pixel 1
+typedef unsigned short GLhalfARB;
+#define GL_HALF_FLOAT_ARB 0x140B
+#endif /* GL_ARB_half_float_pixel */
+
+#ifndef GL_ARB_half_float_vertex
+#define GL_ARB_half_float_vertex 1
+#endif /* GL_ARB_half_float_vertex */
+
+#ifndef GL_ARB_imaging
+#define GL_ARB_imaging 1
+#define GL_BLEND_COLOR 0x8005
+#define GL_BLEND_EQUATION 0x8009
+#define GL_CONVOLUTION_1D 0x8010
+#define GL_CONVOLUTION_2D 0x8011
+#define GL_SEPARABLE_2D 0x8012
+#define GL_CONVOLUTION_BORDER_MODE 0x8013
+#define GL_CONVOLUTION_FILTER_SCALE 0x8014
+#define GL_CONVOLUTION_FILTER_BIAS 0x8015
+#define GL_REDUCE 0x8016
+#define GL_CONVOLUTION_FORMAT 0x8017
+#define GL_CONVOLUTION_WIDTH 0x8018
+#define GL_CONVOLUTION_HEIGHT 0x8019
+#define GL_MAX_CONVOLUTION_WIDTH 0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT 0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE 0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS 0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023
+#define GL_HISTOGRAM 0x8024
+#define GL_PROXY_HISTOGRAM 0x8025
+#define GL_HISTOGRAM_WIDTH 0x8026
+#define GL_HISTOGRAM_FORMAT 0x8027
+#define GL_HISTOGRAM_RED_SIZE 0x8028
+#define GL_HISTOGRAM_GREEN_SIZE 0x8029
+#define GL_HISTOGRAM_BLUE_SIZE 0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE 0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C
+#define GL_HISTOGRAM_SINK 0x802D
+#define GL_MINMAX 0x802E
+#define GL_MINMAX_FORMAT 0x802F
+#define GL_MINMAX_SINK 0x8030
+#define GL_TABLE_TOO_LARGE 0x8031
+#define GL_COLOR_MATRIX 0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB
+#define GL_COLOR_TABLE 0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2
+#define GL_PROXY_COLOR_TABLE 0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5
+#define GL_COLOR_TABLE_SCALE 0x80D6
+#define GL_COLOR_TABLE_BIAS 0x80D7
+#define GL_COLOR_TABLE_FORMAT 0x80D8
+#define GL_COLOR_TABLE_WIDTH 0x80D9
+#define GL_COLOR_TABLE_RED_SIZE 0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE 0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE 0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF
+#define GL_CONSTANT_BORDER 0x8151
+#define GL_REPLICATE_BORDER 0x8153
+#define GL_CONVOLUTION_BORDER_COLOR 0x8154
+typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
+GLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, void *table);
+GLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
+GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
+GLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params);
+GLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params);
+GLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, void *image);
+GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
+GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
+GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+GLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+GLAPI void APIENTRY glMinmax (GLenum target, GLenum internalformat, GLboolean sink);
+GLAPI void APIENTRY glResetHistogram (GLenum target);
+GLAPI void APIENTRY glResetMinmax (GLenum target);
+#endif
+#endif /* GL_ARB_imaging */
+
+#ifndef GL_ARB_indirect_parameters
+#define GL_ARB_indirect_parameters 1
+#define GL_PARAMETER_BUFFER_ARB 0x80EE
+#define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysIndirectCountARB (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+GLAPI void APIENTRY glMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+#endif
+#endif /* GL_ARB_indirect_parameters */
+
+#ifndef GL_ARB_instanced_arrays
+#define GL_ARB_instanced_arrays 1
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE
+typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor);
+#endif
+#endif /* GL_ARB_instanced_arrays */
+
+#ifndef GL_ARB_internalformat_query
+#define GL_ARB_internalformat_query 1
+#endif /* GL_ARB_internalformat_query */
+
+#ifndef GL_ARB_internalformat_query2
+#define GL_ARB_internalformat_query2 1
+#define GL_SRGB_DECODE_ARB 0x8299
+#endif /* GL_ARB_internalformat_query2 */
+
+#ifndef GL_ARB_invalidate_subdata
+#define GL_ARB_invalidate_subdata 1
+#endif /* GL_ARB_invalidate_subdata */
+
+#ifndef GL_ARB_map_buffer_alignment
+#define GL_ARB_map_buffer_alignment 1
+#endif /* GL_ARB_map_buffer_alignment */
+
+#ifndef GL_ARB_map_buffer_range
+#define GL_ARB_map_buffer_range 1
+#endif /* GL_ARB_map_buffer_range */
+
+#ifndef GL_ARB_matrix_palette
+#define GL_ARB_matrix_palette 1
+#define GL_MATRIX_PALETTE_ARB 0x8840
+#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841
+#define GL_MAX_PALETTE_MATRICES_ARB 0x8842
+#define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843
+#define GL_MATRIX_INDEX_ARRAY_ARB 0x8844
+#define GL_CURRENT_MATRIX_INDEX_ARB 0x8845
+#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846
+#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847
+#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848
+#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849
+typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index);
+GLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices);
+GLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices);
+GLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices);
+GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_ARB_matrix_palette */
+
+#ifndef GL_ARB_multi_bind
+#define GL_ARB_multi_bind 1
+#endif /* GL_ARB_multi_bind */
+
+#ifndef GL_ARB_multi_draw_indirect
+#define GL_ARB_multi_draw_indirect 1
+#endif /* GL_ARB_multi_draw_indirect */
+
+#ifndef GL_ARB_multisample
+#define GL_ARB_multisample 1
+#define GL_MULTISAMPLE_ARB 0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F
+#define GL_SAMPLE_COVERAGE_ARB 0x80A0
+#define GL_SAMPLE_BUFFERS_ARB 0x80A8
+#define GL_SAMPLES_ARB 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB
+#define GL_MULTISAMPLE_BIT_ARB 0x20000000
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleCoverageARB (GLfloat value, GLboolean invert);
+#endif
+#endif /* GL_ARB_multisample */
+
+#ifndef GL_ARB_multitexture
+#define GL_ARB_multitexture 1
+#define GL_TEXTURE0_ARB 0x84C0
+#define GL_TEXTURE1_ARB 0x84C1
+#define GL_TEXTURE2_ARB 0x84C2
+#define GL_TEXTURE3_ARB 0x84C3
+#define GL_TEXTURE4_ARB 0x84C4
+#define GL_TEXTURE5_ARB 0x84C5
+#define GL_TEXTURE6_ARB 0x84C6
+#define GL_TEXTURE7_ARB 0x84C7
+#define GL_TEXTURE8_ARB 0x84C8
+#define GL_TEXTURE9_ARB 0x84C9
+#define GL_TEXTURE10_ARB 0x84CA
+#define GL_TEXTURE11_ARB 0x84CB
+#define GL_TEXTURE12_ARB 0x84CC
+#define GL_TEXTURE13_ARB 0x84CD
+#define GL_TEXTURE14_ARB 0x84CE
+#define GL_TEXTURE15_ARB 0x84CF
+#define GL_TEXTURE16_ARB 0x84D0
+#define GL_TEXTURE17_ARB 0x84D1
+#define GL_TEXTURE18_ARB 0x84D2
+#define GL_TEXTURE19_ARB 0x84D3
+#define GL_TEXTURE20_ARB 0x84D4
+#define GL_TEXTURE21_ARB 0x84D5
+#define GL_TEXTURE22_ARB 0x84D6
+#define GL_TEXTURE23_ARB 0x84D7
+#define GL_TEXTURE24_ARB 0x84D8
+#define GL_TEXTURE25_ARB 0x84D9
+#define GL_TEXTURE26_ARB 0x84DA
+#define GL_TEXTURE27_ARB 0x84DB
+#define GL_TEXTURE28_ARB 0x84DC
+#define GL_TEXTURE29_ARB 0x84DD
+#define GL_TEXTURE30_ARB 0x84DE
+#define GL_TEXTURE31_ARB 0x84DF
+#define GL_ACTIVE_TEXTURE_ARB 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1
+#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2
+typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTextureARB (GLenum texture);
+GLAPI void APIENTRY glClientActiveTextureARB (GLenum texture);
+GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum target, GLdouble s);
+GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum target, GLfloat s);
+GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum target, GLint s);
+GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum target, GLshort s);
+GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t);
+GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t);
+GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum target, GLint s, GLint t);
+GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t);
+GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r);
+GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r);
+GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q);
+GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum target, const GLshort *v);
+#endif
+#endif /* GL_ARB_multitexture */
+
+#ifndef GL_ARB_occlusion_query
+#define GL_ARB_occlusion_query 1
+#define GL_QUERY_COUNTER_BITS_ARB 0x8864
+#define GL_CURRENT_QUERY_ARB 0x8865
+#define GL_QUERY_RESULT_ARB 0x8866
+#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867
+#define GL_SAMPLES_PASSED_ARB 0x8914
+typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueriesARB (GLsizei n, GLuint *ids);
+GLAPI void APIENTRY glDeleteQueriesARB (GLsizei n, const GLuint *ids);
+GLAPI GLboolean APIENTRY glIsQueryARB (GLuint id);
+GLAPI void APIENTRY glBeginQueryARB (GLenum target, GLuint id);
+GLAPI void APIENTRY glEndQueryARB (GLenum target);
+GLAPI void APIENTRY glGetQueryivARB (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params);
+#endif
+#endif /* GL_ARB_occlusion_query */
+
+#ifndef GL_ARB_occlusion_query2
+#define GL_ARB_occlusion_query2 1
+#endif /* GL_ARB_occlusion_query2 */
+
+#ifndef GL_ARB_pixel_buffer_object
+#define GL_ARB_pixel_buffer_object 1
+#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF
+#endif /* GL_ARB_pixel_buffer_object */
+
+#ifndef GL_ARB_point_parameters
+#define GL_ARB_point_parameters 1
+#define GL_POINT_SIZE_MIN_ARB 0x8126
+#define GL_POINT_SIZE_MAX_ARB 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128
+#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfARB (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params);
+#endif
+#endif /* GL_ARB_point_parameters */
+
+#ifndef GL_ARB_point_sprite
+#define GL_ARB_point_sprite 1
+#define GL_POINT_SPRITE_ARB 0x8861
+#define GL_COORD_REPLACE_ARB 0x8862
+#endif /* GL_ARB_point_sprite */
+
+#ifndef GL_ARB_program_interface_query
+#define GL_ARB_program_interface_query 1
+#endif /* GL_ARB_program_interface_query */
+
+#ifndef GL_ARB_provoking_vertex
+#define GL_ARB_provoking_vertex 1
+#endif /* GL_ARB_provoking_vertex */
+
+#ifndef GL_ARB_query_buffer_object
+#define GL_ARB_query_buffer_object 1
+#endif /* GL_ARB_query_buffer_object */
+
+#ifndef GL_ARB_robust_buffer_access_behavior
+#define GL_ARB_robust_buffer_access_behavior 1
+#endif /* GL_ARB_robust_buffer_access_behavior */
+
+#ifndef GL_ARB_robustness
+#define GL_ARB_robustness 1
+#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004
+#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
+#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253
+#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254
+#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255
+#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
+#define GL_NO_RESET_NOTIFICATION_ARB 0x8261
+typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void);
+typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img);
+typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img);
+typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
+typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);
+typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);
+typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v);
+typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values);
+typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values);
+typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values);
+typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern);
+typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);
+typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);
+typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);
+typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void);
+GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img);
+GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, void *img);
+GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
+GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
+GLAPI void APIENTRY glGetnMapdvARB (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);
+GLAPI void APIENTRY glGetnMapfvARB (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);
+GLAPI void APIENTRY glGetnMapivARB (GLenum target, GLenum query, GLsizei bufSize, GLint *v);
+GLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *values);
+GLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values);
+GLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values);
+GLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern);
+GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);
+GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);
+GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);
+GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+#endif
+#endif /* GL_ARB_robustness */
+
+#ifndef GL_ARB_robustness_isolation
+#define GL_ARB_robustness_isolation 1
+#endif /* GL_ARB_robustness_isolation */
+
+#ifndef GL_ARB_sample_shading
+#define GL_ARB_sample_shading 1
+#define GL_SAMPLE_SHADING_ARB 0x8C36
+#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37
+typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLfloat value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value);
+#endif
+#endif /* GL_ARB_sample_shading */
+
+#ifndef GL_ARB_sampler_objects
+#define GL_ARB_sampler_objects 1
+#endif /* GL_ARB_sampler_objects */
+
+#ifndef GL_ARB_seamless_cube_map
+#define GL_ARB_seamless_cube_map 1
+#endif /* GL_ARB_seamless_cube_map */
+
+#ifndef GL_ARB_seamless_cubemap_per_texture
+#define GL_ARB_seamless_cubemap_per_texture 1
+#endif /* GL_ARB_seamless_cubemap_per_texture */
+
+#ifndef GL_ARB_separate_shader_objects
+#define GL_ARB_separate_shader_objects 1
+#endif /* GL_ARB_separate_shader_objects */
+
+#ifndef GL_ARB_shader_atomic_counters
+#define GL_ARB_shader_atomic_counters 1
+#endif /* GL_ARB_shader_atomic_counters */
+
+#ifndef GL_ARB_shader_bit_encoding
+#define GL_ARB_shader_bit_encoding 1
+#endif /* GL_ARB_shader_bit_encoding */
+
+#ifndef GL_ARB_shader_draw_parameters
+#define GL_ARB_shader_draw_parameters 1
+#endif /* GL_ARB_shader_draw_parameters */
+
+#ifndef GL_ARB_shader_group_vote
+#define GL_ARB_shader_group_vote 1
+#endif /* GL_ARB_shader_group_vote */
+
+#ifndef GL_ARB_shader_image_load_store
+#define GL_ARB_shader_image_load_store 1
+#endif /* GL_ARB_shader_image_load_store */
+
+#ifndef GL_ARB_shader_image_size
+#define GL_ARB_shader_image_size 1
+#endif /* GL_ARB_shader_image_size */
+
+#ifndef GL_ARB_shader_objects
+#define GL_ARB_shader_objects 1
+#ifdef __APPLE__
+typedef void *GLhandleARB;
+#else
+typedef unsigned int GLhandleARB;
+#endif
+typedef char GLcharARB;
+#define GL_PROGRAM_OBJECT_ARB 0x8B40
+#define GL_SHADER_OBJECT_ARB 0x8B48
+#define GL_OBJECT_TYPE_ARB 0x8B4E
+#define GL_OBJECT_SUBTYPE_ARB 0x8B4F
+#define GL_FLOAT_VEC2_ARB 0x8B50
+#define GL_FLOAT_VEC3_ARB 0x8B51
+#define GL_FLOAT_VEC4_ARB 0x8B52
+#define GL_INT_VEC2_ARB 0x8B53
+#define GL_INT_VEC3_ARB 0x8B54
+#define GL_INT_VEC4_ARB 0x8B55
+#define GL_BOOL_ARB 0x8B56
+#define GL_BOOL_VEC2_ARB 0x8B57
+#define GL_BOOL_VEC3_ARB 0x8B58
+#define GL_BOOL_VEC4_ARB 0x8B59
+#define GL_FLOAT_MAT2_ARB 0x8B5A
+#define GL_FLOAT_MAT3_ARB 0x8B5B
+#define GL_FLOAT_MAT4_ARB 0x8B5C
+#define GL_SAMPLER_1D_ARB 0x8B5D
+#define GL_SAMPLER_2D_ARB 0x8B5E
+#define GL_SAMPLER_3D_ARB 0x8B5F
+#define GL_SAMPLER_CUBE_ARB 0x8B60
+#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61
+#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62
+#define GL_SAMPLER_2D_RECT_ARB 0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64
+#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80
+#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81
+#define GL_OBJECT_LINK_STATUS_ARB 0x8B82
+#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83
+#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84
+#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85
+#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86
+#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87
+#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88
+typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj);
+typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);
+typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length);
+typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void);
+typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);
+typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
+typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj);
+GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname);
+GLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj);
+GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum shaderType);
+GLAPI void APIENTRY glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length);
+GLAPI void APIENTRY glCompileShaderARB (GLhandleARB shaderObj);
+GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void);
+GLAPI void APIENTRY glAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj);
+GLAPI void APIENTRY glLinkProgramARB (GLhandleARB programObj);
+GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB programObj);
+GLAPI void APIENTRY glValidateProgramARB (GLhandleARB programObj);
+GLAPI void APIENTRY glUniform1fARB (GLint location, GLfloat v0);
+GLAPI void APIENTRY glUniform2fARB (GLint location, GLfloat v0, GLfloat v1);
+GLAPI void APIENTRY glUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+GLAPI void APIENTRY glUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLAPI void APIENTRY glUniform1iARB (GLint location, GLint v0);
+GLAPI void APIENTRY glUniform2iARB (GLint location, GLint v0, GLint v1);
+GLAPI void APIENTRY glUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2);
+GLAPI void APIENTRY glUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+GLAPI void APIENTRY glUniform1fvARB (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform2fvARB (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform3fvARB (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform4fvARB (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform1ivARB (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform2ivARB (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform3ivARB (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform4ivARB (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
+GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);
+GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name);
+GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params);
+GLAPI void APIENTRY glGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params);
+GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);
+#endif
+#endif /* GL_ARB_shader_objects */
+
+#ifndef GL_ARB_shader_precision
+#define GL_ARB_shader_precision 1
+#endif /* GL_ARB_shader_precision */
+
+#ifndef GL_ARB_shader_stencil_export
+#define GL_ARB_shader_stencil_export 1
+#endif /* GL_ARB_shader_stencil_export */
+
+#ifndef GL_ARB_shader_storage_buffer_object
+#define GL_ARB_shader_storage_buffer_object 1
+#endif /* GL_ARB_shader_storage_buffer_object */
+
+#ifndef GL_ARB_shader_subroutine
+#define GL_ARB_shader_subroutine 1
+#endif /* GL_ARB_shader_subroutine */
+
+#ifndef GL_ARB_shader_texture_lod
+#define GL_ARB_shader_texture_lod 1
+#endif /* GL_ARB_shader_texture_lod */
+
+#ifndef GL_ARB_shading_language_100
+#define GL_ARB_shading_language_100 1
+#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C
+#endif /* GL_ARB_shading_language_100 */
+
+#ifndef GL_ARB_shading_language_420pack
+#define GL_ARB_shading_language_420pack 1
+#endif /* GL_ARB_shading_language_420pack */
+
+#ifndef GL_ARB_shading_language_include
+#define GL_ARB_shading_language_include 1
+#define GL_SHADER_INCLUDE_ARB 0x8DAE
+#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9
+#define GL_NAMED_STRING_TYPE_ARB 0x8DEA
+typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string);
+typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);
+typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length);
+typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string);
+typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string);
+GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name);
+GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length);
+GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name);
+GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string);
+GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params);
+#endif
+#endif /* GL_ARB_shading_language_include */
+
+#ifndef GL_ARB_shading_language_packing
+#define GL_ARB_shading_language_packing 1
+#endif /* GL_ARB_shading_language_packing */
+
+#ifndef GL_ARB_shadow
+#define GL_ARB_shadow 1
+#define GL_TEXTURE_COMPARE_MODE_ARB 0x884C
+#define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D
+#define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E
+#endif /* GL_ARB_shadow */
+
+#ifndef GL_ARB_shadow_ambient
+#define GL_ARB_shadow_ambient 1
+#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF
+#endif /* GL_ARB_shadow_ambient */
+
+#ifndef GL_ARB_sparse_texture
+#define GL_ARB_sparse_texture 1
+#define GL_TEXTURE_SPARSE_ARB 0x91A6
+#define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB 0x91A7
+#define GL_MIN_SPARSE_LEVEL_ARB 0x919B
+#define GL_NUM_VIRTUAL_PAGE_SIZES_ARB 0x91A8
+#define GL_VIRTUAL_PAGE_SIZE_X_ARB 0x9195
+#define GL_VIRTUAL_PAGE_SIZE_Y_ARB 0x9196
+#define GL_VIRTUAL_PAGE_SIZE_Z_ARB 0x9197
+#define GL_MAX_SPARSE_TEXTURE_SIZE_ARB 0x9198
+#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB 0x9199
+#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB 0x919A
+#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9
+typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident);
+#endif
+#endif /* GL_ARB_sparse_texture */
+
+#ifndef GL_ARB_stencil_texturing
+#define GL_ARB_stencil_texturing 1
+#endif /* GL_ARB_stencil_texturing */
+
+#ifndef GL_ARB_sync
+#define GL_ARB_sync 1
+#endif /* GL_ARB_sync */
+
+#ifndef GL_ARB_tessellation_shader
+#define GL_ARB_tessellation_shader 1
+#endif /* GL_ARB_tessellation_shader */
+
+#ifndef GL_ARB_texture_border_clamp
+#define GL_ARB_texture_border_clamp 1
+#define GL_CLAMP_TO_BORDER_ARB 0x812D
+#endif /* GL_ARB_texture_border_clamp */
+
+#ifndef GL_ARB_texture_buffer_object
+#define GL_ARB_texture_buffer_object 1
+#define GL_TEXTURE_BUFFER_ARB 0x8C2A
+#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B
+#define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C
+#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D
+#define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E
+typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer);
+#endif
+#endif /* GL_ARB_texture_buffer_object */
+
+#ifndef GL_ARB_texture_buffer_object_rgb32
+#define GL_ARB_texture_buffer_object_rgb32 1
+#endif /* GL_ARB_texture_buffer_object_rgb32 */
+
+#ifndef GL_ARB_texture_buffer_range
+#define GL_ARB_texture_buffer_range 1
+#endif /* GL_ARB_texture_buffer_range */
+
+#ifndef GL_ARB_texture_compression
+#define GL_ARB_texture_compression 1
+#define GL_COMPRESSED_ALPHA_ARB 0x84E9
+#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB
+#define GL_COMPRESSED_INTENSITY_ARB 0x84EC
+#define GL_COMPRESSED_RGB_ARB 0x84ED
+#define GL_COMPRESSED_RGBA_ARB 0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0
+#define GL_TEXTURE_COMPRESSED_ARB 0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, void *img);
+#endif
+#endif /* GL_ARB_texture_compression */
+
+#ifndef GL_ARB_texture_compression_bptc
+#define GL_ARB_texture_compression_bptc 1
+#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C
+#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D
+#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E
+#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F
+#endif /* GL_ARB_texture_compression_bptc */
+
+#ifndef GL_ARB_texture_compression_rgtc
+#define GL_ARB_texture_compression_rgtc 1
+#endif /* GL_ARB_texture_compression_rgtc */
+
+#ifndef GL_ARB_texture_cube_map
+#define GL_ARB_texture_cube_map 1
+#define GL_NORMAL_MAP_ARB 0x8511
+#define GL_REFLECTION_MAP_ARB 0x8512
+#define GL_TEXTURE_CUBE_MAP_ARB 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C
+#endif /* GL_ARB_texture_cube_map */
+
+#ifndef GL_ARB_texture_cube_map_array
+#define GL_ARB_texture_cube_map_array 1
+#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A
+#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B
+#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C
+#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D
+#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F
+#endif /* GL_ARB_texture_cube_map_array */
+
+#ifndef GL_ARB_texture_env_add
+#define GL_ARB_texture_env_add 1
+#endif /* GL_ARB_texture_env_add */
+
+#ifndef GL_ARB_texture_env_combine
+#define GL_ARB_texture_env_combine 1
+#define GL_COMBINE_ARB 0x8570
+#define GL_COMBINE_RGB_ARB 0x8571
+#define GL_COMBINE_ALPHA_ARB 0x8572
+#define GL_SOURCE0_RGB_ARB 0x8580
+#define GL_SOURCE1_RGB_ARB 0x8581
+#define GL_SOURCE2_RGB_ARB 0x8582
+#define GL_SOURCE0_ALPHA_ARB 0x8588
+#define GL_SOURCE1_ALPHA_ARB 0x8589
+#define GL_SOURCE2_ALPHA_ARB 0x858A
+#define GL_OPERAND0_RGB_ARB 0x8590
+#define GL_OPERAND1_RGB_ARB 0x8591
+#define GL_OPERAND2_RGB_ARB 0x8592
+#define GL_OPERAND0_ALPHA_ARB 0x8598
+#define GL_OPERAND1_ALPHA_ARB 0x8599
+#define GL_OPERAND2_ALPHA_ARB 0x859A
+#define GL_RGB_SCALE_ARB 0x8573
+#define GL_ADD_SIGNED_ARB 0x8574
+#define GL_INTERPOLATE_ARB 0x8575
+#define GL_SUBTRACT_ARB 0x84E7
+#define GL_CONSTANT_ARB 0x8576
+#define GL_PRIMARY_COLOR_ARB 0x8577
+#define GL_PREVIOUS_ARB 0x8578
+#endif /* GL_ARB_texture_env_combine */
+
+#ifndef GL_ARB_texture_env_crossbar
+#define GL_ARB_texture_env_crossbar 1
+#endif /* GL_ARB_texture_env_crossbar */
+
+#ifndef GL_ARB_texture_env_dot3
+#define GL_ARB_texture_env_dot3 1
+#define GL_DOT3_RGB_ARB 0x86AE
+#define GL_DOT3_RGBA_ARB 0x86AF
+#endif /* GL_ARB_texture_env_dot3 */
+
+#ifndef GL_ARB_texture_float
+#define GL_ARB_texture_float 1
+#define GL_TEXTURE_RED_TYPE_ARB 0x8C10
+#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11
+#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12
+#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13
+#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14
+#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15
+#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16
+#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17
+#define GL_RGBA32F_ARB 0x8814
+#define GL_RGB32F_ARB 0x8815
+#define GL_ALPHA32F_ARB 0x8816
+#define GL_INTENSITY32F_ARB 0x8817
+#define GL_LUMINANCE32F_ARB 0x8818
+#define GL_LUMINANCE_ALPHA32F_ARB 0x8819
+#define GL_RGBA16F_ARB 0x881A
+#define GL_RGB16F_ARB 0x881B
+#define GL_ALPHA16F_ARB 0x881C
+#define GL_INTENSITY16F_ARB 0x881D
+#define GL_LUMINANCE16F_ARB 0x881E
+#define GL_LUMINANCE_ALPHA16F_ARB 0x881F
+#endif /* GL_ARB_texture_float */
+
+#ifndef GL_ARB_texture_gather
+#define GL_ARB_texture_gather 1
+#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E
+#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F
+#define GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB 0x8F9F
+#endif /* GL_ARB_texture_gather */
+
+#ifndef GL_ARB_texture_mirror_clamp_to_edge
+#define GL_ARB_texture_mirror_clamp_to_edge 1
+#endif /* GL_ARB_texture_mirror_clamp_to_edge */
+
+#ifndef GL_ARB_texture_mirrored_repeat
+#define GL_ARB_texture_mirrored_repeat 1
+#define GL_MIRRORED_REPEAT_ARB 0x8370
+#endif /* GL_ARB_texture_mirrored_repeat */
+
+#ifndef GL_ARB_texture_multisample
+#define GL_ARB_texture_multisample 1
+#endif /* GL_ARB_texture_multisample */
+
+#ifndef GL_ARB_texture_non_power_of_two
+#define GL_ARB_texture_non_power_of_two 1
+#endif /* GL_ARB_texture_non_power_of_two */
+
+#ifndef GL_ARB_texture_query_levels
+#define GL_ARB_texture_query_levels 1
+#endif /* GL_ARB_texture_query_levels */
+
+#ifndef GL_ARB_texture_query_lod
+#define GL_ARB_texture_query_lod 1
+#endif /* GL_ARB_texture_query_lod */
+
+#ifndef GL_ARB_texture_rectangle
+#define GL_ARB_texture_rectangle 1
+#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+#endif /* GL_ARB_texture_rectangle */
+
+#ifndef GL_ARB_texture_rg
+#define GL_ARB_texture_rg 1
+#endif /* GL_ARB_texture_rg */
+
+#ifndef GL_ARB_texture_rgb10_a2ui
+#define GL_ARB_texture_rgb10_a2ui 1
+#endif /* GL_ARB_texture_rgb10_a2ui */
+
+#ifndef GL_ARB_texture_stencil8
+#define GL_ARB_texture_stencil8 1
+#endif /* GL_ARB_texture_stencil8 */
+
+#ifndef GL_ARB_texture_storage
+#define GL_ARB_texture_storage 1
+#endif /* GL_ARB_texture_storage */
+
+#ifndef GL_ARB_texture_storage_multisample
+#define GL_ARB_texture_storage_multisample 1
+#endif /* GL_ARB_texture_storage_multisample */
+
+#ifndef GL_ARB_texture_swizzle
+#define GL_ARB_texture_swizzle 1
+#endif /* GL_ARB_texture_swizzle */
+
+#ifndef GL_ARB_texture_view
+#define GL_ARB_texture_view 1
+#endif /* GL_ARB_texture_view */
+
+#ifndef GL_ARB_timer_query
+#define GL_ARB_timer_query 1
+#endif /* GL_ARB_timer_query */
+
+#ifndef GL_ARB_transform_feedback2
+#define GL_ARB_transform_feedback2 1
+#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23
+#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24
+#endif /* GL_ARB_transform_feedback2 */
+
+#ifndef GL_ARB_transform_feedback3
+#define GL_ARB_transform_feedback3 1
+#endif /* GL_ARB_transform_feedback3 */
+
+#ifndef GL_ARB_transform_feedback_instanced
+#define GL_ARB_transform_feedback_instanced 1
+#endif /* GL_ARB_transform_feedback_instanced */
+
+#ifndef GL_ARB_transpose_matrix
+#define GL_ARB_transpose_matrix 1
+#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *m);
+GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *m);
+GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *m);
+GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m);
+#endif
+#endif /* GL_ARB_transpose_matrix */
+
+#ifndef GL_ARB_uniform_buffer_object
+#define GL_ARB_uniform_buffer_object 1
+#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C
+#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45
+#endif /* GL_ARB_uniform_buffer_object */
+
+#ifndef GL_ARB_vertex_array_bgra
+#define GL_ARB_vertex_array_bgra 1
+#endif /* GL_ARB_vertex_array_bgra */
+
+#ifndef GL_ARB_vertex_array_object
+#define GL_ARB_vertex_array_object 1
+#endif /* GL_ARB_vertex_array_object */
+
+#ifndef GL_ARB_vertex_attrib_64bit
+#define GL_ARB_vertex_attrib_64bit 1
+#endif /* GL_ARB_vertex_attrib_64bit */
+
+#ifndef GL_ARB_vertex_attrib_binding
+#define GL_ARB_vertex_attrib_binding 1
+#endif /* GL_ARB_vertex_attrib_binding */
+
+#ifndef GL_ARB_vertex_blend
+#define GL_ARB_vertex_blend 1
+#define GL_MAX_VERTEX_UNITS_ARB 0x86A4
+#define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5
+#define GL_WEIGHT_SUM_UNITY_ARB 0x86A6
+#define GL_VERTEX_BLEND_ARB 0x86A7
+#define GL_CURRENT_WEIGHT_ARB 0x86A8
+#define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9
+#define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA
+#define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB
+#define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC
+#define GL_WEIGHT_ARRAY_ARB 0x86AD
+#define GL_MODELVIEW0_ARB 0x1700
+#define GL_MODELVIEW1_ARB 0x850A
+#define GL_MODELVIEW2_ARB 0x8722
+#define GL_MODELVIEW3_ARB 0x8723
+#define GL_MODELVIEW4_ARB 0x8724
+#define GL_MODELVIEW5_ARB 0x8725
+#define GL_MODELVIEW6_ARB 0x8726
+#define GL_MODELVIEW7_ARB 0x8727
+#define GL_MODELVIEW8_ARB 0x8728
+#define GL_MODELVIEW9_ARB 0x8729
+#define GL_MODELVIEW10_ARB 0x872A
+#define GL_MODELVIEW11_ARB 0x872B
+#define GL_MODELVIEW12_ARB 0x872C
+#define GL_MODELVIEW13_ARB 0x872D
+#define GL_MODELVIEW14_ARB 0x872E
+#define GL_MODELVIEW15_ARB 0x872F
+#define GL_MODELVIEW16_ARB 0x8730
+#define GL_MODELVIEW17_ARB 0x8731
+#define GL_MODELVIEW18_ARB 0x8732
+#define GL_MODELVIEW19_ARB 0x8733
+#define GL_MODELVIEW20_ARB 0x8734
+#define GL_MODELVIEW21_ARB 0x8735
+#define GL_MODELVIEW22_ARB 0x8736
+#define GL_MODELVIEW23_ARB 0x8737
+#define GL_MODELVIEW24_ARB 0x8738
+#define GL_MODELVIEW25_ARB 0x8739
+#define GL_MODELVIEW26_ARB 0x873A
+#define GL_MODELVIEW27_ARB 0x873B
+#define GL_MODELVIEW28_ARB 0x873C
+#define GL_MODELVIEW29_ARB 0x873D
+#define GL_MODELVIEW30_ARB 0x873E
+#define GL_MODELVIEW31_ARB 0x873F
+typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
+typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights);
+GLAPI void APIENTRY glWeightsvARB (GLint size, const GLshort *weights);
+GLAPI void APIENTRY glWeightivARB (GLint size, const GLint *weights);
+GLAPI void APIENTRY glWeightfvARB (GLint size, const GLfloat *weights);
+GLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights);
+GLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights);
+GLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights);
+GLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights);
+GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glVertexBlendARB (GLint count);
+#endif
+#endif /* GL_ARB_vertex_blend */
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_ARB_vertex_buffer_object 1
+#ifdef __MACOSX__ /* The OS X headers haven't caught up with Khronos yet */
+typedef long GLsizeiptrARB;
+typedef long GLintptrARB;
+#else
+typedef ptrdiff_t GLsizeiptrARB;
+typedef ptrdiff_t GLintptrARB;
+#endif
+#define GL_BUFFER_SIZE_ARB 0x8764
+#define GL_BUFFER_USAGE_ARB 0x8765
+#define GL_ARRAY_BUFFER_ARB 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893
+#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
+#define GL_READ_ONLY_ARB 0x88B8
+#define GL_WRITE_ONLY_ARB 0x88B9
+#define GL_READ_WRITE_ARB 0x88BA
+#define GL_BUFFER_ACCESS_ARB 0x88BB
+#define GL_BUFFER_MAPPED_ARB 0x88BC
+#define GL_BUFFER_MAP_POINTER_ARB 0x88BD
+#define GL_STREAM_DRAW_ARB 0x88E0
+#define GL_STREAM_READ_ARB 0x88E1
+#define GL_STREAM_COPY_ARB 0x88E2
+#define GL_STATIC_DRAW_ARB 0x88E4
+#define GL_STATIC_READ_ARB 0x88E5
+#define GL_STATIC_COPY_ARB 0x88E6
+#define GL_DYNAMIC_DRAW_ARB 0x88E8
+#define GL_DYNAMIC_READ_ARB 0x88E9
+#define GL_DYNAMIC_COPY_ARB 0x88EA
+typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data);
+typedef void *(APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer);
+GLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers);
+GLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers);
+GLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer);
+GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage);
+GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data);
+GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data);
+GLAPI void *APIENTRY glMapBufferARB (GLenum target, GLenum access);
+GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target);
+GLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, void **params);
+#endif
+#endif /* GL_ARB_vertex_buffer_object */
+
+#ifndef GL_ARB_vertex_program
+#define GL_ARB_vertex_program 1
+#define GL_COLOR_SUM_ARB 0x8458
+#define GL_VERTEX_PROGRAM_ARB 0x8620
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625
+#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626
+#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645
+#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A
+#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0
+#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1
+#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2
+#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x);
+GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib1fARB (GLuint index, GLfloat x);
+GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib1sARB (GLuint index, GLshort x);
+GLAPI void APIENTRY glVertexAttrib1svARB (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y);
+GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib2sARB (GLuint index, GLshort x, GLshort y);
+GLAPI void APIENTRY glVertexAttrib2svARB (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glVertexAttrib3svARB (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index);
+GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index);
+GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, void **pointer);
+#endif
+#endif /* GL_ARB_vertex_program */
+
+#ifndef GL_ARB_vertex_shader
+#define GL_ARB_vertex_shader 1
+#define GL_VERTEX_SHADER_ARB 0x8B31
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A
+#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D
+#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89
+#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name);
+GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name);
+#endif
+#endif /* GL_ARB_vertex_shader */
+
+#ifndef GL_ARB_vertex_type_10f_11f_11f_rev
+#define GL_ARB_vertex_type_10f_11f_11f_rev 1
+#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */
+
+#ifndef GL_ARB_vertex_type_2_10_10_10_rev
+#define GL_ARB_vertex_type_2_10_10_10_rev 1
+#endif /* GL_ARB_vertex_type_2_10_10_10_rev */
+
+#ifndef GL_ARB_viewport_array
+#define GL_ARB_viewport_array 1
+#endif /* GL_ARB_viewport_array */
+
+#ifndef GL_ARB_window_pos
+#define GL_ARB_window_pos 1
+typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dARB (GLdouble x, GLdouble y);
+GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos2fARB (GLfloat x, GLfloat y);
+GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos2iARB (GLint x, GLint y);
+GLAPI void APIENTRY glWindowPos2ivARB (const GLint *v);
+GLAPI void APIENTRY glWindowPos2sARB (GLshort x, GLshort y);
+GLAPI void APIENTRY glWindowPos2svARB (const GLshort *v);
+GLAPI void APIENTRY glWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos3iARB (GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glWindowPos3ivARB (const GLint *v);
+GLAPI void APIENTRY glWindowPos3sARB (GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v);
+#endif
+#endif /* GL_ARB_window_pos */
+
+#ifndef GL_KHR_debug
+#define GL_KHR_debug 1
+#endif /* GL_KHR_debug */
+
+#ifndef GL_KHR_texture_compression_astc_hdr
+#define GL_KHR_texture_compression_astc_hdr 1
+#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0
+#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1
+#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2
+#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3
+#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4
+#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5
+#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6
+#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7
+#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8
+#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9
+#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA
+#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB
+#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC
+#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD
+#endif /* GL_KHR_texture_compression_astc_hdr */
+
+#ifndef GL_KHR_texture_compression_astc_ldr
+#define GL_KHR_texture_compression_astc_ldr 1
+#endif /* GL_KHR_texture_compression_astc_ldr */
+
+#ifndef GL_OES_byte_coordinates
+#define GL_OES_byte_coordinates 1
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD1BOESPROC) (GLbyte s);
+typedef void (APIENTRYP PFNGLTEXCOORD1BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t);
+typedef void (APIENTRYP PFNGLTEXCOORD2BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r);
+typedef void (APIENTRYP PFNGLTEXCOORD3BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q);
+typedef void (APIENTRYP PFNGLTEXCOORD4BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLVERTEX2BOESPROC) (GLbyte x);
+typedef void (APIENTRYP PFNGLVERTEX2BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLVERTEX3BOESPROC) (GLbyte x, GLbyte y);
+typedef void (APIENTRYP PFNGLVERTEX3BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z);
+typedef void (APIENTRYP PFNGLVERTEX4BVOESPROC) (const GLbyte *coords);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiTexCoord1bOES (GLenum texture, GLbyte s);
+GLAPI void APIENTRY glMultiTexCoord1bvOES (GLenum texture, const GLbyte *coords);
+GLAPI void APIENTRY glMultiTexCoord2bOES (GLenum texture, GLbyte s, GLbyte t);
+GLAPI void APIENTRY glMultiTexCoord2bvOES (GLenum texture, const GLbyte *coords);
+GLAPI void APIENTRY glMultiTexCoord3bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r);
+GLAPI void APIENTRY glMultiTexCoord3bvOES (GLenum texture, const GLbyte *coords);
+GLAPI void APIENTRY glMultiTexCoord4bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q);
+GLAPI void APIENTRY glMultiTexCoord4bvOES (GLenum texture, const GLbyte *coords);
+GLAPI void APIENTRY glTexCoord1bOES (GLbyte s);
+GLAPI void APIENTRY glTexCoord1bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glTexCoord2bOES (GLbyte s, GLbyte t);
+GLAPI void APIENTRY glTexCoord2bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glTexCoord3bOES (GLbyte s, GLbyte t, GLbyte r);
+GLAPI void APIENTRY glTexCoord3bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glTexCoord4bOES (GLbyte s, GLbyte t, GLbyte r, GLbyte q);
+GLAPI void APIENTRY glTexCoord4bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glVertex2bOES (GLbyte x);
+GLAPI void APIENTRY glVertex2bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glVertex3bOES (GLbyte x, GLbyte y);
+GLAPI void APIENTRY glVertex3bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glVertex4bOES (GLbyte x, GLbyte y, GLbyte z);
+GLAPI void APIENTRY glVertex4bvOES (const GLbyte *coords);
+#endif
+#endif /* GL_OES_byte_coordinates */
+
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+#endif /* GL_OES_compressed_paletted_texture */
+
+#ifndef GL_OES_fixed_point
+#define GL_OES_fixed_point 1
+typedef GLint GLfixed;
+#define GL_FIXED_OES 0x140C
+typedef void (APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref);
+typedef void (APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLfixed depth);
+typedef void (APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation);
+typedef void (APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f);
+typedef void (APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *param);
+typedef void (APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+typedef void (APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation);
+typedef void (APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param);
+typedef void (APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width);
+typedef void (APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param);
+typedef void (APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+typedef void (APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz);
+typedef void (APIENTRYP PFNGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size);
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units);
+typedef void (APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEOESPROC) (GLfixed value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP PFNGLACCUMXOESPROC) (GLenum op, GLfixed value);
+typedef void (APIENTRYP PFNGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap);
+typedef void (APIENTRYP PFNGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP PFNGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP PFNGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue);
+typedef void (APIENTRYP PFNGLCOLOR3XVOESPROC) (const GLfixed *components);
+typedef void (APIENTRYP PFNGLCOLOR4XVOESPROC) (const GLfixed *components);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLEVALCOORD1XOESPROC) (GLfixed u);
+typedef void (APIENTRYP PFNGLEVALCOORD1XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v);
+typedef void (APIENTRYP PFNGLEVALCOORD2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v);
+typedef void (APIENTRYP PFNGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values);
+typedef void (APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLINDEXXOESPROC) (GLfixed component);
+typedef void (APIENTRYP PFNGLINDEXXVOESPROC) (const GLfixed *component);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP PFNGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points);
+typedef void (APIENTRYP PFNGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points);
+typedef void (APIENTRYP PFNGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2);
+typedef void (APIENTRYP PFNGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP PFNGLNORMAL3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLPASSTHROUGHXOESPROC) (GLfixed token);
+typedef void (APIENTRYP PFNGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values);
+typedef void (APIENTRYP PFNGLPIXELSTOREXPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor);
+typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities);
+typedef void (APIENTRYP PFNGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y);
+typedef void (APIENTRYP PFNGLRASTERPOS2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP PFNGLRASTERPOS3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w);
+typedef void (APIENTRYP PFNGLRASTERPOS4XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2);
+typedef void (APIENTRYP PFNGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2);
+typedef void (APIENTRYP PFNGLTEXCOORD1XOESPROC) (GLfixed s);
+typedef void (APIENTRYP PFNGLTEXCOORD1XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t);
+typedef void (APIENTRYP PFNGLTEXCOORD2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r);
+typedef void (APIENTRYP PFNGLTEXCOORD3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+typedef void (APIENTRYP PFNGLTEXCOORD4XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLVERTEX2XOESPROC) (GLfixed x);
+typedef void (APIENTRYP PFNGLVERTEX2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLVERTEX3XOESPROC) (GLfixed x, GLfixed y);
+typedef void (APIENTRYP PFNGLVERTEX3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP PFNGLVERTEX4XVOESPROC) (const GLfixed *coords);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glAlphaFuncxOES (GLenum func, GLfixed ref);
+GLAPI void APIENTRY glClearColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GLAPI void APIENTRY glClearDepthxOES (GLfixed depth);
+GLAPI void APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation);
+GLAPI void APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GLAPI void APIENTRY glDepthRangexOES (GLfixed n, GLfixed f);
+GLAPI void APIENTRY glFogxOES (GLenum pname, GLfixed param);
+GLAPI void APIENTRY glFogxvOES (GLenum pname, const GLfixed *param);
+GLAPI void APIENTRY glFrustumxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+GLAPI void APIENTRY glGetClipPlanexOES (GLenum plane, GLfixed *equation);
+GLAPI void APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetTexEnvxvOES (GLenum target, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glLightModelxOES (GLenum pname, GLfixed param);
+GLAPI void APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *param);
+GLAPI void APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glLineWidthxOES (GLfixed width);
+GLAPI void APIENTRY glLoadMatrixxOES (const GLfixed *m);
+GLAPI void APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *param);
+GLAPI void APIENTRY glMultMatrixxOES (const GLfixed *m);
+GLAPI void APIENTRY glMultiTexCoord4xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GLAPI void APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz);
+GLAPI void APIENTRY glOrthoxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+GLAPI void APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glPointSizexOES (GLfixed size);
+GLAPI void APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units);
+GLAPI void APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glSampleCoverageOES (GLfixed value, GLboolean invert);
+GLAPI void APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glAccumxOES (GLenum op, GLfixed value);
+GLAPI void APIENTRY glBitmapxOES (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap);
+GLAPI void APIENTRY glBlendColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GLAPI void APIENTRY glClearAccumxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GLAPI void APIENTRY glColor3xOES (GLfixed red, GLfixed green, GLfixed blue);
+GLAPI void APIENTRY glColor3xvOES (const GLfixed *components);
+GLAPI void APIENTRY glColor4xvOES (const GLfixed *components);
+GLAPI void APIENTRY glConvolutionParameterxOES (GLenum target, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glConvolutionParameterxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glEvalCoord1xOES (GLfixed u);
+GLAPI void APIENTRY glEvalCoord1xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glEvalCoord2xOES (GLfixed u, GLfixed v);
+GLAPI void APIENTRY glEvalCoord2xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glFeedbackBufferxOES (GLsizei n, GLenum type, const GLfixed *buffer);
+GLAPI void APIENTRY glGetConvolutionParameterxvOES (GLenum target, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetHistogramParameterxvOES (GLenum target, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetLightxOES (GLenum light, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetMapxvOES (GLenum target, GLenum query, GLfixed *v);
+GLAPI void APIENTRY glGetMaterialxOES (GLenum face, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glGetPixelMapxv (GLenum map, GLint size, GLfixed *values);
+GLAPI void APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetTexLevelParameterxvOES (GLenum target, GLint level, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glIndexxOES (GLfixed component);
+GLAPI void APIENTRY glIndexxvOES (const GLfixed *component);
+GLAPI void APIENTRY glLoadTransposeMatrixxOES (const GLfixed *m);
+GLAPI void APIENTRY glMap1xOES (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points);
+GLAPI void APIENTRY glMap2xOES (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points);
+GLAPI void APIENTRY glMapGrid1xOES (GLint n, GLfixed u1, GLfixed u2);
+GLAPI void APIENTRY glMapGrid2xOES (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2);
+GLAPI void APIENTRY glMultTransposeMatrixxOES (const GLfixed *m);
+GLAPI void APIENTRY glMultiTexCoord1xOES (GLenum texture, GLfixed s);
+GLAPI void APIENTRY glMultiTexCoord1xvOES (GLenum texture, const GLfixed *coords);
+GLAPI void APIENTRY glMultiTexCoord2xOES (GLenum texture, GLfixed s, GLfixed t);
+GLAPI void APIENTRY glMultiTexCoord2xvOES (GLenum texture, const GLfixed *coords);
+GLAPI void APIENTRY glMultiTexCoord3xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r);
+GLAPI void APIENTRY glMultiTexCoord3xvOES (GLenum texture, const GLfixed *coords);
+GLAPI void APIENTRY glMultiTexCoord4xvOES (GLenum texture, const GLfixed *coords);
+GLAPI void APIENTRY glNormal3xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glPassThroughxOES (GLfixed token);
+GLAPI void APIENTRY glPixelMapx (GLenum map, GLint size, const GLfixed *values);
+GLAPI void APIENTRY glPixelStorex (GLenum pname, GLfixed param);
+GLAPI void APIENTRY glPixelTransferxOES (GLenum pname, GLfixed param);
+GLAPI void APIENTRY glPixelZoomxOES (GLfixed xfactor, GLfixed yfactor);
+GLAPI void APIENTRY glPrioritizeTexturesxOES (GLsizei n, const GLuint *textures, const GLfixed *priorities);
+GLAPI void APIENTRY glRasterPos2xOES (GLfixed x, GLfixed y);
+GLAPI void APIENTRY glRasterPos2xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glRasterPos3xOES (GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glRasterPos3xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glRasterPos4xOES (GLfixed x, GLfixed y, GLfixed z, GLfixed w);
+GLAPI void APIENTRY glRasterPos4xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glRectxOES (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2);
+GLAPI void APIENTRY glRectxvOES (const GLfixed *v1, const GLfixed *v2);
+GLAPI void APIENTRY glTexCoord1xOES (GLfixed s);
+GLAPI void APIENTRY glTexCoord1xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glTexCoord2xOES (GLfixed s, GLfixed t);
+GLAPI void APIENTRY glTexCoord2xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glTexCoord3xOES (GLfixed s, GLfixed t, GLfixed r);
+GLAPI void APIENTRY glTexCoord3xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glTexCoord4xOES (GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GLAPI void APIENTRY glTexCoord4xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glVertex2xOES (GLfixed x);
+GLAPI void APIENTRY glVertex2xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glVertex3xOES (GLfixed x, GLfixed y);
+GLAPI void APIENTRY glVertex3xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glVertex4xOES (GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glVertex4xvOES (const GLfixed *coords);
+#endif
+#endif /* GL_OES_fixed_point */
+
+#ifndef GL_OES_query_matrix
+#define GL_OES_query_matrix 1
+typedef GLbitfield (APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLbitfield APIENTRY glQueryMatrixxOES (GLfixed *mantissa, GLint *exponent);
+#endif
+#endif /* GL_OES_query_matrix */
+
+#ifndef GL_OES_read_format
+#define GL_OES_read_format 1
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
+#endif /* GL_OES_read_format */
+
+#ifndef GL_OES_single_precision
+#define GL_OES_single_precision 1
+typedef void (APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth);
+typedef void (APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);
+typedef void (APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f);
+typedef void (APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+typedef void (APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation);
+typedef void (APIENTRYP PFNGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glClearDepthfOES (GLclampf depth);
+GLAPI void APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation);
+GLAPI void APIENTRY glDepthRangefOES (GLclampf n, GLclampf f);
+GLAPI void APIENTRY glFrustumfOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+GLAPI void APIENTRY glGetClipPlanefOES (GLenum plane, GLfloat *equation);
+GLAPI void APIENTRY glOrthofOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+#endif
+#endif /* GL_OES_single_precision */
+
+#ifndef GL_3DFX_multisample
+#define GL_3DFX_multisample 1
+#define GL_MULTISAMPLE_3DFX 0x86B2
+#define GL_SAMPLE_BUFFERS_3DFX 0x86B3
+#define GL_SAMPLES_3DFX 0x86B4
+#define GL_MULTISAMPLE_BIT_3DFX 0x20000000
+#endif /* GL_3DFX_multisample */
+
+#ifndef GL_3DFX_tbuffer
+#define GL_3DFX_tbuffer 1
+typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTbufferMask3DFX (GLuint mask);
+#endif
+#endif /* GL_3DFX_tbuffer */
+
+#ifndef GL_3DFX_texture_compression_FXT1
+#define GL_3DFX_texture_compression_FXT1 1
+#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
+#define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1
+#endif /* GL_3DFX_texture_compression_FXT1 */
+
+#ifndef GL_AMD_blend_minmax_factor
+#define GL_AMD_blend_minmax_factor 1
+#define GL_FACTOR_MIN_AMD 0x901C
+#define GL_FACTOR_MAX_AMD 0x901D
+#endif /* GL_AMD_blend_minmax_factor */
+
+#ifndef GL_AMD_conservative_depth
+#define GL_AMD_conservative_depth 1
+#endif /* GL_AMD_conservative_depth */
+
+#ifndef GL_AMD_debug_output
+#define GL_AMD_debug_output 1
+typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
+#define GL_MAX_DEBUG_MESSAGE_LENGTH_AMD 0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144
+#define GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145
+#define GL_DEBUG_SEVERITY_HIGH_AMD 0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147
+#define GL_DEBUG_SEVERITY_LOW_AMD 0x9148
+#define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149
+#define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A
+#define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B
+#define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C
+#define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D
+#define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E
+#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F
+#define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void *userParam);
+typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf);
+GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, void *userParam);
+GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
+#endif
+#endif /* GL_AMD_debug_output */
+
+#ifndef GL_AMD_depth_clamp_separate
+#define GL_AMD_depth_clamp_separate 1
+#define GL_DEPTH_CLAMP_NEAR_AMD 0x901E
+#define GL_DEPTH_CLAMP_FAR_AMD 0x901F
+#endif /* GL_AMD_depth_clamp_separate */
+
+#ifndef GL_AMD_draw_buffers_blend
+#define GL_AMD_draw_buffers_blend 1
+typedef void (APIENTRYP PFNGLBLENDFUNCINDEXEDAMDPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONINDEXEDAMDPROC) (GLuint buf, GLenum mode);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncIndexedAMD (GLuint buf, GLenum src, GLenum dst);
+GLAPI void APIENTRY glBlendFuncSeparateIndexedAMD (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GLAPI void APIENTRY glBlendEquationIndexedAMD (GLuint buf, GLenum mode);
+GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+#endif
+#endif /* GL_AMD_draw_buffers_blend */
+
+#ifndef GL_AMD_gcn_shader
+#define GL_AMD_gcn_shader 1
+#endif /* GL_AMD_gcn_shader */
+
+#ifndef GL_AMD_gpu_shader_int64
+#define GL_AMD_gpu_shader_int64 1
+typedef int64_t GLint64EXT;
+#define GL_INT64_NV 0x140E
+#define GL_UNSIGNED_INT64_NV 0x140F
+#define GL_INT8_NV 0x8FE0
+#define GL_INT8_VEC2_NV 0x8FE1
+#define GL_INT8_VEC3_NV 0x8FE2
+#define GL_INT8_VEC4_NV 0x8FE3
+#define GL_INT16_NV 0x8FE4
+#define GL_INT16_VEC2_NV 0x8FE5
+#define GL_INT16_VEC3_NV 0x8FE6
+#define GL_INT16_VEC4_NV 0x8FE7
+#define GL_INT64_VEC2_NV 0x8FE9
+#define GL_INT64_VEC3_NV 0x8FEA
+#define GL_INT64_VEC4_NV 0x8FEB
+#define GL_UNSIGNED_INT8_NV 0x8FEC
+#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED
+#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE
+#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF
+#define GL_UNSIGNED_INT16_NV 0x8FF0
+#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1
+#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2
+#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3
+#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5
+#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6
+#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7
+#define GL_FLOAT16_NV 0x8FF8
+#define GL_FLOAT16_VEC2_NV 0x8FF9
+#define GL_FLOAT16_VEC3_NV 0x8FFA
+#define GL_FLOAT16_VEC4_NV 0x8FFB
+typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x);
+typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y);
+typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x);
+typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y);
+typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x);
+GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y);
+GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x);
+GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y);
+GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params);
+GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params);
+GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x);
+GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y);
+GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x);
+GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y);
+GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+#endif
+#endif /* GL_AMD_gpu_shader_int64 */
+
+#ifndef GL_AMD_interleaved_elements
+#define GL_AMD_interleaved_elements 1
+#define GL_VERTEX_ELEMENT_SWIZZLE_AMD 0x91A4
+#define GL_VERTEX_ID_SWIZZLE_AMD 0x91A5
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPARAMETERIAMDPROC) (GLuint index, GLenum pname, GLint param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribParameteriAMD (GLuint index, GLenum pname, GLint param);
+#endif
+#endif /* GL_AMD_interleaved_elements */
+
+#ifndef GL_AMD_multi_draw_indirect
+#define GL_AMD_multi_draw_indirect 1
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride);
+GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride);
+#endif
+#endif /* GL_AMD_multi_draw_indirect */
+
+#ifndef GL_AMD_name_gen_delete
+#define GL_AMD_name_gen_delete 1
+#define GL_DATA_BUFFER_AMD 0x9151
+#define GL_PERFORMANCE_MONITOR_AMD 0x9152
+#define GL_QUERY_OBJECT_AMD 0x9153
+#define GL_VERTEX_ARRAY_OBJECT_AMD 0x9154
+#define GL_SAMPLER_OBJECT_AMD 0x9155
+typedef void (APIENTRYP PFNGLGENNAMESAMDPROC) (GLenum identifier, GLuint num, GLuint *names);
+typedef void (APIENTRYP PFNGLDELETENAMESAMDPROC) (GLenum identifier, GLuint num, const GLuint *names);
+typedef GLboolean (APIENTRYP PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint name);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenNamesAMD (GLenum identifier, GLuint num, GLuint *names);
+GLAPI void APIENTRY glDeleteNamesAMD (GLenum identifier, GLuint num, const GLuint *names);
+GLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name);
+#endif
+#endif /* GL_AMD_name_gen_delete */
+
+#ifndef GL_AMD_occlusion_query_event
+#define GL_AMD_occlusion_query_event 1
+#define GL_OCCLUSION_QUERY_EVENT_MASK_AMD 0x874F
+#define GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD 0x00000001
+#define GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD 0x00000002
+#define GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD 0x00000004
+#define GL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD 0x00000008
+#define GL_QUERY_ALL_EVENT_BITS_AMD 0xFFFFFFFF
+typedef void (APIENTRYP PFNGLQUERYOBJECTPARAMETERUIAMDPROC) (GLenum target, GLuint id, GLenum pname, GLuint param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glQueryObjectParameteruiAMD (GLenum target, GLuint id, GLenum pname, GLuint param);
+#endif
+#endif /* GL_AMD_occlusion_query_event */
+
+#ifndef GL_AMD_performance_monitor
+#define GL_AMD_performance_monitor 1
+#define GL_COUNTER_TYPE_AMD 0x8BC0
+#define GL_COUNTER_RANGE_AMD 0x8BC1
+#define GL_UNSIGNED_INT64_AMD 0x8BC2
+#define GL_PERCENTAGE_AMD 0x8BC3
+#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4
+#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5
+#define GL_PERFMON_RESULT_AMD 0x8BC6
+typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data);
+typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList);
+typedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data);
+GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList);
+GLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
+GLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor);
+GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+#endif /* GL_AMD_performance_monitor */
+
+#ifndef GL_AMD_pinned_memory
+#define GL_AMD_pinned_memory 1
+#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160
+#endif /* GL_AMD_pinned_memory */
+
+#ifndef GL_AMD_query_buffer_object
+#define GL_AMD_query_buffer_object 1
+#define GL_QUERY_BUFFER_AMD 0x9192
+#define GL_QUERY_BUFFER_BINDING_AMD 0x9193
+#define GL_QUERY_RESULT_NO_WAIT_AMD 0x9194
+#endif /* GL_AMD_query_buffer_object */
+
+#ifndef GL_AMD_sample_positions
+#define GL_AMD_sample_positions 1
+#define GL_SUBSAMPLE_DISTANCE_AMD 0x883F
+typedef void (APIENTRYP PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint index, const GLfloat *val);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLfloat *val);
+#endif
+#endif /* GL_AMD_sample_positions */
+
+#ifndef GL_AMD_seamless_cubemap_per_texture
+#define GL_AMD_seamless_cubemap_per_texture 1
+#endif /* GL_AMD_seamless_cubemap_per_texture */
+
+#ifndef GL_AMD_shader_atomic_counter_ops
+#define GL_AMD_shader_atomic_counter_ops 1
+#endif /* GL_AMD_shader_atomic_counter_ops */
+
+#ifndef GL_AMD_shader_stencil_export
+#define GL_AMD_shader_stencil_export 1
+#endif /* GL_AMD_shader_stencil_export */
+
+#ifndef GL_AMD_shader_trinary_minmax
+#define GL_AMD_shader_trinary_minmax 1
+#endif /* GL_AMD_shader_trinary_minmax */
+
+#ifndef GL_AMD_sparse_texture
+#define GL_AMD_sparse_texture 1
+#define GL_VIRTUAL_PAGE_SIZE_X_AMD 0x9195
+#define GL_VIRTUAL_PAGE_SIZE_Y_AMD 0x9196
+#define GL_VIRTUAL_PAGE_SIZE_Z_AMD 0x9197
+#define GL_MAX_SPARSE_TEXTURE_SIZE_AMD 0x9198
+#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD 0x9199
+#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS 0x919A
+#define GL_MIN_SPARSE_LEVEL_AMD 0x919B
+#define GL_MIN_LOD_WARNING_AMD 0x919C
+#define GL_TEXTURE_STORAGE_SPARSE_BIT_AMD 0x00000001
+typedef void (APIENTRYP PFNGLTEXSTORAGESPARSEAMDPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGESPARSEAMDPROC) (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexStorageSparseAMD (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);
+GLAPI void APIENTRY glTextureStorageSparseAMD (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);
+#endif
+#endif /* GL_AMD_sparse_texture */
+
+#ifndef GL_AMD_stencil_operation_extended
+#define GL_AMD_stencil_operation_extended 1
+#define GL_SET_AMD 0x874A
+#define GL_REPLACE_VALUE_AMD 0x874B
+#define GL_STENCIL_OP_VALUE_AMD 0x874C
+#define GL_STENCIL_BACK_OP_VALUE_AMD 0x874D
+typedef void (APIENTRYP PFNGLSTENCILOPVALUEAMDPROC) (GLenum face, GLuint value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStencilOpValueAMD (GLenum face, GLuint value);
+#endif
+#endif /* GL_AMD_stencil_operation_extended */
+
+#ifndef GL_AMD_texture_texture4
+#define GL_AMD_texture_texture4 1
+#endif /* GL_AMD_texture_texture4 */
+
+#ifndef GL_AMD_transform_feedback3_lines_triangles
+#define GL_AMD_transform_feedback3_lines_triangles 1
+#endif /* GL_AMD_transform_feedback3_lines_triangles */
+
+#ifndef GL_AMD_transform_feedback4
+#define GL_AMD_transform_feedback4 1
+#define GL_STREAM_RASTERIZATION_AMD 0x91A0
+#endif /* GL_AMD_transform_feedback4 */
+
+#ifndef GL_AMD_vertex_shader_layer
+#define GL_AMD_vertex_shader_layer 1
+#endif /* GL_AMD_vertex_shader_layer */
+
+#ifndef GL_AMD_vertex_shader_tessellator
+#define GL_AMD_vertex_shader_tessellator 1
+#define GL_SAMPLER_BUFFER_AMD 0x9001
+#define GL_INT_SAMPLER_BUFFER_AMD 0x9002
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003
+#define GL_TESSELLATION_MODE_AMD 0x9004
+#define GL_TESSELLATION_FACTOR_AMD 0x9005
+#define GL_DISCRETE_AMD 0x9006
+#define GL_CONTINUOUS_AMD 0x9007
+typedef void (APIENTRYP PFNGLTESSELLATIONFACTORAMDPROC) (GLfloat factor);
+typedef void (APIENTRYP PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTessellationFactorAMD (GLfloat factor);
+GLAPI void APIENTRY glTessellationModeAMD (GLenum mode);
+#endif
+#endif /* GL_AMD_vertex_shader_tessellator */
+
+#ifndef GL_AMD_vertex_shader_viewport_index
+#define GL_AMD_vertex_shader_viewport_index 1
+#endif /* GL_AMD_vertex_shader_viewport_index */
+
+#ifndef GL_APPLE_aux_depth_stencil
+#define GL_APPLE_aux_depth_stencil 1
+#define GL_AUX_DEPTH_STENCIL_APPLE 0x8A14
+#endif /* GL_APPLE_aux_depth_stencil */
+
+#ifndef GL_APPLE_client_storage
+#define GL_APPLE_client_storage 1
+#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2
+#endif /* GL_APPLE_client_storage */
+
+#ifndef GL_APPLE_element_array
+#define GL_APPLE_element_array 1
+#define GL_ELEMENT_ARRAY_APPLE 0x8A0C
+#define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8A0D
+#define GL_ELEMENT_ARRAY_POINTER_APPLE 0x8A0E
+typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const void *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const void *pointer);
+GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count);
+GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);
+GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount);
+#endif
+#endif /* GL_APPLE_element_array */
+
+#ifndef GL_APPLE_fence
+#define GL_APPLE_fence 1
+#define GL_DRAW_PIXELS_APPLE 0x8A0A
+#define GL_FENCE_APPLE 0x8A0B
+typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences);
+typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name);
+typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenFencesAPPLE (GLsizei n, GLuint *fences);
+GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei n, const GLuint *fences);
+GLAPI void APIENTRY glSetFenceAPPLE (GLuint fence);
+GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint fence);
+GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint fence);
+GLAPI void APIENTRY glFinishFenceAPPLE (GLuint fence);
+GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum object, GLuint name);
+GLAPI void APIENTRY glFinishObjectAPPLE (GLenum object, GLint name);
+#endif
+#endif /* GL_APPLE_fence */
+
+#ifndef GL_APPLE_float_pixels
+#define GL_APPLE_float_pixels 1
+#define GL_HALF_APPLE 0x140B
+#define GL_RGBA_FLOAT32_APPLE 0x8814
+#define GL_RGB_FLOAT32_APPLE 0x8815
+#define GL_ALPHA_FLOAT32_APPLE 0x8816
+#define GL_INTENSITY_FLOAT32_APPLE 0x8817
+#define GL_LUMINANCE_FLOAT32_APPLE 0x8818
+#define GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819
+#define GL_RGBA_FLOAT16_APPLE 0x881A
+#define GL_RGB_FLOAT16_APPLE 0x881B
+#define GL_ALPHA_FLOAT16_APPLE 0x881C
+#define GL_INTENSITY_FLOAT16_APPLE 0x881D
+#define GL_LUMINANCE_FLOAT16_APPLE 0x881E
+#define GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F
+#define GL_COLOR_FLOAT_APPLE 0x8A0F
+#endif /* GL_APPLE_float_pixels */
+
+#ifndef GL_APPLE_flush_buffer_range
+#define GL_APPLE_flush_buffer_range 1
+#define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12
+#define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13
+typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum target, GLintptr offset, GLsizeiptr size);
+#endif
+#endif /* GL_APPLE_flush_buffer_range */
+
+#ifndef GL_APPLE_object_purgeable
+#define GL_APPLE_object_purgeable 1
+#define GL_BUFFER_OBJECT_APPLE 0x85B3
+#define GL_RELEASED_APPLE 0x8A19
+#define GL_VOLATILE_APPLE 0x8A1A
+#define GL_RETAINED_APPLE 0x8A1B
+#define GL_UNDEFINED_APPLE 0x8A1C
+#define GL_PURGEABLE_APPLE 0x8A1D
+typedef GLenum (APIENTRYP PFNGLOBJECTPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option);
+typedef GLenum (APIENTRYP PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVAPPLEPROC) (GLenum objectType, GLuint name, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLenum APIENTRY glObjectPurgeableAPPLE (GLenum objectType, GLuint name, GLenum option);
+GLAPI GLenum APIENTRY glObjectUnpurgeableAPPLE (GLenum objectType, GLuint name, GLenum option);
+GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, GLenum pname, GLint *params);
+#endif
+#endif /* GL_APPLE_object_purgeable */
+
+#ifndef GL_APPLE_rgb_422
+#define GL_APPLE_rgb_422 1
+#define GL_RGB_422_APPLE 0x8A1F
+#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
+#define GL_RGB_RAW_422_APPLE 0x8A51
+#endif /* GL_APPLE_rgb_422 */
+
+#ifndef GL_APPLE_row_bytes
+#define GL_APPLE_row_bytes 1
+#define GL_PACK_ROW_BYTES_APPLE 0x8A15
+#define GL_UNPACK_ROW_BYTES_APPLE 0x8A16
+#endif /* GL_APPLE_row_bytes */
+
+#ifndef GL_APPLE_specular_vector
+#define GL_APPLE_specular_vector 1
+#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0
+#endif /* GL_APPLE_specular_vector */
+
+#ifndef GL_APPLE_texture_range
+#define GL_APPLE_texture_range 1
+#define GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7
+#define GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8
+#define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC
+#define GL_STORAGE_PRIVATE_APPLE 0x85BD
+#define GL_STORAGE_CACHED_APPLE 0x85BE
+#define GL_STORAGE_SHARED_APPLE 0x85BF
+typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const void *pointer);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, void **params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const void *pointer);
+GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, void **params);
+#endif
+#endif /* GL_APPLE_texture_range */
+
+#ifndef GL_APPLE_transform_hint
+#define GL_APPLE_transform_hint 1
+#define GL_TRANSFORM_HINT_APPLE 0x85B1
+#endif /* GL_APPLE_transform_hint */
+
+#ifndef GL_APPLE_vertex_array_object
+#define GL_APPLE_vertex_array_object 1
+#define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5
+typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array);
+typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint array);
+GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays);
+GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei n, GLuint *arrays);
+GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array);
+#endif
+#endif /* GL_APPLE_vertex_array_object */
+
+#ifndef GL_APPLE_vertex_array_range
+#define GL_APPLE_vertex_array_range 1
+#define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E
+#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F
+#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521
+#define GL_STORAGE_CLIENT_APPLE 0x85B4
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer);
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer);
+typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, void *pointer);
+GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, void *pointer);
+GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param);
+#endif
+#endif /* GL_APPLE_vertex_array_range */
+
+#ifndef GL_APPLE_vertex_program_evaluators
+#define GL_APPLE_vertex_program_evaluators 1
+#define GL_VERTEX_ATTRIB_MAP1_APPLE 0x8A00
+#define GL_VERTEX_ATTRIB_MAP2_APPLE 0x8A01
+#define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE 0x8A02
+#define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03
+#define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04
+#define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05
+#define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE 0x8A06
+#define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07
+#define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08
+#define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname);
+typedef GLboolean (APIENTRYP PFNGLISVERTEXATTRIBENABLEDAPPLEPROC) (GLuint index, GLenum pname);
+typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
+typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
+typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
+typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glEnableVertexAttribAPPLE (GLuint index, GLenum pname);
+GLAPI void APIENTRY glDisableVertexAttribAPPLE (GLuint index, GLenum pname);
+GLAPI GLboolean APIENTRY glIsVertexAttribEnabledAPPLE (GLuint index, GLenum pname);
+GLAPI void APIENTRY glMapVertexAttrib1dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
+GLAPI void APIENTRY glMapVertexAttrib1fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
+GLAPI void APIENTRY glMapVertexAttrib2dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
+GLAPI void APIENTRY glMapVertexAttrib2fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
+#endif
+#endif /* GL_APPLE_vertex_program_evaluators */
+
+#ifndef GL_APPLE_ycbcr_422
+#define GL_APPLE_ycbcr_422 1
+#define GL_YCBCR_422_APPLE 0x85B9
+#endif /* GL_APPLE_ycbcr_422 */
+
+#ifndef GL_ATI_draw_buffers
+#define GL_ATI_draw_buffers 1
+#define GL_MAX_DRAW_BUFFERS_ATI 0x8824
+#define GL_DRAW_BUFFER0_ATI 0x8825
+#define GL_DRAW_BUFFER1_ATI 0x8826
+#define GL_DRAW_BUFFER2_ATI 0x8827
+#define GL_DRAW_BUFFER3_ATI 0x8828
+#define GL_DRAW_BUFFER4_ATI 0x8829
+#define GL_DRAW_BUFFER5_ATI 0x882A
+#define GL_DRAW_BUFFER6_ATI 0x882B
+#define GL_DRAW_BUFFER7_ATI 0x882C
+#define GL_DRAW_BUFFER8_ATI 0x882D
+#define GL_DRAW_BUFFER9_ATI 0x882E
+#define GL_DRAW_BUFFER10_ATI 0x882F
+#define GL_DRAW_BUFFER11_ATI 0x8830
+#define GL_DRAW_BUFFER12_ATI 0x8831
+#define GL_DRAW_BUFFER13_ATI 0x8832
+#define GL_DRAW_BUFFER14_ATI 0x8833
+#define GL_DRAW_BUFFER15_ATI 0x8834
+typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs);
+#endif
+#endif /* GL_ATI_draw_buffers */
+
+#ifndef GL_ATI_element_array
+#define GL_ATI_element_array 1
+#define GL_ELEMENT_ARRAY_ATI 0x8768
+#define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769
+#define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A
+typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const void *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerATI (GLenum type, const void *pointer);
+GLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count);
+GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count);
+#endif
+#endif /* GL_ATI_element_array */
+
+#ifndef GL_ATI_envmap_bumpmap
+#define GL_ATI_envmap_bumpmap 1
+#define GL_BUMP_ROT_MATRIX_ATI 0x8775
+#define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776
+#define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777
+#define GL_BUMP_TEX_UNITS_ATI 0x8778
+#define GL_DUDV_ATI 0x8779
+#define GL_DU8DV8_ATI 0x877A
+#define GL_BUMP_ENVMAP_ATI 0x877B
+#define GL_BUMP_TARGET_ATI 0x877C
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param);
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexBumpParameterivATI (GLenum pname, const GLint *param);
+GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum pname, const GLfloat *param);
+GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum pname, GLint *param);
+GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum pname, GLfloat *param);
+#endif
+#endif /* GL_ATI_envmap_bumpmap */
+
+#ifndef GL_ATI_fragment_shader
+#define GL_ATI_fragment_shader 1
+#define GL_FRAGMENT_SHADER_ATI 0x8920
+#define GL_REG_0_ATI 0x8921
+#define GL_REG_1_ATI 0x8922
+#define GL_REG_2_ATI 0x8923
+#define GL_REG_3_ATI 0x8924
+#define GL_REG_4_ATI 0x8925
+#define GL_REG_5_ATI 0x8926
+#define GL_REG_6_ATI 0x8927
+#define GL_REG_7_ATI 0x8928
+#define GL_REG_8_ATI 0x8929
+#define GL_REG_9_ATI 0x892A
+#define GL_REG_10_ATI 0x892B
+#define GL_REG_11_ATI 0x892C
+#define GL_REG_12_ATI 0x892D
+#define GL_REG_13_ATI 0x892E
+#define GL_REG_14_ATI 0x892F
+#define GL_REG_15_ATI 0x8930
+#define GL_REG_16_ATI 0x8931
+#define GL_REG_17_ATI 0x8932
+#define GL_REG_18_ATI 0x8933
+#define GL_REG_19_ATI 0x8934
+#define GL_REG_20_ATI 0x8935
+#define GL_REG_21_ATI 0x8936
+#define GL_REG_22_ATI 0x8937
+#define GL_REG_23_ATI 0x8938
+#define GL_REG_24_ATI 0x8939
+#define GL_REG_25_ATI 0x893A
+#define GL_REG_26_ATI 0x893B
+#define GL_REG_27_ATI 0x893C
+#define GL_REG_28_ATI 0x893D
+#define GL_REG_29_ATI 0x893E
+#define GL_REG_30_ATI 0x893F
+#define GL_REG_31_ATI 0x8940
+#define GL_CON_0_ATI 0x8941
+#define GL_CON_1_ATI 0x8942
+#define GL_CON_2_ATI 0x8943
+#define GL_CON_3_ATI 0x8944
+#define GL_CON_4_ATI 0x8945
+#define GL_CON_5_ATI 0x8946
+#define GL_CON_6_ATI 0x8947
+#define GL_CON_7_ATI 0x8948
+#define GL_CON_8_ATI 0x8949
+#define GL_CON_9_ATI 0x894A
+#define GL_CON_10_ATI 0x894B
+#define GL_CON_11_ATI 0x894C
+#define GL_CON_12_ATI 0x894D
+#define GL_CON_13_ATI 0x894E
+#define GL_CON_14_ATI 0x894F
+#define GL_CON_15_ATI 0x8950
+#define GL_CON_16_ATI 0x8951
+#define GL_CON_17_ATI 0x8952
+#define GL_CON_18_ATI 0x8953
+#define GL_CON_19_ATI 0x8954
+#define GL_CON_20_ATI 0x8955
+#define GL_CON_21_ATI 0x8956
+#define GL_CON_22_ATI 0x8957
+#define GL_CON_23_ATI 0x8958
+#define GL_CON_24_ATI 0x8959
+#define GL_CON_25_ATI 0x895A
+#define GL_CON_26_ATI 0x895B
+#define GL_CON_27_ATI 0x895C
+#define GL_CON_28_ATI 0x895D
+#define GL_CON_29_ATI 0x895E
+#define GL_CON_30_ATI 0x895F
+#define GL_CON_31_ATI 0x8960
+#define GL_MOV_ATI 0x8961
+#define GL_ADD_ATI 0x8963
+#define GL_MUL_ATI 0x8964
+#define GL_SUB_ATI 0x8965
+#define GL_DOT3_ATI 0x8966
+#define GL_DOT4_ATI 0x8967
+#define GL_MAD_ATI 0x8968
+#define GL_LERP_ATI 0x8969
+#define GL_CND_ATI 0x896A
+#define GL_CND0_ATI 0x896B
+#define GL_DOT2_ADD_ATI 0x896C
+#define GL_SECONDARY_INTERPOLATOR_ATI 0x896D
+#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E
+#define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F
+#define GL_NUM_PASSES_ATI 0x8970
+#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971
+#define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972
+#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973
+#define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974
+#define GL_COLOR_ALPHA_PAIRING_ATI 0x8975
+#define GL_SWIZZLE_STR_ATI 0x8976
+#define GL_SWIZZLE_STQ_ATI 0x8977
+#define GL_SWIZZLE_STR_DR_ATI 0x8978
+#define GL_SWIZZLE_STQ_DQ_ATI 0x8979
+#define GL_SWIZZLE_STRQ_ATI 0x897A
+#define GL_SWIZZLE_STRQ_DQ_ATI 0x897B
+#define GL_RED_BIT_ATI 0x00000001
+#define GL_GREEN_BIT_ATI 0x00000002
+#define GL_BLUE_BIT_ATI 0x00000004
+#define GL_2X_BIT_ATI 0x00000001
+#define GL_4X_BIT_ATI 0x00000002
+#define GL_8X_BIT_ATI 0x00000004
+#define GL_HALF_BIT_ATI 0x00000008
+#define GL_QUARTER_BIT_ATI 0x00000010
+#define GL_EIGHTH_BIT_ATI 0x00000020
+#define GL_SATURATE_BIT_ATI 0x00000040
+#define GL_COMP_BIT_ATI 0x00000002
+#define GL_NEGATE_BIT_ATI 0x00000004
+#define GL_BIAS_BIT_ATI 0x00000008
+typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle);
+typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint range);
+GLAPI void APIENTRY glBindFragmentShaderATI (GLuint id);
+GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint id);
+GLAPI void APIENTRY glBeginFragmentShaderATI (void);
+GLAPI void APIENTRY glEndFragmentShaderATI (void);
+GLAPI void APIENTRY glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle);
+GLAPI void APIENTRY glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle);
+GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value);
+#endif
+#endif /* GL_ATI_fragment_shader */
+
+#ifndef GL_ATI_map_object_buffer
+#define GL_ATI_map_object_buffer 1
+typedef void *(APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void *APIENTRY glMapObjectBufferATI (GLuint buffer);
+GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint buffer);
+#endif
+#endif /* GL_ATI_map_object_buffer */
+
+#ifndef GL_ATI_meminfo
+#define GL_ATI_meminfo 1
+#define GL_VBO_FREE_MEMORY_ATI 0x87FB
+#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC
+#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD
+#endif /* GL_ATI_meminfo */
+
+#ifndef GL_ATI_pixel_format_float
+#define GL_ATI_pixel_format_float 1
+#define GL_RGBA_FLOAT_MODE_ATI 0x8820
+#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835
+#endif /* GL_ATI_pixel_format_float */
+
+#ifndef GL_ATI_pn_triangles
+#define GL_ATI_pn_triangles 1
+#define GL_PN_TRIANGLES_ATI 0x87F0
+#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1
+#define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2
+#define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3
+#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4
+#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5
+#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6
+#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7
+#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8
+typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPNTrianglesiATI (GLenum pname, GLint param);
+GLAPI void APIENTRY glPNTrianglesfATI (GLenum pname, GLfloat param);
+#endif
+#endif /* GL_ATI_pn_triangles */
+
+#ifndef GL_ATI_separate_stencil
+#define GL_ATI_separate_stencil 1
+#define GL_STENCIL_BACK_FUNC_ATI 0x8800
+#define GL_STENCIL_BACK_FAIL_ATI 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+#endif
+#endif /* GL_ATI_separate_stencil */
+
+#ifndef GL_ATI_text_fragment_shader
+#define GL_ATI_text_fragment_shader 1
+#define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200
+#endif /* GL_ATI_text_fragment_shader */
+
+#ifndef GL_ATI_texture_env_combine3
+#define GL_ATI_texture_env_combine3 1
+#define GL_MODULATE_ADD_ATI 0x8744
+#define GL_MODULATE_SIGNED_ADD_ATI 0x8745
+#define GL_MODULATE_SUBTRACT_ATI 0x8746
+#endif /* GL_ATI_texture_env_combine3 */
+
+#ifndef GL_ATI_texture_float
+#define GL_ATI_texture_float 1
+#define GL_RGBA_FLOAT32_ATI 0x8814
+#define GL_RGB_FLOAT32_ATI 0x8815
+#define GL_ALPHA_FLOAT32_ATI 0x8816
+#define GL_INTENSITY_FLOAT32_ATI 0x8817
+#define GL_LUMINANCE_FLOAT32_ATI 0x8818
+#define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819
+#define GL_RGBA_FLOAT16_ATI 0x881A
+#define GL_RGB_FLOAT16_ATI 0x881B
+#define GL_ALPHA_FLOAT16_ATI 0x881C
+#define GL_INTENSITY_FLOAT16_ATI 0x881D
+#define GL_LUMINANCE_FLOAT16_ATI 0x881E
+#define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F
+#endif /* GL_ATI_texture_float */
+
+#ifndef GL_ATI_texture_mirror_once
+#define GL_ATI_texture_mirror_once 1
+#define GL_MIRROR_CLAMP_ATI 0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743
+#endif /* GL_ATI_texture_mirror_once */
+
+#ifndef GL_ATI_vertex_array_object
+#define GL_ATI_vertex_array_object 1
+#define GL_STATIC_ATI 0x8760
+#define GL_DYNAMIC_ATI 0x8761
+#define GL_PRESERVE_ATI 0x8762
+#define GL_DISCARD_ATI 0x8763
+#define GL_OBJECT_BUFFER_SIZE_ATI 0x8764
+#define GL_OBJECT_BUFFER_USAGE_ATI 0x8765
+#define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766
+#define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767
+typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const void *pointer, GLenum usage);
+typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const void *pointer, GLenum usage);
+GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer);
+GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve);
+GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer);
+GLAPI void APIENTRY glArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params);
+GLAPI void APIENTRY glVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params);
+#endif
+#endif /* GL_ATI_vertex_array_object */
+
+#ifndef GL_ATI_vertex_attrib_array_object
+#define GL_ATI_vertex_attrib_array_object 1
+typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params);
+#endif
+#endif /* GL_ATI_vertex_attrib_array_object */
+
+#ifndef GL_ATI_vertex_streams
+#define GL_ATI_vertex_streams 1
+#define GL_MAX_VERTEX_STREAMS_ATI 0x876B
+#define GL_VERTEX_STREAM0_ATI 0x876C
+#define GL_VERTEX_STREAM1_ATI 0x876D
+#define GL_VERTEX_STREAM2_ATI 0x876E
+#define GL_VERTEX_STREAM3_ATI 0x876F
+#define GL_VERTEX_STREAM4_ATI 0x8770
+#define GL_VERTEX_STREAM5_ATI 0x8771
+#define GL_VERTEX_STREAM6_ATI 0x8772
+#define GL_VERTEX_STREAM7_ATI 0x8773
+#define GL_VERTEX_SOURCE_ATI 0x8774
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexStream1sATI (GLenum stream, GLshort x);
+GLAPI void APIENTRY glVertexStream1svATI (GLenum stream, const GLshort *coords);
+GLAPI void APIENTRY glVertexStream1iATI (GLenum stream, GLint x);
+GLAPI void APIENTRY glVertexStream1ivATI (GLenum stream, const GLint *coords);
+GLAPI void APIENTRY glVertexStream1fATI (GLenum stream, GLfloat x);
+GLAPI void APIENTRY glVertexStream1fvATI (GLenum stream, const GLfloat *coords);
+GLAPI void APIENTRY glVertexStream1dATI (GLenum stream, GLdouble x);
+GLAPI void APIENTRY glVertexStream1dvATI (GLenum stream, const GLdouble *coords);
+GLAPI void APIENTRY glVertexStream2sATI (GLenum stream, GLshort x, GLshort y);
+GLAPI void APIENTRY glVertexStream2svATI (GLenum stream, const GLshort *coords);
+GLAPI void APIENTRY glVertexStream2iATI (GLenum stream, GLint x, GLint y);
+GLAPI void APIENTRY glVertexStream2ivATI (GLenum stream, const GLint *coords);
+GLAPI void APIENTRY glVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y);
+GLAPI void APIENTRY glVertexStream2fvATI (GLenum stream, const GLfloat *coords);
+GLAPI void APIENTRY glVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexStream2dvATI (GLenum stream, const GLdouble *coords);
+GLAPI void APIENTRY glVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glVertexStream3svATI (GLenum stream, const GLshort *coords);
+GLAPI void APIENTRY glVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glVertexStream3ivATI (GLenum stream, const GLint *coords);
+GLAPI void APIENTRY glVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glVertexStream3fvATI (GLenum stream, const GLfloat *coords);
+GLAPI void APIENTRY glVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexStream3dvATI (GLenum stream, const GLdouble *coords);
+GLAPI void APIENTRY glVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI void APIENTRY glVertexStream4svATI (GLenum stream, const GLshort *coords);
+GLAPI void APIENTRY glVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glVertexStream4ivATI (GLenum stream, const GLint *coords);
+GLAPI void APIENTRY glVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glVertexStream4fvATI (GLenum stream, const GLfloat *coords);
+GLAPI void APIENTRY glVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexStream4dvATI (GLenum stream, const GLdouble *coords);
+GLAPI void APIENTRY glNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz);
+GLAPI void APIENTRY glNormalStream3bvATI (GLenum stream, const GLbyte *coords);
+GLAPI void APIENTRY glNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz);
+GLAPI void APIENTRY glNormalStream3svATI (GLenum stream, const GLshort *coords);
+GLAPI void APIENTRY glNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz);
+GLAPI void APIENTRY glNormalStream3ivATI (GLenum stream, const GLint *coords);
+GLAPI void APIENTRY glNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz);
+GLAPI void APIENTRY glNormalStream3fvATI (GLenum stream, const GLfloat *coords);
+GLAPI void APIENTRY glNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz);
+GLAPI void APIENTRY glNormalStream3dvATI (GLenum stream, const GLdouble *coords);
+GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum stream);
+GLAPI void APIENTRY glVertexBlendEnviATI (GLenum pname, GLint param);
+GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum pname, GLfloat param);
+#endif
+#endif /* GL_ATI_vertex_streams */
+
+#ifndef GL_EXT_422_pixels
+#define GL_EXT_422_pixels 1
+#define GL_422_EXT 0x80CC
+#define GL_422_REV_EXT 0x80CD
+#define GL_422_AVERAGE_EXT 0x80CE
+#define GL_422_REV_AVERAGE_EXT 0x80CF
+#endif /* GL_EXT_422_pixels */
+
+#ifndef GL_EXT_abgr
+#define GL_EXT_abgr 1
+#define GL_ABGR_EXT 0x8000
+#endif /* GL_EXT_abgr */
+
+#ifndef GL_EXT_bgra
+#define GL_EXT_bgra 1
+#define GL_BGR_EXT 0x80E0
+#define GL_BGRA_EXT 0x80E1
+#endif /* GL_EXT_bgra */
+
+#ifndef GL_EXT_bindable_uniform
+#define GL_EXT_bindable_uniform 1
+#define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2
+#define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3
+#define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4
+#define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED
+#define GL_UNIFORM_BUFFER_EXT 0x8DEE
+#define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF
+typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location);
+typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glUniformBufferEXT (GLuint program, GLint location, GLuint buffer);
+GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint program, GLint location);
+GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint program, GLint location);
+#endif
+#endif /* GL_EXT_bindable_uniform */
+
+#ifndef GL_EXT_blend_color
+#define GL_EXT_blend_color 1
+#define GL_CONSTANT_COLOR_EXT 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002
+#define GL_CONSTANT_ALPHA_EXT 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004
+#define GL_BLEND_COLOR_EXT 0x8005
+typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendColorEXT (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+#endif
+#endif /* GL_EXT_blend_color */
+
+#ifndef GL_EXT_blend_equation_separate
+#define GL_EXT_blend_equation_separate 1
+#define GL_BLEND_EQUATION_RGB_EXT 0x8009
+#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha);
+#endif
+#endif /* GL_EXT_blend_equation_separate */
+
+#ifndef GL_EXT_blend_func_separate
+#define GL_EXT_blend_func_separate 1
+#define GL_BLEND_DST_RGB_EXT 0x80C8
+#define GL_BLEND_SRC_RGB_EXT 0x80C9
+#define GL_BLEND_DST_ALPHA_EXT 0x80CA
+#define GL_BLEND_SRC_ALPHA_EXT 0x80CB
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+#endif /* GL_EXT_blend_func_separate */
+
+#ifndef GL_EXT_blend_logic_op
+#define GL_EXT_blend_logic_op 1
+#endif /* GL_EXT_blend_logic_op */
+
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+#define GL_MIN_EXT 0x8007
+#define GL_MAX_EXT 0x8008
+#define GL_FUNC_ADD_EXT 0x8006
+#define GL_BLEND_EQUATION_EXT 0x8009
+typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationEXT (GLenum mode);
+#endif
+#endif /* GL_EXT_blend_minmax */
+
+#ifndef GL_EXT_blend_subtract
+#define GL_EXT_blend_subtract 1
+#define GL_FUNC_SUBTRACT_EXT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B
+#endif /* GL_EXT_blend_subtract */
+
+#ifndef GL_EXT_clip_volume_hint
+#define GL_EXT_clip_volume_hint 1
+#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0
+#endif /* GL_EXT_clip_volume_hint */
+
+#ifndef GL_EXT_cmyka
+#define GL_EXT_cmyka 1
+#define GL_CMYK_EXT 0x800C
+#define GL_CMYKA_EXT 0x800D
+#define GL_PACK_CMYK_HINT_EXT 0x800E
+#define GL_UNPACK_CMYK_HINT_EXT 0x800F
+#endif /* GL_EXT_cmyka */
+
+#ifndef GL_EXT_color_subtable
+#define GL_EXT_color_subtable 1
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+#endif
+#endif /* GL_EXT_color_subtable */
+
+#ifndef GL_EXT_compiled_vertex_array
+#define GL_EXT_compiled_vertex_array 1
+#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8
+#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9
+typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count);
+GLAPI void APIENTRY glUnlockArraysEXT (void);
+#endif
+#endif /* GL_EXT_compiled_vertex_array */
+
+#ifndef GL_EXT_convolution
+#define GL_EXT_convolution 1
+#define GL_CONVOLUTION_1D_EXT 0x8010
+#define GL_CONVOLUTION_2D_EXT 0x8011
+#define GL_SEPARABLE_2D_EXT 0x8012
+#define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013
+#define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014
+#define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015
+#define GL_REDUCE_EXT 0x8016
+#define GL_CONVOLUTION_FORMAT_EXT 0x8017
+#define GL_CONVOLUTION_WIDTH_EXT 0x8018
+#define GL_CONVOLUTION_HEIGHT_EXT 0x8019
+#define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
+GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
+GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params);
+GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params);
+GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, void *image);
+GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
+GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
+#endif
+#endif /* GL_EXT_convolution */
+
+#ifndef GL_EXT_coordinate_frame
+#define GL_EXT_coordinate_frame 1
+#define GL_TANGENT_ARRAY_EXT 0x8439
+#define GL_BINORMAL_ARRAY_EXT 0x843A
+#define GL_CURRENT_TANGENT_EXT 0x843B
+#define GL_CURRENT_BINORMAL_EXT 0x843C
+#define GL_TANGENT_ARRAY_TYPE_EXT 0x843E
+#define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F
+#define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440
+#define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441
+#define GL_TANGENT_ARRAY_POINTER_EXT 0x8442
+#define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443
+#define GL_MAP1_TANGENT_EXT 0x8444
+#define GL_MAP2_TANGENT_EXT 0x8445
+#define GL_MAP1_BINORMAL_EXT 0x8446
+#define GL_MAP2_BINORMAL_EXT 0x8447
+typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz);
+typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz);
+typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz);
+typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz);
+typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz);
+typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz);
+typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz);
+typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz);
+typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz);
+typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz);
+typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz);
+GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v);
+GLAPI void APIENTRY glTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz);
+GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *v);
+GLAPI void APIENTRY glTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz);
+GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *v);
+GLAPI void APIENTRY glTangent3iEXT (GLint tx, GLint ty, GLint tz);
+GLAPI void APIENTRY glTangent3ivEXT (const GLint *v);
+GLAPI void APIENTRY glTangent3sEXT (GLshort tx, GLshort ty, GLshort tz);
+GLAPI void APIENTRY glTangent3svEXT (const GLshort *v);
+GLAPI void APIENTRY glBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz);
+GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *v);
+GLAPI void APIENTRY glBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz);
+GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *v);
+GLAPI void APIENTRY glBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz);
+GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *v);
+GLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz);
+GLAPI void APIENTRY glBinormal3ivEXT (const GLint *v);
+GLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz);
+GLAPI void APIENTRY glBinormal3svEXT (const GLshort *v);
+GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_EXT_coordinate_frame */
+
+#ifndef GL_EXT_copy_texture
+#define GL_EXT_copy_texture 1
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+#endif /* GL_EXT_copy_texture */
+
+#ifndef GL_EXT_cull_vertex
+#define GL_EXT_cull_vertex 1
+#define GL_CULL_VERTEX_EXT 0x81AA
+#define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB
+#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC
+typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCullParameterdvEXT (GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_EXT_cull_vertex */
+
+#ifndef GL_EXT_debug_label
+#define GL_EXT_debug_label 1
+#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F
+#define GL_PROGRAM_OBJECT_EXT 0x8B40
+#define GL_SHADER_OBJECT_EXT 0x8B48
+#define GL_BUFFER_OBJECT_EXT 0x9151
+#define GL_QUERY_OBJECT_EXT 0x9153
+#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154
+typedef void (APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+typedef void (APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+GLAPI void APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+#endif /* GL_EXT_debug_label */
+
+#ifndef GL_EXT_debug_marker
+#define GL_EXT_debug_marker 1
+typedef void (APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);
+GLAPI void APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);
+GLAPI void APIENTRY glPopGroupMarkerEXT (void);
+#endif
+#endif /* GL_EXT_debug_marker */
+
+#ifndef GL_EXT_depth_bounds_test
+#define GL_EXT_depth_bounds_test 1
+#define GL_DEPTH_BOUNDS_TEST_EXT 0x8890
+#define GL_DEPTH_BOUNDS_EXT 0x8891
+typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDepthBoundsEXT (GLclampd zmin, GLclampd zmax);
+#endif
+#endif /* GL_EXT_depth_bounds_test */
+
+#ifndef GL_EXT_direct_state_access
+#define GL_EXT_direct_state_access 1
+#define GL_PROGRAM_MATRIX_EXT 0x8E2D
+#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E
+#define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F
+typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param);
+typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params);
+typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
+typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index);
+typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index);
+typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data);
+typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, void **data);
+typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index);
+typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data);
+typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, void *img);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, void *img);
+typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, void **params);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params);
+typedef void (APIENTRYP PFNGLENABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index);
+typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index);
+typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, void *string);
+typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target);
+typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face);
+typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYINDEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYNORMALOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array);
+typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERVEXTPROC) (GLuint vaobj, GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, void **param);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param);
+typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);
+typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) (GLuint framebuffer, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC) (GLuint vaobj, GLuint index, GLuint divisor);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m);
+GLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m);
+GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode);
+GLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GLAPI void APIENTRY glMatrixPopEXT (GLenum mode);
+GLAPI void APIENTRY glMatrixPushEXT (GLenum mode);
+GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask);
+GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask);
+GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
+GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params);
+GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture);
+GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param);
+GLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params);
+GLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param);
+GLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params);
+GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
+GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params);
+GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index);
+GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index);
+GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data);
+GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data);
+GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, void **data);
+GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index);
+GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index);
+GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index);
+GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data);
+GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data);
+GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, void *img);
+GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, void *img);
+GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m);
+GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m);
+GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);
+GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+GLAPI void *APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access);
+GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer);
+GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, void **params);
+GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);
+GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0);
+GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1);
+GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+GLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0);
+GLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1);
+GLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+GLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer);
+GLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer);
+GLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params);
+GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params);
+GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0);
+GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1);
+GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params);
+GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params);
+GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params);
+GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params);
+GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params);
+GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params);
+GLAPI void APIENTRY glEnableClientStateiEXT (GLenum array, GLuint index);
+GLAPI void APIENTRY glDisableClientStateiEXT (GLenum array, GLuint index);
+GLAPI void APIENTRY glGetFloati_vEXT (GLenum pname, GLuint index, GLfloat *params);
+GLAPI void APIENTRY glGetDoublei_vEXT (GLenum pname, GLuint index, GLdouble *params);
+GLAPI void APIENTRY glGetPointeri_vEXT (GLenum pname, GLuint index, void **params);
+GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string);
+GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params);
+GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params);
+GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params);
+GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params);
+GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, void *string);
+GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target);
+GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target);
+GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target);
+GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode);
+GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs);
+GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode);
+GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
+GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face);
+GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer);
+GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer);
+GLAPI void APIENTRY glVertexArrayVertexOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayEdgeFlagOffsetEXT (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayIndexOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayNormalOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayMultiTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayFogCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArraySecondaryColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayVertexAttribOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayVertexAttribIOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glEnableVertexArrayEXT (GLuint vaobj, GLenum array);
+GLAPI void APIENTRY glDisableVertexArrayEXT (GLuint vaobj, GLenum array);
+GLAPI void APIENTRY glEnableVertexArrayAttribEXT (GLuint vaobj, GLuint index);
+GLAPI void APIENTRY glDisableVertexArrayAttribEXT (GLuint vaobj, GLuint index);
+GLAPI void APIENTRY glGetVertexArrayIntegervEXT (GLuint vaobj, GLenum pname, GLint *param);
+GLAPI void APIENTRY glGetVertexArrayPointervEXT (GLuint vaobj, GLenum pname, void **param);
+GLAPI void APIENTRY glGetVertexArrayIntegeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
+GLAPI void APIENTRY glGetVertexArrayPointeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, void **param);
+GLAPI void *APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
+GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length);
+GLAPI void APIENTRY glNamedBufferStorageEXT (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);
+GLAPI void APIENTRY glClearNamedBufferDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glNamedFramebufferParameteriEXT (GLuint framebuffer, GLenum pname, GLint param);
+GLAPI void APIENTRY glGetNamedFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x);
+GLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glTextureBufferRangeEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GLAPI void APIENTRY glTextureStorage2DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glTextureStorage3DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glVertexArrayBindVertexBufferEXT (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+GLAPI void APIENTRY glVertexArrayVertexAttribFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexArrayVertexAttribIFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT (GLuint vaobj, GLuint attribindex, GLuint bindingindex);
+GLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT (GLuint vaobj, GLuint bindingindex, GLuint divisor);
+GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glTexturePageCommitmentEXT (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident);
+GLAPI void APIENTRY glVertexArrayVertexAttribDivisorEXT (GLuint vaobj, GLuint index, GLuint divisor);
+#endif
+#endif /* GL_EXT_direct_state_access */
+
+#ifndef GL_EXT_draw_buffers2
+#define GL_EXT_draw_buffers2 1
+typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+#endif
+#endif /* GL_EXT_draw_buffers2 */
+
+#ifndef GL_EXT_draw_instanced
+#define GL_EXT_draw_instanced 1
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
+GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+#endif
+#endif /* GL_EXT_draw_instanced */
+
+#ifndef GL_EXT_draw_range_elements
+#define GL_EXT_draw_range_elements 1
+#define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8
+#define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+#endif
+#endif /* GL_EXT_draw_range_elements */
+
+#ifndef GL_EXT_fog_coord
+#define GL_EXT_fog_coord 1
+#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450
+#define GL_FOG_COORDINATE_EXT 0x8451
+#define GL_FRAGMENT_DEPTH_EXT 0x8452
+#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456
+#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457
+typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogCoordfEXT (GLfloat coord);
+GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord);
+GLAPI void APIENTRY glFogCoorddEXT (GLdouble coord);
+GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord);
+GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_EXT_fog_coord */
+
+#ifndef GL_EXT_framebuffer_blit
+#define GL_EXT_framebuffer_blit 1
+#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA
+typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+#endif /* GL_EXT_framebuffer_blit */
+
+#ifndef GL_EXT_framebuffer_multisample
+#define GL_EXT_framebuffer_multisample 1
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
+#define GL_MAX_SAMPLES_EXT 0x8D57
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+#endif /* GL_EXT_framebuffer_multisample */
+
+#ifndef GL_EXT_framebuffer_multisample_blit_scaled
+#define GL_EXT_framebuffer_multisample_blit_scaled 1
+#define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA
+#define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB
+#endif /* GL_EXT_framebuffer_multisample_blit_scaled */
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_EXT_framebuffer_object 1
+#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
+#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8
+#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6
+#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
+#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD
+#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
+#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
+#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
+#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
+#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
+#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
+#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
+#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
+#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
+#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
+#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
+#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
+#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
+#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
+#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
+#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
+#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
+#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
+#define GL_STENCIL_ATTACHMENT_EXT 0x8D20
+#define GL_FRAMEBUFFER_EXT 0x8D40
+#define GL_RENDERBUFFER_EXT 0x8D41
+#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42
+#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
+#define GL_STENCIL_INDEX1_EXT 0x8D46
+#define GL_STENCIL_INDEX4_EXT 0x8D47
+#define GL_STENCIL_INDEX8_EXT 0x8D48
+#define GL_STENCIL_INDEX16_EXT 0x8D49
+#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer);
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint renderbuffer);
+GLAPI void APIENTRY glBindRenderbufferEXT (GLenum target, GLuint renderbuffer);
+GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers);
+GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers);
+GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint framebuffer);
+GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer);
+GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers);
+GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers);
+GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum target);
+GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGenerateMipmapEXT (GLenum target);
+#endif
+#endif /* GL_EXT_framebuffer_object */
+
+#ifndef GL_EXT_framebuffer_sRGB
+#define GL_EXT_framebuffer_sRGB 1
+#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9
+#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA
+#endif /* GL_EXT_framebuffer_sRGB */
+
+#ifndef GL_EXT_geometry_shader4
+#define GL_EXT_geometry_shader4 1
+#define GL_GEOMETRY_SHADER_EXT 0x8DD9
+#define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA
+#define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB
+#define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29
+#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD
+#define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE
+#define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1
+#define GL_LINES_ADJACENCY_EXT 0x000A
+#define GL_LINE_STRIP_ADJACENCY_EXT 0x000B
+#define GL_TRIANGLES_ADJACENCY_EXT 0x000C
+#define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4
+#define GL_PROGRAM_POINT_SIZE_EXT 0x8642
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value);
+#endif
+#endif /* GL_EXT_geometry_shader4 */
+
+#ifndef GL_EXT_gpu_program_parameters
+#define GL_EXT_gpu_program_parameters 1
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+#endif
+#endif /* GL_EXT_gpu_program_parameters */
+
+#ifndef GL_EXT_gpu_shader4
+#define GL_EXT_gpu_shader4 1
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD
+#define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0
+#define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1
+#define GL_SAMPLER_BUFFER_EXT 0x8DC2
+#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3
+#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4
+#define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5
+#define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6
+#define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7
+#define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8
+#define GL_INT_SAMPLER_1D_EXT 0x8DC9
+#define GL_INT_SAMPLER_2D_EXT 0x8DCA
+#define GL_INT_SAMPLER_3D_EXT 0x8DCB
+#define GL_INT_SAMPLER_CUBE_EXT 0x8DCC
+#define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD
+#define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE
+#define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF
+#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0
+#define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1
+#define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2
+#define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4
+#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5
+#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8
+#define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904
+#define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905
+typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params);
+typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params);
+GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name);
+GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glUniform1uiEXT (GLint location, GLuint v0);
+GLAPI void APIENTRY glUniform2uiEXT (GLint location, GLuint v0, GLuint v1);
+GLAPI void APIENTRY glUniform3uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2);
+GLAPI void APIENTRY glUniform4uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+GLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value);
+#endif
+#endif /* GL_EXT_gpu_shader4 */
+
+#ifndef GL_EXT_histogram
+#define GL_EXT_histogram 1
+#define GL_HISTOGRAM_EXT 0x8024
+#define GL_PROXY_HISTOGRAM_EXT 0x8025
+#define GL_HISTOGRAM_WIDTH_EXT 0x8026
+#define GL_HISTOGRAM_FORMAT_EXT 0x8027
+#define GL_HISTOGRAM_RED_SIZE_EXT 0x8028
+#define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029
+#define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C
+#define GL_HISTOGRAM_SINK_EXT 0x802D
+#define GL_MINMAX_EXT 0x802E
+#define GL_MINMAX_FORMAT_EXT 0x802F
+#define GL_MINMAX_SINK_EXT 0x8030
+#define GL_TABLE_TOO_LARGE_EXT 0x8031
+typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+GLAPI void APIENTRY glMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink);
+GLAPI void APIENTRY glResetHistogramEXT (GLenum target);
+GLAPI void APIENTRY glResetMinmaxEXT (GLenum target);
+#endif
+#endif /* GL_EXT_histogram */
+
+#ifndef GL_EXT_index_array_formats
+#define GL_EXT_index_array_formats 1
+#define GL_IUI_V2F_EXT 0x81AD
+#define GL_IUI_V3F_EXT 0x81AE
+#define GL_IUI_N3F_V2F_EXT 0x81AF
+#define GL_IUI_N3F_V3F_EXT 0x81B0
+#define GL_T2F_IUI_V2F_EXT 0x81B1
+#define GL_T2F_IUI_V3F_EXT 0x81B2
+#define GL_T2F_IUI_N3F_V2F_EXT 0x81B3
+#define GL_T2F_IUI_N3F_V3F_EXT 0x81B4
+#endif /* GL_EXT_index_array_formats */
+
+#ifndef GL_EXT_index_func
+#define GL_EXT_index_func 1
+#define GL_INDEX_TEST_EXT 0x81B5
+#define GL_INDEX_TEST_FUNC_EXT 0x81B6
+#define GL_INDEX_TEST_REF_EXT 0x81B7
+typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexFuncEXT (GLenum func, GLclampf ref);
+#endif
+#endif /* GL_EXT_index_func */
+
+#ifndef GL_EXT_index_material
+#define GL_EXT_index_material 1
+#define GL_INDEX_MATERIAL_EXT 0x81B8
+#define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9
+#define GL_INDEX_MATERIAL_FACE_EXT 0x81BA
+typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexMaterialEXT (GLenum face, GLenum mode);
+#endif
+#endif /* GL_EXT_index_material */
+
+#ifndef GL_EXT_index_texture
+#define GL_EXT_index_texture 1
+#endif /* GL_EXT_index_texture */
+
+#ifndef GL_EXT_light_texture
+#define GL_EXT_light_texture 1
+#define GL_FRAGMENT_MATERIAL_EXT 0x8349
+#define GL_FRAGMENT_NORMAL_EXT 0x834A
+#define GL_FRAGMENT_COLOR_EXT 0x834C
+#define GL_ATTENUATION_EXT 0x834D
+#define GL_SHADOW_ATTENUATION_EXT 0x834E
+#define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F
+#define GL_TEXTURE_LIGHT_EXT 0x8350
+#define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351
+#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352
+typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glApplyTextureEXT (GLenum mode);
+GLAPI void APIENTRY glTextureLightEXT (GLenum pname);
+GLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode);
+#endif
+#endif /* GL_EXT_light_texture */
+
+#ifndef GL_EXT_misc_attribute
+#define GL_EXT_misc_attribute 1
+#endif /* GL_EXT_misc_attribute */
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 1
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
+#endif
+#endif /* GL_EXT_multi_draw_arrays */
+
+#ifndef GL_EXT_multisample
+#define GL_EXT_multisample 1
+#define GL_MULTISAMPLE_EXT 0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F
+#define GL_SAMPLE_MASK_EXT 0x80A0
+#define GL_1PASS_EXT 0x80A1
+#define GL_2PASS_0_EXT 0x80A2
+#define GL_2PASS_1_EXT 0x80A3
+#define GL_4PASS_0_EXT 0x80A4
+#define GL_4PASS_1_EXT 0x80A5
+#define GL_4PASS_2_EXT 0x80A6
+#define GL_4PASS_3_EXT 0x80A7
+#define GL_SAMPLE_BUFFERS_EXT 0x80A8
+#define GL_SAMPLES_EXT 0x80A9
+#define GL_SAMPLE_MASK_VALUE_EXT 0x80AA
+#define GL_SAMPLE_MASK_INVERT_EXT 0x80AB
+#define GL_SAMPLE_PATTERN_EXT 0x80AC
+#define GL_MULTISAMPLE_BIT_EXT 0x20000000
+typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskEXT (GLclampf value, GLboolean invert);
+GLAPI void APIENTRY glSamplePatternEXT (GLenum pattern);
+#endif
+#endif /* GL_EXT_multisample */
+
+#ifndef GL_EXT_packed_depth_stencil
+#define GL_EXT_packed_depth_stencil 1
+#define GL_DEPTH_STENCIL_EXT 0x84F9
+#define GL_UNSIGNED_INT_24_8_EXT 0x84FA
+#define GL_DEPTH24_STENCIL8_EXT 0x88F0
+#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1
+#endif /* GL_EXT_packed_depth_stencil */
+
+#ifndef GL_EXT_packed_float
+#define GL_EXT_packed_float 1
+#define GL_R11F_G11F_B10F_EXT 0x8C3A
+#define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B
+#define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C
+#endif /* GL_EXT_packed_float */
+
+#ifndef GL_EXT_packed_pixels
+#define GL_EXT_packed_pixels 1
+#define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034
+#define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035
+#define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036
+#endif /* GL_EXT_packed_pixels */
+
+#ifndef GL_EXT_paletted_texture
+#define GL_EXT_paletted_texture 1
+#define GL_COLOR_INDEX1_EXT 0x80E2
+#define GL_COLOR_INDEX2_EXT 0x80E3
+#define GL_COLOR_INDEX4_EXT 0x80E4
+#define GL_COLOR_INDEX8_EXT 0x80E5
+#define GL_COLOR_INDEX12_EXT 0x80E6
+#define GL_COLOR_INDEX16_EXT 0x80E7
+#define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED
+typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, void *data);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table);
+GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, void *data);
+GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_EXT_paletted_texture */
+
+#ifndef GL_EXT_pixel_buffer_object
+#define GL_EXT_pixel_buffer_object 1
+#define GL_PIXEL_PACK_BUFFER_EXT 0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF
+#endif /* GL_EXT_pixel_buffer_object */
+
+#ifndef GL_EXT_pixel_transform
+#define GL_EXT_pixel_transform 1
+#define GL_PIXEL_TRANSFORM_2D_EXT 0x8330
+#define GL_PIXEL_MAG_FILTER_EXT 0x8331
+#define GL_PIXEL_MIN_FILTER_EXT 0x8332
+#define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333
+#define GL_CUBIC_EXT 0x8334
+#define GL_AVERAGE_EXT 0x8335
+#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336
+#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337
+#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glGetPixelTransformParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetPixelTransformParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_EXT_pixel_transform */
+
+#ifndef GL_EXT_pixel_transform_color_table
+#define GL_EXT_pixel_transform_color_table 1
+#endif /* GL_EXT_pixel_transform_color_table */
+
+#ifndef GL_EXT_point_parameters
+#define GL_EXT_point_parameters 1
+#define GL_POINT_SIZE_MIN_EXT 0x8126
+#define GL_POINT_SIZE_MAX_EXT 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128
+#define GL_DISTANCE_ATTENUATION_EXT 0x8129
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfEXT (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPointParameterfvEXT (GLenum pname, const GLfloat *params);
+#endif
+#endif /* GL_EXT_point_parameters */
+
+#ifndef GL_EXT_polygon_offset
+#define GL_EXT_polygon_offset 1
+#define GL_POLYGON_OFFSET_EXT 0x8037
+#define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038
+#define GL_POLYGON_OFFSET_BIAS_EXT 0x8039
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat factor, GLfloat bias);
+#endif
+#endif /* GL_EXT_polygon_offset */
+
+#ifndef GL_EXT_provoking_vertex
+#define GL_EXT_provoking_vertex 1
+#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C
+#define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D
+#define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E
+#define GL_PROVOKING_VERTEX_EXT 0x8E4F
+typedef void (APIENTRYP PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProvokingVertexEXT (GLenum mode);
+#endif
+#endif /* GL_EXT_provoking_vertex */
+
+#ifndef GL_EXT_rescale_normal
+#define GL_EXT_rescale_normal 1
+#define GL_RESCALE_NORMAL_EXT 0x803A
+#endif /* GL_EXT_rescale_normal */
+
+#ifndef GL_EXT_secondary_color
+#define GL_EXT_secondary_color 1
+#define GL_COLOR_SUM_EXT 0x8458
+#define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D
+#define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue);
+GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v);
+GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue);
+GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *v);
+GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue);
+GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *v);
+GLAPI void APIENTRY glSecondaryColor3iEXT (GLint red, GLint green, GLint blue);
+GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *v);
+GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue);
+GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *v);
+GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue);
+GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *v);
+GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue);
+GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v);
+GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue);
+GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v);
+GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_EXT_secondary_color */
+
+#ifndef GL_EXT_separate_shader_objects
+#define GL_EXT_separate_shader_objects 1
+#define GL_ACTIVE_PROGRAM_EXT 0x8B8D
+typedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program);
+typedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program);
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program);
+GLAPI void APIENTRY glActiveProgramEXT (GLuint program);
+GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string);
+#endif
+#endif /* GL_EXT_separate_shader_objects */
+
+#ifndef GL_EXT_separate_specular_color
+#define GL_EXT_separate_specular_color 1
+#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8
+#define GL_SINGLE_COLOR_EXT 0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA
+#endif /* GL_EXT_separate_specular_color */
+
+#ifndef GL_EXT_shader_image_load_formatted
+#define GL_EXT_shader_image_load_formatted 1
+#endif /* GL_EXT_shader_image_load_formatted */
+
+#ifndef GL_EXT_shader_image_load_store
+#define GL_EXT_shader_image_load_store 1
+#define GL_MAX_IMAGE_UNITS_EXT 0x8F38
+#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39
+#define GL_IMAGE_BINDING_NAME_EXT 0x8F3A
+#define GL_IMAGE_BINDING_LEVEL_EXT 0x8F3B
+#define GL_IMAGE_BINDING_LAYERED_EXT 0x8F3C
+#define GL_IMAGE_BINDING_LAYER_EXT 0x8F3D
+#define GL_IMAGE_BINDING_ACCESS_EXT 0x8F3E
+#define GL_IMAGE_1D_EXT 0x904C
+#define GL_IMAGE_2D_EXT 0x904D
+#define GL_IMAGE_3D_EXT 0x904E
+#define GL_IMAGE_2D_RECT_EXT 0x904F
+#define GL_IMAGE_CUBE_EXT 0x9050
+#define GL_IMAGE_BUFFER_EXT 0x9051
+#define GL_IMAGE_1D_ARRAY_EXT 0x9052
+#define GL_IMAGE_2D_ARRAY_EXT 0x9053
+#define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054
+#define GL_IMAGE_2D_MULTISAMPLE_EXT 0x9055
+#define GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056
+#define GL_INT_IMAGE_1D_EXT 0x9057
+#define GL_INT_IMAGE_2D_EXT 0x9058
+#define GL_INT_IMAGE_3D_EXT 0x9059
+#define GL_INT_IMAGE_2D_RECT_EXT 0x905A
+#define GL_INT_IMAGE_CUBE_EXT 0x905B
+#define GL_INT_IMAGE_BUFFER_EXT 0x905C
+#define GL_INT_IMAGE_1D_ARRAY_EXT 0x905D
+#define GL_INT_IMAGE_2D_ARRAY_EXT 0x905E
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F
+#define GL_INT_IMAGE_2D_MULTISAMPLE_EXT 0x9060
+#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061
+#define GL_UNSIGNED_INT_IMAGE_1D_EXT 0x9062
+#define GL_UNSIGNED_INT_IMAGE_2D_EXT 0x9063
+#define GL_UNSIGNED_INT_IMAGE_3D_EXT 0x9064
+#define GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065
+#define GL_UNSIGNED_INT_IMAGE_CUBE_EXT 0x9066
+#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067
+#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C
+#define GL_MAX_IMAGE_SAMPLES_EXT 0x906D
+#define GL_IMAGE_BINDING_FORMAT_EXT 0x906E
+#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001
+#define GL_ELEMENT_ARRAY_BARRIER_BIT_EXT 0x00000002
+#define GL_UNIFORM_BARRIER_BIT_EXT 0x00000004
+#define GL_TEXTURE_FETCH_BARRIER_BIT_EXT 0x00000008
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020
+#define GL_COMMAND_BARRIER_BIT_EXT 0x00000040
+#define GL_PIXEL_BUFFER_BARRIER_BIT_EXT 0x00000080
+#define GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100
+#define GL_BUFFER_UPDATE_BARRIER_BIT_EXT 0x00000200
+#define GL_FRAMEBUFFER_BARRIER_BIT_EXT 0x00000400
+#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800
+#define GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000
+#define GL_ALL_BARRIER_BITS_EXT 0xFFFFFFFF
+typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREEXTPROC) (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format);
+typedef void (APIENTRYP PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindImageTextureEXT (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format);
+GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers);
+#endif
+#endif /* GL_EXT_shader_image_load_store */
+
+#ifndef GL_EXT_shader_integer_mix
+#define GL_EXT_shader_integer_mix 1
+#endif /* GL_EXT_shader_integer_mix */
+
+#ifndef GL_EXT_shadow_funcs
+#define GL_EXT_shadow_funcs 1
+#endif /* GL_EXT_shadow_funcs */
+
+#ifndef GL_EXT_shared_texture_palette
+#define GL_EXT_shared_texture_palette 1
+#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB
+#endif /* GL_EXT_shared_texture_palette */
+
+#ifndef GL_EXT_stencil_clear_tag
+#define GL_EXT_stencil_clear_tag 1
+#define GL_STENCIL_TAG_BITS_EXT 0x88F2
+#define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3
+typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStencilClearTagEXT (GLsizei stencilTagBits, GLuint stencilClearTag);
+#endif
+#endif /* GL_EXT_stencil_clear_tag */
+
+#ifndef GL_EXT_stencil_two_side
+#define GL_EXT_stencil_two_side 1
+#define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910
+#define GL_ACTIVE_STENCIL_FACE_EXT 0x8911
+typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face);
+#endif
+#endif /* GL_EXT_stencil_two_side */
+
+#ifndef GL_EXT_stencil_wrap
+#define GL_EXT_stencil_wrap 1
+#define GL_INCR_WRAP_EXT 0x8507
+#define GL_DECR_WRAP_EXT 0x8508
+#endif /* GL_EXT_stencil_wrap */
+
+#ifndef GL_EXT_subtexture
+#define GL_EXT_subtexture 1
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+#endif
+#endif /* GL_EXT_subtexture */
+
+#ifndef GL_EXT_texture
+#define GL_EXT_texture 1
+#define GL_ALPHA4_EXT 0x803B
+#define GL_ALPHA8_EXT 0x803C
+#define GL_ALPHA12_EXT 0x803D
+#define GL_ALPHA16_EXT 0x803E
+#define GL_LUMINANCE4_EXT 0x803F
+#define GL_LUMINANCE8_EXT 0x8040
+#define GL_LUMINANCE12_EXT 0x8041
+#define GL_LUMINANCE16_EXT 0x8042
+#define GL_LUMINANCE4_ALPHA4_EXT 0x8043
+#define GL_LUMINANCE6_ALPHA2_EXT 0x8044
+#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
+#define GL_LUMINANCE12_ALPHA4_EXT 0x8046
+#define GL_LUMINANCE12_ALPHA12_EXT 0x8047
+#define GL_LUMINANCE16_ALPHA16_EXT 0x8048
+#define GL_INTENSITY_EXT 0x8049
+#define GL_INTENSITY4_EXT 0x804A
+#define GL_INTENSITY8_EXT 0x804B
+#define GL_INTENSITY12_EXT 0x804C
+#define GL_INTENSITY16_EXT 0x804D
+#define GL_RGB2_EXT 0x804E
+#define GL_RGB4_EXT 0x804F
+#define GL_RGB5_EXT 0x8050
+#define GL_RGB8_EXT 0x8051
+#define GL_RGB10_EXT 0x8052
+#define GL_RGB12_EXT 0x8053
+#define GL_RGB16_EXT 0x8054
+#define GL_RGBA2_EXT 0x8055
+#define GL_RGBA4_EXT 0x8056
+#define GL_RGB5_A1_EXT 0x8057
+#define GL_RGBA8_EXT 0x8058
+#define GL_RGB10_A2_EXT 0x8059
+#define GL_RGBA12_EXT 0x805A
+#define GL_RGBA16_EXT 0x805B
+#define GL_TEXTURE_RED_SIZE_EXT 0x805C
+#define GL_TEXTURE_GREEN_SIZE_EXT 0x805D
+#define GL_TEXTURE_BLUE_SIZE_EXT 0x805E
+#define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F
+#define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060
+#define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061
+#define GL_REPLACE_EXT 0x8062
+#define GL_PROXY_TEXTURE_1D_EXT 0x8063
+#define GL_PROXY_TEXTURE_2D_EXT 0x8064
+#define GL_TEXTURE_TOO_LARGE_EXT 0x8065
+#endif /* GL_EXT_texture */
+
+#ifndef GL_EXT_texture3D
+#define GL_EXT_texture3D 1
+#define GL_PACK_SKIP_IMAGES_EXT 0x806B
+#define GL_PACK_IMAGE_HEIGHT_EXT 0x806C
+#define GL_UNPACK_SKIP_IMAGES_EXT 0x806D
+#define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E
+#define GL_TEXTURE_3D_EXT 0x806F
+#define GL_PROXY_TEXTURE_3D_EXT 0x8070
+#define GL_TEXTURE_DEPTH_EXT 0x8071
+#define GL_TEXTURE_WRAP_R_EXT 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073
+typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+#endif
+#endif /* GL_EXT_texture3D */
+
+#ifndef GL_EXT_texture_array
+#define GL_EXT_texture_array 1
+#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18
+#define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19
+#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A
+#define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B
+#define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C
+#define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D
+#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF
+#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E
+#endif /* GL_EXT_texture_array */
+
+#ifndef GL_EXT_texture_buffer_object
+#define GL_EXT_texture_buffer_object 1
+#define GL_TEXTURE_BUFFER_EXT 0x8C2A
+#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B
+#define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C
+#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D
+#define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E
+typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer);
+#endif
+#endif /* GL_EXT_texture_buffer_object */
+
+#ifndef GL_EXT_texture_compression_latc
+#define GL_EXT_texture_compression_latc 1
+#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70
+#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71
+#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72
+#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73
+#endif /* GL_EXT_texture_compression_latc */
+
+#ifndef GL_EXT_texture_compression_rgtc
+#define GL_EXT_texture_compression_rgtc 1
+#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB
+#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC
+#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD
+#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE
+#endif /* GL_EXT_texture_compression_rgtc */
+
+#ifndef GL_EXT_texture_compression_s3tc
+#define GL_EXT_texture_compression_s3tc 1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+#endif /* GL_EXT_texture_compression_s3tc */
+
+#ifndef GL_EXT_texture_cube_map
+#define GL_EXT_texture_cube_map 1
+#define GL_NORMAL_MAP_EXT 0x8511
+#define GL_REFLECTION_MAP_EXT 0x8512
+#define GL_TEXTURE_CUBE_MAP_EXT 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C
+#endif /* GL_EXT_texture_cube_map */
+
+#ifndef GL_EXT_texture_env_add
+#define GL_EXT_texture_env_add 1
+#endif /* GL_EXT_texture_env_add */
+
+#ifndef GL_EXT_texture_env_combine
+#define GL_EXT_texture_env_combine 1
+#define GL_COMBINE_EXT 0x8570
+#define GL_COMBINE_RGB_EXT 0x8571
+#define GL_COMBINE_ALPHA_EXT 0x8572
+#define GL_RGB_SCALE_EXT 0x8573
+#define GL_ADD_SIGNED_EXT 0x8574
+#define GL_INTERPOLATE_EXT 0x8575
+#define GL_CONSTANT_EXT 0x8576
+#define GL_PRIMARY_COLOR_EXT 0x8577
+#define GL_PREVIOUS_EXT 0x8578
+#define GL_SOURCE0_RGB_EXT 0x8580
+#define GL_SOURCE1_RGB_EXT 0x8581
+#define GL_SOURCE2_RGB_EXT 0x8582
+#define GL_SOURCE0_ALPHA_EXT 0x8588
+#define GL_SOURCE1_ALPHA_EXT 0x8589
+#define GL_SOURCE2_ALPHA_EXT 0x858A
+#define GL_OPERAND0_RGB_EXT 0x8590
+#define GL_OPERAND1_RGB_EXT 0x8591
+#define GL_OPERAND2_RGB_EXT 0x8592
+#define GL_OPERAND0_ALPHA_EXT 0x8598
+#define GL_OPERAND1_ALPHA_EXT 0x8599
+#define GL_OPERAND2_ALPHA_EXT 0x859A
+#endif /* GL_EXT_texture_env_combine */
+
+#ifndef GL_EXT_texture_env_dot3
+#define GL_EXT_texture_env_dot3 1
+#define GL_DOT3_RGB_EXT 0x8740
+#define GL_DOT3_RGBA_EXT 0x8741
+#endif /* GL_EXT_texture_env_dot3 */
+
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif /* GL_EXT_texture_filter_anisotropic */
+
+#ifndef GL_EXT_texture_integer
+#define GL_EXT_texture_integer 1
+#define GL_RGBA32UI_EXT 0x8D70
+#define GL_RGB32UI_EXT 0x8D71
+#define GL_ALPHA32UI_EXT 0x8D72
+#define GL_INTENSITY32UI_EXT 0x8D73
+#define GL_LUMINANCE32UI_EXT 0x8D74
+#define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75
+#define GL_RGBA16UI_EXT 0x8D76
+#define GL_RGB16UI_EXT 0x8D77
+#define GL_ALPHA16UI_EXT 0x8D78
+#define GL_INTENSITY16UI_EXT 0x8D79
+#define GL_LUMINANCE16UI_EXT 0x8D7A
+#define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B
+#define GL_RGBA8UI_EXT 0x8D7C
+#define GL_RGB8UI_EXT 0x8D7D
+#define GL_ALPHA8UI_EXT 0x8D7E
+#define GL_INTENSITY8UI_EXT 0x8D7F
+#define GL_LUMINANCE8UI_EXT 0x8D80
+#define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81
+#define GL_RGBA32I_EXT 0x8D82
+#define GL_RGB32I_EXT 0x8D83
+#define GL_ALPHA32I_EXT 0x8D84
+#define GL_INTENSITY32I_EXT 0x8D85
+#define GL_LUMINANCE32I_EXT 0x8D86
+#define GL_LUMINANCE_ALPHA32I_EXT 0x8D87
+#define GL_RGBA16I_EXT 0x8D88
+#define GL_RGB16I_EXT 0x8D89
+#define GL_ALPHA16I_EXT 0x8D8A
+#define GL_INTENSITY16I_EXT 0x8D8B
+#define GL_LUMINANCE16I_EXT 0x8D8C
+#define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D
+#define GL_RGBA8I_EXT 0x8D8E
+#define GL_RGB8I_EXT 0x8D8F
+#define GL_ALPHA8I_EXT 0x8D90
+#define GL_INTENSITY8I_EXT 0x8D91
+#define GL_LUMINANCE8I_EXT 0x8D92
+#define GL_LUMINANCE_ALPHA8I_EXT 0x8D93
+#define GL_RED_INTEGER_EXT 0x8D94
+#define GL_GREEN_INTEGER_EXT 0x8D95
+#define GL_BLUE_INTEGER_EXT 0x8D96
+#define GL_ALPHA_INTEGER_EXT 0x8D97
+#define GL_RGB_INTEGER_EXT 0x8D98
+#define GL_RGBA_INTEGER_EXT 0x8D99
+#define GL_BGR_INTEGER_EXT 0x8D9A
+#define GL_BGRA_INTEGER_EXT 0x8D9B
+#define GL_LUMINANCE_INTEGER_EXT 0x8D9C
+#define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D
+#define GL_RGBA_INTEGER_MODE_EXT 0x8D9E
+typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha);
+typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params);
+GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glClearColorIiEXT (GLint red, GLint green, GLint blue, GLint alpha);
+GLAPI void APIENTRY glClearColorIuiEXT (GLuint red, GLuint green, GLuint blue, GLuint alpha);
+#endif
+#endif /* GL_EXT_texture_integer */
+
+#ifndef GL_EXT_texture_lod_bias
+#define GL_EXT_texture_lod_bias 1
+#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD
+#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500
+#define GL_TEXTURE_LOD_BIAS_EXT 0x8501
+#endif /* GL_EXT_texture_lod_bias */
+
+#ifndef GL_EXT_texture_mirror_clamp
+#define GL_EXT_texture_mirror_clamp 1
+#define GL_MIRROR_CLAMP_EXT 0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743
+#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912
+#endif /* GL_EXT_texture_mirror_clamp */
+
+#ifndef GL_EXT_texture_object
+#define GL_EXT_texture_object 1
+#define GL_TEXTURE_PRIORITY_EXT 0x8066
+#define GL_TEXTURE_RESIDENT_EXT 0x8067
+#define GL_TEXTURE_1D_BINDING_EXT 0x8068
+#define GL_TEXTURE_2D_BINDING_EXT 0x8069
+#define GL_TEXTURE_3D_BINDING_EXT 0x806A
+typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture);
+typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures);
+typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures);
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture);
+typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences);
+GLAPI void APIENTRY glBindTextureEXT (GLenum target, GLuint texture);
+GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures);
+GLAPI void APIENTRY glGenTexturesEXT (GLsizei n, GLuint *textures);
+GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint texture);
+GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities);
+#endif
+#endif /* GL_EXT_texture_object */
+
+#ifndef GL_EXT_texture_perturb_normal
+#define GL_EXT_texture_perturb_normal 1
+#define GL_PERTURB_EXT 0x85AE
+#define GL_TEXTURE_NORMAL_EXT 0x85AF
+typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureNormalEXT (GLenum mode);
+#endif
+#endif /* GL_EXT_texture_perturb_normal */
+
+#ifndef GL_EXT_texture_sRGB
+#define GL_EXT_texture_sRGB 1
+#define GL_SRGB_EXT 0x8C40
+#define GL_SRGB8_EXT 0x8C41
+#define GL_SRGB_ALPHA_EXT 0x8C42
+#define GL_SRGB8_ALPHA8_EXT 0x8C43
+#define GL_SLUMINANCE_ALPHA_EXT 0x8C44
+#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45
+#define GL_SLUMINANCE_EXT 0x8C46
+#define GL_SLUMINANCE8_EXT 0x8C47
+#define GL_COMPRESSED_SRGB_EXT 0x8C48
+#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49
+#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A
+#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B
+#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
+#endif /* GL_EXT_texture_sRGB */
+
+#ifndef GL_EXT_texture_sRGB_decode
+#define GL_EXT_texture_sRGB_decode 1
+#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48
+#define GL_DECODE_EXT 0x8A49
+#define GL_SKIP_DECODE_EXT 0x8A4A
+#endif /* GL_EXT_texture_sRGB_decode */
+
+#ifndef GL_EXT_texture_shared_exponent
+#define GL_EXT_texture_shared_exponent 1
+#define GL_RGB9_E5_EXT 0x8C3D
+#define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E
+#define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F
+#endif /* GL_EXT_texture_shared_exponent */
+
+#ifndef GL_EXT_texture_snorm
+#define GL_EXT_texture_snorm 1
+#define GL_ALPHA_SNORM 0x9010
+#define GL_LUMINANCE_SNORM 0x9011
+#define GL_LUMINANCE_ALPHA_SNORM 0x9012
+#define GL_INTENSITY_SNORM 0x9013
+#define GL_ALPHA8_SNORM 0x9014
+#define GL_LUMINANCE8_SNORM 0x9015
+#define GL_LUMINANCE8_ALPHA8_SNORM 0x9016
+#define GL_INTENSITY8_SNORM 0x9017
+#define GL_ALPHA16_SNORM 0x9018
+#define GL_LUMINANCE16_SNORM 0x9019
+#define GL_LUMINANCE16_ALPHA16_SNORM 0x901A
+#define GL_INTENSITY16_SNORM 0x901B
+#define GL_RED_SNORM 0x8F90
+#define GL_RG_SNORM 0x8F91
+#define GL_RGB_SNORM 0x8F92
+#define GL_RGBA_SNORM 0x8F93
+#endif /* GL_EXT_texture_snorm */
+
+#ifndef GL_EXT_texture_swizzle
+#define GL_EXT_texture_swizzle 1
+#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42
+#define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43
+#define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44
+#define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45
+#define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46
+#endif /* GL_EXT_texture_swizzle */
+
+#ifndef GL_EXT_timer_query
+#define GL_EXT_timer_query 1
+#define GL_TIME_ELAPSED_EXT 0x88BF
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64 *params);
+GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64 *params);
+#endif
+#endif /* GL_EXT_timer_query */
+
+#ifndef GL_EXT_transform_feedback
+#define GL_EXT_transform_feedback 1
+#define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F
+#define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C
+#define GL_SEPARATE_ATTRIBS_EXT 0x8C8D
+#define GL_PRIMITIVES_GENERATED_EXT 0x8C87
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88
+#define GL_RASTERIZER_DISCARD_EXT 0x8C89
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80
+#define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F
+#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76
+typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode);
+typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void);
+typedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset);
+typedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum primitiveMode);
+GLAPI void APIENTRY glEndTransformFeedbackEXT (void);
+GLAPI void APIENTRY glBindBufferRangeEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glBindBufferOffsetEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset);
+GLAPI void APIENTRY glBindBufferBaseEXT (GLenum target, GLuint index, GLuint buffer);
+GLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
+GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+#endif
+#endif /* GL_EXT_transform_feedback */
+
+#ifndef GL_EXT_vertex_array
+#define GL_EXT_vertex_array 1
+#define GL_VERTEX_ARRAY_EXT 0x8074
+#define GL_NORMAL_ARRAY_EXT 0x8075
+#define GL_COLOR_ARRAY_EXT 0x8076
+#define GL_INDEX_ARRAY_EXT 0x8077
+#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078
+#define GL_EDGE_FLAG_ARRAY_EXT 0x8079
+#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A
+#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B
+#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C
+#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D
+#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E
+#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F
+#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080
+#define GL_COLOR_ARRAY_SIZE_EXT 0x8081
+#define GL_COLOR_ARRAY_TYPE_EXT 0x8082
+#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083
+#define GL_COLOR_ARRAY_COUNT_EXT 0x8084
+#define GL_INDEX_ARRAY_TYPE_EXT 0x8085
+#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086
+#define GL_INDEX_ARRAY_COUNT_EXT 0x8087
+#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A
+#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B
+#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C
+#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D
+#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E
+#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F
+#define GL_COLOR_ARRAY_POINTER_EXT 0x8090
+#define GL_INDEX_ARRAY_POINTER_EXT 0x8091
+#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092
+#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093
+typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i);
+typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer);
+typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, void **params);
+typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glArrayElementEXT (GLint i);
+GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+GLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count);
+GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer);
+GLAPI void APIENTRY glGetPointervEXT (GLenum pname, void **params);
+GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+#endif
+#endif /* GL_EXT_vertex_array */
+
+#ifndef GL_EXT_vertex_array_bgra
+#define GL_EXT_vertex_array_bgra 1
+#endif /* GL_EXT_vertex_array_bgra */
+
+#ifndef GL_EXT_vertex_attrib_64bit
+#define GL_EXT_vertex_attrib_64bit 1
+#define GL_DOUBLE_VEC2_EXT 0x8FFC
+#define GL_DOUBLE_VEC3_EXT 0x8FFD
+#define GL_DOUBLE_VEC4_EXT 0x8FFE
+#define GL_DOUBLE_MAT2_EXT 0x8F46
+#define GL_DOUBLE_MAT3_EXT 0x8F47
+#define GL_DOUBLE_MAT4_EXT 0x8F48
+#define GL_DOUBLE_MAT2x3_EXT 0x8F49
+#define GL_DOUBLE_MAT2x4_EXT 0x8F4A
+#define GL_DOUBLE_MAT3x2_EXT 0x8F4B
+#define GL_DOUBLE_MAT3x4_EXT 0x8F4C
+#define GL_DOUBLE_MAT4x2_EXT 0x8F4D
+#define GL_DOUBLE_MAT4x3_EXT 0x8F4E
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DEXTPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DEXTPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x);
+GLAPI void APIENTRY glVertexAttribL2dEXT (GLuint index, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexAttribL3dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexAttribL4dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params);
+#endif
+#endif /* GL_EXT_vertex_attrib_64bit */
+
+#ifndef GL_EXT_vertex_shader
+#define GL_EXT_vertex_shader 1
+#define GL_VERTEX_SHADER_EXT 0x8780
+#define GL_VERTEX_SHADER_BINDING_EXT 0x8781
+#define GL_OP_INDEX_EXT 0x8782
+#define GL_OP_NEGATE_EXT 0x8783
+#define GL_OP_DOT3_EXT 0x8784
+#define GL_OP_DOT4_EXT 0x8785
+#define GL_OP_MUL_EXT 0x8786
+#define GL_OP_ADD_EXT 0x8787
+#define GL_OP_MADD_EXT 0x8788
+#define GL_OP_FRAC_EXT 0x8789
+#define GL_OP_MAX_EXT 0x878A
+#define GL_OP_MIN_EXT 0x878B
+#define GL_OP_SET_GE_EXT 0x878C
+#define GL_OP_SET_LT_EXT 0x878D
+#define GL_OP_CLAMP_EXT 0x878E
+#define GL_OP_FLOOR_EXT 0x878F
+#define GL_OP_ROUND_EXT 0x8790
+#define GL_OP_EXP_BASE_2_EXT 0x8791
+#define GL_OP_LOG_BASE_2_EXT 0x8792
+#define GL_OP_POWER_EXT 0x8793
+#define GL_OP_RECIP_EXT 0x8794
+#define GL_OP_RECIP_SQRT_EXT 0x8795
+#define GL_OP_SUB_EXT 0x8796
+#define GL_OP_CROSS_PRODUCT_EXT 0x8797
+#define GL_OP_MULTIPLY_MATRIX_EXT 0x8798
+#define GL_OP_MOV_EXT 0x8799
+#define GL_OUTPUT_VERTEX_EXT 0x879A
+#define GL_OUTPUT_COLOR0_EXT 0x879B
+#define GL_OUTPUT_COLOR1_EXT 0x879C
+#define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D
+#define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E
+#define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F
+#define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0
+#define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1
+#define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2
+#define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3
+#define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4
+#define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5
+#define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6
+#define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7
+#define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8
+#define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9
+#define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA
+#define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB
+#define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC
+#define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD
+#define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE
+#define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF
+#define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0
+#define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1
+#define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2
+#define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3
+#define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4
+#define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5
+#define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6
+#define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7
+#define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8
+#define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9
+#define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA
+#define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB
+#define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC
+#define GL_OUTPUT_FOG_EXT 0x87BD
+#define GL_SCALAR_EXT 0x87BE
+#define GL_VECTOR_EXT 0x87BF
+#define GL_MATRIX_EXT 0x87C0
+#define GL_VARIANT_EXT 0x87C1
+#define GL_INVARIANT_EXT 0x87C2
+#define GL_LOCAL_CONSTANT_EXT 0x87C3
+#define GL_LOCAL_EXT 0x87C4
+#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5
+#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6
+#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7
+#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8
+#define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE
+#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF
+#define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0
+#define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1
+#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2
+#define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3
+#define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4
+#define GL_X_EXT 0x87D5
+#define GL_Y_EXT 0x87D6
+#define GL_Z_EXT 0x87D7
+#define GL_W_EXT 0x87D8
+#define GL_NEGATIVE_X_EXT 0x87D9
+#define GL_NEGATIVE_Y_EXT 0x87DA
+#define GL_NEGATIVE_Z_EXT 0x87DB
+#define GL_NEGATIVE_W_EXT 0x87DC
+#define GL_ZERO_EXT 0x87DD
+#define GL_ONE_EXT 0x87DE
+#define GL_NEGATIVE_ONE_EXT 0x87DF
+#define GL_NORMALIZED_RANGE_EXT 0x87E0
+#define GL_FULL_RANGE_EXT 0x87E1
+#define GL_CURRENT_VERTEX_EXT 0x87E2
+#define GL_MVP_MATRIX_EXT 0x87E3
+#define GL_VARIANT_VALUE_EXT 0x87E4
+#define GL_VARIANT_DATATYPE_EXT 0x87E5
+#define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6
+#define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7
+#define GL_VARIANT_ARRAY_EXT 0x87E8
+#define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9
+#define GL_INVARIANT_VALUE_EXT 0x87EA
+#define GL_INVARIANT_DATATYPE_EXT 0x87EB
+#define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC
+#define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED
+typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1);
+typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2);
+typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);
+typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components);
+typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const void *addr);
+typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const void *addr);
+typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr);
+typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr);
+typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr);
+typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr);
+typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr);
+typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr);
+typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const void *addr);
+typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value);
+typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap);
+typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, void **data);
+typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginVertexShaderEXT (void);
+GLAPI void APIENTRY glEndVertexShaderEXT (void);
+GLAPI void APIENTRY glBindVertexShaderEXT (GLuint id);
+GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint range);
+GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint id);
+GLAPI void APIENTRY glShaderOp1EXT (GLenum op, GLuint res, GLuint arg1);
+GLAPI void APIENTRY glShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2);
+GLAPI void APIENTRY glShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);
+GLAPI void APIENTRY glSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+GLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+GLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num);
+GLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num);
+GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components);
+GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const void *addr);
+GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const void *addr);
+GLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr);
+GLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr);
+GLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr);
+GLAPI void APIENTRY glVariantfvEXT (GLuint id, const GLfloat *addr);
+GLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr);
+GLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr);
+GLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr);
+GLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr);
+GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const void *addr);
+GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id);
+GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id);
+GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value);
+GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum face, GLenum value);
+GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value);
+GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum unit, GLenum value);
+GLAPI GLuint APIENTRY glBindParameterEXT (GLenum value);
+GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap);
+GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data);
+GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data);
+GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data);
+GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, void **data);
+GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data);
+GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data);
+GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data);
+GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data);
+GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data);
+GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data);
+#endif
+#endif /* GL_EXT_vertex_shader */
+
+#ifndef GL_EXT_vertex_weighting
+#define GL_EXT_vertex_weighting 1
+#define GL_MODELVIEW0_STACK_DEPTH_EXT 0x0BA3
+#define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502
+#define GL_MODELVIEW0_MATRIX_EXT 0x0BA6
+#define GL_MODELVIEW1_MATRIX_EXT 0x8506
+#define GL_VERTEX_WEIGHTING_EXT 0x8509
+#define GL_MODELVIEW0_EXT 0x1700
+#define GL_MODELVIEW1_EXT 0x850A
+#define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B
+#define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C
+#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D
+#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E
+#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F
+#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight);
+GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight);
+GLAPI void APIENTRY glVertexWeightPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_EXT_vertex_weighting */
+
+#ifndef GL_EXT_x11_sync_object
+#define GL_EXT_x11_sync_object 1
+#define GL_SYNC_X11_FENCE_EXT 0x90E1
+typedef GLsync (APIENTRYP PFNGLIMPORTSYNCEXTPROC) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLsync APIENTRY glImportSyncEXT (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags);
+#endif
+#endif /* GL_EXT_x11_sync_object */
+
+#ifndef GL_GREMEDY_frame_terminator
+#define GL_GREMEDY_frame_terminator 1
+typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFrameTerminatorGREMEDY (void);
+#endif
+#endif /* GL_GREMEDY_frame_terminator */
+
+#ifndef GL_GREMEDY_string_marker
+#define GL_GREMEDY_string_marker 1
+typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const void *string);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const void *string);
+#endif
+#endif /* GL_GREMEDY_string_marker */
+
+#ifndef GL_HP_convolution_border_modes
+#define GL_HP_convolution_border_modes 1
+#define GL_IGNORE_BORDER_HP 0x8150
+#define GL_CONSTANT_BORDER_HP 0x8151
+#define GL_REPLICATE_BORDER_HP 0x8153
+#define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154
+#endif /* GL_HP_convolution_border_modes */
+
+#ifndef GL_HP_image_transform
+#define GL_HP_image_transform 1
+#define GL_IMAGE_SCALE_X_HP 0x8155
+#define GL_IMAGE_SCALE_Y_HP 0x8156
+#define GL_IMAGE_TRANSLATE_X_HP 0x8157
+#define GL_IMAGE_TRANSLATE_Y_HP 0x8158
+#define GL_IMAGE_ROTATE_ANGLE_HP 0x8159
+#define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A
+#define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B
+#define GL_IMAGE_MAG_FILTER_HP 0x815C
+#define GL_IMAGE_MIN_FILTER_HP 0x815D
+#define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E
+#define GL_CUBIC_HP 0x815F
+#define GL_AVERAGE_HP 0x8160
+#define GL_IMAGE_TRANSFORM_2D_HP 0x8161
+#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162
+#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glImageTransformParameteriHP (GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_HP_image_transform */
+
+#ifndef GL_HP_occlusion_test
+#define GL_HP_occlusion_test 1
+#define GL_OCCLUSION_TEST_HP 0x8165
+#define GL_OCCLUSION_TEST_RESULT_HP 0x8166
+#endif /* GL_HP_occlusion_test */
+
+#ifndef GL_HP_texture_lighting
+#define GL_HP_texture_lighting 1
+#define GL_TEXTURE_LIGHTING_MODE_HP 0x8167
+#define GL_TEXTURE_POST_SPECULAR_HP 0x8168
+#define GL_TEXTURE_PRE_SPECULAR_HP 0x8169
+#endif /* GL_HP_texture_lighting */
+
+#ifndef GL_IBM_cull_vertex
+#define GL_IBM_cull_vertex 1
+#define GL_CULL_VERTEX_IBM 103050
+#endif /* GL_IBM_cull_vertex */
+
+#ifndef GL_IBM_multimode_draw_arrays
+#define GL_IBM_multimode_draw_arrays 1
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);
+GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride);
+#endif
+#endif /* GL_IBM_multimode_draw_arrays */
+
+#ifndef GL_IBM_rasterpos_clip
+#define GL_IBM_rasterpos_clip 1
+#define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262
+#endif /* GL_IBM_rasterpos_clip */
+
+#ifndef GL_IBM_static_data
+#define GL_IBM_static_data 1
+#define GL_ALL_STATIC_DATA_IBM 103060
+#define GL_STATIC_VERTEX_ARRAY_IBM 103061
+typedef void (APIENTRYP PFNGLFLUSHSTATICDATAIBMPROC) (GLenum target);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushStaticDataIBM (GLenum target);
+#endif
+#endif /* GL_IBM_static_data */
+
+#ifndef GL_IBM_texture_mirrored_repeat
+#define GL_IBM_texture_mirrored_repeat 1
+#define GL_MIRRORED_REPEAT_IBM 0x8370
+#endif /* GL_IBM_texture_mirrored_repeat */
+
+#ifndef GL_IBM_vertex_array_lists
+#define GL_IBM_vertex_array_lists 1
+#define GL_VERTEX_ARRAY_LIST_IBM 103070
+#define GL_NORMAL_ARRAY_LIST_IBM 103071
+#define GL_COLOR_ARRAY_LIST_IBM 103072
+#define GL_INDEX_ARRAY_LIST_IBM 103073
+#define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074
+#define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075
+#define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076
+#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077
+#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080
+#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081
+#define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082
+#define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083
+#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084
+#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085
+#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086
+#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087
+typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean **pointer, GLint ptrstride);
+GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+#endif
+#endif /* GL_IBM_vertex_array_lists */
+
+#ifndef GL_INGR_blend_func_separate
+#define GL_INGR_blend_func_separate 1
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+#endif /* GL_INGR_blend_func_separate */
+
+#ifndef GL_INGR_color_clamp
+#define GL_INGR_color_clamp 1
+#define GL_RED_MIN_CLAMP_INGR 0x8560
+#define GL_GREEN_MIN_CLAMP_INGR 0x8561
+#define GL_BLUE_MIN_CLAMP_INGR 0x8562
+#define GL_ALPHA_MIN_CLAMP_INGR 0x8563
+#define GL_RED_MAX_CLAMP_INGR 0x8564
+#define GL_GREEN_MAX_CLAMP_INGR 0x8565
+#define GL_BLUE_MAX_CLAMP_INGR 0x8566
+#define GL_ALPHA_MAX_CLAMP_INGR 0x8567
+#endif /* GL_INGR_color_clamp */
+
+#ifndef GL_INGR_interlace_read
+#define GL_INGR_interlace_read 1
+#define GL_INTERLACE_READ_INGR 0x8568
+#endif /* GL_INGR_interlace_read */
+
+#ifndef GL_INTEL_fragment_shader_ordering
+#define GL_INTEL_fragment_shader_ordering 1
+#endif /* GL_INTEL_fragment_shader_ordering */
+
+#ifndef GL_INTEL_map_texture
+#define GL_INTEL_map_texture 1
+#define GL_TEXTURE_MEMORY_LAYOUT_INTEL 0x83FF
+#define GL_LAYOUT_DEFAULT_INTEL 0
+#define GL_LAYOUT_LINEAR_INTEL 1
+#define GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2
+typedef void (APIENTRYP PFNGLSYNCTEXTUREINTELPROC) (GLuint texture);
+typedef void (APIENTRYP PFNGLUNMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level);
+typedef void *(APIENTRYP PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSyncTextureINTEL (GLuint texture);
+GLAPI void APIENTRY glUnmapTexture2DINTEL (GLuint texture, GLint level);
+GLAPI void *APIENTRY glMapTexture2DINTEL (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout);
+#endif
+#endif /* GL_INTEL_map_texture */
+
+#ifndef GL_INTEL_parallel_arrays
+#define GL_INTEL_parallel_arrays 1
+#define GL_PARALLEL_ARRAYS_INTEL 0x83F4
+#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5
+#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6
+#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7
+#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8
+typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const void **pointer);
+typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const void **pointer);
+GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const void **pointer);
+GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const void **pointer);
+GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const void **pointer);
+#endif
+#endif /* GL_INTEL_parallel_arrays */
+
+#ifndef GL_INTEL_performance_query
+#define GL_INTEL_performance_query 1
+#define GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x00000000
+#define GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x00000001
+#define GL_PERFQUERY_WAIT_INTEL 0x83FB
+#define GL_PERFQUERY_FLUSH_INTEL 0x83FA
+#define GL_PERFQUERY_DONOT_FLUSH_INTEL 0x83F9
+#define GL_PERFQUERY_COUNTER_EVENT_INTEL 0x94F0
+#define GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1
+#define GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2
+#define GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3
+#define GL_PERFQUERY_COUNTER_RAW_INTEL 0x94F4
+#define GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5
+#define GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8
+#define GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9
+#define GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL 0x94FA
+#define GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL 0x94FB
+#define GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL 0x94FC
+#define GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL 0x94FD
+#define GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE
+#define GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF
+#define GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500
+typedef void (APIENTRYP PFNGLBEGINPERFQUERYINTELPROC) (GLuint queryHandle);
+typedef void (APIENTRYP PFNGLCREATEPERFQUERYINTELPROC) (GLuint queryId, GLuint *queryHandle);
+typedef void (APIENTRYP PFNGLDELETEPERFQUERYINTELPROC) (GLuint queryHandle);
+typedef void (APIENTRYP PFNGLENDPERFQUERYINTELPROC) (GLuint queryHandle);
+typedef void (APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint *queryId);
+typedef void (APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint *nextQueryId);
+typedef void (APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue);
+typedef void (APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten);
+typedef void (APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar *queryName, GLuint *queryId);
+typedef void (APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginPerfQueryINTEL (GLuint queryHandle);
+GLAPI void APIENTRY glCreatePerfQueryINTEL (GLuint queryId, GLuint *queryHandle);
+GLAPI void APIENTRY glDeletePerfQueryINTEL (GLuint queryHandle);
+GLAPI void APIENTRY glEndPerfQueryINTEL (GLuint queryHandle);
+GLAPI void APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId);
+GLAPI void APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId);
+GLAPI void APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue);
+GLAPI void APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten);
+GLAPI void APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId);
+GLAPI void APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask);
+#endif
+#endif /* GL_INTEL_performance_query */
+
+#ifndef GL_MESAX_texture_stack
+#define GL_MESAX_texture_stack 1
+#define GL_TEXTURE_1D_STACK_MESAX 0x8759
+#define GL_TEXTURE_2D_STACK_MESAX 0x875A
+#define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B
+#define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C
+#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D
+#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E
+#endif /* GL_MESAX_texture_stack */
+
+#ifndef GL_MESA_pack_invert
+#define GL_MESA_pack_invert 1
+#define GL_PACK_INVERT_MESA 0x8758
+#endif /* GL_MESA_pack_invert */
+
+#ifndef GL_MESA_resize_buffers
+#define GL_MESA_resize_buffers 1
+typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glResizeBuffersMESA (void);
+#endif
+#endif /* GL_MESA_resize_buffers */
+
+#ifndef GL_MESA_window_pos
+#define GL_MESA_window_pos 1
+typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dMESA (GLdouble x, GLdouble y);
+GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos2fMESA (GLfloat x, GLfloat y);
+GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos2iMESA (GLint x, GLint y);
+GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *v);
+GLAPI void APIENTRY glWindowPos2sMESA (GLshort x, GLshort y);
+GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *v);
+GLAPI void APIENTRY glWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos3iMESA (GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *v);
+GLAPI void APIENTRY glWindowPos3sMESA (GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *v);
+GLAPI void APIENTRY glWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *v);
+GLAPI void APIENTRY glWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *v);
+#endif
+#endif /* GL_MESA_window_pos */
+
+#ifndef GL_MESA_ycbcr_texture
+#define GL_MESA_ycbcr_texture 1
+#define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB
+#define GL_YCBCR_MESA 0x8757
+#endif /* GL_MESA_ycbcr_texture */
+
+#ifndef GL_NVX_conditional_render
+#define GL_NVX_conditional_render 1
+typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVXPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVXPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginConditionalRenderNVX (GLuint id);
+GLAPI void APIENTRY glEndConditionalRenderNVX (void);
+#endif
+#endif /* GL_NVX_conditional_render */
+
+#ifndef GL_NVX_gpu_memory_info
+#define GL_NVX_gpu_memory_info 1
+#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047
+#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048
+#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049
+#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A
+#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B
+#endif /* GL_NVX_gpu_memory_info */
+
+#ifndef GL_NV_bindless_multi_draw_indirect
+#define GL_NV_bindless_multi_draw_indirect 1
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
+GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
+#endif
+#endif /* GL_NV_bindless_multi_draw_indirect */
+
+#ifndef GL_NV_bindless_texture
+#define GL_NV_bindless_texture 1
+typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture);
+typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLENVPROC) (GLuint texture, GLuint sampler);
+typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC) (GLuint64 handle);
+typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLENVPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
+typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle, GLenum access);
+typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64NVPROC) (GLint location, GLuint64 value);
+typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC) (GLuint program, GLint location, GLuint64 value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle);
+typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint64 APIENTRY glGetTextureHandleNV (GLuint texture);
+GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleNV (GLuint texture, GLuint sampler);
+GLAPI void APIENTRY glMakeTextureHandleResidentNV (GLuint64 handle);
+GLAPI void APIENTRY glMakeTextureHandleNonResidentNV (GLuint64 handle);
+GLAPI GLuint64 APIENTRY glGetImageHandleNV (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
+GLAPI void APIENTRY glMakeImageHandleResidentNV (GLuint64 handle, GLenum access);
+GLAPI void APIENTRY glMakeImageHandleNonResidentNV (GLuint64 handle);
+GLAPI void APIENTRY glUniformHandleui64NV (GLint location, GLuint64 value);
+GLAPI void APIENTRY glUniformHandleui64vNV (GLint location, GLsizei count, const GLuint64 *value);
+GLAPI void APIENTRY glProgramUniformHandleui64NV (GLuint program, GLint location, GLuint64 value);
+GLAPI void APIENTRY glProgramUniformHandleui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+GLAPI GLboolean APIENTRY glIsTextureHandleResidentNV (GLuint64 handle);
+GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle);
+#endif
+#endif /* GL_NV_bindless_texture */
+
+#ifndef GL_NV_blend_equation_advanced
+#define GL_NV_blend_equation_advanced 1
+#define GL_BLEND_OVERLAP_NV 0x9281
+#define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280
+#define GL_BLUE_NV 0x1905
+#define GL_COLORBURN_NV 0x929A
+#define GL_COLORDODGE_NV 0x9299
+#define GL_CONJOINT_NV 0x9284
+#define GL_CONTRAST_NV 0x92A1
+#define GL_DARKEN_NV 0x9297
+#define GL_DIFFERENCE_NV 0x929E
+#define GL_DISJOINT_NV 0x9283
+#define GL_DST_ATOP_NV 0x928F
+#define GL_DST_IN_NV 0x928B
+#define GL_DST_NV 0x9287
+#define GL_DST_OUT_NV 0x928D
+#define GL_DST_OVER_NV 0x9289
+#define GL_EXCLUSION_NV 0x92A0
+#define GL_GREEN_NV 0x1904
+#define GL_HARDLIGHT_NV 0x929B
+#define GL_HARDMIX_NV 0x92A9
+#define GL_HSL_COLOR_NV 0x92AF
+#define GL_HSL_HUE_NV 0x92AD
+#define GL_HSL_LUMINOSITY_NV 0x92B0
+#define GL_HSL_SATURATION_NV 0x92AE
+#define GL_INVERT_OVG_NV 0x92B4
+#define GL_INVERT_RGB_NV 0x92A3
+#define GL_LIGHTEN_NV 0x9298
+#define GL_LINEARBURN_NV 0x92A5
+#define GL_LINEARDODGE_NV 0x92A4
+#define GL_LINEARLIGHT_NV 0x92A7
+#define GL_MINUS_CLAMPED_NV 0x92B3
+#define GL_MINUS_NV 0x929F
+#define GL_MULTIPLY_NV 0x9294
+#define GL_OVERLAY_NV 0x9296
+#define GL_PINLIGHT_NV 0x92A8
+#define GL_PLUS_CLAMPED_ALPHA_NV 0x92B2
+#define GL_PLUS_CLAMPED_NV 0x92B1
+#define GL_PLUS_DARKER_NV 0x9292
+#define GL_PLUS_NV 0x9291
+#define GL_RED_NV 0x1903
+#define GL_SCREEN_NV 0x9295
+#define GL_SOFTLIGHT_NV 0x929C
+#define GL_SRC_ATOP_NV 0x928E
+#define GL_SRC_IN_NV 0x928A
+#define GL_SRC_NV 0x9286
+#define GL_SRC_OUT_NV 0x928C
+#define GL_SRC_OVER_NV 0x9288
+#define GL_UNCORRELATED_NV 0x9282
+#define GL_VIVIDLIGHT_NV 0x92A6
+#define GL_XOR_NV 0x1506
+typedef void (APIENTRYP PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value);
+typedef void (APIENTRYP PFNGLBLENDBARRIERNVPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendParameteriNV (GLenum pname, GLint value);
+GLAPI void APIENTRY glBlendBarrierNV (void);
+#endif
+#endif /* GL_NV_blend_equation_advanced */
+
+#ifndef GL_NV_blend_equation_advanced_coherent
+#define GL_NV_blend_equation_advanced_coherent 1
+#define GL_BLEND_ADVANCED_COHERENT_NV 0x9285
+#endif /* GL_NV_blend_equation_advanced_coherent */
+
+#ifndef GL_NV_blend_square
+#define GL_NV_blend_square 1
+#endif /* GL_NV_blend_square */
+
+#ifndef GL_NV_compute_program5
+#define GL_NV_compute_program5 1
+#define GL_COMPUTE_PROGRAM_NV 0x90FB
+#define GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV 0x90FC
+#endif /* GL_NV_compute_program5 */
+
+#ifndef GL_NV_conditional_render
+#define GL_NV_conditional_render 1
+#define GL_QUERY_WAIT_NV 0x8E13
+#define GL_QUERY_NO_WAIT_NV 0x8E14
+#define GL_QUERY_BY_REGION_WAIT_NV 0x8E15
+#define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16
+typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode);
+typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode);
+GLAPI void APIENTRY glEndConditionalRenderNV (void);
+#endif
+#endif /* GL_NV_conditional_render */
+
+#ifndef GL_NV_copy_depth_to_color
+#define GL_NV_copy_depth_to_color 1
+#define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E
+#define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F
+#endif /* GL_NV_copy_depth_to_color */
+
+#ifndef GL_NV_copy_image
+#define GL_NV_copy_image 1
+typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATANVPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCopyImageSubDataNV (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+#endif /* GL_NV_copy_image */
+
+#ifndef GL_NV_deep_texture3D
+#define GL_NV_deep_texture3D 1
+#define GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV 0x90D0
+#define GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV 0x90D1
+#endif /* GL_NV_deep_texture3D */
+
+#ifndef GL_NV_depth_buffer_float
+#define GL_NV_depth_buffer_float 1
+#define GL_DEPTH_COMPONENT32F_NV 0x8DAB
+#define GL_DEPTH32F_STENCIL8_NV 0x8DAC
+#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD
+#define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF
+typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar);
+typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth);
+typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar);
+GLAPI void APIENTRY glClearDepthdNV (GLdouble depth);
+GLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax);
+#endif
+#endif /* GL_NV_depth_buffer_float */
+
+#ifndef GL_NV_depth_clamp
+#define GL_NV_depth_clamp 1
+#define GL_DEPTH_CLAMP_NV 0x864F
+#endif /* GL_NV_depth_clamp */
+
+#ifndef GL_NV_draw_texture
+#define GL_NV_draw_texture 1
+typedef void (APIENTRYP PFNGLDRAWTEXTURENVPROC) (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawTextureNV (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);
+#endif
+#endif /* GL_NV_draw_texture */
+
+#ifndef GL_NV_evaluators
+#define GL_NV_evaluators 1
+#define GL_EVAL_2D_NV 0x86C0
+#define GL_EVAL_TRIANGULAR_2D_NV 0x86C1
+#define GL_MAP_TESSELLATION_NV 0x86C2
+#define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3
+#define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4
+#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5
+#define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6
+#define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7
+#define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8
+#define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9
+#define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA
+#define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB
+#define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC
+#define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD
+#define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE
+#define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF
+#define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0
+#define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1
+#define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2
+#define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3
+#define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4
+#define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5
+#define GL_MAX_MAP_TESSELLATION_NV 0x86D6
+#define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7
+typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points);
+typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points);
+GLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points);
+GLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glEvalMapsNV (GLenum target, GLenum mode);
+#endif
+#endif /* GL_NV_evaluators */
+
+#ifndef GL_NV_explicit_multisample
+#define GL_NV_explicit_multisample 1
+#define GL_SAMPLE_POSITION_NV 0x8E50
+#define GL_SAMPLE_MASK_NV 0x8E51
+#define GL_SAMPLE_MASK_VALUE_NV 0x8E52
+#define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53
+#define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54
+#define GL_TEXTURE_RENDERBUFFER_NV 0x8E55
+#define GL_SAMPLER_RENDERBUFFER_NV 0x8E56
+#define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57
+#define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58
+#define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59
+typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val);
+typedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask);
+typedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetMultisamplefvNV (GLenum pname, GLuint index, GLfloat *val);
+GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint index, GLbitfield mask);
+GLAPI void APIENTRY glTexRenderbufferNV (GLenum target, GLuint renderbuffer);
+#endif
+#endif /* GL_NV_explicit_multisample */
+
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences);
+GLAPI void APIENTRY glGenFencesNV (GLsizei n, GLuint *fences);
+GLAPI GLboolean APIENTRY glIsFenceNV (GLuint fence);
+GLAPI GLboolean APIENTRY glTestFenceNV (GLuint fence);
+GLAPI void APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params);
+GLAPI void APIENTRY glFinishFenceNV (GLuint fence);
+GLAPI void APIENTRY glSetFenceNV (GLuint fence, GLenum condition);
+#endif
+#endif /* GL_NV_fence */
+
+#ifndef GL_NV_float_buffer
+#define GL_NV_float_buffer 1
+#define GL_FLOAT_R_NV 0x8880
+#define GL_FLOAT_RG_NV 0x8881
+#define GL_FLOAT_RGB_NV 0x8882
+#define GL_FLOAT_RGBA_NV 0x8883
+#define GL_FLOAT_R16_NV 0x8884
+#define GL_FLOAT_R32_NV 0x8885
+#define GL_FLOAT_RG16_NV 0x8886
+#define GL_FLOAT_RG32_NV 0x8887
+#define GL_FLOAT_RGB16_NV 0x8888
+#define GL_FLOAT_RGB32_NV 0x8889
+#define GL_FLOAT_RGBA16_NV 0x888A
+#define GL_FLOAT_RGBA32_NV 0x888B
+#define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C
+#define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D
+#define GL_FLOAT_RGBA_MODE_NV 0x888E
+#endif /* GL_NV_float_buffer */
+
+#ifndef GL_NV_fog_distance
+#define GL_NV_fog_distance 1
+#define GL_FOG_DISTANCE_MODE_NV 0x855A
+#define GL_EYE_RADIAL_NV 0x855B
+#define GL_EYE_PLANE_ABSOLUTE_NV 0x855C
+#endif /* GL_NV_fog_distance */
+
+#ifndef GL_NV_fragment_program
+#define GL_NV_fragment_program 1
+#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868
+#define GL_FRAGMENT_PROGRAM_NV 0x8870
+#define GL_MAX_TEXTURE_COORDS_NV 0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872
+#define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873
+#define GL_PROGRAM_ERROR_STRING_NV 0x8874
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v);
+GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v);
+GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params);
+GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params);
+#endif
+#endif /* GL_NV_fragment_program */
+
+#ifndef GL_NV_fragment_program2
+#define GL_NV_fragment_program2 1
+#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4
+#define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5
+#define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6
+#define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7
+#define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8
+#endif /* GL_NV_fragment_program2 */
+
+#ifndef GL_NV_fragment_program4
+#define GL_NV_fragment_program4 1
+#endif /* GL_NV_fragment_program4 */
+
+#ifndef GL_NV_fragment_program_option
+#define GL_NV_fragment_program_option 1
+#endif /* GL_NV_fragment_program_option */
+
+#ifndef GL_NV_framebuffer_multisample_coverage
+#define GL_NV_framebuffer_multisample_coverage 1
+#define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB
+#define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10
+#define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11
+#define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+#endif /* GL_NV_framebuffer_multisample_coverage */
+
+#ifndef GL_NV_geometry_program4
+#define GL_NV_geometry_program4 1
+#define GL_GEOMETRY_PROGRAM_NV 0x8C26
+#define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27
+#define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28
+typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit);
+GLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
+#endif
+#endif /* GL_NV_geometry_program4 */
+
+#ifndef GL_NV_geometry_shader4
+#define GL_NV_geometry_shader4 1
+#endif /* GL_NV_geometry_shader4 */
+
+#ifndef GL_NV_gpu_program4
+#define GL_NV_gpu_program4 1
+#define GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904
+#define GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905
+#define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906
+#define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907
+#define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908
+#define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909
+#define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5
+#define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum target, GLuint index, const GLint *params);
+GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params);
+GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum target, GLuint index, const GLuint *params);
+GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params);
+GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum target, GLuint index, const GLint *params);
+GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params);
+GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum target, GLuint index, const GLuint *params);
+GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params);
+GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum target, GLuint index, GLint *params);
+GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum target, GLuint index, GLuint *params);
+GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum target, GLuint index, GLint *params);
+GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum target, GLuint index, GLuint *params);
+#endif
+#endif /* GL_NV_gpu_program4 */
+
+#ifndef GL_NV_gpu_program5
+#define GL_NV_gpu_program5 1
+#define GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A
+#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B
+#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C
+#define GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D
+#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E
+#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F
+#define GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44
+#define GL_MAX_PROGRAM_SUBROUTINE_NUM_NV 0x8F45
+typedef void (APIENTRYP PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC) (GLenum target, GLsizei count, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC) (GLenum target, GLuint index, GLuint *param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramSubroutineParametersuivNV (GLenum target, GLsizei count, const GLuint *params);
+GLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint index, GLuint *param);
+#endif
+#endif /* GL_NV_gpu_program5 */
+
+#ifndef GL_NV_gpu_program5_mem_extended
+#define GL_NV_gpu_program5_mem_extended 1
+#endif /* GL_NV_gpu_program5_mem_extended */
+
+#ifndef GL_NV_gpu_shader5
+#define GL_NV_gpu_shader5 1
+#endif /* GL_NV_gpu_shader5 */
+
+#ifndef GL_NV_half_float
+#define GL_NV_half_float 1
+typedef unsigned short GLhalfNV;
+#define GL_HALF_FLOAT_NV 0x140B
+typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz);
+typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha);
+typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s);
+typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);
+typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y);
+GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z);
+GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz);
+GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha);
+GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV s);
+GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV s, GLhalfNV t);
+GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r);
+GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum target, GLhalfNV s);
+GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v);
+GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t);
+GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v);
+GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r);
+GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v);
+GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v);
+GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog);
+GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog);
+GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight);
+GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight);
+GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x);
+GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y);
+GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint index, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z);
+GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint index, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint index, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
+#endif
+#endif /* GL_NV_half_float */
+
+#ifndef GL_NV_light_max_exponent
+#define GL_NV_light_max_exponent 1
+#define GL_MAX_SHININESS_NV 0x8504
+#define GL_MAX_SPOT_EXPONENT_NV 0x8505
+#endif /* GL_NV_light_max_exponent */
+
+#ifndef GL_NV_multisample_coverage
+#define GL_NV_multisample_coverage 1
+#define GL_COLOR_SAMPLES_NV 0x8E20
+#endif /* GL_NV_multisample_coverage */
+
+#ifndef GL_NV_multisample_filter_hint
+#define GL_NV_multisample_filter_hint 1
+#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534
+#endif /* GL_NV_multisample_filter_hint */
+
+#ifndef GL_NV_occlusion_query
+#define GL_NV_occlusion_query 1
+#define GL_PIXEL_COUNTER_BITS_NV 0x8864
+#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865
+#define GL_PIXEL_COUNT_NV 0x8866
+#define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867
+typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei n, GLuint *ids);
+GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids);
+GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint id);
+GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint id);
+GLAPI void APIENTRY glEndOcclusionQueryNV (void);
+GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params);
+#endif
+#endif /* GL_NV_occlusion_query */
+
+#ifndef GL_NV_packed_depth_stencil
+#define GL_NV_packed_depth_stencil 1
+#define GL_DEPTH_STENCIL_NV 0x84F9
+#define GL_UNSIGNED_INT_24_8_NV 0x84FA
+#endif /* GL_NV_packed_depth_stencil */
+
+#ifndef GL_NV_parameter_buffer_object
+#define GL_NV_parameter_buffer_object 1
+#define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0
+#define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1
+#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2
+#define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3
+#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4
+typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params);
+GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params);
+GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params);
+#endif
+#endif /* GL_NV_parameter_buffer_object */
+
+#ifndef GL_NV_parameter_buffer_object2
+#define GL_NV_parameter_buffer_object2 1
+#endif /* GL_NV_parameter_buffer_object2 */
+
+#ifndef GL_NV_path_rendering
+#define GL_NV_path_rendering 1
+#define GL_PATH_FORMAT_SVG_NV 0x9070
+#define GL_PATH_FORMAT_PS_NV 0x9071
+#define GL_STANDARD_FONT_NAME_NV 0x9072
+#define GL_SYSTEM_FONT_NAME_NV 0x9073
+#define GL_FILE_NAME_NV 0x9074
+#define GL_PATH_STROKE_WIDTH_NV 0x9075
+#define GL_PATH_END_CAPS_NV 0x9076
+#define GL_PATH_INITIAL_END_CAP_NV 0x9077
+#define GL_PATH_TERMINAL_END_CAP_NV 0x9078
+#define GL_PATH_JOIN_STYLE_NV 0x9079
+#define GL_PATH_MITER_LIMIT_NV 0x907A
+#define GL_PATH_DASH_CAPS_NV 0x907B
+#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C
+#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D
+#define GL_PATH_DASH_OFFSET_NV 0x907E
+#define GL_PATH_CLIENT_LENGTH_NV 0x907F
+#define GL_PATH_FILL_MODE_NV 0x9080
+#define GL_PATH_FILL_MASK_NV 0x9081
+#define GL_PATH_FILL_COVER_MODE_NV 0x9082
+#define GL_PATH_STROKE_COVER_MODE_NV 0x9083
+#define GL_PATH_STROKE_MASK_NV 0x9084
+#define GL_COUNT_UP_NV 0x9088
+#define GL_COUNT_DOWN_NV 0x9089
+#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A
+#define GL_CONVEX_HULL_NV 0x908B
+#define GL_BOUNDING_BOX_NV 0x908D
+#define GL_TRANSLATE_X_NV 0x908E
+#define GL_TRANSLATE_Y_NV 0x908F
+#define GL_TRANSLATE_2D_NV 0x9090
+#define GL_TRANSLATE_3D_NV 0x9091
+#define GL_AFFINE_2D_NV 0x9092
+#define GL_AFFINE_3D_NV 0x9094
+#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096
+#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098
+#define GL_UTF8_NV 0x909A
+#define GL_UTF16_NV 0x909B
+#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C
+#define GL_PATH_COMMAND_COUNT_NV 0x909D
+#define GL_PATH_COORD_COUNT_NV 0x909E
+#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F
+#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0
+#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1
+#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2
+#define GL_SQUARE_NV 0x90A3
+#define GL_ROUND_NV 0x90A4
+#define GL_TRIANGULAR_NV 0x90A5
+#define GL_BEVEL_NV 0x90A6
+#define GL_MITER_REVERT_NV 0x90A7
+#define GL_MITER_TRUNCATE_NV 0x90A8
+#define GL_SKIP_MISSING_GLYPH_NV 0x90A9
+#define GL_USE_MISSING_GLYPH_NV 0x90AA
+#define GL_PATH_ERROR_POSITION_NV 0x90AB
+#define GL_PATH_FOG_GEN_MODE_NV 0x90AC
+#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD
+#define GL_ADJACENT_PAIRS_NV 0x90AE
+#define GL_FIRST_TO_REST_NV 0x90AF
+#define GL_PATH_GEN_MODE_NV 0x90B0
+#define GL_PATH_GEN_COEFF_NV 0x90B1
+#define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2
+#define GL_PATH_GEN_COMPONENTS_NV 0x90B3
+#define GL_PATH_STENCIL_FUNC_NV 0x90B7
+#define GL_PATH_STENCIL_REF_NV 0x90B8
+#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9
+#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD
+#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE
+#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF
+#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4
+#define GL_MOVE_TO_RESETS_NV 0x90B5
+#define GL_MOVE_TO_CONTINUES_NV 0x90B6
+#define GL_CLOSE_PATH_NV 0x00
+#define GL_MOVE_TO_NV 0x02
+#define GL_RELATIVE_MOVE_TO_NV 0x03
+#define GL_LINE_TO_NV 0x04
+#define GL_RELATIVE_LINE_TO_NV 0x05
+#define GL_HORIZONTAL_LINE_TO_NV 0x06
+#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07
+#define GL_VERTICAL_LINE_TO_NV 0x08
+#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09
+#define GL_QUADRATIC_CURVE_TO_NV 0x0A
+#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B
+#define GL_CUBIC_CURVE_TO_NV 0x0C
+#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D
+#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E
+#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F
+#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10
+#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11
+#define GL_SMALL_CCW_ARC_TO_NV 0x12
+#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13
+#define GL_SMALL_CW_ARC_TO_NV 0x14
+#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15
+#define GL_LARGE_CCW_ARC_TO_NV 0x16
+#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17
+#define GL_LARGE_CW_ARC_TO_NV 0x18
+#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19
+#define GL_RESTART_PATH_NV 0xF0
+#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2
+#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4
+#define GL_RECT_NV 0xF6
+#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8
+#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA
+#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC
+#define GL_ARC_TO_NV 0xFE
+#define GL_RELATIVE_ARC_TO_NV 0xFF
+#define GL_BOLD_BIT_NV 0x01
+#define GL_ITALIC_BIT_NV 0x02
+#define GL_GLYPH_WIDTH_BIT_NV 0x01
+#define GL_GLYPH_HEIGHT_BIT_NV 0x02
+#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04
+#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08
+#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10
+#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20
+#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40
+#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80
+#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100
+#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000
+#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000
+#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000
+#define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000
+#define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000
+#define GL_FONT_ASCENDER_BIT_NV 0x00200000
+#define GL_FONT_DESCENDER_BIT_NV 0x00400000
+#define GL_FONT_HEIGHT_BIT_NV 0x00800000
+#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000
+#define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000
+#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000
+#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000
+#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000
+#define GL_PRIMARY_COLOR_NV 0x852C
+#define GL_SECONDARY_COLOR_NV 0x852D
+typedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range);
+typedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range);
+typedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path);
+typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString);
+typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights);
+typedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath);
+typedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight);
+typedef void (APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues);
+typedef void (APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value);
+typedef void (APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value);
+typedef void (APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value);
+typedef void (APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray);
+typedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask);
+typedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units);
+typedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask);
+typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask);
+typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+typedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func);
+typedef void (APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs);
+typedef void (APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs);
+typedef void (APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode);
+typedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode);
+typedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode);
+typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value);
+typedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value);
+typedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands);
+typedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords);
+typedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray);
+typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics);
+typedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics);
+typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing);
+typedef void (APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value);
+typedef void (APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value);
+typedef void (APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value);
+typedef void (APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value);
+typedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y);
+typedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y);
+typedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments);
+typedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glGenPathsNV (GLsizei range);
+GLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range);
+GLAPI GLboolean APIENTRY glIsPathNV (GLuint path);
+GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);
+GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords);
+GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);
+GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords);
+GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const void *pathString);
+GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+GLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights);
+GLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath);
+GLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight);
+GLAPI void APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues);
+GLAPI void APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value);
+GLAPI void APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value);
+GLAPI void APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value);
+GLAPI void APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value);
+GLAPI void APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray);
+GLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask);
+GLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units);
+GLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask);
+GLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask);
+GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+GLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func);
+GLAPI void APIENTRY glPathColorGenNV (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs);
+GLAPI void APIENTRY glPathTexGenNV (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs);
+GLAPI void APIENTRY glPathFogGenNV (GLenum genMode);
+GLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode);
+GLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode);
+GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+GLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value);
+GLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value);
+GLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands);
+GLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords);
+GLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray);
+GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics);
+GLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics);
+GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing);
+GLAPI void APIENTRY glGetPathColorGenivNV (GLenum color, GLenum pname, GLint *value);
+GLAPI void APIENTRY glGetPathColorGenfvNV (GLenum color, GLenum pname, GLfloat *value);
+GLAPI void APIENTRY glGetPathTexGenivNV (GLenum texCoordSet, GLenum pname, GLint *value);
+GLAPI void APIENTRY glGetPathTexGenfvNV (GLenum texCoordSet, GLenum pname, GLfloat *value);
+GLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y);
+GLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y);
+GLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments);
+GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY);
+#endif
+#endif /* GL_NV_path_rendering */
+
+#ifndef GL_NV_pixel_data_range
+#define GL_NV_pixel_data_range 1
+#define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878
+#define GL_READ_PIXEL_DATA_RANGE_NV 0x8879
+#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A
+#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B
+#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C
+#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D
+typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, const void *pointer);
+typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, const void *pointer);
+GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target);
+#endif
+#endif /* GL_NV_pixel_data_range */
+
+#ifndef GL_NV_point_sprite
+#define GL_NV_point_sprite 1
+#define GL_POINT_SPRITE_NV 0x8861
+#define GL_COORD_REPLACE_NV 0x8862
+#define GL_POINT_SPRITE_R_MODE_NV 0x8863
+typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameteriNV (GLenum pname, GLint param);
+GLAPI void APIENTRY glPointParameterivNV (GLenum pname, const GLint *params);
+#endif
+#endif /* GL_NV_point_sprite */
+
+#ifndef GL_NV_present_video
+#define GL_NV_present_video 1
+#define GL_FRAME_NV 0x8E26
+#define GL_FIELDS_NV 0x8E27
+#define GL_CURRENT_TIME_NV 0x8E28
+#define GL_NUM_FILL_STREAMS_NV 0x8E29
+#define GL_PRESENT_TIME_NV 0x8E2A
+#define GL_PRESENT_DURATION_NV 0x8E2B
+typedef void (APIENTRYP PFNGLPRESENTFRAMEKEYEDNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1);
+typedef void (APIENTRYP PFNGLPRESENTFRAMEDUALFILLNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3);
+typedef void (APIENTRYP PFNGLGETVIDEOIVNVPROC) (GLuint video_slot, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVIDEOUIVNVPROC) (GLuint video_slot, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLGETVIDEOI64VNVPROC) (GLuint video_slot, GLenum pname, GLint64EXT *params);
+typedef void (APIENTRYP PFNGLGETVIDEOUI64VNVPROC) (GLuint video_slot, GLenum pname, GLuint64EXT *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPresentFrameKeyedNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1);
+GLAPI void APIENTRY glPresentFrameDualFillNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3);
+GLAPI void APIENTRY glGetVideoivNV (GLuint video_slot, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVideouivNV (GLuint video_slot, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glGetVideoi64vNV (GLuint video_slot, GLenum pname, GLint64EXT *params);
+GLAPI void APIENTRY glGetVideoui64vNV (GLuint video_slot, GLenum pname, GLuint64EXT *params);
+#endif
+#endif /* GL_NV_present_video */
+
+#ifndef GL_NV_primitive_restart
+#define GL_NV_primitive_restart 1
+#define GL_PRIMITIVE_RESTART_NV 0x8558
+#define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void);
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPrimitiveRestartNV (void);
+GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint index);
+#endif
+#endif /* GL_NV_primitive_restart */
+
+#ifndef GL_NV_register_combiners
+#define GL_NV_register_combiners 1
+#define GL_REGISTER_COMBINERS_NV 0x8522
+#define GL_VARIABLE_A_NV 0x8523
+#define GL_VARIABLE_B_NV 0x8524
+#define GL_VARIABLE_C_NV 0x8525
+#define GL_VARIABLE_D_NV 0x8526
+#define GL_VARIABLE_E_NV 0x8527
+#define GL_VARIABLE_F_NV 0x8528
+#define GL_VARIABLE_G_NV 0x8529
+#define GL_CONSTANT_COLOR0_NV 0x852A
+#define GL_CONSTANT_COLOR1_NV 0x852B
+#define GL_SPARE0_NV 0x852E
+#define GL_SPARE1_NV 0x852F
+#define GL_DISCARD_NV 0x8530
+#define GL_E_TIMES_F_NV 0x8531
+#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532
+#define GL_UNSIGNED_IDENTITY_NV 0x8536
+#define GL_UNSIGNED_INVERT_NV 0x8537
+#define GL_EXPAND_NORMAL_NV 0x8538
+#define GL_EXPAND_NEGATE_NV 0x8539
+#define GL_HALF_BIAS_NORMAL_NV 0x853A
+#define GL_HALF_BIAS_NEGATE_NV 0x853B
+#define GL_SIGNED_IDENTITY_NV 0x853C
+#define GL_SIGNED_NEGATE_NV 0x853D
+#define GL_SCALE_BY_TWO_NV 0x853E
+#define GL_SCALE_BY_FOUR_NV 0x853F
+#define GL_SCALE_BY_ONE_HALF_NV 0x8540
+#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541
+#define GL_COMBINER_INPUT_NV 0x8542
+#define GL_COMBINER_MAPPING_NV 0x8543
+#define GL_COMBINER_COMPONENT_USAGE_NV 0x8544
+#define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545
+#define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546
+#define GL_COMBINER_MUX_SUM_NV 0x8547
+#define GL_COMBINER_SCALE_NV 0x8548
+#define GL_COMBINER_BIAS_NV 0x8549
+#define GL_COMBINER_AB_OUTPUT_NV 0x854A
+#define GL_COMBINER_CD_OUTPUT_NV 0x854B
+#define GL_COMBINER_SUM_OUTPUT_NV 0x854C
+#define GL_MAX_GENERAL_COMBINERS_NV 0x854D
+#define GL_NUM_GENERAL_COMBINERS_NV 0x854E
+#define GL_COLOR_SUM_CLAMP_NV 0x854F
+#define GL_COMBINER0_NV 0x8550
+#define GL_COMBINER1_NV 0x8551
+#define GL_COMBINER2_NV 0x8552
+#define GL_COMBINER3_NV 0x8553
+#define GL_COMBINER4_NV 0x8554
+#define GL_COMBINER5_NV 0x8555
+#define GL_COMBINER6_NV 0x8556
+#define GL_COMBINER7_NV 0x8557
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);
+typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerParameterfvNV (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glCombinerParameterfNV (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glCombinerParameterivNV (GLenum pname, const GLint *params);
+GLAPI void APIENTRY glCombinerParameteriNV (GLenum pname, GLint param);
+GLAPI void APIENTRY glCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+GLAPI void APIENTRY glCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);
+GLAPI void APIENTRY glFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params);
+#endif
+#endif /* GL_NV_register_combiners */
+
+#ifndef GL_NV_register_combiners2
+#define GL_NV_register_combiners2 1
+#define GL_PER_STAGE_CONSTANTS_NV 0x8535
+typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_NV_register_combiners2 */
+
+#ifndef GL_NV_shader_atomic_counters
+#define GL_NV_shader_atomic_counters 1
+#endif /* GL_NV_shader_atomic_counters */
+
+#ifndef GL_NV_shader_atomic_float
+#define GL_NV_shader_atomic_float 1
+#endif /* GL_NV_shader_atomic_float */
+
+#ifndef GL_NV_shader_buffer_load
+#define GL_NV_shader_buffer_load 1
+#define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D
+#define GL_GPU_ADDRESS_NV 0x8F34
+#define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35
+typedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access);
+typedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access);
+typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer);
+typedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params);
+typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result);
+typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value);
+typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access);
+GLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target);
+GLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target);
+GLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access);
+GLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer);
+GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer);
+GLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params);
+GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params);
+GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result);
+GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value);
+GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value);
+GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+#endif
+#endif /* GL_NV_shader_buffer_load */
+
+#ifndef GL_NV_shader_buffer_store
+#define GL_NV_shader_buffer_store 1
+#define GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010
+#endif /* GL_NV_shader_buffer_store */
+
+#ifndef GL_NV_shader_storage_buffer_object
+#define GL_NV_shader_storage_buffer_object 1
+#endif /* GL_NV_shader_storage_buffer_object */
+
+#ifndef GL_NV_shader_thread_group
+#define GL_NV_shader_thread_group 1
+#define GL_WARP_SIZE_NV 0x9339
+#define GL_WARPS_PER_SM_NV 0x933A
+#define GL_SM_COUNT_NV 0x933B
+#endif /* GL_NV_shader_thread_group */
+
+#ifndef GL_NV_shader_thread_shuffle
+#define GL_NV_shader_thread_shuffle 1
+#endif /* GL_NV_shader_thread_shuffle */
+
+#ifndef GL_NV_tessellation_program5
+#define GL_NV_tessellation_program5 1
+#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8
+#define GL_TESS_CONTROL_PROGRAM_NV 0x891E
+#define GL_TESS_EVALUATION_PROGRAM_NV 0x891F
+#define GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74
+#define GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75
+#endif /* GL_NV_tessellation_program5 */
+
+#ifndef GL_NV_texgen_emboss
+#define GL_NV_texgen_emboss 1
+#define GL_EMBOSS_LIGHT_NV 0x855D
+#define GL_EMBOSS_CONSTANT_NV 0x855E
+#define GL_EMBOSS_MAP_NV 0x855F
+#endif /* GL_NV_texgen_emboss */
+
+#ifndef GL_NV_texgen_reflection
+#define GL_NV_texgen_reflection 1
+#define GL_NORMAL_MAP_NV 0x8511
+#define GL_REFLECTION_MAP_NV 0x8512
+#endif /* GL_NV_texgen_reflection */
+
+#ifndef GL_NV_texture_barrier
+#define GL_NV_texture_barrier 1
+typedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureBarrierNV (void);
+#endif
+#endif /* GL_NV_texture_barrier */
+
+#ifndef GL_NV_texture_compression_vtc
+#define GL_NV_texture_compression_vtc 1
+#endif /* GL_NV_texture_compression_vtc */
+
+#ifndef GL_NV_texture_env_combine4
+#define GL_NV_texture_env_combine4 1
+#define GL_COMBINE4_NV 0x8503
+#define GL_SOURCE3_RGB_NV 0x8583
+#define GL_SOURCE3_ALPHA_NV 0x858B
+#define GL_OPERAND3_RGB_NV 0x8593
+#define GL_OPERAND3_ALPHA_NV 0x859B
+#endif /* GL_NV_texture_env_combine4 */
+
+#ifndef GL_NV_texture_expand_normal
+#define GL_NV_texture_expand_normal 1
+#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F
+#endif /* GL_NV_texture_expand_normal */
+
+#ifndef GL_NV_texture_multisample
+#define GL_NV_texture_multisample 1
+#define GL_TEXTURE_COVERAGE_SAMPLES_NV 0x9045
+#define GL_TEXTURE_COLOR_SAMPLES_NV 0x9046
+typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage2DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+GLAPI void APIENTRY glTexImage3DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+GLAPI void APIENTRY glTextureImage2DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+GLAPI void APIENTRY glTextureImage3DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+GLAPI void APIENTRY glTextureImage2DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+GLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+#endif
+#endif /* GL_NV_texture_multisample */
+
+#ifndef GL_NV_texture_rectangle
+#define GL_NV_texture_rectangle 1
+#define GL_TEXTURE_RECTANGLE_NV 0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8
+#endif /* GL_NV_texture_rectangle */
+
+#ifndef GL_NV_texture_shader
+#define GL_NV_texture_shader 1
+#define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C
+#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D
+#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E
+#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9
+#define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA
+#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB
+#define GL_DSDT_MAG_INTENSITY_NV 0x86DC
+#define GL_SHADER_CONSISTENT_NV 0x86DD
+#define GL_TEXTURE_SHADER_NV 0x86DE
+#define GL_SHADER_OPERATION_NV 0x86DF
+#define GL_CULL_MODES_NV 0x86E0
+#define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1
+#define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2
+#define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3
+#define GL_OFFSET_TEXTURE_2D_MATRIX_NV 0x86E1
+#define GL_OFFSET_TEXTURE_2D_SCALE_NV 0x86E2
+#define GL_OFFSET_TEXTURE_2D_BIAS_NV 0x86E3
+#define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4
+#define GL_CONST_EYE_NV 0x86E5
+#define GL_PASS_THROUGH_NV 0x86E6
+#define GL_CULL_FRAGMENT_NV 0x86E7
+#define GL_OFFSET_TEXTURE_2D_NV 0x86E8
+#define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9
+#define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA
+#define GL_DOT_PRODUCT_NV 0x86EC
+#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED
+#define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE
+#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0
+#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1
+#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2
+#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3
+#define GL_HILO_NV 0x86F4
+#define GL_DSDT_NV 0x86F5
+#define GL_DSDT_MAG_NV 0x86F6
+#define GL_DSDT_MAG_VIB_NV 0x86F7
+#define GL_HILO16_NV 0x86F8
+#define GL_SIGNED_HILO_NV 0x86F9
+#define GL_SIGNED_HILO16_NV 0x86FA
+#define GL_SIGNED_RGBA_NV 0x86FB
+#define GL_SIGNED_RGBA8_NV 0x86FC
+#define GL_SIGNED_RGB_NV 0x86FE
+#define GL_SIGNED_RGB8_NV 0x86FF
+#define GL_SIGNED_LUMINANCE_NV 0x8701
+#define GL_SIGNED_LUMINANCE8_NV 0x8702
+#define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703
+#define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704
+#define GL_SIGNED_ALPHA_NV 0x8705
+#define GL_SIGNED_ALPHA8_NV 0x8706
+#define GL_SIGNED_INTENSITY_NV 0x8707
+#define GL_SIGNED_INTENSITY8_NV 0x8708
+#define GL_DSDT8_NV 0x8709
+#define GL_DSDT8_MAG8_NV 0x870A
+#define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B
+#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C
+#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D
+#define GL_HI_SCALE_NV 0x870E
+#define GL_LO_SCALE_NV 0x870F
+#define GL_DS_SCALE_NV 0x8710
+#define GL_DT_SCALE_NV 0x8711
+#define GL_MAGNITUDE_SCALE_NV 0x8712
+#define GL_VIBRANCE_SCALE_NV 0x8713
+#define GL_HI_BIAS_NV 0x8714
+#define GL_LO_BIAS_NV 0x8715
+#define GL_DS_BIAS_NV 0x8716
+#define GL_DT_BIAS_NV 0x8717
+#define GL_MAGNITUDE_BIAS_NV 0x8718
+#define GL_VIBRANCE_BIAS_NV 0x8719
+#define GL_TEXTURE_BORDER_VALUES_NV 0x871A
+#define GL_TEXTURE_HI_SIZE_NV 0x871B
+#define GL_TEXTURE_LO_SIZE_NV 0x871C
+#define GL_TEXTURE_DS_SIZE_NV 0x871D
+#define GL_TEXTURE_DT_SIZE_NV 0x871E
+#define GL_TEXTURE_MAG_SIZE_NV 0x871F
+#endif /* GL_NV_texture_shader */
+
+#ifndef GL_NV_texture_shader2
+#define GL_NV_texture_shader2 1
+#define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF
+#endif /* GL_NV_texture_shader2 */
+
+#ifndef GL_NV_texture_shader3
+#define GL_NV_texture_shader3 1
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853
+#define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854
+#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857
+#define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858
+#define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859
+#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A
+#define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B
+#define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C
+#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D
+#define GL_HILO8_NV 0x885E
+#define GL_SIGNED_HILO8_NV 0x885F
+#define GL_FORCE_BLUE_TO_ONE_NV 0x8860
+#endif /* GL_NV_texture_shader3 */
+
+#ifndef GL_NV_transform_feedback
+#define GL_NV_transform_feedback 1
+#define GL_BACK_PRIMARY_COLOR_NV 0x8C77
+#define GL_BACK_SECONDARY_COLOR_NV 0x8C78
+#define GL_TEXTURE_COORD_NV 0x8C79
+#define GL_CLIP_DISTANCE_NV 0x8C7A
+#define GL_VERTEX_ID_NV 0x8C7B
+#define GL_PRIMITIVE_ID_NV 0x8C7C
+#define GL_GENERIC_ATTRIB_NV 0x8C7D
+#define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80
+#define GL_ACTIVE_VARYINGS_NV 0x8C81
+#define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82
+#define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85
+#define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86
+#define GL_PRIMITIVES_GENERATED_NV 0x8C87
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88
+#define GL_RASTERIZER_DISCARD_NV 0x8C89
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B
+#define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C
+#define GL_SEPARATE_ATTRIBS_NV 0x8C8D
+#define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F
+#define GL_LAYER_NV 0x8DAA
+#define GL_NEXT_BUFFER_NV -2
+#define GL_SKIP_COMPONENTS4_NV -3
+#define GL_SKIP_COMPONENTS3_NV -4
+#define GL_SKIP_COMPONENTS2_NV -5
+#define GL_SKIP_COMPONENTS1_NV -6
+typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode);
+typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLuint count, const GLint *attribs, GLenum bufferMode);
+typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset);
+typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode);
+typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode);
+GLAPI void APIENTRY glEndTransformFeedbackNV (void);
+GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLuint count, const GLint *attribs, GLenum bufferMode);
+GLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset);
+GLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer);
+GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode);
+GLAPI void APIENTRY glActiveVaryingNV (GLuint program, const GLchar *name);
+GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glGetActiveVaryingNV (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint program, GLuint index, GLint *location);
+GLAPI void APIENTRY glTransformFeedbackStreamAttribsNV (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode);
+#endif
+#endif /* GL_NV_transform_feedback */
+
+#ifndef GL_NV_transform_feedback2
+#define GL_NV_transform_feedback2 1
+#define GL_TRANSFORM_FEEDBACK_NV 0x8E22
+#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23
+#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24
+#define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25
+typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids);
+typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void);
+typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void);
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum target, GLuint id);
+GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei n, const GLuint *ids);
+GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei n, GLuint *ids);
+GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint id);
+GLAPI void APIENTRY glPauseTransformFeedbackNV (void);
+GLAPI void APIENTRY glResumeTransformFeedbackNV (void);
+GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id);
+#endif
+#endif /* GL_NV_transform_feedback2 */
+
+#ifndef GL_NV_vdpau_interop
+#define GL_NV_vdpau_interop 1
+typedef GLintptr GLvdpauSurfaceNV;
+#define GL_SURFACE_STATE_NV 0x86EB
+#define GL_SURFACE_REGISTERED_NV 0x86FD
+#define GL_SURFACE_MAPPED_NV 0x8700
+#define GL_WRITE_DISCARD_NV 0x88BE
+typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const void *vdpDevice, const void *getProcAddress);
+typedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void);
+typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);
+typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);
+typedef GLboolean (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface);
+typedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface);
+typedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+typedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access);
+typedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces);
+typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVDPAUInitNV (const void *vdpDevice, const void *getProcAddress);
+GLAPI void APIENTRY glVDPAUFiniNV (void);
+GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);
+GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);
+GLAPI GLboolean APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface);
+GLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface);
+GLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+GLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access);
+GLAPI void APIENTRY glVDPAUMapSurfacesNV (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces);
+GLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces);
+#endif
+#endif /* GL_NV_vdpau_interop */
+
+#ifndef GL_NV_vertex_array_range
+#define GL_NV_vertex_array_range 1
+#define GL_VERTEX_ARRAY_RANGE_NV 0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E
+#define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F
+#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520
+#define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void);
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushVertexArrayRangeNV (void);
+GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const void *pointer);
+#endif
+#endif /* GL_NV_vertex_array_range */
+
+#ifndef GL_NV_vertex_array_range2
+#define GL_NV_vertex_array_range2 1
+#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533
+#endif /* GL_NV_vertex_array_range2 */
+
+#ifndef GL_NV_vertex_attrib_integer_64bit
+#define GL_NV_vertex_attrib_integer_64bit 1
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x);
+GLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y);
+GLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+GLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+GLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x);
+GLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y);
+GLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+GLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+GLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v);
+GLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params);
+GLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params);
+GLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride);
+#endif
+#endif /* GL_NV_vertex_attrib_integer_64bit */
+
+#ifndef GL_NV_vertex_buffer_unified_memory
+#define GL_NV_vertex_buffer_unified_memory 1
+#define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E
+#define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F
+#define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20
+#define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21
+#define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22
+#define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23
+#define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24
+#define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25
+#define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26
+#define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27
+#define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28
+#define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29
+#define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A
+#define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B
+#define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C
+#define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D
+#define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E
+#define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F
+#define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30
+#define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31
+#define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32
+#define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33
+#define GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40
+#define GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41
+#define GL_DRAW_INDIRECT_LENGTH_NV 0x8F42
+typedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length);
+typedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length);
+GLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride);
+GLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride);
+GLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride);
+GLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride);
+GLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride);
+GLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride);
+GLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride);
+GLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride);
+GLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride);
+GLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride);
+GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result);
+#endif
+#endif /* GL_NV_vertex_buffer_unified_memory */
+
+#ifndef GL_NV_vertex_program
+#define GL_NV_vertex_program 1
+#define GL_VERTEX_PROGRAM_NV 0x8620
+#define GL_VERTEX_STATE_PROGRAM_NV 0x8621
+#define GL_ATTRIB_ARRAY_SIZE_NV 0x8623
+#define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624
+#define GL_ATTRIB_ARRAY_TYPE_NV 0x8625
+#define GL_CURRENT_ATTRIB_NV 0x8626
+#define GL_PROGRAM_LENGTH_NV 0x8627
+#define GL_PROGRAM_STRING_NV 0x8628
+#define GL_MODELVIEW_PROJECTION_NV 0x8629
+#define GL_IDENTITY_NV 0x862A
+#define GL_INVERSE_NV 0x862B
+#define GL_TRANSPOSE_NV 0x862C
+#define GL_INVERSE_TRANSPOSE_NV 0x862D
+#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E
+#define GL_MAX_TRACK_MATRICES_NV 0x862F
+#define GL_MATRIX0_NV 0x8630
+#define GL_MATRIX1_NV 0x8631
+#define GL_MATRIX2_NV 0x8632
+#define GL_MATRIX3_NV 0x8633
+#define GL_MATRIX4_NV 0x8634
+#define GL_MATRIX5_NV 0x8635
+#define GL_MATRIX6_NV 0x8636
+#define GL_MATRIX7_NV 0x8637
+#define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640
+#define GL_CURRENT_MATRIX_NV 0x8641
+#define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643
+#define GL_PROGRAM_PARAMETER_NV 0x8644
+#define GL_ATTRIB_ARRAY_POINTER_NV 0x8645
+#define GL_PROGRAM_TARGET_NV 0x8646
+#define GL_PROGRAM_RESIDENT_NV 0x8647
+#define GL_TRACK_MATRIX_NV 0x8648
+#define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649
+#define GL_VERTEX_PROGRAM_BINDING_NV 0x864A
+#define GL_PROGRAM_ERROR_POSITION_NV 0x864B
+#define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650
+#define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651
+#define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652
+#define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653
+#define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654
+#define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655
+#define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656
+#define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657
+#define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658
+#define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659
+#define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A
+#define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B
+#define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C
+#define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D
+#define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E
+#define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F
+#define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660
+#define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661
+#define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662
+#define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663
+#define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664
+#define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665
+#define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666
+#define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667
+#define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668
+#define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669
+#define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A
+#define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B
+#define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C
+#define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D
+#define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E
+#define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F
+#define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670
+#define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671
+#define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672
+#define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673
+#define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674
+#define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675
+#define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676
+#define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677
+#define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678
+#define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679
+#define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A
+#define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B
+#define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C
+#define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D
+#define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E
+#define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F
+typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program);
+typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, void **pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences);
+GLAPI void APIENTRY glBindProgramNV (GLenum target, GLuint id);
+GLAPI void APIENTRY glDeleteProgramsNV (GLsizei n, const GLuint *programs);
+GLAPI void APIENTRY glExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params);
+GLAPI void APIENTRY glGenProgramsNV (GLsizei n, GLuint *programs);
+GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetProgramivNV (GLuint id, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program);
+GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, void **pointer);
+GLAPI GLboolean APIENTRY glIsProgramNV (GLuint id);
+GLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program);
+GLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs);
+GLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform);
+GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x);
+GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x);
+GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib1sNV (GLuint index, GLshort x);
+GLAPI void APIENTRY glVertexAttrib1svNV (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y);
+GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib2sNV (GLuint index, GLshort x, GLshort y);
+GLAPI void APIENTRY glVertexAttrib2svNV (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glVertexAttrib3svNV (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI void APIENTRY glVertexAttrib4svNV (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v);
+#endif
+#endif /* GL_NV_vertex_program */
+
+#ifndef GL_NV_vertex_program1_1
+#define GL_NV_vertex_program1_1 1
+#endif /* GL_NV_vertex_program1_1 */
+
+#ifndef GL_NV_vertex_program2
+#define GL_NV_vertex_program2 1
+#endif /* GL_NV_vertex_program2 */
+
+#ifndef GL_NV_vertex_program2_option
+#define GL_NV_vertex_program2_option 1
+#endif /* GL_NV_vertex_program2_option */
+
+#ifndef GL_NV_vertex_program3
+#define GL_NV_vertex_program3 1
+#endif /* GL_NV_vertex_program3 */
+
+#ifndef GL_NV_vertex_program4
+#define GL_NV_vertex_program4 1
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x);
+GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y);
+GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x);
+GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y);
+GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z);
+GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params);
+#endif
+#endif /* GL_NV_vertex_program4 */
+
+#ifndef GL_NV_video_capture
+#define GL_NV_video_capture 1
+#define GL_VIDEO_BUFFER_NV 0x9020
+#define GL_VIDEO_BUFFER_BINDING_NV 0x9021
+#define GL_FIELD_UPPER_NV 0x9022
+#define GL_FIELD_LOWER_NV 0x9023
+#define GL_NUM_VIDEO_CAPTURE_STREAMS_NV 0x9024
+#define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025
+#define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026
+#define GL_LAST_VIDEO_CAPTURE_STATUS_NV 0x9027
+#define GL_VIDEO_BUFFER_PITCH_NV 0x9028
+#define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029
+#define GL_VIDEO_COLOR_CONVERSION_MAX_NV 0x902A
+#define GL_VIDEO_COLOR_CONVERSION_MIN_NV 0x902B
+#define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C
+#define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D
+#define GL_PARTIAL_SUCCESS_NV 0x902E
+#define GL_SUCCESS_NV 0x902F
+#define GL_FAILURE_NV 0x9030
+#define GL_YCBYCR8_422_NV 0x9031
+#define GL_YCBAYCR8A_4224_NV 0x9032
+#define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV 0x9033
+#define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034
+#define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV 0x9035
+#define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036
+#define GL_Z4Y12Z4CB12Z4CR12_444_NV 0x9037
+#define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV 0x9038
+#define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV 0x9039
+#define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A
+#define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B
+#define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C
+typedef void (APIENTRYP PFNGLBEGINVIDEOCAPTURENVPROC) (GLuint video_capture_slot);
+typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset);
+typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture);
+typedef void (APIENTRYP PFNGLENDVIDEOCAPTURENVPROC) (GLuint video_capture_slot);
+typedef void (APIENTRYP PFNGLGETVIDEOCAPTUREIVNVPROC) (GLuint video_capture_slot, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params);
+typedef GLenum (APIENTRYP PFNGLVIDEOCAPTURENVPROC) (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time);
+typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginVideoCaptureNV (GLuint video_capture_slot);
+GLAPI void APIENTRY glBindVideoCaptureStreamBufferNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset);
+GLAPI void APIENTRY glBindVideoCaptureStreamTextureNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture);
+GLAPI void APIENTRY glEndVideoCaptureNV (GLuint video_capture_slot);
+GLAPI void APIENTRY glGetVideoCaptureivNV (GLuint video_capture_slot, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVideoCaptureStreamivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVideoCaptureStreamfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVideoCaptureStreamdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params);
+GLAPI GLenum APIENTRY glVideoCaptureNV (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time);
+GLAPI void APIENTRY glVideoCaptureStreamParameterivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glVideoCaptureStreamParameterfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params);
+#endif
+#endif /* GL_NV_video_capture */
+
+#ifndef GL_OML_interlace
+#define GL_OML_interlace 1
+#define GL_INTERLACE_OML 0x8980
+#define GL_INTERLACE_READ_OML 0x8981
+#endif /* GL_OML_interlace */
+
+#ifndef GL_OML_resample
+#define GL_OML_resample 1
+#define GL_PACK_RESAMPLE_OML 0x8984
+#define GL_UNPACK_RESAMPLE_OML 0x8985
+#define GL_RESAMPLE_REPLICATE_OML 0x8986
+#define GL_RESAMPLE_ZERO_FILL_OML 0x8987
+#define GL_RESAMPLE_AVERAGE_OML 0x8988
+#define GL_RESAMPLE_DECIMATE_OML 0x8989
+#endif /* GL_OML_resample */
+
+#ifndef GL_OML_subsample
+#define GL_OML_subsample 1
+#define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982
+#define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983
+#endif /* GL_OML_subsample */
+
+#ifndef GL_PGI_misc_hints
+#define GL_PGI_misc_hints 1
+#define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8
+#define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD
+#define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE
+#define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202
+#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203
+#define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204
+#define GL_ALWAYS_FAST_HINT_PGI 0x1A20C
+#define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D
+#define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E
+#define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F
+#define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210
+#define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211
+#define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216
+#define GL_STRICT_LIGHTING_HINT_PGI 0x1A217
+#define GL_STRICT_SCISSOR_HINT_PGI 0x1A218
+#define GL_FULL_STIPPLE_HINT_PGI 0x1A219
+#define GL_CLIP_NEAR_HINT_PGI 0x1A220
+#define GL_CLIP_FAR_HINT_PGI 0x1A221
+#define GL_WIDE_LINE_HINT_PGI 0x1A222
+#define GL_BACK_NORMALS_HINT_PGI 0x1A223
+typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glHintPGI (GLenum target, GLint mode);
+#endif
+#endif /* GL_PGI_misc_hints */
+
+#ifndef GL_PGI_vertex_hints
+#define GL_PGI_vertex_hints 1
+#define GL_VERTEX_DATA_HINT_PGI 0x1A22A
+#define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B
+#define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C
+#define GL_MAX_VERTEX_HINT_PGI 0x1A22D
+#define GL_COLOR3_BIT_PGI 0x00010000
+#define GL_COLOR4_BIT_PGI 0x00020000
+#define GL_EDGEFLAG_BIT_PGI 0x00040000
+#define GL_INDEX_BIT_PGI 0x00080000
+#define GL_MAT_AMBIENT_BIT_PGI 0x00100000
+#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000
+#define GL_MAT_DIFFUSE_BIT_PGI 0x00400000
+#define GL_MAT_EMISSION_BIT_PGI 0x00800000
+#define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000
+#define GL_MAT_SHININESS_BIT_PGI 0x02000000
+#define GL_MAT_SPECULAR_BIT_PGI 0x04000000
+#define GL_NORMAL_BIT_PGI 0x08000000
+#define GL_TEXCOORD1_BIT_PGI 0x10000000
+#define GL_TEXCOORD2_BIT_PGI 0x20000000
+#define GL_TEXCOORD3_BIT_PGI 0x40000000
+#define GL_TEXCOORD4_BIT_PGI 0x80000000
+#define GL_VERTEX23_BIT_PGI 0x00000004
+#define GL_VERTEX4_BIT_PGI 0x00000008
+#endif /* GL_PGI_vertex_hints */
+
+#ifndef GL_REND_screen_coordinates
+#define GL_REND_screen_coordinates 1
+#define GL_SCREEN_COORDINATES_REND 0x8490
+#define GL_INVERTED_SCREEN_W_REND 0x8491
+#endif /* GL_REND_screen_coordinates */
+
+#ifndef GL_S3_s3tc
+#define GL_S3_s3tc 1
+#define GL_RGB_S3TC 0x83A0
+#define GL_RGB4_S3TC 0x83A1
+#define GL_RGBA_S3TC 0x83A2
+#define GL_RGBA4_S3TC 0x83A3
+#define GL_RGBA_DXT5_S3TC 0x83A4
+#define GL_RGBA4_DXT5_S3TC 0x83A5
+#endif /* GL_S3_s3tc */
+
+#ifndef GL_SGIS_detail_texture
+#define GL_SGIS_detail_texture 1
+#define GL_DETAIL_TEXTURE_2D_SGIS 0x8095
+#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096
+#define GL_LINEAR_DETAIL_SGIS 0x8097
+#define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098
+#define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099
+#define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A
+#define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B
+#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C
+typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points);
+GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum target, GLfloat *points);
+#endif
+#endif /* GL_SGIS_detail_texture */
+
+#ifndef GL_SGIS_fog_function
+#define GL_SGIS_fog_function 1
+#define GL_FOG_FUNC_SGIS 0x812A
+#define GL_FOG_FUNC_POINTS_SGIS 0x812B
+#define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C
+typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogFuncSGIS (GLsizei n, const GLfloat *points);
+GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *points);
+#endif
+#endif /* GL_SGIS_fog_function */
+
+#ifndef GL_SGIS_generate_mipmap
+#define GL_SGIS_generate_mipmap 1
+#define GL_GENERATE_MIPMAP_SGIS 0x8191
+#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
+#endif /* GL_SGIS_generate_mipmap */
+
+#ifndef GL_SGIS_multisample
+#define GL_SGIS_multisample 1
+#define GL_MULTISAMPLE_SGIS 0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F
+#define GL_SAMPLE_MASK_SGIS 0x80A0
+#define GL_1PASS_SGIS 0x80A1
+#define GL_2PASS_0_SGIS 0x80A2
+#define GL_2PASS_1_SGIS 0x80A3
+#define GL_4PASS_0_SGIS 0x80A4
+#define GL_4PASS_1_SGIS 0x80A5
+#define GL_4PASS_2_SGIS 0x80A6
+#define GL_4PASS_3_SGIS 0x80A7
+#define GL_SAMPLE_BUFFERS_SGIS 0x80A8
+#define GL_SAMPLES_SGIS 0x80A9
+#define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA
+#define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB
+#define GL_SAMPLE_PATTERN_SGIS 0x80AC
+typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskSGIS (GLclampf value, GLboolean invert);
+GLAPI void APIENTRY glSamplePatternSGIS (GLenum pattern);
+#endif
+#endif /* GL_SGIS_multisample */
+
+#ifndef GL_SGIS_pixel_texture
+#define GL_SGIS_pixel_texture 1
+#define GL_PIXEL_TEXTURE_SGIS 0x8353
+#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354
+#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355
+#define GL_PIXEL_GROUP_COLOR_SGIS 0x8356
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum pname, GLint param);
+GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum pname, const GLint *params);
+GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_SGIS_pixel_texture */
+
+#ifndef GL_SGIS_point_line_texgen
+#define GL_SGIS_point_line_texgen 1
+#define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0
+#define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1
+#define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2
+#define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3
+#define GL_EYE_POINT_SGIS 0x81F4
+#define GL_OBJECT_POINT_SGIS 0x81F5
+#define GL_EYE_LINE_SGIS 0x81F6
+#define GL_OBJECT_LINE_SGIS 0x81F7
+#endif /* GL_SGIS_point_line_texgen */
+
+#ifndef GL_SGIS_point_parameters
+#define GL_SGIS_point_parameters 1
+#define GL_POINT_SIZE_MIN_SGIS 0x8126
+#define GL_POINT_SIZE_MAX_SGIS 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128
+#define GL_DISTANCE_ATTENUATION_SGIS 0x8129
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfSGIS (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPointParameterfvSGIS (GLenum pname, const GLfloat *params);
+#endif
+#endif /* GL_SGIS_point_parameters */
+
+#ifndef GL_SGIS_sharpen_texture
+#define GL_SGIS_sharpen_texture 1
+#define GL_LINEAR_SHARPEN_SGIS 0x80AD
+#define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE
+#define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF
+#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0
+typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points);
+GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points);
+#endif
+#endif /* GL_SGIS_sharpen_texture */
+
+#ifndef GL_SGIS_texture4D
+#define GL_SGIS_texture4D 1
+#define GL_PACK_SKIP_VOLUMES_SGIS 0x8130
+#define GL_PACK_IMAGE_DEPTH_SGIS 0x8131
+#define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132
+#define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133
+#define GL_TEXTURE_4D_SGIS 0x8134
+#define GL_PROXY_TEXTURE_4D_SGIS 0x8135
+#define GL_TEXTURE_4DSIZE_SGIS 0x8136
+#define GL_TEXTURE_WRAP_Q_SGIS 0x8137
+#define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138
+#define GL_TEXTURE_4D_BINDING_SGIS 0x814F
+typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels);
+#endif
+#endif /* GL_SGIS_texture4D */
+
+#ifndef GL_SGIS_texture_border_clamp
+#define GL_SGIS_texture_border_clamp 1
+#define GL_CLAMP_TO_BORDER_SGIS 0x812D
+#endif /* GL_SGIS_texture_border_clamp */
+
+#ifndef GL_SGIS_texture_color_mask
+#define GL_SGIS_texture_color_mask 1
+#define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF
+typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+#endif
+#endif /* GL_SGIS_texture_color_mask */
+
+#ifndef GL_SGIS_texture_edge_clamp
+#define GL_SGIS_texture_edge_clamp 1
+#define GL_CLAMP_TO_EDGE_SGIS 0x812F
+#endif /* GL_SGIS_texture_edge_clamp */
+
+#ifndef GL_SGIS_texture_filter4
+#define GL_SGIS_texture_filter4 1
+#define GL_FILTER4_SGIS 0x8146
+#define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147
+typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights);
+typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights);
+GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);
+#endif
+#endif /* GL_SGIS_texture_filter4 */
+
+#ifndef GL_SGIS_texture_lod
+#define GL_SGIS_texture_lod 1
+#define GL_TEXTURE_MIN_LOD_SGIS 0x813A
+#define GL_TEXTURE_MAX_LOD_SGIS 0x813B
+#define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C
+#define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D
+#endif /* GL_SGIS_texture_lod */
+
+#ifndef GL_SGIS_texture_select
+#define GL_SGIS_texture_select 1
+#define GL_DUAL_ALPHA4_SGIS 0x8110
+#define GL_DUAL_ALPHA8_SGIS 0x8111
+#define GL_DUAL_ALPHA12_SGIS 0x8112
+#define GL_DUAL_ALPHA16_SGIS 0x8113
+#define GL_DUAL_LUMINANCE4_SGIS 0x8114
+#define GL_DUAL_LUMINANCE8_SGIS 0x8115
+#define GL_DUAL_LUMINANCE12_SGIS 0x8116
+#define GL_DUAL_LUMINANCE16_SGIS 0x8117
+#define GL_DUAL_INTENSITY4_SGIS 0x8118
+#define GL_DUAL_INTENSITY8_SGIS 0x8119
+#define GL_DUAL_INTENSITY12_SGIS 0x811A
+#define GL_DUAL_INTENSITY16_SGIS 0x811B
+#define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C
+#define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D
+#define GL_QUAD_ALPHA4_SGIS 0x811E
+#define GL_QUAD_ALPHA8_SGIS 0x811F
+#define GL_QUAD_LUMINANCE4_SGIS 0x8120
+#define GL_QUAD_LUMINANCE8_SGIS 0x8121
+#define GL_QUAD_INTENSITY4_SGIS 0x8122
+#define GL_QUAD_INTENSITY8_SGIS 0x8123
+#define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124
+#define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125
+#endif /* GL_SGIS_texture_select */
+
+#ifndef GL_SGIX_async
+#define GL_SGIX_async 1
+#define GL_ASYNC_MARKER_SGIX 0x8329
+typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker);
+typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp);
+typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp);
+typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range);
+typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range);
+typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint marker);
+GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *markerp);
+GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *markerp);
+GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei range);
+GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range);
+GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint marker);
+#endif
+#endif /* GL_SGIX_async */
+
+#ifndef GL_SGIX_async_histogram
+#define GL_SGIX_async_histogram 1
+#define GL_ASYNC_HISTOGRAM_SGIX 0x832C
+#define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D
+#endif /* GL_SGIX_async_histogram */
+
+#ifndef GL_SGIX_async_pixel
+#define GL_SGIX_async_pixel 1
+#define GL_ASYNC_TEX_IMAGE_SGIX 0x835C
+#define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D
+#define GL_ASYNC_READ_PIXELS_SGIX 0x835E
+#define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F
+#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360
+#define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361
+#endif /* GL_SGIX_async_pixel */
+
+#ifndef GL_SGIX_blend_alpha_minmax
+#define GL_SGIX_blend_alpha_minmax 1
+#define GL_ALPHA_MIN_SGIX 0x8320
+#define GL_ALPHA_MAX_SGIX 0x8321
+#endif /* GL_SGIX_blend_alpha_minmax */
+
+#ifndef GL_SGIX_calligraphic_fragment
+#define GL_SGIX_calligraphic_fragment 1
+#define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183
+#endif /* GL_SGIX_calligraphic_fragment */
+
+#ifndef GL_SGIX_clipmap
+#define GL_SGIX_clipmap 1
+#define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170
+#define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171
+#define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172
+#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173
+#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174
+#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175
+#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176
+#define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177
+#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178
+#define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D
+#define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E
+#define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F
+#endif /* GL_SGIX_clipmap */
+
+#ifndef GL_SGIX_convolution_accuracy
+#define GL_SGIX_convolution_accuracy 1
+#define GL_CONVOLUTION_HINT_SGIX 0x8316
+#endif /* GL_SGIX_convolution_accuracy */
+
+#ifndef GL_SGIX_depth_pass_instrument
+#define GL_SGIX_depth_pass_instrument 1
+#endif /* GL_SGIX_depth_pass_instrument */
+
+#ifndef GL_SGIX_depth_texture
+#define GL_SGIX_depth_texture 1
+#define GL_DEPTH_COMPONENT16_SGIX 0x81A5
+#define GL_DEPTH_COMPONENT24_SGIX 0x81A6
+#define GL_DEPTH_COMPONENT32_SGIX 0x81A7
+#endif /* GL_SGIX_depth_texture */
+
+#ifndef GL_SGIX_flush_raster
+#define GL_SGIX_flush_raster 1
+typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushRasterSGIX (void);
+#endif
+#endif /* GL_SGIX_flush_raster */
+
+#ifndef GL_SGIX_fog_offset
+#define GL_SGIX_fog_offset 1
+#define GL_FOG_OFFSET_SGIX 0x8198
+#define GL_FOG_OFFSET_VALUE_SGIX 0x8199
+#endif /* GL_SGIX_fog_offset */
+
+#ifndef GL_SGIX_fragment_lighting
+#define GL_SGIX_fragment_lighting 1
+#define GL_FRAGMENT_LIGHTING_SGIX 0x8400
+#define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401
+#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402
+#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403
+#define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404
+#define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405
+#define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406
+#define GL_LIGHT_ENV_MODE_SGIX 0x8407
+#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408
+#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409
+#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A
+#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B
+#define GL_FRAGMENT_LIGHT0_SGIX 0x840C
+#define GL_FRAGMENT_LIGHT1_SGIX 0x840D
+#define GL_FRAGMENT_LIGHT2_SGIX 0x840E
+#define GL_FRAGMENT_LIGHT3_SGIX 0x840F
+#define GL_FRAGMENT_LIGHT4_SGIX 0x8410
+#define GL_FRAGMENT_LIGHT5_SGIX 0x8411
+#define GL_FRAGMENT_LIGHT6_SGIX 0x8412
+#define GL_FRAGMENT_LIGHT7_SGIX 0x8413
+typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum face, GLenum mode);
+GLAPI void APIENTRY glFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glFragmentLightiSGIX (GLenum light, GLenum pname, GLint param);
+GLAPI void APIENTRY glFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum pname, GLint param);
+GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum pname, const GLint *params);
+GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param);
+GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params);
+GLAPI void APIENTRY glLightEnviSGIX (GLenum pname, GLint param);
+#endif
+#endif /* GL_SGIX_fragment_lighting */
+
+#ifndef GL_SGIX_framezoom
+#define GL_SGIX_framezoom 1
+#define GL_FRAMEZOOM_SGIX 0x818B
+#define GL_FRAMEZOOM_FACTOR_SGIX 0x818C
+#define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D
+typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFrameZoomSGIX (GLint factor);
+#endif
+#endif /* GL_SGIX_framezoom */
+
+#ifndef GL_SGIX_igloo_interface
+#define GL_SGIX_igloo_interface 1
+typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const void *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const void *params);
+#endif
+#endif /* GL_SGIX_igloo_interface */
+
+#ifndef GL_SGIX_instruments
+#define GL_SGIX_instruments 1
+#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180
+#define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181
+typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer);
+typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p);
+typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker);
+typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLint APIENTRY glGetInstrumentsSGIX (void);
+GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei size, GLint *buffer);
+GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *marker_p);
+GLAPI void APIENTRY glReadInstrumentsSGIX (GLint marker);
+GLAPI void APIENTRY glStartInstrumentsSGIX (void);
+GLAPI void APIENTRY glStopInstrumentsSGIX (GLint marker);
+#endif
+#endif /* GL_SGIX_instruments */
+
+#ifndef GL_SGIX_interlace
+#define GL_SGIX_interlace 1
+#define GL_INTERLACE_SGIX 0x8094
+#endif /* GL_SGIX_interlace */
+
+#ifndef GL_SGIX_ir_instrument1
+#define GL_SGIX_ir_instrument1 1
+#define GL_IR_INSTRUMENT1_SGIX 0x817F
+#endif /* GL_SGIX_ir_instrument1 */
+
+#ifndef GL_SGIX_list_priority
+#define GL_SGIX_list_priority 1
+#define GL_LIST_PRIORITY_SGIX 0x8182
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params);
+GLAPI void APIENTRY glListParameterfSGIX (GLuint list, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glListParameteriSGIX (GLuint list, GLenum pname, GLint param);
+GLAPI void APIENTRY glListParameterivSGIX (GLuint list, GLenum pname, const GLint *params);
+#endif
+#endif /* GL_SGIX_list_priority */
+
+#ifndef GL_SGIX_pixel_texture
+#define GL_SGIX_pixel_texture 1
+#define GL_PIXEL_TEX_GEN_SGIX 0x8139
+#define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B
+typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenSGIX (GLenum mode);
+#endif
+#endif /* GL_SGIX_pixel_texture */
+
+#ifndef GL_SGIX_pixel_tiles
+#define GL_SGIX_pixel_tiles 1
+#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E
+#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F
+#define GL_PIXEL_TILE_WIDTH_SGIX 0x8140
+#define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141
+#define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142
+#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143
+#define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144
+#define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145
+#endif /* GL_SGIX_pixel_tiles */
+
+#ifndef GL_SGIX_polynomial_ffd
+#define GL_SGIX_polynomial_ffd 1
+#define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001
+#define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002
+#define GL_GEOMETRY_DEFORMATION_SGIX 0x8194
+#define GL_TEXTURE_DEFORMATION_SGIX 0x8195
+#define GL_DEFORMATIONS_MASK_SGIX 0x8196
+#define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points);
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points);
+typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points);
+GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points);
+GLAPI void APIENTRY glDeformSGIX (GLbitfield mask);
+GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield mask);
+#endif
+#endif /* GL_SGIX_polynomial_ffd */
+
+#ifndef GL_SGIX_reference_plane
+#define GL_SGIX_reference_plane 1
+#define GL_REFERENCE_PLANE_SGIX 0x817D
+#define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E
+typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *equation);
+#endif
+#endif /* GL_SGIX_reference_plane */
+
+#ifndef GL_SGIX_resample
+#define GL_SGIX_resample 1
+#define GL_PACK_RESAMPLE_SGIX 0x842C
+#define GL_UNPACK_RESAMPLE_SGIX 0x842D
+#define GL_RESAMPLE_REPLICATE_SGIX 0x842E
+#define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F
+#define GL_RESAMPLE_DECIMATE_SGIX 0x8430
+#endif /* GL_SGIX_resample */
+
+#ifndef GL_SGIX_scalebias_hint
+#define GL_SGIX_scalebias_hint 1
+#define GL_SCALEBIAS_HINT_SGIX 0x8322
+#endif /* GL_SGIX_scalebias_hint */
+
+#ifndef GL_SGIX_shadow
+#define GL_SGIX_shadow 1
+#define GL_TEXTURE_COMPARE_SGIX 0x819A
+#define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B
+#define GL_TEXTURE_LEQUAL_R_SGIX 0x819C
+#define GL_TEXTURE_GEQUAL_R_SGIX 0x819D
+#endif /* GL_SGIX_shadow */
+
+#ifndef GL_SGIX_shadow_ambient
+#define GL_SGIX_shadow_ambient 1
+#define GL_SHADOW_AMBIENT_SGIX 0x80BF
+#endif /* GL_SGIX_shadow_ambient */
+
+#ifndef GL_SGIX_sprite
+#define GL_SGIX_sprite 1
+#define GL_SPRITE_SGIX 0x8148
+#define GL_SPRITE_MODE_SGIX 0x8149
+#define GL_SPRITE_AXIS_SGIX 0x814A
+#define GL_SPRITE_TRANSLATION_SGIX 0x814B
+#define GL_SPRITE_AXIAL_SGIX 0x814C
+#define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D
+#define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum pname, GLint param);
+GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum pname, const GLint *params);
+#endif
+#endif /* GL_SGIX_sprite */
+
+#ifndef GL_SGIX_subsample
+#define GL_SGIX_subsample 1
+#define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0
+#define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1
+#define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2
+#define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3
+#define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4
+#endif /* GL_SGIX_subsample */
+
+#ifndef GL_SGIX_tag_sample_buffer
+#define GL_SGIX_tag_sample_buffer 1
+typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTagSampleBufferSGIX (void);
+#endif
+#endif /* GL_SGIX_tag_sample_buffer */
+
+#ifndef GL_SGIX_texture_add_env
+#define GL_SGIX_texture_add_env 1
+#define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE
+#endif /* GL_SGIX_texture_add_env */
+
+#ifndef GL_SGIX_texture_coordinate_clamp
+#define GL_SGIX_texture_coordinate_clamp 1
+#define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369
+#define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A
+#define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B
+#endif /* GL_SGIX_texture_coordinate_clamp */
+
+#ifndef GL_SGIX_texture_lod_bias
+#define GL_SGIX_texture_lod_bias 1
+#define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E
+#define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F
+#define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190
+#endif /* GL_SGIX_texture_lod_bias */
+
+#ifndef GL_SGIX_texture_multi_buffer
+#define GL_SGIX_texture_multi_buffer 1
+#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E
+#endif /* GL_SGIX_texture_multi_buffer */
+
+#ifndef GL_SGIX_texture_scale_bias
+#define GL_SGIX_texture_scale_bias 1
+#define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179
+#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A
+#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B
+#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C
+#endif /* GL_SGIX_texture_scale_bias */
+
+#ifndef GL_SGIX_vertex_preclip
+#define GL_SGIX_vertex_preclip 1
+#define GL_VERTEX_PRECLIP_SGIX 0x83EE
+#define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF
+#endif /* GL_SGIX_vertex_preclip */
+
+#ifndef GL_SGIX_ycrcb
+#define GL_SGIX_ycrcb 1
+#define GL_YCRCB_422_SGIX 0x81BB
+#define GL_YCRCB_444_SGIX 0x81BC
+#endif /* GL_SGIX_ycrcb */
+
+#ifndef GL_SGIX_ycrcb_subsample
+#define GL_SGIX_ycrcb_subsample 1
+#endif /* GL_SGIX_ycrcb_subsample */
+
+#ifndef GL_SGIX_ycrcba
+#define GL_SGIX_ycrcba 1
+#define GL_YCRCB_SGIX 0x8318
+#define GL_YCRCBA_SGIX 0x8319
+#endif /* GL_SGIX_ycrcba */
+
+#ifndef GL_SGI_color_matrix
+#define GL_SGI_color_matrix 1
+#define GL_COLOR_MATRIX_SGI 0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB
+#endif /* GL_SGI_color_matrix */
+
+#ifndef GL_SGI_color_table
+#define GL_SGI_color_table 1
+#define GL_COLOR_TABLE_SGI 0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2
+#define GL_PROXY_COLOR_TABLE_SGI 0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5
+#define GL_COLOR_TABLE_SCALE_SGI 0x80D6
+#define GL_COLOR_TABLE_BIAS_SGI 0x80D7
+#define GL_COLOR_TABLE_FORMAT_SGI 0x80D8
+#define GL_COLOR_TABLE_WIDTH_SGI 0x80D9
+#define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF
+typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, void *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
+GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, void *table);
+GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params);
+#endif
+#endif /* GL_SGI_color_table */
+
+#ifndef GL_SGI_texture_color_table
+#define GL_SGI_texture_color_table 1
+#define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC
+#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD
+#endif /* GL_SGI_texture_color_table */
+
+#ifndef GL_SUNX_constant_data
+#define GL_SUNX_constant_data 1
+#define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5
+#define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6
+typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFinishTextureSUNX (void);
+#endif
+#endif /* GL_SUNX_constant_data */
+
+#ifndef GL_SUN_convolution_border_modes
+#define GL_SUN_convolution_border_modes 1
+#define GL_WRAP_BORDER_SUN 0x81D4
+#endif /* GL_SUN_convolution_border_modes */
+
+#ifndef GL_SUN_global_alpha
+#define GL_SUN_global_alpha 1
+#define GL_GLOBAL_ALPHA_SUN 0x81D9
+#define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte factor);
+GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort factor);
+GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint factor);
+GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat factor);
+GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble factor);
+GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte factor);
+GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort factor);
+GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint factor);
+#endif
+#endif /* GL_SUN_global_alpha */
+
+#ifndef GL_SUN_mesh_array
+#define GL_SUN_mesh_array 1
+#define GL_QUAD_MESH_SUN 0x8614
+#define GL_TRIANGLE_MESH_SUN 0x8615
+typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width);
+#endif
+#endif /* GL_SUN_mesh_array */
+
+#ifndef GL_SUN_slice_accum
+#define GL_SUN_slice_accum 1
+#define GL_SLICE_ACCUM_SUN 0x85CC
+#endif /* GL_SUN_slice_accum */
+
+#ifndef GL_SUN_triangle_list
+#define GL_SUN_triangle_list 1
+#define GL_RESTART_SUN 0x0001
+#define GL_REPLACE_MIDDLE_SUN 0x0002
+#define GL_REPLACE_OLDEST_SUN 0x0003
+#define GL_TRIANGLE_LIST_SUN 0x81D7
+#define GL_REPLACEMENT_CODE_SUN 0x81D8
+#define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0
+#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1
+#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2
+#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3
+#define GL_R1UI_V3F_SUN 0x85C4
+#define GL_R1UI_C4UB_V3F_SUN 0x85C5
+#define GL_R1UI_C3F_V3F_SUN 0x85C6
+#define GL_R1UI_N3F_V3F_SUN 0x85C7
+#define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8
+#define GL_R1UI_T2F_V3F_SUN 0x85C9
+#define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA
+#define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const void **pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code);
+GLAPI void APIENTRY glReplacementCodeusSUN (GLushort code);
+GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code);
+GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code);
+GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code);
+GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code);
+GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const void **pointer);
+#endif
+#endif /* GL_SUN_triangle_list */
+
+#ifndef GL_SUN_vertex
+#define GL_SUN_vertex 1
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y);
+GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v);
+GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v);
+GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v);
+GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+#endif
+#endif /* GL_SUN_vertex */
+
+#ifndef GL_WIN_phong_shading
+#define GL_WIN_phong_shading 1
+#define GL_PHONG_WIN 0x80EA
+#define GL_PHONG_HINT_WIN 0x80EB
+#endif /* GL_WIN_phong_shading */
+
+#ifndef GL_WIN_specular_fog
+#define GL_WIN_specular_fog 1
+#define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC
+#endif /* GL_WIN_specular_fog */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/SDL2/include/SDL_opengles.h b/external/SDL2/include/SDL_opengles.h
new file mode 100644
index 0000000..bcc1277
--- /dev/null
+++ b/external/SDL2/include/SDL_opengles.h
@@ -0,0 +1,38 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_opengles.h
+ *
+ * This is a simple file to encapsulate the OpenGL ES 1.X API headers.
+ */
+
+#ifdef __IPHONEOS__
+#include <OpenGLES/ES1/gl.h>
+#include <OpenGLES/ES1/glext.h>
+#else
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
diff --git a/external/SDL2/include/SDL_opengles2.h b/external/SDL2/include/SDL_opengles2.h
new file mode 100644
index 0000000..edcd1a2
--- /dev/null
+++ b/external/SDL2/include/SDL_opengles2.h
@@ -0,0 +1,50 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_opengles2.h
+ *
+ * This is a simple file to encapsulate the OpenGL ES 2.0 API headers.
+ */
+#ifndef _MSC_VER
+
+#ifdef __IPHONEOS__
+#include <OpenGLES/ES2/gl.h>
+#include <OpenGLES/ES2/glext.h>
+#else
+#include <GLES2/gl2platform.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#endif
+
+#else /* _MSC_VER */
+
+/* OpenGL ES2 headers for Visual Studio */
+#include "SDL_opengles2_khrplatform.h"
+#include "SDL_opengles2_gl2platform.h"
+#include "SDL_opengles2_gl2.h"
+#include "SDL_opengles2_gl2ext.h"
+
+#endif /* _MSC_VER */
+
+#ifndef APIENTRY
+#define APIENTRY GL_APIENTRY
+#endif
diff --git a/external/SDL2/include/SDL_opengles2_gl2.h b/external/SDL2/include/SDL_opengles2_gl2.h
new file mode 100644
index 0000000..c62fb0a
--- /dev/null
+++ b/external/SDL2/include/SDL_opengles2_gl2.h
@@ -0,0 +1,621 @@
+#ifndef __gl2_h_
+#define __gl2_h_
+
+/* $Revision: 20555 $ on $Date:: 2013-02-12 14:32:47 -0800 #$ */
+
+/*#include <GLES2/gl2platform.h>*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*-------------------------------------------------------------------------
+ * Data type definitions
+ *-----------------------------------------------------------------------*/
+
+typedef void GLvoid;
+typedef char GLchar;
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef khronos_int8_t GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef khronos_uint8_t GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef khronos_int32_t GLfixed;
+
+/* GL types for handling large vertex buffer objects */
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t GLsizeiptr;
+
+/* OpenGL ES core versions */
+#define GL_ES_VERSION_2_0 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Boolean */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* AlphaFunction (not supported in ES20) */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+#define GL_FUNC_ADD 0x8006
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+
+/* BlendSubtract */
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+
+/* Separate Blend Functions */
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BLEND_COLOR 0x8005
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+
+/* CullFaceMode */
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* DepthFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* EnableCap */
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_BLEND 0x0BE2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* FrontFaceDirection */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+/* GetPName */
+#define GL_LINE_WIDTH 0x0B21
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_VIEWPORT 0x0BA2
+#define GL_SCISSOR_BOX 0x0C10
+/* GL_SCISSOR_TEST */
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+/* GL_POLYGON_OFFSET_FILL */
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+
+/* GetTextureParameter */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* PixelFormat */
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_DELETE_STATUS 0x8B80
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+
+/* StencilFunction */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* StencilOp */
+/* GL_ZERO */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_INVERT 0x150A
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureMinFilter */
+/* GL_NEAREST */
+/* GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+
+/* TextureTarget */
+/* GL_TEXTURE_2D */
+#define GL_TEXTURE 0x1702
+
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+
+/* TextureUnit */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_MIRRORED_REPEAT 0x8370
+
+/* Uniform Types */
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_CUBE 0x8B60
+
+/* Vertex Arrays */
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+
+/* Read Format */
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+
+/* Shader Source */
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_COMPILER 0x8DFA
+
+/* Shader Binary */
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+
+/* Shader Precision-Specified Types */
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
+/* Framebuffer Object. */
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGB565 0x8D62
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_STENCIL_INDEX8 0x8D48
+
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+
+#define GL_NONE 0
+
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+
+/*-------------------------------------------------------------------------
+ * GL core functions.
+ *-----------------------------------------------------------------------*/
+
+GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name);
+GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode );
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
+GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
+GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
+GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
+GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
+GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glFinish (void);
+GL_APICALL void GL_APIENTRY glFlush (void);
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
+GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+GL_APICALL GLint GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLenum GL_APIENTRY glGetError (void);
+GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
+GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
+GL_APICALL GLint GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer);
+GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
+GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
+GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
+GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
+GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
+GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
+GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2_h_ */
+
diff --git a/external/SDL2/include/SDL_opengles2_gl2ext.h b/external/SDL2/include/SDL_opengles2_gl2ext.h
new file mode 100644
index 0000000..e8ca8b1
--- /dev/null
+++ b/external/SDL2/include/SDL_opengles2_gl2ext.h
@@ -0,0 +1,2050 @@
+#ifndef __gl2ext_h_
+#define __gl2ext_h_
+
+/* $Revision: 22801 $ on $Date:: 2013-08-21 03:20:48 -0700 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+# define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/* New types shared by several extensions */
+
+#ifndef __gl3_h_
+/* These are defined with respect to <inttypes.h> in the
+ * Apple extension spec, but they are also used by non-APPLE
+ * extensions, and in the Khronos header we use the Khronos
+ * portable types in khrplatform.h, which must be defined.
+ */
+typedef khronos_int64_t GLint64;
+typedef khronos_uint64_t GLuint64;
+typedef struct __GLsync *GLsync;
+#endif
+
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES 0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#endif
+
+/* GL_OES_depth_texture */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+/* GLeglImageOES defined in GL_OES_EGL_image already. */
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#define GL_SAMPLER_EXTERNAL_OES 0x8D66
+#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_UNSIGNED_INT 0x1405
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE
+#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES 0x88B9
+#define GL_BUFFER_ACCESS_OES 0x88BB
+#define GL_BUFFER_MAPPED_OES 0x88BC
+#define GL_BUFFER_MAP_POINTER_OES 0x88BD
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+
+/* GL_OES_required_internalformat */
+#ifndef GL_OES_required_internalformat
+#define GL_ALPHA8_OES 0x803C
+#define GL_DEPTH_COMPONENT16_OES 0x81A5
+/* reuse GL_DEPTH_COMPONENT24_OES */
+/* reuse GL_DEPTH24_STENCIL8_OES */
+/* reuse GL_DEPTH_COMPONENT32_OES */
+#define GL_LUMINANCE4_ALPHA4_OES 0x8043
+#define GL_LUMINANCE8_ALPHA8_OES 0x8045
+#define GL_LUMINANCE8_OES 0x8040
+#define GL_RGBA4_OES 0x8056
+#define GL_RGB5_A1_OES 0x8057
+#define GL_RGB565_OES 0x8D62
+/* reuse GL_RGB8_OES */
+/* reuse GL_RGBA8_OES */
+/* reuse GL_RGB10_EXT */
+/* reuse GL_RGB10_A2_EXT */
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES 0x8051
+#define GL_RGBA8_OES 0x8058
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES 0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES 0x8D47
+#endif
+
+#ifndef GL_OES_surfaceless_context
+#define GL_FRAMEBUFFER_UNDEFINED_OES 0x8219
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_TEXTURE_WRAP_R_OES 0x8072
+#define GL_TEXTURE_3D_OES 0x806F
+#define GL_TEXTURE_BINDING_3D_OES 0x806A
+#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073
+#define GL_SAMPLER_3D_OES 0x8B5F
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4
+#endif
+
+/* GL_OES_texture_float */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_HALF_FLOAT_OES 0x8D61
+#endif
+
+/* GL_OES_texture_half_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_npot */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5
+#endif
+
+/* GL_OES_vertex_half_float */
+/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6
+#define GL_INT_10_10_10_2_OES 0x8DF7
+#endif
+
+/*------------------------------------------------------------------------*
+ * KHR extension tokens
+ *------------------------------------------------------------------------*/
+
+#ifndef GL_KHR_debug
+typedef void (GL_APIENTRYP GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243
+#define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245
+#define GL_DEBUG_SOURCE_API_KHR 0x8246
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247
+#define GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249
+#define GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A
+#define GL_DEBUG_SOURCE_OTHER_KHR 0x824B
+#define GL_DEBUG_TYPE_ERROR_KHR 0x824C
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E
+#define GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F
+#define GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250
+#define GL_DEBUG_TYPE_OTHER_KHR 0x8251
+#define GL_DEBUG_TYPE_MARKER_KHR 0x8268
+#define GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269
+#define GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A
+#define GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B
+#define GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C
+#define GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D
+#define GL_BUFFER_KHR 0x82E0
+#define GL_SHADER_KHR 0x82E1
+#define GL_PROGRAM_KHR 0x82E2
+#define GL_QUERY_KHR 0x82E3
+/* PROGRAM_PIPELINE only in GL */
+#define GL_SAMPLER_KHR 0x82E6
+/* DISPLAY_LIST only in GL */
+#define GL_MAX_LABEL_LENGTH_KHR 0x82E8
+#define GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144
+#define GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145
+#define GL_DEBUG_SEVERITY_HIGH_KHR 0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147
+#define GL_DEBUG_SEVERITY_LOW_KHR 0x9148
+#define GL_DEBUG_OUTPUT_KHR 0x92E0
+#define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002
+#define GL_STACK_OVERFLOW_KHR 0x0503
+#define GL_STACK_UNDERFLOW_KHR 0x0504
+#endif
+
+#ifndef GL_KHR_texture_compression_astc_ldr
+#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0
+#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1
+#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2
+#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3
+#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4
+#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5
+#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6
+#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7
+#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8
+#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9
+#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA
+#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB
+#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC
+#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD 0x87F9
+#define GL_3DC_XY_AMD 0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD 0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
+#endif
+
+/* GL_AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_COUNTER_TYPE_AMD 0x8BC0
+#define GL_COUNTER_RANGE_AMD 0x8BC1
+#define GL_UNSIGNED_INT64_AMD 0x8BC2
+#define GL_PERCENTAGE_AMD 0x8BC3
+#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4
+#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5
+#define GL_PERFMON_RESULT_AMD 0x8BC6
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_Z400_BINARY_AMD 0x8740
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_depth_texture */
+#ifndef GL_ANGLE_depth_texture
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_UNSIGNED_INT 0x1405
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_READ_FRAMEBUFFER_ANGLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56
+#define GL_MAX_SAMPLES_ANGLE 0x8D57
+#endif
+
+/* GL_ANGLE_instanced_arrays */
+#ifndef GL_ANGLE_instanced_arrays
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE
+#endif
+
+/* GL_ANGLE_pack_reverse_row_order */
+#ifndef GL_ANGLE_pack_reverse_row_order
+#define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4
+#endif
+
+/* GL_ANGLE_program_binary */
+#ifndef GL_ANGLE_program_binary
+#define GL_PROGRAM_BINARY_ANGLE 0x93A6
+#endif
+
+/* GL_ANGLE_texture_compression_dxt3 */
+#ifndef GL_ANGLE_texture_compression_dxt3
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2
+#endif
+
+/* GL_ANGLE_texture_compression_dxt5 */
+#ifndef GL_ANGLE_texture_compression_dxt5
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3
+#endif
+
+/* GL_ANGLE_texture_usage */
+#ifndef GL_ANGLE_texture_usage
+#define GL_TEXTURE_USAGE_ANGLE 0x93A2
+#define GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3
+#endif
+
+/* GL_ANGLE_translated_shader_source */
+#ifndef GL_ANGLE_translated_shader_source
+#define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_copy_texture_levels */
+/* No new tokens introduced by this extension. */
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56
+#define GL_MAX_SAMPLES_APPLE 0x8D57
+#define GL_READ_FRAMEBUFFER_APPLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA
+#endif
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_RGB_422_APPLE 0x8A1F
+#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
+#endif
+
+/* GL_APPLE_sync */
+#ifndef GL_APPLE_sync
+
+#define GL_SYNC_OBJECT_APPLE 0x8A53
+#define GL_MAX_SERVER_WAIT_TIMEOUT_APPLE 0x9111
+#define GL_OBJECT_TYPE_APPLE 0x9112
+#define GL_SYNC_CONDITION_APPLE 0x9113
+#define GL_SYNC_STATUS_APPLE 0x9114
+#define GL_SYNC_FLAGS_APPLE 0x9115
+#define GL_SYNC_FENCE_APPLE 0x9116
+#define GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE 0x9117
+#define GL_UNSIGNALED_APPLE 0x9118
+#define GL_SIGNALED_APPLE 0x9119
+#define GL_ALREADY_SIGNALED_APPLE 0x911A
+#define GL_TIMEOUT_EXPIRED_APPLE 0x911B
+#define GL_CONDITION_SATISFIED_APPLE 0x911C
+#define GL_WAIT_FAILED_APPLE 0x911D
+#define GL_SYNC_FLUSH_COMMANDS_BIT_APPLE 0x00000001
+#define GL_TIMEOUT_IGNORED_APPLE 0xFFFFFFFFFFFFFFFFull
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_program_binary */
+#ifndef GL_ARM_mali_program_binary
+#define GL_MALI_PROGRAM_BINARY_ARM 0x8F61
+#endif
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_MALI_SHADER_BINARY_ARM 0x8F60
+#endif
+
+/* GL_ARM_rgba8 */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_MIN_EXT 0x8007
+#define GL_MAX_EXT 0x8008
+#endif
+
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_RGBA16F_EXT 0x881A
+#define GL_RGB16F_EXT 0x881B
+#define GL_RG16F_EXT 0x822F
+#define GL_R16F_EXT 0x822D
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211
+#define GL_UNSIGNED_NORMALIZED_EXT 0x8C17
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F
+#define GL_PROGRAM_OBJECT_EXT 0x8B40
+#define GL_SHADER_OBJECT_EXT 0x8B48
+#define GL_BUFFER_OBJECT_EXT 0x9151
+#define GL_QUERY_OBJECT_EXT 0x9153
+#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154
+#endif
+
+/* GL_EXT_debug_marker */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_COLOR_EXT 0x1800
+#define GL_DEPTH_EXT 0x1801
+#define GL_STENCIL_EXT 0x1802
+#endif
+
+#ifndef GL_EXT_disjoint_timer_query
+#define GL_QUERY_COUNTER_BITS_EXT 0x8864
+#define GL_CURRENT_QUERY_EXT 0x8865
+#define GL_QUERY_RESULT_EXT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867
+#define GL_TIME_ELAPSED_EXT 0x88BF
+#define GL_TIMESTAMP_EXT 0x8E28
+#define GL_GPU_DISJOINT_EXT 0x8FBB
+#endif
+
+#ifndef GL_EXT_draw_buffers
+#define GL_EXT_draw_buffers 1
+#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
+#define GL_MAX_DRAW_BUFFERS_EXT 0x8824
+#define GL_DRAW_BUFFER0_EXT 0x8825
+#define GL_DRAW_BUFFER1_EXT 0x8826
+#define GL_DRAW_BUFFER2_EXT 0x8827
+#define GL_DRAW_BUFFER3_EXT 0x8828
+#define GL_DRAW_BUFFER4_EXT 0x8829
+#define GL_DRAW_BUFFER5_EXT 0x882A
+#define GL_DRAW_BUFFER6_EXT 0x882B
+#define GL_DRAW_BUFFER7_EXT 0x882C
+#define GL_DRAW_BUFFER8_EXT 0x882D
+#define GL_DRAW_BUFFER9_EXT 0x882E
+#define GL_DRAW_BUFFER10_EXT 0x882F
+#define GL_DRAW_BUFFER11_EXT 0x8830
+#define GL_DRAW_BUFFER12_EXT 0x8831
+#define GL_DRAW_BUFFER13_EXT 0x8832
+#define GL_DRAW_BUFFER14_EXT 0x8833
+#define GL_DRAW_BUFFER15_EXT 0x8834
+#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
+#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
+#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
+#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
+#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
+#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
+#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
+#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
+#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
+#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
+#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
+#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
+#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
+#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
+#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
+#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
+#endif
+
+/* GL_EXT_map_buffer_range */
+#ifndef GL_EXT_map_buffer_range
+#define GL_MAP_READ_BIT_EXT 0x0001
+#define GL_MAP_WRITE_BIT_EXT 0x0002
+#define GL_MAP_INVALIDATE_RANGE_BIT_EXT 0x0004
+#define GL_MAP_INVALIDATE_BUFFER_BIT_EXT 0x0008
+#define GL_MAP_FLUSH_EXPLICIT_BIT_EXT 0x0010
+#define GL_MAP_UNSYNCHRONIZED_BIT_EXT 0x0020
+#endif
+
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C
+/* reuse values from GL_EXT_framebuffer_multisample (desktop extension) */
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
+#define GL_MAX_SAMPLES_EXT 0x8D57
+#endif
+
+/* GL_EXT_multiview_draw_buffers */
+#ifndef GL_EXT_multiview_draw_buffers
+#define GL_COLOR_ATTACHMENT_EXT 0x90F0
+#define GL_MULTIVIEW_EXT 0x90F1
+#define GL_DRAW_BUFFER_EXT 0x0C01
+#define GL_READ_BUFFER_EXT 0x0C02
+#define GL_MAX_MULTIVIEW_BUFFERS_EXT 0x90F2
+#endif
+
+/* GL_EXT_multi_draw_arrays */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A
+#define GL_CURRENT_QUERY_EXT 0x8865
+#define GL_QUERY_RESULT_EXT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867
+#endif
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_BGRA_EXT 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366
+#endif
+
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+/* reuse GL_NO_ERROR */
+#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253
+#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254
+#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255
+#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3
+#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256
+#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252
+#define GL_NO_RESET_NOTIFICATION_EXT 0x8261
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_VERTEX_SHADER_BIT_EXT 0x00000001
+#define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002
+#define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF
+#define GL_PROGRAM_SEPARABLE_EXT 0x8258
+#define GL_ACTIVE_PROGRAM_EXT 0x8259
+#define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A
+#endif
+
+/* GL_EXT_shader_framebuffer_fetch */
+#ifndef GL_EXT_shader_framebuffer_fetch
+#define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52
+#endif
+
+/* GL_EXT_shader_texture_lod */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_TEXTURE_COMPARE_MODE_EXT 0x884C
+#define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D
+#define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E
+#define GL_SAMPLER_2D_SHADOW_EXT 0x8B62
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_SRGB_EXT 0x8C40
+#define GL_SRGB_ALPHA_EXT 0x8C42
+#define GL_SRGB8_ALPHA8_EXT 0x8C43
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210
+#endif
+
+/* GL_EXT_sRGB_write_control */
+#ifndef GL_EXT_sRGB_write_control
+#define GL_EXT_sRGB_write_control 1
+#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_RED_EXT 0x1903
+#define GL_RG_EXT 0x8227
+#define GL_R8_EXT 0x8229
+#define GL_RG8_EXT 0x822B
+#endif
+
+/* GL_EXT_texture_sRGB_decode */
+#ifndef GL_EXT_texture_sRGB_decode
+#define GL_EXT_texture_sRGB_decode 1
+#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48
+#define GL_DECODE_EXT 0x8A49
+#define GL_SKIP_DECODE_EXT 0x8A4A
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
+#define GL_ALPHA8_EXT 0x803C
+#define GL_LUMINANCE8_EXT 0x8040
+#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
+#define GL_RGBA32F_EXT 0x8814
+#define GL_RGB32F_EXT 0x8815
+#define GL_ALPHA32F_EXT 0x8816
+#define GL_LUMINANCE32F_EXT 0x8818
+#define GL_LUMINANCE_ALPHA32F_EXT 0x8819
+/* reuse GL_RGBA16F_EXT */
+/* reuse GL_RGB16F_EXT */
+#define GL_ALPHA16F_EXT 0x881C
+#define GL_LUMINANCE16F_EXT 0x881E
+#define GL_LUMINANCE_ALPHA16F_EXT 0x881F
+#define GL_RGB10_A2_EXT 0x8059
+#define GL_RGB10_EXT 0x8052
+#define GL_BGRA8_EXT 0x93A1
+#define GL_R8_EXT 0x8229
+#define GL_RG8_EXT 0x822B
+#define GL_R32F_EXT 0x822E
+#define GL_RG32F_EXT 0x8230
+#define GL_R16F_EXT 0x822D
+#define GL_RG16F_EXT 0x822F
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368
+#endif
+
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_UNPACK_ROW_LENGTH_EXT 0x0CF2
+#define GL_UNPACK_SKIP_ROWS_EXT 0x0CF3
+#define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_SHADER_BINARY_DMP 0x9250
+#endif
+
+/*------------------------------------------------------------------------*
+ * FJ extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_FJ_shader_binary_GCCSO */
+#ifndef GL_FJ_shader_binary_GCCSO
+#define GL_GCCSO_SHADER_BINARY_FJ 0x9260
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_SGX_PROGRAM_BINARY_IMG 0x9130
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_BGRA_IMG 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_SGX_BINARY_IMG 0x8C0A
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+#endif
+
+/* GL_IMG_texture_compression_pvrtc2 */
+#ifndef GL_IMG_texture_compression_pvrtc2
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG 0x9137
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG 0x9138
+#endif
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_RENDERBUFFER_SAMPLES_IMG 0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134
+#define GL_MAX_SAMPLES_IMG 0x9135
+#define GL_TEXTURE_SAMPLES_IMG 0x9136
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_COVERAGE_COMPONENT_NV 0x8ED0
+#define GL_COVERAGE_COMPONENT4_NV 0x8ED1
+#define GL_COVERAGE_ATTACHMENT_NV 0x8ED2
+#define GL_COVERAGE_BUFFERS_NV 0x8ED3
+#define GL_COVERAGE_SAMPLES_NV 0x8ED4
+#define GL_COVERAGE_ALL_FRAGMENTS_NV 0x8ED5
+#define GL_COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6
+#define GL_COVERAGE_AUTOMATIC_NV 0x8ED7
+#define GL_COVERAGE_BUFFER_BIT_NV 0x00008000
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_DEPTH_COMPONENT16_NONLINEAR_NV 0x8E2C
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_NV 0x8824
+#define GL_DRAW_BUFFER0_NV 0x8825
+#define GL_DRAW_BUFFER1_NV 0x8826
+#define GL_DRAW_BUFFER2_NV 0x8827
+#define GL_DRAW_BUFFER3_NV 0x8828
+#define GL_DRAW_BUFFER4_NV 0x8829
+#define GL_DRAW_BUFFER5_NV 0x882A
+#define GL_DRAW_BUFFER6_NV 0x882B
+#define GL_DRAW_BUFFER7_NV 0x882C
+#define GL_DRAW_BUFFER8_NV 0x882D
+#define GL_DRAW_BUFFER9_NV 0x882E
+#define GL_DRAW_BUFFER10_NV 0x882F
+#define GL_DRAW_BUFFER11_NV 0x8830
+#define GL_DRAW_BUFFER12_NV 0x8831
+#define GL_DRAW_BUFFER13_NV 0x8832
+#define GL_DRAW_BUFFER14_NV 0x8833
+#define GL_DRAW_BUFFER15_NV 0x8834
+#define GL_COLOR_ATTACHMENT0_NV 0x8CE0
+#define GL_COLOR_ATTACHMENT1_NV 0x8CE1
+#define GL_COLOR_ATTACHMENT2_NV 0x8CE2
+#define GL_COLOR_ATTACHMENT3_NV 0x8CE3
+#define GL_COLOR_ATTACHMENT4_NV 0x8CE4
+#define GL_COLOR_ATTACHMENT5_NV 0x8CE5
+#define GL_COLOR_ATTACHMENT6_NV 0x8CE6
+#define GL_COLOR_ATTACHMENT7_NV 0x8CE7
+#define GL_COLOR_ATTACHMENT8_NV 0x8CE8
+#define GL_COLOR_ATTACHMENT9_NV 0x8CE9
+#define GL_COLOR_ATTACHMENT10_NV 0x8CEA
+#define GL_COLOR_ATTACHMENT11_NV 0x8CEB
+#define GL_COLOR_ATTACHMENT12_NV 0x8CEC
+#define GL_COLOR_ATTACHMENT13_NV 0x8CED
+#define GL_COLOR_ATTACHMENT14_NV 0x8CEE
+#define GL_COLOR_ATTACHMENT15_NV 0x8CEF
+#endif
+
+/* GL_NV_draw_instanced */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_MAX_COLOR_ATTACHMENTS_NV 0x8CDF
+/* GL_COLOR_ATTACHMENT{0-15}_NV defined in GL_NV_draw_buffers already. */
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+#endif
+
+/* GL_NV_framebuffer_blit */
+#ifndef GL_NV_framebuffer_blit
+#define GL_READ_FRAMEBUFFER_NV 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_NV 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_NV 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_NV 0x8CAA
+#endif
+
+/* GL_NV_framebuffer_multisample */
+#ifndef GL_NV_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_NV 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_NV 0x8D56
+#define GL_MAX_SAMPLES_NV 0x8D57
+#endif
+
+/* GL_NV_generate_mipmap_sRGB */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_instanced_arrays */
+#ifndef GL_NV_instanced_arrays
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_NV 0x88FE
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_READ_BUFFER_NV 0x0C02
+#endif
+
+/* GL_NV_read_buffer_front */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_shadow_samplers_array */
+#ifndef GL_NV_shadow_samplers_array
+#define GL_SAMPLER_2D_ARRAY_SHADOW_NV 0x8DC4
+#endif
+
+/* GL_NV_shadow_samplers_cube */
+#ifndef GL_NV_shadow_samplers_cube
+#define GL_SAMPLER_CUBE_SHADOW_NV 0x8DC5
+#endif
+
+/* GL_NV_sRGB_formats */
+#ifndef GL_NV_sRGB_formats
+#define GL_SLUMINANCE_NV 0x8C46
+#define GL_SLUMINANCE_ALPHA_NV 0x8C44
+#define GL_SRGB8_NV 0x8C41
+#define GL_SLUMINANCE8_NV 0x8C47
+#define GL_SLUMINANCE8_ALPHA8_NV 0x8C45
+#define GL_COMPRESSED_SRGB_S3TC_DXT1_NV 0x8C4C
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV 0x8C4D
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV 0x8C4E
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV 0x8C4F
+#define GL_ETC1_SRGB8_NV 0x88EE
+#endif
+
+/* GL_NV_texture_border_clamp */
+#ifndef GL_NV_texture_border_clamp
+#define GL_TEXTURE_BORDER_COLOR_NV 0x1004
+#define GL_CLAMP_TO_BORDER_NV 0x812D
+#endif
+
+/* GL_NV_texture_compression_s3tc_update */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_npot_2D_mipmap */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
+ * QCOM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_ALPHA_TEST_QCOM 0x0BC0
+#define GL_ALPHA_TEST_FUNC_QCOM 0x0BC1
+#define GL_ALPHA_TEST_REF_QCOM 0x0BC2
+#endif
+
+/* GL_QCOM_binning_control */
+#ifndef GL_QCOM_binning_control
+#define GL_BINNING_CONTROL_HINT_QCOM 0x8FB0
+#define GL_CPU_OPTIMIZED_QCOM 0x8FB1
+#define GL_GPU_OPTIMIZED_QCOM 0x8FB2
+#define GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM 0x8FB3
+#endif
+
+/* GL_QCOM_driver_control */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_TEXTURE_WIDTH_QCOM 0x8BD2
+#define GL_TEXTURE_HEIGHT_QCOM 0x8BD3
+#define GL_TEXTURE_DEPTH_QCOM 0x8BD4
+#define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5
+#define GL_TEXTURE_FORMAT_QCOM 0x8BD6
+#define GL_TEXTURE_TYPE_QCOM 0x8BD7
+#define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8
+#define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9
+#define GL_TEXTURE_TARGET_QCOM 0x8BDA
+#define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB
+#define GL_STATE_RESTORE 0x8BDC
+#endif
+
+/* GL_QCOM_extended_get2 */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_WRITEONLY_RENDERING_QCOM 0x8823
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001
+#define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002
+#define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004
+#define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008
+#define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010
+#define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020
+#define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040
+#define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080
+#define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100
+#define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200
+#define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400
+#define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800
+#define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000
+#define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000
+#define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000
+#define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000
+#define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000
+#define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000
+#define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000
+#define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000
+#define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000
+#define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000
+#define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000
+#define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000
+#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000
+#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000
+#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000
+#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000
+#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000
+#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000
+#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000
+#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000
+#endif
+
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_SHADER_BINARY_VIV 0x8FC4
+#endif
+
+/*------------------------------------------------------------------------*
+ * End of extension tokens, start of corresponding extension functions
+ *------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 1
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 1
+#endif
+
+/* GL_OES_depth_texture */
+#ifndef GL_OES_depth_texture
+#define GL_OES_depth_texture 1
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
+/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 1
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 1
+#endif
+
+/* GL_OES_fragment_precision_high */
+#ifndef GL_OES_fragment_precision_high
+#define GL_OES_fragment_precision_high 1
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_OES_get_program_binary 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid **params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid **params);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 1
+#endif
+
+/* GL_OES_required_internalformat */
+#ifndef GL_OES_required_internalformat
+#define GL_OES_required_internalformat 1
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 1
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_OES_standard_derivatives 1
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 1
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 1
+#endif
+
+#ifndef GL_OES_surfaceless_context
+#define GL_OES_surfaceless_context 1
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_OES_texture_3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+
+/* GL_OES_texture_float */
+#ifndef GL_OES_texture_float
+#define GL_OES_texture_float 1
+#endif
+
+/* GL_OES_texture_float_linear */
+#ifndef GL_OES_texture_float_linear
+#define GL_OES_texture_float_linear 1
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_OES_texture_half_float 1
+#endif
+
+/* GL_OES_texture_half_float_linear */
+#ifndef GL_OES_texture_half_float_linear
+#define GL_OES_texture_half_float_linear 1
+#endif
+
+/* GL_OES_texture_npot */
+#ifndef GL_OES_texture_npot
+#define GL_OES_texture_npot 1
+#endif
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_OES_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLuint array);
+GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays);
+GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays);
+GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array);
+#endif
+typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
+typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
+#endif
+
+/* GL_OES_vertex_half_float */
+#ifndef GL_OES_vertex_half_float
+#define GL_OES_vertex_half_float 1
+#endif
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_OES_vertex_type_10_10_10_2 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * KHR extension functions
+ *------------------------------------------------------------------------*/
+
+#ifndef GL_KHR_debug
+#define GL_KHR_debug 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDebugMessageControlKHR (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+GL_APICALL void GL_APIENTRY glDebugMessageInsertKHR (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+GL_APICALL void GL_APIENTRY glDebugMessageCallbackKHR (GLDEBUGPROCKHR callback, const void *userParam);
+GL_APICALL GLuint GL_APIENTRY glGetDebugMessageLogKHR (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+GL_APICALL void GL_APIENTRY glPushDebugGroupKHR (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+GL_APICALL void GL_APIENTRY glPopDebugGroupKHR (void);
+GL_APICALL void GL_APIENTRY glObjectLabelKHR (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+GL_APICALL void GL_APIENTRY glGetObjectLabelKHR (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+GL_APICALL void GL_APIENTRY glObjectPtrLabelKHR (const void *ptr, GLsizei length, const GLchar *label);
+GL_APICALL void GL_APIENTRY glGetObjectPtrLabelKHR (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+GL_APICALL void GL_APIENTRY glGetPointervKHR (GLenum pname, GLvoid **params);
+#endif
+typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECONTROLKHRPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGEINSERTKHRPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECALLBACKKHRPROC) (GLDEBUGPROCKHR callback, const void *userParam);
+typedef GLuint (GL_APIENTRYP PFNGLGETDEBUGMESSAGELOGKHRPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+typedef void (GL_APIENTRYP PFNGLPUSHDEBUGGROUPKHRPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+typedef void (GL_APIENTRYP PFNGLPOPDEBUGGROUPKHRPROC) (void);
+typedef void (GL_APIENTRYP PFNGLOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (GL_APIENTRYP PFNGLOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETPOINTERVKHRPROC) (GLenum pname, GLvoid **params);
+#endif
+
+#ifndef GL_KHR_texture_compression_astc_ldr
+#define GL_KHR_texture_compression_astc_ldr 1
+#endif
+
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 1
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 1
+#endif
+
+/* AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_AMD_performance_monitor 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_AMD_program_binary_Z400 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_depth_texture */
+#ifndef GL_ANGLE_depth_texture
+#define GL_ANGLE_depth_texture 1
+#endif
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_ANGLE_framebuffer_blit 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_ANGLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_ANGLE_instanced_arrays
+#define GL_ANGLE_instanced_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDANGLEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDANGLEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORANGLEPROC) (GLuint index, GLuint divisor);
+#endif
+
+/* GL_ANGLE_pack_reverse_row_order */
+#ifndef GL_ANGLE_pack_reverse_row_order
+#define GL_ANGLE_pack_reverse_row_order 1
+#endif
+
+/* GL_ANGLE_program_binary */
+#ifndef GL_ANGLE_program_binary
+#define GL_ANGLE_program_binary 1
+#endif
+
+/* GL_ANGLE_texture_compression_dxt3 */
+#ifndef GL_ANGLE_texture_compression_dxt3
+#define GL_ANGLE_texture_compression_dxt3 1
+#endif
+
+/* GL_ANGLE_texture_compression_dxt5 */
+#ifndef GL_ANGLE_texture_compression_dxt5
+#define GL_ANGLE_texture_compression_dxt5 1
+#endif
+
+/* GL_ANGLE_texture_usage */
+#ifndef GL_ANGLE_texture_usage
+#define GL_ANGLE_texture_usage 1
+#endif
+
+#ifndef GL_ANGLE_translated_shader_source
+#define GL_ANGLE_translated_shader_source 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source);
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_copy_texture_levels */
+#ifndef GL_APPLE_copy_texture_levels
+#define GL_APPLE_copy_texture_levels 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glCopyTextureLevelsAPPLE (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount);
+#endif
+typedef void (GL_APIENTRYP PFNGLCOPYTEXTURELEVELSAPPLEPROC) (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount);
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_APPLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
+#endif
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_APPLE_rgb_422 1
+#endif
+
+/* GL_APPLE_sync */
+#ifndef GL_APPLE_sync
+#define GL_APPLE_sync 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLsync GL_APIENTRY glFenceSyncAPPLE (GLenum condition, GLbitfield flags);
+GL_APICALL GLboolean GL_APIENTRY glIsSyncAPPLE (GLsync sync);
+GL_APICALL void GL_APIENTRY glDeleteSyncAPPLE (GLsync sync);
+GL_APICALL GLenum GL_APIENTRY glClientWaitSyncAPPLE (GLsync sync, GLbitfield flags, GLuint64 timeout);
+GL_APICALL void GL_APIENTRY glWaitSyncAPPLE (GLsync sync, GLbitfield flags, GLuint64 timeout);
+GL_APICALL void GL_APIENTRY glGetInteger64vAPPLE (GLenum pname, GLint64 *params);
+GL_APICALL void GL_APIENTRY glGetSyncivAPPLE (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+#endif
+typedef GLsync (GL_APIENTRYP PFNGLFENCESYNCAPPLEPROC) (GLenum condition, GLbitfield flags);
+typedef GLboolean (GL_APIENTRYP PFNGLISSYNCAPPLEPROC) (GLsync sync);
+typedef void (GL_APIENTRYP PFNGLDELETESYNCAPPLEPROC) (GLsync sync);
+typedef GLenum (GL_APIENTRYP PFNGLCLIENTWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (GL_APIENTRYP PFNGLWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (GL_APIENTRYP PFNGLGETINTEGER64VAPPLEPROC) (GLenum pname, GLint64 *params);
+typedef void (GL_APIENTRYP PFNGLGETSYNCIVAPPLEPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_APPLE_texture_format_BGRA8888 1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_APPLE_texture_max_level 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_program_binary */
+#ifndef GL_ARM_mali_program_binary
+#define GL_ARM_mali_program_binary 1
+#endif
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_ARM_mali_shader_binary 1
+#endif
+
+/* GL_ARM_rgba8 */
+#ifndef GL_ARM_rgba8
+#define GL_ARM_rgba8 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+#endif
+
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_EXT_color_buffer_half_float 1
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_EXT_debug_label 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+GL_APICALL void GL_APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+typedef void (GL_APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+
+/* GL_EXT_debug_marker */
+#ifndef GL_EXT_debug_marker
+#define GL_EXT_debug_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void);
+#endif
+typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
+#endif
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_EXT_discard_framebuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+
+#ifndef GL_EXT_disjoint_timer_query
+#define GL_EXT_disjoint_timer_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizei n, GLuint *ids);
+GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizei n, const GLuint *ids);
+GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLuint id);
+GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenum target, GLuint id);
+GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenum target);
+GL_APICALL void GL_APIENTRY glQueryCounterEXT (GLuint id, GLenum target);
+GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenum target, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glGetQueryObjectivEXT (GLuint id, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLuint id, GLenum pname, GLuint *params);
+GL_APICALL void GL_APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64 *params);
+GL_APICALL void GL_APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64 *params);
+#endif
+typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
+typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id);
+typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
+typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTIVEXTPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params);
+typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params);
+#endif /* GL_EXT_disjoint_timer_query */
+
+#ifndef GL_EXT_draw_buffers
+#define GL_EXT_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawBuffersEXT (GLsizei n, const GLenum *bufs);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);
+#endif /* GL_EXT_draw_buffers */
+
+/* GL_EXT_map_buffer_range */
+#ifndef GL_EXT_map_buffer_range
+#define GL_EXT_map_buffer_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+GL_APICALL void GL_APIENTRY glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
+#endif
+
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_EXT_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
+/* GL_EXT_multiview_draw_buffers */
+#ifndef GL_EXT_multiview_draw_buffers
+#define GL_EXT_multiview_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glReadBufferIndexedEXT (GLenum src, GLint index);
+GL_APICALL void GL_APIENTRY glDrawBuffersIndexedEXT (GLint n, const GLenum *location, const GLint *indices);
+GL_APICALL void GL_APIENTRY glGetIntegeri_vEXT (GLenum target, GLuint index, GLint *data);
+#endif
+typedef void (GL_APIENTRYP PFNGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index);
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices);
+typedef void (GL_APIENTRYP PFNGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data);
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount);
+#endif
+
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_EXT_occlusion_query_boolean 1
+/* All entry points also exist in GL_EXT_disjoint_timer_query */
+#endif
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_EXT_read_format_bgra 1
+#endif
+
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+#define GL_EXT_robustness 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void);
+GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data);
+GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
+typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_EXT_separate_shader_objects 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glUseProgramStagesEXT (GLuint pipeline, GLbitfield stages, GLuint program);
+GL_APICALL void GL_APIENTRY glActiveShaderProgramEXT (GLuint pipeline, GLuint program);
+GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramvEXT (GLenum type, GLsizei count, const GLchar **strings);
+GL_APICALL void GL_APIENTRY glBindProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glDeleteProgramPipelinesEXT (GLsizei n, const GLuint *pipelines);
+GL_APICALL void GL_APIENTRY glGenProgramPipelinesEXT (GLsizei n, GLuint *pipelines);
+GL_APICALL GLboolean GL_APIENTRY glIsProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineivEXT (GLuint pipeline, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glValidateProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLogEXT (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
+typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
+typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
+typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
+typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint x, GLint y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+
+/* GL_EXT_shader_framebuffer_fetch */
+#ifndef GL_EXT_shader_framebuffer_fetch
+#define GL_EXT_shader_framebuffer_fetch 1
+#endif
+
+/* GL_EXT_shader_texture_lod */
+#ifndef GL_EXT_shader_texture_lod
+#define GL_EXT_shader_texture_lod 1
+#endif
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_EXT_shadow_samplers 1
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_EXT_sRGB 1
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_EXT_texture_compression_dxt1 1
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_EXT_texture_format_BGRA8888 1
+#endif
+
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_EXT_texture_rg 1
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_EXT_texture_storage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GL_APICALL void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_EXT_texture_type_2_10_10_10_REV 1
+#endif
+
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_EXT_unpack_subimage 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_DMP_shader_binary 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * FJ extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_FJ_shader_binary_GCCSO */
+#ifndef GL_FJ_shader_binary_GCCSO
+#define GL_FJ_shader_binary_GCCSO 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_IMG_program_binary 1
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_IMG_read_format 1
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_IMG_shader_binary 1
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_IMG_texture_compression_pvrtc 1
+#endif
+
+/* GL_IMG_texture_compression_pvrtc2 */
+#ifndef GL_IMG_texture_compression_pvrtc2
+#define GL_IMG_texture_compression_pvrtc2 1
+#endif
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_IMG_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMGPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMGPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_NV_coverage_sample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask);
+GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation);
+#endif
+typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask);
+typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation);
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_NV_depth_nonlinear 1
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_NV_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawBuffersNV (GLsizei n, const GLenum *bufs);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSNVPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+/* GL_NV_draw_instanced */
+#ifndef GL_NV_draw_instanced
+#define GL_NV_draw_instanced 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawArraysInstancedNV (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glDrawElementsInstancedNV (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDNVPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDNVPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_NV_fbo_color_attachments 1
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences);
+GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei n, GLuint *fences);
+GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint fence);
+GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint fence);
+GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint fence);
+GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint fence, GLenum condition);
+#endif
+typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+/* GL_NV_framebuffer_blit */
+#ifndef GL_NV_framebuffer_blit
+#define GL_NV_framebuffer_blit 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBlitFramebufferNV (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERNVPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+
+/* GL_NV_framebuffer_multisample */
+#ifndef GL_NV_framebuffer_multisample
+#define GL_NV_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleNV ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLENVPROC) ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+/* GL_NV_generate_mipmap_sRGB */
+#ifndef GL_NV_generate_mipmap_sRGB
+#define GL_NV_generate_mipmap_sRGB 1
+#endif
+
+/* GL_NV_instanced_arrays */
+#ifndef GL_NV_instanced_arrays
+#define GL_NV_instanced_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glVertexAttribDivisorNV (GLuint index, GLuint divisor);
+#endif
+typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORNVPROC) (GLuint index, GLuint divisor);
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_NV_read_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glReadBufferNV (GLenum mode);
+#endif
+typedef void (GL_APIENTRYP PFNGLREADBUFFERNVPROC) (GLenum mode);
+#endif
+
+/* GL_NV_read_buffer_front */
+#ifndef GL_NV_read_buffer_front
+#define GL_NV_read_buffer_front 1
+#endif
+
+/* GL_NV_read_depth */
+#ifndef GL_NV_read_depth
+#define GL_NV_read_depth 1
+#endif
+
+/* GL_NV_read_depth_stencil */
+#ifndef GL_NV_read_depth_stencil
+#define GL_NV_read_depth_stencil 1
+#endif
+
+/* GL_NV_read_stencil */
+#ifndef GL_NV_read_stencil
+#define GL_NV_read_stencil 1
+#endif
+
+/* GL_NV_shadow_samplers_array */
+#ifndef GL_NV_shadow_samplers_array
+#define GL_NV_shadow_samplers_array 1
+#endif
+
+/* GL_NV_shadow_samplers_cube */
+#ifndef GL_NV_shadow_samplers_cube
+#define GL_NV_shadow_samplers_cube 1
+#endif
+
+/* GL_NV_sRGB_formats */
+#ifndef GL_NV_sRGB_formats
+#define GL_NV_sRGB_formats 1
+#endif
+
+/* GL_NV_texture_border_clamp */
+#ifndef GL_NV_texture_border_clamp
+#define GL_NV_texture_border_clamp 1
+#endif
+
+/* GL_NV_texture_compression_s3tc_update */
+#ifndef GL_NV_texture_compression_s3tc_update
+#define GL_NV_texture_compression_s3tc_update 1
+#endif
+
+/* GL_NV_texture_npot_2D_mipmap */
+#ifndef GL_NV_texture_npot_2D_mipmap
+#define GL_NV_texture_npot_2D_mipmap 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_QCOM_alpha_test 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glAlphaFuncQCOM (GLenum func, GLclampf ref);
+#endif
+typedef void (GL_APIENTRYP PFNGLALPHAFUNCQCOMPROC) (GLenum func, GLclampf ref);
+#endif
+
+/* GL_QCOM_binning_control */
+#ifndef GL_QCOM_binning_control
+#define GL_QCOM_binning_control 1
+#endif
+
+/* GL_QCOM_driver_control */
+#ifndef GL_QCOM_driver_control
+#define GL_QCOM_driver_control 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
+GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
+GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+#endif
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_QCOM_extended_get 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures);
+GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params);
+#endif
+
+/* GL_QCOM_extended_get2 */
+#ifndef GL_QCOM_extended_get2
+#define GL_QCOM_extended_get2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+GL_APICALL GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program);
+GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_QCOM_perfmon_global_mode 1
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_QCOM_writeonly_rendering 1
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_QCOM_tiled_rendering 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask);
+#endif
+typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
+#endif
+
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_VIV_shader_binary 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2ext_h_ */
diff --git a/external/SDL2/include/SDL_opengles2_gl2platform.h b/external/SDL2/include/SDL_opengles2_gl2platform.h
new file mode 100644
index 0000000..c325686
--- /dev/null
+++ b/external/SDL2/include/SDL_opengles2_gl2platform.h
@@ -0,0 +1,30 @@
+#ifndef __gl2platform_h_
+#define __gl2platform_h_
+
+/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+/*#include <KHR/khrplatform.h>*/
+
+#ifndef GL_APICALL
+#define GL_APICALL KHRONOS_APICALL
+#endif
+
+#ifndef GL_APIENTRY
+#define GL_APIENTRY KHRONOS_APIENTRY
+#endif
+
+#endif /* __gl2platform_h_ */
diff --git a/external/SDL2/include/SDL_opengles2_khrplatform.h b/external/SDL2/include/SDL_opengles2_khrplatform.h
new file mode 100644
index 0000000..c9e6f17
--- /dev/null
+++ b/external/SDL2/include/SDL_opengles2_khrplatform.h
@@ -0,0 +1,282 @@
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Khronos platform-specific types and definitions.
+ *
+ * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $
+ *
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by sending them to the public Khronos Bugzilla
+ * (http://khronos.org/bugzilla) by filing a bug against product
+ * "Khronos (general)" component "Registry".
+ *
+ * A predefined template which fills in some of the bug fields can be
+ * reached using http://tinyurl.com/khrplatform-h-bugreport, but you
+ * must create a Bugzilla login first.
+ *
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system and for more details of its use:
+ * http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ * This file should be included as
+ * #include <KHR/khrplatform.h>
+ * by Khronos client API header files that use its types and defines.
+ *
+ * The types in khrplatform.h should only be used to define API-specific types.
+ *
+ * Types defined in khrplatform.h:
+ * khronos_int8_t signed 8 bit
+ * khronos_uint8_t unsigned 8 bit
+ * khronos_int16_t signed 16 bit
+ * khronos_uint16_t unsigned 16 bit
+ * khronos_int32_t signed 32 bit
+ * khronos_uint32_t unsigned 32 bit
+ * khronos_int64_t signed 64 bit
+ * khronos_uint64_t unsigned 64 bit
+ * khronos_intptr_t signed same number of bits as a pointer
+ * khronos_uintptr_t unsigned same number of bits as a pointer
+ * khronos_ssize_t signed size
+ * khronos_usize_t unsigned size
+ * khronos_float_t signed 32 bit floating point
+ * khronos_time_ns_t unsigned 64 bit time in nanoseconds
+ * khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ * nanoseconds
+ * khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ * khronos_boolean_enum_t enumerated boolean type. This should
+ * only be used as a base type when a client API's boolean type is
+ * an enum. Client APIs which use an integer or other type for
+ * booleans cannot use this as the base type for their boolean.
+ *
+ * Tokens defined in khrplatform.h:
+ *
+ * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
+ *
+ * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ *
+ * Calling convention macros defined in this file:
+ * KHRONOS_APICALL
+ * KHRONOS_APIENTRY
+ * KHRONOS_APIATTRIBUTES
+ *
+ * These may be used in function prototypes as:
+ *
+ * KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+ * int arg1,
+ * int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
+# define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+# define KHRONOS_APICALL IMPORT_C
+#else
+# define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIENTRY
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
+ /* Win32 but not WinCE */
+# define KHRONOS_APIENTRY __stdcall
+#else
+# define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32 khronos_int32_t;
+typedef unsigned __int32 khronos_uint32_t;
+typedef __int64 khronos_int64_t;
+typedef unsigned __int64 khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int khronos_int64_t;
+typedef unsigned long int khronos_uint64_t;
+#else
+typedef long long int khronos_int64_t;
+typedef unsigned long long int khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64 0
+#define KHRONOS_SUPPORT_FLOAT 0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed char khronos_int8_t;
+typedef unsigned char khronos_uint8_t;
+typedef signed short int khronos_int16_t;
+typedef unsigned short int khronos_uint16_t;
+
+/*
+ * Types that differ between LLP64 and LP64 architectures - in LLP64,
+ * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
+ * to be the only LLP64 architecture in current use.
+ */
+#ifdef _WIN64
+typedef signed long long int khronos_intptr_t;
+typedef unsigned long long int khronos_uintptr_t;
+typedef signed long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
+typedef signed long int khronos_intptr_t;
+typedef unsigned long int khronos_uintptr_t;
+typedef signed long int khronos_ssize_t;
+typedef unsigned long int khronos_usize_t;
+#endif
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef float khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or
+ * an absolute Unadjusted System Time. Unadjusted System Time is the number
+ * of nanoseconds since some arbitrary system event (e.g. since the last
+ * time the system booted). The Unadjusted System Time is an unsigned
+ * 64 bit value that wraps back to 0 every 584 years. Time intervals
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t khronos_utime_nanoseconds_t;
+typedef khronos_int64_t khronos_stime_nanoseconds_t;
+#endif
+
+/*
+ * Dummy value used to pad enum types to 32 bits.
+ */
+#ifndef KHRONOS_MAX_ENUM
+#define KHRONOS_MAX_ENUM 0x7FFFFFFF
+#endif
+
+/*
+ * Enumerated boolean type
+ *
+ * Values other than zero should be considered to be true. Therefore
+ * comparisons should not be made against KHRONOS_TRUE.
+ */
+typedef enum {
+ KHRONOS_FALSE = 0,
+ KHRONOS_TRUE = 1,
+ KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
+} khronos_boolean_enum_t;
+
+#endif /* __khrplatform_h_ */
diff --git a/external/SDL2/include/SDL_pixels.h b/external/SDL2/include/SDL_pixels.h
new file mode 100644
index 0000000..8499c32
--- /dev/null
+++ b/external/SDL2/include/SDL_pixels.h
@@ -0,0 +1,454 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_pixels.h
+ *
+ * Header for the enumerated pixel format definitions.
+ */
+
+#ifndef _SDL_pixels_h
+#define _SDL_pixels_h
+
+#include "SDL_stdinc.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \name Transparency definitions
+ *
+ * These define alpha as the opacity of a surface.
+ */
+/* @{ */
+#define SDL_ALPHA_OPAQUE 255
+#define SDL_ALPHA_TRANSPARENT 0
+/* @} */
+
+/** Pixel type. */
+enum
+{
+ SDL_PIXELTYPE_UNKNOWN,
+ SDL_PIXELTYPE_INDEX1,
+ SDL_PIXELTYPE_INDEX4,
+ SDL_PIXELTYPE_INDEX8,
+ SDL_PIXELTYPE_PACKED8,
+ SDL_PIXELTYPE_PACKED16,
+ SDL_PIXELTYPE_PACKED32,
+ SDL_PIXELTYPE_ARRAYU8,
+ SDL_PIXELTYPE_ARRAYU16,
+ SDL_PIXELTYPE_ARRAYU32,
+ SDL_PIXELTYPE_ARRAYF16,
+ SDL_PIXELTYPE_ARRAYF32
+};
+
+/** Bitmap pixel order, high bit -> low bit. */
+enum
+{
+ SDL_BITMAPORDER_NONE,
+ SDL_BITMAPORDER_4321,
+ SDL_BITMAPORDER_1234
+};
+
+/** Packed component order, high bit -> low bit. */
+enum
+{
+ SDL_PACKEDORDER_NONE,
+ SDL_PACKEDORDER_XRGB,
+ SDL_PACKEDORDER_RGBX,
+ SDL_PACKEDORDER_ARGB,
+ SDL_PACKEDORDER_RGBA,
+ SDL_PACKEDORDER_XBGR,
+ SDL_PACKEDORDER_BGRX,
+ SDL_PACKEDORDER_ABGR,
+ SDL_PACKEDORDER_BGRA
+};
+
+/** Array component order, low byte -> high byte. */
+/* !!! FIXME: in 2.1, make these not overlap differently with
+ !!! FIXME: SDL_PACKEDORDER_*, so we can simplify SDL_ISPIXELFORMAT_ALPHA */
+enum
+{
+ SDL_ARRAYORDER_NONE,
+ SDL_ARRAYORDER_RGB,
+ SDL_ARRAYORDER_RGBA,
+ SDL_ARRAYORDER_ARGB,
+ SDL_ARRAYORDER_BGR,
+ SDL_ARRAYORDER_BGRA,
+ SDL_ARRAYORDER_ABGR
+};
+
+/** Packed component layout. */
+enum
+{
+ SDL_PACKEDLAYOUT_NONE,
+ SDL_PACKEDLAYOUT_332,
+ SDL_PACKEDLAYOUT_4444,
+ SDL_PACKEDLAYOUT_1555,
+ SDL_PACKEDLAYOUT_5551,
+ SDL_PACKEDLAYOUT_565,
+ SDL_PACKEDLAYOUT_8888,
+ SDL_PACKEDLAYOUT_2101010,
+ SDL_PACKEDLAYOUT_1010102
+};
+
+#define SDL_DEFINE_PIXELFOURCC(A, B, C, D) SDL_FOURCC(A, B, C, D)
+
+#define SDL_DEFINE_PIXELFORMAT(type, order, layout, bits, bytes) \
+ ((1 << 28) | ((type) << 24) | ((order) << 20) | ((layout) << 16) | \
+ ((bits) << 8) | ((bytes) << 0))
+
+#define SDL_PIXELFLAG(X) (((X) >> 28) & 0x0F)
+#define SDL_PIXELTYPE(X) (((X) >> 24) & 0x0F)
+#define SDL_PIXELORDER(X) (((X) >> 20) & 0x0F)
+#define SDL_PIXELLAYOUT(X) (((X) >> 16) & 0x0F)
+#define SDL_BITSPERPIXEL(X) (((X) >> 8) & 0xFF)
+#define SDL_BYTESPERPIXEL(X) \
+ (SDL_ISPIXELFORMAT_FOURCC(X) ? \
+ ((((X) == SDL_PIXELFORMAT_YUY2) || \
+ ((X) == SDL_PIXELFORMAT_UYVY) || \
+ ((X) == SDL_PIXELFORMAT_YVYU)) ? 2 : 1) : (((X) >> 0) & 0xFF))
+
+#define SDL_ISPIXELFORMAT_INDEXED(format) \
+ (!SDL_ISPIXELFORMAT_FOURCC(format) && \
+ ((SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX1) || \
+ (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX4) || \
+ (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX8)))
+
+#define SDL_ISPIXELFORMAT_PACKED(format) \
+ (!SDL_ISPIXELFORMAT_FOURCC(format) && \
+ ((SDL_PIXELTYPE(format) == SDL_PIXELTYPE_PACKED8) || \
+ (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_PACKED16) || \
+ (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_PACKED32)))
+
+#define SDL_ISPIXELFORMAT_ARRAY(format) \
+ (!SDL_ISPIXELFORMAT_FOURCC(format) && \
+ ((SDL_PIXELTYPE(format) == SDL_PIXELTYPE_ARRAYU8) || \
+ (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_ARRAYU16) || \
+ (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_ARRAYU32) || \
+ (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_ARRAYF16) || \
+ (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_ARRAYF32)))
+
+#define SDL_ISPIXELFORMAT_ALPHA(format) \
+ ((SDL_ISPIXELFORMAT_PACKED(format) && \
+ ((SDL_PIXELORDER(format) == SDL_PACKEDORDER_ARGB) || \
+ (SDL_PIXELORDER(format) == SDL_PACKEDORDER_RGBA) || \
+ (SDL_PIXELORDER(format) == SDL_PACKEDORDER_ABGR) || \
+ (SDL_PIXELORDER(format) == SDL_PACKEDORDER_BGRA))) || \
+ (SDL_ISPIXELFORMAT_ARRAY(format) && \
+ ((SDL_PIXELORDER(format) == SDL_ARRAYORDER_ARGB) || \
+ (SDL_PIXELORDER(format) == SDL_ARRAYORDER_RGBA) || \
+ (SDL_PIXELORDER(format) == SDL_ARRAYORDER_ABGR) || \
+ (SDL_PIXELORDER(format) == SDL_ARRAYORDER_BGRA))))
+
+/* The flag is set to 1 because 0x1? is not in the printable ASCII range */
+#define SDL_ISPIXELFORMAT_FOURCC(format) \
+ ((format) && (SDL_PIXELFLAG(format) != 1))
+
+/* Note: If you modify this list, update SDL_GetPixelFormatName() */
+enum
+{
+ SDL_PIXELFORMAT_UNKNOWN,
+ SDL_PIXELFORMAT_INDEX1LSB =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX1, SDL_BITMAPORDER_4321, 0,
+ 1, 0),
+ SDL_PIXELFORMAT_INDEX1MSB =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX1, SDL_BITMAPORDER_1234, 0,
+ 1, 0),
+ SDL_PIXELFORMAT_INDEX4LSB =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX4, SDL_BITMAPORDER_4321, 0,
+ 4, 0),
+ SDL_PIXELFORMAT_INDEX4MSB =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX4, SDL_BITMAPORDER_1234, 0,
+ 4, 0),
+ SDL_PIXELFORMAT_INDEX8 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX8, 0, 0, 8, 1),
+ SDL_PIXELFORMAT_RGB332 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED8, SDL_PACKEDORDER_XRGB,
+ SDL_PACKEDLAYOUT_332, 8, 1),
+ SDL_PIXELFORMAT_RGB444 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XRGB,
+ SDL_PACKEDLAYOUT_4444, 12, 2),
+ SDL_PIXELFORMAT_RGB555 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XRGB,
+ SDL_PACKEDLAYOUT_1555, 15, 2),
+ SDL_PIXELFORMAT_BGR555 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XBGR,
+ SDL_PACKEDLAYOUT_1555, 15, 2),
+ SDL_PIXELFORMAT_ARGB4444 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ARGB,
+ SDL_PACKEDLAYOUT_4444, 16, 2),
+ SDL_PIXELFORMAT_RGBA4444 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_RGBA,
+ SDL_PACKEDLAYOUT_4444, 16, 2),
+ SDL_PIXELFORMAT_ABGR4444 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ABGR,
+ SDL_PACKEDLAYOUT_4444, 16, 2),
+ SDL_PIXELFORMAT_BGRA4444 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_BGRA,
+ SDL_PACKEDLAYOUT_4444, 16, 2),
+ SDL_PIXELFORMAT_ARGB1555 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ARGB,
+ SDL_PACKEDLAYOUT_1555, 16, 2),
+ SDL_PIXELFORMAT_RGBA5551 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_RGBA,
+ SDL_PACKEDLAYOUT_5551, 16, 2),
+ SDL_PIXELFORMAT_ABGR1555 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ABGR,
+ SDL_PACKEDLAYOUT_1555, 16, 2),
+ SDL_PIXELFORMAT_BGRA5551 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_BGRA,
+ SDL_PACKEDLAYOUT_5551, 16, 2),
+ SDL_PIXELFORMAT_RGB565 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XRGB,
+ SDL_PACKEDLAYOUT_565, 16, 2),
+ SDL_PIXELFORMAT_BGR565 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XBGR,
+ SDL_PACKEDLAYOUT_565, 16, 2),
+ SDL_PIXELFORMAT_RGB24 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_ARRAYU8, SDL_ARRAYORDER_RGB, 0,
+ 24, 3),
+ SDL_PIXELFORMAT_BGR24 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_ARRAYU8, SDL_ARRAYORDER_BGR, 0,
+ 24, 3),
+ SDL_PIXELFORMAT_RGB888 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_XRGB,
+ SDL_PACKEDLAYOUT_8888, 24, 4),
+ SDL_PIXELFORMAT_RGBX8888 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_RGBX,
+ SDL_PACKEDLAYOUT_8888, 24, 4),
+ SDL_PIXELFORMAT_BGR888 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_XBGR,
+ SDL_PACKEDLAYOUT_8888, 24, 4),
+ SDL_PIXELFORMAT_BGRX8888 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_BGRX,
+ SDL_PACKEDLAYOUT_8888, 24, 4),
+ SDL_PIXELFORMAT_ARGB8888 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ARGB,
+ SDL_PACKEDLAYOUT_8888, 32, 4),
+ SDL_PIXELFORMAT_RGBA8888 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_RGBA,
+ SDL_PACKEDLAYOUT_8888, 32, 4),
+ SDL_PIXELFORMAT_ABGR8888 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ABGR,
+ SDL_PACKEDLAYOUT_8888, 32, 4),
+ SDL_PIXELFORMAT_BGRA8888 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_BGRA,
+ SDL_PACKEDLAYOUT_8888, 32, 4),
+ SDL_PIXELFORMAT_ARGB2101010 =
+ SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ARGB,
+ SDL_PACKEDLAYOUT_2101010, 32, 4),
+
+ SDL_PIXELFORMAT_YV12 = /**< Planar mode: Y + V + U (3 planes) */
+ SDL_DEFINE_PIXELFOURCC('Y', 'V', '1', '2'),
+ SDL_PIXELFORMAT_IYUV = /**< Planar mode: Y + U + V (3 planes) */
+ SDL_DEFINE_PIXELFOURCC('I', 'Y', 'U', 'V'),
+ SDL_PIXELFORMAT_YUY2 = /**< Packed mode: Y0+U0+Y1+V0 (1 plane) */
+ SDL_DEFINE_PIXELFOURCC('Y', 'U', 'Y', '2'),
+ SDL_PIXELFORMAT_UYVY = /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */
+ SDL_DEFINE_PIXELFOURCC('U', 'Y', 'V', 'Y'),
+ SDL_PIXELFORMAT_YVYU = /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */
+ SDL_DEFINE_PIXELFOURCC('Y', 'V', 'Y', 'U'),
+ SDL_PIXELFORMAT_NV12 = /**< Planar mode: Y + U/V interleaved (2 planes) */
+ SDL_DEFINE_PIXELFOURCC('N', 'V', '1', '2'),
+ SDL_PIXELFORMAT_NV21 = /**< Planar mode: Y + V/U interleaved (2 planes) */
+ SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1')
+};
+
+typedef struct SDL_Color
+{
+ Uint8 r;
+ Uint8 g;
+ Uint8 b;
+ Uint8 a;
+} SDL_Color;
+#define SDL_Colour SDL_Color
+
+typedef struct SDL_Palette
+{
+ int ncolors;
+ SDL_Color *colors;
+ Uint32 version;
+ int refcount;
+} SDL_Palette;
+
+/**
+ * \note Everything in the pixel format structure is read-only.
+ */
+typedef struct SDL_PixelFormat
+{
+ Uint32 format;
+ SDL_Palette *palette;
+ Uint8 BitsPerPixel;
+ Uint8 BytesPerPixel;
+ Uint8 padding[2];
+ Uint32 Rmask;
+ Uint32 Gmask;
+ Uint32 Bmask;
+ Uint32 Amask;
+ Uint8 Rloss;
+ Uint8 Gloss;
+ Uint8 Bloss;
+ Uint8 Aloss;
+ Uint8 Rshift;
+ Uint8 Gshift;
+ Uint8 Bshift;
+ Uint8 Ashift;
+ int refcount;
+ struct SDL_PixelFormat *next;
+} SDL_PixelFormat;
+
+/**
+ * \brief Get the human readable name of a pixel format
+ */
+extern DECLSPEC const char* SDLCALL SDL_GetPixelFormatName(Uint32 format);
+
+/**
+ * \brief Convert one of the enumerated pixel formats to a bpp and RGBA masks.
+ *
+ * \return SDL_TRUE, or SDL_FALSE if the conversion wasn't possible.
+ *
+ * \sa SDL_MasksToPixelFormatEnum()
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_PixelFormatEnumToMasks(Uint32 format,
+ int *bpp,
+ Uint32 * Rmask,
+ Uint32 * Gmask,
+ Uint32 * Bmask,
+ Uint32 * Amask);
+
+/**
+ * \brief Convert a bpp and RGBA masks to an enumerated pixel format.
+ *
+ * \return The pixel format, or ::SDL_PIXELFORMAT_UNKNOWN if the conversion
+ * wasn't possible.
+ *
+ * \sa SDL_PixelFormatEnumToMasks()
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_MasksToPixelFormatEnum(int bpp,
+ Uint32 Rmask,
+ Uint32 Gmask,
+ Uint32 Bmask,
+ Uint32 Amask);
+
+/**
+ * \brief Create an SDL_PixelFormat structure from a pixel format enum.
+ */
+extern DECLSPEC SDL_PixelFormat * SDLCALL SDL_AllocFormat(Uint32 pixel_format);
+
+/**
+ * \brief Free an SDL_PixelFormat structure.
+ */
+extern DECLSPEC void SDLCALL SDL_FreeFormat(SDL_PixelFormat *format);
+
+/**
+ * \brief Create a palette structure with the specified number of color
+ * entries.
+ *
+ * \return A new palette, or NULL if there wasn't enough memory.
+ *
+ * \note The palette entries are initialized to white.
+ *
+ * \sa SDL_FreePalette()
+ */
+extern DECLSPEC SDL_Palette *SDLCALL SDL_AllocPalette(int ncolors);
+
+/**
+ * \brief Set the palette for a pixel format structure.
+ */
+extern DECLSPEC int SDLCALL SDL_SetPixelFormatPalette(SDL_PixelFormat * format,
+ SDL_Palette *palette);
+
+/**
+ * \brief Set a range of colors in a palette.
+ *
+ * \param palette The palette to modify.
+ * \param colors An array of colors to copy into the palette.
+ * \param firstcolor The index of the first palette entry to modify.
+ * \param ncolors The number of entries to modify.
+ *
+ * \return 0 on success, or -1 if not all of the colors could be set.
+ */
+extern DECLSPEC int SDLCALL SDL_SetPaletteColors(SDL_Palette * palette,
+ const SDL_Color * colors,
+ int firstcolor, int ncolors);
+
+/**
+ * \brief Free a palette created with SDL_AllocPalette().
+ *
+ * \sa SDL_AllocPalette()
+ */
+extern DECLSPEC void SDLCALL SDL_FreePalette(SDL_Palette * palette);
+
+/**
+ * \brief Maps an RGB triple to an opaque pixel value for a given pixel format.
+ *
+ * \sa SDL_MapRGBA
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_MapRGB(const SDL_PixelFormat * format,
+ Uint8 r, Uint8 g, Uint8 b);
+
+/**
+ * \brief Maps an RGBA quadruple to a pixel value for a given pixel format.
+ *
+ * \sa SDL_MapRGB
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_MapRGBA(const SDL_PixelFormat * format,
+ Uint8 r, Uint8 g, Uint8 b,
+ Uint8 a);
+
+/**
+ * \brief Get the RGB components from a pixel of the specified format.
+ *
+ * \sa SDL_GetRGBA
+ */
+extern DECLSPEC void SDLCALL SDL_GetRGB(Uint32 pixel,
+ const SDL_PixelFormat * format,
+ Uint8 * r, Uint8 * g, Uint8 * b);
+
+/**
+ * \brief Get the RGBA components from a pixel of the specified format.
+ *
+ * \sa SDL_GetRGB
+ */
+extern DECLSPEC void SDLCALL SDL_GetRGBA(Uint32 pixel,
+ const SDL_PixelFormat * format,
+ Uint8 * r, Uint8 * g, Uint8 * b,
+ Uint8 * a);
+
+/**
+ * \brief Calculate a 256 entry gamma ramp for a gamma value.
+ */
+extern DECLSPEC void SDLCALL SDL_CalculateGammaRamp(float gamma, Uint16 * ramp);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_pixels_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_platform.h b/external/SDL2/include/SDL_platform.h
new file mode 100644
index 0000000..c6c2139
--- /dev/null
+++ b/external/SDL2/include/SDL_platform.h
@@ -0,0 +1,181 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_platform.h
+ *
+ * Try to get a standard set of platform defines.
+ */
+
+#ifndef _SDL_platform_h
+#define _SDL_platform_h
+
+#if defined(_AIX)
+#undef __AIX__
+#define __AIX__ 1
+#endif
+#if defined(__HAIKU__)
+#undef __HAIKU__
+#define __HAIKU__ 1
+#endif
+#if defined(bsdi) || defined(__bsdi) || defined(__bsdi__)
+#undef __BSDI__
+#define __BSDI__ 1
+#endif
+#if defined(_arch_dreamcast)
+#undef __DREAMCAST__
+#define __DREAMCAST__ 1
+#endif
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#undef __FREEBSD__
+#define __FREEBSD__ 1
+#endif
+#if defined(hpux) || defined(__hpux) || defined(__hpux__)
+#undef __HPUX__
+#define __HPUX__ 1
+#endif
+#if defined(sgi) || defined(__sgi) || defined(__sgi__) || defined(_SGI_SOURCE)
+#undef __IRIX__
+#define __IRIX__ 1
+#endif
+#if (defined(linux) || defined(__linux) || defined(__linux__))
+#undef __LINUX__
+#define __LINUX__ 1
+#endif
+#if defined(ANDROID) || defined(__ANDROID__)
+#undef __ANDROID__
+#undef __LINUX__ /* do we need to do this? */
+#define __ANDROID__ 1
+#endif
+
+#if defined(__APPLE__)
+/* lets us know what version of Mac OS X we're compiling on */
+#include "AvailabilityMacros.h"
+#include "TargetConditionals.h"
+#if TARGET_OS_IPHONE
+/* if compiling for iPhone */
+#undef __IPHONEOS__
+#define __IPHONEOS__ 1
+#undef __MACOSX__
+#else
+/* if not compiling for iPhone */
+#undef __MACOSX__
+#define __MACOSX__ 1
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
+# error SDL for Mac OS X only supports deploying on 10.5 and above.
+#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1050 */
+#endif /* TARGET_OS_IPHONE */
+#endif /* defined(__APPLE__) */
+
+#if defined(__NetBSD__)
+#undef __NETBSD__
+#define __NETBSD__ 1
+#endif
+#if defined(__OpenBSD__)
+#undef __OPENBSD__
+#define __OPENBSD__ 1
+#endif
+#if defined(__OS2__)
+#undef __OS2__
+#define __OS2__ 1
+#endif
+#if defined(osf) || defined(__osf) || defined(__osf__) || defined(_OSF_SOURCE)
+#undef __OSF__
+#define __OSF__ 1
+#endif
+#if defined(__QNXNTO__)
+#undef __QNXNTO__
+#define __QNXNTO__ 1
+#endif
+#if defined(riscos) || defined(__riscos) || defined(__riscos__)
+#undef __RISCOS__
+#define __RISCOS__ 1
+#endif
+#if defined(__sun) && defined(__SVR4)
+#undef __SOLARIS__
+#define __SOLARIS__ 1
+#endif
+
+#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+/* Try to find out if we're compiling for WinRT or non-WinRT */
+/* If _USING_V110_SDK71_ is defined it means we are using the v110_xp or v120_xp toolset. */
+#if (defined(_MSC_VER) && (_MSC_VER >= 1700) && !_USING_V110_SDK71_) /* _MSC_VER==1700 for MSVC 2012 */
+#include <winapifamily.h>
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#undef __WINDOWS__
+#define __WINDOWS__ 1
+/* See if we're compiling for WinRT: */
+#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+#undef __WINRT__
+#define __WINRT__ 1
+#endif
+#else
+#undef __WINDOWS__
+#define __WINDOWS__ 1
+#endif /* _MSC_VER < 1700 */
+#endif /* defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) */
+
+#if defined(__WINDOWS__)
+#undef __WIN32__
+#define __WIN32__ 1
+#endif
+#if defined(__PSP__)
+#undef __PSP__
+#define __PSP__ 1
+#endif
+
+/* The NACL compiler defines __native_client__ and __pnacl__
+ * Ref: http://www.chromium.org/nativeclient/pnacl/stability-of-the-pnacl-bitcode-abi
+ */
+#if defined(__native_client__)
+#undef __LINUX__
+#undef __NACL__
+#define __NACL__ 1
+#endif
+#if defined(__pnacl__)
+#undef __LINUX__
+#undef __PNACL__
+#define __PNACL__ 1
+/* PNACL with newlib supports static linking only */
+#define __SDL_NOGETPROCADDR__
+#endif
+
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Gets the name of the platform.
+ */
+extern DECLSPEC const char * SDLCALL SDL_GetPlatform (void);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_platform_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_power.h b/external/SDL2/include/SDL_power.h
new file mode 100644
index 0000000..24c0501
--- /dev/null
+++ b/external/SDL2/include/SDL_power.h
@@ -0,0 +1,75 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_power_h
+#define _SDL_power_h
+
+/**
+ * \file SDL_power.h
+ *
+ * Header for the SDL power management routines.
+ */
+
+#include "SDL_stdinc.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief The basic state for the system's power supply.
+ */
+typedef enum
+{
+ SDL_POWERSTATE_UNKNOWN, /**< cannot determine power status */
+ SDL_POWERSTATE_ON_BATTERY, /**< Not plugged in, running on the battery */
+ SDL_POWERSTATE_NO_BATTERY, /**< Plugged in, no battery available */
+ SDL_POWERSTATE_CHARGING, /**< Plugged in, charging battery */
+ SDL_POWERSTATE_CHARGED /**< Plugged in, battery charged */
+} SDL_PowerState;
+
+
+/**
+ * \brief Get the current power supply details.
+ *
+ * \param secs Seconds of battery life left. You can pass a NULL here if
+ * you don't care. Will return -1 if we can't determine a
+ * value, or we're not running on a battery.
+ *
+ * \param pct Percentage of battery life left, between 0 and 100. You can
+ * pass a NULL here if you don't care. Will return -1 if we
+ * can't determine a value, or we're not running on a battery.
+ *
+ * \return The state of the battery (if any).
+ */
+extern DECLSPEC SDL_PowerState SDLCALL SDL_GetPowerInfo(int *secs, int *pct);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_power_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_quit.h b/external/SDL2/include/SDL_quit.h
new file mode 100644
index 0000000..cc06f28
--- /dev/null
+++ b/external/SDL2/include/SDL_quit.h
@@ -0,0 +1,58 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_quit.h
+ *
+ * Include file for SDL quit event handling.
+ */
+
+#ifndef _SDL_quit_h
+#define _SDL_quit_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+/**
+ * \file SDL_quit.h
+ *
+ * An ::SDL_QUIT event is generated when the user tries to close the application
+ * window. If it is ignored or filtered out, the window will remain open.
+ * If it is not ignored or filtered, it is queued normally and the window
+ * is allowed to close. When the window is closed, screen updates will
+ * complete, but have no effect.
+ *
+ * SDL_Init() installs signal handlers for SIGINT (keyboard interrupt)
+ * and SIGTERM (system termination request), if handlers do not already
+ * exist, that generate ::SDL_QUIT events as well. There is no way
+ * to determine the cause of an ::SDL_QUIT event, but setting a signal
+ * handler in your application will override the default generation of
+ * quit events for that signal.
+ *
+ * \sa SDL_Quit()
+ */
+
+/* There are no functions directly affecting the quit event */
+
+#define SDL_QuitRequested() \
+ (SDL_PumpEvents(), (SDL_PeepEvents(NULL,0,SDL_PEEKEVENT,SDL_QUIT,SDL_QUIT) > 0))
+
+#endif /* _SDL_quit_h */
diff --git a/external/SDL2/include/SDL_rect.h b/external/SDL2/include/SDL_rect.h
new file mode 100644
index 0000000..bbcb9a3
--- /dev/null
+++ b/external/SDL2/include/SDL_rect.h
@@ -0,0 +1,148 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_rect.h
+ *
+ * Header file for SDL_rect definition and management functions.
+ */
+
+#ifndef _SDL_rect_h
+#define _SDL_rect_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_pixels.h"
+#include "SDL_rwops.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief The structure that defines a point
+ *
+ * \sa SDL_EnclosePoints
+ * \sa SDL_PointInRect
+ */
+typedef struct SDL_Point
+{
+ int x;
+ int y;
+} SDL_Point;
+
+/**
+ * \brief A rectangle, with the origin at the upper left.
+ *
+ * \sa SDL_RectEmpty
+ * \sa SDL_RectEquals
+ * \sa SDL_HasIntersection
+ * \sa SDL_IntersectRect
+ * \sa SDL_UnionRect
+ * \sa SDL_EnclosePoints
+ */
+typedef struct SDL_Rect
+{
+ int x, y;
+ int w, h;
+} SDL_Rect;
+
+/**
+ * \brief Returns true if point resides inside a rectangle.
+ */
+SDL_FORCE_INLINE SDL_bool SDL_PointInRect(const SDL_Point *p, const SDL_Rect *r)
+{
+ return ( (p->x >= r->x) && (p->x < (r->x + r->w)) &&
+ (p->y >= r->y) && (p->y < (r->y + r->h)) ) ? SDL_TRUE : SDL_FALSE;
+}
+
+/**
+ * \brief Returns true if the rectangle has no area.
+ */
+SDL_FORCE_INLINE SDL_bool SDL_RectEmpty(const SDL_Rect *r)
+{
+ return ((!r) || (r->w <= 0) || (r->h <= 0)) ? SDL_TRUE : SDL_FALSE;
+}
+
+/**
+ * \brief Returns true if the two rectangles are equal.
+ */
+SDL_FORCE_INLINE SDL_bool SDL_RectEquals(const SDL_Rect *a, const SDL_Rect *b)
+{
+ return (a && b && (a->x == b->x) && (a->y == b->y) &&
+ (a->w == b->w) && (a->h == b->h)) ? SDL_TRUE : SDL_FALSE;
+}
+
+/**
+ * \brief Determine whether two rectangles intersect.
+ *
+ * \return SDL_TRUE if there is an intersection, SDL_FALSE otherwise.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasIntersection(const SDL_Rect * A,
+ const SDL_Rect * B);
+
+/**
+ * \brief Calculate the intersection of two rectangles.
+ *
+ * \return SDL_TRUE if there is an intersection, SDL_FALSE otherwise.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IntersectRect(const SDL_Rect * A,
+ const SDL_Rect * B,
+ SDL_Rect * result);
+
+/**
+ * \brief Calculate the union of two rectangles.
+ */
+extern DECLSPEC void SDLCALL SDL_UnionRect(const SDL_Rect * A,
+ const SDL_Rect * B,
+ SDL_Rect * result);
+
+/**
+ * \brief Calculate a minimal rectangle enclosing a set of points
+ *
+ * \return SDL_TRUE if any points were within the clipping rect
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_EnclosePoints(const SDL_Point * points,
+ int count,
+ const SDL_Rect * clip,
+ SDL_Rect * result);
+
+/**
+ * \brief Calculate the intersection of a rectangle and line segment.
+ *
+ * \return SDL_TRUE if there is an intersection, SDL_FALSE otherwise.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IntersectRectAndLine(const SDL_Rect *
+ rect, int *X1,
+ int *Y1, int *X2,
+ int *Y2);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_rect_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_render.h b/external/SDL2/include/SDL_render.h
new file mode 100644
index 0000000..e4ed2af
--- /dev/null
+++ b/external/SDL2/include/SDL_render.h
@@ -0,0 +1,880 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_render.h
+ *
+ * Header file for SDL 2D rendering functions.
+ *
+ * This API supports the following features:
+ * * single pixel points
+ * * single pixel lines
+ * * filled rectangles
+ * * texture images
+ *
+ * The primitives may be drawn in opaque, blended, or additive modes.
+ *
+ * The texture images may be drawn in opaque, blended, or additive modes.
+ * They can have an additional color tint or alpha modulation applied to
+ * them, and may also be stretched with linear interpolation.
+ *
+ * This API is designed to accelerate simple 2D operations. You may
+ * want more functionality such as polygons and particle effects and
+ * in that case you should use SDL's OpenGL/Direct3D support or one
+ * of the many good 3D engines.
+ *
+ * These functions must be called from the main thread.
+ * See this bug for details: http://bugzilla.libsdl.org/show_bug.cgi?id=1995
+ */
+
+#ifndef _SDL_render_h
+#define _SDL_render_h
+
+#include "SDL_stdinc.h"
+#include "SDL_rect.h"
+#include "SDL_video.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Flags used when creating a rendering context
+ */
+typedef enum
+{
+ SDL_RENDERER_SOFTWARE = 0x00000001, /**< The renderer is a software fallback */
+ SDL_RENDERER_ACCELERATED = 0x00000002, /**< The renderer uses hardware
+ acceleration */
+ SDL_RENDERER_PRESENTVSYNC = 0x00000004, /**< Present is synchronized
+ with the refresh rate */
+ SDL_RENDERER_TARGETTEXTURE = 0x00000008 /**< The renderer supports
+ rendering to texture */
+} SDL_RendererFlags;
+
+/**
+ * \brief Information on the capabilities of a render driver or context.
+ */
+typedef struct SDL_RendererInfo
+{
+ const char *name; /**< The name of the renderer */
+ Uint32 flags; /**< Supported ::SDL_RendererFlags */
+ Uint32 num_texture_formats; /**< The number of available texture formats */
+ Uint32 texture_formats[16]; /**< The available texture formats */
+ int max_texture_width; /**< The maximum texture width */
+ int max_texture_height; /**< The maximum texture height */
+} SDL_RendererInfo;
+
+/**
+ * \brief The access pattern allowed for a texture.
+ */
+typedef enum
+{
+ SDL_TEXTUREACCESS_STATIC, /**< Changes rarely, not lockable */
+ SDL_TEXTUREACCESS_STREAMING, /**< Changes frequently, lockable */
+ SDL_TEXTUREACCESS_TARGET /**< Texture can be used as a render target */
+} SDL_TextureAccess;
+
+/**
+ * \brief The texture channel modulation used in SDL_RenderCopy().
+ */
+typedef enum
+{
+ SDL_TEXTUREMODULATE_NONE = 0x00000000, /**< No modulation */
+ SDL_TEXTUREMODULATE_COLOR = 0x00000001, /**< srcC = srcC * color */
+ SDL_TEXTUREMODULATE_ALPHA = 0x00000002 /**< srcA = srcA * alpha */
+} SDL_TextureModulate;
+
+/**
+ * \brief Flip constants for SDL_RenderCopyEx
+ */
+typedef enum
+{
+ SDL_FLIP_NONE = 0x00000000, /**< Do not flip */
+ SDL_FLIP_HORIZONTAL = 0x00000001, /**< flip horizontally */
+ SDL_FLIP_VERTICAL = 0x00000002 /**< flip vertically */
+} SDL_RendererFlip;
+
+/**
+ * \brief A structure representing rendering state
+ */
+struct SDL_Renderer;
+typedef struct SDL_Renderer SDL_Renderer;
+
+/**
+ * \brief An efficient driver-specific representation of pixel data
+ */
+struct SDL_Texture;
+typedef struct SDL_Texture SDL_Texture;
+
+
+/* Function prototypes */
+
+/**
+ * \brief Get the number of 2D rendering drivers available for the current
+ * display.
+ *
+ * A render driver is a set of code that handles rendering and texture
+ * management on a particular display. Normally there is only one, but
+ * some drivers may have several available with different capabilities.
+ *
+ * \sa SDL_GetRenderDriverInfo()
+ * \sa SDL_CreateRenderer()
+ */
+extern DECLSPEC int SDLCALL SDL_GetNumRenderDrivers(void);
+
+/**
+ * \brief Get information about a specific 2D rendering driver for the current
+ * display.
+ *
+ * \param index The index of the driver to query information about.
+ * \param info A pointer to an SDL_RendererInfo struct to be filled with
+ * information on the rendering driver.
+ *
+ * \return 0 on success, -1 if the index was out of range.
+ *
+ * \sa SDL_CreateRenderer()
+ */
+extern DECLSPEC int SDLCALL SDL_GetRenderDriverInfo(int index,
+ SDL_RendererInfo * info);
+
+/**
+ * \brief Create a window and default renderer
+ *
+ * \param width The width of the window
+ * \param height The height of the window
+ * \param window_flags The flags used to create the window
+ * \param window A pointer filled with the window, or NULL on error
+ * \param renderer A pointer filled with the renderer, or NULL on error
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_CreateWindowAndRenderer(
+ int width, int height, Uint32 window_flags,
+ SDL_Window **window, SDL_Renderer **renderer);
+
+
+/**
+ * \brief Create a 2D rendering context for a window.
+ *
+ * \param window The window where rendering is displayed.
+ * \param index The index of the rendering driver to initialize, or -1 to
+ * initialize the first one supporting the requested flags.
+ * \param flags ::SDL_RendererFlags.
+ *
+ * \return A valid rendering context or NULL if there was an error.
+ *
+ * \sa SDL_CreateSoftwareRenderer()
+ * \sa SDL_GetRendererInfo()
+ * \sa SDL_DestroyRenderer()
+ */
+extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window * window,
+ int index, Uint32 flags);
+
+/**
+ * \brief Create a 2D software rendering context for a surface.
+ *
+ * \param surface The surface where rendering is done.
+ *
+ * \return A valid rendering context or NULL if there was an error.
+ *
+ * \sa SDL_CreateRenderer()
+ * \sa SDL_DestroyRenderer()
+ */
+extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateSoftwareRenderer(SDL_Surface * surface);
+
+/**
+ * \brief Get the renderer associated with a window.
+ */
+extern DECLSPEC SDL_Renderer * SDLCALL SDL_GetRenderer(SDL_Window * window);
+
+/**
+ * \brief Get information about a rendering context.
+ */
+extern DECLSPEC int SDLCALL SDL_GetRendererInfo(SDL_Renderer * renderer,
+ SDL_RendererInfo * info);
+
+/**
+ * \brief Get the output size in pixels of a rendering context.
+ */
+extern DECLSPEC int SDLCALL SDL_GetRendererOutputSize(SDL_Renderer * renderer,
+ int *w, int *h);
+
+/**
+ * \brief Create a texture for a rendering context.
+ *
+ * \param renderer The renderer.
+ * \param format The format of the texture.
+ * \param access One of the enumerated values in ::SDL_TextureAccess.
+ * \param w The width of the texture in pixels.
+ * \param h The height of the texture in pixels.
+ *
+ * \return The created texture is returned, or NULL if no rendering context was
+ * active, the format was unsupported, or the width or height were out
+ * of range.
+ *
+ * \sa SDL_QueryTexture()
+ * \sa SDL_UpdateTexture()
+ * \sa SDL_DestroyTexture()
+ */
+extern DECLSPEC SDL_Texture * SDLCALL SDL_CreateTexture(SDL_Renderer * renderer,
+ Uint32 format,
+ int access, int w,
+ int h);
+
+/**
+ * \brief Create a texture from an existing surface.
+ *
+ * \param renderer The renderer.
+ * \param surface The surface containing pixel data used to fill the texture.
+ *
+ * \return The created texture is returned, or NULL on error.
+ *
+ * \note The surface is not modified or freed by this function.
+ *
+ * \sa SDL_QueryTexture()
+ * \sa SDL_DestroyTexture()
+ */
+extern DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface);
+
+/**
+ * \brief Query the attributes of a texture
+ *
+ * \param texture A texture to be queried.
+ * \param format A pointer filled in with the raw format of the texture. The
+ * actual format may differ, but pixel transfers will use this
+ * format.
+ * \param access A pointer filled in with the actual access to the texture.
+ * \param w A pointer filled in with the width of the texture in pixels.
+ * \param h A pointer filled in with the height of the texture in pixels.
+ *
+ * \return 0 on success, or -1 if the texture is not valid.
+ */
+extern DECLSPEC int SDLCALL SDL_QueryTexture(SDL_Texture * texture,
+ Uint32 * format, int *access,
+ int *w, int *h);
+
+/**
+ * \brief Set an additional color value used in render copy operations.
+ *
+ * \param texture The texture to update.
+ * \param r The red color value multiplied into copy operations.
+ * \param g The green color value multiplied into copy operations.
+ * \param b The blue color value multiplied into copy operations.
+ *
+ * \return 0 on success, or -1 if the texture is not valid or color modulation
+ * is not supported.
+ *
+ * \sa SDL_GetTextureColorMod()
+ */
+extern DECLSPEC int SDLCALL SDL_SetTextureColorMod(SDL_Texture * texture,
+ Uint8 r, Uint8 g, Uint8 b);
+
+
+/**
+ * \brief Get the additional color value used in render copy operations.
+ *
+ * \param texture The texture to query.
+ * \param r A pointer filled in with the current red color value.
+ * \param g A pointer filled in with the current green color value.
+ * \param b A pointer filled in with the current blue color value.
+ *
+ * \return 0 on success, or -1 if the texture is not valid.
+ *
+ * \sa SDL_SetTextureColorMod()
+ */
+extern DECLSPEC int SDLCALL SDL_GetTextureColorMod(SDL_Texture * texture,
+ Uint8 * r, Uint8 * g,
+ Uint8 * b);
+
+/**
+ * \brief Set an additional alpha value used in render copy operations.
+ *
+ * \param texture The texture to update.
+ * \param alpha The alpha value multiplied into copy operations.
+ *
+ * \return 0 on success, or -1 if the texture is not valid or alpha modulation
+ * is not supported.
+ *
+ * \sa SDL_GetTextureAlphaMod()
+ */
+extern DECLSPEC int SDLCALL SDL_SetTextureAlphaMod(SDL_Texture * texture,
+ Uint8 alpha);
+
+/**
+ * \brief Get the additional alpha value used in render copy operations.
+ *
+ * \param texture The texture to query.
+ * \param alpha A pointer filled in with the current alpha value.
+ *
+ * \return 0 on success, or -1 if the texture is not valid.
+ *
+ * \sa SDL_SetTextureAlphaMod()
+ */
+extern DECLSPEC int SDLCALL SDL_GetTextureAlphaMod(SDL_Texture * texture,
+ Uint8 * alpha);
+
+/**
+ * \brief Set the blend mode used for texture copy operations.
+ *
+ * \param texture The texture to update.
+ * \param blendMode ::SDL_BlendMode to use for texture blending.
+ *
+ * \return 0 on success, or -1 if the texture is not valid or the blend mode is
+ * not supported.
+ *
+ * \note If the blend mode is not supported, the closest supported mode is
+ * chosen.
+ *
+ * \sa SDL_GetTextureBlendMode()
+ */
+extern DECLSPEC int SDLCALL SDL_SetTextureBlendMode(SDL_Texture * texture,
+ SDL_BlendMode blendMode);
+
+/**
+ * \brief Get the blend mode used for texture copy operations.
+ *
+ * \param texture The texture to query.
+ * \param blendMode A pointer filled in with the current blend mode.
+ *
+ * \return 0 on success, or -1 if the texture is not valid.
+ *
+ * \sa SDL_SetTextureBlendMode()
+ */
+extern DECLSPEC int SDLCALL SDL_GetTextureBlendMode(SDL_Texture * texture,
+ SDL_BlendMode *blendMode);
+
+/**
+ * \brief Update the given texture rectangle with new pixel data.
+ *
+ * \param texture The texture to update
+ * \param rect A pointer to the rectangle of pixels to update, or NULL to
+ * update the entire texture.
+ * \param pixels The raw pixel data.
+ * \param pitch The number of bytes in a row of pixel data, including padding between lines.
+ *
+ * \return 0 on success, or -1 if the texture is not valid.
+ *
+ * \note This is a fairly slow function.
+ */
+extern DECLSPEC int SDLCALL SDL_UpdateTexture(SDL_Texture * texture,
+ const SDL_Rect * rect,
+ const void *pixels, int pitch);
+
+/**
+ * \brief Update a rectangle within a planar YV12 or IYUV texture with new pixel data.
+ *
+ * \param texture The texture to update
+ * \param rect A pointer to the rectangle of pixels to update, or NULL to
+ * update the entire texture.
+ * \param Yplane The raw pixel data for the Y plane.
+ * \param Ypitch The number of bytes between rows of pixel data for the Y plane.
+ * \param Uplane The raw pixel data for the U plane.
+ * \param Upitch The number of bytes between rows of pixel data for the U plane.
+ * \param Vplane The raw pixel data for the V plane.
+ * \param Vpitch The number of bytes between rows of pixel data for the V plane.
+ *
+ * \return 0 on success, or -1 if the texture is not valid.
+ *
+ * \note You can use SDL_UpdateTexture() as long as your pixel data is
+ * a contiguous block of Y and U/V planes in the proper order, but
+ * this function is available if your pixel data is not contiguous.
+ */
+extern DECLSPEC int SDLCALL SDL_UpdateYUVTexture(SDL_Texture * texture,
+ const SDL_Rect * rect,
+ const Uint8 *Yplane, int Ypitch,
+ const Uint8 *Uplane, int Upitch,
+ const Uint8 *Vplane, int Vpitch);
+
+/**
+ * \brief Lock a portion of the texture for write-only pixel access.
+ *
+ * \param texture The texture to lock for access, which was created with
+ * ::SDL_TEXTUREACCESS_STREAMING.
+ * \param rect A pointer to the rectangle to lock for access. If the rect
+ * is NULL, the entire texture will be locked.
+ * \param pixels This is filled in with a pointer to the locked pixels,
+ * appropriately offset by the locked area.
+ * \param pitch This is filled in with the pitch of the locked pixels.
+ *
+ * \return 0 on success, or -1 if the texture is not valid or was not created with ::SDL_TEXTUREACCESS_STREAMING.
+ *
+ * \sa SDL_UnlockTexture()
+ */
+extern DECLSPEC int SDLCALL SDL_LockTexture(SDL_Texture * texture,
+ const SDL_Rect * rect,
+ void **pixels, int *pitch);
+
+/**
+ * \brief Unlock a texture, uploading the changes to video memory, if needed.
+ *
+ * \sa SDL_LockTexture()
+ */
+extern DECLSPEC void SDLCALL SDL_UnlockTexture(SDL_Texture * texture);
+
+/**
+ * \brief Determines whether a window supports the use of render targets
+ *
+ * \param renderer The renderer that will be checked
+ *
+ * \return SDL_TRUE if supported, SDL_FALSE if not.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_RenderTargetSupported(SDL_Renderer *renderer);
+
+/**
+ * \brief Set a texture as the current rendering target.
+ *
+ * \param renderer The renderer.
+ * \param texture The targeted texture, which must be created with the SDL_TEXTUREACCESS_TARGET flag, or NULL for the default render target
+ *
+ * \return 0 on success, or -1 on error
+ *
+ * \sa SDL_GetRenderTarget()
+ */
+extern DECLSPEC int SDLCALL SDL_SetRenderTarget(SDL_Renderer *renderer,
+ SDL_Texture *texture);
+
+/**
+ * \brief Get the current render target or NULL for the default render target.
+ *
+ * \return The current render target
+ *
+ * \sa SDL_SetRenderTarget()
+ */
+extern DECLSPEC SDL_Texture * SDLCALL SDL_GetRenderTarget(SDL_Renderer *renderer);
+
+/**
+ * \brief Set device independent resolution for rendering
+ *
+ * \param renderer The renderer for which resolution should be set.
+ * \param w The width of the logical resolution
+ * \param h The height of the logical resolution
+ *
+ * This function uses the viewport and scaling functionality to allow a fixed logical
+ * resolution for rendering, regardless of the actual output resolution. If the actual
+ * output resolution doesn't have the same aspect ratio the output rendering will be
+ * centered within the output display.
+ *
+ * If the output display is a window, mouse events in the window will be filtered
+ * and scaled so they seem to arrive within the logical resolution.
+ *
+ * \note If this function results in scaling or subpixel drawing by the
+ * rendering backend, it will be handled using the appropriate
+ * quality hints.
+ *
+ * \sa SDL_RenderGetLogicalSize()
+ * \sa SDL_RenderSetScale()
+ * \sa SDL_RenderSetViewport()
+ */
+extern DECLSPEC int SDLCALL SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h);
+
+/**
+ * \brief Get device independent resolution for rendering
+ *
+ * \param renderer The renderer from which resolution should be queried.
+ * \param w A pointer filled with the width of the logical resolution
+ * \param h A pointer filled with the height of the logical resolution
+ *
+ * \sa SDL_RenderSetLogicalSize()
+ */
+extern DECLSPEC void SDLCALL SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h);
+
+/**
+ * \brief Set the drawing area for rendering on the current target.
+ *
+ * \param renderer The renderer for which the drawing area should be set.
+ * \param rect The rectangle representing the drawing area, or NULL to set the viewport to the entire target.
+ *
+ * The x,y of the viewport rect represents the origin for rendering.
+ *
+ * \return 0 on success, or -1 on error
+ *
+ * \note If the window associated with the renderer is resized, the viewport is automatically reset.
+ *
+ * \sa SDL_RenderGetViewport()
+ * \sa SDL_RenderSetLogicalSize()
+ */
+extern DECLSPEC int SDLCALL SDL_RenderSetViewport(SDL_Renderer * renderer,
+ const SDL_Rect * rect);
+
+/**
+ * \brief Get the drawing area for the current target.
+ *
+ * \sa SDL_RenderSetViewport()
+ */
+extern DECLSPEC void SDLCALL SDL_RenderGetViewport(SDL_Renderer * renderer,
+ SDL_Rect * rect);
+
+/**
+ * \brief Set the clip rectangle for the current target.
+ *
+ * \param renderer The renderer for which clip rectangle should be set.
+ * \param rect A pointer to the rectangle to set as the clip rectangle, or
+ * NULL to disable clipping.
+ *
+ * \return 0 on success, or -1 on error
+ *
+ * \sa SDL_RenderGetClipRect()
+ */
+extern DECLSPEC int SDLCALL SDL_RenderSetClipRect(SDL_Renderer * renderer,
+ const SDL_Rect * rect);
+
+/**
+ * \brief Get the clip rectangle for the current target.
+ *
+ * \param renderer The renderer from which clip rectangle should be queried.
+ * \param rect A pointer filled in with the current clip rectangle, or
+ * an empty rectangle if clipping is disabled.
+ *
+ * \sa SDL_RenderSetClipRect()
+ */
+extern DECLSPEC void SDLCALL SDL_RenderGetClipRect(SDL_Renderer * renderer,
+ SDL_Rect * rect);
+
+/**
+ * \brief Get whether clipping is enabled on the given renderer.
+ *
+ * \param renderer The renderer from which clip state should be queried.
+ *
+ * \sa SDL_RenderGetClipRect()
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_RenderIsClipEnabled(SDL_Renderer * renderer);
+
+
+/**
+ * \brief Set the drawing scale for rendering on the current target.
+ *
+ * \param renderer The renderer for which the drawing scale should be set.
+ * \param scaleX The horizontal scaling factor
+ * \param scaleY The vertical scaling factor
+ *
+ * The drawing coordinates are scaled by the x/y scaling factors
+ * before they are used by the renderer. This allows resolution
+ * independent drawing with a single coordinate system.
+ *
+ * \note If this results in scaling or subpixel drawing by the
+ * rendering backend, it will be handled using the appropriate
+ * quality hints. For best results use integer scaling factors.
+ *
+ * \sa SDL_RenderGetScale()
+ * \sa SDL_RenderSetLogicalSize()
+ */
+extern DECLSPEC int SDLCALL SDL_RenderSetScale(SDL_Renderer * renderer,
+ float scaleX, float scaleY);
+
+/**
+ * \brief Get the drawing scale for the current target.
+ *
+ * \param renderer The renderer from which drawing scale should be queried.
+ * \param scaleX A pointer filled in with the horizontal scaling factor
+ * \param scaleY A pointer filled in with the vertical scaling factor
+ *
+ * \sa SDL_RenderSetScale()
+ */
+extern DECLSPEC void SDLCALL SDL_RenderGetScale(SDL_Renderer * renderer,
+ float *scaleX, float *scaleY);
+
+/**
+ * \brief Set the color used for drawing operations (Rect, Line and Clear).
+ *
+ * \param renderer The renderer for which drawing color should be set.
+ * \param r The red value used to draw on the rendering target.
+ * \param g The green value used to draw on the rendering target.
+ * \param b The blue value used to draw on the rendering target.
+ * \param a The alpha value used to draw on the rendering target, usually
+ * ::SDL_ALPHA_OPAQUE (255).
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_SetRenderDrawColor(SDL_Renderer * renderer,
+ Uint8 r, Uint8 g, Uint8 b,
+ Uint8 a);
+
+/**
+ * \brief Get the color used for drawing operations (Rect, Line and Clear).
+ *
+ * \param renderer The renderer from which drawing color should be queried.
+ * \param r A pointer to the red value used to draw on the rendering target.
+ * \param g A pointer to the green value used to draw on the rendering target.
+ * \param b A pointer to the blue value used to draw on the rendering target.
+ * \param a A pointer to the alpha value used to draw on the rendering target,
+ * usually ::SDL_ALPHA_OPAQUE (255).
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_GetRenderDrawColor(SDL_Renderer * renderer,
+ Uint8 * r, Uint8 * g, Uint8 * b,
+ Uint8 * a);
+
+/**
+ * \brief Set the blend mode used for drawing operations (Fill and Line).
+ *
+ * \param renderer The renderer for which blend mode should be set.
+ * \param blendMode ::SDL_BlendMode to use for blending.
+ *
+ * \return 0 on success, or -1 on error
+ *
+ * \note If the blend mode is not supported, the closest supported mode is
+ * chosen.
+ *
+ * \sa SDL_GetRenderDrawBlendMode()
+ */
+extern DECLSPEC int SDLCALL SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer,
+ SDL_BlendMode blendMode);
+
+/**
+ * \brief Get the blend mode used for drawing operations.
+ *
+ * \param renderer The renderer from which blend mode should be queried.
+ * \param blendMode A pointer filled in with the current blend mode.
+ *
+ * \return 0 on success, or -1 on error
+ *
+ * \sa SDL_SetRenderDrawBlendMode()
+ */
+extern DECLSPEC int SDLCALL SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer,
+ SDL_BlendMode *blendMode);
+
+/**
+ * \brief Clear the current rendering target with the drawing color
+ *
+ * This function clears the entire rendering target, ignoring the viewport.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderClear(SDL_Renderer * renderer);
+
+/**
+ * \brief Draw a point on the current rendering target.
+ *
+ * \param renderer The renderer which should draw a point.
+ * \param x The x coordinate of the point.
+ * \param y The y coordinate of the point.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawPoint(SDL_Renderer * renderer,
+ int x, int y);
+
+/**
+ * \brief Draw multiple points on the current rendering target.
+ *
+ * \param renderer The renderer which should draw multiple points.
+ * \param points The points to draw
+ * \param count The number of points to draw
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawPoints(SDL_Renderer * renderer,
+ const SDL_Point * points,
+ int count);
+
+/**
+ * \brief Draw a line on the current rendering target.
+ *
+ * \param renderer The renderer which should draw a line.
+ * \param x1 The x coordinate of the start point.
+ * \param y1 The y coordinate of the start point.
+ * \param x2 The x coordinate of the end point.
+ * \param y2 The y coordinate of the end point.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawLine(SDL_Renderer * renderer,
+ int x1, int y1, int x2, int y2);
+
+/**
+ * \brief Draw a series of connected lines on the current rendering target.
+ *
+ * \param renderer The renderer which should draw multiple lines.
+ * \param points The points along the lines
+ * \param count The number of points, drawing count-1 lines
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawLines(SDL_Renderer * renderer,
+ const SDL_Point * points,
+ int count);
+
+/**
+ * \brief Draw a rectangle on the current rendering target.
+ *
+ * \param renderer The renderer which should draw a rectangle.
+ * \param rect A pointer to the destination rectangle, or NULL to outline the entire rendering target.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawRect(SDL_Renderer * renderer,
+ const SDL_Rect * rect);
+
+/**
+ * \brief Draw some number of rectangles on the current rendering target.
+ *
+ * \param renderer The renderer which should draw multiple rectangles.
+ * \param rects A pointer to an array of destination rectangles.
+ * \param count The number of rectangles.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawRects(SDL_Renderer * renderer,
+ const SDL_Rect * rects,
+ int count);
+
+/**
+ * \brief Fill a rectangle on the current rendering target with the drawing color.
+ *
+ * \param renderer The renderer which should fill a rectangle.
+ * \param rect A pointer to the destination rectangle, or NULL for the entire
+ * rendering target.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderFillRect(SDL_Renderer * renderer,
+ const SDL_Rect * rect);
+
+/**
+ * \brief Fill some number of rectangles on the current rendering target with the drawing color.
+ *
+ * \param renderer The renderer which should fill multiple rectangles.
+ * \param rects A pointer to an array of destination rectangles.
+ * \param count The number of rectangles.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderFillRects(SDL_Renderer * renderer,
+ const SDL_Rect * rects,
+ int count);
+
+/**
+ * \brief Copy a portion of the texture to the current rendering target.
+ *
+ * \param renderer The renderer which should copy parts of a texture.
+ * \param texture The source texture.
+ * \param srcrect A pointer to the source rectangle, or NULL for the entire
+ * texture.
+ * \param dstrect A pointer to the destination rectangle, or NULL for the
+ * entire rendering target.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderCopy(SDL_Renderer * renderer,
+ SDL_Texture * texture,
+ const SDL_Rect * srcrect,
+ const SDL_Rect * dstrect);
+
+/**
+ * \brief Copy a portion of the source texture to the current rendering target, rotating it by angle around the given center
+ *
+ * \param renderer The renderer which should copy parts of a texture.
+ * \param texture The source texture.
+ * \param srcrect A pointer to the source rectangle, or NULL for the entire
+ * texture.
+ * \param dstrect A pointer to the destination rectangle, or NULL for the
+ * entire rendering target.
+ * \param angle An angle in degrees that indicates the rotation that will be applied to dstrect
+ * \param center A pointer to a point indicating the point around which dstrect will be rotated (if NULL, rotation will be done around dstrect.w/2, dstrect.h/2).
+ * \param flip An SDL_RendererFlip value stating which flipping actions should be performed on the texture
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderCopyEx(SDL_Renderer * renderer,
+ SDL_Texture * texture,
+ const SDL_Rect * srcrect,
+ const SDL_Rect * dstrect,
+ const double angle,
+ const SDL_Point *center,
+ const SDL_RendererFlip flip);
+
+/**
+ * \brief Read pixels from the current rendering target.
+ *
+ * \param renderer The renderer from which pixels should be read.
+ * \param rect A pointer to the rectangle to read, or NULL for the entire
+ * render target.
+ * \param format The desired format of the pixel data, or 0 to use the format
+ * of the rendering target
+ * \param pixels A pointer to be filled in with the pixel data
+ * \param pitch The pitch of the pixels parameter.
+ *
+ * \return 0 on success, or -1 if pixel reading is not supported.
+ *
+ * \warning This is a very slow operation, and should not be used frequently.
+ */
+extern DECLSPEC int SDLCALL SDL_RenderReadPixels(SDL_Renderer * renderer,
+ const SDL_Rect * rect,
+ Uint32 format,
+ void *pixels, int pitch);
+
+/**
+ * \brief Update the screen with rendering performed.
+ */
+extern DECLSPEC void SDLCALL SDL_RenderPresent(SDL_Renderer * renderer);
+
+/**
+ * \brief Destroy the specified texture.
+ *
+ * \sa SDL_CreateTexture()
+ * \sa SDL_CreateTextureFromSurface()
+ */
+extern DECLSPEC void SDLCALL SDL_DestroyTexture(SDL_Texture * texture);
+
+/**
+ * \brief Destroy the rendering context for a window and free associated
+ * textures.
+ *
+ * \sa SDL_CreateRenderer()
+ */
+extern DECLSPEC void SDLCALL SDL_DestroyRenderer(SDL_Renderer * renderer);
+
+
+/**
+ * \brief Bind the texture to the current OpenGL/ES/ES2 context for use with
+ * OpenGL instructions.
+ *
+ * \param texture The SDL texture to bind
+ * \param texw A pointer to a float that will be filled with the texture width
+ * \param texh A pointer to a float that will be filled with the texture height
+ *
+ * \return 0 on success, or -1 if the operation is not supported
+ */
+extern DECLSPEC int SDLCALL SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh);
+
+/**
+ * \brief Unbind a texture from the current OpenGL/ES/ES2 context.
+ *
+ * \param texture The SDL texture to unbind
+ *
+ * \return 0 on success, or -1 if the operation is not supported
+ */
+extern DECLSPEC int SDLCALL SDL_GL_UnbindTexture(SDL_Texture *texture);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_render_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_revision.h b/external/SDL2/include/SDL_revision.h
new file mode 100644
index 0000000..6d7163d
--- /dev/null
+++ b/external/SDL2/include/SDL_revision.h
@@ -0,0 +1,2 @@
+#define SDL_REVISION "hg-10001:e12c38730512"
+#define SDL_REVISION_NUMBER 10001
diff --git a/external/SDL2/include/SDL_rwops.h b/external/SDL2/include/SDL_rwops.h
new file mode 100644
index 0000000..f460ae7
--- /dev/null
+++ b/external/SDL2/include/SDL_rwops.h
@@ -0,0 +1,231 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_rwops.h
+ *
+ * This file provides a general interface for SDL to read and write
+ * data streams. It can easily be extended to files, memory, etc.
+ */
+
+#ifndef _SDL_rwops_h
+#define _SDL_rwops_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* RWops Types */
+#define SDL_RWOPS_UNKNOWN 0 /* Unknown stream type */
+#define SDL_RWOPS_WINFILE 1 /* Win32 file */
+#define SDL_RWOPS_STDFILE 2 /* Stdio file */
+#define SDL_RWOPS_JNIFILE 3 /* Android asset */
+#define SDL_RWOPS_MEMORY 4 /* Memory stream */
+#define SDL_RWOPS_MEMORY_RO 5 /* Read-Only memory stream */
+
+/**
+ * This is the read/write operation structure -- very basic.
+ */
+typedef struct SDL_RWops
+{
+ /**
+ * Return the size of the file in this rwops, or -1 if unknown
+ */
+ Sint64 (SDLCALL * size) (struct SDL_RWops * context);
+
+ /**
+ * Seek to \c offset relative to \c whence, one of stdio's whence values:
+ * RW_SEEK_SET, RW_SEEK_CUR, RW_SEEK_END
+ *
+ * \return the final offset in the data stream, or -1 on error.
+ */
+ Sint64 (SDLCALL * seek) (struct SDL_RWops * context, Sint64 offset,
+ int whence);
+
+ /**
+ * Read up to \c maxnum objects each of size \c size from the data
+ * stream to the area pointed at by \c ptr.
+ *
+ * \return the number of objects read, or 0 at error or end of file.
+ */
+ size_t (SDLCALL * read) (struct SDL_RWops * context, void *ptr,
+ size_t size, size_t maxnum);
+
+ /**
+ * Write exactly \c num objects each of size \c size from the area
+ * pointed at by \c ptr to data stream.
+ *
+ * \return the number of objects written, or 0 at error or end of file.
+ */
+ size_t (SDLCALL * write) (struct SDL_RWops * context, const void *ptr,
+ size_t size, size_t num);
+
+ /**
+ * Close and free an allocated SDL_RWops structure.
+ *
+ * \return 0 if successful or -1 on write error when flushing data.
+ */
+ int (SDLCALL * close) (struct SDL_RWops * context);
+
+ Uint32 type;
+ union
+ {
+#if defined(__ANDROID__)
+ struct
+ {
+ void *fileNameRef;
+ void *inputStreamRef;
+ void *readableByteChannelRef;
+ void *readMethod;
+ void *assetFileDescriptorRef;
+ long position;
+ long size;
+ long offset;
+ int fd;
+ } androidio;
+#elif defined(__WIN32__)
+ struct
+ {
+ SDL_bool append;
+ void *h;
+ struct
+ {
+ void *data;
+ size_t size;
+ size_t left;
+ } buffer;
+ } windowsio;
+#endif
+
+#ifdef HAVE_STDIO_H
+ struct
+ {
+ SDL_bool autoclose;
+ FILE *fp;
+ } stdio;
+#endif
+ struct
+ {
+ Uint8 *base;
+ Uint8 *here;
+ Uint8 *stop;
+ } mem;
+ struct
+ {
+ void *data1;
+ void *data2;
+ } unknown;
+ } hidden;
+
+} SDL_RWops;
+
+
+/**
+ * \name RWFrom functions
+ *
+ * Functions to create SDL_RWops structures from various data streams.
+ */
+/* @{ */
+
+extern DECLSPEC SDL_RWops *SDLCALL SDL_RWFromFile(const char *file,
+ const char *mode);
+
+#ifdef HAVE_STDIO_H
+extern DECLSPEC SDL_RWops *SDLCALL SDL_RWFromFP(FILE * fp,
+ SDL_bool autoclose);
+#else
+extern DECLSPEC SDL_RWops *SDLCALL SDL_RWFromFP(void * fp,
+ SDL_bool autoclose);
+#endif
+
+extern DECLSPEC SDL_RWops *SDLCALL SDL_RWFromMem(void *mem, int size);
+extern DECLSPEC SDL_RWops *SDLCALL SDL_RWFromConstMem(const void *mem,
+ int size);
+
+/* @} *//* RWFrom functions */
+
+
+extern DECLSPEC SDL_RWops *SDLCALL SDL_AllocRW(void);
+extern DECLSPEC void SDLCALL SDL_FreeRW(SDL_RWops * area);
+
+#define RW_SEEK_SET 0 /**< Seek from the beginning of data */
+#define RW_SEEK_CUR 1 /**< Seek relative to current read point */
+#define RW_SEEK_END 2 /**< Seek relative to the end of data */
+
+/**
+ * \name Read/write macros
+ *
+ * Macros to easily read and write from an SDL_RWops structure.
+ */
+/* @{ */
+#define SDL_RWsize(ctx) (ctx)->size(ctx)
+#define SDL_RWseek(ctx, offset, whence) (ctx)->seek(ctx, offset, whence)
+#define SDL_RWtell(ctx) (ctx)->seek(ctx, 0, RW_SEEK_CUR)
+#define SDL_RWread(ctx, ptr, size, n) (ctx)->read(ctx, ptr, size, n)
+#define SDL_RWwrite(ctx, ptr, size, n) (ctx)->write(ctx, ptr, size, n)
+#define SDL_RWclose(ctx) (ctx)->close(ctx)
+/* @} *//* Read/write macros */
+
+
+/**
+ * \name Read endian functions
+ *
+ * Read an item of the specified endianness and return in native format.
+ */
+/* @{ */
+extern DECLSPEC Uint8 SDLCALL SDL_ReadU8(SDL_RWops * src);
+extern DECLSPEC Uint16 SDLCALL SDL_ReadLE16(SDL_RWops * src);
+extern DECLSPEC Uint16 SDLCALL SDL_ReadBE16(SDL_RWops * src);
+extern DECLSPEC Uint32 SDLCALL SDL_ReadLE32(SDL_RWops * src);
+extern DECLSPEC Uint32 SDLCALL SDL_ReadBE32(SDL_RWops * src);
+extern DECLSPEC Uint64 SDLCALL SDL_ReadLE64(SDL_RWops * src);
+extern DECLSPEC Uint64 SDLCALL SDL_ReadBE64(SDL_RWops * src);
+/* @} *//* Read endian functions */
+
+/**
+ * \name Write endian functions
+ *
+ * Write an item of native format to the specified endianness.
+ */
+/* @{ */
+extern DECLSPEC size_t SDLCALL SDL_WriteU8(SDL_RWops * dst, Uint8 value);
+extern DECLSPEC size_t SDLCALL SDL_WriteLE16(SDL_RWops * dst, Uint16 value);
+extern DECLSPEC size_t SDLCALL SDL_WriteBE16(SDL_RWops * dst, Uint16 value);
+extern DECLSPEC size_t SDLCALL SDL_WriteLE32(SDL_RWops * dst, Uint32 value);
+extern DECLSPEC size_t SDLCALL SDL_WriteBE32(SDL_RWops * dst, Uint32 value);
+extern DECLSPEC size_t SDLCALL SDL_WriteLE64(SDL_RWops * dst, Uint64 value);
+extern DECLSPEC size_t SDLCALL SDL_WriteBE64(SDL_RWops * dst, Uint64 value);
+/* @} *//* Write endian functions */
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_rwops_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_scancode.h b/external/SDL2/include/SDL_scancode.h
new file mode 100644
index 0000000..0af1dd5
--- /dev/null
+++ b/external/SDL2/include/SDL_scancode.h
@@ -0,0 +1,401 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_scancode.h
+ *
+ * Defines keyboard scancodes.
+ */
+
+#ifndef _SDL_scancode_h
+#define _SDL_scancode_h
+
+#include "SDL_stdinc.h"
+
+/**
+ * \brief The SDL keyboard scancode representation.
+ *
+ * Values of this type are used to represent keyboard keys, among other places
+ * in the \link SDL_Keysym::scancode key.keysym.scancode \endlink field of the
+ * SDL_Event structure.
+ *
+ * The values in this enumeration are based on the USB usage page standard:
+ * http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf
+ */
+typedef enum
+{
+ SDL_SCANCODE_UNKNOWN = 0,
+
+ /**
+ * \name Usage page 0x07
+ *
+ * These values are from usage page 0x07 (USB keyboard page).
+ */
+ /* @{ */
+
+ SDL_SCANCODE_A = 4,
+ SDL_SCANCODE_B = 5,
+ SDL_SCANCODE_C = 6,
+ SDL_SCANCODE_D = 7,
+ SDL_SCANCODE_E = 8,
+ SDL_SCANCODE_F = 9,
+ SDL_SCANCODE_G = 10,
+ SDL_SCANCODE_H = 11,
+ SDL_SCANCODE_I = 12,
+ SDL_SCANCODE_J = 13,
+ SDL_SCANCODE_K = 14,
+ SDL_SCANCODE_L = 15,
+ SDL_SCANCODE_M = 16,
+ SDL_SCANCODE_N = 17,
+ SDL_SCANCODE_O = 18,
+ SDL_SCANCODE_P = 19,
+ SDL_SCANCODE_Q = 20,
+ SDL_SCANCODE_R = 21,
+ SDL_SCANCODE_S = 22,
+ SDL_SCANCODE_T = 23,
+ SDL_SCANCODE_U = 24,
+ SDL_SCANCODE_V = 25,
+ SDL_SCANCODE_W = 26,
+ SDL_SCANCODE_X = 27,
+ SDL_SCANCODE_Y = 28,
+ SDL_SCANCODE_Z = 29,
+
+ SDL_SCANCODE_1 = 30,
+ SDL_SCANCODE_2 = 31,
+ SDL_SCANCODE_3 = 32,
+ SDL_SCANCODE_4 = 33,
+ SDL_SCANCODE_5 = 34,
+ SDL_SCANCODE_6 = 35,
+ SDL_SCANCODE_7 = 36,
+ SDL_SCANCODE_8 = 37,
+ SDL_SCANCODE_9 = 38,
+ SDL_SCANCODE_0 = 39,
+
+ SDL_SCANCODE_RETURN = 40,
+ SDL_SCANCODE_ESCAPE = 41,
+ SDL_SCANCODE_BACKSPACE = 42,
+ SDL_SCANCODE_TAB = 43,
+ SDL_SCANCODE_SPACE = 44,
+
+ SDL_SCANCODE_MINUS = 45,
+ SDL_SCANCODE_EQUALS = 46,
+ SDL_SCANCODE_LEFTBRACKET = 47,
+ SDL_SCANCODE_RIGHTBRACKET = 48,
+ SDL_SCANCODE_BACKSLASH = 49, /**< Located at the lower left of the return
+ * key on ISO keyboards and at the right end
+ * of the QWERTY row on ANSI keyboards.
+ * Produces REVERSE SOLIDUS (backslash) and
+ * VERTICAL LINE in a US layout, REVERSE
+ * SOLIDUS and VERTICAL LINE in a UK Mac
+ * layout, NUMBER SIGN and TILDE in a UK
+ * Windows layout, DOLLAR SIGN and POUND SIGN
+ * in a Swiss German layout, NUMBER SIGN and
+ * APOSTROPHE in a German layout, GRAVE
+ * ACCENT and POUND SIGN in a French Mac
+ * layout, and ASTERISK and MICRO SIGN in a
+ * French Windows layout.
+ */
+ SDL_SCANCODE_NONUSHASH = 50, /**< ISO USB keyboards actually use this code
+ * instead of 49 for the same key, but all
+ * OSes I've seen treat the two codes
+ * identically. So, as an implementor, unless
+ * your keyboard generates both of those
+ * codes and your OS treats them differently,
+ * you should generate SDL_SCANCODE_BACKSLASH
+ * instead of this code. As a user, you
+ * should not rely on this code because SDL
+ * will never generate it with most (all?)
+ * keyboards.
+ */
+ SDL_SCANCODE_SEMICOLON = 51,
+ SDL_SCANCODE_APOSTROPHE = 52,
+ SDL_SCANCODE_GRAVE = 53, /**< Located in the top left corner (on both ANSI
+ * and ISO keyboards). Produces GRAVE ACCENT and
+ * TILDE in a US Windows layout and in US and UK
+ * Mac layouts on ANSI keyboards, GRAVE ACCENT
+ * and NOT SIGN in a UK Windows layout, SECTION
+ * SIGN and PLUS-MINUS SIGN in US and UK Mac
+ * layouts on ISO keyboards, SECTION SIGN and
+ * DEGREE SIGN in a Swiss German layout (Mac:
+ * only on ISO keyboards), CIRCUMFLEX ACCENT and
+ * DEGREE SIGN in a German layout (Mac: only on
+ * ISO keyboards), SUPERSCRIPT TWO and TILDE in a
+ * French Windows layout, COMMERCIAL AT and
+ * NUMBER SIGN in a French Mac layout on ISO
+ * keyboards, and LESS-THAN SIGN and GREATER-THAN
+ * SIGN in a Swiss German, German, or French Mac
+ * layout on ANSI keyboards.
+ */
+ SDL_SCANCODE_COMMA = 54,
+ SDL_SCANCODE_PERIOD = 55,
+ SDL_SCANCODE_SLASH = 56,
+
+ SDL_SCANCODE_CAPSLOCK = 57,
+
+ SDL_SCANCODE_F1 = 58,
+ SDL_SCANCODE_F2 = 59,
+ SDL_SCANCODE_F3 = 60,
+ SDL_SCANCODE_F4 = 61,
+ SDL_SCANCODE_F5 = 62,
+ SDL_SCANCODE_F6 = 63,
+ SDL_SCANCODE_F7 = 64,
+ SDL_SCANCODE_F8 = 65,
+ SDL_SCANCODE_F9 = 66,
+ SDL_SCANCODE_F10 = 67,
+ SDL_SCANCODE_F11 = 68,
+ SDL_SCANCODE_F12 = 69,
+
+ SDL_SCANCODE_PRINTSCREEN = 70,
+ SDL_SCANCODE_SCROLLLOCK = 71,
+ SDL_SCANCODE_PAUSE = 72,
+ SDL_SCANCODE_INSERT = 73, /**< insert on PC, help on some Mac keyboards (but
+ does send code 73, not 117) */
+ SDL_SCANCODE_HOME = 74,
+ SDL_SCANCODE_PAGEUP = 75,
+ SDL_SCANCODE_DELETE = 76,
+ SDL_SCANCODE_END = 77,
+ SDL_SCANCODE_PAGEDOWN = 78,
+ SDL_SCANCODE_RIGHT = 79,
+ SDL_SCANCODE_LEFT = 80,
+ SDL_SCANCODE_DOWN = 81,
+ SDL_SCANCODE_UP = 82,
+
+ SDL_SCANCODE_NUMLOCKCLEAR = 83, /**< num lock on PC, clear on Mac keyboards
+ */
+ SDL_SCANCODE_KP_DIVIDE = 84,
+ SDL_SCANCODE_KP_MULTIPLY = 85,
+ SDL_SCANCODE_KP_MINUS = 86,
+ SDL_SCANCODE_KP_PLUS = 87,
+ SDL_SCANCODE_KP_ENTER = 88,
+ SDL_SCANCODE_KP_1 = 89,
+ SDL_SCANCODE_KP_2 = 90,
+ SDL_SCANCODE_KP_3 = 91,
+ SDL_SCANCODE_KP_4 = 92,
+ SDL_SCANCODE_KP_5 = 93,
+ SDL_SCANCODE_KP_6 = 94,
+ SDL_SCANCODE_KP_7 = 95,
+ SDL_SCANCODE_KP_8 = 96,
+ SDL_SCANCODE_KP_9 = 97,
+ SDL_SCANCODE_KP_0 = 98,
+ SDL_SCANCODE_KP_PERIOD = 99,
+
+ SDL_SCANCODE_NONUSBACKSLASH = 100, /**< This is the additional key that ISO
+ * keyboards have over ANSI ones,
+ * located between left shift and Y.
+ * Produces GRAVE ACCENT and TILDE in a
+ * US or UK Mac layout, REVERSE SOLIDUS
+ * (backslash) and VERTICAL LINE in a
+ * US or UK Windows layout, and
+ * LESS-THAN SIGN and GREATER-THAN SIGN
+ * in a Swiss German, German, or French
+ * layout. */
+ SDL_SCANCODE_APPLICATION = 101, /**< windows contextual menu, compose */
+ SDL_SCANCODE_POWER = 102, /**< The USB document says this is a status flag,
+ * not a physical key - but some Mac keyboards
+ * do have a power key. */
+ SDL_SCANCODE_KP_EQUALS = 103,
+ SDL_SCANCODE_F13 = 104,
+ SDL_SCANCODE_F14 = 105,
+ SDL_SCANCODE_F15 = 106,
+ SDL_SCANCODE_F16 = 107,
+ SDL_SCANCODE_F17 = 108,
+ SDL_SCANCODE_F18 = 109,
+ SDL_SCANCODE_F19 = 110,
+ SDL_SCANCODE_F20 = 111,
+ SDL_SCANCODE_F21 = 112,
+ SDL_SCANCODE_F22 = 113,
+ SDL_SCANCODE_F23 = 114,
+ SDL_SCANCODE_F24 = 115,
+ SDL_SCANCODE_EXECUTE = 116,
+ SDL_SCANCODE_HELP = 117,
+ SDL_SCANCODE_MENU = 118,
+ SDL_SCANCODE_SELECT = 119,
+ SDL_SCANCODE_STOP = 120,
+ SDL_SCANCODE_AGAIN = 121, /**< redo */
+ SDL_SCANCODE_UNDO = 122,
+ SDL_SCANCODE_CUT = 123,
+ SDL_SCANCODE_COPY = 124,
+ SDL_SCANCODE_PASTE = 125,
+ SDL_SCANCODE_FIND = 126,
+ SDL_SCANCODE_MUTE = 127,
+ SDL_SCANCODE_VOLUMEUP = 128,
+ SDL_SCANCODE_VOLUMEDOWN = 129,
+/* not sure whether there's a reason to enable these */
+/* SDL_SCANCODE_LOCKINGCAPSLOCK = 130, */
+/* SDL_SCANCODE_LOCKINGNUMLOCK = 131, */
+/* SDL_SCANCODE_LOCKINGSCROLLLOCK = 132, */
+ SDL_SCANCODE_KP_COMMA = 133,
+ SDL_SCANCODE_KP_EQUALSAS400 = 134,
+
+ SDL_SCANCODE_INTERNATIONAL1 = 135, /**< used on Asian keyboards, see
+ footnotes in USB doc */
+ SDL_SCANCODE_INTERNATIONAL2 = 136,
+ SDL_SCANCODE_INTERNATIONAL3 = 137, /**< Yen */
+ SDL_SCANCODE_INTERNATIONAL4 = 138,
+ SDL_SCANCODE_INTERNATIONAL5 = 139,
+ SDL_SCANCODE_INTERNATIONAL6 = 140,
+ SDL_SCANCODE_INTERNATIONAL7 = 141,
+ SDL_SCANCODE_INTERNATIONAL8 = 142,
+ SDL_SCANCODE_INTERNATIONAL9 = 143,
+ SDL_SCANCODE_LANG1 = 144, /**< Hangul/English toggle */
+ SDL_SCANCODE_LANG2 = 145, /**< Hanja conversion */
+ SDL_SCANCODE_LANG3 = 146, /**< Katakana */
+ SDL_SCANCODE_LANG4 = 147, /**< Hiragana */
+ SDL_SCANCODE_LANG5 = 148, /**< Zenkaku/Hankaku */
+ SDL_SCANCODE_LANG6 = 149, /**< reserved */
+ SDL_SCANCODE_LANG7 = 150, /**< reserved */
+ SDL_SCANCODE_LANG8 = 151, /**< reserved */
+ SDL_SCANCODE_LANG9 = 152, /**< reserved */
+
+ SDL_SCANCODE_ALTERASE = 153, /**< Erase-Eaze */
+ SDL_SCANCODE_SYSREQ = 154,
+ SDL_SCANCODE_CANCEL = 155,
+ SDL_SCANCODE_CLEAR = 156,
+ SDL_SCANCODE_PRIOR = 157,
+ SDL_SCANCODE_RETURN2 = 158,
+ SDL_SCANCODE_SEPARATOR = 159,
+ SDL_SCANCODE_OUT = 160,
+ SDL_SCANCODE_OPER = 161,
+ SDL_SCANCODE_CLEARAGAIN = 162,
+ SDL_SCANCODE_CRSEL = 163,
+ SDL_SCANCODE_EXSEL = 164,
+
+ SDL_SCANCODE_KP_00 = 176,
+ SDL_SCANCODE_KP_000 = 177,
+ SDL_SCANCODE_THOUSANDSSEPARATOR = 178,
+ SDL_SCANCODE_DECIMALSEPARATOR = 179,
+ SDL_SCANCODE_CURRENCYUNIT = 180,
+ SDL_SCANCODE_CURRENCYSUBUNIT = 181,
+ SDL_SCANCODE_KP_LEFTPAREN = 182,
+ SDL_SCANCODE_KP_RIGHTPAREN = 183,
+ SDL_SCANCODE_KP_LEFTBRACE = 184,
+ SDL_SCANCODE_KP_RIGHTBRACE = 185,
+ SDL_SCANCODE_KP_TAB = 186,
+ SDL_SCANCODE_KP_BACKSPACE = 187,
+ SDL_SCANCODE_KP_A = 188,
+ SDL_SCANCODE_KP_B = 189,
+ SDL_SCANCODE_KP_C = 190,
+ SDL_SCANCODE_KP_D = 191,
+ SDL_SCANCODE_KP_E = 192,
+ SDL_SCANCODE_KP_F = 193,
+ SDL_SCANCODE_KP_XOR = 194,
+ SDL_SCANCODE_KP_POWER = 195,
+ SDL_SCANCODE_KP_PERCENT = 196,
+ SDL_SCANCODE_KP_LESS = 197,
+ SDL_SCANCODE_KP_GREATER = 198,
+ SDL_SCANCODE_KP_AMPERSAND = 199,
+ SDL_SCANCODE_KP_DBLAMPERSAND = 200,
+ SDL_SCANCODE_KP_VERTICALBAR = 201,
+ SDL_SCANCODE_KP_DBLVERTICALBAR = 202,
+ SDL_SCANCODE_KP_COLON = 203,
+ SDL_SCANCODE_KP_HASH = 204,
+ SDL_SCANCODE_KP_SPACE = 205,
+ SDL_SCANCODE_KP_AT = 206,
+ SDL_SCANCODE_KP_EXCLAM = 207,
+ SDL_SCANCODE_KP_MEMSTORE = 208,
+ SDL_SCANCODE_KP_MEMRECALL = 209,
+ SDL_SCANCODE_KP_MEMCLEAR = 210,
+ SDL_SCANCODE_KP_MEMADD = 211,
+ SDL_SCANCODE_KP_MEMSUBTRACT = 212,
+ SDL_SCANCODE_KP_MEMMULTIPLY = 213,
+ SDL_SCANCODE_KP_MEMDIVIDE = 214,
+ SDL_SCANCODE_KP_PLUSMINUS = 215,
+ SDL_SCANCODE_KP_CLEAR = 216,
+ SDL_SCANCODE_KP_CLEARENTRY = 217,
+ SDL_SCANCODE_KP_BINARY = 218,
+ SDL_SCANCODE_KP_OCTAL = 219,
+ SDL_SCANCODE_KP_DECIMAL = 220,
+ SDL_SCANCODE_KP_HEXADECIMAL = 221,
+
+ SDL_SCANCODE_LCTRL = 224,
+ SDL_SCANCODE_LSHIFT = 225,
+ SDL_SCANCODE_LALT = 226, /**< alt, option */
+ SDL_SCANCODE_LGUI = 227, /**< windows, command (apple), meta */
+ SDL_SCANCODE_RCTRL = 228,
+ SDL_SCANCODE_RSHIFT = 229,
+ SDL_SCANCODE_RALT = 230, /**< alt gr, option */
+ SDL_SCANCODE_RGUI = 231, /**< windows, command (apple), meta */
+
+ SDL_SCANCODE_MODE = 257, /**< I'm not sure if this is really not covered
+ * by any of the above, but since there's a
+ * special KMOD_MODE for it I'm adding it here
+ */
+
+ /* @} *//* Usage page 0x07 */
+
+ /**
+ * \name Usage page 0x0C
+ *
+ * These values are mapped from usage page 0x0C (USB consumer page).
+ */
+ /* @{ */
+
+ SDL_SCANCODE_AUDIONEXT = 258,
+ SDL_SCANCODE_AUDIOPREV = 259,
+ SDL_SCANCODE_AUDIOSTOP = 260,
+ SDL_SCANCODE_AUDIOPLAY = 261,
+ SDL_SCANCODE_AUDIOMUTE = 262,
+ SDL_SCANCODE_MEDIASELECT = 263,
+ SDL_SCANCODE_WWW = 264,
+ SDL_SCANCODE_MAIL = 265,
+ SDL_SCANCODE_CALCULATOR = 266,
+ SDL_SCANCODE_COMPUTER = 267,
+ SDL_SCANCODE_AC_SEARCH = 268,
+ SDL_SCANCODE_AC_HOME = 269,
+ SDL_SCANCODE_AC_BACK = 270,
+ SDL_SCANCODE_AC_FORWARD = 271,
+ SDL_SCANCODE_AC_STOP = 272,
+ SDL_SCANCODE_AC_REFRESH = 273,
+ SDL_SCANCODE_AC_BOOKMARKS = 274,
+
+ /* @} *//* Usage page 0x0C */
+
+ /**
+ * \name Walther keys
+ *
+ * These are values that Christian Walther added (for mac keyboard?).
+ */
+ /* @{ */
+
+ SDL_SCANCODE_BRIGHTNESSDOWN = 275,
+ SDL_SCANCODE_BRIGHTNESSUP = 276,
+ SDL_SCANCODE_DISPLAYSWITCH = 277, /**< display mirroring/dual display
+ switch, video mode switch */
+ SDL_SCANCODE_KBDILLUMTOGGLE = 278,
+ SDL_SCANCODE_KBDILLUMDOWN = 279,
+ SDL_SCANCODE_KBDILLUMUP = 280,
+ SDL_SCANCODE_EJECT = 281,
+ SDL_SCANCODE_SLEEP = 282,
+
+ SDL_SCANCODE_APP1 = 283,
+ SDL_SCANCODE_APP2 = 284,
+
+ /* @} *//* Walther keys */
+
+ /* Add any other keys here. */
+
+ SDL_NUM_SCANCODES = 512 /**< not a key, just marks the number of scancodes
+ for array bounds */
+} SDL_Scancode;
+
+#endif /* _SDL_scancode_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_shape.h b/external/SDL2/include/SDL_shape.h
new file mode 100644
index 0000000..db10a8f
--- /dev/null
+++ b/external/SDL2/include/SDL_shape.h
@@ -0,0 +1,143 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_shape_h
+#define _SDL_shape_h
+
+#include "SDL_stdinc.h"
+#include "SDL_pixels.h"
+#include "SDL_rect.h"
+#include "SDL_surface.h"
+#include "SDL_video.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file SDL_shape.h
+ *
+ * Header file for the shaped window API.
+ */
+
+#define SDL_NONSHAPEABLE_WINDOW -1
+#define SDL_INVALID_SHAPE_ARGUMENT -2
+#define SDL_WINDOW_LACKS_SHAPE -3
+
+/**
+ * \brief Create a window that can be shaped with the specified position, dimensions, and flags.
+ *
+ * \param title The title of the window, in UTF-8 encoding.
+ * \param x The x position of the window, ::SDL_WINDOWPOS_CENTERED, or
+ * ::SDL_WINDOWPOS_UNDEFINED.
+ * \param y The y position of the window, ::SDL_WINDOWPOS_CENTERED, or
+ * ::SDL_WINDOWPOS_UNDEFINED.
+ * \param w The width of the window.
+ * \param h The height of the window.
+ * \param flags The flags for the window, a mask of SDL_WINDOW_BORDERLESS with any of the following:
+ * ::SDL_WINDOW_OPENGL, ::SDL_WINDOW_INPUT_GRABBED,
+ * ::SDL_WINDOW_HIDDEN, ::SDL_WINDOW_RESIZABLE,
+ * ::SDL_WINDOW_MAXIMIZED, ::SDL_WINDOW_MINIMIZED,
+ * ::SDL_WINDOW_BORDERLESS is always set, and ::SDL_WINDOW_FULLSCREEN is always unset.
+ *
+ * \return The window created, or NULL if window creation failed.
+ *
+ * \sa SDL_DestroyWindow()
+ */
+extern DECLSPEC SDL_Window * SDLCALL SDL_CreateShapedWindow(const char *title,unsigned int x,unsigned int y,unsigned int w,unsigned int h,Uint32 flags);
+
+/**
+ * \brief Return whether the given window is a shaped window.
+ *
+ * \param window The window to query for being shaped.
+ *
+ * \return SDL_TRUE if the window is a window that can be shaped, SDL_FALSE if the window is unshaped or NULL.
+ * \sa SDL_CreateShapedWindow
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsShapedWindow(const SDL_Window *window);
+
+/** \brief An enum denoting the specific type of contents present in an SDL_WindowShapeParams union. */
+typedef enum {
+ /** \brief The default mode, a binarized alpha cutoff of 1. */
+ ShapeModeDefault,
+ /** \brief A binarized alpha cutoff with a given integer value. */
+ ShapeModeBinarizeAlpha,
+ /** \brief A binarized alpha cutoff with a given integer value, but with the opposite comparison. */
+ ShapeModeReverseBinarizeAlpha,
+ /** \brief A color key is applied. */
+ ShapeModeColorKey
+} WindowShapeMode;
+
+#define SDL_SHAPEMODEALPHA(mode) (mode == ShapeModeDefault || mode == ShapeModeBinarizeAlpha || mode == ShapeModeReverseBinarizeAlpha)
+
+/** \brief A union containing parameters for shaped windows. */
+typedef union {
+ /** \brief a cutoff alpha value for binarization of the window shape's alpha channel. */
+ Uint8 binarizationCutoff;
+ SDL_Color colorKey;
+} SDL_WindowShapeParams;
+
+/** \brief A struct that tags the SDL_WindowShapeParams union with an enum describing the type of its contents. */
+typedef struct SDL_WindowShapeMode {
+ /** \brief The mode of these window-shape parameters. */
+ WindowShapeMode mode;
+ /** \brief Window-shape parameters. */
+ SDL_WindowShapeParams parameters;
+} SDL_WindowShapeMode;
+
+/**
+ * \brief Set the shape and parameters of a shaped window.
+ *
+ * \param window The shaped window whose parameters should be set.
+ * \param shape A surface encoding the desired shape for the window.
+ * \param shape_mode The parameters to set for the shaped window.
+ *
+ * \return 0 on success, SDL_INVALID_SHAPE_ARGUMENT on invalid an invalid shape argument, or SDL_NONSHAPEABLE_WINDOW
+ * if the SDL_Window* given does not reference a valid shaped window.
+ *
+ * \sa SDL_WindowShapeMode
+ * \sa SDL_GetShapedWindowMode.
+ */
+extern DECLSPEC int SDLCALL SDL_SetWindowShape(SDL_Window *window,SDL_Surface *shape,SDL_WindowShapeMode *shape_mode);
+
+/**
+ * \brief Get the shape parameters of a shaped window.
+ *
+ * \param window The shaped window whose parameters should be retrieved.
+ * \param shape_mode An empty shape-mode structure to fill, or NULL to check whether the window has a shape.
+ *
+ * \return 0 if the window has a shape and, provided shape_mode was not NULL, shape_mode has been filled with the mode
+ * data, SDL_NONSHAPEABLE_WINDOW if the SDL_Window given is not a shaped window, or SDL_WINDOW_LACKS_SHAPE if
+ * the SDL_Window* given is a shapeable window currently lacking a shape.
+ *
+ * \sa SDL_WindowShapeMode
+ * \sa SDL_SetWindowShape
+ */
+extern DECLSPEC int SDLCALL SDL_GetShapedWindowMode(SDL_Window *window,SDL_WindowShapeMode *shape_mode);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_shape_h */
diff --git a/external/SDL2/include/SDL_stdinc.h b/external/SDL2/include/SDL_stdinc.h
new file mode 100644
index 0000000..887bcd2
--- /dev/null
+++ b/external/SDL2/include/SDL_stdinc.h
@@ -0,0 +1,527 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_stdinc.h
+ *
+ * This is a general header that includes C language support.
+ */
+
+#ifndef _SDL_stdinc_h
+#define _SDL_stdinc_h
+
+#include "SDL_config.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if defined(STDC_HEADERS)
+# include <stdlib.h>
+# include <stddef.h>
+# include <stdarg.h>
+#else
+# if defined(HAVE_STDLIB_H)
+# include <stdlib.h>
+# elif defined(HAVE_MALLOC_H)
+# include <malloc.h>
+# endif
+# if defined(HAVE_STDDEF_H)
+# include <stddef.h>
+# endif
+# if defined(HAVE_STDARG_H)
+# include <stdarg.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#elif defined(HAVE_STDINT_H)
+# include <stdint.h>
+#endif
+#ifdef HAVE_CTYPE_H
+# include <ctype.h>
+#endif
+#ifdef HAVE_MATH_H
+# if defined(__WINRT__)
+/* Defining _USE_MATH_DEFINES is required to get M_PI to be defined on
+ WinRT. See http://msdn.microsoft.com/en-us/library/4hwaceh6.aspx
+ for more information.
+*/
+# define _USE_MATH_DEFINES
+# endif
+# include <math.h>
+#endif
+#ifdef HAVE_FLOAT_H
+# include <float.h>
+#endif
+#if defined(HAVE_ICONV) && defined(HAVE_ICONV_H)
+# include <iconv.h>
+#endif
+
+/**
+ * The number of elements in an array.
+ */
+#define SDL_arraysize(array) (sizeof(array)/sizeof(array[0]))
+#define SDL_TABLESIZE(table) SDL_arraysize(table)
+
+/**
+ * \name Cast operators
+ *
+ * Use proper C++ casts when compiled as C++ to be compatible with the option
+ * -Wold-style-cast of GCC (and -Werror=old-style-cast in GCC 4.2 and above).
+ */
+/* @{ */
+#ifdef __cplusplus
+#define SDL_reinterpret_cast(type, expression) reinterpret_cast<type>(expression)
+#define SDL_static_cast(type, expression) static_cast<type>(expression)
+#define SDL_const_cast(type, expression) const_cast<type>(expression)
+#else
+#define SDL_reinterpret_cast(type, expression) ((type)(expression))
+#define SDL_static_cast(type, expression) ((type)(expression))
+#define SDL_const_cast(type, expression) ((type)(expression))
+#endif
+/* @} *//* Cast operators */
+
+/* Define a four character code as a Uint32 */
+#define SDL_FOURCC(A, B, C, D) \
+ ((SDL_static_cast(Uint32, SDL_static_cast(Uint8, (A))) << 0) | \
+ (SDL_static_cast(Uint32, SDL_static_cast(Uint8, (B))) << 8) | \
+ (SDL_static_cast(Uint32, SDL_static_cast(Uint8, (C))) << 16) | \
+ (SDL_static_cast(Uint32, SDL_static_cast(Uint8, (D))) << 24))
+
+/**
+ * \name Basic data types
+ */
+/* @{ */
+
+typedef enum
+{
+ SDL_FALSE = 0,
+ SDL_TRUE = 1
+} SDL_bool;
+
+/**
+ * \brief A signed 8-bit integer type.
+ */
+typedef int8_t Sint8;
+/**
+ * \brief An unsigned 8-bit integer type.
+ */
+typedef uint8_t Uint8;
+/**
+ * \brief A signed 16-bit integer type.
+ */
+typedef int16_t Sint16;
+/**
+ * \brief An unsigned 16-bit integer type.
+ */
+typedef uint16_t Uint16;
+/**
+ * \brief A signed 32-bit integer type.
+ */
+typedef int32_t Sint32;
+/**
+ * \brief An unsigned 32-bit integer type.
+ */
+typedef uint32_t Uint32;
+
+/**
+ * \brief A signed 64-bit integer type.
+ */
+typedef int64_t Sint64;
+/**
+ * \brief An unsigned 64-bit integer type.
+ */
+typedef uint64_t Uint64;
+
+/* @} *//* Basic data types */
+
+/* Make sure we have macros for printing 64 bit values.
+ * <stdint.h> should define these but this is not true all platforms.
+ * (for example win32) */
+#ifndef SDL_PRIs64
+#ifdef PRIs64
+#define SDL_PRIs64 PRIs64
+#elif defined(__WIN32__)
+#define SDL_PRIs64 "I64d"
+#elif defined(__LINUX__) && defined(__LP64__)
+#define SDL_PRIs64 "ld"
+#else
+#define SDL_PRIs64 "lld"
+#endif
+#endif
+#ifndef SDL_PRIu64
+#ifdef PRIu64
+#define SDL_PRIu64 PRIu64
+#elif defined(__WIN32__)
+#define SDL_PRIu64 "I64u"
+#elif defined(__LINUX__) && defined(__LP64__)
+#define SDL_PRIu64 "lu"
+#else
+#define SDL_PRIu64 "llu"
+#endif
+#endif
+#ifndef SDL_PRIx64
+#ifdef PRIx64
+#define SDL_PRIx64 PRIx64
+#elif defined(__WIN32__)
+#define SDL_PRIx64 "I64x"
+#elif defined(__LINUX__) && defined(__LP64__)
+#define SDL_PRIx64 "lx"
+#else
+#define SDL_PRIx64 "llx"
+#endif
+#endif
+#ifndef SDL_PRIX64
+#ifdef PRIX64
+#define SDL_PRIX64 PRIX64
+#elif defined(__WIN32__)
+#define SDL_PRIX64 "I64X"
+#elif defined(__LINUX__) && defined(__LP64__)
+#define SDL_PRIX64 "lX"
+#else
+#define SDL_PRIX64 "llX"
+#endif
+#endif
+
+/* Annotations to help code analysis tools */
+#ifdef SDL_DISABLE_ANALYZE_MACROS
+#define SDL_IN_BYTECAP(x)
+#define SDL_INOUT_Z_CAP(x)
+#define SDL_OUT_Z_CAP(x)
+#define SDL_OUT_CAP(x)
+#define SDL_OUT_BYTECAP(x)
+#define SDL_OUT_Z_BYTECAP(x)
+#define SDL_PRINTF_FORMAT_STRING
+#define SDL_SCANF_FORMAT_STRING
+#define SDL_PRINTF_VARARG_FUNC( fmtargnumber )
+#define SDL_SCANF_VARARG_FUNC( fmtargnumber )
+#else
+#if defined(_MSC_VER) && (_MSC_VER >= 1600) /* VS 2010 and above */
+#include <sal.h>
+
+#define SDL_IN_BYTECAP(x) _In_bytecount_(x)
+#define SDL_INOUT_Z_CAP(x) _Inout_z_cap_(x)
+#define SDL_OUT_Z_CAP(x) _Out_z_cap_(x)
+#define SDL_OUT_CAP(x) _Out_cap_(x)
+#define SDL_OUT_BYTECAP(x) _Out_bytecap_(x)
+#define SDL_OUT_Z_BYTECAP(x) _Out_z_bytecap_(x)
+
+#define SDL_PRINTF_FORMAT_STRING _Printf_format_string_
+#define SDL_SCANF_FORMAT_STRING _Scanf_format_string_impl_
+#else
+#define SDL_IN_BYTECAP(x)
+#define SDL_INOUT_Z_CAP(x)
+#define SDL_OUT_Z_CAP(x)
+#define SDL_OUT_CAP(x)
+#define SDL_OUT_BYTECAP(x)
+#define SDL_OUT_Z_BYTECAP(x)
+#define SDL_PRINTF_FORMAT_STRING
+#define SDL_SCANF_FORMAT_STRING
+#endif
+#if defined(__GNUC__)
+#define SDL_PRINTF_VARARG_FUNC( fmtargnumber ) __attribute__ (( format( __printf__, fmtargnumber, fmtargnumber+1 )))
+#define SDL_SCANF_VARARG_FUNC( fmtargnumber ) __attribute__ (( format( __scanf__, fmtargnumber, fmtargnumber+1 )))
+#else
+#define SDL_PRINTF_VARARG_FUNC( fmtargnumber )
+#define SDL_SCANF_VARARG_FUNC( fmtargnumber )
+#endif
+#endif /* SDL_DISABLE_ANALYZE_MACROS */
+
+#define SDL_COMPILE_TIME_ASSERT(name, x) \
+ typedef int SDL_dummy_ ## name[(x) * 2 - 1]
+/** \cond */
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+SDL_COMPILE_TIME_ASSERT(uint8, sizeof(Uint8) == 1);
+SDL_COMPILE_TIME_ASSERT(sint8, sizeof(Sint8) == 1);
+SDL_COMPILE_TIME_ASSERT(uint16, sizeof(Uint16) == 2);
+SDL_COMPILE_TIME_ASSERT(sint16, sizeof(Sint16) == 2);
+SDL_COMPILE_TIME_ASSERT(uint32, sizeof(Uint32) == 4);
+SDL_COMPILE_TIME_ASSERT(sint32, sizeof(Sint32) == 4);
+SDL_COMPILE_TIME_ASSERT(uint64, sizeof(Uint64) == 8);
+SDL_COMPILE_TIME_ASSERT(sint64, sizeof(Sint64) == 8);
+#endif /* DOXYGEN_SHOULD_IGNORE_THIS */
+/** \endcond */
+
+/* Check to make sure enums are the size of ints, for structure packing.
+ For both Watcom C/C++ and Borland C/C++ the compiler option that makes
+ enums having the size of an int must be enabled.
+ This is "-b" for Borland C/C++ and "-ei" for Watcom C/C++ (v11).
+*/
+
+/** \cond */
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+#if !defined(__ANDROID__)
+ /* TODO: include/SDL_stdinc.h:174: error: size of array 'SDL_dummy_enum' is negative */
+typedef enum
+{
+ DUMMY_ENUM_VALUE
+} SDL_DUMMY_ENUM;
+
+SDL_COMPILE_TIME_ASSERT(enum, sizeof(SDL_DUMMY_ENUM) == sizeof(int));
+#endif
+#endif /* DOXYGEN_SHOULD_IGNORE_THIS */
+/** \endcond */
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(HAVE_ALLOCA) && !defined(alloca)
+# if defined(HAVE_ALLOCA_H)
+# include <alloca.h>
+# elif defined(__GNUC__)
+# define alloca __builtin_alloca
+# elif defined(_MSC_VER)
+# include <malloc.h>
+# define alloca _alloca
+# elif defined(__WATCOMC__)
+# include <malloc.h>
+# elif defined(__BORLANDC__)
+# include <malloc.h>
+# elif defined(__DMC__)
+# include <stdlib.h>
+# elif defined(__AIX__)
+#pragma alloca
+# elif defined(__MRC__)
+void *alloca(unsigned);
+# else
+char *alloca();
+# endif
+#endif
+#ifdef HAVE_ALLOCA
+#define SDL_stack_alloc(type, count) (type*)alloca(sizeof(type)*(count))
+#define SDL_stack_free(data)
+#else
+#define SDL_stack_alloc(type, count) (type*)SDL_malloc(sizeof(type)*(count))
+#define SDL_stack_free(data) SDL_free(data)
+#endif
+
+extern DECLSPEC void *SDLCALL SDL_malloc(size_t size);
+extern DECLSPEC void *SDLCALL SDL_calloc(size_t nmemb, size_t size);
+extern DECLSPEC void *SDLCALL SDL_realloc(void *mem, size_t size);
+extern DECLSPEC void SDLCALL SDL_free(void *mem);
+
+extern DECLSPEC char *SDLCALL SDL_getenv(const char *name);
+extern DECLSPEC int SDLCALL SDL_setenv(const char *name, const char *value, int overwrite);
+
+extern DECLSPEC void SDLCALL SDL_qsort(void *base, size_t nmemb, size_t size, int (*compare) (const void *, const void *));
+
+extern DECLSPEC int SDLCALL SDL_abs(int x);
+
+/* !!! FIXME: these have side effects. You probably shouldn't use them. */
+/* !!! FIXME: Maybe we do forceinline functions of SDL_mini, SDL_minf, etc? */
+#define SDL_min(x, y) (((x) < (y)) ? (x) : (y))
+#define SDL_max(x, y) (((x) > (y)) ? (x) : (y))
+
+extern DECLSPEC int SDLCALL SDL_isdigit(int x);
+extern DECLSPEC int SDLCALL SDL_isspace(int x);
+extern DECLSPEC int SDLCALL SDL_toupper(int x);
+extern DECLSPEC int SDLCALL SDL_tolower(int x);
+
+extern DECLSPEC void *SDLCALL SDL_memset(SDL_OUT_BYTECAP(len) void *dst, int c, size_t len);
+
+#define SDL_zero(x) SDL_memset(&(x), 0, sizeof((x)))
+#define SDL_zerop(x) SDL_memset((x), 0, sizeof(*(x)))
+
+/* Note that memset() is a byte assignment and this is a 32-bit assignment, so they're not directly equivalent. */
+SDL_FORCE_INLINE void SDL_memset4(void *dst, Uint32 val, size_t dwords)
+{
+#if defined(__GNUC__) && defined(i386)
+ int u0, u1, u2;
+ __asm__ __volatile__ (
+ "cld \n\t"
+ "rep ; stosl \n\t"
+ : "=&D" (u0), "=&a" (u1), "=&c" (u2)
+ : "0" (dst), "1" (val), "2" (SDL_static_cast(Uint32, dwords))
+ : "memory"
+ );
+#else
+ size_t _n = (dwords + 3) / 4;
+ Uint32 *_p = SDL_static_cast(Uint32 *, dst);
+ Uint32 _val = (val);
+ if (dwords == 0)
+ return;
+ switch (dwords % 4)
+ {
+ case 0: do { *_p++ = _val;
+ case 3: *_p++ = _val;
+ case 2: *_p++ = _val;
+ case 1: *_p++ = _val;
+ } while ( --_n );
+ }
+#endif
+}
+
+
+extern DECLSPEC void *SDLCALL SDL_memcpy(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
+
+extern DECLSPEC void *SDLCALL SDL_memmove(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
+extern DECLSPEC int SDLCALL SDL_memcmp(const void *s1, const void *s2, size_t len);
+
+extern DECLSPEC size_t SDLCALL SDL_wcslen(const wchar_t *wstr);
+extern DECLSPEC size_t SDLCALL SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
+extern DECLSPEC size_t SDLCALL SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
+
+extern DECLSPEC size_t SDLCALL SDL_strlen(const char *str);
+extern DECLSPEC size_t SDLCALL SDL_strlcpy(SDL_OUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen);
+extern DECLSPEC size_t SDLCALL SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_bytes);
+extern DECLSPEC size_t SDLCALL SDL_strlcat(SDL_INOUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen);
+extern DECLSPEC char *SDLCALL SDL_strdup(const char *str);
+extern DECLSPEC char *SDLCALL SDL_strrev(char *str);
+extern DECLSPEC char *SDLCALL SDL_strupr(char *str);
+extern DECLSPEC char *SDLCALL SDL_strlwr(char *str);
+extern DECLSPEC char *SDLCALL SDL_strchr(const char *str, int c);
+extern DECLSPEC char *SDLCALL SDL_strrchr(const char *str, int c);
+extern DECLSPEC char *SDLCALL SDL_strstr(const char *haystack, const char *needle);
+
+extern DECLSPEC char *SDLCALL SDL_itoa(int value, char *str, int radix);
+extern DECLSPEC char *SDLCALL SDL_uitoa(unsigned int value, char *str, int radix);
+extern DECLSPEC char *SDLCALL SDL_ltoa(long value, char *str, int radix);
+extern DECLSPEC char *SDLCALL SDL_ultoa(unsigned long value, char *str, int radix);
+extern DECLSPEC char *SDLCALL SDL_lltoa(Sint64 value, char *str, int radix);
+extern DECLSPEC char *SDLCALL SDL_ulltoa(Uint64 value, char *str, int radix);
+
+extern DECLSPEC int SDLCALL SDL_atoi(const char *str);
+extern DECLSPEC double SDLCALL SDL_atof(const char *str);
+extern DECLSPEC long SDLCALL SDL_strtol(const char *str, char **endp, int base);
+extern DECLSPEC unsigned long SDLCALL SDL_strtoul(const char *str, char **endp, int base);
+extern DECLSPEC Sint64 SDLCALL SDL_strtoll(const char *str, char **endp, int base);
+extern DECLSPEC Uint64 SDLCALL SDL_strtoull(const char *str, char **endp, int base);
+extern DECLSPEC double SDLCALL SDL_strtod(const char *str, char **endp);
+
+extern DECLSPEC int SDLCALL SDL_strcmp(const char *str1, const char *str2);
+extern DECLSPEC int SDLCALL SDL_strncmp(const char *str1, const char *str2, size_t maxlen);
+extern DECLSPEC int SDLCALL SDL_strcasecmp(const char *str1, const char *str2);
+extern DECLSPEC int SDLCALL SDL_strncasecmp(const char *str1, const char *str2, size_t len);
+
+extern DECLSPEC int SDLCALL SDL_sscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, ...) SDL_SCANF_VARARG_FUNC(2);
+extern DECLSPEC int SDLCALL SDL_vsscanf(const char *text, const char *fmt, va_list ap);
+extern DECLSPEC int SDLCALL SDL_snprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ... ) SDL_PRINTF_VARARG_FUNC(3);
+extern DECLSPEC int SDLCALL SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap);
+
+#ifndef HAVE_M_PI
+#ifndef M_PI
+#define M_PI 3.14159265358979323846264338327950288 /* pi */
+#endif
+#endif
+
+extern DECLSPEC double SDLCALL SDL_acos(double x);
+extern DECLSPEC double SDLCALL SDL_asin(double x);
+extern DECLSPEC double SDLCALL SDL_atan(double x);
+extern DECLSPEC double SDLCALL SDL_atan2(double x, double y);
+extern DECLSPEC double SDLCALL SDL_ceil(double x);
+extern DECLSPEC double SDLCALL SDL_copysign(double x, double y);
+extern DECLSPEC double SDLCALL SDL_cos(double x);
+extern DECLSPEC float SDLCALL SDL_cosf(float x);
+extern DECLSPEC double SDLCALL SDL_fabs(double x);
+extern DECLSPEC double SDLCALL SDL_floor(double x);
+extern DECLSPEC double SDLCALL SDL_log(double x);
+extern DECLSPEC double SDLCALL SDL_pow(double x, double y);
+extern DECLSPEC double SDLCALL SDL_scalbn(double x, int n);
+extern DECLSPEC double SDLCALL SDL_sin(double x);
+extern DECLSPEC float SDLCALL SDL_sinf(float x);
+extern DECLSPEC double SDLCALL SDL_sqrt(double x);
+extern DECLSPEC float SDLCALL SDL_sqrtf(float x);
+extern DECLSPEC double SDLCALL SDL_tan(double x);
+extern DECLSPEC float SDLCALL SDL_tanf(float x);
+
+/* The SDL implementation of iconv() returns these error codes */
+#define SDL_ICONV_ERROR (size_t)-1
+#define SDL_ICONV_E2BIG (size_t)-2
+#define SDL_ICONV_EILSEQ (size_t)-3
+#define SDL_ICONV_EINVAL (size_t)-4
+
+/* SDL_iconv_* are now always real symbols/types, not macros or inlined. */
+typedef struct _SDL_iconv_t *SDL_iconv_t;
+extern DECLSPEC SDL_iconv_t SDLCALL SDL_iconv_open(const char *tocode,
+ const char *fromcode);
+extern DECLSPEC int SDLCALL SDL_iconv_close(SDL_iconv_t cd);
+extern DECLSPEC size_t SDLCALL SDL_iconv(SDL_iconv_t cd, const char **inbuf,
+ size_t * inbytesleft, char **outbuf,
+ size_t * outbytesleft);
+/**
+ * This function converts a string between encodings in one pass, returning a
+ * string that must be freed with SDL_free() or NULL on error.
+ */
+extern DECLSPEC char *SDLCALL SDL_iconv_string(const char *tocode,
+ const char *fromcode,
+ const char *inbuf,
+ size_t inbytesleft);
+#define SDL_iconv_utf8_locale(S) SDL_iconv_string("", "UTF-8", S, SDL_strlen(S)+1)
+#define SDL_iconv_utf8_ucs2(S) (Uint16 *)SDL_iconv_string("UCS-2-INTERNAL", "UTF-8", S, SDL_strlen(S)+1)
+#define SDL_iconv_utf8_ucs4(S) (Uint32 *)SDL_iconv_string("UCS-4-INTERNAL", "UTF-8", S, SDL_strlen(S)+1)
+
+/* force builds using Clang's static analysis tools to use literal C runtime
+ here, since there are possibly tests that are ineffective otherwise. */
+#if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS)
+#define SDL_malloc malloc
+#define SDL_calloc calloc
+#define SDL_realloc realloc
+#define SDL_free free
+#define SDL_memset memset
+#define SDL_memcpy memcpy
+#define SDL_memmove memmove
+#define SDL_memcmp memcmp
+#define SDL_strlen strlen
+#define SDL_strlcpy strlcpy
+#define SDL_strlcat strlcat
+#define SDL_strdup strdup
+#define SDL_strchr strchr
+#define SDL_strrchr strrchr
+#define SDL_strstr strstr
+#define SDL_strcmp strcmp
+#define SDL_strncmp strncmp
+#define SDL_strcasecmp strcasecmp
+#define SDL_strncasecmp strncasecmp
+#define SDL_sscanf sscanf
+#define SDL_vsscanf vsscanf
+#define SDL_snprintf snprintf
+#define SDL_vsnprintf vsnprintf
+#endif
+
+SDL_FORCE_INLINE void *SDL_memcpy4(SDL_OUT_BYTECAP(dwords*4) void *dst, SDL_IN_BYTECAP(dwords*4) const void *src, size_t dwords)
+{
+ return SDL_memcpy(dst, src, dwords * 4);
+}
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_stdinc_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_surface.h b/external/SDL2/include/SDL_surface.h
new file mode 100644
index 0000000..e63ca89
--- /dev/null
+++ b/external/SDL2/include/SDL_surface.h
@@ -0,0 +1,503 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_surface.h
+ *
+ * Header file for ::SDL_Surface definition and management functions.
+ */
+
+#ifndef _SDL_surface_h
+#define _SDL_surface_h
+
+#include "SDL_stdinc.h"
+#include "SDL_pixels.h"
+#include "SDL_rect.h"
+#include "SDL_blendmode.h"
+#include "SDL_rwops.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \name Surface flags
+ *
+ * These are the currently supported flags for the ::SDL_Surface.
+ *
+ * \internal
+ * Used internally (read-only).
+ */
+/* @{ */
+#define SDL_SWSURFACE 0 /**< Just here for compatibility */
+#define SDL_PREALLOC 0x00000001 /**< Surface uses preallocated memory */
+#define SDL_RLEACCEL 0x00000002 /**< Surface is RLE encoded */
+#define SDL_DONTFREE 0x00000004 /**< Surface is referenced internally */
+/* @} *//* Surface flags */
+
+/**
+ * Evaluates to true if the surface needs to be locked before access.
+ */
+#define SDL_MUSTLOCK(S) (((S)->flags & SDL_RLEACCEL) != 0)
+
+/**
+ * \brief A collection of pixels used in software blitting.
+ *
+ * \note This structure should be treated as read-only, except for \c pixels,
+ * which, if not NULL, contains the raw pixel data for the surface.
+ */
+typedef struct SDL_Surface
+{
+ Uint32 flags; /**< Read-only */
+ SDL_PixelFormat *format; /**< Read-only */
+ int w, h; /**< Read-only */
+ int pitch; /**< Read-only */
+ void *pixels; /**< Read-write */
+
+ /** Application data associated with the surface */
+ void *userdata; /**< Read-write */
+
+ /** information needed for surfaces requiring locks */
+ int locked; /**< Read-only */
+ void *lock_data; /**< Read-only */
+
+ /** clipping information */
+ SDL_Rect clip_rect; /**< Read-only */
+
+ /** info for fast blit mapping to other surfaces */
+ struct SDL_BlitMap *map; /**< Private */
+
+ /** Reference count -- used when freeing surface */
+ int refcount; /**< Read-mostly */
+} SDL_Surface;
+
+/**
+ * \brief The type of function used for surface blitting functions.
+ */
+typedef int (*SDL_blit) (struct SDL_Surface * src, SDL_Rect * srcrect,
+ struct SDL_Surface * dst, SDL_Rect * dstrect);
+
+/**
+ * Allocate and free an RGB surface.
+ *
+ * If the depth is 4 or 8 bits, an empty palette is allocated for the surface.
+ * If the depth is greater than 8 bits, the pixel format is set using the
+ * flags '[RGB]mask'.
+ *
+ * If the function runs out of memory, it will return NULL.
+ *
+ * \param flags The \c flags are obsolete and should be set to 0.
+ * \param width The width in pixels of the surface to create.
+ * \param height The height in pixels of the surface to create.
+ * \param depth The depth in bits of the surface to create.
+ * \param Rmask The red mask of the surface to create.
+ * \param Gmask The green mask of the surface to create.
+ * \param Bmask The blue mask of the surface to create.
+ * \param Amask The alpha mask of the surface to create.
+ */
+extern DECLSPEC SDL_Surface *SDLCALL SDL_CreateRGBSurface
+ (Uint32 flags, int width, int height, int depth,
+ Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
+extern DECLSPEC SDL_Surface *SDLCALL SDL_CreateRGBSurfaceFrom(void *pixels,
+ int width,
+ int height,
+ int depth,
+ int pitch,
+ Uint32 Rmask,
+ Uint32 Gmask,
+ Uint32 Bmask,
+ Uint32 Amask);
+extern DECLSPEC void SDLCALL SDL_FreeSurface(SDL_Surface * surface);
+
+/**
+ * \brief Set the palette used by a surface.
+ *
+ * \return 0, or -1 if the surface format doesn't use a palette.
+ *
+ * \note A single palette can be shared with many surfaces.
+ */
+extern DECLSPEC int SDLCALL SDL_SetSurfacePalette(SDL_Surface * surface,
+ SDL_Palette * palette);
+
+/**
+ * \brief Sets up a surface for directly accessing the pixels.
+ *
+ * Between calls to SDL_LockSurface() / SDL_UnlockSurface(), you can write
+ * to and read from \c surface->pixels, using the pixel format stored in
+ * \c surface->format. Once you are done accessing the surface, you should
+ * use SDL_UnlockSurface() to release it.
+ *
+ * Not all surfaces require locking. If SDL_MUSTLOCK(surface) evaluates
+ * to 0, then you can read and write to the surface at any time, and the
+ * pixel format of the surface will not change.
+ *
+ * No operating system or library calls should be made between lock/unlock
+ * pairs, as critical system locks may be held during this time.
+ *
+ * SDL_LockSurface() returns 0, or -1 if the surface couldn't be locked.
+ *
+ * \sa SDL_UnlockSurface()
+ */
+extern DECLSPEC int SDLCALL SDL_LockSurface(SDL_Surface * surface);
+/** \sa SDL_LockSurface() */
+extern DECLSPEC void SDLCALL SDL_UnlockSurface(SDL_Surface * surface);
+
+/**
+ * Load a surface from a seekable SDL data stream (memory or file).
+ *
+ * If \c freesrc is non-zero, the stream will be closed after being read.
+ *
+ * The new surface should be freed with SDL_FreeSurface().
+ *
+ * \return the new surface, or NULL if there was an error.
+ */
+extern DECLSPEC SDL_Surface *SDLCALL SDL_LoadBMP_RW(SDL_RWops * src,
+ int freesrc);
+
+/**
+ * Load a surface from a file.
+ *
+ * Convenience macro.
+ */
+#define SDL_LoadBMP(file) SDL_LoadBMP_RW(SDL_RWFromFile(file, "rb"), 1)
+
+/**
+ * Save a surface to a seekable SDL data stream (memory or file).
+ *
+ * If \c freedst is non-zero, the stream will be closed after being written.
+ *
+ * \return 0 if successful or -1 if there was an error.
+ */
+extern DECLSPEC int SDLCALL SDL_SaveBMP_RW
+ (SDL_Surface * surface, SDL_RWops * dst, int freedst);
+
+/**
+ * Save a surface to a file.
+ *
+ * Convenience macro.
+ */
+#define SDL_SaveBMP(surface, file) \
+ SDL_SaveBMP_RW(surface, SDL_RWFromFile(file, "wb"), 1)
+
+/**
+ * \brief Sets the RLE acceleration hint for a surface.
+ *
+ * \return 0 on success, or -1 if the surface is not valid
+ *
+ * \note If RLE is enabled, colorkey and alpha blending blits are much faster,
+ * but the surface must be locked before directly accessing the pixels.
+ */
+extern DECLSPEC int SDLCALL SDL_SetSurfaceRLE(SDL_Surface * surface,
+ int flag);
+
+/**
+ * \brief Sets the color key (transparent pixel) in a blittable surface.
+ *
+ * \param surface The surface to update
+ * \param flag Non-zero to enable colorkey and 0 to disable colorkey
+ * \param key The transparent pixel in the native surface format
+ *
+ * \return 0 on success, or -1 if the surface is not valid
+ *
+ * You can pass SDL_RLEACCEL to enable RLE accelerated blits.
+ */
+extern DECLSPEC int SDLCALL SDL_SetColorKey(SDL_Surface * surface,
+ int flag, Uint32 key);
+
+/**
+ * \brief Gets the color key (transparent pixel) in a blittable surface.
+ *
+ * \param surface The surface to update
+ * \param key A pointer filled in with the transparent pixel in the native
+ * surface format
+ *
+ * \return 0 on success, or -1 if the surface is not valid or colorkey is not
+ * enabled.
+ */
+extern DECLSPEC int SDLCALL SDL_GetColorKey(SDL_Surface * surface,
+ Uint32 * key);
+
+/**
+ * \brief Set an additional color value used in blit operations.
+ *
+ * \param surface The surface to update.
+ * \param r The red color value multiplied into blit operations.
+ * \param g The green color value multiplied into blit operations.
+ * \param b The blue color value multiplied into blit operations.
+ *
+ * \return 0 on success, or -1 if the surface is not valid.
+ *
+ * \sa SDL_GetSurfaceColorMod()
+ */
+extern DECLSPEC int SDLCALL SDL_SetSurfaceColorMod(SDL_Surface * surface,
+ Uint8 r, Uint8 g, Uint8 b);
+
+
+/**
+ * \brief Get the additional color value used in blit operations.
+ *
+ * \param surface The surface to query.
+ * \param r A pointer filled in with the current red color value.
+ * \param g A pointer filled in with the current green color value.
+ * \param b A pointer filled in with the current blue color value.
+ *
+ * \return 0 on success, or -1 if the surface is not valid.
+ *
+ * \sa SDL_SetSurfaceColorMod()
+ */
+extern DECLSPEC int SDLCALL SDL_GetSurfaceColorMod(SDL_Surface * surface,
+ Uint8 * r, Uint8 * g,
+ Uint8 * b);
+
+/**
+ * \brief Set an additional alpha value used in blit operations.
+ *
+ * \param surface The surface to update.
+ * \param alpha The alpha value multiplied into blit operations.
+ *
+ * \return 0 on success, or -1 if the surface is not valid.
+ *
+ * \sa SDL_GetSurfaceAlphaMod()
+ */
+extern DECLSPEC int SDLCALL SDL_SetSurfaceAlphaMod(SDL_Surface * surface,
+ Uint8 alpha);
+
+/**
+ * \brief Get the additional alpha value used in blit operations.
+ *
+ * \param surface The surface to query.
+ * \param alpha A pointer filled in with the current alpha value.
+ *
+ * \return 0 on success, or -1 if the surface is not valid.
+ *
+ * \sa SDL_SetSurfaceAlphaMod()
+ */
+extern DECLSPEC int SDLCALL SDL_GetSurfaceAlphaMod(SDL_Surface * surface,
+ Uint8 * alpha);
+
+/**
+ * \brief Set the blend mode used for blit operations.
+ *
+ * \param surface The surface to update.
+ * \param blendMode ::SDL_BlendMode to use for blit blending.
+ *
+ * \return 0 on success, or -1 if the parameters are not valid.
+ *
+ * \sa SDL_GetSurfaceBlendMode()
+ */
+extern DECLSPEC int SDLCALL SDL_SetSurfaceBlendMode(SDL_Surface * surface,
+ SDL_BlendMode blendMode);
+
+/**
+ * \brief Get the blend mode used for blit operations.
+ *
+ * \param surface The surface to query.
+ * \param blendMode A pointer filled in with the current blend mode.
+ *
+ * \return 0 on success, or -1 if the surface is not valid.
+ *
+ * \sa SDL_SetSurfaceBlendMode()
+ */
+extern DECLSPEC int SDLCALL SDL_GetSurfaceBlendMode(SDL_Surface * surface,
+ SDL_BlendMode *blendMode);
+
+/**
+ * Sets the clipping rectangle for the destination surface in a blit.
+ *
+ * If the clip rectangle is NULL, clipping will be disabled.
+ *
+ * If the clip rectangle doesn't intersect the surface, the function will
+ * return SDL_FALSE and blits will be completely clipped. Otherwise the
+ * function returns SDL_TRUE and blits to the surface will be clipped to
+ * the intersection of the surface area and the clipping rectangle.
+ *
+ * Note that blits are automatically clipped to the edges of the source
+ * and destination surfaces.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_SetClipRect(SDL_Surface * surface,
+ const SDL_Rect * rect);
+
+/**
+ * Gets the clipping rectangle for the destination surface in a blit.
+ *
+ * \c rect must be a pointer to a valid rectangle which will be filled
+ * with the correct values.
+ */
+extern DECLSPEC void SDLCALL SDL_GetClipRect(SDL_Surface * surface,
+ SDL_Rect * rect);
+
+/**
+ * Creates a new surface of the specified format, and then copies and maps
+ * the given surface to it so the blit of the converted surface will be as
+ * fast as possible. If this function fails, it returns NULL.
+ *
+ * The \c flags parameter is passed to SDL_CreateRGBSurface() and has those
+ * semantics. You can also pass ::SDL_RLEACCEL in the flags parameter and
+ * SDL will try to RLE accelerate colorkey and alpha blits in the resulting
+ * surface.
+ */
+extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurface
+ (SDL_Surface * src, const SDL_PixelFormat * fmt, Uint32 flags);
+extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurfaceFormat
+ (SDL_Surface * src, Uint32 pixel_format, Uint32 flags);
+
+/**
+ * \brief Copy a block of pixels of one format to another format
+ *
+ * \return 0 on success, or -1 if there was an error
+ */
+extern DECLSPEC int SDLCALL SDL_ConvertPixels(int width, int height,
+ Uint32 src_format,
+ const void * src, int src_pitch,
+ Uint32 dst_format,
+ void * dst, int dst_pitch);
+
+/**
+ * Performs a fast fill of the given rectangle with \c color.
+ *
+ * If \c rect is NULL, the whole surface will be filled with \c color.
+ *
+ * The color should be a pixel of the format used by the surface, and
+ * can be generated by the SDL_MapRGB() function.
+ *
+ * \return 0 on success, or -1 on error.
+ */
+extern DECLSPEC int SDLCALL SDL_FillRect
+ (SDL_Surface * dst, const SDL_Rect * rect, Uint32 color);
+extern DECLSPEC int SDLCALL SDL_FillRects
+ (SDL_Surface * dst, const SDL_Rect * rects, int count, Uint32 color);
+
+/**
+ * Performs a fast blit from the source surface to the destination surface.
+ *
+ * This assumes that the source and destination rectangles are
+ * the same size. If either \c srcrect or \c dstrect are NULL, the entire
+ * surface (\c src or \c dst) is copied. The final blit rectangles are saved
+ * in \c srcrect and \c dstrect after all clipping is performed.
+ *
+ * \return If the blit is successful, it returns 0, otherwise it returns -1.
+ *
+ * The blit function should not be called on a locked surface.
+ *
+ * The blit semantics for surfaces with and without blending and colorkey
+ * are defined as follows:
+ * \verbatim
+ RGBA->RGB:
+ Source surface blend mode set to SDL_BLENDMODE_BLEND:
+ alpha-blend (using the source alpha-channel and per-surface alpha)
+ SDL_SRCCOLORKEY ignored.
+ Source surface blend mode set to SDL_BLENDMODE_NONE:
+ copy RGB.
+ if SDL_SRCCOLORKEY set, only copy the pixels matching the
+ RGB values of the source color key, ignoring alpha in the
+ comparison.
+
+ RGB->RGBA:
+ Source surface blend mode set to SDL_BLENDMODE_BLEND:
+ alpha-blend (using the source per-surface alpha)
+ Source surface blend mode set to SDL_BLENDMODE_NONE:
+ copy RGB, set destination alpha to source per-surface alpha value.
+ both:
+ if SDL_SRCCOLORKEY set, only copy the pixels matching the
+ source color key.
+
+ RGBA->RGBA:
+ Source surface blend mode set to SDL_BLENDMODE_BLEND:
+ alpha-blend (using the source alpha-channel and per-surface alpha)
+ SDL_SRCCOLORKEY ignored.
+ Source surface blend mode set to SDL_BLENDMODE_NONE:
+ copy all of RGBA to the destination.
+ if SDL_SRCCOLORKEY set, only copy the pixels matching the
+ RGB values of the source color key, ignoring alpha in the
+ comparison.
+
+ RGB->RGB:
+ Source surface blend mode set to SDL_BLENDMODE_BLEND:
+ alpha-blend (using the source per-surface alpha)
+ Source surface blend mode set to SDL_BLENDMODE_NONE:
+ copy RGB.
+ both:
+ if SDL_SRCCOLORKEY set, only copy the pixels matching the
+ source color key.
+ \endverbatim
+ *
+ * You should call SDL_BlitSurface() unless you know exactly how SDL
+ * blitting works internally and how to use the other blit functions.
+ */
+#define SDL_BlitSurface SDL_UpperBlit
+
+/**
+ * This is the public blit function, SDL_BlitSurface(), and it performs
+ * rectangle validation and clipping before passing it to SDL_LowerBlit()
+ */
+extern DECLSPEC int SDLCALL SDL_UpperBlit
+ (SDL_Surface * src, const SDL_Rect * srcrect,
+ SDL_Surface * dst, SDL_Rect * dstrect);
+
+/**
+ * This is a semi-private blit function and it performs low-level surface
+ * blitting only.
+ */
+extern DECLSPEC int SDLCALL SDL_LowerBlit
+ (SDL_Surface * src, SDL_Rect * srcrect,
+ SDL_Surface * dst, SDL_Rect * dstrect);
+
+/**
+ * \brief Perform a fast, low quality, stretch blit between two surfaces of the
+ * same pixel format.
+ *
+ * \note This function uses a static buffer, and is not thread-safe.
+ */
+extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface * src,
+ const SDL_Rect * srcrect,
+ SDL_Surface * dst,
+ const SDL_Rect * dstrect);
+
+#define SDL_BlitScaled SDL_UpperBlitScaled
+
+/**
+ * This is the public scaled blit function, SDL_BlitScaled(), and it performs
+ * rectangle validation and clipping before passing it to SDL_LowerBlitScaled()
+ */
+extern DECLSPEC int SDLCALL SDL_UpperBlitScaled
+ (SDL_Surface * src, const SDL_Rect * srcrect,
+ SDL_Surface * dst, SDL_Rect * dstrect);
+
+/**
+ * This is a semi-private blit function and it performs low-level surface
+ * scaled blitting only.
+ */
+extern DECLSPEC int SDLCALL SDL_LowerBlitScaled
+ (SDL_Surface * src, SDL_Rect * srcrect,
+ SDL_Surface * dst, SDL_Rect * dstrect);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_surface_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_system.h b/external/SDL2/include/SDL_system.h
new file mode 100644
index 0000000..5da9adb
--- /dev/null
+++ b/external/SDL2/include/SDL_system.h
@@ -0,0 +1,216 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_system.h
+ *
+ * Include file for platform specific SDL API functions
+ */
+
+#ifndef _SDL_system_h
+#define _SDL_system_h
+
+#include "SDL_stdinc.h"
+#include "SDL_keyboard.h"
+#include "SDL_render.h"
+#include "SDL_video.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Platform specific functions for Windows */
+#ifdef __WIN32__
+
+/**
+ \brief Set a function that is called for every windows message, before TranslateMessage()
+*/
+typedef void (SDLCALL * SDL_WindowsMessageHook)(void *userdata, void *hWnd, unsigned int message, Uint64 wParam, Sint64 lParam);
+extern DECLSPEC void SDLCALL SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata);
+
+/**
+ \brief Returns the D3D9 adapter index that matches the specified display index.
+
+ This adapter index can be passed to IDirect3D9::CreateDevice and controls
+ on which monitor a full screen application will appear.
+*/
+extern DECLSPEC int SDLCALL SDL_Direct3D9GetAdapterIndex( int displayIndex );
+
+typedef struct IDirect3DDevice9 IDirect3DDevice9;
+/**
+ \brief Returns the D3D device associated with a renderer, or NULL if it's not a D3D renderer.
+
+ Once you are done using the device, you should release it to avoid a resource leak.
+ */
+extern DECLSPEC IDirect3DDevice9* SDLCALL SDL_RenderGetD3D9Device(SDL_Renderer * renderer);
+
+/**
+ \brief Returns the DXGI Adapter and Output indices for the specified display index.
+
+ These can be passed to EnumAdapters and EnumOutputs respectively to get the objects
+ required to create a DX10 or DX11 device and swap chain.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_DXGIGetOutputInfo( int displayIndex, int *adapterIndex, int *outputIndex );
+
+#endif /* __WIN32__ */
+
+
+/* Platform specific functions for iOS */
+#if defined(__IPHONEOS__) && __IPHONEOS__
+
+#define SDL_iOSSetAnimationCallback(window, interval, callback, callbackParam) SDL_iPhoneSetAnimationCallback(window, interval, callback, callbackParam)
+extern DECLSPEC int SDLCALL SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam);
+
+#define SDL_iOSSetEventPump(enabled) SDL_iPhoneSetEventPump(enabled)
+extern DECLSPEC void SDLCALL SDL_iPhoneSetEventPump(SDL_bool enabled);
+
+#endif /* __IPHONEOS__ */
+
+
+/* Platform specific functions for Android */
+#if defined(__ANDROID__) && __ANDROID__
+
+/**
+ \brief Get the JNI environment for the current thread
+
+ This returns JNIEnv*, but the prototype is void* so we don't need jni.h
+ */
+extern DECLSPEC void * SDLCALL SDL_AndroidGetJNIEnv();
+
+/**
+ \brief Get the SDL Activity object for the application
+
+ This returns jobject, but the prototype is void* so we don't need jni.h
+ The jobject returned by SDL_AndroidGetActivity is a local reference.
+ It is the caller's responsibility to properly release it
+ (using env->Push/PopLocalFrame or manually with env->DeleteLocalRef)
+ */
+extern DECLSPEC void * SDLCALL SDL_AndroidGetActivity();
+
+/**
+ See the official Android developer guide for more information:
+ http://developer.android.com/guide/topics/data/data-storage.html
+*/
+#define SDL_ANDROID_EXTERNAL_STORAGE_READ 0x01
+#define SDL_ANDROID_EXTERNAL_STORAGE_WRITE 0x02
+
+/**
+ \brief Get the path used for internal storage for this application.
+
+ This path is unique to your application and cannot be written to
+ by other applications.
+ */
+extern DECLSPEC const char * SDLCALL SDL_AndroidGetInternalStoragePath();
+
+/**
+ \brief Get the current state of external storage, a bitmask of these values:
+ SDL_ANDROID_EXTERNAL_STORAGE_READ
+ SDL_ANDROID_EXTERNAL_STORAGE_WRITE
+
+ If external storage is currently unavailable, this will return 0.
+*/
+extern DECLSPEC int SDLCALL SDL_AndroidGetExternalStorageState();
+
+/**
+ \brief Get the path used for external storage for this application.
+
+ This path is unique to your application, but is public and can be
+ written to by other applications.
+ */
+extern DECLSPEC const char * SDLCALL SDL_AndroidGetExternalStoragePath();
+
+#endif /* __ANDROID__ */
+
+/* Platform specific functions for WinRT */
+#if defined(__WINRT__) && __WINRT__
+
+/**
+ * \brief WinRT / Windows Phone path types
+ */
+typedef enum
+{
+ /** \brief The installed app's root directory.
+ Files here are likely to be read-only. */
+ SDL_WINRT_PATH_INSTALLED_LOCATION,
+
+ /** \brief The app's local data store. Files may be written here */
+ SDL_WINRT_PATH_LOCAL_FOLDER,
+
+ /** \brief The app's roaming data store. Unsupported on Windows Phone.
+ Files written here may be copied to other machines via a network
+ connection.
+ */
+ SDL_WINRT_PATH_ROAMING_FOLDER,
+
+ /** \brief The app's temporary data store. Unsupported on Windows Phone.
+ Files written here may be deleted at any time. */
+ SDL_WINRT_PATH_TEMP_FOLDER
+} SDL_WinRT_Path;
+
+
+/**
+ * \brief Retrieves a WinRT defined path on the local file system
+ *
+ * \note Documentation on most app-specific path types on WinRT
+ * can be found on MSDN, at the URL:
+ * http://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx
+ *
+ * \param pathType The type of path to retrieve.
+ * \return A UCS-2 string (16-bit, wide-char) containing the path, or NULL
+ * if the path is not available for any reason. Not all paths are
+ * available on all versions of Windows. This is especially true on
+ * Windows Phone. Check the documentation for the given
+ * SDL_WinRT_Path for more information on which path types are
+ * supported where.
+ */
+extern DECLSPEC const wchar_t * SDLCALL SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType);
+
+/**
+ * \brief Retrieves a WinRT defined path on the local file system
+ *
+ * \note Documentation on most app-specific path types on WinRT
+ * can be found on MSDN, at the URL:
+ * http://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx
+ *
+ * \param pathType The type of path to retrieve.
+ * \return A UTF-8 string (8-bit, multi-byte) containing the path, or NULL
+ * if the path is not available for any reason. Not all paths are
+ * available on all versions of Windows. This is especially true on
+ * Windows Phone. Check the documentation for the given
+ * SDL_WinRT_Path for more information on which path types are
+ * supported where.
+ */
+extern DECLSPEC const char * SDLCALL SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType);
+
+#endif /* __WINRT__ */
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_system_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_syswm.h b/external/SDL2/include/SDL_syswm.h
new file mode 100644
index 0000000..1056e52
--- /dev/null
+++ b/external/SDL2/include/SDL_syswm.h
@@ -0,0 +1,301 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_syswm.h
+ *
+ * Include file for SDL custom system window manager hooks.
+ */
+
+#ifndef _SDL_syswm_h
+#define _SDL_syswm_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_video.h"
+#include "SDL_version.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file SDL_syswm.h
+ *
+ * Your application has access to a special type of event ::SDL_SYSWMEVENT,
+ * which contains window-manager specific information and arrives whenever
+ * an unhandled window event occurs. This event is ignored by default, but
+ * you can enable it with SDL_EventState().
+ */
+#ifdef SDL_PROTOTYPES_ONLY
+struct SDL_SysWMinfo;
+#else
+
+#if defined(SDL_VIDEO_DRIVER_WINDOWS)
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#endif
+
+#if defined(SDL_VIDEO_DRIVER_WINRT)
+#include <Inspectable.h>
+#endif
+
+/* This is the structure for custom window manager events */
+#if defined(SDL_VIDEO_DRIVER_X11)
+#if defined(__APPLE__) && defined(__MACH__)
+/* conflicts with Quickdraw.h */
+#define Cursor X11Cursor
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#if defined(__APPLE__) && defined(__MACH__)
+/* matches the re-define above */
+#undef Cursor
+#endif
+
+#endif /* defined(SDL_VIDEO_DRIVER_X11) */
+
+#if defined(SDL_VIDEO_DRIVER_DIRECTFB)
+#include <directfb.h>
+#endif
+
+#if defined(SDL_VIDEO_DRIVER_COCOA)
+#ifdef __OBJC__
+@class NSWindow;
+#else
+typedef struct _NSWindow NSWindow;
+#endif
+#endif
+
+#if defined(SDL_VIDEO_DRIVER_UIKIT)
+#ifdef __OBJC__
+#include <UIKit/UIKit.h>
+#else
+typedef struct _UIWindow UIWindow;
+typedef struct _UIViewController UIViewController;
+#endif
+typedef Uint32 GLuint;
+#endif
+
+#if defined(SDL_VIDEO_DRIVER_ANDROID)
+typedef struct ANativeWindow ANativeWindow;
+typedef void *EGLSurface;
+#endif
+
+/**
+ * These are the various supported windowing subsystems
+ */
+typedef enum
+{
+ SDL_SYSWM_UNKNOWN,
+ SDL_SYSWM_WINDOWS,
+ SDL_SYSWM_X11,
+ SDL_SYSWM_DIRECTFB,
+ SDL_SYSWM_COCOA,
+ SDL_SYSWM_UIKIT,
+ SDL_SYSWM_WAYLAND,
+ SDL_SYSWM_MIR,
+ SDL_SYSWM_WINRT,
+ SDL_SYSWM_ANDROID
+} SDL_SYSWM_TYPE;
+
+/**
+ * The custom event structure.
+ */
+struct SDL_SysWMmsg
+{
+ SDL_version version;
+ SDL_SYSWM_TYPE subsystem;
+ union
+ {
+#if defined(SDL_VIDEO_DRIVER_WINDOWS)
+ struct {
+ HWND hwnd; /**< The window for the message */
+ UINT msg; /**< The type of message */
+ WPARAM wParam; /**< WORD message parameter */
+ LPARAM lParam; /**< LONG message parameter */
+ } win;
+#endif
+#if defined(SDL_VIDEO_DRIVER_X11)
+ struct {
+ XEvent event;
+ } x11;
+#endif
+#if defined(SDL_VIDEO_DRIVER_DIRECTFB)
+ struct {
+ DFBEvent event;
+ } dfb;
+#endif
+#if defined(SDL_VIDEO_DRIVER_COCOA)
+ struct
+ {
+ /* Latest version of Xcode clang complains about empty structs in C v. C++:
+ error: empty struct has size 0 in C, size 1 in C++
+ */
+ int dummy;
+ /* No Cocoa window events yet */
+ } cocoa;
+#endif
+#if defined(SDL_VIDEO_DRIVER_UIKIT)
+ struct
+ {
+ int dummy;
+ /* No UIKit window events yet */
+ } uikit;
+#endif
+ /* Can't have an empty union */
+ int dummy;
+ } msg;
+};
+
+/**
+ * The custom window manager information structure.
+ *
+ * When this structure is returned, it holds information about which
+ * low level system it is using, and will be one of SDL_SYSWM_TYPE.
+ */
+struct SDL_SysWMinfo
+{
+ SDL_version version;
+ SDL_SYSWM_TYPE subsystem;
+ union
+ {
+#if defined(SDL_VIDEO_DRIVER_WINDOWS)
+ struct
+ {
+ HWND window; /**< The window handle */
+ HDC hdc; /**< The window device context */
+ } win;
+#endif
+#if defined(SDL_VIDEO_DRIVER_WINRT)
+ struct
+ {
+ IInspectable * window; /**< The WinRT CoreWindow */
+ } winrt;
+#endif
+#if defined(SDL_VIDEO_DRIVER_X11)
+ struct
+ {
+ Display *display; /**< The X11 display */
+ Window window; /**< The X11 window */
+ } x11;
+#endif
+#if defined(SDL_VIDEO_DRIVER_DIRECTFB)
+ struct
+ {
+ IDirectFB *dfb; /**< The directfb main interface */
+ IDirectFBWindow *window; /**< The directfb window handle */
+ IDirectFBSurface *surface; /**< The directfb client surface */
+ } dfb;
+#endif
+#if defined(SDL_VIDEO_DRIVER_COCOA)
+ struct
+ {
+#if defined(__OBJC__) && defined(__has_feature) && __has_feature(objc_arc)
+ NSWindow __unsafe_unretained *window; /* The Cocoa window */
+#else
+ NSWindow *window; /* The Cocoa window */
+#endif
+ } cocoa;
+#endif
+#if defined(SDL_VIDEO_DRIVER_UIKIT)
+ struct
+ {
+#if defined(__OBJC__) && defined(__has_feature) && __has_feature(objc_arc)
+ UIWindow __unsafe_unretained *window; /* The UIKit window */
+#else
+ UIWindow *window; /* The UIKit window */
+#endif
+ GLuint framebuffer; /* The GL view's Framebuffer Object. It must be bound when rendering to the screen using GL. */
+ GLuint colorbuffer; /* The GL view's color Renderbuffer Object. It must be bound when SDL_GL_SwapWindow is called. */
+ GLuint resolveFramebuffer; /* The Framebuffer Object which holds the resolve color Renderbuffer, when MSAA is used. */
+ } uikit;
+#endif
+#if defined(SDL_VIDEO_DRIVER_WAYLAND)
+ struct
+ {
+ struct wl_display *display; /**< Wayland display */
+ struct wl_surface *surface; /**< Wayland surface */
+ struct wl_shell_surface *shell_surface; /**< Wayland shell_surface (window manager handle) */
+ } wl;
+#endif
+#if defined(SDL_VIDEO_DRIVER_MIR)
+ struct
+ {
+ struct MirConnection *connection; /**< Mir display server connection */
+ struct MirSurface *surface; /**< Mir surface */
+ } mir;
+#endif
+
+#if defined(SDL_VIDEO_DRIVER_ANDROID)
+ struct
+ {
+ ANativeWindow *window;
+ EGLSurface surface;
+ } android;
+#endif
+
+ /* Can't have an empty union */
+ int dummy;
+ } info;
+};
+
+#endif /* SDL_PROTOTYPES_ONLY */
+
+typedef struct SDL_SysWMinfo SDL_SysWMinfo;
+
+/* Function prototypes */
+/**
+ * \brief This function allows access to driver-dependent window information.
+ *
+ * \param window The window about which information is being requested
+ * \param info This structure must be initialized with the SDL version, and is
+ * then filled in with information about the given window.
+ *
+ * \return SDL_TRUE if the function is implemented and the version member of
+ * the \c info struct is valid, SDL_FALSE otherwise.
+ *
+ * You typically use this function like this:
+ * \code
+ * SDL_SysWMinfo info;
+ * SDL_VERSION(&info.version);
+ * if ( SDL_GetWindowWMInfo(window, &info) ) { ... }
+ * \endcode
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_GetWindowWMInfo(SDL_Window * window,
+ SDL_SysWMinfo * info);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_syswm_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test.h b/external/SDL2/include/SDL_test.h
new file mode 100644
index 0000000..217847b
--- /dev/null
+++ b/external/SDL2/include/SDL_test.h
@@ -0,0 +1,68 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+#ifndef _SDL_test_h
+#define _SDL_test_h
+
+#include "SDL.h"
+#include "SDL_test_common.h"
+#include "SDL_test_font.h"
+#include "SDL_test_random.h"
+#include "SDL_test_fuzzer.h"
+#include "SDL_test_crc32.h"
+#include "SDL_test_md5.h"
+#include "SDL_test_log.h"
+#include "SDL_test_assert.h"
+#include "SDL_test_harness.h"
+#include "SDL_test_images.h"
+#include "SDL_test_compare.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global definitions */
+
+/*
+ * Note: Maximum size of SDLTest log message is less than SDL's limit
+ * to ensure we can fit additional information such as the timestamp.
+ */
+#define SDLTEST_MAX_LOGMESSAGE_LENGTH 3584
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test_assert.h b/external/SDL2/include/SDL_test_assert.h
new file mode 100644
index 0000000..29277e1
--- /dev/null
+++ b/external/SDL2/include/SDL_test_assert.h
@@ -0,0 +1,105 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test_assert.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+/*
+ *
+ * Assert API for test code and test cases
+ *
+ */
+
+#ifndef _SDL_test_assert_h
+#define _SDL_test_assert_h
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Fails the assert.
+ */
+#define ASSERT_FAIL 0
+
+/**
+ * \brief Passes the assert.
+ */
+#define ASSERT_PASS 1
+
+/**
+ * \brief Assert that logs and break execution flow on failures.
+ *
+ * \param assertCondition Evaluated condition or variable to assert; fail (==0) or pass (!=0).
+ * \param assertDescription Message to log with the assert describing it.
+ */
+void SDLTest_Assert(int assertCondition, SDL_PRINTF_FORMAT_STRING const char *assertDescription, ...) SDL_PRINTF_VARARG_FUNC(2);
+
+/**
+ * \brief Assert for test cases that logs but does not break execution flow on failures. Updates assertion counters.
+ *
+ * \param assertCondition Evaluated condition or variable to assert; fail (==0) or pass (!=0).
+ * \param assertDescription Message to log with the assert describing it.
+ *
+ * \returns Returns the assertCondition so it can be used to externally to break execution flow if desired.
+ */
+int SDLTest_AssertCheck(int assertCondition, SDL_PRINTF_FORMAT_STRING const char *assertDescription, ...) SDL_PRINTF_VARARG_FUNC(2);
+
+/**
+ * \brief Explicitly pass without checking an assertion condition. Updates assertion counter.
+ *
+ * \param assertDescription Message to log with the assert describing it.
+ */
+void SDLTest_AssertPass(SDL_PRINTF_FORMAT_STRING const char *assertDescription, ...) SDL_PRINTF_VARARG_FUNC(1);
+
+/**
+ * \brief Resets the assert summary counters to zero.
+ */
+void SDLTest_ResetAssertSummary();
+
+/**
+ * \brief Logs summary of all assertions (total, pass, fail) since last reset as INFO or ERROR.
+ */
+void SDLTest_LogAssertSummary();
+
+
+/**
+ * \brief Converts the current assert summary state to a test result.
+ *
+ * \returns TEST_RESULT_PASSED, TEST_RESULT_FAILED, or TEST_RESULT_NO_ASSERT
+ */
+int SDLTest_AssertSummaryToTestResult();
+
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_assert_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test_common.h b/external/SDL2/include/SDL_test_common.h
new file mode 100644
index 0000000..0ebf31c
--- /dev/null
+++ b/external/SDL2/include/SDL_test_common.h
@@ -0,0 +1,188 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test_common.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+/* Ported from original test\common.h file. */
+
+#ifndef _SDL_test_common_h
+#define _SDL_test_common_h
+
+#include "SDL.h"
+
+#if defined(__PSP__)
+#define DEFAULT_WINDOW_WIDTH 480
+#define DEFAULT_WINDOW_HEIGHT 272
+#else
+#define DEFAULT_WINDOW_WIDTH 640
+#define DEFAULT_WINDOW_HEIGHT 480
+#endif
+
+#define VERBOSE_VIDEO 0x00000001
+#define VERBOSE_MODES 0x00000002
+#define VERBOSE_RENDER 0x00000004
+#define VERBOSE_EVENT 0x00000008
+#define VERBOSE_AUDIO 0x00000010
+
+typedef struct
+{
+ /* SDL init flags */
+ char **argv;
+ Uint32 flags;
+ Uint32 verbose;
+
+ /* Video info */
+ const char *videodriver;
+ int display;
+ const char *window_title;
+ const char *window_icon;
+ Uint32 window_flags;
+ int window_x;
+ int window_y;
+ int window_w;
+ int window_h;
+ int window_minW;
+ int window_minH;
+ int window_maxW;
+ int window_maxH;
+ int logical_w;
+ int logical_h;
+ float scale;
+ int depth;
+ int refresh_rate;
+ int num_windows;
+ SDL_Window **windows;
+
+ /* Renderer info */
+ const char *renderdriver;
+ Uint32 render_flags;
+ SDL_bool skip_renderer;
+ SDL_Renderer **renderers;
+ SDL_Texture **targets;
+
+ /* Audio info */
+ const char *audiodriver;
+ SDL_AudioSpec audiospec;
+
+ /* GL settings */
+ int gl_red_size;
+ int gl_green_size;
+ int gl_blue_size;
+ int gl_alpha_size;
+ int gl_buffer_size;
+ int gl_depth_size;
+ int gl_stencil_size;
+ int gl_double_buffer;
+ int gl_accum_red_size;
+ int gl_accum_green_size;
+ int gl_accum_blue_size;
+ int gl_accum_alpha_size;
+ int gl_stereo;
+ int gl_multisamplebuffers;
+ int gl_multisamplesamples;
+ int gl_retained_backing;
+ int gl_accelerated;
+ int gl_major_version;
+ int gl_minor_version;
+ int gl_debug;
+ int gl_profile_mask;
+} SDLTest_CommonState;
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Function prototypes */
+
+/**
+ * \brief Parse command line parameters and create common state.
+ *
+ * \param argv Array of command line parameters
+ * \param flags Flags indicating which subsystem to initialize (i.e. SDL_INIT_VIDEO | SDL_INIT_AUDIO)
+ *
+ * \returns Returns a newly allocated common state object.
+ */
+SDLTest_CommonState *SDLTest_CommonCreateState(char **argv, Uint32 flags);
+
+/**
+ * \brief Process one common argument.
+ *
+ * \param state The common state describing the test window to create.
+ * \param index The index of the argument to process in argv[].
+ *
+ * \returns The number of arguments processed (i.e. 1 for --fullscreen, 2 for --video [videodriver], or -1 on error.
+ */
+int SDLTest_CommonArg(SDLTest_CommonState * state, int index);
+
+/**
+ * \brief Returns common usage information
+ *
+ * \param state The common state describing the test window to create.
+ *
+ * \returns String with usage information
+ */
+const char *SDLTest_CommonUsage(SDLTest_CommonState * state);
+
+/**
+ * \brief Open test window.
+ *
+ * \param state The common state describing the test window to create.
+ *
+ * \returns True if initialization succeeded, false otherwise
+ */
+SDL_bool SDLTest_CommonInit(SDLTest_CommonState * state);
+
+/**
+ * \brief Common event handler for test windows.
+ *
+ * \param state The common state used to create test window.
+ * \param event The event to handle.
+ * \param done Flag indicating we are done.
+ *
+ */
+void SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done);
+
+/**
+ * \brief Close test window.
+ *
+ * \param state The common state used to create test window.
+ *
+ */
+void SDLTest_CommonQuit(SDLTest_CommonState * state);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_common_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test_compare.h b/external/SDL2/include/SDL_test_compare.h
new file mode 100644
index 0000000..772cf9f
--- /dev/null
+++ b/external/SDL2/include/SDL_test_compare.h
@@ -0,0 +1,69 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test_compare.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+/*
+
+ Defines comparison functions (i.e. for surfaces).
+
+*/
+
+#ifndef _SDL_test_compare_h
+#define _SDL_test_compare_h
+
+#include "SDL.h"
+
+#include "SDL_test_images.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Compares a surface and with reference image data for equality
+ *
+ * \param surface Surface used in comparison
+ * \param referenceSurface Test Surface used in comparison
+ * \param allowable_error Allowable difference (=sum of squared difference for each RGB component) in blending accuracy.
+ *
+ * \returns 0 if comparison succeeded, >0 (=number of pixels for which the comparison failed) if comparison failed, -1 if any of the surfaces were NULL, -2 if the surface sizes differ.
+ */
+int SDLTest_CompareSurfaces(SDL_Surface *surface, SDL_Surface *referenceSurface, int allowable_error);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_compare_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test_crc32.h b/external/SDL2/include/SDL_test_crc32.h
new file mode 100644
index 0000000..572a3d9
--- /dev/null
+++ b/external/SDL2/include/SDL_test_crc32.h
@@ -0,0 +1,124 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test_crc32.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+/*
+
+ Implements CRC32 calculations (default output is Perl String::CRC32 compatible).
+
+*/
+
+#ifndef _SDL_test_crc32_h
+#define _SDL_test_crc32_h
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* ------------ Definitions --------- */
+
+/* Definition shared by all CRC routines */
+
+#ifndef CrcUint32
+ #define CrcUint32 unsigned int
+#endif
+#ifndef CrcUint8
+ #define CrcUint8 unsigned char
+#endif
+
+#ifdef ORIGINAL_METHOD
+ #define CRC32_POLY 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */
+#else
+ #define CRC32_POLY 0xEDB88320 /* Perl String::CRC32 compatible */
+#endif
+
+/**
+ * Data structure for CRC32 (checksum) computation
+ */
+ typedef struct {
+ CrcUint32 crc32_table[256]; /* CRC table */
+ } SDLTest_Crc32Context;
+
+/* ---------- Function Prototypes ------------- */
+
+/**
+ * \brief Initialize the CRC context
+ *
+ * Note: The function initializes the crc table required for all crc calculations.
+ *
+ * \param crcContext pointer to context variable
+ *
+ * \returns 0 for OK, -1 on error
+ *
+ */
+ int SDLTest_Crc32Init(SDLTest_Crc32Context * crcContext);
+
+
+/**
+ * \brief calculate a crc32 from a data block
+ *
+ * \param crcContext pointer to context variable
+ * \param inBuf input buffer to checksum
+ * \param inLen length of input buffer
+ * \param crc32 pointer to Uint32 to store the final CRC into
+ *
+ * \returns 0 for OK, -1 on error
+ *
+ */
+int SDLTest_crc32Calc(SDLTest_Crc32Context * crcContext, CrcUint8 *inBuf, CrcUint32 inLen, CrcUint32 *crc32);
+
+/* Same routine broken down into three steps */
+int SDLTest_Crc32CalcStart(SDLTest_Crc32Context * crcContext, CrcUint32 *crc32);
+int SDLTest_Crc32CalcEnd(SDLTest_Crc32Context * crcContext, CrcUint32 *crc32);
+int SDLTest_Crc32CalcBuffer(SDLTest_Crc32Context * crcContext, CrcUint8 *inBuf, CrcUint32 inLen, CrcUint32 *crc32);
+
+
+/**
+ * \brief clean up CRC context
+ *
+ * \param crcContext pointer to context variable
+ *
+ * \returns 0 for OK, -1 on error
+ *
+*/
+
+int SDLTest_Crc32Done(SDLTest_Crc32Context * crcContext);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_crc32_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test_font.h b/external/SDL2/include/SDL_test_font.h
new file mode 100644
index 0000000..3378ea8
--- /dev/null
+++ b/external/SDL2/include/SDL_test_font.h
@@ -0,0 +1,76 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test_font.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+#ifndef _SDL_test_font_h
+#define _SDL_test_font_h
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Function prototypes */
+
+#define FONT_CHARACTER_SIZE 8
+
+/**
+ * \brief Draw a string in the currently set font.
+ *
+ * \param renderer The renderer to draw on.
+ * \param x The X coordinate of the upper left corner of the character.
+ * \param y The Y coordinate of the upper left corner of the character.
+ * \param c The character to draw.
+ *
+ * \returns Returns 0 on success, -1 on failure.
+ */
+int SDLTest_DrawCharacter( SDL_Renderer *renderer, int x, int y, char c );
+
+/**
+ * \brief Draw a string in the currently set font.
+ *
+ * \param renderer The renderer to draw on.
+ * \param x The X coordinate of the upper left corner of the string.
+ * \param y The Y coordinate of the upper left corner of the string.
+ * \param s The string to draw.
+ *
+ * \returns Returns 0 on success, -1 on failure.
+ */
+int SDLTest_DrawString( SDL_Renderer * renderer, int x, int y, const char *s );
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_font_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test_fuzzer.h b/external/SDL2/include/SDL_test_fuzzer.h
new file mode 100644
index 0000000..9603652
--- /dev/null
+++ b/external/SDL2/include/SDL_test_fuzzer.h
@@ -0,0 +1,384 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test_fuzzer.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+/*
+
+ Data generators for fuzzing test data in a reproducible way.
+
+*/
+
+#ifndef _SDL_test_fuzzer_h
+#define _SDL_test_fuzzer_h
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ Based on GSOC code by Markus Kauppila <markus.kauppila@gmail.com>
+*/
+
+
+/**
+ * \file
+ * Note: The fuzzer implementation uses a static instance of random context
+ * internally which makes it thread-UNsafe.
+ */
+
+/**
+ * Initializes the fuzzer for a test
+ *
+ * \param execKey Execution "Key" that initializes the random number generator uniquely for the test.
+ *
+ */
+void SDLTest_FuzzerInit(Uint64 execKey);
+
+
+/**
+ * Returns a random Uint8
+ *
+ * \returns Generated integer
+ */
+Uint8 SDLTest_RandomUint8();
+
+/**
+ * Returns a random Sint8
+ *
+ * \returns Generated signed integer
+ */
+Sint8 SDLTest_RandomSint8();
+
+
+/**
+ * Returns a random Uint16
+ *
+ * \returns Generated integer
+ */
+Uint16 SDLTest_RandomUint16();
+
+/**
+ * Returns a random Sint16
+ *
+ * \returns Generated signed integer
+ */
+Sint16 SDLTest_RandomSint16();
+
+
+/**
+ * Returns a random integer
+ *
+ * \returns Generated integer
+ */
+Sint32 SDLTest_RandomSint32();
+
+
+/**
+ * Returns a random positive integer
+ *
+ * \returns Generated integer
+ */
+Uint32 SDLTest_RandomUint32();
+
+/**
+ * Returns random Uint64.
+ *
+ * \returns Generated integer
+ */
+Uint64 SDLTest_RandomUint64();
+
+
+/**
+ * Returns random Sint64.
+ *
+ * \returns Generated signed integer
+ */
+Sint64 SDLTest_RandomSint64();
+
+/**
+ * \returns random float in range [0.0 - 1.0[
+ */
+float SDLTest_RandomUnitFloat();
+
+/**
+ * \returns random double in range [0.0 - 1.0[
+ */
+double SDLTest_RandomUnitDouble();
+
+/**
+ * \returns random float.
+ *
+ */
+float SDLTest_RandomFloat();
+
+/**
+ * \returns random double.
+ *
+ */
+double SDLTest_RandomDouble();
+
+/**
+ * Returns a random boundary value for Uint8 within the given boundaries.
+ * Boundaries are inclusive, see the usage examples below. If validDomain
+ * is true, the function will only return valid boundaries, otherwise non-valid
+ * boundaries are also possible.
+ * If boundary1 > boundary2, the values are swapped
+ *
+ * Usage examples:
+ * RandomUint8BoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20
+ * RandomUint8BoundaryValue(1, 20, SDL_FALSE) returns 0 or 21
+ * RandomUint8BoundaryValue(0, 99, SDL_FALSE) returns 100
+ * RandomUint8BoundaryValue(0, 255, SDL_FALSE) returns 0 (error set)
+ *
+ * \param boundary1 Lower boundary limit
+ * \param boundary2 Upper boundary limit
+ * \param validDomain Should the generated boundary be valid (=within the bounds) or not?
+ *
+ * \returns Random boundary value for the given range and domain or 0 with error set
+ */
+Uint8 SDLTest_RandomUint8BoundaryValue(Uint8 boundary1, Uint8 boundary2, SDL_bool validDomain);
+
+/**
+ * Returns a random boundary value for Uint16 within the given boundaries.
+ * Boundaries are inclusive, see the usage examples below. If validDomain
+ * is true, the function will only return valid boundaries, otherwise non-valid
+ * boundaries are also possible.
+ * If boundary1 > boundary2, the values are swapped
+ *
+ * Usage examples:
+ * RandomUint16BoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20
+ * RandomUint16BoundaryValue(1, 20, SDL_FALSE) returns 0 or 21
+ * RandomUint16BoundaryValue(0, 99, SDL_FALSE) returns 100
+ * RandomUint16BoundaryValue(0, 0xFFFF, SDL_FALSE) returns 0 (error set)
+ *
+ * \param boundary1 Lower boundary limit
+ * \param boundary2 Upper boundary limit
+ * \param validDomain Should the generated boundary be valid (=within the bounds) or not?
+ *
+ * \returns Random boundary value for the given range and domain or 0 with error set
+ */
+Uint16 SDLTest_RandomUint16BoundaryValue(Uint16 boundary1, Uint16 boundary2, SDL_bool validDomain);
+
+/**
+ * Returns a random boundary value for Uint32 within the given boundaries.
+ * Boundaries are inclusive, see the usage examples below. If validDomain
+ * is true, the function will only return valid boundaries, otherwise non-valid
+ * boundaries are also possible.
+ * If boundary1 > boundary2, the values are swapped
+ *
+ * Usage examples:
+ * RandomUint32BoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20
+ * RandomUint32BoundaryValue(1, 20, SDL_FALSE) returns 0 or 21
+ * RandomUint32BoundaryValue(0, 99, SDL_FALSE) returns 100
+ * RandomUint32BoundaryValue(0, 0xFFFFFFFF, SDL_FALSE) returns 0 (with error set)
+ *
+ * \param boundary1 Lower boundary limit
+ * \param boundary2 Upper boundary limit
+ * \param validDomain Should the generated boundary be valid (=within the bounds) or not?
+ *
+ * \returns Random boundary value for the given range and domain or 0 with error set
+ */
+Uint32 SDLTest_RandomUint32BoundaryValue(Uint32 boundary1, Uint32 boundary2, SDL_bool validDomain);
+
+/**
+ * Returns a random boundary value for Uint64 within the given boundaries.
+ * Boundaries are inclusive, see the usage examples below. If validDomain
+ * is true, the function will only return valid boundaries, otherwise non-valid
+ * boundaries are also possible.
+ * If boundary1 > boundary2, the values are swapped
+ *
+ * Usage examples:
+ * RandomUint64BoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20
+ * RandomUint64BoundaryValue(1, 20, SDL_FALSE) returns 0 or 21
+ * RandomUint64BoundaryValue(0, 99, SDL_FALSE) returns 100
+ * RandomUint64BoundaryValue(0, 0xFFFFFFFFFFFFFFFF, SDL_FALSE) returns 0 (with error set)
+ *
+ * \param boundary1 Lower boundary limit
+ * \param boundary2 Upper boundary limit
+ * \param validDomain Should the generated boundary be valid (=within the bounds) or not?
+ *
+ * \returns Random boundary value for the given range and domain or 0 with error set
+ */
+Uint64 SDLTest_RandomUint64BoundaryValue(Uint64 boundary1, Uint64 boundary2, SDL_bool validDomain);
+
+/**
+ * Returns a random boundary value for Sint8 within the given boundaries.
+ * Boundaries are inclusive, see the usage examples below. If validDomain
+ * is true, the function will only return valid boundaries, otherwise non-valid
+ * boundaries are also possible.
+ * If boundary1 > boundary2, the values are swapped
+ *
+ * Usage examples:
+ * RandomSint8BoundaryValue(-10, 20, SDL_TRUE) returns -11, -10, 19 or 20
+ * RandomSint8BoundaryValue(-100, -10, SDL_FALSE) returns -101 or -9
+ * RandomSint8BoundaryValue(SINT8_MIN, 99, SDL_FALSE) returns 100
+ * RandomSint8BoundaryValue(SINT8_MIN, SINT8_MAX, SDL_FALSE) returns SINT8_MIN (== error value) with error set
+ *
+ * \param boundary1 Lower boundary limit
+ * \param boundary2 Upper boundary limit
+ * \param validDomain Should the generated boundary be valid (=within the bounds) or not?
+ *
+ * \returns Random boundary value for the given range and domain or SINT8_MIN with error set
+ */
+Sint8 SDLTest_RandomSint8BoundaryValue(Sint8 boundary1, Sint8 boundary2, SDL_bool validDomain);
+
+
+/**
+ * Returns a random boundary value for Sint16 within the given boundaries.
+ * Boundaries are inclusive, see the usage examples below. If validDomain
+ * is true, the function will only return valid boundaries, otherwise non-valid
+ * boundaries are also possible.
+ * If boundary1 > boundary2, the values are swapped
+ *
+ * Usage examples:
+ * RandomSint16BoundaryValue(-10, 20, SDL_TRUE) returns -11, -10, 19 or 20
+ * RandomSint16BoundaryValue(-100, -10, SDL_FALSE) returns -101 or -9
+ * RandomSint16BoundaryValue(SINT16_MIN, 99, SDL_FALSE) returns 100
+ * RandomSint16BoundaryValue(SINT16_MIN, SINT16_MAX, SDL_FALSE) returns SINT16_MIN (== error value) with error set
+ *
+ * \param boundary1 Lower boundary limit
+ * \param boundary2 Upper boundary limit
+ * \param validDomain Should the generated boundary be valid (=within the bounds) or not?
+ *
+ * \returns Random boundary value for the given range and domain or SINT16_MIN with error set
+ */
+Sint16 SDLTest_RandomSint16BoundaryValue(Sint16 boundary1, Sint16 boundary2, SDL_bool validDomain);
+
+/**
+ * Returns a random boundary value for Sint32 within the given boundaries.
+ * Boundaries are inclusive, see the usage examples below. If validDomain
+ * is true, the function will only return valid boundaries, otherwise non-valid
+ * boundaries are also possible.
+ * If boundary1 > boundary2, the values are swapped
+ *
+ * Usage examples:
+ * RandomSint32BoundaryValue(-10, 20, SDL_TRUE) returns -11, -10, 19 or 20
+ * RandomSint32BoundaryValue(-100, -10, SDL_FALSE) returns -101 or -9
+ * RandomSint32BoundaryValue(SINT32_MIN, 99, SDL_FALSE) returns 100
+ * RandomSint32BoundaryValue(SINT32_MIN, SINT32_MAX, SDL_FALSE) returns SINT32_MIN (== error value)
+ *
+ * \param boundary1 Lower boundary limit
+ * \param boundary2 Upper boundary limit
+ * \param validDomain Should the generated boundary be valid (=within the bounds) or not?
+ *
+ * \returns Random boundary value for the given range and domain or SINT32_MIN with error set
+ */
+Sint32 SDLTest_RandomSint32BoundaryValue(Sint32 boundary1, Sint32 boundary2, SDL_bool validDomain);
+
+/**
+ * Returns a random boundary value for Sint64 within the given boundaries.
+ * Boundaries are inclusive, see the usage examples below. If validDomain
+ * is true, the function will only return valid boundaries, otherwise non-valid
+ * boundaries are also possible.
+ * If boundary1 > boundary2, the values are swapped
+ *
+ * Usage examples:
+ * RandomSint64BoundaryValue(-10, 20, SDL_TRUE) returns -11, -10, 19 or 20
+ * RandomSint64BoundaryValue(-100, -10, SDL_FALSE) returns -101 or -9
+ * RandomSint64BoundaryValue(SINT64_MIN, 99, SDL_FALSE) returns 100
+ * RandomSint64BoundaryValue(SINT64_MIN, SINT64_MAX, SDL_FALSE) returns SINT64_MIN (== error value) and error set
+ *
+ * \param boundary1 Lower boundary limit
+ * \param boundary2 Upper boundary limit
+ * \param validDomain Should the generated boundary be valid (=within the bounds) or not?
+ *
+ * \returns Random boundary value for the given range and domain or SINT64_MIN with error set
+ */
+Sint64 SDLTest_RandomSint64BoundaryValue(Sint64 boundary1, Sint64 boundary2, SDL_bool validDomain);
+
+
+/**
+ * Returns integer in range [min, max] (inclusive).
+ * Min and max values can be negative values.
+ * If Max in smaller than min, then the values are swapped.
+ * Min and max are the same value, that value will be returned.
+ *
+ * \param min Minimum inclusive value of returned random number
+ * \param max Maximum inclusive value of returned random number
+ *
+ * \returns Generated random integer in range
+ */
+Sint32 SDLTest_RandomIntegerInRange(Sint32 min, Sint32 max);
+
+
+/**
+ * Generates random null-terminated string. The minimum length for
+ * the string is 1 character, maximum length for the string is 255
+ * characters and it can contain ASCII characters from 32 to 126.
+ *
+ * Note: Returned string needs to be deallocated.
+ *
+ * \returns Newly allocated random string; or NULL if length was invalid or string could not be allocated.
+ */
+char * SDLTest_RandomAsciiString();
+
+
+/**
+ * Generates random null-terminated string. The maximum length for
+ * the string is defined by the maxLength parameter.
+ * String can contain ASCII characters from 32 to 126.
+ *
+ * Note: Returned string needs to be deallocated.
+ *
+ * \param maxLength The maximum length of the generated string.
+ *
+ * \returns Newly allocated random string; or NULL if maxLength was invalid or string could not be allocated.
+ */
+char * SDLTest_RandomAsciiStringWithMaximumLength(int maxLength);
+
+
+/**
+ * Generates random null-terminated string. The length for
+ * the string is defined by the size parameter.
+ * String can contain ASCII characters from 32 to 126.
+ *
+ * Note: Returned string needs to be deallocated.
+ *
+ * \param size The length of the generated string
+ *
+ * \returns Newly allocated random string; or NULL if size was invalid or string could not be allocated.
+ */
+char * SDLTest_RandomAsciiStringOfSize(int size);
+
+/**
+ * Returns the invocation count for the fuzzer since last ...FuzzerInit.
+ */
+int SDLTest_GetFuzzerInvocationCount();
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_fuzzer_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test_harness.h b/external/SDL2/include/SDL_test_harness.h
new file mode 100644
index 0000000..74c0950
--- /dev/null
+++ b/external/SDL2/include/SDL_test_harness.h
@@ -0,0 +1,123 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test_harness.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+/*
+ Defines types for test case definitions and the test execution harness API.
+
+ Based on original GSOC code by Markus Kauppila <markus.kauppila@gmail.com>
+*/
+
+#ifndef _SDL_test_harness_h
+#define _SDL_test_harness_h
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* ! Definitions for test case structures */
+#define TEST_ENABLED 1
+#define TEST_DISABLED 0
+
+/* ! Definition of all the possible test return values of the test case method */
+#define TEST_ABORTED -1
+#define TEST_STARTED 0
+#define TEST_COMPLETED 1
+#define TEST_SKIPPED 2
+
+/* ! Definition of all the possible test results for the harness */
+#define TEST_RESULT_PASSED 0
+#define TEST_RESULT_FAILED 1
+#define TEST_RESULT_NO_ASSERT 2
+#define TEST_RESULT_SKIPPED 3
+#define TEST_RESULT_SETUP_FAILURE 4
+
+/* !< Function pointer to a test case setup function (run before every test) */
+typedef void (*SDLTest_TestCaseSetUpFp)(void *arg);
+
+/* !< Function pointer to a test case function */
+typedef int (*SDLTest_TestCaseFp)(void *arg);
+
+/* !< Function pointer to a test case teardown function (run after every test) */
+typedef void (*SDLTest_TestCaseTearDownFp)(void *arg);
+
+/**
+ * Holds information about a single test case.
+ */
+typedef struct SDLTest_TestCaseReference {
+ /* !< Func2Stress */
+ SDLTest_TestCaseFp testCase;
+ /* !< Short name (or function name) "Func2Stress" */
+ char *name;
+ /* !< Long name or full description "This test pushes func2() to the limit." */
+ char *description;
+ /* !< Set to TEST_ENABLED or TEST_DISABLED (test won't be run) */
+ int enabled;
+} SDLTest_TestCaseReference;
+
+/**
+ * Holds information about a test suite (multiple test cases).
+ */
+typedef struct SDLTest_TestSuiteReference {
+ /* !< "PlatformSuite" */
+ char *name;
+ /* !< The function that is run before each test. NULL skips. */
+ SDLTest_TestCaseSetUpFp testSetUp;
+ /* !< The test cases that are run as part of the suite. Last item should be NULL. */
+ const SDLTest_TestCaseReference **testCases;
+ /* !< The function that is run after each test. NULL skips. */
+ SDLTest_TestCaseTearDownFp testTearDown;
+} SDLTest_TestSuiteReference;
+
+
+/**
+ * \brief Execute a test suite using the given run seed and execution key.
+ *
+ * \param testSuites Suites containing the test case.
+ * \param userRunSeed Custom run seed provided by user, or NULL to autogenerate one.
+ * \param userExecKey Custom execution key provided by user, or 0 to autogenerate one.
+ * \param filter Filter specification. NULL disables. Case sensitive.
+ * \param testIterations Number of iterations to run each test case.
+ *
+ * \returns Test run result; 0 when all tests passed, 1 if any tests failed.
+ */
+int SDLTest_RunSuites(SDLTest_TestSuiteReference *testSuites[], const char *userRunSeed, Uint64 userExecKey, const char *filter, int testIterations);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_harness_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test_images.h b/external/SDL2/include/SDL_test_images.h
new file mode 100644
index 0000000..8c64b4f
--- /dev/null
+++ b/external/SDL2/include/SDL_test_images.h
@@ -0,0 +1,78 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test_images.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+/*
+
+ Defines some images for tests.
+
+*/
+
+#ifndef _SDL_test_images_h
+#define _SDL_test_images_h
+
+#include "SDL.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ *Type for test images.
+ */
+typedef struct SDLTest_SurfaceImage_s {
+ int width;
+ int height;
+ unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */
+ const char *pixel_data;
+} SDLTest_SurfaceImage_t;
+
+/* Test images */
+SDL_Surface *SDLTest_ImageBlit();
+SDL_Surface *SDLTest_ImageBlitColor();
+SDL_Surface *SDLTest_ImageBlitAlpha();
+SDL_Surface *SDLTest_ImageBlitBlendAdd();
+SDL_Surface *SDLTest_ImageBlitBlend();
+SDL_Surface *SDLTest_ImageBlitBlendMod();
+SDL_Surface *SDLTest_ImageBlitBlendNone();
+SDL_Surface *SDLTest_ImageBlitBlendAll();
+SDL_Surface *SDLTest_ImageFace();
+SDL_Surface *SDLTest_ImagePrimitives();
+SDL_Surface *SDLTest_ImagePrimitivesBlend();
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_images_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test_log.h b/external/SDL2/include/SDL_test_log.h
new file mode 100644
index 0000000..73a5c01
--- /dev/null
+++ b/external/SDL2/include/SDL_test_log.h
@@ -0,0 +1,67 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test_log.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+/*
+ *
+ * Wrapper to log in the TEST category
+ *
+ */
+
+#ifndef _SDL_test_log_h
+#define _SDL_test_log_h
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Prints given message with a timestamp in the TEST category and INFO priority.
+ *
+ * \param fmt Message to be logged
+ */
+void SDLTest_Log(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(1);
+
+/**
+ * \brief Prints given message with a timestamp in the TEST category and the ERROR priority.
+ *
+ * \param fmt Message to be logged
+ */
+void SDLTest_LogError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(1);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_log_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test_md5.h b/external/SDL2/include/SDL_test_md5.h
new file mode 100644
index 0000000..f2d9a7d
--- /dev/null
+++ b/external/SDL2/include/SDL_test_md5.h
@@ -0,0 +1,129 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test_md5.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+/*
+ ***********************************************************************
+ ** Header file for implementation of MD5 **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
+ ** Revised (for MD5): RLR 4/27/91 **
+ ** -- G modified to have y&~z instead of y&z **
+ ** -- FF, GG, HH modified to add in last register done **
+ ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
+ ** -- distinct additive constant for each step **
+ ** -- round 4 added, working mod 7 **
+ ***********************************************************************
+*/
+
+/*
+ ***********************************************************************
+ ** Message-digest routines: **
+ ** To form the message digest for a message M **
+ ** (1) Initialize a context buffer mdContext using MD5Init **
+ ** (2) Call MD5Update on mdContext and M **
+ ** (3) Call MD5Final on mdContext **
+ ** The message digest is now in mdContext->digest[0...15] **
+ ***********************************************************************
+*/
+
+#ifndef _SDL_test_md5_h
+#define _SDL_test_md5_h
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ------------ Definitions --------- */
+
+/* typedef a 32-bit type */
+ typedef unsigned long int MD5UINT4;
+
+/* Data structure for MD5 (Message-Digest) computation */
+ typedef struct {
+ MD5UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
+ MD5UINT4 buf[4]; /* scratch buffer */
+ unsigned char in[64]; /* input buffer */
+ unsigned char digest[16]; /* actual digest after Md5Final call */
+ } SDLTest_Md5Context;
+
+/* ---------- Function Prototypes ------------- */
+
+/**
+ * \brief initialize the context
+ *
+ * \param mdContext pointer to context variable
+ *
+ * Note: The function initializes the message-digest context
+ * mdContext. Call before each new use of the context -
+ * all fields are set to zero.
+ */
+ void SDLTest_Md5Init(SDLTest_Md5Context * mdContext);
+
+
+/**
+ * \brief update digest from variable length data
+ *
+ * \param mdContext pointer to context variable
+ * \param inBuf pointer to data array/string
+ * \param inLen length of data array/string
+ *
+ * Note: The function updates the message-digest context to account
+ * for the presence of each of the characters inBuf[0..inLen-1]
+ * in the message whose digest is being computed.
+*/
+
+ void SDLTest_Md5Update(SDLTest_Md5Context * mdContext, unsigned char *inBuf,
+ unsigned int inLen);
+
+
+/**
+ * \brief complete digest computation
+ *
+ * \param mdContext pointer to context variable
+ *
+ * Note: The function terminates the message-digest computation and
+ * ends with the desired message digest in mdContext.digest[0..15].
+ * Always call before using the digest[] variable.
+*/
+
+ void SDLTest_Md5Final(SDLTest_Md5Context * mdContext);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_md5_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_test_random.h b/external/SDL2/include/SDL_test_random.h
new file mode 100644
index 0000000..91c3652
--- /dev/null
+++ b/external/SDL2/include/SDL_test_random.h
@@ -0,0 +1,115 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_test_random.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+/*
+
+ A "32-bit Multiply with carry random number generator. Very fast.
+ Includes a list of recommended multipliers.
+
+ multiply-with-carry generator: x(n) = a*x(n-1) + carry mod 2^32.
+ period: (a*2^31)-1
+
+*/
+
+#ifndef _SDL_test_random_h
+#define _SDL_test_random_h
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* --- Definitions */
+
+/*
+ * Macros that return a random number in a specific format.
+ */
+#define SDLTest_RandomInt(c) ((int)SDLTest_Random(c))
+
+/*
+ * Context structure for the random number generator state.
+ */
+ typedef struct {
+ unsigned int a;
+ unsigned int x;
+ unsigned int c;
+ unsigned int ah;
+ unsigned int al;
+ } SDLTest_RandomContext;
+
+
+/* --- Function prototypes */
+
+/**
+ * \brief Initialize random number generator with two integers.
+ *
+ * Note: The random sequence of numbers returned by ...Random() is the
+ * same for the same two integers and has a period of 2^31.
+ *
+ * \param rndContext pointer to context structure
+ * \param xi integer that defines the random sequence
+ * \param ci integer that defines the random sequence
+ *
+ */
+ void SDLTest_RandomInit(SDLTest_RandomContext * rndContext, unsigned int xi,
+ unsigned int ci);
+
+/**
+ * \brief Initialize random number generator based on current system time.
+ *
+ * \param rndContext pointer to context structure
+ *
+ */
+ void SDLTest_RandomInitTime(SDLTest_RandomContext *rndContext);
+
+
+/**
+ * \brief Initialize random number generator based on current system time.
+ *
+ * Note: ...RandomInit() or ...RandomInitTime() must have been called
+ * before using this function.
+ *
+ * \param rndContext pointer to context structure
+ *
+ * \returns A random number (32bit unsigned integer)
+ *
+ */
+ unsigned int SDLTest_Random(SDLTest_RandomContext *rndContext);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_test_random_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_thread.h b/external/SDL2/include/SDL_thread.h
new file mode 100644
index 0000000..377e6c7
--- /dev/null
+++ b/external/SDL2/include/SDL_thread.h
@@ -0,0 +1,287 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_thread_h
+#define _SDL_thread_h
+
+/**
+ * \file SDL_thread.h
+ *
+ * Header for the SDL thread management routines.
+ */
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+/* Thread synchronization primitives */
+#include "SDL_atomic.h"
+#include "SDL_mutex.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The SDL thread structure, defined in SDL_thread.c */
+struct SDL_Thread;
+typedef struct SDL_Thread SDL_Thread;
+
+/* The SDL thread ID */
+typedef unsigned long SDL_threadID;
+
+/* Thread local storage ID, 0 is the invalid ID */
+typedef unsigned int SDL_TLSID;
+
+/**
+ * The SDL thread priority.
+ *
+ * \note On many systems you require special privileges to set high priority.
+ */
+typedef enum {
+ SDL_THREAD_PRIORITY_LOW,
+ SDL_THREAD_PRIORITY_NORMAL,
+ SDL_THREAD_PRIORITY_HIGH
+} SDL_ThreadPriority;
+
+/**
+ * The function passed to SDL_CreateThread().
+ * It is passed a void* user context parameter and returns an int.
+ */
+typedef int (SDLCALL * SDL_ThreadFunction) (void *data);
+
+#if defined(__WIN32__) && !defined(HAVE_LIBC)
+/**
+ * \file SDL_thread.h
+ *
+ * We compile SDL into a DLL. This means, that it's the DLL which
+ * creates a new thread for the calling process with the SDL_CreateThread()
+ * API. There is a problem with this, that only the RTL of the SDL.DLL will
+ * be initialized for those threads, and not the RTL of the calling
+ * application!
+ *
+ * To solve this, we make a little hack here.
+ *
+ * We'll always use the caller's _beginthread() and _endthread() APIs to
+ * start a new thread. This way, if it's the SDL.DLL which uses this API,
+ * then the RTL of SDL.DLL will be used to create the new thread, and if it's
+ * the application, then the RTL of the application will be used.
+ *
+ * So, in short:
+ * Always use the _beginthread() and _endthread() of the calling runtime
+ * library!
+ */
+#define SDL_PASSED_BEGINTHREAD_ENDTHREAD
+#include <process.h> /* This has _beginthread() and _endthread() defined! */
+
+typedef uintptr_t(__cdecl * pfnSDL_CurrentBeginThread) (void *, unsigned,
+ unsigned (__stdcall *
+ func) (void
+ *),
+ void *arg, unsigned,
+ unsigned *threadID);
+typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code);
+
+/**
+ * Create a thread.
+ */
+extern DECLSPEC SDL_Thread *SDLCALL
+SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
+ pfnSDL_CurrentBeginThread pfnBeginThread,
+ pfnSDL_CurrentEndThread pfnEndThread);
+
+/**
+ * Create a thread.
+ */
+#if defined(SDL_CreateThread) && SDL_DYNAMIC_API
+#undef SDL_CreateThread
+#define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
+#else
+#define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
+#endif
+
+#else
+
+/**
+ * Create a thread.
+ *
+ * Thread naming is a little complicated: Most systems have very small
+ * limits for the string length (Haiku has 32 bytes, Linux currently has 16,
+ * Visual C++ 6.0 has nine!), and possibly other arbitrary rules. You'll
+ * have to see what happens with your system's debugger. The name should be
+ * UTF-8 (but using the naming limits of C identifiers is a better bet).
+ * There are no requirements for thread naming conventions, so long as the
+ * string is null-terminated UTF-8, but these guidelines are helpful in
+ * choosing a name:
+ *
+ * http://stackoverflow.com/questions/149932/naming-conventions-for-threads
+ *
+ * If a system imposes requirements, SDL will try to munge the string for
+ * it (truncate, etc), but the original string contents will be available
+ * from SDL_GetThreadName().
+ */
+extern DECLSPEC SDL_Thread *SDLCALL
+SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data);
+
+#endif
+
+/**
+ * Get the thread name, as it was specified in SDL_CreateThread().
+ * This function returns a pointer to a UTF-8 string that names the
+ * specified thread, or NULL if it doesn't have a name. This is internal
+ * memory, not to be free()'d by the caller, and remains valid until the
+ * specified thread is cleaned up by SDL_WaitThread().
+ */
+extern DECLSPEC const char *SDLCALL SDL_GetThreadName(SDL_Thread *thread);
+
+/**
+ * Get the thread identifier for the current thread.
+ */
+extern DECLSPEC SDL_threadID SDLCALL SDL_ThreadID(void);
+
+/**
+ * Get the thread identifier for the specified thread.
+ *
+ * Equivalent to SDL_ThreadID() if the specified thread is NULL.
+ */
+extern DECLSPEC SDL_threadID SDLCALL SDL_GetThreadID(SDL_Thread * thread);
+
+/**
+ * Set the priority for the current thread
+ */
+extern DECLSPEC int SDLCALL SDL_SetThreadPriority(SDL_ThreadPriority priority);
+
+/**
+ * Wait for a thread to finish. Threads that haven't been detached will
+ * remain (as a "zombie") until this function cleans them up. Not doing so
+ * is a resource leak.
+ *
+ * Once a thread has been cleaned up through this function, the SDL_Thread
+ * that references it becomes invalid and should not be referenced again.
+ * As such, only one thread may call SDL_WaitThread() on another.
+ *
+ * The return code for the thread function is placed in the area
+ * pointed to by \c status, if \c status is not NULL.
+ *
+ * You may not wait on a thread that has been used in a call to
+ * SDL_DetachThread(). Use either that function or this one, but not
+ * both, or behavior is undefined.
+ *
+ * It is safe to pass NULL to this function; it is a no-op.
+ */
+extern DECLSPEC void SDLCALL SDL_WaitThread(SDL_Thread * thread, int *status);
+
+/**
+ * A thread may be "detached" to signify that it should not remain until
+ * another thread has called SDL_WaitThread() on it. Detaching a thread
+ * is useful for long-running threads that nothing needs to synchronize
+ * with or further manage. When a detached thread is done, it simply
+ * goes away.
+ *
+ * There is no way to recover the return code of a detached thread. If you
+ * need this, don't detach the thread and instead use SDL_WaitThread().
+ *
+ * Once a thread is detached, you should usually assume the SDL_Thread isn't
+ * safe to reference again, as it will become invalid immediately upon
+ * the detached thread's exit, instead of remaining until someone has called
+ * SDL_WaitThread() to finally clean it up. As such, don't detach the same
+ * thread more than once.
+ *
+ * If a thread has already exited when passed to SDL_DetachThread(), it will
+ * stop waiting for a call to SDL_WaitThread() and clean up immediately.
+ * It is not safe to detach a thread that might be used with SDL_WaitThread().
+ *
+ * You may not call SDL_WaitThread() on a thread that has been detached.
+ * Use either that function or this one, but not both, or behavior is
+ * undefined.
+ *
+ * It is safe to pass NULL to this function; it is a no-op.
+ */
+extern DECLSPEC void SDLCALL SDL_DetachThread(SDL_Thread * thread);
+
+/**
+ * \brief Create an identifier that is globally visible to all threads but refers to data that is thread-specific.
+ *
+ * \return The newly created thread local storage identifier, or 0 on error
+ *
+ * \code
+ * static SDL_SpinLock tls_lock;
+ * static SDL_TLSID thread_local_storage;
+ *
+ * void SetMyThreadData(void *value)
+ * {
+ * if (!thread_local_storage) {
+ * SDL_AtomicLock(&tls_lock);
+ * if (!thread_local_storage) {
+ * thread_local_storage = SDL_TLSCreate();
+ * }
+ * SDL_AtomicUnlock(&tls_lock);
+ * }
+ * SDL_TLSSet(thread_local_storage, value, 0);
+ * }
+ *
+ * void *GetMyThreadData(void)
+ * {
+ * return SDL_TLSGet(thread_local_storage);
+ * }
+ * \endcode
+ *
+ * \sa SDL_TLSGet()
+ * \sa SDL_TLSSet()
+ */
+extern DECLSPEC SDL_TLSID SDLCALL SDL_TLSCreate(void);
+
+/**
+ * \brief Get the value associated with a thread local storage ID for the current thread.
+ *
+ * \param id The thread local storage ID
+ *
+ * \return The value associated with the ID for the current thread, or NULL if no value has been set.
+ *
+ * \sa SDL_TLSCreate()
+ * \sa SDL_TLSSet()
+ */
+extern DECLSPEC void * SDLCALL SDL_TLSGet(SDL_TLSID id);
+
+/**
+ * \brief Set the value associated with a thread local storage ID for the current thread.
+ *
+ * \param id The thread local storage ID
+ * \param value The value to associate with the ID for the current thread
+ * \param destructor A function called when the thread exits, to free the value.
+ *
+ * \return 0 on success, -1 on error
+ *
+ * \sa SDL_TLSCreate()
+ * \sa SDL_TLSGet()
+ */
+extern DECLSPEC int SDLCALL SDL_TLSSet(SDL_TLSID id, const void *value, void (*destructor)(void*));
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_thread_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_timer.h b/external/SDL2/include/SDL_timer.h
new file mode 100644
index 0000000..e0d3785
--- /dev/null
+++ b/external/SDL2/include/SDL_timer.h
@@ -0,0 +1,115 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+#ifndef _SDL_timer_h
+#define _SDL_timer_h
+
+/**
+ * \file SDL_timer.h
+ *
+ * Header for the SDL time management routines.
+ */
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Get the number of milliseconds since the SDL library initialization.
+ *
+ * \note This value wraps if the program runs for more than ~49 days.
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_GetTicks(void);
+
+/**
+ * \brief Compare SDL ticks values, and return true if A has passed B
+ *
+ * e.g. if you want to wait 100 ms, you could do this:
+ * Uint32 timeout = SDL_GetTicks() + 100;
+ * while (!SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
+ * ... do work until timeout has elapsed
+ * }
+ */
+#define SDL_TICKS_PASSED(A, B) ((Sint32)((B) - (A)) <= 0)
+
+/**
+ * \brief Get the current value of the high resolution counter
+ */
+extern DECLSPEC Uint64 SDLCALL SDL_GetPerformanceCounter(void);
+
+/**
+ * \brief Get the count per second of the high resolution counter
+ */
+extern DECLSPEC Uint64 SDLCALL SDL_GetPerformanceFrequency(void);
+
+/**
+ * \brief Wait a specified number of milliseconds before returning.
+ */
+extern DECLSPEC void SDLCALL SDL_Delay(Uint32 ms);
+
+/**
+ * Function prototype for the timer callback function.
+ *
+ * The callback function is passed the current timer interval and returns
+ * the next timer interval. If the returned value is the same as the one
+ * passed in, the periodic alarm continues, otherwise a new alarm is
+ * scheduled. If the callback returns 0, the periodic alarm is cancelled.
+ */
+typedef Uint32 (SDLCALL * SDL_TimerCallback) (Uint32 interval, void *param);
+
+/**
+ * Definition of the timer ID type.
+ */
+typedef int SDL_TimerID;
+
+/**
+ * \brief Add a new timer to the pool of timers already running.
+ *
+ * \return A timer ID, or 0 when an error occurs.
+ */
+extern DECLSPEC SDL_TimerID SDLCALL SDL_AddTimer(Uint32 interval,
+ SDL_TimerCallback callback,
+ void *param);
+
+/**
+ * \brief Remove a timer knowing its ID.
+ *
+ * \return A boolean value indicating success or failure.
+ *
+ * \warning It is not safe to remove a timer multiple times.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_RemoveTimer(SDL_TimerID id);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_timer_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_touch.h b/external/SDL2/include/SDL_touch.h
new file mode 100644
index 0000000..2643e36
--- /dev/null
+++ b/external/SDL2/include/SDL_touch.h
@@ -0,0 +1,86 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_touch.h
+ *
+ * Include file for SDL touch event handling.
+ */
+
+#ifndef _SDL_touch_h
+#define _SDL_touch_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_video.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef Sint64 SDL_TouchID;
+typedef Sint64 SDL_FingerID;
+
+typedef struct SDL_Finger
+{
+ SDL_FingerID id;
+ float x;
+ float y;
+ float pressure;
+} SDL_Finger;
+
+/* Used as the device ID for mouse events simulated with touch input */
+#define SDL_TOUCH_MOUSEID ((Uint32)-1)
+
+
+/* Function prototypes */
+
+/**
+ * \brief Get the number of registered touch devices.
+ */
+extern DECLSPEC int SDLCALL SDL_GetNumTouchDevices(void);
+
+/**
+ * \brief Get the touch ID with the given index, or 0 if the index is invalid.
+ */
+extern DECLSPEC SDL_TouchID SDLCALL SDL_GetTouchDevice(int index);
+
+/**
+ * \brief Get the number of active fingers for a given touch device.
+ */
+extern DECLSPEC int SDLCALL SDL_GetNumTouchFingers(SDL_TouchID touchID);
+
+/**
+ * \brief Get the finger object of the given touch, with the given index.
+ */
+extern DECLSPEC SDL_Finger * SDLCALL SDL_GetTouchFinger(SDL_TouchID touchID, int index);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_touch_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_types.h b/external/SDL2/include/SDL_types.h
new file mode 100644
index 0000000..5118af2
--- /dev/null
+++ b/external/SDL2/include/SDL_types.h
@@ -0,0 +1,29 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_types.h
+ *
+ * \deprecated
+ */
+
+/* DEPRECATED */
+#include "SDL_stdinc.h"
diff --git a/external/SDL2/include/SDL_version.h b/external/SDL2/include/SDL_version.h
new file mode 100644
index 0000000..de1f160
--- /dev/null
+++ b/external/SDL2/include/SDL_version.h
@@ -0,0 +1,162 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_version.h
+ *
+ * This header defines the current SDL version.
+ */
+
+#ifndef _SDL_version_h
+#define _SDL_version_h
+
+#include "SDL_stdinc.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Information the version of SDL in use.
+ *
+ * Represents the library's version as three levels: major revision
+ * (increments with massive changes, additions, and enhancements),
+ * minor revision (increments with backwards-compatible changes to the
+ * major revision), and patchlevel (increments with fixes to the minor
+ * revision).
+ *
+ * \sa SDL_VERSION
+ * \sa SDL_GetVersion
+ */
+typedef struct SDL_version
+{
+ Uint8 major; /**< major version */
+ Uint8 minor; /**< minor version */
+ Uint8 patch; /**< update version */
+} SDL_version;
+
+/* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
+*/
+#define SDL_MAJOR_VERSION 2
+#define SDL_MINOR_VERSION 0
+#define SDL_PATCHLEVEL 4
+
+/**
+ * \brief Macro to determine SDL version program was compiled against.
+ *
+ * This macro fills in a SDL_version structure with the version of the
+ * library you compiled against. This is determined by what header the
+ * compiler uses. Note that if you dynamically linked the library, you might
+ * have a slightly newer or older version at runtime. That version can be
+ * determined with SDL_GetVersion(), which, unlike SDL_VERSION(),
+ * is not a macro.
+ *
+ * \param x A pointer to a SDL_version struct to initialize.
+ *
+ * \sa SDL_version
+ * \sa SDL_GetVersion
+ */
+#define SDL_VERSION(x) \
+{ \
+ (x)->major = SDL_MAJOR_VERSION; \
+ (x)->minor = SDL_MINOR_VERSION; \
+ (x)->patch = SDL_PATCHLEVEL; \
+}
+
+/**
+ * This macro turns the version numbers into a numeric value:
+ * \verbatim
+ (1,2,3) -> (1203)
+ \endverbatim
+ *
+ * This assumes that there will never be more than 100 patchlevels.
+ */
+#define SDL_VERSIONNUM(X, Y, Z) \
+ ((X)*1000 + (Y)*100 + (Z))
+
+/**
+ * This is the version number macro for the current SDL version.
+ */
+#define SDL_COMPILEDVERSION \
+ SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL)
+
+/**
+ * This macro will evaluate to true if compiled with SDL at least X.Y.Z.
+ */
+#define SDL_VERSION_ATLEAST(X, Y, Z) \
+ (SDL_COMPILEDVERSION >= SDL_VERSIONNUM(X, Y, Z))
+
+/**
+ * \brief Get the version of SDL that is linked against your program.
+ *
+ * If you are linking to SDL dynamically, then it is possible that the
+ * current version will be different than the version you compiled against.
+ * This function returns the current version, while SDL_VERSION() is a
+ * macro that tells you what version you compiled with.
+ *
+ * \code
+ * SDL_version compiled;
+ * SDL_version linked;
+ *
+ * SDL_VERSION(&compiled);
+ * SDL_GetVersion(&linked);
+ * printf("We compiled against SDL version %d.%d.%d ...\n",
+ * compiled.major, compiled.minor, compiled.patch);
+ * printf("But we linked against SDL version %d.%d.%d.\n",
+ * linked.major, linked.minor, linked.patch);
+ * \endcode
+ *
+ * This function may be called safely at any time, even before SDL_Init().
+ *
+ * \sa SDL_VERSION
+ */
+extern DECLSPEC void SDLCALL SDL_GetVersion(SDL_version * ver);
+
+/**
+ * \brief Get the code revision of SDL that is linked against your program.
+ *
+ * Returns an arbitrary string (a hash value) uniquely identifying the
+ * exact revision of the SDL library in use, and is only useful in comparing
+ * against other revisions. It is NOT an incrementing number.
+ */
+extern DECLSPEC const char *SDLCALL SDL_GetRevision(void);
+
+/**
+ * \brief Get the revision number of SDL that is linked against your program.
+ *
+ * Returns a number uniquely identifying the exact revision of the SDL
+ * library in use. It is an incrementing number based on commits to
+ * hg.libsdl.org.
+ */
+extern DECLSPEC int SDLCALL SDL_GetRevisionNumber(void);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_version_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/SDL_video.h b/external/SDL2/include/SDL_video.h
new file mode 100644
index 0000000..52dbbc7
--- /dev/null
+++ b/external/SDL2/include/SDL_video.h
@@ -0,0 +1,1103 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file SDL_video.h
+ *
+ * Header file for SDL video functions.
+ */
+
+#ifndef _SDL_video_h
+#define _SDL_video_h
+
+#include "SDL_stdinc.h"
+#include "SDL_pixels.h"
+#include "SDL_rect.h"
+#include "SDL_surface.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief The structure that defines a display mode
+ *
+ * \sa SDL_GetNumDisplayModes()
+ * \sa SDL_GetDisplayMode()
+ * \sa SDL_GetDesktopDisplayMode()
+ * \sa SDL_GetCurrentDisplayMode()
+ * \sa SDL_GetClosestDisplayMode()
+ * \sa SDL_SetWindowDisplayMode()
+ * \sa SDL_GetWindowDisplayMode()
+ */
+typedef struct
+{
+ Uint32 format; /**< pixel format */
+ int w; /**< width, in screen coordinates */
+ int h; /**< height, in screen coordinates */
+ int refresh_rate; /**< refresh rate (or zero for unspecified) */
+ void *driverdata; /**< driver-specific data, initialize to 0 */
+} SDL_DisplayMode;
+
+/**
+ * \brief The type used to identify a window
+ *
+ * \sa SDL_CreateWindow()
+ * \sa SDL_CreateWindowFrom()
+ * \sa SDL_DestroyWindow()
+ * \sa SDL_GetWindowData()
+ * \sa SDL_GetWindowFlags()
+ * \sa SDL_GetWindowGrab()
+ * \sa SDL_GetWindowPosition()
+ * \sa SDL_GetWindowSize()
+ * \sa SDL_GetWindowTitle()
+ * \sa SDL_HideWindow()
+ * \sa SDL_MaximizeWindow()
+ * \sa SDL_MinimizeWindow()
+ * \sa SDL_RaiseWindow()
+ * \sa SDL_RestoreWindow()
+ * \sa SDL_SetWindowData()
+ * \sa SDL_SetWindowFullscreen()
+ * \sa SDL_SetWindowGrab()
+ * \sa SDL_SetWindowIcon()
+ * \sa SDL_SetWindowPosition()
+ * \sa SDL_SetWindowSize()
+ * \sa SDL_SetWindowBordered()
+ * \sa SDL_SetWindowTitle()
+ * \sa SDL_ShowWindow()
+ */
+typedef struct SDL_Window SDL_Window;
+
+/**
+ * \brief The flags on a window
+ *
+ * \sa SDL_GetWindowFlags()
+ */
+typedef enum
+{
+ SDL_WINDOW_FULLSCREEN = 0x00000001, /**< fullscreen window */
+ SDL_WINDOW_OPENGL = 0x00000002, /**< window usable with OpenGL context */
+ SDL_WINDOW_SHOWN = 0x00000004, /**< window is visible */
+ SDL_WINDOW_HIDDEN = 0x00000008, /**< window is not visible */
+ SDL_WINDOW_BORDERLESS = 0x00000010, /**< no window decoration */
+ SDL_WINDOW_RESIZABLE = 0x00000020, /**< window can be resized */
+ SDL_WINDOW_MINIMIZED = 0x00000040, /**< window is minimized */
+ SDL_WINDOW_MAXIMIZED = 0x00000080, /**< window is maximized */
+ SDL_WINDOW_INPUT_GRABBED = 0x00000100, /**< window has grabbed input focus */
+ SDL_WINDOW_INPUT_FOCUS = 0x00000200, /**< window has input focus */
+ SDL_WINDOW_MOUSE_FOCUS = 0x00000400, /**< window has mouse focus */
+ SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),
+ SDL_WINDOW_FOREIGN = 0x00000800, /**< window not created by SDL */
+ SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000, /**< window should be created in high-DPI mode if supported */
+ SDL_WINDOW_MOUSE_CAPTURE = 0x00004000 /**< window has mouse captured (unrelated to INPUT_GRABBED) */
+} SDL_WindowFlags;
+
+/**
+ * \brief Used to indicate that you don't care what the window position is.
+ */
+#define SDL_WINDOWPOS_UNDEFINED_MASK 0x1FFF0000
+#define SDL_WINDOWPOS_UNDEFINED_DISPLAY(X) (SDL_WINDOWPOS_UNDEFINED_MASK|(X))
+#define SDL_WINDOWPOS_UNDEFINED SDL_WINDOWPOS_UNDEFINED_DISPLAY(0)
+#define SDL_WINDOWPOS_ISUNDEFINED(X) \
+ (((X)&0xFFFF0000) == SDL_WINDOWPOS_UNDEFINED_MASK)
+
+/**
+ * \brief Used to indicate that the window position should be centered.
+ */
+#define SDL_WINDOWPOS_CENTERED_MASK 0x2FFF0000
+#define SDL_WINDOWPOS_CENTERED_DISPLAY(X) (SDL_WINDOWPOS_CENTERED_MASK|(X))
+#define SDL_WINDOWPOS_CENTERED SDL_WINDOWPOS_CENTERED_DISPLAY(0)
+#define SDL_WINDOWPOS_ISCENTERED(X) \
+ (((X)&0xFFFF0000) == SDL_WINDOWPOS_CENTERED_MASK)
+
+/**
+ * \brief Event subtype for window events
+ */
+typedef enum
+{
+ SDL_WINDOWEVENT_NONE, /**< Never used */
+ SDL_WINDOWEVENT_SHOWN, /**< Window has been shown */
+ SDL_WINDOWEVENT_HIDDEN, /**< Window has been hidden */
+ SDL_WINDOWEVENT_EXPOSED, /**< Window has been exposed and should be
+ redrawn */
+ SDL_WINDOWEVENT_MOVED, /**< Window has been moved to data1, data2
+ */
+ SDL_WINDOWEVENT_RESIZED, /**< Window has been resized to data1xdata2 */
+ SDL_WINDOWEVENT_SIZE_CHANGED, /**< The window size has changed, either as
+ a result of an API call or through the
+ system or user changing the window size. */
+ SDL_WINDOWEVENT_MINIMIZED, /**< Window has been minimized */
+ SDL_WINDOWEVENT_MAXIMIZED, /**< Window has been maximized */
+ SDL_WINDOWEVENT_RESTORED, /**< Window has been restored to normal size
+ and position */
+ SDL_WINDOWEVENT_ENTER, /**< Window has gained mouse focus */
+ SDL_WINDOWEVENT_LEAVE, /**< Window has lost mouse focus */
+ SDL_WINDOWEVENT_FOCUS_GAINED, /**< Window has gained keyboard focus */
+ SDL_WINDOWEVENT_FOCUS_LOST, /**< Window has lost keyboard focus */
+ SDL_WINDOWEVENT_CLOSE /**< The window manager requests that the
+ window be closed */
+} SDL_WindowEventID;
+
+/**
+ * \brief An opaque handle to an OpenGL context.
+ */
+typedef void *SDL_GLContext;
+
+/**
+ * \brief OpenGL configuration attributes
+ */
+typedef enum
+{
+ SDL_GL_RED_SIZE,
+ SDL_GL_GREEN_SIZE,
+ SDL_GL_BLUE_SIZE,
+ SDL_GL_ALPHA_SIZE,
+ SDL_GL_BUFFER_SIZE,
+ SDL_GL_DOUBLEBUFFER,
+ SDL_GL_DEPTH_SIZE,
+ SDL_GL_STENCIL_SIZE,
+ SDL_GL_ACCUM_RED_SIZE,
+ SDL_GL_ACCUM_GREEN_SIZE,
+ SDL_GL_ACCUM_BLUE_SIZE,
+ SDL_GL_ACCUM_ALPHA_SIZE,
+ SDL_GL_STEREO,
+ SDL_GL_MULTISAMPLEBUFFERS,
+ SDL_GL_MULTISAMPLESAMPLES,
+ SDL_GL_ACCELERATED_VISUAL,
+ SDL_GL_RETAINED_BACKING,
+ SDL_GL_CONTEXT_MAJOR_VERSION,
+ SDL_GL_CONTEXT_MINOR_VERSION,
+ SDL_GL_CONTEXT_EGL,
+ SDL_GL_CONTEXT_FLAGS,
+ SDL_GL_CONTEXT_PROFILE_MASK,
+ SDL_GL_SHARE_WITH_CURRENT_CONTEXT,
+ SDL_GL_FRAMEBUFFER_SRGB_CAPABLE,
+ SDL_GL_CONTEXT_RELEASE_BEHAVIOR
+} SDL_GLattr;
+
+typedef enum
+{
+ SDL_GL_CONTEXT_PROFILE_CORE = 0x0001,
+ SDL_GL_CONTEXT_PROFILE_COMPATIBILITY = 0x0002,
+ SDL_GL_CONTEXT_PROFILE_ES = 0x0004 /* GLX_CONTEXT_ES2_PROFILE_BIT_EXT */
+} SDL_GLprofile;
+
+typedef enum
+{
+ SDL_GL_CONTEXT_DEBUG_FLAG = 0x0001,
+ SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG = 0x0002,
+ SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG = 0x0004,
+ SDL_GL_CONTEXT_RESET_ISOLATION_FLAG = 0x0008
+} SDL_GLcontextFlag;
+
+typedef enum
+{
+ SDL_GL_CONTEXT_RELEASE_BEHAVIOR_NONE = 0x0000,
+ SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH = 0x0001
+} SDL_GLcontextReleaseFlag;
+
+
+/* Function prototypes */
+
+/**
+ * \brief Get the number of video drivers compiled into SDL
+ *
+ * \sa SDL_GetVideoDriver()
+ */
+extern DECLSPEC int SDLCALL SDL_GetNumVideoDrivers(void);
+
+/**
+ * \brief Get the name of a built in video driver.
+ *
+ * \note The video drivers are presented in the order in which they are
+ * normally checked during initialization.
+ *
+ * \sa SDL_GetNumVideoDrivers()
+ */
+extern DECLSPEC const char *SDLCALL SDL_GetVideoDriver(int index);
+
+/**
+ * \brief Initialize the video subsystem, optionally specifying a video driver.
+ *
+ * \param driver_name Initialize a specific driver by name, or NULL for the
+ * default video driver.
+ *
+ * \return 0 on success, -1 on error
+ *
+ * This function initializes the video subsystem; setting up a connection
+ * to the window manager, etc, and determines the available display modes
+ * and pixel formats, but does not initialize a window or graphics mode.
+ *
+ * \sa SDL_VideoQuit()
+ */
+extern DECLSPEC int SDLCALL SDL_VideoInit(const char *driver_name);
+
+/**
+ * \brief Shuts down the video subsystem.
+ *
+ * This function closes all windows, and restores the original video mode.
+ *
+ * \sa SDL_VideoInit()
+ */
+extern DECLSPEC void SDLCALL SDL_VideoQuit(void);
+
+/**
+ * \brief Returns the name of the currently initialized video driver.
+ *
+ * \return The name of the current video driver or NULL if no driver
+ * has been initialized
+ *
+ * \sa SDL_GetNumVideoDrivers()
+ * \sa SDL_GetVideoDriver()
+ */
+extern DECLSPEC const char *SDLCALL SDL_GetCurrentVideoDriver(void);
+
+/**
+ * \brief Returns the number of available video displays.
+ *
+ * \sa SDL_GetDisplayBounds()
+ */
+extern DECLSPEC int SDLCALL SDL_GetNumVideoDisplays(void);
+
+/**
+ * \brief Get the name of a display in UTF-8 encoding
+ *
+ * \return The name of a display, or NULL for an invalid display index.
+ *
+ * \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC const char * SDLCALL SDL_GetDisplayName(int displayIndex);
+
+/**
+ * \brief Get the desktop area represented by a display, with the primary
+ * display located at 0,0
+ *
+ * \return 0 on success, or -1 if the index is out of range.
+ *
+ * \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC int SDLCALL SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect);
+
+/**
+ * \brief Get the dots/pixels-per-inch for a display
+ *
+ * \note Diagonal, horizontal and vertical DPI can all be optionally
+ * returned if the parameter is non-NULL.
+ *
+ * \return 0 on success, or -1 if no DPI information is available or the index is out of range.
+ *
+ * \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
+
+/**
+ * \brief Returns the number of available display modes.
+ *
+ * \sa SDL_GetDisplayMode()
+ */
+extern DECLSPEC int SDLCALL SDL_GetNumDisplayModes(int displayIndex);
+
+/**
+ * \brief Fill in information about a specific display mode.
+ *
+ * \note The display modes are sorted in this priority:
+ * \li bits per pixel -> more colors to fewer colors
+ * \li width -> largest to smallest
+ * \li height -> largest to smallest
+ * \li refresh rate -> highest to lowest
+ *
+ * \sa SDL_GetNumDisplayModes()
+ */
+extern DECLSPEC int SDLCALL SDL_GetDisplayMode(int displayIndex, int modeIndex,
+ SDL_DisplayMode * mode);
+
+/**
+ * \brief Fill in information about the desktop display mode.
+ */
+extern DECLSPEC int SDLCALL SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode);
+
+/**
+ * \brief Fill in information about the current display mode.
+ */
+extern DECLSPEC int SDLCALL SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode);
+
+
+/**
+ * \brief Get the closest match to the requested display mode.
+ *
+ * \param displayIndex The index of display from which mode should be queried.
+ * \param mode The desired display mode
+ * \param closest A pointer to a display mode to be filled in with the closest
+ * match of the available display modes.
+ *
+ * \return The passed in value \c closest, or NULL if no matching video mode
+ * was available.
+ *
+ * The available display modes are scanned, and \c closest is filled in with the
+ * closest mode matching the requested mode and returned. The mode format and
+ * refresh_rate default to the desktop mode if they are 0. The modes are
+ * scanned with size being first priority, format being second priority, and
+ * finally checking the refresh_rate. If all the available modes are too
+ * small, then NULL is returned.
+ *
+ * \sa SDL_GetNumDisplayModes()
+ * \sa SDL_GetDisplayMode()
+ */
+extern DECLSPEC SDL_DisplayMode * SDLCALL SDL_GetClosestDisplayMode(int displayIndex, const SDL_DisplayMode * mode, SDL_DisplayMode * closest);
+
+/**
+ * \brief Get the display index associated with a window.
+ *
+ * \return the display index of the display containing the center of the
+ * window, or -1 on error.
+ */
+extern DECLSPEC int SDLCALL SDL_GetWindowDisplayIndex(SDL_Window * window);
+
+/**
+ * \brief Set the display mode used when a fullscreen window is visible.
+ *
+ * By default the window's dimensions and the desktop format and refresh rate
+ * are used.
+ *
+ * \param window The window for which the display mode should be set.
+ * \param mode The mode to use, or NULL for the default mode.
+ *
+ * \return 0 on success, or -1 if setting the display mode failed.
+ *
+ * \sa SDL_GetWindowDisplayMode()
+ * \sa SDL_SetWindowFullscreen()
+ */
+extern DECLSPEC int SDLCALL SDL_SetWindowDisplayMode(SDL_Window * window,
+ const SDL_DisplayMode
+ * mode);
+
+/**
+ * \brief Fill in information about the display mode used when a fullscreen
+ * window is visible.
+ *
+ * \sa SDL_SetWindowDisplayMode()
+ * \sa SDL_SetWindowFullscreen()
+ */
+extern DECLSPEC int SDLCALL SDL_GetWindowDisplayMode(SDL_Window * window,
+ SDL_DisplayMode * mode);
+
+/**
+ * \brief Get the pixel format associated with the window.
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_GetWindowPixelFormat(SDL_Window * window);
+
+/**
+ * \brief Create a window with the specified position, dimensions, and flags.
+ *
+ * \param title The title of the window, in UTF-8 encoding.
+ * \param x The x position of the window, ::SDL_WINDOWPOS_CENTERED, or
+ * ::SDL_WINDOWPOS_UNDEFINED.
+ * \param y The y position of the window, ::SDL_WINDOWPOS_CENTERED, or
+ * ::SDL_WINDOWPOS_UNDEFINED.
+ * \param w The width of the window, in screen coordinates.
+ * \param h The height of the window, in screen coordinates.
+ * \param flags The flags for the window, a mask of any of the following:
+ * ::SDL_WINDOW_FULLSCREEN, ::SDL_WINDOW_OPENGL,
+ * ::SDL_WINDOW_HIDDEN, ::SDL_WINDOW_BORDERLESS,
+ * ::SDL_WINDOW_RESIZABLE, ::SDL_WINDOW_MAXIMIZED,
+ * ::SDL_WINDOW_MINIMIZED, ::SDL_WINDOW_INPUT_GRABBED,
+ * ::SDL_WINDOW_ALLOW_HIGHDPI.
+ *
+ * \return The id of the window created, or zero if window creation failed.
+ *
+ * If the window is created with the SDL_WINDOW_ALLOW_HIGHDPI flag, its size
+ * in pixels may differ from its size in screen coordinates on platforms with
+ * high-DPI support (e.g. iOS and Mac OS X). Use SDL_GetWindowSize() to query
+ * the client area's size in screen coordinates, and SDL_GL_GetDrawableSize()
+ * or SDL_GetRendererOutputSize() to query the drawable size in pixels.
+ *
+ * \sa SDL_DestroyWindow()
+ */
+extern DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title,
+ int x, int y, int w,
+ int h, Uint32 flags);
+
+/**
+ * \brief Create an SDL window from an existing native window.
+ *
+ * \param data A pointer to driver-dependent window creation data
+ *
+ * \return The id of the window created, or zero if window creation failed.
+ *
+ * \sa SDL_DestroyWindow()
+ */
+extern DECLSPEC SDL_Window * SDLCALL SDL_CreateWindowFrom(const void *data);
+
+/**
+ * \brief Get the numeric ID of a window, for logging purposes.
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_GetWindowID(SDL_Window * window);
+
+/**
+ * \brief Get a window from a stored ID, or NULL if it doesn't exist.
+ */
+extern DECLSPEC SDL_Window * SDLCALL SDL_GetWindowFromID(Uint32 id);
+
+/**
+ * \brief Get the window flags.
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_GetWindowFlags(SDL_Window * window);
+
+/**
+ * \brief Set the title of a window, in UTF-8 format.
+ *
+ * \sa SDL_GetWindowTitle()
+ */
+extern DECLSPEC void SDLCALL SDL_SetWindowTitle(SDL_Window * window,
+ const char *title);
+
+/**
+ * \brief Get the title of a window, in UTF-8 format.
+ *
+ * \sa SDL_SetWindowTitle()
+ */
+extern DECLSPEC const char *SDLCALL SDL_GetWindowTitle(SDL_Window * window);
+
+/**
+ * \brief Set the icon for a window.
+ *
+ * \param window The window for which the icon should be set.
+ * \param icon The icon for the window.
+ */
+extern DECLSPEC void SDLCALL SDL_SetWindowIcon(SDL_Window * window,
+ SDL_Surface * icon);
+
+/**
+ * \brief Associate an arbitrary named pointer with a window.
+ *
+ * \param window The window to associate with the pointer.
+ * \param name The name of the pointer.
+ * \param userdata The associated pointer.
+ *
+ * \return The previous value associated with 'name'
+ *
+ * \note The name is case-sensitive.
+ *
+ * \sa SDL_GetWindowData()
+ */
+extern DECLSPEC void* SDLCALL SDL_SetWindowData(SDL_Window * window,
+ const char *name,
+ void *userdata);
+
+/**
+ * \brief Retrieve the data pointer associated with a window.
+ *
+ * \param window The window to query.
+ * \param name The name of the pointer.
+ *
+ * \return The value associated with 'name'
+ *
+ * \sa SDL_SetWindowData()
+ */
+extern DECLSPEC void *SDLCALL SDL_GetWindowData(SDL_Window * window,
+ const char *name);
+
+/**
+ * \brief Set the position of a window.
+ *
+ * \param window The window to reposition.
+ * \param x The x coordinate of the window in screen coordinates, or
+ * ::SDL_WINDOWPOS_CENTERED or ::SDL_WINDOWPOS_UNDEFINED.
+ * \param y The y coordinate of the window in screen coordinates, or
+ * ::SDL_WINDOWPOS_CENTERED or ::SDL_WINDOWPOS_UNDEFINED.
+ *
+ * \note The window coordinate origin is the upper left of the display.
+ *
+ * \sa SDL_GetWindowPosition()
+ */
+extern DECLSPEC void SDLCALL SDL_SetWindowPosition(SDL_Window * window,
+ int x, int y);
+
+/**
+ * \brief Get the position of a window.
+ *
+ * \param window The window to query.
+ * \param x Pointer to variable for storing the x position, in screen
+ * coordinates. May be NULL.
+ * \param y Pointer to variable for storing the y position, in screen
+ * coordinates. May be NULL.
+ *
+ * \sa SDL_SetWindowPosition()
+ */
+extern DECLSPEC void SDLCALL SDL_GetWindowPosition(SDL_Window * window,
+ int *x, int *y);
+
+/**
+ * \brief Set the size of a window's client area.
+ *
+ * \param window The window to resize.
+ * \param w The width of the window, in screen coordinates. Must be >0.
+ * \param h The height of the window, in screen coordinates. Must be >0.
+ *
+ * \note You can't change the size of a fullscreen window, it automatically
+ * matches the size of the display mode.
+ *
+ * The window size in screen coordinates may differ from the size in pixels, if
+ * the window was created with SDL_WINDOW_ALLOW_HIGHDPI on a platform with
+ * high-dpi support (e.g. iOS or OS X). Use SDL_GL_GetDrawableSize() or
+ * SDL_GetRendererOutputSize() to get the real client area size in pixels.
+ *
+ * \sa SDL_GetWindowSize()
+ */
+extern DECLSPEC void SDLCALL SDL_SetWindowSize(SDL_Window * window, int w,
+ int h);
+
+/**
+ * \brief Get the size of a window's client area.
+ *
+ * \param window The window to query.
+ * \param w Pointer to variable for storing the width, in screen
+ * coordinates. May be NULL.
+ * \param h Pointer to variable for storing the height, in screen
+ * coordinates. May be NULL.
+ *
+ * The window size in screen coordinates may differ from the size in pixels, if
+ * the window was created with SDL_WINDOW_ALLOW_HIGHDPI on a platform with
+ * high-dpi support (e.g. iOS or OS X). Use SDL_GL_GetDrawableSize() or
+ * SDL_GetRendererOutputSize() to get the real client area size in pixels.
+ *
+ * \sa SDL_SetWindowSize()
+ */
+extern DECLSPEC void SDLCALL SDL_GetWindowSize(SDL_Window * window, int *w,
+ int *h);
+
+/**
+ * \brief Set the minimum size of a window's client area.
+ *
+ * \param window The window to set a new minimum size.
+ * \param min_w The minimum width of the window, must be >0
+ * \param min_h The minimum height of the window, must be >0
+ *
+ * \note You can't change the minimum size of a fullscreen window, it
+ * automatically matches the size of the display mode.
+ *
+ * \sa SDL_GetWindowMinimumSize()
+ * \sa SDL_SetWindowMaximumSize()
+ */
+extern DECLSPEC void SDLCALL SDL_SetWindowMinimumSize(SDL_Window * window,
+ int min_w, int min_h);
+
+/**
+ * \brief Get the minimum size of a window's client area.
+ *
+ * \param window The window to query.
+ * \param w Pointer to variable for storing the minimum width, may be NULL
+ * \param h Pointer to variable for storing the minimum height, may be NULL
+ *
+ * \sa SDL_GetWindowMaximumSize()
+ * \sa SDL_SetWindowMinimumSize()
+ */
+extern DECLSPEC void SDLCALL SDL_GetWindowMinimumSize(SDL_Window * window,
+ int *w, int *h);
+
+/**
+ * \brief Set the maximum size of a window's client area.
+ *
+ * \param window The window to set a new maximum size.
+ * \param max_w The maximum width of the window, must be >0
+ * \param max_h The maximum height of the window, must be >0
+ *
+ * \note You can't change the maximum size of a fullscreen window, it
+ * automatically matches the size of the display mode.
+ *
+ * \sa SDL_GetWindowMaximumSize()
+ * \sa SDL_SetWindowMinimumSize()
+ */
+extern DECLSPEC void SDLCALL SDL_SetWindowMaximumSize(SDL_Window * window,
+ int max_w, int max_h);
+
+/**
+ * \brief Get the maximum size of a window's client area.
+ *
+ * \param window The window to query.
+ * \param w Pointer to variable for storing the maximum width, may be NULL
+ * \param h Pointer to variable for storing the maximum height, may be NULL
+ *
+ * \sa SDL_GetWindowMinimumSize()
+ * \sa SDL_SetWindowMaximumSize()
+ */
+extern DECLSPEC void SDLCALL SDL_GetWindowMaximumSize(SDL_Window * window,
+ int *w, int *h);
+
+/**
+ * \brief Set the border state of a window.
+ *
+ * This will add or remove the window's SDL_WINDOW_BORDERLESS flag and
+ * add or remove the border from the actual window. This is a no-op if the
+ * window's border already matches the requested state.
+ *
+ * \param window The window of which to change the border state.
+ * \param bordered SDL_FALSE to remove border, SDL_TRUE to add border.
+ *
+ * \note You can't change the border state of a fullscreen window.
+ *
+ * \sa SDL_GetWindowFlags()
+ */
+extern DECLSPEC void SDLCALL SDL_SetWindowBordered(SDL_Window * window,
+ SDL_bool bordered);
+
+/**
+ * \brief Show a window.
+ *
+ * \sa SDL_HideWindow()
+ */
+extern DECLSPEC void SDLCALL SDL_ShowWindow(SDL_Window * window);
+
+/**
+ * \brief Hide a window.
+ *
+ * \sa SDL_ShowWindow()
+ */
+extern DECLSPEC void SDLCALL SDL_HideWindow(SDL_Window * window);
+
+/**
+ * \brief Raise a window above other windows and set the input focus.
+ */
+extern DECLSPEC void SDLCALL SDL_RaiseWindow(SDL_Window * window);
+
+/**
+ * \brief Make a window as large as possible.
+ *
+ * \sa SDL_RestoreWindow()
+ */
+extern DECLSPEC void SDLCALL SDL_MaximizeWindow(SDL_Window * window);
+
+/**
+ * \brief Minimize a window to an iconic representation.
+ *
+ * \sa SDL_RestoreWindow()
+ */
+extern DECLSPEC void SDLCALL SDL_MinimizeWindow(SDL_Window * window);
+
+/**
+ * \brief Restore the size and position of a minimized or maximized window.
+ *
+ * \sa SDL_MaximizeWindow()
+ * \sa SDL_MinimizeWindow()
+ */
+extern DECLSPEC void SDLCALL SDL_RestoreWindow(SDL_Window * window);
+
+/**
+ * \brief Set a window's fullscreen state.
+ *
+ * \return 0 on success, or -1 if setting the display mode failed.
+ *
+ * \sa SDL_SetWindowDisplayMode()
+ * \sa SDL_GetWindowDisplayMode()
+ */
+extern DECLSPEC int SDLCALL SDL_SetWindowFullscreen(SDL_Window * window,
+ Uint32 flags);
+
+/**
+ * \brief Get the SDL surface associated with the window.
+ *
+ * \return The window's framebuffer surface, or NULL on error.
+ *
+ * A new surface will be created with the optimal format for the window,
+ * if necessary. This surface will be freed when the window is destroyed.
+ *
+ * \note You may not combine this with 3D or the rendering API on this window.
+ *
+ * \sa SDL_UpdateWindowSurface()
+ * \sa SDL_UpdateWindowSurfaceRects()
+ */
+extern DECLSPEC SDL_Surface * SDLCALL SDL_GetWindowSurface(SDL_Window * window);
+
+/**
+ * \brief Copy the window surface to the screen.
+ *
+ * \return 0 on success, or -1 on error.
+ *
+ * \sa SDL_GetWindowSurface()
+ * \sa SDL_UpdateWindowSurfaceRects()
+ */
+extern DECLSPEC int SDLCALL SDL_UpdateWindowSurface(SDL_Window * window);
+
+/**
+ * \brief Copy a number of rectangles on the window surface to the screen.
+ *
+ * \return 0 on success, or -1 on error.
+ *
+ * \sa SDL_GetWindowSurface()
+ * \sa SDL_UpdateWindowSurfaceRect()
+ */
+extern DECLSPEC int SDLCALL SDL_UpdateWindowSurfaceRects(SDL_Window * window,
+ const SDL_Rect * rects,
+ int numrects);
+
+/**
+ * \brief Set a window's input grab mode.
+ *
+ * \param window The window for which the input grab mode should be set.
+ * \param grabbed This is SDL_TRUE to grab input, and SDL_FALSE to release input.
+ *
+ * If the caller enables a grab while another window is currently grabbed,
+ * the other window loses its grab in favor of the caller's window.
+ *
+ * \sa SDL_GetWindowGrab()
+ */
+extern DECLSPEC void SDLCALL SDL_SetWindowGrab(SDL_Window * window,
+ SDL_bool grabbed);
+
+/**
+ * \brief Get a window's input grab mode.
+ *
+ * \return This returns SDL_TRUE if input is grabbed, and SDL_FALSE otherwise.
+ *
+ * \sa SDL_SetWindowGrab()
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_GetWindowGrab(SDL_Window * window);
+
+/**
+ * \brief Get the window that currently has an input grab enabled.
+ *
+ * \return This returns the window if input is grabbed, and NULL otherwise.
+ *
+ * \sa SDL_SetWindowGrab()
+ */
+extern DECLSPEC SDL_Window * SDLCALL SDL_GetGrabbedWindow(void);
+
+/**
+ * \brief Set the brightness (gamma correction) for a window.
+ *
+ * \return 0 on success, or -1 if setting the brightness isn't supported.
+ *
+ * \sa SDL_GetWindowBrightness()
+ * \sa SDL_SetWindowGammaRamp()
+ */
+extern DECLSPEC int SDLCALL SDL_SetWindowBrightness(SDL_Window * window, float brightness);
+
+/**
+ * \brief Get the brightness (gamma correction) for a window.
+ *
+ * \return The last brightness value passed to SDL_SetWindowBrightness()
+ *
+ * \sa SDL_SetWindowBrightness()
+ */
+extern DECLSPEC float SDLCALL SDL_GetWindowBrightness(SDL_Window * window);
+
+/**
+ * \brief Set the gamma ramp for a window.
+ *
+ * \param window The window for which the gamma ramp should be set.
+ * \param red The translation table for the red channel, or NULL.
+ * \param green The translation table for the green channel, or NULL.
+ * \param blue The translation table for the blue channel, or NULL.
+ *
+ * \return 0 on success, or -1 if gamma ramps are unsupported.
+ *
+ * Set the gamma translation table for the red, green, and blue channels
+ * of the video hardware. Each table is an array of 256 16-bit quantities,
+ * representing a mapping between the input and output for that channel.
+ * The input is the index into the array, and the output is the 16-bit
+ * gamma value at that index, scaled to the output color precision.
+ *
+ * \sa SDL_GetWindowGammaRamp()
+ */
+extern DECLSPEC int SDLCALL SDL_SetWindowGammaRamp(SDL_Window * window,
+ const Uint16 * red,
+ const Uint16 * green,
+ const Uint16 * blue);
+
+/**
+ * \brief Get the gamma ramp for a window.
+ *
+ * \param window The window from which the gamma ramp should be queried.
+ * \param red A pointer to a 256 element array of 16-bit quantities to hold
+ * the translation table for the red channel, or NULL.
+ * \param green A pointer to a 256 element array of 16-bit quantities to hold
+ * the translation table for the green channel, or NULL.
+ * \param blue A pointer to a 256 element array of 16-bit quantities to hold
+ * the translation table for the blue channel, or NULL.
+ *
+ * \return 0 on success, or -1 if gamma ramps are unsupported.
+ *
+ * \sa SDL_SetWindowGammaRamp()
+ */
+extern DECLSPEC int SDLCALL SDL_GetWindowGammaRamp(SDL_Window * window,
+ Uint16 * red,
+ Uint16 * green,
+ Uint16 * blue);
+
+/**
+ * \brief Possible return values from the SDL_HitTest callback.
+ *
+ * \sa SDL_HitTest
+ */
+typedef enum
+{
+ SDL_HITTEST_NORMAL, /**< Region is normal. No special properties. */
+ SDL_HITTEST_DRAGGABLE, /**< Region can drag entire window. */
+ SDL_HITTEST_RESIZE_TOPLEFT,
+ SDL_HITTEST_RESIZE_TOP,
+ SDL_HITTEST_RESIZE_TOPRIGHT,
+ SDL_HITTEST_RESIZE_RIGHT,
+ SDL_HITTEST_RESIZE_BOTTOMRIGHT,
+ SDL_HITTEST_RESIZE_BOTTOM,
+ SDL_HITTEST_RESIZE_BOTTOMLEFT,
+ SDL_HITTEST_RESIZE_LEFT
+} SDL_HitTestResult;
+
+/**
+ * \brief Callback used for hit-testing.
+ *
+ * \sa SDL_SetWindowHitTest
+ */
+typedef SDL_HitTestResult (SDLCALL *SDL_HitTest)(SDL_Window *win,
+ const SDL_Point *area,
+ void *data);
+
+/**
+ * \brief Provide a callback that decides if a window region has special properties.
+ *
+ * Normally windows are dragged and resized by decorations provided by the
+ * system window manager (a title bar, borders, etc), but for some apps, it
+ * makes sense to drag them from somewhere else inside the window itself; for
+ * example, one might have a borderless window that wants to be draggable
+ * from any part, or simulate its own title bar, etc.
+ *
+ * This function lets the app provide a callback that designates pieces of
+ * a given window as special. This callback is run during event processing
+ * if we need to tell the OS to treat a region of the window specially; the
+ * use of this callback is known as "hit testing."
+ *
+ * Mouse input may not be delivered to your application if it is within
+ * a special area; the OS will often apply that input to moving the window or
+ * resizing the window and not deliver it to the application.
+ *
+ * Specifying NULL for a callback disables hit-testing. Hit-testing is
+ * disabled by default.
+ *
+ * Platforms that don't support this functionality will return -1
+ * unconditionally, even if you're attempting to disable hit-testing.
+ *
+ * Your callback may fire at any time, and its firing does not indicate any
+ * specific behavior (for example, on Windows, this certainly might fire
+ * when the OS is deciding whether to drag your window, but it fires for lots
+ * of other reasons, too, some unrelated to anything you probably care about
+ * _and when the mouse isn't actually at the location it is testing_).
+ * Since this can fire at any time, you should try to keep your callback
+ * efficient, devoid of allocations, etc.
+ *
+ * \param window The window to set hit-testing on.
+ * \param callback The callback to call when doing a hit-test.
+ * \param callback_data An app-defined void pointer passed to the callback.
+ * \return 0 on success, -1 on error (including unsupported).
+ */
+extern DECLSPEC int SDLCALL SDL_SetWindowHitTest(SDL_Window * window,
+ SDL_HitTest callback,
+ void *callback_data);
+
+/**
+ * \brief Destroy a window.
+ */
+extern DECLSPEC void SDLCALL SDL_DestroyWindow(SDL_Window * window);
+
+
+/**
+ * \brief Returns whether the screensaver is currently enabled (default on).
+ *
+ * \sa SDL_EnableScreenSaver()
+ * \sa SDL_DisableScreenSaver()
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsScreenSaverEnabled(void);
+
+/**
+ * \brief Allow the screen to be blanked by a screensaver
+ *
+ * \sa SDL_IsScreenSaverEnabled()
+ * \sa SDL_DisableScreenSaver()
+ */
+extern DECLSPEC void SDLCALL SDL_EnableScreenSaver(void);
+
+/**
+ * \brief Prevent the screen from being blanked by a screensaver
+ *
+ * \sa SDL_IsScreenSaverEnabled()
+ * \sa SDL_EnableScreenSaver()
+ */
+extern DECLSPEC void SDLCALL SDL_DisableScreenSaver(void);
+
+
+/**
+ * \name OpenGL support functions
+ */
+/* @{ */
+
+/**
+ * \brief Dynamically load an OpenGL library.
+ *
+ * \param path The platform dependent OpenGL library name, or NULL to open the
+ * default OpenGL library.
+ *
+ * \return 0 on success, or -1 if the library couldn't be loaded.
+ *
+ * This should be done after initializing the video driver, but before
+ * creating any OpenGL windows. If no OpenGL library is loaded, the default
+ * library will be loaded upon creation of the first OpenGL window.
+ *
+ * \note If you do this, you need to retrieve all of the GL functions used in
+ * your program from the dynamic library using SDL_GL_GetProcAddress().
+ *
+ * \sa SDL_GL_GetProcAddress()
+ * \sa SDL_GL_UnloadLibrary()
+ */
+extern DECLSPEC int SDLCALL SDL_GL_LoadLibrary(const char *path);
+
+/**
+ * \brief Get the address of an OpenGL function.
+ */
+extern DECLSPEC void *SDLCALL SDL_GL_GetProcAddress(const char *proc);
+
+/**
+ * \brief Unload the OpenGL library previously loaded by SDL_GL_LoadLibrary().
+ *
+ * \sa SDL_GL_LoadLibrary()
+ */
+extern DECLSPEC void SDLCALL SDL_GL_UnloadLibrary(void);
+
+/**
+ * \brief Return true if an OpenGL extension is supported for the current
+ * context.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_GL_ExtensionSupported(const char
+ *extension);
+
+/**
+ * \brief Reset all previously set OpenGL context attributes to their default values
+ */
+extern DECLSPEC void SDLCALL SDL_GL_ResetAttributes(void);
+
+/**
+ * \brief Set an OpenGL window attribute before window creation.
+ */
+extern DECLSPEC int SDLCALL SDL_GL_SetAttribute(SDL_GLattr attr, int value);
+
+/**
+ * \brief Get the actual value for an attribute from the current context.
+ */
+extern DECLSPEC int SDLCALL SDL_GL_GetAttribute(SDL_GLattr attr, int *value);
+
+/**
+ * \brief Create an OpenGL context for use with an OpenGL window, and make it
+ * current.
+ *
+ * \sa SDL_GL_DeleteContext()
+ */
+extern DECLSPEC SDL_GLContext SDLCALL SDL_GL_CreateContext(SDL_Window *
+ window);
+
+/**
+ * \brief Set up an OpenGL context for rendering into an OpenGL window.
+ *
+ * \note The context must have been created with a compatible window.
+ */
+extern DECLSPEC int SDLCALL SDL_GL_MakeCurrent(SDL_Window * window,
+ SDL_GLContext context);
+
+/**
+ * \brief Get the currently active OpenGL window.
+ */
+extern DECLSPEC SDL_Window* SDLCALL SDL_GL_GetCurrentWindow(void);
+
+/**
+ * \brief Get the currently active OpenGL context.
+ */
+extern DECLSPEC SDL_GLContext SDLCALL SDL_GL_GetCurrentContext(void);
+
+/**
+ * \brief Get the size of a window's underlying drawable in pixels (for use
+ * with glViewport).
+ *
+ * \param window Window from which the drawable size should be queried
+ * \param w Pointer to variable for storing the width in pixels, may be NULL
+ * \param h Pointer to variable for storing the height in pixels, may be NULL
+ *
+ * This may differ from SDL_GetWindowSize() if we're rendering to a high-DPI
+ * drawable, i.e. the window was created with SDL_WINDOW_ALLOW_HIGHDPI on a
+ * platform with high-DPI support (Apple calls this "Retina"), and not disabled
+ * by the SDL_HINT_VIDEO_HIGHDPI_DISABLED hint.
+ *
+ * \sa SDL_GetWindowSize()
+ * \sa SDL_CreateWindow()
+ */
+extern DECLSPEC void SDLCALL SDL_GL_GetDrawableSize(SDL_Window * window, int *w,
+ int *h);
+
+/**
+ * \brief Set the swap interval for the current OpenGL context.
+ *
+ * \param interval 0 for immediate updates, 1 for updates synchronized with the
+ * vertical retrace. If the system supports it, you may
+ * specify -1 to allow late swaps to happen immediately
+ * instead of waiting for the next retrace.
+ *
+ * \return 0 on success, or -1 if setting the swap interval is not supported.
+ *
+ * \sa SDL_GL_GetSwapInterval()
+ */
+extern DECLSPEC int SDLCALL SDL_GL_SetSwapInterval(int interval);
+
+/**
+ * \brief Get the swap interval for the current OpenGL context.
+ *
+ * \return 0 if there is no vertical retrace synchronization, 1 if the buffer
+ * swap is synchronized with the vertical retrace, and -1 if late
+ * swaps happen immediately instead of waiting for the next retrace.
+ * If the system can't determine the swap interval, or there isn't a
+ * valid current context, this will return 0 as a safe default.
+ *
+ * \sa SDL_GL_SetSwapInterval()
+ */
+extern DECLSPEC int SDLCALL SDL_GL_GetSwapInterval(void);
+
+/**
+ * \brief Swap the OpenGL buffers for a window, if double-buffering is
+ * supported.
+ */
+extern DECLSPEC void SDLCALL SDL_GL_SwapWindow(SDL_Window * window);
+
+/**
+ * \brief Delete an OpenGL context.
+ *
+ * \sa SDL_GL_CreateContext()
+ */
+extern DECLSPEC void SDLCALL SDL_GL_DeleteContext(SDL_GLContext context);
+
+/* @} *//* OpenGL support functions */
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_video_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/external/SDL2/include/begin_code.h b/external/SDL2/include/begin_code.h
new file mode 100644
index 0000000..04e78c6
--- /dev/null
+++ b/external/SDL2/include/begin_code.h
@@ -0,0 +1,146 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file begin_code.h
+ *
+ * This file sets things up for C dynamic library function definitions,
+ * static inlined functions, and structures aligned at 4-byte alignment.
+ * If you don't like ugly C preprocessor code, don't look at this file. :)
+ */
+
+/* This shouldn't be nested -- included it around code only. */
+#ifdef _begin_code_h
+#error Nested inclusion of begin_code.h
+#endif
+#define _begin_code_h
+
+#ifndef SDL_DEPRECATED
+# if (__GNUC__ >= 4) /* technically, this arrived in gcc 3.1, but oh well. */
+# define SDL_DEPRECATED __attribute__((deprecated))
+# else
+# define SDL_DEPRECATED
+# endif
+#endif
+
+#ifndef SDL_UNUSED
+# ifdef __GNUC__
+# define SDL_UNUSED __attribute__((unused))
+# else
+# define SDL_UNUSED
+# endif
+#endif
+
+/* Some compilers use a special export keyword */
+#ifndef DECLSPEC
+# if defined(__WIN32__) || defined(__WINRT__)
+# ifdef __BORLANDC__
+# ifdef BUILD_SDL
+# define DECLSPEC
+# else
+# define DECLSPEC __declspec(dllimport)
+# endif
+# else
+# define DECLSPEC __declspec(dllexport)
+# endif
+# else
+# if defined(__GNUC__) && __GNUC__ >= 4
+# define DECLSPEC __attribute__ ((visibility("default")))
+# else
+# define DECLSPEC
+# endif
+# endif
+#endif
+
+/* By default SDL uses the C calling convention */
+#ifndef SDLCALL
+#if (defined(__WIN32__) || defined(__WINRT__)) && !defined(__GNUC__)
+#define SDLCALL __cdecl
+#else
+#define SDLCALL
+#endif
+#endif /* SDLCALL */
+
+/* Removed DECLSPEC on Symbian OS because SDL cannot be a DLL in EPOC */
+#ifdef __SYMBIAN32__
+#undef DECLSPEC
+#define DECLSPEC
+#endif /* __SYMBIAN32__ */
+
+/* Force structure packing at 4 byte alignment.
+ This is necessary if the header is included in code which has structure
+ packing set to an alternate value, say for loading structures from disk.
+ The packing is reset to the previous value in close_code.h
+ */
+#if defined(_MSC_VER) || defined(__MWERKS__) || defined(__BORLANDC__)
+#ifdef _MSC_VER
+#pragma warning(disable: 4103)
+#endif
+#ifdef __BORLANDC__
+#pragma nopackwarning
+#endif
+#ifdef _M_X64
+/* Use 8-byte alignment on 64-bit architectures, so pointers are aligned */
+#pragma pack(push,8)
+#else
+#pragma pack(push,4)
+#endif
+#endif /* Compiler needs structure packing set */
+
+#ifndef SDL_INLINE
+#if defined(__GNUC__)
+#define SDL_INLINE __inline__
+#elif defined(_MSC_VER) || defined(__BORLANDC__) || \
+ defined(__DMC__) || defined(__SC__) || \
+ defined(__WATCOMC__) || defined(__LCC__) || \
+ defined(__DECC)
+#define SDL_INLINE __inline
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#else
+#define SDL_INLINE inline
+#ifndef __inline__
+#define __inline__ inline
+#endif
+#endif
+#endif /* SDL_INLINE not defined */
+
+#ifndef SDL_FORCE_INLINE
+#if defined(_MSC_VER)
+#define SDL_FORCE_INLINE __forceinline
+#elif ( (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) )
+#define SDL_FORCE_INLINE __attribute__((always_inline)) static __inline__
+#else
+#define SDL_FORCE_INLINE static SDL_INLINE
+#endif
+#endif /* SDL_FORCE_INLINE not defined */
+
+/* Apparently this is needed by several Windows compilers */
+#if !defined(__MACH__)
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif /* NULL */
+#endif /* ! Mac OS X - breaks precompiled headers */
diff --git a/external/SDL2/include/close_code.h b/external/SDL2/include/close_code.h
new file mode 100644
index 0000000..d908b00
--- /dev/null
+++ b/external/SDL2/include/close_code.h
@@ -0,0 +1,37 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+*/
+
+/**
+ * \file close_code.h
+ *
+ * This file reverses the effects of begin_code.h and should be included
+ * after you finish any function and structure declarations in your headers
+ */
+
+#undef _begin_code_h
+
+/* Reset structure packing at previous byte alignment */
+#if defined(_MSC_VER) || defined(__MWERKS__) || defined(__WATCOMC__) || defined(__BORLANDC__)
+#ifdef __BORLANDC__
+#pragma nopackwarning
+#endif
+#pragma pack(pop)
+#endif /* Compiler needs structure packing set */
diff --git a/external/SDL2/libs/Darwin/libSDL2-2.0.0.dylib b/external/SDL2/libs/Darwin/libSDL2-2.0.0.dylib
new file mode 100644
index 0000000..a14c323
--- /dev/null
+++ b/external/SDL2/libs/Darwin/libSDL2-2.0.0.dylib
Binary files differ
diff --git a/external/SDL2/libs/Darwin/libSDL2main.a b/external/SDL2/libs/Darwin/libSDL2main.a
new file mode 100644
index 0000000..4364d15
--- /dev/null
+++ b/external/SDL2/libs/Darwin/libSDL2main.a
Binary files differ
diff --git a/external/jpeg-8c/CMakeLists.txt b/external/jpeg-8c/CMakeLists.txt
new file mode 100644
index 0000000..ab26be3
--- /dev/null
+++ b/external/jpeg-8c/CMakeLists.txt
@@ -0,0 +1,60 @@
+add_library (
+ jpeg-8c STATIC
+ jaricom.c
+ jcapimin.c
+ jcapistd.c
+ jcarith.c
+ jccoefct.c
+ jccolor.c
+ jcdctmgr.c
+ jchuff.c
+ jcinit.c
+ jcmainct.c
+ jcmarker.c
+ jcmaster.c
+ jcomapi.c
+ jconfig.h
+ jcparam.c
+ jcprepct.c
+ jcsample.c
+ jctrans.c
+ jdapimin.c
+ jdapistd.c
+ jdarith.c
+ jdatadst.c
+ jdatasrc.c
+ jdcoefct.c
+ jdcolor.c
+ jdct.h
+ jddctmgr.c
+ jdhuff.c
+ jdinput.c
+ jdmainct.c
+ jdmarker.c
+ jdmaster.c
+ jdmerge.c
+ jdpostct.c
+ jdsample.c
+ jdtrans.c
+ jerror.c
+ jerror.h
+ jfdctflt.c
+ jfdctfst.c
+ jfdctint.c
+ jidctflt.c
+ jidctfst.c
+ jidctint.c
+ jinclude.h
+ jmemmgr.c
+ jmemnobs.c
+ jmemsys.h
+ jmorecfg.h
+ jpegint.h
+ jpeglib.h
+ jquant1.c
+ jquant2.c
+ jutils.c
+ jversion.h
+)
+
+set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11" )
diff --git a/external/jpeg-8c/README b/external/jpeg-8c/README
new file mode 100644
index 0000000..451265d
--- /dev/null
+++ b/external/jpeg-8c/README
@@ -0,0 +1,326 @@
+The Independent JPEG Group's JPEG software
+==========================================
+
+README for release 8c of 16-Jan-2011
+====================================
+
+This distribution contains the eighth public release of the Independent JPEG
+Group's free JPEG software. You are welcome to redistribute this software and
+to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
+
+This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,
+Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,
+Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,
+and other members of the Independent JPEG Group.
+
+IJG is not affiliated with the official ISO JPEG standards committee.
+
+
+DOCUMENTATION ROADMAP
+=====================
+
+This file contains the following sections:
+
+OVERVIEW General description of JPEG and the IJG software.
+LEGAL ISSUES Copyright, lack of warranty, terms of distribution.
+REFERENCES Where to learn more about JPEG.
+ARCHIVE LOCATIONS Where to find newer versions of this software.
+ACKNOWLEDGMENTS Special thanks.
+FILE FORMAT WARS Software *not* to get.
+TO DO Plans for future IJG releases.
+
+Other documentation files in the distribution are:
+
+User documentation:
+ install.txt How to configure and install the IJG software.
+ usage.txt Usage instructions for cjpeg, djpeg, jpegtran,
+ rdjpgcom, and wrjpgcom.
+ *.1 Unix-style man pages for programs (same info as usage.txt).
+ wizard.txt Advanced usage instructions for JPEG wizards only.
+ change.log Version-to-version change highlights.
+Programmer and internal documentation:
+ libjpeg.txt How to use the JPEG library in your own programs.
+ example.c Sample code for calling the JPEG library.
+ structure.txt Overview of the JPEG library's internal structure.
+ filelist.txt Road map of IJG files.
+ coderules.txt Coding style rules --- please read if you contribute code.
+
+Please read at least the files install.txt and usage.txt. Some information
+can also be found in the JPEG FAQ (Frequently Asked Questions) article. See
+ARCHIVE LOCATIONS below to find out where to obtain the FAQ article.
+
+If you want to understand how the JPEG code works, we suggest reading one or
+more of the REFERENCES, then looking at the documentation files (in roughly
+the order listed) before diving into the code.
+
+
+OVERVIEW
+========
+
+This package contains C software to implement JPEG image encoding, decoding,
+and transcoding. JPEG (pronounced "jay-peg") is a standardized compression
+method for full-color and gray-scale images.
+
+This software implements JPEG baseline, extended-sequential, and progressive
+compression processes. Provision is made for supporting all variants of these
+processes, although some uncommon parameter settings aren't implemented yet.
+We have made no provision for supporting the hierarchical or lossless
+processes defined in the standard.
+
+We provide a set of library routines for reading and writing JPEG image files,
+plus two sample applications "cjpeg" and "djpeg", which use the library to
+perform conversion between JPEG and some other popular image file formats.
+The library is intended to be reused in other applications.
+
+In order to support file conversion and viewing software, we have included
+considerable functionality beyond the bare JPEG coding/decoding capability;
+for example, the color quantization modules are not strictly part of JPEG
+decoding, but they are essential for output to colormapped file formats or
+colormapped displays. These extra functions can be compiled out of the
+library if not required for a particular application.
+
+We have also included "jpegtran", a utility for lossless transcoding between
+different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple
+applications for inserting and extracting textual comments in JFIF files.
+
+The emphasis in designing this software has been on achieving portability and
+flexibility, while also making it fast enough to be useful. In particular,
+the software is not intended to be read as a tutorial on JPEG. (See the
+REFERENCES section for introductory material.) Rather, it is intended to
+be reliable, portable, industrial-strength code. We do not claim to have
+achieved that goal in every aspect of the software, but we strive for it.
+
+We welcome the use of this software as a component of commercial products.
+No royalty is required, but we do ask for an acknowledgement in product
+documentation, as described under LEGAL ISSUES.
+
+
+LEGAL ISSUES
+============
+
+In plain English:
+
+1. We don't promise that this software works. (But if you find any bugs,
+ please let us know!)
+2. You can use this software for whatever you want. You don't have to pay us.
+3. You may not pretend that you wrote this software. If you use it in a
+ program, you must acknowledge somewhere in your documentation that
+ you've used the IJG code.
+
+In legalese:
+
+The authors make NO WARRANTY or representation, either express or implied,
+with respect to this software, its quality, accuracy, merchantability, or
+fitness for a particular purpose. This software is provided "AS IS", and you,
+its user, assume the entire risk as to its quality and accuracy.
+
+This software is copyright (C) 1991-2011, Thomas G. Lane, Guido Vollbeding.
+All Rights Reserved except as specified below.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+software (or portions thereof) for any purpose, without fee, subject to these
+conditions:
+(1) If any part of the source code for this software is distributed, then this
+README file must be included, with this copyright and no-warranty notice
+unaltered; and any additions, deletions, or changes to the original files
+must be clearly indicated in accompanying documentation.
+(2) If only executable code is distributed, then the accompanying
+documentation must state that "this software is based in part on the work of
+the Independent JPEG Group".
+(3) Permission for use of this software is granted only if the user accepts
+full responsibility for any undesirable consequences; the authors accept
+NO LIABILITY for damages of any kind.
+
+These conditions apply to any software derived from or based on the IJG code,
+not just to the unmodified library. If you use our work, you ought to
+acknowledge us.
+
+Permission is NOT granted for the use of any IJG author's name or company name
+in advertising or publicity relating to this software or products derived from
+it. This software may be referred to only as "the Independent JPEG Group's
+software".
+
+We specifically permit and encourage the use of this software as the basis of
+commercial products, provided that all warranty or liability claims are
+assumed by the product vendor.
+
+
+ansi2knr.c is included in this distribution by permission of L. Peter Deutsch,
+sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA.
+ansi2knr.c is NOT covered by the above copyright and conditions, but instead
+by the usual distribution terms of the Free Software Foundation; principally,
+that you must include source code if you redistribute it. (See the file
+ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part
+of any program generated from the IJG code, this does not limit you more than
+the foregoing paragraphs do.
+
+The Unix configuration script "configure" was produced with GNU Autoconf.
+It is copyright by the Free Software Foundation but is freely distributable.
+The same holds for its supporting scripts (config.guess, config.sub,
+ltmain.sh). Another support script, install-sh, is copyright by X Consortium
+but is also freely distributable.
+
+The IJG distribution formerly included code to read and write GIF files.
+To avoid entanglement with the Unisys LZW patent, GIF reading support has
+been removed altogether, and the GIF writer has been simplified to produce
+"uncompressed GIFs". This technique does not use the LZW algorithm; the
+resulting GIF files are larger than usual, but are readable by all standard
+GIF decoders.
+
+We are required to state that
+ "The Graphics Interchange Format(c) is the Copyright property of
+ CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ CompuServe Incorporated."
+
+
+REFERENCES
+==========
+
+We recommend reading one or more of these references before trying to
+understand the innards of the JPEG software.
+
+The best short technical introduction to the JPEG compression algorithm is
+ Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+ Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
+(Adjacent articles in that issue discuss MPEG motion picture compression,
+applications of JPEG, and related topics.) If you don't have the CACM issue
+handy, a PostScript file containing a revised version of Wallace's article is
+available at http://www.ijg.org/files/wallace.ps.gz. The file (actually
+a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
+omits the sample images that appeared in CACM, but it includes corrections
+and some added material. Note: the Wallace article is copyright ACM and IEEE,
+and it may not be used for commercial purposes.
+
+A somewhat less technical, more leisurely introduction to JPEG can be found in
+"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by
+M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides
+good explanations and example C code for a multitude of compression methods
+including JPEG. It is an excellent source if you are comfortable reading C
+code but don't know much about data compression in general. The book's JPEG
+sample code is far from industrial-strength, but when you are ready to look
+at a full implementation, you've got one here...
+
+The best currently available description of JPEG is the textbook "JPEG Still
+Image Data Compression Standard" by William B. Pennebaker and Joan L.
+Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.
+Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG
+standards (DIS 10918-1 and draft DIS 10918-2).
+Although this is by far the most detailed and comprehensive exposition of
+JPEG publicly available, we point out that it is still missing an explanation
+of the most essential properties and algorithms of the underlying DCT
+technology.
+If you think that you know about DCT-based JPEG after reading this book,
+then you are in delusion. The real fundamentals and corresponding potential
+of DCT-based JPEG are not publicly known so far, and that is the reason for
+all the mistaken developments taking place in the image coding domain.
+
+The original JPEG standard is divided into two parts, Part 1 being the actual
+specification, while Part 2 covers compliance testing methods. Part 1 is
+titled "Digital Compression and Coding of Continuous-tone Still Images,
+Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
+10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of
+Continuous-tone Still Images, Part 2: Compliance testing" and has document
+numbers ISO/IEC IS 10918-2, ITU-T T.83.
+IJG JPEG 8 introduces an implementation of the JPEG SmartScale extension
+which is specified in a contributed document at ITU and ISO with title "ITU-T
+JPEG-Plus Proposal for Extending ITU-T T.81 for Advanced Image Coding", April
+2006, Geneva, Switzerland. The latest version of the document is Revision 3.
+
+The JPEG standard does not specify all details of an interchangeable file
+format. For the omitted details we follow the "JFIF" conventions, revision
+1.02. JFIF 1.02 has been adopted as an Ecma International Technical Report
+and thus received a formal publication status. It is available as a free
+download in PDF format from
+http://www.ecma-international.org/publications/techreports/E-TR-098.htm.
+A PostScript version of the JFIF document is available at
+http://www.ijg.org/files/jfif.ps.gz. There is also a plain text version at
+http://www.ijg.org/files/jfif.txt.gz, but it is missing the figures.
+
+The TIFF 6.0 file format specification can be obtained by FTP from
+ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme
+found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.
+IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).
+Instead, we recommend the JPEG design proposed by TIFF Technical Note #2
+(Compression tag 7). Copies of this Note can be obtained from
+http://www.ijg.org/files/. It is expected that the next revision
+of the TIFF spec will replace the 6.0 JPEG design with the Note's design.
+Although IJG's own code does not support TIFF/JPEG, the free libtiff library
+uses our library to implement TIFF/JPEG per the Note.
+
+
+ARCHIVE LOCATIONS
+=================
+
+The "official" archive site for this software is www.ijg.org.
+The most recent released version can always be found there in
+directory "files". This particular version will be archived as
+http://www.ijg.org/files/jpegsrc.v8c.tar.gz, and in Windows-compatible
+"zip" archive format as http://www.ijg.org/files/jpegsr8c.zip.
+
+The JPEG FAQ (Frequently Asked Questions) article is a source of some
+general information about JPEG.
+It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/
+and other news.answers archive sites, including the official news.answers
+archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/.
+If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu
+with body
+ send usenet/news.answers/jpeg-faq/part1
+ send usenet/news.answers/jpeg-faq/part2
+
+
+ACKNOWLEDGMENTS
+===============
+
+Thank to Juergen Bruder for providing me with a copy of the common DCT
+algorithm article, only to find out that I had come to the same result
+in a more direct and comprehensible way with a more generative approach.
+
+Thank to Istvan Sebestyen and Joan L. Mitchell for inviting me to the
+ITU JPEG (Study Group 16) meeting in Geneva, Switzerland.
+
+Thank to Thomas Wiegand and Gary Sullivan for inviting me to the
+Joint Video Team (MPEG & ITU) meeting in Geneva, Switzerland.
+
+Thank to John Korejwa and Massimo Ballerini for inviting me to
+fruitful consultations in Boston, MA and Milan, Italy.
+
+Thank to Hendrik Elstner, Roland Fassauer, Simone Zuck, Guenther
+Maier-Gerber, Walter Stoeber, Fred Schmitz, and Norbert Braunagel
+for corresponding business development.
+
+Thank to Nico Zschach and Dirk Stelling of the technical support team
+at the Digital Images company in Halle for providing me with extra
+equipment for configuration tests.
+
+Thank to Richard F. Lyon (then of Foveon Inc.) for fruitful
+communication about JPEG configuration in Sigma Photo Pro software.
+
+Thank to Andrew Finkenstadt for hosting the ijg.org site.
+
+Last but not least special thank to Thomas G. Lane for the original
+design and development of this singular software package.
+
+
+FILE FORMAT WARS
+================
+
+The ISO JPEG standards committee actually promotes different formats like
+"JPEG 2000" or "JPEG XR" which are incompatible with original DCT-based
+JPEG and which are based on faulty technologies. IJG therefore does not
+and will not support such momentary mistakes (see REFERENCES).
+We have little or no sympathy for the promotion of these formats. Indeed,
+one of the original reasons for developing this free software was to help
+force convergence on common, interoperable format standards for JPEG files.
+Don't use an incompatible file format!
+(In any case, our decoder will remain capable of reading existing JPEG
+image files indefinitely.)
+
+
+TO DO
+=====
+
+Version 8 is the first release of a new generation JPEG standard
+to overcome the limitations of the original JPEG specification.
+More features are being prepared for coming releases...
+
+Please send bug reports, offers of help, etc. to jpeg-info@uc.ag.
diff --git a/external/jpeg-8c/ioquake3-changes.diff b/external/jpeg-8c/ioquake3-changes.diff
new file mode 100644
index 0000000..f3a89f1
--- /dev/null
+++ b/external/jpeg-8c/ioquake3-changes.diff
@@ -0,0 +1,683 @@
+As required by the libjpeg license, additions, deletions and changes to
+the original files are listed here. Files noted as "Only in jpeg-8c"
+were deleted; files noted as "Only in ioquake3/code/jpeg-8c" were added.
+
+To regenerate this file, replace everything after "------" with the output
+of this command: diff -ru jpeg-8c ioquake3/code/jpeg-8c
+
+------
+
+Only in jpeg-8c: aclocal.m4
+Only in jpeg-8c: ansi2knr.1
+Only in jpeg-8c: ansi2knr.c
+Only in jpeg-8c: cderror.h
+Only in jpeg-8c: cdjpeg.c
+Only in jpeg-8c: cdjpeg.h
+Only in jpeg-8c: change.log
+Only in jpeg-8c: cjpeg.1
+Only in jpeg-8c: cjpeg.c
+Only in jpeg-8c: ckconfig.c
+Only in jpeg-8c: coderules.txt
+Only in jpeg-8c: config.guess
+Only in jpeg-8c: config.sub
+Only in jpeg-8c: configure
+Only in jpeg-8c: configure.ac
+Only in jpeg-8c: depcomp
+Only in jpeg-8c: djpeg.1
+Only in jpeg-8c: djpeg.c
+Only in jpeg-8c: example.c
+Only in jpeg-8c: filelist.txt
+Only in jpeg-8c: install-sh
+Only in jpeg-8c: install.txt
+diff -ru jpeg-8c/jcmainct.c ioquake3/code/jpeg-8c/jcmainct.c
+--- jpeg-8c/jcmainct.c 2003-10-19 18:55:34.000000000 +0100
++++ ioquake3/code/jpeg-8c/jcmainct.c 2011-11-25 11:24:52.000000000 +0000
+@@ -68,32 +68,32 @@
+ METHODDEF(void)
+ start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+ {
+- my_main_ptr main = (my_main_ptr) cinfo->main;
++ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+
+ /* Do nothing in raw-data mode. */
+ if (cinfo->raw_data_in)
+ return;
+
+- main->cur_iMCU_row = 0; /* initialize counters */
+- main->rowgroup_ctr = 0;
+- main->suspended = FALSE;
+- main->pass_mode = pass_mode; /* save mode for use by process_data */
++ main_ptr->cur_iMCU_row = 0; /* initialize counters */
++ main_ptr->rowgroup_ctr = 0;
++ main_ptr->suspended = FALSE;
++ main_ptr->pass_mode = pass_mode; /* save mode for use by process_data */
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ #ifdef FULL_MAIN_BUFFER_SUPPORTED
+- if (main->whole_image[0] != NULL)
++ if (main_ptr->whole_image[0] != NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ #endif
+- main->pub.process_data = process_data_simple_main;
++ main_ptr->pub.process_data = process_data_simple_main;
+ break;
+ #ifdef FULL_MAIN_BUFFER_SUPPORTED
+ case JBUF_SAVE_SOURCE:
+ case JBUF_CRANK_DEST:
+ case JBUF_SAVE_AND_PASS:
+- if (main->whole_image[0] == NULL)
++ if (main_ptr->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+- main->pub.process_data = process_data_buffer_main;
++ main_ptr->pub.process_data = process_data_buffer_main;
+ break;
+ #endif
+ default:
+@@ -114,46 +114,46 @@
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail)
+ {
+- my_main_ptr main = (my_main_ptr) cinfo->main;
++ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+
+- while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
++ while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
+ /* Read input data if we haven't filled the main buffer yet */
+- if (main->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size)
++ if (main_ptr->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size)
+ (*cinfo->prep->pre_process_data) (cinfo,
+ input_buf, in_row_ctr, in_rows_avail,
+- main->buffer, &main->rowgroup_ctr,
++ main_ptr->buffer, &main_ptr->rowgroup_ctr,
+ (JDIMENSION) cinfo->min_DCT_v_scaled_size);
+
+ /* If we don't have a full iMCU row buffered, return to application for
+ * more data. Note that preprocessor will always pad to fill the iMCU row
+ * at the bottom of the image.
+ */
+- if (main->rowgroup_ctr != (JDIMENSION) cinfo->min_DCT_v_scaled_size)
++ if (main_ptr->rowgroup_ctr != (JDIMENSION) cinfo->min_DCT_v_scaled_size)
+ return;
+
+ /* Send the completed row to the compressor */
+- if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
++ if (! (*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
+ /* If compressor did not consume the whole row, then we must need to
+ * suspend processing and return to the application. In this situation
+ * we pretend we didn't yet consume the last input row; otherwise, if
+ * it happened to be the last row of the image, the application would
+ * think we were done.
+ */
+- if (! main->suspended) {
++ if (! main_ptr->suspended) {
+ (*in_row_ctr)--;
+- main->suspended = TRUE;
++ main_ptr->suspended = TRUE;
+ }
+ return;
+ }
+ /* We did finish the row. Undo our little suspension hack if a previous
+ * call suspended; then mark the main buffer empty.
+ */
+- if (main->suspended) {
++ if (main_ptr->suspended) {
+ (*in_row_ctr)++;
+- main->suspended = FALSE;
++ main_ptr->suspended = FALSE;
+ }
+- main->rowgroup_ctr = 0;
+- main->cur_iMCU_row++;
++ main_ptr->rowgroup_ctr = 0;
++ main_ptr->cur_iMCU_row++;
+ }
+ }
+
+@@ -170,25 +170,25 @@
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail)
+ {
+- my_main_ptr main = (my_main_ptr) cinfo->main;
++ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ int ci;
+ jpeg_component_info *compptr;
+- boolean writing = (main->pass_mode != JBUF_CRANK_DEST);
++ boolean writing = (main_ptr->pass_mode != JBUF_CRANK_DEST);
+
+- while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
++ while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
+ /* Realign the virtual buffers if at the start of an iMCU row. */
+- if (main->rowgroup_ctr == 0) {
++ if (main_ptr->rowgroup_ctr == 0) {
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+- main->buffer[ci] = (*cinfo->mem->access_virt_sarray)
+- ((j_common_ptr) cinfo, main->whole_image[ci],
+- main->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
++ main_ptr->buffer[ci] = (*cinfo->mem->access_virt_sarray)
++ ((j_common_ptr) cinfo, main_ptr->whole_image[ci],
++ main_ptr->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
+ (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing);
+ }
+ /* In a read pass, pretend we just read some source data. */
+ if (! writing) {
+ *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE;
+- main->rowgroup_ctr = DCTSIZE;
++ main_ptr->rowgroup_ctr = DCTSIZE;
+ }
+ }
+
+@@ -197,40 +197,40 @@
+ if (writing) {
+ (*cinfo->prep->pre_process_data) (cinfo,
+ input_buf, in_row_ctr, in_rows_avail,
+- main->buffer, &main->rowgroup_ctr,
++ main_ptr->buffer, &main_ptr->rowgroup_ctr,
+ (JDIMENSION) DCTSIZE);
+ /* Return to application if we need more data to fill the iMCU row. */
+- if (main->rowgroup_ctr < DCTSIZE)
++ if (main_ptr->rowgroup_ctr < DCTSIZE)
+ return;
+ }
+
+ /* Emit data, unless this is a sink-only pass. */
+- if (main->pass_mode != JBUF_SAVE_SOURCE) {
+- if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
++ if (main_ptr->pass_mode != JBUF_SAVE_SOURCE) {
++ if (! (*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
+ /* If compressor did not consume the whole row, then we must need to
+ * suspend processing and return to the application. In this situation
+ * we pretend we didn't yet consume the last input row; otherwise, if
+ * it happened to be the last row of the image, the application would
+ * think we were done.
+ */
+- if (! main->suspended) {
++ if (! main_ptr->suspended) {
+ (*in_row_ctr)--;
+- main->suspended = TRUE;
++ main_ptr->suspended = TRUE;
+ }
+ return;
+ }
+ /* We did finish the row. Undo our little suspension hack if a previous
+ * call suspended; then mark the main buffer empty.
+ */
+- if (main->suspended) {
++ if (main_ptr->suspended) {
+ (*in_row_ctr)++;
+- main->suspended = FALSE;
++ main_ptr->suspended = FALSE;
+ }
+ }
+
+ /* If get here, we are done with this iMCU row. Mark buffer empty. */
+- main->rowgroup_ctr = 0;
+- main->cur_iMCU_row++;
++ main_ptr->rowgroup_ctr = 0;
++ main_ptr->cur_iMCU_row++;
+ }
+ }
+
+@@ -244,15 +244,15 @@
+ GLOBAL(void)
+ jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+ {
+- my_main_ptr main;
++ my_main_ptr main_ptr;
+ int ci;
+ jpeg_component_info *compptr;
+
+- main = (my_main_ptr)
++ main_ptr = (my_main_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_main_controller));
+- cinfo->main = (struct jpeg_c_main_controller *) main;
+- main->pub.start_pass = start_pass_main;
++ cinfo->main = (struct jpeg_c_main_controller *) main_ptr;
++ main_ptr->pub.start_pass = start_pass_main;
+
+ /* We don't need to create a buffer in raw-data mode. */
+ if (cinfo->raw_data_in)
+@@ -267,7 +267,7 @@
+ /* Note we pad the bottom to a multiple of the iMCU height */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+- main->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
++ main_ptr->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+ (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+@@ -279,12 +279,12 @@
+ #endif
+ } else {
+ #ifdef FULL_MAIN_BUFFER_SUPPORTED
+- main->whole_image[0] = NULL; /* flag for no virtual arrays */
++ main_ptr->whole_image[0] = NULL; /* flag for no virtual arrays */
+ #endif
+ /* Allocate a strip buffer for each component */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+- main->buffer[ci] = (*cinfo->mem->alloc_sarray)
++ main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+ (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size));
+Only in jpeg-8c: jconfig.bcc
+Only in jpeg-8c: jconfig.cfg
+Only in jpeg-8c: jconfig.dj
+Only in ioquake3/code/jpeg-8c: jconfig.h
+Only in jpeg-8c: jconfig.mac
+Only in jpeg-8c: jconfig.manx
+Only in jpeg-8c: jconfig.mc6
+Only in jpeg-8c: jconfig.sas
+Only in jpeg-8c: jconfig.st
+Only in jpeg-8c: jconfig.txt
+Only in jpeg-8c: jconfig.vc
+Only in jpeg-8c: jconfig.vms
+Only in jpeg-8c: jconfig.wat
+diff -ru jpeg-8c/jdmainct.c ioquake3/code/jpeg-8c/jdmainct.c
+--- jpeg-8c/jdmainct.c 2002-02-24 19:07:28.000000000 +0000
++++ ioquake3/code/jpeg-8c/jdmainct.c 2011-11-25 11:24:52.000000000 +0000
+@@ -159,7 +159,7 @@
+ * This is done only once, not once per pass.
+ */
+ {
+- my_main_ptr main = (my_main_ptr) cinfo->main;
++ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ int ci, rgroup;
+ int M = cinfo->min_DCT_v_scaled_size;
+ jpeg_component_info *compptr;
+@@ -168,10 +168,10 @@
+ /* Get top-level space for component array pointers.
+ * We alloc both arrays with one call to save a few cycles.
+ */
+- main->xbuffer[0] = (JSAMPIMAGE)
++ main_ptr->xbuffer[0] = (JSAMPIMAGE)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components * 2 * SIZEOF(JSAMPARRAY));
+- main->xbuffer[1] = main->xbuffer[0] + cinfo->num_components;
++ main_ptr->xbuffer[1] = main_ptr->xbuffer[0] + cinfo->num_components;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+@@ -184,9 +184,9 @@
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW));
+ xbuf += rgroup; /* want one row group at negative offsets */
+- main->xbuffer[0][ci] = xbuf;
++ main_ptr->xbuffer[0][ci] = xbuf;
+ xbuf += rgroup * (M + 4);
+- main->xbuffer[1][ci] = xbuf;
++ main_ptr->xbuffer[1][ci] = xbuf;
+ }
+ }
+
+@@ -194,13 +194,13 @@
+ LOCAL(void)
+ make_funny_pointers (j_decompress_ptr cinfo)
+ /* Create the funny pointer lists discussed in the comments above.
+- * The actual workspace is already allocated (in main->buffer),
++ * The actual workspace is already allocated (in main_ptr->buffer),
+ * and the space for the pointer lists is allocated too.
+ * This routine just fills in the curiously ordered lists.
+ * This will be repeated at the beginning of each pass.
+ */
+ {
+- my_main_ptr main = (my_main_ptr) cinfo->main;
++ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup;
+ int M = cinfo->min_DCT_v_scaled_size;
+ jpeg_component_info *compptr;
+@@ -210,10 +210,10 @@
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+- xbuf0 = main->xbuffer[0][ci];
+- xbuf1 = main->xbuffer[1][ci];
++ xbuf0 = main_ptr->xbuffer[0][ci];
++ xbuf1 = main_ptr->xbuffer[1][ci];
+ /* First copy the workspace pointers as-is */
+- buf = main->buffer[ci];
++ buf = main_ptr->buffer[ci];
+ for (i = 0; i < rgroup * (M + 2); i++) {
+ xbuf0[i] = xbuf1[i] = buf[i];
+ }
+@@ -240,7 +240,7 @@
+ * This changes the pointer list state from top-of-image to the normal state.
+ */
+ {
+- my_main_ptr main = (my_main_ptr) cinfo->main;
++ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup;
+ int M = cinfo->min_DCT_v_scaled_size;
+ jpeg_component_info *compptr;
+@@ -250,8 +250,8 @@
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+- xbuf0 = main->xbuffer[0][ci];
+- xbuf1 = main->xbuffer[1][ci];
++ xbuf0 = main_ptr->xbuffer[0][ci];
++ xbuf1 = main_ptr->xbuffer[1][ci];
+ for (i = 0; i < rgroup; i++) {
+ xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
+ xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
+@@ -269,7 +269,7 @@
+ * Also sets rowgroups_avail to indicate number of nondummy row groups in row.
+ */
+ {
+- my_main_ptr main = (my_main_ptr) cinfo->main;
++ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup, iMCUheight, rows_left;
+ jpeg_component_info *compptr;
+ JSAMPARRAY xbuf;
+@@ -286,12 +286,12 @@
+ * so we need only do it once.
+ */
+ if (ci == 0) {
+- main->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
++ main_ptr->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
+ }
+ /* Duplicate the last real sample row rgroup*2 times; this pads out the
+ * last partial rowgroup and ensures at least one full rowgroup of context.
+ */
+- xbuf = main->xbuffer[main->whichptr][ci];
++ xbuf = main_ptr->xbuffer[main_ptr->whichptr][ci];
+ for (i = 0; i < rgroup * 2; i++) {
+ xbuf[rows_left + i] = xbuf[rows_left-1];
+ }
+@@ -306,27 +306,27 @@
+ METHODDEF(void)
+ start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
+ {
+- my_main_ptr main = (my_main_ptr) cinfo->main;
++ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (cinfo->upsample->need_context_rows) {
+- main->pub.process_data = process_data_context_main;
++ main_ptr->pub.process_data = process_data_context_main;
+ make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
+- main->whichptr = 0; /* Read first iMCU row into xbuffer[0] */
+- main->context_state = CTX_PREPARE_FOR_IMCU;
+- main->iMCU_row_ctr = 0;
++ main_ptr->whichptr = 0; /* Read first iMCU row into xbuffer[0] */
++ main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
++ main_ptr->iMCU_row_ctr = 0;
+ } else {
+ /* Simple case with no context needed */
+- main->pub.process_data = process_data_simple_main;
++ main_ptr->pub.process_data = process_data_simple_main;
+ }
+- main->buffer_full = FALSE; /* Mark buffer empty */
+- main->rowgroup_ctr = 0;
++ main_ptr->buffer_full = FALSE; /* Mark buffer empty */
++ main_ptr->rowgroup_ctr = 0;
+ break;
+ #ifdef QUANT_2PASS_SUPPORTED
+ case JBUF_CRANK_DEST:
+ /* For last pass of 2-pass quantization, just crank the postprocessor */
+- main->pub.process_data = process_data_crank_post;
++ main_ptr->pub.process_data = process_data_crank_post;
+ break;
+ #endif
+ default:
+@@ -346,14 +346,14 @@
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+ {
+- my_main_ptr main = (my_main_ptr) cinfo->main;
++ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ JDIMENSION rowgroups_avail;
+
+ /* Read input data if we haven't filled the main buffer yet */
+- if (! main->buffer_full) {
+- if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer))
++ if (! main_ptr->buffer_full) {
++ if (! (*cinfo->coef->decompress_data) (cinfo, main_ptr->buffer))
+ return; /* suspension forced, can do nothing more */
+- main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
++ main_ptr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
+ }
+
+ /* There are always min_DCT_scaled_size row groups in an iMCU row. */
+@@ -364,14 +364,14 @@
+ */
+
+ /* Feed the postprocessor */
+- (*cinfo->post->post_process_data) (cinfo, main->buffer,
+- &main->rowgroup_ctr, rowgroups_avail,
++ (*cinfo->post->post_process_data) (cinfo, main_ptr->buffer,
++ &main_ptr->rowgroup_ctr, rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+
+ /* Has postprocessor consumed all the data yet? If so, mark buffer empty */
+- if (main->rowgroup_ctr >= rowgroups_avail) {
+- main->buffer_full = FALSE;
+- main->rowgroup_ctr = 0;
++ if (main_ptr->rowgroup_ctr >= rowgroups_avail) {
++ main_ptr->buffer_full = FALSE;
++ main_ptr->rowgroup_ctr = 0;
+ }
+ }
+
+@@ -386,15 +386,15 @@
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+ {
+- my_main_ptr main = (my_main_ptr) cinfo->main;
++ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+
+ /* Read input data if we haven't filled the main buffer yet */
+- if (! main->buffer_full) {
++ if (! main_ptr->buffer_full) {
+ if (! (*cinfo->coef->decompress_data) (cinfo,
+- main->xbuffer[main->whichptr]))
++ main_ptr->xbuffer[main_ptr->whichptr]))
+ return; /* suspension forced, can do nothing more */
+- main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
+- main->iMCU_row_ctr++; /* count rows received */
++ main_ptr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
++ main_ptr->iMCU_row_ctr++; /* count rows received */
+ }
+
+ /* Postprocessor typically will not swallow all the input data it is handed
+@@ -402,47 +402,47 @@
+ * to exit and restart. This switch lets us keep track of how far we got.
+ * Note that each case falls through to the next on successful completion.
+ */
+- switch (main->context_state) {
++ switch (main_ptr->context_state) {
+ case CTX_POSTPONED_ROW:
+ /* Call postprocessor using previously set pointers for postponed row */
+- (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
+- &main->rowgroup_ctr, main->rowgroups_avail,
++ (*cinfo->post->post_process_data) (cinfo, main_ptr->xbuffer[main_ptr->whichptr],
++ &main_ptr->rowgroup_ctr, main_ptr->rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+- if (main->rowgroup_ctr < main->rowgroups_avail)
++ if (main_ptr->rowgroup_ctr < main_ptr->rowgroups_avail)
+ return; /* Need to suspend */
+- main->context_state = CTX_PREPARE_FOR_IMCU;
++ main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
+ if (*out_row_ctr >= out_rows_avail)
+ return; /* Postprocessor exactly filled output buf */
+ /*FALLTHROUGH*/
+ case CTX_PREPARE_FOR_IMCU:
+ /* Prepare to process first M-1 row groups of this iMCU row */
+- main->rowgroup_ctr = 0;
+- main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size - 1);
++ main_ptr->rowgroup_ctr = 0;
++ main_ptr->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size - 1);
+ /* Check for bottom of image: if so, tweak pointers to "duplicate"
+ * the last sample row, and adjust rowgroups_avail to ignore padding rows.
+ */
+- if (main->iMCU_row_ctr == cinfo->total_iMCU_rows)
++ if (main_ptr->iMCU_row_ctr == cinfo->total_iMCU_rows)
+ set_bottom_pointers(cinfo);
+- main->context_state = CTX_PROCESS_IMCU;
++ main_ptr->context_state = CTX_PROCESS_IMCU;
+ /*FALLTHROUGH*/
+ case CTX_PROCESS_IMCU:
+ /* Call postprocessor using previously set pointers */
+- (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
+- &main->rowgroup_ctr, main->rowgroups_avail,
++ (*cinfo->post->post_process_data) (cinfo, main_ptr->xbuffer[main_ptr->whichptr],
++ &main_ptr->rowgroup_ctr, main_ptr->rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+- if (main->rowgroup_ctr < main->rowgroups_avail)
++ if (main_ptr->rowgroup_ctr < main_ptr->rowgroups_avail)
+ return; /* Need to suspend */
+ /* After the first iMCU, change wraparound pointers to normal state */
+- if (main->iMCU_row_ctr == 1)
++ if (main_ptr->iMCU_row_ctr == 1)
+ set_wraparound_pointers(cinfo);
+ /* Prepare to load new iMCU row using other xbuffer list */
+- main->whichptr ^= 1; /* 0=>1 or 1=>0 */
+- main->buffer_full = FALSE;
++ main_ptr->whichptr ^= 1; /* 0=>1 or 1=>0 */
++ main_ptr->buffer_full = FALSE;
+ /* Still need to process last row group of this iMCU row, */
+ /* which is saved at index M+1 of the other xbuffer */
+- main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 1);
+- main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 2);
+- main->context_state = CTX_POSTPONED_ROW;
++ main_ptr->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 1);
++ main_ptr->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 2);
++ main_ptr->context_state = CTX_POSTPONED_ROW;
+ }
+ }
+
+@@ -475,15 +475,15 @@
+ GLOBAL(void)
+ jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+ {
+- my_main_ptr main;
++ my_main_ptr main_ptr;
+ int ci, rgroup, ngroups;
+ jpeg_component_info *compptr;
+
+- main = (my_main_ptr)
++ main_ptr = (my_main_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_main_controller));
+- cinfo->main = (struct jpeg_d_main_controller *) main;
+- main->pub.start_pass = start_pass_main;
++ cinfo->main = (struct jpeg_d_main_controller *) main_ptr;
++ main_ptr->pub.start_pass = start_pass_main;
+
+ if (need_full_buffer) /* shouldn't happen */
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+@@ -504,7 +504,7 @@
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+- main->buffer[ci] = (*cinfo->mem->alloc_sarray)
++ main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+ (JDIMENSION) (rgroup * ngroups));
+diff -ru jpeg-8c/jerror.c ioquake3/code/jpeg-8c/jerror.c
+--- jpeg-8c/jerror.c 1998-02-21 19:03:16.000000000 +0000
++++ ioquake3/code/jpeg-8c/jerror.c 2011-11-25 11:24:52.000000000 +0000
+@@ -24,6 +24,8 @@
+ #include "jversion.h"
+ #include "jerror.h"
+
++#include <stdlib.h>
++
+ #ifdef USE_WINDOWS_MESSAGEBOX
+ #include <windows.h>
+ #endif
+Only in jpeg-8c: jmemansi.c
+Only in jpeg-8c: jmemdosa.asm
+Only in jpeg-8c: jmemdos.c
+Only in jpeg-8c: jmemmac.c
+Only in jpeg-8c: jmemname.c
+Only in jpeg-8c: jpegtran.1
+Only in jpeg-8c: jpegtran.c
+Only in jpeg-8c: libjpeg.map
+Only in jpeg-8c: libjpeg.txt
+Only in jpeg-8c: ltmain.sh
+Only in jpeg-8c: makcjpeg.st
+Only in jpeg-8c: makdjpeg.st
+Only in jpeg-8c: makeadsw.vc6
+Only in jpeg-8c: makeasln.v10
+Only in jpeg-8c: makecdep.vc6
+Only in jpeg-8c: makecdsp.vc6
+Only in jpeg-8c: makecfil.v10
+Only in jpeg-8c: makecmak.vc6
+Only in jpeg-8c: makecvcx.v10
+Only in jpeg-8c: makeddep.vc6
+Only in jpeg-8c: makeddsp.vc6
+Only in jpeg-8c: makedfil.v10
+Only in jpeg-8c: makedmak.vc6
+Only in jpeg-8c: makedvcx.v10
+Only in jpeg-8c: Makefile.am
+Only in jpeg-8c: makefile.ansi
+Only in jpeg-8c: makefile.bcc
+Only in jpeg-8c: makefile.dj
+Only in jpeg-8c: Makefile.in
+Only in jpeg-8c: makefile.manx
+Only in jpeg-8c: makefile.mc6
+Only in jpeg-8c: makefile.mms
+Only in jpeg-8c: makefile.sas
+Only in jpeg-8c: makefile.unix
+Only in jpeg-8c: makefile.vc
+Only in jpeg-8c: makefile.vms
+Only in jpeg-8c: makefile.wat
+Only in jpeg-8c: makejdep.vc6
+Only in jpeg-8c: makejdsp.vc6
+Only in jpeg-8c: makejdsw.vc6
+Only in jpeg-8c: makejfil.v10
+Only in jpeg-8c: makejmak.vc6
+Only in jpeg-8c: makejsln.v10
+Only in jpeg-8c: makejvcx.v10
+Only in jpeg-8c: makeproj.mac
+Only in jpeg-8c: makerdep.vc6
+Only in jpeg-8c: makerdsp.vc6
+Only in jpeg-8c: makerfil.v10
+Only in jpeg-8c: makermak.vc6
+Only in jpeg-8c: makervcx.v10
+Only in jpeg-8c: maketdep.vc6
+Only in jpeg-8c: maketdsp.vc6
+Only in jpeg-8c: maketfil.v10
+Only in jpeg-8c: maketmak.vc6
+Only in jpeg-8c: maketvcx.v10
+Only in jpeg-8c: makewdep.vc6
+Only in jpeg-8c: makewdsp.vc6
+Only in jpeg-8c: makewfil.v10
+Only in jpeg-8c: makewmak.vc6
+Only in jpeg-8c: makewvcx.v10
+Only in jpeg-8c: makljpeg.st
+Only in jpeg-8c: maktjpeg.st
+Only in jpeg-8c: makvms.opt
+Only in jpeg-8c: missing
+Only in jpeg-8c: rdbmp.c
+Only in jpeg-8c: rdcolmap.c
+Only in jpeg-8c: rdgif.c
+Only in jpeg-8c: rdjpgcom.1
+Only in jpeg-8c: rdjpgcom.c
+Only in jpeg-8c: rdppm.c
+Only in jpeg-8c: rdrle.c
+Only in jpeg-8c: rdswitch.c
+Only in jpeg-8c: rdtarga.c
+Only in jpeg-8c: structure.txt
+Only in jpeg-8c: testimg.bmp
+Only in jpeg-8c: testimg.jpg
+Only in jpeg-8c: testimgp.jpg
+Only in jpeg-8c: testimg.ppm
+Only in jpeg-8c: testorig.jpg
+Only in jpeg-8c: testprog.jpg
+Only in jpeg-8c: transupp.c
+Only in jpeg-8c: transupp.h
+Only in jpeg-8c: usage.txt
+Only in jpeg-8c: wizard.txt
+Only in jpeg-8c: wrbmp.c
+Only in jpeg-8c: wrgif.c
+Only in jpeg-8c: wrjpgcom.1
+Only in jpeg-8c: wrjpgcom.c
+Only in jpeg-8c: wrppm.c
+Only in jpeg-8c: wrrle.c
+Only in jpeg-8c: wrtarga.c
diff --git a/external/jpeg-8c/jaricom.c b/external/jpeg-8c/jaricom.c
new file mode 100644
index 0000000..f43e2ea
--- /dev/null
+++ b/external/jpeg-8c/jaricom.c
@@ -0,0 +1,153 @@
+/*
+ * jaricom.c
+ *
+ * Developed 1997-2009 by Guido Vollbeding.
+ * 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 probability estimation tables for common use in
+ * arithmetic entropy encoding and decoding routines.
+ *
+ * This data represents Table D.2 in the JPEG spec (ISO/IEC IS 10918-1
+ * and CCITT Recommendation ITU-T T.81) and Table 24 in the JBIG spec
+ * (ISO/IEC IS 11544 and CCITT Recommendation ITU-T T.82).
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+/* The following #define specifies the packing of the four components
+ * into the compact INT32 representation.
+ * Note that this formula must match the actual arithmetic encoder
+ * and decoder implementation. The implementation has to be changed
+ * if this formula is changed.
+ * The current organization is leaned on Markus Kuhn's JBIG
+ * implementation (jbig_tab.c).
+ */
+
+#define V(i,a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b)
+
+const INT32 jpeg_aritab[113+1] = {
+/*
+ * Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS
+ */
+ V( 0, 0x5a1d, 1, 1, 1 ),
+ V( 1, 0x2586, 14, 2, 0 ),
+ V( 2, 0x1114, 16, 3, 0 ),
+ V( 3, 0x080b, 18, 4, 0 ),
+ V( 4, 0x03d8, 20, 5, 0 ),
+ V( 5, 0x01da, 23, 6, 0 ),
+ V( 6, 0x00e5, 25, 7, 0 ),
+ V( 7, 0x006f, 28, 8, 0 ),
+ V( 8, 0x0036, 30, 9, 0 ),
+ V( 9, 0x001a, 33, 10, 0 ),
+ V( 10, 0x000d, 35, 11, 0 ),
+ V( 11, 0x0006, 9, 12, 0 ),
+ V( 12, 0x0003, 10, 13, 0 ),
+ V( 13, 0x0001, 12, 13, 0 ),
+ V( 14, 0x5a7f, 15, 15, 1 ),
+ V( 15, 0x3f25, 36, 16, 0 ),
+ V( 16, 0x2cf2, 38, 17, 0 ),
+ V( 17, 0x207c, 39, 18, 0 ),
+ V( 18, 0x17b9, 40, 19, 0 ),
+ V( 19, 0x1182, 42, 20, 0 ),
+ V( 20, 0x0cef, 43, 21, 0 ),
+ V( 21, 0x09a1, 45, 22, 0 ),
+ V( 22, 0x072f, 46, 23, 0 ),
+ V( 23, 0x055c, 48, 24, 0 ),
+ V( 24, 0x0406, 49, 25, 0 ),
+ V( 25, 0x0303, 51, 26, 0 ),
+ V( 26, 0x0240, 52, 27, 0 ),
+ V( 27, 0x01b1, 54, 28, 0 ),
+ V( 28, 0x0144, 56, 29, 0 ),
+ V( 29, 0x00f5, 57, 30, 0 ),
+ V( 30, 0x00b7, 59, 31, 0 ),
+ V( 31, 0x008a, 60, 32, 0 ),
+ V( 32, 0x0068, 62, 33, 0 ),
+ V( 33, 0x004e, 63, 34, 0 ),
+ V( 34, 0x003b, 32, 35, 0 ),
+ V( 35, 0x002c, 33, 9, 0 ),
+ V( 36, 0x5ae1, 37, 37, 1 ),
+ V( 37, 0x484c, 64, 38, 0 ),
+ V( 38, 0x3a0d, 65, 39, 0 ),
+ V( 39, 0x2ef1, 67, 40, 0 ),
+ V( 40, 0x261f, 68, 41, 0 ),
+ V( 41, 0x1f33, 69, 42, 0 ),
+ V( 42, 0x19a8, 70, 43, 0 ),
+ V( 43, 0x1518, 72, 44, 0 ),
+ V( 44, 0x1177, 73, 45, 0 ),
+ V( 45, 0x0e74, 74, 46, 0 ),
+ V( 46, 0x0bfb, 75, 47, 0 ),
+ V( 47, 0x09f8, 77, 48, 0 ),
+ V( 48, 0x0861, 78, 49, 0 ),
+ V( 49, 0x0706, 79, 50, 0 ),
+ V( 50, 0x05cd, 48, 51, 0 ),
+ V( 51, 0x04de, 50, 52, 0 ),
+ V( 52, 0x040f, 50, 53, 0 ),
+ V( 53, 0x0363, 51, 54, 0 ),
+ V( 54, 0x02d4, 52, 55, 0 ),
+ V( 55, 0x025c, 53, 56, 0 ),
+ V( 56, 0x01f8, 54, 57, 0 ),
+ V( 57, 0x01a4, 55, 58, 0 ),
+ V( 58, 0x0160, 56, 59, 0 ),
+ V( 59, 0x0125, 57, 60, 0 ),
+ V( 60, 0x00f6, 58, 61, 0 ),
+ V( 61, 0x00cb, 59, 62, 0 ),
+ V( 62, 0x00ab, 61, 63, 0 ),
+ V( 63, 0x008f, 61, 32, 0 ),
+ V( 64, 0x5b12, 65, 65, 1 ),
+ V( 65, 0x4d04, 80, 66, 0 ),
+ V( 66, 0x412c, 81, 67, 0 ),
+ V( 67, 0x37d8, 82, 68, 0 ),
+ V( 68, 0x2fe8, 83, 69, 0 ),
+ V( 69, 0x293c, 84, 70, 0 ),
+ V( 70, 0x2379, 86, 71, 0 ),
+ V( 71, 0x1edf, 87, 72, 0 ),
+ V( 72, 0x1aa9, 87, 73, 0 ),
+ V( 73, 0x174e, 72, 74, 0 ),
+ V( 74, 0x1424, 72, 75, 0 ),
+ V( 75, 0x119c, 74, 76, 0 ),
+ V( 76, 0x0f6b, 74, 77, 0 ),
+ V( 77, 0x0d51, 75, 78, 0 ),
+ V( 78, 0x0bb6, 77, 79, 0 ),
+ V( 79, 0x0a40, 77, 48, 0 ),
+ V( 80, 0x5832, 80, 81, 1 ),
+ V( 81, 0x4d1c, 88, 82, 0 ),
+ V( 82, 0x438e, 89, 83, 0 ),
+ V( 83, 0x3bdd, 90, 84, 0 ),
+ V( 84, 0x34ee, 91, 85, 0 ),
+ V( 85, 0x2eae, 92, 86, 0 ),
+ V( 86, 0x299a, 93, 87, 0 ),
+ V( 87, 0x2516, 86, 71, 0 ),
+ V( 88, 0x5570, 88, 89, 1 ),
+ V( 89, 0x4ca9, 95, 90, 0 ),
+ V( 90, 0x44d9, 96, 91, 0 ),
+ V( 91, 0x3e22, 97, 92, 0 ),
+ V( 92, 0x3824, 99, 93, 0 ),
+ V( 93, 0x32b4, 99, 94, 0 ),
+ V( 94, 0x2e17, 93, 86, 0 ),
+ V( 95, 0x56a8, 95, 96, 1 ),
+ V( 96, 0x4f46, 101, 97, 0 ),
+ V( 97, 0x47e5, 102, 98, 0 ),
+ V( 98, 0x41cf, 103, 99, 0 ),
+ V( 99, 0x3c3d, 104, 100, 0 ),
+ V( 100, 0x375e, 99, 93, 0 ),
+ V( 101, 0x5231, 105, 102, 0 ),
+ V( 102, 0x4c0f, 106, 103, 0 ),
+ V( 103, 0x4639, 107, 104, 0 ),
+ V( 104, 0x415e, 103, 99, 0 ),
+ V( 105, 0x5627, 105, 106, 1 ),
+ V( 106, 0x50e7, 108, 107, 0 ),
+ V( 107, 0x4b85, 109, 103, 0 ),
+ V( 108, 0x5597, 110, 109, 0 ),
+ V( 109, 0x504f, 111, 107, 0 ),
+ V( 110, 0x5a10, 110, 111, 1 ),
+ V( 111, 0x5522, 112, 109, 0 ),
+ V( 112, 0x59eb, 112, 111, 1 ),
+/*
+ * This last entry is used for fixed probability estimate of 0.5
+ * as recommended in Section 10.3 Table 5 of ITU-T Rec. T.851.
+ */
+ V( 113, 0x5a1d, 113, 113, 0 )
+};
diff --git a/external/jpeg-8c/jcapimin.c b/external/jpeg-8c/jcapimin.c
new file mode 100644
index 0000000..639ce86
--- /dev/null
+++ b/external/jpeg-8c/jcapimin.c
@@ -0,0 +1,288 @@
+/*
+ * jcapimin.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * Modified 2003-2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the compression half
+ * of the JPEG library. These are the "minimum" API routines that may be
+ * needed in either the normal full-compression case or the transcoding-only
+ * case.
+ *
+ * Most of the routines intended to be called directly by an application
+ * are in this file or in jcapistd.c. But also see jcparam.c for
+ * parameter-setup helper routines, jcomapi.c for routines shared by
+ * compression and decompression, and jctrans.c for the transcoding case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Initialization of a JPEG compression object.
+ * The error manager must already be set up (in case memory manager fails).
+ */
+
+GLOBAL(void)
+jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)
+{
+ int i;
+
+ /* Guard against version mismatches between library and caller. */
+ cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */
+ if (version != JPEG_LIB_VERSION)
+ ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
+ if (structsize != SIZEOF(struct jpeg_compress_struct))
+ ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
+ (int) SIZEOF(struct jpeg_compress_struct), (int) structsize);
+
+ /* For debugging purposes, we zero the whole master structure.
+ * But the application has already set the err pointer, and may have set
+ * client_data, so we have to save and restore those fields.
+ * Note: if application hasn't set client_data, tools like Purify may
+ * complain here.
+ */
+ {
+ struct jpeg_error_mgr * err = cinfo->err;
+ void * client_data = cinfo->client_data; /* ignore Purify complaint here */
+ MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct));
+ cinfo->err = err;
+ cinfo->client_data = client_data;
+ }
+ cinfo->is_decompressor = FALSE;
+
+ /* Initialize a memory manager instance for this object */
+ jinit_memory_mgr((j_common_ptr) cinfo);
+
+ /* Zero out pointers to permanent structures. */
+ cinfo->progress = NULL;
+ cinfo->dest = NULL;
+
+ cinfo->comp_info = NULL;
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ cinfo->quant_tbl_ptrs[i] = NULL;
+ cinfo->q_scale_factor[i] = 100;
+ }
+
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ cinfo->dc_huff_tbl_ptrs[i] = NULL;
+ cinfo->ac_huff_tbl_ptrs[i] = NULL;
+ }
+
+ /* Must do it here for emit_dqt in case jpeg_write_tables is used */
+ cinfo->block_size = DCTSIZE;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+
+ cinfo->script_space = NULL;
+
+ cinfo->input_gamma = 1.0; /* in case application forgets */
+
+ /* OK, I'm ready */
+ cinfo->global_state = CSTATE_START;
+}
+
+
+/*
+ * Destruction of a JPEG compression object
+ */
+
+GLOBAL(void)
+jpeg_destroy_compress (j_compress_ptr cinfo)
+{
+ jpeg_destroy((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Abort processing of a JPEG compression operation,
+ * but don't destroy the object itself.
+ */
+
+GLOBAL(void)
+jpeg_abort_compress (j_compress_ptr cinfo)
+{
+ jpeg_abort((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Forcibly suppress or un-suppress all quantization and Huffman tables.
+ * Marks all currently defined tables as already written (if suppress)
+ * or not written (if !suppress). This will control whether they get emitted
+ * by a subsequent jpeg_start_compress call.
+ *
+ * This routine is exported for use by applications that want to produce
+ * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but
+ * since it is called by jpeg_start_compress, we put it here --- otherwise
+ * jcparam.o would be linked whether the application used it or not.
+ */
+
+GLOBAL(void)
+jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress)
+{
+ int i;
+ JQUANT_TBL * qtbl;
+ JHUFF_TBL * htbl;
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL)
+ qtbl->sent_table = suppress;
+ }
+
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL)
+ htbl->sent_table = suppress;
+ if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL)
+ htbl->sent_table = suppress;
+ }
+}
+
+
+/*
+ * Finish JPEG compression.
+ *
+ * If a multipass operating mode was selected, this may do a great deal of
+ * work including most of the actual output.
+ */
+
+GLOBAL(void)
+jpeg_finish_compress (j_compress_ptr cinfo)
+{
+ JDIMENSION iMCU_row;
+
+ if (cinfo->global_state == CSTATE_SCANNING ||
+ cinfo->global_state == CSTATE_RAW_OK) {
+ /* Terminate first pass */
+ if (cinfo->next_scanline < cinfo->image_height)
+ ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
+ (*cinfo->master->finish_pass) (cinfo);
+ } else if (cinfo->global_state != CSTATE_WRCOEFS)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Perform any remaining passes */
+ while (! cinfo->master->is_last_pass) {
+ (*cinfo->master->prepare_for_pass) (cinfo);
+ for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) {
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) iMCU_row;
+ cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+ /* We bypass the main controller and invoke coef controller directly;
+ * all work is being done from the coefficient buffer.
+ */
+ if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ }
+ (*cinfo->master->finish_pass) (cinfo);
+ }
+ /* Write EOI, do final cleanup */
+ (*cinfo->marker->write_file_trailer) (cinfo);
+ (*cinfo->dest->term_destination) (cinfo);
+ /* We can use jpeg_abort to release memory and reset global_state */
+ jpeg_abort((j_common_ptr) cinfo);
+}
+
+
+/*
+ * Write a special marker.
+ * This is only recommended for writing COM or APPn markers.
+ * Must be called after jpeg_start_compress() and before
+ * first call to jpeg_write_scanlines() or jpeg_write_raw_data().
+ */
+
+GLOBAL(void)
+jpeg_write_marker (j_compress_ptr cinfo, int marker,
+ const JOCTET *dataptr, unsigned int datalen)
+{
+ JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val));
+
+ if (cinfo->next_scanline != 0 ||
+ (cinfo->global_state != CSTATE_SCANNING &&
+ cinfo->global_state != CSTATE_RAW_OK &&
+ cinfo->global_state != CSTATE_WRCOEFS))
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ (*cinfo->marker->write_marker_header) (cinfo, marker, datalen);
+ write_marker_byte = cinfo->marker->write_marker_byte; /* copy for speed */
+ while (datalen--) {
+ (*write_marker_byte) (cinfo, *dataptr);
+ dataptr++;
+ }
+}
+
+/* Same, but piecemeal. */
+
+GLOBAL(void)
+jpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen)
+{
+ if (cinfo->next_scanline != 0 ||
+ (cinfo->global_state != CSTATE_SCANNING &&
+ cinfo->global_state != CSTATE_RAW_OK &&
+ cinfo->global_state != CSTATE_WRCOEFS))
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ (*cinfo->marker->write_marker_header) (cinfo, marker, datalen);
+}
+
+GLOBAL(void)
+jpeg_write_m_byte (j_compress_ptr cinfo, int val)
+{
+ (*cinfo->marker->write_marker_byte) (cinfo, val);
+}
+
+
+/*
+ * Alternate compression function: just write an abbreviated table file.
+ * Before calling this, all parameters and a data destination must be set up.
+ *
+ * To produce a pair of files containing abbreviated tables and abbreviated
+ * image data, one would proceed as follows:
+ *
+ * initialize JPEG object
+ * set JPEG parameters
+ * set destination to table file
+ * jpeg_write_tables(cinfo);
+ * set destination to image file
+ * jpeg_start_compress(cinfo, FALSE);
+ * write data...
+ * jpeg_finish_compress(cinfo);
+ *
+ * jpeg_write_tables has the side effect of marking all tables written
+ * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress
+ * will not re-emit the tables unless it is passed write_all_tables=TRUE.
+ */
+
+GLOBAL(void)
+jpeg_write_tables (j_compress_ptr cinfo)
+{
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* (Re)initialize error mgr and destination modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->dest->init_destination) (cinfo);
+ /* Initialize the marker writer ... bit of a crock to do it here. */
+ jinit_marker_writer(cinfo);
+ /* Write them tables! */
+ (*cinfo->marker->write_tables_only) (cinfo);
+ /* And clean up. */
+ (*cinfo->dest->term_destination) (cinfo);
+ /*
+ * In library releases up through v6a, we called jpeg_abort() here to free
+ * any working memory allocated by the destination manager and marker
+ * writer. Some applications had a problem with that: they allocated space
+ * of their own from the library memory manager, and didn't want it to go
+ * away during write_tables. So now we do nothing. This will cause a
+ * memory leak if an app calls write_tables repeatedly without doing a full
+ * compression cycle or otherwise resetting the JPEG object. However, that
+ * seems less bad than unexpectedly freeing memory in the normal case.
+ * An app that prefers the old behavior can call jpeg_abort for itself after
+ * each call to jpeg_write_tables().
+ */
+}
diff --git a/external/jpeg-8c/jcapistd.c b/external/jpeg-8c/jcapistd.c
new file mode 100644
index 0000000..c0320b1
--- /dev/null
+++ b/external/jpeg-8c/jcapistd.c
@@ -0,0 +1,161 @@
+/*
+ * jcapistd.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the compression half
+ * of the JPEG library. These are the "standard" API routines that are
+ * used in the normal full-compression case. They are not used by a
+ * transcoding-only application. Note that if an application links in
+ * jpeg_start_compress, it will end up linking in the entire compressor.
+ * We thus must separate this file from jcapimin.c to avoid linking the
+ * whole compression library into a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Compression initialization.
+ * Before calling this, all parameters and a data destination must be set up.
+ *
+ * We require a write_all_tables parameter as a failsafe check when writing
+ * multiple datastreams from the same compression object. Since prior runs
+ * will have left all the tables marked sent_table=TRUE, a subsequent run
+ * would emit an abbreviated stream (no tables) by default. This may be what
+ * is wanted, but for safety's sake it should not be the default behavior:
+ * programmers should have to make a deliberate choice to emit abbreviated
+ * images. Therefore the documentation and examples should encourage people
+ * to pass write_all_tables=TRUE; then it will take active thought to do the
+ * wrong thing.
+ */
+
+GLOBAL(void)
+jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables)
+{
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ if (write_all_tables)
+ jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */
+
+ /* (Re)initialize error mgr and destination modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->dest->init_destination) (cinfo);
+ /* Perform master selection of active modules */
+ jinit_compress_master(cinfo);
+ /* Set up for the first pass */
+ (*cinfo->master->prepare_for_pass) (cinfo);
+ /* Ready for application to drive first pass through jpeg_write_scanlines
+ * or jpeg_write_raw_data.
+ */
+ cinfo->next_scanline = 0;
+ cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
+}
+
+
+/*
+ * Write some scanlines of data to the JPEG compressor.
+ *
+ * The return value will be the number of lines actually written.
+ * This should be less than the supplied num_lines only in case that
+ * the data destination module has requested suspension of the compressor,
+ * or if more than image_height scanlines are passed in.
+ *
+ * Note: we warn about excess calls to jpeg_write_scanlines() since
+ * this likely signals an application programmer error. However,
+ * excess scanlines passed in the last valid call are *silently* ignored,
+ * so that the application need not adjust num_lines for end-of-image
+ * when using a multiple-scanline buffer.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,
+ JDIMENSION num_lines)
+{
+ JDIMENSION row_ctr, rows_left;
+
+ if (cinfo->global_state != CSTATE_SCANNING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->next_scanline >= cinfo->image_height)
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->next_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->image_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Give master control module another chance if this is first call to
+ * jpeg_write_scanlines. This lets output of the frame/scan headers be
+ * delayed so that application can write COM, etc, markers between
+ * jpeg_start_compress and jpeg_write_scanlines.
+ */
+ if (cinfo->master->call_pass_startup)
+ (*cinfo->master->pass_startup) (cinfo);
+
+ /* Ignore any extra scanlines at bottom of image. */
+ rows_left = cinfo->image_height - cinfo->next_scanline;
+ if (num_lines > rows_left)
+ num_lines = rows_left;
+
+ row_ctr = 0;
+ (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
+ cinfo->next_scanline += row_ctr;
+ return row_ctr;
+}
+
+
+/*
+ * Alternate entry point to write raw data.
+ * Processes exactly one iMCU row per call, unless suspended.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data,
+ JDIMENSION num_lines)
+{
+ JDIMENSION lines_per_iMCU_row;
+
+ if (cinfo->global_state != CSTATE_RAW_OK)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->next_scanline >= cinfo->image_height) {
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->next_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->image_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Give master control module another chance if this is first call to
+ * jpeg_write_raw_data. This lets output of the frame/scan headers be
+ * delayed so that application can write COM, etc, markers between
+ * jpeg_start_compress and jpeg_write_raw_data.
+ */
+ if (cinfo->master->call_pass_startup)
+ (*cinfo->master->pass_startup) (cinfo);
+
+ /* Verify that at least one iMCU row has been passed. */
+ lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE;
+ if (num_lines < lines_per_iMCU_row)
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+ /* Directly compress the row. */
+ if (! (*cinfo->coef->compress_data) (cinfo, data)) {
+ /* If compressor did not consume the whole row, suspend processing. */
+ return 0;
+ }
+
+ /* OK, we processed one iMCU row. */
+ cinfo->next_scanline += lines_per_iMCU_row;
+ return lines_per_iMCU_row;
+}
diff --git a/external/jpeg-8c/jcarith.c b/external/jpeg-8c/jcarith.c
new file mode 100644
index 0000000..0b7ea55
--- /dev/null
+++ b/external/jpeg-8c/jcarith.c
@@ -0,0 +1,934 @@
+/*
+ * jcarith.c
+ *
+ * Developed 1997-2009 by Guido Vollbeding.
+ * 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 portable arithmetic entropy encoding routines for JPEG
+ * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
+ *
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Suspension is not currently supported in this module.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Expanded entropy encoder object for arithmetic encoding. */
+
+typedef struct {
+ struct jpeg_entropy_encoder pub; /* public fields */
+
+ INT32 c; /* C register, base of coding interval, layout as in sec. D.1.3 */
+ INT32 a; /* A register, normalized size of coding interval */
+ INT32 sc; /* counter for stacked 0xFF values which might overflow */
+ INT32 zc; /* counter for pending 0x00 output values which might *
+ * be discarded at the end ("Pacman" termination) */
+ int ct; /* bit shift counter, determines when next byte will be written */
+ int buffer; /* buffer for most recent output byte != 0xFF */
+
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+ int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */
+
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+ int next_restart_num; /* next restart number to write (0-7) */
+
+ /* Pointers to statistics areas (these workspaces have image lifespan) */
+ unsigned char * dc_stats[NUM_ARITH_TBLS];
+ unsigned char * ac_stats[NUM_ARITH_TBLS];
+
+ /* Statistics bin for coding with fixed probability 0.5 */
+ unsigned char fixed_bin[4];
+} arith_entropy_encoder;
+
+typedef arith_entropy_encoder * arith_entropy_ptr;
+
+/* The following two definitions specify the allocation chunk size
+ * for the statistics area.
+ * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least
+ * 49 statistics bins for DC, and 245 statistics bins for AC coding.
+ *
+ * We use a compact representation with 1 byte per statistics bin,
+ * thus the numbers directly represent byte sizes.
+ * This 1 byte per statistics bin contains the meaning of the MPS
+ * (more probable symbol) in the highest bit (mask 0x80), and the
+ * index into the probability estimation state machine table
+ * in the lower bits (mask 0x7F).
+ */
+
+#define DC_STAT_BINS 64
+#define AC_STAT_BINS 256
+
+/* NOTE: Uncomment the following #define if you want to use the
+ * given formula for calculating the AC conditioning parameter Kx
+ * for spectral selection progressive coding in section G.1.3.2
+ * of the spec (Kx = Kmin + SRL (8 + Se - Kmin) 4).
+ * Although the spec and P&M authors claim that this "has proven
+ * to give good results for 8 bit precision samples", I'm not
+ * convinced yet that this is really beneficial.
+ * Early tests gave only very marginal compression enhancements
+ * (a few - around 5 or so - bytes even for very large files),
+ * which would turn out rather negative if we'd suppress the
+ * DAC (Define Arithmetic Conditioning) marker segments for
+ * the default parameters in the future.
+ * Note that currently the marker writing module emits 12-byte
+ * DAC segments for a full-component scan in a color image.
+ * This is not worth worrying about IMHO. However, since the
+ * spec defines the default values to be used if the tables
+ * are omitted (unlike Huffman tables, which are required
+ * anyway), one might optimize this behaviour in the future,
+ * and then it would be disadvantageous to use custom tables if
+ * they don't provide sufficient gain to exceed the DAC size.
+ *
+ * On the other hand, I'd consider it as a reasonable result
+ * that the conditioning has no significant influence on the
+ * compression performance. This means that the basic
+ * statistical model is already rather stable.
+ *
+ * Thus, at the moment, we use the default conditioning values
+ * anyway, and do not use the custom formula.
+ *
+#define CALCULATE_SPECTRAL_CONDITIONING
+ */
+
+/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
+ * We assume that int right shift is unsigned if INT32 right shift is,
+ * which should be safe.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS int ishift_temp;
+#define IRIGHT_SHIFT(x,shft) \
+ ((ishift_temp = (x)) < 0 ? \
+ (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \
+ (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
+#endif
+
+
+LOCAL(void)
+emit_byte (int val, j_compress_ptr cinfo)
+/* Write next output byte; we do not support suspension in this module. */
+{
+ struct jpeg_destination_mgr * dest = cinfo->dest;
+
+ *dest->next_output_byte++ = (JOCTET) val;
+ if (--dest->free_in_buffer == 0)
+ if (! (*dest->empty_output_buffer) (cinfo))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+}
+
+
+/*
+ * Finish up at the end of an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass (j_compress_ptr cinfo)
+{
+ arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+ INT32 temp;
+
+ /* Section D.1.8: Termination of encoding */
+
+ /* Find the e->c in the coding interval with the largest
+ * number of trailing zero bits */
+ if ((temp = (e->a - 1 + e->c) & 0xFFFF0000L) < e->c)
+ e->c = temp + 0x8000L;
+ else
+ e->c = temp;
+ /* Send remaining bytes to output */
+ e->c <<= e->ct;
+ if (e->c & 0xF8000000L) {
+ /* One final overflow has to be handled */
+ if (e->buffer >= 0) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ emit_byte(e->buffer + 1, cinfo);
+ if (e->buffer + 1 == 0xFF)
+ emit_byte(0x00, cinfo);
+ }
+ e->zc += e->sc; /* carry-over converts stacked 0xFF bytes to 0x00 */
+ e->sc = 0;
+ } else {
+ if (e->buffer == 0)
+ ++e->zc;
+ else if (e->buffer >= 0) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ emit_byte(e->buffer, cinfo);
+ }
+ if (e->sc) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ do {
+ emit_byte(0xFF, cinfo);
+ emit_byte(0x00, cinfo);
+ } while (--e->sc);
+ }
+ }
+ /* Output final bytes only if they are not 0x00 */
+ if (e->c & 0x7FFF800L) {
+ if (e->zc) /* output final pending zero bytes */
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ emit_byte((e->c >> 19) & 0xFF, cinfo);
+ if (((e->c >> 19) & 0xFF) == 0xFF)
+ emit_byte(0x00, cinfo);
+ if (e->c & 0x7F800L) {
+ emit_byte((e->c >> 11) & 0xFF, cinfo);
+ if (((e->c >> 11) & 0xFF) == 0xFF)
+ emit_byte(0x00, cinfo);
+ }
+ }
+}
+
+
+/*
+ * The core arithmetic encoding routine (common in JPEG and JBIG).
+ * This needs to go as fast as possible.
+ * Machine-dependent optimization facilities
+ * are not utilized in this portable implementation.
+ * However, this code should be fairly efficient and
+ * may be a good base for further optimizations anyway.
+ *
+ * Parameter 'val' to be encoded may be 0 or 1 (binary decision).
+ *
+ * Note: I've added full "Pacman" termination support to the
+ * byte output routines, which is equivalent to the optional
+ * Discard_final_zeros procedure (Figure D.15) in the spec.
+ * Thus, we always produce the shortest possible output
+ * stream compliant to the spec (no trailing zero bytes,
+ * except for FF stuffing).
+ *
+ * I've also introduced a new scheme for accessing
+ * the probability estimation state machine table,
+ * derived from Markus Kuhn's JBIG implementation.
+ */
+
+LOCAL(void)
+arith_encode (j_compress_ptr cinfo, unsigned char *st, int val)
+{
+ register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+ register unsigned char nl, nm;
+ register INT32 qe, temp;
+ register int sv;
+
+ /* Fetch values from our compact representation of Table D.2:
+ * Qe values and probability estimation state machine
+ */
+ sv = *st;
+ qe = jpeg_aritab[sv & 0x7F]; /* => Qe_Value */
+ nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */
+ nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */
+
+ /* Encode & estimation procedures per sections D.1.4 & D.1.5 */
+ e->a -= qe;
+ if (val != (sv >> 7)) {
+ /* Encode the less probable symbol */
+ if (e->a >= qe) {
+ /* If the interval size (qe) for the less probable symbol (LPS)
+ * is larger than the interval size for the MPS, then exchange
+ * the two symbols for coding efficiency, otherwise code the LPS
+ * as usual: */
+ e->c += e->a;
+ e->a = qe;
+ }
+ *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */
+ } else {
+ /* Encode the more probable symbol */
+ if (e->a >= 0x8000L)
+ return; /* A >= 0x8000 -> ready, no renormalization required */
+ if (e->a < qe) {
+ /* If the interval size (qe) for the less probable symbol (LPS)
+ * is larger than the interval size for the MPS, then exchange
+ * the two symbols for coding efficiency: */
+ e->c += e->a;
+ e->a = qe;
+ }
+ *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */
+ }
+
+ /* Renormalization & data output per section D.1.6 */
+ do {
+ e->a <<= 1;
+ e->c <<= 1;
+ if (--e->ct == 0) {
+ /* Another byte is ready for output */
+ temp = e->c >> 19;
+ if (temp > 0xFF) {
+ /* Handle overflow over all stacked 0xFF bytes */
+ if (e->buffer >= 0) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ emit_byte(e->buffer + 1, cinfo);
+ if (e->buffer + 1 == 0xFF)
+ emit_byte(0x00, cinfo);
+ }
+ e->zc += e->sc; /* carry-over converts stacked 0xFF bytes to 0x00 */
+ e->sc = 0;
+ /* Note: The 3 spacer bits in the C register guarantee
+ * that the new buffer byte can't be 0xFF here
+ * (see page 160 in the P&M JPEG book). */
+ e->buffer = temp & 0xFF; /* new output byte, might overflow later */
+ } else if (temp == 0xFF) {
+ ++e->sc; /* stack 0xFF byte (which might overflow later) */
+ } else {
+ /* Output all stacked 0xFF bytes, they will not overflow any more */
+ if (e->buffer == 0)
+ ++e->zc;
+ else if (e->buffer >= 0) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ emit_byte(e->buffer, cinfo);
+ }
+ if (e->sc) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ do {
+ emit_byte(0xFF, cinfo);
+ emit_byte(0x00, cinfo);
+ } while (--e->sc);
+ }
+ e->buffer = temp & 0xFF; /* new output byte (can still overflow) */
+ }
+ e->c &= 0x7FFFFL;
+ e->ct += 8;
+ }
+ } while (e->a < 0x8000L);
+}
+
+
+/*
+ * Emit a restart marker & resynchronize predictions.
+ */
+
+LOCAL(void)
+emit_restart (j_compress_ptr cinfo, int restart_num)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ int ci;
+ jpeg_component_info * compptr;
+
+ finish_pass(cinfo);
+
+ emit_byte(0xFF, cinfo);
+ emit_byte(JPEG_RST0 + restart_num, cinfo);
+
+ /* Re-initialize statistics areas */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+ MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
+ /* Reset DC predictions to 0 */
+ entropy->last_dc_val[ci] = 0;
+ entropy->dc_context[ci] = 0;
+ }
+ /* AC needs no table when not present */
+ if (cinfo->Se) {
+ MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
+ }
+ }
+
+ /* Reset arithmetic encoding variables */
+ entropy->c = 0;
+ entropy->a = 0x10000L;
+ entropy->sc = 0;
+ entropy->zc = 0;
+ entropy->ct = 11;
+ entropy->buffer = -1; /* empty */
+}
+
+
+/*
+ * MCU encoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ unsigned char *st;
+ int blkn, ci, tbl;
+ int v, v2, m;
+ ISHIFT_TEMPS
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ emit_restart(cinfo, entropy->next_restart_num);
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;
+
+ /* Compute the DC value after the required point transform by Al.
+ * This is simply an arithmetic right shift.
+ */
+ m = IRIGHT_SHIFT((int) ((*block)[0]), cinfo->Al);
+
+ /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */
+
+ /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+ st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+ /* Figure F.4: Encode_DC_DIFF */
+ if ((v = m - entropy->last_dc_val[ci]) == 0) {
+ arith_encode(cinfo, st, 0);
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ } else {
+ entropy->last_dc_val[ci] = m;
+ arith_encode(cinfo, st, 1);
+ /* Figure F.6: Encoding nonzero value v */
+ /* Figure F.7: Encoding the sign of v */
+ if (v > 0) {
+ arith_encode(cinfo, st + 1, 0); /* Table F.4: SS = S0 + 1 */
+ st += 2; /* Table F.4: SP = S0 + 2 */
+ entropy->dc_context[ci] = 4; /* small positive diff category */
+ } else {
+ v = -v;
+ arith_encode(cinfo, st + 1, 1); /* Table F.4: SS = S0 + 1 */
+ st += 3; /* Table F.4: SN = S0 + 3 */
+ entropy->dc_context[ci] = 8; /* small negative diff category */
+ }
+ /* Figure F.8: Encoding the magnitude category of v */
+ m = 0;
+ if (v -= 1) {
+ arith_encode(cinfo, st, 1);
+ m = 1;
+ v2 = v;
+ st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+ while (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st += 1;
+ }
+ }
+ arith_encode(cinfo, st, 0);
+ /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+ if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+ entropy->dc_context[ci] += 8; /* large diff category */
+ /* Figure F.9: Encoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ arith_encode(cinfo, st, (m & v) ? 1 : 0);
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ unsigned char *st;
+ int tbl, k, ke;
+ int v, v2, m;
+ const int * natural_order;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ emit_restart(cinfo, entropy->next_restart_num);
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ natural_order = cinfo->natural_order;
+
+ /* Encode the MCU data block */
+ block = MCU_data[0];
+ tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+ /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */
+
+ /* Establish EOB (end-of-block) index */
+ for (ke = cinfo->Se; ke > 0; ke--)
+ /* We must apply the point transform by Al. For AC coefficients this
+ * is an integer division with rounding towards 0. To do this portably
+ * in C, we shift after obtaining the absolute value.
+ */
+ if ((v = (*block)[natural_order[ke]]) >= 0) {
+ if (v >>= cinfo->Al) break;
+ } else {
+ v = -v;
+ if (v >>= cinfo->Al) break;
+ }
+
+ /* Figure F.5: Encode_AC_Coefficients */
+ for (k = cinfo->Ss; k <= ke; k++) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ arith_encode(cinfo, st, 0); /* EOB decision */
+ for (;;) {
+ if ((v = (*block)[natural_order[k]]) >= 0) {
+ if (v >>= cinfo->Al) {
+ arith_encode(cinfo, st + 1, 1);
+ arith_encode(cinfo, entropy->fixed_bin, 0);
+ break;
+ }
+ } else {
+ v = -v;
+ if (v >>= cinfo->Al) {
+ arith_encode(cinfo, st + 1, 1);
+ arith_encode(cinfo, entropy->fixed_bin, 1);
+ break;
+ }
+ }
+ arith_encode(cinfo, st + 1, 0); st += 3; k++;
+ }
+ st += 2;
+ /* Figure F.8: Encoding the magnitude category of v */
+ m = 0;
+ if (v -= 1) {
+ arith_encode(cinfo, st, 1);
+ m = 1;
+ v2 = v;
+ if (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st = entropy->ac_stats[tbl] +
+ (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+ while (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st += 1;
+ }
+ }
+ }
+ arith_encode(cinfo, st, 0);
+ /* Figure F.9: Encoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ arith_encode(cinfo, st, (m & v) ? 1 : 0);
+ }
+ /* Encode EOB decision only if k <= cinfo->Se */
+ if (k <= cinfo->Se) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ arith_encode(cinfo, st, 1);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for DC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ unsigned char *st;
+ int Al, blkn;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ emit_restart(cinfo, entropy->next_restart_num);
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ st = entropy->fixed_bin; /* use fixed probability estimation */
+ Al = cinfo->Al;
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ /* We simply emit the Al'th bit of the DC coefficient value. */
+ arith_encode(cinfo, st, (MCU_data[blkn][0][0] >> Al) & 1);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ unsigned char *st;
+ int tbl, k, ke, kex;
+ int v;
+ const int * natural_order;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ emit_restart(cinfo, entropy->next_restart_num);
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ natural_order = cinfo->natural_order;
+
+ /* Encode the MCU data block */
+ block = MCU_data[0];
+ tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+ /* Section G.1.3.3: Encoding of AC coefficients */
+
+ /* Establish EOB (end-of-block) index */
+ for (ke = cinfo->Se; ke > 0; ke--)
+ /* We must apply the point transform by Al. For AC coefficients this
+ * is an integer division with rounding towards 0. To do this portably
+ * in C, we shift after obtaining the absolute value.
+ */
+ if ((v = (*block)[natural_order[ke]]) >= 0) {
+ if (v >>= cinfo->Al) break;
+ } else {
+ v = -v;
+ if (v >>= cinfo->Al) break;
+ }
+
+ /* Establish EOBx (previous stage end-of-block) index */
+ for (kex = ke; kex > 0; kex--)
+ if ((v = (*block)[natural_order[kex]]) >= 0) {
+ if (v >>= cinfo->Ah) break;
+ } else {
+ v = -v;
+ if (v >>= cinfo->Ah) break;
+ }
+
+ /* Figure G.10: Encode_AC_Coefficients_SA */
+ for (k = cinfo->Ss; k <= ke; k++) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ if (k > kex)
+ arith_encode(cinfo, st, 0); /* EOB decision */
+ for (;;) {
+ if ((v = (*block)[natural_order[k]]) >= 0) {
+ if (v >>= cinfo->Al) {
+ if (v >> 1) /* previously nonzero coef */
+ arith_encode(cinfo, st + 2, (v & 1));
+ else { /* newly nonzero coef */
+ arith_encode(cinfo, st + 1, 1);
+ arith_encode(cinfo, entropy->fixed_bin, 0);
+ }
+ break;
+ }
+ } else {
+ v = -v;
+ if (v >>= cinfo->Al) {
+ if (v >> 1) /* previously nonzero coef */
+ arith_encode(cinfo, st + 2, (v & 1));
+ else { /* newly nonzero coef */
+ arith_encode(cinfo, st + 1, 1);
+ arith_encode(cinfo, entropy->fixed_bin, 1);
+ }
+ break;
+ }
+ }
+ arith_encode(cinfo, st + 1, 0); st += 3; k++;
+ }
+ }
+ /* Encode EOB decision only if k <= cinfo->Se */
+ if (k <= cinfo->Se) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ arith_encode(cinfo, st, 1);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Encode and output one MCU's worth of arithmetic-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+encode_mcu (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ jpeg_component_info * compptr;
+ JBLOCKROW block;
+ unsigned char *st;
+ int blkn, ci, tbl, k, ke;
+ int v, v2, m;
+ const int * natural_order;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ emit_restart(cinfo, entropy->next_restart_num);
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ natural_order = cinfo->natural_order;
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+
+ /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */
+
+ tbl = compptr->dc_tbl_no;
+
+ /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+ st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+ /* Figure F.4: Encode_DC_DIFF */
+ if ((v = (*block)[0] - entropy->last_dc_val[ci]) == 0) {
+ arith_encode(cinfo, st, 0);
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ } else {
+ entropy->last_dc_val[ci] = (*block)[0];
+ arith_encode(cinfo, st, 1);
+ /* Figure F.6: Encoding nonzero value v */
+ /* Figure F.7: Encoding the sign of v */
+ if (v > 0) {
+ arith_encode(cinfo, st + 1, 0); /* Table F.4: SS = S0 + 1 */
+ st += 2; /* Table F.4: SP = S0 + 2 */
+ entropy->dc_context[ci] = 4; /* small positive diff category */
+ } else {
+ v = -v;
+ arith_encode(cinfo, st + 1, 1); /* Table F.4: SS = S0 + 1 */
+ st += 3; /* Table F.4: SN = S0 + 3 */
+ entropy->dc_context[ci] = 8; /* small negative diff category */
+ }
+ /* Figure F.8: Encoding the magnitude category of v */
+ m = 0;
+ if (v -= 1) {
+ arith_encode(cinfo, st, 1);
+ m = 1;
+ v2 = v;
+ st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+ while (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st += 1;
+ }
+ }
+ arith_encode(cinfo, st, 0);
+ /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+ if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+ entropy->dc_context[ci] += 8; /* large diff category */
+ /* Figure F.9: Encoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ arith_encode(cinfo, st, (m & v) ? 1 : 0);
+ }
+
+ /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */
+
+ tbl = compptr->ac_tbl_no;
+
+ /* Establish EOB (end-of-block) index */
+ for (ke = cinfo->lim_Se; ke > 0; ke--)
+ if ((*block)[natural_order[ke]]) break;
+
+ /* Figure F.5: Encode_AC_Coefficients */
+ for (k = 1; k <= ke; k++) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ arith_encode(cinfo, st, 0); /* EOB decision */
+ while ((v = (*block)[natural_order[k]]) == 0) {
+ arith_encode(cinfo, st + 1, 0); st += 3; k++;
+ }
+ arith_encode(cinfo, st + 1, 1);
+ /* Figure F.6: Encoding nonzero value v */
+ /* Figure F.7: Encoding the sign of v */
+ if (v > 0) {
+ arith_encode(cinfo, entropy->fixed_bin, 0);
+ } else {
+ v = -v;
+ arith_encode(cinfo, entropy->fixed_bin, 1);
+ }
+ st += 2;
+ /* Figure F.8: Encoding the magnitude category of v */
+ m = 0;
+ if (v -= 1) {
+ arith_encode(cinfo, st, 1);
+ m = 1;
+ v2 = v;
+ if (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st = entropy->ac_stats[tbl] +
+ (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+ while (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st += 1;
+ }
+ }
+ }
+ arith_encode(cinfo, st, 0);
+ /* Figure F.9: Encoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ arith_encode(cinfo, st, (m & v) ? 1 : 0);
+ }
+ /* Encode EOB decision only if k <= cinfo->lim_Se */
+ if (k <= cinfo->lim_Se) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ arith_encode(cinfo, st, 1);
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Initialize for an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass (j_compress_ptr cinfo, boolean gather_statistics)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ int ci, tbl;
+ jpeg_component_info * compptr;
+
+ if (gather_statistics)
+ /* Make sure to avoid that in the master control logic!
+ * We are fully adaptive here and need no extra
+ * statistics gathering pass!
+ */
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+
+ /* We assume jcmaster.c already validated the progressive scan parameters. */
+
+ /* Select execution routines */
+ if (cinfo->progressive_mode) {
+ if (cinfo->Ah == 0) {
+ if (cinfo->Ss == 0)
+ entropy->pub.encode_mcu = encode_mcu_DC_first;
+ else
+ entropy->pub.encode_mcu = encode_mcu_AC_first;
+ } else {
+ if (cinfo->Ss == 0)
+ entropy->pub.encode_mcu = encode_mcu_DC_refine;
+ else
+ entropy->pub.encode_mcu = encode_mcu_AC_refine;
+ }
+ } else
+ entropy->pub.encode_mcu = encode_mcu;
+
+ /* Allocate & initialize requested statistics areas */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+ tbl = compptr->dc_tbl_no;
+ if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+ ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+ if (entropy->dc_stats[tbl] == NULL)
+ entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);
+ MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
+ /* Initialize DC predictions to 0 */
+ entropy->last_dc_val[ci] = 0;
+ entropy->dc_context[ci] = 0;
+ }
+ /* AC needs no table when not present */
+ if (cinfo->Se) {
+ tbl = compptr->ac_tbl_no;
+ if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+ ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+ if (entropy->ac_stats[tbl] == NULL)
+ entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);
+ MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
+#ifdef CALCULATE_SPECTRAL_CONDITIONING
+ if (cinfo->progressive_mode)
+ /* Section G.1.3.2: Set appropriate arithmetic conditioning value Kx */
+ cinfo->arith_ac_K[tbl] = cinfo->Ss + ((8 + cinfo->Se - cinfo->Ss) >> 4);
+#endif
+ }
+ }
+
+ /* Initialize arithmetic encoding variables */
+ entropy->c = 0;
+ entropy->a = 0x10000L;
+ entropy->sc = 0;
+ entropy->zc = 0;
+ entropy->ct = 11;
+ entropy->buffer = -1; /* empty */
+
+ /* Initialize restart stuff */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num = 0;
+}
+
+
+/*
+ * Module initialization routine for arithmetic entropy encoding.
+ */
+
+GLOBAL(void)
+jinit_arith_encoder (j_compress_ptr cinfo)
+{
+ arith_entropy_ptr entropy;
+ int i;
+
+ entropy = (arith_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(arith_entropy_encoder));
+ cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
+ entropy->pub.start_pass = start_pass;
+ entropy->pub.finish_pass = finish_pass;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ entropy->dc_stats[i] = NULL;
+ entropy->ac_stats[i] = NULL;
+ }
+
+ /* Initialize index for fixed probability estimation */
+ entropy->fixed_bin[0] = 113;
+}
diff --git a/external/jpeg-8c/jccoefct.c b/external/jpeg-8c/jccoefct.c
new file mode 100644
index 0000000..d775313
--- /dev/null
+++ b/external/jpeg-8c/jccoefct.c
@@ -0,0 +1,453 @@
+/*
+ * jccoefct.c
+ *
+ * Copyright (C) 1994-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 the coefficient buffer controller for compression.
+ * This controller is the top level of the JPEG compressor proper.
+ * The coefficient buffer lies between forward-DCT and entropy encoding steps.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* We use a full-image coefficient buffer when doing Huffman optimization,
+ * and also for writing multiple-scan JPEG files. In all cases, the DCT
+ * step is run during the first pass, and subsequent passes need only read
+ * the buffered coefficients.
+ */
+#ifdef ENTROPY_OPT_SUPPORTED
+#define FULL_COEF_BUFFER_SUPPORTED
+#else
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+#define FULL_COEF_BUFFER_SUPPORTED
+#endif
+#endif
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_coef_controller pub; /* public fields */
+
+ JDIMENSION iMCU_row_num; /* iMCU row # within image */
+ JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* For single-pass compression, it's sufficient to buffer just one MCU
+ * (although this may prove a bit slow in practice). We allocate a
+ * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each
+ * MCU constructed and sent. (On 80x86, the workspace is FAR even though
+ * it's not really very big; this is to keep the module interfaces unchanged
+ * when a large coefficient buffer is necessary.)
+ * In multi-pass modes, this array points to the current MCU's blocks
+ * within the virtual arrays.
+ */
+ JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
+
+ /* In multi-pass modes, we need a virtual block array for each component. */
+ jvirt_barray_ptr whole_image[MAX_COMPONENTS];
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+
+/* Forward declarations */
+METHODDEF(boolean) compress_data
+ JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+METHODDEF(boolean) compress_first_pass
+ JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+METHODDEF(boolean) compress_output
+ JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+#endif
+
+
+LOCAL(void)
+start_iMCU_row (j_compress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row */
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ coef->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ coef->mcu_ctr = 0;
+ coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ coef->iMCU_row_num = 0;
+ start_iMCU_row(cinfo);
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (coef->whole_image[0] != NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ coef->pub.compress_data = compress_data;
+ break;
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+ case JBUF_SAVE_AND_PASS:
+ if (coef->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ coef->pub.compress_data = compress_first_pass;
+ break;
+ case JBUF_CRANK_DEST:
+ if (coef->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ coef->pub.compress_data = compress_output;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+}
+
+
+/*
+ * Process some data in the single-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the image.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf contains a plane for each component in image,
+ * which we index according to the component's SOF position.
+ */
+
+METHODDEF(boolean)
+compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int blkn, bi, ci, yindex, yoffset, blockcnt;
+ JDIMENSION ypos, xpos;
+ jpeg_component_info *compptr;
+ forward_DCT_ptr forward_DCT;
+
+ /* Loop to write as much as one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col;
+ MCU_col_num++) {
+ /* Determine where data comes from in input_buf and do the DCT thing.
+ * Each call on forward_DCT processes a horizontal row of DCT blocks
+ * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
+ * sequentially. Dummy blocks at the right or bottom edge are filled in
+ * specially. The data in them does not matter for image reconstruction,
+ * so we fill them with values that will encode to the smallest amount of
+ * data, viz: all zeroes in the AC entries, DC entries equal to previous
+ * block's DC value. (Thanks to Thomas Kinsman for this idea.)
+ */
+ blkn = 0;
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ forward_DCT = cinfo->fdct->forward_DCT[compptr->component_index];
+ blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+ : compptr->last_col_width;
+ xpos = MCU_col_num * compptr->MCU_sample_width;
+ ypos = yoffset * compptr->DCT_v_scaled_size;
+ /* ypos == (yoffset+yindex) * DCTSIZE */
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ if (coef->iMCU_row_num < last_iMCU_row ||
+ yoffset+yindex < compptr->last_row_height) {
+ (*forward_DCT) (cinfo, compptr,
+ input_buf[compptr->component_index],
+ coef->MCU_buffer[blkn],
+ ypos, xpos, (JDIMENSION) blockcnt);
+ if (blockcnt < compptr->MCU_width) {
+ /* Create some dummy blocks at the right edge of the image. */
+ jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt],
+ (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK));
+ for (bi = blockcnt; bi < compptr->MCU_width; bi++) {
+ coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0];
+ }
+ }
+ } else {
+ /* Create a row of dummy blocks at the bottom of the image. */
+ jzero_far((void FAR *) coef->MCU_buffer[blkn],
+ compptr->MCU_width * SIZEOF(JBLOCK));
+ for (bi = 0; bi < compptr->MCU_width; bi++) {
+ coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0];
+ }
+ }
+ blkn += compptr->MCU_width;
+ ypos += compptr->DCT_v_scaled_size;
+ }
+ }
+ /* Try to write the MCU. In event of a suspension failure, we will
+ * re-DCT the MCU on restart (a bit inefficient, could be fixed...)
+ */
+ if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->mcu_ctr = MCU_col_num;
+ return FALSE;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->mcu_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ coef->iMCU_row_num++;
+ start_iMCU_row(cinfo);
+ return TRUE;
+}
+
+
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+
+/*
+ * Process some data in the first pass of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the image.
+ * This amount of data is read from the source buffer, DCT'd and quantized,
+ * and saved into the virtual arrays. We also generate suitable dummy blocks
+ * as needed at the right and lower edges. (The dummy blocks are constructed
+ * in the virtual arrays, which have been padded appropriately.) This makes
+ * it possible for subsequent passes not to worry about real vs. dummy blocks.
+ *
+ * We must also emit the data to the entropy encoder. This is conveniently
+ * done by calling compress_output() after we've loaded the current strip
+ * of the virtual arrays.
+ *
+ * NB: input_buf contains a plane for each component in image. All
+ * components are DCT'd and loaded into the virtual arrays in this pass.
+ * However, it may be that only a subset of the components are emitted to
+ * the entropy encoder during this first pass; be careful about looking
+ * at the scan-dependent variables (MCU dimensions, etc).
+ */
+
+METHODDEF(boolean)
+compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ JDIMENSION blocks_across, MCUs_across, MCUindex;
+ int bi, ci, h_samp_factor, block_row, block_rows, ndummy;
+ JCOEF lastDC;
+ jpeg_component_info *compptr;
+ JBLOCKARRAY buffer;
+ JBLOCKROW thisblockrow, lastblockrow;
+ forward_DCT_ptr forward_DCT;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Align the virtual buffer for this component. */
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ coef->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ /* Count non-dummy DCT block rows in this iMCU row. */
+ if (coef->iMCU_row_num < last_iMCU_row)
+ block_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here, since may not be set! */
+ block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (block_rows == 0) block_rows = compptr->v_samp_factor;
+ }
+ blocks_across = compptr->width_in_blocks;
+ h_samp_factor = compptr->h_samp_factor;
+ /* Count number of dummy blocks to be added at the right margin. */
+ ndummy = (int) (blocks_across % h_samp_factor);
+ if (ndummy > 0)
+ ndummy = h_samp_factor - ndummy;
+ forward_DCT = cinfo->fdct->forward_DCT[ci];
+ /* Perform DCT for all non-dummy blocks in this iMCU row. Each call
+ * on forward_DCT processes a complete horizontal row of DCT blocks.
+ */
+ for (block_row = 0; block_row < block_rows; block_row++) {
+ thisblockrow = buffer[block_row];
+ (*forward_DCT) (cinfo, compptr, input_buf[ci], thisblockrow,
+ (JDIMENSION) (block_row * compptr->DCT_v_scaled_size),
+ (JDIMENSION) 0, blocks_across);
+ if (ndummy > 0) {
+ /* Create dummy blocks at the right edge of the image. */
+ thisblockrow += blocks_across; /* => first dummy block */
+ jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK));
+ lastDC = thisblockrow[-1][0];
+ for (bi = 0; bi < ndummy; bi++) {
+ thisblockrow[bi][0] = lastDC;
+ }
+ }
+ }
+ /* If at end of image, create dummy block rows as needed.
+ * The tricky part here is that within each MCU, we want the DC values
+ * of the dummy blocks to match the last real block's DC value.
+ * This squeezes a few more bytes out of the resulting file...
+ */
+ if (coef->iMCU_row_num == last_iMCU_row) {
+ blocks_across += ndummy; /* include lower right corner */
+ MCUs_across = blocks_across / h_samp_factor;
+ for (block_row = block_rows; block_row < compptr->v_samp_factor;
+ block_row++) {
+ thisblockrow = buffer[block_row];
+ lastblockrow = buffer[block_row-1];
+ jzero_far((void FAR *) thisblockrow,
+ (size_t) (blocks_across * SIZEOF(JBLOCK)));
+ for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) {
+ lastDC = lastblockrow[h_samp_factor-1][0];
+ for (bi = 0; bi < h_samp_factor; bi++) {
+ thisblockrow[bi][0] = lastDC;
+ }
+ thisblockrow += h_samp_factor; /* advance to next MCU in row */
+ lastblockrow += h_samp_factor;
+ }
+ }
+ }
+ }
+ /* NB: compress_output will increment iMCU_row_num if successful.
+ * A suspension return will result in redoing all the work above next time.
+ */
+
+ /* Emit data to the entropy encoder, sharing code with subsequent passes */
+ return compress_output(cinfo, input_buf);
+}
+
+
+/*
+ * Process some data in subsequent passes of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the scan.
+ * The data is obtained from the virtual arrays and fed to the entropy coder.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf is ignored; it is likely to be a NULL pointer.
+ */
+
+METHODDEF(boolean)
+compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ int blkn, ci, xindex, yindex, yoffset;
+ JDIMENSION start_col;
+ JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+ JBLOCKROW buffer_ptr;
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan.
+ * NB: during first pass, this is safe only because the buffers will
+ * already be aligned properly, so jmemmgr.c won't need to do any I/O.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ buffer[ci] = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+ coef->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ }
+
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
+ MCU_col_num++) {
+ /* Construct list of pointers to DCT blocks belonging to this MCU */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ start_col = MCU_col_num * compptr->MCU_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
+ coef->MCU_buffer[blkn++] = buffer_ptr++;
+ }
+ }
+ }
+ /* Try to write the MCU. */
+ if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->mcu_ctr = MCU_col_num;
+ return FALSE;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->mcu_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ coef->iMCU_row_num++;
+ start_iMCU_row(cinfo);
+ return TRUE;
+}
+
+#endif /* FULL_COEF_BUFFER_SUPPORTED */
+
+
+/*
+ * Initialize coefficient buffer controller.
+ */
+
+GLOBAL(void)
+jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+ my_coef_ptr coef;
+
+ coef = (my_coef_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_coef_controller));
+ cinfo->coef = (struct jpeg_c_coef_controller *) coef;
+ coef->pub.start_pass = start_pass_coef;
+
+ /* Create the coefficient buffer. */
+ if (need_full_buffer) {
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+ /* Allocate a full-image virtual array for each component, */
+ /* padded to a multiple of samp_factor DCT blocks in each direction. */
+ int ci;
+ jpeg_component_info *compptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION) jround_up((long) compptr->width_in_blocks,
+ (long) compptr->h_samp_factor),
+ (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+ (long) compptr->v_samp_factor),
+ (JDIMENSION) compptr->v_samp_factor);
+ }
+#else
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+ } else {
+ /* We only need a single-MCU buffer. */
+ JBLOCKROW buffer;
+ int i;
+
+ buffer = (JBLOCKROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
+ coef->MCU_buffer[i] = buffer + i;
+ }
+ coef->whole_image[0] = NULL; /* flag for no virtual arrays */
+ }
+}
diff --git a/external/jpeg-8c/jccolor.c b/external/jpeg-8c/jccolor.c
new file mode 100644
index 0000000..0a8a4b5
--- /dev/null
+++ b/external/jpeg-8c/jccolor.c
@@ -0,0 +1,459 @@
+/*
+ * jccolor.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains input colorspace conversion routines.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_color_converter pub; /* public fields */
+
+ /* Private state for RGB->YCC conversion */
+ INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */
+} my_color_converter;
+
+typedef my_color_converter * my_cconvert_ptr;
+
+
+/**************** RGB -> YCbCr conversion: most common case **************/
+
+/*
+ * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+ * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * The conversion equations to be implemented are therefore
+ * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
+ * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE
+ * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE
+ * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
+ * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2,
+ * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and
+ * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0)
+ * were not represented exactly. Now we sacrifice exact representation of
+ * maximum red and maximum blue in order to get exact grayscales.
+ *
+ * To avoid floating-point arithmetic, we represent the fractional constants
+ * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+ * the products by 2^16, with appropriate rounding, to get the correct answer.
+ *
+ * For even more speed, we avoid doing any multiplications in the inner loop
+ * by precalculating the constants times R,G,B for all possible values.
+ * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * for 12-bit samples it is still acceptable. It's not very reasonable for
+ * 16-bit samples, but if you want lossless storage you shouldn't be changing
+ * colorspace anyway.
+ * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
+ * in the tables to save adding them separately in the inner loop.
+ */
+
+#define SCALEBITS 16 /* speediest right-shift on some machines */
+#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS)
+#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
+#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
+
+/* We allocate one big table and divide it up into eight parts, instead of
+ * doing eight alloc_small requests. This lets us use a single table base
+ * address, which can be held in a register in the inner loops on many
+ * machines (more than can hold all eight addresses, anyway).
+ */
+
+#define R_Y_OFF 0 /* offset to R => Y section */
+#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */
+#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */
+#define R_CB_OFF (3*(MAXJSAMPLE+1))
+#define G_CB_OFF (4*(MAXJSAMPLE+1))
+#define B_CB_OFF (5*(MAXJSAMPLE+1))
+#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */
+#define G_CR_OFF (6*(MAXJSAMPLE+1))
+#define B_CR_OFF (7*(MAXJSAMPLE+1))
+#define TABLE_SIZE (8*(MAXJSAMPLE+1))
+
+
+/*
+ * Initialize for RGB->YCC colorspace conversion.
+ */
+
+METHODDEF(void)
+rgb_ycc_start (j_compress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ INT32 * rgb_ycc_tab;
+ INT32 i;
+
+ /* Allocate and fill in the conversion tables. */
+ cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (TABLE_SIZE * SIZEOF(INT32)));
+
+ for (i = 0; i <= MAXJSAMPLE; i++) {
+ rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i;
+ rgb_ycc_tab[i+G_Y_OFF] = FIX(0.58700) * i;
+ rgb_ycc_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF;
+ rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i;
+ rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i;
+ /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.
+ * This ensures that the maximum output will round to MAXJSAMPLE
+ * not MAXJSAMPLE+1, and thus that we don't have to range-limit.
+ */
+ rgb_ycc_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1;
+/* B=>Cb and R=>Cr tables are the same
+ rgb_ycc_tab[i+R_CR_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1;
+*/
+ rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i;
+ rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i;
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ *
+ * Note that we change from the application's interleaved-pixel format
+ * to our internal noninterleaved, one-plane-per-component format.
+ * The input buffer is therefore three times as wide as the output buffer.
+ *
+ * A starting row offset is provided only for the output buffer. The caller
+ * can easily adjust the passed input_buf value to accommodate any row
+ * offset required on that side.
+ */
+
+METHODDEF(void)
+rgb_ycc_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int r, g, b;
+ register INT32 * ctab = cconvert->rgb_ycc_tab;
+ register JSAMPROW inptr;
+ register JSAMPROW outptr0, outptr1, outptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr0 = output_buf[0][output_row];
+ outptr1 = output_buf[1][output_row];
+ outptr2 = output_buf[2][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ r = GETJSAMPLE(inptr[RGB_RED]);
+ g = GETJSAMPLE(inptr[RGB_GREEN]);
+ b = GETJSAMPLE(inptr[RGB_BLUE]);
+ inptr += RGB_PIXELSIZE;
+ /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+ * must be too; we do not need an explicit range-limiting operation.
+ * Hence the value being shifted is never negative, and we don't
+ * need the general RIGHT_SHIFT macro.
+ */
+ /* Y */
+ outptr0[col] = (JSAMPLE)
+ ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+ >> SCALEBITS);
+ /* Cb */
+ outptr1[col] = (JSAMPLE)
+ ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
+ >> SCALEBITS);
+ /* Cr */
+ outptr2[col] = (JSAMPLE)
+ ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
+ >> SCALEBITS);
+ }
+ }
+}
+
+
+/**************** Cases other than RGB -> YCbCr **************/
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles RGB->grayscale conversion, which is the same
+ * as the RGB->Y portion of RGB->YCbCr.
+ * We assume rgb_ycc_start has been called (we only use the Y tables).
+ */
+
+METHODDEF(void)
+rgb_gray_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int r, g, b;
+ register INT32 * ctab = cconvert->rgb_ycc_tab;
+ register JSAMPROW inptr;
+ register JSAMPROW outptr;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr = output_buf[0][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ r = GETJSAMPLE(inptr[RGB_RED]);
+ g = GETJSAMPLE(inptr[RGB_GREEN]);
+ b = GETJSAMPLE(inptr[RGB_BLUE]);
+ inptr += RGB_PIXELSIZE;
+ /* Y */
+ outptr[col] = (JSAMPLE)
+ ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+ >> SCALEBITS);
+ }
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles Adobe-style CMYK->YCCK conversion,
+ * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same
+ * conversion as above, while passing K (black) unchanged.
+ * We assume rgb_ycc_start has been called.
+ */
+
+METHODDEF(void)
+cmyk_ycck_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int r, g, b;
+ register INT32 * ctab = cconvert->rgb_ycc_tab;
+ register JSAMPROW inptr;
+ register JSAMPROW outptr0, outptr1, outptr2, outptr3;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr0 = output_buf[0][output_row];
+ outptr1 = output_buf[1][output_row];
+ outptr2 = output_buf[2][output_row];
+ outptr3 = output_buf[3][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ r = MAXJSAMPLE - GETJSAMPLE(inptr[0]);
+ g = MAXJSAMPLE - GETJSAMPLE(inptr[1]);
+ b = MAXJSAMPLE - GETJSAMPLE(inptr[2]);
+ /* K passes through as-is */
+ outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */
+ inptr += 4;
+ /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+ * must be too; we do not need an explicit range-limiting operation.
+ * Hence the value being shifted is never negative, and we don't
+ * need the general RIGHT_SHIFT macro.
+ */
+ /* Y */
+ outptr0[col] = (JSAMPLE)
+ ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+ >> SCALEBITS);
+ /* Cb */
+ outptr1[col] = (JSAMPLE)
+ ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
+ >> SCALEBITS);
+ /* Cr */
+ outptr2[col] = (JSAMPLE)
+ ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
+ >> SCALEBITS);
+ }
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles grayscale output with no conversion.
+ * The source can be either plain grayscale or YCbCr (since Y == gray).
+ */
+
+METHODDEF(void)
+grayscale_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ register JSAMPROW inptr;
+ register JSAMPROW outptr;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+ int instride = cinfo->input_components;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr = output_buf[0][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */
+ inptr += instride;
+ }
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles multi-component colorspaces without conversion.
+ * We assume input_components == num_components.
+ */
+
+METHODDEF(void)
+null_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ register JSAMPROW inptr;
+ register JSAMPROW outptr;
+ register JDIMENSION col;
+ register int ci;
+ int nc = cinfo->num_components;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ /* It seems fastest to make a separate pass for each component. */
+ for (ci = 0; ci < nc; ci++) {
+ inptr = *input_buf;
+ outptr = output_buf[ci][output_row];
+ for (col = 0; col < num_cols; col++) {
+ outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */
+ inptr += nc;
+ }
+ }
+ input_buf++;
+ output_row++;
+ }
+}
+
+
+/*
+ * Empty method for start_pass.
+ */
+
+METHODDEF(void)
+null_method (j_compress_ptr cinfo)
+{
+ /* no work needed */
+}
+
+
+/*
+ * Module initialization routine for input colorspace conversion.
+ */
+
+GLOBAL(void)
+jinit_color_converter (j_compress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert;
+
+ cconvert = (my_cconvert_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_color_converter));
+ cinfo->cconvert = (struct jpeg_color_converter *) cconvert;
+ /* set start_pass to null method until we find out differently */
+ cconvert->pub.start_pass = null_method;
+
+ /* Make sure input_components agrees with in_color_space */
+ switch (cinfo->in_color_space) {
+ case JCS_GRAYSCALE:
+ if (cinfo->input_components != 1)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+
+ case JCS_RGB:
+#if RGB_PIXELSIZE != 3
+ if (cinfo->input_components != RGB_PIXELSIZE)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+#endif /* else share code with YCbCr */
+
+ case JCS_YCbCr:
+ if (cinfo->input_components != 3)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+
+ case JCS_CMYK:
+ case JCS_YCCK:
+ if (cinfo->input_components != 4)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+
+ default: /* JCS_UNKNOWN can be anything */
+ if (cinfo->input_components < 1)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+ }
+
+ /* Check num_components, set conversion method based on requested space */
+ switch (cinfo->jpeg_color_space) {
+ case JCS_GRAYSCALE:
+ if (cinfo->num_components != 1)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_GRAYSCALE)
+ cconvert->pub.color_convert = grayscale_convert;
+ else if (cinfo->in_color_space == JCS_RGB) {
+ cconvert->pub.start_pass = rgb_ycc_start;
+ cconvert->pub.color_convert = rgb_gray_convert;
+ } else if (cinfo->in_color_space == JCS_YCbCr)
+ cconvert->pub.color_convert = grayscale_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_RGB:
+ if (cinfo->num_components != 3)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_RGB && RGB_PIXELSIZE == 3)
+ cconvert->pub.color_convert = null_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_YCbCr:
+ if (cinfo->num_components != 3)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_RGB) {
+ cconvert->pub.start_pass = rgb_ycc_start;
+ cconvert->pub.color_convert = rgb_ycc_convert;
+ } else if (cinfo->in_color_space == JCS_YCbCr)
+ cconvert->pub.color_convert = null_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_CMYK:
+ if (cinfo->num_components != 4)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_CMYK)
+ cconvert->pub.color_convert = null_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_YCCK:
+ if (cinfo->num_components != 4)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_CMYK) {
+ cconvert->pub.start_pass = rgb_ycc_start;
+ cconvert->pub.color_convert = cmyk_ycck_convert;
+ } else if (cinfo->in_color_space == JCS_YCCK)
+ cconvert->pub.color_convert = null_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ default: /* allow null conversion of JCS_UNKNOWN */
+ if (cinfo->jpeg_color_space != cinfo->in_color_space ||
+ cinfo->num_components != cinfo->input_components)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ cconvert->pub.color_convert = null_convert;
+ break;
+ }
+}
diff --git a/external/jpeg-8c/jcdctmgr.c b/external/jpeg-8c/jcdctmgr.c
new file mode 100644
index 0000000..0bbdbb6
--- /dev/null
+++ b/external/jpeg-8c/jcdctmgr.c
@@ -0,0 +1,482 @@
+/*
+ * jcdctmgr.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the forward-DCT management logic.
+ * This code selects a particular DCT implementation to be used,
+ * and it performs related housekeeping chores including coefficient
+ * quantization.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+
+/* Private subobject for this module */
+
+typedef struct {
+ struct jpeg_forward_dct pub; /* public fields */
+
+ /* Pointer to the DCT routine actually in use */
+ forward_DCT_method_ptr do_dct[MAX_COMPONENTS];
+
+ /* The actual post-DCT divisors --- not identical to the quant table
+ * entries, because of scaling (especially for an unnormalized DCT).
+ * Each table is given in normal array order.
+ */
+ DCTELEM * divisors[NUM_QUANT_TBLS];
+
+#ifdef DCT_FLOAT_SUPPORTED
+ /* Same as above for the floating-point case. */
+ float_DCT_method_ptr do_float_dct[MAX_COMPONENTS];
+ FAST_FLOAT * float_divisors[NUM_QUANT_TBLS];
+#endif
+} my_fdct_controller;
+
+typedef my_fdct_controller * my_fdct_ptr;
+
+
+/* The current scaled-DCT routines require ISLOW-style divisor tables,
+ * so be sure to compile that code if either ISLOW or SCALING is requested.
+ */
+#ifdef DCT_ISLOW_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#else
+#ifdef DCT_SCALING_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#endif
+#endif
+
+
+/*
+ * Perform forward DCT on one or more blocks of a component.
+ *
+ * The input samples are taken from the sample_data[] array starting at
+ * position start_row/start_col, and moving to the right for any additional
+ * blocks. The quantized coefficients are returned in coef_blocks[].
+ */
+
+METHODDEF(void)
+forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks)
+/* This version is used for integer DCT implementations. */
+{
+ /* This routine is heavily used, so it's worth coding it tightly. */
+ my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+ forward_DCT_method_ptr do_dct = fdct->do_dct[compptr->component_index];
+ DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no];
+ DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */
+ JDIMENSION bi;
+
+ sample_data += start_row; /* fold in the vertical offset once */
+
+ for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) {
+ /* Perform the DCT */
+ (*do_dct) (workspace, sample_data, start_col);
+
+ /* Quantize/descale the coefficients, and store into coef_blocks[] */
+ { register DCTELEM temp, qval;
+ register int i;
+ register JCOEFPTR output_ptr = coef_blocks[bi];
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ qval = divisors[i];
+ temp = workspace[i];
+ /* Divide the coefficient value by qval, ensuring proper rounding.
+ * Since C does not specify the direction of rounding for negative
+ * quotients, we have to force the dividend positive for portability.
+ *
+ * In most files, at least half of the output values will be zero
+ * (at default quantization settings, more like three-quarters...)
+ * so we should ensure that this case is fast. On many machines,
+ * a comparison is enough cheaper than a divide to make a special test
+ * a win. Since both inputs will be nonnegative, we need only test
+ * for a < b to discover whether a/b is 0.
+ * If your machine's division is fast enough, define FAST_DIVIDE.
+ */
+#ifdef FAST_DIVIDE
+#define DIVIDE_BY(a,b) a /= b
+#else
+#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0
+#endif
+ if (temp < 0) {
+ temp = -temp;
+ temp += qval>>1; /* for rounding */
+ DIVIDE_BY(temp, qval);
+ temp = -temp;
+ } else {
+ temp += qval>>1; /* for rounding */
+ DIVIDE_BY(temp, qval);
+ }
+ output_ptr[i] = (JCOEF) temp;
+ }
+ }
+ }
+}
+
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+METHODDEF(void)
+forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks)
+/* This version is used for floating-point DCT implementations. */
+{
+ /* This routine is heavily used, so it's worth coding it tightly. */
+ my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+ float_DCT_method_ptr do_dct = fdct->do_float_dct[compptr->component_index];
+ FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no];
+ FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */
+ JDIMENSION bi;
+
+ sample_data += start_row; /* fold in the vertical offset once */
+
+ for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) {
+ /* Perform the DCT */
+ (*do_dct) (workspace, sample_data, start_col);
+
+ /* Quantize/descale the coefficients, and store into coef_blocks[] */
+ { register FAST_FLOAT temp;
+ register int i;
+ register JCOEFPTR output_ptr = coef_blocks[bi];
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ /* Apply the quantization and scaling factor */
+ temp = workspace[i] * divisors[i];
+ /* Round to nearest integer.
+ * Since C does not specify the direction of rounding for negative
+ * quotients, we have to force the dividend positive for portability.
+ * The maximum coefficient size is +-16K (for 12-bit data), so this
+ * code should work for either 16-bit or 32-bit ints.
+ */
+ output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384);
+ }
+ }
+ }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
+
+
+/*
+ * Initialize for a processing pass.
+ * Verify that all referenced Q-tables are present, and set up
+ * the divisor table for each one.
+ * In the current implementation, DCT of all components is done during
+ * the first pass, even if only some components will be output in the
+ * first scan. Hence all components should be examined here.
+ */
+
+METHODDEF(void)
+start_pass_fdctmgr (j_compress_ptr cinfo)
+{
+ my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+ int ci, qtblno, i;
+ jpeg_component_info *compptr;
+ int method = 0;
+ JQUANT_TBL * qtbl;
+ DCTELEM * dtbl;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Select the proper DCT routine for this component's scaling */
+ switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) {
+#ifdef DCT_SCALING_SUPPORTED
+ case ((1 << 8) + 1):
+ fdct->do_dct[ci] = jpeg_fdct_1x1;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((2 << 8) + 2):
+ fdct->do_dct[ci] = jpeg_fdct_2x2;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((3 << 8) + 3):
+ fdct->do_dct[ci] = jpeg_fdct_3x3;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((4 << 8) + 4):
+ fdct->do_dct[ci] = jpeg_fdct_4x4;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((5 << 8) + 5):
+ fdct->do_dct[ci] = jpeg_fdct_5x5;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((6 << 8) + 6):
+ fdct->do_dct[ci] = jpeg_fdct_6x6;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((7 << 8) + 7):
+ fdct->do_dct[ci] = jpeg_fdct_7x7;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((9 << 8) + 9):
+ fdct->do_dct[ci] = jpeg_fdct_9x9;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((10 << 8) + 10):
+ fdct->do_dct[ci] = jpeg_fdct_10x10;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((11 << 8) + 11):
+ fdct->do_dct[ci] = jpeg_fdct_11x11;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((12 << 8) + 12):
+ fdct->do_dct[ci] = jpeg_fdct_12x12;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((13 << 8) + 13):
+ fdct->do_dct[ci] = jpeg_fdct_13x13;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((14 << 8) + 14):
+ fdct->do_dct[ci] = jpeg_fdct_14x14;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((15 << 8) + 15):
+ fdct->do_dct[ci] = jpeg_fdct_15x15;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((16 << 8) + 16):
+ fdct->do_dct[ci] = jpeg_fdct_16x16;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((16 << 8) + 8):
+ fdct->do_dct[ci] = jpeg_fdct_16x8;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((14 << 8) + 7):
+ fdct->do_dct[ci] = jpeg_fdct_14x7;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((12 << 8) + 6):
+ fdct->do_dct[ci] = jpeg_fdct_12x6;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((10 << 8) + 5):
+ fdct->do_dct[ci] = jpeg_fdct_10x5;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((8 << 8) + 4):
+ fdct->do_dct[ci] = jpeg_fdct_8x4;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((6 << 8) + 3):
+ fdct->do_dct[ci] = jpeg_fdct_6x3;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((4 << 8) + 2):
+ fdct->do_dct[ci] = jpeg_fdct_4x2;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((2 << 8) + 1):
+ fdct->do_dct[ci] = jpeg_fdct_2x1;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((8 << 8) + 16):
+ fdct->do_dct[ci] = jpeg_fdct_8x16;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((7 << 8) + 14):
+ fdct->do_dct[ci] = jpeg_fdct_7x14;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((6 << 8) + 12):
+ fdct->do_dct[ci] = jpeg_fdct_6x12;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((5 << 8) + 10):
+ fdct->do_dct[ci] = jpeg_fdct_5x10;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((4 << 8) + 8):
+ fdct->do_dct[ci] = jpeg_fdct_4x8;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((3 << 8) + 6):
+ fdct->do_dct[ci] = jpeg_fdct_3x6;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((2 << 8) + 4):
+ fdct->do_dct[ci] = jpeg_fdct_2x4;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((1 << 8) + 2):
+ fdct->do_dct[ci] = jpeg_fdct_1x2;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+#endif
+ case ((DCTSIZE << 8) + DCTSIZE):
+ switch (cinfo->dct_method) {
+#ifdef DCT_ISLOW_SUPPORTED
+ case JDCT_ISLOW:
+ fdct->do_dct[ci] = jpeg_fdct_islow;
+ method = JDCT_ISLOW;
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ fdct->do_dct[ci] = jpeg_fdct_ifast;
+ method = JDCT_IFAST;
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ fdct->do_float_dct[ci] = jpeg_fdct_float;
+ method = JDCT_FLOAT;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ break;
+ default:
+ ERREXIT2(cinfo, JERR_BAD_DCTSIZE,
+ compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size);
+ break;
+ }
+ qtblno = compptr->quant_tbl_no;
+ /* Make sure specified quantization table is present */
+ if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
+ cinfo->quant_tbl_ptrs[qtblno] == NULL)
+ ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
+ qtbl = cinfo->quant_tbl_ptrs[qtblno];
+ /* Compute divisors for this quant table */
+ /* We may do this more than once for same table, but it's not a big deal */
+ switch (method) {
+#ifdef PROVIDE_ISLOW_TABLES
+ case JDCT_ISLOW:
+ /* For LL&M IDCT method, divisors are equal to raw quantization
+ * coefficients multiplied by 8 (to counteract scaling).
+ */
+ if (fdct->divisors[qtblno] == NULL) {
+ fdct->divisors[qtblno] = (DCTELEM *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ DCTSIZE2 * SIZEOF(DCTELEM));
+ }
+ dtbl = fdct->divisors[qtblno];
+ for (i = 0; i < DCTSIZE2; i++) {
+ dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3;
+ }
+ fdct->pub.forward_DCT[ci] = forward_DCT;
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ {
+ /* For AA&N IDCT method, divisors are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * We apply a further scale factor of 8.
+ */
+#define CONST_BITS 14
+ static const INT16 aanscales[DCTSIZE2] = {
+ /* precomputed values scaled up by 14 bits */
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
+ 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
+ 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
+ 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
+ 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
+ };
+ SHIFT_TEMPS
+
+ if (fdct->divisors[qtblno] == NULL) {
+ fdct->divisors[qtblno] = (DCTELEM *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ DCTSIZE2 * SIZEOF(DCTELEM));
+ }
+ dtbl = fdct->divisors[qtblno];
+ for (i = 0; i < DCTSIZE2; i++) {
+ dtbl[i] = (DCTELEM)
+ DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
+ (INT32) aanscales[i]),
+ CONST_BITS-3);
+ }
+ }
+ fdct->pub.forward_DCT[ci] = forward_DCT;
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ {
+ /* For float AA&N IDCT method, divisors are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * We apply a further scale factor of 8.
+ * What's actually stored is 1/divisor so that the inner loop can
+ * use a multiplication rather than a division.
+ */
+ FAST_FLOAT * fdtbl;
+ int row, col;
+ static const double aanscalefactor[DCTSIZE] = {
+ 1.0, 1.387039845, 1.306562965, 1.175875602,
+ 1.0, 0.785694958, 0.541196100, 0.275899379
+ };
+
+ if (fdct->float_divisors[qtblno] == NULL) {
+ fdct->float_divisors[qtblno] = (FAST_FLOAT *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ DCTSIZE2 * SIZEOF(FAST_FLOAT));
+ }
+ fdtbl = fdct->float_divisors[qtblno];
+ i = 0;
+ for (row = 0; row < DCTSIZE; row++) {
+ for (col = 0; col < DCTSIZE; col++) {
+ fdtbl[i] = (FAST_FLOAT)
+ (1.0 / (((double) qtbl->quantval[i] *
+ aanscalefactor[row] * aanscalefactor[col] * 8.0)));
+ i++;
+ }
+ }
+ }
+ fdct->pub.forward_DCT[ci] = forward_DCT_float;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ }
+}
+
+
+/*
+ * Initialize FDCT manager.
+ */
+
+GLOBAL(void)
+jinit_forward_dct (j_compress_ptr cinfo)
+{
+ my_fdct_ptr fdct;
+ int i;
+
+ fdct = (my_fdct_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_fdct_controller));
+ cinfo->fdct = (struct jpeg_forward_dct *) fdct;
+ fdct->pub.start_pass = start_pass_fdctmgr;
+
+ /* Mark divisor tables unallocated */
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ fdct->divisors[i] = NULL;
+#ifdef DCT_FLOAT_SUPPORTED
+ fdct->float_divisors[i] = NULL;
+#endif
+ }
+}
diff --git a/external/jpeg-8c/jchuff.c b/external/jpeg-8c/jchuff.c
new file mode 100644
index 0000000..257d7aa
--- /dev/null
+++ b/external/jpeg-8c/jchuff.c
@@ -0,0 +1,1576 @@
+/*
+ * jchuff.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2006-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains Huffman entropy encoding routines.
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Much of the complexity here has to do with supporting output suspension.
+ * If the data destination module demands suspension, we want to be able to
+ * back up to the start of the current MCU. To do this, we copy state
+ * variables into local working storage, and update them back to the
+ * permanent JPEG objects only upon successful completion of an MCU.
+ *
+ * We do not support output suspension for the progressive JPEG mode, since
+ * the library currently does not allow multiple-scan files to be written
+ * with output suspension.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* The legal range of a DCT coefficient is
+ * -1024 .. +1023 for 8-bit data;
+ * -16384 .. +16383 for 12-bit data.
+ * Hence the magnitude should always fit in 10 or 14 bits respectively.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MAX_COEF_BITS 10
+#else
+#define MAX_COEF_BITS 14
+#endif
+
+/* Derived data constructed for each Huffman table */
+
+typedef struct {
+ unsigned int ehufco[256]; /* code for each symbol */
+ char ehufsi[256]; /* length of code for each symbol */
+ /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */
+} c_derived_tbl;
+
+
+/* Expanded entropy encoder object for Huffman encoding.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+ INT32 put_buffer; /* current bit-accumulation buffer */
+ int put_bits; /* # of bits now in it */
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+} savable_state;
+
+/* This macro is to work around compilers with missing or broken
+ * structure assignment. You'll need to fix this code if you have
+ * such a compiler and you change MAX_COMPS_IN_SCAN.
+ */
+
+#ifndef NO_STRUCT_ASSIGN
+#define ASSIGN_STATE(dest,src) ((dest) = (src))
+#else
+#if MAX_COMPS_IN_SCAN == 4
+#define ASSIGN_STATE(dest,src) \
+ ((dest).put_buffer = (src).put_buffer, \
+ (dest).put_bits = (src).put_bits, \
+ (dest).last_dc_val[0] = (src).last_dc_val[0], \
+ (dest).last_dc_val[1] = (src).last_dc_val[1], \
+ (dest).last_dc_val[2] = (src).last_dc_val[2], \
+ (dest).last_dc_val[3] = (src).last_dc_val[3])
+#endif
+#endif
+
+
+typedef struct {
+ struct jpeg_entropy_encoder pub; /* public fields */
+
+ savable_state saved; /* Bit buffer & DC state at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+ int next_restart_num; /* next restart number to write (0-7) */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
+ c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
+
+ /* Statistics tables for optimization */
+ long * dc_count_ptrs[NUM_HUFF_TBLS];
+ long * ac_count_ptrs[NUM_HUFF_TBLS];
+
+ /* Following fields used only in progressive mode */
+
+ /* Mode flag: TRUE for optimization, FALSE for actual data output */
+ boolean gather_statistics;
+
+ /* next_output_byte/free_in_buffer are local copies of cinfo->dest fields.
+ */
+ JOCTET * next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+ j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */
+
+ /* Coding status for AC components */
+ int ac_tbl_no; /* the table number of the single component */
+ unsigned int EOBRUN; /* run length of EOBs */
+ unsigned int BE; /* # of buffered correction bits before MCU */
+ char * bit_buffer; /* buffer for correction bits (1 per char) */
+ /* packing correction bits tightly would save some space but cost time... */
+} huff_entropy_encoder;
+
+typedef huff_entropy_encoder * huff_entropy_ptr;
+
+/* Working state while writing an MCU (sequential mode).
+ * This struct contains all the fields that are needed by subroutines.
+ */
+
+typedef struct {
+ JOCTET * next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+ savable_state cur; /* Current bit buffer & DC state */
+ j_compress_ptr cinfo; /* dump_buffer needs access to this */
+} working_state;
+
+/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit
+ * buffer can hold. Larger sizes may slightly improve compression, but
+ * 1000 is already well into the realm of overkill.
+ * The minimum safe size is 64 bits.
+ */
+
+#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */
+
+/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
+ * We assume that int right shift is unsigned if INT32 right shift is,
+ * which should be safe.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS int ishift_temp;
+#define IRIGHT_SHIFT(x,shft) \
+ ((ishift_temp = (x)) < 0 ? \
+ (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \
+ (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
+#endif
+
+
+/*
+ * Compute the derived values for a Huffman table.
+ * This routine also performs some validation checks on the table.
+ */
+
+LOCAL(void)
+jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
+ c_derived_tbl ** pdtbl)
+{
+ JHUFF_TBL *htbl;
+ c_derived_tbl *dtbl;
+ int p, i, l, lastp, si, maxsymbol;
+ char huffsize[257];
+ unsigned int huffcode[257];
+ unsigned int code;
+
+ /* Note that huffsize[] and huffcode[] are filled in code-length order,
+ * paralleling the order of the symbols themselves in htbl->huffval[].
+ */
+
+ /* Find the input Huffman table */
+ if (tblno < 0 || tblno >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+ htbl =
+ isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno];
+ if (htbl == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+
+ /* Allocate a workspace if we haven't already done so. */
+ if (*pdtbl == NULL)
+ *pdtbl = (c_derived_tbl *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(c_derived_tbl));
+ dtbl = *pdtbl;
+
+ /* Figure C.1: make table of Huffman code length for each symbol */
+
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ i = (int) htbl->bits[l];
+ if (i < 0 || p + i > 256) /* protect against table overrun */
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ while (i--)
+ huffsize[p++] = (char) l;
+ }
+ huffsize[p] = 0;
+ lastp = p;
+
+ /* Figure C.2: generate the codes themselves */
+ /* We also validate that the counts represent a legal Huffman code tree. */
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while (huffsize[p]) {
+ while (((int) huffsize[p]) == si) {
+ huffcode[p++] = code;
+ code++;
+ }
+ /* code is now 1 more than the last code used for codelength si; but
+ * it must still fit in si bits, since no code is allowed to be all ones.
+ */
+ if (((INT32) code) >= (((INT32) 1) << si))
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ code <<= 1;
+ si++;
+ }
+
+ /* Figure C.3: generate encoding tables */
+ /* These are code and size indexed by symbol value */
+
+ /* Set all codeless symbols to have code length 0;
+ * this lets us detect duplicate VAL entries here, and later
+ * allows emit_bits to detect any attempt to emit such symbols.
+ */
+ MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi));
+
+ /* This is also a convenient place to check for out-of-range
+ * and duplicated VAL entries. We allow 0..255 for AC symbols
+ * but only 0..15 for DC. (We could constrain them further
+ * based on data depth and mode, but this seems enough.)
+ */
+ maxsymbol = isDC ? 15 : 255;
+
+ for (p = 0; p < lastp; p++) {
+ i = htbl->huffval[p];
+ if (i < 0 || i > maxsymbol || dtbl->ehufsi[i])
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ dtbl->ehufco[i] = huffcode[p];
+ dtbl->ehufsi[i] = huffsize[p];
+ }
+}
+
+
+/* Outputting bytes to the file.
+ * NB: these must be called only when actually outputting,
+ * that is, entropy->gather_statistics == FALSE.
+ */
+
+/* Emit a byte, taking 'action' if must suspend. */
+#define emit_byte_s(state,val,action) \
+ { *(state)->next_output_byte++ = (JOCTET) (val); \
+ if (--(state)->free_in_buffer == 0) \
+ if (! dump_buffer_s(state)) \
+ { action; } }
+
+/* Emit a byte */
+#define emit_byte_e(entropy,val) \
+ { *(entropy)->next_output_byte++ = (JOCTET) (val); \
+ if (--(entropy)->free_in_buffer == 0) \
+ dump_buffer_e(entropy); }
+
+
+LOCAL(boolean)
+dump_buffer_s (working_state * state)
+/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
+{
+ struct jpeg_destination_mgr * dest = state->cinfo->dest;
+
+ if (! (*dest->empty_output_buffer) (state->cinfo))
+ return FALSE;
+ /* After a successful buffer dump, must reset buffer pointers */
+ state->next_output_byte = dest->next_output_byte;
+ state->free_in_buffer = dest->free_in_buffer;
+ return TRUE;
+}
+
+
+LOCAL(void)
+dump_buffer_e (huff_entropy_ptr entropy)
+/* Empty the output buffer; we do not support suspension in this case. */
+{
+ struct jpeg_destination_mgr * dest = entropy->cinfo->dest;
+
+ if (! (*dest->empty_output_buffer) (entropy->cinfo))
+ ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND);
+ /* After a successful buffer dump, must reset buffer pointers */
+ entropy->next_output_byte = dest->next_output_byte;
+ entropy->free_in_buffer = dest->free_in_buffer;
+}
+
+
+/* Outputting bits to the file */
+
+/* Only the right 24 bits of put_buffer are used; the valid bits are
+ * left-justified in this part. At most 16 bits can be passed to emit_bits
+ * in one call, and we never retain more than 7 bits in put_buffer
+ * between calls, so 24 bits are sufficient.
+ */
+
+INLINE
+LOCAL(boolean)
+emit_bits_s (working_state * state, unsigned int code, int size)
+/* Emit some bits; return TRUE if successful, FALSE if must suspend */
+{
+ /* This routine is heavily used, so it's worth coding tightly. */
+ register INT32 put_buffer = (INT32) code;
+ register int put_bits = state->cur.put_bits;
+
+ /* if size is 0, caller used an invalid Huffman table entry */
+ if (size == 0)
+ ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE);
+
+ put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
+
+ put_bits += size; /* new number of bits in buffer */
+
+ put_buffer <<= 24 - put_bits; /* align incoming bits */
+
+ put_buffer |= state->cur.put_buffer; /* and merge with old buffer contents */
+
+ while (put_bits >= 8) {
+ int c = (int) ((put_buffer >> 16) & 0xFF);
+
+ emit_byte_s(state, c, return FALSE);
+ if (c == 0xFF) { /* need to stuff a zero byte? */
+ emit_byte_s(state, 0, return FALSE);
+ }
+ put_buffer <<= 8;
+ put_bits -= 8;
+ }
+
+ state->cur.put_buffer = put_buffer; /* update state variables */
+ state->cur.put_bits = put_bits;
+
+ return TRUE;
+}
+
+
+INLINE
+LOCAL(void)
+emit_bits_e (huff_entropy_ptr entropy, unsigned int code, int size)
+/* Emit some bits, unless we are in gather mode */
+{
+ /* This routine is heavily used, so it's worth coding tightly. */
+ register INT32 put_buffer = (INT32) code;
+ register int put_bits = entropy->saved.put_bits;
+
+ /* if size is 0, caller used an invalid Huffman table entry */
+ if (size == 0)
+ ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);
+
+ if (entropy->gather_statistics)
+ return; /* do nothing if we're only getting stats */
+
+ put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
+
+ put_bits += size; /* new number of bits in buffer */
+
+ put_buffer <<= 24 - put_bits; /* align incoming bits */
+
+ /* and merge with old buffer contents */
+ put_buffer |= entropy->saved.put_buffer;
+
+ while (put_bits >= 8) {
+ int c = (int) ((put_buffer >> 16) & 0xFF);
+
+ emit_byte_e(entropy, c);
+ if (c == 0xFF) { /* need to stuff a zero byte? */
+ emit_byte_e(entropy, 0);
+ }
+ put_buffer <<= 8;
+ put_bits -= 8;
+ }
+
+ entropy->saved.put_buffer = put_buffer; /* update variables */
+ entropy->saved.put_bits = put_bits;
+}
+
+
+LOCAL(boolean)
+flush_bits_s (working_state * state)
+{
+ if (! emit_bits_s(state, 0x7F, 7)) /* fill any partial byte with ones */
+ return FALSE;
+ state->cur.put_buffer = 0; /* and reset bit-buffer to empty */
+ state->cur.put_bits = 0;
+ return TRUE;
+}
+
+
+LOCAL(void)
+flush_bits_e (huff_entropy_ptr entropy)
+{
+ emit_bits_e(entropy, 0x7F, 7); /* fill any partial byte with ones */
+ entropy->saved.put_buffer = 0; /* and reset bit-buffer to empty */
+ entropy->saved.put_bits = 0;
+}
+
+
+/*
+ * Emit (or just count) a Huffman symbol.
+ */
+
+INLINE
+LOCAL(void)
+emit_dc_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol)
+{
+ if (entropy->gather_statistics)
+ entropy->dc_count_ptrs[tbl_no][symbol]++;
+ else {
+ c_derived_tbl * tbl = entropy->dc_derived_tbls[tbl_no];
+ emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
+ }
+}
+
+
+INLINE
+LOCAL(void)
+emit_ac_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol)
+{
+ if (entropy->gather_statistics)
+ entropy->ac_count_ptrs[tbl_no][symbol]++;
+ else {
+ c_derived_tbl * tbl = entropy->ac_derived_tbls[tbl_no];
+ emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
+ }
+}
+
+
+/*
+ * Emit bits from a correction bit buffer.
+ */
+
+LOCAL(void)
+emit_buffered_bits (huff_entropy_ptr entropy, char * bufstart,
+ unsigned int nbits)
+{
+ if (entropy->gather_statistics)
+ return; /* no real work */
+
+ while (nbits > 0) {
+ emit_bits_e(entropy, (unsigned int) (*bufstart), 1);
+ bufstart++;
+ nbits--;
+ }
+}
+
+
+/*
+ * Emit any pending EOBRUN symbol.
+ */
+
+LOCAL(void)
+emit_eobrun (huff_entropy_ptr entropy)
+{
+ register int temp, nbits;
+
+ if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */
+ temp = entropy->EOBRUN;
+ nbits = 0;
+ while ((temp >>= 1))
+ nbits++;
+ /* safety check: shouldn't happen given limited correction-bit buffer */
+ if (nbits > 14)
+ ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);
+
+ emit_ac_symbol(entropy, entropy->ac_tbl_no, nbits << 4);
+ if (nbits)
+ emit_bits_e(entropy, entropy->EOBRUN, nbits);
+
+ entropy->EOBRUN = 0;
+
+ /* Emit any buffered correction bits */
+ emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE);
+ entropy->BE = 0;
+ }
+}
+
+
+/*
+ * Emit a restart marker & resynchronize predictions.
+ */
+
+LOCAL(boolean)
+emit_restart_s (working_state * state, int restart_num)
+{
+ int ci;
+
+ if (! flush_bits_s(state))
+ return FALSE;
+
+ emit_byte_s(state, 0xFF, return FALSE);
+ emit_byte_s(state, JPEG_RST0 + restart_num, return FALSE);
+
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < state->cinfo->comps_in_scan; ci++)
+ state->cur.last_dc_val[ci] = 0;
+
+ /* The restart counter is not updated until we successfully write the MCU. */
+
+ return TRUE;
+}
+
+
+LOCAL(void)
+emit_restart_e (huff_entropy_ptr entropy, int restart_num)
+{
+ int ci;
+
+ emit_eobrun(entropy);
+
+ if (! entropy->gather_statistics) {
+ flush_bits_e(entropy);
+ emit_byte_e(entropy, 0xFF);
+ emit_byte_e(entropy, JPEG_RST0 + restart_num);
+ }
+
+ if (entropy->cinfo->Ss == 0) {
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++)
+ entropy->saved.last_dc_val[ci] = 0;
+ } else {
+ /* Re-initialize all AC-related fields to 0 */
+ entropy->EOBRUN = 0;
+ entropy->BE = 0;
+ }
+}
+
+
+/*
+ * MCU encoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int temp, temp2;
+ register int nbits;
+ int blkn, ci;
+ int Al = cinfo->Al;
+ JBLOCKROW block;
+ jpeg_component_info * compptr;
+ ISHIFT_TEMPS
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart_e(entropy, entropy->next_restart_num);
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+
+ /* Compute the DC value after the required point transform by Al.
+ * This is simply an arithmetic right shift.
+ */
+ temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al);
+
+ /* DC differences are figured on the point-transformed values. */
+ temp = temp2 - entropy->saved.last_dc_val[ci];
+ entropy->saved.last_dc_val[ci] = temp2;
+
+ /* Encode the DC coefficient difference per section G.1.2.1 */
+ temp2 = temp;
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ /* For a negative input, want temp2 = bitwise complement of abs(input) */
+ /* This code assumes we are on a two's complement machine */
+ temp2--;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+ /* Check for out-of-range coefficient values.
+ * Since we're encoding a difference, the range limit is twice as much.
+ */
+ if (nbits > MAX_COEF_BITS+1)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Count/emit the Huffman-coded symbol for the number of bits */
+ emit_dc_symbol(entropy, compptr->dc_tbl_no, nbits);
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ if (nbits) /* emit_bits rejects calls with size 0 */
+ emit_bits_e(entropy, (unsigned int) temp2, nbits);
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int temp, temp2;
+ register int nbits;
+ register int r, k;
+ int Se, Al;
+ const int * natural_order;
+ JBLOCKROW block;
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart_e(entropy, entropy->next_restart_num);
+
+ Se = cinfo->Se;
+ Al = cinfo->Al;
+ natural_order = cinfo->natural_order;
+
+ /* Encode the MCU data block */
+ block = MCU_data[0];
+
+ /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */
+
+ r = 0; /* r = run length of zeros */
+
+ for (k = cinfo->Ss; k <= Se; k++) {
+ if ((temp = (*block)[natural_order[k]]) == 0) {
+ r++;
+ continue;
+ }
+ /* We must apply the point transform by Al. For AC coefficients this
+ * is an integer division with rounding towards 0. To do this portably
+ * in C, we shift after obtaining the absolute value; so the code is
+ * interwoven with finding the abs value (temp) and output bits (temp2).
+ */
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ temp >>= Al; /* apply the point transform */
+ /* For a negative coef, want temp2 = bitwise complement of abs(coef) */
+ temp2 = ~temp;
+ } else {
+ temp >>= Al; /* apply the point transform */
+ temp2 = temp;
+ }
+ /* Watch out for case that nonzero coef is zero after point transform */
+ if (temp == 0) {
+ r++;
+ continue;
+ }
+
+ /* Emit any pending EOBRUN */
+ if (entropy->EOBRUN > 0)
+ emit_eobrun(entropy);
+ /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+ while (r > 15) {
+ emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0);
+ r -= 16;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 1; /* there must be at least one 1 bit */
+ while ((temp >>= 1))
+ nbits++;
+ /* Check for out-of-range coefficient values */
+ if (nbits > MAX_COEF_BITS)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Count/emit Huffman symbol for run length / number of bits */
+ emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits);
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ emit_bits_e(entropy, (unsigned int) temp2, nbits);
+
+ r = 0; /* reset zero run length */
+ }
+
+ if (r > 0) { /* If there are trailing zeroes, */
+ entropy->EOBRUN++; /* count an EOB */
+ if (entropy->EOBRUN == 0x7FFF)
+ emit_eobrun(entropy); /* force it out to avoid overflow */
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for DC successive approximation refinement scan.
+ * Note: we assume such scans can be multi-component, although the spec
+ * is not very clear on the point.
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int temp;
+ int blkn;
+ int Al = cinfo->Al;
+ JBLOCKROW block;
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart_e(entropy, entropy->next_restart_num);
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+
+ /* We simply emit the Al'th bit of the DC coefficient value. */
+ temp = (*block)[0];
+ emit_bits_e(entropy, (unsigned int) (temp >> Al), 1);
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int temp;
+ register int r, k;
+ int EOB;
+ char *BR_buffer;
+ unsigned int BR;
+ int Se, Al;
+ const int * natural_order;
+ JBLOCKROW block;
+ int absvalues[DCTSIZE2];
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart_e(entropy, entropy->next_restart_num);
+
+ Se = cinfo->Se;
+ Al = cinfo->Al;
+ natural_order = cinfo->natural_order;
+
+ /* Encode the MCU data block */
+ block = MCU_data[0];
+
+ /* It is convenient to make a pre-pass to determine the transformed
+ * coefficients' absolute values and the EOB position.
+ */
+ EOB = 0;
+ for (k = cinfo->Ss; k <= Se; k++) {
+ temp = (*block)[natural_order[k]];
+ /* We must apply the point transform by Al. For AC coefficients this
+ * is an integer division with rounding towards 0. To do this portably
+ * in C, we shift after obtaining the absolute value.
+ */
+ if (temp < 0)
+ temp = -temp; /* temp is abs value of input */
+ temp >>= Al; /* apply the point transform */
+ absvalues[k] = temp; /* save abs value for main pass */
+ if (temp == 1)
+ EOB = k; /* EOB = index of last newly-nonzero coef */
+ }
+
+ /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */
+
+ r = 0; /* r = run length of zeros */
+ BR = 0; /* BR = count of buffered bits added now */
+ BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */
+
+ for (k = cinfo->Ss; k <= Se; k++) {
+ if ((temp = absvalues[k]) == 0) {
+ r++;
+ continue;
+ }
+
+ /* Emit any required ZRLs, but not if they can be folded into EOB */
+ while (r > 15 && k <= EOB) {
+ /* emit any pending EOBRUN and the BE correction bits */
+ emit_eobrun(entropy);
+ /* Emit ZRL */
+ emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0);
+ r -= 16;
+ /* Emit buffered correction bits that must be associated with ZRL */
+ emit_buffered_bits(entropy, BR_buffer, BR);
+ BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
+ BR = 0;
+ }
+
+ /* If the coef was previously nonzero, it only needs a correction bit.
+ * NOTE: a straight translation of the spec's figure G.7 would suggest
+ * that we also need to test r > 15. But if r > 15, we can only get here
+ * if k > EOB, which implies that this coefficient is not 1.
+ */
+ if (temp > 1) {
+ /* The correction bit is the next bit of the absolute value. */
+ BR_buffer[BR++] = (char) (temp & 1);
+ continue;
+ }
+
+ /* Emit any pending EOBRUN and the BE correction bits */
+ emit_eobrun(entropy);
+
+ /* Count/emit Huffman symbol for run length / number of bits */
+ emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1);
+
+ /* Emit output bit for newly-nonzero coef */
+ temp = ((*block)[natural_order[k]] < 0) ? 0 : 1;
+ emit_bits_e(entropy, (unsigned int) temp, 1);
+
+ /* Emit buffered correction bits that must be associated with this code */
+ emit_buffered_bits(entropy, BR_buffer, BR);
+ BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
+ BR = 0;
+ r = 0; /* reset zero run length */
+ }
+
+ if (r > 0 || BR > 0) { /* If there are trailing zeroes, */
+ entropy->EOBRUN++; /* count an EOB */
+ entropy->BE += BR; /* concat my correction bits to older ones */
+ /* We force out the EOB if we risk either:
+ * 1. overflow of the EOB counter;
+ * 2. overflow of the correction bit buffer during the next MCU.
+ */
+ if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1))
+ emit_eobrun(entropy);
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/* Encode a single block's worth of coefficients */
+
+LOCAL(boolean)
+encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
+ c_derived_tbl *dctbl, c_derived_tbl *actbl)
+{
+ register int temp, temp2;
+ register int nbits;
+ register int k, r, i;
+ int Se = state->cinfo->lim_Se;
+ const int * natural_order = state->cinfo->natural_order;
+
+ /* Encode the DC coefficient difference per section F.1.2.1 */
+
+ temp = temp2 = block[0] - last_dc_val;
+
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ /* For a negative input, want temp2 = bitwise complement of abs(input) */
+ /* This code assumes we are on a two's complement machine */
+ temp2--;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+ /* Check for out-of-range coefficient values.
+ * Since we're encoding a difference, the range limit is twice as much.
+ */
+ if (nbits > MAX_COEF_BITS+1)
+ ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
+
+ /* Emit the Huffman-coded symbol for the number of bits */
+ if (! emit_bits_s(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))
+ return FALSE;
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ if (nbits) /* emit_bits rejects calls with size 0 */
+ if (! emit_bits_s(state, (unsigned int) temp2, nbits))
+ return FALSE;
+
+ /* Encode the AC coefficients per section F.1.2.2 */
+
+ r = 0; /* r = run length of zeros */
+
+ for (k = 1; k <= Se; k++) {
+ if ((temp = block[natural_order[k]]) == 0) {
+ r++;
+ } else {
+ /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+ while (r > 15) {
+ if (! emit_bits_s(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0]))
+ return FALSE;
+ r -= 16;
+ }
+
+ temp2 = temp;
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ /* This code assumes we are on a two's complement machine */
+ temp2--;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 1; /* there must be at least one 1 bit */
+ while ((temp >>= 1))
+ nbits++;
+ /* Check for out-of-range coefficient values */
+ if (nbits > MAX_COEF_BITS)
+ ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
+
+ /* Emit Huffman symbol for run length / number of bits */
+ i = (r << 4) + nbits;
+ if (! emit_bits_s(state, actbl->ehufco[i], actbl->ehufsi[i]))
+ return FALSE;
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ if (! emit_bits_s(state, (unsigned int) temp2, nbits))
+ return FALSE;
+
+ r = 0;
+ }
+ }
+
+ /* If the last coef(s) were zero, emit an end-of-block code */
+ if (r > 0)
+ if (! emit_bits_s(state, actbl->ehufco[0], actbl->ehufsi[0]))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Encode and output one MCU's worth of Huffman-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ working_state state;
+ int blkn, ci;
+ jpeg_component_info * compptr;
+
+ /* Load up working state */
+ state.next_output_byte = cinfo->dest->next_output_byte;
+ state.free_in_buffer = cinfo->dest->free_in_buffer;
+ ASSIGN_STATE(state.cur, entropy->saved);
+ state.cinfo = cinfo;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! emit_restart_s(&state, entropy->next_restart_num))
+ return FALSE;
+ }
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ if (! encode_one_block(&state,
+ MCU_data[blkn][0], state.cur.last_dc_val[ci],
+ entropy->dc_derived_tbls[compptr->dc_tbl_no],
+ entropy->ac_derived_tbls[compptr->ac_tbl_no]))
+ return FALSE;
+ /* Update last_dc_val */
+ state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
+ }
+
+ /* Completed MCU, so update state */
+ cinfo->dest->next_output_byte = state.next_output_byte;
+ cinfo->dest->free_in_buffer = state.free_in_buffer;
+ ASSIGN_STATE(entropy->saved, state.cur);
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Finish up at the end of a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass_huff (j_compress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ working_state state;
+
+ if (cinfo->progressive_mode) {
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Flush out any buffered data */
+ emit_eobrun(entropy);
+ flush_bits_e(entropy);
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+ } else {
+ /* Load up working state ... flush_bits needs it */
+ state.next_output_byte = cinfo->dest->next_output_byte;
+ state.free_in_buffer = cinfo->dest->free_in_buffer;
+ ASSIGN_STATE(state.cur, entropy->saved);
+ state.cinfo = cinfo;
+
+ /* Flush out the last data */
+ if (! flush_bits_s(&state))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+
+ /* Update state */
+ cinfo->dest->next_output_byte = state.next_output_byte;
+ cinfo->dest->free_in_buffer = state.free_in_buffer;
+ ASSIGN_STATE(entropy->saved, state.cur);
+ }
+}
+
+
+/*
+ * Huffman coding optimization.
+ *
+ * We first scan the supplied data and count the number of uses of each symbol
+ * that is to be Huffman-coded. (This process MUST agree with the code above.)
+ * Then we build a Huffman coding tree for the observed counts.
+ * Symbols which are not needed at all for the particular image are not
+ * assigned any code, which saves space in the DHT marker as well as in
+ * the compressed data.
+ */
+
+
+/* Process a single block's worth of coefficients */
+
+LOCAL(void)
+htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
+ long dc_counts[], long ac_counts[])
+{
+ register int temp;
+ register int nbits;
+ register int k, r;
+ int Se = cinfo->lim_Se;
+ const int * natural_order = cinfo->natural_order;
+
+ /* Encode the DC coefficient difference per section F.1.2.1 */
+
+ temp = block[0] - last_dc_val;
+ if (temp < 0)
+ temp = -temp;
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+ /* Check for out-of-range coefficient values.
+ * Since we're encoding a difference, the range limit is twice as much.
+ */
+ if (nbits > MAX_COEF_BITS+1)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Count the Huffman symbol for the number of bits */
+ dc_counts[nbits]++;
+
+ /* Encode the AC coefficients per section F.1.2.2 */
+
+ r = 0; /* r = run length of zeros */
+
+ for (k = 1; k <= Se; k++) {
+ if ((temp = block[natural_order[k]]) == 0) {
+ r++;
+ } else {
+ /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+ while (r > 15) {
+ ac_counts[0xF0]++;
+ r -= 16;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ if (temp < 0)
+ temp = -temp;
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 1; /* there must be at least one 1 bit */
+ while ((temp >>= 1))
+ nbits++;
+ /* Check for out-of-range coefficient values */
+ if (nbits > MAX_COEF_BITS)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Count Huffman symbol for run length / number of bits */
+ ac_counts[(r << 4) + nbits]++;
+
+ r = 0;
+ }
+ }
+
+ /* If the last coef(s) were zero, emit an end-of-block code */
+ if (r > 0)
+ ac_counts[0]++;
+}
+
+
+/*
+ * Trial-encode one MCU's worth of Huffman-compressed coefficients.
+ * No data is actually output, so no suspension return is possible.
+ */
+
+METHODDEF(boolean)
+encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int blkn, ci;
+ jpeg_component_info * compptr;
+
+ /* Take care of restart intervals if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++)
+ entropy->saved.last_dc_val[ci] = 0;
+ /* Update restart state */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci],
+ entropy->dc_count_ptrs[compptr->dc_tbl_no],
+ entropy->ac_count_ptrs[compptr->ac_tbl_no]);
+ entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0];
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Generate the best Huffman code table for the given counts, fill htbl.
+ *
+ * The JPEG standard requires that no symbol be assigned a codeword of all
+ * one bits (so that padding bits added at the end of a compressed segment
+ * can't look like a valid code). Because of the canonical ordering of
+ * codewords, this just means that there must be an unused slot in the
+ * longest codeword length category. Section K.2 of the JPEG spec suggests
+ * reserving such a slot by pretending that symbol 256 is a valid symbol
+ * with count 1. In theory that's not optimal; giving it count zero but
+ * including it in the symbol set anyway should give a better Huffman code.
+ * But the theoretically better code actually seems to come out worse in
+ * practice, because it produces more all-ones bytes (which incur stuffed
+ * zero bytes in the final file). In any case the difference is tiny.
+ *
+ * The JPEG standard requires Huffman codes to be no more than 16 bits long.
+ * If some symbols have a very small but nonzero probability, the Huffman tree
+ * must be adjusted to meet the code length restriction. We currently use
+ * the adjustment method suggested in JPEG section K.2. This method is *not*
+ * optimal; it may not choose the best possible limited-length code. But
+ * typically only very-low-frequency symbols will be given less-than-optimal
+ * lengths, so the code is almost optimal. Experimental comparisons against
+ * an optimal limited-length-code algorithm indicate that the difference is
+ * microscopic --- usually less than a hundredth of a percent of total size.
+ * So the extra complexity of an optimal algorithm doesn't seem worthwhile.
+ */
+
+LOCAL(void)
+jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])
+{
+#define MAX_CLEN 32 /* assumed maximum initial code length */
+ UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */
+ int codesize[257]; /* codesize[k] = code length of symbol k */
+ int others[257]; /* next symbol in current branch of tree */
+ int c1, c2;
+ int p, i, j;
+ long v;
+
+ /* This algorithm is explained in section K.2 of the JPEG standard */
+
+ MEMZERO(bits, SIZEOF(bits));
+ MEMZERO(codesize, SIZEOF(codesize));
+ for (i = 0; i < 257; i++)
+ others[i] = -1; /* init links to empty */
+
+ freq[256] = 1; /* make sure 256 has a nonzero count */
+ /* Including the pseudo-symbol 256 in the Huffman procedure guarantees
+ * that no real symbol is given code-value of all ones, because 256
+ * will be placed last in the largest codeword category.
+ */
+
+ /* Huffman's basic algorithm to assign optimal code lengths to symbols */
+
+ for (;;) {
+ /* Find the smallest nonzero frequency, set c1 = its symbol */
+ /* In case of ties, take the larger symbol number */
+ c1 = -1;
+ v = 1000000000L;
+ for (i = 0; i <= 256; i++) {
+ if (freq[i] && freq[i] <= v) {
+ v = freq[i];
+ c1 = i;
+ }
+ }
+
+ /* Find the next smallest nonzero frequency, set c2 = its symbol */
+ /* In case of ties, take the larger symbol number */
+ c2 = -1;
+ v = 1000000000L;
+ for (i = 0; i <= 256; i++) {
+ if (freq[i] && freq[i] <= v && i != c1) {
+ v = freq[i];
+ c2 = i;
+ }
+ }
+
+ /* Done if we've merged everything into one frequency */
+ if (c2 < 0)
+ break;
+
+ /* Else merge the two counts/trees */
+ freq[c1] += freq[c2];
+ freq[c2] = 0;
+
+ /* Increment the codesize of everything in c1's tree branch */
+ codesize[c1]++;
+ while (others[c1] >= 0) {
+ c1 = others[c1];
+ codesize[c1]++;
+ }
+
+ others[c1] = c2; /* chain c2 onto c1's tree branch */
+
+ /* Increment the codesize of everything in c2's tree branch */
+ codesize[c2]++;
+ while (others[c2] >= 0) {
+ c2 = others[c2];
+ codesize[c2]++;
+ }
+ }
+
+ /* Now count the number of symbols of each code length */
+ for (i = 0; i <= 256; i++) {
+ if (codesize[i]) {
+ /* The JPEG standard seems to think that this can't happen, */
+ /* but I'm paranoid... */
+ if (codesize[i] > MAX_CLEN)
+ ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW);
+
+ bits[codesize[i]]++;
+ }
+ }
+
+ /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure
+ * Huffman procedure assigned any such lengths, we must adjust the coding.
+ * Here is what the JPEG spec says about how this next bit works:
+ * Since symbols are paired for the longest Huffman code, the symbols are
+ * removed from this length category two at a time. The prefix for the pair
+ * (which is one bit shorter) is allocated to one of the pair; then,
+ * skipping the BITS entry for that prefix length, a code word from the next
+ * shortest nonzero BITS entry is converted into a prefix for two code words
+ * one bit longer.
+ */
+
+ for (i = MAX_CLEN; i > 16; i--) {
+ while (bits[i] > 0) {
+ j = i - 2; /* find length of new prefix to be used */
+ while (bits[j] == 0)
+ j--;
+
+ bits[i] -= 2; /* remove two symbols */
+ bits[i-1]++; /* one goes in this length */
+ bits[j+1] += 2; /* two new symbols in this length */
+ bits[j]--; /* symbol of this length is now a prefix */
+ }
+ }
+
+ /* Remove the count for the pseudo-symbol 256 from the largest codelength */
+ while (bits[i] == 0) /* find largest codelength still in use */
+ i--;
+ bits[i]--;
+
+ /* Return final symbol counts (only for lengths 0..16) */
+ MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits));
+
+ /* Return a list of the symbols sorted by code length */
+ /* It's not real clear to me why we don't need to consider the codelength
+ * changes made above, but the JPEG spec seems to think this works.
+ */
+ p = 0;
+ for (i = 1; i <= MAX_CLEN; i++) {
+ for (j = 0; j <= 255; j++) {
+ if (codesize[j] == i) {
+ htbl->huffval[p] = (UINT8) j;
+ p++;
+ }
+ }
+ }
+
+ /* Set sent_table FALSE so updated table will be written to JPEG file. */
+ htbl->sent_table = FALSE;
+}
+
+
+/*
+ * Finish up a statistics-gathering pass and create the new Huffman tables.
+ */
+
+METHODDEF(void)
+finish_pass_gather (j_compress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci, tbl;
+ jpeg_component_info * compptr;
+ JHUFF_TBL **htblptr;
+ boolean did_dc[NUM_HUFF_TBLS];
+ boolean did_ac[NUM_HUFF_TBLS];
+
+ /* It's important not to apply jpeg_gen_optimal_table more than once
+ * per table, because it clobbers the input frequency counts!
+ */
+ if (cinfo->progressive_mode)
+ /* Flush out buffered data (all we care about is counting the EOB symbol) */
+ emit_eobrun(entropy);
+
+ MEMZERO(did_dc, SIZEOF(did_dc));
+ MEMZERO(did_ac, SIZEOF(did_ac));
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+ tbl = compptr->dc_tbl_no;
+ if (! did_dc[tbl]) {
+ htblptr = & cinfo->dc_huff_tbl_ptrs[tbl];
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+ jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[tbl]);
+ did_dc[tbl] = TRUE;
+ }
+ }
+ /* AC needs no table when not present */
+ if (cinfo->Se) {
+ tbl = compptr->ac_tbl_no;
+ if (! did_ac[tbl]) {
+ htblptr = & cinfo->ac_huff_tbl_ptrs[tbl];
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+ jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[tbl]);
+ did_ac[tbl] = TRUE;
+ }
+ }
+ }
+}
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ * If gather_statistics is TRUE, we do not output anything during the scan,
+ * just count the Huffman symbols used and generate Huffman code tables.
+ */
+
+METHODDEF(void)
+start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci, tbl;
+ jpeg_component_info * compptr;
+
+ if (gather_statistics)
+ entropy->pub.finish_pass = finish_pass_gather;
+ else
+ entropy->pub.finish_pass = finish_pass_huff;
+
+ if (cinfo->progressive_mode) {
+ entropy->cinfo = cinfo;
+ entropy->gather_statistics = gather_statistics;
+
+ /* We assume jcmaster.c already validated the scan parameters. */
+
+ /* Select execution routine */
+ if (cinfo->Ah == 0) {
+ if (cinfo->Ss == 0)
+ entropy->pub.encode_mcu = encode_mcu_DC_first;
+ else
+ entropy->pub.encode_mcu = encode_mcu_AC_first;
+ } else {
+ if (cinfo->Ss == 0)
+ entropy->pub.encode_mcu = encode_mcu_DC_refine;
+ else {
+ entropy->pub.encode_mcu = encode_mcu_AC_refine;
+ /* AC refinement needs a correction bit buffer */
+ if (entropy->bit_buffer == NULL)
+ entropy->bit_buffer = (char *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ MAX_CORR_BITS * SIZEOF(char));
+ }
+ }
+
+ /* Initialize AC stuff */
+ entropy->ac_tbl_no = cinfo->cur_comp_info[0]->ac_tbl_no;
+ entropy->EOBRUN = 0;
+ entropy->BE = 0;
+ } else {
+ if (gather_statistics)
+ entropy->pub.encode_mcu = encode_mcu_gather;
+ else
+ entropy->pub.encode_mcu = encode_mcu_huff;
+ }
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+ tbl = compptr->dc_tbl_no;
+ if (gather_statistics) {
+ /* Check for invalid table index */
+ /* (make_c_derived_tbl does this in the other path) */
+ if (tbl < 0 || tbl >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);
+ /* Allocate and zero the statistics tables */
+ /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
+ if (entropy->dc_count_ptrs[tbl] == NULL)
+ entropy->dc_count_ptrs[tbl] = (long *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ 257 * SIZEOF(long));
+ MEMZERO(entropy->dc_count_ptrs[tbl], 257 * SIZEOF(long));
+ } else {
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ jpeg_make_c_derived_tbl(cinfo, TRUE, tbl,
+ & entropy->dc_derived_tbls[tbl]);
+ }
+ /* Initialize DC predictions to 0 */
+ entropy->saved.last_dc_val[ci] = 0;
+ }
+ /* AC needs no table when not present */
+ if (cinfo->Se) {
+ tbl = compptr->ac_tbl_no;
+ if (gather_statistics) {
+ if (tbl < 0 || tbl >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);
+ if (entropy->ac_count_ptrs[tbl] == NULL)
+ entropy->ac_count_ptrs[tbl] = (long *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ 257 * SIZEOF(long));
+ MEMZERO(entropy->ac_count_ptrs[tbl], 257 * SIZEOF(long));
+ } else {
+ jpeg_make_c_derived_tbl(cinfo, FALSE, tbl,
+ & entropy->ac_derived_tbls[tbl]);
+ }
+ }
+ }
+
+ /* Initialize bit buffer to empty */
+ entropy->saved.put_buffer = 0;
+ entropy->saved.put_bits = 0;
+
+ /* Initialize restart stuff */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num = 0;
+}
+
+
+/*
+ * Module initialization routine for Huffman entropy encoding.
+ */
+
+GLOBAL(void)
+jinit_huff_encoder (j_compress_ptr cinfo)
+{
+ huff_entropy_ptr entropy;
+ int i;
+
+ entropy = (huff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(huff_entropy_encoder));
+ cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
+ entropy->pub.start_pass = start_pass_huff;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
+ entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL;
+ }
+
+ if (cinfo->progressive_mode)
+ entropy->bit_buffer = NULL; /* needed only in AC refinement scan */
+}
diff --git a/external/jpeg-8c/jcinit.c b/external/jpeg-8c/jcinit.c
new file mode 100644
index 0000000..0ba310f
--- /dev/null
+++ b/external/jpeg-8c/jcinit.c
@@ -0,0 +1,65 @@
+/*
+ * jcinit.c
+ *
+ * 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 initialization logic for the JPEG compressor.
+ * This routine is in charge of selecting the modules to be executed and
+ * making an initialization call to each one.
+ *
+ * Logically, this code belongs in jcmaster.c. It's split out because
+ * linking this routine implies linking the entire compression library.
+ * For a transcoding-only application, we want to be able to use jcmaster.c
+ * without linking in the whole library.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Master selection of compression modules.
+ * This is done once at the start of processing an image. We determine
+ * which modules will be used and give them appropriate initialization calls.
+ */
+
+GLOBAL(void)
+jinit_compress_master (j_compress_ptr cinfo)
+{
+ /* Initialize master control (includes parameter checking/processing) */
+ jinit_c_master_control(cinfo, FALSE /* full compression */);
+
+ /* Preprocessing */
+ if (! cinfo->raw_data_in) {
+ jinit_color_converter(cinfo);
+ jinit_downsampler(cinfo);
+ jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);
+ }
+ /* Forward DCT */
+ jinit_forward_dct(cinfo);
+ /* Entropy encoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code)
+ jinit_arith_encoder(cinfo);
+ else {
+ jinit_huff_encoder(cinfo);
+ }
+
+ /* Need a full-image coefficient buffer in any multi-pass mode. */
+ jinit_c_coef_controller(cinfo,
+ (boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding));
+ jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
+
+ jinit_marker_writer(cinfo);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Write the datastream header (SOI) immediately.
+ * Frame and scan headers are postponed till later.
+ * This lets application insert special markers after the SOI.
+ */
+ (*cinfo->marker->write_file_header) (cinfo);
+}
diff --git a/external/jpeg-8c/jcmainct.c b/external/jpeg-8c/jcmainct.c
new file mode 100644
index 0000000..b9f525b
--- /dev/null
+++ b/external/jpeg-8c/jcmainct.c
@@ -0,0 +1,293 @@
+/*
+ * jcmainct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the main buffer controller for compression.
+ * The main buffer lies between the pre-processor and the JPEG
+ * compressor proper; it holds downsampled data in the JPEG colorspace.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Note: currently, there is no operating mode in which a full-image buffer
+ * is needed at this step. If there were, that mode could not be used with
+ * "raw data" input, since this module is bypassed in that case. However,
+ * we've left the code here for possible use in special applications.
+ */
+#undef FULL_MAIN_BUFFER_SUPPORTED
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_main_controller pub; /* public fields */
+
+ JDIMENSION cur_iMCU_row; /* number of current iMCU row */
+ JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */
+ boolean suspended; /* remember if we suspended output */
+ J_BUF_MODE pass_mode; /* current operating mode */
+
+ /* If using just a strip buffer, this points to the entire set of buffers
+ * (we allocate one for each component). In the full-image case, this
+ * points to the currently accessible strips of the virtual arrays.
+ */
+ JSAMPARRAY buffer[MAX_COMPONENTS];
+
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ /* If using full-image storage, this array holds pointers to virtual-array
+ * control blocks for each component. Unused if not full-image storage.
+ */
+ jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
+#endif
+} my_main_controller;
+
+typedef my_main_controller * my_main_ptr;
+
+
+/* Forward declarations */
+METHODDEF(void) process_data_simple_main
+ JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+METHODDEF(void) process_data_buffer_main
+ JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
+#endif
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+
+ /* Do nothing in raw-data mode. */
+ if (cinfo->raw_data_in)
+ return;
+
+ main_ptr->cur_iMCU_row = 0; /* initialize counters */
+ main_ptr->rowgroup_ctr = 0;
+ main_ptr->suspended = FALSE;
+ main_ptr->pass_mode = pass_mode; /* save mode for use by process_data */
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ if (main_ptr->whole_image[0] != NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+ main_ptr->pub.process_data = process_data_simple_main;
+ break;
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ case JBUF_SAVE_SOURCE:
+ case JBUF_CRANK_DEST:
+ case JBUF_SAVE_AND_PASS:
+ if (main_ptr->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ main_ptr->pub.process_data = process_data_buffer_main;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+}
+
+
+/*
+ * Process some data.
+ * This routine handles the simple pass-through mode,
+ * where we have only a strip buffer.
+ */
+
+METHODDEF(void)
+process_data_simple_main (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail)
+{
+ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+
+ while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
+ /* Read input data if we haven't filled the main buffer yet */
+ if (main_ptr->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size)
+ (*cinfo->prep->pre_process_data) (cinfo,
+ input_buf, in_row_ctr, in_rows_avail,
+ main_ptr->buffer, &main_ptr->rowgroup_ctr,
+ (JDIMENSION) cinfo->min_DCT_v_scaled_size);
+
+ /* If we don't have a full iMCU row buffered, return to application for
+ * more data. Note that preprocessor will always pad to fill the iMCU row
+ * at the bottom of the image.
+ */
+ if (main_ptr->rowgroup_ctr != (JDIMENSION) cinfo->min_DCT_v_scaled_size)
+ return;
+
+ /* Send the completed row to the compressor */
+ if (! (*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
+ /* If compressor did not consume the whole row, then we must need to
+ * suspend processing and return to the application. In this situation
+ * we pretend we didn't yet consume the last input row; otherwise, if
+ * it happened to be the last row of the image, the application would
+ * think we were done.
+ */
+ if (! main_ptr->suspended) {
+ (*in_row_ctr)--;
+ main_ptr->suspended = TRUE;
+ }
+ return;
+ }
+ /* We did finish the row. Undo our little suspension hack if a previous
+ * call suspended; then mark the main buffer empty.
+ */
+ if (main_ptr->suspended) {
+ (*in_row_ctr)++;
+ main_ptr->suspended = FALSE;
+ }
+ main_ptr->rowgroup_ctr = 0;
+ main_ptr->cur_iMCU_row++;
+ }
+}
+
+
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+
+/*
+ * Process some data.
+ * This routine handles all of the modes that use a full-size buffer.
+ */
+
+METHODDEF(void)
+process_data_buffer_main (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail)
+{
+ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ int ci;
+ jpeg_component_info *compptr;
+ boolean writing = (main_ptr->pass_mode != JBUF_CRANK_DEST);
+
+ while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
+ /* Realign the virtual buffers if at the start of an iMCU row. */
+ if (main_ptr->rowgroup_ctr == 0) {
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ main_ptr->buffer[ci] = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, main_ptr->whole_image[ci],
+ main_ptr->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
+ (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing);
+ }
+ /* In a read pass, pretend we just read some source data. */
+ if (! writing) {
+ *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE;
+ main_ptr->rowgroup_ctr = DCTSIZE;
+ }
+ }
+
+ /* If a write pass, read input data until the current iMCU row is full. */
+ /* Note: preprocessor will pad if necessary to fill the last iMCU row. */
+ if (writing) {
+ (*cinfo->prep->pre_process_data) (cinfo,
+ input_buf, in_row_ctr, in_rows_avail,
+ main_ptr->buffer, &main_ptr->rowgroup_ctr,
+ (JDIMENSION) DCTSIZE);
+ /* Return to application if we need more data to fill the iMCU row. */
+ if (main_ptr->rowgroup_ctr < DCTSIZE)
+ return;
+ }
+
+ /* Emit data, unless this is a sink-only pass. */
+ if (main_ptr->pass_mode != JBUF_SAVE_SOURCE) {
+ if (! (*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
+ /* If compressor did not consume the whole row, then we must need to
+ * suspend processing and return to the application. In this situation
+ * we pretend we didn't yet consume the last input row; otherwise, if
+ * it happened to be the last row of the image, the application would
+ * think we were done.
+ */
+ if (! main_ptr->suspended) {
+ (*in_row_ctr)--;
+ main_ptr->suspended = TRUE;
+ }
+ return;
+ }
+ /* We did finish the row. Undo our little suspension hack if a previous
+ * call suspended; then mark the main buffer empty.
+ */
+ if (main_ptr->suspended) {
+ (*in_row_ctr)++;
+ main_ptr->suspended = FALSE;
+ }
+ }
+
+ /* If get here, we are done with this iMCU row. Mark buffer empty. */
+ main_ptr->rowgroup_ctr = 0;
+ main_ptr->cur_iMCU_row++;
+ }
+}
+
+#endif /* FULL_MAIN_BUFFER_SUPPORTED */
+
+
+/*
+ * Initialize main buffer controller.
+ */
+
+GLOBAL(void)
+jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+ my_main_ptr main_ptr;
+ int ci;
+ jpeg_component_info *compptr;
+
+ main_ptr = (my_main_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_main_controller));
+ cinfo->main = (struct jpeg_c_main_controller *) main_ptr;
+ main_ptr->pub.start_pass = start_pass_main;
+
+ /* We don't need to create a buffer in raw-data mode. */
+ if (cinfo->raw_data_in)
+ return;
+
+ /* Create the buffer. It holds downsampled data, so each component
+ * may be of a different size.
+ */
+ if (need_full_buffer) {
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ /* Allocate a full-image virtual array for each component */
+ /* Note we pad the bottom to a multiple of the iMCU height */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ main_ptr->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+ (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+ (long) compptr->v_samp_factor) * DCTSIZE,
+ (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size));
+ }
+#else
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+ } else {
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ main_ptr->whole_image[0] = NULL; /* flag for no virtual arrays */
+#endif
+ /* Allocate a strip buffer for each component */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+ (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size));
+ }
+ }
+}
diff --git a/external/jpeg-8c/jcmarker.c b/external/jpeg-8c/jcmarker.c
new file mode 100644
index 0000000..606c19a
--- /dev/null
+++ b/external/jpeg-8c/jcmarker.c
@@ -0,0 +1,682 @@
+/*
+ * jcmarker.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2003-2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write JPEG datastream markers.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+typedef enum { /* JPEG marker codes */
+ M_SOF0 = 0xc0,
+ M_SOF1 = 0xc1,
+ M_SOF2 = 0xc2,
+ M_SOF3 = 0xc3,
+
+ M_SOF5 = 0xc5,
+ M_SOF6 = 0xc6,
+ M_SOF7 = 0xc7,
+
+ M_JPG = 0xc8,
+ M_SOF9 = 0xc9,
+ M_SOF10 = 0xca,
+ M_SOF11 = 0xcb,
+
+ M_SOF13 = 0xcd,
+ M_SOF14 = 0xce,
+ M_SOF15 = 0xcf,
+
+ M_DHT = 0xc4,
+
+ M_DAC = 0xcc,
+
+ M_RST0 = 0xd0,
+ M_RST1 = 0xd1,
+ M_RST2 = 0xd2,
+ M_RST3 = 0xd3,
+ M_RST4 = 0xd4,
+ M_RST5 = 0xd5,
+ M_RST6 = 0xd6,
+ M_RST7 = 0xd7,
+
+ M_SOI = 0xd8,
+ M_EOI = 0xd9,
+ M_SOS = 0xda,
+ M_DQT = 0xdb,
+ M_DNL = 0xdc,
+ M_DRI = 0xdd,
+ M_DHP = 0xde,
+ M_EXP = 0xdf,
+
+ M_APP0 = 0xe0,
+ M_APP1 = 0xe1,
+ M_APP2 = 0xe2,
+ M_APP3 = 0xe3,
+ M_APP4 = 0xe4,
+ M_APP5 = 0xe5,
+ M_APP6 = 0xe6,
+ M_APP7 = 0xe7,
+ M_APP8 = 0xe8,
+ M_APP9 = 0xe9,
+ M_APP10 = 0xea,
+ M_APP11 = 0xeb,
+ M_APP12 = 0xec,
+ M_APP13 = 0xed,
+ M_APP14 = 0xee,
+ M_APP15 = 0xef,
+
+ M_JPG0 = 0xf0,
+ M_JPG13 = 0xfd,
+ M_COM = 0xfe,
+
+ M_TEM = 0x01,
+
+ M_ERROR = 0x100
+} JPEG_MARKER;
+
+
+/* Private state */
+
+typedef struct {
+ struct jpeg_marker_writer pub; /* public fields */
+
+ unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */
+} my_marker_writer;
+
+typedef my_marker_writer * my_marker_ptr;
+
+
+/*
+ * Basic output routines.
+ *
+ * Note that we do not support suspension while writing a marker.
+ * Therefore, an application using suspension must ensure that there is
+ * enough buffer space for the initial markers (typ. 600-700 bytes) before
+ * calling jpeg_start_compress, and enough space to write the trailing EOI
+ * (a few bytes) before calling jpeg_finish_compress. Multipass compression
+ * modes are not supported at all with suspension, so those two are the only
+ * points where markers will be written.
+ */
+
+LOCAL(void)
+emit_byte (j_compress_ptr cinfo, int val)
+/* Emit a byte */
+{
+ struct jpeg_destination_mgr * dest = cinfo->dest;
+
+ *(dest->next_output_byte)++ = (JOCTET) val;
+ if (--dest->free_in_buffer == 0) {
+ if (! (*dest->empty_output_buffer) (cinfo))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ }
+}
+
+
+LOCAL(void)
+emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark)
+/* Emit a marker code */
+{
+ emit_byte(cinfo, 0xFF);
+ emit_byte(cinfo, (int) mark);
+}
+
+
+LOCAL(void)
+emit_2bytes (j_compress_ptr cinfo, int value)
+/* Emit a 2-byte integer; these are always MSB first in JPEG files */
+{
+ emit_byte(cinfo, (value >> 8) & 0xFF);
+ emit_byte(cinfo, value & 0xFF);
+}
+
+
+/*
+ * Routines to write specific marker types.
+ */
+
+LOCAL(int)
+emit_dqt (j_compress_ptr cinfo, int index)
+/* Emit a DQT marker */
+/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */
+{
+ JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index];
+ int prec;
+ int i;
+
+ if (qtbl == NULL)
+ ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index);
+
+ prec = 0;
+ for (i = 0; i <= cinfo->lim_Se; i++) {
+ if (qtbl->quantval[cinfo->natural_order[i]] > 255)
+ prec = 1;
+ }
+
+ if (! qtbl->sent_table) {
+ emit_marker(cinfo, M_DQT);
+
+ emit_2bytes(cinfo,
+ prec ? cinfo->lim_Se * 2 + 2 + 1 + 2 : cinfo->lim_Se + 1 + 1 + 2);
+
+ emit_byte(cinfo, index + (prec<<4));
+
+ for (i = 0; i <= cinfo->lim_Se; i++) {
+ /* The table entries must be emitted in zigzag order. */
+ unsigned int qval = qtbl->quantval[cinfo->natural_order[i]];
+ if (prec)
+ emit_byte(cinfo, (int) (qval >> 8));
+ emit_byte(cinfo, (int) (qval & 0xFF));
+ }
+
+ qtbl->sent_table = TRUE;
+ }
+
+ return prec;
+}
+
+
+LOCAL(void)
+emit_dht (j_compress_ptr cinfo, int index, boolean is_ac)
+/* Emit a DHT marker */
+{
+ JHUFF_TBL * htbl;
+ int length, i;
+
+ if (is_ac) {
+ htbl = cinfo->ac_huff_tbl_ptrs[index];
+ index += 0x10; /* output index has AC bit set */
+ } else {
+ htbl = cinfo->dc_huff_tbl_ptrs[index];
+ }
+
+ if (htbl == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index);
+
+ if (! htbl->sent_table) {
+ emit_marker(cinfo, M_DHT);
+
+ length = 0;
+ for (i = 1; i <= 16; i++)
+ length += htbl->bits[i];
+
+ emit_2bytes(cinfo, length + 2 + 1 + 16);
+ emit_byte(cinfo, index);
+
+ for (i = 1; i <= 16; i++)
+ emit_byte(cinfo, htbl->bits[i]);
+
+ for (i = 0; i < length; i++)
+ emit_byte(cinfo, htbl->huffval[i]);
+
+ htbl->sent_table = TRUE;
+ }
+}
+
+
+LOCAL(void)
+emit_dac (j_compress_ptr cinfo)
+/* Emit a DAC marker */
+/* Since the useful info is so small, we want to emit all the tables in */
+/* one DAC marker. Therefore this routine does its own scan of the table. */
+{
+#ifdef C_ARITH_CODING_SUPPORTED
+ char dc_in_use[NUM_ARITH_TBLS];
+ char ac_in_use[NUM_ARITH_TBLS];
+ int length, i;
+ jpeg_component_info *compptr;
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++)
+ dc_in_use[i] = ac_in_use[i] = 0;
+
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ compptr = cinfo->cur_comp_info[i];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0)
+ dc_in_use[compptr->dc_tbl_no] = 1;
+ /* AC needs no table when not present */
+ if (cinfo->Se)
+ ac_in_use[compptr->ac_tbl_no] = 1;
+ }
+
+ length = 0;
+ for (i = 0; i < NUM_ARITH_TBLS; i++)
+ length += dc_in_use[i] + ac_in_use[i];
+
+ if (length) {
+ emit_marker(cinfo, M_DAC);
+
+ emit_2bytes(cinfo, length*2 + 2);
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ if (dc_in_use[i]) {
+ emit_byte(cinfo, i);
+ emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4));
+ }
+ if (ac_in_use[i]) {
+ emit_byte(cinfo, i + 0x10);
+ emit_byte(cinfo, cinfo->arith_ac_K[i]);
+ }
+ }
+ }
+#endif /* C_ARITH_CODING_SUPPORTED */
+}
+
+
+LOCAL(void)
+emit_dri (j_compress_ptr cinfo)
+/* Emit a DRI marker */
+{
+ emit_marker(cinfo, M_DRI);
+
+ emit_2bytes(cinfo, 4); /* fixed length */
+
+ emit_2bytes(cinfo, (int) cinfo->restart_interval);
+}
+
+
+LOCAL(void)
+emit_sof (j_compress_ptr cinfo, JPEG_MARKER code)
+/* Emit a SOF marker */
+{
+ int ci;
+ jpeg_component_info *compptr;
+
+ emit_marker(cinfo, code);
+
+ emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */
+
+ /* Make sure image isn't bigger than SOF field can handle */
+ if ((long) cinfo->jpeg_height > 65535L ||
+ (long) cinfo->jpeg_width > 65535L)
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);
+
+ emit_byte(cinfo, cinfo->data_precision);
+ emit_2bytes(cinfo, (int) cinfo->jpeg_height);
+ emit_2bytes(cinfo, (int) cinfo->jpeg_width);
+
+ emit_byte(cinfo, cinfo->num_components);
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ emit_byte(cinfo, compptr->component_id);
+ emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor);
+ emit_byte(cinfo, compptr->quant_tbl_no);
+ }
+}
+
+
+LOCAL(void)
+emit_sos (j_compress_ptr cinfo)
+/* Emit a SOS marker */
+{
+ int i, td, ta;
+ jpeg_component_info *compptr;
+
+ emit_marker(cinfo, M_SOS);
+
+ emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */
+
+ emit_byte(cinfo, cinfo->comps_in_scan);
+
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ compptr = cinfo->cur_comp_info[i];
+ emit_byte(cinfo, compptr->component_id);
+
+ /* We emit 0 for unused field(s); this is recommended by the P&M text
+ * but does not seem to be specified in the standard.
+ */
+
+ /* DC needs no table for refinement scan */
+ td = cinfo->Ss == 0 && cinfo->Ah == 0 ? compptr->dc_tbl_no : 0;
+ /* AC needs no table when not present */
+ ta = cinfo->Se ? compptr->ac_tbl_no : 0;
+
+ emit_byte(cinfo, (td << 4) + ta);
+ }
+
+ emit_byte(cinfo, cinfo->Ss);
+ emit_byte(cinfo, cinfo->Se);
+ emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al);
+}
+
+
+LOCAL(void)
+emit_pseudo_sos (j_compress_ptr cinfo)
+/* Emit a pseudo SOS marker */
+{
+ emit_marker(cinfo, M_SOS);
+
+ emit_2bytes(cinfo, 2 + 1 + 3); /* length */
+
+ emit_byte(cinfo, 0); /* Ns */
+
+ emit_byte(cinfo, 0); /* Ss */
+ emit_byte(cinfo, cinfo->block_size * cinfo->block_size - 1); /* Se */
+ emit_byte(cinfo, 0); /* Ah/Al */
+}
+
+
+LOCAL(void)
+emit_jfif_app0 (j_compress_ptr cinfo)
+/* Emit a JFIF-compliant APP0 marker */
+{
+ /*
+ * Length of APP0 block (2 bytes)
+ * Block ID (4 bytes - ASCII "JFIF")
+ * Zero byte (1 byte to terminate the ID string)
+ * Version Major, Minor (2 bytes - major first)
+ * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm)
+ * Xdpu (2 bytes - dots per unit horizontal)
+ * Ydpu (2 bytes - dots per unit vertical)
+ * Thumbnail X size (1 byte)
+ * Thumbnail Y size (1 byte)
+ */
+
+ emit_marker(cinfo, M_APP0);
+
+ emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */
+
+ emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */
+ emit_byte(cinfo, 0x46);
+ emit_byte(cinfo, 0x49);
+ emit_byte(cinfo, 0x46);
+ emit_byte(cinfo, 0);
+ emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */
+ emit_byte(cinfo, cinfo->JFIF_minor_version);
+ emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */
+ emit_2bytes(cinfo, (int) cinfo->X_density);
+ emit_2bytes(cinfo, (int) cinfo->Y_density);
+ emit_byte(cinfo, 0); /* No thumbnail image */
+ emit_byte(cinfo, 0);
+}
+
+
+LOCAL(void)
+emit_adobe_app14 (j_compress_ptr cinfo)
+/* Emit an Adobe APP14 marker */
+{
+ /*
+ * Length of APP14 block (2 bytes)
+ * Block ID (5 bytes - ASCII "Adobe")
+ * Version Number (2 bytes - currently 100)
+ * Flags0 (2 bytes - currently 0)
+ * Flags1 (2 bytes - currently 0)
+ * Color transform (1 byte)
+ *
+ * Although Adobe TN 5116 mentions Version = 101, all the Adobe files
+ * now in circulation seem to use Version = 100, so that's what we write.
+ *
+ * We write the color transform byte as 1 if the JPEG color space is
+ * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with
+ * whether the encoder performed a transformation, which is pretty useless.
+ */
+
+ emit_marker(cinfo, M_APP14);
+
+ emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */
+
+ emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */
+ emit_byte(cinfo, 0x64);
+ emit_byte(cinfo, 0x6F);
+ emit_byte(cinfo, 0x62);
+ emit_byte(cinfo, 0x65);
+ emit_2bytes(cinfo, 100); /* Version */
+ emit_2bytes(cinfo, 0); /* Flags0 */
+ emit_2bytes(cinfo, 0); /* Flags1 */
+ switch (cinfo->jpeg_color_space) {
+ case JCS_YCbCr:
+ emit_byte(cinfo, 1); /* Color transform = 1 */
+ break;
+ case JCS_YCCK:
+ emit_byte(cinfo, 2); /* Color transform = 2 */
+ break;
+ default:
+ emit_byte(cinfo, 0); /* Color transform = 0 */
+ break;
+ }
+}
+
+
+/*
+ * These routines allow writing an arbitrary marker with parameters.
+ * The only intended use is to emit COM or APPn markers after calling
+ * write_file_header and before calling write_frame_header.
+ * Other uses are not guaranteed to produce desirable results.
+ * Counting the parameter bytes properly is the caller's responsibility.
+ */
+
+METHODDEF(void)
+write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen)
+/* Emit an arbitrary marker header */
+{
+ if (datalen > (unsigned int) 65533) /* safety check */
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ emit_marker(cinfo, (JPEG_MARKER) marker);
+
+ emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */
+}
+
+METHODDEF(void)
+write_marker_byte (j_compress_ptr cinfo, int val)
+/* Emit one byte of marker parameters following write_marker_header */
+{
+ emit_byte(cinfo, val);
+}
+
+
+/*
+ * Write datastream header.
+ * This consists of an SOI and optional APPn markers.
+ * We recommend use of the JFIF marker, but not the Adobe marker,
+ * when using YCbCr or grayscale data. The JFIF marker should NOT
+ * be used for any other JPEG colorspace. The Adobe marker is helpful
+ * to distinguish RGB, CMYK, and YCCK colorspaces.
+ * Note that an application can write additional header markers after
+ * jpeg_start_compress returns.
+ */
+
+METHODDEF(void)
+write_file_header (j_compress_ptr cinfo)
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+
+ emit_marker(cinfo, M_SOI); /* first the SOI */
+
+ /* SOI is defined to reset restart interval to 0 */
+ marker->last_restart_interval = 0;
+
+ if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */
+ emit_jfif_app0(cinfo);
+ if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */
+ emit_adobe_app14(cinfo);
+}
+
+
+/*
+ * Write frame header.
+ * This consists of DQT and SOFn markers, and a conditional pseudo SOS marker.
+ * Note that we do not emit the SOF until we have emitted the DQT(s).
+ * This avoids compatibility problems with incorrect implementations that
+ * try to error-check the quant table numbers as soon as they see the SOF.
+ */
+
+METHODDEF(void)
+write_frame_header (j_compress_ptr cinfo)
+{
+ int ci, prec;
+ boolean is_baseline;
+ jpeg_component_info *compptr;
+
+ /* Emit DQT for each quantization table.
+ * Note that emit_dqt() suppresses any duplicate tables.
+ */
+ prec = 0;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ prec += emit_dqt(cinfo, compptr->quant_tbl_no);
+ }
+ /* now prec is nonzero iff there are any 16-bit quant tables. */
+
+ /* Check for a non-baseline specification.
+ * Note we assume that Huffman table numbers won't be changed later.
+ */
+ if (cinfo->arith_code || cinfo->progressive_mode ||
+ cinfo->data_precision != 8 || cinfo->block_size != DCTSIZE) {
+ is_baseline = FALSE;
+ } else {
+ is_baseline = TRUE;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1)
+ is_baseline = FALSE;
+ }
+ if (prec && is_baseline) {
+ is_baseline = FALSE;
+ /* If it's baseline except for quantizer size, warn the user */
+ TRACEMS(cinfo, 0, JTRC_16BIT_TABLES);
+ }
+ }
+
+ /* Emit the proper SOF marker */
+ if (cinfo->arith_code) {
+ if (cinfo->progressive_mode)
+ emit_sof(cinfo, M_SOF10); /* SOF code for progressive arithmetic */
+ else
+ emit_sof(cinfo, M_SOF9); /* SOF code for sequential arithmetic */
+ } else {
+ if (cinfo->progressive_mode)
+ emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */
+ else if (is_baseline)
+ emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */
+ else
+ emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */
+ }
+
+ /* Check to emit pseudo SOS marker */
+ if (cinfo->progressive_mode && cinfo->block_size != DCTSIZE)
+ emit_pseudo_sos(cinfo);
+}
+
+
+/*
+ * Write scan header.
+ * This consists of DHT or DAC markers, optional DRI, and SOS.
+ * Compressed data will be written following the SOS.
+ */
+
+METHODDEF(void)
+write_scan_header (j_compress_ptr cinfo)
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+ int i;
+ jpeg_component_info *compptr;
+
+ if (cinfo->arith_code) {
+ /* Emit arith conditioning info. We may have some duplication
+ * if the file has multiple scans, but it's so small it's hardly
+ * worth worrying about.
+ */
+ emit_dac(cinfo);
+ } else {
+ /* Emit Huffman tables.
+ * Note that emit_dht() suppresses any duplicate tables.
+ */
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ compptr = cinfo->cur_comp_info[i];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0)
+ emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
+ /* AC needs no table when not present */
+ if (cinfo->Se)
+ emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
+ }
+ }
+
+ /* Emit DRI if required --- note that DRI value could change for each scan.
+ * We avoid wasting space with unnecessary DRIs, however.
+ */
+ if (cinfo->restart_interval != marker->last_restart_interval) {
+ emit_dri(cinfo);
+ marker->last_restart_interval = cinfo->restart_interval;
+ }
+
+ emit_sos(cinfo);
+}
+
+
+/*
+ * Write datastream trailer.
+ */
+
+METHODDEF(void)
+write_file_trailer (j_compress_ptr cinfo)
+{
+ emit_marker(cinfo, M_EOI);
+}
+
+
+/*
+ * Write an abbreviated table-specification datastream.
+ * This consists of SOI, DQT and DHT tables, and EOI.
+ * Any table that is defined and not marked sent_table = TRUE will be
+ * emitted. Note that all tables will be marked sent_table = TRUE at exit.
+ */
+
+METHODDEF(void)
+write_tables_only (j_compress_ptr cinfo)
+{
+ int i;
+
+ emit_marker(cinfo, M_SOI);
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ if (cinfo->quant_tbl_ptrs[i] != NULL)
+ (void) emit_dqt(cinfo, i);
+ }
+
+ if (! cinfo->arith_code) {
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ if (cinfo->dc_huff_tbl_ptrs[i] != NULL)
+ emit_dht(cinfo, i, FALSE);
+ if (cinfo->ac_huff_tbl_ptrs[i] != NULL)
+ emit_dht(cinfo, i, TRUE);
+ }
+ }
+
+ emit_marker(cinfo, M_EOI);
+}
+
+
+/*
+ * Initialize the marker writer module.
+ */
+
+GLOBAL(void)
+jinit_marker_writer (j_compress_ptr cinfo)
+{
+ my_marker_ptr marker;
+
+ /* Create the subobject */
+ marker = (my_marker_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_marker_writer));
+ cinfo->marker = (struct jpeg_marker_writer *) marker;
+ /* Initialize method pointers */
+ marker->pub.write_file_header = write_file_header;
+ marker->pub.write_frame_header = write_frame_header;
+ marker->pub.write_scan_header = write_scan_header;
+ marker->pub.write_file_trailer = write_file_trailer;
+ marker->pub.write_tables_only = write_tables_only;
+ marker->pub.write_marker_header = write_marker_header;
+ marker->pub.write_marker_byte = write_marker_byte;
+ /* Initialize private state */
+ marker->last_restart_interval = 0;
+}
diff --git a/external/jpeg-8c/jcmaster.c b/external/jpeg-8c/jcmaster.c
new file mode 100644
index 0000000..caf80a5
--- /dev/null
+++ b/external/jpeg-8c/jcmaster.c
@@ -0,0 +1,858 @@
+/*
+ * jcmaster.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2003-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains master control logic for the JPEG compressor.
+ * These routines are concerned with parameter validation, initial setup,
+ * and inter-pass control (determining the number of passes and the work
+ * to be done in each pass).
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef enum {
+ main_pass, /* input data, also do first output step */
+ huff_opt_pass, /* Huffman code optimization pass */
+ output_pass /* data output pass */
+} c_pass_type;
+
+typedef struct {
+ struct jpeg_comp_master pub; /* public fields */
+
+ c_pass_type pass_type; /* the type of the current pass */
+
+ int pass_number; /* # of passes completed */
+ int total_passes; /* total # of passes needed */
+
+ int scan_number; /* current index in scan_info[] */
+} my_comp_master;
+
+typedef my_comp_master * my_master_ptr;
+
+
+/*
+ * Support routines that do various essential calculations.
+ */
+
+/*
+ * Compute JPEG image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ */
+
+GLOBAL(void)
+jpeg_calc_jpeg_dimensions (j_compress_ptr cinfo)
+/* Do computations that are needed before master selection phase */
+{
+#ifdef DCT_SCALING_SUPPORTED
+
+ /* Sanity check on input image dimensions to prevent overflow in
+ * following calculation.
+ * We do check jpeg_width and jpeg_height in initial_setup below,
+ * but image_width and image_height can come from arbitrary data,
+ * and we need some space for multiplication by block_size.
+ */
+ if (((long) cinfo->image_width >> 24) || ((long) cinfo->image_height >> 24))
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+ /* Compute actual JPEG image dimensions and DCT scaling choices. */
+ if (cinfo->scale_num >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/1 scaling */
+ cinfo->jpeg_width = cinfo->image_width * cinfo->block_size;
+ cinfo->jpeg_height = cinfo->image_height * cinfo->block_size;
+ cinfo->min_DCT_h_scaled_size = 1;
+ cinfo->min_DCT_v_scaled_size = 1;
+ } else if (cinfo->scale_num * 2 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/2 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 2L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 2L);
+ cinfo->min_DCT_h_scaled_size = 2;
+ cinfo->min_DCT_v_scaled_size = 2;
+ } else if (cinfo->scale_num * 3 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/3 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 3L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 3L);
+ cinfo->min_DCT_h_scaled_size = 3;
+ cinfo->min_DCT_v_scaled_size = 3;
+ } else if (cinfo->scale_num * 4 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/4 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 4L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 4L);
+ cinfo->min_DCT_h_scaled_size = 4;
+ cinfo->min_DCT_v_scaled_size = 4;
+ } else if (cinfo->scale_num * 5 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/5 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 5L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 5L);
+ cinfo->min_DCT_h_scaled_size = 5;
+ cinfo->min_DCT_v_scaled_size = 5;
+ } else if (cinfo->scale_num * 6 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/6 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 6L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 6L);
+ cinfo->min_DCT_h_scaled_size = 6;
+ cinfo->min_DCT_v_scaled_size = 6;
+ } else if (cinfo->scale_num * 7 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/7 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 7L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 7L);
+ cinfo->min_DCT_h_scaled_size = 7;
+ cinfo->min_DCT_v_scaled_size = 7;
+ } else if (cinfo->scale_num * 8 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/8 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 8L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 8L);
+ cinfo->min_DCT_h_scaled_size = 8;
+ cinfo->min_DCT_v_scaled_size = 8;
+ } else if (cinfo->scale_num * 9 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/9 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 9L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 9L);
+ cinfo->min_DCT_h_scaled_size = 9;
+ cinfo->min_DCT_v_scaled_size = 9;
+ } else if (cinfo->scale_num * 10 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/10 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 10L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 10L);
+ cinfo->min_DCT_h_scaled_size = 10;
+ cinfo->min_DCT_v_scaled_size = 10;
+ } else if (cinfo->scale_num * 11 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/11 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 11L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 11L);
+ cinfo->min_DCT_h_scaled_size = 11;
+ cinfo->min_DCT_v_scaled_size = 11;
+ } else if (cinfo->scale_num * 12 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/12 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 12L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 12L);
+ cinfo->min_DCT_h_scaled_size = 12;
+ cinfo->min_DCT_v_scaled_size = 12;
+ } else if (cinfo->scale_num * 13 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/13 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 13L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 13L);
+ cinfo->min_DCT_h_scaled_size = 13;
+ cinfo->min_DCT_v_scaled_size = 13;
+ } else if (cinfo->scale_num * 14 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/14 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 14L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 14L);
+ cinfo->min_DCT_h_scaled_size = 14;
+ cinfo->min_DCT_v_scaled_size = 14;
+ } else if (cinfo->scale_num * 15 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/15 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 15L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 15L);
+ cinfo->min_DCT_h_scaled_size = 15;
+ cinfo->min_DCT_v_scaled_size = 15;
+ } else {
+ /* Provide block_size/16 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 16L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 16L);
+ cinfo->min_DCT_h_scaled_size = 16;
+ cinfo->min_DCT_v_scaled_size = 16;
+ }
+
+#else /* !DCT_SCALING_SUPPORTED */
+
+ /* Hardwire it to "no scaling" */
+ cinfo->jpeg_width = cinfo->image_width;
+ cinfo->jpeg_height = cinfo->image_height;
+ cinfo->min_DCT_h_scaled_size = DCTSIZE;
+ cinfo->min_DCT_v_scaled_size = DCTSIZE;
+
+#endif /* DCT_SCALING_SUPPORTED */
+}
+
+
+LOCAL(void)
+jpeg_calc_trans_dimensions (j_compress_ptr cinfo)
+{
+ if (cinfo->min_DCT_h_scaled_size != cinfo->min_DCT_v_scaled_size)
+ ERREXIT2(cinfo, JERR_BAD_DCTSIZE,
+ cinfo->min_DCT_h_scaled_size, cinfo->min_DCT_v_scaled_size);
+
+ cinfo->block_size = cinfo->min_DCT_h_scaled_size;
+}
+
+
+LOCAL(void)
+initial_setup (j_compress_ptr cinfo, boolean transcode_only)
+/* Do computations that are needed before master selection phase */
+{
+ int ci, ssize;
+ jpeg_component_info *compptr;
+ long samplesperrow;
+ JDIMENSION jd_samplesperrow;
+
+ if (transcode_only)
+ jpeg_calc_trans_dimensions(cinfo);
+ else
+ jpeg_calc_jpeg_dimensions(cinfo);
+
+ /* Sanity check on block_size */
+ if (cinfo->block_size < 1 || cinfo->block_size > 16)
+ ERREXIT2(cinfo, JERR_BAD_DCTSIZE, cinfo->block_size, cinfo->block_size);
+
+ /* Derive natural_order from block_size */
+ switch (cinfo->block_size) {
+ case 2: cinfo->natural_order = jpeg_natural_order2; break;
+ case 3: cinfo->natural_order = jpeg_natural_order3; break;
+ case 4: cinfo->natural_order = jpeg_natural_order4; break;
+ case 5: cinfo->natural_order = jpeg_natural_order5; break;
+ case 6: cinfo->natural_order = jpeg_natural_order6; break;
+ case 7: cinfo->natural_order = jpeg_natural_order7; break;
+ default: cinfo->natural_order = jpeg_natural_order; break;
+ }
+
+ /* Derive lim_Se from block_size */
+ cinfo->lim_Se = cinfo->block_size < DCTSIZE ?
+ cinfo->block_size * cinfo->block_size - 1 : DCTSIZE2-1;
+
+ /* Sanity check on image dimensions */
+ if (cinfo->jpeg_height <= 0 || cinfo->jpeg_width <= 0 ||
+ cinfo->num_components <= 0 || cinfo->input_components <= 0)
+ ERREXIT(cinfo, JERR_EMPTY_IMAGE);
+
+ /* Make sure image isn't bigger than I can handle */
+ if ((long) cinfo->jpeg_height > (long) JPEG_MAX_DIMENSION ||
+ (long) cinfo->jpeg_width > (long) JPEG_MAX_DIMENSION)
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+ /* Width of an input scanline must be representable as JDIMENSION. */
+ samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components;
+ jd_samplesperrow = (JDIMENSION) samplesperrow;
+ if ((long) jd_samplesperrow != samplesperrow)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+
+ /* For now, precision must match compiled-in value... */
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ /* Check that number of components won't exceed internal array sizes */
+ if (cinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPONENTS);
+
+ /* Compute maximum sampling factors; check factor validity */
+ cinfo->max_h_samp_factor = 1;
+ cinfo->max_v_samp_factor = 1;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
+ compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
+ ERREXIT(cinfo, JERR_BAD_SAMPLING);
+ cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
+ compptr->h_samp_factor);
+ cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
+ compptr->v_samp_factor);
+ }
+
+ /* Compute dimensions of components */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Fill in the correct component_index value; don't rely on application */
+ compptr->component_index = ci;
+ /* In selecting the actual DCT scaling for each component, we try to
+ * scale down the chroma components via DCT scaling rather than downsampling.
+ * This saves time if the downsampler gets to use 1:1 scaling.
+ * Note this code adapts subsampling ratios which are powers of 2.
+ */
+ ssize = 1;
+#ifdef DCT_SCALING_SUPPORTED
+ while (cinfo->min_DCT_h_scaled_size * ssize <=
+ (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&
+ (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == 0) {
+ ssize = ssize * 2;
+ }
+#endif
+ compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize;
+ ssize = 1;
+#ifdef DCT_SCALING_SUPPORTED
+ while (cinfo->min_DCT_v_scaled_size * ssize <=
+ (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&
+ (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == 0) {
+ ssize = ssize * 2;
+ }
+#endif
+ compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize;
+
+ /* We don't support DCT ratios larger than 2. */
+ if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2)
+ compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2;
+ else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2)
+ compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2;
+
+ /* Size in DCT blocks */
+ compptr->width_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_width * (long) compptr->h_samp_factor,
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ compptr->height_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_height * (long) compptr->v_samp_factor,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+ /* Size in samples */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_width *
+ (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size),
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_height *
+ (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size),
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+ /* Mark component needed (this flag isn't actually used for compression) */
+ compptr->component_needed = TRUE;
+ }
+
+ /* Compute number of fully interleaved MCU rows (number of times that
+ * main controller will call coefficient controller).
+ */
+ cinfo->total_iMCU_rows = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_height,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+}
+
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+
+LOCAL(void)
+validate_script (j_compress_ptr cinfo)
+/* Verify that the scan script in cinfo->scan_info[] is valid; also
+ * determine whether it uses progressive JPEG, and set cinfo->progressive_mode.
+ */
+{
+ const jpeg_scan_info * scanptr;
+ int scanno, ncomps, ci, coefi, thisi;
+ int Ss, Se, Ah, Al;
+ boolean component_sent[MAX_COMPONENTS];
+#ifdef C_PROGRESSIVE_SUPPORTED
+ int * last_bitpos_ptr;
+ int last_bitpos[MAX_COMPONENTS][DCTSIZE2];
+ /* -1 until that coefficient has been seen; then last Al for it */
+#endif
+
+ if (cinfo->num_scans <= 0)
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0);
+
+ /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1;
+ * for progressive JPEG, no scan can have this.
+ */
+ scanptr = cinfo->scan_info;
+ if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ cinfo->progressive_mode = TRUE;
+ last_bitpos_ptr = & last_bitpos[0][0];
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ for (coefi = 0; coefi < DCTSIZE2; coefi++)
+ *last_bitpos_ptr++ = -1;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ cinfo->progressive_mode = FALSE;
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ component_sent[ci] = FALSE;
+ }
+
+ for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) {
+ /* Validate component indexes */
+ ncomps = scanptr->comps_in_scan;
+ if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN);
+ for (ci = 0; ci < ncomps; ci++) {
+ thisi = scanptr->component_index[ci];
+ if (thisi < 0 || thisi >= cinfo->num_components)
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+ /* Components must appear in SOF order within each scan */
+ if (ci > 0 && thisi <= scanptr->component_index[ci-1])
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+ }
+ /* Validate progression parameters */
+ Ss = scanptr->Ss;
+ Se = scanptr->Se;
+ Ah = scanptr->Ah;
+ Al = scanptr->Al;
+ if (cinfo->progressive_mode) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that
+ * seems wrong: the upper bound ought to depend on data precision.
+ * Perhaps they really meant 0..N+1 for N-bit precision.
+ * Here we allow 0..10 for 8-bit data; Al larger than 10 results in
+ * out-of-range reconstructed DC values during the first DC scan,
+ * which might cause problems for some decoders.
+ */
+#if BITS_IN_JSAMPLE == 8
+#define MAX_AH_AL 10
+#else
+#define MAX_AH_AL 13
+#endif
+ if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 ||
+ Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ if (Ss == 0) {
+ if (Se != 0) /* DC and AC together not OK */
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ } else {
+ if (ncomps != 1) /* AC scans must be for only one component */
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ }
+ for (ci = 0; ci < ncomps; ci++) {
+ last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0];
+ if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ for (coefi = Ss; coefi <= Se; coefi++) {
+ if (last_bitpos_ptr[coefi] < 0) {
+ /* first scan of this coefficient */
+ if (Ah != 0)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ } else {
+ /* not first scan */
+ if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ }
+ last_bitpos_ptr[coefi] = Al;
+ }
+ }
+#endif
+ } else {
+ /* For sequential JPEG, all progression parameters must be these: */
+ if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ /* Make sure components are not sent twice */
+ for (ci = 0; ci < ncomps; ci++) {
+ thisi = scanptr->component_index[ci];
+ if (component_sent[thisi])
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+ component_sent[thisi] = TRUE;
+ }
+ }
+ }
+
+ /* Now verify that everything got sent. */
+ if (cinfo->progressive_mode) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ /* For progressive mode, we only check that at least some DC data
+ * got sent for each component; the spec does not require that all bits
+ * of all coefficients be transmitted. Would it be wiser to enforce
+ * transmission of all coefficient bits??
+ */
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ if (last_bitpos[ci][0] < 0)
+ ERREXIT(cinfo, JERR_MISSING_DATA);
+ }
+#endif
+ } else {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ if (! component_sent[ci])
+ ERREXIT(cinfo, JERR_MISSING_DATA);
+ }
+ }
+}
+
+
+LOCAL(void)
+reduce_script (j_compress_ptr cinfo)
+/* Adapt scan script for use with reduced block size;
+ * assume that script has been validated before.
+ */
+{
+ jpeg_scan_info * scanptr;
+ int idxout, idxin;
+
+ /* Circumvent const declaration for this function */
+ scanptr = (jpeg_scan_info *) cinfo->scan_info;
+ idxout = 0;
+
+ for (idxin = 0; idxin < cinfo->num_scans; idxin++) {
+ /* After skipping, idxout becomes smaller than idxin */
+ if (idxin != idxout)
+ /* Copy rest of data;
+ * note we stay in given chunk of allocated memory.
+ */
+ scanptr[idxout] = scanptr[idxin];
+ if (scanptr[idxout].Ss > cinfo->lim_Se)
+ /* Entire scan out of range - skip this entry */
+ continue;
+ if (scanptr[idxout].Se > cinfo->lim_Se)
+ /* Limit scan to end of block */
+ scanptr[idxout].Se = cinfo->lim_Se;
+ idxout++;
+ }
+
+ cinfo->num_scans = idxout;
+}
+
+#endif /* C_MULTISCAN_FILES_SUPPORTED */
+
+
+LOCAL(void)
+select_scan_parameters (j_compress_ptr cinfo)
+/* Set up the scan parameters for the current scan */
+{
+ int ci;
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ if (cinfo->scan_info != NULL) {
+ /* Prepare for current scan --- the script is already validated */
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+ const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number;
+
+ cinfo->comps_in_scan = scanptr->comps_in_scan;
+ for (ci = 0; ci < scanptr->comps_in_scan; ci++) {
+ cinfo->cur_comp_info[ci] =
+ &cinfo->comp_info[scanptr->component_index[ci]];
+ }
+ if (cinfo->progressive_mode) {
+ cinfo->Ss = scanptr->Ss;
+ cinfo->Se = scanptr->Se;
+ cinfo->Ah = scanptr->Ah;
+ cinfo->Al = scanptr->Al;
+ return;
+ }
+ }
+ else
+#endif
+ {
+ /* Prepare for single sequential-JPEG scan containing all components */
+ if (cinfo->num_components > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPS_IN_SCAN);
+ cinfo->comps_in_scan = cinfo->num_components;
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci];
+ }
+ }
+ cinfo->Ss = 0;
+ cinfo->Se = cinfo->block_size * cinfo->block_size - 1;
+ cinfo->Ah = 0;
+ cinfo->Al = 0;
+}
+
+
+LOCAL(void)
+per_scan_setup (j_compress_ptr cinfo)
+/* Do computations that are needed before processing a JPEG scan */
+/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */
+{
+ int ci, mcublks, tmp;
+ jpeg_component_info *compptr;
+
+ if (cinfo->comps_in_scan == 1) {
+
+ /* Noninterleaved (single-component) scan */
+ compptr = cinfo->cur_comp_info[0];
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = compptr->width_in_blocks;
+ cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
+
+ /* For noninterleaved scan, always one block per MCU */
+ compptr->MCU_width = 1;
+ compptr->MCU_height = 1;
+ compptr->MCU_blocks = 1;
+ compptr->MCU_sample_width = compptr->DCT_h_scaled_size;
+ compptr->last_col_width = 1;
+ /* For noninterleaved scans, it is convenient to define last_row_height
+ * as the number of block rows present in the last iMCU row.
+ */
+ tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (tmp == 0) tmp = compptr->v_samp_factor;
+ compptr->last_row_height = tmp;
+
+ /* Prepare array describing MCU composition */
+ cinfo->blocks_in_MCU = 1;
+ cinfo->MCU_membership[0] = 0;
+
+ } else {
+
+ /* Interleaved (multi-component) scan */
+ if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
+ MAX_COMPS_IN_SCAN);
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_width,
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ cinfo->MCU_rows_in_scan = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_height,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+
+ cinfo->blocks_in_MCU = 0;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Sampling factors give # of blocks of component in each MCU */
+ compptr->MCU_width = compptr->h_samp_factor;
+ compptr->MCU_height = compptr->v_samp_factor;
+ compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
+ compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size;
+ /* Figure number of non-dummy blocks in last MCU column & row */
+ tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
+ if (tmp == 0) tmp = compptr->MCU_width;
+ compptr->last_col_width = tmp;
+ tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
+ if (tmp == 0) tmp = compptr->MCU_height;
+ compptr->last_row_height = tmp;
+ /* Prepare array describing MCU composition */
+ mcublks = compptr->MCU_blocks;
+ if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU)
+ ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
+ while (mcublks-- > 0) {
+ cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
+ }
+ }
+
+ }
+
+ /* Convert restart specified in rows to actual MCU count. */
+ /* Note that count must fit in 16 bits, so we provide limiting. */
+ if (cinfo->restart_in_rows > 0) {
+ long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row;
+ cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L);
+ }
+}
+
+
+/*
+ * Per-pass setup.
+ * This is called at the beginning of each pass. We determine which modules
+ * will be active during this pass and give them appropriate start_pass calls.
+ * We also set is_last_pass to indicate whether any more passes will be
+ * required.
+ */
+
+METHODDEF(void)
+prepare_for_pass (j_compress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ switch (master->pass_type) {
+ case main_pass:
+ /* Initial pass: will collect input data, and do either Huffman
+ * optimization or data output for the first scan.
+ */
+ select_scan_parameters(cinfo);
+ per_scan_setup(cinfo);
+ if (! cinfo->raw_data_in) {
+ (*cinfo->cconvert->start_pass) (cinfo);
+ (*cinfo->downsample->start_pass) (cinfo);
+ (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU);
+ }
+ (*cinfo->fdct->start_pass) (cinfo);
+ (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding);
+ (*cinfo->coef->start_pass) (cinfo,
+ (master->total_passes > 1 ?
+ JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
+ (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
+ if (cinfo->optimize_coding) {
+ /* No immediate data output; postpone writing frame/scan headers */
+ master->pub.call_pass_startup = FALSE;
+ } else {
+ /* Will write frame/scan headers at first jpeg_write_scanlines call */
+ master->pub.call_pass_startup = TRUE;
+ }
+ break;
+#ifdef ENTROPY_OPT_SUPPORTED
+ case huff_opt_pass:
+ /* Do Huffman optimization for a scan after the first one. */
+ select_scan_parameters(cinfo);
+ per_scan_setup(cinfo);
+ if (cinfo->Ss != 0 || cinfo->Ah == 0) {
+ (*cinfo->entropy->start_pass) (cinfo, TRUE);
+ (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
+ master->pub.call_pass_startup = FALSE;
+ break;
+ }
+ /* Special case: Huffman DC refinement scans need no Huffman table
+ * and therefore we can skip the optimization pass for them.
+ */
+ master->pass_type = output_pass;
+ master->pass_number++;
+ /*FALLTHROUGH*/
+#endif
+ case output_pass:
+ /* Do a data-output pass. */
+ /* We need not repeat per-scan setup if prior optimization pass did it. */
+ if (! cinfo->optimize_coding) {
+ select_scan_parameters(cinfo);
+ per_scan_setup(cinfo);
+ }
+ (*cinfo->entropy->start_pass) (cinfo, FALSE);
+ (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
+ /* We emit frame/scan headers now */
+ if (master->scan_number == 0)
+ (*cinfo->marker->write_frame_header) (cinfo);
+ (*cinfo->marker->write_scan_header) (cinfo);
+ master->pub.call_pass_startup = FALSE;
+ break;
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ }
+
+ master->pub.is_last_pass = (master->pass_number == master->total_passes-1);
+
+ /* Set up progress monitor's pass info if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->completed_passes = master->pass_number;
+ cinfo->progress->total_passes = master->total_passes;
+ }
+}
+
+
+/*
+ * Special start-of-pass hook.
+ * This is called by jpeg_write_scanlines if call_pass_startup is TRUE.
+ * In single-pass processing, we need this hook because we don't want to
+ * write frame/scan headers during jpeg_start_compress; we want to let the
+ * application write COM markers etc. between jpeg_start_compress and the
+ * jpeg_write_scanlines loop.
+ * In multi-pass processing, this routine is not used.
+ */
+
+METHODDEF(void)
+pass_startup (j_compress_ptr cinfo)
+{
+ cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */
+
+ (*cinfo->marker->write_frame_header) (cinfo);
+ (*cinfo->marker->write_scan_header) (cinfo);
+}
+
+
+/*
+ * Finish up at end of pass.
+ */
+
+METHODDEF(void)
+finish_pass_master (j_compress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ /* The entropy coder always needs an end-of-pass call,
+ * either to analyze statistics or to flush its output buffer.
+ */
+ (*cinfo->entropy->finish_pass) (cinfo);
+
+ /* Update state for next pass */
+ switch (master->pass_type) {
+ case main_pass:
+ /* next pass is either output of scan 0 (after optimization)
+ * or output of scan 1 (if no optimization).
+ */
+ master->pass_type = output_pass;
+ if (! cinfo->optimize_coding)
+ master->scan_number++;
+ break;
+ case huff_opt_pass:
+ /* next pass is always output of current scan */
+ master->pass_type = output_pass;
+ break;
+ case output_pass:
+ /* next pass is either optimization or output of next scan */
+ if (cinfo->optimize_coding)
+ master->pass_type = huff_opt_pass;
+ master->scan_number++;
+ break;
+ }
+
+ master->pass_number++;
+}
+
+
+/*
+ * Initialize master compression control.
+ */
+
+GLOBAL(void)
+jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
+{
+ my_master_ptr master;
+
+ master = (my_master_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_comp_master));
+ cinfo->master = (struct jpeg_comp_master *) master;
+ master->pub.prepare_for_pass = prepare_for_pass;
+ master->pub.pass_startup = pass_startup;
+ master->pub.finish_pass = finish_pass_master;
+ master->pub.is_last_pass = FALSE;
+
+ /* Validate parameters, determine derived values */
+ initial_setup(cinfo, transcode_only);
+
+ if (cinfo->scan_info != NULL) {
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ validate_script(cinfo);
+ if (cinfo->block_size < DCTSIZE)
+ reduce_script(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ cinfo->progressive_mode = FALSE;
+ cinfo->num_scans = 1;
+ }
+
+ if ((cinfo->progressive_mode || cinfo->block_size < DCTSIZE) &&
+ !cinfo->arith_code) /* TEMPORARY HACK ??? */
+ /* assume default tables no good for progressive or downscale mode */
+ cinfo->optimize_coding = TRUE;
+
+ /* Initialize my private state */
+ if (transcode_only) {
+ /* no main pass in transcoding */
+ if (cinfo->optimize_coding)
+ master->pass_type = huff_opt_pass;
+ else
+ master->pass_type = output_pass;
+ } else {
+ /* for normal compression, first pass is always this type: */
+ master->pass_type = main_pass;
+ }
+ master->scan_number = 0;
+ master->pass_number = 0;
+ if (cinfo->optimize_coding)
+ master->total_passes = cinfo->num_scans * 2;
+ else
+ master->total_passes = cinfo->num_scans;
+}
diff --git a/external/jpeg-8c/jcomapi.c b/external/jpeg-8c/jcomapi.c
new file mode 100644
index 0000000..9b1fa75
--- /dev/null
+++ b/external/jpeg-8c/jcomapi.c
@@ -0,0 +1,106 @@
+/*
+ * jcomapi.c
+ *
+ * Copyright (C) 1994-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 application interface routines that are used for both
+ * compression and decompression.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Abort processing of a JPEG compression or decompression operation,
+ * but don't destroy the object itself.
+ *
+ * For this, we merely clean up all the nonpermanent memory pools.
+ * Note that temp files (virtual arrays) are not allowed to belong to
+ * the permanent pool, so we will be able to close all temp files here.
+ * Closing a data source or destination, if necessary, is the application's
+ * responsibility.
+ */
+
+GLOBAL(void)
+jpeg_abort (j_common_ptr cinfo)
+{
+ int pool;
+
+ /* Do nothing if called on a not-initialized or destroyed JPEG object. */
+ if (cinfo->mem == NULL)
+ return;
+
+ /* Releasing pools in reverse order might help avoid fragmentation
+ * with some (brain-damaged) malloc libraries.
+ */
+ for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) {
+ (*cinfo->mem->free_pool) (cinfo, pool);
+ }
+
+ /* Reset overall state for possible reuse of object */
+ if (cinfo->is_decompressor) {
+ cinfo->global_state = DSTATE_START;
+ /* Try to keep application from accessing now-deleted marker list.
+ * A bit kludgy to do it here, but this is the most central place.
+ */
+ ((j_decompress_ptr) cinfo)->marker_list = NULL;
+ } else {
+ cinfo->global_state = CSTATE_START;
+ }
+}
+
+
+/*
+ * Destruction of a JPEG object.
+ *
+ * Everything gets deallocated except the master jpeg_compress_struct itself
+ * and the error manager struct. Both of these are supplied by the application
+ * and must be freed, if necessary, by the application. (Often they are on
+ * the stack and so don't need to be freed anyway.)
+ * Closing a data source or destination, if necessary, is the application's
+ * responsibility.
+ */
+
+GLOBAL(void)
+jpeg_destroy (j_common_ptr cinfo)
+{
+ /* We need only tell the memory manager to release everything. */
+ /* NB: mem pointer is NULL if memory mgr failed to initialize. */
+ if (cinfo->mem != NULL)
+ (*cinfo->mem->self_destruct) (cinfo);
+ cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */
+ cinfo->global_state = 0; /* mark it destroyed */
+}
+
+
+/*
+ * Convenience routines for allocating quantization and Huffman tables.
+ * (Would jutils.c be a more reasonable place to put these?)
+ */
+
+GLOBAL(JQUANT_TBL *)
+jpeg_alloc_quant_table (j_common_ptr cinfo)
+{
+ JQUANT_TBL *tbl;
+
+ tbl = (JQUANT_TBL *)
+ (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL));
+ tbl->sent_table = FALSE; /* make sure this is false in any new table */
+ return tbl;
+}
+
+
+GLOBAL(JHUFF_TBL *)
+jpeg_alloc_huff_table (j_common_ptr cinfo)
+{
+ JHUFF_TBL *tbl;
+
+ tbl = (JHUFF_TBL *)
+ (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL));
+ tbl->sent_table = FALSE; /* make sure this is false in any new table */
+ return tbl;
+}
diff --git a/external/jpeg-8c/jconfig.h b/external/jpeg-8c/jconfig.h
new file mode 100644
index 0000000..248d6d0
--- /dev/null
+++ b/external/jpeg-8c/jconfig.h
@@ -0,0 +1,60 @@
+/* jconfig.h. Generated from jconfig.cfg by configure. */
+/* jconfig.cfg --- source file edited by configure script */
+/* see jconfig.txt for explanations */
+
+/* Define this if you get warnings about undefined structures. */
+/* #undef INCOMPLETE_TYPES_BROKEN */
+
+#define HAVE_PROTOTYPES 1
+#define HAVE_UNSIGNED_CHAR 1
+#define HAVE_UNSIGNED_SHORT 1
+/* #undef void */
+/* #undef const */
+/* #undef CHAR_IS_UNSIGNED */
+
+#ifdef JPEG_INTERNALS
+
+#define HAVE_STDDEF_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_LOCALE_H 1
+/* #undef NEED_BSD_STRINGS */
+/* #undef NEED_SYS_TYPES_H */
+/* #undef NEED_FAR_POINTERS */
+/* #undef NEED_SHORT_EXTERNAL_NAMES */
+
+/* Define "boolean" as unsigned char, not int, on Windows systems. */
+#ifdef _WIN32
+#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
+typedef unsigned char boolean;
+#endif
+#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
+#endif
+
+/* #undef RIGHT_SHIFT_IS_UNSIGNED */
+#ifdef _MSC_VER
+#define INLINE __inline
+#else
+#define INLINE __inline__
+#endif
+/* These are for configuring the JPEG memory manager. */
+/* #undef DEFAULT_MAX_MEM */
+/* #undef NO_MKTEMP */
+
+#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 */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+/* #undef TWO_FILE_COMMANDLINE */
+/* #undef NEED_SIGNAL_CATCHER */
+/* #undef DONT_USE_B_MODE */
+
+/* Define this if you want percent-done progress reports from cjpeg/djpeg. */
+/* #undef PROGRESS_REPORT */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/external/jpeg-8c/jcparam.c b/external/jpeg-8c/jcparam.c
new file mode 100644
index 0000000..c5e85dd
--- /dev/null
+++ b/external/jpeg-8c/jcparam.c
@@ -0,0 +1,632 @@
+/*
+ * jcparam.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2003-2008 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains optional default-setting code for the JPEG compressor.
+ * Applications do not have to use this file, but those that don't use it
+ * must know a lot more about the innards of the JPEG code.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Quantization table setup routines
+ */
+
+GLOBAL(void)
+jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
+ const unsigned int *basic_table,
+ int scale_factor, boolean force_baseline)
+/* Define a quantization table equal to the basic_table times
+ * a scale factor (given as a percentage).
+ * If force_baseline is TRUE, the computed quantization table entries
+ * are limited to 1..255 for JPEG baseline compatibility.
+ */
+{
+ JQUANT_TBL ** qtblptr;
+ int i;
+ long temp;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS)
+ ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl);
+
+ qtblptr = & cinfo->quant_tbl_ptrs[which_tbl];
+
+ if (*qtblptr == NULL)
+ *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo);
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ temp = ((long) basic_table[i] * scale_factor + 50L) / 100L;
+ /* limit the values to the valid range */
+ if (temp <= 0L) temp = 1L;
+ if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */
+ if (force_baseline && temp > 255L)
+ temp = 255L; /* limit to baseline range if requested */
+ (*qtblptr)->quantval[i] = (UINT16) temp;
+ }
+
+ /* Initialize sent_table FALSE so table will be written to JPEG file. */
+ (*qtblptr)->sent_table = FALSE;
+}
+
+
+/* These are the sample quantization tables given in JPEG spec section K.1.
+ * The spec says that the values given produce "good" quality, and
+ * when divided by 2, "very good" quality.
+ */
+static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+};
+static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+
+GLOBAL(void)
+jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables
+ * and straight percentage-scaling quality scales.
+ * This entry point allows different scalings for luminance and chrominance.
+ */
+{
+ /* Set up two quantization tables using the specified scaling */
+ jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
+ cinfo->q_scale_factor[0], force_baseline);
+ jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
+ cinfo->q_scale_factor[1], force_baseline);
+}
+
+
+GLOBAL(void)
+jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,
+ boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables
+ * and a straight percentage-scaling quality scale. In most cases it's better
+ * to use jpeg_set_quality (below); this entry point is provided for
+ * applications that insist on a linear percentage scaling.
+ */
+{
+ /* Set up two quantization tables using the specified scaling */
+ jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
+ scale_factor, force_baseline);
+ jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
+ scale_factor, force_baseline);
+}
+
+
+GLOBAL(int)
+jpeg_quality_scaling (int quality)
+/* Convert a user-specified quality rating to a percentage scaling factor
+ * for an underlying quantization table, using our recommended scaling curve.
+ * The input 'quality' factor should be 0 (terrible) to 100 (very good).
+ */
+{
+ /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */
+ if (quality <= 0) quality = 1;
+ if (quality > 100) quality = 100;
+
+ /* The basic table is used as-is (scaling 100) for a quality of 50.
+ * Qualities 50..100 are converted to scaling percentage 200 - 2*Q;
+ * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table
+ * to make all the table entries 1 (hence, minimum quantization loss).
+ * Qualities 1..50 are converted to scaling percentage 5000/Q.
+ */
+ if (quality < 50)
+ quality = 5000 / quality;
+ else
+ quality = 200 - quality*2;
+
+ return quality;
+}
+
+
+GLOBAL(void)
+jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables.
+ * This is the standard quality-adjusting entry point for typical user
+ * interfaces; only those who want detailed control over quantization tables
+ * would use the preceding three routines directly.
+ */
+{
+ /* Convert user 0-100 rating to percentage scaling */
+ quality = jpeg_quality_scaling(quality);
+
+ /* Set up standard quality tables */
+ jpeg_set_linear_quality(cinfo, quality, force_baseline);
+}
+
+
+/*
+ * Huffman table setup routines
+ */
+
+LOCAL(void)
+add_huff_table (j_compress_ptr cinfo,
+ JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val)
+/* Define a Huffman table */
+{
+ int nsymbols, len;
+
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+
+ /* Copy the number-of-symbols-of-each-code-length counts */
+ MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits));
+
+ /* Validate the counts. We do this here mainly so we can copy the right
+ * number of symbols from the val[] array, without risking marching off
+ * the end of memory. jchuff.c will do a more thorough test later.
+ */
+ nsymbols = 0;
+ for (len = 1; len <= 16; len++)
+ nsymbols += bits[len];
+ if (nsymbols < 1 || nsymbols > 256)
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+
+ MEMCOPY((*htblptr)->huffval, val, nsymbols * SIZEOF(UINT8));
+
+ /* Initialize sent_table FALSE so table will be written to JPEG file. */
+ (*htblptr)->sent_table = FALSE;
+}
+
+
+LOCAL(void)
+std_huff_tables (j_compress_ptr cinfo)
+/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
+/* IMPORTANT: these are only valid for 8-bit data precision! */
+{
+ static const UINT8 bits_dc_luminance[17] =
+ { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
+ static const UINT8 val_dc_luminance[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ static const UINT8 bits_dc_chrominance[17] =
+ { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
+ static const UINT8 val_dc_chrominance[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ static const UINT8 bits_ac_luminance[17] =
+ { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
+ static const UINT8 val_ac_luminance[] =
+ { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa };
+
+ static const UINT8 bits_ac_chrominance[17] =
+ { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
+ static const UINT8 val_ac_chrominance[] =
+ { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa };
+
+ add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0],
+ bits_dc_luminance, val_dc_luminance);
+ add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0],
+ bits_ac_luminance, val_ac_luminance);
+ add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1],
+ bits_dc_chrominance, val_dc_chrominance);
+ add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1],
+ bits_ac_chrominance, val_ac_chrominance);
+}
+
+
+/*
+ * Default parameter setup for compression.
+ *
+ * Applications that don't choose to use this routine must do their
+ * own setup of all these parameters. Alternately, you can call this
+ * to establish defaults and then alter parameters selectively. This
+ * is the recommended approach since, if we add any new parameters,
+ * your code will still work (they'll be set to reasonable defaults).
+ */
+
+GLOBAL(void)
+jpeg_set_defaults (j_compress_ptr cinfo)
+{
+ int i;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* Allocate comp_info array large enough for maximum component count.
+ * Array is made permanent in case application wants to compress
+ * multiple images at same param settings.
+ */
+ if (cinfo->comp_info == NULL)
+ cinfo->comp_info = (jpeg_component_info *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ MAX_COMPONENTS * SIZEOF(jpeg_component_info));
+
+ /* Initialize everything not dependent on the color space */
+
+ cinfo->scale_num = 1; /* 1:1 scaling */
+ cinfo->scale_denom = 1;
+ cinfo->data_precision = BITS_IN_JSAMPLE;
+ /* Set up two quantization tables using default quality of 75 */
+ jpeg_set_quality(cinfo, 75, TRUE);
+ /* Set up two Huffman tables */
+ std_huff_tables(cinfo);
+
+ /* Initialize default arithmetic coding conditioning */
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ cinfo->arith_dc_L[i] = 0;
+ cinfo->arith_dc_U[i] = 1;
+ cinfo->arith_ac_K[i] = 5;
+ }
+
+ /* Default is no multiple-scan output */
+ cinfo->scan_info = NULL;
+ cinfo->num_scans = 0;
+
+ /* Expect normal source image, not raw downsampled data */
+ cinfo->raw_data_in = FALSE;
+
+ /* Use Huffman coding, not arithmetic coding, by default */
+ cinfo->arith_code = FALSE;
+
+ /* By default, don't do extra passes to optimize entropy coding */
+ cinfo->optimize_coding = FALSE;
+ /* The standard Huffman tables are only valid for 8-bit data precision.
+ * If the precision is higher, force optimization on so that usable
+ * tables will be computed. This test can be removed if default tables
+ * are supplied that are valid for the desired precision.
+ */
+ if (cinfo->data_precision > 8)
+ cinfo->optimize_coding = TRUE;
+
+ /* By default, use the simpler non-cosited sampling alignment */
+ cinfo->CCIR601_sampling = FALSE;
+
+ /* By default, apply fancy downsampling */
+ cinfo->do_fancy_downsampling = TRUE;
+
+ /* No input smoothing */
+ cinfo->smoothing_factor = 0;
+
+ /* DCT algorithm preference */
+ cinfo->dct_method = JDCT_DEFAULT;
+
+ /* No restart markers */
+ cinfo->restart_interval = 0;
+ cinfo->restart_in_rows = 0;
+
+ /* Fill in default JFIF marker parameters. Note that whether the marker
+ * will actually be written is determined by jpeg_set_colorspace.
+ *
+ * By default, the library emits JFIF version code 1.01.
+ * An application that wants to emit JFIF 1.02 extension markers should set
+ * JFIF_minor_version to 2. We could probably get away with just defaulting
+ * to 1.02, but there may still be some decoders in use that will complain
+ * about that; saying 1.01 should minimize compatibility problems.
+ */
+ cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */
+ cinfo->JFIF_minor_version = 1;
+ cinfo->density_unit = 0; /* Pixel size is unknown by default */
+ cinfo->X_density = 1; /* Pixel aspect ratio is square by default */
+ cinfo->Y_density = 1;
+
+ /* Choose JPEG colorspace based on input space, set defaults accordingly */
+
+ jpeg_default_colorspace(cinfo);
+}
+
+
+/*
+ * Select an appropriate JPEG colorspace for in_color_space.
+ */
+
+GLOBAL(void)
+jpeg_default_colorspace (j_compress_ptr cinfo)
+{
+ switch (cinfo->in_color_space) {
+ case JCS_GRAYSCALE:
+ jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
+ break;
+ case JCS_RGB:
+ jpeg_set_colorspace(cinfo, JCS_YCbCr);
+ break;
+ case JCS_YCbCr:
+ jpeg_set_colorspace(cinfo, JCS_YCbCr);
+ break;
+ case JCS_CMYK:
+ jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */
+ break;
+ case JCS_YCCK:
+ jpeg_set_colorspace(cinfo, JCS_YCCK);
+ break;
+ case JCS_UNKNOWN:
+ jpeg_set_colorspace(cinfo, JCS_UNKNOWN);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ }
+}
+
+
+/*
+ * Set the JPEG colorspace, and choose colorspace-dependent default values.
+ */
+
+GLOBAL(void)
+jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
+{
+ jpeg_component_info * compptr;
+ int ci;
+
+#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \
+ (compptr = &cinfo->comp_info[index], \
+ compptr->component_id = (id), \
+ compptr->h_samp_factor = (hsamp), \
+ compptr->v_samp_factor = (vsamp), \
+ compptr->quant_tbl_no = (quant), \
+ compptr->dc_tbl_no = (dctbl), \
+ compptr->ac_tbl_no = (actbl) )
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* For all colorspaces, we use Q and Huff tables 0 for luminance components,
+ * tables 1 for chrominance components.
+ */
+
+ cinfo->jpeg_color_space = colorspace;
+
+ cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */
+ cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */
+
+ switch (colorspace) {
+ case JCS_GRAYSCALE:
+ cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
+ cinfo->num_components = 1;
+ /* JFIF specifies component ID 1 */
+ SET_COMP(0, 1, 1,1, 0, 0,0);
+ break;
+ case JCS_RGB:
+ cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */
+ cinfo->num_components = 3;
+ SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0);
+ SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0);
+ SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0);
+ break;
+ case JCS_YCbCr:
+ cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
+ cinfo->num_components = 3;
+ /* JFIF specifies component IDs 1,2,3 */
+ /* We default to 2x2 subsamples of chrominance */
+ SET_COMP(0, 1, 2,2, 0, 0,0);
+ SET_COMP(1, 2, 1,1, 1, 1,1);
+ SET_COMP(2, 3, 1,1, 1, 1,1);
+ break;
+ case JCS_CMYK:
+ cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */
+ cinfo->num_components = 4;
+ SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0);
+ SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0);
+ SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0);
+ SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0);
+ break;
+ case JCS_YCCK:
+ cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */
+ cinfo->num_components = 4;
+ SET_COMP(0, 1, 2,2, 0, 0,0);
+ SET_COMP(1, 2, 1,1, 1, 1,1);
+ SET_COMP(2, 3, 1,1, 1, 1,1);
+ SET_COMP(3, 4, 2,2, 0, 0,0);
+ break;
+ case JCS_UNKNOWN:
+ cinfo->num_components = cinfo->input_components;
+ if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPONENTS);
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ SET_COMP(ci, ci, 1,1, 0, 0,0);
+ }
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ }
+}
+
+
+#ifdef C_PROGRESSIVE_SUPPORTED
+
+LOCAL(jpeg_scan_info *)
+fill_a_scan (jpeg_scan_info * scanptr, int ci,
+ int Ss, int Se, int Ah, int Al)
+/* Support routine: generate one scan for specified component */
+{
+ scanptr->comps_in_scan = 1;
+ scanptr->component_index[0] = ci;
+ scanptr->Ss = Ss;
+ scanptr->Se = Se;
+ scanptr->Ah = Ah;
+ scanptr->Al = Al;
+ scanptr++;
+ return scanptr;
+}
+
+LOCAL(jpeg_scan_info *)
+fill_scans (jpeg_scan_info * scanptr, int ncomps,
+ int Ss, int Se, int Ah, int Al)
+/* Support routine: generate one scan for each component */
+{
+ int ci;
+
+ for (ci = 0; ci < ncomps; ci++) {
+ scanptr->comps_in_scan = 1;
+ scanptr->component_index[0] = ci;
+ scanptr->Ss = Ss;
+ scanptr->Se = Se;
+ scanptr->Ah = Ah;
+ scanptr->Al = Al;
+ scanptr++;
+ }
+ return scanptr;
+}
+
+LOCAL(jpeg_scan_info *)
+fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al)
+/* Support routine: generate interleaved DC scan if possible, else N scans */
+{
+ int ci;
+
+ if (ncomps <= MAX_COMPS_IN_SCAN) {
+ /* Single interleaved DC scan */
+ scanptr->comps_in_scan = ncomps;
+ for (ci = 0; ci < ncomps; ci++)
+ scanptr->component_index[ci] = ci;
+ scanptr->Ss = scanptr->Se = 0;
+ scanptr->Ah = Ah;
+ scanptr->Al = Al;
+ scanptr++;
+ } else {
+ /* Noninterleaved DC scan for each component */
+ scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al);
+ }
+ return scanptr;
+}
+
+
+/*
+ * Create a recommended progressive-JPEG script.
+ * cinfo->num_components and cinfo->jpeg_color_space must be correct.
+ */
+
+GLOBAL(void)
+jpeg_simple_progression (j_compress_ptr cinfo)
+{
+ int ncomps = cinfo->num_components;
+ int nscans;
+ jpeg_scan_info * scanptr;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* Figure space needed for script. Calculation must match code below! */
+ if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
+ /* Custom script for YCbCr color images. */
+ nscans = 10;
+ } else {
+ /* All-purpose script for other color spaces. */
+ if (ncomps > MAX_COMPS_IN_SCAN)
+ nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */
+ else
+ nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */
+ }
+
+ /* Allocate space for script.
+ * We need to put it in the permanent pool in case the application performs
+ * multiple compressions without changing the settings. To avoid a memory
+ * leak if jpeg_simple_progression is called repeatedly for the same JPEG
+ * object, we try to re-use previously allocated space, and we allocate
+ * enough space to handle YCbCr even if initially asked for grayscale.
+ */
+ if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) {
+ cinfo->script_space_size = MAX(nscans, 10);
+ cinfo->script_space = (jpeg_scan_info *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ cinfo->script_space_size * SIZEOF(jpeg_scan_info));
+ }
+ scanptr = cinfo->script_space;
+ cinfo->scan_info = scanptr;
+ cinfo->num_scans = nscans;
+
+ if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
+ /* Custom script for YCbCr color images. */
+ /* Initial DC scan */
+ scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
+ /* Initial AC scan: get some luma data out in a hurry */
+ scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2);
+ /* Chroma data is too small to be worth expending many scans on */
+ scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1);
+ scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1);
+ /* Complete spectral selection for luma AC */
+ scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2);
+ /* Refine next bit of luma AC */
+ scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1);
+ /* Finish DC successive approximation */
+ scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
+ /* Finish AC successive approximation */
+ scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0);
+ scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0);
+ /* Luma bottom bit comes last since it's usually largest scan */
+ scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0);
+ } else {
+ /* All-purpose script for other color spaces. */
+ /* Successive approximation first pass */
+ scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
+ scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2);
+ scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2);
+ /* Successive approximation second pass */
+ scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1);
+ /* Successive approximation final pass */
+ scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
+ scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0);
+ }
+}
+
+#endif /* C_PROGRESSIVE_SUPPORTED */
diff --git a/external/jpeg-8c/jcprepct.c b/external/jpeg-8c/jcprepct.c
new file mode 100644
index 0000000..be44cc4
--- /dev/null
+++ b/external/jpeg-8c/jcprepct.c
@@ -0,0 +1,358 @@
+/*
+ * jcprepct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the compression preprocessing controller.
+ * This controller manages the color conversion, downsampling,
+ * and edge expansion steps.
+ *
+ * Most of the complexity here is associated with buffering input rows
+ * as required by the downsampler. See the comments at the head of
+ * jcsample.c for the downsampler's needs.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* At present, jcsample.c can request context rows only for smoothing.
+ * In the future, we might also need context rows for CCIR601 sampling
+ * or other more-complex downsampling procedures. The code to support
+ * context rows should be compiled only if needed.
+ */
+#ifdef INPUT_SMOOTHING_SUPPORTED
+#define CONTEXT_ROWS_SUPPORTED
+#endif
+
+
+/*
+ * For the simple (no-context-row) case, we just need to buffer one
+ * row group's worth of pixels for the downsampling step. At the bottom of
+ * the image, we pad to a full row group by replicating the last pixel row.
+ * The downsampler's last output row is then replicated if needed to pad
+ * out to a full iMCU row.
+ *
+ * When providing context rows, we must buffer three row groups' worth of
+ * pixels. Three row groups are physically allocated, but the row pointer
+ * arrays are made five row groups high, with the extra pointers above and
+ * below "wrapping around" to point to the last and first real row groups.
+ * This allows the downsampler to access the proper context rows.
+ * At the top and bottom of the image, we create dummy context rows by
+ * copying the first or last real pixel row. This copying could be avoided
+ * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the
+ * trouble on the compression side.
+ */
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_prep_controller pub; /* public fields */
+
+ /* Downsampling input buffer. This buffer holds color-converted data
+ * until we have enough to do a downsample step.
+ */
+ JSAMPARRAY color_buf[MAX_COMPONENTS];
+
+ JDIMENSION rows_to_go; /* counts rows remaining in source image */
+ int next_buf_row; /* index of next row to store in color_buf */
+
+#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */
+ int this_row_group; /* starting row index of group to process */
+ int next_buf_stop; /* downsample when we reach this index */
+#endif
+} my_prep_controller;
+
+typedef my_prep_controller * my_prep_ptr;
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+
+ if (pass_mode != JBUF_PASS_THRU)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ /* Initialize total-height counter for detecting bottom of image */
+ prep->rows_to_go = cinfo->image_height;
+ /* Mark the conversion buffer empty */
+ prep->next_buf_row = 0;
+#ifdef CONTEXT_ROWS_SUPPORTED
+ /* Preset additional state variables for context mode.
+ * These aren't used in non-context mode, so we needn't test which mode.
+ */
+ prep->this_row_group = 0;
+ /* Set next_buf_stop to stop after two row groups have been read in. */
+ prep->next_buf_stop = 2 * cinfo->max_v_samp_factor;
+#endif
+}
+
+
+/*
+ * Expand an image vertically from height input_rows to height output_rows,
+ * by duplicating the bottom row.
+ */
+
+LOCAL(void)
+expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols,
+ int input_rows, int output_rows)
+{
+ register int row;
+
+ for (row = input_rows; row < output_rows; row++) {
+ jcopy_sample_rows(image_data, input_rows-1, image_data, row,
+ 1, num_cols);
+ }
+}
+
+
+/*
+ * Process some data in the simple no-context case.
+ *
+ * Preprocessor output data is counted in "row groups". A row group
+ * is defined to be v_samp_factor sample rows of each component.
+ * Downsampling will produce this much data from each max_v_samp_factor
+ * input rows.
+ */
+
+METHODDEF(void)
+pre_process_data (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+ int numrows, ci;
+ JDIMENSION inrows;
+ jpeg_component_info * compptr;
+
+ while (*in_row_ctr < in_rows_avail &&
+ *out_row_group_ctr < out_row_groups_avail) {
+ /* Do color conversion to fill the conversion buffer. */
+ inrows = in_rows_avail - *in_row_ctr;
+ numrows = cinfo->max_v_samp_factor - prep->next_buf_row;
+ numrows = (int) MIN((JDIMENSION) numrows, inrows);
+ (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
+ prep->color_buf,
+ (JDIMENSION) prep->next_buf_row,
+ numrows);
+ *in_row_ctr += numrows;
+ prep->next_buf_row += numrows;
+ prep->rows_to_go -= numrows;
+ /* If at bottom of image, pad to fill the conversion buffer. */
+ if (prep->rows_to_go == 0 &&
+ prep->next_buf_row < cinfo->max_v_samp_factor) {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
+ prep->next_buf_row, cinfo->max_v_samp_factor);
+ }
+ prep->next_buf_row = cinfo->max_v_samp_factor;
+ }
+ /* If we've filled the conversion buffer, empty it. */
+ if (prep->next_buf_row == cinfo->max_v_samp_factor) {
+ (*cinfo->downsample->downsample) (cinfo,
+ prep->color_buf, (JDIMENSION) 0,
+ output_buf, *out_row_group_ctr);
+ prep->next_buf_row = 0;
+ (*out_row_group_ctr)++;
+ }
+ /* If at bottom of image, pad the output to a full iMCU height.
+ * Note we assume the caller is providing a one-iMCU-height output buffer!
+ */
+ if (prep->rows_to_go == 0 &&
+ *out_row_group_ctr < out_row_groups_avail) {
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ numrows = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size;
+ expand_bottom_edge(output_buf[ci],
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+ (int) (*out_row_group_ctr * numrows),
+ (int) (out_row_groups_avail * numrows));
+ }
+ *out_row_group_ctr = out_row_groups_avail;
+ break; /* can exit outer loop without test */
+ }
+ }
+}
+
+
+#ifdef CONTEXT_ROWS_SUPPORTED
+
+/*
+ * Process some data in the context case.
+ */
+
+METHODDEF(void)
+pre_process_context (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+ int numrows, ci;
+ int buf_height = cinfo->max_v_samp_factor * 3;
+ JDIMENSION inrows;
+
+ while (*out_row_group_ctr < out_row_groups_avail) {
+ if (*in_row_ctr < in_rows_avail) {
+ /* Do color conversion to fill the conversion buffer. */
+ inrows = in_rows_avail - *in_row_ctr;
+ numrows = prep->next_buf_stop - prep->next_buf_row;
+ numrows = (int) MIN((JDIMENSION) numrows, inrows);
+ (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
+ prep->color_buf,
+ (JDIMENSION) prep->next_buf_row,
+ numrows);
+ /* Pad at top of image, if first time through */
+ if (prep->rows_to_go == cinfo->image_height) {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ int row;
+ for (row = 1; row <= cinfo->max_v_samp_factor; row++) {
+ jcopy_sample_rows(prep->color_buf[ci], 0,
+ prep->color_buf[ci], -row,
+ 1, cinfo->image_width);
+ }
+ }
+ }
+ *in_row_ctr += numrows;
+ prep->next_buf_row += numrows;
+ prep->rows_to_go -= numrows;
+ } else {
+ /* Return for more data, unless we are at the bottom of the image. */
+ if (prep->rows_to_go != 0)
+ break;
+ /* When at bottom of image, pad to fill the conversion buffer. */
+ if (prep->next_buf_row < prep->next_buf_stop) {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
+ prep->next_buf_row, prep->next_buf_stop);
+ }
+ prep->next_buf_row = prep->next_buf_stop;
+ }
+ }
+ /* If we've gotten enough data, downsample a row group. */
+ if (prep->next_buf_row == prep->next_buf_stop) {
+ (*cinfo->downsample->downsample) (cinfo,
+ prep->color_buf,
+ (JDIMENSION) prep->this_row_group,
+ output_buf, *out_row_group_ctr);
+ (*out_row_group_ctr)++;
+ /* Advance pointers with wraparound as necessary. */
+ prep->this_row_group += cinfo->max_v_samp_factor;
+ if (prep->this_row_group >= buf_height)
+ prep->this_row_group = 0;
+ if (prep->next_buf_row >= buf_height)
+ prep->next_buf_row = 0;
+ prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor;
+ }
+ }
+}
+
+
+/*
+ * Create the wrapped-around downsampling input buffer needed for context mode.
+ */
+
+LOCAL(void)
+create_context_buffer (j_compress_ptr cinfo)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+ int rgroup_height = cinfo->max_v_samp_factor;
+ int ci, i;
+ jpeg_component_info * compptr;
+ JSAMPARRAY true_buffer, fake_buffer;
+
+ /* Grab enough space for fake row pointers for all the components;
+ * we need five row groups' worth of pointers for each component.
+ */
+ fake_buffer = (JSAMPARRAY)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (cinfo->num_components * 5 * rgroup_height) *
+ SIZEOF(JSAMPROW));
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Allocate the actual buffer space (3 row groups) for this component.
+ * We make the buffer wide enough to allow the downsampler to edge-expand
+ * horizontally within the buffer, if it so chooses.
+ */
+ true_buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (((long) compptr->width_in_blocks *
+ cinfo->min_DCT_h_scaled_size *
+ cinfo->max_h_samp_factor) / compptr->h_samp_factor),
+ (JDIMENSION) (3 * rgroup_height));
+ /* Copy true buffer row pointers into the middle of the fake row array */
+ MEMCOPY(fake_buffer + rgroup_height, true_buffer,
+ 3 * rgroup_height * SIZEOF(JSAMPROW));
+ /* Fill in the above and below wraparound pointers */
+ for (i = 0; i < rgroup_height; i++) {
+ fake_buffer[i] = true_buffer[2 * rgroup_height + i];
+ fake_buffer[4 * rgroup_height + i] = true_buffer[i];
+ }
+ prep->color_buf[ci] = fake_buffer + rgroup_height;
+ fake_buffer += 5 * rgroup_height; /* point to space for next component */
+ }
+}
+
+#endif /* CONTEXT_ROWS_SUPPORTED */
+
+
+/*
+ * Initialize preprocessing controller.
+ */
+
+GLOBAL(void)
+jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+ my_prep_ptr prep;
+ int ci;
+ jpeg_component_info * compptr;
+
+ if (need_full_buffer) /* safety check */
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ prep = (my_prep_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_prep_controller));
+ cinfo->prep = (struct jpeg_c_prep_controller *) prep;
+ prep->pub.start_pass = start_pass_prep;
+
+ /* Allocate the color conversion buffer.
+ * We make the buffer wide enough to allow the downsampler to edge-expand
+ * horizontally within the buffer, if it so chooses.
+ */
+ if (cinfo->downsample->need_context_rows) {
+ /* Set up to provide context rows */
+#ifdef CONTEXT_ROWS_SUPPORTED
+ prep->pub.pre_process_data = pre_process_context;
+ create_context_buffer(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ /* No context, just make it tall enough for one row group */
+ prep->pub.pre_process_data = pre_process_data;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ prep->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (((long) compptr->width_in_blocks *
+ cinfo->min_DCT_h_scaled_size *
+ cinfo->max_h_samp_factor) / compptr->h_samp_factor),
+ (JDIMENSION) cinfo->max_v_samp_factor);
+ }
+ }
+}
diff --git a/external/jpeg-8c/jcsample.c b/external/jpeg-8c/jcsample.c
new file mode 100644
index 0000000..4d36f85
--- /dev/null
+++ b/external/jpeg-8c/jcsample.c
@@ -0,0 +1,545 @@
+/*
+ * jcsample.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains downsampling routines.
+ *
+ * Downsampling input data is counted in "row groups". A row group
+ * is defined to be max_v_samp_factor pixel rows of each component,
+ * from which the downsampler produces v_samp_factor sample rows.
+ * A single row group is processed in each call to the downsampler module.
+ *
+ * The downsampler is responsible for edge-expansion of its output data
+ * to fill an integral number of DCT blocks horizontally. The source buffer
+ * may be modified if it is helpful for this purpose (the source buffer is
+ * allocated wide enough to correspond to the desired output width).
+ * The caller (the prep controller) is responsible for vertical padding.
+ *
+ * The downsampler may request "context rows" by setting need_context_rows
+ * during startup. In this case, the input arrays will contain at least
+ * one row group's worth of pixels above and below the passed-in data;
+ * the caller will create dummy rows at image top and bottom by replicating
+ * the first or last real pixel row.
+ *
+ * An excellent reference for image resampling is
+ * Digital Image Warping, George Wolberg, 1990.
+ * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
+ *
+ * The downsampling algorithm used here is a simple average of the source
+ * pixels covered by the output pixel. The hi-falutin sampling literature
+ * refers to this as a "box filter". In general the characteristics of a box
+ * filter are not very good, but for the specific cases we normally use (1:1
+ * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not
+ * nearly so bad. If you intend to use other sampling ratios, you'd be well
+ * advised to improve this code.
+ *
+ * A simple input-smoothing capability is provided. This is mainly intended
+ * for cleaning up color-dithered GIF input files (if you find it inadequate,
+ * we suggest using an external filtering program such as pnmconvol). When
+ * enabled, each input pixel P is replaced by a weighted sum of itself and its
+ * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF,
+ * where SF = (smoothing_factor / 1024).
+ * Currently, smoothing is only supported for 2h2v sampling factors.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Pointer to routine to downsample a single component */
+typedef JMETHOD(void, downsample1_ptr,
+ (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data));
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_downsampler pub; /* public fields */
+
+ /* Downsampling method pointers, one per component */
+ downsample1_ptr methods[MAX_COMPONENTS];
+
+ /* Height of an output row group for each component. */
+ int rowgroup_height[MAX_COMPONENTS];
+
+ /* These arrays save pixel expansion factors so that int_downsample need not
+ * recompute them each time. They are unused for other downsampling methods.
+ */
+ UINT8 h_expand[MAX_COMPONENTS];
+ UINT8 v_expand[MAX_COMPONENTS];
+} my_downsampler;
+
+typedef my_downsampler * my_downsample_ptr;
+
+
+/*
+ * Initialize for a downsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_downsample (j_compress_ptr cinfo)
+{
+ /* no work for now */
+}
+
+
+/*
+ * Expand a component horizontally from width input_cols to width output_cols,
+ * by duplicating the rightmost samples.
+ */
+
+LOCAL(void)
+expand_right_edge (JSAMPARRAY image_data, int num_rows,
+ JDIMENSION input_cols, JDIMENSION output_cols)
+{
+ register JSAMPROW ptr;
+ register JSAMPLE pixval;
+ register int count;
+ int row;
+ int numcols = (int) (output_cols - input_cols);
+
+ if (numcols > 0) {
+ for (row = 0; row < num_rows; row++) {
+ ptr = image_data[row] + input_cols;
+ pixval = ptr[-1]; /* don't need GETJSAMPLE() here */
+ for (count = numcols; count > 0; count--)
+ *ptr++ = pixval;
+ }
+ }
+}
+
+
+/*
+ * Do downsampling for a whole row group (all components).
+ *
+ * In this version we simply downsample each component independently.
+ */
+
+METHODDEF(void)
+sep_downsample (j_compress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_index,
+ JSAMPIMAGE output_buf, JDIMENSION out_row_group_index)
+{
+ my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
+ int ci;
+ jpeg_component_info * compptr;
+ JSAMPARRAY in_ptr, out_ptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ in_ptr = input_buf[ci] + in_row_index;
+ out_ptr = output_buf[ci] +
+ (out_row_group_index * downsample->rowgroup_height[ci]);
+ (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr);
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * One row group is processed per call.
+ * This version handles arbitrary integral sampling ratios, without smoothing.
+ * Note that this version is not actually used for customary sampling ratios.
+ */
+
+METHODDEF(void)
+int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
+ int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
+ JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */
+ JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+ JSAMPROW inptr, outptr;
+ INT32 outvalue;
+
+ h_expand = downsample->h_expand[compptr->component_index];
+ v_expand = downsample->v_expand[compptr->component_index];
+ numpix = h_expand * v_expand;
+ numpix2 = numpix/2;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data, cinfo->max_v_samp_factor,
+ cinfo->image_width, output_cols * h_expand);
+
+ inrow = outrow = 0;
+ while (inrow < cinfo->max_v_samp_factor) {
+ outptr = output_data[outrow];
+ for (outcol = 0, outcol_h = 0; outcol < output_cols;
+ outcol++, outcol_h += h_expand) {
+ outvalue = 0;
+ for (v = 0; v < v_expand; v++) {
+ inptr = input_data[inrow+v] + outcol_h;
+ for (h = 0; h < h_expand; h++) {
+ outvalue += (INT32) GETJSAMPLE(*inptr++);
+ }
+ }
+ *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix);
+ }
+ inrow += v_expand;
+ outrow++;
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the special case of a full-size component,
+ * without smoothing.
+ */
+
+METHODDEF(void)
+fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ /* Copy the data */
+ jcopy_sample_rows(input_data, 0, output_data, 0,
+ cinfo->max_v_samp_factor, cinfo->image_width);
+ /* Edge-expand */
+ expand_right_edge(output_data, cinfo->max_v_samp_factor, cinfo->image_width,
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size);
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the common case of 2:1 horizontal and 1:1 vertical,
+ * without smoothing.
+ *
+ * A note about the "bias" calculations: when rounding fractional values to
+ * integer, we do not want to always round 0.5 up to the next integer.
+ * If we did that, we'd introduce a noticeable bias towards larger values.
+ * Instead, this code is arranged so that 0.5 will be rounded up or down at
+ * alternate pixel locations (a simple ordered dither pattern).
+ */
+
+METHODDEF(void)
+h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int inrow;
+ JDIMENSION outcol;
+ JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+ register JSAMPROW inptr, outptr;
+ register int bias;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data, cinfo->max_v_samp_factor,
+ cinfo->image_width, output_cols * 2);
+
+ for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
+ outptr = output_data[inrow];
+ inptr = input_data[inrow];
+ bias = 0; /* bias = 0,1,0,1,... for successive samples */
+ for (outcol = 0; outcol < output_cols; outcol++) {
+ *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1])
+ + bias) >> 1);
+ bias ^= 1; /* 0=>1, 1=>0 */
+ inptr += 2;
+ }
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the standard case of 2:1 horizontal and 2:1 vertical,
+ * without smoothing.
+ */
+
+METHODDEF(void)
+h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int inrow, outrow;
+ JDIMENSION outcol;
+ JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+ register JSAMPROW inptr0, inptr1, outptr;
+ register int bias;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data, cinfo->max_v_samp_factor,
+ cinfo->image_width, output_cols * 2);
+
+ inrow = outrow = 0;
+ while (inrow < cinfo->max_v_samp_factor) {
+ outptr = output_data[outrow];
+ inptr0 = input_data[inrow];
+ inptr1 = input_data[inrow+1];
+ bias = 1; /* bias = 1,2,1,2,... for successive samples */
+ for (outcol = 0; outcol < output_cols; outcol++) {
+ *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1])
+ + bias) >> 2);
+ bias ^= 3; /* 1=>2, 2=>1 */
+ inptr0 += 2; inptr1 += 2;
+ }
+ inrow += 2;
+ outrow++;
+ }
+}
+
+
+#ifdef INPUT_SMOOTHING_SUPPORTED
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the standard case of 2:1 horizontal and 2:1 vertical,
+ * with smoothing. One row of context is required.
+ */
+
+METHODDEF(void)
+h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int inrow, outrow;
+ JDIMENSION colctr;
+ JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+ register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
+ INT32 membersum, neighsum, memberscale, neighscale;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
+ cinfo->image_width, output_cols * 2);
+
+ /* We don't bother to form the individual "smoothed" input pixel values;
+ * we can directly compute the output which is the average of the four
+ * smoothed values. Each of the four member pixels contributes a fraction
+ * (1-8*SF) to its own smoothed image and a fraction SF to each of the three
+ * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final
+ * output. The four corner-adjacent neighbor pixels contribute a fraction
+ * SF to just one smoothed pixel, or SF/4 to the final output; while the
+ * eight edge-adjacent neighbors contribute SF to each of two smoothed
+ * pixels, or SF/2 overall. In order to use integer arithmetic, these
+ * factors are scaled by 2^16 = 65536.
+ * Also recall that SF = smoothing_factor / 1024.
+ */
+
+ memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */
+ neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */
+
+ inrow = outrow = 0;
+ while (inrow < cinfo->max_v_samp_factor) {
+ outptr = output_data[outrow];
+ inptr0 = input_data[inrow];
+ inptr1 = input_data[inrow+1];
+ above_ptr = input_data[inrow-1];
+ below_ptr = input_data[inrow+2];
+
+ /* Special case for first column: pretend column -1 is same as column 0 */
+ membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+ neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+ GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]);
+ neighsum += neighsum;
+ neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]);
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
+
+ for (colctr = output_cols - 2; colctr > 0; colctr--) {
+ /* sum of pixels directly mapped to this output element */
+ membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+ /* sum of edge-neighbor pixels */
+ neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+ GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) +
+ GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]);
+ /* The edge-neighbors count twice as much as corner-neighbors */
+ neighsum += neighsum;
+ /* Add in the corner-neighbors */
+ neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) +
+ GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]);
+ /* form final output scaled up by 2^16 */
+ membersum = membersum * memberscale + neighsum * neighscale;
+ /* round, descale and output it */
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
+ }
+
+ /* Special case for last column */
+ membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+ neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+ GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]);
+ neighsum += neighsum;
+ neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]);
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr = (JSAMPLE) ((membersum + 32768) >> 16);
+
+ inrow += 2;
+ outrow++;
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the special case of a full-size component,
+ * with smoothing. One row of context is required.
+ */
+
+METHODDEF(void)
+fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int inrow;
+ JDIMENSION colctr;
+ JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+ register JSAMPROW inptr, above_ptr, below_ptr, outptr;
+ INT32 membersum, neighsum, memberscale, neighscale;
+ int colsum, lastcolsum, nextcolsum;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
+ cinfo->image_width, output_cols);
+
+ /* Each of the eight neighbor pixels contributes a fraction SF to the
+ * smoothed pixel, while the main pixel contributes (1-8*SF). In order
+ * to use integer arithmetic, these factors are multiplied by 2^16 = 65536.
+ * Also recall that SF = smoothing_factor / 1024.
+ */
+
+ memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */
+ neighscale = cinfo->smoothing_factor * 64; /* scaled SF */
+
+ for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
+ outptr = output_data[inrow];
+ inptr = input_data[inrow];
+ above_ptr = input_data[inrow-1];
+ below_ptr = input_data[inrow+1];
+
+ /* Special case for first column */
+ colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) +
+ GETJSAMPLE(*inptr);
+ membersum = GETJSAMPLE(*inptr++);
+ nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
+ GETJSAMPLE(*inptr);
+ neighsum = colsum + (colsum - membersum) + nextcolsum;
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ lastcolsum = colsum; colsum = nextcolsum;
+
+ for (colctr = output_cols - 2; colctr > 0; colctr--) {
+ membersum = GETJSAMPLE(*inptr++);
+ above_ptr++; below_ptr++;
+ nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
+ GETJSAMPLE(*inptr);
+ neighsum = lastcolsum + (colsum - membersum) + nextcolsum;
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ lastcolsum = colsum; colsum = nextcolsum;
+ }
+
+ /* Special case for last column */
+ membersum = GETJSAMPLE(*inptr);
+ neighsum = lastcolsum + (colsum - membersum) + colsum;
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr = (JSAMPLE) ((membersum + 32768) >> 16);
+
+ }
+}
+
+#endif /* INPUT_SMOOTHING_SUPPORTED */
+
+
+/*
+ * Module initialization routine for downsampling.
+ * Note that we must select a routine for each component.
+ */
+
+GLOBAL(void)
+jinit_downsampler (j_compress_ptr cinfo)
+{
+ my_downsample_ptr downsample;
+ int ci;
+ jpeg_component_info * compptr;
+ boolean smoothok = TRUE;
+ int h_in_group, v_in_group, h_out_group, v_out_group;
+
+ downsample = (my_downsample_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_downsampler));
+ cinfo->downsample = (struct jpeg_downsampler *) downsample;
+ downsample->pub.start_pass = start_pass_downsample;
+ downsample->pub.downsample = sep_downsample;
+ downsample->pub.need_context_rows = FALSE;
+
+ if (cinfo->CCIR601_sampling)
+ ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
+
+ /* Verify we can handle the sampling factors, and set up method pointers */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Compute size of an "output group" for DCT scaling. This many samples
+ * are to be converted from max_h_samp_factor * max_v_samp_factor pixels.
+ */
+ h_out_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) /
+ cinfo->min_DCT_h_scaled_size;
+ v_out_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size;
+ h_in_group = cinfo->max_h_samp_factor;
+ v_in_group = cinfo->max_v_samp_factor;
+ downsample->rowgroup_height[ci] = v_out_group; /* save for use later */
+ if (h_in_group == h_out_group && v_in_group == v_out_group) {
+#ifdef INPUT_SMOOTHING_SUPPORTED
+ if (cinfo->smoothing_factor) {
+ downsample->methods[ci] = fullsize_smooth_downsample;
+ downsample->pub.need_context_rows = TRUE;
+ } else
+#endif
+ downsample->methods[ci] = fullsize_downsample;
+ } else if (h_in_group == h_out_group * 2 &&
+ v_in_group == v_out_group) {
+ smoothok = FALSE;
+ downsample->methods[ci] = h2v1_downsample;
+ } else if (h_in_group == h_out_group * 2 &&
+ v_in_group == v_out_group * 2) {
+#ifdef INPUT_SMOOTHING_SUPPORTED
+ if (cinfo->smoothing_factor) {
+ downsample->methods[ci] = h2v2_smooth_downsample;
+ downsample->pub.need_context_rows = TRUE;
+ } else
+#endif
+ downsample->methods[ci] = h2v2_downsample;
+ } else if ((h_in_group % h_out_group) == 0 &&
+ (v_in_group % v_out_group) == 0) {
+ smoothok = FALSE;
+ downsample->methods[ci] = int_downsample;
+ downsample->h_expand[ci] = (UINT8) (h_in_group / h_out_group);
+ downsample->v_expand[ci] = (UINT8) (v_in_group / v_out_group);
+ } else
+ ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
+ }
+
+#ifdef INPUT_SMOOTHING_SUPPORTED
+ if (cinfo->smoothing_factor && !smoothok)
+ TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL);
+#endif
+}
diff --git a/external/jpeg-8c/jctrans.c b/external/jpeg-8c/jctrans.c
new file mode 100644
index 0000000..3364811
--- /dev/null
+++ b/external/jpeg-8c/jctrans.c
@@ -0,0 +1,382 @@
+/*
+ * jctrans.c
+ *
+ * Copyright (C) 1995-1998, Thomas G. Lane.
+ * Modified 2000-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains library routines for transcoding compression,
+ * that is, writing raw DCT coefficient arrays to an output JPEG file.
+ * The routines in jcapimin.c will also be needed by a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(void) transencode_master_selection
+ JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
+LOCAL(void) transencode_coef_controller
+ JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
+
+
+/*
+ * Compression initialization for writing raw-coefficient data.
+ * Before calling this, all parameters and a data destination must be set up.
+ * Call jpeg_finish_compress() to actually write the data.
+ *
+ * The number of passed virtual arrays must match cinfo->num_components.
+ * Note that the virtual arrays need not be filled or even realized at
+ * the time write_coefficients is called; indeed, if the virtual arrays
+ * were requested from this compression object's memory manager, they
+ * typically will be realized during this routine and filled afterwards.
+ */
+
+GLOBAL(void)
+jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)
+{
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Mark all tables to be written */
+ jpeg_suppress_tables(cinfo, FALSE);
+ /* (Re)initialize error mgr and destination modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->dest->init_destination) (cinfo);
+ /* Perform master selection of active modules */
+ transencode_master_selection(cinfo, coef_arrays);
+ /* Wait for jpeg_finish_compress() call */
+ cinfo->next_scanline = 0; /* so jpeg_write_marker works */
+ cinfo->global_state = CSTATE_WRCOEFS;
+}
+
+
+/*
+ * Initialize the compression object with default parameters,
+ * then copy from the source object all parameters needed for lossless
+ * transcoding. Parameters that can be varied without loss (such as
+ * scan script and Huffman optimization) are left in their default states.
+ */
+
+GLOBAL(void)
+jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
+ j_compress_ptr dstinfo)
+{
+ JQUANT_TBL ** qtblptr;
+ jpeg_component_info *incomp, *outcomp;
+ JQUANT_TBL *c_quant, *slot_quant;
+ int tblno, ci, coefi;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (dstinfo->global_state != CSTATE_START)
+ ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state);
+ /* Copy fundamental image dimensions */
+ dstinfo->image_width = srcinfo->image_width;
+ dstinfo->image_height = srcinfo->image_height;
+ dstinfo->input_components = srcinfo->num_components;
+ dstinfo->in_color_space = srcinfo->jpeg_color_space;
+ dstinfo->jpeg_width = srcinfo->output_width;
+ dstinfo->jpeg_height = srcinfo->output_height;
+ dstinfo->min_DCT_h_scaled_size = srcinfo->min_DCT_h_scaled_size;
+ dstinfo->min_DCT_v_scaled_size = srcinfo->min_DCT_v_scaled_size;
+ /* Initialize all parameters to default values */
+ jpeg_set_defaults(dstinfo);
+ /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB.
+ * Fix it to get the right header markers for the image colorspace.
+ */
+ jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space);
+ dstinfo->data_precision = srcinfo->data_precision;
+ dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling;
+ /* Copy the source's quantization tables. */
+ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
+ if (srcinfo->quant_tbl_ptrs[tblno] != NULL) {
+ qtblptr = & dstinfo->quant_tbl_ptrs[tblno];
+ if (*qtblptr == NULL)
+ *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo);
+ MEMCOPY((*qtblptr)->quantval,
+ srcinfo->quant_tbl_ptrs[tblno]->quantval,
+ SIZEOF((*qtblptr)->quantval));
+ (*qtblptr)->sent_table = FALSE;
+ }
+ }
+ /* Copy the source's per-component info.
+ * Note we assume jpeg_set_defaults has allocated the dest comp_info array.
+ */
+ dstinfo->num_components = srcinfo->num_components;
+ if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components,
+ MAX_COMPONENTS);
+ for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info;
+ ci < dstinfo->num_components; ci++, incomp++, outcomp++) {
+ outcomp->component_id = incomp->component_id;
+ outcomp->h_samp_factor = incomp->h_samp_factor;
+ outcomp->v_samp_factor = incomp->v_samp_factor;
+ outcomp->quant_tbl_no = incomp->quant_tbl_no;
+ /* Make sure saved quantization table for component matches the qtable
+ * slot. If not, the input file re-used this qtable slot.
+ * IJG encoder currently cannot duplicate this.
+ */
+ tblno = outcomp->quant_tbl_no;
+ if (tblno < 0 || tblno >= NUM_QUANT_TBLS ||
+ srcinfo->quant_tbl_ptrs[tblno] == NULL)
+ ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno);
+ slot_quant = srcinfo->quant_tbl_ptrs[tblno];
+ c_quant = incomp->quant_table;
+ if (c_quant != NULL) {
+ for (coefi = 0; coefi < DCTSIZE2; coefi++) {
+ if (c_quant->quantval[coefi] != slot_quant->quantval[coefi])
+ ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno);
+ }
+ }
+ /* Note: we do not copy the source's Huffman table assignments;
+ * instead we rely on jpeg_set_colorspace to have made a suitable choice.
+ */
+ }
+ /* Also copy JFIF version and resolution information, if available.
+ * Strictly speaking this isn't "critical" info, but it's nearly
+ * always appropriate to copy it if available. In particular,
+ * if the application chooses to copy JFIF 1.02 extension markers from
+ * the source file, we need to copy the version to make sure we don't
+ * emit a file that has 1.02 extensions but a claimed version of 1.01.
+ * We will *not*, however, copy version info from mislabeled "2.01" files.
+ */
+ if (srcinfo->saw_JFIF_marker) {
+ if (srcinfo->JFIF_major_version == 1) {
+ dstinfo->JFIF_major_version = srcinfo->JFIF_major_version;
+ dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version;
+ }
+ dstinfo->density_unit = srcinfo->density_unit;
+ dstinfo->X_density = srcinfo->X_density;
+ dstinfo->Y_density = srcinfo->Y_density;
+ }
+}
+
+
+/*
+ * Master selection of compression modules for transcoding.
+ * This substitutes for jcinit.c's initialization of the full compressor.
+ */
+
+LOCAL(void)
+transencode_master_selection (j_compress_ptr cinfo,
+ jvirt_barray_ptr * coef_arrays)
+{
+ /* Initialize master control (includes parameter checking/processing) */
+ jinit_c_master_control(cinfo, TRUE /* transcode only */);
+
+ /* Entropy encoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code)
+ jinit_arith_encoder(cinfo);
+ else {
+ jinit_huff_encoder(cinfo);
+ }
+
+ /* We need a special coefficient buffer controller. */
+ transencode_coef_controller(cinfo, coef_arrays);
+
+ jinit_marker_writer(cinfo);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Write the datastream header (SOI, JFIF) immediately.
+ * Frame and scan headers are postponed till later.
+ * This lets application insert special markers after the SOI.
+ */
+ (*cinfo->marker->write_file_header) (cinfo);
+}
+
+
+/*
+ * The rest of this file is a special implementation of the coefficient
+ * buffer controller. This is similar to jccoefct.c, but it handles only
+ * output from presupplied virtual arrays. Furthermore, we generate any
+ * dummy padding blocks on-the-fly rather than expecting them to be present
+ * in the arrays.
+ */
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_coef_controller pub; /* public fields */
+
+ JDIMENSION iMCU_row_num; /* iMCU row # within image */
+ JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* Virtual block array for each component. */
+ jvirt_barray_ptr * whole_image;
+
+ /* Workspace for constructing dummy blocks at right/bottom edges. */
+ JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU];
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+
+LOCAL(void)
+start_iMCU_row (j_compress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row */
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ coef->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ coef->mcu_ctr = 0;
+ coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ if (pass_mode != JBUF_CRANK_DEST)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ coef->iMCU_row_num = 0;
+ start_iMCU_row(cinfo);
+}
+
+
+/*
+ * Process some data.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the scan.
+ * The data is obtained from the virtual arrays and fed to the entropy coder.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf is ignored; it is likely to be a NULL pointer.
+ */
+
+METHODDEF(boolean)
+compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int blkn, ci, xindex, yindex, yoffset, blockcnt;
+ JDIMENSION start_col;
+ JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+ JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
+ JBLOCKROW buffer_ptr;
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan. */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ buffer[ci] = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+ coef->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ }
+
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
+ MCU_col_num++) {
+ /* Construct list of pointers to DCT blocks belonging to this MCU */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ start_col = MCU_col_num * compptr->MCU_width;
+ blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+ : compptr->last_col_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ if (coef->iMCU_row_num < last_iMCU_row ||
+ yindex+yoffset < compptr->last_row_height) {
+ /* Fill in pointers to real blocks in this row */
+ buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ for (xindex = 0; xindex < blockcnt; xindex++)
+ MCU_buffer[blkn++] = buffer_ptr++;
+ } else {
+ /* At bottom of image, need a whole row of dummy blocks */
+ xindex = 0;
+ }
+ /* Fill in any dummy blocks needed in this row.
+ * Dummy blocks are filled in the same way as in jccoefct.c:
+ * all zeroes in the AC entries, DC entries equal to previous
+ * block's DC value. The init routine has already zeroed the
+ * AC entries, so we need only set the DC entries correctly.
+ */
+ for (; xindex < compptr->MCU_width; xindex++) {
+ MCU_buffer[blkn] = coef->dummy_buffer[blkn];
+ MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0];
+ blkn++;
+ }
+ }
+ }
+ /* Try to write the MCU. */
+ if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->mcu_ctr = MCU_col_num;
+ return FALSE;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->mcu_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ coef->iMCU_row_num++;
+ start_iMCU_row(cinfo);
+ return TRUE;
+}
+
+
+/*
+ * Initialize coefficient buffer controller.
+ *
+ * Each passed coefficient array must be the right size for that
+ * coefficient: width_in_blocks wide and height_in_blocks high,
+ * with unitheight at least v_samp_factor.
+ */
+
+LOCAL(void)
+transencode_coef_controller (j_compress_ptr cinfo,
+ jvirt_barray_ptr * coef_arrays)
+{
+ my_coef_ptr coef;
+ JBLOCKROW buffer;
+ int i;
+
+ coef = (my_coef_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_coef_controller));
+ cinfo->coef = (struct jpeg_c_coef_controller *) coef;
+ coef->pub.start_pass = start_pass_coef;
+ coef->pub.compress_data = compress_output;
+
+ /* Save pointer to virtual arrays */
+ coef->whole_image = coef_arrays;
+
+ /* Allocate and pre-zero space for dummy DCT blocks. */
+ buffer = (JBLOCKROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ jzero_far((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
+ coef->dummy_buffer[i] = buffer + i;
+ }
+}
diff --git a/external/jpeg-8c/jdapimin.c b/external/jpeg-8c/jdapimin.c
new file mode 100644
index 0000000..7f1ce4c
--- /dev/null
+++ b/external/jpeg-8c/jdapimin.c
@@ -0,0 +1,396 @@
+/*
+ * jdapimin.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the decompression half
+ * of the JPEG library. These are the "minimum" API routines that may be
+ * needed in either the normal full-decompression case or the
+ * transcoding-only case.
+ *
+ * Most of the routines intended to be called directly by an application
+ * are in this file or in jdapistd.c. But also see jcomapi.c for routines
+ * shared by compression and decompression, and jdtrans.c for the transcoding
+ * case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Initialization of a JPEG decompression object.
+ * The error manager must already be set up (in case memory manager fails).
+ */
+
+GLOBAL(void)
+jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize)
+{
+ int i;
+
+ /* Guard against version mismatches between library and caller. */
+ cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */
+ if (version != JPEG_LIB_VERSION)
+ ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
+ if (structsize != SIZEOF(struct jpeg_decompress_struct))
+ ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
+ (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize);
+
+ /* For debugging purposes, we zero the whole master structure.
+ * But the application has already set the err pointer, and may have set
+ * client_data, so we have to save and restore those fields.
+ * Note: if application hasn't set client_data, tools like Purify may
+ * complain here.
+ */
+ {
+ struct jpeg_error_mgr * err = cinfo->err;
+ void * client_data = cinfo->client_data; /* ignore Purify complaint here */
+ MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct));
+ cinfo->err = err;
+ cinfo->client_data = client_data;
+ }
+ cinfo->is_decompressor = TRUE;
+
+ /* Initialize a memory manager instance for this object */
+ jinit_memory_mgr((j_common_ptr) cinfo);
+
+ /* Zero out pointers to permanent structures. */
+ cinfo->progress = NULL;
+ cinfo->src = NULL;
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++)
+ cinfo->quant_tbl_ptrs[i] = NULL;
+
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ cinfo->dc_huff_tbl_ptrs[i] = NULL;
+ cinfo->ac_huff_tbl_ptrs[i] = NULL;
+ }
+
+ /* Initialize marker processor so application can override methods
+ * for COM, APPn markers before calling jpeg_read_header.
+ */
+ cinfo->marker_list = NULL;
+ jinit_marker_reader(cinfo);
+
+ /* And initialize the overall input controller. */
+ jinit_input_controller(cinfo);
+
+ /* OK, I'm ready */
+ cinfo->global_state = DSTATE_START;
+}
+
+
+/*
+ * Destruction of a JPEG decompression object
+ */
+
+GLOBAL(void)
+jpeg_destroy_decompress (j_decompress_ptr cinfo)
+{
+ jpeg_destroy((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Abort processing of a JPEG decompression operation,
+ * but don't destroy the object itself.
+ */
+
+GLOBAL(void)
+jpeg_abort_decompress (j_decompress_ptr cinfo)
+{
+ jpeg_abort((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Set default decompression parameters.
+ */
+
+LOCAL(void)
+default_decompress_parms (j_decompress_ptr cinfo)
+{
+ /* Guess the input colorspace, and set output colorspace accordingly. */
+ /* (Wish JPEG committee had provided a real way to specify this...) */
+ /* Note application may override our guesses. */
+ switch (cinfo->num_components) {
+ case 1:
+ cinfo->jpeg_color_space = JCS_GRAYSCALE;
+ cinfo->out_color_space = JCS_GRAYSCALE;
+ break;
+
+ case 3:
+ if (cinfo->saw_JFIF_marker) {
+ cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */
+ } else if (cinfo->saw_Adobe_marker) {
+ switch (cinfo->Adobe_transform) {
+ case 0:
+ cinfo->jpeg_color_space = JCS_RGB;
+ break;
+ case 1:
+ cinfo->jpeg_color_space = JCS_YCbCr;
+ break;
+ default:
+ WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
+ break;
+ }
+ } else {
+ /* Saw no special markers, try to guess from the component IDs */
+ int cid0 = cinfo->comp_info[0].component_id;
+ int cid1 = cinfo->comp_info[1].component_id;
+ int cid2 = cinfo->comp_info[2].component_id;
+
+ if (cid0 == 1 && cid1 == 2 && cid2 == 3)
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
+ else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
+ cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */
+ else {
+ TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
+ }
+ }
+ /* Always guess RGB is proper output colorspace. */
+ cinfo->out_color_space = JCS_RGB;
+ break;
+
+ case 4:
+ if (cinfo->saw_Adobe_marker) {
+ switch (cinfo->Adobe_transform) {
+ case 0:
+ cinfo->jpeg_color_space = JCS_CMYK;
+ break;
+ case 2:
+ cinfo->jpeg_color_space = JCS_YCCK;
+ break;
+ default:
+ WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
+ cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */
+ break;
+ }
+ } else {
+ /* No special markers, assume straight CMYK. */
+ cinfo->jpeg_color_space = JCS_CMYK;
+ }
+ cinfo->out_color_space = JCS_CMYK;
+ break;
+
+ default:
+ cinfo->jpeg_color_space = JCS_UNKNOWN;
+ cinfo->out_color_space = JCS_UNKNOWN;
+ break;
+ }
+
+ /* Set defaults for other decompression parameters. */
+ cinfo->scale_num = cinfo->block_size; /* 1:1 scaling */
+ cinfo->scale_denom = cinfo->block_size;
+ cinfo->output_gamma = 1.0;
+ cinfo->buffered_image = FALSE;
+ cinfo->raw_data_out = FALSE;
+ cinfo->dct_method = JDCT_DEFAULT;
+ cinfo->do_fancy_upsampling = TRUE;
+ cinfo->do_block_smoothing = TRUE;
+ cinfo->quantize_colors = FALSE;
+ /* We set these in case application only sets quantize_colors. */
+ cinfo->dither_mode = JDITHER_FS;
+#ifdef QUANT_2PASS_SUPPORTED
+ cinfo->two_pass_quantize = TRUE;
+#else
+ cinfo->two_pass_quantize = FALSE;
+#endif
+ cinfo->desired_number_of_colors = 256;
+ cinfo->colormap = NULL;
+ /* Initialize for no mode change in buffered-image mode. */
+ cinfo->enable_1pass_quant = FALSE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+}
+
+
+/*
+ * Decompression startup: read start of JPEG datastream to see what's there.
+ * Need only initialize JPEG object and supply a data source before calling.
+ *
+ * This routine will read as far as the first SOS marker (ie, actual start of
+ * compressed data), and will save all tables and parameters in the JPEG
+ * object. It will also initialize the decompression parameters to default
+ * values, and finally return JPEG_HEADER_OK. On return, the application may
+ * adjust the decompression parameters and then call jpeg_start_decompress.
+ * (Or, if the application only wanted to determine the image parameters,
+ * the data need not be decompressed. In that case, call jpeg_abort or
+ * jpeg_destroy to release any temporary space.)
+ * If an abbreviated (tables only) datastream is presented, the routine will
+ * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then
+ * re-use the JPEG object to read the abbreviated image datastream(s).
+ * It is unnecessary (but OK) to call jpeg_abort in this case.
+ * The JPEG_SUSPENDED return code only occurs if the data source module
+ * requests suspension of the decompressor. In this case the application
+ * should load more source data and then re-call jpeg_read_header to resume
+ * processing.
+ * If a non-suspending data source is used and require_image is TRUE, then the
+ * return code need not be inspected since only JPEG_HEADER_OK is possible.
+ *
+ * This routine is now just a front end to jpeg_consume_input, with some
+ * extra error checking.
+ */
+
+GLOBAL(int)
+jpeg_read_header (j_decompress_ptr cinfo, boolean require_image)
+{
+ int retcode;
+
+ if (cinfo->global_state != DSTATE_START &&
+ cinfo->global_state != DSTATE_INHEADER)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ retcode = jpeg_consume_input(cinfo);
+
+ switch (retcode) {
+ case JPEG_REACHED_SOS:
+ retcode = JPEG_HEADER_OK;
+ break;
+ case JPEG_REACHED_EOI:
+ if (require_image) /* Complain if application wanted an image */
+ ERREXIT(cinfo, JERR_NO_IMAGE);
+ /* Reset to start state; it would be safer to require the application to
+ * call jpeg_abort, but we can't change it now for compatibility reasons.
+ * A side effect is to free any temporary memory (there shouldn't be any).
+ */
+ jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */
+ retcode = JPEG_HEADER_TABLES_ONLY;
+ break;
+ case JPEG_SUSPENDED:
+ /* no work */
+ break;
+ }
+
+ return retcode;
+}
+
+
+/*
+ * Consume data in advance of what the decompressor requires.
+ * This can be called at any time once the decompressor object has
+ * been created and a data source has been set up.
+ *
+ * This routine is essentially a state machine that handles a couple
+ * of critical state-transition actions, namely initial setup and
+ * transition from header scanning to ready-for-start_decompress.
+ * All the actual input is done via the input controller's consume_input
+ * method.
+ */
+
+GLOBAL(int)
+jpeg_consume_input (j_decompress_ptr cinfo)
+{
+ int retcode = JPEG_SUSPENDED;
+
+ /* NB: every possible DSTATE value should be listed in this switch */
+ switch (cinfo->global_state) {
+ case DSTATE_START:
+ /* Start-of-datastream actions: reset appropriate modules */
+ (*cinfo->inputctl->reset_input_controller) (cinfo);
+ /* Initialize application's data source module */
+ (*cinfo->src->init_source) (cinfo);
+ cinfo->global_state = DSTATE_INHEADER;
+ /*FALLTHROUGH*/
+ case DSTATE_INHEADER:
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */
+ /* Set up default parameters based on header data */
+ default_decompress_parms(cinfo);
+ /* Set global state: ready for start_decompress */
+ cinfo->global_state = DSTATE_READY;
+ }
+ break;
+ case DSTATE_READY:
+ /* Can't advance past first SOS until start_decompress is called */
+ retcode = JPEG_REACHED_SOS;
+ break;
+ case DSTATE_PRELOAD:
+ case DSTATE_PRESCAN:
+ case DSTATE_SCANNING:
+ case DSTATE_RAW_OK:
+ case DSTATE_BUFIMAGE:
+ case DSTATE_BUFPOST:
+ case DSTATE_STOPPING:
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ break;
+ default:
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ }
+ return retcode;
+}
+
+
+/*
+ * Have we finished reading the input file?
+ */
+
+GLOBAL(boolean)
+jpeg_input_complete (j_decompress_ptr cinfo)
+{
+ /* Check for valid jpeg object */
+ if (cinfo->global_state < DSTATE_START ||
+ cinfo->global_state > DSTATE_STOPPING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ return cinfo->inputctl->eoi_reached;
+}
+
+
+/*
+ * Is there more than one scan?
+ */
+
+GLOBAL(boolean)
+jpeg_has_multiple_scans (j_decompress_ptr cinfo)
+{
+ /* Only valid after jpeg_read_header completes */
+ if (cinfo->global_state < DSTATE_READY ||
+ cinfo->global_state > DSTATE_STOPPING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ return cinfo->inputctl->has_multiple_scans;
+}
+
+
+/*
+ * Finish JPEG decompression.
+ *
+ * This will normally just verify the file trailer and release temp storage.
+ *
+ * Returns FALSE if suspended. The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_finish_decompress (j_decompress_ptr cinfo)
+{
+ if ((cinfo->global_state == DSTATE_SCANNING ||
+ cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) {
+ /* Terminate final pass of non-buffered mode */
+ if (cinfo->output_scanline < cinfo->output_height)
+ ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
+ (*cinfo->master->finish_output_pass) (cinfo);
+ cinfo->global_state = DSTATE_STOPPING;
+ } else if (cinfo->global_state == DSTATE_BUFIMAGE) {
+ /* Finishing after a buffered-image operation */
+ cinfo->global_state = DSTATE_STOPPING;
+ } else if (cinfo->global_state != DSTATE_STOPPING) {
+ /* STOPPING = repeat call after a suspension, anything else is error */
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ }
+ /* Read until EOI */
+ while (! cinfo->inputctl->eoi_reached) {
+ if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
+ return FALSE; /* Suspend, come back later */
+ }
+ /* Do final cleanup */
+ (*cinfo->src->term_source) (cinfo);
+ /* We can use jpeg_abort to release memory and reset global_state */
+ jpeg_abort((j_common_ptr) cinfo);
+ return TRUE;
+}
diff --git a/external/jpeg-8c/jdapistd.c b/external/jpeg-8c/jdapistd.c
new file mode 100644
index 0000000..9d74537
--- /dev/null
+++ b/external/jpeg-8c/jdapistd.c
@@ -0,0 +1,275 @@
+/*
+ * jdapistd.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the decompression half
+ * of the JPEG library. These are the "standard" API routines that are
+ * used in the normal full-decompression case. They are not used by a
+ * transcoding-only application. Note that if an application links in
+ * jpeg_start_decompress, it will end up linking in the entire decompressor.
+ * We thus must separate this file from jdapimin.c to avoid linking the
+ * whole decompression library into a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Decompression initialization.
+ * jpeg_read_header must be completed before calling this.
+ *
+ * If a multipass operating mode was selected, this will do all but the
+ * last pass, and thus may take a great deal of time.
+ *
+ * Returns FALSE if suspended. The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_start_decompress (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state == DSTATE_READY) {
+ /* First call: initialize master control, select active modules */
+ jinit_master_decompress(cinfo);
+ if (cinfo->buffered_image) {
+ /* No more work here; expecting jpeg_start_output next */
+ cinfo->global_state = DSTATE_BUFIMAGE;
+ return TRUE;
+ }
+ cinfo->global_state = DSTATE_PRELOAD;
+ }
+ if (cinfo->global_state == DSTATE_PRELOAD) {
+ /* If file has multiple scans, absorb them all into the coef buffer */
+ if (cinfo->inputctl->has_multiple_scans) {
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ for (;;) {
+ int retcode;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL)
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ /* Absorb some more input */
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ if (retcode == JPEG_SUSPENDED)
+ return FALSE;
+ if (retcode == JPEG_REACHED_EOI)
+ break;
+ /* Advance progress counter if appropriate */
+ if (cinfo->progress != NULL &&
+ (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+ if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
+ /* jdmaster underestimated number of scans; ratchet up one scan */
+ cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
+ }
+ }
+ }
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+ }
+ cinfo->output_scan_number = cinfo->input_scan_number;
+ } else if (cinfo->global_state != DSTATE_PRESCAN)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Perform any dummy output passes, and set up for the final pass */
+ return output_pass_setup(cinfo);
+}
+
+
+/*
+ * Set up for an output pass, and perform any dummy pass(es) needed.
+ * Common subroutine for jpeg_start_decompress and jpeg_start_output.
+ * Entry: global_state = DSTATE_PRESCAN only if previously suspended.
+ * Exit: If done, returns TRUE and sets global_state for proper output mode.
+ * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN.
+ */
+
+LOCAL(boolean)
+output_pass_setup (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state != DSTATE_PRESCAN) {
+ /* First call: do pass setup */
+ (*cinfo->master->prepare_for_output_pass) (cinfo);
+ cinfo->output_scanline = 0;
+ cinfo->global_state = DSTATE_PRESCAN;
+ }
+ /* Loop over any required dummy passes */
+ while (cinfo->master->is_dummy_pass) {
+#ifdef QUANT_2PASS_SUPPORTED
+ /* Crank through the dummy pass */
+ while (cinfo->output_scanline < cinfo->output_height) {
+ JDIMENSION last_scanline;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+ /* Process some data */
+ last_scanline = cinfo->output_scanline;
+ (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL,
+ &cinfo->output_scanline, (JDIMENSION) 0);
+ if (cinfo->output_scanline == last_scanline)
+ return FALSE; /* No progress made, must suspend */
+ }
+ /* Finish up dummy pass, and set up for another one */
+ (*cinfo->master->finish_output_pass) (cinfo);
+ (*cinfo->master->prepare_for_output_pass) (cinfo);
+ cinfo->output_scanline = 0;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* QUANT_2PASS_SUPPORTED */
+ }
+ /* Ready for application to drive output pass through
+ * jpeg_read_scanlines or jpeg_read_raw_data.
+ */
+ cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;
+ return TRUE;
+}
+
+
+/*
+ * Read some scanlines of data from the JPEG decompressor.
+ *
+ * The return value will be the number of lines actually read.
+ * This may be less than the number requested in several cases,
+ * including bottom of image, data source suspension, and operating
+ * modes that emit multiple scanlines at a time.
+ *
+ * Note: we warn about excess calls to jpeg_read_scanlines() since
+ * this likely signals an application programmer error. However,
+ * an oversize buffer (max_lines > scanlines remaining) is not an error.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,
+ JDIMENSION max_lines)
+{
+ JDIMENSION row_ctr;
+
+ if (cinfo->global_state != DSTATE_SCANNING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->output_scanline >= cinfo->output_height) {
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Process some data */
+ row_ctr = 0;
+ (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines);
+ cinfo->output_scanline += row_ctr;
+ return row_ctr;
+}
+
+
+/*
+ * Alternate entry point to read raw data.
+ * Processes exactly one iMCU row per call, unless suspended.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,
+ JDIMENSION max_lines)
+{
+ JDIMENSION lines_per_iMCU_row;
+
+ if (cinfo->global_state != DSTATE_RAW_OK)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->output_scanline >= cinfo->output_height) {
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Verify that at least one iMCU row can be returned. */
+ lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size;
+ if (max_lines < lines_per_iMCU_row)
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+ /* Decompress directly into user's buffer. */
+ if (! (*cinfo->coef->decompress_data) (cinfo, data))
+ return 0; /* suspension forced, can do nothing more */
+
+ /* OK, we processed one iMCU row. */
+ cinfo->output_scanline += lines_per_iMCU_row;
+ return lines_per_iMCU_row;
+}
+
+
+/* Additional entry points for buffered-image mode. */
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Initialize for an output pass in buffered-image mode.
+ */
+
+GLOBAL(boolean)
+jpeg_start_output (j_decompress_ptr cinfo, int scan_number)
+{
+ if (cinfo->global_state != DSTATE_BUFIMAGE &&
+ cinfo->global_state != DSTATE_PRESCAN)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Limit scan number to valid range */
+ if (scan_number <= 0)
+ scan_number = 1;
+ if (cinfo->inputctl->eoi_reached &&
+ scan_number > cinfo->input_scan_number)
+ scan_number = cinfo->input_scan_number;
+ cinfo->output_scan_number = scan_number;
+ /* Perform any dummy output passes, and set up for the real pass */
+ return output_pass_setup(cinfo);
+}
+
+
+/*
+ * Finish up after an output pass in buffered-image mode.
+ *
+ * Returns FALSE if suspended. The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_finish_output (j_decompress_ptr cinfo)
+{
+ if ((cinfo->global_state == DSTATE_SCANNING ||
+ cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) {
+ /* Terminate this pass. */
+ /* We do not require the whole pass to have been completed. */
+ (*cinfo->master->finish_output_pass) (cinfo);
+ cinfo->global_state = DSTATE_BUFPOST;
+ } else if (cinfo->global_state != DSTATE_BUFPOST) {
+ /* BUFPOST = repeat call after a suspension, anything else is error */
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ }
+ /* Read markers looking for SOS or EOI */
+ while (cinfo->input_scan_number <= cinfo->output_scan_number &&
+ ! cinfo->inputctl->eoi_reached) {
+ if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
+ return FALSE; /* Suspend, come back later */
+ }
+ cinfo->global_state = DSTATE_BUFIMAGE;
+ return TRUE;
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
diff --git a/external/jpeg-8c/jdarith.c b/external/jpeg-8c/jdarith.c
new file mode 100644
index 0000000..c858b24
--- /dev/null
+++ b/external/jpeg-8c/jdarith.c
@@ -0,0 +1,772 @@
+/*
+ * jdarith.c
+ *
+ * Developed 1997-2009 by Guido Vollbeding.
+ * 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 portable arithmetic entropy decoding routines for JPEG
+ * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
+ *
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Suspension is not currently supported in this module.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Expanded entropy decoder object for arithmetic decoding. */
+
+typedef struct {
+ struct jpeg_entropy_decoder pub; /* public fields */
+
+ INT32 c; /* C register, base of coding interval + input bit buffer */
+ INT32 a; /* A register, normalized size of coding interval */
+ int ct; /* bit shift counter, # of bits left in bit buffer part of C */
+ /* init: ct = -16 */
+ /* run: ct = 0..7 */
+ /* error: ct = -1 */
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+ int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */
+
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+
+ /* Pointers to statistics areas (these workspaces have image lifespan) */
+ unsigned char * dc_stats[NUM_ARITH_TBLS];
+ unsigned char * ac_stats[NUM_ARITH_TBLS];
+
+ /* Statistics bin for coding with fixed probability 0.5 */
+ unsigned char fixed_bin[4];
+} arith_entropy_decoder;
+
+typedef arith_entropy_decoder * arith_entropy_ptr;
+
+/* The following two definitions specify the allocation chunk size
+ * for the statistics area.
+ * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least
+ * 49 statistics bins for DC, and 245 statistics bins for AC coding.
+ *
+ * We use a compact representation with 1 byte per statistics bin,
+ * thus the numbers directly represent byte sizes.
+ * This 1 byte per statistics bin contains the meaning of the MPS
+ * (more probable symbol) in the highest bit (mask 0x80), and the
+ * index into the probability estimation state machine table
+ * in the lower bits (mask 0x7F).
+ */
+
+#define DC_STAT_BINS 64
+#define AC_STAT_BINS 256
+
+
+LOCAL(int)
+get_byte (j_decompress_ptr cinfo)
+/* Read next input byte; we do not support suspension in this module. */
+{
+ struct jpeg_source_mgr * src = cinfo->src;
+
+ if (src->bytes_in_buffer == 0)
+ if (! (*src->fill_input_buffer) (cinfo))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ src->bytes_in_buffer--;
+ return GETJOCTET(*src->next_input_byte++);
+}
+
+
+/*
+ * The core arithmetic decoding routine (common in JPEG and JBIG).
+ * This needs to go as fast as possible.
+ * Machine-dependent optimization facilities
+ * are not utilized in this portable implementation.
+ * However, this code should be fairly efficient and
+ * may be a good base for further optimizations anyway.
+ *
+ * Return value is 0 or 1 (binary decision).
+ *
+ * Note: I've changed the handling of the code base & bit
+ * buffer register C compared to other implementations
+ * based on the standards layout & procedures.
+ * While it also contains both the actual base of the
+ * coding interval (16 bits) and the next-bits buffer,
+ * the cut-point between these two parts is floating
+ * (instead of fixed) with the bit shift counter CT.
+ * Thus, we also need only one (variable instead of
+ * fixed size) shift for the LPS/MPS decision, and
+ * we can get away with any renormalization update
+ * of C (except for new data insertion, of course).
+ *
+ * I've also introduced a new scheme for accessing
+ * the probability estimation state machine table,
+ * derived from Markus Kuhn's JBIG implementation.
+ */
+
+LOCAL(int)
+arith_decode (j_decompress_ptr cinfo, unsigned char *st)
+{
+ register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+ register unsigned char nl, nm;
+ register INT32 qe, temp;
+ register int sv, data;
+
+ /* Renormalization & data input per section D.2.6 */
+ while (e->a < 0x8000L) {
+ if (--e->ct < 0) {
+ /* Need to fetch next data byte */
+ if (cinfo->unread_marker)
+ data = 0; /* stuff zero data */
+ else {
+ data = get_byte(cinfo); /* read next input byte */
+ if (data == 0xFF) { /* zero stuff or marker code */
+ do data = get_byte(cinfo);
+ while (data == 0xFF); /* swallow extra 0xFF bytes */
+ if (data == 0)
+ data = 0xFF; /* discard stuffed zero byte */
+ else {
+ /* Note: Different from the Huffman decoder, hitting
+ * a marker while processing the compressed data
+ * segment is legal in arithmetic coding.
+ * The convention is to supply zero data
+ * then until decoding is complete.
+ */
+ cinfo->unread_marker = data;
+ data = 0;
+ }
+ }
+ }
+ e->c = (e->c << 8) | data; /* insert data into C register */
+ if ((e->ct += 8) < 0) /* update bit shift counter */
+ /* Need more initial bytes */
+ if (++e->ct == 0)
+ /* Got 2 initial bytes -> re-init A and exit loop */
+ e->a = 0x8000L; /* => e->a = 0x10000L after loop exit */
+ }
+ e->a <<= 1;
+ }
+
+ /* Fetch values from our compact representation of Table D.2:
+ * Qe values and probability estimation state machine
+ */
+ sv = *st;
+ qe = jpeg_aritab[sv & 0x7F]; /* => Qe_Value */
+ nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */
+ nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */
+
+ /* Decode & estimation procedures per sections D.2.4 & D.2.5 */
+ temp = e->a - qe;
+ e->a = temp;
+ temp <<= e->ct;
+ if (e->c >= temp) {
+ e->c -= temp;
+ /* Conditional LPS (less probable symbol) exchange */
+ if (e->a < qe) {
+ e->a = qe;
+ *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */
+ } else {
+ e->a = qe;
+ *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */
+ sv ^= 0x80; /* Exchange LPS/MPS */
+ }
+ } else if (e->a < 0x8000L) {
+ /* Conditional MPS (more probable symbol) exchange */
+ if (e->a < qe) {
+ *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */
+ sv ^= 0x80; /* Exchange LPS/MPS */
+ } else {
+ *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */
+ }
+ }
+
+ return sv >> 7;
+}
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ */
+
+LOCAL(void)
+process_restart (j_decompress_ptr cinfo)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ int ci;
+ jpeg_component_info * compptr;
+
+ /* Advance past the RSTn marker */
+ if (! (*cinfo->marker->read_restart_marker) (cinfo))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+
+ /* Re-initialize statistics areas */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
+ MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
+ /* Reset DC predictions to 0 */
+ entropy->last_dc_val[ci] = 0;
+ entropy->dc_context[ci] = 0;
+ }
+ if ((! cinfo->progressive_mode && cinfo->lim_Se) ||
+ (cinfo->progressive_mode && cinfo->Ss)) {
+ MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
+ }
+ }
+
+ /* Reset arithmetic decoding variables */
+ entropy->c = 0;
+ entropy->a = 0;
+ entropy->ct = -16; /* force reading 2 initial bytes to fill C */
+
+ /* Reset restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Arithmetic MCU decoding.
+ * Each of these routines decodes and returns one MCU's worth of
+ * arithmetic-compressed coefficients.
+ * The coefficients are reordered from zigzag order into natural array order,
+ * but are not dequantized.
+ *
+ * The i'th block of the MCU is stored into the block pointed to by
+ * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
+ */
+
+/*
+ * MCU decoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ unsigned char *st;
+ int blkn, ci, tbl, sign;
+ int v, m;
+
+ /* Process restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ process_restart(cinfo);
+ entropy->restarts_to_go--;
+ }
+
+ if (entropy->ct == -1) return TRUE; /* if error do nothing */
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;
+
+ /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */
+
+ /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+ st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+ /* Figure F.19: Decode_DC_DIFF */
+ if (arith_decode(cinfo, st) == 0)
+ entropy->dc_context[ci] = 0;
+ else {
+ /* Figure F.21: Decoding nonzero value v */
+ /* Figure F.22: Decoding the sign of v */
+ sign = arith_decode(cinfo, st + 1);
+ st += 2; st += sign;
+ /* Figure F.23: Decoding the magnitude category of v */
+ if ((m = arith_decode(cinfo, st)) != 0) {
+ st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+ while (arith_decode(cinfo, st)) {
+ if ((m <<= 1) == 0x8000) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* magnitude overflow */
+ return TRUE;
+ }
+ st += 1;
+ }
+ }
+ /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+ if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+ entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */
+ else
+ entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */
+ v = m;
+ /* Figure F.24: Decoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ if (arith_decode(cinfo, st)) v |= m;
+ v += 1; if (sign) v = -v;
+ entropy->last_dc_val[ci] += v;
+ }
+
+ /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */
+ (*block)[0] = (JCOEF) (entropy->last_dc_val[ci] << cinfo->Al);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ unsigned char *st;
+ int tbl, sign, k;
+ int v, m;
+ const int * natural_order;
+
+ /* Process restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ process_restart(cinfo);
+ entropy->restarts_to_go--;
+ }
+
+ if (entropy->ct == -1) return TRUE; /* if error do nothing */
+
+ natural_order = cinfo->natural_order;
+
+ /* There is always only one block per MCU */
+ block = MCU_data[0];
+ tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+ /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
+
+ /* Figure F.20: Decode_AC_coefficients */
+ for (k = cinfo->Ss; k <= cinfo->Se; k++) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ if (arith_decode(cinfo, st)) break; /* EOB flag */
+ while (arith_decode(cinfo, st + 1) == 0) {
+ st += 3; k++;
+ if (k > cinfo->Se) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* spectral overflow */
+ return TRUE;
+ }
+ }
+ /* Figure F.21: Decoding nonzero value v */
+ /* Figure F.22: Decoding the sign of v */
+ sign = arith_decode(cinfo, entropy->fixed_bin);
+ st += 2;
+ /* Figure F.23: Decoding the magnitude category of v */
+ if ((m = arith_decode(cinfo, st)) != 0) {
+ if (arith_decode(cinfo, st)) {
+ m <<= 1;
+ st = entropy->ac_stats[tbl] +
+ (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+ while (arith_decode(cinfo, st)) {
+ if ((m <<= 1) == 0x8000) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* magnitude overflow */
+ return TRUE;
+ }
+ st += 1;
+ }
+ }
+ }
+ v = m;
+ /* Figure F.24: Decoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ if (arith_decode(cinfo, st)) v |= m;
+ v += 1; if (sign) v = -v;
+ /* Scale and output coefficient in natural (dezigzagged) order */
+ (*block)[natural_order[k]] = (JCOEF) (v << cinfo->Al);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for DC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ unsigned char *st;
+ int p1, blkn;
+
+ /* Process restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ process_restart(cinfo);
+ entropy->restarts_to_go--;
+ }
+
+ st = entropy->fixed_bin; /* use fixed probability estimation */
+ p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ /* Encoded data is simply the next bit of the two's-complement DC value */
+ if (arith_decode(cinfo, st))
+ MCU_data[blkn][0][0] |= p1;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ JCOEFPTR thiscoef;
+ unsigned char *st;
+ int tbl, k, kex;
+ int p1, m1;
+ const int * natural_order;
+
+ /* Process restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ process_restart(cinfo);
+ entropy->restarts_to_go--;
+ }
+
+ if (entropy->ct == -1) return TRUE; /* if error do nothing */
+
+ natural_order = cinfo->natural_order;
+
+ /* There is always only one block per MCU */
+ block = MCU_data[0];
+ tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+ p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+ m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */
+
+ /* Establish EOBx (previous stage end-of-block) index */
+ for (kex = cinfo->Se; kex > 0; kex--)
+ if ((*block)[natural_order[kex]]) break;
+
+ for (k = cinfo->Ss; k <= cinfo->Se; k++) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ if (k > kex)
+ if (arith_decode(cinfo, st)) break; /* EOB flag */
+ for (;;) {
+ thiscoef = *block + natural_order[k];
+ if (*thiscoef) { /* previously nonzero coef */
+ if (arith_decode(cinfo, st + 2)) {
+ if (*thiscoef < 0)
+ *thiscoef += m1;
+ else
+ *thiscoef += p1;
+ }
+ break;
+ }
+ if (arith_decode(cinfo, st + 1)) { /* newly nonzero coef */
+ if (arith_decode(cinfo, entropy->fixed_bin))
+ *thiscoef = m1;
+ else
+ *thiscoef = p1;
+ break;
+ }
+ st += 3; k++;
+ if (k > cinfo->Se) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* spectral overflow */
+ return TRUE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Decode one MCU's worth of arithmetic-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ jpeg_component_info * compptr;
+ JBLOCKROW block;
+ unsigned char *st;
+ int blkn, ci, tbl, sign, k;
+ int v, m;
+ const int * natural_order;
+
+ /* Process restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ process_restart(cinfo);
+ entropy->restarts_to_go--;
+ }
+
+ if (entropy->ct == -1) return TRUE; /* if error do nothing */
+
+ natural_order = cinfo->natural_order;
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+
+ /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */
+
+ tbl = compptr->dc_tbl_no;
+
+ /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+ st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+ /* Figure F.19: Decode_DC_DIFF */
+ if (arith_decode(cinfo, st) == 0)
+ entropy->dc_context[ci] = 0;
+ else {
+ /* Figure F.21: Decoding nonzero value v */
+ /* Figure F.22: Decoding the sign of v */
+ sign = arith_decode(cinfo, st + 1);
+ st += 2; st += sign;
+ /* Figure F.23: Decoding the magnitude category of v */
+ if ((m = arith_decode(cinfo, st)) != 0) {
+ st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+ while (arith_decode(cinfo, st)) {
+ if ((m <<= 1) == 0x8000) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* magnitude overflow */
+ return TRUE;
+ }
+ st += 1;
+ }
+ }
+ /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+ if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+ entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */
+ else
+ entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */
+ v = m;
+ /* Figure F.24: Decoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ if (arith_decode(cinfo, st)) v |= m;
+ v += 1; if (sign) v = -v;
+ entropy->last_dc_val[ci] += v;
+ }
+
+ (*block)[0] = (JCOEF) entropy->last_dc_val[ci];
+
+ /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
+
+ tbl = compptr->ac_tbl_no;
+
+ /* Figure F.20: Decode_AC_coefficients */
+ for (k = 1; k <= cinfo->lim_Se; k++) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ if (arith_decode(cinfo, st)) break; /* EOB flag */
+ while (arith_decode(cinfo, st + 1) == 0) {
+ st += 3; k++;
+ if (k > cinfo->lim_Se) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* spectral overflow */
+ return TRUE;
+ }
+ }
+ /* Figure F.21: Decoding nonzero value v */
+ /* Figure F.22: Decoding the sign of v */
+ sign = arith_decode(cinfo, entropy->fixed_bin);
+ st += 2;
+ /* Figure F.23: Decoding the magnitude category of v */
+ if ((m = arith_decode(cinfo, st)) != 0) {
+ if (arith_decode(cinfo, st)) {
+ m <<= 1;
+ st = entropy->ac_stats[tbl] +
+ (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+ while (arith_decode(cinfo, st)) {
+ if ((m <<= 1) == 0x8000) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* magnitude overflow */
+ return TRUE;
+ }
+ st += 1;
+ }
+ }
+ }
+ v = m;
+ /* Figure F.24: Decoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ if (arith_decode(cinfo, st)) v |= m;
+ v += 1; if (sign) v = -v;
+ (*block)[natural_order[k]] = (JCOEF) v;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Initialize for an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass (j_decompress_ptr cinfo)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ int ci, tbl;
+ jpeg_component_info * compptr;
+
+ if (cinfo->progressive_mode) {
+ /* Validate progressive scan parameters */
+ if (cinfo->Ss == 0) {
+ if (cinfo->Se != 0)
+ goto bad;
+ } else {
+ /* need not check Ss/Se < 0 since they came from unsigned bytes */
+ if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se)
+ goto bad;
+ /* AC scans may have only one component */
+ if (cinfo->comps_in_scan != 1)
+ goto bad;
+ }
+ if (cinfo->Ah != 0) {
+ /* Successive approximation refinement scan: must have Al = Ah-1. */
+ if (cinfo->Ah-1 != cinfo->Al)
+ goto bad;
+ }
+ if (cinfo->Al > 13) { /* need not check for < 0 */
+ bad:
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+ }
+ /* Update progression status, and verify that scan order is legal.
+ * Note that inter-scan inconsistencies are treated as warnings
+ * not fatal errors ... not clear if this is right way to behave.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ int coefi, cindex = cinfo->cur_comp_info[ci]->component_index;
+ int *coef_bit_ptr = & cinfo->coef_bits[cindex][0];
+ if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
+ for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
+ int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
+ if (cinfo->Ah != expected)
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
+ coef_bit_ptr[coefi] = cinfo->Al;
+ }
+ }
+ /* Select MCU decoding routine */
+ if (cinfo->Ah == 0) {
+ if (cinfo->Ss == 0)
+ entropy->pub.decode_mcu = decode_mcu_DC_first;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_first;
+ } else {
+ if (cinfo->Ss == 0)
+ entropy->pub.decode_mcu = decode_mcu_DC_refine;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_refine;
+ }
+ } else {
+ /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
+ * This ought to be an error condition, but we make it a warning.
+ */
+ if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 ||
+ (cinfo->Se < DCTSIZE2 && cinfo->Se != cinfo->lim_Se))
+ WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
+ /* Select MCU decoding routine */
+ entropy->pub.decode_mcu = decode_mcu;
+ }
+
+ /* Allocate & initialize requested statistics areas */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
+ tbl = compptr->dc_tbl_no;
+ if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+ ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+ if (entropy->dc_stats[tbl] == NULL)
+ entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);
+ MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
+ /* Initialize DC predictions to 0 */
+ entropy->last_dc_val[ci] = 0;
+ entropy->dc_context[ci] = 0;
+ }
+ if ((! cinfo->progressive_mode && cinfo->lim_Se) ||
+ (cinfo->progressive_mode && cinfo->Ss)) {
+ tbl = compptr->ac_tbl_no;
+ if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+ ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+ if (entropy->ac_stats[tbl] == NULL)
+ entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);
+ MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
+ }
+ }
+
+ /* Initialize arithmetic decoding variables */
+ entropy->c = 0;
+ entropy->a = 0;
+ entropy->ct = -16; /* force reading 2 initial bytes to fill C */
+
+ /* Initialize restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Module initialization routine for arithmetic entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_arith_decoder (j_decompress_ptr cinfo)
+{
+ arith_entropy_ptr entropy;
+ int i;
+
+ entropy = (arith_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(arith_entropy_decoder));
+ cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
+ entropy->pub.start_pass = start_pass;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ entropy->dc_stats[i] = NULL;
+ entropy->ac_stats[i] = NULL;
+ }
+
+ /* Initialize index for fixed probability estimation */
+ entropy->fixed_bin[0] = 113;
+
+ if (cinfo->progressive_mode) {
+ /* Create progression status table */
+ int *coef_bit_ptr, ci;
+ cinfo->coef_bits = (int (*)[DCTSIZE2])
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components*DCTSIZE2*SIZEOF(int));
+ coef_bit_ptr = & cinfo->coef_bits[0][0];
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ for (i = 0; i < DCTSIZE2; i++)
+ *coef_bit_ptr++ = -1;
+ }
+}
diff --git a/external/jpeg-8c/jdatadst.c b/external/jpeg-8c/jdatadst.c
new file mode 100644
index 0000000..472d5f3
--- /dev/null
+++ b/external/jpeg-8c/jdatadst.c
@@ -0,0 +1,267 @@
+/*
+ * jdatadst.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains compression data destination routines for the case of
+ * emitting JPEG data to memory or to a file (or any stdio stream).
+ * While these routines are sufficient for most applications,
+ * some will want to use a different destination manager.
+ * IMPORTANT: we assume that fwrite() will correctly transcribe an array of
+ * JOCTETs into 8-bit-wide elements on external storage. If char is wider
+ * than 8 bits on your machine, you may need to do some tweaking.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+
+/* Expanded data destination object for stdio output */
+
+typedef struct {
+ struct jpeg_destination_mgr pub; /* public fields */
+
+ FILE * outfile; /* target stream */
+ JOCTET * buffer; /* start of buffer */
+} my_destination_mgr;
+
+typedef my_destination_mgr * my_dest_ptr;
+
+#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
+
+
+/* Expanded data destination object for memory output */
+
+typedef struct {
+ struct jpeg_destination_mgr pub; /* public fields */
+
+ unsigned char ** outbuffer; /* target buffer */
+ unsigned long * outsize;
+ unsigned char * newbuffer; /* newly allocated buffer */
+ JOCTET * buffer; /* start of buffer */
+ size_t bufsize;
+} my_mem_destination_mgr;
+
+typedef my_mem_destination_mgr * my_mem_dest_ptr;
+
+
+/*
+ * Initialize destination --- called by jpeg_start_compress
+ * before any data is actually written.
+ */
+
+METHODDEF(void)
+init_destination (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ /* Allocate the output buffer --- it will be released when done with image */
+ dest->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
+
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+}
+
+METHODDEF(void)
+init_mem_destination (j_compress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+
+/*
+ * Empty the output buffer --- called whenever buffer fills up.
+ *
+ * In typical applications, this should write the entire output buffer
+ * (ignoring the current state of next_output_byte & free_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been dumped.
+ *
+ * In applications that need to be able to suspend compression due to output
+ * overrun, a FALSE return indicates that the buffer cannot be emptied now.
+ * In this situation, the compressor will return to its caller (possibly with
+ * an indication that it has not accepted all the supplied scanlines). The
+ * application should resume compression after it has made more room in the
+ * output buffer. Note that there are substantial restrictions on the use of
+ * suspension --- see the documentation.
+ *
+ * When suspending, the compressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_output_byte & free_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point will be regenerated after resumption, so do not
+ * write it out when emptying the buffer externally.
+ */
+
+METHODDEF(boolean)
+empty_output_buffer (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) !=
+ (size_t) OUTPUT_BUF_SIZE)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+
+ return TRUE;
+}
+
+METHODDEF(boolean)
+empty_mem_output_buffer (j_compress_ptr cinfo)
+{
+ size_t nextsize;
+ JOCTET * nextbuffer;
+ my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
+
+ /* Try to allocate new buffer with double size */
+ nextsize = dest->bufsize * 2;
+ nextbuffer = malloc(nextsize);
+
+ if (nextbuffer == NULL)
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
+
+ MEMCOPY(nextbuffer, dest->buffer, dest->bufsize);
+
+ if (dest->newbuffer != NULL)
+ free(dest->newbuffer);
+
+ dest->newbuffer = nextbuffer;
+
+ dest->pub.next_output_byte = nextbuffer + dest->bufsize;
+ dest->pub.free_in_buffer = dest->bufsize;
+
+ dest->buffer = nextbuffer;
+ dest->bufsize = nextsize;
+
+ return TRUE;
+}
+
+
+/*
+ * Terminate destination --- called by jpeg_finish_compress
+ * after all data has been written. Usually needs to flush buffer.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_destination (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+ size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
+
+ /* Write any data remaining in the buffer */
+ if (datacount > 0) {
+ if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+ }
+ fflush(dest->outfile);
+ /* Make sure we wrote the output file OK */
+ if (ferror(dest->outfile))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+METHODDEF(void)
+term_mem_destination (j_compress_ptr cinfo)
+{
+ my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
+
+ *dest->outbuffer = dest->buffer;
+ *dest->outsize = dest->bufsize - dest->pub.free_in_buffer;
+}
+
+
+/*
+ * Prepare for output to a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing compression.
+ */
+
+GLOBAL(void)
+jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)
+{
+ my_dest_ptr dest;
+
+ /* The destination object is made permanent so that multiple JPEG images
+ * can be written to the same file without re-executing jpeg_stdio_dest.
+ * This makes it dangerous to use this manager and a different destination
+ * manager serially with the same JPEG object, because their private object
+ * sizes may be different. Caveat programmer.
+ */
+ if (cinfo->dest == NULL) { /* first time for this JPEG object? */
+ cinfo->dest = (struct jpeg_destination_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_destination_mgr));
+ }
+
+ dest = (my_dest_ptr) cinfo->dest;
+ dest->pub.init_destination = init_destination;
+ dest->pub.empty_output_buffer = empty_output_buffer;
+ dest->pub.term_destination = term_destination;
+ dest->outfile = outfile;
+}
+
+
+/*
+ * Prepare for output to a memory buffer.
+ * The caller may supply an own initial buffer with appropriate size.
+ * Otherwise, or when the actual data output exceeds the given size,
+ * the library adapts the buffer size as necessary.
+ * The standard library functions malloc/free are used for allocating
+ * larger memory, so the buffer is available to the application after
+ * finishing compression, and then the application is responsible for
+ * freeing the requested memory.
+ */
+
+GLOBAL(void)
+jpeg_mem_dest (j_compress_ptr cinfo,
+ unsigned char ** outbuffer, unsigned long * outsize)
+{
+ my_mem_dest_ptr dest;
+
+ if (outbuffer == NULL || outsize == NULL) /* sanity check */
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+ /* The destination object is made permanent so that multiple JPEG images
+ * can be written to the same buffer without re-executing jpeg_mem_dest.
+ */
+ if (cinfo->dest == NULL) { /* first time for this JPEG object? */
+ cinfo->dest = (struct jpeg_destination_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_mem_destination_mgr));
+ }
+
+ dest = (my_mem_dest_ptr) cinfo->dest;
+ dest->pub.init_destination = init_mem_destination;
+ dest->pub.empty_output_buffer = empty_mem_output_buffer;
+ dest->pub.term_destination = term_mem_destination;
+ dest->outbuffer = outbuffer;
+ dest->outsize = outsize;
+ dest->newbuffer = NULL;
+
+ if (*outbuffer == NULL || *outsize == 0) {
+ /* Allocate initial buffer */
+ dest->newbuffer = *outbuffer = malloc(OUTPUT_BUF_SIZE);
+ if (dest->newbuffer == NULL)
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
+ *outsize = OUTPUT_BUF_SIZE;
+ }
+
+ dest->pub.next_output_byte = dest->buffer = *outbuffer;
+ dest->pub.free_in_buffer = dest->bufsize = *outsize;
+}
diff --git a/external/jpeg-8c/jdatasrc.c b/external/jpeg-8c/jdatasrc.c
new file mode 100644
index 0000000..c8fe3da
--- /dev/null
+++ b/external/jpeg-8c/jdatasrc.c
@@ -0,0 +1,274 @@
+/*
+ * jdatasrc.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009-2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains decompression data source routines for the case of
+ * reading JPEG data from memory or from a file (or any stdio stream).
+ * While these routines are sufficient for most applications,
+ * some will want to use a different source manager.
+ * IMPORTANT: we assume that fread() will correctly transcribe an array of
+ * JOCTETs from 8-bit-wide elements on external storage. If char is wider
+ * than 8 bits on your machine, you may need to do some tweaking.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+
+/* Expanded data source object for stdio input */
+
+typedef struct {
+ struct jpeg_source_mgr pub; /* public fields */
+
+ FILE * infile; /* source stream */
+ JOCTET * buffer; /* start of buffer */
+ boolean start_of_file; /* have we gotten any data yet? */
+} my_source_mgr;
+
+typedef my_source_mgr * my_src_ptr;
+
+#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
+
+
+/*
+ * Initialize source --- called by jpeg_read_header
+ * before any data is actually read.
+ */
+
+METHODDEF(void)
+init_source (j_decompress_ptr cinfo)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ /* We reset the empty-input-file flag for each image,
+ * but we don't clear the input buffer.
+ * This is correct behavior for reading a series of images from one source.
+ */
+ src->start_of_file = TRUE;
+}
+
+METHODDEF(void)
+init_mem_source (j_decompress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+
+/*
+ * Fill the input buffer --- called whenever buffer is emptied.
+ *
+ * In typical applications, this should read fresh data into the buffer
+ * (ignoring the current state of next_input_byte & bytes_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been reloaded. It is not necessary to
+ * fill the buffer entirely, only to obtain at least one more byte.
+ *
+ * There is no such thing as an EOF return. If the end of the file has been
+ * reached, the routine has a choice of ERREXIT() or inserting fake data into
+ * the buffer. In most cases, generating a warning message and inserting a
+ * fake EOI marker is the best course of action --- this will allow the
+ * decompressor to output however much of the image is there. However,
+ * the resulting error message is misleading if the real problem is an empty
+ * input file, so we handle that case specially.
+ *
+ * In applications that need to be able to suspend compression due to input
+ * not being available yet, a FALSE return indicates that no more data can be
+ * obtained right now, but more may be forthcoming later. In this situation,
+ * the decompressor will return to its caller (with an indication of the
+ * number of scanlines it has read, if any). The application should resume
+ * decompression after it has loaded more data into the input buffer. Note
+ * that there are substantial restrictions on the use of suspension --- see
+ * the documentation.
+ *
+ * When suspending, the decompressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point must be rescanned after resumption, so move it to
+ * the front of the buffer rather than discarding it.
+ */
+
+METHODDEF(boolean)
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+ size_t nbytes;
+
+ nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE);
+
+ if (nbytes <= 0) {
+ if (src->start_of_file) /* Treat empty input file as fatal error */
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+ /* Insert a fake EOI marker */
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ nbytes = 2;
+ }
+
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = nbytes;
+ src->start_of_file = FALSE;
+
+ return TRUE;
+}
+
+METHODDEF(boolean)
+fill_mem_input_buffer (j_decompress_ptr cinfo)
+{
+ static JOCTET mybuffer[4];
+
+ /* The whole JPEG data is expected to reside in the supplied memory
+ * buffer, so any request for more data beyond the given buffer size
+ * is treated as an error.
+ */
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+ /* Insert a fake EOI marker */
+ mybuffer[0] = (JOCTET) 0xFF;
+ mybuffer[1] = (JOCTET) JPEG_EOI;
+
+ cinfo->src->next_input_byte = mybuffer;
+ cinfo->src->bytes_in_buffer = 2;
+
+ return TRUE;
+}
+
+
+/*
+ * Skip data --- used to skip over a potentially large amount of
+ * uninteresting data (such as an APPn marker).
+ *
+ * Writers of suspendable-input applications must note that skip_input_data
+ * is not granted the right to give a suspension return. If the skip extends
+ * beyond the data currently in the buffer, the buffer can be marked empty so
+ * that the next read will cause a fill_input_buffer call that can suspend.
+ * Arranging for additional bytes to be discarded before reloading the input
+ * buffer is the application writer's problem.
+ */
+
+METHODDEF(void)
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ struct jpeg_source_mgr * src = cinfo->src;
+
+ /* Just a dumb implementation for now. Could use fseek() except
+ * it doesn't work on pipes. Not clear that being smart is worth
+ * any trouble anyway --- large skips are infrequent.
+ */
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->bytes_in_buffer) {
+ num_bytes -= (long) src->bytes_in_buffer;
+ (void) (*src->fill_input_buffer) (cinfo);
+ /* note we assume that fill_input_buffer will never return FALSE,
+ * so suspension need not be handled.
+ */
+ }
+ src->next_input_byte += (size_t) num_bytes;
+ src->bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+
+/*
+ * An additional method that can be provided by data source modules is the
+ * resync_to_restart method for error recovery in the presence of RST markers.
+ * For the moment, this source module just uses the default resync method
+ * provided by the JPEG library. That method assumes that no backtracking
+ * is possible.
+ */
+
+
+/*
+ * Terminate source --- called by jpeg_finish_decompress
+ * after all data has been read. Often a no-op.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_source (j_decompress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+
+/*
+ * Prepare for input from a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing decompression.
+ */
+
+GLOBAL(void)
+jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
+{
+ my_src_ptr src;
+
+ /* The source object and input buffer are made permanent so that a series
+ * of JPEG images can be read from the same file by calling jpeg_stdio_src
+ * only before the first one. (If we discarded the buffer at the end of
+ * one image, we'd likely lose the start of the next one.)
+ * This makes it unsafe to use this manager and a different source
+ * manager serially with the same JPEG object. Caveat programmer.
+ */
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_source_mgr));
+ src = (my_src_ptr) cinfo->src;
+ src->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ INPUT_BUF_SIZE * SIZEOF(JOCTET));
+ }
+
+ src = (my_src_ptr) cinfo->src;
+ src->pub.init_source = init_source;
+ src->pub.fill_input_buffer = fill_input_buffer;
+ src->pub.skip_input_data = skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->pub.term_source = term_source;
+ src->infile = infile;
+ src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+ src->pub.next_input_byte = NULL; /* until buffer loaded */
+}
+
+
+/*
+ * Prepare for input from a supplied memory buffer.
+ * The buffer must contain the whole JPEG data.
+ */
+
+GLOBAL(void)
+jpeg_mem_src (j_decompress_ptr cinfo,
+ unsigned char * inbuffer, unsigned long insize)
+{
+ struct jpeg_source_mgr * src;
+
+ if (inbuffer == NULL || insize == 0) /* Treat empty input as fatal error */
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+
+ /* The source object is made permanent so that a series of JPEG images
+ * can be read from the same buffer by calling jpeg_mem_src only before
+ * the first one.
+ */
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(struct jpeg_source_mgr));
+ }
+
+ src = cinfo->src;
+ src->init_source = init_mem_source;
+ src->fill_input_buffer = fill_mem_input_buffer;
+ src->skip_input_data = skip_input_data;
+ src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->term_source = term_source;
+ src->bytes_in_buffer = (size_t) insize;
+ src->next_input_byte = (JOCTET *) inbuffer;
+}
diff --git a/external/jpeg-8c/jdcoefct.c b/external/jpeg-8c/jdcoefct.c
new file mode 100644
index 0000000..462e92c
--- /dev/null
+++ b/external/jpeg-8c/jdcoefct.c
@@ -0,0 +1,736 @@
+/*
+ * jdcoefct.c
+ *
+ * Copyright (C) 1994-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 the coefficient buffer controller for decompression.
+ * This controller is the top level of the JPEG decompressor proper.
+ * The coefficient buffer lies between entropy decoding and inverse-DCT steps.
+ *
+ * In buffered-image mode, this controller is the interface between
+ * input-oriented processing and output-oriented processing.
+ * Also, the input side (only) is used when reading a file for transcoding.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+/* Block smoothing is only applicable for progressive JPEG, so: */
+#ifndef D_PROGRESSIVE_SUPPORTED
+#undef BLOCK_SMOOTHING_SUPPORTED
+#endif
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_d_coef_controller pub; /* public fields */
+
+ /* These variables keep track of the current location of the input side. */
+ /* cinfo->input_iMCU_row is also used for this. */
+ JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* The output side's location is represented by cinfo->output_iMCU_row. */
+
+ /* In single-pass modes, it's sufficient to buffer just one MCU.
+ * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
+ * and let the entropy decoder write into that workspace each time.
+ * (On 80x86, the workspace is FAR even though it's not really very big;
+ * this is to keep the module interfaces unchanged when a large coefficient
+ * buffer is necessary.)
+ * In multi-pass modes, this array points to the current MCU's blocks
+ * within the virtual arrays; it is used only by the input side.
+ */
+ JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* In multi-pass modes, we need a virtual block array for each component. */
+ jvirt_barray_ptr whole_image[MAX_COMPONENTS];
+#endif
+
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ /* When doing block smoothing, we latch coefficient Al values here */
+ int * coef_bits_latch;
+#define SAVED_COEFS 6 /* we save coef_bits[0..5] */
+#endif
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+/* Forward declarations */
+METHODDEF(int) decompress_onepass
+ JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+METHODDEF(int) decompress_data
+ JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#endif
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo));
+METHODDEF(int) decompress_smooth_data
+ JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#endif
+
+
+LOCAL(void)
+start_iMCU_row (j_decompress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row (input side) */
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ coef->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ coef->MCU_ctr = 0;
+ coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for an input processing pass.
+ */
+
+METHODDEF(void)
+start_input_pass (j_decompress_ptr cinfo)
+{
+ cinfo->input_iMCU_row = 0;
+ start_iMCU_row(cinfo);
+}
+
+
+/*
+ * Initialize for an output processing pass.
+ */
+
+METHODDEF(void)
+start_output_pass (j_decompress_ptr cinfo)
+{
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* If multipass, check to see whether to use block smoothing on this pass */
+ if (coef->pub.coef_arrays != NULL) {
+ if (cinfo->do_block_smoothing && smoothing_ok(cinfo))
+ coef->pub.decompress_data = decompress_smooth_data;
+ else
+ coef->pub.decompress_data = decompress_data;
+ }
+#endif
+ cinfo->output_iMCU_row = 0;
+}
+
+
+/*
+ * Decompress and return some data in the single-pass case.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Input and output must run in lockstep since we have only a one-MCU buffer.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image,
+ * which we index according to the component's SOF position.
+ */
+
+METHODDEF(int)
+decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int blkn, ci, xindex, yindex, yoffset, useful_width;
+ JSAMPARRAY output_ptr;
+ JDIMENSION start_col, output_col;
+ jpeg_component_info *compptr;
+ inverse_DCT_method_ptr inverse_DCT;
+
+ /* Loop to process as much as one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col;
+ MCU_col_num++) {
+ /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */
+ jzero_far((void FAR *) coef->MCU_buffer[0],
+ (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK)));
+ if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
+ }
+ /* Determine where data should go in output_buf and do the IDCT thing.
+ * We skip dummy blocks at the right and bottom edges (but blkn gets
+ * incremented past them!). Note the inner loop relies on having
+ * allocated the MCU_buffer[] blocks sequentially.
+ */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr->component_needed) {
+ blkn += compptr->MCU_blocks;
+ continue;
+ }
+ inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
+ useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+ : compptr->last_col_width;
+ output_ptr = output_buf[compptr->component_index] +
+ yoffset * compptr->DCT_v_scaled_size;
+ start_col = MCU_col_num * compptr->MCU_sample_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ if (cinfo->input_iMCU_row < last_iMCU_row ||
+ yoffset+yindex < compptr->last_row_height) {
+ output_col = start_col;
+ for (xindex = 0; xindex < useful_width; xindex++) {
+ (*inverse_DCT) (cinfo, compptr,
+ (JCOEFPTR) coef->MCU_buffer[blkn+xindex],
+ output_ptr, output_col);
+ output_col += compptr->DCT_h_scaled_size;
+ }
+ }
+ blkn += compptr->MCU_width;
+ output_ptr += compptr->DCT_v_scaled_size;
+ }
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->MCU_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ cinfo->output_iMCU_row++;
+ if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+ start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+
+/*
+ * Dummy consume-input routine for single-pass operation.
+ */
+
+METHODDEF(int)
+dummy_consume_data (j_decompress_ptr cinfo)
+{
+ return JPEG_SUSPENDED; /* Always indicate nothing was done */
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Consume input data and store it in the full-image coefficient buffer.
+ * We read as much as one fully interleaved MCU row ("iMCU" row) per call,
+ * ie, v_samp_factor block rows for each component in the scan.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ */
+
+METHODDEF(int)
+consume_data (j_decompress_ptr cinfo)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ int blkn, ci, xindex, yindex, yoffset;
+ JDIMENSION start_col;
+ JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+ JBLOCKROW buffer_ptr;
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan. */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ buffer[ci] = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+ cinfo->input_iMCU_row * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ /* Note: entropy decoder expects buffer to be zeroed,
+ * but this is handled automatically by the memory manager
+ * because we requested a pre-zeroed array.
+ */
+ }
+
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row;
+ MCU_col_num++) {
+ /* Construct list of pointers to DCT blocks belonging to this MCU */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ start_col = MCU_col_num * compptr->MCU_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
+ coef->MCU_buffer[blkn++] = buffer_ptr++;
+ }
+ }
+ }
+ /* Try to fetch the MCU. */
+ if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->MCU_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+ start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+
+/*
+ * Decompress and return some data in the multi-pass case.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image.
+ */
+
+METHODDEF(int)
+decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ JDIMENSION block_num;
+ int ci, block_row, block_rows;
+ JBLOCKARRAY buffer;
+ JBLOCKROW buffer_ptr;
+ JSAMPARRAY output_ptr;
+ JDIMENSION output_col;
+ jpeg_component_info *compptr;
+ inverse_DCT_method_ptr inverse_DCT;
+
+ /* Force some input to be done if we are getting ahead of the input. */
+ while (cinfo->input_scan_number < cinfo->output_scan_number ||
+ (cinfo->input_scan_number == cinfo->output_scan_number &&
+ cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) {
+ if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
+ return JPEG_SUSPENDED;
+ }
+
+ /* OK, output from the virtual arrays. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr->component_needed)
+ continue;
+ /* Align the virtual buffer for this component. */
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ cinfo->output_iMCU_row * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ /* Count non-dummy DCT block rows in this iMCU row. */
+ if (cinfo->output_iMCU_row < last_iMCU_row)
+ block_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here; it is input-side-dependent! */
+ block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (block_rows == 0) block_rows = compptr->v_samp_factor;
+ }
+ inverse_DCT = cinfo->idct->inverse_DCT[ci];
+ output_ptr = output_buf[ci];
+ /* Loop over all DCT blocks to be processed. */
+ for (block_row = 0; block_row < block_rows; block_row++) {
+ buffer_ptr = buffer[block_row];
+ output_col = 0;
+ for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) {
+ (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
+ output_ptr, output_col);
+ buffer_ptr++;
+ output_col += compptr->DCT_h_scaled_size;
+ }
+ output_ptr += compptr->DCT_v_scaled_size;
+ }
+ }
+
+ if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
+ return JPEG_ROW_COMPLETED;
+ return JPEG_SCAN_COMPLETED;
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+
+/*
+ * This code applies interblock smoothing as described by section K.8
+ * of the JPEG standard: the first 5 AC coefficients are estimated from
+ * the DC values of a DCT block and its 8 neighboring blocks.
+ * We apply smoothing only for progressive JPEG decoding, and only if
+ * the coefficients it can estimate are not yet known to full precision.
+ */
+
+/* Natural-order array positions of the first 5 zigzag-order coefficients */
+#define Q01_POS 1
+#define Q10_POS 8
+#define Q20_POS 16
+#define Q11_POS 9
+#define Q02_POS 2
+
+/*
+ * Determine whether block smoothing is applicable and safe.
+ * We also latch the current states of the coef_bits[] entries for the
+ * AC coefficients; otherwise, if the input side of the decompressor
+ * advances into a new scan, we might think the coefficients are known
+ * more accurately than they really are.
+ */
+
+LOCAL(boolean)
+smoothing_ok (j_decompress_ptr cinfo)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ boolean smoothing_useful = FALSE;
+ int ci, coefi;
+ jpeg_component_info *compptr;
+ JQUANT_TBL * qtable;
+ int * coef_bits;
+ int * coef_bits_latch;
+
+ if (! cinfo->progressive_mode || cinfo->coef_bits == NULL)
+ return FALSE;
+
+ /* Allocate latch area if not already done */
+ if (coef->coef_bits_latch == NULL)
+ coef->coef_bits_latch = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components *
+ (SAVED_COEFS * SIZEOF(int)));
+ coef_bits_latch = coef->coef_bits_latch;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* All components' quantization values must already be latched. */
+ if ((qtable = compptr->quant_table) == NULL)
+ return FALSE;
+ /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */
+ if (qtable->quantval[0] == 0 ||
+ qtable->quantval[Q01_POS] == 0 ||
+ qtable->quantval[Q10_POS] == 0 ||
+ qtable->quantval[Q20_POS] == 0 ||
+ qtable->quantval[Q11_POS] == 0 ||
+ qtable->quantval[Q02_POS] == 0)
+ return FALSE;
+ /* DC values must be at least partly known for all components. */
+ coef_bits = cinfo->coef_bits[ci];
+ if (coef_bits[0] < 0)
+ return FALSE;
+ /* Block smoothing is helpful if some AC coefficients remain inaccurate. */
+ for (coefi = 1; coefi <= 5; coefi++) {
+ coef_bits_latch[coefi] = coef_bits[coefi];
+ if (coef_bits[coefi] != 0)
+ smoothing_useful = TRUE;
+ }
+ coef_bits_latch += SAVED_COEFS;
+ }
+
+ return smoothing_useful;
+}
+
+
+/*
+ * Variant of decompress_data for use when doing block smoothing.
+ */
+
+METHODDEF(int)
+decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ JDIMENSION block_num, last_block_column;
+ int ci, block_row, block_rows, access_rows;
+ JBLOCKARRAY buffer;
+ JBLOCKROW buffer_ptr, prev_block_row, next_block_row;
+ JSAMPARRAY output_ptr;
+ JDIMENSION output_col;
+ jpeg_component_info *compptr;
+ inverse_DCT_method_ptr inverse_DCT;
+ boolean first_row, last_row;
+ JBLOCK workspace;
+ int *coef_bits;
+ JQUANT_TBL *quanttbl;
+ INT32 Q00,Q01,Q02,Q10,Q11,Q20, num;
+ int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9;
+ int Al, pred;
+
+ /* Force some input to be done if we are getting ahead of the input. */
+ while (cinfo->input_scan_number <= cinfo->output_scan_number &&
+ ! cinfo->inputctl->eoi_reached) {
+ if (cinfo->input_scan_number == cinfo->output_scan_number) {
+ /* If input is working on current scan, we ordinarily want it to
+ * have completed the current row. But if input scan is DC,
+ * we want it to keep one row ahead so that next block row's DC
+ * values are up to date.
+ */
+ JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0;
+ if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta)
+ break;
+ }
+ if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
+ return JPEG_SUSPENDED;
+ }
+
+ /* OK, output from the virtual arrays. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr->component_needed)
+ continue;
+ /* Count non-dummy DCT block rows in this iMCU row. */
+ if (cinfo->output_iMCU_row < last_iMCU_row) {
+ block_rows = compptr->v_samp_factor;
+ access_rows = block_rows * 2; /* this and next iMCU row */
+ last_row = FALSE;
+ } else {
+ /* NB: can't use last_row_height here; it is input-side-dependent! */
+ block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (block_rows == 0) block_rows = compptr->v_samp_factor;
+ access_rows = block_rows; /* this iMCU row only */
+ last_row = TRUE;
+ }
+ /* Align the virtual buffer for this component. */
+ if (cinfo->output_iMCU_row > 0) {
+ access_rows += compptr->v_samp_factor; /* prior iMCU row too */
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor,
+ (JDIMENSION) access_rows, FALSE);
+ buffer += compptr->v_samp_factor; /* point to current iMCU row */
+ first_row = FALSE;
+ } else {
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE);
+ first_row = TRUE;
+ }
+ /* Fetch component-dependent info */
+ coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS);
+ quanttbl = compptr->quant_table;
+ Q00 = quanttbl->quantval[0];
+ Q01 = quanttbl->quantval[Q01_POS];
+ Q10 = quanttbl->quantval[Q10_POS];
+ Q20 = quanttbl->quantval[Q20_POS];
+ Q11 = quanttbl->quantval[Q11_POS];
+ Q02 = quanttbl->quantval[Q02_POS];
+ inverse_DCT = cinfo->idct->inverse_DCT[ci];
+ output_ptr = output_buf[ci];
+ /* Loop over all DCT blocks to be processed. */
+ for (block_row = 0; block_row < block_rows; block_row++) {
+ buffer_ptr = buffer[block_row];
+ if (first_row && block_row == 0)
+ prev_block_row = buffer_ptr;
+ else
+ prev_block_row = buffer[block_row-1];
+ if (last_row && block_row == block_rows-1)
+ next_block_row = buffer_ptr;
+ else
+ next_block_row = buffer[block_row+1];
+ /* We fetch the surrounding DC values using a sliding-register approach.
+ * Initialize all nine here so as to do the right thing on narrow pics.
+ */
+ DC1 = DC2 = DC3 = (int) prev_block_row[0][0];
+ DC4 = DC5 = DC6 = (int) buffer_ptr[0][0];
+ DC7 = DC8 = DC9 = (int) next_block_row[0][0];
+ output_col = 0;
+ last_block_column = compptr->width_in_blocks - 1;
+ for (block_num = 0; block_num <= last_block_column; block_num++) {
+ /* Fetch current DCT block into workspace so we can modify it. */
+ jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1);
+ /* Update DC values */
+ if (block_num < last_block_column) {
+ DC3 = (int) prev_block_row[1][0];
+ DC6 = (int) buffer_ptr[1][0];
+ DC9 = (int) next_block_row[1][0];
+ }
+ /* Compute coefficient estimates per K.8.
+ * An estimate is applied only if coefficient is still zero,
+ * and is not known to be fully accurate.
+ */
+ /* AC01 */
+ if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) {
+ num = 36 * Q00 * (DC4 - DC6);
+ if (num >= 0) {
+ pred = (int) (((Q01<<7) + num) / (Q01<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q01<<7) - num) / (Q01<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[1] = (JCOEF) pred;
+ }
+ /* AC10 */
+ if ((Al=coef_bits[2]) != 0 && workspace[8] == 0) {
+ num = 36 * Q00 * (DC2 - DC8);
+ if (num >= 0) {
+ pred = (int) (((Q10<<7) + num) / (Q10<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q10<<7) - num) / (Q10<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[8] = (JCOEF) pred;
+ }
+ /* AC20 */
+ if ((Al=coef_bits[3]) != 0 && workspace[16] == 0) {
+ num = 9 * Q00 * (DC2 + DC8 - 2*DC5);
+ if (num >= 0) {
+ pred = (int) (((Q20<<7) + num) / (Q20<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q20<<7) - num) / (Q20<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[16] = (JCOEF) pred;
+ }
+ /* AC11 */
+ if ((Al=coef_bits[4]) != 0 && workspace[9] == 0) {
+ num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9);
+ if (num >= 0) {
+ pred = (int) (((Q11<<7) + num) / (Q11<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q11<<7) - num) / (Q11<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[9] = (JCOEF) pred;
+ }
+ /* AC02 */
+ if ((Al=coef_bits[5]) != 0 && workspace[2] == 0) {
+ num = 9 * Q00 * (DC4 + DC6 - 2*DC5);
+ if (num >= 0) {
+ pred = (int) (((Q02<<7) + num) / (Q02<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q02<<7) - num) / (Q02<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[2] = (JCOEF) pred;
+ }
+ /* OK, do the IDCT */
+ (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) workspace,
+ output_ptr, output_col);
+ /* Advance for next column */
+ DC1 = DC2; DC2 = DC3;
+ DC4 = DC5; DC5 = DC6;
+ DC7 = DC8; DC8 = DC9;
+ buffer_ptr++, prev_block_row++, next_block_row++;
+ output_col += compptr->DCT_h_scaled_size;
+ }
+ output_ptr += compptr->DCT_v_scaled_size;
+ }
+ }
+
+ if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
+ return JPEG_ROW_COMPLETED;
+ return JPEG_SCAN_COMPLETED;
+}
+
+#endif /* BLOCK_SMOOTHING_SUPPORTED */
+
+
+/*
+ * Initialize coefficient buffer controller.
+ */
+
+GLOBAL(void)
+jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+ my_coef_ptr coef;
+
+ coef = (my_coef_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_coef_controller));
+ cinfo->coef = (struct jpeg_d_coef_controller *) coef;
+ coef->pub.start_input_pass = start_input_pass;
+ coef->pub.start_output_pass = start_output_pass;
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ coef->coef_bits_latch = NULL;
+#endif
+
+ /* Create the coefficient buffer. */
+ if (need_full_buffer) {
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* Allocate a full-image virtual array for each component, */
+ /* padded to a multiple of samp_factor DCT blocks in each direction. */
+ /* Note we ask for a pre-zeroed array. */
+ int ci, access_rows;
+ jpeg_component_info *compptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ access_rows = compptr->v_samp_factor;
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ /* If block smoothing could be used, need a bigger window */
+ if (cinfo->progressive_mode)
+ access_rows *= 3;
+#endif
+ coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE,
+ (JDIMENSION) jround_up((long) compptr->width_in_blocks,
+ (long) compptr->h_samp_factor),
+ (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+ (long) compptr->v_samp_factor),
+ (JDIMENSION) access_rows);
+ }
+ coef->pub.consume_data = consume_data;
+ coef->pub.decompress_data = decompress_data;
+ coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ /* We only need a single-MCU buffer. */
+ JBLOCKROW buffer;
+ int i;
+
+ buffer = (JBLOCKROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) {
+ coef->MCU_buffer[i] = buffer + i;
+ }
+ coef->pub.consume_data = dummy_consume_data;
+ coef->pub.decompress_data = decompress_onepass;
+ coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */
+ }
+}
diff --git a/external/jpeg-8c/jdcolor.c b/external/jpeg-8c/jdcolor.c
new file mode 100644
index 0000000..6c04dfe
--- /dev/null
+++ b/external/jpeg-8c/jdcolor.c
@@ -0,0 +1,396 @@
+/*
+ * jdcolor.c
+ *
+ * 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 output colorspace conversion routines.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_color_deconverter pub; /* public fields */
+
+ /* Private state for YCC->RGB conversion */
+ int * Cr_r_tab; /* => table for Cr to R conversion */
+ int * Cb_b_tab; /* => table for Cb to B conversion */
+ INT32 * Cr_g_tab; /* => table for Cr to G conversion */
+ INT32 * Cb_g_tab; /* => table for Cb to G conversion */
+} my_color_deconverter;
+
+typedef my_color_deconverter * my_cconvert_ptr;
+
+
+/**************** YCbCr -> RGB conversion: most common case **************/
+
+/*
+ * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+ * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * The conversion equations to be implemented are therefore
+ * R = Y + 1.40200 * Cr
+ * G = Y - 0.34414 * Cb - 0.71414 * Cr
+ * B = Y + 1.77200 * Cb
+ * where Cb and Cr represent the incoming values less CENTERJSAMPLE.
+ * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
+ *
+ * To avoid floating-point arithmetic, we represent the fractional constants
+ * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+ * the products by 2^16, with appropriate rounding, to get the correct answer.
+ * Notice that Y, being an integral input, does not contribute any fraction
+ * so it need not participate in the rounding.
+ *
+ * For even more speed, we avoid doing any multiplications in the inner loop
+ * by precalculating the constants times Cb and Cr for all possible values.
+ * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * for 12-bit samples it is still acceptable. It's not very reasonable for
+ * 16-bit samples, but if you want lossless storage you shouldn't be changing
+ * colorspace anyway.
+ * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
+ * values for the G calculation are left scaled up, since we must add them
+ * together before rounding.
+ */
+
+#define SCALEBITS 16 /* speediest right-shift on some machines */
+#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
+#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
+
+
+/*
+ * Initialize tables for YCC->RGB colorspace conversion.
+ */
+
+LOCAL(void)
+build_ycc_rgb_table (j_decompress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ int i;
+ INT32 x;
+ SHIFT_TEMPS
+
+ cconvert->Cr_r_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ cconvert->Cb_b_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ cconvert->Cr_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+ cconvert->Cb_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+
+ for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
+ /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ /* Cr=>R value is nearest int to 1.40200 * x */
+ cconvert->Cr_r_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
+ /* Cb=>B value is nearest int to 1.77200 * x */
+ cconvert->Cb_b_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS);
+ /* Cr=>G value is scaled-up -0.71414 * x */
+ cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x;
+ /* Cb=>G value is scaled-up -0.34414 * x */
+ /* We also add in ONE_HALF so that need not do it in inner loop */
+ cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF;
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the output colorspace.
+ *
+ * Note that we change from noninterleaved, one-plane-per-component format
+ * to interleaved-pixel format. The output buffer is therefore three times
+ * as wide as the input buffer.
+ * A starting row offset is provided only for the input buffer. The caller
+ * can easily adjust the passed output_buf value to accommodate any row
+ * offset required on that side.
+ */
+
+METHODDEF(void)
+ycc_rgb_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int y, cb, cr;
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ register int * Crrtab = cconvert->Cr_r_tab;
+ register int * Cbbtab = cconvert->Cb_b_tab;
+ register INT32 * Crgtab = cconvert->Cr_g_tab;
+ register INT32 * Cbgtab = cconvert->Cb_g_tab;
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ y = GETJSAMPLE(inptr0[col]);
+ cb = GETJSAMPLE(inptr1[col]);
+ cr = GETJSAMPLE(inptr2[col]);
+ /* Range-limiting is essential due to noise introduced by DCT losses. */
+ outptr[RGB_RED] = range_limit[y + Crrtab[cr]];
+ outptr[RGB_GREEN] = range_limit[y +
+ ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
+ SCALEBITS))];
+ outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]];
+ outptr += RGB_PIXELSIZE;
+ }
+ }
+}
+
+
+/**************** Cases other than YCbCr -> RGB **************/
+
+
+/*
+ * Color conversion for no colorspace change: just copy the data,
+ * converting from separate-planes to interleaved representation.
+ */
+
+METHODDEF(void)
+null_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION count;
+ register int num_components = cinfo->num_components;
+ JDIMENSION num_cols = cinfo->output_width;
+ int ci;
+
+ while (--num_rows >= 0) {
+ for (ci = 0; ci < num_components; ci++) {
+ inptr = input_buf[ci][input_row];
+ outptr = output_buf[0] + ci;
+ for (count = num_cols; count > 0; count--) {
+ *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */
+ outptr += num_components;
+ }
+ }
+ input_row++;
+ output_buf++;
+ }
+}
+
+
+/*
+ * Color conversion for grayscale: just copy the data.
+ * This also works for YCbCr -> grayscale conversion, in which
+ * we just copy the Y (luminance) component and ignore chrominance.
+ */
+
+METHODDEF(void)
+grayscale_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0,
+ num_rows, cinfo->output_width);
+}
+
+
+/*
+ * Convert grayscale to RGB: just duplicate the graylevel three times.
+ * This is provided to support applications that don't want to cope
+ * with grayscale as a separate case.
+ */
+
+METHODDEF(void)
+gray_rgb_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+
+ while (--num_rows >= 0) {
+ inptr = input_buf[0][input_row++];
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ /* We can dispense with GETJSAMPLE() here */
+ outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col];
+ outptr += RGB_PIXELSIZE;
+ }
+ }
+}
+
+
+/*
+ * Adobe-style YCCK->CMYK conversion.
+ * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same
+ * conversion as above, while passing K (black) unchanged.
+ * We assume build_ycc_rgb_table has been called.
+ */
+
+METHODDEF(void)
+ycck_cmyk_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int y, cb, cr;
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2, inptr3;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ register int * Crrtab = cconvert->Cr_r_tab;
+ register int * Cbbtab = cconvert->Cb_b_tab;
+ register INT32 * Crgtab = cconvert->Cr_g_tab;
+ register INT32 * Cbgtab = cconvert->Cb_g_tab;
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ inptr3 = input_buf[3][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ y = GETJSAMPLE(inptr0[col]);
+ cb = GETJSAMPLE(inptr1[col]);
+ cr = GETJSAMPLE(inptr2[col]);
+ /* Range-limiting is essential due to noise introduced by DCT losses. */
+ outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */
+ outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */
+ ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
+ SCALEBITS)))];
+ outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */
+ /* K passes through unchanged */
+ outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */
+ outptr += 4;
+ }
+ }
+}
+
+
+/*
+ * Empty method for start_pass.
+ */
+
+METHODDEF(void)
+start_pass_dcolor (j_decompress_ptr cinfo)
+{
+ /* no work needed */
+}
+
+
+/*
+ * Module initialization routine for output colorspace conversion.
+ */
+
+GLOBAL(void)
+jinit_color_deconverter (j_decompress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert;
+ int ci;
+
+ cconvert = (my_cconvert_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_color_deconverter));
+ cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert;
+ cconvert->pub.start_pass = start_pass_dcolor;
+
+ /* Make sure num_components agrees with jpeg_color_space */
+ switch (cinfo->jpeg_color_space) {
+ case JCS_GRAYSCALE:
+ if (cinfo->num_components != 1)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ case JCS_RGB:
+ case JCS_YCbCr:
+ if (cinfo->num_components != 3)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ case JCS_CMYK:
+ case JCS_YCCK:
+ if (cinfo->num_components != 4)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ default: /* JCS_UNKNOWN can be anything */
+ if (cinfo->num_components < 1)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+ }
+
+ /* Set out_color_components and conversion method based on requested space.
+ * Also clear the component_needed flags for any unused components,
+ * so that earlier pipeline stages can avoid useless computation.
+ */
+
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ cinfo->out_color_components = 1;
+ if (cinfo->jpeg_color_space == JCS_GRAYSCALE ||
+ cinfo->jpeg_color_space == JCS_YCbCr) {
+ cconvert->pub.color_convert = grayscale_convert;
+ /* For color->grayscale conversion, only the Y (0) component is needed */
+ for (ci = 1; ci < cinfo->num_components; ci++)
+ cinfo->comp_info[ci].component_needed = FALSE;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_RGB:
+ cinfo->out_color_components = RGB_PIXELSIZE;
+ if (cinfo->jpeg_color_space == JCS_YCbCr) {
+ cconvert->pub.color_convert = ycc_rgb_convert;
+ build_ycc_rgb_table(cinfo);
+ } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
+ cconvert->pub.color_convert = gray_rgb_convert;
+ } else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) {
+ cconvert->pub.color_convert = null_convert;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_CMYK:
+ cinfo->out_color_components = 4;
+ if (cinfo->jpeg_color_space == JCS_YCCK) {
+ cconvert->pub.color_convert = ycck_cmyk_convert;
+ build_ycc_rgb_table(cinfo);
+ } else if (cinfo->jpeg_color_space == JCS_CMYK) {
+ cconvert->pub.color_convert = null_convert;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ default:
+ /* Permit null conversion to same output space */
+ if (cinfo->out_color_space == cinfo->jpeg_color_space) {
+ cinfo->out_color_components = cinfo->num_components;
+ cconvert->pub.color_convert = null_convert;
+ } else /* unsupported non-null conversion */
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+ }
+
+ if (cinfo->quantize_colors)
+ cinfo->output_components = 1; /* single colormapped output component */
+ else
+ cinfo->output_components = cinfo->out_color_components;
+}
diff --git a/external/jpeg-8c/jdct.h b/external/jpeg-8c/jdct.h
new file mode 100644
index 0000000..360dec8
--- /dev/null
+++ b/external/jpeg-8c/jdct.h
@@ -0,0 +1,393 @@
+/*
+ * jdct.h
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This include file contains common declarations for the forward and
+ * inverse DCT modules. These declarations are private to the DCT managers
+ * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms.
+ * The individual DCT algorithms are kept in separate files to ease
+ * machine-dependent tuning (e.g., assembly coding).
+ */
+
+
+/*
+ * A forward DCT routine is given a pointer to an input sample array and
+ * a pointer to a work area of type DCTELEM[]; the DCT is to be performed
+ * in-place in that buffer. Type DCTELEM is int for 8-bit samples, INT32
+ * for 12-bit samples. (NOTE: Floating-point DCT implementations use an
+ * array of type FAST_FLOAT, instead.)
+ * The input data is to be fetched from the sample array starting at a
+ * specified column. (Any row offset needed will be applied to the array
+ * pointer before it is passed to the FDCT code.)
+ * Note that the number of samples fetched by the FDCT routine is
+ * DCT_h_scaled_size * DCT_v_scaled_size.
+ * The DCT outputs are returned scaled up by a factor of 8; they therefore
+ * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This
+ * convention improves accuracy in integer implementations and saves some
+ * work in floating-point ones.
+ * Quantization of the output coefficients is done by jcdctmgr.c.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+typedef int DCTELEM; /* 16 or 32 bits is fine */
+#else
+typedef INT32 DCTELEM; /* must have 32 bits */
+#endif
+
+typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data,
+ JSAMPARRAY sample_data,
+ JDIMENSION start_col));
+typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data,
+ JSAMPARRAY sample_data,
+ JDIMENSION start_col));
+
+
+/*
+ * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer
+ * to an output sample array. The routine must dequantize the input data as
+ * well as perform the IDCT; for dequantization, it uses the multiplier table
+ * pointed to by compptr->dct_table. The output data is to be placed into the
+ * sample array starting at a specified column. (Any row offset needed will
+ * be applied to the array pointer before it is passed to the IDCT code.)
+ * Note that the number of samples emitted by the IDCT routine is
+ * DCT_h_scaled_size * DCT_v_scaled_size.
+ */
+
+/* typedef inverse_DCT_method_ptr is declared in jpegint.h */
+
+/*
+ * Each IDCT routine has its own ideas about the best dct_table element type.
+ */
+
+typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */
+#if BITS_IN_JSAMPLE == 8
+typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */
+#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */
+#else
+typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */
+#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */
+#endif
+typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
+
+
+/*
+ * Each IDCT routine is responsible for range-limiting its results and
+ * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could
+ * be quite far out of range if the input data is corrupt, so a bulletproof
+ * range-limiting step is required. We use a mask-and-table-lookup method
+ * to do the combined operations quickly. See the comments with
+ * prepare_range_limit_table (in jdmaster.c) for more info.
+ */
+
+#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE)
+
+#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_fdct_islow jFDislow
+#define jpeg_fdct_ifast jFDifast
+#define jpeg_fdct_float jFDfloat
+#define jpeg_fdct_7x7 jFD7x7
+#define jpeg_fdct_6x6 jFD6x6
+#define jpeg_fdct_5x5 jFD5x5
+#define jpeg_fdct_4x4 jFD4x4
+#define jpeg_fdct_3x3 jFD3x3
+#define jpeg_fdct_2x2 jFD2x2
+#define jpeg_fdct_1x1 jFD1x1
+#define jpeg_fdct_9x9 jFD9x9
+#define jpeg_fdct_10x10 jFD10x10
+#define jpeg_fdct_11x11 jFD11x11
+#define jpeg_fdct_12x12 jFD12x12
+#define jpeg_fdct_13x13 jFD13x13
+#define jpeg_fdct_14x14 jFD14x14
+#define jpeg_fdct_15x15 jFD15x15
+#define jpeg_fdct_16x16 jFD16x16
+#define jpeg_fdct_16x8 jFD16x8
+#define jpeg_fdct_14x7 jFD14x7
+#define jpeg_fdct_12x6 jFD12x6
+#define jpeg_fdct_10x5 jFD10x5
+#define jpeg_fdct_8x4 jFD8x4
+#define jpeg_fdct_6x3 jFD6x3
+#define jpeg_fdct_4x2 jFD4x2
+#define jpeg_fdct_2x1 jFD2x1
+#define jpeg_fdct_8x16 jFD8x16
+#define jpeg_fdct_7x14 jFD7x14
+#define jpeg_fdct_6x12 jFD6x12
+#define jpeg_fdct_5x10 jFD5x10
+#define jpeg_fdct_4x8 jFD4x8
+#define jpeg_fdct_3x6 jFD3x6
+#define jpeg_fdct_2x4 jFD2x4
+#define jpeg_fdct_1x2 jFD1x2
+#define jpeg_idct_islow jRDislow
+#define jpeg_idct_ifast jRDifast
+#define jpeg_idct_float jRDfloat
+#define jpeg_idct_7x7 jRD7x7
+#define jpeg_idct_6x6 jRD6x6
+#define jpeg_idct_5x5 jRD5x5
+#define jpeg_idct_4x4 jRD4x4
+#define jpeg_idct_3x3 jRD3x3
+#define jpeg_idct_2x2 jRD2x2
+#define jpeg_idct_1x1 jRD1x1
+#define jpeg_idct_9x9 jRD9x9
+#define jpeg_idct_10x10 jRD10x10
+#define jpeg_idct_11x11 jRD11x11
+#define jpeg_idct_12x12 jRD12x12
+#define jpeg_idct_13x13 jRD13x13
+#define jpeg_idct_14x14 jRD14x14
+#define jpeg_idct_15x15 jRD15x15
+#define jpeg_idct_16x16 jRD16x16
+#define jpeg_idct_16x8 jRD16x8
+#define jpeg_idct_14x7 jRD14x7
+#define jpeg_idct_12x6 jRD12x6
+#define jpeg_idct_10x5 jRD10x5
+#define jpeg_idct_8x4 jRD8x4
+#define jpeg_idct_6x3 jRD6x3
+#define jpeg_idct_4x2 jRD4x2
+#define jpeg_idct_2x1 jRD2x1
+#define jpeg_idct_8x16 jRD8x16
+#define jpeg_idct_7x14 jRD7x14
+#define jpeg_idct_6x12 jRD6x12
+#define jpeg_idct_5x10 jRD5x10
+#define jpeg_idct_4x8 jRD4x8
+#define jpeg_idct_3x6 jRD3x8
+#define jpeg_idct_2x4 jRD2x4
+#define jpeg_idct_1x2 jRD1x2
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+/* Extern declarations for the forward and inverse DCT routines. */
+
+EXTERN(void) jpeg_fdct_islow
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_ifast
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_float
+ JPP((FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_7x7
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_6x6
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_5x5
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_4x4
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_3x3
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_2x2
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_1x1
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_9x9
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_10x10
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_11x11
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_12x12
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_13x13
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_14x14
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_15x15
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_16x16
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_16x8
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_14x7
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_12x6
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_10x5
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_8x4
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_6x3
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_4x2
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_2x1
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_8x16
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_7x14
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_6x12
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_5x10
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_4x8
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_3x6
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_2x4
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_1x2
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+
+EXTERN(void) jpeg_idct_islow
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_ifast
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_float
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_7x7
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_6x6
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_5x5
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_4x4
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_3x3
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_2x2
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_1x1
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_9x9
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_10x10
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_11x11
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_12x12
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_13x13
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_14x14
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_15x15
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_16x16
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_16x8
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_14x7
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_12x6
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_10x5
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_8x4
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_6x3
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_4x2
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_2x1
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_8x16
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_7x14
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_6x12
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_5x10
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_4x8
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_3x6
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_2x4
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_1x2
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+
+
+/*
+ * Macros for handling fixed-point arithmetic; these are used by many
+ * but not all of the DCT/IDCT modules.
+ *
+ * All values are expected to be of type INT32.
+ * Fractional constants are scaled left by CONST_BITS bits.
+ * CONST_BITS is defined within each module using these macros,
+ * and may differ from one module to the next.
+ */
+
+#define ONE ((INT32) 1)
+#define CONST_SCALE (ONE << CONST_BITS)
+
+/* Convert a positive real constant to an integer scaled by CONST_SCALE.
+ * Caution: some C compilers fail to reduce "FIX(constant)" at compile time,
+ * thus causing a lot of useless floating-point operations at run time.
+ */
+
+#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5))
+
+/* Descale and correctly round an INT32 value that's scaled by N bits.
+ * We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+ * the fudge factor is correct for either sign of X.
+ */
+
+#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * This macro is used only when the two inputs will actually be no more than
+ * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a
+ * full 32x32 multiply. This provides a useful speedup on many machines.
+ * Unfortunately there is no way to specify a 16x16->32 multiply portably
+ * in C, but some C compilers will do the right thing if you provide the
+ * correct combination of casts.
+ */
+
+#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
+#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const)))
+#endif
+#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */
+#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const)))
+#endif
+
+#ifndef MULTIPLY16C16 /* default definition */
+#define MULTIPLY16C16(var,const) ((var) * (const))
+#endif
+
+/* Same except both inputs are variables. */
+
+#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
+#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2)))
+#endif
+
+#ifndef MULTIPLY16V16 /* default definition */
+#define MULTIPLY16V16(var1,var2) ((var1) * (var2))
+#endif
diff --git a/external/jpeg-8c/jddctmgr.c b/external/jpeg-8c/jddctmgr.c
new file mode 100644
index 0000000..0ded9d5
--- /dev/null
+++ b/external/jpeg-8c/jddctmgr.c
@@ -0,0 +1,384 @@
+/*
+ * jddctmgr.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2002-2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the inverse-DCT management logic.
+ * This code selects a particular IDCT implementation to be used,
+ * and it performs related housekeeping chores. No code in this file
+ * is executed per IDCT step, only during output pass setup.
+ *
+ * Note that the IDCT routines are responsible for performing coefficient
+ * dequantization as well as the IDCT proper. This module sets up the
+ * dequantization multiplier table needed by the IDCT routine.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+
+/*
+ * The decompressor input side (jdinput.c) saves away the appropriate
+ * quantization table for each component at the start of the first scan
+ * involving that component. (This is necessary in order to correctly
+ * decode files that reuse Q-table slots.)
+ * When we are ready to make an output pass, the saved Q-table is converted
+ * to a multiplier table that will actually be used by the IDCT routine.
+ * The multiplier table contents are IDCT-method-dependent. To support
+ * application changes in IDCT method between scans, we can remake the
+ * multiplier tables if necessary.
+ * In buffered-image mode, the first output pass may occur before any data
+ * has been seen for some components, and thus before their Q-tables have
+ * been saved away. To handle this case, multiplier tables are preset
+ * to zeroes; the result of the IDCT will be a neutral gray level.
+ */
+
+
+/* Private subobject for this module */
+
+typedef struct {
+ struct jpeg_inverse_dct pub; /* public fields */
+
+ /* This array contains the IDCT method code that each multiplier table
+ * is currently set up for, or -1 if it's not yet set up.
+ * The actual multiplier tables are pointed to by dct_table in the
+ * per-component comp_info structures.
+ */
+ int cur_method[MAX_COMPONENTS];
+} my_idct_controller;
+
+typedef my_idct_controller * my_idct_ptr;
+
+
+/* Allocated multiplier tables: big enough for any supported variant */
+
+typedef union {
+ ISLOW_MULT_TYPE islow_array[DCTSIZE2];
+#ifdef DCT_IFAST_SUPPORTED
+ IFAST_MULT_TYPE ifast_array[DCTSIZE2];
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ FLOAT_MULT_TYPE float_array[DCTSIZE2];
+#endif
+} multiplier_table;
+
+
+/* The current scaled-IDCT routines require ISLOW-style multiplier tables,
+ * so be sure to compile that code if either ISLOW or SCALING is requested.
+ */
+#ifdef DCT_ISLOW_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#else
+#ifdef IDCT_SCALING_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#endif
+#endif
+
+
+/*
+ * Prepare for an output pass.
+ * Here we select the proper IDCT routine for each component and build
+ * a matching multiplier table.
+ */
+
+METHODDEF(void)
+start_pass (j_decompress_ptr cinfo)
+{
+ my_idct_ptr idct = (my_idct_ptr) cinfo->idct;
+ int ci, i;
+ jpeg_component_info *compptr;
+ int method = 0;
+ inverse_DCT_method_ptr method_ptr = NULL;
+ JQUANT_TBL * qtbl;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Select the proper IDCT routine for this component's scaling */
+ switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) {
+#ifdef IDCT_SCALING_SUPPORTED
+ case ((1 << 8) + 1):
+ method_ptr = jpeg_idct_1x1;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((2 << 8) + 2):
+ method_ptr = jpeg_idct_2x2;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((3 << 8) + 3):
+ method_ptr = jpeg_idct_3x3;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((4 << 8) + 4):
+ method_ptr = jpeg_idct_4x4;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((5 << 8) + 5):
+ method_ptr = jpeg_idct_5x5;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((6 << 8) + 6):
+ method_ptr = jpeg_idct_6x6;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((7 << 8) + 7):
+ method_ptr = jpeg_idct_7x7;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((9 << 8) + 9):
+ method_ptr = jpeg_idct_9x9;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((10 << 8) + 10):
+ method_ptr = jpeg_idct_10x10;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((11 << 8) + 11):
+ method_ptr = jpeg_idct_11x11;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((12 << 8) + 12):
+ method_ptr = jpeg_idct_12x12;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((13 << 8) + 13):
+ method_ptr = jpeg_idct_13x13;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((14 << 8) + 14):
+ method_ptr = jpeg_idct_14x14;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((15 << 8) + 15):
+ method_ptr = jpeg_idct_15x15;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((16 << 8) + 16):
+ method_ptr = jpeg_idct_16x16;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((16 << 8) + 8):
+ method_ptr = jpeg_idct_16x8;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((14 << 8) + 7):
+ method_ptr = jpeg_idct_14x7;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((12 << 8) + 6):
+ method_ptr = jpeg_idct_12x6;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((10 << 8) + 5):
+ method_ptr = jpeg_idct_10x5;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((8 << 8) + 4):
+ method_ptr = jpeg_idct_8x4;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((6 << 8) + 3):
+ method_ptr = jpeg_idct_6x3;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((4 << 8) + 2):
+ method_ptr = jpeg_idct_4x2;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((2 << 8) + 1):
+ method_ptr = jpeg_idct_2x1;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((8 << 8) + 16):
+ method_ptr = jpeg_idct_8x16;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((7 << 8) + 14):
+ method_ptr = jpeg_idct_7x14;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((6 << 8) + 12):
+ method_ptr = jpeg_idct_6x12;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((5 << 8) + 10):
+ method_ptr = jpeg_idct_5x10;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((4 << 8) + 8):
+ method_ptr = jpeg_idct_4x8;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((3 << 8) + 6):
+ method_ptr = jpeg_idct_3x6;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((2 << 8) + 4):
+ method_ptr = jpeg_idct_2x4;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((1 << 8) + 2):
+ method_ptr = jpeg_idct_1x2;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+#endif
+ case ((DCTSIZE << 8) + DCTSIZE):
+ switch (cinfo->dct_method) {
+#ifdef DCT_ISLOW_SUPPORTED
+ case JDCT_ISLOW:
+ method_ptr = jpeg_idct_islow;
+ method = JDCT_ISLOW;
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ method_ptr = jpeg_idct_ifast;
+ method = JDCT_IFAST;
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ method_ptr = jpeg_idct_float;
+ method = JDCT_FLOAT;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ break;
+ default:
+ ERREXIT2(cinfo, JERR_BAD_DCTSIZE,
+ compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size);
+ break;
+ }
+ idct->pub.inverse_DCT[ci] = method_ptr;
+ /* Create multiplier table from quant table.
+ * However, we can skip this if the component is uninteresting
+ * or if we already built the table. Also, if no quant table
+ * has yet been saved for the component, we leave the
+ * multiplier table all-zero; we'll be reading zeroes from the
+ * coefficient controller's buffer anyway.
+ */
+ if (! compptr->component_needed || idct->cur_method[ci] == method)
+ continue;
+ qtbl = compptr->quant_table;
+ if (qtbl == NULL) /* happens if no data yet for component */
+ continue;
+ idct->cur_method[ci] = method;
+ switch (method) {
+#ifdef PROVIDE_ISLOW_TABLES
+ case JDCT_ISLOW:
+ {
+ /* For LL&M IDCT method, multipliers are equal to raw quantization
+ * coefficients, but are stored as ints to ensure access efficiency.
+ */
+ ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ for (i = 0; i < DCTSIZE2; i++) {
+ ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i];
+ }
+ }
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ {
+ /* For AA&N IDCT method, multipliers are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * For integer operation, the multiplier table is to be scaled by
+ * IFAST_SCALE_BITS.
+ */
+ IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table;
+#define CONST_BITS 14
+ static const INT16 aanscales[DCTSIZE2] = {
+ /* precomputed values scaled up by 14 bits */
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
+ 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
+ 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
+ 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
+ 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
+ };
+ SHIFT_TEMPS
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ ifmtbl[i] = (IFAST_MULT_TYPE)
+ DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
+ (INT32) aanscales[i]),
+ CONST_BITS-IFAST_SCALE_BITS);
+ }
+ }
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ {
+ /* For float AA&N IDCT method, multipliers are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * We apply a further scale factor of 1/8.
+ */
+ FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table;
+ int row, col;
+ static const double aanscalefactor[DCTSIZE] = {
+ 1.0, 1.387039845, 1.306562965, 1.175875602,
+ 1.0, 0.785694958, 0.541196100, 0.275899379
+ };
+
+ i = 0;
+ for (row = 0; row < DCTSIZE; row++) {
+ for (col = 0; col < DCTSIZE; col++) {
+ fmtbl[i] = (FLOAT_MULT_TYPE)
+ ((double) qtbl->quantval[i] *
+ aanscalefactor[row] * aanscalefactor[col] * 0.125);
+ i++;
+ }
+ }
+ }
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ }
+}
+
+
+/*
+ * Initialize IDCT manager.
+ */
+
+GLOBAL(void)
+jinit_inverse_dct (j_decompress_ptr cinfo)
+{
+ my_idct_ptr idct;
+ int ci;
+ jpeg_component_info *compptr;
+
+ idct = (my_idct_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_idct_controller));
+ cinfo->idct = (struct jpeg_inverse_dct *) idct;
+ idct->pub.start_pass = start_pass;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Allocate and pre-zero a multiplier table for each component */
+ compptr->dct_table =
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(multiplier_table));
+ MEMZERO(compptr->dct_table, SIZEOF(multiplier_table));
+ /* Mark multiplier table not yet set up for any method */
+ idct->cur_method[ci] = -1;
+ }
+}
diff --git a/external/jpeg-8c/jdhuff.c b/external/jpeg-8c/jdhuff.c
new file mode 100644
index 0000000..06f92fe
--- /dev/null
+++ b/external/jpeg-8c/jdhuff.c
@@ -0,0 +1,1541 @@
+/*
+ * jdhuff.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2006-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains Huffman entropy decoding routines.
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Much of the complexity here has to do with supporting input suspension.
+ * If the data source module demands suspension, we want to be able to back
+ * up to the start of the current MCU. To do this, we copy state variables
+ * into local working storage, and update them back to the permanent
+ * storage only upon successful completion of an MCU.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Derived data constructed for each Huffman table */
+
+#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */
+
+typedef struct {
+ /* Basic tables: (element [0] of each array is unused) */
+ INT32 maxcode[18]; /* largest code of length k (-1 if none) */
+ /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */
+ INT32 valoffset[17]; /* huffval[] offset for codes of length k */
+ /* valoffset[k] = huffval[] index of 1st symbol of code length k, less
+ * the smallest code of length k; so given a code of length k, the
+ * corresponding symbol is huffval[code + valoffset[k]]
+ */
+
+ /* Link to public Huffman table (needed only in jpeg_huff_decode) */
+ JHUFF_TBL *pub;
+
+ /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of
+ * the input data stream. If the next Huffman code is no more
+ * than HUFF_LOOKAHEAD bits long, we can obtain its length and
+ * the corresponding symbol directly from these tables.
+ */
+ int look_nbits[1<<HUFF_LOOKAHEAD]; /* # bits, or 0 if too long */
+ UINT8 look_sym[1<<HUFF_LOOKAHEAD]; /* symbol, or unused */
+} d_derived_tbl;
+
+
+/*
+ * Fetching the next N bits from the input stream is a time-critical operation
+ * for the Huffman decoders. We implement it with a combination of inline
+ * macros and out-of-line subroutines. Note that N (the number of bits
+ * demanded at one time) never exceeds 15 for JPEG use.
+ *
+ * We read source bytes into get_buffer and dole out bits as needed.
+ * If get_buffer already contains enough bits, they are fetched in-line
+ * by the macros CHECK_BIT_BUFFER and GET_BITS. When there aren't enough
+ * bits, jpeg_fill_bit_buffer is called; it will attempt to fill get_buffer
+ * as full as possible (not just to the number of bits needed; this
+ * prefetching reduces the overhead cost of calling jpeg_fill_bit_buffer).
+ * Note that jpeg_fill_bit_buffer may return FALSE to indicate suspension.
+ * On TRUE return, jpeg_fill_bit_buffer guarantees that get_buffer contains
+ * at least the requested number of bits --- dummy zeroes are inserted if
+ * necessary.
+ */
+
+typedef INT32 bit_buf_type; /* type of bit-extraction buffer */
+#define BIT_BUF_SIZE 32 /* size of buffer in bits */
+
+/* If long is > 32 bits on your machine, and shifting/masking longs is
+ * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE
+ * appropriately should be a win. Unfortunately we can't define the size
+ * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8)
+ * because not all machines measure sizeof in 8-bit bytes.
+ */
+
+typedef struct { /* Bitreading state saved across MCUs */
+ bit_buf_type get_buffer; /* current bit-extraction buffer */
+ int bits_left; /* # of unused bits in it */
+} bitread_perm_state;
+
+typedef struct { /* Bitreading working state within an MCU */
+ /* Current data source location */
+ /* We need a copy, rather than munging the original, in case of suspension */
+ const JOCTET * next_input_byte; /* => next byte to read from source */
+ size_t bytes_in_buffer; /* # of bytes remaining in source buffer */
+ /* Bit input buffer --- note these values are kept in register variables,
+ * not in this struct, inside the inner loops.
+ */
+ bit_buf_type get_buffer; /* current bit-extraction buffer */
+ int bits_left; /* # of unused bits in it */
+ /* Pointer needed by jpeg_fill_bit_buffer. */
+ j_decompress_ptr cinfo; /* back link to decompress master record */
+} bitread_working_state;
+
+/* Macros to declare and load/save bitread local variables. */
+#define BITREAD_STATE_VARS \
+ register bit_buf_type get_buffer; \
+ register int bits_left; \
+ bitread_working_state br_state
+
+#define BITREAD_LOAD_STATE(cinfop,permstate) \
+ br_state.cinfo = cinfop; \
+ br_state.next_input_byte = cinfop->src->next_input_byte; \
+ br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \
+ get_buffer = permstate.get_buffer; \
+ bits_left = permstate.bits_left;
+
+#define BITREAD_SAVE_STATE(cinfop,permstate) \
+ cinfop->src->next_input_byte = br_state.next_input_byte; \
+ cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \
+ permstate.get_buffer = get_buffer; \
+ permstate.bits_left = bits_left
+
+/*
+ * These macros provide the in-line portion of bit fetching.
+ * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer
+ * before using GET_BITS, PEEK_BITS, or DROP_BITS.
+ * The variables get_buffer and bits_left are assumed to be locals,
+ * but the state struct might not be (jpeg_huff_decode needs this).
+ * CHECK_BIT_BUFFER(state,n,action);
+ * Ensure there are N bits in get_buffer; if suspend, take action.
+ * val = GET_BITS(n);
+ * Fetch next N bits.
+ * val = PEEK_BITS(n);
+ * Fetch next N bits without removing them from the buffer.
+ * DROP_BITS(n);
+ * Discard next N bits.
+ * The value N should be a simple variable, not an expression, because it
+ * is evaluated multiple times.
+ */
+
+#define CHECK_BIT_BUFFER(state,nbits,action) \
+ { if (bits_left < (nbits)) { \
+ if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \
+ { action; } \
+ get_buffer = (state).get_buffer; bits_left = (state).bits_left; } }
+
+#define GET_BITS(nbits) \
+ (((int) (get_buffer >> (bits_left -= (nbits)))) & BIT_MASK(nbits))
+
+#define PEEK_BITS(nbits) \
+ (((int) (get_buffer >> (bits_left - (nbits)))) & BIT_MASK(nbits))
+
+#define DROP_BITS(nbits) \
+ (bits_left -= (nbits))
+
+
+/*
+ * Code for extracting next Huffman-coded symbol from input bit stream.
+ * Again, this is time-critical and we make the main paths be macros.
+ *
+ * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits
+ * without looping. Usually, more than 95% of the Huffman codes will be 8
+ * or fewer bits long. The few overlength codes are handled with a loop,
+ * which need not be inline code.
+ *
+ * Notes about the HUFF_DECODE macro:
+ * 1. Near the end of the data segment, we may fail to get enough bits
+ * for a lookahead. In that case, we do it the hard way.
+ * 2. If the lookahead table contains no entry, the next code must be
+ * more than HUFF_LOOKAHEAD bits long.
+ * 3. jpeg_huff_decode returns -1 if forced to suspend.
+ */
+
+#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \
+{ register int nb, look; \
+ if (bits_left < HUFF_LOOKAHEAD) { \
+ if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \
+ get_buffer = state.get_buffer; bits_left = state.bits_left; \
+ if (bits_left < HUFF_LOOKAHEAD) { \
+ nb = 1; goto slowlabel; \
+ } \
+ } \
+ look = PEEK_BITS(HUFF_LOOKAHEAD); \
+ if ((nb = htbl->look_nbits[look]) != 0) { \
+ DROP_BITS(nb); \
+ result = htbl->look_sym[look]; \
+ } else { \
+ nb = HUFF_LOOKAHEAD+1; \
+slowlabel: \
+ if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \
+ { failaction; } \
+ get_buffer = state.get_buffer; bits_left = state.bits_left; \
+ } \
+}
+
+
+/*
+ * Expanded entropy decoder object for Huffman decoding.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+ unsigned int EOBRUN; /* remaining EOBs in EOBRUN */
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+} savable_state;
+
+/* This macro is to work around compilers with missing or broken
+ * structure assignment. You'll need to fix this code if you have
+ * such a compiler and you change MAX_COMPS_IN_SCAN.
+ */
+
+#ifndef NO_STRUCT_ASSIGN
+#define ASSIGN_STATE(dest,src) ((dest) = (src))
+#else
+#if MAX_COMPS_IN_SCAN == 4
+#define ASSIGN_STATE(dest,src) \
+ ((dest).EOBRUN = (src).EOBRUN, \
+ (dest).last_dc_val[0] = (src).last_dc_val[0], \
+ (dest).last_dc_val[1] = (src).last_dc_val[1], \
+ (dest).last_dc_val[2] = (src).last_dc_val[2], \
+ (dest).last_dc_val[3] = (src).last_dc_val[3])
+#endif
+#endif
+
+
+typedef struct {
+ struct jpeg_entropy_decoder pub; /* public fields */
+
+ /* These fields are loaded into local variables at start of each MCU.
+ * In case of suspension, we exit WITHOUT updating them.
+ */
+ bitread_perm_state bitstate; /* Bit buffer at start of MCU */
+ savable_state saved; /* Other state at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ boolean insufficient_data; /* set TRUE after emitting warning */
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+
+ /* Following two fields used only in progressive mode */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ d_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
+
+ d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */
+
+ /* Following fields used only in sequential mode */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
+ d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
+
+ /* Precalculated info set up by start_pass for use in decode_mcu: */
+
+ /* Pointers to derived tables to be used for each block within an MCU */
+ d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU];
+ d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU];
+ /* Whether we care about the DC and AC coefficient values for each block */
+ int coef_limit[D_MAX_BLOCKS_IN_MCU];
+} huff_entropy_decoder;
+
+typedef huff_entropy_decoder * huff_entropy_ptr;
+
+
+static const int jpeg_zigzag_order[8][8] = {
+ { 0, 1, 5, 6, 14, 15, 27, 28 },
+ { 2, 4, 7, 13, 16, 26, 29, 42 },
+ { 3, 8, 12, 17, 25, 30, 41, 43 },
+ { 9, 11, 18, 24, 31, 40, 44, 53 },
+ { 10, 19, 23, 32, 39, 45, 52, 54 },
+ { 20, 22, 33, 38, 46, 51, 55, 60 },
+ { 21, 34, 37, 47, 50, 56, 59, 61 },
+ { 35, 36, 48, 49, 57, 58, 62, 63 }
+};
+
+static const int jpeg_zigzag_order7[7][7] = {
+ { 0, 1, 5, 6, 14, 15, 27 },
+ { 2, 4, 7, 13, 16, 26, 28 },
+ { 3, 8, 12, 17, 25, 29, 38 },
+ { 9, 11, 18, 24, 30, 37, 39 },
+ { 10, 19, 23, 31, 36, 40, 45 },
+ { 20, 22, 32, 35, 41, 44, 46 },
+ { 21, 33, 34, 42, 43, 47, 48 }
+};
+
+static const int jpeg_zigzag_order6[6][6] = {
+ { 0, 1, 5, 6, 14, 15 },
+ { 2, 4, 7, 13, 16, 25 },
+ { 3, 8, 12, 17, 24, 26 },
+ { 9, 11, 18, 23, 27, 32 },
+ { 10, 19, 22, 28, 31, 33 },
+ { 20, 21, 29, 30, 34, 35 }
+};
+
+static const int jpeg_zigzag_order5[5][5] = {
+ { 0, 1, 5, 6, 14 },
+ { 2, 4, 7, 13, 15 },
+ { 3, 8, 12, 16, 21 },
+ { 9, 11, 17, 20, 22 },
+ { 10, 18, 19, 23, 24 }
+};
+
+static const int jpeg_zigzag_order4[4][4] = {
+ { 0, 1, 5, 6 },
+ { 2, 4, 7, 12 },
+ { 3, 8, 11, 13 },
+ { 9, 10, 14, 15 }
+};
+
+static const int jpeg_zigzag_order3[3][3] = {
+ { 0, 1, 5 },
+ { 2, 4, 6 },
+ { 3, 7, 8 }
+};
+
+static const int jpeg_zigzag_order2[2][2] = {
+ { 0, 1 },
+ { 2, 3 }
+};
+
+
+/*
+ * Compute the derived values for a Huffman table.
+ * This routine also performs some validation checks on the table.
+ */
+
+LOCAL(void)
+jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
+ d_derived_tbl ** pdtbl)
+{
+ JHUFF_TBL *htbl;
+ d_derived_tbl *dtbl;
+ int p, i, l, si, numsymbols;
+ int lookbits, ctr;
+ char huffsize[257];
+ unsigned int huffcode[257];
+ unsigned int code;
+
+ /* Note that huffsize[] and huffcode[] are filled in code-length order,
+ * paralleling the order of the symbols themselves in htbl->huffval[].
+ */
+
+ /* Find the input Huffman table */
+ if (tblno < 0 || tblno >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+ htbl =
+ isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno];
+ if (htbl == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+
+ /* Allocate a workspace if we haven't already done so. */
+ if (*pdtbl == NULL)
+ *pdtbl = (d_derived_tbl *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(d_derived_tbl));
+ dtbl = *pdtbl;
+ dtbl->pub = htbl; /* fill in back link */
+
+ /* Figure C.1: make table of Huffman code length for each symbol */
+
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ i = (int) htbl->bits[l];
+ if (i < 0 || p + i > 256) /* protect against table overrun */
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ while (i--)
+ huffsize[p++] = (char) l;
+ }
+ huffsize[p] = 0;
+ numsymbols = p;
+
+ /* Figure C.2: generate the codes themselves */
+ /* We also validate that the counts represent a legal Huffman code tree. */
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while (huffsize[p]) {
+ while (((int) huffsize[p]) == si) {
+ huffcode[p++] = code;
+ code++;
+ }
+ /* code is now 1 more than the last code used for codelength si; but
+ * it must still fit in si bits, since no code is allowed to be all ones.
+ */
+ if (((INT32) code) >= (((INT32) 1) << si))
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ code <<= 1;
+ si++;
+ }
+
+ /* Figure F.15: generate decoding tables for bit-sequential decoding */
+
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ if (htbl->bits[l]) {
+ /* valoffset[l] = huffval[] index of 1st symbol of code length l,
+ * minus the minimum code of length l
+ */
+ dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p];
+ p += htbl->bits[l];
+ dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */
+ } else {
+ dtbl->maxcode[l] = -1; /* -1 if no codes of this length */
+ }
+ }
+ dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */
+
+ /* Compute lookahead tables to speed up decoding.
+ * First we set all the table entries to 0, indicating "too long";
+ * then we iterate through the Huffman codes that are short enough and
+ * fill in all the entries that correspond to bit sequences starting
+ * with that code.
+ */
+
+ MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits));
+
+ p = 0;
+ for (l = 1; l <= HUFF_LOOKAHEAD; l++) {
+ for (i = 1; i <= (int) htbl->bits[l]; i++, p++) {
+ /* l = current code's length, p = its index in huffcode[] & huffval[]. */
+ /* Generate left-justified code followed by all possible bit sequences */
+ lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l);
+ for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) {
+ dtbl->look_nbits[lookbits] = l;
+ dtbl->look_sym[lookbits] = htbl->huffval[p];
+ lookbits++;
+ }
+ }
+ }
+
+ /* Validate symbols as being reasonable.
+ * For AC tables, we make no check, but accept all byte values 0..255.
+ * For DC tables, we require the symbols to be in range 0..15.
+ * (Tighter bounds could be applied depending on the data depth and mode,
+ * but this is sufficient to ensure safe decoding.)
+ */
+ if (isDC) {
+ for (i = 0; i < numsymbols; i++) {
+ int sym = htbl->huffval[i];
+ if (sym < 0 || sym > 15)
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ }
+ }
+}
+
+
+/*
+ * Out-of-line code for bit fetching.
+ * Note: current values of get_buffer and bits_left are passed as parameters,
+ * but are returned in the corresponding fields of the state struct.
+ *
+ * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width
+ * of get_buffer to be used. (On machines with wider words, an even larger
+ * buffer could be used.) However, on some machines 32-bit shifts are
+ * quite slow and take time proportional to the number of places shifted.
+ * (This is true with most PC compilers, for instance.) In this case it may
+ * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the
+ * average shift distance at the cost of more calls to jpeg_fill_bit_buffer.
+ */
+
+#ifdef SLOW_SHIFT_32
+#define MIN_GET_BITS 15 /* minimum allowable value */
+#else
+#define MIN_GET_BITS (BIT_BUF_SIZE-7)
+#endif
+
+
+LOCAL(boolean)
+jpeg_fill_bit_buffer (bitread_working_state * state,
+ register bit_buf_type get_buffer, register int bits_left,
+ int nbits)
+/* Load up the bit buffer to a depth of at least nbits */
+{
+ /* Copy heavily used state fields into locals (hopefully registers) */
+ register const JOCTET * next_input_byte = state->next_input_byte;
+ register size_t bytes_in_buffer = state->bytes_in_buffer;
+ j_decompress_ptr cinfo = state->cinfo;
+
+ /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */
+ /* (It is assumed that no request will be for more than that many bits.) */
+ /* We fail to do so only if we hit a marker or are forced to suspend. */
+
+ if (cinfo->unread_marker == 0) { /* cannot advance past a marker */
+ while (bits_left < MIN_GET_BITS) {
+ register int c;
+
+ /* Attempt to read a byte */
+ if (bytes_in_buffer == 0) {
+ if (! (*cinfo->src->fill_input_buffer) (cinfo))
+ return FALSE;
+ next_input_byte = cinfo->src->next_input_byte;
+ bytes_in_buffer = cinfo->src->bytes_in_buffer;
+ }
+ bytes_in_buffer--;
+ c = GETJOCTET(*next_input_byte++);
+
+ /* If it's 0xFF, check and discard stuffed zero byte */
+ if (c == 0xFF) {
+ /* Loop here to discard any padding FF's on terminating marker,
+ * so that we can save a valid unread_marker value. NOTE: we will
+ * accept multiple FF's followed by a 0 as meaning a single FF data
+ * byte. This data pattern is not valid according to the standard.
+ */
+ do {
+ if (bytes_in_buffer == 0) {
+ if (! (*cinfo->src->fill_input_buffer) (cinfo))
+ return FALSE;
+ next_input_byte = cinfo->src->next_input_byte;
+ bytes_in_buffer = cinfo->src->bytes_in_buffer;
+ }
+ bytes_in_buffer--;
+ c = GETJOCTET(*next_input_byte++);
+ } while (c == 0xFF);
+
+ if (c == 0) {
+ /* Found FF/00, which represents an FF data byte */
+ c = 0xFF;
+ } else {
+ /* Oops, it's actually a marker indicating end of compressed data.
+ * Save the marker code for later use.
+ * Fine point: it might appear that we should save the marker into
+ * bitread working state, not straight into permanent state. But
+ * once we have hit a marker, we cannot need to suspend within the
+ * current MCU, because we will read no more bytes from the data
+ * source. So it is OK to update permanent state right away.
+ */
+ cinfo->unread_marker = c;
+ /* See if we need to insert some fake zero bits. */
+ goto no_more_bytes;
+ }
+ }
+
+ /* OK, load c into get_buffer */
+ get_buffer = (get_buffer << 8) | c;
+ bits_left += 8;
+ } /* end while */
+ } else {
+ no_more_bytes:
+ /* We get here if we've read the marker that terminates the compressed
+ * data segment. There should be enough bits in the buffer register
+ * to satisfy the request; if so, no problem.
+ */
+ if (nbits > bits_left) {
+ /* Uh-oh. Report corrupted data to user and stuff zeroes into
+ * the data stream, so that we can produce some kind of image.
+ * We use a nonvolatile flag to ensure that only one warning message
+ * appears per data segment.
+ */
+ if (! ((huff_entropy_ptr) cinfo->entropy)->insufficient_data) {
+ WARNMS(cinfo, JWRN_HIT_MARKER);
+ ((huff_entropy_ptr) cinfo->entropy)->insufficient_data = TRUE;
+ }
+ /* Fill the buffer with zero bits */
+ get_buffer <<= MIN_GET_BITS - bits_left;
+ bits_left = MIN_GET_BITS;
+ }
+ }
+
+ /* Unload the local registers */
+ state->next_input_byte = next_input_byte;
+ state->bytes_in_buffer = bytes_in_buffer;
+ state->get_buffer = get_buffer;
+ state->bits_left = bits_left;
+
+ return TRUE;
+}
+
+
+/*
+ * Figure F.12: extend sign bit.
+ * On some machines, a shift and sub will be faster than a table lookup.
+ */
+
+#ifdef AVOID_TABLES
+
+#define BIT_MASK(nbits) ((1<<(nbits))-1)
+#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) - ((1<<(s))-1) : (x))
+
+#else
+
+#define BIT_MASK(nbits) bmask[nbits]
+#define HUFF_EXTEND(x,s) ((x) <= bmask[(s) - 1] ? (x) - bmask[s] : (x))
+
+static const int bmask[16] = /* bmask[n] is mask for n rightmost bits */
+ { 0, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
+ 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF };
+
+#endif /* AVOID_TABLES */
+
+
+/*
+ * Out-of-line code for Huffman code decoding.
+ */
+
+LOCAL(int)
+jpeg_huff_decode (bitread_working_state * state,
+ register bit_buf_type get_buffer, register int bits_left,
+ d_derived_tbl * htbl, int min_bits)
+{
+ register int l = min_bits;
+ register INT32 code;
+
+ /* HUFF_DECODE has determined that the code is at least min_bits */
+ /* bits long, so fetch that many bits in one swoop. */
+
+ CHECK_BIT_BUFFER(*state, l, return -1);
+ code = GET_BITS(l);
+
+ /* Collect the rest of the Huffman code one bit at a time. */
+ /* This is per Figure F.16 in the JPEG spec. */
+
+ while (code > htbl->maxcode[l]) {
+ code <<= 1;
+ CHECK_BIT_BUFFER(*state, 1, return -1);
+ code |= GET_BITS(1);
+ l++;
+ }
+
+ /* Unload the local registers */
+ state->get_buffer = get_buffer;
+ state->bits_left = bits_left;
+
+ /* With garbage input we may reach the sentinel value l = 17. */
+
+ if (l > 16) {
+ WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE);
+ return 0; /* fake a zero as the safest result */
+ }
+
+ return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ];
+}
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ * Returns FALSE if must suspend.
+ */
+
+LOCAL(boolean)
+process_restart (j_decompress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci;
+
+ /* Throw away any unused bits remaining in bit buffer; */
+ /* include any full bytes in next_marker's count of discarded bytes */
+ cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
+ entropy->bitstate.bits_left = 0;
+
+ /* Advance past the RSTn marker */
+ if (! (*cinfo->marker->read_restart_marker) (cinfo))
+ return FALSE;
+
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++)
+ entropy->saved.last_dc_val[ci] = 0;
+ /* Re-init EOB run count, too */
+ entropy->saved.EOBRUN = 0;
+
+ /* Reset restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+
+ /* Reset out-of-data flag, unless read_restart_marker left us smack up
+ * against a marker. In that case we will end up treating the next data
+ * segment as empty, and we can avoid producing bogus output pixels by
+ * leaving the flag set.
+ */
+ if (cinfo->unread_marker == 0)
+ entropy->insufficient_data = FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Huffman MCU decoding.
+ * Each of these routines decodes and returns one MCU's worth of
+ * Huffman-compressed coefficients.
+ * The coefficients are reordered from zigzag order into natural array order,
+ * but are not dequantized.
+ *
+ * The i'th block of the MCU is stored into the block pointed to by
+ * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
+ * (Wholesale zeroing is usually a little faster than retail...)
+ *
+ * We return FALSE if data source requested suspension. In that case no
+ * changes have been made to permanent state. (Exception: some output
+ * coefficients may already have been assigned. This is harmless for
+ * spectral selection, since we'll just re-assign them on the next call.
+ * Successive approximation AC refinement has to be more careful, however.)
+ */
+
+/*
+ * MCU decoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int Al = cinfo->Al;
+ register int s, r;
+ int blkn, ci;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+ savable_state state;
+ d_derived_tbl * tbl;
+ jpeg_component_info * compptr;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy->insufficient_data) {
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(state, entropy->saved);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ tbl = entropy->derived_tbls[compptr->dc_tbl_no];
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+ HUFF_DECODE(s, br_state, tbl, return FALSE, label1);
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+
+ /* Convert DC difference to actual value, update last_dc_val */
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */
+ (*block)[0] = (JCOEF) (s << Al);
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(entropy->saved, state);
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int s, k, r;
+ unsigned int EOBRUN;
+ int Se, Al;
+ const int * natural_order;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+ d_derived_tbl * tbl;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy->insufficient_data) {
+
+ Se = cinfo->Se;
+ Al = cinfo->Al;
+ natural_order = cinfo->natural_order;
+
+ /* Load up working state.
+ * We can avoid loading/saving bitread state if in an EOB run.
+ */
+ EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */
+
+ /* There is always only one block per MCU */
+
+ if (EOBRUN > 0) /* if it's a band of zeroes... */
+ EOBRUN--; /* ...process it now (we do nothing) */
+ else {
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ block = MCU_data[0];
+ tbl = entropy->ac_derived_tbl;
+
+ for (k = cinfo->Ss; k <= Se; k++) {
+ HUFF_DECODE(s, br_state, tbl, return FALSE, label2);
+ r = s >> 4;
+ s &= 15;
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ /* Scale and output coefficient in natural (dezigzagged) order */
+ (*block)[natural_order[k]] = (JCOEF) (s << Al);
+ } else {
+ if (r == 15) { /* ZRL */
+ k += 15; /* skip 15 zeroes in band */
+ } else { /* EOBr, run length is 2^r + appended bits */
+ EOBRUN = 1 << r;
+ if (r) { /* EOBr, r > 0 */
+ CHECK_BIT_BUFFER(br_state, r, return FALSE);
+ r = GET_BITS(r);
+ EOBRUN += r;
+ }
+ EOBRUN--; /* this band is processed at this moment */
+ break; /* force end-of-band */
+ }
+ }
+ }
+
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ }
+
+ /* Completed MCU, so update state */
+ entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for DC successive approximation refinement scan.
+ * Note: we assume such scans can be multi-component, although the spec
+ * is not very clear on the point.
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+ int blkn;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* Not worth the cycles to check insufficient_data here,
+ * since we will not change the data anyway if we read zeroes.
+ */
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+
+ /* Encoded data is simply the next bit of the two's-complement DC value */
+ CHECK_BIT_BUFFER(br_state, 1, return FALSE);
+ if (GET_BITS(1))
+ (*block)[0] |= p1;
+ /* Note: since we use |=, repeating the assignment later is safe */
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int s, k, r;
+ unsigned int EOBRUN;
+ int Se, p1, m1;
+ const int * natural_order;
+ JBLOCKROW block;
+ JCOEFPTR thiscoef;
+ BITREAD_STATE_VARS;
+ d_derived_tbl * tbl;
+ int num_newnz;
+ int newnz_pos[DCTSIZE2];
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, don't modify the MCU.
+ */
+ if (! entropy->insufficient_data) {
+
+ Se = cinfo->Se;
+ p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+ m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */
+ natural_order = cinfo->natural_order;
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */
+
+ /* There is always only one block per MCU */
+ block = MCU_data[0];
+ tbl = entropy->ac_derived_tbl;
+
+ /* If we are forced to suspend, we must undo the assignments to any newly
+ * nonzero coefficients in the block, because otherwise we'd get confused
+ * next time about which coefficients were already nonzero.
+ * But we need not undo addition of bits to already-nonzero coefficients;
+ * instead, we can test the current bit to see if we already did it.
+ */
+ num_newnz = 0;
+
+ /* initialize coefficient loop counter to start of band */
+ k = cinfo->Ss;
+
+ if (EOBRUN == 0) {
+ for (; k <= Se; k++) {
+ HUFF_DECODE(s, br_state, tbl, goto undoit, label3);
+ r = s >> 4;
+ s &= 15;
+ if (s) {
+ if (s != 1) /* size of new coef should always be 1 */
+ WARNMS(cinfo, JWRN_HUFF_BAD_CODE);
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1))
+ s = p1; /* newly nonzero coef is positive */
+ else
+ s = m1; /* newly nonzero coef is negative */
+ } else {
+ if (r != 15) {
+ EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */
+ if (r) {
+ CHECK_BIT_BUFFER(br_state, r, goto undoit);
+ r = GET_BITS(r);
+ EOBRUN += r;
+ }
+ break; /* rest of block is handled by EOB logic */
+ }
+ /* note s = 0 for processing ZRL */
+ }
+ /* Advance over already-nonzero coefs and r still-zero coefs,
+ * appending correction bits to the nonzeroes. A correction bit is 1
+ * if the absolute value of the coefficient must be increased.
+ */
+ do {
+ thiscoef = *block + natural_order[k];
+ if (*thiscoef != 0) {
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1)) {
+ if ((*thiscoef & p1) == 0) { /* do nothing if already set it */
+ if (*thiscoef >= 0)
+ *thiscoef += p1;
+ else
+ *thiscoef += m1;
+ }
+ }
+ } else {
+ if (--r < 0)
+ break; /* reached target zero coefficient */
+ }
+ k++;
+ } while (k <= Se);
+ if (s) {
+ int pos = natural_order[k];
+ /* Output newly nonzero coefficient */
+ (*block)[pos] = (JCOEF) s;
+ /* Remember its position in case we have to suspend */
+ newnz_pos[num_newnz++] = pos;
+ }
+ }
+ }
+
+ if (EOBRUN > 0) {
+ /* Scan any remaining coefficient positions after the end-of-band
+ * (the last newly nonzero coefficient, if any). Append a correction
+ * bit to each already-nonzero coefficient. A correction bit is 1
+ * if the absolute value of the coefficient must be increased.
+ */
+ for (; k <= Se; k++) {
+ thiscoef = *block + natural_order[k];
+ if (*thiscoef != 0) {
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1)) {
+ if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */
+ if (*thiscoef >= 0)
+ *thiscoef += p1;
+ else
+ *thiscoef += m1;
+ }
+ }
+ }
+ }
+ /* Count one block completed in EOB run */
+ EOBRUN--;
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+
+undoit:
+ /* Re-zero any output coefficients that we made newly nonzero */
+ while (num_newnz > 0)
+ (*block)[newnz_pos[--num_newnz]] = 0;
+
+ return FALSE;
+}
+
+
+/*
+ * Decode one MCU's worth of Huffman-compressed coefficients,
+ * partial blocks.
+ */
+
+METHODDEF(boolean)
+decode_mcu_sub (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ const int * natural_order;
+ int Se, blkn;
+ BITREAD_STATE_VARS;
+ savable_state state;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy->insufficient_data) {
+
+ natural_order = cinfo->natural_order;
+ Se = cinfo->lim_Se;
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(state, entropy->saved);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ JBLOCKROW block = MCU_data[blkn];
+ d_derived_tbl * htbl;
+ register int s, k, r;
+ int coef_limit, ci;
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+ htbl = entropy->dc_cur_tbls[blkn];
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label1);
+
+ htbl = entropy->ac_cur_tbls[blkn];
+ k = 1;
+ coef_limit = entropy->coef_limit[blkn];
+ if (coef_limit) {
+ /* Convert DC difference to actual value, update last_dc_val */
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+ ci = cinfo->MCU_membership[blkn];
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ /* Output the DC coefficient */
+ (*block)[0] = (JCOEF) s;
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* Since zeroes are skipped, output area must be cleared beforehand */
+ for (; k < coef_limit; k++) {
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label2);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ /* Output coefficient in natural (dezigzagged) order.
+ * Note: the extra entries in natural_order[] will save us
+ * if k > Se, which could happen if the data is corrupted.
+ */
+ (*block)[natural_order[k]] = (JCOEF) s;
+ } else {
+ if (r != 15)
+ goto EndOfBlock;
+ k += 15;
+ }
+ }
+ } else {
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ DROP_BITS(s);
+ }
+ }
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* In this path we just discard the values */
+ for (; k <= Se; k++) {
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label3);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ DROP_BITS(s);
+ } else {
+ if (r != 15)
+ break;
+ k += 15;
+ }
+ }
+
+ EndOfBlock: ;
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(entropy->saved, state);
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * Decode one MCU's worth of Huffman-compressed coefficients,
+ * full-size blocks.
+ */
+
+METHODDEF(boolean)
+decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int blkn;
+ BITREAD_STATE_VARS;
+ savable_state state;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy->insufficient_data) {
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(state, entropy->saved);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ JBLOCKROW block = MCU_data[blkn];
+ d_derived_tbl * htbl;
+ register int s, k, r;
+ int coef_limit, ci;
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+ htbl = entropy->dc_cur_tbls[blkn];
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label1);
+
+ htbl = entropy->ac_cur_tbls[blkn];
+ k = 1;
+ coef_limit = entropy->coef_limit[blkn];
+ if (coef_limit) {
+ /* Convert DC difference to actual value, update last_dc_val */
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+ ci = cinfo->MCU_membership[blkn];
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ /* Output the DC coefficient */
+ (*block)[0] = (JCOEF) s;
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* Since zeroes are skipped, output area must be cleared beforehand */
+ for (; k < coef_limit; k++) {
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label2);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ /* Output coefficient in natural (dezigzagged) order.
+ * Note: the extra entries in jpeg_natural_order[] will save us
+ * if k >= DCTSIZE2, which could happen if the data is corrupted.
+ */
+ (*block)[jpeg_natural_order[k]] = (JCOEF) s;
+ } else {
+ if (r != 15)
+ goto EndOfBlock;
+ k += 15;
+ }
+ }
+ } else {
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ DROP_BITS(s);
+ }
+ }
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* In this path we just discard the values */
+ for (; k < DCTSIZE2; k++) {
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label3);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ DROP_BITS(s);
+ } else {
+ if (r != 15)
+ break;
+ k += 15;
+ }
+ }
+
+ EndOfBlock: ;
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(entropy->saved, state);
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass_huff_decoder (j_decompress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci, blkn, tbl, i;
+ jpeg_component_info * compptr;
+
+ if (cinfo->progressive_mode) {
+ /* Validate progressive scan parameters */
+ if (cinfo->Ss == 0) {
+ if (cinfo->Se != 0)
+ goto bad;
+ } else {
+ /* need not check Ss/Se < 0 since they came from unsigned bytes */
+ if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se)
+ goto bad;
+ /* AC scans may have only one component */
+ if (cinfo->comps_in_scan != 1)
+ goto bad;
+ }
+ if (cinfo->Ah != 0) {
+ /* Successive approximation refinement scan: must have Al = Ah-1. */
+ if (cinfo->Ah-1 != cinfo->Al)
+ goto bad;
+ }
+ if (cinfo->Al > 13) { /* need not check for < 0 */
+ /* Arguably the maximum Al value should be less than 13 for 8-bit precision,
+ * but the spec doesn't say so, and we try to be liberal about what we
+ * accept. Note: large Al values could result in out-of-range DC
+ * coefficients during early scans, leading to bizarre displays due to
+ * overflows in the IDCT math. But we won't crash.
+ */
+ bad:
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+ }
+ /* Update progression status, and verify that scan order is legal.
+ * Note that inter-scan inconsistencies are treated as warnings
+ * not fatal errors ... not clear if this is right way to behave.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ int coefi, cindex = cinfo->cur_comp_info[ci]->component_index;
+ int *coef_bit_ptr = & cinfo->coef_bits[cindex][0];
+ if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
+ for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
+ int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
+ if (cinfo->Ah != expected)
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
+ coef_bit_ptr[coefi] = cinfo->Al;
+ }
+ }
+
+ /* Select MCU decoding routine */
+ if (cinfo->Ah == 0) {
+ if (cinfo->Ss == 0)
+ entropy->pub.decode_mcu = decode_mcu_DC_first;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_first;
+ } else {
+ if (cinfo->Ss == 0)
+ entropy->pub.decode_mcu = decode_mcu_DC_refine;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_refine;
+ }
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Make sure requested tables are present, and compute derived tables.
+ * We may build same derived table more than once, but it's not expensive.
+ */
+ if (cinfo->Ss == 0) {
+ if (cinfo->Ah == 0) { /* DC refinement needs no table */
+ tbl = compptr->dc_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, TRUE, tbl,
+ & entropy->derived_tbls[tbl]);
+ }
+ } else {
+ tbl = compptr->ac_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, FALSE, tbl,
+ & entropy->derived_tbls[tbl]);
+ /* remember the single active table */
+ entropy->ac_derived_tbl = entropy->derived_tbls[tbl];
+ }
+ /* Initialize DC predictions to 0 */
+ entropy->saved.last_dc_val[ci] = 0;
+ }
+
+ /* Initialize private state variables */
+ entropy->saved.EOBRUN = 0;
+ } else {
+ /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
+ * This ought to be an error condition, but we make it a warning because
+ * there are some baseline files out there with all zeroes in these bytes.
+ */
+ if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 ||
+ ((cinfo->is_baseline || cinfo->Se < DCTSIZE2) &&
+ cinfo->Se != cinfo->lim_Se))
+ WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
+
+ /* Select MCU decoding routine */
+ /* We retain the hard-coded case for full-size blocks.
+ * This is not necessary, but it appears that this version is slightly
+ * more performant in the given implementation.
+ * With an improved implementation we would prefer a single optimized
+ * function.
+ */
+ if (cinfo->lim_Se != DCTSIZE2-1)
+ entropy->pub.decode_mcu = decode_mcu_sub;
+ else
+ entropy->pub.decode_mcu = decode_mcu;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ tbl = compptr->dc_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, TRUE, tbl,
+ & entropy->dc_derived_tbls[tbl]);
+ if (cinfo->lim_Se) { /* AC needs no table when not present */
+ tbl = compptr->ac_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, FALSE, tbl,
+ & entropy->ac_derived_tbls[tbl]);
+ }
+ /* Initialize DC predictions to 0 */
+ entropy->saved.last_dc_val[ci] = 0;
+ }
+
+ /* Precalculate decoding info for each block in an MCU of this scan */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ /* Precalculate which table to use for each block */
+ entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no];
+ entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no];
+ /* Decide whether we really care about the coefficient values */
+ if (compptr->component_needed) {
+ ci = compptr->DCT_v_scaled_size;
+ i = compptr->DCT_h_scaled_size;
+ switch (cinfo->lim_Se) {
+ case (1*1-1):
+ entropy->coef_limit[blkn] = 1;
+ break;
+ case (2*2-1):
+ if (ci <= 0 || ci > 2) ci = 2;
+ if (i <= 0 || i > 2) i = 2;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order2[ci - 1][i - 1];
+ break;
+ case (3*3-1):
+ if (ci <= 0 || ci > 3) ci = 3;
+ if (i <= 0 || i > 3) i = 3;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order3[ci - 1][i - 1];
+ break;
+ case (4*4-1):
+ if (ci <= 0 || ci > 4) ci = 4;
+ if (i <= 0 || i > 4) i = 4;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order4[ci - 1][i - 1];
+ break;
+ case (5*5-1):
+ if (ci <= 0 || ci > 5) ci = 5;
+ if (i <= 0 || i > 5) i = 5;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order5[ci - 1][i - 1];
+ break;
+ case (6*6-1):
+ if (ci <= 0 || ci > 6) ci = 6;
+ if (i <= 0 || i > 6) i = 6;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order6[ci - 1][i - 1];
+ break;
+ case (7*7-1):
+ if (ci <= 0 || ci > 7) ci = 7;
+ if (i <= 0 || i > 7) i = 7;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order7[ci - 1][i - 1];
+ break;
+ default:
+ if (ci <= 0 || ci > 8) ci = 8;
+ if (i <= 0 || i > 8) i = 8;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order[ci - 1][i - 1];
+ break;
+ }
+ } else {
+ entropy->coef_limit[blkn] = 0;
+ }
+ }
+ }
+
+ /* Initialize bitread state variables */
+ entropy->bitstate.bits_left = 0;
+ entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
+ entropy->insufficient_data = FALSE;
+
+ /* Initialize restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Module initialization routine for Huffman entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_huff_decoder (j_decompress_ptr cinfo)
+{
+ huff_entropy_ptr entropy;
+ int i;
+
+ entropy = (huff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(huff_entropy_decoder));
+ cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
+ entropy->pub.start_pass = start_pass_huff_decoder;
+
+ if (cinfo->progressive_mode) {
+ /* Create progression status table */
+ int *coef_bit_ptr, ci;
+ cinfo->coef_bits = (int (*)[DCTSIZE2])
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components*DCTSIZE2*SIZEOF(int));
+ coef_bit_ptr = & cinfo->coef_bits[0][0];
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ for (i = 0; i < DCTSIZE2; i++)
+ *coef_bit_ptr++ = -1;
+
+ /* Mark derived tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->derived_tbls[i] = NULL;
+ }
+ } else {
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
+ }
+ }
+}
diff --git a/external/jpeg-8c/jdinput.c b/external/jpeg-8c/jdinput.c
new file mode 100644
index 0000000..2c5c717
--- /dev/null
+++ b/external/jpeg-8c/jdinput.c
@@ -0,0 +1,661 @@
+/*
+ * jdinput.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2002-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains input control logic for the JPEG decompressor.
+ * These routines are concerned with controlling the decompressor's input
+ * processing (marker reading and coefficient decoding). The actual input
+ * reading is done in jdmarker.c, jdhuff.c, and jdarith.c.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef struct {
+ struct jpeg_input_controller pub; /* public fields */
+
+ int inheaders; /* Nonzero until first SOS is reached */
+} my_input_controller;
+
+typedef my_input_controller * my_inputctl_ptr;
+
+
+/* Forward declarations */
+METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Routines to calculate various quantities related to the size of the image.
+ */
+
+
+/*
+ * Compute output image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ */
+
+GLOBAL(void)
+jpeg_core_output_dimensions (j_decompress_ptr cinfo)
+/* Do computations that are needed before master selection phase.
+ * This function is used for transcoding and full decompression.
+ */
+{
+#ifdef IDCT_SCALING_SUPPORTED
+ int ci;
+ jpeg_component_info *compptr;
+
+ /* Compute actual output image dimensions and DCT scaling choices. */
+ if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom) {
+ /* Provide 1/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 1;
+ cinfo->min_DCT_v_scaled_size = 1;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 2) {
+ /* Provide 2/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 2L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 2L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 2;
+ cinfo->min_DCT_v_scaled_size = 2;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 3) {
+ /* Provide 3/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 3L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 3L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 3;
+ cinfo->min_DCT_v_scaled_size = 3;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 4) {
+ /* Provide 4/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 4L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 4L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 4;
+ cinfo->min_DCT_v_scaled_size = 4;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 5) {
+ /* Provide 5/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 5L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 5L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 5;
+ cinfo->min_DCT_v_scaled_size = 5;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 6) {
+ /* Provide 6/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 6L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 6L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 6;
+ cinfo->min_DCT_v_scaled_size = 6;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 7) {
+ /* Provide 7/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 7L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 7L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 7;
+ cinfo->min_DCT_v_scaled_size = 7;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 8) {
+ /* Provide 8/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 8L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 8L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 8;
+ cinfo->min_DCT_v_scaled_size = 8;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 9) {
+ /* Provide 9/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 9L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 9L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 9;
+ cinfo->min_DCT_v_scaled_size = 9;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 10) {
+ /* Provide 10/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 10L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 10L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 10;
+ cinfo->min_DCT_v_scaled_size = 10;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 11) {
+ /* Provide 11/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 11L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 11L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 11;
+ cinfo->min_DCT_v_scaled_size = 11;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 12) {
+ /* Provide 12/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 12L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 12L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 12;
+ cinfo->min_DCT_v_scaled_size = 12;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 13) {
+ /* Provide 13/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 13L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 13L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 13;
+ cinfo->min_DCT_v_scaled_size = 13;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 14) {
+ /* Provide 14/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 14L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 14L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 14;
+ cinfo->min_DCT_v_scaled_size = 14;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 15) {
+ /* Provide 15/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 15L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 15L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 15;
+ cinfo->min_DCT_v_scaled_size = 15;
+ } else {
+ /* Provide 16/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 16L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 16L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 16;
+ cinfo->min_DCT_v_scaled_size = 16;
+ }
+
+ /* Recompute dimensions of components */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size;
+ compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size;
+ }
+
+#else /* !IDCT_SCALING_SUPPORTED */
+
+ /* Hardwire it to "no scaling" */
+ cinfo->output_width = cinfo->image_width;
+ cinfo->output_height = cinfo->image_height;
+ /* jdinput.c has already initialized DCT_scaled_size,
+ * and has computed unscaled downsampled_width and downsampled_height.
+ */
+
+#endif /* IDCT_SCALING_SUPPORTED */
+}
+
+
+LOCAL(void)
+initial_setup (j_decompress_ptr cinfo)
+/* Called once, when first SOS marker is reached */
+{
+ int ci;
+ jpeg_component_info *compptr;
+
+ /* Make sure image isn't bigger than I can handle */
+ if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
+ (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+ /* For now, precision must match compiled-in value... */
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ /* Check that number of components won't exceed internal array sizes */
+ if (cinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPONENTS);
+
+ /* Compute maximum sampling factors; check factor validity */
+ cinfo->max_h_samp_factor = 1;
+ cinfo->max_v_samp_factor = 1;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
+ compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
+ ERREXIT(cinfo, JERR_BAD_SAMPLING);
+ cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
+ compptr->h_samp_factor);
+ cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
+ compptr->v_samp_factor);
+ }
+
+ /* Derive block_size, natural_order, and lim_Se */
+ if (cinfo->is_baseline || (cinfo->progressive_mode &&
+ cinfo->comps_in_scan)) { /* no pseudo SOS marker */
+ cinfo->block_size = DCTSIZE;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ } else
+ switch (cinfo->Se) {
+ case (1*1-1):
+ cinfo->block_size = 1;
+ cinfo->natural_order = jpeg_natural_order; /* not needed */
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (2*2-1):
+ cinfo->block_size = 2;
+ cinfo->natural_order = jpeg_natural_order2;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (3*3-1):
+ cinfo->block_size = 3;
+ cinfo->natural_order = jpeg_natural_order3;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (4*4-1):
+ cinfo->block_size = 4;
+ cinfo->natural_order = jpeg_natural_order4;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (5*5-1):
+ cinfo->block_size = 5;
+ cinfo->natural_order = jpeg_natural_order5;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (6*6-1):
+ cinfo->block_size = 6;
+ cinfo->natural_order = jpeg_natural_order6;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (7*7-1):
+ cinfo->block_size = 7;
+ cinfo->natural_order = jpeg_natural_order7;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (8*8-1):
+ cinfo->block_size = 8;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (9*9-1):
+ cinfo->block_size = 9;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (10*10-1):
+ cinfo->block_size = 10;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (11*11-1):
+ cinfo->block_size = 11;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (12*12-1):
+ cinfo->block_size = 12;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (13*13-1):
+ cinfo->block_size = 13;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (14*14-1):
+ cinfo->block_size = 14;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (15*15-1):
+ cinfo->block_size = 15;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (16*16-1):
+ cinfo->block_size = 16;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ default:
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+ break;
+ }
+
+ /* We initialize DCT_scaled_size and min_DCT_scaled_size to block_size.
+ * In the full decompressor,
+ * this will be overridden by jpeg_calc_output_dimensions in jdmaster.c;
+ * but in the transcoder,
+ * jpeg_calc_output_dimensions is not used, so we must do it here.
+ */
+ cinfo->min_DCT_h_scaled_size = cinfo->block_size;
+ cinfo->min_DCT_v_scaled_size = cinfo->block_size;
+
+ /* Compute dimensions of components */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ compptr->DCT_h_scaled_size = cinfo->block_size;
+ compptr->DCT_v_scaled_size = cinfo->block_size;
+ /* Size in DCT blocks */
+ compptr->width_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ compptr->height_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+ /* downsampled_width and downsampled_height will also be overridden by
+ * jdmaster.c if we are doing full decompression. The transcoder library
+ * doesn't use these values, but the calling application might.
+ */
+ /* Size in samples */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+ (long) cinfo->max_h_samp_factor);
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+ (long) cinfo->max_v_samp_factor);
+ /* Mark component needed, until color conversion says otherwise */
+ compptr->component_needed = TRUE;
+ /* Mark no quantization table yet saved for component */
+ compptr->quant_table = NULL;
+ }
+
+ /* Compute number of fully interleaved MCU rows. */
+ cinfo->total_iMCU_rows = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+
+ /* Decide whether file contains multiple scans */
+ if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode)
+ cinfo->inputctl->has_multiple_scans = TRUE;
+ else
+ cinfo->inputctl->has_multiple_scans = FALSE;
+}
+
+
+LOCAL(void)
+per_scan_setup (j_decompress_ptr cinfo)
+/* Do computations that are needed before processing a JPEG scan */
+/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */
+{
+ int ci, mcublks, tmp;
+ jpeg_component_info *compptr;
+
+ if (cinfo->comps_in_scan == 1) {
+
+ /* Noninterleaved (single-component) scan */
+ compptr = cinfo->cur_comp_info[0];
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = compptr->width_in_blocks;
+ cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
+
+ /* For noninterleaved scan, always one block per MCU */
+ compptr->MCU_width = 1;
+ compptr->MCU_height = 1;
+ compptr->MCU_blocks = 1;
+ compptr->MCU_sample_width = compptr->DCT_h_scaled_size;
+ compptr->last_col_width = 1;
+ /* For noninterleaved scans, it is convenient to define last_row_height
+ * as the number of block rows present in the last iMCU row.
+ */
+ tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (tmp == 0) tmp = compptr->v_samp_factor;
+ compptr->last_row_height = tmp;
+
+ /* Prepare array describing MCU composition */
+ cinfo->blocks_in_MCU = 1;
+ cinfo->MCU_membership[0] = 0;
+
+ } else {
+
+ /* Interleaved (multi-component) scan */
+ if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
+ MAX_COMPS_IN_SCAN);
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width,
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ cinfo->MCU_rows_in_scan = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+
+ cinfo->blocks_in_MCU = 0;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Sampling factors give # of blocks of component in each MCU */
+ compptr->MCU_width = compptr->h_samp_factor;
+ compptr->MCU_height = compptr->v_samp_factor;
+ compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
+ compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size;
+ /* Figure number of non-dummy blocks in last MCU column & row */
+ tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
+ if (tmp == 0) tmp = compptr->MCU_width;
+ compptr->last_col_width = tmp;
+ tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
+ if (tmp == 0) tmp = compptr->MCU_height;
+ compptr->last_row_height = tmp;
+ /* Prepare array describing MCU composition */
+ mcublks = compptr->MCU_blocks;
+ if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU)
+ ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
+ while (mcublks-- > 0) {
+ cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
+ }
+ }
+
+ }
+}
+
+
+/*
+ * Save away a copy of the Q-table referenced by each component present
+ * in the current scan, unless already saved during a prior scan.
+ *
+ * In a multiple-scan JPEG file, the encoder could assign different components
+ * the same Q-table slot number, but change table definitions between scans
+ * so that each component uses a different Q-table. (The IJG encoder is not
+ * currently capable of doing this, but other encoders might.) Since we want
+ * to be able to dequantize all the components at the end of the file, this
+ * means that we have to save away the table actually used for each component.
+ * We do this by copying the table at the start of the first scan containing
+ * the component.
+ * The JPEG spec prohibits the encoder from changing the contents of a Q-table
+ * slot between scans of a component using that slot. If the encoder does so
+ * anyway, this decoder will simply use the Q-table values that were current
+ * at the start of the first scan for the component.
+ *
+ * The decompressor output side looks only at the saved quant tables,
+ * not at the current Q-table slots.
+ */
+
+LOCAL(void)
+latch_quant_tables (j_decompress_ptr cinfo)
+{
+ int ci, qtblno;
+ jpeg_component_info *compptr;
+ JQUANT_TBL * qtbl;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* No work if we already saved Q-table for this component */
+ if (compptr->quant_table != NULL)
+ continue;
+ /* Make sure specified quantization table is present */
+ qtblno = compptr->quant_tbl_no;
+ if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
+ cinfo->quant_tbl_ptrs[qtblno] == NULL)
+ ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
+ /* OK, save away the quantization table */
+ qtbl = (JQUANT_TBL *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(JQUANT_TBL));
+ MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL));
+ compptr->quant_table = qtbl;
+ }
+}
+
+
+/*
+ * Initialize the input modules to read a scan of compressed data.
+ * The first call to this is done by jdmaster.c after initializing
+ * the entire decompressor (during jpeg_start_decompress).
+ * Subsequent calls come from consume_markers, below.
+ */
+
+METHODDEF(void)
+start_input_pass (j_decompress_ptr cinfo)
+{
+ per_scan_setup(cinfo);
+ latch_quant_tables(cinfo);
+ (*cinfo->entropy->start_pass) (cinfo);
+ (*cinfo->coef->start_input_pass) (cinfo);
+ cinfo->inputctl->consume_input = cinfo->coef->consume_data;
+}
+
+
+/*
+ * Finish up after inputting a compressed-data scan.
+ * This is called by the coefficient controller after it's read all
+ * the expected data of the scan.
+ */
+
+METHODDEF(void)
+finish_input_pass (j_decompress_ptr cinfo)
+{
+ cinfo->inputctl->consume_input = consume_markers;
+}
+
+
+/*
+ * Read JPEG markers before, between, or after compressed-data scans.
+ * Change state as necessary when a new scan is reached.
+ * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ *
+ * The consume_input method pointer points either here or to the
+ * coefficient controller's consume_data routine, depending on whether
+ * we are reading a compressed data segment or inter-segment markers.
+ *
+ * Note: This function should NOT return a pseudo SOS marker (with zero
+ * component number) to the caller. A pseudo marker received by
+ * read_markers is processed and then skipped for other markers.
+ */
+
+METHODDEF(int)
+consume_markers (j_decompress_ptr cinfo)
+{
+ my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
+ int val;
+
+ if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */
+ return JPEG_REACHED_EOI;
+
+ for (;;) { /* Loop to pass pseudo SOS marker */
+ val = (*cinfo->marker->read_markers) (cinfo);
+
+ switch (val) {
+ case JPEG_REACHED_SOS: /* Found SOS */
+ if (inputctl->inheaders) { /* 1st SOS */
+ if (inputctl->inheaders == 1)
+ initial_setup(cinfo);
+ if (cinfo->comps_in_scan == 0) { /* pseudo SOS marker */
+ inputctl->inheaders = 2;
+ break;
+ }
+ inputctl->inheaders = 0;
+ /* Note: start_input_pass must be called by jdmaster.c
+ * before any more input can be consumed. jdapimin.c is
+ * responsible for enforcing this sequencing.
+ */
+ } else { /* 2nd or later SOS marker */
+ if (! inputctl->pub.has_multiple_scans)
+ ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */
+ if (cinfo->comps_in_scan == 0) /* unexpected pseudo SOS marker */
+ break;
+ start_input_pass(cinfo);
+ }
+ return val;
+ case JPEG_REACHED_EOI: /* Found EOI */
+ inputctl->pub.eoi_reached = TRUE;
+ if (inputctl->inheaders) { /* Tables-only datastream, apparently */
+ if (cinfo->marker->saw_SOF)
+ ERREXIT(cinfo, JERR_SOF_NO_SOS);
+ } else {
+ /* Prevent infinite loop in coef ctlr's decompress_data routine
+ * if user set output_scan_number larger than number of scans.
+ */
+ if (cinfo->output_scan_number > cinfo->input_scan_number)
+ cinfo->output_scan_number = cinfo->input_scan_number;
+ }
+ return val;
+ case JPEG_SUSPENDED:
+ return val;
+ default:
+ return val;
+ }
+ }
+}
+
+
+/*
+ * Reset state to begin a fresh datastream.
+ */
+
+METHODDEF(void)
+reset_input_controller (j_decompress_ptr cinfo)
+{
+ my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
+
+ inputctl->pub.consume_input = consume_markers;
+ inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
+ inputctl->pub.eoi_reached = FALSE;
+ inputctl->inheaders = 1;
+ /* Reset other modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->marker->reset_marker_reader) (cinfo);
+ /* Reset progression state -- would be cleaner if entropy decoder did this */
+ cinfo->coef_bits = NULL;
+}
+
+
+/*
+ * Initialize the input controller module.
+ * This is called only once, when the decompression object is created.
+ */
+
+GLOBAL(void)
+jinit_input_controller (j_decompress_ptr cinfo)
+{
+ my_inputctl_ptr inputctl;
+
+ /* Create subobject in permanent pool */
+ inputctl = (my_inputctl_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_input_controller));
+ cinfo->inputctl = (struct jpeg_input_controller *) inputctl;
+ /* Initialize method pointers */
+ inputctl->pub.consume_input = consume_markers;
+ inputctl->pub.reset_input_controller = reset_input_controller;
+ inputctl->pub.start_input_pass = start_input_pass;
+ inputctl->pub.finish_input_pass = finish_input_pass;
+ /* Initialize state: can't use reset_input_controller since we don't
+ * want to try to reset other modules yet.
+ */
+ inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
+ inputctl->pub.eoi_reached = FALSE;
+ inputctl->inheaders = 1;
+}
diff --git a/external/jpeg-8c/jdmainct.c b/external/jpeg-8c/jdmainct.c
new file mode 100644
index 0000000..c04e822
--- /dev/null
+++ b/external/jpeg-8c/jdmainct.c
@@ -0,0 +1,512 @@
+/*
+ * jdmainct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the main buffer controller for decompression.
+ * The main buffer lies between the JPEG decompressor proper and the
+ * post-processor; it holds downsampled data in the JPEG colorspace.
+ *
+ * Note that this code is bypassed in raw-data mode, since the application
+ * supplies the equivalent of the main buffer in that case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * In the current system design, the main buffer need never be a full-image
+ * buffer; any full-height buffers will be found inside the coefficient or
+ * postprocessing controllers. Nonetheless, the main controller is not
+ * trivial. Its responsibility is to provide context rows for upsampling/
+ * rescaling, and doing this in an efficient fashion is a bit tricky.
+ *
+ * Postprocessor input data is counted in "row groups". A row group
+ * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
+ * sample rows of each component. (We require DCT_scaled_size values to be
+ * chosen such that these numbers are integers. In practice DCT_scaled_size
+ * values will likely be powers of two, so we actually have the stronger
+ * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.)
+ * Upsampling will typically produce max_v_samp_factor pixel rows from each
+ * row group (times any additional scale factor that the upsampler is
+ * applying).
+ *
+ * The coefficient controller will deliver data to us one iMCU row at a time;
+ * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or
+ * exactly min_DCT_scaled_size row groups. (This amount of data corresponds
+ * to one row of MCUs when the image is fully interleaved.) Note that the
+ * number of sample rows varies across components, but the number of row
+ * groups does not. Some garbage sample rows may be included in the last iMCU
+ * row at the bottom of the image.
+ *
+ * Depending on the vertical scaling algorithm used, the upsampler may need
+ * access to the sample row(s) above and below its current input row group.
+ * The upsampler is required to set need_context_rows TRUE at global selection
+ * time if so. When need_context_rows is FALSE, this controller can simply
+ * obtain one iMCU row at a time from the coefficient controller and dole it
+ * out as row groups to the postprocessor.
+ *
+ * When need_context_rows is TRUE, this controller guarantees that the buffer
+ * passed to postprocessing contains at least one row group's worth of samples
+ * above and below the row group(s) being processed. Note that the context
+ * rows "above" the first passed row group appear at negative row offsets in
+ * the passed buffer. At the top and bottom of the image, the required
+ * context rows are manufactured by duplicating the first or last real sample
+ * row; this avoids having special cases in the upsampling inner loops.
+ *
+ * The amount of context is fixed at one row group just because that's a
+ * convenient number for this controller to work with. The existing
+ * upsamplers really only need one sample row of context. An upsampler
+ * supporting arbitrary output rescaling might wish for more than one row
+ * group of context when shrinking the image; tough, we don't handle that.
+ * (This is justified by the assumption that downsizing will be handled mostly
+ * by adjusting the DCT_scaled_size values, so that the actual scale factor at
+ * the upsample step needn't be much less than one.)
+ *
+ * To provide the desired context, we have to retain the last two row groups
+ * of one iMCU row while reading in the next iMCU row. (The last row group
+ * can't be processed until we have another row group for its below-context,
+ * and so we have to save the next-to-last group too for its above-context.)
+ * We could do this most simply by copying data around in our buffer, but
+ * that'd be very slow. We can avoid copying any data by creating a rather
+ * strange pointer structure. Here's how it works. We allocate a workspace
+ * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number
+ * of row groups per iMCU row). We create two sets of redundant pointers to
+ * the workspace. Labeling the physical row groups 0 to M+1, the synthesized
+ * pointer lists look like this:
+ * M+1 M-1
+ * master pointer --> 0 master pointer --> 0
+ * 1 1
+ * ... ...
+ * M-3 M-3
+ * M-2 M
+ * M-1 M+1
+ * M M-2
+ * M+1 M-1
+ * 0 0
+ * We read alternate iMCU rows using each master pointer; thus the last two
+ * row groups of the previous iMCU row remain un-overwritten in the workspace.
+ * The pointer lists are set up so that the required context rows appear to
+ * be adjacent to the proper places when we pass the pointer lists to the
+ * upsampler.
+ *
+ * The above pictures describe the normal state of the pointer lists.
+ * At top and bottom of the image, we diddle the pointer lists to duplicate
+ * the first or last sample row as necessary (this is cheaper than copying
+ * sample rows around).
+ *
+ * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that
+ * situation each iMCU row provides only one row group so the buffering logic
+ * must be different (eg, we must read two iMCU rows before we can emit the
+ * first row group). For now, we simply do not support providing context
+ * rows when min_DCT_scaled_size is 1. That combination seems unlikely to
+ * be worth providing --- if someone wants a 1/8th-size preview, they probably
+ * want it quick and dirty, so a context-free upsampler is sufficient.
+ */
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_d_main_controller pub; /* public fields */
+
+ /* Pointer to allocated workspace (M or M+2 row groups). */
+ JSAMPARRAY buffer[MAX_COMPONENTS];
+
+ boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
+ JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */
+
+ /* Remaining fields are only used in the context case. */
+
+ /* These are the master pointers to the funny-order pointer lists. */
+ JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
+
+ int whichptr; /* indicates which pointer set is now in use */
+ int context_state; /* process_data state machine status */
+ JDIMENSION rowgroups_avail; /* row groups available to postprocessor */
+ JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */
+} my_main_controller;
+
+typedef my_main_controller * my_main_ptr;
+
+/* context_state values: */
+#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */
+#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */
+#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */
+
+
+/* Forward declarations */
+METHODDEF(void) process_data_simple_main
+ JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+METHODDEF(void) process_data_context_main
+ JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+#ifdef QUANT_2PASS_SUPPORTED
+METHODDEF(void) process_data_crank_post
+ JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+#endif
+
+
+LOCAL(void)
+alloc_funny_pointers (j_decompress_ptr cinfo)
+/* Allocate space for the funny pointer lists.
+ * This is done only once, not once per pass.
+ */
+{
+ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ int ci, rgroup;
+ int M = cinfo->min_DCT_v_scaled_size;
+ jpeg_component_info *compptr;
+ JSAMPARRAY xbuf;
+
+ /* Get top-level space for component array pointers.
+ * We alloc both arrays with one call to save a few cycles.
+ */
+ main_ptr->xbuffer[0] = (JSAMPIMAGE)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components * 2 * SIZEOF(JSAMPARRAY));
+ main_ptr->xbuffer[1] = main_ptr->xbuffer[0] + cinfo->num_components;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+ /* Get space for pointer lists --- M+4 row groups in each list.
+ * We alloc both pointer lists with one call to save a few cycles.
+ */
+ xbuf = (JSAMPARRAY)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW));
+ xbuf += rgroup; /* want one row group at negative offsets */
+ main_ptr->xbuffer[0][ci] = xbuf;
+ xbuf += rgroup * (M + 4);
+ main_ptr->xbuffer[1][ci] = xbuf;
+ }
+}
+
+
+LOCAL(void)
+make_funny_pointers (j_decompress_ptr cinfo)
+/* Create the funny pointer lists discussed in the comments above.
+ * The actual workspace is already allocated (in main_ptr->buffer),
+ * and the space for the pointer lists is allocated too.
+ * This routine just fills in the curiously ordered lists.
+ * This will be repeated at the beginning of each pass.
+ */
+{
+ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup;
+ int M = cinfo->min_DCT_v_scaled_size;
+ jpeg_component_info *compptr;
+ JSAMPARRAY buf, xbuf0, xbuf1;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+ xbuf0 = main_ptr->xbuffer[0][ci];
+ xbuf1 = main_ptr->xbuffer[1][ci];
+ /* First copy the workspace pointers as-is */
+ buf = main_ptr->buffer[ci];
+ for (i = 0; i < rgroup * (M + 2); i++) {
+ xbuf0[i] = xbuf1[i] = buf[i];
+ }
+ /* In the second list, put the last four row groups in swapped order */
+ for (i = 0; i < rgroup * 2; i++) {
+ xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i];
+ xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i];
+ }
+ /* The wraparound pointers at top and bottom will be filled later
+ * (see set_wraparound_pointers, below). Initially we want the "above"
+ * pointers to duplicate the first actual data line. This only needs
+ * to happen in xbuffer[0].
+ */
+ for (i = 0; i < rgroup; i++) {
+ xbuf0[i - rgroup] = xbuf0[0];
+ }
+ }
+}
+
+
+LOCAL(void)
+set_wraparound_pointers (j_decompress_ptr cinfo)
+/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
+ * This changes the pointer list state from top-of-image to the normal state.
+ */
+{
+ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup;
+ int M = cinfo->min_DCT_v_scaled_size;
+ jpeg_component_info *compptr;
+ JSAMPARRAY xbuf0, xbuf1;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+ xbuf0 = main_ptr->xbuffer[0][ci];
+ xbuf1 = main_ptr->xbuffer[1][ci];
+ for (i = 0; i < rgroup; i++) {
+ xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
+ xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
+ xbuf0[rgroup*(M+2) + i] = xbuf0[i];
+ xbuf1[rgroup*(M+2) + i] = xbuf1[i];
+ }
+ }
+}
+
+
+LOCAL(void)
+set_bottom_pointers (j_decompress_ptr cinfo)
+/* Change the pointer lists to duplicate the last sample row at the bottom
+ * of the image. whichptr indicates which xbuffer holds the final iMCU row.
+ * Also sets rowgroups_avail to indicate number of nondummy row groups in row.
+ */
+{
+ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup, iMCUheight, rows_left;
+ jpeg_component_info *compptr;
+ JSAMPARRAY xbuf;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Count sample rows in one iMCU row and in one row group */
+ iMCUheight = compptr->v_samp_factor * compptr->DCT_v_scaled_size;
+ rgroup = iMCUheight / cinfo->min_DCT_v_scaled_size;
+ /* Count nondummy sample rows remaining for this component */
+ rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight);
+ if (rows_left == 0) rows_left = iMCUheight;
+ /* Count nondummy row groups. Should get same answer for each component,
+ * so we need only do it once.
+ */
+ if (ci == 0) {
+ main_ptr->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
+ }
+ /* Duplicate the last real sample row rgroup*2 times; this pads out the
+ * last partial rowgroup and ensures at least one full rowgroup of context.
+ */
+ xbuf = main_ptr->xbuffer[main_ptr->whichptr][ci];
+ for (i = 0; i < rgroup * 2; i++) {
+ xbuf[rows_left + i] = xbuf[rows_left-1];
+ }
+ }
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (cinfo->upsample->need_context_rows) {
+ main_ptr->pub.process_data = process_data_context_main;
+ make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
+ main_ptr->whichptr = 0; /* Read first iMCU row into xbuffer[0] */
+ main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
+ main_ptr->iMCU_row_ctr = 0;
+ } else {
+ /* Simple case with no context needed */
+ main_ptr->pub.process_data = process_data_simple_main;
+ }
+ main_ptr->buffer_full = FALSE; /* Mark buffer empty */
+ main_ptr->rowgroup_ctr = 0;
+ break;
+#ifdef QUANT_2PASS_SUPPORTED
+ case JBUF_CRANK_DEST:
+ /* For last pass of 2-pass quantization, just crank the postprocessor */
+ main_ptr->pub.process_data = process_data_crank_post;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+}
+
+
+/*
+ * Process some data.
+ * This handles the simple case where no context is required.
+ */
+
+METHODDEF(void)
+process_data_simple_main (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+ JDIMENSION rowgroups_avail;
+
+ /* Read input data if we haven't filled the main buffer yet */
+ if (! main_ptr->buffer_full) {
+ if (! (*cinfo->coef->decompress_data) (cinfo, main_ptr->buffer))
+ return; /* suspension forced, can do nothing more */
+ main_ptr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
+ }
+
+ /* There are always min_DCT_scaled_size row groups in an iMCU row. */
+ rowgroups_avail = (JDIMENSION) cinfo->min_DCT_v_scaled_size;
+ /* Note: at the bottom of the image, we may pass extra garbage row groups
+ * to the postprocessor. The postprocessor has to check for bottom
+ * of image anyway (at row resolution), so no point in us doing it too.
+ */
+
+ /* Feed the postprocessor */
+ (*cinfo->post->post_process_data) (cinfo, main_ptr->buffer,
+ &main_ptr->rowgroup_ctr, rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+
+ /* Has postprocessor consumed all the data yet? If so, mark buffer empty */
+ if (main_ptr->rowgroup_ctr >= rowgroups_avail) {
+ main_ptr->buffer_full = FALSE;
+ main_ptr->rowgroup_ctr = 0;
+ }
+}
+
+
+/*
+ * Process some data.
+ * This handles the case where context rows must be provided.
+ */
+
+METHODDEF(void)
+process_data_context_main (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+
+ /* Read input data if we haven't filled the main buffer yet */
+ if (! main_ptr->buffer_full) {
+ if (! (*cinfo->coef->decompress_data) (cinfo,
+ main_ptr->xbuffer[main_ptr->whichptr]))
+ return; /* suspension forced, can do nothing more */
+ main_ptr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
+ main_ptr->iMCU_row_ctr++; /* count rows received */
+ }
+
+ /* Postprocessor typically will not swallow all the input data it is handed
+ * in one call (due to filling the output buffer first). Must be prepared
+ * to exit and restart. This switch lets us keep track of how far we got.
+ * Note that each case falls through to the next on successful completion.
+ */
+ switch (main_ptr->context_state) {
+ case CTX_POSTPONED_ROW:
+ /* Call postprocessor using previously set pointers for postponed row */
+ (*cinfo->post->post_process_data) (cinfo, main_ptr->xbuffer[main_ptr->whichptr],
+ &main_ptr->rowgroup_ctr, main_ptr->rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+ if (main_ptr->rowgroup_ctr < main_ptr->rowgroups_avail)
+ return; /* Need to suspend */
+ main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
+ if (*out_row_ctr >= out_rows_avail)
+ return; /* Postprocessor exactly filled output buf */
+ /*FALLTHROUGH*/
+ case CTX_PREPARE_FOR_IMCU:
+ /* Prepare to process first M-1 row groups of this iMCU row */
+ main_ptr->rowgroup_ctr = 0;
+ main_ptr->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size - 1);
+ /* Check for bottom of image: if so, tweak pointers to "duplicate"
+ * the last sample row, and adjust rowgroups_avail to ignore padding rows.
+ */
+ if (main_ptr->iMCU_row_ctr == cinfo->total_iMCU_rows)
+ set_bottom_pointers(cinfo);
+ main_ptr->context_state = CTX_PROCESS_IMCU;
+ /*FALLTHROUGH*/
+ case CTX_PROCESS_IMCU:
+ /* Call postprocessor using previously set pointers */
+ (*cinfo->post->post_process_data) (cinfo, main_ptr->xbuffer[main_ptr->whichptr],
+ &main_ptr->rowgroup_ctr, main_ptr->rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+ if (main_ptr->rowgroup_ctr < main_ptr->rowgroups_avail)
+ return; /* Need to suspend */
+ /* After the first iMCU, change wraparound pointers to normal state */
+ if (main_ptr->iMCU_row_ctr == 1)
+ set_wraparound_pointers(cinfo);
+ /* Prepare to load new iMCU row using other xbuffer list */
+ main_ptr->whichptr ^= 1; /* 0=>1 or 1=>0 */
+ main_ptr->buffer_full = FALSE;
+ /* Still need to process last row group of this iMCU row, */
+ /* which is saved at index M+1 of the other xbuffer */
+ main_ptr->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 1);
+ main_ptr->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 2);
+ main_ptr->context_state = CTX_POSTPONED_ROW;
+ }
+}
+
+
+/*
+ * Process some data.
+ * Final pass of two-pass quantization: just call the postprocessor.
+ * Source data will be the postprocessor controller's internal buffer.
+ */
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+METHODDEF(void)
+process_data_crank_post (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL,
+ (JDIMENSION *) NULL, (JDIMENSION) 0,
+ output_buf, out_row_ctr, out_rows_avail);
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
+
+
+/*
+ * Initialize main buffer controller.
+ */
+
+GLOBAL(void)
+jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+ my_main_ptr main_ptr;
+ int ci, rgroup, ngroups;
+ jpeg_component_info *compptr;
+
+ main_ptr = (my_main_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_main_controller));
+ cinfo->main = (struct jpeg_d_main_controller *) main_ptr;
+ main_ptr->pub.start_pass = start_pass_main;
+
+ if (need_full_buffer) /* shouldn't happen */
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ /* Allocate the workspace.
+ * ngroups is the number of row groups we need.
+ */
+ if (cinfo->upsample->need_context_rows) {
+ if (cinfo->min_DCT_v_scaled_size < 2) /* unsupported, see comments above */
+ ERREXIT(cinfo, JERR_NOTIMPL);
+ alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */
+ ngroups = cinfo->min_DCT_v_scaled_size + 2;
+ } else {
+ ngroups = cinfo->min_DCT_v_scaled_size;
+ }
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+ main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+ (JDIMENSION) (rgroup * ngroups));
+ }
+}
diff --git a/external/jpeg-8c/jdmarker.c b/external/jpeg-8c/jdmarker.c
new file mode 100644
index 0000000..f2a9cc4
--- /dev/null
+++ b/external/jpeg-8c/jdmarker.c
@@ -0,0 +1,1406 @@
+/*
+ * jdmarker.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to decode JPEG datastream markers.
+ * Most of the complexity arises from our desire to support input
+ * suspension: if not all of the data for a marker is available,
+ * we must exit back to the application. On resumption, we reprocess
+ * the marker.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+typedef enum { /* JPEG marker codes */
+ M_SOF0 = 0xc0,
+ M_SOF1 = 0xc1,
+ M_SOF2 = 0xc2,
+ M_SOF3 = 0xc3,
+
+ M_SOF5 = 0xc5,
+ M_SOF6 = 0xc6,
+ M_SOF7 = 0xc7,
+
+ M_JPG = 0xc8,
+ M_SOF9 = 0xc9,
+ M_SOF10 = 0xca,
+ M_SOF11 = 0xcb,
+
+ M_SOF13 = 0xcd,
+ M_SOF14 = 0xce,
+ M_SOF15 = 0xcf,
+
+ M_DHT = 0xc4,
+
+ M_DAC = 0xcc,
+
+ M_RST0 = 0xd0,
+ M_RST1 = 0xd1,
+ M_RST2 = 0xd2,
+ M_RST3 = 0xd3,
+ M_RST4 = 0xd4,
+ M_RST5 = 0xd5,
+ M_RST6 = 0xd6,
+ M_RST7 = 0xd7,
+
+ M_SOI = 0xd8,
+ M_EOI = 0xd9,
+ M_SOS = 0xda,
+ M_DQT = 0xdb,
+ M_DNL = 0xdc,
+ M_DRI = 0xdd,
+ M_DHP = 0xde,
+ M_EXP = 0xdf,
+
+ M_APP0 = 0xe0,
+ M_APP1 = 0xe1,
+ M_APP2 = 0xe2,
+ M_APP3 = 0xe3,
+ M_APP4 = 0xe4,
+ M_APP5 = 0xe5,
+ M_APP6 = 0xe6,
+ M_APP7 = 0xe7,
+ M_APP8 = 0xe8,
+ M_APP9 = 0xe9,
+ M_APP10 = 0xea,
+ M_APP11 = 0xeb,
+ M_APP12 = 0xec,
+ M_APP13 = 0xed,
+ M_APP14 = 0xee,
+ M_APP15 = 0xef,
+
+ M_JPG0 = 0xf0,
+ M_JPG13 = 0xfd,
+ M_COM = 0xfe,
+
+ M_TEM = 0x01,
+
+ M_ERROR = 0x100
+} JPEG_MARKER;
+
+
+/* Private state */
+
+typedef struct {
+ struct jpeg_marker_reader pub; /* public fields */
+
+ /* Application-overridable marker processing methods */
+ jpeg_marker_parser_method process_COM;
+ jpeg_marker_parser_method process_APPn[16];
+
+ /* Limit on marker data length to save for each marker type */
+ unsigned int length_limit_COM;
+ unsigned int length_limit_APPn[16];
+
+ /* Status of COM/APPn marker saving */
+ jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */
+ unsigned int bytes_read; /* data bytes read so far in marker */
+ /* Note: cur_marker is not linked into marker_list until it's all read. */
+} my_marker_reader;
+
+typedef my_marker_reader * my_marker_ptr;
+
+
+/*
+ * Macros for fetching data from the data source module.
+ *
+ * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect
+ * the current restart point; we update them only when we have reached a
+ * suitable place to restart if a suspension occurs.
+ */
+
+/* Declare and initialize local copies of input pointer/count */
+#define INPUT_VARS(cinfo) \
+ struct jpeg_source_mgr * datasrc = (cinfo)->src; \
+ const JOCTET * next_input_byte = datasrc->next_input_byte; \
+ size_t bytes_in_buffer = datasrc->bytes_in_buffer
+
+/* Unload the local copies --- do this only at a restart boundary */
+#define INPUT_SYNC(cinfo) \
+ ( datasrc->next_input_byte = next_input_byte, \
+ datasrc->bytes_in_buffer = bytes_in_buffer )
+
+/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */
+#define INPUT_RELOAD(cinfo) \
+ ( next_input_byte = datasrc->next_input_byte, \
+ bytes_in_buffer = datasrc->bytes_in_buffer )
+
+/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available.
+ * Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+ * but we must reload the local copies after a successful fill.
+ */
+#define MAKE_BYTE_AVAIL(cinfo,action) \
+ if (bytes_in_buffer == 0) { \
+ if (! (*datasrc->fill_input_buffer) (cinfo)) \
+ { action; } \
+ INPUT_RELOAD(cinfo); \
+ }
+
+/* Read a byte into variable V.
+ * If must suspend, take the specified action (typically "return FALSE").
+ */
+#define INPUT_BYTE(cinfo,V,action) \
+ MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
+ bytes_in_buffer--; \
+ V = GETJOCTET(*next_input_byte++); )
+
+/* As above, but read two bytes interpreted as an unsigned 16-bit integer.
+ * V should be declared unsigned int or perhaps INT32.
+ */
+#define INPUT_2BYTES(cinfo,V,action) \
+ MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
+ bytes_in_buffer--; \
+ V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \
+ MAKE_BYTE_AVAIL(cinfo,action); \
+ bytes_in_buffer--; \
+ V += GETJOCTET(*next_input_byte++); )
+
+
+/*
+ * Routines to process JPEG markers.
+ *
+ * Entry condition: JPEG marker itself has been read and its code saved
+ * in cinfo->unread_marker; input restart point is just after the marker.
+ *
+ * Exit: if return TRUE, have read and processed any parameters, and have
+ * updated the restart point to point after the parameters.
+ * If return FALSE, was forced to suspend before reaching end of
+ * marker parameters; restart point has not been moved. Same routine
+ * will be called again after application supplies more input data.
+ *
+ * This approach to suspension assumes that all of a marker's parameters
+ * can fit into a single input bufferload. This should hold for "normal"
+ * markers. Some COM/APPn markers might have large parameter segments
+ * that might not fit. If we are simply dropping such a marker, we use
+ * skip_input_data to get past it, and thereby put the problem on the
+ * source manager's shoulders. If we are saving the marker's contents
+ * into memory, we use a slightly different convention: when forced to
+ * suspend, the marker processor updates the restart point to the end of
+ * what it's consumed (ie, the end of the buffer) before returning FALSE.
+ * On resumption, cinfo->unread_marker still contains the marker code,
+ * but the data source will point to the next chunk of marker data.
+ * The marker processor must retain internal state to deal with this.
+ *
+ * Note that we don't bother to avoid duplicate trace messages if a
+ * suspension occurs within marker parameters. Other side effects
+ * require more care.
+ */
+
+
+LOCAL(boolean)
+get_soi (j_decompress_ptr cinfo)
+/* Process an SOI marker */
+{
+ int i;
+
+ TRACEMS(cinfo, 1, JTRC_SOI);
+
+ if (cinfo->marker->saw_SOI)
+ ERREXIT(cinfo, JERR_SOI_DUPLICATE);
+
+ /* Reset all parameters that are defined to be reset by SOI */
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ cinfo->arith_dc_L[i] = 0;
+ cinfo->arith_dc_U[i] = 1;
+ cinfo->arith_ac_K[i] = 5;
+ }
+ cinfo->restart_interval = 0;
+
+ /* Set initial assumptions for colorspace etc */
+
+ cinfo->jpeg_color_space = JCS_UNKNOWN;
+ cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */
+
+ cinfo->saw_JFIF_marker = FALSE;
+ cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */
+ cinfo->JFIF_minor_version = 1;
+ cinfo->density_unit = 0;
+ cinfo->X_density = 1;
+ cinfo->Y_density = 1;
+ cinfo->saw_Adobe_marker = FALSE;
+ cinfo->Adobe_transform = 0;
+
+ cinfo->marker->saw_SOI = TRUE;
+
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_sof (j_decompress_ptr cinfo, boolean is_baseline, boolean is_prog,
+ boolean is_arith)
+/* Process a SOFn marker */
+{
+ INT32 length;
+ int c, ci;
+ jpeg_component_info * compptr;
+ INPUT_VARS(cinfo);
+
+ cinfo->is_baseline = is_baseline;
+ cinfo->progressive_mode = is_prog;
+ cinfo->arith_code = is_arith;
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+
+ INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE);
+ INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE);
+ INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE);
+ INPUT_BYTE(cinfo, cinfo->num_components, return FALSE);
+
+ length -= 8;
+
+ TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker,
+ (int) cinfo->image_width, (int) cinfo->image_height,
+ cinfo->num_components);
+
+ if (cinfo->marker->saw_SOF)
+ ERREXIT(cinfo, JERR_SOF_DUPLICATE);
+
+ /* We don't support files in which the image height is initially specified */
+ /* as 0 and is later redefined by DNL. As long as we have to check that, */
+ /* might as well have a general sanity check. */
+ if (cinfo->image_height <= 0 || cinfo->image_width <= 0
+ || cinfo->num_components <= 0)
+ ERREXIT(cinfo, JERR_EMPTY_IMAGE);
+
+ if (length != (cinfo->num_components * 3))
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ if (cinfo->comp_info == NULL) /* do only once, even if suspend */
+ cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components * SIZEOF(jpeg_component_info));
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ compptr->component_index = ci;
+ INPUT_BYTE(cinfo, compptr->component_id, return FALSE);
+ INPUT_BYTE(cinfo, c, return FALSE);
+ compptr->h_samp_factor = (c >> 4) & 15;
+ compptr->v_samp_factor = (c ) & 15;
+ INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE);
+
+ TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT,
+ compptr->component_id, compptr->h_samp_factor,
+ compptr->v_samp_factor, compptr->quant_tbl_no);
+ }
+
+ cinfo->marker->saw_SOF = TRUE;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_sos (j_decompress_ptr cinfo)
+/* Process a SOS marker */
+{
+ INT32 length;
+ int i, ci, n, c, cc;
+ jpeg_component_info * compptr;
+ INPUT_VARS(cinfo);
+
+ if (! cinfo->marker->saw_SOF)
+ ERREXIT(cinfo, JERR_SOS_NO_SOF);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+
+ INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */
+
+ TRACEMS1(cinfo, 1, JTRC_SOS, n);
+
+ if (length != (n * 2 + 6) || n > MAX_COMPS_IN_SCAN ||
+ (n == 0 && !cinfo->progressive_mode))
+ /* pseudo SOS marker only allowed in progressive mode */
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ cinfo->comps_in_scan = n;
+
+ /* Collect the component-spec parameters */
+
+ for (i = 0; i < n; i++) {
+ INPUT_BYTE(cinfo, cc, return FALSE);
+ INPUT_BYTE(cinfo, c, return FALSE);
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (cc == compptr->component_id)
+ goto id_found;
+ }
+
+ ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc);
+
+ id_found:
+
+ cinfo->cur_comp_info[i] = compptr;
+ compptr->dc_tbl_no = (c >> 4) & 15;
+ compptr->ac_tbl_no = (c ) & 15;
+
+ TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc,
+ compptr->dc_tbl_no, compptr->ac_tbl_no);
+ }
+
+ /* Collect the additional scan parameters Ss, Se, Ah/Al. */
+ INPUT_BYTE(cinfo, c, return FALSE);
+ cinfo->Ss = c;
+ INPUT_BYTE(cinfo, c, return FALSE);
+ cinfo->Se = c;
+ INPUT_BYTE(cinfo, c, return FALSE);
+ cinfo->Ah = (c >> 4) & 15;
+ cinfo->Al = (c ) & 15;
+
+ TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se,
+ cinfo->Ah, cinfo->Al);
+
+ /* Prepare to scan data & restart markers */
+ cinfo->marker->next_restart_num = 0;
+
+ /* Count another (non-pseudo) SOS marker */
+ if (n) cinfo->input_scan_number++;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+#ifdef D_ARITH_CODING_SUPPORTED
+
+LOCAL(boolean)
+get_dac (j_decompress_ptr cinfo)
+/* Process a DAC marker */
+{
+ INT32 length;
+ int index, val;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ while (length > 0) {
+ INPUT_BYTE(cinfo, index, return FALSE);
+ INPUT_BYTE(cinfo, val, return FALSE);
+
+ length -= 2;
+
+ TRACEMS2(cinfo, 1, JTRC_DAC, index, val);
+
+ if (index < 0 || index >= (2*NUM_ARITH_TBLS))
+ ERREXIT1(cinfo, JERR_DAC_INDEX, index);
+
+ if (index >= NUM_ARITH_TBLS) { /* define AC table */
+ cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val;
+ } else { /* define DC table */
+ cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F);
+ cinfo->arith_dc_U[index] = (UINT8) (val >> 4);
+ if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index])
+ ERREXIT1(cinfo, JERR_DAC_VALUE, val);
+ }
+ }
+
+ if (length != 0)
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+#else /* ! D_ARITH_CODING_SUPPORTED */
+
+#define get_dac(cinfo) skip_variable(cinfo)
+
+#endif /* D_ARITH_CODING_SUPPORTED */
+
+
+LOCAL(boolean)
+get_dht (j_decompress_ptr cinfo)
+/* Process a DHT marker */
+{
+ INT32 length;
+ UINT8 bits[17];
+ UINT8 huffval[256];
+ int i, index, count;
+ JHUFF_TBL **htblptr;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ while (length > 16) {
+ INPUT_BYTE(cinfo, index, return FALSE);
+
+ TRACEMS1(cinfo, 1, JTRC_DHT, index);
+
+ bits[0] = 0;
+ count = 0;
+ for (i = 1; i <= 16; i++) {
+ INPUT_BYTE(cinfo, bits[i], return FALSE);
+ count += bits[i];
+ }
+
+ length -= 1 + 16;
+
+ TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
+ bits[1], bits[2], bits[3], bits[4],
+ bits[5], bits[6], bits[7], bits[8]);
+ TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
+ bits[9], bits[10], bits[11], bits[12],
+ bits[13], bits[14], bits[15], bits[16]);
+
+ /* Here we just do minimal validation of the counts to avoid walking
+ * off the end of our table space. jdhuff.c will check more carefully.
+ */
+ if (count > 256 || ((INT32) count) > length)
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+
+ for (i = 0; i < count; i++)
+ INPUT_BYTE(cinfo, huffval[i], return FALSE);
+
+ length -= count;
+
+ if (index & 0x10) { /* AC table definition */
+ index -= 0x10;
+ htblptr = &cinfo->ac_huff_tbl_ptrs[index];
+ } else { /* DC table definition */
+ htblptr = &cinfo->dc_huff_tbl_ptrs[index];
+ }
+
+ if (index < 0 || index >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_DHT_INDEX, index);
+
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+
+ MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits));
+ MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval));
+ }
+
+ if (length != 0)
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_dqt (j_decompress_ptr cinfo)
+/* Process a DQT marker */
+{
+ INT32 length, count, i;
+ int n, prec;
+ unsigned int tmp;
+ JQUANT_TBL *quant_ptr;
+ const int *natural_order;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ while (length > 0) {
+ length--;
+ INPUT_BYTE(cinfo, n, return FALSE);
+ prec = n >> 4;
+ n &= 0x0F;
+
+ TRACEMS2(cinfo, 1, JTRC_DQT, n, prec);
+
+ if (n >= NUM_QUANT_TBLS)
+ ERREXIT1(cinfo, JERR_DQT_INDEX, n);
+
+ if (cinfo->quant_tbl_ptrs[n] == NULL)
+ cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo);
+ quant_ptr = cinfo->quant_tbl_ptrs[n];
+
+ if (prec) {
+ if (length < DCTSIZE2 * 2) {
+ /* Initialize full table for safety. */
+ for (i = 0; i < DCTSIZE2; i++) {
+ quant_ptr->quantval[i] = 1;
+ }
+ count = length >> 1;
+ } else
+ count = DCTSIZE2;
+ } else {
+ if (length < DCTSIZE2) {
+ /* Initialize full table for safety. */
+ for (i = 0; i < DCTSIZE2; i++) {
+ quant_ptr->quantval[i] = 1;
+ }
+ count = length;
+ } else
+ count = DCTSIZE2;
+ }
+
+ switch (count) {
+ case (2*2): natural_order = jpeg_natural_order2; break;
+ case (3*3): natural_order = jpeg_natural_order3; break;
+ case (4*4): natural_order = jpeg_natural_order4; break;
+ case (5*5): natural_order = jpeg_natural_order5; break;
+ case (6*6): natural_order = jpeg_natural_order6; break;
+ case (7*7): natural_order = jpeg_natural_order7; break;
+ default: natural_order = jpeg_natural_order; break;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (prec)
+ INPUT_2BYTES(cinfo, tmp, return FALSE);
+ else
+ INPUT_BYTE(cinfo, tmp, return FALSE);
+ /* We convert the zigzag-order table to natural array order. */
+ quant_ptr->quantval[natural_order[i]] = (UINT16) tmp;
+ }
+
+ if (cinfo->err->trace_level >= 2) {
+ for (i = 0; i < DCTSIZE2; i += 8) {
+ TRACEMS8(cinfo, 2, JTRC_QUANTVALS,
+ quant_ptr->quantval[i], quant_ptr->quantval[i+1],
+ quant_ptr->quantval[i+2], quant_ptr->quantval[i+3],
+ quant_ptr->quantval[i+4], quant_ptr->quantval[i+5],
+ quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]);
+ }
+ }
+
+ length -= count;
+ if (prec) length -= count;
+ }
+
+ if (length != 0)
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_dri (j_decompress_ptr cinfo)
+/* Process a DRI marker */
+{
+ INT32 length;
+ unsigned int tmp;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+
+ if (length != 4)
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ INPUT_2BYTES(cinfo, tmp, return FALSE);
+
+ TRACEMS1(cinfo, 1, JTRC_DRI, tmp);
+
+ cinfo->restart_interval = tmp;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+/*
+ * Routines for processing APPn and COM markers.
+ * These are either saved in memory or discarded, per application request.
+ * APP0 and APP14 are specially checked to see if they are
+ * JFIF and Adobe markers, respectively.
+ */
+
+#define APP0_DATA_LEN 14 /* Length of interesting data in APP0 */
+#define APP14_DATA_LEN 12 /* Length of interesting data in APP14 */
+#define APPN_DATA_LEN 14 /* Must be the largest of the above!! */
+
+
+LOCAL(void)
+examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data,
+ unsigned int datalen, INT32 remaining)
+/* Examine first few bytes from an APP0.
+ * Take appropriate action if it is a JFIF marker.
+ * datalen is # of bytes at data[], remaining is length of rest of marker data.
+ */
+{
+ INT32 totallen = (INT32) datalen + remaining;
+
+ if (datalen >= APP0_DATA_LEN &&
+ GETJOCTET(data[0]) == 0x4A &&
+ GETJOCTET(data[1]) == 0x46 &&
+ GETJOCTET(data[2]) == 0x49 &&
+ GETJOCTET(data[3]) == 0x46 &&
+ GETJOCTET(data[4]) == 0) {
+ /* Found JFIF APP0 marker: save info */
+ cinfo->saw_JFIF_marker = TRUE;
+ cinfo->JFIF_major_version = GETJOCTET(data[5]);
+ cinfo->JFIF_minor_version = GETJOCTET(data[6]);
+ cinfo->density_unit = GETJOCTET(data[7]);
+ cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]);
+ cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]);
+ /* Check version.
+ * Major version must be 1, anything else signals an incompatible change.
+ * (We used to treat this as an error, but now it's a nonfatal warning,
+ * because some bozo at Hijaak couldn't read the spec.)
+ * Minor version should be 0..2, but process anyway if newer.
+ */
+ if (cinfo->JFIF_major_version != 1)
+ WARNMS2(cinfo, JWRN_JFIF_MAJOR,
+ cinfo->JFIF_major_version, cinfo->JFIF_minor_version);
+ /* Generate trace messages */
+ TRACEMS5(cinfo, 1, JTRC_JFIF,
+ cinfo->JFIF_major_version, cinfo->JFIF_minor_version,
+ cinfo->X_density, cinfo->Y_density, cinfo->density_unit);
+ /* Validate thumbnail dimensions and issue appropriate messages */
+ if (GETJOCTET(data[12]) | GETJOCTET(data[13]))
+ TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL,
+ GETJOCTET(data[12]), GETJOCTET(data[13]));
+ totallen -= APP0_DATA_LEN;
+ if (totallen !=
+ ((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3))
+ TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen);
+ } else if (datalen >= 6 &&
+ GETJOCTET(data[0]) == 0x4A &&
+ GETJOCTET(data[1]) == 0x46 &&
+ GETJOCTET(data[2]) == 0x58 &&
+ GETJOCTET(data[3]) == 0x58 &&
+ GETJOCTET(data[4]) == 0) {
+ /* Found JFIF "JFXX" extension APP0 marker */
+ /* The library doesn't actually do anything with these,
+ * but we try to produce a helpful trace message.
+ */
+ switch (GETJOCTET(data[5])) {
+ case 0x10:
+ TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen);
+ break;
+ case 0x11:
+ TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen);
+ break;
+ case 0x13:
+ TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen);
+ break;
+ default:
+ TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION,
+ GETJOCTET(data[5]), (int) totallen);
+ break;
+ }
+ } else {
+ /* Start of APP0 does not match "JFIF" or "JFXX", or too short */
+ TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen);
+ }
+}
+
+
+LOCAL(void)
+examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data,
+ unsigned int datalen, INT32 remaining)
+/* Examine first few bytes from an APP14.
+ * Take appropriate action if it is an Adobe marker.
+ * datalen is # of bytes at data[], remaining is length of rest of marker data.
+ */
+{
+ unsigned int version, flags0, flags1, transform;
+
+ if (datalen >= APP14_DATA_LEN &&
+ GETJOCTET(data[0]) == 0x41 &&
+ GETJOCTET(data[1]) == 0x64 &&
+ GETJOCTET(data[2]) == 0x6F &&
+ GETJOCTET(data[3]) == 0x62 &&
+ GETJOCTET(data[4]) == 0x65) {
+ /* Found Adobe APP14 marker */
+ version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]);
+ flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]);
+ flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]);
+ transform = GETJOCTET(data[11]);
+ TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform);
+ cinfo->saw_Adobe_marker = TRUE;
+ cinfo->Adobe_transform = (UINT8) transform;
+ } else {
+ /* Start of APP14 does not match "Adobe", or too short */
+ TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining));
+ }
+}
+
+
+METHODDEF(boolean)
+get_interesting_appn (j_decompress_ptr cinfo)
+/* Process an APP0 or APP14 marker without saving it */
+{
+ INT32 length;
+ JOCTET b[APPN_DATA_LEN];
+ unsigned int i, numtoread;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ /* get the interesting part of the marker data */
+ if (length >= APPN_DATA_LEN)
+ numtoread = APPN_DATA_LEN;
+ else if (length > 0)
+ numtoread = (unsigned int) length;
+ else
+ numtoread = 0;
+ for (i = 0; i < numtoread; i++)
+ INPUT_BYTE(cinfo, b[i], return FALSE);
+ length -= numtoread;
+
+ /* process it */
+ switch (cinfo->unread_marker) {
+ case M_APP0:
+ examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length);
+ break;
+ case M_APP14:
+ examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length);
+ break;
+ default:
+ /* can't get here unless jpeg_save_markers chooses wrong processor */
+ ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);
+ break;
+ }
+
+ /* skip any remaining data -- could be lots */
+ INPUT_SYNC(cinfo);
+ if (length > 0)
+ (*cinfo->src->skip_input_data) (cinfo, (long) length);
+
+ return TRUE;
+}
+
+
+#ifdef SAVE_MARKERS_SUPPORTED
+
+METHODDEF(boolean)
+save_marker (j_decompress_ptr cinfo)
+/* Save an APPn or COM marker into the marker list */
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+ jpeg_saved_marker_ptr cur_marker = marker->cur_marker;
+ unsigned int bytes_read, data_length;
+ JOCTET FAR * data;
+ INT32 length = 0;
+ INPUT_VARS(cinfo);
+
+ if (cur_marker == NULL) {
+ /* begin reading a marker */
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+ if (length >= 0) { /* watch out for bogus length word */
+ /* figure out how much we want to save */
+ unsigned int limit;
+ if (cinfo->unread_marker == (int) M_COM)
+ limit = marker->length_limit_COM;
+ else
+ limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0];
+ if ((unsigned int) length < limit)
+ limit = (unsigned int) length;
+ /* allocate and initialize the marker item */
+ cur_marker = (jpeg_saved_marker_ptr)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(struct jpeg_marker_struct) + limit);
+ cur_marker->next = NULL;
+ cur_marker->marker = (UINT8) cinfo->unread_marker;
+ cur_marker->original_length = (unsigned int) length;
+ cur_marker->data_length = limit;
+ /* data area is just beyond the jpeg_marker_struct */
+ data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1);
+ marker->cur_marker = cur_marker;
+ marker->bytes_read = 0;
+ bytes_read = 0;
+ data_length = limit;
+ } else {
+ /* deal with bogus length word */
+ bytes_read = data_length = 0;
+ data = NULL;
+ }
+ } else {
+ /* resume reading a marker */
+ bytes_read = marker->bytes_read;
+ data_length = cur_marker->data_length;
+ data = cur_marker->data + bytes_read;
+ }
+
+ while (bytes_read < data_length) {
+ INPUT_SYNC(cinfo); /* move the restart point to here */
+ marker->bytes_read = bytes_read;
+ /* If there's not at least one byte in buffer, suspend */
+ MAKE_BYTE_AVAIL(cinfo, return FALSE);
+ /* Copy bytes with reasonable rapidity */
+ while (bytes_read < data_length && bytes_in_buffer > 0) {
+ *data++ = *next_input_byte++;
+ bytes_in_buffer--;
+ bytes_read++;
+ }
+ }
+
+ /* Done reading what we want to read */
+ if (cur_marker != NULL) { /* will be NULL if bogus length word */
+ /* Add new marker to end of list */
+ if (cinfo->marker_list == NULL) {
+ cinfo->marker_list = cur_marker;
+ } else {
+ jpeg_saved_marker_ptr prev = cinfo->marker_list;
+ while (prev->next != NULL)
+ prev = prev->next;
+ prev->next = cur_marker;
+ }
+ /* Reset pointer & calc remaining data length */
+ data = cur_marker->data;
+ length = cur_marker->original_length - data_length;
+ }
+ /* Reset to initial state for next marker */
+ marker->cur_marker = NULL;
+
+ /* Process the marker if interesting; else just make a generic trace msg */
+ switch (cinfo->unread_marker) {
+ case M_APP0:
+ examine_app0(cinfo, data, data_length, length);
+ break;
+ case M_APP14:
+ examine_app14(cinfo, data, data_length, length);
+ break;
+ default:
+ TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker,
+ (int) (data_length + length));
+ break;
+ }
+
+ /* skip any remaining data -- could be lots */
+ INPUT_SYNC(cinfo); /* do before skip_input_data */
+ if (length > 0)
+ (*cinfo->src->skip_input_data) (cinfo, (long) length);
+
+ return TRUE;
+}
+
+#endif /* SAVE_MARKERS_SUPPORTED */
+
+
+METHODDEF(boolean)
+skip_variable (j_decompress_ptr cinfo)
+/* Skip over an unknown or uninteresting variable-length marker */
+{
+ INT32 length;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length);
+
+ INPUT_SYNC(cinfo); /* do before skip_input_data */
+ if (length > 0)
+ (*cinfo->src->skip_input_data) (cinfo, (long) length);
+
+ return TRUE;
+}
+
+
+/*
+ * Find the next JPEG marker, save it in cinfo->unread_marker.
+ * Returns FALSE if had to suspend before reaching a marker;
+ * in that case cinfo->unread_marker is unchanged.
+ *
+ * Note that the result might not be a valid marker code,
+ * but it will never be 0 or FF.
+ */
+
+LOCAL(boolean)
+next_marker (j_decompress_ptr cinfo)
+{
+ int c;
+ INPUT_VARS(cinfo);
+
+ for (;;) {
+ INPUT_BYTE(cinfo, c, return FALSE);
+ /* Skip any non-FF bytes.
+ * This may look a bit inefficient, but it will not occur in a valid file.
+ * We sync after each discarded byte so that a suspending data source
+ * can discard the byte from its buffer.
+ */
+ while (c != 0xFF) {
+ cinfo->marker->discarded_bytes++;
+ INPUT_SYNC(cinfo);
+ INPUT_BYTE(cinfo, c, return FALSE);
+ }
+ /* This loop swallows any duplicate FF bytes. Extra FFs are legal as
+ * pad bytes, so don't count them in discarded_bytes. We assume there
+ * will not be so many consecutive FF bytes as to overflow a suspending
+ * data source's input buffer.
+ */
+ do {
+ INPUT_BYTE(cinfo, c, return FALSE);
+ } while (c == 0xFF);
+ if (c != 0)
+ break; /* found a valid marker, exit loop */
+ /* Reach here if we found a stuffed-zero data sequence (FF/00).
+ * Discard it and loop back to try again.
+ */
+ cinfo->marker->discarded_bytes += 2;
+ INPUT_SYNC(cinfo);
+ }
+
+ if (cinfo->marker->discarded_bytes != 0) {
+ WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c);
+ cinfo->marker->discarded_bytes = 0;
+ }
+
+ cinfo->unread_marker = c;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+first_marker (j_decompress_ptr cinfo)
+/* Like next_marker, but used to obtain the initial SOI marker. */
+/* For this marker, we do not allow preceding garbage or fill; otherwise,
+ * we might well scan an entire input file before realizing it ain't JPEG.
+ * If an application wants to process non-JFIF files, it must seek to the
+ * SOI before calling the JPEG library.
+ */
+{
+ int c, c2;
+ INPUT_VARS(cinfo);
+
+ INPUT_BYTE(cinfo, c, return FALSE);
+ INPUT_BYTE(cinfo, c2, return FALSE);
+ if (c != 0xFF || c2 != (int) M_SOI)
+ ERREXIT2(cinfo, JERR_NO_SOI, c, c2);
+
+ cinfo->unread_marker = c2;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+/*
+ * Read markers until SOS or EOI.
+ *
+ * Returns same codes as are defined for jpeg_consume_input:
+ * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ *
+ * Note: This function may return a pseudo SOS marker (with zero
+ * component number) for treat by input controller's consume_input.
+ * consume_input itself should filter out (skip) the pseudo marker
+ * after processing for the caller.
+ */
+
+METHODDEF(int)
+read_markers (j_decompress_ptr cinfo)
+{
+ /* Outer loop repeats once for each marker. */
+ for (;;) {
+ /* Collect the marker proper, unless we already did. */
+ /* NB: first_marker() enforces the requirement that SOI appear first. */
+ if (cinfo->unread_marker == 0) {
+ if (! cinfo->marker->saw_SOI) {
+ if (! first_marker(cinfo))
+ return JPEG_SUSPENDED;
+ } else {
+ if (! next_marker(cinfo))
+ return JPEG_SUSPENDED;
+ }
+ }
+ /* At this point cinfo->unread_marker contains the marker code and the
+ * input point is just past the marker proper, but before any parameters.
+ * A suspension will cause us to return with this state still true.
+ */
+ switch (cinfo->unread_marker) {
+ case M_SOI:
+ if (! get_soi(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF0: /* Baseline */
+ if (! get_sof(cinfo, TRUE, FALSE, FALSE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF1: /* Extended sequential, Huffman */
+ if (! get_sof(cinfo, FALSE, FALSE, FALSE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF2: /* Progressive, Huffman */
+ if (! get_sof(cinfo, FALSE, TRUE, FALSE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF9: /* Extended sequential, arithmetic */
+ if (! get_sof(cinfo, FALSE, FALSE, TRUE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF10: /* Progressive, arithmetic */
+ if (! get_sof(cinfo, FALSE, TRUE, TRUE))
+ return JPEG_SUSPENDED;
+ break;
+
+ /* Currently unsupported SOFn types */
+ case M_SOF3: /* Lossless, Huffman */
+ case M_SOF5: /* Differential sequential, Huffman */
+ case M_SOF6: /* Differential progressive, Huffman */
+ case M_SOF7: /* Differential lossless, Huffman */
+ case M_JPG: /* Reserved for JPEG extensions */
+ case M_SOF11: /* Lossless, arithmetic */
+ case M_SOF13: /* Differential sequential, arithmetic */
+ case M_SOF14: /* Differential progressive, arithmetic */
+ case M_SOF15: /* Differential lossless, arithmetic */
+ ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker);
+ break;
+
+ case M_SOS:
+ if (! get_sos(cinfo))
+ return JPEG_SUSPENDED;
+ cinfo->unread_marker = 0; /* processed the marker */
+ return JPEG_REACHED_SOS;
+
+ case M_EOI:
+ TRACEMS(cinfo, 1, JTRC_EOI);
+ cinfo->unread_marker = 0; /* processed the marker */
+ return JPEG_REACHED_EOI;
+
+ case M_DAC:
+ if (! get_dac(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DHT:
+ if (! get_dht(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DQT:
+ if (! get_dqt(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DRI:
+ if (! get_dri(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_APP0:
+ case M_APP1:
+ case M_APP2:
+ case M_APP3:
+ case M_APP4:
+ case M_APP5:
+ case M_APP6:
+ case M_APP7:
+ case M_APP8:
+ case M_APP9:
+ case M_APP10:
+ case M_APP11:
+ case M_APP12:
+ case M_APP13:
+ case M_APP14:
+ case M_APP15:
+ if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[
+ cinfo->unread_marker - (int) M_APP0]) (cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_COM:
+ if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_RST0: /* these are all parameterless */
+ case M_RST1:
+ case M_RST2:
+ case M_RST3:
+ case M_RST4:
+ case M_RST5:
+ case M_RST6:
+ case M_RST7:
+ case M_TEM:
+ TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker);
+ break;
+
+ case M_DNL: /* Ignore DNL ... perhaps the wrong thing */
+ if (! skip_variable(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ default: /* must be DHP, EXP, JPGn, or RESn */
+ /* For now, we treat the reserved markers as fatal errors since they are
+ * likely to be used to signal incompatible JPEG Part 3 extensions.
+ * Once the JPEG 3 version-number marker is well defined, this code
+ * ought to change!
+ */
+ ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);
+ break;
+ }
+ /* Successfully processed marker, so reset state variable */
+ cinfo->unread_marker = 0;
+ } /* end loop */
+}
+
+
+/*
+ * Read a restart marker, which is expected to appear next in the datastream;
+ * if the marker is not there, take appropriate recovery action.
+ * Returns FALSE if suspension is required.
+ *
+ * This is called by the entropy decoder after it has read an appropriate
+ * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder
+ * has already read a marker from the data source. Under normal conditions
+ * cinfo->unread_marker will be reset to 0 before returning; if not reset,
+ * it holds a marker which the decoder will be unable to read past.
+ */
+
+METHODDEF(boolean)
+read_restart_marker (j_decompress_ptr cinfo)
+{
+ /* Obtain a marker unless we already did. */
+ /* Note that next_marker will complain if it skips any data. */
+ if (cinfo->unread_marker == 0) {
+ if (! next_marker(cinfo))
+ return FALSE;
+ }
+
+ if (cinfo->unread_marker ==
+ ((int) M_RST0 + cinfo->marker->next_restart_num)) {
+ /* Normal case --- swallow the marker and let entropy decoder continue */
+ TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num);
+ cinfo->unread_marker = 0;
+ } else {
+ /* Uh-oh, the restart markers have been messed up. */
+ /* Let the data source manager determine how to resync. */
+ if (! (*cinfo->src->resync_to_restart) (cinfo,
+ cinfo->marker->next_restart_num))
+ return FALSE;
+ }
+
+ /* Update next-restart state */
+ cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7;
+
+ return TRUE;
+}
+
+
+/*
+ * This is the default resync_to_restart method for data source managers
+ * to use if they don't have any better approach. Some data source managers
+ * may be able to back up, or may have additional knowledge about the data
+ * which permits a more intelligent recovery strategy; such managers would
+ * presumably supply their own resync method.
+ *
+ * read_restart_marker calls resync_to_restart if it finds a marker other than
+ * the restart marker it was expecting. (This code is *not* used unless
+ * a nonzero restart interval has been declared.) cinfo->unread_marker is
+ * the marker code actually found (might be anything, except 0 or FF).
+ * The desired restart marker number (0..7) is passed as a parameter.
+ * This routine is supposed to apply whatever error recovery strategy seems
+ * appropriate in order to position the input stream to the next data segment.
+ * Note that cinfo->unread_marker is treated as a marker appearing before
+ * the current data-source input point; usually it should be reset to zero
+ * before returning.
+ * Returns FALSE if suspension is required.
+ *
+ * This implementation is substantially constrained by wanting to treat the
+ * input as a data stream; this means we can't back up. Therefore, we have
+ * only the following actions to work with:
+ * 1. Simply discard the marker and let the entropy decoder resume at next
+ * byte of file.
+ * 2. Read forward until we find another marker, discarding intervening
+ * data. (In theory we could look ahead within the current bufferload,
+ * without having to discard data if we don't find the desired marker.
+ * This idea is not implemented here, in part because it makes behavior
+ * dependent on buffer size and chance buffer-boundary positions.)
+ * 3. Leave the marker unread (by failing to zero cinfo->unread_marker).
+ * This will cause the entropy decoder to process an empty data segment,
+ * inserting dummy zeroes, and then we will reprocess the marker.
+ *
+ * #2 is appropriate if we think the desired marker lies ahead, while #3 is
+ * appropriate if the found marker is a future restart marker (indicating
+ * that we have missed the desired restart marker, probably because it got
+ * corrupted).
+ * We apply #2 or #3 if the found marker is a restart marker no more than
+ * two counts behind or ahead of the expected one. We also apply #2 if the
+ * found marker is not a legal JPEG marker code (it's certainly bogus data).
+ * If the found marker is a restart marker more than 2 counts away, we do #1
+ * (too much risk that the marker is erroneous; with luck we will be able to
+ * resync at some future point).
+ * For any valid non-restart JPEG marker, we apply #3. This keeps us from
+ * overrunning the end of a scan. An implementation limited to single-scan
+ * files might find it better to apply #2 for markers other than EOI, since
+ * any other marker would have to be bogus data in that case.
+ */
+
+GLOBAL(boolean)
+jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired)
+{
+ int marker = cinfo->unread_marker;
+ int action = 1;
+
+ /* Always put up a warning. */
+ WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired);
+
+ /* Outer loop handles repeated decision after scanning forward. */
+ for (;;) {
+ if (marker < (int) M_SOF0)
+ action = 2; /* invalid marker */
+ else if (marker < (int) M_RST0 || marker > (int) M_RST7)
+ action = 3; /* valid non-restart marker */
+ else {
+ if (marker == ((int) M_RST0 + ((desired+1) & 7)) ||
+ marker == ((int) M_RST0 + ((desired+2) & 7)))
+ action = 3; /* one of the next two expected restarts */
+ else if (marker == ((int) M_RST0 + ((desired-1) & 7)) ||
+ marker == ((int) M_RST0 + ((desired-2) & 7)))
+ action = 2; /* a prior restart, so advance */
+ else
+ action = 1; /* desired restart or too far away */
+ }
+ TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action);
+ switch (action) {
+ case 1:
+ /* Discard marker and let entropy decoder resume processing. */
+ cinfo->unread_marker = 0;
+ return TRUE;
+ case 2:
+ /* Scan to the next marker, and repeat the decision loop. */
+ if (! next_marker(cinfo))
+ return FALSE;
+ marker = cinfo->unread_marker;
+ break;
+ case 3:
+ /* Return without advancing past this marker. */
+ /* Entropy decoder will be forced to process an empty segment. */
+ return TRUE;
+ }
+ } /* end loop */
+}
+
+
+/*
+ * Reset marker processing state to begin a fresh datastream.
+ */
+
+METHODDEF(void)
+reset_marker_reader (j_decompress_ptr cinfo)
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+
+ cinfo->comp_info = NULL; /* until allocated by get_sof */
+ cinfo->input_scan_number = 0; /* no SOS seen yet */
+ cinfo->unread_marker = 0; /* no pending marker */
+ marker->pub.saw_SOI = FALSE; /* set internal state too */
+ marker->pub.saw_SOF = FALSE;
+ marker->pub.discarded_bytes = 0;
+ marker->cur_marker = NULL;
+}
+
+
+/*
+ * Initialize the marker reader module.
+ * This is called only once, when the decompression object is created.
+ */
+
+GLOBAL(void)
+jinit_marker_reader (j_decompress_ptr cinfo)
+{
+ my_marker_ptr marker;
+ int i;
+
+ /* Create subobject in permanent pool */
+ marker = (my_marker_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_marker_reader));
+ cinfo->marker = (struct jpeg_marker_reader *) marker;
+ /* Initialize public method pointers */
+ marker->pub.reset_marker_reader = reset_marker_reader;
+ marker->pub.read_markers = read_markers;
+ marker->pub.read_restart_marker = read_restart_marker;
+ /* Initialize COM/APPn processing.
+ * By default, we examine and then discard APP0 and APP14,
+ * but simply discard COM and all other APPn.
+ */
+ marker->process_COM = skip_variable;
+ marker->length_limit_COM = 0;
+ for (i = 0; i < 16; i++) {
+ marker->process_APPn[i] = skip_variable;
+ marker->length_limit_APPn[i] = 0;
+ }
+ marker->process_APPn[0] = get_interesting_appn;
+ marker->process_APPn[14] = get_interesting_appn;
+ /* Reset marker processing state */
+ reset_marker_reader(cinfo);
+}
+
+
+/*
+ * Control saving of COM and APPn markers into marker_list.
+ */
+
+#ifdef SAVE_MARKERS_SUPPORTED
+
+GLOBAL(void)
+jpeg_save_markers (j_decompress_ptr cinfo, int marker_code,
+ unsigned int length_limit)
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+ long maxlength;
+ jpeg_marker_parser_method processor;
+
+ /* Length limit mustn't be larger than what we can allocate
+ * (should only be a concern in a 16-bit environment).
+ */
+ maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct);
+ if (((long) length_limit) > maxlength)
+ length_limit = (unsigned int) maxlength;
+
+ /* Choose processor routine to use.
+ * APP0/APP14 have special requirements.
+ */
+ if (length_limit) {
+ processor = save_marker;
+ /* If saving APP0/APP14, save at least enough for our internal use. */
+ if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN)
+ length_limit = APP0_DATA_LEN;
+ else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN)
+ length_limit = APP14_DATA_LEN;
+ } else {
+ processor = skip_variable;
+ /* If discarding APP0/APP14, use our regular on-the-fly processor. */
+ if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14)
+ processor = get_interesting_appn;
+ }
+
+ if (marker_code == (int) M_COM) {
+ marker->process_COM = processor;
+ marker->length_limit_COM = length_limit;
+ } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) {
+ marker->process_APPn[marker_code - (int) M_APP0] = processor;
+ marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit;
+ } else
+ ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);
+}
+
+#endif /* SAVE_MARKERS_SUPPORTED */
+
+
+/*
+ * Install a special processing method for COM or APPn markers.
+ */
+
+GLOBAL(void)
+jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code,
+ jpeg_marker_parser_method routine)
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+
+ if (marker_code == (int) M_COM)
+ marker->process_COM = routine;
+ else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15)
+ marker->process_APPn[marker_code - (int) M_APP0] = routine;
+ else
+ ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);
+}
diff --git a/external/jpeg-8c/jdmaster.c b/external/jpeg-8c/jdmaster.c
new file mode 100644
index 0000000..8c1146e
--- /dev/null
+++ b/external/jpeg-8c/jdmaster.c
@@ -0,0 +1,533 @@
+/*
+ * jdmaster.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2002-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains master control logic for the JPEG decompressor.
+ * These routines are concerned with selecting the modules to be executed
+ * and with determining the number of passes and the work to be done in each
+ * pass.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef struct {
+ struct jpeg_decomp_master pub; /* public fields */
+
+ int pass_number; /* # of passes completed */
+
+ boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
+
+ /* Saved references to initialized quantizer modules,
+ * in case we need to switch modes.
+ */
+ struct jpeg_color_quantizer * quantizer_1pass;
+ struct jpeg_color_quantizer * quantizer_2pass;
+} my_decomp_master;
+
+typedef my_decomp_master * my_master_ptr;
+
+
+/*
+ * Determine whether merged upsample/color conversion should be used.
+ * CRUCIAL: this must match the actual capabilities of jdmerge.c!
+ */
+
+LOCAL(boolean)
+use_merged_upsample (j_decompress_ptr cinfo)
+{
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+ /* Merging is the equivalent of plain box-filter upsampling */
+ if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling)
+ return FALSE;
+ /* jdmerge.c only supports YCC=>RGB color conversion */
+ if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 ||
+ cinfo->out_color_space != JCS_RGB ||
+ cinfo->out_color_components != RGB_PIXELSIZE)
+ return FALSE;
+ /* and it only handles 2h1v or 2h2v sampling ratios */
+ if (cinfo->comp_info[0].h_samp_factor != 2 ||
+ cinfo->comp_info[1].h_samp_factor != 1 ||
+ cinfo->comp_info[2].h_samp_factor != 1 ||
+ cinfo->comp_info[0].v_samp_factor > 2 ||
+ cinfo->comp_info[1].v_samp_factor != 1 ||
+ cinfo->comp_info[2].v_samp_factor != 1)
+ return FALSE;
+ /* furthermore, it doesn't work if we've scaled the IDCTs differently */
+ if (cinfo->comp_info[0].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||
+ cinfo->comp_info[1].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||
+ cinfo->comp_info[2].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||
+ cinfo->comp_info[0].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size ||
+ cinfo->comp_info[1].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size ||
+ cinfo->comp_info[2].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size)
+ return FALSE;
+ /* ??? also need to test for upsample-time rescaling, when & if supported */
+ return TRUE; /* by golly, it'll work... */
+#else
+ return FALSE;
+#endif
+}
+
+
+/*
+ * Compute output image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ * Also note that it may be called before the master module is initialized!
+ */
+
+GLOBAL(void)
+jpeg_calc_output_dimensions (j_decompress_ptr cinfo)
+/* Do computations that are needed before master selection phase.
+ * This function is used for full decompression.
+ */
+{
+#ifdef IDCT_SCALING_SUPPORTED
+ int ci;
+ jpeg_component_info *compptr;
+#endif
+
+ /* Prevent application from calling me at wrong times */
+ if (cinfo->global_state != DSTATE_READY)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* Compute core output image dimensions and DCT scaling choices. */
+ jpeg_core_output_dimensions(cinfo);
+
+#ifdef IDCT_SCALING_SUPPORTED
+
+ /* In selecting the actual DCT scaling for each component, we try to
+ * scale up the chroma components via IDCT scaling rather than upsampling.
+ * This saves time if the upsampler gets to use 1:1 scaling.
+ * Note this code adapts subsampling ratios which are powers of 2.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ int ssize = 1;
+ while (cinfo->min_DCT_h_scaled_size * ssize <=
+ (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) &&
+ (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == 0) {
+ ssize = ssize * 2;
+ }
+ compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize;
+ ssize = 1;
+ while (cinfo->min_DCT_v_scaled_size * ssize <=
+ (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) &&
+ (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == 0) {
+ ssize = ssize * 2;
+ }
+ compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize;
+
+ /* We don't support IDCT ratios larger than 2. */
+ if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2)
+ compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2;
+ else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2)
+ compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2;
+ }
+
+ /* Recompute downsampled dimensions of components;
+ * application needs to know these if using raw downsampled data.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Size in samples, after IDCT scaling */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width *
+ (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size),
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height *
+ (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size),
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+ }
+
+#endif /* IDCT_SCALING_SUPPORTED */
+
+ /* Report number of components in selected colorspace. */
+ /* Probably this should be in the color conversion module... */
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ cinfo->out_color_components = 1;
+ break;
+ case JCS_RGB:
+#if RGB_PIXELSIZE != 3
+ cinfo->out_color_components = RGB_PIXELSIZE;
+ break;
+#endif /* else share code with YCbCr */
+ case JCS_YCbCr:
+ cinfo->out_color_components = 3;
+ break;
+ case JCS_CMYK:
+ case JCS_YCCK:
+ cinfo->out_color_components = 4;
+ break;
+ default: /* else must be same colorspace as in file */
+ cinfo->out_color_components = cinfo->num_components;
+ break;
+ }
+ cinfo->output_components = (cinfo->quantize_colors ? 1 :
+ cinfo->out_color_components);
+
+ /* See if upsampler will want to emit more than one row at a time */
+ if (use_merged_upsample(cinfo))
+ cinfo->rec_outbuf_height = cinfo->max_v_samp_factor;
+ else
+ cinfo->rec_outbuf_height = 1;
+}
+
+
+/*
+ * Several decompression processes need to range-limit values to the range
+ * 0..MAXJSAMPLE; the input value may fall somewhat outside this range
+ * due to noise introduced by quantization, roundoff error, etc. These
+ * processes are inner loops and need to be as fast as possible. On most
+ * machines, particularly CPUs with pipelines or instruction prefetch,
+ * a (subscript-check-less) C table lookup
+ * x = sample_range_limit[x];
+ * is faster than explicit tests
+ * if (x < 0) x = 0;
+ * else if (x > MAXJSAMPLE) x = MAXJSAMPLE;
+ * These processes all use a common table prepared by the routine below.
+ *
+ * For most steps we can mathematically guarantee that the initial value
+ * of x is within MAXJSAMPLE+1 of the legal range, so a table running from
+ * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial
+ * limiting step (just after the IDCT), a wildly out-of-range value is
+ * possible if the input data is corrupt. To avoid any chance of indexing
+ * off the end of memory and getting a bad-pointer trap, we perform the
+ * post-IDCT limiting thus:
+ * x = range_limit[x & MASK];
+ * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit
+ * samples. Under normal circumstances this is more than enough range and
+ * a correct output will be generated; with bogus input data the mask will
+ * cause wraparound, and we will safely generate a bogus-but-in-range output.
+ * For the post-IDCT step, we want to convert the data from signed to unsigned
+ * representation by adding CENTERJSAMPLE at the same time that we limit it.
+ * So the post-IDCT limiting table ends up looking like this:
+ * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE,
+ * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ * 0,1,...,CENTERJSAMPLE-1
+ * Negative inputs select values from the upper half of the table after
+ * masking.
+ *
+ * We can save some space by overlapping the start of the post-IDCT table
+ * with the simpler range limiting table. The post-IDCT table begins at
+ * sample_range_limit + CENTERJSAMPLE.
+ *
+ * Note that the table is allocated in near data space on PCs; it's small
+ * enough and used often enough to justify this.
+ */
+
+LOCAL(void)
+prepare_range_limit_table (j_decompress_ptr cinfo)
+/* Allocate and fill in the sample_range_limit table */
+{
+ JSAMPLE * table;
+ int i;
+
+ table = (JSAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE));
+ table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */
+ cinfo->sample_range_limit = table;
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE));
+ /* Main part of "simple" table: limit[x] = x */
+ for (i = 0; i <= MAXJSAMPLE; i++)
+ table[i] = (JSAMPLE) i;
+ table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++)
+ table[i] = MAXJSAMPLE;
+ /* Second half of post-IDCT table */
+ MEMZERO(table + (2 * (MAXJSAMPLE+1)),
+ (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE));
+ MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE),
+ cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE));
+}
+
+
+/*
+ * Master selection of decompression modules.
+ * This is done once at jpeg_start_decompress time. We determine
+ * which modules will be used and give them appropriate initialization calls.
+ * We also initialize the decompressor input side to begin consuming data.
+ *
+ * Since jpeg_read_header has finished, we know what is in the SOF
+ * and (first) SOS markers. We also have all the application parameter
+ * settings.
+ */
+
+LOCAL(void)
+master_selection (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+ boolean use_c_buffer;
+ long samplesperrow;
+ JDIMENSION jd_samplesperrow;
+
+ /* Initialize dimensions and other stuff */
+ jpeg_calc_output_dimensions(cinfo);
+ prepare_range_limit_table(cinfo);
+
+ /* Width of an output scanline must be representable as JDIMENSION. */
+ samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components;
+ jd_samplesperrow = (JDIMENSION) samplesperrow;
+ if ((long) jd_samplesperrow != samplesperrow)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+
+ /* Initialize my private state */
+ master->pass_number = 0;
+ master->using_merged_upsample = use_merged_upsample(cinfo);
+
+ /* Color quantizer selection */
+ master->quantizer_1pass = NULL;
+ master->quantizer_2pass = NULL;
+ /* No mode changes if not using buffered-image mode. */
+ if (! cinfo->quantize_colors || ! cinfo->buffered_image) {
+ cinfo->enable_1pass_quant = FALSE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+ }
+ if (cinfo->quantize_colors) {
+ if (cinfo->raw_data_out)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+ /* 2-pass quantizer only works in 3-component color space. */
+ if (cinfo->out_color_components != 3) {
+ cinfo->enable_1pass_quant = TRUE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+ cinfo->colormap = NULL;
+ } else if (cinfo->colormap != NULL) {
+ cinfo->enable_external_quant = TRUE;
+ } else if (cinfo->two_pass_quantize) {
+ cinfo->enable_2pass_quant = TRUE;
+ } else {
+ cinfo->enable_1pass_quant = TRUE;
+ }
+
+ if (cinfo->enable_1pass_quant) {
+#ifdef QUANT_1PASS_SUPPORTED
+ jinit_1pass_quantizer(cinfo);
+ master->quantizer_1pass = cinfo->cquantize;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+
+ /* We use the 2-pass code to map to external colormaps. */
+ if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) {
+#ifdef QUANT_2PASS_SUPPORTED
+ jinit_2pass_quantizer(cinfo);
+ master->quantizer_2pass = cinfo->cquantize;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+ /* If both quantizers are initialized, the 2-pass one is left active;
+ * this is necessary for starting with quantization to an external map.
+ */
+ }
+
+ /* Post-processing: in particular, color conversion first */
+ if (! cinfo->raw_data_out) {
+ if (master->using_merged_upsample) {
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+ jinit_merged_upsampler(cinfo); /* does color conversion too */
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ jinit_color_deconverter(cinfo);
+ jinit_upsampler(cinfo);
+ }
+ jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+ }
+ /* Inverse DCT */
+ jinit_inverse_dct(cinfo);
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code)
+ jinit_arith_decoder(cinfo);
+ else {
+ jinit_huff_decoder(cinfo);
+ }
+
+ /* Initialize principal buffer controllers. */
+ use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
+ jinit_d_coef_controller(cinfo, use_c_buffer);
+
+ if (! cinfo->raw_data_out)
+ jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Initialize input side of decompressor to consume first scan. */
+ (*cinfo->inputctl->start_input_pass) (cinfo);
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* If jpeg_start_decompress will read the whole file, initialize
+ * progress monitoring appropriately. The input step is counted
+ * as one pass.
+ */
+ if (cinfo->progress != NULL && ! cinfo->buffered_image &&
+ cinfo->inputctl->has_multiple_scans) {
+ int nscans;
+ /* Estimate number of scans to set pass_limit. */
+ if (cinfo->progressive_mode) {
+ /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
+ nscans = 2 + 3 * cinfo->num_components;
+ } else {
+ /* For a nonprogressive multiscan file, estimate 1 scan per component. */
+ nscans = cinfo->num_components;
+ }
+ cinfo->progress->pass_counter = 0L;
+ cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
+ cinfo->progress->completed_passes = 0;
+ cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2);
+ /* Count the input pass as done */
+ master->pass_number++;
+ }
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+}
+
+
+/*
+ * Per-pass setup.
+ * This is called at the beginning of each output pass. We determine which
+ * modules will be active during this pass and give them appropriate
+ * start_pass calls. We also set is_dummy_pass to indicate whether this
+ * is a "real" output pass or a dummy pass for color quantization.
+ * (In the latter case, jdapistd.c will crank the pass to completion.)
+ */
+
+METHODDEF(void)
+prepare_for_output_pass (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ if (master->pub.is_dummy_pass) {
+#ifdef QUANT_2PASS_SUPPORTED
+ /* Final pass of 2-pass quantization */
+ master->pub.is_dummy_pass = FALSE;
+ (*cinfo->cquantize->start_pass) (cinfo, FALSE);
+ (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST);
+ (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* QUANT_2PASS_SUPPORTED */
+ } else {
+ if (cinfo->quantize_colors && cinfo->colormap == NULL) {
+ /* Select new quantization method */
+ if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) {
+ cinfo->cquantize = master->quantizer_2pass;
+ master->pub.is_dummy_pass = TRUE;
+ } else if (cinfo->enable_1pass_quant) {
+ cinfo->cquantize = master->quantizer_1pass;
+ } else {
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+ }
+ }
+ (*cinfo->idct->start_pass) (cinfo);
+ (*cinfo->coef->start_output_pass) (cinfo);
+ if (! cinfo->raw_data_out) {
+ if (! master->using_merged_upsample)
+ (*cinfo->cconvert->start_pass) (cinfo);
+ (*cinfo->upsample->start_pass) (cinfo);
+ if (cinfo->quantize_colors)
+ (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass);
+ (*cinfo->post->start_pass) (cinfo,
+ (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
+ (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
+ }
+ }
+
+ /* Set up progress monitor's pass info if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->completed_passes = master->pass_number;
+ cinfo->progress->total_passes = master->pass_number +
+ (master->pub.is_dummy_pass ? 2 : 1);
+ /* In buffered-image mode, we assume one more output pass if EOI not
+ * yet reached, but no more passes if EOI has been reached.
+ */
+ if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) {
+ cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1);
+ }
+ }
+}
+
+
+/*
+ * Finish up at end of an output pass.
+ */
+
+METHODDEF(void)
+finish_output_pass (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ if (cinfo->quantize_colors)
+ (*cinfo->cquantize->finish_pass) (cinfo);
+ master->pass_number++;
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Switch to a new external colormap between output passes.
+ */
+
+GLOBAL(void)
+jpeg_new_colormap (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ /* Prevent application from calling me at wrong times */
+ if (cinfo->global_state != DSTATE_BUFIMAGE)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ if (cinfo->quantize_colors && cinfo->enable_external_quant &&
+ cinfo->colormap != NULL) {
+ /* Select 2-pass quantizer for external colormap use */
+ cinfo->cquantize = master->quantizer_2pass;
+ /* Notify quantizer of colormap change */
+ (*cinfo->cquantize->new_color_map) (cinfo);
+ master->pub.is_dummy_pass = FALSE; /* just in case */
+ } else
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+/*
+ * Initialize master decompression control and select active modules.
+ * This is performed at the start of jpeg_start_decompress.
+ */
+
+GLOBAL(void)
+jinit_master_decompress (j_decompress_ptr cinfo)
+{
+ my_master_ptr master;
+
+ master = (my_master_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_decomp_master));
+ cinfo->master = (struct jpeg_decomp_master *) master;
+ master->pub.prepare_for_output_pass = prepare_for_output_pass;
+ master->pub.finish_output_pass = finish_output_pass;
+
+ master->pub.is_dummy_pass = FALSE;
+
+ master_selection(cinfo);
+}
diff --git a/external/jpeg-8c/jdmerge.c b/external/jpeg-8c/jdmerge.c
new file mode 100644
index 0000000..3744446
--- /dev/null
+++ b/external/jpeg-8c/jdmerge.c
@@ -0,0 +1,400 @@
+/*
+ * jdmerge.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains code for merged upsampling/color conversion.
+ *
+ * This file combines functions from jdsample.c and jdcolor.c;
+ * read those files first to understand what's going on.
+ *
+ * When the chroma components are to be upsampled by simple replication
+ * (ie, box filtering), we can save some work in color conversion by
+ * calculating all the output pixels corresponding to a pair of chroma
+ * samples at one time. In the conversion equations
+ * R = Y + K1 * Cr
+ * G = Y + K2 * Cb + K3 * Cr
+ * B = Y + K4 * Cb
+ * only the Y term varies among the group of pixels corresponding to a pair
+ * of chroma samples, so the rest of the terms can be calculated just once.
+ * At typical sampling ratios, this eliminates half or three-quarters of the
+ * multiplications needed for color conversion.
+ *
+ * This file currently provides implementations for the following cases:
+ * YCbCr => RGB color conversion only.
+ * Sampling ratios of 2h1v or 2h2v.
+ * No scaling needed at upsample time.
+ * Corner-aligned (non-CCIR601) sampling alignment.
+ * Other special cases could be added, but in most applications these are
+ * the only common cases. (For uncommon cases we fall back on the more
+ * general code in jdsample.c and jdcolor.c.)
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_upsampler pub; /* public fields */
+
+ /* Pointer to routine to do actual upsampling/conversion of one row group */
+ JMETHOD(void, upmethod, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf));
+
+ /* Private state for YCC->RGB conversion */
+ int * Cr_r_tab; /* => table for Cr to R conversion */
+ int * Cb_b_tab; /* => table for Cb to B conversion */
+ INT32 * Cr_g_tab; /* => table for Cr to G conversion */
+ INT32 * Cb_g_tab; /* => table for Cb to G conversion */
+
+ /* For 2:1 vertical sampling, we produce two output rows at a time.
+ * We need a "spare" row buffer to hold the second output row if the
+ * application provides just a one-row buffer; we also use the spare
+ * to discard the dummy last row if the image height is odd.
+ */
+ JSAMPROW spare_row;
+ boolean spare_full; /* T if spare buffer is occupied */
+
+ JDIMENSION out_row_width; /* samples per output row */
+ JDIMENSION rows_to_go; /* counts rows remaining in image */
+} my_upsampler;
+
+typedef my_upsampler * my_upsample_ptr;
+
+#define SCALEBITS 16 /* speediest right-shift on some machines */
+#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
+#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
+
+
+/*
+ * Initialize tables for YCC->RGB colorspace conversion.
+ * This is taken directly from jdcolor.c; see that file for more info.
+ */
+
+LOCAL(void)
+build_ycc_rgb_table (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ int i;
+ INT32 x;
+ SHIFT_TEMPS
+
+ upsample->Cr_r_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ upsample->Cb_b_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ upsample->Cr_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+ upsample->Cb_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+
+ for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
+ /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ /* Cr=>R value is nearest int to 1.40200 * x */
+ upsample->Cr_r_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
+ /* Cb=>B value is nearest int to 1.77200 * x */
+ upsample->Cb_b_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS);
+ /* Cr=>G value is scaled-up -0.71414 * x */
+ upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x;
+ /* Cb=>G value is scaled-up -0.34414 * x */
+ /* We also add in ONE_HALF so that need not do it in inner loop */
+ upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF;
+ }
+}
+
+
+/*
+ * Initialize for an upsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_merged_upsample (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+ /* Mark the spare buffer empty */
+ upsample->spare_full = FALSE;
+ /* Initialize total-height counter for detecting bottom of image */
+ upsample->rows_to_go = cinfo->output_height;
+}
+
+
+/*
+ * Control routine to do upsampling (and color conversion).
+ *
+ * The control routine just handles the row buffering considerations.
+ */
+
+METHODDEF(void)
+merged_2v_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+/* 2:1 vertical sampling case: may need a spare row. */
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ JSAMPROW work_ptrs[2];
+ JDIMENSION num_rows; /* number of rows returned to caller */
+
+ if (upsample->spare_full) {
+ /* If we have a spare row saved from a previous cycle, just return it. */
+ jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0,
+ 1, upsample->out_row_width);
+ num_rows = 1;
+ upsample->spare_full = FALSE;
+ } else {
+ /* Figure number of rows to return to caller. */
+ num_rows = 2;
+ /* Not more than the distance to the end of the image. */
+ if (num_rows > upsample->rows_to_go)
+ num_rows = upsample->rows_to_go;
+ /* And not more than what the client can accept: */
+ out_rows_avail -= *out_row_ctr;
+ if (num_rows > out_rows_avail)
+ num_rows = out_rows_avail;
+ /* Create output pointer array for upsampler. */
+ work_ptrs[0] = output_buf[*out_row_ctr];
+ if (num_rows > 1) {
+ work_ptrs[1] = output_buf[*out_row_ctr + 1];
+ } else {
+ work_ptrs[1] = upsample->spare_row;
+ upsample->spare_full = TRUE;
+ }
+ /* Now do the upsampling. */
+ (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs);
+ }
+
+ /* Adjust counts */
+ *out_row_ctr += num_rows;
+ upsample->rows_to_go -= num_rows;
+ /* When the buffer is emptied, declare this input row group consumed */
+ if (! upsample->spare_full)
+ (*in_row_group_ctr)++;
+}
+
+
+METHODDEF(void)
+merged_1v_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+/* 1:1 vertical sampling case: much easier, never need a spare row. */
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+ /* Just do the upsampling. */
+ (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr,
+ output_buf + *out_row_ctr);
+ /* Adjust counts */
+ (*out_row_ctr)++;
+ (*in_row_group_ctr)++;
+}
+
+
+/*
+ * These are the routines invoked by the control routines to do
+ * the actual upsampling/conversion. One row group is processed per call.
+ *
+ * Note: since we may be writing directly into application-supplied buffers,
+ * we have to be honest about the output width; we can't assume the buffer
+ * has been rounded up to an even width.
+ */
+
+
+/*
+ * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical.
+ */
+
+METHODDEF(void)
+h2v1_merged_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr;
+ JSAMPROW inptr0, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ SHIFT_TEMPS
+
+ inptr0 = input_buf[0][in_row_group_ctr];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr = output_buf[0];
+ /* Loop for each pair of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 2 Y values and emit 2 pixels */
+ y = GETJSAMPLE(*inptr0++);
+ outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_GREEN] = range_limit[y + cgreen];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
+ outptr += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr0++);
+ outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_GREEN] = range_limit[y + cgreen];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
+ outptr += RGB_PIXELSIZE;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr0);
+ outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_GREEN] = range_limit[y + cgreen];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
+ }
+}
+
+
+/*
+ * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical.
+ */
+
+METHODDEF(void)
+h2v2_merged_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr0, outptr1;
+ JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ SHIFT_TEMPS
+
+ inptr00 = input_buf[0][in_row_group_ctr*2];
+ inptr01 = input_buf[0][in_row_group_ctr*2 + 1];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr0 = output_buf[0];
+ outptr1 = output_buf[1];
+ /* Loop for each group of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 4 Y values and emit 4 pixels */
+ y = GETJSAMPLE(*inptr00++);
+ outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_GREEN] = range_limit[y + cgreen];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
+ outptr0 += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr00++);
+ outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_GREEN] = range_limit[y + cgreen];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
+ outptr0 += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr01++);
+ outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_GREEN] = range_limit[y + cgreen];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
+ outptr1 += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr01++);
+ outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_GREEN] = range_limit[y + cgreen];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
+ outptr1 += RGB_PIXELSIZE;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr00);
+ outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_GREEN] = range_limit[y + cgreen];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
+ y = GETJSAMPLE(*inptr01);
+ outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_GREEN] = range_limit[y + cgreen];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
+ }
+}
+
+
+/*
+ * Module initialization routine for merged upsampling/color conversion.
+ *
+ * NB: this is called under the conditions determined by use_merged_upsample()
+ * in jdmaster.c. That routine MUST correspond to the actual capabilities
+ * of this module; no safety checks are made here.
+ */
+
+GLOBAL(void)
+jinit_merged_upsampler (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample;
+
+ upsample = (my_upsample_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_upsampler));
+ cinfo->upsample = (struct jpeg_upsampler *) upsample;
+ upsample->pub.start_pass = start_pass_merged_upsample;
+ upsample->pub.need_context_rows = FALSE;
+
+ upsample->out_row_width = cinfo->output_width * cinfo->out_color_components;
+
+ if (cinfo->max_v_samp_factor == 2) {
+ upsample->pub.upsample = merged_2v_upsample;
+ upsample->upmethod = h2v2_merged_upsample;
+ /* Allocate a spare row buffer */
+ upsample->spare_row = (JSAMPROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE)));
+ } else {
+ upsample->pub.upsample = merged_1v_upsample;
+ upsample->upmethod = h2v1_merged_upsample;
+ /* No spare row needed */
+ upsample->spare_row = NULL;
+ }
+
+ build_ycc_rgb_table(cinfo);
+}
+
+#endif /* UPSAMPLE_MERGING_SUPPORTED */
diff --git a/external/jpeg-8c/jdpostct.c b/external/jpeg-8c/jdpostct.c
new file mode 100644
index 0000000..571563d
--- /dev/null
+++ b/external/jpeg-8c/jdpostct.c
@@ -0,0 +1,290 @@
+/*
+ * jdpostct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the decompression postprocessing controller.
+ * This controller manages the upsampling, color conversion, and color
+ * quantization/reduction steps; specifically, it controls the buffering
+ * between upsample/color conversion and color quantization/reduction.
+ *
+ * If no color quantization/reduction is required, then this module has no
+ * work to do, and it just hands off to the upsample/color conversion code.
+ * An integrated upsample/convert/quantize process would replace this module
+ * entirely.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_d_post_controller pub; /* public fields */
+
+ /* Color quantization source buffer: this holds output data from
+ * the upsample/color conversion step to be passed to the quantizer.
+ * For two-pass color quantization, we need a full-image buffer;
+ * for one-pass operation, a strip buffer is sufficient.
+ */
+ jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */
+ JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */
+ JDIMENSION strip_height; /* buffer size in rows */
+ /* for two-pass mode only: */
+ JDIMENSION starting_row; /* row # of first row in current strip */
+ JDIMENSION next_row; /* index of next row to fill/empty in strip */
+} my_post_controller;
+
+typedef my_post_controller * my_post_ptr;
+
+
+/* Forward declarations */
+METHODDEF(void) post_process_1pass
+ JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+#ifdef QUANT_2PASS_SUPPORTED
+METHODDEF(void) post_process_prepass
+ JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+METHODDEF(void) post_process_2pass
+ JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+#endif
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (cinfo->quantize_colors) {
+ /* Single-pass processing with color quantization. */
+ post->pub.post_process_data = post_process_1pass;
+ /* We could be doing buffered-image output before starting a 2-pass
+ * color quantization; in that case, jinit_d_post_controller did not
+ * allocate a strip buffer. Use the virtual-array buffer as workspace.
+ */
+ if (post->buffer == NULL) {
+ post->buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, post->whole_image,
+ (JDIMENSION) 0, post->strip_height, TRUE);
+ }
+ } else {
+ /* For single-pass processing without color quantization,
+ * I have no work to do; just call the upsampler directly.
+ */
+ post->pub.post_process_data = cinfo->upsample->upsample;
+ }
+ break;
+#ifdef QUANT_2PASS_SUPPORTED
+ case JBUF_SAVE_AND_PASS:
+ /* First pass of 2-pass quantization */
+ if (post->whole_image == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ post->pub.post_process_data = post_process_prepass;
+ break;
+ case JBUF_CRANK_DEST:
+ /* Second pass of 2-pass quantization */
+ if (post->whole_image == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ post->pub.post_process_data = post_process_2pass;
+ break;
+#endif /* QUANT_2PASS_SUPPORTED */
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+ post->starting_row = post->next_row = 0;
+}
+
+
+/*
+ * Process some data in the one-pass (strip buffer) case.
+ * This is used for color precision reduction as well as one-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_1pass (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+ JDIMENSION num_rows, max_rows;
+
+ /* Fill the buffer, but not more than what we can dump out in one go. */
+ /* Note we rely on the upsampler to detect bottom of image. */
+ max_rows = out_rows_avail - *out_row_ctr;
+ if (max_rows > post->strip_height)
+ max_rows = post->strip_height;
+ num_rows = 0;
+ (*cinfo->upsample->upsample) (cinfo,
+ input_buf, in_row_group_ctr, in_row_groups_avail,
+ post->buffer, &num_rows, max_rows);
+ /* Quantize and emit data. */
+ (*cinfo->cquantize->color_quantize) (cinfo,
+ post->buffer, output_buf + *out_row_ctr, (int) num_rows);
+ *out_row_ctr += num_rows;
+}
+
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+/*
+ * Process some data in the first pass of 2-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_prepass (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+ JDIMENSION old_next_row, num_rows;
+
+ /* Reposition virtual buffer if at start of strip. */
+ if (post->next_row == 0) {
+ post->buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, post->whole_image,
+ post->starting_row, post->strip_height, TRUE);
+ }
+
+ /* Upsample some data (up to a strip height's worth). */
+ old_next_row = post->next_row;
+ (*cinfo->upsample->upsample) (cinfo,
+ input_buf, in_row_group_ctr, in_row_groups_avail,
+ post->buffer, &post->next_row, post->strip_height);
+
+ /* Allow quantizer to scan new data. No data is emitted, */
+ /* but we advance out_row_ctr so outer loop can tell when we're done. */
+ if (post->next_row > old_next_row) {
+ num_rows = post->next_row - old_next_row;
+ (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row,
+ (JSAMPARRAY) NULL, (int) num_rows);
+ *out_row_ctr += num_rows;
+ }
+
+ /* Advance if we filled the strip. */
+ if (post->next_row >= post->strip_height) {
+ post->starting_row += post->strip_height;
+ post->next_row = 0;
+ }
+}
+
+
+/*
+ * Process some data in the second pass of 2-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_2pass (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+ JDIMENSION num_rows, max_rows;
+
+ /* Reposition virtual buffer if at start of strip. */
+ if (post->next_row == 0) {
+ post->buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, post->whole_image,
+ post->starting_row, post->strip_height, FALSE);
+ }
+
+ /* Determine number of rows to emit. */
+ num_rows = post->strip_height - post->next_row; /* available in strip */
+ max_rows = out_rows_avail - *out_row_ctr; /* available in output area */
+ if (num_rows > max_rows)
+ num_rows = max_rows;
+ /* We have to check bottom of image here, can't depend on upsampler. */
+ max_rows = cinfo->output_height - post->starting_row;
+ if (num_rows > max_rows)
+ num_rows = max_rows;
+
+ /* Quantize and emit data. */
+ (*cinfo->cquantize->color_quantize) (cinfo,
+ post->buffer + post->next_row, output_buf + *out_row_ctr,
+ (int) num_rows);
+ *out_row_ctr += num_rows;
+
+ /* Advance if we filled the strip. */
+ post->next_row += num_rows;
+ if (post->next_row >= post->strip_height) {
+ post->starting_row += post->strip_height;
+ post->next_row = 0;
+ }
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
+
+
+/*
+ * Initialize postprocessing controller.
+ */
+
+GLOBAL(void)
+jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+ my_post_ptr post;
+
+ post = (my_post_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_post_controller));
+ cinfo->post = (struct jpeg_d_post_controller *) post;
+ post->pub.start_pass = start_pass_dpost;
+ post->whole_image = NULL; /* flag for no virtual arrays */
+ post->buffer = NULL; /* flag for no strip buffer */
+
+ /* Create the quantization buffer, if needed */
+ if (cinfo->quantize_colors) {
+ /* The buffer strip height is max_v_samp_factor, which is typically
+ * an efficient number of rows for upsampling to return.
+ * (In the presence of output rescaling, we might want to be smarter?)
+ */
+ post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor;
+ if (need_full_buffer) {
+ /* Two-pass color quantization: need full-image storage. */
+ /* We round up the number of rows to a multiple of the strip height. */
+#ifdef QUANT_2PASS_SUPPORTED
+ post->whole_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ cinfo->output_width * cinfo->out_color_components,
+ (JDIMENSION) jround_up((long) cinfo->output_height,
+ (long) post->strip_height),
+ post->strip_height);
+#else
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif /* QUANT_2PASS_SUPPORTED */
+ } else {
+ /* One-pass color quantization: just make a strip buffer. */
+ post->buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->output_width * cinfo->out_color_components,
+ post->strip_height);
+ }
+ }
+}
diff --git a/external/jpeg-8c/jdsample.c b/external/jpeg-8c/jdsample.c
new file mode 100644
index 0000000..7bc8885
--- /dev/null
+++ b/external/jpeg-8c/jdsample.c
@@ -0,0 +1,361 @@
+/*
+ * jdsample.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2002-2008 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains upsampling routines.
+ *
+ * Upsampling input data is counted in "row groups". A row group
+ * is defined to be (v_samp_factor * DCT_v_scaled_size / min_DCT_v_scaled_size)
+ * sample rows of each component. Upsampling will normally produce
+ * max_v_samp_factor pixel rows from each row group (but this could vary
+ * if the upsampler is applying a scale factor of its own).
+ *
+ * An excellent reference for image resampling is
+ * Digital Image Warping, George Wolberg, 1990.
+ * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Pointer to routine to upsample a single component */
+typedef JMETHOD(void, upsample1_ptr,
+ (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr));
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_upsampler pub; /* public fields */
+
+ /* Color conversion buffer. When using separate upsampling and color
+ * conversion steps, this buffer holds one upsampled row group until it
+ * has been color converted and output.
+ * Note: we do not allocate any storage for component(s) which are full-size,
+ * ie do not need rescaling. The corresponding entry of color_buf[] is
+ * simply set to point to the input data array, thereby avoiding copying.
+ */
+ JSAMPARRAY color_buf[MAX_COMPONENTS];
+
+ /* Per-component upsampling method pointers */
+ upsample1_ptr methods[MAX_COMPONENTS];
+
+ int next_row_out; /* counts rows emitted from color_buf */
+ JDIMENSION rows_to_go; /* counts rows remaining in image */
+
+ /* Height of an input row group for each component. */
+ int rowgroup_height[MAX_COMPONENTS];
+
+ /* These arrays save pixel expansion factors so that int_expand need not
+ * recompute them each time. They are unused for other upsampling methods.
+ */
+ UINT8 h_expand[MAX_COMPONENTS];
+ UINT8 v_expand[MAX_COMPONENTS];
+} my_upsampler;
+
+typedef my_upsampler * my_upsample_ptr;
+
+
+/*
+ * Initialize for an upsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_upsample (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+ /* Mark the conversion buffer empty */
+ upsample->next_row_out = cinfo->max_v_samp_factor;
+ /* Initialize total-height counter for detecting bottom of image */
+ upsample->rows_to_go = cinfo->output_height;
+}
+
+
+/*
+ * Control routine to do upsampling (and color conversion).
+ *
+ * In this version we upsample each component independently.
+ * We upsample one row group into the conversion buffer, then apply
+ * color conversion a row at a time.
+ */
+
+METHODDEF(void)
+sep_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ int ci;
+ jpeg_component_info * compptr;
+ JDIMENSION num_rows;
+
+ /* Fill the conversion buffer, if it's empty */
+ if (upsample->next_row_out >= cinfo->max_v_samp_factor) {
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Invoke per-component upsample method. Notice we pass a POINTER
+ * to color_buf[ci], so that fullsize_upsample can change it.
+ */
+ (*upsample->methods[ci]) (cinfo, compptr,
+ input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]),
+ upsample->color_buf + ci);
+ }
+ upsample->next_row_out = 0;
+ }
+
+ /* Color-convert and emit rows */
+
+ /* How many we have in the buffer: */
+ num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out);
+ /* Not more than the distance to the end of the image. Need this test
+ * in case the image height is not a multiple of max_v_samp_factor:
+ */
+ if (num_rows > upsample->rows_to_go)
+ num_rows = upsample->rows_to_go;
+ /* And not more than what the client can accept: */
+ out_rows_avail -= *out_row_ctr;
+ if (num_rows > out_rows_avail)
+ num_rows = out_rows_avail;
+
+ (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf,
+ (JDIMENSION) upsample->next_row_out,
+ output_buf + *out_row_ctr,
+ (int) num_rows);
+
+ /* Adjust counts */
+ *out_row_ctr += num_rows;
+ upsample->rows_to_go -= num_rows;
+ upsample->next_row_out += num_rows;
+ /* When the buffer is emptied, declare this input row group consumed */
+ if (upsample->next_row_out >= cinfo->max_v_samp_factor)
+ (*in_row_group_ctr)++;
+}
+
+
+/*
+ * These are the routines invoked by sep_upsample to upsample pixel values
+ * of a single component. One row group is processed per call.
+ */
+
+
+/*
+ * For full-size components, we just make color_buf[ci] point at the
+ * input buffer, and thus avoid copying any data. Note that this is
+ * safe only because sep_upsample doesn't declare the input row group
+ * "consumed" until we are done color converting and emitting it.
+ */
+
+METHODDEF(void)
+fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ *output_data_ptr = input_data;
+}
+
+
+/*
+ * This is a no-op version used for "uninteresting" components.
+ * These components will not be referenced by color conversion.
+ */
+
+METHODDEF(void)
+noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ *output_data_ptr = NULL; /* safety check */
+}
+
+
+/*
+ * This version handles any integral sampling ratios.
+ * This is not used for typical JPEG files, so it need not be fast.
+ * Nor, for that matter, is it particularly accurate: the algorithm is
+ * simple replication of the input pixel onto the corresponding output
+ * pixels. The hi-falutin sampling literature refers to this as a
+ * "box filter". A box filter tends to introduce visible artifacts,
+ * so if you are actually going to use 3:1 or 4:1 sampling ratios
+ * you would be well advised to improve this code.
+ */
+
+METHODDEF(void)
+int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ JSAMPARRAY output_data = *output_data_ptr;
+ register JSAMPROW inptr, outptr;
+ register JSAMPLE invalue;
+ register int h;
+ JSAMPROW outend;
+ int h_expand, v_expand;
+ int inrow, outrow;
+
+ h_expand = upsample->h_expand[compptr->component_index];
+ v_expand = upsample->v_expand[compptr->component_index];
+
+ inrow = outrow = 0;
+ while (outrow < cinfo->max_v_samp_factor) {
+ /* Generate one output row with proper horizontal expansion */
+ inptr = input_data[inrow];
+ outptr = output_data[outrow];
+ outend = outptr + cinfo->output_width;
+ while (outptr < outend) {
+ invalue = *inptr++; /* don't need GETJSAMPLE() here */
+ for (h = h_expand; h > 0; h--) {
+ *outptr++ = invalue;
+ }
+ }
+ /* Generate any additional output rows by duplicating the first one */
+ if (v_expand > 1) {
+ jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
+ v_expand-1, cinfo->output_width);
+ }
+ inrow++;
+ outrow += v_expand;
+ }
+}
+
+
+/*
+ * Fast processing for the common case of 2:1 horizontal and 1:1 vertical.
+ * It's still a box filter.
+ */
+
+METHODDEF(void)
+h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ JSAMPARRAY output_data = *output_data_ptr;
+ register JSAMPROW inptr, outptr;
+ register JSAMPLE invalue;
+ JSAMPROW outend;
+ int outrow;
+
+ for (outrow = 0; outrow < cinfo->max_v_samp_factor; outrow++) {
+ inptr = input_data[outrow];
+ outptr = output_data[outrow];
+ outend = outptr + cinfo->output_width;
+ while (outptr < outend) {
+ invalue = *inptr++; /* don't need GETJSAMPLE() here */
+ *outptr++ = invalue;
+ *outptr++ = invalue;
+ }
+ }
+}
+
+
+/*
+ * Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
+ * It's still a box filter.
+ */
+
+METHODDEF(void)
+h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ JSAMPARRAY output_data = *output_data_ptr;
+ register JSAMPROW inptr, outptr;
+ register JSAMPLE invalue;
+ JSAMPROW outend;
+ int inrow, outrow;
+
+ inrow = outrow = 0;
+ while (outrow < cinfo->max_v_samp_factor) {
+ inptr = input_data[inrow];
+ outptr = output_data[outrow];
+ outend = outptr + cinfo->output_width;
+ while (outptr < outend) {
+ invalue = *inptr++; /* don't need GETJSAMPLE() here */
+ *outptr++ = invalue;
+ *outptr++ = invalue;
+ }
+ jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
+ 1, cinfo->output_width);
+ inrow++;
+ outrow += 2;
+ }
+}
+
+
+/*
+ * Module initialization routine for upsampling.
+ */
+
+GLOBAL(void)
+jinit_upsampler (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample;
+ int ci;
+ jpeg_component_info * compptr;
+ boolean need_buffer;
+ int h_in_group, v_in_group, h_out_group, v_out_group;
+
+ upsample = (my_upsample_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_upsampler));
+ cinfo->upsample = (struct jpeg_upsampler *) upsample;
+ upsample->pub.start_pass = start_pass_upsample;
+ upsample->pub.upsample = sep_upsample;
+ upsample->pub.need_context_rows = FALSE; /* until we find out differently */
+
+ if (cinfo->CCIR601_sampling) /* this isn't supported */
+ ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
+
+ /* Verify we can handle the sampling factors, select per-component methods,
+ * and create storage as needed.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Compute size of an "input group" after IDCT scaling. This many samples
+ * are to be converted to max_h_samp_factor * max_v_samp_factor pixels.
+ */
+ h_in_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) /
+ cinfo->min_DCT_h_scaled_size;
+ v_in_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size;
+ h_out_group = cinfo->max_h_samp_factor;
+ v_out_group = cinfo->max_v_samp_factor;
+ upsample->rowgroup_height[ci] = v_in_group; /* save for use later */
+ need_buffer = TRUE;
+ if (! compptr->component_needed) {
+ /* Don't bother to upsample an uninteresting component. */
+ upsample->methods[ci] = noop_upsample;
+ need_buffer = FALSE;
+ } else if (h_in_group == h_out_group && v_in_group == v_out_group) {
+ /* Fullsize components can be processed without any work. */
+ upsample->methods[ci] = fullsize_upsample;
+ need_buffer = FALSE;
+ } else if (h_in_group * 2 == h_out_group &&
+ v_in_group == v_out_group) {
+ /* Special case for 2h1v upsampling */
+ upsample->methods[ci] = h2v1_upsample;
+ } else if (h_in_group * 2 == h_out_group &&
+ v_in_group * 2 == v_out_group) {
+ /* Special case for 2h2v upsampling */
+ upsample->methods[ci] = h2v2_upsample;
+ } else if ((h_out_group % h_in_group) == 0 &&
+ (v_out_group % v_in_group) == 0) {
+ /* Generic integral-factors upsampling method */
+ upsample->methods[ci] = int_upsample;
+ upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group);
+ upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group);
+ } else
+ ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
+ if (need_buffer) {
+ upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) jround_up((long) cinfo->output_width,
+ (long) cinfo->max_h_samp_factor),
+ (JDIMENSION) cinfo->max_v_samp_factor);
+ }
+ }
+}
diff --git a/external/jpeg-8c/jdtrans.c b/external/jpeg-8c/jdtrans.c
new file mode 100644
index 0000000..e358b1b
--- /dev/null
+++ b/external/jpeg-8c/jdtrans.c
@@ -0,0 +1,140 @@
+/*
+ * jdtrans.c
+ *
+ * Copyright (C) 1995-1997, Thomas G. Lane.
+ * Modified 2000-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains library routines for transcoding decompression,
+ * that is, reading raw DCT coefficient arrays from an input JPEG file.
+ * The routines in jdapimin.c will also be needed by a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Read the coefficient arrays from a JPEG file.
+ * jpeg_read_header must be completed before calling this.
+ *
+ * The entire image is read into a set of virtual coefficient-block arrays,
+ * one per component. The return value is a pointer to the array of
+ * virtual-array descriptors. These can be manipulated directly via the
+ * JPEG memory manager, or handed off to jpeg_write_coefficients().
+ * To release the memory occupied by the virtual arrays, call
+ * jpeg_finish_decompress() when done with the data.
+ *
+ * An alternative usage is to simply obtain access to the coefficient arrays
+ * during a buffered-image-mode decompression operation. This is allowed
+ * after any jpeg_finish_output() call. The arrays can be accessed until
+ * jpeg_finish_decompress() is called. (Note that any call to the library
+ * may reposition the arrays, so don't rely on access_virt_barray() results
+ * to stay valid across library calls.)
+ *
+ * Returns NULL if suspended. This case need be checked only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(jvirt_barray_ptr *)
+jpeg_read_coefficients (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state == DSTATE_READY) {
+ /* First call: initialize active modules */
+ transdecode_master_selection(cinfo);
+ cinfo->global_state = DSTATE_RDCOEFS;
+ }
+ if (cinfo->global_state == DSTATE_RDCOEFS) {
+ /* Absorb whole file into the coef buffer */
+ for (;;) {
+ int retcode;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL)
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ /* Absorb some more input */
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ if (retcode == JPEG_SUSPENDED)
+ return NULL;
+ if (retcode == JPEG_REACHED_EOI)
+ break;
+ /* Advance progress counter if appropriate */
+ if (cinfo->progress != NULL &&
+ (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+ if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
+ /* startup underestimated number of scans; ratchet up one scan */
+ cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
+ }
+ }
+ }
+ /* Set state so that jpeg_finish_decompress does the right thing */
+ cinfo->global_state = DSTATE_STOPPING;
+ }
+ /* At this point we should be in state DSTATE_STOPPING if being used
+ * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access
+ * to the coefficients during a full buffered-image-mode decompression.
+ */
+ if ((cinfo->global_state == DSTATE_STOPPING ||
+ cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) {
+ return cinfo->coef->coef_arrays;
+ }
+ /* Oops, improper usage */
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ return NULL; /* keep compiler happy */
+}
+
+
+/*
+ * Master selection of decompression modules for transcoding.
+ * This substitutes for jdmaster.c's initialization of the full decompressor.
+ */
+
+LOCAL(void)
+transdecode_master_selection (j_decompress_ptr cinfo)
+{
+ /* This is effectively a buffered-image operation. */
+ cinfo->buffered_image = TRUE;
+
+ /* Compute output image dimensions and related values. */
+ jpeg_core_output_dimensions(cinfo);
+
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code)
+ jinit_arith_decoder(cinfo);
+ else {
+ jinit_huff_decoder(cinfo);
+ }
+
+ /* Always get a full-image coefficient buffer. */
+ jinit_d_coef_controller(cinfo, TRUE);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Initialize input side of decompressor to consume first scan. */
+ (*cinfo->inputctl->start_input_pass) (cinfo);
+
+ /* Initialize progress monitoring. */
+ if (cinfo->progress != NULL) {
+ int nscans;
+ /* Estimate number of scans to set pass_limit. */
+ if (cinfo->progressive_mode) {
+ /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
+ nscans = 2 + 3 * cinfo->num_components;
+ } else if (cinfo->inputctl->has_multiple_scans) {
+ /* For a nonprogressive multiscan file, estimate 1 scan per component. */
+ nscans = cinfo->num_components;
+ } else {
+ nscans = 1;
+ }
+ cinfo->progress->pass_counter = 0L;
+ cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
+ cinfo->progress->completed_passes = 0;
+ cinfo->progress->total_passes = 1;
+ }
+}
diff --git a/external/jpeg-8c/jerror.c b/external/jpeg-8c/jerror.c
new file mode 100644
index 0000000..2860d3f
--- /dev/null
+++ b/external/jpeg-8c/jerror.c
@@ -0,0 +1,254 @@
+/*
+ * jerror.c
+ *
+ * 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 contains simple error-reporting and trace-message routines.
+ * These are suitable for Unix-like systems and others where writing to
+ * stderr is the right thing to do. Many applications will want to replace
+ * some or all of these routines.
+ *
+ * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile,
+ * you get a Windows-specific hack to display error messages in a dialog box.
+ * It ain't much, but it beats dropping error messages into the bit bucket,
+ * which is what happens to output to stderr under most Windows C compilers.
+ *
+ * These routines are used by both the compression and decompression code.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jversion.h"
+#include "jerror.h"
+
+#include <stdlib.h>
+
+#ifdef USE_WINDOWS_MESSAGEBOX
+#include <windows.h>
+#endif
+
+#ifndef EXIT_FAILURE /* define exit() codes if not provided */
+#define EXIT_FAILURE 1
+#endif
+
+
+/*
+ * Create the message string table.
+ * We do this from the master message list in jerror.h by re-reading
+ * jerror.h with a suitable definition for macro JMESSAGE.
+ * The message table is made an external symbol just in case any applications
+ * want to refer to it directly.
+ */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_std_message_table jMsgTable
+#endif
+
+#define JMESSAGE(code,string) string ,
+
+const char * const jpeg_std_message_table[] = {
+#include "jerror.h"
+ NULL
+};
+
+
+/*
+ * Error exit handler: must not return to caller.
+ *
+ * Applications may override this if they want to get control back after
+ * an error. Typically one would longjmp somewhere instead of exiting.
+ * The setjmp buffer can be made a private field within an expanded error
+ * handler object. Note that the info needed to generate an error message
+ * is stored in the error object, so you can generate the message now or
+ * later, at your convenience.
+ * You should make sure that the JPEG object is cleaned up (with jpeg_abort
+ * or jpeg_destroy) at some point.
+ */
+
+METHODDEF(void)
+error_exit (j_common_ptr cinfo)
+{
+ /* Always display the message */
+ (*cinfo->err->output_message) (cinfo);
+
+ /* Let the memory manager delete any temp files before we die */
+ jpeg_destroy(cinfo);
+
+ exit(EXIT_FAILURE);
+}
+
+
+/*
+ * Actual output of an error or trace message.
+ * Applications may override this method to send JPEG messages somewhere
+ * other than stderr.
+ *
+ * On Windows, printing to stderr is generally completely useless,
+ * so we provide optional code to produce an error-dialog popup.
+ * Most Windows applications will still prefer to override this routine,
+ * but if they don't, it'll do something at least marginally useful.
+ *
+ * NOTE: to use the library in an environment that doesn't support the
+ * C stdio library, you may have to delete the call to fprintf() entirely,
+ * not just not use this routine.
+ */
+
+METHODDEF(void)
+output_message (j_common_ptr cinfo)
+{
+ char buffer[JMSG_LENGTH_MAX];
+
+ /* Create the message */
+ (*cinfo->err->format_message) (cinfo, buffer);
+
+#ifdef USE_WINDOWS_MESSAGEBOX
+ /* Display it in a message dialog box */
+ MessageBox(GetActiveWindow(), buffer, "JPEG Library Error",
+ MB_OK | MB_ICONERROR);
+#else
+ /* Send it to stderr, adding a newline */
+ fprintf(stderr, "%s\n", buffer);
+#endif
+}
+
+
+/*
+ * Decide whether to emit a trace or warning message.
+ * msg_level is one of:
+ * -1: recoverable corrupt-data warning, may want to abort.
+ * 0: important advisory messages (always display to user).
+ * 1: first level of tracing detail.
+ * 2,3,...: successively more detailed tracing messages.
+ * An application might override this method if it wanted to abort on warnings
+ * or change the policy about which messages to display.
+ */
+
+METHODDEF(void)
+emit_message (j_common_ptr cinfo, int msg_level)
+{
+ struct jpeg_error_mgr * err = cinfo->err;
+
+ if (msg_level < 0) {
+ /* It's a warning message. Since corrupt files may generate many warnings,
+ * the policy implemented here is to show only the first warning,
+ * unless trace_level >= 3.
+ */
+ if (err->num_warnings == 0 || err->trace_level >= 3)
+ (*err->output_message) (cinfo);
+ /* Always count warnings in num_warnings. */
+ err->num_warnings++;
+ } else {
+ /* It's a trace message. Show it if trace_level >= msg_level. */
+ if (err->trace_level >= msg_level)
+ (*err->output_message) (cinfo);
+ }
+}
+
+
+/*
+ * Format a message string for the most recent JPEG error or message.
+ * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX
+ * characters. Note that no '\n' character is added to the string.
+ * Few applications should need to override this method.
+ */
+
+METHODDEF(void)
+format_message (j_common_ptr cinfo, char * buffer)
+{
+ struct jpeg_error_mgr * err = cinfo->err;
+ int msg_code = err->msg_code;
+ const char * msgtext = NULL;
+ const char * msgptr;
+ char ch;
+ boolean isstring;
+
+ /* Look up message string in proper table */
+ if (msg_code > 0 && msg_code <= err->last_jpeg_message) {
+ msgtext = err->jpeg_message_table[msg_code];
+ } else if (err->addon_message_table != NULL &&
+ msg_code >= err->first_addon_message &&
+ msg_code <= err->last_addon_message) {
+ msgtext = err->addon_message_table[msg_code - err->first_addon_message];
+ }
+
+ /* Defend against bogus message number */
+ if (msgtext == NULL) {
+ err->msg_parm.i[0] = msg_code;
+ msgtext = err->jpeg_message_table[0];
+ }
+
+ /* Check for string parameter, as indicated by %s in the message text */
+ isstring = FALSE;
+ msgptr = msgtext;
+ while ((ch = *msgptr++) != '\0') {
+ if (ch == '%') {
+ if (*msgptr == 's') isstring = TRUE;
+ break;
+ }
+ }
+
+ /* Format the message into the passed buffer */
+ if (isstring)
+ sprintf(buffer, msgtext, err->msg_parm.s);
+ else
+ sprintf(buffer, msgtext,
+ err->msg_parm.i[0], err->msg_parm.i[1],
+ err->msg_parm.i[2], err->msg_parm.i[3],
+ err->msg_parm.i[4], err->msg_parm.i[5],
+ err->msg_parm.i[6], err->msg_parm.i[7]);
+}
+
+
+/*
+ * Reset error state variables at start of a new image.
+ * This is called during compression startup to reset trace/error
+ * processing to default state, without losing any application-specific
+ * method pointers. An application might possibly want to override
+ * this method if it has additional error processing state.
+ */
+
+METHODDEF(void)
+reset_error_mgr (j_common_ptr cinfo)
+{
+ cinfo->err->num_warnings = 0;
+ /* trace_level is not reset since it is an application-supplied parameter */
+ cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */
+}
+
+
+/*
+ * Fill in the standard error-handling methods in a jpeg_error_mgr object.
+ * Typical call is:
+ * struct jpeg_compress_struct cinfo;
+ * struct jpeg_error_mgr err;
+ *
+ * cinfo.err = jpeg_std_error(&err);
+ * after which the application may override some of the methods.
+ */
+
+GLOBAL(struct jpeg_error_mgr *)
+jpeg_std_error (struct jpeg_error_mgr * err)
+{
+ err->error_exit = error_exit;
+ err->emit_message = emit_message;
+ err->output_message = output_message;
+ err->format_message = format_message;
+ err->reset_error_mgr = reset_error_mgr;
+
+ err->trace_level = 0; /* default = no tracing */
+ err->num_warnings = 0; /* no warnings emitted yet */
+ err->msg_code = 0; /* may be useful as a flag for "no error" */
+
+ /* Initialize message table pointers */
+ err->jpeg_message_table = jpeg_std_message_table;
+ err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1;
+
+ err->addon_message_table = NULL;
+ err->first_addon_message = 0; /* for safety */
+ err->last_addon_message = 0;
+
+ return err;
+}
diff --git a/external/jpeg-8c/jerror.h b/external/jpeg-8c/jerror.h
new file mode 100644
index 0000000..1cfb2b1
--- /dev/null
+++ b/external/jpeg-8c/jerror.h
@@ -0,0 +1,304 @@
+/*
+ * jerror.h
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 1997-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the error and message codes for the JPEG library.
+ * Edit this file to add new codes, or to translate the message strings to
+ * some other language.
+ * A set of error-reporting macros are defined too. Some applications using
+ * the JPEG library may wish to include this file to get the error codes
+ * and/or the macros.
+ */
+
+/*
+ * To define the enum list of message codes, include this file without
+ * defining macro JMESSAGE. To create a message string table, include it
+ * again with a suitable JMESSAGE definition (see jerror.c for an example).
+ */
+#ifndef JMESSAGE
+#ifndef JERROR_H
+/* First time through, define the enum list */
+#define JMAKE_ENUM_LIST
+#else
+/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */
+#define JMESSAGE(code,string)
+#endif /* JERROR_H */
+#endif /* JMESSAGE */
+
+#ifdef JMAKE_ENUM_LIST
+
+typedef enum {
+
+#define JMESSAGE(code,string) code ,
+
+#endif /* JMAKE_ENUM_LIST */
+
+JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */
+
+/* For maintenance convenience, list is alphabetical by message code name */
+JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix")
+JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
+JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
+JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
+JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
+JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
+JMESSAGE(JERR_BAD_DCTSIZE, "DCT scaled block size %dx%d not supported")
+JMESSAGE(JERR_BAD_DROP_SAMPLING,
+ "Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c")
+JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition")
+JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace")
+JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace")
+JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length")
+JMESSAGE(JERR_BAD_LIB_VERSION,
+ "Wrong JPEG library version: library is %d, caller expects %d")
+JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan")
+JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d")
+JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d")
+JMESSAGE(JERR_BAD_PROGRESSION,
+ "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d")
+JMESSAGE(JERR_BAD_PROG_SCRIPT,
+ "Invalid progressive parameters at scan script entry %d")
+JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors")
+JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d")
+JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d")
+JMESSAGE(JERR_BAD_STRUCT_SIZE,
+ "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u")
+JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access")
+JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small")
+JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here")
+JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet")
+JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d")
+JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request")
+JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d")
+JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x")
+JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d")
+JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d")
+JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)")
+JMESSAGE(JERR_EMS_READ, "Read from EMS failed")
+JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed")
+JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan")
+JMESSAGE(JERR_FILE_READ, "Input file read error")
+JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?")
+JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet")
+JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow")
+JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry")
+JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels")
+JMESSAGE(JERR_INPUT_EMPTY, "Empty input file")
+JMESSAGE(JERR_INPUT_EOF, "Premature end of input file")
+JMESSAGE(JERR_MISMATCHED_QUANT_TABLE,
+ "Cannot transcode due to multiple use of quantization table %d")
+JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data")
+JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change")
+JMESSAGE(JERR_NOTIMPL, "Not implemented yet")
+JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
+JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined")
+JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
+JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
+JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
+JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined")
+JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x")
+JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)")
+JMESSAGE(JERR_QUANT_COMPONENTS,
+ "Cannot quantize more than %d color components")
+JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors")
+JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors")
+JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers")
+JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker")
+JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x")
+JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers")
+JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF")
+JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s")
+JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file")
+JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file")
+JMESSAGE(JERR_TFILE_WRITE,
+ "Write failed on temporary file --- out of disk space?")
+JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines")
+JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x")
+JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up")
+JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation")
+JMESSAGE(JERR_XMS_READ, "Read from XMS failed")
+JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed")
+JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT)
+JMESSAGE(JMSG_VERSION, JVERSION)
+JMESSAGE(JTRC_16BIT_TABLES,
+ "Caution: quantization tables are too coarse for baseline JPEG")
+JMESSAGE(JTRC_ADOBE,
+ "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d")
+JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u")
+JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u")
+JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x")
+JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x")
+JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d")
+JMESSAGE(JTRC_DRI, "Define Restart Interval %u")
+JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u")
+JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u")
+JMESSAGE(JTRC_EOI, "End Of Image")
+JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d")
+JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d")
+JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE,
+ "Warning: thumbnail image size does not match data length %u")
+JMESSAGE(JTRC_JFIF_EXTENSION,
+ "JFIF extension marker: type 0x%02x, length %u")
+JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image")
+JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u")
+JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x")
+JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u")
+JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors")
+JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors")
+JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization")
+JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d")
+JMESSAGE(JTRC_RST, "RST%d")
+JMESSAGE(JTRC_SMOOTH_NOTIMPL,
+ "Smoothing not supported with nonstandard sampling ratios")
+JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d")
+JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d")
+JMESSAGE(JTRC_SOI, "Start of Image")
+JMESSAGE(JTRC_SOS, "Start Of Scan: %d components")
+JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d")
+JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d")
+JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s")
+JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s")
+JMESSAGE(JTRC_THUMB_JPEG,
+ "JFIF extension marker: JPEG-compressed thumbnail image, length %u")
+JMESSAGE(JTRC_THUMB_PALETTE,
+ "JFIF extension marker: palette thumbnail image, length %u")
+JMESSAGE(JTRC_THUMB_RGB,
+ "JFIF extension marker: RGB thumbnail image, length %u")
+JMESSAGE(JTRC_UNKNOWN_IDS,
+ "Unrecognized component IDs %d %d %d, assuming YCbCr")
+JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
+JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
+JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
+JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code")
+JMESSAGE(JWRN_BOGUS_PROGRESSION,
+ "Inconsistent progression sequence for component %d coefficient %d")
+JMESSAGE(JWRN_EXTRANEOUS_DATA,
+ "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x")
+JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment")
+JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code")
+JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d")
+JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file")
+JMESSAGE(JWRN_MUST_RESYNC,
+ "Corrupt JPEG data: found marker 0x%02x instead of RST%d")
+JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG")
+JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines")
+
+#ifdef JMAKE_ENUM_LIST
+
+ JMSG_LASTMSGCODE
+} J_MESSAGE_CODE;
+
+#undef JMAKE_ENUM_LIST
+#endif /* JMAKE_ENUM_LIST */
+
+/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */
+#undef JMESSAGE
+
+
+#ifndef JERROR_H
+#define JERROR_H
+
+/* Macros to simplify using the error and trace message stuff */
+/* The first parameter is either type of cinfo pointer */
+
+/* Fatal errors (print message and exit) */
+#define ERREXIT(cinfo,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT1(cinfo,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT2(cinfo,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT3(cinfo,code,p1,p2,p3) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (cinfo)->err->msg_parm.i[3] = (p4), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT6(cinfo,code,p1,p2,p3,p4,p5,p6) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (cinfo)->err->msg_parm.i[3] = (p4), \
+ (cinfo)->err->msg_parm.i[4] = (p5), \
+ (cinfo)->err->msg_parm.i[5] = (p6), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXITS(cinfo,code,str) \
+ ((cinfo)->err->msg_code = (code), \
+ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+
+#define MAKESTMT(stuff) do { stuff } while (0)
+
+/* Nonfatal errors (we can keep going, but the data is probably corrupt) */
+#define WARNMS(cinfo,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS1(cinfo,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS2(cinfo,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+
+/* Informational/debugging messages */
+#define TRACEMS(cinfo,lvl,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS1(cinfo,lvl,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS2(cinfo,lvl,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ _mp[4] = (p5); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMSS(cinfo,lvl,code,str) \
+ ((cinfo)->err->msg_code = (code), \
+ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+
+#endif /* JERROR_H */
diff --git a/external/jpeg-8c/jfdctflt.c b/external/jpeg-8c/jfdctflt.c
new file mode 100644
index 0000000..74d0d86
--- /dev/null
+++ b/external/jpeg-8c/jfdctflt.c
@@ -0,0 +1,174 @@
+/*
+ * jfdctflt.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2003-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a floating-point implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * This implementation should be more accurate than either of the integer
+ * DCT implementations. However, it may not give the same results on all
+ * machines because of differences in roundoff behavior. Speed will depend
+ * on the hardware's floating point capacity.
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column. Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with a fixed-point
+ * implementation, accuracy is lost due to imprecise representation of the
+ * scaled quantization values. However, that problem does not arise if
+ * we use floating point arithmetic.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_float (FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
+ FAST_FLOAT z1, z2, z3, z4, z5, z11, z13;
+ FAST_FLOAT *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+
+ /* Pass 1: process rows. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Load data into workspace */
+ tmp0 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]));
+ tmp7 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]));
+ tmp1 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]));
+ tmp6 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]));
+ tmp2 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]));
+ tmp5 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]));
+ tmp3 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]));
+ tmp4 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]));
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */
+ dataptr[4] = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */
+ dataptr[2] = tmp13 + z1; /* phase 5 */
+ dataptr[6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */
+ z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */
+ z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */
+ z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[5] = z13 + z2; /* phase 6 */
+ dataptr[3] = z13 - z2;
+ dataptr[1] = z11 + z4;
+ dataptr[7] = z11 - z4;
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns. */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
+ dataptr[DCTSIZE*4] = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */
+ dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
+ dataptr[DCTSIZE*6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */
+ z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */
+ z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */
+ z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
+ dataptr[DCTSIZE*3] = z13 - z2;
+ dataptr[DCTSIZE*1] = z11 + z4;
+ dataptr[DCTSIZE*7] = z11 - z4;
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
diff --git a/external/jpeg-8c/jfdctfst.c b/external/jpeg-8c/jfdctfst.c
new file mode 100644
index 0000000..8cad5f2
--- /dev/null
+++ b/external/jpeg-8c/jfdctfst.c
@@ -0,0 +1,230 @@
+/*
+ * jfdctfst.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2003-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a fast, not so accurate integer implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column. Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with fixed-point math,
+ * accuracy is lost due to imprecise representation of the scaled
+ * quantization values. The smaller the quantization table entry, the less
+ * precise the scaled value, so this implementation does worse with high-
+ * quality-setting files than with low-quality ones.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_IFAST_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Scaling decisions are generally the same as in the LL&M algorithm;
+ * see jfdctint.c for more details. However, we choose to descale
+ * (right shift) multiplication products as soon as they are formed,
+ * rather than carrying additional fractional bits into subsequent additions.
+ * This compromises accuracy slightly, but it lets us save a few shifts.
+ * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
+ * everywhere except in the multiplications proper; this saves a good deal
+ * of work on 16-bit-int machines.
+ *
+ * Again to save a few shifts, the intermediate results between pass 1 and
+ * pass 2 are not upscaled, but are represented only to integral precision.
+ *
+ * A final compromise is to represent the multiplicative constants to only
+ * 8 fractional bits, rather than 13. This saves some shifting work on some
+ * machines, and may also reduce the cost of multiplication (since there
+ * are fewer one-bits in the constants).
+ */
+
+#define CONST_BITS 8
+
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 8
+#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */
+#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */
+#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */
+#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */
+#else
+#define FIX_0_382683433 FIX(0.382683433)
+#define FIX_0_541196100 FIX(0.541196100)
+#define FIX_0_707106781 FIX(0.707106781)
+#define FIX_1_306562965 FIX(1.306562965)
+#endif
+
+
+/* We can gain a little more speed, with a further compromise in accuracy,
+ * by omitting the addition in a descaling shift. This yields an incorrectly
+ * rounded result half the time...
+ */
+
+#ifndef USE_ACCURATE_ROUNDING
+#undef DESCALE
+#define DESCALE(x,n) RIGHT_SHIFT(x, n)
+#endif
+
+
+/* Multiply a DCTELEM variable by an INT32 constant, and immediately
+ * descale to yield a DCTELEM result.
+ */
+
+#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS))
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_ifast (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ DCTELEM tmp10, tmp11, tmp12, tmp13;
+ DCTELEM z1, z2, z3, z4, z5, z11, z13;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Load data into workspace */
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+ tmp7 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+ tmp6 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+ tmp5 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+ tmp4 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */
+ dataptr[4] = tmp10 - tmp11;
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
+ dataptr[2] = tmp13 + z1; /* phase 5 */
+ dataptr[6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
+ z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
+ z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
+ z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[5] = z13 + z2; /* phase 6 */
+ dataptr[3] = z13 - z2;
+ dataptr[1] = z11 + z4;
+ dataptr[7] = z11 - z4;
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns. */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
+ dataptr[DCTSIZE*4] = tmp10 - tmp11;
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
+ dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
+ dataptr[DCTSIZE*6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
+ z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
+ z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
+ z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
+ dataptr[DCTSIZE*3] = z13 - z2;
+ dataptr[DCTSIZE*1] = z11 + z4;
+ dataptr[DCTSIZE*7] = z11 - z4;
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+#endif /* DCT_IFAST_SUPPORTED */
diff --git a/external/jpeg-8c/jfdctint.c b/external/jpeg-8c/jfdctint.c
new file mode 100644
index 0000000..1dde58c
--- /dev/null
+++ b/external/jpeg-8c/jfdctint.c
@@ -0,0 +1,4348 @@
+/*
+ * jfdctint.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modification developed 2003-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a slow-but-accurate integer implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column. Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on an algorithm described in
+ * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+ * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+ * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+ * The primary algorithm described there uses 11 multiplies and 29 adds.
+ * We use their alternate method with 12 multiplies and 32 adds.
+ * The advantage of this method is that no data path contains more than one
+ * multiplication; this allows a very simple and accurate implementation in
+ * scaled fixed-point arithmetic, with a minimal number of shifts.
+ *
+ * We also provide FDCT routines with various input sample block sizes for
+ * direct resolution reduction or enlargement and for direct resolving the
+ * common 2x1 and 1x2 subsampling cases without additional resampling: NxN
+ * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 output DCT block.
+ *
+ * For N<8 we fill the remaining block coefficients with zero.
+ * For N>8 we apply a partial N-point FDCT on the input samples, computing
+ * just the lower 8 frequency coefficients and discarding the rest.
+ *
+ * We must scale the output coefficients of the N-point FDCT appropriately
+ * to the standard 8-point FDCT level by 8/N per 1-D pass. This scaling
+ * is folded into the constant multipliers (pass 2) and/or final/initial
+ * shifting.
+ *
+ * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases
+ * since there would be too many additional constants to pre-calculate.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_ISLOW_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */
+#endif
+
+
+/*
+ * The poop on this scaling stuff is as follows:
+ *
+ * Each 1-D DCT step produces outputs which are a factor of sqrt(N)
+ * larger than the true DCT outputs. The final outputs are therefore
+ * a factor of N larger than desired; since N=8 this can be cured by
+ * a simple right shift at the end of the algorithm. The advantage of
+ * this arrangement is that we save two multiplications per 1-D DCT,
+ * because the y0 and y4 outputs need not be divided by sqrt(N).
+ * In the IJG code, this factor of 8 is removed by the quantization step
+ * (in jcdctmgr.c), NOT in this module.
+ *
+ * We have to do addition and subtraction of the integer inputs, which
+ * is no problem, and multiplication by fractional constants, which is
+ * a problem to do in integer arithmetic. We multiply all the constants
+ * by CONST_SCALE and convert them to integer constants (thus retaining
+ * CONST_BITS bits of precision in the constants). After doing a
+ * multiplication we have to divide the product by CONST_SCALE, with proper
+ * rounding, to produce the correct output. This division can be done
+ * cheaply as a right shift of CONST_BITS bits. We postpone shifting
+ * as long as possible so that partial sums can be added together with
+ * full fractional precision.
+ *
+ * The outputs of the first pass are scaled up by PASS1_BITS bits so that
+ * they are represented to better-than-integral precision. These outputs
+ * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+ * with the recommended scaling. (For 12-bit sample data, the intermediate
+ * array is INT32 anyway.)
+ *
+ * To avoid overflow of the 32-bit intermediate results in pass 2, we must
+ * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis
+ * shows that the values given below are the most effective.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS 13
+#define PASS1_BITS 2
+#else
+#define CONST_BITS 13
+#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 13
+#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */
+#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */
+#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */
+#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */
+#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */
+#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */
+#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */
+#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */
+#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */
+#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */
+#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */
+#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */
+#else
+#define FIX_0_298631336 FIX(0.298631336)
+#define FIX_0_390180644 FIX(0.390180644)
+#define FIX_0_541196100 FIX(0.541196100)
+#define FIX_0_765366865 FIX(0.765366865)
+#define FIX_0_899976223 FIX(0.899976223)
+#define FIX_1_175875602 FIX(1.175875602)
+#define FIX_1_501321110 FIX(1.501321110)
+#define FIX_1_847759065 FIX(1.847759065)
+#define FIX_1_961570560 FIX(1.961570560)
+#define FIX_2_053119869 FIX(2.053119869)
+#define FIX_2_562915447 FIX(2.562915447)
+#define FIX_3_072711026 FIX(3.072711026)
+#endif
+
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * For 8-bit samples with the recommended scaling, all the variable
+ * and constant values involved are no more than 16 bits wide, so a
+ * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+ * For 12-bit samples, a full 32-bit multiplication will be needed.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MULTIPLY(var,const) MULTIPLY16C16(var,const)
+#else
+#define MULTIPLY(var,const) ((var) * (const))
+#endif
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_islow (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+
+ tmp10 = tmp0 + tmp3;
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+ dataptr[2] = (DCTELEM) RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865),
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM) RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065),
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM)
+ RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM)
+ RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM)
+ RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+
+ /* Add fudge factor here for final descale. */
+ tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1));
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), CONST_BITS+PASS1_BITS);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*7] = (DCTELEM)
+ RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+#ifdef DCT_SCALING_SUPPORTED
+
+
+/*
+ * Perform the forward DCT on a 7x7 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_7x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12;
+ INT32 z1, z2, z3;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* cK represents sqrt(2) * cos(K*pi/14). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 7; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]);
+ tmp3 = GETJSAMPLE(elemptr[3]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]);
+
+ z1 = tmp0 + tmp2;
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS);
+ tmp3 += tmp3;
+ z1 -= tmp3;
+ z1 -= tmp3;
+ z1 = MULTIPLY(z1, FIX(0.353553391)); /* (c2+c6-c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002)); /* (c2+c4-c6)/2 */
+ z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123)); /* c6 */
+ dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS);
+ z1 -= z2;
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734)); /* c4 */
+ dataptr[4] = (DCTELEM)
+ DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */
+ tmp1 += tmp2;
+ tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268)); /* c5 */
+ tmp0 += tmp3;
+ tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693)); /* c3+c1-c5 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/7)**2 = 64/49, which we fold
+ * into the constant multipliers:
+ * cK now represents sqrt(2) * cos(K*pi/14) * 64/49.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 7; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4];
+ tmp3 = dataptr[DCTSIZE*3];
+
+ tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5];
+ tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4];
+
+ z1 = tmp0 + tmp2;
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */
+ CONST_BITS+PASS1_BITS);
+ tmp3 += tmp3;
+ z1 -= tmp3;
+ z1 -= tmp3;
+ z1 = MULTIPLY(z1, FIX(0.461784020)); /* (c2+c6-c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084)); /* (c2+c4-c6)/2 */
+ z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446)); /* c6 */
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS);
+ z1 -= z2;
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509)); /* c4 */
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */
+ tmp1 += tmp2;
+ tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310)); /* c5 */
+ tmp0 += tmp3;
+ tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355)); /* c3+c1-c5 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 6x6 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_6x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2;
+ INT32 tmp10, tmp11, tmp12;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* cK represents sqrt(2) * cos(K*pi/12). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 6; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);
+ tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */
+ CONST_BITS-PASS1_BITS);
+
+ dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS));
+ dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS);
+ dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS));
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/6)**2 = 16/9, which we fold
+ * into the constant multipliers:
+ * cK now represents sqrt(2) * cos(K*pi/12) * 16/9.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 6; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];
+ tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 5x5 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_5x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2;
+ INT32 tmp10, tmp11;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* cK represents sqrt(2) * cos(K*pi/10). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 5; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]);
+ tmp2 = GETJSAMPLE(elemptr[2]);
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << (PASS1_BITS+1));
+ tmp11 = MULTIPLY(tmp11, FIX(0.790569415)); /* (c2+c4)/2 */
+ tmp10 -= tmp2 << 2;
+ tmp10 = MULTIPLY(tmp10, FIX(0.353553391)); /* (c2-c4)/2 */
+ dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS-1);
+ dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS-1);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876)); /* c3 */
+
+ dataptr[1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */
+ CONST_BITS-PASS1_BITS-1);
+ dataptr[3] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */
+ CONST_BITS-PASS1_BITS-1);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/5)**2 = 64/25, which we partially
+ * fold into the constant multipliers (other part was done in pass 1):
+ * cK now represents sqrt(2) * cos(K*pi/10) * 32/25.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 5; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3];
+ tmp2 = dataptr[DCTSIZE*2];
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)), /* 32/25 */
+ CONST_BITS+PASS1_BITS);
+ tmp11 = MULTIPLY(tmp11, FIX(1.011928851)); /* (c2+c4)/2 */
+ tmp10 -= tmp2 << 2;
+ tmp10 = MULTIPLY(tmp10, FIX(0.452548340)); /* (c2-c4)/2 */
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961)); /* c3 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 4x4 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_4x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1;
+ INT32 tmp10, tmp11;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We must also scale the output by (8/4)**2 = 2**2, which we add here. */
+ /* cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+2));
+ dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+2));
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-3);
+
+ dataptr[1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS-PASS1_BITS-2);
+ dataptr[3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS-PASS1_BITS-2);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1));
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];
+
+ tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS);
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 3x3 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_3x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We scale the results further by 2**2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* cK represents sqrt(2) * cos(K*pi/6). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 3; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]);
+ tmp1 = GETJSAMPLE(elemptr[1]);
+
+ tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+2));
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */
+ CONST_BITS-PASS1_BITS-2);
+
+ /* Odd part */
+
+ dataptr[1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2, FIX(1.224744871)), /* c1 */
+ CONST_BITS-PASS1_BITS-2);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/3)**2 = 64/9, which we partially
+ * fold into the constant multipliers (other part was done in pass 1):
+ * cK now represents sqrt(2) * cos(K*pi/6) * 16/9.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 3; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2];
+ tmp1 = dataptr[DCTSIZE*1];
+
+ tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2, FIX(2.177324216)), /* c1 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 2x2 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_2x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ JSAMPROW elemptr;
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+
+ /* Row 0 */
+ elemptr = sample_data[0] + start_col;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]);
+ tmp1 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]);
+
+ /* Row 1 */
+ elemptr = sample_data[1] + start_col;
+
+ tmp2 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]);
+ tmp3 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]);
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/2)**2 = 2**4.
+ */
+
+ /* Column 0 */
+ /* Apply unsigned->signed conversion */
+ data[DCTSIZE*0] = (DCTELEM) ((tmp0 + tmp2 - 4 * CENTERJSAMPLE) << 4);
+ data[DCTSIZE*1] = (DCTELEM) ((tmp0 - tmp2) << 4);
+
+ /* Column 1 */
+ data[DCTSIZE*0+1] = (DCTELEM) ((tmp1 + tmp3) << 4);
+ data[DCTSIZE*1+1] = (DCTELEM) ((tmp1 - tmp3) << 4);
+}
+
+
+/*
+ * Perform the forward DCT on a 1x1 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_1x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* We leave the result scaled up by an overall factor of 8. */
+ /* We must also scale the output by (8/1)**2 = 2**6. */
+ /* Apply unsigned->signed conversion */
+ data[0] = (DCTELEM)
+ ((GETJSAMPLE(sample_data[0][start_col]) - CENTERJSAMPLE) << 6);
+}
+
+
+/*
+ * Perform the forward DCT on a 9x9 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_9x9 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2;
+ DCTELEM workspace[8];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* we scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* cK represents sqrt(2) * cos(K*pi/18). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[8]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[7]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[6]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[5]);
+ tmp4 = GETJSAMPLE(elemptr[4]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[8]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[7]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[6]);
+ tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[5]);
+
+ z1 = tmp0 + tmp2 + tmp3;
+ z2 = tmp1 + tmp4;
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) ((z1 + z2 - 9 * CENTERJSAMPLE) << 1);
+ dataptr[6] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 - z2 - z2, FIX(0.707106781)), /* c6 */
+ CONST_BITS-1);
+ z1 = MULTIPLY(tmp0 - tmp2, FIX(1.328926049)); /* c2 */
+ z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(0.707106781)); /* c6 */
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.083350441)) /* c4 */
+ + z1 + z2, CONST_BITS-1);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.245575608)) /* c8 */
+ + z1 - z2, CONST_BITS-1);
+
+ /* Odd part */
+
+ dataptr[3] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.224744871)), /* c3 */
+ CONST_BITS-1);
+
+ tmp11 = MULTIPLY(tmp11, FIX(1.224744871)); /* c3 */
+ tmp0 = MULTIPLY(tmp10 + tmp12, FIX(0.909038955)); /* c5 */
+ tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.483689525)); /* c7 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS-1);
+
+ tmp2 = MULTIPLY(tmp12 - tmp13, FIX(1.392728481)); /* c1 */
+
+ dataptr[5] = (DCTELEM) DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS-1);
+ dataptr[7] = (DCTELEM) DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS-1);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 9)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/9)**2 = 64/81, which we partially
+ * fold into the constant multipliers and final/initial shifting:
+ * cK now represents sqrt(2) * cos(K*pi/18) * 128/81.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*0];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*7];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*6];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*5];
+ tmp4 = dataptr[DCTSIZE*4];
+
+ tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*0];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*7];
+ tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*6];
+ tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*5];
+
+ z1 = tmp0 + tmp2 + tmp3;
+ z2 = tmp1 + tmp4;
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 + z2, FIX(1.580246914)), /* 128/81 */
+ CONST_BITS+2);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 - z2 - z2, FIX(1.117403309)), /* c6 */
+ CONST_BITS+2);
+ z1 = MULTIPLY(tmp0 - tmp2, FIX(2.100031287)); /* c2 */
+ z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(1.117403309)); /* c6 */
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.711961190)) /* c4 */
+ + z1 + z2, CONST_BITS+2);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.388070096)) /* c8 */
+ + z1 - z2, CONST_BITS+2);
+
+ /* Odd part */
+
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.935399303)), /* c3 */
+ CONST_BITS+2);
+
+ tmp11 = MULTIPLY(tmp11, FIX(1.935399303)); /* c3 */
+ tmp0 = MULTIPLY(tmp10 + tmp12, FIX(1.436506004)); /* c5 */
+ tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.764348879)); /* c7 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS+2);
+
+ tmp2 = MULTIPLY(tmp12 - tmp13, FIX(2.200854883)); /* c1 */
+
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS+2);
+ dataptr[DCTSIZE*7] = (DCTELEM)
+ DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS+2);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 10x10 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_10x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ DCTELEM workspace[8*2];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* we scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* cK represents sqrt(2) * cos(K*pi/20). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]);
+ tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]);
+
+ tmp10 = tmp0 + tmp4;
+ tmp13 = tmp0 - tmp4;
+ tmp11 = tmp1 + tmp3;
+ tmp14 = tmp1 - tmp3;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << 1);
+ tmp12 += tmp12;
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */
+ MULTIPLY(tmp11 - tmp12, FIX(0.437016024)), /* c8 */
+ CONST_BITS-1);
+ tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876)); /* c6 */
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)), /* c2-c6 */
+ CONST_BITS-1);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)), /* c2+c6 */
+ CONST_BITS-1);
+
+ /* Odd part */
+
+ tmp10 = tmp0 + tmp4;
+ tmp11 = tmp1 - tmp3;
+ dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << 1);
+ tmp2 <<= CONST_BITS;
+ dataptr[1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) + /* c1 */
+ MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 + /* c3 */
+ MULTIPLY(tmp3, FIX(0.642039522)) + /* c7 */
+ MULTIPLY(tmp4, FIX(0.221231742)), /* c9 */
+ CONST_BITS-1);
+ tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) - /* (c3+c7)/2 */
+ MULTIPLY(tmp1 + tmp3, FIX(0.587785252)); /* (c1-c9)/2 */
+ tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) + /* (c3-c7)/2 */
+ (tmp11 << (CONST_BITS - 1)) - tmp2;
+ dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-1);
+ dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-1);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 10)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/10)**2 = 16/25, which we partially
+ * fold into the constant multipliers and final/initial shifting:
+ * cK now represents sqrt(2) * cos(K*pi/20) * 32/25.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0];
+ tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6];
+ tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5];
+
+ tmp10 = tmp0 + tmp4;
+ tmp13 = tmp0 - tmp4;
+ tmp11 = tmp1 + tmp3;
+ tmp14 = tmp1 - tmp3;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7];
+ tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6];
+ tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */
+ CONST_BITS+2);
+ tmp12 += tmp12;
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */
+ MULTIPLY(tmp11 - tmp12, FIX(0.559380511)), /* c8 */
+ CONST_BITS+2);
+ tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961)); /* c6 */
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)), /* c2-c6 */
+ CONST_BITS+2);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)), /* c2+c6 */
+ CONST_BITS+2);
+
+ /* Odd part */
+
+ tmp10 = tmp0 + tmp4;
+ tmp11 = tmp1 - tmp3;
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)), /* 32/25 */
+ CONST_BITS+2);
+ tmp2 = MULTIPLY(tmp2, FIX(1.28)); /* 32/25 */
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) + /* c1 */
+ MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 + /* c3 */
+ MULTIPLY(tmp3, FIX(0.821810588)) + /* c7 */
+ MULTIPLY(tmp4, FIX(0.283176630)), /* c9 */
+ CONST_BITS+2);
+ tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) - /* (c3+c7)/2 */
+ MULTIPLY(tmp1 + tmp3, FIX(0.752365123)); /* (c1-c9)/2 */
+ tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) + /* (c3-c7)/2 */
+ MULTIPLY(tmp11, FIX(0.64)) - tmp2; /* 16/25 */
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+2);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+2);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on an 11x11 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_11x11 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 z1, z2, z3;
+ DCTELEM workspace[8*3];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* we scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* cK represents sqrt(2) * cos(K*pi/22). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[10]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[9]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[8]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[7]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[6]);
+ tmp5 = GETJSAMPLE(elemptr[5]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[10]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[9]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[8]);
+ tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[7]);
+ tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[6]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 - 11 * CENTERJSAMPLE) << 1);
+ tmp5 += tmp5;
+ tmp0 -= tmp5;
+ tmp1 -= tmp5;
+ tmp2 -= tmp5;
+ tmp3 -= tmp5;
+ tmp4 -= tmp5;
+ z1 = MULTIPLY(tmp0 + tmp3, FIX(1.356927976)) + /* c2 */
+ MULTIPLY(tmp2 + tmp4, FIX(0.201263574)); /* c10 */
+ z2 = MULTIPLY(tmp1 - tmp3, FIX(0.926112931)); /* c6 */
+ z3 = MULTIPLY(tmp0 - tmp1, FIX(1.189712156)); /* c4 */
+ dataptr[2] = (DCTELEM)
+ DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.018300590)) /* c2+c8-c6 */
+ - MULTIPLY(tmp4, FIX(1.390975730)), /* c4+c10 */
+ CONST_BITS-1);
+ dataptr[4] = (DCTELEM)
+ DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.062335650)) /* c4-c6-c10 */
+ - MULTIPLY(tmp2, FIX(1.356927976)) /* c2 */
+ + MULTIPLY(tmp4, FIX(0.587485545)), /* c8 */
+ CONST_BITS-1);
+ dataptr[6] = (DCTELEM)
+ DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.620527200)) /* c2+c4-c6 */
+ - MULTIPLY(tmp2, FIX(0.788749120)), /* c8+c10 */
+ CONST_BITS-1);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.286413905)); /* c3 */
+ tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.068791298)); /* c5 */
+ tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.764581576)); /* c7 */
+ tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.719967871)) /* c7+c5+c3-c1 */
+ + MULTIPLY(tmp14, FIX(0.398430003)); /* c9 */
+ tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.764581576)); /* -c7 */
+ tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.399818907)); /* -c1 */
+ tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.276416582)) /* c9+c7+c1-c3 */
+ - MULTIPLY(tmp14, FIX(1.068791298)); /* c5 */
+ tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.398430003)); /* c9 */
+ tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(1.989053629)) /* c9+c5+c3-c7 */
+ + MULTIPLY(tmp14, FIX(1.399818907)); /* c1 */
+ tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.305598626)) /* c1+c5-c9-c7 */
+ - MULTIPLY(tmp14, FIX(1.286413905)); /* c3 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-1);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-1);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-1);
+ dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS-1);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 11)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/11)**2 = 64/121, which we partially
+ * fold into the constant multipliers and final/initial shifting:
+ * cK now represents sqrt(2) * cos(K*pi/22) * 128/121.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*2];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*1];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*0];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*7];
+ tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*6];
+ tmp5 = dataptr[DCTSIZE*5];
+
+ tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*2];
+ tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*1];
+ tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*0];
+ tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*7];
+ tmp14 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*6];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5,
+ FIX(1.057851240)), /* 128/121 */
+ CONST_BITS+2);
+ tmp5 += tmp5;
+ tmp0 -= tmp5;
+ tmp1 -= tmp5;
+ tmp2 -= tmp5;
+ tmp3 -= tmp5;
+ tmp4 -= tmp5;
+ z1 = MULTIPLY(tmp0 + tmp3, FIX(1.435427942)) + /* c2 */
+ MULTIPLY(tmp2 + tmp4, FIX(0.212906922)); /* c10 */
+ z2 = MULTIPLY(tmp1 - tmp3, FIX(0.979689713)); /* c6 */
+ z3 = MULTIPLY(tmp0 - tmp1, FIX(1.258538479)); /* c4 */
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.077210542)) /* c2+c8-c6 */
+ - MULTIPLY(tmp4, FIX(1.471445400)), /* c4+c10 */
+ CONST_BITS+2);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.065941844)) /* c4-c6-c10 */
+ - MULTIPLY(tmp2, FIX(1.435427942)) /* c2 */
+ + MULTIPLY(tmp4, FIX(0.621472312)), /* c8 */
+ CONST_BITS+2);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.714276708)) /* c2+c4-c6 */
+ - MULTIPLY(tmp2, FIX(0.834379234)), /* c8+c10 */
+ CONST_BITS+2);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.360834544)); /* c3 */
+ tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.130622199)); /* c5 */
+ tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.808813568)); /* c7 */
+ tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.819470145)) /* c7+c5+c3-c1 */
+ + MULTIPLY(tmp14, FIX(0.421479672)); /* c9 */
+ tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.808813568)); /* -c7 */
+ tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.480800167)); /* -c1 */
+ tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.350258864)) /* c9+c7+c1-c3 */
+ - MULTIPLY(tmp14, FIX(1.130622199)); /* c5 */
+ tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.421479672)); /* c9 */
+ tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(2.104122847)) /* c9+c5+c3-c7 */
+ + MULTIPLY(tmp14, FIX(1.480800167)); /* c1 */
+ tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.381129125)) /* c1+c5-c9-c7 */
+ - MULTIPLY(tmp14, FIX(1.360834544)); /* c3 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 12x12 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_12x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ DCTELEM workspace[8*4];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+ /* cK represents sqrt(2) * cos(K*pi/24). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]);
+
+ tmp10 = tmp0 + tmp5;
+ tmp13 = tmp0 - tmp5;
+ tmp11 = tmp1 + tmp4;
+ tmp14 = tmp1 - tmp4;
+ tmp12 = tmp2 + tmp3;
+ tmp15 = tmp2 - tmp3;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) (tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE);
+ dataptr[6] = (DCTELEM) (tmp13 - tmp14 - tmp15);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */
+ CONST_BITS);
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */
+ CONST_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100); /* c9 */
+ tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865); /* c3-c9 */
+ tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065); /* c3+c9 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054)); /* c5 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669)); /* c7 */
+ tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */
+ + MULTIPLY(tmp5, FIX(0.184591911)); /* c11 */
+ tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */
+ tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */
+ + MULTIPLY(tmp5, FIX(0.860918669)); /* c7 */
+ tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */
+ - MULTIPLY(tmp5, FIX(1.121971054)); /* c5 */
+ tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */
+ - MULTIPLY(tmp2 + tmp5, FIX_0_541196100); /* c9 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 12)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/12)**2 = 4/9, which we partially
+ * fold into the constant multipliers and final shifting:
+ * cK now represents sqrt(2) * cos(K*pi/24) * 8/9.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0];
+ tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7];
+ tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6];
+
+ tmp10 = tmp0 + tmp5;
+ tmp13 = tmp0 - tmp5;
+ tmp11 = tmp1 + tmp4;
+ tmp14 = tmp1 - tmp4;
+ tmp12 = tmp2 + tmp3;
+ tmp15 = tmp2 - tmp3;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0];
+ tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7];
+ tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */
+ CONST_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */
+ CONST_BITS+1);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)), /* c4 */
+ CONST_BITS+1);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) + /* 8/9 */
+ MULTIPLY(tmp13 + tmp15, FIX(1.214244803)), /* c2 */
+ CONST_BITS+1);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200)); /* c9 */
+ tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102)); /* c3-c9 */
+ tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502)); /* c3+c9 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603)); /* c5 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039)); /* c7 */
+ tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */
+ + MULTIPLY(tmp5, FIX(0.164081699)); /* c11 */
+ tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */
+ tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */
+ + MULTIPLY(tmp5, FIX(0.765261039)); /* c7 */
+ tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */
+ - MULTIPLY(tmp5, FIX(0.997307603)); /* c5 */
+ tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */
+ - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+1);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 13x13 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_13x13 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ INT32 z1, z2;
+ DCTELEM workspace[8*5];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+ /* cK represents sqrt(2) * cos(K*pi/26). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[12]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[11]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[10]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[9]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[8]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[7]);
+ tmp6 = GETJSAMPLE(elemptr[6]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[12]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[11]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[10]);
+ tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[9]);
+ tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[8]);
+ tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[7]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ (tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 - 13 * CENTERJSAMPLE);
+ tmp6 += tmp6;
+ tmp0 -= tmp6;
+ tmp1 -= tmp6;
+ tmp2 -= tmp6;
+ tmp3 -= tmp6;
+ tmp4 -= tmp6;
+ tmp5 -= tmp6;
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.373119086)) + /* c2 */
+ MULTIPLY(tmp1, FIX(1.058554052)) + /* c6 */
+ MULTIPLY(tmp2, FIX(0.501487041)) - /* c10 */
+ MULTIPLY(tmp3, FIX(0.170464608)) - /* c12 */
+ MULTIPLY(tmp4, FIX(0.803364869)) - /* c8 */
+ MULTIPLY(tmp5, FIX(1.252223920)), /* c4 */
+ CONST_BITS);
+ z1 = MULTIPLY(tmp0 - tmp2, FIX(1.155388986)) - /* (c4+c6)/2 */
+ MULTIPLY(tmp3 - tmp4, FIX(0.435816023)) - /* (c2-c10)/2 */
+ MULTIPLY(tmp1 - tmp5, FIX(0.316450131)); /* (c8-c12)/2 */
+ z2 = MULTIPLY(tmp0 + tmp2, FIX(0.096834934)) - /* (c4-c6)/2 */
+ MULTIPLY(tmp3 + tmp4, FIX(0.937303064)) + /* (c2+c10)/2 */
+ MULTIPLY(tmp1 + tmp5, FIX(0.486914739)); /* (c8+c12)/2 */
+
+ dataptr[4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS);
+ dataptr[6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.322312651)); /* c3 */
+ tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.163874945)); /* c5 */
+ tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.937797057)) + /* c7 */
+ MULTIPLY(tmp14 + tmp15, FIX(0.338443458)); /* c11 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(tmp10, FIX(2.020082300)) + /* c3+c5+c7-c1 */
+ MULTIPLY(tmp14, FIX(0.318774355)); /* c9-c11 */
+ tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.937797057)) - /* c7 */
+ MULTIPLY(tmp11 + tmp12, FIX(0.338443458)); /* c11 */
+ tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.163874945)); /* -c5 */
+ tmp1 += tmp4 + tmp5 +
+ MULTIPLY(tmp11, FIX(0.837223564)) - /* c5+c9+c11-c3 */
+ MULTIPLY(tmp14, FIX(2.341699410)); /* c1+c7 */
+ tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.657217813)); /* -c9 */
+ tmp2 += tmp4 + tmp6 -
+ MULTIPLY(tmp12, FIX(1.572116027)) + /* c1+c5-c9-c11 */
+ MULTIPLY(tmp15, FIX(2.260109708)); /* c3+c7 */
+ tmp3 += tmp5 + tmp6 +
+ MULTIPLY(tmp13, FIX(2.205608352)) - /* c3+c5+c9-c7 */
+ MULTIPLY(tmp15, FIX(1.742345811)); /* c1+c11 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 13)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/13)**2 = 64/169, which we partially
+ * fold into the constant multipliers and final shifting:
+ * cK now represents sqrt(2) * cos(K*pi/26) * 128/169.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*4];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*3];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*2];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*1];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*0];
+ tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*7];
+ tmp6 = dataptr[DCTSIZE*6];
+
+ tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*4];
+ tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*3];
+ tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*2];
+ tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*1];
+ tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*0];
+ tmp15 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*7];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6,
+ FIX(0.757396450)), /* 128/169 */
+ CONST_BITS+1);
+ tmp6 += tmp6;
+ tmp0 -= tmp6;
+ tmp1 -= tmp6;
+ tmp2 -= tmp6;
+ tmp3 -= tmp6;
+ tmp4 -= tmp6;
+ tmp5 -= tmp6;
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.039995521)) + /* c2 */
+ MULTIPLY(tmp1, FIX(0.801745081)) + /* c6 */
+ MULTIPLY(tmp2, FIX(0.379824504)) - /* c10 */
+ MULTIPLY(tmp3, FIX(0.129109289)) - /* c12 */
+ MULTIPLY(tmp4, FIX(0.608465700)) - /* c8 */
+ MULTIPLY(tmp5, FIX(0.948429952)), /* c4 */
+ CONST_BITS+1);
+ z1 = MULTIPLY(tmp0 - tmp2, FIX(0.875087516)) - /* (c4+c6)/2 */
+ MULTIPLY(tmp3 - tmp4, FIX(0.330085509)) - /* (c2-c10)/2 */
+ MULTIPLY(tmp1 - tmp5, FIX(0.239678205)); /* (c8-c12)/2 */
+ z2 = MULTIPLY(tmp0 + tmp2, FIX(0.073342435)) - /* (c4-c6)/2 */
+ MULTIPLY(tmp3 + tmp4, FIX(0.709910013)) + /* (c2+c10)/2 */
+ MULTIPLY(tmp1 + tmp5, FIX(0.368787494)); /* (c8+c12)/2 */
+
+ dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS+1);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.001514908)); /* c3 */
+ tmp2 = MULTIPLY(tmp10 + tmp12, FIX(0.881514751)); /* c5 */
+ tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.710284161)) + /* c7 */
+ MULTIPLY(tmp14 + tmp15, FIX(0.256335874)); /* c11 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(tmp10, FIX(1.530003162)) + /* c3+c5+c7-c1 */
+ MULTIPLY(tmp14, FIX(0.241438564)); /* c9-c11 */
+ tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.710284161)) - /* c7 */
+ MULTIPLY(tmp11 + tmp12, FIX(0.256335874)); /* c11 */
+ tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(0.881514751)); /* -c5 */
+ tmp1 += tmp4 + tmp5 +
+ MULTIPLY(tmp11, FIX(0.634110155)) - /* c5+c9+c11-c3 */
+ MULTIPLY(tmp14, FIX(1.773594819)); /* c1+c7 */
+ tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.497774438)); /* -c9 */
+ tmp2 += tmp4 + tmp6 -
+ MULTIPLY(tmp12, FIX(1.190715098)) + /* c1+c5-c9-c11 */
+ MULTIPLY(tmp15, FIX(1.711799069)); /* c3+c7 */
+ tmp3 += tmp5 + tmp6 +
+ MULTIPLY(tmp13, FIX(1.670519935)) - /* c3+c5+c9-c7 */
+ MULTIPLY(tmp15, FIX(1.319646532)); /* c1+c11 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+1);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 14x14 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_14x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ DCTELEM workspace[8*6];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+ /* cK represents sqrt(2) * cos(K*pi/28). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]);
+ tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]);
+ tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]);
+
+ tmp10 = tmp0 + tmp6;
+ tmp14 = tmp0 - tmp6;
+ tmp11 = tmp1 + tmp5;
+ tmp15 = tmp1 - tmp5;
+ tmp12 = tmp2 + tmp4;
+ tmp16 = tmp2 - tmp4;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]);
+ tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ (tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE);
+ tmp13 += tmp13;
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */
+ MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */
+ MULTIPLY(tmp12 - tmp13, FIX(0.881747734)), /* c8 */
+ CONST_BITS);
+
+ tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686)); /* c6 */
+
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590)) /* c2-c6 */
+ + MULTIPLY(tmp16, FIX(0.613604268)), /* c10 */
+ CONST_BITS);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954)) /* c6+c10 */
+ - MULTIPLY(tmp16, FIX(1.378756276)), /* c2 */
+ CONST_BITS);
+
+ /* Odd part */
+
+ tmp10 = tmp1 + tmp2;
+ tmp11 = tmp5 - tmp4;
+ dataptr[7] = (DCTELEM) (tmp0 - tmp10 + tmp3 - tmp11 - tmp6);
+ tmp3 <<= CONST_BITS;
+ tmp10 = MULTIPLY(tmp10, - FIX(0.158341681)); /* -c13 */
+ tmp11 = MULTIPLY(tmp11, FIX(1.405321284)); /* c1 */
+ tmp10 += tmp11 - tmp3;
+ tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) + /* c5 */
+ MULTIPLY(tmp4 + tmp6, FIX(0.752406978)); /* c9 */
+ dataptr[5] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */
+ + MULTIPLY(tmp4, FIX(1.119999435)), /* c1+c11-c9 */
+ CONST_BITS);
+ tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) + /* c3 */
+ MULTIPLY(tmp5 - tmp6, FIX(0.467085129)); /* c11 */
+ dataptr[3] = (DCTELEM)
+ DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */
+ - MULTIPLY(tmp5, FIX(3.069855259)), /* c1+c5+c11 */
+ CONST_BITS);
+ dataptr[1] = (DCTELEM)
+ DESCALE(tmp11 + tmp12 + tmp3 + tmp6 -
+ MULTIPLY(tmp0 + tmp6, FIX(1.126980169)), /* c3+c5-c1 */
+ CONST_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 14)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/14)**2 = 16/49, which we partially
+ * fold into the constant multipliers and final shifting:
+ * cK now represents sqrt(2) * cos(K*pi/28) * 32/49.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3];
+ tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1];
+ tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0];
+ tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7];
+
+ tmp10 = tmp0 + tmp6;
+ tmp14 = tmp0 - tmp6;
+ tmp11 = tmp1 + tmp5;
+ tmp15 = tmp1 - tmp5;
+ tmp12 = tmp2 + tmp4;
+ tmp16 = tmp2 - tmp4;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2];
+ tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1];
+ tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0];
+ tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13,
+ FIX(0.653061224)), /* 32/49 */
+ CONST_BITS+1);
+ tmp13 += tmp13;
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */
+ MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */
+ MULTIPLY(tmp12 - tmp13, FIX(0.575835255)), /* c8 */
+ CONST_BITS+1);
+
+ tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570)); /* c6 */
+
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691)) /* c2-c6 */
+ + MULTIPLY(tmp16, FIX(0.400721155)), /* c10 */
+ CONST_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725)) /* c6+c10 */
+ - MULTIPLY(tmp16, FIX(0.900412262)), /* c2 */
+ CONST_BITS+1);
+
+ /* Odd part */
+
+ tmp10 = tmp1 + tmp2;
+ tmp11 = tmp5 - tmp4;
+ dataptr[DCTSIZE*7] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6,
+ FIX(0.653061224)), /* 32/49 */
+ CONST_BITS+1);
+ tmp3 = MULTIPLY(tmp3 , FIX(0.653061224)); /* 32/49 */
+ tmp10 = MULTIPLY(tmp10, - FIX(0.103406812)); /* -c13 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.917760839)); /* c1 */
+ tmp10 += tmp11 - tmp3;
+ tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) + /* c5 */
+ MULTIPLY(tmp4 + tmp6, FIX(0.491367823)); /* c9 */
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */
+ + MULTIPLY(tmp4, FIX(0.731428202)), /* c1+c11-c9 */
+ CONST_BITS+1);
+ tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) + /* c3 */
+ MULTIPLY(tmp5 - tmp6, FIX(0.305035186)); /* c11 */
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */
+ - MULTIPLY(tmp5, FIX(2.004803435)), /* c1+c5+c11 */
+ CONST_BITS+1);
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp11 + tmp12 + tmp3
+ - MULTIPLY(tmp0, FIX(0.735987049)) /* c3+c5-c1 */
+ - MULTIPLY(tmp6, FIX(0.082925825)), /* c9-c11-c13 */
+ CONST_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 15x15 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_15x15 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 z1, z2, z3;
+ DCTELEM workspace[8*7];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+ /* cK represents sqrt(2) * cos(K*pi/30). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[14]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[13]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[12]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[11]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[10]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[9]);
+ tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[8]);
+ tmp7 = GETJSAMPLE(elemptr[7]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[14]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[13]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[12]);
+ tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[11]);
+ tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[10]);
+ tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[9]);
+ tmp16 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[8]);
+
+ z1 = tmp0 + tmp4 + tmp5;
+ z2 = tmp1 + tmp3 + tmp6;
+ z3 = tmp2 + tmp7;
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) (z1 + z2 + z3 - 15 * CENTERJSAMPLE);
+ z3 += z3;
+ dataptr[6] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 - z3, FIX(1.144122806)) - /* c6 */
+ MULTIPLY(z2 - z3, FIX(0.437016024)), /* c12 */
+ CONST_BITS);
+ tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7;
+ z1 = MULTIPLY(tmp3 - tmp2, FIX(1.531135173)) - /* c2+c14 */
+ MULTIPLY(tmp6 - tmp2, FIX(2.238241955)); /* c4+c8 */
+ z2 = MULTIPLY(tmp5 - tmp2, FIX(0.798468008)) - /* c8-c14 */
+ MULTIPLY(tmp0 - tmp2, FIX(0.091361227)); /* c2-c4 */
+ z3 = MULTIPLY(tmp0 - tmp3, FIX(1.383309603)) + /* c2 */
+ MULTIPLY(tmp6 - tmp5, FIX(0.946293579)) + /* c8 */
+ MULTIPLY(tmp1 - tmp4, FIX(0.790569415)); /* (c6+c12)/2 */
+
+ dataptr[2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS);
+ dataptr[4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS);
+
+ /* Odd part */
+
+ tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16,
+ FIX(1.224744871)); /* c5 */
+ tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.344997024)) + /* c3 */
+ MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.831253876)); /* c9 */
+ tmp12 = MULTIPLY(tmp12, FIX(1.224744871)); /* c5 */
+ tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.406466353)) + /* c1 */
+ MULTIPLY(tmp11 + tmp14, FIX(1.344997024)) + /* c3 */
+ MULTIPLY(tmp13 + tmp15, FIX(0.575212477)); /* c11 */
+ tmp0 = MULTIPLY(tmp13, FIX(0.475753014)) - /* c7-c11 */
+ MULTIPLY(tmp14, FIX(0.513743148)) + /* c3-c9 */
+ MULTIPLY(tmp16, FIX(1.700497885)) + tmp4 + tmp12; /* c1+c13 */
+ tmp3 = MULTIPLY(tmp10, - FIX(0.355500862)) - /* -(c1-c7) */
+ MULTIPLY(tmp11, FIX(2.176250899)) - /* c3+c9 */
+ MULTIPLY(tmp15, FIX(0.869244010)) + tmp4 - tmp12; /* c11+c13 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 15)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/15)**2 = 64/225, which we partially
+ * fold into the constant multipliers and final shifting:
+ * cK now represents sqrt(2) * cos(K*pi/30) * 256/225.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*6];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*5];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*4];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*3];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*2];
+ tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*1];
+ tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*0];
+ tmp7 = dataptr[DCTSIZE*7];
+
+ tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*6];
+ tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*5];
+ tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*4];
+ tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*3];
+ tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*2];
+ tmp15 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*1];
+ tmp16 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*0];
+
+ z1 = tmp0 + tmp4 + tmp5;
+ z2 = tmp1 + tmp3 + tmp6;
+ z3 = tmp2 + tmp7;
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 + z2 + z3, FIX(1.137777778)), /* 256/225 */
+ CONST_BITS+2);
+ z3 += z3;
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 - z3, FIX(1.301757503)) - /* c6 */
+ MULTIPLY(z2 - z3, FIX(0.497227121)), /* c12 */
+ CONST_BITS+2);
+ tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7;
+ z1 = MULTIPLY(tmp3 - tmp2, FIX(1.742091575)) - /* c2+c14 */
+ MULTIPLY(tmp6 - tmp2, FIX(2.546621957)); /* c4+c8 */
+ z2 = MULTIPLY(tmp5 - tmp2, FIX(0.908479156)) - /* c8-c14 */
+ MULTIPLY(tmp0 - tmp2, FIX(0.103948774)); /* c2-c4 */
+ z3 = MULTIPLY(tmp0 - tmp3, FIX(1.573898926)) + /* c2 */
+ MULTIPLY(tmp6 - tmp5, FIX(1.076671805)) + /* c8 */
+ MULTIPLY(tmp1 - tmp4, FIX(0.899492312)); /* (c6+c12)/2 */
+
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS+2);
+ dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS+2);
+
+ /* Odd part */
+
+ tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16,
+ FIX(1.393487498)); /* c5 */
+ tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.530307725)) + /* c3 */
+ MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.945782187)); /* c9 */
+ tmp12 = MULTIPLY(tmp12, FIX(1.393487498)); /* c5 */
+ tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.600246161)) + /* c1 */
+ MULTIPLY(tmp11 + tmp14, FIX(1.530307725)) + /* c3 */
+ MULTIPLY(tmp13 + tmp15, FIX(0.654463974)); /* c11 */
+ tmp0 = MULTIPLY(tmp13, FIX(0.541301207)) - /* c7-c11 */
+ MULTIPLY(tmp14, FIX(0.584525538)) + /* c3-c9 */
+ MULTIPLY(tmp16, FIX(1.934788705)) + tmp4 + tmp12; /* c1+c13 */
+ tmp3 = MULTIPLY(tmp10, - FIX(0.404480980)) - /* -(c1-c7) */
+ MULTIPLY(tmp11, FIX(2.476089912)) - /* c3+c9 */
+ MULTIPLY(tmp15, FIX(0.989006518)) + tmp4 - tmp12; /* c11+c13 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 16x16 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_16x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;
+ DCTELEM workspace[DCTSIZE2];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* cK represents sqrt(2) * cos(K*pi/32). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]);
+ tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]);
+ tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]);
+
+ tmp10 = tmp0 + tmp7;
+ tmp14 = tmp0 - tmp7;
+ tmp11 = tmp1 + tmp6;
+ tmp15 = tmp1 - tmp6;
+ tmp12 = tmp2 + tmp5;
+ tmp16 = tmp2 - tmp5;
+ tmp13 = tmp3 + tmp4;
+ tmp17 = tmp3 - tmp4;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]);
+ tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]);
+ tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+ MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */
+ CONST_BITS-PASS1_BITS);
+
+ tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */
+ MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */
+ + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */
+ - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */
+ MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */
+ MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */
+ MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */
+ tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */
+ MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */
+ tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */
+ MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */
+ tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */
+ MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */
+ MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */
+ tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+ - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */
+ tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+ + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */
+ tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+ + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == DCTSIZE * 2)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/16)**2 = 1/2**2.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3];
+ tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2];
+ tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1];
+ tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0];
+
+ tmp10 = tmp0 + tmp7;
+ tmp14 = tmp0 - tmp7;
+ tmp11 = tmp1 + tmp6;
+ tmp15 = tmp1 - tmp6;
+ tmp12 = tmp2 + tmp5;
+ tmp16 = tmp2 - tmp5;
+ tmp13 = tmp3 + tmp4;
+ tmp17 = tmp3 - tmp4;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3];
+ tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2];
+ tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1];
+ tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+2);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+ MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */
+ CONST_BITS+PASS1_BITS+2);
+
+ tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */
+ MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */
+ + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+10 */
+ CONST_BITS+PASS1_BITS+2);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */
+ - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */
+ CONST_BITS+PASS1_BITS+2);
+
+ /* Odd part */
+
+ tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */
+ MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */
+ MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */
+ MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */
+ tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */
+ MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */
+ tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */
+ MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */
+ tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */
+ MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */
+ MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */
+ tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+ - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */
+ tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+ + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */
+ tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+ + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+2);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+2);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+2);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+2);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 16x8 sample block.
+ *
+ * 16-point FDCT in pass 1 (rows), 8-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_16x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;
+ INT32 z1;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32). */
+
+ dataptr = data;
+ ctr = 0;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]);
+ tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]);
+ tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]);
+
+ tmp10 = tmp0 + tmp7;
+ tmp14 = tmp0 - tmp7;
+ tmp11 = tmp1 + tmp6;
+ tmp15 = tmp1 - tmp6;
+ tmp12 = tmp2 + tmp5;
+ tmp16 = tmp2 - tmp5;
+ tmp13 = tmp3 + tmp4;
+ tmp17 = tmp3 - tmp4;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]);
+ tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]);
+ tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+ MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */
+ CONST_BITS-PASS1_BITS);
+
+ tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */
+ MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */
+ + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */
+ - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */
+ MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */
+ MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */
+ MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */
+ tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */
+ MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */
+ tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */
+ MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */
+ tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */
+ MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */
+ MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */
+ tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+ - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */
+ tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+ + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */
+ tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+ + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by 8/16 = 1/2.
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+
+ tmp10 = tmp0 + tmp3;
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS+1);
+ dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS+1);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865),
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065),
+ CONST_BITS+PASS1_BITS+1);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0 + tmp10 + tmp12,
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1 + tmp11 + tmp13,
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2 + tmp11 + tmp12,
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3 + tmp10 + tmp13,
+ CONST_BITS+PASS1_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 14x7 sample block.
+ *
+ * 14-point FDCT in pass 1 (rows), 7-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_14x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 z1, z2, z3;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Zero bottom row of output coefficient block. */
+ MEMZERO(&data[DCTSIZE*7], SIZEOF(DCTELEM) * DCTSIZE);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 7; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]);
+ tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]);
+ tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]);
+
+ tmp10 = tmp0 + tmp6;
+ tmp14 = tmp0 - tmp6;
+ tmp11 = tmp1 + tmp5;
+ tmp15 = tmp1 - tmp5;
+ tmp12 = tmp2 + tmp4;
+ tmp16 = tmp2 - tmp4;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]);
+ tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE) << PASS1_BITS);
+ tmp13 += tmp13;
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */
+ MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */
+ MULTIPLY(tmp12 - tmp13, FIX(0.881747734)), /* c8 */
+ CONST_BITS-PASS1_BITS);
+
+ tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686)); /* c6 */
+
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590)) /* c2-c6 */
+ + MULTIPLY(tmp16, FIX(0.613604268)), /* c10 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954)) /* c6+c10 */
+ - MULTIPLY(tmp16, FIX(1.378756276)), /* c2 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = tmp1 + tmp2;
+ tmp11 = tmp5 - tmp4;
+ dataptr[7] = (DCTELEM) ((tmp0 - tmp10 + tmp3 - tmp11 - tmp6) << PASS1_BITS);
+ tmp3 <<= CONST_BITS;
+ tmp10 = MULTIPLY(tmp10, - FIX(0.158341681)); /* -c13 */
+ tmp11 = MULTIPLY(tmp11, FIX(1.405321284)); /* c1 */
+ tmp10 += tmp11 - tmp3;
+ tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) + /* c5 */
+ MULTIPLY(tmp4 + tmp6, FIX(0.752406978)); /* c9 */
+ dataptr[5] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */
+ + MULTIPLY(tmp4, FIX(1.119999435)), /* c1+c11-c9 */
+ CONST_BITS-PASS1_BITS);
+ tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) + /* c3 */
+ MULTIPLY(tmp5 - tmp6, FIX(0.467085129)); /* c11 */
+ dataptr[3] = (DCTELEM)
+ DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */
+ - MULTIPLY(tmp5, FIX(3.069855259)), /* c1+c5+c11 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[1] = (DCTELEM)
+ DESCALE(tmp11 + tmp12 + tmp3 + tmp6 -
+ MULTIPLY(tmp0 + tmp6, FIX(1.126980169)), /* c3+c5-c1 */
+ CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/14)*(8/7) = 32/49, which we
+ * partially fold into the constant multipliers and final shifting:
+ * 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14) * 64/49.
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4];
+ tmp3 = dataptr[DCTSIZE*3];
+
+ tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5];
+ tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4];
+
+ z1 = tmp0 + tmp2;
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */
+ CONST_BITS+PASS1_BITS+1);
+ tmp3 += tmp3;
+ z1 -= tmp3;
+ z1 -= tmp3;
+ z1 = MULTIPLY(z1, FIX(0.461784020)); /* (c2+c6-c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084)); /* (c2+c4-c6)/2 */
+ z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446)); /* c6 */
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS+1);
+ z1 -= z2;
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509)); /* c4 */
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS+1);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */
+ tmp1 += tmp2;
+ tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310)); /* c5 */
+ tmp0 += tmp3;
+ tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355)); /* c3+c1-c5 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 12x6 sample block.
+ *
+ * 12-point FDCT in pass 1 (rows), 6-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_12x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Zero 2 bottom rows of output coefficient block. */
+ MEMZERO(&data[DCTSIZE*6], SIZEOF(DCTELEM) * DCTSIZE * 2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 6; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]);
+
+ tmp10 = tmp0 + tmp5;
+ tmp13 = tmp0 - tmp5;
+ tmp11 = tmp1 + tmp4;
+ tmp14 = tmp1 - tmp4;
+ tmp12 = tmp2 + tmp3;
+ tmp15 = tmp2 - tmp3;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[6] = (DCTELEM) ((tmp13 - tmp14 - tmp15) << PASS1_BITS);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100); /* c9 */
+ tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865); /* c3-c9 */
+ tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065); /* c3+c9 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054)); /* c5 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669)); /* c7 */
+ tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */
+ + MULTIPLY(tmp5, FIX(0.184591911)); /* c11 */
+ tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */
+ tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */
+ + MULTIPLY(tmp5, FIX(0.860918669)); /* c7 */
+ tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */
+ - MULTIPLY(tmp5, FIX(1.121971054)); /* c5 */
+ tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */
+ - MULTIPLY(tmp2 + tmp5, FIX_0_541196100); /* c9 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/12)*(8/6) = 8/9, which we
+ * partially fold into the constant multipliers and final shifting:
+ * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9.
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];
+ tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */
+ CONST_BITS+PASS1_BITS+1);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 10x5 sample block.
+ *
+ * 10-point FDCT in pass 1 (rows), 5-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_10x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Zero 3 bottom rows of output coefficient block. */
+ MEMZERO(&data[DCTSIZE*5], SIZEOF(DCTELEM) * DCTSIZE * 3);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 5; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]);
+ tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]);
+
+ tmp10 = tmp0 + tmp4;
+ tmp13 = tmp0 - tmp4;
+ tmp11 = tmp1 + tmp3;
+ tmp14 = tmp1 - tmp3;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << PASS1_BITS);
+ tmp12 += tmp12;
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */
+ MULTIPLY(tmp11 - tmp12, FIX(0.437016024)), /* c8 */
+ CONST_BITS-PASS1_BITS);
+ tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876)); /* c6 */
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)), /* c2-c6 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)), /* c2+c6 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = tmp0 + tmp4;
+ tmp11 = tmp1 - tmp3;
+ dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << PASS1_BITS);
+ tmp2 <<= CONST_BITS;
+ dataptr[1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) + /* c1 */
+ MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 + /* c3 */
+ MULTIPLY(tmp3, FIX(0.642039522)) + /* c7 */
+ MULTIPLY(tmp4, FIX(0.221231742)), /* c9 */
+ CONST_BITS-PASS1_BITS);
+ tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) - /* (c3+c7)/2 */
+ MULTIPLY(tmp1 + tmp3, FIX(0.587785252)); /* (c1-c9)/2 */
+ tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) + /* (c3-c7)/2 */
+ (tmp11 << (CONST_BITS - 1)) - tmp2;
+ dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/10)*(8/5) = 32/25, which we
+ * fold into the constant multipliers:
+ * 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10) * 32/25.
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3];
+ tmp2 = dataptr[DCTSIZE*2];
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)), /* 32/25 */
+ CONST_BITS+PASS1_BITS);
+ tmp11 = MULTIPLY(tmp11, FIX(1.011928851)); /* (c2+c4)/2 */
+ tmp10 -= tmp2 << 2;
+ tmp10 = MULTIPLY(tmp10, FIX(0.452548340)); /* (c2-c4)/2 */
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961)); /* c3 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on an 8x4 sample block.
+ *
+ * 8-point FDCT in pass 1 (rows), 4-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_8x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Zero 4 bottom rows of output coefficient block. */
+ MEMZERO(&data[DCTSIZE*4], SIZEOF(DCTELEM) * DCTSIZE * 4);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We must also scale the output by 8/4 = 2, which we add here. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+
+ tmp10 = tmp0 + tmp3;
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << (PASS1_BITS+1));
+ dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << (PASS1_BITS+1));
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-2);
+ dataptr[2] = (DCTELEM) RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865),
+ CONST_BITS-PASS1_BITS-1);
+ dataptr[6] = (DCTELEM) RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065),
+ CONST_BITS-PASS1_BITS-1);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-2);
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS-PASS1_BITS-1);
+ dataptr[3] = (DCTELEM)
+ RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS-PASS1_BITS-1);
+ dataptr[5] = (DCTELEM)
+ RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS-PASS1_BITS-1);
+ dataptr[7] = (DCTELEM)
+ RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS-PASS1_BITS-1);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * 4-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1));
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];
+
+ tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS);
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 6x3 sample block.
+ *
+ * 6-point FDCT in pass 1 (rows), 3-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_6x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2;
+ INT32 tmp10, tmp11, tmp12;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 3; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);
+ tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << (PASS1_BITS+1));
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */
+ CONST_BITS-PASS1_BITS-1);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */
+ CONST_BITS-PASS1_BITS-1);
+
+ /* Odd part */
+
+ tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */
+ CONST_BITS-PASS1_BITS-1);
+
+ dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << (PASS1_BITS+1)));
+ dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << (PASS1_BITS+1));
+ dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << (PASS1_BITS+1)));
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially
+ * fold into the constant multipliers (other part was done in pass 1):
+ * 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6) * 16/9.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 6; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2];
+ tmp1 = dataptr[DCTSIZE*1];
+
+ tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2, FIX(2.177324216)), /* c1 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 4x2 sample block.
+ *
+ * 4-point FDCT in pass 1 (rows), 2-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_4x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1;
+ INT32 tmp10, tmp11;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We must also scale the output by (8/4)*(8/2) = 2**3, which we add here. */
+ /* 4-point FDCT kernel, */
+ /* cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 2; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+3));
+ dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+3));
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-4);
+
+ dataptr[1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS-PASS1_BITS-3);
+ dataptr[3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS-PASS1_BITS-3);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = dataptr[DCTSIZE*0] + (ONE << (PASS1_BITS-1));
+ tmp1 = dataptr[DCTSIZE*1];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS);
+
+ /* Odd part */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 2x1 sample block.
+ *
+ * 2-point FDCT in pass 1 (rows), 1-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_2x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1;
+ JSAMPROW elemptr;
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ elemptr = sample_data[0] + start_col;
+
+ tmp0 = GETJSAMPLE(elemptr[0]);
+ tmp1 = GETJSAMPLE(elemptr[1]);
+
+ /* We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/2)*(8/1) = 2**5.
+ */
+
+ /* Even part */
+ /* Apply unsigned->signed conversion */
+ data[0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5);
+
+ /* Odd part */
+ data[1] = (DCTELEM) ((tmp0 - tmp1) << 5);
+}
+
+
+/*
+ * Perform the forward DCT on an 8x16 sample block.
+ *
+ * 8-point FDCT in pass 1 (rows), 16-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_8x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;
+ INT32 z1;
+ DCTELEM workspace[DCTSIZE2];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+
+ tmp10 = tmp0 + tmp3;
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865),
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM) DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065),
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0 + tmp10 + tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1 + tmp11 + tmp13, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2 + tmp11 + tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp3 + tmp10 + tmp13, CONST_BITS-PASS1_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == DCTSIZE * 2)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by 8/16 = 1/2.
+ * 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32).
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3];
+ tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2];
+ tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1];
+ tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0];
+
+ tmp10 = tmp0 + tmp7;
+ tmp14 = tmp0 - tmp7;
+ tmp11 = tmp1 + tmp6;
+ tmp15 = tmp1 - tmp6;
+ tmp12 = tmp2 + tmp5;
+ tmp16 = tmp2 - tmp5;
+ tmp13 = tmp3 + tmp4;
+ tmp17 = tmp3 - tmp4;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3];
+ tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2];
+ tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1];
+ tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+1);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+ MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */
+ CONST_BITS+PASS1_BITS+1);
+
+ tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */
+ MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */
+ + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */
+ - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */
+ CONST_BITS+PASS1_BITS+1);
+
+ /* Odd part */
+
+ tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */
+ MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */
+ MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */
+ MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */
+ tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */
+ MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */
+ tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */
+ MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */
+ tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */
+ MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */
+ MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */
+ tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+ - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */
+ tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+ + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */
+ tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+ + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 7x14 sample block.
+ *
+ * 7-point FDCT in pass 1 (rows), 14-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_7x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 z1, z2, z3;
+ DCTELEM workspace[8*6];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]);
+ tmp3 = GETJSAMPLE(elemptr[3]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]);
+
+ z1 = tmp0 + tmp2;
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS);
+ tmp3 += tmp3;
+ z1 -= tmp3;
+ z1 -= tmp3;
+ z1 = MULTIPLY(z1, FIX(0.353553391)); /* (c2+c6-c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002)); /* (c2+c4-c6)/2 */
+ z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123)); /* c6 */
+ dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS);
+ z1 -= z2;
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734)); /* c4 */
+ dataptr[4] = (DCTELEM)
+ DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */
+ tmp1 += tmp2;
+ tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268)); /* c5 */
+ tmp0 += tmp3;
+ tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693)); /* c3+c1-c5 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 14)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/7)*(8/14) = 32/49, which we
+ * fold into the constant multipliers:
+ * 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28) * 32/49.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 7; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3];
+ tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1];
+ tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0];
+ tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7];
+
+ tmp10 = tmp0 + tmp6;
+ tmp14 = tmp0 - tmp6;
+ tmp11 = tmp1 + tmp5;
+ tmp15 = tmp1 - tmp5;
+ tmp12 = tmp2 + tmp4;
+ tmp16 = tmp2 - tmp4;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2];
+ tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1];
+ tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0];
+ tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13,
+ FIX(0.653061224)), /* 32/49 */
+ CONST_BITS+PASS1_BITS);
+ tmp13 += tmp13;
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */
+ MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */
+ MULTIPLY(tmp12 - tmp13, FIX(0.575835255)), /* c8 */
+ CONST_BITS+PASS1_BITS);
+
+ tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570)); /* c6 */
+
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691)) /* c2-c6 */
+ + MULTIPLY(tmp16, FIX(0.400721155)), /* c10 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725)) /* c6+c10 */
+ - MULTIPLY(tmp16, FIX(0.900412262)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = tmp1 + tmp2;
+ tmp11 = tmp5 - tmp4;
+ dataptr[DCTSIZE*7] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6,
+ FIX(0.653061224)), /* 32/49 */
+ CONST_BITS+PASS1_BITS);
+ tmp3 = MULTIPLY(tmp3 , FIX(0.653061224)); /* 32/49 */
+ tmp10 = MULTIPLY(tmp10, - FIX(0.103406812)); /* -c13 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.917760839)); /* c1 */
+ tmp10 += tmp11 - tmp3;
+ tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) + /* c5 */
+ MULTIPLY(tmp4 + tmp6, FIX(0.491367823)); /* c9 */
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */
+ + MULTIPLY(tmp4, FIX(0.731428202)), /* c1+c11-c9 */
+ CONST_BITS+PASS1_BITS);
+ tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) + /* c3 */
+ MULTIPLY(tmp5 - tmp6, FIX(0.305035186)); /* c11 */
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */
+ - MULTIPLY(tmp5, FIX(2.004803435)), /* c1+c5+c11 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp11 + tmp12 + tmp3
+ - MULTIPLY(tmp0, FIX(0.735987049)) /* c3+c5-c1 */
+ - MULTIPLY(tmp6, FIX(0.082925825)), /* c9-c11-c13 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 6x12 sample block.
+ *
+ * 6-point FDCT in pass 1 (rows), 12-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_6x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ DCTELEM workspace[8*4];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);
+ tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */
+ CONST_BITS-PASS1_BITS);
+
+ dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS));
+ dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS);
+ dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS));
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 12)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/6)*(8/12) = 8/9, which we
+ * fold into the constant multipliers:
+ * 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24) * 8/9.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0];
+ tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7];
+ tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6];
+
+ tmp10 = tmp0 + tmp5;
+ tmp13 = tmp0 - tmp5;
+ tmp11 = tmp1 + tmp4;
+ tmp14 = tmp1 - tmp4;
+ tmp12 = tmp2 + tmp3;
+ tmp15 = tmp2 - tmp3;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0];
+ tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7];
+ tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)), /* c4 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) + /* 8/9 */
+ MULTIPLY(tmp13 + tmp15, FIX(1.214244803)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200)); /* c9 */
+ tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102)); /* c3-c9 */
+ tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502)); /* c3+c9 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603)); /* c5 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039)); /* c7 */
+ tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */
+ + MULTIPLY(tmp5, FIX(0.164081699)); /* c11 */
+ tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */
+ tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */
+ + MULTIPLY(tmp5, FIX(0.765261039)); /* c7 */
+ tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */
+ - MULTIPLY(tmp5, FIX(0.997307603)); /* c5 */
+ tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */
+ - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 5x10 sample block.
+ *
+ * 5-point FDCT in pass 1 (rows), 10-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_5x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ DCTELEM workspace[8*2];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]);
+ tmp2 = GETJSAMPLE(elemptr[2]);
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << PASS1_BITS);
+ tmp11 = MULTIPLY(tmp11, FIX(0.790569415)); /* (c2+c4)/2 */
+ tmp10 -= tmp2 << 2;
+ tmp10 = MULTIPLY(tmp10, FIX(0.353553391)); /* (c2-c4)/2 */
+ dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS);
+ dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876)); /* c3 */
+
+ dataptr[1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */
+ CONST_BITS-PASS1_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 10)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/5)*(8/10) = 32/25, which we
+ * fold into the constant multipliers:
+ * 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20) * 32/25.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 5; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0];
+ tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6];
+ tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5];
+
+ tmp10 = tmp0 + tmp4;
+ tmp13 = tmp0 - tmp4;
+ tmp11 = tmp1 + tmp3;
+ tmp14 = tmp1 - tmp3;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7];
+ tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6];
+ tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */
+ CONST_BITS+PASS1_BITS);
+ tmp12 += tmp12;
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */
+ MULTIPLY(tmp11 - tmp12, FIX(0.559380511)), /* c8 */
+ CONST_BITS+PASS1_BITS);
+ tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961)); /* c6 */
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)), /* c2-c6 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)), /* c2+c6 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = tmp0 + tmp4;
+ tmp11 = tmp1 - tmp3;
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)), /* 32/25 */
+ CONST_BITS+PASS1_BITS);
+ tmp2 = MULTIPLY(tmp2, FIX(1.28)); /* 32/25 */
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) + /* c1 */
+ MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 + /* c3 */
+ MULTIPLY(tmp3, FIX(0.821810588)) + /* c7 */
+ MULTIPLY(tmp4, FIX(0.283176630)), /* c9 */
+ CONST_BITS+PASS1_BITS);
+ tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) - /* (c3+c7)/2 */
+ MULTIPLY(tmp1 + tmp3, FIX(0.752365123)); /* (c1-c9)/2 */
+ tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) + /* (c3-c7)/2 */
+ MULTIPLY(tmp11, FIX(0.64)) - tmp2; /* 16/25 */
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 4x8 sample block.
+ *
+ * 4-point FDCT in pass 1 (rows), 8-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_4x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We must also scale the output by 8/4 = 2, which we add here. */
+ /* 4-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+1));
+ dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+1));
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-2);
+
+ dataptr[1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS-PASS1_BITS-1);
+ dataptr[3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS-PASS1_BITS-1);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+
+ /* Add fudge factor here for final descale. */
+ tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1));
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), CONST_BITS+PASS1_BITS);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*7] = (DCTELEM)
+ RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 3x6 sample block.
+ *
+ * 3-point FDCT in pass 1 (rows), 6-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_3x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2;
+ INT32 tmp10, tmp11, tmp12;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 6; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]);
+ tmp1 = GETJSAMPLE(elemptr[1]);
+
+ tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+1));
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */
+ CONST_BITS-PASS1_BITS-1);
+
+ /* Odd part */
+
+ dataptr[1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2, FIX(1.224744871)), /* c1 */
+ CONST_BITS-PASS1_BITS-1);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially
+ * fold into the constant multipliers (other part was done in pass 1):
+ * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 3; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];
+ tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 2x4 sample block.
+ *
+ * 2-point FDCT in pass 1 (rows), 4-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_2x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1;
+ INT32 tmp10, tmp11;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+ /* We must also scale the output by (8/2)*(8/4) = 2**3, which we add here. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]);
+ tmp1 = GETJSAMPLE(elemptr[1]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 3);
+
+ /* Odd part */
+
+ dataptr[1] = (DCTELEM) ((tmp0 - tmp1) << 3);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * 4-point FDCT kernel,
+ * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 2; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];
+
+ tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) (tmp0 + tmp1);
+ dataptr[DCTSIZE*2] = (DCTELEM) (tmp0 - tmp1);
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-1);
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 1x2 sample block.
+ *
+ * 1-point FDCT in pass 1 (rows), 2-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_1x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1;
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ tmp0 = GETJSAMPLE(sample_data[0][start_col]);
+ tmp1 = GETJSAMPLE(sample_data[1][start_col]);
+
+ /* We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/1)*(8/2) = 2**5.
+ */
+
+ /* Even part */
+ /* Apply unsigned->signed conversion */
+ data[DCTSIZE*0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5);
+
+ /* Odd part */
+ data[DCTSIZE*1] = (DCTELEM) ((tmp0 - tmp1) << 5);
+}
+
+#endif /* DCT_SCALING_SUPPORTED */
+#endif /* DCT_ISLOW_SUPPORTED */
diff --git a/external/jpeg-8c/jidctflt.c b/external/jpeg-8c/jidctflt.c
new file mode 100644
index 0000000..23ae9d3
--- /dev/null
+++ b/external/jpeg-8c/jidctflt.c
@@ -0,0 +1,235 @@
+/*
+ * jidctflt.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * Modified 2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a floating-point implementation of the
+ * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * This implementation should be more accurate than either of the integer
+ * IDCT implementations. However, it may not give the same results on all
+ * machines because of differences in roundoff behavior. Speed will depend
+ * on the hardware's floating point capacity.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time). Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with a fixed-point
+ * implementation, accuracy is lost due to imprecise representation of the
+ * scaled quantization values. However, that problem does not arise if
+ * we use floating point arithmetic.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce a float result.
+ */
+
+#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval))
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+GLOBAL(void)
+jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
+ FAST_FLOAT z5, z10, z11, z12, z13;
+ JCOEFPTR inptr;
+ FLOAT_MULT_TYPE * quantptr;
+ FAST_FLOAT * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = cinfo->sample_range_limit;
+ int ctr;
+ FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+ inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+ inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+ inptr[DCTSIZE*7] == 0) {
+ /* AC terms all zero */
+ FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = tmp0 + tmp2; /* phase 3 */
+ tmp11 = tmp0 - tmp2;
+
+ tmp13 = tmp1 + tmp3; /* phases 5-3 */
+ tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */
+
+ tmp0 = tmp10 + tmp13; /* phase 2 */
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ z13 = tmp6 + tmp5; /* phase 6 */
+ z10 = tmp6 - tmp5;
+ z11 = tmp4 + tmp7;
+ z12 = tmp4 - tmp7;
+
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */
+
+ z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+ tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */
+ tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 - tmp5;
+
+ wsptr[DCTSIZE*0] = tmp0 + tmp7;
+ wsptr[DCTSIZE*7] = tmp0 - tmp7;
+ wsptr[DCTSIZE*1] = tmp1 + tmp6;
+ wsptr[DCTSIZE*6] = tmp1 - tmp6;
+ wsptr[DCTSIZE*2] = tmp2 + tmp5;
+ wsptr[DCTSIZE*5] = tmp2 - tmp5;
+ wsptr[DCTSIZE*3] = tmp3 + tmp4;
+ wsptr[DCTSIZE*4] = tmp3 - tmp4;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+ /* Rows of zeroes can be exploited in the same way as we did with columns.
+ * However, the column calculation has created many nonzero AC terms, so
+ * the simplification applies less often (typically 5% to 10% of the time).
+ * And testing floats for zero is relatively expensive, so we don't bother.
+ */
+
+ /* Even part */
+
+ /* Apply signed->unsigned and prepare float->int conversion */
+ z5 = wsptr[0] + ((FAST_FLOAT) CENTERJSAMPLE + (FAST_FLOAT) 0.5);
+ tmp10 = z5 + wsptr[4];
+ tmp11 = z5 - wsptr[4];
+
+ tmp13 = wsptr[2] + wsptr[6];
+ tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13;
+
+ tmp0 = tmp10 + tmp13;
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z13 = wsptr[5] + wsptr[3];
+ z10 = wsptr[5] - wsptr[3];
+ z11 = wsptr[1] + wsptr[7];
+ z12 = wsptr[1] - wsptr[7];
+
+ tmp7 = z11 + z13;
+ tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562);
+
+ z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+ tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */
+ tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7;
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 - tmp5;
+
+ /* Final output stage: float->int conversion and range-limit */
+
+ outptr[0] = range_limit[((int) (tmp0 + tmp7)) & RANGE_MASK];
+ outptr[7] = range_limit[((int) (tmp0 - tmp7)) & RANGE_MASK];
+ outptr[1] = range_limit[((int) (tmp1 + tmp6)) & RANGE_MASK];
+ outptr[6] = range_limit[((int) (tmp1 - tmp6)) & RANGE_MASK];
+ outptr[2] = range_limit[((int) (tmp2 + tmp5)) & RANGE_MASK];
+ outptr[5] = range_limit[((int) (tmp2 - tmp5)) & RANGE_MASK];
+ outptr[3] = range_limit[((int) (tmp3 + tmp4)) & RANGE_MASK];
+ outptr[4] = range_limit[((int) (tmp3 - tmp4)) & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
diff --git a/external/jpeg-8c/jidctfst.c b/external/jpeg-8c/jidctfst.c
new file mode 100644
index 0000000..dba4216
--- /dev/null
+++ b/external/jpeg-8c/jidctfst.c
@@ -0,0 +1,368 @@
+/*
+ * jidctfst.c
+ *
+ * Copyright (C) 1994-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 contains a fast, not so accurate integer implementation of the
+ * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time). Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with fixed-point math,
+ * accuracy is lost due to imprecise representation of the scaled
+ * quantization values. The smaller the quantization table entry, the less
+ * precise the scaled value, so this implementation does worse with high-
+ * quality-setting files than with low-quality ones.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_IFAST_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Scaling decisions are generally the same as in the LL&M algorithm;
+ * see jidctint.c for more details. However, we choose to descale
+ * (right shift) multiplication products as soon as they are formed,
+ * rather than carrying additional fractional bits into subsequent additions.
+ * This compromises accuracy slightly, but it lets us save a few shifts.
+ * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
+ * everywhere except in the multiplications proper; this saves a good deal
+ * of work on 16-bit-int machines.
+ *
+ * The dequantized coefficients are not integers because the AA&N scaling
+ * factors have been incorporated. We represent them scaled up by PASS1_BITS,
+ * so that the first and second IDCT rounds have the same input scaling.
+ * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to
+ * avoid a descaling shift; this compromises accuracy rather drastically
+ * for small quantization table entries, but it saves a lot of shifts.
+ * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway,
+ * so we use a much larger scaling factor to preserve accuracy.
+ *
+ * A final compromise is to represent the multiplicative constants to only
+ * 8 fractional bits, rather than 13. This saves some shifting work on some
+ * machines, and may also reduce the cost of multiplication (since there
+ * are fewer one-bits in the constants).
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS 8
+#define PASS1_BITS 2
+#else
+#define CONST_BITS 8
+#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 8
+#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */
+#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */
+#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */
+#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */
+#else
+#define FIX_1_082392200 FIX(1.082392200)
+#define FIX_1_414213562 FIX(1.414213562)
+#define FIX_1_847759065 FIX(1.847759065)
+#define FIX_2_613125930 FIX(2.613125930)
+#endif
+
+
+/* We can gain a little more speed, with a further compromise in accuracy,
+ * by omitting the addition in a descaling shift. This yields an incorrectly
+ * rounded result half the time...
+ */
+
+#ifndef USE_ACCURATE_ROUNDING
+#undef DESCALE
+#define DESCALE(x,n) RIGHT_SHIFT(x, n)
+#endif
+
+
+/* Multiply a DCTELEM variable by an INT32 constant, and immediately
+ * descale to yield a DCTELEM result.
+ */
+
+#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS))
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce a DCTELEM result. For 8-bit data a 16x16->16
+ * multiplication will do. For 12-bit data, the multiplier table is
+ * declared INT32, so a 32-bit multiply will be used.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval))
+#else
+#define DEQUANTIZE(coef,quantval) \
+ DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS)
+#endif
+
+
+/* Like DESCALE, but applies to a DCTELEM and produces an int.
+ * We assume that int right shift is unsigned if INT32 right shift is.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS DCTELEM ishift_temp;
+#if BITS_IN_JSAMPLE == 8
+#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */
+#else
+#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */
+#endif
+#define IRIGHT_SHIFT(x,shft) \
+ ((ishift_temp = (x)) < 0 ? \
+ (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \
+ (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
+#endif
+
+#ifdef USE_ACCURATE_ROUNDING
+#define IDESCALE(x,n) ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n))
+#else
+#define IDESCALE(x,n) ((int) IRIGHT_SHIFT(x, n))
+#endif
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+GLOBAL(void)
+jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ DCTELEM tmp10, tmp11, tmp12, tmp13;
+ DCTELEM z5, z10, z11, z12, z13;
+ JCOEFPTR inptr;
+ IFAST_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[DCTSIZE2]; /* buffers data between passes */
+ SHIFT_TEMPS /* for DESCALE */
+ ISHIFT_TEMPS /* for IDESCALE */
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (IFAST_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+ inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+ inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+ inptr[DCTSIZE*7] == 0) {
+ /* AC terms all zero */
+ int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = tmp0 + tmp2; /* phase 3 */
+ tmp11 = tmp0 - tmp2;
+
+ tmp13 = tmp1 + tmp3; /* phases 5-3 */
+ tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
+
+ tmp0 = tmp10 + tmp13; /* phase 2 */
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ z13 = tmp6 + tmp5; /* phase 6 */
+ z10 = tmp6 - tmp5;
+ z11 = tmp4 + tmp7;
+ z12 = tmp4 - tmp7;
+
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+ tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7);
+ wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7);
+ wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6);
+ wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6);
+ wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5);
+ wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5);
+ wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4);
+ wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4);
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+ /* Rows of zeroes can be exploited in the same way as we did with columns.
+ * However, the column calculation has created many nonzero AC terms, so
+ * the simplification applies less often (typically 5% to 10% of the time).
+ * On machines with very fast multiplication, it's possible that the
+ * test takes more time than it's worth. In that case this section
+ * may be commented out.
+ */
+
+#ifndef NO_ZERO_ROW_TEST
+ if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
+ wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
+ /* AC terms all zero */
+ JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3)
+ & RANGE_MASK];
+
+ outptr[0] = dcval;
+ outptr[1] = dcval;
+ outptr[2] = dcval;
+ outptr[3] = dcval;
+ outptr[4] = dcval;
+ outptr[5] = dcval;
+ outptr[6] = dcval;
+ outptr[7] = dcval;
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ continue;
+ }
+#endif
+
+ /* Even part */
+
+ tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]);
+ tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]);
+
+ tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]);
+ tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562)
+ - tmp13;
+
+ tmp0 = tmp10 + tmp13;
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3];
+ z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3];
+ z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7];
+ z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7];
+
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+ tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ /* Final output stage: scale down by a factor of 8 and range-limit */
+
+ outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+#endif /* DCT_IFAST_SUPPORTED */
diff --git a/external/jpeg-8c/jidctint.c b/external/jpeg-8c/jidctint.c
new file mode 100644
index 0000000..dcdf7ce
--- /dev/null
+++ b/external/jpeg-8c/jidctint.c
@@ -0,0 +1,5137 @@
+/*
+ * jidctint.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modification developed 2002-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a slow-but-accurate integer implementation of the
+ * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time). Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on an algorithm described in
+ * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+ * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+ * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+ * The primary algorithm described there uses 11 multiplies and 29 adds.
+ * We use their alternate method with 12 multiplies and 32 adds.
+ * The advantage of this method is that no data path contains more than one
+ * multiplication; this allows a very simple and accurate implementation in
+ * scaled fixed-point arithmetic, with a minimal number of shifts.
+ *
+ * We also provide IDCT routines with various output sample block sizes for
+ * direct resolution reduction or enlargement and for direct resolving the
+ * common 2x1 and 1x2 subsampling cases without additional resampling: NxN
+ * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 input DCT block.
+ *
+ * For N<8 we simply take the corresponding low-frequency coefficients of
+ * the 8x8 input DCT block and apply an NxN point IDCT on the sub-block
+ * to yield the downscaled outputs.
+ * This can be seen as direct low-pass downsampling from the DCT domain
+ * point of view rather than the usual spatial domain point of view,
+ * yielding significant computational savings and results at least
+ * as good as common bilinear (averaging) spatial downsampling.
+ *
+ * For N>8 we apply a partial NxN IDCT on the 8 input coefficients as
+ * lower frequencies and higher frequencies assumed to be zero.
+ * It turns out that the computational effort is similar to the 8x8 IDCT
+ * regarding the output size.
+ * Furthermore, the scaling and descaling is the same for all IDCT sizes.
+ *
+ * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases
+ * since there would be too many additional constants to pre-calculate.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_ISLOW_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */
+#endif
+
+
+/*
+ * The poop on this scaling stuff is as follows:
+ *
+ * Each 1-D IDCT step produces outputs which are a factor of sqrt(N)
+ * larger than the true IDCT outputs. The final outputs are therefore
+ * a factor of N larger than desired; since N=8 this can be cured by
+ * a simple right shift at the end of the algorithm. The advantage of
+ * this arrangement is that we save two multiplications per 1-D IDCT,
+ * because the y0 and y4 inputs need not be divided by sqrt(N).
+ *
+ * We have to do addition and subtraction of the integer inputs, which
+ * is no problem, and multiplication by fractional constants, which is
+ * a problem to do in integer arithmetic. We multiply all the constants
+ * by CONST_SCALE and convert them to integer constants (thus retaining
+ * CONST_BITS bits of precision in the constants). After doing a
+ * multiplication we have to divide the product by CONST_SCALE, with proper
+ * rounding, to produce the correct output. This division can be done
+ * cheaply as a right shift of CONST_BITS bits. We postpone shifting
+ * as long as possible so that partial sums can be added together with
+ * full fractional precision.
+ *
+ * The outputs of the first pass are scaled up by PASS1_BITS bits so that
+ * they are represented to better-than-integral precision. These outputs
+ * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+ * with the recommended scaling. (To scale up 12-bit sample data further, an
+ * intermediate INT32 array would be needed.)
+ *
+ * To avoid overflow of the 32-bit intermediate results in pass 2, we must
+ * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis
+ * shows that the values given below are the most effective.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS 13
+#define PASS1_BITS 2
+#else
+#define CONST_BITS 13
+#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 13
+#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */
+#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */
+#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */
+#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */
+#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */
+#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */
+#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */
+#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */
+#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */
+#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */
+#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */
+#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */
+#else
+#define FIX_0_298631336 FIX(0.298631336)
+#define FIX_0_390180644 FIX(0.390180644)
+#define FIX_0_541196100 FIX(0.541196100)
+#define FIX_0_765366865 FIX(0.765366865)
+#define FIX_0_899976223 FIX(0.899976223)
+#define FIX_1_175875602 FIX(1.175875602)
+#define FIX_1_501321110 FIX(1.501321110)
+#define FIX_1_847759065 FIX(1.847759065)
+#define FIX_1_961570560 FIX(1.961570560)
+#define FIX_2_053119869 FIX(2.053119869)
+#define FIX_2_562915447 FIX(2.562915447)
+#define FIX_3_072711026 FIX(3.072711026)
+#endif
+
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * For 8-bit samples with the recommended scaling, all the variable
+ * and constant values involved are no more than 16 bits wide, so a
+ * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+ * For 12-bit samples, a full 32-bit multiplication will be needed.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MULTIPLY(var,const) MULTIPLY16C16(var,const)
+#else
+#define MULTIPLY(var,const) ((var) * (const))
+#endif
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce an int result. In this module, both inputs and result
+ * are 16 bits or less, so either int or short multiply will work.
+ */
+
+#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval))
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+GLOBAL(void)
+jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[DCTSIZE2]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+ /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+ inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+ inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+ inptr[DCTSIZE*7] == 0) {
+ /* AC terms all zero */
+ int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z2 <<= CONST_BITS;
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z2 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ tmp0 = z2 + z3;
+ tmp1 = z2 - z3;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+ /* Rows of zeroes can be exploited in the same way as we did with columns.
+ * However, the column calculation has created many nonzero AC terms, so
+ * the simplification applies less often (typically 5% to 10% of the time).
+ * On machines with very fast multiplication, it's possible that the
+ * test takes more time than it's worth. In that case this section
+ * may be commented out.
+ */
+
+#ifndef NO_ZERO_ROW_TEST
+ if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
+ wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
+ /* AC terms all zero */
+ JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
+ & RANGE_MASK];
+
+ outptr[0] = dcval;
+ outptr[1] = dcval;
+ outptr[2] = dcval;
+ outptr[3] = dcval;
+ outptr[4] = dcval;
+ outptr[5] = dcval;
+ outptr[6] = dcval;
+ outptr[7] = dcval;
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ continue;
+ }
+#endif
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[6];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ /* Add fudge factor here for final descale. */
+ z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 = (INT32) wsptr[4];
+
+ tmp0 = (z2 + z3) << CONST_BITS;
+ tmp1 = (z2 - z3) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = (INT32) wsptr[7];
+ tmp1 = (INT32) wsptr[5];
+ tmp2 = (INT32) wsptr[3];
+ tmp3 = (INT32) wsptr[1];
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+#ifdef IDCT_SCALING_SUPPORTED
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 7x7 output block.
+ *
+ * Optimized algorithm with 12 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/14).
+ */
+
+GLOBAL(void)
+jpeg_idct_7x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[7*7]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp13 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp13 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp13 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */
+ tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+ tmp0 = z1 + z3;
+ z2 -= tmp0;
+ tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */
+ tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */
+ tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */
+ tmp13 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */
+ tmp1 += tmp2;
+ z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */
+ tmp0 += z2;
+ tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */
+
+ /* Final output stage */
+
+ wsptr[7*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[7*6] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[7*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[7*5] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[7*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[7*4] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[7*3] = (int) RIGHT_SHIFT(tmp13, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 7 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 7; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp13 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp13 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[4];
+ z3 = (INT32) wsptr[6];
+
+ tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */
+ tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+ tmp0 = z1 + z3;
+ z2 -= tmp0;
+ tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */
+ tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */
+ tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */
+ tmp13 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */
+ tmp1 += tmp2;
+ z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */
+ tmp0 += z2;
+ tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 7; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 6x6 output block.
+ *
+ * Optimized algorithm with 3 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/12).
+ */
+
+GLOBAL(void)
+jpeg_idct_6x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[6*6]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */
+ tmp1 = tmp0 + tmp10;
+ tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS);
+ tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */
+ tmp10 = tmp1 + tmp0;
+ tmp12 = tmp1 - tmp0;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+ tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+ tmp1 = (z1 - z2 - z3) << PASS1_BITS;
+
+ /* Final output stage */
+
+ wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[6*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[6*1] = (int) (tmp11 + tmp1);
+ wsptr[6*4] = (int) (tmp11 - tmp1);
+ wsptr[6*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[6*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 6 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+ tmp2 = (INT32) wsptr[4];
+ tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */
+ tmp1 = tmp0 + tmp10;
+ tmp11 = tmp0 - tmp10 - tmp10;
+ tmp10 = (INT32) wsptr[2];
+ tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */
+ tmp10 = tmp1 + tmp0;
+ tmp12 = tmp1 - tmp0;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+ tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+ tmp1 = (z1 - z2 - z3) << CONST_BITS;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 6; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 5x5 output block.
+ *
+ * Optimized algorithm with 5 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/10).
+ */
+
+GLOBAL(void)
+jpeg_idct_5x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp10, tmp11, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[5*5]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp12 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp12 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */
+ z3 = tmp12 + z2;
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z1;
+ tmp12 -= z2 << 2;
+
+ /* Odd part */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */
+ tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */
+ tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */
+
+ /* Final output stage */
+
+ wsptr[5*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[5*4] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[5*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[5*3] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[5*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 5 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 5; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp12 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp12 <<= CONST_BITS;
+ tmp0 = (INT32) wsptr[2];
+ tmp1 = (INT32) wsptr[4];
+ z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */
+ z3 = tmp12 + z2;
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z1;
+ tmp12 -= z2 << 2;
+
+ /* Odd part */
+
+ z2 = (INT32) wsptr[1];
+ z3 = (INT32) wsptr[3];
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */
+ tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */
+ tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 5; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 4x4 output block.
+ *
+ * Optimized algorithm with 3 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].
+ */
+
+GLOBAL(void)
+jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp2, tmp10, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[4*4]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+
+ tmp10 = (tmp0 + tmp2) << PASS1_BITS;
+ tmp12 = (tmp0 - tmp2) << PASS1_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS-PASS1_BITS);
+ tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Final output stage */
+
+ wsptr[4*0] = (int) (tmp10 + tmp0);
+ wsptr[4*3] = (int) (tmp10 - tmp0);
+ wsptr[4*1] = (int) (tmp12 + tmp2);
+ wsptr[4*2] = (int) (tmp12 - tmp2);
+ }
+
+ /* Pass 2: process 4 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 4; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp2 = (INT32) wsptr[2];
+
+ tmp10 = (tmp0 + tmp2) << CONST_BITS;
+ tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = (INT32) wsptr[1];
+ z3 = (INT32) wsptr[3];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+ tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 4; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 3x3 output block.
+ *
+ * Optimized algorithm with 2 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/6).
+ */
+
+GLOBAL(void)
+jpeg_idct_3x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp2, tmp10, tmp12;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[3*3]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+ tmp10 = tmp0 + tmp12;
+ tmp2 = tmp0 - tmp12 - tmp12;
+
+ /* Odd part */
+
+ tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+ /* Final output stage */
+
+ wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[3*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[3*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 3 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 3; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+ tmp2 = (INT32) wsptr[2];
+ tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+ tmp10 = tmp0 + tmp12;
+ tmp2 = tmp0 - tmp12 - tmp12;
+
+ /* Odd part */
+
+ tmp12 = (INT32) wsptr[1];
+ tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 3; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 2x2 output block.
+ *
+ * Multiplication-less algorithm.
+ */
+
+GLOBAL(void)
+jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+ ISLOW_MULT_TYPE * quantptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input. */
+
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+
+ /* Column 0 */
+ tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ /* Add fudge factor here for final descale. */
+ tmp4 += ONE << 2;
+
+ tmp0 = tmp4 + tmp5;
+ tmp2 = tmp4 - tmp5;
+
+ /* Column 1 */
+ tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0+1], quantptr[DCTSIZE*0+1]);
+ tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1+1], quantptr[DCTSIZE*1+1]);
+
+ tmp1 = tmp4 + tmp5;
+ tmp3 = tmp4 - tmp5;
+
+ /* Pass 2: process 2 rows, store into output array. */
+
+ /* Row 0 */
+ outptr = output_buf[0] + output_col;
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK];
+
+ /* Row 1 */
+ outptr = output_buf[1] + output_col;
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp2 + tmp3, 3) & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2 - tmp3, 3) & RANGE_MASK];
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 1x1 output block.
+ *
+ * We hardly need an inverse DCT routine for this: just take the
+ * average pixel value, which is one-eighth of the DC coefficient.
+ */
+
+GLOBAL(void)
+jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ int dcval;
+ ISLOW_MULT_TYPE * quantptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ SHIFT_TEMPS
+
+ /* 1x1 is trivial: just take the DC coefficient divided by 8. */
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ dcval = DEQUANTIZE(coef_block[0], quantptr[0]);
+ dcval = (int) DESCALE((INT32) dcval, 3);
+
+ output_buf[0][output_col] = range_limit[dcval & RANGE_MASK];
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 9x9 output block.
+ *
+ * Optimized algorithm with 10 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/18).
+ */
+
+GLOBAL(void)
+jpeg_idct_9x9 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*9]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp3 = MULTIPLY(z3, FIX(0.707106781)); /* c6 */
+ tmp1 = tmp0 + tmp3;
+ tmp2 = tmp0 - tmp3 - tmp3;
+
+ tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */
+ tmp11 = tmp2 + tmp0;
+ tmp14 = tmp2 - tmp0 - tmp0;
+
+ tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */
+ tmp2 = MULTIPLY(z1, FIX(1.083350441)); /* c4 */
+ tmp3 = MULTIPLY(z2, FIX(0.245575608)); /* c8 */
+
+ tmp10 = tmp1 + tmp0 - tmp3;
+ tmp12 = tmp1 - tmp0 + tmp2;
+ tmp13 = tmp1 - tmp2 + tmp3;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ z2 = MULTIPLY(z2, - FIX(1.224744871)); /* -c3 */
+
+ tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525)); /* c7 */
+ tmp0 = tmp2 + tmp3 - z2;
+ tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481)); /* c1 */
+ tmp2 += z2 - tmp1;
+ tmp3 += z2 + tmp1;
+ tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp13 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp13 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp14, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 9 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 9; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[4];
+ z3 = (INT32) wsptr[6];
+
+ tmp3 = MULTIPLY(z3, FIX(0.707106781)); /* c6 */
+ tmp1 = tmp0 + tmp3;
+ tmp2 = tmp0 - tmp3 - tmp3;
+
+ tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */
+ tmp11 = tmp2 + tmp0;
+ tmp14 = tmp2 - tmp0 - tmp0;
+
+ tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */
+ tmp2 = MULTIPLY(z1, FIX(1.083350441)); /* c4 */
+ tmp3 = MULTIPLY(z2, FIX(0.245575608)); /* c8 */
+
+ tmp10 = tmp1 + tmp0 - tmp3;
+ tmp12 = tmp1 - tmp0 + tmp2;
+ tmp13 = tmp1 - tmp2 + tmp3;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ z2 = MULTIPLY(z2, - FIX(1.224744871)); /* -c3 */
+
+ tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525)); /* c7 */
+ tmp0 = tmp2 + tmp3 - z2;
+ tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481)); /* c1 */
+ tmp2 += z2 - tmp1;
+ tmp3 += z2 + tmp1;
+ tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 10x10 output block.
+ *
+ * Optimized algorithm with 12 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/20).
+ */
+
+GLOBAL(void)
+jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24;
+ INT32 z1, z2, z3, z4, z5;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*10]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */
+ z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z2;
+
+ tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1), /* c0 = (c4-c8)*2 */
+ CONST_BITS-PASS1_BITS);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */
+ tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+ tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+ tmp20 = tmp10 + tmp12;
+ tmp24 = tmp10 - tmp12;
+ tmp21 = tmp11 + tmp13;
+ tmp23 = tmp11 - tmp13;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = z2 + z4;
+ tmp13 = z2 - z4;
+
+ tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */
+ z5 = z3 << CONST_BITS;
+
+ z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */
+ z4 = z5 + tmp12;
+
+ tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+ tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */
+ z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+ tmp12 = (z1 - tmp13 - z3) << PASS1_BITS;
+
+ tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+ tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) (tmp22 + tmp12);
+ wsptr[8*7] = (int) (tmp22 - tmp12);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 10 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 10; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 <<= CONST_BITS;
+ z4 = (INT32) wsptr[4];
+ z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */
+ z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z2;
+
+ tmp22 = z3 - ((z1 - z2) << 1); /* c0 = (c4-c8)*2 */
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[6];
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */
+ tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+ tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+ tmp20 = tmp10 + tmp12;
+ tmp24 = tmp10 - tmp12;
+ tmp21 = tmp11 + tmp13;
+ tmp23 = tmp11 - tmp13;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z3 <<= CONST_BITS;
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = z2 + z4;
+ tmp13 = z2 - z4;
+
+ tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */
+ z4 = z3 + tmp12;
+
+ tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+ tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */
+ z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+ tmp12 = ((z1 - tmp13) << CONST_BITS) - z3;
+
+ tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+ tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 11x11 output block.
+ *
+ * Optimized algorithm with 24 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/22).
+ */
+
+GLOBAL(void)
+jpeg_idct_11x11 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*11]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp10 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp10 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132)); /* c2+c4 */
+ tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045)); /* c2-c6 */
+ z4 = z1 + z3;
+ tmp24 = MULTIPLY(z4, - FIX(1.155664402)); /* -(c2-c10) */
+ z4 -= z2;
+ tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976)); /* c2 */
+ tmp21 = tmp20 + tmp23 + tmp25 -
+ MULTIPLY(z2, FIX(1.821790775)); /* c2+c4+c10-c6 */
+ tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */
+ tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */
+ tmp24 += tmp25;
+ tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120)); /* c8+c10 */
+ tmp24 += MULTIPLY(z2, FIX(1.944413522)) - /* c2+c8 */
+ MULTIPLY(z1, FIX(1.390975730)); /* c4+c10 */
+ tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = z1 + z2;
+ tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.887983902)); /* c3-c9 */
+ tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295)); /* c5-c9 */
+ tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(z1, FIX(0.923107866)); /* c7+c5+c3-c1-2*c9 */
+ z1 = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */
+ tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588)); /* c1+c7+3*c9-c3 */
+ tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623)); /* c3+c5-c7-c9 */
+ z1 = MULTIPLY(z2 + z4, - FIX(1.798248910)); /* -(c1+c9) */
+ tmp11 += z1;
+ tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632)); /* c1+c5+c9-c7 */
+ tmp14 += MULTIPLY(z2, - FIX(1.467221301)) + /* -(c5+c9) */
+ MULTIPLY(z3, FIX(1.001388905)) - /* c1-c9 */
+ MULTIPLY(z4, FIX(1.684843907)); /* c3+c9 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 11 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 11; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp10 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp10 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[4];
+ z3 = (INT32) wsptr[6];
+
+ tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132)); /* c2+c4 */
+ tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045)); /* c2-c6 */
+ z4 = z1 + z3;
+ tmp24 = MULTIPLY(z4, - FIX(1.155664402)); /* -(c2-c10) */
+ z4 -= z2;
+ tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976)); /* c2 */
+ tmp21 = tmp20 + tmp23 + tmp25 -
+ MULTIPLY(z2, FIX(1.821790775)); /* c2+c4+c10-c6 */
+ tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */
+ tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */
+ tmp24 += tmp25;
+ tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120)); /* c8+c10 */
+ tmp24 += MULTIPLY(z2, FIX(1.944413522)) - /* c2+c8 */
+ MULTIPLY(z1, FIX(1.390975730)); /* c4+c10 */
+ tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = z1 + z2;
+ tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.887983902)); /* c3-c9 */
+ tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295)); /* c5-c9 */
+ tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(z1, FIX(0.923107866)); /* c7+c5+c3-c1-2*c9 */
+ z1 = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */
+ tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588)); /* c1+c7+3*c9-c3 */
+ tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623)); /* c3+c5-c7-c9 */
+ z1 = MULTIPLY(z2 + z4, - FIX(1.798248910)); /* -(c1+c9) */
+ tmp11 += z1;
+ tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632)); /* c1+c5+c9-c7 */
+ tmp14 += MULTIPLY(z2, - FIX(1.467221301)) + /* -(c5+c9) */
+ MULTIPLY(z3, FIX(1.001388905)) - /* c1-c9 */
+ MULTIPLY(z4, FIX(1.684843907)); /* c3+c9 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 12x12 output block.
+ *
+ * Optimized algorithm with 15 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/24).
+ */
+
+GLOBAL(void)
+jpeg_idct_12x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*12]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+ z1 <<= CONST_BITS;
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+ z2 <<= CONST_BITS;
+
+ tmp12 = z1 - z2;
+
+ tmp21 = z3 + tmp12;
+ tmp24 = z3 - tmp12;
+
+ tmp12 = z4 + z2;
+
+ tmp20 = tmp10 + tmp12;
+ tmp25 = tmp10 - tmp12;
+
+ tmp12 = z4 - z1 - z2;
+
+ tmp22 = tmp11 + tmp12;
+ tmp23 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */
+ tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */
+
+ tmp10 = z1 + z3;
+ tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */
+ tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */
+ tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */
+ tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */
+ tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+ tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+ tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */
+ MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */
+
+ z1 -= z4;
+ z2 -= z3;
+ z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */
+ tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */
+ tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 12 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 12; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 <<= CONST_BITS;
+
+ z4 = (INT32) wsptr[4];
+ z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ z1 = (INT32) wsptr[2];
+ z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+ z1 <<= CONST_BITS;
+ z2 = (INT32) wsptr[6];
+ z2 <<= CONST_BITS;
+
+ tmp12 = z1 - z2;
+
+ tmp21 = z3 + tmp12;
+ tmp24 = z3 - tmp12;
+
+ tmp12 = z4 + z2;
+
+ tmp20 = tmp10 + tmp12;
+ tmp25 = tmp10 - tmp12;
+
+ tmp12 = z4 - z1 - z2;
+
+ tmp22 = tmp11 + tmp12;
+ tmp23 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */
+ tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */
+
+ tmp10 = z1 + z3;
+ tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */
+ tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */
+ tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */
+ tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */
+ tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+ tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+ tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */
+ MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */
+
+ z1 -= z4;
+ z2 -= z3;
+ z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */
+ tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */
+ tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 13x13 output block.
+ *
+ * Optimized algorithm with 29 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/26).
+ */
+
+GLOBAL(void)
+jpeg_idct_13x13 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*13]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z1 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ tmp12 = MULTIPLY(tmp10, FIX(1.155388986)); /* (c4+c6)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1; /* (c4-c6)/2 */
+
+ tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13; /* c2 */
+ tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13; /* c10 */
+
+ tmp12 = MULTIPLY(tmp10, FIX(0.316450131)); /* (c8-c12)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1; /* (c8+c12)/2 */
+
+ tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13; /* c6 */
+ tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */
+
+ tmp12 = MULTIPLY(tmp10, FIX(0.435816023)); /* (c2-c10)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1; /* (c2+c10)/2 */
+
+ tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */
+ tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */
+
+ tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1; /* c0 */
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651)); /* c3 */
+ tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945)); /* c5 */
+ tmp15 = z1 + z4;
+ tmp13 = MULTIPLY(tmp15, FIX(0.937797057)); /* c7 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(z1, FIX(2.020082300)); /* c7+c5+c3-c1 */
+ tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458)); /* -c11 */
+ tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */
+ tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */
+ tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945)); /* -c5 */
+ tmp11 += tmp14;
+ tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */
+ tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813)); /* -c9 */
+ tmp12 += tmp14;
+ tmp13 += tmp14;
+ tmp15 = MULTIPLY(tmp15, FIX(0.338443458)); /* c11 */
+ tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */
+ MULTIPLY(z2, FIX(0.466105296)); /* c1-c7 */
+ z1 = MULTIPLY(z3 - z2, FIX(0.937797057)); /* c7 */
+ tmp14 += z1;
+ tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) - /* c3-c7 */
+ MULTIPLY(z4, FIX(1.742345811)); /* c1+c11 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*12] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp26, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 13 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 13; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z1 <<= CONST_BITS;
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[4];
+ z4 = (INT32) wsptr[6];
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ tmp12 = MULTIPLY(tmp10, FIX(1.155388986)); /* (c4+c6)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1; /* (c4-c6)/2 */
+
+ tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13; /* c2 */
+ tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13; /* c10 */
+
+ tmp12 = MULTIPLY(tmp10, FIX(0.316450131)); /* (c8-c12)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1; /* (c8+c12)/2 */
+
+ tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13; /* c6 */
+ tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */
+
+ tmp12 = MULTIPLY(tmp10, FIX(0.435816023)); /* (c2-c10)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1; /* (c2+c10)/2 */
+
+ tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */
+ tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */
+
+ tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1; /* c0 */
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651)); /* c3 */
+ tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945)); /* c5 */
+ tmp15 = z1 + z4;
+ tmp13 = MULTIPLY(tmp15, FIX(0.937797057)); /* c7 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(z1, FIX(2.020082300)); /* c7+c5+c3-c1 */
+ tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458)); /* -c11 */
+ tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */
+ tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */
+ tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945)); /* -c5 */
+ tmp11 += tmp14;
+ tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */
+ tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813)); /* -c9 */
+ tmp12 += tmp14;
+ tmp13 += tmp14;
+ tmp15 = MULTIPLY(tmp15, FIX(0.338443458)); /* c11 */
+ tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */
+ MULTIPLY(z2, FIX(0.466105296)); /* c1-c7 */
+ z1 = MULTIPLY(z3 - z2, FIX(0.937797057)); /* c7 */
+ tmp14 += z1;
+ tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) - /* c3-c7 */
+ MULTIPLY(z4, FIX(1.742345811)); /* c1+c11 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 14x14 output block.
+ *
+ * Optimized algorithm with 20 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/28).
+ */
+
+GLOBAL(void)
+jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*14]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z1 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */
+ z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */
+ z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */
+
+ tmp10 = z1 + z2;
+ tmp11 = z1 + z3;
+ tmp12 = z1 - z4;
+
+ tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */
+ CONST_BITS-PASS1_BITS);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */
+
+ tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+ tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+ tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */
+ MULTIPLY(z2, FIX(1.378756276)); /* c2 */
+
+ tmp20 = tmp10 + tmp13;
+ tmp26 = tmp10 - tmp13;
+ tmp21 = tmp11 + tmp14;
+ tmp25 = tmp11 - tmp14;
+ tmp22 = tmp12 + tmp15;
+ tmp24 = tmp12 - tmp15;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp13 = z4 << CONST_BITS;
+
+ tmp14 = z1 + z3;
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */
+ tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */
+ tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+ tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */
+ tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */
+ z1 -= z2;
+ tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13; /* c11 */
+ tmp16 += tmp15;
+ z1 += z4;
+ z4 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */
+ tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */
+ tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */
+ z4 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */
+ tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+ tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */
+
+ tmp13 = (z1 - z3) << PASS1_BITS;
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) (tmp23 + tmp13);
+ wsptr[8*10] = (int) (tmp23 - tmp13);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 14 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 14; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z1 <<= CONST_BITS;
+ z4 = (INT32) wsptr[4];
+ z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */
+ z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */
+ z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */
+
+ tmp10 = z1 + z2;
+ tmp11 = z1 + z3;
+ tmp12 = z1 - z4;
+
+ tmp23 = z1 - ((z2 + z3 - z4) << 1); /* c0 = (c4+c12-c8)*2 */
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[6];
+
+ z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */
+
+ tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+ tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+ tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */
+ MULTIPLY(z2, FIX(1.378756276)); /* c2 */
+
+ tmp20 = tmp10 + tmp13;
+ tmp26 = tmp10 - tmp13;
+ tmp21 = tmp11 + tmp14;
+ tmp25 = tmp11 - tmp14;
+ tmp22 = tmp12 + tmp15;
+ tmp24 = tmp12 - tmp15;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+ z4 <<= CONST_BITS;
+
+ tmp14 = z1 + z3;
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */
+ tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */
+ tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+ tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */
+ tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */
+ z1 -= z2;
+ tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4; /* c11 */
+ tmp16 += tmp15;
+ tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4; /* -c13 */
+ tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */
+ tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */
+ tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */
+ tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+ tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */
+
+ tmp13 = ((z1 - z3) << CONST_BITS) + z4;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 15x15 output block.
+ *
+ * Optimized algorithm with 22 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/30).
+ */
+
+GLOBAL(void)
+jpeg_idct_15x15 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*15]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z1 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */
+ tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */
+
+ tmp12 = z1 - tmp10;
+ tmp13 = z1 + tmp11;
+ z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */
+
+ z4 = z2 - z3;
+ z3 += z2;
+ tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */
+ z2 = MULTIPLY(z2, FIX(1.439773946)); /* c4+c14 */
+
+ tmp20 = tmp13 + tmp10 + tmp11;
+ tmp23 = tmp12 - tmp10 + tmp11 + z2;
+
+ tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */
+
+ tmp25 = tmp13 - tmp10 - tmp11;
+ tmp26 = tmp12 + tmp10 - tmp11 - z2;
+
+ tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */
+
+ tmp21 = tmp12 + tmp10 + tmp11;
+ tmp24 = tmp13 - tmp10 + tmp11;
+ tmp11 += tmp11;
+ tmp22 = z1 + tmp11; /* c10 = c6-c12 */
+ tmp27 = z1 - tmp11 - tmp11; /* c0 = (c6-c12)*2 */
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z3 = MULTIPLY(z4, FIX(1.224744871)); /* c5 */
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp13 = z2 - z4;
+ tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876)); /* c9 */
+ tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148)); /* c3-c9 */
+ tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899)); /* c3+c9 */
+
+ tmp13 = MULTIPLY(z2, - FIX(0.831253876)); /* -c9 */
+ tmp15 = MULTIPLY(z2, - FIX(1.344997024)); /* -c3 */
+ z2 = z1 - z4;
+ tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353)); /* c1 */
+
+ tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */
+ tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */
+ tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3; /* c5 */
+ z2 = MULTIPLY(z1 + z4, FIX(0.575212477)); /* c11 */
+ tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3; /* c7-c11 */
+ tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3; /* c11+c13 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*14] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*13] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*12] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp27, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 15 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 15; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z1 <<= CONST_BITS;
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[4];
+ z4 = (INT32) wsptr[6];
+
+ tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */
+ tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */
+
+ tmp12 = z1 - tmp10;
+ tmp13 = z1 + tmp11;
+ z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */
+
+ z4 = z2 - z3;
+ z3 += z2;
+ tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */
+ z2 = MULTIPLY(z2, FIX(1.439773946)); /* c4+c14 */
+
+ tmp20 = tmp13 + tmp10 + tmp11;
+ tmp23 = tmp12 - tmp10 + tmp11 + z2;
+
+ tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */
+
+ tmp25 = tmp13 - tmp10 - tmp11;
+ tmp26 = tmp12 + tmp10 - tmp11 - z2;
+
+ tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */
+
+ tmp21 = tmp12 + tmp10 + tmp11;
+ tmp24 = tmp13 - tmp10 + tmp11;
+ tmp11 += tmp11;
+ tmp22 = z1 + tmp11; /* c10 = c6-c12 */
+ tmp27 = z1 - tmp11 - tmp11; /* c0 = (c6-c12)*2 */
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z4 = (INT32) wsptr[5];
+ z3 = MULTIPLY(z4, FIX(1.224744871)); /* c5 */
+ z4 = (INT32) wsptr[7];
+
+ tmp13 = z2 - z4;
+ tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876)); /* c9 */
+ tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148)); /* c3-c9 */
+ tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899)); /* c3+c9 */
+
+ tmp13 = MULTIPLY(z2, - FIX(0.831253876)); /* -c9 */
+ tmp15 = MULTIPLY(z2, - FIX(1.344997024)); /* -c3 */
+ z2 = z1 - z4;
+ tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353)); /* c1 */
+
+ tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */
+ tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */
+ tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3; /* c5 */
+ z2 = MULTIPLY(z1 + z4, FIX(0.575212477)); /* c11 */
+ tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3; /* c7-c11 */
+ tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3; /* c11+c13 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 16x16 output block.
+ *
+ * Optimized algorithm with 28 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/32).
+ */
+
+GLOBAL(void)
+jpeg_idct_16x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*16]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += 1 << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */
+ tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+ z3 = z1 - z2;
+ z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */
+ z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */
+ tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */
+ tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+ tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+ tmp20 = tmp10 + tmp0;
+ tmp27 = tmp10 - tmp0;
+ tmp21 = tmp12 + tmp1;
+ tmp26 = tmp12 - tmp1;
+ tmp22 = tmp13 + tmp2;
+ tmp25 = tmp13 - tmp2;
+ tmp23 = tmp11 + tmp3;
+ tmp24 = tmp11 - tmp3;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = z1 + z3;
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */
+ tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */
+ tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */
+ tmp13 = tmp10 + tmp11 + tmp12 -
+ MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */
+ z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */
+ tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */
+ tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */
+ z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */
+ tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */
+ tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */
+ z2 += z4;
+ z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */
+ tmp1 += z1;
+ tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */
+ z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */
+ tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */
+ tmp12 += z2;
+ z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+ tmp2 += z2;
+ tmp3 += z2;
+ z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */
+ tmp10 += z2;
+ tmp11 += z2;
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 16 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 16; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[4];
+ tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */
+ tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[6];
+ z3 = z1 - z2;
+ z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */
+ z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */
+ tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */
+ tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+ tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+ tmp20 = tmp10 + tmp0;
+ tmp27 = tmp10 - tmp0;
+ tmp21 = tmp12 + tmp1;
+ tmp26 = tmp12 - tmp1;
+ tmp22 = tmp13 + tmp2;
+ tmp25 = tmp13 - tmp2;
+ tmp23 = tmp11 + tmp3;
+ tmp24 = tmp11 - tmp3;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = z1 + z3;
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */
+ tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */
+ tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */
+ tmp13 = tmp10 + tmp11 + tmp12 -
+ MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */
+ z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */
+ tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */
+ tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */
+ z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */
+ tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */
+ tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */
+ z2 += z4;
+ z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */
+ tmp1 += z1;
+ tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */
+ z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */
+ tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */
+ tmp12 += z2;
+ z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+ tmp2 += z2;
+ tmp3 += z2;
+ z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */
+ tmp10 += z2;
+ tmp11 += z2;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 16x8 output block.
+ *
+ * 8-point IDCT in pass 1 (columns), 16-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_16x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*8]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+ /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+ inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+ inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+ inptr[DCTSIZE*7] == 0) {
+ /* AC terms all zero */
+ int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z2 <<= CONST_BITS;
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z2 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ tmp0 = z2 + z3;
+ tmp1 = z2 - z3;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process 8 rows from work array, store into output array.
+ * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[4];
+ tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */
+ tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[6];
+ z3 = z1 - z2;
+ z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */
+ z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */
+ tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */
+ tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+ tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+ tmp20 = tmp10 + tmp0;
+ tmp27 = tmp10 - tmp0;
+ tmp21 = tmp12 + tmp1;
+ tmp26 = tmp12 - tmp1;
+ tmp22 = tmp13 + tmp2;
+ tmp25 = tmp13 - tmp2;
+ tmp23 = tmp11 + tmp3;
+ tmp24 = tmp11 - tmp3;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = z1 + z3;
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */
+ tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */
+ tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */
+ tmp13 = tmp10 + tmp11 + tmp12 -
+ MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */
+ z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */
+ tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */
+ tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */
+ z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */
+ tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */
+ tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */
+ z2 += z4;
+ z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */
+ tmp1 += z1;
+ tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */
+ z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */
+ tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */
+ tmp12 += z2;
+ z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+ tmp2 += z2;
+ tmp3 += z2;
+ z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */
+ tmp10 += z2;
+ tmp11 += z2;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 14x7 output block.
+ *
+ * 7-point IDCT in pass 1 (columns), 14-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_14x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*7]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp23 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp23 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp23 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */
+ tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */
+ tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+ tmp10 = z1 + z3;
+ z2 -= tmp10;
+ tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */
+ tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */
+ tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */
+ tmp23 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+
+ tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp10 = tmp11 - tmp12;
+ tmp11 += tmp12;
+ tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */
+ tmp11 += tmp12;
+ z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */
+ tmp10 += z2;
+ tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 7 rows from work array, store into output array.
+ * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 7; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z1 <<= CONST_BITS;
+ z4 = (INT32) wsptr[4];
+ z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */
+ z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */
+ z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */
+
+ tmp10 = z1 + z2;
+ tmp11 = z1 + z3;
+ tmp12 = z1 - z4;
+
+ tmp23 = z1 - ((z2 + z3 - z4) << 1); /* c0 = (c4+c12-c8)*2 */
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[6];
+
+ z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */
+
+ tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+ tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+ tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */
+ MULTIPLY(z2, FIX(1.378756276)); /* c2 */
+
+ tmp20 = tmp10 + tmp13;
+ tmp26 = tmp10 - tmp13;
+ tmp21 = tmp11 + tmp14;
+ tmp25 = tmp11 - tmp14;
+ tmp22 = tmp12 + tmp15;
+ tmp24 = tmp12 - tmp15;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+ z4 <<= CONST_BITS;
+
+ tmp14 = z1 + z3;
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */
+ tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */
+ tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+ tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */
+ tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */
+ z1 -= z2;
+ tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4; /* c11 */
+ tmp16 += tmp15;
+ tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4; /* -c13 */
+ tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */
+ tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */
+ tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */
+ tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+ tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */
+
+ tmp13 = ((z1 - z3) << CONST_BITS) + z4;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 12x6 output block.
+ *
+ * 6-point IDCT in pass 1 (columns), 12-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_12x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*6]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp10 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp10 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp12 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp20 = MULTIPLY(tmp12, FIX(0.707106781)); /* c4 */
+ tmp11 = tmp10 + tmp20;
+ tmp21 = RIGHT_SHIFT(tmp10 - tmp20 - tmp20, CONST_BITS-PASS1_BITS);
+ tmp20 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp10 = MULTIPLY(tmp20, FIX(1.224744871)); /* c2 */
+ tmp20 = tmp11 + tmp10;
+ tmp22 = tmp11 - tmp10;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp10 = tmp11 + ((z1 + z2) << CONST_BITS);
+ tmp12 = tmp11 + ((z3 - z2) << CONST_BITS);
+ tmp11 = (z1 - z2 - z3) << PASS1_BITS;
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) (tmp21 + tmp11);
+ wsptr[8*4] = (int) (tmp21 - tmp11);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 6 rows from work array, store into output array.
+ * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 <<= CONST_BITS;
+
+ z4 = (INT32) wsptr[4];
+ z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ z1 = (INT32) wsptr[2];
+ z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+ z1 <<= CONST_BITS;
+ z2 = (INT32) wsptr[6];
+ z2 <<= CONST_BITS;
+
+ tmp12 = z1 - z2;
+
+ tmp21 = z3 + tmp12;
+ tmp24 = z3 - tmp12;
+
+ tmp12 = z4 + z2;
+
+ tmp20 = tmp10 + tmp12;
+ tmp25 = tmp10 - tmp12;
+
+ tmp12 = z4 - z1 - z2;
+
+ tmp22 = tmp11 + tmp12;
+ tmp23 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */
+ tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */
+
+ tmp10 = z1 + z3;
+ tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */
+ tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */
+ tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */
+ tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */
+ tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+ tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+ tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */
+ MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */
+
+ z1 -= z4;
+ z2 -= z3;
+ z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */
+ tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */
+ tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 10x5 output block.
+ *
+ * 5-point IDCT in pass 1 (columns), 10-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_10x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*5]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp12 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp12 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp13 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp14 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */
+ z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */
+ z3 = tmp12 + z2;
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z1;
+ tmp12 -= z2 << 2;
+
+ /* Odd part */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */
+ tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */
+ tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp10 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp11 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 5 rows from work array, store into output array.
+ * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 5; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 <<= CONST_BITS;
+ z4 = (INT32) wsptr[4];
+ z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */
+ z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z2;
+
+ tmp22 = z3 - ((z1 - z2) << 1); /* c0 = (c4-c8)*2 */
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[6];
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */
+ tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+ tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+ tmp20 = tmp10 + tmp12;
+ tmp24 = tmp10 - tmp12;
+ tmp21 = tmp11 + tmp13;
+ tmp23 = tmp11 - tmp13;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z3 <<= CONST_BITS;
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = z2 + z4;
+ tmp13 = z2 - z4;
+
+ tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */
+ z4 = z3 + tmp12;
+
+ tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+ tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */
+ z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+ tmp12 = ((z1 - tmp13) << CONST_BITS) - z3;
+
+ tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+ tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 8x4 output block.
+ *
+ * 4-point IDCT in pass 1 (columns), 8-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_8x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*4]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 4-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+
+ tmp10 = (tmp0 + tmp2) << PASS1_BITS;
+ tmp12 = (tmp0 - tmp2) << PASS1_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS-PASS1_BITS);
+ tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) (tmp10 + tmp0);
+ wsptr[8*3] = (int) (tmp10 - tmp0);
+ wsptr[8*1] = (int) (tmp12 + tmp2);
+ wsptr[8*2] = (int) (tmp12 - tmp2);
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 4; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[6];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ /* Add fudge factor here for final descale. */
+ z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 = (INT32) wsptr[4];
+
+ tmp0 = (z2 + z3) << CONST_BITS;
+ tmp1 = (z2 - z3) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = (INT32) wsptr[7];
+ tmp1 = (INT32) wsptr[5];
+ tmp2 = (INT32) wsptr[3];
+ tmp3 = (INT32) wsptr[1];
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 6x3 output block.
+ *
+ * 3-point IDCT in pass 1 (columns), 6-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_6x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[6*3]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+ tmp10 = tmp0 + tmp12;
+ tmp2 = tmp0 - tmp12 - tmp12;
+
+ /* Odd part */
+
+ tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+ /* Final output stage */
+
+ wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[6*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[6*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 3 rows from work array, store into output array.
+ * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 3; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+ tmp2 = (INT32) wsptr[4];
+ tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */
+ tmp1 = tmp0 + tmp10;
+ tmp11 = tmp0 - tmp10 - tmp10;
+ tmp10 = (INT32) wsptr[2];
+ tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */
+ tmp10 = tmp1 + tmp0;
+ tmp12 = tmp1 - tmp0;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+ tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+ tmp1 = (z1 - z2 - z3) << CONST_BITS;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 6; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 4x2 output block.
+ *
+ * 2-point IDCT in pass 1 (columns), 4-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_4x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp2, tmp10, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ INT32 * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ INT32 workspace[4*2]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+ /* Odd part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ /* Final output stage */
+
+ wsptr[4*0] = tmp10 + tmp0;
+ wsptr[4*1] = tmp10 - tmp0;
+ }
+
+ /* Pass 2: process 2 rows from work array, store into output array.
+ * 4-point IDCT kernel,
+ * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 2; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = wsptr[0] + (ONE << 2);
+ tmp2 = wsptr[2];
+
+ tmp10 = (tmp0 + tmp2) << CONST_BITS;
+ tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = wsptr[1];
+ z3 = wsptr[3];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+ tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 4; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 2x1 output block.
+ *
+ * 1-point IDCT in pass 1 (columns), 2-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_2x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp10;
+ ISLOW_MULT_TYPE * quantptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ SHIFT_TEMPS
+
+ /* Pass 1: empty. */
+
+ /* Pass 2: process 1 row from input, store into output array. */
+
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ outptr = output_buf[0] + output_col;
+
+ /* Even part */
+
+ tmp10 = DEQUANTIZE(coef_block[0], quantptr[0]);
+ /* Add fudge factor here for final descale. */
+ tmp10 += ONE << 2;
+
+ /* Odd part */
+
+ tmp0 = DEQUANTIZE(coef_block[1], quantptr[1]);
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, 3) & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, 3) & RANGE_MASK];
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 8x16 output block.
+ *
+ * 16-point IDCT in pass 1 (columns), 8-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_8x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*16]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */
+ tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+ z3 = z1 - z2;
+ z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */
+ z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */
+ tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */
+ tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+ tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+ tmp20 = tmp10 + tmp0;
+ tmp27 = tmp10 - tmp0;
+ tmp21 = tmp12 + tmp1;
+ tmp26 = tmp12 - tmp1;
+ tmp22 = tmp13 + tmp2;
+ tmp25 = tmp13 - tmp2;
+ tmp23 = tmp11 + tmp3;
+ tmp24 = tmp11 - tmp3;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = z1 + z3;
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */
+ tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */
+ tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */
+ tmp13 = tmp10 + tmp11 + tmp12 -
+ MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */
+ z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */
+ tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */
+ tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */
+ z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */
+ tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */
+ tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */
+ z2 += z4;
+ z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */
+ tmp1 += z1;
+ tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */
+ z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */
+ tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */
+ tmp12 += z2;
+ z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+ tmp2 += z2;
+ tmp3 += z2;
+ z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */
+ tmp10 += z2;
+ tmp11 += z2;
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 16; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[6];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ /* Add fudge factor here for final descale. */
+ z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 = (INT32) wsptr[4];
+
+ tmp0 = (z2 + z3) << CONST_BITS;
+ tmp1 = (z2 - z3) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = (INT32) wsptr[7];
+ tmp1 = (INT32) wsptr[5];
+ tmp2 = (INT32) wsptr[3];
+ tmp3 = (INT32) wsptr[1];
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 7x14 output block.
+ *
+ * 14-point IDCT in pass 1 (columns), 7-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_7x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[7*14]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z1 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */
+ z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */
+ z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */
+
+ tmp10 = z1 + z2;
+ tmp11 = z1 + z3;
+ tmp12 = z1 - z4;
+
+ tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */
+ CONST_BITS-PASS1_BITS);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */
+
+ tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+ tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+ tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */
+ MULTIPLY(z2, FIX(1.378756276)); /* c2 */
+
+ tmp20 = tmp10 + tmp13;
+ tmp26 = tmp10 - tmp13;
+ tmp21 = tmp11 + tmp14;
+ tmp25 = tmp11 - tmp14;
+ tmp22 = tmp12 + tmp15;
+ tmp24 = tmp12 - tmp15;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp13 = z4 << CONST_BITS;
+
+ tmp14 = z1 + z3;
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */
+ tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */
+ tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+ tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */
+ tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */
+ z1 -= z2;
+ tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13; /* c11 */
+ tmp16 += tmp15;
+ z1 += z4;
+ z4 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */
+ tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */
+ tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */
+ z4 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */
+ tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+ tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */
+
+ tmp13 = (z1 - z3) << PASS1_BITS;
+
+ /* Final output stage */
+
+ wsptr[7*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[7*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[7*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[7*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[7*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[7*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[7*3] = (int) (tmp23 + tmp13);
+ wsptr[7*10] = (int) (tmp23 - tmp13);
+ wsptr[7*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[7*9] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[7*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[7*8] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[7*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);
+ wsptr[7*7] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 14 rows from work array, store into output array.
+ * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 14; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp23 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp23 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[4];
+ z3 = (INT32) wsptr[6];
+
+ tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */
+ tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */
+ tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+ tmp10 = z1 + z3;
+ z2 -= tmp10;
+ tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */
+ tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */
+ tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */
+ tmp23 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+
+ tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp10 = tmp11 - tmp12;
+ tmp11 += tmp12;
+ tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */
+ tmp11 += tmp12;
+ z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */
+ tmp10 += z2;
+ tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 7; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 6x12 output block.
+ *
+ * 12-point IDCT in pass 1 (columns), 6-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_6x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[6*12]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+ z1 <<= CONST_BITS;
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+ z2 <<= CONST_BITS;
+
+ tmp12 = z1 - z2;
+
+ tmp21 = z3 + tmp12;
+ tmp24 = z3 - tmp12;
+
+ tmp12 = z4 + z2;
+
+ tmp20 = tmp10 + tmp12;
+ tmp25 = tmp10 - tmp12;
+
+ tmp12 = z4 - z1 - z2;
+
+ tmp22 = tmp11 + tmp12;
+ tmp23 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */
+ tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */
+
+ tmp10 = z1 + z3;
+ tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */
+ tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */
+ tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */
+ tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */
+ tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+ tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+ tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */
+ MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */
+
+ z1 -= z4;
+ z2 -= z3;
+ z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */
+ tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */
+ tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */
+
+ /* Final output stage */
+
+ wsptr[6*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[6*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[6*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[6*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[6*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[6*9] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[6*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[6*8] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[6*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[6*7] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[6*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[6*6] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 12 rows from work array, store into output array.
+ * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 12; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp10 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp10 <<= CONST_BITS;
+ tmp12 = (INT32) wsptr[4];
+ tmp20 = MULTIPLY(tmp12, FIX(0.707106781)); /* c4 */
+ tmp11 = tmp10 + tmp20;
+ tmp21 = tmp10 - tmp20 - tmp20;
+ tmp20 = (INT32) wsptr[2];
+ tmp10 = MULTIPLY(tmp20, FIX(1.224744871)); /* c2 */
+ tmp20 = tmp11 + tmp10;
+ tmp22 = tmp11 - tmp10;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp10 = tmp11 + ((z1 + z2) << CONST_BITS);
+ tmp12 = tmp11 + ((z3 - z2) << CONST_BITS);
+ tmp11 = (z1 - z2 - z3) << CONST_BITS;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 6; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 5x10 output block.
+ *
+ * 10-point IDCT in pass 1 (columns), 5-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_5x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24;
+ INT32 z1, z2, z3, z4, z5;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[5*10]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */
+ z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z2;
+
+ tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1), /* c0 = (c4-c8)*2 */
+ CONST_BITS-PASS1_BITS);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */
+ tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+ tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+ tmp20 = tmp10 + tmp12;
+ tmp24 = tmp10 - tmp12;
+ tmp21 = tmp11 + tmp13;
+ tmp23 = tmp11 - tmp13;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = z2 + z4;
+ tmp13 = z2 - z4;
+
+ tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */
+ z5 = z3 << CONST_BITS;
+
+ z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */
+ z4 = z5 + tmp12;
+
+ tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+ tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */
+ z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+ tmp12 = (z1 - tmp13 - z3) << PASS1_BITS;
+
+ tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+ tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+ /* Final output stage */
+
+ wsptr[5*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[5*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[5*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[5*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[5*2] = (int) (tmp22 + tmp12);
+ wsptr[5*7] = (int) (tmp22 - tmp12);
+ wsptr[5*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[5*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[5*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[5*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 10 rows from work array, store into output array.
+ * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 10; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp12 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp12 <<= CONST_BITS;
+ tmp13 = (INT32) wsptr[2];
+ tmp14 = (INT32) wsptr[4];
+ z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */
+ z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */
+ z3 = tmp12 + z2;
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z1;
+ tmp12 -= z2 << 2;
+
+ /* Odd part */
+
+ z2 = (INT32) wsptr[1];
+ z3 = (INT32) wsptr[3];
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */
+ tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */
+ tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 5; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 4x8 output block.
+ *
+ * 8-point IDCT in pass 1 (columns), 4-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_4x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[4*8]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+ /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 4; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+ inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+ inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+ inptr[DCTSIZE*7] == 0) {
+ /* AC terms all zero */
+ int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+ wsptr[4*0] = dcval;
+ wsptr[4*1] = dcval;
+ wsptr[4*2] = dcval;
+ wsptr[4*3] = dcval;
+ wsptr[4*4] = dcval;
+ wsptr[4*5] = dcval;
+ wsptr[4*6] = dcval;
+ wsptr[4*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z2 <<= CONST_BITS;
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z2 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ tmp0 = z2 + z3;
+ tmp1 = z2 - z3;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ wsptr[4*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[4*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[4*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[4*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[4*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[4*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[4*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[4*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process 8 rows from work array, store into output array.
+ * 4-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp2 = (INT32) wsptr[2];
+
+ tmp10 = (tmp0 + tmp2) << CONST_BITS;
+ tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = (INT32) wsptr[1];
+ z3 = (INT32) wsptr[3];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+ tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 4; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 3x6 output block.
+ *
+ * 6-point IDCT in pass 1 (columns), 3-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_3x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[3*6]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */
+ tmp1 = tmp0 + tmp10;
+ tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS);
+ tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */
+ tmp10 = tmp1 + tmp0;
+ tmp12 = tmp1 - tmp0;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+ tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+ tmp1 = (z1 - z2 - z3) << PASS1_BITS;
+
+ /* Final output stage */
+
+ wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[3*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[3*1] = (int) (tmp11 + tmp1);
+ wsptr[3*4] = (int) (tmp11 - tmp1);
+ wsptr[3*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[3*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 6 rows from work array, store into output array.
+ * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+ tmp2 = (INT32) wsptr[2];
+ tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+ tmp10 = tmp0 + tmp12;
+ tmp2 = tmp0 - tmp12 - tmp12;
+
+ /* Odd part */
+
+ tmp12 = (INT32) wsptr[1];
+ tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 3; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 2x4 output block.
+ *
+ * 4-point IDCT in pass 1 (columns), 2-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_2x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp2, tmp10, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ INT32 * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ INT32 workspace[2*4]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 4-point IDCT kernel,
+ * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 2; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+
+ tmp10 = (tmp0 + tmp2) << CONST_BITS;
+ tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+ tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+ /* Final output stage */
+
+ wsptr[2*0] = tmp10 + tmp0;
+ wsptr[2*3] = tmp10 - tmp0;
+ wsptr[2*1] = tmp12 + tmp2;
+ wsptr[2*2] = tmp12 - tmp2;
+ }
+
+ /* Pass 2: process 4 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 4; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp10 = wsptr[0] + (ONE << (CONST_BITS+2));
+
+ /* Odd part */
+
+ tmp0 = wsptr[1];
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 2; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 1x2 output block.
+ *
+ * 2-point IDCT in pass 1 (columns), 1-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_1x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp10;
+ ISLOW_MULT_TYPE * quantptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ SHIFT_TEMPS
+
+ /* Process 1 column from input, store into output array. */
+
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+
+ /* Even part */
+
+ tmp10 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ /* Add fudge factor here for final descale. */
+ tmp10 += ONE << 2;
+
+ /* Odd part */
+
+ tmp0 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ /* Final output stage */
+
+ output_buf[0][output_col] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, 3)
+ & RANGE_MASK];
+ output_buf[1][output_col] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, 3)
+ & RANGE_MASK];
+}
+
+#endif /* IDCT_SCALING_SUPPORTED */
+#endif /* DCT_ISLOW_SUPPORTED */
diff --git a/external/jpeg-8c/jinclude.h b/external/jpeg-8c/jinclude.h
new file mode 100644
index 0000000..0a4f151
--- /dev/null
+++ b/external/jpeg-8c/jinclude.h
@@ -0,0 +1,91 @@
+/*
+ * jinclude.h
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file exists to provide a single place to fix any problems with
+ * including the wrong system include files. (Common problems are taken
+ * care of by the standard jconfig symbols, but on really weird systems
+ * you may have to edit this file.)
+ *
+ * NOTE: this file is NOT intended to be included by applications using the
+ * JPEG library. Most applications need only include jpeglib.h.
+ */
+
+
+/* Include auto-config file to find out which system include files we need. */
+
+#include "jconfig.h" /* auto configuration options */
+#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */
+
+/*
+ * We need the NULL macro and size_t typedef.
+ * On an ANSI-conforming system it is sufficient to include <stddef.h>.
+ * Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to
+ * pull in <sys/types.h> as well.
+ * Note that the core JPEG library does not require <stdio.h>;
+ * only the default error handler and data source/destination modules do.
+ * But we must pull it in because of the references to FILE in jpeglib.h.
+ * You can remove those references if you want to compile without <stdio.h>.
+ */
+
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef NEED_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <stdio.h>
+
+/*
+ * We need memory copying and zeroing functions, plus strncpy().
+ * ANSI and System V implementations declare these in <string.h>.
+ * BSD doesn't have the mem() functions, but it does have bcopy()/bzero().
+ * Some systems may declare memset and memcpy in <memory.h>.
+ *
+ * NOTE: we assume the size parameters to these functions are of type size_t.
+ * Change the casts in these macros if not!
+ */
+
+#ifdef NEED_BSD_STRINGS
+
+#include <strings.h>
+#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size))
+#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size))
+
+#else /* not BSD, assume ANSI/SysV string lib */
+
+#include <string.h>
+#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size))
+#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size))
+
+#endif
+
+/*
+ * In ANSI C, and indeed any rational implementation, size_t is also the
+ * type returned by sizeof(). However, it seems there are some irrational
+ * implementations out there, in which sizeof() returns an int even though
+ * size_t is defined as long or unsigned long. To ensure consistent results
+ * we always use this SIZEOF() macro in place of using sizeof() directly.
+ */
+
+#define SIZEOF(object) ((size_t) sizeof(object))
+
+/*
+ * The modules that use fread() and fwrite() always invoke them through
+ * these macros. On some systems you may need to twiddle the argument casts.
+ * CAUTION: argument order is different from underlying functions!
+ */
+
+#define JFREAD(file,buf,sizeofbuf) \
+ ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
+#define JFWRITE(file,buf,sizeofbuf) \
+ ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
diff --git a/external/jpeg-8c/jmemmgr.c b/external/jpeg-8c/jmemmgr.c
new file mode 100644
index 0000000..d801b32
--- /dev/null
+++ b/external/jpeg-8c/jmemmgr.c
@@ -0,0 +1,1118 @@
+/*
+ * jmemmgr.c
+ *
+ * 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 the JPEG system-independent memory management
+ * routines. This code is usable across a wide variety of machines; most
+ * of the system dependencies have been isolated in a separate file.
+ * The major functions provided here are:
+ * * pool-based allocation and freeing of memory;
+ * * policy decisions about how to divide available memory among the
+ * virtual arrays;
+ * * control logic for swapping virtual arrays between main memory and
+ * backing storage.
+ * The separate system-dependent file provides the actual backing-storage
+ * access code, and it contains the policy decision about how much total
+ * main memory to use.
+ * This file is system-dependent in the sense that some of its functions
+ * are unnecessary in some systems. For example, if there is enough virtual
+ * memory so that backing storage will never be used, much of the virtual
+ * array control logic could be removed. (Of course, if you have that much
+ * memory then you shouldn't care about a little bit of unused code...)
+ */
+
+#define JPEG_INTERNALS
+#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef NO_GETENV
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare getenv() */
+extern char * getenv JPP((const char * name));
+#endif
+#endif
+
+
+/*
+ * Some important notes:
+ * The allocation routines provided here must never return NULL.
+ * They should exit to error_exit if unsuccessful.
+ *
+ * It's not a good idea to try to merge the sarray and barray routines,
+ * even though they are textually almost the same, because samples are
+ * usually stored as bytes while coefficients are shorts or ints. Thus,
+ * in machines where byte pointers have a different representation from
+ * word pointers, the resulting machine code could not be the same.
+ */
+
+
+/*
+ * Many machines require storage alignment: longs must start on 4-byte
+ * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc()
+ * always returns pointers that are multiples of the worst-case alignment
+ * requirement, and we had better do so too.
+ * There isn't any really portable way to determine the worst-case alignment
+ * requirement. This module assumes that the alignment requirement is
+ * multiples of sizeof(ALIGN_TYPE).
+ * By default, we define ALIGN_TYPE as double. This is necessary on some
+ * workstations (where doubles really do need 8-byte alignment) and will work
+ * fine on nearly everything. If your machine has lesser alignment needs,
+ * you can save a few bytes by making ALIGN_TYPE smaller.
+ * The only place I know of where this will NOT work is certain Macintosh
+ * 680x0 compilers that define double as a 10-byte IEEE extended float.
+ * Doing 10-byte alignment is counterproductive because longwords won't be
+ * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have
+ * such a compiler.
+ */
+
+#ifndef ALIGN_TYPE /* so can override from jconfig.h */
+#define ALIGN_TYPE double
+#endif
+
+
+/*
+ * We allocate objects from "pools", where each pool is gotten with a single
+ * request to jpeg_get_small() or jpeg_get_large(). There is no per-object
+ * overhead within a pool, except for alignment padding. Each pool has a
+ * header with a link to the next pool of the same class.
+ * Small and large pool headers are identical except that the latter's
+ * link pointer must be FAR on 80x86 machines.
+ * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE
+ * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple
+ * of the alignment requirement of ALIGN_TYPE.
+ */
+
+typedef union small_pool_struct * small_pool_ptr;
+
+typedef union small_pool_struct {
+ struct {
+ small_pool_ptr next; /* next in list of pools */
+ size_t bytes_used; /* how many bytes already used within pool */
+ size_t bytes_left; /* bytes still available in this pool */
+ } hdr;
+ ALIGN_TYPE dummy; /* included in union to ensure alignment */
+} small_pool_hdr;
+
+typedef union large_pool_struct FAR * large_pool_ptr;
+
+typedef union large_pool_struct {
+ struct {
+ large_pool_ptr next; /* next in list of pools */
+ size_t bytes_used; /* how many bytes already used within pool */
+ size_t bytes_left; /* bytes still available in this pool */
+ } hdr;
+ ALIGN_TYPE dummy; /* included in union to ensure alignment */
+} large_pool_hdr;
+
+
+/*
+ * Here is the full definition of a memory manager object.
+ */
+
+typedef struct {
+ struct jpeg_memory_mgr pub; /* public fields */
+
+ /* Each pool identifier (lifetime class) names a linked list of pools. */
+ small_pool_ptr small_list[JPOOL_NUMPOOLS];
+ large_pool_ptr large_list[JPOOL_NUMPOOLS];
+
+ /* Since we only have one lifetime class of virtual arrays, only one
+ * linked list is necessary (for each datatype). Note that the virtual
+ * array control blocks being linked together are actually stored somewhere
+ * in the small-pool list.
+ */
+ jvirt_sarray_ptr virt_sarray_list;
+ jvirt_barray_ptr virt_barray_list;
+
+ /* This counts total space obtained from jpeg_get_small/large */
+ long total_space_allocated;
+
+ /* alloc_sarray and alloc_barray set this value for use by virtual
+ * array routines.
+ */
+ JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */
+} my_memory_mgr;
+
+typedef my_memory_mgr * my_mem_ptr;
+
+
+/*
+ * The control blocks for virtual arrays.
+ * Note that these blocks are allocated in the "small" pool area.
+ * System-dependent info for the associated backing store (if any) is hidden
+ * inside the backing_store_info struct.
+ */
+
+struct jvirt_sarray_control {
+ JSAMPARRAY mem_buffer; /* => the in-memory buffer */
+ JDIMENSION rows_in_array; /* total virtual array height */
+ JDIMENSION samplesperrow; /* width of array (and of memory buffer) */
+ JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */
+ JDIMENSION rows_in_mem; /* height of memory buffer */
+ JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */
+ JDIMENSION cur_start_row; /* first logical row # in the buffer */
+ JDIMENSION first_undef_row; /* row # of first uninitialized row */
+ boolean pre_zero; /* pre-zero mode requested? */
+ boolean dirty; /* do current buffer contents need written? */
+ boolean b_s_open; /* is backing-store data valid? */
+ jvirt_sarray_ptr next; /* link to next virtual sarray control block */
+ backing_store_info b_s_info; /* System-dependent control info */
+};
+
+struct jvirt_barray_control {
+ JBLOCKARRAY mem_buffer; /* => the in-memory buffer */
+ JDIMENSION rows_in_array; /* total virtual array height */
+ JDIMENSION blocksperrow; /* width of array (and of memory buffer) */
+ JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */
+ JDIMENSION rows_in_mem; /* height of memory buffer */
+ JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */
+ JDIMENSION cur_start_row; /* first logical row # in the buffer */
+ JDIMENSION first_undef_row; /* row # of first uninitialized row */
+ boolean pre_zero; /* pre-zero mode requested? */
+ boolean dirty; /* do current buffer contents need written? */
+ boolean b_s_open; /* is backing-store data valid? */
+ jvirt_barray_ptr next; /* link to next virtual barray control block */
+ backing_store_info b_s_info; /* System-dependent control info */
+};
+
+
+#ifdef MEM_STATS /* optional extra stuff for statistics */
+
+LOCAL(void)
+print_mem_stats (j_common_ptr cinfo, int pool_id)
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ small_pool_ptr shdr_ptr;
+ large_pool_ptr lhdr_ptr;
+
+ /* Since this is only a debugging stub, we can cheat a little by using
+ * fprintf directly rather than going through the trace message code.
+ * This is helpful because message parm array can't handle longs.
+ */
+ fprintf(stderr, "Freeing pool %d, total space = %ld\n",
+ pool_id, mem->total_space_allocated);
+
+ for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL;
+ lhdr_ptr = lhdr_ptr->hdr.next) {
+ fprintf(stderr, " Large chunk used %ld\n",
+ (long) lhdr_ptr->hdr.bytes_used);
+ }
+
+ for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL;
+ shdr_ptr = shdr_ptr->hdr.next) {
+ fprintf(stderr, " Small chunk used %ld free %ld\n",
+ (long) shdr_ptr->hdr.bytes_used,
+ (long) shdr_ptr->hdr.bytes_left);
+ }
+}
+
+#endif /* MEM_STATS */
+
+
+LOCAL(void)
+out_of_memory (j_common_ptr cinfo, int which)
+/* Report an out-of-memory error and stop execution */
+/* If we compiled MEM_STATS support, report alloc requests before dying */
+{
+#ifdef MEM_STATS
+ cinfo->err->trace_level = 2; /* force self_destruct to report stats */
+#endif
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which);
+}
+
+
+/*
+ * Allocation of "small" objects.
+ *
+ * For these, we use pooled storage. When a new pool must be created,
+ * we try to get enough space for the current request plus a "slop" factor,
+ * where the slop will be the amount of leftover space in the new pool.
+ * The speed vs. space tradeoff is largely determined by the slop values.
+ * A different slop value is provided for each pool class (lifetime),
+ * and we also distinguish the first pool of a class from later ones.
+ * NOTE: the values given work fairly well on both 16- and 32-bit-int
+ * machines, but may be too small if longs are 64 bits or more.
+ */
+
+static const size_t first_pool_slop[JPOOL_NUMPOOLS] =
+{
+ 1600, /* first PERMANENT pool */
+ 16000 /* first IMAGE pool */
+};
+
+static const size_t extra_pool_slop[JPOOL_NUMPOOLS] =
+{
+ 0, /* additional PERMANENT pools */
+ 5000 /* additional IMAGE pools */
+};
+
+#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */
+
+
+METHODDEF(void *)
+alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
+/* Allocate a "small" object */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ small_pool_ptr hdr_ptr, prev_hdr_ptr;
+ char * data_ptr;
+ size_t odd_bytes, min_request, slop;
+
+ /* Check for unsatisfiable request (do now to ensure no overflow below) */
+ if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr)))
+ out_of_memory(cinfo, 1); /* request exceeds malloc's ability */
+
+ /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
+ odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
+ if (odd_bytes > 0)
+ sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
+
+ /* See if space is available in any existing pool */
+ if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+ prev_hdr_ptr = NULL;
+ hdr_ptr = mem->small_list[pool_id];
+ while (hdr_ptr != NULL) {
+ if (hdr_ptr->hdr.bytes_left >= sizeofobject)
+ break; /* found pool with enough space */
+ prev_hdr_ptr = hdr_ptr;
+ hdr_ptr = hdr_ptr->hdr.next;
+ }
+
+ /* Time to make a new pool? */
+ if (hdr_ptr == NULL) {
+ /* min_request is what we need now, slop is what will be leftover */
+ min_request = sizeofobject + SIZEOF(small_pool_hdr);
+ if (prev_hdr_ptr == NULL) /* first pool in class? */
+ slop = first_pool_slop[pool_id];
+ else
+ slop = extra_pool_slop[pool_id];
+ /* Don't ask for more than MAX_ALLOC_CHUNK */
+ if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request))
+ slop = (size_t) (MAX_ALLOC_CHUNK-min_request);
+ /* Try to get space, if fail reduce slop and try again */
+ for (;;) {
+ hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop);
+ if (hdr_ptr != NULL)
+ break;
+ slop /= 2;
+ if (slop < MIN_SLOP) /* give up when it gets real small */
+ out_of_memory(cinfo, 2); /* jpeg_get_small failed */
+ }
+ mem->total_space_allocated += min_request + slop;
+ /* Success, initialize the new pool header and add to end of list */
+ hdr_ptr->hdr.next = NULL;
+ hdr_ptr->hdr.bytes_used = 0;
+ hdr_ptr->hdr.bytes_left = sizeofobject + slop;
+ if (prev_hdr_ptr == NULL) /* first pool in class? */
+ mem->small_list[pool_id] = hdr_ptr;
+ else
+ prev_hdr_ptr->hdr.next = hdr_ptr;
+ }
+
+ /* OK, allocate the object from the current pool */
+ data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */
+ data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */
+ hdr_ptr->hdr.bytes_used += sizeofobject;
+ hdr_ptr->hdr.bytes_left -= sizeofobject;
+
+ return (void *) data_ptr;
+}
+
+
+/*
+ * Allocation of "large" objects.
+ *
+ * The external semantics of these are the same as "small" objects,
+ * except that FAR pointers are used on 80x86. However the pool
+ * management heuristics are quite different. We assume that each
+ * request is large enough that it may as well be passed directly to
+ * jpeg_get_large; the pool management just links everything together
+ * so that we can free it all on demand.
+ * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY
+ * structures. The routines that create these structures (see below)
+ * deliberately bunch rows together to ensure a large request size.
+ */
+
+METHODDEF(void FAR *)
+alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
+/* Allocate a "large" object */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ large_pool_ptr hdr_ptr;
+ size_t odd_bytes;
+
+ /* Check for unsatisfiable request (do now to ensure no overflow below) */
+ if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)))
+ out_of_memory(cinfo, 3); /* request exceeds malloc's ability */
+
+ /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
+ odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
+ if (odd_bytes > 0)
+ sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
+
+ /* Always make a new pool */
+ if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+ hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject +
+ SIZEOF(large_pool_hdr));
+ if (hdr_ptr == NULL)
+ out_of_memory(cinfo, 4); /* jpeg_get_large failed */
+ mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr);
+
+ /* Success, initialize the new pool header and add to list */
+ hdr_ptr->hdr.next = mem->large_list[pool_id];
+ /* We maintain space counts in each pool header for statistical purposes,
+ * even though they are not needed for allocation.
+ */
+ hdr_ptr->hdr.bytes_used = sizeofobject;
+ hdr_ptr->hdr.bytes_left = 0;
+ mem->large_list[pool_id] = hdr_ptr;
+
+ return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */
+}
+
+
+/*
+ * Creation of 2-D sample arrays.
+ * The pointers are in near heap, the samples themselves in FAR heap.
+ *
+ * To minimize allocation overhead and to allow I/O of large contiguous
+ * blocks, we allocate the sample rows in groups of as many rows as possible
+ * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
+ * NB: the virtual array control routines, later in this file, know about
+ * this chunking of rows. The rowsperchunk value is left in the mem manager
+ * object so that it can be saved away if this sarray is the workspace for
+ * a virtual array.
+ */
+
+METHODDEF(JSAMPARRAY)
+alloc_sarray (j_common_ptr cinfo, int pool_id,
+ JDIMENSION samplesperrow, JDIMENSION numrows)
+/* Allocate a 2-D sample array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ JSAMPARRAY result;
+ JSAMPROW workspace;
+ JDIMENSION rowsperchunk, currow, i;
+ long ltemp;
+
+ /* Calculate max # of rows allowed in one allocation chunk */
+ ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
+ ((long) samplesperrow * SIZEOF(JSAMPLE));
+ if (ltemp <= 0)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+ if (ltemp < (long) numrows)
+ rowsperchunk = (JDIMENSION) ltemp;
+ else
+ rowsperchunk = numrows;
+ mem->last_rowsperchunk = rowsperchunk;
+
+ /* Get space for row pointers (small object) */
+ result = (JSAMPARRAY) alloc_small(cinfo, pool_id,
+ (size_t) (numrows * SIZEOF(JSAMPROW)));
+
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace = (JSAMPROW) alloc_large(cinfo, pool_id,
+ (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow
+ * SIZEOF(JSAMPLE)));
+ for (i = rowsperchunk; i > 0; i--) {
+ result[currow++] = workspace;
+ workspace += samplesperrow;
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * Creation of 2-D coefficient-block arrays.
+ * This is essentially the same as the code for sample arrays, above.
+ */
+
+METHODDEF(JBLOCKARRAY)
+alloc_barray (j_common_ptr cinfo, int pool_id,
+ JDIMENSION blocksperrow, JDIMENSION numrows)
+/* Allocate a 2-D coefficient-block array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ JBLOCKARRAY result;
+ JBLOCKROW workspace;
+ JDIMENSION rowsperchunk, currow, i;
+ long ltemp;
+
+ /* Calculate max # of rows allowed in one allocation chunk */
+ ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
+ ((long) blocksperrow * SIZEOF(JBLOCK));
+ if (ltemp <= 0)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+ if (ltemp < (long) numrows)
+ rowsperchunk = (JDIMENSION) ltemp;
+ else
+ rowsperchunk = numrows;
+ mem->last_rowsperchunk = rowsperchunk;
+
+ /* Get space for row pointers (small object) */
+ result = (JBLOCKARRAY) alloc_small(cinfo, pool_id,
+ (size_t) (numrows * SIZEOF(JBLOCKROW)));
+
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace = (JBLOCKROW) alloc_large(cinfo, pool_id,
+ (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow
+ * SIZEOF(JBLOCK)));
+ for (i = rowsperchunk; i > 0; i--) {
+ result[currow++] = workspace;
+ workspace += blocksperrow;
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * About virtual array management:
+ *
+ * The above "normal" array routines are only used to allocate strip buffers
+ * (as wide as the image, but just a few rows high). Full-image-sized buffers
+ * are handled as "virtual" arrays. The array is still accessed a strip at a
+ * time, but the memory manager must save the whole array for repeated
+ * accesses. The intended implementation is that there is a strip buffer in
+ * memory (as high as is possible given the desired memory limit), plus a
+ * backing file that holds the rest of the array.
+ *
+ * The request_virt_array routines are told the total size of the image and
+ * the maximum number of rows that will be accessed at once. The in-memory
+ * buffer must be at least as large as the maxaccess value.
+ *
+ * The request routines create control blocks but not the in-memory buffers.
+ * That is postponed until realize_virt_arrays is called. At that time the
+ * total amount of space needed is known (approximately, anyway), so free
+ * memory can be divided up fairly.
+ *
+ * The access_virt_array routines are responsible for making a specific strip
+ * area accessible (after reading or writing the backing file, if necessary).
+ * Note that the access routines are told whether the caller intends to modify
+ * the accessed strip; during a read-only pass this saves having to rewrite
+ * data to disk. The access routines are also responsible for pre-zeroing
+ * any newly accessed rows, if pre-zeroing was requested.
+ *
+ * In current usage, the access requests are usually for nonoverlapping
+ * strips; that is, successive access start_row numbers differ by exactly
+ * num_rows = maxaccess. This means we can get good performance with simple
+ * buffer dump/reload logic, by making the in-memory buffer be a multiple
+ * of the access height; then there will never be accesses across bufferload
+ * boundaries. The code will still work with overlapping access requests,
+ * but it doesn't handle bufferload overlaps very efficiently.
+ */
+
+
+METHODDEF(jvirt_sarray_ptr)
+request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
+ JDIMENSION samplesperrow, JDIMENSION numrows,
+ JDIMENSION maxaccess)
+/* Request a virtual 2-D sample array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ jvirt_sarray_ptr result;
+
+ /* Only IMAGE-lifetime virtual arrays are currently supported */
+ if (pool_id != JPOOL_IMAGE)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+ /* get control block */
+ result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id,
+ SIZEOF(struct jvirt_sarray_control));
+
+ result->mem_buffer = NULL; /* marks array not yet realized */
+ result->rows_in_array = numrows;
+ result->samplesperrow = samplesperrow;
+ result->maxaccess = maxaccess;
+ result->pre_zero = pre_zero;
+ result->b_s_open = FALSE; /* no associated backing-store object */
+ result->next = mem->virt_sarray_list; /* add to list of virtual arrays */
+ mem->virt_sarray_list = result;
+
+ return result;
+}
+
+
+METHODDEF(jvirt_barray_ptr)
+request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
+ JDIMENSION blocksperrow, JDIMENSION numrows,
+ JDIMENSION maxaccess)
+/* Request a virtual 2-D coefficient-block array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ jvirt_barray_ptr result;
+
+ /* Only IMAGE-lifetime virtual arrays are currently supported */
+ if (pool_id != JPOOL_IMAGE)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+ /* get control block */
+ result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id,
+ SIZEOF(struct jvirt_barray_control));
+
+ result->mem_buffer = NULL; /* marks array not yet realized */
+ result->rows_in_array = numrows;
+ result->blocksperrow = blocksperrow;
+ result->maxaccess = maxaccess;
+ result->pre_zero = pre_zero;
+ result->b_s_open = FALSE; /* no associated backing-store object */
+ result->next = mem->virt_barray_list; /* add to list of virtual arrays */
+ mem->virt_barray_list = result;
+
+ return result;
+}
+
+
+METHODDEF(void)
+realize_virt_arrays (j_common_ptr cinfo)
+/* Allocate the in-memory buffers for any unrealized virtual arrays */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ long space_per_minheight, maximum_space, avail_mem;
+ long minheights, max_minheights;
+ jvirt_sarray_ptr sptr;
+ jvirt_barray_ptr bptr;
+
+ /* Compute the minimum space needed (maxaccess rows in each buffer)
+ * and the maximum space needed (full image height in each buffer).
+ * These may be of use to the system-dependent jpeg_mem_available routine.
+ */
+ space_per_minheight = 0;
+ maximum_space = 0;
+ for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+ if (sptr->mem_buffer == NULL) { /* if not realized yet */
+ space_per_minheight += (long) sptr->maxaccess *
+ (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
+ maximum_space += (long) sptr->rows_in_array *
+ (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
+ }
+ }
+ for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+ if (bptr->mem_buffer == NULL) { /* if not realized yet */
+ space_per_minheight += (long) bptr->maxaccess *
+ (long) bptr->blocksperrow * SIZEOF(JBLOCK);
+ maximum_space += (long) bptr->rows_in_array *
+ (long) bptr->blocksperrow * SIZEOF(JBLOCK);
+ }
+ }
+
+ if (space_per_minheight <= 0)
+ return; /* no unrealized arrays, no work */
+
+ /* Determine amount of memory to actually use; this is system-dependent. */
+ avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space,
+ mem->total_space_allocated);
+
+ /* If the maximum space needed is available, make all the buffers full
+ * height; otherwise parcel it out with the same number of minheights
+ * in each buffer.
+ */
+ if (avail_mem >= maximum_space)
+ max_minheights = 1000000000L;
+ else {
+ max_minheights = avail_mem / space_per_minheight;
+ /* If there doesn't seem to be enough space, try to get the minimum
+ * anyway. This allows a "stub" implementation of jpeg_mem_available().
+ */
+ if (max_minheights <= 0)
+ max_minheights = 1;
+ }
+
+ /* Allocate the in-memory buffers and initialize backing store as needed. */
+
+ for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+ if (sptr->mem_buffer == NULL) { /* if not realized yet */
+ minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L;
+ if (minheights <= max_minheights) {
+ /* This buffer fits in memory */
+ sptr->rows_in_mem = sptr->rows_in_array;
+ } else {
+ /* It doesn't fit in memory, create backing store. */
+ sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess);
+ jpeg_open_backing_store(cinfo, & sptr->b_s_info,
+ (long) sptr->rows_in_array *
+ (long) sptr->samplesperrow *
+ (long) SIZEOF(JSAMPLE));
+ sptr->b_s_open = TRUE;
+ }
+ sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE,
+ sptr->samplesperrow, sptr->rows_in_mem);
+ sptr->rowsperchunk = mem->last_rowsperchunk;
+ sptr->cur_start_row = 0;
+ sptr->first_undef_row = 0;
+ sptr->dirty = FALSE;
+ }
+ }
+
+ for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+ if (bptr->mem_buffer == NULL) { /* if not realized yet */
+ minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L;
+ if (minheights <= max_minheights) {
+ /* This buffer fits in memory */
+ bptr->rows_in_mem = bptr->rows_in_array;
+ } else {
+ /* It doesn't fit in memory, create backing store. */
+ bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess);
+ jpeg_open_backing_store(cinfo, & bptr->b_s_info,
+ (long) bptr->rows_in_array *
+ (long) bptr->blocksperrow *
+ (long) SIZEOF(JBLOCK));
+ bptr->b_s_open = TRUE;
+ }
+ bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE,
+ bptr->blocksperrow, bptr->rows_in_mem);
+ bptr->rowsperchunk = mem->last_rowsperchunk;
+ bptr->cur_start_row = 0;
+ bptr->first_undef_row = 0;
+ bptr->dirty = FALSE;
+ }
+ }
+}
+
+
+LOCAL(void)
+do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)
+/* Do backing store read or write of a virtual sample array */
+{
+ long bytesperrow, file_offset, byte_count, rows, thisrow, i;
+
+ bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE);
+ file_offset = ptr->cur_start_row * bytesperrow;
+ /* Loop to read or write each allocation chunk in mem_buffer */
+ for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
+ /* One chunk, but check for short chunk at end of buffer */
+ rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
+ /* Transfer no more than is currently defined */
+ thisrow = (long) ptr->cur_start_row + i;
+ rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
+ /* Transfer no more than fits in file */
+ rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
+ if (rows <= 0) /* this chunk might be past end of file! */
+ break;
+ byte_count = rows * bytesperrow;
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ file_offset += byte_count;
+ }
+}
+
+
+LOCAL(void)
+do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing)
+/* Do backing store read or write of a virtual coefficient-block array */
+{
+ long bytesperrow, file_offset, byte_count, rows, thisrow, i;
+
+ bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK);
+ file_offset = ptr->cur_start_row * bytesperrow;
+ /* Loop to read or write each allocation chunk in mem_buffer */
+ for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
+ /* One chunk, but check for short chunk at end of buffer */
+ rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
+ /* Transfer no more than is currently defined */
+ thisrow = (long) ptr->cur_start_row + i;
+ rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
+ /* Transfer no more than fits in file */
+ rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
+ if (rows <= 0) /* this chunk might be past end of file! */
+ break;
+ byte_count = rows * bytesperrow;
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ file_offset += byte_count;
+ }
+}
+
+
+METHODDEF(JSAMPARRAY)
+access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr,
+ JDIMENSION start_row, JDIMENSION num_rows,
+ boolean writable)
+/* Access the part of a virtual sample array starting at start_row */
+/* and extending for num_rows rows. writable is true if */
+/* caller intends to modify the accessed area. */
+{
+ JDIMENSION end_row = start_row + num_rows;
+ JDIMENSION undef_row;
+
+ /* debugging check */
+ if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
+ ptr->mem_buffer == NULL)
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+
+ /* Make the desired part of the virtual array accessible */
+ if (start_row < ptr->cur_start_row ||
+ end_row > ptr->cur_start_row+ptr->rows_in_mem) {
+ if (! ptr->b_s_open)
+ ERREXIT(cinfo, JERR_VIRTUAL_BUG);
+ /* Flush old buffer contents if necessary */
+ if (ptr->dirty) {
+ do_sarray_io(cinfo, ptr, TRUE);
+ ptr->dirty = FALSE;
+ }
+ /* Decide what part of virtual array to access.
+ * Algorithm: if target address > current window, assume forward scan,
+ * load starting at target address. If target address < current window,
+ * assume backward scan, load so that target area is top of window.
+ * Note that when switching from forward write to forward read, will have
+ * start_row = 0, so the limiting case applies and we load from 0 anyway.
+ */
+ if (start_row > ptr->cur_start_row) {
+ ptr->cur_start_row = start_row;
+ } else {
+ /* use long arithmetic here to avoid overflow & unsigned problems */
+ long ltemp;
+
+ ltemp = (long) end_row - (long) ptr->rows_in_mem;
+ if (ltemp < 0)
+ ltemp = 0; /* don't fall off front end of file */
+ ptr->cur_start_row = (JDIMENSION) ltemp;
+ }
+ /* Read in the selected part of the array.
+ * During the initial write pass, we will do no actual read
+ * because the selected part is all undefined.
+ */
+ do_sarray_io(cinfo, ptr, FALSE);
+ }
+ /* Ensure the accessed part of the array is defined; prezero if needed.
+ * To improve locality of access, we only prezero the part of the array
+ * that the caller is about to access, not the entire in-memory array.
+ */
+ if (ptr->first_undef_row < end_row) {
+ if (ptr->first_undef_row < start_row) {
+ if (writable) /* writer skipped over a section of array */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ undef_row = start_row; /* but reader is allowed to read ahead */
+ } else {
+ undef_row = ptr->first_undef_row;
+ }
+ if (writable)
+ ptr->first_undef_row = end_row;
+ if (ptr->pre_zero) {
+ size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE);
+ undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
+ end_row -= ptr->cur_start_row;
+ while (undef_row < end_row) {
+ jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
+ undef_row++;
+ }
+ } else {
+ if (! writable) /* reader looking at undefined data */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ }
+ }
+ /* Flag the buffer dirty if caller will write in it */
+ if (writable)
+ ptr->dirty = TRUE;
+ /* Return address of proper part of the buffer */
+ return ptr->mem_buffer + (start_row - ptr->cur_start_row);
+}
+
+
+METHODDEF(JBLOCKARRAY)
+access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr,
+ JDIMENSION start_row, JDIMENSION num_rows,
+ boolean writable)
+/* Access the part of a virtual block array starting at start_row */
+/* and extending for num_rows rows. writable is true if */
+/* caller intends to modify the accessed area. */
+{
+ JDIMENSION end_row = start_row + num_rows;
+ JDIMENSION undef_row;
+
+ /* debugging check */
+ if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
+ ptr->mem_buffer == NULL)
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+
+ /* Make the desired part of the virtual array accessible */
+ if (start_row < ptr->cur_start_row ||
+ end_row > ptr->cur_start_row+ptr->rows_in_mem) {
+ if (! ptr->b_s_open)
+ ERREXIT(cinfo, JERR_VIRTUAL_BUG);
+ /* Flush old buffer contents if necessary */
+ if (ptr->dirty) {
+ do_barray_io(cinfo, ptr, TRUE);
+ ptr->dirty = FALSE;
+ }
+ /* Decide what part of virtual array to access.
+ * Algorithm: if target address > current window, assume forward scan,
+ * load starting at target address. If target address < current window,
+ * assume backward scan, load so that target area is top of window.
+ * Note that when switching from forward write to forward read, will have
+ * start_row = 0, so the limiting case applies and we load from 0 anyway.
+ */
+ if (start_row > ptr->cur_start_row) {
+ ptr->cur_start_row = start_row;
+ } else {
+ /* use long arithmetic here to avoid overflow & unsigned problems */
+ long ltemp;
+
+ ltemp = (long) end_row - (long) ptr->rows_in_mem;
+ if (ltemp < 0)
+ ltemp = 0; /* don't fall off front end of file */
+ ptr->cur_start_row = (JDIMENSION) ltemp;
+ }
+ /* Read in the selected part of the array.
+ * During the initial write pass, we will do no actual read
+ * because the selected part is all undefined.
+ */
+ do_barray_io(cinfo, ptr, FALSE);
+ }
+ /* Ensure the accessed part of the array is defined; prezero if needed.
+ * To improve locality of access, we only prezero the part of the array
+ * that the caller is about to access, not the entire in-memory array.
+ */
+ if (ptr->first_undef_row < end_row) {
+ if (ptr->first_undef_row < start_row) {
+ if (writable) /* writer skipped over a section of array */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ undef_row = start_row; /* but reader is allowed to read ahead */
+ } else {
+ undef_row = ptr->first_undef_row;
+ }
+ if (writable)
+ ptr->first_undef_row = end_row;
+ if (ptr->pre_zero) {
+ size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK);
+ undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
+ end_row -= ptr->cur_start_row;
+ while (undef_row < end_row) {
+ jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
+ undef_row++;
+ }
+ } else {
+ if (! writable) /* reader looking at undefined data */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ }
+ }
+ /* Flag the buffer dirty if caller will write in it */
+ if (writable)
+ ptr->dirty = TRUE;
+ /* Return address of proper part of the buffer */
+ return ptr->mem_buffer + (start_row - ptr->cur_start_row);
+}
+
+
+/*
+ * Release all objects belonging to a specified pool.
+ */
+
+METHODDEF(void)
+free_pool (j_common_ptr cinfo, int pool_id)
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ small_pool_ptr shdr_ptr;
+ large_pool_ptr lhdr_ptr;
+ size_t space_freed;
+
+ if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+#ifdef MEM_STATS
+ if (cinfo->err->trace_level > 1)
+ print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */
+#endif
+
+ /* If freeing IMAGE pool, close any virtual arrays first */
+ if (pool_id == JPOOL_IMAGE) {
+ jvirt_sarray_ptr sptr;
+ jvirt_barray_ptr bptr;
+
+ for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+ if (sptr->b_s_open) { /* there may be no backing store */
+ sptr->b_s_open = FALSE; /* prevent recursive close if error */
+ (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info);
+ }
+ }
+ mem->virt_sarray_list = NULL;
+ for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+ if (bptr->b_s_open) { /* there may be no backing store */
+ bptr->b_s_open = FALSE; /* prevent recursive close if error */
+ (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info);
+ }
+ }
+ mem->virt_barray_list = NULL;
+ }
+
+ /* Release large objects */
+ lhdr_ptr = mem->large_list[pool_id];
+ mem->large_list[pool_id] = NULL;
+
+ while (lhdr_ptr != NULL) {
+ large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next;
+ space_freed = lhdr_ptr->hdr.bytes_used +
+ lhdr_ptr->hdr.bytes_left +
+ SIZEOF(large_pool_hdr);
+ jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed);
+ mem->total_space_allocated -= space_freed;
+ lhdr_ptr = next_lhdr_ptr;
+ }
+
+ /* Release small objects */
+ shdr_ptr = mem->small_list[pool_id];
+ mem->small_list[pool_id] = NULL;
+
+ while (shdr_ptr != NULL) {
+ small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next;
+ space_freed = shdr_ptr->hdr.bytes_used +
+ shdr_ptr->hdr.bytes_left +
+ SIZEOF(small_pool_hdr);
+ jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed);
+ mem->total_space_allocated -= space_freed;
+ shdr_ptr = next_shdr_ptr;
+ }
+}
+
+
+/*
+ * Close up shop entirely.
+ * Note that this cannot be called unless cinfo->mem is non-NULL.
+ */
+
+METHODDEF(void)
+self_destruct (j_common_ptr cinfo)
+{
+ int pool;
+
+ /* Close all backing store, release all memory.
+ * Releasing pools in reverse order might help avoid fragmentation
+ * with some (brain-damaged) malloc libraries.
+ */
+ for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
+ free_pool(cinfo, pool);
+ }
+
+ /* Release the memory manager control block too. */
+ jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr));
+ cinfo->mem = NULL; /* ensures I will be called only once */
+
+ jpeg_mem_term(cinfo); /* system-dependent cleanup */
+}
+
+
+/*
+ * Memory manager initialization.
+ * When this is called, only the error manager pointer is valid in cinfo!
+ */
+
+GLOBAL(void)
+jinit_memory_mgr (j_common_ptr cinfo)
+{
+ my_mem_ptr mem;
+ long max_to_use;
+ int pool;
+ size_t test_mac;
+
+ cinfo->mem = NULL; /* for safety if init fails */
+
+ /* Check for configuration errors.
+ * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably
+ * doesn't reflect any real hardware alignment requirement.
+ * The test is a little tricky: for X>0, X and X-1 have no one-bits
+ * in common if and only if X is a power of 2, ie has only one one-bit.
+ * Some compilers may give an "unreachable code" warning here; ignore it.
+ */
+ if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0)
+ ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE);
+ /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be
+ * a multiple of SIZEOF(ALIGN_TYPE).
+ * Again, an "unreachable code" warning may be ignored here.
+ * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK.
+ */
+ test_mac = (size_t) MAX_ALLOC_CHUNK;
+ if ((long) test_mac != MAX_ALLOC_CHUNK ||
+ (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0)
+ ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
+
+ max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */
+
+ /* Attempt to allocate memory manager's control block */
+ mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr));
+
+ if (mem == NULL) {
+ jpeg_mem_term(cinfo); /* system-dependent cleanup */
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);
+ }
+
+ /* OK, fill in the method pointers */
+ mem->pub.alloc_small = alloc_small;
+ mem->pub.alloc_large = alloc_large;
+ mem->pub.alloc_sarray = alloc_sarray;
+ mem->pub.alloc_barray = alloc_barray;
+ mem->pub.request_virt_sarray = request_virt_sarray;
+ mem->pub.request_virt_barray = request_virt_barray;
+ mem->pub.realize_virt_arrays = realize_virt_arrays;
+ mem->pub.access_virt_sarray = access_virt_sarray;
+ mem->pub.access_virt_barray = access_virt_barray;
+ mem->pub.free_pool = free_pool;
+ mem->pub.self_destruct = self_destruct;
+
+ /* Make MAX_ALLOC_CHUNK accessible to other modules */
+ mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK;
+
+ /* Initialize working state */
+ mem->pub.max_memory_to_use = max_to_use;
+
+ for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
+ mem->small_list[pool] = NULL;
+ mem->large_list[pool] = NULL;
+ }
+ mem->virt_sarray_list = NULL;
+ mem->virt_barray_list = NULL;
+
+ mem->total_space_allocated = SIZEOF(my_memory_mgr);
+
+ /* Declare ourselves open for business */
+ cinfo->mem = & mem->pub;
+
+ /* Check for an environment variable JPEGMEM; if found, override the
+ * default max_memory setting from jpeg_mem_init. Note that the
+ * surrounding application may again override this value.
+ * If your system doesn't support getenv(), define NO_GETENV to disable
+ * this feature.
+ */
+#ifndef NO_GETENV
+ { char * memenv;
+
+ if ((memenv = getenv("JPEGMEM")) != NULL) {
+ char ch = 'x';
+
+ if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) {
+ if (ch == 'm' || ch == 'M')
+ max_to_use *= 1000L;
+ mem->pub.max_memory_to_use = max_to_use * 1000L;
+ }
+ }
+ }
+#endif
+
+}
diff --git a/external/jpeg-8c/jmemnobs.c b/external/jpeg-8c/jmemnobs.c
new file mode 100644
index 0000000..eb8c337
--- /dev/null
+++ b/external/jpeg-8c/jmemnobs.c
@@ -0,0 +1,109 @@
+/*
+ * jmemnobs.c
+ *
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides a really simple implementation of the system-
+ * dependent portion of the JPEG memory manager. This implementation
+ * assumes that no backing-store files are needed: all required space
+ * can be obtained from malloc().
+ * This is very portable in the sense that it'll compile on almost anything,
+ * but you'd better have lots of main memory (or virtual memory) if you want
+ * to process big images.
+ * Note that the max_memory_to_use option is ignored by this implementation.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+
+/*
+ * Memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: although we include FAR keywords in the routine declarations,
+ * this file won't actually work in 80x86 small/medium model; at least,
+ * you probably won't be able to process useful-size images in only 64KB.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void FAR *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * Here we always say, "we got all you want bud!"
+ */
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ return max_bytes_needed;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Since jpeg_mem_available always promised the moon,
+ * this should never be called and we can just error out.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ ERREXIT(cinfo, JERR_NO_BACKING_STORE);
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required. Here, there isn't any.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ return 0; /* just set max_memory_to_use to 0 */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* no work */
+}
diff --git a/external/jpeg-8c/jmemsys.h b/external/jpeg-8c/jmemsys.h
new file mode 100644
index 0000000..6c3c6d3
--- /dev/null
+++ b/external/jpeg-8c/jmemsys.h
@@ -0,0 +1,198 @@
+/*
+ * jmemsys.h
+ *
+ * Copyright (C) 1992-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 include file defines the interface between the system-independent
+ * and system-dependent portions of the JPEG memory manager. No other
+ * modules need include it. (The system-independent portion is jmemmgr.c;
+ * there are several different versions of the system-dependent portion.)
+ *
+ * This file works as-is for the system-dependent memory managers supplied
+ * in the IJG distribution. You may need to modify it if you write a
+ * custom memory manager. If system-dependent changes are needed in
+ * this file, the best method is to #ifdef them based on a configuration
+ * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR
+ * and USE_MAC_MEMMGR.
+ */
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_get_small jGetSmall
+#define jpeg_free_small jFreeSmall
+#define jpeg_get_large jGetLarge
+#define jpeg_free_large jFreeLarge
+#define jpeg_mem_available jMemAvail
+#define jpeg_open_backing_store jOpenBackStore
+#define jpeg_mem_init jMemInit
+#define jpeg_mem_term jMemTerm
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/*
+ * These two functions are used to allocate and release small chunks of
+ * memory. (Typically the total amount requested through jpeg_get_small is
+ * no more than 20K or so; this will be requested in chunks of a few K each.)
+ * Behavior should be the same as for the standard library functions malloc
+ * and free; in particular, jpeg_get_small must return NULL on failure.
+ * On most systems, these ARE malloc and free. jpeg_free_small is passed the
+ * size of the object being freed, just in case it's needed.
+ * On an 80x86 machine using small-data memory model, these manage near heap.
+ */
+
+EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject));
+EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object,
+ size_t sizeofobject));
+
+/*
+ * These two functions are used to allocate and release large chunks of
+ * memory (up to the total free space designated by jpeg_mem_available).
+ * The interface is the same as above, except that on an 80x86 machine,
+ * far pointers are used. On most other machines these are identical to
+ * the jpeg_get/free_small routines; but we keep them separate anyway,
+ * in case a different allocation strategy is desirable for large chunks.
+ */
+
+EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo,
+ size_t sizeofobject));
+EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object,
+ size_t sizeofobject));
+
+/*
+ * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may
+ * be requested in a single call to jpeg_get_large (and jpeg_get_small for that
+ * matter, but that case should never come into play). This macro is needed
+ * to model the 64Kb-segment-size limit of far addressing on 80x86 machines.
+ * On those machines, we expect that jconfig.h will provide a proper value.
+ * On machines with 32-bit flat address spaces, any large constant may be used.
+ *
+ * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type
+ * size_t and will be a multiple of sizeof(align_type).
+ */
+
+#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */
+#define MAX_ALLOC_CHUNK 1000000000L
+#endif
+
+/*
+ * This routine computes the total space still available for allocation by
+ * jpeg_get_large. If more space than this is needed, backing store will be
+ * used. NOTE: any memory already allocated must not be counted.
+ *
+ * There is a minimum space requirement, corresponding to the minimum
+ * feasible buffer sizes; jmemmgr.c will request that much space even if
+ * jpeg_mem_available returns zero. The maximum space needed, enough to hold
+ * all working storage in memory, is also passed in case it is useful.
+ * Finally, the total space already allocated is passed. If no better
+ * method is available, cinfo->mem->max_memory_to_use - already_allocated
+ * is often a suitable calculation.
+ *
+ * It is OK for jpeg_mem_available to underestimate the space available
+ * (that'll just lead to more backing-store access than is really necessary).
+ * However, an overestimate will lead to failure. Hence it's wise to subtract
+ * a slop factor from the true available space. 5% should be enough.
+ *
+ * On machines with lots of virtual memory, any large constant may be returned.
+ * Conversely, zero may be returned to always use the minimum amount of memory.
+ */
+
+EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo,
+ long min_bytes_needed,
+ long max_bytes_needed,
+ long already_allocated));
+
+
+/*
+ * This structure holds whatever state is needed to access a single
+ * backing-store object. The read/write/close method pointers are called
+ * by jmemmgr.c to manipulate the backing-store object; all other fields
+ * are private to the system-dependent backing store routines.
+ */
+
+#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */
+
+
+#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */
+
+typedef unsigned short XMSH; /* type of extended-memory handles */
+typedef unsigned short EMSH; /* type of expanded-memory handles */
+
+typedef union {
+ short file_handle; /* DOS file handle if it's a temp file */
+ XMSH xms_handle; /* handle if it's a chunk of XMS */
+ EMSH ems_handle; /* handle if it's a chunk of EMS */
+} handle_union;
+
+#endif /* USE_MSDOS_MEMMGR */
+
+#ifdef USE_MAC_MEMMGR /* Mac-specific junk */
+#include <Files.h>
+#endif /* USE_MAC_MEMMGR */
+
+
+typedef struct backing_store_struct * backing_store_ptr;
+
+typedef struct backing_store_struct {
+ /* Methods for reading/writing/closing this backing-store object */
+ JMETHOD(void, read_backing_store, (j_common_ptr cinfo,
+ backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count));
+ JMETHOD(void, write_backing_store, (j_common_ptr cinfo,
+ backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count));
+ JMETHOD(void, close_backing_store, (j_common_ptr cinfo,
+ backing_store_ptr info));
+
+ /* Private fields for system-dependent backing-store management */
+#ifdef USE_MSDOS_MEMMGR
+ /* For the MS-DOS manager (jmemdos.c), we need: */
+ handle_union handle; /* reference to backing-store storage object */
+ char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
+#else
+#ifdef USE_MAC_MEMMGR
+ /* For the Mac manager (jmemmac.c), we need: */
+ short temp_file; /* file reference number to temp file */
+ FSSpec tempSpec; /* the FSSpec for the temp file */
+ char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
+#else
+ /* For a typical implementation with temp files, we need: */
+ FILE * temp_file; /* stdio reference to temp file */
+ char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */
+#endif
+#endif
+} backing_store_info;
+
+
+/*
+ * Initial opening of a backing-store object. This must fill in the
+ * read/write/close pointers in the object. The read/write routines
+ * may take an error exit if the specified maximum file size is exceeded.
+ * (If jpeg_mem_available always returns a large value, this routine can
+ * just take an error exit.)
+ */
+
+EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo,
+ backing_store_ptr info,
+ long total_bytes_needed));
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required. jpeg_mem_init will be called before anything is
+ * allocated (and, therefore, nothing in cinfo is of use except the error
+ * manager pointer). It should return a suitable default value for
+ * max_memory_to_use; this may subsequently be overridden by the surrounding
+ * application. (Note that max_memory_to_use is only important if
+ * jpeg_mem_available chooses to consult it ... no one else will.)
+ * jpeg_mem_term may assume that all requested memory has been freed and that
+ * all opened backing-store objects have been closed.
+ */
+
+EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo));
+EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo));
diff --git a/external/jpeg-8c/jmorecfg.h b/external/jpeg-8c/jmorecfg.h
new file mode 100644
index 0000000..928d052
--- /dev/null
+++ b/external/jpeg-8c/jmorecfg.h
@@ -0,0 +1,371 @@
+/*
+ * jmorecfg.h
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 1997-2009 by Guido Vollbeding.
+ * 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 */
+#ifndef _BASETSD_H_ /* Microsoft defines it in basetsd.h */
+#ifndef _BASETSD_H /* MinGW is slightly different */
+#ifndef QGLOBAL_H /* Qt defines it in qglobal.h */
+typedef long INT32;
+#endif
+#endif
+#endif
+#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.
+ */
+
+#ifndef FAR
+#ifdef NEED_FAR_POINTERS
+#define FAR far
+#else
+#define FAR
+#endif
+#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.)
+ */
+
+/* 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: */
+
+#define 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 DCT_SCALING_SUPPORTED /* Input rescaling via DCT? (Requires DCT_ISLOW)*/
+#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: */
+
+#define 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 IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */
+#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */
+#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */
+#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/external/jpeg-8c/jpegint.h b/external/jpeg-8c/jpegint.h
new file mode 100644
index 0000000..0c27a4e
--- /dev/null
+++ b/external/jpeg-8c/jpegint.h
@@ -0,0 +1,407 @@
+/*
+ * jpegint.h
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 1997-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides common declarations for the various JPEG modules.
+ * These declarations are considered internal to the JPEG library; most
+ * applications using the library shouldn't need to include this file.
+ */
+
+
+/* Declarations for both compression & decompression */
+
+typedef enum { /* Operating modes for buffer controllers */
+ JBUF_PASS_THRU, /* Plain stripwise operation */
+ /* Remaining modes require a full-image buffer to have been created */
+ JBUF_SAVE_SOURCE, /* Run source subobject only, save output */
+ JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */
+ JBUF_SAVE_AND_PASS /* Run both subobjects, save output */
+} J_BUF_MODE;
+
+/* Values of global_state field (jdapi.c has some dependencies on ordering!) */
+#define CSTATE_START 100 /* after create_compress */
+#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */
+#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */
+#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */
+#define DSTATE_START 200 /* after create_decompress */
+#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */
+#define DSTATE_READY 202 /* found SOS, ready for start_decompress */
+#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/
+#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */
+#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */
+#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */
+#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */
+#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */
+#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */
+#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */
+
+
+/* Declarations for compression modules */
+
+/* Master control module */
+struct jpeg_comp_master {
+ JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo));
+ JMETHOD(void, pass_startup, (j_compress_ptr cinfo));
+ JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
+
+ /* State variables made visible to other modules */
+ boolean call_pass_startup; /* True if pass_startup must be called */
+ boolean is_last_pass; /* True during last pass */
+};
+
+/* Main buffer control (downsampled-data buffer) */
+struct jpeg_c_main_controller {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, process_data, (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail));
+};
+
+/* Compression preprocessing (downsampling input buffer control) */
+struct jpeg_c_prep_controller {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, pre_process_data, (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ JSAMPIMAGE output_buf,
+ JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail));
+};
+
+/* Coefficient buffer control */
+struct jpeg_c_coef_controller {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(boolean, compress_data, (j_compress_ptr cinfo,
+ JSAMPIMAGE input_buf));
+};
+
+/* Colorspace conversion */
+struct jpeg_color_converter {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+ JMETHOD(void, color_convert, (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows));
+};
+
+/* Downsampling */
+struct jpeg_downsampler {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+ JMETHOD(void, downsample, (j_compress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_index,
+ JSAMPIMAGE output_buf,
+ JDIMENSION out_row_group_index));
+
+ boolean need_context_rows; /* TRUE if need rows above & below */
+};
+
+/* Forward DCT (also controls coefficient quantization) */
+typedef JMETHOD(void, forward_DCT_ptr,
+ (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks));
+
+struct jpeg_forward_dct {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+ /* It is useful to allow each component to have a separate FDCT method. */
+ forward_DCT_ptr forward_DCT[MAX_COMPONENTS];
+};
+
+/* Entropy encoding */
+struct jpeg_entropy_encoder {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics));
+ JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data));
+ JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
+};
+
+/* Marker writing */
+struct jpeg_marker_writer {
+ JMETHOD(void, write_file_header, (j_compress_ptr cinfo));
+ JMETHOD(void, write_frame_header, (j_compress_ptr cinfo));
+ JMETHOD(void, write_scan_header, (j_compress_ptr cinfo));
+ JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo));
+ JMETHOD(void, write_tables_only, (j_compress_ptr cinfo));
+ /* These routines are exported to allow insertion of extra markers */
+ /* Probably only COM and APPn markers should be written this way */
+ JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker,
+ unsigned int datalen));
+ JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val));
+};
+
+
+/* Declarations for decompression modules */
+
+/* Master control module */
+struct jpeg_decomp_master {
+ JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo));
+
+ /* State variables made visible to other modules */
+ boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */
+};
+
+/* Input control module */
+struct jpeg_input_controller {
+ JMETHOD(int, consume_input, (j_decompress_ptr cinfo));
+ JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo));
+ JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo));
+
+ /* State variables made visible to other modules */
+ boolean has_multiple_scans; /* True if file has multiple scans */
+ boolean eoi_reached; /* True when EOI has been consumed */
+};
+
+/* Main buffer control (downsampled-data buffer) */
+struct jpeg_d_main_controller {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, process_data, (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+};
+
+/* Coefficient buffer control */
+struct jpeg_d_coef_controller {
+ JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
+ JMETHOD(int, consume_data, (j_decompress_ptr cinfo));
+ JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo));
+ JMETHOD(int, decompress_data, (j_decompress_ptr cinfo,
+ JSAMPIMAGE output_buf));
+ /* Pointer to array of coefficient virtual arrays, or NULL if none */
+ jvirt_barray_ptr *coef_arrays;
+};
+
+/* Decompression postprocessing (color quantization buffer control) */
+struct jpeg_d_post_controller {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, post_process_data, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+};
+
+/* Marker reading & parsing */
+struct jpeg_marker_reader {
+ JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo));
+ /* Read markers until SOS or EOI.
+ * Returns same codes as are defined for jpeg_consume_input:
+ * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ */
+ JMETHOD(int, read_markers, (j_decompress_ptr cinfo));
+ /* Read a restart marker --- exported for use by entropy decoder only */
+ jpeg_marker_parser_method read_restart_marker;
+
+ /* State of marker reader --- nominally internal, but applications
+ * supplying COM or APPn handlers might like to know the state.
+ */
+ boolean saw_SOI; /* found SOI? */
+ boolean saw_SOF; /* found SOF? */
+ int next_restart_num; /* next restart number expected (0-7) */
+ unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */
+};
+
+/* Entropy decoding */
+struct jpeg_entropy_decoder {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+};
+
+/* Inverse DCT (also performs dequantization) */
+typedef JMETHOD(void, inverse_DCT_method_ptr,
+ (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col));
+
+struct jpeg_inverse_dct {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ /* It is useful to allow each component to have a separate IDCT method. */
+ inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
+};
+
+/* Upsampling (note that upsampler must also call color converter) */
+struct jpeg_upsampler {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, upsample, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+
+ boolean need_context_rows; /* TRUE if need rows above & below */
+};
+
+/* Colorspace conversion */
+struct jpeg_color_deconverter {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, color_convert, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows));
+};
+
+/* Color quantization or color precision reduction */
+struct jpeg_color_quantizer {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan));
+ JMETHOD(void, color_quantize, (j_decompress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPARRAY output_buf,
+ int num_rows));
+ JMETHOD(void, finish_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, new_color_map, (j_decompress_ptr cinfo));
+};
+
+
+/* Miscellaneous useful macros */
+
+#undef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#undef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+
+/* We assume that right shift corresponds to signed division by 2 with
+ * rounding towards minus infinity. This is correct for typical "arithmetic
+ * shift" instructions that shift in copies of the sign bit. But some
+ * C compilers implement >> with an unsigned shift. For these machines you
+ * must define RIGHT_SHIFT_IS_UNSIGNED.
+ * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
+ * It is only applied with constant shift counts. SHIFT_TEMPS must be
+ * included in the variables of any routine using RIGHT_SHIFT.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define SHIFT_TEMPS INT32 shift_temp;
+#define RIGHT_SHIFT(x,shft) \
+ ((shift_temp = (x)) < 0 ? \
+ (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
+ (shift_temp >> (shft)))
+#else
+#define SHIFT_TEMPS
+#define RIGHT_SHIFT(x,shft) ((x) >> (shft))
+#endif
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jinit_compress_master jICompress
+#define jinit_c_master_control jICMaster
+#define jinit_c_main_controller jICMainC
+#define jinit_c_prep_controller jICPrepC
+#define jinit_c_coef_controller jICCoefC
+#define jinit_color_converter jICColor
+#define jinit_downsampler jIDownsampler
+#define jinit_forward_dct jIFDCT
+#define jinit_huff_encoder jIHEncoder
+#define jinit_arith_encoder jIAEncoder
+#define jinit_marker_writer jIMWriter
+#define jinit_master_decompress jIDMaster
+#define jinit_d_main_controller jIDMainC
+#define jinit_d_coef_controller jIDCoefC
+#define jinit_d_post_controller jIDPostC
+#define jinit_input_controller jIInCtlr
+#define jinit_marker_reader jIMReader
+#define jinit_huff_decoder jIHDecoder
+#define jinit_arith_decoder jIADecoder
+#define jinit_inverse_dct jIIDCT
+#define jinit_upsampler jIUpsampler
+#define jinit_color_deconverter jIDColor
+#define jinit_1pass_quantizer jI1Quant
+#define jinit_2pass_quantizer jI2Quant
+#define jinit_merged_upsampler jIMUpsampler
+#define jinit_memory_mgr jIMemMgr
+#define jdiv_round_up jDivRound
+#define jround_up jRound
+#define jcopy_sample_rows jCopySamples
+#define jcopy_block_row jCopyBlocks
+#define jzero_far jZeroFar
+#define jpeg_zigzag_order jZIGTable
+#define jpeg_natural_order jZAGTable
+#define jpeg_natural_order7 jZAGTable7
+#define jpeg_natural_order6 jZAGTable6
+#define jpeg_natural_order5 jZAGTable5
+#define jpeg_natural_order4 jZAGTable4
+#define jpeg_natural_order3 jZAGTable3
+#define jpeg_natural_order2 jZAGTable2
+#define jpeg_aritab jAriTab
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/* Compression module initialization routines */
+EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo,
+ boolean transcode_only));
+EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo));
+/* Decompression module initialization routines */
+EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo));
+/* Memory manager initialization */
+EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo));
+
+/* Utility routines in jutils.c */
+EXTERN(long) jdiv_round_up JPP((long a, long b));
+EXTERN(long) jround_up JPP((long a, long b));
+EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row,
+ JSAMPARRAY output_array, int dest_row,
+ int num_rows, JDIMENSION num_cols));
+EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row,
+ JDIMENSION num_blocks));
+EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero));
+/* Constant tables in jutils.c */
+#if 0 /* This table is not actually needed in v6a */
+extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */
+#endif
+extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */
+extern const int jpeg_natural_order7[]; /* zz to natural order for 7x7 block */
+extern const int jpeg_natural_order6[]; /* zz to natural order for 6x6 block */
+extern const int jpeg_natural_order5[]; /* zz to natural order for 5x5 block */
+extern const int jpeg_natural_order4[]; /* zz to natural order for 4x4 block */
+extern const int jpeg_natural_order3[]; /* zz to natural order for 3x3 block */
+extern const int jpeg_natural_order2[]; /* zz to natural order for 2x2 block */
+
+/* Arithmetic coding probability estimation tables in jaricom.c */
+extern const INT32 jpeg_aritab[];
+
+/* Suppress undefined-structure complaints if necessary. */
+
+#ifdef INCOMPLETE_TYPES_BROKEN
+#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */
+struct jvirt_sarray_control { long dummy; };
+struct jvirt_barray_control { long dummy; };
+#endif
+#endif /* INCOMPLETE_TYPES_BROKEN */
diff --git a/external/jpeg-8c/jpeglib.h b/external/jpeg-8c/jpeglib.h
new file mode 100644
index 0000000..1eb1fac
--- /dev/null
+++ b/external/jpeg-8c/jpeglib.h
@@ -0,0 +1,1160 @@
+/*
+ * jpeglib.h
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2002-2010 by Guido Vollbeding.
+ * 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 */
+
+
+#ifdef __cplusplus
+#ifndef DONT_USE_EXTERN_C
+extern "C" {
+#endif
+#endif
+
+/* Version IDs for the JPEG library.
+ * Might be useful for tests like "#if JPEG_LIB_VERSION >= 80".
+ */
+
+#define JPEG_LIB_VERSION 80 /* Compatibility version 8.0 */
+#define JPEG_LIB_VERSION_MAJOR 8
+#define JPEG_LIB_VERSION_MINOR 3
+
+
+/* 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.
+ */
+
+typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */
+typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */
+typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */
+
+typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */
+typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */
+typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */
+typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */
+
+typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */
+
+
+/* Types for JPEG compression parameters and working tables. */
+
+
+/* DCT coefficient quantization tables. */
+
+typedef struct {
+ /* This 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,
+ * reflecting any scaling we choose to apply during the DCT step.
+ * Values from 1 to 16 are supported.
+ * Note that different components may receive different DCT scalings.
+ */
+ int DCT_h_scaled_size;
+ int DCT_v_scaled_size;
+ /* The downsampled dimensions are the component's actual, unpadded number
+ * of samples at the main buffer (preprocessing/compression interface);
+ * DCT scaling is included, so
+ * downsampled_width = ceil(image_width * Hi/Hmax * DCT_h_scaled_size/DCTSIZE)
+ * and similarly for height.
+ */
+ 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_h_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.
+ */
+
+ unsigned int scale_num, scale_denom; /* fraction by which to scale image */
+
+ JDIMENSION jpeg_width; /* scaled JPEG image width */
+ JDIMENSION jpeg_height; /* scaled JPEG image height */
+ /* Dimensions of actual JPEG image that will be written to file,
+ * derived from input dimensions by scaling factors above.
+ * These fields are computed by jpeg_start_compress().
+ * You can also use jpeg_calc_jpeg_dimensions() to determine these values
+ * in advance of calling jpeg_start_compress().
+ */
+
+ 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];
+ int q_scale_factor[NUM_QUANT_TBLS];
+ /* ptrs to coefficient quantization tables, or NULL if not defined,
+ * and corresponding scale factors (percentage, initialized 100).
+ */
+
+ 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 */
+ boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */
+ 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 */
+
+ int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */
+ int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */
+
+ 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 */
+
+ int block_size; /* the basic DCT block size: 1..16 */
+ const int * natural_order; /* natural-order position array */
+ int lim_Se; /* min( Se, DCTSIZE2-1 ) */
+
+ /*
+ * 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 is_baseline; /* TRUE if Baseline SOF0 encountered */
+ 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_h_scaled_size; /* smallest DCT_h_scaled_size of any component */
+ int min_DCT_v_scaled_size; /* smallest DCT_v_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_v_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 */
+
+ /* These fields are derived from Se of first SOS marker.
+ */
+ int block_size; /* the basic DCT block size: 1..16 */
+ const int * natural_order; /* natural-order position array for entropy decode */
+ int lim_Se; /* min( Se, DCTSIZE2-1 ) for entropy decode */
+
+ /* 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_mem_dest jMemDest
+#define jpeg_mem_src jMemSrc
+#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_default_qtables jDefQTables
+#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_calc_jpeg_dimensions jCjpegDimensions
+#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_core_output_dimensions jCoreDimensions
+#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));
+
+/* Data source and destination managers: memory buffers. */
+EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo,
+ unsigned char ** outbuffer,
+ unsigned long * outsize));
+EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo,
+ unsigned char * inbuffer,
+ unsigned long insize));
+
+/* 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_default_qtables JPP((j_compress_ptr cinfo,
+ 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));
+
+/* Precalculate JPEG dimensions for current compression parameters. */
+EXTERN(void) jpeg_calc_jpeg_dimensions 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.txt 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_core_output_dimensions JPP((j_decompress_ptr cinfo));
+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
+
+#ifdef __cplusplus
+#ifndef DONT_USE_EXTERN_C
+}
+#endif
+#endif
+
+#endif /* JPEGLIB_H */
diff --git a/external/jpeg-8c/jquant1.c b/external/jpeg-8c/jquant1.c
new file mode 100644
index 0000000..b2f96aa
--- /dev/null
+++ b/external/jpeg-8c/jquant1.c
@@ -0,0 +1,856 @@
+/*
+ * jquant1.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains 1-pass color quantization (color mapping) routines.
+ * These routines provide mapping to a fixed color map using equally spaced
+ * color values. Optional Floyd-Steinberg or ordered dithering is available.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef QUANT_1PASS_SUPPORTED
+
+
+/*
+ * The main purpose of 1-pass quantization is to provide a fast, if not very
+ * high quality, colormapped output capability. A 2-pass quantizer usually
+ * gives better visual quality; however, for quantized grayscale output this
+ * quantizer is perfectly adequate. Dithering is highly recommended with this
+ * quantizer, though you can turn it off if you really want to.
+ *
+ * In 1-pass quantization the colormap must be chosen in advance of seeing the
+ * image. We use a map consisting of all combinations of Ncolors[i] color
+ * values for the i'th component. The Ncolors[] values are chosen so that
+ * their product, the total number of colors, is no more than that requested.
+ * (In most cases, the product will be somewhat less.)
+ *
+ * Since the colormap is orthogonal, the representative value for each color
+ * component can be determined without considering the other components;
+ * then these indexes can be combined into a colormap index by a standard
+ * N-dimensional-array-subscript calculation. Most of the arithmetic involved
+ * can be precalculated and stored in the lookup table colorindex[].
+ * colorindex[i][j] maps pixel value j in component i to the nearest
+ * representative value (grid plane) for that component; this index is
+ * multiplied by the array stride for component i, so that the
+ * index of the colormap entry closest to a given pixel value is just
+ * sum( colorindex[component-number][pixel-component-value] )
+ * Aside from being fast, this scheme allows for variable spacing between
+ * representative values with no additional lookup cost.
+ *
+ * If gamma correction has been applied in color conversion, it might be wise
+ * to adjust the color grid spacing so that the representative colors are
+ * equidistant in linear space. At this writing, gamma correction is not
+ * implemented by jdcolor, so nothing is done here.
+ */
+
+
+/* Declarations for ordered dithering.
+ *
+ * We use a standard 16x16 ordered dither array. The basic concept of ordered
+ * dithering is described in many references, for instance Dale Schumacher's
+ * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991).
+ * In place of Schumacher's comparisons against a "threshold" value, we add a
+ * "dither" value to the input pixel and then round the result to the nearest
+ * output value. The dither value is equivalent to (0.5 - threshold) times
+ * the distance between output values. For ordered dithering, we assume that
+ * the output colors are equally spaced; if not, results will probably be
+ * worse, since the dither may be too much or too little at a given point.
+ *
+ * The normal calculation would be to form pixel value + dither, range-limit
+ * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual.
+ * We can skip the separate range-limiting step by extending the colorindex
+ * table in both directions.
+ */
+
+#define ODITHER_SIZE 16 /* dimension of dither matrix */
+/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */
+#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */
+#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */
+
+typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE];
+typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE];
+
+static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = {
+ /* Bayer's order-4 dither array. Generated by the code given in
+ * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I.
+ * The values in this array must range from 0 to ODITHER_CELLS-1.
+ */
+ { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
+ { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
+ { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
+ { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
+ { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
+ { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
+ { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
+ { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
+ { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
+ { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
+ { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
+ { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
+ { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
+ { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
+ { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
+ { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
+};
+
+
+/* Declarations for Floyd-Steinberg dithering.
+ *
+ * Errors are accumulated into the array fserrors[], at a resolution of
+ * 1/16th of a pixel count. The error at a given pixel is propagated
+ * to its not-yet-processed neighbors using the standard F-S fractions,
+ * ... (here) 7/16
+ * 3/16 5/16 1/16
+ * We work left-to-right on even rows, right-to-left on odd rows.
+ *
+ * We can get away with a single array (holding one row's worth of errors)
+ * by using it to store the current row's errors at pixel columns not yet
+ * processed, but the next row's errors at columns already processed. We
+ * need only a few extra variables to hold the errors immediately around the
+ * current column. (If we are lucky, those variables are in registers, but
+ * even if not, they're probably cheaper to access than array elements are.)
+ *
+ * The fserrors[] array is indexed [component#][position].
+ * We provide (#columns + 2) entries per component; the extra entry at each
+ * end saves us from special-casing the first and last pixels.
+ *
+ * Note: on a wide image, we might not have enough room in a PC's near data
+ * segment to hold the error array; so it is allocated with alloc_large.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+typedef INT16 FSERROR; /* 16 bits should be enough */
+typedef int LOCFSERROR; /* use 'int' for calculation temps */
+#else
+typedef INT32 FSERROR; /* may need more than 16 bits */
+typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */
+#endif
+
+typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */
+
+
+/* Private subobject */
+
+#define MAX_Q_COMPS 4 /* max components I can handle */
+
+typedef struct {
+ struct jpeg_color_quantizer pub; /* public fields */
+
+ /* Initially allocated colormap is saved here */
+ JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */
+ int sv_actual; /* number of entries in use */
+
+ JSAMPARRAY colorindex; /* Precomputed mapping for speed */
+ /* colorindex[i][j] = index of color closest to pixel value j in component i,
+ * premultiplied as described above. Since colormap indexes must fit into
+ * JSAMPLEs, the entries of this array will too.
+ */
+ boolean is_padded; /* is the colorindex padded for odither? */
+
+ int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */
+
+ /* Variables for ordered dithering */
+ int row_index; /* cur row's vertical index in dither matrix */
+ ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */
+
+ /* Variables for Floyd-Steinberg dithering */
+ FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */
+ boolean on_odd_row; /* flag to remember which row we are on */
+} my_cquantizer;
+
+typedef my_cquantizer * my_cquantize_ptr;
+
+
+/*
+ * Policy-making subroutines for create_colormap and create_colorindex.
+ * These routines determine the colormap to be used. The rest of the module
+ * only assumes that the colormap is orthogonal.
+ *
+ * * select_ncolors decides how to divvy up the available colors
+ * among the components.
+ * * output_value defines the set of representative values for a component.
+ * * largest_input_value defines the mapping from input values to
+ * representative values for a component.
+ * Note that the latter two routines may impose different policies for
+ * different components, though this is not currently done.
+ */
+
+
+LOCAL(int)
+select_ncolors (j_decompress_ptr cinfo, int Ncolors[])
+/* Determine allocation of desired colors to components, */
+/* and fill in Ncolors[] array to indicate choice. */
+/* Return value is total number of colors (product of Ncolors[] values). */
+{
+ int nc = cinfo->out_color_components; /* number of color components */
+ int max_colors = cinfo->desired_number_of_colors;
+ int total_colors, iroot, i, j;
+ boolean changed;
+ long temp;
+ static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE };
+
+ /* We can allocate at least the nc'th root of max_colors per component. */
+ /* Compute floor(nc'th root of max_colors). */
+ iroot = 1;
+ do {
+ iroot++;
+ temp = iroot; /* set temp = iroot ** nc */
+ for (i = 1; i < nc; i++)
+ temp *= iroot;
+ } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */
+ iroot--; /* now iroot = floor(root) */
+
+ /* Must have at least 2 color values per component */
+ if (iroot < 2)
+ ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp);
+
+ /* Initialize to iroot color values for each component */
+ total_colors = 1;
+ for (i = 0; i < nc; i++) {
+ Ncolors[i] = iroot;
+ total_colors *= iroot;
+ }
+ /* We may be able to increment the count for one or more components without
+ * exceeding max_colors, though we know not all can be incremented.
+ * Sometimes, the first component can be incremented more than once!
+ * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.)
+ * In RGB colorspace, try to increment G first, then R, then B.
+ */
+ do {
+ changed = FALSE;
+ for (i = 0; i < nc; i++) {
+ j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i);
+ /* calculate new total_colors if Ncolors[j] is incremented */
+ temp = total_colors / Ncolors[j];
+ temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */
+ if (temp > (long) max_colors)
+ break; /* won't fit, done with this pass */
+ Ncolors[j]++; /* OK, apply the increment */
+ total_colors = (int) temp;
+ changed = TRUE;
+ }
+ } while (changed);
+
+ return total_colors;
+}
+
+
+LOCAL(int)
+output_value (j_decompress_ptr cinfo, int ci, int j, int maxj)
+/* Return j'th output value, where j will range from 0 to maxj */
+/* The output values must fall in 0..MAXJSAMPLE in increasing order */
+{
+ /* We always provide values 0 and MAXJSAMPLE for each component;
+ * any additional values are equally spaced between these limits.
+ * (Forcing the upper and lower values to the limits ensures that
+ * dithering can't produce a color outside the selected gamut.)
+ */
+ return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj);
+}
+
+
+LOCAL(int)
+largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj)
+/* Return largest input value that should map to j'th output value */
+/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */
+{
+ /* Breakpoints are halfway between values returned by output_value */
+ return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj));
+}
+
+
+/*
+ * Create the colormap.
+ */
+
+LOCAL(void)
+create_colormap (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ JSAMPARRAY colormap; /* Created colormap */
+ int total_colors; /* Number of distinct output colors */
+ int i,j,k, nci, blksize, blkdist, ptr, val;
+
+ /* Select number of colors for each component */
+ total_colors = select_ncolors(cinfo, cquantize->Ncolors);
+
+ /* Report selected color counts */
+ if (cinfo->out_color_components == 3)
+ TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS,
+ total_colors, cquantize->Ncolors[0],
+ cquantize->Ncolors[1], cquantize->Ncolors[2]);
+ else
+ TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors);
+
+ /* Allocate and fill in the colormap. */
+ /* The colors are ordered in the map in standard row-major order, */
+ /* i.e. rightmost (highest-indexed) color changes most rapidly. */
+
+ colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components);
+
+ /* blksize is number of adjacent repeated entries for a component */
+ /* blkdist is distance between groups of identical entries for a component */
+ blkdist = total_colors;
+
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ /* fill in colormap entries for i'th color component */
+ nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+ blksize = blkdist / nci;
+ for (j = 0; j < nci; j++) {
+ /* Compute j'th output value (out of nci) for component */
+ val = output_value(cinfo, i, j, nci-1);
+ /* Fill in all colormap entries that have this value of this component */
+ for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) {
+ /* fill in blksize entries beginning at ptr */
+ for (k = 0; k < blksize; k++)
+ colormap[i][ptr+k] = (JSAMPLE) val;
+ }
+ }
+ blkdist = blksize; /* blksize of this color is blkdist of next */
+ }
+
+ /* Save the colormap in private storage,
+ * where it will survive color quantization mode changes.
+ */
+ cquantize->sv_colormap = colormap;
+ cquantize->sv_actual = total_colors;
+}
+
+
+/*
+ * Create the color index table.
+ */
+
+LOCAL(void)
+create_colorindex (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ JSAMPROW indexptr;
+ int i,j,k, nci, blksize, val, pad;
+
+ /* For ordered dither, we pad the color index tables by MAXJSAMPLE in
+ * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE).
+ * This is not necessary in the other dithering modes. However, we
+ * flag whether it was done in case user changes dithering mode.
+ */
+ if (cinfo->dither_mode == JDITHER_ORDERED) {
+ pad = MAXJSAMPLE*2;
+ cquantize->is_padded = TRUE;
+ } else {
+ pad = 0;
+ cquantize->is_padded = FALSE;
+ }
+
+ cquantize->colorindex = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (MAXJSAMPLE+1 + pad),
+ (JDIMENSION) cinfo->out_color_components);
+
+ /* blksize is number of adjacent repeated entries for a component */
+ blksize = cquantize->sv_actual;
+
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ /* fill in colorindex entries for i'th color component */
+ nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+ blksize = blksize / nci;
+
+ /* adjust colorindex pointers to provide padding at negative indexes. */
+ if (pad)
+ cquantize->colorindex[i] += MAXJSAMPLE;
+
+ /* in loop, val = index of current output value, */
+ /* and k = largest j that maps to current val */
+ indexptr = cquantize->colorindex[i];
+ val = 0;
+ k = largest_input_value(cinfo, i, 0, nci-1);
+ for (j = 0; j <= MAXJSAMPLE; j++) {
+ while (j > k) /* advance val if past boundary */
+ k = largest_input_value(cinfo, i, ++val, nci-1);
+ /* premultiply so that no multiplication needed in main processing */
+ indexptr[j] = (JSAMPLE) (val * blksize);
+ }
+ /* Pad at both ends if necessary */
+ if (pad)
+ for (j = 1; j <= MAXJSAMPLE; j++) {
+ indexptr[-j] = indexptr[0];
+ indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE];
+ }
+ }
+}
+
+
+/*
+ * Create an ordered-dither array for a component having ncolors
+ * distinct output values.
+ */
+
+LOCAL(ODITHER_MATRIX_PTR)
+make_odither_array (j_decompress_ptr cinfo, int ncolors)
+{
+ ODITHER_MATRIX_PTR odither;
+ int j,k;
+ INT32 num,den;
+
+ odither = (ODITHER_MATRIX_PTR)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(ODITHER_MATRIX));
+ /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1).
+ * Hence the dither value for the matrix cell with fill order f
+ * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1).
+ * On 16-bit-int machine, be careful to avoid overflow.
+ */
+ den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1));
+ for (j = 0; j < ODITHER_SIZE; j++) {
+ for (k = 0; k < ODITHER_SIZE; k++) {
+ num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k])))
+ * MAXJSAMPLE;
+ /* Ensure round towards zero despite C's lack of consistency
+ * about rounding negative values in integer division...
+ */
+ odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den);
+ }
+ }
+ return odither;
+}
+
+
+/*
+ * Create the ordered-dither tables.
+ * Components having the same number of representative colors may
+ * share a dither table.
+ */
+
+LOCAL(void)
+create_odither_tables (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ ODITHER_MATRIX_PTR odither;
+ int i, j, nci;
+
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+ odither = NULL; /* search for matching prior component */
+ for (j = 0; j < i; j++) {
+ if (nci == cquantize->Ncolors[j]) {
+ odither = cquantize->odither[j];
+ break;
+ }
+ }
+ if (odither == NULL) /* need a new table? */
+ odither = make_odither_array(cinfo, nci);
+ cquantize->odither[i] = odither;
+ }
+}
+
+
+/*
+ * Map some rows of pixels to the output colormapped representation.
+ */
+
+METHODDEF(void)
+color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* General case, no dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ JSAMPARRAY colorindex = cquantize->colorindex;
+ register int pixcode, ci;
+ register JSAMPROW ptrin, ptrout;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+ register int nc = cinfo->out_color_components;
+
+ for (row = 0; row < num_rows; row++) {
+ ptrin = input_buf[row];
+ ptrout = output_buf[row];
+ for (col = width; col > 0; col--) {
+ pixcode = 0;
+ for (ci = 0; ci < nc; ci++) {
+ pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]);
+ }
+ *ptrout++ = (JSAMPLE) pixcode;
+ }
+ }
+}
+
+
+METHODDEF(void)
+color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* Fast path for out_color_components==3, no dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register int pixcode;
+ register JSAMPROW ptrin, ptrout;
+ JSAMPROW colorindex0 = cquantize->colorindex[0];
+ JSAMPROW colorindex1 = cquantize->colorindex[1];
+ JSAMPROW colorindex2 = cquantize->colorindex[2];
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ ptrin = input_buf[row];
+ ptrout = output_buf[row];
+ for (col = width; col > 0; col--) {
+ pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]);
+ pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]);
+ pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]);
+ *ptrout++ = (JSAMPLE) pixcode;
+ }
+ }
+}
+
+
+METHODDEF(void)
+quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* General case, with ordered dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register JSAMPROW input_ptr;
+ register JSAMPROW output_ptr;
+ JSAMPROW colorindex_ci;
+ int * dither; /* points to active row of dither matrix */
+ int row_index, col_index; /* current indexes into dither matrix */
+ int nc = cinfo->out_color_components;
+ int ci;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ /* Initialize output values to 0 so can process components separately */
+ jzero_far((void FAR *) output_buf[row],
+ (size_t) (width * SIZEOF(JSAMPLE)));
+ row_index = cquantize->row_index;
+ for (ci = 0; ci < nc; ci++) {
+ input_ptr = input_buf[row] + ci;
+ output_ptr = output_buf[row];
+ colorindex_ci = cquantize->colorindex[ci];
+ dither = cquantize->odither[ci][row_index];
+ col_index = 0;
+
+ for (col = width; col > 0; col--) {
+ /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE,
+ * select output value, accumulate into output code for this pixel.
+ * Range-limiting need not be done explicitly, as we have extended
+ * the colorindex table to produce the right answers for out-of-range
+ * inputs. The maximum dither is +- MAXJSAMPLE; this sets the
+ * required amount of padding.
+ */
+ *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]];
+ input_ptr += nc;
+ output_ptr++;
+ col_index = (col_index + 1) & ODITHER_MASK;
+ }
+ }
+ /* Advance row index for next row */
+ row_index = (row_index + 1) & ODITHER_MASK;
+ cquantize->row_index = row_index;
+ }
+}
+
+
+METHODDEF(void)
+quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* Fast path for out_color_components==3, with ordered dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register int pixcode;
+ register JSAMPROW input_ptr;
+ register JSAMPROW output_ptr;
+ JSAMPROW colorindex0 = cquantize->colorindex[0];
+ JSAMPROW colorindex1 = cquantize->colorindex[1];
+ JSAMPROW colorindex2 = cquantize->colorindex[2];
+ int * dither0; /* points to active row of dither matrix */
+ int * dither1;
+ int * dither2;
+ int row_index, col_index; /* current indexes into dither matrix */
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ row_index = cquantize->row_index;
+ input_ptr = input_buf[row];
+ output_ptr = output_buf[row];
+ dither0 = cquantize->odither[0][row_index];
+ dither1 = cquantize->odither[1][row_index];
+ dither2 = cquantize->odither[2][row_index];
+ col_index = 0;
+
+ for (col = width; col > 0; col--) {
+ pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) +
+ dither0[col_index]]);
+ pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) +
+ dither1[col_index]]);
+ pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) +
+ dither2[col_index]]);
+ *output_ptr++ = (JSAMPLE) pixcode;
+ col_index = (col_index + 1) & ODITHER_MASK;
+ }
+ row_index = (row_index + 1) & ODITHER_MASK;
+ cquantize->row_index = row_index;
+ }
+}
+
+
+METHODDEF(void)
+quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* General case, with Floyd-Steinberg dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register LOCFSERROR cur; /* current error or pixel value */
+ LOCFSERROR belowerr; /* error for pixel below cur */
+ LOCFSERROR bpreverr; /* error for below/prev col */
+ LOCFSERROR bnexterr; /* error for below/next col */
+ LOCFSERROR delta;
+ register FSERRPTR errorptr; /* => fserrors[] at column before current */
+ register JSAMPROW input_ptr;
+ register JSAMPROW output_ptr;
+ JSAMPROW colorindex_ci;
+ JSAMPROW colormap_ci;
+ int pixcode;
+ int nc = cinfo->out_color_components;
+ int dir; /* 1 for left-to-right, -1 for right-to-left */
+ int dirnc; /* dir * nc */
+ int ci;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+ JSAMPLE *range_limit = cinfo->sample_range_limit;
+ SHIFT_TEMPS
+
+ for (row = 0; row < num_rows; row++) {
+ /* Initialize output values to 0 so can process components separately */
+ jzero_far((void FAR *) output_buf[row],
+ (size_t) (width * SIZEOF(JSAMPLE)));
+ for (ci = 0; ci < nc; ci++) {
+ input_ptr = input_buf[row] + ci;
+ output_ptr = output_buf[row];
+ if (cquantize->on_odd_row) {
+ /* work right to left in this row */
+ input_ptr += (width-1) * nc; /* so point to rightmost pixel */
+ output_ptr += width-1;
+ dir = -1;
+ dirnc = -nc;
+ errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */
+ } else {
+ /* work left to right in this row */
+ dir = 1;
+ dirnc = nc;
+ errorptr = cquantize->fserrors[ci]; /* => entry before first column */
+ }
+ colorindex_ci = cquantize->colorindex[ci];
+ colormap_ci = cquantize->sv_colormap[ci];
+ /* Preset error values: no error propagated to first pixel from left */
+ cur = 0;
+ /* and no error propagated to row below yet */
+ belowerr = bpreverr = 0;
+
+ for (col = width; col > 0; col--) {
+ /* cur holds the error propagated from the previous pixel on the
+ * current line. Add the error propagated from the previous line
+ * to form the complete error correction term for this pixel, and
+ * round the error term (which is expressed * 16) to an integer.
+ * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
+ * for either sign of the error value.
+ * Note: errorptr points to *previous* column's array entry.
+ */
+ cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4);
+ /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+ * The maximum error is +- MAXJSAMPLE; this sets the required size
+ * of the range_limit array.
+ */
+ cur += GETJSAMPLE(*input_ptr);
+ cur = GETJSAMPLE(range_limit[cur]);
+ /* Select output value, accumulate into output code for this pixel */
+ pixcode = GETJSAMPLE(colorindex_ci[cur]);
+ *output_ptr += (JSAMPLE) pixcode;
+ /* Compute actual representation error at this pixel */
+ /* Note: we can do this even though we don't have the final */
+ /* pixel code, because the colormap is orthogonal. */
+ cur -= GETJSAMPLE(colormap_ci[pixcode]);
+ /* Compute error fractions to be propagated to adjacent pixels.
+ * Add these into the running sums, and simultaneously shift the
+ * next-line error sums left by 1 column.
+ */
+ bnexterr = cur;
+ delta = cur * 2;
+ cur += delta; /* form error * 3 */
+ errorptr[0] = (FSERROR) (bpreverr + cur);
+ cur += delta; /* form error * 5 */
+ bpreverr = belowerr + cur;
+ belowerr = bnexterr;
+ cur += delta; /* form error * 7 */
+ /* At this point cur contains the 7/16 error value to be propagated
+ * to the next pixel on the current line, and all the errors for the
+ * next line have been shifted over. We are therefore ready to move on.
+ */
+ input_ptr += dirnc; /* advance input ptr to next column */
+ output_ptr += dir; /* advance output ptr to next column */
+ errorptr += dir; /* advance errorptr to current column */
+ }
+ /* Post-loop cleanup: we must unload the final error value into the
+ * final fserrors[] entry. Note we need not unload belowerr because
+ * it is for the dummy column before or after the actual array.
+ */
+ errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */
+ }
+ cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE);
+ }
+}
+
+
+/*
+ * Allocate workspace for Floyd-Steinberg errors.
+ */
+
+LOCAL(void)
+alloc_fs_workspace (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ size_t arraysize;
+ int i;
+
+ arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR));
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ cquantize->fserrors[i] = (FSERRPTR)
+ (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);
+ }
+}
+
+
+/*
+ * Initialize for one-pass color quantization.
+ */
+
+METHODDEF(void)
+start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ size_t arraysize;
+ int i;
+
+ /* Install my colormap. */
+ cinfo->colormap = cquantize->sv_colormap;
+ cinfo->actual_number_of_colors = cquantize->sv_actual;
+
+ /* Initialize for desired dithering mode. */
+ switch (cinfo->dither_mode) {
+ case JDITHER_NONE:
+ if (cinfo->out_color_components == 3)
+ cquantize->pub.color_quantize = color_quantize3;
+ else
+ cquantize->pub.color_quantize = color_quantize;
+ break;
+ case JDITHER_ORDERED:
+ if (cinfo->out_color_components == 3)
+ cquantize->pub.color_quantize = quantize3_ord_dither;
+ else
+ cquantize->pub.color_quantize = quantize_ord_dither;
+ cquantize->row_index = 0; /* initialize state for ordered dither */
+ /* If user changed to ordered dither from another mode,
+ * we must recreate the color index table with padding.
+ * This will cost extra space, but probably isn't very likely.
+ */
+ if (! cquantize->is_padded)
+ create_colorindex(cinfo);
+ /* Create ordered-dither tables if we didn't already. */
+ if (cquantize->odither[0] == NULL)
+ create_odither_tables(cinfo);
+ break;
+ case JDITHER_FS:
+ cquantize->pub.color_quantize = quantize_fs_dither;
+ cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */
+ /* Allocate Floyd-Steinberg workspace if didn't already. */
+ if (cquantize->fserrors[0] == NULL)
+ alloc_fs_workspace(cinfo);
+ /* Initialize the propagated errors to zero. */
+ arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR));
+ for (i = 0; i < cinfo->out_color_components; i++)
+ jzero_far((void FAR *) cquantize->fserrors[i], arraysize);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+}
+
+
+/*
+ * Finish up at the end of the pass.
+ */
+
+METHODDEF(void)
+finish_pass_1_quant (j_decompress_ptr cinfo)
+{
+ /* no work in 1-pass case */
+}
+
+
+/*
+ * Switch to a new external colormap between output passes.
+ * Shouldn't get to this module!
+ */
+
+METHODDEF(void)
+new_color_map_1_quant (j_decompress_ptr cinfo)
+{
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+}
+
+
+/*
+ * Module initialization routine for 1-pass color quantization.
+ */
+
+GLOBAL(void)
+jinit_1pass_quantizer (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize;
+
+ cquantize = (my_cquantize_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_cquantizer));
+ cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize;
+ cquantize->pub.start_pass = start_pass_1_quant;
+ cquantize->pub.finish_pass = finish_pass_1_quant;
+ cquantize->pub.new_color_map = new_color_map_1_quant;
+ cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */
+ cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */
+
+ /* Make sure my internal arrays won't overflow */
+ if (cinfo->out_color_components > MAX_Q_COMPS)
+ ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS);
+ /* Make sure colormap indexes can be represented by JSAMPLEs */
+ if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1))
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1);
+
+ /* Create the colormap and color index table. */
+ create_colormap(cinfo);
+ create_colorindex(cinfo);
+
+ /* Allocate Floyd-Steinberg workspace now if requested.
+ * We do this now since it is FAR storage and may affect the memory
+ * manager's space calculations. If the user changes to FS dither
+ * mode in a later pass, we will allocate the space then, and will
+ * possibly overrun the max_memory_to_use setting.
+ */
+ if (cinfo->dither_mode == JDITHER_FS)
+ alloc_fs_workspace(cinfo);
+}
+
+#endif /* QUANT_1PASS_SUPPORTED */
diff --git a/external/jpeg-8c/jquant2.c b/external/jpeg-8c/jquant2.c
new file mode 100644
index 0000000..af601e3
--- /dev/null
+++ b/external/jpeg-8c/jquant2.c
@@ -0,0 +1,1310 @@
+/*
+ * jquant2.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains 2-pass color quantization (color mapping) routines.
+ * These routines provide selection of a custom color map for an image,
+ * followed by mapping of the image to that color map, with optional
+ * Floyd-Steinberg dithering.
+ * It is also possible to use just the second pass to map to an arbitrary
+ * externally-given color map.
+ *
+ * Note: ordered dithering is not supported, since there isn't any fast
+ * way to compute intercolor distances; it's unclear that ordered dither's
+ * fundamental assumptions even hold with an irregularly spaced color map.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+
+/*
+ * This module implements the well-known Heckbert paradigm for color
+ * quantization. Most of the ideas used here can be traced back to
+ * Heckbert's seminal paper
+ * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display",
+ * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304.
+ *
+ * In the first pass over the image, we accumulate a histogram showing the
+ * usage count of each possible color. To keep the histogram to a reasonable
+ * size, we reduce the precision of the input; typical practice is to retain
+ * 5 or 6 bits per color, so that 8 or 4 different input values are counted
+ * in the same histogram cell.
+ *
+ * Next, the color-selection step begins with a box representing the whole
+ * color space, and repeatedly splits the "largest" remaining box until we
+ * have as many boxes as desired colors. Then the mean color in each
+ * remaining box becomes one of the possible output colors.
+ *
+ * The second pass over the image maps each input pixel to the closest output
+ * color (optionally after applying a Floyd-Steinberg dithering correction).
+ * This mapping is logically trivial, but making it go fast enough requires
+ * considerable care.
+ *
+ * Heckbert-style quantizers vary a good deal in their policies for choosing
+ * the "largest" box and deciding where to cut it. The particular policies
+ * used here have proved out well in experimental comparisons, but better ones
+ * may yet be found.
+ *
+ * In earlier versions of the IJG code, this module quantized in YCbCr color
+ * space, processing the raw upsampled data without a color conversion step.
+ * This allowed the color conversion math to be done only once per colormap
+ * entry, not once per pixel. However, that optimization precluded other
+ * useful optimizations (such as merging color conversion with upsampling)
+ * and it also interfered with desired capabilities such as quantizing to an
+ * externally-supplied colormap. We have therefore abandoned that approach.
+ * The present code works in the post-conversion color space, typically RGB.
+ *
+ * To improve the visual quality of the results, we actually work in scaled
+ * RGB space, giving G distances more weight than R, and R in turn more than
+ * B. To do everything in integer math, we must use integer scale factors.
+ * The 2/3/1 scale factors used here correspond loosely to the relative
+ * weights of the colors in the NTSC grayscale equation.
+ * If you want to use this code to quantize a non-RGB color space, you'll
+ * probably need to change these scale factors.
+ */
+
+#define R_SCALE 2 /* scale R distances by this much */
+#define G_SCALE 3 /* scale G distances by this much */
+#define B_SCALE 1 /* and B by this much */
+
+/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined
+ * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B
+ * and B,G,R orders. If you define some other weird order in jmorecfg.h,
+ * you'll get compile errors until you extend this logic. In that case
+ * you'll probably want to tweak the histogram sizes too.
+ */
+
+#if RGB_RED == 0
+#define C0_SCALE R_SCALE
+#endif
+#if RGB_BLUE == 0
+#define C0_SCALE B_SCALE
+#endif
+#if RGB_GREEN == 1
+#define C1_SCALE G_SCALE
+#endif
+#if RGB_RED == 2
+#define C2_SCALE R_SCALE
+#endif
+#if RGB_BLUE == 2
+#define C2_SCALE B_SCALE
+#endif
+
+
+/*
+ * First we have the histogram data structure and routines for creating it.
+ *
+ * The number of bits of precision can be adjusted by changing these symbols.
+ * We recommend keeping 6 bits for G and 5 each for R and B.
+ * If you have plenty of memory and cycles, 6 bits all around gives marginally
+ * better results; if you are short of memory, 5 bits all around will save
+ * some space but degrade the results.
+ * To maintain a fully accurate histogram, we'd need to allocate a "long"
+ * (preferably unsigned long) for each cell. In practice this is overkill;
+ * we can get by with 16 bits per cell. Few of the cell counts will overflow,
+ * and clamping those that do overflow to the maximum value will give close-
+ * enough results. This reduces the recommended histogram size from 256Kb
+ * to 128Kb, which is a useful savings on PC-class machines.
+ * (In the second pass the histogram space is re-used for pixel mapping data;
+ * in that capacity, each cell must be able to store zero to the number of
+ * desired colors. 16 bits/cell is plenty for that too.)
+ * Since the JPEG code is intended to run in small memory model on 80x86
+ * machines, we can't just allocate the histogram in one chunk. Instead
+ * of a true 3-D array, we use a row of pointers to 2-D arrays. Each
+ * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and
+ * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that
+ * on 80x86 machines, the pointer row is in near memory but the actual
+ * arrays are in far memory (same arrangement as we use for image arrays).
+ */
+
+#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */
+
+/* These will do the right thing for either R,G,B or B,G,R color order,
+ * but you may not like the results for other color orders.
+ */
+#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */
+#define HIST_C1_BITS 6 /* bits of precision in G histogram */
+#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */
+
+/* Number of elements along histogram axes. */
+#define HIST_C0_ELEMS (1<<HIST_C0_BITS)
+#define HIST_C1_ELEMS (1<<HIST_C1_BITS)
+#define HIST_C2_ELEMS (1<<HIST_C2_BITS)
+
+/* These are the amounts to shift an input value to get a histogram index. */
+#define C0_SHIFT (BITS_IN_JSAMPLE-HIST_C0_BITS)
+#define C1_SHIFT (BITS_IN_JSAMPLE-HIST_C1_BITS)
+#define C2_SHIFT (BITS_IN_JSAMPLE-HIST_C2_BITS)
+
+
+typedef UINT16 histcell; /* histogram cell; prefer an unsigned type */
+
+typedef histcell FAR * histptr; /* for pointers to histogram cells */
+
+typedef histcell hist1d[HIST_C2_ELEMS]; /* typedefs for the array */
+typedef hist1d FAR * hist2d; /* type for the 2nd-level pointers */
+typedef hist2d * hist3d; /* type for top-level pointer */
+
+
+/* Declarations for Floyd-Steinberg dithering.
+ *
+ * Errors are accumulated into the array fserrors[], at a resolution of
+ * 1/16th of a pixel count. The error at a given pixel is propagated
+ * to its not-yet-processed neighbors using the standard F-S fractions,
+ * ... (here) 7/16
+ * 3/16 5/16 1/16
+ * We work left-to-right on even rows, right-to-left on odd rows.
+ *
+ * We can get away with a single array (holding one row's worth of errors)
+ * by using it to store the current row's errors at pixel columns not yet
+ * processed, but the next row's errors at columns already processed. We
+ * need only a few extra variables to hold the errors immediately around the
+ * current column. (If we are lucky, those variables are in registers, but
+ * even if not, they're probably cheaper to access than array elements are.)
+ *
+ * The fserrors[] array has (#columns + 2) entries; the extra entry at
+ * each end saves us from special-casing the first and last pixels.
+ * Each entry is three values long, one value for each color component.
+ *
+ * Note: on a wide image, we might not have enough room in a PC's near data
+ * segment to hold the error array; so it is allocated with alloc_large.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+typedef INT16 FSERROR; /* 16 bits should be enough */
+typedef int LOCFSERROR; /* use 'int' for calculation temps */
+#else
+typedef INT32 FSERROR; /* may need more than 16 bits */
+typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */
+#endif
+
+typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_color_quantizer pub; /* public fields */
+
+ /* Space for the eventually created colormap is stashed here */
+ JSAMPARRAY sv_colormap; /* colormap allocated at init time */
+ int desired; /* desired # of colors = size of colormap */
+
+ /* Variables for accumulating image statistics */
+ hist3d histogram; /* pointer to the histogram */
+
+ boolean needs_zeroed; /* TRUE if next pass must zero histogram */
+
+ /* Variables for Floyd-Steinberg dithering */
+ FSERRPTR fserrors; /* accumulated errors */
+ boolean on_odd_row; /* flag to remember which row we are on */
+ int * error_limiter; /* table for clamping the applied error */
+} my_cquantizer;
+
+typedef my_cquantizer * my_cquantize_ptr;
+
+
+/*
+ * Prescan some rows of pixels.
+ * In this module the prescan simply updates the histogram, which has been
+ * initialized to zeroes by start_pass.
+ * An output_buf parameter is required by the method signature, but no data
+ * is actually output (in fact the buffer controller is probably passing a
+ * NULL pointer).
+ */
+
+METHODDEF(void)
+prescan_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register JSAMPROW ptr;
+ register histptr histp;
+ register hist3d histogram = cquantize->histogram;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ ptr = input_buf[row];
+ for (col = width; col > 0; col--) {
+ /* get pixel value and index into the histogram */
+ histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT]
+ [GETJSAMPLE(ptr[1]) >> C1_SHIFT]
+ [GETJSAMPLE(ptr[2]) >> C2_SHIFT];
+ /* increment, check for overflow and undo increment if so. */
+ if (++(*histp) <= 0)
+ (*histp)--;
+ ptr += 3;
+ }
+ }
+}
+
+
+/*
+ * Next we have the really interesting routines: selection of a colormap
+ * given the completed histogram.
+ * These routines work with a list of "boxes", each representing a rectangular
+ * subset of the input color space (to histogram precision).
+ */
+
+typedef struct {
+ /* The bounds of the box (inclusive); expressed as histogram indexes */
+ int c0min, c0max;
+ int c1min, c1max;
+ int c2min, c2max;
+ /* The volume (actually 2-norm) of the box */
+ INT32 volume;
+ /* The number of nonzero histogram cells within this box */
+ long colorcount;
+} box;
+
+typedef box * boxptr;
+
+
+LOCAL(boxptr)
+find_biggest_color_pop (boxptr boxlist, int numboxes)
+/* Find the splittable box with the largest color population */
+/* Returns NULL if no splittable boxes remain */
+{
+ register boxptr boxp;
+ register int i;
+ register long maxc = 0;
+ boxptr which = NULL;
+
+ for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
+ if (boxp->colorcount > maxc && boxp->volume > 0) {
+ which = boxp;
+ maxc = boxp->colorcount;
+ }
+ }
+ return which;
+}
+
+
+LOCAL(boxptr)
+find_biggest_volume (boxptr boxlist, int numboxes)
+/* Find the splittable box with the largest (scaled) volume */
+/* Returns NULL if no splittable boxes remain */
+{
+ register boxptr boxp;
+ register int i;
+ register INT32 maxv = 0;
+ boxptr which = NULL;
+
+ for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
+ if (boxp->volume > maxv) {
+ which = boxp;
+ maxv = boxp->volume;
+ }
+ }
+ return which;
+}
+
+
+LOCAL(void)
+update_box (j_decompress_ptr cinfo, boxptr boxp)
+/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
+/* and recompute its volume and population */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ histptr histp;
+ int c0,c1,c2;
+ int c0min,c0max,c1min,c1max,c2min,c2max;
+ INT32 dist0,dist1,dist2;
+ long ccount;
+
+ c0min = boxp->c0min; c0max = boxp->c0max;
+ c1min = boxp->c1min; c1max = boxp->c1max;
+ c2min = boxp->c2min; c2max = boxp->c2max;
+
+ if (c0max > c0min)
+ for (c0 = c0min; c0 <= c0max; c0++)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c0min = c0min = c0;
+ goto have_c0min;
+ }
+ }
+ have_c0min:
+ if (c0max > c0min)
+ for (c0 = c0max; c0 >= c0min; c0--)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c0max = c0max = c0;
+ goto have_c0max;
+ }
+ }
+ have_c0max:
+ if (c1max > c1min)
+ for (c1 = c1min; c1 <= c1max; c1++)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c1min = c1min = c1;
+ goto have_c1min;
+ }
+ }
+ have_c1min:
+ if (c1max > c1min)
+ for (c1 = c1max; c1 >= c1min; c1--)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c1max = c1max = c1;
+ goto have_c1max;
+ }
+ }
+ have_c1max:
+ if (c2max > c2min)
+ for (c2 = c2min; c2 <= c2max; c2++)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1min][c2];
+ for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)
+ if (*histp != 0) {
+ boxp->c2min = c2min = c2;
+ goto have_c2min;
+ }
+ }
+ have_c2min:
+ if (c2max > c2min)
+ for (c2 = c2max; c2 >= c2min; c2--)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1min][c2];
+ for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)
+ if (*histp != 0) {
+ boxp->c2max = c2max = c2;
+ goto have_c2max;
+ }
+ }
+ have_c2max:
+
+ /* Update box volume.
+ * We use 2-norm rather than real volume here; this biases the method
+ * against making long narrow boxes, and it has the side benefit that
+ * a box is splittable iff norm > 0.
+ * Since the differences are expressed in histogram-cell units,
+ * we have to shift back to JSAMPLE units to get consistent distances;
+ * after which, we scale according to the selected distance scale factors.
+ */
+ dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE;
+ dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE;
+ dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE;
+ boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2;
+
+ /* Now scan remaining volume of box and compute population */
+ ccount = 0;
+ for (c0 = c0min; c0 <= c0max; c0++)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++, histp++)
+ if (*histp != 0) {
+ ccount++;
+ }
+ }
+ boxp->colorcount = ccount;
+}
+
+
+LOCAL(int)
+median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes,
+ int desired_colors)
+/* Repeatedly select and split the largest box until we have enough boxes */
+{
+ int n,lb;
+ int c0,c1,c2,cmax;
+ register boxptr b1,b2;
+
+ while (numboxes < desired_colors) {
+ /* Select box to split.
+ * Current algorithm: by population for first half, then by volume.
+ */
+ if (numboxes*2 <= desired_colors) {
+ b1 = find_biggest_color_pop(boxlist, numboxes);
+ } else {
+ b1 = find_biggest_volume(boxlist, numboxes);
+ }
+ if (b1 == NULL) /* no splittable boxes left! */
+ break;
+ b2 = &boxlist[numboxes]; /* where new box will go */
+ /* Copy the color bounds to the new box. */
+ b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max;
+ b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min;
+ /* Choose which axis to split the box on.
+ * Current algorithm: longest scaled axis.
+ * See notes in update_box about scaling distances.
+ */
+ c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE;
+ c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE;
+ c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE;
+ /* We want to break any ties in favor of green, then red, blue last.
+ * This code does the right thing for R,G,B or B,G,R color orders only.
+ */
+#if RGB_RED == 0
+ cmax = c1; n = 1;
+ if (c0 > cmax) { cmax = c0; n = 0; }
+ if (c2 > cmax) { n = 2; }
+#else
+ cmax = c1; n = 1;
+ if (c2 > cmax) { cmax = c2; n = 2; }
+ if (c0 > cmax) { n = 0; }
+#endif
+ /* Choose split point along selected axis, and update box bounds.
+ * Current algorithm: split at halfway point.
+ * (Since the box has been shrunk to minimum volume,
+ * any split will produce two nonempty subboxes.)
+ * Note that lb value is max for lower box, so must be < old max.
+ */
+ switch (n) {
+ case 0:
+ lb = (b1->c0max + b1->c0min) / 2;
+ b1->c0max = lb;
+ b2->c0min = lb+1;
+ break;
+ case 1:
+ lb = (b1->c1max + b1->c1min) / 2;
+ b1->c1max = lb;
+ b2->c1min = lb+1;
+ break;
+ case 2:
+ lb = (b1->c2max + b1->c2min) / 2;
+ b1->c2max = lb;
+ b2->c2min = lb+1;
+ break;
+ }
+ /* Update stats for boxes */
+ update_box(cinfo, b1);
+ update_box(cinfo, b2);
+ numboxes++;
+ }
+ return numboxes;
+}
+
+
+LOCAL(void)
+compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor)
+/* Compute representative color for a box, put it in colormap[icolor] */
+{
+ /* Current algorithm: mean weighted by pixels (not colors) */
+ /* Note it is important to get the rounding correct! */
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ histptr histp;
+ int c0,c1,c2;
+ int c0min,c0max,c1min,c1max,c2min,c2max;
+ long count;
+ long total = 0;
+ long c0total = 0;
+ long c1total = 0;
+ long c2total = 0;
+
+ c0min = boxp->c0min; c0max = boxp->c0max;
+ c1min = boxp->c1min; c1max = boxp->c1max;
+ c2min = boxp->c2min; c2max = boxp->c2max;
+
+ for (c0 = c0min; c0 <= c0max; c0++)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++) {
+ if ((count = *histp++) != 0) {
+ total += count;
+ c0total += ((c0 << C0_SHIFT) + ((1<<C0_SHIFT)>>1)) * count;
+ c1total += ((c1 << C1_SHIFT) + ((1<<C1_SHIFT)>>1)) * count;
+ c2total += ((c2 << C2_SHIFT) + ((1<<C2_SHIFT)>>1)) * count;
+ }
+ }
+ }
+
+ cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total);
+ cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total);
+ cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total);
+}
+
+
+LOCAL(void)
+select_colors (j_decompress_ptr cinfo, int desired_colors)
+/* Master routine for color selection */
+{
+ boxptr boxlist;
+ int numboxes;
+ int i;
+
+ /* Allocate workspace for box list */
+ boxlist = (boxptr) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box));
+ /* Initialize one box containing whole space */
+ numboxes = 1;
+ boxlist[0].c0min = 0;
+ boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT;
+ boxlist[0].c1min = 0;
+ boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT;
+ boxlist[0].c2min = 0;
+ boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT;
+ /* Shrink it to actually-used volume and set its statistics */
+ update_box(cinfo, & boxlist[0]);
+ /* Perform median-cut to produce final box list */
+ numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors);
+ /* Compute the representative color for each box, fill colormap */
+ for (i = 0; i < numboxes; i++)
+ compute_color(cinfo, & boxlist[i], i);
+ cinfo->actual_number_of_colors = numboxes;
+ TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes);
+}
+
+
+/*
+ * These routines are concerned with the time-critical task of mapping input
+ * colors to the nearest color in the selected colormap.
+ *
+ * We re-use the histogram space as an "inverse color map", essentially a
+ * cache for the results of nearest-color searches. All colors within a
+ * histogram cell will be mapped to the same colormap entry, namely the one
+ * closest to the cell's center. This may not be quite the closest entry to
+ * the actual input color, but it's almost as good. A zero in the cache
+ * indicates we haven't found the nearest color for that cell yet; the array
+ * is cleared to zeroes before starting the mapping pass. When we find the
+ * nearest color for a cell, its colormap index plus one is recorded in the
+ * cache for future use. The pass2 scanning routines call fill_inverse_cmap
+ * when they need to use an unfilled entry in the cache.
+ *
+ * Our method of efficiently finding nearest colors is based on the "locally
+ * sorted search" idea described by Heckbert and on the incremental distance
+ * calculation described by Spencer W. Thomas in chapter III.1 of Graphics
+ * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that
+ * the distances from a given colormap entry to each cell of the histogram can
+ * be computed quickly using an incremental method: the differences between
+ * distances to adjacent cells themselves differ by a constant. This allows a
+ * fairly fast implementation of the "brute force" approach of computing the
+ * distance from every colormap entry to every histogram cell. Unfortunately,
+ * it needs a work array to hold the best-distance-so-far for each histogram
+ * cell (because the inner loop has to be over cells, not colormap entries).
+ * The work array elements have to be INT32s, so the work array would need
+ * 256Kb at our recommended precision. This is not feasible in DOS machines.
+ *
+ * To get around these problems, we apply Thomas' method to compute the
+ * nearest colors for only the cells within a small subbox of the histogram.
+ * The work array need be only as big as the subbox, so the memory usage
+ * problem is solved. Furthermore, we need not fill subboxes that are never
+ * referenced in pass2; many images use only part of the color gamut, so a
+ * fair amount of work is saved. An additional advantage of this
+ * approach is that we can apply Heckbert's locality criterion to quickly
+ * eliminate colormap entries that are far away from the subbox; typically
+ * three-fourths of the colormap entries are rejected by Heckbert's criterion,
+ * and we need not compute their distances to individual cells in the subbox.
+ * The speed of this approach is heavily influenced by the subbox size: too
+ * small means too much overhead, too big loses because Heckbert's criterion
+ * can't eliminate as many colormap entries. Empirically the best subbox
+ * size seems to be about 1/512th of the histogram (1/8th in each direction).
+ *
+ * Thomas' article also describes a refined method which is asymptotically
+ * faster than the brute-force method, but it is also far more complex and
+ * cannot efficiently be applied to small subboxes. It is therefore not
+ * useful for programs intended to be portable to DOS machines. On machines
+ * with plenty of memory, filling the whole histogram in one shot with Thomas'
+ * refined method might be faster than the present code --- but then again,
+ * it might not be any faster, and it's certainly more complicated.
+ */
+
+
+/* log2(histogram cells in update box) for each axis; this can be adjusted */
+#define BOX_C0_LOG (HIST_C0_BITS-3)
+#define BOX_C1_LOG (HIST_C1_BITS-3)
+#define BOX_C2_LOG (HIST_C2_BITS-3)
+
+#define BOX_C0_ELEMS (1<<BOX_C0_LOG) /* # of hist cells in update box */
+#define BOX_C1_ELEMS (1<<BOX_C1_LOG)
+#define BOX_C2_ELEMS (1<<BOX_C2_LOG)
+
+#define BOX_C0_SHIFT (C0_SHIFT + BOX_C0_LOG)
+#define BOX_C1_SHIFT (C1_SHIFT + BOX_C1_LOG)
+#define BOX_C2_SHIFT (C2_SHIFT + BOX_C2_LOG)
+
+
+/*
+ * The next three routines implement inverse colormap filling. They could
+ * all be folded into one big routine, but splitting them up this way saves
+ * some stack space (the mindist[] and bestdist[] arrays need not coexist)
+ * and may allow some compilers to produce better code by registerizing more
+ * inner-loop variables.
+ */
+
+LOCAL(int)
+find_nearby_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
+ JSAMPLE colorlist[])
+/* Locate the colormap entries close enough to an update box to be candidates
+ * for the nearest entry to some cell(s) in the update box. The update box
+ * is specified by the center coordinates of its first cell. The number of
+ * candidate colormap entries is returned, and their colormap indexes are
+ * placed in colorlist[].
+ * This routine uses Heckbert's "locally sorted search" criterion to select
+ * the colors that need further consideration.
+ */
+{
+ int numcolors = cinfo->actual_number_of_colors;
+ int maxc0, maxc1, maxc2;
+ int centerc0, centerc1, centerc2;
+ int i, x, ncolors;
+ INT32 minmaxdist, min_dist, max_dist, tdist;
+ INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */
+
+ /* Compute true coordinates of update box's upper corner and center.
+ * Actually we compute the coordinates of the center of the upper-corner
+ * histogram cell, which are the upper bounds of the volume we care about.
+ * Note that since ">>" rounds down, the "center" values may be closer to
+ * min than to max; hence comparisons to them must be "<=", not "<".
+ */
+ maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT));
+ centerc0 = (minc0 + maxc0) >> 1;
+ maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT));
+ centerc1 = (minc1 + maxc1) >> 1;
+ maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT));
+ centerc2 = (minc2 + maxc2) >> 1;
+
+ /* For each color in colormap, find:
+ * 1. its minimum squared-distance to any point in the update box
+ * (zero if color is within update box);
+ * 2. its maximum squared-distance to any point in the update box.
+ * Both of these can be found by considering only the corners of the box.
+ * We save the minimum distance for each color in mindist[];
+ * only the smallest maximum distance is of interest.
+ */
+ minmaxdist = 0x7FFFFFFFL;
+
+ for (i = 0; i < numcolors; i++) {
+ /* We compute the squared-c0-distance term, then add in the other two. */
+ x = GETJSAMPLE(cinfo->colormap[0][i]);
+ if (x < minc0) {
+ tdist = (x - minc0) * C0_SCALE;
+ min_dist = tdist*tdist;
+ tdist = (x - maxc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ } else if (x > maxc0) {
+ tdist = (x - maxc0) * C0_SCALE;
+ min_dist = tdist*tdist;
+ tdist = (x - minc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ } else {
+ /* within cell range so no contribution to min_dist */
+ min_dist = 0;
+ if (x <= centerc0) {
+ tdist = (x - maxc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ } else {
+ tdist = (x - minc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ }
+ }
+
+ x = GETJSAMPLE(cinfo->colormap[1][i]);
+ if (x < minc1) {
+ tdist = (x - minc1) * C1_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - maxc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ } else if (x > maxc1) {
+ tdist = (x - maxc1) * C1_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - minc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ /* within cell range so no contribution to min_dist */
+ if (x <= centerc1) {
+ tdist = (x - maxc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ tdist = (x - minc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ }
+ }
+
+ x = GETJSAMPLE(cinfo->colormap[2][i]);
+ if (x < minc2) {
+ tdist = (x - minc2) * C2_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - maxc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ } else if (x > maxc2) {
+ tdist = (x - maxc2) * C2_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - minc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ /* within cell range so no contribution to min_dist */
+ if (x <= centerc2) {
+ tdist = (x - maxc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ tdist = (x - minc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ }
+ }
+
+ mindist[i] = min_dist; /* save away the results */
+ if (max_dist < minmaxdist)
+ minmaxdist = max_dist;
+ }
+
+ /* Now we know that no cell in the update box is more than minmaxdist
+ * away from some colormap entry. Therefore, only colors that are
+ * within minmaxdist of some part of the box need be considered.
+ */
+ ncolors = 0;
+ for (i = 0; i < numcolors; i++) {
+ if (mindist[i] <= minmaxdist)
+ colorlist[ncolors++] = (JSAMPLE) i;
+ }
+ return ncolors;
+}
+
+
+LOCAL(void)
+find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
+ int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[])
+/* Find the closest colormap entry for each cell in the update box,
+ * given the list of candidate colors prepared by find_nearby_colors.
+ * Return the indexes of the closest entries in the bestcolor[] array.
+ * This routine uses Thomas' incremental distance calculation method to
+ * find the distance from a colormap entry to successive cells in the box.
+ */
+{
+ int ic0, ic1, ic2;
+ int i, icolor;
+ register INT32 * bptr; /* pointer into bestdist[] array */
+ JSAMPLE * cptr; /* pointer into bestcolor[] array */
+ INT32 dist0, dist1; /* initial distance values */
+ register INT32 dist2; /* current distance in inner loop */
+ INT32 xx0, xx1; /* distance increments */
+ register INT32 xx2;
+ INT32 inc0, inc1, inc2; /* initial values for increments */
+ /* This array holds the distance to the nearest-so-far color for each cell */
+ INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+
+ /* Initialize best-distance for each cell of the update box */
+ bptr = bestdist;
+ for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--)
+ *bptr++ = 0x7FFFFFFFL;
+
+ /* For each color selected by find_nearby_colors,
+ * compute its distance to the center of each cell in the box.
+ * If that's less than best-so-far, update best distance and color number.
+ */
+
+ /* Nominal steps between cell centers ("x" in Thomas article) */
+#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE)
+#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE)
+#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE)
+
+ for (i = 0; i < numcolors; i++) {
+ icolor = GETJSAMPLE(colorlist[i]);
+ /* Compute (square of) distance from minc0/c1/c2 to this color */
+ inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE;
+ dist0 = inc0*inc0;
+ inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE;
+ dist0 += inc1*inc1;
+ inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE;
+ dist0 += inc2*inc2;
+ /* Form the initial difference increments */
+ inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0;
+ inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1;
+ inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2;
+ /* Now loop over all cells in box, updating distance per Thomas method */
+ bptr = bestdist;
+ cptr = bestcolor;
+ xx0 = inc0;
+ for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) {
+ dist1 = dist0;
+ xx1 = inc1;
+ for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) {
+ dist2 = dist1;
+ xx2 = inc2;
+ for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) {
+ if (dist2 < *bptr) {
+ *bptr = dist2;
+ *cptr = (JSAMPLE) icolor;
+ }
+ dist2 += xx2;
+ xx2 += 2 * STEP_C2 * STEP_C2;
+ bptr++;
+ cptr++;
+ }
+ dist1 += xx1;
+ xx1 += 2 * STEP_C1 * STEP_C1;
+ }
+ dist0 += xx0;
+ xx0 += 2 * STEP_C0 * STEP_C0;
+ }
+ }
+}
+
+
+LOCAL(void)
+fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2)
+/* Fill the inverse-colormap entries in the update box that contains */
+/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */
+/* we can fill as many others as we wish.) */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ int minc0, minc1, minc2; /* lower left corner of update box */
+ int ic0, ic1, ic2;
+ register JSAMPLE * cptr; /* pointer into bestcolor[] array */
+ register histptr cachep; /* pointer into main cache array */
+ /* This array lists the candidate colormap indexes. */
+ JSAMPLE colorlist[MAXNUMCOLORS];
+ int numcolors; /* number of candidate colors */
+ /* This array holds the actually closest colormap index for each cell. */
+ JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+
+ /* Convert cell coordinates to update box ID */
+ c0 >>= BOX_C0_LOG;
+ c1 >>= BOX_C1_LOG;
+ c2 >>= BOX_C2_LOG;
+
+ /* Compute true coordinates of update box's origin corner.
+ * Actually we compute the coordinates of the center of the corner
+ * histogram cell, which are the lower bounds of the volume we care about.
+ */
+ minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1);
+ minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1);
+ minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1);
+
+ /* Determine which colormap entries are close enough to be candidates
+ * for the nearest entry to some cell in the update box.
+ */
+ numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist);
+
+ /* Determine the actually nearest colors. */
+ find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist,
+ bestcolor);
+
+ /* Save the best color numbers (plus 1) in the main cache array */
+ c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */
+ c1 <<= BOX_C1_LOG;
+ c2 <<= BOX_C2_LOG;
+ cptr = bestcolor;
+ for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) {
+ for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) {
+ cachep = & histogram[c0+ic0][c1+ic1][c2];
+ for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) {
+ *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1);
+ }
+ }
+ }
+}
+
+
+/*
+ * Map some rows of pixels to the output colormapped representation.
+ */
+
+METHODDEF(void)
+pass2_no_dither (j_decompress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
+/* This version performs no dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ register JSAMPROW inptr, outptr;
+ register histptr cachep;
+ register int c0, c1, c2;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ inptr = input_buf[row];
+ outptr = output_buf[row];
+ for (col = width; col > 0; col--) {
+ /* get pixel value and index into the cache */
+ c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT;
+ c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT;
+ c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT;
+ cachep = & histogram[c0][c1][c2];
+ /* If we have not seen this color before, find nearest colormap entry */
+ /* and update the cache */
+ if (*cachep == 0)
+ fill_inverse_cmap(cinfo, c0,c1,c2);
+ /* Now emit the colormap index for this cell */
+ *outptr++ = (JSAMPLE) (*cachep - 1);
+ }
+ }
+}
+
+
+METHODDEF(void)
+pass2_fs_dither (j_decompress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
+/* This version performs Floyd-Steinberg dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */
+ LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */
+ LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */
+ register FSERRPTR errorptr; /* => fserrors[] at column before current */
+ JSAMPROW inptr; /* => current input pixel */
+ JSAMPROW outptr; /* => current output pixel */
+ histptr cachep;
+ int dir; /* +1 or -1 depending on direction */
+ int dir3; /* 3*dir, for advancing inptr & errorptr */
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+ JSAMPLE *range_limit = cinfo->sample_range_limit;
+ int *error_limit = cquantize->error_limiter;
+ JSAMPROW colormap0 = cinfo->colormap[0];
+ JSAMPROW colormap1 = cinfo->colormap[1];
+ JSAMPROW colormap2 = cinfo->colormap[2];
+ SHIFT_TEMPS
+
+ for (row = 0; row < num_rows; row++) {
+ inptr = input_buf[row];
+ outptr = output_buf[row];
+ if (cquantize->on_odd_row) {
+ /* work right to left in this row */
+ inptr += (width-1) * 3; /* so point to rightmost pixel */
+ outptr += width-1;
+ dir = -1;
+ dir3 = -3;
+ errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */
+ cquantize->on_odd_row = FALSE; /* flip for next time */
+ } else {
+ /* work left to right in this row */
+ dir = 1;
+ dir3 = 3;
+ errorptr = cquantize->fserrors; /* => entry before first real column */
+ cquantize->on_odd_row = TRUE; /* flip for next time */
+ }
+ /* Preset error values: no error propagated to first pixel from left */
+ cur0 = cur1 = cur2 = 0;
+ /* and no error propagated to row below yet */
+ belowerr0 = belowerr1 = belowerr2 = 0;
+ bpreverr0 = bpreverr1 = bpreverr2 = 0;
+
+ for (col = width; col > 0; col--) {
+ /* curN holds the error propagated from the previous pixel on the
+ * current line. Add the error propagated from the previous line
+ * to form the complete error correction term for this pixel, and
+ * round the error term (which is expressed * 16) to an integer.
+ * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
+ * for either sign of the error value.
+ * Note: errorptr points to *previous* column's array entry.
+ */
+ cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4);
+ cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4);
+ cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4);
+ /* Limit the error using transfer function set by init_error_limit.
+ * See comments with init_error_limit for rationale.
+ */
+ cur0 = error_limit[cur0];
+ cur1 = error_limit[cur1];
+ cur2 = error_limit[cur2];
+ /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+ * The maximum error is +- MAXJSAMPLE (or less with error limiting);
+ * this sets the required size of the range_limit array.
+ */
+ cur0 += GETJSAMPLE(inptr[0]);
+ cur1 += GETJSAMPLE(inptr[1]);
+ cur2 += GETJSAMPLE(inptr[2]);
+ cur0 = GETJSAMPLE(range_limit[cur0]);
+ cur1 = GETJSAMPLE(range_limit[cur1]);
+ cur2 = GETJSAMPLE(range_limit[cur2]);
+ /* Index into the cache with adjusted pixel value */
+ cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT];
+ /* If we have not seen this color before, find nearest colormap */
+ /* entry and update the cache */
+ if (*cachep == 0)
+ fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT);
+ /* Now emit the colormap index for this cell */
+ { register int pixcode = *cachep - 1;
+ *outptr = (JSAMPLE) pixcode;
+ /* Compute representation error for this pixel */
+ cur0 -= GETJSAMPLE(colormap0[pixcode]);
+ cur1 -= GETJSAMPLE(colormap1[pixcode]);
+ cur2 -= GETJSAMPLE(colormap2[pixcode]);
+ }
+ /* Compute error fractions to be propagated to adjacent pixels.
+ * Add these into the running sums, and simultaneously shift the
+ * next-line error sums left by 1 column.
+ */
+ { register LOCFSERROR bnexterr, delta;
+
+ bnexterr = cur0; /* Process component 0 */
+ delta = cur0 * 2;
+ cur0 += delta; /* form error * 3 */
+ errorptr[0] = (FSERROR) (bpreverr0 + cur0);
+ cur0 += delta; /* form error * 5 */
+ bpreverr0 = belowerr0 + cur0;
+ belowerr0 = bnexterr;
+ cur0 += delta; /* form error * 7 */
+ bnexterr = cur1; /* Process component 1 */
+ delta = cur1 * 2;
+ cur1 += delta; /* form error * 3 */
+ errorptr[1] = (FSERROR) (bpreverr1 + cur1);
+ cur1 += delta; /* form error * 5 */
+ bpreverr1 = belowerr1 + cur1;
+ belowerr1 = bnexterr;
+ cur1 += delta; /* form error * 7 */
+ bnexterr = cur2; /* Process component 2 */
+ delta = cur2 * 2;
+ cur2 += delta; /* form error * 3 */
+ errorptr[2] = (FSERROR) (bpreverr2 + cur2);
+ cur2 += delta; /* form error * 5 */
+ bpreverr2 = belowerr2 + cur2;
+ belowerr2 = bnexterr;
+ cur2 += delta; /* form error * 7 */
+ }
+ /* At this point curN contains the 7/16 error value to be propagated
+ * to the next pixel on the current line, and all the errors for the
+ * next line have been shifted over. We are therefore ready to move on.
+ */
+ inptr += dir3; /* Advance pixel pointers to next column */
+ outptr += dir;
+ errorptr += dir3; /* advance errorptr to current column */
+ }
+ /* Post-loop cleanup: we must unload the final error values into the
+ * final fserrors[] entry. Note we need not unload belowerrN because
+ * it is for the dummy column before or after the actual array.
+ */
+ errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */
+ errorptr[1] = (FSERROR) bpreverr1;
+ errorptr[2] = (FSERROR) bpreverr2;
+ }
+}
+
+
+/*
+ * Initialize the error-limiting transfer function (lookup table).
+ * The raw F-S error computation can potentially compute error values of up to
+ * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be
+ * much less, otherwise obviously wrong pixels will be created. (Typical
+ * effects include weird fringes at color-area boundaries, isolated bright
+ * pixels in a dark area, etc.) The standard advice for avoiding this problem
+ * is to ensure that the "corners" of the color cube are allocated as output
+ * colors; then repeated errors in the same direction cannot cause cascading
+ * error buildup. However, that only prevents the error from getting
+ * completely out of hand; Aaron Giles reports that error limiting improves
+ * the results even with corner colors allocated.
+ * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty
+ * well, but the smoother transfer function used below is even better. Thanks
+ * to Aaron Giles for this idea.
+ */
+
+LOCAL(void)
+init_error_limit (j_decompress_ptr cinfo)
+/* Allocate and fill in the error_limiter table */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ int * table;
+ int in, out;
+
+ table = (int *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int));
+ table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */
+ cquantize->error_limiter = table;
+
+#define STEPSIZE ((MAXJSAMPLE+1)/16)
+ /* Map errors 1:1 up to +- MAXJSAMPLE/16 */
+ out = 0;
+ for (in = 0; in < STEPSIZE; in++, out++) {
+ table[in] = out; table[-in] = -out;
+ }
+ /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */
+ for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) {
+ table[in] = out; table[-in] = -out;
+ }
+ /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */
+ for (; in <= MAXJSAMPLE; in++) {
+ table[in] = out; table[-in] = -out;
+ }
+#undef STEPSIZE
+}
+
+
+/*
+ * Finish up at the end of each pass.
+ */
+
+METHODDEF(void)
+finish_pass1 (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+
+ /* Select the representative colors and fill in cinfo->colormap */
+ cinfo->colormap = cquantize->sv_colormap;
+ select_colors(cinfo, cquantize->desired);
+ /* Force next pass to zero the color index table */
+ cquantize->needs_zeroed = TRUE;
+}
+
+
+METHODDEF(void)
+finish_pass2 (j_decompress_ptr cinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * Initialize for each processing pass.
+ */
+
+METHODDEF(void)
+start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ int i;
+
+ /* Only F-S dithering or no dithering is supported. */
+ /* If user asks for ordered dither, give him F-S. */
+ if (cinfo->dither_mode != JDITHER_NONE)
+ cinfo->dither_mode = JDITHER_FS;
+
+ if (is_pre_scan) {
+ /* Set up method pointers */
+ cquantize->pub.color_quantize = prescan_quantize;
+ cquantize->pub.finish_pass = finish_pass1;
+ cquantize->needs_zeroed = TRUE; /* Always zero histogram */
+ } else {
+ /* Set up method pointers */
+ if (cinfo->dither_mode == JDITHER_FS)
+ cquantize->pub.color_quantize = pass2_fs_dither;
+ else
+ cquantize->pub.color_quantize = pass2_no_dither;
+ cquantize->pub.finish_pass = finish_pass2;
+
+ /* Make sure color count is acceptable */
+ i = cinfo->actual_number_of_colors;
+ if (i < 1)
+ ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1);
+ if (i > MAXNUMCOLORS)
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
+
+ if (cinfo->dither_mode == JDITHER_FS) {
+ size_t arraysize = (size_t) ((cinfo->output_width + 2) *
+ (3 * SIZEOF(FSERROR)));
+ /* Allocate Floyd-Steinberg workspace if we didn't already. */
+ if (cquantize->fserrors == NULL)
+ cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);
+ /* Initialize the propagated errors to zero. */
+ jzero_far((void FAR *) cquantize->fserrors, arraysize);
+ /* Make the error-limit table if we didn't already. */
+ if (cquantize->error_limiter == NULL)
+ init_error_limit(cinfo);
+ cquantize->on_odd_row = FALSE;
+ }
+
+ }
+ /* Zero the histogram or inverse color map, if necessary */
+ if (cquantize->needs_zeroed) {
+ for (i = 0; i < HIST_C0_ELEMS; i++) {
+ jzero_far((void FAR *) histogram[i],
+ HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));
+ }
+ cquantize->needs_zeroed = FALSE;
+ }
+}
+
+
+/*
+ * Switch to a new external colormap between output passes.
+ */
+
+METHODDEF(void)
+new_color_map_2_quant (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+
+ /* Reset the inverse color map */
+ cquantize->needs_zeroed = TRUE;
+}
+
+
+/*
+ * Module initialization routine for 2-pass color quantization.
+ */
+
+GLOBAL(void)
+jinit_2pass_quantizer (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize;
+ int i;
+
+ cquantize = (my_cquantize_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_cquantizer));
+ cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize;
+ cquantize->pub.start_pass = start_pass_2_quant;
+ cquantize->pub.new_color_map = new_color_map_2_quant;
+ cquantize->fserrors = NULL; /* flag optional arrays not allocated */
+ cquantize->error_limiter = NULL;
+
+ /* Make sure jdmaster didn't give me a case I can't handle */
+ if (cinfo->out_color_components != 3)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
+ /* Allocate the histogram/inverse colormap storage */
+ cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d));
+ for (i = 0; i < HIST_C0_ELEMS; i++) {
+ cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));
+ }
+ cquantize->needs_zeroed = TRUE; /* histogram is garbage now */
+
+ /* Allocate storage for the completed colormap, if required.
+ * We do this now since it is FAR storage and may affect
+ * the memory manager's space calculations.
+ */
+ if (cinfo->enable_2pass_quant) {
+ /* Make sure color count is acceptable */
+ int desired = cinfo->desired_number_of_colors;
+ /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */
+ if (desired < 8)
+ ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8);
+ /* Make sure colormap indexes can be represented by JSAMPLEs */
+ if (desired > MAXNUMCOLORS)
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
+ cquantize->sv_colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3);
+ cquantize->desired = desired;
+ } else
+ cquantize->sv_colormap = NULL;
+
+ /* Only F-S dithering or no dithering is supported. */
+ /* If user asks for ordered dither, give him F-S. */
+ if (cinfo->dither_mode != JDITHER_NONE)
+ cinfo->dither_mode = JDITHER_FS;
+
+ /* Allocate Floyd-Steinberg workspace if necessary.
+ * This isn't really needed until pass 2, but again it is FAR storage.
+ * Although we will cope with a later change in dither_mode,
+ * we do not promise to honor max_memory_to_use if dither_mode changes.
+ */
+ if (cinfo->dither_mode == JDITHER_FS) {
+ cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR))));
+ /* Might as well create the error-limiting table too. */
+ init_error_limit(cinfo);
+ }
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
diff --git a/external/jpeg-8c/jutils.c b/external/jpeg-8c/jutils.c
new file mode 100644
index 0000000..0435179
--- /dev/null
+++ b/external/jpeg-8c/jutils.c
@@ -0,0 +1,231 @@
+/*
+ * jutils.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains tables and miscellaneous utility routines needed
+ * for both compression and decompression.
+ * Note we prefix all global names with "j" to minimize conflicts with
+ * a surrounding application.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element
+ * of a DCT block read in natural order (left to right, top to bottom).
+ */
+
+#if 0 /* This table is not actually needed in v6a */
+
+const int jpeg_zigzag_order[DCTSIZE2] = {
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63
+};
+
+#endif
+
+/*
+ * jpeg_natural_order[i] is the natural-order position of the i'th element
+ * of zigzag order.
+ *
+ * When reading corrupted data, the Huffman decoders could attempt
+ * to reference an entry beyond the end of this array (if the decoded
+ * zero run length reaches past the end of the block). To prevent
+ * wild stores without adding an inner-loop test, we put some extra
+ * "63"s after the real entries. This will cause the extra coefficient
+ * to be stored in location 63 of the block, not somewhere random.
+ * The worst case would be a run-length of 15, which means we need 16
+ * fake entries.
+ */
+
+const int jpeg_natural_order[DCTSIZE2+16] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order7[7*7+16] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 14, 21, 28, 35,
+ 42, 49, 50, 43, 36, 29, 22, 30,
+ 37, 44, 51, 52, 45, 38, 46, 53,
+ 54,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order6[6*6+16] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 41, 34, 27,
+ 20, 13, 21, 28, 35, 42, 43, 36,
+ 29, 37, 44, 45,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order5[5*5+16] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 12,
+ 19, 26, 33, 34, 27, 20, 28, 35,
+ 36,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order4[4*4+16] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 25, 18, 11, 19, 26, 27,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order3[3*3+16] = {
+ 0, 1, 8, 16, 9, 2, 10, 17,
+ 18,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order2[2*2+16] = {
+ 0, 1, 8, 9,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+
+/*
+ * Arithmetic utilities
+ */
+
+GLOBAL(long)
+jdiv_round_up (long a, long b)
+/* Compute a/b rounded up to next integer, ie, ceil(a/b) */
+/* Assumes a >= 0, b > 0 */
+{
+ return (a + b - 1L) / b;
+}
+
+
+GLOBAL(long)
+jround_up (long a, long b)
+/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */
+/* Assumes a >= 0, b > 0 */
+{
+ a += b - 1L;
+ return a - (a % b);
+}
+
+
+/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays
+ * and coefficient-block arrays. This won't work on 80x86 because the arrays
+ * are FAR and we're assuming a small-pointer memory model. However, some
+ * DOS compilers provide far-pointer versions of memcpy() and memset() even
+ * in the small-model libraries. These will be used if USE_FMEM is defined.
+ * Otherwise, the routines below do it the hard way. (The performance cost
+ * is not all that great, because these routines aren't very heavily used.)
+ */
+
+#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */
+#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size)
+#define FMEMZERO(target,size) MEMZERO(target,size)
+#else /* 80x86 case, define if we can */
+#ifdef USE_FMEM
+#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size))
+#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size))
+#endif
+#endif
+
+
+GLOBAL(void)
+jcopy_sample_rows (JSAMPARRAY input_array, int source_row,
+ JSAMPARRAY output_array, int dest_row,
+ int num_rows, JDIMENSION num_cols)
+/* Copy some rows of samples from one place to another.
+ * num_rows rows are copied from input_array[source_row++]
+ * to output_array[dest_row++]; these areas may overlap for duplication.
+ * The source and destination arrays must be at least as wide as num_cols.
+ */
+{
+ register JSAMPROW inptr, outptr;
+#ifdef FMEMCOPY
+ register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE));
+#else
+ register JDIMENSION count;
+#endif
+ register int row;
+
+ input_array += source_row;
+ output_array += dest_row;
+
+ for (row = num_rows; row > 0; row--) {
+ inptr = *input_array++;
+ outptr = *output_array++;
+#ifdef FMEMCOPY
+ FMEMCOPY(outptr, inptr, count);
+#else
+ for (count = num_cols; count > 0; count--)
+ *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */
+#endif
+ }
+}
+
+
+GLOBAL(void)
+jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row,
+ JDIMENSION num_blocks)
+/* Copy a row of coefficient blocks from one place to another. */
+{
+#ifdef FMEMCOPY
+ FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF)));
+#else
+ register JCOEFPTR inptr, outptr;
+ register long count;
+
+ inptr = (JCOEFPTR) input_row;
+ outptr = (JCOEFPTR) output_row;
+ for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) {
+ *outptr++ = *inptr++;
+ }
+#endif
+}
+
+
+GLOBAL(void)
+jzero_far (void FAR * target, size_t bytestozero)
+/* Zero out a chunk of FAR memory. */
+/* This might be sample-array data, block-array data, or alloc_large data. */
+{
+#ifdef FMEMZERO
+ FMEMZERO(target, bytestozero);
+#else
+ register char FAR * ptr = (char FAR *) target;
+ register size_t count;
+
+ for (count = bytestozero; count > 0; count--) {
+ *ptr++ = 0;
+ }
+#endif
+}
diff --git a/external/jpeg-8c/jversion.h b/external/jpeg-8c/jversion.h
new file mode 100644
index 0000000..e868538
--- /dev/null
+++ b/external/jpeg-8c/jversion.h
@@ -0,0 +1,14 @@
+/*
+ * jversion.h
+ *
+ * Copyright (C) 1991-2011, Thomas G. Lane, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains software version identification.
+ */
+
+
+#define JVERSION "8c 16-Jan-2011"
+
+#define JCOPYRIGHT "Copyright (C) 2011, Thomas G. Lane, Guido Vollbeding"
diff --git a/external/libcurl-7.35.0/CMakeLists.txt b/external/libcurl-7.35.0/CMakeLists.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/external/libcurl-7.35.0/CMakeLists.txt
@@ -0,0 +1 @@
+
diff --git a/external/libcurl-7.35.0/curl/curl.h b/external/libcurl-7.35.0/curl/curl.h
new file mode 100644
index 0000000..aafaeed
--- /dev/null
+++ b/external/libcurl-7.35.0/curl/curl.h
@@ -0,0 +1,2296 @@
+#ifndef __CURL_CURL_H
+#define __CURL_CURL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * If you have libcurl problems, all docs and details are found here:
+ * http://curl.haxx.se/libcurl/
+ *
+ * curl-library mailing list subscription and unsubscription web interface:
+ * http://cool.haxx.se/mailman/listinfo/curl-library/
+ */
+
+#include "curlver.h" /* libcurl version defines */
+#include "curlbuild.h" /* libcurl build definitions */
+#include "curlrules.h" /* libcurl rules enforcement */
+
+/*
+ * Define WIN32 when build target is Win32 API
+ */
+
+#if (defined(_WIN32) || defined(__WIN32__)) && \
+ !defined(WIN32) && !defined(__SYMBIAN32__)
+#define WIN32
+#endif
+
+#include <stdio.h>
+#include <limits.h>
+
+#if defined(__FreeBSD__) && (__FreeBSD__ >= 2)
+/* Needed for __FreeBSD_version symbol definition */
+#include <osreldate.h>
+#endif
+
+/* The include stuff here below is mainly for time_t! */
+#include <sys/types.h>
+#include <time.h>
+
+#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__)
+#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || defined(__LWIP_OPT_H__))
+/* The check above prevents the winsock2 inclusion if winsock.h already was
+ included, since they can't co-exist without problems */
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+#endif
+
+/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
+ libc5-based Linux systems. Only include it on systems that are known to
+ require it! */
+#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
+ defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
+ defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
+ (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
+#include <sys/select.h>
+#endif
+
+#if !defined(WIN32) && !defined(_WIN32_WCE)
+#include <sys/socket.h>
+#endif
+
+#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__)
+#include <sys/time.h>
+#endif
+
+#ifdef __BEOS__
+#include <support/SupportDefs.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void CURL;
+
+/*
+ * libcurl external API function linkage decorations.
+ */
+
+#ifdef CURL_STATICLIB
+# define CURL_EXTERN
+#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)
+# if defined(BUILDING_LIBCURL)
+# define CURL_EXTERN __declspec(dllexport)
+# else
+# define CURL_EXTERN __declspec(dllimport)
+# endif
+#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS)
+# define CURL_EXTERN CURL_EXTERN_SYMBOL
+#else
+# define CURL_EXTERN
+#endif
+
+#ifndef curl_socket_typedef
+/* socket typedef */
+#if defined(WIN32) && !defined(__LWIP_OPT_H__)
+typedef SOCKET curl_socket_t;
+#define CURL_SOCKET_BAD INVALID_SOCKET
+#else
+typedef int curl_socket_t;
+#define CURL_SOCKET_BAD -1
+#endif
+#define curl_socket_typedef
+#endif /* curl_socket_typedef */
+
+struct curl_httppost {
+ struct curl_httppost *next; /* next entry in the list */
+ char *name; /* pointer to allocated name */
+ long namelength; /* length of name length */
+ char *contents; /* pointer to allocated data contents */
+ long contentslength; /* length of contents field */
+ char *buffer; /* pointer to allocated buffer contents */
+ long bufferlength; /* length of buffer field */
+ char *contenttype; /* Content-Type */
+ struct curl_slist* contentheader; /* list of extra headers for this form */
+ struct curl_httppost *more; /* if one field name has more than one
+ file, this link should link to following
+ files */
+ long flags; /* as defined below */
+#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */
+#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */
+#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer
+ do not free in formfree */
+#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer
+ do not free in formfree */
+#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */
+#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */
+#define HTTPPOST_CALLBACK (1<<6) /* upload file contents by using the
+ regular read callback to get the data
+ and pass the given pointer as custom
+ pointer */
+
+ char *showfilename; /* The file name to show. If not set, the
+ actual file name will be used (if this
+ is a file part) */
+ void *userp; /* custom pointer used for
+ HTTPPOST_CALLBACK posts */
+};
+
+/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered
+ deprecated but was the only choice up until 7.31.0 */
+typedef int (*curl_progress_callback)(void *clientp,
+ double dltotal,
+ double dlnow,
+ double ultotal,
+ double ulnow);
+
+/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in
+ 7.32.0, it avoids floating point and provides more detailed information. */
+typedef int (*curl_xferinfo_callback)(void *clientp,
+ curl_off_t dltotal,
+ curl_off_t dlnow,
+ curl_off_t ultotal,
+ curl_off_t ulnow);
+
+#ifndef CURL_MAX_WRITE_SIZE
+ /* Tests have proven that 20K is a very bad buffer size for uploads on
+ Windows, while 16K for some odd reason performed a lot better.
+ We do the ifndef check to allow this value to easier be changed at build
+ time for those who feel adventurous. The practical minimum is about
+ 400 bytes since libcurl uses a buffer of this size as a scratch area
+ (unrelated to network send operations). */
+#define CURL_MAX_WRITE_SIZE 16384
+#endif
+
+#ifndef CURL_MAX_HTTP_HEADER
+/* The only reason to have a max limit for this is to avoid the risk of a bad
+ server feeding libcurl with a never-ending header that will cause reallocs
+ infinitely */
+#define CURL_MAX_HTTP_HEADER (100*1024)
+#endif
+
+/* This is a magic return code for the write callback that, when returned,
+ will signal libcurl to pause receiving on the current transfer. */
+#define CURL_WRITEFUNC_PAUSE 0x10000001
+
+typedef size_t (*curl_write_callback)(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *outstream);
+
+
+
+/* enumeration of file types */
+typedef enum {
+ CURLFILETYPE_FILE = 0,
+ CURLFILETYPE_DIRECTORY,
+ CURLFILETYPE_SYMLINK,
+ CURLFILETYPE_DEVICE_BLOCK,
+ CURLFILETYPE_DEVICE_CHAR,
+ CURLFILETYPE_NAMEDPIPE,
+ CURLFILETYPE_SOCKET,
+ CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */
+
+ CURLFILETYPE_UNKNOWN /* should never occur */
+} curlfiletype;
+
+#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0)
+#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1)
+#define CURLFINFOFLAG_KNOWN_TIME (1<<2)
+#define CURLFINFOFLAG_KNOWN_PERM (1<<3)
+#define CURLFINFOFLAG_KNOWN_UID (1<<4)
+#define CURLFINFOFLAG_KNOWN_GID (1<<5)
+#define CURLFINFOFLAG_KNOWN_SIZE (1<<6)
+#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7)
+
+/* Content of this structure depends on information which is known and is
+ achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man
+ page for callbacks returning this structure -- some fields are mandatory,
+ some others are optional. The FLAG field has special meaning. */
+struct curl_fileinfo {
+ char *filename;
+ curlfiletype filetype;
+ time_t time;
+ unsigned int perm;
+ int uid;
+ int gid;
+ curl_off_t size;
+ long int hardlinks;
+
+ struct {
+ /* If some of these fields is not NULL, it is a pointer to b_data. */
+ char *time;
+ char *perm;
+ char *user;
+ char *group;
+ char *target; /* pointer to the target filename of a symlink */
+ } strings;
+
+ unsigned int flags;
+
+ /* used internally */
+ char * b_data;
+ size_t b_size;
+ size_t b_used;
+};
+
+/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */
+#define CURL_CHUNK_BGN_FUNC_OK 0
+#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */
+#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */
+
+/* if splitting of data transfer is enabled, this callback is called before
+ download of an individual chunk started. Note that parameter "remains" works
+ only for FTP wildcard downloading (for now), otherwise is not used */
+typedef long (*curl_chunk_bgn_callback)(const void *transfer_info,
+ void *ptr,
+ int remains);
+
+/* return codes for CURLOPT_CHUNK_END_FUNCTION */
+#define CURL_CHUNK_END_FUNC_OK 0
+#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */
+
+/* If splitting of data transfer is enabled this callback is called after
+ download of an individual chunk finished.
+ Note! After this callback was set then it have to be called FOR ALL chunks.
+ Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC.
+ This is the reason why we don't need "transfer_info" parameter in this
+ callback and we are not interested in "remains" parameter too. */
+typedef long (*curl_chunk_end_callback)(void *ptr);
+
+/* return codes for FNMATCHFUNCTION */
+#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */
+#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */
+#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */
+
+/* callback type for wildcard downloading pattern matching. If the
+ string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */
+typedef int (*curl_fnmatch_callback)(void *ptr,
+ const char *pattern,
+ const char *string);
+
+/* These are the return codes for the seek callbacks */
+#define CURL_SEEKFUNC_OK 0
+#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */
+#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so
+ libcurl might try other means instead */
+typedef int (*curl_seek_callback)(void *instream,
+ curl_off_t offset,
+ int origin); /* 'whence' */
+
+/* This is a return code for the read callback that, when returned, will
+ signal libcurl to immediately abort the current transfer. */
+#define CURL_READFUNC_ABORT 0x10000000
+/* This is a return code for the read callback that, when returned, will
+ signal libcurl to pause sending data on the current transfer. */
+#define CURL_READFUNC_PAUSE 0x10000001
+
+typedef size_t (*curl_read_callback)(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *instream);
+
+typedef enum {
+ CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */
+ CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
+ CURLSOCKTYPE_LAST /* never use */
+} curlsocktype;
+
+/* The return code from the sockopt_callback can signal information back
+ to libcurl: */
+#define CURL_SOCKOPT_OK 0
+#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return
+ CURLE_ABORTED_BY_CALLBACK */
+#define CURL_SOCKOPT_ALREADY_CONNECTED 2
+
+typedef int (*curl_sockopt_callback)(void *clientp,
+ curl_socket_t curlfd,
+ curlsocktype purpose);
+
+struct curl_sockaddr {
+ int family;
+ int socktype;
+ int protocol;
+ unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it
+ turned really ugly and painful on the systems that
+ lack this type */
+ struct sockaddr addr;
+};
+
+typedef curl_socket_t
+(*curl_opensocket_callback)(void *clientp,
+ curlsocktype purpose,
+ struct curl_sockaddr *address);
+
+typedef int
+(*curl_closesocket_callback)(void *clientp, curl_socket_t item);
+
+typedef enum {
+ CURLIOE_OK, /* I/O operation successful */
+ CURLIOE_UNKNOWNCMD, /* command was unknown to callback */
+ CURLIOE_FAILRESTART, /* failed to restart the read */
+ CURLIOE_LAST /* never use */
+} curlioerr;
+
+typedef enum {
+ CURLIOCMD_NOP, /* no operation */
+ CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
+ CURLIOCMD_LAST /* never use */
+} curliocmd;
+
+typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
+ int cmd,
+ void *clientp);
+
+/*
+ * The following typedef's are signatures of malloc, free, realloc, strdup and
+ * calloc respectively. Function pointers of these types can be passed to the
+ * curl_global_init_mem() function to set user defined memory management
+ * callback routines.
+ */
+typedef void *(*curl_malloc_callback)(size_t size);
+typedef void (*curl_free_callback)(void *ptr);
+typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
+typedef char *(*curl_strdup_callback)(const char *str);
+typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
+
+/* the kind of data that is passed to information_callback*/
+typedef enum {
+ CURLINFO_TEXT = 0,
+ CURLINFO_HEADER_IN, /* 1 */
+ CURLINFO_HEADER_OUT, /* 2 */
+ CURLINFO_DATA_IN, /* 3 */
+ CURLINFO_DATA_OUT, /* 4 */
+ CURLINFO_SSL_DATA_IN, /* 5 */
+ CURLINFO_SSL_DATA_OUT, /* 6 */
+ CURLINFO_END
+} curl_infotype;
+
+typedef int (*curl_debug_callback)
+ (CURL *handle, /* the handle/transfer this concerns */
+ curl_infotype type, /* what kind of data */
+ char *data, /* points to the data */
+ size_t size, /* size of the data pointed to */
+ void *userptr); /* whatever the user please */
+
+/* All possible error codes from all sorts of curl functions. Future versions
+ may return other values, stay prepared.
+
+ Always add new return codes last. Never *EVER* remove any. The return
+ codes must remain the same!
+ */
+
+typedef enum {
+ CURLE_OK = 0,
+ CURLE_UNSUPPORTED_PROTOCOL, /* 1 */
+ CURLE_FAILED_INIT, /* 2 */
+ CURLE_URL_MALFORMAT, /* 3 */
+ CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for
+ 7.17.0, reused in April 2011 for 7.21.5] */
+ CURLE_COULDNT_RESOLVE_PROXY, /* 5 */
+ CURLE_COULDNT_RESOLVE_HOST, /* 6 */
+ CURLE_COULDNT_CONNECT, /* 7 */
+ CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */
+ CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server
+ due to lack of access - when login fails
+ this is not returned. */
+ CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for
+ 7.15.4, reused in Dec 2011 for 7.24.0]*/
+ CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */
+ CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server
+ [was obsoleted in August 2007 for 7.17.0,
+ reused in Dec 2011 for 7.24.0]*/
+ CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */
+ CURLE_FTP_WEIRD_227_FORMAT, /* 14 */
+ CURLE_FTP_CANT_GET_HOST, /* 15 */
+ CURLE_OBSOLETE16, /* 16 - NOT USED */
+ CURLE_FTP_COULDNT_SET_TYPE, /* 17 */
+ CURLE_PARTIAL_FILE, /* 18 */
+ CURLE_FTP_COULDNT_RETR_FILE, /* 19 */
+ CURLE_OBSOLETE20, /* 20 - NOT USED */
+ CURLE_QUOTE_ERROR, /* 21 - quote command failure */
+ CURLE_HTTP_RETURNED_ERROR, /* 22 */
+ CURLE_WRITE_ERROR, /* 23 */
+ CURLE_OBSOLETE24, /* 24 - NOT USED */
+ CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */
+ CURLE_READ_ERROR, /* 26 - couldn't open/read from file */
+ CURLE_OUT_OF_MEMORY, /* 27 */
+ /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error
+ instead of a memory allocation error if CURL_DOES_CONVERSIONS
+ is defined
+ */
+ CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */
+ CURLE_OBSOLETE29, /* 29 - NOT USED */
+ CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */
+ CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */
+ CURLE_OBSOLETE32, /* 32 - NOT USED */
+ CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */
+ CURLE_HTTP_POST_ERROR, /* 34 */
+ CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */
+ CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */
+ CURLE_FILE_COULDNT_READ_FILE, /* 37 */
+ CURLE_LDAP_CANNOT_BIND, /* 38 */
+ CURLE_LDAP_SEARCH_FAILED, /* 39 */
+ CURLE_OBSOLETE40, /* 40 - NOT USED */
+ CURLE_FUNCTION_NOT_FOUND, /* 41 */
+ CURLE_ABORTED_BY_CALLBACK, /* 42 */
+ CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */
+ CURLE_OBSOLETE44, /* 44 - NOT USED */
+ CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */
+ CURLE_OBSOLETE46, /* 46 - NOT USED */
+ CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */
+ CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */
+ CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */
+ CURLE_OBSOLETE50, /* 50 - NOT USED */
+ CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint
+ wasn't verified fine */
+ CURLE_GOT_NOTHING, /* 52 - when this is a specific error */
+ CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */
+ CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as
+ default */
+ CURLE_SEND_ERROR, /* 55 - failed sending network data */
+ CURLE_RECV_ERROR, /* 56 - failure in receiving network data */
+ CURLE_OBSOLETE57, /* 57 - NOT IN USE */
+ CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */
+ CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */
+ CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */
+ CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */
+ CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */
+ CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */
+ CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */
+ CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind
+ that failed */
+ CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */
+ CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not
+ accepted and we failed to login */
+ CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */
+ CURLE_TFTP_PERM, /* 69 - permission problem on server */
+ CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */
+ CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */
+ CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */
+ CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */
+ CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */
+ CURLE_CONV_FAILED, /* 75 - conversion failed */
+ CURLE_CONV_REQD, /* 76 - caller must register conversion
+ callbacks using curl_easy_setopt options
+ CURLOPT_CONV_FROM_NETWORK_FUNCTION,
+ CURLOPT_CONV_TO_NETWORK_FUNCTION, and
+ CURLOPT_CONV_FROM_UTF8_FUNCTION */
+ CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing
+ or wrong format */
+ CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */
+ CURLE_SSH, /* 79 - error from the SSH layer, somewhat
+ generic so the error message will be of
+ interest when this has happened */
+
+ CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL
+ connection */
+ CURLE_AGAIN, /* 81 - socket is not ready for send/recv,
+ wait till it's ready and try again (Added
+ in 7.18.2) */
+ CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or
+ wrong format (Added in 7.19.0) */
+ CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in
+ 7.19.0) */
+ CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */
+ CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */
+ CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */
+ CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */
+ CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */
+ CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the
+ session will be queued */
+ CURL_LAST /* never use! */
+} CURLcode;
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+ the obsolete stuff removed! */
+
+/* Previously obsoletes error codes re-used in 7.24.0 */
+#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED
+#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT
+
+/* compatibility with older names */
+#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING
+
+/* The following were added in 7.21.5, April 2011 */
+#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION
+
+/* The following were added in 7.17.1 */
+/* These are scheduled to disappear by 2009 */
+#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION
+
+/* The following were added in 7.17.0 */
+/* These are scheduled to disappear by 2009 */
+#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */
+#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46
+#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44
+#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10
+#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16
+#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32
+#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29
+#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12
+#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20
+#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40
+#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24
+#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57
+#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN
+
+#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED
+#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE
+#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR
+#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL
+#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS
+#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR
+#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED
+
+/* The following were added earlier */
+
+#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT
+
+#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
+#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
+#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED
+
+#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE
+#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME
+
+/* This was the error code 50 in 7.7.3 and a few earlier versions, this
+ is no longer used by libcurl but is instead #defined here only to not
+ make programs break */
+#define CURLE_ALREADY_COMPLETE 99999
+
+#endif /*!CURL_NO_OLDIES*/
+
+/* This prototype applies to all conversion callbacks */
+typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
+
+typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */
+ void *ssl_ctx, /* actually an
+ OpenSSL SSL_CTX */
+ void *userptr);
+
+typedef enum {
+ CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use
+ CONNECT HTTP/1.1 */
+ CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT
+ HTTP/1.0 */
+ CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
+ in 7.10 */
+ CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
+ CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
+ CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
+ host name rather than the IP address. added
+ in 7.18.0 */
+} curl_proxytype; /* this enum was added in 7.10 */
+
+/*
+ * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options:
+ *
+ * CURLAUTH_NONE - No HTTP authentication
+ * CURLAUTH_BASIC - HTTP Basic authentication (default)
+ * CURLAUTH_DIGEST - HTTP Digest authentication
+ * CURLAUTH_GSSNEGOTIATE - HTTP GSS-Negotiate authentication
+ * CURLAUTH_NTLM - HTTP NTLM authentication
+ * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour
+ * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper
+ * CURLAUTH_ONLY - Use together with a single other type to force no
+ * authentication or just that single type
+ * CURLAUTH_ANY - All fine types set
+ * CURLAUTH_ANYSAFE - All fine types except Basic
+ */
+
+#define CURLAUTH_NONE ((unsigned long)0)
+#define CURLAUTH_BASIC (((unsigned long)1)<<0)
+#define CURLAUTH_DIGEST (((unsigned long)1)<<1)
+#define CURLAUTH_GSSNEGOTIATE (((unsigned long)1)<<2)
+#define CURLAUTH_NTLM (((unsigned long)1)<<3)
+#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4)
+#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5)
+#define CURLAUTH_ONLY (((unsigned long)1)<<31)
+#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE)
+#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
+
+#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */
+#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */
+#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */
+#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */
+#define CURLSSH_AUTH_HOST (1<<2) /* host key files */
+#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */
+#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */
+#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY
+
+#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */
+#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */
+#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */
+
+#define CURL_ERROR_SIZE 256
+
+enum curl_khtype {
+ CURLKHTYPE_UNKNOWN,
+ CURLKHTYPE_RSA1,
+ CURLKHTYPE_RSA,
+ CURLKHTYPE_DSS
+};
+
+struct curl_khkey {
+ const char *key; /* points to a zero-terminated string encoded with base64
+ if len is zero, otherwise to the "raw" data */
+ size_t len;
+ enum curl_khtype keytype;
+};
+
+/* this is the set of return values expected from the curl_sshkeycallback
+ callback */
+enum curl_khstat {
+ CURLKHSTAT_FINE_ADD_TO_FILE,
+ CURLKHSTAT_FINE,
+ CURLKHSTAT_REJECT, /* reject the connection, return an error */
+ CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so
+ this causes a CURLE_DEFER error but otherwise the
+ connection will be left intact etc */
+ CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */
+};
+
+/* this is the set of status codes pass in to the callback */
+enum curl_khmatch {
+ CURLKHMATCH_OK, /* match */
+ CURLKHMATCH_MISMATCH, /* host found, key mismatch! */
+ CURLKHMATCH_MISSING, /* no matching host/key found */
+ CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */
+};
+
+typedef int
+ (*curl_sshkeycallback) (CURL *easy, /* easy handle */
+ const struct curl_khkey *knownkey, /* known */
+ const struct curl_khkey *foundkey, /* found */
+ enum curl_khmatch, /* libcurl's view on the keys */
+ void *clientp); /* custom pointer passed from app */
+
+/* parameter for the CURLOPT_USE_SSL option */
+typedef enum {
+ CURLUSESSL_NONE, /* do not attempt to use SSL */
+ CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */
+ CURLUSESSL_CONTROL, /* SSL for the control connection or fail */
+ CURLUSESSL_ALL, /* SSL for all communication or fail */
+ CURLUSESSL_LAST /* not an option, never use */
+} curl_usessl;
+
+/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */
+
+/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the
+ name of improving interoperability with older servers. Some SSL libraries
+ have introduced work-arounds for this flaw but those work-arounds sometimes
+ make the SSL communication fail. To regain functionality with those broken
+ servers, a user can this way allow the vulnerability back. */
+#define CURLSSLOPT_ALLOW_BEAST (1<<0)
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+ the obsolete stuff removed! */
+
+/* Backwards compatibility with older names */
+/* These are scheduled to disappear by 2009 */
+
+#define CURLFTPSSL_NONE CURLUSESSL_NONE
+#define CURLFTPSSL_TRY CURLUSESSL_TRY
+#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL
+#define CURLFTPSSL_ALL CURLUSESSL_ALL
+#define CURLFTPSSL_LAST CURLUSESSL_LAST
+#define curl_ftpssl curl_usessl
+#endif /*!CURL_NO_OLDIES*/
+
+/* parameter for the CURLOPT_FTP_SSL_CCC option */
+typedef enum {
+ CURLFTPSSL_CCC_NONE, /* do not send CCC */
+ CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */
+ CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */
+ CURLFTPSSL_CCC_LAST /* not an option, never use */
+} curl_ftpccc;
+
+/* parameter for the CURLOPT_FTPSSLAUTH option */
+typedef enum {
+ CURLFTPAUTH_DEFAULT, /* let libcurl decide */
+ CURLFTPAUTH_SSL, /* use "AUTH SSL" */
+ CURLFTPAUTH_TLS, /* use "AUTH TLS" */
+ CURLFTPAUTH_LAST /* not an option, never use */
+} curl_ftpauth;
+
+/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */
+typedef enum {
+ CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */
+ CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD
+ again if MKD succeeded, for SFTP this does
+ similar magic */
+ CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD
+ again even if MKD failed! */
+ CURLFTP_CREATE_DIR_LAST /* not an option, never use */
+} curl_ftpcreatedir;
+
+/* parameter for the CURLOPT_FTP_FILEMETHOD option */
+typedef enum {
+ CURLFTPMETHOD_DEFAULT, /* let libcurl pick */
+ CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */
+ CURLFTPMETHOD_NOCWD, /* no CWD at all */
+ CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */
+ CURLFTPMETHOD_LAST /* not an option, never use */
+} curl_ftpmethod;
+
+/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
+#define CURLPROTO_HTTP (1<<0)
+#define CURLPROTO_HTTPS (1<<1)
+#define CURLPROTO_FTP (1<<2)
+#define CURLPROTO_FTPS (1<<3)
+#define CURLPROTO_SCP (1<<4)
+#define CURLPROTO_SFTP (1<<5)
+#define CURLPROTO_TELNET (1<<6)
+#define CURLPROTO_LDAP (1<<7)
+#define CURLPROTO_LDAPS (1<<8)
+#define CURLPROTO_DICT (1<<9)
+#define CURLPROTO_FILE (1<<10)
+#define CURLPROTO_TFTP (1<<11)
+#define CURLPROTO_IMAP (1<<12)
+#define CURLPROTO_IMAPS (1<<13)
+#define CURLPROTO_POP3 (1<<14)
+#define CURLPROTO_POP3S (1<<15)
+#define CURLPROTO_SMTP (1<<16)
+#define CURLPROTO_SMTPS (1<<17)
+#define CURLPROTO_RTSP (1<<18)
+#define CURLPROTO_RTMP (1<<19)
+#define CURLPROTO_RTMPT (1<<20)
+#define CURLPROTO_RTMPE (1<<21)
+#define CURLPROTO_RTMPTE (1<<22)
+#define CURLPROTO_RTMPS (1<<23)
+#define CURLPROTO_RTMPTS (1<<24)
+#define CURLPROTO_GOPHER (1<<25)
+#define CURLPROTO_ALL (~0) /* enable everything */
+
+/* long may be 32 or 64 bits, but we should never depend on anything else
+ but 32 */
+#define CURLOPTTYPE_LONG 0
+#define CURLOPTTYPE_OBJECTPOINT 10000
+#define CURLOPTTYPE_FUNCTIONPOINT 20000
+#define CURLOPTTYPE_OFF_T 30000
+
+/* name is uppercase CURLOPT_<name>,
+ type is one of the defined CURLOPTTYPE_<type>
+ number is unique identifier */
+#ifdef CINIT
+#undef CINIT
+#endif
+
+#ifdef CURL_ISOCPP
+#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define LONG CURLOPTTYPE_LONG
+#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
+#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
+#define OFF_T CURLOPTTYPE_OFF_T
+#define CINIT(name,type,number) CURLOPT_/**/name = type + number
+#endif
+
+/*
+ * This macro-mania below setups the CURLOPT_[what] enum, to be used with
+ * curl_easy_setopt(). The first argument in the CINIT() macro is the [what]
+ * word.
+ */
+
+typedef enum {
+ /* This is the FILE * or void * the regular output should be written to. */
+ CINIT(FILE, OBJECTPOINT, 1),
+
+ /* The full URL to get/put */
+ CINIT(URL, OBJECTPOINT, 2),
+
+ /* Port number to connect to, if other than default. */
+ CINIT(PORT, LONG, 3),
+
+ /* Name of proxy to use. */
+ CINIT(PROXY, OBJECTPOINT, 4),
+
+ /* "user:password;options" to use when fetching. */
+ CINIT(USERPWD, OBJECTPOINT, 5),
+
+ /* "user:password" to use with proxy. */
+ CINIT(PROXYUSERPWD, OBJECTPOINT, 6),
+
+ /* Range to get, specified as an ASCII string. */
+ CINIT(RANGE, OBJECTPOINT, 7),
+
+ /* not used */
+
+ /* Specified file stream to upload from (use as input): */
+ CINIT(INFILE, OBJECTPOINT, 9),
+
+ /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE
+ * bytes big. If this is not used, error messages go to stderr instead: */
+ CINIT(ERRORBUFFER, OBJECTPOINT, 10),
+
+ /* Function that will be called to store the output (instead of fwrite). The
+ * parameters will use fwrite() syntax, make sure to follow them. */
+ CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11),
+
+ /* Function that will be called to read the input (instead of fread). The
+ * parameters will use fread() syntax, make sure to follow them. */
+ CINIT(READFUNCTION, FUNCTIONPOINT, 12),
+
+ /* Time-out the read operation after this amount of seconds */
+ CINIT(TIMEOUT, LONG, 13),
+
+ /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about
+ * how large the file being sent really is. That allows better error
+ * checking and better verifies that the upload was successful. -1 means
+ * unknown size.
+ *
+ * For large file support, there is also a _LARGE version of the key
+ * which takes an off_t type, allowing platforms with larger off_t
+ * sizes to handle larger files. See below for INFILESIZE_LARGE.
+ */
+ CINIT(INFILESIZE, LONG, 14),
+
+ /* POST static input fields. */
+ CINIT(POSTFIELDS, OBJECTPOINT, 15),
+
+ /* Set the referrer page (needed by some CGIs) */
+ CINIT(REFERER, OBJECTPOINT, 16),
+
+ /* Set the FTP PORT string (interface name, named or numerical IP address)
+ Use i.e '-' to use default address. */
+ CINIT(FTPPORT, OBJECTPOINT, 17),
+
+ /* Set the User-Agent string (examined by some CGIs) */
+ CINIT(USERAGENT, OBJECTPOINT, 18),
+
+ /* If the download receives less than "low speed limit" bytes/second
+ * during "low speed time" seconds, the operations is aborted.
+ * You could i.e if you have a pretty high speed connection, abort if
+ * it is less than 2000 bytes/sec during 20 seconds.
+ */
+
+ /* Set the "low speed limit" */
+ CINIT(LOW_SPEED_LIMIT, LONG, 19),
+
+ /* Set the "low speed time" */
+ CINIT(LOW_SPEED_TIME, LONG, 20),
+
+ /* Set the continuation offset.
+ *
+ * Note there is also a _LARGE version of this key which uses
+ * off_t types, allowing for large file offsets on platforms which
+ * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE.
+ */
+ CINIT(RESUME_FROM, LONG, 21),
+
+ /* Set cookie in request: */
+ CINIT(COOKIE, OBJECTPOINT, 22),
+
+ /* This points to a linked list of headers, struct curl_slist kind */
+ CINIT(HTTPHEADER, OBJECTPOINT, 23),
+
+ /* This points to a linked list of post entries, struct curl_httppost */
+ CINIT(HTTPPOST, OBJECTPOINT, 24),
+
+ /* name of the file keeping your private SSL-certificate */
+ CINIT(SSLCERT, OBJECTPOINT, 25),
+
+ /* password for the SSL or SSH private key */
+ CINIT(KEYPASSWD, OBJECTPOINT, 26),
+
+ /* send TYPE parameter? */
+ CINIT(CRLF, LONG, 27),
+
+ /* send linked-list of QUOTE commands */
+ CINIT(QUOTE, OBJECTPOINT, 28),
+
+ /* send FILE * or void * to store headers to, if you use a callback it
+ is simply passed to the callback unmodified */
+ CINIT(WRITEHEADER, OBJECTPOINT, 29),
+
+ /* point to a file to read the initial cookies from, also enables
+ "cookie awareness" */
+ CINIT(COOKIEFILE, OBJECTPOINT, 31),
+
+ /* What version to specifically try to use.
+ See CURL_SSLVERSION defines below. */
+ CINIT(SSLVERSION, LONG, 32),
+
+ /* What kind of HTTP time condition to use, see defines */
+ CINIT(TIMECONDITION, LONG, 33),
+
+ /* Time to use with the above condition. Specified in number of seconds
+ since 1 Jan 1970 */
+ CINIT(TIMEVALUE, LONG, 34),
+
+ /* 35 = OBSOLETE */
+
+ /* Custom request, for customizing the get command like
+ HTTP: DELETE, TRACE and others
+ FTP: to use a different list command
+ */
+ CINIT(CUSTOMREQUEST, OBJECTPOINT, 36),
+
+ /* HTTP request, for odd commands like DELETE, TRACE and others */
+ CINIT(STDERR, OBJECTPOINT, 37),
+
+ /* 38 is not used */
+
+ /* send linked-list of post-transfer QUOTE commands */
+ CINIT(POSTQUOTE, OBJECTPOINT, 39),
+
+ CINIT(WRITEINFO, OBJECTPOINT, 40), /* DEPRECATED, do not use! */
+
+ CINIT(VERBOSE, LONG, 41), /* talk a lot */
+ CINIT(HEADER, LONG, 42), /* throw the header out too */
+ CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */
+ CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */
+ CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */
+ CINIT(UPLOAD, LONG, 46), /* this is an upload */
+ CINIT(POST, LONG, 47), /* HTTP POST method */
+ CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */
+
+ CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */
+
+ /* Specify whether to read the user+password from the .netrc or the URL.
+ * This must be one of the CURL_NETRC_* enums below. */
+ CINIT(NETRC, LONG, 51),
+
+ CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */
+
+ CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */
+ CINIT(PUT, LONG, 54), /* HTTP PUT */
+
+ /* 55 = OBSOLETE */
+
+ /* DEPRECATED
+ * Function that will be called instead of the internal progress display
+ * function. This function should be defined as the curl_progress_callback
+ * prototype defines. */
+ CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56),
+
+ /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION
+ callbacks */
+ CINIT(PROGRESSDATA, OBJECTPOINT, 57),
+#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA
+
+ /* We want the referrer field set automatically when following locations */
+ CINIT(AUTOREFERER, LONG, 58),
+
+ /* Port of the proxy, can be set in the proxy string as well with:
+ "[host]:[port]" */
+ CINIT(PROXYPORT, LONG, 59),
+
+ /* size of the POST input data, if strlen() is not good to use */
+ CINIT(POSTFIELDSIZE, LONG, 60),
+
+ /* tunnel non-http operations through a HTTP proxy */
+ CINIT(HTTPPROXYTUNNEL, LONG, 61),
+
+ /* Set the interface string to use as outgoing network interface */
+ CINIT(INTERFACE, OBJECTPOINT, 62),
+
+ /* Set the krb4/5 security level, this also enables krb4/5 awareness. This
+ * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string
+ * is set but doesn't match one of these, 'private' will be used. */
+ CINIT(KRBLEVEL, OBJECTPOINT, 63),
+
+ /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
+ CINIT(SSL_VERIFYPEER, LONG, 64),
+
+ /* The CApath or CAfile used to validate the peer certificate
+ this option is used only if SSL_VERIFYPEER is true */
+ CINIT(CAINFO, OBJECTPOINT, 65),
+
+ /* 66 = OBSOLETE */
+ /* 67 = OBSOLETE */
+
+ /* Maximum number of http redirects to follow */
+ CINIT(MAXREDIRS, LONG, 68),
+
+ /* Pass a long set to 1 to get the date of the requested document (if
+ possible)! Pass a zero to shut it off. */
+ CINIT(FILETIME, LONG, 69),
+
+ /* This points to a linked list of telnet options */
+ CINIT(TELNETOPTIONS, OBJECTPOINT, 70),
+
+ /* Max amount of cached alive connections */
+ CINIT(MAXCONNECTS, LONG, 71),
+
+ CINIT(CLOSEPOLICY, LONG, 72), /* DEPRECATED, do not use! */
+
+ /* 73 = OBSOLETE */
+
+ /* Set to explicitly use a new connection for the upcoming transfer.
+ Do not use this unless you're absolutely sure of this, as it makes the
+ operation slower and is less friendly for the network. */
+ CINIT(FRESH_CONNECT, LONG, 74),
+
+ /* Set to explicitly forbid the upcoming transfer's connection to be re-used
+ when done. Do not use this unless you're absolutely sure of this, as it
+ makes the operation slower and is less friendly for the network. */
+ CINIT(FORBID_REUSE, LONG, 75),
+
+ /* Set to a file name that contains random data for libcurl to use to
+ seed the random engine when doing SSL connects. */
+ CINIT(RANDOM_FILE, OBJECTPOINT, 76),
+
+ /* Set to the Entropy Gathering Daemon socket pathname */
+ CINIT(EGDSOCKET, OBJECTPOINT, 77),
+
+ /* Time-out connect operations after this amount of seconds, if connects are
+ OK within this time, then fine... This only aborts the connect phase. */
+ CINIT(CONNECTTIMEOUT, LONG, 78),
+
+ /* Function that will be called to store headers (instead of fwrite). The
+ * parameters will use fwrite() syntax, make sure to follow them. */
+ CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79),
+
+ /* Set this to force the HTTP request to get back to GET. Only really usable
+ if POST, PUT or a custom request have been used first.
+ */
+ CINIT(HTTPGET, LONG, 80),
+
+ /* Set if we should verify the Common name from the peer certificate in ssl
+ * handshake, set 1 to check existence, 2 to ensure that it matches the
+ * provided hostname. */
+ CINIT(SSL_VERIFYHOST, LONG, 81),
+
+ /* Specify which file name to write all known cookies in after completed
+ operation. Set file name to "-" (dash) to make it go to stdout. */
+ CINIT(COOKIEJAR, OBJECTPOINT, 82),
+
+ /* Specify which SSL ciphers to use */
+ CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83),
+
+ /* Specify which HTTP version to use! This must be set to one of the
+ CURL_HTTP_VERSION* enums set below. */
+ CINIT(HTTP_VERSION, LONG, 84),
+
+ /* Specifically switch on or off the FTP engine's use of the EPSV command. By
+ default, that one will always be attempted before the more traditional
+ PASV command. */
+ CINIT(FTP_USE_EPSV, LONG, 85),
+
+ /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */
+ CINIT(SSLCERTTYPE, OBJECTPOINT, 86),
+
+ /* name of the file keeping your private SSL-key */
+ CINIT(SSLKEY, OBJECTPOINT, 87),
+
+ /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */
+ CINIT(SSLKEYTYPE, OBJECTPOINT, 88),
+
+ /* crypto engine for the SSL-sub system */
+ CINIT(SSLENGINE, OBJECTPOINT, 89),
+
+ /* set the crypto engine for the SSL-sub system as default
+ the param has no meaning...
+ */
+ CINIT(SSLENGINE_DEFAULT, LONG, 90),
+
+ /* Non-zero value means to use the global dns cache */
+ CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */
+
+ /* DNS cache timeout */
+ CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
+
+ /* send linked-list of pre-transfer QUOTE commands */
+ CINIT(PREQUOTE, OBJECTPOINT, 93),
+
+ /* set the debug function */
+ CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94),
+
+ /* set the data for the debug function */
+ CINIT(DEBUGDATA, OBJECTPOINT, 95),
+
+ /* mark this as start of a cookie session */
+ CINIT(COOKIESESSION, LONG, 96),
+
+ /* The CApath directory used to validate the peer certificate
+ this option is used only if SSL_VERIFYPEER is true */
+ CINIT(CAPATH, OBJECTPOINT, 97),
+
+ /* Instruct libcurl to use a smaller receive buffer */
+ CINIT(BUFFERSIZE, LONG, 98),
+
+ /* Instruct libcurl to not use any signal/alarm handlers, even when using
+ timeouts. This option is useful for multi-threaded applications.
+ See libcurl-the-guide for more background information. */
+ CINIT(NOSIGNAL, LONG, 99),
+
+ /* Provide a CURLShare for mutexing non-ts data */
+ CINIT(SHARE, OBJECTPOINT, 100),
+
+ /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default),
+ CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */
+ CINIT(PROXYTYPE, LONG, 101),
+
+ /* Set the Accept-Encoding string. Use this to tell a server you would like
+ the response to be compressed. Before 7.21.6, this was known as
+ CURLOPT_ENCODING */
+ CINIT(ACCEPT_ENCODING, OBJECTPOINT, 102),
+
+ /* Set pointer to private data */
+ CINIT(PRIVATE, OBJECTPOINT, 103),
+
+ /* Set aliases for HTTP 200 in the HTTP Response header */
+ CINIT(HTTP200ALIASES, OBJECTPOINT, 104),
+
+ /* Continue to send authentication (user+password) when following locations,
+ even when hostname changed. This can potentially send off the name
+ and password to whatever host the server decides. */
+ CINIT(UNRESTRICTED_AUTH, LONG, 105),
+
+ /* Specifically switch on or off the FTP engine's use of the EPRT command (
+ it also disables the LPRT attempt). By default, those ones will always be
+ attempted before the good old traditional PORT command. */
+ CINIT(FTP_USE_EPRT, LONG, 106),
+
+ /* Set this to a bitmask value to enable the particular authentications
+ methods you like. Use this in combination with CURLOPT_USERPWD.
+ Note that setting multiple bits may cause extra network round-trips. */
+ CINIT(HTTPAUTH, LONG, 107),
+
+ /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx
+ in second argument. The function must be matching the
+ curl_ssl_ctx_callback proto. */
+ CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108),
+
+ /* Set the userdata for the ssl context callback function's third
+ argument */
+ CINIT(SSL_CTX_DATA, OBJECTPOINT, 109),
+
+ /* FTP Option that causes missing dirs to be created on the remote server.
+ In 7.19.4 we introduced the convenience enums for this option using the
+ CURLFTP_CREATE_DIR prefix.
+ */
+ CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110),
+
+ /* Set this to a bitmask value to enable the particular authentications
+ methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
+ Note that setting multiple bits may cause extra network round-trips. */
+ CINIT(PROXYAUTH, LONG, 111),
+
+ /* FTP option that changes the timeout, in seconds, associated with
+ getting a response. This is different from transfer timeout time and
+ essentially places a demand on the FTP server to acknowledge commands
+ in a timely manner. */
+ CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112),
+#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
+
+ /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
+ tell libcurl to resolve names to those IP versions only. This only has
+ affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
+ CINIT(IPRESOLVE, LONG, 113),
+
+ /* Set this option to limit the size of a file that will be downloaded from
+ an HTTP or FTP server.
+
+ Note there is also _LARGE version which adds large file support for
+ platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */
+ CINIT(MAXFILESIZE, LONG, 114),
+
+ /* See the comment for INFILESIZE above, but in short, specifies
+ * the size of the file being uploaded. -1 means unknown.
+ */
+ CINIT(INFILESIZE_LARGE, OFF_T, 115),
+
+ /* Sets the continuation offset. There is also a LONG version of this;
+ * look above for RESUME_FROM.
+ */
+ CINIT(RESUME_FROM_LARGE, OFF_T, 116),
+
+ /* Sets the maximum size of data that will be downloaded from
+ * an HTTP or FTP server. See MAXFILESIZE above for the LONG version.
+ */
+ CINIT(MAXFILESIZE_LARGE, OFF_T, 117),
+
+ /* Set this option to the file name of your .netrc file you want libcurl
+ to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
+ a poor attempt to find the user's home directory and check for a .netrc
+ file in there. */
+ CINIT(NETRC_FILE, OBJECTPOINT, 118),
+
+ /* Enable SSL/TLS for FTP, pick one of:
+ CURLUSESSL_TRY - try using SSL, proceed anyway otherwise
+ CURLUSESSL_CONTROL - SSL for the control connection or fail
+ CURLUSESSL_ALL - SSL for all communication or fail
+ */
+ CINIT(USE_SSL, LONG, 119),
+
+ /* The _LARGE version of the standard POSTFIELDSIZE option */
+ CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120),
+
+ /* Enable/disable the TCP Nagle algorithm */
+ CINIT(TCP_NODELAY, LONG, 121),
+
+ /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 123 OBSOLETE. Gone in 7.16.0 */
+ /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 127 OBSOLETE. Gone in 7.16.0 */
+ /* 128 OBSOLETE. Gone in 7.16.0 */
+
+ /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option
+ can be used to change libcurl's default action which is to first try
+ "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK
+ response has been received.
+
+ Available parameters are:
+ CURLFTPAUTH_DEFAULT - let libcurl decide
+ CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS
+ CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL
+ */
+ CINIT(FTPSSLAUTH, LONG, 129),
+
+ CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130),
+ CINIT(IOCTLDATA, OBJECTPOINT, 131),
+
+ /* 132 OBSOLETE. Gone in 7.16.0 */
+ /* 133 OBSOLETE. Gone in 7.16.0 */
+
+ /* zero terminated string for pass on to the FTP server when asked for
+ "account" info */
+ CINIT(FTP_ACCOUNT, OBJECTPOINT, 134),
+
+ /* feed cookies into cookie engine */
+ CINIT(COOKIELIST, OBJECTPOINT, 135),
+
+ /* ignore Content-Length */
+ CINIT(IGNORE_CONTENT_LENGTH, LONG, 136),
+
+ /* Set to non-zero to skip the IP address received in a 227 PASV FTP server
+ response. Typically used for FTP-SSL purposes but is not restricted to
+ that. libcurl will then instead use the same IP address it used for the
+ control connection. */
+ CINIT(FTP_SKIP_PASV_IP, LONG, 137),
+
+ /* Select "file method" to use when doing FTP, see the curl_ftpmethod
+ above. */
+ CINIT(FTP_FILEMETHOD, LONG, 138),
+
+ /* Local port number to bind the socket to */
+ CINIT(LOCALPORT, LONG, 139),
+
+ /* Number of ports to try, including the first one set with LOCALPORT.
+ Thus, setting it to 1 will make no additional attempts but the first.
+ */
+ CINIT(LOCALPORTRANGE, LONG, 140),
+
+ /* no transfer, set up connection and let application use the socket by
+ extracting it with CURLINFO_LASTSOCKET */
+ CINIT(CONNECT_ONLY, LONG, 141),
+
+ /* Function that will be called to convert from the
+ network encoding (instead of using the iconv calls in libcurl) */
+ CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142),
+
+ /* Function that will be called to convert to the
+ network encoding (instead of using the iconv calls in libcurl) */
+ CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143),
+
+ /* Function that will be called to convert from UTF8
+ (instead of using the iconv calls in libcurl)
+ Note that this is used only for SSL certificate processing */
+ CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144),
+
+ /* if the connection proceeds too quickly then need to slow it down */
+ /* limit-rate: maximum number of bytes per second to send or receive */
+ CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145),
+ CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146),
+
+ /* Pointer to command string to send if USER/PASS fails. */
+ CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147),
+
+ /* callback function for setting socket options */
+ CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148),
+ CINIT(SOCKOPTDATA, OBJECTPOINT, 149),
+
+ /* set to 0 to disable session ID re-use for this transfer, default is
+ enabled (== 1) */
+ CINIT(SSL_SESSIONID_CACHE, LONG, 150),
+
+ /* allowed SSH authentication methods */
+ CINIT(SSH_AUTH_TYPES, LONG, 151),
+
+ /* Used by scp/sftp to do public/private key authentication */
+ CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152),
+ CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153),
+
+ /* Send CCC (Clear Command Channel) after authentication */
+ CINIT(FTP_SSL_CCC, LONG, 154),
+
+ /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */
+ CINIT(TIMEOUT_MS, LONG, 155),
+ CINIT(CONNECTTIMEOUT_MS, LONG, 156),
+
+ /* set to zero to disable the libcurl's decoding and thus pass the raw body
+ data to the application even when it is encoded/compressed */
+ CINIT(HTTP_TRANSFER_DECODING, LONG, 157),
+ CINIT(HTTP_CONTENT_DECODING, LONG, 158),
+
+ /* Permission used when creating new files and directories on the remote
+ server for protocols that support it, SFTP/SCP/FILE */
+ CINIT(NEW_FILE_PERMS, LONG, 159),
+ CINIT(NEW_DIRECTORY_PERMS, LONG, 160),
+
+ /* Set the behaviour of POST when redirecting. Values must be set to one
+ of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */
+ CINIT(POSTREDIR, LONG, 161),
+
+ /* used by scp/sftp to verify the host's public key */
+ CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162),
+
+ /* Callback function for opening socket (instead of socket(2)). Optionally,
+ callback is able change the address or refuse to connect returning
+ CURL_SOCKET_BAD. The callback should have type
+ curl_opensocket_callback */
+ CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163),
+ CINIT(OPENSOCKETDATA, OBJECTPOINT, 164),
+
+ /* POST volatile input fields. */
+ CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165),
+
+ /* set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy */
+ CINIT(PROXY_TRANSFER_MODE, LONG, 166),
+
+ /* Callback function for seeking in the input stream */
+ CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167),
+ CINIT(SEEKDATA, OBJECTPOINT, 168),
+
+ /* CRL file */
+ CINIT(CRLFILE, OBJECTPOINT, 169),
+
+ /* Issuer certificate */
+ CINIT(ISSUERCERT, OBJECTPOINT, 170),
+
+ /* (IPv6) Address scope */
+ CINIT(ADDRESS_SCOPE, LONG, 171),
+
+ /* Collect certificate chain info and allow it to get retrievable with
+ CURLINFO_CERTINFO after the transfer is complete. */
+ CINIT(CERTINFO, LONG, 172),
+
+ /* "name" and "pwd" to use when fetching. */
+ CINIT(USERNAME, OBJECTPOINT, 173),
+ CINIT(PASSWORD, OBJECTPOINT, 174),
+
+ /* "name" and "pwd" to use with Proxy when fetching. */
+ CINIT(PROXYUSERNAME, OBJECTPOINT, 175),
+ CINIT(PROXYPASSWORD, OBJECTPOINT, 176),
+
+ /* Comma separated list of hostnames defining no-proxy zones. These should
+ match both hostnames directly, and hostnames within a domain. For
+ example, local.com will match local.com and www.local.com, but NOT
+ notlocal.com or www.notlocal.com. For compatibility with other
+ implementations of this, .local.com will be considered to be the same as
+ local.com. A single * is the only valid wildcard, and effectively
+ disables the use of proxy. */
+ CINIT(NOPROXY, OBJECTPOINT, 177),
+
+ /* block size for TFTP transfers */
+ CINIT(TFTP_BLKSIZE, LONG, 178),
+
+ /* Socks Service */
+ CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179),
+
+ /* Socks Service */
+ CINIT(SOCKS5_GSSAPI_NEC, LONG, 180),
+
+ /* set the bitmask for the protocols that are allowed to be used for the
+ transfer, which thus helps the app which takes URLs from users or other
+ external inputs and want to restrict what protocol(s) to deal
+ with. Defaults to CURLPROTO_ALL. */
+ CINIT(PROTOCOLS, LONG, 181),
+
+ /* set the bitmask for the protocols that libcurl is allowed to follow to,
+ as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+ to be set in both bitmasks to be allowed to get redirected to. Defaults
+ to all protocols except FILE and SCP. */
+ CINIT(REDIR_PROTOCOLS, LONG, 182),
+
+ /* set the SSH knownhost file name to use */
+ CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183),
+
+ /* set the SSH host key callback, must point to a curl_sshkeycallback
+ function */
+ CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184),
+
+ /* set the SSH host key callback custom pointer */
+ CINIT(SSH_KEYDATA, OBJECTPOINT, 185),
+
+ /* set the SMTP mail originator */
+ CINIT(MAIL_FROM, OBJECTPOINT, 186),
+
+ /* set the SMTP mail receiver(s) */
+ CINIT(MAIL_RCPT, OBJECTPOINT, 187),
+
+ /* FTP: send PRET before PASV */
+ CINIT(FTP_USE_PRET, LONG, 188),
+
+ /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */
+ CINIT(RTSP_REQUEST, LONG, 189),
+
+ /* The RTSP session identifier */
+ CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190),
+
+ /* The RTSP stream URI */
+ CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191),
+
+ /* The Transport: header to use in RTSP requests */
+ CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192),
+
+ /* Manually initialize the client RTSP CSeq for this handle */
+ CINIT(RTSP_CLIENT_CSEQ, LONG, 193),
+
+ /* Manually initialize the server RTSP CSeq for this handle */
+ CINIT(RTSP_SERVER_CSEQ, LONG, 194),
+
+ /* The stream to pass to INTERLEAVEFUNCTION. */
+ CINIT(INTERLEAVEDATA, OBJECTPOINT, 195),
+
+ /* Let the application define a custom write method for RTP data */
+ CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196),
+
+ /* Turn on wildcard matching */
+ CINIT(WILDCARDMATCH, LONG, 197),
+
+ /* Directory matching callback called before downloading of an
+ individual file (chunk) started */
+ CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198),
+
+ /* Directory matching callback called after the file (chunk)
+ was downloaded, or skipped */
+ CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199),
+
+ /* Change match (fnmatch-like) callback for wildcard matching */
+ CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200),
+
+ /* Let the application define custom chunk data pointer */
+ CINIT(CHUNK_DATA, OBJECTPOINT, 201),
+
+ /* FNMATCH_FUNCTION user pointer */
+ CINIT(FNMATCH_DATA, OBJECTPOINT, 202),
+
+ /* send linked-list of name:port:address sets */
+ CINIT(RESOLVE, OBJECTPOINT, 203),
+
+ /* Set a username for authenticated TLS */
+ CINIT(TLSAUTH_USERNAME, OBJECTPOINT, 204),
+
+ /* Set a password for authenticated TLS */
+ CINIT(TLSAUTH_PASSWORD, OBJECTPOINT, 205),
+
+ /* Set authentication type for authenticated TLS */
+ CINIT(TLSAUTH_TYPE, OBJECTPOINT, 206),
+
+ /* Set to 1 to enable the "TE:" header in HTTP requests to ask for
+ compressed transfer-encoded responses. Set to 0 to disable the use of TE:
+ in outgoing requests. The current default is 0, but it might change in a
+ future libcurl release.
+
+ libcurl will ask for the compressed methods it knows of, and if that
+ isn't any, it will not ask for transfer-encoding at all even if this
+ option is set to 1.
+
+ */
+ CINIT(TRANSFER_ENCODING, LONG, 207),
+
+ /* Callback function for closing socket (instead of close(2)). The callback
+ should have type curl_closesocket_callback */
+ CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208),
+ CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209),
+
+ /* allow GSSAPI credential delegation */
+ CINIT(GSSAPI_DELEGATION, LONG, 210),
+
+ /* Set the name servers to use for DNS resolution */
+ CINIT(DNS_SERVERS, OBJECTPOINT, 211),
+
+ /* Time-out accept operations (currently for FTP only) after this amount
+ of miliseconds. */
+ CINIT(ACCEPTTIMEOUT_MS, LONG, 212),
+
+ /* Set TCP keepalive */
+ CINIT(TCP_KEEPALIVE, LONG, 213),
+
+ /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */
+ CINIT(TCP_KEEPIDLE, LONG, 214),
+ CINIT(TCP_KEEPINTVL, LONG, 215),
+
+ /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */
+ CINIT(SSL_OPTIONS, LONG, 216),
+
+ /* Set the SMTP auth originator */
+ CINIT(MAIL_AUTH, OBJECTPOINT, 217),
+
+ /* Enable/disable SASL initial response */
+ CINIT(SASL_IR, LONG, 218),
+
+ /* Function that will be called instead of the internal progress display
+ * function. This function should be defined as the curl_xferinfo_callback
+ * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */
+ CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219),
+
+ /* The XOAUTH2 bearer token */
+ CINIT(XOAUTH2_BEARER, OBJECTPOINT, 220),
+
+ /* Set the interface string to use as outgoing network
+ * interface for DNS requests.
+ * Only supported by the c-ares DNS backend */
+ CINIT(DNS_INTERFACE, OBJECTPOINT, 221),
+
+ /* Set the local IPv4 address to use for outgoing DNS requests.
+ * Only supported by the c-ares DNS backend */
+ CINIT(DNS_LOCAL_IP4, OBJECTPOINT, 222),
+
+ /* Set the local IPv4 address to use for outgoing DNS requests.
+ * Only supported by the c-ares DNS backend */
+ CINIT(DNS_LOCAL_IP6, OBJECTPOINT, 223),
+
+ /* Set authentication options directly */
+ CINIT(LOGIN_OPTIONS, OBJECTPOINT, 224),
+
+ CURLOPT_LASTENTRY /* the last unused */
+} CURLoption;
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+ the obsolete stuff removed! */
+
+/* Backwards compatibility with older names */
+/* These are scheduled to disappear by 2011 */
+
+/* This was added in version 7.19.1 */
+#define CURLOPT_POST301 CURLOPT_POSTREDIR
+
+/* These are scheduled to disappear by 2009 */
+
+/* The following were added in 7.17.0 */
+#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD
+#define CURLOPT_FTPAPPEND CURLOPT_APPEND
+#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY
+#define CURLOPT_FTP_SSL CURLOPT_USE_SSL
+
+/* The following were added earlier */
+
+#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD
+#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL
+
+#else
+/* This is set if CURL_NO_OLDIES is defined at compile-time */
+#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
+#endif
+
+
+ /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
+ name resolves addresses using more than one IP protocol version, this
+ option might be handy to force libcurl to use a specific IP version. */
+#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
+ versions that your system allows */
+#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */
+#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */
+
+ /* three convenient "aliases" that follow the name scheme better */
+#define CURLOPT_WRITEDATA CURLOPT_FILE
+#define CURLOPT_READDATA CURLOPT_INFILE
+#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER
+#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
+
+ /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
+enum {
+ CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
+ like the library to choose the best possible
+ for us! */
+ CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */
+ CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */
+ CURL_HTTP_VERSION_2_0, /* please use HTTP 2.0 in the request */
+
+ CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
+};
+
+/*
+ * Public API enums for RTSP requests
+ */
+enum {
+ CURL_RTSPREQ_NONE, /* first in list */
+ CURL_RTSPREQ_OPTIONS,
+ CURL_RTSPREQ_DESCRIBE,
+ CURL_RTSPREQ_ANNOUNCE,
+ CURL_RTSPREQ_SETUP,
+ CURL_RTSPREQ_PLAY,
+ CURL_RTSPREQ_PAUSE,
+ CURL_RTSPREQ_TEARDOWN,
+ CURL_RTSPREQ_GET_PARAMETER,
+ CURL_RTSPREQ_SET_PARAMETER,
+ CURL_RTSPREQ_RECORD,
+ CURL_RTSPREQ_RECEIVE,
+ CURL_RTSPREQ_LAST /* last in list */
+};
+
+ /* These enums are for use with the CURLOPT_NETRC option. */
+enum CURL_NETRC_OPTION {
+ CURL_NETRC_IGNORED, /* The .netrc will never be read.
+ * This is the default. */
+ CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred
+ * to one in the .netrc. */
+ CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored.
+ * Unless one is set programmatically, the .netrc
+ * will be queried. */
+ CURL_NETRC_LAST
+};
+
+enum {
+ CURL_SSLVERSION_DEFAULT,
+ CURL_SSLVERSION_TLSv1, /* TLS 1.x */
+ CURL_SSLVERSION_SSLv2,
+ CURL_SSLVERSION_SSLv3,
+ CURL_SSLVERSION_TLSv1_0,
+ CURL_SSLVERSION_TLSv1_1,
+ CURL_SSLVERSION_TLSv1_2,
+
+ CURL_SSLVERSION_LAST /* never use, keep last */
+};
+
+enum CURL_TLSAUTH {
+ CURL_TLSAUTH_NONE,
+ CURL_TLSAUTH_SRP,
+ CURL_TLSAUTH_LAST /* never use, keep last */
+};
+
+/* symbols to use with CURLOPT_POSTREDIR.
+ CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303
+ can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302
+ | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */
+
+#define CURL_REDIR_GET_ALL 0
+#define CURL_REDIR_POST_301 1
+#define CURL_REDIR_POST_302 2
+#define CURL_REDIR_POST_303 4
+#define CURL_REDIR_POST_ALL \
+ (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303)
+
+typedef enum {
+ CURL_TIMECOND_NONE,
+
+ CURL_TIMECOND_IFMODSINCE,
+ CURL_TIMECOND_IFUNMODSINCE,
+ CURL_TIMECOND_LASTMOD,
+
+ CURL_TIMECOND_LAST
+} curl_TimeCond;
+
+
+/* curl_strequal() and curl_strnequal() are subject for removal in a future
+ libcurl, see lib/README.curlx for details */
+CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2);
+CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n);
+
+/* name is uppercase CURLFORM_<name> */
+#ifdef CFINIT
+#undef CFINIT
+#endif
+
+#ifdef CURL_ISOCPP
+#define CFINIT(name) CURLFORM_ ## name
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define CFINIT(name) CURLFORM_/**/name
+#endif
+
+typedef enum {
+ CFINIT(NOTHING), /********* the first one is unused ************/
+
+ /* */
+ CFINIT(COPYNAME),
+ CFINIT(PTRNAME),
+ CFINIT(NAMELENGTH),
+ CFINIT(COPYCONTENTS),
+ CFINIT(PTRCONTENTS),
+ CFINIT(CONTENTSLENGTH),
+ CFINIT(FILECONTENT),
+ CFINIT(ARRAY),
+ CFINIT(OBSOLETE),
+ CFINIT(FILE),
+
+ CFINIT(BUFFER),
+ CFINIT(BUFFERPTR),
+ CFINIT(BUFFERLENGTH),
+
+ CFINIT(CONTENTTYPE),
+ CFINIT(CONTENTHEADER),
+ CFINIT(FILENAME),
+ CFINIT(END),
+ CFINIT(OBSOLETE2),
+
+ CFINIT(STREAM),
+
+ CURLFORM_LASTENTRY /* the last unused */
+} CURLformoption;
+
+#undef CFINIT /* done */
+
+/* structure to be used as parameter for CURLFORM_ARRAY */
+struct curl_forms {
+ CURLformoption option;
+ const char *value;
+};
+
+/* use this for multipart formpost building */
+/* Returns code for curl_formadd()
+ *
+ * Returns:
+ * CURL_FORMADD_OK on success
+ * CURL_FORMADD_MEMORY if the FormInfo allocation fails
+ * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
+ * CURL_FORMADD_NULL if a null pointer was given for a char
+ * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
+ * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
+ * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
+ * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated
+ * CURL_FORMADD_MEMORY if some allocation for string copying failed.
+ * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
+ *
+ ***************************************************************************/
+typedef enum {
+ CURL_FORMADD_OK, /* first, no error */
+
+ CURL_FORMADD_MEMORY,
+ CURL_FORMADD_OPTION_TWICE,
+ CURL_FORMADD_NULL,
+ CURL_FORMADD_UNKNOWN_OPTION,
+ CURL_FORMADD_INCOMPLETE,
+ CURL_FORMADD_ILLEGAL_ARRAY,
+ CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */
+
+ CURL_FORMADD_LAST /* last */
+} CURLFORMcode;
+
+/*
+ * NAME curl_formadd()
+ *
+ * DESCRIPTION
+ *
+ * Pretty advanced function for building multi-part formposts. Each invoke
+ * adds one part that together construct a full post. Then use
+ * CURLOPT_HTTPPOST to send it off to libcurl.
+ */
+CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ ...);
+
+/*
+ * callback function for curl_formget()
+ * The void *arg pointer will be the one passed as second argument to
+ * curl_formget().
+ * The character buffer passed to it must not be freed.
+ * Should return the buffer length passed to it as the argument "len" on
+ * success.
+ */
+typedef size_t (*curl_formget_callback)(void *arg, const char *buf,
+ size_t len);
+
+/*
+ * NAME curl_formget()
+ *
+ * DESCRIPTION
+ *
+ * Serialize a curl_httppost struct built with curl_formadd().
+ * Accepts a void pointer as second argument which will be passed to
+ * the curl_formget_callback function.
+ * Returns 0 on success.
+ */
+CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg,
+ curl_formget_callback append);
+/*
+ * NAME curl_formfree()
+ *
+ * DESCRIPTION
+ *
+ * Free a multipart formpost previously built with curl_formadd().
+ */
+CURL_EXTERN void curl_formfree(struct curl_httppost *form);
+
+/*
+ * NAME curl_getenv()
+ *
+ * DESCRIPTION
+ *
+ * Returns a malloc()'ed string that MUST be curl_free()ed after usage is
+ * complete. DEPRECATED - see lib/README.curlx
+ */
+CURL_EXTERN char *curl_getenv(const char *variable);
+
+/*
+ * NAME curl_version()
+ *
+ * DESCRIPTION
+ *
+ * Returns a static ascii string of the libcurl version.
+ */
+CURL_EXTERN char *curl_version(void);
+
+/*
+ * NAME curl_easy_escape()
+ *
+ * DESCRIPTION
+ *
+ * Escapes URL strings (converts all letters consider illegal in URLs to their
+ * %XX versions). This function returns a new allocated string or NULL if an
+ * error occurred.
+ */
+CURL_EXTERN char *curl_easy_escape(CURL *handle,
+ const char *string,
+ int length);
+
+/* the previous version: */
+CURL_EXTERN char *curl_escape(const char *string,
+ int length);
+
+
+/*
+ * NAME curl_easy_unescape()
+ *
+ * DESCRIPTION
+ *
+ * Unescapes URL encoding in strings (converts all %XX codes to their 8bit
+ * versions). This function returns a new allocated string or NULL if an error
+ * occurred.
+ * Conversion Note: On non-ASCII platforms the ASCII %XX codes are
+ * converted into the host encoding.
+ */
+CURL_EXTERN char *curl_easy_unescape(CURL *handle,
+ const char *string,
+ int length,
+ int *outlength);
+
+/* the previous version */
+CURL_EXTERN char *curl_unescape(const char *string,
+ int length);
+
+/*
+ * NAME curl_free()
+ *
+ * DESCRIPTION
+ *
+ * Provided for de-allocation in the same translation unit that did the
+ * allocation. Added in libcurl 7.10
+ */
+CURL_EXTERN void curl_free(void *p);
+
+/*
+ * NAME curl_global_init()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() should be invoked exactly once for each application that
+ * uses libcurl and before any call of other libcurl functions.
+ *
+ * This function is not thread-safe!
+ */
+CURL_EXTERN CURLcode curl_global_init(long flags);
+
+/*
+ * NAME curl_global_init_mem()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() or curl_global_init_mem() should be invoked exactly once
+ * for each application that uses libcurl. This function can be used to
+ * initialize libcurl and set user defined memory management callback
+ * functions. Users can implement memory management routines to check for
+ * memory leaks, check for mis-use of the curl library etc. User registered
+ * callback routines with be invoked by this library instead of the system
+ * memory management routines like malloc, free etc.
+ */
+CURL_EXTERN CURLcode curl_global_init_mem(long flags,
+ curl_malloc_callback m,
+ curl_free_callback f,
+ curl_realloc_callback r,
+ curl_strdup_callback s,
+ curl_calloc_callback c);
+
+/*
+ * NAME curl_global_cleanup()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_cleanup() should be invoked exactly once for each application
+ * that uses libcurl
+ */
+CURL_EXTERN void curl_global_cleanup(void);
+
+/* linked-list structure for the CURLOPT_QUOTE option (and other) */
+struct curl_slist {
+ char *data;
+ struct curl_slist *next;
+};
+
+/*
+ * NAME curl_slist_append()
+ *
+ * DESCRIPTION
+ *
+ * Appends a string to a linked list. If no list exists, it will be created
+ * first. Returns the new list, after appending.
+ */
+CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
+ const char *);
+
+/*
+ * NAME curl_slist_free_all()
+ *
+ * DESCRIPTION
+ *
+ * free a previously built curl_slist.
+ */
+CURL_EXTERN void curl_slist_free_all(struct curl_slist *);
+
+/*
+ * NAME curl_getdate()
+ *
+ * DESCRIPTION
+ *
+ * Returns the time, in seconds since 1 Jan 1970 of the time string given in
+ * the first argument. The time argument in the second parameter is unused
+ * and should be set to NULL.
+ */
+CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
+
+/* info about the certificate chain, only for OpenSSL builds. Asked
+ for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+struct curl_certinfo {
+ int num_of_certs; /* number of certificates with information */
+ struct curl_slist **certinfo; /* for each index in this array, there's a
+ linked list with textual information in the
+ format "name: value" */
+};
+
+/* enum for the different supported SSL backends */
+typedef enum {
+ CURLSSLBACKEND_NONE = 0,
+ CURLSSLBACKEND_OPENSSL = 1,
+ CURLSSLBACKEND_GNUTLS = 2,
+ CURLSSLBACKEND_NSS = 3,
+ CURLSSLBACKEND_QSOSSL = 4,
+ CURLSSLBACKEND_GSKIT = 5,
+ CURLSSLBACKEND_POLARSSL = 6,
+ CURLSSLBACKEND_CYASSL = 7,
+ CURLSSLBACKEND_SCHANNEL = 8,
+ CURLSSLBACKEND_DARWINSSL = 9
+} curl_sslbackend;
+
+/* Information about the SSL library used and the respective internal SSL
+ handle, which can be used to obtain further information regarding the
+ connection. Asked for with CURLINFO_TLS_SESSION. */
+struct curl_tlssessioninfo {
+ curl_sslbackend backend;
+ void *internals;
+};
+
+#define CURLINFO_STRING 0x100000
+#define CURLINFO_LONG 0x200000
+#define CURLINFO_DOUBLE 0x300000
+#define CURLINFO_SLIST 0x400000
+#define CURLINFO_MASK 0x0fffff
+#define CURLINFO_TYPEMASK 0xf00000
+
+typedef enum {
+ CURLINFO_NONE, /* first, never use this */
+ CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1,
+ CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2,
+ CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3,
+ CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4,
+ CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5,
+ CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
+ CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7,
+ CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8,
+ CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9,
+ CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10,
+ CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11,
+ CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12,
+ CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13,
+ CURLINFO_FILETIME = CURLINFO_LONG + 14,
+ CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15,
+ CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16,
+ CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
+ CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18,
+ CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19,
+ CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20,
+ CURLINFO_PRIVATE = CURLINFO_STRING + 21,
+ CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22,
+ CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23,
+ CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24,
+ CURLINFO_OS_ERRNO = CURLINFO_LONG + 25,
+ CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26,
+ CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27,
+ CURLINFO_COOKIELIST = CURLINFO_SLIST + 28,
+ CURLINFO_LASTSOCKET = CURLINFO_LONG + 29,
+ CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30,
+ CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31,
+ CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32,
+ CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33,
+ CURLINFO_CERTINFO = CURLINFO_SLIST + 34,
+ CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35,
+ CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36,
+ CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37,
+ CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38,
+ CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39,
+ CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40,
+ CURLINFO_LOCAL_IP = CURLINFO_STRING + 41,
+ CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42,
+ CURLINFO_TLS_SESSION = CURLINFO_SLIST + 43,
+ /* Fill in new entries below here! */
+
+ CURLINFO_LASTONE = 43
+} CURLINFO;
+
+/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
+ CURLINFO_HTTP_CODE */
+#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE
+
+typedef enum {
+ CURLCLOSEPOLICY_NONE, /* first, never use this */
+
+ CURLCLOSEPOLICY_OLDEST,
+ CURLCLOSEPOLICY_LEAST_RECENTLY_USED,
+ CURLCLOSEPOLICY_LEAST_TRAFFIC,
+ CURLCLOSEPOLICY_SLOWEST,
+ CURLCLOSEPOLICY_CALLBACK,
+
+ CURLCLOSEPOLICY_LAST /* last, never use this */
+} curl_closepolicy;
+
+#define CURL_GLOBAL_SSL (1<<0)
+#define CURL_GLOBAL_WIN32 (1<<1)
+#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
+#define CURL_GLOBAL_NOTHING 0
+#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL
+#define CURL_GLOBAL_ACK_EINTR (1<<2)
+
+
+/*****************************************************************************
+ * Setup defines, protos etc for the sharing stuff.
+ */
+
+/* Different data locks for a single share */
+typedef enum {
+ CURL_LOCK_DATA_NONE = 0,
+ /* CURL_LOCK_DATA_SHARE is used internally to say that
+ * the locking is just made to change the internal state of the share
+ * itself.
+ */
+ CURL_LOCK_DATA_SHARE,
+ CURL_LOCK_DATA_COOKIE,
+ CURL_LOCK_DATA_DNS,
+ CURL_LOCK_DATA_SSL_SESSION,
+ CURL_LOCK_DATA_CONNECT,
+ CURL_LOCK_DATA_LAST
+} curl_lock_data;
+
+/* Different lock access types */
+typedef enum {
+ CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */
+ CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */
+ CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */
+ CURL_LOCK_ACCESS_LAST /* never use */
+} curl_lock_access;
+
+typedef void (*curl_lock_function)(CURL *handle,
+ curl_lock_data data,
+ curl_lock_access locktype,
+ void *userptr);
+typedef void (*curl_unlock_function)(CURL *handle,
+ curl_lock_data data,
+ void *userptr);
+
+typedef void CURLSH;
+
+typedef enum {
+ CURLSHE_OK, /* all is fine */
+ CURLSHE_BAD_OPTION, /* 1 */
+ CURLSHE_IN_USE, /* 2 */
+ CURLSHE_INVALID, /* 3 */
+ CURLSHE_NOMEM, /* 4 out of memory */
+ CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */
+ CURLSHE_LAST /* never use */
+} CURLSHcode;
+
+typedef enum {
+ CURLSHOPT_NONE, /* don't use */
+ CURLSHOPT_SHARE, /* specify a data type to share */
+ CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */
+ CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */
+ CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */
+ CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock
+ callback functions */
+ CURLSHOPT_LAST /* never use */
+} CURLSHoption;
+
+CURL_EXTERN CURLSH *curl_share_init(void);
+CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...);
+CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *);
+
+/****************************************************************************
+ * Structures for querying information about the curl library at runtime.
+ */
+
+typedef enum {
+ CURLVERSION_FIRST,
+ CURLVERSION_SECOND,
+ CURLVERSION_THIRD,
+ CURLVERSION_FOURTH,
+ CURLVERSION_LAST /* never actually use this */
+} CURLversion;
+
+/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by
+ basically all programs ever that want to get version information. It is
+ meant to be a built-in version number for what kind of struct the caller
+ expects. If the struct ever changes, we redefine the NOW to another enum
+ from above. */
+#define CURLVERSION_NOW CURLVERSION_FOURTH
+
+typedef struct {
+ CURLversion age; /* age of the returned struct */
+ const char *version; /* LIBCURL_VERSION */
+ unsigned int version_num; /* LIBCURL_VERSION_NUM */
+ const char *host; /* OS/host/cpu/machine when configured */
+ int features; /* bitmask, see defines below */
+ const char *ssl_version; /* human readable string */
+ long ssl_version_num; /* not used anymore, always 0 */
+ const char *libz_version; /* human readable string */
+ /* protocols is terminated by an entry with a NULL protoname */
+ const char * const *protocols;
+
+ /* The fields below this were added in CURLVERSION_SECOND */
+ const char *ares;
+ int ares_num;
+
+ /* This field was added in CURLVERSION_THIRD */
+ const char *libidn;
+
+ /* These field were added in CURLVERSION_FOURTH */
+
+ /* Same as '_libiconv_version' if built with HAVE_ICONV */
+ int iconv_ver_num;
+
+ const char *libssh_version; /* human readable string */
+
+} curl_version_info_data;
+
+#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */
+#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */
+#define CURL_VERSION_SSL (1<<2) /* SSL options are present */
+#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */
+#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */
+#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */
+#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */
+#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */
+#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth */
+#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */
+#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */
+#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */
+#define CURL_VERSION_CONV (1<<12) /* character conversions supported */
+#define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */
+#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */
+#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegating to winbind helper */
+#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */
+
+ /*
+ * NAME curl_version_info()
+ *
+ * DESCRIPTION
+ *
+ * This function returns a pointer to a static copy of the version info
+ * struct. See above.
+ */
+CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion);
+
+/*
+ * NAME curl_easy_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_strerror function may be used to turn a CURLcode value
+ * into the equivalent human readable error string. This is useful
+ * for printing meaningful error messages.
+ */
+CURL_EXTERN const char *curl_easy_strerror(CURLcode);
+
+/*
+ * NAME curl_share_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_share_strerror function may be used to turn a CURLSHcode value
+ * into the equivalent human readable error string. This is useful
+ * for printing meaningful error messages.
+ */
+CURL_EXTERN const char *curl_share_strerror(CURLSHcode);
+
+/*
+ * NAME curl_easy_pause()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_pause function pauses or unpauses transfers. Select the new
+ * state by setting the bitmask, use the convenience defines below.
+ *
+ */
+CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
+
+#define CURLPAUSE_RECV (1<<0)
+#define CURLPAUSE_RECV_CONT (0)
+
+#define CURLPAUSE_SEND (1<<2)
+#define CURLPAUSE_SEND_CONT (0)
+
+#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND)
+#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT)
+
+#ifdef __cplusplus
+}
+#endif
+
+/* unfortunately, the easy.h and multi.h include files need options and info
+ stuff before they can be included! */
+#include "easy.h" /* nothing in curl is fun without the easy stuff */
+#include "multi.h"
+
+/* the typechecker doesn't work in C++ (yet) */
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
+ ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \
+ !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK)
+#include "typecheck-gcc.h"
+#else
+#if defined(__STDC__) && (__STDC__ >= 1)
+/* This preprocessor magic that replaces a call with the exact same call is
+ only done to make sure application authors pass exactly three arguments
+ to these functions. */
+#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param)
+#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg)
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
+#endif /* __STDC__ >= 1 */
+#endif /* gcc >= 4.3 && !__cplusplus */
+
+#endif /* __CURL_CURL_H */
diff --git a/external/libcurl-7.35.0/curl/curlbuild.h b/external/libcurl-7.35.0/curl/curlbuild.h
new file mode 100644
index 0000000..d7790db
--- /dev/null
+++ b/external/libcurl-7.35.0/curl/curlbuild.h
@@ -0,0 +1,587 @@
+#ifndef __CURL_CURLBUILD_H
+#define __CURL_CURLBUILD_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * See file include/curl/curlbuild.h.in, run configure, and forget
+ * that this file exists it is only used for non-configure systems.
+ * But you can keep reading if you want ;-)
+ *
+ */
+
+/* ================================================================ */
+/* NOTES FOR NON-CONFIGURE SYSTEMS */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * Nothing in this file is intended to be modified or adjusted by the
+ * curl library user nor by the curl library builder.
+ *
+ * If you think that something actually needs to be changed, adjusted
+ * or fixed in this file, then, report it on the libcurl development
+ * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/
+ *
+ * Try to keep one section per platform, compiler and architecture,
+ * otherwise, if an existing section is reused for a different one and
+ * later on the original is adjusted, probably the piggybacking one can
+ * be adversely changed.
+ *
+ * In order to differentiate between platforms/compilers/architectures
+ * use only compiler built in predefined preprocessor symbols.
+ *
+ * This header file shall only export symbols which are 'curl' or 'CURL'
+ * prefixed, otherwise public name space would be polluted.
+ *
+ * NOTE 2:
+ * -------
+ *
+ * For any given platform/compiler curl_off_t must be typedef'ed to a
+ * 64-bit wide signed integral data type. The width of this data type
+ * must remain constant and independent of any possible large file
+ * support settings.
+ *
+ * As an exception to the above, curl_off_t shall be typedef'ed to a
+ * 32-bit wide signed integral data type if there is no 64-bit type.
+ *
+ * As a general rule, curl_off_t shall not be mapped to off_t. This
+ * rule shall only be violated if off_t is the only 64-bit data type
+ * available and the size of off_t is independent of large file support
+ * settings. Keep your build on the safe side avoiding an off_t gating.
+ * If you have a 64-bit off_t then take for sure that another 64-bit
+ * data type exists, dig deeper and you will find it.
+ *
+ * NOTE 3:
+ * -------
+ *
+ * Right now you might be staring at file include/curl/curlbuild.h.dist or
+ * at file include/curl/curlbuild.h, this is due to the following reason:
+ * file include/curl/curlbuild.h.dist is renamed to include/curl/curlbuild.h
+ * when the libcurl source code distribution archive file is created.
+ *
+ * File include/curl/curlbuild.h.dist is not included in the distribution
+ * archive. File include/curl/curlbuild.h is not present in the git tree.
+ *
+ * The distributed include/curl/curlbuild.h file is only intended to be used
+ * on systems which can not run the also distributed configure script.
+ *
+ * On systems capable of running the configure script, the configure process
+ * will overwrite the distributed include/curl/curlbuild.h file with one that
+ * is suitable and specific to the library being configured and built, which
+ * is generated from the include/curl/curlbuild.h.in template file.
+ *
+ * If you check out from git on a non-configure platform, you must run the
+ * appropriate buildconf* script to set up curlbuild.h and other local files.
+ *
+ */
+
+/* ================================================================ */
+/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */
+/* ================================================================ */
+
+#ifdef CURL_SIZEOF_LONG
+# error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined
+#endif
+
+#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
+# error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_SOCKLEN_T
+# error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined
+#endif
+
+#ifdef CURL_TYPEOF_CURL_OFF_T
+# error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_T
+# error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_TU
+# error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined
+#endif
+
+#ifdef CURL_FORMAT_OFF_T
+# error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_OFF_T
+# error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_T
+# error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_TU
+# error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined
+#endif
+
+/* ================================================================ */
+/* EXTERNAL INTERFACE SETTINGS FOR NON-CONFIGURE SYSTEMS ONLY */
+/* ================================================================ */
+
+#if defined(__DJGPP__) || defined(__GO32__)
+# if defined(__DJGPP__) && (__DJGPP__ > 1)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__SALFORDC__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__BORLANDC__)
+# if (__BORLANDC__ < 0x520)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T i64
+# define CURL_SUFFIX_CURL_OFF_TU ui64
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__TURBOC__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__WATCOMC__)
+# if defined(__386__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T i64
+# define CURL_SUFFIX_CURL_OFF_TU ui64
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__POCC__)
+# if (__POCC__ < 280)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# elif defined(_MSC_VER)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T i64
+# define CURL_SUFFIX_CURL_OFF_TU ui64
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__LCC__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__SYMBIAN32__)
+# if defined(__EABI__) /* Treat all ARM compilers equally */
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# elif defined(__CW32__)
+# pragma longlong on
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# elif defined(__VC32__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__MWERKS__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(_WIN32_WCE)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T i64
+# define CURL_SUFFIX_CURL_OFF_TU ui64
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__MINGW32__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__VMS)
+# if defined(__VAX)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__OS400__)
+# if defined(__ILEC400__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+# define CURL_PULL_SYS_TYPES_H 1
+# define CURL_PULL_SYS_SOCKET_H 1
+# endif
+
+#elif defined(__MVS__)
+# if defined(__IBMC__) || defined(__IBMCPP__)
+# if defined(_ILP32)
+# define CURL_SIZEOF_LONG 4
+# elif defined(_LP64)
+# define CURL_SIZEOF_LONG 8
+# endif
+# if defined(_LONG_LONG)
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# elif defined(_LP64)
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+# define CURL_PULL_SYS_TYPES_H 1
+# define CURL_PULL_SYS_SOCKET_H 1
+# endif
+
+#elif defined(__370__)
+# if defined(__IBMC__) || defined(__IBMCPP__)
+# if defined(_ILP32)
+# define CURL_SIZEOF_LONG 4
+# elif defined(_LP64)
+# define CURL_SIZEOF_LONG 8
+# endif
+# if defined(_LONG_LONG)
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# elif defined(_LP64)
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+# define CURL_PULL_SYS_TYPES_H 1
+# define CURL_PULL_SYS_SOCKET_H 1
+# endif
+
+#elif defined(TPF)
+# define CURL_SIZEOF_LONG 8
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+/* ===================================== */
+/* KEEP MSVC THE PENULTIMATE ENTRY */
+/* ===================================== */
+
+#elif defined(_MSC_VER)
+# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T i64
+# define CURL_SUFFIX_CURL_OFF_TU ui64
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+/* ===================================== */
+/* KEEP GENERIC GCC THE LAST ENTRY */
+/* ===================================== */
+
+#elif defined(__GNUC__)
+# if defined(__ILP32__) || \
+ defined(__i386__) || defined(__ppc__) || defined(__powerpc__) || \
+ defined(__arm__) || defined(__sparc__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# elif defined(__LP64__) || \
+ defined(__x86_64__) || defined(__ppc64__) || defined(__powerpc64__) || \
+ defined(__sparc64__)
+# define CURL_SIZEOF_LONG 8
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+# define CURL_PULL_SYS_TYPES_H 1
+# define CURL_PULL_SYS_SOCKET_H 1
+
+#else
+# error "Unknown non-configure build target!"
+ Error Compilation_aborted_Unknown_non_configure_build_target
+#endif
+
+/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */
+/* sys/types.h is required here to properly make type definitions below. */
+#ifdef CURL_PULL_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */
+/* sys/socket.h is required here to properly make type definitions below. */
+#ifdef CURL_PULL_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+/* Data type definition of curl_socklen_t. */
+
+#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
+ typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t;
+#endif
+
+/* Data type definition of curl_off_t. */
+
+#ifdef CURL_TYPEOF_CURL_OFF_T
+ typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
+#endif
+
+#endif /* __CURL_CURLBUILD_H */
diff --git a/external/libcurl-7.35.0/curl/curlrules.h b/external/libcurl-7.35.0/curl/curlrules.h
new file mode 100644
index 0000000..7c2ede3
--- /dev/null
+++ b/external/libcurl-7.35.0/curl/curlrules.h
@@ -0,0 +1,262 @@
+#ifndef __CURL_CURLRULES_H
+#define __CURL_CURLRULES_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* COMPILE TIME SANITY CHECKS */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * All checks done in this file are intentionally placed in a public
+ * header file which is pulled by curl/curl.h when an application is
+ * being built using an already built libcurl library. Additionally
+ * this file is also included and used when building the library.
+ *
+ * If compilation fails on this file it is certainly sure that the
+ * problem is elsewhere. It could be a problem in the curlbuild.h
+ * header file, or simply that you are using different compilation
+ * settings than those used to build the library.
+ *
+ * Nothing in this file is intended to be modified or adjusted by the
+ * curl library user nor by the curl library builder.
+ *
+ * Do not deactivate any check, these are done to make sure that the
+ * library is properly built and used.
+ *
+ * You can find further help on the libcurl development mailing list:
+ * http://cool.haxx.se/mailman/listinfo/curl-library/
+ *
+ * NOTE 2
+ * ------
+ *
+ * Some of the following compile time checks are based on the fact
+ * that the dimension of a constant array can not be a negative one.
+ * In this way if the compile time verification fails, the compilation
+ * will fail issuing an error. The error description wording is compiler
+ * dependent but it will be quite similar to one of the following:
+ *
+ * "negative subscript or subscript is too large"
+ * "array must have at least one element"
+ * "-1 is an illegal array size"
+ * "size of array is negative"
+ *
+ * If you are building an application which tries to use an already
+ * built libcurl library and you are getting this kind of errors on
+ * this file, it is a clear indication that there is a mismatch between
+ * how the library was built and how you are trying to use it for your
+ * application. Your already compiled or binary library provider is the
+ * only one who can give you the details you need to properly use it.
+ */
+
+/*
+ * Verify that some macros are actually defined.
+ */
+
+#ifndef CURL_SIZEOF_LONG
+# error "CURL_SIZEOF_LONG definition is missing!"
+ Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing
+#endif
+
+#ifndef CURL_TYPEOF_CURL_SOCKLEN_T
+# error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing
+#endif
+
+#ifndef CURL_SIZEOF_CURL_SOCKLEN_T
+# error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing
+#endif
+
+#ifndef CURL_TYPEOF_CURL_OFF_T
+# error "CURL_TYPEOF_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_FORMAT_CURL_OFF_T
+# error "CURL_FORMAT_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_FORMAT_CURL_OFF_TU
+# error "CURL_FORMAT_CURL_OFF_TU definition is missing!"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing
+#endif
+
+#ifndef CURL_FORMAT_OFF_T
+# error "CURL_FORMAT_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing
+#endif
+
+#ifndef CURL_SIZEOF_CURL_OFF_T
+# error "CURL_SIZEOF_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_SUFFIX_CURL_OFF_T
+# error "CURL_SUFFIX_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_SUFFIX_CURL_OFF_TU
+# error "CURL_SUFFIX_CURL_OFF_TU definition is missing!"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing
+#endif
+
+/*
+ * Macros private to this header file.
+ */
+
+#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1
+
+#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1
+
+/*
+ * Verify that the size previously defined and expected for long
+ * is the same as the one reported by sizeof() at compile time.
+ */
+
+typedef char
+ __curl_rule_01__
+ [CurlchkszEQ(long, CURL_SIZEOF_LONG)];
+
+/*
+ * Verify that the size previously defined and expected for
+ * curl_off_t is actually the the same as the one reported
+ * by sizeof() at compile time.
+ */
+
+typedef char
+ __curl_rule_02__
+ [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)];
+
+/*
+ * Verify at compile time that the size of curl_off_t as reported
+ * by sizeof() is greater or equal than the one reported for long
+ * for the current compilation.
+ */
+
+typedef char
+ __curl_rule_03__
+ [CurlchkszGE(curl_off_t, long)];
+
+/*
+ * Verify that the size previously defined and expected for
+ * curl_socklen_t is actually the the same as the one reported
+ * by sizeof() at compile time.
+ */
+
+typedef char
+ __curl_rule_04__
+ [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)];
+
+/*
+ * Verify at compile time that the size of curl_socklen_t as reported
+ * by sizeof() is greater or equal than the one reported for int for
+ * the current compilation.
+ */
+
+typedef char
+ __curl_rule_05__
+ [CurlchkszGE(curl_socklen_t, int)];
+
+/* ================================================================ */
+/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */
+/* ================================================================ */
+
+/*
+ * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow
+ * these to be visible and exported by the external libcurl interface API,
+ * while also making them visible to the library internals, simply including
+ * curl_setup.h, without actually needing to include curl.h internally.
+ * If some day this section would grow big enough, all this should be moved
+ * to its own header file.
+ */
+
+/*
+ * Figure out if we can use the ## preprocessor operator, which is supported
+ * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__
+ * or __cplusplus so we need to carefully check for them too.
+ */
+
+#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
+ defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
+ defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \
+ defined(__ILEC400__)
+ /* This compiler is believed to have an ISO compatible preprocessor */
+#define CURL_ISOCPP
+#else
+ /* This compiler is believed NOT to have an ISO compatible preprocessor */
+#undef CURL_ISOCPP
+#endif
+
+/*
+ * Macros for minimum-width signed and unsigned curl_off_t integer constants.
+ */
+
+#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551)
+# define __CURL_OFF_T_C_HLPR2(x) x
+# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x)
+# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
+ __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
+# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
+ __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
+#else
+# ifdef CURL_ISOCPP
+# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
+# else
+# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
+# endif
+# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix)
+# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
+# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
+#endif
+
+/*
+ * Get rid of macros private to this header file.
+ */
+
+#undef CurlchkszEQ
+#undef CurlchkszGE
+
+/*
+ * Get rid of macros not intended to exist beyond this point.
+ */
+
+#undef CURL_PULL_WS2TCPIP_H
+#undef CURL_PULL_SYS_TYPES_H
+#undef CURL_PULL_SYS_SOCKET_H
+#undef CURL_PULL_SYS_POLL_H
+#undef CURL_PULL_STDINT_H
+#undef CURL_PULL_INTTYPES_H
+
+#undef CURL_TYPEOF_CURL_SOCKLEN_T
+#undef CURL_TYPEOF_CURL_OFF_T
+
+#ifdef CURL_NO_OLDIES
+#undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */
+#endif
+
+#endif /* __CURL_CURLRULES_H */
diff --git a/external/libcurl-7.35.0/curl/curlver.h b/external/libcurl-7.35.0/curl/curlver.h
new file mode 100644
index 0000000..2de9e5a
--- /dev/null
+++ b/external/libcurl-7.35.0/curl/curlver.h
@@ -0,0 +1,69 @@
+#ifndef __CURL_CURLVER_H
+#define __CURL_CURLVER_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* This header file contains nothing but libcurl version info, generated by
+ a script at release-time. This was made its own header file in 7.11.2 */
+
+/* This is the global package copyright */
+#define LIBCURL_COPYRIGHT "1996 - 2014 Daniel Stenberg, <daniel@haxx.se>."
+
+/* This is the version number of the libcurl package from which this header
+ file origins: */
+#define LIBCURL_VERSION "7.35.0"
+
+/* The numeric version number is also available "in parts" by using these
+ defines: */
+#define LIBCURL_VERSION_MAJOR 7
+#define LIBCURL_VERSION_MINOR 35
+#define LIBCURL_VERSION_PATCH 0
+
+/* This is the numeric version of the libcurl version number, meant for easier
+ parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
+ always follow this syntax:
+
+ 0xXXYYZZ
+
+ Where XX, YY and ZZ are the main version, release and patch numbers in
+ hexadecimal (using 8 bits each). All three numbers are always represented
+ using two digits. 1.2 would appear as "0x010200" while version 9.11.7
+ appears as "0x090b07".
+
+ This 6-digit (24 bits) hexadecimal number does not show pre-release number,
+ and it is always a greater number in a more recent release. It makes
+ comparisons with greater than and less than work.
+*/
+#define LIBCURL_VERSION_NUM 0x072300
+
+/*
+ * This is the date and time when the full source package was created. The
+ * timestamp is not stored in git, as the timestamp is properly set in the
+ * tarballs by the maketgz script.
+ *
+ * The format of the date should follow this template:
+ *
+ * "Mon Feb 12 11:35:33 UTC 2007"
+ */
+#define LIBCURL_TIMESTAMP "Wed Jan 29 07:09:27 UTC 2014"
+
+#endif /* __CURL_CURLVER_H */
diff --git a/external/libcurl-7.35.0/curl/easy.h b/external/libcurl-7.35.0/curl/easy.h
new file mode 100644
index 0000000..c1e3e76
--- /dev/null
+++ b/external/libcurl-7.35.0/curl/easy.h
@@ -0,0 +1,102 @@
+#ifndef __CURL_EASY_H
+#define __CURL_EASY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CURL_EXTERN CURL *curl_easy_init(void);
+CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
+CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
+CURL_EXTERN void curl_easy_cleanup(CURL *curl);
+
+/*
+ * NAME curl_easy_getinfo()
+ *
+ * DESCRIPTION
+ *
+ * Request internal information from the curl session with this function. The
+ * third argument MUST be a pointer to a long, a pointer to a char * or a
+ * pointer to a double (as the documentation describes elsewhere). The data
+ * pointed to will be filled in accordingly and can be relied upon only if the
+ * function returns CURLE_OK. This function is intended to get used *AFTER* a
+ * performed transfer, all results from this function are undefined until the
+ * transfer is completed.
+ */
+CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
+
+
+/*
+ * NAME curl_easy_duphandle()
+ *
+ * DESCRIPTION
+ *
+ * Creates a new curl session handle with the same options set for the handle
+ * passed in. Duplicating a handle could only be a matter of cloning data and
+ * options, internal state info and things like persistent connections cannot
+ * be transferred. It is useful in multithreaded applications when you can run
+ * curl_easy_duphandle() for each new thread to avoid a series of identical
+ * curl_easy_setopt() invokes in every thread.
+ */
+CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl);
+
+/*
+ * NAME curl_easy_reset()
+ *
+ * DESCRIPTION
+ *
+ * Re-initializes a CURL handle to the default values. This puts back the
+ * handle to the same state as it was in when it was just created.
+ *
+ * It does keep: live connections, the Session ID cache, the DNS cache and the
+ * cookies.
+ */
+CURL_EXTERN void curl_easy_reset(CURL *curl);
+
+/*
+ * NAME curl_easy_recv()
+ *
+ * DESCRIPTION
+ *
+ * Receives data from the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen,
+ size_t *n);
+
+/*
+ * NAME curl_easy_send()
+ *
+ * DESCRIPTION
+ *
+ * Sends data over the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer,
+ size_t buflen, size_t *n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/libcurl-7.35.0/curl/mprintf.h b/external/libcurl-7.35.0/curl/mprintf.h
new file mode 100644
index 0000000..cc9e7f5
--- /dev/null
+++ b/external/libcurl-7.35.0/curl/mprintf.h
@@ -0,0 +1,81 @@
+#ifndef __CURL_MPRINTF_H
+#define __CURL_MPRINTF_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <stdarg.h>
+#include <stdio.h> /* needed for FILE */
+
+#include "curl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CURL_EXTERN int curl_mprintf(const char *format, ...);
+CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...);
+CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...);
+CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength,
+ const char *format, ...);
+CURL_EXTERN int curl_mvprintf(const char *format, va_list args);
+CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args);
+CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args);
+CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength,
+ const char *format, va_list args);
+CURL_EXTERN char *curl_maprintf(const char *format, ...);
+CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
+
+#ifdef _MPRINTF_REPLACE
+# undef printf
+# undef fprintf
+# undef sprintf
+# undef vsprintf
+# undef snprintf
+# undef vprintf
+# undef vfprintf
+# undef vsnprintf
+# undef aprintf
+# undef vaprintf
+# define printf curl_mprintf
+# define fprintf curl_mfprintf
+#ifdef CURLDEBUG
+/* When built with CURLDEBUG we define away the sprintf functions since we
+ don't want internal code to be using them */
+# define sprintf sprintf_was_used
+# define vsprintf vsprintf_was_used
+#else
+# define sprintf curl_msprintf
+# define vsprintf curl_mvsprintf
+#endif
+# define snprintf curl_msnprintf
+# define vprintf curl_mvprintf
+# define vfprintf curl_mvfprintf
+# define vsnprintf curl_mvsnprintf
+# define aprintf curl_maprintf
+# define vaprintf curl_mvaprintf
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CURL_MPRINTF_H */
diff --git a/external/libcurl-7.35.0/curl/multi.h b/external/libcurl-7.35.0/curl/multi.h
new file mode 100644
index 0000000..3c4acb0
--- /dev/null
+++ b/external/libcurl-7.35.0/curl/multi.h
@@ -0,0 +1,399 @@
+#ifndef __CURL_MULTI_H
+#define __CURL_MULTI_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+/*
+ This is an "external" header file. Don't give away any internals here!
+
+ GOALS
+
+ o Enable a "pull" interface. The application that uses libcurl decides where
+ and when to ask libcurl to get/send data.
+
+ o Enable multiple simultaneous transfers in the same thread without making it
+ complicated for the application.
+
+ o Enable the application to select() on its own file descriptors and curl's
+ file descriptors simultaneous easily.
+
+*/
+
+/*
+ * This header file should not really need to include "curl.h" since curl.h
+ * itself includes this file and we expect user applications to do #include
+ * <curl/curl.h> without the need for especially including multi.h.
+ *
+ * For some reason we added this include here at one point, and rather than to
+ * break existing (wrongly written) libcurl applications, we leave it as-is
+ * but with this warning attached.
+ */
+#include "curl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void CURLM;
+
+typedef enum {
+ CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
+ curl_multi_socket*() soon */
+ CURLM_OK,
+ CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */
+ CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
+ CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */
+ CURLM_INTERNAL_ERROR, /* this is a libcurl bug */
+ CURLM_BAD_SOCKET, /* the passed in socket argument did not match */
+ CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */
+ CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was
+ attempted to get added - again */
+ CURLM_LAST
+} CURLMcode;
+
+/* just to make code nicer when using curl_multi_socket() you can now check
+ for CURLM_CALL_MULTI_SOCKET too in the same style it works for
+ curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
+#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
+
+typedef enum {
+ CURLMSG_NONE, /* first, not used */
+ CURLMSG_DONE, /* This easy handle has completed. 'result' contains
+ the CURLcode of the transfer */
+ CURLMSG_LAST /* last, not used */
+} CURLMSG;
+
+struct CURLMsg {
+ CURLMSG msg; /* what this message means */
+ CURL *easy_handle; /* the handle it concerns */
+ union {
+ void *whatever; /* message-specific data */
+ CURLcode result; /* return code for transfer */
+ } data;
+};
+typedef struct CURLMsg CURLMsg;
+
+/* Based on poll(2) structure and values.
+ * We don't use pollfd and POLL* constants explicitly
+ * to cover platforms without poll(). */
+#define CURL_WAIT_POLLIN 0x0001
+#define CURL_WAIT_POLLPRI 0x0002
+#define CURL_WAIT_POLLOUT 0x0004
+
+struct curl_waitfd {
+ curl_socket_t fd;
+ short events;
+ short revents; /* not supported yet */
+};
+
+/*
+ * Name: curl_multi_init()
+ *
+ * Desc: inititalize multi-style curl usage
+ *
+ * Returns: a new CURLM handle to use in all 'curl_multi' functions.
+ */
+CURL_EXTERN CURLM *curl_multi_init(void);
+
+/*
+ * Name: curl_multi_add_handle()
+ *
+ * Desc: add a standard curl handle to the multi stack
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle,
+ CURL *curl_handle);
+
+ /*
+ * Name: curl_multi_remove_handle()
+ *
+ * Desc: removes a curl handle from the multi stack again
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
+ CURL *curl_handle);
+
+ /*
+ * Name: curl_multi_fdset()
+ *
+ * Desc: Ask curl for its fd_set sets. The app can use these to select() or
+ * poll() on. We want curl_multi_perform() called as soon as one of
+ * them are ready.
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ fd_set *exc_fd_set,
+ int *max_fd);
+
+/*
+ * Name: curl_multi_wait()
+ *
+ * Desc: Poll on all fds within a CURLM set as well as any
+ * additional fds passed to the function.
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle,
+ struct curl_waitfd extra_fds[],
+ unsigned int extra_nfds,
+ int timeout_ms,
+ int *ret);
+
+ /*
+ * Name: curl_multi_perform()
+ *
+ * Desc: When the app thinks there's data available for curl it calls this
+ * function to read/write whatever there is right now. This returns
+ * as soon as the reads and writes are done. This function does not
+ * require that there actually is data available for reading or that
+ * data can be written, it can be called just in case. It returns
+ * the number of handles that still transfer data in the second
+ * argument's integer-pointer.
+ *
+ * Returns: CURLMcode type, general multi error code. *NOTE* that this only
+ * returns errors etc regarding the whole multi stack. There might
+ * still have occurred problems on invidual transfers even when this
+ * returns OK.
+ */
+CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
+ int *running_handles);
+
+ /*
+ * Name: curl_multi_cleanup()
+ *
+ * Desc: Cleans up and removes a whole multi stack. It does not free or
+ * touch any individual easy handles in any way. We need to define
+ * in what state those handles will be if this function is called
+ * in the middle of a transfer.
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
+
+/*
+ * Name: curl_multi_info_read()
+ *
+ * Desc: Ask the multi handle if there's any messages/informationals from
+ * the individual transfers. Messages include informationals such as
+ * error code from the transfer or just the fact that a transfer is
+ * completed. More details on these should be written down as well.
+ *
+ * Repeated calls to this function will return a new struct each
+ * time, until a special "end of msgs" struct is returned as a signal
+ * that there is no more to get at this point.
+ *
+ * The data the returned pointer points to will not survive calling
+ * curl_multi_cleanup().
+ *
+ * The 'CURLMsg' struct is meant to be very simple and only contain
+ * very basic informations. If more involved information is wanted,
+ * we will provide the particular "transfer handle" in that struct
+ * and that should/could/would be used in subsequent
+ * curl_easy_getinfo() calls (or similar). The point being that we
+ * must never expose complex structs to applications, as then we'll
+ * undoubtably get backwards compatibility problems in the future.
+ *
+ * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
+ * of structs. It also writes the number of messages left in the
+ * queue (after this read) in the integer the second argument points
+ * to.
+ */
+CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
+ int *msgs_in_queue);
+
+/*
+ * Name: curl_multi_strerror()
+ *
+ * Desc: The curl_multi_strerror function may be used to turn a CURLMcode
+ * value into the equivalent human readable error string. This is
+ * useful for printing meaningful error messages.
+ *
+ * Returns: A pointer to a zero-terminated error message.
+ */
+CURL_EXTERN const char *curl_multi_strerror(CURLMcode);
+
+/*
+ * Name: curl_multi_socket() and
+ * curl_multi_socket_all()
+ *
+ * Desc: An alternative version of curl_multi_perform() that allows the
+ * application to pass in one of the file descriptors that have been
+ * detected to have "action" on them and let libcurl perform.
+ * See man page for details.
+ */
+#define CURL_POLL_NONE 0
+#define CURL_POLL_IN 1
+#define CURL_POLL_OUT 2
+#define CURL_POLL_INOUT 3
+#define CURL_POLL_REMOVE 4
+
+#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD
+
+#define CURL_CSELECT_IN 0x01
+#define CURL_CSELECT_OUT 0x02
+#define CURL_CSELECT_ERR 0x04
+
+typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */
+ curl_socket_t s, /* socket */
+ int what, /* see above */
+ void *userp, /* private callback
+ pointer */
+ void *socketp); /* private socket
+ pointer */
+/*
+ * Name: curl_multi_timer_callback
+ *
+ * Desc: Called by libcurl whenever the library detects a change in the
+ * maximum number of milliseconds the app is allowed to wait before
+ * curl_multi_socket() or curl_multi_perform() must be called
+ * (to allow libcurl's timed events to take place).
+ *
+ * Returns: The callback should return zero.
+ */
+typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */
+ long timeout_ms, /* see above */
+ void *userp); /* private callback
+ pointer */
+
+CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
+ int *running_handles);
+
+CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle,
+ curl_socket_t s,
+ int ev_bitmask,
+ int *running_handles);
+
+CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
+ int *running_handles);
+
+#ifndef CURL_ALLOW_OLD_MULTI_SOCKET
+/* This macro below was added in 7.16.3 to push users who recompile to use
+ the new curl_multi_socket_action() instead of the old curl_multi_socket()
+*/
+#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z)
+#endif
+
+/*
+ * Name: curl_multi_timeout()
+ *
+ * Desc: Returns the maximum number of milliseconds the app is allowed to
+ * wait before curl_multi_socket() or curl_multi_perform() must be
+ * called (to allow libcurl's timed events to take place).
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle,
+ long *milliseconds);
+
+#undef CINIT /* re-using the same name as in curl.h */
+
+#ifdef CURL_ISOCPP
+#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define LONG CURLOPTTYPE_LONG
+#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
+#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
+#define OFF_T CURLOPTTYPE_OFF_T
+#define CINIT(name,type,number) CURLMOPT_/**/name = type + number
+#endif
+
+typedef enum {
+ /* This is the socket callback function pointer */
+ CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1),
+
+ /* This is the argument passed to the socket callback */
+ CINIT(SOCKETDATA, OBJECTPOINT, 2),
+
+ /* set to 1 to enable pipelining for this multi handle */
+ CINIT(PIPELINING, LONG, 3),
+
+ /* This is the timer callback function pointer */
+ CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4),
+
+ /* This is the argument passed to the timer callback */
+ CINIT(TIMERDATA, OBJECTPOINT, 5),
+
+ /* maximum number of entries in the connection cache */
+ CINIT(MAXCONNECTS, LONG, 6),
+
+ /* maximum number of (pipelining) connections to one host */
+ CINIT(MAX_HOST_CONNECTIONS, LONG, 7),
+
+ /* maximum number of requests in a pipeline */
+ CINIT(MAX_PIPELINE_LENGTH, LONG, 8),
+
+ /* a connection with a content-length longer than this
+ will not be considered for pipelining */
+ CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9),
+
+ /* a connection with a chunk length longer than this
+ will not be considered for pipelining */
+ CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10),
+
+ /* a list of site names(+port) that are blacklisted from
+ pipelining */
+ CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11),
+
+ /* a list of server types that are blacklisted from
+ pipelining */
+ CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12),
+
+ /* maximum number of open connections in total */
+ CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13),
+
+ CURLMOPT_LASTENTRY /* the last unused */
+} CURLMoption;
+
+
+/*
+ * Name: curl_multi_setopt()
+ *
+ * Desc: Sets options for the multi handle.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
+ CURLMoption option, ...);
+
+
+/*
+ * Name: curl_multi_assign()
+ *
+ * Desc: This function sets an association in the multi handle between the
+ * given socket and a private pointer of the application. This is
+ * (only) useful for curl_multi_socket uses.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
+ curl_socket_t sockfd, void *sockp);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif
diff --git a/external/libcurl-7.35.0/curl/stdcheaders.h b/external/libcurl-7.35.0/curl/stdcheaders.h
new file mode 100644
index 0000000..ad82ef6
--- /dev/null
+++ b/external/libcurl-7.35.0/curl/stdcheaders.h
@@ -0,0 +1,33 @@
+#ifndef __STDC_HEADERS_H
+#define __STDC_HEADERS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <sys/types.h>
+
+size_t fread (void *, size_t, size_t, FILE *);
+size_t fwrite (const void *, size_t, size_t, FILE *);
+
+int strcasecmp(const char *, const char *);
+int strncasecmp(const char *, const char *, size_t);
+
+#endif /* __STDC_HEADERS_H */
diff --git a/external/libcurl-7.35.0/curl/typecheck-gcc.h b/external/libcurl-7.35.0/curl/typecheck-gcc.h
new file mode 100644
index 0000000..cdeba21
--- /dev/null
+++ b/external/libcurl-7.35.0/curl/typecheck-gcc.h
@@ -0,0 +1,610 @@
+#ifndef __CURL_TYPECHECK_GCC_H
+#define __CURL_TYPECHECK_GCC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* wraps curl_easy_setopt() with typechecking */
+
+/* To add a new kind of warning, add an
+ * if(_curl_is_sometype_option(_curl_opt))
+ * if(!_curl_is_sometype(value))
+ * _curl_easy_setopt_err_sometype();
+ * block and define _curl_is_sometype_option, _curl_is_sometype and
+ * _curl_easy_setopt_err_sometype below
+ *
+ * NOTE: We use two nested 'if' statements here instead of the && operator, in
+ * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x
+ * when compiling with -Wlogical-op.
+ *
+ * To add an option that uses the same type as an existing option, you'll just
+ * need to extend the appropriate _curl_*_option macro
+ */
+#define curl_easy_setopt(handle, option, value) \
+__extension__ ({ \
+ __typeof__ (option) _curl_opt = option; \
+ if(__builtin_constant_p(_curl_opt)) { \
+ if(_curl_is_long_option(_curl_opt)) \
+ if(!_curl_is_long(value)) \
+ _curl_easy_setopt_err_long(); \
+ if(_curl_is_off_t_option(_curl_opt)) \
+ if(!_curl_is_off_t(value)) \
+ _curl_easy_setopt_err_curl_off_t(); \
+ if(_curl_is_string_option(_curl_opt)) \
+ if(!_curl_is_string(value)) \
+ _curl_easy_setopt_err_string(); \
+ if(_curl_is_write_cb_option(_curl_opt)) \
+ if(!_curl_is_write_cb(value)) \
+ _curl_easy_setopt_err_write_callback(); \
+ if((_curl_opt) == CURLOPT_READFUNCTION) \
+ if(!_curl_is_read_cb(value)) \
+ _curl_easy_setopt_err_read_cb(); \
+ if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \
+ if(!_curl_is_ioctl_cb(value)) \
+ _curl_easy_setopt_err_ioctl_cb(); \
+ if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \
+ if(!_curl_is_sockopt_cb(value)) \
+ _curl_easy_setopt_err_sockopt_cb(); \
+ if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \
+ if(!_curl_is_opensocket_cb(value)) \
+ _curl_easy_setopt_err_opensocket_cb(); \
+ if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \
+ if(!_curl_is_progress_cb(value)) \
+ _curl_easy_setopt_err_progress_cb(); \
+ if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \
+ if(!_curl_is_debug_cb(value)) \
+ _curl_easy_setopt_err_debug_cb(); \
+ if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \
+ if(!_curl_is_ssl_ctx_cb(value)) \
+ _curl_easy_setopt_err_ssl_ctx_cb(); \
+ if(_curl_is_conv_cb_option(_curl_opt)) \
+ if(!_curl_is_conv_cb(value)) \
+ _curl_easy_setopt_err_conv_cb(); \
+ if((_curl_opt) == CURLOPT_SEEKFUNCTION) \
+ if(!_curl_is_seek_cb(value)) \
+ _curl_easy_setopt_err_seek_cb(); \
+ if(_curl_is_cb_data_option(_curl_opt)) \
+ if(!_curl_is_cb_data(value)) \
+ _curl_easy_setopt_err_cb_data(); \
+ if((_curl_opt) == CURLOPT_ERRORBUFFER) \
+ if(!_curl_is_error_buffer(value)) \
+ _curl_easy_setopt_err_error_buffer(); \
+ if((_curl_opt) == CURLOPT_STDERR) \
+ if(!_curl_is_FILE(value)) \
+ _curl_easy_setopt_err_FILE(); \
+ if(_curl_is_postfields_option(_curl_opt)) \
+ if(!_curl_is_postfields(value)) \
+ _curl_easy_setopt_err_postfields(); \
+ if((_curl_opt) == CURLOPT_HTTPPOST) \
+ if(!_curl_is_arr((value), struct curl_httppost)) \
+ _curl_easy_setopt_err_curl_httpost(); \
+ if(_curl_is_slist_option(_curl_opt)) \
+ if(!_curl_is_arr((value), struct curl_slist)) \
+ _curl_easy_setopt_err_curl_slist(); \
+ if((_curl_opt) == CURLOPT_SHARE) \
+ if(!_curl_is_ptr((value), CURLSH)) \
+ _curl_easy_setopt_err_CURLSH(); \
+ } \
+ curl_easy_setopt(handle, _curl_opt, value); \
+})
+
+/* wraps curl_easy_getinfo() with typechecking */
+/* FIXME: don't allow const pointers */
+#define curl_easy_getinfo(handle, info, arg) \
+__extension__ ({ \
+ __typeof__ (info) _curl_info = info; \
+ if(__builtin_constant_p(_curl_info)) { \
+ if(_curl_is_string_info(_curl_info)) \
+ if(!_curl_is_arr((arg), char *)) \
+ _curl_easy_getinfo_err_string(); \
+ if(_curl_is_long_info(_curl_info)) \
+ if(!_curl_is_arr((arg), long)) \
+ _curl_easy_getinfo_err_long(); \
+ if(_curl_is_double_info(_curl_info)) \
+ if(!_curl_is_arr((arg), double)) \
+ _curl_easy_getinfo_err_double(); \
+ if(_curl_is_slist_info(_curl_info)) \
+ if(!_curl_is_arr((arg), struct curl_slist *)) \
+ _curl_easy_getinfo_err_curl_slist(); \
+ } \
+ curl_easy_getinfo(handle, _curl_info, arg); \
+})
+
+/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(),
+ * for now just make sure that the functions are called with three
+ * arguments
+ */
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
+
+
+/* the actual warnings, triggered by calling the _curl_easy_setopt_err*
+ * functions */
+
+/* To define a new warning, use _CURL_WARNING(identifier, "message") */
+#define _CURL_WARNING(id, message) \
+ static void __attribute__((__warning__(message))) \
+ __attribute__((__unused__)) __attribute__((__noinline__)) \
+ id(void) { __asm__(""); }
+
+_CURL_WARNING(_curl_easy_setopt_err_long,
+ "curl_easy_setopt expects a long argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_off_t,
+ "curl_easy_setopt expects a curl_off_t argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_string,
+ "curl_easy_setopt expects a "
+ "string (char* or char[]) argument for this option"
+ )
+_CURL_WARNING(_curl_easy_setopt_err_write_callback,
+ "curl_easy_setopt expects a curl_write_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_read_cb,
+ "curl_easy_setopt expects a curl_read_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb,
+ "curl_easy_setopt expects a curl_ioctl_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb,
+ "curl_easy_setopt expects a curl_sockopt_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb,
+ "curl_easy_setopt expects a "
+ "curl_opensocket_callback argument for this option"
+ )
+_CURL_WARNING(_curl_easy_setopt_err_progress_cb,
+ "curl_easy_setopt expects a curl_progress_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_debug_cb,
+ "curl_easy_setopt expects a curl_debug_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb,
+ "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_conv_cb,
+ "curl_easy_setopt expects a curl_conv_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_seek_cb,
+ "curl_easy_setopt expects a curl_seek_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_cb_data,
+ "curl_easy_setopt expects a "
+ "private data pointer as argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_error_buffer,
+ "curl_easy_setopt expects a "
+ "char buffer of CURL_ERROR_SIZE as argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_FILE,
+ "curl_easy_setopt expects a FILE* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_postfields,
+ "curl_easy_setopt expects a void* or char* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_httpost,
+ "curl_easy_setopt expects a struct curl_httppost* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_slist,
+ "curl_easy_setopt expects a struct curl_slist* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_CURLSH,
+ "curl_easy_setopt expects a CURLSH* argument for this option")
+
+_CURL_WARNING(_curl_easy_getinfo_err_string,
+ "curl_easy_getinfo expects a pointer to char * for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_long,
+ "curl_easy_getinfo expects a pointer to long for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_double,
+ "curl_easy_getinfo expects a pointer to double for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
+ "curl_easy_getinfo expects a pointer to struct curl_slist * for this info")
+
+/* groups of curl_easy_setops options that take the same type of argument */
+
+/* To add a new option to one of the groups, just add
+ * (option) == CURLOPT_SOMETHING
+ * to the or-expression. If the option takes a long or curl_off_t, you don't
+ * have to do anything
+ */
+
+/* evaluates to true if option takes a long argument */
+#define _curl_is_long_option(option) \
+ (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT)
+
+#define _curl_is_off_t_option(option) \
+ ((option) > CURLOPTTYPE_OFF_T)
+
+/* evaluates to true if option takes a char* argument */
+#define _curl_is_string_option(option) \
+ ((option) == CURLOPT_URL || \
+ (option) == CURLOPT_PROXY || \
+ (option) == CURLOPT_INTERFACE || \
+ (option) == CURLOPT_NETRC_FILE || \
+ (option) == CURLOPT_USERPWD || \
+ (option) == CURLOPT_USERNAME || \
+ (option) == CURLOPT_PASSWORD || \
+ (option) == CURLOPT_PROXYUSERPWD || \
+ (option) == CURLOPT_PROXYUSERNAME || \
+ (option) == CURLOPT_PROXYPASSWORD || \
+ (option) == CURLOPT_NOPROXY || \
+ (option) == CURLOPT_ACCEPT_ENCODING || \
+ (option) == CURLOPT_REFERER || \
+ (option) == CURLOPT_USERAGENT || \
+ (option) == CURLOPT_COOKIE || \
+ (option) == CURLOPT_COOKIEFILE || \
+ (option) == CURLOPT_COOKIEJAR || \
+ (option) == CURLOPT_COOKIELIST || \
+ (option) == CURLOPT_FTPPORT || \
+ (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \
+ (option) == CURLOPT_FTP_ACCOUNT || \
+ (option) == CURLOPT_RANGE || \
+ (option) == CURLOPT_CUSTOMREQUEST || \
+ (option) == CURLOPT_SSLCERT || \
+ (option) == CURLOPT_SSLCERTTYPE || \
+ (option) == CURLOPT_SSLKEY || \
+ (option) == CURLOPT_SSLKEYTYPE || \
+ (option) == CURLOPT_KEYPASSWD || \
+ (option) == CURLOPT_SSLENGINE || \
+ (option) == CURLOPT_CAINFO || \
+ (option) == CURLOPT_CAPATH || \
+ (option) == CURLOPT_RANDOM_FILE || \
+ (option) == CURLOPT_EGDSOCKET || \
+ (option) == CURLOPT_SSL_CIPHER_LIST || \
+ (option) == CURLOPT_KRBLEVEL || \
+ (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \
+ (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \
+ (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \
+ (option) == CURLOPT_CRLFILE || \
+ (option) == CURLOPT_ISSUERCERT || \
+ (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \
+ (option) == CURLOPT_SSH_KNOWNHOSTS || \
+ (option) == CURLOPT_MAIL_FROM || \
+ (option) == CURLOPT_RTSP_SESSION_ID || \
+ (option) == CURLOPT_RTSP_STREAM_URI || \
+ (option) == CURLOPT_RTSP_TRANSPORT || \
+ (option) == CURLOPT_XOAUTH2_BEARER || \
+ (option) == CURLOPT_DNS_SERVERS || \
+ (option) == CURLOPT_DNS_INTERFACE || \
+ (option) == CURLOPT_DNS_LOCAL_IP4 || \
+ (option) == CURLOPT_DNS_LOCAL_IP6 || \
+ (option) == CURLOPT_LOGIN_OPTIONS || \
+ 0)
+
+/* evaluates to true if option takes a curl_write_callback argument */
+#define _curl_is_write_cb_option(option) \
+ ((option) == CURLOPT_HEADERFUNCTION || \
+ (option) == CURLOPT_WRITEFUNCTION)
+
+/* evaluates to true if option takes a curl_conv_callback argument */
+#define _curl_is_conv_cb_option(option) \
+ ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \
+ (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \
+ (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION)
+
+/* evaluates to true if option takes a data argument to pass to a callback */
+#define _curl_is_cb_data_option(option) \
+ ((option) == CURLOPT_WRITEDATA || \
+ (option) == CURLOPT_READDATA || \
+ (option) == CURLOPT_IOCTLDATA || \
+ (option) == CURLOPT_SOCKOPTDATA || \
+ (option) == CURLOPT_OPENSOCKETDATA || \
+ (option) == CURLOPT_PROGRESSDATA || \
+ (option) == CURLOPT_WRITEHEADER || \
+ (option) == CURLOPT_DEBUGDATA || \
+ (option) == CURLOPT_SSL_CTX_DATA || \
+ (option) == CURLOPT_SEEKDATA || \
+ (option) == CURLOPT_PRIVATE || \
+ (option) == CURLOPT_SSH_KEYDATA || \
+ (option) == CURLOPT_INTERLEAVEDATA || \
+ (option) == CURLOPT_CHUNK_DATA || \
+ (option) == CURLOPT_FNMATCH_DATA || \
+ 0)
+
+/* evaluates to true if option takes a POST data argument (void* or char*) */
+#define _curl_is_postfields_option(option) \
+ ((option) == CURLOPT_POSTFIELDS || \
+ (option) == CURLOPT_COPYPOSTFIELDS || \
+ 0)
+
+/* evaluates to true if option takes a struct curl_slist * argument */
+#define _curl_is_slist_option(option) \
+ ((option) == CURLOPT_HTTPHEADER || \
+ (option) == CURLOPT_HTTP200ALIASES || \
+ (option) == CURLOPT_QUOTE || \
+ (option) == CURLOPT_POSTQUOTE || \
+ (option) == CURLOPT_PREQUOTE || \
+ (option) == CURLOPT_TELNETOPTIONS || \
+ (option) == CURLOPT_MAIL_RCPT || \
+ 0)
+
+/* groups of curl_easy_getinfo infos that take the same type of argument */
+
+/* evaluates to true if info expects a pointer to char * argument */
+#define _curl_is_string_info(info) \
+ (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG)
+
+/* evaluates to true if info expects a pointer to long argument */
+#define _curl_is_long_info(info) \
+ (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE)
+
+/* evaluates to true if info expects a pointer to double argument */
+#define _curl_is_double_info(info) \
+ (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST)
+
+/* true if info expects a pointer to struct curl_slist * argument */
+#define _curl_is_slist_info(info) \
+ (CURLINFO_SLIST < (info))
+
+
+/* typecheck helpers -- check whether given expression has requested type*/
+
+/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros,
+ * otherwise define a new macro. Search for __builtin_types_compatible_p
+ * in the GCC manual.
+ * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is
+ * the actual expression passed to the curl_easy_setopt macro. This
+ * means that you can only apply the sizeof and __typeof__ operators, no
+ * == or whatsoever.
+ */
+
+/* XXX: should evaluate to true iff expr is a pointer */
+#define _curl_is_any_ptr(expr) \
+ (sizeof(expr) == sizeof(void*))
+
+/* evaluates to true if expr is NULL */
+/* XXX: must not evaluate expr, so this check is not accurate */
+#define _curl_is_NULL(expr) \
+ (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL)))
+
+/* evaluates to true if expr is type*, const type* or NULL */
+#define _curl_is_ptr(expr, type) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), type *) || \
+ __builtin_types_compatible_p(__typeof__(expr), const type *))
+
+/* evaluates to true if expr is one of type[], type*, NULL or const type* */
+#define _curl_is_arr(expr, type) \
+ (_curl_is_ptr((expr), type) || \
+ __builtin_types_compatible_p(__typeof__(expr), type []))
+
+/* evaluates to true if expr is a string */
+#define _curl_is_string(expr) \
+ (_curl_is_arr((expr), char) || \
+ _curl_is_arr((expr), signed char) || \
+ _curl_is_arr((expr), unsigned char))
+
+/* evaluates to true if expr is a long (no matter the signedness)
+ * XXX: for now, int is also accepted (and therefore short and char, which
+ * are promoted to int when passed to a variadic function) */
+#define _curl_is_long(expr) \
+ (__builtin_types_compatible_p(__typeof__(expr), long) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed long) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \
+ __builtin_types_compatible_p(__typeof__(expr), int) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed int) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \
+ __builtin_types_compatible_p(__typeof__(expr), short) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed short) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \
+ __builtin_types_compatible_p(__typeof__(expr), char) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed char) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned char))
+
+/* evaluates to true if expr is of type curl_off_t */
+#define _curl_is_off_t(expr) \
+ (__builtin_types_compatible_p(__typeof__(expr), curl_off_t))
+
+/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */
+/* XXX: also check size of an char[] array? */
+#define _curl_is_error_buffer(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), char *) || \
+ __builtin_types_compatible_p(__typeof__(expr), char[]))
+
+/* evaluates to true if expr is of type (const) void* or (const) FILE* */
+#if 0
+#define _curl_is_cb_data(expr) \
+ (_curl_is_ptr((expr), void) || \
+ _curl_is_ptr((expr), FILE))
+#else /* be less strict */
+#define _curl_is_cb_data(expr) \
+ _curl_is_any_ptr(expr)
+#endif
+
+/* evaluates to true if expr is of type FILE* */
+#define _curl_is_FILE(expr) \
+ (__builtin_types_compatible_p(__typeof__(expr), FILE *))
+
+/* evaluates to true if expr can be passed as POST data (void* or char*) */
+#define _curl_is_postfields(expr) \
+ (_curl_is_ptr((expr), void) || \
+ _curl_is_arr((expr), char))
+
+/* FIXME: the whole callback checking is messy...
+ * The idea is to tolerate char vs. void and const vs. not const
+ * pointers in arguments at least
+ */
+/* helper: __builtin_types_compatible_p distinguishes between functions and
+ * function pointers, hide it */
+#define _curl_callback_compatible(func, type) \
+ (__builtin_types_compatible_p(__typeof__(func), type) || \
+ __builtin_types_compatible_p(__typeof__(func), type*))
+
+/* evaluates to true if expr is of type curl_read_callback or "similar" */
+#define _curl_is_read_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), __typeof__(fread)) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_read_callback) || \
+ _curl_callback_compatible((expr), _curl_read_callback1) || \
+ _curl_callback_compatible((expr), _curl_read_callback2) || \
+ _curl_callback_compatible((expr), _curl_read_callback3) || \
+ _curl_callback_compatible((expr), _curl_read_callback4) || \
+ _curl_callback_compatible((expr), _curl_read_callback5) || \
+ _curl_callback_compatible((expr), _curl_read_callback6))
+typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void*);
+typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void*);
+typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE*);
+typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void*);
+typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void*);
+typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE*);
+
+/* evaluates to true if expr is of type curl_write_callback or "similar" */
+#define _curl_is_write_cb(expr) \
+ (_curl_is_read_cb(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), __typeof__(fwrite)) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_write_callback) || \
+ _curl_callback_compatible((expr), _curl_write_callback1) || \
+ _curl_callback_compatible((expr), _curl_write_callback2) || \
+ _curl_callback_compatible((expr), _curl_write_callback3) || \
+ _curl_callback_compatible((expr), _curl_write_callback4) || \
+ _curl_callback_compatible((expr), _curl_write_callback5) || \
+ _curl_callback_compatible((expr), _curl_write_callback6))
+typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void*);
+typedef size_t (_curl_write_callback2)(const char *, size_t, size_t,
+ const void*);
+typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE*);
+typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void*);
+typedef size_t (_curl_write_callback5)(const void *, size_t, size_t,
+ const void*);
+typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE*);
+
+/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */
+#define _curl_is_ioctl_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_ioctl_callback) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback1) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback2) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback3) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback4))
+typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void*);
+typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void*);
+typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void*);
+typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void*);
+
+/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */
+#define _curl_is_sockopt_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_sockopt_callback) || \
+ _curl_callback_compatible((expr), _curl_sockopt_callback1) || \
+ _curl_callback_compatible((expr), _curl_sockopt_callback2))
+typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype);
+typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t,
+ curlsocktype);
+
+/* evaluates to true if expr is of type curl_opensocket_callback or
+ "similar" */
+#define _curl_is_opensocket_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\
+ _curl_callback_compatible((expr), _curl_opensocket_callback1) || \
+ _curl_callback_compatible((expr), _curl_opensocket_callback2) || \
+ _curl_callback_compatible((expr), _curl_opensocket_callback3) || \
+ _curl_callback_compatible((expr), _curl_opensocket_callback4))
+typedef curl_socket_t (_curl_opensocket_callback1)
+ (void *, curlsocktype, struct curl_sockaddr *);
+typedef curl_socket_t (_curl_opensocket_callback2)
+ (void *, curlsocktype, const struct curl_sockaddr *);
+typedef curl_socket_t (_curl_opensocket_callback3)
+ (const void *, curlsocktype, struct curl_sockaddr *);
+typedef curl_socket_t (_curl_opensocket_callback4)
+ (const void *, curlsocktype, const struct curl_sockaddr *);
+
+/* evaluates to true if expr is of type curl_progress_callback or "similar" */
+#define _curl_is_progress_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_progress_callback) || \
+ _curl_callback_compatible((expr), _curl_progress_callback1) || \
+ _curl_callback_compatible((expr), _curl_progress_callback2))
+typedef int (_curl_progress_callback1)(void *,
+ double, double, double, double);
+typedef int (_curl_progress_callback2)(const void *,
+ double, double, double, double);
+
+/* evaluates to true if expr is of type curl_debug_callback or "similar" */
+#define _curl_is_debug_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_debug_callback) || \
+ _curl_callback_compatible((expr), _curl_debug_callback1) || \
+ _curl_callback_compatible((expr), _curl_debug_callback2) || \
+ _curl_callback_compatible((expr), _curl_debug_callback3) || \
+ _curl_callback_compatible((expr), _curl_debug_callback4) || \
+ _curl_callback_compatible((expr), _curl_debug_callback5) || \
+ _curl_callback_compatible((expr), _curl_debug_callback6) || \
+ _curl_callback_compatible((expr), _curl_debug_callback7) || \
+ _curl_callback_compatible((expr), _curl_debug_callback8))
+typedef int (_curl_debug_callback1) (CURL *,
+ curl_infotype, char *, size_t, void *);
+typedef int (_curl_debug_callback2) (CURL *,
+ curl_infotype, char *, size_t, const void *);
+typedef int (_curl_debug_callback3) (CURL *,
+ curl_infotype, const char *, size_t, void *);
+typedef int (_curl_debug_callback4) (CURL *,
+ curl_infotype, const char *, size_t, const void *);
+typedef int (_curl_debug_callback5) (CURL *,
+ curl_infotype, unsigned char *, size_t, void *);
+typedef int (_curl_debug_callback6) (CURL *,
+ curl_infotype, unsigned char *, size_t, const void *);
+typedef int (_curl_debug_callback7) (CURL *,
+ curl_infotype, const unsigned char *, size_t, void *);
+typedef int (_curl_debug_callback8) (CURL *,
+ curl_infotype, const unsigned char *, size_t, const void *);
+
+/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */
+/* this is getting even messier... */
+#define _curl_is_ssl_ctx_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_ssl_ctx_callback) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback8))
+typedef CURLcode (_curl_ssl_ctx_callback1)(CURL *, void *, void *);
+typedef CURLcode (_curl_ssl_ctx_callback2)(CURL *, void *, const void *);
+typedef CURLcode (_curl_ssl_ctx_callback3)(CURL *, const void *, void *);
+typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *);
+#ifdef HEADER_SSL_H
+/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
+ * this will of course break if we're included before OpenSSL headers...
+ */
+typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *);
+typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *);
+typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *);
+typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX,
+ const void *);
+#else
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8;
+#endif
+
+/* evaluates to true if expr is of type curl_conv_callback or "similar" */
+#define _curl_is_conv_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_conv_callback) || \
+ _curl_callback_compatible((expr), _curl_conv_callback1) || \
+ _curl_callback_compatible((expr), _curl_conv_callback2) || \
+ _curl_callback_compatible((expr), _curl_conv_callback3) || \
+ _curl_callback_compatible((expr), _curl_conv_callback4))
+typedef CURLcode (*_curl_conv_callback1)(char *, size_t length);
+typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length);
+typedef CURLcode (*_curl_conv_callback3)(void *, size_t length);
+typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length);
+
+/* evaluates to true if expr is of type curl_seek_callback or "similar" */
+#define _curl_is_seek_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_seek_callback) || \
+ _curl_callback_compatible((expr), _curl_seek_callback1) || \
+ _curl_callback_compatible((expr), _curl_seek_callback2))
+typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int);
+typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int);
+
+
+#endif /* __CURL_TYPECHECK_GCC_H */
diff --git a/external/libogg-1.3.2/CMakeLists.txt b/external/libogg-1.3.2/CMakeLists.txt
new file mode 100644
index 0000000..e2abfd6
--- /dev/null
+++ b/external/libogg-1.3.2/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_library (
+ ogg STATIC
+ include/ogg/config_types.h
+ include/ogg/ogg.h
+ include/ogg/os_types.h
+ src/bitwise.c
+ src/framing.c
+ )
+
+include_directories(include)
diff --git a/external/libogg-1.3.2/include/ogg/config_types.h b/external/libogg-1.3.2/include/ogg/config_types.h
new file mode 100644
index 0000000..2828827
--- /dev/null
+++ b/external/libogg-1.3.2/include/ogg/config_types.h
@@ -0,0 +1,25 @@
+#ifndef __CONFIG_TYPES_H__
+#define __CONFIG_TYPES_H__
+
+/* these are filled in by configure */
+/* #define INCLUDE_INTTYPES_H 1 */
+#define INCLUDE_STDINT_H 1
+/* #define INCLUDE_SYS_TYPES_H 1 */
+
+#if INCLUDE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#if INCLUDE_STDINT_H
+# include <stdint.h>
+#endif
+#if INCLUDE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+typedef int16_t ogg_int16_t;
+typedef uint16_t ogg_uint16_t;
+typedef int32_t ogg_int32_t;
+typedef uint32_t ogg_uint32_t;
+typedef int64_t ogg_int64_t;
+
+#endif
diff --git a/external/libogg-1.3.2/include/ogg/ogg.h b/external/libogg-1.3.2/include/ogg/ogg.h
new file mode 100644
index 0000000..cea4ebe
--- /dev/null
+++ b/external/libogg-1.3.2/include/ogg/ogg.h
@@ -0,0 +1,210 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel libogg include
+ last mod: $Id: ogg.h 18044 2011-08-01 17:55:20Z gmaxwell $
+
+ ********************************************************************/
+#ifndef _OGG_H
+#define _OGG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <ogg/os_types.h>
+
+typedef struct {
+ void *iov_base;
+ size_t iov_len;
+} ogg_iovec_t;
+
+typedef struct {
+ long endbyte;
+ int endbit;
+
+ unsigned char *buffer;
+ unsigned char *ptr;
+ long storage;
+} oggpack_buffer;
+
+/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
+
+typedef struct {
+ unsigned char *header;
+ long header_len;
+ unsigned char *body;
+ long body_len;
+} ogg_page;
+
+/* ogg_stream_state contains the current encode/decode state of a logical
+ Ogg bitstream **********************************************************/
+
+typedef struct {
+ unsigned char *body_data; /* bytes from packet bodies */
+ long body_storage; /* storage elements allocated */
+ long body_fill; /* elements stored; fill mark */
+ long body_returned; /* elements of fill returned */
+
+
+ int *lacing_vals; /* The values that will go to the segment table */
+ ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
+ this way, but it is simple coupled to the
+ lacing fifo */
+ long lacing_storage;
+ long lacing_fill;
+ long lacing_packet;
+ long lacing_returned;
+
+ unsigned char header[282]; /* working space for header encode */
+ int header_fill;
+
+ int e_o_s; /* set when we have buffered the last packet in the
+ logical bitstream */
+ int b_o_s; /* set after we've written the initial page
+ of a logical bitstream */
+ long serialno;
+ long pageno;
+ ogg_int64_t packetno; /* sequence number for decode; the framing
+ knows where there's a hole in the data,
+ but we need coupling so that the codec
+ (which is in a separate abstraction
+ layer) also knows about the gap */
+ ogg_int64_t granulepos;
+
+} ogg_stream_state;
+
+/* ogg_packet is used to encapsulate the data and metadata belonging
+ to a single raw Ogg/Vorbis packet *************************************/
+
+typedef struct {
+ unsigned char *packet;
+ long bytes;
+ long b_o_s;
+ long e_o_s;
+
+ ogg_int64_t granulepos;
+
+ ogg_int64_t packetno; /* sequence number for decode; the framing
+ knows where there's a hole in the data,
+ but we need coupling so that the codec
+ (which is in a separate abstraction
+ layer) also knows about the gap */
+} ogg_packet;
+
+typedef struct {
+ unsigned char *data;
+ int storage;
+ int fill;
+ int returned;
+
+ int unsynced;
+ int headerbytes;
+ int bodybytes;
+} ogg_sync_state;
+
+/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
+
+extern void oggpack_writeinit(oggpack_buffer *b);
+extern int oggpack_writecheck(oggpack_buffer *b);
+extern void oggpack_writetrunc(oggpack_buffer *b,long bits);
+extern void oggpack_writealign(oggpack_buffer *b);
+extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits);
+extern void oggpack_reset(oggpack_buffer *b);
+extern void oggpack_writeclear(oggpack_buffer *b);
+extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
+extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
+extern long oggpack_look(oggpack_buffer *b,int bits);
+extern long oggpack_look1(oggpack_buffer *b);
+extern void oggpack_adv(oggpack_buffer *b,int bits);
+extern void oggpack_adv1(oggpack_buffer *b);
+extern long oggpack_read(oggpack_buffer *b,int bits);
+extern long oggpack_read1(oggpack_buffer *b);
+extern long oggpack_bytes(oggpack_buffer *b);
+extern long oggpack_bits(oggpack_buffer *b);
+extern unsigned char *oggpack_get_buffer(oggpack_buffer *b);
+
+extern void oggpackB_writeinit(oggpack_buffer *b);
+extern int oggpackB_writecheck(oggpack_buffer *b);
+extern void oggpackB_writetrunc(oggpack_buffer *b,long bits);
+extern void oggpackB_writealign(oggpack_buffer *b);
+extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits);
+extern void oggpackB_reset(oggpack_buffer *b);
+extern void oggpackB_writeclear(oggpack_buffer *b);
+extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
+extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits);
+extern long oggpackB_look(oggpack_buffer *b,int bits);
+extern long oggpackB_look1(oggpack_buffer *b);
+extern void oggpackB_adv(oggpack_buffer *b,int bits);
+extern void oggpackB_adv1(oggpack_buffer *b);
+extern long oggpackB_read(oggpack_buffer *b,int bits);
+extern long oggpackB_read1(oggpack_buffer *b);
+extern long oggpackB_bytes(oggpack_buffer *b);
+extern long oggpackB_bits(oggpack_buffer *b);
+extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b);
+
+/* Ogg BITSTREAM PRIMITIVES: encoding **************************/
+
+extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
+extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov,
+ int count, long e_o_s, ogg_int64_t granulepos);
+extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
+extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill);
+extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
+extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill);
+
+/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
+
+extern int ogg_sync_init(ogg_sync_state *oy);
+extern int ogg_sync_clear(ogg_sync_state *oy);
+extern int ogg_sync_reset(ogg_sync_state *oy);
+extern int ogg_sync_destroy(ogg_sync_state *oy);
+extern int ogg_sync_check(ogg_sync_state *oy);
+
+extern char *ogg_sync_buffer(ogg_sync_state *oy, long size);
+extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
+extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
+extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
+extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
+extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
+extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
+
+/* Ogg BITSTREAM PRIMITIVES: general ***************************/
+
+extern int ogg_stream_init(ogg_stream_state *os,int serialno);
+extern int ogg_stream_clear(ogg_stream_state *os);
+extern int ogg_stream_reset(ogg_stream_state *os);
+extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
+extern int ogg_stream_destroy(ogg_stream_state *os);
+extern int ogg_stream_check(ogg_stream_state *os);
+extern int ogg_stream_eos(ogg_stream_state *os);
+
+extern void ogg_page_checksum_set(ogg_page *og);
+
+extern int ogg_page_version(const ogg_page *og);
+extern int ogg_page_continued(const ogg_page *og);
+extern int ogg_page_bos(const ogg_page *og);
+extern int ogg_page_eos(const ogg_page *og);
+extern ogg_int64_t ogg_page_granulepos(const ogg_page *og);
+extern int ogg_page_serialno(const ogg_page *og);
+extern long ogg_page_pageno(const ogg_page *og);
+extern int ogg_page_packets(const ogg_page *og);
+
+extern void ogg_packet_clear(ogg_packet *op);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OGG_H */
diff --git a/external/libogg-1.3.2/include/ogg/os_types.h b/external/libogg-1.3.2/include/ogg/os_types.h
new file mode 100644
index 0000000..8bf8210
--- /dev/null
+++ b/external/libogg-1.3.2/include/ogg/os_types.h
@@ -0,0 +1,147 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: #ifdef jail to whip a few platforms into the UNIX ideal.
+ last mod: $Id: os_types.h 19098 2014-02-26 19:06:45Z giles $
+
+ ********************************************************************/
+#ifndef _OS_TYPES_H
+#define _OS_TYPES_H
+
+/* make it easy on the folks that want to compile the libs with a
+ different malloc than stdlib */
+#define _ogg_malloc malloc
+#define _ogg_calloc calloc
+#define _ogg_realloc realloc
+#define _ogg_free free
+
+#if defined(_WIN32)
+
+# if defined(__CYGWIN__)
+# include <stdint.h>
+ typedef int16_t ogg_int16_t;
+ typedef uint16_t ogg_uint16_t;
+ typedef int32_t ogg_int32_t;
+ typedef uint32_t ogg_uint32_t;
+ typedef int64_t ogg_int64_t;
+ typedef uint64_t ogg_uint64_t;
+# elif defined(__MINGW32__)
+# include <sys/types.h>
+ typedef short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long ogg_int64_t;
+ typedef unsigned long long ogg_uint64_t;
+# elif defined(__MWERKS__)
+ typedef long long ogg_int64_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+# else
+ /* MSVC/Borland */
+ typedef __int64 ogg_int64_t;
+ typedef __int32 ogg_int32_t;
+ typedef unsigned __int32 ogg_uint32_t;
+ typedef __int16 ogg_int16_t;
+ typedef unsigned __int16 ogg_uint16_t;
+# endif
+
+#elif defined(__MACOS__)
+
+# include <sys/types.h>
+ typedef SInt16 ogg_int16_t;
+ typedef UInt16 ogg_uint16_t;
+ typedef SInt32 ogg_int32_t;
+ typedef UInt32 ogg_uint32_t;
+ typedef SInt64 ogg_int64_t;
+
+#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
+
+# include <inttypes.h>
+ typedef int16_t ogg_int16_t;
+ typedef uint16_t ogg_uint16_t;
+ typedef int32_t ogg_int32_t;
+ typedef uint32_t ogg_uint32_t;
+ typedef int64_t ogg_int64_t;
+
+#elif defined(__HAIKU__)
+
+ /* Haiku */
+# include <sys/types.h>
+ typedef short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long ogg_int64_t;
+
+#elif defined(__BEOS__)
+
+ /* Be */
+# include <inttypes.h>
+ typedef int16_t ogg_int16_t;
+ typedef uint16_t ogg_uint16_t;
+ typedef int32_t ogg_int32_t;
+ typedef uint32_t ogg_uint32_t;
+ typedef int64_t ogg_int64_t;
+
+#elif defined (__EMX__)
+
+ /* OS/2 GCC */
+ typedef short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long ogg_int64_t;
+
+#elif defined (DJGPP)
+
+ /* DJGPP */
+ typedef short ogg_int16_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long ogg_int64_t;
+
+#elif defined(R5900)
+
+ /* PS2 EE */
+ typedef long ogg_int64_t;
+ typedef int ogg_int32_t;
+ typedef unsigned ogg_uint32_t;
+ typedef short ogg_int16_t;
+
+#elif defined(__SYMBIAN32__)
+
+ /* Symbian GCC */
+ typedef signed short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef signed int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long int ogg_int64_t;
+
+#elif defined(__TMS320C6X__)
+
+ /* TI C64x compiler */
+ typedef signed short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef signed int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long int ogg_int64_t;
+
+#else
+
+# include <ogg/config_types.h>
+
+#endif
+
+#endif /* _OS_TYPES_H */
diff --git a/external/libogg-1.3.2/src/bitwise.c b/external/libogg-1.3.2/src/bitwise.c
new file mode 100644
index 0000000..145901d
--- /dev/null
+++ b/external/libogg-1.3.2/src/bitwise.c
@@ -0,0 +1,1088 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2014 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: packing variable sized words into an octet stream
+ last mod: $Id: bitwise.c 19149 2014-05-27 16:26:23Z giles $
+
+ ********************************************************************/
+
+/* We're 'LSb' endian; if we write a word but read individual bits,
+ then we'll read the lsb first */
+
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ogg/ogg.h>
+
+#define BUFFER_INCREMENT 256
+
+static const unsigned long mask[]=
+{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f,
+ 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff,
+ 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff,
+ 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
+ 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff,
+ 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,
+ 0x3fffffff,0x7fffffff,0xffffffff };
+
+static const unsigned int mask8B[]=
+{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};
+
+void oggpack_writeinit(oggpack_buffer *b){
+ memset(b,0,sizeof(*b));
+ b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT);
+ b->buffer[0]='\0';
+ b->storage=BUFFER_INCREMENT;
+}
+
+void oggpackB_writeinit(oggpack_buffer *b){
+ oggpack_writeinit(b);
+}
+
+int oggpack_writecheck(oggpack_buffer *b){
+ if(!b->ptr || !b->storage)return -1;
+ return 0;
+}
+
+int oggpackB_writecheck(oggpack_buffer *b){
+ return oggpack_writecheck(b);
+}
+
+void oggpack_writetrunc(oggpack_buffer *b,long bits){
+ long bytes=bits>>3;
+ if(b->ptr){
+ bits-=bytes*8;
+ b->ptr=b->buffer+bytes;
+ b->endbit=bits;
+ b->endbyte=bytes;
+ *b->ptr&=mask[bits];
+ }
+}
+
+void oggpackB_writetrunc(oggpack_buffer *b,long bits){
+ long bytes=bits>>3;
+ if(b->ptr){
+ bits-=bytes*8;
+ b->ptr=b->buffer+bytes;
+ b->endbit=bits;
+ b->endbyte=bytes;
+ *b->ptr&=mask8B[bits];
+ }
+}
+
+/* Takes only up to 32 bits. */
+void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){
+ if(bits<0 || bits>32) goto err;
+ if(b->endbyte>=b->storage-4){
+ void *ret;
+ if(!b->ptr)return;
+ if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err;
+ ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT);
+ if(!ret) goto err;
+ b->buffer=ret;
+ b->storage+=BUFFER_INCREMENT;
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ value&=mask[bits];
+ bits+=b->endbit;
+
+ b->ptr[0]|=value<<b->endbit;
+
+ if(bits>=8){
+ b->ptr[1]=(unsigned char)(value>>(8-b->endbit));
+ if(bits>=16){
+ b->ptr[2]=(unsigned char)(value>>(16-b->endbit));
+ if(bits>=24){
+ b->ptr[3]=(unsigned char)(value>>(24-b->endbit));
+ if(bits>=32){
+ if(b->endbit)
+ b->ptr[4]=(unsigned char)(value>>(32-b->endbit));
+ else
+ b->ptr[4]=0;
+ }
+ }
+ }
+ }
+
+ b->endbyte+=bits/8;
+ b->ptr+=bits/8;
+ b->endbit=bits&7;
+ return;
+ err:
+ oggpack_writeclear(b);
+}
+
+/* Takes only up to 32 bits. */
+void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){
+ if(bits<0 || bits>32) goto err;
+ if(b->endbyte>=b->storage-4){
+ void *ret;
+ if(!b->ptr)return;
+ if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err;
+ ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT);
+ if(!ret) goto err;
+ b->buffer=ret;
+ b->storage+=BUFFER_INCREMENT;
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ value=(value&mask[bits])<<(32-bits);
+ bits+=b->endbit;
+
+ b->ptr[0]|=value>>(24+b->endbit);
+
+ if(bits>=8){
+ b->ptr[1]=(unsigned char)(value>>(16+b->endbit));
+ if(bits>=16){
+ b->ptr[2]=(unsigned char)(value>>(8+b->endbit));
+ if(bits>=24){
+ b->ptr[3]=(unsigned char)(value>>(b->endbit));
+ if(bits>=32){
+ if(b->endbit)
+ b->ptr[4]=(unsigned char)(value<<(8-b->endbit));
+ else
+ b->ptr[4]=0;
+ }
+ }
+ }
+ }
+
+ b->endbyte+=bits/8;
+ b->ptr+=bits/8;
+ b->endbit=bits&7;
+ return;
+ err:
+ oggpack_writeclear(b);
+}
+
+void oggpack_writealign(oggpack_buffer *b){
+ int bits=8-b->endbit;
+ if(bits<8)
+ oggpack_write(b,0,bits);
+}
+
+void oggpackB_writealign(oggpack_buffer *b){
+ int bits=8-b->endbit;
+ if(bits<8)
+ oggpackB_write(b,0,bits);
+}
+
+static void oggpack_writecopy_helper(oggpack_buffer *b,
+ void *source,
+ long bits,
+ void (*w)(oggpack_buffer *,
+ unsigned long,
+ int),
+ int msb){
+ unsigned char *ptr=(unsigned char *)source;
+
+ long bytes=bits/8;
+ long pbytes=(b->endbit+bits)/8;
+ bits-=bytes*8;
+
+ /* expand storage up-front */
+ if(b->endbyte+pbytes>=b->storage){
+ void *ret;
+ if(!b->ptr) goto err;
+ if(b->storage>b->endbyte+pbytes+BUFFER_INCREMENT) goto err;
+ b->storage=b->endbyte+pbytes+BUFFER_INCREMENT;
+ ret=_ogg_realloc(b->buffer,b->storage);
+ if(!ret) goto err;
+ b->buffer=ret;
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ /* copy whole octets */
+ if(b->endbit){
+ int i;
+ /* unaligned copy. Do it the hard way. */
+ for(i=0;i<bytes;i++)
+ w(b,(unsigned long)(ptr[i]),8);
+ }else{
+ /* aligned block copy */
+ memmove(b->ptr,source,bytes);
+ b->ptr+=bytes;
+ b->endbyte+=bytes;
+ *b->ptr=0;
+ }
+
+ /* copy trailing bits */
+ if(bits){
+ if(msb)
+ w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits);
+ else
+ w(b,(unsigned long)(ptr[bytes]),bits);
+ }
+ return;
+ err:
+ oggpack_writeclear(b);
+}
+
+void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){
+ oggpack_writecopy_helper(b,source,bits,oggpack_write,0);
+}
+
+void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){
+ oggpack_writecopy_helper(b,source,bits,oggpackB_write,1);
+}
+
+void oggpack_reset(oggpack_buffer *b){
+ if(!b->ptr)return;
+ b->ptr=b->buffer;
+ b->buffer[0]=0;
+ b->endbit=b->endbyte=0;
+}
+
+void oggpackB_reset(oggpack_buffer *b){
+ oggpack_reset(b);
+}
+
+void oggpack_writeclear(oggpack_buffer *b){
+ if(b->buffer)_ogg_free(b->buffer);
+ memset(b,0,sizeof(*b));
+}
+
+void oggpackB_writeclear(oggpack_buffer *b){
+ oggpack_writeclear(b);
+}
+
+void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
+ memset(b,0,sizeof(*b));
+ b->buffer=b->ptr=buf;
+ b->storage=bytes;
+}
+
+void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
+ oggpack_readinit(b,buf,bytes);
+}
+
+/* Read in bits without advancing the bitptr; bits <= 32 */
+long oggpack_look(oggpack_buffer *b,int bits){
+ unsigned long ret;
+ unsigned long m;
+
+ if(bits<0 || bits>32) return -1;
+ m=mask[bits];
+ bits+=b->endbit;
+
+ if(b->endbyte >= b->storage-4){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) return -1;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
+
+ ret=b->ptr[0]>>b->endbit;
+ if(bits>8){
+ ret|=b->ptr[1]<<(8-b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(16-b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(24-b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]<<(32-b->endbit);
+ }
+ }
+ }
+ return(m&ret);
+}
+
+/* Read in bits without advancing the bitptr; bits <= 32 */
+long oggpackB_look(oggpack_buffer *b,int bits){
+ unsigned long ret;
+ int m=32-bits;
+
+ if(m<0 || m>32) return -1;
+ bits+=b->endbit;
+
+ if(b->endbyte >= b->storage-4){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) return -1;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
+
+ ret=b->ptr[0]<<(24+b->endbit);
+ if(bits>8){
+ ret|=b->ptr[1]<<(16+b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(8+b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]>>(8-b->endbit);
+ }
+ }
+ }
+ return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1);
+}
+
+long oggpack_look1(oggpack_buffer *b){
+ if(b->endbyte>=b->storage)return(-1);
+ return((b->ptr[0]>>b->endbit)&1);
+}
+
+long oggpackB_look1(oggpack_buffer *b){
+ if(b->endbyte>=b->storage)return(-1);
+ return((b->ptr[0]>>(7-b->endbit))&1);
+}
+
+void oggpack_adv(oggpack_buffer *b,int bits){
+ bits+=b->endbit;
+
+ if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
+
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+ return;
+
+ overflow:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+}
+
+void oggpackB_adv(oggpack_buffer *b,int bits){
+ oggpack_adv(b,bits);
+}
+
+void oggpack_adv1(oggpack_buffer *b){
+ if(++(b->endbit)>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+}
+
+void oggpackB_adv1(oggpack_buffer *b){
+ oggpack_adv1(b);
+}
+
+/* bits <= 32 */
+long oggpack_read(oggpack_buffer *b,int bits){
+ long ret;
+ unsigned long m;
+
+ if(bits<0 || bits>32) goto err;
+ m=mask[bits];
+ bits+=b->endbit;
+
+ if(b->endbyte >= b->storage-4){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
+
+ ret=b->ptr[0]>>b->endbit;
+ if(bits>8){
+ ret|=b->ptr[1]<<(8-b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(16-b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(24-b->endbit);
+ if(bits>32 && b->endbit){
+ ret|=b->ptr[4]<<(32-b->endbit);
+ }
+ }
+ }
+ }
+ ret&=m;
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+ return ret;
+
+ overflow:
+ err:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
+}
+
+/* bits <= 32 */
+long oggpackB_read(oggpack_buffer *b,int bits){
+ long ret;
+ long m=32-bits;
+
+ if(m<0 || m>32) goto err;
+ bits+=b->endbit;
+
+ if(b->endbyte+4>=b->storage){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
+
+ ret=b->ptr[0]<<(24+b->endbit);
+ if(bits>8){
+ ret|=b->ptr[1]<<(16+b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(8+b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]>>(8-b->endbit);
+ }
+ }
+ }
+ ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1);
+
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+ return ret;
+
+ overflow:
+ err:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
+}
+
+long oggpack_read1(oggpack_buffer *b){
+ long ret;
+
+ if(b->endbyte >= b->storage) goto overflow;
+ ret=(b->ptr[0]>>b->endbit)&1;
+
+ b->endbit++;
+ if(b->endbit>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+ return ret;
+
+ overflow:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
+}
+
+long oggpackB_read1(oggpack_buffer *b){
+ long ret;
+
+ if(b->endbyte >= b->storage) goto overflow;
+ ret=(b->ptr[0]>>(7-b->endbit))&1;
+
+ b->endbit++;
+ if(b->endbit>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+ return ret;
+
+ overflow:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
+}
+
+long oggpack_bytes(oggpack_buffer *b){
+ return(b->endbyte+(b->endbit+7)/8);
+}
+
+long oggpack_bits(oggpack_buffer *b){
+ return(b->endbyte*8+b->endbit);
+}
+
+long oggpackB_bytes(oggpack_buffer *b){
+ return oggpack_bytes(b);
+}
+
+long oggpackB_bits(oggpack_buffer *b){
+ return oggpack_bits(b);
+}
+
+unsigned char *oggpack_get_buffer(oggpack_buffer *b){
+ return(b->buffer);
+}
+
+unsigned char *oggpackB_get_buffer(oggpack_buffer *b){
+ return oggpack_get_buffer(b);
+}
+
+/* Self test of the bitwise routines; everything else is based on
+ them, so they damned well better be solid. */
+
+#ifdef _V_SELFTEST
+#include <stdio.h>
+
+static int ilog(unsigned int v){
+ int ret=0;
+ while(v){
+ ret++;
+ v>>=1;
+ }
+ return(ret);
+}
+
+oggpack_buffer o;
+oggpack_buffer r;
+
+void report(char *in){
+ fprintf(stderr,"%s",in);
+ exit(1);
+}
+
+void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){
+ long bytes,i;
+ unsigned char *buffer;
+
+ oggpack_reset(&o);
+ for(i=0;i<vals;i++)
+ oggpack_write(&o,b[i],bits?bits:ilog(b[i]));
+ buffer=oggpack_get_buffer(&o);
+ bytes=oggpack_bytes(&o);
+ if(bytes!=compsize)report("wrong number of bytes!\n");
+ for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){
+ for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]);
+ report("wrote incorrect value!\n");
+ }
+ oggpack_readinit(&r,buffer,bytes);
+ for(i=0;i<vals;i++){
+ int tbit=bits?bits:ilog(b[i]);
+ if(oggpack_look(&r,tbit)==-1)
+ report("out of data!\n");
+ if(oggpack_look(&r,tbit)!=(b[i]&mask[tbit]))
+ report("looked at incorrect value!\n");
+ if(tbit==1)
+ if(oggpack_look1(&r)!=(b[i]&mask[tbit]))
+ report("looked at single bit incorrect value!\n");
+ if(tbit==1){
+ if(oggpack_read1(&r)!=(b[i]&mask[tbit]))
+ report("read incorrect single bit value!\n");
+ }else{
+ if(oggpack_read(&r,tbit)!=(b[i]&mask[tbit]))
+ report("read incorrect value!\n");
+ }
+ }
+ if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+}
+
+void cliptestB(unsigned long *b,int vals,int bits,int *comp,int compsize){
+ long bytes,i;
+ unsigned char *buffer;
+
+ oggpackB_reset(&o);
+ for(i=0;i<vals;i++)
+ oggpackB_write(&o,b[i],bits?bits:ilog(b[i]));
+ buffer=oggpackB_get_buffer(&o);
+ bytes=oggpackB_bytes(&o);
+ if(bytes!=compsize)report("wrong number of bytes!\n");
+ for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){
+ for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]);
+ report("wrote incorrect value!\n");
+ }
+ oggpackB_readinit(&r,buffer,bytes);
+ for(i=0;i<vals;i++){
+ int tbit=bits?bits:ilog(b[i]);
+ if(oggpackB_look(&r,tbit)==-1)
+ report("out of data!\n");
+ if(oggpackB_look(&r,tbit)!=(b[i]&mask[tbit]))
+ report("looked at incorrect value!\n");
+ if(tbit==1)
+ if(oggpackB_look1(&r)!=(b[i]&mask[tbit]))
+ report("looked at single bit incorrect value!\n");
+ if(tbit==1){
+ if(oggpackB_read1(&r)!=(b[i]&mask[tbit]))
+ report("read incorrect single bit value!\n");
+ }else{
+ if(oggpackB_read(&r,tbit)!=(b[i]&mask[tbit]))
+ report("read incorrect value!\n");
+ }
+ }
+ if(oggpackB_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+}
+
+void copytest(int prefill, int copy){
+ oggpack_buffer source_write;
+ oggpack_buffer dest_write;
+ oggpack_buffer source_read;
+ oggpack_buffer dest_read;
+ unsigned char *source;
+ unsigned char *dest;
+ long source_bytes,dest_bytes;
+ int i;
+
+ oggpack_writeinit(&source_write);
+ oggpack_writeinit(&dest_write);
+
+ for(i=0;i<(prefill+copy+7)/8;i++)
+ oggpack_write(&source_write,(i^0x5a)&0xff,8);
+ source=oggpack_get_buffer(&source_write);
+ source_bytes=oggpack_bytes(&source_write);
+
+ /* prefill */
+ oggpack_writecopy(&dest_write,source,prefill);
+
+ /* check buffers; verify end byte masking */
+ dest=oggpack_get_buffer(&dest_write);
+ dest_bytes=oggpack_bytes(&dest_write);
+ if(dest_bytes!=(prefill+7)/8){
+ fprintf(stderr,"wrong number of bytes after prefill! %ld!=%d\n",dest_bytes,(prefill+7)/8);
+ exit(1);
+ }
+ oggpack_readinit(&source_read,source,source_bytes);
+ oggpack_readinit(&dest_read,dest,dest_bytes);
+
+ for(i=0;i<prefill;i+=8){
+ int s=oggpack_read(&source_read,prefill-i<8?prefill-i:8);
+ int d=oggpack_read(&dest_read,prefill-i<8?prefill-i:8);
+ if(s!=d){
+ fprintf(stderr,"prefill=%d mismatch! byte %d, %x!=%x\n",prefill,i/8,s,d);
+ exit(1);
+ }
+ }
+ if(prefill<dest_bytes){
+ if(oggpack_read(&dest_read,dest_bytes-prefill)!=0){
+ fprintf(stderr,"prefill=%d mismatch! trailing bits not zero\n",prefill);
+ exit(1);
+ }
+ }
+
+ /* second copy */
+ oggpack_writecopy(&dest_write,source,copy);
+
+ /* check buffers; verify end byte masking */
+ dest=oggpack_get_buffer(&dest_write);
+ dest_bytes=oggpack_bytes(&dest_write);
+ if(dest_bytes!=(copy+prefill+7)/8){
+ fprintf(stderr,"wrong number of bytes after prefill+copy! %ld!=%d\n",dest_bytes,(copy+prefill+7)/8);
+ exit(1);
+ }
+ oggpack_readinit(&source_read,source,source_bytes);
+ oggpack_readinit(&dest_read,dest,dest_bytes);
+
+ for(i=0;i<prefill;i+=8){
+ int s=oggpack_read(&source_read,prefill-i<8?prefill-i:8);
+ int d=oggpack_read(&dest_read,prefill-i<8?prefill-i:8);
+ if(s!=d){
+ fprintf(stderr,"prefill=%d mismatch! byte %d, %x!=%x\n",prefill,i/8,s,d);
+ exit(1);
+ }
+ }
+
+ oggpack_readinit(&source_read,source,source_bytes);
+ for(i=0;i<copy;i+=8){
+ int s=oggpack_read(&source_read,copy-i<8?copy-i:8);
+ int d=oggpack_read(&dest_read,copy-i<8?copy-i:8);
+ if(s!=d){
+ fprintf(stderr,"prefill=%d copy=%d mismatch! byte %d, %x!=%x\n",prefill,copy,i/8,s,d);
+ exit(1);
+ }
+ }
+
+ if(copy+prefill<dest_bytes){
+ if(oggpack_read(&dest_read,dest_bytes-copy-prefill)!=0){
+ fprintf(stderr,"prefill=%d copy=%d mismatch! trailing bits not zero\n",prefill,copy);
+ exit(1);
+ }
+ }
+
+ oggpack_writeclear(&source_write);
+ oggpack_writeclear(&dest_write);
+
+
+}
+
+void copytestB(int prefill, int copy){
+ oggpack_buffer source_write;
+ oggpack_buffer dest_write;
+ oggpack_buffer source_read;
+ oggpack_buffer dest_read;
+ unsigned char *source;
+ unsigned char *dest;
+ long source_bytes,dest_bytes;
+ int i;
+
+ oggpackB_writeinit(&source_write);
+ oggpackB_writeinit(&dest_write);
+
+ for(i=0;i<(prefill+copy+7)/8;i++)
+ oggpackB_write(&source_write,(i^0x5a)&0xff,8);
+ source=oggpackB_get_buffer(&source_write);
+ source_bytes=oggpackB_bytes(&source_write);
+
+ /* prefill */
+ oggpackB_writecopy(&dest_write,source,prefill);
+
+ /* check buffers; verify end byte masking */
+ dest=oggpackB_get_buffer(&dest_write);
+ dest_bytes=oggpackB_bytes(&dest_write);
+ if(dest_bytes!=(prefill+7)/8){
+ fprintf(stderr,"wrong number of bytes after prefill! %ld!=%d\n",dest_bytes,(prefill+7)/8);
+ exit(1);
+ }
+ oggpackB_readinit(&source_read,source,source_bytes);
+ oggpackB_readinit(&dest_read,dest,dest_bytes);
+
+ for(i=0;i<prefill;i+=8){
+ int s=oggpackB_read(&source_read,prefill-i<8?prefill-i:8);
+ int d=oggpackB_read(&dest_read,prefill-i<8?prefill-i:8);
+ if(s!=d){
+ fprintf(stderr,"prefill=%d mismatch! byte %d, %x!=%x\n",prefill,i/8,s,d);
+ exit(1);
+ }
+ }
+ if(prefill<dest_bytes){
+ if(oggpackB_read(&dest_read,dest_bytes-prefill)!=0){
+ fprintf(stderr,"prefill=%d mismatch! trailing bits not zero\n",prefill);
+ exit(1);
+ }
+ }
+
+ /* second copy */
+ oggpackB_writecopy(&dest_write,source,copy);
+
+ /* check buffers; verify end byte masking */
+ dest=oggpackB_get_buffer(&dest_write);
+ dest_bytes=oggpackB_bytes(&dest_write);
+ if(dest_bytes!=(copy+prefill+7)/8){
+ fprintf(stderr,"wrong number of bytes after prefill+copy! %ld!=%d\n",dest_bytes,(copy+prefill+7)/8);
+ exit(1);
+ }
+ oggpackB_readinit(&source_read,source,source_bytes);
+ oggpackB_readinit(&dest_read,dest,dest_bytes);
+
+ for(i=0;i<prefill;i+=8){
+ int s=oggpackB_read(&source_read,prefill-i<8?prefill-i:8);
+ int d=oggpackB_read(&dest_read,prefill-i<8?prefill-i:8);
+ if(s!=d){
+ fprintf(stderr,"prefill=%d mismatch! byte %d, %x!=%x\n",prefill,i/8,s,d);
+ exit(1);
+ }
+ }
+
+ oggpackB_readinit(&source_read,source,source_bytes);
+ for(i=0;i<copy;i+=8){
+ int s=oggpackB_read(&source_read,copy-i<8?copy-i:8);
+ int d=oggpackB_read(&dest_read,copy-i<8?copy-i:8);
+ if(s!=d){
+ fprintf(stderr,"prefill=%d copy=%d mismatch! byte %d, %x!=%x\n",prefill,copy,i/8,s,d);
+ exit(1);
+ }
+ }
+
+ if(copy+prefill<dest_bytes){
+ if(oggpackB_read(&dest_read,dest_bytes-copy-prefill)!=0){
+ fprintf(stderr,"prefill=%d copy=%d mismatch! trailing bits not zero\n",prefill,copy);
+ exit(1);
+ }
+ }
+
+ oggpackB_writeclear(&source_write);
+ oggpackB_writeclear(&dest_write);
+
+}
+
+int main(void){
+ unsigned char *buffer;
+ long bytes,i,j;
+ static unsigned long testbuffer1[]=
+ {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7,
+ 567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4};
+ int test1size=43;
+
+ static unsigned long testbuffer2[]=
+ {216531625L,1237861823,56732452,131,3212421,12325343,34547562,12313212,
+ 1233432,534,5,346435231,14436467,7869299,76326614,167548585,
+ 85525151,0,12321,1,349528352};
+ int test2size=21;
+
+ static unsigned long testbuffer3[]=
+ {1,0,14,0,1,0,12,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1,
+ 0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1};
+ int test3size=56;
+
+ static unsigned long large[]=
+ {2136531625L,2137861823,56732452,131,3212421,12325343,34547562,12313212,
+ 1233432,534,5,2146435231,14436467,7869299,76326614,167548585,
+ 85525151,0,12321,1,2146528352};
+
+ int onesize=33;
+ static int one[33]={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40,
+ 34,242,223,136,35,222,211,86,171,50,225,135,214,75,172,
+ 223,4};
+ static int oneB[33]={150,101,131,33,203,15,204,216,105,193,156,65,84,85,222,
+ 8,139,145,227,126,34,55,244,171,85,100,39,195,173,18,
+ 245,251,128};
+
+ int twosize=6;
+ static int two[6]={61,255,255,251,231,29};
+ static int twoB[6]={247,63,255,253,249,120};
+
+ int threesize=54;
+ static int three[54]={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254,
+ 142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83,
+ 58,135,196,61,55,129,183,54,101,100,170,37,127,126,10,
+ 100,52,4,14,18,86,77,1};
+ static int threeB[54]={206,128,42,153,57,8,183,251,13,89,36,30,32,144,183,
+ 130,59,240,121,59,85,223,19,228,180,134,33,107,74,98,
+ 233,253,196,135,63,2,110,114,50,155,90,127,37,170,104,
+ 200,20,254,4,58,106,176,144,0};
+
+ int foursize=38;
+ static int four[38]={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72,
+ 132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169,
+ 28,2,133,0,1};
+ static int fourB[38]={36,48,102,83,243,24,52,7,4,35,132,10,145,21,2,93,2,41,
+ 1,219,184,16,33,184,54,149,170,132,18,30,29,98,229,67,
+ 129,10,4,32};
+
+ int fivesize=45;
+ static int five[45]={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62,
+ 241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169,
+ 84,75,159,2,1,0,132,192,8,0,0,18,22};
+ static int fiveB[45]={1,84,145,111,245,100,128,8,56,36,40,71,126,78,213,226,
+ 124,105,12,0,133,128,0,162,233,242,67,152,77,205,77,
+ 172,150,169,129,79,128,0,6,4,32,0,27,9,0};
+
+ int sixsize=7;
+ static int six[7]={17,177,170,242,169,19,148};
+ static int sixB[7]={136,141,85,79,149,200,41};
+
+ /* Test read/write together */
+ /* Later we test against pregenerated bitstreams */
+ oggpack_writeinit(&o);
+
+ fprintf(stderr,"\nSmall preclipped packing (LSb): ");
+ cliptest(testbuffer1,test1size,0,one,onesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nNull bit call (LSb): ");
+ cliptest(testbuffer3,test3size,0,two,twosize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge preclipped packing (LSb): ");
+ cliptest(testbuffer2,test2size,0,three,threesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\n32 bit preclipped packing (LSb): ");
+ oggpack_reset(&o);
+ for(i=0;i<test2size;i++)
+ oggpack_write(&o,large[i],32);
+ buffer=oggpack_get_buffer(&o);
+ bytes=oggpack_bytes(&o);
+ oggpack_readinit(&r,buffer,bytes);
+ for(i=0;i<test2size;i++){
+ if(oggpack_look(&r,32)==-1)report("out of data. failed!");
+ if(oggpack_look(&r,32)!=large[i]){
+ fprintf(stderr,"%ld != %ld (%lx!=%lx):",oggpack_look(&r,32),large[i],
+ oggpack_look(&r,32),large[i]);
+ report("read incorrect value!\n");
+ }
+ oggpack_adv(&r,32);
+ }
+ if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSmall unclipped packing (LSb): ");
+ cliptest(testbuffer1,test1size,7,four,foursize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge unclipped packing (LSb): ");
+ cliptest(testbuffer2,test2size,17,five,fivesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSingle bit unclipped packing (LSb): ");
+ cliptest(testbuffer3,test3size,1,six,sixsize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nTesting read past end (LSb): ");
+ oggpack_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
+ for(i=0;i<64;i++){
+ if(oggpack_read(&r,1)!=0){
+ fprintf(stderr,"failed; got -1 prematurely.\n");
+ exit(1);
+ }
+ }
+ if(oggpack_look(&r,1)!=-1 ||
+ oggpack_read(&r,1)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ oggpack_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
+ if(oggpack_read(&r,30)!=0 || oggpack_read(&r,16)!=0){
+ fprintf(stderr,"failed 2; got -1 prematurely.\n");
+ exit(1);
+ }
+
+ if(oggpack_look(&r,18)!=0 ||
+ oggpack_look(&r,18)!=0){
+ fprintf(stderr,"failed 3; got -1 prematurely.\n");
+ exit(1);
+ }
+ if(oggpack_look(&r,19)!=-1 ||
+ oggpack_look(&r,19)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ if(oggpack_look(&r,32)!=-1 ||
+ oggpack_look(&r,32)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ oggpack_writeclear(&o);
+ fprintf(stderr,"ok.");
+
+ /* this is partly glassbox; we're mostly concerned about the allocation boundaries */
+
+ fprintf(stderr,"\nTesting aligned writecopies (LSb): ");
+ for(i=0;i<71;i++)
+ for(j=0;j<5;j++)
+ copytest(j*8,i);
+ for(i=BUFFER_INCREMENT*8-71;i<BUFFER_INCREMENT*8+71;i++)
+ for(j=0;j<5;j++)
+ copytest(j*8,i);
+ fprintf(stderr,"ok. ");
+
+ fprintf(stderr,"\nTesting unaligned writecopies (LSb): ");
+ for(i=0;i<71;i++)
+ for(j=1;j<40;j++)
+ if(j&0x7)
+ copytest(j,i);
+ for(i=BUFFER_INCREMENT*8-71;i<BUFFER_INCREMENT*8+71;i++)
+ for(j=1;j<40;j++)
+ if(j&0x7)
+ copytest(j,i);
+
+ fprintf(stderr,"ok. \n");
+
+
+ /********** lazy, cut-n-paste retest with MSb packing ***********/
+
+ /* Test read/write together */
+ /* Later we test against pregenerated bitstreams */
+ oggpackB_writeinit(&o);
+
+ fprintf(stderr,"\nSmall preclipped packing (MSb): ");
+ cliptestB(testbuffer1,test1size,0,oneB,onesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nNull bit call (MSb): ");
+ cliptestB(testbuffer3,test3size,0,twoB,twosize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge preclipped packing (MSb): ");
+ cliptestB(testbuffer2,test2size,0,threeB,threesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\n32 bit preclipped packing (MSb): ");
+ oggpackB_reset(&o);
+ for(i=0;i<test2size;i++)
+ oggpackB_write(&o,large[i],32);
+ buffer=oggpackB_get_buffer(&o);
+ bytes=oggpackB_bytes(&o);
+ oggpackB_readinit(&r,buffer,bytes);
+ for(i=0;i<test2size;i++){
+ if(oggpackB_look(&r,32)==-1)report("out of data. failed!");
+ if(oggpackB_look(&r,32)!=large[i]){
+ fprintf(stderr,"%ld != %ld (%lx!=%lx):",oggpackB_look(&r,32),large[i],
+ oggpackB_look(&r,32),large[i]);
+ report("read incorrect value!\n");
+ }
+ oggpackB_adv(&r,32);
+ }
+ if(oggpackB_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSmall unclipped packing (MSb): ");
+ cliptestB(testbuffer1,test1size,7,fourB,foursize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge unclipped packing (MSb): ");
+ cliptestB(testbuffer2,test2size,17,fiveB,fivesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSingle bit unclipped packing (MSb): ");
+ cliptestB(testbuffer3,test3size,1,sixB,sixsize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nTesting read past end (MSb): ");
+ oggpackB_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
+ for(i=0;i<64;i++){
+ if(oggpackB_read(&r,1)!=0){
+ fprintf(stderr,"failed; got -1 prematurely.\n");
+ exit(1);
+ }
+ }
+ if(oggpackB_look(&r,1)!=-1 ||
+ oggpackB_read(&r,1)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ oggpackB_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
+ if(oggpackB_read(&r,30)!=0 || oggpackB_read(&r,16)!=0){
+ fprintf(stderr,"failed 2; got -1 prematurely.\n");
+ exit(1);
+ }
+
+ if(oggpackB_look(&r,18)!=0 ||
+ oggpackB_look(&r,18)!=0){
+ fprintf(stderr,"failed 3; got -1 prematurely.\n");
+ exit(1);
+ }
+ if(oggpackB_look(&r,19)!=-1 ||
+ oggpackB_look(&r,19)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ if(oggpackB_look(&r,32)!=-1 ||
+ oggpackB_look(&r,32)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ fprintf(stderr,"ok.");
+ oggpackB_writeclear(&o);
+
+ /* this is partly glassbox; we're mostly concerned about the allocation boundaries */
+
+ fprintf(stderr,"\nTesting aligned writecopies (MSb): ");
+ for(i=0;i<71;i++)
+ for(j=0;j<5;j++)
+ copytestB(j*8,i);
+ for(i=BUFFER_INCREMENT*8-71;i<BUFFER_INCREMENT*8+71;i++)
+ for(j=0;j<5;j++)
+ copytestB(j*8,i);
+ fprintf(stderr,"ok. ");
+
+ fprintf(stderr,"\nTesting unaligned writecopies (MSb): ");
+ for(i=0;i<71;i++)
+ for(j=1;j<40;j++)
+ if(j&0x7)
+ copytestB(j,i);
+ for(i=BUFFER_INCREMENT*8-71;i<BUFFER_INCREMENT*8+71;i++)
+ for(j=1;j<40;j++)
+ if(j&0x7)
+ copytestB(j,i);
+
+ fprintf(stderr,"ok. \n\n");
+
+ return(0);
+}
+#endif /* _V_SELFTEST */
+
+#undef BUFFER_INCREMENT
diff --git a/external/libogg-1.3.2/src/framing.c b/external/libogg-1.3.2/src/framing.c
new file mode 100644
index 0000000..3a2f0a6
--- /dev/null
+++ b/external/libogg-1.3.2/src/framing.c
@@ -0,0 +1,2111 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: code raw packets into framed OggSquish stream and
+ decode Ogg streams back into raw packets
+ last mod: $Id: framing.c 18758 2013-01-08 16:29:56Z tterribe $
+
+ note: The CRC code is directly derived from public domain code by
+ Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
+ for details.
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ogg/ogg.h>
+
+/* A complete description of Ogg framing exists in docs/framing.html */
+
+int ogg_page_version(const ogg_page *og){
+ return((int)(og->header[4]));
+}
+
+int ogg_page_continued(const ogg_page *og){
+ return((int)(og->header[5]&0x01));
+}
+
+int ogg_page_bos(const ogg_page *og){
+ return((int)(og->header[5]&0x02));
+}
+
+int ogg_page_eos(const ogg_page *og){
+ return((int)(og->header[5]&0x04));
+}
+
+ogg_int64_t ogg_page_granulepos(const ogg_page *og){
+ unsigned char *page=og->header;
+ ogg_int64_t granulepos=page[13]&(0xff);
+ granulepos= (granulepos<<8)|(page[12]&0xff);
+ granulepos= (granulepos<<8)|(page[11]&0xff);
+ granulepos= (granulepos<<8)|(page[10]&0xff);
+ granulepos= (granulepos<<8)|(page[9]&0xff);
+ granulepos= (granulepos<<8)|(page[8]&0xff);
+ granulepos= (granulepos<<8)|(page[7]&0xff);
+ granulepos= (granulepos<<8)|(page[6]&0xff);
+ return(granulepos);
+}
+
+int ogg_page_serialno(const ogg_page *og){
+ return(og->header[14] |
+ (og->header[15]<<8) |
+ (og->header[16]<<16) |
+ (og->header[17]<<24));
+}
+
+long ogg_page_pageno(const ogg_page *og){
+ return(og->header[18] |
+ (og->header[19]<<8) |
+ (og->header[20]<<16) |
+ (og->header[21]<<24));
+}
+
+
+
+/* returns the number of packets that are completed on this page (if
+ the leading packet is begun on a previous page, but ends on this
+ page, it's counted */
+
+/* NOTE:
+ If a page consists of a packet begun on a previous page, and a new
+ packet begun (but not completed) on this page, the return will be:
+ ogg_page_packets(page) ==1,
+ ogg_page_continued(page) !=0
+
+ If a page happens to be a single packet that was begun on a
+ previous page, and spans to the next page (in the case of a three or
+ more page packet), the return will be:
+ ogg_page_packets(page) ==0,
+ ogg_page_continued(page) !=0
+*/
+
+int ogg_page_packets(const ogg_page *og){
+ int i,n=og->header[26],count=0;
+ for(i=0;i<n;i++)
+ if(og->header[27+i]<255)count++;
+ return(count);
+}
+
+
+#if 0
+/* helper to initialize lookup for direct-table CRC (illustrative; we
+ use the static init below) */
+
+static ogg_uint32_t _ogg_crc_entry(unsigned long index){
+ int i;
+ unsigned long r;
+
+ r = index << 24;
+ for (i=0; i<8; i++)
+ if (r & 0x80000000UL)
+ r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
+ polynomial, although we use an
+ unreflected alg and an init/final
+ of 0, not 0xffffffff */
+ else
+ r<<=1;
+ return (r & 0xffffffffUL);
+}
+#endif
+
+static const ogg_uint32_t crc_lookup[256]={
+ 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
+ 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
+ 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
+ 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
+ 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
+ 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
+ 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
+ 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
+ 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
+ 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
+ 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
+ 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
+ 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
+ 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
+ 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
+ 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
+ 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
+ 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
+ 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
+ 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
+ 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
+ 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
+ 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
+ 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
+ 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
+ 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
+ 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
+ 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
+ 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
+ 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
+ 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
+ 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
+ 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
+ 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
+ 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
+ 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
+ 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
+ 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
+ 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
+ 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
+ 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
+ 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
+ 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
+ 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
+ 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
+ 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
+ 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
+ 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
+ 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
+ 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
+ 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
+ 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
+ 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
+ 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
+ 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
+ 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
+ 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
+ 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
+ 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
+ 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
+ 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
+ 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
+ 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
+ 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
+
+/* init the encode/decode logical stream state */
+
+int ogg_stream_init(ogg_stream_state *os,int serialno){
+ if(os){
+ memset(os,0,sizeof(*os));
+ os->body_storage=16*1024;
+ os->lacing_storage=1024;
+
+ os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
+ os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
+ os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
+
+ if(!os->body_data || !os->lacing_vals || !os->granule_vals){
+ ogg_stream_clear(os);
+ return -1;
+ }
+
+ os->serialno=serialno;
+
+ return(0);
+ }
+ return(-1);
+}
+
+/* async/delayed error detection for the ogg_stream_state */
+int ogg_stream_check(ogg_stream_state *os){
+ if(!os || !os->body_data) return -1;
+ return 0;
+}
+
+/* _clear does not free os, only the non-flat storage within */
+int ogg_stream_clear(ogg_stream_state *os){
+ if(os){
+ if(os->body_data)_ogg_free(os->body_data);
+ if(os->lacing_vals)_ogg_free(os->lacing_vals);
+ if(os->granule_vals)_ogg_free(os->granule_vals);
+
+ memset(os,0,sizeof(*os));
+ }
+ return(0);
+}
+
+int ogg_stream_destroy(ogg_stream_state *os){
+ if(os){
+ ogg_stream_clear(os);
+ _ogg_free(os);
+ }
+ return(0);
+}
+
+/* Helpers for ogg_stream_encode; this keeps the structure and
+ what's happening fairly clear */
+
+static int _os_body_expand(ogg_stream_state *os,long needed){
+ if(os->body_storage-needed<=os->body_fill){
+ long body_storage;
+ void *ret;
+ if(os->body_storage>LONG_MAX-needed){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ body_storage=os->body_storage+needed;
+ if(body_storage<LONG_MAX-1024)body_storage+=1024;
+ ret=_ogg_realloc(os->body_data,body_storage*sizeof(*os->body_data));
+ if(!ret){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ os->body_storage=body_storage;
+ os->body_data=ret;
+ }
+ return 0;
+}
+
+static int _os_lacing_expand(ogg_stream_state *os,long needed){
+ if(os->lacing_storage-needed<=os->lacing_fill){
+ long lacing_storage;
+ void *ret;
+ if(os->lacing_storage>LONG_MAX-needed){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ lacing_storage=os->lacing_storage+needed;
+ if(lacing_storage<LONG_MAX-32)lacing_storage+=32;
+ ret=_ogg_realloc(os->lacing_vals,lacing_storage*sizeof(*os->lacing_vals));
+ if(!ret){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ os->lacing_vals=ret;
+ ret=_ogg_realloc(os->granule_vals,lacing_storage*
+ sizeof(*os->granule_vals));
+ if(!ret){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ os->granule_vals=ret;
+ os->lacing_storage=lacing_storage;
+ }
+ return 0;
+}
+
+/* checksum the page */
+/* Direct table CRC; note that this will be faster in the future if we
+ perform the checksum simultaneously with other copies */
+
+void ogg_page_checksum_set(ogg_page *og){
+ if(og){
+ ogg_uint32_t crc_reg=0;
+ int i;
+
+ /* safety; needed for API behavior, but not framing code */
+ og->header[22]=0;
+ og->header[23]=0;
+ og->header[24]=0;
+ og->header[25]=0;
+
+ for(i=0;i<og->header_len;i++)
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
+ for(i=0;i<og->body_len;i++)
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
+
+ og->header[22]=(unsigned char)(crc_reg&0xff);
+ og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
+ og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
+ og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
+ }
+}
+
+/* submit data to the internal buffer of the framing engine */
+int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
+ long e_o_s, ogg_int64_t granulepos){
+
+ long bytes = 0, lacing_vals;
+ int i;
+
+ if(ogg_stream_check(os)) return -1;
+ if(!iov) return 0;
+
+ for (i = 0; i < count; ++i){
+ if(iov[i].iov_len>LONG_MAX) return -1;
+ if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1;
+ bytes += (long)iov[i].iov_len;
+ }
+ lacing_vals=bytes/255+1;
+
+ if(os->body_returned){
+ /* advance packet data according to the body_returned pointer. We
+ had to keep it around to return a pointer into the buffer last
+ call */
+
+ os->body_fill-=os->body_returned;
+ if(os->body_fill)
+ memmove(os->body_data,os->body_data+os->body_returned,
+ os->body_fill);
+ os->body_returned=0;
+ }
+
+ /* make sure we have the buffer storage */
+ if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals))
+ return -1;
+
+ /* Copy in the submitted packet. Yes, the copy is a waste; this is
+ the liability of overly clean abstraction for the time being. It
+ will actually be fairly easy to eliminate the extra copy in the
+ future */
+
+ for (i = 0; i < count; ++i) {
+ memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len);
+ os->body_fill += (int)iov[i].iov_len;
+ }
+
+ /* Store lacing vals for this packet */
+ for(i=0;i<lacing_vals-1;i++){
+ os->lacing_vals[os->lacing_fill+i]=255;
+ os->granule_vals[os->lacing_fill+i]=os->granulepos;
+ }
+ os->lacing_vals[os->lacing_fill+i]=bytes%255;
+ os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos;
+
+ /* flag the first segment as the beginning of the packet */
+ os->lacing_vals[os->lacing_fill]|= 0x100;
+
+ os->lacing_fill+=lacing_vals;
+
+ /* for the sake of completeness */
+ os->packetno++;
+
+ if(e_o_s)os->e_o_s=1;
+
+ return(0);
+}
+
+int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
+ ogg_iovec_t iov;
+ iov.iov_base = op->packet;
+ iov.iov_len = op->bytes;
+ return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos);
+}
+
+/* Conditionally flush a page; force==0 will only flush nominal-size
+ pages, force==1 forces us to flush a page regardless of page size
+ so long as there's any data available at all. */
+static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){
+ int i;
+ int vals=0;
+ int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
+ int bytes=0;
+ long acc=0;
+ ogg_int64_t granule_pos=-1;
+
+ if(ogg_stream_check(os)) return(0);
+ if(maxvals==0) return(0);
+
+ /* construct a page */
+ /* decide how many segments to include */
+
+ /* If this is the initial header case, the first page must only include
+ the initial header packet */
+ if(os->b_o_s==0){ /* 'initial header page' case */
+ granule_pos=0;
+ for(vals=0;vals<maxvals;vals++){
+ if((os->lacing_vals[vals]&0x0ff)<255){
+ vals++;
+ break;
+ }
+ }
+ }else{
+
+ /* The extra packets_done, packet_just_done logic here attempts to do two things:
+ 1) Don't unneccessarily span pages.
+ 2) Unless necessary, don't flush pages if there are less than four packets on
+ them; this expands page size to reduce unneccessary overhead if incoming packets
+ are large.
+ These are not necessary behaviors, just 'always better than naive flushing'
+ without requiring an application to explicitly request a specific optimized
+ behavior. We'll want an explicit behavior setup pathway eventually as well. */
+
+ int packets_done=0;
+ int packet_just_done=0;
+ for(vals=0;vals<maxvals;vals++){
+ if(acc>nfill && packet_just_done>=4){
+ force=1;
+ break;
+ }
+ acc+=os->lacing_vals[vals]&0x0ff;
+ if((os->lacing_vals[vals]&0xff)<255){
+ granule_pos=os->granule_vals[vals];
+ packet_just_done=++packets_done;
+ }else
+ packet_just_done=0;
+ }
+ if(vals==255)force=1;
+ }
+
+ if(!force) return(0);
+
+ /* construct the header in temp storage */
+ memcpy(os->header,"OggS",4);
+
+ /* stream structure version */
+ os->header[4]=0x00;
+
+ /* continued packet flag? */
+ os->header[5]=0x00;
+ if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
+ /* first page flag? */
+ if(os->b_o_s==0)os->header[5]|=0x02;
+ /* last page flag? */
+ if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
+ os->b_o_s=1;
+
+ /* 64 bits of PCM position */
+ for(i=6;i<14;i++){
+ os->header[i]=(unsigned char)(granule_pos&0xff);
+ granule_pos>>=8;
+ }
+
+ /* 32 bits of stream serial number */
+ {
+ long serialno=os->serialno;
+ for(i=14;i<18;i++){
+ os->header[i]=(unsigned char)(serialno&0xff);
+ serialno>>=8;
+ }
+ }
+
+ /* 32 bits of page counter (we have both counter and page header
+ because this val can roll over) */
+ if(os->pageno==-1)os->pageno=0; /* because someone called
+ stream_reset; this would be a
+ strange thing to do in an
+ encode stream, but it has
+ plausible uses */
+ {
+ long pageno=os->pageno++;
+ for(i=18;i<22;i++){
+ os->header[i]=(unsigned char)(pageno&0xff);
+ pageno>>=8;
+ }
+ }
+
+ /* zero for computation; filled in later */
+ os->header[22]=0;
+ os->header[23]=0;
+ os->header[24]=0;
+ os->header[25]=0;
+
+ /* segment table */
+ os->header[26]=(unsigned char)(vals&0xff);
+ for(i=0;i<vals;i++)
+ bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
+
+ /* set pointers in the ogg_page struct */
+ og->header=os->header;
+ og->header_len=os->header_fill=vals+27;
+ og->body=os->body_data+os->body_returned;
+ og->body_len=bytes;
+
+ /* advance the lacing data and set the body_returned pointer */
+
+ os->lacing_fill-=vals;
+ memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
+ memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
+ os->body_returned+=bytes;
+
+ /* calculate the checksum */
+
+ ogg_page_checksum_set(og);
+
+ /* done */
+ return(1);
+}
+
+/* This will flush remaining packets into a page (returning nonzero),
+ even if there is not enough data to trigger a flush normally
+ (undersized page). If there are no packets or partial packets to
+ flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
+ try to flush a normal sized page like ogg_stream_pageout; a call to
+ ogg_stream_flush does not guarantee that all packets have flushed.
+ Only a return value of 0 from ogg_stream_flush indicates all packet
+ data is flushed into pages.
+
+ since ogg_stream_flush will flush the last page in a stream even if
+ it's undersized, you almost certainly want to use ogg_stream_pageout
+ (and *not* ogg_stream_flush) unless you specifically need to flush
+ a page regardless of size in the middle of a stream. */
+
+int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
+ return ogg_stream_flush_i(os,og,1,4096);
+}
+
+/* Like the above, but an argument is provided to adjust the nominal
+ page size for applications which are smart enough to provide their
+ own delay based flushing */
+
+int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){
+ return ogg_stream_flush_i(os,og,1,nfill);
+}
+
+/* This constructs pages from buffered packet segments. The pointers
+returned are to static buffers; do not free. The returned buffers are
+good only until the next call (using the same ogg_stream_state) */
+
+int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
+ int force=0;
+ if(ogg_stream_check(os)) return 0;
+
+ if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
+ (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
+ force=1;
+
+ return(ogg_stream_flush_i(os,og,force,4096));
+}
+
+/* Like the above, but an argument is provided to adjust the nominal
+page size for applications which are smart enough to provide their
+own delay based flushing */
+
+int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){
+ int force=0;
+ if(ogg_stream_check(os)) return 0;
+
+ if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
+ (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
+ force=1;
+
+ return(ogg_stream_flush_i(os,og,force,nfill));
+}
+
+int ogg_stream_eos(ogg_stream_state *os){
+ if(ogg_stream_check(os)) return 1;
+ return os->e_o_s;
+}
+
+/* DECODING PRIMITIVES: packet streaming layer **********************/
+
+/* This has two layers to place more of the multi-serialno and paging
+ control in the application's hands. First, we expose a data buffer
+ using ogg_sync_buffer(). The app either copies into the
+ buffer, or passes it directly to read(), etc. We then call
+ ogg_sync_wrote() to tell how many bytes we just added.
+
+ Pages are returned (pointers into the buffer in ogg_sync_state)
+ by ogg_sync_pageout(). The page is then submitted to
+ ogg_stream_pagein() along with the appropriate
+ ogg_stream_state* (ie, matching serialno). We then get raw
+ packets out calling ogg_stream_packetout() with a
+ ogg_stream_state. */
+
+/* initialize the struct to a known state */
+int ogg_sync_init(ogg_sync_state *oy){
+ if(oy){
+ oy->storage = -1; /* used as a readiness flag */
+ memset(oy,0,sizeof(*oy));
+ }
+ return(0);
+}
+
+/* clear non-flat storage within */
+int ogg_sync_clear(ogg_sync_state *oy){
+ if(oy){
+ if(oy->data)_ogg_free(oy->data);
+ memset(oy,0,sizeof(*oy));
+ }
+ return(0);
+}
+
+int ogg_sync_destroy(ogg_sync_state *oy){
+ if(oy){
+ ogg_sync_clear(oy);
+ _ogg_free(oy);
+ }
+ return(0);
+}
+
+int ogg_sync_check(ogg_sync_state *oy){
+ if(oy->storage<0) return -1;
+ return 0;
+}
+
+char *ogg_sync_buffer(ogg_sync_state *oy, long size){
+ if(ogg_sync_check(oy)) return NULL;
+
+ /* first, clear out any space that has been previously returned */
+ if(oy->returned){
+ oy->fill-=oy->returned;
+ if(oy->fill>0)
+ memmove(oy->data,oy->data+oy->returned,oy->fill);
+ oy->returned=0;
+ }
+
+ if(size>oy->storage-oy->fill){
+ /* We need to extend the internal buffer */
+ long newsize=size+oy->fill+4096; /* an extra page to be nice */
+ void *ret;
+
+ if(oy->data)
+ ret=_ogg_realloc(oy->data,newsize);
+ else
+ ret=_ogg_malloc(newsize);
+ if(!ret){
+ ogg_sync_clear(oy);
+ return NULL;
+ }
+ oy->data=ret;
+ oy->storage=newsize;
+ }
+
+ /* expose a segment at least as large as requested at the fill mark */
+ return((char *)oy->data+oy->fill);
+}
+
+int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
+ if(ogg_sync_check(oy))return -1;
+ if(oy->fill+bytes>oy->storage)return -1;
+ oy->fill+=bytes;
+ return(0);
+}
+
+/* sync the stream. This is meant to be useful for finding page
+ boundaries.
+
+ return values for this:
+ -n) skipped n bytes
+ 0) page not ready; more data (no bytes skipped)
+ n) page synced at current location; page length n bytes
+
+*/
+
+long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
+ unsigned char *page=oy->data+oy->returned;
+ unsigned char *next;
+ long bytes=oy->fill-oy->returned;
+
+ if(ogg_sync_check(oy))return 0;
+
+ if(oy->headerbytes==0){
+ int headerbytes,i;
+ if(bytes<27)return(0); /* not enough for a header */
+
+ /* verify capture pattern */
+ if(memcmp(page,"OggS",4))goto sync_fail;
+
+ headerbytes=page[26]+27;
+ if(bytes<headerbytes)return(0); /* not enough for header + seg table */
+
+ /* count up body length in the segment table */
+
+ for(i=0;i<page[26];i++)
+ oy->bodybytes+=page[27+i];
+ oy->headerbytes=headerbytes;
+ }
+
+ if(oy->bodybytes+oy->headerbytes>bytes)return(0);
+
+ /* The whole test page is buffered. Verify the checksum */
+ {
+ /* Grab the checksum bytes, set the header field to zero */
+ char chksum[4];
+ ogg_page log;
+
+ memcpy(chksum,page+22,4);
+ memset(page+22,0,4);
+
+ /* set up a temp page struct and recompute the checksum */
+ log.header=page;
+ log.header_len=oy->headerbytes;
+ log.body=page+oy->headerbytes;
+ log.body_len=oy->bodybytes;
+ ogg_page_checksum_set(&log);
+
+ /* Compare */
+ if(memcmp(chksum,page+22,4)){
+ /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
+ at all) */
+ /* replace the computed checksum with the one actually read in */
+ memcpy(page+22,chksum,4);
+
+ /* Bad checksum. Lose sync */
+ goto sync_fail;
+ }
+ }
+
+ /* yes, have a whole page all ready to go */
+ {
+ unsigned char *page=oy->data+oy->returned;
+ long bytes;
+
+ if(og){
+ og->header=page;
+ og->header_len=oy->headerbytes;
+ og->body=page+oy->headerbytes;
+ og->body_len=oy->bodybytes;
+ }
+
+ oy->unsynced=0;
+ oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
+ oy->headerbytes=0;
+ oy->bodybytes=0;
+ return(bytes);
+ }
+
+ sync_fail:
+
+ oy->headerbytes=0;
+ oy->bodybytes=0;
+
+ /* search for possible capture */
+ next=memchr(page+1,'O',bytes-1);
+ if(!next)
+ next=oy->data+oy->fill;
+
+ oy->returned=(int)(next-oy->data);
+ return((long)-(next-page));
+}
+
+/* sync the stream and get a page. Keep trying until we find a page.
+ Suppress 'sync errors' after reporting the first.
+
+ return values:
+ -1) recapture (hole in data)
+ 0) need more data
+ 1) page returned
+
+ Returns pointers into buffered data; invalidated by next call to
+ _stream, _clear, _init, or _buffer */
+
+int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
+
+ if(ogg_sync_check(oy))return 0;
+
+ /* all we need to do is verify a page at the head of the stream
+ buffer. If it doesn't verify, we look for the next potential
+ frame */
+
+ for(;;){
+ long ret=ogg_sync_pageseek(oy,og);
+ if(ret>0){
+ /* have a page */
+ return(1);
+ }
+ if(ret==0){
+ /* need more data */
+ return(0);
+ }
+
+ /* head did not start a synced page... skipped some bytes */
+ if(!oy->unsynced){
+ oy->unsynced=1;
+ return(-1);
+ }
+
+ /* loop. keep looking */
+
+ }
+}
+
+/* add the incoming page to the stream state; we decompose the page
+ into packet segments here as well. */
+
+int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
+ unsigned char *header=og->header;
+ unsigned char *body=og->body;
+ long bodysize=og->body_len;
+ int segptr=0;
+
+ int version=ogg_page_version(og);
+ int continued=ogg_page_continued(og);
+ int bos=ogg_page_bos(og);
+ int eos=ogg_page_eos(og);
+ ogg_int64_t granulepos=ogg_page_granulepos(og);
+ int serialno=ogg_page_serialno(og);
+ long pageno=ogg_page_pageno(og);
+ int segments=header[26];
+
+ if(ogg_stream_check(os)) return -1;
+
+ /* clean up 'returned data' */
+ {
+ long lr=os->lacing_returned;
+ long br=os->body_returned;
+
+ /* body data */
+ if(br){
+ os->body_fill-=br;
+ if(os->body_fill)
+ memmove(os->body_data,os->body_data+br,os->body_fill);
+ os->body_returned=0;
+ }
+
+ if(lr){
+ /* segment table */
+ if(os->lacing_fill-lr){
+ memmove(os->lacing_vals,os->lacing_vals+lr,
+ (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
+ memmove(os->granule_vals,os->granule_vals+lr,
+ (os->lacing_fill-lr)*sizeof(*os->granule_vals));
+ }
+ os->lacing_fill-=lr;
+ os->lacing_packet-=lr;
+ os->lacing_returned=0;
+ }
+ }
+
+ /* check the serial number */
+ if(serialno!=os->serialno)return(-1);
+ if(version>0)return(-1);
+
+ if(_os_lacing_expand(os,segments+1)) return -1;
+
+ /* are we in sequence? */
+ if(pageno!=os->pageno){
+ int i;
+
+ /* unroll previous partial packet (if any) */
+ for(i=os->lacing_packet;i<os->lacing_fill;i++)
+ os->body_fill-=os->lacing_vals[i]&0xff;
+ os->lacing_fill=os->lacing_packet;
+
+ /* make a note of dropped data in segment table */
+ if(os->pageno!=-1){
+ os->lacing_vals[os->lacing_fill++]=0x400;
+ os->lacing_packet++;
+ }
+ }
+
+ /* are we a 'continued packet' page? If so, we may need to skip
+ some segments */
+ if(continued){
+ if(os->lacing_fill<1 ||
+ os->lacing_vals[os->lacing_fill-1]==0x400){
+ bos=0;
+ for(;segptr<segments;segptr++){
+ int val=header[27+segptr];
+ body+=val;
+ bodysize-=val;
+ if(val<255){
+ segptr++;
+ break;
+ }
+ }
+ }
+ }
+
+ if(bodysize){
+ if(_os_body_expand(os,bodysize)) return -1;
+ memcpy(os->body_data+os->body_fill,body,bodysize);
+ os->body_fill+=bodysize;
+ }
+
+ {
+ int saved=-1;
+ while(segptr<segments){
+ int val=header[27+segptr];
+ os->lacing_vals[os->lacing_fill]=val;
+ os->granule_vals[os->lacing_fill]=-1;
+
+ if(bos){
+ os->lacing_vals[os->lacing_fill]|=0x100;
+ bos=0;
+ }
+
+ if(val<255)saved=os->lacing_fill;
+
+ os->lacing_fill++;
+ segptr++;
+
+ if(val<255)os->lacing_packet=os->lacing_fill;
+ }
+
+ /* set the granulepos on the last granuleval of the last full packet */
+ if(saved!=-1){
+ os->granule_vals[saved]=granulepos;
+ }
+
+ }
+
+ if(eos){
+ os->e_o_s=1;
+ if(os->lacing_fill>0)
+ os->lacing_vals[os->lacing_fill-1]|=0x200;
+ }
+
+ os->pageno=pageno+1;
+
+ return(0);
+}
+
+/* clear things to an initial state. Good to call, eg, before seeking */
+int ogg_sync_reset(ogg_sync_state *oy){
+ if(ogg_sync_check(oy))return -1;
+
+ oy->fill=0;
+ oy->returned=0;
+ oy->unsynced=0;
+ oy->headerbytes=0;
+ oy->bodybytes=0;
+ return(0);
+}
+
+int ogg_stream_reset(ogg_stream_state *os){
+ if(ogg_stream_check(os)) return -1;
+
+ os->body_fill=0;
+ os->body_returned=0;
+
+ os->lacing_fill=0;
+ os->lacing_packet=0;
+ os->lacing_returned=0;
+
+ os->header_fill=0;
+
+ os->e_o_s=0;
+ os->b_o_s=0;
+ os->pageno=-1;
+ os->packetno=0;
+ os->granulepos=0;
+
+ return(0);
+}
+
+int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
+ if(ogg_stream_check(os)) return -1;
+ ogg_stream_reset(os);
+ os->serialno=serialno;
+ return(0);
+}
+
+static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
+
+ /* The last part of decode. We have the stream broken into packet
+ segments. Now we need to group them into packets (or return the
+ out of sync markers) */
+
+ int ptr=os->lacing_returned;
+
+ if(os->lacing_packet<=ptr)return(0);
+
+ if(os->lacing_vals[ptr]&0x400){
+ /* we need to tell the codec there's a gap; it might need to
+ handle previous packet dependencies. */
+ os->lacing_returned++;
+ os->packetno++;
+ return(-1);
+ }
+
+ if(!op && !adv)return(1); /* just using peek as an inexpensive way
+ to ask if there's a whole packet
+ waiting */
+
+ /* Gather the whole packet. We'll have no holes or a partial packet */
+ {
+ int size=os->lacing_vals[ptr]&0xff;
+ long bytes=size;
+ int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
+ int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
+
+ while(size==255){
+ int val=os->lacing_vals[++ptr];
+ size=val&0xff;
+ if(val&0x200)eos=0x200;
+ bytes+=size;
+ }
+
+ if(op){
+ op->e_o_s=eos;
+ op->b_o_s=bos;
+ op->packet=os->body_data+os->body_returned;
+ op->packetno=os->packetno;
+ op->granulepos=os->granule_vals[ptr];
+ op->bytes=bytes;
+ }
+
+ if(adv){
+ os->body_returned+=bytes;
+ os->lacing_returned=ptr+1;
+ os->packetno++;
+ }
+ }
+ return(1);
+}
+
+int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
+ if(ogg_stream_check(os)) return 0;
+ return _packetout(os,op,1);
+}
+
+int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
+ if(ogg_stream_check(os)) return 0;
+ return _packetout(os,op,0);
+}
+
+void ogg_packet_clear(ogg_packet *op) {
+ _ogg_free(op->packet);
+ memset(op, 0, sizeof(*op));
+}
+
+#ifdef _V_SELFTEST
+#include <stdio.h>
+
+ogg_stream_state os_en, os_de;
+ogg_sync_state oy;
+
+void checkpacket(ogg_packet *op,long len, int no, long pos){
+ long j;
+ static int sequence=0;
+ static int lastno=0;
+
+ if(op->bytes!=len){
+ fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len);
+ exit(1);
+ }
+ if(op->granulepos!=pos){
+ fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
+ exit(1);
+ }
+
+ /* packet number just follows sequence/gap; adjust the input number
+ for that */
+ if(no==0){
+ sequence=0;
+ }else{
+ sequence++;
+ if(no>lastno+1)
+ sequence++;
+ }
+ lastno=no;
+ if(op->packetno!=sequence){
+ fprintf(stderr,"incorrect packet sequence %ld != %d\n",
+ (long)(op->packetno),sequence);
+ exit(1);
+ }
+
+ /* Test data */
+ for(j=0;j<op->bytes;j++)
+ if(op->packet[j]!=((j+no)&0xff)){
+ fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
+ j,op->packet[j],(j+no)&0xff);
+ exit(1);
+ }
+}
+
+void check_page(unsigned char *data,const int *header,ogg_page *og){
+ long j;
+ /* Test data */
+ for(j=0;j<og->body_len;j++)
+ if(og->body[j]!=data[j]){
+ fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
+ j,data[j],og->body[j]);
+ exit(1);
+ }
+
+ /* Test header */
+ for(j=0;j<og->header_len;j++){
+ if(og->header[j]!=header[j]){
+ fprintf(stderr,"header content mismatch at pos %ld:\n",j);
+ for(j=0;j<header[26]+27;j++)
+ fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
+ fprintf(stderr,"\n");
+ exit(1);
+ }
+ }
+ if(og->header_len!=header[26]+27){
+ fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
+ og->header_len,header[26]+27);
+ exit(1);
+ }
+}
+
+void print_header(ogg_page *og){
+ int j;
+ fprintf(stderr,"\nHEADER:\n");
+ fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
+ og->header[0],og->header[1],og->header[2],og->header[3],
+ (int)og->header[4],(int)og->header[5]);
+
+ fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
+ (og->header[9]<<24)|(og->header[8]<<16)|
+ (og->header[7]<<8)|og->header[6],
+ (og->header[17]<<24)|(og->header[16]<<16)|
+ (og->header[15]<<8)|og->header[14],
+ ((long)(og->header[21])<<24)|(og->header[20]<<16)|
+ (og->header[19]<<8)|og->header[18]);
+
+ fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
+ (int)og->header[22],(int)og->header[23],
+ (int)og->header[24],(int)og->header[25],
+ (int)og->header[26]);
+
+ for(j=27;j<og->header_len;j++)
+ fprintf(stderr,"%d ",(int)og->header[j]);
+ fprintf(stderr,")\n\n");
+}
+
+void copy_page(ogg_page *og){
+ unsigned char *temp=_ogg_malloc(og->header_len);
+ memcpy(temp,og->header,og->header_len);
+ og->header=temp;
+
+ temp=_ogg_malloc(og->body_len);
+ memcpy(temp,og->body,og->body_len);
+ og->body=temp;
+}
+
+void free_page(ogg_page *og){
+ _ogg_free (og->header);
+ _ogg_free (og->body);
+}
+
+void error(void){
+ fprintf(stderr,"error!\n");
+ exit(1);
+}
+
+/* 17 only */
+const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x15,0xed,0xec,0x91,
+ 1,
+ 17};
+
+/* 17, 254, 255, 256, 500, 510, 600 byte, pad */
+const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x59,0x10,0x6c,0x2c,
+ 1,
+ 17};
+const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x89,0x33,0x85,0xce,
+ 13,
+ 254,255,0,255,1,255,245,255,255,0,
+ 255,255,90};
+
+/* nil packets; beginning,middle,end */
+const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x5c,0x3f,0x66,0xcb,
+ 17,
+ 17,254,255,0,0,255,1,0,255,245,255,255,0,
+ 255,255,90,0};
+
+/* large initial packet */
+const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x01,0x27,0x31,0xaa,
+ 18,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,10};
+
+const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x7f,0x4e,0x8a,0xd2,
+ 4,
+ 255,4,255,0};
+
+
+/* continuing packet test */
+const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xf8,0x3c,0x19,0x79,
+ 255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255};
+
+const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x38,0xe6,0xb6,0x28,
+ 6,
+ 255,220,255,4,255,0};
+
+
+/* spill expansion test */
+const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xce,0x8f,0x17,0x1a,
+ 23,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
+
+
+const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x9b,0xb2,0x50,0xa1,
+ 1,
+ 0};
+
+/* page with the 255 segment limit */
+const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xed,0x2a,0x2e,0xa7,
+ 255,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10};
+
+const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x6c,0x3b,0x82,0x3d,
+ 1,
+ 50};
+
+
+/* packet that overspans over an entire page */
+const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x68,0x22,0x7c,0x3d,
+ 255,
+ 100,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255};
+
+const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xf4,0x87,0xba,0xf3,
+ 255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255};
+
+const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,3,0,0,0,
+ 0xf7,0x2f,0x6c,0x60,
+ 5,
+ 254,255,4,255,0};
+
+/* packet that overspans over an entire page */
+const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x68,0x22,0x7c,0x3d,
+ 255,
+ 100,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255};
+
+const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xd4,0xe0,0x60,0xe5,
+ 1,
+ 0};
+
+void test_pack(const int *pl, const int **headers, int byteskip,
+ int pageskip, int packetskip){
+ unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
+ long inptr=0;
+ long outptr=0;
+ long deptr=0;
+ long depacket=0;
+ long granule_pos=7,pageno=0;
+ int i,j,packets,pageout=pageskip;
+ int eosflag=0;
+ int bosflag=0;
+
+ int byteskipcount=0;
+
+ ogg_stream_reset(&os_en);
+ ogg_stream_reset(&os_de);
+ ogg_sync_reset(&oy);
+
+ for(packets=0;packets<packetskip;packets++)
+ depacket+=pl[packets];
+
+ for(packets=0;;packets++)if(pl[packets]==-1)break;
+
+ for(i=0;i<packets;i++){
+ /* construct a test packet */
+ ogg_packet op;
+ int len=pl[i];
+
+ op.packet=data+inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.granulepos=granule_pos;
+
+ granule_pos+=1024;
+
+ for(j=0;j<len;j++)data[inptr++]=i+j;
+
+ /* submit the test packet */
+ ogg_stream_packetin(&os_en,&op);
+
+ /* retrieve any finished pages */
+ {
+ ogg_page og;
+
+ while(ogg_stream_pageout(&os_en,&og)){
+ /* We have a page. Check it carefully */
+
+ fprintf(stderr,"%ld, ",pageno);
+
+ if(headers[pageno]==NULL){
+ fprintf(stderr,"coded too many pages!\n");
+ exit(1);
+ }
+
+ check_page(data+outptr,headers[pageno],&og);
+
+ outptr+=og.body_len;
+ pageno++;
+ if(pageskip){
+ bosflag=1;
+ pageskip--;
+ deptr+=og.body_len;
+ }
+
+ /* have a complete page; submit it to sync/decode */
+
+ {
+ ogg_page og_de;
+ ogg_packet op_de,op_de2;
+ char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
+ char *next=buf;
+ byteskipcount+=og.header_len;
+ if(byteskipcount>byteskip){
+ memcpy(next,og.header,byteskipcount-byteskip);
+ next+=byteskipcount-byteskip;
+ byteskipcount=byteskip;
+ }
+
+ byteskipcount+=og.body_len;
+ if(byteskipcount>byteskip){
+ memcpy(next,og.body,byteskipcount-byteskip);
+ next+=byteskipcount-byteskip;
+ byteskipcount=byteskip;
+ }
+
+ ogg_sync_wrote(&oy,next-buf);
+
+ while(1){
+ int ret=ogg_sync_pageout(&oy,&og_de);
+ if(ret==0)break;
+ if(ret<0)continue;
+ /* got a page. Happy happy. Verify that it's good. */
+
+ fprintf(stderr,"(%d), ",pageout);
+
+ check_page(data+deptr,headers[pageout],&og_de);
+ deptr+=og_de.body_len;
+ pageout++;
+
+ /* submit it to deconstitution */
+ ogg_stream_pagein(&os_de,&og_de);
+
+ /* packets out? */
+ while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
+ ogg_stream_packetpeek(&os_de,NULL);
+ ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
+
+ /* verify peek and out match */
+ if(memcmp(&op_de,&op_de2,sizeof(op_de))){
+ fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
+ depacket);
+ exit(1);
+ }
+
+ /* verify the packet! */
+ /* check data */
+ if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
+ fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
+ depacket);
+ exit(1);
+ }
+ /* check bos flag */
+ if(bosflag==0 && op_de.b_o_s==0){
+ fprintf(stderr,"b_o_s flag not set on packet!\n");
+ exit(1);
+ }
+ if(bosflag && op_de.b_o_s){
+ fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
+ exit(1);
+ }
+ bosflag=1;
+ depacket+=op_de.bytes;
+
+ /* check eos flag */
+ if(eosflag){
+ fprintf(stderr,"Multiple decoded packets with eos flag!\n");
+ exit(1);
+ }
+
+ if(op_de.e_o_s)eosflag=1;
+
+ /* check granulepos flag */
+ if(op_de.granulepos!=-1){
+ fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ _ogg_free(data);
+ if(headers[pageno]!=NULL){
+ fprintf(stderr,"did not write last page!\n");
+ exit(1);
+ }
+ if(headers[pageout]!=NULL){
+ fprintf(stderr,"did not decode last page!\n");
+ exit(1);
+ }
+ if(inptr!=outptr){
+ fprintf(stderr,"encoded page data incomplete!\n");
+ exit(1);
+ }
+ if(inptr!=deptr){
+ fprintf(stderr,"decoded page data incomplete!\n");
+ exit(1);
+ }
+ if(inptr!=depacket){
+ fprintf(stderr,"decoded packet data incomplete!\n");
+ exit(1);
+ }
+ if(!eosflag){
+ fprintf(stderr,"Never got a packet with EOS set!\n");
+ exit(1);
+ }
+ fprintf(stderr,"ok.\n");
+}
+
+int main(void){
+
+ ogg_stream_init(&os_en,0x04030201);
+ ogg_stream_init(&os_de,0x04030201);
+ ogg_sync_init(&oy);
+
+ /* Exercise each code path in the framing code. Also verify that
+ the checksums are working. */
+
+ {
+ /* 17 only */
+ const int packets[]={17, -1};
+ const int *headret[]={head1_0,NULL};
+
+ fprintf(stderr,"testing single page encoding... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
+ const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
+ const int *headret[]={head1_1,head2_1,NULL};
+
+ fprintf(stderr,"testing basic page encoding... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* nil packets; beginning,middle,end */
+ const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
+ const int *headret[]={head1_2,head2_2,NULL};
+
+ fprintf(stderr,"testing basic nil packets... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* large initial packet */
+ const int packets[]={4345,259,255,-1};
+ const int *headret[]={head1_3,head2_3,NULL};
+
+ fprintf(stderr,"testing initial-packet lacing > 4k... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* continuing packet test; with page spill expansion, we have to
+ overflow the lacing table. */
+ const int packets[]={0,65500,259,255,-1};
+ const int *headret[]={head1_4,head2_4,head3_4,NULL};
+
+ fprintf(stderr,"testing single packet page span... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* spill expand packet test */
+ const int packets[]={0,4345,259,255,0,0,-1};
+ const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
+
+ fprintf(stderr,"testing page spill expansion... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ /* page with the 255 segment limit */
+ {
+
+ const int packets[]={0,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,50,-1};
+ const int *headret[]={head1_5,head2_5,head3_5,NULL};
+
+ fprintf(stderr,"testing max packet segments... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* packet that overspans over an entire page */
+ const int packets[]={0,100,130049,259,255,-1};
+ const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
+
+ fprintf(stderr,"testing very large packets... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* test for the libogg 1.1.1 resync in large continuation bug
+ found by Josh Coalson) */
+ const int packets[]={0,100,130049,259,255,-1};
+ const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
+
+ fprintf(stderr,"testing continuation resync in very large packets... ");
+ test_pack(packets,headret,100,2,3);
+ }
+
+ {
+ /* term only page. why not? */
+ const int packets[]={0,100,64770,-1};
+ const int *headret[]={head1_7,head2_7,head3_7,NULL};
+
+ fprintf(stderr,"testing zero data page (1 nil packet)... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+
+
+ {
+ /* build a bunch of pages for testing */
+ unsigned char *data=_ogg_malloc(1024*1024);
+ int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
+ int inptr=0,i,j;
+ ogg_page og[5];
+
+ ogg_stream_reset(&os_en);
+
+ for(i=0;pl[i]!=-1;i++){
+ ogg_packet op;
+ int len=pl[i];
+
+ op.packet=data+inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.granulepos=(i+1)*1000;
+
+ for(j=0;j<len;j++)data[inptr++]=i+j;
+ ogg_stream_packetin(&os_en,&op);
+ }
+
+ _ogg_free(data);
+
+ /* retrieve finished pages */
+ for(i=0;i<5;i++){
+ if(ogg_stream_pageout(&os_en,&og[i])==0){
+ fprintf(stderr,"Too few pages output building sync tests!\n");
+ exit(1);
+ }
+ copy_page(&og[i]);
+ }
+
+ /* Test lost pages on pagein/packetout: no rollback */
+ {
+ ogg_page temp;
+ ogg_packet test;
+
+ fprintf(stderr,"Testing loss of pages... ");
+
+ ogg_sync_reset(&oy);
+ ogg_stream_reset(&os_de);
+ for(i=0;i<5;i++){
+ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
+ og[i].header_len);
+ ogg_sync_wrote(&oy,og[i].header_len);
+ memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
+ ogg_sync_wrote(&oy,og[i].body_len);
+ }
+
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ /* skip */
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+
+ /* do we get the expected results/packets? */
+
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,0,0,0);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,1,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,2,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,98,3,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,4079,4,5000);
+ if(ogg_stream_packetout(&os_de,&test)!=-1){
+ fprintf(stderr,"Error: loss of page did not return error\n");
+ exit(1);
+ }
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,76,9,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,34,10,-1);
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test lost pages on pagein/packetout: rollback with continuation */
+ {
+ ogg_page temp;
+ ogg_packet test;
+
+ fprintf(stderr,"Testing loss of pages (rollback required)... ");
+
+ ogg_sync_reset(&oy);
+ ogg_stream_reset(&os_de);
+ for(i=0;i<5;i++){
+ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
+ og[i].header_len);
+ ogg_sync_wrote(&oy,og[i].header_len);
+ memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
+ ogg_sync_wrote(&oy,og[i].body_len);
+ }
+
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ /* skip */
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+
+ /* do we get the expected results/packets? */
+
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,0,0,0);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,1,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,2,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,98,3,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,4079,4,5000);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,5,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,6,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,2954,7,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,2057,8,9000);
+ if(ogg_stream_packetout(&os_de,&test)!=-1){
+ fprintf(stderr,"Error: loss of page did not return error\n");
+ exit(1);
+ }
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,300,17,18000);
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* the rest only test sync */
+ {
+ ogg_page og_de;
+ /* Test fractional page inputs: incomplete capture */
+ fprintf(stderr,"Testing sync on partial inputs... ");
+ ogg_sync_reset(&oy);
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ 3);
+ ogg_sync_wrote(&oy,3);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ /* Test fractional page inputs: incomplete fixed header */
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ /* Test fractional page inputs: incomplete header */
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
+ 5);
+ ogg_sync_wrote(&oy,5);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ /* Test fractional page inputs: incomplete body */
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
+ og[1].header_len-28);
+ ogg_sync_wrote(&oy,og[1].header_len-28);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
+ ogg_sync_wrote(&oy,1000);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
+ og[1].body_len-1000);
+ ogg_sync_wrote(&oy,og[1].body_len-1000);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test fractional page inputs: page + incomplete capture */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing sync on 1+partial inputs... ");
+ ogg_sync_reset(&oy);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
+ og[1].header_len-20);
+ ogg_sync_wrote(&oy,og[1].header_len-20);
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test recapture: garbage + page */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing search for capture... ");
+ ogg_sync_reset(&oy);
+
+ /* 'garbage' */
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
+ og[2].header_len-20);
+ ogg_sync_wrote(&oy,og[2].header_len-20);
+ memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
+ og[2].body_len);
+ ogg_sync_wrote(&oy,og[2].body_len);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test recapture: page + garbage + page */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing recapture... ");
+ ogg_sync_reset(&oy);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ og[2].header_len);
+ ogg_sync_wrote(&oy,og[2].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ og[2].header_len);
+ ogg_sync_wrote(&oy,og[2].header_len);
+
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
+ og[2].body_len-5);
+ ogg_sync_wrote(&oy,og[2].body_len-5);
+
+ memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
+ og[3].header_len);
+ ogg_sync_wrote(&oy,og[3].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
+ og[3].body_len);
+ ogg_sync_wrote(&oy,og[3].body_len);
+
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Free page data that was previously copied */
+ {
+ for(i=0;i<5;i++){
+ free_page(&og[i]);
+ }
+ }
+ }
+
+ return(0);
+}
+
+#endif
diff --git a/external/libs/macosx/CMakeLists.txt b/external/libs/macosx/CMakeLists.txt
new file mode 100644
index 0000000..9ef4889
--- /dev/null
+++ b/external/libs/macosx/CMakeLists.txt
@@ -0,0 +1,28 @@
+project(SDL2)
+
+add_library(SDL2 INTERFACE IMPORTED)
+
+set_property(TARGET SDL2
+ PROPERTY INTERFACE_INCLUDE_DIRECTORES
+ "${CMAKE_SOURCE_DIR}/src/SDL2/include")
+
+set_property(TARGET SDL2
+ PROPERTY INTERFACE_LINK_LIBRARIES
+ "libSDL2main.a"
+ "libSDL2-2.0.0.dylib" )
+
+set_property(TARGET SDL2
+ PROPERTY INTERFACE_COMPILE_OPTIONS
+ "-L${CMAKE_CURRENT_SOURCE_DIR}")
+
+set_property(
+ TARGET SDL2
+ APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<INSTALL_INTERFACE:>
+ )
+
+message(STATUS "
+ ${lib}: LINK_INTERFACE_LIBRARIES = \"${lil}\"
+ INTERFACE_LINK_LIBRARIES = \"${ill}\""
+ )
diff --git a/external/libs/macosx/libSDL2-2.0.0.dylib b/external/libs/macosx/libSDL2-2.0.0.dylib
new file mode 100644
index 0000000..a14c323
--- /dev/null
+++ b/external/libs/macosx/libSDL2-2.0.0.dylib
Binary files differ
diff --git a/external/libs/macosx/libSDL2main.a b/external/libs/macosx/libSDL2main.a
new file mode 100644
index 0000000..4364d15
--- /dev/null
+++ b/external/libs/macosx/libSDL2main.a
Binary files differ
diff --git a/external/libs/win32/SDL.dll b/external/libs/win32/SDL.dll
new file mode 100644
index 0000000..7e09169
--- /dev/null
+++ b/external/libs/win32/SDL.dll
Binary files differ
diff --git a/external/libs/win32/SDL2.dll b/external/libs/win32/SDL2.dll
new file mode 100644
index 0000000..e499174
--- /dev/null
+++ b/external/libs/win32/SDL2.dll
Binary files differ
diff --git a/external/libs/win32/libSDL.a b/external/libs/win32/libSDL.a
new file mode 100644
index 0000000..0b2291f
--- /dev/null
+++ b/external/libs/win32/libSDL.a
Binary files differ
diff --git a/external/libs/win32/libSDL2.a b/external/libs/win32/libSDL2.a
new file mode 100644
index 0000000..d1b5f45
--- /dev/null
+++ b/external/libs/win32/libSDL2.a
Binary files differ
diff --git a/external/libs/win32/libSDL2.dll.a b/external/libs/win32/libSDL2.dll.a
new file mode 100644
index 0000000..e5d5a94
--- /dev/null
+++ b/external/libs/win32/libSDL2.dll.a
Binary files differ
diff --git a/external/libs/win32/libSDL2main.a b/external/libs/win32/libSDL2main.a
new file mode 100644
index 0000000..6e9ce3d
--- /dev/null
+++ b/external/libs/win32/libSDL2main.a
Binary files differ
diff --git a/external/libs/win32/libcurl.a b/external/libs/win32/libcurl.a
new file mode 100644
index 0000000..eef9dc7
--- /dev/null
+++ b/external/libs/win32/libcurl.a
Binary files differ
diff --git a/external/libs/win64/SDL264.dll b/external/libs/win64/SDL264.dll
new file mode 100644
index 0000000..b469787
--- /dev/null
+++ b/external/libs/win64/SDL264.dll
Binary files differ
diff --git a/external/libs/win64/SDL64.dll b/external/libs/win64/SDL64.dll
new file mode 100644
index 0000000..1d14407
--- /dev/null
+++ b/external/libs/win64/SDL64.dll
Binary files differ
diff --git a/external/libs/win64/libSDL264.a b/external/libs/win64/libSDL264.a
new file mode 100644
index 0000000..3fed695
--- /dev/null
+++ b/external/libs/win64/libSDL264.a
Binary files differ
diff --git a/external/libs/win64/libSDL264.dll.a b/external/libs/win64/libSDL264.dll.a
new file mode 100644
index 0000000..4d866e7
--- /dev/null
+++ b/external/libs/win64/libSDL264.dll.a
Binary files differ
diff --git a/external/libs/win64/libSDL264main.a b/external/libs/win64/libSDL264main.a
new file mode 100644
index 0000000..d5b6a26
--- /dev/null
+++ b/external/libs/win64/libSDL264main.a
Binary files differ
diff --git a/external/libs/win64/libSDL64.a b/external/libs/win64/libSDL64.a
new file mode 100644
index 0000000..b1a0298
--- /dev/null
+++ b/external/libs/win64/libSDL64.a
Binary files differ
diff --git a/external/libs/win64/libSDL64main.a b/external/libs/win64/libSDL64main.a
new file mode 100644
index 0000000..4e527e2
--- /dev/null
+++ b/external/libs/win64/libSDL64main.a
Binary files differ
diff --git a/external/libs/win64/libcurl.a b/external/libs/win64/libcurl.a
new file mode 100644
index 0000000..e50e75e
--- /dev/null
+++ b/external/libs/win64/libcurl.a
Binary files differ
diff --git a/external/libvorbis-1.3.5/CMakeLists.txt b/external/libvorbis-1.3.5/CMakeLists.txt
new file mode 100644
index 0000000..29bc750
--- /dev/null
+++ b/external/libvorbis-1.3.5/CMakeLists.txt
@@ -0,0 +1,82 @@
+set( VORBIS_INCLUDES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include )
+
+add_library (
+ vorbis STATIC
+ lib/analysis.c
+ lib/backends.h
+ lib/bitrate.c
+ lib/bitrate.h
+ lib/block.c
+ lib/books
+ lib/books/coupled
+ lib/books/coupled/res_books_51.h
+ lib/books/coupled/res_books_stereo.h
+ lib/books/floor
+ lib/books/floor/floor_books.h
+ lib/books/uncoupled
+ lib/books/uncoupled/res_books_uncoupled.h
+ lib/codebook.c
+ lib/codebook.h
+ lib/codec_internal.h
+ lib/envelope.c
+ lib/envelope.h
+ lib/floor0.c
+ lib/floor1.c
+ lib/highlevel.h
+ lib/info.c
+ lib/lookup.c
+ lib/lookup.h
+ lib/lookup_data.h
+ lib/lpc.c
+ lib/lpc.h
+ lib/lsp.c
+ lib/lsp.h
+ lib/mapping0.c
+ lib/masking.h
+ lib/mdct.c
+ lib/mdct.h
+ lib/misc.h
+ lib/modes
+ lib/modes/floor_all.h
+ lib/modes/psych_11.h
+ lib/modes/psych_16.h
+ lib/modes/psych_44.h
+ lib/modes/psych_8.h
+ lib/modes/residue_16.h
+ lib/modes/residue_44.h
+ lib/modes/residue_44p51.h
+ lib/modes/residue_44u.h
+ lib/modes/residue_8.h
+ lib/modes/setup_11.h
+ lib/modes/setup_16.h
+ lib/modes/setup_22.h
+ lib/modes/setup_32.h
+ lib/modes/setup_44.h
+ lib/modes/setup_44p51.h
+ lib/modes/setup_44u.h
+ lib/modes/setup_8.h
+ lib/modes/setup_X.h
+ lib/os.h
+ lib/psy.c
+ lib/psy.h
+ lib/registry.c
+ lib/registry.h
+ lib/res0.c
+ lib/scales.h
+ lib/sharedbook.c
+ lib/smallft.c
+ lib/smallft.h
+ lib/synthesis.c
+ lib/vorbisenc.c
+ lib/vorbisfile.c
+ lib/window.c
+ lib/window.h
+ )
+
+target_include_directories(
+ vorbis PUBLIC
+ ${VORBIS_INCLUDES_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/lib
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libogg-1.3.2/include
+ )
+
diff --git a/external/libvorbis-1.3.5/include/vorbis/codec.h b/external/libvorbis-1.3.5/include/vorbis/codec.h
new file mode 100644
index 0000000..999aa33
--- /dev/null
+++ b/external/libvorbis-1.3.5/include/vorbis/codec.h
@@ -0,0 +1,243 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+
+ ********************************************************************
+
+ function: libvorbis codec headers
+ last mod: $Id: codec.h 17021 2010-03-24 09:29:41Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _vorbis_codec_h_
+#define _vorbis_codec_h_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#include <ogg/ogg.h>
+
+typedef struct vorbis_info{
+ int version;
+ int channels;
+ long rate;
+
+ /* The below bitrate declarations are *hints*.
+ Combinations of the three values carry the following implications:
+
+ all three set to the same value:
+ implies a fixed rate bitstream
+ only nominal set:
+ implies a VBR stream that averages the nominal bitrate. No hard
+ upper/lower limit
+ upper and or lower set:
+ implies a VBR bitstream that obeys the bitrate limits. nominal
+ may also be set to give a nominal rate.
+ none set:
+ the coder does not care to speculate.
+ */
+
+ long bitrate_upper;
+ long bitrate_nominal;
+ long bitrate_lower;
+ long bitrate_window;
+
+ void *codec_setup;
+} vorbis_info;
+
+/* vorbis_dsp_state buffers the current vorbis audio
+ analysis/synthesis state. The DSP state belongs to a specific
+ logical bitstream ****************************************************/
+typedef struct vorbis_dsp_state{
+ int analysisp;
+ vorbis_info *vi;
+
+ float **pcm;
+ float **pcmret;
+ int pcm_storage;
+ int pcm_current;
+ int pcm_returned;
+
+ int preextrapolate;
+ int eofflag;
+
+ long lW;
+ long W;
+ long nW;
+ long centerW;
+
+ ogg_int64_t granulepos;
+ ogg_int64_t sequence;
+
+ ogg_int64_t glue_bits;
+ ogg_int64_t time_bits;
+ ogg_int64_t floor_bits;
+ ogg_int64_t res_bits;
+
+ void *backend_state;
+} vorbis_dsp_state;
+
+typedef struct vorbis_block{
+ /* necessary stream state for linking to the framing abstraction */
+ float **pcm; /* this is a pointer into local storage */
+ oggpack_buffer opb;
+
+ long lW;
+ long W;
+ long nW;
+ int pcmend;
+ int mode;
+
+ int eofflag;
+ ogg_int64_t granulepos;
+ ogg_int64_t sequence;
+ vorbis_dsp_state *vd; /* For read-only access of configuration */
+
+ /* local storage to avoid remallocing; it's up to the mapping to
+ structure it */
+ void *localstore;
+ long localtop;
+ long localalloc;
+ long totaluse;
+ struct alloc_chain *reap;
+
+ /* bitmetrics for the frame */
+ long glue_bits;
+ long time_bits;
+ long floor_bits;
+ long res_bits;
+
+ void *internal;
+
+} vorbis_block;
+
+/* vorbis_block is a single block of data to be processed as part of
+the analysis/synthesis stream; it belongs to a specific logical
+bitstream, but is independent from other vorbis_blocks belonging to
+that logical bitstream. *************************************************/
+
+struct alloc_chain{
+ void *ptr;
+ struct alloc_chain *next;
+};
+
+/* vorbis_info contains all the setup information specific to the
+ specific compression/decompression mode in progress (eg,
+ psychoacoustic settings, channel setup, options, codebook
+ etc). vorbis_info and substructures are in backends.h.
+*********************************************************************/
+
+/* the comments are not part of vorbis_info so that vorbis_info can be
+ static storage */
+typedef struct vorbis_comment{
+ /* unlimited user comment fields. libvorbis writes 'libvorbis'
+ whatever vendor is set to in encode */
+ char **user_comments;
+ int *comment_lengths;
+ int comments;
+ char *vendor;
+
+} vorbis_comment;
+
+
+/* libvorbis encodes in two abstraction layers; first we perform DSP
+ and produce a packet (see docs/analysis.txt). The packet is then
+ coded into a framed OggSquish bitstream by the second layer (see
+ docs/framing.txt). Decode is the reverse process; we sync/frame
+ the bitstream and extract individual packets, then decode the
+ packet back into PCM audio.
+
+ The extra framing/packetizing is used in streaming formats, such as
+ files. Over the net (such as with UDP), the framing and
+ packetization aren't necessary as they're provided by the transport
+ and the streaming layer is not used */
+
+/* Vorbis PRIMITIVES: general ***************************************/
+
+extern void vorbis_info_init(vorbis_info *vi);
+extern void vorbis_info_clear(vorbis_info *vi);
+extern int vorbis_info_blocksize(vorbis_info *vi,int zo);
+extern void vorbis_comment_init(vorbis_comment *vc);
+extern void vorbis_comment_add(vorbis_comment *vc, const char *comment);
+extern void vorbis_comment_add_tag(vorbis_comment *vc,
+ const char *tag, const char *contents);
+extern char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count);
+extern int vorbis_comment_query_count(vorbis_comment *vc, const char *tag);
+extern void vorbis_comment_clear(vorbis_comment *vc);
+
+extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb);
+extern int vorbis_block_clear(vorbis_block *vb);
+extern void vorbis_dsp_clear(vorbis_dsp_state *v);
+extern double vorbis_granule_time(vorbis_dsp_state *v,
+ ogg_int64_t granulepos);
+
+extern const char *vorbis_version_string(void);
+
+/* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
+
+extern int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi);
+extern int vorbis_commentheader_out(vorbis_comment *vc, ogg_packet *op);
+extern int vorbis_analysis_headerout(vorbis_dsp_state *v,
+ vorbis_comment *vc,
+ ogg_packet *op,
+ ogg_packet *op_comm,
+ ogg_packet *op_code);
+extern float **vorbis_analysis_buffer(vorbis_dsp_state *v,int vals);
+extern int vorbis_analysis_wrote(vorbis_dsp_state *v,int vals);
+extern int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb);
+extern int vorbis_analysis(vorbis_block *vb,ogg_packet *op);
+
+extern int vorbis_bitrate_addblock(vorbis_block *vb);
+extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,
+ ogg_packet *op);
+
+/* Vorbis PRIMITIVES: synthesis layer *******************************/
+extern int vorbis_synthesis_idheader(ogg_packet *op);
+extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,
+ ogg_packet *op);
+
+extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi);
+extern int vorbis_synthesis_restart(vorbis_dsp_state *v);
+extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op);
+extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op);
+extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb);
+extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm);
+extern int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm);
+extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples);
+extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op);
+
+extern int vorbis_synthesis_halfrate(vorbis_info *v,int flag);
+extern int vorbis_synthesis_halfrate_p(vorbis_info *v);
+
+/* Vorbis ERRORS and return codes ***********************************/
+
+#define OV_FALSE -1
+#define OV_EOF -2
+#define OV_HOLE -3
+
+#define OV_EREAD -128
+#define OV_EFAULT -129
+#define OV_EIMPL -130
+#define OV_EINVAL -131
+#define OV_ENOTVORBIS -132
+#define OV_EBADHEADER -133
+#define OV_EVERSION -134
+#define OV_ENOTAUDIO -135
+#define OV_EBADPACKET -136
+#define OV_EBADLINK -137
+#define OV_ENOSEEK -138
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+
diff --git a/external/libvorbis-1.3.5/include/vorbis/vorbisenc.h b/external/libvorbis-1.3.5/include/vorbis/vorbisenc.h
new file mode 100644
index 0000000..02332b5
--- /dev/null
+++ b/external/libvorbis-1.3.5/include/vorbis/vorbisenc.h
@@ -0,0 +1,436 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: vorbis encode-engine setup
+ last mod: $Id: vorbisenc.h 17021 2010-03-24 09:29:41Z xiphmont $
+
+ ********************************************************************/
+
+/** \file
+ * Libvorbisenc is a convenient API for setting up an encoding
+ * environment using libvorbis. Libvorbisenc encapsulates the
+ * actions needed to set up the encoder properly.
+ */
+
+#ifndef _OV_ENC_H_
+#define _OV_ENC_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#include "codec.h"
+
+/**
+ * This is the primary function within libvorbisenc for setting up managed
+ * bitrate modes.
+ *
+ * Before this function is called, the \ref vorbis_info
+ * struct should be initialized by using vorbis_info_init() from the libvorbis
+ * API. After encoding, vorbis_info_clear() should be called.
+ *
+ * The max_bitrate, nominal_bitrate, and min_bitrate settings are used to set
+ * constraints for the encoded file. This function uses these settings to
+ * select the appropriate encoding mode and set it up.
+ *
+ * \param vi Pointer to an initialized \ref vorbis_info struct.
+ * \param channels The number of channels to be encoded.
+ * \param rate The sampling rate of the source audio.
+ * \param max_bitrate Desired maximum bitrate (limit). -1 indicates unset.
+ * \param nominal_bitrate Desired average, or central, bitrate. -1 indicates unset.
+ * \param min_bitrate Desired minimum bitrate. -1 indicates unset.
+ *
+ * \return Zero for success, and negative values for failure.
+ *
+ * \retval 0 Success.
+ * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption.
+ * \retval OV_EINVAL Invalid setup request, eg, out of range argument.
+ * \retval OV_EIMPL Unimplemented mode; unable to comply with bitrate request.
+ */
+extern int vorbis_encode_init(vorbis_info *vi,
+ long channels,
+ long rate,
+
+ long max_bitrate,
+ long nominal_bitrate,
+ long min_bitrate);
+
+/**
+ * This function performs step-one of a three-step bitrate-managed encode
+ * setup. It functions similarly to the one-step setup performed by \ref
+ * vorbis_encode_init but allows an application to make further encode setup
+ * tweaks using \ref vorbis_encode_ctl before finally calling \ref
+ * vorbis_encode_setup_init to complete the setup process.
+ *
+ * Before this function is called, the \ref vorbis_info struct should be
+ * initialized by using vorbis_info_init() from the libvorbis API. After
+ * encoding, vorbis_info_clear() should be called.
+ *
+ * The max_bitrate, nominal_bitrate, and min_bitrate settings are used to set
+ * constraints for the encoded file. This function uses these settings to
+ * select the appropriate encoding mode and set it up.
+ *
+ * \param vi Pointer to an initialized vorbis_info struct.
+ * \param channels The number of channels to be encoded.
+ * \param rate The sampling rate of the source audio.
+ * \param max_bitrate Desired maximum bitrate (limit). -1 indicates unset.
+ * \param nominal_bitrate Desired average, or central, bitrate. -1 indicates unset.
+ * \param min_bitrate Desired minimum bitrate. -1 indicates unset.
+ *
+ * \return Zero for success, and negative for failure.
+ *
+ * \retval 0 Success
+ * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption.
+ * \retval OV_EINVAL Invalid setup request, eg, out of range argument.
+ * \retval OV_EIMPL Unimplemented mode; unable to comply with bitrate request.
+ */
+extern int vorbis_encode_setup_managed(vorbis_info *vi,
+ long channels,
+ long rate,
+
+ long max_bitrate,
+ long nominal_bitrate,
+ long min_bitrate);
+
+/**
+ * This function performs step-one of a three-step variable bitrate
+ * (quality-based) encode setup. It functions similarly to the one-step setup
+ * performed by \ref vorbis_encode_init_vbr() but allows an application to
+ * make further encode setup tweaks using \ref vorbis_encode_ctl() before
+ * finally calling \ref vorbis_encode_setup_init to complete the setup
+ * process.
+ *
+ * Before this function is called, the \ref vorbis_info struct should be
+ * initialized by using \ref vorbis_info_init() from the libvorbis API. After
+ * encoding, vorbis_info_clear() should be called.
+ *
+ * \param vi Pointer to an initialized vorbis_info struct.
+ * \param channels The number of channels to be encoded.
+ * \param rate The sampling rate of the source audio.
+ * \param quality Desired quality level, currently from -0.1 to 1.0 (lo to hi).
+ *
+ * \return Zero for success, and negative values for failure.
+ *
+ * \retval 0 Success
+ * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption.
+ * \retval OV_EINVAL Invalid setup request, eg, out of range argument.
+ * \retval OV_EIMPL Unimplemented mode; unable to comply with quality level request.
+ */
+extern int vorbis_encode_setup_vbr(vorbis_info *vi,
+ long channels,
+ long rate,
+
+ float quality
+ );
+
+/**
+ * This is the primary function within libvorbisenc for setting up variable
+ * bitrate ("quality" based) modes.
+ *
+ *
+ * Before this function is called, the vorbis_info struct should be
+ * initialized by using vorbis_info_init() from the libvorbis API. After
+ * encoding, vorbis_info_clear() should be called.
+ *
+ * \param vi Pointer to an initialized vorbis_info struct.
+ * \param channels The number of channels to be encoded.
+ * \param rate The sampling rate of the source audio.
+ * \param base_quality Desired quality level, currently from -0.1 to 1.0 (lo to hi).
+ *
+ *
+ * \return Zero for success, or a negative number for failure.
+ *
+ * \retval 0 Success
+ * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption.
+ * \retval OV_EINVAL Invalid setup request, eg, out of range argument.
+ * \retval OV_EIMPL Unimplemented mode; unable to comply with quality level request.
+ */
+extern int vorbis_encode_init_vbr(vorbis_info *vi,
+ long channels,
+ long rate,
+
+ float base_quality
+ );
+
+/**
+ * This function performs the last stage of three-step encoding setup, as
+ * described in the API overview under managed bitrate modes.
+ *
+ * Before this function is called, the \ref vorbis_info struct should be
+ * initialized by using vorbis_info_init() from the libvorbis API, one of
+ * \ref vorbis_encode_setup_managed() or \ref vorbis_encode_setup_vbr() called to
+ * initialize the high-level encoding setup, and \ref vorbis_encode_ctl()
+ * called if necessary to make encoding setup changes.
+ * vorbis_encode_setup_init() finalizes the highlevel encoding structure into
+ * a complete encoding setup after which the application may make no further
+ * setup changes.
+ *
+ * After encoding, vorbis_info_clear() should be called.
+ *
+ * \param vi Pointer to an initialized \ref vorbis_info struct.
+ *
+ * \return Zero for success, and negative values for failure.
+ *
+ * \retval 0 Success.
+ * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption.
+ *
+ * \retval OV_EINVAL Attempt to use vorbis_encode_setup_init() without first
+ * calling one of vorbis_encode_setup_managed() or vorbis_encode_setup_vbr() to
+ * initialize the high-level encoding setup
+ *
+ */
+extern int vorbis_encode_setup_init(vorbis_info *vi);
+
+/**
+ * This function implements a generic interface to miscellaneous encoder
+ * settings similar to the classic UNIX 'ioctl()' system call. Applications
+ * may use vorbis_encode_ctl() to query or set bitrate management or quality
+ * mode details by using one of several \e request arguments detailed below.
+ * vorbis_encode_ctl() must be called after one of
+ * vorbis_encode_setup_managed() or vorbis_encode_setup_vbr(). When used
+ * to modify settings, \ref vorbis_encode_ctl() must be called before \ref
+ * vorbis_encode_setup_init().
+ *
+ * \param vi Pointer to an initialized vorbis_info struct.
+ *
+ * \param number Specifies the desired action; See \ref encctlcodes "the list
+ * of available requests".
+ *
+ * \param arg void * pointing to a data structure matching the request
+ * argument.
+ *
+ * \retval 0 Success. Any further return information (such as the result of a
+ * query) is placed into the storage pointed to by *arg.
+ *
+ * \retval OV_EINVAL Invalid argument, or an attempt to modify a setting after
+ * calling vorbis_encode_setup_init().
+ *
+ * \retval OV_EIMPL Unimplemented or unknown request
+ */
+extern int vorbis_encode_ctl(vorbis_info *vi,int number,void *arg);
+
+/**
+ * \deprecated This is a deprecated interface. Please use vorbis_encode_ctl()
+ * with the \ref ovectl_ratemanage2_arg struct and \ref
+ * OV_ECTL_RATEMANAGE2_GET and \ref OV_ECTL_RATEMANAGE2_SET calls in new code.
+ *
+ * The \ref ovectl_ratemanage_arg structure is used with vorbis_encode_ctl()
+ * and the \ref OV_ECTL_RATEMANAGE_GET, \ref OV_ECTL_RATEMANAGE_SET, \ref
+ * OV_ECTL_RATEMANAGE_AVG, \ref OV_ECTL_RATEMANAGE_HARD calls in order to
+ * query and modify specifics of the encoder's bitrate management
+ * configuration.
+*/
+struct ovectl_ratemanage_arg {
+ int management_active; /**< nonzero if bitrate management is active*/
+/** hard lower limit (in kilobits per second) below which the stream bitrate
+ will never be allowed for any given bitrate_hard_window seconds of time.*/
+ long bitrate_hard_min;
+/** hard upper limit (in kilobits per second) above which the stream bitrate
+ will never be allowed for any given bitrate_hard_window seconds of time.*/
+ long bitrate_hard_max;
+/** the window period (in seconds) used to regulate the hard bitrate minimum
+ and maximum*/
+ double bitrate_hard_window;
+/** soft lower limit (in kilobits per second) below which the average bitrate
+ tracker will start nudging the bitrate higher.*/
+ long bitrate_av_lo;
+/** soft upper limit (in kilobits per second) above which the average bitrate
+ tracker will start nudging the bitrate lower.*/
+ long bitrate_av_hi;
+/** the window period (in seconds) used to regulate the average bitrate
+ minimum and maximum.*/
+ double bitrate_av_window;
+/** Regulates the relative centering of the average and hard windows; in
+ libvorbis 1.0 and 1.0.1, the hard window regulation overlapped but
+ followed the average window regulation. In libvorbis 1.1 a bit-reservoir
+ interface replaces the old windowing interface; the older windowing
+ interface is simulated and this field has no effect.*/
+ double bitrate_av_window_center;
+};
+
+/**
+ * \name struct ovectl_ratemanage2_arg
+ *
+ * The ovectl_ratemanage2_arg structure is used with vorbis_encode_ctl() and
+ * the OV_ECTL_RATEMANAGE2_GET and OV_ECTL_RATEMANAGE2_SET calls in order to
+ * query and modify specifics of the encoder's bitrate management
+ * configuration.
+ *
+*/
+struct ovectl_ratemanage2_arg {
+ int management_active; /**< nonzero if bitrate management is active */
+/** Lower allowed bitrate limit in kilobits per second */
+ long bitrate_limit_min_kbps;
+/** Upper allowed bitrate limit in kilobits per second */
+ long bitrate_limit_max_kbps;
+ long bitrate_limit_reservoir_bits; /**<Size of the bitrate reservoir in bits */
+/** Regulates the bitrate reservoir's preferred fill level in a range from 0.0
+ * to 1.0; 0.0 tries to bank bits to buffer against future bitrate spikes, 1.0
+ * buffers against future sudden drops in instantaneous bitrate. Default is
+ * 0.1
+ */
+ double bitrate_limit_reservoir_bias;
+/** Average bitrate setting in kilobits per second */
+ long bitrate_average_kbps;
+/** Slew rate limit setting for average bitrate adjustment; sets the minimum
+ * time in seconds the bitrate tracker may swing from one extreme to the
+ * other when boosting or damping average bitrate.
+ */
+ double bitrate_average_damping;
+};
+
+
+/**
+ * \name vorbis_encode_ctl() codes
+ *
+ * \anchor encctlcodes
+ *
+ * These values are passed as the \c number parameter of vorbis_encode_ctl().
+ * The type of the referent of that function's \c arg pointer depends on these
+ * codes.
+ */
+/*@{*/
+
+/**
+ * Query the current encoder bitrate management setting.
+ *
+ *Argument: <tt>struct ovectl_ratemanage2_arg *</tt>
+ *
+ * Used to query the current encoder bitrate management setting. Also used to
+ * initialize fields of an ovectl_ratemanage2_arg structure for use with
+ * \ref OV_ECTL_RATEMANAGE2_SET.
+ */
+#define OV_ECTL_RATEMANAGE2_GET 0x14
+
+/**
+ * Set the current encoder bitrate management settings.
+ *
+ * Argument: <tt>struct ovectl_ratemanage2_arg *</tt>
+ *
+ * Used to set the current encoder bitrate management settings to the values
+ * listed in the ovectl_ratemanage2_arg. Passing a NULL pointer will disable
+ * bitrate management.
+*/
+#define OV_ECTL_RATEMANAGE2_SET 0x15
+
+/**
+ * Returns the current encoder hard-lowpass setting (kHz) in the double
+ * pointed to by arg.
+ *
+ * Argument: <tt>double *</tt>
+*/
+#define OV_ECTL_LOWPASS_GET 0x20
+
+/**
+ * Sets the encoder hard-lowpass to the value (kHz) pointed to by arg. Valid
+ * lowpass settings range from 2 to 99.
+ *
+ * Argument: <tt>double *</tt>
+*/
+#define OV_ECTL_LOWPASS_SET 0x21
+
+/**
+ * Returns the current encoder impulse block setting in the double pointed
+ * to by arg.
+ *
+ * Argument: <tt>double *</tt>
+*/
+#define OV_ECTL_IBLOCK_GET 0x30
+
+/**
+ * Sets the impulse block bias to the the value pointed to by arg.
+ *
+ * Argument: <tt>double *</tt>
+ *
+ * Valid range is -15.0 to 0.0 [default]. A negative impulse block bias will
+ * direct to encoder to use more bits when incoding short blocks that contain
+ * strong impulses, thus improving the accuracy of impulse encoding.
+ */
+#define OV_ECTL_IBLOCK_SET 0x31
+
+/**
+ * Returns the current encoder coupling setting in the int pointed
+ * to by arg.
+ *
+ * Argument: <tt>int *</tt>
+*/
+#define OV_ECTL_COUPLING_GET 0x40
+
+/**
+ * Enables/disables channel coupling in multichannel encoding according to arg.
+ *
+ * Argument: <tt>int *</tt>
+ *
+ * Zero disables channel coupling for multichannel inputs, nonzer enables
+ * channel coupling. Setting has no effect on monophonic encoding or
+ * multichannel counts that do not offer coupling. At present, coupling is
+ * available for stereo and 5.1 encoding.
+ */
+#define OV_ECTL_COUPLING_SET 0x41
+
+ /* deprecated rate management supported only for compatibility */
+
+/**
+ * Old interface to querying bitrate management settings.
+ *
+ * Deprecated after move to bit-reservoir style management in 1.1 rendered
+ * this interface partially obsolete.
+
+ * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_GET instead.
+ *
+ * Argument: <tt>struct ovectl_ratemanage_arg *</tt>
+ */
+#define OV_ECTL_RATEMANAGE_GET 0x10
+/**
+ * Old interface to modifying bitrate management settings.
+ *
+ * deprecated after move to bit-reservoir style management in 1.1 rendered
+ * this interface partially obsolete.
+ *
+ * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_SET instead.
+ *
+ * Argument: <tt>struct ovectl_ratemanage_arg *</tt>
+ */
+#define OV_ECTL_RATEMANAGE_SET 0x11
+/**
+ * Old interface to setting average-bitrate encoding mode.
+ *
+ * Deprecated after move to bit-reservoir style management in 1.1 rendered
+ * this interface partially obsolete.
+ *
+ * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_SET instead.
+ *
+ * Argument: <tt>struct ovectl_ratemanage_arg *</tt>
+ */
+#define OV_ECTL_RATEMANAGE_AVG 0x12
+/**
+ * Old interface to setting bounded-bitrate encoding modes.
+ *
+ * deprecated after move to bit-reservoir style management in 1.1 rendered
+ * this interface partially obsolete.
+ *
+ * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_SET instead.
+ *
+ * Argument: <tt>struct ovectl_ratemanage_arg *</tt>
+ */
+#define OV_ECTL_RATEMANAGE_HARD 0x13
+
+/*@}*/
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/external/libvorbis-1.3.5/include/vorbis/vorbisfile.h b/external/libvorbis-1.3.5/include/vorbis/vorbisfile.h
new file mode 100644
index 0000000..9271331
--- /dev/null
+++ b/external/libvorbis-1.3.5/include/vorbis/vorbisfile.h
@@ -0,0 +1,206 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: stdio-based convenience library for opening/seeking/decoding
+ last mod: $Id: vorbisfile.h 17182 2010-04-29 03:48:32Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _OV_FILE_H_
+#define _OV_FILE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#include <stdio.h>
+#include "codec.h"
+
+/* The function prototypes for the callbacks are basically the same as for
+ * the stdio functions fread, fseek, fclose, ftell.
+ * The one difference is that the FILE * arguments have been replaced with
+ * a void * - this is to be used as a pointer to whatever internal data these
+ * functions might need. In the stdio case, it's just a FILE * cast to a void *
+ *
+ * If you use other functions, check the docs for these functions and return
+ * the right values. For seek_func(), you *MUST* return -1 if the stream is
+ * unseekable
+ */
+typedef struct {
+ size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource);
+ int (*seek_func) (void *datasource, ogg_int64_t offset, int whence);
+ int (*close_func) (void *datasource);
+ long (*tell_func) (void *datasource);
+} ov_callbacks;
+
+#ifndef OV_EXCLUDE_STATIC_CALLBACKS
+
+/* a few sets of convenient callbacks, especially for use under
+ * Windows where ov_open_callbacks() should always be used instead of
+ * ov_open() to avoid problems with incompatible crt.o version linking
+ * issues. */
+
+static int _ov_header_fseek_wrap(FILE *f,ogg_int64_t off,int whence){
+ if(f==NULL)return(-1);
+
+#ifdef __MINGW32__
+ return fseeko64(f,off,whence);
+#elif defined (_WIN32)
+ return _fseeki64(f,off,whence);
+#else
+ return fseek(f,off,whence);
+#endif
+}
+
+/* These structs below (OV_CALLBACKS_DEFAULT etc) are defined here as
+ * static data. That means that every file which includes this header
+ * will get its own copy of these structs whether it uses them or
+ * not unless it #defines OV_EXCLUDE_STATIC_CALLBACKS.
+ * These static symbols are essential on platforms such as Windows on
+ * which several different versions of stdio support may be linked to
+ * by different DLLs, and we need to be certain we know which one
+ * we're using (the same one as the main application).
+ */
+
+static ov_callbacks OV_CALLBACKS_DEFAULT = {
+ (size_t (*)(void *, size_t, size_t, void *)) fread,
+ (int (*)(void *, ogg_int64_t, int)) _ov_header_fseek_wrap,
+ (int (*)(void *)) fclose,
+ (long (*)(void *)) ftell
+};
+
+static ov_callbacks OV_CALLBACKS_NOCLOSE = {
+ (size_t (*)(void *, size_t, size_t, void *)) fread,
+ (int (*)(void *, ogg_int64_t, int)) _ov_header_fseek_wrap,
+ (int (*)(void *)) NULL,
+ (long (*)(void *)) ftell
+};
+
+static ov_callbacks OV_CALLBACKS_STREAMONLY = {
+ (size_t (*)(void *, size_t, size_t, void *)) fread,
+ (int (*)(void *, ogg_int64_t, int)) NULL,
+ (int (*)(void *)) fclose,
+ (long (*)(void *)) NULL
+};
+
+static ov_callbacks OV_CALLBACKS_STREAMONLY_NOCLOSE = {
+ (size_t (*)(void *, size_t, size_t, void *)) fread,
+ (int (*)(void *, ogg_int64_t, int)) NULL,
+ (int (*)(void *)) NULL,
+ (long (*)(void *)) NULL
+};
+
+#endif
+
+#define NOTOPEN 0
+#define PARTOPEN 1
+#define OPENED 2
+#define STREAMSET 3
+#define INITSET 4
+
+typedef struct OggVorbis_File {
+ void *datasource; /* Pointer to a FILE *, etc. */
+ int seekable;
+ ogg_int64_t offset;
+ ogg_int64_t end;
+ ogg_sync_state oy;
+
+ /* If the FILE handle isn't seekable (eg, a pipe), only the current
+ stream appears */
+ int links;
+ ogg_int64_t *offsets;
+ ogg_int64_t *dataoffsets;
+ long *serialnos;
+ ogg_int64_t *pcmlengths; /* overloaded to maintain binary
+ compatibility; x2 size, stores both
+ beginning and end values */
+ vorbis_info *vi;
+ vorbis_comment *vc;
+
+ /* Decoding working state local storage */
+ ogg_int64_t pcm_offset;
+ int ready_state;
+ long current_serialno;
+ int current_link;
+
+ double bittrack;
+ double samptrack;
+
+ ogg_stream_state os; /* take physical pages, weld into a logical
+ stream of packets */
+ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
+ vorbis_block vb; /* local working space for packet->PCM decode */
+
+ ov_callbacks callbacks;
+
+} OggVorbis_File;
+
+
+extern int ov_clear(OggVorbis_File *vf);
+extern int ov_fopen(const char *path,OggVorbis_File *vf);
+extern int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes);
+extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf,
+ const char *initial, long ibytes, ov_callbacks callbacks);
+
+extern int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes);
+extern int ov_test_callbacks(void *datasource, OggVorbis_File *vf,
+ const char *initial, long ibytes, ov_callbacks callbacks);
+extern int ov_test_open(OggVorbis_File *vf);
+
+extern long ov_bitrate(OggVorbis_File *vf,int i);
+extern long ov_bitrate_instant(OggVorbis_File *vf);
+extern long ov_streams(OggVorbis_File *vf);
+extern long ov_seekable(OggVorbis_File *vf);
+extern long ov_serialnumber(OggVorbis_File *vf,int i);
+
+extern ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i);
+extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i);
+extern double ov_time_total(OggVorbis_File *vf,int i);
+
+extern int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos);
+extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos);
+extern int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos);
+extern int ov_time_seek(OggVorbis_File *vf,double pos);
+extern int ov_time_seek_page(OggVorbis_File *vf,double pos);
+
+extern int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos);
+extern int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos);
+extern int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos);
+extern int ov_time_seek_lap(OggVorbis_File *vf,double pos);
+extern int ov_time_seek_page_lap(OggVorbis_File *vf,double pos);
+
+extern ogg_int64_t ov_raw_tell(OggVorbis_File *vf);
+extern ogg_int64_t ov_pcm_tell(OggVorbis_File *vf);
+extern double ov_time_tell(OggVorbis_File *vf);
+
+extern vorbis_info *ov_info(OggVorbis_File *vf,int link);
+extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link);
+
+extern long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int samples,
+ int *bitstream);
+extern long ov_read_filter(OggVorbis_File *vf,char *buffer,int length,
+ int bigendianp,int word,int sgned,int *bitstream,
+ void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param);
+extern long ov_read(OggVorbis_File *vf,char *buffer,int length,
+ int bigendianp,int word,int sgned,int *bitstream);
+extern int ov_crosslap(OggVorbis_File *vf1,OggVorbis_File *vf2);
+
+extern int ov_halfrate(OggVorbis_File *vf,int flag);
+extern int ov_halfrate_p(OggVorbis_File *vf);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+
diff --git a/external/libvorbis-1.3.5/lib/analysis.c b/external/libvorbis-1.3.5/lib/analysis.c
new file mode 100644
index 0000000..01aa6f3
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/analysis.c
@@ -0,0 +1,120 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: single-block PCM analysis mode dispatch
+ last mod: $Id: analysis.c 16226 2009-07-08 06:43:49Z xiphmont $
+
+ ********************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+#include "registry.h"
+#include "scales.h"
+#include "os.h"
+#include "misc.h"
+
+/* decides between modes, dispatches to the appropriate mapping. */
+int vorbis_analysis(vorbis_block *vb, ogg_packet *op){
+ int ret,i;
+ vorbis_block_internal *vbi=vb->internal;
+
+ vb->glue_bits=0;
+ vb->time_bits=0;
+ vb->floor_bits=0;
+ vb->res_bits=0;
+
+ /* first things first. Make sure encode is ready */
+ for(i=0;i<PACKETBLOBS;i++)
+ oggpack_reset(vbi->packetblob[i]);
+
+ /* we only have one mapping type (0), and we let the mapping code
+ itself figure out what soft mode to use. This allows easier
+ bitrate management */
+
+ if((ret=_mapping_P[0]->forward(vb)))
+ return(ret);
+
+ if(op){
+ if(vorbis_bitrate_managed(vb))
+ /* The app is using a bitmanaged mode... but not using the
+ bitrate management interface. */
+ return(OV_EINVAL);
+
+ op->packet=oggpack_get_buffer(&vb->opb);
+ op->bytes=oggpack_bytes(&vb->opb);
+ op->b_o_s=0;
+ op->e_o_s=vb->eofflag;
+ op->granulepos=vb->granulepos;
+ op->packetno=vb->sequence; /* for sake of completeness */
+ }
+ return(0);
+}
+
+#ifdef ANALYSIS
+int analysis_noisy=1;
+
+/* there was no great place to put this.... */
+void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,ogg_int64_t off){
+ int j;
+ FILE *of;
+ char buffer[80];
+
+ sprintf(buffer,"%s_%d.m",base,i);
+ of=fopen(buffer,"w");
+
+ if(!of)perror("failed to open data dump file");
+
+ for(j=0;j<n;j++){
+ if(bark){
+ float b=toBARK((4000.f*j/n)+.25);
+ fprintf(of,"%f ",b);
+ }else
+ if(off!=0)
+ fprintf(of,"%f ",(double)(j+off)/8000.);
+ else
+ fprintf(of,"%f ",(double)j);
+
+ if(dB){
+ float val;
+ if(v[j]==0.)
+ val=-140.;
+ else
+ val=todB(v+j);
+ fprintf(of,"%f\n",val);
+ }else{
+ fprintf(of,"%f\n",v[j]);
+ }
+ }
+ fclose(of);
+}
+
+void _analysis_output(char *base,int i,float *v,int n,int bark,int dB,
+ ogg_int64_t off){
+ if(analysis_noisy)_analysis_output_always(base,i,v,n,bark,dB,off);
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
diff --git a/external/libvorbis-1.3.5/lib/backends.h b/external/libvorbis-1.3.5/lib/backends.h
new file mode 100644
index 0000000..ff5bcc9
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/backends.h
@@ -0,0 +1,144 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: libvorbis backend and mapping structures; needed for
+ static mode headers
+ last mod: $Id: backends.h 16962 2010-03-11 07:30:34Z xiphmont $
+
+ ********************************************************************/
+
+/* this is exposed up here because we need it for static modes.
+ Lookups for each backend aren't exposed because there's no reason
+ to do so */
+
+#ifndef _vorbis_backend_h_
+#define _vorbis_backend_h_
+
+#include "codec_internal.h"
+
+/* this would all be simpler/shorter with templates, but.... */
+/* Floor backend generic *****************************************/
+typedef struct{
+ void (*pack) (vorbis_info_floor *,oggpack_buffer *);
+ vorbis_info_floor *(*unpack)(vorbis_info *,oggpack_buffer *);
+ vorbis_look_floor *(*look) (vorbis_dsp_state *,vorbis_info_floor *);
+ void (*free_info) (vorbis_info_floor *);
+ void (*free_look) (vorbis_look_floor *);
+ void *(*inverse1) (struct vorbis_block *,vorbis_look_floor *);
+ int (*inverse2) (struct vorbis_block *,vorbis_look_floor *,
+ void *buffer,float *);
+} vorbis_func_floor;
+
+typedef struct{
+ int order;
+ long rate;
+ long barkmap;
+
+ int ampbits;
+ int ampdB;
+
+ int numbooks; /* <= 16 */
+ int books[16];
+
+ float lessthan; /* encode-only config setting hacks for libvorbis */
+ float greaterthan; /* encode-only config setting hacks for libvorbis */
+
+} vorbis_info_floor0;
+
+
+#define VIF_POSIT 63
+#define VIF_CLASS 16
+#define VIF_PARTS 31
+typedef struct{
+ int partitions; /* 0 to 31 */
+ int partitionclass[VIF_PARTS]; /* 0 to 15 */
+
+ int class_dim[VIF_CLASS]; /* 1 to 8 */
+ int class_subs[VIF_CLASS]; /* 0,1,2,3 (bits: 1<<n poss) */
+ int class_book[VIF_CLASS]; /* subs ^ dim entries */
+ int class_subbook[VIF_CLASS][8]; /* [VIF_CLASS][subs] */
+
+
+ int mult; /* 1 2 3 or 4 */
+ int postlist[VIF_POSIT+2]; /* first two implicit */
+
+
+ /* encode side analysis parameters */
+ float maxover;
+ float maxunder;
+ float maxerr;
+
+ float twofitweight;
+ float twofitatten;
+
+ int n;
+
+} vorbis_info_floor1;
+
+/* Residue backend generic *****************************************/
+typedef struct{
+ void (*pack) (vorbis_info_residue *,oggpack_buffer *);
+ vorbis_info_residue *(*unpack)(vorbis_info *,oggpack_buffer *);
+ vorbis_look_residue *(*look) (vorbis_dsp_state *,
+ vorbis_info_residue *);
+ void (*free_info) (vorbis_info_residue *);
+ void (*free_look) (vorbis_look_residue *);
+ long **(*class) (struct vorbis_block *,vorbis_look_residue *,
+ int **,int *,int);
+ int (*forward) (oggpack_buffer *,struct vorbis_block *,
+ vorbis_look_residue *,
+ int **,int *,int,long **,int);
+ int (*inverse) (struct vorbis_block *,vorbis_look_residue *,
+ float **,int *,int);
+} vorbis_func_residue;
+
+typedef struct vorbis_info_residue0{
+/* block-partitioned VQ coded straight residue */
+ long begin;
+ long end;
+
+ /* first stage (lossless partitioning) */
+ int grouping; /* group n vectors per partition */
+ int partitions; /* possible codebooks for a partition */
+ int partvals; /* partitions ^ groupbook dim */
+ int groupbook; /* huffbook for partitioning */
+ int secondstages[64]; /* expanded out to pointers in lookup */
+ int booklist[512]; /* list of second stage books */
+
+ const int classmetric1[64];
+ const int classmetric2[64];
+} vorbis_info_residue0;
+
+/* Mapping backend generic *****************************************/
+typedef struct{
+ void (*pack) (vorbis_info *,vorbis_info_mapping *,
+ oggpack_buffer *);
+ vorbis_info_mapping *(*unpack)(vorbis_info *,oggpack_buffer *);
+ void (*free_info) (vorbis_info_mapping *);
+ int (*forward) (struct vorbis_block *vb);
+ int (*inverse) (struct vorbis_block *vb,vorbis_info_mapping *);
+} vorbis_func_mapping;
+
+typedef struct vorbis_info_mapping0{
+ int submaps; /* <= 16 */
+ int chmuxlist[256]; /* up to 256 channels in a Vorbis stream */
+
+ int floorsubmap[16]; /* [mux] submap to floors */
+ int residuesubmap[16]; /* [mux] submap to residue */
+
+ int coupling_steps;
+ int coupling_mag[256];
+ int coupling_ang[256];
+
+} vorbis_info_mapping0;
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/bitrate.c b/external/libvorbis-1.3.5/lib/bitrate.c
new file mode 100644
index 0000000..3a71b1d
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/bitrate.c
@@ -0,0 +1,253 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: bitrate tracking and management
+ last mod: $Id: bitrate.c 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+#include "os.h"
+#include "misc.h"
+#include "bitrate.h"
+
+/* compute bitrate tracking setup */
+void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){
+ codec_setup_info *ci=vi->codec_setup;
+ bitrate_manager_info *bi=&ci->bi;
+
+ memset(bm,0,sizeof(*bm));
+
+ if(bi && (bi->reservoir_bits>0)){
+ long ratesamples=vi->rate;
+ int halfsamples=ci->blocksizes[0]>>1;
+
+ bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0];
+ bm->managed=1;
+
+ bm->avg_bitsper= rint(1.*bi->avg_rate*halfsamples/ratesamples);
+ bm->min_bitsper= rint(1.*bi->min_rate*halfsamples/ratesamples);
+ bm->max_bitsper= rint(1.*bi->max_rate*halfsamples/ratesamples);
+
+ bm->avgfloat=PACKETBLOBS/2;
+
+ /* not a necessary fix, but one that leads to a more balanced
+ typical initialization */
+ {
+ long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
+ bm->minmax_reservoir=desired_fill;
+ bm->avg_reservoir=desired_fill;
+ }
+
+ }
+}
+
+void vorbis_bitrate_clear(bitrate_manager_state *bm){
+ memset(bm,0,sizeof(*bm));
+ return;
+}
+
+int vorbis_bitrate_managed(vorbis_block *vb){
+ vorbis_dsp_state *vd=vb->vd;
+ private_state *b=vd->backend_state;
+ bitrate_manager_state *bm=&b->bms;
+
+ if(bm && bm->managed)return(1);
+ return(0);
+}
+
+/* finish taking in the block we just processed */
+int vorbis_bitrate_addblock(vorbis_block *vb){
+ vorbis_block_internal *vbi=vb->internal;
+ vorbis_dsp_state *vd=vb->vd;
+ private_state *b=vd->backend_state;
+ bitrate_manager_state *bm=&b->bms;
+ vorbis_info *vi=vd->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ bitrate_manager_info *bi=&ci->bi;
+
+ int choice=rint(bm->avgfloat);
+ long this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
+ long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper);
+ long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper);
+ int samples=ci->blocksizes[vb->W]>>1;
+ long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
+ if(!bm->managed){
+ /* not a bitrate managed stream, but for API simplicity, we'll
+ buffer the packet to keep the code path clean */
+
+ if(bm->vb)return(-1); /* one has been submitted without
+ being claimed */
+ bm->vb=vb;
+ return(0);
+ }
+
+ bm->vb=vb;
+
+ /* look ahead for avg floater */
+ if(bm->avg_bitsper>0){
+ double slew=0.;
+ long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
+ double slewlimit= 15./bi->slew_damp;
+
+ /* choosing a new floater:
+ if we're over target, we slew down
+ if we're under target, we slew up
+
+ choose slew as follows: look through packetblobs of this frame
+ and set slew as the first in the appropriate direction that
+ gives us the slew we want. This may mean no slew if delta is
+ already favorable.
+
+ Then limit slew to slew max */
+
+ if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
+ while(choice>0 && this_bits>avg_target_bits &&
+ bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
+ choice--;
+ this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
+ }
+ }else if(bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
+ while(choice+1<PACKETBLOBS && this_bits<avg_target_bits &&
+ bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
+ choice++;
+ this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
+ }
+ }
+
+ slew=rint(choice-bm->avgfloat)/samples*vi->rate;
+ if(slew<-slewlimit)slew=-slewlimit;
+ if(slew>slewlimit)slew=slewlimit;
+ choice=rint(bm->avgfloat+= slew/vi->rate*samples);
+ this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
+ }
+
+
+
+ /* enforce min(if used) on the current floater (if used) */
+ if(bm->min_bitsper>0){
+ /* do we need to force the bitrate up? */
+ if(this_bits<min_target_bits){
+ while(bm->minmax_reservoir-(min_target_bits-this_bits)<0){
+ choice++;
+ if(choice>=PACKETBLOBS)break;
+ this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
+ }
+ }
+ }
+
+ /* enforce max (if used) on the current floater (if used) */
+ if(bm->max_bitsper>0){
+ /* do we need to force the bitrate down? */
+ if(this_bits>max_target_bits){
+ while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){
+ choice--;
+ if(choice<0)break;
+ this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
+ }
+ }
+ }
+
+ /* Choice of packetblobs now made based on floater, and min/max
+ requirements. Now boundary check extreme choices */
+
+ if(choice<0){
+ /* choosing a smaller packetblob is insufficient to trim bitrate.
+ frame will need to be truncated */
+ long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8;
+ bm->choice=choice=0;
+
+ if(oggpack_bytes(vbi->packetblob[choice])>maxsize){
+
+ oggpack_writetrunc(vbi->packetblob[choice],maxsize*8);
+ this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
+ }
+ }else{
+ long minsize=(min_target_bits-bm->minmax_reservoir+7)/8;
+ if(choice>=PACKETBLOBS)
+ choice=PACKETBLOBS-1;
+
+ bm->choice=choice;
+
+ /* prop up bitrate according to demand. pad this frame out with zeroes */
+ minsize-=oggpack_bytes(vbi->packetblob[choice]);
+ while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8);
+ this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
+
+ }
+
+ /* now we have the final packet and the final packet size. Update statistics */
+ /* min and max reservoir */
+ if(bm->min_bitsper>0 || bm->max_bitsper>0){
+
+ if(max_target_bits>0 && this_bits>max_target_bits){
+ bm->minmax_reservoir+=(this_bits-max_target_bits);
+ }else if(min_target_bits>0 && this_bits<min_target_bits){
+ bm->minmax_reservoir+=(this_bits-min_target_bits);
+ }else{
+ /* inbetween; we want to take reservoir toward but not past desired_fill */
+ if(bm->minmax_reservoir>desired_fill){
+ if(max_target_bits>0){ /* logical bulletproofing against initialization state */
+ bm->minmax_reservoir+=(this_bits-max_target_bits);
+ if(bm->minmax_reservoir<desired_fill)bm->minmax_reservoir=desired_fill;
+ }else{
+ bm->minmax_reservoir=desired_fill;
+ }
+ }else{
+ if(min_target_bits>0){ /* logical bulletproofing against initialization state */
+ bm->minmax_reservoir+=(this_bits-min_target_bits);
+ if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill;
+ }else{
+ bm->minmax_reservoir=desired_fill;
+ }
+ }
+ }
+ }
+
+ /* avg reservoir */
+ if(bm->avg_bitsper>0){
+ long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
+ bm->avg_reservoir+=this_bits-avg_target_bits;
+ }
+
+ return(0);
+}
+
+int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){
+ private_state *b=vd->backend_state;
+ bitrate_manager_state *bm=&b->bms;
+ vorbis_block *vb=bm->vb;
+ int choice=PACKETBLOBS/2;
+ if(!vb)return 0;
+
+ if(op){
+ vorbis_block_internal *vbi=vb->internal;
+
+ if(vorbis_bitrate_managed(vb))
+ choice=bm->choice;
+
+ op->packet=oggpack_get_buffer(vbi->packetblob[choice]);
+ op->bytes=oggpack_bytes(vbi->packetblob[choice]);
+ op->b_o_s=0;
+ op->e_o_s=vb->eofflag;
+ op->granulepos=vb->granulepos;
+ op->packetno=vb->sequence; /* for sake of completeness */
+ }
+
+ bm->vb=0;
+ return(1);
+}
diff --git a/external/libvorbis-1.3.5/lib/bitrate.h b/external/libvorbis-1.3.5/lib/bitrate.h
new file mode 100644
index 0000000..db48fcb
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/bitrate.h
@@ -0,0 +1,59 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: bitrate tracking and management
+ last mod: $Id: bitrate.h 13293 2007-07-24 00:09:47Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_BITRATE_H_
+#define _V_BITRATE_H_
+
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+#include "os.h"
+
+/* encode side bitrate tracking */
+typedef struct bitrate_manager_state {
+ int managed;
+
+ long avg_reservoir;
+ long minmax_reservoir;
+ long avg_bitsper;
+ long min_bitsper;
+ long max_bitsper;
+
+ long short_per_long;
+ double avgfloat;
+
+ vorbis_block *vb;
+ int choice;
+} bitrate_manager_state;
+
+typedef struct bitrate_manager_info{
+ long avg_rate;
+ long min_rate;
+ long max_rate;
+ long reservoir_bits;
+ double reservoir_bias;
+
+ double slew_damp;
+
+} bitrate_manager_info;
+
+extern void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bs);
+extern void vorbis_bitrate_clear(bitrate_manager_state *bs);
+extern int vorbis_bitrate_managed(vorbis_block *vb);
+extern int vorbis_bitrate_addblock(vorbis_block *vb);
+extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd, ogg_packet *op);
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/block.c b/external/libvorbis-1.3.5/lib/block.c
new file mode 100644
index 0000000..345c042
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/block.c
@@ -0,0 +1,1047 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: PCM data vector blocking, windowing and dis/reassembly
+ last mod: $Id: block.c 19457 2015-03-03 00:15:29Z giles $
+
+ Handle windowing, overlap-add, etc of the PCM vectors. This is made
+ more amusing by Vorbis' current two allowed block sizes.
+
+ ********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+
+#include "window.h"
+#include "mdct.h"
+#include "lpc.h"
+#include "registry.h"
+#include "misc.h"
+
+/* pcm accumulator examples (not exhaustive):
+
+ <-------------- lW ---------------->
+ <--------------- W ---------------->
+: .....|..... _______________ |
+: .''' | '''_--- | |\ |
+:.....''' |_____--- '''......| | \_______|
+:.................|__________________|_______|__|______|
+ |<------ Sl ------>| > Sr < |endW
+ |beginSl |endSl | |endSr
+ |beginW |endlW |beginSr
+
+
+ |< lW >|
+ <--------------- W ---------------->
+ | | .. ______________ |
+ | | ' `/ | ---_ |
+ |___.'___/`. | ---_____|
+ |_______|__|_______|_________________|
+ | >|Sl|< |<------ Sr ----->|endW
+ | | |endSl |beginSr |endSr
+ |beginW | |endlW
+ mult[0] |beginSl mult[n]
+
+ <-------------- lW ----------------->
+ |<--W-->|
+: .............. ___ | |
+: .''' |`/ \ | |
+:.....''' |/`....\|...|
+:.........................|___|___|___|
+ |Sl |Sr |endW
+ | | |endSr
+ | |beginSr
+ | |endSl
+ |beginSl
+ |beginW
+*/
+
+/* block abstraction setup *********************************************/
+
+#ifndef WORD_ALIGN
+#define WORD_ALIGN 8
+#endif
+
+int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
+ int i;
+ memset(vb,0,sizeof(*vb));
+ vb->vd=v;
+ vb->localalloc=0;
+ vb->localstore=NULL;
+ if(v->analysisp){
+ vorbis_block_internal *vbi=
+ vb->internal=_ogg_calloc(1,sizeof(vorbis_block_internal));
+ vbi->ampmax=-9999;
+
+ for(i=0;i<PACKETBLOBS;i++){
+ if(i==PACKETBLOBS/2){
+ vbi->packetblob[i]=&vb->opb;
+ }else{
+ vbi->packetblob[i]=
+ _ogg_calloc(1,sizeof(oggpack_buffer));
+ }
+ oggpack_writeinit(vbi->packetblob[i]);
+ }
+ }
+
+ return(0);
+}
+
+void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
+ bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
+ if(bytes+vb->localtop>vb->localalloc){
+ /* can't just _ogg_realloc... there are outstanding pointers */
+ if(vb->localstore){
+ struct alloc_chain *link=_ogg_malloc(sizeof(*link));
+ vb->totaluse+=vb->localtop;
+ link->next=vb->reap;
+ link->ptr=vb->localstore;
+ vb->reap=link;
+ }
+ /* highly conservative */
+ vb->localalloc=bytes;
+ vb->localstore=_ogg_malloc(vb->localalloc);
+ vb->localtop=0;
+ }
+ {
+ void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
+ vb->localtop+=bytes;
+ return ret;
+ }
+}
+
+/* reap the chain, pull the ripcord */
+void _vorbis_block_ripcord(vorbis_block *vb){
+ /* reap the chain */
+ struct alloc_chain *reap=vb->reap;
+ while(reap){
+ struct alloc_chain *next=reap->next;
+ _ogg_free(reap->ptr);
+ memset(reap,0,sizeof(*reap));
+ _ogg_free(reap);
+ reap=next;
+ }
+ /* consolidate storage */
+ if(vb->totaluse){
+ vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
+ vb->localalloc+=vb->totaluse;
+ vb->totaluse=0;
+ }
+
+ /* pull the ripcord */
+ vb->localtop=0;
+ vb->reap=NULL;
+}
+
+int vorbis_block_clear(vorbis_block *vb){
+ int i;
+ vorbis_block_internal *vbi=vb->internal;
+
+ _vorbis_block_ripcord(vb);
+ if(vb->localstore)_ogg_free(vb->localstore);
+
+ if(vbi){
+ for(i=0;i<PACKETBLOBS;i++){
+ oggpack_writeclear(vbi->packetblob[i]);
+ if(i!=PACKETBLOBS/2)_ogg_free(vbi->packetblob[i]);
+ }
+ _ogg_free(vbi);
+ }
+ memset(vb,0,sizeof(*vb));
+ return(0);
+}
+
+/* Analysis side code, but directly related to blocking. Thus it's
+ here and not in analysis.c (which is for analysis transforms only).
+ The init is here because some of it is shared */
+
+static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi,int encp){
+ int i;
+ codec_setup_info *ci=vi->codec_setup;
+ private_state *b=NULL;
+ int hs;
+
+ if(ci==NULL||
+ ci->modes<=0||
+ ci->blocksizes[0]<64||
+ ci->blocksizes[1]<ci->blocksizes[0]){
+ return 1;
+ }
+ hs=ci->halfrate_flag;
+
+ memset(v,0,sizeof(*v));
+ b=v->backend_state=_ogg_calloc(1,sizeof(*b));
+
+ v->vi=vi;
+ b->modebits=ov_ilog(ci->modes-1);
+
+ b->transform[0]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[0]));
+ b->transform[1]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[1]));
+
+ /* MDCT is tranform 0 */
+
+ b->transform[0][0]=_ogg_calloc(1,sizeof(mdct_lookup));
+ b->transform[1][0]=_ogg_calloc(1,sizeof(mdct_lookup));
+ mdct_init(b->transform[0][0],ci->blocksizes[0]>>hs);
+ mdct_init(b->transform[1][0],ci->blocksizes[1]>>hs);
+
+ /* Vorbis I uses only window type 0 */
+ /* note that the correct computation below is technically:
+ b->window[0]=ov_ilog(ci->blocksizes[0]-1)-6;
+ b->window[1]=ov_ilog(ci->blocksizes[1]-1)-6;
+ but since blocksizes are always powers of two,
+ the below is equivalent.
+ */
+ b->window[0]=ov_ilog(ci->blocksizes[0])-7;
+ b->window[1]=ov_ilog(ci->blocksizes[1])-7;
+
+ if(encp){ /* encode/decode differ here */
+
+ /* analysis always needs an fft */
+ drft_init(&b->fft_look[0],ci->blocksizes[0]);
+ drft_init(&b->fft_look[1],ci->blocksizes[1]);
+
+ /* finish the codebooks */
+ if(!ci->fullbooks){
+ ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
+ for(i=0;i<ci->books;i++)
+ vorbis_book_init_encode(ci->fullbooks+i,ci->book_param[i]);
+ }
+
+ b->psy=_ogg_calloc(ci->psys,sizeof(*b->psy));
+ for(i=0;i<ci->psys;i++){
+ _vp_psy_init(b->psy+i,
+ ci->psy_param[i],
+ &ci->psy_g_param,
+ ci->blocksizes[ci->psy_param[i]->blockflag]/2,
+ vi->rate);
+ }
+
+ v->analysisp=1;
+ }else{
+ /* finish the codebooks */
+ if(!ci->fullbooks){
+ ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
+ for(i=0;i<ci->books;i++){
+ if(ci->book_param[i]==NULL)
+ goto abort_books;
+ if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
+ goto abort_books;
+ /* decode codebooks are now standalone after init */
+ vorbis_staticbook_destroy(ci->book_param[i]);
+ ci->book_param[i]=NULL;
+ }
+ }
+ }
+
+ /* initialize the storage vectors. blocksize[1] is small for encode,
+ but the correct size for decode */
+ v->pcm_storage=ci->blocksizes[1];
+ v->pcm=_ogg_malloc(vi->channels*sizeof(*v->pcm));
+ v->pcmret=_ogg_malloc(vi->channels*sizeof(*v->pcmret));
+ {
+ int i;
+ for(i=0;i<vi->channels;i++)
+ v->pcm[i]=_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
+ }
+
+ /* all 1 (large block) or 0 (small block) */
+ /* explicitly set for the sake of clarity */
+ v->lW=0; /* previous window size */
+ v->W=0; /* current window size */
+
+ /* all vector indexes */
+ v->centerW=ci->blocksizes[1]/2;
+
+ v->pcm_current=v->centerW;
+
+ /* initialize all the backend lookups */
+ b->flr=_ogg_calloc(ci->floors,sizeof(*b->flr));
+ b->residue=_ogg_calloc(ci->residues,sizeof(*b->residue));
+
+ for(i=0;i<ci->floors;i++)
+ b->flr[i]=_floor_P[ci->floor_type[i]]->
+ look(v,ci->floor_param[i]);
+
+ for(i=0;i<ci->residues;i++)
+ b->residue[i]=_residue_P[ci->residue_type[i]]->
+ look(v,ci->residue_param[i]);
+
+ return 0;
+ abort_books:
+ for(i=0;i<ci->books;i++){
+ if(ci->book_param[i]!=NULL){
+ vorbis_staticbook_destroy(ci->book_param[i]);
+ ci->book_param[i]=NULL;
+ }
+ }
+ vorbis_dsp_clear(v);
+ return -1;
+}
+
+/* arbitrary settings and spec-mandated numbers get filled in here */
+int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
+ private_state *b=NULL;
+
+ if(_vds_shared_init(v,vi,1))return 1;
+ b=v->backend_state;
+ b->psy_g_look=_vp_global_look(vi);
+
+ /* Initialize the envelope state storage */
+ b->ve=_ogg_calloc(1,sizeof(*b->ve));
+ _ve_envelope_init(b->ve,vi);
+
+ vorbis_bitrate_init(vi,&b->bms);
+
+ /* compressed audio packets start after the headers
+ with sequence number 3 */
+ v->sequence=3;
+
+ return(0);
+}
+
+void vorbis_dsp_clear(vorbis_dsp_state *v){
+ int i;
+ if(v){
+ vorbis_info *vi=v->vi;
+ codec_setup_info *ci=(vi?vi->codec_setup:NULL);
+ private_state *b=v->backend_state;
+
+ if(b){
+
+ if(b->ve){
+ _ve_envelope_clear(b->ve);
+ _ogg_free(b->ve);
+ }
+
+ if(b->transform[0]){
+ mdct_clear(b->transform[0][0]);
+ _ogg_free(b->transform[0][0]);
+ _ogg_free(b->transform[0]);
+ }
+ if(b->transform[1]){
+ mdct_clear(b->transform[1][0]);
+ _ogg_free(b->transform[1][0]);
+ _ogg_free(b->transform[1]);
+ }
+
+ if(b->flr){
+ if(ci)
+ for(i=0;i<ci->floors;i++)
+ _floor_P[ci->floor_type[i]]->
+ free_look(b->flr[i]);
+ _ogg_free(b->flr);
+ }
+ if(b->residue){
+ if(ci)
+ for(i=0;i<ci->residues;i++)
+ _residue_P[ci->residue_type[i]]->
+ free_look(b->residue[i]);
+ _ogg_free(b->residue);
+ }
+ if(b->psy){
+ if(ci)
+ for(i=0;i<ci->psys;i++)
+ _vp_psy_clear(b->psy+i);
+ _ogg_free(b->psy);
+ }
+
+ if(b->psy_g_look)_vp_global_free(b->psy_g_look);
+ vorbis_bitrate_clear(&b->bms);
+
+ drft_clear(&b->fft_look[0]);
+ drft_clear(&b->fft_look[1]);
+
+ }
+
+ if(v->pcm){
+ if(vi)
+ for(i=0;i<vi->channels;i++)
+ if(v->pcm[i])_ogg_free(v->pcm[i]);
+ _ogg_free(v->pcm);
+ if(v->pcmret)_ogg_free(v->pcmret);
+ }
+
+ if(b){
+ /* free header, header1, header2 */
+ if(b->header)_ogg_free(b->header);
+ if(b->header1)_ogg_free(b->header1);
+ if(b->header2)_ogg_free(b->header2);
+ _ogg_free(b);
+ }
+
+ memset(v,0,sizeof(*v));
+ }
+}
+
+float **vorbis_analysis_buffer(vorbis_dsp_state *v, int vals){
+ int i;
+ vorbis_info *vi=v->vi;
+ private_state *b=v->backend_state;
+
+ /* free header, header1, header2 */
+ if(b->header)_ogg_free(b->header);b->header=NULL;
+ if(b->header1)_ogg_free(b->header1);b->header1=NULL;
+ if(b->header2)_ogg_free(b->header2);b->header2=NULL;
+
+ /* Do we have enough storage space for the requested buffer? If not,
+ expand the PCM (and envelope) storage */
+
+ if(v->pcm_current+vals>=v->pcm_storage){
+ v->pcm_storage=v->pcm_current+vals*2;
+
+ for(i=0;i<vi->channels;i++){
+ v->pcm[i]=_ogg_realloc(v->pcm[i],v->pcm_storage*sizeof(*v->pcm[i]));
+ }
+ }
+
+ for(i=0;i<vi->channels;i++)
+ v->pcmret[i]=v->pcm[i]+v->pcm_current;
+
+ return(v->pcmret);
+}
+
+static void _preextrapolate_helper(vorbis_dsp_state *v){
+ int i;
+ int order=16;
+ float *lpc=alloca(order*sizeof(*lpc));
+ float *work=alloca(v->pcm_current*sizeof(*work));
+ long j;
+ v->preextrapolate=1;
+
+ if(v->pcm_current-v->centerW>order*2){ /* safety */
+ for(i=0;i<v->vi->channels;i++){
+ /* need to run the extrapolation in reverse! */
+ for(j=0;j<v->pcm_current;j++)
+ work[j]=v->pcm[i][v->pcm_current-j-1];
+
+ /* prime as above */
+ vorbis_lpc_from_data(work,lpc,v->pcm_current-v->centerW,order);
+
+#if 0
+ if(v->vi->channels==2){
+ if(i==0)
+ _analysis_output("predataL",0,work,v->pcm_current-v->centerW,0,0,0);
+ else
+ _analysis_output("predataR",0,work,v->pcm_current-v->centerW,0,0,0);
+ }else{
+ _analysis_output("predata",0,work,v->pcm_current-v->centerW,0,0,0);
+ }
+#endif
+
+ /* run the predictor filter */
+ vorbis_lpc_predict(lpc,work+v->pcm_current-v->centerW-order,
+ order,
+ work+v->pcm_current-v->centerW,
+ v->centerW);
+
+ for(j=0;j<v->pcm_current;j++)
+ v->pcm[i][v->pcm_current-j-1]=work[j];
+
+ }
+ }
+}
+
+
+/* call with val<=0 to set eof */
+
+int vorbis_analysis_wrote(vorbis_dsp_state *v, int vals){
+ vorbis_info *vi=v->vi;
+ codec_setup_info *ci=vi->codec_setup;
+
+ if(vals<=0){
+ int order=32;
+ int i;
+ float *lpc=alloca(order*sizeof(*lpc));
+
+ /* if it wasn't done earlier (very short sample) */
+ if(!v->preextrapolate)
+ _preextrapolate_helper(v);
+
+ /* We're encoding the end of the stream. Just make sure we have
+ [at least] a few full blocks of zeroes at the end. */
+ /* actually, we don't want zeroes; that could drop a large
+ amplitude off a cliff, creating spread spectrum noise that will
+ suck to encode. Extrapolate for the sake of cleanliness. */
+
+ vorbis_analysis_buffer(v,ci->blocksizes[1]*3);
+ v->eofflag=v->pcm_current;
+ v->pcm_current+=ci->blocksizes[1]*3;
+
+ for(i=0;i<vi->channels;i++){
+ if(v->eofflag>order*2){
+ /* extrapolate with LPC to fill in */
+ long n;
+
+ /* make a predictor filter */
+ n=v->eofflag;
+ if(n>ci->blocksizes[1])n=ci->blocksizes[1];
+ vorbis_lpc_from_data(v->pcm[i]+v->eofflag-n,lpc,n,order);
+
+ /* run the predictor filter */
+ vorbis_lpc_predict(lpc,v->pcm[i]+v->eofflag-order,order,
+ v->pcm[i]+v->eofflag,v->pcm_current-v->eofflag);
+ }else{
+ /* not enough data to extrapolate (unlikely to happen due to
+ guarding the overlap, but bulletproof in case that
+ assumtion goes away). zeroes will do. */
+ memset(v->pcm[i]+v->eofflag,0,
+ (v->pcm_current-v->eofflag)*sizeof(*v->pcm[i]));
+
+ }
+ }
+ }else{
+
+ if(v->pcm_current+vals>v->pcm_storage)
+ return(OV_EINVAL);
+
+ v->pcm_current+=vals;
+
+ /* we may want to reverse extrapolate the beginning of a stream
+ too... in case we're beginning on a cliff! */
+ /* clumsy, but simple. It only runs once, so simple is good. */
+ if(!v->preextrapolate && v->pcm_current-v->centerW>ci->blocksizes[1])
+ _preextrapolate_helper(v);
+
+ }
+ return(0);
+}
+
+/* do the deltas, envelope shaping, pre-echo and determine the size of
+ the next block on which to continue analysis */
+int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
+ int i;
+ vorbis_info *vi=v->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ private_state *b=v->backend_state;
+ vorbis_look_psy_global *g=b->psy_g_look;
+ long beginW=v->centerW-ci->blocksizes[v->W]/2,centerNext;
+ vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal;
+
+ /* check to see if we're started... */
+ if(!v->preextrapolate)return(0);
+
+ /* check to see if we're done... */
+ if(v->eofflag==-1)return(0);
+
+ /* By our invariant, we have lW, W and centerW set. Search for
+ the next boundary so we can determine nW (the next window size)
+ which lets us compute the shape of the current block's window */
+
+ /* we do an envelope search even on a single blocksize; we may still
+ be throwing more bits at impulses, and envelope search handles
+ marking impulses too. */
+ {
+ long bp=_ve_envelope_search(v);
+ if(bp==-1){
+
+ if(v->eofflag==0)return(0); /* not enough data currently to search for a
+ full long block */
+ v->nW=0;
+ }else{
+
+ if(ci->blocksizes[0]==ci->blocksizes[1])
+ v->nW=0;
+ else
+ v->nW=bp;
+ }
+ }
+
+ centerNext=v->centerW+ci->blocksizes[v->W]/4+ci->blocksizes[v->nW]/4;
+
+ {
+ /* center of next block + next block maximum right side. */
+
+ long blockbound=centerNext+ci->blocksizes[v->nW]/2;
+ if(v->pcm_current<blockbound)return(0); /* not enough data yet;
+ although this check is
+ less strict that the
+ _ve_envelope_search,
+ the search is not run
+ if we only use one
+ block size */
+
+
+ }
+
+ /* fill in the block. Note that for a short window, lW and nW are *short*
+ regardless of actual settings in the stream */
+
+ _vorbis_block_ripcord(vb);
+ vb->lW=v->lW;
+ vb->W=v->W;
+ vb->nW=v->nW;
+
+ if(v->W){
+ if(!v->lW || !v->nW){
+ vbi->blocktype=BLOCKTYPE_TRANSITION;
+ /*fprintf(stderr,"-");*/
+ }else{
+ vbi->blocktype=BLOCKTYPE_LONG;
+ /*fprintf(stderr,"_");*/
+ }
+ }else{
+ if(_ve_envelope_mark(v)){
+ vbi->blocktype=BLOCKTYPE_IMPULSE;
+ /*fprintf(stderr,"|");*/
+
+ }else{
+ vbi->blocktype=BLOCKTYPE_PADDING;
+ /*fprintf(stderr,".");*/
+
+ }
+ }
+
+ vb->vd=v;
+ vb->sequence=v->sequence++;
+ vb->granulepos=v->granulepos;
+ vb->pcmend=ci->blocksizes[v->W];
+
+ /* copy the vectors; this uses the local storage in vb */
+
+ /* this tracks 'strongest peak' for later psychoacoustics */
+ /* moved to the global psy state; clean this mess up */
+ if(vbi->ampmax>g->ampmax)g->ampmax=vbi->ampmax;
+ g->ampmax=_vp_ampmax_decay(g->ampmax,v);
+ vbi->ampmax=g->ampmax;
+
+ vb->pcm=_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels);
+ vbi->pcmdelay=_vorbis_block_alloc(vb,sizeof(*vbi->pcmdelay)*vi->channels);
+ for(i=0;i<vi->channels;i++){
+ vbi->pcmdelay[i]=
+ _vorbis_block_alloc(vb,(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i]));
+ memcpy(vbi->pcmdelay[i],v->pcm[i],(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i]));
+ vb->pcm[i]=vbi->pcmdelay[i]+beginW;
+
+ /* before we added the delay
+ vb->pcm[i]=_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i]));
+ memcpy(vb->pcm[i],v->pcm[i]+beginW,ci->blocksizes[v->W]*sizeof(*vb->pcm[i]));
+ */
+
+ }
+
+ /* handle eof detection: eof==0 means that we've not yet received EOF
+ eof>0 marks the last 'real' sample in pcm[]
+ eof<0 'no more to do'; doesn't get here */
+
+ if(v->eofflag){
+ if(v->centerW>=v->eofflag){
+ v->eofflag=-1;
+ vb->eofflag=1;
+ return(1);
+ }
+ }
+
+ /* advance storage vectors and clean up */
+ {
+ int new_centerNext=ci->blocksizes[1]/2;
+ int movementW=centerNext-new_centerNext;
+
+ if(movementW>0){
+
+ _ve_envelope_shift(b->ve,movementW);
+ v->pcm_current-=movementW;
+
+ for(i=0;i<vi->channels;i++)
+ memmove(v->pcm[i],v->pcm[i]+movementW,
+ v->pcm_current*sizeof(*v->pcm[i]));
+
+
+ v->lW=v->W;
+ v->W=v->nW;
+ v->centerW=new_centerNext;
+
+ if(v->eofflag){
+ v->eofflag-=movementW;
+ if(v->eofflag<=0)v->eofflag=-1;
+ /* do not add padding to end of stream! */
+ if(v->centerW>=v->eofflag){
+ v->granulepos+=movementW-(v->centerW-v->eofflag);
+ }else{
+ v->granulepos+=movementW;
+ }
+ }else{
+ v->granulepos+=movementW;
+ }
+ }
+ }
+
+ /* done */
+ return(1);
+}
+
+int vorbis_synthesis_restart(vorbis_dsp_state *v){
+ vorbis_info *vi=v->vi;
+ codec_setup_info *ci;
+ int hs;
+
+ if(!v->backend_state)return -1;
+ if(!vi)return -1;
+ ci=vi->codec_setup;
+ if(!ci)return -1;
+ hs=ci->halfrate_flag;
+
+ v->centerW=ci->blocksizes[1]>>(hs+1);
+ v->pcm_current=v->centerW>>hs;
+
+ v->pcm_returned=-1;
+ v->granulepos=-1;
+ v->sequence=-1;
+ v->eofflag=0;
+ ((private_state *)(v->backend_state))->sample_count=-1;
+
+ return(0);
+}
+
+int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
+ if(_vds_shared_init(v,vi,0)){
+ vorbis_dsp_clear(v);
+ return 1;
+ }
+ vorbis_synthesis_restart(v);
+ return 0;
+}
+
+/* Unlike in analysis, the window is only partially applied for each
+ block. The time domain envelope is not yet handled at the point of
+ calling (as it relies on the previous block). */
+
+int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
+ vorbis_info *vi=v->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ private_state *b=v->backend_state;
+ int hs=ci->halfrate_flag;
+ int i,j;
+
+ if(!vb)return(OV_EINVAL);
+ if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
+
+ v->lW=v->W;
+ v->W=vb->W;
+ v->nW=-1;
+
+ if((v->sequence==-1)||
+ (v->sequence+1 != vb->sequence)){
+ v->granulepos=-1; /* out of sequence; lose count */
+ b->sample_count=-1;
+ }
+
+ v->sequence=vb->sequence;
+
+ if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly
+ was called on block */
+ int n=ci->blocksizes[v->W]>>(hs+1);
+ int n0=ci->blocksizes[0]>>(hs+1);
+ int n1=ci->blocksizes[1]>>(hs+1);
+
+ int thisCenter;
+ int prevCenter;
+
+ v->glue_bits+=vb->glue_bits;
+ v->time_bits+=vb->time_bits;
+ v->floor_bits+=vb->floor_bits;
+ v->res_bits+=vb->res_bits;
+
+ if(v->centerW){
+ thisCenter=n1;
+ prevCenter=0;
+ }else{
+ thisCenter=0;
+ prevCenter=n1;
+ }
+
+ /* v->pcm is now used like a two-stage double buffer. We don't want
+ to have to constantly shift *or* adjust memory usage. Don't
+ accept a new block until the old is shifted out */
+
+ for(j=0;j<vi->channels;j++){
+ /* the overlap/add section */
+ if(v->lW){
+ if(v->W){
+ /* large/large */
+ const float *w=_vorbis_window_get(b->window[1]-hs);
+ float *pcm=v->pcm[j]+prevCenter;
+ float *p=vb->pcm[j];
+ for(i=0;i<n1;i++)
+ pcm[i]=pcm[i]*w[n1-i-1] + p[i]*w[i];
+ }else{
+ /* large/small */
+ const float *w=_vorbis_window_get(b->window[0]-hs);
+ float *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
+ float *p=vb->pcm[j];
+ for(i=0;i<n0;i++)
+ pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
+ }
+ }else{
+ if(v->W){
+ /* small/large */
+ const float *w=_vorbis_window_get(b->window[0]-hs);
+ float *pcm=v->pcm[j]+prevCenter;
+ float *p=vb->pcm[j]+n1/2-n0/2;
+ for(i=0;i<n0;i++)
+ pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
+ for(;i<n1/2+n0/2;i++)
+ pcm[i]=p[i];
+ }else{
+ /* small/small */
+ const float *w=_vorbis_window_get(b->window[0]-hs);
+ float *pcm=v->pcm[j]+prevCenter;
+ float *p=vb->pcm[j];
+ for(i=0;i<n0;i++)
+ pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
+ }
+ }
+
+ /* the copy section */
+ {
+ float *pcm=v->pcm[j]+thisCenter;
+ float *p=vb->pcm[j]+n;
+ for(i=0;i<n;i++)
+ pcm[i]=p[i];
+ }
+ }
+
+ if(v->centerW)
+ v->centerW=0;
+ else
+ v->centerW=n1;
+
+ /* deal with initial packet state; we do this using the explicit
+ pcm_returned==-1 flag otherwise we're sensitive to first block
+ being short or long */
+
+ if(v->pcm_returned==-1){
+ v->pcm_returned=thisCenter;
+ v->pcm_current=thisCenter;
+ }else{
+ v->pcm_returned=prevCenter;
+ v->pcm_current=prevCenter+
+ ((ci->blocksizes[v->lW]/4+
+ ci->blocksizes[v->W]/4)>>hs);
+ }
+
+ }
+
+ /* track the frame number... This is for convenience, but also
+ making sure our last packet doesn't end with added padding. If
+ the last packet is partial, the number of samples we'll have to
+ return will be past the vb->granulepos.
+
+ This is not foolproof! It will be confused if we begin
+ decoding at the last page after a seek or hole. In that case,
+ we don't have a starting point to judge where the last frame
+ is. For this reason, vorbisfile will always try to make sure
+ it reads the last two marked pages in proper sequence */
+
+ if(b->sample_count==-1){
+ b->sample_count=0;
+ }else{
+ b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
+ }
+
+ if(v->granulepos==-1){
+ if(vb->granulepos!=-1){ /* only set if we have a position to set to */
+
+ v->granulepos=vb->granulepos;
+
+ /* is this a short page? */
+ if(b->sample_count>v->granulepos){
+ /* corner case; if this is both the first and last audio page,
+ then spec says the end is cut, not beginning */
+ long extra=b->sample_count-vb->granulepos;
+
+ /* we use ogg_int64_t for granule positions because a
+ uint64 isn't universally available. Unfortunately,
+ that means granposes can be 'negative' and result in
+ extra being negative */
+ if(extra<0)
+ extra=0;
+
+ if(vb->eofflag){
+ /* trim the end */
+ /* no preceding granulepos; assume we started at zero (we'd
+ have to in a short single-page stream) */
+ /* granulepos could be -1 due to a seek, but that would result
+ in a long count, not short count */
+
+ /* Guard against corrupt/malicious frames that set EOP and
+ a backdated granpos; don't rewind more samples than we
+ actually have */
+ if(extra > (v->pcm_current - v->pcm_returned)<<hs)
+ extra = (v->pcm_current - v->pcm_returned)<<hs;
+
+ v->pcm_current-=extra>>hs;
+ }else{
+ /* trim the beginning */
+ v->pcm_returned+=extra>>hs;
+ if(v->pcm_returned>v->pcm_current)
+ v->pcm_returned=v->pcm_current;
+ }
+
+ }
+
+ }
+ }else{
+ v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
+ if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
+
+ if(v->granulepos>vb->granulepos){
+ long extra=v->granulepos-vb->granulepos;
+
+ if(extra)
+ if(vb->eofflag){
+ /* partial last frame. Strip the extra samples off */
+
+ /* Guard against corrupt/malicious frames that set EOP and
+ a backdated granpos; don't rewind more samples than we
+ actually have */
+ if(extra > (v->pcm_current - v->pcm_returned)<<hs)
+ extra = (v->pcm_current - v->pcm_returned)<<hs;
+
+ /* we use ogg_int64_t for granule positions because a
+ uint64 isn't universally available. Unfortunately,
+ that means granposes can be 'negative' and result in
+ extra being negative */
+ if(extra<0)
+ extra=0;
+
+ v->pcm_current-=extra>>hs;
+ } /* else {Shouldn't happen *unless* the bitstream is out of
+ spec. Either way, believe the bitstream } */
+ } /* else {Shouldn't happen *unless* the bitstream is out of
+ spec. Either way, believe the bitstream } */
+ v->granulepos=vb->granulepos;
+ }
+ }
+
+ /* Update, cleanup */
+
+ if(vb->eofflag)v->eofflag=1;
+ return(0);
+
+}
+
+/* pcm==NULL indicates we just want the pending samples, no more */
+int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm){
+ vorbis_info *vi=v->vi;
+
+ if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
+ if(pcm){
+ int i;
+ for(i=0;i<vi->channels;i++)
+ v->pcmret[i]=v->pcm[i]+v->pcm_returned;
+ *pcm=v->pcmret;
+ }
+ return(v->pcm_current-v->pcm_returned);
+ }
+ return(0);
+}
+
+int vorbis_synthesis_read(vorbis_dsp_state *v,int n){
+ if(n && v->pcm_returned+n>v->pcm_current)return(OV_EINVAL);
+ v->pcm_returned+=n;
+ return(0);
+}
+
+/* intended for use with a specific vorbisfile feature; we want access
+ to the [usually synthetic/postextrapolated] buffer and lapping at
+ the end of a decode cycle, specifically, a half-short-block worth.
+ This funtion works like pcmout above, except it will also expose
+ this implicit buffer data not normally decoded. */
+int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm){
+ vorbis_info *vi=v->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ int hs=ci->halfrate_flag;
+
+ int n=ci->blocksizes[v->W]>>(hs+1);
+ int n0=ci->blocksizes[0]>>(hs+1);
+ int n1=ci->blocksizes[1]>>(hs+1);
+ int i,j;
+
+ if(v->pcm_returned<0)return 0;
+
+ /* our returned data ends at pcm_returned; because the synthesis pcm
+ buffer is a two-fragment ring, that means our data block may be
+ fragmented by buffering, wrapping or a short block not filling
+ out a buffer. To simplify things, we unfragment if it's at all
+ possibly needed. Otherwise, we'd need to call lapout more than
+ once as well as hold additional dsp state. Opt for
+ simplicity. */
+
+ /* centerW was advanced by blockin; it would be the center of the
+ *next* block */
+ if(v->centerW==n1){
+ /* the data buffer wraps; swap the halves */
+ /* slow, sure, small */
+ for(j=0;j<vi->channels;j++){
+ float *p=v->pcm[j];
+ for(i=0;i<n1;i++){
+ float temp=p[i];
+ p[i]=p[i+n1];
+ p[i+n1]=temp;
+ }
+ }
+
+ v->pcm_current-=n1;
+ v->pcm_returned-=n1;
+ v->centerW=0;
+ }
+
+ /* solidify buffer into contiguous space */
+ if((v->lW^v->W)==1){
+ /* long/short or short/long */
+ for(j=0;j<vi->channels;j++){
+ float *s=v->pcm[j];
+ float *d=v->pcm[j]+(n1-n0)/2;
+ for(i=(n1+n0)/2-1;i>=0;--i)
+ d[i]=s[i];
+ }
+ v->pcm_returned+=(n1-n0)/2;
+ v->pcm_current+=(n1-n0)/2;
+ }else{
+ if(v->lW==0){
+ /* short/short */
+ for(j=0;j<vi->channels;j++){
+ float *s=v->pcm[j];
+ float *d=v->pcm[j]+n1-n0;
+ for(i=n0-1;i>=0;--i)
+ d[i]=s[i];
+ }
+ v->pcm_returned+=n1-n0;
+ v->pcm_current+=n1-n0;
+ }
+ }
+
+ if(pcm){
+ int i;
+ for(i=0;i<vi->channels;i++)
+ v->pcmret[i]=v->pcm[i]+v->pcm_returned;
+ *pcm=v->pcmret;
+ }
+
+ return(n1+n-v->pcm_returned);
+
+}
+
+const float *vorbis_window(vorbis_dsp_state *v,int W){
+ vorbis_info *vi=v->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ int hs=ci->halfrate_flag;
+ private_state *b=v->backend_state;
+
+ if(b->window[W]-1<0)return NULL;
+ return _vorbis_window_get(b->window[W]-hs);
+}
diff --git a/external/libvorbis-1.3.5/lib/books/coupled/res_books_51.h b/external/libvorbis-1.3.5/lib/books/coupled/res_books_51.h
new file mode 100644
index 0000000..93910ff
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/books/coupled/res_books_51.h
@@ -0,0 +1,12274 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+ *
+ * function: static codebooks for 5.1 surround
+ * last modified: $Id: res_books_51.h 19057 2014-01-22 12:32:31Z xiphmont $
+ *
+ ********************************************************************/
+
+static const long _vq_quantlist__44p0_l0_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44p0_l0_0[] = {
+ 1, 3, 4, 7, 7, 8, 8, 9, 9, 9,10,10,10, 5, 6, 5,
+ 8, 7, 9, 8, 9, 9,10, 9,11,10, 5, 5, 7, 7, 8, 8,
+ 9, 9, 9, 9,10,10,11, 8, 9, 8,10, 9,10, 9,10, 9,
+ 11,10,11,10, 8, 8, 9, 9,10, 9,10, 9,11,10,11,10,
+ 11,10,11,11,11,11,11,11,11,11,11,11,11,11,10,11,
+ 11,11,12,11,11,11,11,11,11,10,12,12,12,12,12,12,
+ 12,11,12,12,12,11,11,11,12,12,12,12,12,12,12,11,
+ 12,11,12,11,11,13,12,12,12,13,12,12,12,12,11,12,
+ 11,11,13,13,13,12,12,12,12,12,12,11,11,11,10,13,
+ 13,13,12,13,12,13,11,13,10,12,11,11,13,13,12,13,
+ 12,12,12,12,11,12,11,11,11,
+};
+
+static const static_codebook _44p0_l0_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44p0_l0_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44p0_l0_0,
+ 0
+};
+
+static const long _vq_quantlist__44p0_l0_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p0_l0_1[] = {
+ 1, 4, 4, 6, 6, 5, 5, 5, 7, 5, 5, 5, 5, 6, 7, 7,
+ 6, 7, 7, 7, 6, 7, 7, 7, 7,
+};
+
+static const static_codebook _44p0_l0_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p0_l0_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p0_l0_1,
+ 0
+};
+
+static const long _vq_quantlist__44p0_l1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p0_l1_0[] = {
+ 1, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+
+static const static_codebook _44p0_l1_0 = {
+ 2, 9,
+ (char *)_vq_lengthlist__44p0_l1_0,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p0_l1_0,
+ 0
+};
+
+static const char _huff_lengthlist__44p0_lfe[] = {
+ 1, 3, 2, 3,
+};
+
+static const static_codebook _huff_book__44p0_lfe = {
+ 2, 4,
+ (char *)_huff_lengthlist__44p0_lfe,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44p0_long[] = {
+ 2, 3, 6, 7,10,14,16, 3, 2, 5, 7,11,14,17, 6, 5,
+ 5, 7,10,12,14, 7, 7, 6, 6, 7, 9,13,10,11, 9, 6,
+ 6, 9,11,15,15,13,10, 9,10,12,18,18,16,14,12,13,
+ 16,
+};
+
+static const static_codebook _huff_book__44p0_long = {
+ 2, 49,
+ (char *)_huff_lengthlist__44p0_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p0_p1_0[] = {
+ 1, 2, 2, 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, 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,
+};
+
+static const static_codebook _44p0_p1_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p0_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p0_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p0_p2_0[] = {
+ 1, 5, 5, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0,12,12, 0,
+ 8, 8, 0, 9, 9, 0,12,12, 0, 8, 8, 0, 6, 6, 0,11,
+ 11, 0,12,12, 0,12,12, 0,15,15, 0,11,11, 0,12,12,
+ 0,15,15, 0,12,12, 0, 5, 5, 0, 5, 5, 0, 6, 6, 0,
+ 7, 7, 0,11,11, 0, 6, 6, 0, 7, 7, 0,10,11, 0, 6,
+ 6, 0, 7, 7, 0,11,11, 0,12,12, 0,11,11, 0,15,15,
+ 0,10,10, 0,12,12, 0,15,15, 0,12,12, 0, 6, 6, 0,
+ 12,12, 0,12,12, 0,12,12, 0,15,15, 0,11,11, 0,12,
+ 12, 0,15,15, 0,12,12, 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, 8, 8, 0,12,12, 0,12,12, 0,12,12, 0,15,
+ 15, 0,12,12, 0,11,12, 0,15,16, 0,11,11, 0, 6, 6,
+ 0,11,12, 0,12,12, 0,12,12, 0,16,15, 0,12,12, 0,
+ 13,12, 0,15,14, 0,12,12, 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,
+};
+
+static const static_codebook _44p0_p2_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p0_p2_0,
+ 1, -533200896, 1614282752, 2, 0,
+ (long *)_vq_quantlist__44p0_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p2_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p0_p2_1[] = {
+ 1, 3, 3, 0, 9, 9, 0, 9, 9, 0,10,10, 0, 9, 9, 0,
+ 10,10, 0,10,10, 0, 9, 9, 0,10,10, 0, 7, 7, 0, 7,
+ 7, 0, 6, 6, 0, 8, 8, 0, 7, 7, 0, 8, 8, 0, 8, 9,
+ 0, 8, 8, 0, 8, 8, 0, 7, 7, 0, 9, 9, 0, 8, 8, 0,
+ 10,10, 0, 9, 9, 0,10,10, 0,10,10, 0, 9, 9, 0,10,
+ 10, 0, 9, 9, 0,11,11, 0,11,11, 0,12,12, 0,11,11,
+ 0,12,12, 0,13,13, 0,12,12, 0,13,12, 0, 8, 8, 0,
+ 12,12, 0,12,12, 0,13,13, 0,12,12, 0,13,13, 0,13,
+ 13, 0,13,13, 0,13,13, 0, 7, 7, 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, 9, 9, 0,11,11, 0,12,12, 0,13,13, 0,12,
+ 12, 0,13,13, 0,13,13, 0,12,12, 0,12,12, 0, 8, 8,
+ 0,12,12, 0,12,12, 0,13,13, 0,13,13, 0,13,14, 0,
+ 14,13, 0,13,13, 0,13,13, 0, 7, 7, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,
+};
+
+static const static_codebook _44p0_p2_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p0_p2_1,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p0_p2_1,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p3_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p0_p3_0[] = {
+ 1, 6, 6, 7, 8, 8, 7, 8, 8, 7, 9, 9,10,12,11, 9,
+ 8, 8, 7, 9, 9,11,12,12, 9, 9, 9, 6, 7, 7,10,11,
+ 11,10,11,11,10,11,11,13,13,14,12,12,12,11,11,11,
+ 14,14,14,12,12,12, 6, 5, 5, 9, 6, 5, 9, 6, 6, 9,
+ 7, 7,12,10,10,11, 6, 6,10, 7, 7,13,10,10,12, 7,
+ 7, 7, 8, 8,12,10,10,12,10,10,11,10,10,15,13,13,
+ 13, 9, 9,12,11,11,16,13,13,15,11,11, 8, 7, 7,12,
+ 12,12,12,11,11,12,11,11,14,14,14,14,12,12,12,12,
+ 12,16,15,15,14,12,12, 0,10,10, 0,12,12, 0,12,12,
+ 0,11,11, 0,14,14, 0,11,11, 0,12,12, 0,15,15, 0,
+ 11,11, 8, 8, 8,13,11,11,13,10,10,13,11,11,15,13,
+ 13,14,11,11,12,10,10,16,14,14,14,10,10, 9, 7, 7,
+ 13,11,11,13,11,11,12,11,11,16,14,14,14,12,12,13,
+ 12,12,15,14,14,15,13,12, 0,11,11, 0,12,12, 0,12,
+ 12, 0,12,12, 0,15,15, 0,12,12, 0,13,12, 0,14,15,
+ 0,12,12,
+};
+
+static const static_codebook _44p0_p3_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p0_p3_0,
+ 1, -531365888, 1616117760, 2, 0,
+ (long *)_vq_quantlist__44p0_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p3_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p0_p3_1[] = {
+ 2, 4, 4, 8, 8,10,12,12,11,11, 9,11,11,12,13,11,
+ 12,12,11,11,11,12,12,12,12,10,13,12,13,13,11,12,
+ 12,13,13,11,12,12,13,13,11,12,13,13,13,11,13,13,
+ 13,13,10,13,13,12,13,11,12,12,14,14,11,13,12,12,
+ 12,11,12,12,13,13,11,13,13,12,12,11,13,13,13,13,
+ 11,12,12,13,13,11,13,13,12,12,11,12,12,13,13,11,
+ 13,13,12,12,11,13,13,13,13,11,12,12,14,14,11,13,
+ 13,12,12,11,12,12,13,13,11,13,13,12,12,11,10,10,
+ 10,10,12,10,10,11,11,11, 8, 8,11,11,13,10,10,10,
+ 10,12,10,10,10,10,13,11,11,11,11,13,10,10,11,11,
+ 13,11,11,12,12,13,11,11,11,11,13,11,11,12,12,13,
+ 11,11,12,12,13,10,10,11,11,13,11,11,11,11,13,11,
+ 10,11,11,13,11,11,11,11,13,11,11,11,11,13,10,10,
+ 11,11,13,11,11,11,11,12,10,11,11,11,13,11,11,11,
+ 11,13,11,11,11,11,13,10,10,11,11,13,11,11,11,11,
+ 13,11,11,11,11,13,11,11,11,11,11,10,10,10,10,12,
+ 10,10, 9, 9,12,12,12,11,11,13,12,12, 9, 9,13,12,
+ 12,10,10,12,12,12,12,12,13,13,13,14,14,13,12,12,
+ 11,11,13,13,13,12,12,13,12,12,11,11,13,12,13,11,
+ 11,13,13,13,14,14,13,12,12,10,10,13,13,13,11,11,
+ 13,12,12,10,10,13,13,13,11,11,13,13,13,14,14,13,
+ 12,12,10,10,13,13,13,11,11,13,12,13,10,10,13,13,
+ 13,11,11,13,13,13,14,14,13,12,12,10,10,13,13,13,
+ 11,11,13,13,12,10,10,14,12,12, 8, 8,14,12,12, 9,
+ 9,14,11,11, 9, 9,14,12,12, 8, 8,14,11,11, 7, 7,
+ 14,13,13,10,10,15,12,12,10,10,15,13,13,10,10,15,
+ 12,12, 9, 9,15,13,13,10,10,15,13,13,10,10,15,12,
+ 12,10,10,15,13,13,10,10,14,12,12, 9, 9,14,13,13,
+ 9, 9,14,13,13, 9, 9,15,12,12, 9, 9,15,13,13, 9,
+ 9,14,12,12, 9, 9,14,13,13, 9, 9,14,13,13, 9, 9,
+ 15,12,12, 9, 9,14,13,13, 9, 9,14,12,12, 9, 9,14,
+ 13,13, 9, 9,13,12,12, 8, 8,13,13,13, 8, 8,14,13,
+ 13, 9, 9,13,13,13, 7, 7,14,13,13, 8, 8,14,14,14,
+ 10,10,14,14,14,11,11,14,14,14, 9, 9,14,14,14,10,
+ 10,14,14,14, 9, 9,14,14,14,10, 9,15,14,14,11,11,
+ 14,14,14, 9, 9,14,14,14,10,10,14,14,14, 9, 9,14,
+ 14,14, 9, 9,15,14,14,11,11,14,14,14, 8, 8,14,14,
+ 14, 9, 9,14,14,14, 8, 8,14,14,14, 9, 9,15,14,14,
+ 11,11,14,14,14, 8, 8,14,14,14, 9, 9,14,14,14, 8,
+ 8,12,12,12,13,13,16,15,15,11,11,16,15,16,12,12,
+ 17,16,16,11,11,17,15,15,12,11,16,16,16,12,13,16,
+ 15,15,13,13,16,16,16,12,12,16,16,15,13,13,16,16,
+ 16,12,12,16,16,16,13,13,17,16,16,14,14,17,17,16,
+ 12,12,17,16,16,13,13,17,17,16,12,13,16,16,17,13,
+ 12,17,16,16,14,13,17,16,16,12,12,17,16,16,12,12,
+ 17,16,17,12,12,17,17,17,13,13,16,16,16,13,14,17,
+ 17,16,12,12,16,16,16,13,13,17,17,17,12,12,13,14,
+ 14,10,10,16,14,14,12,12,16,15,15,14,14,16,14,14,
+ 12,12,15,14,14,13,13,17,15,15,14,13,16,16,15,15,
+ 15,16,15,15,14,14,16,15,15,14,14,17,15,15,14,14,
+ 16,15,15,14,14,16,16,15,15,15,17,15,15,13,13,16,
+ 15,15,14,14,17,15,15,13,13,17,15,15,14,14,16,15,
+ 15,15,15,16,14,14,13,13,16,15,15,14,14,16,14,14,
+ 13,13,17,15,15,14,14,16,16,15,15,15,17,14,14,13,
+ 13,16,15,15,14,14,17,14,14,13,13,13,11,11,10,10,
+ 16,14,14,13,13,15,14,14,13,13,16,14,14,12,12,16,
+ 14,14,12,12,15,15,15,14,14,16,14,14,14,14,16,15,
+ 14,14,14,16,14,14,14,14,16,15,15,14,13,16,15,15,
+ 14,14,16,14,14,14,14,17,15,15,14,14,16,14,14,14,
+ 14,16,15,15,13,14,16,15,15,14,14,16,14,14,14,14,
+ 16,15,15,13,13,16,14,14,13,13,16,15,15,13,13,16,
+ 15,15,14,14,16,14,14,14,14,17,15,15,13,13,16,15,
+ 14,13,13,17,15,15,13,13,14,14,14, 9, 9,14,14,14,
+ 17,17,14,15,15,18,18,14,14,14,18,19,14,14,14,18,
+ 18,15,15,15,19,18,15,16,15,18,20,15,15,15,18,19,
+ 15,15,15,19,19,15,15,15,18,20,15,15,15,18,19,15,
+ 15,16,20,18,15,15,15,18,18,15,15,15,19,19,15,15,
+ 15,18,19,15,15,15,18,19,15,15,15,19,19,14,15,14,
+ 19,19,15,15,15,20,19,15,14,14,19,18,14,15,15,18,
+ 19,15,15,16,20,20,14,14,14,18,19,15,15,15,19,18,
+ 14,14,14,18,18,14,12,12, 9, 9,13,14,14,18,18,14,
+ 13,13,18,19,14,14,14,18,18,14,14,14,18,18,15,15,
+ 15,19,19,15,14,14,19,18,14,15,15,19,18,15,14,14,
+ 18,18,15,15,15,19,18,14,15,15,19,19,15,14,14,19,
+ 18,14,15,15,19,18,15,14,14,19,18,14,15,15,19,18,
+ 15,15,15,21,18,15,14,14,19,18,14,15,15,18,19,14,
+ 15,14,20,19,14,15,15,18,19,14,15,15,19,19,15,14,
+ 14,19,20,14,15,15,18,18,14,14,14,19,19,14,15,15,
+ 19,18,12,12,12,13,13,16,15,15,11,11,16,15,15,12,
+ 12,16,16,16,11,11,16,15,15,11,11,16,16,16,13,13,
+ 17,16,16,13,13,17,17,17,12,12,16,16,16,13,13,17,
+ 16,17,13,12,15,16,16,12,12,16,15,15,13,13,17,16,
+ 16,12,12,16,16,15,12,12,16,16,16,12,12,17,17,16,
+ 13,12,16,16,16,13,13,17,16,16,12,12,17,16,16,12,
+ 12,17,17,16,12,12,16,17,16,12,12,17,15,15,13,13,
+ 17,16,16,12,12,16,16,16,12,12,16,16,16,12,12,13,
+ 13,13, 9, 9,15,14,14,13,13,16,15,14,14,14,16,14,
+ 14,13,13,15,14,14,13,13,17,15,15,14,14,16,15,15,
+ 15,15,16,15,15,14,14,16,15,15,15,15,17,15,15,14,
+ 14,16,15,15,14,14,16,15,15,15,15,17,14,15,14,14,
+ 16,15,15,14,14,17,15,15,13,14,17,15,15,14,14,16,
+ 15,15,15,15,17,14,14,13,13,16,15,15,14,14,17,14,
+ 14,13,13,17,15,15,14,14,16,15,16,15,15,17,14,14,
+ 13,13,16,15,15,14,14,18,14,14,13,13,13,11,11,11,
+ 11,15,14,14,12,12,15,14,14,13,13,16,14,14,12,12,
+ 16,13,14,12,12,16,15,15,13,13,16,14,14,14,14,16,
+ 15,15,13,13,16,14,14,13,13,16,14,15,13,13,15,15,
+ 15,13,13,16,14,14,14,13,16,14,14,13,13,16,14,14,
+ 13,13,16,15,15,13,13,16,15,15,13,13,16,14,14,14,
+ 14,16,15,15,12,12,16,14,14,13,13,16,15,15,12,12,
+ 16,15,15,13,13,16,14,14,14,14,17,15,14,12,12,16,
+ 14,14,13,13,16,15,15,12,12,14,14,14, 8, 8,14,14,
+ 14,17,18,14,15,15,17,18,14,14,14,17,18,14,14,14,
+ 18,18,14,15,15,18,18,14,16,15,19,19,15,15,15,18,
+ 19,15,16,15,20,19,15,15,15,18,18,14,15,15,18,19,
+ 15,16,16,20,19,15,15,15,19,17,14,15,15,20,18,14,
+ 15,15,18,18,14,15,15,18,19,14,15,15,19,20,14,14,
+ 14,18,18,14,15,15,18,19,14,14,14,18,19,14,15,15,
+ 19,18,15,16,16,20,21,14,14,15,19,19,14,15,15,19,
+ 19,14,14,14,19,18,13,12,12, 9, 9,13,14,14,18,19,
+ 14,14,14,18,19,14,14,14,18,18,14,14,14,18,18,14,
+ 15,15,19,19,15,14,14,19,18,15,15,15,19,19,15,14,
+ 14,19,20,14,15,15,18,19,14,15,15,20,18,15,14,14,
+ 18,18,14,15,15,18,18,14,14,14,19,19,14,15,15,18,
+ 18,14,15,15,19,18,15,14,14,19,19,14,15,15,19,18,
+ 15,14,14,19,18,14,14,15,18,19,14,15,15,19,18,15,
+ 14,14,18,19,14,15,14,19,20,14,14,14,19,19,14,15,
+ 15,19,19,12,12,12,13,13,16,16,16,11,11,16,16,16,
+ 12,12,17,16,16,11,11,17,15,15,11,11,16,16,16,13,
+ 13,17,15,16,13,13,16,16,16,12,12,17,16,16,13,13,
+ 17,17,16,12,12,17,17,16,13,13,17,16,16,13,13,17,
+ 17,17,12,12,17,16,16,13,13,17,17,17,12,12,16,16,
+ 16,12,12,17,15,15,13,13,17,16,16,11,11,17,16,16,
+ 12,12,16,16,16,11,11,16,17,16,12,12,17,16,16,13,
+ 13,17,17,16,12,12,17,17,16,12,12,17,16,16,11,11,
+ 13,14,14, 9, 9,16,14,14,13,13,16,14,15,14,14,16,
+ 14,14,12,12,16,14,14,13,13,17,15,15,14,14,16,15,
+ 15,15,15,17,15,15,14,14,16,15,15,14,14,17,15,15,
+ 14,14,16,15,15,14,14,16,15,15,15,16,17,14,15,14,
+ 14,16,15,15,14,14,17,15,15,14,14,16,15,15,14,14,
+ 16,15,15,15,15,17,14,14,13,13,16,15,15,14,14,16,
+ 14,14,13,13,17,15,15,14,14,16,16,15,15,15,17,14,
+ 14,13,13,16,15,15,14,14,17,14,14,13,13,13,11,11,
+ 10,10,16,14,14,12,12,15,13,13,13,12,16,14,14,11,
+ 11,16,14,14,11,11,16,14,15,13,14,16,14,14,13,13,
+ 16,15,15,13,13,16,14,14,13,13,16,15,15,13,13,16,
+ 15,15,13,13,17,14,14,14,14,17,15,15,13,13,16,14,
+ 15,13,13,16,15,15,13,13,16,15,15,13,13,16,14,14,
+ 13,13,17,15,15,12,12,16,14,14,12,12,16,15,15,12,
+ 12,16,15,15,13,13,16,14,14,13,13,17,15,15,12,12,
+ 17,14,14,12,12,16,15,15,12,12,13,14,14, 8, 8,13,
+ 14,14,18,18,13,15,15,17,18,14,14,14,18,19,14,14,
+ 14,19,18,14,15,15,19,18,15,15,16,21,18,15,15,15,
+ 19,19,14,16,16,19,19,14,15,15,18,19,14,15,15,19,
+ 20,14,16,16,19,18,15,15,15,18,19,14,15,15,19,18,
+ 15,15,15,18,18,15,15,15,20,18,15,16,16,20,19,14,
+ 15,14,18,19,14,15,16,19,20,14,15,15,19,18,15,15,
+ 15,19,18,15,16,16,20,19,15,14,14,18,18,14,15,15,
+ 19,19,14,15,15,18,18,13,12,12, 8, 8,13,14,14,19,
+ 18,14,13,13,20,18,14,14,14,19,18,14,13,13,18,19,
+ 14,15,15,20,19,15,14,14,19,19,14,15,15,19,18,15,
+ 14,14,20,20,15,15,15,19,18,14,15,15,19,18,15,14,
+ 14,19,18,14,15,15,20,19,14,14,14,20,19,14,15,15,
+ 19,18,15,15,15,18,18,15,14,14,18,18,14,15,15,19,
+ 19,14,14,14,19,19,14,15,15,19,19,15,15,15,19,18,
+ 15,14,14,20,19,15,15,15,19,19,14,14,14,20,19,14,
+ 15,15,20,20,12,12,12,13,13,17,16,16,11,11,16,16,
+ 15,12,12,17,16,16,11,11,17,15,15,11,11,17,17,17,
+ 13,13,17,16,16,13,13,17,17,17,12,12,17,16,16,13,
+ 13,17,17,16,12,13,16,17,16,13,13,17,16,15,13,13,
+ 17,16,16,12,12,17,16,16,12,13,17,16,17,12,12,17,
+ 17,17,12,12,17,16,15,13,13,17,16,16,12,12,17,16,
+ 16,12,12,17,16,16,11,11,16,16,16,12,12,17,15,15,
+ 13,13,17,16,15,11,11,16,16,16,12,12,17,16,16,11,
+ 11,13,14,14, 9, 9,16,14,14,13,13,16,14,15,14,14,
+ 16,14,14,12,12,16,14,14,13,13,17,15,15,14,15,16,
+ 15,15,15,15,17,15,15,14,14,16,15,15,15,14,16,15,
+ 15,14,14,16,15,15,14,14,16,15,16,15,15,17,15,14,
+ 14,14,16,15,15,14,14,17,15,15,13,13,16,15,15,14,
+ 14,16,16,16,15,15,17,14,14,13,13,16,15,15,14,14,
+ 18,14,15,13,13,16,15,15,14,14,16,16,15,15,15,16,
+ 14,14,13,13,16,15,15,14,14,17,14,15,13,13,13,11,
+ 11,10,10,15,14,14,12,12,15,14,14,13,13,16,14,14,
+ 12,12,16,13,14,12,12,16,14,15,14,13,16,14,14,14,
+ 14,16,15,15,13,13,16,14,14,13,13,16,15,15,13,13,
+ 15,15,15,13,13,16,14,14,14,14,17,15,15,13,13,16,
+ 14,14,13,13,16,15,15,13,13,16,15,15,13,13,16,14,
+ 14,13,13,17,15,15,12,12,16,14,14,12,12,16,14,15,
+ 12,12,16,15,15,13,13,16,14,14,13,13,17,15,15,12,
+ 12,16,14,14,12,12,16,15,15,12,12,14,14,14, 8, 8,
+ 14,14,14,17,17,14,15,15,18,18,14,14,14,18,17,14,
+ 14,14,18,18,14,15,15,18,20,15,16,15,19,18,15,15,
+ 15,19,18,15,15,16,19,18,15,15,15,18,18,14,15,15,
+ 18,18,15,16,16,18,19,15,15,15,18,18,15,15,15,19,
+ 20,15,15,15,18,18,15,15,15,18,18,15,16,16,19,19,
+ 15,14,15,19,19,15,15,15,19,20,14,14,15,18,18,15,
+ 15,15,19,19,15,16,16,19,19,15,15,14,18,19,15,15,
+ 15,20,20,15,15,14,18,18,13,12,12, 8, 8,13,14,14,
+ 18,18,14,14,14,18,18,14,14,14,18,20,14,14,14,18,
+ 18,14,15,15,19,18,15,14,14,18,19,15,15,15,18,19,
+ 15,14,14,18,19,15,15,15,18,18,14,15,14,18,19,15,
+ 14,14,21,19,15,15,15,19,18,14,14,14,19,18,14,15,
+ 15,19,18,15,15,15,20,19,15,14,14,20,18,14,15,15,
+ 18,19,14,14,14,19,18,14,15,15,18,19,15,15,15,18,
+ 19,15,14,14,19,19,15,15,15,19,19,14,14,14,19,20,
+ 14,15,15,18,19,
+};
+
+static const static_codebook _44p0_p3_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p0_p3_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p0_p3_1,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p0_p4_0[] = {
+ 2, 6, 6,14,14, 6, 8, 8,14,14, 7, 7, 7,14,14, 0,
+ 13,13,15,16, 0,13,13,15,15, 7, 8, 8,15,15, 9,10,
+ 10,16,16, 9, 8, 8,14,15, 0,13,13,17,17, 0,13,13,
+ 16,16, 8, 8, 8,15,15,12,11,11,16,16, 9, 8, 8,14,
+ 14, 0,13,13,17,17, 0,13,13,15,15, 0,14,14,16,16,
+ 0, 0, 0,18,19, 0,12,12,16,15, 0,16,16, 0,20, 0,
+ 14,14,16,16, 0,14,14,17,17, 0, 0, 0,19,19, 0,12,
+ 12,15,15, 0,18,17,21,21, 0,14,14,16,16, 5, 7, 7,
+ 12,13, 9,10, 9,14,14,11,10,10,14,14, 0, 0, 0,18,
+ 17, 0,20,21,18,18, 9,10,10,14,14,12,12,12,17,16,
+ 12,10,10,14,14, 0,20,20,18,17, 0,21,21,17,17,11,
+ 10,10,14,14,15,13,13,18,18,13,11,11,14,14, 0,20,
+ 0,18,18, 0,20,21,18,17, 0,21, 0,18,19, 0, 0, 0,
+ 0,21, 0,21,20,16,17, 0, 0, 0,21,21, 0, 0, 0,20,
+ 18, 0,20, 0,17,18, 0, 0, 0, 0, 0, 0, 0,20,16,17,
+ 0, 0, 0,20, 0, 0, 0, 0,18,18, 6, 6, 6,13,13, 8,
+ 5, 5,11,11, 9, 6, 6,13,13, 0, 9, 9,12,12, 0,10,
+ 10,14,14, 9, 7, 7,13,13,12, 9, 9,13,13,10, 6, 6,
+ 13,13, 0,10,10,14,14, 0,10,10,13,13, 9, 7, 7,13,
+ 13,13,10,10,13,13,11, 6, 6,13,13, 0,10,10,15,15,
+ 0,10,10,13,13, 0,12,11,15,15, 0,20,19,17,16, 0,
+ 9, 9,13,13, 0,13,13,20,19, 0,11,11,13,13, 0,11,
+ 11,15,15, 0,20,19,17,17, 0,10,10,13,13, 0,14,15,
+ 0,21, 0,12,12,13,13, 0,10,10,12,12, 0,11,11,15,
+ 15, 0,11,11,15,15, 0,15,15,20,20, 0,16,16, 0, 0,
+ 0,11,11,15,15, 0,14,14,17,17, 0,11,11,15,15, 0,
+ 15,15,20,21, 0,16,16,21,21, 0,12,12,15,15, 0,15,
+ 15,18,20, 0,11,11,16,15, 0,15,15,21,21, 0,16,16,
+ 0,21, 0,16,16, 0, 0, 0, 0, 0, 0, 0, 0,14,14,21,
+ 21, 0,17,18, 0, 0, 0,16,17,20, 0, 0,16,16, 0, 0,
+ 0, 0, 0, 0, 0, 0,15,15,20,20, 0,19,18, 0,21, 0,
+ 18,17, 0, 0, 0,10,10,11,11, 0,10,10,10,10, 0,11,
+ 11,12,12, 0,11,11, 9, 9, 0,13,13,12,12, 0,11,11,
+ 12,12, 0,13,13,12,12, 0,10,10,12,12, 0,12,12,13,
+ 13, 0,12,12,12,12, 0,11,11,12,12, 0,13,13,12,12,
+ 0,10,10,12,12, 0,13,13,13,13, 0,12,12,12,12, 0,
+ 14,13,13,13, 0,19,21,15,15, 0,12,11,12,12, 0,16,
+ 15,19,19, 0,13,13,11,11, 0,13,13,13,13, 0, 0,21,
+ 15,16, 0,12,12,12,12, 0,16,16,19,21, 0,13,13,12,
+ 12, 7, 7, 7,16,16,11, 9, 9,16,16,12, 9, 9,16,16,
+ 0,13,13,16,16, 0,14,14,17,16,11, 9, 9,16,16,14,
+ 12,11,17,17,13, 8, 9,15,15, 0,13,13,19,19, 0,13,
+ 13,16,15,12,10,10,17,17,15,12,12,19,18,14, 9, 9,
+ 17,16, 0,14,14,18, 0, 0,14,13,16,16, 0,14,15,18,
+ 17, 0,21, 0,19,21, 0,12,12,16,16, 0,16,16, 0, 0,
+ 0,14,14,16,16, 0,14,14,18,18, 0, 0,21,20, 0, 0,
+ 13,13,16,17, 0,18,18, 0, 0, 0,15,14,17,16, 8, 7,
+ 7,14,14,11,10,10,15,15,13,10,10,15,15, 0,21,20,
+ 19,19, 0,21, 0,17,18,11,10,10,15,16,14,12,12,18,
+ 18,14,11,11,15,14, 0,21,20,18,19, 0, 0,21,18,18,
+ 12,11,11,16,16,16,14,14,18,20,14,11,11,16,15, 0,
+ 20,20,19,19, 0, 0,20,18,18, 0,21, 0,18,19, 0, 0,
+ 0, 0, 0, 0,20,20,17,18, 0, 0, 0,20,20, 0, 0, 0,
+ 19,19, 0, 0, 0,20,18, 0, 0, 0, 0, 0, 0, 0,21,18,
+ 18, 0,21,21, 0,21, 0, 0, 0,19,20,11, 9, 9,14,14,
+ 13,10,10,14,14,13,11,11,15,15, 0,13,13,13,13, 0,
+ 14,14,16,16,13,11,11,15,15,16,12,12,15,15,14,10,
+ 10,14,14, 0,14,14,16,16, 0,14,14,15,15,13,10,10,
+ 15,15,17,13,14,15,16,15,10,10,15,15, 0,14,14,17,
+ 16, 0,14,14,15,15, 0,15,15,17,17, 0, 0,21,18,18,
+ 0,13,13,15,15, 0,16,16,21,20, 0,14,14,15,14, 0,
+ 15,14,16,17, 0, 0,20,20,19, 0,13,13,15,15, 0,19,
+ 18, 0, 0, 0,15,15,15,15, 0,11,11,14,14, 0,12,12,
+ 16,16, 0,12,12,16,16, 0,15,16,21,21, 0,16,17,21,
+ 0, 0,12,12,17,16, 0,14,14,18,19, 0,11,11,16,16,
+ 0,15,15,20,21, 0,16,16,21, 0, 0,12,12,17,16, 0,
+ 15,15,19,19, 0,12,12,16,17, 0,16,15, 0, 0, 0,16,
+ 16, 0, 0, 0,17,17, 0,21, 0, 0, 0, 0, 0, 0,14,15,
+ 20, 0, 0,17,17, 0, 0, 0,17,17, 0, 0, 0,17,16, 0,
+ 0, 0, 0, 0, 0, 0, 0,15,15, 0, 0, 0,18,18, 0, 0,
+ 0,18,17, 0, 0, 0,11,11,14,14, 0,12,12,15,15, 0,
+ 12,12,15,15, 0,13,13,14,14, 0,14,14,17,17, 0,12,
+ 12,16,16, 0,14,14,16,16, 0,11,11,15,15, 0,13,13,
+ 16,17, 0,13,13,16,16, 0,12,12,15,15, 0,14,14,17,
+ 16, 0,11,11,15,15, 0,14,14,17,17, 0,13,13,16,16,
+ 0,15,15,17,18, 0,21,20,20,21, 0,12,12,15,15, 0,
+ 16,16,20,21, 0,14,14,15,15, 0,14,14,17,17, 0, 0,
+ 0,18,19, 0,12,13,15,15, 0,18,17,21, 0, 0,14,15,
+ 15,15, 8, 8, 8,16,16,12,10,10,16,16,13, 9, 9,16,
+ 16, 0,14,14,18,17, 0,14,14,16,17,12,10,10,18,17,
+ 14,12,11,18,18,14, 9, 9,16,16, 0,13,13,18,18, 0,
+ 13,13,17,16,12, 9, 9,16,17,17,13,13,17,17,14, 9,
+ 9,15,15, 0,14,14,20,19, 0,13,13,16,16, 0,15,15,
+ 19,18, 0, 0, 0,20,19, 0,12,13,17,17, 0,16,16,20,
+ 0, 0,14,14,16,17, 0,14,14,19,18, 0, 0, 0,20,20,
+ 0,13,13,16,16, 0,18,17, 0, 0, 0,15,15,16,16, 9,
+ 7, 7,14,14,12,10,10,15,15,13,10,10,15,15, 0,21,
+ 0,18,19, 0,20,21,19,18,12,10,10,16,15,15,13,13,
+ 18,18,14,11,11,15,15, 0, 0, 0,19,18, 0, 0,21,18,
+ 18,13,11,11,15,15,16,14,14,17,19,15,11,11,15,15,
+ 0,21,21,20,18, 0, 0,21,18,18, 0, 0,21,21,19, 0,
+ 0, 0, 0, 0, 0,19,20,18,17, 0, 0, 0,21,21, 0,21,
+ 0,20,18, 0, 0,21,19,19, 0, 0, 0, 0, 0, 0,20,21,
+ 17,17, 0, 0, 0, 0, 0, 0,21, 0,18,20, 0,10,10,14,
+ 14, 0,11,11,15,15, 0,11,11,15,15, 0,14,14,15,15,
+ 0,15,15,16,16, 0,11,12,16,16, 0,13,13,16,16, 0,
+ 11,11,15,15, 0,14,14,17,17, 0,14,14,15,15, 0,11,
+ 11,16,15, 0,14,14,15,15, 0,11,11,15,15, 0,15,15,
+ 17,17, 0,14,14,15,15, 0,16,16,18,18, 0, 0, 0,20,
+ 19, 0,14,13,16,15, 0,17,17,21, 0, 0,15,15,15,15,
+ 0,16,15,17,16, 0,20, 0,20,18, 0,13,14,15,15, 0,
+ 19,18, 0,21, 0,15,15,15,15, 0,11,11,14,14, 0,12,
+ 12,16,16, 0,12,12,16,16, 0,16,15,20,21, 0,17,16,
+ 0, 0, 0,12,12,16,16, 0,14,14,18,18, 0,11,11,16,
+ 16, 0,15,15,21,20, 0,16,16, 0, 0, 0,12,12,16,17,
+ 0,15,14,19,19, 0,11,12,16,16, 0,15,15,21, 0, 0,
+ 16,16, 0, 0, 0,16,17, 0, 0, 0, 0, 0, 0, 0, 0,15,
+ 15,21, 0, 0,17,17, 0, 0, 0,17,17, 0, 0, 0,17,16,
+ 0, 0, 0, 0, 0, 0, 0, 0,15,15, 0,20, 0,19,20, 0,
+ 0, 0,17,17, 0, 0, 0,12,12,15,15, 0,12,12,15,15,
+ 0,12,12,16,16, 0,13,13,15,15, 0,15,15,17,17, 0,
+ 13,13,17,16, 0,14,14,17,17, 0,11,11,16,16, 0,14,
+ 14,17,17, 0,13,13,16,16, 0,12,12,16,16, 0,15,15,
+ 16,17, 0,11,11,15,16, 0,14,14,17,17, 0,13,14,16,
+ 16, 0,15,15,18,18, 0,21,20,20,19, 0,13,13,16,17,
+ 0,16,16, 0, 0, 0,14,14,16,16, 0,15,15,18,18, 0,
+ 0, 0,20,19, 0,13,13,16,16, 0,17,17, 0, 0, 0,14,
+ 14,16,16, 0,11,11,16,16, 0,13,13,18,17, 0,13,13,
+ 17,17, 0,16,16,17,17, 0,16,16,17,18, 0,12,12,17,
+ 17, 0,15,15,18,18, 0,12,12,16,16, 0,16,16,19,19,
+ 0,15,15,16,17, 0,12,12,17,17, 0,17,17,18,18, 0,
+ 12,12,17,17, 0,16,16,19,19, 0,15,16,17,17, 0,16,
+ 16,18,17, 0, 0, 0,21,21, 0,13,13,16,16, 0,17,17,
+ 0,20, 0,15,15,16,17, 0,16,16,19,18, 0, 0,21,20,
+ 21, 0,14,14,17,16, 0,20, 0, 0, 0, 0,15,16,16,17,
+ 0, 9, 9,14,14, 0,13,13,16,16, 0,14,14,15,15, 0,
+ 0,20,19,19, 0, 0, 0,19,19, 0,12,12,15,15, 0,15,
+ 16,19,18, 0,14,14,15,15, 0,21, 0,18,18, 0,20, 0,
+ 17,18, 0,13,13,16,16, 0,17,17,17,19, 0,14,14,16,
+ 15, 0,21,20,20,19, 0, 0, 0,19,19, 0, 0, 0,19,18,
+ 0, 0, 0, 0, 0, 0,20,20,17,18, 0, 0, 0,21,21, 0,
+ 0, 0,18,18, 0,21, 0,18,19, 0, 0, 0, 0, 0, 0,20,
+ 21,18,18, 0, 0, 0,20,21, 0, 0, 0,19,19, 0,18,18,
+ 15,15, 0,20,21,17,17, 0,19,21,17,17, 0, 0, 0,17,
+ 18, 0, 0, 0,20,19, 0,19,19,17,17, 0, 0, 0,18,18,
+ 0,19,20,16,17, 0, 0,21,20,20, 0,19,20,19,18, 0,
+ 19,20,16,16, 0, 0, 0,18,19, 0,19,20,17,17, 0, 0,
+ 21, 0,20, 0,21,21,17,19, 0,20, 0,19,20, 0, 0, 0,
+ 20, 0, 0,19,18,17,16, 0, 0, 0, 0, 0, 0, 0,20,17,
+ 17, 0,20,21,18,20, 0, 0, 0, 0,21, 0,19,20,17,17,
+ 0, 0, 0, 0, 0, 0,20,21,17,17, 0,11,11,14,14, 0,
+ 13,13,16,17, 0,13,13,16,16, 0,17,17, 0,21, 0,18,
+ 17,21, 0, 0,13,13,16,16, 0,15,15,18,18, 0,12,12,
+ 16,16, 0,17,16,21, 0, 0,17,17, 0, 0, 0,12,12,17,
+ 17, 0,17,17,19,21, 0,13,12,16,16, 0,17,17, 0, 0,
+ 0,17,17, 0, 0, 0,18,17, 0,21, 0, 0, 0, 0, 0, 0,
+ 15,15,20, 0, 0,20,18, 0, 0, 0,17,18, 0, 0, 0,16,
+ 17, 0, 0, 0, 0, 0, 0, 0, 0,15,15, 0, 0, 0,19,19,
+ 0, 0, 0,18,18, 0, 0, 0,14,14,18,18, 0,16,16, 0,
+ 21, 0,16,16,21,21, 0,17,17, 0,20, 0,17,17,20, 0,
+ 0,16,15, 0, 0, 0,20,20, 0, 0, 0,15,15,20,20, 0,
+ 17,17,21, 0, 0,17,18,20,20, 0,15,15,20,20, 0,18,
+ 18, 0, 0, 0,15,15,19,20, 0,17,18, 0, 0, 0,17,17,
+ 20,20, 0,18,17,21, 0, 0, 0, 0, 0,21, 0,15,15,20,
+ 20, 0,19,19, 0, 0, 0,17,17,21, 0, 0,17,17, 0, 0,
+ 0, 0, 0,21, 0, 0,15,15,19,19, 0,20,21, 0, 0, 0,
+ 18,17,21,21, 0,12,12,16,16, 0,14,14,17,17, 0,13,
+ 13,17,18, 0,16,16,18,17, 0,16,16,18,18, 0,13,13,
+ 18,18, 0,15,16,19,18, 0,13,13,16,16, 0,16,16,20,
+ 18, 0,16,16,17,17, 0,12,13,17,17, 0,17,16,18,18,
+ 0,12,12,16,16, 0,17,16,20,19, 0,16,16,16,16, 0,
+ 16,17,18,20, 0, 0, 0,21,20, 0,14,14,17,16, 0,19,
+ 18, 0,20, 0,16,16,17,16, 0,16,16,17,18, 0, 0,21,
+ 21,21, 0,14,14,16,16, 0,20,20,21, 0, 0,16,16,16,
+ 16, 0,10,10,14,14, 0,14,14,15,16, 0,14,14,15,15,
+ 0, 0,21,18,18, 0, 0,21,18,19, 0,13,13,16,16, 0,
+ 16,16,18,18, 0,14,14,15,15, 0,21, 0,18,18, 0,21,
+ 0,18,18, 0,13,13,16,16, 0,17,17,19,20, 0,14,14,
+ 15,15, 0, 0, 0,18,20, 0, 0,21,18,18, 0, 0,21,19,
+ 18, 0, 0, 0, 0, 0, 0,20,21,18,17, 0, 0, 0,21,21,
+ 0, 0, 0,19,19, 0,21, 0,18,19, 0, 0, 0, 0, 0, 0,
+ 21,20,17,17, 0, 0,21,20, 0, 0, 0, 0,19,19, 0,19,
+ 20,15,16, 0, 0,20,18,17, 0,20,21,17,18, 0,21, 0,
+ 18,18, 0, 0, 0,19,19, 0,20,20,17,18, 0, 0, 0,18,
+ 19, 0,20,20,18,17, 0, 0, 0, 0,20, 0, 0,21,17,18,
+ 0,20,21,17,17, 0, 0, 0,18,18, 0,19,19,17,17, 0,
+ 0, 0,21,21, 0,20,20,17,17, 0, 0, 0,21,19, 0, 0,
+ 0,20,19, 0,21,20,17,18, 0, 0, 0, 0, 0, 0, 0,20,
+ 18,17, 0,21,20,18,18, 0, 0, 0,20,21, 0,20,20,17,
+ 17, 0, 0, 0, 0, 0, 0,20, 0,17,17, 0,11,11,13,14,
+ 0,13,13,16,16, 0,13,13,16,16, 0,17,17, 0, 0, 0,
+ 17,18, 0, 0, 0,13,13,16,16, 0,15,16,18,18, 0,13,
+ 13,16,17, 0,16,17,20, 0, 0,17,18,20, 0, 0,13,13,
+ 17,17, 0,16,16,20,21, 0,13,13,16,16, 0,17,17,21,
+ 0, 0,17,18, 0, 0, 0,17,18, 0,21, 0, 0, 0, 0, 0,
+ 0,15,15,20, 0, 0,19,19, 0, 0, 0,17,17, 0, 0, 0,
+ 18,17,21,20, 0, 0, 0, 0, 0, 0,16,16,20,21, 0,21,
+ 20, 0,21, 0,19,21, 0, 0, 0,15,15, 0, 0, 0,16,17,
+ 0,19, 0,16,16, 0, 0, 0,17,17, 0, 0, 0,19,18, 0,
+ 0, 0,16,16,20,20, 0,20,18,21, 0, 0,15,15,21,21,
+ 0,18,18, 0, 0, 0,18,19, 0, 0, 0,16,15, 0,21, 0,
+ 20,19, 0, 0, 0,16,16, 0, 0, 0,20,18, 0,21, 0,17,
+ 18,21, 0, 0,18,19, 0, 0, 0, 0, 0, 0, 0, 0,16,16,
+ 20,20, 0,19,20, 0, 0, 0,17,17, 0, 0, 0,18,17,20,
+ 21, 0, 0, 0, 0, 0, 0,16,16, 0,20, 0,20,22, 0, 0,
+ 0,18,18, 0,22,
+};
+
+static const static_codebook _44p0_p4_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p0_p4_0,
+ 1, -528744448, 1616642048, 3, 0,
+ (long *)_vq_quantlist__44p0_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p4_1[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44p0_p4_1[] = {
+ 2, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _44p0_p4_1 = {
+ 1, 7,
+ (char *)_vq_lengthlist__44p0_p4_1,
+ 1, -533200896, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p0_p4_1,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p5_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p0_p5_0[] = {
+ 1, 6, 6, 6, 8, 8, 7, 8, 8, 7, 9, 8,10,11,11, 9,
+ 8, 8, 7, 8, 8,11,11,11, 9, 8, 8, 6, 7, 7,10,10,
+ 10,10,10,10,10,10,10,14,13,13,12,11,11,10,10,10,
+ 14,14,13,13,11,11, 6, 6, 6, 8, 5, 5, 8, 7, 7, 8,
+ 7, 7,11, 9, 9, 9, 7, 7, 8, 7, 7,12,10,10,10, 7,
+ 7, 7, 8, 8,12,11,11,12,10,10,11,10,10,14,13,13,
+ 13,10,10,11,10,11,16,14,14,13,10,10, 7, 8, 7,12,
+ 12,12,12,11,11,12,11,11,16,14,15,13,12,12,11,11,
+ 11,17,15,14,14,13,13,10, 9, 9,13,11,11,13,11,11,
+ 12,11,11,16,14,13,14,11,11,12,11,11,16,15,14,14,
+ 11,11, 7, 8, 8,12,11,11,12,10,10,12,10,10,16,14,
+ 13,13,11,11,12,10,10,16,14,14,13,10,10, 8, 8, 8,
+ 12,12,12,12,11,11,12,11,11,16,14,15,14,12,12,12,
+ 11,11,16,15,15,14,12,12,10,10,10,13,11,11,13,11,
+ 11,12,12,12,16,14,14,14,11,11,12,11,11,17,14,15,
+ 14,11,11,
+};
+
+static const static_codebook _44p0_p5_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p0_p5_0,
+ 1, -527106048, 1620377600, 2, 0,
+ (long *)_vq_quantlist__44p0_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p5_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p0_p5_1[] = {
+ 2, 7, 7, 7, 8, 8, 7, 7, 7, 7, 8, 8, 8, 8, 9, 8,
+ 7, 7, 8, 8, 8, 9, 9, 9, 9, 7, 7, 6, 6, 6, 9, 7,
+ 7, 9, 7, 7, 9, 8, 8,10, 8, 8,10, 8, 8,10, 8, 8,
+ 10, 8, 8,10, 8, 8, 7, 6, 6, 9, 6, 6, 9, 6, 6, 9,
+ 7, 7,10, 8, 8, 9, 6, 6, 9, 7, 7,10, 8, 8, 9, 7,
+ 7, 7, 8, 8,11, 9, 9,11, 9, 9,11, 9, 9,12, 9, 9,
+ 12, 8, 8,12, 9, 9,12,10, 9,12, 8, 8, 8, 7, 7,10,
+ 9, 9,11, 9, 9,11, 9, 9,11,11,10,11, 9, 9,11,10,
+ 9,11,10,11,11, 9, 9,10, 8, 8,11, 9, 9,11, 9, 9,
+ 11, 9, 9,11,10,10,11, 9, 9,11, 9, 9,11,10,10,11,
+ 9, 9, 9, 8, 8,12, 9, 9,12, 9, 9,11, 9, 9,12, 9,
+ 9,12, 8, 8,12, 9, 9,12, 9, 9,12, 8, 8, 9, 7, 7,
+ 11, 9,10,11,10, 9,11, 9, 9,11,11,11,11, 9, 9,11,
+ 10,10,11,11,11,11, 9, 9,10, 9, 9,11, 9, 9,11,10,
+ 10,11,10, 9,11,10,10,11, 9, 9,11,10,10,11,10,11,
+ 11, 9, 9,
+};
+
+static const static_codebook _44p0_p5_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p0_p5_1,
+ 1, -530841600, 1616642048, 2, 0,
+ (long *)_vq_quantlist__44p0_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p0_p6_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p0_p6_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p0_p6_0,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p0_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p6_1[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p0_p6_1[] = {
+ 1, 3, 2, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,
+ 11,12,12,12,14,14,14,15,15,
+};
+
+static const static_codebook _44p0_p6_1 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p0_p6_1,
+ 1, -518864896, 1620639744, 5, 0,
+ (long *)_vq_quantlist__44p0_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44p0_p6_2[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p0_p6_2[] = {
+ 3, 4, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p0_p6_2 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p0_p6_2,
+ 1, -529006592, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44p0_p6_2,
+ 0
+};
+
+static const char _huff_lengthlist__44p0_short[] = {
+ 3, 3, 7, 8,10,13,16, 3, 2, 5, 7, 9,13,16, 6, 4,
+ 4, 6,10,14,15, 7, 5, 5, 7,10,13,14, 9, 8, 9, 9,
+ 9,11,13,12,11,12, 9, 7, 8,11,14,12,10, 6, 5, 7,
+ 10,
+};
+
+static const static_codebook _huff_book__44p0_short = {
+ 2, 49,
+ (char *)_huff_lengthlist__44p0_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p1_l0_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44p1_l0_0[] = {
+ 1, 4, 4, 7, 7, 8, 8, 9, 9,10,10,11,11, 4, 6, 5,
+ 8, 6, 9, 8,10, 9,10,10,11,10, 5, 5, 6, 6, 8, 8,
+ 9, 9,10,10,10,10,11, 7, 8, 8, 9, 8,10, 9,10, 9,
+ 11,10,11,10, 7, 8, 8, 8,10, 9,10,10,10,10,11,10,
+ 11, 9,10,10,11,11,11,11,12,11,12,11,12,11, 9,10,
+ 10,11,11,11,11,11,11,11,12,11,12,11,11,11,12,12,
+ 12,12,12,12,12,12,12,11,11,12,11,12,12,12,12,12,
+ 12,12,12,11,12,12,12,12,12,13,12,13,12,12,12,12,
+ 12,12,12,12,12,13,13,13,13,12,13,12,12,12,12,12,
+ 13,13,12,13,12,13,12,13,12,12,12,12,13,13,13,13,
+ 13,13,12,12,12,12,12,11,12,
+};
+
+static const static_codebook _44p1_l0_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44p1_l0_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44p1_l0_0,
+ 0
+};
+
+static const long _vq_quantlist__44p1_l0_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p1_l0_1[] = {
+ 1, 4, 4, 6, 6, 5, 5, 5, 6, 6, 5, 6, 5, 6, 6, 6,
+ 6, 7, 7, 7, 6, 7, 6, 7, 7,
+};
+
+static const static_codebook _44p1_l0_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p1_l0_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p1_l0_1,
+ 0
+};
+
+static const long _vq_quantlist__44p1_l1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p1_l1_0[] = {
+ 1, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+
+static const static_codebook _44p1_l1_0 = {
+ 2, 9,
+ (char *)_vq_lengthlist__44p1_l1_0,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p1_l1_0,
+ 0
+};
+
+static const char _huff_lengthlist__44p1_lfe[] = {
+ 1, 3, 2, 3,
+};
+
+static const static_codebook _huff_book__44p1_lfe = {
+ 2, 4,
+ (char *)_huff_lengthlist__44p1_lfe,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44p1_long[] = {
+ 3, 3, 7, 7, 9,13,16, 3, 2, 4, 6,10,13,17, 7, 4,
+ 4, 6, 9,12,14, 7, 6, 6, 5, 7, 9,12,10,10, 9, 6,
+ 6, 9,12,14,14,13, 9, 8,10,11,18,18,15,13,11,10,
+ 11,
+};
+
+static const static_codebook _huff_book__44p1_long = {
+ 2, 49,
+ (char *)_huff_lengthlist__44p1_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p1_p1_0[] = {
+ 1, 2, 2, 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, 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,
+};
+
+static const static_codebook _44p1_p1_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p1_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p1_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p1_p2_0[] = {
+ 1, 4, 4, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0,12,12, 0,
+ 8, 8, 0, 9, 9, 0,12,12, 0, 8, 8, 0, 6, 6, 0,11,
+ 11, 0,11,11, 0,12,12, 0,14,14, 0,11,11, 0,12,12,
+ 0,14,14, 0,11,11, 0, 6, 6, 0, 6, 5, 0, 7, 6, 0,
+ 7, 7, 0,10,10, 0, 6, 6, 0, 7, 7, 0,10,10, 0, 7,
+ 7, 0, 7, 7, 0,10,10, 0,11,11, 0,11,11, 0,14,14,
+ 0,10,10, 0,12,12, 0,14,14, 0,12,12, 0, 6, 6, 0,
+ 11,11, 0,11,11, 0,12,12, 0,14,14, 0,11,11, 0,12,
+ 12, 0,15,15, 0,11,11, 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, 8, 8, 0,11,11, 0,11,11, 0,12,12, 0,15,
+ 15, 0,12,12, 0,11,11, 0,15,15, 0,11,11, 0, 6, 6,
+ 0,11,11, 0,12,12, 0,12,12, 0,15,15, 0,11,11, 0,
+ 12,12, 0,14,14, 0,12,12, 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,
+};
+
+static const static_codebook _44p1_p2_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p1_p2_0,
+ 1, -533200896, 1614282752, 2, 0,
+ (long *)_vq_quantlist__44p1_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p2_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p1_p2_1[] = {
+ 1, 3, 3, 0, 8, 8, 0, 8, 8, 0,10,10, 0, 9, 9, 0,
+ 10,10, 0,10,10, 0, 9, 9, 0,10,10, 0, 7, 7, 0, 7,
+ 7, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0, 8, 8, 0, 9, 9,
+ 0, 8, 8, 0, 8, 8, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0,
+ 10,10, 0, 9, 9, 0, 9, 9, 0,10,10, 0, 9, 9, 0,10,
+ 10, 0, 8, 8, 0,11,11, 0,11,11, 0,12,12, 0,11,11,
+ 0,12,12, 0,12,12, 0,12,12, 0,12,12, 0, 8, 8, 0,
+ 11,11, 0,11,11, 0,13,12, 0,12,12, 0,13,12, 0,13,
+ 13, 0,12,12, 0,13,13, 0, 7, 7, 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, 8, 8, 0,11,11, 0,11,11, 0,13,12, 0,12,
+ 12, 0,12,12, 0,12,12, 0,11,11, 0,12,12, 0, 8, 8,
+ 0,12,12, 0,12,12, 0,13,13, 0,12,12, 0,13,13, 0,
+ 13,13, 0,12,13, 0,13,13, 0, 7, 7, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,
+};
+
+static const static_codebook _44p1_p2_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p1_p2_1,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p1_p2_1,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p3_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p1_p3_0[] = {
+ 1, 6, 6, 6, 7, 7, 7, 8, 8, 7, 8, 8,10,11,11, 9,
+ 8, 8, 7, 9, 9,11,12,12, 9, 8, 8, 6, 7, 7, 9,11,
+ 11,10,11,11,10,11,11,13,13,13,11,12,12,10,11,11,
+ 13,14,14,12,12,12, 6, 6, 6, 8, 6, 6, 8, 6, 6, 9,
+ 7, 7,12,10,10,10, 6, 6, 9, 7, 7,12,10,10,11, 7,
+ 6, 7, 8, 8,12,10,10,12,10,10,11,10,10,15,13,13,
+ 13,10,10,12,11,11,15,13,13,14,11,11, 8, 7, 7,12,
+ 11,11,12,11,11,11,11,11,14,14,14,13,12,12,12,11,
+ 11,16,15,15,14,12,12, 0,10,10, 0,11,11, 0,12,12,
+ 0,11,11, 0,14,14, 0,11,11, 0,11,11, 0,15,15, 0,
+ 11,11, 7, 8, 8,13,10,10,12,10,10,12,11,11,15,13,
+ 13,14,11,11,12,10,10,16,14,14,14,10,10, 8, 7, 7,
+ 12,11,11,13,11,11,12,11,11,15,14,14,14,12,12,13,
+ 12,12,15,14,14,15,12,12, 0,11,11, 0,12,12, 0,12,
+ 12, 0,12,12, 0,15,15, 0,12,12, 0,12,12, 0,15,14,
+ 0,12,12,
+};
+
+static const static_codebook _44p1_p3_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p1_p3_0,
+ 1, -531365888, 1616117760, 2, 0,
+ (long *)_vq_quantlist__44p1_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p3_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p1_p3_1[] = {
+ 2, 3, 4, 7, 7,10,12,12,12,12,10,11,11,13,13,11,
+ 12,12,11,11,12,12,12,12,12,11,13,13,13,13,12,12,
+ 12,13,14,12,13,13,13,13,12,13,13,13,13,12,13,13,
+ 13,13,11,13,13,13,13,12,12,12,14,14,12,13,13,12,
+ 12,12,12,13,13,13,12,13,13,13,13,12,13,13,13,13,
+ 12,12,12,14,14,12,13,13,12,12,12,13,13,13,13,12,
+ 13,13,12,12,12,13,13,13,13,12,12,12,14,14,12,13,
+ 13,12,12,12,13,13,13,13,12,13,13,12,12,10,10,11,
+ 10,10,11,11,11,11,11,11, 9, 9,10,10,12,11,11,10,
+ 10,12,10,10,10,10,13,12,12,12,12,13,11,11,11,11,
+ 13,12,12,12,12,13,11,11,11,11,13,12,12,12,12,13,
+ 12,12,12,12,13,11,11,11,11,13,12,12,12,12,13,11,
+ 11,11,11,13,12,12,11,11,13,12,12,11,11,13,11,11,
+ 11,11,13,12,12,11,11,13,11,11,11,11,13,12,12,11,
+ 11,13,12,12,11,11,13,11,11,11,11,13,12,12,11,11,
+ 13,11,11,11,11,13,12,12,11,11,11,11,11,10,10,11,
+ 11,11, 9, 9,11,12,12,11,11,12,12,12, 9, 9,13,13,
+ 13,10,10,13,13,13,11,11,13,13,13,14,14,13,13,13,
+ 11,10,13,13,14,12,12,13,13,13,11,11,13,13,13,11,
+ 11,13,13,13,14,14,13,13,13,10,10,13,13,13,11,11,
+ 13,13,13,10,10,13,14,13,11,11,13,14,14,14,14,13,
+ 13,13,10,10,13,14,14,11,11,13,13,13,10,10,13,14,
+ 14,11,11,13,13,13,14,14,14,13,13,10,10,13,14,14,
+ 11,11,13,13,13,10,10,14,12,12, 9, 9,14,12,12, 9,
+ 9,14,11,11, 9, 9,14,12,12, 8, 8,14,11,11, 7, 7,
+ 15,13,13,10,10,15,12,12,10,10,15,13,13,10,10,15,
+ 12,12,10,10,15,13,13,10,10,15,13,13,10,10,15,12,
+ 12,10,10,15,13,13,10,10,15,12,12,10,10,15,13,13,
+ 10,10,15,13,13,10,10,15,12,12,10,10,15,13,13, 9,
+ 9,15,12,12, 9, 9,14,13,13, 9, 9,15,13,13,10,10,
+ 15,12,12,10,10,15,13,13, 9, 9,15,12,12, 9, 9,15,
+ 13,13, 9, 9,13,12,12, 9, 9,13,13,13, 8, 8,13,13,
+ 13, 9, 9,13,13,13, 7, 7,14,13,13, 8, 8,14,14,14,
+ 10,10,15,14,14,11,11,14,14,14, 9, 9,15,14,14,10,
+ 10,15,14,14, 9, 9,14,14,14,10,10,15,14,14,11,11,
+ 15,14,14, 9, 9,14,14,14,10,10,14,14,14, 9, 9,15,
+ 14,15,10,10,15,14,14,11,11,14,14,14, 9, 9,14,14,
+ 14, 9, 9,14,14,14, 8, 8,15,14,14,10,10,15,14,14,
+ 11,11,14,14,14, 9, 9,15,14,14, 9, 9,14,14,14, 8,
+ 8,12,12,12,13,13,16,16,16,11,11,17,16,16,12,12,
+ 17,16,16,11,11,17,16,16,11,11,17,17,16,13,13,17,
+ 16,16,13,13,18,17,16,12,12,17,16,16,13,13,17,16,
+ 17,12,12,18,17,17,13,13,17,16,16,14,14,18,17,17,
+ 12,12,18,16,16,13,13,17,17,17,13,12,17,17,17,13,
+ 13,17,16,16,13,13,18,17,17,12,12,17,16,16,13,12,
+ 17,17,17,12,12,18,17,17,13,13,18,16,16,14,14,18,
+ 17,17,12,12,17,17,17,13,13,18,17,18,12,12,13,14,
+ 14,10,10,16,14,14,13,13,17,15,15,14,14,17,14,14,
+ 12,13,16,14,14,13,13,17,15,15,14,14,16,16,16,15,
+ 15,17,15,15,14,14,17,16,16,14,15,17,15,15,14,14,
+ 17,15,16,14,14,17,16,16,15,15,17,15,15,13,13,17,
+ 15,15,14,14,18,15,15,13,14,17,15,15,14,14,16,16,
+ 16,15,15,17,15,15,13,13,17,15,15,14,14,17,15,15,
+ 13,13,17,15,15,14,14,16,16,16,15,15,17,15,15,13,
+ 13,17,15,15,14,14,18,15,15,13,13,13,11,11,10,10,
+ 16,14,14,13,12,16,14,14,13,13,16,15,14,12,12,16,
+ 14,14,12,12,16,15,15,14,14,16,14,14,14,14,17,15,
+ 15,13,13,16,15,15,14,14,17,15,15,13,14,17,15,15,
+ 14,14,17,15,14,14,14,17,15,15,13,13,17,15,15,14,
+ 14,17,15,15,13,13,17,15,15,14,14,17,14,14,14,14,
+ 17,15,15,13,13,17,15,15,13,13,17,15,15,13,13,17,
+ 15,15,14,14,17,15,15,14,14,17,15,15,13,13,17,15,
+ 15,13,13,17,15,15,13,13,14,14,15, 8, 8,14,14,14,
+ 19,19,14,15,15,18,19,14,14,14,19,18,14,14,14,19,
+ 19,15,15,15,19,18,15,16,16,19,19,15,15,15,19,19,
+ 15,16,16,20,19,15,15,15,19,19,15,15,15,19,19,16,
+ 16,16,20,19,15,15,15,19,18,15,16,16,20,19,15,15,
+ 15,18,18,15,15,15,19,20,15,16,16,19,19,15,15,15,
+ 20,19,15,15,15,20,19,15,15,15,19,18,15,15,15,19,
+ 19,15,16,16,19,20,15,15,15,19,19,15,15,15,19,20,
+ 15,15,15,19,19,14,12,12, 9, 9,14,14,14,19,19,14,
+ 14,14,19,19,14,14,15,20,19,15,14,14,18,19,15,15,
+ 15,19,19,15,15,14,20,19,15,15,15,20,19,15,15,14,
+ 20,19,15,15,15,20,19,15,15,15,19,20,15,14,14,19,
+ 20,15,15,15,20,20,15,14,14,20,19,15,15,15,19,19,
+ 15,15,15,19,19,15,14,14,19,19,15,15,15,19,20,15,
+ 15,15,20,20,15,15,15,19,19,15,15,15,20,19,16,14,
+ 14,19,19,15,15,15,20,19,15,14,15,20,19,14,15,15,
+ 20,19,12,12,12,13,13,16,16,16,11,11,16,16,16,12,
+ 12,17,16,16,11,11,17,15,16,11,11,17,17,17,13,13,
+ 18,16,17,13,13,18,17,17,13,12,17,16,17,13,13,17,
+ 17,17,13,13,16,16,16,12,12,17,16,16,13,13,17,16,
+ 16,12,12,17,16,16,12,13,17,17,17,12,12,17,17,17,
+ 13,13,18,16,16,13,13,18,17,17,12,12,18,17,17,12,
+ 12,17,17,17,12,12,17,17,17,12,12,17,16,16,13,13,
+ 17,17,17,12,12,17,16,16,12,12,17,17,17,12,12,13,
+ 14,14, 9, 9,16,14,14,13,13,16,15,15,14,14,17,14,
+ 14,13,13,16,14,14,13,13,17,15,15,15,15,16,16,16,
+ 15,15,17,15,15,14,14,17,15,15,15,15,17,15,15,14,
+ 14,17,15,15,14,14,16,16,16,15,15,17,15,15,14,14,
+ 17,15,15,14,14,17,15,15,14,14,17,15,15,14,14,16,
+ 16,16,15,15,18,15,15,14,13,17,15,15,14,14,17,15,
+ 15,13,13,17,15,15,14,14,16,16,16,15,15,17,15,15,
+ 14,13,17,15,15,14,14,17,15,15,13,13,13,11,11,11,
+ 11,16,14,14,12,12,16,14,14,13,13,16,15,14,12,12,
+ 17,14,14,12,12,17,15,15,13,13,17,14,14,14,14,17,
+ 15,15,13,13,17,14,15,14,13,17,15,15,13,13,16,15,
+ 15,13,13,16,14,14,14,14,17,15,15,13,13,16,14,14,
+ 13,13,16,15,15,13,13,17,15,15,13,13,17,14,14,14,
+ 14,17,15,15,12,12,17,15,15,13,13,17,15,15,12,12,
+ 16,15,15,13,13,17,14,14,13,14,17,15,15,12,12,17,
+ 14,14,13,13,17,15,15,12,12,14,14,14, 8, 8,14,14,
+ 14,18,18,14,15,15,19,19,14,14,14,19,19,14,15,14,
+ 18,19,15,15,15,18,19,15,16,16,20,20,15,15,15,19,
+ 20,15,16,16,19,20,15,15,15,19,20,15,15,16,19,19,
+ 15,16,16,20,20,15,15,15,20,19,15,16,16,20,19,15,
+ 15,15,19,20,15,15,15,19,19,15,16,16,20,19,15,15,
+ 15,19,19,15,16,15,20,19,15,15,15,19,19,15,15,15,
+ 19,20,15,16,16,20,20,15,15,15,19,19,15,15,15,20,
+ 20,15,15,15,19,19,14,12,12, 9, 9,14,14,14,18,18,
+ 14,14,14,19,20,14,14,14,18,18,14,14,14,18,19,15,
+ 15,15,19,20,15,14,14,19,19,15,15,15,19,19,15,14,
+ 15,19,19,15,15,15,18,20,15,15,15,19,19,15,14,14,
+ 19,19,15,15,15,20,19,15,15,14,20,20,15,15,15,19,
+ 19,15,15,15,19,19,15,14,14,19,19,15,15,15,19,19,
+ 15,14,14,19,20,14,15,15,19,19,15,15,15,19,19,15,
+ 14,14,20,19,15,15,15,19,19,15,14,14,20,19,15,15,
+ 15,19,19,13,12,12,13,13,17,17,16,11,11,16,16,16,
+ 12,12,17,17,16,11,11,17,16,16,11,11,17,17,17,13,
+ 13,17,16,16,13,13,18,17,17,12,12,17,16,16,13,13,
+ 18,17,17,12,12,18,17,17,13,13,18,16,17,13,13,17,
+ 17,17,12,12,18,17,17,13,13,18,17,17,12,12,17,16,
+ 17,12,12,17,16,16,13,13,17,16,16,11,11,17,16,16,
+ 12,12,17,17,17,11,11,17,17,17,12,12,18,16,16,13,
+ 13,18,17,17,12,11,17,16,16,12,12,18,17,17,11,11,
+ 13,14,14, 9, 9,16,14,14,13,13,16,15,15,14,14,17,
+ 14,14,12,12,16,14,14,13,13,17,15,15,14,14,17,16,
+ 16,15,16,18,15,15,14,14,17,15,15,14,14,17,15,15,
+ 14,14,18,15,15,14,14,16,16,16,15,16,18,15,15,14,
+ 14,17,16,15,14,14,18,15,15,14,14,17,15,15,14,14,
+ 17,16,16,15,15,18,14,15,13,13,17,15,15,14,14,18,
+ 15,15,13,13,17,15,15,14,14,17,16,15,15,15,17,15,
+ 15,13,13,17,15,15,14,14,18,15,15,13,13,13,11,11,
+ 10,10,16,14,14,12,12,16,14,14,12,12,17,14,15,11,
+ 11,17,14,14,11,11,17,15,15,13,13,17,14,14,14,13,
+ 17,15,15,13,13,16,15,15,13,13,17,15,15,13,13,17,
+ 15,15,13,13,17,14,14,14,14,17,15,15,13,13,17,14,
+ 15,13,13,16,15,15,13,13,17,15,15,13,13,17,14,14,
+ 13,13,17,15,15,12,12,16,14,14,12,12,17,15,15,12,
+ 12,17,15,15,13,13,17,14,14,13,13,17,15,15,12,12,
+ 17,14,14,12,12,17,15,15,12,12,13,15,14, 8, 8,14,
+ 14,14,19,19,14,15,15,18,19,14,14,14,18,19,14,15,
+ 14,19,19,15,16,15,19,19,15,16,16,19,20,15,15,15,
+ 19,19,15,16,16,19,19,15,16,16,19,19,15,15,15,19,
+ 19,15,16,16,20,20,15,15,15,19,19,15,15,15,19,19,
+ 15,15,15,19,19,15,15,15,19,19,15,16,16,20,19,15,
+ 15,15,19,19,15,15,15,19,19,15,15,15,19,19,15,16,
+ 15,19,19,15,16,16,21,19,15,15,15,20,20,15,15,15,
+ 20,21,15,15,15,19,20,14,12,12, 8, 8,14,14,14,19,
+ 19,14,13,13,19,19,14,14,14,19,19,14,13,14,19,19,
+ 15,15,15,20,20,15,14,14,20,19,15,15,15,19,20,15,
+ 14,14,19,20,15,15,15,20,19,15,15,15,19,20,15,14,
+ 14,20,20,15,15,15,20,19,15,14,14,19,19,15,15,15,
+ 19,19,15,15,15,20,19,15,14,14,21,19,15,15,15,20,
+ 21,15,14,14,21,19,15,15,15,19,19,15,15,15,20,20,
+ 15,14,14,19,21,15,15,15,19,19,15,14,14,19,20,15,
+ 15,15,19,19,13,12,12,13,13,17,16,16,11,11,17,16,
+ 15,12,12,18,16,16,11,11,17,16,16,11,11,18,17,17,
+ 13,13,18,16,16,13,13,17,17,17,12,13,18,17,16,13,
+ 13,18,17,17,13,13,17,17,17,13,13,17,16,16,13,13,
+ 18,16,17,12,12,17,16,16,13,12,17,17,17,12,12,18,
+ 17,17,13,12,18,16,16,13,13,18,17,17,12,12,17,16,
+ 16,12,12,17,17,17,11,11,17,16,16,12,12,17,16,16,
+ 13,13,17,16,16,11,11,17,16,16,12,12,17,17,17,11,
+ 11,13,14,14, 9, 9,16,14,14,13,13,16,15,15,14,14,
+ 17,14,14,12,12,16,14,14,13,13,17,15,15,14,14,17,
+ 15,16,15,15,17,15,15,14,14,17,15,16,14,15,18,15,
+ 15,14,14,17,15,15,14,14,16,16,16,15,15,18,15,15,
+ 13,14,17,15,15,14,14,18,15,15,14,14,17,15,15,14,
+ 14,17,16,16,15,15,17,15,15,13,13,17,15,15,14,14,
+ 18,15,15,13,13,17,15,15,14,14,17,16,16,15,15,17,
+ 15,15,13,13,17,15,15,14,14,18,15,15,13,13,13,11,
+ 11,10,10,16,14,14,12,12,16,14,14,13,13,17,14,14,
+ 11,11,17,14,14,12,12,17,15,15,14,14,17,14,14,14,
+ 14,17,15,15,13,13,17,15,14,13,13,16,15,15,13,13,
+ 16,15,15,13,13,17,14,14,14,14,17,15,15,13,13,17,
+ 14,14,13,13,16,15,15,13,13,16,15,15,13,13,17,14,
+ 14,13,13,17,15,15,12,12,17,14,14,12,12,16,15,15,
+ 12,12,17,15,15,13,13,17,14,14,13,13,17,15,15,12,
+ 12,17,14,14,12,12,16,15,15,12,12,14,14,14, 8, 8,
+ 14,14,14,18,18,14,15,15,19,18,14,14,14,18,18,14,
+ 14,14,18,19,15,16,15,19,19,15,17,16,20,20,15,15,
+ 15,19,19,15,16,16,19,19,15,15,15,19,19,15,16,15,
+ 18,19,15,16,16,20,20,15,15,15,19,19,15,16,16,19,
+ 20,15,15,15,19,19,15,15,16,19,19,15,16,16,20,20,
+ 15,15,15,19,19,15,15,15,19,20,15,15,15,19,19,15,
+ 15,15,19,19,15,16,16,20,20,15,15,15,19,20,15,16,
+ 16,20,20,15,15,15,19,19,13,12,12, 8, 8,14,14,14,
+ 19,20,14,14,14,19,19,14,14,14,18,19,14,14,14,19,
+ 20,15,15,15,19,20,15,14,14,21,20,15,15,15,20,20,
+ 15,15,14,19,19,15,15,15,19,19,15,15,15,19,19,15,
+ 14,14,19,20,15,15,15,19,20,15,14,14,19,19,15,15,
+ 15,19,19,15,15,15,19,19,16,14,14,19,19,15,15,15,
+ 20,20,15,14,14,21,19,15,15,15,19,19,15,15,15,19,
+ 20,16,14,14,19,20,15,15,15,19,19,15,14,14,19,19,
+ 15,15,15,20,19,
+};
+
+static const static_codebook _44p1_p3_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p1_p3_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p1_p3_1,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p1_p4_0[] = {
+ 2, 6, 6,14,14, 6, 7, 7,14,14, 7, 7, 7,14,14, 0,
+ 13,13,16,16, 0,13,13,15,14, 7, 8, 8,15,15, 9,10,
+ 10,16,16, 9, 8, 8,15,15, 0,13,13,17,16, 0,13,13,
+ 15,16, 8, 8, 8,15,15,12,11,11,16,16, 9, 8, 8,14,
+ 14, 0,13,13,17,18, 0,13,13,15,15, 0,14,14,16,16,
+ 0, 0, 0,19,18, 0,12,12,16,15, 0,15,16, 0,20, 0,
+ 14,14,16,16, 0,14,14,17,17, 0, 0, 0,19,18, 0,12,
+ 12,15,15, 0,17,17, 0,20, 0,14,14,16,16, 5, 6, 7,
+ 12,12, 9, 9, 9,14,14,10,10,10,14,14, 0,21,21,18,
+ 17, 0,20,20,18,17, 9,10,10,14,14,12,12,12,16,16,
+ 12,10,10,14,14, 0,20,19,18,17, 0, 0,20,17,18,11,
+ 10,10,14,14,14,13,13,18,18,13,11,11,14,14, 0,20,
+ 20,17,18, 0,21,21,17,17, 0,21, 0,18,18, 0, 0, 0,
+ 0, 0, 0,20,19,16,17, 0, 0, 0,19,19, 0, 0, 0,18,
+ 18, 0,21,21,18,18, 0, 0, 0, 0, 0, 0,20,20,16,17,
+ 0, 0, 0,21,21, 0, 0, 0,18,19, 6, 6, 6,13,12, 8,
+ 6, 6,11,11, 8, 6, 6,13,13, 0, 9, 9,11,11, 0,11,
+ 10,14,14, 9, 7, 7,13,13,11, 9, 9,13,13,10, 6, 6,
+ 13,13, 0,10,10,14,15, 0,10,10,13,13, 9, 7, 7,13,
+ 13,13,10, 9,13,13,10, 6, 6,13,13, 0,10,10,15,14,
+ 0,10,10,13,13, 0,11,11,15,15, 0,19,20,17,17, 0,
+ 9, 9,13,13, 0,13,13,20,20, 0,11,11,13,13, 0,11,
+ 11,15,15, 0,19,19,17,17, 0,10,10,13,13, 0,15,15,
+ 20,20, 0,12,12,13,13, 0,10,10,12,12, 0,11,11,15,
+ 15, 0,11,11,15,15, 0,15,15,20, 0, 0,16,16, 0,21,
+ 0,11,11,15,15, 0,14,14,18,17, 0,11,11,15,15, 0,
+ 15,16,19,20, 0,16,16,21,21, 0,12,12,15,15, 0,15,
+ 14,18,18, 0,11,11,16,16, 0,15,15,21,21, 0,16,15,
+ 0, 0, 0,16,16,21, 0, 0, 0, 0, 0, 0, 0,14,14,20,
+ 20, 0,18,18, 0, 0, 0,16,17,21, 0, 0,16,16,21,21,
+ 0, 0, 0, 0, 0, 0,15,15,21,21, 0,20,19, 0,21, 0,
+ 17,17, 0, 0, 0,10,10,12,11, 0,10,10,10,11, 0,11,
+ 11,12,12, 0,11,11, 9, 9, 0,13,13,11,12, 0,11,11,
+ 12,12, 0,13,13,12,12, 0,10,10,12,12, 0,12,12,13,
+ 13, 0,12,12,12,12, 0,11,11,12,12, 0,13,13,12,12,
+ 0,10,10,12,12, 0,13,13,14,14, 0,12,12,12,12, 0,
+ 14,14,14,13, 0,19,20,15,15, 0,12,11,12,12, 0,15,
+ 15,21,20, 0,13,13,11,11, 0,13,13,13,13, 0,19, 0,
+ 15,15, 0,12,12,12,12, 0,17,16,19, 0, 0,13,13,12,
+ 12, 7, 7, 7,16,16,11, 9, 9,15,15,12, 9, 9,16,16,
+ 0,13,13,15,14, 0,14,14,17,16,10, 9, 9,16,16,14,
+ 11,11,17,16,12, 9, 8,15,15, 0,13,13,18,18, 0,13,
+ 13,15,15,12,10,10,18,17,15,12,12,17,17,14, 9, 9,
+ 16,16, 0,13,13,18,19, 0,14,13,17,16, 0,14,14,18,
+ 18, 0, 0, 0,20,21, 0,12,12,16,16, 0,16,16,20,21,
+ 0,14,14,17,16, 0,14,14,18,19, 0, 0, 0,19,21, 0,
+ 13,13,17,17, 0,17,17, 0,21, 0,15,15,16,16, 8, 7,
+ 7,14,14,11,10,10,15,15,12,10,10,15,15, 0,20,20,
+ 18,18, 0, 0, 0,17,17,11,10,10,16,16,14,12,12,18,
+ 17,14,11,11,15,15, 0,20,21,18,18, 0, 0,19,18,17,
+ 12,10,10,16,16,17,14,14,19,19,14,11,11,15,15, 0,
+ 21,21,19,19, 0,21,20,19,18, 0,21, 0,18,19, 0, 0,
+ 0, 0, 0, 0,20,20,18,17, 0,21, 0, 0, 0, 0, 0, 0,
+ 19,18, 0, 0, 0,18,19, 0, 0, 0, 0, 0, 0, 0,21,17,
+ 18, 0, 0, 0, 0,21, 0, 0,21,18,19,11, 9, 9,14,14,
+ 13,10,10,13,13,13,11,11,15,15, 0,13,13,12,12, 0,
+ 15,15,16,16,13,10,10,15,15,16,12,12,15,15,15,10,
+ 10,15,15, 0,14,13,16,15, 0,14,13,15,15,13,10,10,
+ 15,15,18,14,14,15,15,15,10,10,14,15, 0,14,14,16,
+ 16, 0,14,14,16,15, 0,15,15,17,16, 0,21, 0,18,18,
+ 0,12,13,15,15, 0,16,16, 0, 0, 0,14,14,15,15, 0,
+ 15,15,16,16, 0,21,20,18,18, 0,13,13,15,15, 0,19,
+ 18, 0, 0, 0,15,15,15,15, 0,11,11,13,13, 0,12,12,
+ 16,16, 0,12,12,16,16, 0,15,16,20, 0, 0,16,17, 0,
+ 0, 0,12,12,16,16, 0,14,14,18,18, 0,11,11,16,17,
+ 0,15,15,20, 0, 0,16,16, 0, 0, 0,12,12,16,16, 0,
+ 15,15,19,19, 0,11,11,17,17, 0,16,16,21, 0, 0,16,
+ 16, 0, 0, 0,17,17,20,20, 0, 0, 0, 0, 0, 0,15,15,
+ 20, 0, 0,17,18, 0, 0, 0,17,17, 0, 0, 0,16,16, 0,
+ 21, 0, 0, 0, 0, 0, 0,15,15,21, 0, 0,19,18, 0, 0,
+ 0,18,17, 0, 0, 0,11,11,14,14, 0,11,11,15,15, 0,
+ 12,12,16,16, 0,13,13,14,14, 0,14,14,17,17, 0,12,
+ 12,16,16, 0,14,14,16,16, 0,11,11,16,15, 0,13,13,
+ 16,17, 0,13,13,16,16, 0,12,12,15,16, 0,15,14,16,
+ 16, 0,11,11,15,15, 0,14,14,17,17, 0,13,13,16,16,
+ 0,15,14,18,18, 0,21, 0,19,19, 0,13,13,15,15, 0,
+ 16,16,20,20, 0,14,14,16,15, 0,14,14,17,17, 0,21,
+ 0,20,18, 0,13,13,15,15, 0,17,17, 0, 0, 0,14,14,
+ 16,15, 8, 8, 8,16,16,12, 9, 9,16,16,13, 9, 9,16,
+ 16, 0,14,14,18,17, 0,14,14,16,17,12,10,10,18,17,
+ 14,11,11,18,18,14, 9, 9,16,16, 0,13,13,18,18, 0,
+ 13,13,17,16,12, 9, 9,16,17,17,13,13,16,16,14, 9,
+ 9,15,15, 0,14,14,20,20, 0,13,13,15,15, 0,15,14,
+ 18,18, 0, 0, 0,20,21, 0,12,13,16,17, 0,16,16,20,
+ 21, 0,14,14,16,17, 0,14,14,18,17, 0, 0, 0,20,21,
+ 0,13,13,16,16, 0,19,17, 0,21, 0,14,15,16,16, 8,
+ 7, 7,14,13,12,10,10,15,15,13,10,10,15,15, 0,21,
+ 21,18,19, 0,20,21,18,18,12,10,10,16,15,15,12,12,
+ 17,17,14,11,11,15,15, 0,21,21,19,18, 0, 0,21,17,
+ 18,13,11,11,15,15,16,13,13,18,19,15,11,11,15,14,
+ 0,21, 0,19,19, 0, 0,21,18,18, 0, 0,21,19,19, 0,
+ 0, 0, 0, 0, 0,20,19,17,17, 0, 0, 0,21, 0, 0,21,
+ 0,18,19, 0, 0,20,20,19, 0, 0, 0, 0, 0, 0,21,20,
+ 18,17, 0, 0, 0, 0,20, 0, 0, 0,18,19, 0,10,10,15,
+ 14, 0,11,11,14,14, 0,11,11,15,16, 0,14,14,15,15,
+ 0,15,15,16,16, 0,11,11,16,16, 0,14,13,16,16, 0,
+ 11,11,15,15, 0,14,14,16,16, 0,14,14,15,15, 0,11,
+ 11,15,15, 0,13,13,15,15, 0,11,11,15,15, 0,15,15,
+ 18,17, 0,14,14,15,15, 0,15,16,18,18, 0, 0, 0,20,
+ 20, 0,14,13,16,15, 0,17,17,21, 0, 0,15,15,15,15,
+ 0,16,15,17,17, 0, 0, 0,19,19, 0,13,13,15,15, 0,
+ 20,19, 0, 0, 0,15,15,15,15, 0,11,11,13,13, 0,12,
+ 12,16,16, 0,12,12,16,16, 0,15,15,21,21, 0,17,16,
+ 0, 0, 0,12,12,16,16, 0,14,14,17,17, 0,11,11,16,
+ 16, 0,15,15, 0, 0, 0,16,16,21, 0, 0,12,12,17,16,
+ 0,14,15,20,20, 0,11,11,16,16, 0,15,15, 0,20, 0,
+ 16,16, 0,21, 0,16,17,21, 0, 0, 0, 0, 0, 0, 0,15,
+ 15, 0,21, 0,18,18, 0, 0, 0,17,16, 0, 0, 0,17,17,
+ 21, 0, 0, 0, 0, 0, 0, 0,15,15, 0,20, 0,19,20,21,
+ 0, 0,17,18, 0, 0, 0,12,12,15,15, 0,12,12,15,15,
+ 0,12,12,16,16, 0,13,13,15,15, 0,15,15,17,17, 0,
+ 13,12,17,16, 0,14,14,17,16, 0,11,11,16,16, 0,14,
+ 14,17,17, 0,14,14,17,17, 0,12,12,16,16, 0,15,15,
+ 17,17, 0,11,11,16,16, 0,14,14,17,17, 0,14,14,16,
+ 16, 0,15,15,18,17, 0, 0, 0,19, 0, 0,13,13,16,16,
+ 0,16,16, 0,21, 0,14,14,16,16, 0,15,15,18,17, 0,
+ 0, 0,19,19, 0,13,13,16,16, 0,18,17, 0,21, 0,14,
+ 15,16,16, 0,11,11,16,16, 0,13,13,17,17, 0,13,13,
+ 17,17, 0,16,16,16,17, 0,16,16,18,18, 0,12,12,17,
+ 17, 0,16,15,18,17, 0,12,12,16,16, 0,16,15,19,19,
+ 0,16,15,17,17, 0,12,12,17,18, 0,16,16,18,18, 0,
+ 12,12,16,16, 0,16,16,19,19, 0,15,16,17,17, 0,15,
+ 16,18,18, 0, 0, 0,20,20, 0,13,13,16,16, 0,18,18,
+ 21,20, 0,15,15,16,16, 0,16,16,19,18, 0, 0, 0,19,
+ 20, 0,14,14,17,17, 0,19,19, 0,21, 0,15,16,16,16,
+ 0, 9, 9,14,14, 0,13,13,15,15, 0,14,14,15,15, 0,
+ 0,21,19,19, 0, 0,21,18,18, 0,12,12,15,15, 0,15,
+ 15,18,18, 0,14,13,15,15, 0,21,21,18,19, 0,21,20,
+ 18,18, 0,13,13,16,16, 0,17,17,18,19, 0,14,14,15,
+ 15, 0, 0,21,19,19, 0,21,20,18,19, 0,20,20,19,19,
+ 0, 0, 0, 0, 0, 0,19,20,17,17, 0, 0, 0,21,21, 0,
+ 21, 0,18,20, 0,21, 0,18,21, 0, 0, 0, 0, 0, 0,21,
+ 21,19,18, 0, 0, 0, 0, 0, 0, 0, 0,19,19, 0,18,18,
+ 15,15, 0,18,20,17,16, 0,20, 0,17,17, 0,21, 0,17,
+ 17, 0,21,20,19,20, 0,19,19,16,16, 0,21,21,17,18,
+ 0,19,19,17,17, 0,20,21,21,21, 0,20,20,18,18, 0,
+ 19,19,16,16, 0, 0,21,18,19, 0,18,19,16,17, 0,21,
+ 21,19,20, 0,21,19,18,18, 0,21,20,19,21, 0, 0, 0,
+ 20,21, 0,19,19,17,16, 0, 0, 0, 0, 0, 0,21,20,17,
+ 17, 0,20,21,19,18, 0, 0, 0, 0,21, 0,19,18,16,17,
+ 0, 0, 0, 0, 0, 0,20,20,17,17, 0,11,11,14,14, 0,
+ 13,13,16,16, 0,13,13,16,16, 0,17,17,21, 0, 0,17,
+ 18, 0, 0, 0,12,12,16,16, 0,15,15,17,18, 0,12,12,
+ 16,16, 0,16,16, 0,20, 0,17,17, 0,21, 0,12,12,17,
+ 17, 0,16,16,19,20, 0,12,12,17,17, 0,17,17, 0,20,
+ 0,17,17, 0, 0, 0,17,17,21, 0, 0, 0, 0, 0, 0, 0,
+ 15,15, 0,20, 0,19,19, 0, 0, 0,18,18, 0, 0, 0,17,
+ 17, 0, 0, 0, 0, 0, 0, 0, 0,15,15, 0, 0, 0,20,19,
+ 0, 0, 0,19,18, 0, 0, 0,14,14,21,19, 0,16,16,20,
+ 21, 0,16,16,20,20, 0,17,17,20, 0, 0,17,17,20,20,
+ 0,15,15,20,20, 0,19,18,20, 0, 0,15,15,20,20, 0,
+ 17,18,21,20, 0,17,17,20,21, 0,15,15,19,19, 0,19,
+ 18,21,21, 0,15,15,19,20, 0,17,18, 0, 0, 0,17,17,
+ 20,20, 0,17,18,20,21, 0, 0, 0, 0, 0, 0,15,15,20,
+ 20, 0,19,19, 0, 0, 0,17,17,19,21, 0,17,17, 0,21,
+ 0, 0, 0, 0,21, 0,15,15,20,19, 0, 0,20, 0, 0, 0,
+ 17,17,21,20, 0,12,12,16,16, 0,14,14,17,17, 0,13,
+ 13,17,17, 0,16,16,17,18, 0,17,16,18,18, 0,13,13,
+ 18,17, 0,15,16,19,18, 0,13,13,16,16, 0,16,16,19,
+ 19, 0,16,16,17,17, 0,13,12,17,17, 0,16,16,18,17,
+ 0,12,12,16,16, 0,17,17,19,18, 0,16,15,16,16, 0,
+ 16,17,18,19, 0, 0, 0,20,20, 0,14,14,17,16, 0,18,
+ 18,21, 0, 0,16,16,16,16, 0,16,16,18,17, 0, 0,21,
+ 21,21, 0,14,14,16,16, 0,21,20,21, 0, 0,16,16,16,
+ 16, 0,10,10,14,14, 0,14,14,15,16, 0,14,14,15,15,
+ 0, 0,21,18,18, 0, 0,21,18,19, 0,13,13,16,16, 0,
+ 16,16,18,17, 0,14,14,15,15, 0,20, 0,18,18, 0,21,
+ 0,18,17, 0,13,13,16,15, 0,17,17,19,19, 0,14,14,
+ 15,15, 0,20,20,18,19, 0, 0, 0,18,17, 0, 0,21,18,
+ 18, 0, 0, 0, 0, 0, 0,20,21,18,17, 0, 0, 0, 0, 0,
+ 0, 0, 0,19,19, 0, 0,21,18,18, 0, 0, 0, 0, 0, 0,
+ 21, 0,18,17, 0, 0, 0, 0,21, 0, 0, 0,19,20, 0,19,
+ 19,16,16, 0, 0,21,18,17, 0,21, 0,18,18, 0,20, 0,
+ 19,18, 0,21,20,19,19, 0,21,19,17,18, 0, 0,21,19,
+ 19, 0,21,19,18,18, 0,21, 0,20,18, 0, 0,21,18,18,
+ 0,20,21,17,17, 0,21, 0,18,18, 0,21,19,17,17, 0,
+ 21, 0, 0,20, 0, 0,20,17,18, 0, 0, 0,19,20, 0, 0,
+ 0,20,19, 0,19,21,17,18, 0,21, 0, 0, 0, 0,21,21,
+ 18,17, 0, 0,21,18,18, 0, 0, 0, 0,21, 0,20,19,16,
+ 17, 0, 0, 0, 0, 0, 0,21,20,17,17, 0,11,11,13,13,
+ 0,13,13,16,16, 0,13,13,16,16, 0,17,17, 0,21, 0,
+ 18,19,21, 0, 0,12,12,16,16, 0,15,15,19,18, 0,13,
+ 13,16,16, 0,16,17,21,19, 0,17,17,21,21, 0,13,13,
+ 16,16, 0,16,16,20,18, 0,13,13,16,16, 0,17,17, 0,
+ 0, 0,18,18, 0, 0, 0,18,17, 0,20, 0, 0, 0, 0, 0,
+ 0,15,15,21,21, 0,19,18, 0, 0, 0,17,17,21,21, 0,
+ 17,17, 0, 0, 0, 0, 0, 0, 0, 0,15,15,20,21, 0,20,
+ 20, 0, 0, 0,19,19, 0, 0, 0,14,15,21,19, 0,16,16,
+ 0,21, 0,17,16,21,21, 0,17,18,21,20, 0,18,18, 0,
+ 21, 0,16,16, 0,20, 0,19,19, 0, 0, 0,16,15, 0,20,
+ 0,18,18, 0, 0, 0,17,17, 0,21, 0,16,16,20,20, 0,
+ 20,19, 0, 0, 0,15,16,21,22, 0,18,18, 0, 0, 0,18,
+ 17, 0, 0, 0,18,18, 0, 0, 0, 0, 0, 0, 0, 0,16,16,
+ 21,20, 0,19,20, 0, 0, 0,18,17,21, 0, 0,17,18, 0,
+ 0, 0, 0, 0, 0, 0, 0,16,16, 0,20, 0, 0,20, 0, 0,
+ 0,18,18,22, 0,
+};
+
+static const static_codebook _44p1_p4_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p1_p4_0,
+ 1, -528744448, 1616642048, 3, 0,
+ (long *)_vq_quantlist__44p1_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p4_1[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44p1_p4_1[] = {
+ 2, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _44p1_p4_1 = {
+ 1, 7,
+ (char *)_vq_lengthlist__44p1_p4_1,
+ 1, -533200896, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p1_p4_1,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p5_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p1_p5_0[] = {
+ 1, 6, 6, 7, 8, 8, 7, 8, 8, 7, 9, 8,10,11,11, 9,
+ 8, 8, 7, 8, 8,11,11,11, 9, 8, 8, 6, 7, 7,10,10,
+ 10,10,10,10,10,10,10,14,13,13,12,11,11,10,10,10,
+ 14,14,13,12,11,11, 6, 6, 6, 8, 5, 5, 8, 7, 7, 9,
+ 7, 7,11,10,10, 9, 7, 7, 9, 7, 7,12,10,10,10, 7,
+ 7, 7, 8, 8,12,11,10,12,10,10,11,10,10,15,13,13,
+ 13,10,10,11,10,10,17,14,13,13,10,10, 7, 7, 7,12,
+ 11,12,12,11,11,12,11,11,16,14,14,13,12,12,12,11,
+ 11,17,15,14,14,12,12,10, 9, 9,13,11,11,13,11,11,
+ 13,11,11,17,14,13,14,11,11,12,11,11,16,15,14,14,
+ 11,11, 7, 8, 8,12,11,11,12,10,10,12,10,10,15,13,
+ 13,14,11,10,12,10,10,16,14,14,14,10,10, 8, 7, 7,
+ 12,11,11,12,11,11,12,11,11,17,14,14,14,12,12,12,
+ 11,11,16,15,15,14,12,12,10,10,10,13,11,11,13,11,
+ 11,13,11,12,16,14,14,14,11,11,13,12,11,16,15,15,
+ 14,11,11,
+};
+
+static const static_codebook _44p1_p5_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p1_p5_0,
+ 1, -527106048, 1620377600, 2, 0,
+ (long *)_vq_quantlist__44p1_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p5_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p1_p5_1[] = {
+ 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 8, 8, 8,
+ 7, 7, 8, 8, 8, 9, 8, 8, 9, 7, 7, 6, 6, 6, 9, 8,
+ 7, 9, 7, 7, 9, 8, 8,10, 8, 8,10, 8, 8,10, 8, 8,
+ 10, 8, 8,10, 8, 8, 7, 6, 6, 9, 6, 6, 9, 7, 7, 9,
+ 7, 7,10, 8, 8, 9, 6, 6, 9, 7, 7,10, 8, 8, 9, 7,
+ 7, 7, 8, 8,11, 9, 9,11, 9, 9,11, 8, 9,12, 9, 9,
+ 12, 8, 8,11, 9, 9,12, 9, 9,12, 8, 8, 8, 7, 7,10,
+ 9, 9,10,10, 9,10, 9, 9,11,10,10,11, 9, 9,11, 9,
+ 9,11,10,11,11, 9, 9,10, 8, 8,11, 9, 9,10, 9, 9,
+ 11, 9, 9,11,10,10,11, 9, 9,11, 9, 9,11,10,10,11,
+ 9, 9, 9, 8, 8,11, 9, 9,12, 9, 9,11, 9, 9,12, 9,
+ 9,12, 8, 8,12, 9, 9,12, 9, 9,12, 8, 8, 9, 7, 7,
+ 11, 9, 9,11,10,10,11, 9, 9,11,11,11,11, 9, 9,11,
+ 10,10,11,11,11,11, 9, 9,10, 9, 9,11, 9, 9,11,10,
+ 10,11, 9, 9,11,10,10,11, 9, 9,11, 9,10,11,10,10,
+ 11, 9, 9,
+};
+
+static const static_codebook _44p1_p5_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p1_p5_1,
+ 1, -530841600, 1616642048, 2, 0,
+ (long *)_vq_quantlist__44p1_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p1_p6_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p1_p6_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p1_p6_0,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p1_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p6_1[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p1_p6_1[] = {
+ 1, 3, 2, 5, 4, 7, 7, 8, 8, 9, 9,10,10,11,11,12,
+ 12,13,13,13,14,16,16,16,16,
+};
+
+static const static_codebook _44p1_p6_1 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p1_p6_1,
+ 1, -518864896, 1620639744, 5, 0,
+ (long *)_vq_quantlist__44p1_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44p1_p6_2[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p1_p6_2[] = {
+ 3, 4, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p1_p6_2 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p1_p6_2,
+ 1, -529006592, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44p1_p6_2,
+ 0
+};
+
+static const char _huff_lengthlist__44p1_short[] = {
+ 4, 5, 7, 8,10,13,14, 4, 2, 4, 6, 8,11,12, 7, 4,
+ 3, 5, 8,12,14, 8, 5, 4, 4, 8,12,12, 9, 7, 7, 7,
+ 9,10,11,13,11,11, 9, 7, 8,10,13,11,10, 6, 5, 7,
+ 9,
+};
+
+static const static_codebook _huff_book__44p1_short = {
+ 2, 49,
+ (char *)_huff_lengthlist__44p1_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p2_l0_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44p2_l0_0[] = {
+ 1, 4, 4, 7, 7, 8, 8, 9, 9,10,10,11,11, 4, 6, 5,
+ 8, 7, 9, 8,10, 9,11,10,11,11, 4, 5, 6, 7, 8, 8,
+ 9, 9,10,10,10,10,11, 8, 9, 8,10, 8,10, 9,11,10,
+ 11,11,11,11, 8, 8, 9, 8,10, 9,10,10,11,11,11,11,
+ 11, 9,10,10,11,11,11,11,11,11,12,11,12,11, 9,10,
+ 10,10,11,11,11,11,11,11,12,11,12,10,11,11,12,11,
+ 12,12,12,12,12,12,12,12,10,11,11,11,11,12,12,12,
+ 13,12,12,12,12,11,12,12,12,12,13,13,12,12,12,12,
+ 12,12,11,12,12,12,12,13,13,12,13,12,12,12,12,12,
+ 13,13,13,13,13,13,12,13,12,13,12,12,12,13,13,13,
+ 13,13,13,13,12,13,12,12,12,
+};
+
+static const static_codebook _44p2_l0_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44p2_l0_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44p2_l0_0,
+ 0
+};
+
+static const long _vq_quantlist__44p2_l0_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p2_l0_1[] = {
+ 2, 4, 4, 5, 5, 4, 5, 5, 6, 5, 4, 5, 5, 5, 6, 5,
+ 5, 6, 6, 6, 5, 6, 5, 6, 6,
+};
+
+static const static_codebook _44p2_l0_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p2_l0_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p2_l0_1,
+ 0
+};
+
+static const long _vq_quantlist__44p2_l1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p2_l1_0[] = {
+ 1, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+
+static const static_codebook _44p2_l1_0 = {
+ 2, 9,
+ (char *)_vq_lengthlist__44p2_l1_0,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p2_l1_0,
+ 0
+};
+
+static const char _huff_lengthlist__44p2_lfe[] = {
+ 1, 3, 2, 3,
+};
+
+static const static_codebook _huff_book__44p2_lfe = {
+ 2, 4,
+ (char *)_huff_lengthlist__44p2_lfe,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44p2_long[] = {
+ 3, 4, 9, 8, 8,10,13,16, 4, 2, 9, 5, 7,10,14,18,
+ 9, 7, 6, 5, 7, 9,12,16, 7, 5, 5, 3, 5, 8,11,13,
+ 8, 7, 7, 5, 5, 7, 9,11,10,10, 9, 8, 6, 6, 8,10,
+ 13,14,13,11, 9, 8, 9,10,17,18,16,14,11,10,10,10,
+};
+
+static const static_codebook _huff_book__44p2_long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p2_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p2_p1_0[] = {
+ 1, 2, 2, 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, 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,
+};
+
+static const static_codebook _44p2_p1_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p2_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p2_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p2_p2_0[] = {
+ 1, 4, 4, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0,
+ 10,10, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 0, 0, 0, 0, 0,
+ 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0,
+ 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0, 0,
+ 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0,11,11, 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, 7, 7,
+ 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, 7, 7, 0, 0, 0,
+ 6, 6, 0, 0, 0, 7, 7, 0, 0, 0, 8, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7,
+ 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0,
+ 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0,
+ 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 8, 0, 0, 0, 9, 9, 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, 8, 8, 0, 0, 0, 8, 8, 0,
+ 0, 0,10,10, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0,
+ 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,
+ 11,11, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 9, 0, 0, 0,11,10, 0, 0, 0, 0, 0,
+ 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0,
+ 0, 0,11,11, 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, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 8, 8, 0, 0, 0,10,10, 0, 0, 0,11,11, 0, 0,
+ 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0,
+ 0, 0, 0, 0, 0,10,10, 0, 0, 0,13,13, 0, 0, 0, 0,
+ 0, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12,12,
+ 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,13,13, 0,
+ 0, 0, 0, 0, 0, 0, 0,12,12, 0, 0, 0,13,13, 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, 6,
+ 6, 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, 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, 9, 9, 0, 0, 0,11,11,
+ 0, 0, 0,12,12, 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0,
+ 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12,11, 0, 0,
+ 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,13,13, 0, 0, 0,
+ 0, 0, 0, 0, 0,12,12, 0, 0, 0,13,13, 0, 0, 0, 0,
+ 0, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12,12,
+ 0, 0, 0,13,13, 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, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 8, 8, 0, 0, 0,10,10, 0, 0, 0,11,11, 0,
+ 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,13,13, 0, 0,
+ 0, 0, 0, 0, 0, 0,12,12, 0, 0, 0,13,13, 0, 0, 0,
+ 0, 0, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0,10,
+ 10, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,14,13,
+ 0, 0, 0, 0, 0, 0, 0, 0,13,12, 0, 0, 0,13,13, 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,
+ 6, 6, 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, 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, 9, 9, 0, 0, 0,11,
+ 11, 0, 0, 0,12,12, 0, 0, 0,12,12, 0, 0, 0, 0, 0,
+ 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,12,12, 0,
+ 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,13,13, 0, 0,
+ 0, 0, 0, 0, 0, 0,12,12, 0, 0, 0,12,12, 0, 0, 0,
+ 0, 0, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12,
+ 12, 0, 0, 0,13,13, 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, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 0, 0, 0,12,12,
+ 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,12,12, 0,
+ 0, 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0,14,14, 0, 0,
+ 0, 0, 0, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,
+ 12,12, 0, 0, 0,12,13, 0, 0, 0, 0, 0, 0, 0, 0,12,
+ 12, 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0,14,13,
+ 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, 7, 7, 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, 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, 9, 9, 0, 0, 0,
+ 11,11, 0, 0, 0,12,12, 0, 0, 0,13,13, 0, 0, 0, 0,
+ 0, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12,12,
+ 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12,12, 0,
+ 0, 0, 0, 0, 0, 0, 0,12,12, 0, 0, 0,14,14, 0, 0,
+ 0, 0, 0, 0, 0, 0,14,14, 0, 0, 0, 0, 0, 0, 0, 0,
+ 12,12, 0, 0, 0,13,13, 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, 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, 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, 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, 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,
+ 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,
+};
+
+static const static_codebook _44p2_p2_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p2_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p2_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p3_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p2_p3_0[] = {
+ 1, 5, 5, 6, 7, 7, 0, 8, 8, 6, 9, 9, 8,11,11, 0,
+ 8, 8, 0, 9, 9, 0,12,12, 0, 8, 8, 5, 7, 7, 7,10,
+ 10, 0,12,12, 8,11,11, 9,12,12, 0,11,12, 0,12,12,
+ 0,15,15, 0,12,12, 0, 6, 6, 0, 6, 6, 0, 7, 7, 0,
+ 7, 7, 0,10,10, 0, 7, 7, 0, 8, 8, 0,11,11, 0, 7,
+ 7, 6, 7, 7,10, 9, 9, 0,11,10,10, 9, 9,12,12,12,
+ 0,10,10, 0,11,11, 0,13,13, 0,11,11, 7, 6, 6,10,
+ 10,10, 0,11,11,11,11,11,12,12,12, 0,11,11, 0,12,
+ 12, 0,15,15, 0,11,11, 0,11,11, 0,11,11, 0,12,12,
+ 0,12,12, 0,14,14, 0,12,12, 0,12,12, 0,15,15, 0,
+ 11,11, 0, 8, 8, 0,10,10, 0,11,11, 0,11,11, 0,12,
+ 12, 0,12,12, 0,11,11, 0,15,15, 0,11,11, 0, 6, 6,
+ 0,10,10, 0,12,12, 0,10,10, 0,13,13, 0,12,12, 0,
+ 13,13, 0,14,14, 0,12,12, 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,
+};
+
+static const static_codebook _44p2_p3_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p2_p3_0,
+ 1, -533200896, 1614282752, 2, 0,
+ (long *)_vq_quantlist__44p2_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p3_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p2_p3_1[] = {
+ 2, 3, 3, 0, 8, 8, 0, 8, 8, 0, 9, 9, 0, 9, 9, 0,
+ 9, 9, 0, 9, 9, 0, 9, 9, 0, 8, 8, 0, 6, 6, 0, 7,
+ 7, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0, 8, 8, 0, 8, 8,
+ 0, 8, 8, 0, 8, 8, 0, 6, 6, 0, 6, 6, 0, 6, 6, 0,
+ 8, 8, 0, 9, 9, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0, 6,
+ 6, 0, 8, 8, 0, 9, 9, 0, 9, 9, 0,10,10, 0,10,10,
+ 0,10,10, 0,10,10, 0,11,11, 0, 9, 9, 0, 7, 7, 0,
+ 10,10, 0,10,10, 0,12,11, 0,12,12, 0,11,11, 0,11,
+ 11, 0,12,12, 0,10,10, 0, 7, 7, 0,10,10, 0,10,10,
+ 0,12,12, 0,11,12, 0,11,11, 0,11,11, 0,11,11, 0,
+ 10,10, 0, 8, 8, 0, 9, 9, 0, 9, 9, 0,10,10, 0,10,
+ 10, 0,10, 9, 0,10,10, 0,10,10, 0, 9, 9, 0, 6, 6,
+ 0,10,10, 0,10,10, 0,11,11, 0,12,12, 0,11,11, 0,
+ 11,11, 0,12,12, 0,11,11, 0, 7, 7, 0, 9, 9, 0, 9,
+ 9, 0,11,11, 0,11,11, 0,10,10, 0,10,10, 0,11,11,
+ 0, 9, 9,
+};
+
+static const static_codebook _44p2_p3_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p2_p3_1,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p2_p3_1,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p4_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p2_p4_0[] = {
+ 1, 6, 6, 6, 7, 7, 7, 8, 8, 7, 8, 8,10,11,11, 9,
+ 8, 8, 7, 8, 8,11,11,11, 9, 8, 8, 6, 7, 7, 9,11,
+ 11, 9,11,11,10,11,11,12,13,13,11,12,12,10,11,11,
+ 13,14,14,12,12,12, 6, 6, 6, 8, 6, 6, 8, 7, 7, 9,
+ 7, 7,11,10,10,10, 6, 6, 9, 7, 7,12,10,10,11, 6,
+ 7, 7, 7, 7,11,10,10,12,10,10,11,10,10,14,13,13,
+ 13,10,10,12,11,11,15,13,13,14,10,10, 8, 7, 7,12,
+ 11,11,12,11,11,11,11,11,14,14,14,13,12,12,12,11,
+ 11,15,15,15,13,12,12, 0,10,10, 0,11,11, 0,11,11,
+ 0,11,11, 0,14,14, 0,11,11, 0,11,11, 0,15,15, 0,
+ 11,11, 7, 8, 8,12,10,10,12,10,10,12,11,11,15,13,
+ 13,14,11,11,12,10,10,16,14,14,14,10,10, 8, 7, 7,
+ 12,11,11,12,11,11,12,11,11,16,14,14,14,12,12,13,
+ 12,12,15,14,14,15,12,12, 0,11,11, 0,12,12, 0,12,
+ 12, 0,12,12, 0,15,15, 0,12,12, 0,12,12, 0,14,14,
+ 0,12,12,
+};
+
+static const static_codebook _44p2_p4_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p2_p4_0,
+ 1, -531365888, 1616117760, 2, 0,
+ (long *)_vq_quantlist__44p2_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p4_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p2_p4_1[] = {
+ 3, 4, 4, 8, 8,11, 9, 9,12,12,11,10,10,12,12,12,
+ 10,10,11,11,12,12,12,12,12,12,11,11,13,13,12,12,
+ 12,13,13,12,10,10,12,12,12,11,11,13,13,12,13,13,
+ 13,13,12,11,11,13,13,12,12,12,13,13,12,10,10,12,
+ 12,12,11,11,13,13,12,13,13,12,12,12,11,11,13,13,
+ 12,13,13,13,13,12,11,11,12,12,12,11,11,12,12,12,
+ 13,13,12,12,12,13,13,13,13,12,13,13,13,13,13,13,
+ 13,12,12,12,13,13,13,13,12,13,13,12,12,11, 8, 8,
+ 10,10,12,11,11,11,11,12,10,10,10,10,13,11,11,10,
+ 10,13,11,11,10,10,13,12,12,12,12,13,11,11,11,11,
+ 13,12,12,11,11,13,12,12,11,11,13,12,12,12,11,13,
+ 12,12,12,12,13,11,11,11,11,13,12,12,11,11,13,11,
+ 12,11,11,13,12,12,11,11,14,12,12,11,11,13,11,11,
+ 11,11,14,12,12,11,11,13,11,12,10,10,14,12,12,11,
+ 11,14,12,12,11,11,14,11,11,11,11,14,12,12,11,11,
+ 13,12,12,11,11,14,12,12,11,11,11, 8, 8,10,10,12,
+ 7, 7,10,10,12, 9, 9,11,11,13, 9, 9, 9, 9,13,13,
+ 13,10,10,13, 9, 9,12,12,13,13,13,12,12,13, 9, 8,
+ 11,11,13,10,10,12,12,14,13,13,11,11,13, 9, 9,11,
+ 11,13,13,13,12,12,13, 9, 9,10,10,13,10,10,11,11,
+ 13,13,13,10,10,14,10,10,11,11,14,14,14,12,12,13,
+ 9, 9,10,10,13,10,10,11,11,14,13,14,10,10,14,14,
+ 14,11,12,14,14,14,14,14,14,13,13,10,10,13,14,14,
+ 11,11,14,14,14,10,10,14, 9, 9, 9, 9,14, 9, 9, 9,
+ 9,14,10,10, 9, 9,14,10,10, 8, 8,14,11,11, 8, 8,
+ 15,11,11,10,10,15,12,12,10,10,15,10,10,10,10,15,
+ 11,11,10,10,15,13,13,10,10,15,11,11,10,10,15,12,
+ 12,10,10,15,10,10,10,10,15,11,11,10,10,15,13,13,
+ 10,10,15,11,11,10,10,15,12,12,10,10,15,11,11, 9,
+ 9,15,11,11, 9, 9,15,13,13, 9, 9,15,13,13,10,10,
+ 15,12,12,10,10,15,13,13,10,10,15,13,12, 9, 9,15,
+ 13,13, 9, 9,14,12,12, 9, 9,14,13,13, 9, 9,14,13,
+ 13, 9, 9,14,13,13, 7, 7,14,13,13, 8, 8,15,14,14,
+ 10,10,15,14,14,10,10,15,14,14,10,10,15,14,14,10,
+ 10,15,14,14, 9, 9,15,14,14,10,10,15,14,14,10,10,
+ 14,14,14, 9, 9,15,14,14,10,10,14,14,14, 9, 9,15,
+ 14,14,10,10,15,14,14,10,10,14,14,14, 9, 9,14,14,
+ 14, 9, 9,14,14,14, 8, 8,15,14,14,10,10,15,14,14,
+ 11,11,15,14,14, 9, 9,15,14,14, 9, 9,14,14,14, 8,
+ 8,13, 9, 9,12,12,17,11,11,12,12,17,12,12,12,12,
+ 17,12,12,11,11,18,15,15,12,12,17,12,12,12,12,17,
+ 14,15,13,13,17,12,12,12,12,17,13,13,12,13,17,15,
+ 15,12,12,18,13,13,13,13,18,15,15,13,13,18,12,12,
+ 12,12,18,13,13,13,13,18,15,15,12,12,18,13,13,12,
+ 12,18,15,15,13,13,18,13,13,12,12,17,13,13,12,12,
+ 17,15,15,12,12,18,15,15,13,13,18,15,15,13,14,18,
+ 15,16,12,12,18,15,15,12,12,18,16,16,12,12,13, 8,
+ 8,10,10,14,15,14,11,11,14,15,15,12,12,15,14,14,
+ 12,11,15,15,15,12,12,15,15,15,12,12,15,15,15,13,
+ 13,15,15,15,12,12,15,15,15,13,13,15,15,15,13,13,
+ 15,15,15,13,13,15,15,16,13,13,15,15,15,12,12,15,
+ 15,15,13,13,15,15,15,13,13,15,15,15,13,13,15,15,
+ 15,13,13,15,15,14,12,12,15,15,15,12,12,16,15,14,
+ 12,12,16,15,15,13,13,16,16,16,13,13,16,15,15,12,
+ 12,15,15,15,13,13,15,15,15,12,12,13,12,12,10,10,
+ 14,14,14,11,11,15,14,14,12,12,15,14,14,11,11,15,
+ 14,14,11,11,15,15,15,13,13,15,14,14,13,13,15,15,
+ 15,12,12,15,14,15,13,13,16,15,15,12,12,15,15,15,
+ 13,13,16,14,14,13,13,15,15,15,12,12,15,15,15,13,
+ 13,16,15,15,12,12,16,15,15,12,12,16,14,14,13,13,
+ 15,15,15,11,11,15,15,15,12,12,16,15,15,11,11,16,
+ 15,15,13,13,16,14,15,14,14,16,15,15,12,12,16,15,
+ 14,12,12,16,15,15,12,12,14,10,10, 9, 9,14,11,11,
+ 12,12,14,12,12,13,13,14,12,12,12,12,15,14,14,13,
+ 13,15,13,13,14,14,15,14,14,15,15,15,12,12,13,13,
+ 15,13,13,14,14,15,14,14,13,13,15,13,13,13,14,15,
+ 14,14,15,15,15,12,12,13,13,15,13,13,14,14,15,14,
+ 14,13,13,15,13,13,14,14,15,14,14,15,15,15,13,13,
+ 12,12,15,13,13,13,13,15,14,14,13,12,15,15,15,14,
+ 15,15,15,14,20,20,15,14,14,13,13,15,14,14,13,13,
+ 15,14,14,13,13,14,12,12, 9, 9,14,14,14,12,12,14,
+ 13,13,12,13,14,14,14,12,12,15,14,14,12,12,15,14,
+ 14,14,13,15,14,14,14,14,15,14,14,13,13,15,14,14,
+ 13,13,15,15,15,14,14,15,14,14,13,13,15,14,14,14,
+ 14,15,14,14,13,13,15,14,14,13,13,15,15,15,15,14,
+ 15,15,15,13,13,15,14,14,14,14,15,14,14,13,13,15,
+ 14,14,13,13,14,15,15,14,14,15,15,15,14,14,15,14,
+ 14,14,14,15,15,15,14,14,15,14,14,13,14,15,15,15,
+ 14,14,13,10,10,12,12,17,11,11,12,12,17,12,12,12,
+ 12,17,12,12,11,11,17,15,15,12,11,18,13,13,13,13,
+ 18,15,15,13,13,17,12,12,12,12,18,13,13,13,13,17,
+ 15,15,12,12,17,12,12,12,12,17,15,15,13,13,17,12,
+ 12,12,12,17,13,13,12,12,17,15,15,12,12,18,14,13,
+ 12,12,18,15,15,13,13,18,13,13,12,12,18,13,13,12,
+ 12,18,16,16,12,12,18,16,16,12,12,18,15,15,13,13,
+ 18,16,16,12,12,17,15,15,12,12,17,16,16,12,12,13,
+ 8, 8,10,10,14,14,15,12,12,14,15,15,12,12,15,14,
+ 14,12,12,15,15,14,12,12,15,15,15,13,13,15,15,15,
+ 13,13,15,15,15,12,12,16,15,15,13,13,16,15,15,13,
+ 13,15,15,15,12,12,15,15,15,14,14,15,15,15,12,12,
+ 15,15,15,13,13,16,15,15,13,13,15,15,15,13,13,16,
+ 15,15,13,13,15,15,14,12,12,15,15,15,12,12,16,14,
+ 15,13,13,16,15,15,13,13,15,16,15,13,13,16,15,14,
+ 13,13,16,15,15,13,13,16,15,15,13,13,13,12,12,11,
+ 11,14,14,14,11,11,14,14,14,12,12,15,14,14,11,11,
+ 16,14,14,11,11,15,15,15,12,13,16,14,14,13,13,15,
+ 15,15,12,12,15,14,14,13,13,16,15,15,12,12,15,15,
+ 15,12,12,15,14,14,13,13,15,15,15,12,12,15,14,14,
+ 12,12,16,15,15,12,12,16,15,15,12,12,16,14,14,13,
+ 13,15,15,15,11,11,15,15,14,12,12,16,15,15,11,11,
+ 16,15,15,12,12,16,14,14,13,13,16,15,15,11,11,16,
+ 14,14,12,12,16,15,15,11,11,14,10,10, 9, 9,14,11,
+ 11,12,12,14,12,12,13,14,14,12,12,12,12,14,14,14,
+ 13,13,15,13,13,14,14,15,14,14,15,15,15,12,12,13,
+ 13,15,13,13,14,14,15,15,15,14,14,15,13,13,14,14,
+ 15,15,15,15,15,15,12,12,13,13,15,13,13,14,14,15,
+ 14,14,13,13,15,13,13,14,14,15,14,14,15,15,15,12,
+ 12,13,13,15,13,13,13,13,14,14,14,13,13,15,15,15,
+ 14,15,15,15,15,21,19,15,14,14,13,13,15,14,14,14,
+ 14,14,14,14,13,13,14,12,12, 9, 9,14,14,14,12,12,
+ 14,14,13,13,13,14,14,14,12,12,14,14,14,12,12,15,
+ 14,14,13,13,15,14,14,14,14,15,14,14,13,13,15,14,
+ 14,13,13,15,15,15,15,15,15,14,14,13,13,15,14,14,
+ 14,14,15,14,14,13,13,15,14,14,13,13,14,15,15,15,
+ 15,15,14,15,13,13,15,14,14,14,14,15,14,14,13,13,
+ 15,14,14,13,13,14,15,15,14,14,15,15,15,14,14,15,
+ 14,14,14,14,15,15,15,15,15,15,14,14,14,13,14,15,
+ 15,14,14,13,10,10,12,12,18,12,12,12,12,17,12,12,
+ 12,12,18,13,13,11,11,18,15,14,11,11,17,13,13,13,
+ 13,18,15,15,12,12,18,12,12,12,12,17,13,13,12,12,
+ 18,15,15,12,12,18,13,13,13,12,18,15,15,13,13,18,
+ 13,13,12,12,18,13,13,12,12,18,15,15,12,12,17,13,
+ 13,12,12,17,15,15,12,12,17,12,12,11,11,17,13,13,
+ 11,11,17,15,15,11,11,18,16,16,12,12,18,15,15,13,
+ 13,18,15,15,11,11,17,15,15,12,12,18,15,15,11,11,
+ 13, 8, 8,10,10,14,14,14,11,11,15,15,15,12,12,15,
+ 14,14,11,11,16,14,14,12,12,15,15,15,12,12,15,15,
+ 15,13,13,15,15,15,12,12,15,15,15,12,12,16,15,15,
+ 13,13,15,15,15,12,12,15,15,15,13,13,16,15,15,12,
+ 12,15,15,15,12,12,16,15,15,13,13,16,15,15,12,12,
+ 15,15,15,13,13,15,14,14,12,12,15,15,15,12,12,16,
+ 15,14,12,12,16,15,15,13,13,16,16,16,13,13,16,14,
+ 15,13,13,15,15,15,13,13,16,15,15,12,12,13,12,12,
+ 10,10,14,14,14,11,11,15,14,14,12,12,15,14,14,11,
+ 11,16,14,14,11,11,15,14,15,12,12,15,14,14,13,13,
+ 15,15,15,12,12,15,14,14,12,12,15,14,15,12,12,15,
+ 15,15,12,12,16,14,14,13,13,15,15,15,11,12,16,14,
+ 14,12,12,16,15,15,12,12,15,15,15,12,12,16,14,14,
+ 12,12,15,15,15,11,11,15,14,14,11,12,15,15,14,11,
+ 11,16,15,15,12,12,16,14,14,13,13,16,15,15,11,11,
+ 16,14,14,12,12,16,15,15,11,11,13,10,10, 8, 8,14,
+ 12,12,12,12,14,12,12,13,13,14,12,12,12,12,14,14,
+ 14,13,13,15,13,13,14,14,15,15,14,15,15,15,13,13,
+ 13,13,15,13,13,14,14,15,14,15,14,14,15,13,13,13,
+ 13,15,15,15,15,15,15,12,12,13,12,15,13,13,14,14,
+ 15,14,14,13,13,15,13,13,14,13,15,15,15,16,16,15,
+ 13,13,12,12,15,13,13,13,13,14,14,14,12,12,15,15,
+ 15,14,14,15,15,15,20,20,15,14,14,13,13,15,15,14,
+ 14,14,15,14,14,13,13,13,12,12, 9, 9,14,13,13,12,
+ 12,14,13,13,12,12,14,14,14,12,12,14,14,14,13,13,
+ 15,14,14,13,13,15,14,14,14,14,15,15,14,12,12,15,
+ 14,14,13,13,15,14,15,14,15,15,14,14,13,13,15,14,
+ 14,14,14,15,14,14,12,12,15,14,14,13,13,14,15,14,
+ 15,14,15,14,14,13,13,15,14,14,14,14,15,14,14,12,
+ 12,15,14,14,13,13,15,15,15,14,14,15,15,15,14,14,
+ 16,14,14,14,14,15,15,15,14,14,15,14,14,14,14,14,
+ 15,15,14,14,13,13,13,12,13,17,15,15,12,12,17,15,
+ 15,12,12,18,15,15,11,11,17,16,16,11,11,18,16,16,
+ 13,13,18,17,16,13,13,18,16,16,12,12,18,16,16,12,
+ 12,18,17,17,12,12,17,16,16,12,13,17,16,16,12,13,
+ 17,16,16,12,12,17,16,16,12,12,18,17,16,12,12,18,
+ 16,16,12,12,17,16,17,12,12,18,15,15,11,11,18,15,
+ 15,12,12,17,17,17,11,11,17,17,17,12,12,17,16,16,
+ 13,13,18,16,16,11,11,18,16,16,12,12,18,17,16,11,
+ 11,14,14,14,10,10,16,15,14,11,11,16,15,15,12,12,
+ 16,14,14,12,12,17,14,14,13,13,17,15,15,13,13,17,
+ 15,15,14,14,16,15,15,12,12,16,15,15,13,13,18,15,
+ 15,14,14,16,15,15,12,12,16,15,15,14,14,16,15,15,
+ 12,12,16,15,15,13,13,17,15,15,13,13,17,15,15,13,
+ 13,17,15,15,14,14,16,14,14,12,12,17,15,15,12,12,
+ 18,15,15,13,13,17,15,15,14,14,17,16,16,15,15,17,
+ 15,14,13,13,17,15,15,14,14,17,15,15,13,13,14,12,
+ 12,11,11,15,14,14,12,12,16,14,14,12,12,16,14,14,
+ 11,11,17,14,14,12,12,16,15,14,13,13,16,14,14,13,
+ 13,16,15,15,12,12,16,14,14,13,13,17,15,15,13,13,
+ 16,15,15,13,13,17,14,14,13,13,16,15,15,12,12,16,
+ 14,14,12,12,16,15,15,12,12,17,15,15,12,12,17,14,
+ 14,13,13,16,15,15,12,12,16,14,14,12,12,16,15,15,
+ 12,12,17,15,15,13,13,17,14,14,13,13,17,15,15,12,
+ 12,17,14,14,12,12,17,15,15,12,12,14,14,14, 8, 8,
+ 14,14,14,13,13,14,15,15,14,14,14,14,14,14,14,15,
+ 15,15,19,19,15,15,15,14,14,15,15,16,20,19,15,15,
+ 15,14,14,15,16,16,15,15,15,15,15,19,19,15,15,15,
+ 14,14,15,16,16,19,20,15,15,15,14,14,15,15,15,15,
+ 15,15,15,15,19,19,15,15,15,15,15,15,15,16,19,20,
+ 15,14,15,14,14,15,15,15,15,15,15,15,15,20,19,15,
+ 15,15,21,19,15,16,16,20,20,15,15,14,19,19,15,15,
+ 16,20,21,15,15,15,20,19,13,12,12, 9, 9,14,14,14,
+ 12,12,14,13,13,13,13,14,14,14,13,13,15,14,14,20,
+ 19,15,14,14,14,13,15,14,14,19,19,15,15,14,13,13,
+ 15,14,14,14,14,15,15,15,19,20,15,14,14,13,13,15,
+ 14,14,20,19,14,15,14,13,13,15,14,14,14,13,15,15,
+ 15,19,20,15,15,14,14,14,15,14,14,21,19,15,15,15,
+ 13,13,15,14,14,14,14,14,15,15,20,20,15,15,15,21,
+ 20,15,14,14,19,20,15,15,15,20,20,15,14,14,19,20,
+ 15,15,15,21,19,
+};
+
+static const static_codebook _44p2_p4_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p2_p4_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p2_p4_1,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p5_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p2_p5_0[] = {
+ 2, 6, 6,14,14, 6, 7, 7,14,14, 7, 7, 7,15,15, 0,
+ 13,13,16,16, 0,13,13,15,15, 7, 8, 8,15,15, 9,10,
+ 10,17,16, 9, 8, 8,15,15, 0,13,13,18,17, 0,13,13,
+ 16,16, 8, 8, 8,15,15,12,11,11,16,17, 9, 8, 8,14,
+ 14, 0,13,13,18,17, 0,13,13,16,15, 0,14,14,18,17,
+ 0,20,22,18,20, 0,12,12,16,16, 0,16,16,22,20, 0,
+ 14,14,16,16, 0,14,14,17,17, 0,22,22,22,19, 0,12,
+ 13,16,16, 0,17,17, 0, 0, 0,15,15,16,16, 5, 7, 7,
+ 13,13, 9, 9, 9,15,14,10,10,10,14,14, 0,21,21,18,
+ 17, 0,21,22,18,17, 9,10,10,14,14,12,12,12,17,17,
+ 12,10,10,14,14, 0,19,21,18,17, 0,20,22,18,18,11,
+ 10,10,14,14,14,13,13,18,17,12,11,11,14,14, 0,22,
+ 19,17,18, 0,20, 0,18,17, 0,22,21,17,17, 0, 0, 0,
+ 0, 0, 0,20,22,17,17, 0,22, 0,21,19, 0,22, 0,18,
+ 18, 0, 0,22,18,19, 0, 0, 0, 0, 0, 0,19,21,17,17,
+ 0, 0, 0,20,20, 0, 0, 0,18,18, 6, 6, 6,13,12, 8,
+ 6, 6,11,11, 8, 6, 6,13,13, 0, 9, 9,11,11, 0,11,
+ 11,14,14, 9, 7, 7,13,13,11, 9, 9,13,13,10, 6, 6,
+ 13,13, 0,10,10,14,14, 0,10,10,13,13, 9, 7, 7,13,
+ 14,13, 9, 9,13,13,10, 6, 6,13,12, 0,11,11,15,15,
+ 0,10,10,13,13, 0,12,12,15,15, 0,19, 0,17,17, 0,
+ 9, 9,13,13, 0,13,14,19,20, 0,11,11,13,13, 0,11,
+ 11,14,14, 0,19,20,17,18, 0,10,10,13,13, 0,15,15,
+ 21,19, 0,12,12,13,13, 0,10,10,12,13, 0,11,11,15,
+ 15, 0,11,11,15,15, 0,15,15,22, 0, 0,16,17,22, 0,
+ 0,11,11,15,15, 0,14,14,18,17, 0,11,11,15,16, 0,
+ 15,15,22,21, 0,16,16, 0,20, 0,12,12,16,15, 0,15,
+ 14,19,19, 0,11,11,16,16, 0,15,15,21, 0, 0,16,15,
+ 0, 0, 0,16,16,22,21, 0, 0, 0, 0, 0, 0,15,15,20,
+ 20, 0,18,18, 0, 0, 0,16,17, 0, 0, 0,17,17, 0,22,
+ 0, 0, 0, 0, 0, 0,15,15,21,22, 0,20,18, 0, 0, 0,
+ 18,17,22, 0, 0,10,10,12,11, 0,10,10,10,10, 0,11,
+ 11,12,12, 0,11,11, 9, 9, 0,13,13,12,12, 0,11,11,
+ 12,12, 0,13,13,12,12, 0,10,10,12,12, 0,13,12,13,
+ 13, 0,12,12,12,12, 0,11,11,12,12, 0,13,13,12,12,
+ 0,10,10,12,12, 0,13,13,13,14, 0,12,12,12,12, 0,
+ 13,14,14,14, 0,20,21,15,15, 0,12,11,12,12, 0,15,
+ 16,20,22, 0,13,12,11,11, 0,13,13,14,13, 0,20, 0,
+ 16,15, 0,12,12,12,12, 0,16,16,22,21, 0,13,13,12,
+ 12, 6, 7, 7,16,16,11, 9, 9,15,15,12, 9, 9,16,16,
+ 0,13,13,14,14, 0,14,14,16,17,10, 9, 9,16,16,14,
+ 12,12,16,16,12, 9, 9,15,15, 0,13,13,18,18, 0,13,
+ 13,15,16,12,10,10,17,18,15,12,12,17,17,13, 9, 9,
+ 16,16, 0,13,13,17,18, 0,14,14,16,16, 0,15,15,18,
+ 18, 0,22, 0,20,20, 0,12,12,16,16, 0,16,16,20,22,
+ 0,14,14,16,16, 0,15,14,18,18, 0, 0,22,19,21, 0,
+ 13,13,16,17, 0,17,17,22,22, 0,15,15,16,16, 7, 7,
+ 7,14,14,11,10,10,15,15,12,10,10,15,14, 0,22, 0,
+ 18,18, 0, 0,21,17,18,11,10,10,15,15,14,12,12,17,
+ 17,14,11,11,15,15, 0,22,20,18,18, 0, 0,20,18,17,
+ 12,10,10,16,16,17,14,14,19,18,14,11,11,15,15, 0,
+ 21,22,19,19, 0,21,22,18,18, 0,22, 0,19,21, 0, 0,
+ 0, 0, 0, 0,22,22,18,17, 0, 0, 0,21,20, 0,22,22,
+ 20,19, 0, 0,22,20,20, 0, 0, 0, 0, 0, 0,20,21,17,
+ 17, 0, 0,22,21,21, 0, 0, 0,18,18,10, 9, 9,14,14,
+ 13,10,10,13,13,13,10,11,14,14, 0,13,13,12,12, 0,
+ 15,15,16,16,13,10,10,15,15,15,12,12,14,14,15,10,
+ 10,14,15, 0,14,14,16,15, 0,14,14,15,15,13,10,10,
+ 15,15,18,13,13,15,15,15,10,10,14,15, 0,14,14,16,
+ 16, 0,14,14,15,15, 0,15,15,16,16, 0,22, 0,18,18,
+ 0,12,13,14,14, 0,17,17,22, 0, 0,14,14,14,14, 0,
+ 15,15,16,16, 0,22, 0,18,17, 0,13,13,14,14, 0,19,
+ 18,21,22, 0,15,15,14,14, 0,11,11,13,13, 0,12,12,
+ 16,16, 0,12,12,16,16, 0,15,16,21, 0, 0,16,17, 0,
+ 22, 0,12,12,16,16, 0,14,14,17,18, 0,11,11,16,16,
+ 0,15,15,21,22, 0,16,16, 0, 0, 0,12,12,16,16, 0,
+ 15,15, 0,19, 0,12,12,16,17, 0,16,16,22, 0, 0,16,
+ 16, 0,22, 0,17,17, 0,22, 0, 0, 0, 0, 0, 0,15,15,
+ 20,19, 0,18,18, 0, 0, 0,17,18, 0, 0, 0,17,17, 0,
+ 0, 0, 0, 0, 0, 0, 0,15,15, 0,22, 0,20,18, 0, 0,
+ 0,18,18,22,22, 0,11,11,14,14, 0,12,12,14,14, 0,
+ 12,12,15,15, 0,13,13,14,14, 0,14,14,17,16, 0,12,
+ 12,16,16, 0,14,14,16,16, 0,11,11,15,15, 0,13,13,
+ 16,16, 0,13,13,15,15, 0,12,12,15,15, 0,15,14,16,
+ 16, 0,11,11,15,15, 0,14,14,17,17, 0,13,13,15,15,
+ 0,15,15,17,17, 0, 0, 0,19,18, 0,13,12,15,15, 0,
+ 16,16, 0, 0, 0,14,14,15,15, 0,14,14,16,17, 0,22,
+ 0,18,18, 0,13,13,15,15, 0,17,17, 0, 0, 0,14,14,
+ 15,15, 8, 8, 8,16,16,12,10,10,16,16,13, 9, 9,16,
+ 16, 0,14,14,17,17, 0,14,14,17,16,12,10,10,18,17,
+ 14,11,11,18,18,14, 9,10,16,16, 0,13,13,18,19, 0,
+ 14,13,16,16,12, 9, 9,16,16,17,13,13,17,17,14, 9,
+ 9,15,15, 0,14,14,19,20, 0,13,13,15,15, 0,15,15,
+ 18,19, 0, 0,22,22,22, 0,13,13,17,17, 0,16,16,19,
+ 21, 0,14,14,16,16, 0,14,14,18,18, 0, 0, 0, 0, 0,
+ 0,13,13,16,16, 0,18,18, 0, 0, 0,15,15,16,16, 8,
+ 7, 7,14,14,12,10,10,15,15,13,10,10,15,14, 0,22,
+ 0,18,18, 0,22, 0,18,18,12,10,10,16,15,15,12,12,
+ 17,17,14,11,11,15,15, 0,20,21,19,18, 0, 0, 0,17,
+ 18,13,11,11,15,15,16,13,13,18,18,15,11,11,14,14,
+ 0,22,21,19,19, 0,21,22,18,18, 0,22,22,20,18, 0,
+ 0, 0, 0, 0, 0,22,19,17,17, 0, 0, 0,22,21, 0, 0,
+ 22,19,17, 0, 0,22,19,19, 0, 0, 0, 0, 0, 0,22,21,
+ 18,17, 0, 0, 0,22, 0, 0, 0, 0,19,19, 0,10,10,14,
+ 14, 0,11,11,15,14, 0,11,11,15,15, 0,14,14,15,14,
+ 0,15,15,16,16, 0,11,11,16,16, 0,13,13,16,16, 0,
+ 11,11,15,15, 0,14,14,17,16, 0,14,14,15,15, 0,11,
+ 11,16,16, 0,14,13,15,15, 0,11,11,15,15, 0,15,15,
+ 17,17, 0,14,14,15,14, 0,16,16,17,17, 0, 0,22,18,
+ 18, 0,13,13,15,15, 0,17,17,22, 0, 0,15,15,15,14,
+ 0,15,16,16,17, 0, 0,22,18,19, 0,13,13,15,15, 0,
+ 20,18,21, 0, 0,15,15,14,14, 0,11,11,13,13, 0,12,
+ 12,16,16, 0,12,12,16,15, 0,15,16,22,22, 0,17,17,
+ 0, 0, 0,12,12,16,16, 0,14,14,18,18, 0,11,11,16,
+ 16, 0,15,16,22,20, 0,16,16, 0,22, 0,12,12,16,16,
+ 0,15,15,18,20, 0,11,11,16,16, 0,15,15, 0, 0, 0,
+ 16,16, 0, 0, 0,17,17,22, 0, 0, 0, 0, 0, 0, 0,15,
+ 15, 0,21, 0,18,18, 0, 0, 0,17,16, 0, 0, 0,17,17,
+ 22,22, 0, 0, 0, 0, 0, 0,15,15,21, 0, 0,20,22, 0,
+ 0, 0,18,18, 0, 0, 0,12,12,15,15, 0,12,12,15,15,
+ 0,12,12,16,16, 0,13,13,15,15, 0,15,15,17,17, 0,
+ 13,12,16,16, 0,14,14,16,16, 0,12,11,16,16, 0,14,
+ 14,17,17, 0,14,14,16,16, 0,12,12,16,16, 0,15,15,
+ 17,16, 0,11,11,15,16, 0,14,14,17,17, 0,14,14,16,
+ 16, 0,15,15,18,18, 0, 0, 0,22,19, 0,13,13,15,16,
+ 0,16,17, 0, 0, 0,14,14,16,16, 0,15,15,18,17, 0,
+ 0, 0,20,20, 0,13,13,16,15, 0,17,17,22,22, 0,14,
+ 14,15,15, 0,11,11,16,16, 0,13,13,16,17, 0,13,13,
+ 17,18, 0,16,16,17,17, 0,17,17,18,18, 0,12,12,17,
+ 17, 0,16,15,18,18, 0,12,12,16,16, 0,16,16,18,18,
+ 0,15,15,17,17, 0,12,12,17,17, 0,16,16,19,18, 0,
+ 12,12,16,17, 0,16,16,19,19, 0,15,16,16,17, 0,16,
+ 16,19,17, 0, 0, 0,20,22, 0,13,13,16,16, 0,19,18,
+ 21, 0, 0,15,15,16,16, 0,16,16,18,18, 0, 0, 0,22,
+ 21, 0,14,14,16,16, 0,21,19,21,22, 0,16,16,16,16,
+ 0, 9, 9,14,14, 0,13,13,15,15, 0,14,14,15,15, 0,
+ 0,20,18,19, 0, 0,22,18,18, 0,12,12,15,15, 0,15,
+ 15,17,18, 0,14,13,14,14, 0,20, 0,18,18, 0,21, 0,
+ 18,17, 0,13,13,15,16, 0,17,17,18,18, 0,14,14,15,
+ 15, 0,22,22,20,19, 0,20,21,18,18, 0,20,22,19,19,
+ 0, 0, 0, 0, 0, 0,20,20,17,17, 0, 0,22,22,21, 0,
+ 22, 0,18,18, 0,20,22,19,19, 0, 0, 0, 0, 0, 0,21,
+ 21,17,18, 0, 0, 0,21,20, 0, 0,22,19,18, 0,18,18,
+ 15,15, 0,22,21,17,16, 0, 0,22,17,17, 0,20,22,18,
+ 18, 0, 0,22,20,20, 0,21,19,16,16, 0,21,21,18,18,
+ 0,19,19,17,17, 0, 0,22,19,19, 0,22,20,17,17, 0,
+ 21,19,16,16, 0,22,22,19,18, 0,19,20,16,16, 0,22,
+ 21,19,21, 0,21,22,17,18, 0,21,20,18,18, 0, 0, 0,
+ 19,20, 0,20,19,16,16, 0,22,22, 0, 0, 0,21,21,17,
+ 16, 0,22,20,19,18, 0, 0, 0,20,20, 0,20,19,16,16,
+ 0, 0, 0, 0, 0, 0,21,22,17,17, 0,11,11,13,13, 0,
+ 13,13,15,16, 0,13,13,16,16, 0,17,18,21, 0, 0,17,
+ 18, 0, 0, 0,12,12,15,16, 0,15,15,19,18, 0,12,12,
+ 16,16, 0,17,17,22, 0, 0,17,17, 0,22, 0,12,12,17,
+ 16, 0,16,16,19,20, 0,12,12,16,16, 0,17,17, 0, 0,
+ 0,17,17, 0,21, 0,17,16,22, 0, 0, 0, 0, 0, 0, 0,
+ 15,15,20,22, 0,20,18, 0, 0, 0,18,18, 0, 0, 0,17,
+ 17,21, 0, 0, 0, 0, 0, 0, 0,15,15,21,22, 0,19,20,
+ 22, 0, 0,19,18, 0, 0, 0,14,14,18,18, 0,16,16,22,
+ 20, 0,16,16,22,19, 0,17,17,20,22, 0,19,19, 0, 0,
+ 0,15,15,20, 0, 0,18,21, 0,20, 0,15,15,21,20, 0,
+ 18,17, 0, 0, 0,17,17, 0,22, 0,15,15,19,19, 0,19,
+ 18, 0, 0, 0,15,15,20, 0, 0,18,18,22,22, 0,17,17,
+ 0,20, 0,18,18, 0, 0, 0, 0,22, 0, 0, 0,15,15,19,
+ 20, 0,20,19, 0, 0, 0,17,17,20,21, 0,17,18,20,22,
+ 0, 0, 0, 0,22, 0,15,15,20,20, 0,22,20, 0, 0, 0,
+ 17,18,20, 0, 0,12,12,17,16, 0,14,14,17,17, 0,13,
+ 13,17,17, 0,16,16,18,18, 0,17,16,17,17, 0,13,13,
+ 17,17, 0,15,16,18,18, 0,13,13,16,16, 0,16,16,18,
+ 18, 0,16,16,17,16, 0,13,13,16,16, 0,17,17,18,17,
+ 0,12,12,15,16, 0,17,17,19,19, 0,16,16,16,16, 0,
+ 16,17,19,18, 0, 0, 0,21,22, 0,14,14,16,16, 0,18,
+ 18, 0,22, 0,16,16,16,16, 0,16,16,18,17, 0, 0, 0,
+ 21,20, 0,14,14,16,16, 0,21,22,22, 0, 0,16,16,16,
+ 16, 0, 9, 9,14,13, 0,13,14,15,16, 0,14,13,15,14,
+ 0,22, 0,18,18, 0,21, 0,17,18, 0,13,13,15,15, 0,
+ 15,16,18,17, 0,14,14,15,14, 0,20,22,18,18, 0,22,
+ 21,17,17, 0,13,13,15,15, 0,17,17,19,19, 0,14,14,
+ 14,14, 0, 0,22,18,18, 0, 0,22,17,17, 0, 0,22,19,
+ 20, 0, 0, 0, 0, 0, 0,21,20,17,16, 0, 0, 0,21,22,
+ 0, 0, 0,18,19, 0, 0, 0,18,18, 0, 0, 0, 0, 0, 0,
+ 22, 0,17,17, 0, 0, 0,20,22, 0, 0, 0,18,19, 0,18,
+ 19,16,16, 0,22,20,17,17, 0,22,22,17,18, 0,22,22,
+ 18,17, 0, 0,22,18,19, 0,20,20,17,18, 0, 0,22,19,
+ 18, 0,22,22,17,17, 0,22, 0,19,19, 0, 0,22,18,18,
+ 0,20,22,17,17, 0, 0,22,18,18, 0,19,20,17,17, 0,
+ 22, 0,20,19, 0,22,21,17,17, 0, 0, 0,18,18, 0, 0,
+ 0,22,19, 0,20, 0,17,17, 0,22, 0, 0,22, 0, 0,20,
+ 17,18, 0,22, 0,19,19, 0, 0, 0, 0,19, 0,19,21,17,
+ 17, 0, 0, 0, 0, 0, 0,20,21,17,16, 0,11,11,13,13,
+ 0,13,13,16,16, 0,13,13,15,16, 0,17,17,21,22, 0,
+ 17,18, 0, 0, 0,12,12,16,16, 0,15,15,18,18, 0,13,
+ 13,16,16, 0,17,16,21,21, 0,17,17, 0, 0, 0,13,13,
+ 16,16, 0,16,16,19,18, 0,13,13,16,16, 0,17,17, 0,
+ 22, 0,17,18,20,22, 0,17,18, 0, 0, 0, 0, 0, 0, 0,
+ 0,15,15,20, 0, 0,18,19, 0, 0, 0,17,17, 0, 0, 0,
+ 18,17,22, 0, 0, 0, 0, 0, 0, 0,15,16,21,20, 0,20,
+ 20, 0, 0, 0,18,19, 0, 0, 0,15,15,22,22, 0,17,16,
+ 20,22, 0,17,17,20,22, 0,18,18, 0,21, 0,19,18, 0,
+ 0, 0,16,16,20,20, 0,19,19,22, 0, 0,15,16,21,22,
+ 0,18,19,22, 0, 0,17,18, 0, 0, 0,16,16,22, 0, 0,
+ 19,19, 0,21, 0,15,16,20, 0, 0,18,18, 0,22, 0,18,
+ 17, 0, 0, 0,18,18, 0, 0, 0, 0, 0, 0, 0, 0,16,16,
+ 22,21, 0,20,21, 0, 0, 0,17,18,22, 0, 0,18,18, 0,
+ 0, 0, 0, 0, 0, 0, 0,16,16,20,19, 0,22,21, 0, 0,
+ 0,18,18,22,22,
+};
+
+static const static_codebook _44p2_p5_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p2_p5_0,
+ 1, -528744448, 1616642048, 3, 0,
+ (long *)_vq_quantlist__44p2_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p5_1[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44p2_p5_1[] = {
+ 2, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _44p2_p5_1 = {
+ 1, 7,
+ (char *)_vq_lengthlist__44p2_p5_1,
+ 1, -533200896, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p2_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p2_p6_0[] = {
+ 1, 7, 7, 7, 8, 8, 7, 8, 8, 7, 9, 9,10,11,11, 9,
+ 8, 8, 7, 8, 9,11,11,11, 9, 8, 8, 6, 7, 7,10,10,
+ 10,10,10,10,10,10,10,14,14,14,12,11,11,10,11,11,
+ 15,14,14,13,11,11, 6, 6, 6, 8, 5, 5, 8, 7, 7, 8,
+ 7, 7,11,10,10, 9, 7, 7, 9, 7, 7,12,10,10,10, 7,
+ 7, 6, 8, 7,12,10,10,12,10,10,11,10,10,15,14,13,
+ 13,10,10,11,10,10,16,14,14,14,10,10, 7, 7, 7,12,
+ 11,11,12,11,11,11,11,11,16,14,14,13,12,12,11,11,
+ 11,17,15,15,14,12,12,10, 9, 9,13,11,11,13,11,11,
+ 12,11,11,16,14,13,14,11,11,12,11,11,17,15,14,14,
+ 11,11, 7, 8, 8,12,11,11,12,10,10,12,10,10,16,13,
+ 14,13,10,10,11,10,10,17,14,14,14,10,10, 7, 7, 7,
+ 12,11,11,12,11,11,12,11,11,15,14,15,14,12,12,12,
+ 11,11,17,15,15,14,12,12,10,10, 9,13,11,11,13,11,
+ 11,13,11,11,16,14,14,14,11,11,13,11,11,16,15,15,
+ 15,11,11,
+};
+
+static const static_codebook _44p2_p6_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p2_p6_0,
+ 1, -527106048, 1620377600, 2, 0,
+ (long *)_vq_quantlist__44p2_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p6_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p2_p6_1[] = {
+ 2, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, 8,
+ 7, 7, 8, 8, 8, 9, 9, 9, 9, 8, 8, 6, 7, 7, 9, 8,
+ 8, 9, 7, 7, 9, 8, 8,10, 8, 8,10, 8, 8,10, 8, 8,
+ 10, 8, 9,10, 8, 8, 7, 6, 6, 8, 6, 6, 9, 6, 6, 9,
+ 7, 7,10, 8, 8, 9, 6, 6, 9, 7, 7,10, 9, 8, 9, 7,
+ 7, 7, 7, 7,11, 8, 8,11, 9, 9,10, 9, 9,12, 9, 9,
+ 12, 8, 8,11, 9, 9,12, 9, 9,12, 8, 8, 8, 7, 7,10,
+ 9, 9,10, 9, 9,10, 9, 9,11,10,11,11, 9, 9,11, 9,
+ 9,11,11,11,11, 9, 9,10, 8, 8,11, 9, 9,10, 9, 9,
+ 11, 9, 9,11,10,10,11, 9, 9,11, 9, 9,12,10,10,11,
+ 9, 9, 8, 8, 8,11, 9, 9,12, 9, 9,11, 9, 9,12, 9,
+ 9,12, 8, 8,12, 9, 9,12, 9,10,12, 8, 8, 9, 7, 7,
+ 11, 9, 9,11,10,10,11, 9, 9,11,11,11,11, 9, 9,11,
+ 10,10,12,11,11,11, 9,10,10, 9, 9,11, 9, 9,11,10,
+ 10,11,10,10,11,11,11,11, 9, 9,11, 9,10,11,11,11,
+ 11, 9, 9,
+};
+
+static const static_codebook _44p2_p6_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p2_p6_1,
+ 1, -530841600, 1616642048, 2, 0,
+ (long *)_vq_quantlist__44p2_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p2_p7_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p2_p7_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p2_p7_0,
+ 1, -513979392, 1633504256, 2, 0,
+ (long *)_vq_quantlist__44p2_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p7_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p2_p7_1[] = {
+ 1, 9, 9, 6, 9, 9, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,
+};
+
+static const static_codebook _44p2_p7_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p2_p7_1,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p2_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p7_2[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p2_p7_2[] = {
+ 1, 3, 2, 5, 4, 7, 7, 8, 8, 9, 9,10,10,11,11,12,
+ 12,13,13,14,14,15,15,15,15,
+};
+
+static const static_codebook _44p2_p7_2 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p2_p7_2,
+ 1, -518864896, 1620639744, 5, 0,
+ (long *)_vq_quantlist__44p2_p7_2,
+ 0
+};
+
+static const long _vq_quantlist__44p2_p7_3[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p2_p7_3[] = {
+ 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p2_p7_3 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p2_p7_3,
+ 1, -529006592, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44p2_p7_3,
+ 0
+};
+
+static const char _huff_lengthlist__44p2_short[] = {
+ 4, 4,12, 9, 8,12,15,17, 4, 2,11, 6, 5, 9,13,15,
+ 11, 7, 8, 7, 7,10,14,13, 8, 5, 7, 5, 5, 8,12,12,
+ 8, 4, 7, 4, 3, 6,11,12,11, 8, 9, 7, 6, 8,11,12,
+ 15,13,14,12, 9, 7,10,13,16,12,17,12, 7, 5, 8,11,
+};
+
+static const static_codebook _huff_book__44p2_short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p2_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p3_l0_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44p3_l0_0[] = {
+ 1, 4, 4, 8, 8, 8, 8, 9, 9,10,10,10,10, 4, 6, 5,
+ 8, 7, 9, 9, 9, 9,10, 9,11, 9, 4, 5, 6, 7, 8, 9,
+ 9, 9, 9, 9,10, 9,10, 8, 9, 8, 9, 8,10, 9,11, 9,
+ 12,10,12,10, 8, 8, 9, 8, 9, 9,10, 9,11,10,12,10,
+ 12, 9,10,10,11,10,12,11,12,11,12,12,12,12, 9,10,
+ 10,11,11,11,11,11,12,12,12,12,12,10,11,11,12,12,
+ 12,12,12,12,12,12,12,12,10,11,11,12,12,12,12,12,
+ 12,12,12,12,12,11,12,12,12,12,12,13,12,13,12,13,
+ 12,12,11,12,12,12,12,12,12,13,12,12,12,12,12,12,
+ 12,12,13,13,12,13,12,13,12,13,12,12,12,13,12,13,
+ 12,13,12,13,12,13,12,12,12,
+};
+
+static const static_codebook _44p3_l0_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44p3_l0_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44p3_l0_0,
+ 0
+};
+
+static const long _vq_quantlist__44p3_l0_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p3_l0_1[] = {
+ 3, 4, 4, 5, 5, 4, 4, 5, 5, 5, 4, 5, 4, 5, 5, 5,
+ 5, 6, 5, 6, 5, 6, 5, 6, 5,
+};
+
+static const static_codebook _44p3_l0_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p3_l0_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p3_l0_1,
+ 0
+};
+
+static const long _vq_quantlist__44p3_l1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p3_l1_0[] = {
+ 1, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+
+static const static_codebook _44p3_l1_0 = {
+ 2, 9,
+ (char *)_vq_lengthlist__44p3_l1_0,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p3_l1_0,
+ 0
+};
+
+static const char _huff_lengthlist__44p3_lfe[] = {
+ 1, 3, 2, 3,
+};
+
+static const static_codebook _huff_book__44p3_lfe = {
+ 2, 4,
+ (char *)_huff_lengthlist__44p3_lfe,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44p3_long[] = {
+ 3, 4,13, 9, 9,12,15,17, 4, 2,18, 5, 7,10,14,18,
+ 11, 8, 6, 5, 6, 8,11,14, 8, 5, 5, 3, 5, 8,11,13,
+ 9, 6, 7, 5, 5, 7, 9,10,11,10, 9, 8, 6, 6, 8,10,
+ 14,14,11,11, 9, 8, 9,10,17,17,14,13,10, 9,10,10,
+};
+
+static const static_codebook _huff_book__44p3_long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p3_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p3_p1_0[] = {
+ 1, 2, 2, 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, 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,
+};
+
+static const static_codebook _44p3_p1_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p3_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p3_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p3_p2_0[] = {
+ 3, 7, 7, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0,
+ 11,11, 0, 0, 0, 0, 0, 0, 0, 0,10, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 9, 0, 0, 0,10,11, 0, 0, 0, 0, 0,
+ 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0,
+ 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0,12,12, 0, 0,
+ 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0,12,12, 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, 7, 7,
+ 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, 7, 7, 0, 0, 0,
+ 5, 5, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5,
+ 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, 7, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 8, 0, 0, 0, 9, 9, 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,11,11, 0, 0, 0, 9, 9, 0,
+ 0, 0,10,10, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0,
+ 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,
+ 10,10, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0,
+ 0, 0, 0,11,12, 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0,
+ 0, 0,12,12, 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, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 9, 9, 0, 0, 0, 7, 7, 0, 0, 0, 8, 8, 0, 0,
+ 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0,
+ 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8,
+ 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 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, 5,
+ 5, 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, 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, 9, 9, 0, 0, 0, 7, 7,
+ 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0,
+ 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0,
+ 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9,
+ 0, 0, 0,10,10, 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, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 9, 9, 0, 0, 0, 7, 7, 0, 0, 0, 8, 8, 0,
+ 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0,
+ 0, 0, 0, 0, 0, 0, 8, 7, 0, 0, 0, 9, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 7,
+ 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,11,11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 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,
+ 5, 5, 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, 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, 9, 9, 0, 0, 0, 7,
+ 7, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0,
+ 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0,
+ 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9,
+ 9, 0, 0, 0,11,11, 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, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,10,10, 0, 0, 0, 9, 9, 0, 0, 0,10,10,
+ 0, 0, 0,11,12, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0,11,11, 0, 0,
+ 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0,
+ 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0,11,
+ 11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,12,12,
+ 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, 7, 7, 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, 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,10,10, 0, 0, 0,
+ 9, 9, 0, 0, 0,10,10, 0, 0, 0,12,12, 0, 0, 0, 0,
+ 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9,
+ 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 0, 0,
+ 0, 0, 0, 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,
+ 10,10, 0, 0, 0,11,11, 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, 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, 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, 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, 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,
+ 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,
+};
+
+static const static_codebook _44p3_p2_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p3_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p3_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p3_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p3_p3_0[] = {
+ 1, 5, 5, 5, 8, 8, 0, 8, 8, 6, 9, 9, 8,10,10, 0,
+ 8, 8, 0, 9, 9, 0,12,12, 0, 8, 8, 4, 7, 7, 6,10,
+ 10, 0,12,12, 7,11,11, 9,12,12, 0,12,12, 0,13,13,
+ 0,15,15, 0,12,12, 0, 7, 7, 0, 7, 7, 0, 8, 8, 0,
+ 8, 8, 0,10,10, 0, 7, 7, 0, 8, 8, 0,11,11, 0, 7,
+ 7, 5, 7, 7, 9, 9, 9, 0,11,10, 9, 9, 9,11,12,12,
+ 0,10,10, 0,11,11, 0,13,13, 0,11,11, 6, 7, 7, 9,
+ 10,10, 0,12,12,10,11,11,11,12,12, 0,12,12, 0,13,
+ 13, 0,15,15, 0,12,12, 0,10,10, 0,11,11, 0,11,11,
+ 0,12,12, 0,13,13, 0,11,11, 0,12,12, 0,15,15, 0,
+ 11,11, 0, 8, 8, 0,10,10, 0,12,12, 0,11,11, 0,12,
+ 12, 0,12,12, 0,12,12, 0,15,15, 0,11,11, 0, 7, 7,
+ 0,10,10, 0,12,12, 0,10,10, 0,12,13, 0,12,12, 0,
+ 13,13, 0,14,14, 0,12,12, 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,
+};
+
+static const static_codebook _44p3_p3_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p3_p3_0,
+ 1, -533200896, 1614282752, 2, 0,
+ (long *)_vq_quantlist__44p3_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p3_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p3_p3_1[] = {
+ 3, 4, 4, 0, 8, 8, 0, 8, 8, 0, 9, 9, 0,10,10, 0,
+ 8, 8, 0, 9, 9, 0,10,10, 0, 8, 8, 0, 7, 7, 0, 8,
+ 8, 0, 8, 8, 0, 8, 8, 0, 8, 8, 0, 8, 8, 0, 8, 8,
+ 0, 8, 8, 0, 8, 8, 0, 7, 7, 0, 6, 6, 0, 7, 7, 0,
+ 7, 7, 0,10,10, 0, 6, 6, 0, 7, 7, 0,10,10, 0, 6,
+ 5, 0, 8, 8, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0, 9, 9,
+ 0, 7, 7, 0, 8, 8, 0, 9, 9, 0, 7, 7, 0, 6, 6, 0,
+ 9,10, 0,10,10, 0,10,10, 0,11,11, 0, 9, 9, 0,10,
+ 10, 0,11,11, 0, 9, 9, 0, 8, 8, 0, 8, 8, 0, 8, 8,
+ 0, 9, 9, 0, 9, 9, 0, 8, 8, 0, 8, 8, 0, 9, 9, 0,
+ 7, 7, 0, 8, 8, 0, 7, 7, 0, 7, 7, 0, 8, 8, 0, 9,
+ 9, 0, 7, 7, 0, 7, 7, 0, 9, 9, 0, 6, 6, 0, 6, 6,
+ 0,10,10, 0,10,10, 0,10,10, 0,12,12, 0, 9, 9, 0,
+ 10,10, 0,12,12, 0, 9, 9, 0, 8, 8, 0, 7, 7, 0, 8,
+ 8, 0, 8, 8, 0, 9, 9, 0, 7, 7, 0, 8, 8, 0, 9, 9,
+ 0, 7, 7,
+};
+
+static const static_codebook _44p3_p3_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p3_p3_1,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p3_p3_1,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p4_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p3_p4_0[] = {
+ 1, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8,10,11,11, 9,
+ 8, 8, 8, 8, 8,11,11,11,10, 8, 8, 5, 7, 7, 9,11,
+ 11,10,11,11,10,11,11,12,13,14,11,12,12,10,11,11,
+ 13,14,14,12,12,12, 5, 6, 6, 8, 6, 6, 8, 7, 7, 8,
+ 7, 7,11,10,10,10, 7, 7, 9, 7, 7,12,11,11,11, 7,
+ 7, 7, 7, 7,11,10,10,12,10,10,11,10,10,15,13,13,
+ 13,10,10,12,11,11,15,13,13,14,11,11, 7, 7, 7,11,
+ 11,11,12,11,11,12,11,11,14,14,14,14,12,12,12,12,
+ 12,16,15,15,14,12,12, 0,10,10, 0,11,11, 0,11,12,
+ 0,11,11, 0,14,14, 0,11,11, 0,12,12, 0,15,15, 0,
+ 11,11, 8, 8, 8,12,10,10,12,10,10,13,11,11,15,13,
+ 13,14,11,11,12,10,10,16,14,14,14,10,10, 8, 7, 7,
+ 12,11,11,13,11,11,12,11,11,15,14,14,14,12,12,13,
+ 12,12,15,14,14,15,12,12, 0,11,11, 0,12,12, 0,12,
+ 12, 0,12,12, 0,15,15, 0,12,12, 0,13,13, 0,14,15,
+ 0,12,12,
+};
+
+static const static_codebook _44p3_p4_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p3_p4_0,
+ 1, -531365888, 1616117760, 2, 0,
+ (long *)_vq_quantlist__44p3_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p4_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p3_p4_1[] = {
+ 3, 4, 5, 8, 8,12,10,10,12,12,12,10,10,12,12,13,
+ 11,11,12,12,13,12,12,12,12,13,10,10,13,13,13,13,
+ 13,13,13,13,10,10,13,13,13,11,11,13,13,14,13,13,
+ 12,12,13,10,10,13,13,13,13,13,13,13,13,10,10,12,
+ 12,13,11,11,13,13,13,13,13,12,12,13,12,12,13,13,
+ 13,13,13,13,13,14,11,11,12,12,14,12,12,13,12,14,
+ 14,14,12,12,13,14,14,13,13,14,13,13,13,13,14,14,
+ 14,12,12,14,13,13,13,13,14,14,14,12,12,12, 8, 8,
+ 11,11,12,12,12,11,11,12,11,11,10,10,13,12,12,10,
+ 10,13,12,12,10,10,13,12,12,12,12,14,12,12,12,12,
+ 13,13,13,11,11,14,12,12,11,11,14,12,12,12,12,14,
+ 12,12,12,12,13,12,12,12,12,13,13,13,11,11,14,12,
+ 12,11,11,14,12,12,12,12,14,13,13,12,12,14,12,12,
+ 12,11,14,13,13,11,11,14,13,12,11,11,14,13,13,11,
+ 11,14,13,13,12,12,14,12,12,12,12,15,13,13,12,12,
+ 14,12,12,11,11,14,13,13,11,11,12, 9, 9,10,10,12,
+ 7, 7,11,11,12, 9, 9,12,12,13,10,10,10,10,14,14,
+ 14,11,11,13, 9, 9,12,12,14,14,14,12,12,13, 8, 8,
+ 11,11,14, 9, 9,12,12,14,14,14,11,11,13, 9, 9,12,
+ 12,14,14,14,12,12,14, 8, 8,11,11,14, 9, 9,12,12,
+ 14,14,14,11,11,14,10,10,12,12,14,14,14,13,13,14,
+ 9, 9,11,11,14,10,10,12,12,14,14,14,11,11,14,14,
+ 15,12,12,15,14,14,14,14,15,14,14,11,11,14,14,14,
+ 12,12,14,14,14,11,11,14,11,11,10,10,14,10,10,10,
+ 10,14,10,10,10,10,15,11,11, 9, 9,14,12,12, 9, 9,
+ 15,11,11,11,11,15,13,13,11,11,15,10,10,10,10,15,
+ 11,11,10,10,15,13,13,11,11,15,11,11,11,11,15,13,
+ 13,11,11,15,10,10,10,10,15,11,11,10,10,15,13,13,
+ 11,11,15,12,12,11,11,15,13,13,11,11,15,11,11,10,
+ 10,15,12,12,10,10,15,13,13,10,10,15,14,14,11,11,
+ 15,13,13,11,11,15,14,14,10,11,15,13,13,10,10,15,
+ 13,14,10,10,14,13,13,10,10,14,13,13,10,10,14,13,
+ 13,10,10,14,13,13, 9, 9,14,14,14, 9, 9,15,14,14,
+ 11,11,15,14,14,10,10,15,14,14,10,10,15,14,14,11,
+ 11,15,14,14,10,10,15,14,14,11,11,15,14,14,10,10,
+ 14,14,14,10,10,15,14,14,10,10,14,14,14,10,10,15,
+ 14,14,11,11,15,14,14,11,11,14,14,14,10,10,15,14,
+ 14,10,10,14,14,14, 9, 9,15,15,15,11,11,15,14,14,
+ 12,12,15,15,14,10,10,15,14,14,10,10,14,15,15, 9,
+ 9,14,10,10,12,12,17, 9, 9,12,12,17,10,10,13,13,
+ 17,11,11,12,12,18,14,14,12,12,17,10,10,13,13,17,
+ 14,14,12,12,17, 9, 9,12,12,17,11,11,12,12,17,14,
+ 14,12,12,18,10,10,13,13,18,14,14,13,13,18, 9, 9,
+ 12,12,18,10,10,13,13,18,14,14,12,12,18,11,11,13,
+ 13,18,14,14,13,13,18,10,10,12,12,17,11,11,12,12,
+ 17,14,14,12,12,18,15,15,13,13,18,14,14,14,14,18,
+ 15,15,12,12,18,14,14,12,12,18,15,15,12,12,13, 7,
+ 7,11,11,14,15,15,11,11,14,15,15,12,12,14,15,15,
+ 11,11,15,15,15,11,11,14,15,15,12,12,14,15,15,12,
+ 12,14,15,15,11,11,14,15,15,11,11,15,15,15,12,12,
+ 14,15,15,12,12,14,15,15,12,12,14,15,15,11,11,14,
+ 15,15,11,11,15,15,15,12,12,15,15,15,12,12,14,15,
+ 15,12,12,14,15,14,12,12,14,15,15,11,11,15,14,14,
+ 12,12,15,15,15,12,12,15,16,16,12,12,15,15,15,12,
+ 12,15,15,15,12,12,15,15,15,12,12,13,13,13,11,10,
+ 14,14,15,11,11,14,14,14,12,12,15,14,14,10,10,15,
+ 15,15,11,11,14,15,15,12,12,14,14,14,11,11,14,15,
+ 15,11,11,14,15,15,12,12,15,15,15,11,11,14,15,15,
+ 12,12,14,14,14,12,12,14,15,15,11,11,14,15,15,12,
+ 12,15,15,15,11,11,15,15,15,12,12,15,14,14,12,12,
+ 14,15,15,11,11,14,15,15,11,11,15,15,15,10,10,15,
+ 15,16,12,12,15,15,15,14,14,15,15,15,11,11,15,15,
+ 15,12,12,15,15,15,11,11,14,11,11,10,10,15, 9, 9,
+ 12,12,15,10,10,12,12,15,11,11,11,11,15,14,14,12,
+ 12,15,10,10,13,13,15,14,14,12,12,15, 9, 9,12,12,
+ 15,10,10,13,13,15,13,13,12,11,15,10,10,12,12,15,
+ 14,14,12,12,15, 9, 9,11,11,15,11,11,12,12,15,13,
+ 13,11,11,15,11,11,13,13,15,13,14,13,14,15,11,11,
+ 11,11,15,11,11,12,12,15,14,14,11,11,15,14,14,13,
+ 13,15,14,14,20,20,15,14,14,12,12,15,14,14,12,12,
+ 15,14,14,11,11,14,13,13,10,10,14,13,13,12,12,14,
+ 14,13,12,12,15,14,14,12,12,15,14,14,11,11,15,14,
+ 14,12,12,15,14,14,13,13,15,14,14,12,11,15,14,14,
+ 11,11,15,14,14,13,13,15,14,14,12,12,15,14,14,13,
+ 13,15,14,14,12,11,15,14,14,12,12,15,14,14,13,13,
+ 15,14,14,13,13,15,14,14,12,12,15,14,14,12,12,15,
+ 14,14,12,12,15,15,15,13,13,15,15,15,13,13,15,14,
+ 14,13,13,15,15,15,13,13,15,14,15,12,12,15,15,15,
+ 13,13,14,10,10,12,13,17, 9, 9,12,12,17,10,10,13,
+ 13,17,11,11,12,12,18,14,14,12,12,18,10,10,13,13,
+ 18,14,14,12,12,17, 9, 9,12,12,18,10,11,13,13,18,
+ 14,14,12,12,17,10,10,12,12,17,14,14,12,12,17, 9,
+ 9,12,12,17,11,11,12,12,17,14,14,12,12,18,11,11,
+ 12,12,18,14,14,13,13,18,11,11,12,12,18,11,11,12,
+ 12,18,14,14,12,12,18,15,15,12,12,18,14,14,13,13,
+ 18,15,15,12,12,17,14,14,12,12,17,15,15,12,12,13,
+ 7, 7,11,11,14,15,15,11,11,14,15,15,11,11,14,15,
+ 14,12,12,15,15,15,12,11,14,15,15,12,12,14,15,15,
+ 12,12,14,15,15,11,11,14,15,15,11,11,15,15,15,13,
+ 13,14,15,15,11,11,14,15,15,13,12,14,15,15,11,11,
+ 14,15,15,11,11,15,15,15,13,13,14,15,15,12,12,15,
+ 15,15,12,12,15,15,15,11,11,15,15,15,11,11,15,15,
+ 15,12,12,15,15,15,13,13,15,16,16,12,12,15,15,15,
+ 12,13,15,15,15,12,12,15,15,15,12,12,13,13,13,11,
+ 11,14,14,14,11,11,14,14,14,12,12,14,14,14,10,10,
+ 15,14,14,11,11,14,15,15,12,12,14,14,14,12,12,14,
+ 15,15,11,11,14,15,14,12,12,15,14,14,11,11,14,15,
+ 15,12,12,14,14,14,11,11,14,15,15,11,11,14,14,14,
+ 12,12,15,15,14,11,11,15,15,15,12,12,15,14,14,12,
+ 12,14,15,15,11,11,14,15,14,11,11,15,15,15,10,10,
+ 15,15,15,12,12,15,14,14,14,13,15,15,15,11,11,15,
+ 15,15,11,11,15,15,15,10,10,14,11,11,10,10,15, 9,
+ 9,12,12,15,10,10,12,12,15,11,11,11,11,15,14,14,
+ 12,12,15,10,10,13,13,15,13,13,12,12,15, 9, 9,12,
+ 12,15,11,11,13,13,15,14,14,12,12,15,10,10,13,13,
+ 15,13,14,12,12,15, 9, 9,12,12,15,10,10,13,13,15,
+ 13,13,11,11,15,11,11,13,13,15,14,14,13,13,15,10,
+ 10,11,11,15,11,11,12,12,15,14,14,11,11,15,14,14,
+ 13,13,15,14,14,21,20,15,14,14,11,11,15,14,14,12,
+ 12,15,14,14,11,11,14,13,13,10,10,14,13,13,11,11,
+ 15,14,14,12,12,15,14,14,12,12,14,14,14,12,12,15,
+ 14,14,12,12,15,14,14,13,13,14,14,14,11,11,15,14,
+ 14,11,11,15,14,14,13,13,15,14,14,12,12,15,14,14,
+ 13,13,14,14,14,11,11,15,14,14,11,11,14,14,14,13,
+ 13,15,14,14,12,12,15,14,14,12,12,15,14,14,12,12,
+ 15,14,14,12,12,14,14,14,13,13,15,15,15,13,13,16,
+ 14,14,12,13,15,15,15,13,13,15,14,14,12,12,15,15,
+ 15,13,13,15,11,11,13,12,18,10,10,12,12,17,11,11,
+ 12,12,18,12,12,11,11,18,14,14,12,12,18,11,11,13,
+ 13,17,14,14,12,12,18,10,10,12,12,18,12,12,12,12,
+ 18,14,15,12,12,18,11,11,13,13,18,14,14,12,12,17,
+ 10,10,12,12,18,11,11,12,12,18,15,14,12,12,17,12,
+ 12,12,12,17,14,14,12,12,17,11,11,11,11,17,12,12,
+ 12,11,17,15,15,11,11,18,15,15,12,12,18,14,15,13,
+ 13,18,15,15,11,11,17,15,15,12,12,18,15,15,11,11,
+ 14, 9, 9,11,11,14,15,15,11,11,15,15,15,11,11,15,
+ 15,15,12,11,15,15,15,12,12,15,15,15,11,11,15,15,
+ 15,13,13,14,15,15,11,11,15,15,15,11,11,15,15,15,
+ 13,13,15,15,15,11,11,15,15,15,13,13,15,15,15,11,
+ 11,15,15,15,11,11,15,15,15,13,13,15,15,15,12,12,
+ 15,15,15,13,13,15,15,14,11,11,15,15,15,12,12,15,
+ 15,15,12,12,16,15,15,13,13,15,16,16,13,13,16,15,
+ 15,12,12,15,15,15,13,12,15,15,15,12,12,13,12,12,
+ 11,11,14,14,14,11,11,14,14,14,12,12,15,14,14,11,
+ 11,15,14,14,12,12,15,14,14,12,12,15,14,14,12,12,
+ 14,15,15,11,11,15,14,14,12,12,15,14,14,11,11,15,
+ 14,14,12,12,15,14,14,12,12,14,15,15,11,11,15,14,
+ 14,12,12,15,14,14,11,11,15,15,15,12,12,15,14,14,
+ 12,12,15,15,15,11,11,15,14,14,11,11,15,14,15,11,
+ 11,15,15,15,12,12,15,14,14,13,13,16,15,15,11,11,
+ 15,14,14,12,12,15,15,15,11,11,14,11,11, 9, 9,15,
+ 10,10,12,12,14,11,11,12,12,15,12,12,12,12,15,14,
+ 14,13,13,15,11,11,13,13,15,14,14,13,13,15,10,10,
+ 12,12,15,12,12,13,13,15,14,14,13,13,15,11,11,12,
+ 12,15,14,14,13,13,14,10,10,12,12,15,12,12,13,13,
+ 15,14,14,12,12,15,12,12,13,13,15,14,14,15,15,15,
+ 11,11,12,12,15,12,12,12,13,15,14,14,12,12,15,15,
+ 15,14,14,15,14,14,20,20,15,14,14,12,12,15,14,14,
+ 13,13,15,14,14,12,12,14,13,13,10,10,14,13,13,11,
+ 11,14,13,13,12,12,14,14,14,12,12,15,14,14,13,13,
+ 15,14,14,12,12,14,14,14,14,14,14,14,14,11,11,15,
+ 14,14,12,12,15,14,14,14,14,15,14,14,12,12,14,14,
+ 14,14,14,14,14,14,11,11,15,14,14,12,12,14,14,14,
+ 14,14,15,14,14,12,12,15,14,14,13,13,15,14,14,12,
+ 12,15,14,14,12,12,14,14,14,14,13,15,15,15,14,14,
+ 15,14,14,13,13,15,15,15,14,14,15,14,14,13,13,15,
+ 15,15,13,13,14,13,13,13,13,18,15,15,12,12,18,15,
+ 15,13,12,18,15,16,11,11,18,16,17,12,12,18,15,15,
+ 13,13,18,17,17,12,12,18,15,15,12,12,17,15,15,12,
+ 12,18,17,17,12,12,18,15,15,13,13,18,16,17,12,12,
+ 17,15,15,12,12,18,15,15,12,12,18,16,17,11,12,18,
+ 16,16,12,12,17,16,17,12,12,18,15,15,11,11,18,15,
+ 15,12,12,18,17,17,11,11,17,17,17,12,12,18,16,16,
+ 13,13,18,17,17,11,11,18,16,16,12,12,18,17,17,11,
+ 11,15,14,14,11,11,16,15,15,11,11,16,15,15,12,12,
+ 16,15,15,12,12,17,15,15,14,13,16,15,15,12,12,17,
+ 15,15,14,14,16,15,15,11,11,16,15,15,12,12,18,15,
+ 15,13,13,16,15,15,11,11,17,15,15,14,14,16,15,15,
+ 11,11,16,15,15,12,12,17,15,15,13,13,16,15,15,12,
+ 12,17,16,15,14,14,16,14,15,12,12,16,15,15,12,12,
+ 18,15,15,13,13,17,15,15,14,14,17,16,16,15,15,17,
+ 15,15,13,13,17,15,15,14,14,18,15,15,13,13,15,12,
+ 13,11,11,15,14,14,12,12,16,14,14,12,12,16,14,14,
+ 12,12,16,14,14,12,12,16,14,14,13,12,17,14,14,13,
+ 13,16,15,15,12,12,16,14,14,12,12,17,14,14,12,12,
+ 16,14,14,12,12,17,14,14,13,13,15,15,15,12,12,16,
+ 14,14,12,12,17,14,14,12,12,17,15,15,12,12,17,14,
+ 14,13,13,16,15,15,12,12,16,14,14,12,12,17,15,15,
+ 12,12,18,15,15,13,13,17,14,14,13,13,17,15,15,12,
+ 12,17,14,14,12,12,17,15,15,12,12,14,15,15, 9, 9,
+ 15,15,15,12,12,15,15,15,13,13,15,15,15,14,14,15,
+ 15,15,19,19,15,15,16,13,13,15,15,16,19,20,15,15,
+ 15,13,12,15,16,16,14,14,15,15,15,19,19,15,15,15,
+ 13,13,15,16,15,20,19,14,15,15,13,13,15,15,15,14,
+ 14,15,15,15,19,19,15,15,15,14,14,15,16,16,19,20,
+ 15,15,15,14,14,15,15,15,14,14,15,15,15,19,19,15,
+ 15,15,20,19,15,16,16,20,19,15,15,15,19,19,15,16,
+ 16,20,20,15,15,15,19,20,14,13,13,10,10,14,14,14,
+ 11,11,14,14,14,12,12,15,14,14,13,13,15,14,14,19,
+ 20,15,14,14,12,12,14,14,14,20,19,14,14,14,11,11,
+ 15,14,14,12,12,15,14,14,20,20,15,14,14,12,12,14,
+ 14,14,20,19,14,14,14,11,11,15,14,14,12,12,15,14,
+ 14,19,20,15,14,14,13,13,15,14,14,22,19,15,15,14,
+ 12,12,15,14,14,13,13,14,15,15,22,20,15,15,15,20,
+ 20,15,14,14,21,20,15,15,15,20,21,15,14,14,20,20,
+ 14,15,15,20,20,
+};
+
+static const static_codebook _44p3_p4_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p3_p4_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p3_p4_1,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p5_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p3_p5_0[] = {
+ 2, 6, 6,14,14, 6, 7, 7,14,14, 7, 7, 7,15,15, 0,
+ 12,12,15,15, 0,13,13,15,15, 7, 8, 8,15,15,10,10,
+ 10,16,16, 9, 8, 8,15,15, 0,13,13,18,17, 0,13,13,
+ 16,16, 8, 8, 8,15,15,12,11,11,16,16, 9, 8, 8,15,
+ 15, 0,13,13,18,18, 0,13,13,16,16, 0,14,14,17,17,
+ 0,20, 0,19,20, 0,12,12,16,16, 0,16,16,20,22, 0,
+ 14,14,16,16, 0,14,14,17,17, 0,20,22,20,19, 0,13,
+ 13,15,16, 0,17,18, 0,21, 0,15,15,16,16, 5, 7, 7,
+ 13,13, 8, 9, 9,14,14,10,10,10,14,14, 0,20,22,18,
+ 18, 0,22,21,18,17, 9,10,10,14,14,12,12,12,17,17,
+ 12,10,10,14,14, 0, 0,20,17,17, 0,22,21,17,18,11,
+ 10,10,14,14,14,13,13,18,18,12,11,11,14,14, 0,22,
+ 21,18,19, 0,20, 0,17,17, 0,22, 0,18,18, 0, 0, 0,
+ 0, 0, 0,20,20,17,17, 0,22, 0,22,21, 0,21, 0,19,
+ 18, 0,22,22,18,18, 0, 0, 0, 0, 0, 0,21, 0,17,17,
+ 0,22, 0,20,20, 0, 0, 0,19,18, 6, 6, 6,12,12, 8,
+ 6, 6,10,10, 8, 6, 6,13,12, 0,10,10,11,11, 0,11,
+ 11,13,13, 8, 7, 7,13,13,11, 9, 9,13,13,10, 6, 6,
+ 12,12, 0,10,10,14,14, 0,10,10,13,13, 9, 7, 7,13,
+ 13,12,10,10,13,13,10, 6, 6,12,12, 0,11,11,15,15,
+ 0,10,10,13,13, 0,12,12,15,14, 0,19,20,16,17, 0,
+ 9, 9,13,13, 0,14,14,20,21, 0,12,11,13,12, 0,12,
+ 12,15,14, 0,20,19,17,17, 0,10,10,12,13, 0,15,15,
+ 22,21, 0,12,12,12,13, 0,10,10,12,12, 0,11,11,15,
+ 15, 0,11,11,15,15, 0,15,15,22,22, 0,16,17, 0, 0,
+ 0,11,11,15,15, 0,14,14,18,18, 0,11,11,16,16, 0,
+ 16,15, 0,21, 0,16,16, 0, 0, 0,12,12,15,15, 0,14,
+ 14,19,19, 0,11,11,15,15, 0,15,15,22, 0, 0,16,16,
+ 22, 0, 0,16,16, 0,21, 0, 0, 0, 0, 0, 0,15,15,19,
+ 20, 0,18,18, 0, 0, 0,17,17, 0, 0, 0,17,17, 0, 0,
+ 0, 0, 0, 0, 0, 0,16,15,22,21, 0,20,20, 0, 0, 0,
+ 18,18, 0, 0, 0,10,10,12,12, 0,10,10,11,11, 0,11,
+ 11,12,12, 0,11,11, 9, 9, 0,13,12,12,12, 0,11,11,
+ 13,13, 0,13,13,12,12, 0,10,10,12,12, 0,13,12,13,
+ 13, 0,12,12,12,12, 0,11,11,13,13, 0,13,13,12,12,
+ 0,10,10,12,12, 0,13,13,14,13, 0,12,12,12,12, 0,
+ 14,13,13,14, 0,20,21,15,15, 0,11,11,12,12, 0,15,
+ 16,20,20, 0,12,13,10,10, 0,13,13,14,13, 0,20,20,
+ 15,15, 0,11,11,12,12, 0,16,17,21,21, 0,13,13,11,
+ 11, 6, 7, 7,16,15,11, 9, 9,14,15,12, 9, 9,16,16,
+ 0,13,13,15,15, 0,14,14,17,17,10, 9, 9,16,16,14,
+ 12,12,16,16,12, 9, 9,15,15, 0,13,13,17,18, 0,13,
+ 13,15,15,12,10,10,17,17,15,12,12,17,17,13, 9, 9,
+ 16,16, 0,13,13,18,19, 0,14,14,16,16, 0,15,15,18,
+ 18, 0, 0, 0,20,19, 0,12,12,17,16, 0,16,17, 0,21,
+ 0,14,15,16,16, 0,15,15,18,18, 0, 0,22,19,21, 0,
+ 13,13,16,16, 0,18,17,22,22, 0,15,15,16,16, 7, 7,
+ 7,13,13,11,10,10,15,15,12,10,10,14,14, 0,21, 0,
+ 18,17, 0,21,22,18,18,11,10,10,15,15,14,12,12,17,
+ 17,14,11,11,14,14, 0,21,20,18,18, 0,22,21,18,17,
+ 12,11,10,16,16,16,14,14,17,19,14,11,11,15,15, 0,
+ 0,22,19,19, 0,21,22,18,18, 0,21, 0,18,19, 0, 0,
+ 0,22, 0, 0,22,21,17,17, 0, 0, 0,20,22, 0, 0,21,
+ 18,18, 0, 0, 0,19,20, 0, 0, 0, 0, 0, 0, 0,21,17,
+ 17, 0, 0, 0,22,21, 0, 0, 0,19,19,10, 9, 9,14,13,
+ 13,10,10,12,12,13,10,10,14,14, 0,13,13,12,12, 0,
+ 15,14,16,15,13,10,10,14,14,15,12,12,14,14,15,10,
+ 10,14,14, 0,14,14,15,15, 0,14,13,14,14,13,10,10,
+ 15,15,17,13,13,15,15,14,10,10,14,14, 0,14,14,15,
+ 16, 0,14,14,15,15, 0,15,15,16,16, 0,21,22,17,18,
+ 0,12,12,14,14, 0,17,17,20,21, 0,14,14,14,14, 0,
+ 15,15,16,16, 0,21,22,18,18, 0,13,13,14,14, 0,18,
+ 18,22, 0, 0,15,15,14,14, 0,11,11,13,13, 0,12,12,
+ 16,15, 0,12,12,16,16, 0,16,16, 0, 0, 0,16,17, 0,
+ 22, 0,12,12,16,16, 0,14,14,17,18, 0,11,11,16,16,
+ 0,15,15, 0,21, 0,16,16,21,22, 0,12,12,16,16, 0,
+ 15,15,19,19, 0,12,12,17,16, 0,16,16,21,22, 0,16,
+ 16, 0, 0, 0,17,17, 0,22, 0, 0, 0, 0, 0, 0,15,15,
+ 19,20, 0,17,19, 0, 0, 0,17,17,22, 0, 0,17,17, 0,
+ 22, 0, 0, 0, 0, 0, 0,15,15,21, 0, 0,19,20, 0, 0,
+ 0,19,18,22, 0, 0,11,12,14,14, 0,11,11,14,14, 0,
+ 12,12,15,15, 0,13,13,13,13, 0,14,14,16,16, 0,12,
+ 12,15,15, 0,14,14,16,15, 0,11,11,15,15, 0,13,13,
+ 16,16, 0,13,13,15,15, 0,12,12,15,15, 0,15,14,16,
+ 16, 0,11,11,15,15, 0,14,14,17,17, 0,13,13,15,15,
+ 0,15,15,16,16, 0, 0, 0,18,18, 0,12,12,14,14, 0,
+ 16,16,22, 0, 0,14,14,15,15, 0,15,15,16,17, 0,21,
+ 22,18,18, 0,13,13,15,14, 0,18,17,22, 0, 0,14,14,
+ 15,15, 8, 8, 8,16,15,12,10,10,16,15,12,10,10,16,
+ 16, 0,14,14,16,17, 0,14,14,17,16,12,10,10,17,18,
+ 14,12,12,18,18,14,10,10,16,16, 0,14,14,18,18, 0,
+ 14,14,16,16,12, 9, 9,16,16,17,13,13,16,17,14, 9,
+ 9,15,15, 0,14,14,18,19, 0,13,13,15,15, 0,15,15,
+ 18,19, 0, 0, 0,22,21, 0,13,13,16,16, 0,16,16,22,
+ 0, 0,15,15,16,16, 0,14,14,18,17, 0, 0, 0,20, 0,
+ 0,13,13,16,16, 0,18,18, 0, 0, 0,15,15,16,16, 8,
+ 7, 7,13,13,12,10,10,15,15,12,10,10,14,14, 0,22,
+ 22,19,18, 0, 0, 0,18,18,12,10,10,15,15,14,13,13,
+ 17,17,14,11,11,15,15, 0,19,20,18,18, 0,22,21,17,
+ 18,13,11,11,15,15,16,13,13,18,18,14,11,11,14,15,
+ 0,22,21,20,19, 0,22,21,17,17, 0, 0,22,19,18, 0,
+ 0, 0, 0, 0, 0,22,20,17,17, 0, 0, 0,21,20, 0, 0,
+ 0,19,17, 0, 0,22,19,19, 0, 0, 0, 0, 0, 0,22,20,
+ 18,17, 0, 0, 0, 0, 0, 0, 0, 0,18,18, 0,10,10,14,
+ 14, 0,11,11,14,14, 0,11,11,15,15, 0,14,14,14,14,
+ 0,15,15,16,16, 0,11,11,16,16, 0,13,13,16,16, 0,
+ 11,11,15,15, 0,14,14,16,16, 0,14,14,15,15, 0,11,
+ 11,15,15, 0,13,13,15,15, 0,10,10,15,15, 0,15,15,
+ 17,17, 0,14,14,14,14, 0,16,16,16,16, 0, 0,22,19,
+ 19, 0,13,13,14,14, 0,17,17, 0, 0, 0,15,15,14,14,
+ 0,16,16,17,17, 0, 0,22,18,18, 0,13,13,14,14, 0,
+ 21,18, 0, 0, 0,15,15,14,14, 0,11,11,13,13, 0,12,
+ 12,15,15, 0,12,12,16,15, 0,16,16, 0, 0, 0,17,17,
+ 22,22, 0,12,12,16,16, 0,14,14,18,18, 0,11,12,16,
+ 16, 0,15,16, 0,21, 0,16,16,22,21, 0,12,12,16,16,
+ 0,15,15,19,20, 0,11,12,16,16, 0,15,15,20,22, 0,
+ 16,16, 0,22, 0,17,17,22, 0, 0, 0, 0, 0, 0, 0,15,
+ 15,21,22, 0,19,18, 0, 0, 0,17,17, 0, 0, 0,17,17,
+ 0,22, 0, 0, 0, 0, 0, 0,16,15,22, 0, 0,19,19, 0,
+ 0, 0,17,18, 0, 0, 0,12,12,15,15, 0,12,12,15,15,
+ 0,12,12,15,15, 0,13,13,14,14, 0,15,15,16,17, 0,
+ 12,12,16,16, 0,14,14,16,16, 0,12,11,15,16, 0,14,
+ 14,16,17, 0,14,14,16,16, 0,13,12,16,16, 0,15,15,
+ 16,16, 0,11,11,15,15, 0,14,14,16,16, 0,14,14,15,
+ 15, 0,15,15,18,17, 0, 0,22, 0,20, 0,13,13,15,15,
+ 0,16,17,22,22, 0,14,14,15,15, 0,15,15,17,18, 0,
+ 20, 0,19,19, 0,13,13,15,15, 0,18,18,22, 0, 0,14,
+ 14,15,15, 0,11,11,16,16, 0,14,14,17,16, 0,13,13,
+ 17,17, 0,16,16,17,17, 0,17,17,18,19, 0,12,12,16,
+ 17, 0,15,15,18,18, 0,12,12,16,16, 0,16,16,19,18,
+ 0,16,16,17,16, 0,12,13,17,17, 0,17,16,18,17, 0,
+ 13,12,16,16, 0,16,16,18,19, 0,16,16,16,17, 0,16,
+ 16,18,18, 0,22, 0,22,22, 0,13,13,16,16, 0,19,18,
+ 22,20, 0,16,15,16,16, 0,16,17,18,18, 0, 0, 0,22,
+ 20, 0,14,14,16,16, 0,19,19, 0, 0, 0,16,16,16,16,
+ 0, 9, 9,13,13, 0,13,13,15,15, 0,14,14,15,15, 0,
+ 0,22,17,18, 0,22, 0,18,19, 0,12,12,15,15, 0,15,
+ 16,17,17, 0,14,14,14,14, 0,22, 0,18,18, 0,21,22,
+ 17,17, 0,13,13,15,15, 0,17,17,17,18, 0,14,14,15,
+ 15, 0,22,21,21,19, 0,20,21,17,17, 0,21,21,19,18,
+ 0, 0, 0, 0, 0, 0,21,21,17,17, 0, 0, 0,22,22, 0,
+ 0,22,19,18, 0, 0,21,19,18, 0, 0, 0, 0,22, 0,19,
+ 20,17,17, 0, 0, 0, 0,22, 0, 0, 0,19,18, 0,19,19,
+ 15,16, 0,21,19,16,17, 0, 0,21,17,17, 0, 0,22,17,
+ 17, 0,22,22,18,19, 0,20,20,16,16, 0, 0,22,18,18,
+ 0,20,19,16,17, 0,22,21,20,19, 0, 0,21,17,17, 0,
+ 21,20,17,17, 0, 0, 0,18,18, 0,19,19,17,16, 0,22,
+ 0,19,19, 0,21,22,17,18, 0, 0,22,19,18, 0, 0, 0,
+ 19,20, 0,19,19,16,16, 0,22,22,22, 0, 0,20,22,16,
+ 16, 0,22,20,18,19, 0, 0, 0,20,19, 0,20,20,16,16,
+ 0, 0, 0, 0, 0, 0,22,20,17,16, 0,11,11,13,13, 0,
+ 14,13,15,15, 0,13,13,16,15, 0,18,17,21, 0, 0,18,
+ 18,21, 0, 0,12,12,15,15, 0,15,16,17,18, 0,12,12,
+ 15,15, 0,17,17,22,20, 0,17,18,22, 0, 0,12,12,17,
+ 16, 0,16,17,19,19, 0,13,13,16,16, 0,17,17, 0,22,
+ 0,17,17, 0,21, 0,18,18,20,22, 0, 0, 0, 0, 0, 0,
+ 15,15,21,20, 0,20,19, 0, 0, 0,18,18,22, 0, 0,17,
+ 17,22, 0, 0, 0, 0, 0, 0, 0,15,16,20,22, 0,20,21,
+ 0, 0, 0,19,18, 0, 0, 0,15,15,19,19, 0,17,16,20,
+ 20, 0,16,17,20,21, 0,18,17, 0, 0, 0,19,19, 0, 0,
+ 0,15,15,21,19, 0,19,19, 0, 0, 0,15,15,22,22, 0,
+ 18,18, 0,22, 0,17,18,22,21, 0,15,15,20,19, 0,19,
+ 19, 0, 0, 0,15,15,20,22, 0,18,19,20, 0, 0,18,17,
+ 21,21, 0,18,18,19,22, 0, 0, 0, 0, 0, 0,15,15,20,
+ 19, 0,19,19, 0, 0, 0,18,18,21,22, 0,18,18,22, 0,
+ 0, 0, 0, 0, 0, 0,15,15,19,20, 0,21,21, 0, 0, 0,
+ 17,17,20,20, 0,12,12,17,17, 0,14,14,16,17, 0,13,
+ 14,17,17, 0,16,16,17,17, 0,17,17,17,19, 0,13,13,
+ 17,17, 0,16,16,18,18, 0,13,13,16,16, 0,16,16,18,
+ 18, 0,16,16,17,17, 0,13,13,17,17, 0,17,17,18,17,
+ 0,12,12,15,16, 0,17,18,19,20, 0,16,16,16,16, 0,
+ 17,16,18,19, 0, 0,22,21,22, 0,14,14,16,16, 0,19,
+ 19, 0, 0, 0,16,16,16,16, 0,16,16,18,17, 0, 0,22,
+ 21,21, 0,14,14,16,16, 0,22,20,22, 0, 0,16,16,15,
+ 15, 0, 9, 9,13,13, 0,14,14,15,15, 0,14,14,14,14,
+ 0,22,22,18,18, 0, 0,22,18,18, 0,12,12,15,15, 0,
+ 16,16,18,17, 0,14,14,14,14, 0,20,21,18,18, 0,22,
+ 21,17,17, 0,13,13,15,15, 0,17,17,18,18, 0,14,14,
+ 14,14, 0, 0,21,18,19, 0, 0,22,17,17, 0,22,22,19,
+ 18, 0, 0, 0, 0, 0, 0,19,21,17,17, 0, 0, 0,22,20,
+ 0, 0,21,18,19, 0, 0,22,18,18, 0, 0, 0, 0,22, 0,
+ 20,22,17,17, 0, 0, 0,20,22, 0, 0, 0,18,18, 0,19,
+ 21,16,16, 0,20,22,16,17, 0,20, 0,17,17, 0,22, 0,
+ 18,17, 0,21, 0,18,19, 0,20,20,17,17, 0,22, 0,18,
+ 18, 0,21,20,17,17, 0, 0,20,20,19, 0, 0,21,18,17,
+ 0,21,21,17,17, 0,22, 0,18,17, 0,19,19,17,17, 0,
+ 0,22,20,21, 0, 0,21,17,17, 0,22, 0,18,18, 0, 0,
+ 0,20,22, 0,20,19,16,16, 0, 0, 0, 0, 0, 0,22,22,
+ 17,17, 0,22, 0,18,19, 0, 0, 0,21,20, 0,19,21,16,
+ 17, 0, 0, 0, 0, 0, 0,22,22,17,16, 0,11,11,13,13,
+ 0,13,13,15,15, 0,13,13,15,15, 0,17,17,22,21, 0,
+ 18,18,22, 0, 0,12,13,16,15, 0,15,16,18,18, 0,13,
+ 13,16,16, 0,17,17, 0,22, 0,17,17,22,22, 0,13,13,
+ 16,16, 0,16,16,19,18, 0,13,13,16,16, 0,18,17, 0,
+ 20, 0,18,17,20, 0, 0,17,17,21, 0, 0, 0, 0, 0, 0,
+ 0,15,15,21,22, 0,19,20, 0, 0, 0,18,18, 0, 0, 0,
+ 18,17, 0, 0, 0, 0, 0, 0, 0, 0,16,16,22,22, 0,20,
+ 20, 0, 0, 0,21,19, 0, 0, 0,15,15,20,19, 0,16,16,
+ 22,20, 0,17,17, 0,22, 0,18,18, 0,22, 0,19,17, 0,
+ 0, 0,15,16,22,20, 0,18,19, 0, 0, 0,16,16,22,20,
+ 0,18,18, 0,22, 0,18,18,22, 0, 0,16,16,21,20, 0,
+ 19,20, 0,22, 0,16,16, 0,22, 0,18,18, 0,22, 0,18,
+ 18, 0,21, 0,19,18, 0,22, 0, 0, 0, 0, 0, 0,16,16,
+ 21,20, 0,20, 0, 0, 0, 0,18,18,21, 0, 0,18,18, 0,
+ 0, 0, 0, 0, 0, 0, 0,16,16,21,19, 0, 0, 0, 0, 0,
+ 0,18,18, 0,21,
+};
+
+static const static_codebook _44p3_p5_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p3_p5_0,
+ 1, -528744448, 1616642048, 3, 0,
+ (long *)_vq_quantlist__44p3_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p5_1[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44p3_p5_1[] = {
+ 2, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _44p3_p5_1 = {
+ 1, 7,
+ (char *)_vq_lengthlist__44p3_p5_1,
+ 1, -533200896, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p3_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p3_p6_0[] = {
+ 1, 6, 6, 7, 7, 7, 7, 8, 8, 7, 9, 9,11,11,11, 9,
+ 8, 8, 8, 9, 9,12,11,11, 9, 8, 8, 6, 7, 7,10,11,
+ 10,10,10,10,11,11,10,14,13,14,12,11,11,11,11,11,
+ 15,14,14,13,12,12, 5, 6, 6, 8, 5, 5, 8, 7, 7, 8,
+ 8, 8,12,10,10, 9, 7, 7, 9, 7, 8,12,10,10,10, 7,
+ 7, 7, 8, 8,12,10,10,12,10,10,11,10,10,15,13,13,
+ 13,10,10,11,10,10,16,13,14,14,10,10, 7, 7, 7,12,
+ 11,11,12,11,11,11,11,11,16,15,15,14,12,12,12,11,
+ 11,16,15,16,14,12,12,10, 9, 9,14,11,11,13,11,11,
+ 12,11,11,16,14,14,14,11,11,12,11,11,17,15,15,14,
+ 11,11, 7, 8, 8,12,11,11,12,10,10,12,10,10,16,14,
+ 13,14,10,10,12,10,10,17,14,14,14,10,10, 8, 7, 7,
+ 13,11,11,12,11,11,12,11,11,16,15,14,14,12,12,12,
+ 11,11,16,15,14,15,12,12,11,10,10,13,11,11,13,12,
+ 11,13,11,11,17,14,14,14,11,11,13,11,11,17,14,15,
+ 14,11,11,
+};
+
+static const static_codebook _44p3_p6_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p3_p6_0,
+ 1, -527106048, 1620377600, 2, 0,
+ (long *)_vq_quantlist__44p3_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p6_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p3_p6_1[] = {
+ 2, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,
+ 7, 7, 8, 8, 8, 9, 9, 9, 9, 7, 8, 6, 7, 7, 8, 8,
+ 8, 8, 8, 8, 9, 8, 8,10, 9, 9,10, 8, 8,10, 8, 8,
+ 10, 9, 9,10, 8, 8, 6, 6, 6, 8, 6, 6, 8, 7, 7, 8,
+ 7, 7,10, 8, 8, 9, 7, 7, 9, 7, 7,10, 8, 9, 9, 7,
+ 7, 7, 7, 7,10, 8, 8,11, 8, 8,10, 8, 8,12, 9, 9,
+ 12, 8, 8,11, 9, 9,12, 9, 9,11, 8, 8, 7, 7, 7,10,
+ 9, 9,10, 9, 9,10, 9, 9,11,10,10,10, 9, 9,11, 9,
+ 9,11,10,10,11, 9, 9, 9, 8, 8,10, 9, 9,10, 9, 9,
+ 11, 9, 9,11,10,10,11, 9, 9,11, 9, 9,11,10,10,11,
+ 9, 9, 8, 8, 8,11, 9, 9,11, 9, 9,11, 9, 9,12, 9,
+ 9,12, 8, 8,12, 9, 9,12, 9, 9,12, 8, 8, 8, 7, 7,
+ 10, 9, 9,10, 9, 9,11, 9, 9,11,11,11,11, 9, 9,11,
+ 10,10,11,11,11,11, 9, 9,10, 9, 9,11, 9, 9,11, 9,
+ 10,11,10, 9,11,10,10,11, 9, 9,11, 9,10,11,10,10,
+ 11, 9, 9,
+};
+
+static const static_codebook _44p3_p6_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p3_p6_1,
+ 1, -530841600, 1616642048, 2, 0,
+ (long *)_vq_quantlist__44p3_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p3_p7_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p3_p7_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p3_p7_0,
+ 1, -513979392, 1633504256, 2, 0,
+ (long *)_vq_quantlist__44p3_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p7_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p3_p7_1[] = {
+ 1, 9, 9, 6, 9, 9, 5, 9, 9, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,
+};
+
+static const static_codebook _44p3_p7_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p3_p7_1,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p3_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p7_2[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p3_p7_2[] = {
+ 1, 3, 2, 5, 4, 7, 7, 8, 8, 9, 9,10,10,11,11,12,
+ 12,13,13,14,14,15,15,15,15,
+};
+
+static const static_codebook _44p3_p7_2 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p3_p7_2,
+ 1, -518864896, 1620639744, 5, 0,
+ (long *)_vq_quantlist__44p3_p7_2,
+ 0
+};
+
+static const long _vq_quantlist__44p3_p7_3[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p3_p7_3[] = {
+ 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p3_p7_3 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p3_p7_3,
+ 1, -529006592, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44p3_p7_3,
+ 0
+};
+
+static const char _huff_lengthlist__44p3_short[] = {
+ 4, 5,16, 9, 9,12,17,18, 4, 2,18, 6, 5, 9,13,15,
+ 10, 7, 7, 6, 7, 9,13,13, 8, 5, 6, 5, 5, 7,11,12,
+ 8, 4, 7, 4, 3, 6,10,12,11, 8, 9, 7, 6, 8,11,12,
+ 15,13,13,11, 9, 7,10,12,16,12,16,12, 6, 5, 8,11,
+};
+
+static const static_codebook _huff_book__44p3_short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p3_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p4_l0_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44p4_l0_0[] = {
+ 1, 4, 4, 8, 8, 9, 8, 9, 9,10,10,10,10, 4, 6, 5,
+ 8, 7, 9, 9, 9, 9,10, 9,10,10, 4, 5, 6, 7, 8, 9,
+ 9, 9, 9, 9,10, 9,10, 8, 9, 8, 9, 8,10, 9,11, 9,
+ 12,10,11,10, 8, 8, 9, 8, 9, 9,10, 9,11,10,11,10,
+ 12, 9,10,10,11,10,11,11,12,11,12,12,12,12, 9,10,
+ 10,11,11,11,11,11,12,12,12,12,12,10,11,11,12,12,
+ 12,12,12,12,12,12,12,12,10,11,11,12,12,12,12,12,
+ 12,12,12,12,12,11,12,12,12,12,12,12,12,12,12,13,
+ 12,12,11,12,11,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,13,12,12,12,12,12,12,11,13,12,12,
+ 12,13,12,12,12,12,12,12,12,
+};
+
+static const static_codebook _44p4_l0_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44p4_l0_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44p4_l0_0,
+ 0
+};
+
+static const long _vq_quantlist__44p4_l0_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p4_l0_1[] = {
+ 3, 4, 4, 5, 5, 4, 4, 5, 5, 5, 4, 5, 4, 5, 5, 5,
+ 5, 6, 5, 6, 5, 6, 5, 6, 5,
+};
+
+static const static_codebook _44p4_l0_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p4_l0_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p4_l0_1,
+ 0
+};
+
+static const long _vq_quantlist__44p4_l1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p4_l1_0[] = {
+ 1, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+
+static const static_codebook _44p4_l1_0 = {
+ 2, 9,
+ (char *)_vq_lengthlist__44p4_l1_0,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p4_l1_0,
+ 0
+};
+
+static const char _huff_lengthlist__44p4_lfe[] = {
+ 1, 3, 2, 3,
+};
+
+static const static_codebook _huff_book__44p4_lfe = {
+ 2, 4,
+ (char *)_huff_lengthlist__44p4_lfe,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44p4_long[] = {
+ 3, 5,13, 9, 9,12,16,18, 4, 2,20, 6, 7,10,15,20,
+ 10, 7, 5, 5, 6, 8,10,13, 8, 5, 5, 3, 5, 7,10,11,
+ 9, 7, 6, 5, 5, 7, 9, 9,11,10, 8, 7, 6, 6, 8, 8,
+ 15,15,10,10, 9, 7, 8, 9,17,19,13,12,10, 8, 9, 9,
+};
+
+static const static_codebook _huff_book__44p4_long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p4_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p4_p1_0[] = {
+ 1, 2, 2, 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, 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,
+};
+
+static const static_codebook _44p4_p1_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p4_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p4_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p4_p2_0[] = {
+ 3, 9, 9, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0,
+ 12,12, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 0, 0, 0, 0, 0,
+ 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0,
+ 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0,12,12, 0, 0,
+ 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0,12,12, 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, 7, 7,
+ 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, 7, 7, 0, 0, 0,
+ 5, 5, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5,
+ 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 7, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,
+ 7, 7, 0, 0, 0, 9, 9, 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,11,11, 0, 0, 0, 9, 9, 0,
+ 0, 0,10,10, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0,
+ 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,
+ 10,10, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0,
+ 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0,
+ 0, 0,12,12, 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, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 9, 9, 0, 0, 0, 7, 7, 0, 0, 0, 8, 8, 0, 0,
+ 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0,
+ 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8,
+ 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 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, 5,
+ 5, 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, 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,10,10, 0, 0, 0, 7, 7,
+ 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0,
+ 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0,
+ 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9,
+ 0, 0, 0,10,10, 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, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 9, 9, 0, 0, 0, 7, 7, 0, 0, 0, 8, 8, 0,
+ 0, 0,10,11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0,
+ 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 7,
+ 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,11,11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 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,
+ 5, 5, 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, 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,10,10, 0, 0, 0, 7,
+ 7, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 0,
+ 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0,
+ 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9,
+ 9, 0, 0, 0,11,11, 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, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,10,10, 0, 0, 0, 9, 9, 0, 0, 0,10,10,
+ 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0,
+ 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0,10,10, 0, 0,
+ 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0,
+ 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0,11,
+ 11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,12,12,
+ 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, 7, 7, 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, 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,10,10, 0, 0, 0,
+ 9, 9, 0, 0, 0,10,10, 0, 0, 0,12,12, 0, 0, 0, 0,
+ 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9,
+ 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0,10,10, 0, 0,
+ 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0,
+ 10,10, 0, 0, 0,11,11, 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, 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, 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, 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, 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,
+ 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,
+};
+
+static const static_codebook _44p4_p2_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p4_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p4_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p3_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p4_p3_0[] = {
+ 1, 6, 6, 5, 7, 8, 0, 8, 8, 6, 9, 9, 7,10,10, 0,
+ 8, 8, 0, 9, 9, 0,12,12, 0, 8, 8, 4, 7, 7, 6,10,
+ 10, 0,12,12, 7,11,11, 8,12,12, 0,12,12, 0,13,12,
+ 0,15,15, 0,12,12, 0, 7, 7, 0, 7, 7, 0, 7, 7, 0,
+ 8, 8, 0,10,10, 0, 7, 7, 0, 8, 8, 0,11,11, 0, 7,
+ 7, 5, 7, 7, 8, 9, 9, 0,10,10, 8, 9, 9,11,11,11,
+ 0,10, 9, 0,11,11, 0,13,13, 0,10,10, 6, 7, 7, 8,
+ 10,10, 0,12,12, 9,10,10,10,12,12, 0,12,12, 0,12,
+ 12, 0,15,15, 0,12,12, 0,10,10, 0,11,11, 0,11,11,
+ 0,11,11, 0,13,13, 0,11,11, 0,11,11, 0,15,15, 0,
+ 10,10, 0, 8, 8, 0,10,10, 0,12,12, 0,11,11, 0,12,
+ 12, 0,12,12, 0,12,12, 0,15,15, 0,11,11, 0, 7, 7,
+ 0,10,10, 0,12,12, 0,10,10, 0,12,12, 0,12,12, 0,
+ 13,13, 0,14,14, 0,12,12, 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,
+};
+
+static const static_codebook _44p4_p3_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p4_p3_0,
+ 1, -533200896, 1614282752, 2, 0,
+ (long *)_vq_quantlist__44p4_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p3_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p4_p3_1[] = {
+ 3, 5, 5, 0, 8, 8, 0, 8, 8, 0, 9, 9, 0,10,10, 0,
+ 8, 8, 0, 8, 8, 0,10,10, 0, 8, 8, 0, 7, 7, 0, 8,
+ 8, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0, 8, 8, 0, 8, 8,
+ 0, 8, 8, 0, 8, 8, 0, 7, 7, 0, 6, 6, 0, 7, 7, 0,
+ 7, 7, 0,10,10, 0, 6, 6, 0, 7, 7, 0,10,10, 0, 5,
+ 5, 0, 8, 8, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0, 9, 9,
+ 0, 7, 7, 0, 8, 8, 0, 9, 9, 0, 7, 7, 0, 6, 6, 0,
+ 9,10, 0,10,10, 0,10,10, 0,11,11, 0, 9, 9, 0,10,
+ 10, 0,11,11, 0, 9, 9, 0, 8, 8, 0, 8, 8, 0, 8, 8,
+ 0, 9, 9, 0, 9, 9, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0,
+ 7, 7, 0, 8, 8, 0, 7, 7, 0, 7, 7, 0, 8, 8, 0, 9,
+ 9, 0, 7, 7, 0, 7, 7, 0, 8, 8, 0, 6, 6, 0, 6, 6,
+ 0,10,10, 0,10,10, 0,10,10, 0,12,12, 0, 9, 9, 0,
+ 10,10, 0,12,12, 0, 9, 9, 0, 8, 8, 0, 7, 7, 0, 7,
+ 7, 0, 8, 8, 0, 9, 9, 0, 7, 7, 0, 8, 8, 0, 9, 9,
+ 0, 6, 6,
+};
+
+static const static_codebook _44p4_p3_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p4_p3_1,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p4_p3_1,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p4_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p4_p4_0[] = {
+ 1, 6, 6, 6, 7, 7, 7, 8, 8, 7, 8, 8,10,11,11, 9,
+ 8, 8, 8, 8, 8,11,11,12, 9, 8, 8, 5, 7, 7, 9,11,
+ 11,10,11,11,10,11,11,12,14,14,11,12,12,10,12,12,
+ 13,14,14,12,12,12, 5, 6, 6, 7, 6, 6, 8, 7, 7, 8,
+ 7, 7,11,10,10,10, 7, 7, 9, 8, 8,12,11,11,10, 7,
+ 7, 7, 7, 7,11,10,10,12,10,10,11,10,10,15,13,13,
+ 13,10,10,12,11,11,15,13,13,14,11,11, 7, 7, 7,11,
+ 11,11,12,11,11,12,11,11,14,14,14,13,12,12,12,12,
+ 12,16,15,15,14,12,12, 0,10,10, 0,11,11, 0,12,12,
+ 0,11,11, 0,14,14, 0,11,11, 0,12,12, 0,15,15, 0,
+ 11,11, 7, 8, 8,12,11,10,12,10,10,12,11,11,15,13,
+ 13,14,11,11,12,10,10,16,14,14,14,10,10, 8, 7, 7,
+ 12,11,11,12,11,11,12,11,11,15,14,14,14,12,12,13,
+ 12,12,15,14,14,15,13,13, 0,11,11, 0,12,12, 0,12,
+ 12, 0,12,12, 0,15,15, 0,12,12, 0,13,13, 0,15,14,
+ 0,12,12,
+};
+
+static const static_codebook _44p4_p4_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p4_p4_0,
+ 1, -531365888, 1616117760, 2, 0,
+ (long *)_vq_quantlist__44p4_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p4_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p4_p4_1[] = {
+ 4, 5, 5, 9, 9,12, 9, 9,12,12,12,10,10,13,13,13,
+ 11,11,12,12,13,13,13,12,12,13,10,10,13,13,13,13,
+ 13,13,13,13,10,10,13,12,13,11,11,13,13,13,14,14,
+ 13,12,13,10,10,13,13,12,13,13,13,13,13,10,10,12,
+ 12,13,11,11,13,13,13,14,14,12,12,13,12,12,13,13,
+ 13,13,13,13,13,13,11,11,12,12,13,11,11,13,13,13,
+ 14,14,12,12,13,14,14,13,13,14,13,13,14,14,14,14,
+ 14,12,12,13,14,14,13,13,14,14,14,12,12,12, 8, 8,
+ 12,12,13,12,12,11,11,13,11,11,11,11,14,12,12,11,
+ 11,14,12,12,10,11,14,12,12,12,12,14,12,12,12,12,
+ 13,13,13,11,11,14,12,12,11,11,14,12,12,12,12,14,
+ 12,12,12,12,14,12,12,12,12,14,13,13,11,11,14,12,
+ 12,11,11,14,12,12,12,12,14,13,13,12,12,14,12,12,
+ 12,12,14,13,13,11,11,14,12,12,11,11,14,13,13,11,
+ 11,15,13,13,12,12,14,12,12,12,12,15,13,13,12,12,
+ 14,12,12,11,11,15,13,13,11,11,12, 9, 9,11,11,13,
+ 7, 7,11,11,13, 8, 8,12,12,14,10,10,10,10,14,14,
+ 14,11,11,14, 8, 8,12,12,14,14,14,12,12,14, 7, 7,
+ 11,11,14, 9, 9,12,12,14,14,14,11,11,14, 8, 8,12,
+ 12,14,14,14,12,12,14, 7, 7,11,11,14, 9, 9,12,12,
+ 14,14,14,11,11,14,10,10,12,12,14,14,14,13,13,14,
+ 9, 9,11,11,14,10,10,12,11,15,14,14,11,11,14,15,
+ 15,12,12,15,14,14,14,14,15,14,14,11,11,15,14,14,
+ 12,12,15,14,14,11,11,14,11,11,10,10,15,10,10,10,
+ 10,15,10,10,10,10,15,11,11, 9, 9,15,12,13, 9, 9,
+ 15,11,11,11,11,15,13,13,11,11,15,10,10,10,10,15,
+ 11,11,10,10,15,13,13,11,11,15,11,11,11,11,15,13,
+ 13,11,11,15,10,10,10,10,15,11,11,10,10,15,13,13,
+ 10,11,15,12,12,11,11,15,13,13,11,10,15,11,11,10,
+ 10,15,11,12,10, 9,15,13,13,10,10,15,14,14,11,11,
+ 15,13,13,11,11,15,14,14,10,10,15,13,13,10,10,15,
+ 14,14,10,10,14,13,13,10,10,15,13,13,10,10,15,13,
+ 13,10,10,14,14,14, 8, 9,15,14,14, 9, 9,15,14,14,
+ 11,11,15,14,14,10,10,15,14,14,10,10,15,14,14,11,
+ 11,15,14,14,10,10,15,14,14,11,11,15,14,14,10,10,
+ 15,14,14,10,10,15,14,14,10,10,15,14,14, 9, 9,15,
+ 14,14,11,11,15,14,14,11,11,15,14,14,10,10,15,14,
+ 14,10,10,14,14,14, 9, 9,15,15,15,11,11,15,14,14,
+ 12,12,15,15,15,10,10,15,14,15,10,10,15,15,15, 9,
+ 9,15,10,10,13,13,17, 8, 8,12,12,17,10, 9,13,13,
+ 18,11,11,12,12,18,14,14,12,12,17, 9, 9,13,13,17,
+ 13,13,12,12,18, 8, 8,12,12,18,10,10,12,12,18,14,
+ 14,12,12,18,10,10,13,13,18,13,13,13,13,18, 9, 9,
+ 12,12,18,10,10,13,13,18,14,14,12,12,18,11,11,13,
+ 13,18,14,14,13,13,18,10,10,12,12,17,11,11,12,12,
+ 18,14,14,12,12,18,14,14,13,13,18,14,14,13,13,19,
+ 14,15,12,12,18,14,14,12,12,18,15,15,12,12,13, 7,
+ 7,11,11,14,15,15,11,11,14,16,15,11,11,14,15,15,
+ 11,11,14,15,15,11,11,14,15,15,11,12,14,15,15,12,
+ 12,13,15,15,11,11,14,15,15,11,11,15,15,15,12,12,
+ 14,15,15,12,12,14,16,16,12,12,14,15,15,11,11,14,
+ 15,15,11,11,15,15,15,12,12,15,15,15,12,12,14,15,
+ 15,12,12,14,15,15,11,11,14,15,15,11,11,15,14,15,
+ 12,12,15,15,15,12,12,15,16,16,12,12,15,15,15,12,
+ 12,14,15,15,12,12,15,15,15,12,12,13,13,13,11,11,
+ 14,14,15,11,11,14,14,14,12,12,14,15,15,10,10,15,
+ 15,15,11,11,14,15,15,12,12,14,14,14,11,11,14,15,
+ 15,11,11,14,15,15,12,12,15,15,15,11,11,14,15,15,
+ 12,12,14,14,15,11,11,14,15,15,11,11,14,15,15,12,
+ 12,15,15,15,11,11,15,15,15,12,12,14,15,15,12,12,
+ 14,15,15,10,10,14,15,15,11,11,15,15,15,10,10,15,
+ 15,15,12,12,15,15,15,14,14,15,15,15,11,11,15,15,
+ 15,11,11,15,15,15,11,11,14,10,10,10,10,15, 9, 9,
+ 12,11,15,10,10,12,12,15,11,11,11,11,15,13,13,12,
+ 12,16,10,10,12,12,15,13,13,12,12,15, 9, 9,11,11,
+ 15,10,10,13,12,15,13,13,11,11,15,10,10,12,12,15,
+ 13,13,12,12,15, 9, 9,11,11,15,10,10,12,12,15,13,
+ 13,11,11,15,11,11,12,12,15,13,13,13,13,15,10,10,
+ 11,11,15,11,11,12,12,15,13,14,11,11,15,14,14,13,
+ 13,16,14,14,20,19,15,14,14,11,11,15,13,14,12,12,
+ 15,14,14,11,11,14,13,13,10,10,14,14,13,11,11,15,
+ 13,14,12,12,15,14,14,12,12,15,14,14,11,11,15,14,
+ 14,12,12,15,15,14,13,13,15,14,14,11,11,15,14,14,
+ 11,11,15,14,14,13,13,15,14,14,12,12,15,14,14,13,
+ 13,15,14,14,11,11,15,14,14,11,11,15,14,14,13,13,
+ 15,14,14,12,12,15,14,14,12,12,15,14,14,12,12,15,
+ 14,14,11,11,15,15,15,12,12,15,15,15,13,13,16,14,
+ 14,12,12,15,15,15,13,13,15,15,15,12,12,15,15,15,
+ 12,12,14,10,10,13,13,17, 9, 9,12,12,17, 9, 9,13,
+ 13,17,11,11,12,12,18,14,14,12,12,18,10,10,13,13,
+ 18,14,13,12,12,18, 9, 9,12,12,18,10,10,12,13,18,
+ 14,14,12,12,17, 9, 9,12,12,17,13,14,12,12,17, 9,
+ 9,12,12,17,10,10,12,12,17,14,14,11,11,18,11,11,
+ 12,12,18,14,14,12,13,18,10,10,12,12,18,11,11,12,
+ 12,18,14,14,11,11,18,15,15,12,12,18,14,14,13,13,
+ 18,14,15,12,12,17,14,14,12,12,17,15,15,12,12,13,
+ 7, 7,11,11,14,15,15,11,11,14,15,15,11,11,14,15,
+ 15,11,11,14,15,15,11,11,14,15,15,11,11,14,15,15,
+ 12,12,14,15,15,11,11,14,15,15,11,11,15,15,15,12,
+ 12,14,15,15,11,11,14,15,15,12,12,14,15,15,11,11,
+ 15,15,15,11,11,15,15,15,12,12,14,15,15,12,12,14,
+ 15,16,12,12,14,15,15,11,11,14,15,15,11,11,15,15,
+ 15,12,12,15,15,15,12,12,15,16,16,12,12,15,15,15,
+ 12,12,15,15,15,12,12,15,15,15,12,12,13,13,13,12,
+ 12,14,14,14,11,11,14,14,14,12,12,14,14,14,10,10,
+ 15,15,15,11,11,14,15,15,12,12,14,14,14,11,11,14,
+ 15,15,11,11,14,14,14,12,12,15,15,14,11,11,14,15,
+ 15,12,12,14,14,14,11,11,14,15,15,11,11,14,14,14,
+ 11,11,15,14,14,10,10,14,15,15,12,12,14,14,14,12,
+ 12,14,15,15,10,10,14,15,15,11,11,15,15,15,10,10,
+ 15,15,15,12,12,15,14,14,13,13,15,15,15,10,10,15,
+ 14,14,11,11,15,15,15,10,10,14,10,10,10,10,14, 9,
+ 9,12,12,15,10,10,12,12,14,11,11,11,11,15,13,14,
+ 12,12,15,10,10,13,13,15,13,13,12,12,15, 9, 9,12,
+ 12,15,10,10,13,13,15,13,14,11,11,15,10,10,12,12,
+ 15,13,13,12,12,15, 9, 9,11,11,15,10,10,12,12,15,
+ 13,13,11,11,15,11,11,12,12,15,13,13,13,13,15,10,
+ 10,11,11,15,11,11,12,12,15,14,14,11,11,15,14,14,
+ 13,13,15,14,14,20,19,15,14,14,11,11,15,14,14,12,
+ 12,15,14,14,11,11,14,13,13,11,11,15,13,13,11,11,
+ 15,14,13,12,12,15,14,14,11,12,15,14,14,11,11,15,
+ 14,14,12,12,14,14,14,13,13,15,14,14,11,11,15,14,
+ 14,11,11,15,14,14,13,13,15,14,14,12,12,15,14,14,
+ 13,13,14,14,14,11,11,15,14,14,11,11,15,14,14,13,
+ 13,15,14,14,12,12,15,14,14,12,12,15,14,14,12,12,
+ 15,14,14,11,11,14,14,14,12,12,15,15,15,13,13,16,
+ 14,14,12,12,15,15,15,13,13,15,14,14,12,12,15,15,
+ 15,12,12,15,11,11,13,13,18,10,10,12,12,17,11,11,
+ 12,12,18,12,12,11,11,18,14,14,12,12,18,10,10,13,
+ 13,18,14,14,12,12,18,10,10,12,12,18,11,11,12,12,
+ 18,14,14,12,12,18,11,11,12,13,18,14,14,12,12,18,
+ 10,10,12,12,18,11,11,12,12,18,14,14,11,11,18,11,
+ 11,12,12,18,14,14,12,12,17,10,10,11,11,17,12,12,
+ 11,11,17,14,14,11,11,18,15,15,12,12,18,14,14,13,
+ 13,18,15,15,11,11,18,15,14,12,12,18,15,15,11,11,
+ 14, 8, 8,11,11,14,15,15,10,10,14,15,15,11,11,14,
+ 15,15,11,11,15,15,15,12,12,15,15,15,11,11,15,15,
+ 15,12,12,14,15,15,10,10,15,15,15,11,11,15,15,15,
+ 12,12,15,15,15,11,11,15,15,15,13,13,14,15,15,10,
+ 10,15,15,15,11,11,15,15,15,12,12,15,15,15,12,12,
+ 15,16,16,12,12,15,14,14,11,11,15,15,15,11,11,15,
+ 15,15,12,12,16,15,15,13,13,15,16,16,13,13,16,15,
+ 15,12,12,15,15,15,12,12,15,15,15,12,12,14,13,13,
+ 11,11,14,14,14,11,11,14,14,14,12,12,15,14,14,11,
+ 11,15,15,14,11,11,15,14,14,12,12,15,14,14,12,12,
+ 14,15,15,11,11,15,14,14,12,12,15,14,14,11,11,15,
+ 14,15,12,12,15,14,14,12,12,14,15,15,11,11,15,14,
+ 14,11,11,15,14,14,11,11,15,15,14,12,12,15,14,14,
+ 12,12,15,15,15,10,11,15,14,14,11,11,15,15,15,10,
+ 10,15,15,15,12,12,16,14,14,13,13,15,15,15,11,11,
+ 15,14,14,11,11,15,15,15,11,11,14,11,11, 9, 9,14,
+ 10,10,12,12,15,11,11,12,12,15,12,12,12,12,15,14,
+ 14,13,13,15,11,11,12,12,15,14,14,13,13,14,10,10,
+ 12,12,15,11,11,13,13,15,14,14,12,12,15,10,10,12,
+ 12,14,14,14,13,13,14,10,10,11,11,15,11,11,12,12,
+ 15,14,14,12,12,15,12,12,13,13,15,14,14,14,14,15,
+ 11,11,11,11,15,12,11,12,12,15,14,14,11,11,15,15,
+ 15,13,14,15,14,14,20,19,15,14,14,12,12,15,14,14,
+ 13,13,15,14,14,12,12,14,13,13,10,10,14,13,13,11,
+ 11,14,13,13,11,11,15,14,14,12,12,15,14,14,12,12,
+ 15,14,14,12,11,14,14,14,13,13,15,14,14,11,11,15,
+ 14,14,11,11,15,14,14,14,14,15,14,14,11,12,15,14,
+ 14,13,13,14,14,14,11,11,15,14,14,11,11,15,14,14,
+ 14,14,15,14,14,12,12,15,14,14,13,13,15,14,14,11,
+ 11,14,14,14,12,12,15,14,14,13,13,15,15,15,13,13,
+ 15,14,14,13,13,15,15,15,13,13,15,14,14,13,13,15,
+ 15,15,13,13,15,14,14,13,13,18,15,15,12,12,18,15,
+ 15,12,12,18,16,16,11,11,18,17,17,12,12,18,15,15,
+ 13,13,18,17,17,12,12,18,15,15,12,12,18,15,16,12,
+ 12,18,17,17,12,12,18,15,15,13,12,17,16,17,12,12,
+ 17,15,15,11,12,18,15,15,12,12,18,17,17,11,11,18,
+ 16,16,12,12,18,17,16,12,12,18,15,15,11,11,18,15,
+ 15,12,12,18,17,17,11,11,18,17,17,12,12,18,16,16,
+ 13,13,18,17,17,11,11,17,16,16,11,11,18,17,17,11,
+ 11,15,15,15,11,11,16,15,15,11,11,16,15,15,11,11,
+ 16,15,15,12,12,17,15,15,14,14,16,15,15,11,11,17,
+ 15,15,14,14,16,15,15,11,11,16,15,15,12,12,18,15,
+ 15,13,13,16,15,15,11,11,17,15,15,14,14,16,15,15,
+ 11,11,16,15,15,12,12,17,15,15,13,13,16,15,15,12,
+ 12,17,16,15,14,14,16,15,15,11,11,16,15,15,12,12,
+ 18,15,15,13,13,17,15,15,14,14,17,16,16,15,15,18,
+ 14,15,13,13,18,15,15,14,14,18,15,15,13,13,15,13,
+ 13,12,12,15,14,14,12,12,16,14,14,12,12,16,14,14,
+ 12,12,17,14,15,12,12,16,14,14,12,12,17,14,14,13,
+ 13,16,15,15,12,12,16,14,14,12,12,17,14,14,12,12,
+ 16,14,14,12,12,17,14,14,13,13,15,15,15,11,11,16,
+ 14,14,12,12,17,14,14,12,12,16,15,15,12,12,17,14,
+ 14,13,12,16,15,15,11,11,16,14,14,12,12,17,15,15,
+ 11,11,17,15,15,13,13,17,14,14,13,13,18,15,15,12,
+ 12,17,14,14,12,12,17,15,15,12,12,14,15,15, 9, 9,
+ 14,15,15,12,12,15,16,15,13,13,15,15,15,14,14,15,
+ 15,15,21,19,15,15,15,13,13,15,15,15,19,19,15,15,
+ 15,12,12,15,16,16,14,14,15,15,15,19,19,15,16,15,
+ 13,13,15,16,16,19,20,15,15,15,12,13,15,16,16,14,
+ 14,15,15,15,20,19,15,15,15,14,14,15,16,16,19,19,
+ 15,15,15,14,13,15,15,15,14,14,15,15,15,19,19,15,
+ 16,16,20,19,15,17,16,21,20,15,15,15,20,19,15,16,
+ 16,20,20,15,15,15,19,20,14,13,13,10,10,14,14,14,
+ 11,11,14,14,14,12,12,15,14,14,13,13,15,15,14,20,
+ 20,15,14,14,12,12,14,14,14,19,19,15,14,14,11,11,
+ 15,14,14,12,12,15,14,14,20,19,15,14,14,12,12,14,
+ 14,14,20,20,14,14,14,11,11,15,14,14,12,12,15,14,
+ 14,20,21,15,14,14,13,13,15,14,14,20,20,15,14,14,
+ 12,12,15,14,14,13,13,14,15,15,20,20,15,15,15,20,
+ 19,15,14,14,20,19,15,15,15,20,20,15,14,14,21,20,
+ 15,15,15,20,20,
+};
+
+static const static_codebook _44p4_p4_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p4_p4_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p4_p4_1,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p5_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p4_p5_0[] = {
+ 1, 7, 6,15,15, 7, 8, 8,15,15, 8, 8, 8,15,15, 0,
+ 13,13,16,16, 0,14,14,16,16, 7, 9, 9,16,16,10,11,
+ 11,17,17,10, 8, 8,15,16, 0,14,14,18,18, 0,14,14,
+ 16,16, 9, 9, 9,16,16,12,11,11,17,17,10, 9, 9,15,
+ 15, 0,14,14,19,19, 0,14,14,16,16, 0,15,15,18,17,
+ 0, 0, 0,20,20, 0,13,13,16,16, 0,17,17,22,20, 0,
+ 15,15,17,17, 0,15,15,18,18, 0,22,21,20,21, 0,13,
+ 13,16,16, 0,18,18, 0,22, 0,15,15,17,17, 6, 7, 7,
+ 13,13, 9,10,10,15,15,11,10,10,15,15, 0,21,22,18,
+ 18, 0, 0, 0,18,18,10,10,10,15,15,12,13,13,17,17,
+ 12,11,11,15,15, 0,22,22,18,18, 0, 0,21,18,18,12,
+ 11,11,15,15,15,14,14,18,18,13,11,11,15,15, 0, 0,
+ 21,18,19, 0,21,22,18,19, 0,22, 0,18,19, 0, 0, 0,
+ 0, 0, 0,21,21,18,18, 0,22, 0, 0,21, 0, 0, 0,19,
+ 18, 0, 0, 0,18,19, 0, 0, 0, 0, 0, 0,20,20,18,17,
+ 0, 0,22, 0,21, 0, 0, 0,19,19, 6, 6, 6,13,13, 8,
+ 6, 6,11,11, 9, 7, 7,13,13, 0,10,10,11,11, 0,12,
+ 12,14,14, 9, 8, 8,14,14,12,10,10,13,13,10, 7, 7,
+ 13,13, 0,11,11,15,15, 0,11,11,13,13, 9, 8, 8,14,
+ 14,13,10,10,13,14,11, 7, 7,13,13, 0,11,11,15,15,
+ 0,11,11,13,13, 0,12,12,15,15, 0,21,21,17,17, 0,
+ 10,10,13,13, 0,14,14,20,20, 0,12,12,13,13, 0,12,
+ 12,15,15, 0,21,22,17,18, 0,10,10,13,13, 0,16,16,
+ 20,21, 0,12,12,13,13, 0,11,11,13,13, 0,12,12,16,
+ 16, 0,12,12,16,16, 0,16,16, 0,21, 0,17,18, 0, 0,
+ 0,12,12,15,15, 0,15,15,18,18, 0,12,12,16,16, 0,
+ 16,16,21,22, 0,17,17,22,21, 0,12,12,16,16, 0,15,
+ 15,19,19, 0,12,12,16,16, 0,16,16,22,22, 0,17,16,
+ 22, 0, 0,17,18, 0, 0, 0, 0, 0, 0, 0, 0,15,15,21,
+ 20, 0,19,20, 0,22, 0,18,18, 0, 0, 0,18,17, 0, 0,
+ 0, 0, 0, 0, 0, 0,16,16,22,21, 0,20,20, 0,22, 0,
+ 20,19, 0, 0, 0,11,11,12,12, 0,10,10,11,11, 0,11,
+ 11,12,12, 0,12,12,10,10, 0,13,13,12,12, 0,11,11,
+ 13,13, 0,13,13,12,12, 0,10,10,12,12, 0,13,13,14,
+ 13, 0,12,12,12,12, 0,12,12,13,13, 0,14,14,13,13,
+ 0,10,10,12,12, 0,13,13,14,14, 0,13,12,12,12, 0,
+ 14,14,14,14, 0,21,21,16,16, 0,12,12,12,12, 0,16,
+ 16,20,21, 0,13,13,11,11, 0,14,14,14,14, 0,20,20,
+ 16,15, 0,12,12,12,12, 0,17,17,20,20, 0,13,13,11,
+ 11, 7, 8, 8,16,16,11,10,10,15,15,12,10,10,17,17,
+ 0,14,14,16,15, 0,15,15,17,17,11, 9, 9,16,16,14,
+ 12,12,17,17,13, 9, 9,16,15, 0,14,14,19,18, 0,14,
+ 14,16,16,12,10,10,17,18,16,13,13,17,18,14,10,10,
+ 16,16, 0,14,14,19,19, 0,14,15,17,17, 0,15,15,18,
+ 19, 0, 0, 0,20,20, 0,13,13,17,17, 0,17,18, 0,22,
+ 0,15,15,16,17, 0,15,15,18,18, 0, 0, 0,20,21, 0,
+ 14,14,17,17, 0,19,18, 0, 0, 0,16,16,17,17, 8, 7,
+ 7,14,14,12,11,11,15,15,13,11,11,15,15, 0, 0, 0,
+ 18,19, 0,21,20,18,18,12,10,11,15,16,14,13,13,18,
+ 18,14,11,11,15,15, 0,20,20,19,18, 0,20, 0,18,18,
+ 13,11,11,16,16,17,15,15,19,19,14,12,12,15,15, 0,
+ 21, 0,18,20, 0,22,22,18,19, 0,22,22,19,19, 0, 0,
+ 0, 0, 0, 0,21,22,19,18, 0, 0, 0, 0,21, 0, 0, 0,
+ 19,19, 0, 0,22,20,20, 0, 0, 0, 0, 0, 0,22, 0,18,
+ 18, 0, 0, 0, 0,22, 0, 0, 0,19,20,11,10,10,14,14,
+ 14,11,11,13,13,14,11,11,15,15, 0,14,13,12,12, 0,
+ 15,15,16,16,13,11,11,15,15,16,13,13,15,15,15,10,
+ 10,14,15, 0,14,14,16,16, 0,14,14,15,15,13,11,11,
+ 15,15,18,14,14,15,15,15,10,10,15,14, 0,14,14,16,
+ 16, 0,14,14,15,15, 0,15,15,17,16, 0,21,22,18,18,
+ 0,13,13,14,14, 0,18,17,20,21, 0,15,15,14,14, 0,
+ 15,16,16,17, 0, 0, 0,19,18, 0,13,13,15,14, 0,19,
+ 19, 0, 0, 0,15,15,14,14, 0,12,12,14,13, 0,13,13,
+ 16,16, 0,12,12,16,16, 0,16,16,22, 0, 0,17,18, 0,
+ 22, 0,13,13,16,16, 0,15,15,18,18, 0,12,12,16,16,
+ 0,16,16,22,22, 0,17,17, 0, 0, 0,13,13,17,17, 0,
+ 16,16,19,20, 0,12,12,17,17, 0,17,17,22, 0, 0,17,
+ 17,22,21, 0,18,18, 0, 0, 0, 0, 0, 0, 0, 0,16,16,
+ 21,21, 0,19,19, 0, 0, 0,18,18, 0,22, 0,18,18, 0,
+ 22, 0, 0, 0, 0, 0, 0,16,16,22, 0, 0,20,20, 0, 0,
+ 0,19,18, 0, 0, 0,12,12,15,15, 0,12,12,15,14, 0,
+ 13,13,15,15, 0,14,14,14,14, 0,15,15,16,16, 0,13,
+ 13,15,16, 0,15,15,16,16, 0,12,12,15,15, 0,14,14,
+ 16,16, 0,14,14,15,15, 0,13,13,15,16, 0,15,15,16,
+ 16, 0,12,12,15,15, 0,15,15,17,17, 0,14,14,15,15,
+ 0,15,15,17,17, 0,21,21,19,19, 0,13,13,14,14, 0,
+ 17,17,22, 0, 0,14,14,15,15, 0,15,15,17,17, 0,22,
+ 0,18,20, 0,13,13,15,15, 0,18,18, 0,22, 0,15,15,
+ 14,15, 8, 8, 8,17,16,12,10,10,16,16,13,10,10,17,
+ 16, 0,15,15,17,17, 0,15,15,17,17,12,11,11,18,18,
+ 15,12,12,18,18,15,10,10,16,17, 0,14,14,18,18, 0,
+ 14,14,17,17,13,10,10,16,16,17,14,14,17,17,15,10,
+ 10,16,15, 0,15,15,19,20, 0,14,14,15,16, 0,16,16,
+ 19,19, 0, 0, 0,21,22, 0,13,13,17,17, 0,18,17, 0,
+ 21, 0,15,15,17,17, 0,15,15,18,19, 0, 0,22, 0,21,
+ 0,13,13,16,17, 0,19,19, 0,22, 0,16,15,16,16, 9,
+ 8, 8,14,14,12,11,11,15,15,13,11,11,15,15, 0,21,
+ 20,19,18, 0, 0, 0,19,18,12,11,11,16,15,15,13,13,
+ 17,18,14,11,11,15,15, 0,22,22,19,18, 0,22,21,18,
+ 18,14,11,11,15,15,17,14,14,18,18,15,12,12,15,15,
+ 0,22,22,20,19, 0, 0,21,18,18, 0, 0,22,20,20, 0,
+ 0, 0, 0, 0, 0,20,21,18,18, 0, 0, 0,21,21, 0, 0,
+ 0,20,19, 0,22,21,19,19, 0, 0, 0, 0, 0, 0, 0,22,
+ 17,18, 0, 0,22, 0,22, 0,22, 0,19,19, 0,11,11,15,
+ 15, 0,11,11,14,14, 0,12,12,15,15, 0,15,15,14,14,
+ 0,16,16,16,16, 0,12,12,16,16, 0,14,14,16,16, 0,
+ 11,11,15,15, 0,15,15,17,17, 0,15,15,15,15, 0,12,
+ 12,16,16, 0,14,14,15,15, 0,11,11,15,15, 0,15,15,
+ 17,17, 0,15,15,14,15, 0,16,16,17,17, 0, 0, 0,19,
+ 19, 0,14,14,15,15, 0,18,18,21, 0, 0,15,15,14,15,
+ 0,16,16,17,17, 0,21, 0,19,19, 0,14,14,15,15, 0,
+ 20,20,22, 0, 0,16,15,14,14, 0,12,12,13,13, 0,12,
+ 12,16,16, 0,12,12,16,16, 0,16,16,22,21, 0,18,17,
+ 21, 0, 0,13,13,16,16, 0,15,15,18,19, 0,12,12,16,
+ 16, 0,16,17,22, 0, 0,17,17, 0,22, 0,13,13,17,16,
+ 0,15,15,19,19, 0,12,12,16,16, 0,16,16,21,20, 0,
+ 17,16,22, 0, 0,18,18,22,21, 0, 0, 0, 0, 0, 0,15,
+ 16,21,21, 0,19,19, 0, 0, 0,18,17, 0, 0, 0,18,18,
+ 21, 0, 0, 0, 0, 0, 0, 0,16,16,22,22, 0,20,21, 0,
+ 0, 0,18,19, 0,22, 0,13,13,16,16, 0,12,12,15,15,
+ 0,13,13,16,16, 0,14,14,15,15, 0,15,15,17,17, 0,
+ 13,13,17,16, 0,15,15,17,17, 0,12,12,16,16, 0,15,
+ 15,17,17, 0,14,14,16,16, 0,13,13,16,17, 0,15,15,
+ 17,17, 0,12,12,16,16, 0,14,14,17,17, 0,14,14,16,
+ 16, 0,16,16,17,17, 0,21, 0,21,19, 0,13,13,16,16,
+ 0,17,17, 0, 0, 0,15,15,16,16, 0,16,15,18,18, 0,
+ 22, 0,20,20, 0,13,13,15,15, 0,18,18, 0, 0, 0,15,
+ 15,15,15, 0,12,12,17,17, 0,14,14,17,17, 0,14,14,
+ 17,17, 0,17,17,18,17, 0,17,17,19,18, 0,13,13,17,
+ 17, 0,16,16,18,18, 0,13,13,16,16, 0,17,17,19,19,
+ 0,16,16,17,17, 0,13,13,18,18, 0,17,17,18,18, 0,
+ 13,13,17,17, 0,17,17,19,19, 0,16,17,17,17, 0,17,
+ 17,19,19, 0,21, 0,21,19, 0,14,14,16,16, 0,20,19,
+ 0,21, 0,16,16,16,16, 0,17,18,19,19, 0, 0, 0, 0,
+ 21, 0,15,15,16,17, 0,21,20, 0, 0, 0,17,18,16,17,
+ 0, 9, 9,14,14, 0,14,14,15,16, 0,14,14,15,15, 0,
+ 0, 0,18,18, 0,21, 0,18,19, 0,12,12,15,15, 0,16,
+ 16,17,17, 0,14,14,14,14, 0,22, 0,19,18, 0,22, 0,
+ 17,18, 0,14,14,16,15, 0,18,18,19,18, 0,14,15,15,
+ 15, 0, 0,21,20,20, 0, 0, 0,18,18, 0,21,21,19,19,
+ 0, 0, 0, 0, 0, 0,21,21,18,18, 0,22, 0,20,20, 0,
+ 22, 0,19,19, 0,22, 0,19,20, 0, 0, 0, 0, 0, 0, 0,
+ 21,17,18, 0, 0, 0,22,22, 0, 0, 0,19,18, 0,18,20,
+ 16,16, 0,21,20,17,17, 0, 0,21,18,18, 0,22,21,18,
+ 18, 0, 0,22,19,19, 0,20,20,17,17, 0, 0, 0,18,18,
+ 0,19,20,17,17, 0,22, 0,19,21, 0,22,21,18,18, 0,
+ 20,19,17,18, 0, 0, 0,19,19, 0,20,20,17,17, 0,22,
+ 22,21,21, 0,20, 0,18,18, 0,22,22,18,18, 0, 0, 0,
+ 20,22, 0,20,20,16,16, 0, 0, 0,21, 0, 0,21,20,16,
+ 17, 0,22, 0,19,20, 0, 0, 0,21,20, 0,19,21,17,17,
+ 0, 0, 0, 0, 0, 0,21,21,17,17, 0,12,12,13,13, 0,
+ 14,14,16,16, 0,14,14,16,16, 0,18,18, 0, 0, 0,19,
+ 18,22, 0, 0,13,13,16,16, 0,16,16,18,18, 0,13,13,
+ 16,16, 0,17,18,21, 0, 0,18,18,21, 0, 0,13,13,16,
+ 16, 0,17,17,19,20, 0,13,13,16,17, 0,18,18,21, 0,
+ 0,18,18,21, 0, 0,18,19, 0,21, 0, 0, 0, 0, 0, 0,
+ 16,16,21,20, 0,20,20, 0, 0, 0,18,19, 0, 0, 0,18,
+ 18, 0, 0, 0, 0, 0, 0, 0, 0,16,16, 0,21, 0,22,22,
+ 0, 0, 0,19,19, 0, 0, 0,16,16,19,20, 0,17,16,22,
+ 21, 0,17,17,21,20, 0,19,18, 0,22, 0,19,19,22,22,
+ 0,16,15,22,22, 0,19,19, 0,21, 0,15,15,20,20, 0,
+ 18,19, 0,21, 0,18,18,22,22, 0,16,16,21,20, 0,20,
+ 19,21,22, 0,16,15,20,20, 0,19,19, 0,22, 0,18,18,
+ 21, 0, 0,19,18,21,22, 0, 0, 0, 0, 0, 0,16,16,19,
+ 21, 0,20,22, 0,22, 0,18,18,20,21, 0,19,18, 0,22,
+ 0, 0, 0,22, 0, 0,16,16,20,20, 0,21,21, 0, 0, 0,
+ 18,18,21, 0, 0,12,12,17,17, 0,15,14,17,17, 0,14,
+ 14,18,18, 0,17,17,17,18, 0,18,18,18,18, 0,13,13,
+ 18,18, 0,16,17,19,18, 0,13,13,16,17, 0,17,17,18,
+ 19, 0,17,17,17,17, 0,13,13,17,17, 0,17,18,18,18,
+ 0,13,13,16,16, 0,18,18,19,20, 0,16,17,17,16, 0,
+ 17,18,19,18, 0, 0, 0,22,21, 0,15,15,16,16, 0,20,
+ 20,21,22, 0,17,17,16,16, 0,16,17,18,18, 0, 0, 0,
+ 21,21, 0,15,15,16,16, 0,21,20, 0, 0, 0,17,17,16,
+ 16, 0,10,10,14,14, 0,14,14,15,15, 0,14,14,15,15,
+ 0,22, 0,18,18, 0, 0, 0,19,19, 0,13,13,15,16, 0,
+ 17,16,18,18, 0,14,14,15,15, 0,21,21,19,18, 0,22,
+ 21,18,17, 0,14,14,15,15, 0,18,18,19,18, 0,15,15,
+ 14,14, 0,22,21,19,19, 0,22,21,17,18, 0, 0, 0,19,
+ 19, 0, 0, 0, 0, 0, 0,20,22,17,17, 0, 0,22,22,20,
+ 0, 0, 0,19,18, 0,21,22,19,18, 0, 0, 0, 0, 0, 0,
+ 22,22,17,18, 0, 0, 0,21,22, 0, 0, 0,19,18, 0,20,
+ 20,17,17, 0,21,21,17,18, 0,21,22,18,18, 0,21, 0,
+ 18,18, 0,22, 0,19,19, 0,19,21,18,18, 0, 0,22,18,
+ 18, 0,22,21,17,17, 0,22, 0,20,20, 0, 0, 0,18,18,
+ 0,22,21,18,18, 0,21, 0,19,19, 0,20,21,17,17, 0,
+ 0,22,22,20, 0,21,22,17,17, 0, 0,21,19,18, 0, 0,
+ 0,21,21, 0,21,20,16,17, 0, 0, 0, 0, 0, 0,21, 0,
+ 17,17, 0,21, 0,19,20, 0, 0, 0,20,22, 0,20,20,17,
+ 17, 0, 0, 0, 0, 0, 0,21,21,17,17, 0,12,12,13,13,
+ 0,14,14,16,16, 0,14,14,16,16, 0,18,18,21, 0, 0,
+ 19,19,22, 0, 0,13,13,16,16, 0,16,16,18,18, 0,13,
+ 13,16,16, 0,18,18,21,22, 0,18,18, 0,22, 0,13,13,
+ 16,16, 0,17,17,20,18, 0,13,13,16,16, 0,19,18, 0,
+ 22, 0,18,18,22,21, 0,18,19, 0, 0, 0, 0, 0, 0, 0,
+ 0,16,16,21,21, 0,21,21, 0, 0, 0,18,19, 0, 0, 0,
+ 19,19,21, 0, 0, 0, 0, 0, 0, 0,16,16, 0,21, 0,20,
+ 20, 0, 0, 0,20,20, 0, 0, 0,16,16,21,20, 0,18,17,
+ 21,22, 0,17,18, 0,21, 0,18,19,22,22, 0,19,19, 0,
+ 22, 0,16,17,21,22, 0,20,19, 0, 0, 0,16,16,20,21,
+ 0,19,19, 0, 0, 0,19,19, 0,22, 0,17,17,21,21, 0,
+ 19,20, 0, 0, 0,16,16, 0,20, 0,19,20, 0,21, 0,18,
+ 18, 0,22, 0,19,20,22,22, 0, 0, 0, 0,22, 0,17,17,
+ 0,21, 0,21,21, 0, 0, 0,18,19,23,21, 0,20,19, 0,
+ 0, 0, 0, 0, 0, 0, 0,17,17, 0,20, 0, 0, 0, 0, 0,
+ 0,19,19,23,22,
+};
+
+static const static_codebook _44p4_p5_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p4_p5_0,
+ 1, -528744448, 1616642048, 3, 0,
+ (long *)_vq_quantlist__44p4_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p5_1[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44p4_p5_1[] = {
+ 2, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _44p4_p5_1 = {
+ 1, 7,
+ (char *)_vq_lengthlist__44p4_p5_1,
+ 1, -533200896, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p4_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p4_p6_0[] = {
+ 1, 7, 7, 7, 8, 8, 7, 8, 8, 7, 9, 9,11,11,11, 9,
+ 8, 8, 8, 9, 9,12,11,12, 9, 8, 8, 6, 7, 7,10,11,
+ 11,10,10,10,11,11,11,14,14,14,12,11,12,11,11,11,
+ 15,15,14,13,12,12, 5, 6, 6, 8, 5, 5, 8, 7, 7, 8,
+ 7, 7,12,10,10,10, 7, 6, 9, 8, 8,12,10,10,10, 6,
+ 6, 7, 8, 8,12,10,10,12,10,10,11,10,10,16,14,14,
+ 13,10,10,12,10,10,15,14,14,14,10,10, 7, 7, 7,13,
+ 11,11,13,11,11,12,11,11,16,14,14,14,12,12,12,11,
+ 11,18,15,15,14,12,12,10, 9,10,14,11,11,13,11,11,
+ 12,11,11,17,14,14,14,11,11,13,11,11,16,15,15,14,
+ 11,11, 7, 8, 8,13,11,11,12,10,10,12,10,10,16,14,
+ 13,13,10,10,12,10,10,17,14,14,14,10,10, 8, 7, 7,
+ 12,11,11,13,11,11,12,11,11,16,15,14,14,12,12,12,
+ 11,11,16,15,15,14,12,12,11,10,10,14,11,11,13,11,
+ 11,13,11,11,17,14,14,14,11,11,13,11,11,18,14,15,
+ 15,11,10,
+};
+
+static const static_codebook _44p4_p6_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p4_p6_0,
+ 1, -527106048, 1620377600, 2, 0,
+ (long *)_vq_quantlist__44p4_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p6_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p4_p6_1[] = {
+ 2, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,
+ 7, 7, 8, 8, 8, 9, 9, 9, 9, 8, 8, 6, 7, 7, 8, 8,
+ 8, 8, 8, 8, 9, 8, 8, 9, 8, 9, 9, 8, 8,10, 8, 8,
+ 10, 9, 9,10, 8, 8, 6, 6, 6, 8, 6, 6, 8, 7, 7, 8,
+ 7, 7,10, 8, 8, 9, 7, 7, 9, 7, 7,10, 8, 8, 9, 7,
+ 7, 7, 7, 7,10, 8, 8,11, 9, 9,10, 9, 9,11, 9, 9,
+ 11, 8, 8,11, 9, 9,12, 9, 9,12, 8, 8, 7, 7, 7,10,
+ 9, 9,10, 9, 9,10, 9, 9,11,10,10,10, 9, 9,11, 9,
+ 10,11,10,11,10, 9, 9, 9, 8, 8,10, 9, 9,10, 9, 9,
+ 11, 9, 9,11,10,10,11, 9, 9,11, 9, 9,11,10,10,11,
+ 9, 9, 8, 8, 8,11, 9, 9,11, 9, 9,11, 9, 9,12, 9,
+ 9,12, 8, 8,11, 9, 9,12, 9, 9,12, 8, 8, 8, 7, 7,
+ 10, 9, 9,10, 9, 9,10, 9, 9,11,11,11,11, 9, 9,11,
+ 10,10,11,11,11,11, 9, 9,10, 9, 9,11, 9, 9,11, 9,
+ 10,11,10,10,11,10,10,11, 9, 9,11,10,10,11,10,10,
+ 11, 9, 9,
+};
+
+static const static_codebook _44p4_p6_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p4_p6_1,
+ 1, -530841600, 1616642048, 2, 0,
+ (long *)_vq_quantlist__44p4_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p4_p7_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p4_p7_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p4_p7_0,
+ 1, -513979392, 1633504256, 2, 0,
+ (long *)_vq_quantlist__44p4_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p7_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p4_p7_1[] = {
+ 1, 9, 9, 7, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8,
+ 9, 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 7, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 5, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 5,10, 9,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10, 8,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,
+};
+
+static const static_codebook _44p4_p7_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p4_p7_1,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p4_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p7_2[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p4_p7_2[] = {
+ 1, 3, 2, 5, 4, 7, 7, 8, 8, 9, 9,10,10,11,11,12,
+ 12,13,13,14,14,15,15,15,15,
+};
+
+static const static_codebook _44p4_p7_2 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p4_p7_2,
+ 1, -518864896, 1620639744, 5, 0,
+ (long *)_vq_quantlist__44p4_p7_2,
+ 0
+};
+
+static const long _vq_quantlist__44p4_p7_3[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p4_p7_3[] = {
+ 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p4_p7_3 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p4_p7_3,
+ 1, -529006592, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44p4_p7_3,
+ 0
+};
+
+static const char _huff_lengthlist__44p4_short[] = {
+ 3, 5,16, 9, 9,13,18,21, 4, 2,21, 6, 6,10,15,21,
+ 16,19, 6, 5, 7,10,13,16, 8, 6, 5, 4, 4, 8,13,16,
+ 8, 5, 6, 4, 4, 7,12,15,13,10, 9, 7, 7, 9,13,16,
+ 18,15,13,12, 9, 7,10,14,21,18,13,13, 7, 5, 8,12,
+};
+
+static const static_codebook _huff_book__44p4_short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p4_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p5_l0_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44p5_l0_0[] = {
+ 1, 4, 4, 8, 8,10,10,10,10, 9, 8,11,11, 4, 6, 5,
+ 8, 6,10,10,10,10,10, 9,10, 9, 4, 5, 6, 6, 9,10,
+ 10,10,10, 9,10, 9,10, 8, 9, 8, 9, 8, 9, 9,10, 9,
+ 11,10,12,10, 8, 8, 9, 8, 9, 9, 9, 9,10,10,11,10,
+ 12, 9,10,10,11,10,11,10,12,11,12,11,13,11, 9,10,
+ 10,10,11,10,11,11,12,11,12,11,12,11,12,12,12,12,
+ 13,12,13,12,13,12,13,13,11,12,12,12,12,12,12,12,
+ 13,13,13,13,13,12,12,12,13,13,13,13,13,13,13,13,
+ 13,13,12,13,12,13,13,13,13,13,13,13,13,13,13,12,
+ 13,13,13,14,14,13,13,13,13,13,13,13,12,13,12,13,
+ 13,13,13,13,13,13,13,13,13,
+};
+
+static const static_codebook _44p5_l0_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44p5_l0_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44p5_l0_0,
+ 0
+};
+
+static const long _vq_quantlist__44p5_l0_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p5_l0_1[] = {
+ 4, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 4, 4, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p5_l0_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p5_l0_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p5_l0_1,
+ 0
+};
+
+static const long _vq_quantlist__44p5_l1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p5_l1_0[] = {
+ 1, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+
+static const static_codebook _44p5_l1_0 = {
+ 2, 9,
+ (char *)_vq_lengthlist__44p5_l1_0,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p5_l1_0,
+ 0
+};
+
+static const char _huff_lengthlist__44p5_lfe[] = {
+ 1, 3, 2, 3,
+};
+
+static const static_codebook _huff_book__44p5_lfe = {
+ 2, 4,
+ (char *)_huff_lengthlist__44p5_lfe,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44p5_long[] = {
+ 3, 7,12,14,14,16,18,19, 6, 2, 4, 6, 8, 9,12,14,
+ 12, 3, 3, 5, 7, 8,11,13,13, 6, 4, 5, 7, 8,10,11,
+ 14, 8, 7, 7, 7, 7, 9,10,15, 9, 8, 7, 7, 6, 8, 9,
+ 17,11,11,10, 9, 8, 9, 9,19,14,13,11,10, 9, 9, 9,
+};
+
+static const static_codebook _huff_book__44p5_long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p5_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p5_p1_0[] = {
+ 2, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 8, 9, 7,
+ 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 5, 7, 8, 8, 9,
+ 10, 8, 9,10, 8, 9,10, 9,10,12,10,11,11, 8,10,10,
+ 10,11,11, 9,11,11, 5, 8, 7, 8, 9, 9, 8,10, 9, 8,
+ 10,10, 9,11,11,10,11,11, 8,10, 9,10,11,11, 9,12,
+ 10, 5, 8, 8, 7, 9,10, 8,10, 9, 7, 9, 9, 9,10,11,
+ 9,11,11, 8,10, 9,10,11,11,10,11,11, 7, 9, 9, 9,
+ 10,11, 9,11,11, 9, 9,11,10,10,13,11,11,12, 9,11,
+ 11,11,12,13,11,13,12, 7, 9, 9, 9,11,11, 9,11,10,
+ 9,11,10,10,11,12,11,13,12, 9,11,11,11,12,13,11,
+ 13,11, 5, 8, 8, 8, 9,10, 7,10, 9, 8, 9,10,10,11,
+ 11,10,11,11, 7, 9, 9, 9,11,11, 9,11,10, 7, 9, 9,
+ 9,10,11, 9,11,11, 9,11,11,11,11,13,11,13,12, 9,
+ 10,11,11,12,13,10,12,11, 7, 9, 9, 9,11,11, 9,11,
+ 10, 9,11,11,11,12,13,11,13,12, 9,11, 9,11,12,11,
+ 10,13,10,
+};
+
+static const static_codebook _44p5_p1_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p5_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p5_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p5_p2_0[] = {
+ 4, 6, 6, 9, 9, 6, 7, 8,10,10, 6, 8, 7,10,10, 8,
+ 10,10,12,13, 8,10,10,13,12, 6, 7, 8,10,10, 7, 8,
+ 9,10,11, 8, 9, 9,11,11,10,10,11,12,14,10,11,11,
+ 14,13, 6, 8, 7,10,10, 8, 9, 9,11,11, 7, 9, 8,11,
+ 10,10,11,11,13,14,10,11,10,14,12, 9,10,10,12,12,
+ 10,10,11,12,13,10,11,11,13,13,12,12,13,12,15,13,
+ 14,13,15,14, 9,10,10,12,12,10,11,11,13,13,10,11,
+ 10,13,12,13,13,14,14,15,12,13,12,15,12, 6, 7, 8,
+ 10,11, 8, 9,10,11,12, 8, 9, 9,11,12,10,11,12,13,
+ 14,10,11,11,14,13, 8, 9,10,11,12, 9,10,11,12,13,
+ 9,10,11,12,13,11,12,13,13,15,12,12,13,15,14, 8,
+ 9, 9,12,12, 9,10,11,12,13, 9,10,10,13,12,12,12,
+ 13,14,15,11,12,12,14,14,11,11,12,13,14,11,12,13,
+ 13,15,12,13,13,14,15,14,13,15,14,16,14,15,15,16,
+ 16,11,12,11,14,13,12,13,13,15,14,11,13,12,14,13,
+ 14,15,15,15,16,13,14,14,16,14, 6, 8, 7,11,10, 8,
+ 9, 9,11,12, 8,10, 9,12,11,10,11,11,13,14,10,12,
+ 11,14,13, 8, 9, 9,12,12, 9,10,10,12,13, 9,11,10,
+ 13,12,11,12,12,13,14,12,13,12,15,14, 8,10, 9,12,
+ 11, 9,11,10,13,12, 9,11,10,13,12,12,13,12,14,15,
+ 11,13,12,15,13,11,11,12,13,14,11,12,13,13,15,12,
+ 13,13,14,15,13,14,14,14,16,14,15,15,16,16,11,12,
+ 11,14,13,12,13,13,15,14,11,13,12,15,13,14,15,15,
+ 16,16,13,15,13,16,14, 9,10,11,12,14,11,11,12,13,
+ 15,11,12,12,13,14,13,14,15,15,17,13,14,14,15,16,
+ 11,11,12,13,15,12,12,13,14,16,12,13,13,14,15,14,
+ 14,16,15,17,15,15,15,16,17,11,12,12,14,14,12,13,
+ 13,15,16,12,13,13,15,15,15,15,15,16,17,14,15,15,
+ 16,16,14,14,15,15,17,14,15,15,15,17,15,15,16,16,
+ 17,16,16,17,16,18,17,17,17,18,18,14,15,14,16,16,
+ 15,15,16,17,17,14,15,15,17,16,17,17,17,18,18,16,
+ 16,16,17,17, 9,11,10,14,12,11,12,12,14,13,11,12,
+ 11,15,13,13,14,14,16,15,13,15,14,17,15,11,12,12,
+ 15,14,12,13,13,15,15,12,13,13,15,15,14,15,15,16,
+ 16,15,15,15,17,16,11,12,11,15,13,12,13,13,15,14,
+ 12,13,12,16,14,15,15,15,17,16,14,15,14,17,15,14,
+ 14,15,16,16,14,15,15,16,16,15,16,15,17,17,16,16,
+ 16,17,17,17,17,17,18,17,14,15,14,16,15,15,15,15,
+ 17,16,15,15,15,17,15,17,17,17,18,18,16,17,16,18,
+ 16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12,11,
+ 10,11,11,13,14,10,12,11,14,13, 7, 9, 9,11,12, 9,
+ 10,10,12,13, 9,10,10,13,13,11,11,12,13,15,11,12,
+ 12,15,14, 8, 9, 9,12,11, 9,11,10,13,13, 9,11,10,
+ 13,12,12,13,12,14,15,11,13,12,15,13,10,11,12,13,
+ 14,11,12,12,13,15,12,12,13,14,15,13,13,14,14,16,
+ 14,15,15,16,16,11,12,11,14,13,12,13,13,15,14,11,
+ 13,12,15,13,14,15,15,15,16,13,14,14,16,14, 7, 9,
+ 9,11,12, 9,10,11,12,13, 9,10,10,13,12,11,12,12,
+ 14,15,11,12,12,15,14, 9, 9,11,11,13,10,10,12,12,
+ 14,10,11,12,13,14,12,12,13,14,16,12,13,13,15,15,
+ 9,11,10,13,13,10,12,12,13,14,10,12,11,14,13,12,
+ 13,13,15,16,12,13,13,15,14,11,11,13,13,15,12,12,
+ 14,13,16,13,13,13,14,15,14,14,15,14,17,15,15,15,
+ 16,16,12,13,12,15,14,13,14,14,15,15,12,14,13,16,
+ 14,15,15,16,16,17,14,15,14,17,15, 7, 9, 9,12,11,
+ 9,10,10,12,13, 9,11,10,13,12,11,12,12,14,14,11,
+ 13,12,15,14, 9,10,10,13,12,10,10,11,12,13,10,12,
+ 11,14,13,12,12,13,13,15,12,14,13,16,15, 9,10,10,
+ 13,12,11,11,12,13,13,10,12,10,14,12,13,13,13,15,
+ 15,12,13,12,15,13,11,12,12,14,14,12,12,13,14,15,
+ 13,14,13,15,15,14,13,15,13,16,15,16,15,17,16,12,
+ 13,12,14,14,13,14,14,15,15,12,13,12,15,14,15,15,
+ 16,16,17,14,15,13,16,13,10,11,12,13,14,11,12,13,
+ 14,15,12,13,13,15,15,14,14,15,15,17,14,15,15,16,
+ 16,12,12,13,12,15,12,12,14,13,16,13,13,14,14,16,
+ 14,14,16,15,17,15,15,16,16,17,12,13,13,15,15,13,
+ 14,14,16,16,13,14,13,16,15,15,16,16,17,17,14,15,
+ 15,17,16,14,14,15,14,17,15,15,16,15,17,15,15,16,
+ 15,17,16,16,17,16,18,17,17,17,17,18,14,15,15,17,
+ 16,15,16,16,17,17,15,16,15,17,16,17,17,17,18,18,
+ 16,17,16,18,17,10,12,11,14,14,12,13,13,15,15,12,
+ 13,12,15,14,14,15,15,16,16,14,15,15,17,16,11,13,
+ 12,15,14,12,13,13,15,15,13,14,13,16,14,15,15,15,
+ 16,16,15,16,15,17,16,12,13,13,15,15,13,14,14,16,
+ 16,12,14,13,16,15,15,16,16,17,17,15,16,15,17,16,
+ 14,15,15,16,16,14,15,15,16,16,15,16,16,17,16,16,
+ 16,16,16,17,17,18,17,18,17,14,15,15,17,16,15,16,
+ 16,17,17,15,16,15,17,16,17,17,18,18,18,16,17,16,
+ 18,16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12,
+ 11,10,11,12,13,14,10,11,11,14,13, 8, 9, 9,11,12,
+ 9,10,11,12,13, 9,10,11,13,13,11,12,13,13,15,12,
+ 12,12,15,14, 7, 9, 9,12,11, 9,10,10,13,13, 9,10,
+ 10,13,12,11,12,12,14,15,11,12,11,15,13,11,11,12,
+ 13,14,11,12,13,13,15,12,13,13,14,15,13,14,14,14,
+ 16,14,15,15,16,16,10,12,11,14,13,12,13,12,14,14,
+ 11,12,12,15,13,14,15,15,16,16,13,14,13,16,14, 7,
+ 9, 9,11,12, 9,10,11,12,13, 9,10,10,13,12,11,12,
+ 13,14,15,11,12,12,14,14, 9,10,10,12,13,10,10,12,
+ 12,14,11,12,11,13,13,12,12,14,13,15,13,13,13,15,
+ 15, 9,10,10,12,13,10,11,12,13,14,10,11,10,13,12,
+ 13,13,14,15,16,12,13,12,15,13,12,13,13,14,14,12,
+ 12,13,14,15,13,14,14,15,15,14,13,15,13,16,15,16,
+ 15,17,16,11,12,12,14,14,13,13,14,15,15,12,13,12,
+ 15,14,15,15,16,16,17,14,14,13,16,13, 7, 9, 9,12,
+ 11, 9,10,10,12,13, 9,11,10,13,12,11,12,12,14,15,
+ 11,12,12,15,14, 9,10,11,13,13,10,11,12,13,14,10,
+ 12,12,14,13,12,13,13,14,16,12,13,13,16,15, 9,11,
+ 9,13,11,10,12,11,13,13,10,12,10,14,12,12,13,13,
+ 15,15,12,13,12,16,14,12,12,13,14,15,12,13,14,14,
+ 15,13,14,14,15,15,14,14,15,15,17,15,16,15,17,16,
+ 11,13,11,15,13,13,14,13,15,14,12,14,12,16,13,15,
+ 15,15,16,16,14,15,14,17,14,10,11,12,14,14,12,12,
+ 13,14,15,12,13,13,15,15,14,15,15,16,17,14,15,15,
+ 16,16,12,12,13,15,15,13,13,14,15,16,13,14,14,16,
+ 16,15,15,16,16,17,15,16,16,17,17,11,12,13,14,15,
+ 13,13,14,15,16,12,13,13,15,15,15,15,16,16,17,15,
+ 15,15,16,16,14,15,15,16,17,15,15,16,16,17,15,16,
+ 16,17,17,16,16,17,16,18,17,17,17,18,18,14,15,15,
+ 16,16,15,16,16,16,17,15,15,15,16,16,17,17,17,18,
+ 18,16,16,16,17,16,10,12,11,14,13,12,13,13,15,15,
+ 11,13,12,15,14,14,15,15,16,16,14,15,14,17,15,12,
+ 13,13,15,15,13,13,14,16,16,13,14,14,16,16,15,15,
+ 15,16,17,15,16,16,17,17,12,13,12,15,12,13,14,13,
+ 16,14,12,14,12,16,13,15,16,15,17,16,14,16,14,17,
+ 15,14,15,15,16,17,15,15,16,17,17,15,16,16,17,17,
+ 16,16,17,17,18,17,18,17,18,18,14,15,14,17,14,15,
+ 16,15,17,15,15,16,15,17,15,17,17,17,18,17,16,17,
+ 16,18,16, 9,11,11,14,14,11,12,12,14,14,11,12,12,
+ 15,14,13,14,14,16,16,13,15,14,16,16,10,11,12,14,
+ 14,11,12,13,15,15,12,13,13,15,15,13,14,15,16,17,
+ 14,15,15,17,16,11,12,12,15,14,12,13,13,15,15,12,
+ 13,13,15,15,14,15,15,16,16,14,15,15,17,16,12,13,
+ 14,15,16,13,14,14,15,16,13,14,15,16,16,15,15,16,
+ 16,18,16,16,16,18,17,14,14,14,16,15,15,15,15,17,
+ 16,14,15,15,17,16,16,17,17,18,17,16,16,16,18,16,
+ 10,12,12,14,14,11,12,13,15,15,12,13,13,15,15,13,
+ 14,15,16,17,14,15,15,17,16,11,12,13,14,15,12,12,
+ 14,15,16,13,13,14,15,16,14,14,15,16,17,15,15,16,
+ 17,17,12,13,13,15,15,13,14,14,16,16,13,14,13,16,
+ 15,15,16,15,17,17,15,16,15,17,16,13,13,15,14,17,
+ 14,13,16,15,17,15,14,16,15,17,15,15,17,16,18,16,
+ 16,17,17,18,14,15,15,17,16,15,16,16,17,17,15,16,
+ 15,17,16,17,17,17,18,18,16,17,16,18,17,10,12,11,
+ 14,14,11,12,13,15,15,12,13,12,15,15,14,15,15,16,
+ 16,14,15,15,17,16,11,12,12,15,15,12,13,13,15,15,
+ 13,14,13,16,15,14,15,15,16,16,15,16,15,17,16,11,
+ 13,13,15,15,13,14,14,15,15,12,14,13,16,15,15,16,
+ 15,17,17,15,16,15,17,16,13,15,14,16,16,14,15,14,
+ 16,16,15,16,15,17,16,15,16,16,16,17,16,17,16,18,
+ 17,14,15,15,16,16,15,16,16,17,17,15,15,15,17,16,
+ 17,17,17,18,18,16,16,16,18,16,12,13,13,15,16,13,
+ 14,14,15,16,13,14,14,16,16,15,15,16,16,18,15,16,
+ 16,17,17,13,13,14,15,16,14,14,15,15,17,14,15,15,
+ 16,17,15,15,17,16,18,16,16,17,17,17,13,14,14,16,
+ 16,14,15,15,17,17,14,15,14,17,16,16,17,16,17,18,
+ 16,17,16,18,17,15,15,16,14,17,16,15,17,14,18,16,
+ 16,16,15,18,16,16,18,15,19,18,18,18,17,19,15,16,
+ 16,18,17,16,17,17,18,17,16,17,16,18,17,18,18,18,
+ 19,19,17,18,16,18,17,11,12,12,15,15,13,13,14,15,
+ 16,13,14,13,16,15,15,16,16,16,17,15,16,16,17,16,
+ 12,14,13,16,15,13,13,14,15,16,14,15,14,17,15,15,
+ 15,16,16,17,16,17,16,18,17,12,13,14,15,16,14,15,
+ 15,16,16,13,14,13,16,15,16,16,16,17,17,15,16,15,
+ 17,15,15,16,15,17,16,15,15,15,16,16,16,17,16,18,
+ 16,16,15,16,15,17,17,18,17,18,17,15,15,16,17,17,
+ 16,16,17,17,17,15,16,15,17,16,18,18,18,18,18,16,
+ 17,16,18,15, 9,11,11,14,14,11,12,12,14,15,10,12,
+ 12,15,14,13,14,15,16,16,13,14,14,16,16,11,12,12,
+ 14,15,12,12,13,15,15,12,13,13,15,15,14,15,15,16,
+ 17,14,15,15,16,16,10,12,12,14,14,12,13,13,15,15,
+ 11,13,12,15,15,14,15,15,16,17,13,15,14,16,16,14,
+ 14,14,15,16,14,15,15,16,17,14,15,15,16,17,16,16,
+ 17,16,18,16,17,17,17,17,12,14,13,16,15,13,15,14,
+ 16,16,13,14,14,16,15,16,16,16,17,17,15,16,15,17,
+ 16,10,11,11,14,14,12,12,13,14,15,11,13,12,15,14,
+ 14,15,15,16,17,14,15,15,16,16,12,13,13,15,15,12,
+ 13,14,15,16,13,14,14,15,15,15,15,16,16,17,15,15,
+ 16,17,17,11,12,12,15,15,13,13,14,15,16,12,13,13,
+ 15,15,15,15,16,16,17,14,15,15,16,16,14,15,15,16,
+ 16,15,15,15,16,17,15,16,16,17,17,16,16,17,16,18,
+ 17,17,17,17,18,13,14,15,16,16,15,15,16,16,17,14,
+ 14,14,16,16,16,16,17,17,18,16,16,16,17,16,10,12,
+ 12,14,14,12,13,13,15,15,11,13,12,15,15,14,15,15,
+ 16,17,13,15,14,17,16,12,13,13,15,15,13,13,14,15,
+ 16,13,14,14,16,16,15,15,16,16,17,15,15,16,17,17,
+ 11,13,12,15,14,13,14,13,16,15,12,14,12,16,15,15,
+ 16,15,17,17,14,15,14,17,16,14,15,15,16,17,15,15,
+ 16,16,17,15,16,16,17,17,16,16,17,17,18,17,17,17,
+ 18,18,13,15,13,17,14,14,16,14,17,16,14,15,13,17,
+ 15,16,17,16,18,17,15,17,15,18,16,11,12,12,15,15,
+ 13,13,14,15,16,13,14,13,16,15,15,16,16,16,17,15,
+ 16,16,17,16,12,14,13,16,15,13,13,14,15,16,14,15,
+ 15,16,16,16,15,16,16,17,16,16,16,17,17,12,13,14,
+ 15,16,14,14,15,15,17,13,14,13,16,15,16,16,17,17,
+ 18,15,16,15,17,15,15,16,15,17,17,15,15,16,16,17,
+ 16,17,16,17,17,16,15,17,15,18,17,18,17,18,18,15,
+ 15,16,16,17,16,16,17,16,18,15,15,15,16,16,17,17,
+ 18,17,18,16,16,15,17,15,12,13,13,15,15,13,14,14,
+ 16,16,13,14,14,16,16,15,16,16,17,18,15,16,15,18,
+ 16,13,14,14,16,16,14,14,15,16,17,14,15,15,17,17,
+ 16,16,17,17,18,16,16,17,18,17,13,14,13,16,14,14,
+ 15,15,17,16,14,15,14,17,15,16,17,17,18,17,15,17,
+ 15,18,16,15,16,16,17,17,16,16,17,17,18,16,17,17,
+ 18,18,17,16,18,17,19,18,18,18,18,18,15,16,15,17,
+ 14,16,16,16,18,15,16,17,15,18,14,18,18,18,18,17,
+ 17,18,16,19,15,
+};
+
+static const static_codebook _44p5_p2_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p5_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p5_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p3_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p5_p3_0[] = {
+ 1, 5, 6, 5, 7, 8, 5, 8, 7, 5, 7, 8, 7, 8,10, 8,
+ 10,10, 5, 8, 7, 8,10,10, 7,10, 8, 6, 8, 9, 8,10,
+ 11, 9,10,10, 9,10,11,10,11,12,11,12,12, 9,11,10,
+ 11,12,12,10,12,11, 6, 9, 8, 9,10,10, 8,11,10, 9,
+ 10,11,10,11,12,11,12,12, 9,11,10,11,12,12,10,12,
+ 11, 6, 9, 9, 8,10,11, 9,11,10, 8,10,10,10,10,12,
+ 11,12,12, 9,11,10,11,12,12,10,12,11, 8,10,10,10,
+ 11,12,10,12,11,10,10,12,11,11,13,12,13,13,10,12,
+ 11,12,13,13,11,13,11, 7,10,10,10,11,12,10,12,11,
+ 10,12,11,11,11,12,12,14,13,10,12,12,12,14,14,11,
+ 13,11, 6, 9, 9, 9,10,11, 8,11,10, 9,10,11,10,11,
+ 12,11,12,12, 8,11,10,11,12,12,10,12,10, 7,10,10,
+ 10,11,12,10,12,11,10,12,12,11,11,13,12,13,13,10,
+ 11,12,12,13,14,11,12,11, 8,10,10,10,11,12,10,12,
+ 11,10,11,12,11,11,13,12,13,13,10,12,10,12,13,13,
+ 11,13,11,
+};
+
+static const static_codebook _44p5_p3_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p5_p3_0,
+ 1, -533200896, 1614282752, 2, 0,
+ (long *)_vq_quantlist__44p5_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p3_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p5_p3_1[] = {
+ 5, 6, 6, 6, 7, 7, 6, 7, 7, 6, 7, 7, 7, 7, 8, 7,
+ 8, 8, 6, 7, 7, 7, 8, 8, 7, 8, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8,
+ 8, 9, 9, 8, 9, 9, 7, 8, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9,
+ 8, 6, 8, 8, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 9,
+ 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8, 8,
+ 9, 9, 8, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 7, 8, 8, 8, 8, 9, 8, 9, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9, 8,
+ 9, 9, 6, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8,
+ 9, 8, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8,
+ 8, 8, 9, 8, 9, 8, 8, 8, 9, 8, 9, 9, 9, 9, 9, 8,
+ 8, 8, 9, 9, 9, 8, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9,
+ 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p5_p3_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p5_p3_1,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p5_p3_1,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p4_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p5_p4_0[] = {
+ 1, 5, 5, 5, 7, 9, 5, 9, 7, 5, 7, 8, 7, 7,10, 9,
+ 10,10, 5, 8, 7, 9,10,10, 7,10, 7, 6, 8, 9, 9,10,
+ 12, 9,11,11, 9,10,11,11,11,13,12,13,13, 9,11,11,
+ 11,12,13,11,13,11, 6, 9, 8, 9,11,11, 9,12,10, 9,
+ 11,11,11,11,13,11,13,12, 9,11,10,12,13,13,11,13,
+ 11, 6, 9, 9, 8,10,11, 9,12,11, 9,10,11,10,10,12,
+ 11,13,13, 9,11,11,11,13,12,11,13,11, 8,10,10, 9,
+ 10,12,10,12,11,10,10,12,10,10,13,12,13,13,10,12,
+ 11,12,13,13,10,13,10, 7,10,10,11,11,13,11,14,11,
+ 10,12,11,11,11,13,13,14,13,10,12,12,14,14,14,11,
+ 14,11, 6, 9, 9, 9,11,12, 8,11,10, 9,11,11,11,11,
+ 13,11,12,13, 8,11,10,11,13,13,10,12,10, 7,10,10,
+ 11,11,14,11,13,11,10,12,12,11,11,14,14,14,14,10,
+ 11,12,13,13,14,11,13,11, 8,10,10,10,11,12, 9,12,
+ 10,10,11,12,11,10,13,12,13,13,10,12,10,12,13,13,
+ 11,13,10,
+};
+
+static const static_codebook _44p5_p4_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p5_p4_0,
+ 1, -531365888, 1616117760, 2, 0,
+ (long *)_vq_quantlist__44p5_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p4_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p5_p4_1[] = {
+ 5, 7, 7,10,10, 7, 8, 9,10,11, 7, 9, 8,11,10, 9,
+ 10,10,11,11, 9,10,10,11,11, 7, 9, 9,10,10, 8, 9,
+ 10,10,11, 9,10,10,11,11,10,10,11,11,11,10,11,11,
+ 12,12, 7, 9, 9,10,10, 9,10,10,11,11, 8,10, 9,11,
+ 10,10,11,11,11,11,10,11,10,11,11,10,10,10,11,11,
+ 10,10,11,11,11,11,11,11,11,11,11,11,12,11,12,11,
+ 12,11,12,12,10,10,10,11,11,10,11,11,11,11,10,11,
+ 10,11,11,11,12,11,12,12,11,12,11,12,11, 8, 9, 9,
+ 11,11, 9,10,10,11,12, 9,10,10,11,11,10,11,11,12,
+ 12,10,11,11,12,12, 9,10,10,11,11,10,10,11,11,12,
+ 10,11,11,12,12,11,11,12,12,12,11,12,12,12,12, 9,
+ 10,10,11,11,10,11,11,12,12,10,11,10,12,12,11,12,
+ 12,12,12,11,12,12,12,12,11,11,11,12,12,11,11,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12, 8, 9, 9,11,11, 9,
+ 10,10,11,11, 9,10,10,11,11,10,11,11,12,12,10,11,
+ 11,12,12, 9,10,10,11,11,10,10,11,12,12,10,11,11,
+ 12,12,11,12,12,12,12,11,12,12,12,12, 9,10,10,11,
+ 11,10,11,11,12,12,10,11,10,12,11,11,12,12,12,12,
+ 11,12,11,12,12,11,11,11,12,12,11,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,
+ 11,12,12,11,12,12,12,12,11,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,10,11,11,12,12,11,12,12,12,
+ 12,11,12,12,12,12,12,12,13,13,13,12,12,12,13,13,
+ 11,12,12,12,12,12,12,12,12,13,12,12,12,13,13,12,
+ 12,13,13,13,12,13,13,13,13,11,12,12,12,12,12,12,
+ 12,13,13,12,12,12,13,13,12,13,13,13,13,12,13,13,
+ 13,13,12,12,12,12,13,12,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,12,12,12,13,12,
+ 13,13,13,13,13,12,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,10,11,11,12,12,11,12,12,12,12,11,12,
+ 11,12,12,12,12,12,13,12,12,12,12,13,13,11,12,12,
+ 12,12,12,12,12,13,13,12,12,12,13,13,12,13,13,13,
+ 13,12,13,13,13,13,11,12,12,12,12,12,12,12,13,13,
+ 12,12,12,13,12,12,13,13,13,13,12,13,12,13,13,12,
+ 12,12,12,13,12,13,13,13,13,12,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,12,12,12,13,12,13,13,13,
+ 13,13,12,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13, 8, 9, 9,11,11, 9,10,10,11,11, 9,10,10,12,11,
+ 10,11,11,12,12,10,11,11,12,12, 9,10,10,11,11,10,
+ 10,11,11,12,10,11,11,12,12,11,11,12,12,12,11,12,
+ 12,12,12, 9,10,10,11,11,10,11,11,12,12,10,11,10,
+ 12,12,11,12,12,12,12,11,12,12,12,12,11,11,11,12,
+ 12,11,11,12,12,12,11,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,11,11,11,12,12,11,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12, 9,10,
+ 10,11,11,10,10,11,12,12,10,11,11,12,12,11,11,12,
+ 12,12,11,12,12,12,12,10,10,11,11,12,11,11,12,12,
+ 12,11,11,12,12,12,11,11,12,12,13,12,12,12,12,12,
+ 10,11,11,12,12,11,12,11,12,12,11,12,11,12,12,12,
+ 12,12,12,12,12,12,12,12,12,11,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,13,12,12,13,12,13,12,12,13,
+ 13,13,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,13,12,12,12,12,13,12, 8,10,10,11,11,
+ 10,11,11,12,12,10,11,10,12,12,11,12,12,12,12,11,
+ 12,12,12,12,10,11,10,12,12,10,10,11,12,12,11,12,
+ 12,12,12,12,12,12,12,13,12,12,12,13,13,10,11,11,
+ 12,12,11,12,12,12,12,10,12,11,12,12,12,12,12,13,
+ 13,12,13,12,13,12,11,12,12,12,12,11,12,12,12,13,
+ 12,12,12,13,13,12,12,13,12,13,12,13,13,13,13,11,
+ 12,12,12,12,12,12,12,13,13,12,12,12,13,12,12,13,
+ 13,13,13,12,13,12,13,12,11,11,11,12,12,11,12,12,
+ 12,13,11,12,12,12,12,12,12,12,13,13,12,12,13,13,
+ 13,11,12,12,12,12,12,12,12,12,13,12,12,13,13,13,
+ 12,12,13,13,13,13,13,13,13,13,11,12,12,12,12,12,
+ 13,12,13,13,12,12,12,13,13,12,13,13,13,13,12,13,
+ 13,13,13,12,12,12,12,13,12,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,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,10,11,11,12,12,11,12,12,12,13,11,
+ 12,12,13,12,12,13,13,13,13,12,13,13,13,13,11,12,
+ 12,12,12,12,12,12,13,13,12,13,12,13,13,13,13,13,
+ 13,13,13,13,13,13,13,11,12,12,13,12,12,13,12,13,
+ 13,12,13,12,13,13,13,13,13,13,13,13,13,13,13,13,
+ 12,13,13,13,13,12,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,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, 8, 9, 9,11,11, 9,10,10,11,12, 9,10,10,11,
+ 11,10,11,11,12,12,10,11,11,12,12, 9,10,10,11,11,
+ 10,10,11,12,12,10,11,11,12,12,11,11,12,12,12,11,
+ 12,12,12,12, 9,10,10,11,11,10,11,11,12,12,10,11,
+ 10,12,12,11,12,12,12,12,11,12,11,12,12,11,11,11,
+ 12,12,11,11,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,11,11,11,12,12,11,12,12,12,12,
+ 11,12,11,12,12,12,12,12,12,12,12,12,12,12,12, 8,
+ 10,10,11,11,10,10,11,12,12,10,11,11,12,12,11,12,
+ 12,12,12,11,12,12,12,12,10,11,11,12,12,10,11,12,
+ 12,12,11,12,12,12,12,12,12,12,12,13,12,12,12,13,
+ 13,10,10,11,12,12,11,12,12,12,12,10,11,10,12,12,
+ 12,12,12,13,13,12,12,12,13,12,11,12,12,12,12,11,
+ 12,12,12,13,12,12,12,13,13,12,12,13,12,13,12,13,
+ 13,13,13,11,12,12,12,12,12,12,12,13,13,11,12,12,
+ 13,12,12,13,13,13,13,12,13,12,13,12, 9,10,10,11,
+ 11,10,11,11,12,12,10,11,11,12,12,11,12,12,12,12,
+ 11,12,11,12,12,10,11,11,12,12,11,11,12,12,12,11,
+ 11,12,12,12,12,12,12,12,13,12,12,12,13,12,10,11,
+ 10,12,11,11,12,11,12,12,11,12,11,12,12,12,12,12,
+ 12,12,12,12,11,12,12,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,13,12,13,12,13,13,13,13,
+ 11,12,11,12,12,12,12,12,13,12,12,12,12,12,12,12,
+ 13,12,13,13,12,12,12,13,12,10,11,11,12,12,11,12,
+ 12,12,13,11,12,12,13,12,12,12,13,13,13,12,13,13,
+ 13,13,11,12,12,12,13,12,12,13,13,13,12,12,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,11,12,12,12,12,
+ 12,12,13,13,13,12,13,12,13,13,13,13,13,13,13,13,
+ 13,13,13,13,12,13,13,13,13,12,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,13,
+ 13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,11,11,11,12,12,11,12,12,12,12,
+ 11,12,12,12,12,12,12,13,13,13,12,13,12,13,13,11,
+ 12,12,12,12,12,12,13,13,13,12,12,13,13,13,12,13,
+ 13,13,13,12,13,13,13,13,11,12,12,12,12,12,13,12,
+ 13,13,12,12,12,13,12,13,13,13,13,13,12,13,12,13,
+ 13,12,12,12,13,13,12,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,12,12,12,13,12,13,
+ 13,13,13,13,12,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,10,11,11,12,12,11,12,12,12,12,11,12,12,
+ 12,12,12,12,12,13,13,12,12,12,13,13,11,12,12,12,
+ 12,11,12,12,13,13,12,12,12,13,13,12,12,13,13,13,
+ 12,13,13,13,13,11,12,12,12,12,12,12,12,13,13,12,
+ 12,12,13,12,12,13,13,13,13,12,13,12,13,13,12,12,
+ 12,12,12,12,12,13,13,13,12,13,13,13,13,12,13,13,
+ 13,13,13,13,13,13,13,12,12,12,13,12,12,13,13,13,
+ 13,12,13,12,13,13,13,13,13,13,13,13,13,13,13,13,
+ 10,11,11,12,12,11,12,12,12,13,11,12,12,13,12,12,
+ 12,12,13,13,12,12,12,13,13,11,12,12,12,12,12,12,
+ 13,13,13,12,12,12,13,13,12,12,13,13,13,12,13,13,
+ 13,13,11,12,12,12,12,12,12,12,13,13,12,12,12,13,
+ 13,12,13,13,13,13,12,13,13,13,13,12,12,12,12,13,
+ 12,12,13,13,13,12,13,13,13,13,12,13,13,13,13,13,
+ 13,13,13,13,12,12,12,13,13,13,13,13,13,13,12,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,10,11,11,
+ 12,12,11,12,12,12,13,11,12,12,13,12,12,13,13,13,
+ 13,12,13,12,13,13,11,12,12,13,13,12,12,12,13,13,
+ 12,12,13,13,13,12,13,13,13,13,13,13,13,13,13,11,
+ 12,12,13,12,12,13,12,13,13,12,13,12,13,13,13,13,
+ 13,13,13,12,13,13,13,13,12,12,12,13,13,12,13,13,
+ 13,13,12,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,12,12,12,13,13,12,13,13,13,13,12,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,11,11,11,12,12,11,
+ 12,12,12,12,11,12,12,12,12,12,12,12,13,13,12,12,
+ 12,13,13,11,12,12,12,12,12,12,12,12,13,12,12,12,
+ 13,13,12,12,13,13,13,12,13,13,13,13,11,12,12,12,
+ 12,12,12,12,13,13,12,12,12,13,12,12,13,13,13,13,
+ 12,13,12,13,13,12,12,12,12,12,12,12,13,12,13,12,
+ 13,13,13,13,12,13,13,12,13,13,13,13,13,13,12,12,
+ 12,12,12,12,13,13,13,13,12,13,12,13,13,13,13,13,
+ 13,13,12,13,13,13,12,10,11,11,12,12,11,12,12,12,
+ 12,11,12,12,12,12,12,12,12,13,13,12,13,12,13,13,
+ 11,12,12,12,12,12,12,12,13,13,12,12,12,13,13,12,
+ 12,13,13,13,13,13,13,13,13,11,12,12,12,12,12,13,
+ 12,13,13,12,13,12,13,13,12,13,13,13,13,12,13,12,
+ 13,13,12,12,12,12,12,12,13,13,13,13,12,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,12,12,12,13,12,
+ 12,13,13,13,13,12,13,12,13,13,13,13,13,13,13,13,
+ 13,13,13,13,10,11,11,12,12,11,12,12,12,12,11,12,
+ 12,12,12,12,12,12,13,13,12,12,12,13,13,11,12,12,
+ 12,12,12,12,12,13,13,12,12,12,13,13,12,12,13,13,
+ 13,12,12,13,13,13,11,12,11,12,12,12,12,12,13,13,
+ 11,12,12,13,13,12,13,13,13,13,12,13,12,13,13,12,
+ 12,12,12,12,12,13,13,13,13,12,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,12,12,12,13,12,12,13,13,
+ 13,13,12,13,12,13,13,13,13,13,13,13,12,13,13,13,
+ 13,10,11,11,12,12,11,12,12,12,13,11,12,12,13,12,
+ 12,12,13,13,13,12,13,13,13,13,11,12,12,13,13,12,
+ 12,13,13,13,12,12,13,13,13,12,13,13,13,13,13,13,
+ 13,13,13,11,12,12,13,12,12,13,12,13,13,12,12,12,
+ 13,13,12,13,13,13,13,13,13,13,13,13,12,12,13,13,
+ 13,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,12,12,12,13,13,13,13,13,13,13,12,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,10,12,
+ 11,12,12,11,12,12,12,13,11,12,12,12,12,12,12,12,
+ 13,13,12,12,12,13,13,11,12,12,12,13,12,12,12,13,
+ 13,12,12,12,13,13,12,13,13,13,13,12,13,13,13,13,
+ 11,12,12,13,12,12,12,12,13,13,12,12,12,13,13,12,
+ 13,13,13,13,12,13,12,13,13,12,13,12,13,13,12,13,
+ 13,13,13,12,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,12,12,12,13,12,13,13,13,13,13,12,13,12,13,
+ 13,13,13,13,13,13,12,13,13,13,13,10,11,11,12,12,
+ 11,12,12,12,13,11,12,12,12,12,12,12,12,13,13,12,
+ 12,12,13,13,11,12,12,12,12,12,12,13,13,13,12,13,
+ 13,13,13,12,12,13,13,13,13,13,13,13,13,11,12,12,
+ 12,12,12,13,12,13,13,12,12,12,13,13,12,13,13,13,
+ 13,12,13,12,13,13,12,12,12,12,13,12,13,13,13,13,
+ 12,13,13,13,13,12,13,13,13,13,13,13,13,13,13,12,
+ 12,12,12,12,12,13,13,13,13,12,13,13,13,13,13,13,
+ 13,13,13,12,13,13,13,13,11,12,11,12,12,11,12,12,
+ 12,12,11,12,12,12,12,12,12,12,12,13,12,12,12,13,
+ 12,11,12,12,12,12,12,12,12,12,13,12,12,12,13,13,
+ 12,12,13,13,13,12,13,13,13,13,11,12,12,12,12,12,
+ 12,12,13,13,12,12,12,13,12,12,13,13,13,13,12,13,
+ 12,13,13,12,12,12,12,12,12,12,13,13,13,12,13,13,
+ 13,13,13,13,13,12,13,13,13,13,13,13,12,12,12,12,
+ 12,12,13,13,13,13,12,13,12,13,12,13,13,13,13,13,
+ 13,13,13,13,12,
+};
+
+static const static_codebook _44p5_p4_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p5_p4_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p5_p4_1,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p5_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p5_p5_0[] = {
+ 1, 6, 6,10,10, 6, 7, 9,11,13, 5, 9, 7,13,11, 8,
+ 11,12,13,15, 8,12,11,15,13, 6, 7, 8,11,11, 7, 8,
+ 10,11,13, 9,10,10,13,13,11,11,13,12,16,12,13,13,
+ 16,15, 6, 8, 7,11,11, 9,10,10,13,13, 7,10, 7,13,
+ 11,12,13,13,15,16,11,13,11,16,12,10,11,11,11,13,
+ 11,11,13,12,15,13,13,13,14,15,13,12,15,12,17,15,
+ 16,16,16,16,10,11,11,14,11,13,13,13,15,14,11,13,
+ 11,15,12,15,15,16,16,16,13,15,12,17,12, 6, 8, 9,
+ 12,12, 9,10,12,13,15, 9,11,11,15,14,12,13,15,16,
+ 18,13,14,14,17,16, 9,10,11,13,14,11,10,13,14,16,
+ 11,12,12,15,15,14,13,16,15,18,14,15,15,17,17, 9,
+ 11,11,14,14,11,12,13,15,16,11,13,11,15,14,15,15,
+ 15,17,18,14,15,14,17,15,13,14,14,15,16,14,14,15,
+ 15,17,15,16,15,17,17,16,16,17,15,19,17,18,18,19,
+ 18,13,14,14,16,15,15,15,16,17,17,14,15,14,18,15,
+ 17,17,17,19,19,16,17,15,19,16, 6, 9, 8,13,12, 9,
+ 11,11,14,15, 9,12,10,15,13,13,14,14,16,17,12,15,
+ 13,18,16, 9,11,11,14,14,11,11,13,14,15,11,13,12,
+ 16,15,14,14,15,15,18,14,15,15,18,17, 9,11,10,14,
+ 13,11,12,12,15,15,11,13,10,16,14,14,15,15,16,18,
+ 14,16,13,18,15,13,14,14,16,16,14,14,15,15,17,15,
+ 16,15,17,17,16,16,17,16,19,17,18,17,18,19,13,14,
+ 14,16,15,15,15,15,17,17,14,15,14,17,15,17,17,17,
+ 18,19,16,17,15,19,15,11,13,13,15,16,13,14,15,16,
+ 18,14,15,15,17,17,16,16,18,18,20,17,18,17,19,20,
+ 13,14,14,16,17,15,15,16,17,18,15,16,16,17,17,18,
+ 17,19,18,19,18,18,18,19,21,14,14,15,16,17,15,15,
+ 16,18,18,15,16,16,17,18,18,18,19,19,21,18,19,19,
+ 22,20,16,16,17,17,19,17,17,17,18,20,17,18,18,20,
+ 19,19,19,20,19, 0,19,19,20,20,21,17,17,17,19,18,
+ 18,18,20,19,19,18,18,18,20,20,19,19,20,20,20,20,
+ 21,20,21,19,11,13,13,16,15,14,15,15,17,17,14,15,
+ 14,18,16,16,18,18,20,19,16,19,17,21,18,13,14,15,
+ 16,17,15,15,16,18,18,15,16,15,19,18,18,18,18,19,
+ 19,18,18,18,22,20,13,14,14,16,16,15,16,16,18,17,
+ 15,16,15,18,17,18,18,18,19,19,17,18,17,21,18,16,
+ 17,17,18,18,17,18,19,19,19,18,20,18,19,19,19,20,
+ 21,19,21,20,20,20, 0,21,16,17,17,19,19,18,18,18,
+ 19,21,17,18,18,19,18,20,19,21,20,21,19,20,20,22,
+ 19, 7, 9, 9,13,13, 8,10,11,14,15, 9,12,11,15,14,
+ 11,13,14,16,17,13,15,14,17,16, 8,10,11,14,14,10,
+ 10,12,14,16,11,12,12,16,15,13,12,15,15,18,14,15,
+ 15,19,17, 9,11,11,14,14,11,12,12,15,15,11,13,11,
+ 16,14,14,15,14,17,17,14,16,14,18,15,12,13,14,15,
+ 16,13,13,15,14,17,15,15,15,17,17,15,14,17,14,19,
+ 17,18,18,19,18,13,14,14,16,16,15,15,15,17,17,14,
+ 15,14,18,15,17,18,17,18,17,16,18,16,19,15, 7,10,
+ 10,13,13, 9,10,12,14,15,10,12,11,15,14,12,13,14,
+ 16,17,13,15,14,18,16,10,10,12,13,14,10,10,13,13,
+ 16,12,12,13,15,15,13,12,15,15,18,15,15,16,18,17,
+ 10,11,11,14,14,12,13,13,15,16,10,13,10,16,14,14,
+ 15,15,17,17,14,15,13,17,15,13,13,14,15,16,14,13,
+ 15,14,18,15,15,16,16,17,16,15,18,15,18,17,18,18,
+ 18,18,13,15,14,17,16,15,16,16,17,17,14,15,13,17,
+ 15,17,17,18,18,18,16,17,14,20,14, 8,10,10,14,14,
+ 11,11,13,14,16,11,13,11,16,14,14,15,16,16,18,14,
+ 16,15,18,16,10,12,11,15,14,11,11,13,14,16,13,14,
+ 13,16,15,15,14,16,15,19,16,17,16,20,18,10,11,12,
+ 14,15,13,13,14,16,16,11,14,11,16,14,16,16,17,18,
+ 19,15,17,14,20,15,14,15,14,17,16,13,14,15,15,18,
+ 16,17,16,19,18,16,15,18,15,19,18,19,18,21,21,14,
+ 14,15,16,17,16,16,17,18,18,13,15,14,17,15,18,18,
+ 19,18,22,16,18,15,21,15,12,13,14,16,16,14,14,16,
+ 16,18,14,15,15,17,18,16,16,18,18,20,18,18,17,20,
+ 20,13,14,15,15,17,15,14,16,16,18,16,16,16,17,19,
+ 17,15,18,17,21,18,18,18,19,19,14,15,15,18,17,15,
+ 16,16,18,19,15,16,15,18,18,17,18,18,20,21,17,19,
+ 17,20,19,16,16,17,16,19,17,17,18,17,20,18,18,18,
+ 18,19,19,18,20,17,22,20,20,19,20,20,17,17,18,18,
+ 19,18,18,20,21,20,17,18,17,20,20,21,21,21,21,21,
+ 19,21,18,22,20,11,13,13,17,16,14,14,16,16,18,14,
+ 16,14,18,16,17,18,19,19,20,18,19,18,21,19,14,15,
+ 14,17,16,14,14,16,18,18,16,17,16,18,17,18,17,19,
+ 18,20,19,19,18,20,20,13,14,15,16,17,16,16,17,18,
+ 19,14,16,14,19,17,18,19,18,20,20,18,20,17,21,18,
+ 17,17,17,19,18,16,17,18,18,19,18,19,18,21,21,18,
+ 18,20,17,21,19,20,20,22,21,16,17,18,18,19,18,18,
+ 19,21,20,16,17,17,20,18,21,21,22,21,22,18,21,18,
+ 0,18, 7, 9, 9,13,13, 9,11,12,14,15, 8,11,10,15,
+ 14,13,14,15,16,18,11,14,13,17,15, 9,11,11,14,14,
+ 11,11,13,14,16,11,12,12,15,15,14,14,16,15,18,14,
+ 14,15,17,17, 8,11,10,14,14,11,12,12,15,15,10,12,
+ 10,16,14,14,15,15,17,18,13,15,12,18,15,13,14,14,
+ 16,16,14,14,15,15,17,15,15,15,16,17,16,15,17,15,
+ 19,17,17,17,18,18,12,14,13,16,15,15,15,15,17,17,
+ 13,15,13,17,14,17,18,18,18,19,15,17,14,19,14, 8,
+ 10,10,14,14,11,11,13,14,16,11,13,11,16,14,14,15,
+ 16,17,19,14,16,15,18,17,10,12,11,15,14,11,11,14,
+ 14,17,13,14,13,17,15,15,14,17,15,19,16,17,16,19,
+ 17,10,11,12,14,15,13,13,14,15,17,11,13,11,17,14,
+ 16,16,17,18,19,15,16,14,18,15,14,15,14,16,16,13,
+ 14,15,15,18,16,16,16,18,18,16,15,18,15,20,18,19,
+ 18,21,18,14,14,15,16,17,16,16,17,17,18,13,15,14,
+ 17,16,19,19,19,19,19,15,18,15,20,15, 7,10,10,13,
+ 13,10,11,12,14,15, 9,12,10,15,14,13,14,15,16,17,
+ 12,15,13,17,16,10,11,11,14,14,10,10,13,14,16,12,
+ 13,13,16,15,14,13,16,15,18,15,15,16,17,17,10,12,
+ 10,14,13,12,13,12,15,15,10,13,10,16,13,15,16,15,
+ 17,18,13,16,12,18,15,13,14,14,16,17,14,13,15,15,
+ 18,15,16,15,17,17,16,14,17,15,19,17,18,18,19,19,
+ 13,15,13,17,14,15,15,15,18,17,14,15,13,17,14,18,
+ 17,18,18,19,15,17,15,19,15,11,13,13,16,17,14,14,
+ 16,16,18,14,16,15,18,17,17,18,19,18,21,18,18,17,
+ 20,18,13,15,14,17,16,14,14,16,17,18,16,17,16,19,
+ 17,18,17,19,18,22,18,19,19,21,21,13,14,15,16,18,
+ 16,16,17,17,20,14,16,14,18,17,18,18,19,19,21,17,
+ 18,17,21,18,17,18,17,19,18,16,17,17,18,19,18,18,
+ 18,22,22,18,17,19,17, 0,20,21,19,21,20,17,17,18,
+ 18,21,18,18,18,19,21,17,17,17,19,19,20,20,22,21,
+ 21,19,20,18,20,17,12,14,13,17,16,14,15,15,17,18,
+ 14,16,14,18,16,17,18,18,21,20,16,18,16,21,18,14,
+ 15,15,17,17,15,15,16,18,18,15,17,16,18,18,17,17,
+ 19,19,20,18,19,18,20,19,14,15,14,17,15,15,16,16,
+ 18,17,15,16,14,19,15,18,18,18,19,20,17,20,15,21,
+ 17,16,17,18,18,19,17,17,18,18,20,18,19,18,19,21,
+ 19,18,19,19,21,20, 0,19,21,20,16,17,16,19,16,18,
+ 18,18,19,19,17,18,17,20,17,19,20,20,22, 0,19,20,
+ 17,21,17,11,13,14,16,17,14,15,15,17,18,14,15,15,
+ 18,18,16,17,17,19,20,16,18,17,19,21,13,14,15,17,
+ 17,14,15,16,17,19,15,16,16,18,19,16,17,18,19,21,
+ 17,18,20,21,21,13,15,15,17,17,15,16,16,18,19,15,
+ 16,16,18,19,17,17,18,19,22,17,19,18,22,19,15,16,
+ 17,19,19,16,17,18,18,20,17,18,18,19,20,19,18,20,
+ 18,22,20,19,19,22,21,16,17,17,18,19,18,18,18,19,
+ 20,17,18,18,20,19,20,19,20,22,20,19,20,21,21,20,
+ 12,14,14,16,16,13,14,16,17,18,14,16,15,18,18,15,
+ 17,17,19,19,17,18,18,19,19,13,14,15,16,17,14,14,
+ 16,16,20,15,16,16,17,19,16,15,18,17,20,18,17,19,
+ 19,19,14,15,15,17,17,16,16,16,18,18,15,16,15,19,
+ 18,17,18,18,20,21,17,18,17,21,18,16,15,17,17,19,
+ 17,15,18,17,20,19,17,18,19,20,18,16,19,17,22,20,
+ 19,20,19,20,17,17,18,19,19,18,18,19,20,20,17,18,
+ 17,18,18,21,21,20,20,21,18,20,17,21,19,11,14,14,
+ 16,17,15,14,16,17,19,14,16,14,18,17,18,18,19,19,
+ 21,17,19,18,20,20,13,15,14,17,17,14,14,16,17,18,
+ 16,17,16,19,18,18,17,19,18,20,18,21,18,20,20,13,
+ 15,15,16,17,16,16,17,18,19,14,16,15,19,18,19,19,
+ 19,21,20,18,19,17,20,18,16,17,16,19,18,16,17,17,
+ 19,20,17,19,18,20,19,18,17,21,18, 0,21,20,20, 0,
+ 20,17,17,18,18,19,18,19,19,20,22,16,17,17,20,18,
+ 21,22,20,20,22,18,22,18,22,18,12,14,14,17,17,14,
+ 15,16,17,19,14,16,15,17,17,17,17,18,18,21,17,19,
+ 17,20,19,14,15,15,16,18,15,14,16,16,19,16,17,16,
+ 19,18,17,16,20,17,20,18,20,19,19,20,14,15,15,18,
+ 17,16,16,17,18,19,14,16,15,19,17,18,21,18,19,21,
+ 17,18,17,19,18,17,17,18,17,20,17,16,18,17,21,18,
+ 19,19,19,19,18,17,19,17,20,20,21,20,21,20,17,17,
+ 17,19,19,19,18,18,20,21,16,18,16,19,18,20,20,21,
+ 21,20,18,19,16, 0,17,12,14,14,17,17,15,15,18,17,
+ 19,15,18,15,20,16,20,19,21,18,22,20,20,20,22,19,
+ 14,16,14,20,17,14,15,17,17,20,18,18,17,20,18,18,
+ 17,19,17,21,20,21,20, 0,21,14,15,16,17,19,18,17,
+ 19,18,21,14,18,15,21,17,21,20,21,20, 0,18,21,17,
+ 21,17,18,19,17,20,18,16,17,17,19,19,19,21,20, 0,
+ 20,18,17,21,17, 0,22, 0,21, 0,22,17,17,19,18,20,
+ 20,20,21,19,22,16,17,18,20,18,22,22, 0,22, 0,17,
+ 21,17,22,17,11,14,13,16,16,14,15,15,17,18,14,15,
+ 14,18,17,17,18,18,19,20,16,17,17,21,19,13,14,15,
+ 17,17,15,16,16,18,18,15,16,16,19,18,18,18,18,19,
+ 20,17,18,18,20,19,13,15,14,17,17,15,16,16,17,18,
+ 14,16,15,19,17,17,18,19,21,21,17,18,17,20,18,16,
+ 17,17,19,19,17,18,19,19,20,18,19,18,21,21,21,20,
+ 19,21,22,20,20,19,21,20,15,17,16,19,19,17,18,18,
+ 20,21,16,18,17,20,18,19,19,21,21,21,19,19,19,20,
+ 18,11,14,13,17,16,14,14,16,16,19,14,16,15,19,16,
+ 18,18,18,19,22,17,18,17,20,19,13,15,14,17,17,15,
+ 15,16,17,19,16,17,16,20,18,18,17,19,18,21,19,19,
+ 18,22, 0,13,14,15,17,18,16,16,17,17,19,14,16,15,
+ 19,18,18,19,19,20,21,18,18,17,20,18,17,18,17,20,
+ 18,16,17,17,18,20,18,19,18,20,20,18,18,21,17,21,
+ 20,21,21, 0,19,16,16,18,18,19,19,18,20,19,20,16,
+ 17,17,20,18,21,20,21,22,22,18,20,17,21,17,12,14,
+ 14,17,16,14,15,16,18,18,13,15,14,18,17,17,18,18,
+ 19,19,15,17,16,19,19,14,15,15,17,17,15,15,16,18,
+ 19,15,16,16,19,18,17,17,18,18,20,18,18,18,21,20,
+ 13,15,14,17,16,15,16,15,18,18,14,16,14,18,17,18,
+ 18,18,19,21,16,18,16,20,17,17,18,17,18,19,17,17,
+ 18,18,19,18,19,19,21,19,19,18,20,18,21,21,20,20,
+ 21,20,16,17,15,20,17,17,19,17,19,19,17,18,15,20,
+ 17,19,20,19,21,22,17,20,16, 0,17,12,14,14,17,18,
+ 16,15,18,16,20,16,18,15,21,17,20,18,21,19,22,19,
+ 21,19, 0,19,14,16,15,19,17,14,15,17,16,21,18,19,
+ 18,21,17,19,17,21,17,22,20,21,21, 0,21,14,15,16,
+ 17,19,18,17,19,18,21,14,17,15,20,17,21,22,21,20,
+ 22,18,21,17,21,17,17,19,17,21,18,16,17,17,19,20,
+ 19,21,20,21,20,17,18,20,17,21, 0,22,20,21,22,17,
+ 17,20,18,21,21,20,22,20,21,16,17,17,21,19, 0,22,
+ 0,21,21,18,22,17,21,17,12,14,14,17,16,14,15,16,
+ 17,18,14,16,15,18,17,17,17,20,19,20,16,18,17,21,
+ 18,14,15,15,17,17,14,15,16,17,19,16,17,16,18,18,
+ 17,16,19,18,19,18,19,18,21,20,14,15,15,18,17,16,
+ 16,16,19,18,15,16,14,20,16,18,18,19,19,20,16,19,
+ 16,21,17,17,17,18,19,19,16,16,18,18,19,19,19,18,
+ 20,20,18,16,19,18,20,22,21,20,19,20,16,18,17,20,
+ 16,18,19,18,19,18,16,18,16,20,17,21,20,21,20,20,
+ 18,19,17,21,16,
+};
+
+static const static_codebook _44p5_p5_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p5_p5_0,
+ 1, -528744448, 1616642048, 3, 0,
+ (long *)_vq_quantlist__44p5_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p5_1[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44p5_p5_1[] = {
+ 2, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _44p5_p5_1 = {
+ 1, 7,
+ (char *)_vq_lengthlist__44p5_p5_1,
+ 1, -533200896, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p5_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p5_p6_0[] = {
+ 1, 5, 5, 5, 7, 9, 5, 9, 7, 5, 7, 8, 7, 7,10, 9,
+ 9,10, 5, 8, 7, 9,10, 9, 7,10, 7, 6, 9, 9, 9,10,
+ 12,10,12,11, 9,10,11,11,10,13,12,12,13,10,11,11,
+ 12,13,13,11,13,11, 6, 9, 9,10,11,12, 9,12,11,10,
+ 11,11,11,11,13,12,13,13, 9,11,10,12,13,13,11,13,
+ 10, 6, 9,10, 9,11,12,10,12,11, 9,10,11,10,10,13,
+ 11,13,13,10,11,11,12,13,12,11,13,11, 7, 9,10, 9,
+ 10,12,10,11,11,10,10,11,10,10,12,12,11,12,10,11,
+ 10,12,12,12,10,12,10, 7,10,10,11,11,13,11,13,11,
+ 10,12,11,11,10,13,13,14,13,10,11,12,13,13,14,11,
+ 13,10, 6,10, 9,10,11,12, 9,12,11, 9,11,11,11,11,
+ 13,12,12,13, 9,11,10,12,13,13,10,13,10, 7,10,10,
+ 11,11,14,11,13,11,10,12,11,11,10,14,13,14,13,10,
+ 11,12,13,13,14,11,13,10, 7,10, 9,10,10,12, 9,12,
+ 10,10,11,11,10,10,12,12,12,12, 9,11,10,11,12,12,
+ 10,12, 9,
+};
+
+static const static_codebook _44p5_p6_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p5_p6_0,
+ 1, -527106048, 1620377600, 2, 0,
+ (long *)_vq_quantlist__44p5_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p6_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p5_p6_1[] = {
+ 2, 6, 6, 5, 7, 8, 5, 8, 7, 6, 7, 7, 7, 7, 8, 8,
+ 8, 8, 6, 7, 7, 7, 8, 8, 7, 8, 7, 6, 8, 8, 8, 9,
+ 10, 8, 9, 9, 8, 9, 9, 9, 9,10,10,10,10, 8, 9, 9,
+ 10,10,10, 9,10,10, 6, 8, 8, 8, 9, 9, 8,10, 9, 9,
+ 9, 9, 9, 9,10,10,10,10, 8, 9, 9,10,10,10, 9,10,
+ 9, 6, 8, 9, 8, 9, 9, 8, 9, 9, 8, 9, 9, 9, 9,10,
+ 9,10,10, 8, 9, 9, 9,10,10, 9,10, 9, 7, 8, 9, 8,
+ 9, 9, 9, 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 7, 9, 9, 9,10,10, 9,10,10,
+ 9,10, 9, 9, 9,10,10,10,10, 9,10, 9,10,10,10, 9,
+ 10, 9, 6, 8, 8, 8, 9, 9, 8, 9, 9, 8, 9, 9, 9, 9,
+ 10, 9,10,10, 8, 9, 9, 9,10,10, 9,10, 9, 7, 9, 9,
+ 9,10,10, 9,10, 9, 9, 9,10,10, 9,10,10,10,10, 9,
+ 9, 9,10,10,10, 9,10, 9, 7, 9, 8, 8, 9, 9, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p5_p6_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p5_p6_1,
+ 1, -530841600, 1616642048, 2, 0,
+ (long *)_vq_quantlist__44p5_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p5_p7_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p5_p7_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p5_p7_0,
+ 1, -513979392, 1633504256, 2, 0,
+ (long *)_vq_quantlist__44p5_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p7_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p5_p7_1[] = {
+ 1, 7, 7, 6, 9, 9, 7, 9, 9, 6, 9, 9, 9, 9, 9, 9,
+ 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,
+};
+
+static const static_codebook _44p5_p7_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p5_p7_1,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p5_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p7_2[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p5_p7_2[] = {
+ 1, 2, 3, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,
+ 11,12,12,13,13,14,14,14,14,
+};
+
+static const static_codebook _44p5_p7_2 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p5_p7_2,
+ 1, -518864896, 1620639744, 5, 0,
+ (long *)_vq_quantlist__44p5_p7_2,
+ 0
+};
+
+static const long _vq_quantlist__44p5_p7_3[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p5_p7_3[] = {
+ 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p5_p7_3 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p5_p7_3,
+ 1, -529006592, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44p5_p7_3,
+ 0
+};
+
+static const char _huff_lengthlist__44p5_short[] = {
+ 4, 7,12,14,15,18,20,20, 5, 3, 4, 6, 9,11,15,19,
+ 9, 4, 3, 4, 7, 9,13,18,11, 6, 3, 3, 5, 8,13,19,
+ 14, 9, 6, 5, 7,10,16,20,16,11, 9, 8,10,10,14,16,
+ 21,14,13,11, 8, 7,11,14,21,14,13, 9, 6, 5,10,12,
+};
+
+static const static_codebook _huff_book__44p5_short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p5_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p6_l0_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44p6_l0_0[] = {
+ 1, 4, 4, 7, 7,10,10,12,12,12,12,13,12, 5, 5, 5,
+ 8, 6,11, 9,12,12,13,12,12,12, 4, 5, 5, 6, 8, 9,
+ 11,12,12,13,12,12,12, 7, 7, 8, 9, 9,11, 8,12, 9,
+ 12,12,12,12, 7, 8, 8, 9, 9, 8,11, 9,12,12,12,11,
+ 12,10,10,10,11,11,11,11,11,10,11,11,12,11,10,10,
+ 10,11,11,11,11,10,11,11,11,11,12,11,11,11,12,11,
+ 12,11,12,11,13,11,13,11,11,11,11,11,12,11,12,10,
+ 13,11,12,11,13,12,12,12,13,12,13,13,13,12,14,12,
+ 14,13,12,12,12,12,13,13,13,12,14,12,14,13,14,13,
+ 14,14,14,14,14,14,14,14,15,14,15,14,13,14,13,14,
+ 14,14,14,14,15,14,14,14,15,
+};
+
+static const static_codebook _44p6_l0_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44p6_l0_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44p6_l0_0,
+ 0
+};
+
+static const long _vq_quantlist__44p6_l0_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p6_l0_1[] = {
+ 4, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5,
+ 5, 5, 4, 5, 5, 5, 5, 5, 4,
+};
+
+static const static_codebook _44p6_l0_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p6_l0_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p6_l0_1,
+ 0
+};
+
+static const long _vq_quantlist__44p6_l1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p6_l1_0[] = {
+ 1, 3, 2, 5, 5, 6, 6, 6, 6,
+};
+
+static const static_codebook _44p6_l1_0 = {
+ 2, 9,
+ (char *)_vq_lengthlist__44p6_l1_0,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p6_l1_0,
+ 0
+};
+
+static const char _huff_lengthlist__44p6_lfe[] = {
+ 2, 3, 1, 3,
+};
+
+static const static_codebook _huff_book__44p6_lfe = {
+ 2, 4,
+ (char *)_huff_lengthlist__44p6_lfe,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44p6_long[] = {
+ 2, 7,13,15,16,17,19,20, 6, 3, 4, 7, 9,10,12,15,
+ 13, 4, 3, 4, 7, 8,11,13,14, 7, 4, 4, 6, 7,10,11,
+ 16, 9, 7, 6, 7, 8, 9,10,16, 9, 8, 7, 7, 6, 8, 8,
+ 18,12,10,10, 9, 8, 8, 9,20,14,13,12,11, 8, 9, 9,
+};
+
+static const static_codebook _huff_book__44p6_long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p6_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p6_p1_0[] = {
+ 2, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 8, 9, 7,
+ 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 5, 7, 8, 8, 9,
+ 10, 8, 9, 9, 8, 9,10, 9,10,12,10,11,11, 8, 9,10,
+ 10,11,11, 9,11,11, 5, 8, 7, 8, 9, 9, 8,10, 9, 8,
+ 10, 9, 9,11,11,10,11,11, 8,10, 9,10,11,11, 9,12,
+ 10, 5, 8, 8, 7, 9,10, 8,10, 9, 7, 9, 9, 9,10,11,
+ 9,11,11, 8,10,10,10,11,11,10,12,11, 7, 9, 9, 9,
+ 10,11, 9,11,11, 9, 9,11,10,10,13,11,11,12, 9,11,
+ 11,11,12,13,11,13,12, 7, 9, 9, 9,11,11, 9,12,10,
+ 9,11,10,10,11,12,11,13,12, 9,11,11,11,13,13,11,
+ 13,11, 5, 8, 8, 8, 9,10, 7,10, 9, 8,10,10,10,11,
+ 11,10,11,11, 7, 9, 9, 9,11,11, 9,11,10, 7, 9, 9,
+ 9,10,12, 9,11,11, 9,11,11,11,11,13,11,13,13, 9,
+ 10,11,11,12,13,10,12,11, 7, 9, 9, 9,11,11, 9,11,
+ 10, 9,11,11,11,12,13,11,13,12, 9,11, 9,11,12,11,
+ 10,13,10,
+};
+
+static const static_codebook _44p6_p1_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p6_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p6_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p6_p2_0[] = {
+ 4, 6, 6, 9, 9, 6, 7, 8,10,10, 6, 8, 7,10,10, 8,
+ 10,10,12,13, 8,10,10,13,12, 6, 8, 8,10,10, 7, 8,
+ 9,10,11, 8, 9, 9,11,11,10,10,11,12,13,10,11,11,
+ 14,13, 6, 8, 8,10,10, 8, 9, 9,11,11, 7, 9, 8,11,
+ 10,10,11,11,13,14,10,11,10,13,12, 9,10,10,12,12,
+ 10,10,11,12,13,10,11,11,13,13,12,12,13,12,15,13,
+ 14,13,15,14, 9,10,10,13,12,10,11,11,13,13,10,11,
+ 10,13,12,13,13,14,14,15,12,13,12,15,12, 6, 8, 8,
+ 10,11, 8, 9,10,11,12, 8, 9, 9,11,11,10,11,12,13,
+ 14,10,11,11,14,13, 8, 9, 9,11,12, 9,10,11,12,13,
+ 9,10,11,12,13,11,11,13,13,15,11,12,12,14,14, 8,
+ 9, 9,12,12, 9,10,11,12,13, 9,10,10,13,12,11,12,
+ 13,14,15,11,12,12,14,14,11,11,12,13,14,11,12,13,
+ 13,15,12,13,13,14,15,13,13,14,14,16,14,15,15,16,
+ 16,11,12,11,14,13,12,13,13,14,14,11,13,12,14,13,
+ 14,15,15,16,16,13,14,14,16,14, 6, 8, 8,11,10, 8,
+ 9, 9,12,11, 8,10, 9,12,11,10,11,11,13,13,10,12,
+ 11,14,13, 8, 9, 9,12,12, 9,10,10,12,13, 9,11,10,
+ 13,12,11,12,12,14,14,11,13,12,15,14, 8, 9, 9,12,
+ 11, 9,10,10,13,12, 9,11,10,13,12,12,12,12,14,14,
+ 11,13,12,15,13,11,11,12,13,14,11,12,13,13,14,12,
+ 13,13,14,15,13,13,14,14,16,14,15,15,16,16,11,12,
+ 11,14,13,12,13,13,15,14,11,13,12,15,13,14,15,15,
+ 16,16,13,15,13,16,14, 9,10,11,12,13,11,11,12,13,
+ 14,11,12,12,13,14,13,13,14,14,16,13,14,14,15,16,
+ 11,11,12,13,14,12,12,13,14,15,12,13,13,14,15,14,
+ 14,15,15,17,14,15,15,16,17,11,12,12,14,14,12,13,
+ 13,14,15,12,13,12,15,15,14,15,15,16,17,14,15,15,
+ 16,16,13,14,14,15,16,14,14,15,15,17,15,15,15,16,
+ 17,16,16,17,16,18,16,17,17,18,18,13,14,14,16,15,
+ 14,15,15,17,16,14,15,15,16,16,16,17,17,18,18,16,
+ 16,16,17,16, 9,11,10,13,12,11,12,12,14,13,11,12,
+ 11,15,13,13,14,14,16,15,13,14,13,17,14,11,12,12,
+ 14,14,12,12,13,15,15,12,13,13,15,14,14,14,15,16,
+ 16,14,15,15,17,16,11,12,11,14,13,12,13,13,15,14,
+ 12,13,12,15,13,14,15,15,16,16,14,15,14,17,15,13,
+ 14,14,15,16,14,15,15,16,17,14,15,15,16,17,16,16,
+ 16,17,17,16,17,17,18,18,13,15,14,16,15,15,15,15,
+ 17,16,14,15,14,17,15,16,17,17,18,18,16,17,16,18,
+ 16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12,11,
+ 10,11,11,13,14,10,12,11,14,13, 7, 9, 9,11,12, 9,
+ 10,10,12,13, 9,10,10,13,12,11,11,12,13,15,11,12,
+ 12,15,14, 8, 9, 9,12,11, 9,10,10,13,13, 9,11,10,
+ 13,12,12,12,12,14,15,11,13,12,15,13,10,11,11,13,
+ 14,11,12,12,13,15,11,12,12,14,14,13,13,14,14,16,
+ 14,15,14,16,16,11,12,11,14,13,12,13,13,15,14,11,
+ 13,12,15,13,14,15,15,16,16,13,14,14,16,14, 8, 9,
+ 9,11,12, 9,10,11,12,13, 9,10,10,13,12,11,12,13,
+ 14,15,11,12,12,15,14, 9, 9,11,11,13,10,10,12,12,
+ 14,10,10,11,13,14,12,12,13,14,16,12,13,13,15,15,
+ 9,11,10,13,12,10,11,11,13,14,10,12,11,14,13,12,
+ 13,13,15,16,12,13,13,15,15,11,11,13,13,15,12,12,
+ 14,13,15,13,13,14,14,15,14,14,15,14,17,15,15,15,
+ 16,16,12,13,12,15,14,13,14,14,15,15,12,14,13,15,
+ 14,15,15,15,17,17,14,15,14,17,15, 7, 9, 9,12,11,
+ 9,10,10,12,12, 9,11,10,13,12,11,12,12,14,14,11,
+ 13,12,15,14, 9,10,10,12,12,10,10,11,12,13,10,11,
+ 11,14,13,12,12,13,14,15,12,13,13,16,15, 9,10,10,
+ 13,12,10,11,11,13,13,10,11,10,14,12,13,13,13,15,
+ 15,12,13,12,15,14,11,12,12,14,14,12,12,13,14,15,
+ 13,14,13,15,15,14,13,15,14,16,15,16,15,17,16,12,
+ 12,12,14,14,13,13,14,15,15,12,13,12,15,14,15,15,
+ 16,16,17,14,15,14,17,14,10,11,12,13,14,11,12,13,
+ 14,15,11,12,13,14,15,13,14,15,15,17,14,15,15,16,
+ 16,11,12,13,12,15,12,12,14,13,16,13,13,14,13,16,
+ 14,14,16,14,18,15,15,16,16,17,12,13,12,15,15,13,
+ 14,14,15,16,13,14,13,16,15,15,15,16,17,18,15,15,
+ 15,17,16,14,14,15,14,17,15,14,16,14,17,15,15,16,
+ 15,18,16,16,17,16,19,17,17,17,17,18,14,15,15,17,
+ 16,15,16,16,17,17,15,16,15,18,16,17,17,18,18,18,
+ 16,17,16,18,17,10,11,11,14,13,11,12,12,15,14,11,
+ 13,12,15,14,14,15,15,16,16,14,15,15,17,16,11,12,
+ 12,15,14,12,13,13,15,14,13,14,13,16,14,14,15,15,
+ 16,16,15,16,15,18,16,11,13,12,15,15,13,14,14,15,
+ 15,12,14,13,16,15,15,16,16,17,17,15,16,15,17,16,
+ 14,15,14,16,16,14,15,15,16,16,15,16,15,17,16,16,
+ 16,17,16,17,17,18,17,19,18,14,15,15,17,16,15,16,
+ 16,17,17,15,15,15,18,16,17,18,18,18,18,16,17,16,
+ 19,16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12,
+ 11,10,11,12,13,14,10,11,11,14,13, 8, 9, 9,11,12,
+ 9,10,11,12,13, 9,10,10,13,13,11,12,13,13,15,11,
+ 12,12,15,14, 7, 9, 9,12,11, 9,10,10,12,13, 9,10,
+ 10,13,12,11,12,12,14,15,11,12,11,14,13,11,11,12,
+ 13,14,11,12,13,13,15,12,13,13,14,15,13,14,14,14,
+ 16,14,15,15,16,16,10,11,11,14,13,11,12,12,14,14,
+ 11,12,12,15,13,14,14,14,16,16,13,14,13,16,14, 7,
+ 9, 9,11,12, 9,10,10,12,13, 9,10,10,12,12,11,12,
+ 13,14,15,11,12,12,14,14, 9,10,10,12,13,10,10,11,
+ 12,14,10,11,11,13,13,12,12,13,14,15,13,13,13,15,
+ 15, 9,10,10,12,12,10,11,11,13,14,10,11,10,13,12,
+ 12,13,13,15,16,12,13,12,15,14,11,12,13,14,14,12,
+ 12,13,14,15,13,14,13,15,15,14,14,15,14,17,15,16,
+ 15,17,16,11,12,12,14,14,13,13,13,15,15,12,13,12,
+ 15,14,15,15,15,16,17,14,15,14,16,14, 8, 9, 9,12,
+ 11, 9,10,10,12,13, 9,11,10,13,12,11,12,12,14,15,
+ 11,12,12,15,14, 9,10,11,13,13,10,11,12,13,14,10,
+ 11,11,14,13,12,13,13,15,15,12,13,13,16,15, 9,11,
+ 9,13,11,10,11,10,14,13,10,12,10,14,12,12,13,13,
+ 15,15,12,13,12,16,14,12,12,13,14,15,12,13,14,14,
+ 16,13,14,14,15,15,14,14,15,15,17,15,16,15,17,16,
+ 11,13,11,15,13,13,14,13,15,14,12,14,12,16,13,15,
+ 15,15,16,16,14,15,14,17,14,10,11,11,13,14,11,12,
+ 13,14,15,11,12,12,14,15,14,14,15,16,17,14,15,15,
+ 16,16,11,12,13,14,15,12,13,14,15,16,13,14,14,15,
+ 16,15,15,16,16,18,15,16,16,17,17,11,12,12,14,15,
+ 13,13,14,14,16,12,13,13,15,15,15,15,16,16,18,14,
+ 15,15,16,16,14,15,15,16,17,15,15,16,16,17,15,16,
+ 16,17,17,16,16,17,16,19,17,18,17,18,18,14,14,15,
+ 16,16,15,15,16,16,17,14,15,15,16,16,17,17,18,18,
+ 19,16,17,16,17,16,10,12,11,14,13,11,13,12,15,14,
+ 11,13,12,15,14,14,15,15,16,16,13,15,14,17,15,12,
+ 13,13,15,15,13,13,14,15,16,13,14,14,16,16,14,15,
+ 15,17,17,15,16,16,17,17,11,13,12,15,12,13,14,13,
+ 16,13,12,14,12,16,13,15,16,15,17,16,14,16,14,18,
+ 14,14,15,15,16,17,15,15,16,16,17,15,16,16,17,17,
+ 16,16,17,17,18,17,18,17,18,18,14,15,14,17,14,15,
+ 16,15,18,15,15,16,15,18,14,17,17,17,18,17,16,17,
+ 16,19,16, 9,11,11,13,13,10,12,12,14,14,11,12,12,
+ 15,14,13,14,14,16,16,13,14,14,16,16,10,11,12,14,
+ 14,11,12,13,14,15,12,13,13,15,15,13,14,15,16,16,
+ 14,15,15,17,16,11,12,12,15,14,12,13,13,15,15,12,
+ 13,12,15,15,14,15,15,16,17,14,15,14,17,16,12,13,
+ 14,15,16,13,13,14,15,16,13,14,15,16,16,14,15,16,
+ 16,18,15,16,16,18,18,13,14,14,16,15,14,15,15,17,
+ 16,14,15,15,17,16,16,17,17,18,18,16,17,16,18,17,
+ 10,12,12,14,14,11,12,13,15,15,12,13,13,15,15,13,
+ 14,15,16,17,14,15,15,17,16,11,11,13,14,15,12,12,
+ 14,15,16,13,13,14,15,16,14,14,15,16,17,15,15,16,
+ 17,17,12,13,12,15,15,13,14,14,16,16,13,14,13,16,
+ 15,15,16,15,17,17,15,16,15,18,16,13,12,15,14,17,
+ 14,13,16,14,17,14,14,16,15,18,15,14,17,16,18,16,
+ 16,17,17,18,14,15,15,17,16,15,16,16,17,17,15,16,
+ 15,18,16,17,17,17,18,18,16,17,16,19,17,10,11,11,
+ 14,14,11,12,12,15,15,11,13,12,15,15,14,15,14,16,
+ 16,14,15,15,17,16,11,12,12,15,14,12,12,13,15,15,
+ 13,14,13,16,15,14,15,15,16,16,15,16,15,18,17,11,
+ 13,12,15,15,13,14,13,15,15,12,14,13,16,15,15,16,
+ 15,17,17,15,16,15,18,16,13,14,13,16,16,14,15,14,
+ 16,16,14,15,15,17,16,16,16,16,16,18,16,18,17,19,
+ 18,14,15,15,17,16,15,16,16,17,17,15,15,15,17,16,
+ 17,17,18,18,19,16,17,16,18,16,12,13,13,15,16,13,
+ 14,14,16,17,13,14,14,16,16,15,15,16,17,18,15,16,
+ 16,18,17,13,13,14,14,17,14,14,15,15,17,14,14,15,
+ 16,17,15,15,17,16,18,16,17,17,18,18,13,14,14,17,
+ 16,14,15,15,17,17,14,15,14,17,16,16,17,17,18,18,
+ 16,17,16,18,17,15,14,16,13,18,16,15,17,14,19,16,
+ 16,17,15,18,17,16,18,15,19,18,18,18,17,19,15,16,
+ 16,18,17,16,17,17,18,18,16,17,16,19,17,18,19,18,
+ 19,19,17,18,17,20,18,11,12,12,15,15,13,13,14,15,
+ 16,13,14,13,16,15,15,16,16,17,17,15,16,16,18,17,
+ 12,14,13,16,15,13,13,14,15,16,14,15,14,17,16,16,
+ 16,16,16,17,16,17,17,19,17,12,13,14,16,16,14,15,
+ 15,16,17,13,15,13,17,15,16,17,17,18,18,16,17,16,
+ 18,16,15,16,15,17,16,15,15,15,17,17,16,17,16,18,
+ 17,17,16,17,16,18,18,19,18,20,18,15,16,16,17,17,
+ 16,17,17,18,18,15,16,15,18,17,18,18,19,19,19,17,
+ 18,16,19,16, 9,11,11,13,13,11,12,12,14,15,10,12,
+ 12,14,14,13,14,14,16,16,13,14,14,16,16,11,12,12,
+ 14,14,12,12,13,15,15,12,13,13,15,15,14,15,15,16,
+ 17,14,15,15,16,16,10,12,11,14,14,12,13,13,15,15,
+ 11,13,12,15,14,14,15,15,16,17,13,15,14,17,16,13,
+ 14,14,15,16,14,15,15,16,17,14,15,15,16,17,16,16,
+ 17,17,18,16,17,17,18,18,12,14,13,16,15,13,15,14,
+ 17,16,13,14,13,17,15,15,16,16,18,18,15,16,15,18,
+ 16,10,11,11,14,14,11,12,13,14,15,11,12,12,15,15,
+ 14,15,15,16,17,14,15,15,16,16,11,12,13,15,15,12,
+ 13,14,15,16,13,14,14,15,16,15,15,16,16,18,15,15,
+ 16,17,17,11,12,12,14,15,13,13,14,15,16,12,13,13,
+ 15,15,15,15,16,17,18,14,15,15,17,16,14,15,15,16,
+ 17,15,15,16,16,17,15,16,16,17,17,16,16,17,16,19,
+ 17,17,18,19,18,13,13,14,16,16,14,15,16,17,17,14,
+ 14,15,16,16,16,16,17,18,18,16,16,16,18,16,10,12,
+ 12,14,14,12,13,13,15,15,11,13,12,15,15,14,15,15,
+ 16,17,13,15,14,17,16,12,13,13,15,15,13,13,14,15,
+ 16,13,14,14,16,16,15,15,16,17,18,15,15,16,17,17,
+ 11,13,12,15,14,13,14,13,16,15,12,14,12,16,14,15,
+ 16,15,17,17,14,16,14,17,16,14,15,15,16,17,15,15,
+ 16,16,18,15,16,16,17,17,16,17,17,17,19,17,17,17,
+ 18,18,13,15,12,17,14,14,16,14,17,15,14,15,13,17,
+ 14,16,17,16,18,17,15,17,14,19,15,11,12,12,15,15,
+ 13,13,14,15,16,13,14,13,16,15,15,16,16,17,18,15,
+ 16,16,17,17,12,14,13,16,16,13,13,15,15,17,14,15,
+ 15,17,16,16,16,17,16,19,16,17,17,18,18,12,13,14,
+ 15,16,14,14,15,16,17,13,14,13,16,15,16,17,17,18,
+ 19,15,16,16,17,16,15,16,16,18,17,15,15,16,17,18,
+ 16,17,17,18,18,16,16,18,16,19,18,19,19,20,19,15,
+ 15,16,16,17,16,16,17,17,18,15,15,15,17,16,18,18,
+ 19,18,20,17,17,16,18,16,12,13,13,16,15,13,14,14,
+ 16,16,13,14,14,16,16,15,16,16,17,18,15,16,15,18,
+ 17,13,14,14,16,16,14,15,15,16,17,14,15,15,17,17,
+ 16,17,17,18,18,16,17,17,18,18,13,14,13,17,14,14,
+ 15,14,17,16,14,15,14,17,15,16,17,17,18,18,15,17,
+ 15,19,15,16,16,16,17,18,16,16,17,17,19,16,17,17,
+ 18,19,17,17,18,18,20,18,18,18,19,19,15,16,14,18,
+ 13,16,17,16,19,15,16,17,15,19,14,18,18,18,19,17,
+ 17,18,16,20,15,
+};
+
+static const static_codebook _44p6_p2_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p6_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p6_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p3_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p6_p3_0[] = {
+ 1, 5, 5, 5, 7, 8, 5, 8, 7, 5, 7, 8, 8, 8,10, 8,
+ 10,10, 5, 8, 7, 8,10,10, 8,10, 8, 6, 8, 9, 8,10,
+ 12, 9,11,11, 9,10,11,11,11,13,12,13,13, 9,11,11,
+ 11,13,13,11,13,12, 6, 9, 8, 9,11,11, 8,12,10, 9,
+ 11,11,11,12,13,11,13,13, 9,11,10,11,13,13,11,13,
+ 11, 5, 9, 9, 8,11,11, 9,12,11, 8,10,11,10,11,13,
+ 11,13,13, 9,11,11,11,13,13,11,13,12, 8,10,11,10,
+ 12,13,10,13,12,10,10,13,11,11,14,12,13,14,11,13,
+ 12,13,14,14,12,14,12, 8,11,10,11,12,13,11,14,12,
+ 10,13,12,12,12,13,13,15,14,11,12,13,13,14,15,12,
+ 14,12, 5, 9, 9, 9,11,12, 8,11,11, 9,11,11,11,12,
+ 13,11,13,13, 8,11,10,11,13,13,10,13,11, 8,10,11,
+ 11,12,14,11,13,12,11,13,12,12,12,14,13,15,14,10,
+ 12,13,13,14,15,12,13,12, 8,11,10,10,12,13,10,13,
+ 12,11,12,13,12,12,14,13,14,14,10,13,10,12,14,13,
+ 11,14,11,
+};
+
+static const static_codebook _44p6_p3_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p6_p3_0,
+ 1, -533200896, 1614282752, 2, 0,
+ (long *)_vq_quantlist__44p6_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p3_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p6_p3_1[] = {
+ 5, 7, 7, 6, 7, 7, 6, 7, 7, 6, 7, 7, 7, 8, 8, 7,
+ 8, 8, 6, 7, 7, 7, 8, 8, 7, 8, 8, 7, 7, 8, 7, 8,
+ 8, 7, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8,
+ 8, 9, 9, 8, 9, 8, 7, 8, 7, 7, 8, 8, 7, 8, 8, 8,
+ 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9,
+ 8, 6, 8, 8, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 9,
+ 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8, 8,
+ 8, 9, 8, 9, 9, 8, 8, 9, 8, 9, 9, 9, 9, 9, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9, 9,
+ 9, 9, 6, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8,
+ 9, 8, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8,
+ 8, 8, 9, 8, 9, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8,
+ 8, 8, 9, 9, 9, 8, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9,
+ 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p6_p3_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p6_p3_1,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p6_p3_1,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p4_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p6_p4_0[] = {
+ 2, 5, 5, 5, 7, 8, 5, 8, 7, 5, 7, 7, 7, 7, 9, 7,
+ 9, 9, 5, 7, 7, 8, 9, 9, 7, 9, 7, 6, 8, 8, 8, 9,
+ 10, 8, 9, 9, 8, 9,10, 9, 9,11,10,11,11, 8, 9, 9,
+ 10,11,11, 9,11,10, 6, 8, 8, 8, 9, 9, 8,10, 9, 8,
+ 9, 9, 9,10,11,10,11,10, 8,10, 9,10,11,11, 9,11,
+ 9, 6, 8, 8, 7, 9, 9, 8,10, 9, 7, 9, 9, 9, 9,10,
+ 9,10,10, 8, 9, 9, 9,10,10, 9,11,10, 7, 9, 9, 8,
+ 10,10, 9,10,10, 9, 9,10,10,10,11,10,11,11, 9,10,
+ 10,10,11,11,10,11,10, 7, 9, 9, 9, 9,10, 9,10, 9,
+ 8,10, 9, 9, 9,11,10,11,11, 9,10,10,10,11,11, 9,
+ 11, 9, 6, 8, 8, 8, 9,10, 7, 9, 9, 8, 9, 9, 9,10,
+ 10, 9,10,10, 7, 9, 9, 9,10,10, 9,10, 9, 7, 9, 9,
+ 9, 9,10, 9,10, 9, 9,10,10, 9, 9,11,10,11,11, 8,
+ 9,10,10,11,11, 9,11, 9, 7, 9, 9, 9,10,10, 8,10,
+ 10, 9,10,10,10,10,11,10,11,11, 9,10, 9,10,11,11,
+ 10,11,10,
+};
+
+static const static_codebook _44p6_p4_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p6_p4_0,
+ 1, -531365888, 1616117760, 2, 0,
+ (long *)_vq_quantlist__44p6_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p4_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p6_p4_1[] = {
+ 6, 8, 8,10,10, 8, 9, 9,10,11, 8,10, 9,11,10, 9,
+ 10,10,11,11, 9,10,10,11,11, 8, 9, 9,10,10, 9, 9,
+ 10,11,11,10,10,10,11,11,10,11,11,11,11,10,11,11,
+ 11,11, 8, 9, 9,11,10,10,10,10,11,11, 9,10, 9,11,
+ 11,10,11,11,11,11,10,11,10,11,11,10,10,11,11,11,
+ 10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,10,11,10,11,11,11,11,11,11,11,10,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11, 8, 9,10,
+ 11,11,10,10,11,11,11,10,10,10,11,11,10,11,11,12,
+ 12,10,11,11,12,12,10,10,11,11,11,10,10,11,11,12,
+ 11,11,11,12,12,11,11,12,12,12,11,11,12,12,12,10,
+ 10,10,11,11,11,11,11,12,12,10,11,11,12,12,11,12,
+ 12,12,12,11,12,11,12,12,11,11,11,11,12,11,11,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,11,11,11,12,11,11,12,12,12,12,11,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12, 8,10, 9,11,11,10,
+ 10,10,11,11,10,11,10,11,11,10,11,11,12,12,10,11,
+ 11,12,12,10,10,10,11,11,10,11,11,12,12,11,11,11,
+ 12,12,11,11,12,12,12,11,12,12,12,12,10,11,10,11,
+ 11,11,11,11,12,12,10,11,10,12,11,11,12,11,12,12,
+ 11,12,11,12,12,11,11,11,12,12,11,11,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,
+ 11,12,11,11,12,12,12,12,11,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,10,11,11,11,12,11,11,12,12,
+ 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,
+ 11,11,12,12,12,11,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,13,11,12,11,12,12,12,12,
+ 12,12,12,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,13,12,13,12,12,12,12,13,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,12,
+ 12,12,13,12,10,11,11,12,11,11,11,12,12,12,11,12,
+ 11,12,12,11,12,12,12,12,11,12,12,12,12,11,11,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,11,12,11,12,12,12,12,12,12,12,
+ 11,12,12,12,12,12,12,12,12,12,12,12,12,13,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,13,12,12,12,12,13,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,13,13,12,13,12,13,
+ 12, 8,10,10,11,11,10,10,11,11,11,10,11,10,11,11,
+ 10,11,11,12,12,10,11,11,12,12, 9,10,11,11,11,10,
+ 10,11,12,12,10,11,11,12,12,11,11,12,12,12,11,12,
+ 12,12,12,10,11,10,11,11,11,11,11,12,12,10,11,11,
+ 12,12,11,12,12,12,12,11,12,11,12,12,11,11,11,12,
+ 12,11,11,12,12,12,11,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,11,11,11,12,12,11,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12, 9,10,
+ 10,11,11,10,11,11,12,12,10,11,11,12,12,11,11,12,
+ 12,12,11,12,12,12,12,10,11,11,12,12,11,11,12,12,
+ 12,11,11,12,12,12,11,11,12,12,12,12,12,12,12,12,
+ 10,11,11,12,12,11,12,12,12,12,11,12,11,12,12,12,
+ 12,12,12,12,12,12,12,12,12,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,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, 9,10,10,11,11,
+ 10,11,11,12,12,10,11,11,12,11,11,12,12,12,12,11,
+ 12,12,12,12,10,11,11,12,12,11,11,11,12,12,11,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,10,11,11,
+ 12,12,11,12,12,12,12,11,12,11,12,12,12,12,12,12,
+ 12,12,12,12,12,12,11,12,12,12,12,11,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,11,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,11,11,11,12,12,11,12,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 13,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,13,12,13,12,12,13,13,13,11,12,12,12,12,12,
+ 12,12,13,13,12,12,12,13,12,12,12,12,13,13,12,13,
+ 12,13,13,12,12,12,12,12,12,12,12,12,13,12,13,13,
+ 13,13,12,13,13,13,13,13,13,13,13,13,12,12,12,12,
+ 12,12,12,13,13,13,12,13,12,13,13,12,13,13,13,13,
+ 12,13,13,13,13,11,11,11,12,12,11,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,
+ 12,13,12,12,12,13,13,11,12,12,12,12,12,12,12,12,
+ 13,12,12,12,13,12,12,13,12,13,13,12,13,12,13,13,
+ 12,12,12,12,12,12,12,13,13,13,12,12,13,13,13,12,
+ 13,13,12,13,13,13,13,13,13,12,12,12,12,12,12,13,
+ 12,13,13,12,13,12,13,12,12,13,13,13,13,12,13,13,
+ 13,13, 8,10,10,11,11,10,10,11,11,11, 9,11,10,11,
+ 11,10,11,11,12,12,10,11,11,12,12,10,10,11,11,11,
+ 10,11,11,12,12,11,11,11,12,12,11,11,12,12,12,11,
+ 12,12,12,12, 9,11,10,11,11,10,11,11,12,12,10,11,
+ 10,12,12,11,12,12,12,12,11,12,11,12,12,11,11,11,
+ 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,11,11,11,12,12,11,12,12,12,12,
+ 11,12,11,12,12,12,12,12,12,12,12,12,12,12,12, 9,
+ 10,10,11,11,10,11,11,12,12,10,11,11,12,12,11,12,
+ 12,12,12,11,12,12,12,12,10,11,11,12,12,11,11,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,10,11,11,12,12,11,11,12,12,12,11,11,11,12,12,
+ 12,12,12,12,12,11,12,12,12,12,11,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,11,12,12,12,12,12,12,12,12,12,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12, 9,10,10,11,
+ 11,10,11,11,12,12,10,11,11,12,12,11,12,12,12,12,
+ 11,12,11,12,12,10,11,11,12,12,11,11,12,12,12,11,
+ 11,12,12,12,12,12,12,12,12,12,12,12,12,12,10,11,
+ 11,12,12,11,12,11,12,12,11,12,11,12,12,12,12,12,
+ 12,12,11,12,11,12,12,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,
+ 11,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,11,11,11,12,12,11,12,
+ 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,13,
+ 13,12,12,12,13,13,12,12,13,13,13,11,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,13,12,13,13,12,
+ 12,12,13,12,12,12,12,12,12,12,12,13,13,13,12,12,
+ 13,13,13,12,13,13,12,13,12,13,13,13,13,12,12,12,
+ 12,12,12,12,13,13,13,12,12,12,13,12,12,13,13,13,
+ 13,12,13,13,13,13,11,11,11,12,12,11,12,12,12,12,
+ 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,13,12,12,12,
+ 13,13,13,12,12,12,13,13,11,12,12,12,12,12,12,12,
+ 13,12,12,12,12,13,12,12,13,12,13,13,12,13,12,13,
+ 12,12,12,12,12,12,12,12,13,13,13,12,13,13,13,13,
+ 12,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,
+ 13,12,13,12,12,13,12,13,12,13,13,13,13,13,12,13,
+ 13,13,13,10,11,11,12,12,11,12,12,12,12,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,11,11,12,12,
+ 12,11,12,12,12,12,12,12,12,12,12,12,12,12,13,13,
+ 12,12,12,13,13,11,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,13,13,12,12,12,13,12,12,12,
+ 12,12,12,12,12,12,12,13,12,12,12,12,13,12,12,13,
+ 12,13,12,13,13,13,13,12,12,12,12,12,12,12,12,13,
+ 12,12,12,12,13,12,12,13,13,13,13,12,13,12,13,13,
+ 11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,12,
+ 12,12,12,13,12,12,12,13,12,11,12,12,12,12,12,12,
+ 12,12,13,12,12,12,12,13,12,12,13,13,13,12,12,13,
+ 13,13,11,12,12,12,12,12,12,12,12,13,12,12,12,13,
+ 12,12,13,12,13,13,12,13,12,13,13,12,12,12,12,12,
+ 12,12,13,12,13,12,12,13,13,13,12,12,13,13,13,13,
+ 13,13,13,13,12,12,12,12,12,12,13,13,13,13,12,13,
+ 12,13,12,12,13,13,13,13,12,13,13,13,13,11,11,11,
+ 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,13,11,12,12,12,12,12,12,12,12,13,
+ 12,12,12,13,13,12,12,13,13,13,12,12,13,13,13,11,
+ 12,12,12,12,12,12,12,13,13,12,12,12,13,12,12,13,
+ 12,13,13,12,13,12,13,13,12,12,12,12,12,12,12,12,
+ 12,13,12,13,12,13,13,12,13,13,13,13,12,13,13,13,
+ 13,12,12,12,12,12,12,13,12,13,13,12,12,12,13,13,
+ 12,13,13,13,13,12,13,12,13,13,11,12,12,12,12,11,
+ 12,12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,13,12,13,12,12,12,13,13,11,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,
+ 12,13,12,13,13,12,12,12,12,12,12,12,13,12,13,12,
+ 12,13,12,13,12,12,13,12,13,12,13,13,13,13,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,13,12,12,13,13,
+ 13,13,12,13,12,13,12,11,11,11,12,12,11,12,12,12,
+ 12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,13,13,11,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,13,13,12,12,12,
+ 13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,13,12,12,12,13,12,12,12,12,12,12,12,12,
+ 12,12,12,13,12,12,12,12,13,12,12,13,12,13,12,12,
+ 13,12,13,12,10,11,11,12,12,11,12,12,12,12,11,12,
+ 11,12,12,11,12,12,12,12,11,12,12,12,12,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 13,12,12,12,13,13,11,12,11,12,12,12,12,12,12,12,
+ 11,12,12,12,12,12,12,12,13,13,12,12,12,13,12,12,
+ 12,12,12,12,12,12,12,12,13,12,12,12,12,13,12,13,
+ 13,12,13,12,13,13,13,13,12,12,12,12,12,12,12,12,
+ 13,13,12,12,12,13,12,12,13,13,13,13,12,13,12,13,
+ 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,
+ 12,12,12,13,13,12,12,12,13,12,11,12,12,12,12,12,
+ 12,12,12,13,12,12,12,13,13,12,12,13,13,13,12,12,
+ 13,13,13,11,12,12,12,12,12,12,12,13,13,12,12,12,
+ 13,12,12,13,12,13,13,12,12,12,13,13,12,12,12,12,
+ 12,12,12,13,13,13,12,12,13,13,13,12,12,13,13,13,
+ 12,13,13,13,13,12,12,12,12,12,12,12,13,13,13,12,
+ 12,12,13,12,12,13,13,13,13,12,13,13,13,13,11,11,
+ 11,12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,
+ 12,13,12,12,12,13,13,11,12,12,12,12,12,12,12,12,
+ 13,12,12,12,13,13,12,12,13,13,13,12,12,13,13,13,
+ 11,12,12,12,12,12,12,12,13,12,12,12,12,13,12,12,
+ 13,12,13,13,12,13,12,13,13,12,12,12,12,12,12,12,
+ 12,13,13,12,13,12,13,13,12,13,13,13,13,13,13,13,
+ 13,13,12,12,12,12,12,12,13,12,13,13,12,13,12,13,
+ 12,12,13,13,13,13,12,13,12,13,13,11,11,11,12,12,
+ 11,12,12,12,12,11,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,13,12,12,12,13,13,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,
+ 13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,
+ 12,12,12,12,13,12,12,12,12,13,12,12,13,12,13,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 13,12,12,12,13,12,12,12,11,12,11,12,12,11,12,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,11,12,12,12,12,12,12,12,12,13,12,12,12,12,12,
+ 12,12,12,13,13,12,12,12,13,13,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,13,12,13,13,12,12,
+ 12,13,12,12,12,12,12,12,12,12,12,12,13,12,12,12,
+ 13,13,12,12,13,12,13,12,13,13,13,13,12,12,12,12,
+ 12,12,12,12,13,12,12,12,12,13,12,12,13,12,13,13,
+ 12,13,12,13,12,
+};
+
+static const static_codebook _44p6_p4_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p6_p4_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p6_p4_1,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p5_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p6_p5_0[] = {
+ 2, 6, 6,10,10, 5, 7, 8,11,12, 5, 8, 7,12,11, 9,
+ 11,11,13,15, 9,11,11,15,13, 6, 7, 8,11,11, 7, 7,
+ 9,11,13, 8, 9, 9,13,12,11,11,12,12,15,11,12,12,
+ 15,14, 6, 8, 7,11,11, 8, 9, 9,12,13, 7, 9, 7,13,
+ 11,11,12,12,14,15,11,12,11,15,12,10,11,11,12,14,
+ 10,11,12,12,15,12,13,13,14,15,13,12,14,12,16,15,
+ 15,15,16,16,10,11,11,14,12,12,13,13,15,14,10,12,
+ 11,15,12,15,15,15,16,17,13,14,12,17,12, 6, 8, 8,
+ 12,12, 8, 9,10,13,13, 8, 9, 9,13,13,12,12,13,15,
+ 16,12,13,13,16,15, 8, 9,10,12,13, 9, 9,11,13,14,
+ 10,11,11,14,14,13,13,14,15,16,13,14,14,16,16, 8,
+ 10, 9,13,13,10,11,11,14,14, 9,10,10,14,13,13,14,
+ 14,16,17,13,13,13,16,15,12,13,13,14,16,13,13,14,
+ 14,16,14,14,14,16,16,15,15,16,15,18,16,17,17,18,
+ 18,12,13,13,15,15,14,14,14,16,16,13,14,13,16,15,
+ 16,16,17,18,18,15,16,15,18,15, 6, 8, 8,12,12, 8,
+ 9, 9,13,13, 8,10, 9,13,13,12,13,13,15,16,12,13,
+ 12,16,15, 8, 9,10,13,13, 9,10,10,13,14,10,11,11,
+ 14,14,13,13,13,15,16,13,14,14,17,16, 8,10, 9,13,
+ 13,10,11,11,14,14, 9,11, 9,14,13,13,14,14,16,16,
+ 13,14,13,16,14,12,13,13,15,16,13,13,14,15,16,14,
+ 14,14,16,16,15,15,16,15,18,17,17,17,18,18,12,13,
+ 13,16,14,14,14,14,16,16,13,14,13,16,14,16,17,17,
+ 18,18,15,16,15,18,15,11,12,13,14,16,13,13,14,15,
+ 17,13,14,14,16,17,16,16,17,17,19,16,17,17,18,19,
+ 13,13,14,16,16,14,14,15,16,17,14,15,15,17,17,17,
+ 16,17,17,19,17,17,18,19,19,13,14,14,16,16,14,14,
+ 15,17,18,14,15,14,17,17,17,17,18,18,19,17,17,17,
+ 18,19,16,16,16,17,18,17,17,17,18,19,17,17,17,18,
+ 19,18,18,19,18,20,19,20,19,21,20,16,17,17,18,18,
+ 17,17,18,19,19,17,17,17,19,18,19,19,19,19,20,19,
+ 19,19,20,19,11,13,12,16,14,13,14,14,17,16,13,14,
+ 13,17,15,16,17,17,18,18,16,17,16,19,17,13,14,14,
+ 16,16,14,14,14,17,17,14,15,15,17,16,17,17,17,19,
+ 19,17,18,17,19,18,13,14,13,17,16,14,15,15,17,17,
+ 14,15,14,18,16,17,17,17,19,19,17,17,16,19,17,16,
+ 17,17,18,19,17,17,17,18,18,17,18,17,19,18,18,19,
+ 18,19,19,19,20,19,20,20,16,17,16,18,17,17,17,17,
+ 18,18,17,18,17,19,17,19,19,19,19,20,18,19,19,20,
+ 18, 6, 8, 8,12,12, 8, 9, 9,13,13, 8,10, 9,13,13,
+ 11,13,13,15,16,12,13,13,16,15, 8, 9, 9,13,13, 9,
+ 9,10,13,14,10,11,11,14,14,12,12,13,14,16,13,14,
+ 14,17,16, 8,10, 9,13,13,10,11,11,14,14, 9,11,10,
+ 14,13,13,14,14,16,16,13,14,13,16,15,12,13,13,14,
+ 16,12,13,14,14,16,13,14,14,16,16,15,14,16,15,18,
+ 16,17,17,18,17,12,13,13,16,15,14,14,14,16,16,13,
+ 14,13,16,15,16,16,17,17,17,15,16,15,18,15, 7, 9,
+ 9,13,13, 9, 9,11,13,14, 9,10,10,14,13,12,13,14,
+ 15,16,12,14,13,17,15, 9, 9,10,13,14,10, 9,11,13,
+ 15,11,11,11,14,14,13,12,14,14,17,14,14,14,17,16,
+ 9,10,10,14,13,11,11,11,14,14,10,11,10,15,13,14,
+ 14,14,16,17,13,14,13,17,14,13,13,14,14,16,13,13,
+ 14,14,17,14,14,14,16,16,15,14,16,15,18,17,17,17,
+ 18,18,13,14,13,16,15,14,14,15,17,16,13,14,13,17,
+ 15,17,16,17,17,17,15,16,14,18,14, 7, 9, 9,13,13,
+ 9,10,10,13,14, 9,11,10,14,13,13,14,14,16,16,13,
+ 14,14,17,15, 9,10,10,14,13, 9,10,11,13,14,11,12,
+ 11,15,14,13,13,14,14,16,14,15,15,17,17, 9,10,10,
+ 14,14,11,12,12,14,15,10,11,10,15,13,14,15,15,17,
+ 17,14,15,13,17,14,13,14,13,16,16,13,13,14,15,16,
+ 14,15,15,17,17,15,14,16,15,18,17,18,17,20,18,13,
+ 14,14,16,16,15,15,15,17,17,13,14,13,17,15,17,17,
+ 18,18,18,15,16,14,19,14,12,13,13,15,16,13,13,15,
+ 16,17,13,14,14,16,16,15,15,17,17,19,16,17,17,19,
+ 18,13,13,14,15,17,14,13,15,15,17,14,15,15,16,17,
+ 16,15,18,16,19,17,17,17,18,19,13,14,14,17,16,14,
+ 15,15,17,17,14,15,14,17,16,17,17,17,18,19,16,17,
+ 16,19,17,16,16,17,16,18,16,16,17,16,19,17,17,18,
+ 18,19,18,17,18,17,21,19,19,19,20,19,16,17,17,18,
+ 18,17,17,18,18,19,16,17,16,18,18,19,19,19,19,20,
+ 18,18,17,20,18,11,13,13,16,15,13,14,14,16,17,13,
+ 15,14,17,16,16,17,17,18,18,17,17,17,19,18,13,14,
+ 13,17,16,14,13,14,16,17,15,16,15,18,16,17,16,17,
+ 17,19,18,18,18,20,18,13,14,14,16,17,15,15,15,17,
+ 18,14,15,14,18,16,18,18,18,19,20,17,18,16,20,17,
+ 16,17,16,18,18,16,16,17,18,18,17,18,18,19,18,18,
+ 17,19,17,20,19,20,19,22,20,16,16,17,18,18,18,17,
+ 17,19,19,16,17,16,18,17,19,20,19,22,21,18,19,18,
+ 21,17, 6, 8, 8,12,12, 8, 9,10,13,13, 8, 9, 9,13,
+ 13,12,13,13,15,16,11,13,13,16,15, 8, 9,10,13,13,
+ 9,10,11,13,14,10,11,11,14,14,13,13,14,15,16,13,
+ 14,14,16,16, 8, 9, 9,13,13,10,11,11,14,14, 9,10,
+ 9,14,13,13,14,14,16,17,12,14,12,16,14,12,13,13,
+ 15,16,13,13,14,15,16,13,14,14,15,17,15,15,16,15,
+ 18,16,16,17,17,17,12,13,13,16,14,13,14,14,16,16,
+ 12,14,13,16,14,16,17,17,18,18,15,15,14,18,14, 7,
+ 9, 9,13,13, 9,10,11,13,14, 9,10,10,14,13,13,14,
+ 14,15,17,13,14,14,16,15, 9,10,10,14,14,10,10,11,
+ 13,15,11,12,12,15,14,14,13,15,14,17,14,15,15,17,
+ 17, 9,10,10,13,14,11,11,12,14,15, 9,11,10,14,13,
+ 14,15,15,16,18,13,14,13,16,14,13,14,14,16,16,13,
+ 13,14,15,17,15,15,15,16,17,15,14,16,15,18,17,17,
+ 18,19,18,13,14,14,16,16,14,15,15,17,17,13,14,13,
+ 16,15,17,17,18,18,18,15,16,14,18,15, 7, 9, 9,13,
+ 13, 9,10,10,13,14, 9,11,10,14,13,12,13,14,15,16,
+ 12,14,13,16,15, 9,10,10,13,14,10,10,11,13,14,11,
+ 11,11,15,14,13,13,14,14,16,14,14,14,17,16, 9,10,
+ 9,14,13,11,11,11,14,14,10,11, 9,15,13,14,14,14,
+ 16,16,13,14,12,17,14,13,13,14,15,16,13,13,14,15,
+ 16,14,15,14,16,17,15,14,16,14,18,16,17,17,18,18,
+ 13,14,13,16,14,14,14,14,16,16,13,14,13,17,14,17,
+ 17,17,18,18,15,16,14,18,15,11,13,13,16,16,13,14,
+ 15,16,17,13,14,14,17,16,16,17,17,18,19,17,17,17,
+ 19,18,13,14,14,17,17,13,13,15,16,18,15,15,15,17,
+ 17,17,16,18,17,20,18,17,18,19,19,13,14,14,16,17,
+ 15,15,16,16,18,14,15,14,16,16,17,17,18,18,20,17,
+ 18,16,18,17,16,17,16,19,18,16,16,17,18,19,18,18,
+ 18,19,19,18,17,18,17,21,20,19,19,21,21,16,16,17,
+ 18,18,17,17,18,19,19,16,17,16,19,18,20,20,20,19,
+ 21,18,18,17,20,18,12,13,13,16,15,13,14,14,16,16,
+ 13,14,13,17,16,16,17,17,18,18,15,17,15,19,17,13,
+ 14,14,16,17,14,14,15,16,17,14,15,15,17,17,16,16,
+ 17,17,18,17,17,17,19,19,13,14,13,17,15,14,15,15,
+ 17,16,14,15,13,17,15,17,18,17,19,18,16,17,15,20,
+ 16,16,17,17,18,18,16,16,17,18,18,17,18,17,19,18,
+ 17,17,18,18,20,19,20,19,20,19,16,16,16,19,16,17,
+ 17,17,19,18,16,17,16,19,16,19,19,19,19,19,18,19,
+ 17,19,17,11,13,13,16,16,13,14,14,17,17,13,14,14,
+ 17,17,15,17,17,19,19,16,18,17,20,19,12,14,14,17,
+ 17,13,14,15,17,18,14,15,15,17,18,16,16,17,18,20,
+ 17,18,18,20,18,13,14,14,17,17,14,15,15,17,18,14,
+ 15,15,17,17,17,18,17,19,19,17,18,17,19,19,15,16,
+ 16,18,18,15,16,17,18,19,16,17,17,19,19,17,17,18,
+ 18,21,18,19,19,21,19,16,17,17,18,18,17,17,18,19,
+ 19,17,18,17,19,19,19,19,19,20,20,18,19,18,21,19,
+ 12,13,13,16,16,13,14,14,16,17,13,15,14,17,16,15,
+ 16,17,17,19,16,17,17,19,18,13,13,14,16,17,14,13,
+ 15,16,17,14,15,15,17,17,15,15,17,17,20,17,17,18,
+ 19,18,13,14,14,17,16,15,15,15,17,18,14,15,14,17,
+ 16,17,17,17,18,18,16,17,16,19,17,16,15,17,17,19,
+ 16,15,17,16,19,17,16,17,18,19,17,16,19,16,20,19,
+ 18,19,19,19,16,17,17,18,18,17,17,17,18,19,16,17,
+ 16,19,18,20,19,19,20,19,18,18,17,20,17,11,13,13,
+ 16,16,13,14,15,16,17,14,15,14,18,16,17,17,17,18,
+ 21,17,18,17,20,19,13,14,14,17,16,13,14,15,16,18,
+ 15,16,15,18,17,17,16,17,17,19,17,18,18,20,19,13,
+ 14,14,16,17,15,15,16,17,18,14,15,14,18,17,17,18,
+ 18,19,20,17,18,16,19,17,16,17,15,19,18,16,16,16,
+ 18,18,17,18,17,20,19,18,17,18,17,20,20,20,19,22,
+ 20,16,17,17,18,19,18,18,18,19,20,16,17,16,19,18,
+ 20,19,19,20,20,18,19,17,20,17,13,14,14,16,17,14,
+ 14,16,16,18,14,16,15,17,16,16,16,17,17,18,17,17,
+ 16,19,18,14,14,15,16,17,14,14,16,16,18,16,16,16,
+ 17,17,16,15,17,16,19,18,18,18,19,19,14,15,15,17,
+ 17,15,16,16,17,18,14,16,14,18,16,17,17,18,18,19,
+ 16,17,16,19,17,16,16,17,16,18,16,16,17,16,19,18,
+ 18,18,17,18,17,16,18,16,20,19,19,19,19,19,16,17,
+ 17,18,18,17,17,18,19,19,16,17,16,19,17,18,19,19,
+ 19,20,17,18,16,20,16,11,14,13,17,17,14,14,16,16,
+ 18,14,16,14,19,16,18,18,19,18,19,18,19,18,21,18,
+ 13,15,14,18,16,14,14,16,16,18,16,17,16,19,17,18,
+ 16,19,17,20,19,19,19,21,19,13,14,15,17,18,17,16,
+ 17,17,19,14,16,14,18,16,20,19,19,20,21,18,19,16,
+ 21,17,17,18,16,19,17,16,16,17,18,18,19,19,18,21,
+ 18,17,17,18,17,20,20,20,20,22,20,17,17,18,18,20,
+ 19,19,19,18,20,16,17,17,19,19,21,21,21,20,21,17,
+ 19,17,23,17,11,13,13,16,16,13,14,14,17,17,13,14,
+ 14,17,17,16,17,17,19,20,15,16,16,19,19,13,14,14,
+ 16,17,14,15,15,17,18,14,15,15,17,17,17,17,18,19,
+ 19,17,17,18,19,19,13,14,14,17,16,14,15,15,17,17,
+ 13,15,14,18,17,17,18,18,19,20,16,17,16,19,18,16,
+ 16,17,18,18,17,17,17,18,19,17,18,17,19,19,19,19,
+ 19,19,20,19,20,19,20,20,15,16,16,18,17,16,17,17,
+ 20,18,15,16,16,19,17,19,19,19,20,20,17,18,17,21,
+ 17,11,13,13,16,16,13,14,15,16,17,13,15,14,17,16,
+ 17,17,18,18,20,17,17,17,19,19,13,14,14,17,17,14,
+ 14,15,17,18,15,15,15,18,17,17,17,18,17,20,18,18,
+ 17,20,18,13,14,14,16,17,15,15,16,17,18,14,15,13,
+ 17,17,17,18,18,19,20,17,17,16,19,17,16,17,17,18,
+ 18,16,16,17,18,18,18,18,18,19,19,18,17,19,18,21,
+ 19,20,20,20,20,16,15,17,18,18,17,17,18,18,20,16,
+ 16,16,18,17,20,19,20,21,22,17,18,17,20,17,12,13,
+ 13,16,16,13,14,15,16,17,13,14,14,17,16,16,17,18,
+ 18,19,15,16,16,19,18,13,14,14,16,17,14,14,15,16,
+ 17,14,15,15,17,17,16,16,17,17,19,17,17,17,19,18,
+ 13,14,13,17,16,14,15,15,17,17,13,15,13,17,16,17,
+ 17,17,19,19,15,17,15,19,17,16,17,17,18,18,16,16,
+ 17,17,19,17,18,17,19,19,18,17,19,17,19,19,19,19,
+ 20,19,15,17,15,19,16,17,17,16,19,18,16,17,15,18,
+ 16,19,19,19,20,19,17,19,16,19,16,11,14,14,17,17,
+ 15,14,16,16,18,15,16,14,18,16,18,18,19,18,21,18,
+ 19,18,20,18,13,15,14,18,17,14,14,16,16,18,16,17,
+ 16,19,17,17,17,19,17,22,19,19,19,21,19,13,14,15,
+ 17,18,17,16,17,17,19,14,16,14,18,16,19,19,19,20,
+ 21,18,18,16,20,17,17,18,16,19,18,15,17,17,19,19,
+ 19,19,18,21,19,18,17,20,17,21,22,21,20,21,21,17,
+ 16,19,18,20,19,18,19,18,20,16,17,16,19,18,21,20,
+ 21,19,23,18,19,16,20,17,13,14,14,17,16,14,14,15,
+ 16,18,14,16,14,17,16,16,16,17,17,19,16,17,16,19,
+ 17,14,15,15,17,17,14,14,16,16,17,15,16,16,18,17,
+ 16,16,17,17,19,17,18,17,19,18,14,15,14,17,16,16,
+ 16,16,17,17,14,16,14,17,16,18,18,18,18,19,16,17,
+ 15,19,16,17,17,17,18,18,16,15,17,17,18,18,18,18,
+ 19,19,17,16,18,16,19,19,19,19,19,19,16,17,16,19,
+ 16,18,18,17,19,18,16,17,16,19,16,19,19,20,19,19,
+ 17,18,16,20,16,
+};
+
+static const static_codebook _44p6_p5_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p6_p5_0,
+ 1, -528744448, 1616642048, 3, 0,
+ (long *)_vq_quantlist__44p6_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p5_1[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44p6_p5_1[] = {
+ 2, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _44p6_p5_1 = {
+ 1, 7,
+ (char *)_vq_lengthlist__44p6_p5_1,
+ 1, -533200896, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p6_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p6_p6_0[] = {
+ 1, 5, 5, 5, 7, 9, 5, 9, 7, 5, 7, 8, 7, 7,10, 9,
+ 10,10, 5, 8, 7, 9,10,10, 7,10, 7, 6, 9, 9, 9,10,
+ 12, 9,11,11, 9,10,11,11,11,13,12,13,13, 9,11,11,
+ 12,13,13,11,13,11, 6, 9, 9, 9,11,11, 9,12,10, 9,
+ 11,11,11,11,13,12,13,13, 9,11,10,12,13,13,11,13,
+ 11, 6, 9, 9, 9,11,12, 9,12,11, 9,10,11,10,10,13,
+ 12,13,13, 9,11,11,12,13,12,11,13,11, 7, 9,10, 9,
+ 10,12,10,12,11,10,10,12,10,10,12,12,12,13,10,11,
+ 11,12,12,13,10,12,10, 7,10,10,11,11,14,11,14,11,
+ 10,12,11,11,11,14,14,14,14,10,11,12,14,14,14,11,
+ 14,11, 6, 9, 9, 9,11,12, 9,12,11, 9,11,11,11,11,
+ 13,12,12,13, 9,11,10,12,13,13,10,13,10, 7,10,10,
+ 11,11,14,11,14,11,10,12,11,11,11,14,14,15,14,10,
+ 11,12,13,14,15,11,14,11, 7,10, 9,10,11,12, 9,12,
+ 10,10,11,11,10,10,12,12,13,12, 9,12,10,12,13,12,
+ 10,12,10,
+};
+
+static const static_codebook _44p6_p6_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p6_p6_0,
+ 1, -527106048, 1620377600, 2, 0,
+ (long *)_vq_quantlist__44p6_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p6_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p6_p6_1[] = {
+ 2, 6, 6, 6, 7, 8, 6, 8, 7, 6, 7, 7, 7, 7, 8, 7,
+ 8, 8, 6, 7, 7, 7, 8, 8, 7, 8, 7, 6, 8, 8, 8, 9,
+ 9, 8, 9, 9, 8, 9, 9, 9, 9,10, 9,10,10, 8, 9, 9,
+ 9,10,10, 9,10, 9, 6, 8, 8, 8, 9, 9, 8, 9, 9, 8,
+ 9, 9, 9, 9,10, 9,10,10, 8, 9, 9, 9,10, 9, 9,10,
+ 9, 6, 8, 8, 8, 9, 9, 8, 9, 9, 8, 9, 9, 9, 9,10,
+ 9, 9,10, 8, 9, 9, 9,10, 9, 9,10, 9, 7, 8, 8, 8,
+ 9, 9, 8, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8, 9,
+ 9, 9,10, 9, 9, 9, 9, 7, 9, 9, 9, 9,10, 9,10, 9,
+ 9, 9, 9, 9, 9,10,10,10,10, 9, 9, 9,10,10,10, 9,
+ 10, 9, 6, 8, 8, 8, 9, 9, 8, 9, 9, 8, 9, 9, 9, 9,
+ 10, 9,10,10, 8, 9, 9, 9,10, 9, 9,10, 9, 7, 9, 9,
+ 9, 9,10, 9,10, 9, 9, 9, 9, 9, 9,10,10,10,10, 9,
+ 9, 9,10,10,10, 9,10, 9, 7, 8, 8, 8, 9, 9, 8, 9,
+ 9, 8, 9, 9, 9, 9,10, 9, 9,10, 8, 9, 8, 9, 9, 9,
+ 9,10, 9,
+};
+
+static const static_codebook _44p6_p6_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p6_p6_1,
+ 1, -530841600, 1616642048, 2, 0,
+ (long *)_vq_quantlist__44p6_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p6_p7_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p6_p7_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p6_p7_0,
+ 1, -513979392, 1633504256, 2, 0,
+ (long *)_vq_quantlist__44p6_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p7_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p6_p7_1[] = {
+ 1, 4, 5, 5,10,10, 5,10,10, 5,10,10,10,10,10,10,
+ 10,10, 5,10,10,10,10,10,10,10,10, 7,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10, 6,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10, 6,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10, 9,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10, 9,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10, 6,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10, 9,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10, 9,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,
+ 11,11,11,
+};
+
+static const static_codebook _44p6_p7_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p6_p7_1,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p6_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p7_2[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p6_p7_2[] = {
+ 1, 2, 3, 4, 5, 7, 7, 8, 8, 9, 9,10,10,11,11,12,
+ 12,13,13,14,14,15,15,15,15,
+};
+
+static const static_codebook _44p6_p7_2 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p6_p7_2,
+ 1, -518864896, 1620639744, 5, 0,
+ (long *)_vq_quantlist__44p6_p7_2,
+ 0
+};
+
+static const long _vq_quantlist__44p6_p7_3[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p6_p7_3[] = {
+ 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p6_p7_3 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p6_p7_3,
+ 1, -529006592, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44p6_p7_3,
+ 0
+};
+
+static const char _huff_lengthlist__44p6_short[] = {
+ 2, 8,13,15,16,18,21,22, 5, 4, 6, 8,10,12,17,21,
+ 9, 5, 5, 6, 8,11,15,19,11, 6, 5, 5, 6, 7,12,14,
+ 14, 8, 7, 5, 4, 4, 9,11,16,11, 9, 7, 4, 3, 7,10,
+ 22,15,14,12, 8, 7, 9,11,21,16,15,12, 9, 5, 6, 8,
+};
+
+static const static_codebook _huff_book__44p6_short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p6_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p7_l0_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44p7_l0_0[] = {
+ 2, 4, 4, 7, 7, 8, 8,10,10,11,11,12,12, 4, 5, 5,
+ 7, 7, 9, 9,11, 9,12,11,12,12, 4, 5, 5, 7, 7, 9,
+ 9, 9,10,10,11,12,12, 7, 7, 7, 7, 8, 9, 8,11, 5,
+ 12, 6,12,10, 7, 7, 7, 8, 7, 8, 9, 5,11, 6,12,10,
+ 12, 8, 9, 9, 9, 9,10,10,11, 7,11, 7,12, 9, 8, 9,
+ 8, 9, 9,10,10, 7,11, 7,11, 9,11,10,10,10,10,10,
+ 10,10,11,10,11, 8,11, 9,10,10,10,10,10,10,10,10,
+ 11, 8,10, 9,11,10,11,11,11,11,11,10,11,10,12,10,
+ 12,11,10,11,11,11,11,10,11,10,11,10,12,11,12,11,
+ 12,12,12,12,12,12,12,12,12,12,13,12,11,12,11,12,
+ 12,12,12,12,11,12,11,12,13,
+};
+
+static const static_codebook _44p7_l0_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44p7_l0_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44p7_l0_0,
+ 0
+};
+
+static const long _vq_quantlist__44p7_l0_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p7_l0_1[] = {
+ 4, 4, 4, 5, 5, 4, 4, 5, 5, 5, 4, 5, 4, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p7_l0_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p7_l0_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p7_l0_1,
+ 0
+};
+
+static const long _vq_quantlist__44p7_l1_0[] = {
+ 54,
+ 29,
+ 79,
+ 0,
+ 108,
+};
+
+static const char _vq_lengthlist__44p7_l1_0[] = {
+ 1, 2, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44p7_l1_0 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p7_l1_0,
+ 1, -514516992, 1620639744, 7, 0,
+ (long *)_vq_quantlist__44p7_l1_0,
+ 0
+};
+
+static const char _huff_lengthlist__44p7_lfe[] = {
+ 2, 3, 1, 3,
+};
+
+static const static_codebook _huff_book__44p7_lfe = {
+ 2, 4,
+ (char *)_huff_lengthlist__44p7_lfe,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44p7_long[] = {
+ 2, 7,14,16,17,17,18,20, 6, 3, 5, 8,10,11,13,15,
+ 13, 5, 3, 5, 8, 9,11,12,15, 7, 4, 3, 5, 7, 9,11,
+ 16,10, 7, 5, 6, 7, 9,10,17,11, 8, 7, 7, 6, 8, 8,
+ 19,13,11, 9, 9, 8, 8, 9,20,14,13,11,10, 8, 9, 9,
+};
+
+static const static_codebook _huff_book__44p7_long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p7_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p7_p1_0[] = {
+ 2, 5, 5, 4, 7, 7, 4, 7, 7, 5, 7, 7, 7, 8, 9, 7,
+ 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 6, 7, 8, 8, 9,
+ 10, 8, 9,10, 8, 9,10,10,10,12,10,11,11, 8,10,10,
+ 10,11,12,10,11,11, 6, 8, 7, 8,10, 9, 8,10, 9, 8,
+ 10,10,10,11,11,10,12,11, 8,10, 9,10,11,11,10,12,
+ 10, 5, 8, 8, 8,10,10, 8,10,10, 7, 9,10, 9,10,11,
+ 9,11,11, 8,10,10,10,11,12,10,12,11, 7, 9, 9, 9,
+ 10,11, 9,11,11, 9, 9,11,10,11,12,11,11,12, 9,11,
+ 11,11,12,12,11,12,12, 7, 9, 9,10,11,11,10,12,11,
+ 9,11,10,11,11,12,11,13,12,10,11,11,12,13,13,11,
+ 13,11, 5, 8, 8, 8,10,10, 8,10,10, 8,10,10,10,11,
+ 12,10,12,11, 7,10, 9, 9,11,11, 9,11,10, 7, 9, 9,
+ 10,11,12,10,11,11,10,11,11,11,11,13,12,13,13, 9,
+ 10,11,11,12,13,11,12,11, 7, 9, 9, 9,11,11, 9,11,
+ 10, 9,11,11,11,12,12,11,12,12, 9,11, 9,11,12,11,
+ 10,12,11,
+};
+
+static const static_codebook _44p7_p1_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p7_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p7_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p7_p2_0[] = {
+ 4, 6, 6, 9, 9, 6, 8, 8,10,10, 6, 8, 8,10,10, 8,
+ 10,10,12,13, 8,10,10,13,12, 6, 8, 8,10,10, 8, 8,
+ 9,10,11, 8, 9, 9,11,11,10,10,11,12,13,10,11,11,
+ 13,13, 6, 8, 8,10,10, 8, 9, 9,11,11, 8, 9, 8,11,
+ 10,10,11,11,13,13,10,11,10,13,12, 9,10,10,12,12,
+ 10,10,11,12,13,10,11,11,13,13,12,12,13,12,15,13,
+ 13,13,15,14, 9,10,10,12,12,10,11,11,13,13,10,11,
+ 10,13,12,12,13,13,14,15,12,13,12,15,12, 6, 8, 8,
+ 10,11, 8, 9,10,11,12, 8, 9, 9,11,11,10,11,12,13,
+ 14,10,11,11,13,13, 8, 9, 9,11,12, 9,10,11,12,13,
+ 9,10,10,12,13,11,12,13,13,15,11,12,12,14,14, 8,
+ 9, 9,11,12, 9,10,11,12,13, 9,10,10,13,12,11,12,
+ 13,14,15,11,12,12,14,13,10,11,12,13,14,11,12,13,
+ 13,15,12,13,13,14,14,13,13,14,14,16,14,15,14,16,
+ 15,10,12,11,14,13,12,12,13,14,14,11,12,12,14,14,
+ 14,14,15,15,16,13,14,14,16,14, 6, 8, 8,11,10, 8,
+ 9, 9,11,11, 8,10, 9,12,11,10,11,11,13,13,10,12,
+ 11,14,13, 8, 9, 9,12,11, 9,10,10,12,13, 9,11,10,
+ 13,12,11,12,12,14,14,11,13,12,15,14, 8, 9, 9,12,
+ 11, 9,10,10,13,12, 9,11,10,13,12,11,12,12,14,14,
+ 11,13,12,15,13,10,11,12,13,14,11,12,13,13,14,12,
+ 13,12,14,14,13,13,14,14,16,14,15,14,16,16,10,12,
+ 11,14,13,12,13,13,14,14,11,13,12,15,13,14,14,15,
+ 16,16,13,14,13,16,14, 9,10,11,12,13,11,11,12,13,
+ 14,11,11,12,13,14,13,13,14,14,16,13,14,14,15,15,
+ 11,11,12,13,14,12,12,13,13,15,12,13,13,14,15,14,
+ 14,15,15,17,14,14,15,16,16,11,12,12,13,14,12,12,
+ 13,14,15,12,13,12,14,15,14,14,15,15,17,14,15,14,
+ 16,16,13,14,14,15,16,14,14,15,15,17,14,15,15,16,
+ 16,15,16,17,16,18,16,17,16,17,17,13,14,14,16,15,
+ 14,15,15,16,16,14,15,14,16,15,16,16,17,17,18,16,
+ 16,16,17,16, 9,11,10,13,12,11,12,11,14,13,11,12,
+ 11,14,13,13,14,14,16,15,13,14,13,16,14,11,12,12,
+ 14,13,12,12,13,14,14,12,13,13,15,14,14,14,15,16,
+ 16,14,15,14,17,15,11,12,11,14,13,12,13,13,15,14,
+ 12,13,12,15,13,14,15,14,16,16,14,15,14,17,15,13,
+ 14,14,15,16,14,14,15,16,16,14,15,15,16,16,15,16,
+ 16,16,17,16,16,16,17,17,13,14,14,16,15,14,15,15,
+ 17,16,14,15,14,17,15,16,17,17,17,17,16,16,16,18,
+ 16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12,11,
+ 10,11,11,13,14,10,11,11,14,13, 8, 9, 9,11,12, 9,
+ 10,10,12,13, 9,10,10,13,12,11,11,12,13,15,11,12,
+ 12,15,14, 8, 9, 9,12,11, 9,10,11,12,13, 9,11,10,
+ 13,12,11,12,12,14,15,11,13,12,15,14,10,11,11,13,
+ 14,11,12,12,13,14,11,12,12,14,14,13,13,14,14,16,
+ 13,14,14,16,15,11,12,11,14,13,12,13,13,14,14,11,
+ 13,12,14,13,14,14,15,16,16,13,14,14,16,14, 8, 9,
+ 9,11,12, 9,10,10,12,13, 9,10,10,13,12,11,12,12,
+ 14,15,11,12,12,14,14, 9, 9,10,11,13,10,10,12,12,
+ 14,10,10,11,13,13,12,12,13,14,16,12,12,13,15,15,
+ 9,10,10,13,12,10,11,11,13,14,10,12,11,14,13,12,
+ 13,13,15,15,12,13,13,15,15,11,11,12,13,15,12,12,
+ 13,13,15,12,13,13,14,15,14,14,15,15,17,14,15,15,
+ 16,16,11,13,12,15,14,13,13,13,15,15,12,14,13,15,
+ 14,15,15,15,16,16,14,15,15,17,15, 7, 9, 9,12,11,
+ 9,10,10,12,12, 9,11,10,13,12,11,12,12,14,14,11,
+ 13,12,15,14, 9,10,10,12,12,10,10,11,12,13,10,11,
+ 11,14,13,12,12,13,14,15,12,13,13,15,14, 9,10,10,
+ 12,12,10,11,11,13,13,10,11,10,14,12,12,13,13,15,
+ 15,12,13,12,15,13,11,12,12,14,14,12,12,13,14,15,
+ 12,13,13,15,15,14,13,14,13,16,14,15,15,16,16,11,
+ 12,12,14,14,13,13,14,15,15,12,13,12,15,14,15,15,
+ 15,16,16,14,15,14,17,14,10,11,12,13,14,11,12,13,
+ 14,15,11,12,12,14,15,13,14,15,15,17,14,14,14,16,
+ 16,11,12,13,12,15,12,12,14,13,16,13,13,14,13,16,
+ 14,14,15,14,17,15,15,15,15,17,11,13,12,15,15,13,
+ 13,14,15,16,12,14,13,16,15,15,15,15,17,17,15,15,
+ 15,17,16,14,14,15,14,16,14,14,16,14,17,15,15,15,
+ 14,17,16,16,17,15,18,17,17,17,16,18,14,15,15,17,
+ 16,15,16,16,17,17,15,16,15,17,16,17,17,17,18,18,
+ 16,17,16,18,17,10,11,11,14,13,11,12,12,14,14,11,
+ 13,12,15,14,14,14,14,16,16,14,15,14,16,15,11,12,
+ 12,15,13,12,13,13,15,14,13,14,13,16,14,14,15,15,
+ 16,16,15,16,15,17,16,11,13,12,15,14,13,13,14,15,
+ 15,12,14,13,16,14,15,15,15,17,17,14,16,15,17,16,
+ 14,14,14,16,15,14,15,15,16,16,15,16,15,17,16,16,
+ 16,16,16,17,16,17,17,18,17,14,15,15,16,16,15,15,
+ 16,17,16,14,15,15,17,16,17,17,17,18,18,16,17,16,
+ 18,16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12,
+ 11,10,11,12,13,14,10,11,11,14,13, 8, 9, 9,11,12,
+ 9,10,11,12,13, 9,11,10,13,12,11,12,13,14,15,11,
+ 12,12,15,14, 8, 9, 9,12,11, 9,10,10,12,13, 9,10,
+ 10,13,12,11,12,12,14,15,11,12,12,14,13,11,11,12,
+ 13,14,11,12,13,13,15,12,13,13,14,14,13,14,14,14,
+ 16,14,15,14,16,16,10,11,11,14,13,11,12,12,14,14,
+ 11,12,12,14,13,13,14,14,15,16,13,14,13,16,14, 7,
+ 9, 9,11,11, 9,10,11,12,13, 9,10,10,12,12,11,12,
+ 13,14,15,11,12,12,14,14, 9,10,10,12,12,10,10,11,
+ 12,13,10,11,11,13,13,12,12,13,13,15,12,13,13,15,
+ 15, 9,10,10,12,12,10,11,11,13,13,10,11,10,13,12,
+ 12,13,13,14,15,12,13,12,15,13,11,12,12,14,14,12,
+ 12,13,14,15,13,14,13,15,15,14,13,15,13,16,15,15,
+ 15,16,16,11,12,12,14,14,12,13,13,14,15,12,13,12,
+ 15,14,14,15,15,16,17,13,14,13,16,13, 8, 9, 9,12,
+ 11, 9,10,10,12,13, 9,10,10,13,12,11,12,12,14,15,
+ 11,12,12,15,14, 9,10,10,12,13,10,11,12,13,14,10,
+ 11,11,14,13,12,13,13,15,15,12,13,13,15,15, 9,10,
+ 9,13,11,10,11,10,13,13,10,12,10,14,12,12,13,12,
+ 15,15,12,13,12,15,14,11,12,13,14,15,12,13,14,14,
+ 15,13,13,13,15,15,14,15,15,15,17,15,15,15,16,16,
+ 11,12,11,15,13,12,13,13,15,14,12,13,12,16,13,14,
+ 15,15,16,16,14,15,14,17,14,10,11,11,13,14,11,12,
+ 13,14,15,11,12,12,14,14,14,14,15,15,17,14,14,14,
+ 15,16,11,12,13,14,15,12,13,14,14,16,13,14,13,15,
+ 15,14,15,16,15,17,15,15,15,17,17,11,12,12,13,15,
+ 13,13,14,14,16,12,13,13,14,15,15,15,15,16,17,14,
+ 15,15,16,16,14,15,15,16,16,14,15,15,16,17,15,15,
+ 16,16,17,16,16,17,16,18,17,17,17,18,18,14,14,15,
+ 15,16,15,15,15,16,17,14,15,15,16,16,16,17,17,17,
+ 18,16,16,16,17,16,10,11,11,14,13,11,13,12,15,14,
+ 11,13,12,15,14,14,15,14,16,16,13,15,14,17,15,11,
+ 12,13,15,15,12,13,14,15,16,13,14,13,16,15,15,15,
+ 15,16,17,15,15,15,17,16,11,13,11,15,12,13,14,13,
+ 16,13,12,14,12,16,13,15,15,15,17,15,14,16,14,17,
+ 14,14,15,15,16,17,15,15,16,16,17,15,16,15,17,17,
+ 16,16,17,17,18,16,17,17,18,18,14,15,14,17,13,15,
+ 16,15,17,15,15,16,15,17,14,16,17,16,18,16,16,17,
+ 16,18,15, 9,11,11,13,13,10,12,12,14,14,11,12,12,
+ 14,14,13,14,14,15,16,13,14,14,16,16,10,11,12,14,
+ 14,11,12,13,14,15,11,13,13,15,15,13,14,14,15,16,
+ 14,15,15,16,16,11,12,12,14,14,12,13,13,15,15,12,
+ 13,12,15,14,14,15,15,16,16,14,15,14,17,16,12,13,
+ 13,15,16,13,13,14,15,16,13,14,14,16,16,14,15,16,
+ 16,17,15,16,16,17,17,13,14,14,16,15,14,15,15,17,
+ 16,14,15,14,17,15,16,16,17,17,17,16,16,16,18,16,
+ 10,11,12,14,14,11,12,13,14,15,11,13,12,15,15,13,
+ 14,15,16,16,14,15,15,17,16,11,11,13,14,15,12,12,
+ 14,14,16,12,13,14,15,15,14,14,15,16,17,15,15,15,
+ 17,17,12,13,12,15,15,13,14,14,16,15,13,14,13,16,
+ 15,15,16,15,17,17,15,16,15,17,16,13,12,15,14,16,
+ 14,13,15,14,17,14,13,15,15,17,15,14,17,15,18,16,
+ 15,17,17,18,14,15,15,17,16,15,16,16,17,17,15,16,
+ 15,17,16,16,17,17,18,18,16,17,16,18,17,10,11,11,
+ 14,14,11,12,12,14,15,11,13,12,15,14,13,14,14,16,
+ 16,14,15,14,16,16,11,12,12,14,14,12,12,13,15,15,
+ 12,13,13,15,15,14,14,15,16,16,14,15,15,17,16,11,
+ 12,12,15,15,13,13,13,15,15,12,13,13,15,15,15,15,
+ 15,17,17,14,15,15,17,16,13,14,13,16,15,14,14,14,
+ 16,16,14,15,14,17,16,15,15,16,16,17,16,17,16,18,
+ 17,14,15,15,16,16,15,15,15,17,17,14,15,15,17,16,
+ 16,17,17,18,18,16,17,16,18,16,12,13,13,15,15,13,
+ 14,14,16,16,13,14,14,16,16,14,15,16,16,18,15,16,
+ 16,17,17,13,13,14,14,16,14,14,15,15,17,14,14,15,
+ 15,17,15,15,17,15,18,16,16,17,17,18,13,14,14,16,
+ 16,14,15,15,16,17,14,15,15,17,16,16,17,16,17,18,
+ 16,17,16,18,17,15,14,16,13,18,16,15,17,14,18,16,
+ 15,17,14,18,17,16,18,15,19,17,17,18,16,19,15,16,
+ 16,17,17,16,17,17,18,18,16,17,16,18,17,18,18,18,
+ 19,18,17,18,17,19,17,11,12,12,15,15,13,13,14,15,
+ 16,13,14,13,16,15,15,15,15,16,17,15,16,15,17,16,
+ 12,13,13,15,15,13,13,14,15,16,14,15,14,16,15,15,
+ 15,16,16,17,16,16,16,18,17,12,13,13,15,15,14,14,
+ 15,16,16,13,14,13,16,15,16,16,16,17,17,15,16,15,
+ 18,16,15,15,15,17,15,14,15,15,16,16,16,17,16,17,
+ 16,16,16,17,16,17,17,18,17,19,18,15,15,16,17,17,
+ 16,16,16,17,17,15,16,15,17,16,17,18,18,18,18,16,
+ 17,16,18,16, 9,11,11,13,13,11,12,12,14,14,10,12,
+ 12,14,14,13,14,14,15,16,13,14,14,16,15,11,12,12,
+ 14,14,12,12,13,14,15,12,13,13,15,15,14,14,15,16,
+ 17,14,15,15,16,16,10,12,11,14,14,11,13,13,15,15,
+ 11,13,12,15,14,14,14,15,16,16,13,14,14,16,15,13,
+ 14,14,15,16,14,14,15,15,17,14,15,15,16,17,16,16,
+ 16,16,18,16,16,17,17,17,12,13,13,16,15,13,14,14,
+ 16,16,12,14,13,16,15,15,16,16,17,17,14,16,15,17,
+ 16,10,11,11,14,14,11,12,13,14,15,11,12,12,15,14,
+ 14,14,15,16,16,13,14,14,16,16,11,12,12,14,15,12,
+ 13,14,15,15,13,13,13,15,15,14,15,15,16,17,15,15,
+ 15,16,17,11,12,12,14,14,12,13,13,15,15,12,13,12,
+ 15,15,14,15,15,16,17,14,15,14,16,16,14,14,15,16,
+ 16,14,15,15,16,17,15,16,15,17,17,16,16,17,16,18,
+ 16,17,17,18,18,13,13,14,15,16,14,14,15,16,17,14,
+ 14,14,16,15,16,16,17,17,18,15,16,15,17,16,10,12,
+ 11,14,14,11,13,13,15,15,11,13,12,15,15,14,15,15,
+ 16,16,13,15,14,16,16,12,12,13,15,15,13,13,14,15,
+ 16,13,14,14,16,15,15,15,16,16,17,15,15,15,17,17,
+ 11,13,11,15,14,12,14,13,16,15,12,14,12,16,14,15,
+ 15,15,17,17,14,15,14,17,15,14,15,15,16,17,15,15,
+ 16,16,17,15,16,16,17,17,16,16,17,17,18,16,17,17,
+ 18,18,13,14,12,16,14,14,15,13,17,15,14,15,13,17,
+ 14,16,17,15,18,17,15,17,14,18,15,11,12,12,14,15,
+ 13,13,14,15,16,13,14,13,16,15,15,15,16,16,17,15,
+ 15,15,16,16,12,13,13,15,15,13,13,14,15,16,14,15,
+ 14,16,16,15,15,16,16,18,16,16,16,18,17,12,13,13,
+ 15,15,14,14,15,15,16,13,14,13,15,15,16,16,16,17,
+ 18,15,16,15,17,16,15,16,15,17,16,15,15,16,16,17,
+ 16,17,16,17,17,16,16,17,16,18,17,18,18,18,18,14,
+ 15,15,15,17,16,15,17,16,17,14,15,15,16,16,17,17,
+ 18,18,19,16,16,16,17,16,12,13,13,15,15,13,14,14,
+ 16,16,13,14,14,16,16,15,16,16,17,17,15,16,15,18,
+ 16,13,14,14,16,16,14,15,15,16,17,14,15,15,17,16,
+ 16,16,17,17,18,16,17,16,18,18,13,14,13,16,14,14,
+ 15,14,17,15,14,15,14,17,14,16,17,16,18,17,15,17,
+ 15,18,15,15,16,16,17,18,16,16,17,17,18,16,17,17,
+ 17,18,17,17,18,18,19,17,18,18,19,18,15,16,14,17,
+ 13,16,17,15,18,14,16,17,15,18,14,18,18,17,19,16,
+ 17,18,16,19,15,
+};
+
+static const static_codebook _44p7_p2_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p7_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p7_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p3_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p7_p3_0[] = {
+ 2, 5, 5, 4, 7, 7, 4, 7, 7, 5, 7, 8, 7, 8,10, 8,
+ 9, 9, 5, 7, 7, 8, 9, 9, 7,10, 8, 5, 7, 8, 8, 9,
+ 10, 8,10,10, 8, 9,10,10,10,12,10,12,12, 8,10,10,
+ 10,12,12,10,12,11, 5, 8, 7, 8,10,10, 8,10, 9, 8,
+ 10,10,10,11,12,10,12,12, 8,10, 9,10,12,12,10,12,
+ 10, 5, 8, 8, 7,10,10, 8,10,10, 7, 9,10, 9,10,12,
+ 10,12,12, 8,10,10,10,12,12,10,12,11, 7, 9,10, 9,
+ 11,12,10,12,11, 9, 9,12,11,10,14,12,12,13,10,12,
+ 11,12,13,13,11,14,12, 7,10, 9,10,11,11,10,12,11,
+ 9,11,11,11,11,13,12,14,13,10,12,12,12,14,14,11,
+ 14,12, 5, 8, 8, 8,10,10, 7,10,10, 8,10,10,10,11,
+ 12,10,12,12, 7,10, 9,10,12,12, 9,12,10, 7, 9,10,
+ 10,11,12,10,11,11,10,12,12,11,12,14,12,14,14, 9,
+ 11,11,12,13,14,11,13,11, 7,10, 9,10,11,12, 9,12,
+ 11,10,11,12,11,12,14,12,13,13, 9,12, 9,12,13,12,
+ 11,14,10,
+};
+
+static const static_codebook _44p7_p3_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p7_p3_0,
+ 1, -533200896, 1614282752, 2, 0,
+ (long *)_vq_quantlist__44p7_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p3_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p7_p3_1[] = {
+ 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 8, 7,
+ 8, 8, 7, 8, 7, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8,
+ 8, 8, 8, 8, 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9,
+ 8, 7, 8, 8, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 7, 8, 8, 8,
+ 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8,
+ 8, 9, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8,
+ 9, 8, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8,
+ 9, 8, 8, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8,
+ 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8, 8, 8, 8, 8, 9,
+ 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 8, 8, 8, 8, 9, 9,
+ 8, 9, 8,
+};
+
+static const static_codebook _44p7_p3_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p7_p3_1,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p7_p3_1,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p4_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p7_p4_0[] = {
+ 1, 5, 5, 5, 7, 8, 5, 8, 7, 5, 7, 8, 7, 8,10, 8,
+ 10,10, 5, 8, 7, 8,10,10, 7,10, 8, 6, 8, 9, 9,10,
+ 12, 9,11,11, 9,10,11,11,11,13,11,13,13, 9,11,11,
+ 11,12,13,11,13,11, 6, 9, 8, 9,11,11, 9,12,10, 9,
+ 11,11,11,11,13,11,13,13, 9,11,10,11,13,13,11,13,
+ 11, 6, 9, 9, 8,10,11, 9,12,11, 8,10,11,10,11,13,
+ 11,13,13, 9,11,11,11,13,12,11,13,11, 8,10,10, 9,
+ 11,12,10,12,12,10,10,12,11,11,14,12,13,14,10,12,
+ 12,12,13,13,11,14,11, 8,11,10,11,12,13,11,14,12,
+ 10,12,11,11,12,14,13,15,14,10,12,12,13,14,15,12,
+ 14,12, 5, 9, 9, 9,11,12, 8,11,10, 9,11,11,11,11,
+ 13,11,12,13, 8,11,10,11,13,13,10,13,11, 8,10,11,
+ 11,12,14,11,13,12,10,12,12,12,12,14,14,15,14,10,
+ 11,12,13,14,15,11,14,12, 8,10,10,10,12,12, 9,12,
+ 11,10,12,12,11,11,14,12,13,13,10,12,10,12,14,13,
+ 11,13,11,
+};
+
+static const static_codebook _44p7_p4_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p7_p4_0,
+ 1, -531365888, 1616117760, 2, 0,
+ (long *)_vq_quantlist__44p7_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p4_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p7_p4_1[] = {
+ 7, 8, 8,10,10, 8, 9, 9,10,11, 8, 9, 9,10,10, 9,
+ 10,10,11,11, 9,10,10,11,11, 8, 9, 9,10,10, 9, 9,
+ 10,11,11, 9,10,10,11,11,10,10,11,11,11,10,11,11,
+ 11,11, 8, 9, 9,10,10, 9,10,10,11,11, 9,10, 9,11,
+ 11,10,11,11,11,11,10,11,10,11,11,10,10,10,11,11,
+ 10,11,11,11,11,10,11,11,11,11,11,11,11,11,12,11,
+ 11,11,11,12,10,10,10,11,11,10,11,11,11,11,10,11,
+ 11,11,11,11,11,11,12,11,11,11,11,12,11, 8, 9,10,
+ 11,11, 9,10,11,11,11, 9,10,10,11,11,10,11,11,12,
+ 12,10,11,11,12,12,10,10,10,11,11,10,10,11,11,12,
+ 10,11,11,12,12,11,11,12,12,12,11,11,12,12,12,10,
+ 10,10,11,11,10,11,11,12,12,10,11,11,12,11,11,12,
+ 12,12,12,11,12,11,12,12,11,11,11,11,12,11,11,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,11,11,11,12,12,11,12,12,12,12,11,12,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12, 8,10, 9,11,11, 9,
+ 10,10,11,11, 9,10,10,11,11,10,11,11,12,12,10,11,
+ 11,12,12,10,10,10,11,11,10,11,11,12,12,10,11,11,
+ 12,12,11,11,12,12,12,11,12,12,12,12,10,10,10,11,
+ 11,10,11,11,12,12,10,11,10,12,11,11,12,11,12,12,
+ 11,12,11,12,12,11,11,11,12,12,11,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,
+ 11,12,11,11,12,12,12,12,11,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,10,11,11,11,12,11,11,12,12,
+ 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,
+ 11,11,12,12,12,11,12,12,12,12,12,12,12,12,12,12,
+ 12,13,12,13,12,12,12,13,13,11,12,11,12,12,11,12,
+ 12,12,12,11,12,12,12,12,12,12,12,13,13,12,12,12,
+ 13,13,12,12,12,12,12,12,12,12,12,13,12,12,13,13,
+ 13,12,13,13,13,13,12,13,13,13,13,12,12,12,12,12,
+ 12,12,13,13,13,12,12,12,13,12,12,13,13,13,13,12,
+ 13,13,13,13,10,11,11,12,11,11,11,11,12,12,11,12,
+ 11,12,12,11,12,12,12,12,11,12,12,12,12,11,11,11,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,13,
+ 13,12,12,12,13,13,11,12,11,12,12,12,12,12,12,12,
+ 11,12,11,12,12,12,12,12,13,13,12,12,12,13,12,12,
+ 12,12,12,12,12,12,12,13,13,12,12,12,13,13,12,13,
+ 13,13,13,12,13,13,13,13,12,12,12,12,12,12,12,12,
+ 13,13,12,13,12,13,12,12,13,13,13,13,13,13,13,13,
+ 13, 8,10,10,11,11, 9,10,10,11,11, 9,10,10,11,11,
+ 10,11,11,12,12,10,11,11,12,12, 9,10,10,11,11,10,
+ 10,11,11,12,10,11,11,12,12,11,11,12,12,12,11,11,
+ 12,12,12,10,10,10,11,11,10,11,11,12,12,10,11,10,
+ 12,11,11,12,11,12,12,11,12,11,12,12,11,11,11,12,
+ 12,11,11,12,12,12,11,12,12,12,12,11,12,12,12,12,
+ 12,12,12,12,12,11,11,11,12,11,11,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12, 9,10,
+ 10,11,11,10,11,11,11,12,10,11,11,12,12,11,11,11,
+ 12,12,11,11,11,12,12,10,10,11,11,12,11,11,12,12,
+ 12,11,11,11,12,12,11,11,12,12,12,11,12,12,12,12,
+ 10,11,11,12,12,11,11,11,12,12,11,12,11,12,12,11,
+ 12,12,12,12,11,12,12,12,12,11,11,12,12,12,11,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,13,12,12,12,
+ 12,13,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,13,12, 9,10,10,11,11,
+ 10,11,11,12,12,10,11,11,12,11,11,12,11,12,12,11,
+ 12,11,12,12,10,11,11,12,12,11,11,11,12,12,11,12,
+ 11,12,12,11,12,12,12,12,12,12,12,12,12,10,11,11,
+ 12,12,11,12,11,12,12,11,12,11,12,12,12,12,12,13,
+ 12,12,12,12,12,12,11,12,11,12,12,11,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,13,12,12,12,12,13,11,
+ 12,12,12,12,12,12,12,13,12,11,12,12,12,12,12,12,
+ 12,13,12,12,12,12,13,12,10,11,11,12,12,11,12,12,
+ 12,12,11,12,12,12,12,12,12,12,12,13,12,12,12,13,
+ 13,11,11,12,12,12,12,12,12,12,13,12,12,12,12,12,
+ 12,12,13,12,13,12,12,13,13,13,11,12,12,12,12,12,
+ 12,12,13,13,12,12,12,13,12,12,13,12,13,13,12,13,
+ 12,13,13,12,12,12,12,12,12,12,13,12,13,12,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,13,
+ 13,12,13,13,13,13,12,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,10,11,11,12,12,11,12,12,12,12,11,
+ 12,12,12,12,12,12,12,13,13,12,12,12,13,13,11,12,
+ 12,12,12,12,12,12,12,13,12,12,12,13,12,12,12,13,
+ 13,13,12,13,13,13,13,11,12,12,12,12,12,12,12,13,
+ 13,12,12,12,13,12,12,13,13,13,13,12,13,12,13,13,
+ 12,12,12,12,12,12,13,13,13,13,12,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,12,12,12,13,12,12,13,
+ 13,13,13,12,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13, 8,10,10,11,11, 9,10,10,11,11, 9,10,10,11,
+ 11,10,11,11,12,12,10,11,11,12,12,10,10,10,11,11,
+ 10,11,11,11,12,10,11,11,12,12,11,11,12,12,12,11,
+ 11,12,12,12, 9,10,10,11,11,10,11,11,12,12,10,11,
+ 10,12,11,11,12,11,12,12,11,12,11,12,12,11,11,11,
+ 12,12,11,11,12,12,12,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,11,11,11,12,11,11,12,12,12,12,
+ 11,12,11,12,12,12,12,12,12,12,12,12,12,12,12, 9,
+ 10,10,11,11,10,11,11,12,12,10,11,11,12,12,11,11,
+ 12,12,12,11,12,12,12,12,10,11,11,12,12,11,11,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,10,11,11,12,12,11,11,12,12,12,11,11,11,12,12,
+ 12,12,12,12,12,11,12,12,12,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,13,12,13,12,12,
+ 12,13,12,11,12,12,12,12,12,12,12,12,12,11,12,12,
+ 12,12,12,12,12,13,12,12,12,12,13,12, 9,10,10,11,
+ 11,10,11,11,12,12,10,11,11,12,12,11,11,11,12,12,
+ 11,12,11,12,12,10,11,11,12,12,11,11,12,12,12,11,
+ 11,11,12,12,11,12,12,12,12,11,12,12,12,12,10,11,
+ 10,12,11,11,11,11,12,12,11,12,11,12,12,11,12,12,
+ 12,12,11,12,11,12,12,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,13,12,12,12,12,13,
+ 11,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,
+ 12,12,13,12,12,12,12,13,12,10,11,11,12,12,11,12,
+ 12,12,12,11,12,12,12,12,12,12,12,13,13,12,12,12,
+ 13,13,11,12,12,12,12,12,12,12,12,13,12,12,12,13,
+ 13,12,12,13,13,13,12,13,13,13,13,11,12,12,12,12,
+ 12,12,12,12,13,12,12,12,12,12,12,13,13,13,13,12,
+ 13,12,13,13,12,12,12,12,13,12,13,13,13,13,12,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,
+ 12,12,12,13,13,13,13,12,13,12,13,13,13,13,13,13,
+ 13,13,13,13,13,13,11,11,11,12,12,11,12,12,12,12,
+ 11,12,12,12,12,12,12,12,13,13,12,12,12,13,12,11,
+ 12,12,12,12,12,12,12,13,13,12,12,12,13,13,12,12,
+ 13,13,13,12,13,13,13,13,11,12,11,12,12,12,12,12,
+ 13,12,12,12,12,13,12,12,13,12,13,13,12,13,12,13,
+ 12,12,12,12,12,13,12,12,13,13,13,12,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,
+ 13,13,13,13,12,13,12,13,12,13,13,13,13,13,13,13,
+ 13,13,13,10,11,11,12,12,10,11,11,12,12,10,11,11,
+ 12,12,11,12,12,12,12,11,12,12,12,12,11,11,11,12,
+ 12,11,11,12,12,12,11,12,12,12,12,12,12,12,13,13,
+ 12,12,12,13,13,11,11,11,12,12,11,12,12,12,12,11,
+ 12,11,13,12,12,12,12,13,13,12,12,12,13,13,11,12,
+ 12,12,12,12,12,12,12,13,12,12,12,13,13,12,12,13,
+ 13,13,12,13,12,13,13,11,12,12,12,12,12,12,12,13,
+ 12,12,12,12,13,12,12,13,13,13,13,12,13,13,13,13,
+ 10,11,11,12,12,11,12,12,12,12,11,12,12,12,12,12,
+ 12,12,13,13,12,12,12,13,13,11,11,12,12,12,11,12,
+ 12,12,13,12,12,12,13,13,12,12,13,13,13,12,12,13,
+ 13,13,11,12,12,12,12,12,12,12,13,13,12,12,12,13,
+ 13,12,13,13,13,13,12,13,12,13,13,12,12,12,12,13,
+ 12,12,13,12,13,12,12,13,13,13,12,12,13,13,13,12,
+ 13,13,13,13,12,12,12,12,13,12,12,13,13,13,12,12,
+ 12,13,13,13,13,13,13,13,12,13,13,13,13,10,11,11,
+ 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,13,
+ 13,12,12,12,13,13,11,12,12,12,12,11,12,12,12,13,
+ 12,12,12,13,13,12,12,13,13,13,12,13,13,13,13,11,
+ 12,12,12,12,12,12,12,13,13,12,12,12,13,12,12,13,
+ 12,13,13,12,13,12,13,13,12,12,12,12,12,12,12,12,
+ 13,13,12,13,12,13,13,12,13,13,13,13,13,13,13,13,
+ 13,12,12,12,13,12,12,13,13,13,13,12,13,12,13,13,
+ 13,13,13,13,13,13,13,13,13,13,11,11,11,12,12,11,
+ 12,12,12,12,11,12,12,12,12,12,12,12,13,13,12,12,
+ 12,13,13,11,12,12,12,12,12,12,12,12,13,12,12,12,
+ 13,13,12,12,13,13,13,12,12,13,13,13,11,12,12,12,
+ 12,12,12,12,13,13,12,12,12,13,13,12,13,13,13,13,
+ 12,13,12,13,13,12,12,12,12,12,12,12,13,12,13,12,
+ 13,13,13,13,12,13,13,12,13,13,13,13,13,13,12,12,
+ 12,12,12,12,13,13,13,13,12,13,12,13,13,13,13,13,
+ 13,13,13,13,13,13,13,10,11,11,12,12,11,12,12,12,
+ 13,11,12,12,13,12,12,12,12,13,13,12,12,12,13,13,
+ 11,12,12,12,12,12,12,12,13,13,12,13,12,13,13,12,
+ 12,13,13,13,12,13,13,13,13,11,12,12,12,13,12,12,
+ 12,13,13,12,12,12,13,12,12,13,13,13,13,12,13,12,
+ 13,13,12,12,12,12,12,12,12,13,13,13,12,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,12,12,12,13,12,
+ 12,13,13,13,13,12,13,12,13,13,13,13,13,13,13,13,
+ 13,13,13,13,10,11,11,12,12,10,11,11,12,12,10,11,
+ 11,12,12,11,12,12,12,12,11,12,12,12,12,11,11,11,
+ 12,12,11,11,12,12,13,11,12,12,12,12,12,12,12,13,
+ 13,12,12,12,13,13,10,11,11,12,12,11,12,12,12,12,
+ 11,12,11,12,12,12,12,12,13,13,12,12,12,13,12,11,
+ 12,12,12,12,12,12,12,12,13,12,12,12,13,13,12,12,
+ 13,13,13,12,13,13,13,13,11,12,12,12,12,12,12,12,
+ 13,13,12,12,12,13,12,12,13,13,13,13,12,13,12,13,
+ 13,10,11,11,12,12,11,12,12,12,12,11,12,12,12,12,
+ 12,12,12,13,13,12,12,12,13,13,11,12,12,12,12,12,
+ 12,12,12,13,12,12,12,13,13,12,12,13,13,13,12,12,
+ 13,13,13,11,12,12,12,12,12,12,12,13,13,11,12,12,
+ 13,12,12,13,13,13,13,12,13,12,13,13,12,12,12,12,
+ 13,12,12,13,13,13,12,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,12,12,12,13,12,12,12,13,13,13,12,
+ 12,12,13,13,13,13,13,13,13,12,13,13,13,13,10,11,
+ 11,12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,
+ 13,13,12,12,12,13,13,11,12,12,12,12,12,12,12,12,
+ 13,12,12,12,13,13,12,12,13,13,13,12,12,13,13,13,
+ 11,12,11,12,12,12,12,12,13,13,11,12,12,13,12,12,
+ 13,12,13,13,12,13,12,13,13,12,12,12,12,12,12,12,
+ 13,13,13,12,13,12,13,13,12,13,13,13,13,13,13,13,
+ 13,13,12,12,12,13,12,12,13,12,13,13,12,13,12,13,
+ 13,13,13,13,13,13,12,13,12,13,13,10,11,11,12,12,
+ 11,12,12,12,12,11,12,12,13,12,12,12,12,13,13,12,
+ 12,12,13,13,11,12,12,12,12,12,12,12,12,13,12,12,
+ 12,13,13,12,12,13,13,13,12,13,13,13,13,11,12,12,
+ 12,12,12,12,12,13,13,12,12,12,13,12,12,13,13,13,
+ 13,12,13,12,13,13,12,12,12,12,13,12,12,13,13,13,
+ 12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,
+ 12,12,12,12,12,13,13,13,13,12,13,12,13,13,13,13,
+ 13,13,13,13,13,13,13,13,11,11,11,12,12,11,12,12,
+ 12,12,11,12,12,12,12,12,12,12,13,13,12,12,12,13,
+ 13,11,12,12,12,12,12,12,12,13,13,12,12,12,13,13,
+ 12,12,13,13,13,12,13,13,13,13,11,12,12,12,12,12,
+ 12,12,13,13,12,12,12,13,12,12,13,12,13,13,12,13,
+ 12,13,13,12,12,12,12,12,12,13,13,13,13,12,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,
+ 12,12,13,13,13,13,12,13,12,13,12,13,13,13,13,13,
+ 13,13,13,13,12,
+};
+
+static const static_codebook _44p7_p4_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p7_p4_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p7_p4_1,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p5_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p7_p5_0[] = {
+ 2, 6, 6, 9, 9, 5, 7, 8,10,11, 5, 8, 7,11,10, 8,
+ 10,11,12,13, 8,11,10,13,12, 6, 7, 8,10,11, 7, 8,
+ 10,10,12, 8, 9, 9,12,11,10,10,12,11,14,10,11,12,
+ 14,13, 6, 8, 7,11,10, 8, 9, 9,11,12, 7,10, 8,12,
+ 10,10,12,12,13,14,10,12,10,14,11, 9,10,11,11,12,
+ 10,10,11,11,13,11,12,12,13,13,12,11,13,11,15,13,
+ 14,13,14,14, 9,11,10,12,11,11,12,12,13,13,10,11,
+ 10,13,11,13,13,14,14,14,12,13,11,14,11, 7, 8, 9,
+ 11,12, 9, 9,11,12,13, 9,10,10,13,12,11,12,13,13,
+ 15,11,12,12,14,14, 9,10,10,12,13,10,10,12,12,14,
+ 11,11,11,13,13,12,12,13,13,15,12,13,13,15,14, 9,
+ 10,10,12,13,10,11,11,13,14,10,12,11,14,13,12,13,
+ 13,14,15,12,13,13,15,14,12,12,13,13,14,12,13,13,
+ 13,15,13,14,14,14,15,14,14,15,14,16,14,15,15,16,
+ 16,12,13,13,14,14,13,13,14,15,14,12,13,13,15,14,
+ 14,15,15,15,16,14,15,14,16,14, 7, 9, 8,12,11, 9,
+ 10,10,12,13, 9,11, 9,13,12,11,12,12,14,14,11,13,
+ 12,15,13, 9,10,10,13,12,10,11,12,13,14,10,12,11,
+ 14,13,12,13,13,14,15,13,13,13,15,14, 9,10,10,13,
+ 12,11,11,11,13,13,10,12,10,14,12,13,13,13,14,15,
+ 12,13,12,15,13,12,13,13,14,14,12,13,13,14,15,13,
+ 14,13,15,15,14,14,15,14,16,14,15,15,16,15,12,13,
+ 12,14,13,13,13,13,15,14,12,13,13,15,13,14,15,15,
+ 16,15,14,15,14,16,14,11,12,12,13,14,12,13,14,14,
+ 15,12,13,13,14,15,14,14,15,15,16,14,15,15,16,16,
+ 12,13,13,14,15,13,13,14,14,16,13,14,14,15,15,15,
+ 15,16,15,17,15,15,15,16,16,12,13,13,14,15,13,14,
+ 14,15,16,13,14,14,15,15,15,15,16,16,17,15,15,15,
+ 17,16,14,15,15,16,16,15,15,16,15,16,15,16,16,16,
+ 17,16,16,17,16,18,16,16,17,18,17,14,15,15,16,16,
+ 15,16,16,16,17,15,16,15,17,16,16,17,17,17,18,16,
+ 16,16,17,16,11,12,12,14,13,12,13,13,15,14,12,14,
+ 13,15,14,14,15,15,16,16,14,15,14,16,15,12,13,13,
+ 15,14,13,14,14,15,15,13,14,14,16,15,15,15,15,16,
+ 16,15,16,15,17,16,12,13,13,15,14,13,14,14,15,15,
+ 13,14,13,16,14,15,15,15,16,16,15,15,15,17,15,14,
+ 15,15,16,16,15,15,15,16,16,15,16,16,17,17,16,16,
+ 17,17,17,16,17,17,18,17,14,15,15,16,15,15,15,16,
+ 16,16,15,15,15,17,15,17,17,17,18,17,16,17,16,18,
+ 16, 6, 9, 9,12,12, 8,10,10,12,13, 9,11,10,13,12,
+ 10,12,12,14,14,11,13,12,14,14, 8,10,10,12,12, 9,
+ 10,11,12,14,10,11,11,13,13,12,12,13,13,15,12,13,
+ 13,15,14, 9,10,10,13,13,10,11,11,13,13,10,12,10,
+ 14,13,12,13,13,14,15,12,13,13,15,14,11,12,12,13,
+ 14,12,12,13,13,15,12,13,13,14,14,13,13,14,13,16,
+ 14,15,15,16,15,11,12,12,14,14,13,13,13,15,14,12,
+ 13,13,15,14,14,15,15,16,15,14,14,14,16,14, 7, 9,
+ 10,12,12, 9,10,11,13,13, 9,11,10,13,13,11,12,13,
+ 14,15,12,13,13,15,14, 9,10,11,12,13,10,10,12,13,
+ 14,11,11,12,14,14,12,12,14,14,15,13,13,13,15,15,
+ 9,11,11,13,13,11,12,12,14,14,10,12,10,14,13,13,
+ 14,13,15,15,12,14,13,15,14,12,12,13,13,15,12,12,
+ 14,13,15,13,14,14,15,15,14,14,15,14,17,14,15,15,
+ 16,16,12,13,13,15,14,13,14,14,15,15,12,14,13,15,
+ 14,14,15,15,16,16,14,15,14,16,14, 7,10,10,12,12,
+ 10,11,11,12,13,10,12,10,14,12,12,13,13,14,15,12,
+ 13,13,15,14, 9,11,10,13,12,10,10,12,12,14,11,13,
+ 12,14,13,13,13,14,13,15,13,14,14,15,14,10,11,11,
+ 13,13,12,12,12,13,14,10,12,10,14,12,13,14,14,15,
+ 15,13,14,13,15,13,12,13,13,14,14,12,12,13,14,15,
+ 13,14,14,15,15,13,13,14,13,15,14,15,15,16,16,12,
+ 13,13,14,14,13,14,14,15,15,12,13,13,15,13,15,15,
+ 15,16,16,13,14,13,16,13,11,12,13,14,14,12,13,14,
+ 14,15,12,13,13,15,15,14,14,15,15,17,14,15,15,16,
+ 16,12,13,14,14,15,13,13,14,14,16,13,14,14,15,16,
+ 14,14,16,15,17,15,15,16,16,16,12,13,13,15,15,13,
+ 14,14,15,16,13,14,14,15,16,15,15,16,17,17,15,16,
+ 15,17,16,14,15,15,15,16,15,15,16,15,17,15,15,16,
+ 16,17,16,16,16,16,18,16,16,17,17,17,14,15,15,16,
+ 16,15,16,16,16,17,15,16,15,17,16,16,17,17,17,17,
+ 16,17,16,18,17,11,12,12,14,14,13,13,14,14,15,13,
+ 14,13,15,14,14,15,15,15,16,14,15,15,17,15,12,13,
+ 13,15,14,13,13,14,15,15,14,15,14,16,15,15,15,15,
+ 15,16,15,16,15,17,16,12,13,13,15,15,14,14,14,15,
+ 16,13,14,13,16,15,15,15,16,16,17,15,16,15,17,15,
+ 14,15,15,16,16,14,15,15,16,16,15,16,16,17,16,15,
+ 15,16,15,17,16,17,17,18,17,14,15,15,16,16,15,16,
+ 16,16,17,14,15,15,17,16,17,17,17,17,18,15,16,16,
+ 18,15, 6, 9, 9,12,12, 9,10,11,12,13, 8,10,10,13,
+ 12,11,12,13,14,14,10,12,12,14,13, 9,10,10,12,13,
+ 10,10,12,13,14,10,11,11,13,13,12,13,13,14,15,12,
+ 13,13,15,14, 8,10,10,12,12,10,11,11,13,13, 9,11,
+ 10,13,13,12,13,13,14,15,12,13,12,15,13,11,12,12,
+ 14,14,12,13,13,13,15,13,13,13,14,15,14,14,15,14,
+ 16,14,15,15,15,15,11,12,12,14,13,12,13,13,15,14,
+ 12,13,12,15,13,14,14,15,16,16,13,14,13,16,13, 7,
+ 10,10,12,12,10,10,12,12,14,10,11,11,13,12,12,13,
+ 13,13,15,12,13,13,15,14,10,11,11,13,13,10,10,12,
+ 12,14,12,12,12,14,13,13,13,14,13,15,13,14,14,15,
+ 14, 9,10,11,13,13,11,12,12,13,14,10,12,10,14,12,
+ 13,13,14,14,15,13,13,12,15,13,12,13,13,14,14,12,
+ 13,13,14,15,13,14,14,15,15,13,13,15,13,16,15,15,
+ 15,16,16,12,13,13,14,14,13,14,14,15,15,12,13,12,
+ 15,14,15,15,15,16,16,13,14,13,15,13, 7,10, 9,12,
+ 12, 9,10,11,13,13, 9,11,10,13,13,11,13,13,14,15,
+ 11,13,12,15,14, 9,11,11,13,13,10,10,12,13,14,11,
+ 12,12,14,14,12,13,14,14,15,13,13,13,15,15, 9,11,
+ 10,13,12,11,12,11,14,14,10,12,10,14,13,13,14,13,
+ 15,15,12,14,12,15,14,12,13,13,14,15,13,13,14,14,
+ 15,13,14,14,15,15,14,14,15,14,17,14,15,15,16,16,
+ 12,13,12,15,13,13,14,14,15,15,12,14,13,15,13,14,
+ 15,15,16,16,14,15,14,16,14,11,12,12,14,14,13,13,
+ 14,14,15,13,14,13,15,15,14,15,15,16,17,14,15,15,
+ 16,15,12,13,13,15,15,13,13,14,15,16,14,14,14,16,
+ 15,15,15,16,15,17,15,16,15,17,16,12,13,13,14,15,
+ 14,14,15,15,16,13,14,13,15,15,15,15,16,16,17,15,
+ 15,15,16,15,14,15,15,16,16,14,15,15,16,17,15,16,
+ 16,17,17,16,15,16,15,17,16,17,17,17,17,14,15,15,
+ 15,16,15,15,16,16,17,14,15,15,16,16,16,16,17,17,
+ 18,15,16,15,17,15,11,13,12,14,14,12,13,13,15,15,
+ 12,14,13,15,14,14,15,15,16,16,14,15,14,16,15,12,
+ 13,13,15,15,13,14,14,15,16,13,14,14,16,16,15,15,
+ 16,16,17,15,16,15,17,16,12,13,13,15,14,13,14,14,
+ 16,15,13,14,13,16,14,15,16,15,17,16,15,15,14,18,
+ 15,14,15,15,16,16,15,15,16,16,17,15,16,15,17,16,
+ 16,16,17,17,18,16,17,17,18,17,14,15,15,16,15,15,
+ 16,15,17,16,15,15,15,17,15,16,17,17,18,17,16,17,
+ 16,18,15,10,12,12,14,14,12,13,13,14,14,12,13,13,
+ 14,14,13,14,14,15,15,13,14,14,16,15,11,12,13,14,
+ 14,12,13,13,15,15,12,13,13,15,15,13,14,15,15,16,
+ 14,15,15,16,16,12,13,13,14,14,13,13,14,15,15,13,
+ 14,13,15,15,14,15,15,16,16,14,15,14,16,15,13,14,
+ 14,15,15,13,14,14,15,16,14,14,15,16,16,14,15,15,
+ 15,17,15,16,16,17,17,13,14,14,15,15,14,15,15,16,
+ 16,14,15,15,16,16,15,16,16,16,17,15,16,15,17,16,
+ 11,12,12,14,14,12,13,13,14,15,12,13,13,15,14,13,
+ 14,14,15,16,13,14,14,16,15,12,13,13,14,15,13,13,
+ 14,15,15,13,14,14,15,15,14,14,15,15,17,14,15,15,
+ 16,16,12,13,13,15,15,13,14,14,15,15,13,14,13,15,
+ 15,14,15,15,16,17,14,15,15,16,16,13,13,14,15,16,
+ 14,14,15,15,16,14,15,15,16,16,15,15,16,15,18,15,
+ 16,16,17,17,14,15,15,16,16,15,15,15,16,16,14,15,
+ 15,17,16,16,16,16,17,17,15,16,16,17,16,10,12,12,
+ 14,14,12,13,13,14,15,12,13,13,15,14,14,14,15,15,
+ 16,14,15,14,16,15,12,13,13,15,14,13,13,14,15,15,
+ 13,14,14,15,15,14,14,15,15,16,14,15,15,16,16,12,
+ 13,13,15,15,13,14,14,15,16,13,14,13,15,14,15,15,
+ 15,16,16,14,15,15,16,15,13,14,14,16,15,14,14,14,
+ 15,16,14,15,15,16,16,15,15,16,15,17,16,17,16,17,
+ 17,14,14,15,15,16,15,15,16,16,16,14,15,14,16,15,
+ 16,16,16,17,17,15,16,15,17,15,11,13,13,14,15,13,
+ 13,14,15,15,13,14,13,15,15,14,15,15,15,16,14,15,
+ 15,17,15,13,13,14,15,15,13,14,15,15,16,14,14,14,
+ 16,16,15,14,16,15,17,15,16,16,17,16,13,14,14,15,
+ 15,14,14,14,16,16,13,15,14,16,15,15,15,16,17,17,
+ 15,16,15,17,16,14,15,15,15,16,15,15,16,15,17,15,
+ 16,16,16,17,16,16,17,15,18,16,17,17,17,17,14,15,
+ 15,16,16,15,16,16,17,17,15,16,15,17,16,16,17,17,
+ 18,18,16,17,15,18,16,10,12,12,14,14,13,13,14,14,
+ 15,13,14,13,15,14,14,15,15,15,16,15,15,15,16,15,
+ 12,13,13,15,14,12,12,14,14,15,14,15,14,16,15,15,
+ 14,15,14,17,15,16,16,17,16,12,13,13,14,15,14,14,
+ 15,15,16,13,14,12,16,14,15,16,16,16,17,15,16,14,
+ 17,15,14,15,14,16,15,14,14,15,15,15,15,16,15,17,
+ 16,15,14,16,14,16,16,17,17,18,17,14,14,15,15,16,
+ 15,16,16,16,17,14,15,14,16,15,16,16,17,17,17,15,
+ 16,14,17,14,10,12,12,14,13,12,13,13,14,14,11,13,
+ 12,14,14,13,14,14,15,16,13,14,14,16,15,12,13,13,
+ 14,14,13,13,14,15,15,13,14,13,15,15,14,14,15,15,
+ 16,14,15,15,16,16,11,13,12,14,14,12,13,13,15,15,
+ 12,13,13,15,15,14,15,15,16,16,13,14,14,16,15,13,
+ 14,14,15,15,14,15,15,15,16,14,15,15,16,16,15,16,
+ 16,16,17,16,16,16,17,17,13,14,14,15,15,14,15,15,
+ 16,16,13,14,14,16,15,15,16,16,17,17,15,15,15,17,
+ 15,11,12,12,14,14,12,13,13,14,15,12,13,13,15,14,
+ 14,14,15,15,16,14,14,14,16,15,12,13,13,15,14,13,
+ 13,14,15,15,13,14,14,16,15,14,15,15,15,16,15,15,
+ 15,16,16,12,13,13,14,15,13,13,14,15,15,13,14,13,
+ 15,15,15,15,15,16,16,14,15,14,16,15,14,14,15,16,
+ 16,14,15,15,15,16,15,16,15,16,16,15,15,16,15,17,
+ 16,16,16,17,17,13,14,14,15,16,14,15,15,16,16,14,
+ 14,14,16,16,16,16,16,17,17,15,15,15,17,15,11,12,
+ 12,14,14,12,13,13,14,15,12,13,13,15,14,14,14,14,
+ 15,16,13,14,14,16,15,12,13,13,15,15,13,13,14,15,
+ 16,13,14,14,15,15,14,15,15,16,17,14,15,15,17,16,
+ 12,13,13,15,14,13,14,14,15,15,13,14,13,15,15,14,
+ 15,15,16,16,14,15,14,17,15,14,15,15,16,16,14,15,
+ 15,16,17,15,15,15,17,17,15,16,16,16,17,16,17,16,
+ 17,17,13,15,14,16,15,14,15,15,16,16,14,15,14,16,
+ 15,16,16,16,17,17,15,16,15,17,15,10,12,12,14,14,
+ 13,13,14,14,15,13,14,13,15,14,14,15,15,15,17,14,
+ 15,15,16,15,12,13,13,15,14,12,12,14,14,15,14,15,
+ 14,16,15,15,14,16,15,17,15,16,16,17,16,12,13,13,
+ 14,15,14,14,15,15,16,12,14,12,15,14,15,16,16,16,
+ 17,15,16,14,17,14,14,15,14,16,16,14,14,15,15,16,
+ 15,16,16,17,16,15,14,16,14,17,16,17,17,18,17,14,
+ 14,15,15,16,15,15,16,16,17,14,15,14,16,15,16,17,
+ 17,17,18,15,16,14,17,14,11,13,13,15,14,13,13,14,
+ 15,15,12,14,13,15,15,14,15,15,15,17,14,15,14,16,
+ 15,13,14,14,15,15,13,14,15,15,16,14,15,14,16,16,
+ 15,15,16,16,17,15,16,16,17,17,13,14,13,15,15,14,
+ 14,14,16,16,13,15,14,16,15,15,16,16,17,17,15,16,
+ 14,17,15,15,15,15,16,17,15,15,16,16,17,15,16,16,
+ 17,17,16,15,17,16,17,17,17,17,18,18,14,15,15,17,
+ 15,15,16,16,17,16,15,16,15,17,15,16,17,17,17,17,
+ 16,17,15,18,15,
+};
+
+static const static_codebook _44p7_p5_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p7_p5_0,
+ 1, -528744448, 1616642048, 3, 0,
+ (long *)_vq_quantlist__44p7_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p5_1[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44p7_p5_1[] = {
+ 2, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _44p7_p5_1 = {
+ 1, 7,
+ (char *)_vq_lengthlist__44p7_p5_1,
+ 1, -533200896, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p7_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p7_p6_0[] = {
+ 2, 5, 6, 5, 7, 8, 5, 8, 7, 5, 7, 7, 7, 7, 9, 8,
+ 9, 9, 5, 7, 7, 8, 9, 9, 7, 9, 7, 6, 8, 8, 8, 9,
+ 10, 8, 9, 9, 8, 9,10, 9, 9,11,10,10,11, 8,10, 9,
+ 10,10,11, 9,10,10, 6, 8, 8, 8, 9, 9, 8,10, 9, 8,
+ 9,10, 9,10,10,10,11,10, 8,10, 9,10,11,10, 9,11,
+ 9, 6, 8, 8, 7, 9, 9, 8, 9, 9, 7, 9, 9, 9, 9,10,
+ 9,10,10, 8, 9, 9, 9,10,10, 9,10, 9, 7, 9, 9, 9,
+ 10,10, 9,10,10, 9, 9,10,10, 9,11,10,11,11, 9,10,
+ 10,10,11,11,10,11,10, 6, 9, 8, 9,10,10, 9,10, 9,
+ 8,10,10, 9, 9,10,10,11,11, 9,10,10,10,11,11, 9,
+ 11, 9, 6, 8, 8, 8, 9, 9, 7, 9, 9, 8, 9, 9, 9, 9,
+ 10, 9,10,10, 7, 9, 9, 9,10,10, 9,10, 9, 6, 8, 9,
+ 9, 9,10, 9,10,10, 9,10,10, 9, 9,11,10,11,11, 8,
+ 10,10,10,11,11, 9,10, 9, 7, 9, 9, 9,10,10, 9,10,
+ 10, 9,10,10,10,10,11,10,11,11, 9,10, 9,10,11,11,
+ 10,11, 9,
+};
+
+static const static_codebook _44p7_p6_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p7_p6_0,
+ 1, -527106048, 1620377600, 2, 0,
+ (long *)_vq_quantlist__44p7_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p6_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p7_p6_1[] = {
+ 4, 7, 7, 6, 7, 8, 6, 8, 7, 7, 7, 8, 7, 7, 8, 8,
+ 8, 8, 7, 7, 7, 8, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8,
+ 8, 9, 9, 8, 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9,
+ 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8, 8,
+ 8, 9, 8, 9, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8,
+ 8, 9, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8,
+ 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8,
+ 8, 8, 8, 9, 9, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 9, 9, 9,
+ 8, 9, 8,
+};
+
+static const static_codebook _44p7_p6_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p7_p6_1,
+ 1, -530841600, 1616642048, 2, 0,
+ (long *)_vq_quantlist__44p7_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p7_p7_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p7_p7_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p7_p7_0,
+ 1, -513979392, 1633504256, 2, 0,
+ (long *)_vq_quantlist__44p7_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p7_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p7_p7_1[] = {
+ 1, 5, 5, 4,10,10, 5,10,10, 5,10,10,10,10,10,10,
+ 10,10, 5,10,10,10,10,10, 9,10,10, 6,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10, 7,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10, 6,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10, 6,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,11,11,
+};
+
+static const static_codebook _44p7_p7_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p7_p7_1,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44p7_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p7_2[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p7_p7_2[] = {
+ 1, 3, 2, 4, 5, 7, 7, 8, 8, 9, 9,10,10,11,11,12,
+ 12,13,13,14,14,15,15,15,15,
+};
+
+static const static_codebook _44p7_p7_2 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p7_p7_2,
+ 1, -518864896, 1620639744, 5, 0,
+ (long *)_vq_quantlist__44p7_p7_2,
+ 0
+};
+
+static const long _vq_quantlist__44p7_p7_3[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p7_p7_3[] = {
+ 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p7_p7_3 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p7_p7_3,
+ 1, -529006592, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44p7_p7_3,
+ 0
+};
+
+static const char _huff_lengthlist__44p7_short[] = {
+ 3, 9,14,16,17,19,22,22, 5, 4, 6, 9,11,13,17,20,
+ 9, 5, 5, 6, 9,11,15,19,11, 7, 5, 5, 7, 9,13,17,
+ 14, 9, 7, 6, 6, 7,11,14,16,11, 9, 7, 6, 4, 4, 8,
+ 19,15,13,11, 9, 4, 3, 4,21,16,16,15,12, 6, 4, 4,
+};
+
+static const static_codebook _huff_book__44p7_short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p7_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p8_l0_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44p8_l0_0[] = {
+ 2, 4, 4, 7, 7, 8, 8,10,10,11,11,12,12, 4, 5, 5,
+ 7, 7, 9, 9,10, 9,12,10,12,12, 4, 5, 5, 7, 7, 9,
+ 9, 9,10,10,12,12,12, 7, 7, 7, 7, 8, 9, 8,11, 5,
+ 12, 6,12,10, 7, 7, 7, 8, 7, 8, 9, 5,11, 6,12,10,
+ 12, 8, 9, 9, 9, 9, 9, 9,11, 7,11, 7,11, 9, 8, 9,
+ 9, 9, 9, 9, 9, 7,10, 7,11, 9,11,10,10,10,10,10,
+ 10,10,11,10,11, 8,12, 9,10,10,10,10,10,10,10,10,
+ 11, 8,11, 9,12,10,11,11,11,11,11,11,11,11,12,10,
+ 12,11,10,11,11,11,11,11,11,11,11,10,12,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,11,12,12,12,
+ 12,12,12,12,12,12,11,12,12,
+};
+
+static const static_codebook _44p8_l0_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44p8_l0_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44p8_l0_0,
+ 0
+};
+
+static const long _vq_quantlist__44p8_l0_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p8_l0_1[] = {
+ 4, 4, 4, 5, 5, 4, 4, 5, 5, 5, 4, 5, 4, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p8_l0_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p8_l0_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p8_l0_1,
+ 0
+};
+
+static const long _vq_quantlist__44p8_l1_0[] = {
+ 54,
+ 29,
+ 79,
+ 0,
+ 108,
+};
+
+static const char _vq_lengthlist__44p8_l1_0[] = {
+ 1, 2, 3, 6, 7, 7, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44p8_l1_0 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p8_l1_0,
+ 1, -514516992, 1620639744, 7, 0,
+ (long *)_vq_quantlist__44p8_l1_0,
+ 0
+};
+
+static const char _huff_lengthlist__44p8_lfe[] = {
+ 2, 3, 1, 3,
+};
+
+static const static_codebook _huff_book__44p8_lfe = {
+ 2, 4,
+ (char *)_huff_lengthlist__44p8_lfe,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44p8_long[] = {
+ 2, 7,14,16,17,18,20,21, 7, 4, 6, 8,11,12,14,16,
+ 13, 5, 4, 4, 8, 9,11,13,15, 8, 4, 3, 5, 7, 9,10,
+ 17,11, 8, 4, 4, 6, 9, 9,17,11, 9, 7, 6, 5, 7, 8,
+ 19,13,11, 9, 9, 7, 8, 8,21,15,13,11,10, 8, 8, 7,
+};
+
+static const static_codebook _huff_book__44p8_long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p8_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p8_p1_0[] = {
+ 2, 5, 5, 4, 7, 7, 4, 7, 7, 5, 7, 7, 7, 8, 9, 7,
+ 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 6, 7, 8, 8, 9,
+ 10, 8, 9,10, 8, 9,10,10,10,12,10,11,12, 8,10,10,
+ 10,11,12,10,11,11, 6, 8, 7, 8,10, 9, 8,10, 9, 8,
+ 10,10,10,11,11,10,12,11, 8,10, 9,10,12,11,10,12,
+ 10, 5, 8, 8, 8,10,10, 8,10,10, 7, 9,10, 9,10,11,
+ 9,11,11, 8,10,10,10,12,12,10,12,11, 7, 9, 9, 9,
+ 10,11, 9,11,11, 9, 9,11,10,11,12,10,11,12, 9,11,
+ 11,11,12,12,11,12,12, 7, 9, 9,10,11,11,10,12,11,
+ 9,11,10,11,11,12,11,13,12,10,11,11,12,13,13,11,
+ 13,11, 5, 8, 8, 8,10,10, 8,10,10, 8,10,10,10,11,
+ 12,10,12,11, 7,10, 9, 9,11,11, 9,11,10, 7, 9, 9,
+ 10,11,12,10,11,11,10,11,11,11,11,13,12,13,13, 9,
+ 10,11,12,12,13,11,12,11, 7, 9, 9, 9,11,11, 9,11,
+ 10, 9,11,11,11,12,12,11,12,12, 9,11, 9,10,12,11,
+ 10,12,11,
+};
+
+static const static_codebook _44p8_p1_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p8_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p8_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p8_p2_0[] = {
+ 4, 6, 6, 9, 9, 6, 8, 8,10,10, 6, 8, 8,10,10, 8,
+ 9,10,12,12, 8,10, 9,12,12, 6, 8, 8,10,10, 8, 8,
+ 9,10,11, 8, 9, 9,11,11, 9,10,11,12,13,10,11,11,
+ 13,13, 6, 8, 8,10,10, 8, 9, 9,11,11, 8, 9, 8,11,
+ 10,10,11,11,13,13, 9,11,10,13,12, 9,10,10,12,12,
+ 10,10,11,12,13,10,11,11,13,13,12,12,13,12,15,12,
+ 13,13,15,14, 9,10,10,12,12,10,11,11,13,13,10,11,
+ 10,13,12,12,13,13,14,15,12,13,12,15,12, 7, 8, 8,
+ 10,11, 8, 9,10,11,12, 8, 9, 9,11,11,10,11,11,13,
+ 14,10,11,11,13,13, 8, 9, 9,11,12, 9,10,11,11,13,
+ 9,10,10,12,12,11,11,12,13,15,11,12,12,14,14, 8,
+ 9, 9,11,11, 9,10,11,12,13, 9,10,10,12,12,11,12,
+ 12,14,15,11,12,12,14,14,10,11,12,13,13,11,12,12,
+ 13,14,12,12,12,14,14,13,13,14,14,16,14,14,14,16,
+ 15,10,11,11,13,13,12,12,12,14,14,11,12,12,14,13,
+ 14,14,14,15,16,13,14,13,16,14, 7, 8, 8,11,10, 8,
+ 9, 9,11,11, 8,10, 9,12,11,10,11,11,13,13,10,11,
+ 11,14,13, 8, 9, 9,12,11, 9,10,10,12,12, 9,11,10,
+ 13,12,11,12,12,13,14,11,12,12,15,14, 8, 9, 9,12,
+ 11, 9,10,10,12,12, 9,11,10,13,11,11,12,12,14,14,
+ 11,12,12,14,13,10,11,11,13,13,11,12,12,13,14,12,
+ 13,12,14,14,13,13,14,14,16,13,14,14,16,15,10,11,
+ 11,13,13,12,12,12,14,14,11,12,12,14,13,13,14,14,
+ 15,15,13,14,13,16,14, 9,10,11,12,13,11,11,12,12,
+ 14,11,11,12,13,14,13,13,14,14,16,13,13,14,15,15,
+ 11,11,12,12,14,12,12,13,13,15,12,12,13,13,15,14,
+ 14,15,15,16,14,14,14,15,16,11,12,12,13,14,12,12,
+ 13,14,15,12,13,12,14,14,14,14,15,15,16,14,14,14,
+ 16,16,13,13,14,15,16,14,14,15,15,16,14,15,15,16,
+ 16,15,15,16,16,18,16,16,16,17,17,13,14,14,15,15,
+ 14,14,15,16,16,14,15,14,16,16,16,16,16,17,18,15,
+ 16,16,17,16, 9,11,10,13,12,11,12,11,14,13,11,12,
+ 11,14,12,13,14,13,15,14,13,14,13,16,14,11,12,12,
+ 14,13,12,12,13,14,14,12,13,12,15,14,14,14,14,16,
+ 16,14,15,14,17,15,11,12,11,14,12,12,13,12,15,13,
+ 12,13,12,15,13,14,14,14,16,15,14,15,14,16,15,13,
+ 14,14,15,15,14,14,15,16,16,14,15,14,16,16,15,15,
+ 16,16,17,16,16,16,17,17,13,14,14,16,15,14,15,15,
+ 16,16,14,15,14,17,15,16,16,16,17,17,15,16,15,18,
+ 16, 7, 8, 8,10,11, 8, 9, 9,11,12, 8, 9, 9,12,11,
+ 10,11,11,13,14,10,11,11,14,13, 8, 9, 9,11,11, 9,
+ 10,10,12,12, 9,10,10,12,12,11,12,12,13,14,11,12,
+ 12,14,14, 8, 9, 9,12,11, 9,10,11,12,13, 9,11,10,
+ 13,12,11,12,12,14,14,11,12,12,14,13,10,11,11,13,
+ 13,11,12,12,13,14,11,12,12,14,14,13,13,14,14,16,
+ 13,14,14,16,15,10,12,11,13,13,12,12,12,14,14,11,
+ 12,12,14,13,14,14,14,15,16,13,14,14,16,14, 8, 9,
+ 9,11,11, 9,10,10,12,12, 9,10,10,12,12,11,11,12,
+ 13,14,11,12,12,14,14, 9, 9,10,11,12,10,10,11,12,
+ 13,10,10,11,12,13,12,12,13,14,15,12,12,13,14,15,
+ 9,10,10,12,12,10,11,11,13,13,10,11,11,13,13,12,
+ 13,13,15,15,12,13,13,15,14,11,11,12,13,14,12,12,
+ 13,13,15,12,12,13,14,15,14,14,15,14,16,14,14,15,
+ 15,16,11,12,12,14,14,12,13,13,15,15,12,13,13,15,
+ 14,14,15,15,16,16,14,15,14,17,15, 8, 9, 9,11,11,
+ 9,10,10,12,12, 9,11,10,13,12,11,12,12,14,14,11,
+ 13,12,15,13, 9,10,10,12,12,10,10,11,12,13,10,12,
+ 11,13,13,12,12,13,13,15,12,13,13,15,14, 9,10,10,
+ 12,12,11,11,12,13,13,10,12,10,13,12,12,13,13,15,
+ 15,12,13,13,15,13,11,12,12,14,14,12,12,13,14,14,
+ 12,13,13,15,14,13,13,14,13,16,14,15,14,16,16,11,
+ 12,12,14,14,13,13,13,15,15,12,13,12,15,14,14,15,
+ 15,16,17,14,15,13,16,13,10,11,11,13,14,11,12,12,
+ 13,15,11,12,12,14,14,13,14,14,15,16,13,14,14,16,
+ 16,11,11,12,12,14,12,12,13,13,15,12,13,13,13,15,
+ 14,14,15,14,17,14,14,15,15,16,11,12,12,14,14,12,
+ 13,13,15,15,12,13,13,15,15,14,15,15,16,17,14,15,
+ 15,16,16,13,14,14,14,16,14,14,15,14,17,14,15,15,
+ 14,17,16,16,17,15,18,16,16,17,16,18,13,14,14,16,
+ 16,14,15,15,17,16,14,15,15,17,16,16,17,17,18,18,
+ 16,17,16,18,17,10,11,11,14,13,11,12,12,14,14,11,
+ 13,12,15,14,14,14,14,16,15,14,15,14,16,15,11,12,
+ 12,14,13,12,13,13,15,14,13,14,13,15,14,14,15,15,
+ 16,16,14,15,15,17,15,11,12,12,14,14,13,13,13,15,
+ 15,12,13,13,15,14,15,15,15,17,17,14,15,15,17,15,
+ 13,14,14,16,15,14,15,15,16,16,15,15,15,17,16,16,
+ 16,16,16,17,16,17,16,18,17,14,14,14,16,16,15,15,
+ 15,16,16,14,15,14,17,16,16,17,17,17,18,16,17,16,
+ 18,16, 7, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12,
+ 11,10,11,11,13,14,10,11,11,14,13, 8, 9, 9,11,12,
+ 9,10,11,12,13, 9,11,10,13,12,11,12,12,13,14,11,
+ 12,12,14,14, 8, 9, 9,11,11, 9,10,10,12,12, 9,10,
+ 10,13,12,11,12,12,14,14,11,12,11,14,13,10,11,12,
+ 13,13,11,12,12,13,14,12,13,12,14,14,13,13,14,14,
+ 16,13,14,14,16,15,10,11,11,13,13,11,12,12,14,14,
+ 11,12,12,14,13,13,14,14,15,16,13,14,13,16,14, 8,
+ 9, 9,11,11, 9,10,11,12,13, 9,10,10,12,12,11,12,
+ 13,13,14,11,12,12,14,14, 9,10,10,12,12,10,10,11,
+ 12,13,11,12,11,13,13,12,12,13,13,15,12,13,13,15,
+ 15, 9,10,10,12,12,10,11,12,13,14,10,11,10,13,12,
+ 12,13,13,14,15,12,13,12,15,13,12,12,12,14,14,12,
+ 12,13,14,15,13,13,13,15,15,14,14,15,13,16,14,15,
+ 15,16,16,11,12,12,14,14,12,13,13,14,15,12,13,12,
+ 14,14,14,14,15,16,16,13,14,13,16,14, 8, 9, 9,11,
+ 11, 9,10,10,12,12, 9,10,10,12,12,11,12,12,14,14,
+ 11,12,11,14,14, 9,10,10,12,12,10,11,11,13,13,10,
+ 11,11,13,13,12,13,13,14,15,12,13,13,15,14, 9,10,
+ 9,12,11,10,11,10,13,12,10,11,10,13,12,12,13,12,
+ 15,14,12,13,12,15,14,11,12,12,14,14,12,13,13,14,
+ 15,12,13,13,15,15,14,14,15,15,17,14,15,15,16,16,
+ 11,12,11,14,13,12,13,12,15,14,12,13,12,15,13,14,
+ 15,14,16,15,13,15,14,17,14,10,11,11,13,14,11,12,
+ 13,13,15,11,12,12,14,14,14,14,15,15,17,13,14,14,
+ 15,16,11,12,12,14,14,12,12,13,14,15,13,13,13,15,
+ 15,14,15,15,15,17,15,15,15,16,16,11,12,12,13,14,
+ 13,13,14,14,15,12,13,13,14,15,14,15,15,16,17,14,
+ 15,15,16,16,14,14,14,16,16,14,14,15,15,17,15,15,
+ 15,17,16,16,16,17,16,18,16,17,17,18,17,13,14,14,
+ 15,16,14,15,15,16,17,14,15,15,16,16,16,17,17,17,
+ 18,16,16,16,17,16,10,11,11,14,13,11,12,12,14,14,
+ 11,12,12,15,13,13,14,14,16,15,13,14,14,16,15,11,
+ 12,12,14,14,12,13,13,15,15,12,13,13,15,15,14,15,
+ 15,16,17,14,15,15,17,16,11,12,11,14,12,12,13,13,
+ 15,13,12,13,12,15,13,14,15,15,16,15,14,15,14,17,
+ 14,13,14,14,16,16,14,15,15,16,17,14,15,15,16,17,
+ 16,16,17,17,18,16,17,17,18,18,13,14,14,16,13,14,
+ 15,15,17,14,14,15,14,17,14,16,17,16,17,16,16,17,
+ 16,18,15, 8,11,11,13,13,10,12,12,14,14,11,12,12,
+ 14,14,13,13,14,15,16,13,14,14,16,15,10,11,11,14,
+ 14,11,12,12,14,15,11,12,12,15,14,13,14,14,15,16,
+ 13,14,14,16,16,11,12,12,14,14,12,13,13,15,15,12,
+ 13,12,15,14,14,14,15,16,16,14,15,14,16,16,12,13,
+ 13,15,15,12,13,14,15,16,13,14,14,16,16,14,15,15,
+ 16,17,15,15,16,17,17,13,14,14,16,15,14,15,15,16,
+ 16,14,15,14,16,16,16,16,16,17,17,15,16,16,18,16,
+ 10,11,11,13,14,11,12,12,14,15,11,12,12,15,14,13,
+ 14,14,16,16,13,14,14,16,16,11,11,12,14,14,12,12,
+ 13,14,15,12,13,13,15,15,14,14,15,15,17,14,14,15,
+ 16,16,11,12,12,15,14,12,13,13,15,15,12,13,13,15,
+ 15,14,15,15,17,17,14,15,15,17,16,13,12,14,14,16,
+ 13,13,15,14,17,14,13,15,15,17,15,14,16,15,18,16,
+ 15,16,16,18,13,14,14,16,16,14,15,15,17,17,14,15,
+ 15,17,16,16,17,17,18,18,16,17,16,18,17,10,11,11,
+ 14,13,11,12,12,14,14,11,13,12,15,14,13,14,14,15,
+ 16,13,14,14,16,16,11,12,12,14,14,12,13,13,14,15,
+ 12,13,13,15,15,14,14,15,15,16,14,15,15,17,16,11,
+ 12,12,14,14,13,13,13,15,15,12,13,13,15,14,14,15,
+ 15,16,17,14,15,14,17,15,13,14,13,16,15,14,14,14,
+ 15,16,14,15,14,16,16,15,15,16,16,17,16,16,16,18,
+ 17,14,14,14,16,16,15,15,15,17,16,14,15,14,17,16,
+ 16,16,17,17,18,16,17,16,18,16,11,13,13,15,15,12,
+ 13,14,15,16,12,14,14,15,15,14,15,15,16,17,14,15,
+ 15,17,17,12,13,14,14,16,13,14,14,14,16,14,14,14,
+ 15,16,15,15,16,15,18,15,16,16,17,17,13,14,14,16,
+ 16,14,14,15,16,16,14,15,14,16,16,15,16,16,17,18,
+ 15,16,16,18,17,14,14,16,13,17,15,15,16,14,18,15,
+ 15,16,14,18,16,16,18,15,19,17,17,18,16,18,15,16,
+ 15,17,17,15,16,17,18,18,16,16,16,18,17,17,18,18,
+ 19,19,17,18,17,19,18,11,12,12,15,14,13,13,14,15,
+ 16,13,14,13,16,14,15,15,15,16,17,15,16,15,17,16,
+ 12,13,13,15,14,13,13,14,15,15,14,15,14,16,15,15,
+ 15,16,16,17,16,16,16,18,17,12,13,13,15,15,14,14,
+ 15,16,16,13,14,13,16,15,16,16,16,17,18,15,16,15,
+ 17,16,14,15,14,17,15,14,15,15,16,16,15,16,15,17,
+ 16,16,15,16,15,17,17,18,17,18,17,15,15,15,16,17,
+ 16,16,16,17,17,15,16,15,17,16,17,18,18,18,18,16,
+ 17,16,18,15, 8,11,11,13,13,11,12,12,14,14,10,12,
+ 12,14,14,13,14,14,15,16,13,14,13,16,15,11,12,12,
+ 14,14,12,12,13,14,15,12,13,13,15,15,14,14,15,15,
+ 16,14,14,14,16,16,10,11,11,14,14,11,12,12,14,15,
+ 11,12,12,15,14,13,14,14,16,16,13,14,14,16,15,13,
+ 14,14,15,16,14,14,15,16,16,14,15,15,16,16,15,16,
+ 16,16,18,16,16,16,17,17,12,13,13,15,15,13,14,14,
+ 16,16,12,14,13,16,15,15,16,15,17,17,14,16,15,17,
+ 16,10,11,11,13,14,11,12,13,14,15,11,13,12,14,14,
+ 14,14,15,16,16,13,14,14,16,16,11,12,12,14,14,12,
+ 13,13,14,15,13,14,13,15,15,14,15,15,16,17,14,15,
+ 15,17,16,11,12,12,14,14,12,13,13,15,15,12,13,12,
+ 15,14,14,15,15,16,17,14,15,15,16,16,14,14,14,16,
+ 16,14,14,15,16,16,15,15,15,16,16,16,16,17,16,18,
+ 16,17,17,18,18,13,13,14,15,16,14,14,15,16,17,13,
+ 14,14,16,16,16,16,17,17,18,15,16,15,17,16,10,11,
+ 11,14,13,11,12,12,14,14,11,12,12,15,14,13,14,14,
+ 16,16,13,14,14,16,16,11,12,12,14,14,12,13,13,15,
+ 15,12,13,13,15,15,14,15,15,16,17,14,15,15,17,16,
+ 11,12,11,14,14,12,13,13,15,15,12,13,12,15,14,14,
+ 15,14,16,16,14,15,14,17,16,14,14,14,16,16,14,15,
+ 15,16,17,14,15,15,17,17,16,16,17,17,18,16,17,17,
+ 18,18,13,14,12,16,14,14,15,13,17,15,13,15,13,17,
+ 14,16,16,15,18,16,15,17,14,18,15,11,12,12,14,15,
+ 13,13,14,14,16,13,14,13,15,14,15,15,16,16,17,15,
+ 16,15,17,16,12,13,13,15,15,13,13,14,15,16,14,15,
+ 14,16,16,15,15,16,15,18,16,16,16,18,17,12,13,13,
+ 15,15,14,14,15,15,16,13,14,13,15,15,16,16,16,16,
+ 18,15,16,15,17,16,15,15,15,17,16,15,15,16,16,17,
+ 16,16,16,18,17,16,16,17,15,18,17,18,17,19,18,14,
+ 14,15,15,17,15,15,16,16,17,14,15,15,16,16,17,17,
+ 18,17,19,16,17,15,17,15,11,13,12,15,15,12,14,14,
+ 15,15,12,14,13,16,15,15,15,15,17,17,14,15,15,17,
+ 16,12,14,14,16,16,14,14,15,16,16,14,14,14,16,16,
+ 15,16,17,17,18,15,16,16,18,17,12,14,13,16,14,13,
+ 14,14,16,15,13,15,14,16,14,15,16,16,17,17,15,16,
+ 15,18,15,15,15,16,17,17,15,16,16,17,18,16,16,16,
+ 18,18,17,17,18,18,19,17,17,18,19,19,14,15,14,17,
+ 13,15,16,15,18,14,15,16,15,18,14,17,18,17,18,16,
+ 16,18,16,19,15,
+};
+
+static const static_codebook _44p8_p2_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p8_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p8_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p3_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p8_p3_0[] = {
+ 2, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 8, 9, 7,
+ 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 5, 7, 8, 7, 9,
+ 10, 8, 9, 9, 8, 9,10, 9,10,12,10,11,11, 8,10, 9,
+ 10,11,12, 9,11,10, 5, 8, 7, 8,10, 9, 7,10, 9, 8,
+ 9,10, 9,10,11,10,12,11, 8,10, 9,10,11,11, 9,12,
+ 10, 5, 8, 8, 7, 9,10, 8,10, 9, 7, 9,10, 9,10,11,
+ 9,11,11, 8,10, 9,10,11,11,10,12,10, 7, 9,10, 9,
+ 10,12, 9,11,11, 9, 9,12,11,10,13,11,11,13,10,12,
+ 11,11,13,13,11,13,12, 7, 9, 9, 9,11,11, 9,12,11,
+ 9,11,10,10,11,12,11,13,12, 9,11,11,12,13,13,11,
+ 13,11, 5, 8, 8, 8, 9,10, 7,10, 9, 8, 9,10,10,10,
+ 12,10,11,11, 7,10, 9, 9,11,11, 9,11,10, 7, 9, 9,
+ 9,11,12, 9,11,11, 9,11,11,11,11,13,12,13,13, 9,
+ 10,11,11,12,13,10,12,11, 7,10, 9, 9,11,11, 9,12,
+ 10,10,11,12,11,12,13,12,13,13, 9,12, 9,11,13,11,
+ 10,13,10,
+};
+
+static const static_codebook _44p8_p3_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p8_p3_0,
+ 1, -533200896, 1614282752, 2, 0,
+ (long *)_vq_quantlist__44p8_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p3_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p8_p3_1[] = {
+ 6, 7, 7, 7, 7, 8, 7, 8, 7, 7, 7, 8, 7, 8, 8, 8,
+ 8, 8, 7, 8, 7, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8,
+ 8, 8, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 9, 9, 8,
+ 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8,
+ 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8, 9, 8,
+ 8, 9, 8,
+};
+
+static const static_codebook _44p8_p3_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p8_p3_1,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p8_p3_1,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p4_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p8_p4_0[] = {
+ 2, 5, 5, 4, 7, 8, 4, 8, 7, 5, 7, 8, 7, 7,10, 8,
+ 9, 9, 5, 7, 7, 8, 9, 9, 7,10, 7, 5, 7, 8, 8, 9,
+ 11, 8,10,10, 8, 9,10,10,10,12,11,12,12, 8,10,10,
+ 10,12,12,10,12,11, 5, 8, 7, 8,10,10, 8,11, 9, 8,
+ 10,10,10,11,12,10,12,12, 8,10, 9,11,12,12,10,12,
+ 10, 5, 8, 8, 7,10,10, 8,11,10, 7, 9,10, 9,10,12,
+ 10,12,12, 8,10,10,10,12,12,10,12,11, 7, 9,10, 9,
+ 11,12,10,12,11, 9, 9,12,10,10,13,12,12,13,10,12,
+ 11,12,13,13,11,13,11, 7,10, 9,10,11,12,10,13,11,
+ 9,11,11,11,11,13,12,14,13,10,11,11,12,14,14,11,
+ 14,11, 5, 8, 8, 8,10,11, 7,10,10, 8,10,10,10,11,
+ 12,10,12,12, 7,10, 9,10,12,12, 9,12,10, 7, 9,10,
+ 10,11,13,10,12,11,10,11,11,11,11,14,12,14,14, 9,
+ 11,11,12,13,14,11,13,11, 7,10, 9,10,11,12, 9,12,
+ 10,10,11,12,11,11,13,12,13,13, 9,12, 9,12,13,12,
+ 10,13,10,
+};
+
+static const static_codebook _44p8_p4_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p8_p4_0,
+ 1, -531365888, 1616117760, 2, 0,
+ (long *)_vq_quantlist__44p8_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p4_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p8_p4_1[] = {
+ 7, 9, 9,10,10, 9,10,10,10,11, 9,10,10,11,10, 9,
+ 10,10,11,11, 9,10,10,11,11, 9,10,10,11,11,10,10,
+ 10,11,11,10,10,10,11,11,10,11,11,11,11,10,11,11,
+ 11,11, 9,10,10,11,11,10,10,10,11,11, 9,10,10,11,
+ 11,10,11,11,11,11,10,11,11,11,11,10,11,11,11,11,
+ 10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,12,10,11,11,11,11,11,11,11,11,11,10,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11, 9,10,10,
+ 11,11,10,10,11,11,11,10,10,11,11,11,10,11,11,11,
+ 12,10,11,11,12,12,10,10,11,11,11,10,11,11,11,12,
+ 11,11,11,12,12,11,11,12,12,12,11,11,12,12,12,10,
+ 11,11,11,11,11,11,11,12,12,10,11,11,12,12,11,12,
+ 11,12,12,11,12,11,12,12,11,11,11,11,12,11,11,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,11,11,11,12,12,11,12,12,12,12,11,12,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12, 9,10,10,11,11,10,
+ 11,10,11,11,10,11,10,11,11,10,11,11,12,12,10,11,
+ 11,12,11,10,11,11,11,11,10,11,11,11,12,11,11,11,
+ 12,12,11,11,12,12,12,11,11,11,12,12,10,11,10,11,
+ 11,11,11,11,12,12,10,11,11,12,11,11,12,11,12,12,
+ 11,12,11,12,12,11,11,11,12,12,11,11,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,
+ 11,12,11,11,12,12,12,12,11,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,10,11,11,11,11,11,11,11,12,
+ 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,
+ 11,11,11,12,12,11,11,12,12,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,11,11,11,12,12,11,12,
+ 12,12,12,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,13,12,13,12,12,12,12,13,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,13,12,10,11,11,11,11,11,11,11,12,12,11,11,
+ 11,12,12,11,12,12,12,12,11,12,12,12,12,11,11,11,
+ 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,11,11,11,12,12,11,12,12,12,12,
+ 11,12,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,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,13,12,12,13,12,13,
+ 12, 9,10,10,11,11,10,10,11,11,11,10,11,10,11,11,
+ 10,11,11,12,12,10,11,11,12,12,10,10,11,11,11,10,
+ 11,11,11,12,10,11,11,12,12,11,11,12,12,12,11,11,
+ 11,12,12,10,11,10,11,11,11,11,11,12,12,10,11,11,
+ 12,11,11,12,11,12,12,11,12,11,12,12,11,11,11,11,
+ 12,11,11,12,12,12,11,12,12,12,12,11,12,12,12,12,
+ 11,12,12,12,12,11,11,11,12,11,11,12,12,12,12,11,
+ 12,11,12,12,12,12,12,12,12,12,12,12,12,12,10,10,
+ 11,11,11,10,11,11,12,12,10,11,11,12,12,11,11,11,
+ 12,12,11,11,12,12,12,10,11,11,11,12,11,11,12,12,
+ 12,11,11,12,12,12,11,11,12,12,12,11,12,12,12,12,
+ 11,11,11,12,12,11,12,12,12,12,11,12,11,12,12,11,
+ 12,12,12,12,11,12,12,12,12,11,11,12,12,12,11,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,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, 9,10,10,11,11,
+ 10,11,11,11,12,10,11,11,12,11,11,12,11,12,12,11,
+ 12,11,12,12,10,11,11,12,11,11,11,11,12,12,11,12,
+ 11,12,12,11,12,12,12,12,11,12,12,12,12,10,11,11,
+ 12,12,11,12,11,12,12,11,12,11,12,12,12,12,12,12,
+ 12,11,12,12,12,12,11,12,11,12,12,11,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,11,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,11,11,11,12,12,11,12,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,13,12,12,12,12,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,13,13,12,12,
+ 12,13,13,12,12,12,12,12,12,12,12,12,13,12,12,12,
+ 12,13,12,12,13,12,13,12,13,13,13,13,12,12,12,12,
+ 12,12,12,12,13,12,12,12,12,13,12,12,13,13,13,13,
+ 12,13,13,13,13,10,11,11,12,12,11,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,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,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,13,12,12,12,12,13,13,12,12,12,13,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,12,
+ 13,13,12,13,12,13,13,13,13,12,12,12,12,12,12,12,
+ 12,13,12,12,12,12,13,12,12,13,13,13,13,12,13,13,
+ 13,13, 9,10,10,11,11,10,10,11,11,11,10,11,10,11,
+ 11,10,11,11,12,12,10,11,11,12,12,10,11,11,11,11,
+ 10,11,11,12,12,11,11,11,12,12,11,11,12,12,12,11,
+ 11,12,12,12,10,11,10,11,11,10,11,11,12,12,10,11,
+ 11,12,11,11,12,11,12,12,11,11,11,12,12,11,11,11,
+ 11,12,11,11,12,12,12,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,11,11,11,12,11,11,12,12,12,12,
+ 11,12,11,12,12,12,12,12,12,12,11,12,12,12,12, 9,
+ 10,10,11,11,10,11,11,11,12,10,11,11,12,11,11,11,
+ 12,12,12,11,11,12,12,12,10,11,11,12,12,11,11,12,
+ 12,12,11,11,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,10,11,11,12,12,11,11,11,12,12,11,11,11,12,12,
+ 11,12,12,12,12,11,12,12,12,12,11,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,11,11,12,12,12,12,12,12,12,12,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,10,11,10,11,
+ 11,10,11,11,12,12,10,11,11,12,12,11,11,11,12,12,
+ 11,12,11,12,12,11,11,11,12,12,11,11,12,12,12,11,
+ 11,12,12,12,11,12,12,12,12,11,12,12,12,12,10,11,
+ 11,12,11,11,12,11,12,12,11,12,11,12,12,11,12,12,
+ 12,12,11,12,11,12,12,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,
+ 11,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,11,11,11,12,12,11,11,
+ 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,11,12,12,12,12,12,12,12,12,13,12,12,12,12,
+ 12,12,12,12,13,13,12,12,12,13,13,11,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,12,
+ 12,12,12,12,12,12,12,12,12,12,12,13,12,13,12,12,
+ 12,13,13,12,13,13,12,13,12,13,13,13,13,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,
+ 13,12,13,12,13,12,11,11,11,12,12,11,12,12,12,12,
+ 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,13,13,12,12,12,13,13,11,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,13,12,12,12,12,13,
+ 12,12,12,12,12,12,12,12,12,13,13,12,12,12,12,13,
+ 12,13,13,13,13,12,13,13,13,13,12,12,12,12,12,12,
+ 12,12,13,12,12,12,12,13,12,12,13,13,13,13,12,13,
+ 13,13,12,10,11,11,12,12,11,11,11,12,12,11,11,11,
+ 12,12,11,12,12,12,12,11,12,12,12,12,11,11,11,12,
+ 12,11,11,12,12,12,11,12,12,12,12,11,12,12,12,12,
+ 12,12,12,12,12,11,11,11,12,12,11,12,12,12,12,11,
+ 12,11,12,12,12,12,12,12,12,12,12,12,12,12,11,12,
+ 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,13,12,12,12,12,12,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,13,12,12,12,12,12,12,
+ 11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,12,
+ 12,12,12,12,11,12,12,12,12,11,11,12,12,12,11,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,13,12,12,12,
+ 13,13,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,13,13,12,12,12,13,13,12,12,12,12,12,
+ 12,12,12,12,13,12,12,12,12,13,12,12,13,12,13,12,
+ 12,13,13,13,12,12,12,12,12,12,12,12,12,13,12,12,
+ 12,13,12,12,13,13,13,13,12,13,13,13,13,10,11,11,
+ 12,12,11,12,12,12,12,11,12,12,12,12,11,12,12,12,
+ 12,12,12,12,12,12,11,11,12,12,12,11,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,13,12,12,12,13,13,11,
+ 12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,
+ 12,13,13,12,12,12,13,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,13,12,12,12,12,12,13,12,13,12,13,
+ 13,12,12,12,12,12,12,12,12,13,12,12,12,12,13,12,
+ 12,13,12,13,13,12,13,12,13,12,11,11,11,12,12,11,
+ 12,12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,13,12,13,12,12,13,13,13,11,12,12,12,
+ 12,12,12,12,12,12,12,12,12,13,12,12,12,12,13,13,
+ 12,12,12,13,12,12,12,12,12,12,12,12,13,12,13,12,
+ 12,12,12,13,12,12,13,12,13,12,13,13,12,13,12,12,
+ 12,12,12,12,13,13,13,12,12,12,12,13,12,12,13,13,
+ 13,13,12,13,13,13,12,11,11,11,12,12,11,12,12,12,
+ 12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,13,12,12,13,13,13,11,12,12,12,12,12,12,
+ 12,12,13,12,12,12,13,12,12,13,12,13,13,12,13,12,
+ 13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,13,12,13,12,13,13,13,12,12,12,12,12,12,
+ 12,13,12,13,12,12,12,12,13,12,12,13,13,13,12,12,
+ 13,12,13,12,10,11,11,12,12,11,11,11,12,12,11,11,
+ 11,12,12,11,12,12,12,12,11,12,12,12,12,11,11,11,
+ 12,12,11,11,12,12,12,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,11,11,11,12,12,11,12,12,12,12,
+ 11,12,11,12,12,12,12,12,12,12,11,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,13,12,12,12,12,12,11,12,12,12,12,12,12,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,10,11,11,12,12,11,11,12,12,12,11,12,12,12,12,
+ 11,12,12,12,12,12,12,12,12,12,11,11,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,13,12,12,
+ 12,13,13,11,11,11,12,12,12,12,12,12,12,11,12,12,
+ 12,12,12,12,12,13,13,12,12,12,13,13,12,12,12,12,
+ 12,12,12,12,12,13,12,12,12,12,13,12,12,13,12,13,
+ 12,12,13,13,13,12,12,12,12,12,12,12,12,12,13,12,
+ 12,12,12,12,12,12,13,13,13,12,12,12,13,12,11,11,
+ 11,12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,
+ 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,13,13,12,12,12,13,13,
+ 11,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,
+ 12,12,13,13,12,12,12,13,12,12,12,12,12,12,12,12,
+ 12,12,13,12,12,12,13,13,12,13,13,13,13,12,13,13,
+ 13,13,12,12,12,12,12,12,12,12,13,12,12,12,12,13,
+ 12,12,13,12,13,13,12,13,12,13,12,11,11,11,12,12,
+ 11,12,12,12,12,11,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,11,12,12,12,12,12,12,12,12,13,12,12,
+ 12,13,13,12,12,13,12,13,12,12,13,13,13,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,
+ 13,12,12,12,13,12,12,12,12,12,12,12,12,12,12,13,
+ 12,12,12,13,13,12,12,13,12,13,12,13,13,13,13,12,
+ 12,12,12,12,12,12,13,12,13,12,12,12,12,12,12,13,
+ 13,12,12,12,13,12,12,12,11,11,11,12,12,11,12,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,11,12,12,12,12,12,12,12,12,13,12,12,12,12,13,
+ 12,12,13,13,13,12,12,12,13,13,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,13,12,13,13,12,13,
+ 12,13,12,12,12,12,12,12,12,12,12,12,13,12,13,12,
+ 13,13,12,13,13,12,13,12,13,13,13,13,12,12,12,12,
+ 12,12,12,12,13,12,12,13,12,13,12,12,13,12,13,12,
+ 12,13,12,13,12,
+};
+
+static const static_codebook _44p8_p4_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p8_p4_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p8_p4_1,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p5_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p8_p5_0[] = {
+ 2, 6, 6, 9, 9, 5, 7, 8,10,11, 5, 8, 7,11,10, 8,
+ 10,11,12,13, 8,11,10,13,12, 6, 7, 8,10,11, 7, 8,
+ 10,10,12, 8, 9, 9,12,12,10,10,12,12,14,10,12,12,
+ 14,13, 6, 8, 7,11,10, 8, 9, 9,12,12, 7,10, 8,12,
+ 11,10,12,12,13,14,10,12,10,14,12, 9,10,11,11,13,
+ 10,10,11,11,13,11,12,12,13,14,12,12,13,11,15,13,
+ 14,14,15,14, 9,11,10,13,11,11,12,12,13,13,10,11,
+ 10,13,11,13,14,14,15,15,12,13,12,15,11, 6, 8, 9,
+ 11,12, 8, 9,11,12,13, 8,10,10,13,13,11,12,13,14,
+ 15,11,12,13,14,14, 9, 9,10,12,13,10,10,12,12,14,
+ 10,11,11,13,14,12,12,14,14,15,13,13,14,15,15, 9,
+ 10,10,13,13,10,11,11,13,14,10,11,10,14,13,13,13,
+ 14,15,15,12,14,13,15,14,12,12,13,13,14,12,13,14,
+ 13,15,13,14,14,15,15,14,14,15,14,16,15,15,15,16,
+ 16,12,13,13,14,14,13,14,14,15,15,12,14,13,15,14,
+ 14,15,15,16,16,14,15,14,16,14, 6, 9, 8,12,11, 8,
+ 10,10,13,13, 8,11, 9,13,12,11,12,12,14,14,11,13,
+ 12,15,14, 9,10,10,13,13,10,10,11,13,14,10,12,11,
+ 14,13,12,13,14,14,15,13,13,13,15,14, 9,10, 9,13,
+ 12,10,11,11,14,13,10,12,10,14,12,13,14,13,15,15,
+ 12,14,12,15,14,12,13,13,14,14,13,13,13,14,15,13,
+ 14,14,15,15,14,14,15,14,16,14,15,15,16,16,12,13,
+ 12,14,13,13,14,14,15,15,12,14,13,15,13,15,15,15,
+ 16,16,14,15,14,16,14,11,12,12,13,14,12,13,14,14,
+ 16,12,13,13,15,15,14,14,16,15,17,14,15,15,16,16,
+ 12,13,14,14,15,13,13,15,15,16,14,14,14,15,16,15,
+ 15,16,16,17,15,15,16,16,17,13,13,13,15,15,14,14,
+ 15,15,16,13,14,14,15,16,15,15,16,16,17,15,16,15,
+ 17,16,14,15,15,16,16,15,15,16,16,17,15,16,16,17,
+ 17,16,16,17,16,18,16,17,17,17,17,15,15,15,16,16,
+ 15,16,16,17,17,15,16,16,17,16,16,17,17,18,18,16,
+ 17,16,17,16,11,12,12,15,13,13,13,13,15,15,12,14,
+ 13,16,14,14,15,15,16,16,14,15,14,17,15,13,13,13,
+ 15,14,13,14,14,16,15,14,14,14,16,15,15,15,16,16,
+ 17,15,16,15,17,16,12,14,13,15,14,14,14,14,16,15,
+ 13,14,13,16,15,15,16,16,17,16,15,16,15,17,16,15,
+ 15,15,16,16,15,15,16,16,17,15,16,16,17,17,16,16,
+ 17,17,17,17,17,17,18,17,14,15,15,16,16,15,16,16,
+ 17,16,15,16,15,17,16,17,17,17,18,17,16,17,16,18,
+ 16, 6, 9, 9,12,12, 8,10,10,12,13, 8,10,10,13,12,
+ 10,12,12,14,15,11,13,12,15,14, 8, 9,10,12,13, 9,
+ 10,11,13,14,10,11,11,14,13,12,12,13,14,15,12,13,
+ 13,15,15, 8,10,10,13,13,10,11,11,13,14,10,12,10,
+ 14,13,12,13,13,15,15,12,14,13,15,14,11,12,12,13,
+ 14,12,12,13,13,15,12,13,13,15,15,14,13,15,14,16,
+ 14,15,15,16,16,12,13,13,14,14,13,13,14,15,14,12,
+ 14,13,15,14,14,15,15,16,15,14,15,14,16,14, 7, 9,
+ 10,12,12, 9,10,11,13,14, 9,11,10,13,13,11,12,13,
+ 14,15,12,13,13,15,14, 9,10,11,12,13,10,10,12,13,
+ 14,11,11,12,14,14,12,12,14,14,15,13,13,14,15,15,
+ 9,11,11,13,13,11,12,12,14,14,10,12,10,14,13,13,
+ 14,14,15,15,13,14,13,16,14,12,12,13,14,15,13,13,
+ 14,14,16,13,14,14,15,15,14,14,15,14,17,14,15,15,
+ 16,16,12,13,13,15,14,13,14,14,15,15,13,14,13,16,
+ 14,15,15,15,16,16,14,15,14,16,14, 7,10, 9,13,12,
+ 10,11,12,12,14,10,12,11,14,12,12,13,13,14,15,12,
+ 14,13,15,14, 9,11,10,13,13,10,11,12,13,14,12,13,
+ 12,15,13,13,13,14,13,15,13,14,14,16,15,10,11,11,
+ 13,13,12,12,13,14,14,11,12,11,14,13,14,14,14,15,
+ 16,13,14,13,16,13,12,13,13,14,14,12,13,13,14,15,
+ 14,14,14,15,15,14,13,15,13,16,15,15,15,17,16,13,
+ 13,13,14,14,14,14,14,15,15,12,13,13,15,14,15,16,
+ 16,16,16,14,15,14,16,13,11,12,13,14,15,12,13,14,
+ 15,16,13,14,14,15,15,14,14,15,15,17,14,15,15,16,
+ 16,13,13,14,14,15,13,13,15,14,16,14,14,15,15,16,
+ 15,14,16,15,17,15,16,16,16,17,13,14,14,15,15,14,
+ 14,15,16,16,13,15,14,16,16,15,16,16,17,17,15,16,
+ 15,17,16,14,15,15,15,17,15,15,16,15,17,15,16,16,
+ 16,17,16,16,17,16,18,17,17,17,17,18,15,15,15,17,
+ 16,15,16,16,17,17,15,16,16,17,16,16,17,17,18,18,
+ 16,17,16,18,17,11,13,12,15,14,13,13,14,15,15,13,
+ 14,13,16,14,15,15,15,16,16,15,16,15,17,16,13,14,
+ 13,15,14,13,13,14,15,15,14,15,14,16,15,15,15,16,
+ 16,16,15,16,15,18,16,13,14,14,15,15,14,15,15,15,
+ 16,13,15,13,16,15,15,16,16,17,17,15,16,15,17,16,
+ 15,15,15,16,16,15,15,15,16,17,16,16,16,17,16,16,
+ 16,17,16,17,17,17,17,18,17,15,15,15,16,16,16,16,
+ 16,17,17,15,16,15,17,16,17,17,17,18,18,16,17,16,
+ 17,15, 6, 9, 9,12,12, 8,10,10,12,13, 8,10,10,13,
+ 12,11,12,13,14,15,10,12,12,14,14, 9,10,10,13,13,
+ 10,10,12,13,14,10,11,11,14,13,12,13,14,14,15,12,
+ 13,13,15,15, 8,10, 9,13,12,10,11,11,13,14, 9,11,
+ 10,14,13,12,13,13,15,15,12,13,12,15,14,12,13,13,
+ 14,14,12,13,13,14,15,13,14,14,14,15,14,14,15,14,
+ 16,14,15,15,16,16,11,12,12,14,13,13,13,13,15,15,
+ 12,13,12,15,13,14,15,15,16,16,14,15,14,16,14, 7,
+ 9,10,12,13,10,10,12,12,14,10,12,11,14,13,12,13,
+ 14,14,15,12,13,13,15,14,10,11,11,13,13,11,11,12,
+ 13,14,12,13,12,14,14,13,13,14,13,16,14,14,14,15,
+ 15, 9,10,11,13,14,12,12,13,13,15,10,12,10,14,13,
+ 13,14,14,15,16,13,14,13,15,13,13,14,13,14,15,12,
+ 13,13,14,15,14,14,14,15,15,14,13,15,13,16,15,16,
+ 16,16,16,12,13,13,14,14,14,14,14,15,15,12,13,13,
+ 15,14,15,15,16,16,16,14,15,13,16,13, 7,10, 9,12,
+ 12, 9,10,11,13,13, 9,11,10,14,13,12,13,13,14,15,
+ 11,13,12,15,14, 9,11,11,13,13,10,10,12,13,14,11,
+ 12,12,14,14,13,13,14,14,16,13,14,14,16,15, 9,11,
+ 10,13,12,11,12,11,14,14,10,12,10,14,13,13,14,13,
+ 15,15,12,14,12,16,14,12,13,13,14,15,13,13,14,14,
+ 16,13,14,14,15,15,14,14,15,14,16,15,15,15,16,16,
+ 12,13,12,15,14,13,14,14,15,15,12,14,13,16,14,14,
+ 15,15,16,16,14,15,14,17,14,11,12,13,14,15,13,13,
+ 14,14,16,13,14,13,15,15,15,15,16,16,17,15,15,15,
+ 16,16,13,14,13,15,15,13,13,15,15,16,14,15,15,16,
+ 16,15,15,16,15,17,16,16,16,17,17,13,13,14,14,15,
+ 14,14,15,15,16,13,14,13,15,15,15,16,16,16,17,15,
+ 16,15,16,16,15,15,15,16,16,15,15,16,16,17,16,16,
+ 16,17,17,16,16,17,16,18,17,17,17,18,18,15,15,15,
+ 16,16,16,16,16,17,17,15,15,15,16,16,17,17,17,17,
+ 18,16,16,16,17,15,11,13,12,15,14,13,13,14,15,15,
+ 12,14,13,16,14,14,15,15,16,16,14,15,14,16,15,13,
+ 14,14,15,15,13,14,14,16,16,14,15,14,16,16,15,15,
+ 16,17,17,15,16,16,17,17,13,14,13,15,14,14,14,14,
+ 16,15,13,15,13,16,14,15,16,15,17,16,15,16,14,17,
+ 15,14,16,15,16,17,15,16,16,16,17,15,16,16,17,17,
+ 16,16,17,17,18,16,17,17,18,17,14,15,15,17,15,15,
+ 16,16,17,16,15,16,15,17,15,16,17,17,18,17,16,17,
+ 16,18,15,10,12,12,14,14,12,13,13,15,15,12,13,13,
+ 15,15,13,14,14,15,16,14,15,14,16,16,12,13,13,15,
+ 15,12,13,14,15,15,13,14,14,15,15,14,14,15,16,17,
+ 14,15,15,17,16,12,13,13,15,15,13,14,14,15,16,13,
+ 14,14,16,15,14,15,15,16,17,14,15,15,17,16,13,14,
+ 14,15,16,14,14,15,15,16,14,15,15,16,16,15,15,16,
+ 16,17,15,16,16,17,17,14,15,15,16,16,15,15,15,16,
+ 16,15,15,15,16,16,16,17,16,17,17,16,16,16,18,16,
+ 11,12,12,14,14,12,13,14,15,15,12,13,13,15,15,13,
+ 14,15,16,16,14,15,15,16,16,12,13,13,15,15,13,13,
+ 14,15,16,13,14,14,15,16,14,14,15,16,17,15,15,15,
+ 16,17,12,13,13,15,15,13,14,14,15,16,13,14,14,16,
+ 15,15,15,15,16,17,15,16,15,17,16,14,14,15,15,16,
+ 14,14,15,15,17,15,15,16,16,17,15,15,16,15,18,16,
+ 16,16,17,17,14,15,15,16,16,15,16,16,17,17,15,15,
+ 15,17,16,16,17,16,17,17,16,16,16,18,16,11,12,12,
+ 14,14,13,13,14,15,15,13,14,13,15,15,14,15,15,16,
+ 16,14,15,15,16,16,12,13,13,15,15,13,13,14,15,15,
+ 14,14,14,16,15,15,15,15,15,16,15,16,15,17,16,12,
+ 13,13,15,15,14,14,15,15,16,13,14,13,16,15,15,15,
+ 16,16,17,15,16,15,17,15,14,15,14,16,16,14,15,15,
+ 16,16,15,16,15,17,16,15,15,16,15,17,16,17,16,17,
+ 17,14,15,15,16,16,15,16,16,16,17,14,15,15,16,16,
+ 16,17,17,17,18,16,16,16,17,16,12,13,13,15,15,13,
+ 13,14,15,16,13,14,14,16,15,14,15,15,16,17,14,15,
+ 15,17,16,13,14,14,15,16,14,14,15,15,17,14,15,15,
+ 16,16,15,14,16,15,17,15,16,16,17,17,13,14,14,16,
+ 16,14,15,15,16,16,14,15,14,16,16,15,16,16,17,17,
+ 15,16,15,17,16,15,15,16,15,17,15,15,16,15,17,15,
+ 16,16,16,17,16,15,17,15,18,17,17,17,17,17,15,15,
+ 15,17,17,16,16,16,17,17,15,16,15,17,17,16,17,17,
+ 18,18,16,17,15,18,15,11,12,12,15,15,13,13,15,14,
+ 16,13,14,13,16,14,15,15,16,16,17,15,16,15,17,15,
+ 12,14,13,16,14,13,13,14,14,16,14,15,14,16,15,15,
+ 15,16,15,17,16,16,16,17,16,12,13,14,15,16,15,15,
+ 15,15,16,13,15,13,16,14,16,16,16,17,17,15,16,15,
+ 17,15,15,16,15,16,15,14,14,15,16,16,16,16,16,17,
+ 16,15,15,16,15,17,17,17,17,18,17,15,15,15,16,16,
+ 16,16,16,16,17,14,15,15,17,16,17,17,17,17,18,15,
+ 16,15,18,14,10,12,12,14,14,12,13,13,15,15,12,13,
+ 13,15,15,14,14,15,15,16,13,15,14,16,16,12,13,13,
+ 15,15,13,14,14,15,16,13,14,14,15,15,14,15,15,16,
+ 17,14,15,15,17,16,12,13,13,15,15,13,14,14,15,15,
+ 12,14,13,15,15,14,15,15,16,17,14,15,14,17,15,14,
+ 15,15,16,16,14,15,15,16,17,15,15,15,17,16,16,16,
+ 16,16,17,16,16,16,17,17,13,14,14,16,15,14,15,15,
+ 16,16,14,15,14,16,16,15,16,16,17,17,15,16,15,17,
+ 16,11,12,12,14,15,13,13,14,14,15,13,14,13,15,15,
+ 14,15,15,16,16,14,15,15,16,16,12,14,13,15,15,13,
+ 13,14,15,16,14,15,14,16,15,15,15,16,15,17,15,16,
+ 16,17,16,12,13,13,15,15,14,14,15,15,16,13,14,13,
+ 16,15,15,15,16,16,17,15,15,15,16,16,14,15,15,16,
+ 16,14,15,15,16,16,15,16,16,17,17,16,16,16,16,17,
+ 16,17,17,18,17,14,14,15,15,16,15,15,16,16,17,14,
+ 15,15,16,16,16,16,16,17,17,15,16,15,17,15,11,12,
+ 12,14,14,12,13,14,15,15,12,13,13,15,15,14,15,15,
+ 16,16,13,15,14,16,16,12,13,13,15,15,13,14,14,15,
+ 16,13,14,14,16,16,15,15,15,16,17,15,15,15,17,16,
+ 12,13,13,15,15,13,14,14,16,15,13,14,13,16,15,15,
+ 16,15,17,17,14,15,14,17,16,14,15,15,16,16,15,15,
+ 16,16,17,15,16,16,17,17,16,16,16,16,18,16,17,16,
+ 18,17,14,15,14,16,15,15,15,15,17,16,14,15,14,17,
+ 15,16,17,16,17,17,15,16,15,17,15,11,12,12,15,15,
+ 13,13,15,14,16,13,15,13,16,14,15,15,16,15,17,15,
+ 16,15,17,16,12,14,13,15,15,13,13,15,15,16,15,15,
+ 15,16,15,15,15,16,15,17,16,16,16,17,16,12,13,14,
+ 15,16,14,14,15,15,16,13,14,13,16,14,16,16,16,16,
+ 17,15,16,15,17,15,15,16,15,16,16,14,15,15,16,16,
+ 16,16,16,17,16,15,15,16,15,17,17,17,17,18,17,15,
+ 15,15,15,16,16,16,16,16,17,14,15,14,16,15,17,17,
+ 17,17,18,15,16,15,17,15,12,13,13,15,15,13,14,14,
+ 15,16,13,14,14,16,15,14,15,15,16,17,14,15,15,17,
+ 16,13,14,14,16,15,13,14,15,16,16,14,15,15,16,16,
+ 15,15,16,16,17,15,16,16,17,17,13,14,13,16,15,14,
+ 15,15,16,16,13,15,14,16,15,15,16,16,17,17,15,16,
+ 14,17,15,15,15,16,17,17,15,15,16,16,17,16,16,16,
+ 17,17,16,15,17,16,18,17,17,17,18,18,15,15,15,17,
+ 14,16,16,16,17,16,15,16,15,17,15,16,17,17,18,17,
+ 16,17,15,18,15,
+};
+
+static const static_codebook _44p8_p5_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p8_p5_0,
+ 1, -528744448, 1616642048, 3, 0,
+ (long *)_vq_quantlist__44p8_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p5_1[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44p8_p5_1[] = {
+ 2, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _44p8_p5_1 = {
+ 1, 7,
+ (char *)_vq_lengthlist__44p8_p5_1,
+ 1, -533200896, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p8_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p8_p6_0[] = {
+ 2, 6, 6, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 7, 9, 7,
+ 9, 9, 6, 7, 7, 8, 9, 9, 7, 9, 7, 6, 8, 8, 8, 9,
+ 10, 8, 9, 9, 8, 9,10, 9, 9,10,10,10,10, 8, 9, 9,
+ 10,10,11, 9,10,10, 6, 8, 8, 8, 9, 9, 8,10, 9, 8,
+ 9, 9, 9,10,10,10,11,10, 8,10, 9,10,11,10, 9,11,
+ 9, 6, 8, 8, 7, 9, 9, 7, 9, 9, 7, 9, 9, 8, 9,10,
+ 9,10,10, 8, 9, 9, 9,10,10, 9,10, 9, 7, 9, 9, 9,
+ 9,10, 9,10,10, 9, 9,10,10, 9,11,10,11,11, 9,10,
+ 10,10,11,11,10,11,10, 6, 9, 8, 9, 9,10, 9,10, 9,
+ 8,10,10, 9, 9,10,10,11,11, 9,10,10,10,11,11, 9,
+ 11, 9, 6, 8, 8, 7, 9, 9, 7, 9, 9, 8, 9, 9, 9, 9,
+ 10, 9,10,10, 7, 9, 9, 9,10,10, 8,10, 9, 6, 8, 9,
+ 9, 9,10, 9,10, 9, 9,10,10, 9, 9,11,10,11,11, 8,
+ 9,10,10,11,11, 9,10, 9, 7, 9, 9, 9,10,10, 9,10,
+ 9, 9,10,10,10,10,11,10,11,11, 9,10, 9,10,11,11,
+ 10,11, 9,
+};
+
+static const static_codebook _44p8_p6_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p8_p6_0,
+ 1, -527106048, 1620377600, 2, 0,
+ (long *)_vq_quantlist__44p8_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p6_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p8_p6_1[] = {
+ 4, 7, 7, 7, 7, 8, 7, 8, 7, 7, 7, 8, 7, 8, 8, 8,
+ 8, 8, 7, 8, 7, 8, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8,
+ 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9,
+ 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 8, 8, 9, 8, 8, 8, 8, 9, 9, 8, 9, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8,
+ 8, 8, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 9, 8, 9, 8, 8, 8, 8, 8, 9, 9, 8,
+ 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 8, 9, 9, 8, 8, 8, 8, 9, 8, 8, 9, 8, 7, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8,
+ 8, 8, 8, 9, 9, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9,
+ 8, 9, 8,
+};
+
+static const static_codebook _44p8_p6_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p8_p6_1,
+ 1, -530841600, 1616642048, 2, 0,
+ (long *)_vq_quantlist__44p8_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p8_p7_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p8_p7_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p8_p7_0,
+ 1, -512202240, 1635281408, 2, 0,
+ (long *)_vq_quantlist__44p8_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p7_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p8_p7_1[] = {
+ 1, 7, 7,12,12, 5,11,12,12,12, 5,12,11,12,12,12,
+ 12,12,12,12,12,13,13,13,13, 7,11,11,13,13,13,12,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13, 7,13,10,13,13,13,13,13,13,13,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,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, 7,13,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,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,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,
+ 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,
+ 13,13,13,13,13,13,13,13,13,13, 8,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,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,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,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,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,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,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,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,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,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,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,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,13,13,13,
+ 13, 8,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,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,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,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,13,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,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,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,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,10,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,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,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,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,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,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,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,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,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,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,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,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13, 8,13,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,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,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,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,11,
+ 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,
+ 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,
+ 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,
+ 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,11,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,
+};
+
+static const static_codebook _44p8_p7_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p8_p7_1,
+ 1, -514619392, 1630767104, 3, 0,
+ (long *)_vq_quantlist__44p8_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p7_2[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p8_p7_2[] = {
+ 1, 3, 2, 4, 5, 7, 7, 8, 8, 9, 9,10,10,11,11,12,
+ 12,13,13,14,14,15,15,15,15,
+};
+
+static const static_codebook _44p8_p7_2 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p8_p7_2,
+ 1, -518864896, 1620639744, 5, 0,
+ (long *)_vq_quantlist__44p8_p7_2,
+ 0
+};
+
+static const long _vq_quantlist__44p8_p7_3[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p8_p7_3[] = {
+ 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p8_p7_3 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p8_p7_3,
+ 1, -529006592, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44p8_p7_3,
+ 0
+};
+
+static const char _huff_lengthlist__44p8_short[] = {
+ 3, 9,15,17,20,21,22,23, 5, 5, 7, 9,11,13,17,20,
+ 9, 5, 5, 6, 8,10,15,18,11, 7, 5, 4, 6, 9,13,17,
+ 14, 9, 7, 5, 6, 7,10,14,17,10, 8, 6, 6, 4, 5, 8,
+ 20,14,13,10, 8, 4, 3, 4,23,17,16,14,12, 6, 4, 4,
+};
+
+static const static_codebook _huff_book__44p8_short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44p8_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p9_l0_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44p9_l0_0[] = {
+ 2, 5, 5, 7, 6, 8, 8, 9, 9,10,10,11,11, 4, 5, 5,
+ 6, 7, 8, 8, 9, 9,10,10,11,10, 4, 5, 5, 7, 6, 8,
+ 8, 9, 9,10,10,10,10, 6, 6, 7, 6, 7, 8, 8, 9, 9,
+ 10, 9,11, 9, 6, 6, 6, 7, 6, 8, 8, 9, 9, 9,10, 9,
+ 11, 7, 7, 8, 8, 8, 8, 9, 9, 9,10, 9,11, 9, 7, 8,
+ 8, 8, 8, 9, 8, 9, 9, 9,10, 9,11, 8, 9, 9, 9, 9,
+ 9, 9,10,10,11,10,12,10, 8, 9, 9, 9, 9, 9, 9,10,
+ 9,10,11,11,12, 9,10,10,10,10,10,10,10,11,11,11,
+ 11,12, 9,10,10,10,10,11,10,11,10,11,11,12,11,11,
+ 11,11,11,11,11,11,11,12,11,12,11,12,11,11,11,11,
+ 11,11,11,12,11,12,11,12,11,
+};
+
+static const static_codebook _44p9_l0_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44p9_l0_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44p9_l0_0,
+ 0
+};
+
+static const long _vq_quantlist__44p9_l0_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p9_l0_1[] = {
+ 4, 4, 4, 5, 5, 4, 4, 5, 5, 5, 4, 5, 4, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p9_l0_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p9_l0_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p9_l0_1,
+ 0
+};
+
+static const long _vq_quantlist__44p9_l1_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p9_l1_0[] = {
+ 1, 2, 3, 5, 9, 9, 4, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _44p9_l1_0 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44p9_l1_0,
+ 1, -514619392, 1630767104, 3, 0,
+ (long *)_vq_quantlist__44p9_l1_0,
+ 0
+};
+
+static const char _huff_lengthlist__44p9_lfe[] = {
+ 1, 1,
+};
+
+static const static_codebook _huff_book__44p9_lfe = {
+ 1, 2,
+ (char *)_huff_lengthlist__44p9_lfe,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44p9_long[] = {
+ 3, 3, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _huff_book__44p9_long = {
+ 1, 8,
+ (char *)_huff_lengthlist__44p9_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p9_p1_0[] = {
+ 1, 5, 5, 4, 8, 8, 4, 8, 8, 5, 7, 8, 8, 9,10, 8,
+ 10,10, 5, 8, 7, 8,10,10, 8,10, 9, 7, 9, 9, 9,11,
+ 11, 9,11,11, 9,11,11,11,12,13,11,13,13, 9,11,11,
+ 11,13,13,11,13,13, 7, 9, 9, 9,11,11, 9,11,11, 9,
+ 11,11,11,13,13,11,13,13, 9,11,11,11,13,13,11,13,
+ 12, 5, 9, 9, 9,11,11, 9,11,11, 9,11,11,11,12,13,
+ 11,13,13, 9,11,11,11,13,13,11,13,13, 9,11,12,11,
+ 13,13,12,13,13,11,12,13,13,14,15,13,14,14,12,13,
+ 13,13,15,15,13,15,14, 8,10,10,11,13,13,12,14,13,
+ 11,12,12,13,14,15,13,15,15,11,12,12,13,15,15,13,
+ 15,14, 5, 9, 9, 9,11,11, 9,11,11, 9,11,11,11,13,
+ 13,11,13,13, 9,11,10,11,13,13,11,13,12, 8,10,10,
+ 11,13,13,12,13,13,11,12,12,13,14,15,14,15,15,10,
+ 12,12,13,14,15,13,15,14, 9,12,11,12,13,13,11,13,
+ 13,12,13,13,13,15,15,13,14,15,11,13,12,13,15,14,
+ 13,15,14,
+};
+
+static const static_codebook _44p9_p1_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p9_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p9_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p9_p2_0[] = {
+ 4, 6, 6, 8, 8, 5, 7, 7, 9, 9, 5, 7, 7, 9, 9, 6,
+ 8, 8,11,11, 6, 8, 8,11,11, 6, 7, 7, 9, 9, 7, 8,
+ 9,10,11, 7, 9, 9,11,10, 8, 9,10,12,12, 8,10,10,
+ 12,12, 6, 7, 7, 9, 9, 7, 9, 9,10,10, 7, 9, 8,11,
+ 10, 8,10,10,12,12, 8,10, 9,12,12, 8, 9, 9,11,11,
+ 9,10,10,12,12, 9,11,11,12,13,11,12,12,13,14,11,
+ 12,12,14,14, 8, 9, 9,11,11, 9,11,10,13,12, 9,10,
+ 10,13,12,11,12,12,14,14,11,12,12,14,13, 7, 8, 9,
+ 10,10, 8,10,10,11,11, 8,10,10,11,11,10,11,11,13,
+ 13,10,11,11,13,13, 8, 9,10,10,11,10,11,11,12,13,
+ 10,11,11,12,12,11,11,12,13,14,11,12,12,14,14, 8,
+ 10,10,11,11,10,11,11,12,13,10,11,11,12,12,11,12,
+ 12,14,14,11,12,12,14,14,10,11,11,12,13,11,12,12,
+ 13,14,12,13,13,14,14,13,13,14,14,16,13,14,14,15,
+ 16,10,11,11,13,13,12,12,12,14,14,11,12,12,14,14,
+ 13,14,14,15,16,13,14,14,16,15, 7, 8, 8,10,10, 8,
+ 10,10,11,11, 8,10,10,12,11,10,11,11,13,13,10,11,
+ 11,13,13, 8,10,10,11,11,10,11,11,12,12,10,11,11,
+ 12,12,11,12,12,14,14,11,12,12,14,14, 8,10, 9,11,
+ 10,10,11,11,13,12,10,11,10,13,12,11,12,12,14,14,
+ 11,12,11,14,13,10,11,11,13,13,11,12,12,14,14,12,
+ 12,12,14,14,13,14,14,15,16,13,14,14,15,15,10,11,
+ 11,13,12,12,12,12,14,14,11,12,12,14,13,13,14,14,
+ 16,15,13,14,13,16,14,10,11,11,13,13,12,12,13,14,
+ 15,12,13,13,14,15,13,14,15,15,16,13,14,14,16,16,
+ 11,12,13,14,14,13,13,14,15,16,13,14,14,15,16,14,
+ 15,15,16,17,14,15,16,17,17,11,12,12,14,14,13,14,
+ 14,15,16,13,14,14,15,15,14,15,15,16,18,14,15,15,
+ 17,16,13,14,15,15,16,15,15,16,16,18,15,15,15,17,
+ 17,16,16,17,17,18,16,16,16,18,18,14,14,14,16,16,
+ 15,15,15,16,17,15,15,15,16,17,16,17,17,18,18,16,
+ 16,17,18,17,10,11,11,14,13,12,13,13,15,14,11,13,
+ 13,15,14,13,15,15,16,16,13,14,14,16,16,11,12,12,
+ 14,14,13,13,13,15,15,13,14,13,15,15,15,15,15,17,
+ 16,14,15,15,17,16,11,13,12,14,14,13,14,13,15,15,
+ 13,14,13,15,15,14,15,15,17,17,14,15,15,17,16,14,
+ 14,14,16,16,14,15,15,17,17,15,15,16,17,16,17,16,
+ 17,18,18,16,17,17,18,18,13,14,14,16,15,15,15,15,
+ 17,17,14,16,15,16,16,17,17,17,18,18,16,17,16,20,
+ 19, 6, 8, 8,10,10, 8,10,10,11,11, 8,10,10,12,11,
+ 10,11,11,13,13,10,11,11,13,13, 8, 9,10,11,11,10,
+ 11,11,12,12,10,11,11,13,12,11,12,12,14,14,11,12,
+ 12,14,14, 9,10,10,11,11,10,11,11,12,12,10,11,11,
+ 13,12,11,12,12,14,14,11,12,12,14,14,10,10,11,12,
+ 13,11,12,12,14,14,11,12,12,14,14,13,14,14,15,16,
+ 13,14,14,15,16,10,11,11,13,13,12,12,12,14,14,12,
+ 13,12,14,14,13,14,14,16,16,13,14,14,15,15, 9,10,
+ 10,11,12,10,11,11,12,13,10,11,11,13,12,11,12,12,
+ 14,14,11,12,12,14,14,10,10,11,12,13,11,12,12,13,
+ 14,11,12,12,13,14,12,13,14,14,15,12,13,13,15,15,
+ 10,11,11,13,13,11,12,12,13,14,11,12,12,14,13,12,
+ 13,13,15,15,12,13,13,15,15,12,11,13,12,14,13,13,
+ 14,14,15,13,13,14,14,15,14,15,15,16,17,14,15,15,
+ 16,17,12,13,12,14,14,13,14,14,15,15,13,14,14,15,
+ 15,14,15,15,16,17,14,15,15,16,17, 8, 9, 9,11,11,
+ 10,11,11,12,13,10,11,11,13,12,12,13,13,14,15,11,
+ 13,12,15,14, 9,11,10,12,12,11,12,12,13,14,11,12,
+ 12,14,13,13,13,14,15,15,13,14,13,15,15, 9,11,11,
+ 12,12,11,12,12,14,14,11,12,12,14,13,13,14,14,15,
+ 16,13,14,13,15,14,11,12,12,14,13,12,13,13,14,15,
+ 13,14,14,16,15,15,15,15,15,16,15,16,15,17,17,11,
+ 12,12,14,14,13,14,14,15,15,12,13,13,15,14,15,15,
+ 15,17,17,14,15,15,17,15,11,12,12,14,14,12,13,13,
+ 15,15,12,13,13,15,15,14,15,15,17,17,14,15,15,16,
+ 16,12,13,13,14,15,13,14,14,16,16,14,14,14,15,16,
+ 15,16,16,17,17,15,16,16,17,17,12,13,13,15,15,14,
+ 14,14,16,16,14,14,15,16,16,15,16,16,17,17,15,16,
+ 16,17,17,14,15,15,15,16,15,15,16,16,18,15,16,16,
+ 17,17,17,17,17,18,18,16,17,17,19,18,14,15,15,16,
+ 17,15,16,16,17,17,15,16,16,18,17,16,17,17,19,18,
+ 17,17,17,19,18,10,12,12,14,14,13,13,14,15,15,12,
+ 14,13,16,15,15,15,15,17,17,14,15,15,17,16,12,13,
+ 13,15,14,13,14,14,16,16,14,14,15,17,16,15,16,16,
+ 17,17,15,16,16,18,17,12,13,13,15,14,14,15,15,16,
+ 16,13,15,14,16,15,16,17,16,19,17,15,16,16,17,17,
+ 14,15,15,17,15,15,16,15,17,17,16,17,16,18,17,17,
+ 17,18,18,18,17,17,18,19,18,14,15,15,16,16,15,16,
+ 16,17,18,15,16,16,18,16,17,18,18,19,19,17,18,17,
+ 18,19, 6, 8, 8,10,10, 8,10,10,11,11, 8,10,10,12,
+ 11,10,11,11,13,13, 9,11,11,13,13, 9,10,10,11,11,
+ 10,11,11,12,12,10,11,11,12,12,11,12,12,14,14,11,
+ 12,12,14,14, 8,10, 9,11,11,10,11,11,12,12,10,11,
+ 11,12,12,11,12,12,14,14,11,12,12,14,14,10,11,11,
+ 13,13,11,12,13,14,14,12,12,12,14,14,13,14,14,15,
+ 16,13,14,14,16,16,10,11,10,13,12,11,12,12,14,14,
+ 11,12,12,14,14,13,14,14,15,16,13,14,14,16,15, 8,
+ 9, 9,11,11,10,11,11,12,13,10,11,11,13,12,12,13,
+ 13,14,15,12,13,13,15,14,10,11,11,12,12,11,11,12,
+ 13,14,11,12,12,14,14,13,13,14,15,16,13,14,14,15,
+ 15, 9,10,11,12,12,11,12,12,13,14,11,12,12,14,13,
+ 13,14,14,15,16,12,14,13,15,15,11,12,12,14,14,12,
+ 13,13,14,15,13,14,14,16,15,14,15,15,15,17,15,15,
+ 16,16,17,11,12,12,13,14,13,14,14,15,15,12,13,13,
+ 15,14,15,16,15,16,17,14,16,15,17,15, 9,10,10,12,
+ 11,10,11,11,13,13,10,11,11,13,12,11,12,12,14,14,
+ 11,12,12,14,14,10,11,11,12,13,11,12,12,13,14,11,
+ 12,12,14,14,12,13,13,15,15,12,13,13,15,15,10,11,
+ 10,13,12,11,12,12,13,13,11,12,12,14,13,12,13,13,
+ 15,15,12,13,13,15,14,12,13,12,14,14,13,14,14,15,
+ 15,13,14,14,15,15,14,15,15,16,16,14,15,15,16,16,
+ 11,13,11,14,12,13,13,13,15,14,12,14,13,15,14,15,
+ 15,15,17,16,14,15,14,17,15,10,12,12,14,14,13,13,
+ 14,15,16,12,14,13,15,15,14,15,16,17,17,14,15,16,
+ 17,17,12,13,13,14,15,13,14,14,16,16,14,14,15,16,
+ 16,16,16,16,17,17,16,16,16,18,18,12,13,13,14,15,
+ 14,14,15,16,16,13,14,14,16,15,16,16,16,17,18,15,
+ 16,16,17,17,14,15,15,16,16,15,15,16,17,17,15,16,
+ 16,17,18,17,18,18,18,19,17,18,18,19,19,14,15,15,
+ 16,16,15,16,16,17,17,15,16,16,17,17,17,17,18,20,
+ 18,17,18,17,18,18,11,12,12,14,14,12,13,14,15,15,
+ 12,13,13,15,15,14,15,15,16,17,14,15,15,16,17,12,
+ 13,13,15,15,14,14,14,16,16,14,14,14,16,16,15,16,
+ 16,17,17,15,16,16,17,17,12,13,13,15,14,13,14,14,
+ 16,15,14,15,14,16,15,15,16,16,17,17,15,16,16,17,
+ 16,14,15,15,16,16,15,16,16,17,17,16,16,16,17,17,
+ 17,17,17,19,18,17,17,17,18,19,14,15,14,17,15,15,
+ 16,16,17,17,15,16,15,17,17,16,17,17,18,18,16,17,
+ 17,18,17, 6,11,11,13,13,11,12,12,14,14,11,12,12,
+ 14,14,13,14,14,16,16,13,14,14,16,16,11,12,12,14,
+ 14,12,13,13,15,15,12,13,13,15,15,14,15,15,16,17,
+ 14,15,15,17,18,11,12,12,14,14,12,13,13,15,15,12,
+ 13,13,15,15,14,15,15,17,17,14,15,15,16,16,13,14,
+ 14,15,16,14,15,15,16,17,14,15,15,17,16,15,16,17,
+ 18,17,16,16,16,18,17,14,14,15,16,16,14,15,15,18,
+ 16,14,15,15,17,16,16,17,17,18,18,16,17,16,18,17,
+ 11,12,12,14,14,12,13,13,15,15,12,13,13,15,15,14,
+ 15,15,17,17,14,15,15,16,16,12,13,13,15,15,13,14,
+ 14,15,16,13,14,14,16,16,15,16,16,17,17,15,15,16,
+ 17,17,12,13,13,15,15,14,14,14,16,16,13,14,14,16,
+ 16,15,16,16,17,17,15,16,16,17,17,14,14,15,15,16,
+ 15,15,16,16,17,15,15,16,16,17,16,17,17,17,18,16,
+ 17,17,18,18,14,15,15,16,16,15,16,16,17,17,15,16,
+ 16,17,17,17,17,17,18,19,17,17,17,18,18,10,12,12,
+ 14,14,12,13,14,15,16,13,14,13,15,15,14,15,15,17,
+ 17,14,15,16,17,17,12,13,13,15,15,13,14,14,15,15,
+ 14,15,14,16,16,15,16,16,17,18,15,17,16,18,17,12,
+ 13,13,15,15,14,14,14,16,16,13,14,14,16,15,15,16,
+ 16,17,18,15,16,16,17,17,14,14,14,16,16,15,15,16,
+ 17,17,15,16,16,17,17,17,17,17,18,20,17,17,17,19,
+ 19,14,15,15,16,16,15,17,16,18,18,15,16,15,17,16,
+ 17,18,19,19,19,17,17,17,18,17,13,14,14,16,16,14,
+ 15,15,17,17,14,15,15,16,17,15,17,17,18,18,16,16,
+ 17,18,17,14,15,15,16,17,15,16,16,17,17,15,16,16,
+ 17,17,16,17,17,18,18,17,17,17,18,19,14,15,15,16,
+ 17,15,16,16,17,17,15,16,16,17,17,16,17,17,18,18,
+ 17,17,17,19,19,16,16,16,16,18,16,17,17,17,18,17,
+ 17,17,17,19,18,18,18,19,19,18,18,18,19,20,16,16,
+ 17,18,18,16,18,17,18,18,17,17,17,20,19,18,18,19,
+ 21,20,18,20,18,18,19,10,12,12,14,14,14,14,15,15,
+ 17,14,15,14,17,15,16,16,17,18,18,16,18,17,19,18,
+ 12,14,13,16,15,14,14,15,15,17,15,16,16,18,17,16,
+ 17,18,17,19,17,19,18,20,19,12,13,13,15,15,15,16,
+ 17,17,18,14,16,14,17,16,17,18,18,19,19,17,17,17,
+ 18,18,15,15,15,17,16,15,16,16,17,17,17,19,17,18,
+ 18,18,18,18,18,21,19,20,19,20,19,15,15,16,16,17,
+ 17,17,18,20,20,15,16,16,18,17,18,19,19,19,20,18,
+ 19,18,19,17, 6,11,11,13,13,11,12,12,14,14,11,12,
+ 12,14,14,13,14,14,16,16,13,14,14,16,16,11,12,12,
+ 14,14,12,13,13,15,15,12,13,13,15,15,14,15,15,17,
+ 17,14,15,15,17,16,11,12,12,14,14,12,13,13,15,15,
+ 12,13,13,15,15,14,15,15,16,16,14,15,15,16,16,13,
+ 14,14,16,16,15,15,15,16,16,14,15,15,17,16,16,17,
+ 17,19,18,16,17,17,18,18,13,14,14,15,15,14,15,15,
+ 17,16,14,15,15,17,16,16,17,16,17,18,15,16,16,18,
+ 18,10,12,12,14,14,12,13,14,15,15,12,13,13,15,15,
+ 14,15,15,17,17,14,15,15,17,16,12,13,13,15,15,14,
+ 14,14,15,16,14,15,15,16,16,15,16,16,17,18,16,16,
+ 16,18,18,12,13,13,14,14,14,14,15,16,16,13,14,14,
+ 16,16,15,16,16,18,18,15,16,16,19,17,14,15,15,16,
+ 17,15,15,16,17,17,16,17,16,17,18,17,17,18,17,19,
+ 17,17,18,18,19,14,14,14,16,16,15,16,16,17,17,15,
+ 16,15,17,17,17,17,17,19,20,16,17,17,18,18,11,12,
+ 12,14,14,12,13,13,15,15,12,13,13,15,15,14,15,15,
+ 16,16,14,15,14,16,16,12,13,13,15,15,14,14,14,16,
+ 16,13,14,14,16,16,15,16,16,18,17,15,16,16,17,17,
+ 12,13,13,15,15,13,14,14,16,16,13,14,14,16,16,15,
+ 16,15,18,18,15,16,15,17,16,14,15,15,16,16,15,16,
+ 16,17,17,15,16,16,18,17,16,17,17,18,18,16,17,17,
+ 18,18,14,15,14,16,15,15,16,15,17,17,15,16,15,17,
+ 16,16,17,17,18,18,17,17,16,19,17,10,12,12,14,15,
+ 14,14,15,15,17,14,15,14,17,15,16,17,17,17,18,16,
+ 17,17,18,18,12,14,13,16,15,14,14,16,15,17,15,17,
+ 16,18,17,17,17,18,17,19,18,18,18,19,18,12,13,14,
+ 15,15,15,16,16,16,17,14,15,14,18,16,18,17,18,19,
+ 19,17,18,17,20,18,15,15,15,17,17,15,16,16,17,18,
+ 18,18,18,19,18,18,18,19,18,20,18,19,19,21,21,15,
+ 15,16,16,17,17,18,18,18,18,15,16,16,17,17,17,19,
+ 20,19,20,17,18,18,19,17,13,14,14,16,16,14,15,15,
+ 16,17,14,15,15,17,17,16,16,17,17,18,15,17,16,17,
+ 17,14,15,15,16,16,15,16,16,17,17,16,16,16,17,17,
+ 17,17,18,17,18,17,17,17,18,20,14,15,15,17,16,15,
+ 16,16,17,17,15,16,16,17,17,17,17,17,18,18,16,17,
+ 17,19,18,16,16,17,17,17,17,18,17,19,18,17,17,17,
+ 18,19,17,20,18,19,21,17,19,18,19,20,15,17,15,17,
+ 16,16,17,17,18,18,17,17,17,18,17,18,19,18,19,21,
+ 18,18,17,19,19,
+};
+
+static const static_codebook _44p9_p2_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p9_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p9_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p3_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p9_p3_0[] = {
+ 2, 5, 4, 4, 7, 7, 4, 7, 6, 5, 6, 7, 7, 8, 9, 7,
+ 9, 9, 5, 7, 6, 7, 9, 9, 7, 9, 8, 6, 8, 8, 8,10,
+ 10, 8,10,10, 8, 9,10,10,11,12,10,12,12, 8,10,10,
+ 10,12,12,10,12,11, 6, 8, 8, 8,10,10, 8,10,10, 8,
+ 10,10,10,11,12,10,12,12, 8,10, 9,10,12,11,10,12,
+ 11, 5, 8, 8, 8,10,10, 8,10,10, 8, 9,10,10,11,11,
+ 10,11,11, 8,10,10,10,11,12,10,12,11, 8,10,10,10,
+ 11,11,10,11,11,10,11,11,11,12,13,11,12,13,10,11,
+ 11,11,13,13,11,13,13, 7, 9, 9,10,11,12,10,12,11,
+ 9,11,11,11,12,13,12,14,13, 9,11,11,12,13,14,11,
+ 13,12, 5, 8, 8, 8,10,10, 8,10,10, 8,10,10,10,11,
+ 12,10,12,12, 8,10, 9,10,12,11, 9,11,11, 7, 9, 9,
+ 10,11,12,10,12,11, 9,11,11,11,12,13,12,14,13, 9,
+ 11,11,12,13,14,11,13,12, 8,10,10,10,11,11,10,11,
+ 11,10,11,11,11,13,13,11,13,13,10,11,10,11,13,12,
+ 11,13,12,
+};
+
+static const static_codebook _44p9_p3_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p9_p3_0,
+ 1, -533200896, 1614282752, 2, 0,
+ (long *)_vq_quantlist__44p9_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p3_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p9_p3_1[] = {
+ 4, 6, 6, 6, 7, 7, 6, 7, 7, 6, 7, 7, 7, 7, 8, 7,
+ 7, 8, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8,
+ 8, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9,
+ 9, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9,
+ 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8,
+ 9, 9, 8, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9, 9,
+ 8, 9, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 9, 7, 8, 8,
+ 8, 9, 9, 8, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8,
+ 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9,
+ 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44p9_p3_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p9_p3_1,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44p9_p3_1,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p4_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p9_p4_0[] = {
+ 2, 5, 5, 4, 7, 7, 4, 7, 6, 5, 7, 7, 7, 8, 9, 7,
+ 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 6, 7, 8, 8, 9,
+ 10, 8,10,10, 8, 9,10,10,11,12,10,11,12, 8,10,10,
+ 10,11,12,10,12,11, 6, 8, 7, 8,10,10, 8,10, 9, 8,
+ 10,10,10,11,12,10,12,12, 8,10, 9,10,12,11,10,12,
+ 11, 5, 8, 8, 8,10,10, 8,10,10, 7, 9,10, 9,10,11,
+ 10,11,11, 8,10,10,10,12,12,10,12,11, 7, 9, 9, 9,
+ 11,11, 9,11,11, 9,10,11,11,11,12,11,12,12, 9,11,
+ 11,11,12,12,11,12,12, 7, 9, 9,10,11,12,10,12,11,
+ 9,11,10,11,11,12,12,13,13, 9,11,11,12,13,13,11,
+ 13,11, 5, 8, 8, 8,10,10, 8,10,10, 8,10,10,10,11,
+ 12,10,12,12, 7, 9, 9, 9,11,11, 9,11,10, 7, 9, 9,
+ 10,11,12,10,12,11, 9,11,11,11,11,13,12,13,13, 9,
+ 10,11,12,13,13,11,12,11, 7, 9, 9, 9,11,11, 9,11,
+ 11, 9,11,11,11,12,12,11,12,12, 9,11,10,11,12,12,
+ 10,12,11,
+};
+
+static const static_codebook _44p9_p4_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p9_p4_0,
+ 1, -531365888, 1616117760, 2, 0,
+ (long *)_vq_quantlist__44p9_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p4_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p9_p4_1[] = {
+ 6, 8, 8,10, 9, 8, 9, 9,10,10, 8, 9, 9,10,10, 8,
+ 10,10,10,10, 8,10,10,10,10, 9, 9, 9,10,10, 9,10,
+ 10,10,11, 9,10,10,11,11,10,10,10,11,11,10,10,10,
+ 11,11, 9, 9, 9,10,10, 9,10,10,11,11, 9,10,10,11,
+ 10,10,10,10,11,11,10,10,10,11,11,10,10,10,10,11,
+ 10,10,11,11,11,10,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,10,10,10,11,10,10,11,11,11,11,10,11,
+ 10,11,11,11,11,11,11,11,10,11,11,11,11, 9,10,10,
+ 10,11,10,10,11,11,11,10,11,11,11,11,10,11,11,11,
+ 11,10,11,11,11,11,10,10,11,11,11,11,11,11,11,11,
+ 11,11,11,11,12,11,11,12,12,12,11,11,11,12,12,10,
+ 11,11,11,11,11,11,11,12,12,11,11,11,11,11,11,11,
+ 11,12,12,11,11,11,12,12,11,11,11,11,11,11,12,12,
+ 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,12,
+ 12,11,11,11,11,11,11,12,12,12,12,11,12,11,12,12,
+ 11,12,12,12,12,12,12,12,12,12, 9,10,10,11,10,10,
+ 11,11,11,11,10,11,11,11,11,10,11,11,11,11,10,11,
+ 11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,
+ 12,12,11,11,12,12,12,11,11,11,12,12,10,11,10,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,
+ 11,11,11,12,12,11,11,11,11,11,11,12,12,12,12,11,
+ 12,12,12,12,11,12,12,12,12,12,12,12,12,12,11,11,
+ 11,11,11,11,12,12,12,12,11,12,11,12,12,12,12,12,
+ 12,12,11,12,12,12,12,11,11,11,11,11,11,12,12,12,
+ 12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,13,13,12,12,12,13,13,11,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,13,13,12,12,12,
+ 13,13,12,12,12,12,12,12,12,12,12,13,12,12,12,13,
+ 13,12,13,13,13,13,12,13,13,13,13,12,12,12,12,12,
+ 12,12,12,13,13,12,12,12,13,13,12,13,13,13,13,12,
+ 13,13,13,13,11,11,11,11,11,11,12,12,12,12,11,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,
+ 13,12,12,12,13,13,11,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,13,13,12,12,12,13,13,12,
+ 12,12,12,12,12,12,12,13,13,12,12,12,13,13,12,13,
+ 13,13,13,12,13,13,13,13,12,12,12,12,12,12,12,12,
+ 13,13,12,12,12,13,12,12,13,13,13,13,12,13,13,13,
+ 13, 7,10,10,11,11,10,10,11,11,11,10,11,11,11,11,
+ 10,11,11,11,11,10,11,11,11,11,10,10,10,11,11,10,
+ 11,11,11,11,11,11,11,11,12,11,11,11,12,12,11,11,
+ 11,12,12,10,11,11,11,11,11,11,11,12,11,11,11,11,
+ 12,11,11,11,11,12,12,11,11,11,12,12,11,11,11,11,
+ 11,11,11,11,12,12,11,11,12,12,12,11,12,12,12,12,
+ 11,12,12,12,12,11,11,11,11,11,11,12,12,12,12,11,
+ 11,12,12,12,11,12,12,12,12,11,12,12,12,12,10,11,
+ 11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,
+ 12,12,11,11,11,12,12,11,11,11,11,11,11,11,12,12,
+ 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,
+ 11,11,11,11,11,11,12,11,12,12,11,11,11,12,12,11,
+ 12,12,12,12,11,12,12,12,12,11,11,11,11,12,11,12,
+ 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,10,11,10,11,11,
+ 11,11,11,12,12,11,11,11,12,12,11,12,12,12,12,11,
+ 12,12,12,12,10,11,11,12,11,11,11,12,12,12,11,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,
+ 12,11,11,12,12,12,12,11,12,11,12,12,12,12,12,12,
+ 12,12,12,12,12,12,11,12,11,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,13,12,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,13,12,12,12,13,12,11,11,11,12,12,12,12,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 13,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,13,13,13,12,12,12,13,13,11,12,12,12,12,12,
+ 12,12,12,13,12,12,12,12,12,12,12,13,13,13,12,13,
+ 12,13,13,12,12,12,12,12,12,12,12,13,13,12,12,12,
+ 13,13,12,13,13,13,13,12,13,13,13,13,12,12,12,12,
+ 12,12,12,12,13,13,12,13,12,13,13,12,13,13,13,13,
+ 12,13,13,13,13,11,11,11,12,12,12,12,12,12,12,11,
+ 12,12,12,12,12,12,12,13,13,12,12,12,13,13,11,12,
+ 12,12,12,12,12,12,12,12,12,12,12,13,13,12,13,12,
+ 13,13,12,13,13,13,13,11,12,12,12,12,12,12,12,13,
+ 13,12,12,12,13,12,12,13,13,13,13,12,13,13,13,13,
+ 12,12,12,12,12,12,12,13,13,13,12,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,13,
+ 13,13,13,12,12,12,13,13,13,13,13,13,13,13,13,13,
+ 13,13, 7,10,10,11,11,10,11,11,11,11,10,11,11,11,
+ 11,10,11,11,11,11,10,11,11,11,11,10,11,11,11,11,
+ 11,11,11,11,11,11,11,11,12,11,11,11,12,12,12,11,
+ 11,11,12,12,10,10,10,11,11,11,11,11,12,11,10,11,
+ 11,11,11,11,11,11,12,12,11,11,11,12,12,11,11,11,
+ 11,11,11,11,12,12,12,11,12,11,12,12,11,12,12,12,
+ 12,11,12,12,12,12,11,11,11,11,11,11,11,11,12,12,
+ 11,12,11,12,12,11,12,12,12,12,11,12,12,12,12,10,
+ 10,10,11,11,11,11,11,12,12,11,11,11,12,12,11,12,
+ 12,12,12,11,12,12,12,12,11,11,11,11,11,11,11,12,
+ 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,11,11,11,11,11,11,12,12,12,12,11,12,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,13,12,12,
+ 12,13,12,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,10,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,
+ 11,11,11,12,12,11,11,11,11,11,11,11,12,12,12,11,
+ 12,11,12,12,11,12,12,12,12,11,12,12,12,12,11,11,
+ 11,11,11,11,11,11,12,12,11,11,11,12,12,11,12,12,
+ 12,12,11,12,12,12,12,11,11,11,12,11,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 11,11,11,12,11,11,12,12,12,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,11,11,11,12,12,11,12,
+ 12,12,12,12,12,12,12,12,12,12,12,13,13,12,12,12,
+ 13,12,11,12,12,12,12,12,12,12,12,13,12,12,12,13,
+ 13,12,13,13,13,13,12,13,13,13,13,11,12,12,12,12,
+ 12,12,12,12,13,12,12,12,12,12,12,13,13,13,13,12,
+ 13,13,13,13,12,12,12,12,12,12,12,13,13,13,12,13,
+ 12,13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,
+ 12,12,12,13,13,13,13,12,13,12,13,13,13,13,13,13,
+ 13,13,13,13,13,13,11,11,11,12,12,11,12,12,12,12,
+ 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,
+ 12,13,13,12,12,12,13,13,11,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,13,13,12,13,12,13,
+ 13,12,12,12,12,12,12,12,12,13,13,12,12,12,13,13,
+ 13,13,13,13,13,12,13,13,13,13,12,12,12,12,12,12,
+ 13,12,13,13,12,13,12,13,12,12,13,13,13,13,12,13,
+ 13,13,13, 8,11,11,12,12,11,12,12,12,12,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,12,
+ 12,11,12,12,12,12,12,12,12,12,12,12,12,12,13,13,
+ 12,12,12,13,13,11,11,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,13,13,12,12,12,13,13,11,12,
+ 12,12,12,12,12,12,12,13,12,12,12,12,12,12,12,13,
+ 13,13,12,12,13,13,13,11,12,12,12,12,12,12,12,13,
+ 12,12,12,12,13,13,12,13,13,13,13,12,13,13,13,13,
+ 11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,11,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,13,13,12,12,12,
+ 13,13,11,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,13,12,13,13,12,13,12,13,13,12,12,12,12,12,
+ 12,12,12,12,13,12,12,12,13,13,12,13,13,13,13,12,
+ 13,13,13,13,12,12,12,12,12,12,12,12,13,13,12,12,
+ 12,13,13,12,13,13,13,13,12,13,13,13,13,11,11,11,
+ 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,13,
+ 12,12,12,12,12,13,11,12,12,12,12,12,12,12,12,13,
+ 12,12,12,12,13,12,13,13,13,13,12,13,13,13,13,11,
+ 12,12,12,12,12,12,12,12,13,12,12,12,13,12,12,13,
+ 13,13,13,12,13,13,13,13,12,12,12,12,12,12,12,12,
+ 13,13,12,12,13,13,13,12,13,13,13,13,12,13,13,13,
+ 13,12,12,12,12,12,12,13,13,13,13,12,13,12,13,13,
+ 12,13,13,13,13,13,13,13,13,13,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,11,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,13,13,13,12,13,13,13,13,11,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,
+ 12,13,12,13,13,12,12,12,12,12,12,12,12,13,13,12,
+ 12,12,13,13,12,13,13,13,13,12,13,13,13,13,12,12,
+ 12,12,12,12,13,12,13,13,12,12,12,13,13,13,13,13,
+ 13,13,12,13,13,13,13,11,11,11,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,13,12,12,12,13,12,
+ 11,12,12,12,12,12,12,12,12,12,12,12,12,13,13,12,
+ 12,13,13,13,12,13,13,13,13,11,12,12,12,12,12,12,
+ 12,12,13,12,12,12,13,12,12,13,13,13,13,12,13,13,
+ 13,13,12,12,12,12,12,12,12,12,13,13,12,12,12,13,
+ 13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,12,
+ 12,13,13,13,13,12,13,12,13,13,13,13,13,13,13,13,
+ 13,13,13,13, 8,11,11,11,11,11,12,12,12,12,11,12,
+ 12,12,12,12,12,12,12,12,11,12,12,12,12,11,11,11,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 13,12,12,12,13,13,11,11,11,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,13,13,12,12,12,13,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,13,13,12,13,
+ 13,13,13,12,13,13,13,13,11,12,12,12,12,12,12,12,
+ 12,13,12,12,12,13,12,12,13,13,13,13,12,13,12,13,
+ 13,11,11,11,12,12,12,12,12,12,12,11,12,12,12,12,
+ 12,12,12,13,13,12,12,12,13,12,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,13,13,12,12,13,13,13,12,13,
+ 13,13,13,11,12,12,12,12,12,12,12,13,13,12,12,12,
+ 12,12,12,13,13,13,13,12,13,13,13,13,12,12,12,12,
+ 12,12,12,13,13,13,12,12,13,13,13,13,13,13,13,13,
+ 12,13,13,13,13,12,12,12,12,12,12,13,12,13,13,12,
+ 12,12,13,13,13,13,13,13,13,12,13,13,13,13,11,11,
+ 11,12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,13,12,13,13,12,12,12,13,13,
+ 11,12,12,12,12,12,12,12,12,13,12,12,12,12,12,12,
+ 12,12,13,13,12,13,12,13,13,12,12,12,12,12,12,12,
+ 12,13,12,12,12,12,13,13,12,13,13,13,13,12,13,13,
+ 13,13,12,12,12,12,12,12,12,12,13,13,12,12,12,13,
+ 12,12,13,13,13,13,12,13,13,13,13,11,11,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,13,13,11,12,12,12,12,12,12,12,12,13,12,12,
+ 12,12,12,12,13,13,13,13,12,13,13,13,13,11,12,12,
+ 12,12,12,12,12,12,13,12,12,12,12,12,12,13,13,13,
+ 13,12,13,13,13,13,12,12,12,12,12,12,12,12,13,13,
+ 12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,12,
+ 12,12,12,12,12,13,13,13,13,12,12,12,13,12,13,13,
+ 13,13,13,12,13,13,13,13,11,11,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 13,11,12,12,12,12,12,12,12,12,12,12,12,12,13,12,
+ 12,12,12,13,13,12,13,13,13,13,11,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,13,13,13,13,12,13,
+ 12,13,13,12,12,12,12,12,12,12,13,13,13,12,13,12,
+ 13,13,12,13,13,13,13,13,13,13,13,13,12,12,12,12,
+ 12,12,12,12,12,13,12,12,12,13,13,13,13,13,13,13,
+ 12,13,13,13,13,
+};
+
+static const static_codebook _44p9_p4_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p9_p4_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p9_p4_1,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p5_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p9_p5_0[] = {
+ 4, 6, 6, 9, 9, 6, 7, 8,10,11, 6, 8, 7,10,10, 8,
+ 10,10,12,12, 8,10,10,12,12, 6, 7, 8,10,10, 7, 8,
+ 9,10,11, 8, 9, 9,11,11,10,10,11,12,13,10,11,11,
+ 13,13, 6, 8, 7,10,10, 8, 9, 9,11,11, 7, 9, 8,11,
+ 10,10,11,11,13,13,10,11,10,13,12, 9,10,10,11,12,
+ 10,10,11,12,13,10,11,11,12,13,12,12,13,12,14,12,
+ 13,13,14,14, 9,10,10,12,11,10,11,11,13,12,10,11,
+ 10,13,12,12,13,13,14,14,12,13,12,14,12, 7, 8, 8,
+ 10,11, 8, 9,10,11,12, 8, 9, 9,11,12,10,11,12,13,
+ 14,10,11,11,13,13, 8, 9,10,11,12, 9,10,11,12,13,
+ 10,10,11,12,12,11,12,12,13,14,11,12,12,14,14, 8,
+ 9, 9,11,12,10,10,11,12,13, 9,10,10,12,12,11,12,
+ 12,14,14,11,12,12,14,13,11,11,12,12,13,11,12,12,
+ 13,14,12,12,13,14,14,13,13,14,14,16,13,14,14,15,
+ 15,11,12,11,13,13,12,12,12,14,14,11,12,12,14,13,
+ 13,14,14,15,15,13,14,13,15,14, 7, 8, 8,11,10, 8,
+ 10, 9,12,11, 8,10, 9,12,11,10,11,11,13,13,10,12,
+ 11,14,13, 8, 9, 9,12,11, 9,10,10,12,12,10,11,10,
+ 13,12,11,12,12,13,14,11,12,12,14,14, 8,10, 9,12,
+ 11,10,11,10,12,12, 9,11,10,13,11,11,12,12,14,14,
+ 11,12,12,14,13,11,11,12,13,13,11,12,12,13,14,12,
+ 12,12,14,14,13,13,14,14,15,13,14,14,15,15,11,12,
+ 11,13,12,12,12,12,14,14,11,12,12,14,13,13,14,14,
+ 15,15,13,14,13,15,14,10,11,11,12,13,11,12,12,13,
+ 14,11,12,12,13,14,13,13,14,14,16,13,14,14,15,15,
+ 11,12,12,12,14,12,12,13,13,15,12,13,13,13,15,14,
+ 14,15,15,16,14,14,15,15,16,11,12,12,13,14,12,13,
+ 13,14,15,12,13,13,14,14,14,14,15,15,16,14,14,14,
+ 15,15,13,14,14,14,15,14,14,15,15,16,14,15,15,15,
+ 16,15,15,16,16,18,16,16,16,17,17,13,14,14,15,15,
+ 14,14,15,16,16,14,14,14,16,15,16,16,16,17,17,15,
+ 16,16,17,16,10,11,11,13,12,11,12,12,14,13,11,12,
+ 12,14,13,13,14,14,15,15,13,14,13,16,14,11,12,12,
+ 14,13,12,13,13,14,14,12,13,13,15,14,14,14,14,15,
+ 15,14,15,14,16,15,11,12,12,14,12,12,13,13,15,14,
+ 12,13,12,15,13,14,15,14,16,15,14,15,14,16,15,13,
+ 14,14,15,15,14,14,14,15,16,14,15,14,16,16,15,16,
+ 16,16,17,16,16,16,17,17,13,14,14,15,14,14,15,15,
+ 16,15,14,15,14,16,15,16,16,16,17,17,15,16,15,18,
+ 16, 6, 8, 8,11,11, 8, 9,10,11,12, 8,10, 9,12,12,
+ 10,11,11,13,13,10,12,11,14,13, 8, 9, 9,11,12, 9,
+ 10,10,12,12, 9,10,10,12,12,11,11,12,13,14,11,12,
+ 12,14,14, 8,10, 9,12,11,10,11,11,12,12, 9,11,10,
+ 13,12,11,12,12,14,14,11,12,12,14,13,10,11,11,13,
+ 13,11,12,12,13,14,11,12,12,14,14,13,13,14,13,15,
+ 13,14,14,15,15,11,12,11,13,13,12,12,12,14,14,11,
+ 12,12,14,13,13,14,14,15,15,13,14,13,15,14, 8, 9,
+ 9,11,11, 9,10,10,12,12, 9,10,10,12,12,11,12,12,
+ 13,14,11,12,12,14,14, 9, 9,10,11,12,10,10,11,12,
+ 13,10,10,11,12,13,12,12,13,13,15,12,12,13,14,14,
+ 9,10,10,12,12,10,11,11,13,13,10,11,11,13,13,12,
+ 13,13,14,15,12,13,12,14,14,11,11,12,12,14,12,12,
+ 13,13,14,12,12,13,13,14,13,13,14,14,16,14,14,14,
+ 15,15,11,12,12,14,13,12,13,13,14,14,12,13,13,15,
+ 14,14,14,14,16,16,13,14,14,16,14, 7, 9, 9,12,11,
+ 9,10,10,12,12, 9,11,10,13,12,11,12,12,13,14,11,
+ 13,12,14,13, 9,10,10,12,12,10,10,11,12,13,10,12,
+ 11,13,13,12,12,13,13,14,12,13,13,15,14, 9,10,10,
+ 12,12,11,11,11,13,13,10,12,10,13,12,12,13,13,14,
+ 15,12,13,12,15,13,11,12,12,14,13,12,12,13,13,14,
+ 12,13,13,15,14,13,13,14,13,16,14,15,14,16,15,12,
+ 12,12,14,14,13,13,13,14,14,12,13,12,14,13,14,15,
+ 15,16,16,13,14,13,16,13,10,11,12,13,14,11,12,13,
+ 13,15,12,12,13,14,14,13,14,14,15,16,13,14,14,16,
+ 15,12,12,13,12,14,12,12,13,13,15,13,13,13,13,15,
+ 14,14,15,14,16,14,15,15,15,16,12,13,12,14,14,13,
+ 13,13,15,15,12,13,13,15,15,14,15,15,16,16,14,15,
+ 15,16,16,13,14,14,13,16,14,14,15,14,16,14,14,15,
+ 14,16,15,15,16,15,18,16,16,16,16,17,14,14,14,16,
+ 15,14,15,15,16,16,14,15,15,16,16,16,16,16,17,17,
+ 15,16,16,17,16,10,12,11,14,13,12,13,13,14,14,12,
+ 13,12,15,14,14,14,14,15,15,14,15,14,16,15,12,13,
+ 12,14,13,12,13,13,15,14,13,14,13,15,14,14,15,15,
+ 16,16,14,15,15,17,15,12,13,12,14,14,13,14,14,15,
+ 15,13,14,13,15,14,15,15,15,16,16,14,15,15,17,15,
+ 14,14,14,16,15,14,15,15,16,16,14,15,15,16,15,16,
+ 16,16,16,17,16,17,16,18,17,14,14,14,16,15,15,15,
+ 15,16,16,14,15,14,16,15,16,16,17,17,17,15,16,15,
+ 17,16, 6, 8, 8,11,11, 8, 9,10,12,12, 8,10, 9,12,
+ 11,10,11,12,13,13,10,11,11,13,13, 8, 9,10,11,12,
+ 9,10,11,12,13,10,11,11,12,12,11,12,12,13,14,11,
+ 12,12,14,14, 8, 9, 9,12,11, 9,10,10,12,12, 9,10,
+ 10,12,12,11,12,12,14,14,11,12,11,14,13,11,11,12,
+ 13,13,11,12,12,13,14,12,12,12,14,14,13,13,14,14,
+ 15,13,14,14,15,15,10,11,11,13,13,11,12,12,14,14,
+ 11,12,12,14,13,13,14,14,15,15,13,14,13,15,13, 7,
+ 9, 9,11,12, 9,10,11,12,13, 9,10,10,12,12,11,12,
+ 13,13,14,11,12,12,14,14, 9,10,10,12,12,10,10,11,
+ 12,13,11,12,11,13,13,12,12,13,13,15,12,13,13,15,
+ 14, 9,10,10,12,12,10,11,12,13,13,10,11,10,13,12,
+ 12,13,13,14,15,12,13,12,14,13,12,12,12,14,14,12,
+ 12,13,13,14,13,13,13,15,14,14,13,14,13,16,14,15,
+ 15,16,16,11,12,12,13,14,12,13,13,14,15,12,13,12,
+ 14,13,14,14,15,15,16,13,14,13,15,13, 8, 9, 9,11,
+ 11, 9,10,10,12,12, 9,10,10,12,12,11,12,12,14,14,
+ 11,12,11,14,13, 9,10,10,12,12,10,11,11,13,13,10,
+ 11,11,13,13,12,12,13,14,15,12,13,13,15,14, 9,10,
+ 9,12,11,10,11,10,13,12,10,11,10,13,12,12,13,12,
+ 14,14,12,13,12,15,13,11,12,12,13,14,12,13,13,14,
+ 14,12,13,13,14,14,14,14,14,14,16,14,14,14,16,15,
+ 11,12,11,14,12,12,13,12,15,13,12,13,12,15,13,14,
+ 14,14,16,15,13,14,13,16,14,10,11,12,13,14,12,12,
+ 13,13,15,12,13,13,14,14,14,14,15,15,16,14,14,14,
+ 15,16,12,12,13,14,14,12,13,14,14,15,13,14,14,15,
+ 15,14,15,15,15,17,15,15,15,16,16,12,12,13,13,14,
+ 13,13,14,14,15,12,13,13,14,15,15,15,15,15,17,14,
+ 15,15,15,15,14,14,14,16,16,14,15,15,15,16,15,15,
+ 15,16,16,16,15,16,16,18,16,16,17,17,17,14,14,14,
+ 15,16,15,15,15,16,17,14,15,14,16,16,16,16,17,17,
+ 18,16,16,15,17,16,10,12,11,14,13,12,12,12,14,14,
+ 11,13,12,14,13,13,14,14,15,15,13,14,13,16,15,12,
+ 12,13,14,14,12,13,13,15,15,13,13,13,15,15,14,15,
+ 15,16,16,14,15,15,17,16,12,13,12,14,12,13,13,13,
+ 15,13,12,13,12,15,13,14,15,15,16,15,14,15,14,16,
+ 14,14,14,14,16,16,14,15,15,16,16,14,15,15,16,16,
+ 15,16,16,16,17,16,17,16,18,17,13,14,14,16,13,14,
+ 15,15,16,14,14,15,14,16,14,16,16,16,17,16,15,16,
+ 15,18,15, 9,11,11,13,13,11,12,12,14,14,11,12,12,
+ 14,14,13,14,14,15,15,13,14,14,15,15,11,12,12,14,
+ 14,11,12,13,14,15,12,13,13,15,14,13,14,14,15,16,
+ 13,14,14,16,16,11,12,12,14,14,12,13,13,15,15,12,
+ 13,13,15,14,14,14,14,16,16,14,15,14,16,15,12,13,
+ 13,14,15,12,13,14,15,16,13,14,14,16,16,14,14,15,
+ 16,17,15,15,15,17,17,13,14,14,15,15,14,15,14,16,
+ 16,14,15,14,16,15,15,16,16,17,17,15,16,15,17,16,
+ 10,12,12,13,14,11,12,13,14,14,12,13,12,14,14,13,
+ 14,14,15,16,13,14,14,16,15,11,12,12,14,14,12,12,
+ 13,14,15,12,13,13,15,15,13,13,15,15,17,14,14,15,
+ 16,16,12,13,12,14,14,12,13,13,15,15,12,13,13,15,
+ 14,14,15,15,16,16,14,15,14,16,16,13,12,14,13,16,
+ 13,13,15,14,16,14,13,15,15,16,14,14,16,15,17,15,
+ 15,16,16,17,13,14,14,16,15,14,15,15,16,16,14,15,
+ 14,16,15,16,16,16,17,17,15,16,16,18,16,10,12,12,
+ 14,14,12,12,13,14,14,12,13,12,15,14,13,14,14,15,
+ 16,14,15,14,16,15,11,12,12,14,14,12,13,13,14,15,
+ 13,14,13,15,15,14,14,15,15,16,14,15,15,17,16,12,
+ 13,13,14,14,13,13,14,15,15,12,14,13,15,15,14,15,
+ 15,16,16,14,15,15,17,15,13,14,13,15,15,13,14,14,
+ 15,16,14,15,14,17,16,15,15,15,15,17,16,16,16,18,
+ 17,14,14,14,16,16,15,15,15,16,16,14,15,14,16,16,
+ 16,16,17,17,17,16,16,16,17,16,11,12,13,14,14,12,
+ 13,13,15,15,12,13,13,15,15,14,15,15,16,16,14,15,
+ 15,17,16,12,13,13,14,15,13,13,14,14,16,13,14,14,
+ 15,16,15,14,16,15,17,15,15,16,16,17,12,13,13,15,
+ 15,13,14,14,16,16,13,14,14,16,15,15,15,16,17,17,
+ 15,16,15,17,16,14,14,15,13,16,15,14,16,14,17,15,
+ 15,16,14,17,16,15,17,15,18,16,16,17,16,18,14,15,
+ 15,17,16,15,16,16,17,17,15,16,15,17,16,16,17,17,
+ 18,18,16,17,15,18,16,11,12,12,14,14,13,13,14,14,
+ 15,13,14,13,16,14,15,15,15,16,16,15,16,15,17,16,
+ 12,13,13,15,14,13,13,14,15,15,14,15,14,16,15,15,
+ 15,16,15,16,16,16,16,18,16,12,13,13,15,15,14,14,
+ 15,15,16,13,14,13,16,15,16,16,16,17,17,15,16,15,
+ 17,15,14,15,14,16,15,14,15,15,16,16,15,16,15,17,
+ 16,16,15,16,15,17,17,18,17,18,17,15,15,15,16,16,
+ 16,16,16,17,17,14,15,15,17,16,17,17,18,18,18,16,
+ 17,15,18,15, 9,11,11,13,13,11,12,12,14,14,11,12,
+ 12,14,14,13,14,14,15,16,13,14,14,15,15,11,12,12,
+ 14,14,12,13,13,14,15,12,13,13,14,14,14,14,15,15,
+ 16,14,14,14,16,16,11,12,12,14,14,12,13,13,14,15,
+ 11,13,12,14,14,13,14,14,16,16,13,14,14,16,15,13,
+ 14,14,15,15,14,14,15,15,16,14,15,14,16,16,15,15,
+ 16,16,17,15,16,16,17,17,12,13,13,15,15,13,14,14,
+ 16,15,12,14,13,16,15,15,16,15,17,17,14,15,15,17,
+ 15,10,12,12,14,14,12,12,13,14,15,12,13,12,14,14,
+ 14,14,15,15,16,13,14,14,16,16,12,13,13,14,14,13,
+ 13,14,14,15,13,14,13,15,15,14,15,15,15,17,14,15,
+ 15,16,16,11,12,12,14,14,13,13,14,15,15,12,13,13,
+ 15,14,14,15,15,16,17,14,15,14,16,15,14,14,14,16,
+ 16,14,15,15,16,16,15,15,15,16,16,15,16,16,16,18,
+ 16,17,16,18,17,13,13,14,15,15,14,14,15,16,16,13,
+ 14,14,16,15,16,16,17,17,17,15,15,15,17,15,10,12,
+ 12,14,13,12,12,13,14,14,11,13,12,14,14,13,14,14,
+ 16,16,13,14,14,16,15,12,12,13,14,14,12,13,13,14,
+ 15,13,13,13,15,15,14,14,15,16,16,14,15,15,16,16,
+ 11,12,12,14,14,12,13,13,15,15,12,13,12,15,14,14,
+ 15,14,16,16,13,15,13,16,15,13,14,14,15,16,14,15,
+ 15,15,17,14,15,15,16,16,16,15,16,16,17,16,16,16,
+ 17,17,13,14,12,16,13,14,15,13,16,15,13,15,13,16,
+ 14,15,16,15,17,16,15,16,14,17,15,11,12,12,14,15,
+ 13,13,14,14,16,13,14,13,15,14,15,15,16,16,17,15,
+ 15,15,16,16,12,13,13,15,15,13,13,14,15,16,14,15,
+ 14,16,15,15,15,16,15,17,16,16,16,17,17,12,13,13,
+ 14,15,14,14,15,15,16,13,14,13,15,15,16,16,16,17,
+ 17,15,16,15,16,15,15,15,15,16,16,14,15,15,16,17,
+ 16,16,16,17,17,16,15,17,15,18,17,18,17,18,18,14,
+ 14,15,15,17,15,15,16,16,17,14,15,15,16,16,17,17,
+ 17,17,18,16,16,15,17,15,11,12,12,14,14,12,13,13,
+ 15,15,12,13,13,15,15,14,15,15,16,16,14,15,14,17,
+ 16,13,13,13,15,15,13,14,14,15,16,13,14,14,16,16,
+ 15,15,16,16,17,15,16,16,17,17,12,13,13,15,14,13,
+ 14,14,16,15,13,14,13,16,14,15,16,16,17,16,15,16,
+ 14,17,15,14,15,15,16,17,15,15,16,16,17,15,16,16,
+ 17,17,16,15,17,16,18,16,17,17,18,18,14,15,14,16,
+ 13,15,16,15,17,14,15,16,14,17,14,16,17,16,18,16,
+ 16,17,15,18,15,
+};
+
+static const static_codebook _44p9_p5_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p9_p5_0,
+ 1, -528744448, 1616642048, 3, 0,
+ (long *)_vq_quantlist__44p9_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p5_1[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44p9_p5_1[] = {
+ 2, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _44p9_p5_1 = {
+ 1, 7,
+ (char *)_vq_lengthlist__44p9_p5_1,
+ 1, -533200896, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44p9_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p9_p6_0[] = {
+ 2, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 8, 9, 7,
+ 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 5, 7, 8, 8, 9,
+ 10, 8, 9,10, 8, 9,10,10,10,12,10,11,11, 8,10,10,
+ 10,11,12,10,11,10, 5, 8, 7, 8,10,10, 8,10, 9, 8,
+ 10,10,10,10,11,10,12,11, 8,10, 9,10,11,11,10,12,
+ 10, 5, 8, 8, 7, 9,10, 8,10, 9, 7, 9,10, 9,10,11,
+ 9,11,11, 8,10, 9,10,11,11, 9,11,10, 7, 9, 9, 9,
+ 10,11, 9,11,11, 9, 9,11,10,10,13,11,12,12, 9,11,
+ 11,11,12,13,11,13,11, 7, 9, 9, 9,10,11, 9,11,10,
+ 9,11,10,10,10,12,11,13,12, 9,11,11,11,12,12,10,
+ 12,10, 5, 8, 8, 8, 9,10, 7,10, 9, 8, 9,10, 9,10,
+ 11,10,11,11, 7,10, 9, 9,11,11, 9,11,10, 7, 9, 9,
+ 9,10,11, 9,11,10, 9,11,11,10,10,12,11,12,12, 9,
+ 10,11,11,12,13,10,12,10, 7, 9, 9, 9,11,11, 9,11,
+ 10, 9,11,11,11,11,13,11,13,12, 9,11, 9,11,12,12,
+ 10,13,10,
+};
+
+static const static_codebook _44p9_p6_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p9_p6_0,
+ 1, -527106048, 1620377600, 2, 0,
+ (long *)_vq_quantlist__44p9_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p6_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44p9_p6_1[] = {
+ 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 8, 7,
+ 8, 8, 7, 8, 7, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8,
+ 8, 8, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 9, 9, 8,
+ 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8,
+ 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8, 9, 8,
+ 8, 9, 8,
+};
+
+static const static_codebook _44p9_p6_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44p9_p6_1,
+ 1, -530841600, 1616642048, 2, 0,
+ (long *)_vq_quantlist__44p9_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p7_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p9_p7_0[] = {
+ 1,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,13,13,13,
+ 13,13,13,13,13,
+};
+
+static const static_codebook _44p9_p7_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p9_p7_0,
+ 1, -510105088, 1635281408, 3, 0,
+ (long *)_vq_quantlist__44p9_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p7_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44p9_p7_1[] = {
+ 1, 4, 4,16,16, 4, 9,11,15,16, 4,12, 8,16,16,12,
+ 16,16,16,16,13,16,16,16,16, 5, 8,10,16,16, 9, 9,
+ 14,15,16,12,14,14,16,16,16,16,16,16,16,16,16,16,
+ 16,16, 5,11, 8,16,15,12,14,16,16,16, 9,15, 9,16,
+ 16,16,16,16,16,16,16,16,16,16,16,15,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, 6,11,11,
+ 16,16,12,13,16,16,16,12,16,14,16,16,16,16,16,16,
+ 16,16,16,16,16,16,11,15,15,16,16,14,16,16,16,16,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,12,
+ 15,16,16,16,16,16,16,16,16,14,16,15,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, 5,11,11,16,16,12,
+ 15,16,16,16,12,16,14,16,16,16,16,16,16,16,16,16,
+ 16,16,16,12,15,15,16,16,14,16,16,16,16,16,16,16,
+ 16,16,16,16,16,16,16,16,16,16,16,16,11,15,15,16,
+ 16,16,16,16,16,16,15,16,14,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,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,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,
+ 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, 6,11,12,16,16,11,15,16,16,16,13,16,14,16,16,
+ 16,16,16,16,16,16,16,16,16,16,11,16,14,16,16,14,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+ 16,16,16,12,14,14,16,16,16,16,16,16,16,15,16,16,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+ 16,16,15,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, 8,13,
+ 15,16,16,15,15,16,16,16,14,16,16,16,16,16,16,16,
+ 16,16,16,16,16,16,16,14,16,16,16,16,16,16,16,16,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+ 15,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, 7,12,12,16,16,
+ 13,12,16,16,16,14,16,14,16,16,16,16,16,16,16,16,
+ 16,16,16,16,13,16,16,16,16,14,14,16,16,16,16,16,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,12,14,16,
+ 16,16,16,16,16,16,16,14,16,14,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,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,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,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, 6,11,11,16,16,13,15,16,16,16,11,15,14,16,
+ 16,16,16,16,16,16,14,16,16,16,16,11,16,16,16,16,
+ 16,16,16,16,16,15,16,16,16,16,16,16,16,16,16,16,
+ 16,16,16,16,11,16,14,16,16,14,16,16,16,16,13,15,
+ 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, 7,
+ 11,11,16,16,13,13,16,16,16,13,16,13,16,16,16,16,
+ 16,16,16,16,16,16,16,16,12,16,15,16,16,14,16,16,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+ 16,12,14,16,16,16,16,16,16,16,16,14,16,13,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, 8,13,14,16,
+ 16,15,16,16,16,16,14,16,16,16,16,16,16,16,16,16,
+ 16,16,16,16,16,15,16,16,16,16,16,16,16,16,16,16,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,15,16,
+ 15,16,16,16,16,16,16,16,16,16,15,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,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,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,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,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,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,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,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,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,
+ 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,16,16,16,
+ 16,16,16,16,15,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,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,15,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,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,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,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,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,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,
+};
+
+static const static_codebook _44p9_p7_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44p9_p7_1,
+ 1, -514619392, 1630767104, 3, 0,
+ (long *)_vq_quantlist__44p9_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p7_2[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p9_p7_2[] = {
+ 1, 3, 2, 5, 4, 7, 7, 8, 8, 9,10,10,10,11,11,11,
+ 12,12,12,13,13,13,13,13,13,
+};
+
+static const static_codebook _44p9_p7_2 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p9_p7_2,
+ 1, -518864896, 1620639744, 5, 0,
+ (long *)_vq_quantlist__44p9_p7_2,
+ 0
+};
+
+static const long _vq_quantlist__44p9_p7_3[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44p9_p7_3[] = {
+ 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44p9_p7_3 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44p9_p7_3,
+ 1, -529006592, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44p9_p7_3,
+ 0
+};
+
+static const char _huff_lengthlist__44p9_short[] = {
+ 3, 3, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _huff_book__44p9_short = {
+ 1, 8,
+ (char *)_huff_lengthlist__44p9_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_l0_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44pn1_l0_0[] = {
+ 1, 3, 3, 8, 8,10,10,10,10,10,10,10,10, 5, 7, 5,
+ 9, 8,10,10,10,10,11,10,11,10, 5, 5, 7, 8, 9,10,
+ 10,11,10,10,11,10,11,10,10,10,11,11,11,11,11,11,
+ 11,10,11,11,10,10,10,10,11,11,11,11,11,10,11,11,
+ 11,11,11,11,11,11,12,11,10,11,11,11,11,11,11,11,
+ 11,11,11,11,11,10,10,11,11,12,11,11,11,11,11,11,
+ 12,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,
+ 10,11,10,11,11,11,11,11,11,11,11,11,11,12,11,11,
+ 12,12,11,11,11,11,11,11,11,11,11,11,11,11,12,11,
+ 10,11,11,11,11,11,11,11,12,11,13,11,11,11,11,11,
+ 11,11,11,11,11,11,12,11,13,
+};
+
+static const static_codebook _44pn1_l0_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44pn1_l0_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44pn1_l0_0,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_l0_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44pn1_l0_1[] = {
+ 1, 4, 4, 7, 7, 4, 5, 6, 7, 7, 4, 6, 5, 7, 7, 7,
+ 6, 7, 6, 7, 7, 7, 6, 7, 6,
+};
+
+static const static_codebook _44pn1_l0_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44pn1_l0_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44pn1_l0_1,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_l1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44pn1_l1_0[] = {
+ 1, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+
+static const static_codebook _44pn1_l1_0 = {
+ 2, 9,
+ (char *)_vq_lengthlist__44pn1_l1_0,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44pn1_l1_0,
+ 0
+};
+
+static const char _huff_lengthlist__44pn1_lfe[] = {
+ 1, 3, 2, 3,
+};
+
+static const static_codebook _huff_book__44pn1_lfe = {
+ 2, 4,
+ (char *)_huff_lengthlist__44pn1_lfe,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44pn1_long[] = {
+ 2, 3, 6, 7, 9,13,17, 3, 2, 5, 7, 9,13,17, 6, 5,
+ 5, 6, 9,12,16, 7, 7, 6, 6, 7,10,13,10,10, 9, 7,
+ 6,10,13,13,13,12,10,10,11,15,17,17,17,14,14,15,
+ 17,
+};
+
+static const static_codebook _huff_book__44pn1_long = {
+ 2, 49,
+ (char *)_huff_lengthlist__44pn1_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44pn1_p1_0[] = {
+ 1, 2, 2, 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, 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,
+};
+
+static const static_codebook _44pn1_p1_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44pn1_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44pn1_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44pn1_p2_0[] = {
+ 1, 5, 5, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0,12,12, 0,
+ 8, 8, 0, 9, 9, 0,13,13, 0, 8, 8, 0, 6, 6, 0,11,
+ 11, 0,12,12, 0,12,12, 0,14,14, 0,11,12, 0,12,12,
+ 0,15,15, 0,12,12, 0, 5, 5, 0, 5, 5, 0, 6, 6, 0,
+ 7, 7, 0,10,10, 0, 6, 6, 0, 7, 7, 0,11,11, 0, 6,
+ 6, 0, 7, 7, 0,11,11, 0,12,11, 0,11,11, 0,14,14,
+ 0,10,10, 0,12,12, 0,15,15, 0,12,12, 0, 6, 6, 0,
+ 12,12, 0,12,12, 0,12,12, 0,14,14, 0,11,11, 0,12,
+ 12, 0,16,16, 0,12,12, 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, 8, 8, 0,12,12, 0,12,12, 0,12,12, 0,15,
+ 15, 0,12,12, 0,11,11, 0,16,16, 0,11,11, 0, 6, 6,
+ 0,12,12, 0,12,12, 0,13,13, 0,15,15, 0,12,12, 0,
+ 13,13, 0,15,15, 0,12,12, 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,
+};
+
+static const static_codebook _44pn1_p2_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44pn1_p2_0,
+ 1, -533200896, 1614282752, 2, 0,
+ (long *)_vq_quantlist__44pn1_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p2_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44pn1_p2_1[] = {
+ 1, 3, 3, 0, 9, 9, 0, 9, 9, 0,10,10, 0, 9, 9, 0,
+ 10,10, 0,10,10, 0,10,10, 0,10,10, 0, 7, 7, 0, 7,
+ 7, 0, 6, 6, 0, 8, 8, 0, 7, 7, 0, 8, 8, 0, 8, 8,
+ 0, 7, 7, 0, 8, 8, 0, 7, 7, 0, 9, 9, 0, 8, 9, 0,
+ 10,10, 0, 9, 9, 0,10,10, 0,10,11, 0, 9, 9, 0,10,
+ 10, 0, 9, 9, 0,11,11, 0,12,12, 0,12,12, 0,11,11,
+ 0,12,12, 0,13,13, 0,12,12, 0,13,13, 0, 8, 8, 0,
+ 12,12, 0,12,12, 0,13,13, 0,13,13, 0,13,13, 0,13,
+ 13, 0,13,13, 0,13,13, 0, 7, 7, 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, 9, 9, 0,11,11, 0,12,12, 0,13,13, 0,12,
+ 12, 0,13,13, 0,13,13, 0,12,12, 0,12,12, 0, 9, 9,
+ 0,12,12, 0,13,13, 0,14,14, 0,13,13, 0,14,14, 0,
+ 14,14, 0,13,13, 0,14,14, 0, 7, 7, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,
+};
+
+static const static_codebook _44pn1_p2_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44pn1_p2_1,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44pn1_p2_1,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p3_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44pn1_p3_0[] = {
+ 1, 6, 6, 6, 8, 8, 6, 8, 8, 7, 9, 9,10,11,11, 8,
+ 8, 8, 7, 9, 9,11,12,12, 9, 9, 9, 6, 7, 7,10,11,
+ 11,10,11,11,10,11,11,13,13,13,12,12,12,10,12,11,
+ 14,14,14,12,12,12, 6, 5, 5, 9, 6, 6, 9, 6, 6, 9,
+ 7, 7,12,10,10,11, 7, 6, 9, 7, 7,13,11,11,12, 7,
+ 7, 7, 8, 8,12,10,10,12,10,10,11,10,10,15,13,13,
+ 13, 9, 9,12,11,11,15,14,14,15,11,11, 8, 7, 7,12,
+ 11,11,12,11,11,11,11,11,14,13,14,14,12,12,12,11,
+ 11,16,15,15,14,12,12, 0,10,10, 0,12,12, 0,12,12,
+ 0,11,11, 0,14,14, 0,11,11, 0,11,11, 0,15,15, 0,
+ 11,11, 7, 8, 8,13,11,11,12,10,10,12,11,11,15,13,
+ 13,14,11,11,12,10,10,16,14,14,15,10,10, 9, 7, 7,
+ 13,11,12,13,12,11,12,11,11,15,14,14,14,12,12,13,
+ 12,12,16,15,15,15,12,12, 0,11,11, 0,12,12, 0,12,
+ 13, 0,12,12, 0,15,15, 0,12,12, 0,12,12, 0,16,15,
+ 0,12,12,
+};
+
+static const static_codebook _44pn1_p3_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44pn1_p3_0,
+ 1, -531365888, 1616117760, 2, 0,
+ (long *)_vq_quantlist__44pn1_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p3_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44pn1_p3_1[] = {
+ 2, 3, 4, 9, 9,10,12,12,12,11,10,12,12,13,12,11,
+ 13,12,11,11,11,12,12,12,11,11,13,13,13,13,11,12,
+ 12,14,14,12,13,13,13,13,11,13,13,13,13,11,13,13,
+ 13,13,11,13,13,13,13,11,12,12,14,14,12,13,13,12,
+ 12,11,13,13,13,13,11,13,13,12,12,11,13,13,13,13,
+ 12,12,13,14,14,12,13,13,12,12,11,13,13,13,13,11,
+ 13,13,12,12,11,13,13,13,13,12,13,13,14,14,12,13,
+ 13,12,12,11,13,13,13,13,11,13,13,12,12,11,10,10,
+ 10,10,12,10,10,11,11,12, 9, 9,11,11,13,11,11,10,
+ 10,13,10,10,10,10,13,11,11,12,12,13,10,10,12,12,
+ 14,12,11,12,12,13,11,11,11,12,13,12,12,12,12,13,
+ 11,11,12,12,13,10,10,12,12,14,11,11,12,12,13,11,
+ 11,12,12,13,11,11,12,12,14,12,12,12,12,14,10,10,
+ 11,11,14,12,11,11,11,13,11,11,11,11,13,12,12,11,
+ 11,14,12,12,12,11,14,10,10,11,11,14,12,11,11,11,
+ 13,11,11,11,11,13,12,12,11,11,11,11,11,10,10,12,
+ 10,11, 9, 9,12,12,12,11,11,13,12,12, 9, 9,13,13,
+ 13,10,10,13,13,13,12,12,13,13,13,14,14,13,12,12,
+ 11,11,14,13,13,12,12,14,13,13,11,11,13,13,13,12,
+ 11,13,13,13,14,14,13,12,12,10,10,14,13,13,11,11,
+ 13,13,13,10,10,13,13,13,11,11,14,13,13,14,14,14,
+ 12,12,10,10,13,13,13,11,11,13,13,13,10,10,13,13,
+ 13,11,11,14,13,13,14,14,14,13,13,10,10,13,13,13,
+ 11,11,13,13,13,10,10,14,12,12, 8, 8,14,12,12, 9,
+ 9,14,11,11, 9, 9,14,12,12, 8, 8,14,12,12, 7, 7,
+ 15,13,13,10,10,15,12,12,10,10,15,13,13,10,10,15,
+ 12,13, 9, 9,15,13,13,10,10,15,13,13,10,10,15,12,
+ 12,10,10,15,13,13,10,10,15,13,13, 9, 9,15,13,13,
+ 10,10,15,13,13,10,10,15,12,12,10,10,15,13,13, 9,
+ 9,14,13,12, 9, 9,14,13,13, 9, 9,15,13,13,10,10,
+ 15,12,12,10,10,15,13,13, 9, 9,15,13,13, 9, 9,14,
+ 13,13, 9, 9,14,12,12, 8, 8,13,13,13, 8, 8,14,14,
+ 13, 9, 9,14,14,13, 7, 7,14,14,14, 8, 8,14,14,14,
+ 10,10,15,14,14,12,12,14,14,14, 9, 9,15,14,14,10,
+ 10,14,14,14, 9, 9,14,14,14,10, 9,15,14,14,12,12,
+ 14,14,14, 9, 9,15,14,14,10,10,14,14,14, 9, 9,15,
+ 14,15, 9, 9,15,14,14,11,11,14,14,14, 8, 8,14,14,
+ 14, 9, 9,14,14,14, 8, 8,14,15,14,10,10,15,14,14,
+ 11,11,14,14,14, 8, 8,15,14,14, 9, 9,14,14,14, 8,
+ 8,12,12,12,13,13,16,16,15,12,12,17,16,16,13,13,
+ 17,16,16,11,11,17,16,16,12,12,17,16,17,13,13,17,
+ 16,16,14,14,17,17,16,12,12,18,16,16,13,13,17,16,
+ 17,12,12,17,17,17,13,13,18,16,16,14,14,18,17,17,
+ 12,12,17,17,17,13,13,18,17,17,13,13,17,17,17,13,
+ 13,17,16,16,14,14,17,17,17,12,12,16,16,17,13,13,
+ 17,17,16,12,12,18,17,17,13,13,18,16,16,14,14,18,
+ 17,17,12,12,19,16,17,13,13,17,16,17,12,12,13,14,
+ 14,10,10,16,14,14,13,13,17,15,15,14,14,17,14,14,
+ 13,13,16,14,14,13,13,17,16,15,14,14,16,16,16,15,
+ 15,17,15,15,14,14,17,15,15,14,14,17,15,15,14,14,
+ 17,16,15,14,14,16,16,16,15,15,18,15,15,13,13,16,
+ 16,15,14,14,17,15,15,14,13,17,15,15,14,14,16,16,
+ 16,15,15,18,15,14,13,13,17,15,15,14,14,18,14,15,
+ 13,13,18,15,15,14,14,16,16,16,15,15,17,15,15,13,
+ 13,17,15,15,14,14,17,15,15,13,13,13,11,11,10,10,
+ 16,14,14,13,13,17,14,15,14,14,17,15,15,12,12,17,
+ 14,14,12,12,16,15,15,14,14,16,14,14,14,14,16,15,
+ 15,14,14,16,15,15,14,14,16,15,15,14,14,16,15,15,
+ 14,14,16,15,14,15,15,17,15,15,14,14,17,15,15,14,
+ 14,17,15,15,14,14,17,15,16,14,14,16,14,14,14,14,
+ 17,15,15,13,13,17,15,15,13,13,16,15,15,13,13,17,
+ 16,16,14,14,17,15,14,15,14,17,15,15,13,13,17,15,
+ 15,13,13,17,15,15,13,13,14,14,14, 9, 9,14,14,14,
+ 18,19,14,15,15,19,18,14,14,14,19,19,15,14,14,19,
+ 19,15,16,16,19,19,15,16,16,19,19,15,15,15,19,19,
+ 15,16,16,19,20,15,15,15,19,19,15,15,15,19,19,15,
+ 16,16,20,20,15,15,15,18,19,15,15,16,19,20,15,15,
+ 15,19,18,15,15,15,18,18,15,16,16,21,20,15,15,15,
+ 19,19,15,15,15,19,19,15,15,14,19,20,15,15,15,20,
+ 19,15,16,16,19,20,15,15,15,19,19,15,15,15,20,21,
+ 15,14,15,19,19,14,12,12, 9, 9,14,14,15,21,19,14,
+ 14,14,18,19,14,15,15,19,20,14,14,14,19,19,15,15,
+ 15,19,20,15,15,14,21,19,15,15,15,20,19,15,14,15,
+ 20,21,15,15,15,18,18,15,15,15,20,21,16,14,14,18,
+ 19,15,15,15,20,19,15,15,15,18,21,15,15,15,19,19,
+ 15,15,15,19,20,16,15,14,20,19,15,16,15,19,19,15,
+ 15,15,19, 0,14,15,15,19,19,15,15,15,19,19,15,15,
+ 14,20,19,15,15,15,20,19,15,15,15,19,19,15,15,15,
+ 20,19,12,12,12,13,13,16,15,16,11,11,16,16,16,12,
+ 12,17,16,16,11,11,17,16,16,12,11,17,17,17,13,13,
+ 18,16,16,14,14,18,18,17,13,13,17,16,16,13,13,17,
+ 17,17,13,13,17,16,17,12,12,17,15,16,13,13,17,16,
+ 17,12,12,17,16,16,13,12,17,16,16,12,12,18,17,17,
+ 13,13,18,16,16,13,14,18,17,17,12,12,17,16,16,12,
+ 12,17,17,17,12,12,18,17,17,13,13,17,16,16,14,14,
+ 17,17,17,12,12,17,16,16,12,12,18,17,17,12,12,13,
+ 14,14, 9, 9,16,14,14,13,13,16,15,15,14,14,16,14,
+ 14,13,13,16,14,14,13,13,17,16,15,15,15,16,15,16,
+ 16,15,17,15,15,14,14,17,15,15,15,15,17,15,15,14,
+ 14,17,15,15,14,14,16,15,16,16,16,17,15,15,14,14,
+ 16,15,15,14,15,16,15,15,14,14,17,15,15,15,15,16,
+ 16,16,15,16,18,15,14,13,14,17,15,15,14,14,17,14,
+ 14,13,13,17,15,15,14,14,16,15,15,15,15,17,15,14,
+ 14,14,17,15,15,14,14,17,14,14,13,13,13,11,11,11,
+ 11,16,14,14,12,12,16,14,14,13,13,16,14,14,12,12,
+ 16,14,14,12,12,16,15,15,13,13,17,14,14,14,14,17,
+ 15,15,13,13,16,15,15,14,13,16,15,15,13,13,16,15,
+ 15,13,13,16,14,14,14,14,16,15,15,13,13,16,14,15,
+ 13,13,17,15,15,13,13,17,15,15,13,13,16,14,14,14,
+ 14,17,15,15,12,12,17,14,15,13,13,17,15,15,12,12,
+ 16,15,15,13,13,17,14,14,14,14,17,15,15,12,12,17,
+ 15,15,13,13,16,15,15,12,12,14,15,15, 8, 8,14,14,
+ 14,19,18,14,15,15,19,20,14,14,14,19,19,14,14,15,
+ 19,20,15,16,15,19,21,15,16,16,21,19,15,15,15,20,
+ 19,15,16,16,19,20,15,15,15,19,18,15,16,15,20,19,
+ 15,16,16,19,20,15,15,15,19,19,15,16,15,20,20,14,
+ 15,15,19,19,15,15,15,21,19,15,17,16,19,20,15,14,
+ 15, 0,21,15,15,15,19,20,14,14,14,19,19,15,15,15,
+ 20,19,15,16,16,19,19,15,15,15,19,18,15,15,15,20,
+ 19,14,14,15,18,18,14,12,12, 9, 9,14,14,14,18,18,
+ 14,14,14,18,18,14,15,14,19,18,14,14,14,19,18,15,
+ 15,15,19,20,15,14,14,18,18,15,15,15,20,19,15,15,
+ 15,18,20,15,15,15,19,18,15,15,15,19,19,15,14,14,
+ 19,21,15,15,15,20,20,15,15,15,18,19,14,15,15,19,
+ 20,15,15,15,20,19,15,14,14,19,21,15,15,15,18,19,
+ 15,14,15,20,19,14,15,15,21,21,14,15,15,19,20,15,
+ 14,14,19,20,15,15,15,19,20,15,15,14,20,20,14,15,
+ 15,20,19,13,12,12,13,13,17,16,16,11,11,17,16,16,
+ 12,12,18,17,16,11,11,18,16,16,11,11,17,17,17,13,
+ 13,18,16,16,13,13,18,17,17,12,12,18,16,16,13,13,
+ 18,17,17,12,12,18,17,17,13,13,18,16,16,14,14,18,
+ 16,17,12,12,18,17,17,13,13,17,17,17,12,12,17,17,
+ 17,12,12,17,16,15,13,13,18,16,16,11,11,17,16,16,
+ 12,12,17,16,17,11,11,18,17,17,13,12,17,16,16,13,
+ 13,17,17,17,12,12,17,16,17,12,12,18,17,17,11,11,
+ 14,14,14, 9, 9,16,14,14,13,13,17,15,15,14,14,17,
+ 14,14,13,13,16,14,14,13,13,17,15,15,14,14,16,16,
+ 16,16,15,18,15,15,14,14,17,16,15,15,15,17,15,15,
+ 14,14,17,15,15,14,15,16,16,16,15,16,18,15,15,14,
+ 14,17,15,15,14,15,17,15,15,14,14,17,15,15,14,14,
+ 16,16,16,15,16,17,14,14,13,13,17,15,15,14,14,18,
+ 15,15,13,13,17,15,15,14,14,16,16,16,15,15,17,14,
+ 14,13,13,17,15,15,14,14,17,14,14,13,13,13,11,11,
+ 11,11,16,14,14,12,12,16,14,14,12,13,17,15,14,11,
+ 11,17,14,14,11,11,17,15,15,13,14,17,14,14,14,14,
+ 17,15,15,13,13,17,14,14,13,13,17,15,15,13,13,17,
+ 15,15,13,13,17,14,14,14,14,17,15,15,13,13,18,14,
+ 15,13,13,17,15,15,13,13,16,15,15,13,13,17,14,14,
+ 13,13,17,15,15,12,12,16,14,14,12,12,16,15,15,12,
+ 12,17,16,15,13,13,17,14,14,13,13,17,15,15,12,12,
+ 16,15,15,12,12,16,15,15,12,12,13,15,15, 8, 8,14,
+ 14,14,18,19,14,15,15,19,20,14,14,14,18,18,14,15,
+ 15,18,18,15,16,16,19,19,15,16,17,20,20,15,15,15,
+ 19,19,15,16,16,18,20,15,15,15,19,19,15,15,16,18,
+ 18,15,17,16,19,19,15,15,15,18,21,15,16,16,21,20,
+ 15,15,15,19,21,15,16,15,20,19,15,16,17,20,20,15,
+ 15,15,19,19,15,16,16,21,20,15,15,15,19,20,15,15,
+ 15,19,19,15,16,16,20,19,15,15,15,19,19,15,16,15,
+ 20,21,15,15,15,21,19,14,12,12, 8, 8,14,14,14,20,
+ 18,14,13,13,19,19,14,14,14,19,18,15,14,14,19,20,
+ 14,15,15,20,20,15,14,14,21,20,15,15,15,20,20,15,
+ 15,14,21,19,15,15,15,19,19,15,15,15,19,20,15,14,
+ 14,20,20,15,15,15,19,20,15,14,14,19,20,15,15,15,
+ 20,20,15,15,15,20,19,15,14,14,20,21,15,15,15,20,
+ 21,15,14,14,20, 0,15,16,15,20,21,15,15,15,19,20,
+ 15,14,14,19,19,15,15,15,19,20,15,15,15,19,19,15,
+ 15,15,18,20,13,12,12,13,13,18,16,17,12,12,17,16,
+ 16,12,12,17,17,16,11,11,18,16,16,11,11,17,17,18,
+ 13,13,18,16,16,14,14,18,17,17,13,13,18,16,16,13,
+ 13,18,17,17,12,12,17,17,16,13,13,17,16,16,13,14,
+ 18,17,17,12,12,18,16,16,12,13,17,16,17,12,12,17,
+ 18,17,13,13,18,16,16,13,13,18,17,17,12,12,17,16,
+ 16,12,12,17,17,17,11,11,17,16,17,12,12,17,16,16,
+ 13,13,17,16,16,11,11,17,16,16,12,12,18,16,17,11,
+ 11,14,14,14, 9, 9,16,14,15,13,13,17,15,15,14,14,
+ 17,14,14,12,12,16,14,14,13,13,18,15,15,15,15,17,
+ 15,16,15,16,18,15,15,14,14,17,15,16,15,15,17,15,
+ 15,14,14,18,15,15,14,14,16,16,16,16,15,17,15,15,
+ 14,14,16,15,15,14,14,17,15,15,14,14,17,15,15,14,
+ 14,17,16,16,15,15,17,15,14,13,13,17,15,15,14,14,
+ 17,15,15,13,13,17,15,15,14,14,16,16,16,15,15,18,
+ 15,14,14,14,17,15,15,14,14,18,15,15,13,13,13,12,
+ 12,11,11,16,14,14,12,12,16,14,14,13,13,17,15,15,
+ 12,12,17,14,14,12,12,17,15,15,14,14,17,14,14,14,
+ 14,17,15,15,13,13,17,15,14,13,13,17,15,15,13,13,
+ 17,15,15,13,13,16,14,14,14,14,17,15,15,13,13,16,
+ 14,14,13,13,16,15,15,13,13,17,15,16,13,13,17,14,
+ 14,14,13,17,15,15,12,12,16,15,14,12,12,17,15,15,
+ 12,12,16,15,16,13,13,16,14,14,14,13,17,15,15,12,
+ 12,16,14,14,12,12,17,15,15,12,12,14,15,15, 8, 8,
+ 14,14,14,18,18,14,15,15,19,18,14,14,14,18,18,14,
+ 15,15,19,20,15,16,15,21,18,15,16,16,18, 0,15,15,
+ 15,19,20,15,16,16,20, 0,15,16,15,19,18,15,15,15,
+ 19,19,15,16,16,21,19,15,15,15,19,19,15,16,16,20,
+ 20,15,15,15,19,19,15,15,15,19,18,15,16,16,20,20,
+ 15,14,15,20,19,15,15,15,19,20,15,15,15,19,19,15,
+ 16,15,19,20,15,16,16,19,20,15,15,15,19,19,15,16,
+ 15,20,20,15,15,15,20,18,13,12,12, 8, 8,14,14,14,
+ 19,20,14,14,14,19,19,14,15,15,20,20,14,14,14,18,
+ 19,15,15,15,20, 0,15,14,14,18,20,15,15,15,19,19,
+ 15,15,15,21,19,15,15,15,19,20,15,15,15,20,21,15,
+ 14,14,20,19,15,15,15,20,19,15,15,14,21,19,15,15,
+ 15,19,18,15,15,15,20,19,15,14,14,19,19,15,15,16,
+ 20,19,15,15,15,20, 0,15,15,15,19,21,15,15,15,22,
+ 20,15,14,14,22,19,15,15,15,19,20,15,14,14,20,19,
+ 14,15,15,19,21,
+};
+
+static const static_codebook _44pn1_p3_1 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44pn1_p3_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44pn1_p3_1,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44pn1_p4_0[] = {
+ 1, 7, 7,14,14, 6, 8, 8,15,16, 7, 8, 8,16,15, 0,
+ 14,14,17,17, 0,14,14,16,16, 7, 9, 9,16,16,10,11,
+ 11,17,18, 9, 8, 8,16,16, 0,14,14,19,19, 0,14,14,
+ 17,16, 8, 9, 9,16,16,12,12,12,17,17,10, 9, 9,16,
+ 16, 0,15,14,18,20, 0,14,14,17,17, 0,15,15,18,17,
+ 0,21, 0, 0,21, 0,13,13,17,17, 0,17,17, 0, 0, 0,
+ 15,15,17,17, 0,15,15,17,18, 0, 0, 0, 0,21, 0,13,
+ 13,17,17, 0,18,18, 0,21, 0,16,15,17,18, 6, 7, 7,
+ 14,14, 9,10,10,16,16,11,10,10,15,15, 0,21, 0,20,
+ 21, 0, 0, 0,18,20,10,10,10,15,16,12,13,13,18,18,
+ 12,11,11,15,15, 0, 0, 0,20,20, 0, 0,21,19,19,12,
+ 11,11,15,15,15,14,14,18,18,13,11,11,15,16, 0, 0,
+ 0,20,19, 0, 0, 0,20,21, 0, 0,20,19,19, 0, 0, 0,
+ 0, 0, 0,20, 0,17,18, 0, 0,21, 0, 0, 0, 0, 0,21,
+ 0, 0,21, 0,20,19, 0, 0, 0, 0, 0, 0,21, 0,18,18,
+ 0, 0, 0,21, 0, 0, 0, 0, 0,20, 7, 6, 6,13,13, 9,
+ 6, 6,12,12, 9, 7, 7,14,14, 0,10,10,12,12, 0,11,
+ 11,15,15, 9, 7, 7,14,14,12, 9, 9,14,14,10, 7, 7,
+ 14,13, 0,11,11,16,15, 0,11,11,14,14, 9, 7, 7,14,
+ 14,13,10,10,14,14,11, 7, 7,14,13, 0,11,11,16,16,
+ 0,11,11,14,14, 0,12,12,16,16, 0,19, 0,17,18, 0,
+ 10,10,14,14, 0,15,14, 0, 0, 0,12,12,14,14, 0,12,
+ 12,15,15, 0,20, 0,18,19, 0,10,10,14,14, 0,16,15,
+ 0,20, 0,13,13,14,14, 0,11,11,13,13, 0,12,13,16,
+ 16, 0,12,12,16,16, 0,16,16, 0,21, 0,17,18, 0, 0,
+ 0,12,12,16,16, 0,15,15,18, 0, 0,12,12,16,16, 0,
+ 17,16,21,21, 0,16,17, 0, 0, 0,13,13,17,16, 0,16,
+ 16,20,21, 0,12,12,17,16, 0,17,17, 0,21, 0,17,17,
+ 21,21, 0,17,18, 0, 0, 0, 0, 0, 0, 0, 0,15,15, 0,
+ 0, 0,18,21, 0, 0, 0,18,19, 0, 0, 0,18,17,21,21,
+ 0, 0, 0, 0, 0, 0,16,16, 0, 0, 0, 0, 0, 0, 0, 0,
+ 19,19, 0, 0, 0,11,11,12,12, 0,11,11,10,10, 0,12,
+ 12,13,13, 0,12,12, 9, 9, 0,14,14,13,13, 0,12,12,
+ 13,13, 0,14,14,12,13, 0,11,11,12,12, 0,13,13,13,
+ 13, 0,13,13,13,13, 0,12,12,13,13, 0,14,14,12,12,
+ 0,11,11,12,12, 0,14,13,14,14, 0,13,13,13,13, 0,
+ 15,15,14,15, 0, 0, 0,16,16, 0,12,12,13,13, 0,16,
+ 17,20,21, 0,14,13,12,12, 0,14,14,14,14, 0,21, 0,
+ 16,16, 0,12,12,13,13, 0,18,17,21, 0, 0,14,14,13,
+ 13, 7, 8, 8,17,17,11,10,10,18,18,12,10,10,17,17,
+ 0,15,15,20,18, 0,15,15,17,17,11, 9, 9,17,17,14,
+ 12,12,19,19,13, 9, 9,16,16, 0,15,14, 0,19, 0,14,
+ 14,16,16,12,10,10,20,18,16,13,13,21,20,14,10,10,
+ 17,17, 0,15,15,21,20, 0,15,14,17,17, 0,15,15,21,
+ 21, 0, 0,21, 0, 0, 0,13,13,18,18, 0,19,16, 0, 0,
+ 0,15,15,17,16, 0,16,16, 0,21, 0, 0, 0, 0,21, 0,
+ 13,14,18,17, 0,20,19, 0, 0, 0,15,15,18,18, 8, 7,
+ 7,15,15,12,11,11,17,16,13,11,11,16,16, 0, 0, 0,
+ 21,20, 0, 0, 0, 0,20,11,10,10,17,17,14,13,13,19,
+ 18,14,11,11,16,16, 0,20, 0,21,19, 0, 0,21, 0,20,
+ 12,11,11,17,17,16,15,15, 0,19,14,11,11,17,16, 0,
+ 21, 0, 0,19, 0, 0, 0,21,20, 0, 0,21,20, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,19,21, 0, 0, 0, 0, 0, 0, 0, 0,
+ 19,20, 0, 0, 0,20,21, 0, 0, 0, 0, 0, 0,20, 0,19,
+ 21, 0, 0, 0, 0, 0, 0, 0, 0,21,20,11,10, 9,15,15,
+ 14,11,11,15,15,14,11,11,16,16, 0,14,14,14,14, 0,
+ 16,15,17,16,13,11,11,16,16,16,13,13,16,16,15,10,
+ 10,15,15, 0,14,15,17,17, 0,14,14,16,15,13,11,11,
+ 16,16,17,15,14,16,16,15,10,10,15,15, 0,15,15,17,
+ 18, 0,15,15,16,16, 0,16,16,17,17, 0,21, 0,21,20,
+ 0,13,13,15,15, 0,18,18, 0,21, 0,15,15,15,15, 0,
+ 16,16,17,17, 0, 0, 0, 0,18, 0,13,13,15,15, 0,19,
+ 18, 0, 0, 0,15,15,16,16, 0,12,12,15,15, 0,13,13,
+ 17,17, 0,13,13,17,18, 0,16,17,21, 0, 0,20,18, 0,
+ 0, 0,13,13,17,17, 0,15,15, 0,18, 0,12,12,17,18,
+ 0,16,16, 0, 0, 0,17,17,21, 0, 0,13,13,18,18, 0,
+ 16,16,21,21, 0,12,12,17,18, 0,16,17,21, 0, 0,17,
+ 17, 0,21, 0,17,18, 0, 0, 0, 0, 0, 0, 0, 0,16,15,
+ 0,21, 0,21,19, 0, 0, 0,18,18, 0, 0, 0,18,19, 0,
+ 0, 0, 0, 0, 0, 0, 0,16,16,21,21, 0,20,19, 0, 0,
+ 0,19,21, 0,21, 0,12,12,15,15, 0,12,12,15,16, 0,
+ 13,13,16,16, 0,14,14,15,15, 0,16,15,17,17, 0,13,
+ 13,17,17, 0,15,15,16,18, 0,12,12,16,16, 0,14,14,
+ 17,17, 0,15,14,16,16, 0,13,13,16,16, 0,16,15,17,
+ 17, 0,12,12,16,16, 0,15,15,18,18, 0,14,14,17,16,
+ 0,16,16,17,18, 0, 0, 0,20,21, 0,13,13,16,17, 0,
+ 17,17, 0, 0, 0,15,15,16,16, 0,15,16,17,17, 0, 0,
+ 0,19, 0, 0,13,13,15,16, 0,19,18, 0, 0, 0,16,15,
+ 16,17, 8, 8, 8,17,17,13,11,10,17,18,13,10,10,17,
+ 17, 0,15,15,20,19, 0,15,15,17,17,12,10,10,19,18,
+ 15,12,12,20,18,14,10,10,17,16, 0,15,15,20,20, 0,
+ 14,15,16,16,13,10,10,17,17,17,14,14, 0,18,15,10,
+ 10,17,17, 0,16,15,20,20, 0,14,14,17,17, 0,15,16,
+ 20,20, 0, 0,21, 0, 0, 0,13,13,17,17, 0,18,17, 0,
+ 0, 0,15,16,17,18, 0,15,15,18,21, 0, 0, 0,21, 0,
+ 0,13,13,18,18, 0,19,19, 0, 0, 0,16,16,18,17, 9,
+ 8, 8,15,15,12,11,11,16,16,13,11,11,16,15, 0, 0,
+ 0, 0,21, 0,21, 0,19,19,12,11,11,17,18,15,13,13,
+ 18,19,14,11,11,16,16, 0, 0,21,21,19, 0, 0, 0,21,
+ 20,13,11,11,18,17,17,14,15,20,21,15,11,12,16,16,
+ 0, 0, 0,20, 0, 0, 0,21, 0,19, 0, 0, 0, 0,19, 0,
+ 0, 0, 0, 0, 0,21,21,19,19, 0, 0, 0,21, 0, 0, 0,
+ 0,19,21, 0, 0, 0,19,20, 0, 0, 0,21, 0, 0, 0,21,
+ 19,19, 0, 0, 0, 0, 0, 0, 0, 0,21,20, 0,11,11,15,
+ 15, 0,12,12,15,16, 0,12,12,16,16, 0,15,15,16,15,
+ 0,16,16,17,17, 0,12,12,17,17, 0,14,14,17,17, 0,
+ 11,11,16,16, 0,15,15,19,18, 0,15,15,16,16, 0,12,
+ 12,17,16, 0,14,15,16,16, 0,11,11,15,15, 0,16,16,
+ 18,19, 0,15,15,15,16, 0,17,17,18,20, 0,21, 0,21,
+ 19, 0,14,14,16,16, 0,18,18, 0, 0, 0,16,16,15,15,
+ 0,16,16,18,17, 0, 0, 0,19,20, 0,14,14,16,16, 0,
+ 19,19, 0, 0, 0,16,17,15,15, 0,12,12,14,15, 0,13,
+ 13,16,17, 0,12,12,17,17, 0,17,16, 0, 0, 0,18,17,
+ 21, 0, 0,13,13,19,17, 0,15,15,20,21, 0,12,12,17,
+ 17, 0,17,17, 0, 0, 0,17,17, 0, 0, 0,13,13,17,18,
+ 0,16,16,21, 0, 0,12,12,17,17, 0,17,17, 0, 0, 0,
+ 17,17, 0, 0, 0,18,21, 0, 0, 0, 0, 0, 0, 0, 0,15,
+ 15,21, 0, 0,20,21, 0, 0, 0,18,19, 0, 0, 0,18,17,
+ 0, 0, 0, 0, 0, 0, 0, 0,16,16,21, 0, 0,21,21, 0,
+ 0, 0,18,19, 0, 0, 0,12,12,16,16, 0,13,13,16,17,
+ 0,13,13,17,16, 0,14,14,16,16, 0,16,15,19,18, 0,
+ 13,13,17,17, 0,15,15,18,18, 0,12,12,16,16, 0,15,
+ 15,18,19, 0,15,15,17,16, 0,13,13,17,17, 0,16,16,
+ 18,17, 0,12,12,17,16, 0,15,15,18,18, 0,15,15,17,
+ 17, 0,16,16, 0,19, 0, 0, 0, 0, 0, 0,14,14,16,17,
+ 0,18,18, 0, 0, 0,15,15,17,17, 0,16,16,21,19, 0,
+ 21, 0,21,21, 0,13,14,16,16, 0,19,19, 0, 0, 0,15,
+ 16,16,16, 0,11,11,17,16, 0,15,14,19,18, 0,14,14,
+ 19,19, 0,18,17,18,20, 0,17,17,18,19, 0,13,13,17,
+ 17, 0,16,17,21,18, 0,13,13,17,16, 0,18,17,19, 0,
+ 0,16,17,18,18, 0,12,12,19,18, 0,18,18,20,20, 0,
+ 13,13,17,17, 0,17,17,21, 0, 0,16,17,17,18, 0,18,
+ 17,19,18, 0, 0, 0, 0, 0, 0,14,14,17,17, 0,19,19,
+ 21, 0, 0,16,16,16,17, 0,17,17,19,20, 0, 0, 0, 0,
+ 21, 0,15,15,17,18, 0,21,21, 0, 0, 0,17,17,17,18,
+ 0,10,10,15,15, 0,15,14,17,18, 0,14,14,16,16, 0,
+ 0, 0,18, 0, 0,21, 0,19, 0, 0,13,13,17,16, 0,17,
+ 17,18, 0, 0,14,14,16,15, 0, 0, 0,21, 0, 0,21, 0,
+ 19,18, 0,13,13,17,17, 0,18,18,20,20, 0,15,15,16,
+ 16, 0, 0, 0,21,21, 0, 0, 0,20,20, 0, 0, 0,19, 0,
+ 0, 0, 0, 0, 0, 0,21,20,18,18, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,20, 0, 0, 0, 0,20, 0, 0, 0, 0, 0, 0, 0,
+ 0,19,18, 0, 0, 0, 0,21, 0, 0, 0,18,20, 0,18,19,
+ 16,17, 0,21,19,17,17, 0, 0,21,18,18, 0, 0,21,20,
+ 19, 0, 0, 0,20,20, 0, 0,21,17,17, 0, 0, 0,19,19,
+ 0,20,20,17,17, 0, 0, 0, 0,20, 0, 0,20,18,18, 0,
+ 21,20,17,17, 0, 0, 0,20,21, 0,19, 0,17,17, 0, 0,
+ 21, 0, 0, 0,20, 0,18,19, 0, 0, 0,21,21, 0, 0, 0,
+ 0,21, 0,20,20,17,17, 0, 0, 0, 0, 0, 0,21, 0,18,
+ 17, 0, 0, 0,20,19, 0, 0, 0, 0,21, 0,20,20,17,17,
+ 0, 0, 0, 0, 0, 0,21,21,18,18, 0,12,12,15,14, 0,
+ 14,14,17,17, 0,14,14,17,16, 0,18,18,21, 0, 0,19,
+ 20, 0, 0, 0,13,13,18,17, 0,16,16,19,18, 0,13,13,
+ 17,17, 0,17,17, 0, 0, 0,17,17,21, 0, 0,13,13,17,
+ 17, 0,17,17,21,20, 0,13,13,18,17, 0,18,19,21,21,
+ 0,19,18, 0, 0, 0,18,17, 0, 0, 0, 0, 0, 0, 0, 0,
+ 15,16, 0, 0, 0,21,21, 0, 0, 0,20,18,21, 0, 0,17,
+ 18, 0, 0, 0, 0, 0, 0, 0, 0,15,16, 0, 0, 0, 0,20,
+ 0, 0, 0, 0,19, 0, 0, 0,15,15,18,19, 0,18,17,21,
+ 0, 0,16,18, 0,20, 0,17,18,21, 0, 0,18,20, 0, 0,
+ 0,16,16,21,21, 0,19,20,21, 0, 0,16,15, 0,21, 0,
+ 18,20, 0, 0, 0,18,19, 0, 0, 0,16,15,21,21, 0,21,
+ 0, 0, 0, 0,16,15,21, 0, 0,20,19, 0, 0, 0,18,21,
+ 21, 0, 0,20,18, 0, 0, 0, 0, 0, 0, 0, 0,16,16, 0,
+ 20, 0,21, 0, 0, 0, 0,17,18,20,21, 0,18,18,21,21,
+ 0, 0, 0, 0, 0, 0,16,16,20, 0, 0, 0,21, 0, 0, 0,
+ 21,18, 0, 0, 0,12,12,20,17, 0,15,15,19,18, 0,14,
+ 14,19,18, 0,18,17,21,19, 0,17,17,21,17, 0,13,13,
+ 21,19, 0,16,17,20,19, 0,13,13,16,16, 0,17,17,20,
+ 21, 0,16,16,19,17, 0,13,13,18,18, 0,17,19,19,19,
+ 0,13,13,17,17, 0,18,18, 0,19, 0,16,17,18,18, 0,
+ 16,17,19,21, 0, 0, 0, 0, 0, 0,15,15,16,17, 0,20,
+ 19,21, 0, 0,17,17,17,17, 0,17,17,21,19, 0, 0, 0,
+ 0, 0, 0,15,15,17,17, 0,21, 0, 0, 0, 0,18,18,17,
+ 17, 0,10,10,15,15, 0,15,15,17,17, 0,15,14,16,16,
+ 0, 0, 0,21,19, 0,21,21,19,21, 0,13,13,17,16, 0,
+ 17,17,18,19, 0,14,15,16,15, 0, 0, 0,21,19, 0,21,
+ 21,18,19, 0,14,14,16,17, 0,18,18,18,19, 0,15,15,
+ 15,16, 0, 0,21, 0,21, 0, 0, 0,19,20, 0, 0, 0,21,
+ 19, 0, 0, 0, 0, 0, 0,21,21,19,17, 0, 0, 0, 0, 0,
+ 0, 0, 0,21,21, 0,21, 0, 0,21, 0, 0, 0, 0, 0, 0,
+ 21,21,19,18, 0, 0, 0, 0, 0, 0, 0, 0, 0,19, 0,21,
+ 18,18,17, 0,21, 0,20,20, 0, 0, 0,18,20, 0, 0,21,
+ 18,21, 0, 0, 0,21,18, 0, 0, 0, 0,19, 0, 0, 0,21,
+ 21, 0,20,21,17,19, 0,21, 0,21, 0, 0,21, 0,18,18,
+ 0,20,21,17,18, 0, 0, 0,21,19, 0,20,21,17,18, 0,
+ 0, 0,21,21, 0, 0, 0,20,19, 0, 0, 0,21,21, 0, 0,
+ 0, 0, 0, 0,21,21,19,18, 0, 0, 0, 0, 0, 0, 0,21,
+ 19,18, 0,21,21,19, 0, 0, 0, 0,21, 0, 0,21,21,18,
+ 17, 0, 0, 0, 0, 0, 0,21, 0,21,18, 0,12,12,14,14,
+ 0,15,14,17,17, 0,14,14,17,16, 0,19,17, 0, 0, 0,
+ 19,19, 0, 0, 0,13,13,17,17, 0,17,17,20,20, 0,13,
+ 13,18,18, 0,18,17, 0, 0, 0,18,21, 0, 0, 0,13,13,
+ 17,17, 0,18,18,21,20, 0,14,14,18,19, 0,19,18,21,
+ 0, 0,19,19, 0, 0, 0,20,18,20, 0, 0, 0, 0, 0, 0,
+ 0,15,16, 0, 0, 0,21,21, 0, 0, 0,19,19, 0, 0, 0,
+ 18,18, 0, 0, 0, 0, 0, 0, 0, 0,16,16, 0,21, 0, 0,
+ 0, 0, 0, 0,19,20, 0, 0, 0,15,15,20,21, 0,17,17,
+ 21,21, 0,17,17, 0, 0, 0,19,18, 0, 0, 0,18,19, 0,
+ 0, 0,17,16, 0,21, 0, 0,20, 0, 0, 0,16,16, 0,20,
+ 0,19,19, 0,21, 0,19,18, 0,21, 0,16,16, 0, 0, 0,
+ 21,21, 0, 0, 0,16,16, 0, 0, 0,21,21, 0, 0, 0,19,
+ 19, 0, 0, 0,20, 0, 0, 0, 0, 0, 0, 0, 0, 0,17,17,
+ 0,21, 0, 0,20, 0, 0, 0,20,18,21,21, 0,19,18, 0,
+ 20, 0, 0, 0, 0, 0, 0,16,17,21, 0, 0, 0,21, 0, 0,
+ 0,19,20,21,20,
+};
+
+static const static_codebook _44pn1_p4_0 = {
+ 5, 3125,
+ (char *)_vq_lengthlist__44pn1_p4_0,
+ 1, -528744448, 1616642048, 3, 0,
+ (long *)_vq_quantlist__44pn1_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p4_1[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44pn1_p4_1[] = {
+ 2, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _44pn1_p4_1 = {
+ 1, 7,
+ (char *)_vq_lengthlist__44pn1_p4_1,
+ 1, -533200896, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44pn1_p4_1,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p5_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44pn1_p5_0[] = {
+ 1, 7, 7, 6, 8, 8, 7, 8, 8, 7, 9, 9,11,11,11, 9,
+ 8, 8, 7, 9, 9,11,12,11, 9, 9, 9, 6, 7, 7,10,11,
+ 11,10,10,10,10,11,11,15,14,14,12,12,12,11,11,11,
+ 14,14,14,12,12,12, 5, 6, 6, 8, 5, 5, 8, 7, 7, 8,
+ 8, 8,12,10,10,10, 7, 7, 8, 7, 7,12,10,10,10, 7,
+ 7, 6, 7, 7,12,11,11,12,10,10,11,10,10,14,14,13,
+ 13,10,10,11,10,10,16,14,14,14,11,10, 7, 7, 7,13,
+ 12,12,12,12,11,11,11,11,15,14,17,13,12,12,12,11,
+ 11,15,15,15,14,13,13,10, 9, 9,14,12,11,13,11,11,
+ 12,11,11,16,15,14,14,11,11,12,11,11,17,14,14,15,
+ 11,11, 7, 8, 8,12,11,11,13,10,10,11,10,10,17,14,
+ 13,14,10,10,12,10,10,18,15,15,14,10,10, 8, 7, 7,
+ 13,12,12,13,11,11,12,11,11,16,14,15,14,12,12,12,
+ 11,11,18,16,16,14,12,12,11,10,10,13,12,11,13,11,
+ 11,13,12,12, 0,15,14,14,11,11,13,11,11,16,15,15,
+ 15,11,11,
+};
+
+static const static_codebook _44pn1_p5_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44pn1_p5_0,
+ 1, -527106048, 1620377600, 2, 0,
+ (long *)_vq_quantlist__44pn1_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p5_1[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44pn1_p5_1[] = {
+ 2, 6, 7, 6, 8, 8, 7, 7, 8, 7, 8, 8, 9, 9, 9, 8,
+ 7, 7, 8, 8, 8, 9, 9, 9, 9, 8, 8, 6, 6, 6, 9, 7,
+ 7, 9, 7, 7, 9, 8, 8,10, 8, 8,10, 8, 8,10, 8, 8,
+ 10, 9, 8,10, 8, 8, 7, 6, 6, 9, 6, 6, 9, 6, 6, 9,
+ 7, 7,10, 8, 8,10, 6, 6, 9, 7, 7,10, 8, 8,10, 6,
+ 6, 7, 7, 7,11, 9, 9,11, 9, 9,10, 9, 9,12,10,10,
+ 12, 8, 8,11, 9, 9,13, 9,10,12, 8, 8, 8, 7, 7,11,
+ 9,10,11,10,10,10, 9, 9,11,11,11,11, 9, 9,11,10,
+ 9,12,11,11,11, 9,10,10, 8, 8,11, 9,10,11, 9, 9,
+ 11, 9, 9,12,10,10,11, 9, 9,11, 9, 9,12,10,11,11,
+ 9, 9, 8, 8, 8,12, 9, 9,12, 9, 9,11, 9, 9,13, 9,
+ 9,13, 8, 8,12, 9, 9,13,10,10,12, 8, 8, 9, 7, 7,
+ 11,10,10,11,10,10,11,10,10,12,11,11,11,10, 9,11,
+ 10,10,11,11,11,11, 9, 9,11, 9, 9,12,10,10,11,10,
+ 10,12,10,10,11,11,11,11, 9, 9,11,10,10,12,11,11,
+ 11, 9, 9,
+};
+
+static const static_codebook _44pn1_p5_1 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44pn1_p5_1,
+ 1, -530841600, 1616642048, 2, 0,
+ (long *)_vq_quantlist__44pn1_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44pn1_p6_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,
+};
+
+static const static_codebook _44pn1_p6_0 = {
+ 5, 243,
+ (char *)_vq_lengthlist__44pn1_p6_0,
+ 1, -516716544, 1630767104, 2, 0,
+ (long *)_vq_quantlist__44pn1_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p6_1[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44pn1_p6_1[] = {
+ 1, 3, 2, 5, 4, 7, 7, 8, 8, 9, 9,10,10,11,11,12,
+ 12,13,13,14,14,15,15,15,15,
+};
+
+static const static_codebook _44pn1_p6_1 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44pn1_p6_1,
+ 1, -518864896, 1620639744, 5, 0,
+ (long *)_vq_quantlist__44pn1_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44pn1_p6_2[] = {
+ 12,
+ 11,
+ 13,
+ 10,
+ 14,
+ 9,
+ 15,
+ 8,
+ 16,
+ 7,
+ 17,
+ 6,
+ 18,
+ 5,
+ 19,
+ 4,
+ 20,
+ 3,
+ 21,
+ 2,
+ 22,
+ 1,
+ 23,
+ 0,
+ 24,
+};
+
+static const char _vq_lengthlist__44pn1_p6_2[] = {
+ 3, 5, 4, 5, 4, 5, 4, 5, 5, 5, 4, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44pn1_p6_2 = {
+ 1, 25,
+ (char *)_vq_lengthlist__44pn1_p6_2,
+ 1, -529006592, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44pn1_p6_2,
+ 0
+};
+
+static const char _huff_lengthlist__44pn1_short[] = {
+ 4, 3, 7, 9,12,16,16, 3, 2, 5, 7,11,14,15, 7, 4,
+ 5, 6, 9,12,15, 8, 5, 5, 5, 8,10,14, 9, 7, 6, 6,
+ 8,10,12,12,10,10, 7, 6, 8,10,15,12,10, 6, 4, 7,
+ 9,
+};
+
+static const static_codebook _huff_book__44pn1_short = {
+ 2, 49,
+ (char *)_huff_lengthlist__44pn1_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
diff --git a/external/libvorbis-1.3.5/lib/books/coupled/res_books_stereo.h b/external/libvorbis-1.3.5/lib/books/coupled/res_books_stereo.h
new file mode 100644
index 0000000..9a9049f
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/books/coupled/res_books_stereo.h
@@ -0,0 +1,15783 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: static codebooks autogenerated by huff/huffbuld
+ last modified: $Id: res_books_stereo.h 19057 2014-01-22 12:32:31Z xiphmont $
+
+ ********************************************************************/
+
+#include "codebook.h"
+
+static const long _vq_quantlist__16c0_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16c0_s_p1_0[] = {
+ 1, 4, 4, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 5, 7, 7, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9,10, 0, 0, 0,
+ 0, 0, 0, 7, 9,10, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 7, 9, 9, 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, 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, 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, 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, 5, 8, 8, 0, 0, 0, 0,
+ 0, 0, 8,10,10, 0, 0, 0, 0, 0, 0, 8,10,10, 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, 7,10,10, 0, 0, 0,
+ 0, 0, 0, 9, 9,12, 0, 0, 0, 0, 0, 0,10,12,11, 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, 7,10,10, 0, 0,
+ 0, 0, 0, 0, 9,12,10, 0, 0, 0, 0, 0, 0,10,11,12,
+ 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, 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, 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, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8,10,10, 0, 0,
+ 0, 0, 0, 0, 8,10,10, 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, 7,10,10, 0, 0, 0, 0, 0, 0,10,12,11, 0,
+ 0, 0, 0, 0, 0, 9,10,12, 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, 7,10,10, 0, 0, 0, 0, 0, 0,10,11,12,
+ 0, 0, 0, 0, 0, 0, 9,12, 9, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _16c0_s_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__16c0_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__16c0_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__16c0_s_p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16c0_s_p3_0[] = {
+ 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 6, 7, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 9, 9,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 6, 6, 9, 9, 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, 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, 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, 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,
+};
+
+static const static_codebook _16c0_s_p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__16c0_s_p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16c0_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__16c0_s_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__16c0_s_p4_0[] = {
+ 1, 3, 2, 7, 8, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7,
+ 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0,
+ 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0,
+ 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _16c0_s_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__16c0_s_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16c0_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__16c0_s_p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__16c0_s_p5_0[] = {
+ 1, 3, 3, 6, 6, 6, 6, 8, 8, 0, 0, 0, 7, 7, 7, 7,
+ 8, 8, 0, 0, 0, 7, 7, 7, 7, 8, 8, 0, 0, 0, 7, 7,
+ 8, 8, 9, 9, 0, 0, 0, 7, 7, 8, 8, 9, 9, 0, 0, 0,
+ 8, 9, 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0,
+ 0, 0,10,10, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,
+};
+
+static const static_codebook _16c0_s_p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__16c0_s_p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16c0_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__16c0_s_p6_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__16c0_s_p6_0[] = {
+ 1, 3, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11,
+ 11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,11,
+ 11,11, 0, 0, 0, 6, 6, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10,
+ 11,11,12,12,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,
+ 10,11,11,12,12,12,13, 0, 0, 0, 9, 9, 9, 9,10,10,
+ 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0,10,10,10,
+ 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,
+ 10,10,11,11,12,12,13,13,13,13, 0, 0, 0, 0, 0, 9,
+ 9,10,10,11,11,12,12,13,13,13,14, 0, 0, 0, 0, 0,
+ 10,10,10,11,11,11,12,12,13,13,13,14, 0, 0, 0, 0,
+ 0, 0, 0,10,10,11,11,12,12,13,13,14,14, 0, 0, 0,
+ 0, 0, 0, 0,11,11,12,12,13,13,13,13,14,14, 0, 0,
+ 0, 0, 0, 0, 0,11,11,12,12,12,13,13,14,15,14, 0,
+ 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,14,14,15,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,13,14,13,14,
+ 14,
+};
+
+static const static_codebook _16c0_s_p6_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__16c0_s_p6_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__16c0_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__16c0_s_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16c0_s_p7_0[] = {
+ 1, 4, 4, 6, 6, 6, 7, 6, 6, 4, 7, 7,11,10,10,11,
+ 11,10, 4, 7, 7,10,10,10,11,10,10, 6,10,10,11,11,
+ 11,11,11,10, 6, 9, 9,11,12,12,11, 9, 9, 6, 9,10,
+ 11,12,12,11, 9,10, 7,11,11,11,11,11,12,13,12, 6,
+ 9,10,11,10,10,12,13,13, 6,10, 9,11,10,10,11,12,
+ 13,
+};
+
+static const static_codebook _16c0_s_p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16c0_s_p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__16c0_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__16c0_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__16c0_s_p7_1[] = {
+ 1, 3, 4, 6, 6, 7, 7, 8, 8, 8, 8,10,10,10, 7, 7,
+ 8, 8, 8, 9, 9, 9,10,10,10, 6, 7, 8, 8, 8, 8, 9,
+ 8,10,10,10, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10, 7,
+ 7, 8, 8, 9, 9, 8, 9,10,10,10, 8, 8, 9, 9, 9, 9,
+ 9, 9,11,11,11, 8, 8, 9, 9, 9, 9, 9,10,10,11,11,
+ 9, 9, 9, 9, 9, 9, 9,10,11,11,11,10,11, 9, 9, 9,
+ 9,10, 9,11,11,11,10,11,10,10, 9, 9,10,10,11,11,
+ 11,11,11, 9, 9, 9, 9,10,10,
+};
+
+static const static_codebook _16c0_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__16c0_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16c0_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__16c0_s_p8_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__16c0_s_p8_0[] = {
+ 1, 4, 4, 7, 7, 7, 7, 7, 6, 8, 8,10,10, 6, 5, 6,
+ 8, 8, 8, 8, 8, 8, 8, 9,10,10, 7, 6, 6, 8, 8, 8,
+ 8, 8, 8, 8, 8,10,10, 0, 8, 8, 8, 8, 9, 8, 9, 9,
+ 9,10,10,10, 0, 9, 8, 8, 8, 9, 9, 8, 8, 9, 9,10,
+ 10, 0,12,11, 8, 8, 9, 9, 9, 9,10,10,11,10, 0,12,
+ 13, 8, 8, 9,10, 9, 9,11,11,11,12, 0, 0, 0, 8, 8,
+ 8, 8,10, 9,12,13,12,14, 0, 0, 0, 8, 8, 8, 9,10,
+ 10,12,12,13,14, 0, 0, 0,13,13, 9, 9,11,11, 0, 0,
+ 14, 0, 0, 0, 0,14,14,10,10,12,11,12,14,14,14, 0,
+ 0, 0, 0, 0,11,11,13,13,14,13,14,14, 0, 0, 0, 0,
+ 0,12,13,13,12,13,14,14,14,
+};
+
+static const static_codebook _16c0_s_p8_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__16c0_s_p8_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__16c0_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__16c0_s_p8_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16c0_s_p8_1[] = {
+ 1, 4, 3, 5, 5, 7, 7, 7, 6, 6, 7, 7, 7, 5, 5, 7,
+ 7, 7, 6, 6, 7, 7, 7, 6, 6,
+};
+
+static const static_codebook _16c0_s_p8_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__16c0_s_p8_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16c0_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__16c0_s_p9_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16c0_s_p9_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7,
+};
+
+static const static_codebook _16c0_s_p9_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16c0_s_p9_0,
+ 1, -518803456, 1628680192, 2, 0,
+ (long *)_vq_quantlist__16c0_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__16c0_s_p9_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__16c0_s_p9_1[] = {
+ 1, 5, 5, 5, 5, 9,11,11,10,10,10,10,10,10,10, 7,
+ 6, 6, 6, 6,10,10,10,10,10,10,10,10,10,10, 7, 6,
+ 6, 6, 6,10, 9,10,10,10,10,10,10,10,10,10, 7, 7,
+ 8, 9,10,10,10,10,10,10,10,10,10,10,10, 8, 7,10,
+ 10,10, 9,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _16c0_s_p9_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__16c0_s_p9_1,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__16c0_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__16c0_s_p9_2[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__16c0_s_p9_2[] = {
+ 1, 5, 5, 7, 8, 8, 7, 9, 9, 9,12,12,11,12,12,10,
+ 10,11,12,12,12,11,12,12, 8, 9, 8, 7, 9,10,10,11,
+ 11,10,11,12,10,12,10,12,12,12,11,12,11, 9, 8, 8,
+ 9,10, 9, 8, 9,10,12,12,11,11,12,11,10,11,12,11,
+ 12,12, 8, 9, 9, 9,10,11,12,11,12,11,11,11,11,12,
+ 12,11,11,12,12,11,11, 9, 9, 8, 9, 9,11, 9, 9,10,
+ 9,11,11,11,11,12,11,11,10,12,12,12, 9,12,11,10,
+ 11,11,11,11,12,12,12,11,11,11,12,10,12,12,12,10,
+ 10, 9,10, 9,10,10, 9, 9, 9,10,10,12,10,11,11, 9,
+ 11,11,10,11,11,11,10,10,10, 9, 9,10,10, 9, 9,10,
+ 11,11,10,11,10,11,10,11,11,10,11,11,11,10, 9,10,
+ 10, 9,10, 9, 9,11, 9, 9,11,10,10,11,11,10,10,11,
+ 10,11, 8, 9,11,11,10, 9,10,11,11,10,11,11,10,10,
+ 10,11,10, 9,10,10,11, 9,10,10, 9,11,10,10,10,10,
+ 11,10,11,11, 9,11,10,11,10,10,11,11,10,10,10, 9,
+ 10,10,11,11,11, 9,10,10,10,10,10,11,10,10,10, 9,
+ 10,10,11,10,10,10,10,10, 9,10,11,10,10,10,10,11,
+ 11,11,10,10,10,10,10,11,10,11,10,11,10,10,10, 9,
+ 11,11,10,10,10,11,11,10,10,10,10,10,10,10,10,11,
+ 11, 9,10,10,10,11,10,11,10,10,10,11, 9,10,11,10,
+ 11,10,10, 9,10,10,10,11,10,11,10,10,10,10,10,11,
+ 11,10,11,11,10,10,11,11,10, 9, 9,10,10,10,10,10,
+ 9,11, 9,10,10,10,11,11,10,10,10,10,11,11,11,10,
+ 9, 9,10,10,11,10,10,10,10,10,11,11,11,10,10,10,
+ 11,11,11, 9,10,10,10,10, 9,10, 9,10,11,10,11,10,
+ 10,11,11,10,11,11,11,11,11,10,11,10,10,10, 9,11,
+ 11,10,11,11,11,11,11,11,11,11,11,10,11,10,10,10,
+ 10,11,10,10,11, 9,10,10,10,
+};
+
+static const static_codebook _16c0_s_p9_2 = {
+ 2, 441,
+ (char *)_vq_lengthlist__16c0_s_p9_2,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__16c0_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__16c0_s_single[] = {
+ 3, 4,19, 7, 9, 7, 8,11, 9,12, 4, 1,19, 6, 7, 7,
+ 8,10,11,13,18,18,18,18,18,18,18,18,18,18, 8, 6,
+ 18, 8, 9, 9,11,12,14,18, 9, 6,18, 9, 7, 8, 9,11,
+ 12,18, 7, 6,18, 8, 7, 7, 7, 9,11,17, 8, 8,18, 9,
+ 7, 6, 6, 8,11,17,10,10,18,12, 9, 8, 7, 9,12,18,
+ 13,15,18,15,13,11,10,11,15,18,14,18,18,18,18,18,
+ 16,16,18,18,
+};
+
+static const static_codebook _huff_book__16c0_s_single = {
+ 2, 100,
+ (char *)_huff_lengthlist__16c0_s_single,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__16c1_s_long[] = {
+ 2, 5,20, 7,10, 7, 8,10,11,11, 4, 2,20, 5, 8, 6,
+ 7, 9,10,10,20,20,20,20,19,19,19,19,19,19, 7, 5,
+ 19, 6,10, 7, 9,11,13,17,11, 8,19,10, 7, 7, 8,10,
+ 11,15, 7, 5,19, 7, 7, 5, 6, 9,11,16, 7, 6,19, 8,
+ 7, 6, 6, 7, 9,13, 9, 9,19,11, 9, 8, 6, 7, 8,13,
+ 12,14,19,16,13,10, 9, 8, 9,13,14,17,19,18,18,17,
+ 12,11,11,13,
+};
+
+static const static_codebook _huff_book__16c1_s_long = {
+ 2, 100,
+ (char *)_huff_lengthlist__16c1_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16c1_s_p1_0[] = {
+ 1, 5, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 5, 7, 7, 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, 5, 8, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0,
+ 0, 0, 0, 7, 8, 9, 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, 5, 7, 8, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0,
+ 0, 0, 0, 0, 7, 9, 9, 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, 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, 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, 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, 5, 8, 7, 0, 0, 0, 0,
+ 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 7, 9, 9, 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, 7, 9, 9, 0, 0, 0,
+ 0, 0, 0, 9, 9,11, 0, 0, 0, 0, 0, 0, 9,11,10, 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, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8,11, 9, 0, 0, 0, 0, 0, 0, 9,10,11,
+ 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, 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, 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, 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, 5, 7, 8, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8, 9, 9, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,11,10, 0,
+ 0, 0, 0, 0, 0, 8, 9,11, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,11,
+ 0, 0, 0, 0, 0, 0, 9,11, 9, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _16c1_s_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__16c1_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__16c1_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16c1_s_p3_0[] = {
+ 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 7, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 5, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 9, 9,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 7, 7, 9, 9, 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, 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, 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, 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,
+};
+
+static const static_codebook _16c1_s_p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__16c1_s_p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16c1_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__16c1_s_p4_0[] = {
+ 1, 2, 3, 7, 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7,
+ 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0,
+ 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0,
+ 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _16c1_s_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__16c1_s_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16c1_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__16c1_s_p5_0[] = {
+ 1, 3, 3, 5, 5, 6, 6, 8, 8, 0, 0, 0, 7, 7, 7, 7,
+ 9, 9, 0, 0, 0, 7, 7, 7, 7, 9, 9, 0, 0, 0, 8, 8,
+ 8, 8, 9, 9, 0, 0, 0, 8, 8, 8, 8,10,10, 0, 0, 0,
+ 9, 9, 8, 8,10,10, 0, 0, 0, 9, 9, 8, 8,10,10, 0,
+ 0, 0,10,10, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,
+};
+
+static const static_codebook _16c1_s_p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__16c1_s_p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16c1_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p6_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__16c1_s_p6_0[] = {
+ 1, 3, 3, 6, 6, 8, 8, 9, 9, 9, 9,10,10,11,11,12,
+ 12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,11,
+ 12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11,12,12, 0, 0, 0, 8, 8, 8, 9,10, 9,10,10,10,10,
+ 11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10,11,
+ 11,11,12,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10,
+ 11,11,12,12,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,
+ 10,11,11,12,12,13,13, 0, 0, 0, 9, 9, 9, 9,10,10,
+ 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,
+ 10,10,11,11,12,12,12,12,13,13, 0, 0, 0, 0, 0, 9,
+ 9,10,10,11,11,12,12,12,12,13,13, 0, 0, 0, 0, 0,
+ 10,10,11,10,11,11,12,12,13,13,13,13, 0, 0, 0, 0,
+ 0, 0, 0,10,10,11,11,12,12,13,13,13,13, 0, 0, 0,
+ 0, 0, 0, 0,11,11,12,12,12,12,13,13,14,14, 0, 0,
+ 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,14,14, 0,
+ 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,13,14,14,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,13,13,13,14,
+ 14,
+};
+
+static const static_codebook _16c1_s_p6_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__16c1_s_p6_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__16c1_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16c1_s_p7_0[] = {
+ 1, 4, 4, 6, 6, 6, 7, 6, 6, 4, 7, 7,10, 9,10,10,
+ 10, 9, 4, 7, 7,10,10,10,11,10,10, 6,10,10,11,11,
+ 11,11,10,10, 6,10, 9,11,11,11,11,10,10, 6,10,10,
+ 11,11,11,11,10,10, 7,11,11,11,11,11,12,12,11, 6,
+ 10,10,11,10,10,11,11,11, 6,10,10,10,11,10,11,11,
+ 11,
+};
+
+static const static_codebook _16c1_s_p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16c1_s_p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__16c1_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__16c1_s_p7_1[] = {
+ 2, 3, 3, 5, 6, 7, 7, 7, 7, 8, 8,10,10,10, 6, 6,
+ 7, 7, 8, 8, 8, 8,10,10,10, 6, 6, 7, 7, 8, 8, 8,
+ 8,10,10,10, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7,
+ 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, 7, 8, 8, 8, 8,
+ 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10,
+ 8, 8, 8, 8, 8, 8, 9, 9,10,10,10,10,10, 8, 8, 8,
+ 8, 9, 9,10,10,10,10,10, 9, 9, 8, 8, 9, 9,10,10,
+ 10,10,10, 8, 8, 8, 8, 9, 9,
+};
+
+static const static_codebook _16c1_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__16c1_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16c1_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p8_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__16c1_s_p8_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 6, 5, 5,
+ 7, 8, 8, 9, 8, 8, 9, 9,10,11, 6, 5, 5, 8, 8, 9,
+ 9, 8, 8, 9,10,10,11, 0, 8, 8, 8, 9, 9, 9, 9, 9,
+ 10,10,11,11, 0, 9, 9, 9, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,13,13, 9, 9,10,10,10,10,11,11,12,12, 0,14,
+ 13, 9, 9,10,10,10,10,11,11,12,12, 0, 0, 0,10,10,
+ 9, 9,11,11,12,12,13,12, 0, 0, 0,10,10, 9, 9,10,
+ 10,12,12,13,13, 0, 0, 0,13,14,11,10,11,11,12,12,
+ 13,14, 0, 0, 0,14,14,10,10,11,11,12,12,13,13, 0,
+ 0, 0, 0, 0,12,12,12,12,13,13,14,15, 0, 0, 0, 0,
+ 0,12,12,12,12,13,13,14,15,
+};
+
+static const static_codebook _16c1_s_p8_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__16c1_s_p8_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__16c1_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p8_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16c1_s_p8_1[] = {
+ 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6,
+ 6, 6, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _16c1_s_p8_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__16c1_s_p8_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16c1_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p9_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__16c1_s_p9_0[] = {
+ 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _16c1_s_p9_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__16c1_s_p9_0,
+ 1, -513964032, 1628680192, 4, 0,
+ (long *)_vq_quantlist__16c1_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p9_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__16c1_s_p9_1[] = {
+ 1, 4, 4, 4, 4, 8, 8,12,13,14,14,14,14,14,14, 6,
+ 6, 6, 6, 6,10, 9,14,14,14,14,14,14,14,14, 7, 6,
+ 5, 6, 6,10, 9,12,13,13,13,13,13,13,13,13, 7, 7,
+ 9, 9,11,11,12,13,13,13,13,13,13,13,13, 7, 7, 8,
+ 8,11,12,13,13,13,13,13,13,13,13,13,12,12,10,10,
+ 13,12,13,13,13,13,13,13,13,13,13,12,12,10,10,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,12,13,12,
+ 13,13,13,13,13,13,13,13,13,13,13,13,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,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,13,13,13,
+ 13,13,13,13,13,13,13,13,13,12,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,
+};
+
+static const static_codebook _16c1_s_p9_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__16c1_s_p9_1,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__16c1_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__16c1_s_p9_2[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__16c1_s_p9_2[] = {
+ 1, 4, 4, 6, 6, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,10, 9,10,10,11,12,12, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,10,10,10,11,11,10,12,11,11,13,11, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9,10,10,10,10, 9,10,10,11,11,12,
+ 11,11, 8, 8, 8, 8, 9, 9,10,10,10,10,11,11,11,11,
+ 11,11,11,12,11,12,12, 8, 8, 9, 9, 9, 9, 9,10,10,
+ 10,10,10,10,11,11,11,11,11,11,12,11, 9, 9, 9, 9,
+ 10,10,10,10,11,10,11,11,11,11,11,11,12,12,12,12,
+ 11, 9, 9, 9, 9,10,10,10,10,11,11,11,11,11,11,11,
+ 11,11,12,12,12,13, 9,10,10, 9,11,10,10,10,10,11,
+ 11,11,11,11,10,11,12,11,12,12,11,12,11,10, 9,10,
+ 10,11,10,11,11,11,11,11,11,11,11,11,12,12,11,12,
+ 12,12,10,10,10,11,10,11,11,11,11,11,11,11,11,11,
+ 11,11,12,13,12,12,11, 9,10,10,11,11,10,11,11,11,
+ 12,11,11,11,11,11,12,12,13,13,12,13,10,10,12,10,
+ 11,11,11,11,11,11,11,11,11,12,12,11,13,12,12,12,
+ 12,13,12,11,11,11,11,11,11,12,11,12,11,11,11,11,
+ 12,12,13,12,11,12,12,11,11,11,11,11,12,11,11,11,
+ 11,12,11,11,12,11,12,13,13,12,12,12,12,11,11,11,
+ 11,11,12,11,11,12,11,12,11,11,11,11,13,12,12,12,
+ 12,13,11,11,11,12,12,11,11,11,12,11,12,12,12,11,
+ 12,13,12,11,11,12,12,11,12,11,11,11,12,12,11,12,
+ 11,11,11,12,12,12,12,13,12,13,12,12,12,12,11,11,
+ 12,11,11,11,11,11,11,12,12,12,13,12,11,13,13,12,
+ 12,11,12,10,11,11,11,11,12,11,12,12,11,12,12,13,
+ 12,12,13,12,12,12,12,12,11,12,12,12,11,12,11,11,
+ 11,12,13,12,13,13,13,13,13,12,13,13,12,12,13,11,
+ 11,11,11,11,12,11,11,12,11,
+};
+
+static const static_codebook _16c1_s_p9_2 = {
+ 2, 441,
+ (char *)_vq_lengthlist__16c1_s_p9_2,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__16c1_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__16c1_s_short[] = {
+ 5, 6,17, 8,12, 9,10,10,12,13, 5, 2,17, 4, 9, 5,
+ 7, 8,11,13,16,16,16,16,16,16,16,16,16,16, 6, 4,
+ 16, 5,10, 5, 7,10,14,16,13, 9,16,11, 8, 7, 8, 9,
+ 13,16, 7, 4,16, 5, 7, 4, 6, 8,11,13, 8, 6,16, 7,
+ 8, 5, 5, 7, 9,13, 9, 8,16, 9, 8, 6, 6, 7, 9,13,
+ 11,11,16,10,10, 7, 7, 7, 9,13,13,13,16,13,13, 9,
+ 9, 9,10,13,
+};
+
+static const static_codebook _huff_book__16c1_s_short = {
+ 2, 100,
+ (char *)_huff_lengthlist__16c1_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__16c2_s_long[] = {
+ 4, 7, 9, 9, 9, 8, 9,10,13,16, 5, 4, 5, 6, 7, 7,
+ 8, 9,12,16, 6, 5, 5, 5, 7, 7, 9,10,12,15, 7, 6,
+ 5, 4, 5, 6, 8, 9,10,13, 8, 7, 7, 5, 5, 5, 7, 9,
+ 10,12, 7, 7, 7, 6, 5, 5, 6, 7,10,12, 8, 8, 8, 7,
+ 7, 5, 5, 6, 9,11, 8, 9, 9, 8, 8, 6, 6, 5, 8,11,
+ 10,11,12,12,11, 9, 9, 8, 9,12,13,14,15,15,14,12,
+ 12,11,11,13,
+};
+
+static const static_codebook _huff_book__16c2_s_long = {
+ 2, 100,
+ (char *)_huff_lengthlist__16c2_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16c2_s_p1_0[] = {
+ 1, 3, 3, 0, 0, 0, 0, 0, 0, 4, 5, 5, 0, 0, 0, 0,
+ 0, 0, 4, 5, 5, 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,
+};
+
+static const static_codebook _16c2_s_p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16c2_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__16c2_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16c2_s_p2_0[] = {
+ 2, 4, 4, 7, 7, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, 0,
+ 0, 0, 8, 8, 0, 0, 0, 8, 8, 4, 4, 4, 8, 7, 0, 0,
+ 0, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0,
+ 9, 9, 4, 4, 4, 7, 8, 0, 0, 0, 8, 8, 0, 0, 0, 8,
+ 8, 0, 0, 0, 9, 9, 0, 0, 0, 9, 9, 7, 8, 8,10, 9,
+ 0, 0, 0,12,11, 0, 0, 0,11,12, 0, 0, 0,14,13, 0,
+ 0, 0,14,14, 7, 8, 8, 9,10, 0, 0, 0,11,12, 0, 0,
+ 0,11,11, 0, 0, 0,14,14, 0, 0, 0,14,14, 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, 8, 8, 8,11,11, 0, 0, 0,
+ 12,11, 0, 0, 0,12,12, 0, 0, 0,13,12, 0, 0, 0,13,
+ 13, 8, 8, 8,11,11, 0, 0, 0,11,11, 0, 0, 0,12,12,
+ 0, 0, 0,13,13, 0, 0, 0,13,13, 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, 8, 9, 8,12,11, 0, 0, 0,12,12, 0,
+ 0, 0,12,11, 0, 0, 0,13,13, 0, 0, 0,13,13, 8, 8,
+ 8,11,12, 0, 0, 0,11,12, 0, 0, 0,11,12, 0, 0, 0,
+ 13,14, 0, 0, 0,13,13, 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, 8, 9, 9,14,14, 0, 0, 0,13,13, 0, 0, 0,13,
+ 13, 0, 0, 0,13,12, 0, 0, 0,13,13, 8, 9, 9,14,14,
+ 0, 0, 0,13,13, 0, 0, 0,13,13, 0, 0, 0,12,13, 0,
+ 0, 0,13,13, 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, 8,
+ 9, 9,14,14, 0, 0, 0,13,13, 0, 0, 0,13,13, 0, 0,
+ 0,13,13, 0, 0, 0,13,12, 8, 9, 9,14,14, 0, 0, 0,
+ 13,13, 0, 0, 0,13,13, 0, 0, 0,13,13, 0, 0, 0,12,
+ 12,
+};
+
+static const static_codebook _16c2_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__16c2_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16c2_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__16c2_s_p3_0[] = {
+ 1, 3, 3, 5, 5, 7, 7, 8, 8, 0, 0, 0, 6, 6, 8, 8,
+ 9, 9, 0, 0, 0, 6, 6, 8, 8, 9, 9, 0, 0, 0, 7, 7,
+ 8, 9,10,10, 0, 0, 0, 7, 7, 9, 9,10,10, 0, 0, 0,
+ 8, 8, 9, 9,11,11, 0, 0, 0, 7, 7, 9, 9,11,11, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _16c2_s_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__16c2_s_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16c2_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p4_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__16c2_s_p4_0[] = {
+ 2, 3, 3, 5, 5, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9,
+ 9, 0, 0, 0, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,
+ 11,10, 0, 0, 0, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,
+ 10,10,10, 0, 0, 0, 6, 6, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,11,11, 0, 0, 0, 7, 6, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9,10,10,
+ 11,11,11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10,
+ 10,11,11,11,11,12,12, 0, 0, 0, 7, 8, 8, 8, 9, 9,
+ 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 8, 8, 9,
+ 9,10,10,11,11,12,12,13,13, 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,
+};
+
+static const static_codebook _16c2_s_p4_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__16c2_s_p4_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__16c2_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p5_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16c2_s_p5_0[] = {
+ 1, 4, 4, 5, 7, 7, 6, 7, 7, 4, 6, 6,10,11,10,10,
+ 10,11, 4, 6, 6,10,10,11,10,11,10, 5,10,10, 9,12,
+ 11,10,12,12, 7,10,10,12,12,12,12,13,13, 7,11,10,
+ 11,12,12,12,13,13, 6,11,10,10,12,12,11,12,12, 7,
+ 11,10,12,13,13,12,12,12, 7,10,11,12,13,13,12,12,
+ 12,
+};
+
+static const static_codebook _16c2_s_p5_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16c2_s_p5_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__16c2_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p5_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__16c2_s_p5_1[] = {
+ 2, 3, 3, 6, 6, 6, 6, 7, 7, 7, 7,11,10,10, 6, 6,
+ 7, 7, 8, 8, 8, 8,10,10,10, 6, 6, 7, 7, 8, 8, 8,
+ 8,11,11,11, 7, 7, 8, 8, 8, 8, 9, 9,11,11,11, 6,
+ 7, 8, 8, 8, 8, 9, 9,11,11,11, 7, 7, 8, 8, 8, 8,
+ 8, 8,11,11,11, 7, 7, 8, 8, 8, 8, 9, 9,11,11,11,
+ 8, 8, 8, 8, 8, 8, 8, 8,11,11,11,11,11, 8, 8, 8,
+ 8, 8, 8,12,11,11,11,11, 8, 8, 8, 8, 8, 8,12,11,
+ 11,11,11, 7, 7, 8, 8, 8, 8,
+};
+
+static const static_codebook _16c2_s_p5_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__16c2_s_p5_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16c2_s_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__16c2_s_p6_0[] = {
+ 1, 4, 4, 6, 6, 8, 7, 8, 8, 9, 9,10,10, 5, 5, 5,
+ 7, 7, 9, 9, 9, 9,11,11,12,12, 6, 5, 5, 7, 7, 9,
+ 9,10, 9,11,11,12,12, 0, 7, 7, 7, 7, 9, 9,10,10,
+ 11,11,12,12, 0, 7, 7, 7, 7, 9, 9,10,10,11,11,12,
+ 12, 0,11,11, 8, 8,10,10,11,11,12,12,13,13, 0,12,
+ 12, 9, 9,10,10,11,11,12,12,13,13, 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,
+};
+
+static const static_codebook _16c2_s_p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__16c2_s_p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__16c2_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16c2_s_p6_1[] = {
+ 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6,
+ 6, 6, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _16c2_s_p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__16c2_s_p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16c2_s_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__16c2_s_p7_0[] = {
+ 1, 4, 4, 7, 7, 8, 8, 8, 8,10, 9,10,10, 5, 5, 5,
+ 7, 7, 9, 9,10,10,11,10,12,11, 6, 5, 5, 7, 7, 9,
+ 9,10,10,11,11,12,12,20, 7, 7, 7, 7, 9, 9,10,10,
+ 11,11,12,12,20, 7, 7, 7, 7, 9, 9,11,10,12,11,12,
+ 12,20,11,11, 8, 8,10,10,11,11,12,12,13,13,20,12,
+ 12, 8, 8, 9, 9,11,11,12,12,13,13,20,20,21,10,10,
+ 10,10,11,11,12,12,13,13,21,21,21,10,10,10,10,11,
+ 11,12,12,13,13,21,21,21,14,14,11,11,12,12,13,13,
+ 13,14,21,21,21,16,15,11,11,12,11,13,13,14,14,21,
+ 21,21,21,21,13,13,12,12,13,13,14,14,21,21,21,21,
+ 21,13,13,12,12,13,13,14,14,
+};
+
+static const static_codebook _16c2_s_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__16c2_s_p7_0,
+ 1, -523206656, 1618345984, 4, 0,
+ (long *)_vq_quantlist__16c2_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__16c2_s_p7_1[] = {
+ 2, 4, 4, 6, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 6, 7,
+ 7, 7, 7, 7, 8, 8, 9, 9, 9, 6, 6, 7, 7, 7, 7, 8,
+ 8, 9, 9, 9, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 7,
+ 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 7, 7, 7, 7, 8, 8,
+ 8, 8, 9, 9, 9, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9,
+ 7, 7, 8, 8, 7, 7, 8, 8, 9, 9, 9, 9, 9, 8, 8, 7,
+ 7, 8, 8, 9, 9, 9, 9, 9, 8, 8, 7, 7, 8, 8, 9, 9,
+ 9, 9, 9, 7, 7, 7, 7, 8, 8,
+};
+
+static const static_codebook _16c2_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__16c2_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16c2_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p8_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__16c2_s_p8_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9,10,10, 6,
+ 6, 6, 8, 8, 9, 9, 8, 8, 9, 9,10,10,11,11, 6, 5,
+ 5, 8, 7, 9, 9, 8, 8, 9, 9,10,10,11,11,20, 8, 8,
+ 8, 8, 9, 9, 9, 9,10,10,11,10,12,11,20, 8, 8, 8,
+ 8, 9, 9, 9, 9,10,10,11,11,12,12,20,12,12, 9, 9,
+ 10,10,10,10,11,11,12,12,13,12,20,13,13, 9, 9,10,
+ 10,10,10,11,11,12,12,13,13,20,20,20, 9, 9, 9, 9,
+ 10,10,11,11,12,12,13,12,20,20,20, 9, 9, 9, 8,10,
+ 10,12,11,12,12,13,13,20,20,20,13,13,10,10,11,11,
+ 12,12,13,13,13,13,20,20,20,13,13,10,10,11,10,12,
+ 11,13,13,14,14,20,20,20,20,20,11,11,11,11,12,12,
+ 13,13,14,14,20,20,20,20,20,11,10,11,11,13,11,13,
+ 13,14,14,20,20,21,21,21,14,14,11,12,13,13,13,13,
+ 14,14,21,21,21,21,21,15,15,12,11,13,12,14,13,15,
+ 14,
+};
+
+static const static_codebook _16c2_s_p8_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__16c2_s_p8_0,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__16c2_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p8_1[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__16c2_s_p8_1[] = {
+ 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8,11,11,11, 7, 7, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,11,10, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,
+ 11,11, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9,11,11,11, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9,10, 9,10,10,10,10,11,11,11, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,11,11,
+ 11, 8, 8, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,
+ 10,10,10,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9,10,10,
+ 10,10,10,10,10,10,10,10,11,11,11,11,11, 9, 9, 9,
+ 9, 9, 9,10,10,10,10,10,10,10,10,10,10,11,11,11,
+ 11,11, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,
+ 10,10,11,11,11,11,11, 9, 9, 9, 9,10,10,10,10,10,
+ 10,10,10,10,10,10,10,11,11,11,11,11,10, 9,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,
+ 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,11,11,11,11,11,11,11,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,
+ 11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,
+ 10,10,10,10,10,11,11,11,11,11,11,11,11,11,10,10,
+ 10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,
+ 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,11,
+ 11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,
+ 10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,10,
+ 10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _16c2_s_p8_1 = {
+ 2, 441,
+ (char *)_vq_lengthlist__16c2_s_p8_1,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__16c2_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p9_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__16c2_s_p9_0[] = {
+ 1, 4, 3,10, 8,10,10,10,10,10,10,10,10,10,10,10,
+ 10, 6,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10, 6,10, 9,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _16c2_s_p9_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__16c2_s_p9_0,
+ 1, -509798400, 1631393792, 5, 0,
+ (long *)_vq_quantlist__16c2_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p9_1[] = {
+ 9,
+ 8,
+ 10,
+ 7,
+ 11,
+ 6,
+ 12,
+ 5,
+ 13,
+ 4,
+ 14,
+ 3,
+ 15,
+ 2,
+ 16,
+ 1,
+ 17,
+ 0,
+ 18,
+};
+
+static const char _vq_lengthlist__16c2_s_p9_1[] = {
+ 1, 4, 4, 7, 7, 7, 7, 7, 7, 8, 8,10, 9,11,10,13,
+ 11,14,13, 6, 6, 6, 8, 8, 8, 8, 8, 7, 9, 8,11, 9,
+ 13,11,14,12,14,13, 5, 6, 6, 8, 8, 8, 8, 8, 8, 9,
+ 9,11,11,13,11,14,13,15,15,17, 8, 8, 8, 8, 9, 9,
+ 9, 8,11, 9,12,10,13,11,14,12,14,13,17, 8, 8, 8,
+ 8, 9, 9, 9, 9,10,10,11,11,13,13,13,14,16,15,17,
+ 12,12, 8, 8, 9, 9,10,10,11,11,12,11,13,12,13,12,
+ 14,13,16,12,12, 8, 8, 9, 9,10,10,11,11,12,12,13,
+ 13,14,14,15,15,17,17,17, 9, 9, 9, 9,11,11,12,12,
+ 12,13,13,13,16,14,14,14,17,17,17, 9, 8, 9, 8,11,
+ 10,12,12,13,13,14,14,15,15,16,16,17,17,17,12,12,
+ 10,10,11,12,12,13,13,14,13,15,15,14,16,15,17,17,
+ 17,12,12,10, 8,12, 9,13,12,14,14,15,14,15,16,16,
+ 16,17,17,17,17,17,11,11,12,12,14,14,14,16,15,16,
+ 15,16,15,17,17,17,17,17,17,11, 9,12,10,13,11,15,
+ 14,16,16,17,16,16,15,17,17,17,17,17,15,15,12,12,
+ 14,14,15,16,16,15,16,16,17,17,17,17,17,17,17,14,
+ 14,12,10,14,11,15,12,17,16,15,16,17,16,17,17,17,
+ 17,17,17,17,13,13,14,14,14,16,17,17,16,17,17,17,
+ 17,17,17,17,17,17,17,13, 9,13,12,15,13,16,16,17,
+ 17,17,17,17,17,17,17,17,17,17,15,17,14,14,15,16,
+ 16,17,16,17,16,17,17,17,17,17,17,17,17,17,17,14,
+ 13,15,16,16,17,16,17,17,17,
+};
+
+static const static_codebook _16c2_s_p9_1 = {
+ 2, 361,
+ (char *)_vq_lengthlist__16c2_s_p9_1,
+ 1, -518287360, 1622704128, 5, 0,
+ (long *)_vq_quantlist__16c2_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__16c2_s_p9_2[] = {
+ 24,
+ 23,
+ 25,
+ 22,
+ 26,
+ 21,
+ 27,
+ 20,
+ 28,
+ 19,
+ 29,
+ 18,
+ 30,
+ 17,
+ 31,
+ 16,
+ 32,
+ 15,
+ 33,
+ 14,
+ 34,
+ 13,
+ 35,
+ 12,
+ 36,
+ 11,
+ 37,
+ 10,
+ 38,
+ 9,
+ 39,
+ 8,
+ 40,
+ 7,
+ 41,
+ 6,
+ 42,
+ 5,
+ 43,
+ 4,
+ 44,
+ 3,
+ 45,
+ 2,
+ 46,
+ 1,
+ 47,
+ 0,
+ 48,
+};
+
+static const char _vq_lengthlist__16c2_s_p9_2[] = {
+ 2, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6,
+ 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7,
+};
+
+static const static_codebook _16c2_s_p9_2 = {
+ 1, 49,
+ (char *)_vq_lengthlist__16c2_s_p9_2,
+ 1, -526909440, 1611661312, 6, 0,
+ (long *)_vq_quantlist__16c2_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__16c2_s_short[] = {
+ 7,10,12,11,12,13,15,16,18,15,10, 8, 8, 8, 9,10,
+ 12,13,14,17,10, 7, 7, 7, 7, 8,10,12,15,18,10, 7,
+ 7, 5, 5, 6, 8,10,13,15,10, 7, 6, 5, 4, 4, 6, 9,
+ 12,15,11, 7, 7, 5, 4, 3, 4, 7,11,13,12, 9, 8, 7,
+ 5, 4, 4, 5,10,13,11,11,11, 9, 7, 5, 5, 5, 9,12,
+ 13,12,13,12,10, 8, 8, 7, 9,13,14,14,14,14,13,11,
+ 11,10,10,13,
+};
+
+static const static_codebook _huff_book__16c2_s_short = {
+ 2, 100,
+ (char *)_huff_lengthlist__16c2_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__8c0_s_p1_0[] = {
+ 1, 5, 4, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 5, 7, 7, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 7, 8, 9, 0, 0, 0,
+ 0, 0, 0, 7, 8, 9, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 7, 9, 8, 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, 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, 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, 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, 5, 8, 8, 0, 0, 0, 0,
+ 0, 0, 8,10,10, 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 7,10, 9, 0, 0, 0,
+ 0, 0, 0, 8, 9,11, 0, 0, 0, 0, 0, 0, 9,11,11, 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, 7, 9,10, 0, 0,
+ 0, 0, 0, 0, 9,11,10, 0, 0, 0, 0, 0, 0, 9,11,11,
+ 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, 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, 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, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8, 9,10, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,11,11, 0,
+ 0, 0, 0, 0, 0, 9,10,11, 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, 7, 9,10, 0, 0, 0, 0, 0, 0, 9,11,11,
+ 0, 0, 0, 0, 0, 0, 8,11, 9, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _8c0_s_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__8c0_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__8c0_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__8c0_s_p3_0[] = {
+ 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 5, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 7, 8, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 7, 7, 8, 8, 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, 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, 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, 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,
+};
+
+static const static_codebook _8c0_s_p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__8c0_s_p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__8c0_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__8c0_s_p4_0[] = {
+ 1, 2, 3, 7, 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7,
+ 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0,
+ 8, 8, 0, 0, 0, 0, 0, 0, 0, 9, 8, 0, 0, 0, 0, 0,
+ 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _8c0_s_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__8c0_s_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__8c0_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__8c0_s_p5_0[] = {
+ 1, 3, 3, 5, 5, 7, 6, 8, 8, 0, 0, 0, 7, 7, 7, 7,
+ 8, 8, 0, 0, 0, 7, 7, 7, 7, 8, 9, 0, 0, 0, 8, 8,
+ 8, 8, 9, 9, 0, 0, 0, 8, 8, 8, 8, 9, 9, 0, 0, 0,
+ 9, 9, 8, 8,10,10, 0, 0, 0, 9, 9, 8, 8,10,10, 0,
+ 0, 0,10,10, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,
+};
+
+static const static_codebook _8c0_s_p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__8c0_s_p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__8c0_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p6_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__8c0_s_p6_0[] = {
+ 1, 3, 3, 6, 6, 8, 8, 9, 9, 8, 8,10, 9,10,10,11,
+ 11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,11,
+ 11,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11,12,11, 0, 0, 0, 8, 8, 9, 9,10,10, 9, 9,10,10,
+ 11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10, 9, 9,11,
+ 10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,10,10,
+ 11,11,11,12,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,10,
+ 10,11,11,12,12,13,13, 0, 0, 0,10,10,10,10,11,11,
+ 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0,10, 9,10,
+ 11,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,
+ 10, 9,10,11,12,12,13,13,14,13, 0, 0, 0, 0, 0, 9,
+ 9, 9,10,10,10,11,11,13,12,13,13, 0, 0, 0, 0, 0,
+ 10,10,10,10,11,11,12,12,13,13,14,14, 0, 0, 0, 0,
+ 0, 0, 0,10,10,11,11,12,12,13,13,13,14, 0, 0, 0,
+ 0, 0, 0, 0,11,11,11,11,12,12,13,14,14,14, 0, 0,
+ 0, 0, 0, 0, 0,11,11,11,11,12,12,13,13,14,13, 0,
+ 0, 0, 0, 0, 0, 0,11,11,12,12,13,13,14,14,14,14,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,14,
+ 14,
+};
+
+static const static_codebook _8c0_s_p6_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__8c0_s_p6_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__8c0_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__8c0_s_p7_0[] = {
+ 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,11, 9,10,12,
+ 9,10, 4, 7, 7,10,10,10,11, 9, 9, 6,11,10,11,11,
+ 12,11,11,11, 6,10,10,11,11,12,11,10,10, 6, 9,10,
+ 11,11,11,11,10,10, 7,10,11,12,11,11,12,11,12, 6,
+ 9, 9,10, 9, 9,11,10,10, 6, 9, 9,10,10,10,11,10,
+ 10,
+};
+
+static const static_codebook _8c0_s_p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__8c0_s_p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__8c0_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__8c0_s_p7_1[] = {
+ 1, 3, 3, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10, 7, 7,
+ 8, 8, 9, 9, 9, 9,10,10, 9, 7, 7, 8, 8, 9, 9, 9,
+ 9,10,10,10, 8, 8, 9, 9, 9, 9, 9, 9,10,10,10, 8,
+ 8, 9, 9, 9, 9, 8, 9,10,10,10, 8, 8, 9, 9, 9,10,
+ 10,10,10,10,10, 9, 9, 9, 9, 9, 9,10,10,11,10,11,
+ 9, 9, 9, 9,10,10,10,10,11,11,11,10,10, 9, 9,10,
+ 10,10, 9,11,10,10,10,10,10,10, 9, 9,10,10,11,11,
+ 10,10,10, 9, 9, 9,10,10,10,
+};
+
+static const static_codebook _8c0_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__8c0_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__8c0_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p8_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__8c0_s_p8_0[] = {
+ 1, 4, 4, 7, 6, 7, 7, 7, 7, 8, 8, 9, 9, 7, 6, 6,
+ 7, 7, 8, 8, 7, 7, 8, 9,10,10, 7, 6, 6, 7, 7, 8,
+ 7, 7, 7, 9, 9,10,12, 0, 8, 8, 8, 8, 8, 9, 8, 8,
+ 9, 9,10,10, 0, 8, 8, 8, 8, 8, 9, 8, 9, 9, 9,11,
+ 10, 0, 0,13, 9, 8, 9, 9, 9, 9,10,10,11,11, 0,13,
+ 0, 9, 9, 9, 9, 9, 9,11,10,11,11, 0, 0, 0, 8, 9,
+ 10, 9,10,10,13,11,12,12, 0, 0, 0, 8, 9, 9, 9,10,
+ 10,13,12,12,13, 0, 0, 0,12, 0,10,10,12,11,10,11,
+ 12,12, 0, 0, 0,13,13,10,10,10,11,12, 0,13, 0, 0,
+ 0, 0, 0, 0,13,11, 0,12,12,12,13,12, 0, 0, 0, 0,
+ 0, 0,13,13,11,13,13,11,12,
+};
+
+static const static_codebook _8c0_s_p8_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__8c0_s_p8_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__8c0_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p8_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__8c0_s_p8_1[] = {
+ 1, 3, 4, 5, 5, 7, 6, 6, 6, 5, 7, 7, 7, 6, 6, 7,
+ 7, 7, 6, 6, 7, 7, 7, 6, 6,
+};
+
+static const static_codebook _8c0_s_p8_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__8c0_s_p8_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__8c0_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p9_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__8c0_s_p9_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7,
+};
+
+static const static_codebook _8c0_s_p9_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__8c0_s_p9_0,
+ 1, -518803456, 1628680192, 2, 0,
+ (long *)_vq_quantlist__8c0_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p9_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__8c0_s_p9_1[] = {
+ 1, 4, 4, 5, 5,10, 8,11,11,11,11,11,11,11,11, 6,
+ 6, 6, 7, 6,11,10,11,11,11,11,11,11,11,11, 7, 5,
+ 6, 6, 6, 8, 7,11,11,11,11,11,11,11,11,11, 7, 8,
+ 8, 8, 9, 9,11,11,11,11,11,11,11,11,11, 9, 8, 7,
+ 8, 9,11,11,11,11,11,11,11,11,11,11,11,10,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,
+};
+
+static const static_codebook _8c0_s_p9_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__8c0_s_p9_1,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__8c0_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__8c0_s_p9_2[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__8c0_s_p9_2[] = {
+ 1, 5, 5, 7, 7, 8, 7, 8, 8,10,10, 9, 9,10,10,10,
+ 11,11,10,12,11,12,12,12, 9, 8, 8, 8, 8, 8, 9,10,
+ 10,10,10,11,11,11,10,11,11,12,12,11,12, 8, 8, 7,
+ 7, 8, 9,10,10,10, 9,10,10, 9,10,10,11,11,11,11,
+ 11,11, 9, 9, 9, 9, 8, 9,10,10,11,10,10,11,11,12,
+ 10,10,12,12,11,11,10, 9, 9,10, 8, 9,10,10,10, 9,
+ 10,10,11,11,10,11,10,10,10,12,12,12, 9,10, 9,10,
+ 9, 9,10,10,11,11,11,11,10,10,10,11,12,11,12,11,
+ 12,10,11,10,11, 9,10, 9,10, 9,10,10, 9,10,10,11,
+ 10,11,11,11,11,12,11, 9,10,10,10,10,11,11,11,11,
+ 11,10,11,11,11,11,10,12,10,12,12,11,12,10,10,11,
+ 10, 9,11,10,11, 9,10,11,10,10,10,11,11,11,11,12,
+ 12,10, 9, 9,11,10, 9,12,11,10,12,12,11,11,11,11,
+ 10,11,11,12,11,10,12, 9,11,10,11,10,10,11,10,11,
+ 9,10,10,10,11,12,11,11,12,11,10,10,11,11, 9,10,
+ 10,12,10,11,10,10,10, 9,10,10,10,10, 9,10,10,11,
+ 11,11,11,12,11,10,10,10,10,11,11,10,11,11, 9,11,
+ 10,12,10,12,11,10,11,10,10,10,11,10,10,11,11,10,
+ 11,10,10,10,10,11,11,12,10,10,10,11,10,11,12,11,
+ 10,11,10,10,11,11,10,12,10, 9,10,10,11,11,11,10,
+ 12,10,10,11,11,11,10,10,11,10,10,10,11,10,11,10,
+ 12,11,11,10,10,10,12,10,10,11, 9,10,11,11,11,10,
+ 10,11,10,10, 9,11,11,12,12,11,12,11,11,11,11,11,
+ 11, 9,10,11,10,12,10,10,10,10,11,10,10,11,10,10,
+ 12,10,10,10,10,10, 9,12,10,10,10,10,12, 9,11,10,
+ 10,11,10,12,12,10,12,12,12,10,10,10,10, 9,10,11,
+ 10,10,12,10,10,12,11,10,11,10,10,12,11,10,12,10,
+ 10,11, 9,11,10, 9,10, 9,10,
+};
+
+static const static_codebook _8c0_s_p9_2 = {
+ 2, 441,
+ (char *)_vq_lengthlist__8c0_s_p9_2,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__8c0_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__8c0_s_single[] = {
+ 4, 5,18, 7,10, 6, 7, 8, 9,10, 5, 2,18, 5, 7, 5,
+ 6, 7, 8,11,17,17,17,17,17,17,17,17,17,17, 7, 4,
+ 17, 6, 9, 6, 8,10,12,15,11, 7,17, 9, 6, 6, 7, 9,
+ 11,15, 6, 4,17, 6, 6, 4, 5, 8,11,16, 6, 6,17, 8,
+ 6, 5, 6, 9,13,16, 8, 9,17,11, 9, 8, 8,11,13,17,
+ 9,12,17,15,14,13,12,13,14,17,12,15,17,17,17,17,
+ 17,16,17,17,
+};
+
+static const static_codebook _huff_book__8c0_s_single = {
+ 2, 100,
+ (char *)_huff_lengthlist__8c0_s_single,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__8c1_s_p1_0[] = {
+ 1, 5, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 5, 7, 7, 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, 5, 8, 7, 0, 0, 0, 0, 0, 0, 7, 8, 9, 0, 0, 0,
+ 0, 0, 0, 7, 8, 9, 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, 5, 7, 8, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0,
+ 0, 0, 0, 0, 7, 9, 8, 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, 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, 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, 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, 5, 8, 8, 0, 0, 0, 0,
+ 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 7, 9, 9, 0, 0, 0,
+ 0, 0, 0, 8, 8,10, 0, 0, 0, 0, 0, 0, 9,10,10, 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, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 9,10,10,
+ 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, 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, 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, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8, 9, 9, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, 0,
+ 0, 0, 0, 0, 0, 8, 9,10, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10,
+ 0, 0, 0, 0, 0, 0, 8,10, 8, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _8c1_s_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__8c1_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__8c1_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__8c1_s_p3_0[] = {
+ 2, 4, 4, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 7, 7,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 6, 6, 7, 7, 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, 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, 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, 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,
+};
+
+static const static_codebook _8c1_s_p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__8c1_s_p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__8c1_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__8c1_s_p4_0[] = {
+ 1, 2, 3, 7, 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7,
+ 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0,
+ 8, 8, 0, 0, 0, 0, 0, 0, 0, 9, 8, 0, 0, 0, 0, 0,
+ 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _8c1_s_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__8c1_s_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__8c1_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__8c1_s_p5_0[] = {
+ 1, 3, 3, 4, 5, 6, 6, 8, 8, 0, 0, 0, 8, 8, 7, 7,
+ 9, 9, 0, 0, 0, 8, 8, 7, 7, 9, 9, 0, 0, 0, 9,10,
+ 8, 8, 9, 9, 0, 0, 0,10,10, 8, 8, 9, 9, 0, 0, 0,
+ 11,10, 8, 8,10,10, 0, 0, 0,11,11, 8, 8,10,10, 0,
+ 0, 0,12,12, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,
+};
+
+static const static_codebook _8c1_s_p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__8c1_s_p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__8c1_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p6_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__8c1_s_p6_0[] = {
+ 1, 3, 3, 5, 5, 8, 8, 8, 8, 9, 9,10,10,11,11,11,
+ 11, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,11,
+ 12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11,12,12, 0, 0, 0, 9, 9, 8, 8,10,10,10,10,11,11,
+ 12,12,12,12, 0, 0, 0, 9, 9, 8, 8,10,10,10,10,11,
+ 11,12,12,12,12, 0, 0, 0,10,10, 9, 9,10,10,10,10,
+ 11,11,12,12,13,13, 0, 0, 0,10,10, 9, 9,10,10,10,
+ 10,11,11,12,12,13,13, 0, 0, 0,11,11, 9, 9,10,10,
+ 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,
+ 10,10,11,11,12,12,12,12,13,13, 0, 0, 0, 0, 0, 9,
+ 9,10,10,11,11,12,11,12,12,13,13, 0, 0, 0, 0, 0,
+ 10,10,11,11,11,11,12,12,13,12,13,13, 0, 0, 0, 0,
+ 0, 0, 0,11,10,11,11,12,12,13,13,13,13, 0, 0, 0,
+ 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,14, 0, 0,
+ 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,14,13, 0,
+ 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,13,14,14,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,13,13,13,14,
+ 14,
+};
+
+static const static_codebook _8c1_s_p6_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__8c1_s_p6_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__8c1_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__8c1_s_p7_0[] = {
+ 1, 4, 4, 6, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,10,
+ 9, 9, 5, 7, 7,10, 9, 9,10, 9, 9, 6,10,10,10,10,
+ 10,11,10,10, 6, 9, 9,10, 9,10,11,10,10, 6, 9, 9,
+ 10, 9, 9,11, 9,10, 7,10,10,11,11,11,11,10,10, 6,
+ 9, 9,10,10,10,11, 9, 9, 6, 9, 9,10,10,10,10, 9,
+ 9,
+};
+
+static const static_codebook _8c1_s_p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__8c1_s_p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__8c1_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__8c1_s_p7_1[] = {
+ 2, 3, 3, 5, 5, 7, 7, 7, 7, 7, 7,10,10, 9, 7, 7,
+ 7, 7, 8, 8, 8, 8, 9, 9, 9, 7, 7, 7, 7, 8, 8, 8,
+ 8,10,10,10, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7,
+ 7, 7, 7, 8, 8, 8, 8,10,10,10, 8, 8, 8, 8, 8, 8,
+ 8, 8,10,10,10, 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,
+ 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8,
+ 8, 8, 8,10,10,10,10,10, 8, 8, 8, 8, 8, 8,10,10,
+ 10,10,10, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _8c1_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__8c1_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__8c1_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p8_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__8c1_s_p8_0[] = {
+ 1, 4, 4, 6, 6, 8, 8, 8, 8, 9, 9,10,10, 7, 5, 5,
+ 7, 7, 8, 8, 8, 8, 9,10,11,11, 7, 5, 5, 7, 7, 8,
+ 8, 9, 9,10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,12,12, 9, 9, 9, 9,10, 9,10,11,11,11, 0,13,
+ 12, 9, 8, 9, 9,10,10,11,11,12,11, 0, 0, 0, 9, 9,
+ 9, 9,10,10,11,11,12,12, 0, 0, 0,10,10, 9, 9,10,
+ 10,11,11,12,12, 0, 0, 0,13,13,10,10,11,11,12,11,
+ 13,12, 0, 0, 0,14,14,10,10,11,10,11,11,12,12, 0,
+ 0, 0, 0, 0,12,12,11,11,12,12,13,13, 0, 0, 0, 0,
+ 0,12,12,11,10,12,11,13,12,
+};
+
+static const static_codebook _8c1_s_p8_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__8c1_s_p8_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__8c1_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p8_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__8c1_s_p8_1[] = {
+ 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6,
+ 6, 6, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _8c1_s_p8_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__8c1_s_p8_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__8c1_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p9_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__8c1_s_p9_0[] = {
+ 1, 3, 3,10,10,10,10,10,10,10,10,10,10, 5, 6, 6,
+ 10,10,10,10,10,10,10,10,10,10, 6, 7, 8,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10, 9, 9, 9, 9,
+};
+
+static const static_codebook _8c1_s_p9_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__8c1_s_p9_0,
+ 1, -513964032, 1628680192, 4, 0,
+ (long *)_vq_quantlist__8c1_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p9_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__8c1_s_p9_1[] = {
+ 1, 4, 4, 5, 5, 7, 7, 9, 9,11,11,12,12,13,13, 6,
+ 5, 5, 6, 6, 9, 9,10,10,12,12,12,13,15,14, 6, 5,
+ 5, 7, 7, 9, 9,10,10,12,12,12,13,14,13,17, 7, 7,
+ 8, 8,10,10,11,11,12,13,13,13,13,13,17, 7, 7, 8,
+ 8,10,10,11,11,13,13,13,13,14,14,17,11,11, 9, 9,
+ 11,11,12,12,12,13,13,14,15,13,17,12,12, 9, 9,11,
+ 11,12,12,13,13,13,13,14,16,17,17,17,11,12,12,12,
+ 13,13,13,14,15,14,15,15,17,17,17,12,12,11,11,13,
+ 13,14,14,15,14,15,15,17,17,17,15,15,13,13,14,14,
+ 15,14,15,15,16,15,17,17,17,15,15,13,13,13,14,14,
+ 15,15,15,15,16,17,17,17,17,16,14,15,14,14,15,14,
+ 14,15,15,15,17,17,17,17,17,14,14,16,14,15,15,15,
+ 15,15,15,17,17,17,17,17,17,16,16,15,17,15,15,14,
+ 17,15,17,16,17,17,17,17,16,15,14,15,15,15,15,15,
+ 15,
+};
+
+static const static_codebook _8c1_s_p9_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__8c1_s_p9_1,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__8c1_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__8c1_s_p9_2[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__8c1_s_p9_2[] = {
+ 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 8, 9, 9, 9,
+ 9, 9, 9, 9, 9,11,11,12, 7, 7, 7, 7, 8, 8, 9, 9,
+ 9, 9,10,10,10,10,10,10,10,10,11,11,11, 7, 7, 7,
+ 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9,10,10,10,10,11,
+ 11,12, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10,10,
+ 10,10,10,10,11,11,11, 7, 7, 8, 8, 8, 8, 9, 9, 9,
+ 9,10,10,10,10,10,10,10,10,11,11,11, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,11,11,
+ 11, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,10,10,10,10,10,
+ 10,10,10,11,12,11, 9, 9, 8, 9, 9, 9, 9, 9,10,10,
+ 10,10,10,10,10,10,10,10,11,11,11,11,11, 8, 8, 9,
+ 9, 9, 9,10,10,10,10,10,10,10,10,10,10,11,12,11,
+ 12,11, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,
+ 10,10,11,11,11,11,11, 9, 9, 9, 9,10,10,10,10,10,
+ 10,10,10,10,10,10,10,12,11,12,11,11, 9, 9, 9,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,12,11,11,11,
+ 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 11,11,11,12,11,11,12,11,10,10,10,10,10,10,10,10,
+ 10,10,10,10,11,10,11,11,11,11,11,11,11,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,11,11,12,11,12,
+ 11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 11,11,12,11,12,11,11,11,11,10,10,10,10,10,10,10,
+ 10,10,10,10,10,11,11,12,11,11,12,11,11,12,10,10,
+ 11,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,
+ 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,12,
+ 12,11,12,11,11,12,12,12,11,11,10,10,10,10,10,10,
+ 10,10,10,11,12,12,11,12,12,11,12,11,11,11,11,10,
+ 10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _8c1_s_p9_2 = {
+ 2, 441,
+ (char *)_vq_lengthlist__8c1_s_p9_2,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__8c1_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__8c1_s_single[] = {
+ 4, 6,18, 8,11, 8, 8, 9, 9,10, 4, 4,18, 5, 9, 5,
+ 6, 7, 8,10,18,18,18,18,17,17,17,17,17,17, 7, 5,
+ 17, 6,11, 6, 7, 8, 9,12,12, 9,17,12, 8, 8, 9,10,
+ 10,13, 7, 5,17, 6, 8, 4, 5, 6, 8,10, 6, 5,17, 6,
+ 8, 5, 4, 5, 7, 9, 7, 7,17, 8, 9, 6, 5, 5, 6, 8,
+ 8, 8,17, 9,11, 8, 6, 6, 6, 7, 9,10,17,12,12,10,
+ 9, 7, 7, 8,
+};
+
+static const static_codebook _huff_book__8c1_s_single = {
+ 2, 100,
+ (char *)_huff_lengthlist__8c1_s_single,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c2_s_long[] = {
+ 6, 6,12,10,10,10, 9,10,12,12, 6, 1,10, 5, 6, 6,
+ 7, 9,11,14,12, 9, 8,11, 7, 8, 9,11,13,15,10, 5,
+ 12, 7, 8, 7, 9,12,14,15,10, 6, 7, 8, 5, 6, 7, 9,
+ 12,14, 9, 6, 8, 7, 6, 6, 7, 9,12,12, 9, 7, 9, 9,
+ 7, 6, 6, 7,10,10,10, 9,10,11, 8, 7, 6, 6, 8,10,
+ 12,11,13,13,11,10, 8, 8, 8,10,11,13,15,15,14,13,
+ 10, 8, 8, 9,
+};
+
+static const static_codebook _huff_book__44c2_s_long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c2_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c2_s_p1_0[] = {
+ 2, 4, 4, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 0,
+ 0, 0, 5, 6, 7, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0,
+ 0, 0, 0, 6, 8, 8, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 6, 8, 7, 0, 0,
+ 0, 0, 0, 0, 7, 8, 8, 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, 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, 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, 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, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 7, 8, 8, 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, 7, 8, 8, 0, 0, 0,
+ 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 6, 8, 8, 0, 0,
+ 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9,
+ 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, 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, 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, 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, 4, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0,
+ 0, 0, 0, 0, 7, 8, 8, 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, 6, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0,
+ 0, 0, 0, 0, 0, 8, 8, 9, 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, 7, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9,
+ 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c2_s_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__44c2_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c2_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c2_s_p2_0[] = {
+ 1, 4, 4, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0,
+ 8, 8, 0, 0, 0, 0, 0, 0, 0, 4, 6, 6, 0, 0, 0, 8,
+ 8, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0,
+ 0, 0, 4, 6, 6, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, 0,
+ 0, 0, 9, 9, 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, 7, 8, 8, 0, 0, 0,11,11, 0, 0,
+ 0,11,11, 0, 0, 0,12,11, 0, 0, 0, 0, 0, 0, 0, 7,
+ 8, 8, 0, 0, 0,10,11, 0, 0, 0,11,11, 0, 0, 0,11,
+ 12, 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, 6, 8, 8, 0, 0, 0,11,11, 0, 0, 0,11,11,
+ 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 6, 8, 8, 0,
+ 0, 0,10,11, 0, 0, 0,10,11, 0, 0, 0,11,11, 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,
+ 8, 9, 9, 0, 0, 0,11,12, 0, 0, 0,11,12, 0, 0, 0,
+ 12,11, 0, 0, 0, 0, 0, 0, 0, 8,10, 9, 0, 0, 0,12,
+ 11, 0, 0, 0,12,11, 0, 0, 0,11,12, 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,
+ 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,
+};
+
+static const static_codebook _44c2_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c2_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c2_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c2_s_p3_0[] = {
+ 2, 4, 3, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 9, 9,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 6, 7, 9, 9, 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, 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, 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, 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,
+};
+
+static const static_codebook _44c2_s_p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c2_s_p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c2_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c2_s_p4_0[] = {
+ 1, 3, 3, 6, 6, 0, 0, 0, 0, 0, 6, 6, 6, 6, 0, 0,
+ 0, 0, 0, 6, 6, 6, 6, 0, 0, 0, 0, 0, 7, 7, 6, 6,
+ 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0,
+ 7, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0,
+ 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c2_s_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c2_s_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c2_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c2_s_p5_0[] = {
+ 1, 3, 3, 6, 6, 7, 7, 9, 9, 0, 7, 7, 7, 7, 7, 7,
+ 9, 9, 0, 7, 7, 7, 7, 7, 7, 9, 9, 0, 8, 8, 7, 7,
+ 8, 8,10,10, 0, 0, 0, 7, 7, 8, 8,10,10, 0, 0, 0,
+ 9, 9, 8, 8,10,10, 0, 0, 0, 9, 9, 8, 8,10,10, 0,
+ 0, 0,10,10, 9, 9,11,11, 0, 0, 0, 0, 0, 9, 9,11,
+ 11,
+};
+
+static const static_codebook _44c2_s_p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c2_s_p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c2_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p6_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c2_s_p6_0[] = {
+ 1, 4, 3, 6, 6, 8, 8, 9, 9, 9, 9, 9, 9,10,10,11,
+ 11, 0, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,11,
+ 12,11, 0, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11,11,12, 0, 8, 8, 7, 7, 9, 9,10,10, 9, 9,10,10,
+ 11,11,12,12, 0, 0, 0, 7, 7, 9, 9,10,10,10, 9,10,
+ 10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10,
+ 11,11,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,
+ 10,11,11,12,12,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,
+ 10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,
+ 10,10,11,11,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9,
+ 9,10,10,11,11,11,11,12,12,13,13, 0, 0, 0, 0, 0,
+ 10,10,10,10,11,11,12,12,13,12,13,13, 0, 0, 0, 0,
+ 0, 0, 0,10,10,11,11,12,12,13,13,13,13, 0, 0, 0,
+ 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,14, 0, 0,
+ 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,14, 0,
+ 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,13,14,14,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,13,13,13,14,
+ 14,
+};
+
+static const static_codebook _44c2_s_p6_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c2_s_p6_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c2_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c2_s_p7_0[] = {
+ 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11,
+ 9, 9, 4, 7, 7,10, 9, 9,10, 9, 9, 7,10,10,11,10,
+ 11,11,10,11, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9,
+ 11,10,11,11,10,10, 7,11,10,11,11,11,12,11,11, 6,
+ 9, 9,11,10,10,11,11,10, 6, 9, 9,11,10,10,12,10,
+ 11,
+};
+
+static const static_codebook _44c2_s_p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c2_s_p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c2_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c2_s_p7_1[] = {
+ 2, 3, 4, 6, 6, 7, 7, 7, 7, 7, 7, 9, 7, 7, 6, 6,
+ 7, 7, 8, 8, 8, 8, 9, 6, 6, 6, 6, 7, 7, 8, 8, 8,
+ 8,10, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7,
+ 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, 7, 8, 8, 8, 8,
+ 8, 8,10,10,10, 7, 8, 8, 8, 8, 8, 8, 8,10,10,10,
+ 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8,
+ 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10,
+ 10,10,10, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44c2_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c2_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c2_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p8_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c2_s_p8_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 6, 5, 5,
+ 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 6, 5, 7, 7, 8,
+ 8, 8, 8, 9, 9,10,10, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,12,12, 9, 9,10,10,10,10,11,11,11,11, 0,13,
+ 13, 9, 9,10,10,10,10,11,11,12,12, 0, 0, 0,10,10,
+ 10,10,11,11,12,12,12,13, 0, 0, 0,10,10,10,10,11,
+ 11,12,12,12,12, 0, 0, 0,14,14,10,11,11,11,12,12,
+ 13,13, 0, 0, 0,14,14,11,10,11,11,13,12,13,13, 0,
+ 0, 0, 0, 0,12,12,11,12,13,12,14,14, 0, 0, 0, 0,
+ 0,12,12,12,12,13,12,14,14,
+};
+
+static const static_codebook _44c2_s_p8_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c2_s_p8_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c2_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p8_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c2_s_p8_1[] = {
+ 2, 4, 4, 5, 4, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6,
+ 5, 5, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44c2_s_p8_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c2_s_p8_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c2_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p9_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c2_s_p9_0[] = {
+ 1, 5, 4,12,12,12,12,12,12,12,12,12,12, 4, 9, 8,
+ 11,11,11,11,11,11,11,11,11,11, 2, 8, 7,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,
+};
+
+static const static_codebook _44c2_s_p9_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c2_s_p9_0,
+ 1, -514541568, 1627103232, 4, 0,
+ (long *)_vq_quantlist__44c2_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p9_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c2_s_p9_1[] = {
+ 1, 4, 4, 6, 6, 7, 6, 8, 8,10, 9,10,10, 6, 5, 5,
+ 7, 7, 8, 7,10, 9,11,11,12,13, 6, 5, 5, 7, 7, 8,
+ 8,10,10,11,11,13,13,18, 8, 8, 8, 8, 9, 9,10,10,
+ 12,12,12,13,18, 8, 8, 8, 8, 9, 9,10,10,12,12,13,
+ 13,18,11,11, 8, 8,10,10,11,11,12,11,13,12,18,11,
+ 11, 9, 7,10,10,11,11,11,12,12,13,17,17,17,10,10,
+ 11,11,12,12,12,10,12,12,17,17,17,11,10,11,10,13,
+ 12,11,12,12,12,17,17,17,15,14,11,11,12,11,13,10,
+ 13,12,17,17,17,14,14,12,10,11,11,13,13,13,13,17,
+ 17,16,17,16,13,13,12,10,13,10,14,13,17,16,17,16,
+ 17,13,12,12,10,13,11,14,14,
+};
+
+static const static_codebook _44c2_s_p9_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c2_s_p9_1,
+ 1, -522616832, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44c2_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44c2_s_p9_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c2_s_p9_2[] = {
+ 2, 4, 4, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8,
+ 8,10, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9,10, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9,10, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10, 8, 7, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9, 9,10,11,11, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9,10, 9, 9, 9,10,11,10, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10,10,11,10, 8, 8, 9, 9, 9, 9,
+ 9, 9,10, 9, 9,10, 9,10,11,10,11,11,11, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9,10,10,11,11,11,11,11, 9, 9,
+ 9, 9, 9, 9,10, 9, 9, 9,10,10,11,11,11,11,11, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10,11,11,11,11,11,
+ 9, 9, 9, 9,10,10, 9, 9, 9,10,10,10,11,11,11,11,
+ 11,11,11, 9, 9, 9,10, 9, 9,10,10,10,10,11,11,10,
+ 11,11,11,11,10, 9,10,10, 9, 9, 9, 9,10,10,11,10,
+ 11,11,11,11,11, 9, 9, 9, 9,10, 9,10,10,10,10,11,
+ 10,11,11,11,11,11,10,10, 9, 9,10, 9,10,10,10,10,
+ 10,10,10,11,11,11,11,11,11, 9, 9,10, 9,10, 9,10,
+ 10,
+};
+
+static const static_codebook _44c2_s_p9_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c2_s_p9_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c2_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c2_s_short[] = {
+ 11, 9,13,12,12,11,12,12,13,15, 8, 2,11, 4, 8, 5,
+ 7,10,12,15,13, 7,10, 9, 8, 8,10,13,17,17,11, 4,
+ 12, 5, 9, 5, 8,11,14,16,12, 6, 8, 7, 6, 6, 8,11,
+ 13,16,11, 4, 9, 5, 6, 4, 6,10,13,16,11, 6,11, 7,
+ 7, 6, 7,10,13,15,13, 9,12, 9, 8, 6, 8,10,12,14,
+ 14,10,10, 8, 6, 5, 6, 9,11,13,15,11,11, 9, 6, 5,
+ 6, 8, 9,12,
+};
+
+static const static_codebook _huff_book__44c2_s_short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c2_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c3_s_long[] = {
+ 5, 6,11,11,11,11,10,10,12,11, 5, 2,11, 5, 6, 6,
+ 7, 9,11,13,13,10, 7,11, 6, 7, 8, 9,10,12,11, 5,
+ 11, 6, 8, 7, 9,11,14,15,11, 6, 6, 8, 4, 5, 7, 8,
+ 10,13,10, 5, 7, 7, 5, 5, 6, 8,10,11,10, 7, 7, 8,
+ 6, 5, 5, 7, 9, 9,11, 8, 8,11, 8, 7, 6, 6, 7, 9,
+ 12,11,10,13, 9, 9, 7, 7, 7, 9,11,13,12,15,12,11,
+ 9, 8, 8, 8,
+};
+
+static const static_codebook _huff_book__44c3_s_long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c3_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c3_s_p1_0[] = {
+ 2, 4, 4, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 0,
+ 0, 0, 5, 6, 6, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0,
+ 0, 0, 0, 6, 7, 8, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 6, 8, 7, 0, 0,
+ 0, 0, 0, 0, 7, 8, 8, 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, 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, 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, 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, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 7, 8, 8, 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, 7, 8, 8, 0, 0, 0,
+ 0, 0, 0, 8, 8, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 6, 8, 8, 0, 0,
+ 0, 0, 0, 0, 7, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9,
+ 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, 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, 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, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0,
+ 0, 0, 0, 0, 7, 8, 8, 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, 6, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0,
+ 0, 0, 0, 0, 0, 7, 8, 9, 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, 6, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9,
+ 0, 0, 0, 0, 0, 0, 8, 9, 8, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c3_s_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__44c3_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c3_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c3_s_p2_0[] = {
+ 2, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0,
+ 7, 8, 0, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 7,
+ 7, 0, 0, 0, 7, 7, 0, 0, 0,10,10, 0, 0, 0, 0, 0,
+ 0, 0, 5, 6, 6, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0,
+ 0, 0,10,10, 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, 5, 7, 7, 0, 0, 0, 7, 7, 0, 0,
+ 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 5,
+ 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 9,
+ 9, 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, 5, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7,
+ 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0,
+ 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 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,
+ 8,10,10, 0, 0, 0, 9, 9, 0, 0, 0, 9, 9, 0, 0, 0,
+ 10,10, 0, 0, 0, 0, 0, 0, 0, 8,10,10, 0, 0, 0, 9,
+ 9, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 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,
+ 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,
+};
+
+static const static_codebook _44c3_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c3_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c3_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c3_s_p3_0[] = {
+ 2, 4, 3, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 9, 9,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 6, 7, 9, 9, 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, 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, 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, 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,
+};
+
+static const static_codebook _44c3_s_p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c3_s_p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c3_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c3_s_p4_0[] = {
+ 2, 3, 3, 6, 6, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0,
+ 0, 0, 0, 4, 4, 6, 6, 0, 0, 0, 0, 0, 5, 5, 6, 6,
+ 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0,
+ 7, 8, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0,
+ 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c3_s_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c3_s_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c3_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c3_s_p5_0[] = {
+ 1, 3, 4, 6, 6, 7, 7, 9, 9, 0, 5, 5, 7, 7, 7, 8,
+ 9, 9, 0, 5, 5, 7, 7, 8, 8, 9, 9, 0, 7, 7, 8, 8,
+ 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, 0, 0,
+ 9, 9, 9, 9,10,10, 0, 0, 0, 9, 9, 9, 9,10,10, 0,
+ 0, 0,10,10,10,10,11,11, 0, 0, 0, 0, 0,10,10,11,
+ 11,
+};
+
+static const static_codebook _44c3_s_p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c3_s_p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c3_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p6_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c3_s_p6_0[] = {
+ 2, 3, 3, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11,
+ 10, 0, 5, 5, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,10,
+ 11,11, 0, 5, 5, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,
+ 10,11,11, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,11,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9,
+ 9,10,10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,
+ 10,10,11,10,11,11,12,12, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9, 8,
+ 9, 9,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 8,
+ 8, 9, 9,10,10,11,11,12,11,12,12, 0, 0, 0, 0, 0,
+ 9,10,10,10,11,11,11,11,12,12,13,13, 0, 0, 0, 0,
+ 0, 0, 0,10,10,10,10,11,11,12,12,13,13, 0, 0, 0,
+ 0, 0, 0, 0,11,11,11,11,12,12,12,12,13,13, 0, 0,
+ 0, 0, 0, 0, 0,11,11,11,11,12,12,12,12,13,13, 0,
+ 0, 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,13,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,
+ 13,
+};
+
+static const static_codebook _44c3_s_p6_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c3_s_p6_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c3_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c3_s_p7_0[] = {
+ 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11,
+ 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 7,10,10,11,11,
+ 10,12,11,11, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9,
+ 11,10,10,11,10,10, 7,11,11,11,11,11,12,11,11, 6,
+ 9, 9,11,10,10,11,10,10, 6, 9, 9,11,10,10,11,10,
+ 10,
+};
+
+static const static_codebook _44c3_s_p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c3_s_p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c3_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c3_s_p7_1[] = {
+ 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8,10, 5, 5, 6, 6,
+ 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6, 7, 7, 8, 8, 8,
+ 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7,
+ 7, 8, 7, 8, 8, 8, 8,10,10,10, 8, 8, 8, 8, 8, 8,
+ 8, 8,10,10,10, 7, 8, 8, 8, 8, 8, 8, 8,10,10,10,
+ 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8,
+ 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 9, 8,10,10,
+ 10,10,10, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44c3_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c3_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c3_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p8_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c3_s_p8_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 6, 5, 5,
+ 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 5, 5, 7, 7, 8,
+ 8, 8, 8, 9, 9,11,10, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,12,12, 9, 9,10,10,10,10,11,11,11,12, 0,13,
+ 13, 9, 9,10,10,10,10,11,11,12,12, 0, 0, 0,10,10,
+ 10,10,11,11,12,12,12,12, 0, 0, 0,10,10,10,10,11,
+ 11,12,12,12,12, 0, 0, 0,14,14,11,11,11,11,12,12,
+ 13,13, 0, 0, 0,14,14,11,11,11,11,12,12,13,13, 0,
+ 0, 0, 0, 0,12,12,12,12,13,13,14,13, 0, 0, 0, 0,
+ 0,13,13,12,12,13,12,14,13,
+};
+
+static const static_codebook _44c3_s_p8_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c3_s_p8_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c3_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p8_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c3_s_p8_1[] = {
+ 2, 4, 4, 5, 5, 6, 5, 5, 5, 5, 6, 4, 5, 5, 5, 6,
+ 5, 5, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44c3_s_p8_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c3_s_p8_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c3_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p9_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c3_s_p9_0[] = {
+ 1, 4, 4,12,12,12,12,12,12,12,12,12,12, 4, 9, 8,
+ 12,12,12,12,12,12,12,12,12,12, 2, 9, 7,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,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,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,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,
+};
+
+static const static_codebook _44c3_s_p9_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c3_s_p9_0,
+ 1, -514332672, 1627381760, 4, 0,
+ (long *)_vq_quantlist__44c3_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p9_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44c3_s_p9_1[] = {
+ 1, 4, 4, 6, 6, 7, 7, 8, 7, 9, 9,10,10,10,10, 6,
+ 5, 5, 7, 7, 8, 8,10, 8,11,10,12,12,13,13, 6, 5,
+ 5, 7, 7, 8, 8,10, 9,11,11,12,12,13,12,18, 8, 8,
+ 8, 8, 9, 9,10, 9,11,10,12,12,13,13,18, 8, 8, 8,
+ 8, 9, 9,10,10,11,11,13,12,14,13,18,11,11, 9, 9,
+ 10,10,11,11,11,12,13,12,13,14,18,11,11, 9, 8,11,
+ 10,11,11,11,11,12,12,14,13,18,18,18,10,11,10,11,
+ 12,12,12,12,13,12,14,13,18,18,18,10,11,11, 9,12,
+ 11,12,12,12,13,13,13,18,18,17,14,14,11,11,12,12,
+ 13,12,14,12,14,13,18,18,18,14,14,11,10,12, 9,12,
+ 13,13,13,13,13,18,18,17,16,18,13,13,12,12,13,11,
+ 14,12,14,14,17,18,18,17,18,13,12,13,10,12,11,14,
+ 14,14,14,17,18,18,18,18,15,16,12,12,13,10,14,12,
+ 14,15,18,18,18,16,17,16,14,12,11,13,10,13,13,14,
+ 15,
+};
+
+static const static_codebook _44c3_s_p9_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44c3_s_p9_1,
+ 1, -522338304, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44c3_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44c3_s_p9_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c3_s_p9_2[] = {
+ 2, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8,
+ 8,10, 6, 6, 7, 7, 8, 7, 8, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9,10, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9,10, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10, 7, 7, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9,11,11,11, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,10,10,10, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9,10, 9,10,10,10,11,11, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,11,10,11,11,11, 9, 9,
+ 9, 9, 9, 9,10,10, 9, 9,10, 9,11,10,11,11,11, 9,
+ 9, 9, 9, 9, 9, 9, 9,10,10,10, 9,11,11,11,11,11,
+ 9, 9, 9, 9,10,10, 9, 9, 9, 9,10, 9,11,11,11,11,
+ 11,11,11, 9, 9, 9, 9, 9, 9,10,10,10,10,11,11,11,
+ 11,11,11,11,10, 9,10,10, 9,10, 9, 9,10, 9,11,10,
+ 10,11,11,11,11, 9,10, 9, 9, 9, 9,10,10,10,10,11,
+ 11,11,11,11,11,10,10,10, 9, 9,10, 9,10, 9,10,10,
+ 10,10,11,11,11,11,11,11,11, 9, 9, 9, 9, 9,10,10,
+ 10,
+};
+
+static const static_codebook _44c3_s_p9_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c3_s_p9_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c3_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c3_s_short[] = {
+ 10, 9,13,11,14,10,12,13,13,14, 7, 2,12, 5,10, 5,
+ 7,10,12,14,12, 6, 9, 8, 7, 7, 9,11,13,16,10, 4,
+ 12, 5,10, 6, 8,12,14,16,12, 6, 8, 7, 6, 5, 7,11,
+ 12,16,10, 4, 8, 5, 6, 4, 6, 9,13,16,10, 6,10, 7,
+ 7, 6, 7, 9,13,15,12, 9,11, 9, 8, 6, 7,10,12,14,
+ 14,11,10, 9, 6, 5, 6, 9,11,13,15,13,11,10, 6, 5,
+ 6, 8, 9,11,
+};
+
+static const static_codebook _huff_book__44c3_s_short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c3_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c4_s_long[] = {
+ 4, 7,11,11,11,11,10,11,12,11, 5, 2,11, 5, 6, 6,
+ 7, 9,11,12,11, 9, 6,10, 6, 7, 8, 9,10,11,11, 5,
+ 11, 7, 8, 8, 9,11,13,14,11, 6, 5, 8, 4, 5, 7, 8,
+ 10,11,10, 6, 7, 7, 5, 5, 6, 8, 9,11,10, 7, 8, 9,
+ 6, 6, 6, 7, 8, 9,11, 9, 9,11, 7, 7, 6, 6, 7, 9,
+ 12,12,10,13, 9, 8, 7, 7, 7, 8,11,13,11,14,11,10,
+ 9, 8, 7, 7,
+};
+
+static const static_codebook _huff_book__44c4_s_long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c4_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c4_s_p1_0[] = {
+ 2, 4, 4, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 0,
+ 0, 0, 5, 6, 7, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0,
+ 0, 0, 0, 6, 8, 8, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 6, 8, 7, 0, 0,
+ 0, 0, 0, 0, 7, 8, 8, 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, 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, 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, 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, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 7, 8, 8, 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, 7, 8, 8, 0, 0, 0,
+ 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 6, 8, 8, 0, 0,
+ 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9,
+ 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, 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, 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, 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, 4, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0,
+ 0, 0, 0, 0, 7, 8, 8, 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, 6, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0,
+ 0, 0, 0, 0, 0, 8, 8, 9, 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, 7, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9,
+ 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c4_s_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__44c4_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c4_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c4_s_p2_0[] = {
+ 2, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0,
+ 7, 7, 0, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 7,
+ 7, 0, 0, 0, 7, 7, 0, 0, 0,10,10, 0, 0, 0, 0, 0,
+ 0, 0, 5, 6, 6, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0,
+ 0, 0,10,10, 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, 5, 8, 7, 0, 0, 0, 7, 7, 0, 0,
+ 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 5,
+ 7, 8, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 9,
+ 9, 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, 5, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7,
+ 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0,
+ 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 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,
+ 7,10,10, 0, 0, 0, 9, 9, 0, 0, 0, 9, 9, 0, 0, 0,
+ 10,10, 0, 0, 0, 0, 0, 0, 0, 8,10,10, 0, 0, 0, 9,
+ 9, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 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,
+ 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,
+};
+
+static const static_codebook _44c4_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c4_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c4_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c4_s_p3_0[] = {
+ 2, 3, 3, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 4, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 4, 5, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 9, 9,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 6, 7, 9, 9, 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, 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, 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, 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,
+};
+
+static const static_codebook _44c4_s_p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c4_s_p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c4_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c4_s_p4_0[] = {
+ 2, 3, 3, 6, 6, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0,
+ 0, 0, 0, 4, 4, 6, 6, 0, 0, 0, 0, 0, 5, 5, 6, 6,
+ 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0,
+ 7, 8, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0,
+ 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c4_s_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c4_s_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c4_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c4_s_p5_0[] = {
+ 2, 3, 3, 6, 6, 7, 7, 9, 9, 0, 4, 4, 6, 6, 7, 7,
+ 9, 9, 0, 4, 5, 6, 6, 7, 7, 9, 9, 0, 6, 6, 7, 7,
+ 8, 8,10,10, 0, 0, 0, 7, 7, 8, 8,10, 9, 0, 0, 0,
+ 9, 8, 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0,
+ 0, 0,10,10, 9, 9,11,11, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,
+};
+
+static const static_codebook _44c4_s_p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c4_s_p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c4_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p6_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c4_s_p6_0[] = {
+ 2, 4, 4, 6, 6, 8, 8, 9, 9, 8, 8, 9, 9,10,10,11,
+ 11, 0, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,11,11,
+ 11,11, 0, 4, 4, 7, 6, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11,11,11, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,11,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9,
+ 9,10,10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,
+ 10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9, 9,
+ 9,10,10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9,
+ 9, 9, 9,10,10,11,11,11,12,12,12, 0, 0, 0, 0, 0,
+ 10,10,10,10,11,11,11,11,12,12,13,12, 0, 0, 0, 0,
+ 0, 0, 0,10,10,11,11,11,11,12,12,12,12, 0, 0, 0,
+ 0, 0, 0, 0,11,11,11,11,12,12,12,12,13,13, 0, 0,
+ 0, 0, 0, 0, 0,11,11,11,11,12,12,12,12,13,13, 0,
+ 0, 0, 0, 0, 0, 0,12,12,12,12,12,12,13,13,13,13,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,12,13,13,
+ 13,
+};
+
+static const static_codebook _44c4_s_p6_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c4_s_p6_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c4_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c4_s_p7_0[] = {
+ 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11,
+ 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 7,10,10,11,11,
+ 10,11,11,11, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9,
+ 11,10,10,11,10,10, 7,11,11,12,11,11,12,11,11, 6,
+ 9, 9,11,10,10,11,10,10, 6, 9, 9,11,10,10,11,10,
+ 10,
+};
+
+static const static_codebook _44c4_s_p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c4_s_p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c4_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c4_s_p7_1[] = {
+ 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8,10, 5, 5, 6, 6,
+ 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6, 7, 7, 8, 8, 8,
+ 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7,
+ 7, 8, 8, 8, 8, 8, 8,10,10,10, 8, 7, 8, 8, 8, 8,
+ 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10,
+ 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8,
+ 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 9, 8,10,10,
+ 10,10,10, 8, 8, 8, 8, 9, 9,
+};
+
+static const static_codebook _44c4_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c4_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c4_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p8_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c4_s_p8_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 6, 5, 5,
+ 7, 7, 8, 8, 8, 8, 9,10,11,11, 7, 5, 5, 7, 7, 8,
+ 8, 9, 9,10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,12,12, 9, 9, 9, 9,10,10,10,10,11,11, 0,13,
+ 13, 9, 9,10, 9,10,10,11,11,11,12, 0, 0, 0,10,10,
+ 10,10,10,10,11,11,12,12, 0, 0, 0,10,10,10,10,10,
+ 10,11,11,12,12, 0, 0, 0,14,14,11,11,11,11,12,12,
+ 12,12, 0, 0, 0,14,14,11,11,11,11,12,12,12,13, 0,
+ 0, 0, 0, 0,12,12,12,12,12,12,13,13, 0, 0, 0, 0,
+ 0,13,12,12,12,12,12,13,13,
+};
+
+static const static_codebook _44c4_s_p8_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c4_s_p8_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c4_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p8_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c4_s_p8_1[] = {
+ 2, 4, 4, 5, 5, 6, 5, 5, 5, 5, 6, 5, 4, 5, 5, 6,
+ 5, 5, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44c4_s_p8_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c4_s_p8_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c4_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p9_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c4_s_p9_0[] = {
+ 1, 3, 3,12,12,12,12,12,12,12,12,12,12, 4, 7, 7,
+ 12,12,12,12,12,12,12,12,12,12, 3, 8, 8,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,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,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,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,12,12,12,
+ 12,12,12,12,12,12,12,12,12,
+};
+
+static const static_codebook _44c4_s_p9_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c4_s_p9_0,
+ 1, -513964032, 1628680192, 4, 0,
+ (long *)_vq_quantlist__44c4_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p9_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44c4_s_p9_1[] = {
+ 1, 4, 4, 5, 5, 7, 7, 9, 8,10, 9,10,10,10,10, 6,
+ 5, 5, 7, 7, 9, 8,10, 9,11,10,12,12,13,13, 6, 5,
+ 5, 7, 7, 9, 9,10,10,11,11,12,12,12,13,19, 8, 8,
+ 8, 8, 9, 9,10,10,12,11,12,12,13,13,19, 8, 8, 8,
+ 8, 9, 9,11,11,12,12,13,13,13,13,19,12,12, 9, 9,
+ 11,11,11,11,12,11,13,12,13,13,18,12,12, 9, 9,11,
+ 10,11,11,12,12,12,13,13,14,19,18,18,11,11,11,11,
+ 12,12,13,12,13,13,14,14,16,18,18,11,11,11,10,12,
+ 11,13,13,13,13,13,14,17,18,18,14,15,11,12,12,13,
+ 13,13,13,14,14,14,18,18,18,15,15,12,10,13,10,13,
+ 13,13,13,13,14,18,17,18,17,18,12,13,12,13,13,13,
+ 14,14,16,14,18,17,18,18,17,13,12,13,10,12,12,14,
+ 14,14,14,17,18,18,18,18,14,15,12,12,13,12,14,14,
+ 15,15,18,18,18,17,18,15,14,12,11,12,12,14,14,14,
+ 15,
+};
+
+static const static_codebook _44c4_s_p9_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44c4_s_p9_1,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__44c4_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44c4_s_p9_2[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__44c4_s_p9_2[] = {
+ 2, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8, 9, 9, 9, 9,11, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10,10,10,11, 6, 6, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10,11,
+ 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9,10,10,10,
+ 10,10,10,10,12,11,11, 7, 7, 8, 8, 9, 9, 9, 9, 9,
+ 9,10,10,10,10,10,10,10,10,12,11,12, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,11,11,
+ 11, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10,10,10,10,10,
+ 10,10,10,11,11,12, 9, 9, 9, 9, 9, 9,10, 9,10,10,
+ 10,10,10,10,10,10,10,10,11,11,11,11,11, 9, 9, 9,
+ 9,10,10,10,10,10,10,10,10,10,10,10,10,11,12,11,
+ 11,11, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,11,11,11,11,11, 9, 9, 9, 9,10,10,10,10,10,
+ 10,10,10,10,10,10,10,11,11,11,12,12,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,11,12,11,12,
+ 11,11,11, 9,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,11,12,11,11,11,11,11,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,11,11,11,12,11,11,11,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,12,11,11,12,11,
+ 11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,
+ 10,10,10,10,10,11,11,11,11,12,12,11,11,11,11,11,
+ 11,11,10,10,10,10,10,10,10,10,12,12,12,11,11,11,
+ 12,11,11,11,10,10,10,10,10,10,10,10,10,10,10,12,
+ 11,12,12,12,12,12,11,12,11,11,10,10,10,10,10,10,
+ 10,10,10,10,12,12,12,12,11,11,11,11,11,11,11,10,
+ 10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _44c4_s_p9_2 = {
+ 2, 441,
+ (char *)_vq_lengthlist__44c4_s_p9_2,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c4_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c4_s_short[] = {
+ 4, 7,14,10,15,10,12,15,16,15, 4, 2,11, 5,10, 6,
+ 8,11,14,14,14,10, 7,11, 6, 8,10,11,13,15, 9, 4,
+ 11, 5, 9, 6, 9,12,14,15,14, 9, 6, 9, 4, 5, 7,10,
+ 12,13, 9, 5, 7, 6, 5, 5, 7,10,13,13,10, 8, 9, 8,
+ 7, 6, 8,10,14,14,13,11,10,10, 7, 7, 8,11,14,15,
+ 13,12, 9, 9, 6, 5, 7,10,14,17,15,13,11,10, 6, 6,
+ 7, 9,12,17,
+};
+
+static const static_codebook _huff_book__44c4_s_short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c4_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c5_s_long[] = {
+ 3, 8, 9,13,10,12,12,12,12,12, 6, 4, 6, 8, 6, 8,
+ 10,10,11,12, 8, 5, 4,10, 4, 7, 8, 9,10,11,13, 8,
+ 10, 8, 9, 9,11,12,13,14,10, 6, 4, 9, 3, 5, 6, 8,
+ 10,11,11, 8, 6, 9, 5, 5, 6, 7, 9,11,12, 9, 7,11,
+ 6, 6, 6, 7, 8,10,12,11, 9,12, 7, 7, 6, 6, 7, 9,
+ 13,12,10,13, 9, 8, 7, 7, 7, 8,11,15,11,15,11,10,
+ 9, 8, 7, 7,
+};
+
+static const static_codebook _huff_book__44c5_s_long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c5_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c5_s_p1_0[] = {
+ 2, 4, 4, 0, 0, 0, 0, 0, 0, 4, 7, 7, 0, 0, 0, 0,
+ 0, 0, 4, 6, 7, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0,
+ 0, 0, 0, 7, 8, 9, 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, 4, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0,
+ 0, 0, 0, 0, 7, 9, 9, 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, 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, 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, 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, 4, 7, 7, 0, 0, 0, 0,
+ 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 7, 9, 9, 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, 7, 9, 9, 0, 0, 0,
+ 0, 0, 0, 9,10,11, 0, 0, 0, 0, 0, 0, 9,10,10, 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, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 9,10,11,
+ 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, 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, 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, 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, 4, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 7, 9, 9, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,11,10, 0,
+ 0, 0, 0, 0, 0, 8, 9,10, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10,
+ 0, 0, 0, 0, 0, 0, 9,11,10, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c5_s_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__44c5_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c5_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c5_s_p2_0[] = {
+ 2, 4, 4, 0, 0, 0, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0,
+ 8, 7, 0, 0, 0, 0, 0, 0, 0, 4, 6, 6, 0, 0, 0, 8,
+ 8, 0, 0, 0, 8, 7, 0, 0, 0,10,10, 0, 0, 0, 0, 0,
+ 0, 0, 4, 6, 6, 0, 0, 0, 8, 8, 0, 0, 0, 7, 8, 0,
+ 0, 0,10,10, 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, 5, 8, 7, 0, 0, 0, 8, 8, 0, 0,
+ 0, 8, 8, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 5,
+ 7, 8, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0,10,
+ 10, 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, 5, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8,
+ 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 5, 8, 8, 0,
+ 0, 0, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0,10,10, 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,
+ 8,10,10, 0, 0, 0,10,10, 0, 0, 0, 9,10, 0, 0, 0,
+ 11,10, 0, 0, 0, 0, 0, 0, 0, 8,10,10, 0, 0, 0,10,
+ 10, 0, 0, 0,10,10, 0, 0, 0,10,11, 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,
+ 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,
+};
+
+static const static_codebook _44c5_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c5_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c5_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c5_s_p3_0[] = {
+ 2, 4, 3, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 5, 5, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 8, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 6, 6, 8, 8, 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, 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, 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, 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,
+};
+
+static const static_codebook _44c5_s_p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c5_s_p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c5_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c5_s_p4_0[] = {
+ 2, 3, 3, 6, 6, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0,
+ 0, 0, 0, 4, 4, 6, 6, 0, 0, 0, 0, 0, 5, 5, 6, 6,
+ 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0,
+ 7, 7, 0, 0, 0, 0, 0, 0, 0, 8, 7, 0, 0, 0, 0, 0,
+ 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c5_s_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c5_s_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c5_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c5_s_p5_0[] = {
+ 2, 4, 3, 6, 6, 7, 7, 9, 9, 0, 4, 4, 6, 6, 7, 7,
+ 9, 9, 0, 4, 4, 6, 6, 7, 7, 9, 9, 0, 6, 6, 7, 7,
+ 7, 7, 9, 9, 0, 0, 0, 7, 6, 7, 7, 9, 9, 0, 0, 0,
+ 8, 8, 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0,
+ 0, 0, 9, 9, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,
+};
+
+static const static_codebook _44c5_s_p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c5_s_p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c5_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p6_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c5_s_p6_0[] = {
+ 2, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10,10,11,
+ 11, 0, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,11,11,
+ 12,12, 0, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11,12,12, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,12,12, 0, 0, 0, 7, 7, 9, 9,10,10,10,10,
+ 11,11,11,11,12,12, 0, 0, 0, 7, 7, 8, 9,10,10,10,
+ 10,11,11,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,
+ 10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9,
+ 10,10,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9,
+ 9, 9,10,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0,
+ 10,10,10,10,11,11,11,12,12,12,13,13, 0, 0, 0, 0,
+ 0, 0, 0,10,10,11,11,11,11,12,12,13,13, 0, 0, 0,
+ 0, 0, 0, 0,11,11,11,11,12,12,12,13,13,13, 0, 0,
+ 0, 0, 0, 0, 0,11,11,11,11,12,12,12,12,13,13, 0,
+ 0, 0, 0, 0, 0, 0,12,12,12,12,13,12,13,13,13,13,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,
+ 13,
+};
+
+static const static_codebook _44c5_s_p6_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c5_s_p6_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c5_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c5_s_p7_0[] = {
+ 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11,
+ 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 7,10,10,11,11,
+ 10,11,11,11, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9,
+ 11,10,10,11,10,10, 7,11,11,12,11,11,12,11,11, 6,
+ 9, 9,11,10,10,11,10,10, 6, 9, 9,11,10,10,11,10,
+ 10,
+};
+
+static const static_codebook _44c5_s_p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c5_s_p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c5_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c5_s_p7_1[] = {
+ 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6,
+ 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6, 7, 7, 8, 8, 8,
+ 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7,
+ 7, 8, 8, 8, 8, 8, 8,10,10,10, 7, 7, 8, 8, 8, 8,
+ 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10,
+ 8, 8, 8, 8, 8, 8, 8, 9,10,10,10,10,10, 8, 8, 8,
+ 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10,
+ 10,10,10, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44c5_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c5_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c5_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p8_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c5_s_p8_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 6, 5, 5,
+ 7, 7, 8, 8, 8, 9,10,10,10,10, 7, 5, 5, 7, 7, 8,
+ 8, 9, 9,10,10,10,10, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,12,12, 9, 9, 9,10,10,10,10,10,11,11, 0,13,
+ 13, 9, 9, 9, 9,10,10,11,11,11,11, 0, 0, 0,10,10,
+ 10,10,10,10,11,11,11,11, 0, 0, 0,10,10,10,10,10,
+ 10,11,11,12,12, 0, 0, 0,14,14,11,11,11,11,12,12,
+ 12,12, 0, 0, 0,14,14,11,11,11,11,12,12,12,12, 0,
+ 0, 0, 0, 0,12,12,12,12,12,12,13,13, 0, 0, 0, 0,
+ 0,12,12,12,12,12,12,13,13,
+};
+
+static const static_codebook _44c5_s_p8_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c5_s_p8_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c5_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p8_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c5_s_p8_1[] = {
+ 2, 4, 4, 5, 5, 6, 5, 5, 5, 5, 6, 4, 5, 5, 5, 6,
+ 5, 5, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44c5_s_p8_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c5_s_p8_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c5_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p9_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44c5_s_p9_0[] = {
+ 1, 3, 3,13,13,13,13,13,13,13,13,13,13,13,13, 4,
+ 7, 7,13,13,13,13,13,13,13,13,13,13,13,13, 3, 8,
+ 6,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,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,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,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,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,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,
+ 12,
+};
+
+static const static_codebook _44c5_s_p9_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44c5_s_p9_0,
+ 1, -512522752, 1628852224, 4, 0,
+ (long *)_vq_quantlist__44c5_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p9_1[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c5_s_p9_1[] = {
+ 1, 4, 4, 5, 5, 7, 7, 9, 8,10, 9,10,10,11,10,11,
+ 11, 6, 5, 5, 7, 7, 8, 9,10,10,11,10,12,11,12,11,
+ 13,12, 6, 5, 5, 7, 7, 9, 9,10,10,11,11,12,12,13,
+ 12,13,13,18, 8, 8, 8, 8, 9, 9,10,11,11,11,12,11,
+ 13,11,13,12,18, 8, 8, 8, 8,10,10,11,11,12,12,13,
+ 13,13,13,13,14,18,12,12, 9, 9,11,11,11,11,12,12,
+ 13,12,13,12,13,13,20,13,12, 9, 9,11,11,11,11,12,
+ 12,13,13,13,14,14,13,20,18,19,11,12,11,11,12,12,
+ 13,13,13,13,13,13,14,13,18,19,19,12,11,11,11,12,
+ 12,13,12,13,13,13,14,14,13,18,17,19,14,15,12,12,
+ 12,13,13,13,14,14,14,14,14,14,19,19,19,16,15,12,
+ 11,13,12,14,14,14,13,13,14,14,14,19,18,19,18,19,
+ 13,13,13,13,14,14,14,13,14,14,14,14,18,17,19,19,
+ 19,13,13,13,11,13,11,13,14,14,14,14,14,19,17,17,
+ 18,18,16,16,13,13,13,13,14,13,15,15,14,14,19,19,
+ 17,17,18,16,16,13,11,14,10,13,12,14,14,14,14,19,
+ 19,19,19,19,18,17,13,14,13,11,14,13,14,14,15,15,
+ 19,19,19,17,19,18,18,14,13,12,11,14,11,15,15,15,
+ 15,
+};
+
+static const static_codebook _44c5_s_p9_1 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c5_s_p9_1,
+ 1, -520814592, 1620377600, 5, 0,
+ (long *)_vq_quantlist__44c5_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44c5_s_p9_2[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__44c5_s_p9_2[] = {
+ 3, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9,11, 5, 6, 7, 7, 8, 7, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11, 5, 5, 7, 7, 7,
+ 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,
+ 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9,10, 9,10,11,11,11, 7, 7, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9,10,10,10,10,10,10,11,11,11, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,11,11,
+ 11, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,10,10,10,10,10,
+ 10,10,10,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,11,11,11,11,11, 9, 9, 9,
+ 9, 9, 9,10, 9,10,10,10,10,10,10,10,10,11,11,11,
+ 11,11, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,
+ 10,10,11,11,11,11,11, 9, 9, 9, 9, 9, 9,10,10,10,
+ 10,10,10,10,10,10,10,11,11,11,11,11, 9, 9,10, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,
+ 11,11,11, 9, 9,10,10,10,10,10,10,10,10,10,10,10,
+ 10,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,11,11,11,11,11,11,11,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,
+ 11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,
+ 10,10,10,10,10,11,11,11,11,11,11,11,11,11,10,10,
+ 10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,
+ 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,11,
+ 11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,
+ 10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,10,
+ 10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _44c5_s_p9_2 = {
+ 2, 441,
+ (char *)_vq_lengthlist__44c5_s_p9_2,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c5_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c5_s_short[] = {
+ 5, 8,10,14,11,11,12,16,15,17, 5, 5, 7, 9, 7, 8,
+ 10,13,17,17, 7, 5, 5,10, 5, 7, 8,11,13,15,10, 8,
+ 10, 8, 8, 8,11,15,18,18, 8, 5, 5, 8, 3, 4, 6,10,
+ 14,16, 9, 7, 6, 7, 4, 3, 5, 9,14,18,10, 9, 8,10,
+ 6, 5, 6, 9,14,18,12,12,11,12, 8, 7, 8,11,14,18,
+ 14,13,12,10, 7, 5, 6, 9,14,18,14,14,13,10, 6, 5,
+ 6, 8,11,16,
+};
+
+static const static_codebook _huff_book__44c5_s_short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c5_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c6_s_long[] = {
+ 3, 8,11,13,14,14,13,13,16,14, 6, 3, 4, 7, 9, 9,
+ 10,11,14,13,10, 4, 3, 5, 7, 7, 9,10,13,15,12, 7,
+ 4, 4, 6, 6, 8,10,13,15,12, 8, 6, 6, 6, 6, 8,10,
+ 13,14,11, 9, 7, 6, 6, 6, 7, 8,12,11,13,10, 9, 8,
+ 7, 6, 6, 7,11,11,13,11,10, 9, 9, 7, 7, 6,10,11,
+ 13,13,13,13,13,11, 9, 8,10,12,12,15,15,16,15,12,
+ 11,10,10,12,
+};
+
+static const static_codebook _huff_book__44c6_s_long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c6_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c6_s_p1_0[] = {
+ 1, 5, 5, 0, 5, 5, 0, 5, 5, 5, 8, 7, 0, 9, 9, 0,
+ 9, 8, 5, 7, 8, 0, 9, 9, 0, 8, 9, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 9, 8, 0, 8, 8, 0, 8, 8, 5, 8, 9,
+ 0, 8, 8, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
+ 9, 9, 0, 8, 8, 0, 8, 8, 5, 9, 9, 0, 8, 8, 0, 8,
+ 8,
+};
+static const static_codebook _44c6_s_p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c6_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c6_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c6_s_p2_0[] = {
+ 3, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0,
+ 7, 7, 9, 9, 0, 0, 0, 9, 9, 5, 7, 7, 9, 9, 0, 8,
+ 8,10,10, 0, 8, 7,10, 9, 0,10,10,11,11, 0, 0, 0,
+ 11,11, 5, 7, 7, 9, 9, 0, 8, 8,10,10, 0, 7, 8, 9,
+ 10, 0,10,10,11,11, 0, 0, 0,11,11, 8, 9, 9,11,11,
+ 0,11,11,12,12, 0,11,10,12,12, 0,13,14,14,14, 0,
+ 0, 0,14,13, 8, 9, 9,11,11, 0,11,11,12,12, 0,10,
+ 11,12,12, 0,14,13,14,14, 0, 0, 0,13,14, 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, 5, 8, 7,11,10, 0, 7, 7,10,10,
+ 0, 7, 7,10,10, 0, 9, 9,11,10, 0, 0, 0,11,11, 5,
+ 7, 8,10,11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9,
+ 9,10,11, 0, 0, 0,11,11, 8,10, 9,12,12, 0,10,10,
+ 12,12, 0,10,10,12,12, 0,12,12,13,13, 0, 0, 0,13,
+ 13, 8, 9,10,12,12, 0,10,10,11,12, 0,10,10,12,12,
+ 0,12,12,13,13, 0, 0, 0,13,13, 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, 5, 8, 8,11,11, 0, 7, 7,10,10, 0, 7, 7,
+ 10,10, 0, 9, 9,10,11, 0, 0, 0,11,10, 5, 8, 8,11,
+ 11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9, 9,11,11,
+ 0, 0, 0,10,11, 8,10,10,12,12, 0,10,10,12,12, 0,
+ 10,10,12,12, 0,12,13,13,13, 0, 0, 0,14,13, 8,10,
+ 10,12,12, 0,10,10,12,12, 0,10,10,12,12, 0,13,12,
+ 13,13, 0, 0, 0,13,13, 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,
+ 7,10,10,14,13, 0, 9, 9,13,12, 0, 9, 9,12,12, 0,
+ 10,10,12,12, 0, 0, 0,12,12, 7,10,10,13,14, 0, 9,
+ 9,12,13, 0, 9, 9,12,12, 0,10,10,12,12, 0, 0, 0,
+ 12,12, 9,11,11,14,13, 0,11,10,14,13, 0,11,11,13,
+ 13, 0,12,12,13,13, 0, 0, 0,13,13, 9,11,11,13,14,
+ 0,10,11,13,14, 0,11,11,13,13, 0,12,12,13,13, 0,
+ 0, 0,13,13, 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, 9,
+ 11,11,14,14, 0,11,11,13,13, 0,11,10,13,13, 0,12,
+ 12,13,13, 0, 0, 0,13,13, 9,11,11,14,14, 0,11,11,
+ 13,13, 0,10,11,13,13, 0,12,12,14,13, 0, 0, 0,13,
+ 13,
+};
+
+static const static_codebook _44c6_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c6_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c6_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c6_s_p3_0[] = {
+ 2, 3, 4, 6, 6, 7, 7, 9, 9, 0, 4, 4, 6, 6, 7, 7,
+ 9,10, 0, 4, 4, 6, 6, 7, 7,10, 9, 0, 5, 5, 7, 7,
+ 8, 8,10,10, 0, 0, 0, 7, 6, 8, 8,10,10, 0, 0, 0,
+ 7, 7, 9, 9,11,11, 0, 0, 0, 7, 7, 9, 9,11,11, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c6_s_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c6_s_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c6_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p4_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c6_s_p4_0[] = {
+ 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9,10,10,
+ 10, 0, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10,10,
+ 11,11, 0, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10,
+ 10,11,11, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,11,11, 0, 0, 0, 7, 7, 9, 9,10,10,10,10,
+ 11,11,11,11,12,12, 0, 0, 0, 7, 7, 9, 9,10,10,10,
+ 10,11,11,11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,
+ 10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 8, 8, 9,
+ 9,10,10,11,11,12,12,12,12, 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,
+};
+
+static const static_codebook _44c6_s_p4_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c6_s_p4_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c6_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p5_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c6_s_p5_0[] = {
+ 1, 4, 4, 5, 7, 7, 6, 7, 7, 4, 6, 6, 9, 9,10,10,
+ 10, 9, 4, 6, 6, 9,10, 9,10, 9,10, 6, 9, 9,10,12,
+ 11,10,11,11, 7,10, 9,11,12,12,12,12,12, 7,10,10,
+ 11,12,12,12,12,12, 6,10,10,10,12,12,11,12,12, 7,
+ 9,10,11,12,12,12,12,12, 7,10, 9,12,12,12,12,12,
+ 12,
+};
+
+static const static_codebook _44c6_s_p5_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c6_s_p5_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c6_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p5_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c6_s_p5_1[] = {
+ 3, 5, 4, 6, 6, 7, 7, 8, 8, 8, 8,11, 4, 4, 6, 6,
+ 7, 7, 8, 8, 8, 8,11, 4, 4, 6, 6, 7, 7, 8, 8, 8,
+ 8,11, 6, 6, 6, 6, 8, 8, 8, 8, 9, 9,11,11,11, 6,
+ 6, 7, 8, 8, 8, 8, 9,11,11,11, 7, 7, 8, 8, 8, 8,
+ 8, 8,11,11,11, 7, 7, 8, 8, 8, 8, 8, 8,11,11,11,
+ 8, 8, 8, 8, 8, 8, 8, 8,11,11,11,10,10, 8, 8, 8,
+ 8, 8, 8,11,11,11,10,10, 8, 8, 8, 8, 8, 8,11,11,
+ 11,10,10, 7, 7, 8, 8, 8, 8,
+};
+
+static const static_codebook _44c6_s_p5_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c6_s_p5_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c6_s_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c6_s_p6_0[] = {
+ 1, 4, 4, 6, 6, 8, 8, 8, 8,10, 9,10,10, 6, 5, 5,
+ 7, 7, 9, 9, 9, 9,10,10,11,11, 6, 5, 5, 7, 7, 9,
+ 9,10, 9,11,10,11,11, 0, 6, 6, 7, 7, 9, 9,10,10,
+ 11,11,12,12, 0, 7, 7, 7, 7, 9, 9,10,10,11,11,12,
+ 12, 0,11,11, 8, 8,10,10,11,11,12,12,12,12, 0,11,
+ 12, 9, 8,10,10,11,11,12,12,13,13, 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,
+};
+
+static const static_codebook _44c6_s_p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c6_s_p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c6_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c6_s_p6_1[] = {
+ 3, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5, 4, 4, 5, 5, 6,
+ 5, 5, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44c6_s_p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c6_s_p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c6_s_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c6_s_p7_0[] = {
+ 1, 4, 4, 6, 6, 8, 8, 8, 8,10,10,11,10, 6, 5, 5,
+ 7, 7, 8, 8, 9, 9,10,10,12,11, 6, 5, 5, 7, 7, 8,
+ 8, 9, 9,10,10,12,11,21, 7, 7, 7, 7, 9, 9,10,10,
+ 11,11,12,12,21, 7, 7, 7, 7, 9, 9,10,10,11,11,12,
+ 12,21,12,12, 9, 9,10,10,11,11,11,11,12,12,21,12,
+ 12, 9, 9,10,10,11,11,12,12,12,12,21,21,21,11,11,
+ 10,10,11,12,12,12,13,13,21,21,21,11,11,10,10,12,
+ 12,12,12,13,13,21,21,21,15,15,11,11,12,12,13,13,
+ 13,13,21,21,21,15,16,11,11,12,12,13,13,14,14,21,
+ 21,21,21,20,13,13,13,13,13,13,14,14,20,20,20,20,
+ 20,13,13,13,13,13,13,14,14,
+};
+
+static const static_codebook _44c6_s_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c6_s_p7_0,
+ 1, -523206656, 1618345984, 4, 0,
+ (long *)_vq_quantlist__44c6_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c6_s_p7_1[] = {
+ 3, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 9, 5, 5, 6, 6,
+ 7, 7, 7, 7, 8, 7, 8, 5, 5, 6, 6, 7, 7, 7, 7, 7,
+ 7, 9, 6, 6, 7, 7, 7, 7, 8, 7, 7, 8, 9, 9, 9, 7,
+ 7, 7, 7, 7, 7, 7, 8, 9, 9, 9, 7, 7, 7, 7, 8, 8,
+ 8, 8, 9, 9, 9, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9,
+ 8, 8, 8, 8, 7, 7, 8, 8, 9, 9, 9, 9, 8, 8, 8, 7,
+ 7, 8, 8, 9, 9, 9, 8, 8, 8, 8, 7, 7, 8, 8, 9, 9,
+ 9, 8, 8, 7, 7, 7, 7, 8, 8,
+};
+
+static const static_codebook _44c6_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c6_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c6_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p8_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44c6_s_p8_0[] = {
+ 1, 4, 4, 7, 7, 8, 8, 7, 7, 8, 7, 9, 8,10, 9, 6,
+ 5, 5, 8, 8, 9, 9, 8, 8, 9, 9,11,10,11,10, 6, 5,
+ 5, 8, 8, 9, 9, 8, 8, 9, 9,10,10,11,11,18, 8, 8,
+ 9, 8,10,10, 9, 9,10,10,10,10,11,10,18, 8, 8, 9,
+ 9,10,10, 9, 9,10,10,11,11,12,12,18,12,13, 9,10,
+ 10,10, 9,10,10,10,11,11,12,11,18,13,13, 9, 9,10,
+ 10,10,10,10,10,11,11,12,12,18,18,18,10,10, 9, 9,
+ 11,11,11,11,11,12,12,12,18,18,18,10, 9,10, 9,11,
+ 10,11,11,11,11,13,12,18,18,18,14,13,10,10,11,11,
+ 12,12,12,12,12,12,18,18,18,14,13,10,10,11,10,12,
+ 12,12,12,12,12,18,18,18,18,18,12,12,11,11,12,12,
+ 13,13,13,14,18,18,18,18,18,12,12,11,11,12,11,13,
+ 13,14,13,18,18,18,18,18,16,16,11,12,12,13,13,13,
+ 14,13,18,18,18,18,18,16,15,12,11,12,11,13,11,15,
+ 14,
+};
+
+static const static_codebook _44c6_s_p8_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44c6_s_p8_0,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__44c6_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p8_1[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__44c6_s_p8_1[] = {
+ 3, 5, 5, 6, 6, 7, 7, 7, 7, 8, 7, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 6, 6, 7, 7, 8,
+ 8, 8, 8, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9,10,
+ 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9,10,11,11, 8, 7, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,11,11,11, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,11,
+ 11, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,11,11,11,11,11, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, 9,11,11,11,
+ 11,11, 9, 9, 9, 9, 9, 9,10, 9, 9,10, 9,10, 9, 9,
+ 10, 9,11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9,10,10,
+ 10,10, 9,10,10, 9,10,11,11,11,11,11, 9, 9, 9, 9,
+ 10,10,10, 9,10,10,10,10, 9,10,10, 9,11,11,11,11,
+ 11,11,11, 9, 9, 9, 9,10,10,10,10, 9,10,10,10,10,
+ 10,11,11,11,11,11,11,11,10, 9,10,10,10,10,10,10,
+ 10, 9,10, 9,10,10,11,11,11,11,11,11,11,10, 9,10,
+ 9,10,10, 9,10,10,10,10,10,10,10,11,11,11,11,11,
+ 11,11,10,10,10,10,10,10,10, 9,10,10,10,10,10, 9,
+ 11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,
+ 10,10,10,10,10,11,11,11,11,11,11,11,11,11,10,10,
+ 10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,
+ 11,11,11,10,10,10,10,10,10,10,10,10, 9,10,10,11,
+ 11,11,11,11,11,11,11,11,10,10,10, 9,10,10,10,10,
+ 10,10,10,10,10,11,11,11,11,11,11,11,11,10,11, 9,
+ 10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _44c6_s_p8_1 = {
+ 2, 441,
+ (char *)_vq_lengthlist__44c6_s_p8_1,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c6_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p9_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c6_s_p9_0[] = {
+ 1, 3, 3,11,11,11,11,11,11,11,11,11,11, 4, 7, 7,
+ 11,11,11,11,11,11,11,11,11,11, 5, 8, 9,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _44c6_s_p9_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c6_s_p9_0,
+ 1, -511845376, 1630791680, 4, 0,
+ (long *)_vq_quantlist__44c6_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p9_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c6_s_p9_1[] = {
+ 1, 4, 4, 7, 7, 7, 7, 7, 6, 8, 8, 8, 8, 6, 6, 6,
+ 8, 8, 8, 8, 8, 7, 9, 8,10,10, 5, 6, 6, 8, 8, 9,
+ 9, 8, 8,10,10,10,10,16, 9, 9, 9, 9, 9, 9, 9, 8,
+ 10, 9,11,11,16, 8, 9, 9, 9, 9, 9, 9, 9,10,10,11,
+ 11,16,13,13, 9, 9,10, 9, 9,10,11,11,11,12,16,13,
+ 14, 9, 8,10, 8, 9, 9,10,10,12,11,16,14,16, 9, 9,
+ 9, 9,11,11,12,11,12,11,16,16,16, 9, 7, 9, 6,11,
+ 11,11,10,11,11,16,16,16,11,12, 9,10,11,11,12,11,
+ 13,13,16,16,16,12,11,10, 7,12,10,12,12,12,12,16,
+ 16,15,16,16,10,11,10,11,13,13,14,12,16,16,16,15,
+ 15,12,10,11,11,13,11,12,13,
+};
+
+static const static_codebook _44c6_s_p9_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c6_s_p9_1,
+ 1, -518889472, 1622704128, 4, 0,
+ (long *)_vq_quantlist__44c6_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44c6_s_p9_2[] = {
+ 24,
+ 23,
+ 25,
+ 22,
+ 26,
+ 21,
+ 27,
+ 20,
+ 28,
+ 19,
+ 29,
+ 18,
+ 30,
+ 17,
+ 31,
+ 16,
+ 32,
+ 15,
+ 33,
+ 14,
+ 34,
+ 13,
+ 35,
+ 12,
+ 36,
+ 11,
+ 37,
+ 10,
+ 38,
+ 9,
+ 39,
+ 8,
+ 40,
+ 7,
+ 41,
+ 6,
+ 42,
+ 5,
+ 43,
+ 4,
+ 44,
+ 3,
+ 45,
+ 2,
+ 46,
+ 1,
+ 47,
+ 0,
+ 48,
+};
+
+static const char _vq_lengthlist__44c6_s_p9_2[] = {
+ 2, 4, 3, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7,
+};
+
+static const static_codebook _44c6_s_p9_2 = {
+ 1, 49,
+ (char *)_vq_lengthlist__44c6_s_p9_2,
+ 1, -526909440, 1611661312, 6, 0,
+ (long *)_vq_quantlist__44c6_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c6_s_short[] = {
+ 3, 9,11,11,13,14,19,17,17,19, 5, 4, 5, 8,10,10,
+ 13,16,18,19, 7, 4, 4, 5, 8, 9,12,14,17,19, 8, 6,
+ 5, 5, 7, 7,10,13,16,18,10, 8, 7, 6, 5, 5, 8,11,
+ 17,19,11, 9, 7, 7, 5, 4, 5, 8,17,19,13,11, 8, 7,
+ 7, 5, 5, 7,16,18,14,13, 8, 6, 6, 5, 5, 7,16,18,
+ 18,16,10, 8, 8, 7, 7, 9,16,18,18,18,12,10,10, 9,
+ 9,10,17,18,
+};
+
+static const static_codebook _huff_book__44c6_s_short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c6_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c7_s_long[] = {
+ 3, 8,11,13,15,14,14,13,15,14, 6, 4, 5, 7, 9,10,
+ 11,11,14,13,10, 4, 3, 5, 7, 8, 9,10,13,13,12, 7,
+ 4, 4, 5, 6, 8, 9,12,14,13, 9, 6, 5, 5, 6, 8, 9,
+ 12,14,12, 9, 7, 6, 5, 5, 6, 8,11,11,12,11, 9, 8,
+ 7, 6, 6, 7,10,11,13,11,10, 9, 8, 7, 6, 6, 9,11,
+ 13,13,12,12,12,10, 9, 8, 9,11,12,14,15,15,14,12,
+ 11,10,10,12,
+};
+
+static const static_codebook _huff_book__44c7_s_long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c7_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c7_s_p1_0[] = {
+ 1, 5, 5, 0, 5, 5, 0, 5, 5, 5, 8, 7, 0, 9, 9, 0,
+ 9, 8, 5, 7, 8, 0, 9, 9, 0, 8, 9, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 9, 9, 0, 8, 8, 0, 8, 8, 5, 8, 9,
+ 0, 8, 8, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
+ 9, 9, 0, 8, 8, 0, 8, 8, 5, 8, 9, 0, 8, 8, 0, 8,
+ 8,
+};
+
+static const static_codebook _44c7_s_p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c7_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c7_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c7_s_p2_0[] = {
+ 3, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0,
+ 7, 7, 9, 9, 0, 0, 0, 9, 9, 5, 7, 7, 9, 9, 0, 8,
+ 8,10,10, 0, 8, 7,10, 9, 0,10,10,11,11, 0, 0, 0,
+ 11,11, 5, 7, 7, 9, 9, 0, 8, 8,10,10, 0, 7, 8, 9,
+ 10, 0,10,10,11,11, 0, 0, 0,11,11, 8, 9, 9,11,10,
+ 0,11,11,12,12, 0,11,10,12,12, 0,13,14,14,14, 0,
+ 0, 0,14,13, 8, 9, 9,10,11, 0,11,11,12,12, 0,10,
+ 11,12,12, 0,13,13,14,14, 0, 0, 0,13,14, 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, 5, 8, 7,11,10, 0, 7, 7,10,10,
+ 0, 7, 7,10,10, 0, 9, 9,11,10, 0, 0, 0,11,11, 5,
+ 7, 8,10,11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9,
+ 9,10,11, 0, 0, 0,11,11, 8,10, 9,12,12, 0,10,10,
+ 12,12, 0,10,10,12,12, 0,12,12,13,13, 0, 0, 0,13,
+ 13, 8, 9,10,12,12, 0,10,10,12,12, 0,10,10,11,12,
+ 0,12,12,13,13, 0, 0, 0,13,13, 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, 5, 8, 8,11,11, 0, 7, 7,10,10, 0, 7, 7,
+ 10,10, 0, 9, 9,10,11, 0, 0, 0,11,10, 5, 8, 8,10,
+ 11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9, 9,11,10,
+ 0, 0, 0,10,11, 9,10,10,12,12, 0,10,10,12,12, 0,
+ 10,10,12,12, 0,12,13,13,13, 0, 0, 0,13,12, 9,10,
+ 10,12,12, 0,10,10,12,12, 0,10,10,12,12, 0,13,12,
+ 13,13, 0, 0, 0,12,13, 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,
+ 7,10,10,14,13, 0, 9, 9,12,12, 0, 9, 9,12,12, 0,
+ 10,10,12,12, 0, 0, 0,12,12, 7,10,10,13,14, 0, 9,
+ 9,12,13, 0, 9, 9,12,12, 0,10,10,12,12, 0, 0, 0,
+ 12,12, 9,11,11,14,13, 0,11,10,13,12, 0,11,11,13,
+ 13, 0,12,12,13,13, 0, 0, 0,13,13, 9,11,11,13,14,
+ 0,10,11,12,13, 0,11,11,13,13, 0,12,12,13,13, 0,
+ 0, 0,13,13, 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, 9,
+ 11,11,14,14, 0,10,11,13,13, 0,11,10,13,13, 0,12,
+ 12,13,13, 0, 0, 0,13,12, 9,11,11,14,14, 0,11,10,
+ 13,13, 0,10,11,13,13, 0,12,12,14,13, 0, 0, 0,13,
+ 13,
+};
+
+static const static_codebook _44c7_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c7_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c7_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c7_s_p3_0[] = {
+ 2, 4, 4, 5, 5, 7, 7, 9, 9, 0, 4, 4, 6, 6, 7, 7,
+ 9, 9, 0, 4, 4, 6, 6, 7, 7, 9, 9, 0, 5, 5, 6, 6,
+ 8, 8,10,10, 0, 0, 0, 6, 6, 8, 8,10,10, 0, 0, 0,
+ 7, 7, 9, 9,10,10, 0, 0, 0, 7, 7, 8, 8,10,10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c7_s_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c7_s_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c7_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p4_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c7_s_p4_0[] = {
+ 3, 4, 4, 5, 5, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11,
+ 11, 0, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,
+ 12,12, 0, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,
+ 11,12,12, 0, 5, 5, 6, 6, 8, 8, 9, 9, 9, 9,10,10,
+ 11,12,12,12, 0, 0, 0, 6, 6, 8, 7, 9, 9, 9, 9,10,
+ 10,11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10,10,
+ 11,11,12,12,13,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10,
+ 10,11,11,12,12,12,13, 0, 0, 0, 7, 7, 8, 8, 9, 9,
+ 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 8, 8, 9,
+ 9,10,10,11,11,12,12,13,13, 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,
+};
+
+static const static_codebook _44c7_s_p4_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c7_s_p4_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c7_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p5_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c7_s_p5_0[] = {
+ 1, 4, 4, 5, 7, 7, 6, 7, 7, 4, 6, 7,10,10,10,10,
+ 10, 9, 4, 6, 6,10,10,10,10, 9,10, 5,10,10, 9,11,
+ 12,10,11,12, 7,10,10,11,12,12,12,12,12, 7,10,10,
+ 11,12,12,12,12,12, 6,10,10,10,12,12,11,12,12, 7,
+ 10,10,12,12,12,12,11,12, 7,10,10,11,12,12,12,12,
+ 12,
+};
+
+static const static_codebook _44c7_s_p5_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c7_s_p5_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c7_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p5_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c7_s_p5_1[] = {
+ 3, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8,11, 4, 4, 6, 6,
+ 7, 7, 8, 8, 9, 9,11, 4, 4, 6, 6, 7, 7, 8, 8, 9,
+ 9,12, 5, 5, 6, 6, 7, 7, 9, 9, 9, 9,12,12,12, 6,
+ 6, 7, 7, 9, 9, 9, 9,11,11,11, 7, 7, 7, 7, 8, 8,
+ 9, 9,11,11,11, 7, 7, 7, 7, 8, 8, 9, 9,11,11,11,
+ 7, 7, 8, 8, 8, 8, 9, 9,11,11,11,11,11, 8, 8, 8,
+ 8, 8, 9,11,11,11,11,11, 8, 8, 8, 8, 8, 8,11,11,
+ 11,11,11, 7, 7, 8, 8, 8, 8,
+};
+
+static const static_codebook _44c7_s_p5_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c7_s_p5_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c7_s_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c7_s_p6_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 8, 7, 9, 8,10,10, 6, 5, 5,
+ 7, 7, 8, 8, 9, 9, 9,10,11,11, 7, 5, 5, 7, 7, 8,
+ 8, 9, 9,10,10,11,11, 0, 7, 7, 7, 7, 9, 8, 9, 9,
+ 10,10,11,11, 0, 8, 8, 7, 7, 8, 9, 9, 9,10,10,11,
+ 11, 0,11,11, 9, 9,10,10,11,10,11,11,12,12, 0,12,
+ 12, 9, 9,10,10,11,11,11,11,12,12, 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,
+};
+
+static const static_codebook _44c7_s_p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c7_s_p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c7_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c7_s_p6_1[] = {
+ 3, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5, 4, 4, 5, 5, 6,
+ 5, 5, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44c7_s_p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c7_s_p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c7_s_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c7_s_p7_0[] = {
+ 1, 4, 4, 6, 6, 7, 8, 9, 9,10,10,12,11, 6, 5, 5,
+ 7, 7, 8, 8, 9,10,11,11,12,12, 7, 5, 5, 7, 7, 8,
+ 8,10,10,11,11,12,12,20, 7, 7, 7, 7, 8, 9,10,10,
+ 11,11,12,13,20, 7, 7, 7, 7, 9, 9,10,10,11,12,13,
+ 13,20,11,11, 8, 8, 9, 9,11,11,12,12,13,13,20,11,
+ 11, 8, 8, 9, 9,11,11,12,12,13,13,20,20,20,10,10,
+ 10,10,12,12,13,13,13,13,20,20,20,10,10,10,10,12,
+ 12,13,13,13,14,20,20,20,14,14,11,11,12,12,13,13,
+ 14,14,20,20,20,14,14,11,11,12,12,13,13,14,14,20,
+ 20,20,20,19,13,13,13,13,14,14,15,14,19,19,19,19,
+ 19,13,13,13,13,14,14,15,15,
+};
+
+static const static_codebook _44c7_s_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c7_s_p7_0,
+ 1, -523206656, 1618345984, 4, 0,
+ (long *)_vq_quantlist__44c7_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c7_s_p7_1[] = {
+ 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 8, 6, 6, 7, 7,
+ 7, 7, 7, 7, 7, 7, 8, 6, 6, 6, 7, 7, 7, 7, 7, 7,
+ 7, 8, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 7,
+ 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7,
+ 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8,
+ 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7,
+ 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 8, 8,
+ 8, 8, 8, 7, 7, 7, 7, 7, 7,
+};
+
+static const static_codebook _44c7_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c7_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c7_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p8_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44c7_s_p8_0[] = {
+ 1, 4, 4, 7, 7, 8, 8, 8, 7, 9, 8, 9, 9,10,10, 6,
+ 5, 5, 7, 7, 9, 9, 8, 8,10, 9,11,10,12,11, 6, 5,
+ 5, 8, 7, 9, 9, 8, 8,10,10,11,11,12,11,19, 8, 8,
+ 8, 8,10,10, 9, 9,10,10,11,11,12,11,19, 8, 8, 8,
+ 8,10,10, 9, 9,10,10,11,11,12,12,19,12,12, 9, 9,
+ 10,10, 9,10,10,10,11,11,12,12,19,12,12, 9, 9,10,
+ 10,10,10,10,10,12,12,12,12,19,19,19, 9, 9, 9, 9,
+ 11,10,11,11,12,11,13,13,19,19,19, 9, 9, 9, 9,11,
+ 10,11,11,11,12,13,13,19,19,19,13,13,10,10,11,11,
+ 12,12,12,12,13,12,19,19,19,14,13,10,10,11,11,12,
+ 12,12,13,13,13,19,19,19,19,19,12,12,12,11,12,13,
+ 14,13,13,13,19,19,19,19,19,12,12,12,11,12,12,13,
+ 14,13,14,19,19,19,19,19,16,16,12,13,12,13,13,14,
+ 15,14,19,18,18,18,18,16,15,12,11,12,11,14,12,14,
+ 14,
+};
+
+static const static_codebook _44c7_s_p8_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44c7_s_p8_0,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__44c7_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p8_1[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__44c7_s_p8_1[] = {
+ 3, 5, 5, 7, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 6, 6, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,
+ 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,
+ 10, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10,11,10,10,10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,10, 9, 9,10, 9, 9,10,11,10,
+ 11,10, 9, 9, 9, 9, 9, 9, 9,10,10,10, 9,10, 9, 9,
+ 9, 9,11,10,11,10,10, 9, 9, 9, 9, 9, 9,10, 9, 9,
+ 10, 9, 9,10, 9, 9,10,11,10,10,11,10, 9, 9, 9, 9,
+ 9,10,10, 9,10,10,10,10, 9,10,10,10,10,10,10,11,
+ 11,11,10, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,11,11,10,10,10,10,10,10,10,10,10,10,10,
+ 10, 9,10,10, 9,10,11,11,10,11,10,11,10, 9,10,10,
+ 9,10,10,10,10,10,10,10,10,10,10,11,11,11,11,10,
+ 11,11,10,10,10,10,10,10, 9,10, 9,10,10, 9,10, 9,
+ 10,10,10,11,10,11,10,11,11,10,10,10,10,10,10, 9,
+ 10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,11,10,11,
+ 11,10,10,10,10, 9, 9,10,10, 9, 9,10, 9,10,10,10,
+ 10,11,11,10,10,10,10,10,10,10, 9, 9,10,10,10, 9,
+ 9,10,10,10,10,10,11,10,11,10,10,10,10,10,10, 9,
+ 10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _44c7_s_p8_1 = {
+ 2, 441,
+ (char *)_vq_lengthlist__44c7_s_p8_1,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c7_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p9_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c7_s_p9_0[] = {
+ 1, 3, 3,11,11,11,11,11,11,11,11,11,11, 4, 6, 6,
+ 11,11,11,11,11,11,11,11,11,11, 4, 7, 7,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,
+};
+
+static const static_codebook _44c7_s_p9_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c7_s_p9_0,
+ 1, -511845376, 1630791680, 4, 0,
+ (long *)_vq_quantlist__44c7_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p9_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c7_s_p9_1[] = {
+ 1, 4, 4, 7, 7, 7, 7, 7, 6, 8, 8, 8, 8, 6, 6, 6,
+ 8, 8, 9, 8, 8, 7, 9, 8,11,10, 5, 6, 6, 8, 8, 9,
+ 8, 8, 8,10, 9,11,11,16, 8, 8, 9, 8, 9, 9, 9, 8,
+ 10, 9,11,10,16, 8, 8, 9, 9,10,10, 9, 9,10,10,11,
+ 11,16,13,13, 9, 9,10,10, 9,10,11,11,12,11,16,13,
+ 13, 9, 8,10, 9,10,10,10,10,11,11,16,14,16, 8, 9,
+ 9, 9,11,10,11,11,12,11,16,16,16, 9, 7,10, 7,11,
+ 10,11,11,12,11,16,16,16,12,12, 9,10,11,11,12,11,
+ 12,12,16,16,16,12,10,10, 7,11, 8,12,11,12,12,16,
+ 16,15,16,16,11,12,10,10,12,11,12,12,16,16,16,15,
+ 15,11,11,10,10,12,12,12,12,
+};
+
+static const static_codebook _44c7_s_p9_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c7_s_p9_1,
+ 1, -518889472, 1622704128, 4, 0,
+ (long *)_vq_quantlist__44c7_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44c7_s_p9_2[] = {
+ 24,
+ 23,
+ 25,
+ 22,
+ 26,
+ 21,
+ 27,
+ 20,
+ 28,
+ 19,
+ 29,
+ 18,
+ 30,
+ 17,
+ 31,
+ 16,
+ 32,
+ 15,
+ 33,
+ 14,
+ 34,
+ 13,
+ 35,
+ 12,
+ 36,
+ 11,
+ 37,
+ 10,
+ 38,
+ 9,
+ 39,
+ 8,
+ 40,
+ 7,
+ 41,
+ 6,
+ 42,
+ 5,
+ 43,
+ 4,
+ 44,
+ 3,
+ 45,
+ 2,
+ 46,
+ 1,
+ 47,
+ 0,
+ 48,
+};
+
+static const char _vq_lengthlist__44c7_s_p9_2[] = {
+ 2, 4, 3, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7,
+};
+
+static const static_codebook _44c7_s_p9_2 = {
+ 1, 49,
+ (char *)_vq_lengthlist__44c7_s_p9_2,
+ 1, -526909440, 1611661312, 6, 0,
+ (long *)_vq_quantlist__44c7_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c7_s_short[] = {
+ 4,11,12,14,15,15,17,17,18,18, 5, 6, 6, 8, 9,10,
+ 13,17,18,19, 7, 5, 4, 6, 8, 9,11,15,19,19, 8, 6,
+ 5, 5, 6, 7,11,14,16,17, 9, 7, 7, 6, 7, 7,10,13,
+ 15,19,10, 8, 7, 6, 7, 6, 7, 9,14,16,12,10, 9, 7,
+ 7, 6, 4, 5,10,15,14,13,11, 7, 6, 6, 4, 2, 7,13,
+ 16,16,15, 9, 8, 8, 8, 6, 9,13,19,19,17,12,11,10,
+ 10, 9,11,14,
+};
+
+static const static_codebook _huff_book__44c7_s_short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c7_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c8_s_long[] = {
+ 3, 8,12,13,14,14,14,13,14,14, 6, 4, 5, 8,10,10,
+ 11,11,14,13, 9, 5, 4, 5, 7, 8, 9,10,13,13,12, 7,
+ 5, 4, 5, 6, 8, 9,12,13,13, 9, 6, 5, 5, 5, 7, 9,
+ 11,14,12,10, 7, 6, 5, 4, 6, 7,10,11,12,11, 9, 8,
+ 7, 5, 5, 6,10,10,13,12,10, 9, 8, 6, 6, 5, 8,10,
+ 14,13,12,12,11,10, 9, 7, 8,10,12,13,14,14,13,12,
+ 11, 9, 9,10,
+};
+
+static const static_codebook _huff_book__44c8_s_long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c8_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c8_s_p1_0[] = {
+ 1, 5, 5, 0, 5, 5, 0, 5, 5, 5, 7, 7, 0, 9, 8, 0,
+ 9, 8, 6, 7, 7, 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 9, 8, 0, 8, 8, 0, 8, 8, 5, 8, 9,
+ 0, 8, 8, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
+ 9, 8, 0, 8, 8, 0, 8, 8, 5, 8, 9, 0, 8, 8, 0, 8,
+ 8,
+};
+
+static const static_codebook _44c8_s_p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c8_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c8_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c8_s_p2_0[] = {
+ 3, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0,
+ 7, 7, 9, 9, 0, 0, 0, 9, 9, 5, 7, 7, 9, 9, 0, 8,
+ 7,10, 9, 0, 8, 7,10, 9, 0,10,10,11,11, 0, 0, 0,
+ 11,11, 5, 7, 7, 9, 9, 0, 7, 8, 9,10, 0, 7, 8, 9,
+ 10, 0,10,10,11,11, 0, 0, 0,11,11, 8, 9, 9,11,10,
+ 0,11,10,12,11, 0,11,10,12,12, 0,13,13,14,14, 0,
+ 0, 0,14,13, 8, 9, 9,10,11, 0,10,11,12,12, 0,10,
+ 11,12,12, 0,13,13,14,14, 0, 0, 0,13,14, 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, 5, 8, 7,11,10, 0, 7, 7,10,10,
+ 0, 7, 7,10,10, 0, 9, 9,10,10, 0, 0, 0,11,10, 5,
+ 7, 8,10,11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9,
+ 9,10,10, 0, 0, 0,10,10, 8,10, 9,12,12, 0,10,10,
+ 12,11, 0,10,10,12,12, 0,12,12,13,12, 0, 0, 0,13,
+ 12, 8, 9,10,12,12, 0,10,10,11,12, 0,10,10,11,12,
+ 0,12,12,13,13, 0, 0, 0,12,13, 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, 6, 8, 7,11,10, 0, 7, 7,10,10, 0, 7, 7,
+ 10,10, 0, 9, 9,10,11, 0, 0, 0,10,10, 6, 7, 8,10,
+ 11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9, 9,10,10,
+ 0, 0, 0,10,10, 9,10, 9,12,12, 0,10,10,12,12, 0,
+ 10,10,12,11, 0,12,12,13,13, 0, 0, 0,13,12, 8, 9,
+ 10,12,12, 0,10,10,12,12, 0,10,10,11,12, 0,12,12,
+ 13,13, 0, 0, 0,12,13, 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,
+ 7,10,10,13,13, 0, 9, 9,12,12, 0, 9, 9,12,12, 0,
+ 10,10,12,12, 0, 0, 0,12,12, 7,10,10,13,13, 0, 9,
+ 9,12,12, 0, 9, 9,12,12, 0,10,10,12,12, 0, 0, 0,
+ 12,12, 9,11,11,14,13, 0,10,10,13,12, 0,11,10,13,
+ 12, 0,12,12,13,12, 0, 0, 0,13,13, 9,11,11,13,14,
+ 0,10,11,12,13, 0,10,11,13,13, 0,12,12,12,13, 0,
+ 0, 0,13,13, 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, 9,
+ 11,11,14,14, 0,10,11,13,13, 0,11,10,13,13, 0,11,
+ 12,13,13, 0, 0, 0,13,12, 9,11,11,14,14, 0,11,10,
+ 13,13, 0,10,11,13,13, 0,12,12,13,13, 0, 0, 0,12,
+ 13,
+};
+
+static const static_codebook _44c8_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c8_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c8_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c8_s_p3_0[] = {
+ 2, 4, 4, 5, 5, 7, 7, 9, 9, 0, 4, 4, 6, 6, 7, 7,
+ 9, 9, 0, 4, 4, 6, 6, 7, 7, 9, 9, 0, 5, 5, 6, 6,
+ 8, 8,10,10, 0, 0, 0, 6, 6, 8, 8,10,10, 0, 0, 0,
+ 7, 7, 9, 9,10,10, 0, 0, 0, 7, 7, 8, 8,10,10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c8_s_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c8_s_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c8_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p4_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c8_s_p4_0[] = {
+ 3, 4, 4, 5, 5, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11,
+ 11, 0, 4, 4, 6, 6, 7, 7, 8, 8, 9, 8,10,10,11,11,
+ 11,11, 0, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,
+ 11,11,11, 0, 6, 5, 6, 6, 7, 7, 9, 9, 9, 9,10,10,
+ 11,11,12,12, 0, 0, 0, 6, 6, 7, 7, 9, 9, 9, 9,10,
+ 10,11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10,10,
+ 11,11,11,12,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10,
+ 10,11,11,11,12,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,
+ 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 8, 8, 9,
+ 9,10,10,11,11,12,12,13,13, 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,
+};
+
+static const static_codebook _44c8_s_p4_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c8_s_p4_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c8_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p5_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c8_s_p5_0[] = {
+ 1, 4, 4, 5, 7, 7, 6, 7, 7, 4, 7, 6,10,10,10,10,
+ 10,10, 4, 6, 6,10,10,10,10, 9,10, 5,10,10, 9,11,
+ 11,10,11,11, 7,10,10,11,12,12,12,12,12, 7,10,10,
+ 11,12,12,12,12,12, 6,10,10,10,12,12,10,12,12, 7,
+ 10,10,11,12,12,12,12,12, 7,10,10,11,12,12,12,12,
+ 12,
+};
+
+static const static_codebook _44c8_s_p5_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c8_s_p5_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c8_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p5_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c8_s_p5_1[] = {
+ 3, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8,11, 4, 5, 6, 6,
+ 7, 7, 8, 8, 8, 8,11, 5, 5, 6, 6, 7, 7, 8, 8, 8,
+ 9,12, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,12,12,12, 6,
+ 6, 7, 7, 8, 8, 9, 9,11,11,11, 6, 6, 7, 7, 8, 8,
+ 8, 8,11,11,11, 6, 6, 7, 7, 8, 8, 8, 8,11,11,11,
+ 7, 7, 7, 8, 8, 8, 8, 8,11,11,11,11,11, 7, 7, 8,
+ 8, 8, 8,11,11,11,11,11, 7, 7, 7, 7, 8, 8,11,11,
+ 11,11,11, 7, 7, 7, 7, 8, 8,
+};
+
+static const static_codebook _44c8_s_p5_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c8_s_p5_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c8_s_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c8_s_p6_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 6, 5, 5,
+ 7, 7, 8, 8, 9, 9,10,10,11,11, 6, 5, 5, 7, 7, 8,
+ 8, 9, 9,10,10,11,11, 0, 7, 7, 7, 7, 9, 9,10,10,
+ 10,10,11,11, 0, 7, 7, 7, 7, 9, 9,10,10,10,10,11,
+ 11, 0,11,11, 9, 9,10,10,11,11,11,11,12,12, 0,12,
+ 12, 9, 9,10,10,11,11,12,12,12,12, 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,
+};
+
+static const static_codebook _44c8_s_p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c8_s_p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c8_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c8_s_p6_1[] = {
+ 3, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5, 4, 4, 5, 5, 6,
+ 5, 5, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44c8_s_p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c8_s_p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c8_s_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c8_s_p7_0[] = {
+ 1, 4, 4, 6, 6, 8, 7, 9, 9,10,10,12,12, 6, 5, 5,
+ 7, 7, 8, 8,10,10,11,11,12,12, 7, 5, 5, 7, 7, 8,
+ 8,10,10,11,11,12,12,21, 7, 7, 7, 7, 8, 9,10,10,
+ 11,11,12,12,21, 7, 7, 7, 7, 9, 9,10,10,12,12,13,
+ 13,21,11,11, 8, 8, 9, 9,11,11,12,12,13,13,21,11,
+ 11, 8, 8, 9, 9,11,11,12,12,13,13,21,21,21,10,10,
+ 10,10,11,11,12,13,13,13,21,21,21,10,10,10,10,11,
+ 11,13,13,14,13,21,21,21,13,13,11,11,12,12,13,13,
+ 14,14,21,21,21,14,14,11,11,12,12,13,13,14,14,21,
+ 21,21,21,20,13,13,13,12,14,14,16,15,20,20,20,20,
+ 20,13,13,13,13,14,13,15,15,
+};
+
+static const static_codebook _44c8_s_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c8_s_p7_0,
+ 1, -523206656, 1618345984, 4, 0,
+ (long *)_vq_quantlist__44c8_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c8_s_p7_1[] = {
+ 4, 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 6, 6, 6, 7,
+ 7, 7, 7, 7, 7, 7, 8, 6, 6, 6, 6, 7, 7, 7, 7, 7,
+ 7, 8, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 7,
+ 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7,
+ 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8,
+ 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7,
+ 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 8, 8,
+ 8, 8, 8, 7, 7, 7, 7, 7, 7,
+};
+
+static const static_codebook _44c8_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c8_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c8_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p8_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44c8_s_p8_0[] = {
+ 1, 4, 4, 7, 6, 8, 8, 8, 7, 9, 8,10,10,11,10, 6,
+ 5, 5, 7, 7, 9, 9, 8, 8,10,10,11,11,12,11, 6, 5,
+ 5, 7, 7, 9, 9, 9, 9,10,10,11,11,12,12,20, 8, 8,
+ 8, 8, 9, 9, 9, 9,10,10,11,11,12,12,20, 8, 8, 8,
+ 8,10, 9, 9, 9,10,10,11,11,12,12,20,12,12, 9, 9,
+ 10,10,10,10,10,11,12,12,12,12,20,12,12, 9, 9,10,
+ 10,10,10,11,11,12,12,13,13,20,20,20, 9, 9, 9, 9,
+ 11,10,11,11,12,12,12,13,20,19,19, 9, 9, 9, 9,11,
+ 11,11,12,12,12,13,13,19,19,19,13,13,10,10,11,11,
+ 12,12,13,13,13,13,19,19,19,14,13,11,10,11,11,12,
+ 12,12,13,13,13,19,19,19,19,19,12,12,12,12,13,13,
+ 13,13,14,13,19,19,19,19,19,12,12,12,11,12,12,13,
+ 14,14,14,19,19,19,19,19,16,15,13,12,13,13,13,14,
+ 14,14,19,19,19,19,19,17,17,13,12,13,11,14,13,15,
+ 15,
+};
+
+static const static_codebook _44c8_s_p8_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44c8_s_p8_0,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__44c8_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p8_1[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__44c8_s_p8_1[] = {
+ 4, 5, 5, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 6, 6, 7, 7, 8,
+ 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,
+ 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,
+ 10, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,
+ 10,10, 9, 9, 9, 9, 9, 9, 9, 9,10, 9, 9, 9, 9, 9,
+ 9, 9,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10, 9, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10, 9, 9, 9, 9, 9,10,10,10,10,
+ 10,10,10, 9, 9, 9, 9, 9,10,10,10, 9, 9, 9, 9, 9,
+ 9,10,10,10,10,10,10,10, 9,10,10, 9,10,10,10,10,
+ 9,10, 9,10,10, 9,10,10,10,10,10,10,10, 9,10,10,
+ 10,10,10,10, 9, 9,10,10, 9,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10, 9, 9, 9,10, 9, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9,
+ 10, 9,10, 9,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10, 9, 9,10, 9, 9, 9,10,10,10,10,10,10,
+ 10,10,10,10,10, 9, 9, 9, 9, 9, 9,10, 9, 9,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10, 9,10, 9,
+ 9,10, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10, 9, 9,10,10, 9,10, 9, 9,
+};
+
+static const static_codebook _44c8_s_p8_1 = {
+ 2, 441,
+ (char *)_vq_lengthlist__44c8_s_p8_1,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c8_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p9_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c8_s_p9_0[] = {
+ 1, 4, 3,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11, 4, 7, 7,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11, 4, 8,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _44c8_s_p9_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c8_s_p9_0,
+ 1, -509798400, 1631393792, 5, 0,
+ (long *)_vq_quantlist__44c8_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p9_1[] = {
+ 9,
+ 8,
+ 10,
+ 7,
+ 11,
+ 6,
+ 12,
+ 5,
+ 13,
+ 4,
+ 14,
+ 3,
+ 15,
+ 2,
+ 16,
+ 1,
+ 17,
+ 0,
+ 18,
+};
+
+static const char _vq_lengthlist__44c8_s_p9_1[] = {
+ 1, 4, 4, 7, 6, 7, 7, 7, 7, 8, 8, 9, 9,10,10,10,
+ 10,11,11, 6, 6, 6, 8, 8, 9, 8, 8, 7,10, 8,11,10,
+ 12,11,12,12,13,13, 5, 5, 6, 8, 8, 9, 9, 8, 8,10,
+ 9,11,11,12,12,13,13,13,13,17, 8, 8, 9, 9, 9, 9,
+ 9, 9,10, 9,12,10,12,12,13,12,13,13,17, 9, 8, 9,
+ 9, 9, 9, 9, 9,10,10,12,12,12,12,13,13,13,13,17,
+ 13,13, 9, 9,10,10,10,10,11,11,12,11,13,12,13,13,
+ 14,15,17,13,13, 9, 8,10, 9,10,10,11,11,12,12,14,
+ 13,15,13,14,15,17,17,17, 9,10, 9,10,11,11,12,12,
+ 12,12,13,13,14,14,15,15,17,17,17, 9, 8, 9, 8,11,
+ 11,12,12,12,12,14,13,14,14,14,15,17,17,17,12,14,
+ 9,10,11,11,12,12,14,13,13,14,15,13,15,15,17,17,
+ 17,13,11,10, 8,11, 9,13,12,13,13,13,13,13,14,14,
+ 14,17,17,17,17,17,11,12,11,11,13,13,14,13,15,14,
+ 13,15,16,15,17,17,17,17,17,11,11,12, 8,13,12,14,
+ 13,17,14,15,14,15,14,17,17,17,17,17,15,15,12,12,
+ 12,12,13,14,14,14,15,14,17,14,17,17,17,17,17,16,
+ 17,12,12,13,12,13,13,14,14,14,14,14,14,17,17,17,
+ 17,17,17,17,14,14,13,12,13,13,15,15,14,13,15,17,
+ 17,17,17,17,17,17,17,13,14,13,13,13,13,14,15,15,
+ 15,14,15,17,17,17,17,17,17,17,16,15,13,14,13,13,
+ 14,14,15,14,14,16,17,17,17,17,17,17,17,16,16,13,
+ 14,13,13,14,14,15,14,15,14,
+};
+
+static const static_codebook _44c8_s_p9_1 = {
+ 2, 361,
+ (char *)_vq_lengthlist__44c8_s_p9_1,
+ 1, -518287360, 1622704128, 5, 0,
+ (long *)_vq_quantlist__44c8_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44c8_s_p9_2[] = {
+ 24,
+ 23,
+ 25,
+ 22,
+ 26,
+ 21,
+ 27,
+ 20,
+ 28,
+ 19,
+ 29,
+ 18,
+ 30,
+ 17,
+ 31,
+ 16,
+ 32,
+ 15,
+ 33,
+ 14,
+ 34,
+ 13,
+ 35,
+ 12,
+ 36,
+ 11,
+ 37,
+ 10,
+ 38,
+ 9,
+ 39,
+ 8,
+ 40,
+ 7,
+ 41,
+ 6,
+ 42,
+ 5,
+ 43,
+ 4,
+ 44,
+ 3,
+ 45,
+ 2,
+ 46,
+ 1,
+ 47,
+ 0,
+ 48,
+};
+
+static const char _vq_lengthlist__44c8_s_p9_2[] = {
+ 2, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7,
+};
+
+static const static_codebook _44c8_s_p9_2 = {
+ 1, 49,
+ (char *)_vq_lengthlist__44c8_s_p9_2,
+ 1, -526909440, 1611661312, 6, 0,
+ (long *)_vq_quantlist__44c8_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c8_s_short[] = {
+ 4,11,13,14,15,15,18,17,19,17, 5, 6, 8, 9,10,10,
+ 12,15,19,19, 6, 6, 6, 6, 8, 8,11,14,18,19, 8, 6,
+ 5, 4, 6, 7,10,13,16,17, 9, 7, 6, 5, 6, 7, 9,12,
+ 15,19,10, 8, 7, 6, 6, 6, 7, 9,13,15,12,10, 9, 8,
+ 7, 6, 4, 5,10,15,13,13,11, 8, 6, 6, 4, 2, 7,12,
+ 17,15,16,10, 8, 8, 7, 6, 9,12,19,18,17,13,11,10,
+ 10, 9,11,14,
+};
+
+static const static_codebook _huff_book__44c8_s_short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c8_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c9_s_long[] = {
+ 3, 8,12,14,15,15,15,13,15,15, 6, 5, 8,10,12,12,
+ 13,12,14,13,10, 6, 5, 6, 8, 9,11,11,13,13,13, 8,
+ 5, 4, 5, 6, 8,10,11,13,14,10, 7, 5, 4, 5, 7, 9,
+ 11,12,13,11, 8, 6, 5, 4, 5, 7, 9,11,12,11,10, 8,
+ 7, 5, 4, 5, 9,10,13,13,11,10, 8, 6, 5, 4, 7, 9,
+ 15,14,13,12,10, 9, 8, 7, 8, 9,12,12,14,13,12,11,
+ 10, 9, 8, 9,
+};
+
+static const static_codebook _huff_book__44c9_s_long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c9_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c9_s_p1_0[] = {
+ 1, 5, 5, 0, 5, 5, 0, 5, 5, 6, 8, 8, 0, 9, 8, 0,
+ 9, 8, 6, 8, 8, 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 8, 8, 0, 7, 7, 0, 8, 8, 5, 8, 8,
+ 0, 7, 8, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
+ 9, 8, 0, 8, 8, 0, 7, 7, 5, 8, 9, 0, 8, 8, 0, 7,
+ 7,
+};
+
+static const static_codebook _44c9_s_p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c9_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c9_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c9_s_p2_0[] = {
+ 3, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0,
+ 7, 7, 9, 9, 0, 0, 0, 9, 9, 6, 7, 7, 9, 8, 0, 8,
+ 8, 9, 9, 0, 8, 7, 9, 9, 0, 9,10,10,10, 0, 0, 0,
+ 11,10, 6, 7, 7, 8, 9, 0, 8, 8, 9, 9, 0, 7, 8, 9,
+ 9, 0,10, 9,11,10, 0, 0, 0,10,10, 8, 9, 8,10,10,
+ 0,10,10,12,11, 0,10,10,11,11, 0,12,13,13,13, 0,
+ 0, 0,13,12, 8, 8, 9,10,10, 0,10,10,11,12, 0,10,
+ 10,11,11, 0,13,12,13,13, 0, 0, 0,13,13, 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, 6, 8, 7,10,10, 0, 7, 7,10, 9,
+ 0, 7, 7,10,10, 0, 9, 9,10,10, 0, 0, 0,10,10, 6,
+ 7, 8,10,10, 0, 7, 7, 9,10, 0, 7, 7,10,10, 0, 9,
+ 9,10,10, 0, 0, 0,10,10, 8, 9, 9,11,11, 0,10,10,
+ 11,11, 0,10,10,11,11, 0,12,12,12,12, 0, 0, 0,12,
+ 12, 8, 9,10,11,11, 0, 9,10,11,11, 0,10,10,11,11,
+ 0,12,12,12,12, 0, 0, 0,12,12, 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, 5, 8, 7,10,10, 0, 7, 7,10,10, 0, 7, 7,
+ 10, 9, 0, 9, 9,10,10, 0, 0, 0,10,10, 6, 7, 8,10,
+ 10, 0, 7, 7,10,10, 0, 7, 7, 9,10, 0, 9, 9,10,10,
+ 0, 0, 0,10,10, 8,10, 9,12,11, 0,10,10,12,11, 0,
+ 10, 9,11,11, 0,11,12,12,12, 0, 0, 0,12,12, 8, 9,
+ 10,11,12, 0,10,10,11,11, 0, 9,10,11,11, 0,12,11,
+ 12,12, 0, 0, 0,12,12, 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,
+ 7,10, 9,12,12, 0, 9, 9,12,11, 0, 9, 9,11,11, 0,
+ 10,10,12,11, 0, 0, 0,11,12, 7, 9,10,12,12, 0, 9,
+ 9,11,12, 0, 9, 9,11,11, 0,10,10,11,12, 0, 0, 0,
+ 11,11, 9,11,10,13,12, 0,10,10,12,12, 0,10,10,12,
+ 12, 0,11,11,12,12, 0, 0, 0,13,12, 9,10,11,12,13,
+ 0,10,10,12,12, 0,10,10,12,12, 0,11,12,12,12, 0,
+ 0, 0,12,13, 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, 9,
+ 11,10,13,13, 0,10,10,12,12, 0,10,10,12,12, 0,11,
+ 12,12,12, 0, 0, 0,12,12, 9,10,11,13,13, 0,10,10,
+ 12,12, 0,10,10,12,12, 0,12,11,13,12, 0, 0, 0,12,
+ 12,
+};
+
+static const static_codebook _44c9_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c9_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c9_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c9_s_p3_0[] = {
+ 3, 4, 4, 5, 5, 6, 6, 8, 8, 0, 4, 4, 5, 5, 6, 7,
+ 8, 8, 0, 4, 4, 5, 5, 7, 7, 8, 8, 0, 5, 5, 6, 6,
+ 7, 7, 9, 9, 0, 0, 0, 6, 6, 7, 7, 9, 9, 0, 0, 0,
+ 7, 7, 8, 8, 9, 9, 0, 0, 0, 7, 7, 8, 8, 9, 9, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c9_s_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c9_s_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c9_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p4_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c9_s_p4_0[] = {
+ 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,10,
+ 10, 0, 5, 4, 5, 5, 7, 7, 8, 8, 8, 8, 9, 9,10,10,
+ 11,11, 0, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,
+ 10,11,11, 0, 6, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,
+ 11,11,11,12, 0, 0, 0, 6, 6, 7, 7, 8, 8, 9, 9,10,
+ 10,11,11,12,12, 0, 0, 0, 7, 7, 7, 7, 9, 9, 9, 9,
+ 10,10,11,11,12,12, 0, 0, 0, 7, 7, 7, 8, 9, 9, 9,
+ 9,10,10,11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,
+ 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 8, 8, 9,
+ 9,10,10,11,11,12,12,12,12, 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,
+};
+
+static const static_codebook _44c9_s_p4_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c9_s_p4_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c9_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p5_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c9_s_p5_0[] = {
+ 1, 4, 4, 5, 7, 7, 6, 7, 7, 4, 7, 6, 9,10,10,10,
+ 10, 9, 4, 6, 7, 9,10,10,10, 9,10, 5, 9, 9, 9,11,
+ 11,10,11,11, 7,10, 9,11,12,11,12,12,12, 7, 9,10,
+ 11,11,12,12,12,12, 6,10,10,10,12,12,10,12,11, 7,
+ 10,10,11,12,12,11,12,12, 7,10,10,11,12,12,12,12,
+ 12,
+};
+
+static const static_codebook _44c9_s_p5_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c9_s_p5_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c9_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p5_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c9_s_p5_1[] = {
+ 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7,11, 5, 5, 6, 6,
+ 7, 7, 7, 7, 8, 8,11, 5, 5, 6, 6, 7, 7, 7, 7, 8,
+ 8,11, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8,11,11,11, 6,
+ 6, 7, 7, 7, 8, 8, 8,11,11,11, 6, 6, 7, 7, 7, 8,
+ 8, 8,11,11,11, 6, 6, 7, 7, 7, 7, 8, 8,11,11,11,
+ 7, 7, 7, 7, 7, 7, 8, 8,11,11,11,10,10, 7, 7, 7,
+ 7, 8, 8,11,11,11,11,11, 7, 7, 7, 7, 7, 7,11,11,
+ 11,11,11, 7, 7, 7, 7, 7, 7,
+};
+
+static const static_codebook _44c9_s_p5_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c9_s_p5_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c9_s_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c9_s_p6_0[] = {
+ 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 5, 4, 4,
+ 6, 6, 8, 8, 9, 9, 9, 9,10,10, 6, 4, 4, 6, 6, 8,
+ 8, 9, 9, 9, 9,10,10, 0, 6, 6, 7, 7, 8, 8, 9, 9,
+ 10,10,11,11, 0, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,
+ 11, 0,10,10, 8, 8, 9, 9,10,10,11,11,12,12, 0,11,
+ 11, 8, 8, 9, 9,10,10,11,11,12,12, 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,
+};
+
+static const static_codebook _44c9_s_p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c9_s_p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c9_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c9_s_p6_1[] = {
+ 4, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44c9_s_p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c9_s_p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c9_s_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c9_s_p7_0[] = {
+ 2, 4, 4, 6, 6, 7, 7, 8, 8,10,10,11,11, 6, 4, 4,
+ 6, 6, 8, 8, 9, 9,10,10,12,12, 6, 4, 5, 6, 6, 8,
+ 8, 9, 9,10,10,12,12,20, 6, 6, 6, 6, 8, 8, 9,10,
+ 11,11,12,12,20, 6, 6, 6, 6, 8, 8,10,10,11,11,12,
+ 12,20,10,10, 7, 7, 9, 9,10,10,11,11,12,12,20,11,
+ 11, 7, 7, 9, 9,10,10,11,11,12,12,20,20,20, 9, 9,
+ 9, 9,11,11,12,12,13,13,20,20,20, 9, 9, 9, 9,11,
+ 11,12,12,13,13,20,20,20,13,13,10,10,11,11,12,13,
+ 13,13,20,20,20,13,13,10,10,11,11,12,13,13,13,20,
+ 20,20,20,19,12,12,12,12,13,13,14,15,19,19,19,19,
+ 19,12,12,12,12,13,13,14,14,
+};
+
+static const static_codebook _44c9_s_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c9_s_p7_0,
+ 1, -523206656, 1618345984, 4, 0,
+ (long *)_vq_quantlist__44c9_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c9_s_p7_1[] = {
+ 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7, 7,
+ 7, 8, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 6,
+ 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7,
+ 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8,
+ 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7,
+ 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 8, 8,
+ 8, 8, 8, 7, 7, 7, 7, 7, 7,
+};
+
+static const static_codebook _44c9_s_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c9_s_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c9_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p8_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44c9_s_p8_0[] = {
+ 1, 4, 4, 7, 6, 8, 8, 8, 8, 9, 9,10,10,11,10, 6,
+ 5, 5, 7, 7, 9, 9, 8, 9,10,10,11,11,12,12, 6, 5,
+ 5, 7, 7, 9, 9, 9, 9,10,10,11,11,12,12,21, 7, 8,
+ 8, 8, 9, 9, 9, 9,10,10,11,11,12,12,21, 8, 8, 8,
+ 8, 9, 9, 9, 9,10,10,11,11,12,12,21,11,12, 9, 9,
+ 10,10,10,10,10,11,11,12,12,12,21,12,12, 9, 8,10,
+ 10,10,10,11,11,12,12,13,13,21,21,21, 9, 9, 9, 9,
+ 11,11,11,11,12,12,12,13,21,20,20, 9, 9, 9, 9,10,
+ 11,11,11,12,12,13,13,20,20,20,13,13,10,10,11,11,
+ 12,12,13,13,13,13,20,20,20,13,13,10,10,11,11,12,
+ 12,13,13,13,13,20,20,20,20,20,12,12,12,12,12,12,
+ 13,13,14,14,20,20,20,20,20,12,12,12,11,13,12,13,
+ 13,14,14,20,20,20,20,20,15,16,13,12,13,13,14,13,
+ 14,14,20,20,20,20,20,16,15,12,12,13,12,14,13,14,
+ 14,
+};
+
+static const static_codebook _44c9_s_p8_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44c9_s_p8_0,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__44c9_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p8_1[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__44c9_s_p8_1[] = {
+ 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 6, 6, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,
+ 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,
+ 10, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,
+ 10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10, 9, 9, 9,10,10,10,10,
+ 10,10,10, 9, 9, 9, 9, 9, 9,10, 9, 9, 9, 9, 9, 9,
+ 9,10,10,10,10,10,10,10, 9, 9, 9,10,10,10,10,10,
+ 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10, 9, 9,10,
+ 9,10, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,
+ 10,10,10,10, 9, 9,10,10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9,
+ 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10, 9, 9,10, 9, 9, 9, 9, 9,10,10,10,10,10,10,
+ 10,10,10,10,10, 9, 9,10,10, 9, 9,10, 9, 9, 9,10,
+ 10,10,10,10,10,10,10,10,10,10, 9, 9,10, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10, 9,
+ 9, 9, 9,10, 9, 9, 9, 9, 9,
+};
+
+static const static_codebook _44c9_s_p8_1 = {
+ 2, 441,
+ (char *)_vq_lengthlist__44c9_s_p8_1,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c9_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p9_0[] = {
+ 9,
+ 8,
+ 10,
+ 7,
+ 11,
+ 6,
+ 12,
+ 5,
+ 13,
+ 4,
+ 14,
+ 3,
+ 15,
+ 2,
+ 16,
+ 1,
+ 17,
+ 0,
+ 18,
+};
+
+static const char _vq_lengthlist__44c9_s_p9_0[] = {
+ 1, 4, 3,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12, 4, 5, 6,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12, 4, 6, 6,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,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,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,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,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,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,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,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,
+};
+
+static const static_codebook _44c9_s_p9_0 = {
+ 2, 361,
+ (char *)_vq_lengthlist__44c9_s_p9_0,
+ 1, -508535424, 1631393792, 5, 0,
+ (long *)_vq_quantlist__44c9_s_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p9_1[] = {
+ 9,
+ 8,
+ 10,
+ 7,
+ 11,
+ 6,
+ 12,
+ 5,
+ 13,
+ 4,
+ 14,
+ 3,
+ 15,
+ 2,
+ 16,
+ 1,
+ 17,
+ 0,
+ 18,
+};
+
+static const char _vq_lengthlist__44c9_s_p9_1[] = {
+ 1, 4, 4, 7, 7, 7, 7, 8, 7, 9, 8, 9, 9,10,10,11,
+ 11,11,11, 6, 5, 5, 8, 8, 9, 9, 9, 8,10, 9,11,10,
+ 12,12,13,12,13,13, 5, 5, 5, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,12,12,13,12,13,13,17, 8, 8, 9, 9, 9, 9,
+ 9, 9,10,10,12,11,13,12,13,13,13,13,18, 8, 8, 9,
+ 9, 9, 9, 9, 9,11,11,12,12,13,13,13,13,13,13,17,
+ 13,12, 9, 9,10,10,10,10,11,11,12,12,12,13,13,13,
+ 14,14,18,13,12, 9, 9,10,10,10,10,11,11,12,12,13,
+ 13,13,14,14,14,17,18,18,10,10,10,10,11,11,11,12,
+ 12,12,14,13,14,13,13,14,18,18,18,10, 9,10, 9,11,
+ 11,12,12,12,12,13,13,15,14,14,14,18,18,16,13,14,
+ 10,11,11,11,12,13,13,13,13,14,13,13,14,14,18,18,
+ 18,14,12,11, 9,11,10,13,12,13,13,13,14,14,14,13,
+ 14,18,18,17,18,18,11,12,12,12,13,13,14,13,14,14,
+ 13,14,14,14,18,18,18,18,17,12,10,12, 9,13,11,13,
+ 14,14,14,14,14,15,14,18,18,17,17,18,14,15,12,13,
+ 13,13,14,13,14,14,15,14,15,14,18,17,18,18,18,15,
+ 15,12,10,14,10,14,14,13,13,14,14,14,14,18,16,18,
+ 18,18,18,17,14,14,13,14,14,13,13,14,14,14,15,15,
+ 18,18,18,18,17,17,17,14,14,14,12,14,13,14,14,15,
+ 14,15,14,18,18,18,18,18,18,18,17,16,13,13,13,14,
+ 14,14,14,15,16,15,18,18,18,18,18,18,18,17,17,13,
+ 13,13,13,14,13,14,15,15,15,
+};
+
+static const static_codebook _44c9_s_p9_1 = {
+ 2, 361,
+ (char *)_vq_lengthlist__44c9_s_p9_1,
+ 1, -518287360, 1622704128, 5, 0,
+ (long *)_vq_quantlist__44c9_s_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44c9_s_p9_2[] = {
+ 24,
+ 23,
+ 25,
+ 22,
+ 26,
+ 21,
+ 27,
+ 20,
+ 28,
+ 19,
+ 29,
+ 18,
+ 30,
+ 17,
+ 31,
+ 16,
+ 32,
+ 15,
+ 33,
+ 14,
+ 34,
+ 13,
+ 35,
+ 12,
+ 36,
+ 11,
+ 37,
+ 10,
+ 38,
+ 9,
+ 39,
+ 8,
+ 40,
+ 7,
+ 41,
+ 6,
+ 42,
+ 5,
+ 43,
+ 4,
+ 44,
+ 3,
+ 45,
+ 2,
+ 46,
+ 1,
+ 47,
+ 0,
+ 48,
+};
+
+static const char _vq_lengthlist__44c9_s_p9_2[] = {
+ 2, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7,
+};
+
+static const static_codebook _44c9_s_p9_2 = {
+ 1, 49,
+ (char *)_vq_lengthlist__44c9_s_p9_2,
+ 1, -526909440, 1611661312, 6, 0,
+ (long *)_vq_quantlist__44c9_s_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c9_s_short[] = {
+ 5,13,18,16,17,17,19,18,19,19, 5, 7,10,11,12,12,
+ 13,16,17,18, 6, 6, 7, 7, 9, 9,10,14,17,19, 8, 7,
+ 6, 5, 6, 7, 9,12,19,17, 8, 7, 7, 6, 5, 6, 8,11,
+ 15,19, 9, 8, 7, 6, 5, 5, 6, 8,13,15,11,10, 8, 8,
+ 7, 5, 4, 4,10,14,12,13,11, 9, 7, 6, 4, 2, 6,12,
+ 18,16,16,13, 8, 7, 7, 5, 8,13,16,17,18,15,11, 9,
+ 9, 8,10,13,
+};
+
+static const static_codebook _huff_book__44c9_s_short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44c9_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c0_s_long[] = {
+ 5, 4, 8, 9, 8, 9,10,12,15, 4, 1, 5, 5, 6, 8,11,
+ 12,12, 8, 5, 8, 9, 9,11,13,12,12, 9, 5, 8, 5, 7,
+ 9,12,13,13, 8, 6, 8, 7, 7, 9,11,11,11, 9, 7, 9,
+ 7, 7, 7, 7,10,12,10,10,11, 9, 8, 7, 7, 9,11,11,
+ 12,13,12,11, 9, 8, 9,11,13,16,16,15,15,12,10,11,
+ 12,
+};
+
+static const static_codebook _huff_book__44c0_s_long = {
+ 2, 81,
+ (char *)_huff_lengthlist__44c0_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c0_s_p1_0[] = {
+ 1, 5, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 5, 7, 7, 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, 5, 8, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0,
+ 0, 0, 0, 7, 9, 9, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 7, 9, 9, 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, 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, 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, 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, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 7, 9, 9, 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, 7, 9, 9, 0, 0, 0,
+ 0, 0, 0, 9,10,11, 0, 0, 0, 0, 0, 0, 9,11,10, 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, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 9,11, 9, 0, 0, 0, 0, 0, 0, 9,10,11,
+ 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, 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, 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, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8, 9, 9, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,11,10, 0,
+ 0, 0, 0, 0, 0, 9, 9,11, 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, 7, 9,10, 0, 0, 0, 0, 0, 0, 9,10,11,
+ 0, 0, 0, 0, 0, 0, 9,11,10, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c0_s_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__44c0_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c0_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c0_s_p2_0[] = {
+ 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 7, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 5, 6, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 7, 9, 9,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 7, 7, 9, 9, 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, 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, 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, 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,
+};
+
+static const static_codebook _44c0_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c0_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c0_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c0_s_p3_0[] = {
+ 1, 3, 2, 8, 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7,
+ 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0,
+ 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0,
+ 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c0_s_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c0_s_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c0_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c0_s_p4_0[] = {
+ 1, 3, 3, 6, 6, 6, 6, 8, 8, 0, 0, 0, 7, 7, 7, 7,
+ 9, 9, 0, 0, 0, 7, 7, 7, 7, 9, 9, 0, 0, 0, 7, 7,
+ 7, 8, 9, 9, 0, 0, 0, 7, 7, 7, 7, 9, 9, 0, 0, 0,
+ 9, 9, 8, 8,10,10, 0, 0, 0, 8, 9, 8, 8,10,10, 0,
+ 0, 0,10,10, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,
+};
+
+static const static_codebook _44c0_s_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c0_s_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c0_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p5_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c0_s_p5_0[] = {
+ 1, 4, 3, 6, 6, 8, 7, 8, 8, 8, 8, 9, 9,10,10,11,
+ 11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9, 9,10,10,10,
+ 11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,
+ 10,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,11,11, 0, 0, 0, 8, 8, 9, 9, 9, 9,10,10,
+ 10,10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9, 9, 9,10,
+ 10,10,10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,
+ 10,10,11,11,11,12,12,12, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9, 9,
+ 10,10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9,
+ 9,10,10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0,
+ 10,10,11,11,11,11,11,12,12,12,13,13, 0, 0, 0, 0,
+ 0, 0, 0,11,10,11,11,11,11,12,12,13,13, 0, 0, 0,
+ 0, 0, 0, 0,11,11,12,11,12,12,12,12,13,13, 0, 0,
+ 0, 0, 0, 0, 0,11,11,11,12,12,12,12,13,13,13, 0,
+ 0, 0, 0, 0, 0, 0,12,12,12,12,12,13,13,13,14,14,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,14,
+ 14,
+};
+
+static const static_codebook _44c0_s_p5_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c0_s_p5_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c0_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c0_s_p6_0[] = {
+ 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,10,
+ 9, 9, 4, 6, 7,10, 9, 9,11, 9, 9, 7,10,10,11,11,
+ 11,12,10,11, 6, 9, 9,11,10,11,11,10,10, 6, 9, 9,
+ 11,10,11,11,10,10, 7,11,10,12,11,11,11,11,11, 7,
+ 9, 9,10,10,10,11,11,10, 6, 9, 9,11,10,10,11,10,
+ 10,
+};
+
+static const static_codebook _44c0_s_p6_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c0_s_p6_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c0_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p6_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c0_s_p6_1[] = {
+ 2, 3, 3, 6, 6, 7, 7, 7, 7, 7, 8,10,10,10, 6, 6,
+ 7, 7, 8, 8, 8, 8,10,10,10, 6, 6, 7, 7, 8, 8, 8,
+ 8,10,10,10, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7,
+ 7, 7, 7, 8, 8, 8, 8,10,10,10, 8, 7, 8, 8, 8, 8,
+ 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10,
+ 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8,
+ 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10,
+ 10,10,10, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44c0_s_p6_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c0_s_p6_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c0_s_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c0_s_p7_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 7, 5, 5,
+ 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 5, 6, 7, 7, 8,
+ 8, 8, 8, 9, 9,10,10, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,12,12, 9, 9,10,10,10,10,11,11,11,11, 0,13,
+ 13, 9, 9, 9, 9,10,10,11,11,11,12, 0, 0, 0,10,10,
+ 10,10,11,11,11,11,12,12, 0, 0, 0,10,10, 9, 9,11,
+ 11,11,12,12,12, 0, 0, 0,13,13,10,10,11,11,12,12,
+ 13,13, 0, 0, 0,14,14,10,10,11,11,12,12,13,13, 0,
+ 0, 0, 0, 0,11,11,11,11,13,12,13,13, 0, 0, 0, 0,
+ 0,12,12,11,11,12,12,13,13,
+};
+
+static const static_codebook _44c0_s_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c0_s_p7_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c0_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p7_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c0_s_p7_1[] = {
+ 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6,
+ 6, 6, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44c0_s_p7_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c0_s_p7_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c0_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p8_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c0_s_p8_0[] = {
+ 1, 5, 5,10,10, 6, 9, 8,10,10, 6,10, 9,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10, 8,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,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,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,
+};
+
+static const static_codebook _44c0_s_p8_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c0_s_p8_0,
+ 1, -518283264, 1627103232, 3, 0,
+ (long *)_vq_quantlist__44c0_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p8_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c0_s_p8_1[] = {
+ 1, 4, 4, 6, 6, 7, 7, 9, 9,11,12,13,12, 6, 5, 5,
+ 7, 7, 8, 8,10, 9,12,12,12,12, 6, 5, 5, 7, 7, 8,
+ 8,10, 9,12,11,11,13,16, 7, 7, 8, 8, 9, 9,10,10,
+ 12,12,13,12,16, 7, 7, 8, 7, 9, 9,10,10,11,12,12,
+ 13,16,10,10, 8, 8,10,10,11,12,12,12,13,13,16,11,
+ 10, 8, 7,11,10,11,11,12,11,13,13,16,16,16,10,10,
+ 10,10,11,11,13,12,13,13,16,16,16,11, 9,11, 9,15,
+ 13,12,13,13,13,16,16,16,15,13,11,11,12,13,12,12,
+ 14,13,16,16,16,14,13,11,11,13,12,14,13,13,13,16,
+ 16,16,16,16,13,13,13,12,14,13,14,14,16,16,16,16,
+ 16,13,13,12,12,14,14,15,13,
+};
+
+static const static_codebook _44c0_s_p8_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c0_s_p8_1,
+ 1, -522616832, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44c0_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c0_s_p8_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c0_s_p8_2[] = {
+ 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8,10,10,10, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9,10,10,10, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9,10,10,10, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9,10, 9, 9,10,10,10, 7, 7, 8, 8, 9, 8, 9, 9, 9,
+ 9,10, 9, 9,10,10,10,10, 8, 8, 8, 8, 9, 8, 9, 9,
+ 9, 9, 9,10, 9,10,10,10,10, 7, 7, 8, 8, 9, 9, 9,
+ 9, 9, 9,10, 9,10,10,10,10,10, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10, 9,11,10,10,10,10, 8, 8, 9,
+ 9, 9, 9, 9,10, 9, 9, 9,10,10,10,10,11,11, 9, 9,
+ 9, 9, 9, 9, 9, 9,10, 9, 9,10,11,10,10,11,11, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,11,11,10,11,11,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,11,10,10,11,
+ 11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,
+ 11,11,11,11, 9,10, 9,10, 9, 9, 9, 9,10, 9,10,11,
+ 10,11,10,10,10,10,10, 9, 9, 9,10, 9, 9, 9,10,11,
+ 11,10,11,11,10,11,10,10,10, 9, 9, 9, 9,10, 9, 9,
+ 10,11,10,11,11,11,11,10,11,10,10, 9,10, 9, 9, 9,
+ 10,
+};
+
+static const static_codebook _44c0_s_p8_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c0_s_p8_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c0_s_p8_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c0_s_short[] = {
+ 9, 8,12,11,12,13,14,14,16, 6, 1, 5, 6, 6, 9,12,
+ 14,17, 9, 4, 5, 9, 7, 9,13,15,16, 8, 5, 8, 6, 8,
+ 10,13,17,17, 9, 6, 7, 7, 8, 9,13,15,17,11, 8, 9,
+ 9, 9,10,12,16,16,13, 7, 8, 7, 7, 9,12,14,15,13,
+ 6, 7, 5, 5, 7,10,13,13,14, 7, 8, 5, 6, 7, 9,10,
+ 12,
+};
+
+static const static_codebook _huff_book__44c0_s_short = {
+ 2, 81,
+ (char *)_huff_lengthlist__44c0_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c0_sm_long[] = {
+ 5, 4, 9,10, 9,10,11,12,13, 4, 1, 5, 7, 7, 9,11,
+ 12,14, 8, 5, 7, 9, 8,10,13,13,13,10, 7, 9, 4, 6,
+ 7,10,12,14, 9, 6, 7, 6, 6, 7,10,12,12, 9, 8, 9,
+ 7, 6, 7, 8,11,12,11,11,11, 9, 8, 7, 8,10,12,12,
+ 13,14,12,11, 9, 9, 9,12,12,17,17,15,16,12,10,11,
+ 13,
+};
+
+static const static_codebook _huff_book__44c0_sm_long = {
+ 2, 81,
+ (char *)_huff_lengthlist__44c0_sm_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c0_sm_p1_0[] = {
+ 1, 5, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 5, 7, 7, 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, 5, 8, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0,
+ 0, 0, 0, 7, 8, 9, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0,
+ 0, 0, 0, 0, 7, 9, 9, 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, 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, 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, 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, 5, 8, 7, 0, 0, 0, 0,
+ 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 7, 9, 9, 0, 0, 0,
+ 0, 0, 0, 9,10,10, 0, 0, 0, 0, 0, 0, 9,10,10, 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, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 9,10,10,
+ 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, 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, 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, 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, 5, 7, 8, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8, 9, 9, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, 0,
+ 0, 0, 0, 0, 0, 9, 9,10, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10,
+ 0, 0, 0, 0, 0, 0, 9,10,10, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c0_sm_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__44c0_sm_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c0_sm_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c0_sm_p2_0[] = {
+ 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 7, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 5, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 7, 9, 9,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 7, 7, 9, 9, 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, 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, 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, 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,
+};
+
+static const static_codebook _44c0_sm_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c0_sm_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c0_sm_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c0_sm_p3_0[] = {
+ 1, 3, 3, 7, 7, 0, 0, 0, 0, 0, 5, 4, 7, 7, 0, 0,
+ 0, 0, 0, 5, 5, 7, 7, 0, 0, 0, 0, 0, 6, 7, 8, 8,
+ 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0,
+ 9,10, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0,
+ 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c0_sm_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c0_sm_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c0_sm_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c0_sm_p4_0[] = {
+ 1, 4, 3, 6, 6, 7, 7, 9, 9, 0, 5, 5, 7, 7, 8, 7,
+ 9, 9, 0, 5, 5, 7, 7, 8, 8, 9, 9, 0, 7, 7, 8, 8,
+ 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, 0, 0,
+ 9, 9, 9, 9,11,11, 0, 0, 0, 9, 9, 9, 9,11,11, 0,
+ 0, 0,10,10,10,10,11,11, 0, 0, 0, 0, 0, 9, 9,11,
+ 11,
+};
+
+static const static_codebook _44c0_sm_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c0_sm_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c0_sm_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p5_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c0_sm_p5_0[] = {
+ 1, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 9, 9,10,10,11,
+ 11, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,11,
+ 11,11, 0, 5, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,
+ 11,11,11, 0, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10,
+ 11,11,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,
+ 10,11,11,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,
+ 10,10,11,11,12,12,12,13, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,
+ 10,10,11,11,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9,
+ 9,10,10,11,10,11,11,12,12,13,13, 0, 0, 0, 0, 0,
+ 10,10,10,10,11,11,12,12,12,13,13,13, 0, 0, 0, 0,
+ 0, 0, 0,10,10,11,11,12,12,12,13,13,13, 0, 0, 0,
+ 0, 0, 0, 0,11,11,12,12,12,12,13,13,14,14, 0, 0,
+ 0, 0, 0, 0, 0,11,11,12,11,12,12,13,13,13,13, 0,
+ 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,13,14,14,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,14,
+ 14,
+};
+
+static const static_codebook _44c0_sm_p5_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c0_sm_p5_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c0_sm_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c0_sm_p6_0[] = {
+ 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11,
+ 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 7,10,10,10,11,
+ 11,11,10,10, 6, 9, 9,11,11,10,11,10,10, 6, 9, 9,
+ 11,10,11,11,10,10, 7,11,10,11,11,11,11,11,11, 6,
+ 9, 9,11,10,10,11,11,10, 6, 9, 9,11,10,10,11,10,
+ 11,
+};
+
+static const static_codebook _44c0_sm_p6_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c0_sm_p6_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c0_sm_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p6_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c0_sm_p6_1[] = {
+ 2, 4, 4, 6, 6, 7, 7, 7, 7, 7, 8, 9, 5, 5, 6, 6,
+ 7, 7, 8, 8, 8, 8, 9, 5, 5, 6, 6, 7, 7, 8, 8, 8,
+ 8,10, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7,
+ 7, 7, 7, 8, 8, 8, 8,10,10,10, 8, 8, 8, 8, 8, 8,
+ 8, 8,10,10,10, 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,
+ 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8,
+ 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10,
+ 10,10,10, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44c0_sm_p6_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c0_sm_p6_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c0_sm_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c0_sm_p7_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 7, 5, 5,
+ 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 6, 5, 7, 7, 8,
+ 8, 8, 8, 9, 9,10,10, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,12,12, 9, 9,10,10,10,10,11,11,11,11, 0,13,
+ 13, 9, 9, 9, 9,10,10,11,11,11,12, 0, 0, 0, 9,10,
+ 10,10,11,11,12,11,12,12, 0, 0, 0,10,10, 9, 9,11,
+ 11,12,12,12,12, 0, 0, 0,13,13,10,10,11,11,12,12,
+ 13,13, 0, 0, 0,14,14,10,10,11,11,12,12,13,13, 0,
+ 0, 0, 0, 0,11,12,11,11,13,12,13,13, 0, 0, 0, 0,
+ 0,12,12,11,11,13,12,14,14,
+};
+
+static const static_codebook _44c0_sm_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c0_sm_p7_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c0_sm_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p7_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c0_sm_p7_1[] = {
+ 2, 4, 4, 4, 4, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6,
+ 6, 6, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44c0_sm_p7_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c0_sm_p7_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c0_sm_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p8_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c0_sm_p8_0[] = {
+ 1, 3, 3,11,11,11,11,11,11, 3, 7, 6,11,11,11,11,
+ 11,11, 4, 8, 7,11,11,11,11,11,11,11,11,11,11,11,
+ 11,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,
+};
+
+static const static_codebook _44c0_sm_p8_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c0_sm_p8_0,
+ 1, -516186112, 1627103232, 4, 0,
+ (long *)_vq_quantlist__44c0_sm_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p8_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c0_sm_p8_1[] = {
+ 1, 4, 4, 6, 6, 7, 7, 9, 9,10,11,12,12, 6, 5, 5,
+ 7, 7, 8, 8,10,10,12,11,12,12, 6, 5, 5, 7, 7, 8,
+ 8,10,10,12,11,12,12,17, 7, 7, 8, 8, 9, 9,10,10,
+ 12,12,13,13,18, 7, 7, 8, 7, 9, 9,10,10,12,12,12,
+ 13,19,10,10, 8, 8,10,10,11,11,12,12,13,14,19,11,
+ 10, 8, 7,10,10,11,11,12,12,13,12,19,19,19,10,10,
+ 10,10,11,11,12,12,13,13,19,19,19,11, 9,11, 9,14,
+ 12,13,12,13,13,19,20,18,13,14,11,11,12,12,13,13,
+ 14,13,20,20,20,15,13,11,10,13,11,13,13,14,13,20,
+ 20,20,20,20,13,14,12,12,13,13,13,13,20,20,20,20,
+ 20,13,13,12,12,16,13,15,13,
+};
+
+static const static_codebook _44c0_sm_p8_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c0_sm_p8_1,
+ 1, -522616832, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44c0_sm_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c0_sm_p8_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c0_sm_p8_2[] = {
+ 2, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8,10, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9,10, 6, 6, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9,10, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10, 7, 7, 8, 8, 9, 8, 9, 9, 9,
+ 9,10, 9, 9,10,10,10,11, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9,10, 9,10,10,10,10, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9, 9,10,10,11,10,10, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10,10,10,10,11,11, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10,11,11,11,11,11, 9, 9,
+ 9, 9, 9, 9, 9, 9,10, 9,10, 9,11,11,10,11,11, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,11,11,10,11,11,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,11,10,11,11,
+ 11,11,11, 9, 9,10, 9, 9, 9, 9, 9, 9, 9,10,11,10,
+ 11,11,11,11,10,10,10,10, 9, 9, 9, 9, 9, 9,10,11,
+ 11,11,11,11,11, 9,10, 9, 9, 9, 9, 9, 9, 9, 9,11,
+ 11,10,11,11,11,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10,11,10,11,11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9,
+ 9,
+};
+
+static const static_codebook _44c0_sm_p8_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c0_sm_p8_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c0_sm_p8_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c0_sm_short[] = {
+ 6, 6,12,13,13,14,16,17,17, 4, 2, 5, 8, 7, 9,12,
+ 15,15, 9, 4, 5, 9, 7, 9,12,16,18,11, 6, 7, 4, 6,
+ 8,11,14,18,10, 5, 6, 5, 5, 7,10,14,17,10, 5, 7,
+ 7, 6, 7,10,13,16,11, 5, 7, 7, 7, 8,10,12,15,13,
+ 6, 7, 5, 5, 7, 9,12,13,16, 8, 9, 6, 6, 7, 9,10,
+ 12,
+};
+
+static const static_codebook _huff_book__44c0_sm_short = {
+ 2, 81,
+ (char *)_huff_lengthlist__44c0_sm_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c1_s_long[] = {
+ 5, 5, 9,10, 9, 9,10,11,12, 5, 1, 5, 6, 6, 7,10,
+ 12,14, 9, 5, 6, 8, 8,10,12,14,14,10, 5, 8, 5, 6,
+ 8,11,13,14, 9, 5, 7, 6, 6, 8,10,12,11, 9, 7, 9,
+ 7, 6, 6, 7,10,10,10, 9,12, 9, 8, 7, 7,10,12,11,
+ 11,13,12,10, 9, 8, 9,11,11,14,15,15,13,11, 9, 9,
+ 11,
+};
+
+static const static_codebook _huff_book__44c1_s_long = {
+ 2, 81,
+ (char *)_huff_lengthlist__44c1_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c1_s_p1_0[] = {
+ 2, 4, 4, 0, 0, 0, 0, 0, 0, 5, 7, 6, 0, 0, 0, 0,
+ 0, 0, 5, 6, 7, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0,
+ 0, 0, 0, 7, 8, 8, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0,
+ 0, 0, 0, 0, 7, 8, 8, 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, 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, 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, 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, 4, 7, 7, 0, 0, 0, 0,
+ 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 7, 8, 8, 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, 7, 8, 8, 0, 0, 0,
+ 0, 0, 0, 8, 9,10, 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 6, 8, 8, 0, 0,
+ 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9,
+ 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, 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, 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, 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, 4, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0,
+ 0, 0, 0, 0, 7, 8, 9, 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, 6, 8, 8, 0, 0, 0, 0, 0, 0, 8,10, 9, 0,
+ 0, 0, 0, 0, 0, 8, 8, 9, 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, 7, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9,
+ 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c1_s_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__44c1_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c1_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c1_s_p2_0[] = {
+ 2, 3, 4, 6, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 4, 5, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 8, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 6, 6, 8, 8, 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, 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, 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, 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,
+};
+
+static const static_codebook _44c1_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c1_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c1_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c1_s_p3_0[] = {
+ 1, 3, 2, 7, 7, 0, 0, 0, 0, 0,13,13, 6, 6, 0, 0,
+ 0, 0, 0,12, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7,
+ 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0,
+ 8, 9, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0,
+ 0, 0,11,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c1_s_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c1_s_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c1_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c1_s_p4_0[] = {
+ 1, 3, 3, 6, 5, 6, 6, 8, 8, 0, 0, 0, 7, 7, 7, 7,
+ 9, 9, 0, 0, 0, 7, 7, 7, 7, 9, 9, 0, 0, 0, 7, 7,
+ 8, 8,10,10, 0, 0, 0, 7, 7, 8, 8,10,10, 0, 0, 0,
+ 9, 9, 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0,
+ 0, 0,10,10, 9, 9,11,11, 0, 0, 0, 0, 0, 9, 9,11,
+ 11,
+};
+
+static const static_codebook _44c1_s_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c1_s_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c1_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p5_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c1_s_p5_0[] = {
+ 1, 4, 3, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11,
+ 11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,10,
+ 11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,
+ 10,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,12,11, 0, 0, 0, 8, 8, 9, 9, 9,10,10,10,
+ 10,10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10, 9,10,
+ 10,10,10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,
+ 10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9,
+ 10,10,10,11,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9,
+ 9,10,10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0,
+ 10,10,10,10,11,11,12,12,12,12,13,13, 0, 0, 0, 0,
+ 0, 0, 0,10,10,11,11,12,12,12,12,13,13, 0, 0, 0,
+ 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,13, 0, 0,
+ 0, 0, 0, 0, 0,11,11,11,11,12,12,13,13,13,13, 0,
+ 0, 0, 0, 0, 0, 0,12,12,12,12,12,12,13,13,14,14,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,14,
+ 14,
+};
+
+static const static_codebook _44c1_s_p5_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c1_s_p5_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c1_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c1_s_p6_0[] = {
+ 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11,
+ 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 6,10,10,11,11,
+ 11,11,10,10, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9,
+ 11,10,11,11,10,10, 7,11,10,11,11,11,12,11,11, 7,
+ 9, 9,11,10,10,11,11,10, 6, 9, 9,10,10,10,12,10,
+ 11,
+};
+
+static const static_codebook _44c1_s_p6_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c1_s_p6_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c1_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p6_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c1_s_p6_1[] = {
+ 2, 3, 3, 6, 6, 7, 7, 7, 7, 8, 8,10,10,10, 6, 6,
+ 7, 7, 8, 8, 8, 8,10,10,10, 6, 6, 7, 7, 8, 8, 8,
+ 8,10,10,10, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7,
+ 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, 7, 8, 8, 8, 8,
+ 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10,
+ 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8,
+ 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10,
+ 10,10,10, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44c1_s_p6_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c1_s_p6_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c1_s_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c1_s_p7_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8,10, 9, 7, 5, 6,
+ 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 5, 5, 7, 7, 8,
+ 8, 8, 8, 9, 9,10,10, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,10, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,12,12, 9, 9, 9,10,10,10,11,11,11,11, 0,13,
+ 13, 9, 9, 9, 9,10,10,11,11,11,11, 0, 0, 0,10,10,
+ 10,10,11,11,12,11,12,12, 0, 0, 0,10,10,10, 9,11,
+ 11,12,11,13,12, 0, 0, 0,13,13,10,10,11,11,12,12,
+ 13,13, 0, 0, 0,14,14,10,10,11,11,12,12,13,13, 0,
+ 0, 0, 0, 0,11,12,11,11,12,12,14,13, 0, 0, 0, 0,
+ 0,12,11,11,11,13,10,14,13,
+};
+
+static const static_codebook _44c1_s_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c1_s_p7_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c1_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p7_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c1_s_p7_1[] = {
+ 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6,
+ 6, 6, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44c1_s_p7_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c1_s_p7_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c1_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p8_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c1_s_p8_0[] = {
+ 1, 4, 3,10,10,10,10,10,10,10,10,10,10, 4, 8, 6,
+ 10,10,10,10,10,10,10,10,10,10, 4, 8, 7,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _44c1_s_p8_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c1_s_p8_0,
+ 1, -514541568, 1627103232, 4, 0,
+ (long *)_vq_quantlist__44c1_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p8_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c1_s_p8_1[] = {
+ 1, 4, 4, 6, 5, 7, 7, 9, 9,10,10,12,12, 6, 5, 5,
+ 7, 7, 8, 8,10,10,12,11,12,12, 6, 5, 5, 7, 7, 8,
+ 8,10,10,11,11,12,12,15, 7, 7, 8, 8, 9, 9,11,11,
+ 12,12,13,12,15, 8, 8, 8, 7, 9, 9,10,10,12,12,13,
+ 13,16,11,10, 8, 8,10,10,11,11,12,12,13,13,16,11,
+ 11, 9, 8,11,10,11,11,12,12,13,12,16,16,16,10,11,
+ 10,11,12,12,12,12,13,13,16,16,16,11, 9,11, 9,14,
+ 12,12,12,13,13,16,16,16,12,14,11,12,12,12,13,13,
+ 14,13,16,16,16,15,13,12,10,13,10,13,14,13,13,16,
+ 16,16,16,16,13,14,12,13,13,12,13,13,16,16,16,16,
+ 16,13,12,12,11,14,12,15,13,
+};
+
+static const static_codebook _44c1_s_p8_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c1_s_p8_1,
+ 1, -522616832, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44c1_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c1_s_p8_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c1_s_p8_2[] = {
+ 2, 4, 4, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8,10,10,10, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9,10,10,10, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9,10,10,10, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9,10, 9, 9,10,10,10, 7, 7, 8, 8, 9, 8, 9, 9, 9,
+ 9,10, 9, 9,10,10,11,11, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9,10, 9, 9,10,10,10,10, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9, 9,10,10,11,11,11, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10,10,10,11,11,11, 8, 8, 9,
+ 9, 9, 9,10, 9, 9, 9, 9, 9,11,11,11,11,11, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,10,10,11,11, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,11,10,11,11,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, 9,10,10,11,11,
+ 11,11,11, 9, 9, 9,10, 9, 9, 9, 9, 9, 9,10,11,11,
+ 11,11,11,11,10,10,10,10, 9, 9, 9, 9, 9, 9,10,11,
+ 11,11,11,11,11, 9,10, 9, 9, 9, 9,10, 9, 9, 9,11,
+ 11,11,11,11,11,11,10,10, 9, 9, 9, 9, 9, 9,10, 9,
+ 11,11,10,11,11,11,11,10,11, 9, 9, 9, 9, 9, 9, 9,
+ 9,
+};
+
+static const static_codebook _44c1_s_p8_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c1_s_p8_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c1_s_p8_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c1_s_short[] = {
+ 6, 8,13,12,13,14,15,16,16, 4, 2, 4, 7, 6, 8,11,
+ 13,15,10, 4, 4, 8, 6, 8,11,14,17,11, 5, 6, 5, 6,
+ 8,12,14,17,11, 5, 5, 6, 5, 7,10,13,16,12, 6, 7,
+ 8, 7, 8,10,13,15,13, 8, 8, 7, 7, 8,10,12,15,15,
+ 7, 7, 5, 5, 7, 9,12,14,15, 8, 8, 6, 6, 7, 8,10,
+ 11,
+};
+
+static const static_codebook _huff_book__44c1_s_short = {
+ 2, 81,
+ (char *)_huff_lengthlist__44c1_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44c1_sm_long[] = {
+ 5, 4, 8,10, 9, 9,10,11,12, 4, 2, 5, 6, 6, 8,10,
+ 11,13, 8, 4, 6, 8, 7, 9,12,12,14,10, 6, 8, 4, 5,
+ 6, 9,11,12, 9, 5, 6, 5, 5, 6, 9,11,11, 9, 7, 9,
+ 6, 5, 5, 7,10,10,10, 9,11, 8, 7, 6, 7, 9,11,11,
+ 12,13,10,10, 9, 8, 9,11,11,15,15,12,13,11, 9,10,
+ 11,
+};
+
+static const static_codebook _huff_book__44c1_sm_long = {
+ 2, 81,
+ (char *)_huff_lengthlist__44c1_sm_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c1_sm_p1_0[] = {
+ 1, 5, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 5, 7, 7, 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, 5, 8, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0,
+ 0, 0, 0, 7, 8, 9, 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, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0,
+ 0, 0, 0, 0, 7, 9, 9, 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, 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, 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, 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, 5, 8, 7, 0, 0, 0, 0,
+ 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 7, 9, 9, 0, 0, 0,
+ 0, 0, 0, 9, 9,10, 0, 0, 0, 0, 0, 0, 9,10,10, 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, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 9,10,10,
+ 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, 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, 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, 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, 5, 7, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8, 9, 9, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, 0,
+ 0, 0, 0, 0, 0, 8, 9,10, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10,
+ 0, 0, 0, 0, 0, 0, 9,10, 9, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c1_sm_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__44c1_sm_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44c1_sm_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c1_sm_p2_0[] = {
+ 2, 3, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 9, 9,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 6, 7, 9, 9, 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, 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, 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, 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,
+};
+
+static const static_codebook _44c1_sm_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44c1_sm_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c1_sm_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c1_sm_p3_0[] = {
+ 1, 3, 3, 7, 7, 0, 0, 0, 0, 0, 5, 5, 6, 6, 0, 0,
+ 0, 0, 0, 5, 5, 7, 7, 0, 0, 0, 0, 0, 7, 7, 7, 7,
+ 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0,
+ 8, 9, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0,
+ 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44c1_sm_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c1_sm_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c1_sm_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44c1_sm_p4_0[] = {
+ 1, 3, 3, 6, 6, 7, 7, 9, 9, 0, 6, 6, 7, 7, 8, 8,
+ 9, 9, 0, 6, 6, 7, 7, 8, 8, 9, 9, 0, 7, 7, 8, 8,
+ 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, 0, 0,
+ 8, 8, 9, 9,11,11, 0, 0, 0, 9, 9, 9, 9,11,11, 0,
+ 0, 0,10,10,10,10,11,11, 0, 0, 0, 0, 0, 9, 9,11,
+ 11,
+};
+
+static const static_codebook _44c1_sm_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44c1_sm_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c1_sm_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p5_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c1_sm_p5_0[] = {
+ 2, 3, 3, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11,
+ 11, 0, 5, 5, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10,10,
+ 11,11, 0, 5, 5, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10,
+ 10,11,11, 0, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9,10,10,
+ 10,11,11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9,10,
+ 10,10,10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,
+ 10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,
+ 9, 9,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9,
+ 9, 9, 9,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0,
+ 9, 9,10,10,11,11,12,12,12,12,13,13, 0, 0, 0, 0,
+ 0, 0, 0,10,10,11,11,12,12,12,12,13,13, 0, 0, 0,
+ 0, 0, 0, 0,11,11,11,11,12,12,13,13,13,13, 0, 0,
+ 0, 0, 0, 0, 0,11,11,11,11,12,12,13,13,13,13, 0,
+ 0, 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,14,14,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,14,
+ 14,
+};
+
+static const static_codebook _44c1_sm_p5_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c1_sm_p5_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c1_sm_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44c1_sm_p6_0[] = {
+ 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11,
+ 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 7,10,10,10,11,
+ 11,11,10,10, 6, 9, 9,11,11,10,11,10,10, 6, 9, 9,
+ 11,10,11,11,10,10, 7,11,11,11,11,11,11,11,11, 6,
+ 9, 9,11,10,10,11,11,10, 6, 9, 9,10,10,10,11,10,
+ 11,
+};
+
+static const static_codebook _44c1_sm_p6_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44c1_sm_p6_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44c1_sm_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p6_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44c1_sm_p6_1[] = {
+ 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8,10, 5, 5, 6, 6,
+ 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6, 7, 7, 8, 8, 8,
+ 8,10, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7,
+ 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, 7, 8, 8, 8, 8,
+ 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10,
+ 8, 8, 8, 8, 8, 8, 9, 8,10,10,10,10,10, 8, 8, 8,
+ 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10,
+ 10,10,10, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44c1_sm_p6_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44c1_sm_p6_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44c1_sm_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c1_sm_p7_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 7, 5, 5,
+ 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 5, 6, 7, 7, 8,
+ 8, 8, 8, 9, 9,11,10, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,12,12, 9, 9,10,10,10,10,11,11,11,11, 0,13,
+ 13, 9, 9, 9, 9,10,10,11,11,12,12, 0, 0, 0, 9,10,
+ 9,10,11,11,12,11,13,12, 0, 0, 0,10,10, 9, 9,11,
+ 11,12,12,13,12, 0, 0, 0,13,13,10,10,11,11,12,12,
+ 13,13, 0, 0, 0,14,14,10,10,11,11,12,12,13,13, 0,
+ 0, 0, 0, 0,11,12,11,11,12,13,14,13, 0, 0, 0, 0,
+ 0,12,12,11,11,13,12,14,13,
+};
+
+static const static_codebook _44c1_sm_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c1_sm_p7_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44c1_sm_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p7_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44c1_sm_p7_1[] = {
+ 2, 4, 4, 4, 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6,
+ 5, 5, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44c1_sm_p7_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44c1_sm_p7_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44c1_sm_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p8_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c1_sm_p8_0[] = {
+ 1, 3, 3,13,13,13,13,13,13,13,13,13,13, 3, 6, 6,
+ 13,13,13,13,13,13,13,13,13,13, 4, 8, 7,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,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,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,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,13,13,13,
+ 13,13,13,13,13,13,13,13,13,
+};
+
+static const static_codebook _44c1_sm_p8_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c1_sm_p8_0,
+ 1, -514541568, 1627103232, 4, 0,
+ (long *)_vq_quantlist__44c1_sm_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p8_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44c1_sm_p8_1[] = {
+ 1, 4, 4, 6, 6, 7, 7, 9, 9,10,11,12,12, 6, 5, 5,
+ 7, 7, 8, 7,10,10,11,11,12,12, 6, 5, 5, 7, 7, 8,
+ 8,10,10,11,11,12,12,16, 7, 7, 8, 8, 9, 9,11,11,
+ 12,12,13,13,17, 7, 7, 8, 7, 9, 9,11,10,12,12,13,
+ 13,19,11,10, 8, 8,10,10,11,11,12,12,13,13,19,11,
+ 11, 9, 7,11,10,11,11,12,12,13,12,19,19,19,10,10,
+ 10,10,11,12,12,12,13,14,18,19,19,11, 9,11, 9,13,
+ 12,12,12,13,13,19,20,19,13,15,11,11,12,12,13,13,
+ 14,13,18,19,20,15,13,12,10,13,10,13,13,13,14,20,
+ 20,20,20,20,13,14,12,12,13,12,13,13,20,20,20,20,
+ 20,13,12,12,12,14,12,14,13,
+};
+
+static const static_codebook _44c1_sm_p8_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44c1_sm_p8_1,
+ 1, -522616832, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44c1_sm_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44c1_sm_p8_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44c1_sm_p8_2[] = {
+ 2, 5, 5, 6, 6, 7, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8,10, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9,10, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9,10, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10, 7, 7, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9,10,11,11, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9,10,10, 9,10,10,10,10, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9, 9,10,10,11,10,10, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9,10, 9,10,10,10,11,11, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,11,11,11,11,11, 9, 9,
+ 9, 9, 9, 9, 9, 9,10, 9,10, 9,11,11,11,11,11, 9,
+ 8, 9, 9, 9, 9, 9, 9, 9,10,10, 9,11,11,10,11,11,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, 9,11,11,11,11,
+ 11,11,11, 9, 9,10, 9, 9, 9, 9,10, 9,10,10,11,10,
+ 11,11,11,11, 9,10,10,10, 9, 9, 9, 9, 9, 9,10,11,
+ 11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,11,
+ 11,10,11,11,11,11,10,10, 9, 9, 9, 9, 9, 9,10, 9,
+ 10,11,10,11,11,11,11,11,11, 9, 9,10, 9, 9, 9, 9,
+ 9,
+};
+
+static const static_codebook _44c1_sm_p8_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44c1_sm_p8_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44c1_sm_p8_2,
+ 0
+};
+
+static const char _huff_lengthlist__44c1_sm_short[] = {
+ 4, 7,13,14,14,15,16,18,18, 4, 2, 5, 8, 7, 9,12,
+ 15,15,10, 4, 5,10, 6, 8,11,15,17,12, 5, 7, 5, 6,
+ 8,11,14,17,11, 5, 6, 6, 5, 6, 9,13,17,12, 6, 7,
+ 6, 5, 6, 8,12,14,14, 7, 8, 6, 6, 7, 9,11,14,14,
+ 8, 9, 6, 5, 6, 9,11,13,16,10,10, 7, 6, 7, 8,10,
+ 11,
+};
+
+static const static_codebook _huff_book__44c1_sm_short = {
+ 2, 81,
+ (char *)_huff_lengthlist__44c1_sm_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44cn1_s_long[] = {
+ 4, 4, 7, 8, 7, 8,10,12,17, 3, 1, 6, 6, 7, 8,10,
+ 12,15, 7, 6, 9, 9, 9,11,12,14,17, 8, 6, 9, 6, 7,
+ 9,11,13,17, 7, 6, 9, 7, 7, 8, 9,12,15, 8, 8,10,
+ 8, 7, 7, 7,10,14, 9,10,12,10, 8, 8, 8,10,14,11,
+ 13,15,13,12,11,11,12,16,17,18,18,19,20,18,16,16,
+ 20,
+};
+
+static const static_codebook _huff_book__44cn1_s_long = {
+ 2, 81,
+ (char *)_huff_lengthlist__44cn1_s_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44cn1_s_p1_0[] = {
+ 1, 4, 4, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 5, 7, 7, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, 0,
+ 0, 0, 0, 7, 9,10, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 7,10, 9, 0, 0,
+ 0, 0, 0, 0, 8,10, 9, 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, 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, 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, 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, 5, 8, 8, 0, 0, 0, 0,
+ 0, 0, 8,10,10, 0, 0, 0, 0, 0, 0, 8, 9,10, 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, 7,10,10, 0, 0, 0,
+ 0, 0, 0, 9, 9,11, 0, 0, 0, 0, 0, 0,10,11,11, 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, 7,10,10, 0, 0,
+ 0, 0, 0, 0, 9,11, 9, 0, 0, 0, 0, 0, 0,10,11,11,
+ 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, 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, 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, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8,10,10, 0, 0,
+ 0, 0, 0, 0, 8,10,10, 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, 7,10,10, 0, 0, 0, 0, 0, 0,10,11,11, 0,
+ 0, 0, 0, 0, 0, 9, 9,11, 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, 7,10,10, 0, 0, 0, 0, 0, 0,10,11,11,
+ 0, 0, 0, 0, 0, 0, 9,11, 9, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _44cn1_s_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__44cn1_s_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44cn1_s_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44cn1_s_p2_0[] = {
+ 1, 4, 4, 7, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 7, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 5, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 7, 9, 9,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 7, 7, 9, 9, 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, 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, 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, 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,
+};
+
+static const static_codebook _44cn1_s_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44cn1_s_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44cn1_s_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44cn1_s_p3_0[] = {
+ 1, 2, 3, 7, 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0,
+ 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7,
+ 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0,
+ 9, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0,
+ 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44cn1_s_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44cn1_s_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44cn1_s_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44cn1_s_p4_0[] = {
+ 1, 3, 3, 6, 6, 6, 6, 8, 8, 0, 0, 0, 6, 6, 7, 7,
+ 9, 9, 0, 0, 0, 6, 6, 7, 7, 9, 9, 0, 0, 0, 7, 7,
+ 8, 8,10,10, 0, 0, 0, 7, 7, 8, 8,10,10, 0, 0, 0,
+ 9, 9, 9, 9,10,10, 0, 0, 0, 9, 9, 9, 9,10,10, 0,
+ 0, 0,10,10,10,10,11,11, 0, 0, 0, 0, 0,10,10,11,
+ 11,
+};
+
+static const static_codebook _44cn1_s_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44cn1_s_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44cn1_s_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p5_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44cn1_s_p5_0[] = {
+ 1, 4, 3, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,10,
+ 10, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,10,
+ 11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,
+ 10,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,11,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,11,11, 0, 0, 0, 8, 8, 9, 9, 9, 9,10,10,
+ 10,10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9, 9, 9,10,
+ 10,10,11,11,11,12,12, 0, 0, 0, 9, 9,10, 9,10,10,
+ 10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9,
+ 10,10,10,11,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9,
+ 9,10,10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0,
+ 10,10,11,10,11,11,11,12,13,12,13,13, 0, 0, 0, 0,
+ 0, 0, 0,11,10,11,11,12,12,12,12,13,13, 0, 0, 0,
+ 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,14, 0, 0,
+ 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,14, 0,
+ 0, 0, 0, 0, 0, 0,12,12,12,13,13,13,13,13,14,14,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,12,13,13,14,
+ 14,
+};
+
+static const static_codebook _44cn1_s_p5_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44cn1_s_p5_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44cn1_s_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44cn1_s_p6_0[] = {
+ 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 6, 6,10, 9, 9,11,
+ 9, 9, 4, 6, 6,10, 9, 9,10, 9, 9, 7,10,10,11,11,
+ 11,12,11,11, 7, 9, 9,11,11,10,11,10,10, 7, 9, 9,
+ 11,10,11,11,10,10, 7,10,10,11,11,11,12,11,11, 7,
+ 9, 9,11,10,10,11,10,10, 7, 9, 9,11,10,10,11,10,
+ 10,
+};
+
+static const static_codebook _44cn1_s_p6_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44cn1_s_p6_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44cn1_s_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p6_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44cn1_s_p6_1[] = {
+ 1, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8,10,10,10, 7, 6,
+ 8, 8, 8, 8, 8, 8,10,10,10, 7, 6, 7, 7, 8, 8, 8,
+ 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7,
+ 7, 8, 8, 8, 8, 8, 8,10,10,10, 8, 8, 8, 8, 9, 9,
+ 9, 9,10,10,10, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10,
+ 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10, 9, 9, 9,
+ 9, 9, 9,10,10,10,10,10, 9, 9, 9, 9, 9, 9,10,10,
+ 10,10,10, 9, 9, 9, 9, 9, 9,
+};
+
+static const static_codebook _44cn1_s_p6_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44cn1_s_p6_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44cn1_s_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44cn1_s_p7_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 6, 5, 5,
+ 7, 7, 8, 8, 8, 8, 9, 9,11,11, 7, 5, 5, 7, 7, 8,
+ 8, 8, 8, 9,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,12,12, 9, 9, 9,10,10,10,11,11,11,12, 0,13,
+ 13, 9, 9, 9, 9,10,10,11,11,11,12, 0, 0, 0,10,10,
+ 10,10,11,11,12,12,12,13, 0, 0, 0,10,10,10,10,11,
+ 11,12,12,13,12, 0, 0, 0,14,14,11,10,11,12,12,13,
+ 13,14, 0, 0, 0,15,15,11,11,12,11,12,12,14,13, 0,
+ 0, 0, 0, 0,12,12,12,12,13,13,14,14, 0, 0, 0, 0,
+ 0,13,13,12,12,13,13,13,14,
+};
+
+static const static_codebook _44cn1_s_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44cn1_s_p7_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44cn1_s_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p7_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44cn1_s_p7_1[] = {
+ 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6,
+ 6, 6, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44cn1_s_p7_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44cn1_s_p7_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44cn1_s_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p8_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44cn1_s_p8_0[] = {
+ 1, 7, 7,11,11, 8,11,11,11,11, 4,11, 3,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11, 7,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11, 8,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,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,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,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,
+};
+
+static const static_codebook _44cn1_s_p8_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44cn1_s_p8_0,
+ 1, -518283264, 1627103232, 3, 0,
+ (long *)_vq_quantlist__44cn1_s_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p8_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44cn1_s_p8_1[] = {
+ 1, 4, 4, 6, 6, 8, 8, 9,10,10,11,11,11, 6, 5, 5,
+ 7, 7, 8, 8, 9,10, 9,11,11,12, 5, 5, 5, 7, 7, 8,
+ 9,10,10,12,12,14,13,15, 7, 7, 8, 8, 9,10,11,11,
+ 10,12,10,11,15, 7, 8, 8, 8, 9, 9,11,11,13,12,12,
+ 13,15,10,10, 8, 8,10,10,12,12,11,14,10,10,15,11,
+ 11, 8, 8,10,10,12,13,13,14,15,13,15,15,15,10,10,
+ 10,10,12,12,13,12,13,10,15,15,15,10,10,11,10,13,
+ 11,13,13,15,13,15,15,15,13,13,10,11,11,11,12,10,
+ 14,11,15,15,14,14,13,10,10,12,11,13,13,14,14,15,
+ 15,15,15,15,11,11,11,11,12,11,15,12,15,15,15,15,
+ 15,12,12,11,11,14,12,13,14,
+};
+
+static const static_codebook _44cn1_s_p8_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44cn1_s_p8_1,
+ 1, -522616832, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44cn1_s_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_s_p8_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44cn1_s_p8_2[] = {
+ 3, 4, 3, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9,10,11,11, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9,10,10,10, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9,10,10,10, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9,10, 9,10,11,10, 7, 6, 7, 7, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10,11, 7, 7, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10,10, 7, 7, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9,10,11,11,11, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9,11,10,10,11,11, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10,11,11, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,11,10,11,11, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,11,10,11,11,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,10,10,11,
+ 11,11,11, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,11,11,
+ 10,11,11,11, 9,10,10, 9, 9, 9, 9, 9, 9, 9,10,11,
+ 11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,
+ 11,11,11,11,11,11,10,10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 11,11,11,10,11,11,11,11,11, 9, 9, 9,10, 9, 9, 9,
+ 9,
+};
+
+static const static_codebook _44cn1_s_p8_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44cn1_s_p8_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44cn1_s_p8_2,
+ 0
+};
+
+static const char _huff_lengthlist__44cn1_s_short[] = {
+ 10, 9,12,15,12,13,16,14,16, 7, 1, 5,14, 7,10,13,
+ 16,16, 9, 4, 6,16, 8,11,16,16,16,14, 4, 7,16, 9,
+ 12,14,16,16,10, 5, 7,14, 9,12,14,15,15,13, 8, 9,
+ 14,10,12,13,14,15,13, 9, 9, 7, 6, 8,11,12,12,14,
+ 8, 8, 5, 4, 5, 8,11,12,16,10,10, 6, 5, 6, 8, 9,
+ 10,
+};
+
+static const static_codebook _huff_book__44cn1_s_short = {
+ 2, 81,
+ (char *)_huff_lengthlist__44cn1_s_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44cn1_sm_long[] = {
+ 3, 3, 8, 8, 8, 8,10,12,14, 3, 2, 6, 7, 7, 8,10,
+ 12,16, 7, 6, 7, 9, 8,10,12,14,16, 8, 6, 8, 4, 5,
+ 7, 9,11,13, 7, 6, 8, 5, 6, 7, 9,11,14, 8, 8,10,
+ 7, 7, 6, 8,10,13, 9,11,12, 9, 9, 7, 8,10,12,10,
+ 13,15,11,11,10, 9,10,13,13,16,17,14,15,14,13,14,
+ 17,
+};
+
+static const static_codebook _huff_book__44cn1_sm_long = {
+ 2, 81,
+ (char *)_huff_lengthlist__44cn1_sm_long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p1_0[] = {
+ 1, 4, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0,
+ 0, 0, 5, 7, 7, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, 0,
+ 0, 0, 0, 7, 8, 9, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0,
+ 0, 0, 0, 0, 8, 9, 9, 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, 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, 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, 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, 5, 8, 8, 0, 0, 0, 0,
+ 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 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, 7,10, 9, 0, 0, 0,
+ 0, 0, 0, 9, 9,10, 0, 0, 0, 0, 0, 0, 9,10,10, 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, 7, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 9,10,10,
+ 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, 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, 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, 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, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0,
+ 0, 0, 0, 0, 8, 9,10, 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, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, 0,
+ 0, 0, 0, 0, 0, 8, 9,10, 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, 7, 9,10, 0, 0, 0, 0, 0, 0, 9,10,10,
+ 0, 0, 0, 0, 0, 0, 9,10, 9, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 0, 0,
+ 0,
+};
+
+static const static_codebook _44cn1_sm_p1_0 = {
+ 8, 6561,
+ (char *)_vq_lengthlist__44cn1_sm_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44cn1_sm_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p2_0[] = {
+ 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 7, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 5, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 7, 9, 9,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 7, 7, 9, 9, 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, 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, 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, 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,
+};
+
+static const static_codebook _44cn1_sm_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44cn1_sm_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44cn1_sm_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p3_0[] = {
+ 1, 3, 4, 7, 7, 0, 0, 0, 0, 0, 4, 4, 7, 7, 0, 0,
+ 0, 0, 0, 4, 5, 7, 7, 0, 0, 0, 0, 0, 6, 7, 8, 8,
+ 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0,
+ 9, 9, 0, 0, 0, 0, 0, 0, 0,10, 9, 0, 0, 0, 0, 0,
+ 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static const static_codebook _44cn1_sm_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44cn1_sm_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44cn1_sm_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p4_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p4_0[] = {
+ 1, 4, 3, 6, 6, 7, 7, 9, 9, 0, 5, 5, 7, 7, 8, 7,
+ 9, 9, 0, 5, 5, 7, 7, 8, 8, 9, 9, 0, 7, 7, 8, 8,
+ 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, 0, 0,
+ 9, 9, 9, 9,10,10, 0, 0, 0, 9, 9, 9, 9,10,10, 0,
+ 0, 0,10,10,10,10,11,11, 0, 0, 0, 0, 0,10,10,11,
+ 11,
+};
+
+static const static_codebook _44cn1_sm_p4_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44cn1_sm_p4_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44cn1_sm_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p5_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p5_0[] = {
+ 1, 4, 4, 6, 6, 8, 8, 9, 9, 8, 8, 9, 9,10,10,11,
+ 11, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,11,
+ 12,12, 0, 6, 5, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11,12,12, 0, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10,10,11,
+ 11,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10,
+ 11,11,12,12,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,
+ 10,11,11,12,12,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,
+ 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,10,
+ 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,
+ 10,10,11,11,12,12,13,13,13,13, 0, 0, 0, 0, 0, 9,
+ 9,10,10,11,11,12,12,12,13,13,13, 0, 0, 0, 0, 0,
+ 10,10,11,11,11,11,12,12,13,13,14,14, 0, 0, 0, 0,
+ 0, 0, 0,11,11,11,11,12,12,13,13,14,14, 0, 0, 0,
+ 0, 0, 0, 0,11,11,12,12,13,13,13,13,14,14, 0, 0,
+ 0, 0, 0, 0, 0,11,11,12,12,13,13,13,13,14,14, 0,
+ 0, 0, 0, 0, 0, 0,12,12,12,13,13,13,14,14,14,14,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,13,14,14,14,
+ 14,
+};
+
+static const static_codebook _44cn1_sm_p5_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44cn1_sm_p5_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44cn1_sm_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p6_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p6_0[] = {
+ 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 6,10, 9, 9,11,
+ 9, 9, 4, 6, 7,10, 9, 9,11, 9, 9, 7,10,10,10,11,
+ 11,11,11,10, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9,
+ 11,10,11,11,10,10, 7,11,11,11,11,11,12,11,11, 7,
+ 9, 9,11,10,10,12,10,10, 7, 9, 9,11,10,10,11,10,
+ 10,
+};
+
+static const static_codebook _44cn1_sm_p6_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44cn1_sm_p6_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44cn1_sm_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p6_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p6_1[] = {
+ 2, 4, 4, 5, 5, 7, 7, 7, 7, 8, 8,10, 5, 5, 6, 6,
+ 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6, 7, 7, 8, 8, 8,
+ 8,10, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7,
+ 7, 7, 7, 8, 8, 8, 8,10,10,10, 8, 8, 8, 8, 8, 8,
+ 8, 8,10,10,10, 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,
+ 8, 8, 8, 8, 8, 8, 9, 9,10,10,10,10,10, 8, 8, 8,
+ 8, 9, 9,10,10,10,10,10, 9, 9, 9, 9, 8, 9,10,10,
+ 10,10,10, 8, 9, 8, 8, 9, 8,
+};
+
+static const static_codebook _44cn1_sm_p6_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44cn1_sm_p6_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44cn1_sm_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p7_0[] = {
+ 1, 4, 4, 6, 6, 7, 7, 7, 7, 9, 9,10,10, 7, 5, 5,
+ 7, 7, 8, 8, 8, 8,10, 9,11,10, 7, 5, 5, 7, 7, 8,
+ 8, 8, 8, 9,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,
+ 11, 0,12,12, 9, 9, 9,10,10,10,11,11,12,12, 0,13,
+ 13, 9, 9, 9, 9,10,10,11,11,12,12, 0, 0, 0,10,10,
+ 10,10,11,11,12,12,12,13, 0, 0, 0,10,10,10,10,11,
+ 11,12,12,12,12, 0, 0, 0,14,14,11,11,11,11,12,13,
+ 13,13, 0, 0, 0,14,14,11,10,11,11,12,12,13,13, 0,
+ 0, 0, 0, 0,12,12,12,12,13,13,13,14, 0, 0, 0, 0,
+ 0,13,12,12,12,13,13,13,14,
+};
+
+static const static_codebook _44cn1_sm_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44cn1_sm_p7_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44cn1_sm_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p7_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p7_1[] = {
+ 2, 4, 4, 4, 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6,
+ 5, 5, 5, 5, 6, 6, 6, 5, 5,
+};
+
+static const static_codebook _44cn1_sm_p7_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44cn1_sm_p7_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44cn1_sm_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p8_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p8_0[] = {
+ 1, 4, 4,12,11,13,13,14,14, 4, 7, 7,11,13,14,14,
+ 14,14, 3, 8, 3,14,14,14,14,14,14,14,10,12,14,14,
+ 14,14,14,14,14,14, 5,14, 8,14,14,14,14,14,12,14,
+ 13,14,14,14,14,14,14,14,13,14,10,14,14,14,14,14,
+ 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
+ 14,
+};
+
+static const static_codebook _44cn1_sm_p8_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44cn1_sm_p8_0,
+ 1, -516186112, 1627103232, 4, 0,
+ (long *)_vq_quantlist__44cn1_sm_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p8_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p8_1[] = {
+ 1, 4, 4, 6, 6, 8, 8, 9, 9,10,11,11,11, 6, 5, 5,
+ 7, 7, 8, 8,10,10,10,11,11,11, 6, 5, 5, 7, 7, 8,
+ 8,10,10,11,12,12,12,14, 7, 7, 7, 8, 9, 9,11,11,
+ 11,12,11,12,17, 7, 7, 8, 7, 9, 9,11,11,12,12,12,
+ 12,14,11,11, 8, 8,10,10,11,12,12,13,11,12,14,11,
+ 11, 8, 8,10,10,11,12,12,13,13,12,14,15,14,10,10,
+ 10,10,11,12,12,12,12,11,14,13,16,10,10,10, 9,12,
+ 11,12,12,13,14,14,15,14,14,13,10,10,11,11,12,11,
+ 13,11,14,12,15,13,14,11,10,12,10,12,12,13,13,13,
+ 13,14,15,15,12,12,11,11,12,11,13,12,14,14,14,14,
+ 17,12,12,11,10,13,11,13,13,
+};
+
+static const static_codebook _44cn1_sm_p8_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44cn1_sm_p8_1,
+ 1, -522616832, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44cn1_sm_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44cn1_sm_p8_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44cn1_sm_p8_2[] = {
+ 3, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9,10, 6, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9,10, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9,10, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10, 7, 7, 7, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9,11,10,11, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,11,11, 8, 8, 8,
+ 8, 9, 9, 9, 9, 9, 9, 9, 9,11,10,11,11,11, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,11,10,11,11, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,11,11,10,11,11,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,10,11,11,
+ 11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,11,11,
+ 11,11,11,11, 9,10,10,10, 9, 9, 9, 9, 9, 9,11,10,
+ 11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,
+ 11,11,11,11,11,11,10,10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10,11,11,11,11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9,
+ 9,
+};
+
+static const static_codebook _44cn1_sm_p8_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44cn1_sm_p8_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44cn1_sm_p8_2,
+ 0
+};
+
+static const char _huff_lengthlist__44cn1_sm_short[] = {
+ 5, 6,12,14,12,14,16,17,18, 4, 2, 5,11, 7,10,12,
+ 14,15, 9, 4, 5,11, 7,10,13,15,18,15, 6, 7, 5, 6,
+ 8,11,13,16,11, 5, 6, 5, 5, 6, 9,13,15,12, 5, 7,
+ 6, 5, 6, 9,12,14,12, 6, 7, 8, 6, 7, 9,12,13,14,
+ 8, 8, 7, 5, 5, 8,10,12,16, 9, 9, 8, 6, 6, 7, 9,
+ 9,
+};
+
+static const static_codebook _huff_book__44cn1_sm_short = {
+ 2, 81,
+ (char *)_huff_lengthlist__44cn1_sm_short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
diff --git a/external/libvorbis-1.3.5/lib/books/floor/floor_books.h b/external/libvorbis-1.3.5/lib/books/floor/floor_books.h
new file mode 100644
index 0000000..e925313
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/books/floor/floor_books.h
@@ -0,0 +1,1547 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: static codebooks autogenerated by huff/huffbuld
+ last modified: $Id: floor_books.h 19057 2014-01-22 12:32:31Z xiphmont $
+
+ ********************************************************************/
+
+#include "codebook.h"
+
+static const char _huff_lengthlist_line_256x7_0sub1[] = {
+ 0, 2, 3, 3, 3, 3, 4, 3, 4,
+};
+
+static const static_codebook _huff_book_line_256x7_0sub1 = {
+ 1, 9,
+ (char *)_huff_lengthlist_line_256x7_0sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x7_0sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 4, 3, 5, 3,
+ 6, 3, 6, 4, 6, 4, 7, 5, 7,
+};
+
+static const static_codebook _huff_book_line_256x7_0sub2 = {
+ 1, 25,
+ (char *)_huff_lengthlist_line_256x7_0sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x7_0sub3[] = {
+ 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, 3, 5, 2, 5, 3, 5, 3,
+ 6, 3, 6, 4, 7, 6, 7, 8, 7, 9, 8, 9, 9, 9,10, 9,
+ 11,13,11,13,10,10,13,13,13,13,13,13,12,12,12,12,
+};
+
+static const static_codebook _huff_book_line_256x7_0sub3 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_256x7_0sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x7_1sub1[] = {
+ 0, 3, 3, 3, 3, 2, 4, 3, 4,
+};
+
+static const static_codebook _huff_book_line_256x7_1sub1 = {
+ 1, 9,
+ (char *)_huff_lengthlist_line_256x7_1sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x7_1sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 4, 3, 4, 4,
+ 5, 4, 6, 5, 6, 7, 6, 8, 8,
+};
+
+static const static_codebook _huff_book_line_256x7_1sub2 = {
+ 1, 25,
+ (char *)_huff_lengthlist_line_256x7_1sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x7_1sub3[] = {
+ 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, 3, 2, 4, 3, 6, 3, 7,
+ 3, 8, 5, 8, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7,
+};
+
+static const static_codebook _huff_book_line_256x7_1sub3 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_256x7_1sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x7_class0[] = {
+ 7, 5, 5, 9, 9, 6, 6, 9,12, 8, 7, 8,11, 8, 9,15,
+ 6, 3, 3, 7, 7, 4, 3, 6, 9, 6, 5, 6, 8, 6, 8,15,
+ 8, 5, 5, 9, 8, 5, 4, 6,10, 7, 5, 5,11, 8, 7,15,
+ 14,15,13,13,13,13, 8,11,15,10, 7, 6,11, 9,10,15,
+};
+
+static const static_codebook _huff_book_line_256x7_class0 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_256x7_class0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x7_class1[] = {
+ 5, 6, 8,15, 6, 9,10,15,10,11,12,15,15,15,15,15,
+ 4, 6, 7,15, 6, 7, 8,15, 9, 8, 9,15,15,15,15,15,
+ 6, 8, 9,15, 7, 7, 8,15,10, 9,10,15,15,15,15,15,
+ 15,13,15,15,15,10,11,15,15,13,13,15,15,15,15,15,
+ 4, 6, 7,15, 6, 8, 9,15,10,10,12,15,15,15,15,15,
+ 2, 5, 6,15, 5, 6, 7,15, 8, 6, 7,15,15,15,15,15,
+ 5, 6, 8,15, 5, 6, 7,15, 9, 6, 7,15,15,15,15,15,
+ 14,12,13,15,12,10,11,15,15,15,15,15,15,15,15,15,
+ 7, 8, 9,15, 9,10,10,15,15,14,14,15,15,15,15,15,
+ 5, 6, 7,15, 7, 8, 9,15,12, 9,10,15,15,15,15,15,
+ 7, 7, 9,15, 7, 7, 8,15,12, 8, 9,15,15,15,15,15,
+ 13,13,14,15,12,11,12,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,
+ 13,13,13,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,12,13,15,15,12,13,15,15,14,15,15,15,15,15,15,
+ 15,15,15,15,15,15,13,15,15,15,15,15,15,15,15,15,
+};
+
+static const static_codebook _huff_book_line_256x7_class1 = {
+ 1, 256,
+ (char *)_huff_lengthlist_line_256x7_class1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_0sub0[] = {
+ 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 6, 5, 6, 6, 6, 6, 5, 6, 6, 7, 6, 7, 6, 7, 6,
+ 7, 6, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 9, 7, 9, 7,
+ 9, 7, 9, 8, 9, 8,10, 8,10, 8,10, 7,10, 6,10, 8,
+ 10, 8,11, 7,10, 7,11, 8,11,11,12,12,11,11,12,11,
+ 13,11,13,11,13,12,15,12,13,13,14,14,14,14,14,15,
+ 15,15,16,14,17,19,19,18,18,18,18,18,18,18,18,18,
+ 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,
+};
+
+static const static_codebook _huff_book_line_512x17_0sub0 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_512x17_0sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_1sub0[] = {
+ 2, 4, 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 5, 6, 5,
+ 6, 5, 6, 6, 7, 6, 7, 6, 8, 7, 8, 7, 8, 7, 8, 7,
+};
+
+static const static_codebook _huff_book_line_512x17_1sub0 = {
+ 1, 32,
+ (char *)_huff_lengthlist_line_512x17_1sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_1sub1[] = {
+ 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,
+ 4, 3, 5, 3, 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 6, 5,
+ 6, 5, 7, 5, 8, 6, 8, 6, 8, 6, 8, 6, 8, 7, 9, 7,
+ 9, 7,11, 9,11,11,12,11,14,12,14,16,14,16,13,16,
+ 14,16,12,15,13,16,14,16,13,14,12,15,13,15,13,13,
+ 13,15,12,14,14,15,13,15,12,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+};
+
+static const static_codebook _huff_book_line_512x17_1sub1 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_512x17_1sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_2sub1[] = {
+ 0, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 5, 4, 5, 3,
+ 5, 3,
+};
+
+static const static_codebook _huff_book_line_512x17_2sub1 = {
+ 1, 18,
+ (char *)_huff_lengthlist_line_512x17_2sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_2sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 3, 4, 3, 4, 4, 5, 4, 5, 4, 6, 4, 6, 5,
+ 6, 5, 7, 5, 7, 6, 8, 6, 8, 6, 8, 7, 8, 7, 9, 7,
+ 9, 8,
+};
+
+static const static_codebook _huff_book_line_512x17_2sub2 = {
+ 1, 50,
+ (char *)_huff_lengthlist_line_512x17_2sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_2sub3[] = {
+ 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, 3, 3, 3, 3, 4, 3, 4, 4, 5, 5, 6, 6, 7, 7,
+ 7, 8, 8,11, 8, 9, 9, 9,10,11,11,11, 9,10,10,11,
+ 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _huff_book_line_512x17_2sub3 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_512x17_2sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_3sub1[] = {
+ 0, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 5, 4, 5,
+ 5, 5,
+};
+
+static const static_codebook _huff_book_line_512x17_3sub1 = {
+ 1, 18,
+ (char *)_huff_lengthlist_line_512x17_3sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_3sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 3, 3, 4, 3, 5, 4, 6, 4, 6, 5, 7, 6, 7,
+ 6, 8, 6, 8, 7, 9, 8,10, 8,12, 9,13,10,15,10,15,
+ 11,14,
+};
+
+static const static_codebook _huff_book_line_512x17_3sub2 = {
+ 1, 50,
+ (char *)_huff_lengthlist_line_512x17_3sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_3sub3[] = {
+ 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, 4, 8, 4, 8, 4, 8, 4, 8, 5, 8, 5, 8, 6, 8,
+ 4, 8, 4, 8, 5, 8, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+};
+
+static const static_codebook _huff_book_line_512x17_3sub3 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_512x17_3sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_class1[] = {
+ 1, 2, 3, 6, 5, 4, 7, 7,
+};
+
+static const static_codebook _huff_book_line_512x17_class1 = {
+ 1, 8,
+ (char *)_huff_lengthlist_line_512x17_class1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_class2[] = {
+ 3, 3, 3,14, 5, 4, 4,11, 8, 6, 6,10,17,12,11,17,
+ 6, 5, 5,15, 5, 3, 4,11, 8, 5, 5, 8,16, 9,10,14,
+ 10, 8, 9,17, 8, 6, 6,13,10, 7, 7,10,16,11,13,14,
+ 17,17,17,17,17,16,16,16,16,15,16,16,16,16,16,16,
+};
+
+static const static_codebook _huff_book_line_512x17_class2 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_512x17_class2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_512x17_class3[] = {
+ 2, 4, 6,17, 4, 5, 7,17, 8, 7,10,17,17,17,17,17,
+ 3, 4, 6,15, 3, 3, 6,15, 7, 6, 9,17,17,17,17,17,
+ 6, 8,10,17, 6, 6, 8,16, 9, 8,10,17,17,15,16,17,
+ 17,17,17,17,12,15,15,16,12,15,15,16,16,16,16,16,
+};
+
+static const static_codebook _huff_book_line_512x17_class3 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_512x17_class3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x4_class0[] = {
+ 7, 7, 7,11, 6, 6, 7,11, 7, 6, 6,10,12,10,10,13,
+ 7, 7, 8,11, 7, 7, 7,11, 7, 6, 7,10,11,10,10,13,
+ 10,10, 9,12, 9, 9, 9,11, 8, 8, 8,11,13,11,10,14,
+ 15,15,14,15,15,14,13,14,15,12,12,17,17,17,17,17,
+ 7, 7, 6, 9, 6, 6, 6, 9, 7, 6, 6, 8,11,11,10,12,
+ 7, 7, 7, 9, 7, 6, 6, 9, 7, 6, 6, 9,13,10,10,11,
+ 10, 9, 8,10, 9, 8, 8,10, 8, 8, 7, 9,13,12,10,11,
+ 17,14,14,13,15,14,12,13,17,13,12,15,17,17,14,17,
+ 7, 6, 6, 7, 6, 6, 5, 7, 6, 6, 6, 6,11, 9, 9, 9,
+ 7, 7, 6, 7, 7, 6, 6, 7, 6, 6, 6, 6,10, 9, 8, 9,
+ 10, 9, 8, 8, 9, 8, 7, 8, 8, 7, 6, 8,11,10, 9,10,
+ 17,17,12,15,15,15,12,14,14,14,10,12,15,13,12,13,
+ 11,10, 8,10,11,10, 8, 8,10, 9, 7, 7,10, 9, 9,11,
+ 11,11, 9,10,11,10, 8, 9,10, 8, 6, 8,10, 9, 9,11,
+ 14,13,10,12,12,11,10,10, 8, 7, 8,10,10,11,11,12,
+ 17,17,15,17,17,17,17,17,17,13,12,17,17,17,14,17,
+};
+
+static const static_codebook _huff_book_line_128x4_class0 = {
+ 1, 256,
+ (char *)_huff_lengthlist_line_128x4_class0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x4_0sub0[] = {
+ 2, 2, 2, 2,
+};
+
+static const static_codebook _huff_book_line_128x4_0sub0 = {
+ 1, 4,
+ (char *)_huff_lengthlist_line_128x4_0sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x4_0sub1[] = {
+ 0, 0, 0, 0, 3, 2, 3, 2, 3, 3,
+};
+
+static const static_codebook _huff_book_line_128x4_0sub1 = {
+ 1, 10,
+ (char *)_huff_lengthlist_line_128x4_0sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x4_0sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 4, 3, 4, 3,
+ 4, 4, 5, 4, 5, 4, 6, 5, 6,
+};
+
+static const static_codebook _huff_book_line_128x4_0sub2 = {
+ 1, 25,
+ (char *)_huff_lengthlist_line_128x4_0sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x4_0sub3[] = {
+ 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, 2, 4, 3, 5, 3, 5, 3,
+ 5, 4, 6, 5, 6, 5, 7, 6, 6, 7, 7, 9, 9,11,11,16,
+ 11,14,10,11,11,13,16,15,15,15,15,15,15,15,15,15,
+};
+
+static const static_codebook _huff_book_line_128x4_0sub3 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_128x4_0sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x4_class0[] = {
+ 6, 7, 7,12, 6, 6, 7,12, 7, 6, 6,10,15,12,11,13,
+ 7, 7, 8,13, 7, 7, 8,12, 7, 7, 7,11,12,12,11,13,
+ 10, 9, 9,11, 9, 9, 9,10,10, 8, 8,12,14,12,12,14,
+ 11,11,12,14,11,12,11,15,15,12,13,15,15,15,15,15,
+ 6, 6, 7,10, 6, 6, 6,11, 7, 6, 6, 9,14,12,11,13,
+ 7, 7, 7,10, 6, 6, 7, 9, 7, 7, 6,10,13,12,10,12,
+ 9, 9, 9,11, 9, 9, 8, 9, 9, 8, 8,10,13,12,10,12,
+ 12,12,11,13,12,12,11,12,15,13,12,15,15,15,14,14,
+ 6, 6, 6, 8, 6, 6, 5, 6, 7, 7, 6, 5,11,10, 9, 8,
+ 7, 6, 6, 7, 6, 6, 5, 6, 7, 7, 6, 6,11,10, 9, 8,
+ 8, 8, 8, 9, 8, 8, 7, 8, 8, 8, 6, 7,11,10, 9, 9,
+ 14,11,10,14,14,11,10,15,13,11, 9,11,15,12,12,11,
+ 11, 9, 8, 8,10, 9, 8, 9,11,10, 9, 8,12,11,12,11,
+ 13,10, 8, 9,11,10, 8, 9,10, 9, 8, 9,10, 8,12,12,
+ 15,11,10,10,13,11,10,10, 8, 8, 7,12,10, 9,11,12,
+ 15,12,11,15,13,11,11,15,12,14,11,13,15,15,13,13,
+};
+
+static const static_codebook _huff_book_line_256x4_class0 = {
+ 1, 256,
+ (char *)_huff_lengthlist_line_256x4_class0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x4_0sub0[] = {
+ 2, 2, 2, 2,
+};
+
+static const static_codebook _huff_book_line_256x4_0sub0 = {
+ 1, 4,
+ (char *)_huff_lengthlist_line_256x4_0sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x4_0sub1[] = {
+ 0, 0, 0, 0, 2, 2, 3, 3, 3, 3,
+};
+
+static const static_codebook _huff_book_line_256x4_0sub1 = {
+ 1, 10,
+ (char *)_huff_lengthlist_line_256x4_0sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x4_0sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 3, 4, 3, 4, 3,
+ 5, 3, 5, 4, 5, 4, 6, 4, 6,
+};
+
+static const static_codebook _huff_book_line_256x4_0sub2 = {
+ 1, 25,
+ (char *)_huff_lengthlist_line_256x4_0sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x4_0sub3[] = {
+ 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, 2, 4, 3, 5, 3, 5, 3,
+ 6, 4, 7, 4, 7, 5, 7, 6, 7, 6, 7, 8,10,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,12,
+};
+
+static const static_codebook _huff_book_line_256x4_0sub3 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_256x4_0sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x7_class0[] = {
+ 10, 7, 8,13, 9, 6, 7,11,10, 8, 8,12,17,17,17,17,
+ 7, 5, 5, 9, 6, 4, 4, 8, 8, 5, 5, 8,16,14,13,16,
+ 7, 5, 5, 7, 6, 3, 3, 5, 8, 5, 4, 7,14,12,12,15,
+ 10, 7, 8, 9, 7, 5, 5, 6, 9, 6, 5, 5,15,12, 9,10,
+};
+
+static const static_codebook _huff_book_line_128x7_class0 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_128x7_class0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x7_class1[] = {
+ 8,13,17,17, 8,11,17,17,11,13,17,17,17,17,17,17,
+ 6,10,16,17, 6,10,15,17, 8,10,16,17,17,17,17,17,
+ 9,13,15,17, 8,11,17,17,10,12,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 6,11,15,17, 7,10,15,17, 8,10,17,17,17,15,17,17,
+ 4, 8,13,17, 4, 7,13,17, 6, 8,15,17,16,15,17,17,
+ 6,11,15,17, 6, 9,13,17, 8,10,17,17,15,17,17,17,
+ 16,17,17,17,12,14,15,17,13,14,15,17,17,17,17,17,
+ 5,10,14,17, 5, 9,14,17, 7, 9,15,17,15,15,17,17,
+ 3, 7,12,17, 3, 6,11,17, 5, 7,13,17,12,12,17,17,
+ 5, 9,14,17, 3, 7,11,17, 5, 8,13,17,13,11,16,17,
+ 12,17,17,17, 9,14,15,17,10,11,14,17,16,14,17,17,
+ 8,12,17,17, 8,12,17,17,10,12,17,17,17,17,17,17,
+ 5,10,17,17, 5, 9,15,17, 7, 9,17,17,13,13,17,17,
+ 7,11,17,17, 6,10,15,17, 7, 9,15,17,12,11,17,17,
+ 12,15,17,17,11,14,17,17,11,10,15,17,17,16,17,17,
+};
+
+static const static_codebook _huff_book_line_128x7_class1 = {
+ 1, 256,
+ (char *)_huff_lengthlist_line_128x7_class1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x7_0sub1[] = {
+ 0, 3, 3, 3, 3, 3, 3, 3, 3,
+};
+
+static const static_codebook _huff_book_line_128x7_0sub1 = {
+ 1, 9,
+ (char *)_huff_lengthlist_line_128x7_0sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x7_0sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 4, 4, 4, 4,
+ 5, 4, 5, 4, 5, 4, 6, 4, 6,
+};
+
+static const static_codebook _huff_book_line_128x7_0sub2 = {
+ 1, 25,
+ (char *)_huff_lengthlist_line_128x7_0sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x7_0sub3[] = {
+ 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, 3, 5, 3, 5, 3, 5, 4,
+ 5, 4, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5,
+ 7, 8, 9,11,13,13,13,13,13,13,13,13,13,13,13,13,
+};
+
+static const static_codebook _huff_book_line_128x7_0sub3 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_128x7_0sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x7_1sub1[] = {
+ 0, 3, 3, 2, 3, 3, 4, 3, 4,
+};
+
+static const static_codebook _huff_book_line_128x7_1sub1 = {
+ 1, 9,
+ (char *)_huff_lengthlist_line_128x7_1sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x7_1sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 6, 3, 6, 3,
+ 6, 3, 7, 3, 8, 4, 9, 4, 9,
+};
+
+static const static_codebook _huff_book_line_128x7_1sub2 = {
+ 1, 25,
+ (char *)_huff_lengthlist_line_128x7_1sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x7_1sub3[] = {
+ 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, 7, 2, 7, 3, 8, 4,
+ 9, 5, 9, 8,10,11,11,12,14,14,14,14,14,14,14,14,
+ 14,14,14,14,14,14,14,14,14,14,14,14,13,13,13,13,
+};
+
+static const static_codebook _huff_book_line_128x7_1sub3 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_128x7_1sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_class1[] = {
+ 1, 6, 3, 7, 2, 4, 5, 7,
+};
+
+static const static_codebook _huff_book_line_128x11_class1 = {
+ 1, 8,
+ (char *)_huff_lengthlist_line_128x11_class1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_class2[] = {
+ 1, 6,12,16, 4,12,15,16, 9,15,16,16,16,16,16,16,
+ 2, 5,11,16, 5,11,13,16, 9,13,16,16,16,16,16,16,
+ 4, 8,12,16, 5, 9,12,16, 9,13,15,16,16,16,16,16,
+ 15,16,16,16,11,14,13,16,12,15,16,16,16,16,16,15,
+};
+
+static const static_codebook _huff_book_line_128x11_class2 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_128x11_class2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_class3[] = {
+ 7, 6, 9,17, 7, 6, 8,17,12, 9,11,16,16,16,16,16,
+ 5, 4, 7,16, 5, 3, 6,14, 9, 6, 8,15,16,16,16,16,
+ 5, 4, 6,13, 3, 2, 4,11, 7, 4, 6,13,16,11,10,14,
+ 12,12,12,16, 9, 7,10,15,12, 9,11,16,16,15,15,16,
+};
+
+static const static_codebook _huff_book_line_128x11_class3 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_128x11_class3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_0sub0[] = {
+ 5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5,
+ 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 6, 6, 6, 7, 6,
+ 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 8, 6, 8, 6, 8, 7,
+ 8, 7, 8, 7, 8, 7, 9, 7, 9, 8, 9, 8, 9, 8,10, 8,
+ 10, 9,10, 9,10, 9,11, 9,11, 9,10,10,11,10,11,10,
+ 11,11,11,11,11,11,12,13,14,14,14,15,15,16,16,16,
+ 17,15,16,15,16,16,17,17,16,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+};
+
+static const static_codebook _huff_book_line_128x11_0sub0 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_128x11_0sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_1sub0[] = {
+ 2, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 5, 6, 5, 6, 5, 7, 6, 7, 6, 7, 6, 8, 6, 8, 6,
+};
+
+static const static_codebook _huff_book_line_128x11_1sub0 = {
+ 1, 32,
+ (char *)_huff_lengthlist_line_128x11_1sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_1sub1[] = {
+ 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,
+ 5, 3, 5, 3, 6, 4, 6, 4, 7, 4, 7, 4, 7, 4, 8, 4,
+ 8, 4, 9, 5, 9, 5, 9, 5, 9, 6,10, 6,10, 6,11, 7,
+ 10, 7,10, 8,11, 9,11, 9,11,10,11,11,12,11,11,12,
+ 15,15,12,14,11,14,12,14,11,14,13,14,12,14,11,14,
+ 11,14,12,14,11,14,11,14,13,13,14,14,14,14,14,14,
+ 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
+};
+
+static const static_codebook _huff_book_line_128x11_1sub1 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_128x11_1sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_2sub1[] = {
+ 0, 4, 5, 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, 4, 4, 4,
+ 5, 5,
+};
+
+static const static_codebook _huff_book_line_128x11_2sub1 = {
+ 1, 18,
+ (char *)_huff_lengthlist_line_128x11_2sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_2sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 4, 4, 4, 4, 5, 4, 5, 4, 6, 5, 7,
+ 5, 7, 6, 8, 6, 8, 6, 9, 7, 9, 7,10, 7, 9, 8,11,
+ 8,11,
+};
+
+static const static_codebook _huff_book_line_128x11_2sub2 = {
+ 1, 50,
+ (char *)_huff_lengthlist_line_128x11_2sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_2sub3[] = {
+ 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, 4, 8, 3, 8, 4, 8, 4, 8, 6, 8, 5, 8, 4, 8,
+ 4, 8, 6, 8, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+};
+
+static const static_codebook _huff_book_line_128x11_2sub3 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_128x11_2sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_3sub1[] = {
+ 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4,
+ 5, 4,
+};
+
+static const static_codebook _huff_book_line_128x11_3sub1 = {
+ 1, 18,
+ (char *)_huff_lengthlist_line_128x11_3sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_3sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 5, 3, 5, 4, 6, 4, 6, 4, 7, 4, 7, 4, 8, 4,
+ 8, 4, 9, 4, 9, 4,10, 4,10, 5,10, 5,11, 5,12, 6,
+ 12, 6,
+};
+
+static const static_codebook _huff_book_line_128x11_3sub2 = {
+ 1, 50,
+ (char *)_huff_lengthlist_line_128x11_3sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x11_3sub3[] = {
+ 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, 7, 1, 6, 3, 7, 3, 8, 4, 8, 5, 8, 8, 8, 9,
+ 7, 8, 8, 7, 7, 7, 8, 9,10, 9, 9,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9,
+};
+
+static const static_codebook _huff_book_line_128x11_3sub3 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_128x11_3sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_class1[] = {
+ 1, 3, 4, 7, 2, 5, 6, 7,
+};
+
+static const static_codebook _huff_book_line_128x17_class1 = {
+ 1, 8,
+ (char *)_huff_lengthlist_line_128x17_class1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_class2[] = {
+ 1, 4,10,19, 3, 8,13,19, 7,12,19,19,19,19,19,19,
+ 2, 6,11,19, 8,13,19,19, 9,11,19,19,19,19,19,19,
+ 6, 7,13,19, 9,13,19,19,10,13,18,18,18,18,18,18,
+ 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,
+};
+
+static const static_codebook _huff_book_line_128x17_class2 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_128x17_class2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_class3[] = {
+ 3, 6,10,17, 4, 8,11,20, 8,10,11,20,20,20,20,20,
+ 2, 4, 8,18, 4, 6, 8,17, 7, 8,10,20,20,17,20,20,
+ 3, 5, 8,17, 3, 4, 6,17, 8, 8,10,17,17,12,16,20,
+ 13,13,15,20,10,10,12,20,15,14,15,20,20,20,19,19,
+};
+
+static const static_codebook _huff_book_line_128x17_class3 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_128x17_class3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_0sub0[] = {
+ 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5,
+ 7, 5, 7, 5, 7, 5, 7, 5, 7, 5, 7, 5, 8, 5, 8, 5,
+ 8, 5, 8, 5, 8, 6, 8, 6, 8, 6, 9, 6, 9, 6, 9, 6,
+ 9, 6, 9, 7, 9, 7, 9, 7, 9, 7,10, 7,10, 8,10, 8,
+ 10, 8,10, 8,10, 8,11, 8,11, 8,11, 8,11, 8,11, 9,
+ 12, 9,12, 9,12, 9,12, 9,12,10,12,10,13,11,13,11,
+ 14,12,14,13,15,14,16,14,17,15,18,16,20,20,20,20,
+ 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
+};
+
+static const static_codebook _huff_book_line_128x17_0sub0 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_128x17_0sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_1sub0[] = {
+ 2, 5, 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 5, 6, 5,
+ 6, 5, 6, 5, 7, 6, 7, 6, 7, 6, 8, 6, 9, 7, 9, 7,
+};
+
+static const static_codebook _huff_book_line_128x17_1sub0 = {
+ 1, 32,
+ (char *)_huff_lengthlist_line_128x17_1sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_1sub1[] = {
+ 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,
+ 4, 3, 5, 3, 5, 3, 6, 3, 6, 4, 6, 4, 7, 4, 7, 5,
+ 8, 5, 8, 6, 9, 7, 9, 7, 9, 8,10, 9,10, 9,11,10,
+ 11,11,11,11,11,11,12,12,12,13,12,13,12,14,12,15,
+ 12,14,12,16,13,17,13,17,14,17,14,16,13,17,14,17,
+ 14,17,15,17,15,15,16,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,
+};
+
+static const static_codebook _huff_book_line_128x17_1sub1 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_128x17_1sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_2sub1[] = {
+ 0, 4, 5, 4, 6, 4, 8, 3, 9, 3, 9, 2, 9, 3, 8, 4,
+ 9, 4,
+};
+
+static const static_codebook _huff_book_line_128x17_2sub1 = {
+ 1, 18,
+ (char *)_huff_lengthlist_line_128x17_2sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_2sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 5, 1, 5, 3, 5, 3, 5, 4, 7, 5,10, 7,10, 7,
+ 12,10,14,10,14, 9,14,11,14,14,14,13,13,13,13,13,
+ 13,13,
+};
+
+static const static_codebook _huff_book_line_128x17_2sub2 = {
+ 1, 50,
+ (char *)_huff_lengthlist_line_128x17_2sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_2sub3[] = {
+ 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, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+};
+
+static const static_codebook _huff_book_line_128x17_2sub3 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_128x17_2sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_3sub1[] = {
+ 0, 4, 4, 4, 4, 4, 4, 4, 5, 3, 5, 3, 5, 4, 6, 4,
+ 6, 4,
+};
+
+static const static_codebook _huff_book_line_128x17_3sub1 = {
+ 1, 18,
+ (char *)_huff_lengthlist_line_128x17_3sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_3sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 5, 3, 6, 3, 6, 4, 7, 4, 7, 4, 7, 4, 8, 4,
+ 8, 4, 8, 4, 8, 4, 9, 4, 9, 5,10, 5,10, 7,10, 8,
+ 10, 8,
+};
+
+static const static_codebook _huff_book_line_128x17_3sub2 = {
+ 1, 50,
+ (char *)_huff_lengthlist_line_128x17_3sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_128x17_3sub3[] = {
+ 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, 3, 2, 4, 3, 4, 4, 4, 5, 4, 7, 5, 8, 5,11,
+ 6,10, 6,12, 7,12, 7,12, 8,12, 8,12,10,12,12,12,
+ 12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+};
+
+static const static_codebook _huff_book_line_128x17_3sub3 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_128x17_3sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_class1[] = {
+ 2,10, 8,14, 7,12,11,14, 1, 5, 3, 7, 4, 9, 7,13,
+};
+
+static const static_codebook _huff_book_line_1024x27_class1 = {
+ 1, 16,
+ (char *)_huff_lengthlist_line_1024x27_class1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_class2[] = {
+ 1, 4, 2, 6, 3, 7, 5, 7,
+};
+
+static const static_codebook _huff_book_line_1024x27_class2 = {
+ 1, 8,
+ (char *)_huff_lengthlist_line_1024x27_class2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_class3[] = {
+ 1, 5, 7,21, 5, 8, 9,21,10, 9,12,20,20,16,20,20,
+ 4, 8, 9,20, 6, 8, 9,20,11,11,13,20,20,15,17,20,
+ 9,11,14,20, 8,10,15,20,11,13,15,20,20,20,20,20,
+ 20,20,20,20,13,20,20,20,18,18,20,20,20,20,20,20,
+ 3, 6, 8,20, 6, 7, 9,20,10, 9,12,20,20,20,20,20,
+ 5, 7, 9,20, 6, 6, 9,20,10, 9,12,20,20,20,20,20,
+ 8,10,13,20, 8, 9,12,20,11,10,12,20,20,20,20,20,
+ 18,20,20,20,15,17,18,20,18,17,18,20,20,20,20,20,
+ 7,10,12,20, 8, 9,11,20,14,13,14,20,20,20,20,20,
+ 6, 9,12,20, 7, 8,11,20,12,11,13,20,20,20,20,20,
+ 9,11,15,20, 8,10,14,20,12,11,14,20,20,20,20,20,
+ 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
+ 11,16,18,20,15,15,17,20,20,17,20,20,20,20,20,20,
+ 9,14,16,20,12,12,15,20,17,15,18,20,20,20,20,20,
+ 16,19,18,20,15,16,20,20,17,17,20,20,20,20,20,20,
+ 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
+};
+
+static const static_codebook _huff_book_line_1024x27_class3 = {
+ 1, 256,
+ (char *)_huff_lengthlist_line_1024x27_class3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_class4[] = {
+ 2, 3, 7,13, 4, 4, 7,15, 8, 6, 9,17,21,16,15,21,
+ 2, 5, 7,11, 5, 5, 7,14, 9, 7,10,16,17,15,16,21,
+ 4, 7,10,17, 7, 7, 9,15,11, 9,11,16,21,18,15,21,
+ 18,21,21,21,15,17,17,19,21,19,18,20,21,21,21,20,
+};
+
+static const static_codebook _huff_book_line_1024x27_class4 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_1024x27_class4,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_0sub0[] = {
+ 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5,
+ 6, 5, 6, 5, 6, 5, 6, 5, 7, 5, 7, 5, 7, 5, 7, 5,
+ 8, 6, 8, 6, 8, 6, 9, 6, 9, 6,10, 6,10, 6,11, 6,
+ 11, 7,11, 7,12, 7,12, 7,12, 7,12, 7,12, 7,12, 7,
+ 12, 7,12, 8,13, 8,12, 8,12, 8,13, 8,13, 9,13, 9,
+ 13, 9,13, 9,12,10,12,10,13,10,14,11,14,12,14,13,
+ 14,13,14,14,15,16,15,15,15,14,15,17,21,22,22,21,
+ 22,22,22,22,22,22,21,21,21,21,21,21,21,21,21,21,
+};
+
+static const static_codebook _huff_book_line_1024x27_0sub0 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_1024x27_0sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_1sub0[] = {
+ 2, 5, 5, 4, 5, 4, 5, 4, 5, 4, 6, 5, 6, 5, 6, 5,
+ 6, 5, 7, 5, 7, 6, 8, 6, 8, 6, 8, 6, 9, 6, 9, 6,
+};
+
+static const static_codebook _huff_book_line_1024x27_1sub0 = {
+ 1, 32,
+ (char *)_huff_lengthlist_line_1024x27_1sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_1sub1[] = {
+ 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,
+ 8, 5, 8, 4, 9, 4, 9, 4, 9, 4, 9, 4, 9, 4, 9, 4,
+ 9, 4, 9, 4, 9, 4, 8, 4, 8, 4, 9, 5, 9, 5, 9, 5,
+ 9, 5, 9, 6,10, 6,10, 7,10, 8,11, 9,11,11,12,13,
+ 12,14,13,15,13,15,14,16,14,17,15,17,15,15,16,16,
+ 15,16,16,16,15,18,16,15,17,17,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+};
+
+static const static_codebook _huff_book_line_1024x27_1sub1 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_1024x27_1sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_2sub0[] = {
+ 1, 5, 5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5,
+ 6, 6, 7, 7, 7, 7, 8, 7, 8, 8, 9, 8,10, 9,10, 9,
+};
+
+static const static_codebook _huff_book_line_1024x27_2sub0 = {
+ 1, 32,
+ (char *)_huff_lengthlist_line_1024x27_2sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_2sub1[] = {
+ 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,
+ 4, 3, 4, 3, 4, 4, 5, 4, 5, 4, 5, 5, 6, 5, 6, 5,
+ 7, 5, 7, 6, 7, 6, 8, 7, 8, 7, 8, 7, 9, 8, 9, 9,
+ 9, 9,10,10,10,11, 9,12, 9,12, 9,15,10,14, 9,13,
+ 10,13,10,12,10,12,10,13,10,12,11,13,11,14,12,13,
+ 13,14,14,13,14,15,14,16,13,13,14,16,16,16,16,16,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,15,15,
+};
+
+static const static_codebook _huff_book_line_1024x27_2sub1 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_1024x27_2sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_3sub1[] = {
+ 0, 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, 4, 4, 4, 4, 5,
+ 5, 5,
+};
+
+static const static_codebook _huff_book_line_1024x27_3sub1 = {
+ 1, 18,
+ (char *)_huff_lengthlist_line_1024x27_3sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_3sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 4, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6,
+ 5, 7, 5, 8, 6, 8, 6, 9, 7,10, 7,10, 8,10, 8,11,
+ 9,11,
+};
+
+static const static_codebook _huff_book_line_1024x27_3sub2 = {
+ 1, 50,
+ (char *)_huff_lengthlist_line_1024x27_3sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_3sub3[] = {
+ 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, 3, 7, 3, 8, 3,10, 3, 8, 3, 9, 3, 8, 4, 9,
+ 4, 9, 5, 9, 6,10, 6, 9, 7,11, 7,12, 9,13,10,13,
+ 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,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+};
+
+static const static_codebook _huff_book_line_1024x27_3sub3 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_1024x27_3sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_4sub1[] = {
+ 0, 4, 5, 4, 5, 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, 4,
+ 5, 4,
+};
+
+static const static_codebook _huff_book_line_1024x27_4sub1 = {
+ 1, 18,
+ (char *)_huff_lengthlist_line_1024x27_4sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_4sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 2, 4, 2, 5, 3, 5, 4, 6, 6, 6, 7, 7, 8,
+ 7, 8, 7, 8, 7, 9, 8, 9, 8, 9, 8,10, 8,11, 9,12,
+ 9,12,
+};
+
+static const static_codebook _huff_book_line_1024x27_4sub2 = {
+ 1, 50,
+ (char *)_huff_lengthlist_line_1024x27_4sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_1024x27_4sub3[] = {
+ 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, 2, 5, 2, 6, 3, 6, 4, 7, 4, 7, 5, 9, 5,11,
+ 6,11, 6,11, 7,11, 6,11, 6,11, 9,11, 8,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,
+};
+
+static const static_codebook _huff_book_line_1024x27_4sub3 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_1024x27_4sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_class1[] = {
+ 2, 6, 8, 9, 7,11,13,13, 1, 3, 5, 5, 6, 6,12,10,
+};
+
+static const static_codebook _huff_book_line_2048x27_class1 = {
+ 1, 16,
+ (char *)_huff_lengthlist_line_2048x27_class1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_class2[] = {
+ 1, 2, 3, 6, 4, 7, 5, 7,
+};
+
+static const static_codebook _huff_book_line_2048x27_class2 = {
+ 1, 8,
+ (char *)_huff_lengthlist_line_2048x27_class2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_class3[] = {
+ 3, 3, 6,16, 5, 5, 7,16, 9, 8,11,16,16,16,16,16,
+ 5, 5, 8,16, 5, 5, 7,16, 8, 7, 9,16,16,16,16,16,
+ 9, 9,12,16, 6, 8,11,16, 9,10,11,16,16,16,16,16,
+ 16,16,16,16,13,16,16,16,15,16,16,16,16,16,16,16,
+ 5, 4, 7,16, 6, 5, 8,16, 9, 8,10,16,16,16,16,16,
+ 5, 5, 7,15, 5, 4, 6,15, 7, 6, 8,16,16,16,16,16,
+ 9, 9,11,15, 7, 7, 9,16, 8, 8, 9,16,16,16,16,16,
+ 16,16,16,16,15,15,15,16,15,15,14,16,16,16,16,16,
+ 8, 8,11,16, 8, 9,10,16,11,10,14,16,16,16,16,16,
+ 6, 8,10,16, 6, 7,10,16, 8, 8,11,16,14,16,16,16,
+ 10,11,14,16, 9, 9,11,16,10,10,11,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,15,16,16,16,16,16,16,16,16,16,16,16,
+ 12,16,15,16,12,14,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,
+};
+
+static const static_codebook _huff_book_line_2048x27_class3 = {
+ 1, 256,
+ (char *)_huff_lengthlist_line_2048x27_class3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_class4[] = {
+ 2, 4, 7,13, 4, 5, 7,15, 8, 7,10,16,16,14,16,16,
+ 2, 4, 7,16, 3, 4, 7,14, 8, 8,10,16,16,16,15,16,
+ 6, 8,11,16, 7, 7, 9,16,11, 9,13,16,16,16,15,16,
+ 16,16,16,16,14,16,16,16,16,16,16,16,16,16,16,16,
+};
+
+static const static_codebook _huff_book_line_2048x27_class4 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_2048x27_class4,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_0sub0[] = {
+ 5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5,
+ 6, 5, 7, 5, 7, 5, 7, 5, 8, 5, 8, 5, 8, 5, 9, 5,
+ 9, 6,10, 6,10, 6,11, 6,11, 6,11, 6,11, 6,11, 6,
+ 11, 6,11, 6,12, 7,11, 7,11, 7,11, 7,11, 7,10, 7,
+ 11, 7,11, 7,12, 7,11, 8,11, 8,11, 8,11, 8,13, 8,
+ 12, 9,11, 9,11, 9,11,10,12,10,12, 9,12,10,12,11,
+ 14,12,16,12,12,11,14,16,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,16,16,16,16,
+};
+
+static const static_codebook _huff_book_line_2048x27_0sub0 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_2048x27_0sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_1sub0[] = {
+ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 6, 6, 6, 6, 6, 6, 7, 6, 7, 6, 7, 6, 7, 6,
+};
+
+static const static_codebook _huff_book_line_2048x27_1sub0 = {
+ 1, 32,
+ (char *)_huff_lengthlist_line_2048x27_1sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_1sub1[] = {
+ 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,
+ 6, 5, 7, 5, 7, 4, 7, 4, 8, 4, 8, 4, 8, 4, 8, 3,
+ 8, 4, 9, 4, 9, 4, 9, 4, 9, 4, 9, 5, 9, 5, 9, 6,
+ 9, 7, 9, 8, 9, 9, 9,10, 9,11, 9,14, 9,15,10,15,
+ 10,15,10,15,10,15,11,15,10,14,12,14,11,14,13,14,
+ 13,15,15,15,12,15,15,15,13,15,13,15,13,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,14,
+};
+
+static const static_codebook _huff_book_line_2048x27_1sub1 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_2048x27_1sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_2sub0[] = {
+ 2, 4, 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 5, 6, 5,
+ 6, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
+};
+
+static const static_codebook _huff_book_line_2048x27_2sub0 = {
+ 1, 32,
+ (char *)_huff_lengthlist_line_2048x27_2sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_2sub1[] = {
+ 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,
+ 3, 4, 3, 4, 3, 4, 4, 5, 4, 5, 5, 5, 6, 6, 6, 7,
+ 6, 8, 6, 8, 6, 9, 7,10, 7,10, 7,10, 7,12, 7,12,
+ 7,12, 9,12,11,12,10,12,10,12,11,12,12,12,10,12,
+ 10,12,10,12, 9,12,11,12,12,12,12,12,11,12,11,12,
+ 12,12,12,12,12,12,12,12,10,10,12,12,12,12,12,10,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+};
+
+static const static_codebook _huff_book_line_2048x27_2sub1 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_2048x27_2sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_3sub1[] = {
+ 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5,
+};
+
+static const static_codebook _huff_book_line_2048x27_3sub1 = {
+ 1, 18,
+ (char *)_huff_lengthlist_line_2048x27_3sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_3sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6,
+ 6, 7, 6, 7, 6, 8, 6, 9, 7, 9, 7, 9, 9,11, 9,12,
+ 10,12,
+};
+
+static const static_codebook _huff_book_line_2048x27_3sub2 = {
+ 1, 50,
+ (char *)_huff_lengthlist_line_2048x27_3sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_3sub3[] = {
+ 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, 3, 6, 3, 7, 3, 7, 5, 7, 7, 7, 7, 7, 6, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+};
+
+static const static_codebook _huff_book_line_2048x27_3sub3 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_2048x27_3sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_4sub1[] = {
+ 0, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 5, 4, 5, 4,
+ 4, 5,
+};
+
+static const static_codebook _huff_book_line_2048x27_4sub1 = {
+ 1, 18,
+ (char *)_huff_lengthlist_line_2048x27_4sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_4sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 2, 4, 3, 4, 4, 4, 5, 5, 6, 5, 6, 5, 7,
+ 6, 6, 6, 7, 7, 7, 8, 9, 9, 9,12,10,11,10,10,12,
+ 10,10,
+};
+
+static const static_codebook _huff_book_line_2048x27_4sub2 = {
+ 1, 50,
+ (char *)_huff_lengthlist_line_2048x27_4sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_2048x27_4sub3[] = {
+ 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, 3, 6, 5, 7, 5, 7, 7, 7, 7, 7, 5, 7, 5, 7,
+ 5, 7, 5, 7, 7, 7, 7, 7, 4, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+};
+
+static const static_codebook _huff_book_line_2048x27_4sub3 = {
+ 1, 128,
+ (char *)_huff_lengthlist_line_2048x27_4sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x4low_class0[] = {
+ 4, 5, 6,11, 5, 5, 6,10, 7, 7, 6, 6,14,13, 9, 9,
+ 6, 6, 6,10, 6, 6, 6, 9, 8, 7, 7, 9,14,12, 8,11,
+ 8, 7, 7,11, 8, 8, 7,11, 9, 9, 7, 9,13,11, 9,13,
+ 19,19,18,19,15,16,16,19,11,11,10,13,10,10, 9,15,
+ 5, 5, 6,13, 6, 6, 6,11, 8, 7, 6, 7,14,11,10,11,
+ 6, 6, 6,12, 7, 6, 6,11, 8, 7, 7,11,13,11, 9,11,
+ 9, 7, 6,12, 8, 7, 6,12, 9, 8, 8,11,13,10, 7,13,
+ 19,19,17,19,17,14,14,19,12,10, 8,12,13,10, 9,16,
+ 7, 8, 7,12, 7, 7, 7,11, 8, 7, 7, 8,12,12,11,11,
+ 8, 8, 7,12, 8, 7, 6,11, 8, 7, 7,10,10,11,10,11,
+ 9, 8, 8,13, 9, 8, 7,12,10, 9, 7,11, 9, 8, 7,11,
+ 18,18,15,18,18,16,17,18,15,11,10,18,11, 9, 9,18,
+ 16,16,13,16,12,11,10,16,12,11, 9, 6,15,12,11,13,
+ 16,16,14,14,13,11,12,16,12, 9, 9,13,13,10,10,12,
+ 17,18,17,17,14,15,14,16,14,12,14,15,12,10,11,12,
+ 18,18,18,18,18,18,18,18,18,12,13,18,16,11, 9,18,
+};
+
+static const static_codebook _huff_book_line_256x4low_class0 = {
+ 1, 256,
+ (char *)_huff_lengthlist_line_256x4low_class0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x4low_0sub0[] = {
+ 1, 3, 2, 3,
+};
+
+static const static_codebook _huff_book_line_256x4low_0sub0 = {
+ 1, 4,
+ (char *)_huff_lengthlist_line_256x4low_0sub0,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x4low_0sub1[] = {
+ 0, 0, 0, 0, 2, 3, 2, 3, 3, 3,
+};
+
+static const static_codebook _huff_book_line_256x4low_0sub1 = {
+ 1, 10,
+ (char *)_huff_lengthlist_line_256x4low_0sub1,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x4low_0sub2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 4, 3, 4,
+ 4, 4, 4, 4, 5, 5, 5, 6, 6,
+};
+
+static const static_codebook _huff_book_line_256x4low_0sub2 = {
+ 1, 25,
+ (char *)_huff_lengthlist_line_256x4low_0sub2,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist_line_256x4low_0sub3[] = {
+ 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, 3, 4, 2, 4, 3, 5, 4,
+ 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 8, 6, 9,
+ 7,12,11,16,13,16,12,15,13,15,12,14,12,15,15,15,
+};
+
+static const static_codebook _huff_book_line_256x4low_0sub3 = {
+ 1, 64,
+ (char *)_huff_lengthlist_line_256x4low_0sub3,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
diff --git a/external/libvorbis-1.3.5/lib/books/uncoupled/res_books_uncoupled.h b/external/libvorbis-1.3.5/lib/books/uncoupled/res_books_uncoupled.h
new file mode 100644
index 0000000..736353b
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/books/uncoupled/res_books_uncoupled.h
@@ -0,0 +1,7758 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: static codebooks autogenerated by huff/huffbuld
+ last modified: $Id: res_books_uncoupled.h 19057 2014-01-22 12:32:31Z xiphmont $
+
+ ********************************************************************/
+
+#include "codebook.h"
+
+static const long _vq_quantlist__16u0__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16u0__p1_0[] = {
+ 1, 4, 4, 5, 7, 7, 5, 7, 8, 5, 8, 8, 8,10,10, 8,
+ 10,11, 5, 8, 8, 8,10,10, 8,10,10, 4, 9, 9, 9,12,
+ 11, 8,11,11, 8,12,11,10,12,14,10,13,13, 7,11,11,
+ 10,14,12,11,14,14, 4, 9, 9, 8,11,11, 9,11,12, 7,
+ 11,11,10,13,14,10,12,14, 8,11,12,10,14,14,10,13,
+ 12,
+};
+
+static const static_codebook _16u0__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16u0__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__16u0__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__16u0__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16u0__p2_0[] = {
+ 2, 4, 4, 5, 6, 6, 5, 6, 6, 5, 7, 7, 7, 8, 9, 7,
+ 8, 9, 5, 7, 7, 7, 9, 8, 7, 9, 7, 4, 7, 7, 7, 9,
+ 9, 7, 8, 8, 6, 9, 8, 7, 8,11, 9,11,10, 6, 8, 9,
+ 8,11, 8, 9,10,11, 4, 7, 7, 7, 8, 8, 7, 9, 9, 6,
+ 9, 8, 9,11,10, 8, 8,11, 6, 8, 9, 9,10,11, 8,11,
+ 8,
+};
+
+static const static_codebook _16u0__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16u0__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__16u0__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__16u0__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16u0__p3_0[] = {
+ 1, 5, 5, 7, 7, 6, 7, 7, 8, 8, 6, 7, 8, 8, 8, 8,
+ 9, 9,11,11, 8, 9, 9,11,11, 6, 9, 8,10,10, 8,10,
+ 10,11,11, 8,10,10,11,11,10,11,10,13,12, 9,11,10,
+ 13,13, 6, 8, 9,10,10, 8,10,10,11,11, 8,10,10,11,
+ 11, 9,10,11,13,12,10,10,11,12,12, 8,11,11,14,13,
+ 10,12,11,15,13, 9,12,11,15,14,12,14,13,16,14,12,
+ 13,13,17,14, 8,11,11,13,14, 9,11,12,14,15,10,11,
+ 12,13,15,11,13,13,14,16,12,13,14,14,16, 5, 9, 9,
+ 11,11, 9,11,11,12,12, 8,11,11,12,12,11,12,12,15,
+ 14,10,12,12,15,15, 8,11,11,13,12,10,12,12,13,13,
+ 10,12,12,14,13,12,12,13,14,15,11,13,13,17,16, 7,
+ 11,11,13,13,10,12,12,14,13,10,12,12,13,14,12,13,
+ 12,15,14,11,13,13,15,14, 9,12,12,16,15,11,13,13,
+ 17,16,10,13,13,16,16,13,14,15,15,16,13,15,14,19,
+ 17, 9,12,12,14,16,11,13,13,15,16,10,13,13,17,16,
+ 13,14,13,17,15,12,15,15,16,17, 5, 9, 9,11,11, 8,
+ 11,11,13,12, 9,11,11,12,12,10,12,12,14,15,11,12,
+ 12,14,14, 7,11,10,13,12,10,12,12,14,13,10,11,12,
+ 13,13,11,13,13,15,16,12,12,13,15,15, 7,11,11,13,
+ 13,10,13,13,14,14,10,12,12,13,13,11,13,13,16,15,
+ 12,13,13,15,14, 9,12,12,15,15,10,13,13,17,16,11,
+ 12,13,15,15,12,15,14,18,18,13,14,14,16,17, 9,12,
+ 12,15,16,10,13,13,15,16,11,13,13,15,16,13,15,15,
+ 17,17,13,15,14,16,15, 7,11,11,15,16,10,13,12,16,
+ 17,10,12,13,15,17,15,16,16,18,17,13,15,15,17,18,
+ 8,12,12,16,16,11,13,14,17,18,11,13,13,18,16,15,
+ 17,16,17,19,14,15,15,17,16, 8,12,12,16,15,11,14,
+ 13,18,17,11,13,14,18,17,15,16,16,18,17,13,16,16,
+ 18,18,11,15,14,18,17,13,14,15,18, 0,12,15,15, 0,
+ 17,17,16,17,17,18,14,16,18,18, 0,11,14,14,17, 0,
+ 12,15,14,17,19,12,15,14,18, 0,15,18,16, 0,17,14,
+ 18,16,18, 0, 7,11,11,16,15,10,12,12,18,16,10,13,
+ 13,16,15,13,15,14,17,17,14,16,16,19,18, 8,12,12,
+ 16,16,11,13,13,18,16,11,13,14,17,16,14,15,15,19,
+ 18,15,16,16, 0,19, 8,12,12,16,17,11,13,13,17,17,
+ 11,14,13,17,17,13,15,15,17,19,15,17,17,19, 0,11,
+ 14,15,19,17,12,15,16,18,18,12,14,15,19,17,14,16,
+ 17, 0,18,16,16,19,17, 0,11,14,14,18,19,12,15,14,
+ 17,17,13,16,14,17,16,14,17,16,18,18,15,18,15, 0,
+ 18,
+};
+
+static const static_codebook _16u0__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__16u0__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16u0__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__16u0__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16u0__p4_0[] = {
+ 3, 5, 5, 8, 8, 6, 6, 6, 9, 9, 6, 6, 6, 9, 9, 9,
+ 10, 9,11,11, 9, 9, 9,11,11, 6, 7, 7,10,10, 7, 7,
+ 8,10,10, 7, 7, 8,10,10,10,10,10,11,12, 9,10,10,
+ 11,12, 6, 7, 7,10,10, 7, 8, 7,10,10, 7, 8, 7,10,
+ 10,10,11,10,12,11,10,10,10,13,10, 9,10,10,12,12,
+ 10,11,10,14,12, 9,11,11,13,13,11,12,13,13,13,11,
+ 12,12,15,13, 9,10,10,12,13, 9,11,10,12,13,10,10,
+ 11,12,13,11,12,12,12,13,11,12,12,13,13, 5, 7, 7,
+ 10,10, 7, 8, 8,10,10, 7, 8, 8,10,10,10,11,10,12,
+ 13,10,10,11,12,12, 6, 8, 8,11,10, 7, 8, 9,10,12,
+ 8, 9, 9,11,11,11,10,11,11,12,10,11,11,13,12, 7,
+ 8, 8,10,11, 8, 9, 8,11,10, 8, 9, 9,11,11,10,12,
+ 10,13,11,10,11,11,13,13,10,11,10,14,13,10,10,11,
+ 13,13,10,12,11,14,13,12,11,13,12,13,13,12,13,14,
+ 14,10,11,11,13,13,10,11,10,12,13,10,12,12,12,14,
+ 12,12,12,14,12,12,13,12,17,15, 5, 7, 7,10,10, 7,
+ 8, 8,10,10, 7, 8, 8,11,10,10,10,11,12,12,10,11,
+ 11,12,13, 6, 8, 8,11,10, 8, 9, 9,11,11, 7, 8, 9,
+ 10,11,11,11,11,12,12,10,10,11,12,13, 6, 8, 8,10,
+ 11, 8, 9, 9,11,11, 7, 9, 7,11,10,10,12,12,13,13,
+ 11,11,10,13,11, 9,11,10,14,13,11,11,11,15,13,10,
+ 10,11,13,13,12,13,13,14,14,12,11,12,12,13,10,11,
+ 11,12,13,10,11,12,13,13,10,11,10,13,12,12,12,13,
+ 14, 0,12,13,11,13,11, 8,10,10,13,13,10,11,11,14,
+ 13,10,11,11,13,12,13,14,14,14,15,12,12,12,15,14,
+ 9,11,10,13,12,10,10,11,13,14,11,11,11,15,12,13,
+ 12,14,15,16,13,13,13,14,13, 9,11,11,12,12,10,12,
+ 11,13,13,10,11,11,13,14,13,13,13,15,15,13,13,14,
+ 17,15,11,12,12,14,14,10,11,12,13,15,12,13,13, 0,
+ 15,13,11,14,12,16,14,16,14, 0,15,11,12,12,14,16,
+ 11,13,12,16,15,12,13,13,14,15,12,14,12,15,13,15,
+ 14,14,16,16, 8,10,10,13,13,10,11,10,13,14,10,11,
+ 11,13,13,13,13,12,14,14,14,13,13,16,17, 9,10,10,
+ 12,14,10,12,11,14,13,10,11,12,13,14,12,12,12,15,
+ 15,13,13,13,14,14, 9,10,10,13,13,10,11,12,12,14,
+ 10,11,10,13,13,13,13,13,14,16,13,13,13,14,14,11,
+ 12,13,15,13,12,14,13,14,16,12,12,13,13,14,13,14,
+ 14,17,15,13,12,17,13,16,11,12,13,14,15,12,13,14,
+ 14,17,11,12,11,14,14,13,16,14,16, 0,14,15,11,15,
+ 11,
+};
+
+static const static_codebook _16u0__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__16u0__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16u0__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__16u0__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__16u0__p5_0[] = {
+ 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 6, 8, 8, 8, 8,
+ 9, 9, 4, 6, 6, 8, 8, 8, 8, 9, 9, 7, 8, 8, 9, 9,
+ 9, 9,11,10, 7, 8, 8, 9, 9, 9, 9,10,11, 7, 8, 8,
+ 9, 9,10,10,11,11, 7, 8, 8, 9, 9,10,10,11,11, 9,
+ 9, 9,10,10,11,11,12,12, 9, 9, 9,10,10,11,11,12,
+ 12,
+};
+
+static const static_codebook _16u0__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__16u0__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16u0__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__16u0__p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__16u0__p6_0[] = {
+ 1, 4, 4, 7, 7,10,10,12,12,13,13,18,17, 3, 6, 6,
+ 9, 9,11,11,13,13,14,14,18,17, 3, 6, 6, 9, 9,11,
+ 11,13,13,14,14,17,18, 7, 9, 9,11,11,13,13,14,14,
+ 15,15, 0, 0, 7, 9, 9,11,11,13,13,14,14,15,16,19,
+ 18,10,11,11,13,13,14,14,16,15,17,18, 0, 0,10,11,
+ 11,13,13,14,14,15,15,16,18, 0, 0,11,13,13,14,14,
+ 15,15,17,17, 0,19, 0, 0,11,13,13,14,14,14,15,16,
+ 18, 0,19, 0, 0,13,14,14,15,15,18,17,18,18, 0,19,
+ 0, 0,13,14,14,15,16,16,16,18,18,19, 0, 0, 0,16,
+ 17,17, 0,17,19,19, 0,19, 0, 0, 0, 0,16,19,16,17,
+ 18, 0,19, 0, 0, 0, 0, 0, 0,
+};
+
+static const static_codebook _16u0__p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__16u0__p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__16u0__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__16u0__p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16u0__p6_1[] = {
+ 1, 4, 5, 6, 6, 4, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6,
+ 6, 6, 7, 7, 6, 6, 6, 7, 7,
+};
+
+static const static_codebook _16u0__p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__16u0__p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16u0__p6_1,
+ 0
+};
+
+static const long _vq_quantlist__16u0__p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16u0__p7_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7,
+};
+
+static const static_codebook _16u0__p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16u0__p7_0,
+ 1, -518803456, 1628680192, 2, 0,
+ (long *)_vq_quantlist__16u0__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__16u0__p7_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__16u0__p7_1[] = {
+ 1, 5, 5, 6, 5, 9,10,11,11,10,10,10,10,10,10, 5,
+ 8, 8, 8,10,10,10,10,10,10,10,10,10,10,10, 5, 8,
+ 9, 9, 9,10,10,10,10,10,10,10,10,10,10, 5,10, 8,
+ 10,10,10,10,10,10,10,10,10,10,10,10, 4, 8, 9,10,
+ 10,10,10,10,10,10,10,10,10,10,10, 9,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10, 9,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _16u0__p7_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__16u0__p7_1,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__16u0__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__16u0__p7_2[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__16u0__p7_2[] = {
+ 1, 6, 6, 7, 8, 7, 7,10, 9,10, 9,11,10, 9,11,10,
+ 9, 9, 9, 9,10, 6, 8, 7, 9, 9, 8, 8,10,10, 9,11,
+ 11,12,12,10, 9,11, 9,12,10, 9, 6, 9, 8, 9,12, 8,
+ 8,11, 9,11,11,12,11,12,12,10,11,11,10,10,11, 7,
+ 10, 9, 9, 9, 9, 9,10, 9,10, 9,10,10,12,10,10,10,
+ 11,12,10,10, 7, 9, 9, 9,10, 9, 9,10,10, 9, 9, 9,
+ 11,11,10,10,10,10, 9, 9,12, 7, 9,10, 9,11, 9,10,
+ 9,10,11,11,11,10,11,12, 9,12,11,10,10,10, 7, 9,
+ 9, 9, 9,10,12,10, 9,11,12,10,11,12,12,11, 9,10,
+ 11,10,11, 7, 9,10,10,11,10, 9,10,11,11,11,10,12,
+ 12,12,11,11,10,11,11,12, 8, 9,10,12,11,10,10,12,
+ 12,12,12,12,10,11,11, 9,11,10,12,11,11, 8, 9,10,
+ 10,11,12,11,11,10,10,10,12,12,12, 9,10,12,12,12,
+ 12,12, 8,10,11,10,10,12, 9,11,12,12,11,12,12,12,
+ 12,10,12,10,10,10,10, 8,12,11,11,11,10,10,11,12,
+ 12,12,12,11,12,12,12,11,11,11,12,10, 9,10,10,12,
+ 10,12,10,12,12,10,10,10,11,12,12,12,11,12,12,12,
+ 11,10,11,12,12,12,11,12,12,11,12,12,11,12,12,12,
+ 12,11,12,12,10,10,10,10,11,11,12,11,12,12,12,12,
+ 12,12,12,11,12,11,10,11,11,12,11,11, 9,10,10,10,
+ 12,10,10,11, 9,11,12,11,12,11,12,12,10,11,10,12,
+ 9, 9, 9,12,11,10,11,10,12,10,12,10,12,12,12,11,
+ 11,11,11,11,10, 9,10,10,11,10,11,11,12,11,10,11,
+ 12,12,12,11,11, 9,12,10,12, 9,10,12,10,10,11,10,
+ 11,11,12,11,10,11,10,11,11,11,11,12,11,11,10, 9,
+ 10,10,10, 9,11,11,10, 9,12,10,11,12,11,12,12,11,
+ 12,11,12,11,10,11,10,12,11,12,11,12,11,12,10,11,
+ 10,10,12,11,10,11,11,11,10,
+};
+
+static const static_codebook _16u0__p7_2 = {
+ 2, 441,
+ (char *)_vq_lengthlist__16u0__p7_2,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__16u0__p7_2,
+ 0
+};
+
+static const char _huff_lengthlist__16u0__single[] = {
+ 3, 5, 8, 7,14, 8, 9,19, 5, 2, 5, 5, 9, 6, 9,19,
+ 8, 4, 5, 7, 8, 9,13,19, 7, 4, 6, 5, 9, 6, 9,19,
+ 12, 8, 7, 9,10,11,13,19, 8, 5, 8, 6, 9, 6, 7,19,
+ 8, 8,10, 7, 7, 4, 5,19,12,17,19,15,18,13,11,18,
+};
+
+static const static_codebook _huff_book__16u0__single = {
+ 2, 64,
+ (char *)_huff_lengthlist__16u0__single,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__16u1__long[] = {
+ 3, 6,10, 8,12, 8,14, 8,14,19, 5, 3, 5, 5, 7, 6,
+ 11, 7,16,19, 7, 5, 6, 7, 7, 9,11,12,19,19, 6, 4,
+ 7, 5, 7, 6,10, 7,18,18, 8, 6, 7, 7, 7, 7, 8, 9,
+ 18,18, 7, 5, 8, 5, 7, 5, 8, 6,18,18,12, 9,10, 9,
+ 9, 9, 8, 9,18,18, 8, 7,10, 6, 8, 5, 6, 4,11,18,
+ 11,15,16,12,11, 8, 8, 6, 9,18,14,18,18,18,16,16,
+ 16,13,16,18,
+};
+
+static const static_codebook _huff_book__16u1__long = {
+ 2, 100,
+ (char *)_huff_lengthlist__16u1__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16u1__p1_0[] = {
+ 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 7, 7,10,10, 7,
+ 9,10, 5, 7, 8, 7,10, 9, 7,10,10, 5, 8, 8, 8,10,
+ 10, 8,10,10, 7,10,10,10,11,12,10,12,13, 7,10,10,
+ 9,13,11,10,12,13, 5, 8, 8, 8,10,10, 8,10,10, 7,
+ 10,10,10,12,12, 9,11,12, 7,10,11,10,12,12,10,13,
+ 11,
+};
+
+static const static_codebook _16u1__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16u1__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__16u1__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16u1__p2_0[] = {
+ 3, 4, 4, 5, 6, 6, 5, 6, 6, 5, 6, 6, 6, 7, 8, 6,
+ 7, 8, 5, 6, 6, 6, 8, 7, 6, 8, 7, 5, 6, 6, 6, 8,
+ 8, 6, 8, 8, 6, 8, 8, 7, 7,10, 8, 9, 9, 6, 8, 8,
+ 7, 9, 8, 8, 9,10, 5, 6, 6, 6, 8, 8, 7, 8, 8, 6,
+ 8, 8, 8,10, 9, 7, 8, 9, 6, 8, 8, 8, 9, 9, 7,10,
+ 8,
+};
+
+static const static_codebook _16u1__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16u1__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__16u1__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16u1__p3_0[] = {
+ 1, 5, 5, 8, 8, 6, 7, 7, 9, 9, 5, 7, 7, 9, 9, 9,
+ 10, 9,11,11, 9, 9,10,11,11, 6, 8, 8,10,10, 8, 9,
+ 10,11,11, 8, 9,10,11,11,10,11,11,12,13,10,11,11,
+ 13,13, 6, 8, 8,10,10, 8,10, 9,11,11, 8,10, 9,11,
+ 11,10,11,11,13,13,10,11,11,13,12, 9,11,11,14,13,
+ 10,12,12,15,14,10,12,11,14,13,12,13,13,15,15,12,
+ 13,13,16,14, 9,11,11,13,14,10,11,12,14,14,10,12,
+ 12,14,15,12,13,13,14,15,12,13,14,15,16, 5, 8, 8,
+ 11,11, 8,10,10,12,12, 8,10,10,12,12,11,12,12,14,
+ 14,11,12,12,14,14, 8,10,10,12,12, 9,11,12,12,13,
+ 10,12,12,13,13,12,12,13,14,15,11,13,13,15,15, 7,
+ 10,10,12,12, 9,12,11,13,12,10,11,12,13,13,12,13,
+ 12,15,14,11,12,13,15,15,10,12,12,15,14,11,13,13,
+ 16,15,11,13,13,16,15,14,13,14,15,16,13,15,15,17,
+ 17,10,12,12,14,15,11,12,12,15,15,11,13,13,15,16,
+ 13,15,13,16,15,13,15,15,16,17, 5, 8, 8,11,11, 8,
+ 10,10,12,12, 8,10,10,12,12,11,12,12,14,14,11,12,
+ 12,14,14, 7,10,10,12,12,10,12,12,14,13, 9,11,12,
+ 12,13,12,13,13,15,15,12,12,13,13,15, 7,10,10,12,
+ 13,10,11,12,13,13,10,12,11,13,13,11,13,13,15,15,
+ 12,13,12,15,14, 9,12,12,15,14,11,13,13,15,15,11,
+ 12,13,15,15,13,14,14,17,19,13,13,14,16,16,10,12,
+ 12,14,15,11,13,13,15,16,11,13,12,16,15,13,15,15,
+ 17,18,14,15,13,16,15, 8,11,11,15,14,10,12,12,16,
+ 15,10,12,12,16,16,14,15,15,18,17,13,14,15,16,18,
+ 9,12,12,15,15,11,12,14,16,17,11,13,13,16,15,15,
+ 15,15,17,18,14,15,16,17,17, 9,12,12,15,15,11,14,
+ 13,16,16,11,13,13,16,16,15,16,15,17,18,14,16,15,
+ 17,16,12,14,14,17,16,12,14,15,18,17,13,15,15,17,
+ 17,15,15,18,16,20,15,16,17,18,18,11,14,14,16,17,
+ 13,15,14,18,17,13,15,15,17,17,15,17,15,18,17,15,
+ 17,16,19,18, 8,11,11,14,15,10,12,12,15,15,10,12,
+ 12,16,16,13,14,14,17,16,14,15,15,17,17, 9,12,12,
+ 15,16,11,13,13,16,16,11,12,13,16,16,14,16,15,20,
+ 17,14,16,16,17,17, 9,12,12,15,16,11,13,13,16,17,
+ 11,13,13,17,16,14,15,15,17,18,15,15,15,18,18,11,
+ 14,14,17,16,13,15,15,17,17,13,14,14,18,17,15,16,
+ 16,18,19,15,15,17,17,19,11,14,14,16,17,13,15,14,
+ 17,19,13,15,14,18,17,15,17,16,18,18,15,17,15,18,
+ 16,
+};
+
+static const static_codebook _16u1__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__16u1__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16u1__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16u1__p4_0[] = {
+ 4, 5, 5, 8, 8, 6, 6, 7, 9, 9, 6, 6, 6, 9, 9, 9,
+ 10, 9,11,11, 9, 9,10,11,11, 6, 7, 7,10, 9, 7, 7,
+ 8, 9,10, 7, 7, 8,10,10,10,10,10,10,12, 9, 9,10,
+ 11,12, 6, 7, 7, 9, 9, 7, 8, 7,10,10, 7, 8, 7,10,
+ 10, 9,10, 9,12,11,10,10, 9,12,10, 9,10,10,12,11,
+ 10,10,10,12,12, 9,10,10,12,12,12,11,12,13,13,11,
+ 11,12,12,13, 9,10,10,11,12, 9,10,10,12,12,10,10,
+ 10,12,12,11,12,11,14,13,11,12,12,14,13, 5, 7, 7,
+ 10,10, 7, 8, 8,10,10, 7, 8, 7,10,10,10,10,10,12,
+ 12,10,10,10,12,12, 6, 8, 7,10,10, 7, 7, 9,10,11,
+ 8, 9, 9,11,10,10,10,11,11,13,10,10,11,12,13, 6,
+ 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,10,11,10,11,
+ 10,13,11,10,11,10,12,12,10,11,10,12,11,10,10,10,
+ 12,13,10,11,11,13,12,11,11,13,11,14,12,12,13,14,
+ 14, 9,10,10,12,13,10,11,10,13,12,10,11,11,12,13,
+ 11,12,11,14,12,12,13,13,15,14, 5, 7, 7,10,10, 7,
+ 7, 8,10,10, 7, 8, 8,10,10,10,10,10,11,12,10,10,
+ 10,12,12, 7, 8, 8,10,10, 8, 9, 8,11,10, 7, 8, 9,
+ 10,11,10,11,11,12,12,10,10,11,11,13, 7, 7, 8,10,
+ 10, 8, 8, 9,10,11, 7, 9, 7,11,10,10,11,11,13,12,
+ 11,11,10,13,11, 9,10,10,12,12,10,11,11,13,12,10,
+ 10,11,12,12,12,13,13,14,14,11,11,12,12,14,10,10,
+ 11,12,12,10,11,11,12,13,10,10,10,13,12,12,13,13,
+ 15,14,12,13,10,14,11, 8,10,10,12,12,10,11,10,13,
+ 13, 9,10,10,12,12,12,13,13,15,14,11,12,12,13,13,
+ 9,10,10,13,12,10,10,11,13,13,10,11,10,13,12,12,
+ 12,13,14,15,12,13,12,15,13, 9,10,10,12,13,10,11,
+ 10,13,12,10,10,11,12,13,12,14,12,15,13,12,12,13,
+ 14,15,11,12,11,14,13,11,11,12,14,15,12,13,12,15,
+ 14,13,11,15,11,16,13,14,14,16,15,11,12,12,14,14,
+ 11,12,11,14,13,12,12,13,14,15,13,14,12,16,12,14,
+ 14,14,15,15, 8,10,10,12,12, 9,10,10,12,12,10,10,
+ 11,13,13,11,12,12,13,13,12,13,13,14,15, 9,10,10,
+ 13,12,10,11,11,13,12,10,10,11,13,13,12,13,12,15,
+ 14,12,12,13,13,16, 9, 9,10,12,13,10,10,11,12,13,
+ 10,11,10,13,13,12,12,13,13,15,13,13,12,15,13,11,
+ 12,12,14,14,12,13,12,15,14,11,11,12,13,14,14,14,
+ 14,16,15,13,12,15,12,16,11,11,12,13,14,12,13,13,
+ 14,15,10,12,11,14,13,14,15,14,16,16,13,14,11,15,
+ 11,
+};
+
+static const static_codebook _16u1__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__16u1__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16u1__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__16u1__p5_0[] = {
+ 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 6, 8, 8, 8, 8,
+ 10,10, 4, 5, 6, 8, 8, 8, 8,10,10, 7, 8, 8, 9, 9,
+ 9, 9,11,11, 7, 8, 8, 9, 9, 9, 9,11,11, 7, 8, 8,
+ 10, 9,11,11,12,11, 7, 8, 8, 9, 9,11,11,12,12, 9,
+ 10,10,11,11,12,12,13,12, 9,10,10,11,11,12,12,12,
+ 13,
+};
+
+static const static_codebook _16u1__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__16u1__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16u1__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p6_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__16u1__p6_0[] = {
+ 3, 4, 4, 6, 6, 7, 7, 9, 9, 4, 4, 4, 6, 6, 8, 8,
+ 9, 9, 4, 4, 4, 6, 6, 7, 7, 9, 9, 6, 6, 6, 7, 7,
+ 8, 8,10, 9, 6, 6, 6, 7, 7, 8, 8, 9,10, 7, 8, 7,
+ 8, 8, 9, 9,10,10, 7, 8, 8, 8, 8, 9, 9,10,10, 9,
+ 9, 9,10,10,10,10,11,11, 9, 9, 9,10,10,10,10,11,
+ 11,
+};
+
+static const static_codebook _16u1__p6_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__16u1__p6_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16u1__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16u1__p7_0[] = {
+ 1, 4, 4, 4, 8, 8, 4, 8, 8, 5,11, 9, 8,12,11, 8,
+ 12,11, 5,10,11, 8,11,12, 8,11,12, 4,11,11,11,14,
+ 13,10,13,13, 8,14,13,12,14,16,12,16,15, 8,14,14,
+ 13,16,14,12,15,16, 4,11,11,10,14,13,11,14,14, 8,
+ 15,14,12,15,15,12,14,16, 8,14,14,11,16,15,12,15,
+ 13,
+};
+
+static const static_codebook _16u1__p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16u1__p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__16u1__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__16u1__p7_1[] = {
+ 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 4, 6, 5, 7, 7,
+ 8, 8, 8, 8, 8, 8, 4, 5, 6, 7, 7, 8, 8, 8, 8, 8,
+ 8, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 6, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9, 7, 8, 8, 8, 8, 9, 9, 9,10,
+ 9,10, 7, 8, 8, 8, 8, 9, 9, 9, 9,10, 9, 8, 8, 8,
+ 9, 9,10,10,10,10,10,10, 8, 8, 8, 9, 9, 9, 9,10,
+ 10,10,10, 8, 8, 8, 9, 9, 9,10,10,10,10,10, 8, 8,
+ 8, 9, 9,10,10,10,10,10,10,
+};
+
+static const static_codebook _16u1__p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__16u1__p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16u1__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p8_0[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__16u1__p8_0[] = {
+ 1, 4, 4, 5, 5, 8, 8,10,10,12,12, 4, 7, 7, 8, 8,
+ 9, 9,12,11,14,13, 4, 7, 7, 7, 8, 9,10,11,11,13,
+ 12, 5, 8, 8, 9, 9,11,11,12,13,15,14, 5, 7, 8, 9,
+ 9,11,11,13,13,17,15, 8, 9,10,11,11,12,13,17,14,
+ 17,16, 8,10, 9,11,11,12,12,13,15,15,17,10,11,11,
+ 12,13,14,15,15,16,16,17, 9,11,11,12,12,14,15,17,
+ 15,15,16,11,14,12,14,15,16,15,16,16,16,15,11,13,
+ 13,14,14,15,15,16,16,15,16,
+};
+
+static const static_codebook _16u1__p8_0 = {
+ 2, 121,
+ (char *)_vq_lengthlist__16u1__p8_0,
+ 1, -524582912, 1618345984, 4, 0,
+ (long *)_vq_quantlist__16u1__p8_0,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p8_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__16u1__p8_1[] = {
+ 2, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 4, 6, 6, 7, 7,
+ 8, 7, 8, 8, 8, 8, 4, 6, 6, 7, 7, 7, 7, 8, 8, 8,
+ 8, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 6, 7, 7, 7,
+ 7, 8, 8, 8, 8, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9,
+ 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 8, 8, 8,
+ 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 8, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9, 8, 8,
+ 8, 9, 9, 9, 9, 9, 9, 9, 9,
+};
+
+static const static_codebook _16u1__p8_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__16u1__p8_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16u1__p8_1,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p9_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__16u1__p9_0[] = {
+ 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8,
+};
+
+static const static_codebook _16u1__p9_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__16u1__p9_0,
+ 1, -514071552, 1627381760, 4, 0,
+ (long *)_vq_quantlist__16u1__p9_0,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p9_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__16u1__p9_1[] = {
+ 1, 6, 5, 9, 9,10,10, 6, 7, 9, 9,10,10,10,10, 5,
+ 10, 8,10, 8,10,10, 8, 8,10, 9,10,10,10,10, 5, 8,
+ 9,10,10,10,10, 8,10,10,10,10,10,10,10, 9,10,10,
+ 10,10,10,10, 9, 9,10,10,10,10,10,10, 9, 9, 8, 9,
+ 10,10,10, 9,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10, 8,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10, 6, 8, 8,10,10,10, 8,
+ 10,10,10,10,10,10,10,10, 5, 8, 8,10,10,10, 9, 9,
+ 10,10,10,10,10,10,10,10, 9,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9,
+};
+
+static const static_codebook _16u1__p9_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__16u1__p9_1,
+ 1, -522338304, 1620115456, 4, 0,
+ (long *)_vq_quantlist__16u1__p9_1,
+ 0
+};
+
+static const long _vq_quantlist__16u1__p9_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__16u1__p9_2[] = {
+ 1, 6, 6, 7, 8, 8,11,10, 9, 9,11, 9,10, 9,11,11,
+ 9, 6, 7, 6,11, 8,11, 9,10,10,11, 9,11,10,10,10,
+ 11, 9, 5, 7, 7, 8, 8,10,11, 8, 8,11, 9, 9,10,11,
+ 9,10,11, 8, 9, 6, 8, 8, 9, 9,10,10,11,11,11, 9,
+ 11,10, 9,11, 8, 8, 8, 9, 8, 9,10,11, 9, 9,11,11,
+ 10, 9, 9,11,10, 8,11, 8, 9, 8,11, 9,10, 9,10,11,
+ 11,10,10, 9,10,10, 8, 8, 9,10,10,10, 9,11, 9,10,
+ 11,11,11,11,10, 9,11, 9, 9,11,11,10, 8,11,11,11,
+ 9,10,10,11,10,11,11, 9,11,10, 9,11,10,10,10,10,
+ 9,11,10,11,10, 9, 9,10,11, 9, 8,10,11,11,10,10,
+ 11, 9,11,10,11,11,10,11, 9, 9, 8,10, 8, 9,11, 9,
+ 8,10,10, 9,11,10,11,10,11, 9,11, 8,10,11,11,11,
+ 11,10,10,11,11,11,11,10,11,11,10, 9, 8,10,10, 9,
+ 11,10,11,11,11, 9, 9, 9,11,11,11,10,10, 9, 9,10,
+ 9,11,11,11,11, 8,10,11,10,11,11,10,11,11, 9, 9,
+ 9,10, 9,11, 9,11,11,11,11,11,10,11,11,10,11,10,
+ 11,11, 9,11,10,11,10, 9,10, 9,10,10,11,11,11,11,
+ 9,10, 9,10,11,11,10,11,11,11,11,11,11,10,11,11,
+ 10,
+};
+
+static const static_codebook _16u1__p9_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__16u1__p9_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__16u1__p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__16u1__short[] = {
+ 5, 7,10, 9,11,10,15,11,13,16, 6, 4, 6, 6, 7, 7,
+ 10, 9,12,16,10, 6, 5, 6, 6, 7,10,11,16,16, 9, 6,
+ 7, 6, 7, 7,10, 8,14,16,11, 6, 5, 4, 5, 6, 8, 9,
+ 15,16, 9, 6, 6, 5, 6, 6, 9, 8,14,16,12, 7, 6, 6,
+ 5, 6, 6, 7,13,16, 8, 6, 7, 6, 5, 5, 4, 4,11,16,
+ 9, 8, 9, 9, 7, 7, 6, 5,13,16,14,14,16,15,16,15,
+ 16,16,16,16,
+};
+
+static const static_codebook _huff_book__16u1__short = {
+ 2, 100,
+ (char *)_huff_lengthlist__16u1__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__16u2__long[] = {
+ 5, 8,10,10,10,11,11,12,14,18, 7, 5, 5, 6, 8, 9,
+ 10,12,14,17, 9, 5, 4, 5, 6, 8,10,11,13,19, 9, 5,
+ 4, 4, 5, 6, 9,10,12,17, 8, 6, 5, 4, 4, 5, 7,10,
+ 11,15, 8, 7, 7, 6, 5, 5, 6, 9,11,14, 8, 9, 8, 7,
+ 6, 5, 6, 7,11,14, 9,11,11, 9, 7, 6, 6, 6, 9,14,
+ 11,14,15,13, 9, 8, 7, 7, 9,14,13,15,19,17,12,11,
+ 10, 9,10,14,
+};
+
+static const static_codebook _huff_book__16u2__long = {
+ 2, 100,
+ (char *)_huff_lengthlist__16u2__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16u2_p1_0[] = {
+ 1, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 9, 9, 7,
+ 9, 9, 5, 7, 7, 7, 9, 9, 8, 9, 9, 5, 7, 7, 8, 9,
+ 9, 7, 9, 9, 7, 9, 9, 9,10,11, 9,10,10, 7, 9, 9,
+ 9,10, 9, 9,10,11, 5, 8, 7, 7, 9, 9, 8, 9, 9, 7,
+ 9, 9, 9,11,10, 9, 9,10, 7, 9, 9, 9,10,10, 9,11,
+ 10,
+};
+
+static const static_codebook _16u2_p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16u2_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__16u2_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16u2_p2_0[] = {
+ 3, 5, 5, 8, 8, 5, 7, 7, 9, 9, 5, 7, 7, 9, 9, 9,
+ 10, 9,11,11, 9, 9, 9,11,11, 5, 7, 7, 9, 9, 7, 8,
+ 8,10,10, 7, 8, 8,10,10,10,10,10,12,12, 9,10,10,
+ 11,12, 5, 7, 7, 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,
+ 10, 9,10,10,12,11,10,10,10,12,12, 9,10,10,12,12,
+ 10,10,10,12,12, 9,10,10,12,12,12,12,12,14,14,11,
+ 12,12,13,14, 9,10,10,12,12, 9,10,10,12,12,10,10,
+ 10,12,12,11,12,12,14,13,12,12,12,14,13, 5, 7, 7,
+ 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12,
+ 12,10,10,10,12,12, 7, 8, 8,11,10, 8, 9, 9,11,11,
+ 8, 9, 9,11,11,10,11,11,12,13,10,11,11,12,13, 7,
+ 8, 8,10,10, 8, 9, 8,11,10, 8, 9, 9,11,11,10,11,
+ 10,13,12,10,11,11,13,13,10,11,10,13,12,10,11,11,
+ 13,13,10,11,11,13,13,12,12,13,13,14,12,13,13,14,
+ 14, 9,10,10,12,12,10,11,10,13,12,10,11,11,13,13,
+ 12,13,12,14,13,12,13,13,14,15, 5, 7, 7, 9,10, 7,
+ 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12,12,10,10,
+ 11,12,12, 7, 8, 8,10,10, 8, 9, 9,11,11, 8, 8, 9,
+ 10,11,10,11,11,13,13,10,10,11,12,13, 7, 8, 8,10,
+ 10, 8, 9, 9,11,11, 8, 9, 9,11,11,10,11,11,13,12,
+ 10,11,11,13,12, 9,10,10,12,12,10,11,11,13,13,10,
+ 10,11,12,13,12,13,13,15,14,12,12,13,12,14, 9,10,
+ 11,12,13,10,11,11,13,13,10,11,11,13,13,12,13,13,
+ 14,14,12,13,12,14,13, 8,10,10,12,12, 9,11,10,13,
+ 12, 9,10,10,12,13,12,13,13,14,14,12,12,12,14,14,
+ 9,10,10,13,13,10,11,11,13,13,10,11,11,13,13,13,
+ 13,13,14,15,12,13,13,14,15, 9,10,10,12,13,10,11,
+ 10,13,13,10,11,11,12,13,12,13,12,15,14,12,13,13,
+ 14,15,11,12,12,15,14,12,12,13,14,15,12,13,13,15,
+ 14,13,13,15,14,16,14,14,14,16,15,11,12,12,14,14,
+ 11,12,12,14,14,12,13,13,14,15,13,14,13,15,13,14,
+ 14,14,15,16, 8, 9,10,12,12, 9,10,10,13,12, 9,10,
+ 11,12,13,12,12,12,14,14,12,13,13,14,14, 9,10,10,
+ 13,12,10,11,11,13,13,10,10,11,13,13,12,13,13,15,
+ 14,12,12,13,14,15, 9,10,10,13,13,10,11,11,13,13,
+ 10,11,11,13,13,12,13,13,14,14,13,13,13,15,15,11,
+ 12,12,14,13,12,13,13,15,14,11,12,12,14,14,14,14,
+ 14,16,15,13,13,14,13,16,11,12,12,14,14,12,13,13,
+ 14,15,12,13,12,14,14,14,14,14,16,16,14,15,13,16,
+ 14,
+};
+
+static const static_codebook _16u2_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__16u2_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16u2_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__16u2_p3_0[] = {
+ 2, 4, 4, 6, 6, 7, 7, 9, 9, 4, 5, 5, 6, 6, 8, 7,
+ 9, 9, 4, 5, 5, 6, 6, 7, 8, 9, 9, 6, 6, 6, 7, 7,
+ 8, 8,10,10, 6, 6, 6, 7, 7, 8, 8,10,10, 7, 8, 7,
+ 8, 8, 9, 9,11,10, 7, 7, 8, 8, 8, 9, 9,10,11, 9,
+ 9, 9,10,10,11,10,11,11, 9, 9, 9,10,10,10,11,11,
+ 11,
+};
+
+static const static_codebook _16u2_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__16u2_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16u2_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p4_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__16u2_p4_0[] = {
+ 2, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,11,
+ 11, 5, 5, 5, 7, 6, 8, 7, 9, 9, 9, 9,10,10,11,11,
+ 12,12, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9, 9,10,10,11,
+ 11,12,12, 6, 7, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,12,12, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,12,12, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,11,11,12,12, 7, 7, 8, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,11,11,12,12, 8, 9, 9, 9, 9, 9, 9,10,10,
+ 10,10,11,11,12,12,12,12, 8, 9, 9, 9, 9, 9, 9,10,
+ 10,10,10,11,11,12,12,12,12, 9, 9, 9, 9, 9,10,10,
+ 10,10,10,11,11,11,12,12,13,13, 9, 9, 9, 9, 9,10,
+ 10,10,10,11,10,11,11,12,12,13,13,10,10,10,10,10,
+ 11,11,11,11,11,11,11,12,12,12,13,13,10,10,10,10,
+ 10,11,11,11,11,11,11,12,11,12,12,13,13,11,11,11,
+ 11,11,11,11,12,12,12,12,12,12,13,13,13,13,11,11,
+ 11,11,11,11,11,12,12,12,12,13,12,13,13,13,13,11,
+ 12,12,12,12,12,12,12,12,13,13,13,13,13,13,14,14,
+ 11,12,12,12,12,12,12,12,13,13,13,13,13,13,13,14,
+ 14,
+};
+
+static const static_codebook _16u2_p4_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__16u2_p4_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__16u2_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p5_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__16u2_p5_0[] = {
+ 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 8, 7, 9, 9, 7,
+ 9,10, 5, 8, 8, 7,10, 9, 7,10, 9, 5, 8, 8, 8,11,
+ 10, 8,10,10, 7,10,10, 9, 9,12,10,12,12, 7,10,10,
+ 9,12,10,10,11,12, 5, 8, 8, 8,10,10, 8,11,11, 7,
+ 11,10,10,12,11, 9,10,12, 7,10,11,10,12,12, 9,12,
+ 9,
+};
+
+static const static_codebook _16u2_p5_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__16u2_p5_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__16u2_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p5_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__16u2_p5_1[] = {
+ 2, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 5, 6, 6, 7, 7,
+ 7, 7, 8, 8, 8, 8, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8,
+ 8, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 6, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8,
+ 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 9, 9, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 8, 8,
+ 8, 8, 8, 8, 8, 9, 9, 9, 9,
+};
+
+static const static_codebook _16u2_p5_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__16u2_p5_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16u2_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__16u2_p6_0[] = {
+ 1, 5, 4, 7, 7, 8, 8, 8, 8,10,10,11,11, 4, 6, 6,
+ 7, 7, 9, 9, 9, 9,10,10,11,11, 4, 6, 6, 7, 7, 9,
+ 9, 9, 9,10,10,11,11, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,12,12, 7, 7, 7, 9, 8,10, 9,10,10,11,11,12,
+ 12, 8, 9, 9, 9,10,10,10,11,11,12,12,13,13, 8, 9,
+ 9,10, 9,10,10,11,11,12,12,13,13, 8, 9, 9,10,10,
+ 11,11,11,11,12,12,13,13, 8, 9, 9,10,10,11,11,12,
+ 11,12,12,13,13,10,10,10,11,11,12,12,12,12,13,13,
+ 14,14,10,10,10,11,11,12,12,12,12,13,13,14,14,11,
+ 11,11,12,12,13,13,13,13,14,14,14,14,11,11,11,12,
+ 12,13,13,13,13,14,14,14,14,
+};
+
+static const static_codebook _16u2_p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__16u2_p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__16u2_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__16u2_p6_1[] = {
+ 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _16u2_p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__16u2_p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__16u2_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__16u2_p7_0[] = {
+ 1, 4, 4, 7, 7, 8, 8, 8, 8, 9, 9,10,10, 4, 6, 6,
+ 8, 8, 9, 9, 9, 9,10,10,11,10, 4, 6, 6, 8, 8, 9,
+ 9, 9, 9,10,10,11,11, 7, 8, 8,10, 9,10,10,10,10,
+ 11,11,12,12, 7, 8, 8,10,10,10,10,10,10,11,11,12,
+ 12, 8, 9, 9,10,10,11,11,11,11,12,12,13,13, 8, 9,
+ 9,10,10,11,11,11,11,12,12,13,13, 8, 9, 9,11,10,
+ 11,11,12,12,13,13,14,13, 8, 9, 9,10,10,11,11,12,
+ 12,13,13,13,13, 9,10,10,11,11,12,12,13,13,13,13,
+ 14,14, 9,10,10,11,11,12,12,13,13,13,13,14,14,10,
+ 11,11,12,12,13,13,14,13,14,14,15,14,10,11,11,12,
+ 12,13,13,14,13,14,14,15,14,
+};
+
+static const static_codebook _16u2_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__16u2_p7_0,
+ 1, -523206656, 1618345984, 4, 0,
+ (long *)_vq_quantlist__16u2_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__16u2_p7_1[] = {
+ 2, 5, 5, 7, 7, 7, 7, 7, 7, 8, 8, 5, 6, 6, 7, 7,
+ 7, 7, 8, 8, 8, 8, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8,
+ 8, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8,
+ 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _16u2_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__16u2_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__16u2_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p8_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__16u2_p8_0[] = {
+ 1, 4, 4, 7, 7, 8, 8, 7, 7, 9, 8,10, 9,11,11, 4,
+ 7, 6, 9, 8, 9, 9, 9, 9,10, 9,11, 9,12, 9, 4, 6,
+ 7, 8, 8, 9, 9, 9, 9,10,10,10,11,11,12, 7, 9, 8,
+ 10,10,11,11,10,10,11,11,12,12,13,12, 7, 8, 8,10,
+ 10,10,11,10,10,11,11,11,12,12,13, 8, 9, 9,11,11,
+ 11,11,11,11,12,12,13,13,13,13, 8, 9, 9,11,11,11,
+ 11,11,11,12,12,13,13,13,14, 8, 9, 9,10,10,11,11,
+ 12,11,13,13,14,13,14,14, 8, 9, 9,10,10,11,11,12,
+ 12,12,12,13,13,14,14, 9,10,10,11,11,12,12,13,12,
+ 13,13,14,14,15,15, 9,10,10,11,11,12,12,12,13,13,
+ 13,14,14,14,15,10,11,11,12,12,13,13,14,13,14,14,
+ 15,14,15,15,10,11,11,12,12,13,12,13,14,14,14,14,
+ 14,15,15,11,12,12,13,13,13,13,14,14,15,14,15,15,
+ 16,16,11,12,12,13,13,13,13,14,14,14,15,15,15,16,
+ 16,
+};
+
+static const static_codebook _16u2_p8_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__16u2_p8_0,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__16u2_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p8_1[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__16u2_p8_1[] = {
+ 3, 5, 5, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10,10,10, 5, 6, 6, 7, 7, 8,
+ 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7,
+ 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9,10,10,10,10,
+ 10,10,10,10, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9,10, 9,10,10,10, 9,10, 9, 8, 8, 8, 9, 8, 9, 9,
+ 9, 9,10, 9,10,10,10,10,10,10,10,10,10,10, 8, 8,
+ 8, 8, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,
+ 10,10,10, 8, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,
+ 10,10,10,10,10,10,10,10, 8, 9, 9, 9, 9, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9,
+ 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9,
+ 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10, 9, 9, 9,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10, 9, 9,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10, 9,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10, 9,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10, 9,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _16u2_p8_1 = {
+ 2, 441,
+ (char *)_vq_lengthlist__16u2_p8_1,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__16u2_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p9_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__16u2_p9_0[] = {
+ 1, 5, 3, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5,
+ 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 7,
+ 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _16u2_p9_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__16u2_p9_0,
+ 1, -510036736, 1631393792, 4, 0,
+ (long *)_vq_quantlist__16u2_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p9_1[] = {
+ 9,
+ 8,
+ 10,
+ 7,
+ 11,
+ 6,
+ 12,
+ 5,
+ 13,
+ 4,
+ 14,
+ 3,
+ 15,
+ 2,
+ 16,
+ 1,
+ 17,
+ 0,
+ 18,
+};
+
+static const char _vq_lengthlist__16u2_p9_1[] = {
+ 1, 4, 4, 7, 7, 7, 7, 7, 6, 9, 7,10, 8,12,12,13,
+ 13,14,14, 4, 7, 7, 9, 9, 9, 8, 9, 8,10, 9,11, 9,
+ 14, 9,14,10,13,11, 4, 7, 7, 9, 9, 9, 9, 8, 9,10,
+ 10,11,11,12,13,12,13,14,15, 7, 9, 9,10,11,10,10,
+ 10,10,11,12,13,13,13,14,17,14,15,16, 7, 9, 9,10,
+ 10,10,10,10,10,11,12,13,13,14,14,15,15,18,18, 8,
+ 9, 9,11,10,11,11,11,12,13,12,14,14,16,15,15,17,
+ 18,15, 8, 9, 9,10,10,11,11,11,11,13,13,14,14,15,
+ 15,15,16,16,18, 7, 9, 8,10,10,11,11,12,12,14,14,
+ 15,15,16,16,15,17,16,18, 8, 9, 9,10,10,11,12,12,
+ 12,13,13,16,15,17,16,17,18,17,18, 9,10,10,12,11,
+ 13,13,14,13,14,14,15,17,16,18,17,18,17,18, 9,10,
+ 10,12,11,12,13,13,14,15,16,14,15,16,18,18,18,18,
+ 17,11,11,11,13,13,14,14,16,15,15,15,16,15,15,18,
+ 18,18,17,16,11,11,12,13,13,15,14,15,16,16,16,17,
+ 16,15,18,17,18,16,18,12,13,13,15,15,15,16,18,16,
+ 17,16,17,16,17,17,17,18,18,17,13,13,13,15,13,16,
+ 15,17,16,16,16,18,18,18,18,16,17,17,18,13,15,14,
+ 15,15,18,17,18,18,18,16,18,17,18,17,18,16,17,17,
+ 14,14,14,15,16,17,16,18,18,18,17,18,17,18,18,18,
+ 16,16,16,14,17,16,17,15,16,18,18,17,18,17,18,17,
+ 18,18,18,17,18,17,15,16,15,18,15,18,17,16,18,18,
+ 18,18,18,18,17,18,16,18,17,
+};
+
+static const static_codebook _16u2_p9_1 = {
+ 2, 361,
+ (char *)_vq_lengthlist__16u2_p9_1,
+ 1, -518287360, 1622704128, 5, 0,
+ (long *)_vq_quantlist__16u2_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__16u2_p9_2[] = {
+ 24,
+ 23,
+ 25,
+ 22,
+ 26,
+ 21,
+ 27,
+ 20,
+ 28,
+ 19,
+ 29,
+ 18,
+ 30,
+ 17,
+ 31,
+ 16,
+ 32,
+ 15,
+ 33,
+ 14,
+ 34,
+ 13,
+ 35,
+ 12,
+ 36,
+ 11,
+ 37,
+ 10,
+ 38,
+ 9,
+ 39,
+ 8,
+ 40,
+ 7,
+ 41,
+ 6,
+ 42,
+ 5,
+ 43,
+ 4,
+ 44,
+ 3,
+ 45,
+ 2,
+ 46,
+ 1,
+ 47,
+ 0,
+ 48,
+};
+
+static const char _vq_lengthlist__16u2_p9_2[] = {
+ 2, 3, 4, 4, 4, 5, 5, 6, 5, 6, 6, 6, 6, 6, 6, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 7, 8, 8, 8, 8, 8,
+ 8,
+};
+
+static const static_codebook _16u2_p9_2 = {
+ 1, 49,
+ (char *)_vq_lengthlist__16u2_p9_2,
+ 1, -526909440, 1611661312, 6, 0,
+ (long *)_vq_quantlist__16u2_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__16u2__short[] = {
+ 8,11,13,13,15,16,19,19,19,19,11, 8, 8, 9, 9,11,
+ 13,15,19,20,14, 8, 7, 7, 8, 9,12,13,15,20,15, 9,
+ 6, 5, 5, 7,10,12,14,18,14, 9, 7, 5, 3, 4, 7,10,
+ 12,16,13,10, 8, 6, 3, 3, 5, 8,11,14,11,10, 9, 7,
+ 5, 4, 4, 6,11,14,10,10,10, 8, 6, 5, 5, 6,10,14,
+ 10,10,10, 9, 8, 7, 7, 7,10,14,11,12,12,12,11,10,
+ 10,10,12,16,
+};
+
+static const static_codebook _huff_book__16u2__short = {
+ 2, 100,
+ (char *)_huff_lengthlist__16u2__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__8u0__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__8u0__p1_0[] = {
+ 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 8, 8,10,10, 7,
+ 10,10, 5, 8, 8, 7,10,10, 8,10,10, 4, 9, 8, 8,11,
+ 11, 8,11,11, 7,11,11,10,11,13,10,13,13, 7,11,11,
+ 10,13,12,10,13,13, 5, 9, 8, 8,11,11, 8,11,11, 7,
+ 11,11, 9,13,13,10,12,13, 7,11,11,10,13,13,10,13,
+ 11,
+};
+
+static const static_codebook _8u0__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__8u0__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__8u0__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__8u0__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__8u0__p2_0[] = {
+ 2, 4, 4, 5, 6, 6, 5, 6, 6, 5, 7, 7, 6, 7, 8, 6,
+ 7, 8, 5, 7, 7, 6, 8, 8, 7, 9, 7, 5, 7, 7, 7, 9,
+ 9, 7, 8, 8, 6, 9, 8, 7, 7,10, 8,10,10, 6, 8, 8,
+ 8,10, 8, 8,10,10, 5, 7, 7, 7, 8, 8, 7, 8, 9, 6,
+ 8, 8, 8,10,10, 8, 8,10, 6, 8, 9, 8,10,10, 7,10,
+ 8,
+};
+
+static const static_codebook _8u0__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__8u0__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__8u0__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__8u0__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__8u0__p3_0[] = {
+ 1, 5, 5, 7, 7, 6, 7, 7, 9, 9, 6, 7, 7, 9, 9, 8,
+ 10, 9,11,11, 8, 9, 9,11,11, 6, 8, 8,10,10, 8,10,
+ 10,11,11, 8,10,10,11,11,10,11,11,12,12,10,11,11,
+ 12,13, 6, 8, 8,10,10, 8,10,10,11,11, 8,10,10,11,
+ 11, 9,10,11,12,12,10,11,11,12,12, 8,11,11,14,13,
+ 10,12,11,15,13,10,12,11,14,14,12,13,12,16,14,12,
+ 14,12,16,15, 8,11,11,13,14,10,11,12,13,15,10,11,
+ 12,13,15,11,12,13,14,15,12,12,14,14,16, 5, 8, 8,
+ 11,11, 9,11,11,12,12, 8,10,11,12,12,11,12,12,15,
+ 14,11,12,12,14,14, 7,11,10,13,12,10,11,12,13,14,
+ 10,12,12,14,13,12,13,13,14,15,12,13,13,15,15, 7,
+ 10,11,12,13,10,12,11,14,13,10,12,13,13,15,12,13,
+ 12,14,14,11,13,13,15,16, 9,12,12,15,14,11,13,13,
+ 15,16,11,13,13,16,16,13,14,15,15,15,12,14,15,17,
+ 16, 9,12,12,14,15,11,13,13,15,16,11,13,13,16,18,
+ 13,14,14,17,16,13,15,15,17,18, 5, 8, 9,11,11, 8,
+ 11,11,12,12, 8,10,11,12,12,11,12,12,14,14,11,12,
+ 12,14,15, 7,11,10,12,13,10,12,12,14,13,10,11,12,
+ 13,14,11,13,13,15,14,12,13,13,14,15, 7,10,11,13,
+ 13,10,12,12,13,14,10,12,12,13,13,11,13,13,16,16,
+ 12,13,13,15,14, 9,12,12,16,15,10,13,13,15,15,11,
+ 13,13,17,15,12,15,15,18,17,13,14,14,15,16, 9,12,
+ 12,15,15,11,13,13,15,16,11,13,13,15,15,12,15,15,
+ 16,16,13,15,14,17,15, 7,11,11,15,15,10,13,13,16,
+ 15,10,13,13,15,16,14,15,15,17,19,13,15,14,15,18,
+ 9,12,12,16,16,11,13,14,17,16,11,13,13,17,16,15,
+ 15,16,17,19,13,15,16, 0,18, 9,12,12,16,15,11,14,
+ 13,17,17,11,13,14,16,16,15,16,16,19,18,13,15,15,
+ 17,19,11,14,14,19,16,12,14,15, 0,18,12,16,15,18,
+ 17,15,15,18,16,19,14,15,17,19,19,11,14,14,18,19,
+ 13,15,14,19,19,12,16,15,18,17,15,17,15, 0,16,14,
+ 17,16,19, 0, 7,11,11,14,14,10,12,12,15,15,10,13,
+ 13,16,15,13,15,15,17, 0,14,15,15,16,19, 9,12,12,
+ 16,16,11,14,14,16,16,11,13,13,16,16,14,17,16,19,
+ 0,14,18,17,17,19, 9,12,12,15,16,11,13,13,15,17,
+ 12,14,13,19,16,13,15,15,17,19,15,17,16,17,19,11,
+ 14,14,19,16,12,15,15,19,17,13,14,15,17,19,14,16,
+ 17,19,19,16,15,16,17,19,11,15,14,16,16,12,15,15,
+ 19, 0,12,14,15,19,19,14,16,16, 0,18,15,19,14,18,
+ 16,
+};
+
+static const static_codebook _8u0__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__8u0__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__8u0__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__8u0__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__8u0__p4_0[] = {
+ 3, 5, 5, 8, 8, 5, 6, 7, 9, 9, 6, 7, 6, 9, 9, 9,
+ 9, 9,10,11, 9, 9, 9,11,10, 6, 7, 7,10,10, 7, 7,
+ 8,10,10, 7, 8, 8,10,10,10,10,10,10,11, 9,10,10,
+ 11,12, 6, 7, 7,10,10, 7, 8, 8,10,10, 7, 8, 7,10,
+ 10, 9,10,10,12,11,10,10,10,11,10, 9,10,10,12,11,
+ 10,10,10,13,11, 9,10,10,12,12,11,11,12,12,13,11,
+ 11,11,12,13, 9,10,10,12,12,10,10,11,12,12,10,10,
+ 11,12,12,11,11,11,13,13,11,12,12,13,13, 5, 7, 7,
+ 10,10, 7, 8, 8,10,10, 7, 8, 8,10,10,10,11,11,12,
+ 12,10,11,10,12,12, 7, 8, 8,11,11, 7, 8, 9,10,11,
+ 8, 9, 9,11,11,11,10,11,10,12,10,11,11,12,13, 7,
+ 8, 8,10,11, 8, 9, 8,12,10, 8, 9, 9,11,12,10,11,
+ 10,13,11,10,11,11,13,12, 9,11,10,13,12,10,10,11,
+ 12,12,10,11,11,13,13,12,10,13,11,14,11,12,12,15,
+ 13, 9,11,11,13,13,10,11,11,13,12,10,11,11,12,14,
+ 12,13,11,14,12,12,12,12,14,14, 5, 7, 7,10,10, 7,
+ 8, 8,10,10, 7, 8, 8,11,10,10,11,11,12,12,10,11,
+ 10,12,12, 7, 8, 8,10,11, 8, 9, 9,12,11, 8, 8, 9,
+ 10,11,10,11,11,12,13,11,10,11,11,13, 6, 8, 8,10,
+ 11, 8, 9, 9,11,11, 7, 9, 7,11,10,10,11,11,12,12,
+ 10,11,10,13,10, 9,11,10,13,12,10,12,11,13,13,10,
+ 10,11,12,13,11,12,13,15,14,11,11,13,12,13, 9,10,
+ 11,12,13,10,11,11,12,13,10,11,10,13,12,12,13,13,
+ 13,14,12,12,11,14,11, 8,10,10,12,13,10,11,11,13,
+ 13,10,11,10,13,13,12,13,14,15,14,12,12,12,14,13,
+ 9,10,10,13,12,10,10,12,13,13,10,11,11,15,12,12,
+ 12,13,15,14,12,13,13,15,13, 9,10,11,12,13,10,12,
+ 10,13,12,10,11,11,12,13,12,14,12,15,13,12,12,12,
+ 15,14,11,12,11,14,13,11,11,12,14,14,12,13,13,14,
+ 13,13,11,15,11,15,14,14,14,16,15,11,12,12,13,14,
+ 11,13,11,14,14,12,12,13,14,15,12,14,12,15,12,13,
+ 15,14,16,15, 8,10,10,12,12,10,10,10,12,13,10,11,
+ 11,13,13,12,12,12,13,14,13,13,13,15,15, 9,10,10,
+ 12,12,10,11,11,13,12,10,10,11,13,13,12,12,12,14,
+ 14,12,12,13,15,14, 9,10,10,13,12,10,10,12,12,13,
+ 10,11,10,13,13,12,13,13,14,14,12,13,12,14,13,11,
+ 12,12,14,13,12,13,12,14,14,10,12,12,14,14,14,14,
+ 14,16,14,13,12,14,12,15,10,12,12,14,15,12,13,13,
+ 14,16,11,12,11,15,14,13,14,14,14,15,13,14,11,14,
+ 12,
+};
+
+static const static_codebook _8u0__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__8u0__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__8u0__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__8u0__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__8u0__p5_0[] = {
+ 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 6, 8, 7, 8, 8,
+ 10,10, 4, 6, 6, 8, 8, 8, 8,10,10, 6, 8, 8, 9, 9,
+ 9, 9,11,11, 7, 8, 8, 9, 9, 9, 9,11,11, 7, 8, 8,
+ 9, 9,10,10,12,11, 7, 8, 8, 9, 9,10,10,11,11, 9,
+ 10,10,11,11,11,12,12,12, 9,10,10,11,11,12,12,12,
+ 12,
+};
+
+static const static_codebook _8u0__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__8u0__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__8u0__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__8u0__p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__8u0__p6_0[] = {
+ 1, 4, 4, 7, 7, 9, 9,11,11,12,12,16,16, 3, 6, 6,
+ 9, 9,11,11,12,12,13,14,18,16, 3, 6, 7, 9, 9,11,
+ 11,13,12,14,14,17,16, 7, 9, 9,11,11,12,12,14,14,
+ 14,14,17,16, 7, 9, 9,11,11,13,12,13,13,14,14,17,
+ 0, 9,11,11,12,13,14,14,14,13,15,14,17,17, 9,11,
+ 11,12,12,14,14,13,14,14,15, 0, 0,11,12,12,15,14,
+ 15,14,15,14,15,16,17, 0,11,12,13,13,13,14,14,15,
+ 14,15,15, 0, 0,12,14,14,15,15,14,16,15,15,17,16,
+ 0,18,13,14,14,15,14,15,14,15,16,17,16, 0, 0,17,
+ 17,18, 0,16,18,16, 0, 0, 0,17, 0, 0,16, 0, 0,16,
+ 16, 0,15, 0,17, 0, 0, 0, 0,
+};
+
+static const static_codebook _8u0__p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__8u0__p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__8u0__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__8u0__p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__8u0__p6_1[] = {
+ 1, 4, 4, 6, 6, 4, 6, 5, 7, 7, 4, 5, 6, 7, 7, 6,
+ 7, 7, 7, 7, 6, 7, 7, 7, 7,
+};
+
+static const static_codebook _8u0__p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__8u0__p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__8u0__p6_1,
+ 0
+};
+
+static const long _vq_quantlist__8u0__p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__8u0__p7_0[] = {
+ 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7,
+};
+
+static const static_codebook _8u0__p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__8u0__p7_0,
+ 1, -518803456, 1628680192, 2, 0,
+ (long *)_vq_quantlist__8u0__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__8u0__p7_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__8u0__p7_1[] = {
+ 1, 5, 5, 5, 5,10,10,11,11,11,11,11,11,11,11, 5,
+ 7, 6, 8, 8, 9,10,11,11,11,11,11,11,11,11, 6, 6,
+ 7, 9, 7,11,10,11,11,11,11,11,11,11,11, 5, 6, 6,
+ 11, 8,11,11,11,11,11,11,11,11,11,11, 5, 6, 6, 9,
+ 10,11,10,11,11,11,11,11,11,11,11, 7,10,10,11,11,
+ 11,11,11,11,11,11,11,11,11,11, 7,11, 8,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _8u0__p7_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__8u0__p7_1,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__8u0__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__8u0__p7_2[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__8u0__p7_2[] = {
+ 1, 6, 5, 7, 7, 9, 9, 9, 9,10,12,12,10,11,11,10,
+ 11,11,11,10,11, 6, 8, 8, 9, 9,10,10, 9,10,11,11,
+ 10,11,11,11,11,10,11,11,11,11, 6, 7, 8, 9, 9, 9,
+ 10,11,10,11,12,11,10,11,11,11,11,11,11,12,10, 8,
+ 9, 9,10, 9,10,10, 9,10,10,10,10,10, 9,10,10,10,
+ 10, 9,10,10, 9, 9, 9, 9,10,10, 9, 9,10,10,11,10,
+ 9,12,10,11,10, 9,10,10,10, 8, 9, 9,10, 9,10, 9,
+ 9,10,10, 9,10, 9,11,10,10,10,10,10, 9,10, 8, 8,
+ 9, 9,10, 9,11, 9, 8, 9, 9,10,11,10,10,10,11,12,
+ 9, 9,11, 8, 9, 8,11,10,11,10,10, 9,11,10,10,10,
+ 10,10,10,10,11,11,11,11, 8, 9, 9, 9,10,10,10,11,
+ 11,12,11,12,11,10,10,10,12,11,11,11,10, 8,10, 9,
+ 11,10,10,11,12,10,11,12,11,11,12,11,12,12,10,11,
+ 11,10, 9, 9,10,11,12,10,10,10,11,10,11,11,10,12,
+ 12,10,11,10,11,12,10, 9,10,10,11,10,11,11,11,11,
+ 11,12,11,11,11, 9,11,10,11,10,11,10, 9, 9,10,11,
+ 11,11,10,10,11,12,12,11,12,11,11,11,12,12,12,12,
+ 11, 9,11,11,12,10,11,11,11,11,11,11,12,11,11,12,
+ 11,11,11,10,11,11, 9,11,10,11,11,11,10,10,10,11,
+ 11,11,12,10,11,10,11,11,11,11,12, 9,11,10,11,11,
+ 10,10,11,11, 9,11,11,12,10,10,10,10,10,11,11,10,
+ 9,10,11,11,12,11,10,10,12,11,11,12,11,12,11,11,
+ 10,10,11,11,10,12,11,10,11,10,11,10,10,10,11,11,
+ 10,10,11,11,11,11,10,10,10,12,11,11,11,11,10, 9,
+ 10,11,11,11,12,11,11,11,12,10,11,11,11, 9,10,11,
+ 11,11,11,11,11,10,10,11,11,12,11,10,11,12,11,10,
+ 10,11, 9,10,11,11,11,11,11,10,11,11,10,12,11,11,
+ 11,12,11,11,11,10,10,11,11,
+};
+
+static const static_codebook _8u0__p7_2 = {
+ 2, 441,
+ (char *)_vq_lengthlist__8u0__p7_2,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__8u0__p7_2,
+ 0
+};
+
+static const char _huff_lengthlist__8u0__single[] = {
+ 4, 7,11, 9,12, 8, 7,10, 6, 4, 5, 5, 7, 5, 6,16,
+ 9, 5, 5, 6, 7, 7, 9,16, 7, 4, 6, 5, 7, 5, 7,17,
+ 10, 7, 7, 8, 7, 7, 8,18, 7, 5, 6, 4, 5, 4, 5,15,
+ 7, 6, 7, 5, 6, 4, 5,15,12,13,18,12,17,11, 9,17,
+};
+
+static const static_codebook _huff_book__8u0__single = {
+ 2, 64,
+ (char *)_huff_lengthlist__8u0__single,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__8u1__p1_0[] = {
+ 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 8, 7, 9,10, 7,
+ 9, 9, 5, 8, 8, 7,10, 9, 7, 9, 9, 5, 8, 8, 8,10,
+ 10, 8,10,10, 7,10,10, 9,10,12,10,12,12, 7,10,10,
+ 9,12,11,10,12,12, 5, 8, 8, 8,10,10, 8,10,10, 7,
+ 10,10,10,12,12, 9,11,12, 7,10,10,10,12,12, 9,12,
+ 10,
+};
+
+static const static_codebook _8u1__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__8u1__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__8u1__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__8u1__p2_0[] = {
+ 3, 4, 5, 5, 6, 6, 5, 6, 6, 5, 7, 6, 6, 7, 8, 6,
+ 7, 8, 5, 6, 6, 6, 8, 7, 6, 8, 7, 5, 6, 6, 7, 8,
+ 8, 6, 7, 7, 6, 8, 7, 7, 7, 9, 8, 9, 9, 6, 7, 8,
+ 7, 9, 7, 8, 9, 9, 5, 6, 6, 6, 7, 7, 7, 8, 8, 6,
+ 8, 7, 8, 9, 9, 7, 7, 9, 6, 7, 8, 8, 9, 9, 7, 9,
+ 7,
+};
+
+static const static_codebook _8u1__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__8u1__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__8u1__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__8u1__p3_0[] = {
+ 1, 5, 5, 7, 7, 6, 7, 7, 9, 9, 6, 7, 7, 9, 9, 8,
+ 10, 9,11,11, 9, 9, 9,11,11, 6, 8, 8,10,10, 8,10,
+ 10,11,11, 8, 9,10,11,11,10,11,11,12,12,10,11,11,
+ 12,13, 6, 8, 8,10,10, 8,10, 9,11,11, 8,10, 9,11,
+ 11,10,11,11,12,12,10,11,11,12,12, 9,11,11,14,13,
+ 10,12,11,14,14,10,12,11,14,13,12,13,13,15,14,12,
+ 13,13,15,14, 8,11,11,13,14,10,11,12,13,15,10,11,
+ 12,14,14,12,13,13,14,15,12,13,13,14,15, 5, 8, 8,
+ 11,11, 8,10,10,12,12, 8,10,10,12,12,11,12,12,14,
+ 13,11,12,12,13,14, 8,10,10,12,12, 9,11,12,13,14,
+ 10,12,12,13,13,12,12,13,14,14,11,13,13,15,15, 7,
+ 10,10,12,12, 9,12,11,14,12,10,11,12,13,14,12,13,
+ 12,14,14,12,13,13,15,16,10,12,12,15,14,11,12,13,
+ 15,15,11,13,13,15,16,14,14,15,15,16,13,14,15,17,
+ 15, 9,12,12,14,15,11,13,12,15,15,11,13,13,15,15,
+ 13,14,13,15,14,13,14,14,17, 0, 5, 8, 8,11,11, 8,
+ 10,10,12,12, 8,10,10,12,12,11,12,12,14,14,11,12,
+ 12,14,14, 7,10,10,12,12,10,12,12,13,13, 9,11,12,
+ 12,13,11,12,13,15,15,11,12,13,14,15, 8,10,10,12,
+ 12,10,12,11,13,13,10,12,11,13,13,11,13,13,15,14,
+ 12,13,12,15,13, 9,12,12,14,14,11,13,13,16,15,11,
+ 12,13,16,15,13,14,15,16,16,13,13,15,15,16,10,12,
+ 12,15,14,11,13,13,14,16,11,13,13,15,16,13,15,15,
+ 16,17,13,15,14,16,15, 8,11,11,14,15,10,12,12,15,
+ 15,10,12,12,15,16,14,15,15,16,17,13,14,14,16,16,
+ 9,12,12,15,15,11,13,14,15,17,11,13,13,15,16,14,
+ 15,16,19,17,13,15,15, 0,17, 9,12,12,15,15,11,14,
+ 13,16,15,11,13,13,15,16,15,15,15,18,17,13,15,15,
+ 17,17,11,15,14,18,16,12,14,15,17,17,12,15,15,18,
+ 18,15,15,16,15,19,14,16,16, 0, 0,11,14,14,16,17,
+ 12,15,14,18,17,12,15,15,18,18,15,17,15,18,16,14,
+ 16,16,18,18, 7,11,11,14,14,10,12,12,15,15,10,12,
+ 13,15,15,13,14,15,16,16,14,15,15,18,18, 9,12,12,
+ 15,15,11,13,13,16,15,11,12,13,16,16,14,15,15,17,
+ 16,15,16,16,17,17, 9,12,12,15,15,11,13,13,15,17,
+ 11,14,13,16,15,13,15,15,17,17,15,15,15,18,17,11,
+ 14,14,17,15,12,14,15,17,18,13,13,15,17,17,14,16,
+ 16,19,18,16,15,17,17, 0,11,14,14,17,17,12,15,15,
+ 18, 0,12,15,14,18,16,14,17,17,19, 0,16,18,15, 0,
+ 16,
+};
+
+static const static_codebook _8u1__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__8u1__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__8u1__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__8u1__p4_0[] = {
+ 4, 5, 5, 9, 9, 6, 7, 7, 9, 9, 6, 7, 7, 9, 9, 9,
+ 9, 9,11,11, 9, 9, 9,11,11, 6, 7, 7, 9, 9, 7, 7,
+ 8, 9,10, 7, 7, 8, 9,10, 9, 9,10,10,11, 9, 9,10,
+ 10,12, 6, 7, 7, 9, 9, 7, 8, 7,10, 9, 7, 8, 7,10,
+ 9, 9,10, 9,12,11,10,10, 9,12,10, 9,10,10,12,11,
+ 9,10,10,12,11, 9,10,10,12,12,11,11,12,12,13,11,
+ 11,12,12,13, 9, 9,10,12,11, 9,10,10,12,12,10,10,
+ 10,12,12,11,12,11,13,12,11,12,11,13,12, 6, 7, 7,
+ 9, 9, 7, 8, 8,10,10, 7, 8, 7,10, 9,10,10,10,12,
+ 12,10,10,10,12,11, 7, 8, 7,10,10, 7, 7, 9,10,11,
+ 8, 9, 9,11,10,10,10,11,10,12,10,10,11,12,12, 7,
+ 8, 8,10,10, 7, 9, 8,11,10, 8, 8, 9,11,11,10,11,
+ 10,12,11,10,11,11,12,12, 9,10,10,12,12, 9,10,10,
+ 12,12,10,11,11,13,12,11,10,12,10,14,12,12,12,13,
+ 14, 9,10,10,12,12, 9,11,10,12,12,10,11,11,12,12,
+ 11,12,11,14,12,12,12,12,14,14, 5, 7, 7, 9, 9, 7,
+ 7, 7, 9,10, 7, 8, 8,10,10,10,10,10,11,11,10,10,
+ 10,12,12, 7, 8, 8,10,10, 8, 9, 8,11,10, 7, 8, 9,
+ 10,11,10,10,10,11,12,10,10,11,11,13, 6, 7, 8,10,
+ 10, 8, 9, 9,10,10, 7, 9, 7,11,10,10,11,10,12,12,
+ 10,11,10,12,10, 9,10,10,12,12,10,11,11,13,12, 9,
+ 10,10,12,12,12,12,12,14,13,11,11,12,11,14, 9,10,
+ 10,11,12,10,11,11,12,13, 9,10,10,12,12,12,12,12,
+ 14,13,11,12,10,14,11, 9, 9,10,11,12, 9,10,10,12,
+ 12, 9,10,10,12,12,12,12,12,14,14,11,12,12,13,12,
+ 9,10, 9,12,12, 9,10,11,12,13,10,11,10,13,11,12,
+ 12,13,13,14,12,12,12,13,13, 9,10,10,12,12,10,11,
+ 10,13,12,10,10,11,12,13,12,13,12,14,13,12,12,12,
+ 13,14,11,12,11,14,13,10,10,11,13,13,12,12,12,14,
+ 13,12,10,14,10,15,13,14,14,14,14,11,11,12,13,14,
+ 10,12,11,13,13,12,12,12,13,15,12,13,11,15,12,13,
+ 13,14,14,14, 9,10, 9,12,12, 9,10,10,12,12,10,10,
+ 10,12,12,11,11,12,12,13,12,12,12,14,14, 9,10,10,
+ 12,12,10,11,10,13,12,10,10,11,12,13,12,12,12,14,
+ 13,12,12,13,13,14, 9,10,10,12,13,10,10,11,11,12,
+ 9,11,10,13,12,12,12,12,13,14,12,13,12,14,13,11,
+ 12,11,13,13,12,13,12,14,13,10,11,12,13,13,13,13,
+ 13,14,15,12,11,14,12,14,11,11,12,12,13,12,12,12,
+ 13,14,10,12,10,14,13,13,13,13,14,15,12,14,11,15,
+ 10,
+};
+
+static const static_codebook _8u1__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__8u1__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__8u1__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__8u1__p5_0[] = {
+ 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 5, 8, 7, 8, 8,
+ 10,10, 4, 6, 6, 8, 8, 8, 8,10,10, 7, 8, 8, 9, 9,
+ 9, 9,11,11, 7, 8, 8, 9, 9, 9, 9,11,11, 8, 8, 8,
+ 9, 9,10,10,12,11, 8, 8, 8, 9, 9,10,10,11,11, 9,
+ 10,10,11,11,11,11,13,12, 9,10,10,11,11,12,12,12,
+ 13,
+};
+
+static const static_codebook _8u1__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__8u1__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__8u1__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p6_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__8u1__p6_0[] = {
+ 3, 4, 4, 6, 6, 7, 7, 9, 9, 4, 4, 5, 6, 6, 7, 7,
+ 9, 9, 4, 4, 4, 6, 6, 7, 7, 9, 9, 6, 6, 6, 7, 7,
+ 8, 8, 9, 9, 6, 6, 6, 7, 7, 8, 8, 9, 9, 7, 7, 7,
+ 8, 8, 8, 9,10,10, 7, 7, 7, 8, 8, 9, 8,10,10, 9,
+ 9, 9, 9, 9,10,10,10,10, 9, 9, 9, 9, 9,10,10,10,
+ 10,
+};
+
+static const static_codebook _8u1__p6_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__8u1__p6_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__8u1__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__8u1__p7_0[] = {
+ 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 9, 9, 8,10,10, 8,
+ 10,10, 5, 9, 9, 7,10,10, 8,10,10, 4,10,10, 9,12,
+ 12, 9,11,11, 7,12,11,10,11,13,10,13,13, 7,12,12,
+ 10,13,12,10,13,13, 4,10,10, 9,12,12, 9,12,12, 7,
+ 12,12,10,13,13,10,12,13, 7,11,12,10,13,13,10,13,
+ 11,
+};
+
+static const static_codebook _8u1__p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__8u1__p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__8u1__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__8u1__p7_1[] = {
+ 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 4, 5, 5, 7, 7,
+ 8, 8, 9, 9, 9, 9, 4, 5, 5, 7, 7, 8, 8, 9, 9, 9,
+ 9, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 6, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 8, 9, 9,
+ 9, 9, 9, 9,10,10,10,10, 8, 9, 9, 9, 9, 9, 9,10,
+ 10,10,10, 8, 9, 9, 9, 9, 9, 9,10,10,10,10, 8, 9,
+ 9, 9, 9, 9, 9,10,10,10,10,
+};
+
+static const static_codebook _8u1__p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__8u1__p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__8u1__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p8_0[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__8u1__p8_0[] = {
+ 1, 4, 4, 6, 6, 8, 8,10,10,11,11, 4, 6, 6, 7, 7,
+ 9, 9,11,11,13,12, 4, 6, 6, 7, 7, 9, 9,11,11,12,
+ 12, 6, 7, 7, 9, 9,11,11,12,12,13,13, 6, 7, 7, 9,
+ 9,11,11,12,12,13,13, 8, 9, 9,11,11,12,12,13,13,
+ 14,14, 8, 9, 9,11,11,12,12,13,13,14,14, 9,11,11,
+ 12,12,13,13,14,14,15,15, 9,11,11,12,12,13,13,14,
+ 14,15,14,11,12,12,13,13,14,14,15,15,16,16,11,12,
+ 12,13,13,14,14,15,15,15,15,
+};
+
+static const static_codebook _8u1__p8_0 = {
+ 2, 121,
+ (char *)_vq_lengthlist__8u1__p8_0,
+ 1, -524582912, 1618345984, 4, 0,
+ (long *)_vq_quantlist__8u1__p8_0,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p8_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__8u1__p8_1[] = {
+ 2, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 5, 6, 6, 7, 7,
+ 7, 7, 8, 8, 8, 8, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8,
+ 8, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 6, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8,
+ 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 9,
+ 8, 9, 9, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 8, 8,
+ 8, 8, 8, 8, 8, 9, 9, 9, 9,
+};
+
+static const static_codebook _8u1__p8_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__8u1__p8_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__8u1__p8_1,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p9_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__8u1__p9_0[] = {
+ 1, 4, 4,11,11,11,11,11,11,11,11,11,11,11,11, 3,
+ 11, 8,11,11,11,11,11,11,11,11,11,11,11,11, 3, 9,
+ 9,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _8u1__p9_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__8u1__p9_0,
+ 1, -514071552, 1627381760, 4, 0,
+ (long *)_vq_quantlist__8u1__p9_0,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p9_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__8u1__p9_1[] = {
+ 1, 4, 4, 7, 7, 9, 9, 7, 7, 8, 8,10,10,11,11, 4,
+ 7, 7, 9, 9,10,10, 8, 8,10,10,10,11,10,11, 4, 7,
+ 7, 9, 9,10,10, 8, 8,10, 9,11,11,11,11, 7, 9, 9,
+ 12,12,11,12,10,10,11,10,12,11,11,11, 7, 9, 9,11,
+ 11,13,12, 9, 9,11,10,11,11,12,11, 9,10,10,12,12,
+ 14,14,10,10,11,12,12,11,11,11, 9,10,11,11,13,14,
+ 13,10,11,11,11,12,11,12,12, 7, 8, 8,10, 9,11,10,
+ 11,12,12,11,12,14,12,13, 7, 8, 8, 9,10,10,11,12,
+ 12,12,11,12,12,12,13, 9, 9, 9,11,11,13,12,12,12,
+ 12,11,12,12,13,12, 8,10,10,11,10,11,12,12,12,12,
+ 12,12,14,12,12, 9,11,11,11,12,12,12,12,13,13,12,
+ 12,13,13,12,10,11,11,12,11,12,12,12,11,12,13,12,
+ 12,12,13,11,11,12,12,12,13,12,12,11,12,13,13,12,
+ 12,13,12,11,12,12,13,13,12,13,12,13,13,13,13,14,
+ 13,
+};
+
+static const static_codebook _8u1__p9_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__8u1__p9_1,
+ 1, -522338304, 1620115456, 4, 0,
+ (long *)_vq_quantlist__8u1__p9_1,
+ 0
+};
+
+static const long _vq_quantlist__8u1__p9_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__8u1__p9_2[] = {
+ 2, 5, 4, 6, 6, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 5, 6, 6, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9,10,10, 9, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,10,10, 8, 8, 8, 9, 9, 9, 9,10,10,10, 9,
+ 10,10,10,10,10,10, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9,10,
+ 10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10,10,10,
+ 10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9,10,
+ 10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10,
+ 10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9,
+ 9,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9,10,
+ 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10, 9,
+ 10, 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 9, 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _8u1__p9_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__8u1__p9_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__8u1__p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__8u1__single[] = {
+ 4, 7,13, 9,15, 9,16, 8,10,13, 7, 5, 8, 6, 9, 7,
+ 10, 7,10,11,11, 6, 7, 8, 8, 9, 9, 9,12,16, 8, 5,
+ 8, 6, 8, 6, 9, 7,10,12,11, 7, 7, 7, 6, 7, 7, 7,
+ 11,15, 7, 5, 8, 6, 7, 5, 7, 6, 9,13,13, 9, 9, 8,
+ 6, 6, 5, 5, 9,14, 8, 6, 8, 6, 6, 4, 5, 3, 5,13,
+ 9, 9,11, 8,10, 7, 8, 4, 5,12,11,16,17,15,17,12,
+ 13, 8, 8,15,
+};
+
+static const static_codebook _huff_book__8u1__single = {
+ 2, 100,
+ (char *)_huff_lengthlist__8u1__single,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44u0__long[] = {
+ 5, 8,13,10,17,11,11,15, 7, 2, 4, 5, 8, 7, 9,16,
+ 13, 4, 3, 5, 6, 8,11,20,10, 4, 5, 5, 7, 6, 8,18,
+ 15, 7, 6, 7, 8,10,14,20,10, 6, 7, 6, 9, 7, 8,17,
+ 9, 8,10, 8,10, 5, 4,11,12,17,19,14,16,10, 7,12,
+};
+
+static const static_codebook _huff_book__44u0__long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44u0__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44u0__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u0__p1_0[] = {
+ 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,11,11, 8,
+ 10,10, 5, 8, 8, 8,11,10, 8,11,11, 4, 8, 8, 8,11,
+ 11, 8,11,11, 8,12,11,11,13,13,11,13,14, 7,11,11,
+ 10,13,12,11,13,14, 4, 8, 8, 8,11,11, 8,11,12, 8,
+ 11,11,11,13,13,10,12,13, 8,11,11,11,14,13,11,14,
+ 13,
+};
+
+static const static_codebook _44u0__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u0__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u0__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44u0__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u0__p2_0[] = {
+ 2, 4, 4, 5, 6, 6, 5, 6, 6, 5, 7, 7, 7, 8, 8, 6,
+ 8, 8, 5, 7, 7, 6, 8, 8, 7, 8, 8, 4, 7, 7, 7, 8,
+ 8, 7, 8, 8, 7, 8, 8, 8, 9,10, 8,10,10, 6, 8, 8,
+ 8,10, 8, 8,10,10, 5, 7, 7, 7, 8, 8, 7, 8, 8, 6,
+ 8, 8, 8,10,10, 8, 8,10, 6, 8, 8, 8,10,10, 8,10,
+ 9,
+};
+
+static const static_codebook _44u0__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u0__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u0__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44u0__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u0__p3_0[] = {
+ 1, 5, 5, 8, 8, 5, 8, 7, 9, 9, 5, 7, 8, 9, 9, 9,
+ 10, 9,12,12, 9, 9,10,12,12, 6, 8, 8,11,10, 8,10,
+ 10,11,11, 8, 9,10,11,11,10,11,11,14,13,10,11,11,
+ 13,13, 5, 8, 8,10,10, 8,10,10,11,11, 8,10,10,11,
+ 11,10,11,11,13,13,10,11,11,13,13, 9,11,11,15,14,
+ 10,12,12,15,14,10,12,11,15,14,13,14,14,16,16,12,
+ 14,13,17,15, 9,11,11,14,15,10,11,12,14,16,10,11,
+ 12,14,16,12,13,14,16,16,13,13,15,15,18, 5, 8, 8,
+ 11,11, 8,10,10,12,12, 8,10,10,12,13,11,12,12,14,
+ 14,11,12,12,15,15, 8,10,10,13,13,10,12,12,13,13,
+ 10,12,12,14,14,12,13,13,15,15,12,13,13,16,16, 7,
+ 10,10,12,12,10,12,11,13,13,10,12,12,13,14,12,13,
+ 12,15,14,12,13,13,16,16,10,12,12,17,16,12,13,13,
+ 16,15,11,13,13,17,17,15,15,15,16,17,14,15,15,19,
+ 19,10,12,12,15,16,11,13,12,15,18,11,13,13,16,16,
+ 14,15,15,17,17,14,15,15,17,19, 5, 8, 8,11,11, 8,
+ 10,10,12,12, 8,10,10,12,12,11,12,12,16,15,11,12,
+ 12,14,15, 7,10,10,13,13,10,12,12,14,13,10,11,12,
+ 13,13,12,13,13,16,16,12,12,13,15,15, 8,10,10,13,
+ 13,10,12,12,14,14,10,12,12,13,13,12,13,13,16,16,
+ 12,13,13,15,15,10,12,12,16,15,11,13,13,17,16,11,
+ 12,13,16,15,13,15,15,19,17,14,15,14,17,16,10,12,
+ 12,16,16,11,13,13,16,17,12,13,13,15,17,14,15,15,
+ 17,19,14,15,15,17,17, 8,11,11,16,16,10,13,12,17,
+ 17,10,12,13,16,16,15,17,16,20,19,14,15,17,18,19,
+ 9,12,12,16,17,11,13,14,17,18,11,13,13,19,18,16,
+ 17,18,19,19,15,16,16,19,19, 9,12,12,16,17,11,14,
+ 13,18,17,11,13,13,17,17,16,17,16,20,19,14,16,16,
+ 18,18,12,15,15,19,17,14,15,16, 0,20,13,15,16,20,
+ 17,18,16,20, 0, 0,15,16,19,20, 0,12,15,14,18,19,
+ 13,16,15,20,19,13,16,15,20,18,17,18,17, 0,20,16,
+ 17,16, 0, 0, 8,11,11,16,15,10,12,12,17,17,10,13,
+ 13,17,16,14,16,15,18,20,15,16,16,19,19, 9,12,12,
+ 16,16,11,13,13,17,16,11,13,14,17,18,15,15,16,20,
+ 20,16,16,17,19,19, 9,13,12,16,17,11,14,13,17,17,
+ 11,14,14,18,17,14,16,15,18,19,16,17,18,18,19,12,
+ 14,15,19,18,13,15,16,18, 0,13,14,15, 0, 0,16,16,
+ 17,20, 0,17,17,20,20, 0,12,15,15,19,20,13,15,15,
+ 0, 0,14,16,15, 0, 0,15,18,16, 0, 0,17,18,16, 0,
+ 19,
+};
+
+static const static_codebook _44u0__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u0__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u0__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44u0__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u0__p4_0[] = {
+ 4, 5, 5, 9, 9, 5, 6, 6, 9, 9, 5, 6, 6, 9, 9, 9,
+ 10, 9,12,12, 9, 9,10,12,12, 5, 7, 7,10,10, 7, 7,
+ 8,10,10, 6, 7, 8,10,10,10,10,10,11,13,10, 9,10,
+ 12,13, 5, 7, 7,10,10, 6, 8, 7,10,10, 7, 8, 7,10,
+ 10, 9,10,10,12,12,10,10,10,13,11, 9,10,10,13,13,
+ 10,11,10,13,13,10,10,10,13,13,12,12,13,14,14,12,
+ 12,13,14,14, 9,10,10,13,13,10,10,10,13,13,10,10,
+ 10,13,13,12,13,12,15,14,12,13,12,15,15, 5, 7, 6,
+ 10,10, 7, 8, 8,10,10, 7, 8, 8,10,10,10,11,10,13,
+ 13,10,10,10,12,12, 7, 8, 8,11,10, 8, 8, 9,10,11,
+ 8, 9, 9,11,11,11,10,11,11,14,11,11,11,13,13, 6,
+ 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11,
+ 10,14,11,10,11,11,13,13,10,11,11,14,13,10,10,11,
+ 14,13,10,11,11,14,14,12,11,13,12,16,13,14,14,15,
+ 15,10,10,11,13,14,10,11,10,14,13,10,11,11,14,14,
+ 12,13,12,15,13,13,13,14,15,16, 5, 7, 7,10,10, 7,
+ 8, 8,10,10, 7, 8, 8,10,10,10,10,10,13,13,10,10,
+ 11,12,13, 6, 8, 8,11,10, 8, 9, 9,11,11, 7, 8, 9,
+ 10,11,10,11,11,13,13,10,10,11,11,13, 6, 8, 8,10,
+ 11, 8, 9, 9,11,11, 8, 9, 8,12,10,10,11,11,13,13,
+ 10,11,10,14,11,10,10,10,14,13,10,11,11,14,13,10,
+ 10,11,13,13,12,14,14,16,16,12,12,13,13,15,10,11,
+ 11,13,14,10,11,11,14,15,10,11,10,13,13,13,14,13,
+ 16,16,12,13,11,15,12, 9,10,10,13,13,10,11,11,14,
+ 13,10,10,11,13,14,13,14,13,16,16,13,13,13,15,16,
+ 9,10,10,13,13,10,10,11,13,14,10,11,11,15,13,13,
+ 13,14,14,18,13,13,14,16,15, 9,10,10,13,14,10,11,
+ 10,14,13,10,11,11,13,14,13,14,13,16,15,13,13,14,
+ 15,16,12,13,12,16,14,11,11,13,15,15,13,14,13,16,
+ 15,15,12,16,12,17,14,15,15,17,17,12,13,13,14,16,
+ 11,13,11,16,15,12,13,14,15,16,14,15,13, 0,14,14,
+ 16,16, 0, 0, 9,10,10,13,13,10,11,10,14,14,10,11,
+ 11,13,13,12,13,13,14,16,13,14,14,16,16, 9,10,10,
+ 14,14,11,11,11,14,13,10,10,11,14,14,13,13,13,16,
+ 16,13,13,14,14,17, 9,10,10,13,14,10,11,11,13,15,
+ 10,11,10,14,14,13,13,13,14,17,13,14,13,17,14,12,
+ 13,13,16,14,13,14,13,16,15,12,12,13,15,16,15,15,
+ 16,18,16,15,13,15,14, 0,12,12,13,14,16,13,13,14,
+ 15,16,11,12,11,16,14,15,16,16,17,17,14,15,12,17,
+ 12,
+};
+
+static const static_codebook _44u0__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u0__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u0__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44u0__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u0__p5_0[] = {
+ 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 6, 8, 8, 8, 8,
+ 9, 9, 4, 6, 6, 8, 8, 8, 8, 9, 9, 7, 8, 8, 9, 9,
+ 9, 9,11,10, 7, 8, 8, 9, 9, 9, 9,10,10, 7, 8, 8,
+ 9, 9,10,10,11,11, 7, 8, 8, 9, 9,10,10,11,11, 9,
+ 9, 9,10,10,11,11,12,12, 9, 9, 9,10,11,11,11,12,
+ 12,
+};
+
+static const static_codebook _44u0__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u0__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u0__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44u0__p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u0__p6_0[] = {
+ 1, 4, 4, 6, 6, 8, 8,10, 9,11,10,14,13, 4, 6, 5,
+ 8, 8, 9, 9,11,10,11,11,14,14, 4, 5, 6, 8, 8, 9,
+ 9,10,10,11,11,14,14, 6, 8, 8, 9, 9,10,10,11,11,
+ 12,12,16,15, 7, 8, 8, 9, 9,10,10,11,11,12,12,15,
+ 15, 9,10,10,10,10,11,11,12,12,12,12,15,15, 9,10,
+ 9,10,11,11,11,12,12,12,13,15,15,10,10,11,11,11,
+ 12,12,13,12,13,13,16,15,10,11,11,11,11,12,12,13,
+ 12,13,13,16,17,11,11,12,12,12,13,13,13,14,14,15,
+ 17,17,11,11,12,12,12,13,13,13,14,14,14,16,18,14,
+ 15,15,15,15,16,16,16,16,17,18, 0, 0,14,15,15,15,
+ 15,17,16,17,18,17,17,18, 0,
+};
+
+static const static_codebook _44u0__p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u0__p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44u0__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44u0__p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u0__p6_1[] = {
+ 2, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 5, 6, 6, 6, 6,
+};
+
+static const static_codebook _44u0__p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44u0__p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u0__p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44u0__p7_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u0__p7_0[] = {
+ 1, 4, 4,11,11, 9,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11, 9,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _44u0__p7_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u0__p7_0,
+ 1, -518709248, 1626677248, 3, 0,
+ (long *)_vq_quantlist__44u0__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44u0__p7_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u0__p7_1[] = {
+ 1, 4, 4, 6, 6, 6, 6, 7, 7, 8, 8, 9, 9, 5, 7, 7,
+ 8, 7, 7, 7, 9, 8,10, 9,10,11, 5, 7, 7, 8, 8, 7,
+ 7, 8, 9,10,10,11,11, 6, 8, 8, 9, 9, 9, 9,11,10,
+ 12,12,15,12, 6, 8, 8, 9, 9, 9, 9,11,11,12,11,14,
+ 12, 7, 8, 8,10,10,12,12,13,13,13,15,13,13, 7, 8,
+ 8,10,10,11,11,13,12,14,15,15,15, 9,10,10,11,12,
+ 13,13,14,15,14,15,14,15, 8,10,10,12,12,14,14,15,
+ 14,14,15,15,14,10,12,12,14,14,15,14,15,15,15,14,
+ 15,15,10,12,12,13,14,15,14,15,15,14,15,15,15,12,
+ 15,13,15,14,15,15,15,15,15,15,15,15,13,13,15,15,
+ 15,15,15,15,15,15,15,15,15,
+};
+
+static const static_codebook _44u0__p7_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u0__p7_1,
+ 1, -523010048, 1618608128, 4, 0,
+ (long *)_vq_quantlist__44u0__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44u0__p7_2[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u0__p7_2[] = {
+ 2, 5, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 8, 5, 5, 6,
+ 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 5, 6, 5, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9, 6, 7, 7, 8, 8, 8, 8, 9, 8,
+ 9, 9, 9, 9, 6, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9, 9,
+ 9, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 7, 8,
+ 8, 9, 8, 9, 8, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9,10, 9,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 9, 9, 9, 9, 9,
+ 9, 9, 9,10, 9, 9,10,10, 9,
+};
+
+static const static_codebook _44u0__p7_2 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u0__p7_2,
+ 1, -531103744, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u0__p7_2,
+ 0
+};
+
+static const char _huff_lengthlist__44u0__short[] = {
+ 12,13,14,13,17,12,15,17, 5, 5, 6,10,10,11,15,16,
+ 4, 3, 3, 7, 5, 7,10,16, 7, 7, 7,10, 9,11,12,16,
+ 6, 5, 5, 9, 5, 6,10,16, 8, 7, 7, 9, 6, 7, 9,16,
+ 11, 7, 3, 6, 4, 5, 8,16,12, 9, 4, 8, 5, 7, 9,16,
+};
+
+static const static_codebook _huff_book__44u0__short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44u0__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44u1__long[] = {
+ 5, 8,13,10,17,11,11,15, 7, 2, 4, 5, 8, 7, 9,16,
+ 13, 4, 3, 5, 6, 8,11,20,10, 4, 5, 5, 7, 6, 8,18,
+ 15, 7, 6, 7, 8,10,14,20,10, 6, 7, 6, 9, 7, 8,17,
+ 9, 8,10, 8,10, 5, 4,11,12,17,19,14,16,10, 7,12,
+};
+
+static const static_codebook _huff_book__44u1__long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44u1__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44u1__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u1__p1_0[] = {
+ 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,11,11, 8,
+ 10,10, 5, 8, 8, 8,11,10, 8,11,11, 4, 8, 8, 8,11,
+ 11, 8,11,11, 8,12,11,11,13,13,11,13,14, 7,11,11,
+ 10,13,12,11,13,14, 4, 8, 8, 8,11,11, 8,11,12, 8,
+ 11,11,11,13,13,10,12,13, 8,11,11,11,14,13,11,14,
+ 13,
+};
+
+static const static_codebook _44u1__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u1__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u1__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44u1__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u1__p2_0[] = {
+ 2, 4, 4, 5, 6, 6, 5, 6, 6, 5, 7, 7, 7, 8, 8, 6,
+ 8, 8, 5, 7, 7, 6, 8, 8, 7, 8, 8, 4, 7, 7, 7, 8,
+ 8, 7, 8, 8, 7, 8, 8, 8, 9,10, 8,10,10, 6, 8, 8,
+ 8,10, 8, 8,10,10, 5, 7, 7, 7, 8, 8, 7, 8, 8, 6,
+ 8, 8, 8,10,10, 8, 8,10, 6, 8, 8, 8,10,10, 8,10,
+ 9,
+};
+
+static const static_codebook _44u1__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u1__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u1__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44u1__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u1__p3_0[] = {
+ 1, 5, 5, 8, 8, 5, 8, 7, 9, 9, 5, 7, 8, 9, 9, 9,
+ 10, 9,12,12, 9, 9,10,12,12, 6, 8, 8,11,10, 8,10,
+ 10,11,11, 8, 9,10,11,11,10,11,11,14,13,10,11,11,
+ 13,13, 5, 8, 8,10,10, 8,10,10,11,11, 8,10,10,11,
+ 11,10,11,11,13,13,10,11,11,13,13, 9,11,11,15,14,
+ 10,12,12,15,14,10,12,11,15,14,13,14,14,16,16,12,
+ 14,13,17,15, 9,11,11,14,15,10,11,12,14,16,10,11,
+ 12,14,16,12,13,14,16,16,13,13,15,15,18, 5, 8, 8,
+ 11,11, 8,10,10,12,12, 8,10,10,12,13,11,12,12,14,
+ 14,11,12,12,15,15, 8,10,10,13,13,10,12,12,13,13,
+ 10,12,12,14,14,12,13,13,15,15,12,13,13,16,16, 7,
+ 10,10,12,12,10,12,11,13,13,10,12,12,13,14,12,13,
+ 12,15,14,12,13,13,16,16,10,12,12,17,16,12,13,13,
+ 16,15,11,13,13,17,17,15,15,15,16,17,14,15,15,19,
+ 19,10,12,12,15,16,11,13,12,15,18,11,13,13,16,16,
+ 14,15,15,17,17,14,15,15,17,19, 5, 8, 8,11,11, 8,
+ 10,10,12,12, 8,10,10,12,12,11,12,12,16,15,11,12,
+ 12,14,15, 7,10,10,13,13,10,12,12,14,13,10,11,12,
+ 13,13,12,13,13,16,16,12,12,13,15,15, 8,10,10,13,
+ 13,10,12,12,14,14,10,12,12,13,13,12,13,13,16,16,
+ 12,13,13,15,15,10,12,12,16,15,11,13,13,17,16,11,
+ 12,13,16,15,13,15,15,19,17,14,15,14,17,16,10,12,
+ 12,16,16,11,13,13,16,17,12,13,13,15,17,14,15,15,
+ 17,19,14,15,15,17,17, 8,11,11,16,16,10,13,12,17,
+ 17,10,12,13,16,16,15,17,16,20,19,14,15,17,18,19,
+ 9,12,12,16,17,11,13,14,17,18,11,13,13,19,18,16,
+ 17,18,19,19,15,16,16,19,19, 9,12,12,16,17,11,14,
+ 13,18,17,11,13,13,17,17,16,17,16,20,19,14,16,16,
+ 18,18,12,15,15,19,17,14,15,16, 0,20,13,15,16,20,
+ 17,18,16,20, 0, 0,15,16,19,20, 0,12,15,14,18,19,
+ 13,16,15,20,19,13,16,15,20,18,17,18,17, 0,20,16,
+ 17,16, 0, 0, 8,11,11,16,15,10,12,12,17,17,10,13,
+ 13,17,16,14,16,15,18,20,15,16,16,19,19, 9,12,12,
+ 16,16,11,13,13,17,16,11,13,14,17,18,15,15,16,20,
+ 20,16,16,17,19,19, 9,13,12,16,17,11,14,13,17,17,
+ 11,14,14,18,17,14,16,15,18,19,16,17,18,18,19,12,
+ 14,15,19,18,13,15,16,18, 0,13,14,15, 0, 0,16,16,
+ 17,20, 0,17,17,20,20, 0,12,15,15,19,20,13,15,15,
+ 0, 0,14,16,15, 0, 0,15,18,16, 0, 0,17,18,16, 0,
+ 19,
+};
+
+static const static_codebook _44u1__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u1__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u1__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44u1__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u1__p4_0[] = {
+ 4, 5, 5, 9, 9, 5, 6, 6, 9, 9, 5, 6, 6, 9, 9, 9,
+ 10, 9,12,12, 9, 9,10,12,12, 5, 7, 7,10,10, 7, 7,
+ 8,10,10, 6, 7, 8,10,10,10,10,10,11,13,10, 9,10,
+ 12,13, 5, 7, 7,10,10, 6, 8, 7,10,10, 7, 8, 7,10,
+ 10, 9,10,10,12,12,10,10,10,13,11, 9,10,10,13,13,
+ 10,11,10,13,13,10,10,10,13,13,12,12,13,14,14,12,
+ 12,13,14,14, 9,10,10,13,13,10,10,10,13,13,10,10,
+ 10,13,13,12,13,12,15,14,12,13,12,15,15, 5, 7, 6,
+ 10,10, 7, 8, 8,10,10, 7, 8, 8,10,10,10,11,10,13,
+ 13,10,10,10,12,12, 7, 8, 8,11,10, 8, 8, 9,10,11,
+ 8, 9, 9,11,11,11,10,11,11,14,11,11,11,13,13, 6,
+ 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11,
+ 10,14,11,10,11,11,13,13,10,11,11,14,13,10,10,11,
+ 14,13,10,11,11,14,14,12,11,13,12,16,13,14,14,15,
+ 15,10,10,11,13,14,10,11,10,14,13,10,11,11,14,14,
+ 12,13,12,15,13,13,13,14,15,16, 5, 7, 7,10,10, 7,
+ 8, 8,10,10, 7, 8, 8,10,10,10,10,10,13,13,10,10,
+ 11,12,13, 6, 8, 8,11,10, 8, 9, 9,11,11, 7, 8, 9,
+ 10,11,10,11,11,13,13,10,10,11,11,13, 6, 8, 8,10,
+ 11, 8, 9, 9,11,11, 8, 9, 8,12,10,10,11,11,13,13,
+ 10,11,10,14,11,10,10,10,14,13,10,11,11,14,13,10,
+ 10,11,13,13,12,14,14,16,16,12,12,13,13,15,10,11,
+ 11,13,14,10,11,11,14,15,10,11,10,13,13,13,14,13,
+ 16,16,12,13,11,15,12, 9,10,10,13,13,10,11,11,14,
+ 13,10,10,11,13,14,13,14,13,16,16,13,13,13,15,16,
+ 9,10,10,13,13,10,10,11,13,14,10,11,11,15,13,13,
+ 13,14,14,18,13,13,14,16,15, 9,10,10,13,14,10,11,
+ 10,14,13,10,11,11,13,14,13,14,13,16,15,13,13,14,
+ 15,16,12,13,12,16,14,11,11,13,15,15,13,14,13,16,
+ 15,15,12,16,12,17,14,15,15,17,17,12,13,13,14,16,
+ 11,13,11,16,15,12,13,14,15,16,14,15,13, 0,14,14,
+ 16,16, 0, 0, 9,10,10,13,13,10,11,10,14,14,10,11,
+ 11,13,13,12,13,13,14,16,13,14,14,16,16, 9,10,10,
+ 14,14,11,11,11,14,13,10,10,11,14,14,13,13,13,16,
+ 16,13,13,14,14,17, 9,10,10,13,14,10,11,11,13,15,
+ 10,11,10,14,14,13,13,13,14,17,13,14,13,17,14,12,
+ 13,13,16,14,13,14,13,16,15,12,12,13,15,16,15,15,
+ 16,18,16,15,13,15,14, 0,12,12,13,14,16,13,13,14,
+ 15,16,11,12,11,16,14,15,16,16,17,17,14,15,12,17,
+ 12,
+};
+
+static const static_codebook _44u1__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u1__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u1__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44u1__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u1__p5_0[] = {
+ 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 6, 8, 8, 8, 8,
+ 9, 9, 4, 6, 6, 8, 8, 8, 8, 9, 9, 7, 8, 8, 9, 9,
+ 9, 9,11,10, 7, 8, 8, 9, 9, 9, 9,10,10, 7, 8, 8,
+ 9, 9,10,10,11,11, 7, 8, 8, 9, 9,10,10,11,11, 9,
+ 9, 9,10,10,11,11,12,12, 9, 9, 9,10,11,11,11,12,
+ 12,
+};
+
+static const static_codebook _44u1__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u1__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u1__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44u1__p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u1__p6_0[] = {
+ 1, 4, 4, 6, 6, 8, 8,10, 9,11,10,14,13, 4, 6, 5,
+ 8, 8, 9, 9,11,10,11,11,14,14, 4, 5, 6, 8, 8, 9,
+ 9,10,10,11,11,14,14, 6, 8, 8, 9, 9,10,10,11,11,
+ 12,12,16,15, 7, 8, 8, 9, 9,10,10,11,11,12,12,15,
+ 15, 9,10,10,10,10,11,11,12,12,12,12,15,15, 9,10,
+ 9,10,11,11,11,12,12,12,13,15,15,10,10,11,11,11,
+ 12,12,13,12,13,13,16,15,10,11,11,11,11,12,12,13,
+ 12,13,13,16,17,11,11,12,12,12,13,13,13,14,14,15,
+ 17,17,11,11,12,12,12,13,13,13,14,14,14,16,18,14,
+ 15,15,15,15,16,16,16,16,17,18, 0, 0,14,15,15,15,
+ 15,17,16,17,18,17,17,18, 0,
+};
+
+static const static_codebook _44u1__p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u1__p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44u1__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44u1__p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u1__p6_1[] = {
+ 2, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 5, 6, 6, 6, 6,
+};
+
+static const static_codebook _44u1__p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44u1__p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u1__p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44u1__p7_0[] = {
+ 3,
+ 2,
+ 4,
+ 1,
+ 5,
+ 0,
+ 6,
+};
+
+static const char _vq_lengthlist__44u1__p7_0[] = {
+ 1, 3, 2, 9, 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8,
+};
+
+static const static_codebook _44u1__p7_0 = {
+ 2, 49,
+ (char *)_vq_lengthlist__44u1__p7_0,
+ 1, -518017024, 1626677248, 3, 0,
+ (long *)_vq_quantlist__44u1__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44u1__p7_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u1__p7_1[] = {
+ 1, 4, 4, 6, 6, 6, 6, 7, 7, 8, 8, 9, 9, 5, 7, 7,
+ 8, 7, 7, 7, 9, 8,10, 9,10,11, 5, 7, 7, 8, 8, 7,
+ 7, 8, 9,10,10,11,11, 6, 8, 8, 9, 9, 9, 9,11,10,
+ 12,12,15,12, 6, 8, 8, 9, 9, 9, 9,11,11,12,11,14,
+ 12, 7, 8, 8,10,10,12,12,13,13,13,15,13,13, 7, 8,
+ 8,10,10,11,11,13,12,14,15,15,15, 9,10,10,11,12,
+ 13,13,14,15,14,15,14,15, 8,10,10,12,12,14,14,15,
+ 14,14,15,15,14,10,12,12,14,14,15,14,15,15,15,14,
+ 15,15,10,12,12,13,14,15,14,15,15,14,15,15,15,12,
+ 15,13,15,14,15,15,15,15,15,15,15,15,13,13,15,15,
+ 15,15,15,15,15,15,15,15,15,
+};
+
+static const static_codebook _44u1__p7_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u1__p7_1,
+ 1, -523010048, 1618608128, 4, 0,
+ (long *)_vq_quantlist__44u1__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44u1__p7_2[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u1__p7_2[] = {
+ 2, 5, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 8, 5, 5, 6,
+ 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 5, 6, 5, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9, 6, 7, 7, 8, 8, 8, 8, 9, 8,
+ 9, 9, 9, 9, 6, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9, 9,
+ 9, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 7, 8,
+ 8, 9, 8, 9, 8, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9,10, 9,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 9, 9, 9, 9, 9,
+ 9, 9, 9,10, 9, 9,10,10, 9,
+};
+
+static const static_codebook _44u1__p7_2 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u1__p7_2,
+ 1, -531103744, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u1__p7_2,
+ 0
+};
+
+static const char _huff_lengthlist__44u1__short[] = {
+ 12,13,14,13,17,12,15,17, 5, 5, 6,10,10,11,15,16,
+ 4, 3, 3, 7, 5, 7,10,16, 7, 7, 7,10, 9,11,12,16,
+ 6, 5, 5, 9, 5, 6,10,16, 8, 7, 7, 9, 6, 7, 9,16,
+ 11, 7, 3, 6, 4, 5, 8,16,12, 9, 4, 8, 5, 7, 9,16,
+};
+
+static const static_codebook _huff_book__44u1__short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44u1__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44u2__long[] = {
+ 5, 9,14,12,15,13,10,13, 7, 4, 5, 6, 8, 7, 8,12,
+ 13, 4, 3, 5, 5, 6, 9,15,12, 6, 5, 6, 6, 6, 7,14,
+ 14, 7, 4, 6, 4, 6, 8,15,12, 6, 6, 5, 5, 5, 6,14,
+ 9, 7, 8, 6, 7, 5, 4,10,10,13,14,14,15,10, 6, 8,
+};
+
+static const static_codebook _huff_book__44u2__long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44u2__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44u2__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u2__p1_0[] = {
+ 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,11,11, 8,
+ 10,11, 5, 8, 8, 8,11,10, 8,11,11, 4, 8, 8, 8,11,
+ 11, 8,11,11, 8,11,11,11,13,14,11,13,13, 7,11,11,
+ 10,13,12,11,14,14, 4, 8, 8, 8,11,11, 8,11,11, 8,
+ 11,11,11,14,13,10,12,13, 8,11,11,11,13,13,11,13,
+ 13,
+};
+
+static const static_codebook _44u2__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u2__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u2__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44u2__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u2__p2_0[] = {
+ 2, 5, 5, 5, 6, 6, 5, 6, 6, 5, 6, 6, 7, 8, 8, 6,
+ 8, 8, 5, 6, 6, 6, 8, 7, 7, 8, 8, 5, 6, 6, 7, 8,
+ 8, 6, 8, 8, 6, 8, 8, 8, 9,10, 8,10,10, 6, 8, 8,
+ 7,10, 8, 8,10,10, 5, 6, 6, 6, 8, 8, 7, 8, 8, 6,
+ 8, 8, 8,10,10, 8, 8,10, 6, 8, 8, 8,10,10, 8,10,
+ 9,
+};
+
+static const static_codebook _44u2__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u2__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u2__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44u2__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u2__p3_0[] = {
+ 2, 4, 4, 7, 8, 5, 7, 7, 9, 9, 5, 7, 7, 9, 9, 8,
+ 9, 9,12,11, 8, 9, 9,11,12, 5, 7, 7,10,10, 7, 9,
+ 9,11,11, 7, 9, 9,10,11,10,11,11,13,13, 9,10,11,
+ 12,13, 5, 7, 7,10,10, 7, 9, 9,11,10, 7, 9, 9,11,
+ 11, 9,11,10,13,13,10,11,11,13,13, 8,10,10,14,13,
+ 10,11,11,15,14, 9,11,11,15,14,13,14,13,16,14,12,
+ 13,13,15,16, 8,10,10,13,14, 9,11,11,14,15,10,11,
+ 11,14,15,12,13,13,15,15,12,13,14,15,16, 5, 7, 7,
+ 10,10, 7, 9, 9,11,11, 7, 9, 9,11,12,10,11,11,14,
+ 13,10,11,11,14,14, 7, 9, 9,12,12, 9,11,11,13,13,
+ 9,11,11,13,13,12,13,12,14,14,11,12,13,15,15, 7,
+ 9, 9,12,12, 8,11,10,13,12, 9,11,11,13,13,11,13,
+ 12,15,13,11,13,13,15,16, 9,12,11,15,15,11,12,12,
+ 16,15,11,12,13,16,16,13,14,15,16,15,13,15,15,17,
+ 17, 9,11,11,14,15,10,12,12,15,15,11,13,12,15,16,
+ 13,15,14,16,16,13,15,15,17,19, 5, 7, 7,10,10, 7,
+ 9, 9,12,11, 7, 9, 9,11,11,10,11,11,14,14,10,11,
+ 11,13,14, 7, 9, 9,12,12, 9,11,11,13,13, 9,10,11,
+ 12,13,11,13,12,16,15,11,12,12,14,15, 7, 9, 9,12,
+ 12, 9,11,11,13,13, 9,11,11,13,12,11,13,12,15,16,
+ 12,13,13,15,14, 9,11,11,15,14,11,13,12,16,15,10,
+ 11,12,15,15,13,14,14,18,17,13,14,14,15,17,10,11,
+ 11,14,15,11,13,12,15,17,11,13,12,15,16,13,15,14,
+ 18,17,14,15,15,16,18, 7,10,10,14,14,10,12,12,15,
+ 15,10,12,12,15,15,14,15,15,18,17,13,15,15,16,16,
+ 9,11,11,16,15,11,13,13,16,18,11,13,13,16,16,15,
+ 16,16, 0, 0,14,15,16,18,17, 9,11,11,15,15,10,13,
+ 12,17,16,11,12,13,16,17,14,15,16,19,19,14,15,15,
+ 0,20,12,14,14, 0, 0,13,14,16,19,18,13,15,16,20,
+ 17,16,18, 0, 0, 0,15,16,17,18,19,11,14,14, 0,19,
+ 12,15,14,17,17,13,15,15, 0, 0,16,17,15,20,19,15,
+ 17,16,19, 0, 8,10,10,14,15,10,12,11,15,15,10,11,
+ 12,16,15,13,14,14,19,17,14,15,15, 0, 0, 9,11,11,
+ 16,15,11,13,13,17,16,10,12,13,16,17,14,15,15,18,
+ 18,14,15,16,20,19, 9,12,12, 0,15,11,13,13,16,17,
+ 11,13,13,19,17,14,16,16,18,17,15,16,16,17,19,11,
+ 14,14,18,18,13,14,15, 0, 0,12,14,15,19,18,15,16,
+ 19, 0,19,15,16,19,19,17,12,14,14,16,19,13,15,15,
+ 0,17,13,15,14,18,18,15,16,15, 0,18,16,17,17, 0,
+ 0,
+};
+
+static const static_codebook _44u2__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u2__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u2__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44u2__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u2__p4_0[] = {
+ 4, 5, 5, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 9,
+ 9, 9,11,11, 9, 9, 9,11,11, 5, 7, 7, 9, 9, 7, 8,
+ 8,10,10, 7, 7, 8,10,10,10,10,10,11,12, 9,10,10,
+ 11,12, 5, 7, 7, 9, 9, 6, 8, 7,10,10, 7, 8, 8,10,
+ 10, 9,10,10,12,11, 9,10,10,12,11, 9,10,10,12,12,
+ 10,10,10,13,12, 9,10,10,12,13,12,12,12,14,14,11,
+ 12,12,13,14, 9,10,10,12,12, 9,10,10,12,13,10,10,
+ 10,12,13,11,12,12,14,13,12,12,12,14,13, 5, 7, 7,
+ 10, 9, 7, 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12,
+ 12,10,10,10,12,12, 7, 8, 8,11,10, 8, 8, 9,11,11,
+ 8, 9, 9,11,11,10,11,11,12,13,10,11,11,13,13, 6,
+ 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11,
+ 10,13,11,10,11,11,13,13, 9,10,10,13,13,10,11,11,
+ 13,13,10,11,11,14,13,12,11,13,12,15,12,13,13,15,
+ 15, 9,10,10,12,13,10,11,10,13,13,10,11,11,13,13,
+ 12,13,11,15,13,12,13,13,15,15, 5, 7, 7, 9,10, 7,
+ 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12,12,10,10,
+ 11,12,12, 6, 8, 8,10,10, 8, 9, 9,11,11, 7, 8, 9,
+ 10,11,10,11,11,13,13,10,10,11,11,13, 7, 8, 8,10,
+ 11, 8, 9, 9,11,11, 8, 9, 8,11,11,10,11,11,13,13,
+ 10,11,11,13,12, 9,10,10,13,12,10,11,11,14,13,10,
+ 10,11,13,13,12,13,13,15,15,12,11,13,12,14, 9,10,
+ 10,12,13,10,11,11,13,14,10,11,11,13,13,12,13,13,
+ 15,15,12,13,12,15,12, 8, 9, 9,12,12, 9,11,10,13,
+ 13, 9,10,10,13,13,12,13,13,15,15,12,12,12,14,14,
+ 9,10,10,13,13,10,11,11,13,14,10,11,11,14,12,13,
+ 13,14,14,16,12,13,13,15,14, 9,10,10,13,13,10,11,
+ 10,14,13,10,11,11,13,14,12,14,13,16,14,13,13,13,
+ 14,15,11,13,12,15,14,11,12,13,14,15,12,13,13,16,
+ 15,14,12,15,12,16,14,15,15,17,16,11,12,12,14,15,
+ 11,13,11,15,14,12,13,13,15,16,13,15,12,17,13,14,
+ 15,15,16,16, 8, 9, 9,12,12, 9,10,10,13,13, 9,10,
+ 10,13,13,12,13,12,14,14,12,13,13,15,15, 9,10,10,
+ 13,13,10,11,11,14,13,10,10,11,13,14,12,13,13,15,
+ 14,12,12,14,14,16, 9,10,10,13,13,10,11,11,13,14,
+ 10,11,11,14,13,13,13,13,15,15,13,14,13,16,14,11,
+ 12,12,14,14,12,13,13,16,15,11,12,13,14,15,14,15,
+ 15,16,16,14,13,15,13,17,11,12,12,14,15,12,13,13,
+ 15,16,11,13,12,15,15,14,15,14,16,16,14,15,12,17,
+ 13,
+};
+
+static const static_codebook _44u2__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u2__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u2__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44u2__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u2__p5_0[] = {
+ 1, 4, 4, 7, 7, 8, 8, 9, 9, 4, 6, 5, 8, 8, 8, 8,
+ 10,10, 4, 5, 6, 8, 8, 8, 8,10,10, 7, 8, 8, 9, 9,
+ 9, 9,11,11, 7, 8, 8, 9, 9, 9, 9,11,11, 8, 8, 8,
+ 9, 9,10,11,12,12, 8, 8, 8, 9, 9,10,10,12,12,10,
+ 10,10,11,11,12,12,13,13,10,10,10,11,11,12,12,13,
+ 13,
+};
+
+static const static_codebook _44u2__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u2__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u2__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44u2__p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u2__p6_0[] = {
+ 1, 4, 4, 6, 6, 8, 8,10,10,11,11,14,13, 4, 6, 5,
+ 8, 8, 9, 9,11,10,12,11,15,14, 4, 5, 6, 8, 8, 9,
+ 9,11,11,11,11,14,14, 6, 8, 8,10, 9,11,11,11,11,
+ 12,12,15,15, 6, 8, 8, 9, 9,11,11,11,12,12,12,15,
+ 15, 8,10,10,11,11,11,11,12,12,13,13,15,16, 8,10,
+ 10,11,11,11,11,12,12,13,13,16,16,10,11,11,12,12,
+ 12,12,13,13,13,13,17,16,10,11,11,12,12,12,12,13,
+ 13,13,14,16,17,11,12,12,13,13,13,13,14,14,15,14,
+ 18,17,11,12,12,13,13,13,13,14,14,14,15,19,18,14,
+ 15,15,15,15,16,16,18,19,18,18, 0, 0,14,15,15,16,
+ 15,17,17,16,18,17,18, 0, 0,
+};
+
+static const static_codebook _44u2__p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u2__p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44u2__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44u2__p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u2__p6_1[] = {
+ 2, 4, 4, 5, 5, 4, 5, 5, 6, 5, 4, 5, 5, 5, 6, 5,
+ 6, 5, 6, 6, 5, 5, 6, 6, 6,
+};
+
+static const static_codebook _44u2__p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44u2__p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u2__p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44u2__p7_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u2__p7_0[] = {
+ 1, 3, 2,12,12,12,12,12,12, 4,12,12,12,12,12,12,
+ 12,12, 5,12,12,12,12,12,12,12,12,12,12,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,
+};
+
+static const static_codebook _44u2__p7_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u2__p7_0,
+ 1, -516612096, 1626677248, 4, 0,
+ (long *)_vq_quantlist__44u2__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44u2__p7_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u2__p7_1[] = {
+ 1, 4, 4, 7, 6, 7, 6, 8, 7, 9, 7, 9, 8, 4, 7, 6,
+ 8, 8, 9, 8,10, 9,10,10,11,11, 4, 7, 7, 8, 8, 8,
+ 8, 9,10,11,11,11,11, 6, 8, 8,10,10,10,10,11,11,
+ 12,12,12,12, 7, 8, 8,10,10,10,10,11,11,12,12,13,
+ 13, 7, 9, 9,11,10,12,12,13,13,14,13,14,14, 7, 9,
+ 9,10,11,11,12,13,13,13,13,16,14, 9,10,10,12,12,
+ 13,13,14,14,15,16,15,16, 9,10,10,12,12,12,13,14,
+ 14,14,15,16,15,10,12,12,13,13,15,13,16,16,15,17,
+ 17,17,10,11,11,12,14,14,14,15,15,17,17,15,17,11,
+ 12,12,14,14,14,15,15,15,17,16,17,17,10,12,12,13,
+ 14,14,14,17,15,17,17,17,17,
+};
+
+static const static_codebook _44u2__p7_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u2__p7_1,
+ 1, -523010048, 1618608128, 4, 0,
+ (long *)_vq_quantlist__44u2__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44u2__p7_2[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u2__p7_2[] = {
+ 2, 5, 5, 6, 6, 7, 7, 8, 7, 8, 8, 8, 8, 5, 6, 6,
+ 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 5, 6, 6, 7, 7, 8,
+ 7, 8, 8, 8, 8, 8, 8, 6, 7, 7, 7, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 6, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9, 9,
+ 9, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 7, 8,
+ 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,
+};
+
+static const static_codebook _44u2__p7_2 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u2__p7_2,
+ 1, -531103744, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u2__p7_2,
+ 0
+};
+
+static const char _huff_lengthlist__44u2__short[] = {
+ 13,15,17,17,15,15,12,17,11, 9, 7,10,10, 9,12,17,
+ 10, 6, 3, 6, 5, 7,10,17,15,10, 6, 9, 8, 9,11,17,
+ 15, 8, 4, 7, 3, 5, 9,16,16,10, 5, 8, 4, 5, 8,16,
+ 13,11, 5, 8, 3, 3, 5,14,13,12, 7,10, 5, 5, 7,14,
+};
+
+static const static_codebook _huff_book__44u2__short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44u2__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44u3__long[] = {
+ 6, 9,13,12,14,11,10,13, 8, 4, 5, 7, 8, 7, 8,12,
+ 11, 4, 3, 5, 5, 7, 9,14,11, 6, 5, 6, 6, 6, 7,13,
+ 13, 7, 5, 6, 4, 5, 7,14,11, 7, 6, 6, 5, 5, 6,13,
+ 9, 7, 8, 6, 7, 5, 3, 9, 9,12,13,12,14,10, 6, 7,
+};
+
+static const static_codebook _huff_book__44u3__long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44u3__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44u3__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u3__p1_0[] = {
+ 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,10,11, 8,
+ 10,11, 5, 8, 8, 8,11,10, 8,11,11, 4, 8, 8, 8,11,
+ 11, 8,11,11, 8,11,11,11,13,14,11,14,14, 8,11,11,
+ 10,14,12,11,14,14, 4, 8, 8, 8,11,11, 8,11,11, 7,
+ 11,11,11,14,14,10,12,14, 8,11,11,11,14,14,11,14,
+ 13,
+};
+
+static const static_codebook _44u3__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u3__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u3__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44u3__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u3__p2_0[] = {
+ 2, 5, 4, 5, 6, 6, 5, 6, 6, 5, 6, 6, 7, 8, 8, 6,
+ 8, 8, 5, 6, 6, 6, 8, 8, 7, 8, 8, 5, 7, 6, 7, 8,
+ 8, 6, 8, 8, 7, 8, 8, 8, 9,10, 8,10,10, 6, 8, 8,
+ 8,10, 8, 8,10,10, 5, 6, 6, 6, 8, 8, 7, 8, 8, 6,
+ 8, 8, 8,10,10, 8, 8,10, 7, 8, 8, 8,10,10, 8,10,
+ 9,
+};
+
+static const static_codebook _44u3__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u3__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u3__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44u3__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u3__p3_0[] = {
+ 2, 4, 4, 7, 7, 5, 7, 7, 9, 9, 5, 7, 7, 9, 9, 8,
+ 9, 9,12,12, 8, 9, 9,11,12, 5, 7, 7,10,10, 7, 9,
+ 9,11,11, 7, 9, 9,10,11,10,11,11,13,13, 9,10,11,
+ 13,13, 5, 7, 7,10,10, 7, 9, 9,11,10, 7, 9, 9,11,
+ 11, 9,11,10,13,13,10,11,11,14,13, 8,10,10,14,13,
+ 10,11,11,15,14, 9,11,11,14,14,13,14,13,16,16,12,
+ 13,13,15,15, 8,10,10,13,14, 9,11,11,14,14,10,11,
+ 11,14,15,12,13,13,15,15,13,14,14,15,16, 5, 7, 7,
+ 10,10, 7, 9, 9,11,11, 7, 9, 9,11,12,10,11,11,14,
+ 14,10,11,11,14,14, 7, 9, 9,12,12, 9,11,11,13,13,
+ 9,11,11,13,13,12,12,13,15,15,11,12,13,15,16, 7,
+ 9, 9,11,11, 8,11,10,13,12, 9,11,11,13,13,11,13,
+ 12,15,13,11,13,13,15,16, 9,12,11,15,14,11,12,13,
+ 16,15,11,13,13,15,16,14,14,15,17,16,13,15,16, 0,
+ 17, 9,11,11,15,15,10,13,12,15,15,11,13,13,15,16,
+ 13,15,13,16,15,14,16,15, 0,19, 5, 7, 7,10,10, 7,
+ 9, 9,11,11, 7, 9, 9,11,11,10,12,11,14,14,10,11,
+ 12,14,14, 7, 9, 9,12,12, 9,11,11,14,13, 9,10,11,
+ 12,13,11,13,13,16,16,11,12,13,13,16, 7, 9, 9,12,
+ 12, 9,11,11,13,13, 9,11,11,13,13,11,13,13,15,15,
+ 12,13,12,15,14, 9,11,11,15,14,11,13,12,16,16,10,
+ 12,12,15,15,13,15,15,17,19,13,14,15,16,17,10,12,
+ 12,15,15,11,13,13,16,16,11,13,13,15,16,13,15,15,
+ 0, 0,14,15,15,16,16, 8,10,10,14,14,10,12,12,15,
+ 15,10,12,11,15,16,14,15,15,19,20,13,14,14,18,16,
+ 9,11,11,15,15,11,13,13,17,16,11,13,13,16,16,15,
+ 17,17,20,20,14,15,16,17,20, 9,11,11,15,15,10,13,
+ 12,16,15,11,13,13,15,17,14,16,15,18, 0,14,16,15,
+ 18,20,12,14,14, 0, 0,14,14,16, 0, 0,13,16,15, 0,
+ 0,17,17,18, 0, 0,16,17,19,19, 0,12,14,14,18, 0,
+ 12,16,14, 0,17,13,15,15,18, 0,16,18,17, 0,17,16,
+ 18,17, 0, 0, 7,10,10,14,14,10,12,11,15,15,10,12,
+ 12,16,15,13,15,15,18, 0,14,15,15,17, 0, 9,11,11,
+ 15,15,11,13,13,16,16,11,12,13,16,16,14,15,16,17,
+ 17,14,16,16,16,18, 9,11,12,16,16,11,13,13,17,17,
+ 11,14,13,20,17,15,16,16,19, 0,15,16,17, 0,19,11,
+ 13,14,17,16,14,15,15,20,18,13,14,15,17,19,16,18,
+ 18, 0,20,16,16,19,17, 0,12,15,14,17, 0,14,15,15,
+ 18,19,13,16,15,19,20,15,18,18, 0,20,17, 0,16, 0,
+ 0,
+};
+
+static const static_codebook _44u3__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u3__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u3__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44u3__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u3__p4_0[] = {
+ 4, 5, 5, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 9,
+ 9, 9,11,11, 9, 9, 9,11,11, 5, 7, 7, 9, 9, 7, 8,
+ 8,10,10, 7, 7, 8,10,10, 9,10,10,11,12, 9,10,10,
+ 11,12, 5, 7, 7, 9, 9, 7, 8, 7,10,10, 7, 8, 8,10,
+ 10, 9,10, 9,12,11, 9,10,10,12,11, 9,10, 9,12,12,
+ 9,10,10,13,12, 9,10,10,12,13,12,12,12,14,14,11,
+ 12,12,13,14, 9, 9,10,12,12, 9,10,10,12,12, 9,10,
+ 10,12,13,11,12,11,14,13,12,12,12,14,13, 5, 7, 7,
+ 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12,
+ 12, 9,10,10,12,12, 7, 8, 8,11,10, 8, 8, 9,11,11,
+ 8, 9, 9,11,11,11,11,11,12,13,10,11,11,13,13, 6,
+ 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11,
+ 10,13,11,10,11,11,13,13, 9,11,10,13,12,10,11,11,
+ 13,13,10,11,11,13,13,12,12,13,12,15,12,13,13,15,
+ 15, 9,10,10,12,13,10,11,10,13,12,10,11,11,13,14,
+ 12,13,11,15,13,12,13,13,15,15, 5, 7, 7, 9, 9, 7,
+ 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12,12,10,10,
+ 11,12,12, 6, 8, 8,10,10, 8, 9, 9,11,11, 7, 8, 9,
+ 10,11,10,11,11,13,13,10,10,11,11,13, 7, 8, 8,10,
+ 10, 8, 9, 9,11,11, 8, 9, 9,11,11,10,11,11,13,13,
+ 11,11,11,13,12, 9,10,10,13,12,10,11,11,14,13,10,
+ 10,11,12,13,12,13,13,15,15,12,11,13,13,14, 9,10,
+ 11,12,13,10,11,11,13,13,10,11,11,13,13,12,13,13,
+ 15,15,12,13,12,15,12, 8, 9, 9,12,12, 9,11,10,13,
+ 13, 9,10,10,13,13,12,13,13,15,14,12,12,12,14,13,
+ 9,10,10,13,12,10,11,11,13,13,10,11,11,14,12,13,
+ 13,14,14,16,12,13,13,15,15, 9,10,10,13,13,10,11,
+ 10,14,13,10,11,11,13,14,12,14,13,15,14,13,13,13,
+ 15,15,11,13,12,15,14,11,12,13,14,15,12,13,13,16,
+ 14,14,12,15,12,16,14,15,15,17,15,11,12,12,14,14,
+ 11,13,11,15,14,12,13,13,15,15,13,15,12,17,13,14,
+ 15,15,16,16, 8, 9, 9,12,12, 9,10,10,12,13, 9,10,
+ 10,13,13,12,12,12,14,14,12,13,13,15,15, 9,10,10,
+ 13,12,10,11,11,14,13,10,10,11,13,14,12,13,13,15,
+ 15,12,12,13,14,16, 9,10,10,13,13,10,11,11,13,14,
+ 10,11,11,14,13,12,13,13,14,15,13,14,13,16,14,11,
+ 12,12,14,14,12,13,13,15,14,11,12,13,14,15,14,15,
+ 15,16,16,13,13,15,13,16,11,12,12,14,15,12,13,13,
+ 14,15,11,13,12,15,14,14,15,15,16,16,14,15,12,16,
+ 13,
+};
+
+static const static_codebook _44u3__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u3__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u3__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44u3__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u3__p5_0[] = {
+ 2, 3, 3, 6, 6, 7, 7, 9, 9, 4, 5, 5, 7, 7, 8, 8,
+ 10,10, 4, 5, 5, 7, 7, 8, 8,10,10, 6, 7, 7, 8, 8,
+ 9, 9,11,10, 6, 7, 7, 8, 8, 9, 9,10,10, 7, 8, 8,
+ 9, 9,10,10,11,11, 7, 8, 8, 9, 9,10,10,11,11, 9,
+ 10,10,11,10,11,11,12,12, 9,10,10,10,10,11,11,12,
+ 12,
+};
+
+static const static_codebook _44u3__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u3__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u3__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44u3__p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u3__p6_0[] = {
+ 1, 4, 4, 6, 6, 8, 8, 9, 9,10,11,13,14, 4, 6, 5,
+ 8, 8, 9, 9,10,10,11,11,14,14, 4, 6, 6, 8, 8, 9,
+ 9,10,10,11,11,14,14, 6, 8, 8, 9, 9,10,10,11,11,
+ 12,12,15,15, 6, 8, 8, 9, 9,10,11,11,11,12,12,15,
+ 15, 8, 9, 9,11,10,11,11,12,12,13,13,15,16, 8, 9,
+ 9,10,11,11,11,12,12,13,13,16,16,10,10,11,11,11,
+ 12,12,13,13,13,14,17,16, 9,10,11,12,11,12,12,13,
+ 13,13,13,16,18,11,12,11,12,12,13,13,13,14,15,14,
+ 17,17,11,11,12,12,12,13,13,13,14,14,15,18,17,14,
+ 15,15,15,15,16,16,17,17,19,18, 0,20,14,15,14,15,
+ 15,16,16,16,17,18,16,20,18,
+};
+
+static const static_codebook _44u3__p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u3__p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44u3__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44u3__p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u3__p6_1[] = {
+ 2, 4, 4, 5, 5, 4, 5, 5, 6, 5, 4, 5, 5, 5, 6, 5,
+ 6, 5, 6, 6, 5, 5, 6, 6, 6,
+};
+
+static const static_codebook _44u3__p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44u3__p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u3__p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44u3__p7_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u3__p7_0[] = {
+ 1, 3, 3,10,10,10,10,10,10, 4,10,10,10,10,10,10,
+ 10,10, 4,10,10,10,10,10,10,10,10,10,10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9,
+};
+
+static const static_codebook _44u3__p7_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u3__p7_0,
+ 1, -515907584, 1627381760, 4, 0,
+ (long *)_vq_quantlist__44u3__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44u3__p7_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44u3__p7_1[] = {
+ 1, 4, 4, 6, 6, 7, 6, 8, 7, 9, 8,10, 9,11,11, 4,
+ 7, 7, 8, 7, 9, 9,10,10,11,11,11,11,12,12, 4, 7,
+ 7, 7, 7, 9, 9,10,10,11,11,12,12,12,11, 6, 8, 8,
+ 9, 9,10,10,11,11,12,12,13,12,13,13, 6, 8, 8, 9,
+ 9,10,11,11,11,12,12,13,14,13,13, 8, 9, 9,11,11,
+ 12,12,12,13,14,13,14,14,14,15, 8, 9, 9,11,11,11,
+ 12,13,14,13,14,15,17,14,15, 9,10,10,12,12,13,13,
+ 13,14,15,15,15,16,16,16, 9,11,11,12,12,13,13,14,
+ 14,14,15,16,16,16,16,10,12,12,13,13,14,14,15,15,
+ 15,16,17,17,17,17,10,12,11,13,13,15,14,15,14,16,
+ 17,16,16,16,16,11,13,12,14,14,14,14,15,16,17,16,
+ 17,17,17,17,11,13,12,14,14,14,15,17,16,17,17,17,
+ 17,17,17,12,13,13,15,16,15,16,17,17,16,16,17,17,
+ 17,17,12,13,13,15,15,15,16,17,17,17,16,17,16,17,
+ 17,
+};
+
+static const static_codebook _44u3__p7_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44u3__p7_1,
+ 1, -522338304, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44u3__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44u3__p7_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44u3__p7_2[] = {
+ 2, 5, 5, 7, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 10,10, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 8, 9, 9, 9,
+ 9,10, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 10,10,10,10, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,
+ 9,10,10,10,10, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 10,10,10,10,10,10, 7, 8, 8, 9, 8, 9, 9, 9, 9,10,
+ 9,10,10,10,10,10,10, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9,10,10,10,10,10,10,10, 8, 9, 8, 9, 9, 9, 9,10,
+ 9,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9,10,
+ 9,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10,
+ 9,10,10,10,10,10,10,10,10,10,10, 9, 9, 9,10, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,11, 9,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,11, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 9,10,10,10,10,10,10,10,10,10,10,10,11,11,11,10,
+ 11,
+};
+
+static const static_codebook _44u3__p7_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44u3__p7_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44u3__p7_2,
+ 0
+};
+
+static const char _huff_lengthlist__44u3__short[] = {
+ 14,14,14,15,13,15,12,16,10, 8, 7, 9, 9, 8,12,16,
+ 10, 5, 4, 6, 5, 6, 9,16,14, 8, 6, 8, 7, 8,10,16,
+ 14, 7, 4, 6, 3, 5, 8,16,15, 9, 5, 7, 4, 4, 7,16,
+ 13,10, 6, 7, 4, 3, 4,13,13,12, 7, 9, 5, 5, 6,12,
+};
+
+static const static_codebook _huff_book__44u3__short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44u3__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44u4__long[] = {
+ 3, 8,12,12,13,12,11,13, 5, 4, 6, 7, 8, 8, 9,13,
+ 9, 5, 4, 5, 5, 7, 9,13, 9, 6, 5, 6, 6, 7, 8,12,
+ 12, 7, 5, 6, 4, 5, 8,13,11, 7, 6, 6, 5, 5, 6,12,
+ 10, 8, 8, 7, 7, 5, 3, 8,10,12,13,12,12, 9, 6, 7,
+};
+
+static const static_codebook _huff_book__44u4__long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44u4__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44u4__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u4__p1_0[] = {
+ 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,10,11, 8,
+ 10,11, 5, 8, 8, 8,11,10, 8,11,11, 4, 8, 8, 8,11,
+ 11, 8,11,11, 8,11,11,11,13,14,11,15,14, 8,11,11,
+ 10,13,12,11,14,14, 4, 8, 8, 8,11,11, 8,11,11, 7,
+ 11,11,11,15,14,10,12,14, 8,11,11,11,14,14,11,14,
+ 13,
+};
+
+static const static_codebook _44u4__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u4__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u4__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44u4__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u4__p2_0[] = {
+ 2, 5, 5, 5, 6, 6, 5, 6, 6, 5, 6, 6, 7, 8, 8, 6,
+ 8, 8, 5, 6, 6, 6, 8, 8, 7, 8, 8, 5, 7, 6, 6, 8,
+ 8, 6, 8, 8, 6, 8, 8, 8, 9,10, 8,10,10, 6, 8, 8,
+ 8,10, 8, 8,10,10, 5, 6, 6, 6, 8, 8, 6, 8, 8, 6,
+ 8, 8, 8,10,10, 8, 8,10, 6, 8, 8, 8,10,10, 8,10,
+ 9,
+};
+
+static const static_codebook _44u4__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u4__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u4__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44u4__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u4__p3_0[] = {
+ 2, 4, 4, 8, 8, 5, 7, 7, 9, 9, 5, 7, 7, 9, 9, 8,
+ 10, 9,12,12, 8, 9,10,12,12, 5, 7, 7,10,10, 7, 9,
+ 9,11,11, 7, 9, 9,11,11,10,12,11,14,14, 9,10,11,
+ 13,14, 5, 7, 7,10,10, 7, 9, 9,11,11, 7, 9, 9,11,
+ 11, 9,11,10,14,13,10,11,11,14,14, 8,10,10,14,13,
+ 10,12,12,15,14, 9,11,11,15,14,13,14,14,17,17,12,
+ 14,14,16,16, 8,10,10,14,14, 9,11,11,14,15,10,12,
+ 12,14,15,12,14,13,16,16,13,14,15,15,18, 4, 7, 7,
+ 10,10, 7, 9, 9,12,11, 7, 9, 9,11,12,10,12,11,15,
+ 14,10,11,12,14,15, 7, 9, 9,12,12, 9,11,12,13,13,
+ 9,11,12,13,13,12,13,13,15,16,11,13,13,15,16, 7,
+ 9, 9,12,12, 9,11,10,13,12, 9,11,12,13,14,11,13,
+ 12,16,14,12,13,13,15,16,10,12,12,16,15,11,13,13,
+ 17,16,11,13,13,17,16,14,15,15,17,17,14,16,16,18,
+ 20, 9,11,11,15,16,11,13,12,16,16,11,13,13,16,17,
+ 14,15,14,18,16,14,16,16,17,20, 5, 7, 7,10,10, 7,
+ 9, 9,12,11, 7, 9,10,11,12,10,12,11,15,15,10,12,
+ 12,14,14, 7, 9, 9,12,12, 9,12,11,14,13, 9,10,11,
+ 12,13,12,13,14,16,16,11,12,13,14,16, 7, 9, 9,12,
+ 12, 9,12,11,13,13, 9,12,11,13,13,11,13,13,16,16,
+ 12,13,13,16,15, 9,11,11,16,14,11,13,13,16,16,11,
+ 12,13,16,16,14,16,16,17,17,13,14,15,16,17,10,12,
+ 12,15,15,11,13,13,16,17,11,13,13,16,16,14,16,15,
+ 19,19,14,15,15,17,18, 8,10,10,14,14,10,12,12,15,
+ 15,10,12,12,16,16,14,16,15,20,19,13,15,15,17,16,
+ 9,12,12,16,16,11,13,13,16,18,11,14,13,16,17,16,
+ 17,16,20, 0,15,16,18,18,20, 9,11,11,15,15,11,14,
+ 12,17,16,11,13,13,17,17,15,17,15,20,20,14,16,16,
+ 17, 0,13,15,14,18,16,14,15,16, 0,18,14,16,16, 0,
+ 0,18,16, 0, 0,20,16,18,18, 0, 0,12,14,14,17,18,
+ 13,15,14,20,18,14,16,15,19,19,16,20,16, 0,18,16,
+ 19,17,19, 0, 8,10,10,14,14,10,12,12,16,15,10,12,
+ 12,16,16,13,15,15,18,17,14,16,16,19, 0, 9,11,11,
+ 16,15,11,14,13,18,17,11,12,13,17,18,14,17,16,18,
+ 18,15,16,17,18,18, 9,12,12,16,16,11,13,13,16,18,
+ 11,14,13,17,17,15,16,16,18,20,16,17,17,20,20,12,
+ 14,14,18,17,14,16,16, 0,19,13,14,15,18, 0,16, 0,
+ 0, 0, 0,16,16, 0,19,20,13,15,14, 0, 0,14,16,16,
+ 18,19,14,16,15, 0,20,16,20,18, 0,20,17,20,17, 0,
+ 0,
+};
+
+static const static_codebook _44u4__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u4__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u4__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44u4__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u4__p4_0[] = {
+ 4, 5, 5, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 9,
+ 9, 9,11,11, 8, 9, 9,11,11, 5, 7, 7, 9, 9, 7, 8,
+ 8,10,10, 7, 7, 8,10,10, 9,10,10,11,12, 9,10,10,
+ 11,12, 5, 7, 7, 9, 9, 7, 8, 7,10,10, 7, 8, 8,10,
+ 10, 9,10,10,12,11, 9,10,10,12,11, 9,10, 9,12,12,
+ 9,10,10,13,12, 9,10,10,12,12,12,12,12,14,14,11,
+ 12,12,13,14, 9, 9,10,12,12, 9,10,10,13,13, 9,10,
+ 10,12,13,11,12,12,14,13,11,12,12,14,14, 5, 7, 7,
+ 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12,
+ 12, 9,10,10,12,12, 7, 8, 8,11,10, 8, 8, 9,11,11,
+ 8, 9, 9,11,11,11,11,11,12,13,10,11,11,13,13, 6,
+ 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11,
+ 10,13,11,10,11,11,13,13, 9,11,10,13,12,10,11,11,
+ 13,14,10,11,11,14,13,12,12,13,12,15,12,13,13,15,
+ 15, 9,10,10,12,13,10,11,10,13,12,10,11,11,13,14,
+ 12,13,11,15,13,13,13,13,15,15, 5, 7, 7, 9, 9, 7,
+ 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12,12,10,10,
+ 11,12,13, 6, 8, 8,10,10, 8, 9, 9,11,11, 7, 8, 9,
+ 10,11,10,11,11,13,13,10,10,11,11,13, 7, 8, 8,10,
+ 11, 8, 9, 9,11,11, 8, 9, 8,11,11,10,11,11,13,13,
+ 11,12,11,13,12, 9,10,10,13,12,10,11,11,14,13,10,
+ 10,11,12,13,12,13,13,15,15,12,11,13,13,14, 9,10,
+ 11,12,13,10,11,11,13,14,10,11,11,13,13,12,13,13,
+ 15,15,12,13,12,15,12, 8, 9, 9,12,12, 9,11,10,13,
+ 13, 9,10,10,13,13,12,13,13,15,15,12,12,12,14,14,
+ 9,10,10,13,13,10,11,11,13,14,10,11,11,14,13,13,
+ 13,14,14,16,13,13,13,15,15, 9,10,10,13,13,10,11,
+ 10,14,13,10,11,11,13,14,12,14,13,16,14,12,13,13,
+ 14,15,11,12,12,15,14,11,12,13,14,15,12,13,13,16,
+ 15,14,12,15,12,16,14,15,15,16,16,11,12,12,14,14,
+ 11,13,12,15,14,12,13,13,15,16,13,15,13,17,13,14,
+ 15,15,16,17, 8, 9, 9,12,12, 9,10,10,12,13, 9,10,
+ 10,13,13,12,12,12,14,14,12,13,13,15,15, 9,10,10,
+ 13,12,10,11,11,14,13,10,10,11,13,14,13,13,13,15,
+ 15,12,13,14,14,16, 9,10,10,13,13,10,11,11,13,14,
+ 10,11,11,14,14,13,13,13,15,15,13,14,13,16,14,11,
+ 12,12,15,14,12,13,13,16,15,11,12,13,14,15,14,15,
+ 15,17,16,13,13,15,13,16,11,12,13,14,15,13,13,13,
+ 15,16,11,13,12,15,14,14,15,15,16,16,14,15,12,17,
+ 13,
+};
+
+static const static_codebook _44u4__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u4__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u4__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44u4__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u4__p5_0[] = {
+ 2, 3, 3, 6, 6, 7, 7, 9, 9, 4, 5, 5, 7, 7, 8, 8,
+ 10, 9, 4, 5, 5, 7, 7, 8, 8,10,10, 6, 7, 7, 8, 8,
+ 9, 9,11,10, 6, 7, 7, 8, 8, 9, 9,10,11, 7, 8, 8,
+ 9, 9,10,10,11,11, 7, 8, 8, 9, 9,10,10,11,11, 9,
+ 10,10,11,10,11,11,12,12, 9,10,10,10,11,11,11,12,
+ 12,
+};
+
+static const static_codebook _44u4__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u4__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u4__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44u4__p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u4__p6_0[] = {
+ 1, 4, 4, 6, 6, 8, 8, 9, 9,11,10,13,13, 4, 6, 5,
+ 8, 8, 9, 9,10,10,11,11,14,14, 4, 6, 6, 8, 8, 9,
+ 9,10,10,11,11,14,14, 6, 8, 8, 9, 9,10,10,11,11,
+ 12,12,15,15, 6, 8, 8, 9, 9,10,11,11,11,12,12,15,
+ 15, 8, 9, 9,11,10,11,11,12,12,13,13,16,16, 8, 9,
+ 9,10,10,11,11,12,12,13,13,16,16,10,10,10,12,11,
+ 12,12,13,13,14,14,16,16,10,10,10,11,12,12,12,13,
+ 13,13,14,16,17,11,12,11,12,12,13,13,14,14,15,14,
+ 18,17,11,11,12,12,12,13,13,14,14,14,15,19,18,14,
+ 15,14,15,15,17,16,17,17,17,17,21, 0,14,15,15,16,
+ 16,16,16,17,17,18,17,20,21,
+};
+
+static const static_codebook _44u4__p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u4__p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44u4__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44u4__p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u4__p6_1[] = {
+ 2, 4, 4, 5, 5, 4, 5, 5, 6, 5, 4, 5, 5, 5, 6, 5,
+ 6, 5, 6, 6, 5, 5, 6, 6, 6,
+};
+
+static const static_codebook _44u4__p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44u4__p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u4__p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44u4__p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u4__p7_0[] = {
+ 1, 3, 3,12,12,12,12,12,12,12,12,12,12, 3,12,11,
+ 12,12,12,12,12,12,12,12,12,12, 4,11,10,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,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,
+};
+
+static const static_codebook _44u4__p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u4__p7_0,
+ 1, -514332672, 1627381760, 4, 0,
+ (long *)_vq_quantlist__44u4__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44u4__p7_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44u4__p7_1[] = {
+ 1, 4, 4, 6, 6, 7, 7, 9, 8,10, 8,10, 9,11,11, 4,
+ 7, 6, 8, 7, 9, 9,10,10,11,10,11,10,12,10, 4, 6,
+ 7, 8, 8, 9, 9,10,10,11,11,11,11,12,12, 6, 8, 8,
+ 10, 9,11,10,12,11,12,12,12,12,13,13, 6, 8, 8,10,
+ 10,10,11,11,11,12,12,13,12,13,13, 8, 9, 9,11,11,
+ 12,11,12,12,13,13,13,13,13,13, 8, 9, 9,11,11,11,
+ 12,12,12,13,13,13,13,13,13, 9,10,10,12,11,13,13,
+ 13,13,14,13,13,14,14,14, 9,10,11,11,12,12,13,13,
+ 13,13,13,14,15,14,14,10,11,11,12,12,13,13,14,14,
+ 14,14,14,15,16,16,10,11,11,12,13,13,13,13,15,14,
+ 14,15,16,15,16,10,12,12,13,13,14,14,14,15,15,15,
+ 15,15,15,16,11,12,12,13,13,14,14,14,15,15,15,16,
+ 15,17,16,11,12,12,13,13,13,15,15,14,16,16,16,16,
+ 16,17,11,12,12,13,13,14,14,15,14,15,15,17,17,16,
+ 16,
+};
+
+static const static_codebook _44u4__p7_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44u4__p7_1,
+ 1, -522338304, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44u4__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44u4__p7_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44u4__p7_2[] = {
+ 2, 5, 5, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 10,10,10,10, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,
+ 9,10, 9,10,10, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 10,10,10,10,10,10, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9,10,10,10,10,10,10, 8, 9, 8, 9, 9, 9, 9, 9, 9,
+ 10,10,10,10,10,10,10,10, 8, 8, 8, 9, 9, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10,10,
+ 10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10,
+ 10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,10,11,10,10,10, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9,
+ 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9,
+ 10, 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 9,10, 9,10,10,10,10,10,10,10,10,10,10,11,10,10,
+ 10,
+};
+
+static const static_codebook _44u4__p7_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44u4__p7_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44u4__p7_2,
+ 0
+};
+
+static const char _huff_lengthlist__44u4__short[] = {
+ 14,17,15,17,16,14,13,16,10, 7, 7,10,13,10,15,16,
+ 9, 4, 4, 6, 5, 7, 9,16,12, 8, 7, 8, 8, 8,11,16,
+ 14, 7, 4, 6, 3, 5, 8,15,13, 8, 5, 7, 4, 5, 7,16,
+ 12, 9, 6, 8, 3, 3, 5,16,14,13, 7,10, 5, 5, 7,15,
+};
+
+static const static_codebook _huff_book__44u4__short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44u4__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44u5__long[] = {
+ 3, 8,13,12,14,12,16,11,13,14, 5, 4, 5, 6, 7, 8,
+ 10, 9,12,15,10, 5, 5, 5, 6, 8, 9, 9,13,15,10, 5,
+ 5, 6, 6, 7, 8, 8,11,13,12, 7, 5, 6, 4, 6, 7, 7,
+ 11,14,11, 7, 7, 6, 6, 6, 7, 6,10,14,14, 9, 8, 8,
+ 6, 7, 7, 7,11,16,11, 8, 8, 7, 6, 6, 7, 4, 7,12,
+ 10,10,12,10,10, 9,10, 5, 6, 9,10,12,15,13,14,14,
+ 14, 8, 7, 8,
+};
+
+static const static_codebook _huff_book__44u5__long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44u5__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u5__p1_0[] = {
+ 1, 4, 4, 5, 8, 7, 5, 7, 7, 5, 8, 8, 8,10,10, 7,
+ 9,10, 5, 8, 8, 7,10, 9, 8,10,10, 5, 8, 8, 8,10,
+ 10, 8,10,10, 8,10,10,10,12,13,10,13,13, 7,10,10,
+ 10,13,11,10,13,13, 4, 8, 8, 8,11,10, 8,10,10, 7,
+ 10,10,10,13,13,10,11,13, 8,10,11,10,13,13,10,13,
+ 12,
+};
+
+static const static_codebook _44u5__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u5__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u5__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u5__p2_0[] = {
+ 3, 4, 4, 5, 6, 6, 5, 6, 6, 5, 6, 6, 6, 8, 8, 6,
+ 7, 8, 5, 6, 6, 6, 8, 7, 6, 8, 8, 5, 6, 6, 6, 8,
+ 8, 6, 8, 8, 6, 8, 8, 8, 9, 9, 8, 9, 9, 6, 8, 7,
+ 7, 9, 8, 8, 9, 9, 5, 6, 6, 6, 8, 7, 6, 8, 8, 6,
+ 8, 7, 8, 9, 9, 7, 8, 9, 6, 8, 8, 8, 9, 9, 8, 9,
+ 9,
+};
+
+static const static_codebook _44u5__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u5__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u5__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u5__p3_0[] = {
+ 2, 4, 5, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 8,
+ 10, 9,13,12, 8, 9,10,12,12, 5, 7, 7,10,10, 7, 9,
+ 9,11,11, 6, 8, 9,11,11,10,11,11,14,14, 9,10,11,
+ 13,14, 5, 7, 7, 9,10, 7, 9, 8,11,11, 7, 9, 9,11,
+ 11, 9,11,10,14,13,10,11,11,14,14, 8,10,10,13,13,
+ 10,11,11,15,14, 9,11,11,14,14,13,14,14,17,16,12,
+ 13,13,15,16, 8,10,10,13,13, 9,11,11,14,15,10,11,
+ 11,14,15,12,14,13,16,16,13,15,14,15,17, 5, 7, 7,
+ 10,10, 7, 9, 9,11,11, 7, 9, 9,11,11,10,11,11,14,
+ 14,10,11,12,14,14, 7, 9, 9,12,11, 9,11,11,13,13,
+ 9,11,11,13,13,12,13,13,15,16,11,12,13,15,16, 6,
+ 9, 9,11,11, 8,11,10,13,12, 9,11,11,13,14,11,13,
+ 12,16,14,11,13,13,16,17,10,12,11,15,15,11,13,13,
+ 16,16,11,13,13,17,16,14,15,15,17,17,14,16,16,17,
+ 18, 9,11,11,14,15,10,12,12,15,15,11,13,13,16,17,
+ 13,15,13,17,15,14,15,16,18, 0, 5, 7, 7,10,10, 7,
+ 9, 9,11,11, 7, 9, 9,11,11,10,11,11,14,14,10,11,
+ 12,14,15, 6, 9, 9,12,11, 9,11,11,13,13, 8,10,11,
+ 12,13,11,13,13,16,15,11,12,13,14,15, 7, 9, 9,11,
+ 12, 9,11,11,13,13, 9,11,11,13,13,11,13,13,15,16,
+ 11,13,13,15,14, 9,11,11,15,14,11,13,13,17,15,10,
+ 12,12,15,15,14,16,16,17,17,13,13,15,15,17,10,11,
+ 12,15,15,11,13,13,16,16,11,13,13,15,15,14,15,15,
+ 18,18,14,15,15,17,17, 8,10,10,13,13,10,12,11,15,
+ 15,10,11,12,15,15,14,15,15,18,18,13,14,14,18,18,
+ 9,11,11,15,16,11,13,13,17,17,11,13,13,16,16,15,
+ 15,16,17, 0,14,15,17, 0, 0, 9,11,11,15,15,10,13,
+ 12,18,16,11,13,13,15,16,14,16,15,20,20,14,15,16,
+ 17, 0,13,14,14,20,16,14,15,16,19,18,14,15,15,19,
+ 0,18,16, 0,20,20,16,18,18, 0, 0,12,14,14,18,18,
+ 13,15,14,18,16,14,15,16,18,20,16,19,16, 0,17,17,
+ 18,18,19, 0, 8,10,10,14,14,10,11,11,14,15,10,11,
+ 12,15,15,13,15,14,19,17,13,15,15,17, 0, 9,11,11,
+ 16,15,11,13,13,16,16,10,12,13,15,17,14,16,16,18,
+ 18,14,15,15,18, 0, 9,11,11,15,15,11,13,13,16,17,
+ 11,13,13,18,17,14,18,16,18,18,15,17,17,18, 0,12,
+ 14,14,18,18,14,15,15,20, 0,13,14,15,17, 0,16,18,
+ 17, 0, 0,16,16, 0,17,20,12,14,14,18,18,14,16,15,
+ 0,18,14,16,15,18, 0,16,19,17, 0, 0,17,18,16, 0,
+ 0,
+};
+
+static const static_codebook _44u5__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u5__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u5__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u5__p4_0[] = {
+ 4, 5, 5, 8, 8, 6, 7, 6, 9, 9, 6, 6, 7, 9, 9, 8,
+ 9, 9,11,11, 8, 9, 9,11,11, 6, 7, 7, 9, 9, 7, 8,
+ 8,10,10, 6, 7, 8, 9,10, 9,10,10,11,12, 9, 9,10,
+ 11,12, 6, 7, 7, 9, 9, 6, 8, 7,10, 9, 7, 8, 8,10,
+ 10, 9,10, 9,12,11, 9,10,10,12,11, 8, 9, 9,12,11,
+ 9,10,10,12,12, 9,10,10,12,12,11,12,12,13,14,11,
+ 11,12,13,14, 8, 9, 9,11,12, 9,10,10,12,12, 9,10,
+ 10,12,12,11,12,11,14,13,11,12,12,13,13, 5, 7, 7,
+ 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12,
+ 12, 9,10,10,12,12, 7, 8, 8,10,10, 8, 8, 9,10,11,
+ 8, 9, 9,11,11,10,10,11,11,13,10,11,11,12,13, 6,
+ 7, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11,
+ 10,13,11,10,11,11,12,12, 9,10,10,12,12,10,10,11,
+ 12,13,10,11,11,13,13,12,11,13,12,15,12,13,13,14,
+ 15, 9,10,10,12,12, 9,11,10,13,12,10,11,11,13,13,
+ 11,13,11,14,12,12,13,13,14,15, 5, 7, 7, 9, 9, 7,
+ 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12,12, 9,10,
+ 10,12,12, 6, 8, 7,10,10, 8, 9, 9,11,11, 7, 8, 9,
+ 10,11,10,11,11,12,12,10,10,11,11,13, 7, 8, 8,10,
+ 10, 8, 9, 9,11,11, 8, 9, 8,11,10,10,11,11,13,12,
+ 10,11,10,13,11, 9,10,10,12,12,10,11,11,13,12, 9,
+ 10,10,12,13,12,13,13,14,15,11,11,13,12,14, 9,10,
+ 10,12,12,10,11,11,13,13,10,11,10,13,12,12,13,13,
+ 14,14,12,13,11,14,12, 8, 9, 9,12,12, 9,10,10,12,
+ 12, 9,10,10,12,12,12,12,12,14,14,11,12,12,14,13,
+ 9,10,10,12,12,10,11,11,13,13,10,11,11,13,12,12,
+ 12,13,14,15,12,13,13,15,14, 9,10,10,12,12,10,11,
+ 10,13,12,10,11,11,12,13,12,13,12,15,13,12,13,13,
+ 14,15,11,12,12,14,13,11,12,12,14,15,12,13,13,15,
+ 14,13,12,14,12,16,13,14,14,15,15,11,11,12,14,14,
+ 11,12,11,14,13,12,13,13,14,15,13,14,12,16,12,14,
+ 14,15,16,16, 8, 9, 9,11,12, 9,10,10,12,12, 9,10,
+ 10,12,13,11,12,12,13,13,12,12,13,14,14, 9,10,10,
+ 12,12,10,11,10,13,12,10,10,11,12,13,12,13,13,15,
+ 14,12,12,13,13,15, 9,10,10,12,13,10,11,11,12,13,
+ 10,11,11,13,13,12,13,13,14,15,12,13,12,15,14,11,
+ 12,11,14,13,12,13,13,15,14,11,11,12,13,14,14,15,
+ 14,16,15,13,12,14,13,16,11,12,12,13,14,12,13,13,
+ 14,15,11,12,11,14,14,14,14,14,15,16,13,15,12,16,
+ 12,
+};
+
+static const static_codebook _44u5__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u5__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u5__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u5__p5_0[] = {
+ 2, 3, 3, 6, 6, 8, 8,10,10, 4, 5, 5, 8, 7, 8, 8,
+ 11,10, 3, 5, 5, 7, 8, 8, 8,10,11, 6, 8, 7,10, 9,
+ 10,10,11,11, 6, 7, 8, 9, 9, 9,10,11,12, 8, 8, 8,
+ 10,10,11,11,13,12, 8, 8, 9, 9,10,11,11,12,13,10,
+ 11,10,12,11,13,12,14,14,10,10,11,11,12,12,13,14,
+ 14,
+};
+
+static const static_codebook _44u5__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u5__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u5__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p6_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u5__p6_0[] = {
+ 3, 4, 4, 5, 5, 7, 7, 9, 9, 4, 5, 4, 6, 6, 7, 7,
+ 9, 9, 4, 4, 5, 6, 6, 7, 7, 9, 9, 5, 6, 6, 7, 7,
+ 8, 8,10,10, 6, 6, 6, 7, 7, 8, 8,10,10, 7, 7, 7,
+ 8, 8, 9, 9,11,10, 7, 7, 7, 8, 8, 9, 9,10,11, 9,
+ 9, 9,10,10,11,10,11,11, 9, 9, 9,10,10,11,10,11,
+ 11,
+};
+
+static const static_codebook _44u5__p6_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u5__p6_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u5__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u5__p7_0[] = {
+ 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 9, 9, 8,11,10, 7,
+ 11,10, 5, 9, 9, 7,10,10, 8,10,11, 4, 9, 9, 9,12,
+ 12, 9,12,12, 8,12,12,11,12,12,10,12,13, 7,12,12,
+ 11,12,12,10,12,13, 4, 9, 9, 9,12,12, 9,12,12, 7,
+ 12,11,10,13,13,11,12,12, 7,12,12,10,13,13,11,12,
+ 12,
+};
+
+static const static_codebook _44u5__p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u5__p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44u5__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u5__p7_1[] = {
+ 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 4, 5, 5, 7, 7,
+ 8, 8, 9, 8, 8, 9, 4, 5, 5, 7, 7, 8, 8, 9, 9, 8,
+ 9, 6, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 6, 7, 7, 8,
+ 8, 9, 9, 9, 9, 9, 9, 7, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9,
+ 9, 9, 9, 9,10,10,10,10, 8, 9, 9, 9, 9, 9, 9,10,
+ 10,10,10, 8, 9, 9, 9, 9, 9, 9,10,10,10,10, 8, 9,
+ 9, 9, 9, 9, 9,10,10,10,10,
+};
+
+static const static_codebook _44u5__p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u5__p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u5__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p8_0[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u5__p8_0[] = {
+ 1, 4, 4, 6, 6, 8, 8, 9, 9,10,10, 4, 6, 6, 7, 7,
+ 9, 9,10,10,11,11, 4, 6, 6, 7, 7, 9, 9,10,10,11,
+ 11, 6, 8, 7, 9, 9,10,10,11,11,13,12, 6, 8, 8, 9,
+ 9,10,10,11,11,12,13, 8, 9, 9,10,10,12,12,13,12,
+ 14,13, 8, 9, 9,10,10,12,12,13,13,14,14, 9,11,11,
+ 12,12,13,13,14,14,15,14, 9,11,11,12,12,13,13,14,
+ 14,15,14,11,12,12,13,13,14,14,15,14,15,14,11,11,
+ 12,13,13,14,14,14,14,15,15,
+};
+
+static const static_codebook _44u5__p8_0 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u5__p8_0,
+ 1, -524582912, 1618345984, 4, 0,
+ (long *)_vq_quantlist__44u5__p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p8_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u5__p8_1[] = {
+ 3, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 5, 6, 5, 7, 6,
+ 7, 7, 8, 8, 8, 8, 5, 5, 5, 6, 6, 7, 7, 8, 8, 8,
+ 8, 6, 7, 6, 7, 7, 8, 8, 8, 8, 8, 8, 6, 6, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8,
+ 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44u5__p8_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u5__p8_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u5__p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p9_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u5__p9_0[] = {
+ 1, 3, 2,12,10,13,13,13,13,13,13,13,13, 4, 9, 9,
+ 13,13,13,13,13,13,13,13,13,13, 5,10, 9,13,13,13,
+ 13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,13,
+ 13,13,13,13,11,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,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,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,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,
+};
+
+static const static_codebook _44u5__p9_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u5__p9_0,
+ 1, -514332672, 1627381760, 4, 0,
+ (long *)_vq_quantlist__44u5__p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p9_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44u5__p9_1[] = {
+ 1, 4, 4, 7, 7, 8, 8, 8, 7, 8, 7, 9, 8, 9, 9, 4,
+ 7, 6, 9, 8,10,10, 9, 8, 9, 9, 9, 9, 9, 8, 5, 6,
+ 6, 8, 9,10,10, 9, 9, 9,10,10,10,10,11, 7, 8, 8,
+ 10,10,11,11,10,10,11,11,11,12,11,11, 7, 8, 8,10,
+ 10,11,11,10,10,11,11,12,11,11,11, 8, 9, 9,11,11,
+ 12,12,11,11,12,11,12,12,12,12, 8, 9,10,11,11,12,
+ 12,11,11,12,12,12,12,12,12, 8, 9, 9,10,10,12,11,
+ 12,12,12,12,12,12,12,13, 8, 9, 9,11,11,11,11,12,
+ 12,12,12,13,12,13,13, 9,10,10,11,11,12,12,12,13,
+ 12,13,13,13,14,13, 9,10,10,11,11,12,12,12,13,13,
+ 12,13,13,14,13, 9,11,10,12,11,13,12,12,13,13,13,
+ 13,13,13,14, 9,10,10,12,12,12,12,12,13,13,13,13,
+ 13,14,14,10,11,11,12,12,12,13,13,13,14,14,13,14,
+ 14,14,10,11,11,12,12,12,12,13,12,13,14,13,14,14,
+ 14,
+};
+
+static const static_codebook _44u5__p9_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44u5__p9_1,
+ 1, -522338304, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44u5__p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44u5__p9_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44u5__p9_2[] = {
+ 2, 5, 5, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 5, 6, 6, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 5, 6, 6, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 7, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 7, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9,10, 9,10,10,10, 8, 8, 8, 9, 8, 9, 9, 9, 9, 9,
+ 9, 9,10, 9,10, 9,10, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9,10, 9,10,10,10,10,10, 8, 9, 9, 9, 9, 9, 9,10,
+ 9,10, 9,10,10,10,10,10,10, 9, 9, 9, 9, 9,10, 9,
+ 10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9,
+ 9,10, 9,10, 9,10,10,10,10,10,10, 9, 9, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9,
+ 9, 9,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9,
+ 9,10,10, 9,10,10,10,10,10,10,10,10,10,10, 9, 9,
+ 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10, 9,
+ 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10,
+ 9, 9, 9,10, 9,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _44u5__p9_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44u5__p9_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44u5__p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44u5__short[] = {
+ 4,10,17,13,17,13,17,17,17,17, 3, 6, 8, 9,11, 9,
+ 15,12,16,17, 6, 5, 5, 7, 7, 8,10,11,17,17, 7, 8,
+ 7, 9, 9,10,13,13,17,17, 8, 6, 5, 7, 4, 7, 5, 8,
+ 14,17, 9, 9, 8, 9, 7, 9, 8,10,16,17,12,10, 7, 8,
+ 4, 7, 4, 7,16,17,12,11, 9,10, 6, 9, 5, 7,14,17,
+ 14,13,10,15, 4, 8, 3, 5,14,17,17,14,11,15, 6,10,
+ 6, 8,15,17,
+};
+
+static const static_codebook _huff_book__44u5__short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44u5__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44u6__long[] = {
+ 3, 9,14,13,14,13,16,12,13,14, 5, 4, 6, 6, 8, 9,
+ 11,10,12,15,10, 5, 5, 6, 6, 8,10,10,13,16,10, 6,
+ 6, 6, 6, 8, 9, 9,12,14,13, 7, 6, 6, 4, 6, 6, 7,
+ 11,14,10, 7, 7, 7, 6, 6, 6, 7,10,13,15,10, 9, 8,
+ 5, 6, 5, 6,10,14,10, 9, 8, 8, 6, 6, 5, 4, 6,11,
+ 11,11,12,11,10, 9, 9, 5, 5, 9,10,12,15,13,13,13,
+ 13, 8, 7, 7,
+};
+
+static const static_codebook _huff_book__44u6__long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44u6__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u6__p1_0[] = {
+ 1, 4, 4, 4, 8, 7, 5, 7, 7, 5, 8, 8, 8,10,10, 7,
+ 9,10, 5, 8, 8, 7,10, 9, 8,10,10, 5, 8, 8, 8,10,
+ 10, 8,10,10, 8,10,10,10,12,13,10,13,13, 7,10,10,
+ 10,13,11,10,13,13, 5, 8, 8, 8,11,10, 8,10,10, 7,
+ 10,10,10,13,13,10,11,13, 8,10,11,10,13,13,10,13,
+ 12,
+};
+
+static const static_codebook _44u6__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u6__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u6__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u6__p2_0[] = {
+ 3, 4, 4, 5, 6, 6, 5, 6, 6, 5, 6, 6, 6, 8, 8, 6,
+ 7, 8, 5, 6, 6, 6, 8, 7, 6, 8, 8, 5, 6, 6, 6, 8,
+ 8, 6, 8, 8, 6, 8, 8, 8, 9, 9, 8, 9, 9, 6, 7, 7,
+ 7, 9, 8, 8, 9, 9, 5, 6, 6, 6, 8, 7, 6, 8, 8, 6,
+ 8, 8, 8, 9, 9, 7, 8, 9, 6, 8, 8, 8, 9, 9, 8, 9,
+ 9,
+};
+
+static const static_codebook _44u6__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u6__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u6__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u6__p3_0[] = {
+ 2, 5, 4, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 8,
+ 9, 9,13,12, 8, 9,10,12,13, 5, 7, 7,10, 9, 7, 9,
+ 9,11,11, 7, 8, 9,11,11,10,11,11,14,14, 9,10,11,
+ 13,14, 5, 7, 7, 9,10, 6, 9, 8,11,11, 7, 9, 9,11,
+ 11, 9,11,10,14,13,10,11,11,14,13, 8,10,10,13,13,
+ 10,11,11,15,15, 9,11,11,14,14,13,14,14,17,16,12,
+ 13,14,16,16, 8,10,10,13,14, 9,11,11,14,15,10,11,
+ 12,14,15,12,14,13,16,15,13,14,14,15,17, 5, 7, 7,
+ 10,10, 7, 9, 9,11,11, 7, 9, 9,11,11,10,12,11,14,
+ 14,10,11,11,14,14, 7, 9, 9,12,11, 9,11,11,13,13,
+ 9,11,11,13,13,11,13,13,14,15,11,12,13,15,16, 6,
+ 9, 9,11,12, 8,11,10,13,12, 9,11,11,13,14,11,13,
+ 12,16,14,11,13,13,15,16,10,12,11,14,15,11,13,13,
+ 15,17,11,13,13,17,16,15,15,16,17,16,14,15,16,18,
+ 0, 9,11,11,14,15,10,12,12,16,15,11,13,13,16,16,
+ 13,15,14,18,15,14,16,16, 0, 0, 5, 7, 7,10,10, 7,
+ 9, 9,11,11, 7, 9, 9,11,11,10,11,11,14,14,10,11,
+ 12,14,14, 6, 9, 9,11,11, 9,11,11,13,13, 8,10,11,
+ 12,13,11,13,13,16,15,11,12,13,14,16, 7, 9, 9,11,
+ 12, 9,11,11,13,13, 9,11,11,13,13,11,13,13,16,15,
+ 11,13,12,15,15, 9,11,11,15,14,11,13,13,17,16,10,
+ 12,13,15,16,14,16,16, 0,18,14,14,15,15,17,10,11,
+ 12,15,15,11,13,13,16,16,11,13,13,16,16,14,16,16,
+ 19,17,14,15,15,17,17, 8,10,10,14,14,10,12,11,15,
+ 15,10,11,12,16,15,14,15,15,18,20,13,14,16,17,18,
+ 9,11,11,15,16,11,13,13,17,17,11,13,13,17,16,15,
+ 16,16, 0, 0,15,16,16, 0, 0, 9,11,11,15,15,10,13,
+ 12,17,15,11,13,13,17,16,15,17,15,20,19,15,16,16,
+ 19, 0,13,15,14, 0,17,14,15,16, 0,20,15,16,16, 0,
+ 19,17,18, 0, 0, 0,16,17,18, 0, 0,12,14,14,19,18,
+ 13,15,14, 0,17,14,15,16,19,19,16,18,16, 0,19,19,
+ 20,17,20, 0, 8,10,10,13,14,10,11,11,15,15,10,12,
+ 12,15,16,14,15,14,19,16,14,15,15, 0,18, 9,11,11,
+ 16,15,11,13,13, 0,16,11,12,13,16,17,14,16,17, 0,
+ 19,15,16,16,18, 0, 9,11,11,15,16,11,13,13,16,16,
+ 11,14,13,18,17,15,16,16,18,20,15,17,19, 0, 0,12,
+ 14,14,17,17,14,16,15, 0, 0,13,14,15,19, 0,16,18,
+ 20, 0, 0,16,16,18,18, 0,12,14,14,17,20,14,16,16,
+ 19, 0,14,16,14, 0,20,16,20,17, 0, 0,17, 0,15, 0,
+ 19,
+};
+
+static const static_codebook _44u6__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u6__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u6__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u6__p4_0[] = {
+ 4, 5, 5, 8, 8, 6, 7, 6, 9, 9, 6, 6, 7, 9, 9, 8,
+ 9, 9,11,11, 8, 9, 9,11,11, 6, 7, 7, 9, 9, 7, 8,
+ 8,10,10, 7, 7, 8, 9,10, 9,10,10,11,11, 9, 9,10,
+ 11,12, 6, 7, 7, 9, 9, 7, 8, 7,10, 9, 7, 8, 8,10,
+ 10, 9,10, 9,12,11, 9,10,10,12,11, 8, 9, 9,11,11,
+ 9,10,10,12,12, 9,10,10,12,12,11,12,12,14,13,11,
+ 11,12,13,13, 8, 9, 9,11,11, 9,10,10,12,12, 9,10,
+ 10,12,12,11,12,11,13,12,11,12,12,13,13, 5, 7, 7,
+ 9, 9, 7, 8, 7,10,10, 7, 7, 8,10,10, 9,10,10,12,
+ 11, 9,10,10,11,12, 7, 8, 8,10,10, 8, 8, 9,11,11,
+ 8, 9, 9,11,11,10,10,11,12,13,10,10,11,12,12, 6,
+ 7, 7,10,10, 7, 9, 8,11,10, 8, 8, 9,10,11,10,11,
+ 10,13,11,10,11,11,12,12, 9,10,10,12,12,10,10,11,
+ 13,13,10,11,11,12,13,12,12,12,13,14,12,12,13,14,
+ 14, 9,10,10,12,12, 9,10,10,13,12,10,11,11,13,13,
+ 11,12,11,14,12,12,13,13,14,14, 6, 7, 7, 9, 9, 7,
+ 8, 7,10,10, 7, 8, 8,10,10, 9,10,10,12,11, 9,10,
+ 10,11,12, 6, 7, 7,10,10, 8, 9, 8,11,10, 7, 8, 9,
+ 10,11,10,11,11,12,12,10,10,11,11,13, 7, 8, 8,10,
+ 10, 8, 9, 9,11,11, 8, 9, 8,11,11,10,11,10,13,12,
+ 10,11,11,13,12, 9,10,10,12,12,10,11,11,13,12, 9,
+ 10,10,12,13,12,13,12,14,14,11,11,12,12,14, 9,10,
+ 10,12,12,10,11,11,13,13,10,11,10,13,12,12,12,12,
+ 14,14,12,13,12,14,13, 8, 9, 9,11,11, 9,10,10,12,
+ 12, 9,10,10,12,12,11,12,12,14,13,11,12,12,13,14,
+ 9,10,10,12,12,10,11,11,13,13,10,11,11,13,13,12,
+ 12,13,14,15,12,12,13,14,14, 9,10,10,12,12, 9,11,
+ 10,13,12,10,10,11,12,13,12,13,12,14,13,12,12,13,
+ 14,15,11,12,12,14,13,11,12,12,14,14,12,13,13,14,
+ 14,13,13,14,14,16,13,14,14,15,15,11,12,11,13,13,
+ 11,12,11,14,13,12,12,13,14,15,12,14,12,15,12,13,
+ 14,15,15,16, 8, 9, 9,11,11, 9,10,10,12,12, 9,10,
+ 10,12,12,11,12,12,14,13,11,12,12,13,13, 9,10,10,
+ 12,12,10,11,10,13,12, 9,10,11,12,13,12,13,12,14,
+ 14,12,12,13,13,14, 9,10,10,12,12,10,11,11,13,13,
+ 10,11,11,13,13,12,13,12,14,14,12,13,13,14,14,11,
+ 11,11,13,13,12,13,12,14,14,11,11,12,13,14,14,14,
+ 14,16,15,12,12,14,12,15,11,12,12,13,14,12,13,13,
+ 14,15,11,12,12,14,14,13,14,14,16,16,13,14,13,16,
+ 13,
+};
+
+static const static_codebook _44u6__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u6__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u6__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u6__p5_0[] = {
+ 2, 3, 3, 6, 6, 8, 8,10,10, 4, 5, 5, 8, 7, 8, 8,
+ 11,11, 3, 5, 5, 7, 8, 8, 8,11,11, 6, 8, 7, 9, 9,
+ 10, 9,12,11, 6, 7, 8, 9, 9, 9,10,11,12, 8, 8, 8,
+ 10, 9,12,11,13,13, 8, 8, 9, 9,10,11,12,13,13,10,
+ 11,11,12,12,13,13,14,14,10,10,11,11,12,13,13,14,
+ 14,
+};
+
+static const static_codebook _44u6__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u6__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u6__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p6_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u6__p6_0[] = {
+ 3, 4, 4, 5, 5, 7, 7, 9, 9, 4, 5, 4, 6, 6, 7, 7,
+ 9, 9, 4, 4, 5, 6, 6, 7, 8, 9, 9, 5, 6, 6, 7, 7,
+ 8, 8,10,10, 5, 6, 6, 7, 7, 8, 8,10,10, 7, 8, 7,
+ 8, 8,10, 9,11,11, 7, 7, 8, 8, 8, 9,10,10,11, 9,
+ 9, 9,10,10,11,11,12,11, 9, 9, 9,10,10,11,11,11,
+ 12,
+};
+
+static const static_codebook _44u6__p6_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u6__p6_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u6__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u6__p7_0[] = {
+ 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 9, 8, 7,10,10, 8,
+ 10,10, 5, 8, 9, 7,10,10, 7,10, 9, 4, 8, 8, 9,11,
+ 11, 8,11,11, 7,11,11,10,10,13,10,13,13, 7,11,11,
+ 10,13,12,10,13,13, 5, 9, 8, 8,11,11, 9,11,11, 7,
+ 11,11,10,13,13,10,12,13, 7,11,11,10,13,13, 9,13,
+ 10,
+};
+
+static const static_codebook _44u6__p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u6__p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44u6__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u6__p7_1[] = {
+ 3, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 4, 5, 5, 7, 6,
+ 8, 8, 8, 8, 8, 8, 4, 5, 5, 6, 7, 8, 8, 8, 8, 8,
+ 8, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 6, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 8, 8, 8,
+ 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 8, 8,
+ 8, 8, 8, 9, 9, 9, 9, 9, 9,
+};
+
+static const static_codebook _44u6__p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u6__p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u6__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p8_0[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u6__p8_0[] = {
+ 1, 4, 4, 6, 6, 8, 8, 9, 9,10,10, 4, 6, 6, 7, 7,
+ 9, 9,10,10,11,11, 4, 6, 6, 7, 7, 9, 9,10,10,11,
+ 11, 6, 8, 8, 9, 9,10,10,11,11,12,12, 6, 8, 8, 9,
+ 9,10,10,11,11,12,12, 8, 9, 9,10,10,11,11,12,12,
+ 13,13, 8, 9, 9,10,10,11,11,12,12,13,13,10,10,10,
+ 11,11,13,13,13,13,15,14, 9,10,10,12,11,12,13,13,
+ 13,14,15,11,12,12,13,13,13,13,15,14,15,15,11,11,
+ 12,13,13,14,14,14,15,15,15,
+};
+
+static const static_codebook _44u6__p8_0 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u6__p8_0,
+ 1, -524582912, 1618345984, 4, 0,
+ (long *)_vq_quantlist__44u6__p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p8_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u6__p8_1[] = {
+ 3, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 5, 6, 5, 7, 7,
+ 7, 7, 8, 7, 8, 8, 5, 5, 6, 6, 7, 7, 7, 7, 7, 8,
+ 8, 6, 7, 7, 7, 7, 8, 7, 8, 8, 8, 8, 6, 6, 7, 7,
+ 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8,
+ 8, 8, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44u6__p8_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u6__p8_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u6__p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p9_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44u6__p9_0[] = {
+ 1, 3, 2, 9, 8,15,15,15,15,15,15,15,15,15,15, 4,
+ 8, 9,13,14,14,14,14,14,14,14,14,14,14,14, 5, 8,
+ 9,14,14,14,14,14,14,14,14,14,14,14,14,11,14,14,
+ 14,14,14,14,14,14,14,14,14,14,14,14,11,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,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,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,
+};
+
+static const static_codebook _44u6__p9_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44u6__p9_0,
+ 1, -514071552, 1627381760, 4, 0,
+ (long *)_vq_quantlist__44u6__p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p9_1[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44u6__p9_1[] = {
+ 1, 4, 4, 7, 7, 8, 9, 8, 8, 9, 8, 9, 8, 9, 9, 4,
+ 7, 6, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 4, 7,
+ 6, 9, 9,10,10, 9, 9,10,10,10,10,11,11, 7, 9, 8,
+ 10,10,11,11,10,10,11,11,11,11,11,11, 7, 8, 9,10,
+ 10,11,11,10,10,11,11,11,11,11,12, 8,10,10,11,11,
+ 12,12,11,11,12,12,12,12,13,12, 8,10,10,11,11,12,
+ 11,11,11,11,12,12,12,12,13, 8, 9, 9,11,10,11,11,
+ 12,12,12,12,13,12,13,12, 8, 9, 9,11,11,11,11,12,
+ 12,12,12,12,13,13,13, 9,10,10,11,12,12,12,12,12,
+ 13,13,13,13,13,13, 9,10,10,11,11,12,12,12,12,13,
+ 13,13,13,14,13,10,10,10,12,11,12,12,13,13,13,13,
+ 13,13,13,13,10,10,11,11,11,12,12,13,13,13,13,13,
+ 13,13,13,10,11,11,12,12,13,12,12,13,13,13,13,13,
+ 13,14,10,11,11,12,12,13,12,13,13,13,14,13,13,14,
+ 13,
+};
+
+static const static_codebook _44u6__p9_1 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44u6__p9_1,
+ 1, -522338304, 1620115456, 4, 0,
+ (long *)_vq_quantlist__44u6__p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44u6__p9_2[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44u6__p9_2[] = {
+ 3, 5, 5, 7, 7, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 9,
+ 9, 5, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 5, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10, 9, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10, 9, 9, 9,10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,10, 9, 9, 9,10, 9, 9,10, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 9,10, 9,10,10,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, 9,10,10, 9, 9,
+ 10,
+};
+
+static const static_codebook _44u6__p9_2 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44u6__p9_2,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44u6__p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44u6__short[] = {
+ 4,11,16,13,17,13,17,16,17,17, 4, 7, 9, 9,13,10,
+ 16,12,16,17, 7, 6, 5, 7, 8, 9,12,12,16,17, 6, 9,
+ 7, 9,10,10,15,15,17,17, 6, 7, 5, 7, 5, 7, 7,10,
+ 16,17, 7, 9, 8, 9, 8,10,11,11,15,17, 7, 7, 7, 8,
+ 5, 8, 8, 9,15,17, 8, 7, 9, 9, 7, 8, 7, 2, 7,15,
+ 14,13,13,15, 5,10, 4, 3, 6,17,17,15,13,17, 7,11,
+ 7, 6, 9,16,
+};
+
+static const static_codebook _huff_book__44u6__short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44u6__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44u7__long[] = {
+ 3, 9,14,13,15,14,16,13,13,14, 5, 5, 7, 7, 8, 9,
+ 11,10,12,15,10, 6, 5, 6, 6, 9,10,10,13,16,10, 6,
+ 6, 6, 6, 8, 9, 9,12,15,14, 7, 6, 6, 5, 6, 6, 8,
+ 12,15,10, 8, 7, 7, 6, 7, 7, 7,11,13,14,10, 9, 8,
+ 5, 6, 4, 5, 9,12,10, 9, 9, 8, 6, 6, 5, 3, 6,11,
+ 12,11,12,12,10, 9, 8, 5, 5, 8,10,11,15,13,13,13,
+ 12, 8, 6, 7,
+};
+
+static const static_codebook _huff_book__44u7__long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44u7__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u7__p1_0[] = {
+ 1, 4, 4, 4, 7, 7, 5, 7, 7, 5, 8, 8, 8,10,10, 7,
+ 10,10, 5, 8, 8, 7,10,10, 8,10,10, 5, 8, 8, 8,11,
+ 10, 8,10,10, 8,10,10,10,12,13,10,13,13, 7,10,10,
+ 10,13,12,10,13,13, 5, 8, 8, 8,11,10, 8,10,11, 7,
+ 10,10,10,13,13,10,12,13, 8,11,11,10,13,13,10,13,
+ 12,
+};
+
+static const static_codebook _44u7__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u7__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u7__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u7__p2_0[] = {
+ 3, 4, 4, 5, 6, 6, 5, 6, 6, 5, 6, 6, 6, 8, 8, 6,
+ 7, 8, 5, 6, 6, 6, 8, 7, 6, 8, 8, 5, 6, 6, 6, 8,
+ 7, 6, 8, 8, 6, 8, 8, 8, 9, 9, 8, 9, 9, 6, 8, 7,
+ 7, 9, 8, 8, 9, 9, 5, 6, 6, 6, 8, 7, 6, 8, 8, 6,
+ 8, 8, 8, 9, 9, 7, 8, 9, 6, 8, 8, 8, 9, 9, 8, 9,
+ 9,
+};
+
+static const static_codebook _44u7__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u7__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u7__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u7__p3_0[] = {
+ 2, 5, 4, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 8,
+ 9, 9,13,12, 8, 9,10,12,13, 5, 7, 7,10, 9, 7, 9,
+ 9,11,11, 6, 8, 9,11,11,10,11,11,14,14, 9,10,11,
+ 13,14, 5, 7, 7, 9, 9, 7, 9, 8,11,11, 7, 9, 9,11,
+ 11, 9,11,10,14,13,10,11,11,14,14, 8,10,10,14,13,
+ 10,11,12,15,14, 9,11,11,15,14,13,14,14,16,16,12,
+ 13,14,17,16, 8,10,10,13,13, 9,11,11,14,15,10,11,
+ 12,14,15,12,14,13,16,16,13,14,15,15,17, 5, 7, 7,
+ 10,10, 7, 9, 9,11,11, 7, 9, 9,11,11,10,12,11,15,
+ 14,10,11,12,14,14, 7, 9, 9,12,12, 9,11,11,13,13,
+ 9,11,11,13,13,11,13,13,14,17,11,13,13,15,16, 6,
+ 9, 9,11,11, 8,11,10,13,12, 9,11,11,13,13,11,13,
+ 12,16,14,11,13,13,16,16,10,12,12,15,15,11,13,13,
+ 16,16,11,13,13,16,15,14,16,17,17,19,14,16,16,18,
+ 0, 9,11,11,14,15,10,13,12,16,15,11,13,13,16,16,
+ 14,15,14, 0,16,14,16,16,18, 0, 5, 7, 7,10,10, 7,
+ 9, 9,12,11, 7, 9, 9,11,12,10,11,11,15,14,10,11,
+ 12,14,14, 6, 9, 9,11,11, 9,11,11,13,13, 8,10,11,
+ 12,13,11,13,13,17,15,11,12,13,14,15, 7, 9, 9,11,
+ 12, 9,11,11,13,13, 9,11,11,13,13,11,13,12,16,16,
+ 11,13,13,15,14, 9,11,11,14,15,11,13,13,16,15,10,
+ 12,13,16,16,15,16,16, 0, 0,14,13,15,16,18,10,11,
+ 11,15,15,11,13,14,16,18,11,13,13,16,15,15,16,16,
+ 19, 0,14,15,15,16,16, 8,10,10,13,13,10,12,11,16,
+ 15,10,11,11,16,15,13,15,16,18, 0,13,14,15,17,17,
+ 9,11,11,15,15,11,13,13,16,18,11,13,13,16,17,15,
+ 16,16, 0, 0,15,18,16, 0,17, 9,11,11,15,15,11,13,
+ 12,17,15,11,13,14,16,17,15,18,15, 0,17,15,16,16,
+ 18,19,13,15,14, 0,18,14,16,16,19,18,14,16,15,19,
+ 19,16,18,19, 0, 0,16,17, 0, 0, 0,12,14,14,17,17,
+ 13,16,14, 0,18,14,16,15,18, 0,16,18,16,19,17,18,
+ 19,17, 0, 0, 8,10,10,14,14, 9,12,11,15,15,10,11,
+ 12,15,17,13,15,15,18,16,14,16,15,18,17, 9,11,11,
+ 16,15,11,13,13, 0,16,11,12,13,16,15,15,16,16, 0,
+ 17,15,15,16,18,17, 9,12,11,15,17,11,13,13,16,16,
+ 11,14,13,16,16,15,15,16,18,19,16,18,16, 0, 0,12,
+ 14,14, 0,16,14,16,16, 0,18,13,14,15,16, 0,17,16,
+ 18, 0, 0,16,16,17,19, 0,13,14,14,17, 0,14,17,16,
+ 0,19,14,15,15,18,19,17,16,18, 0, 0,15,19,16, 0,
+ 0,
+};
+
+static const static_codebook _44u7__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u7__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u7__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u7__p4_0[] = {
+ 4, 5, 5, 8, 8, 6, 7, 6, 9, 9, 6, 6, 7, 9, 9, 8,
+ 9, 9,11,11, 8, 9, 9,10,11, 6, 7, 7, 9, 9, 7, 8,
+ 8,10,10, 6, 7, 8, 9,10, 9,10,10,12,12, 9, 9,10,
+ 11,12, 6, 7, 7, 9, 9, 6, 8, 7,10, 9, 7, 8, 8,10,
+ 10, 9,10, 9,12,11, 9,10,10,12,11, 8, 9, 9,11,11,
+ 9,10,10,12,12, 9,10,10,12,12,11,12,12,13,14,11,
+ 11,12,13,13, 8, 9, 9,11,11, 9,10,10,12,11, 9,10,
+ 10,12,12,11,12,11,13,13,11,12,12,13,13, 6, 7, 7,
+ 9, 9, 7, 8, 7,10,10, 7, 7, 8,10,10, 9,10,10,12,
+ 11, 9,10,10,12,12, 7, 8, 8,10,10, 8, 8, 9,11,11,
+ 8, 9, 9,11,11,10,11,11,12,12,10,10,11,12,13, 6,
+ 7, 7,10,10, 7, 9, 8,11,10, 8, 8, 9,10,11,10,11,
+ 10,13,11,10,11,11,12,12, 9,10,10,12,12,10,10,11,
+ 13,13,10,11,11,13,12,12,12,13,13,14,12,12,13,14,
+ 14, 9,10,10,12,12, 9,10,10,12,12,10,11,11,13,13,
+ 11,12,11,14,12,12,13,13,14,14, 6, 7, 7, 9, 9, 7,
+ 8, 7,10,10, 7, 7, 8,10,10, 9,10,10,12,11, 9,10,
+ 10,11,12, 6, 7, 7,10,10, 8, 9, 8,11,10, 7, 8, 9,
+ 10,11,10,11,11,13,12,10,10,11,11,13, 7, 8, 8,10,
+ 10, 8, 9, 9,11,11, 8, 9, 9,11,11,10,11,10,13,12,
+ 10,11,11,12,12, 9,10,10,12,12,10,11,11,13,12, 9,
+ 10,10,12,13,12,13,12,14,14,11,11,12,12,14, 9,10,
+ 10,12,12,10,11,11,13,13,10,11,11,13,13,12,13,12,
+ 14,14,12,13,12,14,13, 8, 9, 9,11,11, 9,10,10,12,
+ 12, 9,10,10,12,12,11,12,12,14,13,11,12,12,13,13,
+ 9,10,10,12,12,10,11,11,13,13,10,11,11,13,12,12,
+ 13,13,14,14,12,12,13,14,14, 9,10,10,12,12, 9,11,
+ 10,13,12,10,10,11,12,13,11,13,12,14,13,12,12,13,
+ 14,14,11,12,12,13,13,11,12,13,14,14,12,13,13,14,
+ 14,13,13,14,14,16,13,14,14,16,16,11,11,11,13,13,
+ 11,12,11,14,13,12,12,13,14,15,13,14,12,16,13,14,
+ 14,14,15,16, 8, 9, 9,11,11, 9,10,10,12,12, 9,10,
+ 10,12,12,11,12,12,14,13,11,12,12,13,14, 9,10,10,
+ 12,12,10,11,10,13,12, 9,10,11,12,13,12,13,12,14,
+ 14,12,12,13,13,14, 9,10,10,12,12,10,11,11,12,13,
+ 10,11,11,13,13,12,13,12,14,14,12,13,13,14,14,11,
+ 12,12,13,13,12,13,12,14,14,11,11,12,13,14,13,15,
+ 14,16,15,13,12,14,13,16,11,12,12,13,13,12,13,13,
+ 14,14,12,12,12,14,14,13,14,14,15,15,13,14,13,16,
+ 14,
+};
+
+static const static_codebook _44u7__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u7__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u7__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u7__p5_0[] = {
+ 2, 3, 3, 6, 6, 7, 8,10,10, 4, 5, 5, 8, 7, 8, 8,
+ 11,11, 3, 5, 5, 7, 7, 8, 9,11,11, 6, 8, 7, 9, 9,
+ 10,10,12,12, 6, 7, 8, 9,10,10,10,12,12, 8, 8, 8,
+ 10,10,12,11,13,13, 8, 8, 9,10,10,11,11,13,13,10,
+ 11,11,12,12,13,13,14,14,10,11,11,12,12,13,13,14,
+ 14,
+};
+
+static const static_codebook _44u7__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u7__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u7__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p6_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u7__p6_0[] = {
+ 3, 4, 4, 5, 5, 7, 7, 9, 9, 4, 5, 4, 6, 6, 8, 7,
+ 9, 9, 4, 4, 5, 6, 6, 7, 7, 9, 9, 5, 6, 6, 7, 7,
+ 8, 8,10,10, 5, 6, 6, 7, 7, 8, 8,10,10, 7, 8, 7,
+ 8, 8,10, 9,11,11, 7, 7, 8, 8, 8, 9,10,11,11, 9,
+ 9, 9,10,10,11,10,12,11, 9, 9, 9,10,10,11,11,11,
+ 12,
+};
+
+static const static_codebook _44u7__p6_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u7__p6_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u7__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p7_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u7__p7_0[] = {
+ 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 9, 8, 8, 9, 9, 7,
+ 10,10, 5, 8, 9, 7, 9,10, 8, 9, 9, 4, 9, 9, 9,11,
+ 10, 8,10,10, 7,11,10,10,10,12,10,12,12, 7,10,10,
+ 10,12,11,10,12,12, 5, 9, 9, 8,10,10, 9,11,11, 7,
+ 11,10,10,12,12,10,11,12, 7,10,11,10,12,12,10,12,
+ 10,
+};
+
+static const static_codebook _44u7__p7_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u7__p7_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44u7__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u7__p7_1[] = {
+ 3, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 4, 5, 5, 6, 6,
+ 8, 7, 8, 8, 8, 8, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,
+ 8, 6, 7, 6, 7, 7, 8, 8, 9, 9, 9, 9, 6, 6, 7, 7,
+ 7, 8, 8, 9, 9, 9, 9, 7, 8, 7, 8, 8, 9, 9, 9, 9,
+ 9, 9, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8,
+ 9, 9, 9, 9,10, 9, 9, 9, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9,10, 8, 8, 8, 9, 9, 9, 9,10, 9,10,10, 8, 8,
+ 8, 9, 9, 9, 9, 9,10,10,10,
+};
+
+static const static_codebook _44u7__p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u7__p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u7__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p8_0[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u7__p8_0[] = {
+ 1, 4, 4, 6, 6, 8, 8,10,10,11,11, 4, 6, 6, 7, 7,
+ 9, 9,11,10,12,12, 5, 6, 5, 7, 7, 9, 9,10,11,12,
+ 12, 6, 7, 7, 8, 8,10,10,11,11,13,13, 6, 7, 7, 8,
+ 8,10,10,11,12,13,13, 8, 9, 9,10,10,11,11,12,12,
+ 14,14, 8, 9, 9,10,10,11,11,12,12,14,14,10,10,10,
+ 11,11,13,12,14,14,15,15,10,10,10,12,12,13,13,14,
+ 14,15,15,11,12,12,13,13,14,14,15,14,16,15,11,12,
+ 12,13,13,14,14,15,15,15,16,
+};
+
+static const static_codebook _44u7__p8_0 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u7__p8_0,
+ 1, -524582912, 1618345984, 4, 0,
+ (long *)_vq_quantlist__44u7__p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p8_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u7__p8_1[] = {
+ 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 5, 6, 6, 7, 7,
+ 7, 7, 7, 7, 7, 7, 5, 6, 6, 6, 7, 7, 7, 7, 7, 7,
+ 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 6, 7, 7, 7,
+ 7, 7, 7, 7, 7, 8, 8, 7, 7, 7, 7, 7, 8, 7, 8, 8,
+ 8, 8, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7,
+ 7, 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 8, 8, 8,
+ 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44u7__p8_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u7__p8_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u7__p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p9_0[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u7__p9_0[] = {
+ 1, 3, 3,10,10,10,10,10,10,10,10, 4,10,10,10,10,
+ 10,10,10,10,10,10, 4,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,
+};
+
+static const static_codebook _44u7__p9_0 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u7__p9_0,
+ 1, -512171520, 1630791680, 4, 0,
+ (long *)_vq_quantlist__44u7__p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p9_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u7__p9_1[] = {
+ 1, 4, 4, 6, 5, 8, 6, 9, 8,10, 9,11,10, 4, 6, 6,
+ 8, 8, 9, 9,11,10,11,11,11,11, 4, 6, 6, 8, 8,10,
+ 9,11,11,11,11,11,12, 6, 8, 8,10,10,11,11,12,12,
+ 13,12,13,13, 6, 8, 8,10,10,11,11,12,12,12,13,14,
+ 13, 8,10,10,11,11,12,13,14,14,14,14,15,15, 8,10,
+ 10,11,12,12,13,13,14,14,14,14,15, 9,11,11,13,13,
+ 14,14,15,14,16,15,17,15, 9,11,11,12,13,14,14,15,
+ 14,15,15,15,16,10,12,12,13,14,15,15,15,15,16,17,
+ 16,17,10,13,12,13,14,14,16,16,16,16,15,16,17,11,
+ 13,13,14,15,14,17,15,16,17,17,17,17,11,13,13,14,
+ 15,15,15,15,17,17,16,17,16,
+};
+
+static const static_codebook _44u7__p9_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u7__p9_1,
+ 1, -518889472, 1622704128, 4, 0,
+ (long *)_vq_quantlist__44u7__p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44u7__p9_2[] = {
+ 24,
+ 23,
+ 25,
+ 22,
+ 26,
+ 21,
+ 27,
+ 20,
+ 28,
+ 19,
+ 29,
+ 18,
+ 30,
+ 17,
+ 31,
+ 16,
+ 32,
+ 15,
+ 33,
+ 14,
+ 34,
+ 13,
+ 35,
+ 12,
+ 36,
+ 11,
+ 37,
+ 10,
+ 38,
+ 9,
+ 39,
+ 8,
+ 40,
+ 7,
+ 41,
+ 6,
+ 42,
+ 5,
+ 43,
+ 4,
+ 44,
+ 3,
+ 45,
+ 2,
+ 46,
+ 1,
+ 47,
+ 0,
+ 48,
+};
+
+static const char _vq_lengthlist__44u7__p9_2[] = {
+ 2, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8,
+ 8,
+};
+
+static const static_codebook _44u7__p9_2 = {
+ 1, 49,
+ (char *)_vq_lengthlist__44u7__p9_2,
+ 1, -526909440, 1611661312, 6, 0,
+ (long *)_vq_quantlist__44u7__p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44u7__short[] = {
+ 5,12,17,16,16,17,17,17,17,17, 4, 7,11,11,12, 9,
+ 17,10,17,17, 7, 7, 8, 9, 7, 9,11,10,15,17, 7, 9,
+ 10,11,10,12,14,12,16,17, 7, 8, 5, 7, 4, 7, 7, 8,
+ 16,16, 6,10, 9,10, 7,10,11,11,16,17, 6, 8, 8, 9,
+ 5, 7, 5, 8,16,17, 5, 5, 8, 7, 6, 7, 7, 6, 6,14,
+ 12,10,12,11, 7,11, 4, 4, 2, 7,17,15,15,15, 8,15,
+ 6, 8, 5, 9,
+};
+
+static const static_codebook _huff_book__44u7__short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44u7__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44u8__long[] = {
+ 3, 9,13,14,14,15,14,14,15,15, 5, 4, 6, 8,10,12,
+ 12,14,15,15, 9, 5, 4, 5, 8,10,11,13,16,16,10, 7,
+ 4, 3, 5, 7, 9,11,13,13,10, 9, 7, 4, 4, 6, 8,10,
+ 12,14,13,11, 9, 6, 5, 5, 6, 8,12,14,13,11,10, 8,
+ 7, 6, 6, 7,10,14,13,11,12,10, 8, 7, 6, 6, 9,13,
+ 12,11,14,12,11, 9, 8, 7, 9,11,11,12,14,13,14,11,
+ 10, 8, 8, 9,
+};
+
+static const static_codebook _huff_book__44u8__long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44u8__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44u8__short[] = {
+ 6,14,18,18,17,17,17,17,17,17, 4, 7, 9, 9,10,13,
+ 15,17,17,17, 6, 7, 5, 6, 8,11,16,17,16,17, 5, 7,
+ 5, 4, 6,10,14,17,17,17, 6, 6, 6, 5, 7,10,13,16,
+ 17,17, 7, 6, 7, 7, 7, 8, 7,10,15,16,12, 9, 9, 6,
+ 6, 5, 3, 5,11,15,14,14,13, 5, 5, 7, 3, 4, 8,15,
+ 17,17,13, 7, 7,10, 6, 6,10,15,17,17,16,10,11,14,
+ 10,10,15,17,
+};
+
+static const static_codebook _huff_book__44u8__short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44u8__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u8_p1_0[] = {
+ 1, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 8, 9, 9, 7,
+ 9, 9, 5, 7, 7, 7, 9, 9, 8, 9, 9, 5, 7, 7, 7, 9,
+ 9, 7, 9, 9, 7, 9, 9, 9,10,11, 9,11,10, 7, 9, 9,
+ 9,11,10, 9,10,11, 5, 7, 7, 7, 9, 9, 7, 9, 9, 7,
+ 9, 9, 9,11,10, 9,10,10, 8, 9, 9, 9,11,11, 9,11,
+ 10,
+};
+
+static const static_codebook _44u8_p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u8_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u8_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u8_p2_0[] = {
+ 4, 5, 5, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 8,
+ 9, 9,11,11, 8, 9, 9,11,11, 5, 7, 7, 9, 9, 7, 8,
+ 8,10,10, 7, 8, 8,10,10, 9,10,10,12,12, 9,10,10,
+ 11,12, 5, 7, 7, 9, 9, 7, 8, 7,10,10, 7, 8, 8,10,
+ 10, 9,10, 9,12,11, 9,10,10,12,12, 8, 9, 9,12,11,
+ 9,10,10,12,12, 9,10,10,12,12,11,12,12,14,14,11,
+ 11,12,13,14, 8, 9, 9,11,11, 9,10,10,12,12, 9,10,
+ 10,12,12,11,12,11,13,13,11,12,12,14,14, 5, 7, 7,
+ 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12,
+ 12, 9,10,10,11,12, 7, 8, 8,10,10, 8, 9, 9,11,11,
+ 8, 9, 9,11,11,10,11,11,12,13,10,11,11,12,13, 6,
+ 8, 8,10,10, 8, 9, 8,11,10, 8, 9, 9,11,11,10,11,
+ 10,13,12,10,11,11,13,13, 9,10,10,12,12,10,11,11,
+ 13,13,10,11,11,13,13,12,12,13,13,14,12,13,13,14,
+ 14, 9,10,10,12,12,10,11,10,13,12,10,11,11,13,13,
+ 11,13,12,14,13,12,13,13,14,14, 5, 7, 7, 9, 9, 7,
+ 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12,12, 9,10,
+ 10,12,12, 7, 8, 8,10,10, 8, 9, 9,11,11, 8, 8, 9,
+ 10,11,10,11,11,13,13,10,10,11,12,13, 7, 8, 8,10,
+ 10, 8, 9, 9,11,11, 8, 9, 9,11,11,10,11,11,13,13,
+ 10,11,11,13,12, 9,10,10,12,12,10,11,11,13,13,10,
+ 10,11,12,13,12,13,13,14,14,12,12,13,13,14, 9,10,
+ 10,12,12,10,11,11,13,13,10,11,11,13,13,12,13,13,
+ 15,14,12,13,13,14,13, 8, 9, 9,11,11, 9,10,10,12,
+ 12, 9,10,10,12,12,12,12,12,14,13,11,12,12,14,14,
+ 9,10,10,12,12,10,11,11,13,13,10,11,11,13,13,12,
+ 13,13,14,15,12,13,13,14,15, 9,10,10,12,12,10,11,
+ 10,13,12,10,11,11,13,13,12,13,12,15,14,12,13,13,
+ 14,15,11,12,12,14,14,12,13,13,14,14,12,13,13,15,
+ 14,14,14,14,14,16,14,14,15,16,16,11,12,12,14,14,
+ 11,12,12,14,14,12,13,13,14,15,13,14,13,16,14,14,
+ 14,14,16,16, 8, 9, 9,11,11, 9,10,10,12,12, 9,10,
+ 10,12,12,11,12,12,14,13,11,12,12,14,14, 9,10,10,
+ 12,12,10,11,11,13,13,10,10,11,12,13,12,13,13,15,
+ 14,12,12,13,13,14, 9,10,10,12,12,10,11,11,13,13,
+ 10,11,11,13,13,12,13,13,14,14,12,13,13,15,14,11,
+ 12,12,14,13,12,13,13,15,14,11,12,12,13,14,14,15,
+ 14,16,15,13,13,14,13,16,11,12,12,14,14,12,13,13,
+ 14,15,12,13,12,15,14,14,14,14,16,15,14,15,13,16,
+ 14,
+};
+
+static const static_codebook _44u8_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u8_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u8_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u8_p3_0[] = {
+ 3, 4, 4, 5, 5, 7, 7, 9, 9, 4, 5, 4, 6, 6, 7, 7,
+ 9, 9, 4, 4, 5, 6, 6, 7, 7, 9, 9, 5, 6, 6, 7, 7,
+ 8, 8,10,10, 6, 6, 6, 7, 7, 8, 8,10,10, 7, 7, 7,
+ 8, 8, 9, 9,11,10, 7, 7, 7, 8, 8, 9, 9,10,11, 9,
+ 9, 9,10,10,11,10,12,11, 9, 9, 9, 9,10,11,11,11,
+ 12,
+};
+
+static const static_codebook _44u8_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u8_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u8_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p4_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44u8_p4_0[] = {
+ 4, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8,10,10,11,11,11,
+ 11, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,
+ 12,12, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,
+ 11,12,12, 6, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,
+ 11,11,12,12, 6, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,
+ 10,11,11,12,12, 7, 7, 7, 8, 8, 9, 8,10, 9,10, 9,
+ 11,10,12,11,13,12, 7, 7, 7, 8, 8, 8, 9, 9,10, 9,
+ 10,10,11,11,12,12,13, 8, 8, 8, 9, 9, 9, 9,10,10,
+ 11,10,11,11,12,12,13,13, 8, 8, 8, 9, 9, 9,10,10,
+ 10,10,11,11,11,12,12,12,13, 8, 9, 9, 9, 9,10, 9,
+ 11,10,11,11,12,11,13,12,13,13, 8, 9, 9, 9, 9, 9,
+ 10,10,11,11,11,11,12,12,13,13,13,10,10,10,10,10,
+ 11,10,11,11,12,11,13,12,13,13,14,13,10,10,10,10,
+ 10,10,11,11,11,11,12,12,13,13,13,13,14,11,11,11,
+ 11,11,12,11,12,12,13,12,13,13,14,13,14,14,11,11,
+ 11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,11,
+ 12,12,12,12,13,12,13,12,13,13,14,13,14,14,14,14,
+ 11,12,12,12,12,12,12,13,13,13,13,13,14,14,14,14,
+ 14,
+};
+
+static const static_codebook _44u8_p4_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44u8_p4_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44u8_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p5_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u8_p5_0[] = {
+ 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 8, 8, 9, 9, 7,
+ 9, 9, 5, 8, 8, 7, 9, 9, 8, 9, 9, 5, 8, 8, 8,10,
+ 10, 8,10,10, 7,10,10, 9,10,12, 9,12,11, 7,10,10,
+ 9,11,10, 9,11,12, 5, 8, 8, 8,10,10, 8,10,10, 7,
+ 10,10, 9,11,11, 9,10,11, 7,10,10, 9,11,11,10,12,
+ 10,
+};
+
+static const static_codebook _44u8_p5_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u8_p5_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44u8_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p5_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u8_p5_1[] = {
+ 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 5, 5, 5, 6, 6,
+ 7, 7, 8, 8, 8, 8, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8,
+ 8, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 6, 6, 6, 7,
+ 7, 7, 7, 8, 8, 8, 8, 7, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 7, 8, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 9, 9,
+};
+
+static const static_codebook _44u8_p5_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u8_p5_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u8_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u8_p6_0[] = {
+ 2, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 4, 6, 5,
+ 7, 7, 8, 8, 8, 8, 9, 9,10,10, 4, 6, 6, 7, 7, 8,
+ 8, 8, 8, 9, 9,10,10, 6, 7, 7, 7, 8, 8, 8, 8, 9,
+ 9,10,10,10, 6, 7, 7, 8, 8, 8, 8, 9, 8,10, 9,11,
+ 10, 7, 8, 8, 8, 8, 8, 9, 9, 9,10,10,11,11, 7, 8,
+ 8, 8, 8, 9, 8, 9, 9,10,10,11,11, 8, 8, 8, 9, 9,
+ 9, 9, 9,10,10,10,11,11, 8, 8, 8, 9, 9, 9, 9,10,
+ 9,10,10,11,11, 9, 9, 9, 9,10,10,10,10,10,10,11,
+ 11,12, 9, 9, 9,10, 9,10,10,10,10,11,10,12,11,10,
+ 10,10,10,10,11,11,11,11,11,12,12,12,10,10,10,10,
+ 11,11,11,11,11,12,11,12,12,
+};
+
+static const static_codebook _44u8_p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u8_p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44u8_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u8_p6_1[] = {
+ 3, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44u8_p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44u8_p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u8_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u8_p7_0[] = {
+ 1, 4, 5, 6, 6, 7, 7, 8, 8,10,10,11,11, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9,11,10,12,11, 5, 6, 6, 7, 7, 8,
+ 8, 9, 9,10,11,11,12, 6, 7, 7, 8, 8, 9, 9,10,10,
+ 11,11,12,12, 6, 7, 7, 8, 8, 9, 9,10,10,11,12,13,
+ 12, 7, 8, 8, 9, 9,10,10,11,11,12,12,13,13, 8, 8,
+ 8, 9, 9,10,10,11,11,12,12,13,13, 9, 9, 9,10,10,
+ 11,11,12,12,13,13,14,14, 9, 9, 9,10,10,11,11,12,
+ 12,13,13,14,14,10,11,11,12,11,13,12,13,13,14,14,
+ 15,15,10,11,11,11,12,12,13,13,14,14,14,15,15,11,
+ 12,12,13,13,14,13,15,14,15,15,16,15,11,11,12,13,
+ 13,13,14,14,14,15,15,15,16,
+};
+
+static const static_codebook _44u8_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u8_p7_0,
+ 1, -523206656, 1618345984, 4, 0,
+ (long *)_vq_quantlist__44u8_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u8_p7_1[] = {
+ 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 5, 6, 6, 7, 7,
+ 7, 7, 7, 7, 7, 7, 5, 6, 6, 7, 7, 7, 7, 7, 7, 7,
+ 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 6, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 8, 8,
+ 8, 8, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 7, 7, 7,
+ 8, 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 8, 8, 8,
+ 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44u8_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u8_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u8_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p8_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44u8_p8_0[] = {
+ 1, 4, 4, 7, 7, 8, 8, 8, 7, 9, 8,10, 9,11,10, 4,
+ 6, 6, 8, 8,10, 9, 9, 9,10,10,11,10,12,10, 4, 6,
+ 6, 8, 8,10,10, 9, 9,10,10,11,11,11,12, 7, 8, 8,
+ 10,10,11,11,11,10,12,11,12,12,13,11, 7, 8, 8,10,
+ 10,11,11,10,10,11,11,12,12,13,13, 8,10,10,11,11,
+ 12,11,12,11,13,12,13,12,14,13, 8,10, 9,11,11,12,
+ 12,12,12,12,12,13,13,14,13, 8, 9, 9,11,10,12,11,
+ 13,12,13,13,14,13,14,13, 8, 9, 9,10,11,12,12,12,
+ 12,13,13,14,15,14,14, 9,10,10,12,11,13,12,13,13,
+ 14,13,14,14,14,14, 9,10,10,12,12,12,12,13,13,14,
+ 14,14,15,14,14,10,11,11,13,12,13,12,14,14,14,14,
+ 14,14,15,15,10,11,11,12,12,13,13,14,14,14,15,15,
+ 14,16,15,11,12,12,13,12,14,14,14,13,15,14,15,15,
+ 15,17,11,12,12,13,13,14,14,14,15,15,14,15,15,14,
+ 17,
+};
+
+static const static_codebook _44u8_p8_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44u8_p8_0,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__44u8_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p8_1[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__44u8_p8_1[] = {
+ 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 6, 6, 7, 7, 8,
+ 8, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7,
+ 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, 9,10, 8, 8,
+ 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10,
+ 10, 9,10, 8, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,
+ 10,10,10,10,10,10,10,10, 8, 9, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10,10,10, 9,10,10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10,10,10,
+ 10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10,
+ 10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9,10, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,
+ 10, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,
+ 9, 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10, 9, 9, 9,10, 9,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10,
+ 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9,
+ 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10, 9, 9, 9,10, 9,10, 9,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _44u8_p8_1 = {
+ 2, 441,
+ (char *)_vq_lengthlist__44u8_p8_1,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44u8_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p9_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u8_p9_0[] = {
+ 1, 3, 3, 9, 9, 9, 9, 9, 9, 4, 9, 9, 9, 9, 9, 9,
+ 9, 9, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8,
+ 8,
+};
+
+static const static_codebook _44u8_p9_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u8_p9_0,
+ 1, -511895552, 1631393792, 4, 0,
+ (long *)_vq_quantlist__44u8_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p9_1[] = {
+ 9,
+ 8,
+ 10,
+ 7,
+ 11,
+ 6,
+ 12,
+ 5,
+ 13,
+ 4,
+ 14,
+ 3,
+ 15,
+ 2,
+ 16,
+ 1,
+ 17,
+ 0,
+ 18,
+};
+
+static const char _vq_lengthlist__44u8_p9_1[] = {
+ 1, 4, 4, 7, 7, 8, 7, 8, 6, 9, 7,10, 8,11,10,11,
+ 11,11,11, 4, 7, 6, 9, 9,10, 9, 9, 9,10,10,11,10,
+ 11,10,11,11,13,11, 4, 7, 7, 9, 9, 9, 9, 9, 9,10,
+ 10,11,10,11,11,11,12,11,12, 7, 9, 8,11,11,11,11,
+ 10,10,11,11,12,12,12,12,12,12,14,13, 7, 8, 9,10,
+ 11,11,11,10,10,11,11,11,11,12,12,14,12,13,14, 8,
+ 9, 9,11,11,11,11,11,11,12,12,14,12,15,14,14,14,
+ 15,14, 8, 9, 9,11,11,11,11,12,11,12,12,13,13,13,
+ 13,13,13,14,14, 8, 9, 9,11,10,12,11,12,12,13,13,
+ 13,13,15,14,14,14,16,16, 8, 9, 9,10,11,11,12,12,
+ 12,13,13,13,14,14,14,15,16,15,15, 9,10,10,11,12,
+ 12,13,13,13,14,14,16,14,14,16,16,16,16,15, 9,10,
+ 10,11,11,12,13,13,14,15,14,16,14,15,16,16,16,16,
+ 15,10,11,11,12,13,13,14,15,15,15,15,15,16,15,16,
+ 15,16,15,15,10,11,11,13,13,14,13,13,15,14,15,15,
+ 16,15,15,15,16,15,16,10,12,12,14,14,14,14,14,16,
+ 16,15,15,15,16,16,16,16,16,16,11,12,12,14,14,14,
+ 14,15,15,16,15,16,15,16,15,16,16,16,16,12,12,13,
+ 14,14,15,16,16,16,16,16,16,15,16,16,16,16,16,16,
+ 12,13,13,14,14,14,14,15,16,15,16,16,16,16,16,16,
+ 16,16,16,12,13,14,14,14,16,15,16,15,16,16,16,16,
+ 16,16,16,16,16,16,12,14,13,14,15,15,15,16,15,16,
+ 16,15,16,16,16,16,16,16,16,
+};
+
+static const static_codebook _44u8_p9_1 = {
+ 2, 361,
+ (char *)_vq_lengthlist__44u8_p9_1,
+ 1, -518287360, 1622704128, 5, 0,
+ (long *)_vq_quantlist__44u8_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44u8_p9_2[] = {
+ 24,
+ 23,
+ 25,
+ 22,
+ 26,
+ 21,
+ 27,
+ 20,
+ 28,
+ 19,
+ 29,
+ 18,
+ 30,
+ 17,
+ 31,
+ 16,
+ 32,
+ 15,
+ 33,
+ 14,
+ 34,
+ 13,
+ 35,
+ 12,
+ 36,
+ 11,
+ 37,
+ 10,
+ 38,
+ 9,
+ 39,
+ 8,
+ 40,
+ 7,
+ 41,
+ 6,
+ 42,
+ 5,
+ 43,
+ 4,
+ 44,
+ 3,
+ 45,
+ 2,
+ 46,
+ 1,
+ 47,
+ 0,
+ 48,
+};
+
+static const char _vq_lengthlist__44u8_p9_2[] = {
+ 2, 3, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7,
+};
+
+static const static_codebook _44u8_p9_2 = {
+ 1, 49,
+ (char *)_vq_lengthlist__44u8_p9_2,
+ 1, -526909440, 1611661312, 6, 0,
+ (long *)_vq_quantlist__44u8_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44u9__long[] = {
+ 3, 9,13,13,14,15,14,14,15,15, 5, 5, 9,10,12,12,
+ 13,14,16,15,10, 6, 6, 6, 8,11,12,13,16,15,11, 7,
+ 5, 3, 5, 8,10,12,15,15,10,10, 7, 4, 3, 5, 8,10,
+ 12,12,12,12, 9, 7, 5, 4, 6, 8,10,13,13,12,11, 9,
+ 7, 5, 5, 6, 9,12,14,12,12,10, 8, 6, 6, 6, 7,11,
+ 13,12,14,13,10, 8, 7, 7, 7,10,11,11,12,13,12,11,
+ 10, 8, 8, 9,
+};
+
+static const static_codebook _huff_book__44u9__long = {
+ 2, 100,
+ (char *)_huff_lengthlist__44u9__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const char _huff_lengthlist__44u9__short[] = {
+ 9,16,18,18,17,17,17,17,17,17, 5, 8,11,12,11,12,
+ 17,17,16,16, 6, 6, 8, 8, 9,10,14,15,16,16, 6, 7,
+ 7, 4, 6, 9,13,16,16,16, 6, 6, 7, 4, 5, 8,11,15,
+ 17,16, 7, 6, 7, 6, 6, 8, 9,10,14,16,11, 8, 8, 7,
+ 6, 6, 3, 4,10,15,14,12,12,10, 5, 6, 3, 3, 8,13,
+ 15,17,15,11, 6, 8, 6, 6, 9,14,17,15,15,12, 8,10,
+ 9, 9,12,15,
+};
+
+static const static_codebook _huff_book__44u9__short = {
+ 2, 100,
+ (char *)_huff_lengthlist__44u9__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u9_p1_0[] = {
+ 1, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 9, 9, 7,
+ 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 9, 5, 7, 7, 7, 9,
+ 9, 7, 9, 9, 8, 9, 9, 9,10,11, 9,11,11, 7, 9, 9,
+ 9,11,10, 9,11,11, 5, 7, 7, 7, 9, 9, 8, 9,10, 7,
+ 9, 9, 9,11,11, 9,10,11, 7, 9,10, 9,11,11, 9,11,
+ 10,
+};
+
+static const static_codebook _44u9_p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u9_p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44u9_p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p2_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u9_p2_0[] = {
+ 3, 5, 5, 8, 8, 5, 7, 7, 9, 9, 6, 7, 7, 9, 9, 8,
+ 9, 9,11,10, 8, 9, 9,11,11, 6, 7, 7, 9, 9, 7, 8,
+ 8,10,10, 7, 8, 8, 9,10, 9,10,10,11,11, 9, 9,10,
+ 11,11, 6, 7, 7, 9, 9, 7, 8, 8,10, 9, 7, 8, 8,10,
+ 10, 9,10, 9,11,11, 9,10,10,11,11, 8, 9, 9,11,11,
+ 9,10,10,12,11, 9,10,10,11,12,11,11,11,13,13,11,
+ 11,11,12,13, 8, 9, 9,11,11, 9,10,10,11,11, 9,10,
+ 10,12,11,11,12,11,13,12,11,11,12,13,13, 6, 7, 7,
+ 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12,
+ 11, 9,10,10,11,12, 7, 8, 8,10,10, 8, 9, 9,11,11,
+ 8, 9, 9,10,10,10,11,11,12,12,10,10,11,12,12, 7,
+ 8, 8,10,10, 8, 9, 8,10,10, 8, 9, 9,10,10,10,11,
+ 10,12,11,10,10,11,12,12, 9,10,10,11,12,10,11,11,
+ 12,12,10,11,10,12,12,12,12,12,13,13,11,12,12,13,
+ 13, 9,10,10,11,11, 9,10,10,12,12,10,11,11,12,13,
+ 11,12,11,13,12,12,12,12,13,14, 6, 7, 7, 9, 9, 7,
+ 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,11,11, 9,10,
+ 10,11,12, 7, 8, 8,10,10, 8, 9, 9,11,10, 8, 8, 9,
+ 10,10,10,11,10,12,12,10,10,11,11,12, 7, 8, 8,10,
+ 10, 8, 9, 9,10,10, 8, 9, 9,10,10,10,11,10,12,12,
+ 10,11,10,12,12, 9,10,10,12,11,10,11,11,12,12, 9,
+ 10,10,12,12,12,12,12,13,13,11,11,12,12,14, 9,10,
+ 10,11,12,10,11,11,12,12,10,11,11,12,12,11,12,12,
+ 14,14,12,12,12,13,13, 8, 9, 9,11,11, 9,10,10,12,
+ 11, 9,10,10,12,12,11,12,11,13,13,11,11,12,13,13,
+ 9,10,10,12,12,10,11,11,12,12,10,11,11,12,12,12,
+ 12,12,14,14,12,12,12,13,13, 9,10,10,12,11,10,11,
+ 10,12,12,10,11,11,12,12,11,12,12,14,13,12,12,12,
+ 13,14,11,12,11,13,13,11,12,12,13,13,12,12,12,14,
+ 14,13,13,13,13,15,13,13,14,15,15,11,11,11,13,13,
+ 11,12,11,13,13,11,12,12,13,13,12,13,12,15,13,13,
+ 13,14,14,15, 8, 9, 9,11,11, 9,10,10,11,12, 9,10,
+ 10,11,12,11,12,11,13,13,11,12,12,13,13, 9,10,10,
+ 11,12,10,11,10,12,12,10,10,11,12,13,12,12,12,14,
+ 13,11,12,12,13,14, 9,10,10,12,12,10,11,11,12,12,
+ 10,11,11,12,12,12,12,12,14,13,12,12,12,14,13,11,
+ 11,11,13,13,11,12,12,14,13,11,11,12,13,13,13,13,
+ 13,15,14,12,12,13,13,15,11,12,12,13,13,12,12,12,
+ 13,14,11,12,12,13,13,13,13,14,14,15,13,13,13,14,
+ 14,
+};
+
+static const static_codebook _44u9_p2_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44u9_p2_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u9_p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p3_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44u9_p3_0[] = {
+ 3, 4, 4, 5, 5, 7, 7, 8, 8, 4, 5, 5, 6, 6, 7, 7,
+ 9, 9, 4, 4, 5, 6, 6, 7, 7, 9, 9, 5, 6, 6, 7, 7,
+ 8, 8, 9, 9, 5, 6, 6, 7, 7, 8, 8, 9, 9, 7, 7, 7,
+ 8, 8, 9, 9,10,10, 7, 7, 7, 8, 8, 9, 9,10,10, 8,
+ 9, 9,10, 9,10,10,11,11, 8, 9, 9, 9,10,10,10,11,
+ 11,
+};
+
+static const static_codebook _44u9_p3_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44u9_p3_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u9_p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p4_0[] = {
+ 8,
+ 7,
+ 9,
+ 6,
+ 10,
+ 5,
+ 11,
+ 4,
+ 12,
+ 3,
+ 13,
+ 2,
+ 14,
+ 1,
+ 15,
+ 0,
+ 16,
+};
+
+static const char _vq_lengthlist__44u9_p4_0[] = {
+ 4, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11,
+ 11, 5, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,
+ 11,11, 5, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,
+ 10,11,11, 6, 6, 6, 7, 6, 7, 7, 8, 8, 9, 9,10,10,
+ 11,11,12,11, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9,10,
+ 10,11,11,11,12, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,
+ 10,10,11,11,12,12, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9,
+ 9,10,10,11,11,12,12, 8, 8, 8, 8, 8, 9, 8,10, 9,
+ 10,10,11,10,12,11,13,12, 8, 8, 8, 8, 8, 9, 9, 9,
+ 10,10,10,10,11,11,12,12,12, 8, 8, 8, 9, 9, 9, 9,
+ 10,10,11,10,12,11,12,12,13,12, 8, 8, 8, 9, 9, 9,
+ 9,10,10,10,11,11,11,12,12,12,13, 9, 9, 9,10,10,
+ 10,10,11,10,11,11,12,11,13,12,13,13, 9, 9,10,10,
+ 10,10,10,10,11,11,11,11,12,12,13,13,13,10,11,10,
+ 11,11,11,11,12,11,12,12,13,12,13,13,14,13,10,10,
+ 10,11,11,11,11,11,12,12,12,12,13,13,13,13,14,11,
+ 11,11,12,11,12,12,12,12,13,13,13,13,14,13,14,14,
+ 11,11,11,11,12,12,12,12,12,12,13,13,13,13,14,14,
+ 14,
+};
+
+static const static_codebook _44u9_p4_0 = {
+ 2, 289,
+ (char *)_vq_lengthlist__44u9_p4_0,
+ 1, -529530880, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44u9_p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p5_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44u9_p5_0[] = {
+ 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 8, 8, 9, 9, 7,
+ 9, 9, 5, 8, 8, 7, 9, 9, 8, 9, 9, 5, 8, 8, 8,10,
+ 10, 8,10,10, 7,10,10, 9,10,12, 9,11,11, 7,10,10,
+ 9,11,10, 9,11,12, 5, 8, 8, 8,10,10, 8,10,10, 7,
+ 10,10, 9,12,11, 9,10,11, 7,10,10, 9,11,11,10,12,
+ 10,
+};
+
+static const static_codebook _44u9_p5_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44u9_p5_0,
+ 1, -529137664, 1618345984, 2, 0,
+ (long *)_vq_quantlist__44u9_p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p5_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u9_p5_1[] = {
+ 5, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 5, 6, 6, 6, 6,
+ 7, 7, 7, 7, 8, 7, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7,
+ 7, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 6, 6, 6, 7,
+ 7, 7, 7, 7, 7, 8, 8, 7, 7, 7, 7, 7, 8, 7, 8, 8,
+ 8, 8, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7,
+ 8, 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static const static_codebook _44u9_p5_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u9_p5_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u9_p5_1,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u9_p6_0[] = {
+ 2, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 4, 6, 5,
+ 7, 7, 8, 8, 8, 8, 9, 9,10,10, 4, 5, 6, 7, 7, 8,
+ 8, 8, 8, 9, 9,10,10, 6, 7, 7, 8, 8, 8, 8, 9, 9,
+ 10,10,10,10, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,10,
+ 10, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,11, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9,10,10,11,11, 8, 8, 8, 9, 9,
+ 9, 9, 9,10,10,10,11,11, 8, 8, 8, 9, 9, 9, 9,10,
+ 9,10,10,11,11, 9, 9, 9,10,10,10,10,10,11,11,11,
+ 11,12, 9, 9, 9,10,10,10,10,10,10,11,10,12,11,10,
+ 10,10,10,10,11,11,11,11,11,12,12,12,10,10,10,10,
+ 10,11,11,11,11,12,11,12,12,
+};
+
+static const static_codebook _44u9_p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u9_p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44u9_p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44u9_p6_1[] = {
+ 4, 4, 4, 5, 5, 4, 5, 4, 5, 5, 4, 4, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const static_codebook _44u9_p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44u9_p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44u9_p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p7_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44u9_p7_0[] = {
+ 1, 4, 5, 6, 6, 7, 7, 8, 9,10,10,11,11, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9,10,10,11,11, 5, 6, 6, 7, 7, 8,
+ 8, 9, 9,10,10,11,11, 6, 7, 7, 8, 8, 9, 9,10,10,
+ 11,11,12,12, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,
+ 12, 8, 8, 8, 9, 9,10,10,11,11,12,12,13,13, 8, 8,
+ 8, 9, 9,10,10,11,11,12,12,13,13, 9, 9, 9,10,10,
+ 11,11,12,12,13,13,13,13, 9, 9, 9,10,10,11,11,12,
+ 12,13,13,14,14,10,10,10,11,11,12,12,13,13,14,13,
+ 15,14,10,10,10,11,11,12,12,13,13,14,14,14,14,11,
+ 11,12,12,12,13,13,14,14,14,14,15,15,11,11,12,12,
+ 12,13,13,14,14,14,15,15,15,
+};
+
+static const static_codebook _44u9_p7_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44u9_p7_0,
+ 1, -523206656, 1618345984, 4, 0,
+ (long *)_vq_quantlist__44u9_p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p7_1[] = {
+ 5,
+ 4,
+ 6,
+ 3,
+ 7,
+ 2,
+ 8,
+ 1,
+ 9,
+ 0,
+ 10,
+};
+
+static const char _vq_lengthlist__44u9_p7_1[] = {
+ 5, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 7, 7,
+ 7, 7, 7, 7, 7, 7, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 8, 8, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 8, 7, 7,
+ 7, 7, 7, 7, 7, 8, 8, 8, 8,
+};
+
+static const static_codebook _44u9_p7_1 = {
+ 2, 121,
+ (char *)_vq_lengthlist__44u9_p7_1,
+ 1, -531365888, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44u9_p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p8_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44u9_p8_0[] = {
+ 1, 4, 4, 7, 7, 8, 8, 8, 8, 9, 9,10, 9,11,10, 4,
+ 6, 6, 8, 8, 9, 9, 9, 9,10,10,11,10,12,10, 4, 6,
+ 6, 8, 8, 9,10, 9, 9,10,10,11,11,12,12, 7, 8, 8,
+ 10,10,11,11,10,10,11,11,12,12,13,12, 7, 8, 8,10,
+ 10,11,11,10,10,11,11,12,12,12,13, 8,10, 9,11,11,
+ 12,12,11,11,12,12,13,13,14,13, 8, 9, 9,11,11,12,
+ 12,11,12,12,12,13,13,14,13, 8, 9, 9,10,10,12,11,
+ 13,12,13,13,14,13,15,14, 8, 9, 9,10,10,11,12,12,
+ 12,13,13,13,14,14,14, 9,10,10,12,11,13,12,13,13,
+ 14,13,14,14,14,15, 9,10,10,11,12,12,12,13,13,14,
+ 14,14,15,15,15,10,11,11,12,12,13,13,14,14,14,14,
+ 15,14,16,15,10,11,11,12,12,13,13,13,14,14,14,14,
+ 14,15,16,11,12,12,13,13,14,13,14,14,15,14,15,16,
+ 16,16,11,12,12,13,13,14,13,14,14,15,15,15,16,15,
+ 15,
+};
+
+static const static_codebook _44u9_p8_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44u9_p8_0,
+ 1, -520986624, 1620377600, 4, 0,
+ (long *)_vq_quantlist__44u9_p8_0,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p8_1[] = {
+ 10,
+ 9,
+ 11,
+ 8,
+ 12,
+ 7,
+ 13,
+ 6,
+ 14,
+ 5,
+ 15,
+ 4,
+ 16,
+ 3,
+ 17,
+ 2,
+ 18,
+ 1,
+ 19,
+ 0,
+ 20,
+};
+
+static const char _vq_lengthlist__44u9_p8_1[] = {
+ 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 6, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7,
+ 7, 7, 8, 8, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10,10,10, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9,10,10, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 9,10, 9,10,10,10,10, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9,10,10, 9,10,10,10,10,10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10,10,10,
+ 10,10, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,
+ 10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,
+ 10, 9, 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10,10,10,
+ 10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 9, 9, 9, 9,10, 9, 9,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10, 9, 9, 9,10, 9,10, 9,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10, 9, 9, 9,10, 9,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9,
+ 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10, 9, 9, 9,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,
+};
+
+static const static_codebook _44u9_p8_1 = {
+ 2, 441,
+ (char *)_vq_lengthlist__44u9_p8_1,
+ 1, -529268736, 1611661312, 5, 0,
+ (long *)_vq_quantlist__44u9_p8_1,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p9_0[] = {
+ 7,
+ 6,
+ 8,
+ 5,
+ 9,
+ 4,
+ 10,
+ 3,
+ 11,
+ 2,
+ 12,
+ 1,
+ 13,
+ 0,
+ 14,
+};
+
+static const char _vq_lengthlist__44u9_p9_0[] = {
+ 1, 3, 3,11,11,11,11,11,11,11,11,11,11,11,11, 4,
+ 10,11,11,11,11,11,11,11,11,11,11,11,11,11, 4,10,
+ 10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _44u9_p9_0 = {
+ 2, 225,
+ (char *)_vq_lengthlist__44u9_p9_0,
+ 1, -510036736, 1631393792, 4, 0,
+ (long *)_vq_quantlist__44u9_p9_0,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p9_1[] = {
+ 9,
+ 8,
+ 10,
+ 7,
+ 11,
+ 6,
+ 12,
+ 5,
+ 13,
+ 4,
+ 14,
+ 3,
+ 15,
+ 2,
+ 16,
+ 1,
+ 17,
+ 0,
+ 18,
+};
+
+static const char _vq_lengthlist__44u9_p9_1[] = {
+ 1, 4, 4, 7, 7, 8, 7, 8, 7, 9, 8,10, 9,10,10,11,
+ 11,12,12, 4, 7, 6, 9, 9,10, 9, 9, 8,10,10,11,10,
+ 12,10,13,12,13,12, 4, 6, 6, 9, 9, 9, 9, 9, 9,10,
+ 10,11,11,11,12,12,12,12,12, 7, 9, 8,11,10,10,10,
+ 11,10,11,11,12,12,13,12,13,13,13,13, 7, 8, 9,10,
+ 10,11,11,10,10,11,11,11,12,13,13,13,13,14,14, 8,
+ 9, 9,11,11,12,11,12,12,13,12,12,13,13,14,15,14,
+ 14,14, 8, 9, 9,10,11,11,11,12,12,13,12,13,13,14,
+ 14,14,15,14,16, 8, 9, 9,11,10,12,12,12,12,15,13,
+ 13,13,17,14,15,15,15,14, 8, 9, 9,10,11,11,12,13,
+ 12,13,13,13,14,15,14,14,14,16,15, 9,11,10,12,12,
+ 13,13,13,13,14,14,16,15,14,14,14,15,15,17, 9,10,
+ 10,11,11,13,13,13,14,14,13,15,14,15,14,15,16,15,
+ 16,10,11,11,12,12,13,14,15,14,15,14,14,15,17,16,
+ 15,15,17,17,10,12,11,13,12,14,14,13,14,15,15,15,
+ 15,16,17,17,15,17,16,11,12,12,14,13,15,14,15,16,
+ 17,15,17,15,17,15,15,16,17,15,11,11,12,14,14,14,
+ 14,14,15,15,16,15,17,17,17,16,17,16,15,12,12,13,
+ 14,14,14,15,14,15,15,16,16,17,16,17,15,17,17,16,
+ 12,14,12,14,14,15,15,15,14,14,16,16,16,15,16,16,
+ 15,17,15,12,13,13,14,15,14,15,17,15,17,16,17,17,
+ 17,16,17,16,17,17,12,13,13,14,16,15,15,15,16,15,
+ 17,17,15,17,15,17,16,16,17,
+};
+
+static const static_codebook _44u9_p9_1 = {
+ 2, 361,
+ (char *)_vq_lengthlist__44u9_p9_1,
+ 1, -518287360, 1622704128, 5, 0,
+ (long *)_vq_quantlist__44u9_p9_1,
+ 0
+};
+
+static const long _vq_quantlist__44u9_p9_2[] = {
+ 24,
+ 23,
+ 25,
+ 22,
+ 26,
+ 21,
+ 27,
+ 20,
+ 28,
+ 19,
+ 29,
+ 18,
+ 30,
+ 17,
+ 31,
+ 16,
+ 32,
+ 15,
+ 33,
+ 14,
+ 34,
+ 13,
+ 35,
+ 12,
+ 36,
+ 11,
+ 37,
+ 10,
+ 38,
+ 9,
+ 39,
+ 8,
+ 40,
+ 7,
+ 41,
+ 6,
+ 42,
+ 5,
+ 43,
+ 4,
+ 44,
+ 3,
+ 45,
+ 2,
+ 46,
+ 1,
+ 47,
+ 0,
+ 48,
+};
+
+static const char _vq_lengthlist__44u9_p9_2[] = {
+ 2, 4, 4, 5, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 7, 6, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7,
+};
+
+static const static_codebook _44u9_p9_2 = {
+ 1, 49,
+ (char *)_vq_lengthlist__44u9_p9_2,
+ 1, -526909440, 1611661312, 6, 0,
+ (long *)_vq_quantlist__44u9_p9_2,
+ 0
+};
+
+static const char _huff_lengthlist__44un1__long[] = {
+ 5, 6,12, 9,14, 9, 9,19, 6, 1, 5, 5, 8, 7, 9,19,
+ 12, 4, 4, 7, 7, 9,11,18, 9, 5, 6, 6, 8, 7, 8,17,
+ 14, 8, 7, 8, 8,10,12,18, 9, 6, 8, 6, 8, 6, 8,18,
+ 9, 8,11, 8,11, 7, 5,15,16,18,18,18,17,15,11,18,
+};
+
+static const static_codebook _huff_book__44un1__long = {
+ 2, 64,
+ (char *)_huff_lengthlist__44un1__long,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
+static const long _vq_quantlist__44un1__p1_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44un1__p1_0[] = {
+ 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,10,11, 8,
+ 10,11, 5, 8, 8, 8,11,10, 8,11,10, 4, 9, 9, 8,11,
+ 11, 8,11,11, 8,12,11,10,12,14,11,13,13, 7,11,11,
+ 10,13,11,11,13,14, 4, 8, 9, 8,11,11, 8,11,12, 7,
+ 11,11,11,14,13,10,11,13, 8,11,12,11,13,13,10,14,
+ 12,
+};
+
+static const static_codebook _44un1__p1_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44un1__p1_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44un1__p1_0,
+ 0
+};
+
+static const long _vq_quantlist__44un1__p2_0[] = {
+ 1,
+ 0,
+ 2,
+};
+
+static const char _vq_lengthlist__44un1__p2_0[] = {
+ 2, 4, 4, 5, 6, 6, 5, 6, 6, 5, 7, 7, 7, 8, 8, 6,
+ 7, 9, 5, 7, 7, 6, 8, 7, 7, 9, 8, 4, 7, 7, 7, 9,
+ 8, 7, 8, 8, 7, 9, 8, 8, 8,10, 9,10,10, 6, 8, 8,
+ 7,10, 8, 9,10,10, 5, 7, 7, 7, 8, 8, 7, 8, 9, 6,
+ 8, 8, 9,10,10, 7, 8,10, 6, 8, 9, 9,10,10, 8,10,
+ 8,
+};
+
+static const static_codebook _44un1__p2_0 = {
+ 4, 81,
+ (char *)_vq_lengthlist__44un1__p2_0,
+ 1, -535822336, 1611661312, 2, 0,
+ (long *)_vq_quantlist__44un1__p2_0,
+ 0
+};
+
+static const long _vq_quantlist__44un1__p3_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44un1__p3_0[] = {
+ 1, 5, 5, 8, 8, 5, 8, 7, 9, 9, 5, 7, 8, 9, 9, 9,
+ 10, 9,12,12, 9, 9,10,11,12, 6, 8, 8,10,10, 8,10,
+ 10,11,11, 8, 9,10,11,11,10,11,11,13,13,10,11,11,
+ 12,13, 6, 8, 8,10,10, 8,10, 9,11,11, 8,10,10,11,
+ 11,10,11,11,13,12,10,11,11,13,12, 9,11,11,15,13,
+ 10,12,11,15,13,10,11,11,15,14,12,14,13,16,15,12,
+ 13,13,17,16, 9,11,11,13,15,10,11,12,14,15,10,11,
+ 12,14,15,12,13,13,15,16,12,13,13,16,16, 5, 8, 8,
+ 11,11, 8,10,10,12,12, 8,10,10,12,12,11,12,12,14,
+ 14,11,12,12,14,14, 8,11,10,13,12,10,11,12,12,13,
+ 10,12,12,13,13,12,12,13,13,15,11,12,13,15,14, 7,
+ 10,10,12,12, 9,12,11,13,12,10,12,12,13,14,12,13,
+ 12,15,13,11,13,12,14,15,10,12,12,16,14,11,12,12,
+ 16,15,11,13,12,17,16,13,13,15,15,17,13,15,15,20,
+ 17,10,12,12,14,16,11,12,12,15,15,11,13,13,15,18,
+ 13,14,13,15,15,13,15,14,16,16, 5, 8, 8,11,11, 8,
+ 10,10,12,12, 8,10,10,12,12,11,12,12,14,14,11,12,
+ 12,14,15, 7,10,10,13,12,10,12,12,14,13, 9,10,12,
+ 12,13,11,13,13,15,15,11,12,13,13,15, 8,10,10,12,
+ 13,10,12,12,13,13,10,12,11,13,13,11,13,12,15,15,
+ 12,13,12,15,13,10,12,12,16,14,11,12,12,16,15,10,
+ 12,12,16,14,14,15,14,18,16,13,13,14,15,16,10,12,
+ 12,14,16,11,13,13,16,16,11,13,12,14,16,13,15,15,
+ 18,18,13,15,13,16,14, 8,11,11,16,16,10,13,13,17,
+ 16,10,12,12,16,15,14,16,15,20,17,13,14,14,17,17,
+ 9,12,12,16,16,11,13,14,16,17,11,13,13,16,16,15,
+ 15,19,18, 0,14,15,15,18,18, 9,12,12,17,16,11,13,
+ 12,17,16,11,12,13,15,17,15,16,15, 0,19,14,15,14,
+ 19,18,12,14,14, 0,16,13,14,14,19,18,13,15,16,17,
+ 16,15,15,17,18, 0,14,16,16,19, 0,12,14,14,16,18,
+ 13,15,13,17,18,13,15,14,17,18,15,18,14,18,18,16,
+ 17,16, 0,17, 8,11,11,15,15,10,12,12,16,16,10,13,
+ 13,16,16,13,15,14,17,17,14,15,17,17,18, 9,12,12,
+ 16,15,11,13,13,16,16,11,12,13,17,17,14,14,15,17,
+ 17,14,15,16, 0,18, 9,12,12,16,17,11,13,13,16,17,
+ 11,14,13,18,17,14,16,14,17,17,15,17,17,18,18,12,
+ 14,14, 0,16,13,15,15,19, 0,12,13,15, 0, 0,14,17,
+ 16,19, 0,16,15,18,18, 0,12,14,14,17, 0,13,14,14,
+ 17, 0,13,15,14, 0,18,15,16,16, 0,18,15,18,15, 0,
+ 17,
+};
+
+static const static_codebook _44un1__p3_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44un1__p3_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44un1__p3_0,
+ 0
+};
+
+static const long _vq_quantlist__44un1__p4_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44un1__p4_0[] = {
+ 3, 5, 5, 9, 9, 5, 6, 6,10, 9, 5, 6, 6, 9,10,10,
+ 10,10,12,11, 9,10,10,12,12, 5, 7, 7,10,10, 7, 7,
+ 8,10,11, 7, 7, 8,10,11,10,10,11,11,13,10,10,11,
+ 11,13, 6, 7, 7,10,10, 7, 8, 7,11,10, 7, 8, 7,10,
+ 10,10,11, 9,13,11,10,11,10,13,11,10,10,10,14,13,
+ 10,11,11,14,13,10,10,11,13,14,12,12,13,15,15,12,
+ 12,13,13,14,10,10,10,12,13,10,11,10,13,13,10,11,
+ 11,13,13,12,13,12,14,13,12,13,13,14,13, 5, 7, 7,
+ 10,10, 7, 8, 8,11,10, 7, 8, 8,10,10,11,11,11,13,
+ 13,10,11,11,12,12, 7, 8, 8,11,11, 7, 8, 9,10,12,
+ 8, 9, 9,11,11,11,10,12,11,14,11,11,12,13,13, 6,
+ 8, 8,10,11, 7, 9, 7,12,10, 8, 9,10,11,12,10,12,
+ 10,14,11,11,12,11,13,13,10,11,11,14,14,10,10,11,
+ 13,14,11,12,12,15,13,12,11,14,12,16,12,13,14,15,
+ 16,10,10,11,13,14,10,11,10,14,12,11,12,12,13,14,
+ 12,13,11,15,12,14,14,14,15,15, 5, 7, 7,10,10, 7,
+ 8, 8,10,10, 7, 8, 8,10,11,10,11,10,12,12,10,11,
+ 11,12,13, 6, 8, 8,11,11, 8, 9, 9,12,11, 7, 7, 9,
+ 10,12,11,11,11,12,13,11,10,12,11,15, 7, 8, 8,11,
+ 11, 8, 9, 9,11,11, 7, 9, 8,12,10,11,12,11,13,12,
+ 11,12,10,15,11,10,11,10,14,12,11,12,11,14,13,10,
+ 10,11,13,14,13,13,13,17,15,12,11,14,12,15,10,10,
+ 11,13,14,11,12,12,14,14,10,11,10,14,13,13,14,13,
+ 16,17,12,14,11,16,12, 9,10,10,14,13,10,11,10,14,
+ 14,10,11,11,13,13,13,14,14,16,15,12,13,13,14,14,
+ 9,11,10,14,13,10,10,12,13,14,11,12,11,14,13,13,
+ 14,14,14,15,13,14,14,15,15, 9,10,11,13,14,10,11,
+ 10,15,13,11,11,12,12,15,13,14,12,15,14,13,13,14,
+ 14,15,12,13,12,16,14,11,11,12,15,14,13,15,13,16,
+ 14,13,12,15,12,17,15,16,15,16,16,12,12,13,13,15,
+ 11,13,11,15,14,13,13,14,15,17,13,14,12, 0,13,14,
+ 15,14,15, 0, 9,10,10,13,13,10,11,11,13,13,10,11,
+ 11,13,13,12,13,12,14,14,13,14,14,15,17, 9,10,10,
+ 13,13,11,12,11,15,12,10,10,11,13,16,13,14,13,15,
+ 14,13,13,14,15,16,10,10,11,13,14,11,11,12,13,14,
+ 10,12,11,14,14,13,13,13,14,15,13,15,13,16,15,12,
+ 13,12,15,13,12,15,13,15,15,11,11,13,14,15,15,15,
+ 15,15,17,13,12,14,13,17,12,12,14,14,15,13,13,14,
+ 14,16,11,13,11,16,15,14,16,16,17, 0,14,13,11,16,
+ 12,
+};
+
+static const static_codebook _44un1__p4_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44un1__p4_0,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44un1__p4_0,
+ 0
+};
+
+static const long _vq_quantlist__44un1__p5_0[] = {
+ 4,
+ 3,
+ 5,
+ 2,
+ 6,
+ 1,
+ 7,
+ 0,
+ 8,
+};
+
+static const char _vq_lengthlist__44un1__p5_0[] = {
+ 1, 4, 4, 7, 7, 8, 8, 9, 9, 4, 6, 5, 8, 7, 8, 8,
+ 10, 9, 4, 6, 6, 8, 8, 8, 8,10,10, 7, 8, 7, 9, 9,
+ 9, 9,11,10, 7, 8, 8, 9, 9, 9, 9,10,11, 8, 8, 8,
+ 9, 9,10,10,11,11, 8, 8, 8, 9, 9,10,10,11,11, 9,
+ 10,10,11,10,11,11,12,12, 9,10,10,10,11,11,11,12,
+ 12,
+};
+
+static const static_codebook _44un1__p5_0 = {
+ 2, 81,
+ (char *)_vq_lengthlist__44un1__p5_0,
+ 1, -531628032, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44un1__p5_0,
+ 0
+};
+
+static const long _vq_quantlist__44un1__p6_0[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44un1__p6_0[] = {
+ 1, 4, 4, 6, 6, 8, 8,10,10,11,11,15,15, 4, 5, 5,
+ 8, 8, 9, 9,11,11,12,12,16,16, 4, 5, 6, 8, 8, 9,
+ 9,11,11,12,12,14,14, 7, 8, 8, 9, 9,10,10,11,12,
+ 13,13,16,17, 7, 8, 8, 9, 9,10,10,12,12,12,13,15,
+ 15, 9,10,10,10,10,11,11,12,12,13,13,15,16, 9, 9,
+ 9,10,10,11,11,13,12,13,13,17,17,10,11,11,11,12,
+ 12,12,13,13,14,15, 0,18,10,11,11,12,12,12,13,14,
+ 13,14,14,17,16,11,12,12,13,13,14,14,14,14,15,16,
+ 17,16,11,12,12,13,13,14,14,14,14,15,15,17,17,14,
+ 15,15,16,16,16,17,17,16, 0,17, 0,18,14,15,15,16,
+ 16, 0,15,18,18, 0,16, 0, 0,
+};
+
+static const static_codebook _44un1__p6_0 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44un1__p6_0,
+ 1, -526516224, 1616117760, 4, 0,
+ (long *)_vq_quantlist__44un1__p6_0,
+ 0
+};
+
+static const long _vq_quantlist__44un1__p6_1[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44un1__p6_1[] = {
+ 2, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 6, 5, 5,
+ 6, 5, 6, 6, 5, 6, 6, 6, 6,
+};
+
+static const static_codebook _44un1__p6_1 = {
+ 2, 25,
+ (char *)_vq_lengthlist__44un1__p6_1,
+ 1, -533725184, 1611661312, 3, 0,
+ (long *)_vq_quantlist__44un1__p6_1,
+ 0
+};
+
+static const long _vq_quantlist__44un1__p7_0[] = {
+ 2,
+ 1,
+ 3,
+ 0,
+ 4,
+};
+
+static const char _vq_lengthlist__44un1__p7_0[] = {
+ 1, 5, 3,11,11,11,11,11,11,11, 8,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11, 8,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11, 7,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 10,
+};
+
+static const static_codebook _44un1__p7_0 = {
+ 4, 625,
+ (char *)_vq_lengthlist__44un1__p7_0,
+ 1, -518709248, 1626677248, 3, 0,
+ (long *)_vq_quantlist__44un1__p7_0,
+ 0
+};
+
+static const long _vq_quantlist__44un1__p7_1[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44un1__p7_1[] = {
+ 1, 4, 4, 6, 6, 6, 6, 9, 8, 9, 8, 8, 8, 5, 7, 7,
+ 7, 7, 8, 8, 8,10, 8,10, 8, 9, 5, 7, 7, 8, 7, 7,
+ 8,10,10,11,10,12,11, 7, 8, 8, 9, 9, 9,10,11,11,
+ 11,11,11,11, 7, 8, 8, 8, 9, 9, 9,10,10,10,11,11,
+ 12, 7, 8, 8, 9, 9,10,11,11,12,11,12,11,11, 7, 8,
+ 8, 9, 9,10,10,11,11,11,12,12,11, 8,10,10,10,10,
+ 11,11,14,11,12,12,12,13, 9,10,10,10,10,12,11,14,
+ 11,14,11,12,13,10,11,11,11,11,13,11,14,14,13,13,
+ 13,14,11,11,11,12,11,12,12,12,13,14,14,13,14,12,
+ 11,12,12,12,12,13,13,13,14,13,14,14,11,12,12,14,
+ 12,13,13,12,13,13,14,14,14,
+};
+
+static const static_codebook _44un1__p7_1 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44un1__p7_1,
+ 1, -523010048, 1618608128, 4, 0,
+ (long *)_vq_quantlist__44un1__p7_1,
+ 0
+};
+
+static const long _vq_quantlist__44un1__p7_2[] = {
+ 6,
+ 5,
+ 7,
+ 4,
+ 8,
+ 3,
+ 9,
+ 2,
+ 10,
+ 1,
+ 11,
+ 0,
+ 12,
+};
+
+static const char _vq_lengthlist__44un1__p7_2[] = {
+ 3, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 9, 8, 4, 5, 5,
+ 6, 6, 8, 8, 9, 8, 9, 9, 9, 9, 4, 5, 5, 7, 6, 8,
+ 8, 8, 8, 9, 8, 9, 8, 6, 7, 7, 7, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9,
+ 9, 7, 8, 8, 8, 8, 9, 8, 9, 9,10, 9, 9,10, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9, 9, 9,10,10, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9,10,10, 9,10, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,10,10, 9, 9, 9,10, 9, 9,10, 9, 9,10,10,
+ 10,10, 9, 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10, 9,
+ 9, 9,10, 9, 9,10,10, 9,10,10,10,10, 9, 9, 9,10,
+ 9, 9, 9,10,10,10,10,10,10,
+};
+
+static const static_codebook _44un1__p7_2 = {
+ 2, 169,
+ (char *)_vq_lengthlist__44un1__p7_2,
+ 1, -531103744, 1611661312, 4, 0,
+ (long *)_vq_quantlist__44un1__p7_2,
+ 0
+};
+
+static const char _huff_lengthlist__44un1__short[] = {
+ 12,12,14,12,14,14,14,14,12, 6, 6, 8, 9, 9,11,14,
+ 12, 4, 2, 6, 6, 7,11,14,13, 6, 5, 7, 8, 9,11,14,
+ 13, 8, 5, 8, 6, 8,12,14,12, 7, 7, 8, 8, 8,10,14,
+ 12, 6, 3, 4, 4, 4, 7,14,11, 7, 4, 6, 6, 6, 8,14,
+};
+
+static const static_codebook _huff_book__44un1__short = {
+ 2, 64,
+ (char *)_huff_lengthlist__44un1__short,
+ 0, 0, 0, 0, 0,
+ NULL,
+ 0
+};
+
diff --git a/external/libvorbis-1.3.5/lib/codebook.c b/external/libvorbis-1.3.5/lib/codebook.c
new file mode 100644
index 0000000..72f8a17
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/codebook.c
@@ -0,0 +1,490 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: basic codebook pack/unpack/code/decode operations
+ last mod: $Id: codebook.c 19457 2015-03-03 00:15:29Z giles $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codebook.h"
+#include "scales.h"
+#include "misc.h"
+#include "os.h"
+
+/* packs the given codebook into the bitstream **************************/
+
+int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *opb){
+ long i,j;
+ int ordered=0;
+
+ /* first the basic parameters */
+ oggpack_write(opb,0x564342,24);
+ oggpack_write(opb,c->dim,16);
+ oggpack_write(opb,c->entries,24);
+
+ /* pack the codewords. There are two packings; length ordered and
+ length random. Decide between the two now. */
+
+ for(i=1;i<c->entries;i++)
+ if(c->lengthlist[i-1]==0 || c->lengthlist[i]<c->lengthlist[i-1])break;
+ if(i==c->entries)ordered=1;
+
+ if(ordered){
+ /* length ordered. We only need to say how many codewords of
+ each length. The actual codewords are generated
+ deterministically */
+
+ long count=0;
+ oggpack_write(opb,1,1); /* ordered */
+ oggpack_write(opb,c->lengthlist[0]-1,5); /* 1 to 32 */
+
+ for(i=1;i<c->entries;i++){
+ char this=c->lengthlist[i];
+ char last=c->lengthlist[i-1];
+ if(this>last){
+ for(j=last;j<this;j++){
+ oggpack_write(opb,i-count,ov_ilog(c->entries-count));
+ count=i;
+ }
+ }
+ }
+ oggpack_write(opb,i-count,ov_ilog(c->entries-count));
+
+ }else{
+ /* length random. Again, we don't code the codeword itself, just
+ the length. This time, though, we have to encode each length */
+ oggpack_write(opb,0,1); /* unordered */
+
+ /* algortihmic mapping has use for 'unused entries', which we tag
+ here. The algorithmic mapping happens as usual, but the unused
+ entry has no codeword. */
+ for(i=0;i<c->entries;i++)
+ if(c->lengthlist[i]==0)break;
+
+ if(i==c->entries){
+ oggpack_write(opb,0,1); /* no unused entries */
+ for(i=0;i<c->entries;i++)
+ oggpack_write(opb,c->lengthlist[i]-1,5);
+ }else{
+ oggpack_write(opb,1,1); /* we have unused entries; thus we tag */
+ for(i=0;i<c->entries;i++){
+ if(c->lengthlist[i]==0){
+ oggpack_write(opb,0,1);
+ }else{
+ oggpack_write(opb,1,1);
+ oggpack_write(opb,c->lengthlist[i]-1,5);
+ }
+ }
+ }
+ }
+
+ /* is the entry number the desired return value, or do we have a
+ mapping? If we have a mapping, what type? */
+ oggpack_write(opb,c->maptype,4);
+ switch(c->maptype){
+ case 0:
+ /* no mapping */
+ break;
+ case 1:case 2:
+ /* implicitly populated value mapping */
+ /* explicitly populated value mapping */
+
+ if(!c->quantlist){
+ /* no quantlist? error */
+ return(-1);
+ }
+
+ /* values that define the dequantization */
+ oggpack_write(opb,c->q_min,32);
+ oggpack_write(opb,c->q_delta,32);
+ oggpack_write(opb,c->q_quant-1,4);
+ oggpack_write(opb,c->q_sequencep,1);
+
+ {
+ int quantvals;
+ switch(c->maptype){
+ case 1:
+ /* a single column of (c->entries/c->dim) quantized values for
+ building a full value list algorithmically (square lattice) */
+ quantvals=_book_maptype1_quantvals(c);
+ break;
+ case 2:
+ /* every value (c->entries*c->dim total) specified explicitly */
+ quantvals=c->entries*c->dim;
+ break;
+ default: /* NOT_REACHABLE */
+ quantvals=-1;
+ }
+
+ /* quantized values */
+ for(i=0;i<quantvals;i++)
+ oggpack_write(opb,labs(c->quantlist[i]),c->q_quant);
+
+ }
+ break;
+ default:
+ /* error case; we don't have any other map types now */
+ return(-1);
+ }
+
+ return(0);
+}
+
+/* unpacks a codebook from the packet buffer into the codebook struct,
+ readies the codebook auxiliary structures for decode *************/
+static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){
+ long i,j;
+ static_codebook *s=_ogg_calloc(1,sizeof(*s));
+ s->allocedp=1;
+
+ /* make sure alignment is correct */
+ if(oggpack_read(opb,24)!=0x564342)goto _eofout;
+
+ /* first the basic parameters */
+ s->dim=oggpack_read(opb,16);
+ s->entries=oggpack_read(opb,24);
+ if(s->entries==-1)goto _eofout;
+
+ if(ov_ilog(s->dim)+ov_ilog(s->entries)>24)goto _eofout;
+
+ /* codeword ordering.... length ordered or unordered? */
+ switch((int)oggpack_read(opb,1)){
+ case 0:{
+ long unused;
+ /* allocated but unused entries? */
+ unused=oggpack_read(opb,1);
+ if((s->entries*(unused?1:5)+7)>>3>opb->storage-oggpack_bytes(opb))
+ goto _eofout;
+ /* unordered */
+ s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
+
+ /* allocated but unused entries? */
+ if(unused){
+ /* yes, unused entries */
+
+ for(i=0;i<s->entries;i++){
+ if(oggpack_read(opb,1)){
+ long num=oggpack_read(opb,5);
+ if(num==-1)goto _eofout;
+ s->lengthlist[i]=num+1;
+ }else
+ s->lengthlist[i]=0;
+ }
+ }else{
+ /* all entries used; no tagging */
+ for(i=0;i<s->entries;i++){
+ long num=oggpack_read(opb,5);
+ if(num==-1)goto _eofout;
+ s->lengthlist[i]=num+1;
+ }
+ }
+
+ break;
+ }
+ case 1:
+ /* ordered */
+ {
+ long length=oggpack_read(opb,5)+1;
+ if(length==0)goto _eofout;
+ s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
+
+ for(i=0;i<s->entries;){
+ long num=oggpack_read(opb,ov_ilog(s->entries-i));
+ if(num==-1)goto _eofout;
+ if(length>32 || num>s->entries-i ||
+ (num>0 && (num-1)>>(length-1)>1)){
+ goto _errout;
+ }
+ if(length>32)goto _errout;
+ for(j=0;j<num;j++,i++)
+ s->lengthlist[i]=length;
+ length++;
+ }
+ }
+ break;
+ default:
+ /* EOF */
+ goto _eofout;
+ }
+
+ /* Do we have a mapping to unpack? */
+ switch((s->maptype=oggpack_read(opb,4))){
+ case 0:
+ /* no mapping */
+ break;
+ case 1: case 2:
+ /* implicitly populated value mapping */
+ /* explicitly populated value mapping */
+
+ s->q_min=oggpack_read(opb,32);
+ s->q_delta=oggpack_read(opb,32);
+ s->q_quant=oggpack_read(opb,4)+1;
+ s->q_sequencep=oggpack_read(opb,1);
+ if(s->q_sequencep==-1)goto _eofout;
+
+ {
+ int quantvals=0;
+ switch(s->maptype){
+ case 1:
+ quantvals=(s->dim==0?0:_book_maptype1_quantvals(s));
+ break;
+ case 2:
+ quantvals=s->entries*s->dim;
+ break;
+ }
+
+ /* quantized values */
+ if(((quantvals*s->q_quant+7)>>3)>opb->storage-oggpack_bytes(opb))
+ goto _eofout;
+ s->quantlist=_ogg_malloc(sizeof(*s->quantlist)*quantvals);
+ for(i=0;i<quantvals;i++)
+ s->quantlist[i]=oggpack_read(opb,s->q_quant);
+
+ if(quantvals&&s->quantlist[quantvals-1]==-1)goto _eofout;
+ }
+ break;
+ default:
+ goto _errout;
+ }
+
+ /* all set */
+ return(s);
+
+ _errout:
+ _eofout:
+ vorbis_staticbook_destroy(s);
+ return(NULL);
+}
+
+/* returns the number of bits ************************************************/
+int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){
+ if(a<0 || a>=book->c->entries)return(0);
+ oggpack_write(b,book->codelist[a],book->c->lengthlist[a]);
+ return(book->c->lengthlist[a]);
+}
+
+/* the 'eliminate the decode tree' optimization actually requires the
+ codewords to be MSb first, not LSb. This is an annoying inelegancy
+ (and one of the first places where carefully thought out design
+ turned out to be wrong; Vorbis II and future Ogg codecs should go
+ to an MSb bitpacker), but not actually the huge hit it appears to
+ be. The first-stage decode table catches most words so that
+ bitreverse is not in the main execution path. */
+
+static ogg_uint32_t bitreverse(ogg_uint32_t x){
+ x= ((x>>16)&0x0000ffff) | ((x<<16)&0xffff0000);
+ x= ((x>> 8)&0x00ff00ff) | ((x<< 8)&0xff00ff00);
+ x= ((x>> 4)&0x0f0f0f0f) | ((x<< 4)&0xf0f0f0f0);
+ x= ((x>> 2)&0x33333333) | ((x<< 2)&0xcccccccc);
+ return((x>> 1)&0x55555555) | ((x<< 1)&0xaaaaaaaa);
+}
+
+STIN long decode_packed_entry_number(codebook *book, oggpack_buffer *b){
+ int read=book->dec_maxlength;
+ long lo,hi;
+ long lok = oggpack_look(b,book->dec_firsttablen);
+
+ if (lok >= 0) {
+ long entry = book->dec_firsttable[lok];
+ if(entry&0x80000000UL){
+ lo=(entry>>15)&0x7fff;
+ hi=book->used_entries-(entry&0x7fff);
+ }else{
+ oggpack_adv(b, book->dec_codelengths[entry-1]);
+ return(entry-1);
+ }
+ }else{
+ lo=0;
+ hi=book->used_entries;
+ }
+
+ /* Single entry codebooks use a firsttablen of 1 and a
+ dec_maxlength of 1. If a single-entry codebook gets here (due to
+ failure to read one bit above), the next look attempt will also
+ fail and we'll correctly kick out instead of trying to walk the
+ underformed tree */
+
+ lok = oggpack_look(b, read);
+
+ while(lok<0 && read>1)
+ lok = oggpack_look(b, --read);
+ if(lok<0)return -1;
+
+ /* bisect search for the codeword in the ordered list */
+ {
+ ogg_uint32_t testword=bitreverse((ogg_uint32_t)lok);
+
+ while(hi-lo>1){
+ long p=(hi-lo)>>1;
+ long test=book->codelist[lo+p]>testword;
+ lo+=p&(test-1);
+ hi-=p&(-test);
+ }
+
+ if(book->dec_codelengths[lo]<=read){
+ oggpack_adv(b, book->dec_codelengths[lo]);
+ return(lo);
+ }
+ }
+
+ oggpack_adv(b, read);
+
+ return(-1);
+}
+
+/* Decode side is specced and easier, because we don't need to find
+ matches using different criteria; we simply read and map. There are
+ two things we need to do 'depending':
+
+ We may need to support interleave. We don't really, but it's
+ convenient to do it here rather than rebuild the vector later.
+
+ Cascades may be additive or multiplicitive; this is not inherent in
+ the codebook, but set in the code using the codebook. Like
+ interleaving, it's easiest to do it here.
+ addmul==0 -> declarative (set the value)
+ addmul==1 -> additive
+ addmul==2 -> multiplicitive */
+
+/* returns the [original, not compacted] entry number or -1 on eof *********/
+long vorbis_book_decode(codebook *book, oggpack_buffer *b){
+ if(book->used_entries>0){
+ long packed_entry=decode_packed_entry_number(book,b);
+ if(packed_entry>=0)
+ return(book->dec_index[packed_entry]);
+ }
+
+ /* if there's no dec_index, the codebook unpacking isn't collapsed */
+ return(-1);
+}
+
+/* returns 0 on OK or -1 on eof *************************************/
+/* decode vector / dim granularity gaurding is done in the upper layer */
+long vorbis_book_decodevs_add(codebook *book,float *a,oggpack_buffer *b,int n){
+ if(book->used_entries>0){
+ int step=n/book->dim;
+ long *entry = alloca(sizeof(*entry)*step);
+ float **t = alloca(sizeof(*t)*step);
+ int i,j,o;
+
+ for (i = 0; i < step; i++) {
+ entry[i]=decode_packed_entry_number(book,b);
+ if(entry[i]==-1)return(-1);
+ t[i] = book->valuelist+entry[i]*book->dim;
+ }
+ for(i=0,o=0;i<book->dim;i++,o+=step)
+ for (j=0;j<step;j++)
+ a[o+j]+=t[j][i];
+ }
+ return(0);
+}
+
+/* decode vector / dim granularity gaurding is done in the upper layer */
+long vorbis_book_decodev_add(codebook *book,float *a,oggpack_buffer *b,int n){
+ if(book->used_entries>0){
+ int i,j,entry;
+ float *t;
+
+ if(book->dim>8){
+ for(i=0;i<n;){
+ entry = decode_packed_entry_number(book,b);
+ if(entry==-1)return(-1);
+ t = book->valuelist+entry*book->dim;
+ for (j=0;j<book->dim;)
+ a[i++]+=t[j++];
+ }
+ }else{
+ for(i=0;i<n;){
+ entry = decode_packed_entry_number(book,b);
+ if(entry==-1)return(-1);
+ t = book->valuelist+entry*book->dim;
+ j=0;
+ switch((int)book->dim){
+ case 8:
+ a[i++]+=t[j++];
+ case 7:
+ a[i++]+=t[j++];
+ case 6:
+ a[i++]+=t[j++];
+ case 5:
+ a[i++]+=t[j++];
+ case 4:
+ a[i++]+=t[j++];
+ case 3:
+ a[i++]+=t[j++];
+ case 2:
+ a[i++]+=t[j++];
+ case 1:
+ a[i++]+=t[j++];
+ case 0:
+ break;
+ }
+ }
+ }
+ }
+ return(0);
+}
+
+/* unlike the others, we guard against n not being an integer number
+ of <dim> internally rather than in the upper layer (called only by
+ floor0) */
+long vorbis_book_decodev_set(codebook *book,float *a,oggpack_buffer *b,int n){
+ if(book->used_entries>0){
+ int i,j,entry;
+ float *t;
+
+ for(i=0;i<n;){
+ entry = decode_packed_entry_number(book,b);
+ if(entry==-1)return(-1);
+ t = book->valuelist+entry*book->dim;
+ for (j=0;i<n && j<book->dim;){
+ a[i++]=t[j++];
+ }
+ }
+ }else{
+ int i;
+
+ for(i=0;i<n;){
+ a[i++]=0.f;
+ }
+ }
+ return(0);
+}
+
+long vorbis_book_decodevv_add(codebook *book,float **a,long offset,int ch,
+ oggpack_buffer *b,int n){
+
+ long i,j,entry;
+ int chptr=0;
+ if(book->used_entries>0){
+ for(i=offset/ch;i<(offset+n)/ch;){
+ entry = decode_packed_entry_number(book,b);
+ if(entry==-1)return(-1);
+ {
+ const float *t = book->valuelist+entry*book->dim;
+ for (j=0;j<book->dim;j++){
+ a[chptr++][i]+=t[j];
+ if(chptr==ch){
+ chptr=0;
+ i++;
+ }
+ }
+ }
+ }
+ }
+ return(0);
+}
diff --git a/external/libvorbis-1.3.5/lib/codebook.h b/external/libvorbis-1.3.5/lib/codebook.h
new file mode 100644
index 0000000..537d6c1
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/codebook.h
@@ -0,0 +1,118 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: basic shared codebook operations
+ last mod: $Id: codebook.h 19457 2015-03-03 00:15:29Z giles $
+
+ ********************************************************************/
+
+#ifndef _V_CODEBOOK_H_
+#define _V_CODEBOOK_H_
+
+#include <ogg/ogg.h>
+
+/* This structure encapsulates huffman and VQ style encoding books; it
+ doesn't do anything specific to either.
+
+ valuelist/quantlist are nonNULL (and q_* significant) only if
+ there's entry->value mapping to be done.
+
+ If encode-side mapping must be done (and thus the entry needs to be
+ hunted), the auxiliary encode pointer will point to a decision
+ tree. This is true of both VQ and huffman, but is mostly useful
+ with VQ.
+
+*/
+
+typedef struct static_codebook{
+ long dim; /* codebook dimensions (elements per vector) */
+ long entries; /* codebook entries */
+ char *lengthlist; /* codeword lengths in bits */
+
+ /* mapping ***************************************************************/
+ int maptype; /* 0=none
+ 1=implicitly populated values from map column
+ 2=listed arbitrary values */
+
+ /* The below does a linear, single monotonic sequence mapping. */
+ long q_min; /* packed 32 bit float; quant value 0 maps to minval */
+ long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */
+ int q_quant; /* bits: 0 < quant <= 16 */
+ int q_sequencep; /* bitflag */
+
+ long *quantlist; /* map == 1: (int)(entries^(1/dim)) element column map
+ map == 2: list of dim*entries quantized entry vals
+ */
+ int allocedp;
+} static_codebook;
+
+typedef struct codebook{
+ long dim; /* codebook dimensions (elements per vector) */
+ long entries; /* codebook entries */
+ long used_entries; /* populated codebook entries */
+ const static_codebook *c;
+
+ /* for encode, the below are entry-ordered, fully populated */
+ /* for decode, the below are ordered by bitreversed codeword and only
+ used entries are populated */
+ float *valuelist; /* list of dim*entries actual entry values */
+ ogg_uint32_t *codelist; /* list of bitstream codewords for each entry */
+
+ int *dec_index; /* only used if sparseness collapsed */
+ char *dec_codelengths;
+ ogg_uint32_t *dec_firsttable;
+ int dec_firsttablen;
+ int dec_maxlength;
+
+ /* The current encoder uses only centered, integer-only lattice books. */
+ int quantvals;
+ int minval;
+ int delta;
+} codebook;
+
+extern void vorbis_staticbook_destroy(static_codebook *b);
+extern int vorbis_book_init_encode(codebook *dest,const static_codebook *source);
+extern int vorbis_book_init_decode(codebook *dest,const static_codebook *source);
+extern void vorbis_book_clear(codebook *b);
+
+extern float *_book_unquantize(const static_codebook *b,int n,int *map);
+extern float *_book_logdist(const static_codebook *b,float *vals);
+extern float _float32_unpack(long val);
+extern long _float32_pack(float val);
+extern int _best(codebook *book, float *a, int step);
+extern long _book_maptype1_quantvals(const static_codebook *b);
+
+extern int vorbis_book_besterror(codebook *book,float *a,int step,int addmul);
+extern long vorbis_book_codeword(codebook *book,int entry);
+extern long vorbis_book_codelen(codebook *book,int entry);
+
+
+
+extern int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *b);
+extern static_codebook *vorbis_staticbook_unpack(oggpack_buffer *b);
+
+extern int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b);
+
+extern long vorbis_book_decode(codebook *book, oggpack_buffer *b);
+extern long vorbis_book_decodevs_add(codebook *book, float *a,
+ oggpack_buffer *b,int n);
+extern long vorbis_book_decodev_set(codebook *book, float *a,
+ oggpack_buffer *b,int n);
+extern long vorbis_book_decodev_add(codebook *book, float *a,
+ oggpack_buffer *b,int n);
+extern long vorbis_book_decodevv_add(codebook *book, float **a,
+ long off,int ch,
+ oggpack_buffer *b,int n);
+
+
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/codec_internal.h b/external/libvorbis-1.3.5/lib/codec_internal.h
new file mode 100644
index 0000000..de1bcca
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/codec_internal.h
@@ -0,0 +1,167 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: libvorbis codec headers
+ last mod: $Id: codec_internal.h 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_CODECI_H_
+#define _V_CODECI_H_
+
+#include "envelope.h"
+#include "codebook.h"
+
+#define BLOCKTYPE_IMPULSE 0
+#define BLOCKTYPE_PADDING 1
+#define BLOCKTYPE_TRANSITION 0
+#define BLOCKTYPE_LONG 1
+
+#define PACKETBLOBS 15
+
+typedef struct vorbis_block_internal{
+ float **pcmdelay; /* this is a pointer into local storage */
+ float ampmax;
+ int blocktype;
+
+ oggpack_buffer *packetblob[PACKETBLOBS]; /* initialized, must be freed;
+ blob [PACKETBLOBS/2] points to
+ the oggpack_buffer in the
+ main vorbis_block */
+} vorbis_block_internal;
+
+typedef void vorbis_look_floor;
+typedef void vorbis_look_residue;
+typedef void vorbis_look_transform;
+
+/* mode ************************************************************/
+typedef struct {
+ int blockflag;
+ int windowtype;
+ int transformtype;
+ int mapping;
+} vorbis_info_mode;
+
+typedef void vorbis_info_floor;
+typedef void vorbis_info_residue;
+typedef void vorbis_info_mapping;
+
+#include "psy.h"
+#include "bitrate.h"
+
+typedef struct private_state {
+ /* local lookup storage */
+ envelope_lookup *ve; /* envelope lookup */
+ int window[2];
+ vorbis_look_transform **transform[2]; /* block, type */
+ drft_lookup fft_look[2];
+
+ int modebits;
+ vorbis_look_floor **flr;
+ vorbis_look_residue **residue;
+ vorbis_look_psy *psy;
+ vorbis_look_psy_global *psy_g_look;
+
+ /* local storage, only used on the encoding side. This way the
+ application does not need to worry about freeing some packets'
+ memory and not others'; packet storage is always tracked.
+ Cleared next call to a _dsp_ function */
+ unsigned char *header;
+ unsigned char *header1;
+ unsigned char *header2;
+
+ bitrate_manager_state bms;
+
+ ogg_int64_t sample_count;
+} private_state;
+
+/* codec_setup_info contains all the setup information specific to the
+ specific compression/decompression mode in progress (eg,
+ psychoacoustic settings, channel setup, options, codebook
+ etc).
+*********************************************************************/
+
+#include "highlevel.h"
+typedef struct codec_setup_info {
+
+ /* Vorbis supports only short and long blocks, but allows the
+ encoder to choose the sizes */
+
+ long blocksizes[2];
+
+ /* modes are the primary means of supporting on-the-fly different
+ blocksizes, different channel mappings (LR or M/A),
+ different residue backends, etc. Each mode consists of a
+ blocksize flag and a mapping (along with the mapping setup */
+
+ int modes;
+ int maps;
+ int floors;
+ int residues;
+ int books;
+ int psys; /* encode only */
+
+ vorbis_info_mode *mode_param[64];
+ int map_type[64];
+ vorbis_info_mapping *map_param[64];
+ int floor_type[64];
+ vorbis_info_floor *floor_param[64];
+ int residue_type[64];
+ vorbis_info_residue *residue_param[64];
+ static_codebook *book_param[256];
+ codebook *fullbooks;
+
+ vorbis_info_psy *psy_param[4]; /* encode only */
+ vorbis_info_psy_global psy_g_param;
+
+ bitrate_manager_info bi;
+ highlevel_encode_setup hi; /* used only by vorbisenc.c. It's a
+ highly redundant structure, but
+ improves clarity of program flow. */
+ int halfrate_flag; /* painless downsample for decode */
+} codec_setup_info;
+
+extern vorbis_look_psy_global *_vp_global_look(vorbis_info *vi);
+extern void _vp_global_free(vorbis_look_psy_global *look);
+
+
+
+typedef struct {
+ int sorted_index[VIF_POSIT+2];
+ int forward_index[VIF_POSIT+2];
+ int reverse_index[VIF_POSIT+2];
+
+ int hineighbor[VIF_POSIT];
+ int loneighbor[VIF_POSIT];
+ int posts;
+
+ int n;
+ int quant_q;
+ vorbis_info_floor1 *vi;
+
+ long phrasebits;
+ long postbits;
+ long frames;
+} vorbis_look_floor1;
+
+
+
+extern int *floor1_fit(vorbis_block *vb,vorbis_look_floor1 *look,
+ const float *logmdct, /* in */
+ const float *logmask);
+extern int *floor1_interpolate_fit(vorbis_block *vb,vorbis_look_floor1 *look,
+ int *A,int *B,
+ int del);
+extern int floor1_encode(oggpack_buffer *opb,vorbis_block *vb,
+ vorbis_look_floor1 *look,
+ int *post,int *ilogmask);
+#endif
diff --git a/external/libvorbis-1.3.5/lib/envelope.c b/external/libvorbis-1.3.5/lib/envelope.c
new file mode 100644
index 0000000..010c66e
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/envelope.c
@@ -0,0 +1,375 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: PCM data envelope analysis
+ last mod: $Id: envelope.c 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+
+#include "os.h"
+#include "scales.h"
+#include "envelope.h"
+#include "mdct.h"
+#include "misc.h"
+
+void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy_global *gi=&ci->psy_g_param;
+ int ch=vi->channels;
+ int i,j;
+ int n=e->winlength=128;
+ e->searchstep=64; /* not random */
+
+ e->minenergy=gi->preecho_minenergy;
+ e->ch=ch;
+ e->storage=128;
+ e->cursor=ci->blocksizes[1]/2;
+ e->mdct_win=_ogg_calloc(n,sizeof(*e->mdct_win));
+ mdct_init(&e->mdct,n);
+
+ for(i=0;i<n;i++){
+ e->mdct_win[i]=sin(i/(n-1.)*M_PI);
+ e->mdct_win[i]*=e->mdct_win[i];
+ }
+
+ /* magic follows */
+ e->band[0].begin=2; e->band[0].end=4;
+ e->band[1].begin=4; e->band[1].end=5;
+ e->band[2].begin=6; e->band[2].end=6;
+ e->band[3].begin=9; e->band[3].end=8;
+ e->band[4].begin=13; e->band[4].end=8;
+ e->band[5].begin=17; e->band[5].end=8;
+ e->band[6].begin=22; e->band[6].end=8;
+
+ for(j=0;j<VE_BANDS;j++){
+ n=e->band[j].end;
+ e->band[j].window=_ogg_malloc(n*sizeof(*e->band[0].window));
+ for(i=0;i<n;i++){
+ e->band[j].window[i]=sin((i+.5)/n*M_PI);
+ e->band[j].total+=e->band[j].window[i];
+ }
+ e->band[j].total=1./e->band[j].total;
+ }
+
+ e->filter=_ogg_calloc(VE_BANDS*ch,sizeof(*e->filter));
+ e->mark=_ogg_calloc(e->storage,sizeof(*e->mark));
+
+}
+
+void _ve_envelope_clear(envelope_lookup *e){
+ int i;
+ mdct_clear(&e->mdct);
+ for(i=0;i<VE_BANDS;i++)
+ _ogg_free(e->band[i].window);
+ _ogg_free(e->mdct_win);
+ _ogg_free(e->filter);
+ _ogg_free(e->mark);
+ memset(e,0,sizeof(*e));
+}
+
+/* fairly straight threshhold-by-band based until we find something
+ that works better and isn't patented. */
+
+static int _ve_amp(envelope_lookup *ve,
+ vorbis_info_psy_global *gi,
+ float *data,
+ envelope_band *bands,
+ envelope_filter_state *filters){
+ long n=ve->winlength;
+ int ret=0;
+ long i,j;
+ float decay;
+
+ /* we want to have a 'minimum bar' for energy, else we're just
+ basing blocks on quantization noise that outweighs the signal
+ itself (for low power signals) */
+
+ float minV=ve->minenergy;
+ float *vec=alloca(n*sizeof(*vec));
+
+ /* stretch is used to gradually lengthen the number of windows
+ considered prevoius-to-potential-trigger */
+ int stretch=max(VE_MINSTRETCH,ve->stretch/2);
+ float penalty=gi->stretch_penalty-(ve->stretch/2-VE_MINSTRETCH);
+ if(penalty<0.f)penalty=0.f;
+ if(penalty>gi->stretch_penalty)penalty=gi->stretch_penalty;
+
+ /*_analysis_output_always("lpcm",seq2,data,n,0,0,
+ totalshift+pos*ve->searchstep);*/
+
+ /* window and transform */
+ for(i=0;i<n;i++)
+ vec[i]=data[i]*ve->mdct_win[i];
+ mdct_forward(&ve->mdct,vec,vec);
+
+ /*_analysis_output_always("mdct",seq2,vec,n/2,0,1,0); */
+
+ /* near-DC spreading function; this has nothing to do with
+ psychoacoustics, just sidelobe leakage and window size */
+ {
+ float temp=vec[0]*vec[0]+.7*vec[1]*vec[1]+.2*vec[2]*vec[2];
+ int ptr=filters->nearptr;
+
+ /* the accumulation is regularly refreshed from scratch to avoid
+ floating point creep */
+ if(ptr==0){
+ decay=filters->nearDC_acc=filters->nearDC_partialacc+temp;
+ filters->nearDC_partialacc=temp;
+ }else{
+ decay=filters->nearDC_acc+=temp;
+ filters->nearDC_partialacc+=temp;
+ }
+ filters->nearDC_acc-=filters->nearDC[ptr];
+ filters->nearDC[ptr]=temp;
+
+ decay*=(1./(VE_NEARDC+1));
+ filters->nearptr++;
+ if(filters->nearptr>=VE_NEARDC)filters->nearptr=0;
+ decay=todB(&decay)*.5-15.f;
+ }
+
+ /* perform spreading and limiting, also smooth the spectrum. yes,
+ the MDCT results in all real coefficients, but it still *behaves*
+ like real/imaginary pairs */
+ for(i=0;i<n/2;i+=2){
+ float val=vec[i]*vec[i]+vec[i+1]*vec[i+1];
+ val=todB(&val)*.5f;
+ if(val<decay)val=decay;
+ if(val<minV)val=minV;
+ vec[i>>1]=val;
+ decay-=8.;
+ }
+
+ /*_analysis_output_always("spread",seq2++,vec,n/4,0,0,0);*/
+
+ /* perform preecho/postecho triggering by band */
+ for(j=0;j<VE_BANDS;j++){
+ float acc=0.;
+ float valmax,valmin;
+
+ /* accumulate amplitude */
+ for(i=0;i<bands[j].end;i++)
+ acc+=vec[i+bands[j].begin]*bands[j].window[i];
+
+ acc*=bands[j].total;
+
+ /* convert amplitude to delta */
+ {
+ int p,this=filters[j].ampptr;
+ float postmax,postmin,premax=-99999.f,premin=99999.f;
+
+ p=this;
+ p--;
+ if(p<0)p+=VE_AMP;
+ postmax=max(acc,filters[j].ampbuf[p]);
+ postmin=min(acc,filters[j].ampbuf[p]);
+
+ for(i=0;i<stretch;i++){
+ p--;
+ if(p<0)p+=VE_AMP;
+ premax=max(premax,filters[j].ampbuf[p]);
+ premin=min(premin,filters[j].ampbuf[p]);
+ }
+
+ valmin=postmin-premin;
+ valmax=postmax-premax;
+
+ /*filters[j].markers[pos]=valmax;*/
+ filters[j].ampbuf[this]=acc;
+ filters[j].ampptr++;
+ if(filters[j].ampptr>=VE_AMP)filters[j].ampptr=0;
+ }
+
+ /* look at min/max, decide trigger */
+ if(valmax>gi->preecho_thresh[j]+penalty){
+ ret|=1;
+ ret|=4;
+ }
+ if(valmin<gi->postecho_thresh[j]-penalty)ret|=2;
+ }
+
+ return(ret);
+}
+
+#if 0
+static int seq=0;
+static ogg_int64_t totalshift=-1024;
+#endif
+
+long _ve_envelope_search(vorbis_dsp_state *v){
+ vorbis_info *vi=v->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy_global *gi=&ci->psy_g_param;
+ envelope_lookup *ve=((private_state *)(v->backend_state))->ve;
+ long i,j;
+
+ int first=ve->current/ve->searchstep;
+ int last=v->pcm_current/ve->searchstep-VE_WIN;
+ if(first<0)first=0;
+
+ /* make sure we have enough storage to match the PCM */
+ if(last+VE_WIN+VE_POST>ve->storage){
+ ve->storage=last+VE_WIN+VE_POST; /* be sure */
+ ve->mark=_ogg_realloc(ve->mark,ve->storage*sizeof(*ve->mark));
+ }
+
+ for(j=first;j<last;j++){
+ int ret=0;
+
+ ve->stretch++;
+ if(ve->stretch>VE_MAXSTRETCH*2)
+ ve->stretch=VE_MAXSTRETCH*2;
+
+ for(i=0;i<ve->ch;i++){
+ float *pcm=v->pcm[i]+ve->searchstep*(j);
+ ret|=_ve_amp(ve,gi,pcm,ve->band,ve->filter+i*VE_BANDS);
+ }
+
+ ve->mark[j+VE_POST]=0;
+ if(ret&1){
+ ve->mark[j]=1;
+ ve->mark[j+1]=1;
+ }
+
+ if(ret&2){
+ ve->mark[j]=1;
+ if(j>0)ve->mark[j-1]=1;
+ }
+
+ if(ret&4)ve->stretch=-1;
+ }
+
+ ve->current=last*ve->searchstep;
+
+ {
+ long centerW=v->centerW;
+ long testW=
+ centerW+
+ ci->blocksizes[v->W]/4+
+ ci->blocksizes[1]/2+
+ ci->blocksizes[0]/4;
+
+ j=ve->cursor;
+
+ while(j<ve->current-(ve->searchstep)){/* account for postecho
+ working back one window */
+ if(j>=testW)return(1);
+
+ ve->cursor=j;
+
+ if(ve->mark[j/ve->searchstep]){
+ if(j>centerW){
+
+#if 0
+ if(j>ve->curmark){
+ float *marker=alloca(v->pcm_current*sizeof(*marker));
+ int l,m;
+ memset(marker,0,sizeof(*marker)*v->pcm_current);
+ fprintf(stderr,"mark! seq=%d, cursor:%fs time:%fs\n",
+ seq,
+ (totalshift+ve->cursor)/44100.,
+ (totalshift+j)/44100.);
+ _analysis_output_always("pcmL",seq,v->pcm[0],v->pcm_current,0,0,totalshift);
+ _analysis_output_always("pcmR",seq,v->pcm[1],v->pcm_current,0,0,totalshift);
+
+ _analysis_output_always("markL",seq,v->pcm[0],j,0,0,totalshift);
+ _analysis_output_always("markR",seq,v->pcm[1],j,0,0,totalshift);
+
+ for(m=0;m<VE_BANDS;m++){
+ char buf[80];
+ sprintf(buf,"delL%d",m);
+ for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[m].markers[l]*.1;
+ _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift);
+ }
+
+ for(m=0;m<VE_BANDS;m++){
+ char buf[80];
+ sprintf(buf,"delR%d",m);
+ for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[m+VE_BANDS].markers[l]*.1;
+ _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift);
+ }
+
+ for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->mark[l]*.4;
+ _analysis_output_always("mark",seq,marker,v->pcm_current,0,0,totalshift);
+
+
+ seq++;
+
+ }
+#endif
+
+ ve->curmark=j;
+ if(j>=testW)return(1);
+ return(0);
+ }
+ }
+ j+=ve->searchstep;
+ }
+ }
+
+ return(-1);
+}
+
+int _ve_envelope_mark(vorbis_dsp_state *v){
+ envelope_lookup *ve=((private_state *)(v->backend_state))->ve;
+ vorbis_info *vi=v->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ long centerW=v->centerW;
+ long beginW=centerW-ci->blocksizes[v->W]/4;
+ long endW=centerW+ci->blocksizes[v->W]/4;
+ if(v->W){
+ beginW-=ci->blocksizes[v->lW]/4;
+ endW+=ci->blocksizes[v->nW]/4;
+ }else{
+ beginW-=ci->blocksizes[0]/4;
+ endW+=ci->blocksizes[0]/4;
+ }
+
+ if(ve->curmark>=beginW && ve->curmark<endW)return(1);
+ {
+ long first=beginW/ve->searchstep;
+ long last=endW/ve->searchstep;
+ long i;
+ for(i=first;i<last;i++)
+ if(ve->mark[i])return(1);
+ }
+ return(0);
+}
+
+void _ve_envelope_shift(envelope_lookup *e,long shift){
+ int smallsize=e->current/e->searchstep+VE_POST; /* adjust for placing marks
+ ahead of ve->current */
+ int smallshift=shift/e->searchstep;
+
+ memmove(e->mark,e->mark+smallshift,(smallsize-smallshift)*sizeof(*e->mark));
+
+#if 0
+ for(i=0;i<VE_BANDS*e->ch;i++)
+ memmove(e->filter[i].markers,
+ e->filter[i].markers+smallshift,
+ (1024-smallshift)*sizeof(*(*e->filter).markers));
+ totalshift+=shift;
+#endif
+
+ e->current-=shift;
+ if(e->curmark>=0)
+ e->curmark-=shift;
+ e->cursor-=shift;
+}
diff --git a/external/libvorbis-1.3.5/lib/envelope.h b/external/libvorbis-1.3.5/lib/envelope.h
new file mode 100644
index 0000000..fd15fb3
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/envelope.h
@@ -0,0 +1,80 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: PCM data envelope analysis and manipulation
+ last mod: $Id: envelope.h 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_ENVELOPE_
+#define _V_ENVELOPE_
+
+#include "mdct.h"
+
+#define VE_PRE 16
+#define VE_WIN 4
+#define VE_POST 2
+#define VE_AMP (VE_PRE+VE_POST-1)
+
+#define VE_BANDS 7
+#define VE_NEARDC 15
+
+#define VE_MINSTRETCH 2 /* a bit less than short block */
+#define VE_MAXSTRETCH 12 /* one-third full block */
+
+typedef struct {
+ float ampbuf[VE_AMP];
+ int ampptr;
+
+ float nearDC[VE_NEARDC];
+ float nearDC_acc;
+ float nearDC_partialacc;
+ int nearptr;
+
+} envelope_filter_state;
+
+typedef struct {
+ int begin;
+ int end;
+ float *window;
+ float total;
+} envelope_band;
+
+typedef struct {
+ int ch;
+ int winlength;
+ int searchstep;
+ float minenergy;
+
+ mdct_lookup mdct;
+ float *mdct_win;
+
+ envelope_band band[VE_BANDS];
+ envelope_filter_state *filter;
+ int stretch;
+
+ int *mark;
+
+ long storage;
+ long current;
+ long curmark;
+ long cursor;
+} envelope_lookup;
+
+extern void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi);
+extern void _ve_envelope_clear(envelope_lookup *e);
+extern long _ve_envelope_search(vorbis_dsp_state *v);
+extern void _ve_envelope_shift(envelope_lookup *e,long shift);
+extern int _ve_envelope_mark(vorbis_dsp_state *v);
+
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/floor0.c b/external/libvorbis-1.3.5/lib/floor0.c
new file mode 100644
index 0000000..213cce4
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/floor0.c
@@ -0,0 +1,224 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: floor backend 0 implementation
+ last mod: $Id: floor0.c 19457 2015-03-03 00:15:29Z giles $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+#include "registry.h"
+#include "lpc.h"
+#include "lsp.h"
+#include "codebook.h"
+#include "scales.h"
+#include "misc.h"
+#include "os.h"
+
+#include "misc.h"
+#include <stdio.h>
+
+typedef struct {
+ int ln;
+ int m;
+ int **linearmap;
+ int n[2];
+
+ vorbis_info_floor0 *vi;
+
+ long bits;
+ long frames;
+} vorbis_look_floor0;
+
+
+/***********************************************/
+
+static void floor0_free_info(vorbis_info_floor *i){
+ vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
+ if(info){
+ memset(info,0,sizeof(*info));
+ _ogg_free(info);
+ }
+}
+
+static void floor0_free_look(vorbis_look_floor *i){
+ vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
+ if(look){
+
+ if(look->linearmap){
+
+ if(look->linearmap[0])_ogg_free(look->linearmap[0]);
+ if(look->linearmap[1])_ogg_free(look->linearmap[1]);
+
+ _ogg_free(look->linearmap);
+ }
+ memset(look,0,sizeof(*look));
+ _ogg_free(look);
+ }
+}
+
+static vorbis_info_floor *floor0_unpack (vorbis_info *vi,oggpack_buffer *opb){
+ codec_setup_info *ci=vi->codec_setup;
+ int j;
+
+ vorbis_info_floor0 *info=_ogg_malloc(sizeof(*info));
+ info->order=oggpack_read(opb,8);
+ info->rate=oggpack_read(opb,16);
+ info->barkmap=oggpack_read(opb,16);
+ info->ampbits=oggpack_read(opb,6);
+ info->ampdB=oggpack_read(opb,8);
+ info->numbooks=oggpack_read(opb,4)+1;
+
+ if(info->order<1)goto err_out;
+ if(info->rate<1)goto err_out;
+ if(info->barkmap<1)goto err_out;
+ if(info->numbooks<1)goto err_out;
+
+ for(j=0;j<info->numbooks;j++){
+ info->books[j]=oggpack_read(opb,8);
+ if(info->books[j]<0 || info->books[j]>=ci->books)goto err_out;
+ if(ci->book_param[info->books[j]]->maptype==0)goto err_out;
+ if(ci->book_param[info->books[j]]->dim<1)goto err_out;
+ }
+ return(info);
+
+ err_out:
+ floor0_free_info(info);
+ return(NULL);
+}
+
+/* initialize Bark scale and normalization lookups. We could do this
+ with static tables, but Vorbis allows a number of possible
+ combinations, so it's best to do it computationally.
+
+ The below is authoritative in terms of defining scale mapping.
+ Note that the scale depends on the sampling rate as well as the
+ linear block and mapping sizes */
+
+static void floor0_map_lazy_init(vorbis_block *vb,
+ vorbis_info_floor *infoX,
+ vorbis_look_floor0 *look){
+ if(!look->linearmap[vb->W]){
+ vorbis_dsp_state *vd=vb->vd;
+ vorbis_info *vi=vd->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_floor0 *info=(vorbis_info_floor0 *)infoX;
+ int W=vb->W;
+ int n=ci->blocksizes[W]/2,j;
+
+ /* we choose a scaling constant so that:
+ floor(bark(rate/2-1)*C)=mapped-1
+ floor(bark(rate/2)*C)=mapped */
+ float scale=look->ln/toBARK(info->rate/2.f);
+
+ /* the mapping from a linear scale to a smaller bark scale is
+ straightforward. We do *not* make sure that the linear mapping
+ does not skip bark-scale bins; the decoder simply skips them and
+ the encoder may do what it wishes in filling them. They're
+ necessary in some mapping combinations to keep the scale spacing
+ accurate */
+ look->linearmap[W]=_ogg_malloc((n+1)*sizeof(**look->linearmap));
+ for(j=0;j<n;j++){
+ int val=floor( toBARK((info->rate/2.f)/n*j)
+ *scale); /* bark numbers represent band edges */
+ if(val>=look->ln)val=look->ln-1; /* guard against the approximation */
+ look->linearmap[W][j]=val;
+ }
+ look->linearmap[W][j]=-1;
+ look->n[W]=n;
+ }
+}
+
+static vorbis_look_floor *floor0_look(vorbis_dsp_state *vd,
+ vorbis_info_floor *i){
+ vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
+ vorbis_look_floor0 *look=_ogg_calloc(1,sizeof(*look));
+
+ (void)vd;
+
+ look->m=info->order;
+ look->ln=info->barkmap;
+ look->vi=info;
+
+ look->linearmap=_ogg_calloc(2,sizeof(*look->linearmap));
+
+ return look;
+}
+
+static void *floor0_inverse1(vorbis_block *vb,vorbis_look_floor *i){
+ vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
+ vorbis_info_floor0 *info=look->vi;
+ int j,k;
+
+ int ampraw=oggpack_read(&vb->opb,info->ampbits);
+ if(ampraw>0){ /* also handles the -1 out of data case */
+ long maxval=(1<<info->ampbits)-1;
+ float amp=(float)ampraw/maxval*info->ampdB;
+ int booknum=oggpack_read(&vb->opb,ov_ilog(info->numbooks));
+
+ if(booknum!=-1 && booknum<info->numbooks){ /* be paranoid */
+ codec_setup_info *ci=vb->vd->vi->codec_setup;
+ codebook *b=ci->fullbooks+info->books[booknum];
+ float last=0.f;
+
+ /* the additional b->dim is a guard against any possible stack
+ smash; b->dim is provably more than we can overflow the
+ vector */
+ float *lsp=_vorbis_block_alloc(vb,sizeof(*lsp)*(look->m+b->dim+1));
+
+ if(vorbis_book_decodev_set(b,lsp,&vb->opb,look->m)==-1)goto eop;
+ for(j=0;j<look->m;){
+ for(k=0;j<look->m && k<b->dim;k++,j++)lsp[j]+=last;
+ last=lsp[j-1];
+ }
+
+ lsp[look->m]=amp;
+ return(lsp);
+ }
+ }
+ eop:
+ return(NULL);
+}
+
+static int floor0_inverse2(vorbis_block *vb,vorbis_look_floor *i,
+ void *memo,float *out){
+ vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
+ vorbis_info_floor0 *info=look->vi;
+
+ floor0_map_lazy_init(vb,info,look);
+
+ if(memo){
+ float *lsp=(float *)memo;
+ float amp=lsp[look->m];
+
+ /* take the coefficients back to a spectral envelope curve */
+ vorbis_lsp_to_curve(out,
+ look->linearmap[vb->W],
+ look->n[vb->W],
+ look->ln,
+ lsp,look->m,amp,(float)info->ampdB);
+ return(1);
+ }
+ memset(out,0,sizeof(*out)*look->n[vb->W]);
+ return(0);
+}
+
+/* export hooks */
+const vorbis_func_floor floor0_exportbundle={
+ NULL,&floor0_unpack,&floor0_look,&floor0_free_info,
+ &floor0_free_look,&floor0_inverse1,&floor0_inverse2
+};
diff --git a/external/libvorbis-1.3.5/lib/floor1.c b/external/libvorbis-1.3.5/lib/floor1.c
new file mode 100644
index 0000000..d8bd464
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/floor1.c
@@ -0,0 +1,1087 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: floor backend 1 implementation
+ last mod: $Id: floor1.c 19457 2015-03-03 00:15:29Z giles $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+#include "registry.h"
+#include "codebook.h"
+#include "misc.h"
+#include "scales.h"
+
+#include <stdio.h>
+
+#define floor1_rangedB 140 /* floor 1 fixed at -140dB to 0dB range */
+
+typedef struct lsfit_acc{
+ int x0;
+ int x1;
+
+ int xa;
+ int ya;
+ int x2a;
+ int y2a;
+ int xya;
+ int an;
+
+ int xb;
+ int yb;
+ int x2b;
+ int y2b;
+ int xyb;
+ int bn;
+} lsfit_acc;
+
+/***********************************************/
+
+static void floor1_free_info(vorbis_info_floor *i){
+ vorbis_info_floor1 *info=(vorbis_info_floor1 *)i;
+ if(info){
+ memset(info,0,sizeof(*info));
+ _ogg_free(info);
+ }
+}
+
+static void floor1_free_look(vorbis_look_floor *i){
+ vorbis_look_floor1 *look=(vorbis_look_floor1 *)i;
+ if(look){
+ /*fprintf(stderr,"floor 1 bit usage %f:%f (%f total)\n",
+ (float)look->phrasebits/look->frames,
+ (float)look->postbits/look->frames,
+ (float)(look->postbits+look->phrasebits)/look->frames);*/
+
+ memset(look,0,sizeof(*look));
+ _ogg_free(look);
+ }
+}
+
+static void floor1_pack (vorbis_info_floor *i,oggpack_buffer *opb){
+ vorbis_info_floor1 *info=(vorbis_info_floor1 *)i;
+ int j,k;
+ int count=0;
+ int rangebits;
+ int maxposit=info->postlist[1];
+ int maxclass=-1;
+
+ /* save out partitions */
+ oggpack_write(opb,info->partitions,5); /* only 0 to 31 legal */
+ for(j=0;j<info->partitions;j++){
+ oggpack_write(opb,info->partitionclass[j],4); /* only 0 to 15 legal */
+ if(maxclass<info->partitionclass[j])maxclass=info->partitionclass[j];
+ }
+
+ /* save out partition classes */
+ for(j=0;j<maxclass+1;j++){
+ oggpack_write(opb,info->class_dim[j]-1,3); /* 1 to 8 */
+ oggpack_write(opb,info->class_subs[j],2); /* 0 to 3 */
+ if(info->class_subs[j])oggpack_write(opb,info->class_book[j],8);
+ for(k=0;k<(1<<info->class_subs[j]);k++)
+ oggpack_write(opb,info->class_subbook[j][k]+1,8);
+ }
+
+ /* save out the post list */
+ oggpack_write(opb,info->mult-1,2); /* only 1,2,3,4 legal now */
+ /* maxposit cannot legally be less than 1; this is encode-side, we
+ can assume our setup is OK */
+ oggpack_write(opb,ov_ilog(maxposit-1),4);
+ rangebits=ov_ilog(maxposit-1);
+
+ for(j=0,k=0;j<info->partitions;j++){
+ count+=info->class_dim[info->partitionclass[j]];
+ for(;k<count;k++)
+ oggpack_write(opb,info->postlist[k+2],rangebits);
+ }
+}
+
+static int icomp(const void *a,const void *b){
+ return(**(int **)a-**(int **)b);
+}
+
+static vorbis_info_floor *floor1_unpack (vorbis_info *vi,oggpack_buffer *opb){
+ codec_setup_info *ci=vi->codec_setup;
+ int j,k,count=0,maxclass=-1,rangebits;
+
+ vorbis_info_floor1 *info=_ogg_calloc(1,sizeof(*info));
+ /* read partitions */
+ info->partitions=oggpack_read(opb,5); /* only 0 to 31 legal */
+ for(j=0;j<info->partitions;j++){
+ info->partitionclass[j]=oggpack_read(opb,4); /* only 0 to 15 legal */
+ if(info->partitionclass[j]<0)goto err_out;
+ if(maxclass<info->partitionclass[j])maxclass=info->partitionclass[j];
+ }
+
+ /* read partition classes */
+ for(j=0;j<maxclass+1;j++){
+ info->class_dim[j]=oggpack_read(opb,3)+1; /* 1 to 8 */
+ info->class_subs[j]=oggpack_read(opb,2); /* 0,1,2,3 bits */
+ if(info->class_subs[j]<0)
+ goto err_out;
+ if(info->class_subs[j])info->class_book[j]=oggpack_read(opb,8);
+ if(info->class_book[j]<0 || info->class_book[j]>=ci->books)
+ goto err_out;
+ for(k=0;k<(1<<info->class_subs[j]);k++){
+ info->class_subbook[j][k]=oggpack_read(opb,8)-1;
+ if(info->class_subbook[j][k]<-1 || info->class_subbook[j][k]>=ci->books)
+ goto err_out;
+ }
+ }
+
+ /* read the post list */
+ info->mult=oggpack_read(opb,2)+1; /* only 1,2,3,4 legal now */
+ rangebits=oggpack_read(opb,4);
+ if(rangebits<0)goto err_out;
+
+ for(j=0,k=0;j<info->partitions;j++){
+ count+=info->class_dim[info->partitionclass[j]];
+ if(count>VIF_POSIT) goto err_out;
+ for(;k<count;k++){
+ int t=info->postlist[k+2]=oggpack_read(opb,rangebits);
+ if(t<0 || t>=(1<<rangebits))
+ goto err_out;
+ }
+ }
+ info->postlist[0]=0;
+ info->postlist[1]=1<<rangebits;
+
+ /* don't allow repeated values in post list as they'd result in
+ zero-length segments */
+ {
+ int *sortpointer[VIF_POSIT+2];
+ for(j=0;j<count+2;j++)sortpointer[j]=info->postlist+j;
+ qsort(sortpointer,count+2,sizeof(*sortpointer),icomp);
+
+ for(j=1;j<count+2;j++)
+ if(*sortpointer[j-1]==*sortpointer[j])goto err_out;
+ }
+
+ return(info);
+
+ err_out:
+ floor1_free_info(info);
+ return(NULL);
+}
+
+static vorbis_look_floor *floor1_look(vorbis_dsp_state *vd,
+ vorbis_info_floor *in){
+
+ int *sortpointer[VIF_POSIT+2];
+ vorbis_info_floor1 *info=(vorbis_info_floor1 *)in;
+ vorbis_look_floor1 *look=_ogg_calloc(1,sizeof(*look));
+ int i,j,n=0;
+
+ (void)vd;
+
+ look->vi=info;
+ look->n=info->postlist[1];
+
+ /* we drop each position value in-between already decoded values,
+ and use linear interpolation to predict each new value past the
+ edges. The positions are read in the order of the position
+ list... we precompute the bounding positions in the lookup. Of
+ course, the neighbors can change (if a position is declined), but
+ this is an initial mapping */
+
+ for(i=0;i<info->partitions;i++)n+=info->class_dim[info->partitionclass[i]];
+ n+=2;
+ look->posts=n;
+
+ /* also store a sorted position index */
+ for(i=0;i<n;i++)sortpointer[i]=info->postlist+i;
+ qsort(sortpointer,n,sizeof(*sortpointer),icomp);
+
+ /* points from sort order back to range number */
+ for(i=0;i<n;i++)look->forward_index[i]=sortpointer[i]-info->postlist;
+ /* points from range order to sorted position */
+ for(i=0;i<n;i++)look->reverse_index[look->forward_index[i]]=i;
+ /* we actually need the post values too */
+ for(i=0;i<n;i++)look->sorted_index[i]=info->postlist[look->forward_index[i]];
+
+ /* quantize values to multiplier spec */
+ switch(info->mult){
+ case 1: /* 1024 -> 256 */
+ look->quant_q=256;
+ break;
+ case 2: /* 1024 -> 128 */
+ look->quant_q=128;
+ break;
+ case 3: /* 1024 -> 86 */
+ look->quant_q=86;
+ break;
+ case 4: /* 1024 -> 64 */
+ look->quant_q=64;
+ break;
+ }
+
+ /* discover our neighbors for decode where we don't use fit flags
+ (that would push the neighbors outward) */
+ for(i=0;i<n-2;i++){
+ int lo=0;
+ int hi=1;
+ int lx=0;
+ int hx=look->n;
+ int currentx=info->postlist[i+2];
+ for(j=0;j<i+2;j++){
+ int x=info->postlist[j];
+ if(x>lx && x<currentx){
+ lo=j;
+ lx=x;
+ }
+ if(x<hx && x>currentx){
+ hi=j;
+ hx=x;
+ }
+ }
+ look->loneighbor[i]=lo;
+ look->hineighbor[i]=hi;
+ }
+
+ return(look);
+}
+
+static int render_point(int x0,int x1,int y0,int y1,int x){
+ y0&=0x7fff; /* mask off flag */
+ y1&=0x7fff;
+
+ {
+ int dy=y1-y0;
+ int adx=x1-x0;
+ int ady=abs(dy);
+ int err=ady*(x-x0);
+
+ int off=err/adx;
+ if(dy<0)return(y0-off);
+ return(y0+off);
+ }
+}
+
+static int vorbis_dBquant(const float *x){
+ int i= *x*7.3142857f+1023.5f;
+ if(i>1023)return(1023);
+ if(i<0)return(0);
+ return i;
+}
+
+static const float FLOOR1_fromdB_LOOKUP[256]={
+ 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F,
+ 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F,
+ 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F,
+ 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F,
+ 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F,
+ 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F,
+ 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F,
+ 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F,
+ 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F,
+ 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F,
+ 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F,
+ 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F,
+ 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F,
+ 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F,
+ 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F,
+ 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F,
+ 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F,
+ 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F,
+ 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F,
+ 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F,
+ 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F,
+ 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F,
+ 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F,
+ 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F,
+ 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F,
+ 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F,
+ 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F,
+ 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F,
+ 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F,
+ 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F,
+ 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F,
+ 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F,
+ 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F,
+ 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F,
+ 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F,
+ 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F,
+ 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F,
+ 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F,
+ 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F,
+ 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F,
+ 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F,
+ 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F,
+ 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F,
+ 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F,
+ 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F,
+ 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F,
+ 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F,
+ 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F,
+ 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F,
+ 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F,
+ 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F,
+ 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F,
+ 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F,
+ 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F,
+ 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F,
+ 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F,
+ 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F,
+ 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F,
+ 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F,
+ 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F,
+ 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F,
+ 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F,
+ 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F,
+ 0.82788260F, 0.88168307F, 0.9389798F, 1.F,
+};
+
+static void render_line(int n, int x0,int x1,int y0,int y1,float *d){
+ int dy=y1-y0;
+ int adx=x1-x0;
+ int ady=abs(dy);
+ int base=dy/adx;
+ int sy=(dy<0?base-1:base+1);
+ int x=x0;
+ int y=y0;
+ int err=0;
+
+ ady-=abs(base*adx);
+
+ if(n>x1)n=x1;
+
+ if(x<n)
+ d[x]*=FLOOR1_fromdB_LOOKUP[y];
+
+ while(++x<n){
+ err=err+ady;
+ if(err>=adx){
+ err-=adx;
+ y+=sy;
+ }else{
+ y+=base;
+ }
+ d[x]*=FLOOR1_fromdB_LOOKUP[y];
+ }
+}
+
+static void render_line0(int n, int x0,int x1,int y0,int y1,int *d){
+ int dy=y1-y0;
+ int adx=x1-x0;
+ int ady=abs(dy);
+ int base=dy/adx;
+ int sy=(dy<0?base-1:base+1);
+ int x=x0;
+ int y=y0;
+ int err=0;
+
+ ady-=abs(base*adx);
+
+ if(n>x1)n=x1;
+
+ if(x<n)
+ d[x]=y;
+
+ while(++x<n){
+ err=err+ady;
+ if(err>=adx){
+ err-=adx;
+ y+=sy;
+ }else{
+ y+=base;
+ }
+ d[x]=y;
+ }
+}
+
+/* the floor has already been filtered to only include relevant sections */
+static int accumulate_fit(const float *flr,const float *mdct,
+ int x0, int x1,lsfit_acc *a,
+ int n,vorbis_info_floor1 *info){
+ long i;
+
+ int xa=0,ya=0,x2a=0,y2a=0,xya=0,na=0, xb=0,yb=0,x2b=0,y2b=0,xyb=0,nb=0;
+
+ memset(a,0,sizeof(*a));
+ a->x0=x0;
+ a->x1=x1;
+ if(x1>=n)x1=n-1;
+
+ for(i=x0;i<=x1;i++){
+ int quantized=vorbis_dBquant(flr+i);
+ if(quantized){
+ if(mdct[i]+info->twofitatten>=flr[i]){
+ xa += i;
+ ya += quantized;
+ x2a += i*i;
+ y2a += quantized*quantized;
+ xya += i*quantized;
+ na++;
+ }else{
+ xb += i;
+ yb += quantized;
+ x2b += i*i;
+ y2b += quantized*quantized;
+ xyb += i*quantized;
+ nb++;
+ }
+ }
+ }
+
+ a->xa=xa;
+ a->ya=ya;
+ a->x2a=x2a;
+ a->y2a=y2a;
+ a->xya=xya;
+ a->an=na;
+
+ a->xb=xb;
+ a->yb=yb;
+ a->x2b=x2b;
+ a->y2b=y2b;
+ a->xyb=xyb;
+ a->bn=nb;
+
+ return(na);
+}
+
+static int fit_line(lsfit_acc *a,int fits,int *y0,int *y1,
+ vorbis_info_floor1 *info){
+ double xb=0,yb=0,x2b=0,y2b=0,xyb=0,bn=0;
+ int i;
+ int x0=a[0].x0;
+ int x1=a[fits-1].x1;
+
+ for(i=0;i<fits;i++){
+ double weight = (a[i].bn+a[i].an)*info->twofitweight/(a[i].an+1)+1.;
+
+ xb+=a[i].xb + a[i].xa * weight;
+ yb+=a[i].yb + a[i].ya * weight;
+ x2b+=a[i].x2b + a[i].x2a * weight;
+ y2b+=a[i].y2b + a[i].y2a * weight;
+ xyb+=a[i].xyb + a[i].xya * weight;
+ bn+=a[i].bn + a[i].an * weight;
+ }
+
+ if(*y0>=0){
+ xb+= x0;
+ yb+= *y0;
+ x2b+= x0 * x0;
+ y2b+= *y0 * *y0;
+ xyb+= *y0 * x0;
+ bn++;
+ }
+
+ if(*y1>=0){
+ xb+= x1;
+ yb+= *y1;
+ x2b+= x1 * x1;
+ y2b+= *y1 * *y1;
+ xyb+= *y1 * x1;
+ bn++;
+ }
+
+ {
+ double denom=(bn*x2b-xb*xb);
+
+ if(denom>0.){
+ double a=(yb*x2b-xyb*xb)/denom;
+ double b=(bn*xyb-xb*yb)/denom;
+ *y0=rint(a+b*x0);
+ *y1=rint(a+b*x1);
+
+ /* limit to our range! */
+ if(*y0>1023)*y0=1023;
+ if(*y1>1023)*y1=1023;
+ if(*y0<0)*y0=0;
+ if(*y1<0)*y1=0;
+
+ return 0;
+ }else{
+ *y0=0;
+ *y1=0;
+ return 1;
+ }
+ }
+}
+
+static int inspect_error(int x0,int x1,int y0,int y1,const float *mask,
+ const float *mdct,
+ vorbis_info_floor1 *info){
+ int dy=y1-y0;
+ int adx=x1-x0;
+ int ady=abs(dy);
+ int base=dy/adx;
+ int sy=(dy<0?base-1:base+1);
+ int x=x0;
+ int y=y0;
+ int err=0;
+ int val=vorbis_dBquant(mask+x);
+ int mse=0;
+ int n=0;
+
+ ady-=abs(base*adx);
+
+ mse=(y-val);
+ mse*=mse;
+ n++;
+ if(mdct[x]+info->twofitatten>=mask[x]){
+ if(y+info->maxover<val)return(1);
+ if(y-info->maxunder>val)return(1);
+ }
+
+ while(++x<x1){
+ err=err+ady;
+ if(err>=adx){
+ err-=adx;
+ y+=sy;
+ }else{
+ y+=base;
+ }
+
+ val=vorbis_dBquant(mask+x);
+ mse+=((y-val)*(y-val));
+ n++;
+ if(mdct[x]+info->twofitatten>=mask[x]){
+ if(val){
+ if(y+info->maxover<val)return(1);
+ if(y-info->maxunder>val)return(1);
+ }
+ }
+ }
+
+ if(info->maxover*info->maxover/n>info->maxerr)return(0);
+ if(info->maxunder*info->maxunder/n>info->maxerr)return(0);
+ if(mse/n>info->maxerr)return(1);
+ return(0);
+}
+
+static int post_Y(int *A,int *B,int pos){
+ if(A[pos]<0)
+ return B[pos];
+ if(B[pos]<0)
+ return A[pos];
+
+ return (A[pos]+B[pos])>>1;
+}
+
+int *floor1_fit(vorbis_block *vb,vorbis_look_floor1 *look,
+ const float *logmdct, /* in */
+ const float *logmask){
+ long i,j;
+ vorbis_info_floor1 *info=look->vi;
+ long n=look->n;
+ long posts=look->posts;
+ long nonzero=0;
+ lsfit_acc fits[VIF_POSIT+1];
+ int fit_valueA[VIF_POSIT+2]; /* index by range list position */
+ int fit_valueB[VIF_POSIT+2]; /* index by range list position */
+
+ int loneighbor[VIF_POSIT+2]; /* sorted index of range list position (+2) */
+ int hineighbor[VIF_POSIT+2];
+ int *output=NULL;
+ int memo[VIF_POSIT+2];
+
+ for(i=0;i<posts;i++)fit_valueA[i]=-200; /* mark all unused */
+ for(i=0;i<posts;i++)fit_valueB[i]=-200; /* mark all unused */
+ for(i=0;i<posts;i++)loneighbor[i]=0; /* 0 for the implicit 0 post */
+ for(i=0;i<posts;i++)hineighbor[i]=1; /* 1 for the implicit post at n */
+ for(i=0;i<posts;i++)memo[i]=-1; /* no neighbor yet */
+
+ /* quantize the relevant floor points and collect them into line fit
+ structures (one per minimal division) at the same time */
+ if(posts==0){
+ nonzero+=accumulate_fit(logmask,logmdct,0,n,fits,n,info);
+ }else{
+ for(i=0;i<posts-1;i++)
+ nonzero+=accumulate_fit(logmask,logmdct,look->sorted_index[i],
+ look->sorted_index[i+1],fits+i,
+ n,info);
+ }
+
+ if(nonzero){
+ /* start by fitting the implicit base case.... */
+ int y0=-200;
+ int y1=-200;
+ fit_line(fits,posts-1,&y0,&y1,info);
+
+ fit_valueA[0]=y0;
+ fit_valueB[0]=y0;
+ fit_valueB[1]=y1;
+ fit_valueA[1]=y1;
+
+ /* Non degenerate case */
+ /* start progressive splitting. This is a greedy, non-optimal
+ algorithm, but simple and close enough to the best
+ answer. */
+ for(i=2;i<posts;i++){
+ int sortpos=look->reverse_index[i];
+ int ln=loneighbor[sortpos];
+ int hn=hineighbor[sortpos];
+
+ /* eliminate repeat searches of a particular range with a memo */
+ if(memo[ln]!=hn){
+ /* haven't performed this error search yet */
+ int lsortpos=look->reverse_index[ln];
+ int hsortpos=look->reverse_index[hn];
+ memo[ln]=hn;
+
+ {
+ /* A note: we want to bound/minimize *local*, not global, error */
+ int lx=info->postlist[ln];
+ int hx=info->postlist[hn];
+ int ly=post_Y(fit_valueA,fit_valueB,ln);
+ int hy=post_Y(fit_valueA,fit_valueB,hn);
+
+ if(ly==-1 || hy==-1){
+ exit(1);
+ }
+
+ if(inspect_error(lx,hx,ly,hy,logmask,logmdct,info)){
+ /* outside error bounds/begin search area. Split it. */
+ int ly0=-200;
+ int ly1=-200;
+ int hy0=-200;
+ int hy1=-200;
+ int ret0=fit_line(fits+lsortpos,sortpos-lsortpos,&ly0,&ly1,info);
+ int ret1=fit_line(fits+sortpos,hsortpos-sortpos,&hy0,&hy1,info);
+
+ if(ret0){
+ ly0=ly;
+ ly1=hy0;
+ }
+ if(ret1){
+ hy0=ly1;
+ hy1=hy;
+ }
+
+ if(ret0 && ret1){
+ fit_valueA[i]=-200;
+ fit_valueB[i]=-200;
+ }else{
+ /* store new edge values */
+ fit_valueB[ln]=ly0;
+ if(ln==0)fit_valueA[ln]=ly0;
+ fit_valueA[i]=ly1;
+ fit_valueB[i]=hy0;
+ fit_valueA[hn]=hy1;
+ if(hn==1)fit_valueB[hn]=hy1;
+
+ if(ly1>=0 || hy0>=0){
+ /* store new neighbor values */
+ for(j=sortpos-1;j>=0;j--)
+ if(hineighbor[j]==hn)
+ hineighbor[j]=i;
+ else
+ break;
+ for(j=sortpos+1;j<posts;j++)
+ if(loneighbor[j]==ln)
+ loneighbor[j]=i;
+ else
+ break;
+ }
+ }
+ }else{
+ fit_valueA[i]=-200;
+ fit_valueB[i]=-200;
+ }
+ }
+ }
+ }
+
+ output=_vorbis_block_alloc(vb,sizeof(*output)*posts);
+
+ output[0]=post_Y(fit_valueA,fit_valueB,0);
+ output[1]=post_Y(fit_valueA,fit_valueB,1);
+
+ /* fill in posts marked as not using a fit; we will zero
+ back out to 'unused' when encoding them so long as curve
+ interpolation doesn't force them into use */
+ for(i=2;i<posts;i++){
+ int ln=look->loneighbor[i-2];
+ int hn=look->hineighbor[i-2];
+ int x0=info->postlist[ln];
+ int x1=info->postlist[hn];
+ int y0=output[ln];
+ int y1=output[hn];
+
+ int predicted=render_point(x0,x1,y0,y1,info->postlist[i]);
+ int vx=post_Y(fit_valueA,fit_valueB,i);
+
+ if(vx>=0 && predicted!=vx){
+ output[i]=vx;
+ }else{
+ output[i]= predicted|0x8000;
+ }
+ }
+ }
+
+ return(output);
+
+}
+
+int *floor1_interpolate_fit(vorbis_block *vb,vorbis_look_floor1 *look,
+ int *A,int *B,
+ int del){
+
+ long i;
+ long posts=look->posts;
+ int *output=NULL;
+
+ if(A && B){
+ output=_vorbis_block_alloc(vb,sizeof(*output)*posts);
+
+ /* overly simpleminded--- look again post 1.2 */
+ for(i=0;i<posts;i++){
+ output[i]=((65536-del)*(A[i]&0x7fff)+del*(B[i]&0x7fff)+32768)>>16;
+ if(A[i]&0x8000 && B[i]&0x8000)output[i]|=0x8000;
+ }
+ }
+
+ return(output);
+}
+
+
+int floor1_encode(oggpack_buffer *opb,vorbis_block *vb,
+ vorbis_look_floor1 *look,
+ int *post,int *ilogmask){
+
+ long i,j;
+ vorbis_info_floor1 *info=look->vi;
+ long posts=look->posts;
+ codec_setup_info *ci=vb->vd->vi->codec_setup;
+ int out[VIF_POSIT+2];
+ static_codebook **sbooks=ci->book_param;
+ codebook *books=ci->fullbooks;
+
+ /* quantize values to multiplier spec */
+ if(post){
+ for(i=0;i<posts;i++){
+ int val=post[i]&0x7fff;
+ switch(info->mult){
+ case 1: /* 1024 -> 256 */
+ val>>=2;
+ break;
+ case 2: /* 1024 -> 128 */
+ val>>=3;
+ break;
+ case 3: /* 1024 -> 86 */
+ val/=12;
+ break;
+ case 4: /* 1024 -> 64 */
+ val>>=4;
+ break;
+ }
+ post[i]=val | (post[i]&0x8000);
+ }
+
+ out[0]=post[0];
+ out[1]=post[1];
+
+ /* find prediction values for each post and subtract them */
+ for(i=2;i<posts;i++){
+ int ln=look->loneighbor[i-2];
+ int hn=look->hineighbor[i-2];
+ int x0=info->postlist[ln];
+ int x1=info->postlist[hn];
+ int y0=post[ln];
+ int y1=post[hn];
+
+ int predicted=render_point(x0,x1,y0,y1,info->postlist[i]);
+
+ if((post[i]&0x8000) || (predicted==post[i])){
+ post[i]=predicted|0x8000; /* in case there was roundoff jitter
+ in interpolation */
+ out[i]=0;
+ }else{
+ int headroom=(look->quant_q-predicted<predicted?
+ look->quant_q-predicted:predicted);
+
+ int val=post[i]-predicted;
+
+ /* at this point the 'deviation' value is in the range +/- max
+ range, but the real, unique range can always be mapped to
+ only [0-maxrange). So we want to wrap the deviation into
+ this limited range, but do it in the way that least screws
+ an essentially gaussian probability distribution. */
+
+ if(val<0)
+ if(val<-headroom)
+ val=headroom-val-1;
+ else
+ val=-1-(val<<1);
+ else
+ if(val>=headroom)
+ val= val+headroom;
+ else
+ val<<=1;
+
+ out[i]=val;
+ post[ln]&=0x7fff;
+ post[hn]&=0x7fff;
+ }
+ }
+
+ /* we have everything we need. pack it out */
+ /* mark nontrivial floor */
+ oggpack_write(opb,1,1);
+
+ /* beginning/end post */
+ look->frames++;
+ look->postbits+=ov_ilog(look->quant_q-1)*2;
+ oggpack_write(opb,out[0],ov_ilog(look->quant_q-1));
+ oggpack_write(opb,out[1],ov_ilog(look->quant_q-1));
+
+
+ /* partition by partition */
+ for(i=0,j=2;i<info->partitions;i++){
+ int class=info->partitionclass[i];
+ int cdim=info->class_dim[class];
+ int csubbits=info->class_subs[class];
+ int csub=1<<csubbits;
+ int bookas[8]={0,0,0,0,0,0,0,0};
+ int cval=0;
+ int cshift=0;
+ int k,l;
+
+ /* generate the partition's first stage cascade value */
+ if(csubbits){
+ int maxval[8]={0,0,0,0,0,0,0,0}; /* gcc's static analysis
+ issues a warning without
+ initialization */
+ for(k=0;k<csub;k++){
+ int booknum=info->class_subbook[class][k];
+ if(booknum<0){
+ maxval[k]=1;
+ }else{
+ maxval[k]=sbooks[info->class_subbook[class][k]]->entries;
+ }
+ }
+ for(k=0;k<cdim;k++){
+ for(l=0;l<csub;l++){
+ int val=out[j+k];
+ if(val<maxval[l]){
+ bookas[k]=l;
+ break;
+ }
+ }
+ cval|= bookas[k]<<cshift;
+ cshift+=csubbits;
+ }
+ /* write it */
+ look->phrasebits+=
+ vorbis_book_encode(books+info->class_book[class],cval,opb);
+
+#ifdef TRAIN_FLOOR1
+ {
+ FILE *of;
+ char buffer[80];
+ sprintf(buffer,"line_%dx%ld_class%d.vqd",
+ vb->pcmend/2,posts-2,class);
+ of=fopen(buffer,"a");
+ fprintf(of,"%d\n",cval);
+ fclose(of);
+ }
+#endif
+ }
+
+ /* write post values */
+ for(k=0;k<cdim;k++){
+ int book=info->class_subbook[class][bookas[k]];
+ if(book>=0){
+ /* hack to allow training with 'bad' books */
+ if(out[j+k]<(books+book)->entries)
+ look->postbits+=vorbis_book_encode(books+book,
+ out[j+k],opb);
+ /*else
+ fprintf(stderr,"+!");*/
+
+#ifdef TRAIN_FLOOR1
+ {
+ FILE *of;
+ char buffer[80];
+ sprintf(buffer,"line_%dx%ld_%dsub%d.vqd",
+ vb->pcmend/2,posts-2,class,bookas[k]);
+ of=fopen(buffer,"a");
+ fprintf(of,"%d\n",out[j+k]);
+ fclose(of);
+ }
+#endif
+ }
+ }
+ j+=cdim;
+ }
+
+ {
+ /* generate quantized floor equivalent to what we'd unpack in decode */
+ /* render the lines */
+ int hx=0;
+ int lx=0;
+ int ly=post[0]*info->mult;
+ int n=ci->blocksizes[vb->W]/2;
+
+ for(j=1;j<look->posts;j++){
+ int current=look->forward_index[j];
+ int hy=post[current]&0x7fff;
+ if(hy==post[current]){
+
+ hy*=info->mult;
+ hx=info->postlist[current];
+
+ render_line0(n,lx,hx,ly,hy,ilogmask);
+
+ lx=hx;
+ ly=hy;
+ }
+ }
+ for(j=hx;j<vb->pcmend/2;j++)ilogmask[j]=ly; /* be certain */
+ return(1);
+ }
+ }else{
+ oggpack_write(opb,0,1);
+ memset(ilogmask,0,vb->pcmend/2*sizeof(*ilogmask));
+ return(0);
+ }
+}
+
+static void *floor1_inverse1(vorbis_block *vb,vorbis_look_floor *in){
+ vorbis_look_floor1 *look=(vorbis_look_floor1 *)in;
+ vorbis_info_floor1 *info=look->vi;
+ codec_setup_info *ci=vb->vd->vi->codec_setup;
+
+ int i,j,k;
+ codebook *books=ci->fullbooks;
+
+ /* unpack wrapped/predicted values from stream */
+ if(oggpack_read(&vb->opb,1)==1){
+ int *fit_value=_vorbis_block_alloc(vb,(look->posts)*sizeof(*fit_value));
+
+ fit_value[0]=oggpack_read(&vb->opb,ov_ilog(look->quant_q-1));
+ fit_value[1]=oggpack_read(&vb->opb,ov_ilog(look->quant_q-1));
+
+ /* partition by partition */
+ for(i=0,j=2;i<info->partitions;i++){
+ int class=info->partitionclass[i];
+ int cdim=info->class_dim[class];
+ int csubbits=info->class_subs[class];
+ int csub=1<<csubbits;
+ int cval=0;
+
+ /* decode the partition's first stage cascade value */
+ if(csubbits){
+ cval=vorbis_book_decode(books+info->class_book[class],&vb->opb);
+
+ if(cval==-1)goto eop;
+ }
+
+ for(k=0;k<cdim;k++){
+ int book=info->class_subbook[class][cval&(csub-1)];
+ cval>>=csubbits;
+ if(book>=0){
+ if((fit_value[j+k]=vorbis_book_decode(books+book,&vb->opb))==-1)
+ goto eop;
+ }else{
+ fit_value[j+k]=0;
+ }
+ }
+ j+=cdim;
+ }
+
+ /* unwrap positive values and reconsitute via linear interpolation */
+ for(i=2;i<look->posts;i++){
+ int predicted=render_point(info->postlist[look->loneighbor[i-2]],
+ info->postlist[look->hineighbor[i-2]],
+ fit_value[look->loneighbor[i-2]],
+ fit_value[look->hineighbor[i-2]],
+ info->postlist[i]);
+ int hiroom=look->quant_q-predicted;
+ int loroom=predicted;
+ int room=(hiroom<loroom?hiroom:loroom)<<1;
+ int val=fit_value[i];
+
+ if(val){
+ if(val>=room){
+ if(hiroom>loroom){
+ val = val-loroom;
+ }else{
+ val = -1-(val-hiroom);
+ }
+ }else{
+ if(val&1){
+ val= -((val+1)>>1);
+ }else{
+ val>>=1;
+ }
+ }
+
+ fit_value[i]=(val+predicted)&0x7fff;
+ fit_value[look->loneighbor[i-2]]&=0x7fff;
+ fit_value[look->hineighbor[i-2]]&=0x7fff;
+
+ }else{
+ fit_value[i]=predicted|0x8000;
+ }
+
+ }
+
+ return(fit_value);
+ }
+ eop:
+ return(NULL);
+}
+
+static int floor1_inverse2(vorbis_block *vb,vorbis_look_floor *in,void *memo,
+ float *out){
+ vorbis_look_floor1 *look=(vorbis_look_floor1 *)in;
+ vorbis_info_floor1 *info=look->vi;
+
+ codec_setup_info *ci=vb->vd->vi->codec_setup;
+ int n=ci->blocksizes[vb->W]/2;
+ int j;
+
+ if(memo){
+ /* render the lines */
+ int *fit_value=(int *)memo;
+ int hx=0;
+ int lx=0;
+ int ly=fit_value[0]*info->mult;
+ /* guard lookup against out-of-range values */
+ ly=(ly<0?0:ly>255?255:ly);
+
+ for(j=1;j<look->posts;j++){
+ int current=look->forward_index[j];
+ int hy=fit_value[current]&0x7fff;
+ if(hy==fit_value[current]){
+
+ hx=info->postlist[current];
+ hy*=info->mult;
+ /* guard lookup against out-of-range values */
+ hy=(hy<0?0:hy>255?255:hy);
+
+ render_line(n,lx,hx,ly,hy,out);
+
+ lx=hx;
+ ly=hy;
+ }
+ }
+ for(j=hx;j<n;j++)out[j]*=FLOOR1_fromdB_LOOKUP[ly]; /* be certain */
+ return(1);
+ }
+ memset(out,0,sizeof(*out)*n);
+ return(0);
+}
+
+/* export hooks */
+const vorbis_func_floor floor1_exportbundle={
+ &floor1_pack,&floor1_unpack,&floor1_look,&floor1_free_info,
+ &floor1_free_look,&floor1_inverse1,&floor1_inverse2
+};
diff --git a/external/libvorbis-1.3.5/lib/highlevel.h b/external/libvorbis-1.3.5/lib/highlevel.h
new file mode 100644
index 0000000..e38f370
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/highlevel.h
@@ -0,0 +1,58 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: highlevel encoder setup struct separated out for vorbisenc clarity
+ last mod: $Id: highlevel.h 17195 2010-05-05 21:49:51Z giles $
+
+ ********************************************************************/
+
+typedef struct highlevel_byblocktype {
+ double tone_mask_setting;
+ double tone_peaklimit_setting;
+ double noise_bias_setting;
+ double noise_compand_setting;
+} highlevel_byblocktype;
+
+typedef struct highlevel_encode_setup {
+ int set_in_stone;
+ const void *setup;
+ double base_setting;
+
+ double impulse_noisetune;
+
+ /* bitrate management below all settable */
+ float req;
+ int managed;
+ long bitrate_min;
+ long bitrate_av;
+ double bitrate_av_damp;
+ long bitrate_max;
+ long bitrate_reservoir;
+ double bitrate_reservoir_bias;
+
+ int impulse_block_p;
+ int noise_normalize_p;
+ int coupling_p;
+
+ double stereo_point_setting;
+ double lowpass_kHz;
+ int lowpass_altered;
+
+ double ath_floating_dB;
+ double ath_absolute_dB;
+
+ double amplitude_track_dBpersec;
+ double trigger_setting;
+
+ highlevel_byblocktype block[4]; /* padding, impulse, transition, long */
+
+} highlevel_encode_setup;
diff --git a/external/libvorbis-1.3.5/lib/info.c b/external/libvorbis-1.3.5/lib/info.c
new file mode 100644
index 0000000..8a2a001
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/info.c
@@ -0,0 +1,673 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: maintain the info structure, info <-> header packets
+ last mod: $Id: info.c 19441 2015-01-21 01:17:41Z xiphmont $
+
+ ********************************************************************/
+
+/* general handling of the header and the vorbis_info structure (and
+ substructures) */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+#include "codebook.h"
+#include "registry.h"
+#include "window.h"
+#include "psy.h"
+#include "misc.h"
+#include "os.h"
+
+#define GENERAL_VENDOR_STRING "Xiph.Org libVorbis 1.3.5"
+#define ENCODE_VENDOR_STRING "Xiph.Org libVorbis I 20150105 (⛄⛄⛄⛄)"
+
+/* helpers */
+static void _v_writestring(oggpack_buffer *o,const char *s, int bytes){
+
+ while(bytes--){
+ oggpack_write(o,*s++,8);
+ }
+}
+
+static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
+ while(bytes--){
+ *buf++=oggpack_read(o,8);
+ }
+}
+
+void vorbis_comment_init(vorbis_comment *vc){
+ memset(vc,0,sizeof(*vc));
+}
+
+void vorbis_comment_add(vorbis_comment *vc,const char *comment){
+ vc->user_comments=_ogg_realloc(vc->user_comments,
+ (vc->comments+2)*sizeof(*vc->user_comments));
+ vc->comment_lengths=_ogg_realloc(vc->comment_lengths,
+ (vc->comments+2)*sizeof(*vc->comment_lengths));
+ vc->comment_lengths[vc->comments]=strlen(comment);
+ vc->user_comments[vc->comments]=_ogg_malloc(vc->comment_lengths[vc->comments]+1);
+ strcpy(vc->user_comments[vc->comments], comment);
+ vc->comments++;
+ vc->user_comments[vc->comments]=NULL;
+}
+
+void vorbis_comment_add_tag(vorbis_comment *vc, const char *tag, const char *contents){
+ char *comment=alloca(strlen(tag)+strlen(contents)+2); /* +2 for = and \0 */
+ strcpy(comment, tag);
+ strcat(comment, "=");
+ strcat(comment, contents);
+ vorbis_comment_add(vc, comment);
+}
+
+/* This is more or less the same as strncasecmp - but that doesn't exist
+ * everywhere, and this is a fairly trivial function, so we include it */
+static int tagcompare(const char *s1, const char *s2, int n){
+ int c=0;
+ while(c < n){
+ if(toupper(s1[c]) != toupper(s2[c]))
+ return !0;
+ c++;
+ }
+ return 0;
+}
+
+char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count){
+ long i;
+ int found = 0;
+ int taglen = strlen(tag)+1; /* +1 for the = we append */
+ char *fulltag = alloca(taglen+ 1);
+
+ strcpy(fulltag, tag);
+ strcat(fulltag, "=");
+
+ for(i=0;i<vc->comments;i++){
+ if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
+ if(count == found)
+ /* We return a pointer to the data, not a copy */
+ return vc->user_comments[i] + taglen;
+ else
+ found++;
+ }
+ }
+ return NULL; /* didn't find anything */
+}
+
+int vorbis_comment_query_count(vorbis_comment *vc, const char *tag){
+ int i,count=0;
+ int taglen = strlen(tag)+1; /* +1 for the = we append */
+ char *fulltag = alloca(taglen+1);
+ strcpy(fulltag,tag);
+ strcat(fulltag, "=");
+
+ for(i=0;i<vc->comments;i++){
+ if(!tagcompare(vc->user_comments[i], fulltag, taglen))
+ count++;
+ }
+
+ return count;
+}
+
+void vorbis_comment_clear(vorbis_comment *vc){
+ if(vc){
+ long i;
+ if(vc->user_comments){
+ for(i=0;i<vc->comments;i++)
+ if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
+ _ogg_free(vc->user_comments);
+ }
+ if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
+ if(vc->vendor)_ogg_free(vc->vendor);
+ memset(vc,0,sizeof(*vc));
+ }
+}
+
+/* blocksize 0 is guaranteed to be short, 1 is guaranteed to be long.
+ They may be equal, but short will never ge greater than long */
+int vorbis_info_blocksize(vorbis_info *vi,int zo){
+ codec_setup_info *ci = vi->codec_setup;
+ return ci ? ci->blocksizes[zo] : -1;
+}
+
+/* used by synthesis, which has a full, alloced vi */
+void vorbis_info_init(vorbis_info *vi){
+ memset(vi,0,sizeof(*vi));
+ vi->codec_setup=_ogg_calloc(1,sizeof(codec_setup_info));
+}
+
+void vorbis_info_clear(vorbis_info *vi){
+ codec_setup_info *ci=vi->codec_setup;
+ int i;
+
+ if(ci){
+
+ for(i=0;i<ci->modes;i++)
+ if(ci->mode_param[i])_ogg_free(ci->mode_param[i]);
+
+ for(i=0;i<ci->maps;i++) /* unpack does the range checking */
+ if(ci->map_param[i]) /* this may be cleaning up an aborted
+ unpack, in which case the below type
+ cannot be trusted */
+ _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]);
+
+ for(i=0;i<ci->floors;i++) /* unpack does the range checking */
+ if(ci->floor_param[i]) /* this may be cleaning up an aborted
+ unpack, in which case the below type
+ cannot be trusted */
+ _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);
+
+ for(i=0;i<ci->residues;i++) /* unpack does the range checking */
+ if(ci->residue_param[i]) /* this may be cleaning up an aborted
+ unpack, in which case the below type
+ cannot be trusted */
+ _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);
+
+ for(i=0;i<ci->books;i++){
+ if(ci->book_param[i]){
+ /* knows if the book was not alloced */
+ vorbis_staticbook_destroy(ci->book_param[i]);
+ }
+ if(ci->fullbooks)
+ vorbis_book_clear(ci->fullbooks+i);
+ }
+ if(ci->fullbooks)
+ _ogg_free(ci->fullbooks);
+
+ for(i=0;i<ci->psys;i++)
+ _vi_psy_free(ci->psy_param[i]);
+
+ _ogg_free(ci);
+ }
+
+ memset(vi,0,sizeof(*vi));
+}
+
+/* Header packing/unpacking ********************************************/
+
+static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
+ codec_setup_info *ci=vi->codec_setup;
+ if(!ci)return(OV_EFAULT);
+
+ vi->version=oggpack_read(opb,32);
+ if(vi->version!=0)return(OV_EVERSION);
+
+ vi->channels=oggpack_read(opb,8);
+ vi->rate=oggpack_read(opb,32);
+
+ vi->bitrate_upper=oggpack_read(opb,32);
+ vi->bitrate_nominal=oggpack_read(opb,32);
+ vi->bitrate_lower=oggpack_read(opb,32);
+
+ ci->blocksizes[0]=1<<oggpack_read(opb,4);
+ ci->blocksizes[1]=1<<oggpack_read(opb,4);
+
+ if(vi->rate<1)goto err_out;
+ if(vi->channels<1)goto err_out;
+ if(ci->blocksizes[0]<64)goto err_out;
+ if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
+ if(ci->blocksizes[1]>8192)goto err_out;
+
+ if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
+
+ return(0);
+ err_out:
+ vorbis_info_clear(vi);
+ return(OV_EBADHEADER);
+}
+
+static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
+ int i;
+ int vendorlen=oggpack_read(opb,32);
+ if(vendorlen<0)goto err_out;
+ if(vendorlen>opb->storage-8)goto err_out;
+ vc->vendor=_ogg_calloc(vendorlen+1,1);
+ _v_readstring(opb,vc->vendor,vendorlen);
+ i=oggpack_read(opb,32);
+ if(i<0)goto err_out;
+ if(i>((opb->storage-oggpack_bytes(opb))>>2))goto err_out;
+ vc->comments=i;
+ vc->user_comments=_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
+ vc->comment_lengths=_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
+
+ for(i=0;i<vc->comments;i++){
+ int len=oggpack_read(opb,32);
+ if(len<0)goto err_out;
+ if(len>opb->storage-oggpack_bytes(opb))goto err_out;
+ vc->comment_lengths[i]=len;
+ vc->user_comments[i]=_ogg_calloc(len+1,1);
+ _v_readstring(opb,vc->user_comments[i],len);
+ }
+ if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
+
+ return(0);
+ err_out:
+ vorbis_comment_clear(vc);
+ return(OV_EBADHEADER);
+}
+
+/* all of the real encoding details are here. The modes, books,
+ everything */
+static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
+ codec_setup_info *ci=vi->codec_setup;
+ int i;
+
+ /* codebooks */
+ ci->books=oggpack_read(opb,8)+1;
+ if(ci->books<=0)goto err_out;
+ for(i=0;i<ci->books;i++){
+ ci->book_param[i]=vorbis_staticbook_unpack(opb);
+ if(!ci->book_param[i])goto err_out;
+ }
+
+ /* time backend settings; hooks are unused */
+ {
+ int times=oggpack_read(opb,6)+1;
+ if(times<=0)goto err_out;
+ for(i=0;i<times;i++){
+ int test=oggpack_read(opb,16);
+ if(test<0 || test>=VI_TIMEB)goto err_out;
+ }
+ }
+
+ /* floor backend settings */
+ ci->floors=oggpack_read(opb,6)+1;
+ if(ci->floors<=0)goto err_out;
+ for(i=0;i<ci->floors;i++){
+ ci->floor_type[i]=oggpack_read(opb,16);
+ if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
+ ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
+ if(!ci->floor_param[i])goto err_out;
+ }
+
+ /* residue backend settings */
+ ci->residues=oggpack_read(opb,6)+1;
+ if(ci->residues<=0)goto err_out;
+ for(i=0;i<ci->residues;i++){
+ ci->residue_type[i]=oggpack_read(opb,16);
+ if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
+ ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
+ if(!ci->residue_param[i])goto err_out;
+ }
+
+ /* map backend settings */
+ ci->maps=oggpack_read(opb,6)+1;
+ if(ci->maps<=0)goto err_out;
+ for(i=0;i<ci->maps;i++){
+ ci->map_type[i]=oggpack_read(opb,16);
+ if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
+ ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
+ if(!ci->map_param[i])goto err_out;
+ }
+
+ /* mode settings */
+ ci->modes=oggpack_read(opb,6)+1;
+ if(ci->modes<=0)goto err_out;
+ for(i=0;i<ci->modes;i++){
+ ci->mode_param[i]=_ogg_calloc(1,sizeof(*ci->mode_param[i]));
+ ci->mode_param[i]->blockflag=oggpack_read(opb,1);
+ ci->mode_param[i]->windowtype=oggpack_read(opb,16);
+ ci->mode_param[i]->transformtype=oggpack_read(opb,16);
+ ci->mode_param[i]->mapping=oggpack_read(opb,8);
+
+ if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
+ if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
+ if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
+ if(ci->mode_param[i]->mapping<0)goto err_out;
+ }
+
+ if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
+
+ return(0);
+ err_out:
+ vorbis_info_clear(vi);
+ return(OV_EBADHEADER);
+}
+
+/* Is this packet a vorbis ID header? */
+int vorbis_synthesis_idheader(ogg_packet *op){
+ oggpack_buffer opb;
+ char buffer[6];
+
+ if(op){
+ oggpack_readinit(&opb,op->packet,op->bytes);
+
+ if(!op->b_o_s)
+ return(0); /* Not the initial packet */
+
+ if(oggpack_read(&opb,8) != 1)
+ return 0; /* not an ID header */
+
+ memset(buffer,0,6);
+ _v_readstring(&opb,buffer,6);
+ if(memcmp(buffer,"vorbis",6))
+ return 0; /* not vorbis */
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/* The Vorbis header is in three packets; the initial small packet in
+ the first page that identifies basic parameters, a second packet
+ with bitstream comments and a third packet that holds the
+ codebook. */
+
+int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
+ oggpack_buffer opb;
+
+ if(op){
+ oggpack_readinit(&opb,op->packet,op->bytes);
+
+ /* Which of the three types of header is this? */
+ /* Also verify header-ness, vorbis */
+ {
+ char buffer[6];
+ int packtype=oggpack_read(&opb,8);
+ memset(buffer,0,6);
+ _v_readstring(&opb,buffer,6);
+ if(memcmp(buffer,"vorbis",6)){
+ /* not a vorbis header */
+ return(OV_ENOTVORBIS);
+ }
+ switch(packtype){
+ case 0x01: /* least significant *bit* is read first */
+ if(!op->b_o_s){
+ /* Not the initial packet */
+ return(OV_EBADHEADER);
+ }
+ if(vi->rate!=0){
+ /* previously initialized info header */
+ return(OV_EBADHEADER);
+ }
+
+ return(_vorbis_unpack_info(vi,&opb));
+
+ case 0x03: /* least significant *bit* is read first */
+ if(vi->rate==0){
+ /* um... we didn't get the initial header */
+ return(OV_EBADHEADER);
+ }
+ if(vc->vendor!=NULL){
+ /* previously initialized comment header */
+ return(OV_EBADHEADER);
+ }
+
+ return(_vorbis_unpack_comment(vc,&opb));
+
+ case 0x05: /* least significant *bit* is read first */
+ if(vi->rate==0 || vc->vendor==NULL){
+ /* um... we didn;t get the initial header or comments yet */
+ return(OV_EBADHEADER);
+ }
+ if(vi->codec_setup==NULL){
+ /* improperly initialized vorbis_info */
+ return(OV_EFAULT);
+ }
+ if(((codec_setup_info *)vi->codec_setup)->books>0){
+ /* previously initialized setup header */
+ return(OV_EBADHEADER);
+ }
+
+ return(_vorbis_unpack_books(vi,&opb));
+
+ default:
+ /* Not a valid vorbis header type */
+ return(OV_EBADHEADER);
+ break;
+ }
+ }
+ }
+ return(OV_EBADHEADER);
+}
+
+/* pack side **********************************************************/
+
+static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){
+ codec_setup_info *ci=vi->codec_setup;
+ if(!ci||
+ ci->blocksizes[0]<64||
+ ci->blocksizes[1]<ci->blocksizes[0]){
+ return(OV_EFAULT);
+ }
+
+ /* preamble */
+ oggpack_write(opb,0x01,8);
+ _v_writestring(opb,"vorbis", 6);
+
+ /* basic information about the stream */
+ oggpack_write(opb,0x00,32);
+ oggpack_write(opb,vi->channels,8);
+ oggpack_write(opb,vi->rate,32);
+
+ oggpack_write(opb,vi->bitrate_upper,32);
+ oggpack_write(opb,vi->bitrate_nominal,32);
+ oggpack_write(opb,vi->bitrate_lower,32);
+
+ oggpack_write(opb,ov_ilog(ci->blocksizes[0]-1),4);
+ oggpack_write(opb,ov_ilog(ci->blocksizes[1]-1),4);
+ oggpack_write(opb,1,1);
+
+ return(0);
+}
+
+static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){
+ int bytes = strlen(ENCODE_VENDOR_STRING);
+
+ /* preamble */
+ oggpack_write(opb,0x03,8);
+ _v_writestring(opb,"vorbis", 6);
+
+ /* vendor */
+ oggpack_write(opb,bytes,32);
+ _v_writestring(opb,ENCODE_VENDOR_STRING, bytes);
+
+ /* comments */
+
+ oggpack_write(opb,vc->comments,32);
+ if(vc->comments){
+ int i;
+ for(i=0;i<vc->comments;i++){
+ if(vc->user_comments[i]){
+ oggpack_write(opb,vc->comment_lengths[i],32);
+ _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]);
+ }else{
+ oggpack_write(opb,0,32);
+ }
+ }
+ }
+ oggpack_write(opb,1,1);
+
+ return(0);
+}
+
+static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){
+ codec_setup_info *ci=vi->codec_setup;
+ int i;
+ if(!ci)return(OV_EFAULT);
+
+ oggpack_write(opb,0x05,8);
+ _v_writestring(opb,"vorbis", 6);
+
+ /* books */
+ oggpack_write(opb,ci->books-1,8);
+ for(i=0;i<ci->books;i++)
+ if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out;
+
+ /* times; hook placeholders */
+ oggpack_write(opb,0,6);
+ oggpack_write(opb,0,16);
+
+ /* floors */
+ oggpack_write(opb,ci->floors-1,6);
+ for(i=0;i<ci->floors;i++){
+ oggpack_write(opb,ci->floor_type[i],16);
+ if(_floor_P[ci->floor_type[i]]->pack)
+ _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb);
+ else
+ goto err_out;
+ }
+
+ /* residues */
+ oggpack_write(opb,ci->residues-1,6);
+ for(i=0;i<ci->residues;i++){
+ oggpack_write(opb,ci->residue_type[i],16);
+ _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb);
+ }
+
+ /* maps */
+ oggpack_write(opb,ci->maps-1,6);
+ for(i=0;i<ci->maps;i++){
+ oggpack_write(opb,ci->map_type[i],16);
+ _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb);
+ }
+
+ /* modes */
+ oggpack_write(opb,ci->modes-1,6);
+ for(i=0;i<ci->modes;i++){
+ oggpack_write(opb,ci->mode_param[i]->blockflag,1);
+ oggpack_write(opb,ci->mode_param[i]->windowtype,16);
+ oggpack_write(opb,ci->mode_param[i]->transformtype,16);
+ oggpack_write(opb,ci->mode_param[i]->mapping,8);
+ }
+ oggpack_write(opb,1,1);
+
+ return(0);
+err_out:
+ return(-1);
+}
+
+int vorbis_commentheader_out(vorbis_comment *vc,
+ ogg_packet *op){
+
+ oggpack_buffer opb;
+
+ oggpack_writeinit(&opb);
+ if(_vorbis_pack_comment(&opb,vc)){
+ oggpack_writeclear(&opb);
+ return OV_EIMPL;
+ }
+
+ op->packet = _ogg_malloc(oggpack_bytes(&opb));
+ memcpy(op->packet, opb.buffer, oggpack_bytes(&opb));
+
+ op->bytes=oggpack_bytes(&opb);
+ op->b_o_s=0;
+ op->e_o_s=0;
+ op->granulepos=0;
+ op->packetno=1;
+
+ oggpack_writeclear(&opb);
+ return 0;
+}
+
+int vorbis_analysis_headerout(vorbis_dsp_state *v,
+ vorbis_comment *vc,
+ ogg_packet *op,
+ ogg_packet *op_comm,
+ ogg_packet *op_code){
+ int ret=OV_EIMPL;
+ vorbis_info *vi=v->vi;
+ oggpack_buffer opb;
+ private_state *b=v->backend_state;
+
+ if(!b||vi->channels<=0){
+ ret=OV_EFAULT;
+ goto err_out;
+ }
+
+ /* first header packet **********************************************/
+
+ oggpack_writeinit(&opb);
+ if(_vorbis_pack_info(&opb,vi))goto err_out;
+
+ /* build the packet */
+ if(b->header)_ogg_free(b->header);
+ b->header=_ogg_malloc(oggpack_bytes(&opb));
+ memcpy(b->header,opb.buffer,oggpack_bytes(&opb));
+ op->packet=b->header;
+ op->bytes=oggpack_bytes(&opb);
+ op->b_o_s=1;
+ op->e_o_s=0;
+ op->granulepos=0;
+ op->packetno=0;
+
+ /* second header packet (comments) **********************************/
+
+ oggpack_reset(&opb);
+ if(_vorbis_pack_comment(&opb,vc))goto err_out;
+
+ if(b->header1)_ogg_free(b->header1);
+ b->header1=_ogg_malloc(oggpack_bytes(&opb));
+ memcpy(b->header1,opb.buffer,oggpack_bytes(&opb));
+ op_comm->packet=b->header1;
+ op_comm->bytes=oggpack_bytes(&opb);
+ op_comm->b_o_s=0;
+ op_comm->e_o_s=0;
+ op_comm->granulepos=0;
+ op_comm->packetno=1;
+
+ /* third header packet (modes/codebooks) ****************************/
+
+ oggpack_reset(&opb);
+ if(_vorbis_pack_books(&opb,vi))goto err_out;
+
+ if(b->header2)_ogg_free(b->header2);
+ b->header2=_ogg_malloc(oggpack_bytes(&opb));
+ memcpy(b->header2,opb.buffer,oggpack_bytes(&opb));
+ op_code->packet=b->header2;
+ op_code->bytes=oggpack_bytes(&opb);
+ op_code->b_o_s=0;
+ op_code->e_o_s=0;
+ op_code->granulepos=0;
+ op_code->packetno=2;
+
+ oggpack_writeclear(&opb);
+ return(0);
+ err_out:
+ memset(op,0,sizeof(*op));
+ memset(op_comm,0,sizeof(*op_comm));
+ memset(op_code,0,sizeof(*op_code));
+
+ if(b){
+ oggpack_writeclear(&opb);
+ if(b->header)_ogg_free(b->header);
+ if(b->header1)_ogg_free(b->header1);
+ if(b->header2)_ogg_free(b->header2);
+ b->header=NULL;
+ b->header1=NULL;
+ b->header2=NULL;
+ }
+ return(ret);
+}
+
+double vorbis_granule_time(vorbis_dsp_state *v,ogg_int64_t granulepos){
+ if(granulepos == -1) return -1;
+
+ /* We're not guaranteed a 64 bit unsigned type everywhere, so we
+ have to put the unsigned granpo in a signed type. */
+ if(granulepos>=0){
+ return((double)granulepos/v->vi->rate);
+ }else{
+ ogg_int64_t granuleoff=0xffffffff;
+ granuleoff<<=31;
+ granuleoff|=0x7ffffffff;
+ return(((double)granulepos+2+granuleoff+granuleoff)/v->vi->rate);
+ }
+}
+
+const char *vorbis_version_string(void){
+ return GENERAL_VENDOR_STRING;
+}
diff --git a/external/libvorbis-1.3.5/lib/lookup.c b/external/libvorbis-1.3.5/lib/lookup.c
new file mode 100644
index 0000000..3321ed3
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/lookup.c
@@ -0,0 +1,94 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: lookup based functions
+ last mod: $Id: lookup.c 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+#include <math.h>
+#include "lookup.h"
+#include "lookup_data.h"
+#include "os.h"
+#include "misc.h"
+
+#ifdef FLOAT_LOOKUP
+
+/* interpolated lookup based cos function, domain 0 to PI only */
+float vorbis_coslook(float a){
+ double d=a*(.31830989*(float)COS_LOOKUP_SZ);
+ int i=vorbis_ftoi(d-.5);
+
+ return COS_LOOKUP[i]+ (d-i)*(COS_LOOKUP[i+1]-COS_LOOKUP[i]);
+}
+
+/* interpolated 1./sqrt(p) where .5 <= p < 1. */
+float vorbis_invsqlook(float a){
+ double d=a*(2.f*(float)INVSQ_LOOKUP_SZ)-(float)INVSQ_LOOKUP_SZ;
+ int i=vorbis_ftoi(d-.5f);
+ return INVSQ_LOOKUP[i]+ (d-i)*(INVSQ_LOOKUP[i+1]-INVSQ_LOOKUP[i]);
+}
+
+/* interpolated 1./sqrt(p) where .5 <= p < 1. */
+float vorbis_invsq2explook(int a){
+ return INVSQ2EXP_LOOKUP[a-INVSQ2EXP_LOOKUP_MIN];
+}
+
+#include <stdio.h>
+/* interpolated lookup based fromdB function, domain -140dB to 0dB only */
+float vorbis_fromdBlook(float a){
+ int i=vorbis_ftoi(a*((float)(-(1<<FROMdB2_SHIFT)))-.5f);
+ return (i<0)?1.f:
+ ((i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT))?0.f:
+ FROMdB_LOOKUP[i>>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]);
+}
+
+#endif
+
+#ifdef INT_LOOKUP
+/* interpolated 1./sqrt(p) where .5 <= a < 1. (.100000... to .111111...) in
+ 16.16 format
+
+ returns in m.8 format */
+long vorbis_invsqlook_i(long a,long e){
+ long i=(a&0x7fff)>>(INVSQ_LOOKUP_I_SHIFT-1);
+ long d=(a&INVSQ_LOOKUP_I_MASK)<<(16-INVSQ_LOOKUP_I_SHIFT); /* 0.16 */
+ long val=INVSQ_LOOKUP_I[i]- /* 1.16 */
+ (((INVSQ_LOOKUP_I[i]-INVSQ_LOOKUP_I[i+1])* /* 0.16 */
+ d)>>16); /* result 1.16 */
+
+ e+=32;
+ if(e&1)val=(val*5792)>>13; /* multiply val by 1/sqrt(2) */
+ e=(e>>1)-8;
+
+ return(val>>e);
+}
+
+/* interpolated lookup based fromdB function, domain -140dB to 0dB only */
+/* a is in n.12 format */
+float vorbis_fromdBlook_i(long a){
+ int i=(-a)>>(12-FROMdB2_SHIFT);
+ return (i<0)?1.f:
+ ((i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT))?0.f:
+ FROMdB_LOOKUP[i>>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]);
+}
+
+/* interpolated lookup based cos function, domain 0 to PI only */
+/* a is in 0.16 format, where 0==0, 2^^16-1==PI, return 0.14 */
+long vorbis_coslook_i(long a){
+ int i=a>>COS_LOOKUP_I_SHIFT;
+ int d=a&COS_LOOKUP_I_MASK;
+ return COS_LOOKUP_I[i]- ((d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>>
+ COS_LOOKUP_I_SHIFT);
+}
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/lookup.h b/external/libvorbis-1.3.5/lib/lookup.h
new file mode 100644
index 0000000..f8b5b82
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/lookup.h
@@ -0,0 +1,32 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: lookup based functions
+ last mod: $Id: lookup.h 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_LOOKUP_H_
+
+#ifdef FLOAT_LOOKUP
+extern float vorbis_coslook(float a);
+extern float vorbis_invsqlook(float a);
+extern float vorbis_invsq2explook(int a);
+extern float vorbis_fromdBlook(float a);
+#endif
+#ifdef INT_LOOKUP
+extern long vorbis_invsqlook_i(long a,long e);
+extern long vorbis_coslook_i(long a);
+extern float vorbis_fromdBlook_i(long a);
+#endif
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/lookup_data.h b/external/libvorbis-1.3.5/lib/lookup_data.h
new file mode 100644
index 0000000..2424a1b
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/lookup_data.h
@@ -0,0 +1,192 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: lookup data; generated by lookups.pl; edit there
+ last mod: $Id: lookup_data.h 16037 2009-05-26 21:10:58Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_LOOKUP_DATA_H_
+
+#ifdef FLOAT_LOOKUP
+#define COS_LOOKUP_SZ 128
+static const float COS_LOOKUP[COS_LOOKUP_SZ+1]={
+ +1.0000000000000f,+0.9996988186962f,+0.9987954562052f,+0.9972904566787f,
+ +0.9951847266722f,+0.9924795345987f,+0.9891765099648f,+0.9852776423889f,
+ +0.9807852804032f,+0.9757021300385f,+0.9700312531945f,+0.9637760657954f,
+ +0.9569403357322f,+0.9495281805930f,+0.9415440651830f,+0.9329927988347f,
+ +0.9238795325113f,+0.9142097557035f,+0.9039892931234f,+0.8932243011955f,
+ +0.8819212643484f,+0.8700869911087f,+0.8577286100003f,+0.8448535652497f,
+ +0.8314696123025f,+0.8175848131516f,+0.8032075314806f,+0.7883464276266f,
+ +0.7730104533627f,+0.7572088465065f,+0.7409511253550f,+0.7242470829515f,
+ +0.7071067811865f,+0.6895405447371f,+0.6715589548470f,+0.6531728429538f,
+ +0.6343932841636f,+0.6152315905806f,+0.5956993044924f,+0.5758081914178f,
+ +0.5555702330196f,+0.5349976198871f,+0.5141027441932f,+0.4928981922298f,
+ +0.4713967368260f,+0.4496113296546f,+0.4275550934303f,+0.4052413140050f,
+ +0.3826834323651f,+0.3598950365350f,+0.3368898533922f,+0.3136817403989f,
+ +0.2902846772545f,+0.2667127574749f,+0.2429801799033f,+0.2191012401569f,
+ +0.1950903220161f,+0.1709618887603f,+0.1467304744554f,+0.1224106751992f,
+ +0.0980171403296f,+0.0735645635997f,+0.0490676743274f,+0.0245412285229f,
+ +0.0000000000000f,-0.0245412285229f,-0.0490676743274f,-0.0735645635997f,
+ -0.0980171403296f,-0.1224106751992f,-0.1467304744554f,-0.1709618887603f,
+ -0.1950903220161f,-0.2191012401569f,-0.2429801799033f,-0.2667127574749f,
+ -0.2902846772545f,-0.3136817403989f,-0.3368898533922f,-0.3598950365350f,
+ -0.3826834323651f,-0.4052413140050f,-0.4275550934303f,-0.4496113296546f,
+ -0.4713967368260f,-0.4928981922298f,-0.5141027441932f,-0.5349976198871f,
+ -0.5555702330196f,-0.5758081914178f,-0.5956993044924f,-0.6152315905806f,
+ -0.6343932841636f,-0.6531728429538f,-0.6715589548470f,-0.6895405447371f,
+ -0.7071067811865f,-0.7242470829515f,-0.7409511253550f,-0.7572088465065f,
+ -0.7730104533627f,-0.7883464276266f,-0.8032075314806f,-0.8175848131516f,
+ -0.8314696123025f,-0.8448535652497f,-0.8577286100003f,-0.8700869911087f,
+ -0.8819212643484f,-0.8932243011955f,-0.9039892931234f,-0.9142097557035f,
+ -0.9238795325113f,-0.9329927988347f,-0.9415440651830f,-0.9495281805930f,
+ -0.9569403357322f,-0.9637760657954f,-0.9700312531945f,-0.9757021300385f,
+ -0.9807852804032f,-0.9852776423889f,-0.9891765099648f,-0.9924795345987f,
+ -0.9951847266722f,-0.9972904566787f,-0.9987954562052f,-0.9996988186962f,
+ -1.0000000000000f,
+};
+
+#define INVSQ_LOOKUP_SZ 32
+static const float INVSQ_LOOKUP[INVSQ_LOOKUP_SZ+1]={
+ 1.414213562373f,1.392621247646f,1.371988681140f,1.352246807566f,
+ 1.333333333333f,1.315191898443f,1.297771369046f,1.281025230441f,
+ 1.264911064067f,1.249390095109f,1.234426799697f,1.219988562661f,
+ 1.206045378311f,1.192569588000f,1.179535649239f,1.166919931983f,
+ 1.154700538379f,1.142857142857f,1.131370849898f,1.120224067222f,
+ 1.109400392450f,1.098884511590f,1.088662107904f,1.078719779941f,
+ 1.069044967650f,1.059625885652f,1.050451462878f,1.041511287847f,
+ 1.032795558989f,1.024295039463f,1.016001016002f,1.007905261358f,
+ 1.000000000000f,
+};
+
+#define INVSQ2EXP_LOOKUP_MIN (-32)
+#define INVSQ2EXP_LOOKUP_MAX 32
+static const float INVSQ2EXP_LOOKUP[INVSQ2EXP_LOOKUP_MAX-\
+ INVSQ2EXP_LOOKUP_MIN+1]={
+ 65536.f, 46340.95001f, 32768.f, 23170.47501f,
+ 16384.f, 11585.2375f, 8192.f, 5792.618751f,
+ 4096.f, 2896.309376f, 2048.f, 1448.154688f,
+ 1024.f, 724.0773439f, 512.f, 362.038672f,
+ 256.f, 181.019336f, 128.f, 90.50966799f,
+ 64.f, 45.254834f, 32.f, 22.627417f,
+ 16.f, 11.3137085f, 8.f, 5.656854249f,
+ 4.f, 2.828427125f, 2.f, 1.414213562f,
+ 1.f, 0.7071067812f, 0.5f, 0.3535533906f,
+ 0.25f, 0.1767766953f, 0.125f, 0.08838834765f,
+ 0.0625f, 0.04419417382f, 0.03125f, 0.02209708691f,
+ 0.015625f, 0.01104854346f, 0.0078125f, 0.005524271728f,
+ 0.00390625f, 0.002762135864f, 0.001953125f, 0.001381067932f,
+ 0.0009765625f, 0.000690533966f, 0.00048828125f, 0.000345266983f,
+ 0.000244140625f,0.0001726334915f,0.0001220703125f,8.631674575e-05f,
+ 6.103515625e-05f,4.315837288e-05f,3.051757812e-05f,2.157918644e-05f,
+ 1.525878906e-05f,
+};
+
+#endif
+
+#define FROMdB_LOOKUP_SZ 35
+#define FROMdB2_LOOKUP_SZ 32
+#define FROMdB_SHIFT 5
+#define FROMdB2_SHIFT 3
+#define FROMdB2_MASK 31
+
+#ifdef FLOAT_LOOKUP
+static const float FROMdB_LOOKUP[FROMdB_LOOKUP_SZ]={
+ 1.f, 0.6309573445f, 0.3981071706f, 0.2511886432f,
+ 0.1584893192f, 0.1f, 0.06309573445f, 0.03981071706f,
+ 0.02511886432f, 0.01584893192f, 0.01f, 0.006309573445f,
+ 0.003981071706f, 0.002511886432f, 0.001584893192f, 0.001f,
+ 0.0006309573445f,0.0003981071706f,0.0002511886432f,0.0001584893192f,
+ 0.0001f,6.309573445e-05f,3.981071706e-05f,2.511886432e-05f,
+ 1.584893192e-05f, 1e-05f,6.309573445e-06f,3.981071706e-06f,
+ 2.511886432e-06f,1.584893192e-06f, 1e-06f,6.309573445e-07f,
+ 3.981071706e-07f,2.511886432e-07f,1.584893192e-07f,
+};
+
+static const float FROMdB2_LOOKUP[FROMdB2_LOOKUP_SZ]={
+ 0.9928302478f, 0.9786445908f, 0.9646616199f, 0.9508784391f,
+ 0.9372921937f, 0.92390007f, 0.9106992942f, 0.8976871324f,
+ 0.8848608897f, 0.8722179097f, 0.8597555737f, 0.8474713009f,
+ 0.835362547f, 0.8234268041f, 0.8116616003f, 0.8000644989f,
+ 0.7886330981f, 0.7773650302f, 0.7662579617f, 0.755309592f,
+ 0.7445176537f, 0.7338799116f, 0.7233941627f, 0.7130582353f,
+ 0.7028699885f, 0.6928273125f, 0.6829281272f, 0.6731703824f,
+ 0.6635520573f, 0.6540711597f, 0.6447257262f, 0.6355138211f,
+};
+#endif
+
+#ifdef INT_LOOKUP
+
+#define INVSQ_LOOKUP_I_SHIFT 10
+#define INVSQ_LOOKUP_I_MASK 1023
+static const long INVSQ_LOOKUP_I[64+1]={
+ 92682l, 91966l, 91267l, 90583l,
+ 89915l, 89261l, 88621l, 87995l,
+ 87381l, 86781l, 86192l, 85616l,
+ 85051l, 84497l, 83953l, 83420l,
+ 82897l, 82384l, 81880l, 81385l,
+ 80899l, 80422l, 79953l, 79492l,
+ 79039l, 78594l, 78156l, 77726l,
+ 77302l, 76885l, 76475l, 76072l,
+ 75674l, 75283l, 74898l, 74519l,
+ 74146l, 73778l, 73415l, 73058l,
+ 72706l, 72359l, 72016l, 71679l,
+ 71347l, 71019l, 70695l, 70376l,
+ 70061l, 69750l, 69444l, 69141l,
+ 68842l, 68548l, 68256l, 67969l,
+ 67685l, 67405l, 67128l, 66855l,
+ 66585l, 66318l, 66054l, 65794l,
+ 65536l,
+};
+
+#define COS_LOOKUP_I_SHIFT 9
+#define COS_LOOKUP_I_MASK 511
+#define COS_LOOKUP_I_SZ 128
+static const long COS_LOOKUP_I[COS_LOOKUP_I_SZ+1]={
+ 16384l, 16379l, 16364l, 16340l,
+ 16305l, 16261l, 16207l, 16143l,
+ 16069l, 15986l, 15893l, 15791l,
+ 15679l, 15557l, 15426l, 15286l,
+ 15137l, 14978l, 14811l, 14635l,
+ 14449l, 14256l, 14053l, 13842l,
+ 13623l, 13395l, 13160l, 12916l,
+ 12665l, 12406l, 12140l, 11866l,
+ 11585l, 11297l, 11003l, 10702l,
+ 10394l, 10080l, 9760l, 9434l,
+ 9102l, 8765l, 8423l, 8076l,
+ 7723l, 7366l, 7005l, 6639l,
+ 6270l, 5897l, 5520l, 5139l,
+ 4756l, 4370l, 3981l, 3590l,
+ 3196l, 2801l, 2404l, 2006l,
+ 1606l, 1205l, 804l, 402l,
+ 0l, -401l, -803l, -1204l,
+ -1605l, -2005l, -2403l, -2800l,
+ -3195l, -3589l, -3980l, -4369l,
+ -4755l, -5138l, -5519l, -5896l,
+ -6269l, -6638l, -7004l, -7365l,
+ -7722l, -8075l, -8422l, -8764l,
+ -9101l, -9433l, -9759l, -10079l,
+ -10393l, -10701l, -11002l, -11296l,
+ -11584l, -11865l, -12139l, -12405l,
+ -12664l, -12915l, -13159l, -13394l,
+ -13622l, -13841l, -14052l, -14255l,
+ -14448l, -14634l, -14810l, -14977l,
+ -15136l, -15285l, -15425l, -15556l,
+ -15678l, -15790l, -15892l, -15985l,
+ -16068l, -16142l, -16206l, -16260l,
+ -16304l, -16339l, -16363l, -16378l,
+ -16383l,
+};
+
+#endif
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/lpc.c b/external/libvorbis-1.3.5/lib/lpc.c
new file mode 100644
index 0000000..f5199ec
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/lpc.c
@@ -0,0 +1,160 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: LPC low level routines
+ last mod: $Id: lpc.c 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+/* Some of these routines (autocorrelator, LPC coefficient estimator)
+ are derived from code written by Jutta Degener and Carsten Bormann;
+ thus we include their copyright below. The entirety of this file
+ is freely redistributable on the condition that both of these
+ copyright notices are preserved without modification. */
+
+/* Preserved Copyright: *********************************************/
+
+/* Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
+Technische Universita"t Berlin
+
+Any use of this software is permitted provided that this notice is not
+removed and that neither the authors nor the Technische Universita"t
+Berlin are deemed to have made any representations as to the
+suitability of this software for any purpose nor are held responsible
+for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR
+THIS SOFTWARE.
+
+As a matter of courtesy, the authors request to be informed about uses
+this software has found, about bugs in this software, and about any
+improvements that may be of general interest.
+
+Berlin, 28.11.1994
+Jutta Degener
+Carsten Bormann
+
+*********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "os.h"
+#include "smallft.h"
+#include "lpc.h"
+#include "scales.h"
+#include "misc.h"
+
+/* Autocorrelation LPC coeff generation algorithm invented by
+ N. Levinson in 1947, modified by J. Durbin in 1959. */
+
+/* Input : n elements of time doamin data
+ Output: m lpc coefficients, excitation energy */
+
+float vorbis_lpc_from_data(float *data,float *lpci,int n,int m){
+ double *aut=alloca(sizeof(*aut)*(m+1));
+ double *lpc=alloca(sizeof(*lpc)*(m));
+ double error;
+ double epsilon;
+ int i,j;
+
+ /* autocorrelation, p+1 lag coefficients */
+ j=m+1;
+ while(j--){
+ double d=0; /* double needed for accumulator depth */
+ for(i=j;i<n;i++)d+=(double)data[i]*data[i-j];
+ aut[j]=d;
+ }
+
+ /* Generate lpc coefficients from autocorr values */
+
+ /* set our noise floor to about -100dB */
+ error=aut[0] * (1. + 1e-10);
+ epsilon=1e-9*aut[0]+1e-10;
+
+ for(i=0;i<m;i++){
+ double r= -aut[i+1];
+
+ if(error<epsilon){
+ memset(lpc+i,0,(m-i)*sizeof(*lpc));
+ goto done;
+ }
+
+ /* Sum up this iteration's reflection coefficient; note that in
+ Vorbis we don't save it. If anyone wants to recycle this code
+ and needs reflection coefficients, save the results of 'r' from
+ each iteration. */
+
+ for(j=0;j<i;j++)r-=lpc[j]*aut[i-j];
+ r/=error;
+
+ /* Update LPC coefficients and total error */
+
+ lpc[i]=r;
+ for(j=0;j<i/2;j++){
+ double tmp=lpc[j];
+
+ lpc[j]+=r*lpc[i-1-j];
+ lpc[i-1-j]+=r*tmp;
+ }
+ if(i&1)lpc[j]+=lpc[j]*r;
+
+ error*=1.-r*r;
+
+ }
+
+ done:
+
+ /* slightly damp the filter */
+ {
+ double g = .99;
+ double damp = g;
+ for(j=0;j<m;j++){
+ lpc[j]*=damp;
+ damp*=g;
+ }
+ }
+
+ for(j=0;j<m;j++)lpci[j]=(float)lpc[j];
+
+ /* we need the error value to know how big an impulse to hit the
+ filter with later */
+
+ return error;
+}
+
+void vorbis_lpc_predict(float *coeff,float *prime,int m,
+ float *data,long n){
+
+ /* in: coeff[0...m-1] LPC coefficients
+ prime[0...m-1] initial values (allocated size of n+m-1)
+ out: data[0...n-1] data samples */
+
+ long i,j,o,p;
+ float y;
+ float *work=alloca(sizeof(*work)*(m+n));
+
+ if(!prime)
+ for(i=0;i<m;i++)
+ work[i]=0.f;
+ else
+ for(i=0;i<m;i++)
+ work[i]=prime[i];
+
+ for(i=0;i<n;i++){
+ y=0;
+ o=i;
+ p=m;
+ for(j=0;j<m;j++)
+ y-=work[o++]*coeff[--p];
+
+ data[i]=work[o]=y;
+ }
+}
diff --git a/external/libvorbis-1.3.5/lib/lpc.h b/external/libvorbis-1.3.5/lib/lpc.h
new file mode 100644
index 0000000..39d2376
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/lpc.h
@@ -0,0 +1,29 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: LPC low level routines
+ last mod: $Id: lpc.h 16037 2009-05-26 21:10:58Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_LPC_H_
+#define _V_LPC_H_
+
+#include "vorbis/codec.h"
+
+/* simple linear scale LPC code */
+extern float vorbis_lpc_from_data(float *data,float *lpc,int n,int m);
+
+extern void vorbis_lpc_predict(float *coeff,float *prime,int m,
+ float *data,long n);
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/lsp.c b/external/libvorbis-1.3.5/lib/lsp.c
new file mode 100644
index 0000000..6a619f7
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/lsp.c
@@ -0,0 +1,454 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: LSP (also called LSF) conversion routines
+ last mod: $Id: lsp.c 19453 2015-03-02 22:35:34Z xiphmont $
+
+ The LSP generation code is taken (with minimal modification and a
+ few bugfixes) from "On the Computation of the LSP Frequencies" by
+ Joseph Rothweiler (see http://www.rothweiler.us for contact info).
+ The paper is available at:
+
+ http://www.myown1.com/joe/lsf
+
+ ********************************************************************/
+
+/* Note that the lpc-lsp conversion finds the roots of polynomial with
+ an iterative root polisher (CACM algorithm 283). It *is* possible
+ to confuse this algorithm into not converging; that should only
+ happen with absurdly closely spaced roots (very sharp peaks in the
+ LPC f response) which in turn should be impossible in our use of
+ the code. If this *does* happen anyway, it's a bug in the floor
+ finder; find the cause of the confusion (probably a single bin
+ spike or accidental near-float-limit resolution problems) and
+ correct it. */
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "lsp.h"
+#include "os.h"
+#include "misc.h"
+#include "lookup.h"
+#include "scales.h"
+
+/* three possible LSP to f curve functions; the exact computation
+ (float), a lookup based float implementation, and an integer
+ implementation. The float lookup is likely the optimal choice on
+ any machine with an FPU. The integer implementation is *not* fixed
+ point (due to the need for a large dynamic range and thus a
+ separately tracked exponent) and thus much more complex than the
+ relatively simple float implementations. It's mostly for future
+ work on a fully fixed point implementation for processors like the
+ ARM family. */
+
+/* define either of these (preferably FLOAT_LOOKUP) to have faster
+ but less precise implementation. */
+#undef FLOAT_LOOKUP
+#undef INT_LOOKUP
+
+#ifdef FLOAT_LOOKUP
+#include "lookup.c" /* catch this in the build system; we #include for
+ compilers (like gcc) that can't inline across
+ modules */
+
+/* side effect: changes *lsp to cosines of lsp */
+void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m,
+ float amp,float ampoffset){
+ int i;
+ float wdel=M_PI/ln;
+ vorbis_fpu_control fpu;
+
+ vorbis_fpu_setround(&fpu);
+ for(i=0;i<m;i++)lsp[i]=vorbis_coslook(lsp[i]);
+
+ i=0;
+ while(i<n){
+ int k=map[i];
+ int qexp;
+ float p=.7071067812f;
+ float q=.7071067812f;
+ float w=vorbis_coslook(wdel*k);
+ float *ftmp=lsp;
+ int c=m>>1;
+
+ while(c--){
+ q*=ftmp[0]-w;
+ p*=ftmp[1]-w;
+ ftmp+=2;
+ }
+
+ if(m&1){
+ /* odd order filter; slightly assymetric */
+ /* the last coefficient */
+ q*=ftmp[0]-w;
+ q*=q;
+ p*=p*(1.f-w*w);
+ }else{
+ /* even order filter; still symmetric */
+ q*=q*(1.f+w);
+ p*=p*(1.f-w);
+ }
+
+ q=frexp(p+q,&qexp);
+ q=vorbis_fromdBlook(amp*
+ vorbis_invsqlook(q)*
+ vorbis_invsq2explook(qexp+m)-
+ ampoffset);
+
+ do{
+ curve[i++]*=q;
+ }while(map[i]==k);
+ }
+ vorbis_fpu_restore(fpu);
+}
+
+#else
+
+#ifdef INT_LOOKUP
+#include "lookup.c" /* catch this in the build system; we #include for
+ compilers (like gcc) that can't inline across
+ modules */
+
+static const int MLOOP_1[64]={
+ 0,10,11,11, 12,12,12,12, 13,13,13,13, 13,13,13,13,
+ 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,
+};
+
+static const int MLOOP_2[64]={
+ 0,4,5,5, 6,6,6,6, 7,7,7,7, 7,7,7,7,
+ 8,8,8,8, 8,8,8,8, 8,8,8,8, 8,8,8,8,
+ 9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9,
+ 9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9,
+};
+
+static const int MLOOP_3[8]={0,1,2,2,3,3,3,3};
+
+
+/* side effect: changes *lsp to cosines of lsp */
+void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m,
+ float amp,float ampoffset){
+
+ /* 0 <= m < 256 */
+
+ /* set up for using all int later */
+ int i;
+ int ampoffseti=rint(ampoffset*4096.f);
+ int ampi=rint(amp*16.f);
+ long *ilsp=alloca(m*sizeof(*ilsp));
+ for(i=0;i<m;i++)ilsp[i]=vorbis_coslook_i(lsp[i]/M_PI*65536.f+.5f);
+
+ i=0;
+ while(i<n){
+ int j,k=map[i];
+ unsigned long pi=46341; /* 2**-.5 in 0.16 */
+ unsigned long qi=46341;
+ int qexp=0,shift;
+ long wi=vorbis_coslook_i(k*65536/ln);
+
+ qi*=labs(ilsp[0]-wi);
+ pi*=labs(ilsp[1]-wi);
+
+ for(j=3;j<m;j+=2){
+ if(!(shift=MLOOP_1[(pi|qi)>>25]))
+ if(!(shift=MLOOP_2[(pi|qi)>>19]))
+ shift=MLOOP_3[(pi|qi)>>16];
+ qi=(qi>>shift)*labs(ilsp[j-1]-wi);
+ pi=(pi>>shift)*labs(ilsp[j]-wi);
+ qexp+=shift;
+ }
+ if(!(shift=MLOOP_1[(pi|qi)>>25]))
+ if(!(shift=MLOOP_2[(pi|qi)>>19]))
+ shift=MLOOP_3[(pi|qi)>>16];
+
+ /* pi,qi normalized collectively, both tracked using qexp */
+
+ if(m&1){
+ /* odd order filter; slightly assymetric */
+ /* the last coefficient */
+ qi=(qi>>shift)*labs(ilsp[j-1]-wi);
+ pi=(pi>>shift)<<14;
+ qexp+=shift;
+
+ if(!(shift=MLOOP_1[(pi|qi)>>25]))
+ if(!(shift=MLOOP_2[(pi|qi)>>19]))
+ shift=MLOOP_3[(pi|qi)>>16];
+
+ pi>>=shift;
+ qi>>=shift;
+ qexp+=shift-14*((m+1)>>1);
+
+ pi=((pi*pi)>>16);
+ qi=((qi*qi)>>16);
+ qexp=qexp*2+m;
+
+ pi*=(1<<14)-((wi*wi)>>14);
+ qi+=pi>>14;
+
+ }else{
+ /* even order filter; still symmetric */
+
+ /* p*=p(1-w), q*=q(1+w), let normalization drift because it isn't
+ worth tracking step by step */
+
+ pi>>=shift;
+ qi>>=shift;
+ qexp+=shift-7*m;
+
+ pi=((pi*pi)>>16);
+ qi=((qi*qi)>>16);
+ qexp=qexp*2+m;
+
+ pi*=(1<<14)-wi;
+ qi*=(1<<14)+wi;
+ qi=(qi+pi)>>14;
+
+ }
+
+
+ /* we've let the normalization drift because it wasn't important;
+ however, for the lookup, things must be normalized again. We
+ need at most one right shift or a number of left shifts */
+
+ if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */
+ qi>>=1; qexp++;
+ }else
+ while(qi && !(qi&0x8000)){ /* checks for 0.0xxxxxxxxxxxxxxx or less*/
+ qi<<=1; qexp--;
+ }
+
+ amp=vorbis_fromdBlook_i(ampi* /* n.4 */
+ vorbis_invsqlook_i(qi,qexp)-
+ /* m.8, m+n<=8 */
+ ampoffseti); /* 8.12[0] */
+
+ curve[i]*=amp;
+ while(map[++i]==k)curve[i]*=amp;
+ }
+}
+
+#else
+
+/* old, nonoptimized but simple version for any poor sap who needs to
+ figure out what the hell this code does, or wants the other
+ fraction of a dB precision */
+
+/* side effect: changes *lsp to cosines of lsp */
+void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m,
+ float amp,float ampoffset){
+ int i;
+ float wdel=M_PI/ln;
+ for(i=0;i<m;i++)lsp[i]=2.f*cos(lsp[i]);
+
+ i=0;
+ while(i<n){
+ int j,k=map[i];
+ float p=.5f;
+ float q=.5f;
+ float w=2.f*cos(wdel*k);
+ for(j=1;j<m;j+=2){
+ q *= w-lsp[j-1];
+ p *= w-lsp[j];
+ }
+ if(j==m){
+ /* odd order filter; slightly assymetric */
+ /* the last coefficient */
+ q*=w-lsp[j-1];
+ p*=p*(4.f-w*w);
+ q*=q;
+ }else{
+ /* even order filter; still symmetric */
+ p*=p*(2.f-w);
+ q*=q*(2.f+w);
+ }
+
+ q=fromdB(amp/sqrt(p+q)-ampoffset);
+
+ curve[i]*=q;
+ while(map[++i]==k)curve[i]*=q;
+ }
+}
+
+#endif
+#endif
+
+static void cheby(float *g, int ord) {
+ int i, j;
+
+ g[0] *= .5f;
+ for(i=2; i<= ord; i++) {
+ for(j=ord; j >= i; j--) {
+ g[j-2] -= g[j];
+ g[j] += g[j];
+ }
+ }
+}
+
+static int comp(const void *a,const void *b){
+ return (*(float *)a<*(float *)b)-(*(float *)a>*(float *)b);
+}
+
+/* Newton-Raphson-Maehly actually functioned as a decent root finder,
+ but there are root sets for which it gets into limit cycles
+ (exacerbated by zero suppression) and fails. We can't afford to
+ fail, even if the failure is 1 in 100,000,000, so we now use
+ Laguerre and later polish with Newton-Raphson (which can then
+ afford to fail) */
+
+#define EPSILON 10e-7
+static int Laguerre_With_Deflation(float *a,int ord,float *r){
+ int i,m;
+ double *defl=alloca(sizeof(*defl)*(ord+1));
+ for(i=0;i<=ord;i++)defl[i]=a[i];
+
+ for(m=ord;m>0;m--){
+ double new=0.f,delta;
+
+ /* iterate a root */
+ while(1){
+ double p=defl[m],pp=0.f,ppp=0.f,denom;
+
+ /* eval the polynomial and its first two derivatives */
+ for(i=m;i>0;i--){
+ ppp = new*ppp + pp;
+ pp = new*pp + p;
+ p = new*p + defl[i-1];
+ }
+
+ /* Laguerre's method */
+ denom=(m-1) * ((m-1)*pp*pp - m*p*ppp);
+ if(denom<0)
+ return(-1); /* complex root! The LPC generator handed us a bad filter */
+
+ if(pp>0){
+ denom = pp + sqrt(denom);
+ if(denom<EPSILON)denom=EPSILON;
+ }else{
+ denom = pp - sqrt(denom);
+ if(denom>-(EPSILON))denom=-(EPSILON);
+ }
+
+ delta = m*p/denom;
+ new -= delta;
+
+ if(delta<0.f)delta*=-1;
+
+ if(fabs(delta/new)<10e-12)break;
+ }
+
+ r[m-1]=new;
+
+ /* forward deflation */
+
+ for(i=m;i>0;i--)
+ defl[i-1]+=new*defl[i];
+ defl++;
+
+ }
+ return(0);
+}
+
+
+/* for spit-and-polish only */
+static int Newton_Raphson(float *a,int ord,float *r){
+ int i, k, count=0;
+ double error=1.f;
+ double *root=alloca(ord*sizeof(*root));
+
+ for(i=0; i<ord;i++) root[i] = r[i];
+
+ while(error>1e-20){
+ error=0;
+
+ for(i=0; i<ord; i++) { /* Update each point. */
+ double pp=0.,delta;
+ double rooti=root[i];
+ double p=a[ord];
+ for(k=ord-1; k>= 0; k--) {
+
+ pp= pp* rooti + p;
+ p = p * rooti + a[k];
+ }
+
+ delta = p/pp;
+ root[i] -= delta;
+ error+= delta*delta;
+ }
+
+ if(count>40)return(-1);
+
+ count++;
+ }
+
+ /* Replaced the original bubble sort with a real sort. With your
+ help, we can eliminate the bubble sort in our lifetime. --Monty */
+
+ for(i=0; i<ord;i++) r[i] = root[i];
+ return(0);
+}
+
+
+/* Convert lpc coefficients to lsp coefficients */
+int vorbis_lpc_to_lsp(float *lpc,float *lsp,int m){
+ int order2=(m+1)>>1;
+ int g1_order,g2_order;
+ float *g1=alloca(sizeof(*g1)*(order2+1));
+ float *g2=alloca(sizeof(*g2)*(order2+1));
+ float *g1r=alloca(sizeof(*g1r)*(order2+1));
+ float *g2r=alloca(sizeof(*g2r)*(order2+1));
+ int i;
+
+ /* even and odd are slightly different base cases */
+ g1_order=(m+1)>>1;
+ g2_order=(m) >>1;
+
+ /* Compute the lengths of the x polynomials. */
+ /* Compute the first half of K & R F1 & F2 polynomials. */
+ /* Compute half of the symmetric and antisymmetric polynomials. */
+ /* Remove the roots at +1 and -1. */
+
+ g1[g1_order] = 1.f;
+ for(i=1;i<=g1_order;i++) g1[g1_order-i] = lpc[i-1]+lpc[m-i];
+ g2[g2_order] = 1.f;
+ for(i=1;i<=g2_order;i++) g2[g2_order-i] = lpc[i-1]-lpc[m-i];
+
+ if(g1_order>g2_order){
+ for(i=2; i<=g2_order;i++) g2[g2_order-i] += g2[g2_order-i+2];
+ }else{
+ for(i=1; i<=g1_order;i++) g1[g1_order-i] -= g1[g1_order-i+1];
+ for(i=1; i<=g2_order;i++) g2[g2_order-i] += g2[g2_order-i+1];
+ }
+
+ /* Convert into polynomials in cos(alpha) */
+ cheby(g1,g1_order);
+ cheby(g2,g2_order);
+
+ /* Find the roots of the 2 even polynomials.*/
+ if(Laguerre_With_Deflation(g1,g1_order,g1r) ||
+ Laguerre_With_Deflation(g2,g2_order,g2r))
+ return(-1);
+
+ Newton_Raphson(g1,g1_order,g1r); /* if it fails, it leaves g1r alone */
+ Newton_Raphson(g2,g2_order,g2r); /* if it fails, it leaves g2r alone */
+
+ qsort(g1r,g1_order,sizeof(*g1r),comp);
+ qsort(g2r,g2_order,sizeof(*g2r),comp);
+
+ for(i=0;i<g1_order;i++)
+ lsp[i*2] = acos(g1r[i]);
+
+ for(i=0;i<g2_order;i++)
+ lsp[i*2+1] = acos(g2r[i]);
+ return(0);
+}
diff --git a/external/libvorbis-1.3.5/lib/lsp.h b/external/libvorbis-1.3.5/lib/lsp.h
new file mode 100644
index 0000000..bacfb09
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/lsp.h
@@ -0,0 +1,28 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: LSP (also called LSF) conversion routines
+ last mod: $Id: lsp.h 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+
+#ifndef _V_LSP_H_
+#define _V_LSP_H_
+
+extern int vorbis_lpc_to_lsp(float *lpc,float *lsp,int m);
+
+extern void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,
+ float *lsp,int m,
+ float amp,float ampoffset);
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/mapping0.c b/external/libvorbis-1.3.5/lib/mapping0.c
new file mode 100644
index 0000000..85c7d22
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/mapping0.c
@@ -0,0 +1,810 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: channel mapping 0 implementation
+ last mod: $Id: mapping0.c 19441 2015-01-21 01:17:41Z xiphmont $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+#include "codebook.h"
+#include "window.h"
+#include "registry.h"
+#include "psy.h"
+#include "misc.h"
+
+/* simplistic, wasteful way of doing this (unique lookup for each
+ mode/submapping); there should be a central repository for
+ identical lookups. That will require minor work, so I'm putting it
+ off as low priority.
+
+ Why a lookup for each backend in a given mode? Because the
+ blocksize is set by the mode, and low backend lookups may require
+ parameters from other areas of the mode/mapping */
+
+static void mapping0_free_info(vorbis_info_mapping *i){
+ vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)i;
+ if(info){
+ memset(info,0,sizeof(*info));
+ _ogg_free(info);
+ }
+}
+
+static void mapping0_pack(vorbis_info *vi,vorbis_info_mapping *vm,
+ oggpack_buffer *opb){
+ int i;
+ vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)vm;
+
+ /* another 'we meant to do it this way' hack... up to beta 4, we
+ packed 4 binary zeros here to signify one submapping in use. We
+ now redefine that to mean four bitflags that indicate use of
+ deeper features; bit0:submappings, bit1:coupling,
+ bit2,3:reserved. This is backward compatable with all actual uses
+ of the beta code. */
+
+ if(info->submaps>1){
+ oggpack_write(opb,1,1);
+ oggpack_write(opb,info->submaps-1,4);
+ }else
+ oggpack_write(opb,0,1);
+
+ if(info->coupling_steps>0){
+ oggpack_write(opb,1,1);
+ oggpack_write(opb,info->coupling_steps-1,8);
+
+ for(i=0;i<info->coupling_steps;i++){
+ oggpack_write(opb,info->coupling_mag[i],ov_ilog(vi->channels-1));
+ oggpack_write(opb,info->coupling_ang[i],ov_ilog(vi->channels-1));
+ }
+ }else
+ oggpack_write(opb,0,1);
+
+ oggpack_write(opb,0,2); /* 2,3:reserved */
+
+ /* we don't write the channel submappings if we only have one... */
+ if(info->submaps>1){
+ for(i=0;i<vi->channels;i++)
+ oggpack_write(opb,info->chmuxlist[i],4);
+ }
+ for(i=0;i<info->submaps;i++){
+ oggpack_write(opb,0,8); /* time submap unused */
+ oggpack_write(opb,info->floorsubmap[i],8);
+ oggpack_write(opb,info->residuesubmap[i],8);
+ }
+}
+
+/* also responsible for range checking */
+static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){
+ int i,b;
+ vorbis_info_mapping0 *info=_ogg_calloc(1,sizeof(*info));
+ codec_setup_info *ci=vi->codec_setup;
+ memset(info,0,sizeof(*info));
+ if(vi->channels<=0)goto err_out;
+
+ b=oggpack_read(opb,1);
+ if(b<0)goto err_out;
+ if(b){
+ info->submaps=oggpack_read(opb,4)+1;
+ if(info->submaps<=0)goto err_out;
+ }else
+ info->submaps=1;
+
+ b=oggpack_read(opb,1);
+ if(b<0)goto err_out;
+ if(b){
+ info->coupling_steps=oggpack_read(opb,8)+1;
+ if(info->coupling_steps<=0)goto err_out;
+ for(i=0;i<info->coupling_steps;i++){
+ /* vi->channels > 0 is enforced in the caller */
+ int testM=info->coupling_mag[i]=
+ oggpack_read(opb,ov_ilog(vi->channels-1));
+ int testA=info->coupling_ang[i]=
+ oggpack_read(opb,ov_ilog(vi->channels-1));
+
+ if(testM<0 ||
+ testA<0 ||
+ testM==testA ||
+ testM>=vi->channels ||
+ testA>=vi->channels) goto err_out;
+ }
+
+ }
+
+ if(oggpack_read(opb,2)!=0)goto err_out; /* 2,3:reserved */
+
+ if(info->submaps>1){
+ for(i=0;i<vi->channels;i++){
+ info->chmuxlist[i]=oggpack_read(opb,4);
+ if(info->chmuxlist[i]>=info->submaps || info->chmuxlist[i]<0)goto err_out;
+ }
+ }
+ for(i=0;i<info->submaps;i++){
+ oggpack_read(opb,8); /* time submap unused */
+ info->floorsubmap[i]=oggpack_read(opb,8);
+ if(info->floorsubmap[i]>=ci->floors || info->floorsubmap[i]<0)goto err_out;
+ info->residuesubmap[i]=oggpack_read(opb,8);
+ if(info->residuesubmap[i]>=ci->residues || info->residuesubmap[i]<0)goto err_out;
+ }
+
+ return info;
+
+ err_out:
+ mapping0_free_info(info);
+ return(NULL);
+}
+
+#include "os.h"
+#include "lpc.h"
+#include "lsp.h"
+#include "envelope.h"
+#include "mdct.h"
+#include "psy.h"
+#include "scales.h"
+
+#if 0
+static long seq=0;
+static ogg_int64_t total=0;
+static float FLOOR1_fromdB_LOOKUP[256]={
+ 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F,
+ 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F,
+ 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F,
+ 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F,
+ 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F,
+ 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F,
+ 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F,
+ 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F,
+ 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F,
+ 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F,
+ 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F,
+ 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F,
+ 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F,
+ 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F,
+ 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F,
+ 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F,
+ 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F,
+ 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F,
+ 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F,
+ 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F,
+ 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F,
+ 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F,
+ 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F,
+ 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F,
+ 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F,
+ 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F,
+ 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F,
+ 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F,
+ 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F,
+ 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F,
+ 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F,
+ 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F,
+ 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F,
+ 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F,
+ 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F,
+ 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F,
+ 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F,
+ 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F,
+ 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F,
+ 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F,
+ 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F,
+ 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F,
+ 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F,
+ 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F,
+ 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F,
+ 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F,
+ 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F,
+ 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F,
+ 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F,
+ 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F,
+ 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F,
+ 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F,
+ 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F,
+ 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F,
+ 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F,
+ 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F,
+ 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F,
+ 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F,
+ 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F,
+ 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F,
+ 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F,
+ 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F,
+ 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F,
+ 0.82788260F, 0.88168307F, 0.9389798F, 1.F,
+};
+
+#endif
+
+
+static int mapping0_forward(vorbis_block *vb){
+ vorbis_dsp_state *vd=vb->vd;
+ vorbis_info *vi=vd->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ private_state *b=vb->vd->backend_state;
+ vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal;
+ int n=vb->pcmend;
+ int i,j,k;
+
+ int *nonzero = alloca(sizeof(*nonzero)*vi->channels);
+ float **gmdct = _vorbis_block_alloc(vb,vi->channels*sizeof(*gmdct));
+ int **iwork = _vorbis_block_alloc(vb,vi->channels*sizeof(*iwork));
+ int ***floor_posts = _vorbis_block_alloc(vb,vi->channels*sizeof(*floor_posts));
+
+ float global_ampmax=vbi->ampmax;
+ float *local_ampmax=alloca(sizeof(*local_ampmax)*vi->channels);
+ int blocktype=vbi->blocktype;
+
+ int modenumber=vb->W;
+ vorbis_info_mapping0 *info=ci->map_param[modenumber];
+ vorbis_look_psy *psy_look=b->psy+blocktype+(vb->W?2:0);
+
+ vb->mode=modenumber;
+
+ for(i=0;i<vi->channels;i++){
+ float scale=4.f/n;
+ float scale_dB;
+
+ float *pcm =vb->pcm[i];
+ float *logfft =pcm;
+
+ iwork[i]=_vorbis_block_alloc(vb,n/2*sizeof(**iwork));
+ gmdct[i]=_vorbis_block_alloc(vb,n/2*sizeof(**gmdct));
+
+ scale_dB=todB(&scale) + .345; /* + .345 is a hack; the original
+ todB estimation used on IEEE 754
+ compliant machines had a bug that
+ returned dB values about a third
+ of a decibel too high. The bug
+ was harmless because tunings
+ implicitly took that into
+ account. However, fixing the bug
+ in the estimator requires
+ changing all the tunings as well.
+ For now, it's easier to sync
+ things back up here, and
+ recalibrate the tunings in the
+ next major model upgrade. */
+
+#if 0
+ if(vi->channels==2){
+ if(i==0)
+ _analysis_output("pcmL",seq,pcm,n,0,0,total-n/2);
+ else
+ _analysis_output("pcmR",seq,pcm,n,0,0,total-n/2);
+ }else{
+ _analysis_output("pcm",seq,pcm,n,0,0,total-n/2);
+ }
+#endif
+
+ /* window the PCM data */
+ _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW);
+
+#if 0
+ if(vi->channels==2){
+ if(i==0)
+ _analysis_output("windowedL",seq,pcm,n,0,0,total-n/2);
+ else
+ _analysis_output("windowedR",seq,pcm,n,0,0,total-n/2);
+ }else{
+ _analysis_output("windowed",seq,pcm,n,0,0,total-n/2);
+ }
+#endif
+
+ /* transform the PCM data */
+ /* only MDCT right now.... */
+ mdct_forward(b->transform[vb->W][0],pcm,gmdct[i]);
+
+ /* FFT yields more accurate tonal estimation (not phase sensitive) */
+ drft_forward(&b->fft_look[vb->W],pcm);
+ logfft[0]=scale_dB+todB(pcm) + .345; /* + .345 is a hack; the
+ original todB estimation used on
+ IEEE 754 compliant machines had a
+ bug that returned dB values about
+ a third of a decibel too high.
+ The bug was harmless because
+ tunings implicitly took that into
+ account. However, fixing the bug
+ in the estimator requires
+ changing all the tunings as well.
+ For now, it's easier to sync
+ things back up here, and
+ recalibrate the tunings in the
+ next major model upgrade. */
+ local_ampmax[i]=logfft[0];
+ for(j=1;j<n-1;j+=2){
+ float temp=pcm[j]*pcm[j]+pcm[j+1]*pcm[j+1];
+ temp=logfft[(j+1)>>1]=scale_dB+.5f*todB(&temp) + .345; /* +
+ .345 is a hack; the original todB
+ estimation used on IEEE 754
+ compliant machines had a bug that
+ returned dB values about a third
+ of a decibel too high. The bug
+ was harmless because tunings
+ implicitly took that into
+ account. However, fixing the bug
+ in the estimator requires
+ changing all the tunings as well.
+ For now, it's easier to sync
+ things back up here, and
+ recalibrate the tunings in the
+ next major model upgrade. */
+ if(temp>local_ampmax[i])local_ampmax[i]=temp;
+ }
+
+ if(local_ampmax[i]>0.f)local_ampmax[i]=0.f;
+ if(local_ampmax[i]>global_ampmax)global_ampmax=local_ampmax[i];
+
+#if 0
+ if(vi->channels==2){
+ if(i==0){
+ _analysis_output("fftL",seq,logfft,n/2,1,0,0);
+ }else{
+ _analysis_output("fftR",seq,logfft,n/2,1,0,0);
+ }
+ }else{
+ _analysis_output("fft",seq,logfft,n/2,1,0,0);
+ }
+#endif
+
+ }
+
+ {
+ float *noise = _vorbis_block_alloc(vb,n/2*sizeof(*noise));
+ float *tone = _vorbis_block_alloc(vb,n/2*sizeof(*tone));
+
+ for(i=0;i<vi->channels;i++){
+ /* the encoder setup assumes that all the modes used by any
+ specific bitrate tweaking use the same floor */
+
+ int submap=info->chmuxlist[i];
+
+ /* the following makes things clearer to *me* anyway */
+ float *mdct =gmdct[i];
+ float *logfft =vb->pcm[i];
+
+ float *logmdct =logfft+n/2;
+ float *logmask =logfft;
+
+ vb->mode=modenumber;
+
+ floor_posts[i]=_vorbis_block_alloc(vb,PACKETBLOBS*sizeof(**floor_posts));
+ memset(floor_posts[i],0,sizeof(**floor_posts)*PACKETBLOBS);
+
+ for(j=0;j<n/2;j++)
+ logmdct[j]=todB(mdct+j) + .345; /* + .345 is a hack; the original
+ todB estimation used on IEEE 754
+ compliant machines had a bug that
+ returned dB values about a third
+ of a decibel too high. The bug
+ was harmless because tunings
+ implicitly took that into
+ account. However, fixing the bug
+ in the estimator requires
+ changing all the tunings as well.
+ For now, it's easier to sync
+ things back up here, and
+ recalibrate the tunings in the
+ next major model upgrade. */
+
+#if 0
+ if(vi->channels==2){
+ if(i==0)
+ _analysis_output("mdctL",seq,logmdct,n/2,1,0,0);
+ else
+ _analysis_output("mdctR",seq,logmdct,n/2,1,0,0);
+ }else{
+ _analysis_output("mdct",seq,logmdct,n/2,1,0,0);
+ }
+#endif
+
+ /* first step; noise masking. Not only does 'noise masking'
+ give us curves from which we can decide how much resolution
+ to give noise parts of the spectrum, it also implicitly hands
+ us a tonality estimate (the larger the value in the
+ 'noise_depth' vector, the more tonal that area is) */
+
+ _vp_noisemask(psy_look,
+ logmdct,
+ noise); /* noise does not have by-frequency offset
+ bias applied yet */
+#if 0
+ if(vi->channels==2){
+ if(i==0)
+ _analysis_output("noiseL",seq,noise,n/2,1,0,0);
+ else
+ _analysis_output("noiseR",seq,noise,n/2,1,0,0);
+ }else{
+ _analysis_output("noise",seq,noise,n/2,1,0,0);
+ }
+#endif
+
+ /* second step: 'all the other crap'; all the stuff that isn't
+ computed/fit for bitrate management goes in the second psy
+ vector. This includes tone masking, peak limiting and ATH */
+
+ _vp_tonemask(psy_look,
+ logfft,
+ tone,
+ global_ampmax,
+ local_ampmax[i]);
+
+#if 0
+ if(vi->channels==2){
+ if(i==0)
+ _analysis_output("toneL",seq,tone,n/2,1,0,0);
+ else
+ _analysis_output("toneR",seq,tone,n/2,1,0,0);
+ }else{
+ _analysis_output("tone",seq,tone,n/2,1,0,0);
+ }
+#endif
+
+ /* third step; we offset the noise vectors, overlay tone
+ masking. We then do a floor1-specific line fit. If we're
+ performing bitrate management, the line fit is performed
+ multiple times for up/down tweakage on demand. */
+
+#if 0
+ {
+ float aotuv[psy_look->n];
+#endif
+
+ _vp_offset_and_mix(psy_look,
+ noise,
+ tone,
+ 1,
+ logmask,
+ mdct,
+ logmdct);
+
+#if 0
+ if(vi->channels==2){
+ if(i==0)
+ _analysis_output("aotuvM1_L",seq,aotuv,psy_look->n,1,1,0);
+ else
+ _analysis_output("aotuvM1_R",seq,aotuv,psy_look->n,1,1,0);
+ }else{
+ _analysis_output("aotuvM1",seq,aotuv,psy_look->n,1,1,0);
+ }
+ }
+#endif
+
+
+#if 0
+ if(vi->channels==2){
+ if(i==0)
+ _analysis_output("mask1L",seq,logmask,n/2,1,0,0);
+ else
+ _analysis_output("mask1R",seq,logmask,n/2,1,0,0);
+ }else{
+ _analysis_output("mask1",seq,logmask,n/2,1,0,0);
+ }
+#endif
+
+ /* this algorithm is hardwired to floor 1 for now; abort out if
+ we're *not* floor1. This won't happen unless someone has
+ broken the encode setup lib. Guard it anyway. */
+ if(ci->floor_type[info->floorsubmap[submap]]!=1)return(-1);
+
+ floor_posts[i][PACKETBLOBS/2]=
+ floor1_fit(vb,b->flr[info->floorsubmap[submap]],
+ logmdct,
+ logmask);
+
+ /* are we managing bitrate? If so, perform two more fits for
+ later rate tweaking (fits represent hi/lo) */
+ if(vorbis_bitrate_managed(vb) && floor_posts[i][PACKETBLOBS/2]){
+ /* higher rate by way of lower noise curve */
+
+ _vp_offset_and_mix(psy_look,
+ noise,
+ tone,
+ 2,
+ logmask,
+ mdct,
+ logmdct);
+
+#if 0
+ if(vi->channels==2){
+ if(i==0)
+ _analysis_output("mask2L",seq,logmask,n/2,1,0,0);
+ else
+ _analysis_output("mask2R",seq,logmask,n/2,1,0,0);
+ }else{
+ _analysis_output("mask2",seq,logmask,n/2,1,0,0);
+ }
+#endif
+
+ floor_posts[i][PACKETBLOBS-1]=
+ floor1_fit(vb,b->flr[info->floorsubmap[submap]],
+ logmdct,
+ logmask);
+
+ /* lower rate by way of higher noise curve */
+ _vp_offset_and_mix(psy_look,
+ noise,
+ tone,
+ 0,
+ logmask,
+ mdct,
+ logmdct);
+
+#if 0
+ if(vi->channels==2){
+ if(i==0)
+ _analysis_output("mask0L",seq,logmask,n/2,1,0,0);
+ else
+ _analysis_output("mask0R",seq,logmask,n/2,1,0,0);
+ }else{
+ _analysis_output("mask0",seq,logmask,n/2,1,0,0);
+ }
+#endif
+
+ floor_posts[i][0]=
+ floor1_fit(vb,b->flr[info->floorsubmap[submap]],
+ logmdct,
+ logmask);
+
+ /* we also interpolate a range of intermediate curves for
+ intermediate rates */
+ for(k=1;k<PACKETBLOBS/2;k++)
+ floor_posts[i][k]=
+ floor1_interpolate_fit(vb,b->flr[info->floorsubmap[submap]],
+ floor_posts[i][0],
+ floor_posts[i][PACKETBLOBS/2],
+ k*65536/(PACKETBLOBS/2));
+ for(k=PACKETBLOBS/2+1;k<PACKETBLOBS-1;k++)
+ floor_posts[i][k]=
+ floor1_interpolate_fit(vb,b->flr[info->floorsubmap[submap]],
+ floor_posts[i][PACKETBLOBS/2],
+ floor_posts[i][PACKETBLOBS-1],
+ (k-PACKETBLOBS/2)*65536/(PACKETBLOBS/2));
+ }
+ }
+ }
+ vbi->ampmax=global_ampmax;
+
+ /*
+ the next phases are performed once for vbr-only and PACKETBLOB
+ times for bitrate managed modes.
+
+ 1) encode actual mode being used
+ 2) encode the floor for each channel, compute coded mask curve/res
+ 3) normalize and couple.
+ 4) encode residue
+ 5) save packet bytes to the packetblob vector
+
+ */
+
+ /* iterate over the many masking curve fits we've created */
+
+ {
+ int **couple_bundle=alloca(sizeof(*couple_bundle)*vi->channels);
+ int *zerobundle=alloca(sizeof(*zerobundle)*vi->channels);
+
+ for(k=(vorbis_bitrate_managed(vb)?0:PACKETBLOBS/2);
+ k<=(vorbis_bitrate_managed(vb)?PACKETBLOBS-1:PACKETBLOBS/2);
+ k++){
+ oggpack_buffer *opb=vbi->packetblob[k];
+
+ /* start out our new packet blob with packet type and mode */
+ /* Encode the packet type */
+ oggpack_write(opb,0,1);
+ /* Encode the modenumber */
+ /* Encode frame mode, pre,post windowsize, then dispatch */
+ oggpack_write(opb,modenumber,b->modebits);
+ if(vb->W){
+ oggpack_write(opb,vb->lW,1);
+ oggpack_write(opb,vb->nW,1);
+ }
+
+ /* encode floor, compute masking curve, sep out residue */
+ for(i=0;i<vi->channels;i++){
+ int submap=info->chmuxlist[i];
+ int *ilogmask=iwork[i];
+
+ nonzero[i]=floor1_encode(opb,vb,b->flr[info->floorsubmap[submap]],
+ floor_posts[i][k],
+ ilogmask);
+#if 0
+ {
+ char buf[80];
+ sprintf(buf,"maskI%c%d",i?'R':'L',k);
+ float work[n/2];
+ for(j=0;j<n/2;j++)
+ work[j]=FLOOR1_fromdB_LOOKUP[iwork[i][j]];
+ _analysis_output(buf,seq,work,n/2,1,1,0);
+ }
+#endif
+ }
+
+ /* our iteration is now based on masking curve, not prequant and
+ coupling. Only one prequant/coupling step */
+
+ /* quantize/couple */
+ /* incomplete implementation that assumes the tree is all depth
+ one, or no tree at all */
+ _vp_couple_quantize_normalize(k,
+ &ci->psy_g_param,
+ psy_look,
+ info,
+ gmdct,
+ iwork,
+ nonzero,
+ ci->psy_g_param.sliding_lowpass[vb->W][k],
+ vi->channels);
+
+#if 0
+ for(i=0;i<vi->channels;i++){
+ char buf[80];
+ sprintf(buf,"res%c%d",i?'R':'L',k);
+ float work[n/2];
+ for(j=0;j<n/2;j++)
+ work[j]=iwork[i][j];
+ _analysis_output(buf,seq,work,n/2,1,0,0);
+ }
+#endif
+
+ /* classify and encode by submap */
+ for(i=0;i<info->submaps;i++){
+ int ch_in_bundle=0;
+ long **classifications;
+ int resnum=info->residuesubmap[i];
+
+ for(j=0;j<vi->channels;j++){
+ if(info->chmuxlist[j]==i){
+ zerobundle[ch_in_bundle]=0;
+ if(nonzero[j])zerobundle[ch_in_bundle]=1;
+ couple_bundle[ch_in_bundle++]=iwork[j];
+ }
+ }
+
+ classifications=_residue_P[ci->residue_type[resnum]]->
+ class(vb,b->residue[resnum],couple_bundle,zerobundle,ch_in_bundle);
+
+ ch_in_bundle=0;
+ for(j=0;j<vi->channels;j++)
+ if(info->chmuxlist[j]==i)
+ couple_bundle[ch_in_bundle++]=iwork[j];
+
+ _residue_P[ci->residue_type[resnum]]->
+ forward(opb,vb,b->residue[resnum],
+ couple_bundle,zerobundle,ch_in_bundle,classifications,i);
+ }
+
+ /* ok, done encoding. Next protopacket. */
+ }
+
+ }
+
+#if 0
+ seq++;
+ total+=ci->blocksizes[vb->W]/4+ci->blocksizes[vb->nW]/4;
+#endif
+ return(0);
+}
+
+static int mapping0_inverse(vorbis_block *vb,vorbis_info_mapping *l){
+ vorbis_dsp_state *vd=vb->vd;
+ vorbis_info *vi=vd->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ private_state *b=vd->backend_state;
+ vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)l;
+
+ int i,j;
+ long n=vb->pcmend=ci->blocksizes[vb->W];
+
+ float **pcmbundle=alloca(sizeof(*pcmbundle)*vi->channels);
+ int *zerobundle=alloca(sizeof(*zerobundle)*vi->channels);
+
+ int *nonzero =alloca(sizeof(*nonzero)*vi->channels);
+ void **floormemo=alloca(sizeof(*floormemo)*vi->channels);
+
+ /* recover the spectral envelope; store it in the PCM vector for now */
+ for(i=0;i<vi->channels;i++){
+ int submap=info->chmuxlist[i];
+ floormemo[i]=_floor_P[ci->floor_type[info->floorsubmap[submap]]]->
+ inverse1(vb,b->flr[info->floorsubmap[submap]]);
+ if(floormemo[i])
+ nonzero[i]=1;
+ else
+ nonzero[i]=0;
+ memset(vb->pcm[i],0,sizeof(*vb->pcm[i])*n/2);
+ }
+
+ /* channel coupling can 'dirty' the nonzero listing */
+ for(i=0;i<info->coupling_steps;i++){
+ if(nonzero[info->coupling_mag[i]] ||
+ nonzero[info->coupling_ang[i]]){
+ nonzero[info->coupling_mag[i]]=1;
+ nonzero[info->coupling_ang[i]]=1;
+ }
+ }
+
+ /* recover the residue into our working vectors */
+ for(i=0;i<info->submaps;i++){
+ int ch_in_bundle=0;
+ for(j=0;j<vi->channels;j++){
+ if(info->chmuxlist[j]==i){
+ if(nonzero[j])
+ zerobundle[ch_in_bundle]=1;
+ else
+ zerobundle[ch_in_bundle]=0;
+ pcmbundle[ch_in_bundle++]=vb->pcm[j];
+ }
+ }
+
+ _residue_P[ci->residue_type[info->residuesubmap[i]]]->
+ inverse(vb,b->residue[info->residuesubmap[i]],
+ pcmbundle,zerobundle,ch_in_bundle);
+ }
+
+ /* channel coupling */
+ for(i=info->coupling_steps-1;i>=0;i--){
+ float *pcmM=vb->pcm[info->coupling_mag[i]];
+ float *pcmA=vb->pcm[info->coupling_ang[i]];
+
+ for(j=0;j<n/2;j++){
+ float mag=pcmM[j];
+ float ang=pcmA[j];
+
+ if(mag>0)
+ if(ang>0){
+ pcmM[j]=mag;
+ pcmA[j]=mag-ang;
+ }else{
+ pcmA[j]=mag;
+ pcmM[j]=mag+ang;
+ }
+ else
+ if(ang>0){
+ pcmM[j]=mag;
+ pcmA[j]=mag+ang;
+ }else{
+ pcmA[j]=mag;
+ pcmM[j]=mag-ang;
+ }
+ }
+ }
+
+ /* compute and apply spectral envelope */
+ for(i=0;i<vi->channels;i++){
+ float *pcm=vb->pcm[i];
+ int submap=info->chmuxlist[i];
+ _floor_P[ci->floor_type[info->floorsubmap[submap]]]->
+ inverse2(vb,b->flr[info->floorsubmap[submap]],
+ floormemo[i],pcm);
+ }
+
+ /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
+ /* only MDCT right now.... */
+ for(i=0;i<vi->channels;i++){
+ float *pcm=vb->pcm[i];
+ mdct_backward(b->transform[vb->W][0],pcm,pcm);
+ }
+
+ /* all done! */
+ return(0);
+}
+
+/* export hooks */
+const vorbis_func_mapping mapping0_exportbundle={
+ &mapping0_pack,
+ &mapping0_unpack,
+ &mapping0_free_info,
+ &mapping0_forward,
+ &mapping0_inverse
+};
diff --git a/external/libvorbis-1.3.5/lib/masking.h b/external/libvorbis-1.3.5/lib/masking.h
new file mode 100644
index 0000000..3576ab7
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/masking.h
@@ -0,0 +1,785 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: masking curve data for psychoacoustics
+ last mod: $Id: masking.h 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_MASKING_H_
+#define _V_MASKING_H_
+
+/* more detailed ATH; the bass if flat to save stressing the floor
+ overly for only a bin or two of savings. */
+
+#define MAX_ATH 88
+static const float ATH[]={
+ /*15*/ -51, -52, -53, -54, -55, -56, -57, -58,
+ /*31*/ -59, -60, -61, -62, -63, -64, -65, -66,
+ /*63*/ -67, -68, -69, -70, -71, -72, -73, -74,
+ /*125*/ -75, -76, -77, -78, -80, -81, -82, -83,
+ /*250*/ -84, -85, -86, -87, -88, -88, -89, -89,
+ /*500*/ -90, -91, -91, -92, -93, -94, -95, -96,
+ /*1k*/ -96, -97, -98, -98, -99, -99,-100,-100,
+ /*2k*/ -101,-102,-103,-104,-106,-107,-107,-107,
+ /*4k*/ -107,-105,-103,-102,-101, -99, -98, -96,
+ /*8k*/ -95, -95, -96, -97, -96, -95, -93, -90,
+ /*16k*/ -80, -70, -50, -40, -30, -30, -30, -30
+};
+
+/* The tone masking curves from Ehmer's and Fielder's papers have been
+ replaced by an empirically collected data set. The previously
+ published values were, far too often, simply on crack. */
+
+#define EHMER_OFFSET 16
+#define EHMER_MAX 56
+
+/* masking tones from -50 to 0dB, 62.5 through 16kHz at half octaves
+ test tones from -2 octaves to +5 octaves sampled at eighth octaves */
+/* (Vorbis 0dB, the loudest possible tone, is assumed to be ~100dB SPL
+ for collection of these curves) */
+
+static const float tonemasks[P_BANDS][6][EHMER_MAX]={
+ /* 62.5 Hz */
+ {{ -60, -60, -60, -60, -60, -60, -60, -60,
+ -60, -60, -60, -60, -62, -62, -65, -73,
+ -69, -68, -68, -67, -70, -70, -72, -74,
+ -75, -79, -79, -80, -83, -88, -93, -100,
+ -110, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -48, -48, -48, -48, -48, -48, -48, -48,
+ -48, -48, -48, -48, -48, -53, -61, -66,
+ -66, -68, -67, -70, -76, -76, -72, -73,
+ -75, -76, -78, -79, -83, -88, -93, -100,
+ -110, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -37, -37, -37, -37, -37, -37, -37, -37,
+ -38, -40, -42, -46, -48, -53, -55, -62,
+ -65, -58, -56, -56, -61, -60, -65, -67,
+ -69, -71, -77, -77, -78, -80, -82, -84,
+ -88, -93, -98, -106, -112, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -26, -27, -29, -32, -38, -48, -52,
+ -52, -50, -48, -48, -51, -52, -54, -60,
+ -67, -67, -66, -68, -69, -73, -73, -76,
+ -80, -81, -81, -85, -85, -86, -88, -93,
+ -100, -110, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -16, -16, -16, -16, -16, -16, -16, -16,
+ -17, -19, -20, -22, -26, -28, -31, -40,
+ -47, -39, -39, -40, -42, -43, -47, -51,
+ -57, -52, -55, -55, -60, -58, -62, -63,
+ -70, -67, -69, -72, -73, -77, -80, -82,
+ -83, -87, -90, -94, -98, -104, -115, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -8, -8, -8, -8, -8, -8, -8, -8,
+ -8, -8, -10, -11, -15, -19, -25, -30,
+ -34, -31, -30, -31, -29, -32, -35, -42,
+ -48, -42, -44, -46, -50, -50, -51, -52,
+ -59, -54, -55, -55, -58, -62, -63, -66,
+ -72, -73, -76, -75, -78, -80, -80, -81,
+ -84, -88, -90, -94, -98, -101, -106, -110}},
+ /* 88Hz */
+ {{ -66, -66, -66, -66, -66, -66, -66, -66,
+ -66, -66, -66, -66, -66, -67, -67, -67,
+ -76, -72, -71, -74, -76, -76, -75, -78,
+ -79, -79, -81, -83, -86, -89, -93, -97,
+ -100, -105, -110, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -47, -47, -47, -47, -47, -47, -47, -47,
+ -47, -47, -47, -48, -51, -55, -59, -66,
+ -66, -66, -67, -66, -68, -69, -70, -74,
+ -79, -77, -77, -78, -80, -81, -82, -84,
+ -86, -88, -91, -95, -100, -108, -116, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -36, -36, -36, -36, -36, -36, -36, -36,
+ -36, -37, -37, -41, -44, -48, -51, -58,
+ -62, -60, -57, -59, -59, -60, -63, -65,
+ -72, -71, -70, -72, -74, -77, -76, -78,
+ -81, -81, -80, -83, -86, -91, -96, -100,
+ -105, -110, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -28, -28, -28, -28, -28, -28, -28, -28,
+ -28, -30, -32, -32, -33, -35, -41, -49,
+ -50, -49, -47, -48, -48, -52, -51, -57,
+ -65, -61, -59, -61, -64, -69, -70, -74,
+ -77, -77, -78, -81, -84, -85, -87, -90,
+ -92, -96, -100, -107, -112, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -19, -19, -19, -19, -19, -19, -19, -19,
+ -20, -21, -23, -27, -30, -35, -36, -41,
+ -46, -44, -42, -40, -41, -41, -43, -48,
+ -55, -53, -52, -53, -56, -59, -58, -60,
+ -67, -66, -69, -71, -72, -75, -79, -81,
+ -84, -87, -90, -93, -97, -101, -107, -114,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -9, -9, -9, -9, -9, -9, -9, -9,
+ -11, -12, -12, -15, -16, -20, -23, -30,
+ -37, -34, -33, -34, -31, -32, -32, -38,
+ -47, -44, -41, -40, -47, -49, -46, -46,
+ -58, -50, -50, -54, -58, -62, -64, -67,
+ -67, -70, -72, -76, -79, -83, -87, -91,
+ -96, -100, -104, -110, -999, -999, -999, -999}},
+ /* 125 Hz */
+ {{ -62, -62, -62, -62, -62, -62, -62, -62,
+ -62, -62, -63, -64, -66, -67, -66, -68,
+ -75, -72, -76, -75, -76, -78, -79, -82,
+ -84, -85, -90, -94, -101, -110, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -59, -59, -59, -59, -59, -59, -59, -59,
+ -59, -59, -59, -60, -60, -61, -63, -66,
+ -71, -68, -70, -70, -71, -72, -72, -75,
+ -81, -78, -79, -82, -83, -86, -90, -97,
+ -103, -113, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -53, -53, -53, -53, -53, -53, -53, -53,
+ -53, -54, -55, -57, -56, -57, -55, -61,
+ -65, -60, -60, -62, -63, -63, -66, -68,
+ -74, -73, -75, -75, -78, -80, -80, -82,
+ -85, -90, -96, -101, -108, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -46, -46, -46, -46, -46, -46, -46, -46,
+ -46, -46, -47, -47, -47, -47, -48, -51,
+ -57, -51, -49, -50, -51, -53, -54, -59,
+ -66, -60, -62, -67, -67, -70, -72, -75,
+ -76, -78, -81, -85, -88, -94, -97, -104,
+ -112, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -36, -36, -36, -36, -36, -36, -36, -36,
+ -39, -41, -42, -42, -39, -38, -41, -43,
+ -52, -44, -40, -39, -37, -37, -40, -47,
+ -54, -50, -48, -50, -55, -61, -59, -62,
+ -66, -66, -66, -69, -69, -73, -74, -74,
+ -75, -77, -79, -82, -87, -91, -95, -100,
+ -108, -115, -999, -999, -999, -999, -999, -999},
+ { -28, -26, -24, -22, -20, -20, -23, -29,
+ -30, -31, -28, -27, -28, -28, -28, -35,
+ -40, -33, -32, -29, -30, -30, -30, -37,
+ -45, -41, -37, -38, -45, -47, -47, -48,
+ -53, -49, -48, -50, -49, -49, -51, -52,
+ -58, -56, -57, -56, -60, -61, -62, -70,
+ -72, -74, -78, -83, -88, -93, -100, -106}},
+ /* 177 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -110, -105, -100, -95, -91, -87, -83,
+ -80, -78, -76, -78, -78, -81, -83, -85,
+ -86, -85, -86, -87, -90, -97, -107, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -110, -105, -100, -95, -90,
+ -85, -81, -77, -73, -70, -67, -67, -68,
+ -75, -73, -70, -69, -70, -72, -75, -79,
+ -84, -83, -84, -86, -88, -89, -89, -93,
+ -98, -105, -112, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-105, -100, -95, -90, -85, -80, -76, -71,
+ -68, -68, -65, -63, -63, -62, -62, -64,
+ -65, -64, -61, -62, -63, -64, -66, -68,
+ -73, -73, -74, -75, -76, -81, -83, -85,
+ -88, -89, -92, -95, -100, -108, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -80, -75, -71, -68, -65, -63, -62, -61,
+ -61, -61, -61, -59, -56, -57, -53, -50,
+ -58, -52, -50, -50, -52, -53, -54, -58,
+ -67, -63, -67, -68, -72, -75, -78, -80,
+ -81, -81, -82, -85, -89, -90, -93, -97,
+ -101, -107, -114, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ { -65, -61, -59, -57, -56, -55, -55, -56,
+ -56, -57, -55, -53, -52, -47, -44, -44,
+ -50, -44, -41, -39, -39, -42, -40, -46,
+ -51, -49, -50, -53, -54, -63, -60, -61,
+ -62, -66, -66, -66, -70, -73, -74, -75,
+ -76, -75, -79, -85, -89, -91, -96, -102,
+ -110, -999, -999, -999, -999, -999, -999, -999},
+ { -52, -50, -49, -49, -48, -48, -48, -49,
+ -50, -50, -49, -46, -43, -39, -35, -33,
+ -38, -36, -32, -29, -32, -32, -32, -35,
+ -44, -39, -38, -38, -46, -50, -45, -46,
+ -53, -50, -50, -50, -54, -54, -53, -53,
+ -56, -57, -59, -66, -70, -72, -74, -79,
+ -83, -85, -90, -97, -114, -999, -999, -999}},
+ /* 250 Hz */
+ {{-999, -999, -999, -999, -999, -999, -110, -105,
+ -100, -95, -90, -86, -80, -75, -75, -79,
+ -80, -79, -80, -81, -82, -88, -95, -103,
+ -110, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -108, -103, -98, -93,
+ -88, -83, -79, -78, -75, -71, -67, -68,
+ -73, -73, -72, -73, -75, -77, -80, -82,
+ -88, -93, -100, -107, -114, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -110, -105, -101, -96, -90,
+ -86, -81, -77, -73, -69, -66, -61, -62,
+ -66, -64, -62, -65, -66, -70, -72, -76,
+ -81, -80, -84, -90, -95, -102, -110, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -107, -103, -97, -92, -88,
+ -83, -79, -74, -70, -66, -59, -53, -58,
+ -62, -55, -54, -54, -54, -58, -61, -62,
+ -72, -70, -72, -75, -78, -80, -81, -80,
+ -83, -83, -88, -93, -100, -107, -115, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -105, -100, -95, -90, -85,
+ -80, -75, -70, -66, -62, -56, -48, -44,
+ -48, -46, -46, -43, -46, -48, -48, -51,
+ -58, -58, -59, -60, -62, -62, -61, -61,
+ -65, -64, -65, -68, -70, -74, -75, -78,
+ -81, -86, -95, -110, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -105, -100, -95, -90, -85, -80,
+ -75, -70, -65, -61, -55, -49, -39, -33,
+ -40, -35, -32, -38, -40, -33, -35, -37,
+ -46, -41, -45, -44, -46, -42, -45, -46,
+ -52, -50, -50, -50, -54, -54, -55, -57,
+ -62, -64, -66, -68, -70, -76, -81, -90,
+ -100, -110, -999, -999, -999, -999, -999, -999}},
+ /* 354 hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -105, -98, -90, -85, -82, -83, -80, -78,
+ -84, -79, -80, -83, -87, -89, -91, -93,
+ -99, -106, -117, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -105, -98, -90, -85, -80, -75, -70, -68,
+ -74, -72, -74, -77, -80, -82, -85, -87,
+ -92, -89, -91, -95, -100, -106, -112, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -105, -98, -90, -83, -75, -71, -63, -64,
+ -67, -62, -64, -67, -70, -73, -77, -81,
+ -84, -83, -85, -89, -90, -93, -98, -104,
+ -109, -114, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -103, -96, -88, -81, -75, -68, -58, -54,
+ -56, -54, -56, -56, -58, -60, -63, -66,
+ -74, -69, -72, -72, -75, -74, -77, -81,
+ -81, -82, -84, -87, -93, -96, -99, -104,
+ -110, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -108, -102, -96,
+ -91, -85, -80, -74, -68, -60, -51, -46,
+ -48, -46, -43, -45, -47, -47, -49, -48,
+ -56, -53, -55, -58, -57, -63, -58, -60,
+ -66, -64, -67, -70, -70, -74, -77, -84,
+ -86, -89, -91, -93, -94, -101, -109, -118,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -108, -103, -98, -93, -88,
+ -83, -78, -73, -68, -60, -53, -44, -35,
+ -38, -38, -34, -34, -36, -40, -41, -44,
+ -51, -45, -46, -47, -46, -54, -50, -49,
+ -50, -50, -50, -51, -54, -57, -58, -60,
+ -66, -66, -66, -64, -65, -68, -77, -82,
+ -87, -95, -110, -999, -999, -999, -999, -999}},
+ /* 500 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -107, -102, -97, -92, -87, -83, -78, -75,
+ -82, -79, -83, -85, -89, -92, -95, -98,
+ -101, -105, -109, -113, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -106,
+ -100, -95, -90, -86, -81, -78, -74, -69,
+ -74, -74, -76, -79, -83, -84, -86, -89,
+ -92, -97, -93, -100, -103, -107, -110, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -106, -100,
+ -95, -90, -87, -83, -80, -75, -69, -60,
+ -66, -66, -68, -70, -74, -78, -79, -81,
+ -81, -83, -84, -87, -93, -96, -99, -103,
+ -107, -110, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -108, -103, -98,
+ -93, -89, -85, -82, -78, -71, -62, -55,
+ -58, -58, -54, -54, -55, -59, -61, -62,
+ -70, -66, -66, -67, -70, -72, -75, -78,
+ -84, -84, -84, -88, -91, -90, -95, -98,
+ -102, -103, -106, -110, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -108, -103, -98, -94,
+ -90, -87, -82, -79, -73, -67, -58, -47,
+ -50, -45, -41, -45, -48, -44, -44, -49,
+ -54, -51, -48, -47, -49, -50, -51, -57,
+ -58, -60, -63, -69, -70, -69, -71, -74,
+ -78, -82, -90, -95, -101, -105, -110, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -105, -101, -97, -93, -90,
+ -85, -80, -77, -72, -65, -56, -48, -37,
+ -40, -36, -34, -40, -50, -47, -38, -41,
+ -47, -38, -35, -39, -38, -43, -40, -45,
+ -50, -45, -44, -47, -50, -55, -48, -48,
+ -52, -66, -70, -76, -82, -90, -97, -105,
+ -110, -999, -999, -999, -999, -999, -999, -999}},
+ /* 707 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -108, -103, -98, -93, -86, -79, -76,
+ -83, -81, -85, -87, -89, -93, -98, -102,
+ -107, -112, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -108, -103, -98, -93, -86, -79, -71,
+ -77, -74, -77, -79, -81, -84, -85, -90,
+ -92, -93, -92, -98, -101, -108, -112, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -108, -103, -98, -93, -87, -78, -68, -65,
+ -66, -62, -65, -67, -70, -73, -75, -78,
+ -82, -82, -83, -84, -91, -93, -98, -102,
+ -106, -110, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -105, -100, -95, -90, -82, -74, -62, -57,
+ -58, -56, -51, -52, -52, -54, -54, -58,
+ -66, -59, -60, -63, -66, -69, -73, -79,
+ -83, -84, -80, -81, -81, -82, -88, -92,
+ -98, -105, -113, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -107,
+ -102, -97, -92, -84, -79, -69, -57, -47,
+ -52, -47, -44, -45, -50, -52, -42, -42,
+ -53, -43, -43, -48, -51, -56, -55, -52,
+ -57, -59, -61, -62, -67, -71, -78, -83,
+ -86, -94, -98, -103, -110, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -105, -100,
+ -95, -90, -84, -78, -70, -61, -51, -41,
+ -40, -38, -40, -46, -52, -51, -41, -40,
+ -46, -40, -38, -38, -41, -46, -41, -46,
+ -47, -43, -43, -45, -41, -45, -56, -67,
+ -68, -83, -87, -90, -95, -102, -107, -113,
+ -999, -999, -999, -999, -999, -999, -999, -999}},
+ /* 1000 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -109, -105, -101, -96, -91, -84, -77,
+ -82, -82, -85, -89, -94, -100, -106, -110,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -106, -103, -98, -92, -85, -80, -71,
+ -75, -72, -76, -80, -84, -86, -89, -93,
+ -100, -107, -113, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -107,
+ -104, -101, -97, -92, -88, -84, -80, -64,
+ -66, -63, -64, -66, -69, -73, -77, -83,
+ -83, -86, -91, -98, -104, -111, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -107,
+ -104, -101, -97, -92, -90, -84, -74, -57,
+ -58, -52, -55, -54, -50, -52, -50, -52,
+ -63, -62, -69, -76, -77, -78, -78, -79,
+ -82, -88, -94, -100, -106, -111, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -106, -102,
+ -98, -95, -90, -85, -83, -78, -70, -50,
+ -50, -41, -44, -49, -47, -50, -50, -44,
+ -55, -46, -47, -48, -48, -54, -49, -49,
+ -58, -62, -71, -81, -87, -92, -97, -102,
+ -108, -114, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -106, -102,
+ -98, -95, -90, -85, -83, -78, -70, -45,
+ -43, -41, -47, -50, -51, -50, -49, -45,
+ -47, -41, -44, -41, -39, -43, -38, -37,
+ -40, -41, -44, -50, -58, -65, -73, -79,
+ -85, -92, -97, -101, -105, -109, -113, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999}},
+ /* 1414 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -107, -100, -95, -87, -81,
+ -85, -83, -88, -93, -100, -107, -114, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -107, -101, -95, -88, -83, -76,
+ -73, -72, -79, -84, -90, -95, -100, -105,
+ -110, -115, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -104, -98, -92, -87, -81, -70,
+ -65, -62, -67, -71, -74, -80, -85, -91,
+ -95, -99, -103, -108, -111, -114, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -103, -97, -90, -85, -76, -60,
+ -56, -54, -60, -62, -61, -56, -63, -65,
+ -73, -74, -77, -75, -78, -81, -86, -87,
+ -88, -91, -94, -98, -103, -110, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -105,
+ -100, -97, -92, -86, -81, -79, -70, -57,
+ -51, -47, -51, -58, -60, -56, -53, -50,
+ -58, -52, -50, -50, -53, -55, -64, -69,
+ -71, -85, -82, -78, -81, -85, -95, -102,
+ -112, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -105,
+ -100, -97, -92, -85, -83, -79, -72, -49,
+ -40, -43, -43, -54, -56, -51, -50, -40,
+ -43, -38, -36, -35, -37, -38, -37, -44,
+ -54, -60, -57, -60, -70, -75, -84, -92,
+ -103, -112, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999}},
+ /* 2000 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -110, -102, -95, -89, -82,
+ -83, -84, -90, -92, -99, -107, -113, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -107, -101, -95, -89, -83, -72,
+ -74, -78, -85, -88, -88, -90, -92, -98,
+ -105, -111, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -109, -103, -97, -93, -87, -81, -70,
+ -70, -67, -75, -73, -76, -79, -81, -83,
+ -88, -89, -97, -103, -110, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -107, -100, -94, -88, -83, -75, -63,
+ -59, -59, -63, -66, -60, -62, -67, -67,
+ -77, -76, -81, -88, -86, -92, -96, -102,
+ -109, -116, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -105, -98, -92, -86, -81, -73, -56,
+ -52, -47, -55, -60, -58, -52, -51, -45,
+ -49, -50, -53, -54, -61, -71, -70, -69,
+ -78, -79, -87, -90, -96, -104, -112, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -103, -96, -90, -86, -78, -70, -51,
+ -42, -47, -48, -55, -54, -54, -53, -42,
+ -35, -28, -33, -38, -37, -44, -47, -49,
+ -54, -63, -68, -78, -82, -89, -94, -99,
+ -104, -109, -114, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999}},
+ /* 2828 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -110, -100, -90, -79,
+ -85, -81, -82, -82, -89, -94, -99, -103,
+ -109, -115, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -105, -97, -85, -72,
+ -74, -70, -70, -70, -76, -85, -91, -93,
+ -97, -103, -109, -115, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -112, -93, -81, -68,
+ -62, -60, -60, -57, -63, -70, -77, -82,
+ -90, -93, -98, -104, -109, -113, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -113, -100, -93, -84, -63,
+ -58, -48, -53, -54, -52, -52, -57, -64,
+ -66, -76, -83, -81, -85, -85, -90, -95,
+ -98, -101, -103, -106, -108, -111, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -105, -95, -86, -74, -53,
+ -50, -38, -43, -49, -43, -42, -39, -39,
+ -46, -52, -57, -56, -72, -69, -74, -81,
+ -87, -92, -94, -97, -99, -102, -105, -108,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -108, -99, -90, -76, -66, -45,
+ -43, -41, -44, -47, -43, -47, -40, -30,
+ -31, -31, -39, -33, -40, -41, -43, -53,
+ -59, -70, -73, -77, -79, -82, -84, -87,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999}},
+ /* 4000 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -110, -91, -76,
+ -75, -85, -93, -98, -104, -110, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -110, -91, -70,
+ -70, -75, -86, -89, -94, -98, -101, -106,
+ -110, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -110, -95, -80, -60,
+ -65, -64, -74, -83, -88, -91, -95, -99,
+ -103, -107, -110, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -110, -95, -80, -58,
+ -55, -49, -66, -68, -71, -78, -78, -80,
+ -88, -85, -89, -97, -100, -105, -110, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -110, -95, -80, -53,
+ -52, -41, -59, -59, -49, -58, -56, -63,
+ -86, -79, -90, -93, -98, -103, -107, -112,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -110, -97, -91, -73, -45,
+ -40, -33, -53, -61, -49, -54, -50, -50,
+ -60, -52, -67, -74, -81, -92, -96, -100,
+ -105, -110, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999}},
+ /* 5657 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -113, -106, -99, -92, -77,
+ -80, -88, -97, -106, -115, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -116, -109, -102, -95, -89, -74,
+ -72, -88, -87, -95, -102, -109, -116, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -116, -109, -102, -95, -89, -75,
+ -66, -74, -77, -78, -86, -87, -90, -96,
+ -105, -115, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -115, -108, -101, -94, -88, -66,
+ -56, -61, -70, -65, -78, -72, -83, -84,
+ -93, -98, -105, -110, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -110, -105, -95, -89, -82, -57,
+ -52, -52, -59, -56, -59, -58, -69, -67,
+ -88, -82, -82, -89, -94, -100, -108, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -110, -101, -96, -90, -83, -77, -54,
+ -43, -38, -50, -48, -52, -48, -42, -42,
+ -51, -52, -53, -59, -65, -71, -78, -85,
+ -95, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999}},
+ /* 8000 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -120, -105, -86, -68,
+ -78, -79, -90, -100, -110, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -120, -105, -86, -66,
+ -73, -77, -88, -96, -105, -115, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -120, -105, -92, -80, -61,
+ -64, -68, -80, -87, -92, -100, -110, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -120, -104, -91, -79, -52,
+ -60, -54, -64, -69, -77, -80, -82, -84,
+ -85, -87, -88, -90, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -118, -100, -87, -77, -49,
+ -50, -44, -58, -61, -61, -67, -65, -62,
+ -62, -62, -65, -68, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -115, -98, -84, -62, -49,
+ -44, -38, -46, -49, -49, -46, -39, -37,
+ -39, -40, -42, -43, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999}},
+ /* 11314 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -110, -88, -74,
+ -77, -82, -82, -85, -90, -94, -99, -104,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -110, -88, -66,
+ -70, -81, -80, -81, -84, -88, -91, -93,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -110, -88, -61,
+ -63, -70, -71, -74, -77, -80, -83, -85,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -110, -86, -62,
+ -63, -62, -62, -58, -52, -50, -50, -52,
+ -54, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -118, -108, -84, -53,
+ -50, -50, -50, -55, -47, -45, -40, -40,
+ -40, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -118, -100, -73, -43,
+ -37, -42, -43, -53, -38, -37, -35, -35,
+ -38, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999}},
+ /* 16000 Hz */
+ {{-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -110, -100, -91, -84, -74,
+ -80, -80, -80, -80, -80, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -110, -100, -91, -84, -74,
+ -68, -68, -68, -68, -68, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -110, -100, -86, -78, -70,
+ -60, -45, -30, -21, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -110, -100, -87, -78, -67,
+ -48, -38, -29, -21, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -110, -100, -86, -69, -56,
+ -45, -35, -33, -29, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999},
+ {-999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -110, -100, -83, -71, -48,
+ -27, -38, -37, -34, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999,
+ -999, -999, -999, -999, -999, -999, -999, -999}}
+};
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/mdct.c b/external/libvorbis-1.3.5/lib/mdct.c
new file mode 100644
index 0000000..0816331
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/mdct.c
@@ -0,0 +1,563 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: normalized modified discrete cosine transform
+ power of two length transform only [64 <= n ]
+ last mod: $Id: mdct.c 16227 2009-07-08 06:58:46Z xiphmont $
+
+ Original algorithm adapted long ago from _The use of multirate filter
+ banks for coding of high quality digital audio_, by T. Sporer,
+ K. Brandenburg and B. Edler, collection of the European Signal
+ Processing Conference (EUSIPCO), Amsterdam, June 1992, Vol.1, pp
+ 211-214
+
+ The below code implements an algorithm that no longer looks much like
+ that presented in the paper, but the basic structure remains if you
+ dig deep enough to see it.
+
+ This module DOES NOT INCLUDE code to generate/apply the window
+ function. Everybody has their own weird favorite including me... I
+ happen to like the properties of y=sin(.5PI*sin^2(x)), but others may
+ vehemently disagree.
+
+ ********************************************************************/
+
+/* this can also be run as an integer transform by uncommenting a
+ define in mdct.h; the integerization is a first pass and although
+ it's likely stable for Vorbis, the dynamic range is constrained and
+ roundoff isn't done (so it's noisy). Consider it functional, but
+ only a starting point. There's no point on a machine with an FPU */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "vorbis/codec.h"
+#include "mdct.h"
+#include "os.h"
+#include "misc.h"
+
+/* build lookups for trig functions; also pre-figure scaling and
+ some window function algebra. */
+
+void mdct_init(mdct_lookup *lookup,int n){
+ int *bitrev=_ogg_malloc(sizeof(*bitrev)*(n/4));
+ DATA_TYPE *T=_ogg_malloc(sizeof(*T)*(n+n/4));
+
+ int i;
+ int n2=n>>1;
+ int log2n=lookup->log2n=rint(log((float)n)/log(2.f));
+ lookup->n=n;
+ lookup->trig=T;
+ lookup->bitrev=bitrev;
+
+/* trig lookups... */
+
+ for(i=0;i<n/4;i++){
+ T[i*2]=FLOAT_CONV(cos((M_PI/n)*(4*i)));
+ T[i*2+1]=FLOAT_CONV(-sin((M_PI/n)*(4*i)));
+ T[n2+i*2]=FLOAT_CONV(cos((M_PI/(2*n))*(2*i+1)));
+ T[n2+i*2+1]=FLOAT_CONV(sin((M_PI/(2*n))*(2*i+1)));
+ }
+ for(i=0;i<n/8;i++){
+ T[n+i*2]=FLOAT_CONV(cos((M_PI/n)*(4*i+2))*.5);
+ T[n+i*2+1]=FLOAT_CONV(-sin((M_PI/n)*(4*i+2))*.5);
+ }
+
+ /* bitreverse lookup... */
+
+ {
+ int mask=(1<<(log2n-1))-1,i,j;
+ int msb=1<<(log2n-2);
+ for(i=0;i<n/8;i++){
+ int acc=0;
+ for(j=0;msb>>j;j++)
+ if((msb>>j)&i)acc|=1<<j;
+ bitrev[i*2]=((~acc)&mask)-1;
+ bitrev[i*2+1]=acc;
+
+ }
+ }
+ lookup->scale=FLOAT_CONV(4.f/n);
+}
+
+/* 8 point butterfly (in place, 4 register) */
+STIN void mdct_butterfly_8(DATA_TYPE *x){
+ REG_TYPE r0 = x[6] + x[2];
+ REG_TYPE r1 = x[6] - x[2];
+ REG_TYPE r2 = x[4] + x[0];
+ REG_TYPE r3 = x[4] - x[0];
+
+ x[6] = r0 + r2;
+ x[4] = r0 - r2;
+
+ r0 = x[5] - x[1];
+ r2 = x[7] - x[3];
+ x[0] = r1 + r0;
+ x[2] = r1 - r0;
+
+ r0 = x[5] + x[1];
+ r1 = x[7] + x[3];
+ x[3] = r2 + r3;
+ x[1] = r2 - r3;
+ x[7] = r1 + r0;
+ x[5] = r1 - r0;
+
+}
+
+/* 16 point butterfly (in place, 4 register) */
+STIN void mdct_butterfly_16(DATA_TYPE *x){
+ REG_TYPE r0 = x[1] - x[9];
+ REG_TYPE r1 = x[0] - x[8];
+
+ x[8] += x[0];
+ x[9] += x[1];
+ x[0] = MULT_NORM((r0 + r1) * cPI2_8);
+ x[1] = MULT_NORM((r0 - r1) * cPI2_8);
+
+ r0 = x[3] - x[11];
+ r1 = x[10] - x[2];
+ x[10] += x[2];
+ x[11] += x[3];
+ x[2] = r0;
+ x[3] = r1;
+
+ r0 = x[12] - x[4];
+ r1 = x[13] - x[5];
+ x[12] += x[4];
+ x[13] += x[5];
+ x[4] = MULT_NORM((r0 - r1) * cPI2_8);
+ x[5] = MULT_NORM((r0 + r1) * cPI2_8);
+
+ r0 = x[14] - x[6];
+ r1 = x[15] - x[7];
+ x[14] += x[6];
+ x[15] += x[7];
+ x[6] = r0;
+ x[7] = r1;
+
+ mdct_butterfly_8(x);
+ mdct_butterfly_8(x+8);
+}
+
+/* 32 point butterfly (in place, 4 register) */
+STIN void mdct_butterfly_32(DATA_TYPE *x){
+ REG_TYPE r0 = x[30] - x[14];
+ REG_TYPE r1 = x[31] - x[15];
+
+ x[30] += x[14];
+ x[31] += x[15];
+ x[14] = r0;
+ x[15] = r1;
+
+ r0 = x[28] - x[12];
+ r1 = x[29] - x[13];
+ x[28] += x[12];
+ x[29] += x[13];
+ x[12] = MULT_NORM( r0 * cPI1_8 - r1 * cPI3_8 );
+ x[13] = MULT_NORM( r0 * cPI3_8 + r1 * cPI1_8 );
+
+ r0 = x[26] - x[10];
+ r1 = x[27] - x[11];
+ x[26] += x[10];
+ x[27] += x[11];
+ x[10] = MULT_NORM(( r0 - r1 ) * cPI2_8);
+ x[11] = MULT_NORM(( r0 + r1 ) * cPI2_8);
+
+ r0 = x[24] - x[8];
+ r1 = x[25] - x[9];
+ x[24] += x[8];
+ x[25] += x[9];
+ x[8] = MULT_NORM( r0 * cPI3_8 - r1 * cPI1_8 );
+ x[9] = MULT_NORM( r1 * cPI3_8 + r0 * cPI1_8 );
+
+ r0 = x[22] - x[6];
+ r1 = x[7] - x[23];
+ x[22] += x[6];
+ x[23] += x[7];
+ x[6] = r1;
+ x[7] = r0;
+
+ r0 = x[4] - x[20];
+ r1 = x[5] - x[21];
+ x[20] += x[4];
+ x[21] += x[5];
+ x[4] = MULT_NORM( r1 * cPI1_8 + r0 * cPI3_8 );
+ x[5] = MULT_NORM( r1 * cPI3_8 - r0 * cPI1_8 );
+
+ r0 = x[2] - x[18];
+ r1 = x[3] - x[19];
+ x[18] += x[2];
+ x[19] += x[3];
+ x[2] = MULT_NORM(( r1 + r0 ) * cPI2_8);
+ x[3] = MULT_NORM(( r1 - r0 ) * cPI2_8);
+
+ r0 = x[0] - x[16];
+ r1 = x[1] - x[17];
+ x[16] += x[0];
+ x[17] += x[1];
+ x[0] = MULT_NORM( r1 * cPI3_8 + r0 * cPI1_8 );
+ x[1] = MULT_NORM( r1 * cPI1_8 - r0 * cPI3_8 );
+
+ mdct_butterfly_16(x);
+ mdct_butterfly_16(x+16);
+
+}
+
+/* N point first stage butterfly (in place, 2 register) */
+STIN void mdct_butterfly_first(DATA_TYPE *T,
+ DATA_TYPE *x,
+ int points){
+
+ DATA_TYPE *x1 = x + points - 8;
+ DATA_TYPE *x2 = x + (points>>1) - 8;
+ REG_TYPE r0;
+ REG_TYPE r1;
+
+ do{
+
+ r0 = x1[6] - x2[6];
+ r1 = x1[7] - x2[7];
+ x1[6] += x2[6];
+ x1[7] += x2[7];
+ x2[6] = MULT_NORM(r1 * T[1] + r0 * T[0]);
+ x2[7] = MULT_NORM(r1 * T[0] - r0 * T[1]);
+
+ r0 = x1[4] - x2[4];
+ r1 = x1[5] - x2[5];
+ x1[4] += x2[4];
+ x1[5] += x2[5];
+ x2[4] = MULT_NORM(r1 * T[5] + r0 * T[4]);
+ x2[5] = MULT_NORM(r1 * T[4] - r0 * T[5]);
+
+ r0 = x1[2] - x2[2];
+ r1 = x1[3] - x2[3];
+ x1[2] += x2[2];
+ x1[3] += x2[3];
+ x2[2] = MULT_NORM(r1 * T[9] + r0 * T[8]);
+ x2[3] = MULT_NORM(r1 * T[8] - r0 * T[9]);
+
+ r0 = x1[0] - x2[0];
+ r1 = x1[1] - x2[1];
+ x1[0] += x2[0];
+ x1[1] += x2[1];
+ x2[0] = MULT_NORM(r1 * T[13] + r0 * T[12]);
+ x2[1] = MULT_NORM(r1 * T[12] - r0 * T[13]);
+
+ x1-=8;
+ x2-=8;
+ T+=16;
+
+ }while(x2>=x);
+}
+
+/* N/stage point generic N stage butterfly (in place, 2 register) */
+STIN void mdct_butterfly_generic(DATA_TYPE *T,
+ DATA_TYPE *x,
+ int points,
+ int trigint){
+
+ DATA_TYPE *x1 = x + points - 8;
+ DATA_TYPE *x2 = x + (points>>1) - 8;
+ REG_TYPE r0;
+ REG_TYPE r1;
+
+ do{
+
+ r0 = x1[6] - x2[6];
+ r1 = x1[7] - x2[7];
+ x1[6] += x2[6];
+ x1[7] += x2[7];
+ x2[6] = MULT_NORM(r1 * T[1] + r0 * T[0]);
+ x2[7] = MULT_NORM(r1 * T[0] - r0 * T[1]);
+
+ T+=trigint;
+
+ r0 = x1[4] - x2[4];
+ r1 = x1[5] - x2[5];
+ x1[4] += x2[4];
+ x1[5] += x2[5];
+ x2[4] = MULT_NORM(r1 * T[1] + r0 * T[0]);
+ x2[5] = MULT_NORM(r1 * T[0] - r0 * T[1]);
+
+ T+=trigint;
+
+ r0 = x1[2] - x2[2];
+ r1 = x1[3] - x2[3];
+ x1[2] += x2[2];
+ x1[3] += x2[3];
+ x2[2] = MULT_NORM(r1 * T[1] + r0 * T[0]);
+ x2[3] = MULT_NORM(r1 * T[0] - r0 * T[1]);
+
+ T+=trigint;
+
+ r0 = x1[0] - x2[0];
+ r1 = x1[1] - x2[1];
+ x1[0] += x2[0];
+ x1[1] += x2[1];
+ x2[0] = MULT_NORM(r1 * T[1] + r0 * T[0]);
+ x2[1] = MULT_NORM(r1 * T[0] - r0 * T[1]);
+
+ T+=trigint;
+ x1-=8;
+ x2-=8;
+
+ }while(x2>=x);
+}
+
+STIN void mdct_butterflies(mdct_lookup *init,
+ DATA_TYPE *x,
+ int points){
+
+ DATA_TYPE *T=init->trig;
+ int stages=init->log2n-5;
+ int i,j;
+
+ if(--stages>0){
+ mdct_butterfly_first(T,x,points);
+ }
+
+ for(i=1;--stages>0;i++){
+ for(j=0;j<(1<<i);j++)
+ mdct_butterfly_generic(T,x+(points>>i)*j,points>>i,4<<i);
+ }
+
+ for(j=0;j<points;j+=32)
+ mdct_butterfly_32(x+j);
+
+}
+
+void mdct_clear(mdct_lookup *l){
+ if(l){
+ if(l->trig)_ogg_free(l->trig);
+ if(l->bitrev)_ogg_free(l->bitrev);
+ memset(l,0,sizeof(*l));
+ }
+}
+
+STIN void mdct_bitreverse(mdct_lookup *init,
+ DATA_TYPE *x){
+ int n = init->n;
+ int *bit = init->bitrev;
+ DATA_TYPE *w0 = x;
+ DATA_TYPE *w1 = x = w0+(n>>1);
+ DATA_TYPE *T = init->trig+n;
+
+ do{
+ DATA_TYPE *x0 = x+bit[0];
+ DATA_TYPE *x1 = x+bit[1];
+
+ REG_TYPE r0 = x0[1] - x1[1];
+ REG_TYPE r1 = x0[0] + x1[0];
+ REG_TYPE r2 = MULT_NORM(r1 * T[0] + r0 * T[1]);
+ REG_TYPE r3 = MULT_NORM(r1 * T[1] - r0 * T[0]);
+
+ w1 -= 4;
+
+ r0 = HALVE(x0[1] + x1[1]);
+ r1 = HALVE(x0[0] - x1[0]);
+
+ w0[0] = r0 + r2;
+ w1[2] = r0 - r2;
+ w0[1] = r1 + r3;
+ w1[3] = r3 - r1;
+
+ x0 = x+bit[2];
+ x1 = x+bit[3];
+
+ r0 = x0[1] - x1[1];
+ r1 = x0[0] + x1[0];
+ r2 = MULT_NORM(r1 * T[2] + r0 * T[3]);
+ r3 = MULT_NORM(r1 * T[3] - r0 * T[2]);
+
+ r0 = HALVE(x0[1] + x1[1]);
+ r1 = HALVE(x0[0] - x1[0]);
+
+ w0[2] = r0 + r2;
+ w1[0] = r0 - r2;
+ w0[3] = r1 + r3;
+ w1[1] = r3 - r1;
+
+ T += 4;
+ bit += 4;
+ w0 += 4;
+
+ }while(w0<w1);
+}
+
+void mdct_backward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out){
+ int n=init->n;
+ int n2=n>>1;
+ int n4=n>>2;
+
+ /* rotate */
+
+ DATA_TYPE *iX = in+n2-7;
+ DATA_TYPE *oX = out+n2+n4;
+ DATA_TYPE *T = init->trig+n4;
+
+ do{
+ oX -= 4;
+ oX[0] = MULT_NORM(-iX[2] * T[3] - iX[0] * T[2]);
+ oX[1] = MULT_NORM (iX[0] * T[3] - iX[2] * T[2]);
+ oX[2] = MULT_NORM(-iX[6] * T[1] - iX[4] * T[0]);
+ oX[3] = MULT_NORM (iX[4] * T[1] - iX[6] * T[0]);
+ iX -= 8;
+ T += 4;
+ }while(iX>=in);
+
+ iX = in+n2-8;
+ oX = out+n2+n4;
+ T = init->trig+n4;
+
+ do{
+ T -= 4;
+ oX[0] = MULT_NORM (iX[4] * T[3] + iX[6] * T[2]);
+ oX[1] = MULT_NORM (iX[4] * T[2] - iX[6] * T[3]);
+ oX[2] = MULT_NORM (iX[0] * T[1] + iX[2] * T[0]);
+ oX[3] = MULT_NORM (iX[0] * T[0] - iX[2] * T[1]);
+ iX -= 8;
+ oX += 4;
+ }while(iX>=in);
+
+ mdct_butterflies(init,out+n2,n2);
+ mdct_bitreverse(init,out);
+
+ /* roatate + window */
+
+ {
+ DATA_TYPE *oX1=out+n2+n4;
+ DATA_TYPE *oX2=out+n2+n4;
+ DATA_TYPE *iX =out;
+ T =init->trig+n2;
+
+ do{
+ oX1-=4;
+
+ oX1[3] = MULT_NORM (iX[0] * T[1] - iX[1] * T[0]);
+ oX2[0] = -MULT_NORM (iX[0] * T[0] + iX[1] * T[1]);
+
+ oX1[2] = MULT_NORM (iX[2] * T[3] - iX[3] * T[2]);
+ oX2[1] = -MULT_NORM (iX[2] * T[2] + iX[3] * T[3]);
+
+ oX1[1] = MULT_NORM (iX[4] * T[5] - iX[5] * T[4]);
+ oX2[2] = -MULT_NORM (iX[4] * T[4] + iX[5] * T[5]);
+
+ oX1[0] = MULT_NORM (iX[6] * T[7] - iX[7] * T[6]);
+ oX2[3] = -MULT_NORM (iX[6] * T[6] + iX[7] * T[7]);
+
+ oX2+=4;
+ iX += 8;
+ T += 8;
+ }while(iX<oX1);
+
+ iX=out+n2+n4;
+ oX1=out+n4;
+ oX2=oX1;
+
+ do{
+ oX1-=4;
+ iX-=4;
+
+ oX2[0] = -(oX1[3] = iX[3]);
+ oX2[1] = -(oX1[2] = iX[2]);
+ oX2[2] = -(oX1[1] = iX[1]);
+ oX2[3] = -(oX1[0] = iX[0]);
+
+ oX2+=4;
+ }while(oX2<iX);
+
+ iX=out+n2+n4;
+ oX1=out+n2+n4;
+ oX2=out+n2;
+ do{
+ oX1-=4;
+ oX1[0]= iX[3];
+ oX1[1]= iX[2];
+ oX1[2]= iX[1];
+ oX1[3]= iX[0];
+ iX+=4;
+ }while(oX1>oX2);
+ }
+}
+
+void mdct_forward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out){
+ int n=init->n;
+ int n2=n>>1;
+ int n4=n>>2;
+ int n8=n>>3;
+ DATA_TYPE *w=alloca(n*sizeof(*w)); /* forward needs working space */
+ DATA_TYPE *w2=w+n2;
+
+ /* rotate */
+
+ /* window + rotate + step 1 */
+
+ REG_TYPE r0;
+ REG_TYPE r1;
+ DATA_TYPE *x0=in+n2+n4;
+ DATA_TYPE *x1=x0+1;
+ DATA_TYPE *T=init->trig+n2;
+
+ int i=0;
+
+ for(i=0;i<n8;i+=2){
+ x0 -=4;
+ T-=2;
+ r0= x0[2] + x1[0];
+ r1= x0[0] + x1[2];
+ w2[i]= MULT_NORM(r1*T[1] + r0*T[0]);
+ w2[i+1]= MULT_NORM(r1*T[0] - r0*T[1]);
+ x1 +=4;
+ }
+
+ x1=in+1;
+
+ for(;i<n2-n8;i+=2){
+ T-=2;
+ x0 -=4;
+ r0= x0[2] - x1[0];
+ r1= x0[0] - x1[2];
+ w2[i]= MULT_NORM(r1*T[1] + r0*T[0]);
+ w2[i+1]= MULT_NORM(r1*T[0] - r0*T[1]);
+ x1 +=4;
+ }
+
+ x0=in+n;
+
+ for(;i<n2;i+=2){
+ T-=2;
+ x0 -=4;
+ r0= -x0[2] - x1[0];
+ r1= -x0[0] - x1[2];
+ w2[i]= MULT_NORM(r1*T[1] + r0*T[0]);
+ w2[i+1]= MULT_NORM(r1*T[0] - r0*T[1]);
+ x1 +=4;
+ }
+
+
+ mdct_butterflies(init,w+n2,n2);
+ mdct_bitreverse(init,w);
+
+ /* roatate + window */
+
+ T=init->trig+n2;
+ x0=out+n2;
+
+ for(i=0;i<n4;i++){
+ x0--;
+ out[i] =MULT_NORM((w[0]*T[0]+w[1]*T[1])*init->scale);
+ x0[0] =MULT_NORM((w[0]*T[1]-w[1]*T[0])*init->scale);
+ w+=2;
+ T+=2;
+ }
+}
diff --git a/external/libvorbis-1.3.5/lib/mdct.h b/external/libvorbis-1.3.5/lib/mdct.h
new file mode 100644
index 0000000..3ed9433
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/mdct.h
@@ -0,0 +1,71 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: modified discrete cosine transform prototypes
+ last mod: $Id: mdct.h 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _OGG_mdct_H_
+#define _OGG_mdct_H_
+
+#include "vorbis/codec.h"
+
+
+
+
+
+/*#define MDCT_INTEGERIZED <- be warned there could be some hurt left here*/
+#ifdef MDCT_INTEGERIZED
+
+#define DATA_TYPE int
+#define REG_TYPE register int
+#define TRIGBITS 14
+#define cPI3_8 6270
+#define cPI2_8 11585
+#define cPI1_8 15137
+
+#define FLOAT_CONV(x) ((int)((x)*(1<<TRIGBITS)+.5))
+#define MULT_NORM(x) ((x)>>TRIGBITS)
+#define HALVE(x) ((x)>>1)
+
+#else
+
+#define DATA_TYPE float
+#define REG_TYPE float
+#define cPI3_8 .38268343236508977175F
+#define cPI2_8 .70710678118654752441F
+#define cPI1_8 .92387953251128675613F
+
+#define FLOAT_CONV(x) (x)
+#define MULT_NORM(x) (x)
+#define HALVE(x) ((x)*.5f)
+
+#endif
+
+
+typedef struct {
+ int n;
+ int log2n;
+
+ DATA_TYPE *trig;
+ int *bitrev;
+
+ DATA_TYPE scale;
+} mdct_lookup;
+
+extern void mdct_init(mdct_lookup *lookup,int n);
+extern void mdct_clear(mdct_lookup *l);
+extern void mdct_forward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out);
+extern void mdct_backward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out);
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/misc.h b/external/libvorbis-1.3.5/lib/misc.h
new file mode 100644
index 0000000..73b4519
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/misc.h
@@ -0,0 +1,58 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: miscellaneous prototypes
+ last mod: $Id: misc.h 19457 2015-03-03 00:15:29Z giles $
+
+ ********************************************************************/
+
+#ifndef _V_RANDOM_H_
+#define _V_RANDOM_H_
+#include "vorbis/codec.h"
+
+extern void *_vorbis_block_alloc(vorbis_block *vb,long bytes);
+extern void _vorbis_block_ripcord(vorbis_block *vb);
+extern int ov_ilog(ogg_uint32_t v);
+
+#ifdef ANALYSIS
+extern int analysis_noisy;
+extern void _analysis_output(char *base,int i,float *v,int n,int bark,int dB,
+ ogg_int64_t off);
+extern void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,
+ ogg_int64_t off);
+#endif
+
+#ifdef DEBUG_MALLOC
+
+#define _VDBG_GRAPHFILE "malloc.m"
+#undef _VDBG_GRAPHFILE
+extern void *_VDBG_malloc(void *ptr,long bytes,char *file,long line);
+extern void _VDBG_free(void *ptr,char *file,long line);
+
+#ifndef MISC_C
+#undef _ogg_malloc
+#undef _ogg_calloc
+#undef _ogg_realloc
+#undef _ogg_free
+
+#define _ogg_malloc(x) _VDBG_malloc(NULL,(x),__FILE__,__LINE__)
+#define _ogg_calloc(x,y) _VDBG_malloc(NULL,(x)*(y),__FILE__,__LINE__)
+#define _ogg_realloc(x,y) _VDBG_malloc((x),(y),__FILE__,__LINE__)
+#define _ogg_free(x) _VDBG_free((x),__FILE__,__LINE__)
+#endif
+#endif
+
+#endif
+
+
+
+
diff --git a/external/libvorbis-1.3.5/lib/modes/floor_all.h b/external/libvorbis-1.3.5/lib/modes/floor_all.h
new file mode 100644
index 0000000..4292be3
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/floor_all.h
@@ -0,0 +1,260 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: key floor settings
+ last mod: $Id: floor_all.h 17050 2010-03-26 01:34:42Z xiphmont $
+
+ ********************************************************************/
+
+#include "vorbis/codec.h"
+#include "backends.h"
+#include "books/floor/floor_books.h"
+
+static const static_codebook*const _floor_128x4_books[]={
+ &_huff_book_line_128x4_class0,
+ &_huff_book_line_128x4_0sub0,
+ &_huff_book_line_128x4_0sub1,
+ &_huff_book_line_128x4_0sub2,
+ &_huff_book_line_128x4_0sub3,
+};
+static const static_codebook*const _floor_256x4_books[]={
+ &_huff_book_line_256x4_class0,
+ &_huff_book_line_256x4_0sub0,
+ &_huff_book_line_256x4_0sub1,
+ &_huff_book_line_256x4_0sub2,
+ &_huff_book_line_256x4_0sub3,
+};
+static const static_codebook*const _floor_128x7_books[]={
+ &_huff_book_line_128x7_class0,
+ &_huff_book_line_128x7_class1,
+
+ &_huff_book_line_128x7_0sub1,
+ &_huff_book_line_128x7_0sub2,
+ &_huff_book_line_128x7_0sub3,
+ &_huff_book_line_128x7_1sub1,
+ &_huff_book_line_128x7_1sub2,
+ &_huff_book_line_128x7_1sub3,
+};
+static const static_codebook*const _floor_256x7_books[]={
+ &_huff_book_line_256x7_class0,
+ &_huff_book_line_256x7_class1,
+
+ &_huff_book_line_256x7_0sub1,
+ &_huff_book_line_256x7_0sub2,
+ &_huff_book_line_256x7_0sub3,
+ &_huff_book_line_256x7_1sub1,
+ &_huff_book_line_256x7_1sub2,
+ &_huff_book_line_256x7_1sub3,
+};
+static const static_codebook*const _floor_128x11_books[]={
+ &_huff_book_line_128x11_class1,
+ &_huff_book_line_128x11_class2,
+ &_huff_book_line_128x11_class3,
+
+ &_huff_book_line_128x11_0sub0,
+ &_huff_book_line_128x11_1sub0,
+ &_huff_book_line_128x11_1sub1,
+ &_huff_book_line_128x11_2sub1,
+ &_huff_book_line_128x11_2sub2,
+ &_huff_book_line_128x11_2sub3,
+ &_huff_book_line_128x11_3sub1,
+ &_huff_book_line_128x11_3sub2,
+ &_huff_book_line_128x11_3sub3,
+};
+static const static_codebook*const _floor_128x17_books[]={
+ &_huff_book_line_128x17_class1,
+ &_huff_book_line_128x17_class2,
+ &_huff_book_line_128x17_class3,
+
+ &_huff_book_line_128x17_0sub0,
+ &_huff_book_line_128x17_1sub0,
+ &_huff_book_line_128x17_1sub1,
+ &_huff_book_line_128x17_2sub1,
+ &_huff_book_line_128x17_2sub2,
+ &_huff_book_line_128x17_2sub3,
+ &_huff_book_line_128x17_3sub1,
+ &_huff_book_line_128x17_3sub2,
+ &_huff_book_line_128x17_3sub3,
+};
+static const static_codebook*const _floor_256x4low_books[]={
+ &_huff_book_line_256x4low_class0,
+ &_huff_book_line_256x4low_0sub0,
+ &_huff_book_line_256x4low_0sub1,
+ &_huff_book_line_256x4low_0sub2,
+ &_huff_book_line_256x4low_0sub3,
+};
+static const static_codebook*const _floor_1024x27_books[]={
+ &_huff_book_line_1024x27_class1,
+ &_huff_book_line_1024x27_class2,
+ &_huff_book_line_1024x27_class3,
+ &_huff_book_line_1024x27_class4,
+
+ &_huff_book_line_1024x27_0sub0,
+ &_huff_book_line_1024x27_1sub0,
+ &_huff_book_line_1024x27_1sub1,
+ &_huff_book_line_1024x27_2sub0,
+ &_huff_book_line_1024x27_2sub1,
+ &_huff_book_line_1024x27_3sub1,
+ &_huff_book_line_1024x27_3sub2,
+ &_huff_book_line_1024x27_3sub3,
+ &_huff_book_line_1024x27_4sub1,
+ &_huff_book_line_1024x27_4sub2,
+ &_huff_book_line_1024x27_4sub3,
+};
+static const static_codebook*const _floor_2048x27_books[]={
+ &_huff_book_line_2048x27_class1,
+ &_huff_book_line_2048x27_class2,
+ &_huff_book_line_2048x27_class3,
+ &_huff_book_line_2048x27_class4,
+
+ &_huff_book_line_2048x27_0sub0,
+ &_huff_book_line_2048x27_1sub0,
+ &_huff_book_line_2048x27_1sub1,
+ &_huff_book_line_2048x27_2sub0,
+ &_huff_book_line_2048x27_2sub1,
+ &_huff_book_line_2048x27_3sub1,
+ &_huff_book_line_2048x27_3sub2,
+ &_huff_book_line_2048x27_3sub3,
+ &_huff_book_line_2048x27_4sub1,
+ &_huff_book_line_2048x27_4sub2,
+ &_huff_book_line_2048x27_4sub3,
+};
+
+static const static_codebook*const _floor_512x17_books[]={
+ &_huff_book_line_512x17_class1,
+ &_huff_book_line_512x17_class2,
+ &_huff_book_line_512x17_class3,
+
+ &_huff_book_line_512x17_0sub0,
+ &_huff_book_line_512x17_1sub0,
+ &_huff_book_line_512x17_1sub1,
+ &_huff_book_line_512x17_2sub1,
+ &_huff_book_line_512x17_2sub2,
+ &_huff_book_line_512x17_2sub3,
+ &_huff_book_line_512x17_3sub1,
+ &_huff_book_line_512x17_3sub2,
+ &_huff_book_line_512x17_3sub3,
+};
+
+static const static_codebook*const _floor_Xx0_books[]={
+ 0
+};
+
+static const static_codebook*const *const _floor_books[11]={
+ _floor_128x4_books,
+ _floor_256x4_books,
+ _floor_128x7_books,
+ _floor_256x7_books,
+ _floor_128x11_books,
+ _floor_128x17_books,
+ _floor_256x4low_books,
+ _floor_1024x27_books,
+ _floor_2048x27_books,
+ _floor_512x17_books,
+ _floor_Xx0_books,
+};
+
+static const vorbis_info_floor1 _floor[11]={
+ /* 0: 128 x 4 */
+ {
+ 1,{0},{4},{2},{0},
+ {{1,2,3,4}},
+ 4,{0,128, 33,8,16,70},
+
+ 60,30,500, 1.,18., 128
+ },
+ /* 1: 256 x 4 */
+ {
+ 1,{0},{4},{2},{0},
+ {{1,2,3,4}},
+ 4,{0,256, 66,16,32,140},
+
+ 60,30,500, 1.,18., 256
+ },
+ /* 2: 128 x 7 */
+ {
+ 2,{0,1},{3,4},{2,2},{0,1},
+ {{-1,2,3,4},{-1,5,6,7}},
+ 4,{0,128, 14,4,58, 2,8,28,90},
+
+ 60,30,500, 1.,18., 128
+ },
+ /* 3: 256 x 7 */
+ {
+ 2,{0,1},{3,4},{2,2},{0,1},
+ {{-1,2,3,4},{-1,5,6,7}},
+ 4,{0,256, 28,8,116, 4,16,56,180},
+
+ 60,30,500, 1.,18., 256
+ },
+ /* 4: 128 x 11 */
+ {
+ 4,{0,1,2,3},{2,3,3,3},{0,1,2,2},{-1,0,1,2},
+ {{3},{4,5},{-1,6,7,8},{-1,9,10,11}},
+
+ 2,{0,128, 8,33, 4,16,70, 2,6,12, 23,46,90},
+
+ 60,30,500, 1,18., 128
+ },
+ /* 5: 128 x 17 */
+ {
+ 6,{0,1,1,2,3,3},{2,3,3,3},{0,1,2,2},{-1,0,1,2},
+ {{3},{4,5},{-1,6,7,8},{-1,9,10,11}},
+ 2,{0,128, 12,46, 4,8,16, 23,33,70, 2,6,10, 14,19,28, 39,58,90},
+
+ 60,30,500, 1,18., 128
+ },
+ /* 6: 256 x 4 (low bitrate version) */
+ {
+ 1,{0},{4},{2},{0},
+ {{1,2,3,4}},
+ 4,{0,256, 66,16,32,140},
+
+ 60,30,500, 1.,18., 256
+ },
+ /* 7: 1024 x 27 */
+ {
+ 8,{0,1,2,2,3,3,4,4},{3,4,3,4,3},{0,1,1,2,2},{-1,0,1,2,3},
+ {{4},{5,6},{7,8},{-1,9,10,11},{-1,12,13,14}},
+ 2,{0,1024, 93,23,372, 6,46,186,750, 14,33,65, 130,260,556,
+ 3,10,18,28, 39,55,79,111, 158,220,312, 464,650,850},
+
+ 60,30,500, 3,18., 1024
+ },
+ /* 8: 2048 x 27 */
+ {
+ 8,{0,1,2,2,3,3,4,4},{3,4,3,4,3},{0,1,1,2,2},{-1,0,1,2,3},
+ {{4},{5,6},{7,8},{-1,9,10,11},{-1,12,13,14}},
+ 2,{0,2048, 186,46,744, 12,92,372,1500, 28,66,130, 260,520,1112,
+ 6,20,36,56, 78,110,158,222, 316,440,624, 928,1300,1700},
+
+ 60,30,500, 3,18., 2048
+ },
+ /* 9: 512 x 17 */
+ {
+ 6,{0,1,1,2,3,3},{2,3,3,3},{0,1,2,2},{-1,0,1,2},
+ {{3},{4,5},{-1,6,7,8},{-1,9,10,11}},
+ 2,{0,512, 46,186, 16,33,65, 93,130,278,
+ 7,23,39, 55,79,110, 156,232,360},
+
+ 60,30,500, 1,18., 512
+ },
+
+ /* 10: X x 0 (LFE floor; edge posts only) */
+ {
+ 0,{0}, {0},{0},{-1},
+ {{-1}},
+ 2,{0,12},
+ 60,30,500, 1.,18., 10
+ },
+
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/psych_11.h b/external/libvorbis-1.3.5/lib/modes/psych_11.h
new file mode 100644
index 0000000..844a8ed
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/psych_11.h
@@ -0,0 +1,51 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: 11kHz settings
+ last mod: $Id: psych_11.h 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+static const double _psy_lowpass_11[3]={4.5,5.5,30.,};
+
+static const att3 _psy_tone_masteratt_11[3]={
+ {{ 30, 25, 12}, 0, 0}, /* 0 */
+ {{ 30, 25, 12}, 0, 0}, /* 0 */
+ {{ 20, 0, -14}, 0, 0}, /* 0 */
+};
+
+static const vp_adjblock _vp_tonemask_adj_11[3]={
+ /* adjust for mode zero */
+ /* 63 125 250 500 1 2 4 8 16 */
+ {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0,10, 2, 0,99,99,99}}, /* 0 */
+ {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0, 5, 0, 0,99,99,99}}, /* 1 */
+ {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0, 0, 0, 0,99,99,99}}, /* 2 */
+};
+
+
+static const noise3 _psy_noisebias_11[3]={
+ /* 63 125 250 500 1k 2k 4k 8k 16k*/
+ {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 10, 10, 12, 12, 12, 99, 99, 99},
+ {-15,-15,-15,-15,-10,-10, -5, 0, 0, 4, 4, 5, 5, 10, 99, 99, 99},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, 99, 99, 99}}},
+
+ {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 10, 10, 12, 12, 12, 99, 99, 99},
+ {-15,-15,-15,-15,-10,-10, -5, -5, -5, 0, 0, 0, 0, 0, 99, 99, 99},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, 99, 99, 99}}},
+
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 99, 99, 99},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-12,-12,-10,-10,-10,-10, 99, 99, 99},
+ {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24, 99, 99, 99}}},
+};
+
+static const double _noise_thresh_11[3]={ .3,.5,.5 };
+
diff --git a/external/libvorbis-1.3.5/lib/modes/psych_16.h b/external/libvorbis-1.3.5/lib/modes/psych_16.h
new file mode 100644
index 0000000..1c10b39
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/psych_16.h
@@ -0,0 +1,133 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: 16kHz settings
+ last mod: $Id: psych_16.h 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+/* stereo mode by base quality level */
+static const adj_stereo _psy_stereo_modes_16[4]={
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 */
+ {{ 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
+ { 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ {{ 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
+ { 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ {{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
+ { 5, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ {{ 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},
+ { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+};
+
+static const double _psy_lowpass_16[4]={6.5,8,30.,99.};
+
+static const att3 _psy_tone_masteratt_16[4]={
+ {{ 30, 25, 12}, 0, 0}, /* 0 */
+ {{ 25, 22, 12}, 0, 0}, /* 0 */
+ {{ 20, 12, 0}, 0, 0}, /* 0 */
+ {{ 15, 0, -14}, 0, 0}, /* 0 */
+};
+
+static const vp_adjblock _vp_tonemask_adj_16[4]={
+ /* adjust for mode zero */
+ /* 63 125 250 500 1 2 4 8 16 */
+ {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0,10, 0, 0, 0, 0, 0}}, /* 0 */
+ {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0,10, 0, 0, 0, 0, 0}}, /* 1 */
+ {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 2 */
+ {{-30,-30,-30,-30,-30,-26,-20,-10, -5, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 2 */
+};
+
+
+static const noise3 _psy_noisebias_16_short[4]={
+ /* 63 125 250 500 1k 2k 4k 8k 16k*/
+ {{{-15,-15,-15,-15,-15,-10,-10,-5, 4, 10, 10, 10, 10, 12, 12, 14, 20},
+ {-15,-15,-15,-15,-15,-10,-10, -5, 0, 0, 4, 5, 5, 6, 8, 8, 15},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -6, -6}}},
+
+ {{{-15,-15,-15,-15,-15,-10,-10,-5, 4, 6, 6, 6, 6, 8, 10, 12, 20},
+ {-15,-15,-15,-15,-15,-15,-15,-10, -5, -5, -5, 4, 5, 6, 8, 8, 15},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10,-10,-10,-10,-10,-10,-10,-10,-10}}},
+
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 5, 8, 12},
+ {-20,-20,-20,-20,-16,-12,-20,-14,-10,-10, -8, 0, 0, 0, 0, 2, 5},
+ {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}},
+
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, -5, -5, -5, -5, -5, 0, 0, 0, 6},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-12,-12,-10,-10,-10,-10,-10,-10, -6},
+ {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}},
+};
+
+static const noise3 _psy_noisebias_16_impulse[4]={
+ /* 63 125 250 500 1k 2k 4k 8k 16k*/
+ {{{-15,-15,-15,-15,-15,-10,-10,-5, 4, 10, 10, 10, 10, 12, 12, 14, 20},
+ {-15,-15,-15,-15,-15,-10,-10, -5, 0, 0, 4, 5, 5, 6, 8, 8, 15},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -6, -6}}},
+
+ {{{-15,-15,-15,-15,-15,-10,-10,-5, 4, 4, 4, 4, 5, 5, 6, 8, 15},
+ {-15,-15,-15,-15,-15,-15,-15,-10, -5, -5, -5, 0, 0, 0, 0, 4, 10},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10,-10,-10,-10,-10,-10,-10,-10,-10}}},
+
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 4, 10},
+ {-20,-20,-20,-20,-16,-12,-20,-14,-10,-10,-10,-10,-10,-10,-10, -7, -5},
+ {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}},
+
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, -5, -5, -5, -5, -5, 0, 0, 0, 6},
+ {-30,-30,-30,-30,-26,-22,-20,-18,-18,-18,-20,-20,-20,-20,-20,-20,-16},
+ {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}},
+};
+
+static const noise3 _psy_noisebias_16[4]={
+ /* 63 125 250 500 1k 2k 4k 8k 16k*/
+ {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 6, 8, 8, 10, 10, 10, 14, 20},
+ {-10,-10,-10,-10,-10, -5, -2, -2, 0, 0, 0, 4, 5, 6, 8, 8, 15},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -6, -6}}},
+
+ {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 6, 6, 6, 6, 8, 10, 12, 20},
+ {-15,-15,-15,-15,-15,-10, -5, -5, 0, 0, 0, 4, 5, 6, 8, 8, 15},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -6, -6}}},
+
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 5, 8, 12},
+ {-20,-20,-20,-20,-16,-12,-20,-10, -5, -5, 0, 0, 0, 0, 0, 2, 5},
+ {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}},
+
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, -5, -5, -5, -5, -5, 0, 0, 0, 6},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-12,-12,-10,-10,-10,-10,-10,-10, -6},
+ {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}},
+};
+
+static const noiseguard _psy_noiseguards_16[4]={
+ {10,10,-1},
+ {10,10,-1},
+ {20,20,-1},
+ {20,20,-1},
+};
+
+static const double _noise_thresh_16[4]={ .3,.5,.5,.5 };
+
+static const int _noise_start_16[3]={ 256,256,9999 };
+static const int _noise_part_16[4]={ 8,8,8,8 };
+
+static const int _psy_ath_floater_16[4]={
+ -100,-100,-100,-105,
+};
+
+static const int _psy_ath_abs_16[4]={
+ -130,-130,-130,-140,
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/psych_44.h b/external/libvorbis-1.3.5/lib/modes/psych_44.h
new file mode 100644
index 0000000..f05c032
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/psych_44.h
@@ -0,0 +1,642 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: key psychoacoustic settings for 44.1/48kHz
+ last mod: $Id: psych_44.h 16962 2010-03-11 07:30:34Z xiphmont $
+
+ ********************************************************************/
+
+
+/* preecho trigger settings *****************************************/
+
+static const vorbis_info_psy_global _psy_global_44[5]={
+
+ {8, /* lines per eighth octave */
+ {20.f,14.f,12.f,12.f,12.f,12.f,12.f},
+ {-60.f,-30.f,-40.f,-40.f,-40.f,-40.f,-40.f}, 2,-75.f,
+ -6.f,
+ {99.},{{99.},{99.}},{0},{0},{{0.},{0.}}
+ },
+ {8, /* lines per eighth octave */
+ {14.f,10.f,10.f,10.f,10.f,10.f,10.f},
+ {-40.f,-30.f,-25.f,-25.f,-25.f,-25.f,-25.f}, 2,-80.f,
+ -6.f,
+ {99.},{{99.},{99.}},{0},{0},{{0.},{0.}}
+ },
+ {8, /* lines per eighth octave */
+ {12.f,10.f,10.f,10.f,10.f,10.f,10.f},
+ {-20.f,-20.f,-15.f,-15.f,-15.f,-15.f,-15.f}, 0,-80.f,
+ -6.f,
+ {99.},{{99.},{99.}},{0},{0},{{0.},{0.}}
+ },
+ {8, /* lines per eighth octave */
+ {10.f,8.f,8.f,8.f,8.f,8.f,8.f},
+ {-20.f,-15.f,-12.f,-12.f,-12.f,-12.f,-12.f}, 0,-80.f,
+ -6.f,
+ {99.},{{99.},{99.}},{0},{0},{{0.},{0.}}
+ },
+ {8, /* lines per eighth octave */
+ {10.f,6.f,6.f,6.f,6.f,6.f,6.f},
+ {-15.f,-15.f,-12.f,-12.f,-12.f,-12.f,-12.f}, 0,-85.f,
+ -6.f,
+ {99.},{{99.},{99.}},{0},{0},{{0.},{0.}}
+ },
+};
+
+/* noise compander lookups * low, mid, high quality ****************/
+static const compandblock _psy_compand_44[6]={
+ /* sub-mode Z short */
+ {{
+ 0, 1, 2, 3, 4, 5, 6, 7, /* 7dB */
+ 8, 9,10,11,12,13,14, 15, /* 15dB */
+ 16,17,18,19,20,21,22, 23, /* 23dB */
+ 24,25,26,27,28,29,30, 31, /* 31dB */
+ 32,33,34,35,36,37,38, 39, /* 39dB */
+ }},
+ /* mode_Z nominal short */
+ {{
+ 0, 1, 2, 3, 4, 5, 6, 6, /* 7dB */
+ 7, 7, 7, 7, 6, 6, 6, 7, /* 15dB */
+ 7, 8, 9,10,11,12,13, 14, /* 23dB */
+ 15,16,17,17,17,18,18, 19, /* 31dB */
+ 19,19,20,21,22,23,24, 25, /* 39dB */
+ }},
+ /* mode A short */
+ {{
+ 0, 1, 2, 3, 4, 5, 5, 5, /* 7dB */
+ 6, 6, 6, 5, 4, 4, 4, 4, /* 15dB */
+ 4, 4, 5, 5, 5, 6, 6, 6, /* 23dB */
+ 7, 7, 7, 8, 8, 8, 9, 10, /* 31dB */
+ 11,12,13,14,15,16,17, 18, /* 39dB */
+ }},
+ /* sub-mode Z long */
+ {{
+ 0, 1, 2, 3, 4, 5, 6, 7, /* 7dB */
+ 8, 9,10,11,12,13,14, 15, /* 15dB */
+ 16,17,18,19,20,21,22, 23, /* 23dB */
+ 24,25,26,27,28,29,30, 31, /* 31dB */
+ 32,33,34,35,36,37,38, 39, /* 39dB */
+ }},
+ /* mode_Z nominal long */
+ {{
+ 0, 1, 2, 3, 4, 5, 6, 7, /* 7dB */
+ 8, 9,10,11,12,12,13, 13, /* 15dB */
+ 13,14,14,14,15,15,15, 15, /* 23dB */
+ 16,16,17,17,17,18,18, 19, /* 31dB */
+ 19,19,20,21,22,23,24, 25, /* 39dB */
+ }},
+ /* mode A long */
+ {{
+ 0, 1, 2, 3, 4, 5, 6, 7, /* 7dB */
+ 8, 8, 7, 6, 5, 4, 4, 4, /* 15dB */
+ 4, 4, 5, 5, 5, 6, 6, 6, /* 23dB */
+ 7, 7, 7, 8, 8, 8, 9, 10, /* 31dB */
+ 11,12,13,14,15,16,17, 18, /* 39dB */
+ }}
+};
+
+/* tonal masking curve level adjustments *************************/
+
+static const vp_adjblock _vp_tonemask_adj_longblock[12]={
+
+ /* 63 125 250 500 1 2 4 8 16 */
+
+ {{ -3, -8,-13,-15,-10,-10,-10,-10,-10,-10,-10, 0, 0, 0, 0, 0, 0}}, /* -1 */
+
+/* {{-15,-15,-15,-15,-10, -8, -4, -2, 0, 0, 0, 10, 0, 0, 0, 0, 0}}, 0 */
+ {{ -4,-10,-14,-16,-15,-14,-13,-12,-12,-12,-11, -1, -1, -1, -1, -1, 0}}, /* 0 */
+
+/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 5, 0, 0, 0, 0, 0}}, 1 */
+ {{ -6,-12,-14,-16,-15,-15,-14,-13,-13,-12,-12, -2, -2, -1, -1, -1, 0}}, /* 1 */
+
+/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 2 */
+ {{-12,-13,-14,-16,-16,-16,-15,-14,-13,-12,-12, -6, -3, -1, -1, -1, 0}}, /* 2 */
+
+/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 3 */
+ {{-15,-15,-15,-16,-16,-16,-16,-14,-13,-13,-13,-10, -4, -2, -1, -1, 0}}, /* 3 */
+
+/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, *//* 4 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-13,-11, -7 -3, -1, -1 , 0}}, /* 4 */
+
+/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 5 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-13,-11, -7 -3, -1, -1 , 0}}, /* 5 */
+
+/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 6 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -8, -4, -2, -2, 0}}, /* 6 */
+
+/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 7 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 7 */
+
+/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 8 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 8 */
+
+/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 9 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 9 */
+
+/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 10 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 10 */
+};
+
+static const vp_adjblock _vp_tonemask_adj_otherblock[12]={
+ /* 63 125 250 500 1 2 4 8 16 */
+
+ {{ -3, -8,-13,-15,-10,-10, -9, -9, -9, -9, -9, 1, 1, 1, 1, 1, 1}}, /* -1 */
+
+/* {{-20,-20,-20,-20,-14,-12,-10, -8, -4, 0, 0, 10, 0, 0, 0, 0, 0}}, 0 */
+ {{ -4,-10,-14,-16,-14,-13,-12,-12,-11,-11,-10, 0, 0, 0, 0, 0, 0}}, /* 0 */
+
+/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 5, 0, 0, 0, 0, 0}}, 1 */
+ {{ -6,-12,-14,-16,-15,-15,-14,-13,-13,-12,-12, -2, -2, -1, 0, 0, 0}}, /* 1 */
+
+/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 2 */
+ {{-12,-13,-14,-16,-16,-16,-15,-14,-13,-12,-12, -5, -2, -1, 0, 0, 0}}, /* 2 */
+
+/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 3 */
+ {{-15,-15,-15,-16,-16,-16,-16,-14,-13,-13,-13,-10, -4, -2, 0, 0, 0}}, /* 3 */
+
+/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 4 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-13,-11, -7 -3, -1, -1 , 0}}, /* 4 */
+
+/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 5 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-13,-11, -7 -3, -1, -1 , 0}}, /* 5 */
+
+/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 6 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -8, -4, -2, -2, 0}}, /* 6 */
+
+/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 7 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 7 */
+
+/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 8 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 8 */
+
+/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 9 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 9 */
+
+/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 10 */
+ {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 10 */
+};
+
+/* noise bias (transition block) */
+static const noise3 _psy_noisebias_trans[12]={
+ /* 63 125 250 500 1k 2k 4k 8k 16k*/
+ /* -1 */
+ {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 8, 8, 8, 8, 10, 12, 14, 20},
+ {-30,-30,-30,-30,-26,-20,-16, -8, -6, -6, -2, 2, 2, 3, 6, 6, 15},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -4, -2}}},
+ /* 0
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 5, 8, 10},
+ {-30,-30,-30,-30,-26,-22,-20,-14, -8, -4, 0, 0, 0, 0, 2, 4, 10},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -6, -4, -4, -4, -2}}},*/
+ {{{-15,-15,-15,-15,-15,-12, -6, -4, 0, 2, 4, 4, 5, 5, 5, 8, 10},
+ {-30,-30,-30,-30,-26,-22,-20,-14, -8, -4, 0, 0, 0, 0, 2, 3, 6},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -6, -4, -4, -4, -2}}},
+ /* 1
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 5, 8, 10},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -2, -2, -2, -2, 0, 2, 8},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -6, -6, -6, -4}}},*/
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 5, 8, 10},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -2, -2, -2, -2, 0, 1, 4},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -6, -6, -6, -4}}},
+ /* 2
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 2, 2, 4, 4, 5, 6, 10},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -2, -2, -2, -2, 0, 2, 6},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}}, */
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 2, 2, 4, 4, 5, 6, 10},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -3, -3, -3, -2, -1, 0, 3},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -7, -4}}},
+ /* 3
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 2, 2, 4, 4, 4, 5, 8},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -3, -3, -3, -3, -1, 1, 6},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},*/
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 2, 2, 4, 4, 4, 5, 8},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -3, -3, -3, -3, -2, 0, 2},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},
+ /* 4
+ {{{-20,-20,-20,-20,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -3, -3, -3, -3, -1, 1, 5},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},*/
+ {{{-20,-20,-20,-20,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -3, -3, -3, -3, -2, -1, 1},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},
+ /* 5
+ {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-32,-32,-32,-32,-28,-24,-22,-16,-12, -6, -4, -4, -4, -4, -2, -1, 2},
+ {-34,-34,-34,-34,-30,-24,-24,-18,-14,-12,-12,-12,-12,-10,-10, -9, -5}}}, */
+ {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-32,-32,-32,-32,-28,-24,-22,-16,-12, -6, -4, -4, -4, -4, -3, -1, 0},
+ {-34,-34,-34,-34,-30,-24,-24,-18,-14,-12,-12,-12,-12,-10,-10, -9, -5}}},
+ /* 6
+ {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-32,-32,-32,-32,-28,-24,-24,-18,-14, -8, -6, -6, -6, -6, -4, -2, 1},
+ {-34,-34,-34,-34,-30,-26,-24,-18,-17,-15,-15,-15,-15,-13,-13,-12, -8}}},*/
+ {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-32,-32,-32,-32,-28,-24,-24,-18,-14, -8, -6, -6, -6, -6, -5, -2, 0},
+ {-34,-34,-34,-34,-30,-26,-26,-24,-22,-19,-19,-19,-19,-18,-17,-16,-12}}},
+ /* 7
+ {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-32,-32,-32,-32,-28,-24,-24,-18,-14,-12,-10, -8, -8, -8, -6, -4, 0},
+ {-34,-34,-34,-34,-30,-26,-26,-24,-22,-19,-19,-19,-19,-18,-17,-16,-12}}},*/
+ {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-32,-32,-32,-32,-28,-24,-24,-24,-18,-14,-12,-10,-10,-10, -8, -6, -2},
+ {-34,-34,-34,-34,-30,-26,-26,-26,-24,-24,-24,-24,-24,-24,-24,-20,-16}}},
+ /* 8
+ {{{-24,-24,-24,-24,-22,-20,-15,-10, -8, -2, 0, 0, 0, 1, 2, 3, 7},
+ {-36,-36,-36,-36,-30,-30,-30,-24,-18,-14,-12,-10,-10,-10, -8, -6, -2},
+ {-36,-36,-36,-36,-34,-30,-28,-26,-24,-24,-24,-24,-24,-24,-24,-20,-16}}},*/
+ {{{-24,-24,-24,-24,-22,-20,-15,-10, -8, -2, 0, 0, 0, 1, 2, 3, 7},
+ {-36,-36,-36,-36,-30,-30,-30,-24,-20,-16,-16,-16,-16,-14,-12,-10, -7},
+ {-36,-36,-36,-36,-34,-30,-28,-26,-24,-30,-30,-30,-30,-30,-30,-24,-20}}},
+ /* 9
+ {{{-28,-28,-28,-28,-28,-28,-28,-20,-14, -8, -4, -4, -4, -4, -4, -2, 2},
+ {-36,-36,-36,-36,-34,-32,-32,-28,-20,-16,-16,-16,-16,-14,-12,-10, -7},
+ {-40,-40,-40,-40,-40,-40,-40,-32,-30,-30,-30,-30,-30,-30,-30,-24,-20}}},*/
+ {{{-28,-28,-28,-28,-28,-28,-28,-20,-14, -8, -4, -4, -4, -4, -4, -2, 2},
+ {-38,-38,-38,-38,-36,-34,-34,-30,-24,-20,-20,-20,-20,-18,-16,-12,-10},
+ {-40,-40,-40,-40,-40,-40,-40,-38,-35,-35,-35,-35,-35,-35,-35,-35,-30}}},
+ /* 10 */
+ {{{-30,-30,-30,-30,-30,-30,-30,-28,-20,-14,-14,-14,-14,-14,-14,-12,-10},
+ {-40,-40,-40,-40,-40,-40,-40,-40,-35,-30,-30,-30,-30,-30,-30,-30,-20},
+ {-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40}}},
+};
+
+/* noise bias (long block) */
+static const noise3 _psy_noisebias_long[12]={
+ /*63 125 250 500 1k 2k 4k 8k 16k*/
+ /* -1 */
+ {{{-10,-10,-10,-10,-10, -4, 0, 0, 0, 6, 6, 6, 6, 10, 10, 12, 20},
+ {-20,-20,-20,-20,-20,-20,-10, -2, 0, 0, 0, 0, 0, 2, 4, 6, 15},
+ {-20,-20,-20,-20,-20,-20,-20,-10, -6, -6, -6, -6, -6, -4, -4, -4, -2}}},
+
+ /* 0 */
+ /* {{{-10,-10,-10,-10,-10,-10, -8, 2, 2, 2, 4, 4, 5, 5, 5, 8, 10},
+ {-20,-20,-20,-20,-20,-20,-20,-14, -6, 0, 0, 0, 0, 0, 2, 4, 10},
+ {-20,-20,-20,-20,-20,-20,-20,-14, -8, -6, -6, -6, -6, -4, -4, -4, -2}}},*/
+ {{{-10,-10,-10,-10,-10,-10, -8, 2, 2, 2, 4, 4, 5, 5, 5, 8, 10},
+ {-20,-20,-20,-20,-20,-20,-20,-14, -6, 0, 0, 0, 0, 0, 2, 3, 6},
+ {-20,-20,-20,-20,-20,-20,-20,-14, -8, -6, -6, -6, -6, -4, -4, -4, -2}}},
+ /* 1 */
+ /* {{{-10,-10,-10,-10,-10,-10, -8, -4, 0, 2, 4, 4, 5, 5, 5, 8, 10},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -2, -2, -2, -2, 0, 2, 8},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10, -8, -8, -8, -8, -6, -6, -6, -4}}},*/
+ {{{-10,-10,-10,-10,-10,-10, -8, -4, 0, 2, 4, 4, 5, 5, 5, 8, 10},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -2, -2, -2, -2, 0, 1, 4},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10, -8, -8, -8, -8, -6, -6, -6, -4}}},
+ /* 2 */
+ /* {{{-10,-10,-10,-10,-10,-10,-10, -8, 0, 2, 2, 2, 4, 4, 5, 6, 10},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -2, -2, -2, -2, 0, 2, 6},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},*/
+ {{{-10,-10,-10,-10,-10,-10,-10, -8, 0, 2, 2, 2, 4, 4, 5, 6, 10},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -3, -3, -3, -2, -1, 0, 3},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},
+ /* 3 */
+ /* {{{-10,-10,-10,-10,-10,-10,-10, -8, 0, 2, 2, 2, 4, 4, 4, 5, 8},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -3, -3, -3, -3, -1, 1, 6},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},*/
+ {{{-10,-10,-10,-10,-10,-10,-10, -8, 0, 2, 2, 2, 4, 4, 4, 5, 8},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -3, -3, -3, -3, -2, 0, 2},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -5}}},
+ /* 4 */
+ /* {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -3, -3, -3, -3, -1, 1, 5},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},*/
+ {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -3, -3, -3, -3, -2, -1, 1},
+ {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -7}}},
+ /* 5 */
+ /* {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-22,-22,-22,-22,-22,-22,-22,-16,-12, -6, -4, -4, -4, -4, -2, -1, 2},
+ {-24,-24,-24,-24,-24,-24,-24,-18,-14,-12,-12,-12,-12,-10,-10, -9, -5}}},*/
+ {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-22,-22,-22,-22,-22,-22,-22,-16,-12, -6, -4, -4, -4, -4, -3, -1, 0},
+ {-24,-24,-24,-24,-24,-24,-24,-18,-14,-12,-12,-12,-12,-10,-10, -9, -8}}},
+ /* 6 */
+ /* {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-24,-24,-24,-24,-24,-24,-24,-18,-14, -8, -6, -6, -6, -6, -4, -2, 1},
+ {-26,-26,-26,-26,-26,-26,-26,-18,-16,-15,-15,-15,-15,-13,-13,-12, -8}}},*/
+ {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-24,-24,-24,-24,-24,-24,-24,-18,-14, -8, -6, -6, -6, -6, -5, -2, 0},
+ {-26,-26,-26,-26,-26,-26,-26,-18,-16,-15,-15,-15,-15,-13,-13,-12,-10}}},
+ /* 7 */
+ {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7},
+ {-24,-24,-24,-24,-24,-24,-24,-18,-14,-10, -8, -8, -8, -8, -6, -4, 0},
+ {-26,-26,-26,-26,-26,-26,-26,-22,-20,-19,-19,-19,-19,-18,-17,-16,-12}}},
+ /* 8 */
+ {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 0, 0, 0, 0, 1, 2, 3, 7},
+ {-26,-26,-26,-26,-26,-26,-26,-20,-16,-12,-10,-10,-10,-10, -8, -6, -2},
+ {-28,-28,-28,-28,-28,-28,-28,-26,-24,-24,-24,-24,-24,-24,-24,-20,-16}}},
+ /* 9 */
+ {{{-22,-22,-22,-22,-22,-22,-22,-18,-14, -8, -4, -4, -4, -4, -4, -2, 2},
+ {-26,-26,-26,-26,-26,-26,-26,-22,-18,-16,-16,-16,-16,-14,-12,-10, -7},
+ {-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-24,-20}}},
+ /* 10 */
+ {{{-24,-24,-24,-24,-24,-24,-24,-24,-24,-18,-14,-14,-14,-14,-14,-12,-10},
+ {-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-20},
+ {-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40}}},
+};
+
+/* noise bias (impulse block) */
+static const noise3 _psy_noisebias_impulse[12]={
+ /* 63 125 250 500 1k 2k 4k 8k 16k*/
+ /* -1 */
+ {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 8, 8, 8, 8, 10, 12, 14, 20},
+ {-30,-30,-30,-30,-26,-20,-16, -8, -6, -6, -2, 2, 2, 3, 6, 6, 15},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -4, -2}}},
+
+ /* 0 */
+ /* {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 4, 8, 8, 8, 10, 12, 14, 20},
+ {-30,-30,-30,-30,-26,-22,-20,-14, -6, -2, 0, 0, 0, 0, 2, 4, 10},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -4, -2}}},*/
+ {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 4, 8, 8, 8, 10, 12, 14, 20},
+ {-30,-30,-30,-30,-26,-22,-20,-14, -6, -2, 0, 0, 0, 0, 2, 3, 6},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -4, -2}}},
+ /* 1 */
+ {{{-12,-12,-12,-12,-12, -8, -6, -4, 0, 4, 4, 4, 4, 10, 12, 14, 20},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -4, -4, -2, -2, -2, -2, 2},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8,-10,-10, -8, -8, -8, -6, -4}}},
+ /* 2 */
+ {{{-14,-14,-14,-14,-14,-10, -8, -6, -2, 2, 2, 2, 2, 8, 10, 10, 16},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -4, -4, -4, -2, 0},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10,-10,-10, -8, -4}}},
+ /* 3 */
+ {{{-14,-14,-14,-14,-14,-10, -8, -6, -2, 2, 2, 2, 2, 6, 8, 8, 14},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -4, -4, -4, -2, 0},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10,-10,-10, -8, -4}}},
+ /* 4 */
+ {{{-16,-16,-16,-16,-16,-12,-10, -6, -2, 0, 0, 0, 0, 4, 6, 6, 12},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -4, -4, -4, -2, 0},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10,-10,-10, -8, -4}}},
+ /* 5 */
+ {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 4, 6, 11},
+ {-32,-32,-32,-32,-28,-24,-22,-16,-10, -6, -8, -8, -6, -6, -6, -4, -2},
+ {-34,-34,-34,-34,-30,-26,-24,-18,-14,-12,-12,-12,-12,-12,-10, -9, -5}}},
+ /* 6
+ {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 4, 6, 11},
+ {-34,-34,-34,-34,-30,-30,-24,-20,-12,-12,-14,-14,-10, -9, -8, -6, -4},
+ {-34,-34,-34,-34,-34,-30,-26,-20,-16,-15,-15,-15,-15,-15,-13,-12, -8}}},*/
+ {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 4, 6, 11},
+ {-34,-34,-34,-34,-30,-30,-30,-24,-16,-16,-16,-16,-16,-16,-14,-14,-12},
+ {-36,-36,-36,-36,-36,-34,-28,-24,-20,-20,-20,-20,-20,-20,-20,-18,-16}}},
+ /* 7 */
+ /* {{{-22,-22,-22,-22,-22,-20,-14,-10, -6, 0, 0, 0, 0, 4, 4, 6, 11},
+ {-34,-34,-34,-34,-30,-30,-24,-20,-14,-14,-16,-16,-14,-12,-10,-10,-10},
+ {-34,-34,-34,-34,-32,-32,-30,-24,-20,-19,-19,-19,-19,-19,-17,-16,-12}}},*/
+ {{{-22,-22,-22,-22,-22,-20,-14,-10, -6, 0, 0, 0, 0, 4, 4, 6, 11},
+ {-34,-34,-34,-34,-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-24,-22},
+ {-40,-40,-40,-40,-40,-40,-40,-32,-30,-30,-30,-30,-30,-30,-30,-30,-24}}},
+ /* 8 */
+ /* {{{-24,-24,-24,-24,-24,-22,-14,-10, -6, -1, -1, -1, -1, 3, 3, 5, 10},
+ {-34,-34,-34,-34,-30,-30,-30,-24,-20,-20,-20,-20,-20,-18,-16,-16,-14},
+ {-36,-36,-36,-36,-36,-34,-28,-24,-24,-24,-24,-24,-24,-24,-24,-20,-16}}},*/
+ {{{-24,-24,-24,-24,-24,-22,-14,-10, -6, -1, -1, -1, -1, 3, 3, 5, 10},
+ {-34,-34,-34,-34,-34,-32,-32,-30,-26,-26,-26,-26,-26,-26,-26,-26,-24},
+ {-40,-40,-40,-40,-40,-40,-40,-32,-30,-30,-30,-30,-30,-30,-30,-30,-24}}},
+ /* 9 */
+ /* {{{-28,-28,-28,-28,-28,-28,-28,-20,-14, -8, -4, -4, -4, -4, -4, -2, 2},
+ {-36,-36,-36,-36,-34,-32,-32,-30,-26,-26,-26,-26,-26,-22,-20,-20,-18},
+ {-40,-40,-40,-40,-40,-40,-40,-32,-30,-30,-30,-30,-30,-30,-30,-24,-20}}},*/
+ {{{-28,-28,-28,-28,-28,-28,-28,-20,-14, -8, -4, -4, -4, -4, -4, -2, 2},
+ {-36,-36,-36,-36,-34,-32,-32,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26},
+ {-40,-40,-40,-40,-40,-40,-40,-32,-30,-30,-30,-30,-30,-30,-30,-24,-20}}},
+ /* 10 */
+ {{{-30,-30,-30,-30,-30,-26,-24,-24,-24,-20,-16,-16,-16,-16,-16,-14,-12},
+ {-40,-40,-40,-40,-40,-40,-40,-40,-35,-30,-30,-30,-30,-30,-30,-30,-26},
+ {-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40}}},
+};
+
+/* noise bias (padding block) */
+static const noise3 _psy_noisebias_padding[12]={
+ /* 63 125 250 500 1k 2k 4k 8k 16k*/
+
+ /* -1 */
+ {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 8, 8, 8, 8, 10, 12, 14, 20},
+ {-30,-30,-30,-30,-26,-20,-16, -8, -6, -6, -2, 2, 2, 3, 6, 6, 15},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -4, -2}}},
+
+ /* 0 */
+ {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 8, 8, 8, 8, 10, 12, 14, 20},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -2, 2, 3, 6, 6, 8, 10},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -4, -4, -4, -4, -2, 0, 2}}},
+ /* 1 */
+ {{{-12,-12,-12,-12,-12, -8, -6, -4, 0, 4, 4, 4, 4, 10, 12, 14, 20},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, 0, 0, 0, 2, 2, 4, 8},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -6, -6, -4, -2, 0}}},
+ /* 2 */
+ /* {{{-14,-14,-14,-14,-14,-10, -8, -6, -2, 2, 2, 2, 2, 8, 10, 10, 16},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, 0, 0, 0, 2, 2, 4, 8},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -8, -6, -4, -2}}},*/
+ {{{-14,-14,-14,-14,-14,-10, -8, -6, -2, 2, 2, 2, 2, 8, 10, 10, 16},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -1, -1, -1, 0, 0, 2, 6},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -8, -6, -4, -2}}},
+ /* 3 */
+ {{{-14,-14,-14,-14,-14,-10, -8, -6, -2, 2, 2, 2, 2, 6, 8, 8, 14},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -1, -1, -1, 0, 0, 2, 6},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -8, -6, -4, -2}}},
+ /* 4 */
+ {{{-16,-16,-16,-16,-16,-12,-10, -6, -2, 0, 0, 0, 0, 4, 6, 6, 12},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -1, -1, -1, -1, 0, 2, 6},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -8, -6, -4, -2}}},
+ /* 5 */
+ {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 6, 6, 12},
+ {-32,-32,-32,-32,-28,-24,-22,-16,-12, -6, -3, -3, -3, -3, -2, 0, 4},
+ {-34,-34,-34,-34,-30,-26,-24,-18,-14,-10,-10,-10,-10,-10, -8, -5, -3}}},
+ /* 6 */
+ {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 6, 6, 12},
+ {-34,-34,-34,-34,-30,-30,-24,-20,-14, -8, -4, -4, -4, -4, -3, -1, 4},
+ {-34,-34,-34,-34,-34,-30,-26,-20,-16,-13,-13,-13,-13,-13,-11, -8, -6}}},
+ /* 7 */
+ {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 6, 6, 12},
+ {-34,-34,-34,-34,-30,-30,-30,-24,-16,-10, -8, -6, -6, -6, -5, -3, 1},
+ {-34,-34,-34,-34,-32,-32,-28,-22,-18,-16,-16,-16,-16,-16,-14,-12,-10}}},
+ /* 8 */
+ {{{-22,-22,-22,-22,-22,-20,-14,-10, -4, 0, 0, 0, 0, 3, 5, 5, 11},
+ {-34,-34,-34,-34,-30,-30,-30,-24,-16,-12,-10, -8, -8, -8, -7, -5, -2},
+ {-36,-36,-36,-36,-36,-34,-28,-22,-20,-20,-20,-20,-20,-20,-20,-16,-14}}},
+ /* 9 */
+ {{{-28,-28,-28,-28,-28,-28,-28,-20,-14, -8, -2, -2, -2, -2, 0, 2, 6},
+ {-36,-36,-36,-36,-34,-32,-32,-24,-16,-12,-12,-12,-12,-12,-10, -8, -5},
+ {-40,-40,-40,-40,-40,-40,-40,-32,-26,-24,-24,-24,-24,-24,-24,-20,-18}}},
+ /* 10 */
+ {{{-30,-30,-30,-30,-30,-26,-24,-24,-24,-20,-12,-12,-12,-12,-12,-10, -8},
+ {-40,-40,-40,-40,-40,-40,-40,-40,-35,-30,-25,-25,-25,-25,-25,-25,-15},
+ {-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40}}},
+};
+
+
+static const noiseguard _psy_noiseguards_44[4]={
+ {3,3,15},
+ {3,3,15},
+ {10,10,100},
+ {10,10,100},
+};
+
+static const int _psy_tone_suppress[12]={
+ -20,-20,-20,-20,-20,-24,-30,-40,-40,-45,-45,-45,
+};
+static const int _psy_tone_0dB[12]={
+ 90,90,95,95,95,95,105,105,105,105,105,105,
+};
+static const int _psy_noise_suppress[12]={
+ -20,-20,-24,-24,-24,-24,-30,-40,-40,-45,-45,-45,
+};
+
+static const vorbis_info_psy _psy_info_template={
+ /* blockflag */
+ -1,
+ /* ath_adjatt, ath_maxatt */
+ -140.,-140.,
+ /* tonemask att boost/decay,suppr,curves */
+ {0.f,0.f,0.f}, 0.,0., -40.f, {0.},
+
+ /*noisemaskp,supp, low/high window, low/hi guard, minimum */
+ 1, -0.f, .5f, .5f, 0,0,0,
+ /* noiseoffset*3, noisecompand, max_curve_dB */
+ {{-1},{-1},{-1}},{-1},105.f,
+ /* noise normalization - noise_p, start, partition, thresh. */
+ 0,-1,-1,0.,
+};
+
+/* ath ****************/
+
+static const int _psy_ath_floater[12]={
+ -100,-100,-100,-100,-100,-100,-105,-105,-105,-105,-110,-120,
+};
+static const int _psy_ath_abs[12]={
+ -130,-130,-130,-130,-140,-140,-140,-140,-140,-140,-140,-150,
+};
+
+/* stereo setup. These don't map directly to quality level, there's
+ an additional indirection as several of the below may be used in a
+ single bitmanaged stream
+
+****************/
+
+/* various stereo possibilities */
+
+/* stereo mode by base quality level */
+static const adj_stereo _psy_stereo_modes_44[12]={
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 -1 */
+ {{ 4, 4, 4, 4, 4, 4, 4, 3, 2, 2, 1, 0, 0, 0, 0},
+ { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 5, 4, 3},
+ { 1, 2, 3, 4, 4, 4, 4, 4, 4, 5, 6, 7, 8, 8, 8},
+ { 12,12.5, 13,13.5, 14,14.5, 15, 99, 99, 99, 99, 99, 99, 99, 99}},
+
+/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 */
+ {{ 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0, 0, 0, 0, 0},
+ { 8, 8, 8, 8, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, 3},
+ { 1, 2, 3, 4, 4, 5, 6, 6, 6, 6, 6, 8, 8, 8, 8},
+ { 12,12.5, 13,13.5, 14,14.5, 15, 99, 99, 99, 99, 99, 99, 99, 99}},
+
+
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 */
+ {{ 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, 0, 0, 0, 0},
+ { 8, 8, 8, 8, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, 3},
+ { 1, 2, 3, 4, 4, 5, 6, 6, 6, 6, 6, 8, 8, 8, 8},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+
+
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 2 */
+ {{ 3, 3, 3, 3, 3, 3, 3, 2, 1, 1, 0, 0, 0, 0, 0},
+ { 8, 8, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4, 3, 2, 1},
+ { 3, 4, 4, 5, 5, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 3 */
+ {{ 2, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
+ { 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1},
+ { 4, 4, 5, 6, 6, 6, 6, 6, 8, 8, 10, 10, 10, 10, 10},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 4 */
+ {{ 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 2, 1, 0},
+ { 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 5 */
+ {{ 2, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0},
+ { 6, 7, 8, 8, 8, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 6 */
+ {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 3, 3, 3, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 8, 8, 8, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 7 */
+ {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 3, 3, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 8, 8, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 8 */
+ {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 8, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 9 */
+ {{ 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},
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 10 */
+ {{ 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},
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+};
+
+/* tone master attenuation by base quality mode and bitrate tweak */
+static const att3 _psy_tone_masteratt_44[12]={
+ {{ 35, 21, 9}, 0, 0}, /* -1 */
+ {{ 30, 20, 8}, -2, 1.25}, /* 0 */
+ /* {{ 25, 14, 4}, 0, 0}, *//* 1 */
+ {{ 25, 12, 2}, 0, 0}, /* 1 */
+ /* {{ 20, 10, -2}, 0, 0}, *//* 2 */
+ {{ 20, 9, -3}, 0, 0}, /* 2 */
+ {{ 20, 9, -4}, 0, 0}, /* 3 */
+ {{ 20, 9, -4}, 0, 0}, /* 4 */
+ {{ 20, 6, -6}, 0, 0}, /* 5 */
+ {{ 20, 3, -10}, 0, 0}, /* 6 */
+ {{ 18, 1, -14}, 0, 0}, /* 7 */
+ {{ 18, 0, -16}, 0, 0}, /* 8 */
+ {{ 18, -2, -16}, 0, 0}, /* 9 */
+ {{ 12, -2, -20}, 0, 0}, /* 10 */
+};
+
+/* lowpass by mode **************/
+static const double _psy_lowpass_44[12]={
+ /* 15.1,15.8,16.5,17.9,20.5,48.,999.,999.,999.,999.,999. */
+ 13.9,15.1,15.8,16.5,17.2,18.9,20.1,48.,999.,999.,999.,999.
+};
+
+/* noise normalization **********/
+
+static const int _noise_start_short_44[11]={
+ /* 16,16,16,16,32,32,9999,9999,9999,9999 */
+ 32,16,16,16,32,9999,9999,9999,9999,9999,9999
+};
+static const int _noise_start_long_44[11]={
+ /* 128,128,128,256,512,512,9999,9999,9999,9999 */
+ 256,128,128,256,512,9999,9999,9999,9999,9999,9999
+};
+
+static const int _noise_part_short_44[11]={
+ 8,8,8,8,8,8,8,8,8,8,8
+};
+static const int _noise_part_long_44[11]={
+ 32,32,32,32,32,32,32,32,32,32,32
+};
+
+static const double _noise_thresh_44[11]={
+ /* .2,.2,.3,.4,.5,.5,9999.,9999.,9999.,9999., */
+ .2,.2,.2,.4,.6,9999.,9999.,9999.,9999.,9999.,9999.,
+};
+
+static const double _noise_thresh_5only[2]={
+ .5,.5,
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/psych_8.h b/external/libvorbis-1.3.5/lib/modes/psych_8.h
new file mode 100644
index 0000000..0e2dd57
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/psych_8.h
@@ -0,0 +1,101 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: 8kHz psychoacoustic settings
+ last mod: $Id: psych_8.h 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+static const att3 _psy_tone_masteratt_8[3]={
+ {{ 32, 25, 12}, 0, 0}, /* 0 */
+ {{ 30, 25, 12}, 0, 0}, /* 0 */
+ {{ 20, 0, -14}, 0, 0}, /* 0 */
+};
+
+static const vp_adjblock _vp_tonemask_adj_8[3]={
+ /* adjust for mode zero */
+ /* 63 125 250 500 1 2 4 8 16 */
+ {{-15,-15,-15,-15,-10,-10, -6, 0, 0, 0, 0,10, 0, 0,99,99,99}}, /* 1 */
+ {{-15,-15,-15,-15,-10,-10, -6, 0, 0, 0, 0,10, 0, 0,99,99,99}}, /* 1 */
+ {{-15,-15,-15,-15,-10,-10, -6, 0, 0, 0, 0, 0, 0, 0,99,99,99}}, /* 1 */
+};
+
+
+static const noise3 _psy_noisebias_8[3]={
+ /* 63 125 250 500 1k 2k 4k 8k 16k*/
+ {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 8, 8, 8, 10, 10, 99, 99, 99},
+ {-10,-10,-10,-10, -5, -5, -5, 0, 0, 4, 4, 4, 4, 4, 99, 99, 99},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, 99, 99, 99}}},
+
+ {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 8, 8, 8, 10, 10, 99, 99, 99},
+ {-10,-10,-10,-10,-10,-10, -5, -5, -5, 0, 0, 0, 0, 0, 99, 99, 99},
+ {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, 99, 99, 99}}},
+
+ {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 99, 99, 99},
+ {-30,-30,-30,-30,-26,-22,-20,-14,-12,-12,-10,-10,-10,-10, 99, 99, 99},
+ {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24, 99, 99, 99}}},
+};
+
+/* stereo mode by base quality level */
+static const adj_stereo _psy_stereo_modes_8[3]={
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 */
+ {{ 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
+ { 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ {{ 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
+ { 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+ {{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}},
+};
+
+static const noiseguard _psy_noiseguards_8[2]={
+ {10,10,-1},
+ {10,10,-1},
+};
+
+static const compandblock _psy_compand_8[2]={
+ {{
+ 0, 1, 2, 3, 4, 5, 6, 7, /* 7dB */
+ 8, 8, 9, 9,10,10,11, 11, /* 15dB */
+ 12,12,13,13,14,14,15, 15, /* 23dB */
+ 16,16,17,17,17,18,18, 19, /* 31dB */
+ 19,19,20,21,22,23,24, 25, /* 39dB */
+ }},
+ {{
+ 0, 1, 2, 3, 4, 5, 6, 6, /* 7dB */
+ 7, 7, 6, 6, 5, 5, 4, 4, /* 15dB */
+ 3, 3, 3, 4, 5, 6, 7, 8, /* 23dB */
+ 9,10,11,12,13,14,15, 16, /* 31dB */
+ 17,18,19,20,21,22,23, 24, /* 39dB */
+ }},
+};
+
+static const double _psy_lowpass_8[3]={3.,4.,4.};
+static const int _noise_start_8[2]={
+ 64,64,
+};
+static const int _noise_part_8[2]={
+ 8,8,
+};
+
+static const int _psy_ath_floater_8[3]={
+ -100,-100,-105,
+};
+
+static const int _psy_ath_abs_8[3]={
+ -130,-130,-140,
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/residue_16.h b/external/libvorbis-1.3.5/lib/modes/residue_16.h
new file mode 100644
index 0000000..dcaca54
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/residue_16.h
@@ -0,0 +1,163 @@
+/********************************************************************
+ * *
+ * This FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel residue templates 16/22kHz
+ last mod: $Id: residue_16.h 16962 2010-03-11 07:30:34Z xiphmont $
+
+ ********************************************************************/
+
+/***** residue backends *********************************************/
+
+static const static_bookblock _resbook_16s_0={
+ {
+ {0},
+ {0,0,&_16c0_s_p1_0},
+ {0},
+ {0,0,&_16c0_s_p3_0},
+ {0,0,&_16c0_s_p4_0},
+ {0,0,&_16c0_s_p5_0},
+ {0,0,&_16c0_s_p6_0},
+ {&_16c0_s_p7_0,&_16c0_s_p7_1},
+ {&_16c0_s_p8_0,&_16c0_s_p8_1},
+ {&_16c0_s_p9_0,&_16c0_s_p9_1,&_16c0_s_p9_2}
+ }
+};
+static const static_bookblock _resbook_16s_1={
+ {
+ {0},
+ {0,0,&_16c1_s_p1_0},
+ {0},
+ {0,0,&_16c1_s_p3_0},
+ {0,0,&_16c1_s_p4_0},
+ {0,0,&_16c1_s_p5_0},
+ {0,0,&_16c1_s_p6_0},
+ {&_16c1_s_p7_0,&_16c1_s_p7_1},
+ {&_16c1_s_p8_0,&_16c1_s_p8_1},
+ {&_16c1_s_p9_0,&_16c1_s_p9_1,&_16c1_s_p9_2}
+ }
+};
+static const static_bookblock _resbook_16s_2={
+ {
+ {0},
+ {0,0,&_16c2_s_p1_0},
+ {0,0,&_16c2_s_p2_0},
+ {0,0,&_16c2_s_p3_0},
+ {0,0,&_16c2_s_p4_0},
+ {&_16c2_s_p5_0,&_16c2_s_p5_1},
+ {&_16c2_s_p6_0,&_16c2_s_p6_1},
+ {&_16c2_s_p7_0,&_16c2_s_p7_1},
+ {&_16c2_s_p8_0,&_16c2_s_p8_1},
+ {&_16c2_s_p9_0,&_16c2_s_p9_1,&_16c2_s_p9_2}
+ }
+};
+
+static const vorbis_residue_template _res_16s_0[]={
+ {2,0,32, &_residue_44_mid,
+ &_huff_book__16c0_s_single,&_huff_book__16c0_s_single,
+ &_resbook_16s_0,&_resbook_16s_0},
+};
+static const vorbis_residue_template _res_16s_1[]={
+ {2,0,32, &_residue_44_mid,
+ &_huff_book__16c1_s_short,&_huff_book__16c1_s_short,
+ &_resbook_16s_1,&_resbook_16s_1},
+
+ {2,0,32, &_residue_44_mid,
+ &_huff_book__16c1_s_long,&_huff_book__16c1_s_long,
+ &_resbook_16s_1,&_resbook_16s_1}
+};
+static const vorbis_residue_template _res_16s_2[]={
+ {2,0,32, &_residue_44_high,
+ &_huff_book__16c2_s_short,&_huff_book__16c2_s_short,
+ &_resbook_16s_2,&_resbook_16s_2},
+
+ {2,0,32, &_residue_44_high,
+ &_huff_book__16c2_s_long,&_huff_book__16c2_s_long,
+ &_resbook_16s_2,&_resbook_16s_2}
+};
+
+static const vorbis_mapping_template _mapres_template_16_stereo[3]={
+ { _map_nominal, _res_16s_0 }, /* 0 */
+ { _map_nominal, _res_16s_1 }, /* 1 */
+ { _map_nominal, _res_16s_2 }, /* 2 */
+};
+
+static const static_bookblock _resbook_16u_0={
+ {
+ {0},
+ {0,0,&_16u0__p1_0},
+ {0,0,&_16u0__p2_0},
+ {0,0,&_16u0__p3_0},
+ {0,0,&_16u0__p4_0},
+ {0,0,&_16u0__p5_0},
+ {&_16u0__p6_0,&_16u0__p6_1},
+ {&_16u0__p7_0,&_16u0__p7_1,&_16u0__p7_2}
+ }
+};
+static const static_bookblock _resbook_16u_1={
+ {
+ {0},
+ {0,0,&_16u1__p1_0},
+ {0,0,&_16u1__p2_0},
+ {0,0,&_16u1__p3_0},
+ {0,0,&_16u1__p4_0},
+ {0,0,&_16u1__p5_0},
+ {0,0,&_16u1__p6_0},
+ {&_16u1__p7_0,&_16u1__p7_1},
+ {&_16u1__p8_0,&_16u1__p8_1},
+ {&_16u1__p9_0,&_16u1__p9_1,&_16u1__p9_2}
+ }
+};
+static const static_bookblock _resbook_16u_2={
+ {
+ {0},
+ {0,0,&_16u2_p1_0},
+ {0,0,&_16u2_p2_0},
+ {0,0,&_16u2_p3_0},
+ {0,0,&_16u2_p4_0},
+ {&_16u2_p5_0,&_16u2_p5_1},
+ {&_16u2_p6_0,&_16u2_p6_1},
+ {&_16u2_p7_0,&_16u2_p7_1},
+ {&_16u2_p8_0,&_16u2_p8_1},
+ {&_16u2_p9_0,&_16u2_p9_1,&_16u2_p9_2}
+ }
+};
+
+static const vorbis_residue_template _res_16u_0[]={
+ {1,0,32, &_residue_44_low_un,
+ &_huff_book__16u0__single,&_huff_book__16u0__single,
+ &_resbook_16u_0,&_resbook_16u_0},
+};
+static const vorbis_residue_template _res_16u_1[]={
+ {1,0,32, &_residue_44_mid_un,
+ &_huff_book__16u1__short,&_huff_book__16u1__short,
+ &_resbook_16u_1,&_resbook_16u_1},
+
+ {1,0,32, &_residue_44_mid_un,
+ &_huff_book__16u1__long,&_huff_book__16u1__long,
+ &_resbook_16u_1,&_resbook_16u_1}
+};
+static const vorbis_residue_template _res_16u_2[]={
+ {1,0,32, &_residue_44_hi_un,
+ &_huff_book__16u2__short,&_huff_book__16u2__short,
+ &_resbook_16u_2,&_resbook_16u_2},
+
+ {1,0,32, &_residue_44_hi_un,
+ &_huff_book__16u2__long,&_huff_book__16u2__long,
+ &_resbook_16u_2,&_resbook_16u_2}
+};
+
+
+static const vorbis_mapping_template _mapres_template_16_uncoupled[3]={
+ { _map_nominal_u, _res_16u_0 }, /* 0 */
+ { _map_nominal_u, _res_16u_1 }, /* 1 */
+ { _map_nominal_u, _res_16u_2 }, /* 2 */
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/residue_44.h b/external/libvorbis-1.3.5/lib/modes/residue_44.h
new file mode 100644
index 0000000..236c183
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/residue_44.h
@@ -0,0 +1,292 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel residue templates for 32/44.1/48kHz
+ last mod: $Id: residue_44.h 16962 2010-03-11 07:30:34Z xiphmont $
+
+ ********************************************************************/
+
+#include "vorbis/codec.h"
+#include "backends.h"
+#include "books/coupled/res_books_stereo.h"
+
+/***** residue backends *********************************************/
+
+static const vorbis_info_residue0 _residue_44_low={
+ 0,-1, -1, 9,-1,-1,
+ /* 0 1 2 3 4 5 6 7 */
+ {0},
+ {-1},
+ { 0, 1, 2, 2, 4, 8, 16, 32},
+ { 0, 0, 0,999, 4, 8, 16, 32},
+};
+
+static const vorbis_info_residue0 _residue_44_mid={
+ 0,-1, -1, 10,-1,-1,
+ /* 0 1 2 3 4 5 6 7 8 */
+ {0},
+ {-1},
+ { 0, 1, 1, 2, 2, 4, 8, 16, 32},
+ { 0, 0,999, 0,999, 4, 8, 16, 32},
+};
+
+static const vorbis_info_residue0 _residue_44_high={
+ 0,-1, -1, 10,-1,-1,
+ /* 0 1 2 3 4 5 6 7 8 */
+ {0},
+ {-1},
+ { 0, 1, 2, 4, 8, 16, 32, 71,157},
+ { 0, 1, 2, 3, 4, 8, 16, 71,157},
+};
+
+static const static_bookblock _resbook_44s_n1={
+ {
+ {0},{0,0,&_44cn1_s_p1_0},{0,0,&_44cn1_s_p2_0},
+ {0,0,&_44cn1_s_p3_0},{0,0,&_44cn1_s_p4_0},{0,0,&_44cn1_s_p5_0},
+ {&_44cn1_s_p6_0,&_44cn1_s_p6_1},{&_44cn1_s_p7_0,&_44cn1_s_p7_1},
+ {&_44cn1_s_p8_0,&_44cn1_s_p8_1,&_44cn1_s_p8_2}
+ }
+};
+static const static_bookblock _resbook_44sm_n1={
+ {
+ {0},{0,0,&_44cn1_sm_p1_0},{0,0,&_44cn1_sm_p2_0},
+ {0,0,&_44cn1_sm_p3_0},{0,0,&_44cn1_sm_p4_0},{0,0,&_44cn1_sm_p5_0},
+ {&_44cn1_sm_p6_0,&_44cn1_sm_p6_1},{&_44cn1_sm_p7_0,&_44cn1_sm_p7_1},
+ {&_44cn1_sm_p8_0,&_44cn1_sm_p8_1,&_44cn1_sm_p8_2}
+ }
+};
+
+static const static_bookblock _resbook_44s_0={
+ {
+ {0},{0,0,&_44c0_s_p1_0},{0,0,&_44c0_s_p2_0},
+ {0,0,&_44c0_s_p3_0},{0,0,&_44c0_s_p4_0},{0,0,&_44c0_s_p5_0},
+ {&_44c0_s_p6_0,&_44c0_s_p6_1},{&_44c0_s_p7_0,&_44c0_s_p7_1},
+ {&_44c0_s_p8_0,&_44c0_s_p8_1,&_44c0_s_p8_2}
+ }
+};
+static const static_bookblock _resbook_44sm_0={
+ {
+ {0},{0,0,&_44c0_sm_p1_0},{0,0,&_44c0_sm_p2_0},
+ {0,0,&_44c0_sm_p3_0},{0,0,&_44c0_sm_p4_0},{0,0,&_44c0_sm_p5_0},
+ {&_44c0_sm_p6_0,&_44c0_sm_p6_1},{&_44c0_sm_p7_0,&_44c0_sm_p7_1},
+ {&_44c0_sm_p8_0,&_44c0_sm_p8_1,&_44c0_sm_p8_2}
+ }
+};
+
+static const static_bookblock _resbook_44s_1={
+ {
+ {0},{0,0,&_44c1_s_p1_0},{0,0,&_44c1_s_p2_0},
+ {0,0,&_44c1_s_p3_0},{0,0,&_44c1_s_p4_0},{0,0,&_44c1_s_p5_0},
+ {&_44c1_s_p6_0,&_44c1_s_p6_1},{&_44c1_s_p7_0,&_44c1_s_p7_1},
+ {&_44c1_s_p8_0,&_44c1_s_p8_1,&_44c1_s_p8_2}
+ }
+};
+static const static_bookblock _resbook_44sm_1={
+ {
+ {0},{0,0,&_44c1_sm_p1_0},{0,0,&_44c1_sm_p2_0},
+ {0,0,&_44c1_sm_p3_0},{0,0,&_44c1_sm_p4_0},{0,0,&_44c1_sm_p5_0},
+ {&_44c1_sm_p6_0,&_44c1_sm_p6_1},{&_44c1_sm_p7_0,&_44c1_sm_p7_1},
+ {&_44c1_sm_p8_0,&_44c1_sm_p8_1,&_44c1_sm_p8_2}
+ }
+};
+
+static const static_bookblock _resbook_44s_2={
+ {
+ {0},{0,0,&_44c2_s_p1_0},{0,0,&_44c2_s_p2_0},{0,0,&_44c2_s_p3_0},
+ {0,0,&_44c2_s_p4_0},{0,0,&_44c2_s_p5_0},{0,0,&_44c2_s_p6_0},
+ {&_44c2_s_p7_0,&_44c2_s_p7_1},{&_44c2_s_p8_0,&_44c2_s_p8_1},
+ {&_44c2_s_p9_0,&_44c2_s_p9_1,&_44c2_s_p9_2}
+ }
+};
+static const static_bookblock _resbook_44s_3={
+ {
+ {0},{0,0,&_44c3_s_p1_0},{0,0,&_44c3_s_p2_0},{0,0,&_44c3_s_p3_0},
+ {0,0,&_44c3_s_p4_0},{0,0,&_44c3_s_p5_0},{0,0,&_44c3_s_p6_0},
+ {&_44c3_s_p7_0,&_44c3_s_p7_1},{&_44c3_s_p8_0,&_44c3_s_p8_1},
+ {&_44c3_s_p9_0,&_44c3_s_p9_1,&_44c3_s_p9_2}
+ }
+};
+static const static_bookblock _resbook_44s_4={
+ {
+ {0},{0,0,&_44c4_s_p1_0},{0,0,&_44c4_s_p2_0},{0,0,&_44c4_s_p3_0},
+ {0,0,&_44c4_s_p4_0},{0,0,&_44c4_s_p5_0},{0,0,&_44c4_s_p6_0},
+ {&_44c4_s_p7_0,&_44c4_s_p7_1},{&_44c4_s_p8_0,&_44c4_s_p8_1},
+ {&_44c4_s_p9_0,&_44c4_s_p9_1,&_44c4_s_p9_2}
+ }
+};
+static const static_bookblock _resbook_44s_5={
+ {
+ {0},{0,0,&_44c5_s_p1_0},{0,0,&_44c5_s_p2_0},{0,0,&_44c5_s_p3_0},
+ {0,0,&_44c5_s_p4_0},{0,0,&_44c5_s_p5_0},{0,0,&_44c5_s_p6_0},
+ {&_44c5_s_p7_0,&_44c5_s_p7_1},{&_44c5_s_p8_0,&_44c5_s_p8_1},
+ {&_44c5_s_p9_0,&_44c5_s_p9_1,&_44c5_s_p9_2}
+ }
+};
+static const static_bookblock _resbook_44s_6={
+ {
+ {0},{0,0,&_44c6_s_p1_0},{0,0,&_44c6_s_p2_0},{0,0,&_44c6_s_p3_0},
+ {0,0,&_44c6_s_p4_0},
+ {&_44c6_s_p5_0,&_44c6_s_p5_1},
+ {&_44c6_s_p6_0,&_44c6_s_p6_1},
+ {&_44c6_s_p7_0,&_44c6_s_p7_1},
+ {&_44c6_s_p8_0,&_44c6_s_p8_1},
+ {&_44c6_s_p9_0,&_44c6_s_p9_1,&_44c6_s_p9_2}
+ }
+};
+static const static_bookblock _resbook_44s_7={
+ {
+ {0},{0,0,&_44c7_s_p1_0},{0,0,&_44c7_s_p2_0},{0,0,&_44c7_s_p3_0},
+ {0,0,&_44c7_s_p4_0},
+ {&_44c7_s_p5_0,&_44c7_s_p5_1},
+ {&_44c7_s_p6_0,&_44c7_s_p6_1},
+ {&_44c7_s_p7_0,&_44c7_s_p7_1},
+ {&_44c7_s_p8_0,&_44c7_s_p8_1},
+ {&_44c7_s_p9_0,&_44c7_s_p9_1,&_44c7_s_p9_2}
+ }
+};
+static const static_bookblock _resbook_44s_8={
+ {
+ {0},{0,0,&_44c8_s_p1_0},{0,0,&_44c8_s_p2_0},{0,0,&_44c8_s_p3_0},
+ {0,0,&_44c8_s_p4_0},
+ {&_44c8_s_p5_0,&_44c8_s_p5_1},
+ {&_44c8_s_p6_0,&_44c8_s_p6_1},
+ {&_44c8_s_p7_0,&_44c8_s_p7_1},
+ {&_44c8_s_p8_0,&_44c8_s_p8_1},
+ {&_44c8_s_p9_0,&_44c8_s_p9_1,&_44c8_s_p9_2}
+ }
+};
+static const static_bookblock _resbook_44s_9={
+ {
+ {0},{0,0,&_44c9_s_p1_0},{0,0,&_44c9_s_p2_0},{0,0,&_44c9_s_p3_0},
+ {0,0,&_44c9_s_p4_0},
+ {&_44c9_s_p5_0,&_44c9_s_p5_1},
+ {&_44c9_s_p6_0,&_44c9_s_p6_1},
+ {&_44c9_s_p7_0,&_44c9_s_p7_1},
+ {&_44c9_s_p8_0,&_44c9_s_p8_1},
+ {&_44c9_s_p9_0,&_44c9_s_p9_1,&_44c9_s_p9_2}
+ }
+};
+
+static const vorbis_residue_template _res_44s_n1[]={
+ {2,0,32, &_residue_44_low,
+ &_huff_book__44cn1_s_short,&_huff_book__44cn1_sm_short,
+ &_resbook_44s_n1,&_resbook_44sm_n1},
+
+ {2,0,32, &_residue_44_low,
+ &_huff_book__44cn1_s_long,&_huff_book__44cn1_sm_long,
+ &_resbook_44s_n1,&_resbook_44sm_n1}
+};
+static const vorbis_residue_template _res_44s_0[]={
+ {2,0,16, &_residue_44_low,
+ &_huff_book__44c0_s_short,&_huff_book__44c0_sm_short,
+ &_resbook_44s_0,&_resbook_44sm_0},
+
+ {2,0,32, &_residue_44_low,
+ &_huff_book__44c0_s_long,&_huff_book__44c0_sm_long,
+ &_resbook_44s_0,&_resbook_44sm_0}
+};
+static const vorbis_residue_template _res_44s_1[]={
+ {2,0,16, &_residue_44_low,
+ &_huff_book__44c1_s_short,&_huff_book__44c1_sm_short,
+ &_resbook_44s_1,&_resbook_44sm_1},
+
+ {2,0,32, &_residue_44_low,
+ &_huff_book__44c1_s_long,&_huff_book__44c1_sm_long,
+ &_resbook_44s_1,&_resbook_44sm_1}
+};
+
+static const vorbis_residue_template _res_44s_2[]={
+ {2,0,16, &_residue_44_mid,
+ &_huff_book__44c2_s_short,&_huff_book__44c2_s_short,
+ &_resbook_44s_2,&_resbook_44s_2},
+
+ {2,0,32, &_residue_44_mid,
+ &_huff_book__44c2_s_long,&_huff_book__44c2_s_long,
+ &_resbook_44s_2,&_resbook_44s_2}
+};
+static const vorbis_residue_template _res_44s_3[]={
+ {2,0,16, &_residue_44_mid,
+ &_huff_book__44c3_s_short,&_huff_book__44c3_s_short,
+ &_resbook_44s_3,&_resbook_44s_3},
+
+ {2,0,32, &_residue_44_mid,
+ &_huff_book__44c3_s_long,&_huff_book__44c3_s_long,
+ &_resbook_44s_3,&_resbook_44s_3}
+};
+static const vorbis_residue_template _res_44s_4[]={
+ {2,0,16, &_residue_44_mid,
+ &_huff_book__44c4_s_short,&_huff_book__44c4_s_short,
+ &_resbook_44s_4,&_resbook_44s_4},
+
+ {2,0,32, &_residue_44_mid,
+ &_huff_book__44c4_s_long,&_huff_book__44c4_s_long,
+ &_resbook_44s_4,&_resbook_44s_4}
+};
+static const vorbis_residue_template _res_44s_5[]={
+ {2,0,16, &_residue_44_mid,
+ &_huff_book__44c5_s_short,&_huff_book__44c5_s_short,
+ &_resbook_44s_5,&_resbook_44s_5},
+
+ {2,0,32, &_residue_44_mid,
+ &_huff_book__44c5_s_long,&_huff_book__44c5_s_long,
+ &_resbook_44s_5,&_resbook_44s_5}
+};
+static const vorbis_residue_template _res_44s_6[]={
+ {2,0,16, &_residue_44_high,
+ &_huff_book__44c6_s_short,&_huff_book__44c6_s_short,
+ &_resbook_44s_6,&_resbook_44s_6},
+
+ {2,0,32, &_residue_44_high,
+ &_huff_book__44c6_s_long,&_huff_book__44c6_s_long,
+ &_resbook_44s_6,&_resbook_44s_6}
+};
+static const vorbis_residue_template _res_44s_7[]={
+ {2,0,16, &_residue_44_high,
+ &_huff_book__44c7_s_short,&_huff_book__44c7_s_short,
+ &_resbook_44s_7,&_resbook_44s_7},
+
+ {2,0,32, &_residue_44_high,
+ &_huff_book__44c7_s_long,&_huff_book__44c7_s_long,
+ &_resbook_44s_7,&_resbook_44s_7}
+};
+static const vorbis_residue_template _res_44s_8[]={
+ {2,0,16, &_residue_44_high,
+ &_huff_book__44c8_s_short,&_huff_book__44c8_s_short,
+ &_resbook_44s_8,&_resbook_44s_8},
+
+ {2,0,32, &_residue_44_high,
+ &_huff_book__44c8_s_long,&_huff_book__44c8_s_long,
+ &_resbook_44s_8,&_resbook_44s_8}
+};
+static const vorbis_residue_template _res_44s_9[]={
+ {2,0,16, &_residue_44_high,
+ &_huff_book__44c9_s_short,&_huff_book__44c9_s_short,
+ &_resbook_44s_9,&_resbook_44s_9},
+
+ {2,0,32, &_residue_44_high,
+ &_huff_book__44c9_s_long,&_huff_book__44c9_s_long,
+ &_resbook_44s_9,&_resbook_44s_9}
+};
+
+static const vorbis_mapping_template _mapres_template_44_stereo[]={
+ { _map_nominal, _res_44s_n1 }, /* -1 */
+ { _map_nominal, _res_44s_0 }, /* 0 */
+ { _map_nominal, _res_44s_1 }, /* 1 */
+ { _map_nominal, _res_44s_2 }, /* 2 */
+ { _map_nominal, _res_44s_3 }, /* 3 */
+ { _map_nominal, _res_44s_4 }, /* 4 */
+ { _map_nominal, _res_44s_5 }, /* 5 */
+ { _map_nominal, _res_44s_6 }, /* 6 */
+ { _map_nominal, _res_44s_7 }, /* 7 */
+ { _map_nominal, _res_44s_8 }, /* 8 */
+ { _map_nominal, _res_44s_9 }, /* 9 */
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/residue_44p51.h b/external/libvorbis-1.3.5/lib/modes/residue_44p51.h
new file mode 100644
index 0000000..a52cc52
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/residue_44p51.h
@@ -0,0 +1,451 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel residue templates for 32/44.1/48kHz uncoupled
+ last mod: $Id: residue_44p51.h 19013 2013-11-12 04:04:50Z giles $
+
+ ********************************************************************/
+
+#include "vorbis/codec.h"
+#include "backends.h"
+
+#include "books/coupled/res_books_51.h"
+
+/***** residue backends *********************************************/
+
+static const vorbis_info_residue0 _residue_44p_lo={
+ 0,-1, -1, 7,-1,-1,
+ /* 0 1 2 3 4 5 6 7 8 */
+ {0},
+ {-1},
+ { 0, 1, 2, 7, 17, 31},
+ { 0, 0, 99, 7, 17, 31},
+};
+
+static const vorbis_info_residue0 _residue_44p={
+ 0,-1, -1, 8,-1,-1,
+ /* 0 1 2 3 4 5 6 7 8 */
+ {0},
+ {-1},
+ { 0, 1, 1, 2, 7, 17, 31},
+ { 0, 0, 99, 99, 7, 17, 31},
+};
+
+static const vorbis_info_residue0 _residue_44p_hi={
+ 0,-1, -1, 8,-1,-1,
+ /* 0 1 2 3 4 5 6 7 8 */
+ {0},
+ {-1},
+ { 0, 1, 2, 4, 7, 17, 31},
+ { 0, 1, 2, 4, 7, 17, 31},
+};
+
+static const vorbis_info_residue0 _residue_44p_lfe={
+ 0,-1, -1, 2,-1,-1,
+ /* 0 1 2 3 4 5 6 7 8 */
+ {0},
+ {-1},
+ { 32},
+ { -1}
+};
+
+static const static_bookblock _resbook_44p_n1={
+ {
+ {0},
+ {0,&_44pn1_p1_0},
+
+ {&_44pn1_p2_0,&_44pn1_p2_1,0},
+ {&_44pn1_p3_0,&_44pn1_p3_1,0},
+ {&_44pn1_p4_0,&_44pn1_p4_1,0},
+
+ {&_44pn1_p5_0,&_44pn1_p5_1,&_44pn1_p4_1},
+ {&_44pn1_p6_0,&_44pn1_p6_1,&_44pn1_p6_2},
+ }
+};
+
+static const static_bookblock _resbook_44p_0={
+ {
+ {0},
+ {0,&_44p0_p1_0},
+
+ {&_44p0_p2_0,&_44p0_p2_1,0},
+ {&_44p0_p3_0,&_44p0_p3_1,0},
+ {&_44p0_p4_0,&_44p0_p4_1,0},
+
+ {&_44p0_p5_0,&_44p0_p5_1,&_44p0_p4_1},
+ {&_44p0_p6_0,&_44p0_p6_1,&_44p0_p6_2},
+ }
+};
+
+static const static_bookblock _resbook_44p_1={
+ {
+ {0},
+ {0,&_44p1_p1_0},
+
+ {&_44p1_p2_0,&_44p1_p2_1,0},
+ {&_44p1_p3_0,&_44p1_p3_1,0},
+ {&_44p1_p4_0,&_44p1_p4_1,0},
+
+ {&_44p1_p5_0,&_44p1_p5_1,&_44p1_p4_1},
+ {&_44p1_p6_0,&_44p1_p6_1,&_44p1_p6_2},
+ }
+};
+
+static const static_bookblock _resbook_44p_2={
+ {
+ {0},
+ {0,0,&_44p2_p1_0},
+ {0,&_44p2_p2_0,0},
+
+ {&_44p2_p3_0,&_44p2_p3_1,0},
+ {&_44p2_p4_0,&_44p2_p4_1,0},
+ {&_44p2_p5_0,&_44p2_p5_1,0},
+
+ {&_44p2_p6_0,&_44p2_p6_1,&_44p2_p5_1},
+ {&_44p2_p7_0,&_44p2_p7_1,&_44p2_p7_2,&_44p2_p7_3}
+ }
+};
+static const static_bookblock _resbook_44p_3={
+ {
+ {0},
+ {0,0,&_44p3_p1_0},
+ {0,&_44p3_p2_0,0},
+
+ {&_44p3_p3_0,&_44p3_p3_1,0},
+ {&_44p3_p4_0,&_44p3_p4_1,0},
+ {&_44p3_p5_0,&_44p3_p5_1,0},
+
+ {&_44p3_p6_0,&_44p3_p6_1,&_44p3_p5_1},
+ {&_44p3_p7_0,&_44p3_p7_1,&_44p3_p7_2,&_44p3_p7_3}
+ }
+};
+static const static_bookblock _resbook_44p_4={
+ {
+ {0},
+ {0,0,&_44p4_p1_0},
+ {0,&_44p4_p2_0,0},
+
+ {&_44p4_p3_0,&_44p4_p3_1,0},
+ {&_44p4_p4_0,&_44p4_p4_1,0},
+ {&_44p4_p5_0,&_44p4_p5_1,0},
+
+ {&_44p4_p6_0,&_44p4_p6_1,&_44p4_p5_1},
+ {&_44p4_p7_0,&_44p4_p7_1,&_44p4_p7_2,&_44p4_p7_3}
+ }
+};
+static const static_bookblock _resbook_44p_5={
+ {
+ {0},
+ {0,0,&_44p5_p1_0},
+ {0,&_44p5_p2_0,0},
+
+ {&_44p5_p3_0,&_44p5_p3_1,0},
+ {&_44p5_p4_0,&_44p5_p4_1,0},
+ {&_44p5_p5_0,&_44p5_p5_1,0},
+
+ {&_44p5_p6_0,&_44p5_p6_1,&_44p5_p5_1},
+ {&_44p5_p7_0,&_44p5_p7_1,&_44p5_p7_2,&_44p5_p7_3}
+ }
+};
+static const static_bookblock _resbook_44p_6={
+ {
+ {0},
+ {0,0,&_44p6_p1_0},
+ {0,&_44p6_p2_0,0},
+
+ {&_44p6_p3_0,&_44p6_p3_1,0},
+ {&_44p6_p4_0,&_44p6_p4_1,0},
+ {&_44p6_p5_0,&_44p6_p5_1,0},
+
+ {&_44p6_p6_0,&_44p6_p6_1,&_44p6_p5_1},
+ {&_44p6_p7_0,&_44p6_p7_1,&_44p6_p7_2,&_44p6_p7_3}
+ }
+};
+static const static_bookblock _resbook_44p_7={
+ {
+ {0},
+ {0,0,&_44p7_p1_0},
+ {0,&_44p7_p2_0,0},
+
+ {&_44p7_p3_0,&_44p7_p3_1,0},
+ {&_44p7_p4_0,&_44p7_p4_1,0},
+ {&_44p7_p5_0,&_44p7_p5_1,0},
+
+ {&_44p7_p6_0,&_44p7_p6_1,&_44p7_p5_1},
+ {&_44p7_p7_0,&_44p7_p7_1,&_44p7_p7_2,&_44p7_p7_3}
+ }
+};
+static const static_bookblock _resbook_44p_8={
+ {
+ {0},
+ {0,0,&_44p8_p1_0},
+ {0,&_44p8_p2_0,0},
+
+ {&_44p8_p3_0,&_44p8_p3_1,0},
+ {&_44p8_p4_0,&_44p8_p4_1,0},
+ {&_44p8_p5_0,&_44p8_p5_1,0},
+
+ {&_44p8_p6_0,&_44p8_p6_1,&_44p8_p5_1},
+ {&_44p8_p7_0,&_44p8_p7_1,&_44p8_p7_2,&_44p8_p7_3}
+ }
+};
+static const static_bookblock _resbook_44p_9={
+ {
+ {0},
+ {0,0,&_44p9_p1_0},
+ {0,&_44p9_p2_0,0},
+
+ {&_44p9_p3_0,&_44p9_p3_1,0},
+ {&_44p9_p4_0,&_44p9_p4_1,0},
+ {&_44p9_p5_0,&_44p9_p5_1,0},
+
+ {&_44p9_p6_0,&_44p9_p6_1,&_44p9_p5_1},
+ {&_44p9_p7_0,&_44p9_p7_1,&_44p9_p7_2,&_44p9_p7_3}
+ }
+};
+
+static const static_bookblock _resbook_44p_ln1={
+ {
+ {&_44pn1_l0_0,&_44pn1_l0_1,0},
+ {&_44pn1_l1_0,&_44pn1_p6_1,&_44pn1_p6_2},
+ }
+};
+static const static_bookblock _resbook_44p_l0={
+ {
+ {&_44p0_l0_0,&_44p0_l0_1,0},
+ {&_44p0_l1_0,&_44p0_p6_1,&_44p0_p6_2},
+ }
+};
+static const static_bookblock _resbook_44p_l1={
+ {
+ {&_44p1_l0_0,&_44p1_l0_1,0},
+ {&_44p1_l1_0,&_44p1_p6_1,&_44p1_p6_2},
+ }
+};
+static const static_bookblock _resbook_44p_l2={
+ {
+ {&_44p2_l0_0,&_44p2_l0_1,0},
+ {&_44p2_l1_0,&_44p2_p7_2,&_44p2_p7_3},
+ }
+};
+static const static_bookblock _resbook_44p_l3={
+ {
+ {&_44p3_l0_0,&_44p3_l0_1,0},
+ {&_44p3_l1_0,&_44p3_p7_2,&_44p3_p7_3},
+ }
+};
+static const static_bookblock _resbook_44p_l4={
+ {
+ {&_44p4_l0_0,&_44p4_l0_1,0},
+ {&_44p4_l1_0,&_44p4_p7_2,&_44p4_p7_3},
+ }
+};
+static const static_bookblock _resbook_44p_l5={
+ {
+ {&_44p5_l0_0,&_44p5_l0_1,0},
+ {&_44p5_l1_0,&_44p5_p7_2,&_44p5_p7_3},
+ }
+};
+static const static_bookblock _resbook_44p_l6={
+ {
+ {&_44p6_l0_0,&_44p6_l0_1,0},
+ {&_44p6_l1_0,&_44p6_p7_2,&_44p6_p7_3},
+ }
+};
+static const static_bookblock _resbook_44p_l7={
+ {
+ {&_44p7_l0_0,&_44p7_l0_1,0},
+ {&_44p7_l1_0,&_44p7_p7_2,&_44p7_p7_3},
+ }
+};
+static const static_bookblock _resbook_44p_l8={
+ {
+ {&_44p8_l0_0,&_44p8_l0_1,0},
+ {&_44p8_l1_0,&_44p8_p7_2,&_44p8_p7_3},
+ }
+};
+static const static_bookblock _resbook_44p_l9={
+ {
+ {&_44p9_l0_0,&_44p9_l0_1,0},
+ {&_44p9_l1_0,&_44p9_p7_2,&_44p9_p7_3},
+ }
+};
+
+
+static const vorbis_info_mapping0 _map_nominal_51[2]={
+ {2, {0,0,0,0,0,1}, {0,2}, {0,2}, 4,{0,3,0,0},{2,4,1,3}},
+ {2, {0,0,0,0,0,1}, {1,2}, {1,2}, 4,{0,3,0,0},{2,4,1,3}}
+};
+static const vorbis_info_mapping0 _map_nominal_51u[2]={
+ {2, {0,0,0,0,0,1}, {0,2}, {0,2}, 0,{0},{0}},
+ {2, {0,0,0,0,0,1}, {1,2}, {1,2}, 0,{0},{0}}
+};
+
+static const vorbis_residue_template _res_44p51_n1[]={
+ {2,0,30, &_residue_44p_lo,
+ &_huff_book__44pn1_short,&_huff_book__44pn1_short,
+ &_resbook_44p_n1,&_resbook_44p_n1},
+
+ {2,0,30, &_residue_44p_lo,
+ &_huff_book__44pn1_long,&_huff_book__44pn1_long,
+ &_resbook_44p_n1,&_resbook_44p_n1},
+
+ {1,2,6, &_residue_44p_lfe,
+ &_huff_book__44pn1_lfe,&_huff_book__44pn1_lfe,
+ &_resbook_44p_ln1,&_resbook_44p_ln1}
+};
+static const vorbis_residue_template _res_44p51_0[]={
+ {2,0,15, &_residue_44p_lo,
+ &_huff_book__44p0_short,&_huff_book__44p0_short,
+ &_resbook_44p_0,&_resbook_44p_0},
+
+ {2,0,30, &_residue_44p_lo,
+ &_huff_book__44p0_long,&_huff_book__44p0_long,
+ &_resbook_44p_0,&_resbook_44p_0},
+
+ {1,2,6, &_residue_44p_lfe,
+ &_huff_book__44p0_lfe,&_huff_book__44p0_lfe,
+ &_resbook_44p_l0,&_resbook_44p_l0}
+};
+static const vorbis_residue_template _res_44p51_1[]={
+ {2,0,15, &_residue_44p_lo,
+ &_huff_book__44p1_short,&_huff_book__44p1_short,
+ &_resbook_44p_1,&_resbook_44p_1},
+
+ {2,0,30, &_residue_44p_lo,
+ &_huff_book__44p1_long,&_huff_book__44p1_long,
+ &_resbook_44p_1,&_resbook_44p_1},
+
+ {1,2,6, &_residue_44p_lfe,
+ &_huff_book__44p1_lfe,&_huff_book__44p1_lfe,
+ &_resbook_44p_l1,&_resbook_44p_l1}
+};
+static const vorbis_residue_template _res_44p51_2[]={
+ {2,0,15, &_residue_44p,
+ &_huff_book__44p2_short,&_huff_book__44p2_short,
+ &_resbook_44p_2,&_resbook_44p_2},
+
+ {2,0,30, &_residue_44p,
+ &_huff_book__44p2_long,&_huff_book__44p2_long,
+ &_resbook_44p_2,&_resbook_44p_2},
+
+ {1,2,6, &_residue_44p_lfe,
+ &_huff_book__44p2_lfe,&_huff_book__44p2_lfe,
+ &_resbook_44p_l2,&_resbook_44p_l2}
+};
+static const vorbis_residue_template _res_44p51_3[]={
+ {2,0,15, &_residue_44p,
+ &_huff_book__44p3_short,&_huff_book__44p3_short,
+ &_resbook_44p_3,&_resbook_44p_3},
+
+ {2,0,30, &_residue_44p,
+ &_huff_book__44p3_long,&_huff_book__44p3_long,
+ &_resbook_44p_3,&_resbook_44p_3},
+
+ {1,2,6, &_residue_44p_lfe,
+ &_huff_book__44p3_lfe,&_huff_book__44p3_lfe,
+ &_resbook_44p_l3,&_resbook_44p_l3}
+};
+static const vorbis_residue_template _res_44p51_4[]={
+ {2,0,15, &_residue_44p,
+ &_huff_book__44p4_short,&_huff_book__44p4_short,
+ &_resbook_44p_4,&_resbook_44p_4},
+
+ {2,0,30, &_residue_44p,
+ &_huff_book__44p4_long,&_huff_book__44p4_long,
+ &_resbook_44p_4,&_resbook_44p_4},
+
+ {1,2,6, &_residue_44p_lfe,
+ &_huff_book__44p4_lfe,&_huff_book__44p4_lfe,
+ &_resbook_44p_l4,&_resbook_44p_l4}
+};
+static const vorbis_residue_template _res_44p51_5[]={
+ {2,0,15, &_residue_44p_hi,
+ &_huff_book__44p5_short,&_huff_book__44p5_short,
+ &_resbook_44p_5,&_resbook_44p_5},
+
+ {2,0,30, &_residue_44p_hi,
+ &_huff_book__44p5_long,&_huff_book__44p5_long,
+ &_resbook_44p_5,&_resbook_44p_5},
+
+ {1,2,6, &_residue_44p_lfe,
+ &_huff_book__44p5_lfe,&_huff_book__44p5_lfe,
+ &_resbook_44p_l5,&_resbook_44p_l5}
+};
+static const vorbis_residue_template _res_44p51_6[]={
+ {2,0,15, &_residue_44p_hi,
+ &_huff_book__44p6_short,&_huff_book__44p6_short,
+ &_resbook_44p_6,&_resbook_44p_6},
+
+ {2,0,30, &_residue_44p_hi,
+ &_huff_book__44p6_long,&_huff_book__44p6_long,
+ &_resbook_44p_6,&_resbook_44p_6},
+
+ {1,2,6, &_residue_44p_lfe,
+ &_huff_book__44p6_lfe,&_huff_book__44p6_lfe,
+ &_resbook_44p_l6,&_resbook_44p_l6}
+};
+
+
+static const vorbis_residue_template _res_44p51_7[]={
+ {2,0,15, &_residue_44p_hi,
+ &_huff_book__44p7_short,&_huff_book__44p7_short,
+ &_resbook_44p_7,&_resbook_44p_7},
+
+ {2,0,30, &_residue_44p_hi,
+ &_huff_book__44p7_long,&_huff_book__44p7_long,
+ &_resbook_44p_7,&_resbook_44p_7},
+
+ {1,2,6, &_residue_44p_lfe,
+ &_huff_book__44p6_lfe,&_huff_book__44p6_lfe,
+ &_resbook_44p_l6,&_resbook_44p_l6}
+};
+static const vorbis_residue_template _res_44p51_8[]={
+ {2,0,15, &_residue_44p_hi,
+ &_huff_book__44p8_short,&_huff_book__44p8_short,
+ &_resbook_44p_8,&_resbook_44p_8},
+
+ {2,0,30, &_residue_44p_hi,
+ &_huff_book__44p8_long,&_huff_book__44p8_long,
+ &_resbook_44p_8,&_resbook_44p_8},
+
+ {1,2,6, &_residue_44p_lfe,
+ &_huff_book__44p6_lfe,&_huff_book__44p6_lfe,
+ &_resbook_44p_l6,&_resbook_44p_l6}
+};
+static const vorbis_residue_template _res_44p51_9[]={
+ {2,0,15, &_residue_44p_hi,
+ &_huff_book__44p9_short,&_huff_book__44p9_short,
+ &_resbook_44p_9,&_resbook_44p_9},
+
+ {2,0,30, &_residue_44p_hi,
+ &_huff_book__44p9_long,&_huff_book__44p9_long,
+ &_resbook_44p_9,&_resbook_44p_9},
+
+ {1,2,6, &_residue_44p_lfe,
+ &_huff_book__44p6_lfe,&_huff_book__44p6_lfe,
+ &_resbook_44p_l6,&_resbook_44p_l6}
+};
+
+static const vorbis_mapping_template _mapres_template_44_51[]={
+ { _map_nominal_51, _res_44p51_n1 }, /* -1 */
+ { _map_nominal_51, _res_44p51_0 }, /* 0 */
+ { _map_nominal_51, _res_44p51_1 }, /* 1 */
+ { _map_nominal_51, _res_44p51_2 }, /* 2 */
+ { _map_nominal_51, _res_44p51_3 }, /* 3 */
+ { _map_nominal_51, _res_44p51_4 }, /* 4 */
+ { _map_nominal_51u, _res_44p51_5 }, /* 5 */
+ { _map_nominal_51u, _res_44p51_6 }, /* 6 */
+ { _map_nominal_51u, _res_44p51_7 }, /* 7 */
+ { _map_nominal_51u, _res_44p51_8 }, /* 8 */
+ { _map_nominal_51u, _res_44p51_9 }, /* 9 */
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/residue_44u.h b/external/libvorbis-1.3.5/lib/modes/residue_44u.h
new file mode 100644
index 0000000..92c4a09
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/residue_44u.h
@@ -0,0 +1,318 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel residue templates for 32/44.1/48kHz uncoupled
+ last mod: $Id: residue_44u.h 16962 2010-03-11 07:30:34Z xiphmont $
+
+ ********************************************************************/
+
+#include "vorbis/codec.h"
+#include "backends.h"
+#include "books/uncoupled/res_books_uncoupled.h"
+
+/***** residue backends *********************************************/
+
+
+static const vorbis_info_residue0 _residue_44_low_un={
+ 0,-1, -1, 8,-1,-1,
+ {0},
+ {-1},
+ { 0, 1, 1, 2, 2, 4, 28},
+ { -1, 25, -1, 45, -1, -1, -1}
+};
+
+static const vorbis_info_residue0 _residue_44_mid_un={
+ 0,-1, -1, 10,-1,-1,
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ {0},
+ {-1},
+ { 0, 1, 1, 2, 2, 4, 4, 16, 60},
+ { -1, 30, -1, 50, -1, 80, -1, -1, -1}
+};
+
+static const vorbis_info_residue0 _residue_44_hi_un={
+ 0,-1, -1, 10,-1,-1,
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ {0},
+ {-1},
+ { 0, 1, 2, 4, 8, 16, 32, 71,157},
+ { -1, -1, -1, -1, -1, -1, -1, -1, -1}
+};
+
+/* mapping conventions:
+ only one submap (this would change for efficient 5.1 support for example)*/
+/* Four psychoacoustic profiles are used, one for each blocktype */
+static const vorbis_info_mapping0 _map_nominal_u[2]={
+ {1, {0,0,0,0,0,0}, {0}, {0}, 0,{0},{0}},
+ {1, {0,0,0,0,0,0}, {1}, {1}, 0,{0},{0}}
+};
+
+static const static_bookblock _resbook_44u_n1={
+ {
+ {0},
+ {0,0,&_44un1__p1_0},
+ {0,0,&_44un1__p2_0},
+ {0,0,&_44un1__p3_0},
+ {0,0,&_44un1__p4_0},
+ {0,0,&_44un1__p5_0},
+ {&_44un1__p6_0,&_44un1__p6_1},
+ {&_44un1__p7_0,&_44un1__p7_1,&_44un1__p7_2}
+ }
+};
+static const static_bookblock _resbook_44u_0={
+ {
+ {0},
+ {0,0,&_44u0__p1_0},
+ {0,0,&_44u0__p2_0},
+ {0,0,&_44u0__p3_0},
+ {0,0,&_44u0__p4_0},
+ {0,0,&_44u0__p5_0},
+ {&_44u0__p6_0,&_44u0__p6_1},
+ {&_44u0__p7_0,&_44u0__p7_1,&_44u0__p7_2}
+ }
+};
+static const static_bookblock _resbook_44u_1={
+ {
+ {0},
+ {0,0,&_44u1__p1_0},
+ {0,0,&_44u1__p2_0},
+ {0,0,&_44u1__p3_0},
+ {0,0,&_44u1__p4_0},
+ {0,0,&_44u1__p5_0},
+ {&_44u1__p6_0,&_44u1__p6_1},
+ {&_44u1__p7_0,&_44u1__p7_1,&_44u1__p7_2}
+ }
+};
+static const static_bookblock _resbook_44u_2={
+ {
+ {0},
+ {0,0,&_44u2__p1_0},
+ {0,0,&_44u2__p2_0},
+ {0,0,&_44u2__p3_0},
+ {0,0,&_44u2__p4_0},
+ {0,0,&_44u2__p5_0},
+ {&_44u2__p6_0,&_44u2__p6_1},
+ {&_44u2__p7_0,&_44u2__p7_1,&_44u2__p7_2}
+ }
+};
+static const static_bookblock _resbook_44u_3={
+ {
+ {0},
+ {0,0,&_44u3__p1_0},
+ {0,0,&_44u3__p2_0},
+ {0,0,&_44u3__p3_0},
+ {0,0,&_44u3__p4_0},
+ {0,0,&_44u3__p5_0},
+ {&_44u3__p6_0,&_44u3__p6_1},
+ {&_44u3__p7_0,&_44u3__p7_1,&_44u3__p7_2}
+ }
+};
+static const static_bookblock _resbook_44u_4={
+ {
+ {0},
+ {0,0,&_44u4__p1_0},
+ {0,0,&_44u4__p2_0},
+ {0,0,&_44u4__p3_0},
+ {0,0,&_44u4__p4_0},
+ {0,0,&_44u4__p5_0},
+ {&_44u4__p6_0,&_44u4__p6_1},
+ {&_44u4__p7_0,&_44u4__p7_1,&_44u4__p7_2}
+ }
+};
+static const static_bookblock _resbook_44u_5={
+ {
+ {0},
+ {0,0,&_44u5__p1_0},
+ {0,0,&_44u5__p2_0},
+ {0,0,&_44u5__p3_0},
+ {0,0,&_44u5__p4_0},
+ {0,0,&_44u5__p5_0},
+ {0,0,&_44u5__p6_0},
+ {&_44u5__p7_0,&_44u5__p7_1},
+ {&_44u5__p8_0,&_44u5__p8_1},
+ {&_44u5__p9_0,&_44u5__p9_1,&_44u5__p9_2}
+ }
+};
+static const static_bookblock _resbook_44u_6={
+ {
+ {0},
+ {0,0,&_44u6__p1_0},
+ {0,0,&_44u6__p2_0},
+ {0,0,&_44u6__p3_0},
+ {0,0,&_44u6__p4_0},
+ {0,0,&_44u6__p5_0},
+ {0,0,&_44u6__p6_0},
+ {&_44u6__p7_0,&_44u6__p7_1},
+ {&_44u6__p8_0,&_44u6__p8_1},
+ {&_44u6__p9_0,&_44u6__p9_1,&_44u6__p9_2}
+ }
+};
+static const static_bookblock _resbook_44u_7={
+ {
+ {0},
+ {0,0,&_44u7__p1_0},
+ {0,0,&_44u7__p2_0},
+ {0,0,&_44u7__p3_0},
+ {0,0,&_44u7__p4_0},
+ {0,0,&_44u7__p5_0},
+ {0,0,&_44u7__p6_0},
+ {&_44u7__p7_0,&_44u7__p7_1},
+ {&_44u7__p8_0,&_44u7__p8_1},
+ {&_44u7__p9_0,&_44u7__p9_1,&_44u7__p9_2}
+ }
+};
+static const static_bookblock _resbook_44u_8={
+ {
+ {0},
+ {0,0,&_44u8_p1_0},
+ {0,0,&_44u8_p2_0},
+ {0,0,&_44u8_p3_0},
+ {0,0,&_44u8_p4_0},
+ {&_44u8_p5_0,&_44u8_p5_1},
+ {&_44u8_p6_0,&_44u8_p6_1},
+ {&_44u8_p7_0,&_44u8_p7_1},
+ {&_44u8_p8_0,&_44u8_p8_1},
+ {&_44u8_p9_0,&_44u8_p9_1,&_44u8_p9_2}
+ }
+};
+static const static_bookblock _resbook_44u_9={
+ {
+ {0},
+ {0,0,&_44u9_p1_0},
+ {0,0,&_44u9_p2_0},
+ {0,0,&_44u9_p3_0},
+ {0,0,&_44u9_p4_0},
+ {&_44u9_p5_0,&_44u9_p5_1},
+ {&_44u9_p6_0,&_44u9_p6_1},
+ {&_44u9_p7_0,&_44u9_p7_1},
+ {&_44u9_p8_0,&_44u9_p8_1},
+ {&_44u9_p9_0,&_44u9_p9_1,&_44u9_p9_2}
+ }
+};
+
+static const vorbis_residue_template _res_44u_n1[]={
+ {1,0,32, &_residue_44_low_un,
+ &_huff_book__44un1__short,&_huff_book__44un1__short,
+ &_resbook_44u_n1,&_resbook_44u_n1},
+
+ {1,0,32, &_residue_44_low_un,
+ &_huff_book__44un1__long,&_huff_book__44un1__long,
+ &_resbook_44u_n1,&_resbook_44u_n1}
+};
+static const vorbis_residue_template _res_44u_0[]={
+ {1,0,16, &_residue_44_low_un,
+ &_huff_book__44u0__short,&_huff_book__44u0__short,
+ &_resbook_44u_0,&_resbook_44u_0},
+
+ {1,0,32, &_residue_44_low_un,
+ &_huff_book__44u0__long,&_huff_book__44u0__long,
+ &_resbook_44u_0,&_resbook_44u_0}
+};
+static const vorbis_residue_template _res_44u_1[]={
+ {1,0,16, &_residue_44_low_un,
+ &_huff_book__44u1__short,&_huff_book__44u1__short,
+ &_resbook_44u_1,&_resbook_44u_1},
+
+ {1,0,32, &_residue_44_low_un,
+ &_huff_book__44u1__long,&_huff_book__44u1__long,
+ &_resbook_44u_1,&_resbook_44u_1}
+};
+static const vorbis_residue_template _res_44u_2[]={
+ {1,0,16, &_residue_44_low_un,
+ &_huff_book__44u2__short,&_huff_book__44u2__short,
+ &_resbook_44u_2,&_resbook_44u_2},
+
+ {1,0,32, &_residue_44_low_un,
+ &_huff_book__44u2__long,&_huff_book__44u2__long,
+ &_resbook_44u_2,&_resbook_44u_2}
+};
+static const vorbis_residue_template _res_44u_3[]={
+ {1,0,16, &_residue_44_low_un,
+ &_huff_book__44u3__short,&_huff_book__44u3__short,
+ &_resbook_44u_3,&_resbook_44u_3},
+
+ {1,0,32, &_residue_44_low_un,
+ &_huff_book__44u3__long,&_huff_book__44u3__long,
+ &_resbook_44u_3,&_resbook_44u_3}
+};
+static const vorbis_residue_template _res_44u_4[]={
+ {1,0,16, &_residue_44_low_un,
+ &_huff_book__44u4__short,&_huff_book__44u4__short,
+ &_resbook_44u_4,&_resbook_44u_4},
+
+ {1,0,32, &_residue_44_low_un,
+ &_huff_book__44u4__long,&_huff_book__44u4__long,
+ &_resbook_44u_4,&_resbook_44u_4}
+};
+
+static const vorbis_residue_template _res_44u_5[]={
+ {1,0,16, &_residue_44_mid_un,
+ &_huff_book__44u5__short,&_huff_book__44u5__short,
+ &_resbook_44u_5,&_resbook_44u_5},
+
+ {1,0,32, &_residue_44_mid_un,
+ &_huff_book__44u5__long,&_huff_book__44u5__long,
+ &_resbook_44u_5,&_resbook_44u_5}
+};
+
+static const vorbis_residue_template _res_44u_6[]={
+ {1,0,16, &_residue_44_mid_un,
+ &_huff_book__44u6__short,&_huff_book__44u6__short,
+ &_resbook_44u_6,&_resbook_44u_6},
+
+ {1,0,32, &_residue_44_mid_un,
+ &_huff_book__44u6__long,&_huff_book__44u6__long,
+ &_resbook_44u_6,&_resbook_44u_6}
+};
+
+static const vorbis_residue_template _res_44u_7[]={
+ {1,0,16, &_residue_44_mid_un,
+ &_huff_book__44u7__short,&_huff_book__44u7__short,
+ &_resbook_44u_7,&_resbook_44u_7},
+
+ {1,0,32, &_residue_44_mid_un,
+ &_huff_book__44u7__long,&_huff_book__44u7__long,
+ &_resbook_44u_7,&_resbook_44u_7}
+};
+
+static const vorbis_residue_template _res_44u_8[]={
+ {1,0,16, &_residue_44_hi_un,
+ &_huff_book__44u8__short,&_huff_book__44u8__short,
+ &_resbook_44u_8,&_resbook_44u_8},
+
+ {1,0,32, &_residue_44_hi_un,
+ &_huff_book__44u8__long,&_huff_book__44u8__long,
+ &_resbook_44u_8,&_resbook_44u_8}
+};
+static const vorbis_residue_template _res_44u_9[]={
+ {1,0,16, &_residue_44_hi_un,
+ &_huff_book__44u9__short,&_huff_book__44u9__short,
+ &_resbook_44u_9,&_resbook_44u_9},
+
+ {1,0,32, &_residue_44_hi_un,
+ &_huff_book__44u9__long,&_huff_book__44u9__long,
+ &_resbook_44u_9,&_resbook_44u_9}
+};
+
+static const vorbis_mapping_template _mapres_template_44_uncoupled[]={
+ { _map_nominal_u, _res_44u_n1 }, /* -1 */
+ { _map_nominal_u, _res_44u_0 }, /* 0 */
+ { _map_nominal_u, _res_44u_1 }, /* 1 */
+ { _map_nominal_u, _res_44u_2 }, /* 2 */
+ { _map_nominal_u, _res_44u_3 }, /* 3 */
+ { _map_nominal_u, _res_44u_4 }, /* 4 */
+ { _map_nominal_u, _res_44u_5 }, /* 5 */
+ { _map_nominal_u, _res_44u_6 }, /* 6 */
+ { _map_nominal_u, _res_44u_7 }, /* 7 */
+ { _map_nominal_u, _res_44u_8 }, /* 8 */
+ { _map_nominal_u, _res_44u_9 }, /* 9 */
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/residue_8.h b/external/libvorbis-1.3.5/lib/modes/residue_8.h
new file mode 100644
index 0000000..94c6d84
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/residue_8.h
@@ -0,0 +1,109 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel residue templates 8/11kHz
+ last mod: $Id: residue_8.h 16962 2010-03-11 07:30:34Z xiphmont $
+
+ ********************************************************************/
+
+#include "vorbis/codec.h"
+#include "backends.h"
+
+/***** residue backends *********************************************/
+
+static const static_bookblock _resbook_8s_0={
+ {
+ {0},
+ {0,0,&_8c0_s_p1_0},
+ {0},
+ {0,0,&_8c0_s_p3_0},
+ {0,0,&_8c0_s_p4_0},
+ {0,0,&_8c0_s_p5_0},
+ {0,0,&_8c0_s_p6_0},
+ {&_8c0_s_p7_0,&_8c0_s_p7_1},
+ {&_8c0_s_p8_0,&_8c0_s_p8_1},
+ {&_8c0_s_p9_0,&_8c0_s_p9_1,&_8c0_s_p9_2}
+ }
+};
+static const static_bookblock _resbook_8s_1={
+ {
+ {0},
+ {0,0,&_8c1_s_p1_0},
+ {0},
+ {0,0,&_8c1_s_p3_0},
+ {0,0,&_8c1_s_p4_0},
+ {0,0,&_8c1_s_p5_0},
+ {0,0,&_8c1_s_p6_0},
+ {&_8c1_s_p7_0,&_8c1_s_p7_1},
+ {&_8c1_s_p8_0,&_8c1_s_p8_1},
+ {&_8c1_s_p9_0,&_8c1_s_p9_1,&_8c1_s_p9_2}
+ }
+};
+
+static const vorbis_residue_template _res_8s_0[]={
+ {2,0,32, &_residue_44_mid,
+ &_huff_book__8c0_s_single,&_huff_book__8c0_s_single,
+ &_resbook_8s_0,&_resbook_8s_0},
+};
+static const vorbis_residue_template _res_8s_1[]={
+ {2,0,32, &_residue_44_mid,
+ &_huff_book__8c1_s_single,&_huff_book__8c1_s_single,
+ &_resbook_8s_1,&_resbook_8s_1},
+};
+
+static const vorbis_mapping_template _mapres_template_8_stereo[2]={
+ { _map_nominal, _res_8s_0 }, /* 0 */
+ { _map_nominal, _res_8s_1 }, /* 1 */
+};
+
+static const static_bookblock _resbook_8u_0={
+ {
+ {0},
+ {0,0,&_8u0__p1_0},
+ {0,0,&_8u0__p2_0},
+ {0,0,&_8u0__p3_0},
+ {0,0,&_8u0__p4_0},
+ {0,0,&_8u0__p5_0},
+ {&_8u0__p6_0,&_8u0__p6_1},
+ {&_8u0__p7_0,&_8u0__p7_1,&_8u0__p7_2}
+ }
+};
+static const static_bookblock _resbook_8u_1={
+ {
+ {0},
+ {0,0,&_8u1__p1_0},
+ {0,0,&_8u1__p2_0},
+ {0,0,&_8u1__p3_0},
+ {0,0,&_8u1__p4_0},
+ {0,0,&_8u1__p5_0},
+ {0,0,&_8u1__p6_0},
+ {&_8u1__p7_0,&_8u1__p7_1},
+ {&_8u1__p8_0,&_8u1__p8_1},
+ {&_8u1__p9_0,&_8u1__p9_1,&_8u1__p9_2}
+ }
+};
+
+static const vorbis_residue_template _res_8u_0[]={
+ {1,0,32, &_residue_44_low_un,
+ &_huff_book__8u0__single,&_huff_book__8u0__single,
+ &_resbook_8u_0,&_resbook_8u_0},
+};
+static const vorbis_residue_template _res_8u_1[]={
+ {1,0,32, &_residue_44_mid_un,
+ &_huff_book__8u1__single,&_huff_book__8u1__single,
+ &_resbook_8u_1,&_resbook_8u_1},
+};
+
+static const vorbis_mapping_template _mapres_template_8_uncoupled[2]={
+ { _map_nominal_u, _res_8u_0 }, /* 0 */
+ { _map_nominal_u, _res_8u_1 }, /* 1 */
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/setup_11.h b/external/libvorbis-1.3.5/lib/modes/setup_11.h
new file mode 100644
index 0000000..4c2d619
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/setup_11.h
@@ -0,0 +1,143 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: 11kHz settings
+ last mod: $Id: setup_11.h 16894 2010-02-12 20:32:12Z xiphmont $
+
+ ********************************************************************/
+
+#include "psych_11.h"
+
+static const int blocksize_11[2]={
+ 512,512
+};
+
+static const int _floor_mapping_11a[]={
+ 6,6
+};
+static const int *_floor_mapping_11[]={
+ _floor_mapping_11a
+};
+
+static const double rate_mapping_11[3]={
+ 8000.,13000.,44000.,
+};
+
+static const double rate_mapping_11_uncoupled[3]={
+ 12000.,20000.,50000.,
+};
+
+static const double quality_mapping_11[3]={
+ -.1,.0,1.
+};
+
+static const ve_setup_data_template ve_setup_11_stereo={
+ 2,
+ rate_mapping_11,
+ quality_mapping_11,
+ 2,
+ 9000,
+ 15000,
+
+ blocksize_11,
+ blocksize_11,
+
+ _psy_tone_masteratt_11,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_11,
+ NULL,
+ _vp_tonemask_adj_11,
+
+ _psy_noiseguards_8,
+ _psy_noisebias_11,
+ _psy_noisebias_11,
+ NULL,
+ NULL,
+ _psy_noise_suppress,
+
+ _psy_compand_8,
+ _psy_compand_8_mapping,
+ NULL,
+
+ {_noise_start_8,_noise_start_8},
+ {_noise_part_8,_noise_part_8},
+ _noise_thresh_11,
+
+ _psy_ath_floater_8,
+ _psy_ath_abs_8,
+
+ _psy_lowpass_11,
+
+ _psy_global_44,
+ _global_mapping_8,
+ _psy_stereo_modes_8,
+
+ _floor_books,
+ _floor,
+ 1,
+ _floor_mapping_11,
+
+ _mapres_template_8_stereo
+};
+
+static const ve_setup_data_template ve_setup_11_uncoupled={
+ 2,
+ rate_mapping_11_uncoupled,
+ quality_mapping_11,
+ -1,
+ 9000,
+ 15000,
+
+ blocksize_11,
+ blocksize_11,
+
+ _psy_tone_masteratt_11,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_11,
+ NULL,
+ _vp_tonemask_adj_11,
+
+ _psy_noiseguards_8,
+ _psy_noisebias_11,
+ _psy_noisebias_11,
+ NULL,
+ NULL,
+ _psy_noise_suppress,
+
+ _psy_compand_8,
+ _psy_compand_8_mapping,
+ NULL,
+
+ {_noise_start_8,_noise_start_8},
+ {_noise_part_8,_noise_part_8},
+ _noise_thresh_11,
+
+ _psy_ath_floater_8,
+ _psy_ath_abs_8,
+
+ _psy_lowpass_11,
+
+ _psy_global_44,
+ _global_mapping_8,
+ _psy_stereo_modes_8,
+
+ _floor_books,
+ _floor,
+ 1,
+ _floor_mapping_11,
+
+ _mapres_template_8_uncoupled
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/setup_16.h b/external/libvorbis-1.3.5/lib/modes/setup_16.h
new file mode 100644
index 0000000..336007f
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/setup_16.h
@@ -0,0 +1,153 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: 16kHz settings
+ last mod: $Id: setup_16.h 16894 2010-02-12 20:32:12Z xiphmont $
+
+ ********************************************************************/
+
+#include "psych_16.h"
+#include "residue_16.h"
+
+static const int blocksize_16_short[3]={
+ 1024,512,512
+};
+static const int blocksize_16_long[3]={
+ 1024,1024,1024
+};
+
+static const int _floor_mapping_16a[]={
+ 9,3,3
+};
+static const int _floor_mapping_16b[]={
+ 9,9,9
+};
+static const int *_floor_mapping_16[]={
+ _floor_mapping_16a,
+ _floor_mapping_16b
+};
+
+static const double rate_mapping_16[4]={
+ 12000.,20000.,44000.,86000.
+};
+
+static const double rate_mapping_16_uncoupled[4]={
+ 16000.,28000.,64000.,100000.
+};
+
+static const double _global_mapping_16[4]={ 1., 2., 3., 4. };
+
+static const double quality_mapping_16[4]={ -.1,.05,.5,1. };
+
+static const double _psy_compand_16_mapping[4]={ 0., .8, 1., 1.};
+
+static const ve_setup_data_template ve_setup_16_stereo={
+ 3,
+ rate_mapping_16,
+ quality_mapping_16,
+ 2,
+ 15000,
+ 19000,
+
+ blocksize_16_short,
+ blocksize_16_long,
+
+ _psy_tone_masteratt_16,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_16,
+ _vp_tonemask_adj_16,
+ _vp_tonemask_adj_16,
+
+ _psy_noiseguards_16,
+ _psy_noisebias_16_impulse,
+ _psy_noisebias_16_short,
+ _psy_noisebias_16_short,
+ _psy_noisebias_16,
+ _psy_noise_suppress,
+
+ _psy_compand_8,
+ _psy_compand_16_mapping,
+ _psy_compand_16_mapping,
+
+ {_noise_start_16,_noise_start_16},
+ { _noise_part_16, _noise_part_16},
+ _noise_thresh_16,
+
+ _psy_ath_floater_16,
+ _psy_ath_abs_16,
+
+ _psy_lowpass_16,
+
+ _psy_global_44,
+ _global_mapping_16,
+ _psy_stereo_modes_16,
+
+ _floor_books,
+ _floor,
+ 2,
+ _floor_mapping_16,
+
+ _mapres_template_16_stereo
+};
+
+static const ve_setup_data_template ve_setup_16_uncoupled={
+ 3,
+ rate_mapping_16_uncoupled,
+ quality_mapping_16,
+ -1,
+ 15000,
+ 19000,
+
+ blocksize_16_short,
+ blocksize_16_long,
+
+ _psy_tone_masteratt_16,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_16,
+ _vp_tonemask_adj_16,
+ _vp_tonemask_adj_16,
+
+ _psy_noiseguards_16,
+ _psy_noisebias_16_impulse,
+ _psy_noisebias_16_short,
+ _psy_noisebias_16_short,
+ _psy_noisebias_16,
+ _psy_noise_suppress,
+
+ _psy_compand_8,
+ _psy_compand_16_mapping,
+ _psy_compand_16_mapping,
+
+ {_noise_start_16,_noise_start_16},
+ { _noise_part_16, _noise_part_16},
+ _noise_thresh_16,
+
+ _psy_ath_floater_16,
+ _psy_ath_abs_16,
+
+ _psy_lowpass_16,
+
+ _psy_global_44,
+ _global_mapping_16,
+ _psy_stereo_modes_16,
+
+ _floor_books,
+ _floor,
+ 2,
+ _floor_mapping_16,
+
+ _mapres_template_16_uncoupled
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/setup_22.h b/external/libvorbis-1.3.5/lib/modes/setup_22.h
new file mode 100644
index 0000000..4fd5e57
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/setup_22.h
@@ -0,0 +1,128 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: 22kHz settings
+ last mod: $Id: setup_22.h 17026 2010-03-25 05:00:27Z xiphmont $
+
+ ********************************************************************/
+
+static const double rate_mapping_22[4]={
+ 15000.,20000.,44000.,86000.
+};
+
+static const double rate_mapping_22_uncoupled[4]={
+ 16000.,28000.,50000.,90000.
+};
+
+static const double _psy_lowpass_22[4]={9.5,11.,30.,99.};
+
+static const ve_setup_data_template ve_setup_22_stereo={
+ 3,
+ rate_mapping_22,
+ quality_mapping_16,
+ 2,
+ 19000,
+ 26000,
+
+ blocksize_16_short,
+ blocksize_16_long,
+
+ _psy_tone_masteratt_16,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_16,
+ _vp_tonemask_adj_16,
+ _vp_tonemask_adj_16,
+
+ _psy_noiseguards_16,
+ _psy_noisebias_16_impulse,
+ _psy_noisebias_16_short,
+ _psy_noisebias_16_short,
+ _psy_noisebias_16,
+ _psy_noise_suppress,
+
+ _psy_compand_8,
+ _psy_compand_16_mapping,
+ _psy_compand_16_mapping,
+
+ {_noise_start_16,_noise_start_16},
+ { _noise_part_16, _noise_part_16},
+ _noise_thresh_16,
+
+ _psy_ath_floater_16,
+ _psy_ath_abs_16,
+
+ _psy_lowpass_22,
+
+ _psy_global_44,
+ _global_mapping_16,
+ _psy_stereo_modes_16,
+
+ _floor_books,
+ _floor,
+ 2,
+ _floor_mapping_16,
+
+ _mapres_template_16_stereo
+};
+
+static const ve_setup_data_template ve_setup_22_uncoupled={
+ 3,
+ rate_mapping_22_uncoupled,
+ quality_mapping_16,
+ -1,
+ 19000,
+ 26000,
+
+ blocksize_16_short,
+ blocksize_16_long,
+
+ _psy_tone_masteratt_16,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_16,
+ _vp_tonemask_adj_16,
+ _vp_tonemask_adj_16,
+
+ _psy_noiseguards_16,
+ _psy_noisebias_16_impulse,
+ _psy_noisebias_16_short,
+ _psy_noisebias_16_short,
+ _psy_noisebias_16,
+ _psy_noise_suppress,
+
+ _psy_compand_8,
+ _psy_compand_16_mapping,
+ _psy_compand_16_mapping,
+
+ {_noise_start_16,_noise_start_16},
+ { _noise_part_16, _noise_part_16},
+ _noise_thresh_16,
+
+ _psy_ath_floater_16,
+ _psy_ath_abs_16,
+
+ _psy_lowpass_22,
+
+ _psy_global_44,
+ _global_mapping_16,
+ _psy_stereo_modes_16,
+
+ _floor_books,
+ _floor,
+ 2,
+ _floor_mapping_16,
+
+ _mapres_template_16_uncoupled
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/setup_32.h b/external/libvorbis-1.3.5/lib/modes/setup_32.h
new file mode 100644
index 0000000..2275ac9
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/setup_32.h
@@ -0,0 +1,132 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel settings for 32kHz
+ last mod: $Id: setup_32.h 16894 2010-02-12 20:32:12Z xiphmont $
+
+ ********************************************************************/
+
+static const double rate_mapping_32[12]={
+ 18000.,28000.,35000.,45000.,56000.,60000.,
+ 75000.,90000.,100000.,115000.,150000.,190000.,
+};
+
+static const double rate_mapping_32_un[12]={
+ 30000.,42000.,52000.,64000.,72000.,78000.,
+ 86000.,92000.,110000.,120000.,140000.,190000.,
+};
+
+static const double _psy_lowpass_32[12]={
+ 12.3,13.,13.,14.,15.,99.,99.,99.,99.,99.,99.,99.
+};
+
+static const ve_setup_data_template ve_setup_32_stereo={
+ 11,
+ rate_mapping_32,
+ quality_mapping_44,
+ 2,
+ 26000,
+ 40000,
+
+ blocksize_short_44,
+ blocksize_long_44,
+
+ _psy_tone_masteratt_44,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_otherblock,
+ _vp_tonemask_adj_longblock,
+ _vp_tonemask_adj_otherblock,
+
+ _psy_noiseguards_44,
+ _psy_noisebias_impulse,
+ _psy_noisebias_padding,
+ _psy_noisebias_trans,
+ _psy_noisebias_long,
+ _psy_noise_suppress,
+
+ _psy_compand_44,
+ _psy_compand_short_mapping,
+ _psy_compand_long_mapping,
+
+ {_noise_start_short_44,_noise_start_long_44},
+ {_noise_part_short_44,_noise_part_long_44},
+ _noise_thresh_44,
+
+ _psy_ath_floater,
+ _psy_ath_abs,
+
+ _psy_lowpass_32,
+
+ _psy_global_44,
+ _global_mapping_44,
+ _psy_stereo_modes_44,
+
+ _floor_books,
+ _floor,
+ 2,
+ _floor_mapping_44,
+
+ _mapres_template_44_stereo
+};
+
+static const ve_setup_data_template ve_setup_32_uncoupled={
+ 11,
+ rate_mapping_32_un,
+ quality_mapping_44,
+ -1,
+ 26000,
+ 40000,
+
+ blocksize_short_44,
+ blocksize_long_44,
+
+ _psy_tone_masteratt_44,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_otherblock,
+ _vp_tonemask_adj_longblock,
+ _vp_tonemask_adj_otherblock,
+
+ _psy_noiseguards_44,
+ _psy_noisebias_impulse,
+ _psy_noisebias_padding,
+ _psy_noisebias_trans,
+ _psy_noisebias_long,
+ _psy_noise_suppress,
+
+ _psy_compand_44,
+ _psy_compand_short_mapping,
+ _psy_compand_long_mapping,
+
+ {_noise_start_short_44,_noise_start_long_44},
+ {_noise_part_short_44,_noise_part_long_44},
+ _noise_thresh_44,
+
+ _psy_ath_floater,
+ _psy_ath_abs,
+
+ _psy_lowpass_32,
+
+ _psy_global_44,
+ _global_mapping_44,
+ NULL,
+
+ _floor_books,
+ _floor,
+ 2,
+ _floor_mapping_44,
+
+ _mapres_template_44_uncoupled
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/setup_44.h b/external/libvorbis-1.3.5/lib/modes/setup_44.h
new file mode 100644
index 0000000..3b88a89
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/setup_44.h
@@ -0,0 +1,117 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel settings for 44.1/48kHz
+ last mod: $Id: setup_44.h 16962 2010-03-11 07:30:34Z xiphmont $
+
+ ********************************************************************/
+
+#include "modes/floor_all.h"
+#include "modes/residue_44.h"
+#include "modes/psych_44.h"
+
+static const double rate_mapping_44_stereo[12]={
+ 22500.,32000.,40000.,48000.,56000.,64000.,
+ 80000.,96000.,112000.,128000.,160000.,250001.
+};
+
+static const double quality_mapping_44[12]={
+ -.1,.0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1.0
+};
+
+static const int blocksize_short_44[11]={
+ 512,256,256,256,256,256,256,256,256,256,256
+};
+static const int blocksize_long_44[11]={
+ 4096,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048
+};
+
+static const double _psy_compand_short_mapping[12]={
+ 0.5, 1., 1., 1.3, 1.6, 2., 2., 2., 2., 2., 2., 2.
+};
+static const double _psy_compand_long_mapping[12]={
+ 3.5, 4., 4., 4.3, 4.6, 5., 5., 5., 5., 5., 5., 5.
+};
+
+static const double _global_mapping_44[12]={
+ /* 1., 1., 1.5, 2., 2., 2.5, 2.7, 3.0, 3.5, 4., 4. */
+ 0., 1., 1., 1.5, 2., 2., 2.5, 2.7, 3.0, 3.7, 4., 4.
+};
+
+static const int _floor_mapping_44a[11]={
+ 1,0,0,2,2,4,5,5,5,5,5
+};
+
+static const int _floor_mapping_44b[11]={
+ 8,7,7,7,7,7,7,7,7,7,7
+};
+
+static const int _floor_mapping_44c[11]={
+ 10,10,10,10,10,10,10,10,10,10,10
+};
+
+static const int *_floor_mapping_44[]={
+ _floor_mapping_44a,
+ _floor_mapping_44b,
+ _floor_mapping_44c,
+};
+
+static const ve_setup_data_template ve_setup_44_stereo={
+ 11,
+ rate_mapping_44_stereo,
+ quality_mapping_44,
+ 2,
+ 40000,
+ 50000,
+
+ blocksize_short_44,
+ blocksize_long_44,
+
+ _psy_tone_masteratt_44,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_otherblock,
+ _vp_tonemask_adj_longblock,
+ _vp_tonemask_adj_otherblock,
+
+ _psy_noiseguards_44,
+ _psy_noisebias_impulse,
+ _psy_noisebias_padding,
+ _psy_noisebias_trans,
+ _psy_noisebias_long,
+ _psy_noise_suppress,
+
+ _psy_compand_44,
+ _psy_compand_short_mapping,
+ _psy_compand_long_mapping,
+
+ {_noise_start_short_44,_noise_start_long_44},
+ {_noise_part_short_44,_noise_part_long_44},
+ _noise_thresh_44,
+
+ _psy_ath_floater,
+ _psy_ath_abs,
+
+ _psy_lowpass_44,
+
+ _psy_global_44,
+ _global_mapping_44,
+ _psy_stereo_modes_44,
+
+ _floor_books,
+ _floor,
+ 2,
+ _floor_mapping_44,
+
+ _mapres_template_44_stereo
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/setup_44p51.h b/external/libvorbis-1.3.5/lib/modes/setup_44p51.h
new file mode 100644
index 0000000..67d9979
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/setup_44p51.h
@@ -0,0 +1,74 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel settings for 44.1/48kHz 5.1 surround modes
+ last mod: $Id: setup_44p51.h 19013 2013-11-12 04:04:50Z giles $
+
+ ********************************************************************/
+
+#include "modes/residue_44p51.h"
+
+static const double rate_mapping_44p51[12]={
+ 14000.,20000.,28000.,38000.,46000.,54000.,
+ 75000.,96000.,120000.,140000.,180000.,240001.
+};
+
+static const ve_setup_data_template ve_setup_44_51={
+ 11,
+ rate_mapping_44p51,
+ quality_mapping_44,
+ 6,
+ 40000,
+ 70000,
+
+ blocksize_short_44,
+ blocksize_long_44,
+
+ _psy_tone_masteratt_44,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_otherblock,
+ _vp_tonemask_adj_longblock,
+ _vp_tonemask_adj_otherblock,
+
+ _psy_noiseguards_44,
+ _psy_noisebias_impulse,
+ _psy_noisebias_padding,
+ _psy_noisebias_trans,
+ _psy_noisebias_long,
+ _psy_noise_suppress,
+
+ _psy_compand_44,
+ _psy_compand_short_mapping,
+ _psy_compand_long_mapping,
+
+ {_noise_start_short_44,_noise_start_long_44},
+ {_noise_part_short_44,_noise_part_long_44},
+ _noise_thresh_44,
+
+ _psy_ath_floater,
+ _psy_ath_abs,
+
+ _psy_lowpass_44,
+
+ _psy_global_44,
+ _global_mapping_44,
+ _psy_stereo_modes_44,
+
+ _floor_books,
+ _floor,
+ 3,
+ _floor_mapping_44,
+
+ _mapres_template_44_51
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/setup_44u.h b/external/libvorbis-1.3.5/lib/modes/setup_44u.h
new file mode 100644
index 0000000..568b5f8
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/setup_44u.h
@@ -0,0 +1,74 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel settings for 44.1/48kHz uncoupled modes
+ last mod: $Id: setup_44u.h 16962 2010-03-11 07:30:34Z xiphmont $
+
+ ********************************************************************/
+
+#include "modes/residue_44u.h"
+
+static const double rate_mapping_44_un[12]={
+ 32000.,48000.,60000.,70000.,80000.,86000.,
+ 96000.,110000.,120000.,140000.,160000.,240001.
+};
+
+static const ve_setup_data_template ve_setup_44_uncoupled={
+ 11,
+ rate_mapping_44_un,
+ quality_mapping_44,
+ -1,
+ 40000,
+ 50000,
+
+ blocksize_short_44,
+ blocksize_long_44,
+
+ _psy_tone_masteratt_44,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_otherblock,
+ _vp_tonemask_adj_longblock,
+ _vp_tonemask_adj_otherblock,
+
+ _psy_noiseguards_44,
+ _psy_noisebias_impulse,
+ _psy_noisebias_padding,
+ _psy_noisebias_trans,
+ _psy_noisebias_long,
+ _psy_noise_suppress,
+
+ _psy_compand_44,
+ _psy_compand_short_mapping,
+ _psy_compand_long_mapping,
+
+ {_noise_start_short_44,_noise_start_long_44},
+ {_noise_part_short_44,_noise_part_long_44},
+ _noise_thresh_44,
+
+ _psy_ath_floater,
+ _psy_ath_abs,
+
+ _psy_lowpass_44,
+
+ _psy_global_44,
+ _global_mapping_44,
+ _psy_stereo_modes_44,
+
+ _floor_books,
+ _floor,
+ 2,
+ _floor_mapping_44,
+
+ _mapres_template_44_uncoupled
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/setup_8.h b/external/libvorbis-1.3.5/lib/modes/setup_8.h
new file mode 100644
index 0000000..14c4837
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/setup_8.h
@@ -0,0 +1,149 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: 8kHz settings
+ last mod: $Id: setup_8.h 16894 2010-02-12 20:32:12Z xiphmont $
+
+ ********************************************************************/
+
+#include "psych_8.h"
+#include "residue_8.h"
+
+static const int blocksize_8[2]={
+ 512,512
+};
+
+static const int _floor_mapping_8a[]={
+ 6,6
+};
+
+static const int *_floor_mapping_8[]={
+ _floor_mapping_8a
+};
+
+static const double rate_mapping_8[3]={
+ 6000.,9000.,32000.,
+};
+
+static const double rate_mapping_8_uncoupled[3]={
+ 8000.,14000.,42000.,
+};
+
+static const double quality_mapping_8[3]={
+ -.1,.0,1.
+};
+
+static const double _psy_compand_8_mapping[3]={ 0., 1., 1.};
+
+static const double _global_mapping_8[3]={ 1., 2., 3. };
+
+static const ve_setup_data_template ve_setup_8_stereo={
+ 2,
+ rate_mapping_8,
+ quality_mapping_8,
+ 2,
+ 8000,
+ 9000,
+
+ blocksize_8,
+ blocksize_8,
+
+ _psy_tone_masteratt_8,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_8,
+ NULL,
+ _vp_tonemask_adj_8,
+
+ _psy_noiseguards_8,
+ _psy_noisebias_8,
+ _psy_noisebias_8,
+ NULL,
+ NULL,
+ _psy_noise_suppress,
+
+ _psy_compand_8,
+ _psy_compand_8_mapping,
+ NULL,
+
+ {_noise_start_8,_noise_start_8},
+ {_noise_part_8,_noise_part_8},
+ _noise_thresh_5only,
+
+ _psy_ath_floater_8,
+ _psy_ath_abs_8,
+
+ _psy_lowpass_8,
+
+ _psy_global_44,
+ _global_mapping_8,
+ _psy_stereo_modes_8,
+
+ _floor_books,
+ _floor,
+ 1,
+ _floor_mapping_8,
+
+ _mapres_template_8_stereo
+};
+
+static const ve_setup_data_template ve_setup_8_uncoupled={
+ 2,
+ rate_mapping_8_uncoupled,
+ quality_mapping_8,
+ -1,
+ 8000,
+ 9000,
+
+ blocksize_8,
+ blocksize_8,
+
+ _psy_tone_masteratt_8,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_8,
+ NULL,
+ _vp_tonemask_adj_8,
+
+ _psy_noiseguards_8,
+ _psy_noisebias_8,
+ _psy_noisebias_8,
+ NULL,
+ NULL,
+ _psy_noise_suppress,
+
+ _psy_compand_8,
+ _psy_compand_8_mapping,
+ NULL,
+
+ {_noise_start_8,_noise_start_8},
+ {_noise_part_8,_noise_part_8},
+ _noise_thresh_5only,
+
+ _psy_ath_floater_8,
+ _psy_ath_abs_8,
+
+ _psy_lowpass_8,
+
+ _psy_global_44,
+ _global_mapping_8,
+ _psy_stereo_modes_8,
+
+ _floor_books,
+ _floor,
+ 1,
+ _floor_mapping_8,
+
+ _mapres_template_8_uncoupled
+};
diff --git a/external/libvorbis-1.3.5/lib/modes/setup_X.h b/external/libvorbis-1.3.5/lib/modes/setup_X.h
new file mode 100644
index 0000000..a69f5d4
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/modes/setup_X.h
@@ -0,0 +1,225 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: catch-all toplevel settings for q modes only
+ last mod: $Id: setup_X.h 16894 2010-02-12 20:32:12Z xiphmont $
+
+ ********************************************************************/
+
+static const double rate_mapping_X[12]={
+ -1.,-1.,-1.,-1.,-1.,-1.,
+ -1.,-1.,-1.,-1.,-1.,-1.
+};
+
+static const ve_setup_data_template ve_setup_X_stereo={
+ 11,
+ rate_mapping_X,
+ quality_mapping_44,
+ 2,
+ 50000,
+ 200000,
+
+ blocksize_short_44,
+ blocksize_long_44,
+
+ _psy_tone_masteratt_44,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_otherblock,
+ _vp_tonemask_adj_longblock,
+ _vp_tonemask_adj_otherblock,
+
+ _psy_noiseguards_44,
+ _psy_noisebias_impulse,
+ _psy_noisebias_padding,
+ _psy_noisebias_trans,
+ _psy_noisebias_long,
+ _psy_noise_suppress,
+
+ _psy_compand_44,
+ _psy_compand_short_mapping,
+ _psy_compand_long_mapping,
+
+ {_noise_start_short_44,_noise_start_long_44},
+ {_noise_part_short_44,_noise_part_long_44},
+ _noise_thresh_44,
+
+ _psy_ath_floater,
+ _psy_ath_abs,
+
+ _psy_lowpass_44,
+
+ _psy_global_44,
+ _global_mapping_44,
+ _psy_stereo_modes_44,
+
+ _floor_books,
+ _floor,
+ 2,
+ _floor_mapping_44,
+
+ _mapres_template_44_stereo
+};
+
+static const ve_setup_data_template ve_setup_X_uncoupled={
+ 11,
+ rate_mapping_X,
+ quality_mapping_44,
+ -1,
+ 50000,
+ 200000,
+
+ blocksize_short_44,
+ blocksize_long_44,
+
+ _psy_tone_masteratt_44,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_otherblock,
+ _vp_tonemask_adj_longblock,
+ _vp_tonemask_adj_otherblock,
+
+ _psy_noiseguards_44,
+ _psy_noisebias_impulse,
+ _psy_noisebias_padding,
+ _psy_noisebias_trans,
+ _psy_noisebias_long,
+ _psy_noise_suppress,
+
+ _psy_compand_44,
+ _psy_compand_short_mapping,
+ _psy_compand_long_mapping,
+
+ {_noise_start_short_44,_noise_start_long_44},
+ {_noise_part_short_44,_noise_part_long_44},
+ _noise_thresh_44,
+
+ _psy_ath_floater,
+ _psy_ath_abs,
+
+ _psy_lowpass_44,
+
+ _psy_global_44,
+ _global_mapping_44,
+ NULL,
+
+ _floor_books,
+ _floor,
+ 2,
+ _floor_mapping_44,
+
+ _mapres_template_44_uncoupled
+};
+
+static const ve_setup_data_template ve_setup_XX_stereo={
+ 2,
+ rate_mapping_X,
+ quality_mapping_8,
+ 2,
+ 0,
+ 8000,
+
+ blocksize_8,
+ blocksize_8,
+
+ _psy_tone_masteratt_8,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_8,
+ NULL,
+ _vp_tonemask_adj_8,
+
+ _psy_noiseguards_8,
+ _psy_noisebias_8,
+ _psy_noisebias_8,
+ NULL,
+ NULL,
+ _psy_noise_suppress,
+
+ _psy_compand_8,
+ _psy_compand_8_mapping,
+ NULL,
+
+ {_noise_start_8,_noise_start_8},
+ {_noise_part_8,_noise_part_8},
+ _noise_thresh_5only,
+
+ _psy_ath_floater_8,
+ _psy_ath_abs_8,
+
+ _psy_lowpass_8,
+
+ _psy_global_44,
+ _global_mapping_8,
+ _psy_stereo_modes_8,
+
+ _floor_books,
+ _floor,
+ 1,
+ _floor_mapping_8,
+
+ _mapres_template_8_stereo
+};
+
+static const ve_setup_data_template ve_setup_XX_uncoupled={
+ 2,
+ rate_mapping_X,
+ quality_mapping_8,
+ -1,
+ 0,
+ 8000,
+
+ blocksize_8,
+ blocksize_8,
+
+ _psy_tone_masteratt_8,
+ _psy_tone_0dB,
+ _psy_tone_suppress,
+
+ _vp_tonemask_adj_8,
+ NULL,
+ _vp_tonemask_adj_8,
+
+ _psy_noiseguards_8,
+ _psy_noisebias_8,
+ _psy_noisebias_8,
+ NULL,
+ NULL,
+ _psy_noise_suppress,
+
+ _psy_compand_8,
+ _psy_compand_8_mapping,
+ NULL,
+
+ {_noise_start_8,_noise_start_8},
+ {_noise_part_8,_noise_part_8},
+ _noise_thresh_5only,
+
+ _psy_ath_floater_8,
+ _psy_ath_abs_8,
+
+ _psy_lowpass_8,
+
+ _psy_global_44,
+ _global_mapping_8,
+ _psy_stereo_modes_8,
+
+ _floor_books,
+ _floor,
+ 1,
+ _floor_mapping_8,
+
+ _mapres_template_8_uncoupled
+};
diff --git a/external/libvorbis-1.3.5/lib/os.h b/external/libvorbis-1.3.5/lib/os.h
new file mode 100644
index 0000000..8bc3e5f
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/os.h
@@ -0,0 +1,191 @@
+#ifndef _OS_H
+#define _OS_H
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: #ifdef jail to whip a few platforms into the UNIX ideal.
+ last mod: $Id: os.h 19457 2015-03-03 00:15:29Z giles $
+
+ ********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <ogg/os_types.h>
+
+#include "misc.h"
+
+#ifndef _V_IFDEFJAIL_H_
+# define _V_IFDEFJAIL_H_
+
+# ifdef __GNUC__
+# define STIN static __inline__
+# elif _WIN32
+# define STIN static __inline
+# else
+# define STIN static
+# endif
+
+#ifdef DJGPP
+# define rint(x) (floor((x)+0.5f))
+#endif
+
+#ifndef M_PI
+# define M_PI (3.1415926536f)
+#endif
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+# include <malloc.h>
+# define rint(x) (floor((x)+0.5f))
+# define NO_FLOAT_MATH_LIB
+# define FAST_HYPOT(a, b) sqrt((a)*(a) + (b)*(b))
+#endif
+
+#if defined(__SYMBIAN32__) && defined(__WINS__)
+void *_alloca(size_t size);
+# define alloca _alloca
+#endif
+
+#ifndef FAST_HYPOT
+# define FAST_HYPOT hypot
+#endif
+
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
+
+#ifdef USE_MEMORY_H
+# include <memory.h>
+#endif
+
+#ifndef min
+# define min(x,y) ((x)>(y)?(y):(x))
+#endif
+
+#ifndef max
+# define max(x,y) ((x)<(y)?(y):(x))
+#endif
+
+
+/* Special i386 GCC implementation */
+#if defined(__i386__) && defined(__GNUC__) && !defined(__BEOS__)
+# define VORBIS_FPU_CONTROL
+/* both GCC and MSVC are kinda stupid about rounding/casting to int.
+ Because of encapsulation constraints (GCC can't see inside the asm
+ block and so we end up doing stupid things like a store/load that
+ is collectively a noop), we do it this way */
+
+/* we must set up the fpu before this works!! */
+
+typedef ogg_int16_t vorbis_fpu_control;
+
+static inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){
+ ogg_int16_t ret;
+ ogg_int16_t temp;
+ __asm__ __volatile__("fnstcw %0\n\t"
+ "movw %0,%%dx\n\t"
+ "andw $62463,%%dx\n\t"
+ "movw %%dx,%1\n\t"
+ "fldcw %1\n\t":"=m"(ret):"m"(temp): "dx");
+ *fpu=ret;
+}
+
+static inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
+ __asm__ __volatile__("fldcw %0":: "m"(fpu));
+}
+
+/* assumes the FPU is in round mode! */
+static inline int vorbis_ftoi(double f){ /* yes, double! Otherwise,
+ we get extra fst/fld to
+ truncate precision */
+ int i;
+ __asm__("fistl %0": "=m"(i) : "t"(f));
+ return(i);
+}
+#endif /* Special i386 GCC implementation */
+
+
+/* MSVC inline assembly. 32 bit only; inline ASM isn't implemented in the
+ * 64 bit compiler and doesn't work on arm. */
+#if defined(_MSC_VER) && !defined(_WIN64) && \
+ !defined(_WIN32_WCE) && !defined(_M_ARM)
+# define VORBIS_FPU_CONTROL
+
+typedef ogg_int16_t vorbis_fpu_control;
+
+static __inline int vorbis_ftoi(double f){
+ int i;
+ __asm{
+ fld f
+ fistp i
+ }
+ return i;
+}
+
+static __inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){
+ (void)fpu;
+}
+
+static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
+ (void)fpu;
+}
+
+#endif /* Special MSVC 32 bit implementation */
+
+
+/* Optimized code path for x86_64 builds. Uses SSE2 intrinsics. This can be
+ done safely because all x86_64 CPUs supports SSE2. */
+#if (defined(_MSC_VER) && defined(_WIN64)) || (defined(__GNUC__) && defined (__x86_64__))
+# define VORBIS_FPU_CONTROL
+
+typedef ogg_int16_t vorbis_fpu_control;
+
+#include <emmintrin.h>
+static __inline int vorbis_ftoi(double f){
+ return _mm_cvtsd_si32(_mm_load_sd(&f));
+}
+
+static __inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){
+ (void)fpu;
+}
+
+static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
+ (void)fpu;
+}
+
+#endif /* Special MSVC x64 implementation */
+
+
+/* If no special implementation was found for the current compiler / platform,
+ use the default implementation here: */
+#ifndef VORBIS_FPU_CONTROL
+
+typedef int vorbis_fpu_control;
+
+static int vorbis_ftoi(double f){
+ /* Note: MSVC and GCC (at least on some systems) round towards zero, thus,
+ the floor() call is required to ensure correct roudning of
+ negative numbers */
+ return (int)floor(f+.5);
+}
+
+/* We don't have special code for this compiler/arch, so do it the slow way */
+# define vorbis_fpu_setround(vorbis_fpu_control) {}
+# define vorbis_fpu_restore(vorbis_fpu_control) {}
+
+#endif /* default implementation */
+
+#endif /* _OS_H */
diff --git a/external/libvorbis-1.3.5/lib/psy.c b/external/libvorbis-1.3.5/lib/psy.c
new file mode 100644
index 0000000..f7a44c6
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/psy.c
@@ -0,0 +1,1206 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: psychoacoustics not including preecho
+ last mod: $Id: psy.c 18077 2011-09-02 02:49:00Z giles $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+
+#include "masking.h"
+#include "psy.h"
+#include "os.h"
+#include "lpc.h"
+#include "smallft.h"
+#include "scales.h"
+#include "misc.h"
+
+#define NEGINF -9999.f
+static const double stereo_threshholds[]={0.0, .5, 1.0, 1.5, 2.5, 4.5, 8.5, 16.5, 9e10};
+static const double stereo_threshholds_limited[]={0.0, .5, 1.0, 1.5, 2.0, 2.5, 4.5, 8.5, 9e10};
+
+vorbis_look_psy_global *_vp_global_look(vorbis_info *vi){
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy_global *gi=&ci->psy_g_param;
+ vorbis_look_psy_global *look=_ogg_calloc(1,sizeof(*look));
+
+ look->channels=vi->channels;
+
+ look->ampmax=-9999.;
+ look->gi=gi;
+ return(look);
+}
+
+void _vp_global_free(vorbis_look_psy_global *look){
+ if(look){
+ memset(look,0,sizeof(*look));
+ _ogg_free(look);
+ }
+}
+
+void _vi_gpsy_free(vorbis_info_psy_global *i){
+ if(i){
+ memset(i,0,sizeof(*i));
+ _ogg_free(i);
+ }
+}
+
+void _vi_psy_free(vorbis_info_psy *i){
+ if(i){
+ memset(i,0,sizeof(*i));
+ _ogg_free(i);
+ }
+}
+
+static void min_curve(float *c,
+ float *c2){
+ int i;
+ for(i=0;i<EHMER_MAX;i++)if(c2[i]<c[i])c[i]=c2[i];
+}
+static void max_curve(float *c,
+ float *c2){
+ int i;
+ for(i=0;i<EHMER_MAX;i++)if(c2[i]>c[i])c[i]=c2[i];
+}
+
+static void attenuate_curve(float *c,float att){
+ int i;
+ for(i=0;i<EHMER_MAX;i++)
+ c[i]+=att;
+}
+
+static float ***setup_tone_curves(float curveatt_dB[P_BANDS],float binHz,int n,
+ float center_boost, float center_decay_rate){
+ int i,j,k,m;
+ float ath[EHMER_MAX];
+ float workc[P_BANDS][P_LEVELS][EHMER_MAX];
+ float athc[P_LEVELS][EHMER_MAX];
+ float *brute_buffer=alloca(n*sizeof(*brute_buffer));
+
+ float ***ret=_ogg_malloc(sizeof(*ret)*P_BANDS);
+
+ memset(workc,0,sizeof(workc));
+
+ for(i=0;i<P_BANDS;i++){
+ /* we add back in the ATH to avoid low level curves falling off to
+ -infinity and unnecessarily cutting off high level curves in the
+ curve limiting (last step). */
+
+ /* A half-band's settings must be valid over the whole band, and
+ it's better to mask too little than too much */
+ int ath_offset=i*4;
+ for(j=0;j<EHMER_MAX;j++){
+ float min=999.;
+ for(k=0;k<4;k++)
+ if(j+k+ath_offset<MAX_ATH){
+ if(min>ATH[j+k+ath_offset])min=ATH[j+k+ath_offset];
+ }else{
+ if(min>ATH[MAX_ATH-1])min=ATH[MAX_ATH-1];
+ }
+ ath[j]=min;
+ }
+
+ /* copy curves into working space, replicate the 50dB curve to 30
+ and 40, replicate the 100dB curve to 110 */
+ for(j=0;j<6;j++)
+ memcpy(workc[i][j+2],tonemasks[i][j],EHMER_MAX*sizeof(*tonemasks[i][j]));
+ memcpy(workc[i][0],tonemasks[i][0],EHMER_MAX*sizeof(*tonemasks[i][0]));
+ memcpy(workc[i][1],tonemasks[i][0],EHMER_MAX*sizeof(*tonemasks[i][0]));
+
+ /* apply centered curve boost/decay */
+ for(j=0;j<P_LEVELS;j++){
+ for(k=0;k<EHMER_MAX;k++){
+ float adj=center_boost+abs(EHMER_OFFSET-k)*center_decay_rate;
+ if(adj<0. && center_boost>0)adj=0.;
+ if(adj>0. && center_boost<0)adj=0.;
+ workc[i][j][k]+=adj;
+ }
+ }
+
+ /* normalize curves so the driving amplitude is 0dB */
+ /* make temp curves with the ATH overlayed */
+ for(j=0;j<P_LEVELS;j++){
+ attenuate_curve(workc[i][j],curveatt_dB[i]+100.-(j<2?2:j)*10.-P_LEVEL_0);
+ memcpy(athc[j],ath,EHMER_MAX*sizeof(**athc));
+ attenuate_curve(athc[j],+100.-j*10.f-P_LEVEL_0);
+ max_curve(athc[j],workc[i][j]);
+ }
+
+ /* Now limit the louder curves.
+
+ the idea is this: We don't know what the playback attenuation
+ will be; 0dB SL moves every time the user twiddles the volume
+ knob. So that means we have to use a single 'most pessimal' curve
+ for all masking amplitudes, right? Wrong. The *loudest* sound
+ can be in (we assume) a range of ...+100dB] SL. However, sounds
+ 20dB down will be in a range ...+80], 40dB down is from ...+60],
+ etc... */
+
+ for(j=1;j<P_LEVELS;j++){
+ min_curve(athc[j],athc[j-1]);
+ min_curve(workc[i][j],athc[j]);
+ }
+ }
+
+ for(i=0;i<P_BANDS;i++){
+ int hi_curve,lo_curve,bin;
+ ret[i]=_ogg_malloc(sizeof(**ret)*P_LEVELS);
+
+ /* low frequency curves are measured with greater resolution than
+ the MDCT/FFT will actually give us; we want the curve applied
+ to the tone data to be pessimistic and thus apply the minimum
+ masking possible for a given bin. That means that a single bin
+ could span more than one octave and that the curve will be a
+ composite of multiple octaves. It also may mean that a single
+ bin may span > an eighth of an octave and that the eighth
+ octave values may also be composited. */
+
+ /* which octave curves will we be compositing? */
+ bin=floor(fromOC(i*.5)/binHz);
+ lo_curve= ceil(toOC(bin*binHz+1)*2);
+ hi_curve= floor(toOC((bin+1)*binHz)*2);
+ if(lo_curve>i)lo_curve=i;
+ if(lo_curve<0)lo_curve=0;
+ if(hi_curve>=P_BANDS)hi_curve=P_BANDS-1;
+
+ for(m=0;m<P_LEVELS;m++){
+ ret[i][m]=_ogg_malloc(sizeof(***ret)*(EHMER_MAX+2));
+
+ for(j=0;j<n;j++)brute_buffer[j]=999.;
+
+ /* render the curve into bins, then pull values back into curve.
+ The point is that any inherent subsampling aliasing results in
+ a safe minimum */
+ for(k=lo_curve;k<=hi_curve;k++){
+ int l=0;
+
+ for(j=0;j<EHMER_MAX;j++){
+ int lo_bin= fromOC(j*.125+k*.5-2.0625)/binHz;
+ int hi_bin= fromOC(j*.125+k*.5-1.9375)/binHz+1;
+
+ if(lo_bin<0)lo_bin=0;
+ if(lo_bin>n)lo_bin=n;
+ if(lo_bin<l)l=lo_bin;
+ if(hi_bin<0)hi_bin=0;
+ if(hi_bin>n)hi_bin=n;
+
+ for(;l<hi_bin && l<n;l++)
+ if(brute_buffer[l]>workc[k][m][j])
+ brute_buffer[l]=workc[k][m][j];
+ }
+
+ for(;l<n;l++)
+ if(brute_buffer[l]>workc[k][m][EHMER_MAX-1])
+ brute_buffer[l]=workc[k][m][EHMER_MAX-1];
+
+ }
+
+ /* be equally paranoid about being valid up to next half ocatve */
+ if(i+1<P_BANDS){
+ int l=0;
+ k=i+1;
+ for(j=0;j<EHMER_MAX;j++){
+ int lo_bin= fromOC(j*.125+i*.5-2.0625)/binHz;
+ int hi_bin= fromOC(j*.125+i*.5-1.9375)/binHz+1;
+
+ if(lo_bin<0)lo_bin=0;
+ if(lo_bin>n)lo_bin=n;
+ if(lo_bin<l)l=lo_bin;
+ if(hi_bin<0)hi_bin=0;
+ if(hi_bin>n)hi_bin=n;
+
+ for(;l<hi_bin && l<n;l++)
+ if(brute_buffer[l]>workc[k][m][j])
+ brute_buffer[l]=workc[k][m][j];
+ }
+
+ for(;l<n;l++)
+ if(brute_buffer[l]>workc[k][m][EHMER_MAX-1])
+ brute_buffer[l]=workc[k][m][EHMER_MAX-1];
+
+ }
+
+
+ for(j=0;j<EHMER_MAX;j++){
+ int bin=fromOC(j*.125+i*.5-2.)/binHz;
+ if(bin<0){
+ ret[i][m][j+2]=-999.;
+ }else{
+ if(bin>=n){
+ ret[i][m][j+2]=-999.;
+ }else{
+ ret[i][m][j+2]=brute_buffer[bin];
+ }
+ }
+ }
+
+ /* add fenceposts */
+ for(j=0;j<EHMER_OFFSET;j++)
+ if(ret[i][m][j+2]>-200.f)break;
+ ret[i][m][0]=j;
+
+ for(j=EHMER_MAX-1;j>EHMER_OFFSET+1;j--)
+ if(ret[i][m][j+2]>-200.f)
+ break;
+ ret[i][m][1]=j;
+
+ }
+ }
+
+ return(ret);
+}
+
+void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi,
+ vorbis_info_psy_global *gi,int n,long rate){
+ long i,j,lo=-99,hi=1;
+ long maxoc;
+ memset(p,0,sizeof(*p));
+
+ p->eighth_octave_lines=gi->eighth_octave_lines;
+ p->shiftoc=rint(log(gi->eighth_octave_lines*8.f)/log(2.f))-1;
+
+ p->firstoc=toOC(.25f*rate*.5/n)*(1<<(p->shiftoc+1))-gi->eighth_octave_lines;
+ maxoc=toOC((n+.25f)*rate*.5/n)*(1<<(p->shiftoc+1))+.5f;
+ p->total_octave_lines=maxoc-p->firstoc+1;
+ p->ath=_ogg_malloc(n*sizeof(*p->ath));
+
+ p->octave=_ogg_malloc(n*sizeof(*p->octave));
+ p->bark=_ogg_malloc(n*sizeof(*p->bark));
+ p->vi=vi;
+ p->n=n;
+ p->rate=rate;
+
+ /* AoTuV HF weighting */
+ p->m_val = 1.;
+ if(rate < 26000) p->m_val = 0;
+ else if(rate < 38000) p->m_val = .94; /* 32kHz */
+ else if(rate > 46000) p->m_val = 1.275; /* 48kHz */
+
+ /* set up the lookups for a given blocksize and sample rate */
+
+ for(i=0,j=0;i<MAX_ATH-1;i++){
+ int endpos=rint(fromOC((i+1)*.125-2.)*2*n/rate);
+ float base=ATH[i];
+ if(j<endpos){
+ float delta=(ATH[i+1]-base)/(endpos-j);
+ for(;j<endpos && j<n;j++){
+ p->ath[j]=base+100.;
+ base+=delta;
+ }
+ }
+ }
+
+ for(;j<n;j++){
+ p->ath[j]=p->ath[j-1];
+ }
+
+ for(i=0;i<n;i++){
+ float bark=toBARK(rate/(2*n)*i);
+
+ for(;lo+vi->noisewindowlomin<i &&
+ toBARK(rate/(2*n)*lo)<(bark-vi->noisewindowlo);lo++);
+
+ for(;hi<=n && (hi<i+vi->noisewindowhimin ||
+ toBARK(rate/(2*n)*hi)<(bark+vi->noisewindowhi));hi++);
+
+ p->bark[i]=((lo-1)<<16)+(hi-1);
+
+ }
+
+ for(i=0;i<n;i++)
+ p->octave[i]=toOC((i+.25f)*.5*rate/n)*(1<<(p->shiftoc+1))+.5f;
+
+ p->tonecurves=setup_tone_curves(vi->toneatt,rate*.5/n,n,
+ vi->tone_centerboost,vi->tone_decay);
+
+ /* set up rolling noise median */
+ p->noiseoffset=_ogg_malloc(P_NOISECURVES*sizeof(*p->noiseoffset));
+ for(i=0;i<P_NOISECURVES;i++)
+ p->noiseoffset[i]=_ogg_malloc(n*sizeof(**p->noiseoffset));
+
+ for(i=0;i<n;i++){
+ float halfoc=toOC((i+.5)*rate/(2.*n))*2.;
+ int inthalfoc;
+ float del;
+
+ if(halfoc<0)halfoc=0;
+ if(halfoc>=P_BANDS-1)halfoc=P_BANDS-1;
+ inthalfoc=(int)halfoc;
+ del=halfoc-inthalfoc;
+
+ for(j=0;j<P_NOISECURVES;j++)
+ p->noiseoffset[j][i]=
+ p->vi->noiseoff[j][inthalfoc]*(1.-del) +
+ p->vi->noiseoff[j][inthalfoc+1]*del;
+
+ }
+#if 0
+ {
+ static int ls=0;
+ _analysis_output_always("noiseoff0",ls,p->noiseoffset[0],n,1,0,0);
+ _analysis_output_always("noiseoff1",ls,p->noiseoffset[1],n,1,0,0);
+ _analysis_output_always("noiseoff2",ls++,p->noiseoffset[2],n,1,0,0);
+ }
+#endif
+}
+
+void _vp_psy_clear(vorbis_look_psy *p){
+ int i,j;
+ if(p){
+ if(p->ath)_ogg_free(p->ath);
+ if(p->octave)_ogg_free(p->octave);
+ if(p->bark)_ogg_free(p->bark);
+ if(p->tonecurves){
+ for(i=0;i<P_BANDS;i++){
+ for(j=0;j<P_LEVELS;j++){
+ _ogg_free(p->tonecurves[i][j]);
+ }
+ _ogg_free(p->tonecurves[i]);
+ }
+ _ogg_free(p->tonecurves);
+ }
+ if(p->noiseoffset){
+ for(i=0;i<P_NOISECURVES;i++){
+ _ogg_free(p->noiseoffset[i]);
+ }
+ _ogg_free(p->noiseoffset);
+ }
+ memset(p,0,sizeof(*p));
+ }
+}
+
+/* octave/(8*eighth_octave_lines) x scale and dB y scale */
+static void seed_curve(float *seed,
+ const float **curves,
+ float amp,
+ int oc, int n,
+ int linesper,float dBoffset){
+ int i,post1;
+ int seedptr;
+ const float *posts,*curve;
+
+ int choice=(int)((amp+dBoffset-P_LEVEL_0)*.1f);
+ choice=max(choice,0);
+ choice=min(choice,P_LEVELS-1);
+ posts=curves[choice];
+ curve=posts+2;
+ post1=(int)posts[1];
+ seedptr=oc+(posts[0]-EHMER_OFFSET)*linesper-(linesper>>1);
+
+ for(i=posts[0];i<post1;i++){
+ if(seedptr>0){
+ float lin=amp+curve[i];
+ if(seed[seedptr]<lin)seed[seedptr]=lin;
+ }
+ seedptr+=linesper;
+ if(seedptr>=n)break;
+ }
+}
+
+static void seed_loop(vorbis_look_psy *p,
+ const float ***curves,
+ const float *f,
+ const float *flr,
+ float *seed,
+ float specmax){
+ vorbis_info_psy *vi=p->vi;
+ long n=p->n,i;
+ float dBoffset=vi->max_curve_dB-specmax;
+
+ /* prime the working vector with peak values */
+
+ for(i=0;i<n;i++){
+ float max=f[i];
+ long oc=p->octave[i];
+ while(i+1<n && p->octave[i+1]==oc){
+ i++;
+ if(f[i]>max)max=f[i];
+ }
+
+ if(max+6.f>flr[i]){
+ oc=oc>>p->shiftoc;
+
+ if(oc>=P_BANDS)oc=P_BANDS-1;
+ if(oc<0)oc=0;
+
+ seed_curve(seed,
+ curves[oc],
+ max,
+ p->octave[i]-p->firstoc,
+ p->total_octave_lines,
+ p->eighth_octave_lines,
+ dBoffset);
+ }
+ }
+}
+
+static void seed_chase(float *seeds, int linesper, long n){
+ long *posstack=alloca(n*sizeof(*posstack));
+ float *ampstack=alloca(n*sizeof(*ampstack));
+ long stack=0;
+ long pos=0;
+ long i;
+
+ for(i=0;i<n;i++){
+ if(stack<2){
+ posstack[stack]=i;
+ ampstack[stack++]=seeds[i];
+ }else{
+ while(1){
+ if(seeds[i]<ampstack[stack-1]){
+ posstack[stack]=i;
+ ampstack[stack++]=seeds[i];
+ break;
+ }else{
+ if(i<posstack[stack-1]+linesper){
+ if(stack>1 && ampstack[stack-1]<=ampstack[stack-2] &&
+ i<posstack[stack-2]+linesper){
+ /* we completely overlap, making stack-1 irrelevant. pop it */
+ stack--;
+ continue;
+ }
+ }
+ posstack[stack]=i;
+ ampstack[stack++]=seeds[i];
+ break;
+
+ }
+ }
+ }
+ }
+
+ /* the stack now contains only the positions that are relevant. Scan
+ 'em straight through */
+
+ for(i=0;i<stack;i++){
+ long endpos;
+ if(i<stack-1 && ampstack[i+1]>ampstack[i]){
+ endpos=posstack[i+1];
+ }else{
+ endpos=posstack[i]+linesper+1; /* +1 is important, else bin 0 is
+ discarded in short frames */
+ }
+ if(endpos>n)endpos=n;
+ for(;pos<endpos;pos++)
+ seeds[pos]=ampstack[i];
+ }
+
+ /* there. Linear time. I now remember this was on a problem set I
+ had in Grad Skool... I didn't solve it at the time ;-) */
+
+}
+
+/* bleaugh, this is more complicated than it needs to be */
+#include<stdio.h>
+static void max_seeds(vorbis_look_psy *p,
+ float *seed,
+ float *flr){
+ long n=p->total_octave_lines;
+ int linesper=p->eighth_octave_lines;
+ long linpos=0;
+ long pos;
+
+ seed_chase(seed,linesper,n); /* for masking */
+
+ pos=p->octave[0]-p->firstoc-(linesper>>1);
+
+ while(linpos+1<p->n){
+ float minV=seed[pos];
+ long end=((p->octave[linpos]+p->octave[linpos+1])>>1)-p->firstoc;
+ if(minV>p->vi->tone_abs_limit)minV=p->vi->tone_abs_limit;
+ while(pos+1<=end){
+ pos++;
+ if((seed[pos]>NEGINF && seed[pos]<minV) || minV==NEGINF)
+ minV=seed[pos];
+ }
+
+ end=pos+p->firstoc;
+ for(;linpos<p->n && p->octave[linpos]<=end;linpos++)
+ if(flr[linpos]<minV)flr[linpos]=minV;
+ }
+
+ {
+ float minV=seed[p->total_octave_lines-1];
+ for(;linpos<p->n;linpos++)
+ if(flr[linpos]<minV)flr[linpos]=minV;
+ }
+
+}
+
+static void bark_noise_hybridmp(int n,const long *b,
+ const float *f,
+ float *noise,
+ const float offset,
+ const int fixed){
+
+ float *N=alloca(n*sizeof(*N));
+ float *X=alloca(n*sizeof(*N));
+ float *XX=alloca(n*sizeof(*N));
+ float *Y=alloca(n*sizeof(*N));
+ float *XY=alloca(n*sizeof(*N));
+
+ float tN, tX, tXX, tY, tXY;
+ int i;
+
+ int lo, hi;
+ float R=0.f;
+ float A=0.f;
+ float B=0.f;
+ float D=1.f;
+ float w, x, y;
+
+ tN = tX = tXX = tY = tXY = 0.f;
+
+ y = f[0] + offset;
+ if (y < 1.f) y = 1.f;
+
+ w = y * y * .5;
+
+ tN += w;
+ tX += w;
+ tY += w * y;
+
+ N[0] = tN;
+ X[0] = tX;
+ XX[0] = tXX;
+ Y[0] = tY;
+ XY[0] = tXY;
+
+ for (i = 1, x = 1.f; i < n; i++, x += 1.f) {
+
+ y = f[i] + offset;
+ if (y < 1.f) y = 1.f;
+
+ w = y * y;
+
+ tN += w;
+ tX += w * x;
+ tXX += w * x * x;
+ tY += w * y;
+ tXY += w * x * y;
+
+ N[i] = tN;
+ X[i] = tX;
+ XX[i] = tXX;
+ Y[i] = tY;
+ XY[i] = tXY;
+ }
+
+ for (i = 0, x = 0.f;; i++, x += 1.f) {
+
+ lo = b[i] >> 16;
+ if( lo>=0 ) break;
+ hi = b[i] & 0xffff;
+
+ tN = N[hi] + N[-lo];
+ tX = X[hi] - X[-lo];
+ tXX = XX[hi] + XX[-lo];
+ tY = Y[hi] + Y[-lo];
+ tXY = XY[hi] - XY[-lo];
+
+ A = tY * tXX - tX * tXY;
+ B = tN * tXY - tX * tY;
+ D = tN * tXX - tX * tX;
+ R = (A + x * B) / D;
+ if (R < 0.f)
+ R = 0.f;
+
+ noise[i] = R - offset;
+ }
+
+ for ( ;; i++, x += 1.f) {
+
+ lo = b[i] >> 16;
+ hi = b[i] & 0xffff;
+ if(hi>=n)break;
+
+ tN = N[hi] - N[lo];
+ tX = X[hi] - X[lo];
+ tXX = XX[hi] - XX[lo];
+ tY = Y[hi] - Y[lo];
+ tXY = XY[hi] - XY[lo];
+
+ A = tY * tXX - tX * tXY;
+ B = tN * tXY - tX * tY;
+ D = tN * tXX - tX * tX;
+ R = (A + x * B) / D;
+ if (R < 0.f) R = 0.f;
+
+ noise[i] = R - offset;
+ }
+ for ( ; i < n; i++, x += 1.f) {
+
+ R = (A + x * B) / D;
+ if (R < 0.f) R = 0.f;
+
+ noise[i] = R - offset;
+ }
+
+ if (fixed <= 0) return;
+
+ for (i = 0, x = 0.f;; i++, x += 1.f) {
+ hi = i + fixed / 2;
+ lo = hi - fixed;
+ if(lo>=0)break;
+
+ tN = N[hi] + N[-lo];
+ tX = X[hi] - X[-lo];
+ tXX = XX[hi] + XX[-lo];
+ tY = Y[hi] + Y[-lo];
+ tXY = XY[hi] - XY[-lo];
+
+
+ A = tY * tXX - tX * tXY;
+ B = tN * tXY - tX * tY;
+ D = tN * tXX - tX * tX;
+ R = (A + x * B) / D;
+
+ if (R - offset < noise[i]) noise[i] = R - offset;
+ }
+ for ( ;; i++, x += 1.f) {
+
+ hi = i + fixed / 2;
+ lo = hi - fixed;
+ if(hi>=n)break;
+
+ tN = N[hi] - N[lo];
+ tX = X[hi] - X[lo];
+ tXX = XX[hi] - XX[lo];
+ tY = Y[hi] - Y[lo];
+ tXY = XY[hi] - XY[lo];
+
+ A = tY * tXX - tX * tXY;
+ B = tN * tXY - tX * tY;
+ D = tN * tXX - tX * tX;
+ R = (A + x * B) / D;
+
+ if (R - offset < noise[i]) noise[i] = R - offset;
+ }
+ for ( ; i < n; i++, x += 1.f) {
+ R = (A + x * B) / D;
+ if (R - offset < noise[i]) noise[i] = R - offset;
+ }
+}
+
+void _vp_noisemask(vorbis_look_psy *p,
+ float *logmdct,
+ float *logmask){
+
+ int i,n=p->n;
+ float *work=alloca(n*sizeof(*work));
+
+ bark_noise_hybridmp(n,p->bark,logmdct,logmask,
+ 140.,-1);
+
+ for(i=0;i<n;i++)work[i]=logmdct[i]-logmask[i];
+
+ bark_noise_hybridmp(n,p->bark,work,logmask,0.,
+ p->vi->noisewindowfixed);
+
+ for(i=0;i<n;i++)work[i]=logmdct[i]-work[i];
+
+#if 0
+ {
+ static int seq=0;
+
+ float work2[n];
+ for(i=0;i<n;i++){
+ work2[i]=logmask[i]+work[i];
+ }
+
+ if(seq&1)
+ _analysis_output("median2R",seq/2,work,n,1,0,0);
+ else
+ _analysis_output("median2L",seq/2,work,n,1,0,0);
+
+ if(seq&1)
+ _analysis_output("envelope2R",seq/2,work2,n,1,0,0);
+ else
+ _analysis_output("envelope2L",seq/2,work2,n,1,0,0);
+ seq++;
+ }
+#endif
+
+ for(i=0;i<n;i++){
+ int dB=logmask[i]+.5;
+ if(dB>=NOISE_COMPAND_LEVELS)dB=NOISE_COMPAND_LEVELS-1;
+ if(dB<0)dB=0;
+ logmask[i]= work[i]+p->vi->noisecompand[dB];
+ }
+
+}
+
+void _vp_tonemask(vorbis_look_psy *p,
+ float *logfft,
+ float *logmask,
+ float global_specmax,
+ float local_specmax){
+
+ int i,n=p->n;
+
+ float *seed=alloca(sizeof(*seed)*p->total_octave_lines);
+ float att=local_specmax+p->vi->ath_adjatt;
+ for(i=0;i<p->total_octave_lines;i++)seed[i]=NEGINF;
+
+ /* set the ATH (floating below localmax, not global max by a
+ specified att) */
+ if(att<p->vi->ath_maxatt)att=p->vi->ath_maxatt;
+
+ for(i=0;i<n;i++)
+ logmask[i]=p->ath[i]+att;
+
+ /* tone masking */
+ seed_loop(p,(const float ***)p->tonecurves,logfft,logmask,seed,global_specmax);
+ max_seeds(p,seed,logmask);
+
+}
+
+void _vp_offset_and_mix(vorbis_look_psy *p,
+ float *noise,
+ float *tone,
+ int offset_select,
+ float *logmask,
+ float *mdct,
+ float *logmdct){
+ int i,n=p->n;
+ float de, coeffi, cx;/* AoTuV */
+ float toneatt=p->vi->tone_masteratt[offset_select];
+
+ cx = p->m_val;
+
+ for(i=0;i<n;i++){
+ float val= noise[i]+p->noiseoffset[offset_select][i];
+ if(val>p->vi->noisemaxsupp)val=p->vi->noisemaxsupp;
+ logmask[i]=max(val,tone[i]+toneatt);
+
+
+ /* AoTuV */
+ /** @ M1 **
+ The following codes improve a noise problem.
+ A fundamental idea uses the value of masking and carries out
+ the relative compensation of the MDCT.
+ However, this code is not perfect and all noise problems cannot be solved.
+ by Aoyumi @ 2004/04/18
+ */
+
+ if(offset_select == 1) {
+ coeffi = -17.2; /* coeffi is a -17.2dB threshold */
+ val = val - logmdct[i]; /* val == mdct line value relative to floor in dB */
+
+ if(val > coeffi){
+ /* mdct value is > -17.2 dB below floor */
+
+ de = 1.0-((val-coeffi)*0.005*cx);
+ /* pro-rated attenuation:
+ -0.00 dB boost if mdct value is -17.2dB (relative to floor)
+ -0.77 dB boost if mdct value is 0dB (relative to floor)
+ -1.64 dB boost if mdct value is +17.2dB (relative to floor)
+ etc... */
+
+ if(de < 0) de = 0.0001;
+ }else
+ /* mdct value is <= -17.2 dB below floor */
+
+ de = 1.0-((val-coeffi)*0.0003*cx);
+ /* pro-rated attenuation:
+ +0.00 dB atten if mdct value is -17.2dB (relative to floor)
+ +0.45 dB atten if mdct value is -34.4dB (relative to floor)
+ etc... */
+
+ mdct[i] *= de;
+
+ }
+ }
+}
+
+float _vp_ampmax_decay(float amp,vorbis_dsp_state *vd){
+ vorbis_info *vi=vd->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy_global *gi=&ci->psy_g_param;
+
+ int n=ci->blocksizes[vd->W]/2;
+ float secs=(float)n/vi->rate;
+
+ amp+=secs*gi->ampmax_att_per_sec;
+ if(amp<-9999)amp=-9999;
+ return(amp);
+}
+
+static float FLOOR1_fromdB_LOOKUP[256]={
+ 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F,
+ 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F,
+ 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F,
+ 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F,
+ 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F,
+ 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F,
+ 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F,
+ 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F,
+ 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F,
+ 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F,
+ 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F,
+ 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F,
+ 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F,
+ 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F,
+ 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F,
+ 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F,
+ 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F,
+ 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F,
+ 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F,
+ 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F,
+ 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F,
+ 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F,
+ 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F,
+ 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F,
+ 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F,
+ 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F,
+ 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F,
+ 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F,
+ 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F,
+ 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F,
+ 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F,
+ 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F,
+ 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F,
+ 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F,
+ 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F,
+ 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F,
+ 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F,
+ 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F,
+ 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F,
+ 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F,
+ 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F,
+ 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F,
+ 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F,
+ 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F,
+ 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F,
+ 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F,
+ 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F,
+ 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F,
+ 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F,
+ 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F,
+ 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F,
+ 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F,
+ 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F,
+ 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F,
+ 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F,
+ 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F,
+ 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F,
+ 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F,
+ 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F,
+ 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F,
+ 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F,
+ 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F,
+ 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F,
+ 0.82788260F, 0.88168307F, 0.9389798F, 1.F,
+};
+
+/* this is for per-channel noise normalization */
+static int apsort(const void *a, const void *b){
+ float f1=**(float**)a;
+ float f2=**(float**)b;
+ return (f1<f2)-(f1>f2);
+}
+
+static void flag_lossless(int limit, float prepoint, float postpoint, float *mdct,
+ float *floor, int *flag, int i, int jn){
+ int j;
+ for(j=0;j<jn;j++){
+ float point = j>=limit-i ? postpoint : prepoint;
+ float r = fabs(mdct[j])/floor[j];
+ if(r<point)
+ flag[j]=0;
+ else
+ flag[j]=1;
+ }
+}
+
+/* Overload/Side effect: On input, the *q vector holds either the
+ quantized energy (for elements with the flag set) or the absolute
+ values of the *r vector (for elements with flag unset). On output,
+ *q holds the quantized energy for all elements */
+static float noise_normalize(vorbis_look_psy *p, int limit, float *r, float *q, float *f, int *flags, float acc, int i, int n, int *out){
+
+ vorbis_info_psy *vi=p->vi;
+ float **sort = alloca(n*sizeof(*sort));
+ int j,count=0;
+ int start = (vi->normal_p ? vi->normal_start-i : n);
+ if(start>n)start=n;
+
+ /* force classic behavior where only energy in the current band is considered */
+ acc=0.f;
+
+ /* still responsible for populating *out where noise norm not in
+ effect. There's no need to [re]populate *q in these areas */
+ for(j=0;j<start;j++){
+ if(!flags || !flags[j]){ /* lossless coupling already quantized.
+ Don't touch; requantizing based on
+ energy would be incorrect. */
+ float ve = q[j]/f[j];
+ if(r[j]<0)
+ out[j] = -rint(sqrt(ve));
+ else
+ out[j] = rint(sqrt(ve));
+ }
+ }
+
+ /* sort magnitudes for noise norm portion of partition */
+ for(;j<n;j++){
+ if(!flags || !flags[j]){ /* can't noise norm elements that have
+ already been loslessly coupled; we can
+ only account for their energy error */
+ float ve = q[j]/f[j];
+ /* Despite all the new, more capable coupling code, for now we
+ implement noise norm as it has been up to this point. Only
+ consider promotions to unit magnitude from 0. In addition
+ the only energy error counted is quantizations to zero. */
+ /* also-- the original point code only applied noise norm at > pointlimit */
+ if(ve<.25f && (!flags || j>=limit-i)){
+ acc += ve;
+ sort[count++]=q+j; /* q is fabs(r) for unflagged element */
+ }else{
+ /* For now: no acc adjustment for nonzero quantization. populate *out and q as this value is final. */
+ if(r[j]<0)
+ out[j] = -rint(sqrt(ve));
+ else
+ out[j] = rint(sqrt(ve));
+ q[j] = out[j]*out[j]*f[j];
+ }
+ }/* else{
+ again, no energy adjustment for error in nonzero quant-- for now
+ }*/
+ }
+
+ if(count){
+ /* noise norm to do */
+ qsort(sort,count,sizeof(*sort),apsort);
+ for(j=0;j<count;j++){
+ int k=sort[j]-q;
+ if(acc>=vi->normal_thresh){
+ out[k]=unitnorm(r[k]);
+ acc-=1.f;
+ q[k]=f[k];
+ }else{
+ out[k]=0;
+ q[k]=0.f;
+ }
+ }
+ }
+
+ return acc;
+}
+
+/* Noise normalization, quantization and coupling are not wholly
+ seperable processes in depth>1 coupling. */
+void _vp_couple_quantize_normalize(int blobno,
+ vorbis_info_psy_global *g,
+ vorbis_look_psy *p,
+ vorbis_info_mapping0 *vi,
+ float **mdct,
+ int **iwork,
+ int *nonzero,
+ int sliding_lowpass,
+ int ch){
+
+ int i;
+ int n = p->n;
+ int partition=(p->vi->normal_p ? p->vi->normal_partition : 16);
+ int limit = g->coupling_pointlimit[p->vi->blockflag][blobno];
+ float prepoint=stereo_threshholds[g->coupling_prepointamp[blobno]];
+ float postpoint=stereo_threshholds[g->coupling_postpointamp[blobno]];
+#if 0
+ float de=0.1*p->m_val; /* a blend of the AoTuV M2 and M3 code here and below */
+#endif
+
+ /* mdct is our raw mdct output, floor not removed. */
+ /* inout passes in the ifloor, passes back quantized result */
+
+ /* unquantized energy (negative indicates amplitude has negative sign) */
+ float **raw = alloca(ch*sizeof(*raw));
+
+ /* dual pupose; quantized energy (if flag set), othersize fabs(raw) */
+ float **quant = alloca(ch*sizeof(*quant));
+
+ /* floor energy */
+ float **floor = alloca(ch*sizeof(*floor));
+
+ /* flags indicating raw/quantized status of elements in raw vector */
+ int **flag = alloca(ch*sizeof(*flag));
+
+ /* non-zero flag working vector */
+ int *nz = alloca(ch*sizeof(*nz));
+
+ /* energy surplus/defecit tracking */
+ float *acc = alloca((ch+vi->coupling_steps)*sizeof(*acc));
+
+ /* The threshold of a stereo is changed with the size of n */
+ if(n > 1000)
+ postpoint=stereo_threshholds_limited[g->coupling_postpointamp[blobno]];
+
+ raw[0] = alloca(ch*partition*sizeof(**raw));
+ quant[0] = alloca(ch*partition*sizeof(**quant));
+ floor[0] = alloca(ch*partition*sizeof(**floor));
+ flag[0] = alloca(ch*partition*sizeof(**flag));
+
+ for(i=1;i<ch;i++){
+ raw[i] = &raw[0][partition*i];
+ quant[i] = &quant[0][partition*i];
+ floor[i] = &floor[0][partition*i];
+ flag[i] = &flag[0][partition*i];
+ }
+ for(i=0;i<ch+vi->coupling_steps;i++)
+ acc[i]=0.f;
+
+ for(i=0;i<n;i+=partition){
+ int k,j,jn = partition > n-i ? n-i : partition;
+ int step,track = 0;
+
+ memcpy(nz,nonzero,sizeof(*nz)*ch);
+
+ /* prefill */
+ memset(flag[0],0,ch*partition*sizeof(**flag));
+ for(k=0;k<ch;k++){
+ int *iout = &iwork[k][i];
+ if(nz[k]){
+
+ for(j=0;j<jn;j++)
+ floor[k][j] = FLOOR1_fromdB_LOOKUP[iout[j]];
+
+ flag_lossless(limit,prepoint,postpoint,&mdct[k][i],floor[k],flag[k],i,jn);
+
+ for(j=0;j<jn;j++){
+ quant[k][j] = raw[k][j] = mdct[k][i+j]*mdct[k][i+j];
+ if(mdct[k][i+j]<0.f) raw[k][j]*=-1.f;
+ floor[k][j]*=floor[k][j];
+ }
+
+ acc[track]=noise_normalize(p,limit,raw[k],quant[k],floor[k],NULL,acc[track],i,jn,iout);
+
+ }else{
+ for(j=0;j<jn;j++){
+ floor[k][j] = 1e-10f;
+ raw[k][j] = 0.f;
+ quant[k][j] = 0.f;
+ flag[k][j] = 0;
+ iout[j]=0;
+ }
+ acc[track]=0.f;
+ }
+ track++;
+ }
+
+ /* coupling */
+ for(step=0;step<vi->coupling_steps;step++){
+ int Mi = vi->coupling_mag[step];
+ int Ai = vi->coupling_ang[step];
+ int *iM = &iwork[Mi][i];
+ int *iA = &iwork[Ai][i];
+ float *reM = raw[Mi];
+ float *reA = raw[Ai];
+ float *qeM = quant[Mi];
+ float *qeA = quant[Ai];
+ float *floorM = floor[Mi];
+ float *floorA = floor[Ai];
+ int *fM = flag[Mi];
+ int *fA = flag[Ai];
+
+ if(nz[Mi] || nz[Ai]){
+ nz[Mi] = nz[Ai] = 1;
+
+ for(j=0;j<jn;j++){
+
+ if(j<sliding_lowpass-i){
+ if(fM[j] || fA[j]){
+ /* lossless coupling */
+
+ reM[j] = fabs(reM[j])+fabs(reA[j]);
+ qeM[j] = qeM[j]+qeA[j];
+ fM[j]=fA[j]=1;
+
+ /* couple iM/iA */
+ {
+ int A = iM[j];
+ int B = iA[j];
+
+ if(abs(A)>abs(B)){
+ iA[j]=(A>0?A-B:B-A);
+ }else{
+ iA[j]=(B>0?A-B:B-A);
+ iM[j]=B;
+ }
+
+ /* collapse two equivalent tuples to one */
+ if(iA[j]>=abs(iM[j])*2){
+ iA[j]= -iA[j];
+ iM[j]= -iM[j];
+ }
+
+ }
+
+ }else{
+ /* lossy (point) coupling */
+ if(j<limit-i){
+ /* dipole */
+ reM[j] += reA[j];
+ qeM[j] = fabs(reM[j]);
+ }else{
+#if 0
+ /* AoTuV */
+ /** @ M2 **
+ The boost problem by the combination of noise normalization and point stereo is eased.
+ However, this is a temporary patch.
+ by Aoyumi @ 2004/04/18
+ */
+ float derate = (1.0 - de*((float)(j-limit+i) / (float)(n-limit)));
+ /* elliptical */
+ if(reM[j]+reA[j]<0){
+ reM[j] = - (qeM[j] = (fabs(reM[j])+fabs(reA[j]))*derate*derate);
+ }else{
+ reM[j] = (qeM[j] = (fabs(reM[j])+fabs(reA[j]))*derate*derate);
+ }
+#else
+ /* elliptical */
+ if(reM[j]+reA[j]<0){
+ reM[j] = - (qeM[j] = fabs(reM[j])+fabs(reA[j]));
+ }else{
+ reM[j] = (qeM[j] = fabs(reM[j])+fabs(reA[j]));
+ }
+#endif
+
+ }
+ reA[j]=qeA[j]=0.f;
+ fA[j]=1;
+ iA[j]=0;
+ }
+ }
+ floorM[j]=floorA[j]=floorM[j]+floorA[j];
+ }
+ /* normalize the resulting mag vector */
+ acc[track]=noise_normalize(p,limit,raw[Mi],quant[Mi],floor[Mi],flag[Mi],acc[track],i,jn,iM);
+ track++;
+ }
+ }
+ }
+
+ for(i=0;i<vi->coupling_steps;i++){
+ /* make sure coupling a zero and a nonzero channel results in two
+ nonzero channels. */
+ if(nonzero[vi->coupling_mag[i]] ||
+ nonzero[vi->coupling_ang[i]]){
+ nonzero[vi->coupling_mag[i]]=1;
+ nonzero[vi->coupling_ang[i]]=1;
+ }
+ }
+}
diff --git a/external/libvorbis-1.3.5/lib/psy.h b/external/libvorbis-1.3.5/lib/psy.h
new file mode 100644
index 0000000..c1ea824
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/psy.h
@@ -0,0 +1,154 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: random psychoacoustics (not including preecho)
+ last mod: $Id: psy.h 16946 2010-03-03 16:12:40Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_PSY_H_
+#define _V_PSY_H_
+#include "smallft.h"
+
+#include "backends.h"
+#include "envelope.h"
+
+#ifndef EHMER_MAX
+#define EHMER_MAX 56
+#endif
+
+/* psychoacoustic setup ********************************************/
+#define P_BANDS 17 /* 62Hz to 16kHz */
+#define P_LEVELS 8 /* 30dB to 100dB */
+#define P_LEVEL_0 30. /* 30 dB */
+#define P_NOISECURVES 3
+
+#define NOISE_COMPAND_LEVELS 40
+typedef struct vorbis_info_psy{
+ int blockflag;
+
+ float ath_adjatt;
+ float ath_maxatt;
+
+ float tone_masteratt[P_NOISECURVES];
+ float tone_centerboost;
+ float tone_decay;
+ float tone_abs_limit;
+ float toneatt[P_BANDS];
+
+ int noisemaskp;
+ float noisemaxsupp;
+ float noisewindowlo;
+ float noisewindowhi;
+ int noisewindowlomin;
+ int noisewindowhimin;
+ int noisewindowfixed;
+ float noiseoff[P_NOISECURVES][P_BANDS];
+ float noisecompand[NOISE_COMPAND_LEVELS];
+
+ float max_curve_dB;
+
+ int normal_p;
+ int normal_start;
+ int normal_partition;
+ double normal_thresh;
+} vorbis_info_psy;
+
+typedef struct{
+ int eighth_octave_lines;
+
+ /* for block long/short tuning; encode only */
+ float preecho_thresh[VE_BANDS];
+ float postecho_thresh[VE_BANDS];
+ float stretch_penalty;
+ float preecho_minenergy;
+
+ float ampmax_att_per_sec;
+
+ /* channel coupling config */
+ int coupling_pkHz[PACKETBLOBS];
+ int coupling_pointlimit[2][PACKETBLOBS];
+ int coupling_prepointamp[PACKETBLOBS];
+ int coupling_postpointamp[PACKETBLOBS];
+ int sliding_lowpass[2][PACKETBLOBS];
+
+} vorbis_info_psy_global;
+
+typedef struct {
+ float ampmax;
+ int channels;
+
+ vorbis_info_psy_global *gi;
+ int coupling_pointlimit[2][P_NOISECURVES];
+} vorbis_look_psy_global;
+
+
+typedef struct {
+ int n;
+ struct vorbis_info_psy *vi;
+
+ float ***tonecurves;
+ float **noiseoffset;
+
+ float *ath;
+ long *octave; /* in n.ocshift format */
+ long *bark;
+
+ long firstoc;
+ long shiftoc;
+ int eighth_octave_lines; /* power of two, please */
+ int total_octave_lines;
+ long rate; /* cache it */
+
+ float m_val; /* Masking compensation value */
+
+} vorbis_look_psy;
+
+extern void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi,
+ vorbis_info_psy_global *gi,int n,long rate);
+extern void _vp_psy_clear(vorbis_look_psy *p);
+extern void *_vi_psy_dup(void *source);
+
+extern void _vi_psy_free(vorbis_info_psy *i);
+extern vorbis_info_psy *_vi_psy_copy(vorbis_info_psy *i);
+
+extern void _vp_noisemask(vorbis_look_psy *p,
+ float *logmdct,
+ float *logmask);
+
+extern void _vp_tonemask(vorbis_look_psy *p,
+ float *logfft,
+ float *logmask,
+ float global_specmax,
+ float local_specmax);
+
+extern void _vp_offset_and_mix(vorbis_look_psy *p,
+ float *noise,
+ float *tone,
+ int offset_select,
+ float *logmask,
+ float *mdct,
+ float *logmdct);
+
+extern float _vp_ampmax_decay(float amp,vorbis_dsp_state *vd);
+
+extern void _vp_couple_quantize_normalize(int blobno,
+ vorbis_info_psy_global *g,
+ vorbis_look_psy *p,
+ vorbis_info_mapping0 *vi,
+ float **mdct,
+ int **iwork,
+ int *nonzero,
+ int sliding_lowpass,
+ int ch);
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/registry.c b/external/libvorbis-1.3.5/lib/registry.c
new file mode 100644
index 0000000..3961ed1
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/registry.c
@@ -0,0 +1,45 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: registry for time, floor, res backends and channel mappings
+ last mod: $Id: registry.c 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+#include "registry.h"
+#include "misc.h"
+/* seems like major overkill now; the backend numbers will grow into
+ the infrastructure soon enough */
+
+extern const vorbis_func_floor floor0_exportbundle;
+extern const vorbis_func_floor floor1_exportbundle;
+extern const vorbis_func_residue residue0_exportbundle;
+extern const vorbis_func_residue residue1_exportbundle;
+extern const vorbis_func_residue residue2_exportbundle;
+extern const vorbis_func_mapping mapping0_exportbundle;
+
+const vorbis_func_floor *const _floor_P[]={
+ &floor0_exportbundle,
+ &floor1_exportbundle,
+};
+
+const vorbis_func_residue *const _residue_P[]={
+ &residue0_exportbundle,
+ &residue1_exportbundle,
+ &residue2_exportbundle,
+};
+
+const vorbis_func_mapping *const _mapping_P[]={
+ &mapping0_exportbundle,
+};
diff --git a/external/libvorbis-1.3.5/lib/registry.h b/external/libvorbis-1.3.5/lib/registry.h
new file mode 100644
index 0000000..3ae0477
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/registry.h
@@ -0,0 +1,32 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: registry for time, floor, res backends and channel mappings
+ last mod: $Id: registry.h 15531 2008-11-24 23:50:06Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_REG_H_
+#define _V_REG_H_
+
+#define VI_TRANSFORMB 1
+#define VI_WINDOWB 1
+#define VI_TIMEB 1
+#define VI_FLOORB 2
+#define VI_RESB 3
+#define VI_MAPB 1
+
+extern const vorbis_func_floor *const _floor_P[];
+extern const vorbis_func_residue *const _residue_P[];
+extern const vorbis_func_mapping *const _mapping_P[];
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/res0.c b/external/libvorbis-1.3.5/lib/res0.c
new file mode 100644
index 0000000..ec11488
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/res0.c
@@ -0,0 +1,890 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: residue backend 0, 1 and 2 implementation
+ last mod: $Id: res0.c 19441 2015-01-21 01:17:41Z xiphmont $
+
+ ********************************************************************/
+
+/* Slow, slow, slow, simpleminded and did I mention it was slow? The
+ encode/decode loops are coded for clarity and performance is not
+ yet even a nagging little idea lurking in the shadows. Oh and BTW,
+ it's slow. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+#include "registry.h"
+#include "codebook.h"
+#include "misc.h"
+#include "os.h"
+
+//#define TRAIN_RES 1
+//#define TRAIN_RESAUX 1
+
+#if defined(TRAIN_RES) || defined (TRAIN_RESAUX)
+#include <stdio.h>
+#endif
+
+typedef struct {
+ vorbis_info_residue0 *info;
+
+ int parts;
+ int stages;
+ codebook *fullbooks;
+ codebook *phrasebook;
+ codebook ***partbooks;
+
+ int partvals;
+ int **decodemap;
+
+ long postbits;
+ long phrasebits;
+ long frames;
+
+#if defined(TRAIN_RES) || defined(TRAIN_RESAUX)
+ int train_seq;
+ long *training_data[8][64];
+ float training_max[8][64];
+ float training_min[8][64];
+ float tmin;
+ float tmax;
+ int submap;
+#endif
+
+} vorbis_look_residue0;
+
+void res0_free_info(vorbis_info_residue *i){
+ vorbis_info_residue0 *info=(vorbis_info_residue0 *)i;
+ if(info){
+ memset(info,0,sizeof(*info));
+ _ogg_free(info);
+ }
+}
+
+void res0_free_look(vorbis_look_residue *i){
+ int j;
+ if(i){
+
+ vorbis_look_residue0 *look=(vorbis_look_residue0 *)i;
+
+#ifdef TRAIN_RES
+ {
+ int j,k,l;
+ for(j=0;j<look->parts;j++){
+ /*fprintf(stderr,"partition %d: ",j);*/
+ for(k=0;k<8;k++)
+ if(look->training_data[k][j]){
+ char buffer[80];
+ FILE *of;
+ codebook *statebook=look->partbooks[j][k];
+
+ /* long and short into the same bucket by current convention */
+ sprintf(buffer,"res_sub%d_part%d_pass%d.vqd",look->submap,j,k);
+ of=fopen(buffer,"a");
+
+ for(l=0;l<statebook->entries;l++)
+ fprintf(of,"%d:%ld\n",l,look->training_data[k][j][l]);
+
+ fclose(of);
+
+ /*fprintf(stderr,"%d(%.2f|%.2f) ",k,
+ look->training_min[k][j],look->training_max[k][j]);*/
+
+ _ogg_free(look->training_data[k][j]);
+ look->training_data[k][j]=NULL;
+ }
+ /*fprintf(stderr,"\n");*/
+ }
+ }
+ fprintf(stderr,"min/max residue: %g::%g\n",look->tmin,look->tmax);
+
+ /*fprintf(stderr,"residue bit usage %f:%f (%f total)\n",
+ (float)look->phrasebits/look->frames,
+ (float)look->postbits/look->frames,
+ (float)(look->postbits+look->phrasebits)/look->frames);*/
+#endif
+
+
+ /*vorbis_info_residue0 *info=look->info;
+
+ fprintf(stderr,
+ "%ld frames encoded in %ld phrasebits and %ld residue bits "
+ "(%g/frame) \n",look->frames,look->phrasebits,
+ look->resbitsflat,
+ (look->phrasebits+look->resbitsflat)/(float)look->frames);
+
+ for(j=0;j<look->parts;j++){
+ long acc=0;
+ fprintf(stderr,"\t[%d] == ",j);
+ for(k=0;k<look->stages;k++)
+ if((info->secondstages[j]>>k)&1){
+ fprintf(stderr,"%ld,",look->resbits[j][k]);
+ acc+=look->resbits[j][k];
+ }
+
+ fprintf(stderr,":: (%ld vals) %1.2fbits/sample\n",look->resvals[j],
+ acc?(float)acc/(look->resvals[j]*info->grouping):0);
+ }
+ fprintf(stderr,"\n");*/
+
+ for(j=0;j<look->parts;j++)
+ if(look->partbooks[j])_ogg_free(look->partbooks[j]);
+ _ogg_free(look->partbooks);
+ for(j=0;j<look->partvals;j++)
+ _ogg_free(look->decodemap[j]);
+ _ogg_free(look->decodemap);
+
+ memset(look,0,sizeof(*look));
+ _ogg_free(look);
+ }
+}
+
+static int icount(unsigned int v){
+ int ret=0;
+ while(v){
+ ret+=v&1;
+ v>>=1;
+ }
+ return(ret);
+}
+
+
+void res0_pack(vorbis_info_residue *vr,oggpack_buffer *opb){
+ vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr;
+ int j,acc=0;
+ oggpack_write(opb,info->begin,24);
+ oggpack_write(opb,info->end,24);
+
+ oggpack_write(opb,info->grouping-1,24); /* residue vectors to group and
+ code with a partitioned book */
+ oggpack_write(opb,info->partitions-1,6); /* possible partition choices */
+ oggpack_write(opb,info->groupbook,8); /* group huffman book */
+
+ /* secondstages is a bitmask; as encoding progresses pass by pass, a
+ bitmask of one indicates this partition class has bits to write
+ this pass */
+ for(j=0;j<info->partitions;j++){
+ if(ov_ilog(info->secondstages[j])>3){
+ /* yes, this is a minor hack due to not thinking ahead */
+ oggpack_write(opb,info->secondstages[j],3);
+ oggpack_write(opb,1,1);
+ oggpack_write(opb,info->secondstages[j]>>3,5);
+ }else
+ oggpack_write(opb,info->secondstages[j],4); /* trailing zero */
+ acc+=icount(info->secondstages[j]);
+ }
+ for(j=0;j<acc;j++)
+ oggpack_write(opb,info->booklist[j],8);
+
+}
+
+/* vorbis_info is for range checking */
+vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){
+ int j,acc=0;
+ vorbis_info_residue0 *info=_ogg_calloc(1,sizeof(*info));
+ codec_setup_info *ci=vi->codec_setup;
+
+ info->begin=oggpack_read(opb,24);
+ info->end=oggpack_read(opb,24);
+ info->grouping=oggpack_read(opb,24)+1;
+ info->partitions=oggpack_read(opb,6)+1;
+ info->groupbook=oggpack_read(opb,8);
+
+ /* check for premature EOP */
+ if(info->groupbook<0)goto errout;
+
+ for(j=0;j<info->partitions;j++){
+ int cascade=oggpack_read(opb,3);
+ int cflag=oggpack_read(opb,1);
+ if(cflag<0) goto errout;
+ if(cflag){
+ int c=oggpack_read(opb,5);
+ if(c<0) goto errout;
+ cascade|=(c<<3);
+ }
+ info->secondstages[j]=cascade;
+
+ acc+=icount(cascade);
+ }
+ for(j=0;j<acc;j++){
+ int book=oggpack_read(opb,8);
+ if(book<0) goto errout;
+ info->booklist[j]=book;
+ }
+
+ if(info->groupbook>=ci->books)goto errout;
+ for(j=0;j<acc;j++){
+ if(info->booklist[j]>=ci->books)goto errout;
+ if(ci->book_param[info->booklist[j]]->maptype==0)goto errout;
+ }
+
+ /* verify the phrasebook is not specifying an impossible or
+ inconsistent partitioning scheme. */
+ /* modify the phrasebook ranging check from r16327; an early beta
+ encoder had a bug where it used an oversized phrasebook by
+ accident. These files should continue to be playable, but don't
+ allow an exploit */
+ {
+ int entries = ci->book_param[info->groupbook]->entries;
+ int dim = ci->book_param[info->groupbook]->dim;
+ int partvals = 1;
+ if (dim<1) goto errout;
+ while(dim>0){
+ partvals *= info->partitions;
+ if(partvals > entries) goto errout;
+ dim--;
+ }
+ info->partvals = partvals;
+ }
+
+ return(info);
+ errout:
+ res0_free_info(info);
+ return(NULL);
+}
+
+vorbis_look_residue *res0_look(vorbis_dsp_state *vd,
+ vorbis_info_residue *vr){
+ vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr;
+ vorbis_look_residue0 *look=_ogg_calloc(1,sizeof(*look));
+ codec_setup_info *ci=vd->vi->codec_setup;
+
+ int j,k,acc=0;
+ int dim;
+ int maxstage=0;
+ look->info=info;
+
+ look->parts=info->partitions;
+ look->fullbooks=ci->fullbooks;
+ look->phrasebook=ci->fullbooks+info->groupbook;
+ dim=look->phrasebook->dim;
+
+ look->partbooks=_ogg_calloc(look->parts,sizeof(*look->partbooks));
+
+ for(j=0;j<look->parts;j++){
+ int stages=ov_ilog(info->secondstages[j]);
+ if(stages){
+ if(stages>maxstage)maxstage=stages;
+ look->partbooks[j]=_ogg_calloc(stages,sizeof(*look->partbooks[j]));
+ for(k=0;k<stages;k++)
+ if(info->secondstages[j]&(1<<k)){
+ look->partbooks[j][k]=ci->fullbooks+info->booklist[acc++];
+#ifdef TRAIN_RES
+ look->training_data[k][j]=_ogg_calloc(look->partbooks[j][k]->entries,
+ sizeof(***look->training_data));
+#endif
+ }
+ }
+ }
+
+ look->partvals=1;
+ for(j=0;j<dim;j++)
+ look->partvals*=look->parts;
+
+ look->stages=maxstage;
+ look->decodemap=_ogg_malloc(look->partvals*sizeof(*look->decodemap));
+ for(j=0;j<look->partvals;j++){
+ long val=j;
+ long mult=look->partvals/look->parts;
+ look->decodemap[j]=_ogg_malloc(dim*sizeof(*look->decodemap[j]));
+ for(k=0;k<dim;k++){
+ long deco=val/mult;
+ val-=deco*mult;
+ mult/=look->parts;
+ look->decodemap[j][k]=deco;
+ }
+ }
+#if defined(TRAIN_RES) || defined (TRAIN_RESAUX)
+ {
+ static int train_seq=0;
+ look->train_seq=train_seq++;
+ }
+#endif
+ return(look);
+}
+
+/* break an abstraction and copy some code for performance purposes */
+static int local_book_besterror(codebook *book,int *a){
+ int dim=book->dim;
+ int i,j,o;
+ int minval=book->minval;
+ int del=book->delta;
+ int qv=book->quantvals;
+ int ze=(qv>>1);
+ int index=0;
+ /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */
+ int p[8]={0,0,0,0,0,0,0,0};
+
+ if(del!=1){
+ for(i=0,o=dim;i<dim;i++){
+ int v = (a[--o]-minval+(del>>1))/del;
+ int m = (v<ze ? ((ze-v)<<1)-1 : ((v-ze)<<1));
+ index = index*qv+ (m<0?0:(m>=qv?qv-1:m));
+ p[o]=v*del+minval;
+ }
+ }else{
+ for(i=0,o=dim;i<dim;i++){
+ int v = a[--o]-minval;
+ int m = (v<ze ? ((ze-v)<<1)-1 : ((v-ze)<<1));
+ index = index*qv+ (m<0?0:(m>=qv?qv-1:m));
+ p[o]=v*del+minval;
+ }
+ }
+
+ if(book->c->lengthlist[index]<=0){
+ const static_codebook *c=book->c;
+ int best=-1;
+ /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */
+ int e[8]={0,0,0,0,0,0,0,0};
+ int maxval = book->minval + book->delta*(book->quantvals-1);
+ for(i=0;i<book->entries;i++){
+ if(c->lengthlist[i]>0){
+ int this=0;
+ for(j=0;j<dim;j++){
+ int val=(e[j]-a[j]);
+ this+=val*val;
+ }
+ if(best==-1 || this<best){
+ memcpy(p,e,sizeof(p));
+ best=this;
+ index=i;
+ }
+ }
+ /* assumes the value patterning created by the tools in vq/ */
+ j=0;
+ while(e[j]>=maxval)
+ e[j++]=0;
+ if(e[j]>=0)
+ e[j]+=book->delta;
+ e[j]= -e[j];
+ }
+ }
+
+ if(index>-1){
+ for(i=0;i<dim;i++)
+ *a++ -= p[i];
+ }
+
+ return(index);
+}
+
+#ifdef TRAIN_RES
+static int _encodepart(oggpack_buffer *opb,int *vec, int n,
+ codebook *book,long *acc){
+#else
+static int _encodepart(oggpack_buffer *opb,int *vec, int n,
+ codebook *book){
+#endif
+ int i,bits=0;
+ int dim=book->dim;
+ int step=n/dim;
+
+ for(i=0;i<step;i++){
+ int entry=local_book_besterror(book,vec+i*dim);
+
+#ifdef TRAIN_RES
+ if(entry>=0)
+ acc[entry]++;
+#endif
+
+ bits+=vorbis_book_encode(book,entry,opb);
+
+ }
+
+ return(bits);
+}
+
+static long **_01class(vorbis_block *vb,vorbis_look_residue *vl,
+ int **in,int ch){
+ long i,j,k;
+ vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
+ vorbis_info_residue0 *info=look->info;
+
+ /* move all this setup out later */
+ int samples_per_partition=info->grouping;
+ int possible_partitions=info->partitions;
+ int n=info->end-info->begin;
+
+ int partvals=n/samples_per_partition;
+ long **partword=_vorbis_block_alloc(vb,ch*sizeof(*partword));
+ float scale=100./samples_per_partition;
+
+ /* we find the partition type for each partition of each
+ channel. We'll go back and do the interleaved encoding in a
+ bit. For now, clarity */
+
+ for(i=0;i<ch;i++){
+ partword[i]=_vorbis_block_alloc(vb,n/samples_per_partition*sizeof(*partword[i]));
+ memset(partword[i],0,n/samples_per_partition*sizeof(*partword[i]));
+ }
+
+ for(i=0;i<partvals;i++){
+ int offset=i*samples_per_partition+info->begin;
+ for(j=0;j<ch;j++){
+ int max=0;
+ int ent=0;
+ for(k=0;k<samples_per_partition;k++){
+ if(abs(in[j][offset+k])>max)max=abs(in[j][offset+k]);
+ ent+=abs(in[j][offset+k]);
+ }
+ ent*=scale;
+
+ for(k=0;k<possible_partitions-1;k++)
+ if(max<=info->classmetric1[k] &&
+ (info->classmetric2[k]<0 || ent<info->classmetric2[k]))
+ break;
+
+ partword[j][i]=k;
+ }
+ }
+
+#ifdef TRAIN_RESAUX
+ {
+ FILE *of;
+ char buffer[80];
+
+ for(i=0;i<ch;i++){
+ sprintf(buffer,"resaux_%d.vqd",look->train_seq);
+ of=fopen(buffer,"a");
+ for(j=0;j<partvals;j++)
+ fprintf(of,"%ld, ",partword[i][j]);
+ fprintf(of,"\n");
+ fclose(of);
+ }
+ }
+#endif
+ look->frames++;
+
+ return(partword);
+}
+
+/* designed for stereo or other modes where the partition size is an
+ integer multiple of the number of channels encoded in the current
+ submap */
+static long **_2class(vorbis_block *vb,vorbis_look_residue *vl,int **in,
+ int ch){
+ long i,j,k,l;
+ vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
+ vorbis_info_residue0 *info=look->info;
+
+ /* move all this setup out later */
+ int samples_per_partition=info->grouping;
+ int possible_partitions=info->partitions;
+ int n=info->end-info->begin;
+
+ int partvals=n/samples_per_partition;
+ long **partword=_vorbis_block_alloc(vb,sizeof(*partword));
+
+#if defined(TRAIN_RES) || defined (TRAIN_RESAUX)
+ FILE *of;
+ char buffer[80];
+#endif
+
+ partword[0]=_vorbis_block_alloc(vb,partvals*sizeof(*partword[0]));
+ memset(partword[0],0,partvals*sizeof(*partword[0]));
+
+ for(i=0,l=info->begin/ch;i<partvals;i++){
+ int magmax=0;
+ int angmax=0;
+ for(j=0;j<samples_per_partition;j+=ch){
+ if(abs(in[0][l])>magmax)magmax=abs(in[0][l]);
+ for(k=1;k<ch;k++)
+ if(abs(in[k][l])>angmax)angmax=abs(in[k][l]);
+ l++;
+ }
+
+ for(j=0;j<possible_partitions-1;j++)
+ if(magmax<=info->classmetric1[j] &&
+ angmax<=info->classmetric2[j])
+ break;
+
+ partword[0][i]=j;
+
+ }
+
+#ifdef TRAIN_RESAUX
+ sprintf(buffer,"resaux_%d.vqd",look->train_seq);
+ of=fopen(buffer,"a");
+ for(i=0;i<partvals;i++)
+ fprintf(of,"%ld, ",partword[0][i]);
+ fprintf(of,"\n");
+ fclose(of);
+#endif
+
+ look->frames++;
+
+ return(partword);
+}
+
+static int _01forward(oggpack_buffer *opb,
+ vorbis_look_residue *vl,
+ int **in,int ch,
+ long **partword,
+#ifdef TRAIN_RES
+ int (*encode)(oggpack_buffer *,int *,int,
+ codebook *,long *),
+ int submap
+#else
+ int (*encode)(oggpack_buffer *,int *,int,
+ codebook *)
+#endif
+){
+ long i,j,k,s;
+ vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
+ vorbis_info_residue0 *info=look->info;
+
+#ifdef TRAIN_RES
+ look->submap=submap;
+#endif
+
+ /* move all this setup out later */
+ int samples_per_partition=info->grouping;
+ int possible_partitions=info->partitions;
+ int partitions_per_word=look->phrasebook->dim;
+ int n=info->end-info->begin;
+
+ int partvals=n/samples_per_partition;
+ long resbits[128];
+ long resvals[128];
+
+#ifdef TRAIN_RES
+ for(i=0;i<ch;i++)
+ for(j=info->begin;j<info->end;j++){
+ if(in[i][j]>look->tmax)look->tmax=in[i][j];
+ if(in[i][j]<look->tmin)look->tmin=in[i][j];
+ }
+#endif
+
+ memset(resbits,0,sizeof(resbits));
+ memset(resvals,0,sizeof(resvals));
+
+ /* we code the partition words for each channel, then the residual
+ words for a partition per channel until we've written all the
+ residual words for that partition word. Then write the next
+ partition channel words... */
+
+ for(s=0;s<look->stages;s++){
+
+ for(i=0;i<partvals;){
+
+ /* first we encode a partition codeword for each channel */
+ if(s==0){
+ for(j=0;j<ch;j++){
+ long val=partword[j][i];
+ for(k=1;k<partitions_per_word;k++){
+ val*=possible_partitions;
+ if(i+k<partvals)
+ val+=partword[j][i+k];
+ }
+
+ /* training hack */
+ if(val<look->phrasebook->entries)
+ look->phrasebits+=vorbis_book_encode(look->phrasebook,val,opb);
+#if 0 /*def TRAIN_RES*/
+ else
+ fprintf(stderr,"!");
+#endif
+
+ }
+ }
+
+ /* now we encode interleaved residual values for the partitions */
+ for(k=0;k<partitions_per_word && i<partvals;k++,i++){
+ long offset=i*samples_per_partition+info->begin;
+
+ for(j=0;j<ch;j++){
+ if(s==0)resvals[partword[j][i]]+=samples_per_partition;
+ if(info->secondstages[partword[j][i]]&(1<<s)){
+ codebook *statebook=look->partbooks[partword[j][i]][s];
+ if(statebook){
+ int ret;
+#ifdef TRAIN_RES
+ long *accumulator=NULL;
+ accumulator=look->training_data[s][partword[j][i]];
+ {
+ int l;
+ int *samples=in[j]+offset;
+ for(l=0;l<samples_per_partition;l++){
+ if(samples[l]<look->training_min[s][partword[j][i]])
+ look->training_min[s][partword[j][i]]=samples[l];
+ if(samples[l]>look->training_max[s][partword[j][i]])
+ look->training_max[s][partword[j][i]]=samples[l];
+ }
+ }
+ ret=encode(opb,in[j]+offset,samples_per_partition,
+ statebook,accumulator);
+#else
+ ret=encode(opb,in[j]+offset,samples_per_partition,
+ statebook);
+#endif
+
+ look->postbits+=ret;
+ resbits[partword[j][i]]+=ret;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return(0);
+}
+
+/* a truncated packet here just means 'stop working'; it's not an error */
+static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl,
+ float **in,int ch,
+ long (*decodepart)(codebook *, float *,
+ oggpack_buffer *,int)){
+
+ long i,j,k,l,s;
+ vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
+ vorbis_info_residue0 *info=look->info;
+
+ /* move all this setup out later */
+ int samples_per_partition=info->grouping;
+ int partitions_per_word=look->phrasebook->dim;
+ int max=vb->pcmend>>1;
+ int end=(info->end<max?info->end:max);
+ int n=end-info->begin;
+
+ if(n>0){
+ int partvals=n/samples_per_partition;
+ int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
+ int ***partword=alloca(ch*sizeof(*partword));
+
+ for(j=0;j<ch;j++)
+ partword[j]=_vorbis_block_alloc(vb,partwords*sizeof(*partword[j]));
+
+ for(s=0;s<look->stages;s++){
+
+ /* each loop decodes on partition codeword containing
+ partitions_per_word partitions */
+ for(i=0,l=0;i<partvals;l++){
+ if(s==0){
+ /* fetch the partition word for each channel */
+ for(j=0;j<ch;j++){
+ int temp=vorbis_book_decode(look->phrasebook,&vb->opb);
+
+ if(temp==-1 || temp>=info->partvals)goto eopbreak;
+ partword[j][l]=look->decodemap[temp];
+ if(partword[j][l]==NULL)goto errout;
+ }
+ }
+
+ /* now we decode residual values for the partitions */
+ for(k=0;k<partitions_per_word && i<partvals;k++,i++)
+ for(j=0;j<ch;j++){
+ long offset=info->begin+i*samples_per_partition;
+ if(info->secondstages[partword[j][l][k]]&(1<<s)){
+ codebook *stagebook=look->partbooks[partword[j][l][k]][s];
+ if(stagebook){
+ if(decodepart(stagebook,in[j]+offset,&vb->opb,
+ samples_per_partition)==-1)goto eopbreak;
+ }
+ }
+ }
+ }
+ }
+ }
+ errout:
+ eopbreak:
+ return(0);
+}
+
+int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,
+ float **in,int *nonzero,int ch){
+ int i,used=0;
+ for(i=0;i<ch;i++)
+ if(nonzero[i])
+ in[used++]=in[i];
+ if(used)
+ return(_01inverse(vb,vl,in,used,vorbis_book_decodevs_add));
+ else
+ return(0);
+}
+
+int res1_forward(oggpack_buffer *opb,vorbis_block *vb,vorbis_look_residue *vl,
+ int **in,int *nonzero,int ch, long **partword, int submap){
+ int i,used=0;
+ (void)vb;
+ for(i=0;i<ch;i++)
+ if(nonzero[i])
+ in[used++]=in[i];
+
+ if(used){
+#ifdef TRAIN_RES
+ return _01forward(opb,vl,in,used,partword,_encodepart,submap);
+#else
+ (void)submap;
+ return _01forward(opb,vl,in,used,partword,_encodepart);
+#endif
+ }else{
+ return(0);
+ }
+}
+
+long **res1_class(vorbis_block *vb,vorbis_look_residue *vl,
+ int **in,int *nonzero,int ch){
+ int i,used=0;
+ for(i=0;i<ch;i++)
+ if(nonzero[i])
+ in[used++]=in[i];
+ if(used)
+ return(_01class(vb,vl,in,used));
+ else
+ return(0);
+}
+
+int res1_inverse(vorbis_block *vb,vorbis_look_residue *vl,
+ float **in,int *nonzero,int ch){
+ int i,used=0;
+ for(i=0;i<ch;i++)
+ if(nonzero[i])
+ in[used++]=in[i];
+ if(used)
+ return(_01inverse(vb,vl,in,used,vorbis_book_decodev_add));
+ else
+ return(0);
+}
+
+long **res2_class(vorbis_block *vb,vorbis_look_residue *vl,
+ int **in,int *nonzero,int ch){
+ int i,used=0;
+ for(i=0;i<ch;i++)
+ if(nonzero[i])used++;
+ if(used)
+ return(_2class(vb,vl,in,ch));
+ else
+ return(0);
+}
+
+/* res2 is slightly more different; all the channels are interleaved
+ into a single vector and encoded. */
+
+int res2_forward(oggpack_buffer *opb,
+ vorbis_block *vb,vorbis_look_residue *vl,
+ int **in,int *nonzero,int ch, long **partword,int submap){
+ long i,j,k,n=vb->pcmend/2,used=0;
+
+ /* don't duplicate the code; use a working vector hack for now and
+ reshape ourselves into a single channel res1 */
+ /* ugly; reallocs for each coupling pass :-( */
+ int *work=_vorbis_block_alloc(vb,ch*n*sizeof(*work));
+ for(i=0;i<ch;i++){
+ int *pcm=in[i];
+ if(nonzero[i])used++;
+ for(j=0,k=i;j<n;j++,k+=ch)
+ work[k]=pcm[j];
+ }
+
+ if(used){
+#ifdef TRAIN_RES
+ return _01forward(opb,vl,&work,1,partword,_encodepart,submap);
+#else
+ (void)submap;
+ return _01forward(opb,vl,&work,1,partword,_encodepart);
+#endif
+ }else{
+ return(0);
+ }
+}
+
+/* duplicate code here as speed is somewhat more important */
+int res2_inverse(vorbis_block *vb,vorbis_look_residue *vl,
+ float **in,int *nonzero,int ch){
+ long i,k,l,s;
+ vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
+ vorbis_info_residue0 *info=look->info;
+
+ /* move all this setup out later */
+ int samples_per_partition=info->grouping;
+ int partitions_per_word=look->phrasebook->dim;
+ int max=(vb->pcmend*ch)>>1;
+ int end=(info->end<max?info->end:max);
+ int n=end-info->begin;
+
+ if(n>0){
+ int partvals=n/samples_per_partition;
+ int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
+ int **partword=_vorbis_block_alloc(vb,partwords*sizeof(*partword));
+
+ for(i=0;i<ch;i++)if(nonzero[i])break;
+ if(i==ch)return(0); /* no nonzero vectors */
+
+ for(s=0;s<look->stages;s++){
+ for(i=0,l=0;i<partvals;l++){
+
+ if(s==0){
+ /* fetch the partition word */
+ int temp=vorbis_book_decode(look->phrasebook,&vb->opb);
+ if(temp==-1 || temp>=info->partvals)goto eopbreak;
+ partword[l]=look->decodemap[temp];
+ if(partword[l]==NULL)goto errout;
+ }
+
+ /* now we decode residual values for the partitions */
+ for(k=0;k<partitions_per_word && i<partvals;k++,i++)
+ if(info->secondstages[partword[l][k]]&(1<<s)){
+ codebook *stagebook=look->partbooks[partword[l][k]][s];
+
+ if(stagebook){
+ if(vorbis_book_decodevv_add(stagebook,in,
+ i*samples_per_partition+info->begin,ch,
+ &vb->opb,samples_per_partition)==-1)
+ goto eopbreak;
+ }
+ }
+ }
+ }
+ }
+ errout:
+ eopbreak:
+ return(0);
+}
+
+
+const vorbis_func_residue residue0_exportbundle={
+ NULL,
+ &res0_unpack,
+ &res0_look,
+ &res0_free_info,
+ &res0_free_look,
+ NULL,
+ NULL,
+ &res0_inverse
+};
+
+const vorbis_func_residue residue1_exportbundle={
+ &res0_pack,
+ &res0_unpack,
+ &res0_look,
+ &res0_free_info,
+ &res0_free_look,
+ &res1_class,
+ &res1_forward,
+ &res1_inverse
+};
+
+const vorbis_func_residue residue2_exportbundle={
+ &res0_pack,
+ &res0_unpack,
+ &res0_look,
+ &res0_free_info,
+ &res0_free_look,
+ &res2_class,
+ &res2_forward,
+ &res2_inverse
+};
diff --git a/external/libvorbis-1.3.5/lib/scales.h b/external/libvorbis-1.3.5/lib/scales.h
new file mode 100644
index 0000000..613f796
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/scales.h
@@ -0,0 +1,90 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: linear scale -> dB, Bark and Mel scales
+ last mod: $Id: scales.h 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_SCALES_H_
+#define _V_SCALES_H_
+
+#include <math.h>
+#include "os.h"
+
+#ifdef _MSC_VER
+/* MS Visual Studio doesn't have C99 inline keyword. */
+#define inline __inline
+#endif
+
+/* 20log10(x) */
+#define VORBIS_IEEE_FLOAT32 1
+#ifdef VORBIS_IEEE_FLOAT32
+
+static inline float unitnorm(float x){
+ union {
+ ogg_uint32_t i;
+ float f;
+ } ix;
+ ix.f = x;
+ ix.i = (ix.i & 0x80000000U) | (0x3f800000U);
+ return ix.f;
+}
+
+/* Segher was off (too high) by ~ .3 decibel. Center the conversion correctly. */
+static inline float todB(const float *x){
+ union {
+ ogg_uint32_t i;
+ float f;
+ } ix;
+ ix.f = *x;
+ ix.i = ix.i&0x7fffffff;
+ return (float)(ix.i * 7.17711438e-7f -764.6161886f);
+}
+
+#define todB_nn(x) todB(x)
+
+#else
+
+static float unitnorm(float x){
+ if(x<0)return(-1.f);
+ return(1.f);
+}
+
+#define todB(x) (*(x)==0?-400.f:log(*(x)**(x))*4.34294480f)
+#define todB_nn(x) (*(x)==0.f?-400.f:log(*(x))*8.6858896f)
+
+#endif
+
+#define fromdB(x) (exp((x)*.11512925f))
+
+/* The bark scale equations are approximations, since the original
+ table was somewhat hand rolled. The below are chosen to have the
+ best possible fit to the rolled tables, thus their somewhat odd
+ appearance (these are more accurate and over a longer range than
+ the oft-quoted bark equations found in the texts I have). The
+ approximations are valid from 0 - 30kHz (nyquist) or so.
+
+ all f in Hz, z in Bark */
+
+#define toBARK(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n))
+#define fromBARK(z) (102.f*(z)-2.f*pow(z,2.f)+.4f*pow(z,3.f)+pow(1.46f,z)-1.f)
+#define toMEL(n) (log(1.f+(n)*.001f)*1442.695f)
+#define fromMEL(m) (1000.f*exp((m)/1442.695f)-1000.f)
+
+/* Frequency to octave. We arbitrarily declare 63.5 Hz to be octave
+ 0.0 */
+
+#define toOC(n) (log(n)*1.442695f-5.965784f)
+#define fromOC(o) (exp(((o)+5.965784f)*.693147f))
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/sharedbook.c b/external/libvorbis-1.3.5/lib/sharedbook.c
new file mode 100644
index 0000000..6bfdf73
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/sharedbook.c
@@ -0,0 +1,586 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: basic shared codebook operations
+ last mod: $Id: sharedbook.c 19457 2015-03-03 00:15:29Z giles $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <ogg/ogg.h>
+#include "os.h"
+#include "misc.h"
+#include "vorbis/codec.h"
+#include "codebook.h"
+#include "scales.h"
+
+/**** pack/unpack helpers ******************************************/
+
+int ov_ilog(ogg_uint32_t v){
+ int ret;
+ for(ret=0;v;ret++)v>>=1;
+ return ret;
+}
+
+/* 32 bit float (not IEEE; nonnormalized mantissa +
+ biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm
+ Why not IEEE? It's just not that important here. */
+
+#define VQ_FEXP 10
+#define VQ_FMAN 21
+#define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */
+
+/* doesn't currently guard under/overflow */
+long _float32_pack(float val){
+ int sign=0;
+ long exp;
+ long mant;
+ if(val<0){
+ sign=0x80000000;
+ val= -val;
+ }
+ exp= floor(log(val)/log(2.f)+.001); //+epsilon
+ mant=rint(ldexp(val,(VQ_FMAN-1)-exp));
+ exp=(exp+VQ_FEXP_BIAS)<<VQ_FMAN;
+
+ return(sign|exp|mant);
+}
+
+float _float32_unpack(long val){
+ double mant=val&0x1fffff;
+ int sign=val&0x80000000;
+ long exp =(val&0x7fe00000L)>>VQ_FMAN;
+ if(sign)mant= -mant;
+ return(ldexp(mant,exp-(VQ_FMAN-1)-VQ_FEXP_BIAS));
+}
+
+/* given a list of word lengths, generate a list of codewords. Works
+ for length ordered or unordered, always assigns the lowest valued
+ codewords first. Extended to handle unused entries (length 0) */
+ogg_uint32_t *_make_words(char *l,long n,long sparsecount){
+ long i,j,count=0;
+ ogg_uint32_t marker[33];
+ ogg_uint32_t *r=_ogg_malloc((sparsecount?sparsecount:n)*sizeof(*r));
+ memset(marker,0,sizeof(marker));
+
+ for(i=0;i<n;i++){
+ long length=l[i];
+ if(length>0){
+ ogg_uint32_t entry=marker[length];
+
+ /* when we claim a node for an entry, we also claim the nodes
+ below it (pruning off the imagined tree that may have dangled
+ from it) as well as blocking the use of any nodes directly
+ above for leaves */
+
+ /* update ourself */
+ if(length<32 && (entry>>length)){
+ /* error condition; the lengths must specify an overpopulated tree */
+ _ogg_free(r);
+ return(NULL);
+ }
+ r[count++]=entry;
+
+ /* Look to see if the next shorter marker points to the node
+ above. if so, update it and repeat. */
+ {
+ for(j=length;j>0;j--){
+
+ if(marker[j]&1){
+ /* have to jump branches */
+ if(j==1)
+ marker[1]++;
+ else
+ marker[j]=marker[j-1]<<1;
+ break; /* invariant says next upper marker would already
+ have been moved if it was on the same path */
+ }
+ marker[j]++;
+ }
+ }
+
+ /* prune the tree; the implicit invariant says all the longer
+ markers were dangling from our just-taken node. Dangle them
+ from our *new* node. */
+ for(j=length+1;j<33;j++)
+ if((marker[j]>>1) == entry){
+ entry=marker[j];
+ marker[j]=marker[j-1]<<1;
+ }else
+ break;
+ }else
+ if(sparsecount==0)count++;
+ }
+
+ /* any underpopulated tree must be rejected. */
+ /* Single-entry codebooks are a retconned extension to the spec.
+ They have a single codeword '0' of length 1 that results in an
+ underpopulated tree. Shield that case from the underformed tree check. */
+ if(!(count==1 && marker[2]==2)){
+ for(i=1;i<33;i++)
+ if(marker[i] & (0xffffffffUL>>(32-i))){
+ _ogg_free(r);
+ return(NULL);
+ }
+ }
+
+ /* bitreverse the words because our bitwise packer/unpacker is LSb
+ endian */
+ for(i=0,count=0;i<n;i++){
+ ogg_uint32_t temp=0;
+ for(j=0;j<l[i];j++){
+ temp<<=1;
+ temp|=(r[count]>>j)&1;
+ }
+
+ if(sparsecount){
+ if(l[i])
+ r[count++]=temp;
+ }else
+ r[count++]=temp;
+ }
+
+ return(r);
+}
+
+/* there might be a straightforward one-line way to do the below
+ that's portable and totally safe against roundoff, but I haven't
+ thought of it. Therefore, we opt on the side of caution */
+long _book_maptype1_quantvals(const static_codebook *b){
+ long vals=floor(pow((float)b->entries,1.f/b->dim));
+
+ /* the above *should* be reliable, but we'll not assume that FP is
+ ever reliable when bitstream sync is at stake; verify via integer
+ means that vals really is the greatest value of dim for which
+ vals^b->bim <= b->entries */
+ /* treat the above as an initial guess */
+ while(1){
+ long acc=1;
+ long acc1=1;
+ int i;
+ for(i=0;i<b->dim;i++){
+ acc*=vals;
+ acc1*=vals+1;
+ }
+ if(acc<=b->entries && acc1>b->entries){
+ return(vals);
+ }else{
+ if(acc>b->entries){
+ vals--;
+ }else{
+ vals++;
+ }
+ }
+ }
+}
+
+/* unpack the quantized list of values for encode/decode ***********/
+/* we need to deal with two map types: in map type 1, the values are
+ generated algorithmically (each column of the vector counts through
+ the values in the quant vector). in map type 2, all the values came
+ in in an explicit list. Both value lists must be unpacked */
+float *_book_unquantize(const static_codebook *b,int n,int *sparsemap){
+ long j,k,count=0;
+ if(b->maptype==1 || b->maptype==2){
+ int quantvals;
+ float mindel=_float32_unpack(b->q_min);
+ float delta=_float32_unpack(b->q_delta);
+ float *r=_ogg_calloc(n*b->dim,sizeof(*r));
+
+ /* maptype 1 and 2 both use a quantized value vector, but
+ different sizes */
+ switch(b->maptype){
+ case 1:
+ /* most of the time, entries%dimensions == 0, but we need to be
+ well defined. We define that the possible vales at each
+ scalar is values == entries/dim. If entries%dim != 0, we'll
+ have 'too few' values (values*dim<entries), which means that
+ we'll have 'left over' entries; left over entries use zeroed
+ values (and are wasted). So don't generate codebooks like
+ that */
+ quantvals=_book_maptype1_quantvals(b);
+ for(j=0;j<b->entries;j++){
+ if((sparsemap && b->lengthlist[j]) || !sparsemap){
+ float last=0.f;
+ int indexdiv=1;
+ for(k=0;k<b->dim;k++){
+ int index= (j/indexdiv)%quantvals;
+ float val=b->quantlist[index];
+ val=fabs(val)*delta+mindel+last;
+ if(b->q_sequencep)last=val;
+ if(sparsemap)
+ r[sparsemap[count]*b->dim+k]=val;
+ else
+ r[count*b->dim+k]=val;
+ indexdiv*=quantvals;
+ }
+ count++;
+ }
+
+ }
+ break;
+ case 2:
+ for(j=0;j<b->entries;j++){
+ if((sparsemap && b->lengthlist[j]) || !sparsemap){
+ float last=0.f;
+
+ for(k=0;k<b->dim;k++){
+ float val=b->quantlist[j*b->dim+k];
+ val=fabs(val)*delta+mindel+last;
+ if(b->q_sequencep)last=val;
+ if(sparsemap)
+ r[sparsemap[count]*b->dim+k]=val;
+ else
+ r[count*b->dim+k]=val;
+ }
+ count++;
+ }
+ }
+ break;
+ }
+
+ return(r);
+ }
+ return(NULL);
+}
+
+void vorbis_staticbook_destroy(static_codebook *b){
+ if(b->allocedp){
+ if(b->quantlist)_ogg_free(b->quantlist);
+ if(b->lengthlist)_ogg_free(b->lengthlist);
+ memset(b,0,sizeof(*b));
+ _ogg_free(b);
+ } /* otherwise, it is in static memory */
+}
+
+void vorbis_book_clear(codebook *b){
+ /* static book is not cleared; we're likely called on the lookup and
+ the static codebook belongs to the info struct */
+ if(b->valuelist)_ogg_free(b->valuelist);
+ if(b->codelist)_ogg_free(b->codelist);
+
+ if(b->dec_index)_ogg_free(b->dec_index);
+ if(b->dec_codelengths)_ogg_free(b->dec_codelengths);
+ if(b->dec_firsttable)_ogg_free(b->dec_firsttable);
+
+ memset(b,0,sizeof(*b));
+}
+
+int vorbis_book_init_encode(codebook *c,const static_codebook *s){
+
+ memset(c,0,sizeof(*c));
+ c->c=s;
+ c->entries=s->entries;
+ c->used_entries=s->entries;
+ c->dim=s->dim;
+ c->codelist=_make_words(s->lengthlist,s->entries,0);
+ //c->valuelist=_book_unquantize(s,s->entries,NULL);
+ c->quantvals=_book_maptype1_quantvals(s);
+ c->minval=(int)rint(_float32_unpack(s->q_min));
+ c->delta=(int)rint(_float32_unpack(s->q_delta));
+
+ return(0);
+}
+
+static ogg_uint32_t bitreverse(ogg_uint32_t x){
+ x= ((x>>16)&0x0000ffffUL) | ((x<<16)&0xffff0000UL);
+ x= ((x>> 8)&0x00ff00ffUL) | ((x<< 8)&0xff00ff00UL);
+ x= ((x>> 4)&0x0f0f0f0fUL) | ((x<< 4)&0xf0f0f0f0UL);
+ x= ((x>> 2)&0x33333333UL) | ((x<< 2)&0xccccccccUL);
+ return((x>> 1)&0x55555555UL) | ((x<< 1)&0xaaaaaaaaUL);
+}
+
+static int sort32a(const void *a,const void *b){
+ return ( **(ogg_uint32_t **)a>**(ogg_uint32_t **)b)-
+ ( **(ogg_uint32_t **)a<**(ogg_uint32_t **)b);
+}
+
+/* decode codebook arrangement is more heavily optimized than encode */
+int vorbis_book_init_decode(codebook *c,const static_codebook *s){
+ int i,j,n=0,tabn;
+ int *sortindex;
+
+ memset(c,0,sizeof(*c));
+
+ /* count actually used entries and find max length */
+ for(i=0;i<s->entries;i++)
+ if(s->lengthlist[i]>0)
+ n++;
+
+ c->entries=s->entries;
+ c->used_entries=n;
+ c->dim=s->dim;
+
+ if(n>0){
+ /* two different remappings go on here.
+
+ First, we collapse the likely sparse codebook down only to
+ actually represented values/words. This collapsing needs to be
+ indexed as map-valueless books are used to encode original entry
+ positions as integers.
+
+ Second, we reorder all vectors, including the entry index above,
+ by sorted bitreversed codeword to allow treeless decode. */
+
+ /* perform sort */
+ ogg_uint32_t *codes=_make_words(s->lengthlist,s->entries,c->used_entries);
+ ogg_uint32_t **codep=alloca(sizeof(*codep)*n);
+
+ if(codes==NULL)goto err_out;
+
+ for(i=0;i<n;i++){
+ codes[i]=bitreverse(codes[i]);
+ codep[i]=codes+i;
+ }
+
+ qsort(codep,n,sizeof(*codep),sort32a);
+
+ sortindex=alloca(n*sizeof(*sortindex));
+ c->codelist=_ogg_malloc(n*sizeof(*c->codelist));
+ /* the index is a reverse index */
+ for(i=0;i<n;i++){
+ int position=codep[i]-codes;
+ sortindex[position]=i;
+ }
+
+ for(i=0;i<n;i++)
+ c->codelist[sortindex[i]]=codes[i];
+ _ogg_free(codes);
+
+ c->valuelist=_book_unquantize(s,n,sortindex);
+ c->dec_index=_ogg_malloc(n*sizeof(*c->dec_index));
+
+ for(n=0,i=0;i<s->entries;i++)
+ if(s->lengthlist[i]>0)
+ c->dec_index[sortindex[n++]]=i;
+
+ c->dec_codelengths=_ogg_malloc(n*sizeof(*c->dec_codelengths));
+ c->dec_maxlength=0;
+ for(n=0,i=0;i<s->entries;i++)
+ if(s->lengthlist[i]>0){
+ c->dec_codelengths[sortindex[n++]]=s->lengthlist[i];
+ if(s->lengthlist[i]>c->dec_maxlength)
+ c->dec_maxlength=s->lengthlist[i];
+ }
+
+ if(n==1 && c->dec_maxlength==1){
+ /* special case the 'single entry codebook' with a single bit
+ fastpath table (that always returns entry 0 )in order to use
+ unmodified decode paths. */
+ c->dec_firsttablen=1;
+ c->dec_firsttable=_ogg_calloc(2,sizeof(*c->dec_firsttable));
+ c->dec_firsttable[0]=c->dec_firsttable[1]=1;
+
+ }else{
+ c->dec_firsttablen=ov_ilog(c->used_entries)-4; /* this is magic */
+ if(c->dec_firsttablen<5)c->dec_firsttablen=5;
+ if(c->dec_firsttablen>8)c->dec_firsttablen=8;
+
+ tabn=1<<c->dec_firsttablen;
+ c->dec_firsttable=_ogg_calloc(tabn,sizeof(*c->dec_firsttable));
+
+ for(i=0;i<n;i++){
+ if(c->dec_codelengths[i]<=c->dec_firsttablen){
+ ogg_uint32_t orig=bitreverse(c->codelist[i]);
+ for(j=0;j<(1<<(c->dec_firsttablen-c->dec_codelengths[i]));j++)
+ c->dec_firsttable[orig|(j<<c->dec_codelengths[i])]=i+1;
+ }
+ }
+
+ /* now fill in 'unused' entries in the firsttable with hi/lo search
+ hints for the non-direct-hits */
+ {
+ ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen);
+ long lo=0,hi=0;
+
+ for(i=0;i<tabn;i++){
+ ogg_uint32_t word=i<<(32-c->dec_firsttablen);
+ if(c->dec_firsttable[bitreverse(word)]==0){
+ while((lo+1)<n && c->codelist[lo+1]<=word)lo++;
+ while( hi<n && word>=(c->codelist[hi]&mask))hi++;
+
+ /* we only actually have 15 bits per hint to play with here.
+ In order to overflow gracefully (nothing breaks, efficiency
+ just drops), encode as the difference from the extremes. */
+ {
+ unsigned long loval=lo;
+ unsigned long hival=n-hi;
+
+ if(loval>0x7fff)loval=0x7fff;
+ if(hival>0x7fff)hival=0x7fff;
+ c->dec_firsttable[bitreverse(word)]=
+ 0x80000000UL | (loval<<15) | hival;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return(0);
+ err_out:
+ vorbis_book_clear(c);
+ return(-1);
+}
+
+long vorbis_book_codeword(codebook *book,int entry){
+ if(book->c) /* only use with encode; decode optimizations are
+ allowed to break this */
+ return book->codelist[entry];
+ return -1;
+}
+
+long vorbis_book_codelen(codebook *book,int entry){
+ if(book->c) /* only use with encode; decode optimizations are
+ allowed to break this */
+ return book->c->lengthlist[entry];
+ return -1;
+}
+
+#ifdef _V_SELFTEST
+
+/* Unit tests of the dequantizer; this stuff will be OK
+ cross-platform, I simply want to be sure that special mapping cases
+ actually work properly; a bug could go unnoticed for a while */
+
+#include <stdio.h>
+
+/* cases:
+
+ no mapping
+ full, explicit mapping
+ algorithmic mapping
+
+ nonsequential
+ sequential
+*/
+
+static long full_quantlist1[]={0,1,2,3, 4,5,6,7, 8,3,6,1};
+static long partial_quantlist1[]={0,7,2};
+
+/* no mapping */
+static_codebook test1={
+ 4,16,
+ NULL,
+ 0,
+ 0,0,0,0,
+ NULL,
+ 0
+};
+static float *test1_result=NULL;
+
+/* linear, full mapping, nonsequential */
+static_codebook test2={
+ 4,3,
+ NULL,
+ 2,
+ -533200896,1611661312,4,0,
+ full_quantlist1,
+ 0
+};
+static float test2_result[]={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2};
+
+/* linear, full mapping, sequential */
+static_codebook test3={
+ 4,3,
+ NULL,
+ 2,
+ -533200896,1611661312,4,1,
+ full_quantlist1,
+ 0
+};
+static float test3_result[]={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6};
+
+/* linear, algorithmic mapping, nonsequential */
+static_codebook test4={
+ 3,27,
+ NULL,
+ 1,
+ -533200896,1611661312,4,0,
+ partial_quantlist1,
+ 0
+};
+static float test4_result[]={-3,-3,-3, 4,-3,-3, -1,-3,-3,
+ -3, 4,-3, 4, 4,-3, -1, 4,-3,
+ -3,-1,-3, 4,-1,-3, -1,-1,-3,
+ -3,-3, 4, 4,-3, 4, -1,-3, 4,
+ -3, 4, 4, 4, 4, 4, -1, 4, 4,
+ -3,-1, 4, 4,-1, 4, -1,-1, 4,
+ -3,-3,-1, 4,-3,-1, -1,-3,-1,
+ -3, 4,-1, 4, 4,-1, -1, 4,-1,
+ -3,-1,-1, 4,-1,-1, -1,-1,-1};
+
+/* linear, algorithmic mapping, sequential */
+static_codebook test5={
+ 3,27,
+ NULL,
+ 1,
+ -533200896,1611661312,4,1,
+ partial_quantlist1,
+ 0
+};
+static float test5_result[]={-3,-6,-9, 4, 1,-2, -1,-4,-7,
+ -3, 1,-2, 4, 8, 5, -1, 3, 0,
+ -3,-4,-7, 4, 3, 0, -1,-2,-5,
+ -3,-6,-2, 4, 1, 5, -1,-4, 0,
+ -3, 1, 5, 4, 8,12, -1, 3, 7,
+ -3,-4, 0, 4, 3, 7, -1,-2, 2,
+ -3,-6,-7, 4, 1, 0, -1,-4,-5,
+ -3, 1, 0, 4, 8, 7, -1, 3, 2,
+ -3,-4,-5, 4, 3, 2, -1,-2,-3};
+
+void run_test(static_codebook *b,float *comp){
+ float *out=_book_unquantize(b,b->entries,NULL);
+ int i;
+
+ if(comp){
+ if(!out){
+ fprintf(stderr,"_book_unquantize incorrectly returned NULL\n");
+ exit(1);
+ }
+
+ for(i=0;i<b->entries*b->dim;i++)
+ if(fabs(out[i]-comp[i])>.0001){
+ fprintf(stderr,"disagreement in unquantized and reference data:\n"
+ "position %d, %g != %g\n",i,out[i],comp[i]);
+ exit(1);
+ }
+
+ }else{
+ if(out){
+ fprintf(stderr,"_book_unquantize returned a value array: \n"
+ " correct result should have been NULL\n");
+ exit(1);
+ }
+ }
+}
+
+int main(){
+ /* run the nine dequant tests, and compare to the hand-rolled results */
+ fprintf(stderr,"Dequant test 1... ");
+ run_test(&test1,test1_result);
+ fprintf(stderr,"OK\nDequant test 2... ");
+ run_test(&test2,test2_result);
+ fprintf(stderr,"OK\nDequant test 3... ");
+ run_test(&test3,test3_result);
+ fprintf(stderr,"OK\nDequant test 4... ");
+ run_test(&test4,test4_result);
+ fprintf(stderr,"OK\nDequant test 5... ");
+ run_test(&test5,test5_result);
+ fprintf(stderr,"OK\n\n");
+
+ return(0);
+}
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/smallft.c b/external/libvorbis-1.3.5/lib/smallft.c
new file mode 100644
index 0000000..ae2bc41
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/smallft.c
@@ -0,0 +1,1255 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: *unnormalized* fft transform
+ last mod: $Id: smallft.c 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+/* FFT implementation from OggSquish, minus cosine transforms,
+ * minus all but radix 2/4 case. In Vorbis we only need this
+ * cut-down version.
+ *
+ * To do more than just power-of-two sized vectors, see the full
+ * version I wrote for NetLib.
+ *
+ * Note that the packing is a little strange; rather than the FFT r/i
+ * packing following R_0, I_n, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1,
+ * it follows R_0, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, I_n like the
+ * FORTRAN version
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "smallft.h"
+#include "os.h"
+#include "misc.h"
+
+static void drfti1(int n, float *wa, int *ifac){
+ static int ntryh[4] = { 4,2,3,5 };
+ static float tpi = 6.28318530717958648f;
+ float arg,argh,argld,fi;
+ int ntry=0,i,j=-1;
+ int k1, l1, l2, ib;
+ int ld, ii, ip, is, nq, nr;
+ int ido, ipm, nfm1;
+ int nl=n;
+ int nf=0;
+
+ L101:
+ j++;
+ if (j < 4)
+ ntry=ntryh[j];
+ else
+ ntry+=2;
+
+ L104:
+ nq=nl/ntry;
+ nr=nl-ntry*nq;
+ if (nr!=0) goto L101;
+
+ nf++;
+ ifac[nf+1]=ntry;
+ nl=nq;
+ if(ntry!=2)goto L107;
+ if(nf==1)goto L107;
+
+ for (i=1;i<nf;i++){
+ ib=nf-i+1;
+ ifac[ib+1]=ifac[ib];
+ }
+ ifac[2] = 2;
+
+ L107:
+ if(nl!=1)goto L104;
+ ifac[0]=n;
+ ifac[1]=nf;
+ argh=tpi/n;
+ is=0;
+ nfm1=nf-1;
+ l1=1;
+
+ if(nfm1==0)return;
+
+ for (k1=0;k1<nfm1;k1++){
+ ip=ifac[k1+2];
+ ld=0;
+ l2=l1*ip;
+ ido=n/l2;
+ ipm=ip-1;
+
+ for (j=0;j<ipm;j++){
+ ld+=l1;
+ i=is;
+ argld=(float)ld*argh;
+ fi=0.f;
+ for (ii=2;ii<ido;ii+=2){
+ fi+=1.f;
+ arg=fi*argld;
+ wa[i++]=cos(arg);
+ wa[i++]=sin(arg);
+ }
+ is+=ido;
+ }
+ l1=l2;
+ }
+}
+
+static void fdrffti(int n, float *wsave, int *ifac){
+
+ if (n == 1) return;
+ drfti1(n, wsave+n, ifac);
+}
+
+static void dradf2(int ido,int l1,float *cc,float *ch,float *wa1){
+ int i,k;
+ float ti2,tr2;
+ int t0,t1,t2,t3,t4,t5,t6;
+
+ t1=0;
+ t0=(t2=l1*ido);
+ t3=ido<<1;
+ for(k=0;k<l1;k++){
+ ch[t1<<1]=cc[t1]+cc[t2];
+ ch[(t1<<1)+t3-1]=cc[t1]-cc[t2];
+ t1+=ido;
+ t2+=ido;
+ }
+
+ if(ido<2)return;
+ if(ido==2)goto L105;
+
+ t1=0;
+ t2=t0;
+ for(k=0;k<l1;k++){
+ t3=t2;
+ t4=(t1<<1)+(ido<<1);
+ t5=t1;
+ t6=t1+t1;
+ for(i=2;i<ido;i+=2){
+ t3+=2;
+ t4-=2;
+ t5+=2;
+ t6+=2;
+ tr2=wa1[i-2]*cc[t3-1]+wa1[i-1]*cc[t3];
+ ti2=wa1[i-2]*cc[t3]-wa1[i-1]*cc[t3-1];
+ ch[t6]=cc[t5]+ti2;
+ ch[t4]=ti2-cc[t5];
+ ch[t6-1]=cc[t5-1]+tr2;
+ ch[t4-1]=cc[t5-1]-tr2;
+ }
+ t1+=ido;
+ t2+=ido;
+ }
+
+ if(ido%2==1)return;
+
+ L105:
+ t3=(t2=(t1=ido)-1);
+ t2+=t0;
+ for(k=0;k<l1;k++){
+ ch[t1]=-cc[t2];
+ ch[t1-1]=cc[t3];
+ t1+=ido<<1;
+ t2+=ido;
+ t3+=ido;
+ }
+}
+
+static void dradf4(int ido,int l1,float *cc,float *ch,float *wa1,
+ float *wa2,float *wa3){
+ static float hsqt2 = .70710678118654752f;
+ int i,k,t0,t1,t2,t3,t4,t5,t6;
+ float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
+ t0=l1*ido;
+
+ t1=t0;
+ t4=t1<<1;
+ t2=t1+(t1<<1);
+ t3=0;
+
+ for(k=0;k<l1;k++){
+ tr1=cc[t1]+cc[t2];
+ tr2=cc[t3]+cc[t4];
+
+ ch[t5=t3<<2]=tr1+tr2;
+ ch[(ido<<2)+t5-1]=tr2-tr1;
+ ch[(t5+=(ido<<1))-1]=cc[t3]-cc[t4];
+ ch[t5]=cc[t2]-cc[t1];
+
+ t1+=ido;
+ t2+=ido;
+ t3+=ido;
+ t4+=ido;
+ }
+
+ if(ido<2)return;
+ if(ido==2)goto L105;
+
+
+ t1=0;
+ for(k=0;k<l1;k++){
+ t2=t1;
+ t4=t1<<2;
+ t5=(t6=ido<<1)+t4;
+ for(i=2;i<ido;i+=2){
+ t3=(t2+=2);
+ t4+=2;
+ t5-=2;
+
+ t3+=t0;
+ cr2=wa1[i-2]*cc[t3-1]+wa1[i-1]*cc[t3];
+ ci2=wa1[i-2]*cc[t3]-wa1[i-1]*cc[t3-1];
+ t3+=t0;
+ cr3=wa2[i-2]*cc[t3-1]+wa2[i-1]*cc[t3];
+ ci3=wa2[i-2]*cc[t3]-wa2[i-1]*cc[t3-1];
+ t3+=t0;
+ cr4=wa3[i-2]*cc[t3-1]+wa3[i-1]*cc[t3];
+ ci4=wa3[i-2]*cc[t3]-wa3[i-1]*cc[t3-1];
+
+ tr1=cr2+cr4;
+ tr4=cr4-cr2;
+ ti1=ci2+ci4;
+ ti4=ci2-ci4;
+
+ ti2=cc[t2]+ci3;
+ ti3=cc[t2]-ci3;
+ tr2=cc[t2-1]+cr3;
+ tr3=cc[t2-1]-cr3;
+
+ ch[t4-1]=tr1+tr2;
+ ch[t4]=ti1+ti2;
+
+ ch[t5-1]=tr3-ti4;
+ ch[t5]=tr4-ti3;
+
+ ch[t4+t6-1]=ti4+tr3;
+ ch[t4+t6]=tr4+ti3;
+
+ ch[t5+t6-1]=tr2-tr1;
+ ch[t5+t6]=ti1-ti2;
+ }
+ t1+=ido;
+ }
+ if(ido&1)return;
+
+ L105:
+
+ t2=(t1=t0+ido-1)+(t0<<1);
+ t3=ido<<2;
+ t4=ido;
+ t5=ido<<1;
+ t6=ido;
+
+ for(k=0;k<l1;k++){
+ ti1=-hsqt2*(cc[t1]+cc[t2]);
+ tr1=hsqt2*(cc[t1]-cc[t2]);
+
+ ch[t4-1]=tr1+cc[t6-1];
+ ch[t4+t5-1]=cc[t6-1]-tr1;
+
+ ch[t4]=ti1-cc[t1+t0];
+ ch[t4+t5]=ti1+cc[t1+t0];
+
+ t1+=ido;
+ t2+=ido;
+ t4+=t3;
+ t6+=ido;
+ }
+}
+
+static void dradfg(int ido,int ip,int l1,int idl1,float *cc,float *c1,
+ float *c2,float *ch,float *ch2,float *wa){
+
+ static float tpi=6.283185307179586f;
+ int idij,ipph,i,j,k,l,ic,ik,is;
+ int t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10;
+ float dc2,ai1,ai2,ar1,ar2,ds2;
+ int nbd;
+ float dcp,arg,dsp,ar1h,ar2h;
+ int idp2,ipp2;
+
+ arg=tpi/(float)ip;
+ dcp=cos(arg);
+ dsp=sin(arg);
+ ipph=(ip+1)>>1;
+ ipp2=ip;
+ idp2=ido;
+ nbd=(ido-1)>>1;
+ t0=l1*ido;
+ t10=ip*ido;
+
+ if(ido==1)goto L119;
+ for(ik=0;ik<idl1;ik++)ch2[ik]=c2[ik];
+
+ t1=0;
+ for(j=1;j<ip;j++){
+ t1+=t0;
+ t2=t1;
+ for(k=0;k<l1;k++){
+ ch[t2]=c1[t2];
+ t2+=ido;
+ }
+ }
+
+ is=-ido;
+ t1=0;
+ if(nbd>l1){
+ for(j=1;j<ip;j++){
+ t1+=t0;
+ is+=ido;
+ t2= -ido+t1;
+ for(k=0;k<l1;k++){
+ idij=is-1;
+ t2+=ido;
+ t3=t2;
+ for(i=2;i<ido;i+=2){
+ idij+=2;
+ t3+=2;
+ ch[t3-1]=wa[idij-1]*c1[t3-1]+wa[idij]*c1[t3];
+ ch[t3]=wa[idij-1]*c1[t3]-wa[idij]*c1[t3-1];
+ }
+ }
+ }
+ }else{
+
+ for(j=1;j<ip;j++){
+ is+=ido;
+ idij=is-1;
+ t1+=t0;
+ t2=t1;
+ for(i=2;i<ido;i+=2){
+ idij+=2;
+ t2+=2;
+ t3=t2;
+ for(k=0;k<l1;k++){
+ ch[t3-1]=wa[idij-1]*c1[t3-1]+wa[idij]*c1[t3];
+ ch[t3]=wa[idij-1]*c1[t3]-wa[idij]*c1[t3-1];
+ t3+=ido;
+ }
+ }
+ }
+ }
+
+ t1=0;
+ t2=ipp2*t0;
+ if(nbd<l1){
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ for(i=2;i<ido;i+=2){
+ t3+=2;
+ t4+=2;
+ t5=t3-ido;
+ t6=t4-ido;
+ for(k=0;k<l1;k++){
+ t5+=ido;
+ t6+=ido;
+ c1[t5-1]=ch[t5-1]+ch[t6-1];
+ c1[t6-1]=ch[t5]-ch[t6];
+ c1[t5]=ch[t5]+ch[t6];
+ c1[t6]=ch[t6-1]-ch[t5-1];
+ }
+ }
+ }
+ }else{
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ for(k=0;k<l1;k++){
+ t5=t3;
+ t6=t4;
+ for(i=2;i<ido;i+=2){
+ t5+=2;
+ t6+=2;
+ c1[t5-1]=ch[t5-1]+ch[t6-1];
+ c1[t6-1]=ch[t5]-ch[t6];
+ c1[t5]=ch[t5]+ch[t6];
+ c1[t6]=ch[t6-1]-ch[t5-1];
+ }
+ t3+=ido;
+ t4+=ido;
+ }
+ }
+ }
+
+L119:
+ for(ik=0;ik<idl1;ik++)c2[ik]=ch2[ik];
+
+ t1=0;
+ t2=ipp2*idl1;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1-ido;
+ t4=t2-ido;
+ for(k=0;k<l1;k++){
+ t3+=ido;
+ t4+=ido;
+ c1[t3]=ch[t3]+ch[t4];
+ c1[t4]=ch[t4]-ch[t3];
+ }
+ }
+
+ ar1=1.f;
+ ai1=0.f;
+ t1=0;
+ t2=ipp2*idl1;
+ t3=(ip-1)*idl1;
+ for(l=1;l<ipph;l++){
+ t1+=idl1;
+ t2-=idl1;
+ ar1h=dcp*ar1-dsp*ai1;
+ ai1=dcp*ai1+dsp*ar1;
+ ar1=ar1h;
+ t4=t1;
+ t5=t2;
+ t6=t3;
+ t7=idl1;
+
+ for(ik=0;ik<idl1;ik++){
+ ch2[t4++]=c2[ik]+ar1*c2[t7++];
+ ch2[t5++]=ai1*c2[t6++];
+ }
+
+ dc2=ar1;
+ ds2=ai1;
+ ar2=ar1;
+ ai2=ai1;
+
+ t4=idl1;
+ t5=(ipp2-1)*idl1;
+ for(j=2;j<ipph;j++){
+ t4+=idl1;
+ t5-=idl1;
+
+ ar2h=dc2*ar2-ds2*ai2;
+ ai2=dc2*ai2+ds2*ar2;
+ ar2=ar2h;
+
+ t6=t1;
+ t7=t2;
+ t8=t4;
+ t9=t5;
+ for(ik=0;ik<idl1;ik++){
+ ch2[t6++]+=ar2*c2[t8++];
+ ch2[t7++]+=ai2*c2[t9++];
+ }
+ }
+ }
+
+ t1=0;
+ for(j=1;j<ipph;j++){
+ t1+=idl1;
+ t2=t1;
+ for(ik=0;ik<idl1;ik++)ch2[ik]+=c2[t2++];
+ }
+
+ if(ido<l1)goto L132;
+
+ t1=0;
+ t2=0;
+ for(k=0;k<l1;k++){
+ t3=t1;
+ t4=t2;
+ for(i=0;i<ido;i++)cc[t4++]=ch[t3++];
+ t1+=ido;
+ t2+=t10;
+ }
+
+ goto L135;
+
+ L132:
+ for(i=0;i<ido;i++){
+ t1=i;
+ t2=i;
+ for(k=0;k<l1;k++){
+ cc[t2]=ch[t1];
+ t1+=ido;
+ t2+=t10;
+ }
+ }
+
+ L135:
+ t1=0;
+ t2=ido<<1;
+ t3=0;
+ t4=ipp2*t0;
+ for(j=1;j<ipph;j++){
+
+ t1+=t2;
+ t3+=t0;
+ t4-=t0;
+
+ t5=t1;
+ t6=t3;
+ t7=t4;
+
+ for(k=0;k<l1;k++){
+ cc[t5-1]=ch[t6];
+ cc[t5]=ch[t7];
+ t5+=t10;
+ t6+=ido;
+ t7+=ido;
+ }
+ }
+
+ if(ido==1)return;
+ if(nbd<l1)goto L141;
+
+ t1=-ido;
+ t3=0;
+ t4=0;
+ t5=ipp2*t0;
+ for(j=1;j<ipph;j++){
+ t1+=t2;
+ t3+=t2;
+ t4+=t0;
+ t5-=t0;
+ t6=t1;
+ t7=t3;
+ t8=t4;
+ t9=t5;
+ for(k=0;k<l1;k++){
+ for(i=2;i<ido;i+=2){
+ ic=idp2-i;
+ cc[i+t7-1]=ch[i+t8-1]+ch[i+t9-1];
+ cc[ic+t6-1]=ch[i+t8-1]-ch[i+t9-1];
+ cc[i+t7]=ch[i+t8]+ch[i+t9];
+ cc[ic+t6]=ch[i+t9]-ch[i+t8];
+ }
+ t6+=t10;
+ t7+=t10;
+ t8+=ido;
+ t9+=ido;
+ }
+ }
+ return;
+
+ L141:
+
+ t1=-ido;
+ t3=0;
+ t4=0;
+ t5=ipp2*t0;
+ for(j=1;j<ipph;j++){
+ t1+=t2;
+ t3+=t2;
+ t4+=t0;
+ t5-=t0;
+ for(i=2;i<ido;i+=2){
+ t6=idp2+t1-i;
+ t7=i+t3;
+ t8=i+t4;
+ t9=i+t5;
+ for(k=0;k<l1;k++){
+ cc[t7-1]=ch[t8-1]+ch[t9-1];
+ cc[t6-1]=ch[t8-1]-ch[t9-1];
+ cc[t7]=ch[t8]+ch[t9];
+ cc[t6]=ch[t9]-ch[t8];
+ t6+=t10;
+ t7+=t10;
+ t8+=ido;
+ t9+=ido;
+ }
+ }
+ }
+}
+
+static void drftf1(int n,float *c,float *ch,float *wa,int *ifac){
+ int i,k1,l1,l2;
+ int na,kh,nf;
+ int ip,iw,ido,idl1,ix2,ix3;
+
+ nf=ifac[1];
+ na=1;
+ l2=n;
+ iw=n;
+
+ for(k1=0;k1<nf;k1++){
+ kh=nf-k1;
+ ip=ifac[kh+1];
+ l1=l2/ip;
+ ido=n/l2;
+ idl1=ido*l1;
+ iw-=(ip-1)*ido;
+ na=1-na;
+
+ if(ip!=4)goto L102;
+
+ ix2=iw+ido;
+ ix3=ix2+ido;
+ if(na!=0)
+ dradf4(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1);
+ else
+ dradf4(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1);
+ goto L110;
+
+ L102:
+ if(ip!=2)goto L104;
+ if(na!=0)goto L103;
+
+ dradf2(ido,l1,c,ch,wa+iw-1);
+ goto L110;
+
+ L103:
+ dradf2(ido,l1,ch,c,wa+iw-1);
+ goto L110;
+
+ L104:
+ if(ido==1)na=1-na;
+ if(na!=0)goto L109;
+
+ dradfg(ido,ip,l1,idl1,c,c,c,ch,ch,wa+iw-1);
+ na=1;
+ goto L110;
+
+ L109:
+ dradfg(ido,ip,l1,idl1,ch,ch,ch,c,c,wa+iw-1);
+ na=0;
+
+ L110:
+ l2=l1;
+ }
+
+ if(na==1)return;
+
+ for(i=0;i<n;i++)c[i]=ch[i];
+}
+
+static void dradb2(int ido,int l1,float *cc,float *ch,float *wa1){
+ int i,k,t0,t1,t2,t3,t4,t5,t6;
+ float ti2,tr2;
+
+ t0=l1*ido;
+
+ t1=0;
+ t2=0;
+ t3=(ido<<1)-1;
+ for(k=0;k<l1;k++){
+ ch[t1]=cc[t2]+cc[t3+t2];
+ ch[t1+t0]=cc[t2]-cc[t3+t2];
+ t2=(t1+=ido)<<1;
+ }
+
+ if(ido<2)return;
+ if(ido==2)goto L105;
+
+ t1=0;
+ t2=0;
+ for(k=0;k<l1;k++){
+ t3=t1;
+ t5=(t4=t2)+(ido<<1);
+ t6=t0+t1;
+ for(i=2;i<ido;i+=2){
+ t3+=2;
+ t4+=2;
+ t5-=2;
+ t6+=2;
+ ch[t3-1]=cc[t4-1]+cc[t5-1];
+ tr2=cc[t4-1]-cc[t5-1];
+ ch[t3]=cc[t4]-cc[t5];
+ ti2=cc[t4]+cc[t5];
+ ch[t6-1]=wa1[i-2]*tr2-wa1[i-1]*ti2;
+ ch[t6]=wa1[i-2]*ti2+wa1[i-1]*tr2;
+ }
+ t2=(t1+=ido)<<1;
+ }
+
+ if(ido%2==1)return;
+
+L105:
+ t1=ido-1;
+ t2=ido-1;
+ for(k=0;k<l1;k++){
+ ch[t1]=cc[t2]+cc[t2];
+ ch[t1+t0]=-(cc[t2+1]+cc[t2+1]);
+ t1+=ido;
+ t2+=ido<<1;
+ }
+}
+
+static void dradb3(int ido,int l1,float *cc,float *ch,float *wa1,
+ float *wa2){
+ static float taur = -.5f;
+ static float taui = .8660254037844386f;
+ int i,k,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10;
+ float ci2,ci3,di2,di3,cr2,cr3,dr2,dr3,ti2,tr2;
+ t0=l1*ido;
+
+ t1=0;
+ t2=t0<<1;
+ t3=ido<<1;
+ t4=ido+(ido<<1);
+ t5=0;
+ for(k=0;k<l1;k++){
+ tr2=cc[t3-1]+cc[t3-1];
+ cr2=cc[t5]+(taur*tr2);
+ ch[t1]=cc[t5]+tr2;
+ ci3=taui*(cc[t3]+cc[t3]);
+ ch[t1+t0]=cr2-ci3;
+ ch[t1+t2]=cr2+ci3;
+ t1+=ido;
+ t3+=t4;
+ t5+=t4;
+ }
+
+ if(ido==1)return;
+
+ t1=0;
+ t3=ido<<1;
+ for(k=0;k<l1;k++){
+ t7=t1+(t1<<1);
+ t6=(t5=t7+t3);
+ t8=t1;
+ t10=(t9=t1+t0)+t0;
+
+ for(i=2;i<ido;i+=2){
+ t5+=2;
+ t6-=2;
+ t7+=2;
+ t8+=2;
+ t9+=2;
+ t10+=2;
+ tr2=cc[t5-1]+cc[t6-1];
+ cr2=cc[t7-1]+(taur*tr2);
+ ch[t8-1]=cc[t7-1]+tr2;
+ ti2=cc[t5]-cc[t6];
+ ci2=cc[t7]+(taur*ti2);
+ ch[t8]=cc[t7]+ti2;
+ cr3=taui*(cc[t5-1]-cc[t6-1]);
+ ci3=taui*(cc[t5]+cc[t6]);
+ dr2=cr2-ci3;
+ dr3=cr2+ci3;
+ di2=ci2+cr3;
+ di3=ci2-cr3;
+ ch[t9-1]=wa1[i-2]*dr2-wa1[i-1]*di2;
+ ch[t9]=wa1[i-2]*di2+wa1[i-1]*dr2;
+ ch[t10-1]=wa2[i-2]*dr3-wa2[i-1]*di3;
+ ch[t10]=wa2[i-2]*di3+wa2[i-1]*dr3;
+ }
+ t1+=ido;
+ }
+}
+
+static void dradb4(int ido,int l1,float *cc,float *ch,float *wa1,
+ float *wa2,float *wa3){
+ static float sqrt2=1.414213562373095f;
+ int i,k,t0,t1,t2,t3,t4,t5,t6,t7,t8;
+ float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
+ t0=l1*ido;
+
+ t1=0;
+ t2=ido<<2;
+ t3=0;
+ t6=ido<<1;
+ for(k=0;k<l1;k++){
+ t4=t3+t6;
+ t5=t1;
+ tr3=cc[t4-1]+cc[t4-1];
+ tr4=cc[t4]+cc[t4];
+ tr1=cc[t3]-cc[(t4+=t6)-1];
+ tr2=cc[t3]+cc[t4-1];
+ ch[t5]=tr2+tr3;
+ ch[t5+=t0]=tr1-tr4;
+ ch[t5+=t0]=tr2-tr3;
+ ch[t5+=t0]=tr1+tr4;
+ t1+=ido;
+ t3+=t2;
+ }
+
+ if(ido<2)return;
+ if(ido==2)goto L105;
+
+ t1=0;
+ for(k=0;k<l1;k++){
+ t5=(t4=(t3=(t2=t1<<2)+t6))+t6;
+ t7=t1;
+ for(i=2;i<ido;i+=2){
+ t2+=2;
+ t3+=2;
+ t4-=2;
+ t5-=2;
+ t7+=2;
+ ti1=cc[t2]+cc[t5];
+ ti2=cc[t2]-cc[t5];
+ ti3=cc[t3]-cc[t4];
+ tr4=cc[t3]+cc[t4];
+ tr1=cc[t2-1]-cc[t5-1];
+ tr2=cc[t2-1]+cc[t5-1];
+ ti4=cc[t3-1]-cc[t4-1];
+ tr3=cc[t3-1]+cc[t4-1];
+ ch[t7-1]=tr2+tr3;
+ cr3=tr2-tr3;
+ ch[t7]=ti2+ti3;
+ ci3=ti2-ti3;
+ cr2=tr1-tr4;
+ cr4=tr1+tr4;
+ ci2=ti1+ti4;
+ ci4=ti1-ti4;
+
+ ch[(t8=t7+t0)-1]=wa1[i-2]*cr2-wa1[i-1]*ci2;
+ ch[t8]=wa1[i-2]*ci2+wa1[i-1]*cr2;
+ ch[(t8+=t0)-1]=wa2[i-2]*cr3-wa2[i-1]*ci3;
+ ch[t8]=wa2[i-2]*ci3+wa2[i-1]*cr3;
+ ch[(t8+=t0)-1]=wa3[i-2]*cr4-wa3[i-1]*ci4;
+ ch[t8]=wa3[i-2]*ci4+wa3[i-1]*cr4;
+ }
+ t1+=ido;
+ }
+
+ if(ido%2 == 1)return;
+
+ L105:
+
+ t1=ido;
+ t2=ido<<2;
+ t3=ido-1;
+ t4=ido+(ido<<1);
+ for(k=0;k<l1;k++){
+ t5=t3;
+ ti1=cc[t1]+cc[t4];
+ ti2=cc[t4]-cc[t1];
+ tr1=cc[t1-1]-cc[t4-1];
+ tr2=cc[t1-1]+cc[t4-1];
+ ch[t5]=tr2+tr2;
+ ch[t5+=t0]=sqrt2*(tr1-ti1);
+ ch[t5+=t0]=ti2+ti2;
+ ch[t5+=t0]=-sqrt2*(tr1+ti1);
+
+ t3+=ido;
+ t1+=t2;
+ t4+=t2;
+ }
+}
+
+static void dradbg(int ido,int ip,int l1,int idl1,float *cc,float *c1,
+ float *c2,float *ch,float *ch2,float *wa){
+ static float tpi=6.283185307179586f;
+ int idij,ipph,i,j,k,l,ik,is,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,
+ t11,t12;
+ float dc2,ai1,ai2,ar1,ar2,ds2;
+ int nbd;
+ float dcp,arg,dsp,ar1h,ar2h;
+ int ipp2;
+
+ t10=ip*ido;
+ t0=l1*ido;
+ arg=tpi/(float)ip;
+ dcp=cos(arg);
+ dsp=sin(arg);
+ nbd=(ido-1)>>1;
+ ipp2=ip;
+ ipph=(ip+1)>>1;
+ if(ido<l1)goto L103;
+
+ t1=0;
+ t2=0;
+ for(k=0;k<l1;k++){
+ t3=t1;
+ t4=t2;
+ for(i=0;i<ido;i++){
+ ch[t3]=cc[t4];
+ t3++;
+ t4++;
+ }
+ t1+=ido;
+ t2+=t10;
+ }
+ goto L106;
+
+ L103:
+ t1=0;
+ for(i=0;i<ido;i++){
+ t2=t1;
+ t3=t1;
+ for(k=0;k<l1;k++){
+ ch[t2]=cc[t3];
+ t2+=ido;
+ t3+=t10;
+ }
+ t1++;
+ }
+
+ L106:
+ t1=0;
+ t2=ipp2*t0;
+ t7=(t5=ido<<1);
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ t6=t5;
+ for(k=0;k<l1;k++){
+ ch[t3]=cc[t6-1]+cc[t6-1];
+ ch[t4]=cc[t6]+cc[t6];
+ t3+=ido;
+ t4+=ido;
+ t6+=t10;
+ }
+ t5+=t7;
+ }
+
+ if (ido == 1)goto L116;
+ if(nbd<l1)goto L112;
+
+ t1=0;
+ t2=ipp2*t0;
+ t7=0;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+
+ t7+=(ido<<1);
+ t8=t7;
+ for(k=0;k<l1;k++){
+ t5=t3;
+ t6=t4;
+ t9=t8;
+ t11=t8;
+ for(i=2;i<ido;i+=2){
+ t5+=2;
+ t6+=2;
+ t9+=2;
+ t11-=2;
+ ch[t5-1]=cc[t9-1]+cc[t11-1];
+ ch[t6-1]=cc[t9-1]-cc[t11-1];
+ ch[t5]=cc[t9]-cc[t11];
+ ch[t6]=cc[t9]+cc[t11];
+ }
+ t3+=ido;
+ t4+=ido;
+ t8+=t10;
+ }
+ }
+ goto L116;
+
+ L112:
+ t1=0;
+ t2=ipp2*t0;
+ t7=0;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ t7+=(ido<<1);
+ t8=t7;
+ t9=t7;
+ for(i=2;i<ido;i+=2){
+ t3+=2;
+ t4+=2;
+ t8+=2;
+ t9-=2;
+ t5=t3;
+ t6=t4;
+ t11=t8;
+ t12=t9;
+ for(k=0;k<l1;k++){
+ ch[t5-1]=cc[t11-1]+cc[t12-1];
+ ch[t6-1]=cc[t11-1]-cc[t12-1];
+ ch[t5]=cc[t11]-cc[t12];
+ ch[t6]=cc[t11]+cc[t12];
+ t5+=ido;
+ t6+=ido;
+ t11+=t10;
+ t12+=t10;
+ }
+ }
+ }
+
+L116:
+ ar1=1.f;
+ ai1=0.f;
+ t1=0;
+ t9=(t2=ipp2*idl1);
+ t3=(ip-1)*idl1;
+ for(l=1;l<ipph;l++){
+ t1+=idl1;
+ t2-=idl1;
+
+ ar1h=dcp*ar1-dsp*ai1;
+ ai1=dcp*ai1+dsp*ar1;
+ ar1=ar1h;
+ t4=t1;
+ t5=t2;
+ t6=0;
+ t7=idl1;
+ t8=t3;
+ for(ik=0;ik<idl1;ik++){
+ c2[t4++]=ch2[t6++]+ar1*ch2[t7++];
+ c2[t5++]=ai1*ch2[t8++];
+ }
+ dc2=ar1;
+ ds2=ai1;
+ ar2=ar1;
+ ai2=ai1;
+
+ t6=idl1;
+ t7=t9-idl1;
+ for(j=2;j<ipph;j++){
+ t6+=idl1;
+ t7-=idl1;
+ ar2h=dc2*ar2-ds2*ai2;
+ ai2=dc2*ai2+ds2*ar2;
+ ar2=ar2h;
+ t4=t1;
+ t5=t2;
+ t11=t6;
+ t12=t7;
+ for(ik=0;ik<idl1;ik++){
+ c2[t4++]+=ar2*ch2[t11++];
+ c2[t5++]+=ai2*ch2[t12++];
+ }
+ }
+ }
+
+ t1=0;
+ for(j=1;j<ipph;j++){
+ t1+=idl1;
+ t2=t1;
+ for(ik=0;ik<idl1;ik++)ch2[ik]+=ch2[t2++];
+ }
+
+ t1=0;
+ t2=ipp2*t0;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ for(k=0;k<l1;k++){
+ ch[t3]=c1[t3]-c1[t4];
+ ch[t4]=c1[t3]+c1[t4];
+ t3+=ido;
+ t4+=ido;
+ }
+ }
+
+ if(ido==1)goto L132;
+ if(nbd<l1)goto L128;
+
+ t1=0;
+ t2=ipp2*t0;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ for(k=0;k<l1;k++){
+ t5=t3;
+ t6=t4;
+ for(i=2;i<ido;i+=2){
+ t5+=2;
+ t6+=2;
+ ch[t5-1]=c1[t5-1]-c1[t6];
+ ch[t6-1]=c1[t5-1]+c1[t6];
+ ch[t5]=c1[t5]+c1[t6-1];
+ ch[t6]=c1[t5]-c1[t6-1];
+ }
+ t3+=ido;
+ t4+=ido;
+ }
+ }
+ goto L132;
+
+ L128:
+ t1=0;
+ t2=ipp2*t0;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ for(i=2;i<ido;i+=2){
+ t3+=2;
+ t4+=2;
+ t5=t3;
+ t6=t4;
+ for(k=0;k<l1;k++){
+ ch[t5-1]=c1[t5-1]-c1[t6];
+ ch[t6-1]=c1[t5-1]+c1[t6];
+ ch[t5]=c1[t5]+c1[t6-1];
+ ch[t6]=c1[t5]-c1[t6-1];
+ t5+=ido;
+ t6+=ido;
+ }
+ }
+ }
+
+L132:
+ if(ido==1)return;
+
+ for(ik=0;ik<idl1;ik++)c2[ik]=ch2[ik];
+
+ t1=0;
+ for(j=1;j<ip;j++){
+ t2=(t1+=t0);
+ for(k=0;k<l1;k++){
+ c1[t2]=ch[t2];
+ t2+=ido;
+ }
+ }
+
+ if(nbd>l1)goto L139;
+
+ is= -ido-1;
+ t1=0;
+ for(j=1;j<ip;j++){
+ is+=ido;
+ t1+=t0;
+ idij=is;
+ t2=t1;
+ for(i=2;i<ido;i+=2){
+ t2+=2;
+ idij+=2;
+ t3=t2;
+ for(k=0;k<l1;k++){
+ c1[t3-1]=wa[idij-1]*ch[t3-1]-wa[idij]*ch[t3];
+ c1[t3]=wa[idij-1]*ch[t3]+wa[idij]*ch[t3-1];
+ t3+=ido;
+ }
+ }
+ }
+ return;
+
+ L139:
+ is= -ido-1;
+ t1=0;
+ for(j=1;j<ip;j++){
+ is+=ido;
+ t1+=t0;
+ t2=t1;
+ for(k=0;k<l1;k++){
+ idij=is;
+ t3=t2;
+ for(i=2;i<ido;i+=2){
+ idij+=2;
+ t3+=2;
+ c1[t3-1]=wa[idij-1]*ch[t3-1]-wa[idij]*ch[t3];
+ c1[t3]=wa[idij-1]*ch[t3]+wa[idij]*ch[t3-1];
+ }
+ t2+=ido;
+ }
+ }
+}
+
+static void drftb1(int n, float *c, float *ch, float *wa, int *ifac){
+ int i,k1,l1,l2;
+ int na;
+ int nf,ip,iw,ix2,ix3,ido,idl1;
+
+ nf=ifac[1];
+ na=0;
+ l1=1;
+ iw=1;
+
+ for(k1=0;k1<nf;k1++){
+ ip=ifac[k1 + 2];
+ l2=ip*l1;
+ ido=n/l2;
+ idl1=ido*l1;
+ if(ip!=4)goto L103;
+ ix2=iw+ido;
+ ix3=ix2+ido;
+
+ if(na!=0)
+ dradb4(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1);
+ else
+ dradb4(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1);
+ na=1-na;
+ goto L115;
+
+ L103:
+ if(ip!=2)goto L106;
+
+ if(na!=0)
+ dradb2(ido,l1,ch,c,wa+iw-1);
+ else
+ dradb2(ido,l1,c,ch,wa+iw-1);
+ na=1-na;
+ goto L115;
+
+ L106:
+ if(ip!=3)goto L109;
+
+ ix2=iw+ido;
+ if(na!=0)
+ dradb3(ido,l1,ch,c,wa+iw-1,wa+ix2-1);
+ else
+ dradb3(ido,l1,c,ch,wa+iw-1,wa+ix2-1);
+ na=1-na;
+ goto L115;
+
+ L109:
+/* The radix five case can be translated later..... */
+/* if(ip!=5)goto L112;
+
+ ix2=iw+ido;
+ ix3=ix2+ido;
+ ix4=ix3+ido;
+ if(na!=0)
+ dradb5(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1,wa+ix4-1);
+ else
+ dradb5(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1,wa+ix4-1);
+ na=1-na;
+ goto L115;
+
+ L112:*/
+ if(na!=0)
+ dradbg(ido,ip,l1,idl1,ch,ch,ch,c,c,wa+iw-1);
+ else
+ dradbg(ido,ip,l1,idl1,c,c,c,ch,ch,wa+iw-1);
+ if(ido==1)na=1-na;
+
+ L115:
+ l1=l2;
+ iw+=(ip-1)*ido;
+ }
+
+ if(na==0)return;
+
+ for(i=0;i<n;i++)c[i]=ch[i];
+}
+
+void drft_forward(drft_lookup *l,float *data){
+ if(l->n==1)return;
+ drftf1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache);
+}
+
+void drft_backward(drft_lookup *l,float *data){
+ if (l->n==1)return;
+ drftb1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache);
+}
+
+void drft_init(drft_lookup *l,int n){
+ l->n=n;
+ l->trigcache=_ogg_calloc(3*n,sizeof(*l->trigcache));
+ l->splitcache=_ogg_calloc(32,sizeof(*l->splitcache));
+ fdrffti(n, l->trigcache, l->splitcache);
+}
+
+void drft_clear(drft_lookup *l){
+ if(l){
+ if(l->trigcache)_ogg_free(l->trigcache);
+ if(l->splitcache)_ogg_free(l->splitcache);
+ memset(l,0,sizeof(*l));
+ }
+}
diff --git a/external/libvorbis-1.3.5/lib/smallft.h b/external/libvorbis-1.3.5/lib/smallft.h
new file mode 100644
index 0000000..4564973
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/smallft.h
@@ -0,0 +1,34 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: fft transform
+ last mod: $Id: smallft.h 13293 2007-07-24 00:09:47Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_SMFT_H_
+#define _V_SMFT_H_
+
+#include "vorbis/codec.h"
+
+typedef struct {
+ int n;
+ float *trigcache;
+ int *splitcache;
+} drft_lookup;
+
+extern void drft_forward(drft_lookup *l,float *data);
+extern void drft_backward(drft_lookup *l,float *data);
+extern void drft_init(drft_lookup *l,int n);
+extern void drft_clear(drft_lookup *l);
+
+#endif
diff --git a/external/libvorbis-1.3.5/lib/synthesis.c b/external/libvorbis-1.3.5/lib/synthesis.c
new file mode 100644
index 0000000..932d271
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/synthesis.c
@@ -0,0 +1,180 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: single-block PCM synthesis
+ last mod: $Id: synthesis.c 19441 2015-01-21 01:17:41Z xiphmont $
+
+ ********************************************************************/
+
+#include <stdio.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codec_internal.h"
+#include "registry.h"
+#include "misc.h"
+#include "os.h"
+
+int vorbis_synthesis(vorbis_block *vb,ogg_packet *op){
+ vorbis_dsp_state *vd= vb ? vb->vd : 0;
+ private_state *b= vd ? vd->backend_state : 0;
+ vorbis_info *vi= vd ? vd->vi : 0;
+ codec_setup_info *ci= vi ? vi->codec_setup : 0;
+ oggpack_buffer *opb=vb ? &vb->opb : 0;
+ int type,mode,i;
+
+ if (!vd || !b || !vi || !ci || !opb) {
+ return OV_EBADPACKET;
+ }
+
+ /* first things first. Make sure decode is ready */
+ _vorbis_block_ripcord(vb);
+ oggpack_readinit(opb,op->packet,op->bytes);
+
+ /* Check the packet type */
+ if(oggpack_read(opb,1)!=0){
+ /* Oops. This is not an audio data packet */
+ return(OV_ENOTAUDIO);
+ }
+
+ /* read our mode and pre/post windowsize */
+ mode=oggpack_read(opb,b->modebits);
+ if(mode==-1){
+ return(OV_EBADPACKET);
+ }
+
+ vb->mode=mode;
+ if(!ci->mode_param[mode]){
+ return(OV_EBADPACKET);
+ }
+
+ vb->W=ci->mode_param[mode]->blockflag;
+ if(vb->W){
+
+ /* this doesn;t get mapped through mode selection as it's used
+ only for window selection */
+ vb->lW=oggpack_read(opb,1);
+ vb->nW=oggpack_read(opb,1);
+ if(vb->nW==-1){
+ return(OV_EBADPACKET);
+ }
+ }else{
+ vb->lW=0;
+ vb->nW=0;
+ }
+
+ /* more setup */
+ vb->granulepos=op->granulepos;
+ vb->sequence=op->packetno;
+ vb->eofflag=op->e_o_s;
+
+ /* alloc pcm passback storage */
+ vb->pcmend=ci->blocksizes[vb->W];
+ vb->pcm=_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels);
+ for(i=0;i<vi->channels;i++)
+ vb->pcm[i]=_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i]));
+
+ /* unpack_header enforces range checking */
+ type=ci->map_type[ci->mode_param[mode]->mapping];
+
+ return(_mapping_P[type]->inverse(vb,ci->map_param[ci->mode_param[mode]->
+ mapping]));
+}
+
+/* used to track pcm position without actually performing decode.
+ Useful for sequential 'fast forward' */
+int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op){
+ vorbis_dsp_state *vd=vb->vd;
+ private_state *b=vd->backend_state;
+ vorbis_info *vi=vd->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ oggpack_buffer *opb=&vb->opb;
+ int mode;
+
+ /* first things first. Make sure decode is ready */
+ _vorbis_block_ripcord(vb);
+ oggpack_readinit(opb,op->packet,op->bytes);
+
+ /* Check the packet type */
+ if(oggpack_read(opb,1)!=0){
+ /* Oops. This is not an audio data packet */
+ return(OV_ENOTAUDIO);
+ }
+
+ /* read our mode and pre/post windowsize */
+ mode=oggpack_read(opb,b->modebits);
+ if(mode==-1)return(OV_EBADPACKET);
+
+ vb->mode=mode;
+ if(!ci->mode_param[mode]){
+ return(OV_EBADPACKET);
+ }
+
+ vb->W=ci->mode_param[mode]->blockflag;
+ if(vb->W){
+ vb->lW=oggpack_read(opb,1);
+ vb->nW=oggpack_read(opb,1);
+ if(vb->nW==-1) return(OV_EBADPACKET);
+ }else{
+ vb->lW=0;
+ vb->nW=0;
+ }
+
+ /* more setup */
+ vb->granulepos=op->granulepos;
+ vb->sequence=op->packetno;
+ vb->eofflag=op->e_o_s;
+
+ /* no pcm */
+ vb->pcmend=0;
+ vb->pcm=NULL;
+
+ return(0);
+}
+
+long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
+ codec_setup_info *ci=vi->codec_setup;
+ oggpack_buffer opb;
+ int mode;
+
+ if(ci==NULL || ci->modes<=0){
+ /* codec setup not properly intialized */
+ return(OV_EFAULT);
+ }
+
+ oggpack_readinit(&opb,op->packet,op->bytes);
+
+ /* Check the packet type */
+ if(oggpack_read(&opb,1)!=0){
+ /* Oops. This is not an audio data packet */
+ return(OV_ENOTAUDIO);
+ }
+
+ /* read our mode and pre/post windowsize */
+ mode=oggpack_read(&opb,ov_ilog(ci->modes-1));
+ if(mode==-1 || !ci->mode_param[mode])return(OV_EBADPACKET);
+ return(ci->blocksizes[ci->mode_param[mode]->blockflag]);
+}
+
+int vorbis_synthesis_halfrate(vorbis_info *vi,int flag){
+ /* set / clear half-sample-rate mode */
+ codec_setup_info *ci=vi->codec_setup;
+
+ /* right now, our MDCT can't handle < 64 sample windows. */
+ if(ci->blocksizes[0]<=64 && flag)return -1;
+ ci->halfrate_flag=(flag?1:0);
+ return 0;
+}
+
+int vorbis_synthesis_halfrate_p(vorbis_info *vi){
+ codec_setup_info *ci=vi->codec_setup;
+ return ci->halfrate_flag;
+}
diff --git a/external/libvorbis-1.3.5/lib/vorbisenc.c b/external/libvorbis-1.3.5/lib/vorbisenc.c
new file mode 100644
index 0000000..b5d621e
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/vorbisenc.c
@@ -0,0 +1,1224 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: simple programmatic interface for encoder mode setup
+ last mod: $Id: vorbisenc.c 19457 2015-03-03 00:15:29Z giles $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "vorbis/codec.h"
+#include "vorbis/vorbisenc.h"
+
+#include "codec_internal.h"
+
+#include "os.h"
+#include "misc.h"
+
+/* careful with this; it's using static array sizing to make managing
+ all the modes a little less annoying. If we use a residue backend
+ with > 12 partition types, or a different division of iteration,
+ this needs to be updated. */
+typedef struct {
+ const static_codebook *books[12][4];
+} static_bookblock;
+
+typedef struct {
+ int res_type;
+ int limit_type; /* 0 lowpass limited, 1 point stereo limited */
+ int grouping;
+ const vorbis_info_residue0 *res;
+ const static_codebook *book_aux;
+ const static_codebook *book_aux_managed;
+ const static_bookblock *books_base;
+ const static_bookblock *books_base_managed;
+} vorbis_residue_template;
+
+typedef struct {
+ const vorbis_info_mapping0 *map;
+ const vorbis_residue_template *res;
+} vorbis_mapping_template;
+
+typedef struct vp_adjblock{
+ int block[P_BANDS];
+} vp_adjblock;
+
+typedef struct {
+ int data[NOISE_COMPAND_LEVELS];
+} compandblock;
+
+/* high level configuration information for setting things up
+ step-by-step with the detailed vorbis_encode_ctl interface.
+ There's a fair amount of redundancy such that interactive setup
+ does not directly deal with any vorbis_info or codec_setup_info
+ initialization; it's all stored (until full init) in this highlevel
+ setup, then flushed out to the real codec setup structs later. */
+
+typedef struct {
+ int att[P_NOISECURVES];
+ float boost;
+ float decay;
+} att3;
+typedef struct { int data[P_NOISECURVES]; } adj3;
+
+typedef struct {
+ int pre[PACKETBLOBS];
+ int post[PACKETBLOBS];
+ float kHz[PACKETBLOBS];
+ float lowpasskHz[PACKETBLOBS];
+} adj_stereo;
+
+typedef struct {
+ int lo;
+ int hi;
+ int fixed;
+} noiseguard;
+typedef struct {
+ int data[P_NOISECURVES][17];
+} noise3;
+
+typedef struct {
+ int mappings;
+ const double *rate_mapping;
+ const double *quality_mapping;
+ int coupling_restriction;
+ long samplerate_min_restriction;
+ long samplerate_max_restriction;
+
+
+ const int *blocksize_short;
+ const int *blocksize_long;
+
+ const att3 *psy_tone_masteratt;
+ const int *psy_tone_0dB;
+ const int *psy_tone_dBsuppress;
+
+ const vp_adjblock *psy_tone_adj_impulse;
+ const vp_adjblock *psy_tone_adj_long;
+ const vp_adjblock *psy_tone_adj_other;
+
+ const noiseguard *psy_noiseguards;
+ const noise3 *psy_noise_bias_impulse;
+ const noise3 *psy_noise_bias_padding;
+ const noise3 *psy_noise_bias_trans;
+ const noise3 *psy_noise_bias_long;
+ const int *psy_noise_dBsuppress;
+
+ const compandblock *psy_noise_compand;
+ const double *psy_noise_compand_short_mapping;
+ const double *psy_noise_compand_long_mapping;
+
+ const int *psy_noise_normal_start[2];
+ const int *psy_noise_normal_partition[2];
+ const double *psy_noise_normal_thresh;
+
+ const int *psy_ath_float;
+ const int *psy_ath_abs;
+
+ const double *psy_lowpass;
+
+ const vorbis_info_psy_global *global_params;
+ const double *global_mapping;
+ const adj_stereo *stereo_modes;
+
+ const static_codebook *const *const *const floor_books;
+ const vorbis_info_floor1 *floor_params;
+ const int floor_mappings;
+ const int **floor_mapping_list;
+
+ const vorbis_mapping_template *maps;
+} ve_setup_data_template;
+
+/* a few static coder conventions */
+static const vorbis_info_mode _mode_template[2]={
+ {0,0,0,0},
+ {1,0,0,1}
+};
+
+static const vorbis_info_mapping0 _map_nominal[2]={
+ {1, {0,0}, {0}, {0}, 1,{0},{1}},
+ {1, {0,0}, {1}, {1}, 1,{0},{1}}
+};
+
+#include "modes/setup_44.h"
+#include "modes/setup_44u.h"
+#include "modes/setup_44p51.h"
+#include "modes/setup_32.h"
+#include "modes/setup_8.h"
+#include "modes/setup_11.h"
+#include "modes/setup_16.h"
+#include "modes/setup_22.h"
+#include "modes/setup_X.h"
+
+static const ve_setup_data_template *const setup_list[]={
+ &ve_setup_44_stereo,
+ &ve_setup_44_51,
+ &ve_setup_44_uncoupled,
+
+ &ve_setup_32_stereo,
+ &ve_setup_32_uncoupled,
+
+ &ve_setup_22_stereo,
+ &ve_setup_22_uncoupled,
+ &ve_setup_16_stereo,
+ &ve_setup_16_uncoupled,
+
+ &ve_setup_11_stereo,
+ &ve_setup_11_uncoupled,
+ &ve_setup_8_stereo,
+ &ve_setup_8_uncoupled,
+
+ &ve_setup_X_stereo,
+ &ve_setup_X_uncoupled,
+ &ve_setup_XX_stereo,
+ &ve_setup_XX_uncoupled,
+ 0
+};
+
+static void vorbis_encode_floor_setup(vorbis_info *vi,int s,
+ const static_codebook *const *const *const books,
+ const vorbis_info_floor1 *in,
+ const int *x){
+ int i,k,is=s;
+ vorbis_info_floor1 *f=_ogg_calloc(1,sizeof(*f));
+ codec_setup_info *ci=vi->codec_setup;
+
+ memcpy(f,in+x[is],sizeof(*f));
+
+ /* books */
+ {
+ int partitions=f->partitions;
+ int maxclass=-1;
+ int maxbook=-1;
+ for(i=0;i<partitions;i++)
+ if(f->partitionclass[i]>maxclass)maxclass=f->partitionclass[i];
+ for(i=0;i<=maxclass;i++){
+ if(f->class_book[i]>maxbook)maxbook=f->class_book[i];
+ f->class_book[i]+=ci->books;
+ for(k=0;k<(1<<f->class_subs[i]);k++){
+ if(f->class_subbook[i][k]>maxbook)maxbook=f->class_subbook[i][k];
+ if(f->class_subbook[i][k]>=0)f->class_subbook[i][k]+=ci->books;
+ }
+ }
+
+ for(i=0;i<=maxbook;i++)
+ ci->book_param[ci->books++]=(static_codebook *)books[x[is]][i];
+ }
+
+ /* for now, we're only using floor 1 */
+ ci->floor_type[ci->floors]=1;
+ ci->floor_param[ci->floors]=f;
+ ci->floors++;
+
+ return;
+}
+
+static void vorbis_encode_global_psych_setup(vorbis_info *vi,double s,
+ const vorbis_info_psy_global *in,
+ const double *x){
+ int i,is=s;
+ double ds=s-is;
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy_global *g=&ci->psy_g_param;
+
+ memcpy(g,in+(int)x[is],sizeof(*g));
+
+ ds=x[is]*(1.-ds)+x[is+1]*ds;
+ is=(int)ds;
+ ds-=is;
+ if(ds==0 && is>0){
+ is--;
+ ds=1.;
+ }
+
+ /* interpolate the trigger threshholds */
+ for(i=0;i<4;i++){
+ g->preecho_thresh[i]=in[is].preecho_thresh[i]*(1.-ds)+in[is+1].preecho_thresh[i]*ds;
+ g->postecho_thresh[i]=in[is].postecho_thresh[i]*(1.-ds)+in[is+1].postecho_thresh[i]*ds;
+ }
+ g->ampmax_att_per_sec=ci->hi.amplitude_track_dBpersec;
+ return;
+}
+
+static void vorbis_encode_global_stereo(vorbis_info *vi,
+ const highlevel_encode_setup *const hi,
+ const adj_stereo *p){
+ float s=hi->stereo_point_setting;
+ int i,is=s;
+ double ds=s-is;
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy_global *g=&ci->psy_g_param;
+
+ if(p){
+ memcpy(g->coupling_prepointamp,p[is].pre,sizeof(*p[is].pre)*PACKETBLOBS);
+ memcpy(g->coupling_postpointamp,p[is].post,sizeof(*p[is].post)*PACKETBLOBS);
+
+ if(hi->managed){
+ /* interpolate the kHz threshholds */
+ for(i=0;i<PACKETBLOBS;i++){
+ float kHz=p[is].kHz[i]*(1.-ds)+p[is+1].kHz[i]*ds;
+ g->coupling_pointlimit[0][i]=kHz*1000./vi->rate*ci->blocksizes[0];
+ g->coupling_pointlimit[1][i]=kHz*1000./vi->rate*ci->blocksizes[1];
+ g->coupling_pkHz[i]=kHz;
+
+ kHz=p[is].lowpasskHz[i]*(1.-ds)+p[is+1].lowpasskHz[i]*ds;
+ g->sliding_lowpass[0][i]=kHz*1000./vi->rate*ci->blocksizes[0];
+ g->sliding_lowpass[1][i]=kHz*1000./vi->rate*ci->blocksizes[1];
+
+ }
+ }else{
+ float kHz=p[is].kHz[PACKETBLOBS/2]*(1.-ds)+p[is+1].kHz[PACKETBLOBS/2]*ds;
+ for(i=0;i<PACKETBLOBS;i++){
+ g->coupling_pointlimit[0][i]=kHz*1000./vi->rate*ci->blocksizes[0];
+ g->coupling_pointlimit[1][i]=kHz*1000./vi->rate*ci->blocksizes[1];
+ g->coupling_pkHz[i]=kHz;
+ }
+
+ kHz=p[is].lowpasskHz[PACKETBLOBS/2]*(1.-ds)+p[is+1].lowpasskHz[PACKETBLOBS/2]*ds;
+ for(i=0;i<PACKETBLOBS;i++){
+ g->sliding_lowpass[0][i]=kHz*1000./vi->rate*ci->blocksizes[0];
+ g->sliding_lowpass[1][i]=kHz*1000./vi->rate*ci->blocksizes[1];
+ }
+ }
+ }else{
+ for(i=0;i<PACKETBLOBS;i++){
+ g->sliding_lowpass[0][i]=ci->blocksizes[0];
+ g->sliding_lowpass[1][i]=ci->blocksizes[1];
+ }
+ }
+ return;
+}
+
+static void vorbis_encode_psyset_setup(vorbis_info *vi,double s,
+ const int *nn_start,
+ const int *nn_partition,
+ const double *nn_thresh,
+ int block){
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy *p=ci->psy_param[block];
+ highlevel_encode_setup *hi=&ci->hi;
+ int is=s;
+
+ if(block>=ci->psys)
+ ci->psys=block+1;
+ if(!p){
+ p=_ogg_calloc(1,sizeof(*p));
+ ci->psy_param[block]=p;
+ }
+
+ memcpy(p,&_psy_info_template,sizeof(*p));
+ p->blockflag=block>>1;
+
+ if(hi->noise_normalize_p){
+ p->normal_p=1;
+ p->normal_start=nn_start[is];
+ p->normal_partition=nn_partition[is];
+ p->normal_thresh=nn_thresh[is];
+ }
+
+ return;
+}
+
+static void vorbis_encode_tonemask_setup(vorbis_info *vi,double s,int block,
+ const att3 *att,
+ const int *max,
+ const vp_adjblock *in){
+ int i,is=s;
+ double ds=s-is;
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy *p=ci->psy_param[block];
+
+ /* 0 and 2 are only used by bitmanagement, but there's no harm to always
+ filling the values in here */
+ p->tone_masteratt[0]=att[is].att[0]*(1.-ds)+att[is+1].att[0]*ds;
+ p->tone_masteratt[1]=att[is].att[1]*(1.-ds)+att[is+1].att[1]*ds;
+ p->tone_masteratt[2]=att[is].att[2]*(1.-ds)+att[is+1].att[2]*ds;
+ p->tone_centerboost=att[is].boost*(1.-ds)+att[is+1].boost*ds;
+ p->tone_decay=att[is].decay*(1.-ds)+att[is+1].decay*ds;
+
+ p->max_curve_dB=max[is]*(1.-ds)+max[is+1]*ds;
+
+ for(i=0;i<P_BANDS;i++)
+ p->toneatt[i]=in[is].block[i]*(1.-ds)+in[is+1].block[i]*ds;
+ return;
+}
+
+
+static void vorbis_encode_compand_setup(vorbis_info *vi,double s,int block,
+ const compandblock *in,
+ const double *x){
+ int i,is=s;
+ double ds=s-is;
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy *p=ci->psy_param[block];
+
+ ds=x[is]*(1.-ds)+x[is+1]*ds;
+ is=(int)ds;
+ ds-=is;
+ if(ds==0 && is>0){
+ is--;
+ ds=1.;
+ }
+
+ /* interpolate the compander settings */
+ for(i=0;i<NOISE_COMPAND_LEVELS;i++)
+ p->noisecompand[i]=in[is].data[i]*(1.-ds)+in[is+1].data[i]*ds;
+ return;
+}
+
+static void vorbis_encode_peak_setup(vorbis_info *vi,double s,int block,
+ const int *suppress){
+ int is=s;
+ double ds=s-is;
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy *p=ci->psy_param[block];
+
+ p->tone_abs_limit=suppress[is]*(1.-ds)+suppress[is+1]*ds;
+
+ return;
+}
+
+static void vorbis_encode_noisebias_setup(vorbis_info *vi,double s,int block,
+ const int *suppress,
+ const noise3 *in,
+ const noiseguard *guard,
+ double userbias){
+ int i,is=s,j;
+ double ds=s-is;
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy *p=ci->psy_param[block];
+
+ p->noisemaxsupp=suppress[is]*(1.-ds)+suppress[is+1]*ds;
+ p->noisewindowlomin=guard[block].lo;
+ p->noisewindowhimin=guard[block].hi;
+ p->noisewindowfixed=guard[block].fixed;
+
+ for(j=0;j<P_NOISECURVES;j++)
+ for(i=0;i<P_BANDS;i++)
+ p->noiseoff[j][i]=in[is].data[j][i]*(1.-ds)+in[is+1].data[j][i]*ds;
+
+ /* impulse blocks may take a user specified bias to boost the
+ nominal/high noise encoding depth */
+ for(j=0;j<P_NOISECURVES;j++){
+ float min=p->noiseoff[j][0]+6; /* the lowest it can go */
+ for(i=0;i<P_BANDS;i++){
+ p->noiseoff[j][i]+=userbias;
+ if(p->noiseoff[j][i]<min)p->noiseoff[j][i]=min;
+ }
+ }
+
+ return;
+}
+
+static void vorbis_encode_ath_setup(vorbis_info *vi,int block){
+ codec_setup_info *ci=vi->codec_setup;
+ vorbis_info_psy *p=ci->psy_param[block];
+
+ p->ath_adjatt=ci->hi.ath_floating_dB;
+ p->ath_maxatt=ci->hi.ath_absolute_dB;
+ return;
+}
+
+
+static int book_dup_or_new(codec_setup_info *ci,const static_codebook *book){
+ int i;
+ for(i=0;i<ci->books;i++)
+ if(ci->book_param[i]==book)return(i);
+
+ return(ci->books++);
+}
+
+static void vorbis_encode_blocksize_setup(vorbis_info *vi,double s,
+ const int *shortb,const int *longb){
+
+ codec_setup_info *ci=vi->codec_setup;
+ int is=s;
+
+ int blockshort=shortb[is];
+ int blocklong=longb[is];
+ ci->blocksizes[0]=blockshort;
+ ci->blocksizes[1]=blocklong;
+
+}
+
+static void vorbis_encode_residue_setup(vorbis_info *vi,
+ int number, int block,
+ const vorbis_residue_template *res){
+
+ codec_setup_info *ci=vi->codec_setup;
+ int i;
+
+ vorbis_info_residue0 *r=ci->residue_param[number]=
+ _ogg_malloc(sizeof(*r));
+
+ memcpy(r,res->res,sizeof(*r));
+ if(ci->residues<=number)ci->residues=number+1;
+
+ r->grouping=res->grouping;
+ ci->residue_type[number]=res->res_type;
+
+ /* fill in all the books */
+ {
+ int booklist=0,k;
+
+ if(ci->hi.managed){
+ for(i=0;i<r->partitions;i++)
+ for(k=0;k<4;k++)
+ if(res->books_base_managed->books[i][k])
+ r->secondstages[i]|=(1<<k);
+
+ r->groupbook=book_dup_or_new(ci,res->book_aux_managed);
+ ci->book_param[r->groupbook]=(static_codebook *)res->book_aux_managed;
+
+ for(i=0;i<r->partitions;i++){
+ for(k=0;k<4;k++){
+ if(res->books_base_managed->books[i][k]){
+ int bookid=book_dup_or_new(ci,res->books_base_managed->books[i][k]);
+ r->booklist[booklist++]=bookid;
+ ci->book_param[bookid]=(static_codebook *)res->books_base_managed->books[i][k];
+ }
+ }
+ }
+
+ }else{
+
+ for(i=0;i<r->partitions;i++)
+ for(k=0;k<4;k++)
+ if(res->books_base->books[i][k])
+ r->secondstages[i]|=(1<<k);
+
+ r->groupbook=book_dup_or_new(ci,res->book_aux);
+ ci->book_param[r->groupbook]=(static_codebook *)res->book_aux;
+
+ for(i=0;i<r->partitions;i++){
+ for(k=0;k<4;k++){
+ if(res->books_base->books[i][k]){
+ int bookid=book_dup_or_new(ci,res->books_base->books[i][k]);
+ r->booklist[booklist++]=bookid;
+ ci->book_param[bookid]=(static_codebook *)res->books_base->books[i][k];
+ }
+ }
+ }
+ }
+ }
+
+ /* lowpass setup/pointlimit */
+ {
+ double freq=ci->hi.lowpass_kHz*1000.;
+ vorbis_info_floor1 *f=ci->floor_param[block]; /* by convention */
+ double nyq=vi->rate/2.;
+ long blocksize=ci->blocksizes[block]>>1;
+
+ /* lowpass needs to be set in the floor and the residue. */
+ if(freq>nyq)freq=nyq;
+ /* in the floor, the granularity can be very fine; it doesn't alter
+ the encoding structure, only the samples used to fit the floor
+ approximation */
+ f->n=freq/nyq*blocksize;
+
+ /* this res may by limited by the maximum pointlimit of the mode,
+ not the lowpass. the floor is always lowpass limited. */
+ switch(res->limit_type){
+ case 1: /* point stereo limited */
+ if(ci->hi.managed)
+ freq=ci->psy_g_param.coupling_pkHz[PACKETBLOBS-1]*1000.;
+ else
+ freq=ci->psy_g_param.coupling_pkHz[PACKETBLOBS/2]*1000.;
+ if(freq>nyq)freq=nyq;
+ break;
+ case 2: /* LFE channel; lowpass at ~ 250Hz */
+ freq=250;
+ break;
+ default:
+ /* already set */
+ break;
+ }
+
+ /* in the residue, we're constrained, physically, by partition
+ boundaries. We still lowpass 'wherever', but we have to round up
+ here to next boundary, or the vorbis spec will round it *down* to
+ previous boundary in encode/decode */
+ if(ci->residue_type[number]==2){
+ /* residue 2 bundles together multiple channels; used by stereo
+ and surround. Count the channels in use */
+ /* Multiple maps/submaps can point to the same residue. In the case
+ of residue 2, they all better have the same number of
+ channels/samples. */
+ int j,k,ch=0;
+ for(i=0;i<ci->maps&&ch==0;i++){
+ vorbis_info_mapping0 *mi=(vorbis_info_mapping0 *)ci->map_param[i];
+ for(j=0;j<mi->submaps && ch==0;j++)
+ if(mi->residuesubmap[j]==number) /* we found a submap referencing theis residue backend */
+ for(k=0;k<vi->channels;k++)
+ if(mi->chmuxlist[k]==j) /* this channel belongs to the submap */
+ ch++;
+ }
+
+ r->end=(int)((freq/nyq*blocksize*ch)/r->grouping+.9)* /* round up only if we're well past */
+ r->grouping;
+ /* the blocksize and grouping may disagree at the end */
+ if(r->end>blocksize*ch)r->end=blocksize*ch/r->grouping*r->grouping;
+
+ }else{
+
+ r->end=(int)((freq/nyq*blocksize)/r->grouping+.9)* /* round up only if we're well past */
+ r->grouping;
+ /* the blocksize and grouping may disagree at the end */
+ if(r->end>blocksize)r->end=blocksize/r->grouping*r->grouping;
+
+ }
+
+ if(r->end==0)r->end=r->grouping; /* LFE channel */
+
+ }
+}
+
+/* we assume two maps in this encoder */
+static void vorbis_encode_map_n_res_setup(vorbis_info *vi,double s,
+ const vorbis_mapping_template *maps){
+
+ codec_setup_info *ci=vi->codec_setup;
+ int i,j,is=s,modes=2;
+ const vorbis_info_mapping0 *map=maps[is].map;
+ const vorbis_info_mode *mode=_mode_template;
+ const vorbis_residue_template *res=maps[is].res;
+
+ if(ci->blocksizes[0]==ci->blocksizes[1])modes=1;
+
+ for(i=0;i<modes;i++){
+
+ ci->map_param[i]=_ogg_calloc(1,sizeof(*map));
+ ci->mode_param[i]=_ogg_calloc(1,sizeof(*mode));
+
+ memcpy(ci->mode_param[i],mode+i,sizeof(*_mode_template));
+ if(i>=ci->modes)ci->modes=i+1;
+
+ ci->map_type[i]=0;
+ memcpy(ci->map_param[i],map+i,sizeof(*map));
+ if(i>=ci->maps)ci->maps=i+1;
+
+ for(j=0;j<map[i].submaps;j++)
+ vorbis_encode_residue_setup(vi,map[i].residuesubmap[j],i
+ ,res+map[i].residuesubmap[j]);
+ }
+}
+
+static double setting_to_approx_bitrate(vorbis_info *vi){
+ codec_setup_info *ci=vi->codec_setup;
+ highlevel_encode_setup *hi=&ci->hi;
+ ve_setup_data_template *setup=(ve_setup_data_template *)hi->setup;
+ int is=hi->base_setting;
+ double ds=hi->base_setting-is;
+ int ch=vi->channels;
+ const double *r=setup->rate_mapping;
+
+ if(r==NULL)
+ return(-1);
+
+ return((r[is]*(1.-ds)+r[is+1]*ds)*ch);
+}
+
+static const void *get_setup_template(long ch,long srate,
+ double req,int q_or_bitrate,
+ double *base_setting){
+ int i=0,j;
+ if(q_or_bitrate)req/=ch;
+
+ while(setup_list[i]){
+ if(setup_list[i]->coupling_restriction==-1 ||
+ setup_list[i]->coupling_restriction==ch){
+ if(srate>=setup_list[i]->samplerate_min_restriction &&
+ srate<=setup_list[i]->samplerate_max_restriction){
+ int mappings=setup_list[i]->mappings;
+ const double *map=(q_or_bitrate?
+ setup_list[i]->rate_mapping:
+ setup_list[i]->quality_mapping);
+
+ /* the template matches. Does the requested quality mode
+ fall within this template's modes? */
+ if(req<map[0]){++i;continue;}
+ if(req>map[setup_list[i]->mappings]){++i;continue;}
+ for(j=0;j<mappings;j++)
+ if(req>=map[j] && req<map[j+1])break;
+ /* an all-points match */
+ if(j==mappings)
+ *base_setting=j-.001;
+ else{
+ float low=map[j];
+ float high=map[j+1];
+ float del=(req-low)/(high-low);
+ *base_setting=j+del;
+ }
+
+ return(setup_list[i]);
+ }
+ }
+ i++;
+ }
+
+ return NULL;
+}
+
+/* encoders will need to use vorbis_info_init beforehand and call
+ vorbis_info clear when all done */
+
+/* two interfaces; this, more detailed one, and later a convenience
+ layer on top */
+
+/* the final setup call */
+int vorbis_encode_setup_init(vorbis_info *vi){
+ int i,i0=0,singleblock=0;
+ codec_setup_info *ci=vi->codec_setup;
+ ve_setup_data_template *setup=NULL;
+ highlevel_encode_setup *hi=&ci->hi;
+
+ if(ci==NULL)return(OV_EINVAL);
+ if(!hi->impulse_block_p)i0=1;
+
+ /* too low/high an ATH floater is nonsensical, but doesn't break anything */
+ if(hi->ath_floating_dB>-80)hi->ath_floating_dB=-80;
+ if(hi->ath_floating_dB<-200)hi->ath_floating_dB=-200;
+
+ /* again, bound this to avoid the app shooting itself int he foot
+ too badly */
+ if(hi->amplitude_track_dBpersec>0.)hi->amplitude_track_dBpersec=0.;
+ if(hi->amplitude_track_dBpersec<-99999.)hi->amplitude_track_dBpersec=-99999.;
+
+ /* get the appropriate setup template; matches the fetch in previous
+ stages */
+ setup=(ve_setup_data_template *)hi->setup;
+ if(setup==NULL)return(OV_EINVAL);
+
+ hi->set_in_stone=1;
+ /* choose block sizes from configured sizes as well as paying
+ attention to long_block_p and short_block_p. If the configured
+ short and long blocks are the same length, we set long_block_p
+ and unset short_block_p */
+ vorbis_encode_blocksize_setup(vi,hi->base_setting,
+ setup->blocksize_short,
+ setup->blocksize_long);
+ if(ci->blocksizes[0]==ci->blocksizes[1])singleblock=1;
+
+ /* floor setup; choose proper floor params. Allocated on the floor
+ stack in order; if we alloc only a single long floor, it's 0 */
+ for(i=0;i<setup->floor_mappings;i++)
+ vorbis_encode_floor_setup(vi,hi->base_setting,
+ setup->floor_books,
+ setup->floor_params,
+ setup->floor_mapping_list[i]);
+
+ /* setup of [mostly] short block detection and stereo*/
+ vorbis_encode_global_psych_setup(vi,hi->trigger_setting,
+ setup->global_params,
+ setup->global_mapping);
+ vorbis_encode_global_stereo(vi,hi,setup->stereo_modes);
+
+ /* basic psych setup and noise normalization */
+ vorbis_encode_psyset_setup(vi,hi->base_setting,
+ setup->psy_noise_normal_start[0],
+ setup->psy_noise_normal_partition[0],
+ setup->psy_noise_normal_thresh,
+ 0);
+ vorbis_encode_psyset_setup(vi,hi->base_setting,
+ setup->psy_noise_normal_start[0],
+ setup->psy_noise_normal_partition[0],
+ setup->psy_noise_normal_thresh,
+ 1);
+ if(!singleblock){
+ vorbis_encode_psyset_setup(vi,hi->base_setting,
+ setup->psy_noise_normal_start[1],
+ setup->psy_noise_normal_partition[1],
+ setup->psy_noise_normal_thresh,
+ 2);
+ vorbis_encode_psyset_setup(vi,hi->base_setting,
+ setup->psy_noise_normal_start[1],
+ setup->psy_noise_normal_partition[1],
+ setup->psy_noise_normal_thresh,
+ 3);
+ }
+
+ /* tone masking setup */
+ vorbis_encode_tonemask_setup(vi,hi->block[i0].tone_mask_setting,0,
+ setup->psy_tone_masteratt,
+ setup->psy_tone_0dB,
+ setup->psy_tone_adj_impulse);
+ vorbis_encode_tonemask_setup(vi,hi->block[1].tone_mask_setting,1,
+ setup->psy_tone_masteratt,
+ setup->psy_tone_0dB,
+ setup->psy_tone_adj_other);
+ if(!singleblock){
+ vorbis_encode_tonemask_setup(vi,hi->block[2].tone_mask_setting,2,
+ setup->psy_tone_masteratt,
+ setup->psy_tone_0dB,
+ setup->psy_tone_adj_other);
+ vorbis_encode_tonemask_setup(vi,hi->block[3].tone_mask_setting,3,
+ setup->psy_tone_masteratt,
+ setup->psy_tone_0dB,
+ setup->psy_tone_adj_long);
+ }
+
+ /* noise companding setup */
+ vorbis_encode_compand_setup(vi,hi->block[i0].noise_compand_setting,0,
+ setup->psy_noise_compand,
+ setup->psy_noise_compand_short_mapping);
+ vorbis_encode_compand_setup(vi,hi->block[1].noise_compand_setting,1,
+ setup->psy_noise_compand,
+ setup->psy_noise_compand_short_mapping);
+ if(!singleblock){
+ vorbis_encode_compand_setup(vi,hi->block[2].noise_compand_setting,2,
+ setup->psy_noise_compand,
+ setup->psy_noise_compand_long_mapping);
+ vorbis_encode_compand_setup(vi,hi->block[3].noise_compand_setting,3,
+ setup->psy_noise_compand,
+ setup->psy_noise_compand_long_mapping);
+ }
+
+ /* peak guarding setup */
+ vorbis_encode_peak_setup(vi,hi->block[i0].tone_peaklimit_setting,0,
+ setup->psy_tone_dBsuppress);
+ vorbis_encode_peak_setup(vi,hi->block[1].tone_peaklimit_setting,1,
+ setup->psy_tone_dBsuppress);
+ if(!singleblock){
+ vorbis_encode_peak_setup(vi,hi->block[2].tone_peaklimit_setting,2,
+ setup->psy_tone_dBsuppress);
+ vorbis_encode_peak_setup(vi,hi->block[3].tone_peaklimit_setting,3,
+ setup->psy_tone_dBsuppress);
+ }
+
+ /* noise bias setup */
+ vorbis_encode_noisebias_setup(vi,hi->block[i0].noise_bias_setting,0,
+ setup->psy_noise_dBsuppress,
+ setup->psy_noise_bias_impulse,
+ setup->psy_noiseguards,
+ (i0==0?hi->impulse_noisetune:0.));
+ vorbis_encode_noisebias_setup(vi,hi->block[1].noise_bias_setting,1,
+ setup->psy_noise_dBsuppress,
+ setup->psy_noise_bias_padding,
+ setup->psy_noiseguards,0.);
+ if(!singleblock){
+ vorbis_encode_noisebias_setup(vi,hi->block[2].noise_bias_setting,2,
+ setup->psy_noise_dBsuppress,
+ setup->psy_noise_bias_trans,
+ setup->psy_noiseguards,0.);
+ vorbis_encode_noisebias_setup(vi,hi->block[3].noise_bias_setting,3,
+ setup->psy_noise_dBsuppress,
+ setup->psy_noise_bias_long,
+ setup->psy_noiseguards,0.);
+ }
+
+ vorbis_encode_ath_setup(vi,0);
+ vorbis_encode_ath_setup(vi,1);
+ if(!singleblock){
+ vorbis_encode_ath_setup(vi,2);
+ vorbis_encode_ath_setup(vi,3);
+ }
+
+ vorbis_encode_map_n_res_setup(vi,hi->base_setting,setup->maps);
+
+ /* set bitrate readonlies and management */
+ if(hi->bitrate_av>0)
+ vi->bitrate_nominal=hi->bitrate_av;
+ else{
+ vi->bitrate_nominal=setting_to_approx_bitrate(vi);
+ }
+
+ vi->bitrate_lower=hi->bitrate_min;
+ vi->bitrate_upper=hi->bitrate_max;
+ if(hi->bitrate_av)
+ vi->bitrate_window=(double)hi->bitrate_reservoir/hi->bitrate_av;
+ else
+ vi->bitrate_window=0.;
+
+ if(hi->managed){
+ ci->bi.avg_rate=hi->bitrate_av;
+ ci->bi.min_rate=hi->bitrate_min;
+ ci->bi.max_rate=hi->bitrate_max;
+
+ ci->bi.reservoir_bits=hi->bitrate_reservoir;
+ ci->bi.reservoir_bias=
+ hi->bitrate_reservoir_bias;
+
+ ci->bi.slew_damp=hi->bitrate_av_damp;
+
+ }
+
+ return(0);
+
+}
+
+static void vorbis_encode_setup_setting(vorbis_info *vi,
+ long channels,
+ long rate){
+ int i,is;
+ codec_setup_info *ci=vi->codec_setup;
+ highlevel_encode_setup *hi=&ci->hi;
+ const ve_setup_data_template *setup=hi->setup;
+ double ds;
+
+ vi->version=0;
+ vi->channels=channels;
+ vi->rate=rate;
+
+ hi->impulse_block_p=1;
+ hi->noise_normalize_p=1;
+
+ is=hi->base_setting;
+ ds=hi->base_setting-is;
+
+ hi->stereo_point_setting=hi->base_setting;
+
+ if(!hi->lowpass_altered)
+ hi->lowpass_kHz=
+ setup->psy_lowpass[is]*(1.-ds)+setup->psy_lowpass[is+1]*ds;
+
+ hi->ath_floating_dB=setup->psy_ath_float[is]*(1.-ds)+
+ setup->psy_ath_float[is+1]*ds;
+ hi->ath_absolute_dB=setup->psy_ath_abs[is]*(1.-ds)+
+ setup->psy_ath_abs[is+1]*ds;
+
+ hi->amplitude_track_dBpersec=-6.;
+ hi->trigger_setting=hi->base_setting;
+
+ for(i=0;i<4;i++){
+ hi->block[i].tone_mask_setting=hi->base_setting;
+ hi->block[i].tone_peaklimit_setting=hi->base_setting;
+ hi->block[i].noise_bias_setting=hi->base_setting;
+ hi->block[i].noise_compand_setting=hi->base_setting;
+ }
+}
+
+int vorbis_encode_setup_vbr(vorbis_info *vi,
+ long channels,
+ long rate,
+ float quality){
+ codec_setup_info *ci;
+ highlevel_encode_setup *hi;
+ if(rate<=0) return OV_EINVAL;
+
+ ci=vi->codec_setup;
+ hi=&ci->hi;
+
+ quality+=.0000001;
+ if(quality>=1.)quality=.9999;
+
+ hi->req=quality;
+ hi->setup=get_setup_template(channels,rate,quality,0,&hi->base_setting);
+ if(!hi->setup)return OV_EIMPL;
+
+ vorbis_encode_setup_setting(vi,channels,rate);
+ hi->managed=0;
+ hi->coupling_p=1;
+
+ return 0;
+}
+
+int vorbis_encode_init_vbr(vorbis_info *vi,
+ long channels,
+ long rate,
+
+ float base_quality /* 0. to 1. */
+ ){
+ int ret=0;
+
+ ret=vorbis_encode_setup_vbr(vi,channels,rate,base_quality);
+
+ if(ret){
+ vorbis_info_clear(vi);
+ return ret;
+ }
+ ret=vorbis_encode_setup_init(vi);
+ if(ret)
+ vorbis_info_clear(vi);
+ return(ret);
+}
+
+int vorbis_encode_setup_managed(vorbis_info *vi,
+ long channels,
+ long rate,
+
+ long max_bitrate,
+ long nominal_bitrate,
+ long min_bitrate){
+
+ codec_setup_info *ci;
+ highlevel_encode_setup *hi;
+ double tnominal;
+ if(rate<=0) return OV_EINVAL;
+
+ ci=vi->codec_setup;
+ hi=&ci->hi;
+ tnominal=nominal_bitrate;
+
+ if(nominal_bitrate<=0.){
+ if(max_bitrate>0.){
+ if(min_bitrate>0.)
+ nominal_bitrate=(max_bitrate+min_bitrate)*.5;
+ else
+ nominal_bitrate=max_bitrate*.875;
+ }else{
+ if(min_bitrate>0.){
+ nominal_bitrate=min_bitrate;
+ }else{
+ return(OV_EINVAL);
+ }
+ }
+ }
+
+ hi->req=nominal_bitrate;
+ hi->setup=get_setup_template(channels,rate,nominal_bitrate,1,&hi->base_setting);
+ if(!hi->setup)return OV_EIMPL;
+
+ vorbis_encode_setup_setting(vi,channels,rate);
+
+ /* initialize management with sane defaults */
+ hi->coupling_p=1;
+ hi->managed=1;
+ hi->bitrate_min=min_bitrate;
+ hi->bitrate_max=max_bitrate;
+ hi->bitrate_av=tnominal;
+ hi->bitrate_av_damp=1.5f; /* full range in no less than 1.5 second */
+ hi->bitrate_reservoir=nominal_bitrate*2;
+ hi->bitrate_reservoir_bias=.1; /* bias toward hoarding bits */
+
+ return(0);
+
+}
+
+int vorbis_encode_init(vorbis_info *vi,
+ long channels,
+ long rate,
+
+ long max_bitrate,
+ long nominal_bitrate,
+ long min_bitrate){
+
+ int ret=vorbis_encode_setup_managed(vi,channels,rate,
+ max_bitrate,
+ nominal_bitrate,
+ min_bitrate);
+ if(ret){
+ vorbis_info_clear(vi);
+ return(ret);
+ }
+
+ ret=vorbis_encode_setup_init(vi);
+ if(ret)
+ vorbis_info_clear(vi);
+ return(ret);
+}
+
+int vorbis_encode_ctl(vorbis_info *vi,int number,void *arg){
+ if(vi){
+ codec_setup_info *ci=vi->codec_setup;
+ highlevel_encode_setup *hi=&ci->hi;
+ int setp=(number&0xf); /* a read request has a low nibble of 0 */
+
+ if(setp && hi->set_in_stone)return(OV_EINVAL);
+
+ switch(number){
+
+ /* now deprecated *****************/
+ case OV_ECTL_RATEMANAGE_GET:
+ {
+
+ struct ovectl_ratemanage_arg *ai=
+ (struct ovectl_ratemanage_arg *)arg;
+
+ ai->management_active=hi->managed;
+ ai->bitrate_hard_window=ai->bitrate_av_window=
+ (double)hi->bitrate_reservoir/vi->rate;
+ ai->bitrate_av_window_center=1.;
+ ai->bitrate_hard_min=hi->bitrate_min;
+ ai->bitrate_hard_max=hi->bitrate_max;
+ ai->bitrate_av_lo=hi->bitrate_av;
+ ai->bitrate_av_hi=hi->bitrate_av;
+
+ }
+ return(0);
+
+ /* now deprecated *****************/
+ case OV_ECTL_RATEMANAGE_SET:
+ {
+ struct ovectl_ratemanage_arg *ai=
+ (struct ovectl_ratemanage_arg *)arg;
+ if(ai==NULL){
+ hi->managed=0;
+ }else{
+ hi->managed=ai->management_active;
+ vorbis_encode_ctl(vi,OV_ECTL_RATEMANAGE_AVG,arg);
+ vorbis_encode_ctl(vi,OV_ECTL_RATEMANAGE_HARD,arg);
+ }
+ }
+ return 0;
+
+ /* now deprecated *****************/
+ case OV_ECTL_RATEMANAGE_AVG:
+ {
+ struct ovectl_ratemanage_arg *ai=
+ (struct ovectl_ratemanage_arg *)arg;
+ if(ai==NULL){
+ hi->bitrate_av=0;
+ }else{
+ hi->bitrate_av=(ai->bitrate_av_lo+ai->bitrate_av_hi)*.5;
+ }
+ }
+ return(0);
+ /* now deprecated *****************/
+ case OV_ECTL_RATEMANAGE_HARD:
+ {
+ struct ovectl_ratemanage_arg *ai=
+ (struct ovectl_ratemanage_arg *)arg;
+ if(ai==NULL){
+ hi->bitrate_min=0;
+ hi->bitrate_max=0;
+ }else{
+ hi->bitrate_min=ai->bitrate_hard_min;
+ hi->bitrate_max=ai->bitrate_hard_max;
+ hi->bitrate_reservoir=ai->bitrate_hard_window*
+ (hi->bitrate_max+hi->bitrate_min)*.5;
+ }
+ if(hi->bitrate_reservoir<128.)
+ hi->bitrate_reservoir=128.;
+ }
+ return(0);
+
+ /* replacement ratemanage interface */
+ case OV_ECTL_RATEMANAGE2_GET:
+ {
+ struct ovectl_ratemanage2_arg *ai=
+ (struct ovectl_ratemanage2_arg *)arg;
+ if(ai==NULL)return OV_EINVAL;
+
+ ai->management_active=hi->managed;
+ ai->bitrate_limit_min_kbps=hi->bitrate_min/1000;
+ ai->bitrate_limit_max_kbps=hi->bitrate_max/1000;
+ ai->bitrate_average_kbps=hi->bitrate_av/1000;
+ ai->bitrate_average_damping=hi->bitrate_av_damp;
+ ai->bitrate_limit_reservoir_bits=hi->bitrate_reservoir;
+ ai->bitrate_limit_reservoir_bias=hi->bitrate_reservoir_bias;
+ }
+ return (0);
+ case OV_ECTL_RATEMANAGE2_SET:
+ {
+ struct ovectl_ratemanage2_arg *ai=
+ (struct ovectl_ratemanage2_arg *)arg;
+ if(ai==NULL){
+ hi->managed=0;
+ }else{
+ /* sanity check; only catch invariant violations */
+ if(ai->bitrate_limit_min_kbps>0 &&
+ ai->bitrate_average_kbps>0 &&
+ ai->bitrate_limit_min_kbps>ai->bitrate_average_kbps)
+ return OV_EINVAL;
+
+ if(ai->bitrate_limit_max_kbps>0 &&
+ ai->bitrate_average_kbps>0 &&
+ ai->bitrate_limit_max_kbps<ai->bitrate_average_kbps)
+ return OV_EINVAL;
+
+ if(ai->bitrate_limit_min_kbps>0 &&
+ ai->bitrate_limit_max_kbps>0 &&
+ ai->bitrate_limit_min_kbps>ai->bitrate_limit_max_kbps)
+ return OV_EINVAL;
+
+ if(ai->bitrate_average_damping <= 0.)
+ return OV_EINVAL;
+
+ if(ai->bitrate_limit_reservoir_bits < 0)
+ return OV_EINVAL;
+
+ if(ai->bitrate_limit_reservoir_bias < 0.)
+ return OV_EINVAL;
+
+ if(ai->bitrate_limit_reservoir_bias > 1.)
+ return OV_EINVAL;
+
+ hi->managed=ai->management_active;
+ hi->bitrate_min=ai->bitrate_limit_min_kbps * 1000;
+ hi->bitrate_max=ai->bitrate_limit_max_kbps * 1000;
+ hi->bitrate_av=ai->bitrate_average_kbps * 1000;
+ hi->bitrate_av_damp=ai->bitrate_average_damping;
+ hi->bitrate_reservoir=ai->bitrate_limit_reservoir_bits;
+ hi->bitrate_reservoir_bias=ai->bitrate_limit_reservoir_bias;
+ }
+ }
+ return 0;
+
+ case OV_ECTL_LOWPASS_GET:
+ {
+ double *farg=(double *)arg;
+ *farg=hi->lowpass_kHz;
+ }
+ return(0);
+ case OV_ECTL_LOWPASS_SET:
+ {
+ double *farg=(double *)arg;
+ hi->lowpass_kHz=*farg;
+
+ if(hi->lowpass_kHz<2.)hi->lowpass_kHz=2.;
+ if(hi->lowpass_kHz>99.)hi->lowpass_kHz=99.;
+ hi->lowpass_altered=1;
+ }
+ return(0);
+ case OV_ECTL_IBLOCK_GET:
+ {
+ double *farg=(double *)arg;
+ *farg=hi->impulse_noisetune;
+ }
+ return(0);
+ case OV_ECTL_IBLOCK_SET:
+ {
+ double *farg=(double *)arg;
+ hi->impulse_noisetune=*farg;
+
+ if(hi->impulse_noisetune>0.)hi->impulse_noisetune=0.;
+ if(hi->impulse_noisetune<-15.)hi->impulse_noisetune=-15.;
+ }
+ return(0);
+ case OV_ECTL_COUPLING_GET:
+ {
+ int *iarg=(int *)arg;
+ *iarg=hi->coupling_p;
+ }
+ return(0);
+ case OV_ECTL_COUPLING_SET:
+ {
+ const void *new_template;
+ double new_base=0.;
+ int *iarg=(int *)arg;
+ hi->coupling_p=((*iarg)!=0);
+
+ /* Fetching a new template can alter the base_setting, which
+ many other parameters are based on. Right now, the only
+ parameter drawn from the base_setting that can be altered
+ by an encctl is the lowpass, so that is explictly flagged
+ to not be overwritten when we fetch a new template and
+ recompute the dependant settings */
+ new_template = get_setup_template(hi->coupling_p?vi->channels:-1,
+ vi->rate,
+ hi->req,
+ hi->managed,
+ &new_base);
+ if(!hi->setup)return OV_EIMPL;
+ hi->setup=new_template;
+ hi->base_setting=new_base;
+ vorbis_encode_setup_setting(vi,vi->channels,vi->rate);
+ }
+ return(0);
+ }
+ return(OV_EIMPL);
+ }
+ return(OV_EINVAL);
+}
diff --git a/external/libvorbis-1.3.5/lib/vorbisfile.c b/external/libvorbis-1.3.5/lib/vorbisfile.c
new file mode 100644
index 0000000..1998e63
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/vorbisfile.c
@@ -0,0 +1,2425 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: stdio-based convenience library for opening/seeking/decoding
+ last mod: $Id: vorbisfile.c 19457 2015-03-03 00:15:29Z giles $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <math.h>
+
+#include "vorbis/codec.h"
+
+/* we don't need or want the static callback symbols here */
+#define OV_EXCLUDE_STATIC_CALLBACKS
+#include "vorbis/vorbisfile.h"
+
+#include "os.h"
+#include "misc.h"
+
+/* A 'chained bitstream' is a Vorbis bitstream that contains more than
+ one logical bitstream arranged end to end (the only form of Ogg
+ multiplexing allowed in a Vorbis bitstream; grouping [parallel
+ multiplexing] is not allowed in Vorbis) */
+
+/* A Vorbis file can be played beginning to end (streamed) without
+ worrying ahead of time about chaining (see decoder_example.c). If
+ we have the whole file, however, and want random access
+ (seeking/scrubbing) or desire to know the total length/time of a
+ file, we need to account for the possibility of chaining. */
+
+/* We can handle things a number of ways; we can determine the entire
+ bitstream structure right off the bat, or find pieces on demand.
+ This example determines and caches structure for the entire
+ bitstream, but builds a virtual decoder on the fly when moving
+ between links in the chain. */
+
+/* There are also different ways to implement seeking. Enough
+ information exists in an Ogg bitstream to seek to
+ sample-granularity positions in the output. Or, one can seek by
+ picking some portion of the stream roughly in the desired area if
+ we only want coarse navigation through the stream. */
+
+/*************************************************************************
+ * Many, many internal helpers. The intention is not to be confusing;
+ * rampant duplication and monolithic function implementation would be
+ * harder to understand anyway. The high level functions are last. Begin
+ * grokking near the end of the file */
+
+/* read a little more data from the file/pipe into the ogg_sync framer
+*/
+#define CHUNKSIZE 65536 /* greater-than-page-size granularity seeking */
+#define READSIZE 2048 /* a smaller read size is needed for low-rate streaming. */
+
+static long _get_data(OggVorbis_File *vf){
+ errno=0;
+ if(!(vf->callbacks.read_func))return(-1);
+ if(vf->datasource){
+ char *buffer=ogg_sync_buffer(&vf->oy,READSIZE);
+ long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource);
+ if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
+ if(bytes==0 && errno)return(-1);
+ return(bytes);
+ }else
+ return(0);
+}
+
+/* save a tiny smidge of verbosity to make the code more readable */
+static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
+ if(vf->datasource){
+ /* only seek if the file position isn't already there */
+ if(vf->offset != offset){
+ if(!(vf->callbacks.seek_func)||
+ (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1)
+ return OV_EREAD;
+ vf->offset=offset;
+ ogg_sync_reset(&vf->oy);
+ }
+ }else{
+ /* shouldn't happen unless someone writes a broken callback */
+ return OV_EFAULT;
+ }
+ return 0;
+}
+
+/* The read/seek functions track absolute position within the stream */
+
+/* from the head of the stream, get the next page. boundary specifies
+ if the function is allowed to fetch more data from the stream (and
+ how much) or only use internally buffered data.
+
+ boundary: -1) unbounded search
+ 0) read no additional data; use cached only
+ n) search for a new page beginning for n bytes
+
+ return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
+ n) found a page at absolute offset n */
+
+static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
+ ogg_int64_t boundary){
+ if(boundary>0)boundary+=vf->offset;
+ while(1){
+ long more;
+
+ if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
+ more=ogg_sync_pageseek(&vf->oy,og);
+
+ if(more<0){
+ /* skipped n bytes */
+ vf->offset-=more;
+ }else{
+ if(more==0){
+ /* send more paramedics */
+ if(!boundary)return(OV_FALSE);
+ {
+ long ret=_get_data(vf);
+ if(ret==0)return(OV_EOF);
+ if(ret<0)return(OV_EREAD);
+ }
+ }else{
+ /* got a page. Return the offset at the page beginning,
+ advance the internal offset past the page end */
+ ogg_int64_t ret=vf->offset;
+ vf->offset+=more;
+ return(ret);
+
+ }
+ }
+ }
+}
+
+/* find the latest page beginning before the passed in position. Much
+ dirtier than the above as Ogg doesn't have any backward search
+ linkage. no 'readp' as it will certainly have to read. */
+/* returns offset or OV_EREAD, OV_FAULT */
+static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_int64_t begin,ogg_page *og){
+ ogg_int64_t end = begin;
+ ogg_int64_t ret;
+ ogg_int64_t offset=-1;
+
+ while(offset==-1){
+ begin-=CHUNKSIZE;
+ if(begin<0)
+ begin=0;
+
+ ret=_seek_helper(vf,begin);
+ if(ret)return(ret);
+
+ while(vf->offset<end){
+ memset(og,0,sizeof(*og));
+ ret=_get_next_page(vf,og,end-vf->offset);
+ if(ret==OV_EREAD)return(OV_EREAD);
+ if(ret<0){
+ break;
+ }else{
+ offset=ret;
+ }
+ }
+ }
+
+ /* In a fully compliant, non-multiplexed stream, we'll still be
+ holding the last page. In multiplexed (or noncompliant streams),
+ we will probably have to re-read the last page we saw */
+ if(og->header_len==0){
+ ret=_seek_helper(vf,offset);
+ if(ret)return(ret);
+
+ ret=_get_next_page(vf,og,CHUNKSIZE);
+ if(ret<0)
+ /* this shouldn't be possible */
+ return(OV_EFAULT);
+ }
+
+ return(offset);
+}
+
+static void _add_serialno(ogg_page *og,long **serialno_list, int *n){
+ long s = ogg_page_serialno(og);
+ (*n)++;
+
+ if(*serialno_list){
+ *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n));
+ }else{
+ *serialno_list = _ogg_malloc(sizeof(**serialno_list));
+ }
+
+ (*serialno_list)[(*n)-1] = s;
+}
+
+/* returns nonzero if found */
+static int _lookup_serialno(long s, long *serialno_list, int n){
+ if(serialno_list){
+ while(n--){
+ if(*serialno_list == s) return 1;
+ serialno_list++;
+ }
+ }
+ return 0;
+}
+
+static int _lookup_page_serialno(ogg_page *og, long *serialno_list, int n){
+ long s = ogg_page_serialno(og);
+ return _lookup_serialno(s,serialno_list,n);
+}
+
+/* performs the same search as _get_prev_page, but prefers pages of
+ the specified serial number. If a page of the specified serialno is
+ spotted during the seek-back-and-read-forward, it will return the
+ info of last page of the matching serial number instead of the very
+ last page. If no page of the specified serialno is seen, it will
+ return the info of last page and alter *serialno. */
+static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, ogg_int64_t begin,
+ long *serial_list, int serial_n,
+ int *serialno, ogg_int64_t *granpos){
+ ogg_page og;
+ ogg_int64_t end=begin;
+ ogg_int64_t ret;
+
+ ogg_int64_t prefoffset=-1;
+ ogg_int64_t offset=-1;
+ ogg_int64_t ret_serialno=-1;
+ ogg_int64_t ret_gran=-1;
+
+ while(offset==-1){
+ begin-=CHUNKSIZE;
+ if(begin<0)
+ begin=0;
+
+ ret=_seek_helper(vf,begin);
+ if(ret)return(ret);
+
+ while(vf->offset<end){
+ ret=_get_next_page(vf,&og,end-vf->offset);
+ if(ret==OV_EREAD)return(OV_EREAD);
+ if(ret<0){
+ break;
+ }else{
+ ret_serialno=ogg_page_serialno(&og);
+ ret_gran=ogg_page_granulepos(&og);
+ offset=ret;
+
+ if(ret_serialno == *serialno){
+ prefoffset=ret;
+ *granpos=ret_gran;
+ }
+
+ if(!_lookup_serialno(ret_serialno,serial_list,serial_n)){
+ /* we fell off the end of the link, which means we seeked
+ back too far and shouldn't have been looking in that link
+ to begin with. If we found the preferred serial number,
+ forget that we saw it. */
+ prefoffset=-1;
+ }
+ }
+ }
+ }
+
+ /* we're not interested in the page... just the serialno and granpos. */
+ if(prefoffset>=0)return(prefoffset);
+
+ *serialno = ret_serialno;
+ *granpos = ret_gran;
+ return(offset);
+
+}
+
+/* uses the local ogg_stream storage in vf; this is important for
+ non-streaming input sources */
+static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
+ long **serialno_list, int *serialno_n,
+ ogg_page *og_ptr){
+ ogg_page og;
+ ogg_packet op;
+ int i,ret;
+ int allbos=0;
+
+ if(!og_ptr){
+ ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
+ if(llret==OV_EREAD)return(OV_EREAD);
+ if(llret<0)return(OV_ENOTVORBIS);
+ og_ptr=&og;
+ }
+
+ vorbis_info_init(vi);
+ vorbis_comment_init(vc);
+ vf->ready_state=OPENED;
+
+ /* extract the serialnos of all BOS pages + the first set of vorbis
+ headers we see in the link */
+
+ while(ogg_page_bos(og_ptr)){
+ if(serialno_list){
+ if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){
+ /* a dupe serialnumber in an initial header packet set == invalid stream */
+ if(*serialno_list)_ogg_free(*serialno_list);
+ *serialno_list=0;
+ *serialno_n=0;
+ ret=OV_EBADHEADER;
+ goto bail_header;
+ }
+
+ _add_serialno(og_ptr,serialno_list,serialno_n);
+ }
+
+ if(vf->ready_state<STREAMSET){
+ /* we don't have a vorbis stream in this link yet, so begin
+ prospective stream setup. We need a stream to get packets */
+ ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr));
+ ogg_stream_pagein(&vf->os,og_ptr);
+
+ if(ogg_stream_packetout(&vf->os,&op) > 0 &&
+ vorbis_synthesis_idheader(&op)){
+ /* vorbis header; continue setup */
+ vf->ready_state=STREAMSET;
+ if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
+ ret=OV_EBADHEADER;
+ goto bail_header;
+ }
+ }
+ }
+
+ /* get next page */
+ {
+ ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE);
+ if(llret==OV_EREAD){
+ ret=OV_EREAD;
+ goto bail_header;
+ }
+ if(llret<0){
+ ret=OV_ENOTVORBIS;
+ goto bail_header;
+ }
+
+ /* if this page also belongs to our vorbis stream, submit it and break */
+ if(vf->ready_state==STREAMSET &&
+ vf->os.serialno == ogg_page_serialno(og_ptr)){
+ ogg_stream_pagein(&vf->os,og_ptr);
+ break;
+ }
+ }
+ }
+
+ if(vf->ready_state!=STREAMSET){
+ ret = OV_ENOTVORBIS;
+ goto bail_header;
+ }
+
+ while(1){
+
+ i=0;
+ while(i<2){ /* get a page loop */
+
+ while(i<2){ /* get a packet loop */
+
+ int result=ogg_stream_packetout(&vf->os,&op);
+ if(result==0)break;
+ if(result==-1){
+ ret=OV_EBADHEADER;
+ goto bail_header;
+ }
+
+ if((ret=vorbis_synthesis_headerin(vi,vc,&op)))
+ goto bail_header;
+
+ i++;
+ }
+
+ while(i<2){
+ if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
+ ret=OV_EBADHEADER;
+ goto bail_header;
+ }
+
+ /* if this page belongs to the correct stream, go parse it */
+ if(vf->os.serialno == ogg_page_serialno(og_ptr)){
+ ogg_stream_pagein(&vf->os,og_ptr);
+ break;
+ }
+
+ /* if we never see the final vorbis headers before the link
+ ends, abort */
+ if(ogg_page_bos(og_ptr)){
+ if(allbos){
+ ret = OV_EBADHEADER;
+ goto bail_header;
+ }else
+ allbos=1;
+ }
+
+ /* otherwise, keep looking */
+ }
+ }
+
+ return 0;
+ }
+
+ bail_header:
+ vorbis_info_clear(vi);
+ vorbis_comment_clear(vc);
+ vf->ready_state=OPENED;
+
+ return ret;
+}
+
+/* Starting from current cursor position, get initial PCM offset of
+ next page. Consumes the page in the process without decoding
+ audio, however this is only called during stream parsing upon
+ seekable open. */
+static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){
+ ogg_page og;
+ ogg_int64_t accumulated=0;
+ long lastblock=-1;
+ int result;
+ int serialno = vf->os.serialno;
+
+ while(1){
+ ogg_packet op;
+ if(_get_next_page(vf,&og,-1)<0)
+ break; /* should not be possible unless the file is truncated/mangled */
+
+ if(ogg_page_bos(&og)) break;
+ if(ogg_page_serialno(&og)!=serialno) continue;
+
+ /* count blocksizes of all frames in the page */
+ ogg_stream_pagein(&vf->os,&og);
+ while((result=ogg_stream_packetout(&vf->os,&op))){
+ if(result>0){ /* ignore holes */
+ long thisblock=vorbis_packet_blocksize(vi,&op);
+ if(thisblock>=0){
+ if(lastblock!=-1)
+ accumulated+=(lastblock+thisblock)>>2;
+ lastblock=thisblock;
+ }
+ }
+ }
+
+ if(ogg_page_granulepos(&og)!=-1){
+ /* pcm offset of last packet on the first audio page */
+ accumulated= ogg_page_granulepos(&og)-accumulated;
+ break;
+ }
+ }
+
+ /* less than zero? Either a corrupt file or a stream with samples
+ trimmed off the beginning, a normal occurrence; in both cases set
+ the offset to zero */
+ if(accumulated<0)accumulated=0;
+
+ return accumulated;
+}
+
+/* finds each bitstream link one at a time using a bisection search
+ (has to begin by knowing the offset of the lb's initial page).
+ Recurses for each link so it can alloc the link storage after
+ finding them all, then unroll and fill the cache at the same time */
+static int _bisect_forward_serialno(OggVorbis_File *vf,
+ ogg_int64_t begin,
+ ogg_int64_t searched,
+ ogg_int64_t end,
+ ogg_int64_t endgran,
+ int endserial,
+ long *currentno_list,
+ int currentnos,
+ long m){
+ ogg_int64_t pcmoffset;
+ ogg_int64_t dataoffset=searched;
+ ogg_int64_t endsearched=end;
+ ogg_int64_t next=end;
+ ogg_int64_t searchgran=-1;
+ ogg_page og;
+ ogg_int64_t ret,last;
+ int serialno = vf->os.serialno;
+
+ /* invariants:
+ we have the headers and serialnos for the link beginning at 'begin'
+ we have the offset and granpos of the last page in the file (potentially
+ not a page we care about)
+ */
+
+ /* Is the last page in our list of current serialnumbers? */
+ if(_lookup_serialno(endserial,currentno_list,currentnos)){
+
+ /* last page is in the starting serialno list, so we've bisected
+ down to (or just started with) a single link. Now we need to
+ find the last vorbis page belonging to the first vorbis stream
+ for this link. */
+ searched = end;
+ while(endserial != serialno){
+ endserial = serialno;
+ searched=_get_prev_page_serial(vf,searched,currentno_list,currentnos,&endserial,&endgran);
+ }
+
+ vf->links=m+1;
+ if(vf->offsets)_ogg_free(vf->offsets);
+ if(vf->serialnos)_ogg_free(vf->serialnos);
+ if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
+
+ vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
+ vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
+ vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
+ vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
+ vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
+ vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
+
+ vf->offsets[m+1]=end;
+ vf->offsets[m]=begin;
+ vf->pcmlengths[m*2+1]=(endgran<0?0:endgran);
+
+ }else{
+
+ /* last page is not in the starting stream's serial number list,
+ so we have multiple links. Find where the stream that begins
+ our bisection ends. */
+
+ long *next_serialno_list=NULL;
+ int next_serialnos=0;
+ vorbis_info vi;
+ vorbis_comment vc;
+ int testserial = serialno+1;
+
+ /* the below guards against garbage seperating the last and
+ first pages of two links. */
+ while(searched<endsearched){
+ ogg_int64_t bisect;
+
+ if(endsearched-searched<CHUNKSIZE){
+ bisect=searched;
+ }else{
+ bisect=(searched+endsearched)/2;
+ }
+
+ ret=_seek_helper(vf,bisect);
+ if(ret)return(ret);
+
+ last=_get_next_page(vf,&og,-1);
+ if(last==OV_EREAD)return(OV_EREAD);
+ if(last<0 || !_lookup_page_serialno(&og,currentno_list,currentnos)){
+ endsearched=bisect;
+ if(last>=0)next=last;
+ }else{
+ searched=vf->offset;
+ }
+ }
+
+ /* Bisection point found */
+ /* for the time being, fetch end PCM offset the simple way */
+ searched = next;
+ while(testserial != serialno){
+ testserial = serialno;
+ searched = _get_prev_page_serial(vf,searched,currentno_list,currentnos,&testserial,&searchgran);
+ }
+
+ ret=_seek_helper(vf,next);
+ if(ret)return(ret);
+
+ ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL);
+ if(ret)return(ret);
+ serialno = vf->os.serialno;
+ dataoffset = vf->offset;
+
+ /* this will consume a page, however the next bisection always
+ starts with a raw seek */
+ pcmoffset = _initial_pcmoffset(vf,&vi);
+
+ ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial,
+ next_serialno_list,next_serialnos,m+1);
+ if(ret)return(ret);
+
+ if(next_serialno_list)_ogg_free(next_serialno_list);
+
+ vf->offsets[m+1]=next;
+ vf->serialnos[m+1]=serialno;
+ vf->dataoffsets[m+1]=dataoffset;
+
+ vf->vi[m+1]=vi;
+ vf->vc[m+1]=vc;
+
+ vf->pcmlengths[m*2+1]=searchgran;
+ vf->pcmlengths[m*2+2]=pcmoffset;
+ vf->pcmlengths[m*2+3]-=pcmoffset;
+ if(vf->pcmlengths[m*2+3]<0)vf->pcmlengths[m*2+3]=0;
+ }
+ return(0);
+}
+
+static int _make_decode_ready(OggVorbis_File *vf){
+ if(vf->ready_state>STREAMSET)return 0;
+ if(vf->ready_state<STREAMSET)return OV_EFAULT;
+ if(vf->seekable){
+ if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link))
+ return OV_EBADLINK;
+ }else{
+ if(vorbis_synthesis_init(&vf->vd,vf->vi))
+ return OV_EBADLINK;
+ }
+ vorbis_block_init(&vf->vd,&vf->vb);
+ vf->ready_state=INITSET;
+ vf->bittrack=0.f;
+ vf->samptrack=0.f;
+ return 0;
+}
+
+static int _open_seekable2(OggVorbis_File *vf){
+ ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1;
+ int endserial=vf->os.serialno;
+ int serialno=vf->os.serialno;
+
+ /* we're partially open and have a first link header state in
+ storage in vf */
+
+ /* fetch initial PCM offset */
+ ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi);
+
+ /* we can seek, so set out learning all about this file */
+ if(vf->callbacks.seek_func && vf->callbacks.tell_func){
+ (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
+ vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
+ }else{
+ vf->offset=vf->end=-1;
+ }
+
+ /* If seek_func is implemented, tell_func must also be implemented */
+ if(vf->end==-1) return(OV_EINVAL);
+
+ /* Get the offset of the last page of the physical bitstream, or, if
+ we're lucky the last vorbis page of this link as most OggVorbis
+ files will contain a single logical bitstream */
+ end=_get_prev_page_serial(vf,vf->end,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran);
+ if(end<0)return(end);
+
+ /* now determine bitstream structure recursively */
+ if(_bisect_forward_serialno(vf,0,dataoffset,end,endgran,endserial,
+ vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD);
+
+ vf->offsets[0]=0;
+ vf->serialnos[0]=serialno;
+ vf->dataoffsets[0]=dataoffset;
+ vf->pcmlengths[0]=pcmoffset;
+ vf->pcmlengths[1]-=pcmoffset;
+ if(vf->pcmlengths[1]<0)vf->pcmlengths[1]=0;
+
+ return(ov_raw_seek(vf,dataoffset));
+}
+
+/* clear out the current logical bitstream decoder */
+static void _decode_clear(OggVorbis_File *vf){
+ vorbis_dsp_clear(&vf->vd);
+ vorbis_block_clear(&vf->vb);
+ vf->ready_state=OPENED;
+}
+
+/* fetch and process a packet. Handles the case where we're at a
+ bitstream boundary and dumps the decoding machine. If the decoding
+ machine is unloaded, it loads it. It also keeps pcm_offset up to
+ date (seek and read both use this. seek uses a special hack with
+ readp).
+
+ return: <0) error, OV_HOLE (lost packet) or OV_EOF
+ 0) need more data (only if readp==0)
+ 1) got a packet
+*/
+
+static int _fetch_and_process_packet(OggVorbis_File *vf,
+ ogg_packet *op_in,
+ int readp,
+ int spanp){
+ ogg_page og;
+
+ /* handle one packet. Try to fetch it from current stream state */
+ /* extract packets from page */
+ while(1){
+
+ if(vf->ready_state==STREAMSET){
+ int ret=_make_decode_ready(vf);
+ if(ret<0)return ret;
+ }
+
+ /* process a packet if we can. */
+
+ if(vf->ready_state==INITSET){
+ int hs=vorbis_synthesis_halfrate_p(vf->vi);
+
+ while(1) {
+ ogg_packet op;
+ ogg_packet *op_ptr=(op_in?op_in:&op);
+ int result=ogg_stream_packetout(&vf->os,op_ptr);
+ ogg_int64_t granulepos;
+
+ op_in=NULL;
+ if(result==-1)return(OV_HOLE); /* hole in the data. */
+ if(result>0){
+ /* got a packet. process it */
+ granulepos=op_ptr->granulepos;
+ if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy
+ header handling. The
+ header packets aren't
+ audio, so if/when we
+ submit them,
+ vorbis_synthesis will
+ reject them */
+
+ /* suck in the synthesis data and track bitrate */
+ {
+ int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
+ /* for proper use of libvorbis within libvorbisfile,
+ oldsamples will always be zero. */
+ if(oldsamples)return(OV_EFAULT);
+
+ vorbis_synthesis_blockin(&vf->vd,&vf->vb);
+ vf->samptrack+=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs);
+ vf->bittrack+=op_ptr->bytes*8;
+ }
+
+ /* update the pcm offset. */
+ if(granulepos!=-1 && !op_ptr->e_o_s){
+ int link=(vf->seekable?vf->current_link:0);
+ int i,samples;
+
+ /* this packet has a pcm_offset on it (the last packet
+ completed on a page carries the offset) After processing
+ (above), we know the pcm position of the *last* sample
+ ready to be returned. Find the offset of the *first*
+
+ As an aside, this trick is inaccurate if we begin
+ reading anew right at the last page; the end-of-stream
+ granulepos declares the last frame in the stream, and the
+ last packet of the last page may be a partial frame.
+ So, we need a previous granulepos from an in-sequence page
+ to have a reference point. Thus the !op_ptr->e_o_s clause
+ above */
+
+ if(vf->seekable && link>0)
+ granulepos-=vf->pcmlengths[link*2];
+ if(granulepos<0)granulepos=0; /* actually, this
+ shouldn't be possible
+ here unless the stream
+ is very broken */
+
+ samples=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs);
+
+ granulepos-=samples;
+ for(i=0;i<link;i++)
+ granulepos+=vf->pcmlengths[i*2+1];
+ vf->pcm_offset=granulepos;
+ }
+ return(1);
+ }
+ }
+ else
+ break;
+ }
+ }
+
+ if(vf->ready_state>=OPENED){
+ ogg_int64_t ret;
+
+ while(1){
+ /* the loop is not strictly necessary, but there's no sense in
+ doing the extra checks of the larger loop for the common
+ case in a multiplexed bistream where the page is simply
+ part of a different logical bitstream; keep reading until
+ we get one with the correct serialno */
+
+ if(!readp)return(0);
+ if((ret=_get_next_page(vf,&og,-1))<0){
+ return(OV_EOF); /* eof. leave unitialized */
+ }
+
+ /* bitrate tracking; add the header's bytes here, the body bytes
+ are done by packet above */
+ vf->bittrack+=og.header_len*8;
+
+ if(vf->ready_state==INITSET){
+ if(vf->current_serialno!=ogg_page_serialno(&og)){
+
+ /* two possibilities:
+ 1) our decoding just traversed a bitstream boundary
+ 2) another stream is multiplexed into this logical section */
+
+ if(ogg_page_bos(&og)){
+ /* boundary case */
+ if(!spanp)
+ return(OV_EOF);
+
+ _decode_clear(vf);
+
+ if(!vf->seekable){
+ vorbis_info_clear(vf->vi);
+ vorbis_comment_clear(vf->vc);
+ }
+ break;
+
+ }else
+ continue; /* possibility #2 */
+ }
+ }
+
+ break;
+ }
+ }
+
+ /* Do we need to load a new machine before submitting the page? */
+ /* This is different in the seekable and non-seekable cases.
+
+ In the seekable case, we already have all the header
+ information loaded and cached; we just initialize the machine
+ with it and continue on our merry way.
+
+ In the non-seekable (streaming) case, we'll only be at a
+ boundary if we just left the previous logical bitstream and
+ we're now nominally at the header of the next bitstream
+ */
+
+ if(vf->ready_state!=INITSET){
+ int link;
+
+ if(vf->ready_state<STREAMSET){
+ if(vf->seekable){
+ long serialno = ogg_page_serialno(&og);
+
+ /* match the serialno to bitstream section. We use this rather than
+ offset positions to avoid problems near logical bitstream
+ boundaries */
+
+ for(link=0;link<vf->links;link++)
+ if(vf->serialnos[link]==serialno)break;
+
+ if(link==vf->links) continue; /* not the desired Vorbis
+ bitstream section; keep
+ trying */
+
+ vf->current_serialno=serialno;
+ vf->current_link=link;
+
+ ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
+ vf->ready_state=STREAMSET;
+
+ }else{
+ /* we're streaming */
+ /* fetch the three header packets, build the info struct */
+
+ int ret=_fetch_headers(vf,vf->vi,vf->vc,NULL,NULL,&og);
+ if(ret)return(ret);
+ vf->current_serialno=vf->os.serialno;
+ vf->current_link++;
+ link=0;
+ }
+ }
+ }
+
+ /* the buffered page is the data we want, and we're ready for it;
+ add it to the stream state */
+ ogg_stream_pagein(&vf->os,&og);
+
+ }
+}
+
+/* if, eg, 64 bit stdio is configured by default, this will build with
+ fseek64 */
+static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
+ if(f==NULL)return(-1);
+ return fseek(f,off,whence);
+}
+
+static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial,
+ long ibytes, ov_callbacks callbacks){
+ int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1);
+ long *serialno_list=NULL;
+ int serialno_list_size=0;
+ int ret;
+
+ memset(vf,0,sizeof(*vf));
+ vf->datasource=f;
+ vf->callbacks = callbacks;
+
+ /* init the framing state */
+ ogg_sync_init(&vf->oy);
+
+ /* perhaps some data was previously read into a buffer for testing
+ against other stream types. Allow initialization from this
+ previously read data (especially as we may be reading from a
+ non-seekable stream) */
+ if(initial){
+ char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
+ memcpy(buffer,initial,ibytes);
+ ogg_sync_wrote(&vf->oy,ibytes);
+ }
+
+ /* can we seek? Stevens suggests the seek test was portable */
+ if(offsettest!=-1)vf->seekable=1;
+
+ /* No seeking yet; Set up a 'single' (current) logical bitstream
+ entry for partial open */
+ vf->links=1;
+ vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
+ vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
+ ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
+
+ /* Fetch all BOS pages, store the vorbis header and all seen serial
+ numbers, load subsequent vorbis setup headers */
+ if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){
+ vf->datasource=NULL;
+ ov_clear(vf);
+ }else{
+ /* serial number list for first link needs to be held somewhere
+ for second stage of seekable stream open; this saves having to
+ seek/reread first link's serialnumber data then. */
+ vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos));
+ vf->serialnos[0]=vf->current_serialno=vf->os.serialno;
+ vf->serialnos[1]=serialno_list_size;
+ memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos));
+
+ vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets));
+ vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets));
+ vf->offsets[0]=0;
+ vf->dataoffsets[0]=vf->offset;
+
+ vf->ready_state=PARTOPEN;
+ }
+ if(serialno_list)_ogg_free(serialno_list);
+ return(ret);
+}
+
+static int _ov_open2(OggVorbis_File *vf){
+ if(vf->ready_state != PARTOPEN) return OV_EINVAL;
+ vf->ready_state=OPENED;
+ if(vf->seekable){
+ int ret=_open_seekable2(vf);
+ if(ret){
+ vf->datasource=NULL;
+ ov_clear(vf);
+ }
+ return(ret);
+ }else
+ vf->ready_state=STREAMSET;
+
+ return 0;
+}
+
+
+/* clear out the OggVorbis_File struct */
+int ov_clear(OggVorbis_File *vf){
+ if(vf){
+ vorbis_block_clear(&vf->vb);
+ vorbis_dsp_clear(&vf->vd);
+ ogg_stream_clear(&vf->os);
+
+ if(vf->vi && vf->links){
+ int i;
+ for(i=0;i<vf->links;i++){
+ vorbis_info_clear(vf->vi+i);
+ vorbis_comment_clear(vf->vc+i);
+ }
+ _ogg_free(vf->vi);
+ _ogg_free(vf->vc);
+ }
+ if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
+ if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
+ if(vf->serialnos)_ogg_free(vf->serialnos);
+ if(vf->offsets)_ogg_free(vf->offsets);
+ ogg_sync_clear(&vf->oy);
+ if(vf->datasource && vf->callbacks.close_func)
+ (vf->callbacks.close_func)(vf->datasource);
+ memset(vf,0,sizeof(*vf));
+ }
+#ifdef DEBUG_LEAKS
+ _VDBG_dump();
+#endif
+ return(0);
+}
+
+/* inspects the OggVorbis file and finds/documents all the logical
+ bitstreams contained in it. Tries to be tolerant of logical
+ bitstream sections that are truncated/woogie.
+
+ return: -1) error
+ 0) OK
+*/
+
+int ov_open_callbacks(void *f,OggVorbis_File *vf,
+ const char *initial,long ibytes,ov_callbacks callbacks){
+ int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
+ if(ret)return ret;
+ return _ov_open2(vf);
+}
+
+int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){
+ ov_callbacks callbacks = {
+ (size_t (*)(void *, size_t, size_t, void *)) fread,
+ (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap,
+ (int (*)(void *)) fclose,
+ (long (*)(void *)) ftell
+ };
+
+ return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
+}
+
+int ov_fopen(const char *path,OggVorbis_File *vf){
+ int ret;
+ FILE *f = fopen(path,"rb");
+ if(!f) return -1;
+
+ ret = ov_open(f,vf,NULL,0);
+ if(ret) fclose(f);
+ return ret;
+}
+
+
+/* cheap hack for game usage where downsampling is desirable; there's
+ no need for SRC as we can just do it cheaply in libvorbis. */
+
+int ov_halfrate(OggVorbis_File *vf,int flag){
+ int i;
+ if(vf->vi==NULL)return OV_EINVAL;
+ if(vf->ready_state>STREAMSET){
+ /* clear out stream state; dumping the decode machine is needed to
+ reinit the MDCT lookups. */
+ vorbis_dsp_clear(&vf->vd);
+ vorbis_block_clear(&vf->vb);
+ vf->ready_state=STREAMSET;
+ if(vf->pcm_offset>=0){
+ ogg_int64_t pos=vf->pcm_offset;
+ vf->pcm_offset=-1; /* make sure the pos is dumped if unseekable */
+ ov_pcm_seek(vf,pos);
+ }
+ }
+
+ for(i=0;i<vf->links;i++){
+ if(vorbis_synthesis_halfrate(vf->vi+i,flag)){
+ if(flag) ov_halfrate(vf,0);
+ return OV_EINVAL;
+ }
+ }
+ return 0;
+}
+
+int ov_halfrate_p(OggVorbis_File *vf){
+ if(vf->vi==NULL)return OV_EINVAL;
+ return vorbis_synthesis_halfrate_p(vf->vi);
+}
+
+/* Only partially open the vorbis file; test for Vorbisness, and load
+ the headers for the first chain. Do not seek (although test for
+ seekability). Use ov_test_open to finish opening the file, else
+ ov_clear to close/free it. Same return codes as open.
+
+ Note that vorbisfile does _not_ take ownership of the file if the
+ call fails; the calling applicaiton is responsible for closing the file
+ if this call returns an error. */
+
+int ov_test_callbacks(void *f,OggVorbis_File *vf,
+ const char *initial,long ibytes,ov_callbacks callbacks)
+{
+ return _ov_open1(f,vf,initial,ibytes,callbacks);
+}
+
+int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){
+ ov_callbacks callbacks = {
+ (size_t (*)(void *, size_t, size_t, void *)) fread,
+ (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap,
+ (int (*)(void *)) fclose,
+ (long (*)(void *)) ftell
+ };
+
+ return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
+}
+
+int ov_test_open(OggVorbis_File *vf){
+ if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);
+ return _ov_open2(vf);
+}
+
+/* How many logical bitstreams in this physical bitstream? */
+long ov_streams(OggVorbis_File *vf){
+ return vf->links;
+}
+
+/* Is the FILE * associated with vf seekable? */
+long ov_seekable(OggVorbis_File *vf){
+ return vf->seekable;
+}
+
+/* returns the bitrate for a given logical bitstream or the entire
+ physical bitstream. If the file is open for random access, it will
+ find the *actual* average bitrate. If the file is streaming, it
+ returns the nominal bitrate (if set) else the average of the
+ upper/lower bounds (if set) else -1 (unset).
+
+ If you want the actual bitrate field settings, get them from the
+ vorbis_info structs */
+
+long ov_bitrate(OggVorbis_File *vf,int i){
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ if(i>=vf->links)return(OV_EINVAL);
+ if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
+ if(i<0){
+ ogg_int64_t bits=0;
+ int i;
+ float br;
+ for(i=0;i<vf->links;i++)
+ bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
+ /* This once read: return(rint(bits/ov_time_total(vf,-1)));
+ * gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
+ * so this is slightly transformed to make it work.
+ */
+ br = bits/ov_time_total(vf,-1);
+ return(rint(br));
+ }else{
+ if(vf->seekable){
+ /* return the actual bitrate */
+ return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i)));
+ }else{
+ /* return nominal if set */
+ if(vf->vi[i].bitrate_nominal>0){
+ return vf->vi[i].bitrate_nominal;
+ }else{
+ if(vf->vi[i].bitrate_upper>0){
+ if(vf->vi[i].bitrate_lower>0){
+ return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
+ }else{
+ return vf->vi[i].bitrate_upper;
+ }
+ }
+ return(OV_FALSE);
+ }
+ }
+ }
+}
+
+/* returns the actual bitrate since last call. returns -1 if no
+ additional data to offer since last call (or at beginning of stream),
+ EINVAL if stream is only partially open
+*/
+long ov_bitrate_instant(OggVorbis_File *vf){
+ int link=(vf->seekable?vf->current_link:0);
+ long ret;
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ if(vf->samptrack==0)return(OV_FALSE);
+ ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5;
+ vf->bittrack=0.f;
+ vf->samptrack=0.f;
+ return(ret);
+}
+
+/* Guess */
+long ov_serialnumber(OggVorbis_File *vf,int i){
+ if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
+ if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
+ if(i<0){
+ return(vf->current_serialno);
+ }else{
+ return(vf->serialnos[i]);
+ }
+}
+
+/* returns: total raw (compressed) length of content if i==-1
+ raw (compressed) length of that logical bitstream for i==0 to n
+ OV_EINVAL if the stream is not seekable (we can't know the length)
+ or if stream is only partially open
+*/
+ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
+ if(i<0){
+ ogg_int64_t acc=0;
+ int i;
+ for(i=0;i<vf->links;i++)
+ acc+=ov_raw_total(vf,i);
+ return(acc);
+ }else{
+ return(vf->offsets[i+1]-vf->offsets[i]);
+ }
+}
+
+/* returns: total PCM length (samples) of content if i==-1 PCM length
+ (samples) of that logical bitstream for i==0 to n
+ OV_EINVAL if the stream is not seekable (we can't know the
+ length) or only partially open
+*/
+ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
+ if(i<0){
+ ogg_int64_t acc=0;
+ int i;
+ for(i=0;i<vf->links;i++)
+ acc+=ov_pcm_total(vf,i);
+ return(acc);
+ }else{
+ return(vf->pcmlengths[i*2+1]);
+ }
+}
+
+/* returns: total seconds of content if i==-1
+ seconds in that logical bitstream for i==0 to n
+ OV_EINVAL if the stream is not seekable (we can't know the
+ length) or only partially open
+*/
+double ov_time_total(OggVorbis_File *vf,int i){
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
+ if(i<0){
+ double acc=0;
+ int i;
+ for(i=0;i<vf->links;i++)
+ acc+=ov_time_total(vf,i);
+ return(acc);
+ }else{
+ return((double)(vf->pcmlengths[i*2+1])/vf->vi[i].rate);
+ }
+}
+
+/* seek to an offset relative to the *compressed* data. This also
+ scans packets to update the PCM cursor. It will cross a logical
+ bitstream boundary, but only if it can't get any packets out of the
+ tail of the bitstream we seek to (so no surprises).
+
+ returns zero on success, nonzero on failure */
+
+int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
+ ogg_stream_state work_os;
+ int ret;
+
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ if(!vf->seekable)
+ return(OV_ENOSEEK); /* don't dump machine if we can't seek */
+
+ if(pos<0 || pos>vf->end)return(OV_EINVAL);
+
+ /* is the seek position outside our current link [if any]? */
+ if(vf->ready_state>=STREAMSET){
+ if(pos<vf->offsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1])
+ _decode_clear(vf); /* clear out stream state */
+ }
+
+ /* don't yet clear out decoding machine (if it's initialized), in
+ the case we're in the same link. Restart the decode lapping, and
+ let _fetch_and_process_packet deal with a potential bitstream
+ boundary */
+ vf->pcm_offset=-1;
+ ogg_stream_reset_serialno(&vf->os,
+ vf->current_serialno); /* must set serialno */
+ vorbis_synthesis_restart(&vf->vd);
+
+ ret=_seek_helper(vf,pos);
+ if(ret)goto seek_error;
+
+ /* we need to make sure the pcm_offset is set, but we don't want to
+ advance the raw cursor past good packets just to get to the first
+ with a granulepos. That's not equivalent behavior to beginning
+ decoding as immediately after the seek position as possible.
+
+ So, a hack. We use two stream states; a local scratch state and
+ the shared vf->os stream state. We use the local state to
+ scan, and the shared state as a buffer for later decode.
+
+ Unfortuantely, on the last page we still advance to last packet
+ because the granulepos on the last page is not necessarily on a
+ packet boundary, and we need to make sure the granpos is
+ correct.
+ */
+
+ {
+ ogg_page og;
+ ogg_packet op;
+ int lastblock=0;
+ int accblock=0;
+ int thisblock=0;
+ int lastflag=0;
+ int firstflag=0;
+ ogg_int64_t pagepos=-1;
+
+ ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */
+ ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE
+ return from not necessarily
+ starting from the beginning */
+
+ while(1){
+ if(vf->ready_state>=STREAMSET){
+ /* snarf/scan a packet if we can */
+ int result=ogg_stream_packetout(&work_os,&op);
+
+ if(result>0){
+
+ if(vf->vi[vf->current_link].codec_setup){
+ thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
+ if(thisblock<0){
+ ogg_stream_packetout(&vf->os,NULL);
+ thisblock=0;
+ }else{
+
+ /* We can't get a guaranteed correct pcm position out of the
+ last page in a stream because it might have a 'short'
+ granpos, which can only be detected in the presence of a
+ preceding page. However, if the last page is also the first
+ page, the granpos rules of a first page take precedence. Not
+ only that, but for first==last, the EOS page must be treated
+ as if its a normal first page for the stream to open/play. */
+ if(lastflag && !firstflag)
+ ogg_stream_packetout(&vf->os,NULL);
+ else
+ if(lastblock)accblock+=(lastblock+thisblock)>>2;
+ }
+
+ if(op.granulepos!=-1){
+ int i,link=vf->current_link;
+ ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
+ if(granulepos<0)granulepos=0;
+
+ for(i=0;i<link;i++)
+ granulepos+=vf->pcmlengths[i*2+1];
+ vf->pcm_offset=granulepos-accblock;
+ if(vf->pcm_offset<0)vf->pcm_offset=0;
+ break;
+ }
+ lastblock=thisblock;
+ continue;
+ }else
+ ogg_stream_packetout(&vf->os,NULL);
+ }
+ }
+
+ if(!lastblock){
+ pagepos=_get_next_page(vf,&og,-1);
+ if(pagepos<0){
+ vf->pcm_offset=ov_pcm_total(vf,-1);
+ break;
+ }
+ }else{
+ /* huh? Bogus stream with packets but no granulepos */
+ vf->pcm_offset=-1;
+ break;
+ }
+
+ /* has our decoding just traversed a bitstream boundary? */
+ if(vf->ready_state>=STREAMSET){
+ if(vf->current_serialno!=ogg_page_serialno(&og)){
+
+ /* two possibilities:
+ 1) our decoding just traversed a bitstream boundary
+ 2) another stream is multiplexed into this logical section? */
+
+ if(ogg_page_bos(&og)){
+ /* we traversed */
+ _decode_clear(vf); /* clear out stream state */
+ ogg_stream_clear(&work_os);
+ } /* else, do nothing; next loop will scoop another page */
+ }
+ }
+
+ if(vf->ready_state<STREAMSET){
+ int link;
+ long serialno = ogg_page_serialno(&og);
+
+ for(link=0;link<vf->links;link++)
+ if(vf->serialnos[link]==serialno)break;
+
+ if(link==vf->links) continue; /* not the desired Vorbis
+ bitstream section; keep
+ trying */
+ vf->current_link=link;
+ vf->current_serialno=serialno;
+ ogg_stream_reset_serialno(&vf->os,serialno);
+ ogg_stream_reset_serialno(&work_os,serialno);
+ vf->ready_state=STREAMSET;
+ firstflag=(pagepos<=vf->dataoffsets[link]);
+ }
+
+ ogg_stream_pagein(&vf->os,&og);
+ ogg_stream_pagein(&work_os,&og);
+ lastflag=ogg_page_eos(&og);
+
+ }
+ }
+
+ ogg_stream_clear(&work_os);
+ vf->bittrack=0.f;
+ vf->samptrack=0.f;
+ return(0);
+
+ seek_error:
+ /* dump the machine so we're in a known state */
+ vf->pcm_offset=-1;
+ ogg_stream_clear(&work_os);
+ _decode_clear(vf);
+ return OV_EBADLINK;
+}
+
+/* Page granularity seek (faster than sample granularity because we
+ don't do the last bit of decode to find a specific sample).
+
+ Seek to the last [granule marked] page preceding the specified pos
+ location, such that decoding past the returned point will quickly
+ arrive at the requested position. */
+int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
+ int link=-1;
+ ogg_int64_t result=0;
+ ogg_int64_t total=ov_pcm_total(vf,-1);
+
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ if(!vf->seekable)return(OV_ENOSEEK);
+
+ if(pos<0 || pos>total)return(OV_EINVAL);
+
+ /* which bitstream section does this pcm offset occur in? */
+ for(link=vf->links-1;link>=0;link--){
+ total-=vf->pcmlengths[link*2+1];
+ if(pos>=total)break;
+ }
+
+ /* Search within the logical bitstream for the page with the highest
+ pcm_pos preceding pos. If we're looking for a position on the
+ first page, bisection will halt without finding our position as
+ it's before the first explicit granulepos fencepost. That case is
+ handled separately below.
+
+ There is a danger here; missing pages or incorrect frame number
+ information in the bitstream could make our task impossible.
+ Account for that (it would be an error condition) */
+
+ /* new search algorithm originally by HB (Nicholas Vinen) */
+
+ {
+ ogg_int64_t end=vf->offsets[link+1];
+ ogg_int64_t begin=vf->dataoffsets[link];
+ ogg_int64_t begintime = vf->pcmlengths[link*2];
+ ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
+ ogg_int64_t target=pos-total+begintime;
+ ogg_int64_t best=-1;
+ int got_page=0;
+
+ ogg_page og;
+
+ /* if we have only one page, there will be no bisection. Grab the page here */
+ if(begin==end){
+ result=_seek_helper(vf,begin);
+ if(result) goto seek_error;
+
+ result=_get_next_page(vf,&og,1);
+ if(result<0) goto seek_error;
+
+ got_page=1;
+ }
+
+ /* bisection loop */
+ while(begin<end){
+ ogg_int64_t bisect;
+
+ if(end-begin<CHUNKSIZE){
+ bisect=begin;
+ }else{
+ /* take a (pretty decent) guess. */
+ bisect=begin +
+ (ogg_int64_t)((double)(target-begintime)*(end-begin)/(endtime-begintime))
+ - CHUNKSIZE;
+ if(bisect<begin+CHUNKSIZE)
+ bisect=begin;
+ }
+
+ result=_seek_helper(vf,bisect);
+ if(result) goto seek_error;
+
+ /* read loop within the bisection loop */
+ while(begin<end){
+ result=_get_next_page(vf,&og,end-vf->offset);
+ if(result==OV_EREAD) goto seek_error;
+ if(result<0){
+ /* there is no next page! */
+ if(bisect<=begin+1)
+ /* No bisection left to perform. We've either found the
+ best candidate already or failed. Exit loop. */
+ end=begin;
+ else{
+ /* We tried to load a fraction of the last page; back up a
+ bit and try to get the whole last page */
+ if(bisect==0) goto seek_error;
+ bisect-=CHUNKSIZE;
+
+ /* don't repeat/loop on a read we've already performed */
+ if(bisect<=begin)bisect=begin+1;
+
+ /* seek and cntinue bisection */
+ result=_seek_helper(vf,bisect);
+ if(result) goto seek_error;
+ }
+ }else{
+ ogg_int64_t granulepos;
+ got_page=1;
+
+ /* got a page. analyze it */
+ /* only consider pages from primary vorbis stream */
+ if(ogg_page_serialno(&og)!=vf->serialnos[link])
+ continue;
+
+ /* only consider pages with the granulepos set */
+ granulepos=ogg_page_granulepos(&og);
+ if(granulepos==-1)continue;
+
+ if(granulepos<target){
+ /* this page is a successful candidate! Set state */
+
+ best=result; /* raw offset of packet with granulepos */
+ begin=vf->offset; /* raw offset of next page */
+ begintime=granulepos;
+
+ /* if we're before our target but within a short distance,
+ don't bisect; read forward */
+ if(target-begintime>44100)break;
+
+ bisect=begin; /* *not* begin + 1 as above */
+ }else{
+
+ /* This is one of our pages, but the granpos is
+ post-target; it is not a bisection return
+ candidate. (The only way we'd use it is if it's the
+ first page in the stream; we handle that case later
+ outside the bisection) */
+ if(bisect<=begin+1){
+ /* No bisection left to perform. We've either found the
+ best candidate already or failed. Exit loop. */
+ end=begin;
+ }else{
+ if(end==vf->offset){
+ /* bisection read to the end; use the known page
+ boundary (result) to update bisection, back up a
+ little bit, and try again */
+ end=result;
+ bisect-=CHUNKSIZE;
+ if(bisect<=begin)bisect=begin+1;
+ result=_seek_helper(vf,bisect);
+ if(result) goto seek_error;
+ }else{
+ /* Normal bisection */
+ end=bisect;
+ endtime=granulepos;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Out of bisection: did it 'fail?' */
+ if(best == -1){
+
+ /* Check the 'looking for data in first page' special case;
+ bisection would 'fail' because our search target was before the
+ first PCM granule position fencepost. */
+
+ if(got_page &&
+ begin == vf->dataoffsets[link] &&
+ ogg_page_serialno(&og)==vf->serialnos[link]){
+
+ /* Yes, this is the beginning-of-stream case. We already have
+ our page, right at the beginning of PCM data. Set state
+ and return. */
+
+ vf->pcm_offset=total;
+
+ if(link!=vf->current_link){
+ /* Different link; dump entire decode machine */
+ _decode_clear(vf);
+
+ vf->current_link=link;
+ vf->current_serialno=vf->serialnos[link];
+ vf->ready_state=STREAMSET;
+
+ }else{
+ vorbis_synthesis_restart(&vf->vd);
+ }
+
+ ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
+ ogg_stream_pagein(&vf->os,&og);
+
+ }else
+ goto seek_error;
+
+ }else{
+
+ /* Bisection found our page. seek to it, update pcm offset. Easier case than
+ raw_seek, don't keep packets preceding granulepos. */
+
+ ogg_page og;
+ ogg_packet op;
+
+ /* seek */
+ result=_seek_helper(vf,best);
+ vf->pcm_offset=-1;
+ if(result) goto seek_error;
+ result=_get_next_page(vf,&og,-1);
+ if(result<0) goto seek_error;
+
+ if(link!=vf->current_link){
+ /* Different link; dump entire decode machine */
+ _decode_clear(vf);
+
+ vf->current_link=link;
+ vf->current_serialno=vf->serialnos[link];
+ vf->ready_state=STREAMSET;
+
+ }else{
+ vorbis_synthesis_restart(&vf->vd);
+ }
+
+ ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
+ ogg_stream_pagein(&vf->os,&og);
+
+ /* pull out all but last packet; the one with granulepos */
+ while(1){
+ result=ogg_stream_packetpeek(&vf->os,&op);
+ if(result==0){
+ /* No packet returned; we exited the bisection with 'best'
+ pointing to a page with a granule position, so the packet
+ finishing this page ('best') originated on a preceding
+ page. Keep fetching previous pages until we get one with
+ a granulepos or without the 'continued' flag set. Then
+ just use raw_seek for simplicity. */
+ /* Do not rewind past the beginning of link data; if we do,
+ it's either a bug or a broken stream */
+ result=best;
+ while(result>vf->dataoffsets[link]){
+ result=_get_prev_page(vf,result,&og);
+ if(result<0) goto seek_error;
+ if(ogg_page_serialno(&og)==vf->current_serialno &&
+ (ogg_page_granulepos(&og)>-1 ||
+ !ogg_page_continued(&og))){
+ return ov_raw_seek(vf,result);
+ }
+ }
+ }
+ if(result<0){
+ result = OV_EBADPACKET;
+ goto seek_error;
+ }
+ if(op.granulepos!=-1){
+ vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
+ if(vf->pcm_offset<0)vf->pcm_offset=0;
+ vf->pcm_offset+=total;
+ break;
+ }else
+ result=ogg_stream_packetout(&vf->os,NULL);
+ }
+ }
+ }
+
+ /* verify result */
+ if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
+ result=OV_EFAULT;
+ goto seek_error;
+ }
+ vf->bittrack=0.f;
+ vf->samptrack=0.f;
+ return(0);
+
+ seek_error:
+ /* dump machine so we're in a known state */
+ vf->pcm_offset=-1;
+ _decode_clear(vf);
+ return (int)result;
+}
+
+/* seek to a sample offset relative to the decompressed pcm stream
+ returns zero on success, nonzero on failure */
+
+int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
+ int thisblock,lastblock=0;
+ int ret=ov_pcm_seek_page(vf,pos);
+ if(ret<0)return(ret);
+ if((ret=_make_decode_ready(vf)))return ret;
+
+ /* discard leading packets we don't need for the lapping of the
+ position we want; don't decode them */
+
+ while(1){
+ ogg_packet op;
+ ogg_page og;
+
+ int ret=ogg_stream_packetpeek(&vf->os,&op);
+ if(ret>0){
+ thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
+ if(thisblock<0){
+ ogg_stream_packetout(&vf->os,NULL);
+ continue; /* non audio packet */
+ }
+ if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
+
+ if(vf->pcm_offset+((thisblock+
+ vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
+
+ /* remove the packet from packet queue and track its granulepos */
+ ogg_stream_packetout(&vf->os,NULL);
+ vorbis_synthesis_trackonly(&vf->vb,&op); /* set up a vb with
+ only tracking, no
+ pcm_decode */
+ vorbis_synthesis_blockin(&vf->vd,&vf->vb);
+
+ /* end of logical stream case is hard, especially with exact
+ length positioning. */
+
+ if(op.granulepos>-1){
+ int i;
+ /* always believe the stream markers */
+ vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
+ if(vf->pcm_offset<0)vf->pcm_offset=0;
+ for(i=0;i<vf->current_link;i++)
+ vf->pcm_offset+=vf->pcmlengths[i*2+1];
+ }
+
+ lastblock=thisblock;
+
+ }else{
+ if(ret<0 && ret!=OV_HOLE)break;
+
+ /* suck in a new page */
+ if(_get_next_page(vf,&og,-1)<0)break;
+ if(ogg_page_bos(&og))_decode_clear(vf);
+
+ if(vf->ready_state<STREAMSET){
+ long serialno=ogg_page_serialno(&og);
+ int link;
+
+ for(link=0;link<vf->links;link++)
+ if(vf->serialnos[link]==serialno)break;
+ if(link==vf->links) continue;
+ vf->current_link=link;
+
+ vf->ready_state=STREAMSET;
+ vf->current_serialno=ogg_page_serialno(&og);
+ ogg_stream_reset_serialno(&vf->os,serialno);
+ ret=_make_decode_ready(vf);
+ if(ret)return ret;
+ lastblock=0;
+ }
+
+ ogg_stream_pagein(&vf->os,&og);
+ }
+ }
+
+ vf->bittrack=0.f;
+ vf->samptrack=0.f;
+ /* discard samples until we reach the desired position. Crossing a
+ logical bitstream boundary with abandon is OK. */
+ {
+ /* note that halfrate could be set differently in each link, but
+ vorbisfile encoforces all links are set or unset */
+ int hs=vorbis_synthesis_halfrate_p(vf->vi);
+ while(vf->pcm_offset<((pos>>hs)<<hs)){
+ ogg_int64_t target=(pos-vf->pcm_offset)>>hs;
+ long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
+
+ if(samples>target)samples=target;
+ vorbis_synthesis_read(&vf->vd,samples);
+ vf->pcm_offset+=samples<<hs;
+
+ if(samples<target)
+ if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
+ vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
+ }
+ }
+ return 0;
+}
+
+/* seek to a playback time relative to the decompressed pcm stream
+ returns zero on success, nonzero on failure */
+int ov_time_seek(OggVorbis_File *vf,double seconds){
+ /* translate time to PCM position and call ov_pcm_seek */
+
+ int link=-1;
+ ogg_int64_t pcm_total=0;
+ double time_total=0.;
+
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ if(!vf->seekable)return(OV_ENOSEEK);
+ if(seconds<0)return(OV_EINVAL);
+
+ /* which bitstream section does this time offset occur in? */
+ for(link=0;link<vf->links;link++){
+ double addsec = ov_time_total(vf,link);
+ if(seconds<time_total+addsec)break;
+ time_total+=addsec;
+ pcm_total+=vf->pcmlengths[link*2+1];
+ }
+
+ if(link==vf->links)return(OV_EINVAL);
+
+ /* enough information to convert time offset to pcm offset */
+ {
+ ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
+ return(ov_pcm_seek(vf,target));
+ }
+}
+
+/* page-granularity version of ov_time_seek
+ returns zero on success, nonzero on failure */
+int ov_time_seek_page(OggVorbis_File *vf,double seconds){
+ /* translate time to PCM position and call ov_pcm_seek */
+
+ int link=-1;
+ ogg_int64_t pcm_total=0;
+ double time_total=0.;
+
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ if(!vf->seekable)return(OV_ENOSEEK);
+ if(seconds<0)return(OV_EINVAL);
+
+ /* which bitstream section does this time offset occur in? */
+ for(link=0;link<vf->links;link++){
+ double addsec = ov_time_total(vf,link);
+ if(seconds<time_total+addsec)break;
+ time_total+=addsec;
+ pcm_total+=vf->pcmlengths[link*2+1];
+ }
+
+ if(link==vf->links)return(OV_EINVAL);
+
+ /* enough information to convert time offset to pcm offset */
+ {
+ ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
+ return(ov_pcm_seek_page(vf,target));
+ }
+}
+
+/* tell the current stream offset cursor. Note that seek followed by
+ tell will likely not give the set offset due to caching */
+ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ return(vf->offset);
+}
+
+/* return PCM offset (sample) of next PCM sample to be read */
+ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ return(vf->pcm_offset);
+}
+
+/* return time offset (seconds) of next PCM sample to be read */
+double ov_time_tell(OggVorbis_File *vf){
+ int link=0;
+ ogg_int64_t pcm_total=0;
+ double time_total=0.f;
+
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ if(vf->seekable){
+ pcm_total=ov_pcm_total(vf,-1);
+ time_total=ov_time_total(vf,-1);
+
+ /* which bitstream section does this time offset occur in? */
+ for(link=vf->links-1;link>=0;link--){
+ pcm_total-=vf->pcmlengths[link*2+1];
+ time_total-=ov_time_total(vf,link);
+ if(vf->pcm_offset>=pcm_total)break;
+ }
+ }
+
+ return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate);
+}
+
+/* link: -1) return the vorbis_info struct for the bitstream section
+ currently being decoded
+ 0-n) to request information for a specific bitstream section
+
+ In the case of a non-seekable bitstream, any call returns the
+ current bitstream. NULL in the case that the machine is not
+ initialized */
+
+vorbis_info *ov_info(OggVorbis_File *vf,int link){
+ if(vf->seekable){
+ if(link<0)
+ if(vf->ready_state>=STREAMSET)
+ return vf->vi+vf->current_link;
+ else
+ return vf->vi;
+ else
+ if(link>=vf->links)
+ return NULL;
+ else
+ return vf->vi+link;
+ }else{
+ return vf->vi;
+ }
+}
+
+/* grr, strong typing, grr, no templates/inheritence, grr */
+vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
+ if(vf->seekable){
+ if(link<0)
+ if(vf->ready_state>=STREAMSET)
+ return vf->vc+vf->current_link;
+ else
+ return vf->vc;
+ else
+ if(link>=vf->links)
+ return NULL;
+ else
+ return vf->vc+link;
+ }else{
+ return vf->vc;
+ }
+}
+
+static int host_is_big_endian(void) {
+ ogg_int32_t pattern = 0xfeedface; /* deadbeef */
+ unsigned char *bytewise = (unsigned char *)&pattern;
+ if (bytewise[0] == 0xfe) return 1;
+ return 0;
+}
+
+/* up to this point, everything could more or less hide the multiple
+ logical bitstream nature of chaining from the toplevel application
+ if the toplevel application didn't particularly care. However, at
+ the point that we actually read audio back, the multiple-section
+ nature must surface: Multiple bitstream sections do not necessarily
+ have to have the same number of channels or sampling rate.
+
+ ov_read returns the sequential logical bitstream number currently
+ being decoded along with the PCM data in order that the toplevel
+ application can take action on channel/sample rate changes. This
+ number will be incremented even for streamed (non-seekable) streams
+ (for seekable streams, it represents the actual logical bitstream
+ index within the physical bitstream. Note that the accessor
+ functions above are aware of this dichotomy).
+
+ ov_read_filter is exactly the same as ov_read except that it processes
+ the decoded audio data through a filter before packing it into the
+ requested format. This gives greater accuracy than applying a filter
+ after the audio has been converted into integral PCM.
+
+ input values: buffer) a buffer to hold packed PCM data for return
+ length) the byte length requested to be placed into buffer
+ bigendianp) should the data be packed LSB first (0) or
+ MSB first (1)
+ word) word size for output. currently 1 (byte) or
+ 2 (16 bit short)
+
+ return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
+ 0) EOF
+ n) number of bytes of PCM actually returned. The
+ below works on a packet-by-packet basis, so the
+ return length is not related to the 'length' passed
+ in, just guaranteed to fit.
+
+ *section) set to the logical bitstream number */
+
+long ov_read_filter(OggVorbis_File *vf,char *buffer,int length,
+ int bigendianp,int word,int sgned,int *bitstream,
+ void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param){
+ int i,j;
+ int host_endian = host_is_big_endian();
+ int hs;
+
+ float **pcm;
+ long samples;
+
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+
+ while(1){
+ if(vf->ready_state==INITSET){
+ samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
+ if(samples)break;
+ }
+
+ /* suck in another packet */
+ {
+ int ret=_fetch_and_process_packet(vf,NULL,1,1);
+ if(ret==OV_EOF)
+ return(0);
+ if(ret<=0)
+ return(ret);
+ }
+
+ }
+
+ if(samples>0){
+
+ /* yay! proceed to pack data into the byte buffer */
+
+ long channels=ov_info(vf,-1)->channels;
+ long bytespersample=word * channels;
+ vorbis_fpu_control fpu;
+ if(samples>length/bytespersample)samples=length/bytespersample;
+
+ if(samples <= 0)
+ return OV_EINVAL;
+
+ /* Here. */
+ if(filter)
+ filter(pcm,channels,samples,filter_param);
+
+ /* a tight loop to pack each size */
+ {
+ int val;
+ if(word==1){
+ int off=(sgned?0:128);
+ vorbis_fpu_setround(&fpu);
+ for(j=0;j<samples;j++)
+ for(i=0;i<channels;i++){
+ val=vorbis_ftoi(pcm[i][j]*128.f);
+ if(val>127)val=127;
+ else if(val<-128)val=-128;
+ *buffer++=val+off;
+ }
+ vorbis_fpu_restore(fpu);
+ }else{
+ int off=(sgned?0:32768);
+
+ if(host_endian==bigendianp){
+ if(sgned){
+
+ vorbis_fpu_setround(&fpu);
+ for(i=0;i<channels;i++) { /* It's faster in this order */
+ float *src=pcm[i];
+ short *dest=((short *)buffer)+i;
+ for(j=0;j<samples;j++) {
+ val=vorbis_ftoi(src[j]*32768.f);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ *dest=val;
+ dest+=channels;
+ }
+ }
+ vorbis_fpu_restore(fpu);
+
+ }else{
+
+ vorbis_fpu_setround(&fpu);
+ for(i=0;i<channels;i++) {
+ float *src=pcm[i];
+ short *dest=((short *)buffer)+i;
+ for(j=0;j<samples;j++) {
+ val=vorbis_ftoi(src[j]*32768.f);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ *dest=val+off;
+ dest+=channels;
+ }
+ }
+ vorbis_fpu_restore(fpu);
+
+ }
+ }else if(bigendianp){
+
+ vorbis_fpu_setround(&fpu);
+ for(j=0;j<samples;j++)
+ for(i=0;i<channels;i++){
+ val=vorbis_ftoi(pcm[i][j]*32768.f);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ val+=off;
+ *buffer++=(val>>8);
+ *buffer++=(val&0xff);
+ }
+ vorbis_fpu_restore(fpu);
+
+ }else{
+ int val;
+ vorbis_fpu_setround(&fpu);
+ for(j=0;j<samples;j++)
+ for(i=0;i<channels;i++){
+ val=vorbis_ftoi(pcm[i][j]*32768.f);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ val+=off;
+ *buffer++=(val&0xff);
+ *buffer++=(val>>8);
+ }
+ vorbis_fpu_restore(fpu);
+
+ }
+ }
+ }
+
+ vorbis_synthesis_read(&vf->vd,samples);
+ hs=vorbis_synthesis_halfrate_p(vf->vi);
+ vf->pcm_offset+=(samples<<hs);
+ if(bitstream)*bitstream=vf->current_link;
+ return(samples*bytespersample);
+ }else{
+ return(samples);
+ }
+}
+
+long ov_read(OggVorbis_File *vf,char *buffer,int length,
+ int bigendianp,int word,int sgned,int *bitstream){
+ return ov_read_filter(vf, buffer, length, bigendianp, word, sgned, bitstream, NULL, NULL);
+}
+
+/* input values: pcm_channels) a float vector per channel of output
+ length) the sample length being read by the app
+
+ return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
+ 0) EOF
+ n) number of samples of PCM actually returned. The
+ below works on a packet-by-packet basis, so the
+ return length is not related to the 'length' passed
+ in, just guaranteed to fit.
+
+ *section) set to the logical bitstream number */
+
+
+
+long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length,
+ int *bitstream){
+
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+
+ while(1){
+ if(vf->ready_state==INITSET){
+ float **pcm;
+ long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
+ if(samples){
+ int hs=vorbis_synthesis_halfrate_p(vf->vi);
+ if(pcm_channels)*pcm_channels=pcm;
+ if(samples>length)samples=length;
+ vorbis_synthesis_read(&vf->vd,samples);
+ vf->pcm_offset+=samples<<hs;
+ if(bitstream)*bitstream=vf->current_link;
+ return samples;
+
+ }
+ }
+
+ /* suck in another packet */
+ {
+ int ret=_fetch_and_process_packet(vf,NULL,1,1);
+ if(ret==OV_EOF)return(0);
+ if(ret<=0)return(ret);
+ }
+
+ }
+}
+
+extern const float *vorbis_window(vorbis_dsp_state *v,int W);
+
+static void _ov_splice(float **pcm,float **lappcm,
+ int n1, int n2,
+ int ch1, int ch2,
+ const float *w1, const float *w2){
+ int i,j;
+ const float *w=w1;
+ int n=n1;
+
+ if(n1>n2){
+ n=n2;
+ w=w2;
+ }
+
+ /* splice */
+ for(j=0;j<ch1 && j<ch2;j++){
+ float *s=lappcm[j];
+ float *d=pcm[j];
+
+ for(i=0;i<n;i++){
+ float wd=w[i]*w[i];
+ float ws=1.-wd;
+ d[i]=d[i]*wd + s[i]*ws;
+ }
+ }
+ /* window from zero */
+ for(;j<ch2;j++){
+ float *d=pcm[j];
+ for(i=0;i<n;i++){
+ float wd=w[i]*w[i];
+ d[i]=d[i]*wd;
+ }
+ }
+
+}
+
+/* make sure vf is INITSET */
+static int _ov_initset(OggVorbis_File *vf){
+ while(1){
+ if(vf->ready_state==INITSET)break;
+ /* suck in another packet */
+ {
+ int ret=_fetch_and_process_packet(vf,NULL,1,0);
+ if(ret<0 && ret!=OV_HOLE)return(ret);
+ }
+ }
+ return 0;
+}
+
+/* make sure vf is INITSET and that we have a primed buffer; if
+ we're crosslapping at a stream section boundary, this also makes
+ sure we're sanity checking against the right stream information */
+static int _ov_initprime(OggVorbis_File *vf){
+ vorbis_dsp_state *vd=&vf->vd;
+ while(1){
+ if(vf->ready_state==INITSET)
+ if(vorbis_synthesis_pcmout(vd,NULL))break;
+
+ /* suck in another packet */
+ {
+ int ret=_fetch_and_process_packet(vf,NULL,1,0);
+ if(ret<0 && ret!=OV_HOLE)return(ret);
+ }
+ }
+ return 0;
+}
+
+/* grab enough data for lapping from vf; this may be in the form of
+ unreturned, already-decoded pcm, remaining PCM we will need to
+ decode, or synthetic postextrapolation from last packets. */
+static void _ov_getlap(OggVorbis_File *vf,vorbis_info *vi,vorbis_dsp_state *vd,
+ float **lappcm,int lapsize){
+ int lapcount=0,i;
+ float **pcm;
+
+ /* try first to decode the lapping data */
+ while(lapcount<lapsize){
+ int samples=vorbis_synthesis_pcmout(vd,&pcm);
+ if(samples){
+ if(samples>lapsize-lapcount)samples=lapsize-lapcount;
+ for(i=0;i<vi->channels;i++)
+ memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
+ lapcount+=samples;
+ vorbis_synthesis_read(vd,samples);
+ }else{
+ /* suck in another packet */
+ int ret=_fetch_and_process_packet(vf,NULL,1,0); /* do *not* span */
+ if(ret==OV_EOF)break;
+ }
+ }
+ if(lapcount<lapsize){
+ /* failed to get lapping data from normal decode; pry it from the
+ postextrapolation buffering, or the second half of the MDCT
+ from the last packet */
+ int samples=vorbis_synthesis_lapout(&vf->vd,&pcm);
+ if(samples==0){
+ for(i=0;i<vi->channels;i++)
+ memset(lappcm[i]+lapcount,0,sizeof(**pcm)*lapsize-lapcount);
+ lapcount=lapsize;
+ }else{
+ if(samples>lapsize-lapcount)samples=lapsize-lapcount;
+ for(i=0;i<vi->channels;i++)
+ memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
+ lapcount+=samples;
+ }
+ }
+}
+
+/* this sets up crosslapping of a sample by using trailing data from
+ sample 1 and lapping it into the windowing buffer of sample 2 */
+int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){
+ vorbis_info *vi1,*vi2;
+ float **lappcm;
+ float **pcm;
+ const float *w1,*w2;
+ int n1,n2,i,ret,hs1,hs2;
+
+ if(vf1==vf2)return(0); /* degenerate case */
+ if(vf1->ready_state<OPENED)return(OV_EINVAL);
+ if(vf2->ready_state<OPENED)return(OV_EINVAL);
+
+ /* the relevant overlap buffers must be pre-checked and pre-primed
+ before looking at settings in the event that priming would cross
+ a bitstream boundary. So, do it now */
+
+ ret=_ov_initset(vf1);
+ if(ret)return(ret);
+ ret=_ov_initprime(vf2);
+ if(ret)return(ret);
+
+ vi1=ov_info(vf1,-1);
+ vi2=ov_info(vf2,-1);
+ hs1=ov_halfrate_p(vf1);
+ hs2=ov_halfrate_p(vf2);
+
+ lappcm=alloca(sizeof(*lappcm)*vi1->channels);
+ n1=vorbis_info_blocksize(vi1,0)>>(1+hs1);
+ n2=vorbis_info_blocksize(vi2,0)>>(1+hs2);
+ w1=vorbis_window(&vf1->vd,0);
+ w2=vorbis_window(&vf2->vd,0);
+
+ for(i=0;i<vi1->channels;i++)
+ lappcm[i]=alloca(sizeof(**lappcm)*n1);
+
+ _ov_getlap(vf1,vi1,&vf1->vd,lappcm,n1);
+
+ /* have a lapping buffer from vf1; now to splice it into the lapping
+ buffer of vf2 */
+ /* consolidate and expose the buffer. */
+ vorbis_synthesis_lapout(&vf2->vd,&pcm);
+
+#if 0
+ _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0);
+ _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0);
+#endif
+
+ /* splice */
+ _ov_splice(pcm,lappcm,n1,n2,vi1->channels,vi2->channels,w1,w2);
+
+ /* done */
+ return(0);
+}
+
+static int _ov_64_seek_lap(OggVorbis_File *vf,ogg_int64_t pos,
+ int (*localseek)(OggVorbis_File *,ogg_int64_t)){
+ vorbis_info *vi;
+ float **lappcm;
+ float **pcm;
+ const float *w1,*w2;
+ int n1,n2,ch1,ch2,hs;
+ int i,ret;
+
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ ret=_ov_initset(vf);
+ if(ret)return(ret);
+ vi=ov_info(vf,-1);
+ hs=ov_halfrate_p(vf);
+
+ ch1=vi->channels;
+ n1=vorbis_info_blocksize(vi,0)>>(1+hs);
+ w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are
+ persistent; even if the decode state
+ from this link gets dumped, this
+ window array continues to exist */
+
+ lappcm=alloca(sizeof(*lappcm)*ch1);
+ for(i=0;i<ch1;i++)
+ lappcm[i]=alloca(sizeof(**lappcm)*n1);
+ _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
+
+ /* have lapping data; seek and prime the buffer */
+ ret=localseek(vf,pos);
+ if(ret)return ret;
+ ret=_ov_initprime(vf);
+ if(ret)return(ret);
+
+ /* Guard against cross-link changes; they're perfectly legal */
+ vi=ov_info(vf,-1);
+ ch2=vi->channels;
+ n2=vorbis_info_blocksize(vi,0)>>(1+hs);
+ w2=vorbis_window(&vf->vd,0);
+
+ /* consolidate and expose the buffer. */
+ vorbis_synthesis_lapout(&vf->vd,&pcm);
+
+ /* splice */
+ _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
+
+ /* done */
+ return(0);
+}
+
+int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
+ return _ov_64_seek_lap(vf,pos,ov_raw_seek);
+}
+
+int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
+ return _ov_64_seek_lap(vf,pos,ov_pcm_seek);
+}
+
+int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos){
+ return _ov_64_seek_lap(vf,pos,ov_pcm_seek_page);
+}
+
+static int _ov_d_seek_lap(OggVorbis_File *vf,double pos,
+ int (*localseek)(OggVorbis_File *,double)){
+ vorbis_info *vi;
+ float **lappcm;
+ float **pcm;
+ const float *w1,*w2;
+ int n1,n2,ch1,ch2,hs;
+ int i,ret;
+
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ ret=_ov_initset(vf);
+ if(ret)return(ret);
+ vi=ov_info(vf,-1);
+ hs=ov_halfrate_p(vf);
+
+ ch1=vi->channels;
+ n1=vorbis_info_blocksize(vi,0)>>(1+hs);
+ w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are
+ persistent; even if the decode state
+ from this link gets dumped, this
+ window array continues to exist */
+
+ lappcm=alloca(sizeof(*lappcm)*ch1);
+ for(i=0;i<ch1;i++)
+ lappcm[i]=alloca(sizeof(**lappcm)*n1);
+ _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
+
+ /* have lapping data; seek and prime the buffer */
+ ret=localseek(vf,pos);
+ if(ret)return ret;
+ ret=_ov_initprime(vf);
+ if(ret)return(ret);
+
+ /* Guard against cross-link changes; they're perfectly legal */
+ vi=ov_info(vf,-1);
+ ch2=vi->channels;
+ n2=vorbis_info_blocksize(vi,0)>>(1+hs);
+ w2=vorbis_window(&vf->vd,0);
+
+ /* consolidate and expose the buffer. */
+ vorbis_synthesis_lapout(&vf->vd,&pcm);
+
+ /* splice */
+ _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
+
+ /* done */
+ return(0);
+}
+
+int ov_time_seek_lap(OggVorbis_File *vf,double pos){
+ return _ov_d_seek_lap(vf,pos,ov_time_seek);
+}
+
+int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){
+ return _ov_d_seek_lap(vf,pos,ov_time_seek_page);
+}
diff --git a/external/libvorbis-1.3.5/lib/window.c b/external/libvorbis-1.3.5/lib/window.c
new file mode 100644
index 0000000..0305b79
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/window.c
@@ -0,0 +1,2136 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: window functions
+ last mod: $Id: window.c 19028 2013-12-02 23:23:39Z tterribe $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <math.h>
+#include "os.h"
+#include "misc.h"
+#include "window.h"
+
+static const float vwin64[32] = {
+ 0.0009460463F, 0.0085006468F, 0.0235352254F, 0.0458950567F,
+ 0.0753351908F, 0.1115073077F, 0.1539457973F, 0.2020557475F,
+ 0.2551056759F, 0.3122276645F, 0.3724270287F, 0.4346027792F,
+ 0.4975789974F, 0.5601459521F, 0.6211085051F, 0.6793382689F,
+ 0.7338252629F, 0.7837245849F, 0.8283939355F, 0.8674186656F,
+ 0.9006222429F, 0.9280614787F, 0.9500073081F, 0.9669131782F,
+ 0.9793740220F, 0.9880792941F, 0.9937636139F, 0.9971582668F,
+ 0.9989462667F, 0.9997230082F, 0.9999638688F, 0.9999995525F,
+};
+
+static const float vwin128[64] = {
+ 0.0002365472F, 0.0021280687F, 0.0059065254F, 0.0115626550F,
+ 0.0190823442F, 0.0284463735F, 0.0396300935F, 0.0526030430F,
+ 0.0673285281F, 0.0837631763F, 0.1018564887F, 0.1215504095F,
+ 0.1427789367F, 0.1654677960F, 0.1895342001F, 0.2148867160F,
+ 0.2414252576F, 0.2690412240F, 0.2976177952F, 0.3270303960F,
+ 0.3571473350F, 0.3878306189F, 0.4189369387F, 0.4503188188F,
+ 0.4818259135F, 0.5133064334F, 0.5446086751F, 0.5755826278F,
+ 0.6060816248F, 0.6359640047F, 0.6650947483F, 0.6933470543F,
+ 0.7206038179F, 0.7467589810F, 0.7717187213F, 0.7954024542F,
+ 0.8177436264F, 0.8386902831F, 0.8582053981F, 0.8762669622F,
+ 0.8928678298F, 0.9080153310F, 0.9217306608F, 0.9340480615F,
+ 0.9450138200F, 0.9546851041F, 0.9631286621F, 0.9704194171F,
+ 0.9766389810F, 0.9818741197F, 0.9862151938F, 0.9897546035F,
+ 0.9925852598F, 0.9947991032F, 0.9964856900F, 0.9977308602F,
+ 0.9986155015F, 0.9992144193F, 0.9995953200F, 0.9998179155F,
+ 0.9999331503F, 0.9999825563F, 0.9999977357F, 0.9999999720F,
+};
+
+static const float vwin256[128] = {
+ 0.0000591390F, 0.0005321979F, 0.0014780301F, 0.0028960636F,
+ 0.0047854363F, 0.0071449926F, 0.0099732775F, 0.0132685298F,
+ 0.0170286741F, 0.0212513119F, 0.0259337111F, 0.0310727950F,
+ 0.0366651302F, 0.0427069140F, 0.0491939614F, 0.0561216907F,
+ 0.0634851102F, 0.0712788035F, 0.0794969160F, 0.0881331402F,
+ 0.0971807028F, 0.1066323515F, 0.1164803426F, 0.1267164297F,
+ 0.1373318534F, 0.1483173323F, 0.1596630553F, 0.1713586755F,
+ 0.1833933062F, 0.1957555184F, 0.2084333404F, 0.2214142599F,
+ 0.2346852280F, 0.2482326664F, 0.2620424757F, 0.2761000481F,
+ 0.2903902813F, 0.3048975959F, 0.3196059553F, 0.3344988887F,
+ 0.3495595160F, 0.3647705766F, 0.3801144597F, 0.3955732382F,
+ 0.4111287047F, 0.4267624093F, 0.4424557009F, 0.4581897696F,
+ 0.4739456913F, 0.4897044744F, 0.5054471075F, 0.5211546088F,
+ 0.5368080763F, 0.5523887395F, 0.5678780103F, 0.5832575361F,
+ 0.5985092508F, 0.6136154277F, 0.6285587300F, 0.6433222619F,
+ 0.6578896175F, 0.6722449294F, 0.6863729144F, 0.7002589187F,
+ 0.7138889597F, 0.7272497662F, 0.7403288154F, 0.7531143679F,
+ 0.7655954985F, 0.7777621249F, 0.7896050322F, 0.8011158947F,
+ 0.8122872932F, 0.8231127294F, 0.8335866365F, 0.8437043850F,
+ 0.8534622861F, 0.8628575905F, 0.8718884835F, 0.8805540765F,
+ 0.8888543947F, 0.8967903616F, 0.9043637797F, 0.9115773078F,
+ 0.9184344360F, 0.9249394562F, 0.9310974312F, 0.9369141608F,
+ 0.9423961446F, 0.9475505439F, 0.9523851406F, 0.9569082947F,
+ 0.9611289005F, 0.9650563408F, 0.9687004405F, 0.9720714191F,
+ 0.9751798427F, 0.9780365753F, 0.9806527301F, 0.9830396204F,
+ 0.9852087111F, 0.9871715701F, 0.9889398207F, 0.9905250941F,
+ 0.9919389832F, 0.9931929973F, 0.9942985174F, 0.9952667537F,
+ 0.9961087037F, 0.9968351119F, 0.9974564312F, 0.9979827858F,
+ 0.9984239359F, 0.9987892441F, 0.9990876435F, 0.9993276081F,
+ 0.9995171241F, 0.9996636648F, 0.9997741654F, 0.9998550016F,
+ 0.9999119692F, 0.9999502656F, 0.9999744742F, 0.9999885497F,
+ 0.9999958064F, 0.9999989077F, 0.9999998584F, 0.9999999983F,
+};
+
+static const float vwin512[256] = {
+ 0.0000147849F, 0.0001330607F, 0.0003695946F, 0.0007243509F,
+ 0.0011972759F, 0.0017882983F, 0.0024973285F, 0.0033242588F,
+ 0.0042689632F, 0.0053312973F, 0.0065110982F, 0.0078081841F,
+ 0.0092223540F, 0.0107533880F, 0.0124010466F, 0.0141650703F,
+ 0.0160451800F, 0.0180410758F, 0.0201524373F, 0.0223789233F,
+ 0.0247201710F, 0.0271757958F, 0.0297453914F, 0.0324285286F,
+ 0.0352247556F, 0.0381335972F, 0.0411545545F, 0.0442871045F,
+ 0.0475306997F, 0.0508847676F, 0.0543487103F, 0.0579219038F,
+ 0.0616036982F, 0.0653934164F, 0.0692903546F, 0.0732937809F,
+ 0.0774029356F, 0.0816170305F, 0.0859352485F, 0.0903567428F,
+ 0.0948806375F, 0.0995060259F, 0.1042319712F, 0.1090575056F,
+ 0.1139816300F, 0.1190033137F, 0.1241214941F, 0.1293350764F,
+ 0.1346429333F, 0.1400439046F, 0.1455367974F, 0.1511203852F,
+ 0.1567934083F, 0.1625545735F, 0.1684025537F, 0.1743359881F,
+ 0.1803534820F, 0.1864536069F, 0.1926349000F, 0.1988958650F,
+ 0.2052349715F, 0.2116506555F, 0.2181413191F, 0.2247053313F,
+ 0.2313410275F, 0.2380467105F, 0.2448206500F, 0.2516610835F,
+ 0.2585662164F, 0.2655342226F, 0.2725632448F, 0.2796513950F,
+ 0.2867967551F, 0.2939973773F, 0.3012512852F, 0.3085564739F,
+ 0.3159109111F, 0.3233125375F, 0.3307592680F, 0.3382489922F,
+ 0.3457795756F, 0.3533488602F, 0.3609546657F, 0.3685947904F,
+ 0.3762670121F, 0.3839690896F, 0.3916987634F, 0.3994537572F,
+ 0.4072317788F, 0.4150305215F, 0.4228476653F, 0.4306808783F,
+ 0.4385278181F, 0.4463861329F, 0.4542534630F, 0.4621274424F,
+ 0.4700057001F, 0.4778858615F, 0.4857655502F, 0.4936423891F,
+ 0.5015140023F, 0.5093780165F, 0.5172320626F, 0.5250737772F,
+ 0.5329008043F, 0.5407107971F, 0.5485014192F, 0.5562703465F,
+ 0.5640152688F, 0.5717338914F, 0.5794239366F, 0.5870831457F,
+ 0.5947092801F, 0.6023001235F, 0.6098534829F, 0.6173671907F,
+ 0.6248391059F, 0.6322671161F, 0.6396491384F, 0.6469831217F,
+ 0.6542670475F, 0.6614989319F, 0.6686768267F, 0.6757988210F,
+ 0.6828630426F, 0.6898676592F, 0.6968108799F, 0.7036909564F,
+ 0.7105061843F, 0.7172549043F, 0.7239355032F, 0.7305464154F,
+ 0.7370861235F, 0.7435531598F, 0.7499461068F, 0.7562635986F,
+ 0.7625043214F, 0.7686670148F, 0.7747504721F, 0.7807535410F,
+ 0.7866751247F, 0.7925141825F, 0.7982697296F, 0.8039408387F,
+ 0.8095266395F, 0.8150263196F, 0.8204391248F, 0.8257643590F,
+ 0.8310013848F, 0.8361496236F, 0.8412085555F, 0.8461777194F,
+ 0.8510567129F, 0.8558451924F, 0.8605428730F, 0.8651495278F,
+ 0.8696649882F, 0.8740891432F, 0.8784219392F, 0.8826633797F,
+ 0.8868135244F, 0.8908724888F, 0.8948404441F, 0.8987176157F,
+ 0.9025042831F, 0.9062007791F, 0.9098074886F, 0.9133248482F,
+ 0.9167533451F, 0.9200935163F, 0.9233459472F, 0.9265112712F,
+ 0.9295901680F, 0.9325833632F, 0.9354916263F, 0.9383157705F,
+ 0.9410566504F, 0.9437151618F, 0.9462922398F, 0.9487888576F,
+ 0.9512060252F, 0.9535447882F, 0.9558062262F, 0.9579914516F,
+ 0.9601016078F, 0.9621378683F, 0.9641014348F, 0.9659935361F,
+ 0.9678154261F, 0.9695683830F, 0.9712537071F, 0.9728727198F,
+ 0.9744267618F, 0.9759171916F, 0.9773453842F, 0.9787127293F,
+ 0.9800206298F, 0.9812705006F, 0.9824637665F, 0.9836018613F,
+ 0.9846862258F, 0.9857183066F, 0.9866995544F, 0.9876314227F,
+ 0.9885153662F, 0.9893528393F, 0.9901452948F, 0.9908941823F,
+ 0.9916009470F, 0.9922670279F, 0.9928938570F, 0.9934828574F,
+ 0.9940354423F, 0.9945530133F, 0.9950369595F, 0.9954886562F,
+ 0.9959094633F, 0.9963007242F, 0.9966637649F, 0.9969998925F,
+ 0.9973103939F, 0.9975965351F, 0.9978595598F, 0.9981006885F,
+ 0.9983211172F, 0.9985220166F, 0.9987045311F, 0.9988697776F,
+ 0.9990188449F, 0.9991527924F, 0.9992726499F, 0.9993794157F,
+ 0.9994740570F, 0.9995575079F, 0.9996306699F, 0.9996944099F,
+ 0.9997495605F, 0.9997969190F, 0.9998372465F, 0.9998712678F,
+ 0.9998996704F, 0.9999231041F, 0.9999421807F, 0.9999574732F,
+ 0.9999695157F, 0.9999788026F, 0.9999857885F, 0.9999908879F,
+ 0.9999944746F, 0.9999968817F, 0.9999984010F, 0.9999992833F,
+ 0.9999997377F, 0.9999999317F, 0.9999999911F, 0.9999999999F,
+};
+
+static const float vwin1024[512] = {
+ 0.0000036962F, 0.0000332659F, 0.0000924041F, 0.0001811086F,
+ 0.0002993761F, 0.0004472021F, 0.0006245811F, 0.0008315063F,
+ 0.0010679699F, 0.0013339631F, 0.0016294757F, 0.0019544965F,
+ 0.0023090133F, 0.0026930125F, 0.0031064797F, 0.0035493989F,
+ 0.0040217533F, 0.0045235250F, 0.0050546946F, 0.0056152418F,
+ 0.0062051451F, 0.0068243817F, 0.0074729278F, 0.0081507582F,
+ 0.0088578466F, 0.0095941655F, 0.0103596863F, 0.0111543789F,
+ 0.0119782122F, 0.0128311538F, 0.0137131701F, 0.0146242260F,
+ 0.0155642855F, 0.0165333111F, 0.0175312640F, 0.0185581042F,
+ 0.0196137903F, 0.0206982797F, 0.0218115284F, 0.0229534910F,
+ 0.0241241208F, 0.0253233698F, 0.0265511886F, 0.0278075263F,
+ 0.0290923308F, 0.0304055484F, 0.0317471241F, 0.0331170013F,
+ 0.0345151222F, 0.0359414274F, 0.0373958560F, 0.0388783456F,
+ 0.0403888325F, 0.0419272511F, 0.0434935347F, 0.0450876148F,
+ 0.0467094213F, 0.0483588828F, 0.0500359261F, 0.0517404765F,
+ 0.0534724575F, 0.0552317913F, 0.0570183983F, 0.0588321971F,
+ 0.0606731048F, 0.0625410369F, 0.0644359070F, 0.0663576272F,
+ 0.0683061077F, 0.0702812571F, 0.0722829821F, 0.0743111878F,
+ 0.0763657775F, 0.0784466526F, 0.0805537129F, 0.0826868561F,
+ 0.0848459782F, 0.0870309736F, 0.0892417345F, 0.0914781514F,
+ 0.0937401128F, 0.0960275056F, 0.0983402145F, 0.1006781223F,
+ 0.1030411101F, 0.1054290568F, 0.1078418397F, 0.1102793336F,
+ 0.1127414119F, 0.1152279457F, 0.1177388042F, 0.1202738544F,
+ 0.1228329618F, 0.1254159892F, 0.1280227980F, 0.1306532471F,
+ 0.1333071937F, 0.1359844927F, 0.1386849970F, 0.1414085575F,
+ 0.1441550230F, 0.1469242403F, 0.1497160539F, 0.1525303063F,
+ 0.1553668381F, 0.1582254875F, 0.1611060909F, 0.1640084822F,
+ 0.1669324936F, 0.1698779549F, 0.1728446939F, 0.1758325362F,
+ 0.1788413055F, 0.1818708232F, 0.1849209084F, 0.1879913785F,
+ 0.1910820485F, 0.1941927312F, 0.1973232376F, 0.2004733764F,
+ 0.2036429541F, 0.2068317752F, 0.2100396421F, 0.2132663552F,
+ 0.2165117125F, 0.2197755102F, 0.2230575422F, 0.2263576007F,
+ 0.2296754753F, 0.2330109540F, 0.2363638225F, 0.2397338646F,
+ 0.2431208619F, 0.2465245941F, 0.2499448389F, 0.2533813719F,
+ 0.2568339669F, 0.2603023956F, 0.2637864277F, 0.2672858312F,
+ 0.2708003718F, 0.2743298135F, 0.2778739186F, 0.2814324472F,
+ 0.2850051576F, 0.2885918065F, 0.2921921485F, 0.2958059366F,
+ 0.2994329219F, 0.3030728538F, 0.3067254799F, 0.3103905462F,
+ 0.3140677969F, 0.3177569747F, 0.3214578205F, 0.3251700736F,
+ 0.3288934718F, 0.3326277513F, 0.3363726468F, 0.3401278914F,
+ 0.3438932168F, 0.3476683533F, 0.3514530297F, 0.3552469734F,
+ 0.3590499106F, 0.3628615659F, 0.3666816630F, 0.3705099239F,
+ 0.3743460698F, 0.3781898204F, 0.3820408945F, 0.3858990095F,
+ 0.3897638820F, 0.3936352274F, 0.3975127601F, 0.4013961936F,
+ 0.4052852405F, 0.4091796123F, 0.4130790198F, 0.4169831732F,
+ 0.4208917815F, 0.4248045534F, 0.4287211965F, 0.4326414181F,
+ 0.4365649248F, 0.4404914225F, 0.4444206167F, 0.4483522125F,
+ 0.4522859146F, 0.4562214270F, 0.4601584538F, 0.4640966984F,
+ 0.4680358644F, 0.4719756548F, 0.4759157726F, 0.4798559209F,
+ 0.4837958024F, 0.4877351199F, 0.4916735765F, 0.4956108751F,
+ 0.4995467188F, 0.5034808109F, 0.5074128550F, 0.5113425550F,
+ 0.5152696149F, 0.5191937395F, 0.5231146336F, 0.5270320028F,
+ 0.5309455530F, 0.5348549910F, 0.5387600239F, 0.5426603597F,
+ 0.5465557070F, 0.5504457754F, 0.5543302752F, 0.5582089175F,
+ 0.5620814145F, 0.5659474793F, 0.5698068262F, 0.5736591704F,
+ 0.5775042283F, 0.5813417176F, 0.5851713571F, 0.5889928670F,
+ 0.5928059689F, 0.5966103856F, 0.6004058415F, 0.6041920626F,
+ 0.6079687761F, 0.6117357113F, 0.6154925986F, 0.6192391705F,
+ 0.6229751612F, 0.6267003064F, 0.6304143441F, 0.6341170137F,
+ 0.6378080569F, 0.6414872173F, 0.6451542405F, 0.6488088741F,
+ 0.6524508681F, 0.6560799742F, 0.6596959469F, 0.6632985424F,
+ 0.6668875197F, 0.6704626398F, 0.6740236662F, 0.6775703649F,
+ 0.6811025043F, 0.6846198554F, 0.6881221916F, 0.6916092892F,
+ 0.6950809269F, 0.6985368861F, 0.7019769510F, 0.7054009085F,
+ 0.7088085484F, 0.7121996632F, 0.7155740484F, 0.7189315023F,
+ 0.7222718263F, 0.7255948245F, 0.7289003043F, 0.7321880760F,
+ 0.7354579530F, 0.7387097518F, 0.7419432921F, 0.7451583966F,
+ 0.7483548915F, 0.7515326059F, 0.7546913723F, 0.7578310265F,
+ 0.7609514077F, 0.7640523581F, 0.7671337237F, 0.7701953535F,
+ 0.7732371001F, 0.7762588195F, 0.7792603711F, 0.7822416178F,
+ 0.7852024259F, 0.7881426654F, 0.7910622097F, 0.7939609356F,
+ 0.7968387237F, 0.7996954579F, 0.8025310261F, 0.8053453193F,
+ 0.8081382324F, 0.8109096638F, 0.8136595156F, 0.8163876936F,
+ 0.8190941071F, 0.8217786690F, 0.8244412960F, 0.8270819086F,
+ 0.8297004305F, 0.8322967896F, 0.8348709171F, 0.8374227481F,
+ 0.8399522213F, 0.8424592789F, 0.8449438672F, 0.8474059356F,
+ 0.8498454378F, 0.8522623306F, 0.8546565748F, 0.8570281348F,
+ 0.8593769787F, 0.8617030779F, 0.8640064080F, 0.8662869477F,
+ 0.8685446796F, 0.8707795899F, 0.8729916682F, 0.8751809079F,
+ 0.8773473059F, 0.8794908626F, 0.8816115819F, 0.8837094713F,
+ 0.8857845418F, 0.8878368079F, 0.8898662874F, 0.8918730019F,
+ 0.8938569760F, 0.8958182380F, 0.8977568194F, 0.8996727552F,
+ 0.9015660837F, 0.9034368465F, 0.9052850885F, 0.9071108577F,
+ 0.9089142057F, 0.9106951869F, 0.9124538591F, 0.9141902832F,
+ 0.9159045233F, 0.9175966464F, 0.9192667228F, 0.9209148257F,
+ 0.9225410313F, 0.9241454187F, 0.9257280701F, 0.9272890704F,
+ 0.9288285075F, 0.9303464720F, 0.9318430576F, 0.9333183603F,
+ 0.9347724792F, 0.9362055158F, 0.9376175745F, 0.9390087622F,
+ 0.9403791881F, 0.9417289644F, 0.9430582055F, 0.9443670283F,
+ 0.9456555521F, 0.9469238986F, 0.9481721917F, 0.9494005577F,
+ 0.9506091252F, 0.9517980248F, 0.9529673894F, 0.9541173540F,
+ 0.9552480557F, 0.9563596334F, 0.9574522282F, 0.9585259830F,
+ 0.9595810428F, 0.9606175542F, 0.9616356656F, 0.9626355274F,
+ 0.9636172915F, 0.9645811114F, 0.9655271425F, 0.9664555414F,
+ 0.9673664664F, 0.9682600774F, 0.9691365355F, 0.9699960034F,
+ 0.9708386448F, 0.9716646250F, 0.9724741103F, 0.9732672685F,
+ 0.9740442683F, 0.9748052795F, 0.9755504729F, 0.9762800205F,
+ 0.9769940950F, 0.9776928703F, 0.9783765210F, 0.9790452223F,
+ 0.9796991504F, 0.9803384823F, 0.9809633954F, 0.9815740679F,
+ 0.9821706784F, 0.9827534063F, 0.9833224312F, 0.9838779332F,
+ 0.9844200928F, 0.9849490910F, 0.9854651087F, 0.9859683274F,
+ 0.9864589286F, 0.9869370940F, 0.9874030054F, 0.9878568447F,
+ 0.9882987937F, 0.9887290343F, 0.9891477481F, 0.9895551169F,
+ 0.9899513220F, 0.9903365446F, 0.9907109658F, 0.9910747662F,
+ 0.9914281260F, 0.9917712252F, 0.9921042433F, 0.9924273593F,
+ 0.9927407516F, 0.9930445982F, 0.9933390763F, 0.9936243626F,
+ 0.9939006331F, 0.9941680631F, 0.9944268269F, 0.9946770982F,
+ 0.9949190498F, 0.9951528537F, 0.9953786808F, 0.9955967011F,
+ 0.9958070836F, 0.9960099963F, 0.9962056061F, 0.9963940787F,
+ 0.9965755786F, 0.9967502693F, 0.9969183129F, 0.9970798704F,
+ 0.9972351013F, 0.9973841640F, 0.9975272151F, 0.9976644103F,
+ 0.9977959036F, 0.9979218476F, 0.9980423932F, 0.9981576901F,
+ 0.9982678862F, 0.9983731278F, 0.9984735596F, 0.9985693247F,
+ 0.9986605645F, 0.9987474186F, 0.9988300248F, 0.9989085193F,
+ 0.9989830364F, 0.9990537085F, 0.9991206662F, 0.9991840382F,
+ 0.9992439513F, 0.9993005303F, 0.9993538982F, 0.9994041757F,
+ 0.9994514817F, 0.9994959330F, 0.9995376444F, 0.9995767286F,
+ 0.9996132960F, 0.9996474550F, 0.9996793121F, 0.9997089710F,
+ 0.9997365339F, 0.9997621003F, 0.9997857677F, 0.9998076311F,
+ 0.9998277836F, 0.9998463156F, 0.9998633155F, 0.9998788692F,
+ 0.9998930603F, 0.9999059701F, 0.9999176774F, 0.9999282586F,
+ 0.9999377880F, 0.9999463370F, 0.9999539749F, 0.9999607685F,
+ 0.9999667820F, 0.9999720773F, 0.9999767136F, 0.9999807479F,
+ 0.9999842344F, 0.9999872249F, 0.9999897688F, 0.9999919127F,
+ 0.9999937009F, 0.9999951749F, 0.9999963738F, 0.9999973342F,
+ 0.9999980900F, 0.9999986724F, 0.9999991103F, 0.9999994297F,
+ 0.9999996543F, 0.9999998049F, 0.9999999000F, 0.9999999552F,
+ 0.9999999836F, 0.9999999957F, 0.9999999994F, 1.0000000000F,
+};
+
+static const float vwin2048[1024] = {
+ 0.0000009241F, 0.0000083165F, 0.0000231014F, 0.0000452785F,
+ 0.0000748476F, 0.0001118085F, 0.0001561608F, 0.0002079041F,
+ 0.0002670379F, 0.0003335617F, 0.0004074748F, 0.0004887765F,
+ 0.0005774661F, 0.0006735427F, 0.0007770054F, 0.0008878533F,
+ 0.0010060853F, 0.0011317002F, 0.0012646969F, 0.0014050742F,
+ 0.0015528307F, 0.0017079650F, 0.0018704756F, 0.0020403610F,
+ 0.0022176196F, 0.0024022497F, 0.0025942495F, 0.0027936173F,
+ 0.0030003511F, 0.0032144490F, 0.0034359088F, 0.0036647286F,
+ 0.0039009061F, 0.0041444391F, 0.0043953253F, 0.0046535621F,
+ 0.0049191472F, 0.0051920781F, 0.0054723520F, 0.0057599664F,
+ 0.0060549184F, 0.0063572052F, 0.0066668239F, 0.0069837715F,
+ 0.0073080449F, 0.0076396410F, 0.0079785566F, 0.0083247884F,
+ 0.0086783330F, 0.0090391871F, 0.0094073470F, 0.0097828092F,
+ 0.0101655700F, 0.0105556258F, 0.0109529726F, 0.0113576065F,
+ 0.0117695237F, 0.0121887200F, 0.0126151913F, 0.0130489335F,
+ 0.0134899422F, 0.0139382130F, 0.0143937415F, 0.0148565233F,
+ 0.0153265536F, 0.0158038279F, 0.0162883413F, 0.0167800889F,
+ 0.0172790660F, 0.0177852675F, 0.0182986882F, 0.0188193231F,
+ 0.0193471668F, 0.0198822141F, 0.0204244594F, 0.0209738974F,
+ 0.0215305225F, 0.0220943289F, 0.0226653109F, 0.0232434627F,
+ 0.0238287784F, 0.0244212519F, 0.0250208772F, 0.0256276481F,
+ 0.0262415582F, 0.0268626014F, 0.0274907711F, 0.0281260608F,
+ 0.0287684638F, 0.0294179736F, 0.0300745833F, 0.0307382859F,
+ 0.0314090747F, 0.0320869424F, 0.0327718819F, 0.0334638860F,
+ 0.0341629474F, 0.0348690586F, 0.0355822122F, 0.0363024004F,
+ 0.0370296157F, 0.0377638502F, 0.0385050960F, 0.0392533451F,
+ 0.0400085896F, 0.0407708211F, 0.0415400315F, 0.0423162123F,
+ 0.0430993552F, 0.0438894515F, 0.0446864926F, 0.0454904698F,
+ 0.0463013742F, 0.0471191969F, 0.0479439288F, 0.0487755607F,
+ 0.0496140836F, 0.0504594879F, 0.0513117642F, 0.0521709031F,
+ 0.0530368949F, 0.0539097297F, 0.0547893979F, 0.0556758894F,
+ 0.0565691941F, 0.0574693019F, 0.0583762026F, 0.0592898858F,
+ 0.0602103410F, 0.0611375576F, 0.0620715250F, 0.0630122324F,
+ 0.0639596688F, 0.0649138234F, 0.0658746848F, 0.0668422421F,
+ 0.0678164838F, 0.0687973985F, 0.0697849746F, 0.0707792005F,
+ 0.0717800645F, 0.0727875547F, 0.0738016591F, 0.0748223656F,
+ 0.0758496620F, 0.0768835359F, 0.0779239751F, 0.0789709668F,
+ 0.0800244985F, 0.0810845574F, 0.0821511306F, 0.0832242052F,
+ 0.0843037679F, 0.0853898056F, 0.0864823050F, 0.0875812525F,
+ 0.0886866347F, 0.0897984378F, 0.0909166480F, 0.0920412513F,
+ 0.0931722338F, 0.0943095813F, 0.0954532795F, 0.0966033140F,
+ 0.0977596702F, 0.0989223336F, 0.1000912894F, 0.1012665227F,
+ 0.1024480185F, 0.1036357616F, 0.1048297369F, 0.1060299290F,
+ 0.1072363224F, 0.1084489014F, 0.1096676504F, 0.1108925534F,
+ 0.1121235946F, 0.1133607577F, 0.1146040267F, 0.1158533850F,
+ 0.1171088163F, 0.1183703040F, 0.1196378312F, 0.1209113812F,
+ 0.1221909370F, 0.1234764815F, 0.1247679974F, 0.1260654674F,
+ 0.1273688740F, 0.1286781995F, 0.1299934263F, 0.1313145365F,
+ 0.1326415121F, 0.1339743349F, 0.1353129866F, 0.1366574490F,
+ 0.1380077035F, 0.1393637315F, 0.1407255141F, 0.1420930325F,
+ 0.1434662677F, 0.1448452004F, 0.1462298115F, 0.1476200814F,
+ 0.1490159906F, 0.1504175195F, 0.1518246482F, 0.1532373569F,
+ 0.1546556253F, 0.1560794333F, 0.1575087606F, 0.1589435866F,
+ 0.1603838909F, 0.1618296526F, 0.1632808509F, 0.1647374648F,
+ 0.1661994731F, 0.1676668546F, 0.1691395880F, 0.1706176516F,
+ 0.1721010238F, 0.1735896829F, 0.1750836068F, 0.1765827736F,
+ 0.1780871610F, 0.1795967468F, 0.1811115084F, 0.1826314234F,
+ 0.1841564689F, 0.1856866221F, 0.1872218600F, 0.1887621595F,
+ 0.1903074974F, 0.1918578503F, 0.1934131947F, 0.1949735068F,
+ 0.1965387630F, 0.1981089393F, 0.1996840117F, 0.2012639560F,
+ 0.2028487479F, 0.2044383630F, 0.2060327766F, 0.2076319642F,
+ 0.2092359007F, 0.2108445614F, 0.2124579211F, 0.2140759545F,
+ 0.2156986364F, 0.2173259411F, 0.2189578432F, 0.2205943168F,
+ 0.2222353361F, 0.2238808751F, 0.2255309076F, 0.2271854073F,
+ 0.2288443480F, 0.2305077030F, 0.2321754457F, 0.2338475493F,
+ 0.2355239869F, 0.2372047315F, 0.2388897560F, 0.2405790329F,
+ 0.2422725350F, 0.2439702347F, 0.2456721043F, 0.2473781159F,
+ 0.2490882418F, 0.2508024539F, 0.2525207240F, 0.2542430237F,
+ 0.2559693248F, 0.2576995986F, 0.2594338166F, 0.2611719498F,
+ 0.2629139695F, 0.2646598466F, 0.2664095520F, 0.2681630564F,
+ 0.2699203304F, 0.2716813445F, 0.2734460691F, 0.2752144744F,
+ 0.2769865307F, 0.2787622079F, 0.2805414760F, 0.2823243047F,
+ 0.2841106637F, 0.2859005227F, 0.2876938509F, 0.2894906179F,
+ 0.2912907928F, 0.2930943447F, 0.2949012426F, 0.2967114554F,
+ 0.2985249520F, 0.3003417009F, 0.3021616708F, 0.3039848301F,
+ 0.3058111471F, 0.3076405901F, 0.3094731273F, 0.3113087266F,
+ 0.3131473560F, 0.3149889833F, 0.3168335762F, 0.3186811024F,
+ 0.3205315294F, 0.3223848245F, 0.3242409552F, 0.3260998886F,
+ 0.3279615918F, 0.3298260319F, 0.3316931758F, 0.3335629903F,
+ 0.3354354423F, 0.3373104982F, 0.3391881247F, 0.3410682882F,
+ 0.3429509551F, 0.3448360917F, 0.3467236642F, 0.3486136387F,
+ 0.3505059811F, 0.3524006575F, 0.3542976336F, 0.3561968753F,
+ 0.3580983482F, 0.3600020179F, 0.3619078499F, 0.3638158096F,
+ 0.3657258625F, 0.3676379737F, 0.3695521086F, 0.3714682321F,
+ 0.3733863094F, 0.3753063055F, 0.3772281852F, 0.3791519134F,
+ 0.3810774548F, 0.3830047742F, 0.3849338362F, 0.3868646053F,
+ 0.3887970459F, 0.3907311227F, 0.3926667998F, 0.3946040417F,
+ 0.3965428125F, 0.3984830765F, 0.4004247978F, 0.4023679403F,
+ 0.4043124683F, 0.4062583455F, 0.4082055359F, 0.4101540034F,
+ 0.4121037117F, 0.4140546246F, 0.4160067058F, 0.4179599190F,
+ 0.4199142277F, 0.4218695956F, 0.4238259861F, 0.4257833627F,
+ 0.4277416888F, 0.4297009279F, 0.4316610433F, 0.4336219983F,
+ 0.4355837562F, 0.4375462803F, 0.4395095337F, 0.4414734797F,
+ 0.4434380815F, 0.4454033021F, 0.4473691046F, 0.4493354521F,
+ 0.4513023078F, 0.4532696345F, 0.4552373954F, 0.4572055533F,
+ 0.4591740713F, 0.4611429123F, 0.4631120393F, 0.4650814151F,
+ 0.4670510028F, 0.4690207650F, 0.4709906649F, 0.4729606651F,
+ 0.4749307287F, 0.4769008185F, 0.4788708972F, 0.4808409279F,
+ 0.4828108732F, 0.4847806962F, 0.4867503597F, 0.4887198264F,
+ 0.4906890593F, 0.4926580213F, 0.4946266753F, 0.4965949840F,
+ 0.4985629105F, 0.5005304176F, 0.5024974683F, 0.5044640255F,
+ 0.5064300522F, 0.5083955114F, 0.5103603659F, 0.5123245790F,
+ 0.5142881136F, 0.5162509328F, 0.5182129997F, 0.5201742774F,
+ 0.5221347290F, 0.5240943178F, 0.5260530070F, 0.5280107598F,
+ 0.5299675395F, 0.5319233095F, 0.5338780330F, 0.5358316736F,
+ 0.5377841946F, 0.5397355596F, 0.5416857320F, 0.5436346755F,
+ 0.5455823538F, 0.5475287304F, 0.5494737691F, 0.5514174337F,
+ 0.5533596881F, 0.5553004962F, 0.5572398218F, 0.5591776291F,
+ 0.5611138821F, 0.5630485449F, 0.5649815818F, 0.5669129570F,
+ 0.5688426349F, 0.5707705799F, 0.5726967564F, 0.5746211290F,
+ 0.5765436624F, 0.5784643212F, 0.5803830702F, 0.5822998743F,
+ 0.5842146984F, 0.5861275076F, 0.5880382669F, 0.5899469416F,
+ 0.5918534968F, 0.5937578981F, 0.5956601107F, 0.5975601004F,
+ 0.5994578326F, 0.6013532732F, 0.6032463880F, 0.6051371429F,
+ 0.6070255039F, 0.6089114372F, 0.6107949090F, 0.6126758856F,
+ 0.6145543334F, 0.6164302191F, 0.6183035092F, 0.6201741706F,
+ 0.6220421700F, 0.6239074745F, 0.6257700513F, 0.6276298674F,
+ 0.6294868903F, 0.6313410873F, 0.6331924262F, 0.6350408745F,
+ 0.6368864001F, 0.6387289710F, 0.6405685552F, 0.6424051209F,
+ 0.6442386364F, 0.6460690702F, 0.6478963910F, 0.6497205673F,
+ 0.6515415682F, 0.6533593625F, 0.6551739194F, 0.6569852082F,
+ 0.6587931984F, 0.6605978593F, 0.6623991609F, 0.6641970728F,
+ 0.6659915652F, 0.6677826081F, 0.6695701718F, 0.6713542268F,
+ 0.6731347437F, 0.6749116932F, 0.6766850461F, 0.6784547736F,
+ 0.6802208469F, 0.6819832374F, 0.6837419164F, 0.6854968559F,
+ 0.6872480275F, 0.6889954034F, 0.6907389556F, 0.6924786566F,
+ 0.6942144788F, 0.6959463950F, 0.6976743780F, 0.6993984008F,
+ 0.7011184365F, 0.7028344587F, 0.7045464407F, 0.7062543564F,
+ 0.7079581796F, 0.7096578844F, 0.7113534450F, 0.7130448359F,
+ 0.7147320316F, 0.7164150070F, 0.7180937371F, 0.7197681970F,
+ 0.7214383620F, 0.7231042077F, 0.7247657098F, 0.7264228443F,
+ 0.7280755871F, 0.7297239147F, 0.7313678035F, 0.7330072301F,
+ 0.7346421715F, 0.7362726046F, 0.7378985069F, 0.7395198556F,
+ 0.7411366285F, 0.7427488034F, 0.7443563584F, 0.7459592717F,
+ 0.7475575218F, 0.7491510873F, 0.7507399471F, 0.7523240803F,
+ 0.7539034661F, 0.7554780839F, 0.7570479136F, 0.7586129349F,
+ 0.7601731279F, 0.7617284730F, 0.7632789506F, 0.7648245416F,
+ 0.7663652267F, 0.7679009872F, 0.7694318044F, 0.7709576599F,
+ 0.7724785354F, 0.7739944130F, 0.7755052749F, 0.7770111035F,
+ 0.7785118815F, 0.7800075916F, 0.7814982170F, 0.7829837410F,
+ 0.7844641472F, 0.7859394191F, 0.7874095408F, 0.7888744965F,
+ 0.7903342706F, 0.7917888476F, 0.7932382124F, 0.7946823501F,
+ 0.7961212460F, 0.7975548855F, 0.7989832544F, 0.8004063386F,
+ 0.8018241244F, 0.8032365981F, 0.8046437463F, 0.8060455560F,
+ 0.8074420141F, 0.8088331080F, 0.8102188253F, 0.8115991536F,
+ 0.8129740810F, 0.8143435957F, 0.8157076861F, 0.8170663409F,
+ 0.8184195489F, 0.8197672994F, 0.8211095817F, 0.8224463853F,
+ 0.8237777001F, 0.8251035161F, 0.8264238235F, 0.8277386129F,
+ 0.8290478750F, 0.8303516008F, 0.8316497814F, 0.8329424083F,
+ 0.8342294731F, 0.8355109677F, 0.8367868841F, 0.8380572148F,
+ 0.8393219523F, 0.8405810893F, 0.8418346190F, 0.8430825345F,
+ 0.8443248294F, 0.8455614974F, 0.8467925323F, 0.8480179285F,
+ 0.8492376802F, 0.8504517822F, 0.8516602292F, 0.8528630164F,
+ 0.8540601391F, 0.8552515928F, 0.8564373733F, 0.8576174766F,
+ 0.8587918990F, 0.8599606368F, 0.8611236868F, 0.8622810460F,
+ 0.8634327113F, 0.8645786802F, 0.8657189504F, 0.8668535195F,
+ 0.8679823857F, 0.8691055472F, 0.8702230025F, 0.8713347503F,
+ 0.8724407896F, 0.8735411194F, 0.8746357394F, 0.8757246489F,
+ 0.8768078479F, 0.8778853364F, 0.8789571146F, 0.8800231832F,
+ 0.8810835427F, 0.8821381942F, 0.8831871387F, 0.8842303777F,
+ 0.8852679127F, 0.8862997456F, 0.8873258784F, 0.8883463132F,
+ 0.8893610527F, 0.8903700994F, 0.8913734562F, 0.8923711263F,
+ 0.8933631129F, 0.8943494196F, 0.8953300500F, 0.8963050083F,
+ 0.8972742985F, 0.8982379249F, 0.8991958922F, 0.9001482052F,
+ 0.9010948688F, 0.9020358883F, 0.9029712690F, 0.9039010165F,
+ 0.9048251367F, 0.9057436357F, 0.9066565195F, 0.9075637946F,
+ 0.9084654678F, 0.9093615456F, 0.9102520353F, 0.9111369440F,
+ 0.9120162792F, 0.9128900484F, 0.9137582595F, 0.9146209204F,
+ 0.9154780394F, 0.9163296248F, 0.9171756853F, 0.9180162296F,
+ 0.9188512667F, 0.9196808057F, 0.9205048559F, 0.9213234270F,
+ 0.9221365285F, 0.9229441704F, 0.9237463629F, 0.9245431160F,
+ 0.9253344404F, 0.9261203465F, 0.9269008453F, 0.9276759477F,
+ 0.9284456648F, 0.9292100080F, 0.9299689889F, 0.9307226190F,
+ 0.9314709103F, 0.9322138747F, 0.9329515245F, 0.9336838721F,
+ 0.9344109300F, 0.9351327108F, 0.9358492275F, 0.9365604931F,
+ 0.9372665208F, 0.9379673239F, 0.9386629160F, 0.9393533107F,
+ 0.9400385220F, 0.9407185637F, 0.9413934501F, 0.9420631954F,
+ 0.9427278141F, 0.9433873208F, 0.9440417304F, 0.9446910576F,
+ 0.9453353176F, 0.9459745255F, 0.9466086968F, 0.9472378469F,
+ 0.9478619915F, 0.9484811463F, 0.9490953274F, 0.9497045506F,
+ 0.9503088323F, 0.9509081888F, 0.9515026365F, 0.9520921921F,
+ 0.9526768723F, 0.9532566940F, 0.9538316742F, 0.9544018300F,
+ 0.9549671786F, 0.9555277375F, 0.9560835241F, 0.9566345562F,
+ 0.9571808513F, 0.9577224275F, 0.9582593027F, 0.9587914949F,
+ 0.9593190225F, 0.9598419038F, 0.9603601571F, 0.9608738012F,
+ 0.9613828546F, 0.9618873361F, 0.9623872646F, 0.9628826591F,
+ 0.9633735388F, 0.9638599227F, 0.9643418303F, 0.9648192808F,
+ 0.9652922939F, 0.9657608890F, 0.9662250860F, 0.9666849046F,
+ 0.9671403646F, 0.9675914861F, 0.9680382891F, 0.9684807937F,
+ 0.9689190202F, 0.9693529890F, 0.9697827203F, 0.9702082347F,
+ 0.9706295529F, 0.9710466953F, 0.9714596828F, 0.9718685362F,
+ 0.9722732762F, 0.9726739240F, 0.9730705005F, 0.9734630267F,
+ 0.9738515239F, 0.9742360134F, 0.9746165163F, 0.9749930540F,
+ 0.9753656481F, 0.9757343198F, 0.9760990909F, 0.9764599829F,
+ 0.9768170175F, 0.9771702164F, 0.9775196013F, 0.9778651941F,
+ 0.9782070167F, 0.9785450909F, 0.9788794388F, 0.9792100824F,
+ 0.9795370437F, 0.9798603449F, 0.9801800080F, 0.9804960554F,
+ 0.9808085092F, 0.9811173916F, 0.9814227251F, 0.9817245318F,
+ 0.9820228343F, 0.9823176549F, 0.9826090160F, 0.9828969402F,
+ 0.9831814498F, 0.9834625674F, 0.9837403156F, 0.9840147169F,
+ 0.9842857939F, 0.9845535692F, 0.9848180654F, 0.9850793052F,
+ 0.9853373113F, 0.9855921062F, 0.9858437127F, 0.9860921535F,
+ 0.9863374512F, 0.9865796287F, 0.9868187085F, 0.9870547136F,
+ 0.9872876664F, 0.9875175899F, 0.9877445067F, 0.9879684396F,
+ 0.9881894112F, 0.9884074444F, 0.9886225619F, 0.9888347863F,
+ 0.9890441404F, 0.9892506468F, 0.9894543284F, 0.9896552077F,
+ 0.9898533074F, 0.9900486502F, 0.9902412587F, 0.9904311555F,
+ 0.9906183633F, 0.9908029045F, 0.9909848019F, 0.9911640779F,
+ 0.9913407550F, 0.9915148557F, 0.9916864025F, 0.9918554179F,
+ 0.9920219241F, 0.9921859437F, 0.9923474989F, 0.9925066120F,
+ 0.9926633054F, 0.9928176012F, 0.9929695218F, 0.9931190891F,
+ 0.9932663254F, 0.9934112527F, 0.9935538932F, 0.9936942686F,
+ 0.9938324012F, 0.9939683126F, 0.9941020248F, 0.9942335597F,
+ 0.9943629388F, 0.9944901841F, 0.9946153170F, 0.9947383593F,
+ 0.9948593325F, 0.9949782579F, 0.9950951572F, 0.9952100516F,
+ 0.9953229625F, 0.9954339111F, 0.9955429186F, 0.9956500062F,
+ 0.9957551948F, 0.9958585056F, 0.9959599593F, 0.9960595769F,
+ 0.9961573792F, 0.9962533869F, 0.9963476206F, 0.9964401009F,
+ 0.9965308483F, 0.9966198833F, 0.9967072261F, 0.9967928971F,
+ 0.9968769164F, 0.9969593041F, 0.9970400804F, 0.9971192651F,
+ 0.9971968781F, 0.9972729391F, 0.9973474680F, 0.9974204842F,
+ 0.9974920074F, 0.9975620569F, 0.9976306521F, 0.9976978122F,
+ 0.9977635565F, 0.9978279039F, 0.9978908736F, 0.9979524842F,
+ 0.9980127547F, 0.9980717037F, 0.9981293499F, 0.9981857116F,
+ 0.9982408073F, 0.9982946554F, 0.9983472739F, 0.9983986810F,
+ 0.9984488947F, 0.9984979328F, 0.9985458132F, 0.9985925534F,
+ 0.9986381711F, 0.9986826838F, 0.9987261086F, 0.9987684630F,
+ 0.9988097640F, 0.9988500286F, 0.9988892738F, 0.9989275163F,
+ 0.9989647727F, 0.9990010597F, 0.9990363938F, 0.9990707911F,
+ 0.9991042679F, 0.9991368404F, 0.9991685244F, 0.9991993358F,
+ 0.9992292905F, 0.9992584038F, 0.9992866914F, 0.9993141686F,
+ 0.9993408506F, 0.9993667526F, 0.9993918895F, 0.9994162761F,
+ 0.9994399273F, 0.9994628576F, 0.9994850815F, 0.9995066133F,
+ 0.9995274672F, 0.9995476574F, 0.9995671978F, 0.9995861021F,
+ 0.9996043841F, 0.9996220573F, 0.9996391352F, 0.9996556310F,
+ 0.9996715579F, 0.9996869288F, 0.9997017568F, 0.9997160543F,
+ 0.9997298342F, 0.9997431088F, 0.9997558905F, 0.9997681914F,
+ 0.9997800236F, 0.9997913990F, 0.9998023292F, 0.9998128261F,
+ 0.9998229009F, 0.9998325650F, 0.9998418296F, 0.9998507058F,
+ 0.9998592044F, 0.9998673362F, 0.9998751117F, 0.9998825415F,
+ 0.9998896358F, 0.9998964047F, 0.9999028584F, 0.9999090066F,
+ 0.9999148590F, 0.9999204253F, 0.9999257148F, 0.9999307368F,
+ 0.9999355003F, 0.9999400144F, 0.9999442878F, 0.9999483293F,
+ 0.9999521472F, 0.9999557499F, 0.9999591457F, 0.9999623426F,
+ 0.9999653483F, 0.9999681708F, 0.9999708175F, 0.9999732959F,
+ 0.9999756132F, 0.9999777765F, 0.9999797928F, 0.9999816688F,
+ 0.9999834113F, 0.9999850266F, 0.9999865211F, 0.9999879009F,
+ 0.9999891721F, 0.9999903405F, 0.9999914118F, 0.9999923914F,
+ 0.9999932849F, 0.9999940972F, 0.9999948336F, 0.9999954989F,
+ 0.9999960978F, 0.9999966349F, 0.9999971146F, 0.9999975411F,
+ 0.9999979185F, 0.9999982507F, 0.9999985414F, 0.9999987944F,
+ 0.9999990129F, 0.9999992003F, 0.9999993596F, 0.9999994939F,
+ 0.9999996059F, 0.9999996981F, 0.9999997732F, 0.9999998333F,
+ 0.9999998805F, 0.9999999170F, 0.9999999444F, 0.9999999643F,
+ 0.9999999784F, 0.9999999878F, 0.9999999937F, 0.9999999972F,
+ 0.9999999990F, 0.9999999997F, 1.0000000000F, 1.0000000000F,
+};
+
+static const float vwin4096[2048] = {
+ 0.0000002310F, 0.0000020791F, 0.0000057754F, 0.0000113197F,
+ 0.0000187121F, 0.0000279526F, 0.0000390412F, 0.0000519777F,
+ 0.0000667623F, 0.0000833949F, 0.0001018753F, 0.0001222036F,
+ 0.0001443798F, 0.0001684037F, 0.0001942754F, 0.0002219947F,
+ 0.0002515616F, 0.0002829761F, 0.0003162380F, 0.0003513472F,
+ 0.0003883038F, 0.0004271076F, 0.0004677584F, 0.0005102563F,
+ 0.0005546011F, 0.0006007928F, 0.0006488311F, 0.0006987160F,
+ 0.0007504474F, 0.0008040251F, 0.0008594490F, 0.0009167191F,
+ 0.0009758351F, 0.0010367969F, 0.0010996044F, 0.0011642574F,
+ 0.0012307558F, 0.0012990994F, 0.0013692880F, 0.0014413216F,
+ 0.0015151998F, 0.0015909226F, 0.0016684898F, 0.0017479011F,
+ 0.0018291565F, 0.0019122556F, 0.0019971983F, 0.0020839845F,
+ 0.0021726138F, 0.0022630861F, 0.0023554012F, 0.0024495588F,
+ 0.0025455588F, 0.0026434008F, 0.0027430847F, 0.0028446103F,
+ 0.0029479772F, 0.0030531853F, 0.0031602342F, 0.0032691238F,
+ 0.0033798538F, 0.0034924239F, 0.0036068338F, 0.0037230833F,
+ 0.0038411721F, 0.0039610999F, 0.0040828664F, 0.0042064714F,
+ 0.0043319145F, 0.0044591954F, 0.0045883139F, 0.0047192696F,
+ 0.0048520622F, 0.0049866914F, 0.0051231569F, 0.0052614583F,
+ 0.0054015953F, 0.0055435676F, 0.0056873748F, 0.0058330166F,
+ 0.0059804926F, 0.0061298026F, 0.0062809460F, 0.0064339226F,
+ 0.0065887320F, 0.0067453738F, 0.0069038476F, 0.0070641531F,
+ 0.0072262899F, 0.0073902575F, 0.0075560556F, 0.0077236838F,
+ 0.0078931417F, 0.0080644288F, 0.0082375447F, 0.0084124891F,
+ 0.0085892615F, 0.0087678614F, 0.0089482885F, 0.0091305422F,
+ 0.0093146223F, 0.0095005281F, 0.0096882592F, 0.0098778153F,
+ 0.0100691958F, 0.0102624002F, 0.0104574281F, 0.0106542791F,
+ 0.0108529525F, 0.0110534480F, 0.0112557651F, 0.0114599032F,
+ 0.0116658618F, 0.0118736405F, 0.0120832387F, 0.0122946560F,
+ 0.0125078917F, 0.0127229454F, 0.0129398166F, 0.0131585046F,
+ 0.0133790090F, 0.0136013292F, 0.0138254647F, 0.0140514149F,
+ 0.0142791792F, 0.0145087572F, 0.0147401481F, 0.0149733515F,
+ 0.0152083667F, 0.0154451932F, 0.0156838304F, 0.0159242777F,
+ 0.0161665345F, 0.0164106001F, 0.0166564741F, 0.0169041557F,
+ 0.0171536443F, 0.0174049393F, 0.0176580401F, 0.0179129461F,
+ 0.0181696565F, 0.0184281708F, 0.0186884883F, 0.0189506084F,
+ 0.0192145303F, 0.0194802535F, 0.0197477772F, 0.0200171008F,
+ 0.0202882236F, 0.0205611449F, 0.0208358639F, 0.0211123801F,
+ 0.0213906927F, 0.0216708011F, 0.0219527043F, 0.0222364019F,
+ 0.0225218930F, 0.0228091769F, 0.0230982529F, 0.0233891203F,
+ 0.0236817782F, 0.0239762259F, 0.0242724628F, 0.0245704880F,
+ 0.0248703007F, 0.0251719002F, 0.0254752858F, 0.0257804565F,
+ 0.0260874117F, 0.0263961506F, 0.0267066722F, 0.0270189760F,
+ 0.0273330609F, 0.0276489263F, 0.0279665712F, 0.0282859949F,
+ 0.0286071966F, 0.0289301753F, 0.0292549303F, 0.0295814607F,
+ 0.0299097656F, 0.0302398442F, 0.0305716957F, 0.0309053191F,
+ 0.0312407135F, 0.0315778782F, 0.0319168122F, 0.0322575145F,
+ 0.0325999844F, 0.0329442209F, 0.0332902231F, 0.0336379900F,
+ 0.0339875208F, 0.0343388146F, 0.0346918703F, 0.0350466871F,
+ 0.0354032640F, 0.0357616000F, 0.0361216943F, 0.0364835458F,
+ 0.0368471535F, 0.0372125166F, 0.0375796339F, 0.0379485046F,
+ 0.0383191276F, 0.0386915020F, 0.0390656267F, 0.0394415008F,
+ 0.0398191231F, 0.0401984927F, 0.0405796086F, 0.0409624698F,
+ 0.0413470751F, 0.0417334235F, 0.0421215141F, 0.0425113457F,
+ 0.0429029172F, 0.0432962277F, 0.0436912760F, 0.0440880610F,
+ 0.0444865817F, 0.0448868370F, 0.0452888257F, 0.0456925468F,
+ 0.0460979992F, 0.0465051816F, 0.0469140931F, 0.0473247325F,
+ 0.0477370986F, 0.0481511902F, 0.0485670064F, 0.0489845458F,
+ 0.0494038074F, 0.0498247899F, 0.0502474922F, 0.0506719131F,
+ 0.0510980514F, 0.0515259060F, 0.0519554756F, 0.0523867590F,
+ 0.0528197550F, 0.0532544624F, 0.0536908800F, 0.0541290066F,
+ 0.0545688408F, 0.0550103815F, 0.0554536274F, 0.0558985772F,
+ 0.0563452297F, 0.0567935837F, 0.0572436377F, 0.0576953907F,
+ 0.0581488412F, 0.0586039880F, 0.0590608297F, 0.0595193651F,
+ 0.0599795929F, 0.0604415117F, 0.0609051202F, 0.0613704170F,
+ 0.0618374009F, 0.0623060704F, 0.0627764243F, 0.0632484611F,
+ 0.0637221795F, 0.0641975781F, 0.0646746555F, 0.0651534104F,
+ 0.0656338413F, 0.0661159469F, 0.0665997257F, 0.0670851763F,
+ 0.0675722973F, 0.0680610873F, 0.0685515448F, 0.0690436684F,
+ 0.0695374567F, 0.0700329081F, 0.0705300213F, 0.0710287947F,
+ 0.0715292269F, 0.0720313163F, 0.0725350616F, 0.0730404612F,
+ 0.0735475136F, 0.0740562172F, 0.0745665707F, 0.0750785723F,
+ 0.0755922207F, 0.0761075143F, 0.0766244515F, 0.0771430307F,
+ 0.0776632505F, 0.0781851092F, 0.0787086052F, 0.0792337371F,
+ 0.0797605032F, 0.0802889018F, 0.0808189315F, 0.0813505905F,
+ 0.0818838773F, 0.0824187903F, 0.0829553277F, 0.0834934881F,
+ 0.0840332697F, 0.0845746708F, 0.0851176899F, 0.0856623252F,
+ 0.0862085751F, 0.0867564379F, 0.0873059119F, 0.0878569954F,
+ 0.0884096867F, 0.0889639840F, 0.0895198858F, 0.0900773902F,
+ 0.0906364955F, 0.0911972000F, 0.0917595019F, 0.0923233995F,
+ 0.0928888909F, 0.0934559745F, 0.0940246485F, 0.0945949110F,
+ 0.0951667604F, 0.0957401946F, 0.0963152121F, 0.0968918109F,
+ 0.0974699893F, 0.0980497454F, 0.0986310773F, 0.0992139832F,
+ 0.0997984614F, 0.1003845098F, 0.1009721267F, 0.1015613101F,
+ 0.1021520582F, 0.1027443692F, 0.1033382410F, 0.1039336718F,
+ 0.1045306597F, 0.1051292027F, 0.1057292990F, 0.1063309466F,
+ 0.1069341435F, 0.1075388878F, 0.1081451776F, 0.1087530108F,
+ 0.1093623856F, 0.1099732998F, 0.1105857516F, 0.1111997389F,
+ 0.1118152597F, 0.1124323121F, 0.1130508939F, 0.1136710032F,
+ 0.1142926379F, 0.1149157960F, 0.1155404755F, 0.1161666742F,
+ 0.1167943901F, 0.1174236211F, 0.1180543652F, 0.1186866202F,
+ 0.1193203841F, 0.1199556548F, 0.1205924300F, 0.1212307078F,
+ 0.1218704860F, 0.1225117624F, 0.1231545349F, 0.1237988013F,
+ 0.1244445596F, 0.1250918074F, 0.1257405427F, 0.1263907632F,
+ 0.1270424667F, 0.1276956512F, 0.1283503142F, 0.1290064537F,
+ 0.1296640674F, 0.1303231530F, 0.1309837084F, 0.1316457312F,
+ 0.1323092193F, 0.1329741703F, 0.1336405820F, 0.1343084520F,
+ 0.1349777782F, 0.1356485582F, 0.1363207897F, 0.1369944704F,
+ 0.1376695979F, 0.1383461700F, 0.1390241842F, 0.1397036384F,
+ 0.1403845300F, 0.1410668567F, 0.1417506162F, 0.1424358061F,
+ 0.1431224240F, 0.1438104674F, 0.1444999341F, 0.1451908216F,
+ 0.1458831274F, 0.1465768492F, 0.1472719844F, 0.1479685308F,
+ 0.1486664857F, 0.1493658468F, 0.1500666115F, 0.1507687775F,
+ 0.1514723422F, 0.1521773031F, 0.1528836577F, 0.1535914035F,
+ 0.1543005380F, 0.1550110587F, 0.1557229631F, 0.1564362485F,
+ 0.1571509124F, 0.1578669524F, 0.1585843657F, 0.1593031499F,
+ 0.1600233024F, 0.1607448205F, 0.1614677017F, 0.1621919433F,
+ 0.1629175428F, 0.1636444975F, 0.1643728047F, 0.1651024619F,
+ 0.1658334665F, 0.1665658156F, 0.1672995067F, 0.1680345371F,
+ 0.1687709041F, 0.1695086050F, 0.1702476372F, 0.1709879978F,
+ 0.1717296843F, 0.1724726938F, 0.1732170237F, 0.1739626711F,
+ 0.1747096335F, 0.1754579079F, 0.1762074916F, 0.1769583819F,
+ 0.1777105760F, 0.1784640710F, 0.1792188642F, 0.1799749529F,
+ 0.1807323340F, 0.1814910049F, 0.1822509628F, 0.1830122046F,
+ 0.1837747277F, 0.1845385292F, 0.1853036062F, 0.1860699558F,
+ 0.1868375751F, 0.1876064613F, 0.1883766114F, 0.1891480226F,
+ 0.1899206919F, 0.1906946164F, 0.1914697932F, 0.1922462194F,
+ 0.1930238919F, 0.1938028079F, 0.1945829643F, 0.1953643583F,
+ 0.1961469868F, 0.1969308468F, 0.1977159353F, 0.1985022494F,
+ 0.1992897859F, 0.2000785420F, 0.2008685145F, 0.2016597005F,
+ 0.2024520968F, 0.2032457005F, 0.2040405084F, 0.2048365175F,
+ 0.2056337247F, 0.2064321269F, 0.2072317211F, 0.2080325041F,
+ 0.2088344727F, 0.2096376240F, 0.2104419547F, 0.2112474618F,
+ 0.2120541420F, 0.2128619923F, 0.2136710094F, 0.2144811902F,
+ 0.2152925315F, 0.2161050301F, 0.2169186829F, 0.2177334866F,
+ 0.2185494381F, 0.2193665340F, 0.2201847712F, 0.2210041465F,
+ 0.2218246565F, 0.2226462981F, 0.2234690680F, 0.2242929629F,
+ 0.2251179796F, 0.2259441147F, 0.2267713650F, 0.2275997272F,
+ 0.2284291979F, 0.2292597739F, 0.2300914518F, 0.2309242283F,
+ 0.2317581001F, 0.2325930638F, 0.2334291160F, 0.2342662534F,
+ 0.2351044727F, 0.2359437703F, 0.2367841431F, 0.2376255875F,
+ 0.2384681001F, 0.2393116776F, 0.2401563165F, 0.2410020134F,
+ 0.2418487649F, 0.2426965675F, 0.2435454178F, 0.2443953122F,
+ 0.2452462474F, 0.2460982199F, 0.2469512262F, 0.2478052628F,
+ 0.2486603262F, 0.2495164129F, 0.2503735194F, 0.2512316421F,
+ 0.2520907776F, 0.2529509222F, 0.2538120726F, 0.2546742250F,
+ 0.2555373760F, 0.2564015219F, 0.2572666593F, 0.2581327845F,
+ 0.2589998939F, 0.2598679840F, 0.2607370510F, 0.2616070916F,
+ 0.2624781019F, 0.2633500783F, 0.2642230173F, 0.2650969152F,
+ 0.2659717684F, 0.2668475731F, 0.2677243257F, 0.2686020226F,
+ 0.2694806601F, 0.2703602344F, 0.2712407419F, 0.2721221789F,
+ 0.2730045417F, 0.2738878265F, 0.2747720297F, 0.2756571474F,
+ 0.2765431760F, 0.2774301117F, 0.2783179508F, 0.2792066895F,
+ 0.2800963240F, 0.2809868505F, 0.2818782654F, 0.2827705647F,
+ 0.2836637447F, 0.2845578016F, 0.2854527315F, 0.2863485307F,
+ 0.2872451953F, 0.2881427215F, 0.2890411055F, 0.2899403433F,
+ 0.2908404312F, 0.2917413654F, 0.2926431418F, 0.2935457567F,
+ 0.2944492061F, 0.2953534863F, 0.2962585932F, 0.2971645230F,
+ 0.2980712717F, 0.2989788356F, 0.2998872105F, 0.3007963927F,
+ 0.3017063781F, 0.3026171629F, 0.3035287430F, 0.3044411145F,
+ 0.3053542736F, 0.3062682161F, 0.3071829381F, 0.3080984356F,
+ 0.3090147047F, 0.3099317413F, 0.3108495414F, 0.3117681011F,
+ 0.3126874163F, 0.3136074830F, 0.3145282972F, 0.3154498548F,
+ 0.3163721517F, 0.3172951841F, 0.3182189477F, 0.3191434385F,
+ 0.3200686525F, 0.3209945856F, 0.3219212336F, 0.3228485927F,
+ 0.3237766585F, 0.3247054271F, 0.3256348943F, 0.3265650560F,
+ 0.3274959081F, 0.3284274465F, 0.3293596671F, 0.3302925657F,
+ 0.3312261382F, 0.3321603804F, 0.3330952882F, 0.3340308574F,
+ 0.3349670838F, 0.3359039634F, 0.3368414919F, 0.3377796651F,
+ 0.3387184789F, 0.3396579290F, 0.3405980113F, 0.3415387216F,
+ 0.3424800556F, 0.3434220091F, 0.3443645779F, 0.3453077578F,
+ 0.3462515446F, 0.3471959340F, 0.3481409217F, 0.3490865036F,
+ 0.3500326754F, 0.3509794328F, 0.3519267715F, 0.3528746873F,
+ 0.3538231759F, 0.3547722330F, 0.3557218544F, 0.3566720357F,
+ 0.3576227727F, 0.3585740610F, 0.3595258964F, 0.3604782745F,
+ 0.3614311910F, 0.3623846417F, 0.3633386221F, 0.3642931280F,
+ 0.3652481549F, 0.3662036987F, 0.3671597548F, 0.3681163191F,
+ 0.3690733870F, 0.3700309544F, 0.3709890167F, 0.3719475696F,
+ 0.3729066089F, 0.3738661299F, 0.3748261285F, 0.3757866002F,
+ 0.3767475406F, 0.3777089453F, 0.3786708100F, 0.3796331302F,
+ 0.3805959014F, 0.3815591194F, 0.3825227796F, 0.3834868777F,
+ 0.3844514093F, 0.3854163698F, 0.3863817549F, 0.3873475601F,
+ 0.3883137810F, 0.3892804131F, 0.3902474521F, 0.3912148933F,
+ 0.3921827325F, 0.3931509650F, 0.3941195865F, 0.3950885925F,
+ 0.3960579785F, 0.3970277400F, 0.3979978725F, 0.3989683716F,
+ 0.3999392328F, 0.4009104516F, 0.4018820234F, 0.4028539438F,
+ 0.4038262084F, 0.4047988125F, 0.4057717516F, 0.4067450214F,
+ 0.4077186172F, 0.4086925345F, 0.4096667688F, 0.4106413155F,
+ 0.4116161703F, 0.4125913284F, 0.4135667854F, 0.4145425368F,
+ 0.4155185780F, 0.4164949044F, 0.4174715116F, 0.4184483949F,
+ 0.4194255498F, 0.4204029718F, 0.4213806563F, 0.4223585987F,
+ 0.4233367946F, 0.4243152392F, 0.4252939281F, 0.4262728566F,
+ 0.4272520202F, 0.4282314144F, 0.4292110345F, 0.4301908760F,
+ 0.4311709343F, 0.4321512047F, 0.4331316828F, 0.4341123639F,
+ 0.4350932435F, 0.4360743168F, 0.4370555794F, 0.4380370267F,
+ 0.4390186540F, 0.4400004567F, 0.4409824303F, 0.4419645701F,
+ 0.4429468716F, 0.4439293300F, 0.4449119409F, 0.4458946996F,
+ 0.4468776014F, 0.4478606418F, 0.4488438162F, 0.4498271199F,
+ 0.4508105483F, 0.4517940967F, 0.4527777607F, 0.4537615355F,
+ 0.4547454165F, 0.4557293991F, 0.4567134786F, 0.4576976505F,
+ 0.4586819101F, 0.4596662527F, 0.4606506738F, 0.4616351687F,
+ 0.4626197328F, 0.4636043614F, 0.4645890499F, 0.4655737936F,
+ 0.4665585880F, 0.4675434284F, 0.4685283101F, 0.4695132286F,
+ 0.4704981791F, 0.4714831570F, 0.4724681577F, 0.4734531766F,
+ 0.4744382089F, 0.4754232501F, 0.4764082956F, 0.4773933406F,
+ 0.4783783806F, 0.4793634108F, 0.4803484267F, 0.4813334237F,
+ 0.4823183969F, 0.4833033419F, 0.4842882540F, 0.4852731285F,
+ 0.4862579608F, 0.4872427462F, 0.4882274802F, 0.4892121580F,
+ 0.4901967751F, 0.4911813267F, 0.4921658083F, 0.4931502151F,
+ 0.4941345427F, 0.4951187863F, 0.4961029412F, 0.4970870029F,
+ 0.4980709667F, 0.4990548280F, 0.5000385822F, 0.5010222245F,
+ 0.5020057505F, 0.5029891553F, 0.5039724345F, 0.5049555834F,
+ 0.5059385973F, 0.5069214716F, 0.5079042018F, 0.5088867831F,
+ 0.5098692110F, 0.5108514808F, 0.5118335879F, 0.5128155277F,
+ 0.5137972956F, 0.5147788869F, 0.5157602971F, 0.5167415215F,
+ 0.5177225555F, 0.5187033945F, 0.5196840339F, 0.5206644692F,
+ 0.5216446956F, 0.5226247086F, 0.5236045035F, 0.5245840759F,
+ 0.5255634211F, 0.5265425344F, 0.5275214114F, 0.5285000474F,
+ 0.5294784378F, 0.5304565781F, 0.5314344637F, 0.5324120899F,
+ 0.5333894522F, 0.5343665461F, 0.5353433670F, 0.5363199102F,
+ 0.5372961713F, 0.5382721457F, 0.5392478287F, 0.5402232159F,
+ 0.5411983027F, 0.5421730845F, 0.5431475569F, 0.5441217151F,
+ 0.5450955548F, 0.5460690714F, 0.5470422602F, 0.5480151169F,
+ 0.5489876368F, 0.5499598155F, 0.5509316484F, 0.5519031310F,
+ 0.5528742587F, 0.5538450271F, 0.5548154317F, 0.5557854680F,
+ 0.5567551314F, 0.5577244174F, 0.5586933216F, 0.5596618395F,
+ 0.5606299665F, 0.5615976983F, 0.5625650302F, 0.5635319580F,
+ 0.5644984770F, 0.5654645828F, 0.5664302709F, 0.5673955370F,
+ 0.5683603765F, 0.5693247850F, 0.5702887580F, 0.5712522912F,
+ 0.5722153800F, 0.5731780200F, 0.5741402069F, 0.5751019362F,
+ 0.5760632034F, 0.5770240042F, 0.5779843341F, 0.5789441889F,
+ 0.5799035639F, 0.5808624549F, 0.5818208575F, 0.5827787673F,
+ 0.5837361800F, 0.5846930910F, 0.5856494961F, 0.5866053910F,
+ 0.5875607712F, 0.5885156324F, 0.5894699703F, 0.5904237804F,
+ 0.5913770586F, 0.5923298004F, 0.5932820016F, 0.5942336578F,
+ 0.5951847646F, 0.5961353179F, 0.5970853132F, 0.5980347464F,
+ 0.5989836131F, 0.5999319090F, 0.6008796298F, 0.6018267713F,
+ 0.6027733292F, 0.6037192993F, 0.6046646773F, 0.6056094589F,
+ 0.6065536400F, 0.6074972162F, 0.6084401833F, 0.6093825372F,
+ 0.6103242736F, 0.6112653884F, 0.6122058772F, 0.6131457359F,
+ 0.6140849604F, 0.6150235464F, 0.6159614897F, 0.6168987862F,
+ 0.6178354318F, 0.6187714223F, 0.6197067535F, 0.6206414213F,
+ 0.6215754215F, 0.6225087501F, 0.6234414028F, 0.6243733757F,
+ 0.6253046646F, 0.6262352654F, 0.6271651739F, 0.6280943862F,
+ 0.6290228982F, 0.6299507057F, 0.6308778048F, 0.6318041913F,
+ 0.6327298612F, 0.6336548105F, 0.6345790352F, 0.6355025312F,
+ 0.6364252945F, 0.6373473211F, 0.6382686070F, 0.6391891483F,
+ 0.6401089409F, 0.6410279808F, 0.6419462642F, 0.6428637869F,
+ 0.6437805452F, 0.6446965350F, 0.6456117524F, 0.6465261935F,
+ 0.6474398544F, 0.6483527311F, 0.6492648197F, 0.6501761165F,
+ 0.6510866174F, 0.6519963186F, 0.6529052162F, 0.6538133064F,
+ 0.6547205854F, 0.6556270492F, 0.6565326941F, 0.6574375162F,
+ 0.6583415117F, 0.6592446769F, 0.6601470079F, 0.6610485009F,
+ 0.6619491521F, 0.6628489578F, 0.6637479143F, 0.6646460177F,
+ 0.6655432643F, 0.6664396505F, 0.6673351724F, 0.6682298264F,
+ 0.6691236087F, 0.6700165157F, 0.6709085436F, 0.6717996889F,
+ 0.6726899478F, 0.6735793167F, 0.6744677918F, 0.6753553697F,
+ 0.6762420466F, 0.6771278190F, 0.6780126832F, 0.6788966357F,
+ 0.6797796728F, 0.6806617909F, 0.6815429866F, 0.6824232562F,
+ 0.6833025961F, 0.6841810030F, 0.6850584731F, 0.6859350031F,
+ 0.6868105894F, 0.6876852284F, 0.6885589168F, 0.6894316510F,
+ 0.6903034275F, 0.6911742430F, 0.6920440939F, 0.6929129769F,
+ 0.6937808884F, 0.6946478251F, 0.6955137837F, 0.6963787606F,
+ 0.6972427525F, 0.6981057560F, 0.6989677678F, 0.6998287845F,
+ 0.7006888028F, 0.7015478194F, 0.7024058309F, 0.7032628340F,
+ 0.7041188254F, 0.7049738019F, 0.7058277601F, 0.7066806969F,
+ 0.7075326089F, 0.7083834929F, 0.7092333457F, 0.7100821640F,
+ 0.7109299447F, 0.7117766846F, 0.7126223804F, 0.7134670291F,
+ 0.7143106273F, 0.7151531721F, 0.7159946602F, 0.7168350885F,
+ 0.7176744539F, 0.7185127534F, 0.7193499837F, 0.7201861418F,
+ 0.7210212247F, 0.7218552293F, 0.7226881526F, 0.7235199914F,
+ 0.7243507428F, 0.7251804039F, 0.7260089715F, 0.7268364426F,
+ 0.7276628144F, 0.7284880839F, 0.7293122481F, 0.7301353040F,
+ 0.7309572487F, 0.7317780794F, 0.7325977930F, 0.7334163868F,
+ 0.7342338579F, 0.7350502033F, 0.7358654202F, 0.7366795059F,
+ 0.7374924573F, 0.7383042718F, 0.7391149465F, 0.7399244787F,
+ 0.7407328655F, 0.7415401041F, 0.7423461920F, 0.7431511261F,
+ 0.7439549040F, 0.7447575227F, 0.7455589797F, 0.7463592723F,
+ 0.7471583976F, 0.7479563532F, 0.7487531363F, 0.7495487443F,
+ 0.7503431745F, 0.7511364244F, 0.7519284913F, 0.7527193726F,
+ 0.7535090658F, 0.7542975683F, 0.7550848776F, 0.7558709910F,
+ 0.7566559062F, 0.7574396205F, 0.7582221314F, 0.7590034366F,
+ 0.7597835334F, 0.7605624194F, 0.7613400923F, 0.7621165495F,
+ 0.7628917886F, 0.7636658072F, 0.7644386030F, 0.7652101735F,
+ 0.7659805164F, 0.7667496292F, 0.7675175098F, 0.7682841556F,
+ 0.7690495645F, 0.7698137341F, 0.7705766622F, 0.7713383463F,
+ 0.7720987844F, 0.7728579741F, 0.7736159132F, 0.7743725994F,
+ 0.7751280306F, 0.7758822046F, 0.7766351192F, 0.7773867722F,
+ 0.7781371614F, 0.7788862848F, 0.7796341401F, 0.7803807253F,
+ 0.7811260383F, 0.7818700769F, 0.7826128392F, 0.7833543230F,
+ 0.7840945263F, 0.7848334471F, 0.7855710833F, 0.7863074330F,
+ 0.7870424941F, 0.7877762647F, 0.7885087428F, 0.7892399264F,
+ 0.7899698137F, 0.7906984026F, 0.7914256914F, 0.7921516780F,
+ 0.7928763607F, 0.7935997375F, 0.7943218065F, 0.7950425661F,
+ 0.7957620142F, 0.7964801492F, 0.7971969692F, 0.7979124724F,
+ 0.7986266570F, 0.7993395214F, 0.8000510638F, 0.8007612823F,
+ 0.8014701754F, 0.8021777413F, 0.8028839784F, 0.8035888849F,
+ 0.8042924592F, 0.8049946997F, 0.8056956048F, 0.8063951727F,
+ 0.8070934020F, 0.8077902910F, 0.8084858381F, 0.8091800419F,
+ 0.8098729007F, 0.8105644130F, 0.8112545774F, 0.8119433922F,
+ 0.8126308561F, 0.8133169676F, 0.8140017251F, 0.8146851272F,
+ 0.8153671726F, 0.8160478598F, 0.8167271874F, 0.8174051539F,
+ 0.8180817582F, 0.8187569986F, 0.8194308741F, 0.8201033831F,
+ 0.8207745244F, 0.8214442966F, 0.8221126986F, 0.8227797290F,
+ 0.8234453865F, 0.8241096700F, 0.8247725781F, 0.8254341097F,
+ 0.8260942636F, 0.8267530385F, 0.8274104334F, 0.8280664470F,
+ 0.8287210782F, 0.8293743259F, 0.8300261889F, 0.8306766662F,
+ 0.8313257566F, 0.8319734591F, 0.8326197727F, 0.8332646963F,
+ 0.8339082288F, 0.8345503692F, 0.8351911167F, 0.8358304700F,
+ 0.8364684284F, 0.8371049907F, 0.8377401562F, 0.8383739238F,
+ 0.8390062927F, 0.8396372618F, 0.8402668305F, 0.8408949977F,
+ 0.8415217626F, 0.8421471245F, 0.8427710823F, 0.8433936354F,
+ 0.8440147830F, 0.8446345242F, 0.8452528582F, 0.8458697844F,
+ 0.8464853020F, 0.8470994102F, 0.8477121084F, 0.8483233958F,
+ 0.8489332718F, 0.8495417356F, 0.8501487866F, 0.8507544243F,
+ 0.8513586479F, 0.8519614568F, 0.8525628505F, 0.8531628283F,
+ 0.8537613897F, 0.8543585341F, 0.8549542611F, 0.8555485699F,
+ 0.8561414603F, 0.8567329315F, 0.8573229832F, 0.8579116149F,
+ 0.8584988262F, 0.8590846165F, 0.8596689855F, 0.8602519327F,
+ 0.8608334577F, 0.8614135603F, 0.8619922399F, 0.8625694962F,
+ 0.8631453289F, 0.8637197377F, 0.8642927222F, 0.8648642821F,
+ 0.8654344172F, 0.8660031272F, 0.8665704118F, 0.8671362708F,
+ 0.8677007039F, 0.8682637109F, 0.8688252917F, 0.8693854460F,
+ 0.8699441737F, 0.8705014745F, 0.8710573485F, 0.8716117953F,
+ 0.8721648150F, 0.8727164073F, 0.8732665723F, 0.8738153098F,
+ 0.8743626197F, 0.8749085021F, 0.8754529569F, 0.8759959840F,
+ 0.8765375835F, 0.8770777553F, 0.8776164996F, 0.8781538162F,
+ 0.8786897054F, 0.8792241670F, 0.8797572013F, 0.8802888082F,
+ 0.8808189880F, 0.8813477407F, 0.8818750664F, 0.8824009653F,
+ 0.8829254375F, 0.8834484833F, 0.8839701028F, 0.8844902961F,
+ 0.8850090636F, 0.8855264054F, 0.8860423218F, 0.8865568131F,
+ 0.8870698794F, 0.8875815212F, 0.8880917386F, 0.8886005319F,
+ 0.8891079016F, 0.8896138479F, 0.8901183712F, 0.8906214719F,
+ 0.8911231503F, 0.8916234067F, 0.8921222417F, 0.8926196556F,
+ 0.8931156489F, 0.8936102219F, 0.8941033752F, 0.8945951092F,
+ 0.8950854244F, 0.8955743212F, 0.8960618003F, 0.8965478621F,
+ 0.8970325071F, 0.8975157359F, 0.8979975490F, 0.8984779471F,
+ 0.8989569307F, 0.8994345004F, 0.8999106568F, 0.9003854005F,
+ 0.9008587323F, 0.9013306526F, 0.9018011623F, 0.9022702619F,
+ 0.9027379521F, 0.9032042337F, 0.9036691074F, 0.9041325739F,
+ 0.9045946339F, 0.9050552882F, 0.9055145376F, 0.9059723828F,
+ 0.9064288246F, 0.9068838638F, 0.9073375013F, 0.9077897379F,
+ 0.9082405743F, 0.9086900115F, 0.9091380503F, 0.9095846917F,
+ 0.9100299364F, 0.9104737854F, 0.9109162397F, 0.9113573001F,
+ 0.9117969675F, 0.9122352430F, 0.9126721275F, 0.9131076219F,
+ 0.9135417273F, 0.9139744447F, 0.9144057750F, 0.9148357194F,
+ 0.9152642787F, 0.9156914542F, 0.9161172468F, 0.9165416576F,
+ 0.9169646877F, 0.9173863382F, 0.9178066102F, 0.9182255048F,
+ 0.9186430232F, 0.9190591665F, 0.9194739359F, 0.9198873324F,
+ 0.9202993574F, 0.9207100120F, 0.9211192973F, 0.9215272147F,
+ 0.9219337653F, 0.9223389504F, 0.9227427713F, 0.9231452290F,
+ 0.9235463251F, 0.9239460607F, 0.9243444371F, 0.9247414557F,
+ 0.9251371177F, 0.9255314245F, 0.9259243774F, 0.9263159778F,
+ 0.9267062270F, 0.9270951264F, 0.9274826774F, 0.9278688814F,
+ 0.9282537398F, 0.9286372540F, 0.9290194254F, 0.9294002555F,
+ 0.9297797458F, 0.9301578976F, 0.9305347125F, 0.9309101919F,
+ 0.9312843373F, 0.9316571503F, 0.9320286323F, 0.9323987849F,
+ 0.9327676097F, 0.9331351080F, 0.9335012816F, 0.9338661320F,
+ 0.9342296607F, 0.9345918694F, 0.9349527596F, 0.9353123330F,
+ 0.9356705911F, 0.9360275357F, 0.9363831683F, 0.9367374905F,
+ 0.9370905042F, 0.9374422108F, 0.9377926122F, 0.9381417099F,
+ 0.9384895057F, 0.9388360014F, 0.9391811985F, 0.9395250989F,
+ 0.9398677043F, 0.9402090165F, 0.9405490371F, 0.9408877680F,
+ 0.9412252110F, 0.9415613678F, 0.9418962402F, 0.9422298301F,
+ 0.9425621392F, 0.9428931695F, 0.9432229226F, 0.9435514005F,
+ 0.9438786050F, 0.9442045381F, 0.9445292014F, 0.9448525971F,
+ 0.9451747268F, 0.9454955926F, 0.9458151963F, 0.9461335399F,
+ 0.9464506253F, 0.9467664545F, 0.9470810293F, 0.9473943517F,
+ 0.9477064238F, 0.9480172474F, 0.9483268246F, 0.9486351573F,
+ 0.9489422475F, 0.9492480973F, 0.9495527087F, 0.9498560837F,
+ 0.9501582243F, 0.9504591325F, 0.9507588105F, 0.9510572603F,
+ 0.9513544839F, 0.9516504834F, 0.9519452609F, 0.9522388186F,
+ 0.9525311584F, 0.9528222826F, 0.9531121932F, 0.9534008923F,
+ 0.9536883821F, 0.9539746647F, 0.9542597424F, 0.9545436171F,
+ 0.9548262912F, 0.9551077667F, 0.9553880459F, 0.9556671309F,
+ 0.9559450239F, 0.9562217272F, 0.9564972429F, 0.9567715733F,
+ 0.9570447206F, 0.9573166871F, 0.9575874749F, 0.9578570863F,
+ 0.9581255236F, 0.9583927890F, 0.9586588849F, 0.9589238134F,
+ 0.9591875769F, 0.9594501777F, 0.9597116180F, 0.9599719003F,
+ 0.9602310267F, 0.9604889995F, 0.9607458213F, 0.9610014942F,
+ 0.9612560206F, 0.9615094028F, 0.9617616433F, 0.9620127443F,
+ 0.9622627083F, 0.9625115376F, 0.9627592345F, 0.9630058016F,
+ 0.9632512411F, 0.9634955555F, 0.9637387471F, 0.9639808185F,
+ 0.9642217720F, 0.9644616100F, 0.9647003349F, 0.9649379493F,
+ 0.9651744556F, 0.9654098561F, 0.9656441534F, 0.9658773499F,
+ 0.9661094480F, 0.9663404504F, 0.9665703593F, 0.9667991774F,
+ 0.9670269071F, 0.9672535509F, 0.9674791114F, 0.9677035909F,
+ 0.9679269921F, 0.9681493174F, 0.9683705694F, 0.9685907506F,
+ 0.9688098636F, 0.9690279108F, 0.9692448948F, 0.9694608182F,
+ 0.9696756836F, 0.9698894934F, 0.9701022503F, 0.9703139569F,
+ 0.9705246156F, 0.9707342291F, 0.9709428000F, 0.9711503309F,
+ 0.9713568243F, 0.9715622829F, 0.9717667093F, 0.9719701060F,
+ 0.9721724757F, 0.9723738210F, 0.9725741446F, 0.9727734490F,
+ 0.9729717369F, 0.9731690109F, 0.9733652737F, 0.9735605279F,
+ 0.9737547762F, 0.9739480212F, 0.9741402656F, 0.9743315120F,
+ 0.9745217631F, 0.9747110216F, 0.9748992901F, 0.9750865714F,
+ 0.9752728681F, 0.9754581829F, 0.9756425184F, 0.9758258775F,
+ 0.9760082627F, 0.9761896768F, 0.9763701224F, 0.9765496024F,
+ 0.9767281193F, 0.9769056760F, 0.9770822751F, 0.9772579193F,
+ 0.9774326114F, 0.9776063542F, 0.9777791502F, 0.9779510023F,
+ 0.9781219133F, 0.9782918858F, 0.9784609226F, 0.9786290264F,
+ 0.9787962000F, 0.9789624461F, 0.9791277676F, 0.9792921671F,
+ 0.9794556474F, 0.9796182113F, 0.9797798615F, 0.9799406009F,
+ 0.9801004321F, 0.9802593580F, 0.9804173813F, 0.9805745049F,
+ 0.9807307314F, 0.9808860637F, 0.9810405046F, 0.9811940568F,
+ 0.9813467232F, 0.9814985065F, 0.9816494095F, 0.9817994351F,
+ 0.9819485860F, 0.9820968650F, 0.9822442750F, 0.9823908186F,
+ 0.9825364988F, 0.9826813184F, 0.9828252801F, 0.9829683868F,
+ 0.9831106413F, 0.9832520463F, 0.9833926048F, 0.9835323195F,
+ 0.9836711932F, 0.9838092288F, 0.9839464291F, 0.9840827969F,
+ 0.9842183351F, 0.9843530464F, 0.9844869337F, 0.9846199998F,
+ 0.9847522475F, 0.9848836798F, 0.9850142993F, 0.9851441090F,
+ 0.9852731117F, 0.9854013101F, 0.9855287073F, 0.9856553058F,
+ 0.9857811087F, 0.9859061188F, 0.9860303388F, 0.9861537717F,
+ 0.9862764202F, 0.9863982872F, 0.9865193756F, 0.9866396882F,
+ 0.9867592277F, 0.9868779972F, 0.9869959993F, 0.9871132370F,
+ 0.9872297131F, 0.9873454304F, 0.9874603918F, 0.9875746001F,
+ 0.9876880581F, 0.9878007688F, 0.9879127348F, 0.9880239592F,
+ 0.9881344447F, 0.9882441941F, 0.9883532104F, 0.9884614962F,
+ 0.9885690546F, 0.9886758883F, 0.9887820001F, 0.9888873930F,
+ 0.9889920697F, 0.9890960331F, 0.9891992859F, 0.9893018312F,
+ 0.9894036716F, 0.9895048100F, 0.9896052493F, 0.9897049923F,
+ 0.9898040418F, 0.9899024006F, 0.9900000717F, 0.9900970577F,
+ 0.9901933616F, 0.9902889862F, 0.9903839343F, 0.9904782087F,
+ 0.9905718122F, 0.9906647477F, 0.9907570180F, 0.9908486259F,
+ 0.9909395742F, 0.9910298658F, 0.9911195034F, 0.9912084899F,
+ 0.9912968281F, 0.9913845208F, 0.9914715708F, 0.9915579810F,
+ 0.9916437540F, 0.9917288928F, 0.9918134001F, 0.9918972788F,
+ 0.9919805316F, 0.9920631613F, 0.9921451707F, 0.9922265626F,
+ 0.9923073399F, 0.9923875052F, 0.9924670615F, 0.9925460114F,
+ 0.9926243577F, 0.9927021033F, 0.9927792508F, 0.9928558032F,
+ 0.9929317631F, 0.9930071333F, 0.9930819167F, 0.9931561158F,
+ 0.9932297337F, 0.9933027728F, 0.9933752362F, 0.9934471264F,
+ 0.9935184462F, 0.9935891985F, 0.9936593859F, 0.9937290112F,
+ 0.9937980771F, 0.9938665864F, 0.9939345418F, 0.9940019460F,
+ 0.9940688018F, 0.9941351118F, 0.9942008789F, 0.9942661057F,
+ 0.9943307950F, 0.9943949494F, 0.9944585717F, 0.9945216645F,
+ 0.9945842307F, 0.9946462728F, 0.9947077936F, 0.9947687957F,
+ 0.9948292820F, 0.9948892550F, 0.9949487174F, 0.9950076719F,
+ 0.9950661212F, 0.9951240679F, 0.9951815148F, 0.9952384645F,
+ 0.9952949196F, 0.9953508828F, 0.9954063568F, 0.9954613442F,
+ 0.9955158476F, 0.9955698697F, 0.9956234132F, 0.9956764806F,
+ 0.9957290746F, 0.9957811978F, 0.9958328528F, 0.9958840423F,
+ 0.9959347688F, 0.9959850351F, 0.9960348435F, 0.9960841969F,
+ 0.9961330977F, 0.9961815486F, 0.9962295521F, 0.9962771108F,
+ 0.9963242274F, 0.9963709043F, 0.9964171441F, 0.9964629494F,
+ 0.9965083228F, 0.9965532668F, 0.9965977840F, 0.9966418768F,
+ 0.9966855479F, 0.9967287998F, 0.9967716350F, 0.9968140559F,
+ 0.9968560653F, 0.9968976655F, 0.9969388591F, 0.9969796485F,
+ 0.9970200363F, 0.9970600250F, 0.9970996170F, 0.9971388149F,
+ 0.9971776211F, 0.9972160380F, 0.9972540683F, 0.9972917142F,
+ 0.9973289783F, 0.9973658631F, 0.9974023709F, 0.9974385042F,
+ 0.9974742655F, 0.9975096571F, 0.9975446816F, 0.9975793413F,
+ 0.9976136386F, 0.9976475759F, 0.9976811557F, 0.9977143803F,
+ 0.9977472521F, 0.9977797736F, 0.9978119470F, 0.9978437748F,
+ 0.9978752593F, 0.9979064029F, 0.9979372079F, 0.9979676768F,
+ 0.9979978117F, 0.9980276151F, 0.9980570893F, 0.9980862367F,
+ 0.9981150595F, 0.9981435600F, 0.9981717406F, 0.9981996035F,
+ 0.9982271511F, 0.9982543856F, 0.9982813093F, 0.9983079246F,
+ 0.9983342336F, 0.9983602386F, 0.9983859418F, 0.9984113456F,
+ 0.9984364522F, 0.9984612638F, 0.9984857825F, 0.9985100108F,
+ 0.9985339507F, 0.9985576044F, 0.9985809743F, 0.9986040624F,
+ 0.9986268710F, 0.9986494022F, 0.9986716583F, 0.9986936413F,
+ 0.9987153535F, 0.9987367969F, 0.9987579738F, 0.9987788864F,
+ 0.9987995366F, 0.9988199267F, 0.9988400587F, 0.9988599348F,
+ 0.9988795572F, 0.9988989278F, 0.9989180487F, 0.9989369222F,
+ 0.9989555501F, 0.9989739347F, 0.9989920780F, 0.9990099820F,
+ 0.9990276487F, 0.9990450803F, 0.9990622787F, 0.9990792460F,
+ 0.9990959841F, 0.9991124952F, 0.9991287812F, 0.9991448440F,
+ 0.9991606858F, 0.9991763084F, 0.9991917139F, 0.9992069042F,
+ 0.9992218813F, 0.9992366471F, 0.9992512035F, 0.9992655525F,
+ 0.9992796961F, 0.9992936361F, 0.9993073744F, 0.9993209131F,
+ 0.9993342538F, 0.9993473987F, 0.9993603494F, 0.9993731080F,
+ 0.9993856762F, 0.9993980559F, 0.9994102490F, 0.9994222573F,
+ 0.9994340827F, 0.9994457269F, 0.9994571918F, 0.9994684793F,
+ 0.9994795910F, 0.9994905288F, 0.9995012945F, 0.9995118898F,
+ 0.9995223165F, 0.9995325765F, 0.9995426713F, 0.9995526029F,
+ 0.9995623728F, 0.9995719829F, 0.9995814349F, 0.9995907304F,
+ 0.9995998712F, 0.9996088590F, 0.9996176954F, 0.9996263821F,
+ 0.9996349208F, 0.9996433132F, 0.9996515609F, 0.9996596656F,
+ 0.9996676288F, 0.9996754522F, 0.9996831375F, 0.9996906862F,
+ 0.9996981000F, 0.9997053804F, 0.9997125290F, 0.9997195474F,
+ 0.9997264371F, 0.9997331998F, 0.9997398369F, 0.9997463500F,
+ 0.9997527406F, 0.9997590103F, 0.9997651606F, 0.9997711930F,
+ 0.9997771089F, 0.9997829098F, 0.9997885973F, 0.9997941728F,
+ 0.9997996378F, 0.9998049936F, 0.9998102419F, 0.9998153839F,
+ 0.9998204211F, 0.9998253550F, 0.9998301868F, 0.9998349182F,
+ 0.9998395503F, 0.9998440847F, 0.9998485226F, 0.9998528654F,
+ 0.9998571146F, 0.9998612713F, 0.9998653370F, 0.9998693130F,
+ 0.9998732007F, 0.9998770012F, 0.9998807159F, 0.9998843461F,
+ 0.9998878931F, 0.9998913581F, 0.9998947424F, 0.9998980473F,
+ 0.9999012740F, 0.9999044237F, 0.9999074976F, 0.9999104971F,
+ 0.9999134231F, 0.9999162771F, 0.9999190601F, 0.9999217733F,
+ 0.9999244179F, 0.9999269950F, 0.9999295058F, 0.9999319515F,
+ 0.9999343332F, 0.9999366519F, 0.9999389088F, 0.9999411050F,
+ 0.9999432416F, 0.9999453196F, 0.9999473402F, 0.9999493044F,
+ 0.9999512132F, 0.9999530677F, 0.9999548690F, 0.9999566180F,
+ 0.9999583157F, 0.9999599633F, 0.9999615616F, 0.9999631116F,
+ 0.9999646144F, 0.9999660709F, 0.9999674820F, 0.9999688487F,
+ 0.9999701719F, 0.9999714526F, 0.9999726917F, 0.9999738900F,
+ 0.9999750486F, 0.9999761682F, 0.9999772497F, 0.9999782941F,
+ 0.9999793021F, 0.9999802747F, 0.9999812126F, 0.9999821167F,
+ 0.9999829878F, 0.9999838268F, 0.9999846343F, 0.9999854113F,
+ 0.9999861584F, 0.9999868765F, 0.9999875664F, 0.9999882287F,
+ 0.9999888642F, 0.9999894736F, 0.9999900577F, 0.9999906172F,
+ 0.9999911528F, 0.9999916651F, 0.9999921548F, 0.9999926227F,
+ 0.9999930693F, 0.9999934954F, 0.9999939015F, 0.9999942883F,
+ 0.9999946564F, 0.9999950064F, 0.9999953390F, 0.9999956547F,
+ 0.9999959541F, 0.9999962377F, 0.9999965062F, 0.9999967601F,
+ 0.9999969998F, 0.9999972260F, 0.9999974392F, 0.9999976399F,
+ 0.9999978285F, 0.9999980056F, 0.9999981716F, 0.9999983271F,
+ 0.9999984724F, 0.9999986081F, 0.9999987345F, 0.9999988521F,
+ 0.9999989613F, 0.9999990625F, 0.9999991562F, 0.9999992426F,
+ 0.9999993223F, 0.9999993954F, 0.9999994625F, 0.9999995239F,
+ 0.9999995798F, 0.9999996307F, 0.9999996768F, 0.9999997184F,
+ 0.9999997559F, 0.9999997895F, 0.9999998195F, 0.9999998462F,
+ 0.9999998698F, 0.9999998906F, 0.9999999088F, 0.9999999246F,
+ 0.9999999383F, 0.9999999500F, 0.9999999600F, 0.9999999684F,
+ 0.9999999754F, 0.9999999811F, 0.9999999858F, 0.9999999896F,
+ 0.9999999925F, 0.9999999948F, 0.9999999965F, 0.9999999978F,
+ 0.9999999986F, 0.9999999992F, 0.9999999996F, 0.9999999998F,
+ 0.9999999999F, 1.0000000000F, 1.0000000000F, 1.0000000000F,
+};
+
+static const float vwin8192[4096] = {
+ 0.0000000578F, 0.0000005198F, 0.0000014438F, 0.0000028299F,
+ 0.0000046780F, 0.0000069882F, 0.0000097604F, 0.0000129945F,
+ 0.0000166908F, 0.0000208490F, 0.0000254692F, 0.0000305515F,
+ 0.0000360958F, 0.0000421021F, 0.0000485704F, 0.0000555006F,
+ 0.0000628929F, 0.0000707472F, 0.0000790635F, 0.0000878417F,
+ 0.0000970820F, 0.0001067842F, 0.0001169483F, 0.0001275744F,
+ 0.0001386625F, 0.0001502126F, 0.0001622245F, 0.0001746984F,
+ 0.0001876343F, 0.0002010320F, 0.0002148917F, 0.0002292132F,
+ 0.0002439967F, 0.0002592421F, 0.0002749493F, 0.0002911184F,
+ 0.0003077493F, 0.0003248421F, 0.0003423967F, 0.0003604132F,
+ 0.0003788915F, 0.0003978316F, 0.0004172335F, 0.0004370971F,
+ 0.0004574226F, 0.0004782098F, 0.0004994587F, 0.0005211694F,
+ 0.0005433418F, 0.0005659759F, 0.0005890717F, 0.0006126292F,
+ 0.0006366484F, 0.0006611292F, 0.0006860716F, 0.0007114757F,
+ 0.0007373414F, 0.0007636687F, 0.0007904576F, 0.0008177080F,
+ 0.0008454200F, 0.0008735935F, 0.0009022285F, 0.0009313250F,
+ 0.0009608830F, 0.0009909025F, 0.0010213834F, 0.0010523257F,
+ 0.0010837295F, 0.0011155946F, 0.0011479211F, 0.0011807090F,
+ 0.0012139582F, 0.0012476687F, 0.0012818405F, 0.0013164736F,
+ 0.0013515679F, 0.0013871235F, 0.0014231402F, 0.0014596182F,
+ 0.0014965573F, 0.0015339576F, 0.0015718190F, 0.0016101415F,
+ 0.0016489251F, 0.0016881698F, 0.0017278754F, 0.0017680421F,
+ 0.0018086698F, 0.0018497584F, 0.0018913080F, 0.0019333185F,
+ 0.0019757898F, 0.0020187221F, 0.0020621151F, 0.0021059690F,
+ 0.0021502837F, 0.0021950591F, 0.0022402953F, 0.0022859921F,
+ 0.0023321497F, 0.0023787679F, 0.0024258467F, 0.0024733861F,
+ 0.0025213861F, 0.0025698466F, 0.0026187676F, 0.0026681491F,
+ 0.0027179911F, 0.0027682935F, 0.0028190562F, 0.0028702794F,
+ 0.0029219628F, 0.0029741066F, 0.0030267107F, 0.0030797749F,
+ 0.0031332994F, 0.0031872841F, 0.0032417289F, 0.0032966338F,
+ 0.0033519988F, 0.0034078238F, 0.0034641089F, 0.0035208539F,
+ 0.0035780589F, 0.0036357237F, 0.0036938485F, 0.0037524331F,
+ 0.0038114775F, 0.0038709817F, 0.0039309456F, 0.0039913692F,
+ 0.0040522524F, 0.0041135953F, 0.0041753978F, 0.0042376599F,
+ 0.0043003814F, 0.0043635624F, 0.0044272029F, 0.0044913028F,
+ 0.0045558620F, 0.0046208806F, 0.0046863585F, 0.0047522955F,
+ 0.0048186919F, 0.0048855473F, 0.0049528619F, 0.0050206356F,
+ 0.0050888684F, 0.0051575601F, 0.0052267108F, 0.0052963204F,
+ 0.0053663890F, 0.0054369163F, 0.0055079025F, 0.0055793474F,
+ 0.0056512510F, 0.0057236133F, 0.0057964342F, 0.0058697137F,
+ 0.0059434517F, 0.0060176482F, 0.0060923032F, 0.0061674166F,
+ 0.0062429883F, 0.0063190183F, 0.0063955066F, 0.0064724532F,
+ 0.0065498579F, 0.0066277207F, 0.0067060416F, 0.0067848205F,
+ 0.0068640575F, 0.0069437523F, 0.0070239051F, 0.0071045157F,
+ 0.0071855840F, 0.0072671102F, 0.0073490940F, 0.0074315355F,
+ 0.0075144345F, 0.0075977911F, 0.0076816052F, 0.0077658768F,
+ 0.0078506057F, 0.0079357920F, 0.0080214355F, 0.0081075363F,
+ 0.0081940943F, 0.0082811094F, 0.0083685816F, 0.0084565108F,
+ 0.0085448970F, 0.0086337401F, 0.0087230401F, 0.0088127969F,
+ 0.0089030104F, 0.0089936807F, 0.0090848076F, 0.0091763911F,
+ 0.0092684311F, 0.0093609276F, 0.0094538805F, 0.0095472898F,
+ 0.0096411554F, 0.0097354772F, 0.0098302552F, 0.0099254894F,
+ 0.0100211796F, 0.0101173259F, 0.0102139281F, 0.0103109863F,
+ 0.0104085002F, 0.0105064700F, 0.0106048955F, 0.0107037766F,
+ 0.0108031133F, 0.0109029056F, 0.0110031534F, 0.0111038565F,
+ 0.0112050151F, 0.0113066289F, 0.0114086980F, 0.0115112222F,
+ 0.0116142015F, 0.0117176359F, 0.0118215252F, 0.0119258695F,
+ 0.0120306686F, 0.0121359225F, 0.0122416312F, 0.0123477944F,
+ 0.0124544123F, 0.0125614847F, 0.0126690116F, 0.0127769928F,
+ 0.0128854284F, 0.0129943182F, 0.0131036623F, 0.0132134604F,
+ 0.0133237126F, 0.0134344188F, 0.0135455790F, 0.0136571929F,
+ 0.0137692607F, 0.0138817821F, 0.0139947572F, 0.0141081859F,
+ 0.0142220681F, 0.0143364037F, 0.0144511927F, 0.0145664350F,
+ 0.0146821304F, 0.0147982791F, 0.0149148808F, 0.0150319355F,
+ 0.0151494431F, 0.0152674036F, 0.0153858168F, 0.0155046828F,
+ 0.0156240014F, 0.0157437726F, 0.0158639962F, 0.0159846723F,
+ 0.0161058007F, 0.0162273814F, 0.0163494142F, 0.0164718991F,
+ 0.0165948361F, 0.0167182250F, 0.0168420658F, 0.0169663584F,
+ 0.0170911027F, 0.0172162987F, 0.0173419462F, 0.0174680452F,
+ 0.0175945956F, 0.0177215974F, 0.0178490504F, 0.0179769545F,
+ 0.0181053098F, 0.0182341160F, 0.0183633732F, 0.0184930812F,
+ 0.0186232399F, 0.0187538494F, 0.0188849094F, 0.0190164200F,
+ 0.0191483809F, 0.0192807923F, 0.0194136539F, 0.0195469656F,
+ 0.0196807275F, 0.0198149394F, 0.0199496012F, 0.0200847128F,
+ 0.0202202742F, 0.0203562853F, 0.0204927460F, 0.0206296561F,
+ 0.0207670157F, 0.0209048245F, 0.0210430826F, 0.0211817899F,
+ 0.0213209462F, 0.0214605515F, 0.0216006057F, 0.0217411086F,
+ 0.0218820603F, 0.0220234605F, 0.0221653093F, 0.0223076066F,
+ 0.0224503521F, 0.0225935459F, 0.0227371879F, 0.0228812779F,
+ 0.0230258160F, 0.0231708018F, 0.0233162355F, 0.0234621169F,
+ 0.0236084459F, 0.0237552224F, 0.0239024462F, 0.0240501175F,
+ 0.0241982359F, 0.0243468015F, 0.0244958141F, 0.0246452736F,
+ 0.0247951800F, 0.0249455331F, 0.0250963329F, 0.0252475792F,
+ 0.0253992720F, 0.0255514111F, 0.0257039965F, 0.0258570281F,
+ 0.0260105057F, 0.0261644293F, 0.0263187987F, 0.0264736139F,
+ 0.0266288747F, 0.0267845811F, 0.0269407330F, 0.0270973302F,
+ 0.0272543727F, 0.0274118604F, 0.0275697930F, 0.0277281707F,
+ 0.0278869932F, 0.0280462604F, 0.0282059723F, 0.0283661287F,
+ 0.0285267295F, 0.0286877747F, 0.0288492641F, 0.0290111976F,
+ 0.0291735751F, 0.0293363965F, 0.0294996617F, 0.0296633706F,
+ 0.0298275231F, 0.0299921190F, 0.0301571583F, 0.0303226409F,
+ 0.0304885667F, 0.0306549354F, 0.0308217472F, 0.0309890017F,
+ 0.0311566989F, 0.0313248388F, 0.0314934211F, 0.0316624459F,
+ 0.0318319128F, 0.0320018220F, 0.0321721732F, 0.0323429663F,
+ 0.0325142013F, 0.0326858779F, 0.0328579962F, 0.0330305559F,
+ 0.0332035570F, 0.0333769994F, 0.0335508829F, 0.0337252074F,
+ 0.0338999728F, 0.0340751790F, 0.0342508259F, 0.0344269134F,
+ 0.0346034412F, 0.0347804094F, 0.0349578178F, 0.0351356663F,
+ 0.0353139548F, 0.0354926831F, 0.0356718511F, 0.0358514588F,
+ 0.0360315059F, 0.0362119924F, 0.0363929182F, 0.0365742831F,
+ 0.0367560870F, 0.0369383297F, 0.0371210113F, 0.0373041315F,
+ 0.0374876902F, 0.0376716873F, 0.0378561226F, 0.0380409961F,
+ 0.0382263077F, 0.0384120571F, 0.0385982443F, 0.0387848691F,
+ 0.0389719315F, 0.0391594313F, 0.0393473683F, 0.0395357425F,
+ 0.0397245537F, 0.0399138017F, 0.0401034866F, 0.0402936080F,
+ 0.0404841660F, 0.0406751603F, 0.0408665909F, 0.0410584576F,
+ 0.0412507603F, 0.0414434988F, 0.0416366731F, 0.0418302829F,
+ 0.0420243282F, 0.0422188088F, 0.0424137246F, 0.0426090755F,
+ 0.0428048613F, 0.0430010819F, 0.0431977371F, 0.0433948269F,
+ 0.0435923511F, 0.0437903095F, 0.0439887020F, 0.0441875285F,
+ 0.0443867889F, 0.0445864830F, 0.0447866106F, 0.0449871717F,
+ 0.0451881661F, 0.0453895936F, 0.0455914542F, 0.0457937477F,
+ 0.0459964738F, 0.0461996326F, 0.0464032239F, 0.0466072475F,
+ 0.0468117032F, 0.0470165910F, 0.0472219107F, 0.0474276622F,
+ 0.0476338452F, 0.0478404597F, 0.0480475056F, 0.0482549827F,
+ 0.0484628907F, 0.0486712297F, 0.0488799994F, 0.0490891998F,
+ 0.0492988306F, 0.0495088917F, 0.0497193830F, 0.0499303043F,
+ 0.0501416554F, 0.0503534363F, 0.0505656468F, 0.0507782867F,
+ 0.0509913559F, 0.0512048542F, 0.0514187815F, 0.0516331376F,
+ 0.0518479225F, 0.0520631358F, 0.0522787775F, 0.0524948475F,
+ 0.0527113455F, 0.0529282715F, 0.0531456252F, 0.0533634066F,
+ 0.0535816154F, 0.0538002515F, 0.0540193148F, 0.0542388051F,
+ 0.0544587222F, 0.0546790660F, 0.0548998364F, 0.0551210331F,
+ 0.0553426561F, 0.0555647051F, 0.0557871801F, 0.0560100807F,
+ 0.0562334070F, 0.0564571587F, 0.0566813357F, 0.0569059378F,
+ 0.0571309649F, 0.0573564168F, 0.0575822933F, 0.0578085942F,
+ 0.0580353195F, 0.0582624689F, 0.0584900423F, 0.0587180396F,
+ 0.0589464605F, 0.0591753049F, 0.0594045726F, 0.0596342635F,
+ 0.0598643774F, 0.0600949141F, 0.0603258735F, 0.0605572555F,
+ 0.0607890597F, 0.0610212862F, 0.0612539346F, 0.0614870049F,
+ 0.0617204968F, 0.0619544103F, 0.0621887451F, 0.0624235010F,
+ 0.0626586780F, 0.0628942758F, 0.0631302942F, 0.0633667331F,
+ 0.0636035923F, 0.0638408717F, 0.0640785710F, 0.0643166901F,
+ 0.0645552288F, 0.0647941870F, 0.0650335645F, 0.0652733610F,
+ 0.0655135765F, 0.0657542108F, 0.0659952636F, 0.0662367348F,
+ 0.0664786242F, 0.0667209316F, 0.0669636570F, 0.0672068000F,
+ 0.0674503605F, 0.0676943384F, 0.0679387334F, 0.0681835454F,
+ 0.0684287742F, 0.0686744196F, 0.0689204814F, 0.0691669595F,
+ 0.0694138536F, 0.0696611637F, 0.0699088894F, 0.0701570307F,
+ 0.0704055873F, 0.0706545590F, 0.0709039458F, 0.0711537473F,
+ 0.0714039634F, 0.0716545939F, 0.0719056387F, 0.0721570975F,
+ 0.0724089702F, 0.0726612565F, 0.0729139563F, 0.0731670694F,
+ 0.0734205956F, 0.0736745347F, 0.0739288866F, 0.0741836510F,
+ 0.0744388277F, 0.0746944166F, 0.0749504175F, 0.0752068301F,
+ 0.0754636543F, 0.0757208899F, 0.0759785367F, 0.0762365946F,
+ 0.0764950632F, 0.0767539424F, 0.0770132320F, 0.0772729319F,
+ 0.0775330418F, 0.0777935616F, 0.0780544909F, 0.0783158298F,
+ 0.0785775778F, 0.0788397349F, 0.0791023009F, 0.0793652755F,
+ 0.0796286585F, 0.0798924498F, 0.0801566492F, 0.0804212564F,
+ 0.0806862712F, 0.0809516935F, 0.0812175231F, 0.0814837597F,
+ 0.0817504031F, 0.0820174532F, 0.0822849097F, 0.0825527724F,
+ 0.0828210412F, 0.0830897158F, 0.0833587960F, 0.0836282816F,
+ 0.0838981724F, 0.0841684682F, 0.0844391688F, 0.0847102740F,
+ 0.0849817835F, 0.0852536973F, 0.0855260150F, 0.0857987364F,
+ 0.0860718614F, 0.0863453897F, 0.0866193211F, 0.0868936554F,
+ 0.0871683924F, 0.0874435319F, 0.0877190737F, 0.0879950175F,
+ 0.0882713632F, 0.0885481105F, 0.0888252592F, 0.0891028091F,
+ 0.0893807600F, 0.0896591117F, 0.0899378639F, 0.0902170165F,
+ 0.0904965692F, 0.0907765218F, 0.0910568740F, 0.0913376258F,
+ 0.0916187767F, 0.0919003268F, 0.0921822756F, 0.0924646230F,
+ 0.0927473687F, 0.0930305126F, 0.0933140545F, 0.0935979940F,
+ 0.0938823310F, 0.0941670653F, 0.0944521966F, 0.0947377247F,
+ 0.0950236494F, 0.0953099704F, 0.0955966876F, 0.0958838007F,
+ 0.0961713094F, 0.0964592136F, 0.0967475131F, 0.0970362075F,
+ 0.0973252967F, 0.0976147805F, 0.0979046585F, 0.0981949307F,
+ 0.0984855967F, 0.0987766563F, 0.0990681093F, 0.0993599555F,
+ 0.0996521945F, 0.0999448263F, 0.1002378506F, 0.1005312671F,
+ 0.1008250755F, 0.1011192757F, 0.1014138675F, 0.1017088505F,
+ 0.1020042246F, 0.1022999895F, 0.1025961450F, 0.1028926909F,
+ 0.1031896268F, 0.1034869526F, 0.1037846680F, 0.1040827729F,
+ 0.1043812668F, 0.1046801497F, 0.1049794213F, 0.1052790813F,
+ 0.1055791294F, 0.1058795656F, 0.1061803894F, 0.1064816006F,
+ 0.1067831991F, 0.1070851846F, 0.1073875568F, 0.1076903155F,
+ 0.1079934604F, 0.1082969913F, 0.1086009079F, 0.1089052101F,
+ 0.1092098975F, 0.1095149699F, 0.1098204270F, 0.1101262687F,
+ 0.1104324946F, 0.1107391045F, 0.1110460982F, 0.1113534754F,
+ 0.1116612359F, 0.1119693793F, 0.1122779055F, 0.1125868142F,
+ 0.1128961052F, 0.1132057781F, 0.1135158328F, 0.1138262690F,
+ 0.1141370863F, 0.1144482847F, 0.1147598638F, 0.1150718233F,
+ 0.1153841631F, 0.1156968828F, 0.1160099822F, 0.1163234610F,
+ 0.1166373190F, 0.1169515559F, 0.1172661714F, 0.1175811654F,
+ 0.1178965374F, 0.1182122874F, 0.1185284149F, 0.1188449198F,
+ 0.1191618018F, 0.1194790606F, 0.1197966960F, 0.1201147076F,
+ 0.1204330953F, 0.1207518587F, 0.1210709976F, 0.1213905118F,
+ 0.1217104009F, 0.1220306647F, 0.1223513029F, 0.1226723153F,
+ 0.1229937016F, 0.1233154615F, 0.1236375948F, 0.1239601011F,
+ 0.1242829803F, 0.1246062319F, 0.1249298559F, 0.1252538518F,
+ 0.1255782195F, 0.1259029586F, 0.1262280689F, 0.1265535501F,
+ 0.1268794019F, 0.1272056241F, 0.1275322163F, 0.1278591784F,
+ 0.1281865099F, 0.1285142108F, 0.1288422805F, 0.1291707190F,
+ 0.1294995259F, 0.1298287009F, 0.1301582437F, 0.1304881542F,
+ 0.1308184319F, 0.1311490766F, 0.1314800881F, 0.1318114660F,
+ 0.1321432100F, 0.1324753200F, 0.1328077955F, 0.1331406364F,
+ 0.1334738422F, 0.1338074129F, 0.1341413479F, 0.1344756472F,
+ 0.1348103103F, 0.1351453370F, 0.1354807270F, 0.1358164801F,
+ 0.1361525959F, 0.1364890741F, 0.1368259145F, 0.1371631167F,
+ 0.1375006805F, 0.1378386056F, 0.1381768917F, 0.1385155384F,
+ 0.1388545456F, 0.1391939129F, 0.1395336400F, 0.1398737266F,
+ 0.1402141724F, 0.1405549772F, 0.1408961406F, 0.1412376623F,
+ 0.1415795421F, 0.1419217797F, 0.1422643746F, 0.1426073268F,
+ 0.1429506358F, 0.1432943013F, 0.1436383231F, 0.1439827008F,
+ 0.1443274342F, 0.1446725229F, 0.1450179667F, 0.1453637652F,
+ 0.1457099181F, 0.1460564252F, 0.1464032861F, 0.1467505006F,
+ 0.1470980682F, 0.1474459888F, 0.1477942620F, 0.1481428875F,
+ 0.1484918651F, 0.1488411942F, 0.1491908748F, 0.1495409065F,
+ 0.1498912889F, 0.1502420218F, 0.1505931048F, 0.1509445376F,
+ 0.1512963200F, 0.1516484516F, 0.1520009321F, 0.1523537612F,
+ 0.1527069385F, 0.1530604638F, 0.1534143368F, 0.1537685571F,
+ 0.1541231244F, 0.1544780384F, 0.1548332987F, 0.1551889052F,
+ 0.1555448574F, 0.1559011550F, 0.1562577978F, 0.1566147853F,
+ 0.1569721173F, 0.1573297935F, 0.1576878135F, 0.1580461771F,
+ 0.1584048838F, 0.1587639334F, 0.1591233255F, 0.1594830599F,
+ 0.1598431361F, 0.1602035540F, 0.1605643131F, 0.1609254131F,
+ 0.1612868537F, 0.1616486346F, 0.1620107555F, 0.1623732160F,
+ 0.1627360158F, 0.1630991545F, 0.1634626319F, 0.1638264476F,
+ 0.1641906013F, 0.1645550926F, 0.1649199212F, 0.1652850869F,
+ 0.1656505892F, 0.1660164278F, 0.1663826024F, 0.1667491127F,
+ 0.1671159583F, 0.1674831388F, 0.1678506541F, 0.1682185036F,
+ 0.1685866872F, 0.1689552044F, 0.1693240549F, 0.1696932384F,
+ 0.1700627545F, 0.1704326029F, 0.1708027833F, 0.1711732952F,
+ 0.1715441385F, 0.1719153127F, 0.1722868175F, 0.1726586526F,
+ 0.1730308176F, 0.1734033121F, 0.1737761359F, 0.1741492886F,
+ 0.1745227698F, 0.1748965792F, 0.1752707164F, 0.1756451812F,
+ 0.1760199731F, 0.1763950918F, 0.1767705370F, 0.1771463083F,
+ 0.1775224054F, 0.1778988279F, 0.1782755754F, 0.1786526477F,
+ 0.1790300444F, 0.1794077651F, 0.1797858094F, 0.1801641771F,
+ 0.1805428677F, 0.1809218810F, 0.1813012165F, 0.1816808739F,
+ 0.1820608528F, 0.1824411530F, 0.1828217739F, 0.1832027154F,
+ 0.1835839770F, 0.1839655584F, 0.1843474592F, 0.1847296790F,
+ 0.1851122175F, 0.1854950744F, 0.1858782492F, 0.1862617417F,
+ 0.1866455514F, 0.1870296780F, 0.1874141211F, 0.1877988804F,
+ 0.1881839555F, 0.1885693461F, 0.1889550517F, 0.1893410721F,
+ 0.1897274068F, 0.1901140555F, 0.1905010178F, 0.1908882933F,
+ 0.1912758818F, 0.1916637828F, 0.1920519959F, 0.1924405208F,
+ 0.1928293571F, 0.1932185044F, 0.1936079625F, 0.1939977308F,
+ 0.1943878091F, 0.1947781969F, 0.1951688939F, 0.1955598998F,
+ 0.1959512141F, 0.1963428364F, 0.1967347665F, 0.1971270038F,
+ 0.1975195482F, 0.1979123990F, 0.1983055561F, 0.1986990190F,
+ 0.1990927873F, 0.1994868607F, 0.1998812388F, 0.2002759212F,
+ 0.2006709075F, 0.2010661974F, 0.2014617904F, 0.2018576862F,
+ 0.2022538844F, 0.2026503847F, 0.2030471865F, 0.2034442897F,
+ 0.2038416937F, 0.2042393982F, 0.2046374028F, 0.2050357071F,
+ 0.2054343107F, 0.2058332133F, 0.2062324145F, 0.2066319138F,
+ 0.2070317110F, 0.2074318055F, 0.2078321970F, 0.2082328852F,
+ 0.2086338696F, 0.2090351498F, 0.2094367255F, 0.2098385962F,
+ 0.2102407617F, 0.2106432213F, 0.2110459749F, 0.2114490220F,
+ 0.2118523621F, 0.2122559950F, 0.2126599202F, 0.2130641373F,
+ 0.2134686459F, 0.2138734456F, 0.2142785361F, 0.2146839168F,
+ 0.2150895875F, 0.2154955478F, 0.2159017972F, 0.2163083353F,
+ 0.2167151617F, 0.2171222761F, 0.2175296780F, 0.2179373670F,
+ 0.2183453428F, 0.2187536049F, 0.2191621529F, 0.2195709864F,
+ 0.2199801051F, 0.2203895085F, 0.2207991961F, 0.2212091677F,
+ 0.2216194228F, 0.2220299610F, 0.2224407818F, 0.2228518850F,
+ 0.2232632699F, 0.2236749364F, 0.2240868839F, 0.2244991121F,
+ 0.2249116204F, 0.2253244086F, 0.2257374763F, 0.2261508229F,
+ 0.2265644481F, 0.2269783514F, 0.2273925326F, 0.2278069911F,
+ 0.2282217265F, 0.2286367384F, 0.2290520265F, 0.2294675902F,
+ 0.2298834292F, 0.2302995431F, 0.2307159314F, 0.2311325937F,
+ 0.2315495297F, 0.2319667388F, 0.2323842207F, 0.2328019749F,
+ 0.2332200011F, 0.2336382988F, 0.2340568675F, 0.2344757070F,
+ 0.2348948166F, 0.2353141961F, 0.2357338450F, 0.2361537629F,
+ 0.2365739493F, 0.2369944038F, 0.2374151261F, 0.2378361156F,
+ 0.2382573720F, 0.2386788948F, 0.2391006836F, 0.2395227380F,
+ 0.2399450575F, 0.2403676417F, 0.2407904902F, 0.2412136026F,
+ 0.2416369783F, 0.2420606171F, 0.2424845185F, 0.2429086820F,
+ 0.2433331072F, 0.2437577936F, 0.2441827409F, 0.2446079486F,
+ 0.2450334163F, 0.2454591435F, 0.2458851298F, 0.2463113747F,
+ 0.2467378779F, 0.2471646389F, 0.2475916573F, 0.2480189325F,
+ 0.2484464643F, 0.2488742521F, 0.2493022955F, 0.2497305940F,
+ 0.2501591473F, 0.2505879549F, 0.2510170163F, 0.2514463311F,
+ 0.2518758989F, 0.2523057193F, 0.2527357916F, 0.2531661157F,
+ 0.2535966909F, 0.2540275169F, 0.2544585931F, 0.2548899193F,
+ 0.2553214948F, 0.2557533193F, 0.2561853924F, 0.2566177135F,
+ 0.2570502822F, 0.2574830981F, 0.2579161608F, 0.2583494697F,
+ 0.2587830245F, 0.2592168246F, 0.2596508697F, 0.2600851593F,
+ 0.2605196929F, 0.2609544701F, 0.2613894904F, 0.2618247534F,
+ 0.2622602586F, 0.2626960055F, 0.2631319938F, 0.2635682230F,
+ 0.2640046925F, 0.2644414021F, 0.2648783511F, 0.2653155391F,
+ 0.2657529657F, 0.2661906305F, 0.2666285329F, 0.2670666725F,
+ 0.2675050489F, 0.2679436616F, 0.2683825101F, 0.2688215940F,
+ 0.2692609127F, 0.2697004660F, 0.2701402532F, 0.2705802739F,
+ 0.2710205278F, 0.2714610142F, 0.2719017327F, 0.2723426830F,
+ 0.2727838644F, 0.2732252766F, 0.2736669191F, 0.2741087914F,
+ 0.2745508930F, 0.2749932235F, 0.2754357824F, 0.2758785693F,
+ 0.2763215837F, 0.2767648251F, 0.2772082930F, 0.2776519870F,
+ 0.2780959066F, 0.2785400513F, 0.2789844207F, 0.2794290143F,
+ 0.2798738316F, 0.2803188722F, 0.2807641355F, 0.2812096211F,
+ 0.2816553286F, 0.2821012574F, 0.2825474071F, 0.2829937773F,
+ 0.2834403673F, 0.2838871768F, 0.2843342053F, 0.2847814523F,
+ 0.2852289174F, 0.2856765999F, 0.2861244996F, 0.2865726159F,
+ 0.2870209482F, 0.2874694962F, 0.2879182594F, 0.2883672372F,
+ 0.2888164293F, 0.2892658350F, 0.2897154540F, 0.2901652858F,
+ 0.2906153298F, 0.2910655856F, 0.2915160527F, 0.2919667306F,
+ 0.2924176189F, 0.2928687171F, 0.2933200246F, 0.2937715409F,
+ 0.2942232657F, 0.2946751984F, 0.2951273386F, 0.2955796856F,
+ 0.2960322391F, 0.2964849986F, 0.2969379636F, 0.2973911335F,
+ 0.2978445080F, 0.2982980864F, 0.2987518684F, 0.2992058534F,
+ 0.2996600409F, 0.3001144305F, 0.3005690217F, 0.3010238139F,
+ 0.3014788067F, 0.3019339995F, 0.3023893920F, 0.3028449835F,
+ 0.3033007736F, 0.3037567618F, 0.3042129477F, 0.3046693306F,
+ 0.3051259102F, 0.3055826859F, 0.3060396572F, 0.3064968236F,
+ 0.3069541847F, 0.3074117399F, 0.3078694887F, 0.3083274307F,
+ 0.3087855653F, 0.3092438920F, 0.3097024104F, 0.3101611199F,
+ 0.3106200200F, 0.3110791103F, 0.3115383902F, 0.3119978592F,
+ 0.3124575169F, 0.3129173627F, 0.3133773961F, 0.3138376166F,
+ 0.3142980238F, 0.3147586170F, 0.3152193959F, 0.3156803598F,
+ 0.3161415084F, 0.3166028410F, 0.3170643573F, 0.3175260566F,
+ 0.3179879384F, 0.3184500023F, 0.3189122478F, 0.3193746743F,
+ 0.3198372814F, 0.3203000685F, 0.3207630351F, 0.3212261807F,
+ 0.3216895048F, 0.3221530069F, 0.3226166865F, 0.3230805430F,
+ 0.3235445760F, 0.3240087849F, 0.3244731693F, 0.3249377285F,
+ 0.3254024622F, 0.3258673698F, 0.3263324507F, 0.3267977045F,
+ 0.3272631306F, 0.3277287286F, 0.3281944978F, 0.3286604379F,
+ 0.3291265482F, 0.3295928284F, 0.3300592777F, 0.3305258958F,
+ 0.3309926821F, 0.3314596361F, 0.3319267573F, 0.3323940451F,
+ 0.3328614990F, 0.3333291186F, 0.3337969033F, 0.3342648525F,
+ 0.3347329658F, 0.3352012427F, 0.3356696825F, 0.3361382849F,
+ 0.3366070492F, 0.3370759749F, 0.3375450616F, 0.3380143087F,
+ 0.3384837156F, 0.3389532819F, 0.3394230071F, 0.3398928905F,
+ 0.3403629317F, 0.3408331302F, 0.3413034854F, 0.3417739967F,
+ 0.3422446638F, 0.3427154860F, 0.3431864628F, 0.3436575938F,
+ 0.3441288782F, 0.3446003158F, 0.3450719058F, 0.3455436478F,
+ 0.3460155412F, 0.3464875856F, 0.3469597804F, 0.3474321250F,
+ 0.3479046189F, 0.3483772617F, 0.3488500527F, 0.3493229914F,
+ 0.3497960774F, 0.3502693100F, 0.3507426887F, 0.3512162131F,
+ 0.3516898825F, 0.3521636965F, 0.3526376545F, 0.3531117559F,
+ 0.3535860003F, 0.3540603870F, 0.3545349157F, 0.3550095856F,
+ 0.3554843964F, 0.3559593474F, 0.3564344381F, 0.3569096680F,
+ 0.3573850366F, 0.3578605432F, 0.3583361875F, 0.3588119687F,
+ 0.3592878865F, 0.3597639402F, 0.3602401293F, 0.3607164533F,
+ 0.3611929117F, 0.3616695038F, 0.3621462292F, 0.3626230873F,
+ 0.3631000776F, 0.3635771995F, 0.3640544525F, 0.3645318360F,
+ 0.3650093496F, 0.3654869926F, 0.3659647645F, 0.3664426648F,
+ 0.3669206930F, 0.3673988484F, 0.3678771306F, 0.3683555390F,
+ 0.3688340731F, 0.3693127322F, 0.3697915160F, 0.3702704237F,
+ 0.3707494549F, 0.3712286091F, 0.3717078857F, 0.3721872840F,
+ 0.3726668037F, 0.3731464441F, 0.3736262047F, 0.3741060850F,
+ 0.3745860843F, 0.3750662023F, 0.3755464382F, 0.3760267915F,
+ 0.3765072618F, 0.3769878484F, 0.3774685509F, 0.3779493686F,
+ 0.3784303010F, 0.3789113475F, 0.3793925076F, 0.3798737809F,
+ 0.3803551666F, 0.3808366642F, 0.3813182733F, 0.3817999932F,
+ 0.3822818234F, 0.3827637633F, 0.3832458124F, 0.3837279702F,
+ 0.3842102360F, 0.3846926093F, 0.3851750897F, 0.3856576764F,
+ 0.3861403690F, 0.3866231670F, 0.3871060696F, 0.3875890765F,
+ 0.3880721870F, 0.3885554007F, 0.3890387168F, 0.3895221349F,
+ 0.3900056544F, 0.3904892748F, 0.3909729955F, 0.3914568160F,
+ 0.3919407356F, 0.3924247539F, 0.3929088702F, 0.3933930841F,
+ 0.3938773949F, 0.3943618021F, 0.3948463052F, 0.3953309035F,
+ 0.3958155966F, 0.3963003838F, 0.3967852646F, 0.3972702385F,
+ 0.3977553048F, 0.3982404631F, 0.3987257127F, 0.3992110531F,
+ 0.3996964838F, 0.4001820041F, 0.4006676136F, 0.4011533116F,
+ 0.4016390976F, 0.4021249710F, 0.4026109313F, 0.4030969779F,
+ 0.4035831102F, 0.4040693277F, 0.4045556299F, 0.4050420160F,
+ 0.4055284857F, 0.4060150383F, 0.4065016732F, 0.4069883899F,
+ 0.4074751879F, 0.4079620665F, 0.4084490252F, 0.4089360635F,
+ 0.4094231807F, 0.4099103763F, 0.4103976498F, 0.4108850005F,
+ 0.4113724280F, 0.4118599315F, 0.4123475107F, 0.4128351648F,
+ 0.4133228934F, 0.4138106959F, 0.4142985716F, 0.4147865201F,
+ 0.4152745408F, 0.4157626330F, 0.4162507963F, 0.4167390301F,
+ 0.4172273337F, 0.4177157067F, 0.4182041484F, 0.4186926583F,
+ 0.4191812359F, 0.4196698805F, 0.4201585915F, 0.4206473685F,
+ 0.4211362108F, 0.4216251179F, 0.4221140892F, 0.4226031241F,
+ 0.4230922221F, 0.4235813826F, 0.4240706050F, 0.4245598887F,
+ 0.4250492332F, 0.4255386379F, 0.4260281022F, 0.4265176256F,
+ 0.4270072075F, 0.4274968473F, 0.4279865445F, 0.4284762984F,
+ 0.4289661086F, 0.4294559743F, 0.4299458951F, 0.4304358704F,
+ 0.4309258996F, 0.4314159822F, 0.4319061175F, 0.4323963050F,
+ 0.4328865441F, 0.4333768342F, 0.4338671749F, 0.4343575654F,
+ 0.4348480052F, 0.4353384938F, 0.4358290306F, 0.4363196149F,
+ 0.4368102463F, 0.4373009241F, 0.4377916478F, 0.4382824168F,
+ 0.4387732305F, 0.4392640884F, 0.4397549899F, 0.4402459343F,
+ 0.4407369212F, 0.4412279499F, 0.4417190198F, 0.4422101305F,
+ 0.4427012813F, 0.4431924717F, 0.4436837010F, 0.4441749686F,
+ 0.4446662742F, 0.4451576169F, 0.4456489963F, 0.4461404118F,
+ 0.4466318628F, 0.4471233487F, 0.4476148690F, 0.4481064230F,
+ 0.4485980103F, 0.4490896302F, 0.4495812821F, 0.4500729654F,
+ 0.4505646797F, 0.4510564243F, 0.4515481986F, 0.4520400021F,
+ 0.4525318341F, 0.4530236942F, 0.4535155816F, 0.4540074959F,
+ 0.4544994365F, 0.4549914028F, 0.4554833941F, 0.4559754100F,
+ 0.4564674499F, 0.4569595131F, 0.4574515991F, 0.4579437074F,
+ 0.4584358372F, 0.4589279881F, 0.4594201595F, 0.4599123508F,
+ 0.4604045615F, 0.4608967908F, 0.4613890383F, 0.4618813034F,
+ 0.4623735855F, 0.4628658841F, 0.4633581984F, 0.4638505281F,
+ 0.4643428724F, 0.4648352308F, 0.4653276028F, 0.4658199877F,
+ 0.4663123849F, 0.4668047940F, 0.4672972143F, 0.4677896451F,
+ 0.4682820861F, 0.4687745365F, 0.4692669958F, 0.4697594634F,
+ 0.4702519387F, 0.4707444211F, 0.4712369102F, 0.4717294052F,
+ 0.4722219056F, 0.4727144109F, 0.4732069204F, 0.4736994336F,
+ 0.4741919498F, 0.4746844686F, 0.4751769893F, 0.4756695113F,
+ 0.4761620341F, 0.4766545571F, 0.4771470797F, 0.4776396013F,
+ 0.4781321213F, 0.4786246392F, 0.4791171544F, 0.4796096663F,
+ 0.4801021744F, 0.4805946779F, 0.4810871765F, 0.4815796694F,
+ 0.4820721561F, 0.4825646360F, 0.4830571086F, 0.4835495732F,
+ 0.4840420293F, 0.4845344763F, 0.4850269136F, 0.4855193407F,
+ 0.4860117569F, 0.4865041617F, 0.4869965545F, 0.4874889347F,
+ 0.4879813018F, 0.4884736551F, 0.4889659941F, 0.4894583182F,
+ 0.4899506268F, 0.4904429193F, 0.4909351952F, 0.4914274538F,
+ 0.4919196947F, 0.4924119172F, 0.4929041207F, 0.4933963046F,
+ 0.4938884685F, 0.4943806116F, 0.4948727335F, 0.4953648335F,
+ 0.4958569110F, 0.4963489656F, 0.4968409965F, 0.4973330032F,
+ 0.4978249852F, 0.4983169419F, 0.4988088726F, 0.4993007768F,
+ 0.4997926539F, 0.5002845034F, 0.5007763247F, 0.5012681171F,
+ 0.5017598801F, 0.5022516132F, 0.5027433157F, 0.5032349871F,
+ 0.5037266268F, 0.5042182341F, 0.5047098086F, 0.5052013497F,
+ 0.5056928567F, 0.5061843292F, 0.5066757664F, 0.5071671679F,
+ 0.5076585330F, 0.5081498613F, 0.5086411520F, 0.5091324047F,
+ 0.5096236187F, 0.5101147934F, 0.5106059284F, 0.5110970230F,
+ 0.5115880766F, 0.5120790887F, 0.5125700587F, 0.5130609860F,
+ 0.5135518700F, 0.5140427102F, 0.5145335059F, 0.5150242566F,
+ 0.5155149618F, 0.5160056208F, 0.5164962331F, 0.5169867980F,
+ 0.5174773151F, 0.5179677837F, 0.5184582033F, 0.5189485733F,
+ 0.5194388931F, 0.5199291621F, 0.5204193798F, 0.5209095455F,
+ 0.5213996588F, 0.5218897190F, 0.5223797256F, 0.5228696779F,
+ 0.5233595755F, 0.5238494177F, 0.5243392039F, 0.5248289337F,
+ 0.5253186063F, 0.5258082213F, 0.5262977781F, 0.5267872760F,
+ 0.5272767146F, 0.5277660932F, 0.5282554112F, 0.5287446682F,
+ 0.5292338635F, 0.5297229965F, 0.5302120667F, 0.5307010736F,
+ 0.5311900164F, 0.5316788947F, 0.5321677079F, 0.5326564554F,
+ 0.5331451366F, 0.5336337511F, 0.5341222981F, 0.5346107771F,
+ 0.5350991876F, 0.5355875290F, 0.5360758007F, 0.5365640021F,
+ 0.5370521327F, 0.5375401920F, 0.5380281792F, 0.5385160939F,
+ 0.5390039355F, 0.5394917034F, 0.5399793971F, 0.5404670159F,
+ 0.5409545594F, 0.5414420269F, 0.5419294179F, 0.5424167318F,
+ 0.5429039680F, 0.5433911261F, 0.5438782053F, 0.5443652051F,
+ 0.5448521250F, 0.5453389644F, 0.5458257228F, 0.5463123995F,
+ 0.5467989940F, 0.5472855057F, 0.5477719341F, 0.5482582786F,
+ 0.5487445387F, 0.5492307137F, 0.5497168031F, 0.5502028063F,
+ 0.5506887228F, 0.5511745520F, 0.5516602934F, 0.5521459463F,
+ 0.5526315103F, 0.5531169847F, 0.5536023690F, 0.5540876626F,
+ 0.5545728649F, 0.5550579755F, 0.5555429937F, 0.5560279189F,
+ 0.5565127507F, 0.5569974884F, 0.5574821315F, 0.5579666794F,
+ 0.5584511316F, 0.5589354875F, 0.5594197465F, 0.5599039080F,
+ 0.5603879716F, 0.5608719367F, 0.5613558026F, 0.5618395689F,
+ 0.5623232350F, 0.5628068002F, 0.5632902642F, 0.5637736262F,
+ 0.5642568858F, 0.5647400423F, 0.5652230953F, 0.5657060442F,
+ 0.5661888883F, 0.5666716272F, 0.5671542603F, 0.5676367870F,
+ 0.5681192069F, 0.5686015192F, 0.5690837235F, 0.5695658192F,
+ 0.5700478058F, 0.5705296827F, 0.5710114494F, 0.5714931052F,
+ 0.5719746497F, 0.5724560822F, 0.5729374023F, 0.5734186094F,
+ 0.5738997029F, 0.5743806823F, 0.5748615470F, 0.5753422965F,
+ 0.5758229301F, 0.5763034475F, 0.5767838480F, 0.5772641310F,
+ 0.5777442960F, 0.5782243426F, 0.5787042700F, 0.5791840778F,
+ 0.5796637654F, 0.5801433322F, 0.5806227778F, 0.5811021016F,
+ 0.5815813029F, 0.5820603814F, 0.5825393363F, 0.5830181673F,
+ 0.5834968737F, 0.5839754549F, 0.5844539105F, 0.5849322399F,
+ 0.5854104425F, 0.5858885179F, 0.5863664653F, 0.5868442844F,
+ 0.5873219746F, 0.5877995353F, 0.5882769660F, 0.5887542661F,
+ 0.5892314351F, 0.5897084724F, 0.5901853776F, 0.5906621500F,
+ 0.5911387892F, 0.5916152945F, 0.5920916655F, 0.5925679016F,
+ 0.5930440022F, 0.5935199669F, 0.5939957950F, 0.5944714861F,
+ 0.5949470396F, 0.5954224550F, 0.5958977317F, 0.5963728692F,
+ 0.5968478669F, 0.5973227244F, 0.5977974411F, 0.5982720163F,
+ 0.5987464497F, 0.5992207407F, 0.5996948887F, 0.6001688932F,
+ 0.6006427537F, 0.6011164696F, 0.6015900405F, 0.6020634657F,
+ 0.6025367447F, 0.6030098770F, 0.6034828621F, 0.6039556995F,
+ 0.6044283885F, 0.6049009288F, 0.6053733196F, 0.6058455606F,
+ 0.6063176512F, 0.6067895909F, 0.6072613790F, 0.6077330152F,
+ 0.6082044989F, 0.6086758295F, 0.6091470065F, 0.6096180294F,
+ 0.6100888977F, 0.6105596108F, 0.6110301682F, 0.6115005694F,
+ 0.6119708139F, 0.6124409011F, 0.6129108305F, 0.6133806017F,
+ 0.6138502139F, 0.6143196669F, 0.6147889599F, 0.6152580926F,
+ 0.6157270643F, 0.6161958746F, 0.6166645230F, 0.6171330088F,
+ 0.6176013317F, 0.6180694910F, 0.6185374863F, 0.6190053171F,
+ 0.6194729827F, 0.6199404828F, 0.6204078167F, 0.6208749841F,
+ 0.6213419842F, 0.6218088168F, 0.6222754811F, 0.6227419768F,
+ 0.6232083032F, 0.6236744600F, 0.6241404465F, 0.6246062622F,
+ 0.6250719067F, 0.6255373795F, 0.6260026799F, 0.6264678076F,
+ 0.6269327619F, 0.6273975425F, 0.6278621487F, 0.6283265800F,
+ 0.6287908361F, 0.6292549163F, 0.6297188201F, 0.6301825471F,
+ 0.6306460966F, 0.6311094683F, 0.6315726617F, 0.6320356761F,
+ 0.6324985111F, 0.6329611662F, 0.6334236410F, 0.6338859348F,
+ 0.6343480472F, 0.6348099777F, 0.6352717257F, 0.6357332909F,
+ 0.6361946726F, 0.6366558704F, 0.6371168837F, 0.6375777122F,
+ 0.6380383552F, 0.6384988123F, 0.6389590830F, 0.6394191668F,
+ 0.6398790631F, 0.6403387716F, 0.6407982916F, 0.6412576228F,
+ 0.6417167645F, 0.6421757163F, 0.6426344778F, 0.6430930483F,
+ 0.6435514275F, 0.6440096149F, 0.6444676098F, 0.6449254119F,
+ 0.6453830207F, 0.6458404356F, 0.6462976562F, 0.6467546820F,
+ 0.6472115125F, 0.6476681472F, 0.6481245856F, 0.6485808273F,
+ 0.6490368717F, 0.6494927183F, 0.6499483667F, 0.6504038164F,
+ 0.6508590670F, 0.6513141178F, 0.6517689684F, 0.6522236185F,
+ 0.6526780673F, 0.6531323146F, 0.6535863598F, 0.6540402024F,
+ 0.6544938419F, 0.6549472779F, 0.6554005099F, 0.6558535373F,
+ 0.6563063598F, 0.6567589769F, 0.6572113880F, 0.6576635927F,
+ 0.6581155906F, 0.6585673810F, 0.6590189637F, 0.6594703380F,
+ 0.6599215035F, 0.6603724598F, 0.6608232064F, 0.6612737427F,
+ 0.6617240684F, 0.6621741829F, 0.6626240859F, 0.6630737767F,
+ 0.6635232550F, 0.6639725202F, 0.6644215720F, 0.6648704098F,
+ 0.6653190332F, 0.6657674417F, 0.6662156348F, 0.6666636121F,
+ 0.6671113731F, 0.6675589174F, 0.6680062445F, 0.6684533538F,
+ 0.6689002450F, 0.6693469177F, 0.6697933712F, 0.6702396052F,
+ 0.6706856193F, 0.6711314129F, 0.6715769855F, 0.6720223369F,
+ 0.6724674664F, 0.6729123736F, 0.6733570581F, 0.6738015194F,
+ 0.6742457570F, 0.6746897706F, 0.6751335596F, 0.6755771236F,
+ 0.6760204621F, 0.6764635747F, 0.6769064609F, 0.6773491204F,
+ 0.6777915525F, 0.6782337570F, 0.6786757332F, 0.6791174809F,
+ 0.6795589995F, 0.6800002886F, 0.6804413477F, 0.6808821765F,
+ 0.6813227743F, 0.6817631409F, 0.6822032758F, 0.6826431785F,
+ 0.6830828485F, 0.6835222855F, 0.6839614890F, 0.6844004585F,
+ 0.6848391936F, 0.6852776939F, 0.6857159589F, 0.6861539883F,
+ 0.6865917815F, 0.6870293381F, 0.6874666576F, 0.6879037398F,
+ 0.6883405840F, 0.6887771899F, 0.6892135571F, 0.6896496850F,
+ 0.6900855733F, 0.6905212216F, 0.6909566294F, 0.6913917963F,
+ 0.6918267218F, 0.6922614055F, 0.6926958471F, 0.6931300459F,
+ 0.6935640018F, 0.6939977141F, 0.6944311825F, 0.6948644066F,
+ 0.6952973859F, 0.6957301200F, 0.6961626085F, 0.6965948510F,
+ 0.6970268470F, 0.6974585961F, 0.6978900980F, 0.6983213521F,
+ 0.6987523580F, 0.6991831154F, 0.6996136238F, 0.7000438828F,
+ 0.7004738921F, 0.7009036510F, 0.7013331594F, 0.7017624166F,
+ 0.7021914224F, 0.7026201763F, 0.7030486779F, 0.7034769268F,
+ 0.7039049226F, 0.7043326648F, 0.7047601531F, 0.7051873870F,
+ 0.7056143662F, 0.7060410902F, 0.7064675586F, 0.7068937711F,
+ 0.7073197271F, 0.7077454264F, 0.7081708684F, 0.7085960529F,
+ 0.7090209793F, 0.7094456474F, 0.7098700566F, 0.7102942066F,
+ 0.7107180970F, 0.7111417274F, 0.7115650974F, 0.7119882066F,
+ 0.7124110545F, 0.7128336409F, 0.7132559653F, 0.7136780272F,
+ 0.7140998264F, 0.7145213624F, 0.7149426348F, 0.7153636433F,
+ 0.7157843874F, 0.7162048668F, 0.7166250810F, 0.7170450296F,
+ 0.7174647124F, 0.7178841289F, 0.7183032786F, 0.7187221613F,
+ 0.7191407765F, 0.7195591239F, 0.7199772030F, 0.7203950135F,
+ 0.7208125550F, 0.7212298271F, 0.7216468294F, 0.7220635616F,
+ 0.7224800233F, 0.7228962140F, 0.7233121335F, 0.7237277813F,
+ 0.7241431571F, 0.7245582604F, 0.7249730910F, 0.7253876484F,
+ 0.7258019322F, 0.7262159422F, 0.7266296778F, 0.7270431388F,
+ 0.7274563247F, 0.7278692353F, 0.7282818700F, 0.7286942287F,
+ 0.7291063108F, 0.7295181160F, 0.7299296440F, 0.7303408944F,
+ 0.7307518669F, 0.7311625609F, 0.7315729763F, 0.7319831126F,
+ 0.7323929695F, 0.7328025466F, 0.7332118435F, 0.7336208600F,
+ 0.7340295955F, 0.7344380499F, 0.7348462226F, 0.7352541134F,
+ 0.7356617220F, 0.7360690478F, 0.7364760907F, 0.7368828502F,
+ 0.7372893259F, 0.7376955176F, 0.7381014249F, 0.7385070475F,
+ 0.7389123849F, 0.7393174368F, 0.7397222029F, 0.7401266829F,
+ 0.7405308763F, 0.7409347829F, 0.7413384023F, 0.7417417341F,
+ 0.7421447780F, 0.7425475338F, 0.7429500009F, 0.7433521791F,
+ 0.7437540681F, 0.7441556674F, 0.7445569769F, 0.7449579960F,
+ 0.7453587245F, 0.7457591621F, 0.7461593084F, 0.7465591631F,
+ 0.7469587259F, 0.7473579963F, 0.7477569741F, 0.7481556590F,
+ 0.7485540506F, 0.7489521486F, 0.7493499526F, 0.7497474623F,
+ 0.7501446775F, 0.7505415977F, 0.7509382227F, 0.7513345521F,
+ 0.7517305856F, 0.7521263229F, 0.7525217636F, 0.7529169074F,
+ 0.7533117541F, 0.7537063032F, 0.7541005545F, 0.7544945076F,
+ 0.7548881623F, 0.7552815182F, 0.7556745749F, 0.7560673323F,
+ 0.7564597899F, 0.7568519474F, 0.7572438046F, 0.7576353611F,
+ 0.7580266166F, 0.7584175708F, 0.7588082235F, 0.7591985741F,
+ 0.7595886226F, 0.7599783685F, 0.7603678116F, 0.7607569515F,
+ 0.7611457879F, 0.7615343206F, 0.7619225493F, 0.7623104735F,
+ 0.7626980931F, 0.7630854078F, 0.7634724171F, 0.7638591209F,
+ 0.7642455188F, 0.7646316106F, 0.7650173959F, 0.7654028744F,
+ 0.7657880459F, 0.7661729100F, 0.7665574664F, 0.7669417150F,
+ 0.7673256553F, 0.7677092871F, 0.7680926100F, 0.7684756239F,
+ 0.7688583284F, 0.7692407232F, 0.7696228080F, 0.7700045826F,
+ 0.7703860467F, 0.7707671999F, 0.7711480420F, 0.7715285728F,
+ 0.7719087918F, 0.7722886989F, 0.7726682938F, 0.7730475762F,
+ 0.7734265458F, 0.7738052023F, 0.7741835454F, 0.7745615750F,
+ 0.7749392906F, 0.7753166921F, 0.7756937791F, 0.7760705514F,
+ 0.7764470087F, 0.7768231508F, 0.7771989773F, 0.7775744880F,
+ 0.7779496827F, 0.7783245610F, 0.7786991227F, 0.7790733676F,
+ 0.7794472953F, 0.7798209056F, 0.7801941982F, 0.7805671729F,
+ 0.7809398294F, 0.7813121675F, 0.7816841869F, 0.7820558873F,
+ 0.7824272684F, 0.7827983301F, 0.7831690720F, 0.7835394940F,
+ 0.7839095957F, 0.7842793768F, 0.7846488373F, 0.7850179767F,
+ 0.7853867948F, 0.7857552914F, 0.7861234663F, 0.7864913191F,
+ 0.7868588497F, 0.7872260578F, 0.7875929431F, 0.7879595055F,
+ 0.7883257445F, 0.7886916601F, 0.7890572520F, 0.7894225198F,
+ 0.7897874635F, 0.7901520827F, 0.7905163772F, 0.7908803468F,
+ 0.7912439912F, 0.7916073102F, 0.7919703035F, 0.7923329710F,
+ 0.7926953124F, 0.7930573274F, 0.7934190158F, 0.7937803774F,
+ 0.7941414120F, 0.7945021193F, 0.7948624991F, 0.7952225511F,
+ 0.7955822752F, 0.7959416711F, 0.7963007387F, 0.7966594775F,
+ 0.7970178875F, 0.7973759685F, 0.7977337201F, 0.7980911422F,
+ 0.7984482346F, 0.7988049970F, 0.7991614292F, 0.7995175310F,
+ 0.7998733022F, 0.8002287426F, 0.8005838519F, 0.8009386299F,
+ 0.8012930765F, 0.8016471914F, 0.8020009744F, 0.8023544253F,
+ 0.8027075438F, 0.8030603298F, 0.8034127831F, 0.8037649035F,
+ 0.8041166906F, 0.8044681445F, 0.8048192647F, 0.8051700512F,
+ 0.8055205038F, 0.8058706222F, 0.8062204062F, 0.8065698556F,
+ 0.8069189702F, 0.8072677499F, 0.8076161944F, 0.8079643036F,
+ 0.8083120772F, 0.8086595151F, 0.8090066170F, 0.8093533827F,
+ 0.8096998122F, 0.8100459051F, 0.8103916613F, 0.8107370806F,
+ 0.8110821628F, 0.8114269077F, 0.8117713151F, 0.8121153849F,
+ 0.8124591169F, 0.8128025108F, 0.8131455666F, 0.8134882839F,
+ 0.8138306627F, 0.8141727027F, 0.8145144038F, 0.8148557658F,
+ 0.8151967886F, 0.8155374718F, 0.8158778154F, 0.8162178192F,
+ 0.8165574830F, 0.8168968067F, 0.8172357900F, 0.8175744328F,
+ 0.8179127349F, 0.8182506962F, 0.8185883164F, 0.8189255955F,
+ 0.8192625332F, 0.8195991295F, 0.8199353840F, 0.8202712967F,
+ 0.8206068673F, 0.8209420958F, 0.8212769820F, 0.8216115256F,
+ 0.8219457266F, 0.8222795848F, 0.8226131000F, 0.8229462721F,
+ 0.8232791009F, 0.8236115863F, 0.8239437280F, 0.8242755260F,
+ 0.8246069801F, 0.8249380901F, 0.8252688559F, 0.8255992774F,
+ 0.8259293544F, 0.8262590867F, 0.8265884741F, 0.8269175167F,
+ 0.8272462141F, 0.8275745663F, 0.8279025732F, 0.8282302344F,
+ 0.8285575501F, 0.8288845199F, 0.8292111437F, 0.8295374215F,
+ 0.8298633530F, 0.8301889382F, 0.8305141768F, 0.8308390688F,
+ 0.8311636141F, 0.8314878124F, 0.8318116637F, 0.8321351678F,
+ 0.8324583246F, 0.8327811340F, 0.8331035957F, 0.8334257098F,
+ 0.8337474761F, 0.8340688944F, 0.8343899647F, 0.8347106867F,
+ 0.8350310605F, 0.8353510857F, 0.8356707624F, 0.8359900904F,
+ 0.8363090696F, 0.8366276999F, 0.8369459811F, 0.8372639131F,
+ 0.8375814958F, 0.8378987292F, 0.8382156130F, 0.8385321472F,
+ 0.8388483316F, 0.8391641662F, 0.8394796508F, 0.8397947853F,
+ 0.8401095697F, 0.8404240037F, 0.8407380873F, 0.8410518204F,
+ 0.8413652029F, 0.8416782347F, 0.8419909156F, 0.8423032456F,
+ 0.8426152245F, 0.8429268523F, 0.8432381289F, 0.8435490541F,
+ 0.8438596279F, 0.8441698502F, 0.8444797208F, 0.8447892396F,
+ 0.8450984067F, 0.8454072218F, 0.8457156849F, 0.8460237959F,
+ 0.8463315547F, 0.8466389612F, 0.8469460154F, 0.8472527170F,
+ 0.8475590661F, 0.8478650625F, 0.8481707063F, 0.8484759971F,
+ 0.8487809351F, 0.8490855201F, 0.8493897521F, 0.8496936308F,
+ 0.8499971564F, 0.8503003286F, 0.8506031474F, 0.8509056128F,
+ 0.8512077246F, 0.8515094828F, 0.8518108872F, 0.8521119379F,
+ 0.8524126348F, 0.8527129777F, 0.8530129666F, 0.8533126015F,
+ 0.8536118822F, 0.8539108087F, 0.8542093809F, 0.8545075988F,
+ 0.8548054623F, 0.8551029712F, 0.8554001257F, 0.8556969255F,
+ 0.8559933707F, 0.8562894611F, 0.8565851968F, 0.8568805775F,
+ 0.8571756034F, 0.8574702743F, 0.8577645902F, 0.8580585509F,
+ 0.8583521566F, 0.8586454070F, 0.8589383021F, 0.8592308420F,
+ 0.8595230265F, 0.8598148556F, 0.8601063292F, 0.8603974473F,
+ 0.8606882098F, 0.8609786167F, 0.8612686680F, 0.8615583636F,
+ 0.8618477034F, 0.8621366874F, 0.8624253156F, 0.8627135878F,
+ 0.8630015042F, 0.8632890646F, 0.8635762690F, 0.8638631173F,
+ 0.8641496096F, 0.8644357457F, 0.8647215257F, 0.8650069495F,
+ 0.8652920171F, 0.8655767283F, 0.8658610833F, 0.8661450820F,
+ 0.8664287243F, 0.8667120102F, 0.8669949397F, 0.8672775127F,
+ 0.8675597293F, 0.8678415894F, 0.8681230929F, 0.8684042398F,
+ 0.8686850302F, 0.8689654640F, 0.8692455412F, 0.8695252617F,
+ 0.8698046255F, 0.8700836327F, 0.8703622831F, 0.8706405768F,
+ 0.8709185138F, 0.8711960940F, 0.8714733174F, 0.8717501840F,
+ 0.8720266939F, 0.8723028469F, 0.8725786430F, 0.8728540824F,
+ 0.8731291648F, 0.8734038905F, 0.8736782592F, 0.8739522711F,
+ 0.8742259261F, 0.8744992242F, 0.8747721653F, 0.8750447496F,
+ 0.8753169770F, 0.8755888475F, 0.8758603611F, 0.8761315177F,
+ 0.8764023175F, 0.8766727603F, 0.8769428462F, 0.8772125752F,
+ 0.8774819474F, 0.8777509626F, 0.8780196209F, 0.8782879224F,
+ 0.8785558669F, 0.8788234546F, 0.8790906854F, 0.8793575594F,
+ 0.8796240765F, 0.8798902368F, 0.8801560403F, 0.8804214870F,
+ 0.8806865768F, 0.8809513099F, 0.8812156863F, 0.8814797059F,
+ 0.8817433687F, 0.8820066749F, 0.8822696243F, 0.8825322171F,
+ 0.8827944532F, 0.8830563327F, 0.8833178556F, 0.8835790219F,
+ 0.8838398316F, 0.8841002848F, 0.8843603815F, 0.8846201217F,
+ 0.8848795054F, 0.8851385327F, 0.8853972036F, 0.8856555182F,
+ 0.8859134764F, 0.8861710783F, 0.8864283239F, 0.8866852133F,
+ 0.8869417464F, 0.8871979234F, 0.8874537443F, 0.8877092090F,
+ 0.8879643177F, 0.8882190704F, 0.8884734671F, 0.8887275078F,
+ 0.8889811927F, 0.8892345216F, 0.8894874948F, 0.8897401122F,
+ 0.8899923738F, 0.8902442798F, 0.8904958301F, 0.8907470248F,
+ 0.8909978640F, 0.8912483477F, 0.8914984759F, 0.8917482487F,
+ 0.8919976662F, 0.8922467284F, 0.8924954353F, 0.8927437871F,
+ 0.8929917837F, 0.8932394252F, 0.8934867118F, 0.8937336433F,
+ 0.8939802199F, 0.8942264417F, 0.8944723087F, 0.8947178210F,
+ 0.8949629785F, 0.8952077815F, 0.8954522299F, 0.8956963239F,
+ 0.8959400634F, 0.8961834486F, 0.8964264795F, 0.8966691561F,
+ 0.8969114786F, 0.8971534470F, 0.8973950614F, 0.8976363219F,
+ 0.8978772284F, 0.8981177812F, 0.8983579802F, 0.8985978256F,
+ 0.8988373174F, 0.8990764556F, 0.8993152405F, 0.8995536720F,
+ 0.8997917502F, 0.9000294751F, 0.9002668470F, 0.9005038658F,
+ 0.9007405317F, 0.9009768446F, 0.9012128048F, 0.9014484123F,
+ 0.9016836671F, 0.9019185693F, 0.9021531191F, 0.9023873165F,
+ 0.9026211616F, 0.9028546546F, 0.9030877954F, 0.9033205841F,
+ 0.9035530210F, 0.9037851059F, 0.9040168392F, 0.9042482207F,
+ 0.9044792507F, 0.9047099293F, 0.9049402564F, 0.9051702323F,
+ 0.9053998569F, 0.9056291305F, 0.9058580531F, 0.9060866248F,
+ 0.9063148457F, 0.9065427159F, 0.9067702355F, 0.9069974046F,
+ 0.9072242233F, 0.9074506917F, 0.9076768100F, 0.9079025782F,
+ 0.9081279964F, 0.9083530647F, 0.9085777833F, 0.9088021523F,
+ 0.9090261717F, 0.9092498417F, 0.9094731623F, 0.9096961338F,
+ 0.9099187561F, 0.9101410295F, 0.9103629540F, 0.9105845297F,
+ 0.9108057568F, 0.9110266354F, 0.9112471656F, 0.9114673475F,
+ 0.9116871812F, 0.9119066668F, 0.9121258046F, 0.9123445945F,
+ 0.9125630367F, 0.9127811314F, 0.9129988786F, 0.9132162785F,
+ 0.9134333312F, 0.9136500368F, 0.9138663954F, 0.9140824073F,
+ 0.9142980724F, 0.9145133910F, 0.9147283632F, 0.9149429890F,
+ 0.9151572687F, 0.9153712023F, 0.9155847900F, 0.9157980319F,
+ 0.9160109282F, 0.9162234790F, 0.9164356844F, 0.9166475445F,
+ 0.9168590595F, 0.9170702296F, 0.9172810548F, 0.9174915354F,
+ 0.9177016714F, 0.9179114629F, 0.9181209102F, 0.9183300134F,
+ 0.9185387726F, 0.9187471879F, 0.9189552595F, 0.9191629876F,
+ 0.9193703723F, 0.9195774136F, 0.9197841119F, 0.9199904672F,
+ 0.9201964797F, 0.9204021495F, 0.9206074767F, 0.9208124616F,
+ 0.9210171043F, 0.9212214049F, 0.9214253636F, 0.9216289805F,
+ 0.9218322558F, 0.9220351896F, 0.9222377821F, 0.9224400335F,
+ 0.9226419439F, 0.9228435134F, 0.9230447423F, 0.9232456307F,
+ 0.9234461787F, 0.9236463865F, 0.9238462543F, 0.9240457822F,
+ 0.9242449704F, 0.9244438190F, 0.9246423282F, 0.9248404983F,
+ 0.9250383293F, 0.9252358214F, 0.9254329747F, 0.9256297896F,
+ 0.9258262660F, 0.9260224042F, 0.9262182044F, 0.9264136667F,
+ 0.9266087913F, 0.9268035783F, 0.9269980280F, 0.9271921405F,
+ 0.9273859160F, 0.9275793546F, 0.9277724566F, 0.9279652221F,
+ 0.9281576513F, 0.9283497443F, 0.9285415014F, 0.9287329227F,
+ 0.9289240084F, 0.9291147586F, 0.9293051737F, 0.9294952536F,
+ 0.9296849987F, 0.9298744091F, 0.9300634850F, 0.9302522266F,
+ 0.9304406340F, 0.9306287074F, 0.9308164471F, 0.9310038532F,
+ 0.9311909259F, 0.9313776654F, 0.9315640719F, 0.9317501455F,
+ 0.9319358865F, 0.9321212951F, 0.9323063713F, 0.9324911155F,
+ 0.9326755279F, 0.9328596085F, 0.9330433577F, 0.9332267756F,
+ 0.9334098623F, 0.9335926182F, 0.9337750434F, 0.9339571380F,
+ 0.9341389023F, 0.9343203366F, 0.9345014409F, 0.9346822155F,
+ 0.9348626606F, 0.9350427763F, 0.9352225630F, 0.9354020207F,
+ 0.9355811498F, 0.9357599503F, 0.9359384226F, 0.9361165667F,
+ 0.9362943830F, 0.9364718716F, 0.9366490327F, 0.9368258666F,
+ 0.9370023733F, 0.9371785533F, 0.9373544066F, 0.9375299335F,
+ 0.9377051341F, 0.9378800087F, 0.9380545576F, 0.9382287809F,
+ 0.9384026787F, 0.9385762515F, 0.9387494993F, 0.9389224223F,
+ 0.9390950209F, 0.9392672951F, 0.9394392453F, 0.9396108716F,
+ 0.9397821743F, 0.9399531536F, 0.9401238096F, 0.9402941427F,
+ 0.9404641530F, 0.9406338407F, 0.9408032061F, 0.9409722495F,
+ 0.9411409709F, 0.9413093707F, 0.9414774491F, 0.9416452062F,
+ 0.9418126424F, 0.9419797579F, 0.9421465528F, 0.9423130274F,
+ 0.9424791819F, 0.9426450166F, 0.9428105317F, 0.9429757274F,
+ 0.9431406039F, 0.9433051616F, 0.9434694005F, 0.9436333209F,
+ 0.9437969232F, 0.9439602074F, 0.9441231739F, 0.9442858229F,
+ 0.9444481545F, 0.9446101691F, 0.9447718669F, 0.9449332481F,
+ 0.9450943129F, 0.9452550617F, 0.9454154945F, 0.9455756118F,
+ 0.9457354136F, 0.9458949003F, 0.9460540721F, 0.9462129292F,
+ 0.9463714719F, 0.9465297003F, 0.9466876149F, 0.9468452157F,
+ 0.9470025031F, 0.9471594772F, 0.9473161384F, 0.9474724869F,
+ 0.9476285229F, 0.9477842466F, 0.9479396584F, 0.9480947585F,
+ 0.9482495470F, 0.9484040243F, 0.9485581906F, 0.9487120462F,
+ 0.9488655913F, 0.9490188262F, 0.9491717511F, 0.9493243662F,
+ 0.9494766718F, 0.9496286683F, 0.9497803557F, 0.9499317345F,
+ 0.9500828047F, 0.9502335668F, 0.9503840209F, 0.9505341673F,
+ 0.9506840062F, 0.9508335380F, 0.9509827629F, 0.9511316810F,
+ 0.9512802928F, 0.9514285984F, 0.9515765982F, 0.9517242923F,
+ 0.9518716810F, 0.9520187646F, 0.9521655434F, 0.9523120176F,
+ 0.9524581875F, 0.9526040534F, 0.9527496154F, 0.9528948739F,
+ 0.9530398292F, 0.9531844814F, 0.9533288310F, 0.9534728780F,
+ 0.9536166229F, 0.9537600659F, 0.9539032071F, 0.9540460470F,
+ 0.9541885858F, 0.9543308237F, 0.9544727611F, 0.9546143981F,
+ 0.9547557351F, 0.9548967723F, 0.9550375100F, 0.9551779485F,
+ 0.9553180881F, 0.9554579290F, 0.9555974714F, 0.9557367158F,
+ 0.9558756623F, 0.9560143112F, 0.9561526628F, 0.9562907174F,
+ 0.9564284752F, 0.9565659366F, 0.9567031017F, 0.9568399710F,
+ 0.9569765446F, 0.9571128229F, 0.9572488061F, 0.9573844944F,
+ 0.9575198883F, 0.9576549879F, 0.9577897936F, 0.9579243056F,
+ 0.9580585242F, 0.9581924497F, 0.9583260824F, 0.9584594226F,
+ 0.9585924705F, 0.9587252264F, 0.9588576906F, 0.9589898634F,
+ 0.9591217452F, 0.9592533360F, 0.9593846364F, 0.9595156465F,
+ 0.9596463666F, 0.9597767971F, 0.9599069382F, 0.9600367901F,
+ 0.9601663533F, 0.9602956279F, 0.9604246143F, 0.9605533128F,
+ 0.9606817236F, 0.9608098471F, 0.9609376835F, 0.9610652332F,
+ 0.9611924963F, 0.9613194733F, 0.9614461644F, 0.9615725699F,
+ 0.9616986901F, 0.9618245253F, 0.9619500757F, 0.9620753418F,
+ 0.9622003238F, 0.9623250219F, 0.9624494365F, 0.9625735679F,
+ 0.9626974163F, 0.9628209821F, 0.9629442656F, 0.9630672671F,
+ 0.9631899868F, 0.9633124251F, 0.9634345822F, 0.9635564585F,
+ 0.9636780543F, 0.9637993699F, 0.9639204056F, 0.9640411616F,
+ 0.9641616383F, 0.9642818359F, 0.9644017549F, 0.9645213955F,
+ 0.9646407579F, 0.9647598426F, 0.9648786497F, 0.9649971797F,
+ 0.9651154328F, 0.9652334092F, 0.9653511095F, 0.9654685337F,
+ 0.9655856823F, 0.9657025556F, 0.9658191538F, 0.9659354773F,
+ 0.9660515263F, 0.9661673013F, 0.9662828024F, 0.9663980300F,
+ 0.9665129845F, 0.9666276660F, 0.9667420750F, 0.9668562118F,
+ 0.9669700766F, 0.9670836698F, 0.9671969917F, 0.9673100425F,
+ 0.9674228227F, 0.9675353325F, 0.9676475722F, 0.9677595422F,
+ 0.9678712428F, 0.9679826742F, 0.9680938368F, 0.9682047309F,
+ 0.9683153569F, 0.9684257150F, 0.9685358056F, 0.9686456289F,
+ 0.9687551853F, 0.9688644752F, 0.9689734987F, 0.9690822564F,
+ 0.9691907483F, 0.9692989750F, 0.9694069367F, 0.9695146337F,
+ 0.9696220663F, 0.9697292349F, 0.9698361398F, 0.9699427813F,
+ 0.9700491597F, 0.9701552754F, 0.9702611286F, 0.9703667197F,
+ 0.9704720490F, 0.9705771169F, 0.9706819236F, 0.9707864695F,
+ 0.9708907549F, 0.9709947802F, 0.9710985456F, 0.9712020514F,
+ 0.9713052981F, 0.9714082859F, 0.9715110151F, 0.9716134862F,
+ 0.9717156993F, 0.9718176549F, 0.9719193532F, 0.9720207946F,
+ 0.9721219794F, 0.9722229080F, 0.9723235806F, 0.9724239976F,
+ 0.9725241593F, 0.9726240661F, 0.9727237183F, 0.9728231161F,
+ 0.9729222601F, 0.9730211503F, 0.9731197873F, 0.9732181713F,
+ 0.9733163027F, 0.9734141817F, 0.9735118088F, 0.9736091842F,
+ 0.9737063083F, 0.9738031814F, 0.9738998039F, 0.9739961760F,
+ 0.9740922981F, 0.9741881706F, 0.9742837938F, 0.9743791680F,
+ 0.9744742935F, 0.9745691707F, 0.9746637999F, 0.9747581814F,
+ 0.9748523157F, 0.9749462029F, 0.9750398435F, 0.9751332378F,
+ 0.9752263861F, 0.9753192887F, 0.9754119461F, 0.9755043585F,
+ 0.9755965262F, 0.9756884496F, 0.9757801291F, 0.9758715650F,
+ 0.9759627575F, 0.9760537071F, 0.9761444141F, 0.9762348789F,
+ 0.9763251016F, 0.9764150828F, 0.9765048228F, 0.9765943218F,
+ 0.9766835802F, 0.9767725984F, 0.9768613767F, 0.9769499154F,
+ 0.9770382149F, 0.9771262755F, 0.9772140976F, 0.9773016815F,
+ 0.9773890275F, 0.9774761360F, 0.9775630073F, 0.9776496418F,
+ 0.9777360398F, 0.9778222016F, 0.9779081277F, 0.9779938182F,
+ 0.9780792736F, 0.9781644943F, 0.9782494805F, 0.9783342326F,
+ 0.9784187509F, 0.9785030359F, 0.9785870877F, 0.9786709069F,
+ 0.9787544936F, 0.9788378484F, 0.9789209714F, 0.9790038631F,
+ 0.9790865238F, 0.9791689538F, 0.9792511535F, 0.9793331232F,
+ 0.9794148633F, 0.9794963742F, 0.9795776561F, 0.9796587094F,
+ 0.9797395345F, 0.9798201316F, 0.9799005013F, 0.9799806437F,
+ 0.9800605593F, 0.9801402483F, 0.9802197112F, 0.9802989483F,
+ 0.9803779600F, 0.9804567465F, 0.9805353082F, 0.9806136455F,
+ 0.9806917587F, 0.9807696482F, 0.9808473143F, 0.9809247574F,
+ 0.9810019778F, 0.9810789759F, 0.9811557519F, 0.9812323064F,
+ 0.9813086395F, 0.9813847517F, 0.9814606433F, 0.9815363147F,
+ 0.9816117662F, 0.9816869981F, 0.9817620108F, 0.9818368047F,
+ 0.9819113801F, 0.9819857374F, 0.9820598769F, 0.9821337989F,
+ 0.9822075038F, 0.9822809920F, 0.9823542638F, 0.9824273195F,
+ 0.9825001596F, 0.9825727843F, 0.9826451940F, 0.9827173891F,
+ 0.9827893700F, 0.9828611368F, 0.9829326901F, 0.9830040302F,
+ 0.9830751574F, 0.9831460720F, 0.9832167745F, 0.9832872652F,
+ 0.9833575444F, 0.9834276124F, 0.9834974697F, 0.9835671166F,
+ 0.9836365535F, 0.9837057806F, 0.9837747983F, 0.9838436071F,
+ 0.9839122072F, 0.9839805990F, 0.9840487829F, 0.9841167591F,
+ 0.9841845282F, 0.9842520903F, 0.9843194459F, 0.9843865953F,
+ 0.9844535389F, 0.9845202771F, 0.9845868101F, 0.9846531383F,
+ 0.9847192622F, 0.9847851820F, 0.9848508980F, 0.9849164108F,
+ 0.9849817205F, 0.9850468276F, 0.9851117324F, 0.9851764352F,
+ 0.9852409365F, 0.9853052366F, 0.9853693358F, 0.9854332344F,
+ 0.9854969330F, 0.9855604317F, 0.9856237309F, 0.9856868310F,
+ 0.9857497325F, 0.9858124355F, 0.9858749404F, 0.9859372477F,
+ 0.9859993577F, 0.9860612707F, 0.9861229871F, 0.9861845072F,
+ 0.9862458315F, 0.9863069601F, 0.9863678936F, 0.9864286322F,
+ 0.9864891764F, 0.9865495264F, 0.9866096826F, 0.9866696454F,
+ 0.9867294152F, 0.9867889922F, 0.9868483769F, 0.9869075695F,
+ 0.9869665706F, 0.9870253803F, 0.9870839991F, 0.9871424273F,
+ 0.9872006653F, 0.9872587135F, 0.9873165721F, 0.9873742415F,
+ 0.9874317222F, 0.9874890144F, 0.9875461185F, 0.9876030348F,
+ 0.9876597638F, 0.9877163057F, 0.9877726610F, 0.9878288300F,
+ 0.9878848130F, 0.9879406104F, 0.9879962225F, 0.9880516497F,
+ 0.9881068924F, 0.9881619509F, 0.9882168256F, 0.9882715168F,
+ 0.9883260249F, 0.9883803502F, 0.9884344931F, 0.9884884539F,
+ 0.9885422331F, 0.9885958309F, 0.9886492477F, 0.9887024838F,
+ 0.9887555397F, 0.9888084157F, 0.9888611120F, 0.9889136292F,
+ 0.9889659675F, 0.9890181273F, 0.9890701089F, 0.9891219128F,
+ 0.9891735392F, 0.9892249885F, 0.9892762610F, 0.9893273572F,
+ 0.9893782774F, 0.9894290219F, 0.9894795911F, 0.9895299853F,
+ 0.9895802049F, 0.9896302502F, 0.9896801217F, 0.9897298196F,
+ 0.9897793443F, 0.9898286961F, 0.9898778755F, 0.9899268828F,
+ 0.9899757183F, 0.9900243823F, 0.9900728753F, 0.9901211976F,
+ 0.9901693495F, 0.9902173314F, 0.9902651436F, 0.9903127865F,
+ 0.9903602605F, 0.9904075659F, 0.9904547031F, 0.9905016723F,
+ 0.9905484740F, 0.9905951086F, 0.9906415763F, 0.9906878775F,
+ 0.9907340126F, 0.9907799819F, 0.9908257858F, 0.9908714247F,
+ 0.9909168988F, 0.9909622086F, 0.9910073543F, 0.9910523364F,
+ 0.9910971552F, 0.9911418110F, 0.9911863042F, 0.9912306351F,
+ 0.9912748042F, 0.9913188117F, 0.9913626580F, 0.9914063435F,
+ 0.9914498684F, 0.9914932333F, 0.9915364383F, 0.9915794839F,
+ 0.9916223703F, 0.9916650981F, 0.9917076674F, 0.9917500787F,
+ 0.9917923323F, 0.9918344286F, 0.9918763679F, 0.9919181505F,
+ 0.9919597769F, 0.9920012473F, 0.9920425621F, 0.9920837217F,
+ 0.9921247263F, 0.9921655765F, 0.9922062724F, 0.9922468145F,
+ 0.9922872030F, 0.9923274385F, 0.9923675211F, 0.9924074513F,
+ 0.9924472294F, 0.9924868557F, 0.9925263306F, 0.9925656544F,
+ 0.9926048275F, 0.9926438503F, 0.9926827230F, 0.9927214461F,
+ 0.9927600199F, 0.9927984446F, 0.9928367208F, 0.9928748486F,
+ 0.9929128285F, 0.9929506608F, 0.9929883459F, 0.9930258841F,
+ 0.9930632757F, 0.9931005211F, 0.9931376207F, 0.9931745747F,
+ 0.9932113836F, 0.9932480476F, 0.9932845671F, 0.9933209425F,
+ 0.9933571742F, 0.9933932623F, 0.9934292074F, 0.9934650097F,
+ 0.9935006696F, 0.9935361874F, 0.9935715635F, 0.9936067982F,
+ 0.9936418919F, 0.9936768448F, 0.9937116574F, 0.9937463300F,
+ 0.9937808629F, 0.9938152565F, 0.9938495111F, 0.9938836271F,
+ 0.9939176047F, 0.9939514444F, 0.9939851465F, 0.9940187112F,
+ 0.9940521391F, 0.9940854303F, 0.9941185853F, 0.9941516044F,
+ 0.9941844879F, 0.9942172361F, 0.9942498495F, 0.9942823283F,
+ 0.9943146729F, 0.9943468836F, 0.9943789608F, 0.9944109047F,
+ 0.9944427158F, 0.9944743944F, 0.9945059408F, 0.9945373553F,
+ 0.9945686384F, 0.9945997902F, 0.9946308112F, 0.9946617017F,
+ 0.9946924621F, 0.9947230926F, 0.9947535937F, 0.9947839656F,
+ 0.9948142086F, 0.9948443232F, 0.9948743097F, 0.9949041683F,
+ 0.9949338995F, 0.9949635035F, 0.9949929807F, 0.9950223315F,
+ 0.9950515561F, 0.9950806549F, 0.9951096282F, 0.9951384764F,
+ 0.9951671998F, 0.9951957987F, 0.9952242735F, 0.9952526245F,
+ 0.9952808520F, 0.9953089564F, 0.9953369380F, 0.9953647971F,
+ 0.9953925340F, 0.9954201491F, 0.9954476428F, 0.9954750153F,
+ 0.9955022670F, 0.9955293981F, 0.9955564092F, 0.9955833003F,
+ 0.9956100720F, 0.9956367245F, 0.9956632582F, 0.9956896733F,
+ 0.9957159703F, 0.9957421494F, 0.9957682110F, 0.9957941553F,
+ 0.9958199828F, 0.9958456937F, 0.9958712884F, 0.9958967672F,
+ 0.9959221305F, 0.9959473784F, 0.9959725115F, 0.9959975300F,
+ 0.9960224342F, 0.9960472244F, 0.9960719011F, 0.9960964644F,
+ 0.9961209148F, 0.9961452525F, 0.9961694779F, 0.9961935913F,
+ 0.9962175930F, 0.9962414834F, 0.9962652627F, 0.9962889313F,
+ 0.9963124895F, 0.9963359377F, 0.9963592761F, 0.9963825051F,
+ 0.9964056250F, 0.9964286361F, 0.9964515387F, 0.9964743332F,
+ 0.9964970198F, 0.9965195990F, 0.9965420709F, 0.9965644360F,
+ 0.9965866946F, 0.9966088469F, 0.9966308932F, 0.9966528340F,
+ 0.9966746695F, 0.9966964001F, 0.9967180260F, 0.9967395475F,
+ 0.9967609651F, 0.9967822789F, 0.9968034894F, 0.9968245968F,
+ 0.9968456014F, 0.9968665036F, 0.9968873037F, 0.9969080019F,
+ 0.9969285987F, 0.9969490942F, 0.9969694889F, 0.9969897830F,
+ 0.9970099769F, 0.9970300708F, 0.9970500651F, 0.9970699601F,
+ 0.9970897561F, 0.9971094533F, 0.9971290522F, 0.9971485531F,
+ 0.9971679561F, 0.9971872617F, 0.9972064702F, 0.9972255818F,
+ 0.9972445968F, 0.9972635157F, 0.9972823386F, 0.9973010659F,
+ 0.9973196980F, 0.9973382350F, 0.9973566773F, 0.9973750253F,
+ 0.9973932791F, 0.9974114392F, 0.9974295059F, 0.9974474793F,
+ 0.9974653599F, 0.9974831480F, 0.9975008438F, 0.9975184476F,
+ 0.9975359598F, 0.9975533806F, 0.9975707104F, 0.9975879495F,
+ 0.9976050981F, 0.9976221566F, 0.9976391252F, 0.9976560043F,
+ 0.9976727941F, 0.9976894950F, 0.9977061073F, 0.9977226312F,
+ 0.9977390671F, 0.9977554152F, 0.9977716759F, 0.9977878495F,
+ 0.9978039361F, 0.9978199363F, 0.9978358501F, 0.9978516780F,
+ 0.9978674202F, 0.9978830771F, 0.9978986488F, 0.9979141358F,
+ 0.9979295383F, 0.9979448566F, 0.9979600909F, 0.9979752417F,
+ 0.9979903091F, 0.9980052936F, 0.9980201952F, 0.9980350145F,
+ 0.9980497515F, 0.9980644067F, 0.9980789804F, 0.9980934727F,
+ 0.9981078841F, 0.9981222147F, 0.9981364649F, 0.9981506350F,
+ 0.9981647253F, 0.9981787360F, 0.9981926674F, 0.9982065199F,
+ 0.9982202936F, 0.9982339890F, 0.9982476062F, 0.9982611456F,
+ 0.9982746074F, 0.9982879920F, 0.9983012996F, 0.9983145304F,
+ 0.9983276849F, 0.9983407632F, 0.9983537657F, 0.9983666926F,
+ 0.9983795442F, 0.9983923208F, 0.9984050226F, 0.9984176501F,
+ 0.9984302033F, 0.9984426827F, 0.9984550884F, 0.9984674208F,
+ 0.9984796802F, 0.9984918667F, 0.9985039808F, 0.9985160227F,
+ 0.9985279926F, 0.9985398909F, 0.9985517177F, 0.9985634734F,
+ 0.9985751583F, 0.9985867727F, 0.9985983167F, 0.9986097907F,
+ 0.9986211949F, 0.9986325297F, 0.9986437953F, 0.9986549919F,
+ 0.9986661199F, 0.9986771795F, 0.9986881710F, 0.9986990946F,
+ 0.9987099507F, 0.9987207394F, 0.9987314611F, 0.9987421161F,
+ 0.9987527045F, 0.9987632267F, 0.9987736829F, 0.9987840734F,
+ 0.9987943985F, 0.9988046584F, 0.9988148534F, 0.9988249838F,
+ 0.9988350498F, 0.9988450516F, 0.9988549897F, 0.9988648641F,
+ 0.9988746753F, 0.9988844233F, 0.9988941086F, 0.9989037313F,
+ 0.9989132918F, 0.9989227902F, 0.9989322269F, 0.9989416021F,
+ 0.9989509160F, 0.9989601690F, 0.9989693613F, 0.9989784931F,
+ 0.9989875647F, 0.9989965763F, 0.9990055283F, 0.9990144208F,
+ 0.9990232541F, 0.9990320286F, 0.9990407443F, 0.9990494016F,
+ 0.9990580008F, 0.9990665421F, 0.9990750257F, 0.9990834519F,
+ 0.9990918209F, 0.9991001331F, 0.9991083886F, 0.9991165877F,
+ 0.9991247307F, 0.9991328177F, 0.9991408491F, 0.9991488251F,
+ 0.9991567460F, 0.9991646119F, 0.9991724232F, 0.9991801801F,
+ 0.9991878828F, 0.9991955316F, 0.9992031267F, 0.9992106684F,
+ 0.9992181569F, 0.9992255925F, 0.9992329753F, 0.9992403057F,
+ 0.9992475839F, 0.9992548101F, 0.9992619846F, 0.9992691076F,
+ 0.9992761793F, 0.9992832001F, 0.9992901701F, 0.9992970895F,
+ 0.9993039587F, 0.9993107777F, 0.9993175470F, 0.9993242667F,
+ 0.9993309371F, 0.9993375583F, 0.9993441307F, 0.9993506545F,
+ 0.9993571298F, 0.9993635570F, 0.9993699362F, 0.9993762678F,
+ 0.9993825519F, 0.9993887887F, 0.9993949785F, 0.9994011216F,
+ 0.9994072181F, 0.9994132683F, 0.9994192725F, 0.9994252307F,
+ 0.9994311434F, 0.9994370107F, 0.9994428327F, 0.9994486099F,
+ 0.9994543423F, 0.9994600303F, 0.9994656739F, 0.9994712736F,
+ 0.9994768294F, 0.9994823417F, 0.9994878105F, 0.9994932363F,
+ 0.9994986191F, 0.9995039592F, 0.9995092568F, 0.9995145122F,
+ 0.9995197256F, 0.9995248971F, 0.9995300270F, 0.9995351156F,
+ 0.9995401630F, 0.9995451695F, 0.9995501352F, 0.9995550604F,
+ 0.9995599454F, 0.9995647903F, 0.9995695953F, 0.9995743607F,
+ 0.9995790866F, 0.9995837734F, 0.9995884211F, 0.9995930300F,
+ 0.9995976004F, 0.9996021324F, 0.9996066263F, 0.9996110822F,
+ 0.9996155004F, 0.9996198810F, 0.9996242244F, 0.9996285306F,
+ 0.9996327999F, 0.9996370326F, 0.9996412287F, 0.9996453886F,
+ 0.9996495125F, 0.9996536004F, 0.9996576527F, 0.9996616696F,
+ 0.9996656512F, 0.9996695977F, 0.9996735094F, 0.9996773865F,
+ 0.9996812291F, 0.9996850374F, 0.9996888118F, 0.9996925523F,
+ 0.9996962591F, 0.9996999325F, 0.9997035727F, 0.9997071798F,
+ 0.9997107541F, 0.9997142957F, 0.9997178049F, 0.9997212818F,
+ 0.9997247266F, 0.9997281396F, 0.9997315209F, 0.9997348708F,
+ 0.9997381893F, 0.9997414767F, 0.9997447333F, 0.9997479591F,
+ 0.9997511544F, 0.9997543194F, 0.9997574542F, 0.9997605591F,
+ 0.9997636342F, 0.9997666797F, 0.9997696958F, 0.9997726828F,
+ 0.9997756407F, 0.9997785698F, 0.9997814703F, 0.9997843423F,
+ 0.9997871860F, 0.9997900016F, 0.9997927894F, 0.9997955494F,
+ 0.9997982818F, 0.9998009869F, 0.9998036648F, 0.9998063157F,
+ 0.9998089398F, 0.9998115373F, 0.9998141082F, 0.9998166529F,
+ 0.9998191715F, 0.9998216642F, 0.9998241311F, 0.9998265724F,
+ 0.9998289884F, 0.9998313790F, 0.9998337447F, 0.9998360854F,
+ 0.9998384015F, 0.9998406930F, 0.9998429602F, 0.9998452031F,
+ 0.9998474221F, 0.9998496171F, 0.9998517885F, 0.9998539364F,
+ 0.9998560610F, 0.9998581624F, 0.9998602407F, 0.9998622962F,
+ 0.9998643291F, 0.9998663394F, 0.9998683274F, 0.9998702932F,
+ 0.9998722370F, 0.9998741589F, 0.9998760591F, 0.9998779378F,
+ 0.9998797952F, 0.9998816313F, 0.9998834464F, 0.9998852406F,
+ 0.9998870141F, 0.9998887670F, 0.9998904995F, 0.9998922117F,
+ 0.9998939039F, 0.9998955761F, 0.9998972285F, 0.9998988613F,
+ 0.9999004746F, 0.9999020686F, 0.9999036434F, 0.9999051992F,
+ 0.9999067362F, 0.9999082544F, 0.9999097541F, 0.9999112354F,
+ 0.9999126984F, 0.9999141433F, 0.9999155703F, 0.9999169794F,
+ 0.9999183709F, 0.9999197449F, 0.9999211014F, 0.9999224408F,
+ 0.9999237631F, 0.9999250684F, 0.9999263570F, 0.9999276289F,
+ 0.9999288843F, 0.9999301233F, 0.9999313461F, 0.9999325529F,
+ 0.9999337437F, 0.9999349187F, 0.9999360780F, 0.9999372218F,
+ 0.9999383503F, 0.9999394635F, 0.9999405616F, 0.9999416447F,
+ 0.9999427129F, 0.9999437665F, 0.9999448055F, 0.9999458301F,
+ 0.9999468404F, 0.9999478365F, 0.9999488185F, 0.9999497867F,
+ 0.9999507411F, 0.9999516819F, 0.9999526091F, 0.9999535230F,
+ 0.9999544236F, 0.9999553111F, 0.9999561856F, 0.9999570472F,
+ 0.9999578960F, 0.9999587323F, 0.9999595560F, 0.9999603674F,
+ 0.9999611666F, 0.9999619536F, 0.9999627286F, 0.9999634917F,
+ 0.9999642431F, 0.9999649828F, 0.9999657110F, 0.9999664278F,
+ 0.9999671334F, 0.9999678278F, 0.9999685111F, 0.9999691835F,
+ 0.9999698451F, 0.9999704960F, 0.9999711364F, 0.9999717662F,
+ 0.9999723858F, 0.9999729950F, 0.9999735942F, 0.9999741834F,
+ 0.9999747626F, 0.9999753321F, 0.9999758919F, 0.9999764421F,
+ 0.9999769828F, 0.9999775143F, 0.9999780364F, 0.9999785495F,
+ 0.9999790535F, 0.9999795485F, 0.9999800348F, 0.9999805124F,
+ 0.9999809813F, 0.9999814417F, 0.9999818938F, 0.9999823375F,
+ 0.9999827731F, 0.9999832005F, 0.9999836200F, 0.9999840316F,
+ 0.9999844353F, 0.9999848314F, 0.9999852199F, 0.9999856008F,
+ 0.9999859744F, 0.9999863407F, 0.9999866997F, 0.9999870516F,
+ 0.9999873965F, 0.9999877345F, 0.9999880656F, 0.9999883900F,
+ 0.9999887078F, 0.9999890190F, 0.9999893237F, 0.9999896220F,
+ 0.9999899140F, 0.9999901999F, 0.9999904796F, 0.9999907533F,
+ 0.9999910211F, 0.9999912830F, 0.9999915391F, 0.9999917896F,
+ 0.9999920345F, 0.9999922738F, 0.9999925077F, 0.9999927363F,
+ 0.9999929596F, 0.9999931777F, 0.9999933907F, 0.9999935987F,
+ 0.9999938018F, 0.9999940000F, 0.9999941934F, 0.9999943820F,
+ 0.9999945661F, 0.9999947456F, 0.9999949206F, 0.9999950912F,
+ 0.9999952575F, 0.9999954195F, 0.9999955773F, 0.9999957311F,
+ 0.9999958807F, 0.9999960265F, 0.9999961683F, 0.9999963063F,
+ 0.9999964405F, 0.9999965710F, 0.9999966979F, 0.9999968213F,
+ 0.9999969412F, 0.9999970576F, 0.9999971707F, 0.9999972805F,
+ 0.9999973871F, 0.9999974905F, 0.9999975909F, 0.9999976881F,
+ 0.9999977824F, 0.9999978738F, 0.9999979624F, 0.9999980481F,
+ 0.9999981311F, 0.9999982115F, 0.9999982892F, 0.9999983644F,
+ 0.9999984370F, 0.9999985072F, 0.9999985750F, 0.9999986405F,
+ 0.9999987037F, 0.9999987647F, 0.9999988235F, 0.9999988802F,
+ 0.9999989348F, 0.9999989873F, 0.9999990379F, 0.9999990866F,
+ 0.9999991334F, 0.9999991784F, 0.9999992217F, 0.9999992632F,
+ 0.9999993030F, 0.9999993411F, 0.9999993777F, 0.9999994128F,
+ 0.9999994463F, 0.9999994784F, 0.9999995091F, 0.9999995384F,
+ 0.9999995663F, 0.9999995930F, 0.9999996184F, 0.9999996426F,
+ 0.9999996657F, 0.9999996876F, 0.9999997084F, 0.9999997282F,
+ 0.9999997469F, 0.9999997647F, 0.9999997815F, 0.9999997973F,
+ 0.9999998123F, 0.9999998265F, 0.9999998398F, 0.9999998524F,
+ 0.9999998642F, 0.9999998753F, 0.9999998857F, 0.9999998954F,
+ 0.9999999045F, 0.9999999130F, 0.9999999209F, 0.9999999282F,
+ 0.9999999351F, 0.9999999414F, 0.9999999472F, 0.9999999526F,
+ 0.9999999576F, 0.9999999622F, 0.9999999664F, 0.9999999702F,
+ 0.9999999737F, 0.9999999769F, 0.9999999798F, 0.9999999824F,
+ 0.9999999847F, 0.9999999868F, 0.9999999887F, 0.9999999904F,
+ 0.9999999919F, 0.9999999932F, 0.9999999943F, 0.9999999953F,
+ 0.9999999961F, 0.9999999969F, 0.9999999975F, 0.9999999980F,
+ 0.9999999985F, 0.9999999988F, 0.9999999991F, 0.9999999993F,
+ 0.9999999995F, 0.9999999997F, 0.9999999998F, 0.9999999999F,
+ 0.9999999999F, 1.0000000000F, 1.0000000000F, 1.0000000000F,
+ 1.0000000000F, 1.0000000000F, 1.0000000000F, 1.0000000000F,
+};
+
+static const float *const vwin[8] = {
+ vwin64,
+ vwin128,
+ vwin256,
+ vwin512,
+ vwin1024,
+ vwin2048,
+ vwin4096,
+ vwin8192,
+};
+
+const float *_vorbis_window_get(int n){
+ return vwin[n];
+}
+
+void _vorbis_apply_window(float *d,int *winno,long *blocksizes,
+ int lW,int W,int nW){
+ lW=(W?lW:0);
+ nW=(W?nW:0);
+
+ {
+ const float *windowLW=vwin[winno[lW]];
+ const float *windowNW=vwin[winno[nW]];
+
+ long n=blocksizes[W];
+ long ln=blocksizes[lW];
+ long rn=blocksizes[nW];
+
+ long leftbegin=n/4-ln/4;
+ long leftend=leftbegin+ln/2;
+
+ long rightbegin=n/2+n/4-rn/4;
+ long rightend=rightbegin+rn/2;
+
+ int i,p;
+
+ for(i=0;i<leftbegin;i++)
+ d[i]=0.f;
+
+ for(p=0;i<leftend;i++,p++)
+ d[i]*=windowLW[p];
+
+ for(i=rightbegin,p=rn/2-1;i<rightend;i++,p--)
+ d[i]*=windowNW[p];
+
+ for(;i<n;i++)
+ d[i]=0.f;
+ }
+}
diff --git a/external/libvorbis-1.3.5/lib/window.h b/external/libvorbis-1.3.5/lib/window.h
new file mode 100644
index 0000000..51f9759
--- /dev/null
+++ b/external/libvorbis-1.3.5/lib/window.h
@@ -0,0 +1,26 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: window functions
+ last mod: $Id: window.h 19028 2013-12-02 23:23:39Z tterribe $
+
+ ********************************************************************/
+
+#ifndef _V_WINDOW_
+#define _V_WINDOW_
+
+extern const float *_vorbis_window_get(int n);
+extern void _vorbis_apply_window(float *d,int *winno,long *blocksizes,
+ int lW,int W,int nW);
+
+
+#endif
diff --git a/external/lua-5.3.3/CMakeLists.txt b/external/lua-5.3.3/CMakeLists.txt
new file mode 100644
index 0000000..6de86af
--- /dev/null
+++ b/external/lua-5.3.3/CMakeLists.txt
@@ -0,0 +1,55 @@
+
+add_library( lua STATIC
+ src/lapi.c
+ src/lcode.c
+ src/lctype.c
+ src/ldebug.c
+ src/ldo.c
+ src/ldump.c
+ src/lfunc.c
+ src/lgc.c
+ src/llex.c
+ src/lmem.c
+ src/lobject.c
+ src/lopcodes.c
+ src/lparser.c
+ src/lstate.c
+ src/lstring.c
+ src/ltable.c
+ src/ltm.c
+ src/lundump.c
+ src/lvm.c
+ src/lzio.c
+ src/lauxlib.c
+ src/lbaselib.c
+ src/lbitlib.c
+ src/lcorolib.c
+ src/ldblib.c
+ src/liolib.c
+ src/lmathlib.c
+ src/loslib.c
+ src/lstrlib.c
+ src/ltablib.c
+ src/lutf8lib.c
+ src/loadlib.c
+ src/linit.c
+ )
+
+if(APPLE)
+ add_definitions(-DLUA_USE_MACOSX)
+endif(APPLE)
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ add_definitions(-DLUA_USE_LINUX)
+endif()
+
+add_definitions (
+ -DLUA_COMPAT_5_2
+ -DNDEBUG
+ -mfpmath=sse
+ -ffast-math
+ )
+
+include_directories (
+ include
+ )
diff --git a/external/lua-5.3.3/README b/external/lua-5.3.3/README
new file mode 100644
index 0000000..e84d9ac
--- /dev/null
+++ b/external/lua-5.3.3/README
@@ -0,0 +1,6 @@
+
+This is Lua 5.3.3, released on 30 May 2016.
+
+For installation instructions, license details, and
+further information about Lua, see doc/readme.html.
+
diff --git a/external/lua-5.3.3/include/lauxlib.h b/external/lua-5.3.3/include/lauxlib.h
new file mode 100644
index 0000000..ddb7c22
--- /dev/null
+++ b/external/lua-5.3.3/include/lauxlib.h
@@ -0,0 +1,256 @@
+/*
+** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lauxlib_h
+#define lauxlib_h
+
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "lua.h"
+
+
+
+/* extra error code for 'luaL_load' */
+#define LUA_ERRFILE (LUA_ERRERR+1)
+
+
+typedef struct luaL_Reg {
+ const char *name;
+ lua_CFunction func;
+} luaL_Reg;
+
+
+#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number))
+
+LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);
+#define luaL_checkversion(L) \
+ luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)
+
+LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
+LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
+LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
+LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
+LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
+ size_t *l);
+LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
+ const char *def, size_t *l);
+LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
+LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
+
+LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
+LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
+ lua_Integer def);
+
+LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
+LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
+LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
+
+LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
+LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
+LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
+LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
+
+LUALIB_API void (luaL_where) (lua_State *L, int lvl);
+LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
+
+LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
+ const char *const lst[]);
+
+LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
+LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
+
+/* predefined references */
+#define LUA_NOREF (-2)
+#define LUA_REFNIL (-1)
+
+LUALIB_API int (luaL_ref) (lua_State *L, int t);
+LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
+
+LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
+ const char *mode);
+
+#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
+
+LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
+ const char *name, const char *mode);
+LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
+
+LUALIB_API lua_State *(luaL_newstate) (void);
+
+LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
+
+LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
+ const char *r);
+
+LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
+
+LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
+
+LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
+ const char *msg, int level);
+
+LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
+ lua_CFunction openf, int glb);
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+
+#define luaL_newlibtable(L,l) \
+ lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
+
+#define luaL_newlib(L,l) \
+ (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
+
+#define luaL_argcheck(L, cond,arg,extramsg) \
+ ((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
+#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
+#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
+
+#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
+
+#define luaL_dofile(L, fn) \
+ (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_dostring(L, s) \
+ (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
+
+#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
+
+#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+typedef struct luaL_Buffer {
+ char *b; /* buffer address */
+ size_t size; /* buffer size */
+ size_t n; /* number of characters in buffer */
+ lua_State *L;
+ char initb[LUAL_BUFFERSIZE]; /* initial buffer */
+} luaL_Buffer;
+
+
+#define luaL_addchar(B,c) \
+ ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
+ ((B)->b[(B)->n++] = (c)))
+
+#define luaL_addsize(B,s) ((B)->n += (s))
+
+LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
+LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
+LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
+LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
+LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
+LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
+
+#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** File handles for IO library
+** =======================================================
+*/
+
+/*
+** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
+** initial structure 'luaL_Stream' (it may contain other fields
+** after that initial structure).
+*/
+
+#define LUA_FILEHANDLE "FILE*"
+
+
+typedef struct luaL_Stream {
+ FILE *f; /* stream (NULL for incompletely created streams) */
+ lua_CFunction closef; /* to close stream (NULL for closed streams) */
+} luaL_Stream;
+
+/* }====================================================== */
+
+
+
+/* compatibility with old module system */
+#if defined(LUA_COMPAT_MODULE)
+
+LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
+ int sizehint);
+LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
+ const luaL_Reg *l, int nup);
+
+#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
+
+#endif
+
+
+/*
+** {==================================================================
+** "Abstraction Layer" for basic report of messages and errors
+** ===================================================================
+*/
+
+/* print a string */
+#if !defined(lua_writestring)
+#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
+#endif
+
+/* print a newline and flush the output */
+#if !defined(lua_writeline)
+#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
+#endif
+
+/* print an error message */
+#if !defined(lua_writestringerror)
+#define lua_writestringerror(s,p) \
+ (fprintf(stderr, (s), (p)), fflush(stderr))
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {============================================================
+** Compatibility with deprecated conversions
+** =============================================================
+*/
+#if defined(LUA_COMPAT_APIINTCASTS)
+
+#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a))
+#define luaL_optunsigned(L,a,d) \
+ ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))
+
+#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
+#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
+
+#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
+#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
+
+#endif
+/* }============================================================ */
+
+
+
+#endif
+
+
diff --git a/external/lua-5.3.3/include/lua.h b/external/lua-5.3.3/include/lua.h
new file mode 100644
index 0000000..f78899f
--- /dev/null
+++ b/external/lua-5.3.3/include/lua.h
@@ -0,0 +1,486 @@
+/*
+** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $
+** Lua - A Scripting Language
+** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
+** See Copyright Notice at the end of this file
+*/
+
+
+#ifndef lua_h
+#define lua_h
+
+#include <stdarg.h>
+#include <stddef.h>
+
+
+#include "luaconf.h"
+
+
+#define LUA_VERSION_MAJOR "5"
+#define LUA_VERSION_MINOR "3"
+#define LUA_VERSION_NUM 503
+#define LUA_VERSION_RELEASE "3"
+
+#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
+#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 Lua.org, PUC-Rio"
+#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
+
+
+/* mark for precompiled code ('<esc>Lua') */
+#define LUA_SIGNATURE "\x1bLua"
+
+/* option for multiple returns in 'lua_pcall' and 'lua_call' */
+#define LUA_MULTRET (-1)
+
+
+/*
+** Pseudo-indices
+** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
+** space after that to help overflow detection)
+*/
+#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
+#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
+
+
+/* thread status */
+#define LUA_OK 0
+#define LUA_YIELD 1
+#define LUA_ERRRUN 2
+#define LUA_ERRSYNTAX 3
+#define LUA_ERRMEM 4
+#define LUA_ERRGCMM 5
+#define LUA_ERRERR 6
+
+
+typedef struct lua_State lua_State;
+
+
+/*
+** basic types
+*/
+#define LUA_TNONE (-1)
+
+#define LUA_TNIL 0
+#define LUA_TBOOLEAN 1
+#define LUA_TLIGHTUSERDATA 2
+#define LUA_TNUMBER 3
+#define LUA_TSTRING 4
+#define LUA_TTABLE 5
+#define LUA_TFUNCTION 6
+#define LUA_TUSERDATA 7
+#define LUA_TTHREAD 8
+
+#define LUA_NUMTAGS 9
+
+
+
+/* minimum Lua stack available to a C function */
+#define LUA_MINSTACK 20
+
+
+/* predefined values in the registry */
+#define LUA_RIDX_MAINTHREAD 1
+#define LUA_RIDX_GLOBALS 2
+#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
+
+
+/* type of numbers in Lua */
+typedef LUA_NUMBER lua_Number;
+
+
+/* type for integer functions */
+typedef LUA_INTEGER lua_Integer;
+
+/* unsigned integer type */
+typedef LUA_UNSIGNED lua_Unsigned;
+
+/* type for continuation-function contexts */
+typedef LUA_KCONTEXT lua_KContext;
+
+
+/*
+** Type for C functions registered with Lua
+*/
+typedef int (*lua_CFunction) (lua_State *L);
+
+/*
+** Type for continuation functions
+*/
+typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
+
+
+/*
+** Type for functions that read/write blocks when loading/dumping Lua chunks
+*/
+typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
+
+typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);
+
+
+/*
+** Type for memory-allocation functions
+*/
+typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
+
+
+
+/*
+** generic extra include file
+*/
+#if defined(LUA_USER_H)
+#include LUA_USER_H
+#endif
+
+
+/*
+** RCS ident string
+*/
+extern const char lua_ident[];
+
+
+/*
+** state manipulation
+*/
+LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
+LUA_API void (lua_close) (lua_State *L);
+LUA_API lua_State *(lua_newthread) (lua_State *L);
+
+LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
+
+
+LUA_API const lua_Number *(lua_version) (lua_State *L);
+
+
+/*
+** basic stack manipulation
+*/
+LUA_API int (lua_absindex) (lua_State *L, int idx);
+LUA_API int (lua_gettop) (lua_State *L);
+LUA_API void (lua_settop) (lua_State *L, int idx);
+LUA_API void (lua_pushvalue) (lua_State *L, int idx);
+LUA_API void (lua_rotate) (lua_State *L, int idx, int n);
+LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx);
+LUA_API int (lua_checkstack) (lua_State *L, int n);
+
+LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
+
+
+/*
+** access functions (stack -> C)
+*/
+
+LUA_API int (lua_isnumber) (lua_State *L, int idx);
+LUA_API int (lua_isstring) (lua_State *L, int idx);
+LUA_API int (lua_iscfunction) (lua_State *L, int idx);
+LUA_API int (lua_isinteger) (lua_State *L, int idx);
+LUA_API int (lua_isuserdata) (lua_State *L, int idx);
+LUA_API int (lua_type) (lua_State *L, int idx);
+LUA_API const char *(lua_typename) (lua_State *L, int tp);
+
+LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
+LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
+LUA_API int (lua_toboolean) (lua_State *L, int idx);
+LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
+LUA_API size_t (lua_rawlen) (lua_State *L, int idx);
+LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
+LUA_API void *(lua_touserdata) (lua_State *L, int idx);
+LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
+LUA_API const void *(lua_topointer) (lua_State *L, int idx);
+
+
+/*
+** Comparison and arithmetic functions
+*/
+
+#define LUA_OPADD 0 /* ORDER TM, ORDER OP */
+#define LUA_OPSUB 1
+#define LUA_OPMUL 2
+#define LUA_OPMOD 3
+#define LUA_OPPOW 4
+#define LUA_OPDIV 5
+#define LUA_OPIDIV 6
+#define LUA_OPBAND 7
+#define LUA_OPBOR 8
+#define LUA_OPBXOR 9
+#define LUA_OPSHL 10
+#define LUA_OPSHR 11
+#define LUA_OPUNM 12
+#define LUA_OPBNOT 13
+
+LUA_API void (lua_arith) (lua_State *L, int op);
+
+#define LUA_OPEQ 0
+#define LUA_OPLT 1
+#define LUA_OPLE 2
+
+LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
+LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op);
+
+
+/*
+** push functions (C -> stack)
+*/
+LUA_API void (lua_pushnil) (lua_State *L);
+LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
+LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
+LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
+LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
+LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
+ va_list argp);
+LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
+LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
+LUA_API void (lua_pushboolean) (lua_State *L, int b);
+LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
+LUA_API int (lua_pushthread) (lua_State *L);
+
+
+/*
+** get functions (Lua -> stack)
+*/
+LUA_API int (lua_getglobal) (lua_State *L, const char *name);
+LUA_API int (lua_gettable) (lua_State *L, int idx);
+LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
+LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);
+LUA_API int (lua_rawget) (lua_State *L, int idx);
+LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
+LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
+
+LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
+LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
+LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
+LUA_API int (lua_getuservalue) (lua_State *L, int idx);
+
+
+/*
+** set functions (stack -> Lua)
+*/
+LUA_API void (lua_setglobal) (lua_State *L, const char *name);
+LUA_API void (lua_settable) (lua_State *L, int idx);
+LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
+LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n);
+LUA_API void (lua_rawset) (lua_State *L, int idx);
+LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n);
+LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p);
+LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
+LUA_API void (lua_setuservalue) (lua_State *L, int idx);
+
+
+/*
+** 'load' and 'call' functions (load and run Lua code)
+*/
+LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults,
+ lua_KContext ctx, lua_KFunction k);
+#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
+
+LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
+ lua_KContext ctx, lua_KFunction k);
+#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
+
+LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
+ const char *chunkname, const char *mode);
+
+LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
+
+
+/*
+** coroutine functions
+*/
+LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx,
+ lua_KFunction k);
+LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg);
+LUA_API int (lua_status) (lua_State *L);
+LUA_API int (lua_isyieldable) (lua_State *L);
+
+#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
+
+
+/*
+** garbage-collection function and options
+*/
+
+#define LUA_GCSTOP 0
+#define LUA_GCRESTART 1
+#define LUA_GCCOLLECT 2
+#define LUA_GCCOUNT 3
+#define LUA_GCCOUNTB 4
+#define LUA_GCSTEP 5
+#define LUA_GCSETPAUSE 6
+#define LUA_GCSETSTEPMUL 7
+#define LUA_GCISRUNNING 9
+
+LUA_API int (lua_gc) (lua_State *L, int what, int data);
+
+
+/*
+** miscellaneous functions
+*/
+
+LUA_API int (lua_error) (lua_State *L);
+
+LUA_API int (lua_next) (lua_State *L, int idx);
+
+LUA_API void (lua_concat) (lua_State *L, int n);
+LUA_API void (lua_len) (lua_State *L, int idx);
+
+LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
+
+LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
+LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
+
+
+
+/*
+** {==============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE))
+
+#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL)
+#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL)
+
+#define lua_pop(L,n) lua_settop(L, -(n)-1)
+
+#define lua_newtable(L) lua_createtable(L, 0, 0)
+
+#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
+
+#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
+
+#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
+#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
+#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
+#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
+#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
+#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
+#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
+#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
+
+#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
+
+#define lua_pushglobaltable(L) \
+ ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
+
+#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
+
+
+#define lua_insert(L,idx) lua_rotate(L, (idx), 1)
+
+#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
+
+#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))
+
+/* }============================================================== */
+
+
+/*
+** {==============================================================
+** compatibility macros for unsigned conversions
+** ===============================================================
+*/
+#if defined(LUA_COMPAT_APIINTCASTS)
+
+#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
+#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is))
+#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL)
+
+#endif
+/* }============================================================== */
+
+/*
+** {======================================================================
+** Debug API
+** =======================================================================
+*/
+
+
+/*
+** Event codes
+*/
+#define LUA_HOOKCALL 0
+#define LUA_HOOKRET 1
+#define LUA_HOOKLINE 2
+#define LUA_HOOKCOUNT 3
+#define LUA_HOOKTAILCALL 4
+
+
+/*
+** Event masks
+*/
+#define LUA_MASKCALL (1 << LUA_HOOKCALL)
+#define LUA_MASKRET (1 << LUA_HOOKRET)
+#define LUA_MASKLINE (1 << LUA_HOOKLINE)
+#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
+
+typedef struct lua_Debug lua_Debug; /* activation record */
+
+
+/* Functions to be called by the debugger in specific events */
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
+
+
+LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
+LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
+LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n);
+LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n);
+
+LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n);
+LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,
+ int fidx2, int n2);
+
+LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
+LUA_API lua_Hook (lua_gethook) (lua_State *L);
+LUA_API int (lua_gethookmask) (lua_State *L);
+LUA_API int (lua_gethookcount) (lua_State *L);
+
+
+struct lua_Debug {
+ int event;
+ const char *name; /* (n) */
+ const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */
+ const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */
+ const char *source; /* (S) */
+ int currentline; /* (l) */
+ int linedefined; /* (S) */
+ int lastlinedefined; /* (S) */
+ unsigned char nups; /* (u) number of upvalues */
+ unsigned char nparams;/* (u) number of parameters */
+ char isvararg; /* (u) */
+ char istailcall; /* (t) */
+ char short_src[LUA_IDSIZE]; /* (S) */
+ /* private part */
+ struct CallInfo *i_ci; /* active function */
+};
+
+/* }====================================================================== */
+
+
+/******************************************************************************
+* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
+*
+* 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+******************************************************************************/
+
+
+#endif
diff --git a/external/lua-5.3.3/include/lua.hpp b/external/lua-5.3.3/include/lua.hpp
new file mode 100644
index 0000000..ec417f5
--- /dev/null
+++ b/external/lua-5.3.3/include/lua.hpp
@@ -0,0 +1,9 @@
+// lua.hpp
+// Lua header files for C++
+// <<extern "C">> not supplied automatically because Lua also compiles as C++
+
+extern "C" {
+#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
+}
diff --git a/external/lua-5.3.3/include/luaconf.h b/external/lua-5.3.3/include/luaconf.h
new file mode 100644
index 0000000..fd447cc
--- /dev/null
+++ b/external/lua-5.3.3/include/luaconf.h
@@ -0,0 +1,767 @@
+/*
+** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $
+** Configuration file for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef luaconf_h
+#define luaconf_h
+
+#include <limits.h>
+#include <stddef.h>
+
+
+/*
+** ===================================================================
+** Search for "@@" to find all configurable definitions.
+** ===================================================================
+*/
+
+
+/*
+** {====================================================================
+** System Configuration: macros to adapt (if needed) Lua to some
+** particular platform, for instance compiling it with 32-bit numbers or
+** restricting it to C89.
+** =====================================================================
+*/
+
+/*
+@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You
+** can also define LUA_32BITS in the make file, but changing here you
+** ensure that all software connected to Lua will be compiled with the
+** same configuration.
+*/
+/* #define LUA_32BITS */
+
+
+/*
+@@ LUA_USE_C89 controls the use of non-ISO-C89 features.
+** Define it if you want Lua to avoid the use of a few C99 features
+** or Windows-specific features on Windows.
+*/
+/* #define LUA_USE_C89 */
+
+
+/*
+** By default, Lua on Windows use (some) specific Windows features
+*/
+#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)
+#define LUA_USE_WINDOWS /* enable goodies for regular Windows */
+#endif
+
+
+#if defined(LUA_USE_WINDOWS)
+#define LUA_DL_DLL /* enable support for DLL */
+#define LUA_USE_C89 /* broadly, Windows is C89 */
+#endif
+
+
+#if defined(LUA_USE_LINUX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
+#define LUA_USE_READLINE /* needs some extra libraries */
+#endif
+
+
+#if defined(LUA_USE_MACOSX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN /* MacOS does not need -ldl */
+#define LUA_USE_READLINE /* needs an extra library: -lreadline */
+#endif
+
+
+/*
+@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
+** C89 ('long' and 'double'); Windows always has '__int64', so it does
+** not need to use this case.
+*/
+#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
+#define LUA_C89_NUMBERS
+#endif
+
+
+
+/*
+@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'.
+*/
+/* avoid undefined shifts */
+#if ((INT_MAX >> 15) >> 15) >= 1
+#define LUAI_BITSINT 32
+#else
+/* 'int' always must have at least 16 bits */
+#define LUAI_BITSINT 16
+#endif
+
+
+/*
+@@ LUA_INT_TYPE defines the type for Lua integers.
+@@ LUA_FLOAT_TYPE defines the type for Lua floats.
+** Lua should work fine with any mix of these options (if supported
+** by your C compiler). The usual configurations are 64-bit integers
+** and 'double' (the default), 32-bit integers and 'float' (for
+** restricted platforms), and 'long'/'double' (for C compilers not
+** compliant with C99, which may not have support for 'long long').
+*/
+
+/* predefined options for LUA_INT_TYPE */
+#define LUA_INT_INT 1
+#define LUA_INT_LONG 2
+#define LUA_INT_LONGLONG 3
+
+/* predefined options for LUA_FLOAT_TYPE */
+#define LUA_FLOAT_FLOAT 1
+#define LUA_FLOAT_DOUBLE 2
+#define LUA_FLOAT_LONGDOUBLE 3
+
+#if defined(LUA_32BITS) /* { */
+/*
+** 32-bit integers and 'float'
+*/
+#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
+#define LUA_INT_TYPE LUA_INT_INT
+#else /* otherwise use 'long' */
+#define LUA_INT_TYPE LUA_INT_LONG
+#endif
+#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
+
+#elif defined(LUA_C89_NUMBERS) /* }{ */
+/*
+** largest types available for C89 ('long' and 'double')
+*/
+#define LUA_INT_TYPE LUA_INT_LONG
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+
+#endif /* } */
+
+
+/*
+** default configuration for 64-bit Lua ('long long' and 'double')
+*/
+#if !defined(LUA_INT_TYPE)
+#define LUA_INT_TYPE LUA_INT_LONGLONG
+#endif
+
+#if !defined(LUA_FLOAT_TYPE)
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+#endif
+
+/* }================================================================== */
+
+
+
+
+/*
+** {==================================================================
+** Configuration for Paths.
+** ===================================================================
+*/
+
+/*
+@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
+** Lua libraries.
+@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
+** C libraries.
+** CHANGE them if your machine has a non-conventional directory
+** hierarchy or if you want to install your libraries in
+** non-conventional directories.
+*/
+#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
+#if defined(_WIN32) /* { */
+/*
+** In Windows, any exclamation mark ('!') in the path is replaced by the
+** path of the directory of the executable file of the current process.
+*/
+#define LUA_LDIR "!\\lua\\"
+#define LUA_CDIR "!\\"
+#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\"
+#define LUA_PATH_DEFAULT \
+ LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
+ LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \
+ ".\\?.lua;" ".\\?\\init.lua"
+#define LUA_CPATH_DEFAULT \
+ LUA_CDIR"?.dll;" \
+ LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
+ LUA_CDIR"loadall.dll;" ".\\?.dll"
+
+#else /* }{ */
+
+#define LUA_ROOT "/usr/local/"
+#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/"
+#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/"
+#define LUA_PATH_DEFAULT \
+ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
+ "./?.lua;" "./?/init.lua"
+#define LUA_CPATH_DEFAULT \
+ LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so"
+#endif /* } */
+
+
+/*
+@@ LUA_DIRSEP is the directory separator (for submodules).
+** CHANGE it if your machine does not use "/" as the directory separator
+** and is not Windows. (On Windows Lua automatically uses "\".)
+*/
+#if defined(_WIN32)
+#define LUA_DIRSEP "\\"
+#else
+#define LUA_DIRSEP "/"
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Marks for exported symbols in the C code
+** ===================================================================
+*/
+
+/*
+@@ LUA_API is a mark for all core API functions.
+@@ LUALIB_API is a mark for all auxiliary library functions.
+@@ LUAMOD_API is a mark for all standard library opening functions.
+** CHANGE them if you need to define those functions in some special way.
+** For instance, if you want to create one Windows DLL with the core and
+** the libraries, you may want to use the following definition (define
+** LUA_BUILD_AS_DLL to get it).
+*/
+#if defined(LUA_BUILD_AS_DLL) /* { */
+
+#if defined(LUA_CORE) || defined(LUA_LIB) /* { */
+#define LUA_API __declspec(dllexport)
+#else /* }{ */
+#define LUA_API __declspec(dllimport)
+#endif /* } */
+
+#else /* }{ */
+
+#define LUA_API extern
+
+#endif /* } */
+
+
+/* more often than not the libs go together with the core */
+#define LUALIB_API LUA_API
+#define LUAMOD_API LUALIB_API
+
+
+/*
+@@ LUAI_FUNC is a mark for all extern functions that are not to be
+** exported to outside modules.
+@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables
+** that are not to be exported to outside modules (LUAI_DDEF for
+** definitions and LUAI_DDEC for declarations).
+** CHANGE them if you need to mark them in some special way. Elf/gcc
+** (versions 3.2 and later) mark them as "hidden" to optimize access
+** when Lua is compiled as a shared library. Not all elf targets support
+** this attribute. Unfortunately, gcc does not offer a way to check
+** whether the target offers that support, and those without support
+** give a warning about it. To avoid these warnings, change to the
+** default definition.
+*/
+#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
+ defined(__ELF__) /* { */
+#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
+#else /* }{ */
+#define LUAI_FUNC extern
+#endif /* } */
+
+#define LUAI_DDEC LUAI_FUNC
+#define LUAI_DDEF /* empty */
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Compatibility with previous versions
+** ===================================================================
+*/
+
+/*
+@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2.
+@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1.
+** You can define it to get all options, or change specific options
+** to fit your specific needs.
+*/
+#if defined(LUA_COMPAT_5_2) /* { */
+
+/*
+@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
+** functions in the mathematical library.
+*/
+#define LUA_COMPAT_MATHLIB
+
+/*
+@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'.
+*/
+#define LUA_COMPAT_BITLIB
+
+/*
+@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod.
+*/
+#define LUA_COMPAT_IPAIRS
+
+/*
+@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for
+** manipulating other integer types (lua_pushunsigned, lua_tounsigned,
+** luaL_checkint, luaL_checklong, etc.)
+*/
+#define LUA_COMPAT_APIINTCASTS
+
+#endif /* } */
+
+
+#if defined(LUA_COMPAT_5_1) /* { */
+
+/* Incompatibilities from 5.2 -> 5.3 */
+#define LUA_COMPAT_MATHLIB
+#define LUA_COMPAT_APIINTCASTS
+
+/*
+@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
+** You can replace it with 'table.unpack'.
+*/
+#define LUA_COMPAT_UNPACK
+
+/*
+@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'.
+** You can replace it with 'package.searchers'.
+*/
+#define LUA_COMPAT_LOADERS
+
+/*
+@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall.
+** You can call your C function directly (with light C functions).
+*/
+#define lua_cpcall(L,f,u) \
+ (lua_pushcfunction(L, (f)), \
+ lua_pushlightuserdata(L,(u)), \
+ lua_pcall(L,1,0,0))
+
+
+/*
+@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library.
+** You can rewrite 'log10(x)' as 'log(x, 10)'.
+*/
+#define LUA_COMPAT_LOG10
+
+/*
+@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base
+** library. You can rewrite 'loadstring(s)' as 'load(s)'.
+*/
+#define LUA_COMPAT_LOADSTRING
+
+/*
+@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library.
+*/
+#define LUA_COMPAT_MAXN
+
+/*
+@@ The following macros supply trivial compatibility for some
+** changes in the API. The macros themselves document how to
+** change your code to avoid using them.
+*/
+#define lua_strlen(L,i) lua_rawlen(L, (i))
+
+#define lua_objlen(L,i) lua_rawlen(L, (i))
+
+#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
+#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
+
+/*
+@@ LUA_COMPAT_MODULE controls compatibility with previous
+** module functions 'module' (Lua) and 'luaL_register' (C).
+*/
+#define LUA_COMPAT_MODULE
+
+#endif /* } */
+
+
+/*
+@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
+@@ a float mark ('.0').
+** This macro is not on by default even in compatibility mode,
+** because this is not really an incompatibility.
+*/
+/* #define LUA_COMPAT_FLOATSTRING */
+
+/* }================================================================== */
+
+
+
+/*
+** {==================================================================
+** Configuration for Numbers.
+** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
+** satisfy your needs.
+** ===================================================================
+*/
+
+/*
+@@ LUA_NUMBER is the floating-point type used by Lua.
+@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
+@@ over a floating number.
+@@ l_mathlim(x) corrects limit name 'x' to the proper float type
+** by prefixing it with one of FLT/DBL/LDBL.
+@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
+@@ LUA_NUMBER_FMT is the format for writing floats.
+@@ lua_number2str converts a float to a string.
+@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
+@@ l_floor takes the floor of a float.
+@@ lua_str2number converts a decimal numeric string to a number.
+*/
+
+
+/* The following definitions are good for most cases here */
+
+#define l_floor(x) (l_mathop(floor)(x))
+
+#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n))
+
+/*
+@@ lua_numbertointeger converts a float number to an integer, or
+** returns 0 if float is not within the range of a lua_Integer.
+** (The range comparisons are tricky because of rounding. The tests
+** here assume a two-complement representation, where MININTEGER always
+** has an exact representation as a float; MAXINTEGER may not have one,
+** and therefore its conversion to float may have an ill-defined value.)
+*/
+#define lua_numbertointeger(n,p) \
+ ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
+ (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
+ (*(p) = (LUA_INTEGER)(n), 1))
+
+
+/* now the variable definitions */
+
+#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
+
+#define LUA_NUMBER float
+
+#define l_mathlim(n) (FLT_##n)
+
+#define LUAI_UACNUMBER double
+
+#define LUA_NUMBER_FRMLEN ""
+#define LUA_NUMBER_FMT "%.7g"
+
+#define l_mathop(op) op##f
+
+#define lua_str2number(s,p) strtof((s), (p))
+
+
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
+
+#define LUA_NUMBER long double
+
+#define l_mathlim(n) (LDBL_##n)
+
+#define LUAI_UACNUMBER long double
+
+#define LUA_NUMBER_FRMLEN "L"
+#define LUA_NUMBER_FMT "%.19Lg"
+
+#define l_mathop(op) op##l
+
+#define lua_str2number(s,p) strtold((s), (p))
+
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
+
+#define LUA_NUMBER double
+
+#define l_mathlim(n) (DBL_##n)
+
+#define LUAI_UACNUMBER double
+
+#define LUA_NUMBER_FRMLEN ""
+#define LUA_NUMBER_FMT "%.14g"
+
+#define l_mathop(op) op
+
+#define lua_str2number(s,p) strtod((s), (p))
+
+#else /* }{ */
+
+#error "numeric float type not defined"
+
+#endif /* } */
+
+
+
+/*
+@@ LUA_INTEGER is the integer type used by Lua.
+**
+@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
+**
+@@ LUAI_UACINT is the result of an 'usual argument conversion'
+@@ over a lUA_INTEGER.
+@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
+@@ LUA_INTEGER_FMT is the format for writing integers.
+@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
+@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
+@@ lua_integer2str converts an integer to a string.
+*/
+
+
+/* The following definitions are good for most cases here */
+
+#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
+#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n))
+
+#define LUAI_UACINT LUA_INTEGER
+
+/*
+** use LUAI_UACINT here to avoid problems with promotions (which
+** can turn a comparison between unsigneds into a signed comparison)
+*/
+#define LUA_UNSIGNED unsigned LUAI_UACINT
+
+
+/* now the variable definitions */
+
+#if LUA_INT_TYPE == LUA_INT_INT /* { int */
+
+#define LUA_INTEGER int
+#define LUA_INTEGER_FRMLEN ""
+
+#define LUA_MAXINTEGER INT_MAX
+#define LUA_MININTEGER INT_MIN
+
+#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
+
+#define LUA_INTEGER long
+#define LUA_INTEGER_FRMLEN "l"
+
+#define LUA_MAXINTEGER LONG_MAX
+#define LUA_MININTEGER LONG_MIN
+
+#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
+
+/* use presence of macro LLONG_MAX as proxy for C99 compliance */
+#if defined(LLONG_MAX) /* { */
+/* use ISO C99 stuff */
+
+#define LUA_INTEGER long long
+#define LUA_INTEGER_FRMLEN "ll"
+
+#define LUA_MAXINTEGER LLONG_MAX
+#define LUA_MININTEGER LLONG_MIN
+
+#elif defined(LUA_USE_WINDOWS) /* }{ */
+/* in Windows, can use specific Windows types */
+
+#define LUA_INTEGER __int64
+#define LUA_INTEGER_FRMLEN "I64"
+
+#define LUA_MAXINTEGER _I64_MAX
+#define LUA_MININTEGER _I64_MIN
+
+#else /* }{ */
+
+#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \
+ or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)"
+
+#endif /* } */
+
+#else /* }{ */
+
+#error "numeric integer type not defined"
+
+#endif /* } */
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Dependencies with C99 and other C details
+** ===================================================================
+*/
+
+/*
+@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
+** (All uses in Lua have only one format item.)
+*/
+#if !defined(LUA_USE_C89)
+#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
+#else
+#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
+#endif
+
+
+/*
+@@ lua_strx2number converts an hexadecimal numeric string to a number.
+** In C99, 'strtod' does that conversion. Otherwise, you can
+** leave 'lua_strx2number' undefined and Lua will provide its own
+** implementation.
+*/
+#if !defined(LUA_USE_C89)
+#define lua_strx2number(s,p) lua_str2number(s,p)
+#endif
+
+
+/*
+@@ lua_number2strx converts a float to an hexadecimal numeric string.
+** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
+** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
+** provide its own implementation.
+*/
+#if !defined(LUA_USE_C89)
+#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n))
+#endif
+
+
+/*
+** 'strtof' and 'opf' variants for math functions are not valid in
+** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the
+** availability of these variants. ('math.h' is already included in
+** all files that use these macros.)
+*/
+#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF))
+#undef l_mathop /* variants not available */
+#undef lua_str2number
+#define l_mathop(op) (lua_Number)op /* no variant */
+#define lua_str2number(s,p) ((lua_Number)strtod((s), (p)))
+#endif
+
+
+/*
+@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation
+** functions. It must be a numerical type; Lua will use 'intptr_t' if
+** available, otherwise it will use 'ptrdiff_t' (the nearest thing to
+** 'intptr_t' in C89)
+*/
+#define LUA_KCONTEXT ptrdiff_t
+
+#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+#if defined(INTPTR_MAX) /* even in C99 this type is optional */
+#undef LUA_KCONTEXT
+#define LUA_KCONTEXT intptr_t
+#endif
+#endif
+
+
+/*
+@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
+** Change that if you do not want to use C locales. (Code using this
+** macro must include header 'locale.h'.)
+*/
+#if !defined(lua_getlocaledecpoint)
+#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Language Variations
+** =====================================================================
+*/
+
+/*
+@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some
+** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from
+** numbers to strings. Define LUA_NOCVTS2N to turn off automatic
+** coercion from strings to numbers.
+*/
+/* #define LUA_NOCVTN2S */
+/* #define LUA_NOCVTS2N */
+
+
+/*
+@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
+** Define it as a help when debugging C code.
+*/
+#if defined(LUA_USE_APICHECK)
+#include <assert.h>
+#define luai_apicheck(l,e) assert(e)
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Macros that affect the API and must be stable (that is, must be the
+** same when you compile Lua and when you compile code that links to
+** Lua). You probably do not want/need to change them.
+** =====================================================================
+*/
+
+/*
+@@ LUAI_MAXSTACK limits the size of the Lua stack.
+** CHANGE it if you need a different limit. This limit is arbitrary;
+** its only purpose is to stop Lua from consuming unlimited stack
+** space (and to reserve some numbers for pseudo-indices).
+*/
+#if LUAI_BITSINT >= 32
+#define LUAI_MAXSTACK 1000000
+#else
+#define LUAI_MAXSTACK 15000
+#endif
+
+
+/*
+@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
+** a Lua state with very fast access.
+** CHANGE it if you need a different size.
+*/
+#define LUA_EXTRASPACE (sizeof(void *))
+
+
+/*
+@@ LUA_IDSIZE gives the maximum size for the description of the source
+@@ of a function in debug information.
+** CHANGE it if you want a different size.
+*/
+#define LUA_IDSIZE 60
+
+
+/*
+@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+** CHANGE it if it uses too much C-stack space. (For long double,
+** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a
+** smaller buffer would force a memory allocation for each call to
+** 'string.format'.)
+*/
+#if defined(LUA_FLOAT_LONGDOUBLE)
+#define LUAL_BUFFERSIZE 8192
+#else
+#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
+#endif
+
+/* }================================================================== */
+
+
+/*
+@@ LUA_QL describes how error messages quote program elements.
+** Lua does not use these macros anymore; they are here for
+** compatibility only.
+*/
+#define LUA_QL(x) "'" x "'"
+#define LUA_QS LUA_QL("%s")
+
+
+
+
+/* =================================================================== */
+
+/*
+** Local configuration. You can use this space to add your redefinitions
+** without modifying the main part of the file.
+*/
+
+
+
+
+
+#endif
+
diff --git a/external/lua-5.3.3/include/lualib.h b/external/lua-5.3.3/include/lualib.h
new file mode 100644
index 0000000..5165c0f
--- /dev/null
+++ b/external/lua-5.3.3/include/lualib.h
@@ -0,0 +1,58 @@
+/*
+** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $
+** Lua standard libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lualib_h
+#define lualib_h
+
+#include "lua.h"
+
+
+
+LUAMOD_API int (luaopen_base) (lua_State *L);
+
+#define LUA_COLIBNAME "coroutine"
+LUAMOD_API int (luaopen_coroutine) (lua_State *L);
+
+#define LUA_TABLIBNAME "table"
+LUAMOD_API int (luaopen_table) (lua_State *L);
+
+#define LUA_IOLIBNAME "io"
+LUAMOD_API int (luaopen_io) (lua_State *L);
+
+#define LUA_OSLIBNAME "os"
+LUAMOD_API int (luaopen_os) (lua_State *L);
+
+#define LUA_STRLIBNAME "string"
+LUAMOD_API int (luaopen_string) (lua_State *L);
+
+#define LUA_UTF8LIBNAME "utf8"
+LUAMOD_API int (luaopen_utf8) (lua_State *L);
+
+#define LUA_BITLIBNAME "bit32"
+LUAMOD_API int (luaopen_bit32) (lua_State *L);
+
+#define LUA_MATHLIBNAME "math"
+LUAMOD_API int (luaopen_math) (lua_State *L);
+
+#define LUA_DBLIBNAME "debug"
+LUAMOD_API int (luaopen_debug) (lua_State *L);
+
+#define LUA_LOADLIBNAME "package"
+LUAMOD_API int (luaopen_package) (lua_State *L);
+
+
+/* open all previous libraries */
+LUALIB_API void (luaL_openlibs) (lua_State *L);
+
+
+
+#if !defined(lua_assert)
+#define lua_assert(x) ((void)0)
+#endif
+
+
+#endif
diff --git a/external/lua-5.3.3/src/lapi.c b/external/lua-5.3.3/src/lapi.c
new file mode 100644
index 0000000..c9455a5
--- /dev/null
+++ b/external/lua-5.3.3/src/lapi.c
@@ -0,0 +1,1298 @@
+/*
+** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $
+** Lua API
+** See Copyright Notice in lua.h
+*/
+
+#define lapi_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lundump.h"
+#include "lvm.h"
+
+
+
+const char lua_ident[] =
+ "$LuaVersion: " LUA_COPYRIGHT " $"
+ "$LuaAuthors: " LUA_AUTHORS " $";
+
+
+/* value at a non-valid index */
+#define NONVALIDVALUE cast(TValue *, luaO_nilobject)
+
+/* corresponding test */
+#define isvalid(o) ((o) != luaO_nilobject)
+
+/* test for pseudo index */
+#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX)
+
+/* test for upvalue */
+#define isupvalue(i) ((i) < LUA_REGISTRYINDEX)
+
+/* test for valid but not pseudo index */
+#define isstackindex(i, o) (isvalid(o) && !ispseudo(i))
+
+#define api_checkvalidindex(l,o) api_check(l, isvalid(o), "invalid index")
+
+#define api_checkstackindex(l, i, o) \
+ api_check(l, isstackindex(i, o), "index not in the stack")
+
+
+static TValue *index2addr (lua_State *L, int idx) {
+ CallInfo *ci = L->ci;
+ if (idx > 0) {
+ TValue *o = ci->func + idx;
+ api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index");
+ if (o >= L->top) return NONVALIDVALUE;
+ else return o;
+ }
+ else if (!ispseudo(idx)) { /* negative index */
+ api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
+ return L->top + idx;
+ }
+ else if (idx == LUA_REGISTRYINDEX)
+ return &G(L)->l_registry;
+ else { /* upvalues */
+ idx = LUA_REGISTRYINDEX - idx;
+ api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
+ if (ttislcf(ci->func)) /* light C function? */
+ return NONVALIDVALUE; /* it has no upvalues */
+ else {
+ CClosure *func = clCvalue(ci->func);
+ return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE;
+ }
+ }
+}
+
+
+/*
+** to be called by 'lua_checkstack' in protected mode, to grow stack
+** capturing memory errors
+*/
+static void growstack (lua_State *L, void *ud) {
+ int size = *(int *)ud;
+ luaD_growstack(L, size);
+}
+
+
+LUA_API int lua_checkstack (lua_State *L, int n) {
+ int res;
+ CallInfo *ci = L->ci;
+ lua_lock(L);
+ api_check(L, n >= 0, "negative 'n'");
+ if (L->stack_last - L->top > n) /* stack large enough? */
+ res = 1; /* yes; check is OK */
+ else { /* no; need to grow stack */
+ int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
+ if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
+ res = 0; /* no */
+ else /* try to grow stack */
+ res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK);
+ }
+ if (res && ci->top < L->top + n)
+ ci->top = L->top + n; /* adjust frame top */
+ lua_unlock(L);
+ return res;
+}
+
+
+LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
+ int i;
+ if (from == to) return;
+ lua_lock(to);
+ api_checknelems(from, n);
+ api_check(from, G(from) == G(to), "moving among independent states");
+ api_check(from, to->ci->top - to->top >= n, "stack overflow");
+ from->top -= n;
+ for (i = 0; i < n; i++) {
+ setobj2s(to, to->top, from->top + i);
+ to->top++; /* stack already checked by previous 'api_check' */
+ }
+ lua_unlock(to);
+}
+
+
+LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) {
+ lua_CFunction old;
+ lua_lock(L);
+ old = G(L)->panic;
+ G(L)->panic = panicf;
+ lua_unlock(L);
+ return old;
+}
+
+
+LUA_API const lua_Number *lua_version (lua_State *L) {
+ static const lua_Number version = LUA_VERSION_NUM;
+ if (L == NULL) return &version;
+ else return G(L)->version;
+}
+
+
+
+/*
+** basic stack manipulation
+*/
+
+
+/*
+** convert an acceptable stack index into an absolute index
+*/
+LUA_API int lua_absindex (lua_State *L, int idx) {
+ return (idx > 0 || ispseudo(idx))
+ ? idx
+ : cast_int(L->top - L->ci->func) + idx;
+}
+
+
+LUA_API int lua_gettop (lua_State *L) {
+ return cast_int(L->top - (L->ci->func + 1));
+}
+
+
+LUA_API void lua_settop (lua_State *L, int idx) {
+ StkId func = L->ci->func;
+ lua_lock(L);
+ if (idx >= 0) {
+ api_check(L, idx <= L->stack_last - (func + 1), "new top too large");
+ while (L->top < (func + 1) + idx)
+ setnilvalue(L->top++);
+ L->top = (func + 1) + idx;
+ }
+ else {
+ api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
+ L->top += idx+1; /* 'subtract' index (index is negative) */
+ }
+ lua_unlock(L);
+}
+
+
+/*
+** Reverse the stack segment from 'from' to 'to'
+** (auxiliary to 'lua_rotate')
+*/
+static void reverse (lua_State *L, StkId from, StkId to) {
+ for (; from < to; from++, to--) {
+ TValue temp;
+ setobj(L, &temp, from);
+ setobjs2s(L, from, to);
+ setobj2s(L, to, &temp);
+ }
+}
+
+
+/*
+** Let x = AB, where A is a prefix of length 'n'. Then,
+** rotate x n == BA. But BA == (A^r . B^r)^r.
+*/
+LUA_API void lua_rotate (lua_State *L, int idx, int n) {
+ StkId p, t, m;
+ lua_lock(L);
+ t = L->top - 1; /* end of stack segment being rotated */
+ p = index2addr(L, idx); /* start of segment */
+ api_checkstackindex(L, idx, p);
+ api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
+ m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
+ reverse(L, p, m); /* reverse the prefix with length 'n' */
+ reverse(L, m + 1, t); /* reverse the suffix */
+ reverse(L, p, t); /* reverse the entire segment */
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
+ TValue *fr, *to;
+ lua_lock(L);
+ fr = index2addr(L, fromidx);
+ to = index2addr(L, toidx);
+ api_checkvalidindex(L, to);
+ setobj(L, to, fr);
+ if (isupvalue(toidx)) /* function upvalue? */
+ luaC_barrier(L, clCvalue(L->ci->func), fr);
+ /* LUA_REGISTRYINDEX does not need gc barrier
+ (collector revisits it before finishing collection) */
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_pushvalue (lua_State *L, int idx) {
+ lua_lock(L);
+ setobj2s(L, L->top, index2addr(L, idx));
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+
+/*
+** access functions (stack -> C)
+*/
+
+
+LUA_API int lua_type (lua_State *L, int idx) {
+ StkId o = index2addr(L, idx);
+ return (isvalid(o) ? ttnov(o) : LUA_TNONE);
+}
+
+
+LUA_API const char *lua_typename (lua_State *L, int t) {
+ UNUSED(L);
+ api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag");
+ return ttypename(t);
+}
+
+
+LUA_API int lua_iscfunction (lua_State *L, int idx) {
+ StkId o = index2addr(L, idx);
+ return (ttislcf(o) || (ttisCclosure(o)));
+}
+
+
+LUA_API int lua_isinteger (lua_State *L, int idx) {
+ StkId o = index2addr(L, idx);
+ return ttisinteger(o);
+}
+
+
+LUA_API int lua_isnumber (lua_State *L, int idx) {
+ lua_Number n;
+ const TValue *o = index2addr(L, idx);
+ return tonumber(o, &n);
+}
+
+
+LUA_API int lua_isstring (lua_State *L, int idx) {
+ const TValue *o = index2addr(L, idx);
+ return (ttisstring(o) || cvt2str(o));
+}
+
+
+LUA_API int lua_isuserdata (lua_State *L, int idx) {
+ const TValue *o = index2addr(L, idx);
+ return (ttisfulluserdata(o) || ttislightuserdata(o));
+}
+
+
+LUA_API int lua_rawequal (lua_State *L, int index1, int index2) {
+ StkId o1 = index2addr(L, index1);
+ StkId o2 = index2addr(L, index2);
+ return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0;
+}
+
+
+LUA_API void lua_arith (lua_State *L, int op) {
+ lua_lock(L);
+ if (op != LUA_OPUNM && op != LUA_OPBNOT)
+ api_checknelems(L, 2); /* all other operations expect two operands */
+ else { /* for unary operations, add fake 2nd operand */
+ api_checknelems(L, 1);
+ setobjs2s(L, L->top, L->top - 1);
+ api_incr_top(L);
+ }
+ /* first operand at top - 2, second at top - 1; result go to top - 2 */
+ luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2);
+ L->top--; /* remove second operand */
+ lua_unlock(L);
+}
+
+
+LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
+ StkId o1, o2;
+ int i = 0;
+ lua_lock(L); /* may call tag method */
+ o1 = index2addr(L, index1);
+ o2 = index2addr(L, index2);
+ if (isvalid(o1) && isvalid(o2)) {
+ switch (op) {
+ case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break;
+ case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break;
+ case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break;
+ default: api_check(L, 0, "invalid option");
+ }
+ }
+ lua_unlock(L);
+ return i;
+}
+
+
+LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
+ size_t sz = luaO_str2num(s, L->top);
+ if (sz != 0)
+ api_incr_top(L);
+ return sz;
+}
+
+
+LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) {
+ lua_Number n;
+ const TValue *o = index2addr(L, idx);
+ int isnum = tonumber(o, &n);
+ if (!isnum)
+ n = 0; /* call to 'tonumber' may change 'n' even if it fails */
+ if (pisnum) *pisnum = isnum;
+ return n;
+}
+
+
+LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) {
+ lua_Integer res;
+ const TValue *o = index2addr(L, idx);
+ int isnum = tointeger(o, &res);
+ if (!isnum)
+ res = 0; /* call to 'tointeger' may change 'n' even if it fails */
+ if (pisnum) *pisnum = isnum;
+ return res;
+}
+
+
+LUA_API int lua_toboolean (lua_State *L, int idx) {
+ const TValue *o = index2addr(L, idx);
+ return !l_isfalse(o);
+}
+
+
+LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
+ StkId o = index2addr(L, idx);
+ if (!ttisstring(o)) {
+ if (!cvt2str(o)) { /* not convertible? */
+ if (len != NULL) *len = 0;
+ return NULL;
+ }
+ lua_lock(L); /* 'luaO_tostring' may create a new string */
+ luaO_tostring(L, o);
+ luaC_checkGC(L);
+ o = index2addr(L, idx); /* previous call may reallocate the stack */
+ lua_unlock(L);
+ }
+ if (len != NULL)
+ *len = vslen(o);
+ return svalue(o);
+}
+
+
+LUA_API size_t lua_rawlen (lua_State *L, int idx) {
+ StkId o = index2addr(L, idx);
+ switch (ttype(o)) {
+ case LUA_TSHRSTR: return tsvalue(o)->shrlen;
+ case LUA_TLNGSTR: return tsvalue(o)->u.lnglen;
+ case LUA_TUSERDATA: return uvalue(o)->len;
+ case LUA_TTABLE: return luaH_getn(hvalue(o));
+ default: return 0;
+ }
+}
+
+
+LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
+ StkId o = index2addr(L, idx);
+ if (ttislcf(o)) return fvalue(o);
+ else if (ttisCclosure(o))
+ return clCvalue(o)->f;
+ else return NULL; /* not a C function */
+}
+
+
+LUA_API void *lua_touserdata (lua_State *L, int idx) {
+ StkId o = index2addr(L, idx);
+ switch (ttnov(o)) {
+ case LUA_TUSERDATA: return getudatamem(uvalue(o));
+ case LUA_TLIGHTUSERDATA: return pvalue(o);
+ default: return NULL;
+ }
+}
+
+
+LUA_API lua_State *lua_tothread (lua_State *L, int idx) {
+ StkId o = index2addr(L, idx);
+ return (!ttisthread(o)) ? NULL : thvalue(o);
+}
+
+
+LUA_API const void *lua_topointer (lua_State *L, int idx) {
+ StkId o = index2addr(L, idx);
+ switch (ttype(o)) {
+ case LUA_TTABLE: return hvalue(o);
+ case LUA_TLCL: return clLvalue(o);
+ case LUA_TCCL: return clCvalue(o);
+ case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o)));
+ case LUA_TTHREAD: return thvalue(o);
+ case LUA_TUSERDATA: return getudatamem(uvalue(o));
+ case LUA_TLIGHTUSERDATA: return pvalue(o);
+ default: return NULL;
+ }
+}
+
+
+
+/*
+** push functions (C -> stack)
+*/
+
+
+LUA_API void lua_pushnil (lua_State *L) {
+ lua_lock(L);
+ setnilvalue(L->top);
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
+ lua_lock(L);
+ setfltvalue(L->top, n);
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
+ lua_lock(L);
+ setivalue(L->top, n);
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+/*
+** Pushes on the stack a string with given length. Avoid using 's' when
+** 'len' == 0 (as 's' can be NULL in that case), due to later use of
+** 'memcmp' and 'memcpy'.
+*/
+LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
+ TString *ts;
+ lua_lock(L);
+ ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
+ setsvalue2s(L, L->top, ts);
+ api_incr_top(L);
+ luaC_checkGC(L);
+ lua_unlock(L);
+ return getstr(ts);
+}
+
+
+LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
+ lua_lock(L);
+ if (s == NULL)
+ setnilvalue(L->top);
+ else {
+ TString *ts;
+ ts = luaS_new(L, s);
+ setsvalue2s(L, L->top, ts);
+ s = getstr(ts); /* internal copy's address */
+ }
+ api_incr_top(L);
+ luaC_checkGC(L);
+ lua_unlock(L);
+ return s;
+}
+
+
+LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
+ va_list argp) {
+ const char *ret;
+ lua_lock(L);
+ ret = luaO_pushvfstring(L, fmt, argp);
+ luaC_checkGC(L);
+ lua_unlock(L);
+ return ret;
+}
+
+
+LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
+ const char *ret;
+ va_list argp;
+ lua_lock(L);
+ va_start(argp, fmt);
+ ret = luaO_pushvfstring(L, fmt, argp);
+ va_end(argp);
+ luaC_checkGC(L);
+ lua_unlock(L);
+ return ret;
+}
+
+
+LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
+ lua_lock(L);
+ if (n == 0) {
+ setfvalue(L->top, fn);
+ }
+ else {
+ CClosure *cl;
+ api_checknelems(L, n);
+ api_check(L, n <= MAXUPVAL, "upvalue index too large");
+ cl = luaF_newCclosure(L, n);
+ cl->f = fn;
+ L->top -= n;
+ while (n--) {
+ setobj2n(L, &cl->upvalue[n], L->top + n);
+ /* does not need barrier because closure is white */
+ }
+ setclCvalue(L, L->top, cl);
+ }
+ api_incr_top(L);
+ luaC_checkGC(L);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_pushboolean (lua_State *L, int b) {
+ lua_lock(L);
+ setbvalue(L->top, (b != 0)); /* ensure that true is 1 */
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
+ lua_lock(L);
+ setpvalue(L->top, p);
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API int lua_pushthread (lua_State *L) {
+ lua_lock(L);
+ setthvalue(L, L->top, L);
+ api_incr_top(L);
+ lua_unlock(L);
+ return (G(L)->mainthread == L);
+}
+
+
+
+/*
+** get functions (Lua -> stack)
+*/
+
+
+static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
+ const TValue *slot;
+ TString *str = luaS_new(L, k);
+ if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
+ setobj2s(L, L->top, slot);
+ api_incr_top(L);
+ }
+ else {
+ setsvalue2s(L, L->top, str);
+ api_incr_top(L);
+ luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
+ }
+ lua_unlock(L);
+ return ttnov(L->top - 1);
+}
+
+
+LUA_API int lua_getglobal (lua_State *L, const char *name) {
+ Table *reg = hvalue(&G(L)->l_registry);
+ lua_lock(L);
+ return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
+}
+
+
+LUA_API int lua_gettable (lua_State *L, int idx) {
+ StkId t;
+ lua_lock(L);
+ t = index2addr(L, idx);
+ luaV_gettable(L, t, L->top - 1, L->top - 1);
+ lua_unlock(L);
+ return ttnov(L->top - 1);
+}
+
+
+LUA_API int lua_getfield (lua_State *L, int idx, const char *k) {
+ lua_lock(L);
+ return auxgetstr(L, index2addr(L, idx), k);
+}
+
+
+LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
+ StkId t;
+ const TValue *slot;
+ lua_lock(L);
+ t = index2addr(L, idx);
+ if (luaV_fastget(L, t, n, slot, luaH_getint)) {
+ setobj2s(L, L->top, slot);
+ api_incr_top(L);
+ }
+ else {
+ setivalue(L->top, n);
+ api_incr_top(L);
+ luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
+ }
+ lua_unlock(L);
+ return ttnov(L->top - 1);
+}
+
+
+LUA_API int lua_rawget (lua_State *L, int idx) {
+ StkId t;
+ lua_lock(L);
+ t = index2addr(L, idx);
+ api_check(L, ttistable(t), "table expected");
+ setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
+ lua_unlock(L);
+ return ttnov(L->top - 1);
+}
+
+
+LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) {
+ StkId t;
+ lua_lock(L);
+ t = index2addr(L, idx);
+ api_check(L, ttistable(t), "table expected");
+ setobj2s(L, L->top, luaH_getint(hvalue(t), n));
+ api_incr_top(L);
+ lua_unlock(L);
+ return ttnov(L->top - 1);
+}
+
+
+LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
+ StkId t;
+ TValue k;
+ lua_lock(L);
+ t = index2addr(L, idx);
+ api_check(L, ttistable(t), "table expected");
+ setpvalue(&k, cast(void *, p));
+ setobj2s(L, L->top, luaH_get(hvalue(t), &k));
+ api_incr_top(L);
+ lua_unlock(L);
+ return ttnov(L->top - 1);
+}
+
+
+LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
+ Table *t;
+ lua_lock(L);
+ t = luaH_new(L);
+ sethvalue(L, L->top, t);
+ api_incr_top(L);
+ if (narray > 0 || nrec > 0)
+ luaH_resize(L, t, narray, nrec);
+ luaC_checkGC(L);
+ lua_unlock(L);
+}
+
+
+LUA_API int lua_getmetatable (lua_State *L, int objindex) {
+ const TValue *obj;
+ Table *mt;
+ int res = 0;
+ lua_lock(L);
+ obj = index2addr(L, objindex);
+ switch (ttnov(obj)) {
+ case LUA_TTABLE:
+ mt = hvalue(obj)->metatable;
+ break;
+ case LUA_TUSERDATA:
+ mt = uvalue(obj)->metatable;
+ break;
+ default:
+ mt = G(L)->mt[ttnov(obj)];
+ break;
+ }
+ if (mt != NULL) {
+ sethvalue(L, L->top, mt);
+ api_incr_top(L);
+ res = 1;
+ }
+ lua_unlock(L);
+ return res;
+}
+
+
+LUA_API int lua_getuservalue (lua_State *L, int idx) {
+ StkId o;
+ lua_lock(L);
+ o = index2addr(L, idx);
+ api_check(L, ttisfulluserdata(o), "full userdata expected");
+ getuservalue(L, uvalue(o), L->top);
+ api_incr_top(L);
+ lua_unlock(L);
+ return ttnov(L->top - 1);
+}
+
+
+/*
+** set functions (stack -> Lua)
+*/
+
+/*
+** t[k] = value at the top of the stack (where 'k' is a string)
+*/
+static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
+ const TValue *slot;
+ TString *str = luaS_new(L, k);
+ api_checknelems(L, 1);
+ if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
+ L->top--; /* pop value */
+ else {
+ setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
+ api_incr_top(L);
+ luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
+ L->top -= 2; /* pop value and key */
+ }
+ lua_unlock(L); /* lock done by caller */
+}
+
+
+LUA_API void lua_setglobal (lua_State *L, const char *name) {
+ Table *reg = hvalue(&G(L)->l_registry);
+ lua_lock(L); /* unlock done in 'auxsetstr' */
+ auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
+}
+
+
+LUA_API void lua_settable (lua_State *L, int idx) {
+ StkId t;
+ lua_lock(L);
+ api_checknelems(L, 2);
+ t = index2addr(L, idx);
+ luaV_settable(L, t, L->top - 2, L->top - 1);
+ L->top -= 2; /* pop index and value */
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
+ lua_lock(L); /* unlock done in 'auxsetstr' */
+ auxsetstr(L, index2addr(L, idx), k);
+}
+
+
+LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
+ StkId t;
+ const TValue *slot;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ t = index2addr(L, idx);
+ if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
+ L->top--; /* pop value */
+ else {
+ setivalue(L->top, n);
+ api_incr_top(L);
+ luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
+ L->top -= 2; /* pop value and key */
+ }
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_rawset (lua_State *L, int idx) {
+ StkId o;
+ TValue *slot;
+ lua_lock(L);
+ api_checknelems(L, 2);
+ o = index2addr(L, idx);
+ api_check(L, ttistable(o), "table expected");
+ slot = luaH_set(L, hvalue(o), L->top - 2);
+ setobj2t(L, slot, L->top - 1);
+ invalidateTMcache(hvalue(o));
+ luaC_barrierback(L, hvalue(o), L->top-1);
+ L->top -= 2;
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
+ StkId o;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ o = index2addr(L, idx);
+ api_check(L, ttistable(o), "table expected");
+ luaH_setint(L, hvalue(o), n, L->top - 1);
+ luaC_barrierback(L, hvalue(o), L->top-1);
+ L->top--;
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
+ StkId o;
+ TValue k, *slot;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ o = index2addr(L, idx);
+ api_check(L, ttistable(o), "table expected");
+ setpvalue(&k, cast(void *, p));
+ slot = luaH_set(L, hvalue(o), &k);
+ setobj2t(L, slot, L->top - 1);
+ luaC_barrierback(L, hvalue(o), L->top - 1);
+ L->top--;
+ lua_unlock(L);
+}
+
+
+LUA_API int lua_setmetatable (lua_State *L, int objindex) {
+ TValue *obj;
+ Table *mt;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ obj = index2addr(L, objindex);
+ if (ttisnil(L->top - 1))
+ mt = NULL;
+ else {
+ api_check(L, ttistable(L->top - 1), "table expected");
+ mt = hvalue(L->top - 1);
+ }
+ switch (ttnov(obj)) {
+ case LUA_TTABLE: {
+ hvalue(obj)->metatable = mt;
+ if (mt) {
+ luaC_objbarrier(L, gcvalue(obj), mt);
+ luaC_checkfinalizer(L, gcvalue(obj), mt);
+ }
+ break;
+ }
+ case LUA_TUSERDATA: {
+ uvalue(obj)->metatable = mt;
+ if (mt) {
+ luaC_objbarrier(L, uvalue(obj), mt);
+ luaC_checkfinalizer(L, gcvalue(obj), mt);
+ }
+ break;
+ }
+ default: {
+ G(L)->mt[ttnov(obj)] = mt;
+ break;
+ }
+ }
+ L->top--;
+ lua_unlock(L);
+ return 1;
+}
+
+
+LUA_API void lua_setuservalue (lua_State *L, int idx) {
+ StkId o;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ o = index2addr(L, idx);
+ api_check(L, ttisfulluserdata(o), "full userdata expected");
+ setuservalue(L, uvalue(o), L->top - 1);
+ luaC_barrier(L, gcvalue(o), L->top - 1);
+ L->top--;
+ lua_unlock(L);
+}
+
+
+/*
+** 'load' and 'call' functions (run Lua code)
+*/
+
+
+#define checkresults(L,na,nr) \
+ api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
+ "results from function overflow current stack size")
+
+
+LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
+ lua_KContext ctx, lua_KFunction k) {
+ StkId func;
+ lua_lock(L);
+ api_check(L, k == NULL || !isLua(L->ci),
+ "cannot use continuations inside hooks");
+ api_checknelems(L, nargs+1);
+ api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
+ checkresults(L, nargs, nresults);
+ func = L->top - (nargs+1);
+ if (k != NULL && L->nny == 0) { /* need to prepare continuation? */
+ L->ci->u.c.k = k; /* save continuation */
+ L->ci->u.c.ctx = ctx; /* save context */
+ luaD_call(L, func, nresults); /* do the call */
+ }
+ else /* no continuation or no yieldable */
+ luaD_callnoyield(L, func, nresults); /* just do the call */
+ adjustresults(L, nresults);
+ lua_unlock(L);
+}
+
+
+
+/*
+** Execute a protected call.
+*/
+struct CallS { /* data to 'f_call' */
+ StkId func;
+ int nresults;
+};
+
+
+static void f_call (lua_State *L, void *ud) {
+ struct CallS *c = cast(struct CallS *, ud);
+ luaD_callnoyield(L, c->func, c->nresults);
+}
+
+
+
+LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
+ lua_KContext ctx, lua_KFunction k) {
+ struct CallS c;
+ int status;
+ ptrdiff_t func;
+ lua_lock(L);
+ api_check(L, k == NULL || !isLua(L->ci),
+ "cannot use continuations inside hooks");
+ api_checknelems(L, nargs+1);
+ api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
+ checkresults(L, nargs, nresults);
+ if (errfunc == 0)
+ func = 0;
+ else {
+ StkId o = index2addr(L, errfunc);
+ api_checkstackindex(L, errfunc, o);
+ func = savestack(L, o);
+ }
+ c.func = L->top - (nargs+1); /* function to be called */
+ if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */
+ c.nresults = nresults; /* do a 'conventional' protected call */
+ status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
+ }
+ else { /* prepare continuation (call is already protected by 'resume') */
+ CallInfo *ci = L->ci;
+ ci->u.c.k = k; /* save continuation */
+ ci->u.c.ctx = ctx; /* save context */
+ /* save information for error recovery */
+ ci->extra = savestack(L, c.func);
+ ci->u.c.old_errfunc = L->errfunc;
+ L->errfunc = func;
+ setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */
+ ci->callstatus |= CIST_YPCALL; /* function can do error recovery */
+ luaD_call(L, c.func, nresults); /* do the call */
+ ci->callstatus &= ~CIST_YPCALL;
+ L->errfunc = ci->u.c.old_errfunc;
+ status = LUA_OK; /* if it is here, there were no errors */
+ }
+ adjustresults(L, nresults);
+ lua_unlock(L);
+ return status;
+}
+
+
+LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
+ const char *chunkname, const char *mode) {
+ ZIO z;
+ int status;
+ lua_lock(L);
+ if (!chunkname) chunkname = "?";
+ luaZ_init(L, &z, reader, data);
+ status = luaD_protectedparser(L, &z, chunkname, mode);
+ if (status == LUA_OK) { /* no errors? */
+ LClosure *f = clLvalue(L->top - 1); /* get newly created function */
+ if (f->nupvalues >= 1) { /* does it have an upvalue? */
+ /* get global table from registry */
+ Table *reg = hvalue(&G(L)->l_registry);
+ const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
+ /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
+ setobj(L, f->upvals[0]->v, gt);
+ luaC_upvalbarrier(L, f->upvals[0]);
+ }
+ }
+ lua_unlock(L);
+ return status;
+}
+
+
+LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
+ int status;
+ TValue *o;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ o = L->top - 1;
+ if (isLfunction(o))
+ status = luaU_dump(L, getproto(o), writer, data, strip);
+ else
+ status = 1;
+ lua_unlock(L);
+ return status;
+}
+
+
+LUA_API int lua_status (lua_State *L) {
+ return L->status;
+}
+
+
+/*
+** Garbage-collection function
+*/
+
+LUA_API int lua_gc (lua_State *L, int what, int data) {
+ int res = 0;
+ global_State *g;
+ lua_lock(L);
+ g = G(L);
+ switch (what) {
+ case LUA_GCSTOP: {
+ g->gcrunning = 0;
+ break;
+ }
+ case LUA_GCRESTART: {
+ luaE_setdebt(g, 0);
+ g->gcrunning = 1;
+ break;
+ }
+ case LUA_GCCOLLECT: {
+ luaC_fullgc(L, 0);
+ break;
+ }
+ case LUA_GCCOUNT: {
+ /* GC values are expressed in Kbytes: #bytes/2^10 */
+ res = cast_int(gettotalbytes(g) >> 10);
+ break;
+ }
+ case LUA_GCCOUNTB: {
+ res = cast_int(gettotalbytes(g) & 0x3ff);
+ break;
+ }
+ case LUA_GCSTEP: {
+ l_mem debt = 1; /* =1 to signal that it did an actual step */
+ lu_byte oldrunning = g->gcrunning;
+ g->gcrunning = 1; /* allow GC to run */
+ if (data == 0) {
+ luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */
+ luaC_step(L);
+ }
+ else { /* add 'data' to total debt */
+ debt = cast(l_mem, data) * 1024 + g->GCdebt;
+ luaE_setdebt(g, debt);
+ luaC_checkGC(L);
+ }
+ g->gcrunning = oldrunning; /* restore previous state */
+ if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */
+ res = 1; /* signal it */
+ break;
+ }
+ case LUA_GCSETPAUSE: {
+ res = g->gcpause;
+ g->gcpause = data;
+ break;
+ }
+ case LUA_GCSETSTEPMUL: {
+ res = g->gcstepmul;
+ if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */
+ g->gcstepmul = data;
+ break;
+ }
+ case LUA_GCISRUNNING: {
+ res = g->gcrunning;
+ break;
+ }
+ default: res = -1; /* invalid option */
+ }
+ lua_unlock(L);
+ return res;
+}
+
+
+
+/*
+** miscellaneous functions
+*/
+
+
+LUA_API int lua_error (lua_State *L) {
+ lua_lock(L);
+ api_checknelems(L, 1);
+ luaG_errormsg(L);
+ /* code unreachable; will unlock when control actually leaves the kernel */
+ return 0; /* to avoid warnings */
+}
+
+
+LUA_API int lua_next (lua_State *L, int idx) {
+ StkId t;
+ int more;
+ lua_lock(L);
+ t = index2addr(L, idx);
+ api_check(L, ttistable(t), "table expected");
+ more = luaH_next(L, hvalue(t), L->top - 1);
+ if (more) {
+ api_incr_top(L);
+ }
+ else /* no more elements */
+ L->top -= 1; /* remove key */
+ lua_unlock(L);
+ return more;
+}
+
+
+LUA_API void lua_concat (lua_State *L, int n) {
+ lua_lock(L);
+ api_checknelems(L, n);
+ if (n >= 2) {
+ luaV_concat(L, n);
+ }
+ else if (n == 0) { /* push empty string */
+ setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));
+ api_incr_top(L);
+ }
+ /* else n == 1; nothing to do */
+ luaC_checkGC(L);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_len (lua_State *L, int idx) {
+ StkId t;
+ lua_lock(L);
+ t = index2addr(L, idx);
+ luaV_objlen(L, L->top, t);
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) {
+ lua_Alloc f;
+ lua_lock(L);
+ if (ud) *ud = G(L)->ud;
+ f = G(L)->frealloc;
+ lua_unlock(L);
+ return f;
+}
+
+
+LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
+ lua_lock(L);
+ G(L)->ud = ud;
+ G(L)->frealloc = f;
+ lua_unlock(L);
+}
+
+
+LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
+ Udata *u;
+ lua_lock(L);
+ u = luaS_newudata(L, size);
+ setuvalue(L, L->top, u);
+ api_incr_top(L);
+ luaC_checkGC(L);
+ lua_unlock(L);
+ return getudatamem(u);
+}
+
+
+
+static const char *aux_upvalue (StkId fi, int n, TValue **val,
+ CClosure **owner, UpVal **uv) {
+ switch (ttype(fi)) {
+ case LUA_TCCL: { /* C closure */
+ CClosure *f = clCvalue(fi);
+ if (!(1 <= n && n <= f->nupvalues)) return NULL;
+ *val = &f->upvalue[n-1];
+ if (owner) *owner = f;
+ return "";
+ }
+ case LUA_TLCL: { /* Lua closure */
+ LClosure *f = clLvalue(fi);
+ TString *name;
+ Proto *p = f->p;
+ if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
+ *val = f->upvals[n-1]->v;
+ if (uv) *uv = f->upvals[n - 1];
+ name = p->upvalues[n-1].name;
+ return (name == NULL) ? "(*no name)" : getstr(name);
+ }
+ default: return NULL; /* not a closure */
+ }
+}
+
+
+LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
+ const char *name;
+ TValue *val = NULL; /* to avoid warnings */
+ lua_lock(L);
+ name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL);
+ if (name) {
+ setobj2s(L, L->top, val);
+ api_incr_top(L);
+ }
+ lua_unlock(L);
+ return name;
+}
+
+
+LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
+ const char *name;
+ TValue *val = NULL; /* to avoid warnings */
+ CClosure *owner = NULL;
+ UpVal *uv = NULL;
+ StkId fi;
+ lua_lock(L);
+ fi = index2addr(L, funcindex);
+ api_checknelems(L, 1);
+ name = aux_upvalue(fi, n, &val, &owner, &uv);
+ if (name) {
+ L->top--;
+ setobj(L, val, L->top);
+ if (owner) { luaC_barrier(L, owner, L->top); }
+ else if (uv) { luaC_upvalbarrier(L, uv); }
+ }
+ lua_unlock(L);
+ return name;
+}
+
+
+static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
+ LClosure *f;
+ StkId fi = index2addr(L, fidx);
+ api_check(L, ttisLclosure(fi), "Lua function expected");
+ f = clLvalue(fi);
+ api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
+ if (pf) *pf = f;
+ return &f->upvals[n - 1]; /* get its upvalue pointer */
+}
+
+
+LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
+ StkId fi = index2addr(L, fidx);
+ switch (ttype(fi)) {
+ case LUA_TLCL: { /* lua closure */
+ return *getupvalref(L, fidx, n, NULL);
+ }
+ case LUA_TCCL: { /* C closure */
+ CClosure *f = clCvalue(fi);
+ api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index");
+ return &f->upvalue[n - 1];
+ }
+ default: {
+ api_check(L, 0, "closure expected");
+ return NULL;
+ }
+ }
+}
+
+
+LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
+ int fidx2, int n2) {
+ LClosure *f1;
+ UpVal **up1 = getupvalref(L, fidx1, n1, &f1);
+ UpVal **up2 = getupvalref(L, fidx2, n2, NULL);
+ luaC_upvdeccount(L, *up1);
+ *up1 = *up2;
+ (*up1)->refcount++;
+ if (upisopen(*up1)) (*up1)->u.open.touched = 1;
+ luaC_upvalbarrier(L, *up1);
+}
+
+
diff --git a/external/lua-5.3.3/src/lapi.h b/external/lua-5.3.3/src/lapi.h
new file mode 100644
index 0000000..6d36dee
--- /dev/null
+++ b/external/lua-5.3.3/src/lapi.h
@@ -0,0 +1,24 @@
+/*
+** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $
+** Auxiliary functions from Lua API
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lapi_h
+#define lapi_h
+
+
+#include "llimits.h"
+#include "lstate.h"
+
+#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
+ "stack overflow");}
+
+#define adjustresults(L,nres) \
+ { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
+
+#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
+ "not enough elements in the stack")
+
+
+#endif
diff --git a/external/lua-5.3.3/src/lauxlib.c b/external/lua-5.3.3/src/lauxlib.c
new file mode 100644
index 0000000..bacf43b
--- /dev/null
+++ b/external/lua-5.3.3/src/lauxlib.c
@@ -0,0 +1,1035 @@
+/*
+** $Id: lauxlib.c,v 1.286 2016/01/08 15:33:09 roberto Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+#define lauxlib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*
+** This file uses only the official API of Lua.
+** Any function declared here could be written as an application function.
+*/
+
+#include "lua.h"
+
+#include "lauxlib.h"
+
+
+/*
+** {======================================================
+** Traceback
+** =======================================================
+*/
+
+
+#define LEVELS1 10 /* size of the first part of the stack */
+#define LEVELS2 11 /* size of the second part of the stack */
+
+
+
+/*
+** search for 'objidx' in table at index -1.
+** return 1 + string at top if find a good name.
+*/
+static int findfield (lua_State *L, int objidx, int level) {
+ if (level == 0 || !lua_istable(L, -1))
+ return 0; /* not found */
+ lua_pushnil(L); /* start 'next' loop */
+ while (lua_next(L, -2)) { /* for each pair in table */
+ if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */
+ if (lua_rawequal(L, objidx, -1)) { /* found object? */
+ lua_pop(L, 1); /* remove value (but keep name) */
+ return 1;
+ }
+ else if (findfield(L, objidx, level - 1)) { /* try recursively */
+ lua_remove(L, -2); /* remove table (but keep name) */
+ lua_pushliteral(L, ".");
+ lua_insert(L, -2); /* place '.' between the two names */
+ lua_concat(L, 3);
+ return 1;
+ }
+ }
+ lua_pop(L, 1); /* remove value */
+ }
+ return 0; /* not found */
+}
+
+
+/*
+** Search for a name for a function in all loaded modules
+** (registry._LOADED).
+*/
+static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
+ int top = lua_gettop(L);
+ lua_getinfo(L, "f", ar); /* push function */
+ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+ if (findfield(L, top + 1, 2)) {
+ const char *name = lua_tostring(L, -1);
+ if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */
+ lua_pushstring(L, name + 3); /* push name without prefix */
+ lua_remove(L, -2); /* remove original name */
+ }
+ lua_copy(L, -1, top + 1); /* move name to proper place */
+ lua_pop(L, 2); /* remove pushed values */
+ return 1;
+ }
+ else {
+ lua_settop(L, top); /* remove function and global table */
+ return 0;
+ }
+}
+
+
+static void pushfuncname (lua_State *L, lua_Debug *ar) {
+ if (pushglobalfuncname(L, ar)) { /* try first a global name */
+ lua_pushfstring(L, "function '%s'", lua_tostring(L, -1));
+ lua_remove(L, -2); /* remove name */
+ }
+ else if (*ar->namewhat != '\0') /* is there a name from code? */
+ lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */
+ else if (*ar->what == 'm') /* main? */
+ lua_pushliteral(L, "main chunk");
+ else if (*ar->what != 'C') /* for Lua functions, use <file:line> */
+ lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
+ else /* nothing left... */
+ lua_pushliteral(L, "?");
+}
+
+
+static int lastlevel (lua_State *L) {
+ lua_Debug ar;
+ int li = 1, le = 1;
+ /* find an upper bound */
+ while (lua_getstack(L, le, &ar)) { li = le; le *= 2; }
+ /* do a binary search */
+ while (li < le) {
+ int m = (li + le)/2;
+ if (lua_getstack(L, m, &ar)) li = m + 1;
+ else le = m;
+ }
+ return le - 1;
+}
+
+
+LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
+ const char *msg, int level) {
+ lua_Debug ar;
+ int top = lua_gettop(L);
+ int last = lastlevel(L1);
+ int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1;
+ if (msg)
+ lua_pushfstring(L, "%s\n", msg);
+ luaL_checkstack(L, 10, NULL);
+ lua_pushliteral(L, "stack traceback:");
+ while (lua_getstack(L1, level++, &ar)) {
+ if (n1-- == 0) { /* too many levels? */
+ lua_pushliteral(L, "\n\t..."); /* add a '...' */
+ level = last - LEVELS2 + 1; /* and skip to last ones */
+ }
+ else {
+ lua_getinfo(L1, "Slnt", &ar);
+ lua_pushfstring(L, "\n\t%s:", ar.short_src);
+ if (ar.currentline > 0)
+ lua_pushfstring(L, "%d:", ar.currentline);
+ lua_pushliteral(L, " in ");
+ pushfuncname(L, &ar);
+ if (ar.istailcall)
+ lua_pushliteral(L, "\n\t(...tail calls...)");
+ lua_concat(L, lua_gettop(L) - top);
+ }
+ }
+ lua_concat(L, lua_gettop(L) - top);
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Error-report functions
+** =======================================================
+*/
+
+LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
+ lua_Debug ar;
+ if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
+ return luaL_error(L, "bad argument #%d (%s)", arg, extramsg);
+ lua_getinfo(L, "n", &ar);
+ if (strcmp(ar.namewhat, "method") == 0) {
+ arg--; /* do not count 'self' */
+ if (arg == 0) /* error is in the self argument itself? */
+ return luaL_error(L, "calling '%s' on bad self (%s)",
+ ar.name, extramsg);
+ }
+ if (ar.name == NULL)
+ ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
+ return luaL_error(L, "bad argument #%d to '%s' (%s)",
+ arg, ar.name, extramsg);
+}
+
+
+static int typeerror (lua_State *L, int arg, const char *tname) {
+ const char *msg;
+ const char *typearg; /* name for the type of the actual argument */
+ if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING)
+ typearg = lua_tostring(L, -1); /* use the given type name */
+ else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA)
+ typearg = "light userdata"; /* special name for messages */
+ else
+ typearg = luaL_typename(L, arg); /* standard name */
+ msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg);
+ return luaL_argerror(L, arg, msg);
+}
+
+
+static void tag_error (lua_State *L, int arg, int tag) {
+ typeerror(L, arg, lua_typename(L, tag));
+}
+
+
+/*
+** The use of 'lua_pushfstring' ensures this function does not
+** need reserved stack space when called.
+*/
+LUALIB_API void luaL_where (lua_State *L, int level) {
+ lua_Debug ar;
+ if (lua_getstack(L, level, &ar)) { /* check function at level */
+ lua_getinfo(L, "Sl", &ar); /* get info about it */
+ if (ar.currentline > 0) { /* is there info? */
+ lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
+ return;
+ }
+ }
+ lua_pushfstring(L, ""); /* else, no information available... */
+}
+
+
+/*
+** Again, the use of 'lua_pushvfstring' ensures this function does
+** not need reserved stack space when called. (At worst, it generates
+** an error with "stack overflow" instead of the given message.)
+*/
+LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
+ va_list argp;
+ va_start(argp, fmt);
+ luaL_where(L, 1);
+ lua_pushvfstring(L, fmt, argp);
+ va_end(argp);
+ lua_concat(L, 2);
+ return lua_error(L);
+}
+
+
+LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
+ int en = errno; /* calls to Lua API may change this value */
+ if (stat) {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ else {
+ lua_pushnil(L);
+ if (fname)
+ lua_pushfstring(L, "%s: %s", fname, strerror(en));
+ else
+ lua_pushstring(L, strerror(en));
+ lua_pushinteger(L, en);
+ return 3;
+ }
+}
+
+
+#if !defined(l_inspectstat) /* { */
+
+#if defined(LUA_USE_POSIX)
+
+#include <sys/wait.h>
+
+/*
+** use appropriate macros to interpret 'pclose' return status
+*/
+#define l_inspectstat(stat,what) \
+ if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \
+ else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; }
+
+#else
+
+#define l_inspectstat(stat,what) /* no op */
+
+#endif
+
+#endif /* } */
+
+
+LUALIB_API int luaL_execresult (lua_State *L, int stat) {
+ const char *what = "exit"; /* type of termination */
+ if (stat == -1) /* error? */
+ return luaL_fileresult(L, 0, NULL);
+ else {
+ l_inspectstat(stat, what); /* interpret result */
+ if (*what == 'e' && stat == 0) /* successful termination? */
+ lua_pushboolean(L, 1);
+ else
+ lua_pushnil(L);
+ lua_pushstring(L, what);
+ lua_pushinteger(L, stat);
+ return 3; /* return true/nil,what,code */
+ }
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Userdata's metatable manipulation
+** =======================================================
+*/
+
+LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
+ if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */
+ return 0; /* leave previous value on top, but return 0 */
+ lua_pop(L, 1);
+ lua_createtable(L, 0, 2); /* create metatable */
+ lua_pushstring(L, tname);
+ lua_setfield(L, -2, "__name"); /* metatable.__name = tname */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */
+ return 1;
+}
+
+
+LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) {
+ luaL_getmetatable(L, tname);
+ lua_setmetatable(L, -2);
+}
+
+
+LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) {
+ void *p = lua_touserdata(L, ud);
+ if (p != NULL) { /* value is a userdata? */
+ if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
+ luaL_getmetatable(L, tname); /* get correct metatable */
+ if (!lua_rawequal(L, -1, -2)) /* not the same? */
+ p = NULL; /* value is a userdata with wrong metatable */
+ lua_pop(L, 2); /* remove both metatables */
+ return p;
+ }
+ }
+ return NULL; /* value is not a userdata with a metatable */
+}
+
+
+LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
+ void *p = luaL_testudata(L, ud, tname);
+ if (p == NULL) typeerror(L, ud, tname);
+ return p;
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Argument check functions
+** =======================================================
+*/
+
+LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
+ const char *const lst[]) {
+ const char *name = (def) ? luaL_optstring(L, arg, def) :
+ luaL_checkstring(L, arg);
+ int i;
+ for (i=0; lst[i]; i++)
+ if (strcmp(lst[i], name) == 0)
+ return i;
+ return luaL_argerror(L, arg,
+ lua_pushfstring(L, "invalid option '%s'", name));
+}
+
+
+/*
+** Ensures the stack has at least 'space' extra slots, raising an error
+** if it cannot fulfill the request. (The error handling needs a few
+** extra slots to format the error message. In case of an error without
+** this extra space, Lua will generate the same 'stack overflow' error,
+** but without 'msg'.)
+*/
+LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
+ if (!lua_checkstack(L, space)) {
+ if (msg)
+ luaL_error(L, "stack overflow (%s)", msg);
+ else
+ luaL_error(L, "stack overflow");
+ }
+}
+
+
+LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) {
+ if (lua_type(L, arg) != t)
+ tag_error(L, arg, t);
+}
+
+
+LUALIB_API void luaL_checkany (lua_State *L, int arg) {
+ if (lua_type(L, arg) == LUA_TNONE)
+ luaL_argerror(L, arg, "value expected");
+}
+
+
+LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) {
+ const char *s = lua_tolstring(L, arg, len);
+ if (!s) tag_error(L, arg, LUA_TSTRING);
+ return s;
+}
+
+
+LUALIB_API const char *luaL_optlstring (lua_State *L, int arg,
+ const char *def, size_t *len) {
+ if (lua_isnoneornil(L, arg)) {
+ if (len)
+ *len = (def ? strlen(def) : 0);
+ return def;
+ }
+ else return luaL_checklstring(L, arg, len);
+}
+
+
+LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) {
+ int isnum;
+ lua_Number d = lua_tonumberx(L, arg, &isnum);
+ if (!isnum)
+ tag_error(L, arg, LUA_TNUMBER);
+ return d;
+}
+
+
+LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) {
+ return luaL_opt(L, luaL_checknumber, arg, def);
+}
+
+
+static void interror (lua_State *L, int arg) {
+ if (lua_isnumber(L, arg))
+ luaL_argerror(L, arg, "number has no integer representation");
+ else
+ tag_error(L, arg, LUA_TNUMBER);
+}
+
+
+LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) {
+ int isnum;
+ lua_Integer d = lua_tointegerx(L, arg, &isnum);
+ if (!isnum) {
+ interror(L, arg);
+ }
+ return d;
+}
+
+
+LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg,
+ lua_Integer def) {
+ return luaL_opt(L, luaL_checkinteger, arg, def);
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+/* userdata to box arbitrary data */
+typedef struct UBox {
+ void *box;
+ size_t bsize;
+} UBox;
+
+
+static void *resizebox (lua_State *L, int idx, size_t newsize) {
+ void *ud;
+ lua_Alloc allocf = lua_getallocf(L, &ud);
+ UBox *box = (UBox *)lua_touserdata(L, idx);
+ void *temp = allocf(ud, box->box, box->bsize, newsize);
+ if (temp == NULL && newsize > 0) { /* allocation error? */
+ resizebox(L, idx, 0); /* free buffer */
+ luaL_error(L, "not enough memory for buffer allocation");
+ }
+ box->box = temp;
+ box->bsize = newsize;
+ return temp;
+}
+
+
+static int boxgc (lua_State *L) {
+ resizebox(L, 1, 0);
+ return 0;
+}
+
+
+static void *newbox (lua_State *L, size_t newsize) {
+ UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox));
+ box->box = NULL;
+ box->bsize = 0;
+ if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */
+ lua_pushcfunction(L, boxgc);
+ lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */
+ }
+ lua_setmetatable(L, -2);
+ return resizebox(L, -1, newsize);
+}
+
+
+/*
+** check whether buffer is using a userdata on the stack as a temporary
+** buffer
+*/
+#define buffonstack(B) ((B)->b != (B)->initb)
+
+
+/*
+** returns a pointer to a free area with at least 'sz' bytes
+*/
+LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
+ lua_State *L = B->L;
+ if (B->size - B->n < sz) { /* not enough space? */
+ char *newbuff;
+ size_t newsize = B->size * 2; /* double buffer size */
+ if (newsize - B->n < sz) /* not big enough? */
+ newsize = B->n + sz;
+ if (newsize < B->n || newsize - B->n < sz)
+ luaL_error(L, "buffer too large");
+ /* create larger buffer */
+ if (buffonstack(B))
+ newbuff = (char *)resizebox(L, -1, newsize);
+ else { /* no buffer yet */
+ newbuff = (char *)newbox(L, newsize);
+ memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */
+ }
+ B->b = newbuff;
+ B->size = newsize;
+ }
+ return &B->b[B->n];
+}
+
+
+LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
+ if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */
+ char *b = luaL_prepbuffsize(B, l);
+ memcpy(b, s, l * sizeof(char));
+ luaL_addsize(B, l);
+ }
+}
+
+
+LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
+ luaL_addlstring(B, s, strlen(s));
+}
+
+
+LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
+ lua_State *L = B->L;
+ lua_pushlstring(L, B->b, B->n);
+ if (buffonstack(B)) {
+ resizebox(L, -2, 0); /* delete old buffer */
+ lua_remove(L, -2); /* remove its header from the stack */
+ }
+}
+
+
+LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
+ luaL_addsize(B, sz);
+ luaL_pushresult(B);
+}
+
+
+LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
+ lua_State *L = B->L;
+ size_t l;
+ const char *s = lua_tolstring(L, -1, &l);
+ if (buffonstack(B))
+ lua_insert(L, -2); /* put value below buffer */
+ luaL_addlstring(B, s, l);
+ lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */
+}
+
+
+LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
+ B->L = L;
+ B->b = B->initb;
+ B->n = 0;
+ B->size = LUAL_BUFFERSIZE;
+}
+
+
+LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
+ luaL_buffinit(L, B);
+ return luaL_prepbuffsize(B, sz);
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Reference system
+** =======================================================
+*/
+
+/* index of free-list header */
+#define freelist 0
+
+
+LUALIB_API int luaL_ref (lua_State *L, int t) {
+ int ref;
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 1); /* remove from stack */
+ return LUA_REFNIL; /* 'nil' has a unique fixed reference */
+ }
+ t = lua_absindex(L, t);
+ lua_rawgeti(L, t, freelist); /* get first free element */
+ ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */
+ lua_pop(L, 1); /* remove it from stack */
+ if (ref != 0) { /* any free element? */
+ lua_rawgeti(L, t, ref); /* remove it from list */
+ lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */
+ }
+ else /* no free elements */
+ ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */
+ lua_rawseti(L, t, ref);
+ return ref;
+}
+
+
+LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
+ if (ref >= 0) {
+ t = lua_absindex(L, t);
+ lua_rawgeti(L, t, freelist);
+ lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */
+ lua_pushinteger(L, ref);
+ lua_rawseti(L, t, freelist); /* t[freelist] = ref */
+ }
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Load functions
+** =======================================================
+*/
+
+typedef struct LoadF {
+ int n; /* number of pre-read characters */
+ FILE *f; /* file being read */
+ char buff[BUFSIZ]; /* area for reading file */
+} LoadF;
+
+
+static const char *getF (lua_State *L, void *ud, size_t *size) {
+ LoadF *lf = (LoadF *)ud;
+ (void)L; /* not used */
+ if (lf->n > 0) { /* are there pre-read characters to be read? */
+ *size = lf->n; /* return them (chars already in buffer) */
+ lf->n = 0; /* no more pre-read characters */
+ }
+ else { /* read a block from file */
+ /* 'fread' can return > 0 *and* set the EOF flag. If next call to
+ 'getF' called 'fread', it might still wait for user input.
+ The next check avoids this problem. */
+ if (feof(lf->f)) return NULL;
+ *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */
+ }
+ return lf->buff;
+}
+
+
+static int errfile (lua_State *L, const char *what, int fnameindex) {
+ const char *serr = strerror(errno);
+ const char *filename = lua_tostring(L, fnameindex) + 1;
+ lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
+ lua_remove(L, fnameindex);
+ return LUA_ERRFILE;
+}
+
+
+static int skipBOM (LoadF *lf) {
+ const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
+ int c;
+ lf->n = 0;
+ do {
+ c = getc(lf->f);
+ if (c == EOF || c != *(const unsigned char *)p++) return c;
+ lf->buff[lf->n++] = c; /* to be read by the parser */
+ } while (*p != '\0');
+ lf->n = 0; /* prefix matched; discard it */
+ return getc(lf->f); /* return next character */
+}
+
+
+/*
+** reads the first character of file 'f' and skips an optional BOM mark
+** in its beginning plus its first line if it starts with '#'. Returns
+** true if it skipped the first line. In any case, '*cp' has the
+** first "valid" character of the file (after the optional BOM and
+** a first-line comment).
+*/
+static int skipcomment (LoadF *lf, int *cp) {
+ int c = *cp = skipBOM(lf);
+ if (c == '#') { /* first line is a comment (Unix exec. file)? */
+ do { /* skip first line */
+ c = getc(lf->f);
+ } while (c != EOF && c != '\n');
+ *cp = getc(lf->f); /* skip end-of-line, if present */
+ return 1; /* there was a comment */
+ }
+ else return 0; /* no comment */
+}
+
+
+LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
+ const char *mode) {
+ LoadF lf;
+ int status, readstatus;
+ int c;
+ int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
+ if (filename == NULL) {
+ lua_pushliteral(L, "=stdin");
+ lf.f = stdin;
+ }
+ else {
+ lua_pushfstring(L, "@%s", filename);
+ lf.f = fopen(filename, "r");
+ if (lf.f == NULL) return errfile(L, "open", fnameindex);
+ }
+ if (skipcomment(&lf, &c)) /* read initial portion */
+ lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
+ if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
+ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
+ if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
+ skipcomment(&lf, &c); /* re-read initial portion */
+ }
+ if (c != EOF)
+ lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
+ status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
+ readstatus = ferror(lf.f);
+ if (filename) fclose(lf.f); /* close file (even in case of errors) */
+ if (readstatus) {
+ lua_settop(L, fnameindex); /* ignore results from 'lua_load' */
+ return errfile(L, "read", fnameindex);
+ }
+ lua_remove(L, fnameindex);
+ return status;
+}
+
+
+typedef struct LoadS {
+ const char *s;
+ size_t size;
+} LoadS;
+
+
+static const char *getS (lua_State *L, void *ud, size_t *size) {
+ LoadS *ls = (LoadS *)ud;
+ (void)L; /* not used */
+ if (ls->size == 0) return NULL;
+ *size = ls->size;
+ ls->size = 0;
+ return ls->s;
+}
+
+
+LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size,
+ const char *name, const char *mode) {
+ LoadS ls;
+ ls.s = buff;
+ ls.size = size;
+ return lua_load(L, getS, &ls, name, mode);
+}
+
+
+LUALIB_API int luaL_loadstring (lua_State *L, const char *s) {
+ return luaL_loadbuffer(L, s, strlen(s), s);
+}
+
+/* }====================================================== */
+
+
+
+LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
+ if (!lua_getmetatable(L, obj)) /* no metatable? */
+ return LUA_TNIL;
+ else {
+ int tt;
+ lua_pushstring(L, event);
+ tt = lua_rawget(L, -2);
+ if (tt == LUA_TNIL) /* is metafield nil? */
+ lua_pop(L, 2); /* remove metatable and metafield */
+ else
+ lua_remove(L, -2); /* remove only metatable */
+ return tt; /* return metafield type */
+ }
+}
+
+
+LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
+ obj = lua_absindex(L, obj);
+ if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */
+ return 0;
+ lua_pushvalue(L, obj);
+ lua_call(L, 1, 1);
+ return 1;
+}
+
+
+LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
+ lua_Integer l;
+ int isnum;
+ lua_len(L, idx);
+ l = lua_tointegerx(L, -1, &isnum);
+ if (!isnum)
+ luaL_error(L, "object length is not an integer");
+ lua_pop(L, 1); /* remove object */
+ return l;
+}
+
+
+LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
+ if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */
+ switch (lua_type(L, idx)) {
+ case LUA_TNUMBER: {
+ if (lua_isinteger(L, idx))
+ lua_pushfstring(L, "%I", lua_tointeger(L, idx));
+ else
+ lua_pushfstring(L, "%f", lua_tonumber(L, idx));
+ break;
+ }
+ case LUA_TSTRING:
+ lua_pushvalue(L, idx);
+ break;
+ case LUA_TBOOLEAN:
+ lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false"));
+ break;
+ case LUA_TNIL:
+ lua_pushliteral(L, "nil");
+ break;
+ default:
+ lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
+ lua_topointer(L, idx));
+ break;
+ }
+ }
+ return lua_tolstring(L, -1, len);
+}
+
+
+/*
+** {======================================================
+** Compatibility with 5.1 module functions
+** =======================================================
+*/
+#if defined(LUA_COMPAT_MODULE)
+
+static const char *luaL_findtable (lua_State *L, int idx,
+ const char *fname, int szhint) {
+ const char *e;
+ if (idx) lua_pushvalue(L, idx);
+ do {
+ e = strchr(fname, '.');
+ if (e == NULL) e = fname + strlen(fname);
+ lua_pushlstring(L, fname, e - fname);
+ if (lua_rawget(L, -2) == LUA_TNIL) { /* no such field? */
+ lua_pop(L, 1); /* remove this nil */
+ lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
+ lua_pushlstring(L, fname, e - fname);
+ lua_pushvalue(L, -2);
+ lua_settable(L, -4); /* set new table into field */
+ }
+ else if (!lua_istable(L, -1)) { /* field has a non-table value? */
+ lua_pop(L, 2); /* remove table and value */
+ return fname; /* return problematic part of the name */
+ }
+ lua_remove(L, -2); /* remove previous table */
+ fname = e + 1;
+ } while (*e == '.');
+ return NULL;
+}
+
+
+/*
+** Count number of elements in a luaL_Reg list.
+*/
+static int libsize (const luaL_Reg *l) {
+ int size = 0;
+ for (; l && l->name; l++) size++;
+ return size;
+}
+
+
+/*
+** Find or create a module table with a given name. The function
+** first looks at the _LOADED table and, if that fails, try a
+** global variable with that name. In any case, leaves on the stack
+** the module table.
+*/
+LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
+ int sizehint) {
+ luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */
+ if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */
+ lua_pop(L, 1); /* remove previous result */
+ /* try global variable (and create one if it does not exist) */
+ lua_pushglobaltable(L);
+ if (luaL_findtable(L, 0, modname, sizehint) != NULL)
+ luaL_error(L, "name conflict for module '%s'", modname);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */
+ }
+ lua_remove(L, -2); /* remove _LOADED table */
+}
+
+
+LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
+ const luaL_Reg *l, int nup) {
+ luaL_checkversion(L);
+ if (libname) {
+ luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */
+ lua_insert(L, -(nup + 1)); /* move library table to below upvalues */
+ }
+ if (l)
+ luaL_setfuncs(L, l, nup);
+ else
+ lua_pop(L, nup); /* remove upvalues */
+}
+
+#endif
+/* }====================================================== */
+
+/*
+** set functions from list 'l' into table at top - 'nup'; each
+** function gets the 'nup' elements at the top as upvalues.
+** Returns with only the table at the stack.
+*/
+LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
+ luaL_checkstack(L, nup, "too many upvalues");
+ for (; l->name != NULL; l++) { /* fill the table with given functions */
+ int i;
+ for (i = 0; i < nup; i++) /* copy upvalues to the top */
+ lua_pushvalue(L, -nup);
+ lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
+ lua_setfield(L, -(nup + 2), l->name);
+ }
+ lua_pop(L, nup); /* remove upvalues */
+}
+
+
+/*
+** ensure that stack[idx][fname] has a table and push that table
+** into the stack
+*/
+LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
+ if (lua_getfield(L, idx, fname) == LUA_TTABLE)
+ return 1; /* table already there */
+ else {
+ lua_pop(L, 1); /* remove previous result */
+ idx = lua_absindex(L, idx);
+ lua_newtable(L);
+ lua_pushvalue(L, -1); /* copy to be left at top */
+ lua_setfield(L, idx, fname); /* assign new table to field */
+ return 0; /* false, because did not find table there */
+ }
+}
+
+
+/*
+** Stripped-down 'require': After checking "loaded" table, calls 'openf'
+** to open a module, registers the result in 'package.loaded' table and,
+** if 'glb' is true, also registers the result in the global table.
+** Leaves resulting module on the top.
+*/
+LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
+ lua_CFunction openf, int glb) {
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
+ lua_getfield(L, -1, modname); /* _LOADED[modname] */
+ if (!lua_toboolean(L, -1)) { /* package not already loaded? */
+ lua_pop(L, 1); /* remove field */
+ lua_pushcfunction(L, openf);
+ lua_pushstring(L, modname); /* argument to open function */
+ lua_call(L, 1, 1); /* call 'openf' to open module */
+ lua_pushvalue(L, -1); /* make copy of module (call result) */
+ lua_setfield(L, -3, modname); /* _LOADED[modname] = module */
+ }
+ lua_remove(L, -2); /* remove _LOADED table */
+ if (glb) {
+ lua_pushvalue(L, -1); /* copy of module */
+ lua_setglobal(L, modname); /* _G[modname] = module */
+ }
+}
+
+
+LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,
+ const char *r) {
+ const char *wild;
+ size_t l = strlen(p);
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ while ((wild = strstr(s, p)) != NULL) {
+ luaL_addlstring(&b, s, wild - s); /* push prefix */
+ luaL_addstring(&b, r); /* push replacement in place of pattern */
+ s = wild + l; /* continue after 'p' */
+ }
+ luaL_addstring(&b, s); /* push last suffix */
+ luaL_pushresult(&b);
+ return lua_tostring(L, -1);
+}
+
+
+static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
+ (void)ud; (void)osize; /* not used */
+ if (nsize == 0) {
+ free(ptr);
+ return NULL;
+ }
+ else
+ return realloc(ptr, nsize);
+}
+
+
+static int panic (lua_State *L) {
+ lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
+ lua_tostring(L, -1));
+ return 0; /* return to Lua to abort */
+}
+
+
+LUALIB_API lua_State *luaL_newstate (void) {
+ lua_State *L = lua_newstate(l_alloc, NULL);
+ if (L) lua_atpanic(L, &panic);
+ return L;
+}
+
+
+LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
+ const lua_Number *v = lua_version(L);
+ if (sz != LUAL_NUMSIZES) /* check numeric types */
+ luaL_error(L, "core and library have incompatible numeric types");
+ if (v != lua_version(NULL))
+ luaL_error(L, "multiple Lua VMs detected");
+ else if (*v != ver)
+ luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
+ ver, *v);
+}
+
diff --git a/external/lua-5.3.3/src/lauxlib.h b/external/lua-5.3.3/src/lauxlib.h
new file mode 100644
index 0000000..5c53523
--- /dev/null
+++ b/external/lua-5.3.3/src/lauxlib.h
@@ -0,0 +1,257 @@
+/*
+** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lauxlib_h
+#define lauxlib_h
+
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "lua.h"
+#ifndef GRANGER
+#include "../../../src/qcommon/q3_lauxlib.h"
+#endif
+
+/* extra error code for 'luaL_load' */
+#define LUA_ERRFILE (LUA_ERRERR+1)
+
+
+typedef struct luaL_Reg {
+ const char *name;
+ lua_CFunction func;
+} luaL_Reg;
+
+
+#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number))
+
+LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);
+#define luaL_checkversion(L) \
+ luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)
+
+LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
+LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
+LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
+LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
+LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
+ size_t *l);
+LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
+ const char *def, size_t *l);
+LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
+LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
+
+LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
+LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
+ lua_Integer def);
+
+LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
+LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
+LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
+
+LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
+LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
+LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
+LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
+
+LUALIB_API void (luaL_where) (lua_State *L, int lvl);
+LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
+
+LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
+ const char *const lst[]);
+
+LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
+LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
+
+/* predefined references */
+#define LUA_NOREF (-2)
+#define LUA_REFNIL (-1)
+
+LUALIB_API int (luaL_ref) (lua_State *L, int t);
+LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
+
+LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
+ const char *mode);
+
+#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
+
+LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
+ const char *name, const char *mode);
+LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
+
+LUALIB_API lua_State *(luaL_newstate) (void);
+
+LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
+
+LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
+ const char *r);
+
+LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
+
+LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
+
+LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
+ const char *msg, int level);
+
+LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
+ lua_CFunction openf, int glb);
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+
+#define luaL_newlibtable(L,l) \
+ lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
+
+#define luaL_newlib(L,l) \
+ (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
+
+#define luaL_argcheck(L, cond,arg,extramsg) \
+ ((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
+#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
+#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
+
+#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
+
+#define luaL_dofile(L, fn) \
+ (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_dostring(L, s) \
+ (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
+
+#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
+
+#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+typedef struct luaL_Buffer {
+ char *b; /* buffer address */
+ size_t size; /* buffer size */
+ size_t n; /* number of characters in buffer */
+ lua_State *L;
+ char initb[LUAL_BUFFERSIZE]; /* initial buffer */
+} luaL_Buffer;
+
+
+#define luaL_addchar(B,c) \
+ ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
+ ((B)->b[(B)->n++] = (c)))
+
+#define luaL_addsize(B,s) ((B)->n += (s))
+
+LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
+LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
+LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
+LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
+LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
+LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
+
+#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** File handles for IO library
+** =======================================================
+*/
+
+/*
+** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
+** initial structure 'luaL_Stream' (it may contain other fields
+** after that initial structure).
+*/
+
+#define LUA_FILEHANDLE "FILE*"
+
+
+typedef struct luaL_Stream {
+ FILE *f; /* stream (NULL for incompletely created streams) */
+ lua_CFunction closef; /* to close stream (NULL for closed streams) */
+} luaL_Stream;
+
+/* }====================================================== */
+
+
+
+/* compatibility with old module system */
+#if defined(LUA_COMPAT_MODULE)
+
+LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
+ int sizehint);
+LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
+ const luaL_Reg *l, int nup);
+
+#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
+
+#endif
+
+
+// XXX -bbq Check q3_lauxlib.h for the overrides
+/*
+** {==================================================================
+** "Abstraction Layer" for basic report of messages and errors
+** ===================================================================
+*/
+
+/* print a string */
+#if !defined(lua_writestring)
+#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
+#endif
+
+/* print a newline and flush the output */
+#if !defined(lua_writeline)
+#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
+#endif
+
+/* print an error message */
+#if !defined(lua_writestringerror)
+#define lua_writestringerror(s,p) \
+ (fprintf(stderr, (s), (p)), fflush(stderr))
+#endif
+
+/* }================================================================== */
+
+/*
+** {============================================================
+** Compatibility with deprecated conversions
+** =============================================================
+*/
+#if defined(LUA_COMPAT_APIINTCASTS)
+
+#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a))
+#define luaL_optunsigned(L,a,d) \
+ ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))
+
+#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
+#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
+
+#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
+#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
+
+#endif
+/* }============================================================ */
+
+
+
+#endif
+
+
diff --git a/external/lua-5.3.3/src/lbaselib.c b/external/lua-5.3.3/src/lbaselib.c
new file mode 100644
index 0000000..c0b89fa
--- /dev/null
+++ b/external/lua-5.3.3/src/lbaselib.c
@@ -0,0 +1,500 @@
+/*
+** $Id: lbaselib.c,v 1.313 2016/04/11 19:18:40 roberto Exp $
+** Basic library
+** See Copyright Notice in lua.h
+*/
+
+#define lbaselib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+static int luaB_print (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ int i;
+ lua_getglobal(L, "tostring");
+ for (i=1; i<=n; i++)
+ {
+ const char *s;
+ size_t l;
+ lua_pushvalue(L, -1); /* function to be called */
+ lua_pushvalue(L, i); /* value to print */
+ lua_call(L, 1, 1);
+ s = lua_tolstring(L, -1, &l); /* get result */
+ if (s == NULL)
+ return luaL_error(L, "'tostring' must return a string to 'print'");
+ if (i>1)
+ lua_writestring("\t", 1);
+ lua_writestring(s, l);
+ lua_pop(L, 1); /* pop result */
+ }
+ lua_writeline();
+ return 0;
+}
+
+
+#define SPACECHARS " \f\n\r\t\v"
+
+static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
+ lua_Unsigned n = 0;
+ int neg = 0;
+ s += strspn(s, SPACECHARS); /* skip initial spaces */
+ if (*s == '-') { s++; neg = 1; } /* handle signal */
+ else if (*s == '+') s++;
+ if (!isalnum((unsigned char)*s)) /* no digit? */
+ return NULL;
+ do {
+ int digit = (isdigit((unsigned char)*s)) ? *s - '0'
+ : (toupper((unsigned char)*s) - 'A') + 10;
+ if (digit >= base) return NULL; /* invalid numeral */
+ n = n * base + digit;
+ s++;
+ } while (isalnum((unsigned char)*s));
+ s += strspn(s, SPACECHARS); /* skip trailing spaces */
+ *pn = (lua_Integer)((neg) ? (0u - n) : n);
+ return s;
+}
+
+
+static int luaB_tonumber (lua_State *L) {
+ if (lua_isnoneornil(L, 2)) { /* standard conversion? */
+ luaL_checkany(L, 1);
+ if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */
+ lua_settop(L, 1); /* yes; return it */
+ return 1;
+ }
+ else {
+ size_t l;
+ const char *s = lua_tolstring(L, 1, &l);
+ if (s != NULL && lua_stringtonumber(L, s) == l + 1)
+ return 1; /* successful conversion to number */
+ /* else not a number */
+ }
+ }
+ else {
+ size_t l;
+ const char *s;
+ lua_Integer n = 0; /* to avoid warnings */
+ lua_Integer base = luaL_checkinteger(L, 2);
+ luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
+ s = lua_tolstring(L, 1, &l);
+ luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
+ if (b_str2int(s, (int)base, &n) == s + l) {
+ lua_pushinteger(L, n);
+ return 1;
+ } /* else not a number */
+ } /* else not a number */
+ lua_pushnil(L); /* not a number */
+ return 1;
+}
+
+
+static int luaB_error (lua_State *L) {
+ int level = (int)luaL_optinteger(L, 2, 1);
+ lua_settop(L, 1);
+ if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
+ luaL_where(L, level); /* add extra information */
+ lua_pushvalue(L, 1);
+ lua_concat(L, 2);
+ }
+ return lua_error(L);
+}
+
+
+static int luaB_getmetatable (lua_State *L) {
+ luaL_checkany(L, 1);
+ if (!lua_getmetatable(L, 1)) {
+ lua_pushnil(L);
+ return 1; /* no metatable */
+ }
+ luaL_getmetafield(L, 1, "__metatable");
+ return 1; /* returns either __metatable field (if present) or metatable */
+}
+
+
+static int luaB_setmetatable (lua_State *L) {
+ int t = lua_type(L, 2);
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
+ "nil or table expected");
+ if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL)
+ return luaL_error(L, "cannot change a protected metatable");
+ lua_settop(L, 2);
+ lua_setmetatable(L, 1);
+ return 1;
+}
+
+
+static int luaB_rawequal (lua_State *L) {
+ luaL_checkany(L, 1);
+ luaL_checkany(L, 2);
+ lua_pushboolean(L, lua_rawequal(L, 1, 2));
+ return 1;
+}
+
+
+static int luaB_rawlen (lua_State *L) {
+ int t = lua_type(L, 1);
+ luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
+ "table or string expected");
+ lua_pushinteger(L, lua_rawlen(L, 1));
+ return 1;
+}
+
+
+static int luaB_rawget (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checkany(L, 2);
+ lua_settop(L, 2);
+ lua_rawget(L, 1);
+ return 1;
+}
+
+static int luaB_rawset (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checkany(L, 2);
+ luaL_checkany(L, 3);
+ lua_settop(L, 3);
+ lua_rawset(L, 1);
+ return 1;
+}
+
+
+static int luaB_collectgarbage (lua_State *L) {
+ static const char *const opts[] = {"stop", "restart", "collect",
+ "count", "step", "setpause", "setstepmul",
+ "isrunning", NULL};
+ static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
+ LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
+ LUA_GCISRUNNING};
+ int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
+ int ex = (int)luaL_optinteger(L, 2, 0);
+ int res = lua_gc(L, o, ex);
+ switch (o) {
+ case LUA_GCCOUNT: {
+ int b = lua_gc(L, LUA_GCCOUNTB, 0);
+ lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024));
+ return 1;
+ }
+ case LUA_GCSTEP: case LUA_GCISRUNNING: {
+ lua_pushboolean(L, res);
+ return 1;
+ }
+ default: {
+ lua_pushinteger(L, res);
+ return 1;
+ }
+ }
+}
+
+
+static int luaB_type (lua_State *L) {
+ int t = lua_type(L, 1);
+ luaL_argcheck(L, t != LUA_TNONE, 1, "value expected");
+ lua_pushstring(L, lua_typename(L, t));
+ return 1;
+}
+
+
+static int pairsmeta (lua_State *L, const char *method, int iszero,
+ lua_CFunction iter) {
+ if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */
+ luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */
+ lua_pushcfunction(L, iter); /* will return generator, */
+ lua_pushvalue(L, 1); /* state, */
+ if (iszero) lua_pushinteger(L, 0); /* and initial value */
+ else lua_pushnil(L);
+ }
+ else {
+ lua_pushvalue(L, 1); /* argument 'self' to metamethod */
+ lua_call(L, 1, 3); /* get 3 values from metamethod */
+ }
+ return 3;
+}
+
+
+static int luaB_next (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_settop(L, 2); /* create a 2nd argument if there isn't one */
+ if (lua_next(L, 1))
+ return 2;
+ else {
+ lua_pushnil(L);
+ return 1;
+ }
+}
+
+
+static int luaB_pairs (lua_State *L) {
+ return pairsmeta(L, "__pairs", 0, luaB_next);
+}
+
+
+/*
+** Traversal function for 'ipairs'
+*/
+static int ipairsaux (lua_State *L) {
+ lua_Integer i = luaL_checkinteger(L, 2) + 1;
+ lua_pushinteger(L, i);
+ return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
+}
+
+
+/*
+** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
+** (The given "table" may not be a table.)
+*/
+static int luaB_ipairs (lua_State *L) {
+#if defined(LUA_COMPAT_IPAIRS)
+ return pairsmeta(L, "__ipairs", 1, ipairsaux);
+#else
+ luaL_checkany(L, 1);
+ lua_pushcfunction(L, ipairsaux); /* iteration function */
+ lua_pushvalue(L, 1); /* state */
+ lua_pushinteger(L, 0); /* initial value */
+ return 3;
+#endif
+}
+
+
+static int load_aux (lua_State *L, int status, int envidx) {
+ if (status == LUA_OK) {
+ if (envidx != 0) { /* 'env' parameter? */
+ lua_pushvalue(L, envidx); /* environment for loaded function */
+ if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
+ lua_pop(L, 1); /* remove 'env' if not used by previous call */
+ }
+ return 1;
+ }
+ else { /* error (message is on top of the stack) */
+ lua_pushnil(L);
+ lua_insert(L, -2); /* put before error message */
+ return 2; /* return nil plus error message */
+ }
+}
+
+
+static int luaB_loadfile (lua_State *L) {
+ const char *fname = luaL_optstring(L, 1, NULL);
+ const char *mode = luaL_optstring(L, 2, NULL);
+ int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
+ int status = luaL_loadfilex(L, fname, mode);
+ return load_aux(L, status, env);
+}
+
+
+/*
+** {======================================================
+** Generic Read function
+** =======================================================
+*/
+
+
+/*
+** reserved slot, above all arguments, to hold a copy of the returned
+** string to avoid it being collected while parsed. 'load' has four
+** optional arguments (chunk, source name, mode, and environment).
+*/
+#define RESERVEDSLOT 5
+
+
+/*
+** Reader for generic 'load' function: 'lua_load' uses the
+** stack for internal stuff, so the reader cannot change the
+** stack top. Instead, it keeps its resulting string in a
+** reserved slot inside the stack.
+*/
+static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
+ (void)(ud); /* not used */
+ luaL_checkstack(L, 2, "too many nested functions");
+ lua_pushvalue(L, 1); /* get function */
+ lua_call(L, 0, 1); /* call it */
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 1); /* pop result */
+ *size = 0;
+ return NULL;
+ }
+ else if (!lua_isstring(L, -1))
+ luaL_error(L, "reader function must return a string");
+ lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
+ return lua_tolstring(L, RESERVEDSLOT, size);
+}
+
+
+static int luaB_load (lua_State *L) {
+ int status;
+ size_t l;
+ const char *s = lua_tolstring(L, 1, &l);
+ const char *mode = luaL_optstring(L, 3, "bt");
+ int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
+ if (s != NULL) { /* loading a string? */
+ const char *chunkname = luaL_optstring(L, 2, s);
+ status = luaL_loadbufferx(L, s, l, chunkname, mode);
+ }
+ else { /* loading from a reader function */
+ const char *chunkname = luaL_optstring(L, 2, "=(load)");
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ lua_settop(L, RESERVEDSLOT); /* create reserved slot */
+ status = lua_load(L, generic_reader, NULL, chunkname, mode);
+ }
+ return load_aux(L, status, env);
+}
+
+/* }====================================================== */
+
+
+static int dofilecont (lua_State *L, int d1, lua_KContext d2) {
+ (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */
+ return lua_gettop(L) - 1;
+}
+
+
+static int luaB_dofile (lua_State *L) {
+ const char *fname = luaL_optstring(L, 1, NULL);
+ lua_settop(L, 1);
+ if (luaL_loadfile(L, fname) != LUA_OK)
+ return lua_error(L);
+ lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
+ return dofilecont(L, 0, 0);
+}
+
+
+static int luaB_assert (lua_State *L) {
+ if (lua_toboolean(L, 1)) /* condition is true? */
+ return lua_gettop(L); /* return all arguments */
+ else { /* error */
+ luaL_checkany(L, 1); /* there must be a condition */
+ lua_remove(L, 1); /* remove it */
+ lua_pushliteral(L, "assertion failed!"); /* default message */
+ lua_settop(L, 1); /* leave only message (default if no other one) */
+ return luaB_error(L); /* call 'error' */
+ }
+}
+
+
+static int luaB_select (lua_State *L) {
+ int n = lua_gettop(L);
+ if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
+ lua_pushinteger(L, n-1);
+ return 1;
+ }
+ else {
+ lua_Integer i = luaL_checkinteger(L, 1);
+ if (i < 0) i = n + i;
+ else if (i > n) i = n;
+ luaL_argcheck(L, 1 <= i, 1, "index out of range");
+ return n - (int)i;
+ }
+}
+
+
+/*
+** Continuation function for 'pcall' and 'xpcall'. Both functions
+** already pushed a 'true' before doing the call, so in case of success
+** 'finishpcall' only has to return everything in the stack minus
+** 'extra' values (where 'extra' is exactly the number of items to be
+** ignored).
+*/
+static int finishpcall (lua_State *L, int status, lua_KContext extra) {
+ if (status != LUA_OK && status != LUA_YIELD) { /* error? */
+ lua_pushboolean(L, 0); /* first result (false) */
+ lua_pushvalue(L, -2); /* error message */
+ return 2; /* return false, msg */
+ }
+ else
+ return lua_gettop(L) - (int)extra; /* return all results */
+}
+
+
+static int luaB_pcall (lua_State *L) {
+ int status;
+ luaL_checkany(L, 1);
+ lua_pushboolean(L, 1); /* first result if no errors */
+ lua_insert(L, 1); /* put it in place */
+ status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall);
+ return finishpcall(L, status, 0);
+}
+
+
+/*
+** Do a protected call with error handling. After 'lua_rotate', the
+** stack will have <f, err, true, f, [args...]>; so, the function passes
+** 2 to 'finishpcall' to skip the 2 first values when returning results.
+*/
+static int luaB_xpcall (lua_State *L) {
+ int status;
+ int n = lua_gettop(L);
+ luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */
+ lua_pushboolean(L, 1); /* first result */
+ lua_pushvalue(L, 1); /* function */
+ lua_rotate(L, 3, 2); /* move them below function's arguments */
+ status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall);
+ return finishpcall(L, status, 2);
+}
+
+
+static int luaB_tostring (lua_State *L) {
+ luaL_checkany(L, 1);
+ luaL_tolstring(L, 1, NULL);
+ return 1;
+}
+
+
+static const luaL_Reg base_funcs[] = {
+ {"assert", luaB_assert},
+ {"collectgarbage", luaB_collectgarbage},
+ {"dofile", luaB_dofile},
+ {"error", luaB_error},
+ {"getmetatable", luaB_getmetatable},
+ {"ipairs", luaB_ipairs},
+ {"loadfile", luaB_loadfile},
+ {"load", luaB_load},
+#if defined(LUA_COMPAT_LOADSTRING)
+ {"loadstring", luaB_load},
+#endif
+ {"next", luaB_next},
+ {"pairs", luaB_pairs},
+ {"pcall", luaB_pcall},
+ {"print", luaB_print},
+ {"rawequal", luaB_rawequal},
+ {"rawlen", luaB_rawlen},
+ {"rawget", luaB_rawget},
+ {"rawset", luaB_rawset},
+ {"select", luaB_select},
+ {"setmetatable", luaB_setmetatable},
+ {"tonumber", luaB_tonumber},
+ {"tostring", luaB_tostring},
+ {"type", luaB_type},
+ {"xpcall", luaB_xpcall},
+ /* placeholders */
+ {"_G", NULL},
+ {"_VERSION", NULL},
+ {NULL, NULL}
+};
+
+
+LUAMOD_API int luaopen_base (lua_State *L) {
+ /* open lib into global table */
+ lua_pushglobaltable(L);
+ luaL_setfuncs(L, base_funcs, 0);
+ /* set global _G */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "_G");
+ /* set global _VERSION */
+ lua_pushliteral(L, LUA_VERSION);
+ lua_setfield(L, -2, "_VERSION");
+ return 1;
+}
+
diff --git a/external/lua-5.3.3/src/lbitlib.c b/external/lua-5.3.3/src/lbitlib.c
new file mode 100644
index 0000000..1cb1d5b
--- /dev/null
+++ b/external/lua-5.3.3/src/lbitlib.c
@@ -0,0 +1,233 @@
+/*
+** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $
+** Standard library for bitwise operations
+** See Copyright Notice in lua.h
+*/
+
+#define lbitlib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+#if defined(LUA_COMPAT_BITLIB) /* { */
+
+
+#define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
+#define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i))
+
+
+/* number of bits to consider in a number */
+#if !defined(LUA_NBITS)
+#define LUA_NBITS 32
+#endif
+
+
+/*
+** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must
+** be made in two parts to avoid problems when LUA_NBITS is equal to the
+** number of bits in a lua_Unsigned.)
+*/
+#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1))
+
+
+/* macro to trim extra bits */
+#define trim(x) ((x) & ALLONES)
+
+
+/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */
+#define mask(n) (~((ALLONES << 1) << ((n) - 1)))
+
+
+
+static lua_Unsigned andaux (lua_State *L) {
+ int i, n = lua_gettop(L);
+ lua_Unsigned r = ~(lua_Unsigned)0;
+ for (i = 1; i <= n; i++)
+ r &= checkunsigned(L, i);
+ return trim(r);
+}
+
+
+static int b_and (lua_State *L) {
+ lua_Unsigned r = andaux(L);
+ pushunsigned(L, r);
+ return 1;
+}
+
+
+static int b_test (lua_State *L) {
+ lua_Unsigned r = andaux(L);
+ lua_pushboolean(L, r != 0);
+ return 1;
+}
+
+
+static int b_or (lua_State *L) {
+ int i, n = lua_gettop(L);
+ lua_Unsigned r = 0;
+ for (i = 1; i <= n; i++)
+ r |= checkunsigned(L, i);
+ pushunsigned(L, trim(r));
+ return 1;
+}
+
+
+static int b_xor (lua_State *L) {
+ int i, n = lua_gettop(L);
+ lua_Unsigned r = 0;
+ for (i = 1; i <= n; i++)
+ r ^= checkunsigned(L, i);
+ pushunsigned(L, trim(r));
+ return 1;
+}
+
+
+static int b_not (lua_State *L) {
+ lua_Unsigned r = ~checkunsigned(L, 1);
+ pushunsigned(L, trim(r));
+ return 1;
+}
+
+
+static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) {
+ if (i < 0) { /* shift right? */
+ i = -i;
+ r = trim(r);
+ if (i >= LUA_NBITS) r = 0;
+ else r >>= i;
+ }
+ else { /* shift left */
+ if (i >= LUA_NBITS) r = 0;
+ else r <<= i;
+ r = trim(r);
+ }
+ pushunsigned(L, r);
+ return 1;
+}
+
+
+static int b_lshift (lua_State *L) {
+ return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2));
+}
+
+
+static int b_rshift (lua_State *L) {
+ return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2));
+}
+
+
+static int b_arshift (lua_State *L) {
+ lua_Unsigned r = checkunsigned(L, 1);
+ lua_Integer i = luaL_checkinteger(L, 2);
+ if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1))))
+ return b_shift(L, r, -i);
+ else { /* arithmetic shift for 'negative' number */
+ if (i >= LUA_NBITS) r = ALLONES;
+ else
+ r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */
+ pushunsigned(L, r);
+ return 1;
+ }
+}
+
+
+static int b_rot (lua_State *L, lua_Integer d) {
+ lua_Unsigned r = checkunsigned(L, 1);
+ int i = d & (LUA_NBITS - 1); /* i = d % NBITS */
+ r = trim(r);
+ if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
+ r = (r << i) | (r >> (LUA_NBITS - i));
+ pushunsigned(L, trim(r));
+ return 1;
+}
+
+
+static int b_lrot (lua_State *L) {
+ return b_rot(L, luaL_checkinteger(L, 2));
+}
+
+
+static int b_rrot (lua_State *L) {
+ return b_rot(L, -luaL_checkinteger(L, 2));
+}
+
+
+/*
+** get field and width arguments for field-manipulation functions,
+** checking whether they are valid.
+** ('luaL_error' called without 'return' to avoid later warnings about
+** 'width' being used uninitialized.)
+*/
+static int fieldargs (lua_State *L, int farg, int *width) {
+ lua_Integer f = luaL_checkinteger(L, farg);
+ lua_Integer w = luaL_optinteger(L, farg + 1, 1);
+ luaL_argcheck(L, 0 <= f, farg, "field cannot be negative");
+ luaL_argcheck(L, 0 < w, farg + 1, "width must be positive");
+ if (f + w > LUA_NBITS)
+ luaL_error(L, "trying to access non-existent bits");
+ *width = (int)w;
+ return (int)f;
+}
+
+
+static int b_extract (lua_State *L) {
+ int w;
+ lua_Unsigned r = trim(checkunsigned(L, 1));
+ int f = fieldargs(L, 2, &w);
+ r = (r >> f) & mask(w);
+ pushunsigned(L, r);
+ return 1;
+}
+
+
+static int b_replace (lua_State *L) {
+ int w;
+ lua_Unsigned r = trim(checkunsigned(L, 1));
+ lua_Unsigned v = trim(checkunsigned(L, 2));
+ int f = fieldargs(L, 3, &w);
+ lua_Unsigned m = mask(w);
+ r = (r & ~(m << f)) | ((v & m) << f);
+ pushunsigned(L, r);
+ return 1;
+}
+
+
+static const luaL_Reg bitlib[] = {
+ {"arshift", b_arshift},
+ {"band", b_and},
+ {"bnot", b_not},
+ {"bor", b_or},
+ {"bxor", b_xor},
+ {"btest", b_test},
+ {"extract", b_extract},
+ {"lrotate", b_lrot},
+ {"lshift", b_lshift},
+ {"replace", b_replace},
+ {"rrotate", b_rrot},
+ {"rshift", b_rshift},
+ {NULL, NULL}
+};
+
+
+
+LUAMOD_API int luaopen_bit32 (lua_State *L) {
+ luaL_newlib(L, bitlib);
+ return 1;
+}
+
+
+#else /* }{ */
+
+
+LUAMOD_API int luaopen_bit32 (lua_State *L) {
+ return luaL_error(L, "library 'bit32' has been deprecated");
+}
+
+#endif /* } */
diff --git a/external/lua-5.3.3/src/lcode.c b/external/lua-5.3.3/src/lcode.c
new file mode 100644
index 0000000..2cd0dd2
--- /dev/null
+++ b/external/lua-5.3.3/src/lcode.c
@@ -0,0 +1,1199 @@
+/*
+** $Id: lcode.c,v 2.109 2016/05/13 19:09:21 roberto Exp $
+** Code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+#define lcode_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "lua.h"
+
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lgc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "lvm.h"
+
+
+/* Maximum number of registers in a Lua function (must fit in 8 bits) */
+#define MAXREGS 255
+
+
+#define hasjumps(e) ((e)->t != (e)->f)
+
+
+/*
+** If expression is a numeric constant, fills 'v' with its value
+** and returns 1. Otherwise, returns 0.
+*/
+static int tonumeral(expdesc *e, TValue *v) {
+ if (hasjumps(e))
+ return 0; /* not a numeral */
+ switch (e->k) {
+ case VKINT:
+ if (v) setivalue(v, e->u.ival);
+ return 1;
+ case VKFLT:
+ if (v) setfltvalue(v, e->u.nval);
+ return 1;
+ default: return 0;
+ }
+}
+
+
+/*
+** Create a OP_LOADNIL instruction, but try to optimize: if the previous
+** instruction is also OP_LOADNIL and ranges are compatible, adjust
+** range of previous instruction instead of emitting a new one. (For
+** instance, 'local a; local b' will generate a single opcode.)
+*/
+void luaK_nil (FuncState *fs, int from, int n) {
+ Instruction *previous;
+ int l = from + n - 1; /* last register to set nil */
+ if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
+ previous = &fs->f->code[fs->pc-1];
+ if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */
+ int pfrom = GETARG_A(*previous); /* get previous range */
+ int pl = pfrom + GETARG_B(*previous);
+ if ((pfrom <= from && from <= pl + 1) ||
+ (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
+ if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */
+ if (pl > l) l = pl; /* l = max(l, pl) */
+ SETARG_A(*previous, from);
+ SETARG_B(*previous, l - from);
+ return;
+ }
+ } /* else go through */
+ }
+ luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
+}
+
+
+/*
+** Gets the destination address of a jump instruction. Used to traverse
+** a list of jumps.
+*/
+static int getjump (FuncState *fs, int pc) {
+ int offset = GETARG_sBx(fs->f->code[pc]);
+ if (offset == NO_JUMP) /* point to itself represents end of list */
+ return NO_JUMP; /* end of list */
+ else
+ return (pc+1)+offset; /* turn offset into absolute position */
+}
+
+
+/*
+** Fix jump instruction at position 'pc' to jump to 'dest'.
+** (Jump addresses are relative in Lua)
+*/
+static void fixjump (FuncState *fs, int pc, int dest) {
+ Instruction *jmp = &fs->f->code[pc];
+ int offset = dest - (pc + 1);
+ lua_assert(dest != NO_JUMP);
+ if (abs(offset) > MAXARG_sBx)
+ luaX_syntaxerror(fs->ls, "control structure too long");
+ SETARG_sBx(*jmp, offset);
+}
+
+
+/*
+** Concatenate jump-list 'l2' into jump-list 'l1'
+*/
+void luaK_concat (FuncState *fs, int *l1, int l2) {
+ if (l2 == NO_JUMP) return; /* nothing to concatenate? */
+ else if (*l1 == NO_JUMP) /* no original list? */
+ *l1 = l2; /* 'l1' points to 'l2' */
+ else {
+ int list = *l1;
+ int next;
+ while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
+ list = next;
+ fixjump(fs, list, l2); /* last element links to 'l2' */
+ }
+}
+
+
+/*
+** Create a jump instruction and return its position, so its destination
+** can be fixed later (with 'fixjump'). If there are jumps to
+** this position (kept in 'jpc'), link them all together so that
+** 'patchlistaux' will fix all them directly to the final destination.
+*/
+int luaK_jump (FuncState *fs) {
+ int jpc = fs->jpc; /* save list of jumps to here */
+ int j;
+ fs->jpc = NO_JUMP; /* no more jumps to here */
+ j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
+ luaK_concat(fs, &j, jpc); /* keep them on hold */
+ return j;
+}
+
+
+/*
+** Code a 'return' instruction
+*/
+void luaK_ret (FuncState *fs, int first, int nret) {
+ luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
+}
+
+
+/*
+** Code a "conditional jump", that is, a test or comparison opcode
+** followed by a jump. Return jump position.
+*/
+static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
+ luaK_codeABC(fs, op, A, B, C);
+ return luaK_jump(fs);
+}
+
+
+/*
+** returns current 'pc' and marks it as a jump target (to avoid wrong
+** optimizations with consecutive instructions not in the same basic block).
+*/
+int luaK_getlabel (FuncState *fs) {
+ fs->lasttarget = fs->pc;
+ return fs->pc;
+}
+
+
+/*
+** Returns the position of the instruction "controlling" a given
+** jump (that is, its condition), or the jump itself if it is
+** unconditional.
+*/
+static Instruction *getjumpcontrol (FuncState *fs, int pc) {
+ Instruction *pi = &fs->f->code[pc];
+ if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
+ return pi-1;
+ else
+ return pi;
+}
+
+
+/*
+** Patch destination register for a TESTSET instruction.
+** If instruction in position 'node' is not a TESTSET, return 0 ("fails").
+** Otherwise, if 'reg' is not 'NO_REG', set it as the destination
+** register. Otherwise, change instruction to a simple 'TEST' (produces
+** no register value)
+*/
+static int patchtestreg (FuncState *fs, int node, int reg) {
+ Instruction *i = getjumpcontrol(fs, node);
+ if (GET_OPCODE(*i) != OP_TESTSET)
+ return 0; /* cannot patch other instructions */
+ if (reg != NO_REG && reg != GETARG_B(*i))
+ SETARG_A(*i, reg);
+ else {
+ /* no register to put value or register already has the value;
+ change instruction to simple test */
+ *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
+ }
+ return 1;
+}
+
+
+/*
+** Traverse a list of tests ensuring no one produces a value
+*/
+static void removevalues (FuncState *fs, int list) {
+ for (; list != NO_JUMP; list = getjump(fs, list))
+ patchtestreg(fs, list, NO_REG);
+}
+
+
+/*
+** Traverse a list of tests, patching their destination address and
+** registers: tests producing values jump to 'vtarget' (and put their
+** values in 'reg'), other tests jump to 'dtarget'.
+*/
+static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
+ int dtarget) {
+ while (list != NO_JUMP) {
+ int next = getjump(fs, list);
+ if (patchtestreg(fs, list, reg))
+ fixjump(fs, list, vtarget);
+ else
+ fixjump(fs, list, dtarget); /* jump to default target */
+ list = next;
+ }
+}
+
+
+/*
+** Ensure all pending jumps to current position are fixed (jumping
+** to current position with no values) and reset list of pending
+** jumps
+*/
+static void dischargejpc (FuncState *fs) {
+ patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
+ fs->jpc = NO_JUMP;
+}
+
+
+/*
+** Add elements in 'list' to list of pending jumps to "here"
+** (current position)
+*/
+void luaK_patchtohere (FuncState *fs, int list) {
+ luaK_getlabel(fs); /* mark "here" as a jump target */
+ luaK_concat(fs, &fs->jpc, list);
+}
+
+
+/*
+** Path all jumps in 'list' to jump to 'target'.
+** (The assert means that we cannot fix a jump to a forward address
+** because we only know addresses once code is generated.)
+*/
+void luaK_patchlist (FuncState *fs, int list, int target) {
+ if (target == fs->pc) /* 'target' is current position? */
+ luaK_patchtohere(fs, list); /* add list to pending jumps */
+ else {
+ lua_assert(target < fs->pc);
+ patchlistaux(fs, list, target, NO_REG, target);
+ }
+}
+
+
+/*
+** Path all jumps in 'list' to close upvalues up to given 'level'
+** (The assertion checks that jumps either were closing nothing
+** or were closing higher levels, from inner blocks.)
+*/
+void luaK_patchclose (FuncState *fs, int list, int level) {
+ level++; /* argument is +1 to reserve 0 as non-op */
+ for (; list != NO_JUMP; list = getjump(fs, list)) {
+ lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
+ (GETARG_A(fs->f->code[list]) == 0 ||
+ GETARG_A(fs->f->code[list]) >= level));
+ SETARG_A(fs->f->code[list], level);
+ }
+}
+
+
+/*
+** Emit instruction 'i', checking for array sizes and saving also its
+** line information. Return 'i' position.
+*/
+static int luaK_code (FuncState *fs, Instruction i) {
+ Proto *f = fs->f;
+ dischargejpc(fs); /* 'pc' will change */
+ /* put new instruction in code array */
+ luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
+ MAX_INT, "opcodes");
+ f->code[fs->pc] = i;
+ /* save corresponding line information */
+ luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
+ MAX_INT, "opcodes");
+ f->lineinfo[fs->pc] = fs->ls->lastline;
+ return fs->pc++;
+}
+
+
+/*
+** Format and emit an 'iABC' instruction. (Assertions check consistency
+** of parameters versus opcode.)
+*/
+int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
+ lua_assert(getOpMode(o) == iABC);
+ lua_assert(getBMode(o) != OpArgN || b == 0);
+ lua_assert(getCMode(o) != OpArgN || c == 0);
+ lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);
+ return luaK_code(fs, CREATE_ABC(o, a, b, c));
+}
+
+
+/*
+** Format and emit an 'iABx' instruction.
+*/
+int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
+ lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
+ lua_assert(getCMode(o) == OpArgN);
+ lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
+ return luaK_code(fs, CREATE_ABx(o, a, bc));
+}
+
+
+/*
+** Emit an "extra argument" instruction (format 'iAx')
+*/
+static int codeextraarg (FuncState *fs, int a) {
+ lua_assert(a <= MAXARG_Ax);
+ return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
+}
+
+
+/*
+** Emit a "load constant" instruction, using either 'OP_LOADK'
+** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX'
+** instruction with "extra argument".
+*/
+int luaK_codek (FuncState *fs, int reg, int k) {
+ if (k <= MAXARG_Bx)
+ return luaK_codeABx(fs, OP_LOADK, reg, k);
+ else {
+ int p = luaK_codeABx(fs, OP_LOADKX, reg, 0);
+ codeextraarg(fs, k);
+ return p;
+ }
+}
+
+
+/*
+** Check register-stack level, keeping track of its maximum size
+** in field 'maxstacksize'
+*/
+void luaK_checkstack (FuncState *fs, int n) {
+ int newstack = fs->freereg + n;
+ if (newstack > fs->f->maxstacksize) {
+ if (newstack >= MAXREGS)
+ luaX_syntaxerror(fs->ls,
+ "function or expression needs too many registers");
+ fs->f->maxstacksize = cast_byte(newstack);
+ }
+}
+
+
+/*
+** Reserve 'n' registers in register stack
+*/
+void luaK_reserveregs (FuncState *fs, int n) {
+ luaK_checkstack(fs, n);
+ fs->freereg += n;
+}
+
+
+/*
+** Free register 'reg', if it is neither a constant index nor
+** a local variable.
+)
+*/
+static void freereg (FuncState *fs, int reg) {
+ if (!ISK(reg) && reg >= fs->nactvar) {
+ fs->freereg--;
+ lua_assert(reg == fs->freereg);
+ }
+}
+
+
+/*
+** Free register used by expression 'e' (if any)
+*/
+static void freeexp (FuncState *fs, expdesc *e) {
+ if (e->k == VNONRELOC)
+ freereg(fs, e->u.info);
+}
+
+
+/*
+** Free registers used by expressions 'e1' and 'e2' (if any) in proper
+** order.
+*/
+static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) {
+ int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1;
+ int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1;
+ if (r1 > r2) {
+ freereg(fs, r1);
+ freereg(fs, r2);
+ }
+ else {
+ freereg(fs, r2);
+ freereg(fs, r1);
+ }
+}
+
+
+/*
+** Add constant 'v' to prototype's list of constants (field 'k').
+** Use scanner's table to cache position of constants in constant list
+** and try to reuse constants. Because some values should not be used
+** as keys (nil cannot be a key, integer keys can collapse with float
+** keys), the caller must provide a useful 'key' for indexing the cache.
+*/
+static int addk (FuncState *fs, TValue *key, TValue *v) {
+ lua_State *L = fs->ls->L;
+ Proto *f = fs->f;
+ TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */
+ int k, oldsize;
+ if (ttisinteger(idx)) { /* is there an index there? */
+ k = cast_int(ivalue(idx));
+ /* correct value? (warning: must distinguish floats from integers!) */
+ if (k < fs->nk && ttype(&f->k[k]) == ttype(v) &&
+ luaV_rawequalobj(&f->k[k], v))
+ return k; /* reuse index */
+ }
+ /* constant not found; create a new entry */
+ oldsize = f->sizek;
+ k = fs->nk;
+ /* numerical value does not need GC barrier;
+ table has no metatable, so it does not need to invalidate cache */
+ setivalue(idx, k);
+ luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
+ while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
+ setobj(L, &f->k[k], v);
+ fs->nk++;
+ luaC_barrier(L, f, v);
+ return k;
+}
+
+
+/*
+** Add a string to list of constants and return its index.
+*/
+int luaK_stringK (FuncState *fs, TString *s) {
+ TValue o;
+ setsvalue(fs->ls->L, &o, s);
+ return addk(fs, &o, &o); /* use string itself as key */
+}
+
+
+/*
+** Add an integer to list of constants and return its index.
+** Integers use userdata as keys to avoid collision with floats with
+** same value; conversion to 'void*' is used only for hashing, so there
+** are no "precision" problems.
+*/
+int luaK_intK (FuncState *fs, lua_Integer n) {
+ TValue k, o;
+ setpvalue(&k, cast(void*, cast(size_t, n)));
+ setivalue(&o, n);
+ return addk(fs, &k, &o);
+}
+
+/*
+** Add a float to list of constants and return its index.
+*/
+static int luaK_numberK (FuncState *fs, lua_Number r) {
+ TValue o;
+ setfltvalue(&o, r);
+ return addk(fs, &o, &o); /* use number itself as key */
+}
+
+
+/*
+** Add a boolean to list of constants and return its index.
+*/
+static int boolK (FuncState *fs, int b) {
+ TValue o;
+ setbvalue(&o, b);
+ return addk(fs, &o, &o); /* use boolean itself as key */
+}
+
+
+/*
+** Add nil to list of constants and return its index.
+*/
+static int nilK (FuncState *fs) {
+ TValue k, v;
+ setnilvalue(&v);
+ /* cannot use nil as key; instead use table itself to represent nil */
+ sethvalue(fs->ls->L, &k, fs->ls->h);
+ return addk(fs, &k, &v);
+}
+
+
+/*
+** Fix an expression to return the number of results 'nresults'.
+** Either 'e' is a multi-ret expression (function call or vararg)
+** or 'nresults' is LUA_MULTRET (as any expression can satisfy that).
+*/
+void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
+ if (e->k == VCALL) { /* expression is an open function call? */
+ SETARG_C(getinstruction(fs, e), nresults + 1);
+ }
+ else if (e->k == VVARARG) {
+ Instruction *pc = &getinstruction(fs, e);
+ SETARG_B(*pc, nresults + 1);
+ SETARG_A(*pc, fs->freereg);
+ luaK_reserveregs(fs, 1);
+ }
+ else lua_assert(nresults == LUA_MULTRET);
+}
+
+
+/*
+** Fix an expression to return one result.
+** If expression is not a multi-ret expression (function call or
+** vararg), it already returns one result, so nothing needs to be done.
+** Function calls become VNONRELOC expressions (as its result comes
+** fixed in the base register of the call), while vararg expressions
+** become VRELOCABLE (as OP_VARARG puts its results where it wants).
+** (Calls are created returning one result, so that does not need
+** to be fixed.)
+*/
+void luaK_setoneret (FuncState *fs, expdesc *e) {
+ if (e->k == VCALL) { /* expression is an open function call? */
+ /* already returns 1 value */
+ lua_assert(GETARG_C(getinstruction(fs, e)) == 2);
+ e->k = VNONRELOC; /* result has fixed position */
+ e->u.info = GETARG_A(getinstruction(fs, e));
+ }
+ else if (e->k == VVARARG) {
+ SETARG_B(getinstruction(fs, e), 2);
+ e->k = VRELOCABLE; /* can relocate its simple result */
+ }
+}
+
+
+/*
+** Ensure that expression 'e' is not a variable.
+*/
+void luaK_dischargevars (FuncState *fs, expdesc *e) {
+ switch (e->k) {
+ case VLOCAL: { /* already in a register */
+ e->k = VNONRELOC; /* becomes a non-relocatable value */
+ break;
+ }
+ case VUPVAL: { /* move value to some (pending) register */
+ e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
+ e->k = VRELOCABLE;
+ break;
+ }
+ case VINDEXED: {
+ OpCode op;
+ freereg(fs, e->u.ind.idx);
+ if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */
+ freereg(fs, e->u.ind.t);
+ op = OP_GETTABLE;
+ }
+ else {
+ lua_assert(e->u.ind.vt == VUPVAL);
+ op = OP_GETTABUP; /* 't' is in an upvalue */
+ }
+ e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
+ e->k = VRELOCABLE;
+ break;
+ }
+ case VVARARG: case VCALL: {
+ luaK_setoneret(fs, e);
+ break;
+ }
+ default: break; /* there is one value available (somewhere) */
+ }
+}
+
+
+/*
+** Ensures expression value is in register 'reg' (and therefore
+** 'e' will become a non-relocatable expression).
+*/
+static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
+ luaK_dischargevars(fs, e);
+ switch (e->k) {
+ case VNIL: {
+ luaK_nil(fs, reg, 1);
+ break;
+ }
+ case VFALSE: case VTRUE: {
+ luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
+ break;
+ }
+ case VK: {
+ luaK_codek(fs, reg, e->u.info);
+ break;
+ }
+ case VKFLT: {
+ luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval));
+ break;
+ }
+ case VKINT: {
+ luaK_codek(fs, reg, luaK_intK(fs, e->u.ival));
+ break;
+ }
+ case VRELOCABLE: {
+ Instruction *pc = &getinstruction(fs, e);
+ SETARG_A(*pc, reg); /* instruction will put result in 'reg' */
+ break;
+ }
+ case VNONRELOC: {
+ if (reg != e->u.info)
+ luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
+ break;
+ }
+ default: {
+ lua_assert(e->k == VJMP);
+ return; /* nothing to do... */
+ }
+ }
+ e->u.info = reg;
+ e->k = VNONRELOC;
+}
+
+
+/*
+** Ensures expression value is in any register.
+*/
+static void discharge2anyreg (FuncState *fs, expdesc *e) {
+ if (e->k != VNONRELOC) { /* no fixed register yet? */
+ luaK_reserveregs(fs, 1); /* get a register */
+ discharge2reg(fs, e, fs->freereg-1); /* put value there */
+ }
+}
+
+
+static int code_loadbool (FuncState *fs, int A, int b, int jump) {
+ luaK_getlabel(fs); /* those instructions may be jump targets */
+ return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
+}
+
+
+/*
+** check whether list has any jump that do not produce a value
+** or produce an inverted value
+*/
+static int need_value (FuncState *fs, int list) {
+ for (; list != NO_JUMP; list = getjump(fs, list)) {
+ Instruction i = *getjumpcontrol(fs, list);
+ if (GET_OPCODE(i) != OP_TESTSET) return 1;
+ }
+ return 0; /* not found */
+}
+
+
+/*
+** Ensures final expression result (including results from its jump
+** lists) is in register 'reg'.
+** If expression has jumps, need to patch these jumps either to
+** its final position or to "load" instructions (for those tests
+** that do not produce values).
+*/
+static void exp2reg (FuncState *fs, expdesc *e, int reg) {
+ discharge2reg(fs, e, reg);
+ if (e->k == VJMP) /* expression itself is a test? */
+ luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */
+ if (hasjumps(e)) {
+ int final; /* position after whole expression */
+ int p_f = NO_JUMP; /* position of an eventual LOAD false */
+ int p_t = NO_JUMP; /* position of an eventual LOAD true */
+ if (need_value(fs, e->t) || need_value(fs, e->f)) {
+ int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
+ p_f = code_loadbool(fs, reg, 0, 1);
+ p_t = code_loadbool(fs, reg, 1, 0);
+ luaK_patchtohere(fs, fj);
+ }
+ final = luaK_getlabel(fs);
+ patchlistaux(fs, e->f, final, reg, p_f);
+ patchlistaux(fs, e->t, final, reg, p_t);
+ }
+ e->f = e->t = NO_JUMP;
+ e->u.info = reg;
+ e->k = VNONRELOC;
+}
+
+
+/*
+** Ensures final expression result (including results from its jump
+** lists) is in next available register.
+*/
+void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
+ luaK_dischargevars(fs, e);
+ freeexp(fs, e);
+ luaK_reserveregs(fs, 1);
+ exp2reg(fs, e, fs->freereg - 1);
+}
+
+
+/*
+** Ensures final expression result (including results from its jump
+** lists) is in some (any) register and return that register.
+*/
+int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
+ luaK_dischargevars(fs, e);
+ if (e->k == VNONRELOC) { /* expression already has a register? */
+ if (!hasjumps(e)) /* no jumps? */
+ return e->u.info; /* result is already in a register */
+ if (e->u.info >= fs->nactvar) { /* reg. is not a local? */
+ exp2reg(fs, e, e->u.info); /* put final result in it */
+ return e->u.info;
+ }
+ }
+ luaK_exp2nextreg(fs, e); /* otherwise, use next available register */
+ return e->u.info;
+}
+
+
+/*
+** Ensures final expression result is either in a register or in an
+** upvalue.
+*/
+void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
+ if (e->k != VUPVAL || hasjumps(e))
+ luaK_exp2anyreg(fs, e);
+}
+
+
+/*
+** Ensures final expression result is either in a register or it is
+** a constant.
+*/
+void luaK_exp2val (FuncState *fs, expdesc *e) {
+ if (hasjumps(e))
+ luaK_exp2anyreg(fs, e);
+ else
+ luaK_dischargevars(fs, e);
+}
+
+
+/*
+** Ensures final expression result is in a valid R/K index
+** (that is, it is either in a register or in 'k' with an index
+** in the range of R/K indices).
+** Returns R/K index.
+*/
+int luaK_exp2RK (FuncState *fs, expdesc *e) {
+ luaK_exp2val(fs, e);
+ switch (e->k) { /* move constants to 'k' */
+ case VTRUE: e->u.info = boolK(fs, 1); goto vk;
+ case VFALSE: e->u.info = boolK(fs, 0); goto vk;
+ case VNIL: e->u.info = nilK(fs); goto vk;
+ case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk;
+ case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk;
+ case VK:
+ vk:
+ e->k = VK;
+ if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */
+ return RKASK(e->u.info);
+ else break;
+ default: break;
+ }
+ /* not a constant in the right range: put it in a register */
+ return luaK_exp2anyreg(fs, e);
+}
+
+
+/*
+** Generate code to store result of expression 'ex' into variable 'var'.
+*/
+void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
+ switch (var->k) {
+ case VLOCAL: {
+ freeexp(fs, ex);
+ exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */
+ return;
+ }
+ case VUPVAL: {
+ int e = luaK_exp2anyreg(fs, ex);
+ luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
+ break;
+ }
+ case VINDEXED: {
+ OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
+ int e = luaK_exp2RK(fs, ex);
+ luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
+ break;
+ }
+ default: lua_assert(0); /* invalid var kind to store */
+ }
+ freeexp(fs, ex);
+}
+
+
+/*
+** Emit SELF instruction (convert expression 'e' into 'e:key(e,').
+*/
+void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
+ int ereg;
+ luaK_exp2anyreg(fs, e);
+ ereg = e->u.info; /* register where 'e' was placed */
+ freeexp(fs, e);
+ e->u.info = fs->freereg; /* base register for op_self */
+ e->k = VNONRELOC; /* self expression has a fixed register */
+ luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */
+ luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key));
+ freeexp(fs, key);
+}
+
+
+/*
+** Negate condition 'e' (where 'e' is a comparison).
+*/
+static void negatecondition (FuncState *fs, expdesc *e) {
+ Instruction *pc = getjumpcontrol(fs, e->u.info);
+ lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
+ GET_OPCODE(*pc) != OP_TEST);
+ SETARG_A(*pc, !(GETARG_A(*pc)));
+}
+
+
+/*
+** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond'
+** is true, code will jump if 'e' is true.) Return jump position.
+** Optimize when 'e' is 'not' something, inverting the condition
+** and removing the 'not'.
+*/
+static int jumponcond (FuncState *fs, expdesc *e, int cond) {
+ if (e->k == VRELOCABLE) {
+ Instruction ie = getinstruction(fs, e);
+ if (GET_OPCODE(ie) == OP_NOT) {
+ fs->pc--; /* remove previous OP_NOT */
+ return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
+ }
+ /* else go through */
+ }
+ discharge2anyreg(fs, e);
+ freeexp(fs, e);
+ return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
+}
+
+
+/*
+** Emit code to go through if 'e' is true, jump otherwise.
+*/
+void luaK_goiftrue (FuncState *fs, expdesc *e) {
+ int pc; /* pc of new jump */
+ luaK_dischargevars(fs, e);
+ switch (e->k) {
+ case VJMP: { /* condition? */
+ negatecondition(fs, e); /* jump when it is false */
+ pc = e->u.info; /* save jump position */
+ break;
+ }
+ case VK: case VKFLT: case VKINT: case VTRUE: {
+ pc = NO_JUMP; /* always true; do nothing */
+ break;
+ }
+ default: {
+ pc = jumponcond(fs, e, 0); /* jump when false */
+ break;
+ }
+ }
+ luaK_concat(fs, &e->f, pc); /* insert new jump in false list */
+ luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */
+ e->t = NO_JUMP;
+}
+
+
+/*
+** Emit code to go through if 'e' is false, jump otherwise.
+*/
+void luaK_goiffalse (FuncState *fs, expdesc *e) {
+ int pc; /* pc of new jump */
+ luaK_dischargevars(fs, e);
+ switch (e->k) {
+ case VJMP: {
+ pc = e->u.info; /* already jump if true */
+ break;
+ }
+ case VNIL: case VFALSE: {
+ pc = NO_JUMP; /* always false; do nothing */
+ break;
+ }
+ default: {
+ pc = jumponcond(fs, e, 1); /* jump if true */
+ break;
+ }
+ }
+ luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */
+ luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */
+ e->f = NO_JUMP;
+}
+
+
+/*
+** Code 'not e', doing constant folding.
+*/
+static void codenot (FuncState *fs, expdesc *e) {
+ luaK_dischargevars(fs, e);
+ switch (e->k) {
+ case VNIL: case VFALSE: {
+ e->k = VTRUE; /* true == not nil == not false */
+ break;
+ }
+ case VK: case VKFLT: case VKINT: case VTRUE: {
+ e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */
+ break;
+ }
+ case VJMP: {
+ negatecondition(fs, e);
+ break;
+ }
+ case VRELOCABLE:
+ case VNONRELOC: {
+ discharge2anyreg(fs, e);
+ freeexp(fs, e);
+ e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0);
+ e->k = VRELOCABLE;
+ break;
+ }
+ default: lua_assert(0); /* cannot happen */
+ }
+ /* interchange true and false lists */
+ { int temp = e->f; e->f = e->t; e->t = temp; }
+ removevalues(fs, e->f); /* values are useless when negated */
+ removevalues(fs, e->t);
+}
+
+
+/*
+** Create expression 't[k]'. 't' must have its final result already in a
+** register or upvalue.
+*/
+void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
+ lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL));
+ t->u.ind.t = t->u.info; /* register or upvalue index */
+ t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */
+ t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL;
+ t->k = VINDEXED;
+}
+
+
+/*
+** Return false if folding can raise an error.
+** Bitwise operations need operands convertible to integers; division
+** operations cannot have 0 as divisor.
+*/
+static int validop (int op, TValue *v1, TValue *v2) {
+ switch (op) {
+ case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:
+ case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */
+ lua_Integer i;
+ return (tointeger(v1, &i) && tointeger(v2, &i));
+ }
+ case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */
+ return (nvalue(v2) != 0);
+ default: return 1; /* everything else is valid */
+ }
+}
+
+
+/*
+** Try to "constant-fold" an operation; return 1 iff successful.
+** (In this case, 'e1' has the final result.)
+*/
+static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
+ TValue v1, v2, res;
+ if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
+ return 0; /* non-numeric operands or not safe to fold */
+ luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */
+ if (ttisinteger(&res)) {
+ e1->k = VKINT;
+ e1->u.ival = ivalue(&res);
+ }
+ else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */
+ lua_Number n = fltvalue(&res);
+ if (luai_numisnan(n) || n == 0)
+ return 0;
+ e1->k = VKFLT;
+ e1->u.nval = n;
+ }
+ return 1;
+}
+
+
+/*
+** Emit code for unary expressions that "produce values"
+** (everything but 'not').
+** Expression to produce final result will be encoded in 'e'.
+*/
+static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) {
+ int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */
+ freeexp(fs, e);
+ e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */
+ e->k = VRELOCABLE; /* all those operations are relocatable */
+ luaK_fixline(fs, line);
+}
+
+
+/*
+** Emit code for binary expressions that "produce values"
+** (everything but logical operators 'and'/'or' and comparison
+** operators).
+** Expression to produce final result will be encoded in 'e1'.
+*/
+static void codebinexpval (FuncState *fs, OpCode op,
+ expdesc *e1, expdesc *e2, int line) {
+ int rk1 = luaK_exp2RK(fs, e1); /* both operands are "RK" */
+ int rk2 = luaK_exp2RK(fs, e2);
+ freeexps(fs, e1, e2);
+ e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */
+ e1->k = VRELOCABLE; /* all those operations are relocatable */
+ luaK_fixline(fs, line);
+}
+
+
+/*
+** Emit code for comparisons.
+** 'e1' was already put in R/K form by 'luaK_infix'.
+*/
+static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
+ int rk1 = (e1->k == VK) ? RKASK(e1->u.info)
+ : check_exp(e1->k == VNONRELOC, e1->u.info);
+ int rk2 = luaK_exp2RK(fs, e2);
+ freeexps(fs, e1, e2);
+ switch (opr) {
+ case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */
+ e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2);
+ break;
+ }
+ case OPR_GT: case OPR_GE: {
+ /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */
+ OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
+ e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */
+ break;
+ }
+ default: { /* '==', '<', '<=' use their own opcodes */
+ OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
+ e1->u.info = condjump(fs, op, 1, rk1, rk2);
+ break;
+ }
+ }
+ e1->k = VJMP;
+}
+
+
+/*
+** Aplly prefix operation 'op' to expression 'e'.
+*/
+void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
+ static expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; /* fake 2nd operand */
+ switch (op) {
+ case OPR_MINUS: case OPR_BNOT:
+ if (constfolding(fs, op + LUA_OPUNM, e, &ef))
+ break;
+ /* FALLTHROUGH */
+ case OPR_LEN:
+ codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
+ break;
+ case OPR_NOT: codenot(fs, e); break;
+ default: lua_assert(0);
+ }
+}
+
+
+/*
+** Process 1st operand 'v' of binary operation 'op' before reading
+** 2nd operand.
+*/
+void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
+ switch (op) {
+ case OPR_AND: {
+ luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */
+ break;
+ }
+ case OPR_OR: {
+ luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */
+ break;
+ }
+ case OPR_CONCAT: {
+ luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */
+ break;
+ }
+ case OPR_ADD: case OPR_SUB:
+ case OPR_MUL: case OPR_DIV: case OPR_IDIV:
+ case OPR_MOD: case OPR_POW:
+ case OPR_BAND: case OPR_BOR: case OPR_BXOR:
+ case OPR_SHL: case OPR_SHR: {
+ if (!tonumeral(v, NULL))
+ luaK_exp2RK(fs, v);
+ /* else keep numeral, which may be folded with 2nd operand */
+ break;
+ }
+ default: {
+ luaK_exp2RK(fs, v);
+ break;
+ }
+ }
+}
+
+
+/*
+** Finalize code for binary operation, after reading 2nd operand.
+** For '(a .. b .. c)' (which is '(a .. (b .. c))', because
+** concatenation is right associative), merge second CONCAT into first
+** one.
+*/
+void luaK_posfix (FuncState *fs, BinOpr op,
+ expdesc *e1, expdesc *e2, int line) {
+ switch (op) {
+ case OPR_AND: {
+ lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */
+ luaK_dischargevars(fs, e2);
+ luaK_concat(fs, &e2->f, e1->f);
+ *e1 = *e2;
+ break;
+ }
+ case OPR_OR: {
+ lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */
+ luaK_dischargevars(fs, e2);
+ luaK_concat(fs, &e2->t, e1->t);
+ *e1 = *e2;
+ break;
+ }
+ case OPR_CONCAT: {
+ luaK_exp2val(fs, e2);
+ if (e2->k == VRELOCABLE &&
+ GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) {
+ lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1);
+ freeexp(fs, e1);
+ SETARG_B(getinstruction(fs, e2), e1->u.info);
+ e1->k = VRELOCABLE; e1->u.info = e2->u.info;
+ }
+ else {
+ luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
+ codebinexpval(fs, OP_CONCAT, e1, e2, line);
+ }
+ break;
+ }
+ case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
+ case OPR_IDIV: case OPR_MOD: case OPR_POW:
+ case OPR_BAND: case OPR_BOR: case OPR_BXOR:
+ case OPR_SHL: case OPR_SHR: {
+ if (!constfolding(fs, op + LUA_OPADD, e1, e2))
+ codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line);
+ break;
+ }
+ case OPR_EQ: case OPR_LT: case OPR_LE:
+ case OPR_NE: case OPR_GT: case OPR_GE: {
+ codecomp(fs, op, e1, e2);
+ break;
+ }
+ default: lua_assert(0);
+ }
+}
+
+
+/*
+** Change line information associated with current position.
+*/
+void luaK_fixline (FuncState *fs, int line) {
+ fs->f->lineinfo[fs->pc - 1] = line;
+}
+
+
+/*
+** Emit a SETLIST instruction.
+** 'base' is register that keeps table;
+** 'nelems' is #table plus those to be stored now;
+** 'tostore' is number of values (in registers 'base + 1',...) to add to
+** table (or LUA_MULTRET to add up to stack top).
+*/
+void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
+ int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
+ int b = (tostore == LUA_MULTRET) ? 0 : tostore;
+ lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH);
+ if (c <= MAXARG_C)
+ luaK_codeABC(fs, OP_SETLIST, base, b, c);
+ else if (c <= MAXARG_Ax) {
+ luaK_codeABC(fs, OP_SETLIST, base, b, 0);
+ codeextraarg(fs, c);
+ }
+ else
+ luaX_syntaxerror(fs->ls, "constructor too long");
+ fs->freereg = base + 1; /* free registers with list values */
+}
+
diff --git a/external/lua-5.3.3/src/lcode.h b/external/lua-5.3.3/src/lcode.h
new file mode 100644
index 0000000..cd306d5
--- /dev/null
+++ b/external/lua-5.3.3/src/lcode.h
@@ -0,0 +1,88 @@
+/*
+** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $
+** Code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lcode_h
+#define lcode_h
+
+#include "llex.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+
+
+/*
+** Marks the end of a patch list. It is an invalid value both as an absolute
+** address, and as a list link (would link an element to itself).
+*/
+#define NO_JUMP (-1)
+
+
+/*
+** grep "ORDER OPR" if you change these enums (ORDER OP)
+*/
+typedef enum BinOpr {
+ OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW,
+ OPR_DIV,
+ OPR_IDIV,
+ OPR_BAND, OPR_BOR, OPR_BXOR,
+ OPR_SHL, OPR_SHR,
+ OPR_CONCAT,
+ OPR_EQ, OPR_LT, OPR_LE,
+ OPR_NE, OPR_GT, OPR_GE,
+ OPR_AND, OPR_OR,
+ OPR_NOBINOPR
+} BinOpr;
+
+
+typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
+
+
+/* get (pointer to) instruction of given 'expdesc' */
+#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
+
+#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
+
+#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET)
+
+#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
+
+LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
+LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
+LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k);
+LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
+LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
+LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
+LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
+LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
+LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n);
+LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
+LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
+LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
+LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
+LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
+LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
+LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
+LUAI_FUNC int luaK_jump (FuncState *fs);
+LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
+LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
+LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
+LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level);
+LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
+LUAI_FUNC int luaK_getlabel (FuncState *fs);
+LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
+LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
+LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
+ expdesc *v2, int line);
+LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
+
+
+#endif
diff --git a/external/lua-5.3.3/src/lcorolib.c b/external/lua-5.3.3/src/lcorolib.c
new file mode 100644
index 0000000..2303429
--- /dev/null
+++ b/external/lua-5.3.3/src/lcorolib.c
@@ -0,0 +1,168 @@
+/*
+** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $
+** Coroutine Library
+** See Copyright Notice in lua.h
+*/
+
+#define lcorolib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include <stdlib.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+static lua_State *getco (lua_State *L) {
+ lua_State *co = lua_tothread(L, 1);
+ luaL_argcheck(L, co, 1, "thread expected");
+ return co;
+}
+
+
+static int auxresume (lua_State *L, lua_State *co, int narg) {
+ int status;
+ if (!lua_checkstack(co, narg)) {
+ lua_pushliteral(L, "too many arguments to resume");
+ return -1; /* error flag */
+ }
+ if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {
+ lua_pushliteral(L, "cannot resume dead coroutine");
+ return -1; /* error flag */
+ }
+ lua_xmove(L, co, narg);
+ status = lua_resume(co, L, narg);
+ if (status == LUA_OK || status == LUA_YIELD) {
+ int nres = lua_gettop(co);
+ if (!lua_checkstack(L, nres + 1)) {
+ lua_pop(co, nres); /* remove results anyway */
+ lua_pushliteral(L, "too many results to resume");
+ return -1; /* error flag */
+ }
+ lua_xmove(co, L, nres); /* move yielded values */
+ return nres;
+ }
+ else {
+ lua_xmove(co, L, 1); /* move error message */
+ return -1; /* error flag */
+ }
+}
+
+
+static int luaB_coresume (lua_State *L) {
+ lua_State *co = getco(L);
+ int r;
+ r = auxresume(L, co, lua_gettop(L) - 1);
+ if (r < 0) {
+ lua_pushboolean(L, 0);
+ lua_insert(L, -2);
+ return 2; /* return false + error message */
+ }
+ else {
+ lua_pushboolean(L, 1);
+ lua_insert(L, -(r + 1));
+ return r + 1; /* return true + 'resume' returns */
+ }
+}
+
+
+static int luaB_auxwrap (lua_State *L) {
+ lua_State *co = lua_tothread(L, lua_upvalueindex(1));
+ int r = auxresume(L, co, lua_gettop(L));
+ if (r < 0) {
+ if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
+ luaL_where(L, 1); /* add extra info */
+ lua_insert(L, -2);
+ lua_concat(L, 2);
+ }
+ return lua_error(L); /* propagate error */
+ }
+ return r;
+}
+
+
+static int luaB_cocreate (lua_State *L) {
+ lua_State *NL;
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ NL = lua_newthread(L);
+ lua_pushvalue(L, 1); /* move function to top */
+ lua_xmove(L, NL, 1); /* move function from L to NL */
+ return 1;
+}
+
+
+static int luaB_cowrap (lua_State *L) {
+ luaB_cocreate(L);
+ lua_pushcclosure(L, luaB_auxwrap, 1);
+ return 1;
+}
+
+
+static int luaB_yield (lua_State *L) {
+ return lua_yield(L, lua_gettop(L));
+}
+
+
+static int luaB_costatus (lua_State *L) {
+ lua_State *co = getco(L);
+ if (L == co) lua_pushliteral(L, "running");
+ else {
+ switch (lua_status(co)) {
+ case LUA_YIELD:
+ lua_pushliteral(L, "suspended");
+ break;
+ case LUA_OK: {
+ lua_Debug ar;
+ if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
+ lua_pushliteral(L, "normal"); /* it is running */
+ else if (lua_gettop(co) == 0)
+ lua_pushliteral(L, "dead");
+ else
+ lua_pushliteral(L, "suspended"); /* initial state */
+ break;
+ }
+ default: /* some error occurred */
+ lua_pushliteral(L, "dead");
+ break;
+ }
+ }
+ return 1;
+}
+
+
+static int luaB_yieldable (lua_State *L) {
+ lua_pushboolean(L, lua_isyieldable(L));
+ return 1;
+}
+
+
+static int luaB_corunning (lua_State *L) {
+ int ismain = lua_pushthread(L);
+ lua_pushboolean(L, ismain);
+ return 2;
+}
+
+
+static const luaL_Reg co_funcs[] = {
+ {"create", luaB_cocreate},
+ {"resume", luaB_coresume},
+ {"running", luaB_corunning},
+ {"status", luaB_costatus},
+ {"wrap", luaB_cowrap},
+ {"yield", luaB_yield},
+ {"isyieldable", luaB_yieldable},
+ {NULL, NULL}
+};
+
+
+
+LUAMOD_API int luaopen_coroutine (lua_State *L) {
+ luaL_newlib(L, co_funcs);
+ return 1;
+}
+
diff --git a/external/lua-5.3.3/src/lctype.c b/external/lua-5.3.3/src/lctype.c
new file mode 100644
index 0000000..ae9367e
--- /dev/null
+++ b/external/lua-5.3.3/src/lctype.c
@@ -0,0 +1,55 @@
+/*
+** $Id: lctype.c,v 1.12 2014/11/02 19:19:04 roberto Exp $
+** 'ctype' functions for Lua
+** See Copyright Notice in lua.h
+*/
+
+#define lctype_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include "lctype.h"
+
+#if !LUA_USE_CTYPE /* { */
+
+#include <limits.h>
+
+LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
+ 0x00, /* EOZ */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */
+ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */
+ 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */
+ 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05,
+ 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */
+ 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+#endif /* } */
diff --git a/external/lua-5.3.3/src/lctype.h b/external/lua-5.3.3/src/lctype.h
new file mode 100644
index 0000000..99c7d12
--- /dev/null
+++ b/external/lua-5.3.3/src/lctype.h
@@ -0,0 +1,95 @@
+/*
+** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $
+** 'ctype' functions for Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lctype_h
+#define lctype_h
+
+#include "lua.h"
+
+
+/*
+** WARNING: the functions defined here do not necessarily correspond
+** to the similar functions in the standard C ctype.h. They are
+** optimized for the specific needs of Lua
+*/
+
+#if !defined(LUA_USE_CTYPE)
+
+#if 'A' == 65 && '0' == 48
+/* ASCII case: can use its own tables; faster and fixed */
+#define LUA_USE_CTYPE 0
+#else
+/* must use standard C ctype */
+#define LUA_USE_CTYPE 1
+#endif
+
+#endif
+
+
+#if !LUA_USE_CTYPE /* { */
+
+#include <limits.h>
+
+#include "llimits.h"
+
+
+#define ALPHABIT 0
+#define DIGITBIT 1
+#define PRINTBIT 2
+#define SPACEBIT 3
+#define XDIGITBIT 4
+
+
+#define MASK(B) (1 << (B))
+
+
+/*
+** add 1 to char to allow index -1 (EOZ)
+*/
+#define testprop(c,p) (luai_ctype_[(c)+1] & (p))
+
+/*
+** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_'
+*/
+#define lislalpha(c) testprop(c, MASK(ALPHABIT))
+#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT)))
+#define lisdigit(c) testprop(c, MASK(DIGITBIT))
+#define lisspace(c) testprop(c, MASK(SPACEBIT))
+#define lisprint(c) testprop(c, MASK(PRINTBIT))
+#define lisxdigit(c) testprop(c, MASK(XDIGITBIT))
+
+/*
+** this 'ltolower' only works for alphabetic characters
+*/
+#define ltolower(c) ((c) | ('A' ^ 'a'))
+
+
+/* two more entries for 0 and -1 (EOZ) */
+LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2];
+
+
+#else /* }{ */
+
+/*
+** use standard C ctypes
+*/
+
+#include <ctype.h>
+
+
+#define lislalpha(c) (isalpha(c) || (c) == '_')
+#define lislalnum(c) (isalnum(c) || (c) == '_')
+#define lisdigit(c) (isdigit(c))
+#define lisspace(c) (isspace(c))
+#define lisprint(c) (isprint(c))
+#define lisxdigit(c) (isxdigit(c))
+
+#define ltolower(c) (tolower(c))
+
+#endif /* } */
+
+#endif
+
diff --git a/external/lua-5.3.3/src/ldblib.c b/external/lua-5.3.3/src/ldblib.c
new file mode 100644
index 0000000..786f6cd
--- /dev/null
+++ b/external/lua-5.3.3/src/ldblib.c
@@ -0,0 +1,456 @@
+/*
+** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp $
+** Interface from Lua to its debug API
+** See Copyright Notice in lua.h
+*/
+
+#define ldblib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/*
+** The hook table at registry[&HOOKKEY] maps threads to their current
+** hook function. (We only need the unique address of 'HOOKKEY'.)
+*/
+static const int HOOKKEY = 0;
+
+
+/*
+** If L1 != L, L1 can be in any state, and therefore there are no
+** guarantees about its stack space; any push in L1 must be
+** checked.
+*/
+static void checkstack (lua_State *L, lua_State *L1, int n) {
+ if (L != L1 && !lua_checkstack(L1, n))
+ luaL_error(L, "stack overflow");
+}
+
+
+static int db_getregistry (lua_State *L) {
+ lua_pushvalue(L, LUA_REGISTRYINDEX);
+ return 1;
+}
+
+
+static int db_getmetatable (lua_State *L) {
+ luaL_checkany(L, 1);
+ if (!lua_getmetatable(L, 1)) {
+ lua_pushnil(L); /* no metatable */
+ }
+ return 1;
+}
+
+
+static int db_setmetatable (lua_State *L) {
+ int t = lua_type(L, 2);
+ luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
+ "nil or table expected");
+ lua_settop(L, 2);
+ lua_setmetatable(L, 1);
+ return 1; /* return 1st argument */
+}
+
+
+static int db_getuservalue (lua_State *L) {
+ if (lua_type(L, 1) != LUA_TUSERDATA)
+ lua_pushnil(L);
+ else
+ lua_getuservalue(L, 1);
+ return 1;
+}
+
+
+static int db_setuservalue (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ luaL_checkany(L, 2);
+ lua_settop(L, 2);
+ lua_setuservalue(L, 1);
+ return 1;
+}
+
+
+/*
+** Auxiliary function used by several library functions: check for
+** an optional thread as function's first argument and set 'arg' with
+** 1 if this argument is present (so that functions can skip it to
+** access their other arguments)
+*/
+static lua_State *getthread (lua_State *L, int *arg) {
+ if (lua_isthread(L, 1)) {
+ *arg = 1;
+ return lua_tothread(L, 1);
+ }
+ else {
+ *arg = 0;
+ return L; /* function will operate over current thread */
+ }
+}
+
+
+/*
+** Variations of 'lua_settable', used by 'db_getinfo' to put results
+** from 'lua_getinfo' into result table. Key is always a string;
+** value can be a string, an int, or a boolean.
+*/
+static void settabss (lua_State *L, const char *k, const char *v) {
+ lua_pushstring(L, v);
+ lua_setfield(L, -2, k);
+}
+
+static void settabsi (lua_State *L, const char *k, int v) {
+ lua_pushinteger(L, v);
+ lua_setfield(L, -2, k);
+}
+
+static void settabsb (lua_State *L, const char *k, int v) {
+ lua_pushboolean(L, v);
+ lua_setfield(L, -2, k);
+}
+
+
+/*
+** In function 'db_getinfo', the call to 'lua_getinfo' may push
+** results on the stack; later it creates the result table to put
+** these objects. Function 'treatstackoption' puts the result from
+** 'lua_getinfo' on top of the result table so that it can call
+** 'lua_setfield'.
+*/
+static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
+ if (L == L1)
+ lua_rotate(L, -2, 1); /* exchange object and table */
+ else
+ lua_xmove(L1, L, 1); /* move object to the "main" stack */
+ lua_setfield(L, -2, fname); /* put object into table */
+}
+
+
+/*
+** Calls 'lua_getinfo' and collects all results in a new table.
+** L1 needs stack space for an optional input (function) plus
+** two optional outputs (function and line table) from function
+** 'lua_getinfo'.
+*/
+static int db_getinfo (lua_State *L) {
+ lua_Debug ar;
+ int arg;
+ lua_State *L1 = getthread(L, &arg);
+ const char *options = luaL_optstring(L, arg+2, "flnStu");
+ checkstack(L, L1, 3);
+ if (lua_isfunction(L, arg + 1)) { /* info about a function? */
+ options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
+ lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
+ lua_xmove(L, L1, 1);
+ }
+ else { /* stack level */
+ if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) {
+ lua_pushnil(L); /* level out of range */
+ return 1;
+ }
+ }
+ if (!lua_getinfo(L1, options, &ar))
+ return luaL_argerror(L, arg+2, "invalid option");
+ lua_newtable(L); /* table to collect results */
+ if (strchr(options, 'S')) {
+ settabss(L, "source", ar.source);
+ settabss(L, "short_src", ar.short_src);
+ settabsi(L, "linedefined", ar.linedefined);
+ settabsi(L, "lastlinedefined", ar.lastlinedefined);
+ settabss(L, "what", ar.what);
+ }
+ if (strchr(options, 'l'))
+ settabsi(L, "currentline", ar.currentline);
+ if (strchr(options, 'u')) {
+ settabsi(L, "nups", ar.nups);
+ settabsi(L, "nparams", ar.nparams);
+ settabsb(L, "isvararg", ar.isvararg);
+ }
+ if (strchr(options, 'n')) {
+ settabss(L, "name", ar.name);
+ settabss(L, "namewhat", ar.namewhat);
+ }
+ if (strchr(options, 't'))
+ settabsb(L, "istailcall", ar.istailcall);
+ if (strchr(options, 'L'))
+ treatstackoption(L, L1, "activelines");
+ if (strchr(options, 'f'))
+ treatstackoption(L, L1, "func");
+ return 1; /* return table */
+}
+
+
+static int db_getlocal (lua_State *L) {
+ int arg;
+ lua_State *L1 = getthread(L, &arg);
+ lua_Debug ar;
+ const char *name;
+ int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */
+ if (lua_isfunction(L, arg + 1)) { /* function argument? */
+ lua_pushvalue(L, arg + 1); /* push function */
+ lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */
+ return 1; /* return only name (there is no value) */
+ }
+ else { /* stack-level argument */
+ int level = (int)luaL_checkinteger(L, arg + 1);
+ if (!lua_getstack(L1, level, &ar)) /* out of range? */
+ return luaL_argerror(L, arg+1, "level out of range");
+ checkstack(L, L1, 1);
+ name = lua_getlocal(L1, &ar, nvar);
+ if (name) {
+ lua_xmove(L1, L, 1); /* move local value */
+ lua_pushstring(L, name); /* push name */
+ lua_rotate(L, -2, 1); /* re-order */
+ return 2;
+ }
+ else {
+ lua_pushnil(L); /* no name (nor value) */
+ return 1;
+ }
+ }
+}
+
+
+static int db_setlocal (lua_State *L) {
+ int arg;
+ const char *name;
+ lua_State *L1 = getthread(L, &arg);
+ lua_Debug ar;
+ int level = (int)luaL_checkinteger(L, arg + 1);
+ int nvar = (int)luaL_checkinteger(L, arg + 2);
+ if (!lua_getstack(L1, level, &ar)) /* out of range? */
+ return luaL_argerror(L, arg+1, "level out of range");
+ luaL_checkany(L, arg+3);
+ lua_settop(L, arg+3);
+ checkstack(L, L1, 1);
+ lua_xmove(L, L1, 1);
+ name = lua_setlocal(L1, &ar, nvar);
+ if (name == NULL)
+ lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */
+ lua_pushstring(L, name);
+ return 1;
+}
+
+
+/*
+** get (if 'get' is true) or set an upvalue from a closure
+*/
+static int auxupvalue (lua_State *L, int get) {
+ const char *name;
+ int n = (int)luaL_checkinteger(L, 2); /* upvalue index */
+ luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */
+ name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
+ if (name == NULL) return 0;
+ lua_pushstring(L, name);
+ lua_insert(L, -(get+1)); /* no-op if get is false */
+ return get + 1;
+}
+
+
+static int db_getupvalue (lua_State *L) {
+ return auxupvalue(L, 1);
+}
+
+
+static int db_setupvalue (lua_State *L) {
+ luaL_checkany(L, 3);
+ return auxupvalue(L, 0);
+}
+
+
+/*
+** Check whether a given upvalue from a given closure exists and
+** returns its index
+*/
+static int checkupval (lua_State *L, int argf, int argnup) {
+ int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */
+ luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */
+ luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup,
+ "invalid upvalue index");
+ return nup;
+}
+
+
+static int db_upvalueid (lua_State *L) {
+ int n = checkupval(L, 1, 2);
+ lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
+ return 1;
+}
+
+
+static int db_upvaluejoin (lua_State *L) {
+ int n1 = checkupval(L, 1, 2);
+ int n2 = checkupval(L, 3, 4);
+ luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
+ luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
+ lua_upvaluejoin(L, 1, n1, 3, n2);
+ return 0;
+}
+
+
+/*
+** Call hook function registered at hook table for the current
+** thread (if there is one)
+*/
+static void hookf (lua_State *L, lua_Debug *ar) {
+ static const char *const hooknames[] =
+ {"call", "return", "line", "count", "tail call"};
+ lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
+ lua_pushthread(L);
+ if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */
+ lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */
+ if (ar->currentline >= 0)
+ lua_pushinteger(L, ar->currentline); /* push current line */
+ else lua_pushnil(L);
+ lua_assert(lua_getinfo(L, "lS", ar));
+ lua_call(L, 2, 0); /* call hook function */
+ }
+}
+
+
+/*
+** Convert a string mask (for 'sethook') into a bit mask
+*/
+static int makemask (const char *smask, int count) {
+ int mask = 0;
+ if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
+ if (strchr(smask, 'r')) mask |= LUA_MASKRET;
+ if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
+ if (count > 0) mask |= LUA_MASKCOUNT;
+ return mask;
+}
+
+
+/*
+** Convert a bit mask (for 'gethook') into a string mask
+*/
+static char *unmakemask (int mask, char *smask) {
+ int i = 0;
+ if (mask & LUA_MASKCALL) smask[i++] = 'c';
+ if (mask & LUA_MASKRET) smask[i++] = 'r';
+ if (mask & LUA_MASKLINE) smask[i++] = 'l';
+ smask[i] = '\0';
+ return smask;
+}
+
+
+static int db_sethook (lua_State *L) {
+ int arg, mask, count;
+ lua_Hook func;
+ lua_State *L1 = getthread(L, &arg);
+ if (lua_isnoneornil(L, arg+1)) { /* no hook? */
+ lua_settop(L, arg+1);
+ func = NULL; mask = 0; count = 0; /* turn off hooks */
+ }
+ else {
+ const char *smask = luaL_checkstring(L, arg+2);
+ luaL_checktype(L, arg+1, LUA_TFUNCTION);
+ count = (int)luaL_optinteger(L, arg + 3, 0);
+ func = hookf; mask = makemask(smask, count);
+ }
+ if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) {
+ lua_createtable(L, 0, 2); /* create a hook table */
+ lua_pushvalue(L, -1);
+ lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */
+ lua_pushstring(L, "k");
+ lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
+ lua_pushvalue(L, -1);
+ lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
+ }
+ checkstack(L, L1, 1);
+ lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */
+ lua_pushvalue(L, arg + 1); /* value (hook function) */
+ lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */
+ lua_sethook(L1, func, mask, count);
+ return 0;
+}
+
+
+static int db_gethook (lua_State *L) {
+ int arg;
+ lua_State *L1 = getthread(L, &arg);
+ char buff[5];
+ int mask = lua_gethookmask(L1);
+ lua_Hook hook = lua_gethook(L1);
+ if (hook == NULL) /* no hook? */
+ lua_pushnil(L);
+ else if (hook != hookf) /* external hook? */
+ lua_pushliteral(L, "external hook");
+ else { /* hook table must exist */
+ lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
+ checkstack(L, L1, 1);
+ lua_pushthread(L1); lua_xmove(L1, L, 1);
+ lua_rawget(L, -2); /* 1st result = hooktable[L1] */
+ lua_remove(L, -2); /* remove hook table */
+ }
+ lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */
+ lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */
+ return 3;
+}
+
+
+static int db_debug (lua_State *L) {
+ for (;;) {
+ char buffer[250];
+ lua_writestringerror("%s", "lua_debug> ");
+ if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
+ strcmp(buffer, "cont\n") == 0)
+ return 0;
+ if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
+ lua_pcall(L, 0, 0, 0))
+ lua_writestringerror("%s\n", lua_tostring(L, -1));
+ lua_settop(L, 0); /* remove eventual returns */
+ }
+}
+
+
+static int db_traceback (lua_State *L) {
+ int arg;
+ lua_State *L1 = getthread(L, &arg);
+ const char *msg = lua_tostring(L, arg + 1);
+ if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */
+ lua_pushvalue(L, arg + 1); /* return it untouched */
+ else {
+ int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0);
+ luaL_traceback(L, L1, msg, level);
+ }
+ return 1;
+}
+
+
+static const luaL_Reg dblib[] = {
+ {"debug", db_debug},
+ {"getuservalue", db_getuservalue},
+ {"gethook", db_gethook},
+ {"getinfo", db_getinfo},
+ {"getlocal", db_getlocal},
+ {"getregistry", db_getregistry},
+ {"getmetatable", db_getmetatable},
+ {"getupvalue", db_getupvalue},
+ {"upvaluejoin", db_upvaluejoin},
+ {"upvalueid", db_upvalueid},
+ {"setuservalue", db_setuservalue},
+ {"sethook", db_sethook},
+ {"setlocal", db_setlocal},
+ {"setmetatable", db_setmetatable},
+ {"setupvalue", db_setupvalue},
+ {"traceback", db_traceback},
+ {NULL, NULL}
+};
+
+
+LUAMOD_API int luaopen_debug (lua_State *L) {
+ luaL_newlib(L, dblib);
+ return 1;
+}
+
diff --git a/external/lua-5.3.3/src/ldebug.c b/external/lua-5.3.3/src/ldebug.c
new file mode 100644
index 0000000..e499ee3
--- /dev/null
+++ b/external/lua-5.3.3/src/ldebug.c
@@ -0,0 +1,679 @@
+/*
+** $Id: ldebug.c,v 2.120 2016/03/31 19:01:21 roberto Exp $
+** Debug Interface
+** See Copyright Notice in lua.h
+*/
+
+#define ldebug_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lvm.h"
+
+
+
+#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)
+
+
+/* Active Lua function (given call info) */
+#define ci_func(ci) (clLvalue((ci)->func))
+
+
+static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
+
+
+static int currentpc (CallInfo *ci) {
+ lua_assert(isLua(ci));
+ return pcRel(ci->u.l.savedpc, ci_func(ci)->p);
+}
+
+
+static int currentline (CallInfo *ci) {
+ return getfuncline(ci_func(ci)->p, currentpc(ci));
+}
+
+
+/*
+** If function yielded, its 'func' can be in the 'extra' field. The
+** next function restores 'func' to its correct value for debugging
+** purposes. (It exchanges 'func' and 'extra'; so, when called again,
+** after debugging, it also "re-restores" ** 'func' to its altered value.
+*/
+static void swapextra (lua_State *L) {
+ if (L->status == LUA_YIELD) {
+ CallInfo *ci = L->ci; /* get function that yielded */
+ StkId temp = ci->func; /* exchange its 'func' and 'extra' values */
+ ci->func = restorestack(L, ci->extra);
+ ci->extra = savestack(L, temp);
+ }
+}
+
+
+/*
+** This function can be called asynchronously (e.g. during a signal).
+** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
+** 'resethookcount') are for debug only, and it is no problem if they
+** get arbitrary values (causes at most one wrong hook call). 'hookmask'
+** is an atomic value. We assume that pointers are atomic too (e.g., gcc
+** ensures that for all platforms where it runs). Moreover, 'hook' is
+** always checked before being called (see 'luaD_hook').
+*/
+LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
+ if (func == NULL || mask == 0) { /* turn off hooks? */
+ mask = 0;
+ func = NULL;
+ }
+ if (isLua(L->ci))
+ L->oldpc = L->ci->u.l.savedpc;
+ L->hook = func;
+ L->basehookcount = count;
+ resethookcount(L);
+ L->hookmask = cast_byte(mask);
+}
+
+
+LUA_API lua_Hook lua_gethook (lua_State *L) {
+ return L->hook;
+}
+
+
+LUA_API int lua_gethookmask (lua_State *L) {
+ return L->hookmask;
+}
+
+
+LUA_API int lua_gethookcount (lua_State *L) {
+ return L->basehookcount;
+}
+
+
+LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
+ int status;
+ CallInfo *ci;
+ if (level < 0) return 0; /* invalid (negative) level */
+ lua_lock(L);
+ for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)
+ level--;
+ if (level == 0 && ci != &L->base_ci) { /* level found? */
+ status = 1;
+ ar->i_ci = ci;
+ }
+ else status = 0; /* no such level */
+ lua_unlock(L);
+ return status;
+}
+
+
+static const char *upvalname (Proto *p, int uv) {
+ TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);
+ if (s == NULL) return "?";
+ else return getstr(s);
+}
+
+
+static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
+ int nparams = clLvalue(ci->func)->p->numparams;
+ if (n >= cast_int(ci->u.l.base - ci->func) - nparams)
+ return NULL; /* no such vararg */
+ else {
+ *pos = ci->func + nparams + n;
+ return "(*vararg)"; /* generic name for any vararg */
+ }
+}
+
+
+static const char *findlocal (lua_State *L, CallInfo *ci, int n,
+ StkId *pos) {
+ const char *name = NULL;
+ StkId base;
+ if (isLua(ci)) {
+ if (n < 0) /* access to vararg values? */
+ return findvararg(ci, -n, pos);
+ else {
+ base = ci->u.l.base;
+ name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
+ }
+ }
+ else
+ base = ci->func + 1;
+ if (name == NULL) { /* no 'standard' name? */
+ StkId limit = (ci == L->ci) ? L->top : ci->next->func;
+ if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */
+ name = "(*temporary)"; /* generic name for any valid slot */
+ else
+ return NULL; /* no name */
+ }
+ *pos = base + (n - 1);
+ return name;
+}
+
+
+LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
+ const char *name;
+ lua_lock(L);
+ swapextra(L);
+ if (ar == NULL) { /* information about non-active function? */
+ if (!isLfunction(L->top - 1)) /* not a Lua function? */
+ name = NULL;
+ else /* consider live variables at function start (parameters) */
+ name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);
+ }
+ else { /* active function; get information through 'ar' */
+ StkId pos = NULL; /* to avoid warnings */
+ name = findlocal(L, ar->i_ci, n, &pos);
+ if (name) {
+ setobj2s(L, L->top, pos);
+ api_incr_top(L);
+ }
+ }
+ swapextra(L);
+ lua_unlock(L);
+ return name;
+}
+
+
+LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
+ StkId pos = NULL; /* to avoid warnings */
+ const char *name;
+ lua_lock(L);
+ swapextra(L);
+ name = findlocal(L, ar->i_ci, n, &pos);
+ if (name) {
+ setobjs2s(L, pos, L->top - 1);
+ L->top--; /* pop value */
+ }
+ swapextra(L);
+ lua_unlock(L);
+ return name;
+}
+
+
+static void funcinfo (lua_Debug *ar, Closure *cl) {
+ if (noLuaClosure(cl)) {
+ ar->source = "=[C]";
+ ar->linedefined = -1;
+ ar->lastlinedefined = -1;
+ ar->what = "C";
+ }
+ else {
+ Proto *p = cl->l.p;
+ ar->source = p->source ? getstr(p->source) : "=?";
+ ar->linedefined = p->linedefined;
+ ar->lastlinedefined = p->lastlinedefined;
+ ar->what = (ar->linedefined == 0) ? "main" : "Lua";
+ }
+ luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
+}
+
+
+static void collectvalidlines (lua_State *L, Closure *f) {
+ if (noLuaClosure(f)) {
+ setnilvalue(L->top);
+ api_incr_top(L);
+ }
+ else {
+ int i;
+ TValue v;
+ int *lineinfo = f->l.p->lineinfo;
+ Table *t = luaH_new(L); /* new table to store active lines */
+ sethvalue(L, L->top, t); /* push it on stack */
+ api_incr_top(L);
+ setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */
+ for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */
+ luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */
+ }
+}
+
+
+static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
+ Closure *f, CallInfo *ci) {
+ int status = 1;
+ for (; *what; what++) {
+ switch (*what) {
+ case 'S': {
+ funcinfo(ar, f);
+ break;
+ }
+ case 'l': {
+ ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1;
+ break;
+ }
+ case 'u': {
+ ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
+ if (noLuaClosure(f)) {
+ ar->isvararg = 1;
+ ar->nparams = 0;
+ }
+ else {
+ ar->isvararg = f->l.p->is_vararg;
+ ar->nparams = f->l.p->numparams;
+ }
+ break;
+ }
+ case 't': {
+ ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
+ break;
+ }
+ case 'n': {
+ /* calling function is a known Lua function? */
+ if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
+ ar->namewhat = getfuncname(L, ci->previous, &ar->name);
+ else
+ ar->namewhat = NULL;
+ if (ar->namewhat == NULL) {
+ ar->namewhat = ""; /* not found */
+ ar->name = NULL;
+ }
+ break;
+ }
+ case 'L':
+ case 'f': /* handled by lua_getinfo */
+ break;
+ default: status = 0; /* invalid option */
+ }
+ }
+ return status;
+}
+
+
+LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
+ int status;
+ Closure *cl;
+ CallInfo *ci;
+ StkId func;
+ lua_lock(L);
+ swapextra(L);
+ if (*what == '>') {
+ ci = NULL;
+ func = L->top - 1;
+ api_check(L, ttisfunction(func), "function expected");
+ what++; /* skip the '>' */
+ L->top--; /* pop function */
+ }
+ else {
+ ci = ar->i_ci;
+ func = ci->func;
+ lua_assert(ttisfunction(ci->func));
+ }
+ cl = ttisclosure(func) ? clvalue(func) : NULL;
+ status = auxgetinfo(L, what, ar, cl, ci);
+ if (strchr(what, 'f')) {
+ setobjs2s(L, L->top, func);
+ api_incr_top(L);
+ }
+ swapextra(L); /* correct before option 'L', which can raise a mem. error */
+ if (strchr(what, 'L'))
+ collectvalidlines(L, cl);
+ lua_unlock(L);
+ return status;
+}
+
+
+/*
+** {======================================================
+** Symbolic Execution
+** =======================================================
+*/
+
+static const char *getobjname (Proto *p, int lastpc, int reg,
+ const char **name);
+
+
+/*
+** find a "name" for the RK value 'c'
+*/
+static void kname (Proto *p, int pc, int c, const char **name) {
+ if (ISK(c)) { /* is 'c' a constant? */
+ TValue *kvalue = &p->k[INDEXK(c)];
+ if (ttisstring(kvalue)) { /* literal constant? */
+ *name = svalue(kvalue); /* it is its own name */
+ return;
+ }
+ /* else no reasonable name found */
+ }
+ else { /* 'c' is a register */
+ const char *what = getobjname(p, pc, c, name); /* search for 'c' */
+ if (what && *what == 'c') { /* found a constant name? */
+ return; /* 'name' already filled */
+ }
+ /* else no reasonable name found */
+ }
+ *name = "?"; /* no reasonable name found */
+}
+
+
+static int filterpc (int pc, int jmptarget) {
+ if (pc < jmptarget) /* is code conditional (inside a jump)? */
+ return -1; /* cannot know who sets that register */
+ else return pc; /* current position sets that register */
+}
+
+
+/*
+** try to find last instruction before 'lastpc' that modified register 'reg'
+*/
+static int findsetreg (Proto *p, int lastpc, int reg) {
+ int pc;
+ int setreg = -1; /* keep last instruction that changed 'reg' */
+ int jmptarget = 0; /* any code before this address is conditional */
+ for (pc = 0; pc < lastpc; pc++) {
+ Instruction i = p->code[pc];
+ OpCode op = GET_OPCODE(i);
+ int a = GETARG_A(i);
+ switch (op) {
+ case OP_LOADNIL: {
+ int b = GETARG_B(i);
+ if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
+ setreg = filterpc(pc, jmptarget);
+ break;
+ }
+ case OP_TFORCALL: {
+ if (reg >= a + 2) /* affect all regs above its base */
+ setreg = filterpc(pc, jmptarget);
+ break;
+ }
+ case OP_CALL:
+ case OP_TAILCALL: {
+ if (reg >= a) /* affect all registers above base */
+ setreg = filterpc(pc, jmptarget);
+ break;
+ }
+ case OP_JMP: {
+ int b = GETARG_sBx(i);
+ int dest = pc + 1 + b;
+ /* jump is forward and do not skip 'lastpc'? */
+ if (pc < dest && dest <= lastpc) {
+ if (dest > jmptarget)
+ jmptarget = dest; /* update 'jmptarget' */
+ }
+ break;
+ }
+ default:
+ if (testAMode(op) && reg == a) /* any instruction that set A */
+ setreg = filterpc(pc, jmptarget);
+ break;
+ }
+ }
+ return setreg;
+}
+
+
+static const char *getobjname (Proto *p, int lastpc, int reg,
+ const char **name) {
+ int pc;
+ *name = luaF_getlocalname(p, reg + 1, lastpc);
+ if (*name) /* is a local? */
+ return "local";
+ /* else try symbolic execution */
+ pc = findsetreg(p, lastpc, reg);
+ if (pc != -1) { /* could find instruction? */
+ Instruction i = p->code[pc];
+ OpCode op = GET_OPCODE(i);
+ switch (op) {
+ case OP_MOVE: {
+ int b = GETARG_B(i); /* move from 'b' to 'a' */
+ if (b < GETARG_A(i))
+ return getobjname(p, pc, b, name); /* get name for 'b' */
+ break;
+ }
+ case OP_GETTABUP:
+ case OP_GETTABLE: {
+ int k = GETARG_C(i); /* key index */
+ int t = GETARG_B(i); /* table index */
+ const char *vn = (op == OP_GETTABLE) /* name of indexed variable */
+ ? luaF_getlocalname(p, t + 1, pc)
+ : upvalname(p, t);
+ kname(p, pc, k, name);
+ return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field";
+ }
+ case OP_GETUPVAL: {
+ *name = upvalname(p, GETARG_B(i));
+ return "upvalue";
+ }
+ case OP_LOADK:
+ case OP_LOADKX: {
+ int b = (op == OP_LOADK) ? GETARG_Bx(i)
+ : GETARG_Ax(p->code[pc + 1]);
+ if (ttisstring(&p->k[b])) {
+ *name = svalue(&p->k[b]);
+ return "constant";
+ }
+ break;
+ }
+ case OP_SELF: {
+ int k = GETARG_C(i); /* key index */
+ kname(p, pc, k, name);
+ return "method";
+ }
+ default: break; /* go through to return NULL */
+ }
+ }
+ return NULL; /* could not find reasonable name */
+}
+
+
+static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
+ TMS tm = (TMS)0; /* to avoid warnings */
+ Proto *p = ci_func(ci)->p; /* calling function */
+ int pc = currentpc(ci); /* calling instruction index */
+ Instruction i = p->code[pc]; /* calling instruction */
+ if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
+ *name = "?";
+ return "hook";
+ }
+ switch (GET_OPCODE(i)) {
+ case OP_CALL:
+ case OP_TAILCALL: /* get function name */
+ return getobjname(p, pc, GETARG_A(i), name);
+ case OP_TFORCALL: { /* for iterator */
+ *name = "for iterator";
+ return "for iterator";
+ }
+ /* all other instructions can call only through metamethods */
+ case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
+ tm = TM_INDEX;
+ break;
+ case OP_SETTABUP: case OP_SETTABLE:
+ tm = TM_NEWINDEX;
+ break;
+ case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD:
+ case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND:
+ case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: {
+ int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */
+ tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */
+ break;
+ }
+ case OP_UNM: tm = TM_UNM; break;
+ case OP_BNOT: tm = TM_BNOT; break;
+ case OP_LEN: tm = TM_LEN; break;
+ case OP_CONCAT: tm = TM_CONCAT; break;
+ case OP_EQ: tm = TM_EQ; break;
+ case OP_LT: tm = TM_LT; break;
+ case OP_LE: tm = TM_LE; break;
+ default: lua_assert(0); /* other instructions cannot call a function */
+ }
+ *name = getstr(G(L)->tmname[tm]);
+ return "metamethod";
+}
+
+/* }====================================================== */
+
+
+
+/*
+** The subtraction of two potentially unrelated pointers is
+** not ISO C, but it should not crash a program; the subsequent
+** checks are ISO C and ensure a correct result.
+*/
+static int isinstack (CallInfo *ci, const TValue *o) {
+ ptrdiff_t i = o - ci->u.l.base;
+ return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o);
+}
+
+
+/*
+** Checks whether value 'o' came from an upvalue. (That can only happen
+** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on
+** upvalues.)
+*/
+static const char *getupvalname (CallInfo *ci, const TValue *o,
+ const char **name) {
+ LClosure *c = ci_func(ci);
+ int i;
+ for (i = 0; i < c->nupvalues; i++) {
+ if (c->upvals[i]->v == o) {
+ *name = upvalname(c->p, i);
+ return "upvalue";
+ }
+ }
+ return NULL;
+}
+
+
+static const char *varinfo (lua_State *L, const TValue *o) {
+ const char *name = NULL; /* to avoid warnings */
+ CallInfo *ci = L->ci;
+ const char *kind = NULL;
+ if (isLua(ci)) {
+ kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
+ if (!kind && isinstack(ci, o)) /* no? try a register */
+ kind = getobjname(ci_func(ci)->p, currentpc(ci),
+ cast_int(o - ci->u.l.base), &name);
+ }
+ return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : "";
+}
+
+
+l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
+ const char *t = luaT_objtypename(L, o);
+ luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
+}
+
+
+l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) {
+ if (ttisstring(p1) || cvt2str(p1)) p1 = p2;
+ luaG_typeerror(L, p1, "concatenate");
+}
+
+
+l_noret luaG_opinterror (lua_State *L, const TValue *p1,
+ const TValue *p2, const char *msg) {
+ lua_Number temp;
+ if (!tonumber(p1, &temp)) /* first operand is wrong? */
+ p2 = p1; /* now second is wrong */
+ luaG_typeerror(L, p2, msg);
+}
+
+
+/*
+** Error when both values are convertible to numbers, but not to integers
+*/
+l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
+ lua_Integer temp;
+ if (!tointeger(p1, &temp))
+ p2 = p1;
+ luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2));
+}
+
+
+l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
+ const char *t1 = luaT_objtypename(L, p1);
+ const char *t2 = luaT_objtypename(L, p2);
+ if (strcmp(t1, t2) == 0)
+ luaG_runerror(L, "attempt to compare two %s values", t1);
+ else
+ luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
+}
+
+
+/* add src:line information to 'msg' */
+const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
+ int line) {
+ char buff[LUA_IDSIZE];
+ if (src)
+ luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
+ else { /* no source available; use "?" instead */
+ buff[0] = '?'; buff[1] = '\0';
+ }
+ return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
+}
+
+
+l_noret luaG_errormsg (lua_State *L) {
+ if (L->errfunc != 0) { /* is there an error handling function? */
+ StkId errfunc = restorestack(L, L->errfunc);
+ setobjs2s(L, L->top, L->top - 1); /* move argument */
+ setobjs2s(L, L->top - 1, errfunc); /* push function */
+ L->top++; /* assume EXTRA_STACK */
+ luaD_callnoyield(L, L->top - 2, 1); /* call it */
+ }
+ luaD_throw(L, LUA_ERRRUN);
+}
+
+
+l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
+ CallInfo *ci = L->ci;
+ const char *msg;
+ va_list argp;
+ va_start(argp, fmt);
+ msg = luaO_pushvfstring(L, fmt, argp); /* format message */
+ va_end(argp);
+ if (isLua(ci)) /* if Lua function, add source:line information */
+ luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci));
+ luaG_errormsg(L);
+}
+
+
+void luaG_traceexec (lua_State *L) {
+ CallInfo *ci = L->ci;
+ lu_byte mask = L->hookmask;
+ int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
+ if (counthook)
+ resethookcount(L); /* reset count */
+ else if (!(mask & LUA_MASKLINE))
+ return; /* no line hook and count != 0; nothing to be done */
+ if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
+ ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
+ return; /* do not call hook again (VM yielded, so it did not move) */
+ }
+ if (counthook)
+ luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */
+ if (mask & LUA_MASKLINE) {
+ Proto *p = ci_func(ci)->p;
+ int npc = pcRel(ci->u.l.savedpc, p);
+ int newline = getfuncline(p, npc);
+ if (npc == 0 || /* call linehook when enter a new function, */
+ ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */
+ newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */
+ luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */
+ }
+ L->oldpc = ci->u.l.savedpc;
+ if (L->status == LUA_YIELD) { /* did hook yield? */
+ if (counthook)
+ L->hookcount = 1; /* undo decrement to zero */
+ ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
+ ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
+ ci->func = L->top - 1; /* protect stack below results */
+ luaD_throw(L, LUA_YIELD);
+ }
+}
+
diff --git a/external/lua-5.3.3/src/ldebug.h b/external/lua-5.3.3/src/ldebug.h
new file mode 100644
index 0000000..0e31546
--- /dev/null
+++ b/external/lua-5.3.3/src/ldebug.h
@@ -0,0 +1,39 @@
+/*
+** $Id: ldebug.h,v 2.14 2015/05/22 17:45:56 roberto Exp $
+** Auxiliary functions from Debug Interface module
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ldebug_h
+#define ldebug_h
+
+
+#include "lstate.h"
+
+
+#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
+
+#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1)
+
+#define resethookcount(L) (L->hookcount = L->basehookcount)
+
+
+LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
+ const char *opname);
+LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1,
+ const TValue *p2);
+LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1,
+ const TValue *p2,
+ const char *msg);
+LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
+ const TValue *p2);
+LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
+ const TValue *p2);
+LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
+LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
+ TString *src, int line);
+LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
+LUAI_FUNC void luaG_traceexec (lua_State *L);
+
+
+#endif
diff --git a/external/lua-5.3.3/src/ldo.c b/external/lua-5.3.3/src/ldo.c
new file mode 100644
index 0000000..8804c99
--- /dev/null
+++ b/external/lua-5.3.3/src/ldo.c
@@ -0,0 +1,800 @@
+/*
+** $Id: ldo.c,v 2.151 2015/12/16 16:40:07 roberto Exp $
+** Stack and Call structure of Lua
+** See Copyright Notice in lua.h
+*/
+
+#define ldo_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <setjmp.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lundump.h"
+#include "lvm.h"
+#include "lzio.h"
+
+
+
+#define errorstatus(s) ((s) > LUA_YIELD)
+
+
+/*
+** {======================================================
+** Error-recovery functions
+** =======================================================
+*/
+
+/*
+** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By
+** default, Lua handles errors with exceptions when compiling as
+** C++ code, with _longjmp/_setjmp when asked to use them, and with
+** longjmp/setjmp otherwise.
+*/
+#if !defined(LUAI_THROW) /* { */
+
+#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */
+
+/* C++ exceptions */
+#define LUAI_THROW(L,c) throw(c)
+#define LUAI_TRY(L,c,a) \
+ try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; }
+#define luai_jmpbuf int /* dummy variable */
+
+#elif defined(LUA_USE_POSIX) /* }{ */
+
+/* in POSIX, try _longjmp/_setjmp (more efficient) */
+#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
+#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }
+#define luai_jmpbuf jmp_buf
+
+#else /* }{ */
+
+/* ISO C handling with long jumps */
+#define LUAI_THROW(L,c) longjmp((c)->b, 1)
+#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
+#define luai_jmpbuf jmp_buf
+
+#endif /* } */
+
+#endif /* } */
+
+
+
+/* chain list of long jump buffers */
+struct lua_longjmp {
+ struct lua_longjmp *previous;
+ luai_jmpbuf b;
+ volatile int status; /* error code */
+};
+
+
+static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {
+ switch (errcode) {
+ case LUA_ERRMEM: { /* memory error? */
+ setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
+ break;
+ }
+ case LUA_ERRERR: {
+ setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
+ break;
+ }
+ default: {
+ setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
+ break;
+ }
+ }
+ L->top = oldtop + 1;
+}
+
+
+l_noret luaD_throw (lua_State *L, int errcode) {
+ if (L->errorJmp) { /* thread has an error handler? */
+ L->errorJmp->status = errcode; /* set status */
+ LUAI_THROW(L, L->errorJmp); /* jump to it */
+ }
+ else { /* thread has no error handler */
+ global_State *g = G(L);
+ L->status = cast_byte(errcode); /* mark it as dead */
+ if (g->mainthread->errorJmp) { /* main thread has a handler? */
+ setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
+ luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
+ }
+ else { /* no handler at all; abort */
+ if (g->panic) { /* panic function? */
+ seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */
+ if (L->ci->top < L->top)
+ L->ci->top = L->top; /* pushing msg. can break this invariant */
+ lua_unlock(L);
+ g->panic(L); /* call panic function (last chance to jump out) */
+ }
+ abort();
+ }
+ }
+}
+
+
+int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
+ unsigned short oldnCcalls = L->nCcalls;
+ struct lua_longjmp lj;
+ lj.status = LUA_OK;
+ lj.previous = L->errorJmp; /* chain new error handler */
+ L->errorJmp = &lj;
+ LUAI_TRY(L, &lj,
+ (*f)(L, ud);
+ );
+ L->errorJmp = lj.previous; /* restore old error handler */
+ L->nCcalls = oldnCcalls;
+ return lj.status;
+}
+
+/* }====================================================== */
+
+
+/*
+** {==================================================================
+** Stack reallocation
+** ===================================================================
+*/
+static void correctstack (lua_State *L, TValue *oldstack) {
+ CallInfo *ci;
+ UpVal *up;
+ L->top = (L->top - oldstack) + L->stack;
+ for (up = L->openupval; up != NULL; up = up->u.open.next)
+ up->v = (up->v - oldstack) + L->stack;
+ for (ci = L->ci; ci != NULL; ci = ci->previous) {
+ ci->top = (ci->top - oldstack) + L->stack;
+ ci->func = (ci->func - oldstack) + L->stack;
+ if (isLua(ci))
+ ci->u.l.base = (ci->u.l.base - oldstack) + L->stack;
+ }
+}
+
+
+/* some space for error handling */
+#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
+
+
+void luaD_reallocstack (lua_State *L, int newsize) {
+ TValue *oldstack = L->stack;
+ int lim = L->stacksize;
+ lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
+ lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
+ luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue);
+ for (; lim < newsize; lim++)
+ setnilvalue(L->stack + lim); /* erase new segment */
+ L->stacksize = newsize;
+ L->stack_last = L->stack + newsize - EXTRA_STACK;
+ correctstack(L, oldstack);
+}
+
+
+void luaD_growstack (lua_State *L, int n) {
+ int size = L->stacksize;
+ if (size > LUAI_MAXSTACK) /* error after extra size? */
+ luaD_throw(L, LUA_ERRERR);
+ else {
+ int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;
+ int newsize = 2 * size;
+ if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;
+ if (newsize < needed) newsize = needed;
+ if (newsize > LUAI_MAXSTACK) { /* stack overflow? */
+ luaD_reallocstack(L, ERRORSTACKSIZE);
+ luaG_runerror(L, "stack overflow");
+ }
+ else
+ luaD_reallocstack(L, newsize);
+ }
+}
+
+
+static int stackinuse (lua_State *L) {
+ CallInfo *ci;
+ StkId lim = L->top;
+ for (ci = L->ci; ci != NULL; ci = ci->previous) {
+ lua_assert(ci->top <= L->stack_last);
+ if (lim < ci->top) lim = ci->top;
+ }
+ return cast_int(lim - L->stack) + 1; /* part of stack in use */
+}
+
+
+void luaD_shrinkstack (lua_State *L) {
+ int inuse = stackinuse(L);
+ int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
+ if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
+ if (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */
+ luaE_freeCI(L); /* free all CIs (list grew because of an error) */
+ else
+ luaE_shrinkCI(L); /* shrink list */
+ if (inuse <= LUAI_MAXSTACK && /* not handling stack overflow? */
+ goodsize < L->stacksize) /* trying to shrink? */
+ luaD_reallocstack(L, goodsize); /* shrink it */
+ else
+ condmovestack(L,,); /* don't change stack (change only for debugging) */
+}
+
+
+void luaD_inctop (lua_State *L) {
+ luaD_checkstack(L, 1);
+ L->top++;
+}
+
+/* }================================================================== */
+
+
+/*
+** Call a hook for the given event. Make sure there is a hook to be
+** called. (Both 'L->hook' and 'L->hookmask', which triggers this
+** function, can be changed asynchronously by signals.)
+*/
+void luaD_hook (lua_State *L, int event, int line) {
+ lua_Hook hook = L->hook;
+ if (hook && L->allowhook) { /* make sure there is a hook */
+ CallInfo *ci = L->ci;
+ ptrdiff_t top = savestack(L, L->top);
+ ptrdiff_t ci_top = savestack(L, ci->top);
+ lua_Debug ar;
+ ar.event = event;
+ ar.currentline = line;
+ ar.i_ci = ci;
+ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
+ ci->top = L->top + LUA_MINSTACK;
+ lua_assert(ci->top <= L->stack_last);
+ L->allowhook = 0; /* cannot call hooks inside a hook */
+ ci->callstatus |= CIST_HOOKED;
+ lua_unlock(L);
+ (*hook)(L, &ar);
+ lua_lock(L);
+ lua_assert(!L->allowhook);
+ L->allowhook = 1;
+ ci->top = restorestack(L, ci_top);
+ L->top = restorestack(L, top);
+ ci->callstatus &= ~CIST_HOOKED;
+ }
+}
+
+
+static void callhook (lua_State *L, CallInfo *ci) {
+ int hook = LUA_HOOKCALL;
+ ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */
+ if (isLua(ci->previous) &&
+ GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) {
+ ci->callstatus |= CIST_TAIL;
+ hook = LUA_HOOKTAILCALL;
+ }
+ luaD_hook(L, hook, -1);
+ ci->u.l.savedpc--; /* correct 'pc' */
+}
+
+
+static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
+ int i;
+ int nfixargs = p->numparams;
+ StkId base, fixed;
+ /* move fixed parameters to final position */
+ fixed = L->top - actual; /* first fixed argument */
+ base = L->top; /* final position of first argument */
+ for (i = 0; i < nfixargs && i < actual; i++) {
+ setobjs2s(L, L->top++, fixed + i);
+ setnilvalue(fixed + i); /* erase original copy (for GC) */
+ }
+ for (; i < nfixargs; i++)
+ setnilvalue(L->top++); /* complete missing arguments */
+ return base;
+}
+
+
+/*
+** Check whether __call metafield of 'func' is a function. If so, put
+** it in stack below original 'func' so that 'luaD_precall' can call
+** it. Raise an error if __call metafield is not a function.
+*/
+static void tryfuncTM (lua_State *L, StkId func) {
+ const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);
+ StkId p;
+ if (!ttisfunction(tm))
+ luaG_typeerror(L, func, "call");
+ /* Open a hole inside the stack at 'func' */
+ for (p = L->top; p > func; p--)
+ setobjs2s(L, p, p-1);
+ L->top++; /* slot ensured by caller */
+ setobj2s(L, func, tm); /* tag method is the new function to be called */
+}
+
+
+
+#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
+
+
+/* macro to check stack size, preserving 'p' */
+#define checkstackp(L,n,p) \
+ luaD_checkstackaux(L, n, \
+ ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
+ luaC_checkGC(L), /* stack grow uses memory */ \
+ p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
+
+
+/*
+** Prepares a function call: checks the stack, creates a new CallInfo
+** entry, fills in the relevant information, calls hook if needed.
+** If function is a C function, does the call, too. (Otherwise, leave
+** the execution ('luaV_execute') to the caller, to allow stackless
+** calls.) Returns true iff function has been executed (C function).
+*/
+int luaD_precall (lua_State *L, StkId func, int nresults) {
+ lua_CFunction f;
+ CallInfo *ci;
+ switch (ttype(func)) {
+ case LUA_TCCL: /* C closure */
+ f = clCvalue(func)->f;
+ goto Cfunc;
+ case LUA_TLCF: /* light C function */
+ f = fvalue(func);
+ Cfunc: {
+ int n; /* number of returns */
+ checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
+ ci = next_ci(L); /* now 'enter' new function */
+ ci->nresults = nresults;
+ ci->func = func;
+ ci->top = L->top + LUA_MINSTACK;
+ lua_assert(ci->top <= L->stack_last);
+ ci->callstatus = 0;
+ if (L->hookmask & LUA_MASKCALL)
+ luaD_hook(L, LUA_HOOKCALL, -1);
+ lua_unlock(L);
+ n = (*f)(L); /* do the actual call */
+ lua_lock(L);
+ api_checknelems(L, n);
+ luaD_poscall(L, ci, L->top - n, n);
+ return 1;
+ }
+ case LUA_TLCL: { /* Lua function: prepare its call */
+ StkId base;
+ Proto *p = clLvalue(func)->p;
+ int n = cast_int(L->top - func) - 1; /* number of real arguments */
+ int fsize = p->maxstacksize; /* frame size */
+ checkstackp(L, fsize, func);
+ if (p->is_vararg != 1) { /* do not use vararg? */
+ for (; n < p->numparams; n++)
+ setnilvalue(L->top++); /* complete missing arguments */
+ base = func + 1;
+ }
+ else
+ base = adjust_varargs(L, p, n);
+ ci = next_ci(L); /* now 'enter' new function */
+ ci->nresults = nresults;
+ ci->func = func;
+ ci->u.l.base = base;
+ L->top = ci->top = base + fsize;
+ lua_assert(ci->top <= L->stack_last);
+ ci->u.l.savedpc = p->code; /* starting point */
+ ci->callstatus = CIST_LUA;
+ if (L->hookmask & LUA_MASKCALL)
+ callhook(L, ci);
+ return 0;
+ }
+ default: { /* not a function */
+ checkstackp(L, 1, func); /* ensure space for metamethod */
+ tryfuncTM(L, func); /* try to get '__call' metamethod */
+ return luaD_precall(L, func, nresults); /* now it must be a function */
+ }
+ }
+}
+
+
+/*
+** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'.
+** Handle most typical cases (zero results for commands, one result for
+** expressions, multiple results for tail calls/single parameters)
+** separated.
+*/
+static int moveresults (lua_State *L, const TValue *firstResult, StkId res,
+ int nres, int wanted) {
+ switch (wanted) { /* handle typical cases separately */
+ case 0: break; /* nothing to move */
+ case 1: { /* one result needed */
+ if (nres == 0) /* no results? */
+ firstResult = luaO_nilobject; /* adjust with nil */
+ setobjs2s(L, res, firstResult); /* move it to proper place */
+ break;
+ }
+ case LUA_MULTRET: {
+ int i;
+ for (i = 0; i < nres; i++) /* move all results to correct place */
+ setobjs2s(L, res + i, firstResult + i);
+ L->top = res + nres;
+ return 0; /* wanted == LUA_MULTRET */
+ }
+ default: {
+ int i;
+ if (wanted <= nres) { /* enough results? */
+ for (i = 0; i < wanted; i++) /* move wanted results to correct place */
+ setobjs2s(L, res + i, firstResult + i);
+ }
+ else { /* not enough results; use all of them plus nils */
+ for (i = 0; i < nres; i++) /* move all results to correct place */
+ setobjs2s(L, res + i, firstResult + i);
+ for (; i < wanted; i++) /* complete wanted number of results */
+ setnilvalue(res + i);
+ }
+ break;
+ }
+ }
+ L->top = res + wanted; /* top points after the last result */
+ return 1;
+}
+
+
+/*
+** Finishes a function call: calls hook if necessary, removes CallInfo,
+** moves current number of results to proper place; returns 0 iff call
+** wanted multiple (variable number of) results.
+*/
+int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
+ StkId res;
+ int wanted = ci->nresults;
+ if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
+ if (L->hookmask & LUA_MASKRET) {
+ ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
+ luaD_hook(L, LUA_HOOKRET, -1);
+ firstResult = restorestack(L, fr);
+ }
+ L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
+ }
+ res = ci->func; /* res == final position of 1st result */
+ L->ci = ci->previous; /* back to caller */
+ /* move results to proper place */
+ return moveresults(L, firstResult, res, nres, wanted);
+}
+
+
+/*
+** Check appropriate error for stack overflow ("regular" overflow or
+** overflow while handling stack overflow). If 'nCalls' is larger than
+** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but
+** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to
+** allow overflow handling to work)
+*/
+static void stackerror (lua_State *L) {
+ if (L->nCcalls == LUAI_MAXCCALLS)
+ luaG_runerror(L, "C stack overflow");
+ else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
+ luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
+}
+
+
+/*
+** Call a function (C or Lua). The function to be called is at *func.
+** The arguments are on the stack, right after the function.
+** When returns, all the results are on the stack, starting at the original
+** function position.
+*/
+void luaD_call (lua_State *L, StkId func, int nResults) {
+ if (++L->nCcalls >= LUAI_MAXCCALLS)
+ stackerror(L);
+ if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
+ luaV_execute(L); /* call it */
+ L->nCcalls--;
+}
+
+
+/*
+** Similar to 'luaD_call', but does not allow yields during the call
+*/
+void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
+ L->nny++;
+ luaD_call(L, func, nResults);
+ L->nny--;
+}
+
+
+/*
+** Completes the execution of an interrupted C function, calling its
+** continuation function.
+*/
+static void finishCcall (lua_State *L, int status) {
+ CallInfo *ci = L->ci;
+ int n;
+ /* must have a continuation and must be able to call it */
+ lua_assert(ci->u.c.k != NULL && L->nny == 0);
+ /* error status can only happen in a protected call */
+ lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
+ if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
+ ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */
+ L->errfunc = ci->u.c.old_errfunc;
+ }
+ /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
+ handled */
+ adjustresults(L, ci->nresults);
+ /* call continuation function */
+ lua_unlock(L);
+ n = (*ci->u.c.k)(L, status, ci->u.c.ctx);
+ lua_lock(L);
+ api_checknelems(L, n);
+ /* finish 'luaD_precall' */
+ luaD_poscall(L, ci, L->top - n, n);
+}
+
+
+/*
+** Executes "full continuation" (everything in the stack) of a
+** previously interrupted coroutine until the stack is empty (or another
+** interruption long-jumps out of the loop). If the coroutine is
+** recovering from an error, 'ud' points to the error status, which must
+** be passed to the first continuation function (otherwise the default
+** status is LUA_YIELD).
+*/
+static void unroll (lua_State *L, void *ud) {
+ if (ud != NULL) /* error status? */
+ finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */
+ while (L->ci != &L->base_ci) { /* something in the stack */
+ if (!isLua(L->ci)) /* C function? */
+ finishCcall(L, LUA_YIELD); /* complete its execution */
+ else { /* Lua function */
+ luaV_finishOp(L); /* finish interrupted instruction */
+ luaV_execute(L); /* execute down to higher C 'boundary' */
+ }
+ }
+}
+
+
+/*
+** Try to find a suspended protected call (a "recover point") for the
+** given thread.
+*/
+static CallInfo *findpcall (lua_State *L) {
+ CallInfo *ci;
+ for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */
+ if (ci->callstatus & CIST_YPCALL)
+ return ci;
+ }
+ return NULL; /* no pending pcall */
+}
+
+
+/*
+** Recovers from an error in a coroutine. Finds a recover point (if
+** there is one) and completes the execution of the interrupted
+** 'luaD_pcall'. If there is no recover point, returns zero.
+*/
+static int recover (lua_State *L, int status) {
+ StkId oldtop;
+ CallInfo *ci = findpcall(L);
+ if (ci == NULL) return 0; /* no recovery point */
+ /* "finish" luaD_pcall */
+ oldtop = restorestack(L, ci->extra);
+ luaF_close(L, oldtop);
+ seterrorobj(L, status, oldtop);
+ L->ci = ci;
+ L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */
+ L->nny = 0; /* should be zero to be yieldable */
+ luaD_shrinkstack(L);
+ L->errfunc = ci->u.c.old_errfunc;
+ return 1; /* continue running the coroutine */
+}
+
+
+/*
+** signal an error in the call to 'resume', not in the execution of the
+** coroutine itself. (Such errors should not be handled by any coroutine
+** error handler and should not kill the coroutine.)
+*/
+static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
+ L->top = firstArg; /* remove args from the stack */
+ setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
+ api_incr_top(L);
+ luaD_throw(L, -1); /* jump back to 'lua_resume' */
+}
+
+
+/*
+** Do the work for 'lua_resume' in protected mode. Most of the work
+** depends on the status of the coroutine: initial state, suspended
+** inside a hook, or regularly suspended (optionally with a continuation
+** function), plus erroneous cases: non-suspended coroutine or dead
+** coroutine.
+*/
+static void resume (lua_State *L, void *ud) {
+ int nCcalls = L->nCcalls;
+ int n = *(cast(int*, ud)); /* number of arguments */
+ StkId firstArg = L->top - n; /* first argument */
+ CallInfo *ci = L->ci;
+ if (nCcalls >= LUAI_MAXCCALLS)
+ resume_error(L, "C stack overflow", firstArg);
+ if (L->status == LUA_OK) { /* may be starting a coroutine */
+ if (ci != &L->base_ci) /* not in base level? */
+ resume_error(L, "cannot resume non-suspended coroutine", firstArg);
+ /* coroutine is in base level; start running it */
+ if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
+ luaV_execute(L); /* call it */
+ }
+ else if (L->status != LUA_YIELD)
+ resume_error(L, "cannot resume dead coroutine", firstArg);
+ else { /* resuming from previous yield */
+ L->status = LUA_OK; /* mark that it is running (again) */
+ ci->func = restorestack(L, ci->extra);
+ if (isLua(ci)) /* yielded inside a hook? */
+ luaV_execute(L); /* just continue running Lua code */
+ else { /* 'common' yield */
+ if (ci->u.c.k != NULL) { /* does it have a continuation function? */
+ lua_unlock(L);
+ n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */
+ lua_lock(L);
+ api_checknelems(L, n);
+ firstArg = L->top - n; /* yield results come from continuation */
+ }
+ luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */
+ }
+ unroll(L, NULL); /* run continuation */
+ }
+ lua_assert(nCcalls == L->nCcalls);
+}
+
+
+LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
+ int status;
+ unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */
+ lua_lock(L);
+ luai_userstateresume(L, nargs);
+ L->nCcalls = (from) ? from->nCcalls + 1 : 1;
+ L->nny = 0; /* allow yields */
+ api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
+ status = luaD_rawrunprotected(L, resume, &nargs);
+ if (status == -1) /* error calling 'lua_resume'? */
+ status = LUA_ERRRUN;
+ else { /* continue running after recoverable errors */
+ while (errorstatus(status) && recover(L, status)) {
+ /* unroll continuation */
+ status = luaD_rawrunprotected(L, unroll, &status);
+ }
+ if (errorstatus(status)) { /* unrecoverable error? */
+ L->status = cast_byte(status); /* mark thread as 'dead' */
+ seterrorobj(L, status, L->top); /* push error message */
+ L->ci->top = L->top;
+ }
+ else lua_assert(status == L->status); /* normal end or yield */
+ }
+ L->nny = oldnny; /* restore 'nny' */
+ L->nCcalls--;
+ lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
+ lua_unlock(L);
+ return status;
+}
+
+
+LUA_API int lua_isyieldable (lua_State *L) {
+ return (L->nny == 0);
+}
+
+
+LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
+ lua_KFunction k) {
+ CallInfo *ci = L->ci;
+ luai_userstateyield(L, nresults);
+ lua_lock(L);
+ api_checknelems(L, nresults);
+ if (L->nny > 0) {
+ if (L != G(L)->mainthread)
+ luaG_runerror(L, "attempt to yield across a C-call boundary");
+ else
+ luaG_runerror(L, "attempt to yield from outside a coroutine");
+ }
+ L->status = LUA_YIELD;
+ ci->extra = savestack(L, ci->func); /* save current 'func' */
+ if (isLua(ci)) { /* inside a hook? */
+ api_check(L, k == NULL, "hooks cannot continue after yielding");
+ }
+ else {
+ if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
+ ci->u.c.ctx = ctx; /* save context */
+ ci->func = L->top - nresults - 1; /* protect stack below results */
+ luaD_throw(L, LUA_YIELD);
+ }
+ lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */
+ lua_unlock(L);
+ return 0; /* return to 'luaD_hook' */
+}
+
+
+int luaD_pcall (lua_State *L, Pfunc func, void *u,
+ ptrdiff_t old_top, ptrdiff_t ef) {
+ int status;
+ CallInfo *old_ci = L->ci;
+ lu_byte old_allowhooks = L->allowhook;
+ unsigned short old_nny = L->nny;
+ ptrdiff_t old_errfunc = L->errfunc;
+ L->errfunc = ef;
+ status = luaD_rawrunprotected(L, func, u);
+ if (status != LUA_OK) { /* an error occurred? */
+ StkId oldtop = restorestack(L, old_top);
+ luaF_close(L, oldtop); /* close possible pending closures */
+ seterrorobj(L, status, oldtop);
+ L->ci = old_ci;
+ L->allowhook = old_allowhooks;
+ L->nny = old_nny;
+ luaD_shrinkstack(L);
+ }
+ L->errfunc = old_errfunc;
+ return status;
+}
+
+
+
+/*
+** Execute a protected parser.
+*/
+struct SParser { /* data to 'f_parser' */
+ ZIO *z;
+ Mbuffer buff; /* dynamic structure used by the scanner */
+ Dyndata dyd; /* dynamic structures used by the parser */
+ const char *mode;
+ const char *name;
+};
+
+
+static void checkmode (lua_State *L, const char *mode, const char *x) {
+ if (mode && strchr(mode, x[0]) == NULL) {
+ luaO_pushfstring(L,
+ "attempt to load a %s chunk (mode is '%s')", x, mode);
+ luaD_throw(L, LUA_ERRSYNTAX);
+ }
+}
+
+
+static void f_parser (lua_State *L, void *ud) {
+ LClosure *cl;
+ struct SParser *p = cast(struct SParser *, ud);
+ int c = zgetc(p->z); /* read first character */
+ if (c == LUA_SIGNATURE[0]) {
+ checkmode(L, p->mode, "binary");
+ cl = luaU_undump(L, p->z, p->name);
+ }
+ else {
+ checkmode(L, p->mode, "text");
+ cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
+ }
+ lua_assert(cl->nupvalues == cl->p->sizeupvalues);
+ luaF_initupvals(L, cl);
+}
+
+
+int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
+ const char *mode) {
+ struct SParser p;
+ int status;
+ L->nny++; /* cannot yield during parsing */
+ p.z = z; p.name = name; p.mode = mode;
+ p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0;
+ p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
+ p.dyd.label.arr = NULL; p.dyd.label.size = 0;
+ luaZ_initbuffer(L, &p.buff);
+ status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
+ luaZ_freebuffer(L, &p.buff);
+ luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
+ luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
+ luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size);
+ L->nny--;
+ return status;
+}
+
+
diff --git a/external/lua-5.3.3/src/ldo.h b/external/lua-5.3.3/src/ldo.h
new file mode 100644
index 0000000..4f5d51c
--- /dev/null
+++ b/external/lua-5.3.3/src/ldo.h
@@ -0,0 +1,58 @@
+/*
+** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $
+** Stack and Call structure of Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ldo_h
+#define ldo_h
+
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lzio.h"
+
+
+/*
+** Macro to check stack size and grow stack if needed. Parameters
+** 'pre'/'pos' allow the macro to preserve a pointer into the
+** stack across reallocations, doing the work only when needed.
+** 'condmovestack' is used in heavy tests to force a stack reallocation
+** at every check.
+*/
+#define luaD_checkstackaux(L,n,pre,pos) \
+ if (L->stack_last - L->top <= (n)) \
+ { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); }
+
+/* In general, 'pre'/'pos' are empty (nothing to save) */
+#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
+
+
+
+#define savestack(L,p) ((char *)(p) - (char *)L->stack)
+#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
+
+
+/* type of protected functions, to be ran by 'runprotected' */
+typedef void (*Pfunc) (lua_State *L, void *ud);
+
+LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
+ const char *mode);
+LUAI_FUNC void luaD_hook (lua_State *L, int event, int line);
+LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
+LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
+LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
+LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
+ ptrdiff_t oldtop, ptrdiff_t ef);
+LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult,
+ int nres);
+LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
+LUAI_FUNC void luaD_growstack (lua_State *L, int n);
+LUAI_FUNC void luaD_shrinkstack (lua_State *L);
+LUAI_FUNC void luaD_inctop (lua_State *L);
+
+LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
+LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
+
+#endif
+
diff --git a/external/lua-5.3.3/src/ldump.c b/external/lua-5.3.3/src/ldump.c
new file mode 100644
index 0000000..016e300
--- /dev/null
+++ b/external/lua-5.3.3/src/ldump.c
@@ -0,0 +1,215 @@
+/*
+** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $
+** save precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#define ldump_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lundump.h"
+
+
+typedef struct {
+ lua_State *L;
+ lua_Writer writer;
+ void *data;
+ int strip;
+ int status;
+} DumpState;
+
+
+/*
+** All high-level dumps go through DumpVector; you can change it to
+** change the endianness of the result
+*/
+#define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D)
+
+#define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D)
+
+
+static void DumpBlock (const void *b, size_t size, DumpState *D) {
+ if (D->status == 0 && size > 0) {
+ lua_unlock(D->L);
+ D->status = (*D->writer)(D->L, b, size, D->data);
+ lua_lock(D->L);
+ }
+}
+
+
+#define DumpVar(x,D) DumpVector(&x,1,D)
+
+
+static void DumpByte (int y, DumpState *D) {
+ lu_byte x = (lu_byte)y;
+ DumpVar(x, D);
+}
+
+
+static void DumpInt (int x, DumpState *D) {
+ DumpVar(x, D);
+}
+
+
+static void DumpNumber (lua_Number x, DumpState *D) {
+ DumpVar(x, D);
+}
+
+
+static void DumpInteger (lua_Integer x, DumpState *D) {
+ DumpVar(x, D);
+}
+
+
+static void DumpString (const TString *s, DumpState *D) {
+ if (s == NULL)
+ DumpByte(0, D);
+ else {
+ size_t size = tsslen(s) + 1; /* include trailing '\0' */
+ const char *str = getstr(s);
+ if (size < 0xFF)
+ DumpByte(cast_int(size), D);
+ else {
+ DumpByte(0xFF, D);
+ DumpVar(size, D);
+ }
+ DumpVector(str, size - 1, D); /* no need to save '\0' */
+ }
+}
+
+
+static void DumpCode (const Proto *f, DumpState *D) {
+ DumpInt(f->sizecode, D);
+ DumpVector(f->code, f->sizecode, D);
+}
+
+
+static void DumpFunction(const Proto *f, TString *psource, DumpState *D);
+
+static void DumpConstants (const Proto *f, DumpState *D) {
+ int i;
+ int n = f->sizek;
+ DumpInt(n, D);
+ for (i = 0; i < n; i++) {
+ const TValue *o = &f->k[i];
+ DumpByte(ttype(o), D);
+ switch (ttype(o)) {
+ case LUA_TNIL:
+ break;
+ case LUA_TBOOLEAN:
+ DumpByte(bvalue(o), D);
+ break;
+ case LUA_TNUMFLT:
+ DumpNumber(fltvalue(o), D);
+ break;
+ case LUA_TNUMINT:
+ DumpInteger(ivalue(o), D);
+ break;
+ case LUA_TSHRSTR:
+ case LUA_TLNGSTR:
+ DumpString(tsvalue(o), D);
+ break;
+ default:
+ lua_assert(0);
+ }
+ }
+}
+
+
+static void DumpProtos (const Proto *f, DumpState *D) {
+ int i;
+ int n = f->sizep;
+ DumpInt(n, D);
+ for (i = 0; i < n; i++)
+ DumpFunction(f->p[i], f->source, D);
+}
+
+
+static void DumpUpvalues (const Proto *f, DumpState *D) {
+ int i, n = f->sizeupvalues;
+ DumpInt(n, D);
+ for (i = 0; i < n; i++) {
+ DumpByte(f->upvalues[i].instack, D);
+ DumpByte(f->upvalues[i].idx, D);
+ }
+}
+
+
+static void DumpDebug (const Proto *f, DumpState *D) {
+ int i, n;
+ n = (D->strip) ? 0 : f->sizelineinfo;
+ DumpInt(n, D);
+ DumpVector(f->lineinfo, n, D);
+ n = (D->strip) ? 0 : f->sizelocvars;
+ DumpInt(n, D);
+ for (i = 0; i < n; i++) {
+ DumpString(f->locvars[i].varname, D);
+ DumpInt(f->locvars[i].startpc, D);
+ DumpInt(f->locvars[i].endpc, D);
+ }
+ n = (D->strip) ? 0 : f->sizeupvalues;
+ DumpInt(n, D);
+ for (i = 0; i < n; i++)
+ DumpString(f->upvalues[i].name, D);
+}
+
+
+static void DumpFunction (const Proto *f, TString *psource, DumpState *D) {
+ if (D->strip || f->source == psource)
+ DumpString(NULL, D); /* no debug info or same source as its parent */
+ else
+ DumpString(f->source, D);
+ DumpInt(f->linedefined, D);
+ DumpInt(f->lastlinedefined, D);
+ DumpByte(f->numparams, D);
+ DumpByte(f->is_vararg, D);
+ DumpByte(f->maxstacksize, D);
+ DumpCode(f, D);
+ DumpConstants(f, D);
+ DumpUpvalues(f, D);
+ DumpProtos(f, D);
+ DumpDebug(f, D);
+}
+
+
+static void DumpHeader (DumpState *D) {
+ DumpLiteral(LUA_SIGNATURE, D);
+ DumpByte(LUAC_VERSION, D);
+ DumpByte(LUAC_FORMAT, D);
+ DumpLiteral(LUAC_DATA, D);
+ DumpByte(sizeof(int), D);
+ DumpByte(sizeof(size_t), D);
+ DumpByte(sizeof(Instruction), D);
+ DumpByte(sizeof(lua_Integer), D);
+ DumpByte(sizeof(lua_Number), D);
+ DumpInteger(LUAC_INT, D);
+ DumpNumber(LUAC_NUM, D);
+}
+
+
+/*
+** dump Lua function as precompiled chunk
+*/
+int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
+ int strip) {
+ DumpState D;
+ D.L = L;
+ D.writer = w;
+ D.data = data;
+ D.strip = strip;
+ D.status = 0;
+ DumpHeader(&D);
+ DumpByte(f->sizeupvalues, &D);
+ DumpFunction(f, NULL, &D);
+ return D.status;
+}
+
diff --git a/external/lua-5.3.3/src/lfunc.c b/external/lua-5.3.3/src/lfunc.c
new file mode 100644
index 0000000..67967da
--- /dev/null
+++ b/external/lua-5.3.3/src/lfunc.c
@@ -0,0 +1,151 @@
+/*
+** $Id: lfunc.c,v 2.45 2014/11/02 19:19:04 roberto Exp $
+** Auxiliary functions to manipulate prototypes and closures
+** See Copyright Notice in lua.h
+*/
+
+#define lfunc_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+
+#include "lua.h"
+
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+
+CClosure *luaF_newCclosure (lua_State *L, int n) {
+ GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n));
+ CClosure *c = gco2ccl(o);
+ c->nupvalues = cast_byte(n);
+ return c;
+}
+
+
+LClosure *luaF_newLclosure (lua_State *L, int n) {
+ GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n));
+ LClosure *c = gco2lcl(o);
+ c->p = NULL;
+ c->nupvalues = cast_byte(n);
+ while (n--) c->upvals[n] = NULL;
+ return c;
+}
+
+/*
+** fill a closure with new closed upvalues
+*/
+void luaF_initupvals (lua_State *L, LClosure *cl) {
+ int i;
+ for (i = 0; i < cl->nupvalues; i++) {
+ UpVal *uv = luaM_new(L, UpVal);
+ uv->refcount = 1;
+ uv->v = &uv->u.value; /* make it closed */
+ setnilvalue(uv->v);
+ cl->upvals[i] = uv;
+ }
+}
+
+
+UpVal *luaF_findupval (lua_State *L, StkId level) {
+ UpVal **pp = &L->openupval;
+ UpVal *p;
+ UpVal *uv;
+ lua_assert(isintwups(L) || L->openupval == NULL);
+ while (*pp != NULL && (p = *pp)->v >= level) {
+ lua_assert(upisopen(p));
+ if (p->v == level) /* found a corresponding upvalue? */
+ return p; /* return it */
+ pp = &p->u.open.next;
+ }
+ /* not found: create a new upvalue */
+ uv = luaM_new(L, UpVal);
+ uv->refcount = 0;
+ uv->u.open.next = *pp; /* link it to list of open upvalues */
+ uv->u.open.touched = 1;
+ *pp = uv;
+ uv->v = level; /* current value lives in the stack */
+ if (!isintwups(L)) { /* thread not in list of threads with upvalues? */
+ L->twups = G(L)->twups; /* link it to the list */
+ G(L)->twups = L;
+ }
+ return uv;
+}
+
+
+void luaF_close (lua_State *L, StkId level) {
+ UpVal *uv;
+ while (L->openupval != NULL && (uv = L->openupval)->v >= level) {
+ lua_assert(upisopen(uv));
+ L->openupval = uv->u.open.next; /* remove from 'open' list */
+ if (uv->refcount == 0) /* no references? */
+ luaM_free(L, uv); /* free upvalue */
+ else {
+ setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
+ uv->v = &uv->u.value; /* now current value lives here */
+ luaC_upvalbarrier(L, uv);
+ }
+ }
+}
+
+
+Proto *luaF_newproto (lua_State *L) {
+ GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto));
+ Proto *f = gco2p(o);
+ f->k = NULL;
+ f->sizek = 0;
+ f->p = NULL;
+ f->sizep = 0;
+ f->code = NULL;
+ f->cache = NULL;
+ f->sizecode = 0;
+ f->lineinfo = NULL;
+ f->sizelineinfo = 0;
+ f->upvalues = NULL;
+ f->sizeupvalues = 0;
+ f->numparams = 0;
+ f->is_vararg = 0;
+ f->maxstacksize = 0;
+ f->locvars = NULL;
+ f->sizelocvars = 0;
+ f->linedefined = 0;
+ f->lastlinedefined = 0;
+ f->source = NULL;
+ return f;
+}
+
+
+void luaF_freeproto (lua_State *L, Proto *f) {
+ luaM_freearray(L, f->code, f->sizecode);
+ luaM_freearray(L, f->p, f->sizep);
+ luaM_freearray(L, f->k, f->sizek);
+ luaM_freearray(L, f->lineinfo, f->sizelineinfo);
+ luaM_freearray(L, f->locvars, f->sizelocvars);
+ luaM_freearray(L, f->upvalues, f->sizeupvalues);
+ luaM_free(L, f);
+}
+
+
+/*
+** Look for n-th local variable at line 'line' in function 'func'.
+** Returns NULL if not found.
+*/
+const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
+ int i;
+ for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
+ if (pc < f->locvars[i].endpc) { /* is variable active? */
+ local_number--;
+ if (local_number == 0)
+ return getstr(f->locvars[i].varname);
+ }
+ }
+ return NULL; /* not found */
+}
+
diff --git a/external/lua-5.3.3/src/lfunc.h b/external/lua-5.3.3/src/lfunc.h
new file mode 100644
index 0000000..2eeb0d5
--- /dev/null
+++ b/external/lua-5.3.3/src/lfunc.h
@@ -0,0 +1,61 @@
+/*
+** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp $
+** Auxiliary functions to manipulate prototypes and closures
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lfunc_h
+#define lfunc_h
+
+
+#include "lobject.h"
+
+
+#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \
+ cast(int, sizeof(TValue)*((n)-1)))
+
+#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
+ cast(int, sizeof(TValue *)*((n)-1)))
+
+
+/* test whether thread is in 'twups' list */
+#define isintwups(L) (L->twups != L)
+
+
+/*
+** maximum number of upvalues in a closure (both C and Lua). (Value
+** must fit in a VM register.)
+*/
+#define MAXUPVAL 255
+
+
+/*
+** Upvalues for Lua closures
+*/
+struct UpVal {
+ TValue *v; /* points to stack or to its own value */
+ lu_mem refcount; /* reference counter */
+ union {
+ struct { /* (when open) */
+ UpVal *next; /* linked list */
+ int touched; /* mark to avoid cycles with dead threads */
+ } open;
+ TValue value; /* the value (when closed) */
+ } u;
+};
+
+#define upisopen(up) ((up)->v != &(up)->u.value)
+
+
+LUAI_FUNC Proto *luaF_newproto (lua_State *L);
+LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
+LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
+LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
+LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
+LUAI_FUNC void luaF_close (lua_State *L, StkId level);
+LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
+LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
+ int pc);
+
+
+#endif
diff --git a/external/lua-5.3.3/src/lgc.c b/external/lua-5.3.3/src/lgc.c
new file mode 100644
index 0000000..7c29fb0
--- /dev/null
+++ b/external/lua-5.3.3/src/lgc.c
@@ -0,0 +1,1176 @@
+/*
+** $Id: lgc.c,v 2.212 2016/03/31 19:02:03 roberto Exp $
+** Garbage Collector
+** See Copyright Notice in lua.h
+*/
+
+#define lgc_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <string.h>
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+
+
+/*
+** internal state for collector while inside the atomic phase. The
+** collector should never be in this state while running regular code.
+*/
+#define GCSinsideatomic (GCSpause + 1)
+
+/*
+** cost of sweeping one element (the size of a small object divided
+** by some adjust for the sweep speed)
+*/
+#define GCSWEEPCOST ((sizeof(TString) + 4) / 4)
+
+/* maximum number of elements to sweep in each single step */
+#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))
+
+/* cost of calling one finalizer */
+#define GCFINALIZECOST GCSWEEPCOST
+
+
+/*
+** macro to adjust 'stepmul': 'stepmul' is actually used like
+** 'stepmul / STEPMULADJ' (value chosen by tests)
+*/
+#define STEPMULADJ 200
+
+
+/*
+** macro to adjust 'pause': 'pause' is actually used like
+** 'pause / PAUSEADJ' (value chosen by tests)
+*/
+#define PAUSEADJ 100
+
+
+/*
+** 'makewhite' erases all color bits then sets only the current white
+** bit
+*/
+#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS))
+#define makewhite(g,x) \
+ (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g)))
+
+#define white2gray(x) resetbits(x->marked, WHITEBITS)
+#define black2gray(x) resetbit(x->marked, BLACKBIT)
+
+
+#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
+
+#define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n)))
+
+
+#define checkconsistency(obj) \
+ lua_longassert(!iscollectable(obj) || righttt(obj))
+
+
+#define markvalue(g,o) { checkconsistency(o); \
+ if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
+
+#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); }
+
+/*
+** mark an object that can be NULL (either because it is really optional,
+** or it was stripped as debug info, or inside an uncompleted structure)
+*/
+#define markobjectN(g,t) { if (t) markobject(g,t); }
+
+static void reallymarkobject (global_State *g, GCObject *o);
+
+
+/*
+** {======================================================
+** Generic functions
+** =======================================================
+*/
+
+
+/*
+** one after last element in a hash array
+*/
+#define gnodelast(h) gnode(h, cast(size_t, sizenode(h)))
+
+
+/*
+** link collectable object 'o' into list pointed by 'p'
+*/
+#define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o))
+
+
+/*
+** If key is not marked, mark its entry as dead. This allows key to be
+** collected, but keeps its entry in the table. A dead node is needed
+** when Lua looks up for a key (it may be part of a chain) and when
+** traversing a weak table (key might be removed from the table during
+** traversal). Other places never manipulate dead keys, because its
+** associated nil value is enough to signal that the entry is logically
+** empty.
+*/
+static void removeentry (Node *n) {
+ lua_assert(ttisnil(gval(n)));
+ if (valiswhite(gkey(n)))
+ setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */
+}
+
+
+/*
+** tells whether a key or value can be cleared from a weak
+** table. Non-collectable objects are never removed from weak
+** tables. Strings behave as 'values', so are never removed too. for
+** other objects: if really collected, cannot keep them; for objects
+** being finalized, keep them in keys, but not in values
+*/
+static int iscleared (global_State *g, const TValue *o) {
+ if (!iscollectable(o)) return 0;
+ else if (ttisstring(o)) {
+ markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */
+ return 0;
+ }
+ else return iswhite(gcvalue(o));
+}
+
+
+/*
+** barrier that moves collector forward, that is, mark the white object
+** being pointed by a black object. (If in sweep phase, clear the black
+** object to white [sweep it] to avoid other barrier calls for this
+** same object.)
+*/
+void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
+ global_State *g = G(L);
+ lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
+ if (keepinvariant(g)) /* must keep invariant? */
+ reallymarkobject(g, v); /* restore invariant */
+ else { /* sweep phase */
+ lua_assert(issweepphase(g));
+ makewhite(g, o); /* mark main obj. as white to avoid other barriers */
+ }
+}
+
+
+/*
+** barrier that moves collector backward, that is, mark the black object
+** pointing to a white object as gray again.
+*/
+void luaC_barrierback_ (lua_State *L, Table *t) {
+ global_State *g = G(L);
+ lua_assert(isblack(t) && !isdead(g, t));
+ black2gray(t); /* make table gray (again) */
+ linkgclist(t, g->grayagain);
+}
+
+
+/*
+** barrier for assignments to closed upvalues. Because upvalues are
+** shared among closures, it is impossible to know the color of all
+** closures pointing to it. So, we assume that the object being assigned
+** must be marked.
+*/
+void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) {
+ global_State *g = G(L);
+ GCObject *o = gcvalue(uv->v);
+ lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */
+ if (keepinvariant(g))
+ markobject(g, o);
+}
+
+
+void luaC_fix (lua_State *L, GCObject *o) {
+ global_State *g = G(L);
+ lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
+ white2gray(o); /* they will be gray forever */
+ g->allgc = o->next; /* remove object from 'allgc' list */
+ o->next = g->fixedgc; /* link it to 'fixedgc' list */
+ g->fixedgc = o;
+}
+
+
+/*
+** create a new collectable object (with given type and size) and link
+** it to 'allgc' list.
+*/
+GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
+ global_State *g = G(L);
+ GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
+ o->marked = luaC_white(g);
+ o->tt = tt;
+ o->next = g->allgc;
+ g->allgc = o;
+ return o;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** Mark functions
+** =======================================================
+*/
+
+
+/*
+** mark an object. Userdata, strings, and closed upvalues are visited
+** and turned black here. Other objects are marked gray and added
+** to appropriate list to be visited (and turned black) later. (Open
+** upvalues are already linked in 'headuv' list.)
+*/
+static void reallymarkobject (global_State *g, GCObject *o) {
+ reentry:
+ white2gray(o);
+ switch (o->tt) {
+ case LUA_TSHRSTR: {
+ gray2black(o);
+ g->GCmemtrav += sizelstring(gco2ts(o)->shrlen);
+ break;
+ }
+ case LUA_TLNGSTR: {
+ gray2black(o);
+ g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen);
+ break;
+ }
+ case LUA_TUSERDATA: {
+ TValue uvalue;
+ markobjectN(g, gco2u(o)->metatable); /* mark its metatable */
+ gray2black(o);
+ g->GCmemtrav += sizeudata(gco2u(o));
+ getuservalue(g->mainthread, gco2u(o), &uvalue);
+ if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */
+ o = gcvalue(&uvalue);
+ goto reentry;
+ }
+ break;
+ }
+ case LUA_TLCL: {
+ linkgclist(gco2lcl(o), g->gray);
+ break;
+ }
+ case LUA_TCCL: {
+ linkgclist(gco2ccl(o), g->gray);
+ break;
+ }
+ case LUA_TTABLE: {
+ linkgclist(gco2t(o), g->gray);
+ break;
+ }
+ case LUA_TTHREAD: {
+ linkgclist(gco2th(o), g->gray);
+ break;
+ }
+ case LUA_TPROTO: {
+ linkgclist(gco2p(o), g->gray);
+ break;
+ }
+ default: lua_assert(0); break;
+ }
+}
+
+
+/*
+** mark metamethods for basic types
+*/
+static void markmt (global_State *g) {
+ int i;
+ for (i=0; i < LUA_NUMTAGS; i++)
+ markobjectN(g, g->mt[i]);
+}
+
+
+/*
+** mark all objects in list of being-finalized
+*/
+static void markbeingfnz (global_State *g) {
+ GCObject *o;
+ for (o = g->tobefnz; o != NULL; o = o->next)
+ markobject(g, o);
+}
+
+
+/*
+** Mark all values stored in marked open upvalues from non-marked threads.
+** (Values from marked threads were already marked when traversing the
+** thread.) Remove from the list threads that no longer have upvalues and
+** not-marked threads.
+*/
+static void remarkupvals (global_State *g) {
+ lua_State *thread;
+ lua_State **p = &g->twups;
+ while ((thread = *p) != NULL) {
+ lua_assert(!isblack(thread)); /* threads are never black */
+ if (isgray(thread) && thread->openupval != NULL)
+ p = &thread->twups; /* keep marked thread with upvalues in the list */
+ else { /* thread is not marked or without upvalues */
+ UpVal *uv;
+ *p = thread->twups; /* remove thread from the list */
+ thread->twups = thread; /* mark that it is out of list */
+ for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) {
+ if (uv->u.open.touched) {
+ markvalue(g, uv->v); /* remark upvalue's value */
+ uv->u.open.touched = 0;
+ }
+ }
+ }
+ }
+}
+
+
+/*
+** mark root set and reset all gray lists, to start a new collection
+*/
+static void restartcollection (global_State *g) {
+ g->gray = g->grayagain = NULL;
+ g->weak = g->allweak = g->ephemeron = NULL;
+ markobject(g, g->mainthread);
+ markvalue(g, &g->l_registry);
+ markmt(g);
+ markbeingfnz(g); /* mark any finalizing object left from previous cycle */
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Traverse functions
+** =======================================================
+*/
+
+/*
+** Traverse a table with weak values and link it to proper list. During
+** propagate phase, keep it in 'grayagain' list, to be revisited in the
+** atomic phase. In the atomic phase, if table has any white value,
+** put it in 'weak' list, to be cleared.
+*/
+static void traverseweakvalue (global_State *g, Table *h) {
+ Node *n, *limit = gnodelast(h);
+ /* if there is array part, assume it may have white values (it is not
+ worth traversing it now just to check) */
+ int hasclears = (h->sizearray > 0);
+ for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */
+ checkdeadkey(n);
+ if (ttisnil(gval(n))) /* entry is empty? */
+ removeentry(n); /* remove it */
+ else {
+ lua_assert(!ttisnil(gkey(n)));
+ markvalue(g, gkey(n)); /* mark key */
+ if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */
+ hasclears = 1; /* table will have to be cleared */
+ }
+ }
+ if (g->gcstate == GCSpropagate)
+ linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */
+ else if (hasclears)
+ linkgclist(h, g->weak); /* has to be cleared later */
+}
+
+
+/*
+** Traverse an ephemeron table and link it to proper list. Returns true
+** iff any object was marked during this traversal (which implies that
+** convergence has to continue). During propagation phase, keep table
+** in 'grayagain' list, to be visited again in the atomic phase. In
+** the atomic phase, if table has any white->white entry, it has to
+** be revisited during ephemeron convergence (as that key may turn
+** black). Otherwise, if it has any white key, table has to be cleared
+** (in the atomic phase).
+*/
+static int traverseephemeron (global_State *g, Table *h) {
+ int marked = 0; /* true if an object is marked in this traversal */
+ int hasclears = 0; /* true if table has white keys */
+ int hasww = 0; /* true if table has entry "white-key -> white-value" */
+ Node *n, *limit = gnodelast(h);
+ unsigned int i;
+ /* traverse array part */
+ for (i = 0; i < h->sizearray; i++) {
+ if (valiswhite(&h->array[i])) {
+ marked = 1;
+ reallymarkobject(g, gcvalue(&h->array[i]));
+ }
+ }
+ /* traverse hash part */
+ for (n = gnode(h, 0); n < limit; n++) {
+ checkdeadkey(n);
+ if (ttisnil(gval(n))) /* entry is empty? */
+ removeentry(n); /* remove it */
+ else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */
+ hasclears = 1; /* table must be cleared */
+ if (valiswhite(gval(n))) /* value not marked yet? */
+ hasww = 1; /* white-white entry */
+ }
+ else if (valiswhite(gval(n))) { /* value not marked yet? */
+ marked = 1;
+ reallymarkobject(g, gcvalue(gval(n))); /* mark it now */
+ }
+ }
+ /* link table into proper list */
+ if (g->gcstate == GCSpropagate)
+ linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */
+ else if (hasww) /* table has white->white entries? */
+ linkgclist(h, g->ephemeron); /* have to propagate again */
+ else if (hasclears) /* table has white keys? */
+ linkgclist(h, g->allweak); /* may have to clean white keys */
+ return marked;
+}
+
+
+static void traversestrongtable (global_State *g, Table *h) {
+ Node *n, *limit = gnodelast(h);
+ unsigned int i;
+ for (i = 0; i < h->sizearray; i++) /* traverse array part */
+ markvalue(g, &h->array[i]);
+ for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */
+ checkdeadkey(n);
+ if (ttisnil(gval(n))) /* entry is empty? */
+ removeentry(n); /* remove it */
+ else {
+ lua_assert(!ttisnil(gkey(n)));
+ markvalue(g, gkey(n)); /* mark key */
+ markvalue(g, gval(n)); /* mark value */
+ }
+ }
+}
+
+
+static lu_mem traversetable (global_State *g, Table *h) {
+ const char *weakkey, *weakvalue;
+ const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
+ markobjectN(g, h->metatable);
+ if (mode && ttisstring(mode) && /* is there a weak mode? */
+ ((weakkey = strchr(svalue(mode), 'k')),
+ (weakvalue = strchr(svalue(mode), 'v')),
+ (weakkey || weakvalue))) { /* is really weak? */
+ black2gray(h); /* keep table gray */
+ if (!weakkey) /* strong keys? */
+ traverseweakvalue(g, h);
+ else if (!weakvalue) /* strong values? */
+ traverseephemeron(g, h);
+ else /* all weak */
+ linkgclist(h, g->allweak); /* nothing to traverse now */
+ }
+ else /* not weak */
+ traversestrongtable(g, h);
+ return sizeof(Table) + sizeof(TValue) * h->sizearray +
+ sizeof(Node) * cast(size_t, sizenode(h));
+}
+
+
+/*
+** Traverse a prototype. (While a prototype is being build, its
+** arrays can be larger than needed; the extra slots are filled with
+** NULL, so the use of 'markobjectN')
+*/
+static int traverseproto (global_State *g, Proto *f) {
+ int i;
+ if (f->cache && iswhite(f->cache))
+ f->cache = NULL; /* allow cache to be collected */
+ markobjectN(g, f->source);
+ for (i = 0; i < f->sizek; i++) /* mark literals */
+ markvalue(g, &f->k[i]);
+ for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
+ markobjectN(g, f->upvalues[i].name);
+ for (i = 0; i < f->sizep; i++) /* mark nested protos */
+ markobjectN(g, f->p[i]);
+ for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
+ markobjectN(g, f->locvars[i].varname);
+ return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
+ sizeof(Proto *) * f->sizep +
+ sizeof(TValue) * f->sizek +
+ sizeof(int) * f->sizelineinfo +
+ sizeof(LocVar) * f->sizelocvars +
+ sizeof(Upvaldesc) * f->sizeupvalues;
+}
+
+
+static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
+ int i;
+ for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
+ markvalue(g, &cl->upvalue[i]);
+ return sizeCclosure(cl->nupvalues);
+}
+
+/*
+** open upvalues point to values in a thread, so those values should
+** be marked when the thread is traversed except in the atomic phase
+** (because then the value cannot be changed by the thread and the
+** thread may not be traversed again)
+*/
+static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
+ int i;
+ markobjectN(g, cl->p); /* mark its prototype */
+ for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */
+ UpVal *uv = cl->upvals[i];
+ if (uv != NULL) {
+ if (upisopen(uv) && g->gcstate != GCSinsideatomic)
+ uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */
+ else
+ markvalue(g, uv->v);
+ }
+ }
+ return sizeLclosure(cl->nupvalues);
+}
+
+
+static lu_mem traversethread (global_State *g, lua_State *th) {
+ StkId o = th->stack;
+ if (o == NULL)
+ return 1; /* stack not completely built yet */
+ lua_assert(g->gcstate == GCSinsideatomic ||
+ th->openupval == NULL || isintwups(th));
+ for (; o < th->top; o++) /* mark live elements in the stack */
+ markvalue(g, o);
+ if (g->gcstate == GCSinsideatomic) { /* final traversal? */
+ StkId lim = th->stack + th->stacksize; /* real end of stack */
+ for (; o < lim; o++) /* clear not-marked stack slice */
+ setnilvalue(o);
+ /* 'remarkupvals' may have removed thread from 'twups' list */
+ if (!isintwups(th) && th->openupval != NULL) {
+ th->twups = g->twups; /* link it back to the list */
+ g->twups = th;
+ }
+ }
+ else if (g->gckind != KGC_EMERGENCY)
+ luaD_shrinkstack(th); /* do not change stack in emergency cycle */
+ return (sizeof(lua_State) + sizeof(TValue) * th->stacksize +
+ sizeof(CallInfo) * th->nci);
+}
+
+
+/*
+** traverse one gray object, turning it to black (except for threads,
+** which are always gray).
+*/
+static void propagatemark (global_State *g) {
+ lu_mem size;
+ GCObject *o = g->gray;
+ lua_assert(isgray(o));
+ gray2black(o);
+ switch (o->tt) {
+ case LUA_TTABLE: {
+ Table *h = gco2t(o);
+ g->gray = h->gclist; /* remove from 'gray' list */
+ size = traversetable(g, h);
+ break;
+ }
+ case LUA_TLCL: {
+ LClosure *cl = gco2lcl(o);
+ g->gray = cl->gclist; /* remove from 'gray' list */
+ size = traverseLclosure(g, cl);
+ break;
+ }
+ case LUA_TCCL: {
+ CClosure *cl = gco2ccl(o);
+ g->gray = cl->gclist; /* remove from 'gray' list */
+ size = traverseCclosure(g, cl);
+ break;
+ }
+ case LUA_TTHREAD: {
+ lua_State *th = gco2th(o);
+ g->gray = th->gclist; /* remove from 'gray' list */
+ linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
+ black2gray(o);
+ size = traversethread(g, th);
+ break;
+ }
+ case LUA_TPROTO: {
+ Proto *p = gco2p(o);
+ g->gray = p->gclist; /* remove from 'gray' list */
+ size = traverseproto(g, p);
+ break;
+ }
+ default: lua_assert(0); return;
+ }
+ g->GCmemtrav += size;
+}
+
+
+static void propagateall (global_State *g) {
+ while (g->gray) propagatemark(g);
+}
+
+
+static void convergeephemerons (global_State *g) {
+ int changed;
+ do {
+ GCObject *w;
+ GCObject *next = g->ephemeron; /* get ephemeron list */
+ g->ephemeron = NULL; /* tables may return to this list when traversed */
+ changed = 0;
+ while ((w = next) != NULL) {
+ next = gco2t(w)->gclist;
+ if (traverseephemeron(g, gco2t(w))) { /* traverse marked some value? */
+ propagateall(g); /* propagate changes */
+ changed = 1; /* will have to revisit all ephemeron tables */
+ }
+ }
+ } while (changed);
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Sweep Functions
+** =======================================================
+*/
+
+
+/*
+** clear entries with unmarked keys from all weaktables in list 'l' up
+** to element 'f'
+*/
+static void clearkeys (global_State *g, GCObject *l, GCObject *f) {
+ for (; l != f; l = gco2t(l)->gclist) {
+ Table *h = gco2t(l);
+ Node *n, *limit = gnodelast(h);
+ for (n = gnode(h, 0); n < limit; n++) {
+ if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) {
+ setnilvalue(gval(n)); /* remove value ... */
+ removeentry(n); /* and remove entry from table */
+ }
+ }
+ }
+}
+
+
+/*
+** clear entries with unmarked values from all weaktables in list 'l' up
+** to element 'f'
+*/
+static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
+ for (; l != f; l = gco2t(l)->gclist) {
+ Table *h = gco2t(l);
+ Node *n, *limit = gnodelast(h);
+ unsigned int i;
+ for (i = 0; i < h->sizearray; i++) {
+ TValue *o = &h->array[i];
+ if (iscleared(g, o)) /* value was collected? */
+ setnilvalue(o); /* remove value */
+ }
+ for (n = gnode(h, 0); n < limit; n++) {
+ if (!ttisnil(gval(n)) && iscleared(g, gval(n))) {
+ setnilvalue(gval(n)); /* remove value ... */
+ removeentry(n); /* and remove entry from table */
+ }
+ }
+ }
+}
+
+
+void luaC_upvdeccount (lua_State *L, UpVal *uv) {
+ lua_assert(uv->refcount > 0);
+ uv->refcount--;
+ if (uv->refcount == 0 && !upisopen(uv))
+ luaM_free(L, uv);
+}
+
+
+static void freeLclosure (lua_State *L, LClosure *cl) {
+ int i;
+ for (i = 0; i < cl->nupvalues; i++) {
+ UpVal *uv = cl->upvals[i];
+ if (uv)
+ luaC_upvdeccount(L, uv);
+ }
+ luaM_freemem(L, cl, sizeLclosure(cl->nupvalues));
+}
+
+
+static void freeobj (lua_State *L, GCObject *o) {
+ switch (o->tt) {
+ case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
+ case LUA_TLCL: {
+ freeLclosure(L, gco2lcl(o));
+ break;
+ }
+ case LUA_TCCL: {
+ luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
+ break;
+ }
+ case LUA_TTABLE: luaH_free(L, gco2t(o)); break;
+ case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;
+ case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
+ case LUA_TSHRSTR:
+ luaS_remove(L, gco2ts(o)); /* remove it from hash table */
+ luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen));
+ break;
+ case LUA_TLNGSTR: {
+ luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen));
+ break;
+ }
+ default: lua_assert(0);
+ }
+}
+
+
+#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM)
+static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);
+
+
+/*
+** sweep at most 'count' elements from a list of GCObjects erasing dead
+** objects, where a dead object is one marked with the old (non current)
+** white; change all non-dead objects back to white, preparing for next
+** collection cycle. Return where to continue the traversal or NULL if
+** list is finished.
+*/
+static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
+ global_State *g = G(L);
+ int ow = otherwhite(g);
+ int white = luaC_white(g); /* current white */
+ while (*p != NULL && count-- > 0) {
+ GCObject *curr = *p;
+ int marked = curr->marked;
+ if (isdeadm(ow, marked)) { /* is 'curr' dead? */
+ *p = curr->next; /* remove 'curr' from list */
+ freeobj(L, curr); /* erase 'curr' */
+ }
+ else { /* change mark to 'white' */
+ curr->marked = cast_byte((marked & maskcolors) | white);
+ p = &curr->next; /* go to next element */
+ }
+ }
+ return (*p == NULL) ? NULL : p;
+}
+
+
+/*
+** sweep a list until a live object (or end of list)
+*/
+static GCObject **sweeptolive (lua_State *L, GCObject **p) {
+ GCObject **old = p;
+ do {
+ p = sweeplist(L, p, 1);
+ } while (p == old);
+ return p;
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Finalization
+** =======================================================
+*/
+
+/*
+** If possible, shrink string table
+*/
+static void checkSizes (lua_State *L, global_State *g) {
+ if (g->gckind != KGC_EMERGENCY) {
+ l_mem olddebt = g->GCdebt;
+ if (g->strt.nuse < g->strt.size / 4) /* string table too big? */
+ luaS_resize(L, g->strt.size / 2); /* shrink it a little */
+ g->GCestimate += g->GCdebt - olddebt; /* update estimate */
+ }
+}
+
+
+static GCObject *udata2finalize (global_State *g) {
+ GCObject *o = g->tobefnz; /* get first element */
+ lua_assert(tofinalize(o));
+ g->tobefnz = o->next; /* remove it from 'tobefnz' list */
+ o->next = g->allgc; /* return it to 'allgc' list */
+ g->allgc = o;
+ resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */
+ if (issweepphase(g))
+ makewhite(g, o); /* "sweep" object */
+ return o;
+}
+
+
+static void dothecall (lua_State *L, void *ud) {
+ UNUSED(ud);
+ luaD_callnoyield(L, L->top - 2, 0);
+}
+
+
+static void GCTM (lua_State *L, int propagateerrors) {
+ global_State *g = G(L);
+ const TValue *tm;
+ TValue v;
+ setgcovalue(L, &v, udata2finalize(g));
+ tm = luaT_gettmbyobj(L, &v, TM_GC);
+ if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */
+ int status;
+ lu_byte oldah = L->allowhook;
+ int running = g->gcrunning;
+ L->allowhook = 0; /* stop debug hooks during GC metamethod */
+ g->gcrunning = 0; /* avoid GC steps */
+ setobj2s(L, L->top, tm); /* push finalizer... */
+ setobj2s(L, L->top + 1, &v); /* ... and its argument */
+ L->top += 2; /* and (next line) call the finalizer */
+ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
+ L->allowhook = oldah; /* restore hooks */
+ g->gcrunning = running; /* restore state */
+ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */
+ if (status == LUA_ERRRUN) { /* is there an error object? */
+ const char *msg = (ttisstring(L->top - 1))
+ ? svalue(L->top - 1)
+ : "no message";
+ luaO_pushfstring(L, "error in __gc metamethod (%s)", msg);
+ status = LUA_ERRGCMM; /* error in __gc metamethod */
+ }
+ luaD_throw(L, status); /* re-throw error */
+ }
+ }
+}
+
+
+/*
+** call a few (up to 'g->gcfinnum') finalizers
+*/
+static int runafewfinalizers (lua_State *L) {
+ global_State *g = G(L);
+ unsigned int i;
+ lua_assert(!g->tobefnz || g->gcfinnum > 0);
+ for (i = 0; g->tobefnz && i < g->gcfinnum; i++)
+ GCTM(L, 1); /* call one finalizer */
+ g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */
+ : g->gcfinnum * 2; /* else call a few more next time */
+ return i;
+}
+
+
+/*
+** call all pending finalizers
+*/
+static void callallpendingfinalizers (lua_State *L) {
+ global_State *g = G(L);
+ while (g->tobefnz)
+ GCTM(L, 0);
+}
+
+
+/*
+** find last 'next' field in list 'p' list (to add elements in its end)
+*/
+static GCObject **findlast (GCObject **p) {
+ while (*p != NULL)
+ p = &(*p)->next;
+ return p;
+}
+
+
+/*
+** move all unreachable objects (or 'all' objects) that need
+** finalization from list 'finobj' to list 'tobefnz' (to be finalized)
+*/
+static void separatetobefnz (global_State *g, int all) {
+ GCObject *curr;
+ GCObject **p = &g->finobj;
+ GCObject **lastnext = findlast(&g->tobefnz);
+ while ((curr = *p) != NULL) { /* traverse all finalizable objects */
+ lua_assert(tofinalize(curr));
+ if (!(iswhite(curr) || all)) /* not being collected? */
+ p = &curr->next; /* don't bother with it */
+ else {
+ *p = curr->next; /* remove 'curr' from 'finobj' list */
+ curr->next = *lastnext; /* link at the end of 'tobefnz' list */
+ *lastnext = curr;
+ lastnext = &curr->next;
+ }
+ }
+}
+
+
+/*
+** if object 'o' has a finalizer, remove it from 'allgc' list (must
+** search the list to find it) and link it in 'finobj' list.
+*/
+void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
+ global_State *g = G(L);
+ if (tofinalize(o) || /* obj. is already marked... */
+ gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */
+ return; /* nothing to be done */
+ else { /* move 'o' to 'finobj' list */
+ GCObject **p;
+ if (issweepphase(g)) {
+ makewhite(g, o); /* "sweep" object 'o' */
+ if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
+ g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
+ }
+ /* search for pointer pointing to 'o' */
+ for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
+ *p = o->next; /* remove 'o' from 'allgc' list */
+ o->next = g->finobj; /* link it in 'finobj' list */
+ g->finobj = o;
+ l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */
+ }
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** GC control
+** =======================================================
+*/
+
+
+/*
+** Set a reasonable "time" to wait before starting a new GC cycle; cycle
+** will start when memory use hits threshold. (Division by 'estimate'
+** should be OK: it cannot be zero (because Lua cannot even start with
+** less than PAUSEADJ bytes).
+*/
+static void setpause (global_State *g) {
+ l_mem threshold, debt;
+ l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
+ lua_assert(estimate > 0);
+ threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */
+ ? estimate * g->gcpause /* no overflow */
+ : MAX_LMEM; /* overflow; truncate to maximum */
+ debt = gettotalbytes(g) - threshold;
+ luaE_setdebt(g, debt);
+}
+
+
+/*
+** Enter first sweep phase.
+** The call to 'sweeplist' tries to make pointer point to an object
+** inside the list (instead of to the header), so that the real sweep do
+** not need to skip objects created between "now" and the start of the
+** real sweep.
+*/
+static void entersweep (lua_State *L) {
+ global_State *g = G(L);
+ g->gcstate = GCSswpallgc;
+ lua_assert(g->sweepgc == NULL);
+ g->sweepgc = sweeplist(L, &g->allgc, 1);
+}
+
+
+void luaC_freeallobjects (lua_State *L) {
+ global_State *g = G(L);
+ separatetobefnz(g, 1); /* separate all objects with finalizers */
+ lua_assert(g->finobj == NULL);
+ callallpendingfinalizers(L);
+ lua_assert(g->tobefnz == NULL);
+ g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
+ g->gckind = KGC_NORMAL;
+ sweepwholelist(L, &g->finobj);
+ sweepwholelist(L, &g->allgc);
+ sweepwholelist(L, &g->fixedgc); /* collect fixed objects */
+ lua_assert(g->strt.nuse == 0);
+}
+
+
+static l_mem atomic (lua_State *L) {
+ global_State *g = G(L);
+ l_mem work;
+ GCObject *origweak, *origall;
+ GCObject *grayagain = g->grayagain; /* save original list */
+ lua_assert(g->ephemeron == NULL && g->weak == NULL);
+ lua_assert(!iswhite(g->mainthread));
+ g->gcstate = GCSinsideatomic;
+ g->GCmemtrav = 0; /* start counting work */
+ markobject(g, L); /* mark running thread */
+ /* registry and global metatables may be changed by API */
+ markvalue(g, &g->l_registry);
+ markmt(g); /* mark global metatables */
+ /* remark occasional upvalues of (maybe) dead threads */
+ remarkupvals(g);
+ propagateall(g); /* propagate changes */
+ work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */
+ g->gray = grayagain;
+ propagateall(g); /* traverse 'grayagain' list */
+ g->GCmemtrav = 0; /* restart counting */
+ convergeephemerons(g);
+ /* at this point, all strongly accessible objects are marked. */
+ /* Clear values from weak tables, before checking finalizers */
+ clearvalues(g, g->weak, NULL);
+ clearvalues(g, g->allweak, NULL);
+ origweak = g->weak; origall = g->allweak;
+ work += g->GCmemtrav; /* stop counting (objects being finalized) */
+ separatetobefnz(g, 0); /* separate objects to be finalized */
+ g->gcfinnum = 1; /* there may be objects to be finalized */
+ markbeingfnz(g); /* mark objects that will be finalized */
+ propagateall(g); /* remark, to propagate 'resurrection' */
+ g->GCmemtrav = 0; /* restart counting */
+ convergeephemerons(g);
+ /* at this point, all resurrected objects are marked. */
+ /* remove dead objects from weak tables */
+ clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */
+ clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */
+ /* clear values from resurrected weak tables */
+ clearvalues(g, g->weak, origweak);
+ clearvalues(g, g->allweak, origall);
+ luaS_clearcache(g);
+ g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
+ work += g->GCmemtrav; /* complete counting */
+ return work; /* estimate of memory marked by 'atomic' */
+}
+
+
+static lu_mem sweepstep (lua_State *L, global_State *g,
+ int nextstate, GCObject **nextlist) {
+ if (g->sweepgc) {
+ l_mem olddebt = g->GCdebt;
+ g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
+ g->GCestimate += g->GCdebt - olddebt; /* update estimate */
+ if (g->sweepgc) /* is there still something to sweep? */
+ return (GCSWEEPMAX * GCSWEEPCOST);
+ }
+ /* else enter next state */
+ g->gcstate = nextstate;
+ g->sweepgc = nextlist;
+ return 0;
+}
+
+
+static lu_mem singlestep (lua_State *L) {
+ global_State *g = G(L);
+ switch (g->gcstate) {
+ case GCSpause: {
+ g->GCmemtrav = g->strt.size * sizeof(GCObject*);
+ restartcollection(g);
+ g->gcstate = GCSpropagate;
+ return g->GCmemtrav;
+ }
+ case GCSpropagate: {
+ g->GCmemtrav = 0;
+ lua_assert(g->gray);
+ propagatemark(g);
+ if (g->gray == NULL) /* no more gray objects? */
+ g->gcstate = GCSatomic; /* finish propagate phase */
+ return g->GCmemtrav; /* memory traversed in this step */
+ }
+ case GCSatomic: {
+ lu_mem work;
+ propagateall(g); /* make sure gray list is empty */
+ work = atomic(L); /* work is what was traversed by 'atomic' */
+ entersweep(L);
+ g->GCestimate = gettotalbytes(g); /* first estimate */;
+ return work;
+ }
+ case GCSswpallgc: { /* sweep "regular" objects */
+ return sweepstep(L, g, GCSswpfinobj, &g->finobj);
+ }
+ case GCSswpfinobj: { /* sweep objects with finalizers */
+ return sweepstep(L, g, GCSswptobefnz, &g->tobefnz);
+ }
+ case GCSswptobefnz: { /* sweep objects to be finalized */
+ return sweepstep(L, g, GCSswpend, NULL);
+ }
+ case GCSswpend: { /* finish sweeps */
+ makewhite(g, g->mainthread); /* sweep main thread */
+ checkSizes(L, g);
+ g->gcstate = GCScallfin;
+ return 0;
+ }
+ case GCScallfin: { /* call remaining finalizers */
+ if (g->tobefnz && g->gckind != KGC_EMERGENCY) {
+ int n = runafewfinalizers(L);
+ return (n * GCFINALIZECOST);
+ }
+ else { /* emergency mode or no more finalizers */
+ g->gcstate = GCSpause; /* finish collection */
+ return 0;
+ }
+ }
+ default: lua_assert(0); return 0;
+ }
+}
+
+
+/*
+** advances the garbage collector until it reaches a state allowed
+** by 'statemask'
+*/
+void luaC_runtilstate (lua_State *L, int statesmask) {
+ global_State *g = G(L);
+ while (!testbit(statesmask, g->gcstate))
+ singlestep(L);
+}
+
+
+/*
+** get GC debt and convert it from Kb to 'work units' (avoid zero debt
+** and overflows)
+*/
+static l_mem getdebt (global_State *g) {
+ l_mem debt = g->GCdebt;
+ int stepmul = g->gcstepmul;
+ if (debt <= 0) return 0; /* minimal debt */
+ else {
+ debt = (debt / STEPMULADJ) + 1;
+ debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
+ return debt;
+ }
+}
+
+/*
+** performs a basic GC step when collector is running
+*/
+void luaC_step (lua_State *L) {
+ global_State *g = G(L);
+ l_mem debt = getdebt(g); /* GC deficit (be paid now) */
+ if (!g->gcrunning) { /* not running? */
+ luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */
+ return;
+ }
+ do { /* repeat until pause or enough "credit" (negative debt) */
+ lu_mem work = singlestep(L); /* perform one single step */
+ debt -= work;
+ } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
+ if (g->gcstate == GCSpause)
+ setpause(g); /* pause until next cycle */
+ else {
+ debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */
+ luaE_setdebt(g, debt);
+ runafewfinalizers(L);
+ }
+}
+
+
+/*
+** Performs a full GC cycle; if 'isemergency', set a flag to avoid
+** some operations which could change the interpreter state in some
+** unexpected ways (running finalizers and shrinking some structures).
+** Before running the collection, check 'keepinvariant'; if it is true,
+** there may be some objects marked as black, so the collector has
+** to sweep all objects to turn them back to white (as white has not
+** changed, nothing will be collected).
+*/
+void luaC_fullgc (lua_State *L, int isemergency) {
+ global_State *g = G(L);
+ lua_assert(g->gckind == KGC_NORMAL);
+ if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */
+ if (keepinvariant(g)) { /* black objects? */
+ entersweep(L); /* sweep everything to turn them back to white */
+ }
+ /* finish any pending sweep phase to start a new cycle */
+ luaC_runtilstate(L, bitmask(GCSpause));
+ luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */
+ luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */
+ /* estimate must be correct after a full GC cycle */
+ lua_assert(g->GCestimate == gettotalbytes(g));
+ luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
+ g->gckind = KGC_NORMAL;
+ setpause(g);
+}
+
+/* }====================================================== */
+
+
diff --git a/external/lua-5.3.3/src/lgc.h b/external/lua-5.3.3/src/lgc.h
new file mode 100644
index 0000000..aed3e18
--- /dev/null
+++ b/external/lua-5.3.3/src/lgc.h
@@ -0,0 +1,147 @@
+/*
+** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $
+** Garbage Collector
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lgc_h
+#define lgc_h
+
+
+#include "lobject.h"
+#include "lstate.h"
+
+/*
+** Collectable objects may have one of three colors: white, which
+** means the object is not marked; gray, which means the
+** object is marked, but its references may be not marked; and
+** black, which means that the object and all its references are marked.
+** The main invariant of the garbage collector, while marking objects,
+** is that a black object can never point to a white one. Moreover,
+** any gray object must be in a "gray list" (gray, grayagain, weak,
+** allweak, ephemeron) so that it can be visited again before finishing
+** the collection cycle. These lists have no meaning when the invariant
+** is not being enforced (e.g., sweep phase).
+*/
+
+
+
+/* how much to allocate before next GC step */
+#if !defined(GCSTEPSIZE)
+/* ~100 small strings */
+#define GCSTEPSIZE (cast_int(100 * sizeof(TString)))
+#endif
+
+
+/*
+** Possible states of the Garbage Collector
+*/
+#define GCSpropagate 0
+#define GCSatomic 1
+#define GCSswpallgc 2
+#define GCSswpfinobj 3
+#define GCSswptobefnz 4
+#define GCSswpend 5
+#define GCScallfin 6
+#define GCSpause 7
+
+
+#define issweepphase(g) \
+ (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend)
+
+
+/*
+** macro to tell when main invariant (white objects cannot point to black
+** ones) must be kept. During a collection, the sweep
+** phase may break the invariant, as objects turned white may point to
+** still-black objects. The invariant is restored when sweep ends and
+** all objects are white again.
+*/
+
+#define keepinvariant(g) ((g)->gcstate <= GCSatomic)
+
+
+/*
+** some useful bit tricks
+*/
+#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m)))
+#define setbits(x,m) ((x) |= (m))
+#define testbits(x,m) ((x) & (m))
+#define bitmask(b) (1<<(b))
+#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2))
+#define l_setbit(x,b) setbits(x, bitmask(b))
+#define resetbit(x,b) resetbits(x, bitmask(b))
+#define testbit(x,b) testbits(x, bitmask(b))
+
+
+/* Layout for bit use in 'marked' field: */
+#define WHITE0BIT 0 /* object is white (type 0) */
+#define WHITE1BIT 1 /* object is white (type 1) */
+#define BLACKBIT 2 /* object is black */
+#define FINALIZEDBIT 3 /* object has been marked for finalization */
+/* bit 7 is currently used by tests (luaL_checkmemory) */
+
+#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
+
+
+#define iswhite(x) testbits((x)->marked, WHITEBITS)
+#define isblack(x) testbit((x)->marked, BLACKBIT)
+#define isgray(x) /* neither white nor black */ \
+ (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT)))
+
+#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT)
+
+#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS)
+#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
+#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
+
+#define changewhite(x) ((x)->marked ^= WHITEBITS)
+#define gray2black(x) l_setbit((x)->marked, BLACKBIT)
+
+#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
+
+
+/*
+** Does one step of collection when debt becomes positive. 'pre'/'pos'
+** allows some adjustments to be done only when needed. macro
+** 'condchangemem' is used only for heavy tests (forcing a full
+** GC cycle on every opportunity)
+*/
+#define luaC_condGC(L,pre,pos) \
+ { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \
+ condchangemem(L,pre,pos); }
+
+/* more often than not, 'pre'/'pos' are empty */
+#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
+
+
+#define luaC_barrier(L,p,v) ( \
+ (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
+ luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
+
+#define luaC_barrierback(L,p,v) ( \
+ (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
+ luaC_barrierback_(L,p) : cast_void(0))
+
+#define luaC_objbarrier(L,p,o) ( \
+ (isblack(p) && iswhite(o)) ? \
+ luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
+
+#define luaC_upvalbarrier(L,uv) ( \
+ (iscollectable((uv)->v) && !upisopen(uv)) ? \
+ luaC_upvalbarrier_(L,uv) : cast_void(0))
+
+LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
+LUAI_FUNC void luaC_freeallobjects (lua_State *L);
+LUAI_FUNC void luaC_step (lua_State *L);
+LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
+LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
+LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
+LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
+LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o);
+LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv);
+LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
+LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv);
+
+
+#endif
diff --git a/external/lua-5.3.3/src/linit.c b/external/lua-5.3.3/src/linit.c
new file mode 100644
index 0000000..8ce94cc
--- /dev/null
+++ b/external/lua-5.3.3/src/linit.c
@@ -0,0 +1,68 @@
+/*
+** $Id: linit.c,v 1.38 2015/01/05 13:48:33 roberto Exp $
+** Initialization of libraries for lua.c and other clients
+** See Copyright Notice in lua.h
+*/
+
+
+#define linit_c
+#define LUA_LIB
+
+/*
+** If you embed Lua in your program and need to open the standard
+** libraries, call luaL_openlibs in your program. If you need a
+** different set of libraries, copy this file to your project and edit
+** it to suit your needs.
+**
+** You can also *preload* libraries, so that a later 'require' can
+** open the library, which is already linked to the application.
+** For that, do the following code:
+**
+** luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
+** lua_pushcfunction(L, luaopen_modname);
+** lua_setfield(L, -2, modname);
+** lua_pop(L, 1); // remove _PRELOAD table
+*/
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+
+#include "lua.h"
+
+#include "lualib.h"
+#include "lauxlib.h"
+
+
+/*
+** these libs are loaded by lua.c and are readily available to any Lua
+** program
+*/
+static const luaL_Reg loadedlibs[] = {
+ {"_G", luaopen_base},
+ {LUA_LOADLIBNAME, luaopen_package},
+ {LUA_COLIBNAME, luaopen_coroutine},
+ {LUA_TABLIBNAME, luaopen_table},
+ {LUA_IOLIBNAME, luaopen_io},
+ {LUA_OSLIBNAME, luaopen_os},
+ {LUA_STRLIBNAME, luaopen_string},
+ {LUA_MATHLIBNAME, luaopen_math},
+ {LUA_UTF8LIBNAME, luaopen_utf8},
+ {LUA_DBLIBNAME, luaopen_debug},
+#if defined(LUA_COMPAT_BITLIB)
+ {LUA_BITLIBNAME, luaopen_bit32},
+#endif
+ {NULL, NULL}
+};
+
+
+LUALIB_API void luaL_openlibs (lua_State *L) {
+ const luaL_Reg *lib;
+ /* "require" functions from 'loadedlibs' and set results to global table */
+ for (lib = loadedlibs; lib->func; lib++) {
+ luaL_requiref(L, lib->name, lib->func, 1);
+ lua_pop(L, 1); /* remove lib */
+ }
+}
+
diff --git a/external/lua-5.3.3/src/liolib.c b/external/lua-5.3.3/src/liolib.c
new file mode 100644
index 0000000..aa78e59
--- /dev/null
+++ b/external/lua-5.3.3/src/liolib.c
@@ -0,0 +1,768 @@
+/*
+** $Id: liolib.c,v 2.149 2016/05/02 14:03:19 roberto Exp $
+** Standard I/O (and system) library
+** See Copyright Notice in lua.h
+*/
+
+#define liolib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include <ctype.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+
+
+/*
+** Change this macro to accept other modes for 'fopen' besides
+** the standard ones.
+*/
+#if !defined(l_checkmode)
+
+/* accepted extensions to 'mode' in 'fopen' */
+#if !defined(L_MODEEXT)
+#define L_MODEEXT "b"
+#endif
+
+/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */
+#define l_checkmode(mode) \
+ (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
+ (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ \
+ (strspn(mode, L_MODEEXT) == strlen(mode)))
+
+#endif
+
+/*
+** {======================================================
+** l_popen spawns a new process connected to the current
+** one through the file streams.
+** =======================================================
+*/
+
+#if !defined(l_popen) /* { */
+
+#if defined(LUA_USE_POSIX) /* { */
+
+#define l_popen(L,c,m) (fflush(NULL), popen(c,m))
+#define l_pclose(L,file) (pclose(file))
+
+#elif defined(LUA_USE_WINDOWS) /* }{ */
+
+#define l_popen(L,c,m) (_popen(c,m))
+#define l_pclose(L,file) (_pclose(file))
+
+#else /* }{ */
+
+/* ISO C definitions */
+#define l_popen(L,c,m) \
+ ((void)((void)c, m), \
+ luaL_error(L, "'popen' not supported"), \
+ (FILE*)0)
+#define l_pclose(L,file) ((void)L, (void)file, -1)
+
+#endif /* } */
+
+#endif /* } */
+
+/* }====================================================== */
+
+
+#if !defined(l_getc) /* { */
+
+#if defined(LUA_USE_POSIX)
+#define l_getc(f) getc_unlocked(f)
+#define l_lockfile(f) flockfile(f)
+#define l_unlockfile(f) funlockfile(f)
+#else
+#define l_getc(f) getc(f)
+#define l_lockfile(f) ((void)0)
+#define l_unlockfile(f) ((void)0)
+#endif
+
+#endif /* } */
+
+
+/*
+** {======================================================
+** l_fseek: configuration for longer offsets
+** =======================================================
+*/
+
+#if !defined(l_fseek) /* { */
+
+#if defined(LUA_USE_POSIX) /* { */
+
+#include <sys/types.h>
+
+#define l_fseek(f,o,w) fseeko(f,o,w)
+#define l_ftell(f) ftello(f)
+#define l_seeknum off_t
+
+#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \
+ && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */
+
+/* Windows (but not DDK) and Visual C++ 2005 or higher */
+#define l_fseek(f,o,w) _fseeki64(f,o,w)
+#define l_ftell(f) _ftelli64(f)
+#define l_seeknum __int64
+
+#else /* }{ */
+
+/* ISO C definitions */
+#define l_fseek(f,o,w) fseek(f,o,w)
+#define l_ftell(f) ftell(f)
+#define l_seeknum long
+
+#endif /* } */
+
+#endif /* } */
+
+/* }====================================================== */
+
+
+#define IO_PREFIX "_IO_"
+#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1)
+#define IO_INPUT (IO_PREFIX "input")
+#define IO_OUTPUT (IO_PREFIX "output")
+
+
+typedef luaL_Stream LStream;
+
+
+#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE))
+
+#define isclosed(p) ((p)->closef == NULL)
+
+
+static int io_type (lua_State *L) {
+ LStream *p;
+ luaL_checkany(L, 1);
+ p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE);
+ if (p == NULL)
+ lua_pushnil(L); /* not a file */
+ else if (isclosed(p))
+ lua_pushliteral(L, "closed file");
+ else
+ lua_pushliteral(L, "file");
+ return 1;
+}
+
+
+static int f_tostring (lua_State *L) {
+ LStream *p = tolstream(L);
+ if (isclosed(p))
+ lua_pushliteral(L, "file (closed)");
+ else
+ lua_pushfstring(L, "file (%p)", p->f);
+ return 1;
+}
+
+
+static FILE *tofile (lua_State *L) {
+ LStream *p = tolstream(L);
+ if (isclosed(p))
+ luaL_error(L, "attempt to use a closed file");
+ lua_assert(p->f);
+ return p->f;
+}
+
+
+/*
+** When creating file handles, always creates a 'closed' file handle
+** before opening the actual file; so, if there is a memory error, the
+** handle is in a consistent state.
+*/
+static LStream *newprefile (lua_State *L) {
+ LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));
+ p->closef = NULL; /* mark file handle as 'closed' */
+ luaL_setmetatable(L, LUA_FILEHANDLE);
+ return p;
+}
+
+
+/*
+** Calls the 'close' function from a file handle. The 'volatile' avoids
+** a bug in some versions of the Clang compiler (e.g., clang 3.0 for
+** 32 bits).
+*/
+static int aux_close (lua_State *L) {
+ LStream *p = tolstream(L);
+ volatile lua_CFunction cf = p->closef;
+ p->closef = NULL; /* mark stream as closed */
+ return (*cf)(L); /* close it */
+}
+
+
+static int io_close (lua_State *L) {
+ if (lua_isnone(L, 1)) /* no argument? */
+ lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */
+ tofile(L); /* make sure argument is an open stream */
+ return aux_close(L);
+}
+
+
+static int f_gc (lua_State *L) {
+ LStream *p = tolstream(L);
+ if (!isclosed(p) && p->f != NULL)
+ aux_close(L); /* ignore closed and incompletely open files */
+ return 0;
+}
+
+
+/*
+** function to close regular files
+*/
+static int io_fclose (lua_State *L) {
+ LStream *p = tolstream(L);
+ int res = fclose(p->f);
+ return luaL_fileresult(L, (res == 0), NULL);
+}
+
+
+static LStream *newfile (lua_State *L) {
+ LStream *p = newprefile(L);
+ p->f = NULL;
+ p->closef = &io_fclose;
+ return p;
+}
+
+
+static void opencheck (lua_State *L, const char *fname, const char *mode) {
+ LStream *p = newfile(L);
+ p->f = fopen(fname, mode);
+ if (p->f == NULL)
+ luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno));
+}
+
+
+static int io_open (lua_State *L) {
+ const char *filename = luaL_checkstring(L, 1);
+ const char *mode = luaL_optstring(L, 2, "r");
+ LStream *p = newfile(L);
+ const char *md = mode; /* to traverse/check mode */
+ luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
+ p->f = fopen(filename, mode);
+ return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
+}
+
+
+/*
+** function to close 'popen' files
+*/
+static int io_pclose (lua_State *L) {
+ LStream *p = tolstream(L);
+ return luaL_execresult(L, l_pclose(L, p->f));
+}
+
+
+static int io_popen (lua_State *L) {
+ const char *filename = luaL_checkstring(L, 1);
+ const char *mode = luaL_optstring(L, 2, "r");
+ LStream *p = newprefile(L);
+ p->f = l_popen(L, filename, mode);
+ p->closef = &io_pclose;
+ return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
+}
+
+
+static int io_tmpfile (lua_State *L) {
+ LStream *p = newfile(L);
+ p->f = tmpfile();
+ return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
+}
+
+
+static FILE *getiofile (lua_State *L, const char *findex) {
+ LStream *p;
+ lua_getfield(L, LUA_REGISTRYINDEX, findex);
+ p = (LStream *)lua_touserdata(L, -1);
+ if (isclosed(p))
+ luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN);
+ return p->f;
+}
+
+
+static int g_iofile (lua_State *L, const char *f, const char *mode) {
+ if (!lua_isnoneornil(L, 1)) {
+ const char *filename = lua_tostring(L, 1);
+ if (filename)
+ opencheck(L, filename, mode);
+ else {
+ tofile(L); /* check that it's a valid file handle */
+ lua_pushvalue(L, 1);
+ }
+ lua_setfield(L, LUA_REGISTRYINDEX, f);
+ }
+ /* return current value */
+ lua_getfield(L, LUA_REGISTRYINDEX, f);
+ return 1;
+}
+
+
+static int io_input (lua_State *L) {
+ return g_iofile(L, IO_INPUT, "r");
+}
+
+
+static int io_output (lua_State *L) {
+ return g_iofile(L, IO_OUTPUT, "w");
+}
+
+
+static int io_readline (lua_State *L);
+
+
+/*
+** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit
+** in the limit for upvalues of a closure)
+*/
+#define MAXARGLINE 250
+
+static void aux_lines (lua_State *L, int toclose) {
+ int n = lua_gettop(L) - 1; /* number of arguments to read */
+ luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments");
+ lua_pushinteger(L, n); /* number of arguments to read */
+ lua_pushboolean(L, toclose); /* close/not close file when finished */
+ lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */
+ lua_pushcclosure(L, io_readline, 3 + n);
+}
+
+
+static int f_lines (lua_State *L) {
+ tofile(L); /* check that it's a valid file handle */
+ aux_lines(L, 0);
+ return 1;
+}
+
+
+static int io_lines (lua_State *L) {
+ int toclose;
+ if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */
+ if (lua_isnil(L, 1)) { /* no file name? */
+ lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */
+ lua_replace(L, 1); /* put it at index 1 */
+ tofile(L); /* check that it's a valid file handle */
+ toclose = 0; /* do not close it after iteration */
+ }
+ else { /* open a new file */
+ const char *filename = luaL_checkstring(L, 1);
+ opencheck(L, filename, "r");
+ lua_replace(L, 1); /* put file at index 1 */
+ toclose = 1; /* close it after iteration */
+ }
+ aux_lines(L, toclose);
+ return 1;
+}
+
+
+/*
+** {======================================================
+** READ
+** =======================================================
+*/
+
+
+/* maximum length of a numeral */
+#if !defined (L_MAXLENNUM)
+#define L_MAXLENNUM 200
+#endif
+
+
+/* auxiliary structure used by 'read_number' */
+typedef struct {
+ FILE *f; /* file being read */
+ int c; /* current character (look ahead) */
+ int n; /* number of elements in buffer 'buff' */
+ char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */
+} RN;
+
+
+/*
+** Add current char to buffer (if not out of space) and read next one
+*/
+static int nextc (RN *rn) {
+ if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */
+ rn->buff[0] = '\0'; /* invalidate result */
+ return 0; /* fail */
+ }
+ else {
+ rn->buff[rn->n++] = rn->c; /* save current char */
+ rn->c = l_getc(rn->f); /* read next one */
+ return 1;
+ }
+}
+
+
+/*
+** Accept current char if it is in 'set' (of size 2)
+*/
+static int test2 (RN *rn, const char *set) {
+ if (rn->c == set[0] || rn->c == set[1])
+ return nextc(rn);
+ else return 0;
+}
+
+
+/*
+** Read a sequence of (hex)digits
+*/
+static int readdigits (RN *rn, int hex) {
+ int count = 0;
+ while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn))
+ count++;
+ return count;
+}
+
+
+/*
+** Read a number: first reads a valid prefix of a numeral into a buffer.
+** Then it calls 'lua_stringtonumber' to check whether the format is
+** correct and to convert it to a Lua number
+*/
+static int read_number (lua_State *L, FILE *f) {
+ RN rn;
+ int count = 0;
+ int hex = 0;
+ char decp[2];
+ rn.f = f; rn.n = 0;
+ decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */
+ decp[1] = '.'; /* always accept a dot */
+ l_lockfile(rn.f);
+ do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
+ test2(&rn, "-+"); /* optional signal */
+ if (test2(&rn, "00")) {
+ if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
+ else count = 1; /* count initial '0' as a valid digit */
+ }
+ count += readdigits(&rn, hex); /* integral part */
+ if (test2(&rn, decp)) /* decimal point? */
+ count += readdigits(&rn, hex); /* fractional part */
+ if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */
+ test2(&rn, "-+"); /* exponent signal */
+ readdigits(&rn, 0); /* exponent digits */
+ }
+ ungetc(rn.c, rn.f); /* unread look-ahead char */
+ l_unlockfile(rn.f);
+ rn.buff[rn.n] = '\0'; /* finish string */
+ if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */
+ return 1; /* ok */
+ else { /* invalid format */
+ lua_pushnil(L); /* "result" to be removed */
+ return 0; /* read fails */
+ }
+}
+
+
+static int test_eof (lua_State *L, FILE *f) {
+ int c = getc(f);
+ ungetc(c, f); /* no-op when c == EOF */
+ lua_pushliteral(L, "");
+ return (c != EOF);
+}
+
+
+static int read_line (lua_State *L, FILE *f, int chop) {
+ luaL_Buffer b;
+ int c = '\0';
+ luaL_buffinit(L, &b);
+ while (c != EOF && c != '\n') { /* repeat until end of line */
+ char *buff = luaL_prepbuffer(&b); /* preallocate buffer */
+ int i = 0;
+ l_lockfile(f); /* no memory errors can happen inside the lock */
+ while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
+ buff[i++] = c;
+ l_unlockfile(f);
+ luaL_addsize(&b, i);
+ }
+ if (!chop && c == '\n') /* want a newline and have one? */
+ luaL_addchar(&b, c); /* add ending newline to result */
+ luaL_pushresult(&b); /* close buffer */
+ /* return ok if read something (either a newline or something else) */
+ return (c == '\n' || lua_rawlen(L, -1) > 0);
+}
+
+
+static void read_all (lua_State *L, FILE *f) {
+ size_t nr;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ do { /* read file in chunks of LUAL_BUFFERSIZE bytes */
+ char *p = luaL_prepbuffer(&b);
+ nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f);
+ luaL_addsize(&b, nr);
+ } while (nr == LUAL_BUFFERSIZE);
+ luaL_pushresult(&b); /* close buffer */
+}
+
+
+static int read_chars (lua_State *L, FILE *f, size_t n) {
+ size_t nr; /* number of chars actually read */
+ char *p;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */
+ nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */
+ luaL_addsize(&b, nr);
+ luaL_pushresult(&b); /* close buffer */
+ return (nr > 0); /* true iff read something */
+}
+
+
+static int g_read (lua_State *L, FILE *f, int first) {
+ int nargs = lua_gettop(L) - 1;
+ int success;
+ int n;
+ clearerr(f);
+ if (nargs == 0) { /* no arguments? */
+ success = read_line(L, f, 1);
+ n = first+1; /* to return 1 result */
+ }
+ else { /* ensure stack space for all results and for auxlib's buffer */
+ luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
+ success = 1;
+ for (n = first; nargs-- && success; n++) {
+ if (lua_type(L, n) == LUA_TNUMBER) {
+ size_t l = (size_t)luaL_checkinteger(L, n);
+ success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
+ }
+ else {
+ const char *p = luaL_checkstring(L, n);
+ if (*p == '*') p++; /* skip optional '*' (for compatibility) */
+ switch (*p) {
+ case 'n': /* number */
+ success = read_number(L, f);
+ break;
+ case 'l': /* line */
+ success = read_line(L, f, 1);
+ break;
+ case 'L': /* line with end-of-line */
+ success = read_line(L, f, 0);
+ break;
+ case 'a': /* file */
+ read_all(L, f); /* read entire file */
+ success = 1; /* always success */
+ break;
+ default:
+ return luaL_argerror(L, n, "invalid format");
+ }
+ }
+ }
+ }
+ if (ferror(f))
+ return luaL_fileresult(L, 0, NULL);
+ if (!success) {
+ lua_pop(L, 1); /* remove last result */
+ lua_pushnil(L); /* push nil instead */
+ }
+ return n - first;
+}
+
+
+static int io_read (lua_State *L) {
+ return g_read(L, getiofile(L, IO_INPUT), 1);
+}
+
+
+static int f_read (lua_State *L) {
+ return g_read(L, tofile(L), 2);
+}
+
+
+static int io_readline (lua_State *L) {
+ LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1));
+ int i;
+ int n = (int)lua_tointeger(L, lua_upvalueindex(2));
+ if (isclosed(p)) /* file is already closed? */
+ return luaL_error(L, "file is already closed");
+ lua_settop(L , 1);
+ luaL_checkstack(L, n, "too many arguments");
+ for (i = 1; i <= n; i++) /* push arguments to 'g_read' */
+ lua_pushvalue(L, lua_upvalueindex(3 + i));
+ n = g_read(L, p->f, 2); /* 'n' is number of results */
+ lua_assert(n > 0); /* should return at least a nil */
+ if (lua_toboolean(L, -n)) /* read at least one value? */
+ return n; /* return them */
+ else { /* first result is nil: EOF or error */
+ if (n > 1) { /* is there error information? */
+ /* 2nd result is error message */
+ return luaL_error(L, "%s", lua_tostring(L, -n + 1));
+ }
+ if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */
+ lua_settop(L, 0);
+ lua_pushvalue(L, lua_upvalueindex(1));
+ aux_close(L); /* close it */
+ }
+ return 0;
+ }
+}
+
+/* }====================================================== */
+
+
+static int g_write (lua_State *L, FILE *f, int arg) {
+ int nargs = lua_gettop(L) - arg;
+ int status = 1;
+ for (; nargs--; arg++) {
+ if (lua_type(L, arg) == LUA_TNUMBER) {
+ /* optimization: could be done exactly as for strings */
+ int len = lua_isinteger(L, arg)
+ ? fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg))
+ : fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg));
+ status = status && (len > 0);
+ }
+ else {
+ size_t l;
+ const char *s = luaL_checklstring(L, arg, &l);
+ status = status && (fwrite(s, sizeof(char), l, f) == l);
+ }
+ }
+ if (status) return 1; /* file handle already on stack top */
+ else return luaL_fileresult(L, status, NULL);
+}
+
+
+static int io_write (lua_State *L) {
+ return g_write(L, getiofile(L, IO_OUTPUT), 1);
+}
+
+
+static int f_write (lua_State *L) {
+ FILE *f = tofile(L);
+ lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */
+ return g_write(L, f, 2);
+}
+
+
+static int f_seek (lua_State *L) {
+ static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
+ static const char *const modenames[] = {"set", "cur", "end", NULL};
+ FILE *f = tofile(L);
+ int op = luaL_checkoption(L, 2, "cur", modenames);
+ lua_Integer p3 = luaL_optinteger(L, 3, 0);
+ l_seeknum offset = (l_seeknum)p3;
+ luaL_argcheck(L, (lua_Integer)offset == p3, 3,
+ "not an integer in proper range");
+ op = l_fseek(f, offset, mode[op]);
+ if (op)
+ return luaL_fileresult(L, 0, NULL); /* error */
+ else {
+ lua_pushinteger(L, (lua_Integer)l_ftell(f));
+ return 1;
+ }
+}
+
+
+static int f_setvbuf (lua_State *L) {
+ static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
+ static const char *const modenames[] = {"no", "full", "line", NULL};
+ FILE *f = tofile(L);
+ int op = luaL_checkoption(L, 2, NULL, modenames);
+ lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
+ int res = setvbuf(f, NULL, mode[op], (size_t)sz);
+ return luaL_fileresult(L, res == 0, NULL);
+}
+
+
+
+static int io_flush (lua_State *L) {
+ return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
+}
+
+
+static int f_flush (lua_State *L) {
+ return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);
+}
+
+
+/*
+** functions for 'io' library
+*/
+static const luaL_Reg iolib[] = {
+ {"close", io_close},
+ {"flush", io_flush},
+ {"input", io_input},
+ {"lines", io_lines},
+ {"open", io_open},
+ {"output", io_output},
+ {"popen", io_popen},
+ {"read", io_read},
+ {"tmpfile", io_tmpfile},
+ {"type", io_type},
+ {"write", io_write},
+ {NULL, NULL}
+};
+
+
+/*
+** methods for file handles
+*/
+static const luaL_Reg flib[] = {
+ {"close", io_close},
+ {"flush", f_flush},
+ {"lines", f_lines},
+ {"read", f_read},
+ {"seek", f_seek},
+ {"setvbuf", f_setvbuf},
+ {"write", f_write},
+ {"__gc", f_gc},
+ {"__tostring", f_tostring},
+ {NULL, NULL}
+};
+
+
+static void createmeta (lua_State *L) {
+ luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */
+ lua_pushvalue(L, -1); /* push metatable */
+ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
+ luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */
+ lua_pop(L, 1); /* pop new metatable */
+}
+
+
+/*
+** function to (not) close the standard files stdin, stdout, and stderr
+*/
+static int io_noclose (lua_State *L) {
+ LStream *p = tolstream(L);
+ p->closef = &io_noclose; /* keep file opened */
+ lua_pushnil(L);
+ lua_pushliteral(L, "cannot close standard file");
+ return 2;
+}
+
+
+static void createstdfile (lua_State *L, FILE *f, const char *k,
+ const char *fname) {
+ LStream *p = newprefile(L);
+ p->f = f;
+ p->closef = &io_noclose;
+ if (k != NULL) {
+ lua_pushvalue(L, -1);
+ lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */
+ }
+ lua_setfield(L, -2, fname); /* add file to module */
+}
+
+
+LUAMOD_API int luaopen_io (lua_State *L) {
+ luaL_newlib(L, iolib); /* new module */
+ createmeta(L);
+ /* create (and set) default files */
+ createstdfile(L, stdin, IO_INPUT, "stdin");
+ createstdfile(L, stdout, IO_OUTPUT, "stdout");
+ createstdfile(L, stderr, NULL, "stderr");
+ return 1;
+}
+
diff --git a/external/lua-5.3.3/src/llex.c b/external/lua-5.3.3/src/llex.c
new file mode 100644
index 0000000..7032827
--- /dev/null
+++ b/external/lua-5.3.3/src/llex.c
@@ -0,0 +1,565 @@
+/*
+** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $
+** Lexical Analyzer
+** See Copyright Notice in lua.h
+*/
+
+#define llex_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <locale.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lctype.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lgc.h"
+#include "llex.h"
+#include "lobject.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "lzio.h"
+
+
+
+#define next(ls) (ls->current = zgetc(ls->z))
+
+
+
+#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')
+
+
+/* ORDER RESERVED */
+static const char *const luaX_tokens [] = {
+ "and", "break", "do", "else", "elseif",
+ "end", "false", "for", "function", "goto", "if",
+ "in", "local", "nil", "not", "or", "repeat",
+ "return", "then", "true", "until", "while",
+ "//", "..", "...", "==", ">=", "<=", "~=",
+ "<<", ">>", "::", "<eof>",
+ "<number>", "<integer>", "<name>", "<string>"
+};
+
+
+#define save_and_next(ls) (save(ls, ls->current), next(ls))
+
+
+static l_noret lexerror (LexState *ls, const char *msg, int token);
+
+
+static void save (LexState *ls, int c) {
+ Mbuffer *b = ls->buff;
+ if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) {
+ size_t newsize;
+ if (luaZ_sizebuffer(b) >= MAX_SIZE/2)
+ lexerror(ls, "lexical element too long", 0);
+ newsize = luaZ_sizebuffer(b) * 2;
+ luaZ_resizebuffer(ls->L, b, newsize);
+ }
+ b->buffer[luaZ_bufflen(b)++] = cast(char, c);
+}
+
+
+void luaX_init (lua_State *L) {
+ int i;
+ TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */
+ luaC_fix(L, obj2gco(e)); /* never collect this name */
+ for (i=0; i<NUM_RESERVED; i++) {
+ TString *ts = luaS_new(L, luaX_tokens[i]);
+ luaC_fix(L, obj2gco(ts)); /* reserved words are never collected */
+ ts->extra = cast_byte(i+1); /* reserved word */
+ }
+}
+
+
+const char *luaX_token2str (LexState *ls, int token) {
+ if (token < FIRST_RESERVED) { /* single-byte symbols? */
+ lua_assert(token == cast_uchar(token));
+ return luaO_pushfstring(ls->L, "'%c'", token);
+ }
+ else {
+ const char *s = luaX_tokens[token - FIRST_RESERVED];
+ if (token < TK_EOS) /* fixed format (symbols and reserved words)? */
+ return luaO_pushfstring(ls->L, "'%s'", s);
+ else /* names, strings, and numerals */
+ return s;
+ }
+}
+
+
+static const char *txtToken (LexState *ls, int token) {
+ switch (token) {
+ case TK_NAME: case TK_STRING:
+ case TK_FLT: case TK_INT:
+ save(ls, '\0');
+ return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff));
+ default:
+ return luaX_token2str(ls, token);
+ }
+}
+
+
+static l_noret lexerror (LexState *ls, const char *msg, int token) {
+ msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber);
+ if (token)
+ luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token));
+ luaD_throw(ls->L, LUA_ERRSYNTAX);
+}
+
+
+l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
+ lexerror(ls, msg, ls->t.token);
+}
+
+
+/*
+** creates a new string and anchors it in scanner's table so that
+** it will not be collected until the end of the compilation
+** (by that time it should be anchored somewhere)
+*/
+TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
+ lua_State *L = ls->L;
+ TValue *o; /* entry for 'str' */
+ TString *ts = luaS_newlstr(L, str, l); /* create new string */
+ setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */
+ o = luaH_set(L, ls->h, L->top - 1);
+ if (ttisnil(o)) { /* not in use yet? */
+ /* boolean value does not need GC barrier;
+ table has no metatable, so it does not need to invalidate cache */
+ setbvalue(o, 1); /* t[string] = true */
+ luaC_checkGC(L);
+ }
+ else { /* string already present */
+ ts = tsvalue(keyfromval(o)); /* re-use value previously stored */
+ }
+ L->top--; /* remove string from stack */
+ return ts;
+}
+
+
+/*
+** increment line number and skips newline sequence (any of
+** \n, \r, \n\r, or \r\n)
+*/
+static void inclinenumber (LexState *ls) {
+ int old = ls->current;
+ lua_assert(currIsNewline(ls));
+ next(ls); /* skip '\n' or '\r' */
+ if (currIsNewline(ls) && ls->current != old)
+ next(ls); /* skip '\n\r' or '\r\n' */
+ if (++ls->linenumber >= MAX_INT)
+ lexerror(ls, "chunk has too many lines", 0);
+}
+
+
+void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
+ int firstchar) {
+ ls->t.token = 0;
+ ls->L = L;
+ ls->current = firstchar;
+ ls->lookahead.token = TK_EOS; /* no look-ahead token */
+ ls->z = z;
+ ls->fs = NULL;
+ ls->linenumber = 1;
+ ls->lastline = 1;
+ ls->source = source;
+ ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */
+ luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
+}
+
+
+
+/*
+** =======================================================
+** LEXICAL ANALYZER
+** =======================================================
+*/
+
+
+static int check_next1 (LexState *ls, int c) {
+ if (ls->current == c) {
+ next(ls);
+ return 1;
+ }
+ else return 0;
+}
+
+
+/*
+** Check whether current char is in set 'set' (with two chars) and
+** saves it
+*/
+static int check_next2 (LexState *ls, const char *set) {
+ lua_assert(set[2] == '\0');
+ if (ls->current == set[0] || ls->current == set[1]) {
+ save_and_next(ls);
+ return 1;
+ }
+ else return 0;
+}
+
+
+/* LUA_NUMBER */
+/*
+** this function is quite liberal in what it accepts, as 'luaO_str2num'
+** will reject ill-formed numerals.
+*/
+static int read_numeral (LexState *ls, SemInfo *seminfo) {
+ TValue obj;
+ const char *expo = "Ee";
+ int first = ls->current;
+ lua_assert(lisdigit(ls->current));
+ save_and_next(ls);
+ if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */
+ expo = "Pp";
+ for (;;) {
+ if (check_next2(ls, expo)) /* exponent part? */
+ check_next2(ls, "-+"); /* optional exponent sign */
+ if (lisxdigit(ls->current))
+ save_and_next(ls);
+ else if (ls->current == '.')
+ save_and_next(ls);
+ else break;
+ }
+ save(ls, '\0');
+ if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */
+ lexerror(ls, "malformed number", TK_FLT);
+ if (ttisinteger(&obj)) {
+ seminfo->i = ivalue(&obj);
+ return TK_INT;
+ }
+ else {
+ lua_assert(ttisfloat(&obj));
+ seminfo->r = fltvalue(&obj);
+ return TK_FLT;
+ }
+}
+
+
+/*
+** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return
+** its number of '='s; otherwise, return a negative number (-1 iff there
+** are no '='s after initial bracket)
+*/
+static int skip_sep (LexState *ls) {
+ int count = 0;
+ int s = ls->current;
+ lua_assert(s == '[' || s == ']');
+ save_and_next(ls);
+ while (ls->current == '=') {
+ save_and_next(ls);
+ count++;
+ }
+ return (ls->current == s) ? count : (-count) - 1;
+}
+
+
+static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
+ int line = ls->linenumber; /* initial line (for error message) */
+ save_and_next(ls); /* skip 2nd '[' */
+ if (currIsNewline(ls)) /* string starts with a newline? */
+ inclinenumber(ls); /* skip it */
+ for (;;) {
+ switch (ls->current) {
+ case EOZ: { /* error */
+ const char *what = (seminfo ? "string" : "comment");
+ const char *msg = luaO_pushfstring(ls->L,
+ "unfinished long %s (starting at line %d)", what, line);
+ lexerror(ls, msg, TK_EOS);
+ break; /* to avoid warnings */
+ }
+ case ']': {
+ if (skip_sep(ls) == sep) {
+ save_and_next(ls); /* skip 2nd ']' */
+ goto endloop;
+ }
+ break;
+ }
+ case '\n': case '\r': {
+ save(ls, '\n');
+ inclinenumber(ls);
+ if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */
+ break;
+ }
+ default: {
+ if (seminfo) save_and_next(ls);
+ else next(ls);
+ }
+ }
+ } endloop:
+ if (seminfo)
+ seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),
+ luaZ_bufflen(ls->buff) - 2*(2 + sep));
+}
+
+
+static void esccheck (LexState *ls, int c, const char *msg) {
+ if (!c) {
+ if (ls->current != EOZ)
+ save_and_next(ls); /* add current to buffer for error message */
+ lexerror(ls, msg, TK_STRING);
+ }
+}
+
+
+static int gethexa (LexState *ls) {
+ save_and_next(ls);
+ esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected");
+ return luaO_hexavalue(ls->current);
+}
+
+
+static int readhexaesc (LexState *ls) {
+ int r = gethexa(ls);
+ r = (r << 4) + gethexa(ls);
+ luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */
+ return r;
+}
+
+
+static unsigned long readutf8esc (LexState *ls) {
+ unsigned long r;
+ int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */
+ save_and_next(ls); /* skip 'u' */
+ esccheck(ls, ls->current == '{', "missing '{'");
+ r = gethexa(ls); /* must have at least one digit */
+ while ((save_and_next(ls), lisxdigit(ls->current))) {
+ i++;
+ r = (r << 4) + luaO_hexavalue(ls->current);
+ esccheck(ls, r <= 0x10FFFF, "UTF-8 value too large");
+ }
+ esccheck(ls, ls->current == '}', "missing '}'");
+ next(ls); /* skip '}' */
+ luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */
+ return r;
+}
+
+
+static void utf8esc (LexState *ls) {
+ char buff[UTF8BUFFSZ];
+ int n = luaO_utf8esc(buff, readutf8esc(ls));
+ for (; n > 0; n--) /* add 'buff' to string */
+ save(ls, buff[UTF8BUFFSZ - n]);
+}
+
+
+static int readdecesc (LexState *ls) {
+ int i;
+ int r = 0; /* result accumulator */
+ for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */
+ r = 10*r + ls->current - '0';
+ save_and_next(ls);
+ }
+ esccheck(ls, r <= UCHAR_MAX, "decimal escape too large");
+ luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */
+ return r;
+}
+
+
+static void read_string (LexState *ls, int del, SemInfo *seminfo) {
+ save_and_next(ls); /* keep delimiter (for error messages) */
+ while (ls->current != del) {
+ switch (ls->current) {
+ case EOZ:
+ lexerror(ls, "unfinished string", TK_EOS);
+ break; /* to avoid warnings */
+ case '\n':
+ case '\r':
+ lexerror(ls, "unfinished string", TK_STRING);
+ break; /* to avoid warnings */
+ case '\\': { /* escape sequences */
+ int c; /* final character to be saved */
+ save_and_next(ls); /* keep '\\' for error messages */
+ switch (ls->current) {
+ case 'a': c = '\a'; goto read_save;
+ case 'b': c = '\b'; goto read_save;
+ case 'f': c = '\f'; goto read_save;
+ case 'n': c = '\n'; goto read_save;
+ case 'r': c = '\r'; goto read_save;
+ case 't': c = '\t'; goto read_save;
+ case 'v': c = '\v'; goto read_save;
+ case 'x': c = readhexaesc(ls); goto read_save;
+ case 'u': utf8esc(ls); goto no_save;
+ case '\n': case '\r':
+ inclinenumber(ls); c = '\n'; goto only_save;
+ case '\\': case '\"': case '\'':
+ c = ls->current; goto read_save;
+ case EOZ: goto no_save; /* will raise an error next loop */
+ case 'z': { /* zap following span of spaces */
+ luaZ_buffremove(ls->buff, 1); /* remove '\\' */
+ next(ls); /* skip the 'z' */
+ while (lisspace(ls->current)) {
+ if (currIsNewline(ls)) inclinenumber(ls);
+ else next(ls);
+ }
+ goto no_save;
+ }
+ default: {
+ esccheck(ls, lisdigit(ls->current), "invalid escape sequence");
+ c = readdecesc(ls); /* digital escape '\ddd' */
+ goto only_save;
+ }
+ }
+ read_save:
+ next(ls);
+ /* go through */
+ only_save:
+ luaZ_buffremove(ls->buff, 1); /* remove '\\' */
+ save(ls, c);
+ /* go through */
+ no_save: break;
+ }
+ default:
+ save_and_next(ls);
+ }
+ }
+ save_and_next(ls); /* skip delimiter */
+ seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1,
+ luaZ_bufflen(ls->buff) - 2);
+}
+
+
+static int llex (LexState *ls, SemInfo *seminfo) {
+ luaZ_resetbuffer(ls->buff);
+ for (;;) {
+ switch (ls->current) {
+ case '\n': case '\r': { /* line breaks */
+ inclinenumber(ls);
+ break;
+ }
+ case ' ': case '\f': case '\t': case '\v': { /* spaces */
+ next(ls);
+ break;
+ }
+ case '-': { /* '-' or '--' (comment) */
+ next(ls);
+ if (ls->current != '-') return '-';
+ /* else is a comment */
+ next(ls);
+ if (ls->current == '[') { /* long comment? */
+ int sep = skip_sep(ls);
+ luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */
+ if (sep >= 0) {
+ read_long_string(ls, NULL, sep); /* skip long comment */
+ luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */
+ break;
+ }
+ }
+ /* else short comment */
+ while (!currIsNewline(ls) && ls->current != EOZ)
+ next(ls); /* skip until end of line (or end of file) */
+ break;
+ }
+ case '[': { /* long string or simply '[' */
+ int sep = skip_sep(ls);
+ if (sep >= 0) {
+ read_long_string(ls, seminfo, sep);
+ return TK_STRING;
+ }
+ else if (sep != -1) /* '[=...' missing second bracket */
+ lexerror(ls, "invalid long string delimiter", TK_STRING);
+ return '[';
+ }
+ case '=': {
+ next(ls);
+ if (check_next1(ls, '=')) return TK_EQ;
+ else return '=';
+ }
+ case '<': {
+ next(ls);
+ if (check_next1(ls, '=')) return TK_LE;
+ else if (check_next1(ls, '<')) return TK_SHL;
+ else return '<';
+ }
+ case '>': {
+ next(ls);
+ if (check_next1(ls, '=')) return TK_GE;
+ else if (check_next1(ls, '>')) return TK_SHR;
+ else return '>';
+ }
+ case '/': {
+ next(ls);
+ if (check_next1(ls, '/')) return TK_IDIV;
+ else return '/';
+ }
+ case '~': {
+ next(ls);
+ if (check_next1(ls, '=')) return TK_NE;
+ else return '~';
+ }
+ case ':': {
+ next(ls);
+ if (check_next1(ls, ':')) return TK_DBCOLON;
+ else return ':';
+ }
+ case '"': case '\'': { /* short literal strings */
+ read_string(ls, ls->current, seminfo);
+ return TK_STRING;
+ }
+ case '.': { /* '.', '..', '...', or number */
+ save_and_next(ls);
+ if (check_next1(ls, '.')) {
+ if (check_next1(ls, '.'))
+ return TK_DOTS; /* '...' */
+ else return TK_CONCAT; /* '..' */
+ }
+ else if (!lisdigit(ls->current)) return '.';
+ else return read_numeral(ls, seminfo);
+ }
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': {
+ return read_numeral(ls, seminfo);
+ }
+ case EOZ: {
+ return TK_EOS;
+ }
+ default: {
+ if (lislalpha(ls->current)) { /* identifier or reserved word? */
+ TString *ts;
+ do {
+ save_and_next(ls);
+ } while (lislalnum(ls->current));
+ ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
+ luaZ_bufflen(ls->buff));
+ seminfo->ts = ts;
+ if (isreserved(ts)) /* reserved word? */
+ return ts->extra - 1 + FIRST_RESERVED;
+ else {
+ return TK_NAME;
+ }
+ }
+ else { /* single-char tokens (+ - / ...) */
+ int c = ls->current;
+ next(ls);
+ return c;
+ }
+ }
+ }
+ }
+}
+
+
+void luaX_next (LexState *ls) {
+ ls->lastline = ls->linenumber;
+ if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */
+ ls->t = ls->lookahead; /* use this one */
+ ls->lookahead.token = TK_EOS; /* and discharge it */
+ }
+ else
+ ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */
+}
+
+
+int luaX_lookahead (LexState *ls) {
+ lua_assert(ls->lookahead.token == TK_EOS);
+ ls->lookahead.token = llex(ls, &ls->lookahead.seminfo);
+ return ls->lookahead.token;
+}
+
diff --git a/external/lua-5.3.3/src/llex.h b/external/lua-5.3.3/src/llex.h
new file mode 100644
index 0000000..2363d87
--- /dev/null
+++ b/external/lua-5.3.3/src/llex.h
@@ -0,0 +1,85 @@
+/*
+** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $
+** Lexical Analyzer
+** See Copyright Notice in lua.h
+*/
+
+#ifndef llex_h
+#define llex_h
+
+#include "lobject.h"
+#include "lzio.h"
+
+
+#define FIRST_RESERVED 257
+
+
+#if !defined(LUA_ENV)
+#define LUA_ENV "_ENV"
+#endif
+
+
+/*
+* WARNING: if you change the order of this enumeration,
+* grep "ORDER RESERVED"
+*/
+enum RESERVED {
+ /* terminal symbols denoted by reserved words */
+ TK_AND = FIRST_RESERVED, TK_BREAK,
+ TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
+ TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
+ TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
+ /* other terminal symbols */
+ TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
+ TK_SHL, TK_SHR,
+ TK_DBCOLON, TK_EOS,
+ TK_FLT, TK_INT, TK_NAME, TK_STRING
+};
+
+/* number of reserved words */
+#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1))
+
+
+typedef union {
+ lua_Number r;
+ lua_Integer i;
+ TString *ts;
+} SemInfo; /* semantics information */
+
+
+typedef struct Token {
+ int token;
+ SemInfo seminfo;
+} Token;
+
+
+/* state of the lexer plus state of the parser when shared by all
+ functions */
+typedef struct LexState {
+ int current; /* current character (charint) */
+ int linenumber; /* input line counter */
+ int lastline; /* line of last token 'consumed' */
+ Token t; /* current token */
+ Token lookahead; /* look ahead token */
+ struct FuncState *fs; /* current function (parser) */
+ struct lua_State *L;
+ ZIO *z; /* input stream */
+ Mbuffer *buff; /* buffer for tokens */
+ Table *h; /* to avoid collection/reuse strings */
+ struct Dyndata *dyd; /* dynamic structures used by the parser */
+ TString *source; /* current source name */
+ TString *envn; /* environment variable name */
+} LexState;
+
+
+LUAI_FUNC void luaX_init (lua_State *L);
+LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z,
+ TString *source, int firstchar);
+LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l);
+LUAI_FUNC void luaX_next (LexState *ls);
+LUAI_FUNC int luaX_lookahead (LexState *ls);
+LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s);
+LUAI_FUNC const char *luaX_token2str (LexState *ls, int token);
+
+
+#endif
diff --git a/external/lua-5.3.3/src/llimits.h b/external/lua-5.3.3/src/llimits.h
new file mode 100644
index 0000000..f21377f
--- /dev/null
+++ b/external/lua-5.3.3/src/llimits.h
@@ -0,0 +1,323 @@
+/*
+** $Id: llimits.h,v 1.141 2015/11/19 19:16:22 roberto Exp $
+** Limits, basic types, and some other 'installation-dependent' definitions
+** See Copyright Notice in lua.h
+*/
+
+#ifndef llimits_h
+#define llimits_h
+
+
+#include <limits.h>
+#include <stddef.h>
+
+
+#include "lua.h"
+
+/*
+** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count
+** the total memory used by Lua (in bytes). Usually, 'size_t' and
+** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines.
+*/
+#if defined(LUAI_MEM) /* { external definitions? */
+typedef LUAI_UMEM lu_mem;
+typedef LUAI_MEM l_mem;
+#elif LUAI_BITSINT >= 32 /* }{ */
+typedef size_t lu_mem;
+typedef ptrdiff_t l_mem;
+#else /* 16-bit ints */ /* }{ */
+typedef unsigned long lu_mem;
+typedef long l_mem;
+#endif /* } */
+
+
+/* chars used as small naturals (so that 'char' is reserved for characters) */
+typedef unsigned char lu_byte;
+
+
+/* maximum value for size_t */
+#define MAX_SIZET ((size_t)(~(size_t)0))
+
+/* maximum size visible for Lua (must be representable in a lua_Integer */
+#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \
+ : (size_t)(LUA_MAXINTEGER))
+
+
+#define MAX_LUMEM ((lu_mem)(~(lu_mem)0))
+
+#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1))
+
+
+#define MAX_INT INT_MAX /* maximum value of an int */
+
+
+/*
+** conversion of pointer to unsigned integer:
+** this is for hashing only; there is no problem if the integer
+** cannot hold the whole pointer value
+*/
+#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
+
+
+
+/* type to ensure maximum alignment */
+#if defined(LUAI_USER_ALIGNMENT_T)
+typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
+#else
+typedef union {
+ lua_Number n;
+ double u;
+ void *s;
+ lua_Integer i;
+ long l;
+} L_Umaxalign;
+#endif
+
+
+
+/* types of 'usual argument conversions' for lua_Number and lua_Integer */
+typedef LUAI_UACNUMBER l_uacNumber;
+typedef LUAI_UACINT l_uacInt;
+
+
+/* internal assertions for in-house debugging */
+#if defined(lua_assert)
+#define check_exp(c,e) (lua_assert(c), (e))
+/* to avoid problems with conditions too long */
+#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0))
+#else
+#define lua_assert(c) ((void)0)
+#define check_exp(c,e) (e)
+#define lua_longassert(c) ((void)0)
+#endif
+
+/*
+** assertion for checking API calls
+*/
+#if !defined(luai_apicheck)
+#define luai_apicheck(l,e) lua_assert(e)
+#endif
+
+#define api_check(l,e,msg) luai_apicheck(l,(e) && msg)
+
+
+/* macro to avoid warnings about unused variables */
+#if !defined(UNUSED)
+#define UNUSED(x) ((void)(x))
+#endif
+
+
+/* type casts (a macro highlights casts in the code) */
+#define cast(t, exp) ((t)(exp))
+
+#define cast_void(i) cast(void, (i))
+#define cast_byte(i) cast(lu_byte, (i))
+#define cast_num(i) cast(lua_Number, (i))
+#define cast_int(i) cast(int, (i))
+#define cast_uchar(i) cast(unsigned char, (i))
+
+
+/* cast a signed lua_Integer to lua_Unsigned */
+#if !defined(l_castS2U)
+#define l_castS2U(i) ((lua_Unsigned)(i))
+#endif
+
+/*
+** cast a lua_Unsigned to a signed lua_Integer; this cast is
+** not strict ISO C, but two-complement architectures should
+** work fine.
+*/
+#if !defined(l_castU2S)
+#define l_castU2S(i) ((lua_Integer)(i))
+#endif
+
+
+/*
+** non-return type
+*/
+#if defined(__GNUC__)
+#define l_noret void __attribute__((noreturn))
+#elif defined(_MSC_VER) && _MSC_VER >= 1200
+#define l_noret void __declspec(noreturn)
+#else
+#define l_noret void
+#endif
+
+
+
+/*
+** maximum depth for nested C calls and syntactical nested non-terminals
+** in a program. (Value must fit in an unsigned short int.)
+*/
+#if !defined(LUAI_MAXCCALLS)
+#define LUAI_MAXCCALLS 200
+#endif
+
+
+
+/*
+** type for virtual-machine instructions;
+** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
+*/
+#if LUAI_BITSINT >= 32
+typedef unsigned int Instruction;
+#else
+typedef unsigned long Instruction;
+#endif
+
+
+
+/*
+** Maximum length for short strings, that is, strings that are
+** internalized. (Cannot be smaller than reserved words or tags for
+** metamethods, as these strings must be internalized;
+** #("function") = 8, #("__newindex") = 10.)
+*/
+#if !defined(LUAI_MAXSHORTLEN)
+#define LUAI_MAXSHORTLEN 40
+#endif
+
+
+/*
+** Initial size for the string table (must be power of 2).
+** The Lua core alone registers ~50 strings (reserved words +
+** metaevent keys + a few others). Libraries would typically add
+** a few dozens more.
+*/
+#if !defined(MINSTRTABSIZE)
+#define MINSTRTABSIZE 128
+#endif
+
+
+/*
+** Size of cache for strings in the API. 'N' is the number of
+** sets (better be a prime) and "M" is the size of each set (M == 1
+** makes a direct cache.)
+*/
+#if !defined(STRCACHE_N)
+#define STRCACHE_N 53
+#define STRCACHE_M 2
+#endif
+
+
+/* minimum size for string buffer */
+#if !defined(LUA_MINBUFFER)
+#define LUA_MINBUFFER 32
+#endif
+
+
+/*
+** macros that are executed whenever program enters the Lua core
+** ('lua_lock') and leaves the core ('lua_unlock')
+*/
+#if !defined(lua_lock)
+#define lua_lock(L) ((void) 0)
+#define lua_unlock(L) ((void) 0)
+#endif
+
+/*
+** macro executed during Lua functions at points where the
+** function can yield.
+*/
+#if !defined(luai_threadyield)
+#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
+#endif
+
+
+/*
+** these macros allow user-specific actions on threads when you defined
+** LUAI_EXTRASPACE and need to do something extra when a thread is
+** created/deleted/resumed/yielded.
+*/
+#if !defined(luai_userstateopen)
+#define luai_userstateopen(L) ((void)L)
+#endif
+
+#if !defined(luai_userstateclose)
+#define luai_userstateclose(L) ((void)L)
+#endif
+
+#if !defined(luai_userstatethread)
+#define luai_userstatethread(L,L1) ((void)L)
+#endif
+
+#if !defined(luai_userstatefree)
+#define luai_userstatefree(L,L1) ((void)L)
+#endif
+
+#if !defined(luai_userstateresume)
+#define luai_userstateresume(L,n) ((void)L)
+#endif
+
+#if !defined(luai_userstateyield)
+#define luai_userstateyield(L,n) ((void)L)
+#endif
+
+
+
+/*
+** The luai_num* macros define the primitive operations over numbers.
+*/
+
+/* floor division (defined as 'floor(a/b)') */
+#if !defined(luai_numidiv)
+#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b)))
+#endif
+
+/* float division */
+#if !defined(luai_numdiv)
+#define luai_numdiv(L,a,b) ((a)/(b))
+#endif
+
+/*
+** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when
+** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of
+** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b)
+** ~= floor(a/b)'. That happens when the division has a non-integer
+** negative result, which is equivalent to the test below.
+*/
+#if !defined(luai_nummod)
+#define luai_nummod(L,a,b,m) \
+ { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); }
+#endif
+
+/* exponentiation */
+#if !defined(luai_numpow)
+#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b))
+#endif
+
+/* the others are quite standard operations */
+#if !defined(luai_numadd)
+#define luai_numadd(L,a,b) ((a)+(b))
+#define luai_numsub(L,a,b) ((a)-(b))
+#define luai_nummul(L,a,b) ((a)*(b))
+#define luai_numunm(L,a) (-(a))
+#define luai_numeq(a,b) ((a)==(b))
+#define luai_numlt(a,b) ((a)<(b))
+#define luai_numle(a,b) ((a)<=(b))
+#define luai_numisnan(a) (!luai_numeq((a), (a)))
+#endif
+
+
+
+
+
+/*
+** macro to control inclusion of some hard tests on stack reallocation
+*/
+#if !defined(HARDSTACKTESTS)
+#define condmovestack(L,pre,pos) ((void)0)
+#else
+/* realloc stack keeping its size */
+#define condmovestack(L,pre,pos) \
+ { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; }
+#endif
+
+#if !defined(HARDMEMTESTS)
+#define condchangemem(L,pre,pos) ((void)0)
+#else
+#define condchangemem(L,pre,pos) \
+ { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } }
+#endif
+
+#endif
diff --git a/external/lua-5.3.3/src/lmathlib.c b/external/lua-5.3.3/src/lmathlib.c
new file mode 100644
index 0000000..94815f1
--- /dev/null
+++ b/external/lua-5.3.3/src/lmathlib.c
@@ -0,0 +1,407 @@
+/*
+** $Id: lmathlib.c,v 1.117 2015/10/02 15:39:23 roberto Exp $
+** Standard mathematical library
+** See Copyright Notice in lua.h
+*/
+
+#define lmathlib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+#undef PI
+#define PI (l_mathop(3.141592653589793238462643383279502884))
+
+
+#if !defined(l_rand) /* { */
+#if defined(LUA_USE_POSIX)
+#define l_rand() random()
+#define l_srand(x) srandom(x)
+#define L_RANDMAX 2147483647 /* (2^31 - 1), following POSIX */
+#else
+#define l_rand() rand()
+#define l_srand(x) srand(x)
+#define L_RANDMAX RAND_MAX
+#endif
+#endif /* } */
+
+
+static int math_abs (lua_State *L) {
+ if (lua_isinteger(L, 1)) {
+ lua_Integer n = lua_tointeger(L, 1);
+ if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n);
+ lua_pushinteger(L, n);
+ }
+ else
+ lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_sin (lua_State *L) {
+ lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_cos (lua_State *L) {
+ lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_tan (lua_State *L) {
+ lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_asin (lua_State *L) {
+ lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_acos (lua_State *L) {
+ lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_atan (lua_State *L) {
+ lua_Number y = luaL_checknumber(L, 1);
+ lua_Number x = luaL_optnumber(L, 2, 1);
+ lua_pushnumber(L, l_mathop(atan2)(y, x));
+ return 1;
+}
+
+
+static int math_toint (lua_State *L) {
+ int valid;
+ lua_Integer n = lua_tointegerx(L, 1, &valid);
+ if (valid)
+ lua_pushinteger(L, n);
+ else {
+ luaL_checkany(L, 1);
+ lua_pushnil(L); /* value is not convertible to integer */
+ }
+ return 1;
+}
+
+
+static void pushnumint (lua_State *L, lua_Number d) {
+ lua_Integer n;
+ if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */
+ lua_pushinteger(L, n); /* result is integer */
+ else
+ lua_pushnumber(L, d); /* result is float */
+}
+
+
+static int math_floor (lua_State *L) {
+ if (lua_isinteger(L, 1))
+ lua_settop(L, 1); /* integer is its own floor */
+ else {
+ lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1));
+ pushnumint(L, d);
+ }
+ return 1;
+}
+
+
+static int math_ceil (lua_State *L) {
+ if (lua_isinteger(L, 1))
+ lua_settop(L, 1); /* integer is its own ceil */
+ else {
+ lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1));
+ pushnumint(L, d);
+ }
+ return 1;
+}
+
+
+static int math_fmod (lua_State *L) {
+ if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) {
+ lua_Integer d = lua_tointeger(L, 2);
+ if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */
+ luaL_argcheck(L, d != 0, 2, "zero");
+ lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */
+ }
+ else
+ lua_pushinteger(L, lua_tointeger(L, 1) % d);
+ }
+ else
+ lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1),
+ luaL_checknumber(L, 2)));
+ return 1;
+}
+
+
+/*
+** next function does not use 'modf', avoiding problems with 'double*'
+** (which is not compatible with 'float*') when lua_Number is not
+** 'double'.
+*/
+static int math_modf (lua_State *L) {
+ if (lua_isinteger(L ,1)) {
+ lua_settop(L, 1); /* number is its own integer part */
+ lua_pushnumber(L, 0); /* no fractional part */
+ }
+ else {
+ lua_Number n = luaL_checknumber(L, 1);
+ /* integer part (rounds toward zero) */
+ lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n);
+ pushnumint(L, ip);
+ /* fractional part (test needed for inf/-inf) */
+ lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip));
+ }
+ return 2;
+}
+
+
+static int math_sqrt (lua_State *L) {
+ lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+
+static int math_ult (lua_State *L) {
+ lua_Integer a = luaL_checkinteger(L, 1);
+ lua_Integer b = luaL_checkinteger(L, 2);
+ lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b);
+ return 1;
+}
+
+static int math_log (lua_State *L) {
+ lua_Number x = luaL_checknumber(L, 1);
+ lua_Number res;
+ if (lua_isnoneornil(L, 2))
+ res = l_mathop(log)(x);
+ else {
+ lua_Number base = luaL_checknumber(L, 2);
+#if !defined(LUA_USE_C89)
+ if (base == 2.0) res = l_mathop(log2)(x); else
+#endif
+ if (base == 10.0) res = l_mathop(log10)(x);
+ else res = l_mathop(log)(x)/l_mathop(log)(base);
+ }
+ lua_pushnumber(L, res);
+ return 1;
+}
+
+static int math_exp (lua_State *L) {
+ lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_deg (lua_State *L) {
+ lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI));
+ return 1;
+}
+
+static int math_rad (lua_State *L) {
+ lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0)));
+ return 1;
+}
+
+
+static int math_min (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ int imin = 1; /* index of current minimum value */
+ int i;
+ luaL_argcheck(L, n >= 1, 1, "value expected");
+ for (i = 2; i <= n; i++) {
+ if (lua_compare(L, i, imin, LUA_OPLT))
+ imin = i;
+ }
+ lua_pushvalue(L, imin);
+ return 1;
+}
+
+
+static int math_max (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ int imax = 1; /* index of current maximum value */
+ int i;
+ luaL_argcheck(L, n >= 1, 1, "value expected");
+ for (i = 2; i <= n; i++) {
+ if (lua_compare(L, imax, i, LUA_OPLT))
+ imax = i;
+ }
+ lua_pushvalue(L, imax);
+ return 1;
+}
+
+/*
+** This function uses 'double' (instead of 'lua_Number') to ensure that
+** all bits from 'l_rand' can be represented, and that 'RANDMAX + 1.0'
+** will keep full precision (ensuring that 'r' is always less than 1.0.)
+*/
+static int math_random (lua_State *L) {
+ lua_Integer low, up;
+ double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0));
+ switch (lua_gettop(L)) { /* check number of arguments */
+ case 0: { /* no arguments */
+ lua_pushnumber(L, (lua_Number)r); /* Number between 0 and 1 */
+ return 1;
+ }
+ case 1: { /* only upper limit */
+ low = 1;
+ up = luaL_checkinteger(L, 1);
+ break;
+ }
+ case 2: { /* lower and upper limits */
+ low = luaL_checkinteger(L, 1);
+ up = luaL_checkinteger(L, 2);
+ break;
+ }
+ default: return luaL_error(L, "wrong number of arguments");
+ }
+ /* random integer in the interval [low, up] */
+ luaL_argcheck(L, low <= up, 1, "interval is empty");
+ luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1,
+ "interval too large");
+ r *= (double)(up - low) + 1.0;
+ lua_pushinteger(L, (lua_Integer)r + low);
+ return 1;
+}
+
+
+static int math_randomseed (lua_State *L) {
+ l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1));
+ (void)l_rand(); /* discard first value to avoid undesirable correlations */
+ return 0;
+}
+
+
+static int math_type (lua_State *L) {
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ if (lua_isinteger(L, 1))
+ lua_pushliteral(L, "integer");
+ else
+ lua_pushliteral(L, "float");
+ }
+ else {
+ luaL_checkany(L, 1);
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+
+/*
+** {==================================================================
+** Deprecated functions (for compatibility only)
+** ===================================================================
+*/
+#if defined(LUA_COMPAT_MATHLIB)
+
+static int math_cosh (lua_State *L) {
+ lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_sinh (lua_State *L) {
+ lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_tanh (lua_State *L) {
+ lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_pow (lua_State *L) {
+ lua_Number x = luaL_checknumber(L, 1);
+ lua_Number y = luaL_checknumber(L, 2);
+ lua_pushnumber(L, l_mathop(pow)(x, y));
+ return 1;
+}
+
+static int math_frexp (lua_State *L) {
+ int e;
+ lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e));
+ lua_pushinteger(L, e);
+ return 2;
+}
+
+static int math_ldexp (lua_State *L) {
+ lua_Number x = luaL_checknumber(L, 1);
+ int ep = (int)luaL_checkinteger(L, 2);
+ lua_pushnumber(L, l_mathop(ldexp)(x, ep));
+ return 1;
+}
+
+static int math_log10 (lua_State *L) {
+ lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+#endif
+/* }================================================================== */
+
+
+
+static const luaL_Reg mathlib[] = {
+ {"abs", math_abs},
+ {"acos", math_acos},
+ {"asin", math_asin},
+ {"atan", math_atan},
+ {"ceil", math_ceil},
+ {"cos", math_cos},
+ {"deg", math_deg},
+ {"exp", math_exp},
+ {"tointeger", math_toint},
+ {"floor", math_floor},
+ {"fmod", math_fmod},
+ {"ult", math_ult},
+ {"log", math_log},
+ {"max", math_max},
+ {"min", math_min},
+ {"modf", math_modf},
+ {"rad", math_rad},
+ {"random", math_random},
+ {"randomseed", math_randomseed},
+ {"sin", math_sin},
+ {"sqrt", math_sqrt},
+ {"tan", math_tan},
+ {"type", math_type},
+#if defined(LUA_COMPAT_MATHLIB)
+ {"atan2", math_atan},
+ {"cosh", math_cosh},
+ {"sinh", math_sinh},
+ {"tanh", math_tanh},
+ {"pow", math_pow},
+ {"frexp", math_frexp},
+ {"ldexp", math_ldexp},
+ {"log10", math_log10},
+#endif
+ /* placeholders */
+ {"pi", NULL},
+ {"huge", NULL},
+ {"maxinteger", NULL},
+ {"mininteger", NULL},
+ {NULL, NULL}
+};
+
+
+/*
+** Open math library
+*/
+LUAMOD_API int luaopen_math (lua_State *L) {
+ luaL_newlib(L, mathlib);
+ lua_pushnumber(L, PI);
+ lua_setfield(L, -2, "pi");
+ lua_pushnumber(L, (lua_Number)HUGE_VAL);
+ lua_setfield(L, -2, "huge");
+ lua_pushinteger(L, LUA_MAXINTEGER);
+ lua_setfield(L, -2, "maxinteger");
+ lua_pushinteger(L, LUA_MININTEGER);
+ lua_setfield(L, -2, "mininteger");
+ return 1;
+}
+
diff --git a/external/lua-5.3.3/src/lmem.c b/external/lua-5.3.3/src/lmem.c
new file mode 100644
index 0000000..0a0476c
--- /dev/null
+++ b/external/lua-5.3.3/src/lmem.c
@@ -0,0 +1,100 @@
+/*
+** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $
+** Interface to Memory Manager
+** See Copyright Notice in lua.h
+*/
+
+#define lmem_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+
+/*
+** About the realloc function:
+** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
+** ('osize' is the old size, 'nsize' is the new size)
+**
+** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no
+** matter 'x').
+**
+** * frealloc(ud, p, x, 0) frees the block 'p'
+** (in this specific case, frealloc must return NULL);
+** particularly, frealloc(ud, NULL, 0, 0) does nothing
+** (which is equivalent to free(NULL) in ISO C)
+**
+** frealloc returns NULL if it cannot create or reallocate the area
+** (any reallocation to an equal or smaller size cannot fail!)
+*/
+
+
+
+#define MINSIZEARRAY 4
+
+
+void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,
+ int limit, const char *what) {
+ void *newblock;
+ int newsize;
+ if (*size >= limit/2) { /* cannot double it? */
+ if (*size >= limit) /* cannot grow even a little? */
+ luaG_runerror(L, "too many %s (limit is %d)", what, limit);
+ newsize = limit; /* still have at least one free place */
+ }
+ else {
+ newsize = (*size)*2;
+ if (newsize < MINSIZEARRAY)
+ newsize = MINSIZEARRAY; /* minimum size */
+ }
+ newblock = luaM_reallocv(L, block, *size, newsize, size_elems);
+ *size = newsize; /* update only when everything else is OK */
+ return newblock;
+}
+
+
+l_noret luaM_toobig (lua_State *L) {
+ luaG_runerror(L, "memory allocation error: block too big");
+}
+
+
+
+/*
+** generic allocation routine.
+*/
+void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
+ void *newblock;
+ global_State *g = G(L);
+ size_t realosize = (block) ? osize : 0;
+ lua_assert((realosize == 0) == (block == NULL));
+#if defined(HARDMEMTESTS)
+ if (nsize > realosize && g->gcrunning)
+ luaC_fullgc(L, 1); /* force a GC whenever possible */
+#endif
+ newblock = (*g->frealloc)(g->ud, block, osize, nsize);
+ if (newblock == NULL && nsize > 0) {
+ lua_assert(nsize > realosize); /* cannot fail when shrinking a block */
+ if (g->version) { /* is state fully built? */
+ luaC_fullgc(L, 1); /* try to free some memory... */
+ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
+ }
+ if (newblock == NULL)
+ luaD_throw(L, LUA_ERRMEM);
+ }
+ lua_assert((nsize == 0) == (newblock == NULL));
+ g->GCdebt = (g->GCdebt + nsize) - realosize;
+ return newblock;
+}
+
diff --git a/external/lua-5.3.3/src/lmem.h b/external/lua-5.3.3/src/lmem.h
new file mode 100644
index 0000000..30f4848
--- /dev/null
+++ b/external/lua-5.3.3/src/lmem.h
@@ -0,0 +1,69 @@
+/*
+** $Id: lmem.h,v 1.43 2014/12/19 17:26:14 roberto Exp $
+** Interface to Memory Manager
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lmem_h
+#define lmem_h
+
+
+#include <stddef.h>
+
+#include "llimits.h"
+#include "lua.h"
+
+
+/*
+** This macro reallocs a vector 'b' from 'on' to 'n' elements, where
+** each element has size 'e'. In case of arithmetic overflow of the
+** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because
+** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e).
+**
+** (The macro is somewhat complex to avoid warnings: The 'sizeof'
+** comparison avoids a runtime comparison when overflow cannot occur.
+** The compiler should be able to optimize the real test by itself, but
+** when it does it, it may give a warning about "comparison is always
+** false due to limited range of data type"; the +1 tricks the compiler,
+** avoiding this warning but also this optimization.)
+*/
+#define luaM_reallocv(L,b,on,n,e) \
+ (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \
+ ? luaM_toobig(L) : cast_void(0)) , \
+ luaM_realloc_(L, (b), (on)*(e), (n)*(e)))
+
+/*
+** Arrays of chars do not need any test
+*/
+#define luaM_reallocvchar(L,b,on,n) \
+ cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char)))
+
+#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0)
+#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0)
+#define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0)
+
+#define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s))
+#define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t)))
+#define luaM_newvector(L,n,t) \
+ cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t)))
+
+#define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s))
+
+#define luaM_growvector(L,v,nelems,size,t,limit,e) \
+ if ((nelems)+1 > (size)) \
+ ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e)))
+
+#define luaM_reallocvector(L, v,oldn,n,t) \
+ ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t))))
+
+LUAI_FUNC l_noret luaM_toobig (lua_State *L);
+
+/* not to be called directly */
+LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
+ size_t size);
+LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size,
+ size_t size_elem, int limit,
+ const char *what);
+
+#endif
+
diff --git a/external/lua-5.3.3/src/loadlib.c b/external/lua-5.3.3/src/loadlib.c
new file mode 100644
index 0000000..7911928
--- /dev/null
+++ b/external/lua-5.3.3/src/loadlib.c
@@ -0,0 +1,787 @@
+/*
+** $Id: loadlib.c,v 1.127 2015/11/23 11:30:45 roberto Exp $
+** Dynamic library loader for Lua
+** See Copyright Notice in lua.h
+**
+** This module contains an implementation of loadlib for Unix systems
+** that have dlfcn, an implementation for Windows, and a stub for other
+** systems.
+*/
+
+#define loadlib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/*
+** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
+** variables that Lua check to set its paths.
+*/
+#if !defined(LUA_PATH_VAR)
+#define LUA_PATH_VAR "LUA_PATH"
+#endif
+
+#if !defined(LUA_CPATH_VAR)
+#define LUA_CPATH_VAR "LUA_CPATH"
+#endif
+
+#define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
+
+#define LUA_PATHVARVERSION LUA_PATH_VAR LUA_PATHSUFFIX
+#define LUA_CPATHVARVERSION LUA_CPATH_VAR LUA_PATHSUFFIX
+
+/*
+** LUA_PATH_SEP is the character that separates templates in a path.
+** LUA_PATH_MARK is the string that marks the substitution points in a
+** template.
+** LUA_EXEC_DIR in a Windows path is replaced by the executable's
+** directory.
+** LUA_IGMARK is a mark to ignore all before it when building the
+** luaopen_ function name.
+*/
+#if !defined (LUA_PATH_SEP)
+#define LUA_PATH_SEP ";"
+#endif
+#if !defined (LUA_PATH_MARK)
+#define LUA_PATH_MARK "?"
+#endif
+#if !defined (LUA_EXEC_DIR)
+#define LUA_EXEC_DIR "!"
+#endif
+#if !defined (LUA_IGMARK)
+#define LUA_IGMARK "-"
+#endif
+
+
+/*
+** LUA_CSUBSEP is the character that replaces dots in submodule names
+** when searching for a C loader.
+** LUA_LSUBSEP is the character that replaces dots in submodule names
+** when searching for a Lua loader.
+*/
+#if !defined(LUA_CSUBSEP)
+#define LUA_CSUBSEP LUA_DIRSEP
+#endif
+
+#if !defined(LUA_LSUBSEP)
+#define LUA_LSUBSEP LUA_DIRSEP
+#endif
+
+
+/* prefix for open functions in C libraries */
+#define LUA_POF "luaopen_"
+
+/* separator for open functions in C libraries */
+#define LUA_OFSEP "_"
+
+
+/*
+** unique key for table in the registry that keeps handles
+** for all loaded C libraries
+*/
+static const int CLIBS = 0;
+
+#define LIB_FAIL "open"
+
+#define setprogdir(L) ((void)0)
+
+
+/*
+** system-dependent functions
+*/
+
+/*
+** unload library 'lib'
+*/
+static void lsys_unloadlib (void *lib);
+
+/*
+** load C library in file 'path'. If 'seeglb', load with all names in
+** the library global.
+** Returns the library; in case of error, returns NULL plus an
+** error string in the stack.
+*/
+static void *lsys_load (lua_State *L, const char *path, int seeglb);
+
+/*
+** Try to find a function named 'sym' in library 'lib'.
+** Returns the function; in case of error, returns NULL plus an
+** error string in the stack.
+*/
+static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym);
+
+
+
+
+#if defined(LUA_USE_DLOPEN) /* { */
+/*
+** {========================================================================
+** This is an implementation of loadlib based on the dlfcn interface.
+** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
+** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
+** as an emulation layer on top of native functions.
+** =========================================================================
+*/
+
+#include <dlfcn.h>
+
+/*
+** Macro to convert pointer-to-void* to pointer-to-function. This cast
+** is undefined according to ISO C, but POSIX assumes that it works.
+** (The '__extension__' in gnu compilers is only to avoid warnings.)
+*/
+#if defined(__GNUC__)
+#define cast_func(p) (__extension__ (lua_CFunction)(p))
+#else
+#define cast_func(p) ((lua_CFunction)(p))
+#endif
+
+
+static void lsys_unloadlib (void *lib) {
+ dlclose(lib);
+}
+
+
+static void *lsys_load (lua_State *L, const char *path, int seeglb) {
+ void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL));
+ if (lib == NULL) lua_pushstring(L, dlerror());
+ return lib;
+}
+
+
+static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
+ lua_CFunction f = cast_func(dlsym(lib, sym));
+ if (f == NULL) lua_pushstring(L, dlerror());
+ return f;
+}
+
+/* }====================================================== */
+
+
+
+#elif defined(LUA_DL_DLL) /* }{ */
+/*
+** {======================================================================
+** This is an implementation of loadlib for Windows using native functions.
+** =======================================================================
+*/
+
+#include <windows.h>
+
+#undef setprogdir
+
+/*
+** optional flags for LoadLibraryEx
+*/
+#if !defined(LUA_LLE_FLAGS)
+#define LUA_LLE_FLAGS 0
+#endif
+
+
+static void setprogdir (lua_State *L) {
+ char buff[MAX_PATH + 1];
+ char *lb;
+ DWORD nsize = sizeof(buff)/sizeof(char);
+ DWORD n = GetModuleFileNameA(NULL, buff, nsize);
+ if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
+ luaL_error(L, "unable to get ModuleFileName");
+ else {
+ *lb = '\0';
+ luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff);
+ lua_remove(L, -2); /* remove original string */
+ }
+}
+
+
+static void pusherror (lua_State *L) {
+ int error = GetLastError();
+ char buffer[128];
+ if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL))
+ lua_pushstring(L, buffer);
+ else
+ lua_pushfstring(L, "system error %d\n", error);
+}
+
+static void lsys_unloadlib (void *lib) {
+ FreeLibrary((HMODULE)lib);
+}
+
+
+static void *lsys_load (lua_State *L, const char *path, int seeglb) {
+ HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS);
+ (void)(seeglb); /* not used: symbols are 'global' by default */
+ if (lib == NULL) pusherror(L);
+ return lib;
+}
+
+
+static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
+ lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym);
+ if (f == NULL) pusherror(L);
+ return f;
+}
+
+/* }====================================================== */
+
+
+#else /* }{ */
+/*
+** {======================================================
+** Fallback for other systems
+** =======================================================
+*/
+
+#undef LIB_FAIL
+#define LIB_FAIL "absent"
+
+
+#define DLMSG "dynamic libraries not enabled; check your Lua installation"
+
+
+static void lsys_unloadlib (void *lib) {
+ (void)(lib); /* not used */
+}
+
+
+static void *lsys_load (lua_State *L, const char *path, int seeglb) {
+ (void)(path); (void)(seeglb); /* not used */
+ lua_pushliteral(L, DLMSG);
+ return NULL;
+}
+
+
+static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
+ (void)(lib); (void)(sym); /* not used */
+ lua_pushliteral(L, DLMSG);
+ return NULL;
+}
+
+/* }====================================================== */
+#endif /* } */
+
+
+/*
+** return registry.CLIBS[path]
+*/
+static void *checkclib (lua_State *L, const char *path) {
+ void *plib;
+ lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS);
+ lua_getfield(L, -1, path);
+ plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */
+ lua_pop(L, 2); /* pop CLIBS table and 'plib' */
+ return plib;
+}
+
+
+/*
+** registry.CLIBS[path] = plib -- for queries
+** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries
+*/
+static void addtoclib (lua_State *L, const char *path, void *plib) {
+ lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS);
+ lua_pushlightuserdata(L, plib);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -3, path); /* CLIBS[path] = plib */
+ lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */
+ lua_pop(L, 1); /* pop CLIBS table */
+}
+
+
+/*
+** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib
+** handles in list CLIBS
+*/
+static int gctm (lua_State *L) {
+ lua_Integer n = luaL_len(L, 1);
+ for (; n >= 1; n--) { /* for each handle, in reverse order */
+ lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */
+ lsys_unloadlib(lua_touserdata(L, -1));
+ lua_pop(L, 1); /* pop handle */
+ }
+ return 0;
+}
+
+
+
+/* error codes for 'lookforfunc' */
+#define ERRLIB 1
+#define ERRFUNC 2
+
+/*
+** Look for a C function named 'sym' in a dynamically loaded library
+** 'path'.
+** First, check whether the library is already loaded; if not, try
+** to load it.
+** Then, if 'sym' is '*', return true (as library has been loaded).
+** Otherwise, look for symbol 'sym' in the library and push a
+** C function with that symbol.
+** Return 0 and 'true' or a function in the stack; in case of
+** errors, return an error code and an error message in the stack.
+*/
+static int lookforfunc (lua_State *L, const char *path, const char *sym) {
+ void *reg = checkclib(L, path); /* check loaded C libraries */
+ if (reg == NULL) { /* must load library? */
+ reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */
+ if (reg == NULL) return ERRLIB; /* unable to load library */
+ addtoclib(L, path, reg);
+ }
+ if (*sym == '*') { /* loading only library (no function)? */
+ lua_pushboolean(L, 1); /* return 'true' */
+ return 0; /* no errors */
+ }
+ else {
+ lua_CFunction f = lsys_sym(L, reg, sym);
+ if (f == NULL)
+ return ERRFUNC; /* unable to find function */
+ lua_pushcfunction(L, f); /* else create new function */
+ return 0; /* no errors */
+ }
+}
+
+
+static int ll_loadlib (lua_State *L) {
+ const char *path = luaL_checkstring(L, 1);
+ const char *init = luaL_checkstring(L, 2);
+ int stat = lookforfunc(L, path, init);
+ if (stat == 0) /* no errors? */
+ return 1; /* return the loaded function */
+ else { /* error; error message is on stack top */
+ lua_pushnil(L);
+ lua_insert(L, -2);
+ lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init");
+ return 3; /* return nil, error message, and where */
+ }
+}
+
+
+
+/*
+** {======================================================
+** 'require' function
+** =======================================================
+*/
+
+
+static int readable (const char *filename) {
+ FILE *f = fopen(filename, "r"); /* try to open file */
+ if (f == NULL) return 0; /* open failed */
+ fclose(f);
+ return 1;
+}
+
+
+static const char *pushnexttemplate (lua_State *L, const char *path) {
+ const char *l;
+ while (*path == *LUA_PATH_SEP) path++; /* skip separators */
+ if (*path == '\0') return NULL; /* no more templates */
+ l = strchr(path, *LUA_PATH_SEP); /* find next separator */
+ if (l == NULL) l = path + strlen(path);
+ lua_pushlstring(L, path, l - path); /* template */
+ return l;
+}
+
+
+static const char *searchpath (lua_State *L, const char *name,
+ const char *path,
+ const char *sep,
+ const char *dirsep) {
+ luaL_Buffer msg; /* to build error message */
+ luaL_buffinit(L, &msg);
+ if (*sep != '\0') /* non-empty separator? */
+ name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */
+ while ((path = pushnexttemplate(L, path)) != NULL) {
+ const char *filename = luaL_gsub(L, lua_tostring(L, -1),
+ LUA_PATH_MARK, name);
+ lua_remove(L, -2); /* remove path template */
+ if (readable(filename)) /* does file exist and is readable? */
+ return filename; /* return that file name */
+ lua_pushfstring(L, "\n\tno file '%s'", filename);
+ lua_remove(L, -2); /* remove file name */
+ luaL_addvalue(&msg); /* concatenate error msg. entry */
+ }
+ luaL_pushresult(&msg); /* create error message */
+ return NULL; /* not found */
+}
+
+
+static int ll_searchpath (lua_State *L) {
+ const char *f = searchpath(L, luaL_checkstring(L, 1),
+ luaL_checkstring(L, 2),
+ luaL_optstring(L, 3, "."),
+ luaL_optstring(L, 4, LUA_DIRSEP));
+ if (f != NULL) return 1;
+ else { /* error message is on top of the stack */
+ lua_pushnil(L);
+ lua_insert(L, -2);
+ return 2; /* return nil + error message */
+ }
+}
+
+
+static const char *findfile (lua_State *L, const char *name,
+ const char *pname,
+ const char *dirsep) {
+ const char *path;
+ lua_getfield(L, lua_upvalueindex(1), pname);
+ path = lua_tostring(L, -1);
+ if (path == NULL)
+ luaL_error(L, "'package.%s' must be a string", pname);
+ return searchpath(L, name, path, ".", dirsep);
+}
+
+
+static int checkload (lua_State *L, int stat, const char *filename) {
+ if (stat) { /* module loaded successfully? */
+ lua_pushstring(L, filename); /* will be 2nd argument to module */
+ return 2; /* return open function and file name */
+ }
+ else
+ return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s",
+ lua_tostring(L, 1), filename, lua_tostring(L, -1));
+}
+
+
+static int searcher_Lua (lua_State *L) {
+ const char *filename;
+ const char *name = luaL_checkstring(L, 1);
+ filename = findfile(L, name, "path", LUA_LSUBSEP);
+ if (filename == NULL) return 1; /* module not found in this path */
+ return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename);
+}
+
+
+/*
+** Try to find a load function for module 'modname' at file 'filename'.
+** First, change '.' to '_' in 'modname'; then, if 'modname' has
+** the form X-Y (that is, it has an "ignore mark"), build a function
+** name "luaopen_X" and look for it. (For compatibility, if that
+** fails, it also tries "luaopen_Y".) If there is no ignore mark,
+** look for a function named "luaopen_modname".
+*/
+static int loadfunc (lua_State *L, const char *filename, const char *modname) {
+ const char *openfunc;
+ const char *mark;
+ modname = luaL_gsub(L, modname, ".", LUA_OFSEP);
+ mark = strchr(modname, *LUA_IGMARK);
+ if (mark) {
+ int stat;
+ openfunc = lua_pushlstring(L, modname, mark - modname);
+ openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc);
+ stat = lookforfunc(L, filename, openfunc);
+ if (stat != ERRFUNC) return stat;
+ modname = mark + 1; /* else go ahead and try old-style name */
+ }
+ openfunc = lua_pushfstring(L, LUA_POF"%s", modname);
+ return lookforfunc(L, filename, openfunc);
+}
+
+
+static int searcher_C (lua_State *L) {
+ const char *name = luaL_checkstring(L, 1);
+ const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP);
+ if (filename == NULL) return 1; /* module not found in this path */
+ return checkload(L, (loadfunc(L, filename, name) == 0), filename);
+}
+
+
+static int searcher_Croot (lua_State *L) {
+ const char *filename;
+ const char *name = luaL_checkstring(L, 1);
+ const char *p = strchr(name, '.');
+ int stat;
+ if (p == NULL) return 0; /* is root */
+ lua_pushlstring(L, name, p - name);
+ filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP);
+ if (filename == NULL) return 1; /* root not found */
+ if ((stat = loadfunc(L, filename, name)) != 0) {
+ if (stat != ERRFUNC)
+ return checkload(L, 0, filename); /* real error */
+ else { /* open function not found */
+ lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename);
+ return 1;
+ }
+ }
+ lua_pushstring(L, filename); /* will be 2nd argument to module */
+ return 2;
+}
+
+
+static int searcher_preload (lua_State *L) {
+ const char *name = luaL_checkstring(L, 1);
+ lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD");
+ if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */
+ lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
+ return 1;
+}
+
+
+static void findloader (lua_State *L, const char *name) {
+ int i;
+ luaL_Buffer msg; /* to build error message */
+ luaL_buffinit(L, &msg);
+ /* push 'package.searchers' to index 3 in the stack */
+ if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE)
+ luaL_error(L, "'package.searchers' must be a table");
+ /* iterate over available searchers to find a loader */
+ for (i = 1; ; i++) {
+ if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */
+ lua_pop(L, 1); /* remove nil */
+ luaL_pushresult(&msg); /* create error message */
+ luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));
+ }
+ lua_pushstring(L, name);
+ lua_call(L, 1, 2); /* call it */
+ if (lua_isfunction(L, -2)) /* did it find a loader? */
+ return; /* module loader found */
+ else if (lua_isstring(L, -2)) { /* searcher returned error message? */
+ lua_pop(L, 1); /* remove extra return */
+ luaL_addvalue(&msg); /* concatenate error message */
+ }
+ else
+ lua_pop(L, 2); /* remove both returns */
+ }
+}
+
+
+static int ll_require (lua_State *L) {
+ const char *name = luaL_checkstring(L, 1);
+ lua_settop(L, 1); /* _LOADED table will be at index 2 */
+ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+ lua_getfield(L, 2, name); /* _LOADED[name] */
+ if (lua_toboolean(L, -1)) /* is it there? */
+ return 1; /* package is already loaded */
+ /* else must load package */
+ lua_pop(L, 1); /* remove 'getfield' result */
+ findloader(L, name);
+ lua_pushstring(L, name); /* pass name as argument to module loader */
+ lua_insert(L, -2); /* name is 1st argument (before search data) */
+ lua_call(L, 2, 1); /* run loader to load module */
+ if (!lua_isnil(L, -1)) /* non-nil return? */
+ lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
+ if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
+ lua_pushboolean(L, 1); /* use true as result */
+ lua_pushvalue(L, -1); /* extra copy to be returned */
+ lua_setfield(L, 2, name); /* _LOADED[name] = true */
+ }
+ return 1;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** 'module' function
+** =======================================================
+*/
+#if defined(LUA_COMPAT_MODULE)
+
+/*
+** changes the environment variable of calling function
+*/
+static void set_env (lua_State *L) {
+ lua_Debug ar;
+ if (lua_getstack(L, 1, &ar) == 0 ||
+ lua_getinfo(L, "f", &ar) == 0 || /* get calling function */
+ lua_iscfunction(L, -1))
+ luaL_error(L, "'module' not called from a Lua function");
+ lua_pushvalue(L, -2); /* copy new environment table to top */
+ lua_setupvalue(L, -2, 1);
+ lua_pop(L, 1); /* remove function */
+}
+
+
+static void dooptions (lua_State *L, int n) {
+ int i;
+ for (i = 2; i <= n; i++) {
+ if (lua_isfunction(L, i)) { /* avoid 'calling' extra info. */
+ lua_pushvalue(L, i); /* get option (a function) */
+ lua_pushvalue(L, -2); /* module */
+ lua_call(L, 1, 0);
+ }
+ }
+}
+
+
+static void modinit (lua_State *L, const char *modname) {
+ const char *dot;
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "_M"); /* module._M = module */
+ lua_pushstring(L, modname);
+ lua_setfield(L, -2, "_NAME");
+ dot = strrchr(modname, '.'); /* look for last dot in module name */
+ if (dot == NULL) dot = modname;
+ else dot++;
+ /* set _PACKAGE as package name (full module name minus last part) */
+ lua_pushlstring(L, modname, dot - modname);
+ lua_setfield(L, -2, "_PACKAGE");
+}
+
+
+static int ll_module (lua_State *L) {
+ const char *modname = luaL_checkstring(L, 1);
+ int lastarg = lua_gettop(L); /* last parameter */
+ luaL_pushmodule(L, modname, 1); /* get/create module table */
+ /* check whether table already has a _NAME field */
+ if (lua_getfield(L, -1, "_NAME") != LUA_TNIL)
+ lua_pop(L, 1); /* table is an initialized module */
+ else { /* no; initialize it */
+ lua_pop(L, 1);
+ modinit(L, modname);
+ }
+ lua_pushvalue(L, -1);
+ set_env(L);
+ dooptions(L, lastarg);
+ return 1;
+}
+
+
+static int ll_seeall (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ if (!lua_getmetatable(L, 1)) {
+ lua_createtable(L, 0, 1); /* create new metatable */
+ lua_pushvalue(L, -1);
+ lua_setmetatable(L, 1);
+ }
+ lua_pushglobaltable(L);
+ lua_setfield(L, -2, "__index"); /* mt.__index = _G */
+ return 0;
+}
+
+#endif
+/* }====================================================== */
+
+
+
+/* auxiliary mark (for internal use) */
+#define AUXMARK "\1"
+
+
+/*
+** return registry.LUA_NOENV as a boolean
+*/
+static int noenv (lua_State *L) {
+ int b;
+ lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
+ b = lua_toboolean(L, -1);
+ lua_pop(L, 1); /* remove value */
+ return b;
+}
+
+
+static void setpath (lua_State *L, const char *fieldname, const char *envname1,
+ const char *envname2, const char *def) {
+ const char *path = getenv(envname1);
+ if (path == NULL) /* no environment variable? */
+ path = getenv(envname2); /* try alternative name */
+ if (path == NULL || noenv(L)) /* no environment variable? */
+ lua_pushstring(L, def); /* use default */
+ else {
+ /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
+ path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
+ LUA_PATH_SEP AUXMARK LUA_PATH_SEP);
+ luaL_gsub(L, path, AUXMARK, def);
+ lua_remove(L, -2);
+ }
+ setprogdir(L);
+ lua_setfield(L, -2, fieldname);
+}
+
+
+static const luaL_Reg pk_funcs[] = {
+ {"loadlib", ll_loadlib},
+ {"searchpath", ll_searchpath},
+#if defined(LUA_COMPAT_MODULE)
+ {"seeall", ll_seeall},
+#endif
+ /* placeholders */
+ {"preload", NULL},
+ {"cpath", NULL},
+ {"path", NULL},
+ {"searchers", NULL},
+ {"loaded", NULL},
+ {NULL, NULL}
+};
+
+
+static const luaL_Reg ll_funcs[] = {
+#if defined(LUA_COMPAT_MODULE)
+ {"module", ll_module},
+#endif
+ {"require", ll_require},
+ {NULL, NULL}
+};
+
+
+static void createsearcherstable (lua_State *L) {
+ static const lua_CFunction searchers[] =
+ {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
+ int i;
+ /* create 'searchers' table */
+ lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
+ /* fill it with predefined searchers */
+ for (i=0; searchers[i] != NULL; i++) {
+ lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */
+ lua_pushcclosure(L, searchers[i], 1);
+ lua_rawseti(L, -2, i+1);
+ }
+#if defined(LUA_COMPAT_LOADERS)
+ lua_pushvalue(L, -1); /* make a copy of 'searchers' table */
+ lua_setfield(L, -3, "loaders"); /* put it in field 'loaders' */
+#endif
+ lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */
+}
+
+
+/*
+** create table CLIBS to keep track of loaded C libraries,
+** setting a finalizer to close all libraries when closing state.
+*/
+static void createclibstable (lua_State *L) {
+ lua_newtable(L); /* create CLIBS table */
+ lua_createtable(L, 0, 1); /* create metatable for CLIBS */
+ lua_pushcfunction(L, gctm);
+ lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */
+ lua_setmetatable(L, -2);
+ lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */
+}
+
+
+LUAMOD_API int luaopen_package (lua_State *L) {
+ createclibstable(L);
+ luaL_newlib(L, pk_funcs); /* create 'package' table */
+ createsearcherstable(L);
+ /* set field 'path' */
+ setpath(L, "path", LUA_PATHVARVERSION, LUA_PATH_VAR, LUA_PATH_DEFAULT);
+ /* set field 'cpath' */
+ setpath(L, "cpath", LUA_CPATHVARVERSION, LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
+ /* store config information */
+ lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
+ LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
+ lua_setfield(L, -2, "config");
+ /* set field 'loaded' */
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
+ lua_setfield(L, -2, "loaded");
+ /* set field 'preload' */
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
+ lua_setfield(L, -2, "preload");
+ lua_pushglobaltable(L);
+ lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */
+ luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */
+ lua_pop(L, 1); /* pop global table */
+ return 1; /* return 'package' table */
+}
+
diff --git a/external/lua-5.3.3/src/lobject.c b/external/lua-5.3.3/src/lobject.c
new file mode 100644
index 0000000..a44b385
--- /dev/null
+++ b/external/lua-5.3.3/src/lobject.c
@@ -0,0 +1,521 @@
+/*
+** $Id: lobject.c,v 2.111 2016/05/20 14:07:48 roberto Exp $
+** Some generic functions over Lua objects
+** See Copyright Notice in lua.h
+*/
+
+#define lobject_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <locale.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lctype.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "lvm.h"
+
+
+
+LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT};
+
+
+/*
+** converts an integer to a "floating point byte", represented as
+** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
+** eeeee != 0 and (xxx) otherwise.
+*/
+int luaO_int2fb (unsigned int x) {
+ int e = 0; /* exponent */
+ if (x < 8) return x;
+ while (x >= (8 << 4)) { /* coarse steps */
+ x = (x + 0xf) >> 4; /* x = ceil(x / 16) */
+ e += 4;
+ }
+ while (x >= (8 << 1)) { /* fine steps */
+ x = (x + 1) >> 1; /* x = ceil(x / 2) */
+ e++;
+ }
+ return ((e+1) << 3) | (cast_int(x) - 8);
+}
+
+
+/* converts back */
+int luaO_fb2int (int x) {
+ return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1);
+}
+
+
+/*
+** Computes ceil(log2(x))
+*/
+int luaO_ceillog2 (unsigned int x) {
+ static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */
+ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
+ };
+ int l = 0;
+ x--;
+ while (x >= 256) { l += 8; x >>= 8; }
+ return l + log_2[x];
+}
+
+
+static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
+ lua_Integer v2) {
+ switch (op) {
+ case LUA_OPADD: return intop(+, v1, v2);
+ case LUA_OPSUB:return intop(-, v1, v2);
+ case LUA_OPMUL:return intop(*, v1, v2);
+ case LUA_OPMOD: return luaV_mod(L, v1, v2);
+ case LUA_OPIDIV: return luaV_div(L, v1, v2);
+ case LUA_OPBAND: return intop(&, v1, v2);
+ case LUA_OPBOR: return intop(|, v1, v2);
+ case LUA_OPBXOR: return intop(^, v1, v2);
+ case LUA_OPSHL: return luaV_shiftl(v1, v2);
+ case LUA_OPSHR: return luaV_shiftl(v1, -v2);
+ case LUA_OPUNM: return intop(-, 0, v1);
+ case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
+ default: lua_assert(0); return 0;
+ }
+}
+
+
+static lua_Number numarith (lua_State *L, int op, lua_Number v1,
+ lua_Number v2) {
+ switch (op) {
+ case LUA_OPADD: return luai_numadd(L, v1, v2);
+ case LUA_OPSUB: return luai_numsub(L, v1, v2);
+ case LUA_OPMUL: return luai_nummul(L, v1, v2);
+ case LUA_OPDIV: return luai_numdiv(L, v1, v2);
+ case LUA_OPPOW: return luai_numpow(L, v1, v2);
+ case LUA_OPIDIV: return luai_numidiv(L, v1, v2);
+ case LUA_OPUNM: return luai_numunm(L, v1);
+ case LUA_OPMOD: {
+ lua_Number m;
+ luai_nummod(L, v1, v2, m);
+ return m;
+ }
+ default: lua_assert(0); return 0;
+ }
+}
+
+
+void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2,
+ TValue *res) {
+ switch (op) {
+ case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:
+ case LUA_OPSHL: case LUA_OPSHR:
+ case LUA_OPBNOT: { /* operate only on integers */
+ lua_Integer i1; lua_Integer i2;
+ if (tointeger(p1, &i1) && tointeger(p2, &i2)) {
+ setivalue(res, intarith(L, op, i1, i2));
+ return;
+ }
+ else break; /* go to the end */
+ }
+ case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */
+ lua_Number n1; lua_Number n2;
+ if (tonumber(p1, &n1) && tonumber(p2, &n2)) {
+ setfltvalue(res, numarith(L, op, n1, n2));
+ return;
+ }
+ else break; /* go to the end */
+ }
+ default: { /* other operations */
+ lua_Number n1; lua_Number n2;
+ if (ttisinteger(p1) && ttisinteger(p2)) {
+ setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2)));
+ return;
+ }
+ else if (tonumber(p1, &n1) && tonumber(p2, &n2)) {
+ setfltvalue(res, numarith(L, op, n1, n2));
+ return;
+ }
+ else break; /* go to the end */
+ }
+ }
+ /* could not perform raw operation; try metamethod */
+ lua_assert(L != NULL); /* should not fail when folding (compile time) */
+ luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD));
+}
+
+
+int luaO_hexavalue (int c) {
+ if (lisdigit(c)) return c - '0';
+ else return (ltolower(c) - 'a') + 10;
+}
+
+
+static int isneg (const char **s) {
+ if (**s == '-') { (*s)++; return 1; }
+ else if (**s == '+') (*s)++;
+ return 0;
+}
+
+
+
+/*
+** {==================================================================
+** Lua's implementation for 'lua_strx2number'
+** ===================================================================
+*/
+
+#if !defined(lua_strx2number)
+
+/* maximum number of significant digits to read (to avoid overflows
+ even with single floats) */
+#define MAXSIGDIG 30
+
+/*
+** convert an hexadecimal numeric string to a number, following
+** C99 specification for 'strtod'
+*/
+static lua_Number lua_strx2number (const char *s, char **endptr) {
+ int dot = lua_getlocaledecpoint();
+ lua_Number r = 0.0; /* result (accumulator) */
+ int sigdig = 0; /* number of significant digits */
+ int nosigdig = 0; /* number of non-significant digits */
+ int e = 0; /* exponent correction */
+ int neg; /* 1 if number is negative */
+ int hasdot = 0; /* true after seen a dot */
+ *endptr = cast(char *, s); /* nothing is valid yet */
+ while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
+ neg = isneg(&s); /* check signal */
+ if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
+ return 0.0; /* invalid format (no '0x') */
+ for (s += 2; ; s++) { /* skip '0x' and read numeral */
+ if (*s == dot) {
+ if (hasdot) break; /* second dot? stop loop */
+ else hasdot = 1;
+ }
+ else if (lisxdigit(cast_uchar(*s))) {
+ if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
+ nosigdig++;
+ else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
+ r = (r * cast_num(16.0)) + luaO_hexavalue(*s);
+ else e++; /* too many digits; ignore, but still count for exponent */
+ if (hasdot) e--; /* decimal digit? correct exponent */
+ }
+ else break; /* neither a dot nor a digit */
+ }
+ if (nosigdig + sigdig == 0) /* no digits? */
+ return 0.0; /* invalid format */
+ *endptr = cast(char *, s); /* valid up to here */
+ e *= 4; /* each digit multiplies/divides value by 2^4 */
+ if (*s == 'p' || *s == 'P') { /* exponent part? */
+ int exp1 = 0; /* exponent value */
+ int neg1; /* exponent signal */
+ s++; /* skip 'p' */
+ neg1 = isneg(&s); /* signal */
+ if (!lisdigit(cast_uchar(*s)))
+ return 0.0; /* invalid; must have at least one digit */
+ while (lisdigit(cast_uchar(*s))) /* read exponent */
+ exp1 = exp1 * 10 + *(s++) - '0';
+ if (neg1) exp1 = -exp1;
+ e += exp1;
+ *endptr = cast(char *, s); /* valid up to here */
+ }
+ if (neg) r = -r;
+ return l_mathop(ldexp)(r, e);
+}
+
+#endif
+/* }====================================================== */
+
+
+/* maximum length of a numeral */
+#if !defined (L_MAXLENNUM)
+#define L_MAXLENNUM 200
+#endif
+
+static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
+ char *endptr;
+ *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */
+ : lua_str2number(s, &endptr);
+ if (endptr == s) return NULL; /* nothing recognized? */
+ while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */
+ return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */
+}
+
+
+/*
+** Convert string 's' to a Lua number (put in 'result'). Return NULL
+** on fail or the address of the ending '\0' on success.
+** 'pmode' points to (and 'mode' contains) special things in the string:
+** - 'x'/'X' means an hexadecimal numeral
+** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)
+** - '.' just optimizes the search for the common case (nothing special)
+** This function accepts both the current locale or a dot as the radix
+** mark. If the convertion fails, it may mean number has a dot but
+** locale accepts something else. In that case, the code copies 's'
+** to a buffer (because 's' is read-only), changes the dot to the
+** current locale radix mark, and tries to convert again.
+*/
+static const char *l_str2d (const char *s, lua_Number *result) {
+ const char *endptr;
+ const char *pmode = strpbrk(s, ".xXnN");
+ int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
+ if (mode == 'n') /* reject 'inf' and 'nan' */
+ return NULL;
+ endptr = l_str2dloc(s, result, mode); /* try to convert */
+ if (endptr == NULL) { /* failed? may be a different locale */
+ char buff[L_MAXLENNUM + 1];
+ char *pdot = strchr(s, '.');
+ if (strlen(s) > L_MAXLENNUM || pdot == NULL)
+ return NULL; /* string too long or no dot; fail */
+ strcpy(buff, s); /* copy string to buffer */
+ buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */
+ endptr = l_str2dloc(buff, result, mode); /* try again */
+ if (endptr != NULL)
+ endptr = s + (endptr - buff); /* make relative to 's' */
+ }
+ return endptr;
+}
+
+
+#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10)
+#define MAXLASTD cast_int(LUA_MAXINTEGER % 10)
+
+static const char *l_str2int (const char *s, lua_Integer *result) {
+ lua_Unsigned a = 0;
+ int empty = 1;
+ int neg;
+ while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
+ neg = isneg(&s);
+ if (s[0] == '0' &&
+ (s[1] == 'x' || s[1] == 'X')) { /* hex? */
+ s += 2; /* skip '0x' */
+ for (; lisxdigit(cast_uchar(*s)); s++) {
+ a = a * 16 + luaO_hexavalue(*s);
+ empty = 0;
+ }
+ }
+ else { /* decimal */
+ for (; lisdigit(cast_uchar(*s)); s++) {
+ int d = *s - '0';
+ if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
+ return NULL; /* do not accept it (as integer) */
+ a = a * 10 + d;
+ empty = 0;
+ }
+ }
+ while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */
+ if (empty || *s != '\0') return NULL; /* something wrong in the numeral */
+ else {
+ *result = l_castU2S((neg) ? 0u - a : a);
+ return s;
+ }
+}
+
+
+size_t luaO_str2num (const char *s, TValue *o) {
+ lua_Integer i; lua_Number n;
+ const char *e;
+ if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */
+ setivalue(o, i);
+ }
+ else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */
+ setfltvalue(o, n);
+ }
+ else
+ return 0; /* conversion failed */
+ return (e - s) + 1; /* success; return string size */
+}
+
+
+int luaO_utf8esc (char *buff, unsigned long x) {
+ int n = 1; /* number of bytes put in buffer (backwards) */
+ lua_assert(x <= 0x10FFFF);
+ if (x < 0x80) /* ascii? */
+ buff[UTF8BUFFSZ - 1] = cast(char, x);
+ else { /* need continuation bytes */
+ unsigned int mfb = 0x3f; /* maximum that fits in first byte */
+ do { /* add continuation bytes */
+ buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f));
+ x >>= 6; /* remove added bits */
+ mfb >>= 1; /* now there is one less bit available in first byte */
+ } while (x > mfb); /* still needs continuation byte? */
+ buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x); /* add first byte */
+ }
+ return n;
+}
+
+
+/* maximum length of the conversion of a number to a string */
+#define MAXNUMBER2STR 50
+
+
+/*
+** Convert a number object to a string
+*/
+void luaO_tostring (lua_State *L, StkId obj) {
+ char buff[MAXNUMBER2STR];
+ size_t len;
+ lua_assert(ttisnumber(obj));
+ if (ttisinteger(obj))
+ len = lua_integer2str(buff, sizeof(buff), ivalue(obj));
+ else {
+ len = lua_number2str(buff, sizeof(buff), fltvalue(obj));
+#if !defined(LUA_COMPAT_FLOATSTRING)
+ if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */
+ buff[len++] = lua_getlocaledecpoint();
+ buff[len++] = '0'; /* adds '.0' to result */
+ }
+#endif
+ }
+ setsvalue2s(L, obj, luaS_newlstr(L, buff, len));
+}
+
+
+static void pushstr (lua_State *L, const char *str, size_t l) {
+ setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
+ luaD_inctop(L);
+}
+
+
+/*
+** this function handles only '%d', '%c', '%f', '%p', and '%s'
+ conventional formats, plus Lua-specific '%I' and '%U'
+*/
+const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
+ int n = 0;
+ for (;;) {
+ const char *e = strchr(fmt, '%');
+ if (e == NULL) break;
+ pushstr(L, fmt, e - fmt);
+ switch (*(e+1)) {
+ case 's': { /* zero-terminated string */
+ const char *s = va_arg(argp, char *);
+ if (s == NULL) s = "(null)";
+ pushstr(L, s, strlen(s));
+ break;
+ }
+ case 'c': { /* an 'int' as a character */
+ char buff = cast(char, va_arg(argp, int));
+ if (lisprint(cast_uchar(buff)))
+ pushstr(L, &buff, 1);
+ else /* non-printable character; print its code */
+ luaO_pushfstring(L, "<\\%d>", cast_uchar(buff));
+ break;
+ }
+ case 'd': { /* an 'int' */
+ setivalue(L->top, va_arg(argp, int));
+ goto top2str;
+ }
+ case 'I': { /* a 'lua_Integer' */
+ setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt)));
+ goto top2str;
+ }
+ case 'f': { /* a 'lua_Number' */
+ setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
+ top2str: /* convert the top element to a string */
+ luaD_inctop(L);
+ luaO_tostring(L, L->top - 1);
+ break;
+ }
+ case 'p': { /* a pointer */
+ char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */
+ int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *));
+ pushstr(L, buff, l);
+ break;
+ }
+ case 'U': { /* an 'int' as a UTF-8 sequence */
+ char buff[UTF8BUFFSZ];
+ int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));
+ pushstr(L, buff + UTF8BUFFSZ - l, l);
+ break;
+ }
+ case '%': {
+ pushstr(L, "%", 1);
+ break;
+ }
+ default: {
+ luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'",
+ *(e + 1));
+ }
+ }
+ n += 2;
+ fmt = e+2;
+ }
+ luaD_checkstack(L, 1);
+ pushstr(L, fmt, strlen(fmt));
+ if (n > 0) luaV_concat(L, n + 1);
+ return svalue(L->top - 1);
+}
+
+
+const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
+ const char *msg;
+ va_list argp;
+ va_start(argp, fmt);
+ msg = luaO_pushvfstring(L, fmt, argp);
+ va_end(argp);
+ return msg;
+}
+
+
+/* number of chars of a literal string without the ending \0 */
+#define LL(x) (sizeof(x)/sizeof(char) - 1)
+
+#define RETS "..."
+#define PRE "[string \""
+#define POS "\"]"
+
+#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) )
+
+void luaO_chunkid (char *out, const char *source, size_t bufflen) {
+ size_t l = strlen(source);
+ if (*source == '=') { /* 'literal' source */
+ if (l <= bufflen) /* small enough? */
+ memcpy(out, source + 1, l * sizeof(char));
+ else { /* truncate it */
+ addstr(out, source + 1, bufflen - 1);
+ *out = '\0';
+ }
+ }
+ else if (*source == '@') { /* file name */
+ if (l <= bufflen) /* small enough? */
+ memcpy(out, source + 1, l * sizeof(char));
+ else { /* add '...' before rest of name */
+ addstr(out, RETS, LL(RETS));
+ bufflen -= LL(RETS);
+ memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char));
+ }
+ }
+ else { /* string; format as [string "source"] */
+ const char *nl = strchr(source, '\n'); /* find first new line (if any) */
+ addstr(out, PRE, LL(PRE)); /* add prefix */
+ bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */
+ if (l < bufflen && nl == NULL) { /* small one-line source? */
+ addstr(out, source, l); /* keep it */
+ }
+ else {
+ if (nl != NULL) l = nl - source; /* stop at first newline */
+ if (l > bufflen) l = bufflen;
+ addstr(out, source, l);
+ addstr(out, RETS, LL(RETS));
+ }
+ memcpy(out, POS, (LL(POS) + 1) * sizeof(char));
+ }
+}
+
diff --git a/external/lua-5.3.3/src/lobject.h b/external/lua-5.3.3/src/lobject.h
new file mode 100644
index 0000000..2d52b41
--- /dev/null
+++ b/external/lua-5.3.3/src/lobject.h
@@ -0,0 +1,549 @@
+/*
+** $Id: lobject.h,v 2.116 2015/11/03 18:33:10 roberto Exp $
+** Type definitions for Lua objects
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lobject_h
+#define lobject_h
+
+
+#include <stdarg.h>
+
+
+#include "llimits.h"
+#include "lua.h"
+
+
+/*
+** Extra tags for non-values
+*/
+#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */
+#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */
+
+/*
+** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
+*/
+#define LUA_TOTALTAGS (LUA_TPROTO + 2)
+
+
+/*
+** tags for Tagged Values have the following use of bits:
+** bits 0-3: actual tag (a LUA_T* value)
+** bits 4-5: variant bits
+** bit 6: whether value is collectable
+*/
+
+
+/*
+** LUA_TFUNCTION variants:
+** 0 - Lua function
+** 1 - light C function
+** 2 - regular C function (closure)
+*/
+
+/* Variant tags for functions */
+#define LUA_TLCL (LUA_TFUNCTION | (0 << 4)) /* Lua closure */
+#define LUA_TLCF (LUA_TFUNCTION | (1 << 4)) /* light C function */
+#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */
+
+
+/* Variant tags for strings */
+#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */
+#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */
+
+
+/* Variant tags for numbers */
+#define LUA_TNUMFLT (LUA_TNUMBER | (0 << 4)) /* float numbers */
+#define LUA_TNUMINT (LUA_TNUMBER | (1 << 4)) /* integer numbers */
+
+
+/* Bit mark for collectable types */
+#define BIT_ISCOLLECTABLE (1 << 6)
+
+/* mark a tag as collectable */
+#define ctb(t) ((t) | BIT_ISCOLLECTABLE)
+
+
+/*
+** Common type for all collectable objects
+*/
+typedef struct GCObject GCObject;
+
+
+/*
+** Common Header for all collectable objects (in macro form, to be
+** included in other objects)
+*/
+#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked
+
+
+/*
+** Common type has only the common header
+*/
+struct GCObject {
+ CommonHeader;
+};
+
+
+
+
+/*
+** Tagged Values. This is the basic representation of values in Lua,
+** an actual value plus a tag with its type.
+*/
+
+/*
+** Union of all Lua values
+*/
+typedef union Value {
+ GCObject *gc; /* collectable objects */
+ void *p; /* light userdata */
+ int b; /* booleans */
+ lua_CFunction f; /* light C functions */
+ lua_Integer i; /* integer numbers */
+ lua_Number n; /* float numbers */
+} Value;
+
+
+#define TValuefields Value value_; int tt_
+
+
+typedef struct lua_TValue {
+ TValuefields;
+} TValue;
+
+
+
+/* macro defining a nil value */
+#define NILCONSTANT {NULL}, LUA_TNIL
+
+
+#define val_(o) ((o)->value_)
+
+
+/* raw type tag of a TValue */
+#define rttype(o) ((o)->tt_)
+
+/* tag with no variants (bits 0-3) */
+#define novariant(x) ((x) & 0x0F)
+
+/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
+#define ttype(o) (rttype(o) & 0x3F)
+
+/* type tag of a TValue with no variants (bits 0-3) */
+#define ttnov(o) (novariant(rttype(o)))
+
+
+/* Macros to test type */
+#define checktag(o,t) (rttype(o) == (t))
+#define checktype(o,t) (ttnov(o) == (t))
+#define ttisnumber(o) checktype((o), LUA_TNUMBER)
+#define ttisfloat(o) checktag((o), LUA_TNUMFLT)
+#define ttisinteger(o) checktag((o), LUA_TNUMINT)
+#define ttisnil(o) checktag((o), LUA_TNIL)
+#define ttisboolean(o) checktag((o), LUA_TBOOLEAN)
+#define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA)
+#define ttisstring(o) checktype((o), LUA_TSTRING)
+#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR))
+#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR))
+#define ttistable(o) checktag((o), ctb(LUA_TTABLE))
+#define ttisfunction(o) checktype(o, LUA_TFUNCTION)
+#define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION)
+#define ttisCclosure(o) checktag((o), ctb(LUA_TCCL))
+#define ttisLclosure(o) checktag((o), ctb(LUA_TLCL))
+#define ttislcf(o) checktag((o), LUA_TLCF)
+#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA))
+#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD))
+#define ttisdeadkey(o) checktag((o), LUA_TDEADKEY)
+
+
+/* Macros to access values */
+#define ivalue(o) check_exp(ttisinteger(o), val_(o).i)
+#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n)
+#define nvalue(o) check_exp(ttisnumber(o), \
+ (ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o)))
+#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc)
+#define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p)
+#define tsvalue(o) check_exp(ttisstring(o), gco2ts(val_(o).gc))
+#define uvalue(o) check_exp(ttisfulluserdata(o), gco2u(val_(o).gc))
+#define clvalue(o) check_exp(ttisclosure(o), gco2cl(val_(o).gc))
+#define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc))
+#define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc))
+#define fvalue(o) check_exp(ttislcf(o), val_(o).f)
+#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc))
+#define bvalue(o) check_exp(ttisboolean(o), val_(o).b)
+#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc))
+/* a dead value may get the 'gc' field, but cannot access its contents */
+#define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc))
+
+#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
+
+
+#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE)
+
+
+/* Macros for internal tests */
+#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt)
+
+#define checkliveness(L,obj) \
+ lua_longassert(!iscollectable(obj) || \
+ (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))
+
+
+/* Macros to set values */
+#define settt_(o,t) ((o)->tt_=(t))
+
+#define setfltvalue(obj,x) \
+ { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); }
+
+#define chgfltvalue(obj,x) \
+ { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); }
+
+#define setivalue(obj,x) \
+ { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); }
+
+#define chgivalue(obj,x) \
+ { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); }
+
+#define setnilvalue(obj) settt_(obj, LUA_TNIL)
+
+#define setfvalue(obj,x) \
+ { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); }
+
+#define setpvalue(obj,x) \
+ { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); }
+
+#define setbvalue(obj,x) \
+ { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); }
+
+#define setgcovalue(L,obj,x) \
+ { TValue *io = (obj); GCObject *i_g=(x); \
+ val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); }
+
+#define setsvalue(L,obj,x) \
+ { TValue *io = (obj); TString *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \
+ checkliveness(L,io); }
+
+#define setuvalue(L,obj,x) \
+ { TValue *io = (obj); Udata *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \
+ checkliveness(L,io); }
+
+#define setthvalue(L,obj,x) \
+ { TValue *io = (obj); lua_State *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \
+ checkliveness(L,io); }
+
+#define setclLvalue(L,obj,x) \
+ { TValue *io = (obj); LClosure *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \
+ checkliveness(L,io); }
+
+#define setclCvalue(L,obj,x) \
+ { TValue *io = (obj); CClosure *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \
+ checkliveness(L,io); }
+
+#define sethvalue(L,obj,x) \
+ { TValue *io = (obj); Table *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
+ checkliveness(L,io); }
+
+#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
+
+
+
+#define setobj(L,obj1,obj2) \
+ { TValue *io1=(obj1); *io1 = *(obj2); \
+ (void)L; checkliveness(L,io1); }
+
+
+/*
+** different types of assignments, according to destination
+*/
+
+/* from stack to (same) stack */
+#define setobjs2s setobj
+/* to stack (not from same stack) */
+#define setobj2s setobj
+#define setsvalue2s setsvalue
+#define sethvalue2s sethvalue
+#define setptvalue2s setptvalue
+/* from table to same table */
+#define setobjt2t setobj
+/* to new object */
+#define setobj2n setobj
+#define setsvalue2n setsvalue
+
+/* to table (define it as an expression to be used in macros) */
+#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1)))
+
+
+
+
+/*
+** {======================================================
+** types and prototypes
+** =======================================================
+*/
+
+
+typedef TValue *StkId; /* index to stack elements */
+
+
+
+
+/*
+** Header for string value; string bytes follow the end of this structure
+** (aligned according to 'UTString'; see next).
+*/
+typedef struct TString {
+ CommonHeader;
+ lu_byte extra; /* reserved words for short strings; "has hash" for longs */
+ lu_byte shrlen; /* length for short strings */
+ unsigned int hash;
+ union {
+ size_t lnglen; /* length for long strings */
+ struct TString *hnext; /* linked list for hash table */
+ } u;
+} TString;
+
+
+/*
+** Ensures that address after this type is always fully aligned.
+*/
+typedef union UTString {
+ L_Umaxalign dummy; /* ensures maximum alignment for strings */
+ TString tsv;
+} UTString;
+
+
+/*
+** Get the actual string (array of bytes) from a 'TString'.
+** (Access to 'extra' ensures that value is really a 'TString'.)
+*/
+#define getstr(ts) \
+ check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString))
+
+
+/* get the actual string (array of bytes) from a Lua value */
+#define svalue(o) getstr(tsvalue(o))
+
+/* get string length from 'TString *s' */
+#define tsslen(s) ((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen)
+
+/* get string length from 'TValue *o' */
+#define vslen(o) tsslen(tsvalue(o))
+
+
+/*
+** Header for userdata; memory area follows the end of this structure
+** (aligned according to 'UUdata'; see next).
+*/
+typedef struct Udata {
+ CommonHeader;
+ lu_byte ttuv_; /* user value's tag */
+ struct Table *metatable;
+ size_t len; /* number of bytes */
+ union Value user_; /* user value */
+} Udata;
+
+
+/*
+** Ensures that address after this type is always fully aligned.
+*/
+typedef union UUdata {
+ L_Umaxalign dummy; /* ensures maximum alignment for 'local' udata */
+ Udata uv;
+} UUdata;
+
+
+/*
+** Get the address of memory block inside 'Udata'.
+** (Access to 'ttuv_' ensures that value is really a 'Udata'.)
+*/
+#define getudatamem(u) \
+ check_exp(sizeof((u)->ttuv_), (cast(char*, (u)) + sizeof(UUdata)))
+
+#define setuservalue(L,u,o) \
+ { const TValue *io=(o); Udata *iu = (u); \
+ iu->user_ = io->value_; iu->ttuv_ = rttype(io); \
+ checkliveness(L,io); }
+
+
+#define getuservalue(L,u,o) \
+ { TValue *io=(o); const Udata *iu = (u); \
+ io->value_ = iu->user_; settt_(io, iu->ttuv_); \
+ checkliveness(L,io); }
+
+
+/*
+** Description of an upvalue for function prototypes
+*/
+typedef struct Upvaldesc {
+ TString *name; /* upvalue name (for debug information) */
+ lu_byte instack; /* whether it is in stack (register) */
+ lu_byte idx; /* index of upvalue (in stack or in outer function's list) */
+} Upvaldesc;
+
+
+/*
+** Description of a local variable for function prototypes
+** (used for debug information)
+*/
+typedef struct LocVar {
+ TString *varname;
+ int startpc; /* first point where variable is active */
+ int endpc; /* first point where variable is dead */
+} LocVar;
+
+
+/*
+** Function Prototypes
+*/
+typedef struct Proto {
+ CommonHeader;
+ lu_byte numparams; /* number of fixed parameters */
+ lu_byte is_vararg; /* 2: declared vararg; 1: uses vararg */
+ lu_byte maxstacksize; /* number of registers needed by this function */
+ int sizeupvalues; /* size of 'upvalues' */
+ int sizek; /* size of 'k' */
+ int sizecode;
+ int sizelineinfo;
+ int sizep; /* size of 'p' */
+ int sizelocvars;
+ int linedefined; /* debug information */
+ int lastlinedefined; /* debug information */
+ TValue *k; /* constants used by the function */
+ Instruction *code; /* opcodes */
+ struct Proto **p; /* functions defined inside the function */
+ int *lineinfo; /* map from opcodes to source lines (debug information) */
+ LocVar *locvars; /* information about local variables (debug information) */
+ Upvaldesc *upvalues; /* upvalue information */
+ struct LClosure *cache; /* last-created closure with this prototype */
+ TString *source; /* used for debug information */
+ GCObject *gclist;
+} Proto;
+
+
+
+/*
+** Lua Upvalues
+*/
+typedef struct UpVal UpVal;
+
+
+/*
+** Closures
+*/
+
+#define ClosureHeader \
+ CommonHeader; lu_byte nupvalues; GCObject *gclist
+
+typedef struct CClosure {
+ ClosureHeader;
+ lua_CFunction f;
+ TValue upvalue[1]; /* list of upvalues */
+} CClosure;
+
+
+typedef struct LClosure {
+ ClosureHeader;
+ struct Proto *p;
+ UpVal *upvals[1]; /* list of upvalues */
+} LClosure;
+
+
+typedef union Closure {
+ CClosure c;
+ LClosure l;
+} Closure;
+
+
+#define isLfunction(o) ttisLclosure(o)
+
+#define getproto(o) (clLvalue(o)->p)
+
+
+/*
+** Tables
+*/
+
+typedef union TKey {
+ struct {
+ TValuefields;
+ int next; /* for chaining (offset for next node) */
+ } nk;
+ TValue tvk;
+} TKey;
+
+
+/* copy a value into a key without messing up field 'next' */
+#define setnodekey(L,key,obj) \
+ { TKey *k_=(key); const TValue *io_=(obj); \
+ k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \
+ (void)L; checkliveness(L,io_); }
+
+
+typedef struct Node {
+ TValue i_val;
+ TKey i_key;
+} Node;
+
+
+typedef struct Table {
+ CommonHeader;
+ lu_byte flags; /* 1<<p means tagmethod(p) is not present */
+ lu_byte lsizenode; /* log2 of size of 'node' array */
+ unsigned int sizearray; /* size of 'array' array */
+ TValue *array; /* array part */
+ Node *node;
+ Node *lastfree; /* any free position is before this position */
+ struct Table *metatable;
+ GCObject *gclist;
+} Table;
+
+
+
+/*
+** 'module' operation for hashing (size is always a power of 2)
+*/
+#define lmod(s,size) \
+ (check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1)))))
+
+
+#define twoto(x) (1<<(x))
+#define sizenode(t) (twoto((t)->lsizenode))
+
+
+/*
+** (address of) a fixed nil value
+*/
+#define luaO_nilobject (&luaO_nilobject_)
+
+
+LUAI_DDEC const TValue luaO_nilobject_;
+
+/* size of buffer for 'luaO_utf8esc' function */
+#define UTF8BUFFSZ 8
+
+LUAI_FUNC int luaO_int2fb (unsigned int x);
+LUAI_FUNC int luaO_fb2int (int x);
+LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x);
+LUAI_FUNC int luaO_ceillog2 (unsigned int x);
+LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1,
+ const TValue *p2, TValue *res);
+LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o);
+LUAI_FUNC int luaO_hexavalue (int c);
+LUAI_FUNC void luaO_tostring (lua_State *L, StkId obj);
+LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
+ va_list argp);
+LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
+LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len);
+
+
+#endif
+
diff --git a/external/lua-5.3.3/src/lopcodes.c b/external/lua-5.3.3/src/lopcodes.c
new file mode 100644
index 0000000..a1cbef8
--- /dev/null
+++ b/external/lua-5.3.3/src/lopcodes.c
@@ -0,0 +1,124 @@
+/*
+** $Id: lopcodes.c,v 1.55 2015/01/05 13:48:33 roberto Exp $
+** Opcodes for Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+#define lopcodes_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+
+#include "lopcodes.h"
+
+
+/* ORDER OP */
+
+LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
+ "MOVE",
+ "LOADK",
+ "LOADKX",
+ "LOADBOOL",
+ "LOADNIL",
+ "GETUPVAL",
+ "GETTABUP",
+ "GETTABLE",
+ "SETTABUP",
+ "SETUPVAL",
+ "SETTABLE",
+ "NEWTABLE",
+ "SELF",
+ "ADD",
+ "SUB",
+ "MUL",
+ "MOD",
+ "POW",
+ "DIV",
+ "IDIV",
+ "BAND",
+ "BOR",
+ "BXOR",
+ "SHL",
+ "SHR",
+ "UNM",
+ "BNOT",
+ "NOT",
+ "LEN",
+ "CONCAT",
+ "JMP",
+ "EQ",
+ "LT",
+ "LE",
+ "TEST",
+ "TESTSET",
+ "CALL",
+ "TAILCALL",
+ "RETURN",
+ "FORLOOP",
+ "FORPREP",
+ "TFORCALL",
+ "TFORLOOP",
+ "SETLIST",
+ "CLOSURE",
+ "VARARG",
+ "EXTRAARG",
+ NULL
+};
+
+
+#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))
+
+LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
+/* T A B C mode opcode */
+ opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */
+ ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */
+ ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */
+ ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */
+ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */
+ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */
+ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */
+ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */
+ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHL */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHR */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */
+ ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */
+ ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */
+ ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */
+ ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */
+ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */
+ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */
+ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */
+ ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */
+ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */
+ ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */
+ ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */
+ ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */
+};
+
diff --git a/external/lua-5.3.3/src/lopcodes.h b/external/lua-5.3.3/src/lopcodes.h
new file mode 100644
index 0000000..864b8e4
--- /dev/null
+++ b/external/lua-5.3.3/src/lopcodes.h
@@ -0,0 +1,295 @@
+/*
+** $Id: lopcodes.h,v 1.148 2014/10/25 11:50:46 roberto Exp $
+** Opcodes for Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lopcodes_h
+#define lopcodes_h
+
+#include "llimits.h"
+
+
+/*===========================================================================
+ We assume that instructions are unsigned numbers.
+ All instructions have an opcode in the first 6 bits.
+ Instructions can have the following fields:
+ 'A' : 8 bits
+ 'B' : 9 bits
+ 'C' : 9 bits
+ 'Ax' : 26 bits ('A', 'B', and 'C' together)
+ 'Bx' : 18 bits ('B' and 'C' together)
+ 'sBx' : signed Bx
+
+ A signed argument is represented in excess K; that is, the number
+ value is the unsigned value minus K. K is exactly the maximum value
+ for that argument (so that -max is represented by 0, and +max is
+ represented by 2*max), which is half the maximum for the corresponding
+ unsigned argument.
+===========================================================================*/
+
+
+enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
+
+
+/*
+** size and position of opcode arguments.
+*/
+#define SIZE_C 9
+#define SIZE_B 9
+#define SIZE_Bx (SIZE_C + SIZE_B)
+#define SIZE_A 8
+#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A)
+
+#define SIZE_OP 6
+
+#define POS_OP 0
+#define POS_A (POS_OP + SIZE_OP)
+#define POS_C (POS_A + SIZE_A)
+#define POS_B (POS_C + SIZE_C)
+#define POS_Bx POS_C
+#define POS_Ax POS_A
+
+
+/*
+** limits for opcode arguments.
+** we use (signed) int to manipulate most arguments,
+** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
+*/
+#if SIZE_Bx < LUAI_BITSINT-1
+#define MAXARG_Bx ((1<<SIZE_Bx)-1)
+#define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */
+#else
+#define MAXARG_Bx MAX_INT
+#define MAXARG_sBx MAX_INT
+#endif
+
+#if SIZE_Ax < LUAI_BITSINT-1
+#define MAXARG_Ax ((1<<SIZE_Ax)-1)
+#else
+#define MAXARG_Ax MAX_INT
+#endif
+
+
+#define MAXARG_A ((1<<SIZE_A)-1)
+#define MAXARG_B ((1<<SIZE_B)-1)
+#define MAXARG_C ((1<<SIZE_C)-1)
+
+
+/* creates a mask with 'n' 1 bits at position 'p' */
+#define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p))
+
+/* creates a mask with 'n' 0 bits at position 'p' */
+#define MASK0(n,p) (~MASK1(n,p))
+
+/*
+** the following macros help to manipulate instructions
+*/
+
+#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
+#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
+ ((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
+
+#define getarg(i,pos,size) (cast(int, ((i)>>pos) & MASK1(size,0)))
+#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \
+ ((cast(Instruction, v)<<pos)&MASK1(size,pos))))
+
+#define GETARG_A(i) getarg(i, POS_A, SIZE_A)
+#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A)
+
+#define GETARG_B(i) getarg(i, POS_B, SIZE_B)
+#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B)
+
+#define GETARG_C(i) getarg(i, POS_C, SIZE_C)
+#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C)
+
+#define GETARG_Bx(i) getarg(i, POS_Bx, SIZE_Bx)
+#define SETARG_Bx(i,v) setarg(i, v, POS_Bx, SIZE_Bx)
+
+#define GETARG_Ax(i) getarg(i, POS_Ax, SIZE_Ax)
+#define SETARG_Ax(i,v) setarg(i, v, POS_Ax, SIZE_Ax)
+
+#define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx)
+#define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))
+
+
+#define CREATE_ABC(o,a,b,c) ((cast(Instruction, o)<<POS_OP) \
+ | (cast(Instruction, a)<<POS_A) \
+ | (cast(Instruction, b)<<POS_B) \
+ | (cast(Instruction, c)<<POS_C))
+
+#define CREATE_ABx(o,a,bc) ((cast(Instruction, o)<<POS_OP) \
+ | (cast(Instruction, a)<<POS_A) \
+ | (cast(Instruction, bc)<<POS_Bx))
+
+#define CREATE_Ax(o,a) ((cast(Instruction, o)<<POS_OP) \
+ | (cast(Instruction, a)<<POS_Ax))
+
+
+/*
+** Macros to operate RK indices
+*/
+
+/* this bit 1 means constant (0 means register) */
+#define BITRK (1 << (SIZE_B - 1))
+
+/* test whether value is a constant */
+#define ISK(x) ((x) & BITRK)
+
+/* gets the index of the constant */
+#define INDEXK(r) ((int)(r) & ~BITRK)
+
+#define MAXINDEXRK (BITRK - 1)
+
+/* code a constant index as a RK value */
+#define RKASK(x) ((x) | BITRK)
+
+
+/*
+** invalid register that fits in 8 bits
+*/
+#define NO_REG MAXARG_A
+
+
+/*
+** R(x) - register
+** Kst(x) - constant (in constant table)
+** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
+*/
+
+
+/*
+** grep "ORDER OP" if you change these enums
+*/
+
+typedef enum {
+/*----------------------------------------------------------------------
+name args description
+------------------------------------------------------------------------*/
+OP_MOVE,/* A B R(A) := R(B) */
+OP_LOADK,/* A Bx R(A) := Kst(Bx) */
+OP_LOADKX,/* A R(A) := Kst(extra arg) */
+OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */
+OP_LOADNIL,/* A B R(A), R(A+1), ..., R(A+B) := nil */
+OP_GETUPVAL,/* A B R(A) := UpValue[B] */
+
+OP_GETTABUP,/* A B C R(A) := UpValue[B][RK(C)] */
+OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */
+
+OP_SETTABUP,/* A B C UpValue[A][RK(B)] := RK(C) */
+OP_SETUPVAL,/* A B UpValue[B] := R(A) */
+OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */
+
+OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */
+
+OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
+
+OP_ADD,/* A B C R(A) := RK(B) + RK(C) */
+OP_SUB,/* A B C R(A) := RK(B) - RK(C) */
+OP_MUL,/* A B C R(A) := RK(B) * RK(C) */
+OP_MOD,/* A B C R(A) := RK(B) % RK(C) */
+OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */
+OP_DIV,/* A B C R(A) := RK(B) / RK(C) */
+OP_IDIV,/* A B C R(A) := RK(B) // RK(C) */
+OP_BAND,/* A B C R(A) := RK(B) & RK(C) */
+OP_BOR,/* A B C R(A) := RK(B) | RK(C) */
+OP_BXOR,/* A B C R(A) := RK(B) ~ RK(C) */
+OP_SHL,/* A B C R(A) := RK(B) << RK(C) */
+OP_SHR,/* A B C R(A) := RK(B) >> RK(C) */
+OP_UNM,/* A B R(A) := -R(B) */
+OP_BNOT,/* A B R(A) := ~R(B) */
+OP_NOT,/* A B R(A) := not R(B) */
+OP_LEN,/* A B R(A) := length of R(B) */
+
+OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
+
+OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
+OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
+OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
+OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
+
+OP_TEST,/* A C if not (R(A) <=> C) then pc++ */
+OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
+
+OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
+OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
+OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */
+
+OP_FORLOOP,/* A sBx R(A)+=R(A+2);
+ if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
+OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */
+
+OP_TFORCALL,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
+OP_TFORLOOP,/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
+
+OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
+
+OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */
+
+OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */
+
+OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
+} OpCode;
+
+
+#define NUM_OPCODES (cast(int, OP_EXTRAARG) + 1)
+
+
+
+/*===========================================================================
+ Notes:
+ (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then 'top' is
+ set to last_result+1, so next open instruction (OP_CALL, OP_RETURN,
+ OP_SETLIST) may use 'top'.
+
+ (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
+ set top (like in OP_CALL with C == 0).
+
+ (*) In OP_RETURN, if (B == 0) then return up to 'top'.
+
+ (*) In OP_SETLIST, if (B == 0) then B = 'top'; if (C == 0) then next
+ 'instruction' is EXTRAARG(real C).
+
+ (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
+
+ (*) For comparisons, A specifies what condition the test should accept
+ (true or false).
+
+ (*) All 'skips' (pc++) assume that next instruction is a jump.
+
+===========================================================================*/
+
+
+/*
+** masks for instruction properties. The format is:
+** bits 0-1: op mode
+** bits 2-3: C arg mode
+** bits 4-5: B arg mode
+** bit 6: instruction set register A
+** bit 7: operator is a test (next instruction must be a jump)
+*/
+
+enum OpArgMask {
+ OpArgN, /* argument is not used */
+ OpArgU, /* argument is used */
+ OpArgR, /* argument is a register or a jump offset */
+ OpArgK /* argument is a constant or register/constant */
+};
+
+LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES];
+
+#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3))
+#define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))
+#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3))
+#define testAMode(m) (luaP_opmodes[m] & (1 << 6))
+#define testTMode(m) (luaP_opmodes[m] & (1 << 7))
+
+
+LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */
+
+
+/* number of list items to accumulate before a SETLIST instruction */
+#define LFIELDS_PER_FLUSH 50
+
+
+#endif
diff --git a/external/lua-5.3.3/src/loslib.c b/external/lua-5.3.3/src/loslib.c
new file mode 100644
index 0000000..4810655
--- /dev/null
+++ b/external/lua-5.3.3/src/loslib.c
@@ -0,0 +1,403 @@
+/*
+** $Id: loslib.c,v 1.64 2016/04/18 13:06:55 roberto Exp $
+** Standard Operating System library
+** See Copyright Notice in lua.h
+*/
+
+#define loslib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include <errno.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/*
+** {==================================================================
+** List of valid conversion specifiers for the 'strftime' function;
+** options are grouped by length; group of length 2 start with '||'.
+** ===================================================================
+*/
+#if !defined(LUA_STRFTIMEOPTIONS) /* { */
+
+/* options for ANSI C 89 */
+#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
+
+/* options for ISO C 99 and POSIX */
+#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
+ "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"
+
+/* options for Windows */
+#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
+ "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"
+
+#if defined(LUA_USE_WINDOWS)
+#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
+#elif defined(LUA_USE_C89)
+#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
+#else /* C99 specification */
+#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
+#endif
+
+#endif /* } */
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Configuration for time-related stuff
+** ===================================================================
+*/
+
+#if !defined(l_time_t) /* { */
+/*
+** type to represent time_t in Lua
+*/
+#define l_timet lua_Integer
+#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t))
+
+static time_t l_checktime (lua_State *L, int arg) {
+ lua_Integer t = luaL_checkinteger(L, arg);
+ luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
+ return (time_t)t;
+}
+
+#endif /* } */
+
+
+#if !defined(l_gmtime) /* { */
+/*
+** By default, Lua uses gmtime/localtime, except when POSIX is available,
+** where it uses gmtime_r/localtime_r
+*/
+
+#if defined(LUA_USE_POSIX) /* { */
+
+#define l_gmtime(t,r) gmtime_r(t,r)
+#define l_localtime(t,r) localtime_r(t,r)
+
+#else /* }{ */
+
+/* ISO C definitions */
+#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t))
+#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t))
+
+#endif /* } */
+
+#endif /* } */
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Configuration for 'tmpnam':
+** By default, Lua uses tmpnam except when POSIX is available, where
+** it uses mkstemp.
+** ===================================================================
+*/
+#if !defined(lua_tmpnam) /* { */
+
+#if defined(LUA_USE_POSIX) /* { */
+
+#include <unistd.h>
+
+#define LUA_TMPNAMBUFSIZE 32
+
+#if !defined(LUA_TMPNAMTEMPLATE)
+#define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX"
+#endif
+
+#define lua_tmpnam(b,e) { \
+ strcpy(b, LUA_TMPNAMTEMPLATE); \
+ e = mkstemp(b); \
+ if (e != -1) close(e); \
+ e = (e == -1); }
+
+#else /* }{ */
+
+/* ISO C definitions */
+#define LUA_TMPNAMBUFSIZE L_tmpnam
+#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
+
+#endif /* } */
+
+#endif /* } */
+/* }================================================================== */
+
+
+
+
+static int os_execute (lua_State *L) {
+ const char *cmd = luaL_optstring(L, 1, NULL);
+ int stat = system(cmd);
+ if (cmd != NULL)
+ return luaL_execresult(L, stat);
+ else {
+ lua_pushboolean(L, stat); /* true if there is a shell */
+ return 1;
+ }
+}
+
+
+static int os_remove (lua_State *L) {
+ const char *filename = luaL_checkstring(L, 1);
+ return luaL_fileresult(L, remove(filename) == 0, filename);
+}
+
+
+static int os_rename (lua_State *L) {
+ const char *fromname = luaL_checkstring(L, 1);
+ const char *toname = luaL_checkstring(L, 2);
+ return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
+}
+
+
+static int os_tmpname (lua_State *L) {
+ char buff[LUA_TMPNAMBUFSIZE];
+ int err;
+ lua_tmpnam(buff, err);
+ if (err)
+ return luaL_error(L, "unable to generate a unique filename");
+ lua_pushstring(L, buff);
+ return 1;
+}
+
+
+static int os_getenv (lua_State *L) {
+ lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */
+ return 1;
+}
+
+
+static int os_clock (lua_State *L) {
+ lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC);
+ return 1;
+}
+
+
+/*
+** {======================================================
+** Time/Date operations
+** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
+** wday=%w+1, yday=%j, isdst=? }
+** =======================================================
+*/
+
+static void setfield (lua_State *L, const char *key, int value) {
+ lua_pushinteger(L, value);
+ lua_setfield(L, -2, key);
+}
+
+static void setboolfield (lua_State *L, const char *key, int value) {
+ if (value < 0) /* undefined? */
+ return; /* does not set field */
+ lua_pushboolean(L, value);
+ lua_setfield(L, -2, key);
+}
+
+
+/*
+** Set all fields from structure 'tm' in the table on top of the stack
+*/
+static void setallfields (lua_State *L, struct tm *stm) {
+ setfield(L, "sec", stm->tm_sec);
+ setfield(L, "min", stm->tm_min);
+ setfield(L, "hour", stm->tm_hour);
+ setfield(L, "day", stm->tm_mday);
+ setfield(L, "month", stm->tm_mon + 1);
+ setfield(L, "year", stm->tm_year + 1900);
+ setfield(L, "wday", stm->tm_wday + 1);
+ setfield(L, "yday", stm->tm_yday + 1);
+ setboolfield(L, "isdst", stm->tm_isdst);
+}
+
+
+static int getboolfield (lua_State *L, const char *key) {
+ int res;
+ res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
+ lua_pop(L, 1);
+ return res;
+}
+
+
+/* maximum value for date fields (to avoid arithmetic overflows with 'int') */
+#if !defined(L_MAXDATEFIELD)
+#define L_MAXDATEFIELD (INT_MAX / 2)
+#endif
+
+static int getfield (lua_State *L, const char *key, int d, int delta) {
+ int isnum;
+ int t = lua_getfield(L, -1, key); /* get field and its type */
+ lua_Integer res = lua_tointegerx(L, -1, &isnum);
+ if (!isnum) { /* field is not an integer? */
+ if (t != LUA_TNIL) /* some other value? */
+ return luaL_error(L, "field '%s' is not an integer", key);
+ else if (d < 0) /* absent field; no default? */
+ return luaL_error(L, "field '%s' missing in date table", key);
+ res = d;
+ }
+ else {
+ if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
+ return luaL_error(L, "field '%s' is out-of-bound", key);
+ res -= delta;
+ }
+ lua_pop(L, 1);
+ return (int)res;
+}
+
+
+static const char *checkoption (lua_State *L, const char *conv, char *buff) {
+ const char *option;
+ int oplen = 1;
+ for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) {
+ if (*option == '|') /* next block? */
+ oplen++; /* next length */
+ else if (memcmp(conv, option, oplen) == 0) { /* match? */
+ memcpy(buff, conv, oplen); /* copy valid option to buffer */
+ buff[oplen] = '\0';
+ return conv + oplen; /* return next item */
+ }
+ }
+ luaL_argerror(L, 1,
+ lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv));
+ return conv; /* to avoid warnings */
+}
+
+
+/* maximum size for an individual 'strftime' item */
+#define SIZETIMEFMT 250
+
+
+static int os_date (lua_State *L) {
+ const char *s = luaL_optstring(L, 1, "%c");
+ time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
+ struct tm tmr, *stm;
+ if (*s == '!') { /* UTC? */
+ stm = l_gmtime(&t, &tmr);
+ s++; /* skip '!' */
+ }
+ else
+ stm = l_localtime(&t, &tmr);
+ if (stm == NULL) /* invalid date? */
+ luaL_error(L, "time result cannot be represented in this installation");
+ if (strcmp(s, "*t") == 0) {
+ lua_createtable(L, 0, 9); /* 9 = number of fields */
+ setallfields(L, stm);
+ }
+ else {
+ char cc[4]; /* buffer for individual conversion specifiers */
+ luaL_Buffer b;
+ cc[0] = '%';
+ luaL_buffinit(L, &b);
+ while (*s) {
+ if (*s != '%') /* not a conversion specifier? */
+ luaL_addchar(&b, *s++);
+ else {
+ size_t reslen;
+ char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
+ s = checkoption(L, s + 1, cc + 1); /* copy specifier to 'cc' */
+ reslen = strftime(buff, SIZETIMEFMT, cc, stm);
+ luaL_addsize(&b, reslen);
+ }
+ }
+ luaL_pushresult(&b);
+ }
+ return 1;
+}
+
+
+static int os_time (lua_State *L) {
+ time_t t;
+ if (lua_isnoneornil(L, 1)) /* called without args? */
+ t = time(NULL); /* get current time */
+ else {
+ struct tm ts;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_settop(L, 1); /* make sure table is at the top */
+ ts.tm_sec = getfield(L, "sec", 0, 0);
+ ts.tm_min = getfield(L, "min", 0, 0);
+ ts.tm_hour = getfield(L, "hour", 12, 0);
+ ts.tm_mday = getfield(L, "day", -1, 0);
+ ts.tm_mon = getfield(L, "month", -1, 1);
+ ts.tm_year = getfield(L, "year", -1, 1900);
+ ts.tm_isdst = getboolfield(L, "isdst");
+ t = mktime(&ts);
+ setallfields(L, &ts); /* update fields with normalized values */
+ }
+ if (t != (time_t)(l_timet)t || t == (time_t)(-1))
+ luaL_error(L, "time result cannot be represented in this installation");
+ l_pushtime(L, t);
+ return 1;
+}
+
+
+static int os_difftime (lua_State *L) {
+ time_t t1 = l_checktime(L, 1);
+ time_t t2 = l_checktime(L, 2);
+ lua_pushnumber(L, (lua_Number)difftime(t1, t2));
+ return 1;
+}
+
+/* }====================================================== */
+
+
+static int os_setlocale (lua_State *L) {
+ static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
+ LC_NUMERIC, LC_TIME};
+ static const char *const catnames[] = {"all", "collate", "ctype", "monetary",
+ "numeric", "time", NULL};
+ const char *l = luaL_optstring(L, 1, NULL);
+ int op = luaL_checkoption(L, 2, "all", catnames);
+ lua_pushstring(L, setlocale(cat[op], l));
+ return 1;
+}
+
+
+static int os_exit (lua_State *L) {
+ int status;
+ if (lua_isboolean(L, 1))
+ status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE);
+ else
+ status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS);
+ if (lua_toboolean(L, 2))
+ lua_close(L);
+ if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */
+ return 0;
+}
+
+
+static const luaL_Reg syslib[] = {
+ {"clock", os_clock},
+ {"date", os_date},
+ {"difftime", os_difftime},
+ {"execute", os_execute},
+ {"exit", os_exit},
+ {"getenv", os_getenv},
+ {"remove", os_remove},
+ {"rename", os_rename},
+ {"setlocale", os_setlocale},
+ {"time", os_time},
+ {"tmpname", os_tmpname},
+ {NULL, NULL}
+};
+
+/* }====================================================== */
+
+
+
+LUAMOD_API int luaopen_os (lua_State *L) {
+ luaL_newlib(L, syslib);
+ return 1;
+}
+
diff --git a/external/lua-5.3.3/src/lparser.c b/external/lua-5.3.3/src/lparser.c
new file mode 100644
index 0000000..22530a5
--- /dev/null
+++ b/external/lua-5.3.3/src/lparser.c
@@ -0,0 +1,1652 @@
+/*
+** $Id: lparser.c,v 2.153 2016/05/13 19:10:16 roberto Exp $
+** Lua Parser
+** See Copyright Notice in lua.h
+*/
+
+#define lparser_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <string.h>
+
+#include "lua.h"
+
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+
+
+
+/* maximum number of local variables per function (must be smaller
+ than 250, due to the bytecode format) */
+#define MAXVARS 200
+
+
+#define hasmultret(k) ((k) == VCALL || (k) == VVARARG)
+
+
+/* because all strings are unified by the scanner, the parser
+ can use pointer equality for string equality */
+#define eqstr(a,b) ((a) == (b))
+
+
+/*
+** nodes for block list (list of active blocks)
+*/
+typedef struct BlockCnt {
+ struct BlockCnt *previous; /* chain */
+ int firstlabel; /* index of first label in this block */
+ int firstgoto; /* index of first pending goto in this block */
+ lu_byte nactvar; /* # active locals outside the block */
+ lu_byte upval; /* true if some variable in the block is an upvalue */
+ lu_byte isloop; /* true if 'block' is a loop */
+} BlockCnt;
+
+
+
+/*
+** prototypes for recursive non-terminal functions
+*/
+static void statement (LexState *ls);
+static void expr (LexState *ls, expdesc *v);
+
+
+/* semantic error */
+static l_noret semerror (LexState *ls, const char *msg) {
+ ls->t.token = 0; /* remove "near <token>" from final message */
+ luaX_syntaxerror(ls, msg);
+}
+
+
+static l_noret error_expected (LexState *ls, int token) {
+ luaX_syntaxerror(ls,
+ luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token)));
+}
+
+
+static l_noret errorlimit (FuncState *fs, int limit, const char *what) {
+ lua_State *L = fs->ls->L;
+ const char *msg;
+ int line = fs->f->linedefined;
+ const char *where = (line == 0)
+ ? "main function"
+ : luaO_pushfstring(L, "function at line %d", line);
+ msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s",
+ what, limit, where);
+ luaX_syntaxerror(fs->ls, msg);
+}
+
+
+static void checklimit (FuncState *fs, int v, int l, const char *what) {
+ if (v > l) errorlimit(fs, l, what);
+}
+
+
+static int testnext (LexState *ls, int c) {
+ if (ls->t.token == c) {
+ luaX_next(ls);
+ return 1;
+ }
+ else return 0;
+}
+
+
+static void check (LexState *ls, int c) {
+ if (ls->t.token != c)
+ error_expected(ls, c);
+}
+
+
+static void checknext (LexState *ls, int c) {
+ check(ls, c);
+ luaX_next(ls);
+}
+
+
+#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); }
+
+
+
+static void check_match (LexState *ls, int what, int who, int where) {
+ if (!testnext(ls, what)) {
+ if (where == ls->linenumber)
+ error_expected(ls, what);
+ else {
+ luaX_syntaxerror(ls, luaO_pushfstring(ls->L,
+ "%s expected (to close %s at line %d)",
+ luaX_token2str(ls, what), luaX_token2str(ls, who), where));
+ }
+ }
+}
+
+
+static TString *str_checkname (LexState *ls) {
+ TString *ts;
+ check(ls, TK_NAME);
+ ts = ls->t.seminfo.ts;
+ luaX_next(ls);
+ return ts;
+}
+
+
+static void init_exp (expdesc *e, expkind k, int i) {
+ e->f = e->t = NO_JUMP;
+ e->k = k;
+ e->u.info = i;
+}
+
+
+static void codestring (LexState *ls, expdesc *e, TString *s) {
+ init_exp(e, VK, luaK_stringK(ls->fs, s));
+}
+
+
+static void checkname (LexState *ls, expdesc *e) {
+ codestring(ls, e, str_checkname(ls));
+}
+
+
+static int registerlocalvar (LexState *ls, TString *varname) {
+ FuncState *fs = ls->fs;
+ Proto *f = fs->f;
+ int oldsize = f->sizelocvars;
+ luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
+ LocVar, SHRT_MAX, "local variables");
+ while (oldsize < f->sizelocvars)
+ f->locvars[oldsize++].varname = NULL;
+ f->locvars[fs->nlocvars].varname = varname;
+ luaC_objbarrier(ls->L, f, varname);
+ return fs->nlocvars++;
+}
+
+
+static void new_localvar (LexState *ls, TString *name) {
+ FuncState *fs = ls->fs;
+ Dyndata *dyd = ls->dyd;
+ int reg = registerlocalvar(ls, name);
+ checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
+ MAXVARS, "local variables");
+ luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
+ dyd->actvar.size, Vardesc, MAX_INT, "local variables");
+ dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg);
+}
+
+
+static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {
+ new_localvar(ls, luaX_newstring(ls, name, sz));
+}
+
+#define new_localvarliteral(ls,v) \
+ new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1)
+
+
+static LocVar *getlocvar (FuncState *fs, int i) {
+ int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;
+ lua_assert(idx < fs->nlocvars);
+ return &fs->f->locvars[idx];
+}
+
+
+static void adjustlocalvars (LexState *ls, int nvars) {
+ FuncState *fs = ls->fs;
+ fs->nactvar = cast_byte(fs->nactvar + nvars);
+ for (; nvars; nvars--) {
+ getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;
+ }
+}
+
+
+static void removevars (FuncState *fs, int tolevel) {
+ fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);
+ while (fs->nactvar > tolevel)
+ getlocvar(fs, --fs->nactvar)->endpc = fs->pc;
+}
+
+
+static int searchupvalue (FuncState *fs, TString *name) {
+ int i;
+ Upvaldesc *up = fs->f->upvalues;
+ for (i = 0; i < fs->nups; i++) {
+ if (eqstr(up[i].name, name)) return i;
+ }
+ return -1; /* not found */
+}
+
+
+static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
+ Proto *f = fs->f;
+ int oldsize = f->sizeupvalues;
+ checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
+ luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
+ Upvaldesc, MAXUPVAL, "upvalues");
+ while (oldsize < f->sizeupvalues)
+ f->upvalues[oldsize++].name = NULL;
+ f->upvalues[fs->nups].instack = (v->k == VLOCAL);
+ f->upvalues[fs->nups].idx = cast_byte(v->u.info);
+ f->upvalues[fs->nups].name = name;
+ luaC_objbarrier(fs->ls->L, f, name);
+ return fs->nups++;
+}
+
+
+static int searchvar (FuncState *fs, TString *n) {
+ int i;
+ for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
+ if (eqstr(n, getlocvar(fs, i)->varname))
+ return i;
+ }
+ return -1; /* not found */
+}
+
+
+/*
+ Mark block where variable at given level was defined
+ (to emit close instructions later).
+*/
+static void markupval (FuncState *fs, int level) {
+ BlockCnt *bl = fs->bl;
+ while (bl->nactvar > level)
+ bl = bl->previous;
+ bl->upval = 1;
+}
+
+
+/*
+ Find variable with given name 'n'. If it is an upvalue, add this
+ upvalue into all intermediate functions.
+*/
+static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
+ if (fs == NULL) /* no more levels? */
+ init_exp(var, VVOID, 0); /* default is global */
+ else {
+ int v = searchvar(fs, n); /* look up locals at current level */
+ if (v >= 0) { /* found? */
+ init_exp(var, VLOCAL, v); /* variable is local */
+ if (!base)
+ markupval(fs, v); /* local will be used as an upval */
+ }
+ else { /* not found as local at current level; try upvalues */
+ int idx = searchupvalue(fs, n); /* try existing upvalues */
+ if (idx < 0) { /* not found? */
+ singlevaraux(fs->prev, n, var, 0); /* try upper levels */
+ if (var->k == VVOID) /* not found? */
+ return; /* it is a global */
+ /* else was LOCAL or UPVAL */
+ idx = newupvalue(fs, n, var); /* will be a new upvalue */
+ }
+ init_exp(var, VUPVAL, idx); /* new or old upvalue */
+ }
+ }
+}
+
+
+static void singlevar (LexState *ls, expdesc *var) {
+ TString *varname = str_checkname(ls);
+ FuncState *fs = ls->fs;
+ singlevaraux(fs, varname, var, 1);
+ if (var->k == VVOID) { /* global name? */
+ expdesc key;
+ singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
+ lua_assert(var->k != VVOID); /* this one must exist */
+ codestring(ls, &key, varname); /* key is variable name */
+ luaK_indexed(fs, var, &key); /* env[varname] */
+ }
+}
+
+
+static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
+ FuncState *fs = ls->fs;
+ int extra = nvars - nexps;
+ if (hasmultret(e->k)) {
+ extra++; /* includes call itself */
+ if (extra < 0) extra = 0;
+ luaK_setreturns(fs, e, extra); /* last exp. provides the difference */
+ if (extra > 1) luaK_reserveregs(fs, extra-1);
+ }
+ else {
+ if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */
+ if (extra > 0) {
+ int reg = fs->freereg;
+ luaK_reserveregs(fs, extra);
+ luaK_nil(fs, reg, extra);
+ }
+ }
+}
+
+
+static void enterlevel (LexState *ls) {
+ lua_State *L = ls->L;
+ ++L->nCcalls;
+ checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels");
+}
+
+
+#define leavelevel(ls) ((ls)->L->nCcalls--)
+
+
+static void closegoto (LexState *ls, int g, Labeldesc *label) {
+ int i;
+ FuncState *fs = ls->fs;
+ Labellist *gl = &ls->dyd->gt;
+ Labeldesc *gt = &gl->arr[g];
+ lua_assert(eqstr(gt->name, label->name));
+ if (gt->nactvar < label->nactvar) {
+ TString *vname = getlocvar(fs, gt->nactvar)->varname;
+ const char *msg = luaO_pushfstring(ls->L,
+ "<goto %s> at line %d jumps into the scope of local '%s'",
+ getstr(gt->name), gt->line, getstr(vname));
+ semerror(ls, msg);
+ }
+ luaK_patchlist(fs, gt->pc, label->pc);
+ /* remove goto from pending list */
+ for (i = g; i < gl->n - 1; i++)
+ gl->arr[i] = gl->arr[i + 1];
+ gl->n--;
+}
+
+
+/*
+** try to close a goto with existing labels; this solves backward jumps
+*/
+static int findlabel (LexState *ls, int g) {
+ int i;
+ BlockCnt *bl = ls->fs->bl;
+ Dyndata *dyd = ls->dyd;
+ Labeldesc *gt = &dyd->gt.arr[g];
+ /* check labels in current block for a match */
+ for (i = bl->firstlabel; i < dyd->label.n; i++) {
+ Labeldesc *lb = &dyd->label.arr[i];
+ if (eqstr(lb->name, gt->name)) { /* correct label? */
+ if (gt->nactvar > lb->nactvar &&
+ (bl->upval || dyd->label.n > bl->firstlabel))
+ luaK_patchclose(ls->fs, gt->pc, lb->nactvar);
+ closegoto(ls, g, lb); /* close it */
+ return 1;
+ }
+ }
+ return 0; /* label not found; cannot close goto */
+}
+
+
+static int newlabelentry (LexState *ls, Labellist *l, TString *name,
+ int line, int pc) {
+ int n = l->n;
+ luaM_growvector(ls->L, l->arr, n, l->size,
+ Labeldesc, SHRT_MAX, "labels/gotos");
+ l->arr[n].name = name;
+ l->arr[n].line = line;
+ l->arr[n].nactvar = ls->fs->nactvar;
+ l->arr[n].pc = pc;
+ l->n = n + 1;
+ return n;
+}
+
+
+/*
+** check whether new label 'lb' matches any pending gotos in current
+** block; solves forward jumps
+*/
+static void findgotos (LexState *ls, Labeldesc *lb) {
+ Labellist *gl = &ls->dyd->gt;
+ int i = ls->fs->bl->firstgoto;
+ while (i < gl->n) {
+ if (eqstr(gl->arr[i].name, lb->name))
+ closegoto(ls, i, lb);
+ else
+ i++;
+ }
+}
+
+
+/*
+** export pending gotos to outer level, to check them against
+** outer labels; if the block being exited has upvalues, and
+** the goto exits the scope of any variable (which can be the
+** upvalue), close those variables being exited.
+*/
+static void movegotosout (FuncState *fs, BlockCnt *bl) {
+ int i = bl->firstgoto;
+ Labellist *gl = &fs->ls->dyd->gt;
+ /* correct pending gotos to current block and try to close it
+ with visible labels */
+ while (i < gl->n) {
+ Labeldesc *gt = &gl->arr[i];
+ if (gt->nactvar > bl->nactvar) {
+ if (bl->upval)
+ luaK_patchclose(fs, gt->pc, bl->nactvar);
+ gt->nactvar = bl->nactvar;
+ }
+ if (!findlabel(fs->ls, i))
+ i++; /* move to next one */
+ }
+}
+
+
+static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
+ bl->isloop = isloop;
+ bl->nactvar = fs->nactvar;
+ bl->firstlabel = fs->ls->dyd->label.n;
+ bl->firstgoto = fs->ls->dyd->gt.n;
+ bl->upval = 0;
+ bl->previous = fs->bl;
+ fs->bl = bl;
+ lua_assert(fs->freereg == fs->nactvar);
+}
+
+
+/*
+** create a label named 'break' to resolve break statements
+*/
+static void breaklabel (LexState *ls) {
+ TString *n = luaS_new(ls->L, "break");
+ int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc);
+ findgotos(ls, &ls->dyd->label.arr[l]);
+}
+
+/*
+** generates an error for an undefined 'goto'; choose appropriate
+** message when label name is a reserved word (which can only be 'break')
+*/
+static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
+ const char *msg = isreserved(gt->name)
+ ? "<%s> at line %d not inside a loop"
+ : "no visible label '%s' for <goto> at line %d";
+ msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
+ semerror(ls, msg);
+}
+
+
+static void leaveblock (FuncState *fs) {
+ BlockCnt *bl = fs->bl;
+ LexState *ls = fs->ls;
+ if (bl->previous && bl->upval) {
+ /* create a 'jump to here' to close upvalues */
+ int j = luaK_jump(fs);
+ luaK_patchclose(fs, j, bl->nactvar);
+ luaK_patchtohere(fs, j);
+ }
+ if (bl->isloop)
+ breaklabel(ls); /* close pending breaks */
+ fs->bl = bl->previous;
+ removevars(fs, bl->nactvar);
+ lua_assert(bl->nactvar == fs->nactvar);
+ fs->freereg = fs->nactvar; /* free registers */
+ ls->dyd->label.n = bl->firstlabel; /* remove local labels */
+ if (bl->previous) /* inner block? */
+ movegotosout(fs, bl); /* update pending gotos to outer block */
+ else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */
+ undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
+}
+
+
+/*
+** adds a new prototype into list of prototypes
+*/
+static Proto *addprototype (LexState *ls) {
+ Proto *clp;
+ lua_State *L = ls->L;
+ FuncState *fs = ls->fs;
+ Proto *f = fs->f; /* prototype of current function */
+ if (fs->np >= f->sizep) {
+ int oldsize = f->sizep;
+ luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
+ while (oldsize < f->sizep)
+ f->p[oldsize++] = NULL;
+ }
+ f->p[fs->np++] = clp = luaF_newproto(L);
+ luaC_objbarrier(L, f, clp);
+ return clp;
+}
+
+
+/*
+** codes instruction to create new closure in parent function.
+** The OP_CLOSURE instruction must use the last available register,
+** so that, if it invokes the GC, the GC knows which registers
+** are in use at that time.
+*/
+static void codeclosure (LexState *ls, expdesc *v) {
+ FuncState *fs = ls->fs->prev;
+ init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1));
+ luaK_exp2nextreg(fs, v); /* fix it at the last register */
+}
+
+
+static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
+ Proto *f;
+ fs->prev = ls->fs; /* linked list of funcstates */
+ fs->ls = ls;
+ ls->fs = fs;
+ fs->pc = 0;
+ fs->lasttarget = 0;
+ fs->jpc = NO_JUMP;
+ fs->freereg = 0;
+ fs->nk = 0;
+ fs->np = 0;
+ fs->nups = 0;
+ fs->nlocvars = 0;
+ fs->nactvar = 0;
+ fs->firstlocal = ls->dyd->actvar.n;
+ fs->bl = NULL;
+ f = fs->f;
+ f->source = ls->source;
+ f->maxstacksize = 2; /* registers 0/1 are always valid */
+ enterblock(fs, bl, 0);
+}
+
+
+static void close_func (LexState *ls) {
+ lua_State *L = ls->L;
+ FuncState *fs = ls->fs;
+ Proto *f = fs->f;
+ luaK_ret(fs, 0, 0); /* final return */
+ leaveblock(fs);
+ luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
+ f->sizecode = fs->pc;
+ luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
+ f->sizelineinfo = fs->pc;
+ luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
+ f->sizek = fs->nk;
+ luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
+ f->sizep = fs->np;
+ luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
+ f->sizelocvars = fs->nlocvars;
+ luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
+ f->sizeupvalues = fs->nups;
+ lua_assert(fs->bl == NULL);
+ ls->fs = fs->prev;
+ luaC_checkGC(L);
+}
+
+
+
+/*============================================================*/
+/* GRAMMAR RULES */
+/*============================================================*/
+
+
+/*
+** check whether current token is in the follow set of a block.
+** 'until' closes syntactical blocks, but do not close scope,
+** so it is handled in separate.
+*/
+static int block_follow (LexState *ls, int withuntil) {
+ switch (ls->t.token) {
+ case TK_ELSE: case TK_ELSEIF:
+ case TK_END: case TK_EOS:
+ return 1;
+ case TK_UNTIL: return withuntil;
+ default: return 0;
+ }
+}
+
+
+static void statlist (LexState *ls) {
+ /* statlist -> { stat [';'] } */
+ while (!block_follow(ls, 1)) {
+ if (ls->t.token == TK_RETURN) {
+ statement(ls);
+ return; /* 'return' must be last statement */
+ }
+ statement(ls);
+ }
+}
+
+
+static void fieldsel (LexState *ls, expdesc *v) {
+ /* fieldsel -> ['.' | ':'] NAME */
+ FuncState *fs = ls->fs;
+ expdesc key;
+ luaK_exp2anyregup(fs, v);
+ luaX_next(ls); /* skip the dot or colon */
+ checkname(ls, &key);
+ luaK_indexed(fs, v, &key);
+}
+
+
+static void yindex (LexState *ls, expdesc *v) {
+ /* index -> '[' expr ']' */
+ luaX_next(ls); /* skip the '[' */
+ expr(ls, v);
+ luaK_exp2val(ls->fs, v);
+ checknext(ls, ']');
+}
+
+
+/*
+** {======================================================================
+** Rules for Constructors
+** =======================================================================
+*/
+
+
+struct ConsControl {
+ expdesc v; /* last list item read */
+ expdesc *t; /* table descriptor */
+ int nh; /* total number of 'record' elements */
+ int na; /* total number of array elements */
+ int tostore; /* number of array elements pending to be stored */
+};
+
+
+static void recfield (LexState *ls, struct ConsControl *cc) {
+ /* recfield -> (NAME | '['exp1']') = exp1 */
+ FuncState *fs = ls->fs;
+ int reg = ls->fs->freereg;
+ expdesc key, val;
+ int rkkey;
+ if (ls->t.token == TK_NAME) {
+ checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
+ checkname(ls, &key);
+ }
+ else /* ls->t.token == '[' */
+ yindex(ls, &key);
+ cc->nh++;
+ checknext(ls, '=');
+ rkkey = luaK_exp2RK(fs, &key);
+ expr(ls, &val);
+ luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val));
+ fs->freereg = reg; /* free registers */
+}
+
+
+static void closelistfield (FuncState *fs, struct ConsControl *cc) {
+ if (cc->v.k == VVOID) return; /* there is no list item */
+ luaK_exp2nextreg(fs, &cc->v);
+ cc->v.k = VVOID;
+ if (cc->tostore == LFIELDS_PER_FLUSH) {
+ luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */
+ cc->tostore = 0; /* no more items pending */
+ }
+}
+
+
+static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
+ if (cc->tostore == 0) return;
+ if (hasmultret(cc->v.k)) {
+ luaK_setmultret(fs, &cc->v);
+ luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET);
+ cc->na--; /* do not count last expression (unknown number of elements) */
+ }
+ else {
+ if (cc->v.k != VVOID)
+ luaK_exp2nextreg(fs, &cc->v);
+ luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);
+ }
+}
+
+
+static void listfield (LexState *ls, struct ConsControl *cc) {
+ /* listfield -> exp */
+ expr(ls, &cc->v);
+ checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
+ cc->na++;
+ cc->tostore++;
+}
+
+
+static void field (LexState *ls, struct ConsControl *cc) {
+ /* field -> listfield | recfield */
+ switch(ls->t.token) {
+ case TK_NAME: { /* may be 'listfield' or 'recfield' */
+ if (luaX_lookahead(ls) != '=') /* expression? */
+ listfield(ls, cc);
+ else
+ recfield(ls, cc);
+ break;
+ }
+ case '[': {
+ recfield(ls, cc);
+ break;
+ }
+ default: {
+ listfield(ls, cc);
+ break;
+ }
+ }
+}
+
+
+static void constructor (LexState *ls, expdesc *t) {
+ /* constructor -> '{' [ field { sep field } [sep] ] '}'
+ sep -> ',' | ';' */
+ FuncState *fs = ls->fs;
+ int line = ls->linenumber;
+ int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
+ struct ConsControl cc;
+ cc.na = cc.nh = cc.tostore = 0;
+ cc.t = t;
+ init_exp(t, VRELOCABLE, pc);
+ init_exp(&cc.v, VVOID, 0); /* no value (yet) */
+ luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */
+ checknext(ls, '{');
+ do {
+ lua_assert(cc.v.k == VVOID || cc.tostore > 0);
+ if (ls->t.token == '}') break;
+ closelistfield(fs, &cc);
+ field(ls, &cc);
+ } while (testnext(ls, ',') || testnext(ls, ';'));
+ check_match(ls, '}', '{', line);
+ lastlistfield(fs, &cc);
+ SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
+ SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */
+}
+
+/* }====================================================================== */
+
+
+
+static void parlist (LexState *ls) {
+ /* parlist -> [ param { ',' param } ] */
+ FuncState *fs = ls->fs;
+ Proto *f = fs->f;
+ int nparams = 0;
+ f->is_vararg = 0;
+ if (ls->t.token != ')') { /* is 'parlist' not empty? */
+ do {
+ switch (ls->t.token) {
+ case TK_NAME: { /* param -> NAME */
+ new_localvar(ls, str_checkname(ls));
+ nparams++;
+ break;
+ }
+ case TK_DOTS: { /* param -> '...' */
+ luaX_next(ls);
+ f->is_vararg = 2; /* declared vararg */
+ break;
+ }
+ default: luaX_syntaxerror(ls, "<name> or '...' expected");
+ }
+ } while (!f->is_vararg && testnext(ls, ','));
+ }
+ adjustlocalvars(ls, nparams);
+ f->numparams = cast_byte(fs->nactvar);
+ luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */
+}
+
+
+static void body (LexState *ls, expdesc *e, int ismethod, int line) {
+ /* body -> '(' parlist ')' block END */
+ FuncState new_fs;
+ BlockCnt bl;
+ new_fs.f = addprototype(ls);
+ new_fs.f->linedefined = line;
+ open_func(ls, &new_fs, &bl);
+ checknext(ls, '(');
+ if (ismethod) {
+ new_localvarliteral(ls, "self"); /* create 'self' parameter */
+ adjustlocalvars(ls, 1);
+ }
+ parlist(ls);
+ checknext(ls, ')');
+ statlist(ls);
+ new_fs.f->lastlinedefined = ls->linenumber;
+ check_match(ls, TK_END, TK_FUNCTION, line);
+ codeclosure(ls, e);
+ close_func(ls);
+}
+
+
+static int explist (LexState *ls, expdesc *v) {
+ /* explist -> expr { ',' expr } */
+ int n = 1; /* at least one expression */
+ expr(ls, v);
+ while (testnext(ls, ',')) {
+ luaK_exp2nextreg(ls->fs, v);
+ expr(ls, v);
+ n++;
+ }
+ return n;
+}
+
+
+static void funcargs (LexState *ls, expdesc *f, int line) {
+ FuncState *fs = ls->fs;
+ expdesc args;
+ int base, nparams;
+ switch (ls->t.token) {
+ case '(': { /* funcargs -> '(' [ explist ] ')' */
+ luaX_next(ls);
+ if (ls->t.token == ')') /* arg list is empty? */
+ args.k = VVOID;
+ else {
+ explist(ls, &args);
+ luaK_setmultret(fs, &args);
+ }
+ check_match(ls, ')', '(', line);
+ break;
+ }
+ case '{': { /* funcargs -> constructor */
+ constructor(ls, &args);
+ break;
+ }
+ case TK_STRING: { /* funcargs -> STRING */
+ codestring(ls, &args, ls->t.seminfo.ts);
+ luaX_next(ls); /* must use 'seminfo' before 'next' */
+ break;
+ }
+ default: {
+ luaX_syntaxerror(ls, "function arguments expected");
+ }
+ }
+ lua_assert(f->k == VNONRELOC);
+ base = f->u.info; /* base register for call */
+ if (hasmultret(args.k))
+ nparams = LUA_MULTRET; /* open call */
+ else {
+ if (args.k != VVOID)
+ luaK_exp2nextreg(fs, &args); /* close last argument */
+ nparams = fs->freereg - (base+1);
+ }
+ init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
+ luaK_fixline(fs, line);
+ fs->freereg = base+1; /* call remove function and arguments and leaves
+ (unless changed) one result */
+}
+
+
+
+
+/*
+** {======================================================================
+** Expression parsing
+** =======================================================================
+*/
+
+
+static void primaryexp (LexState *ls, expdesc *v) {
+ /* primaryexp -> NAME | '(' expr ')' */
+ switch (ls->t.token) {
+ case '(': {
+ int line = ls->linenumber;
+ luaX_next(ls);
+ expr(ls, v);
+ check_match(ls, ')', '(', line);
+ luaK_dischargevars(ls->fs, v);
+ return;
+ }
+ case TK_NAME: {
+ singlevar(ls, v);
+ return;
+ }
+ default: {
+ luaX_syntaxerror(ls, "unexpected symbol");
+ }
+ }
+}
+
+
+static void suffixedexp (LexState *ls, expdesc *v) {
+ /* suffixedexp ->
+ primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
+ FuncState *fs = ls->fs;
+ int line = ls->linenumber;
+ primaryexp(ls, v);
+ for (;;) {
+ switch (ls->t.token) {
+ case '.': { /* fieldsel */
+ fieldsel(ls, v);
+ break;
+ }
+ case '[': { /* '[' exp1 ']' */
+ expdesc key;
+ luaK_exp2anyregup(fs, v);
+ yindex(ls, &key);
+ luaK_indexed(fs, v, &key);
+ break;
+ }
+ case ':': { /* ':' NAME funcargs */
+ expdesc key;
+ luaX_next(ls);
+ checkname(ls, &key);
+ luaK_self(fs, v, &key);
+ funcargs(ls, v, line);
+ break;
+ }
+ case '(': case TK_STRING: case '{': { /* funcargs */
+ luaK_exp2nextreg(fs, v);
+ funcargs(ls, v, line);
+ break;
+ }
+ default: return;
+ }
+ }
+}
+
+
+static void simpleexp (LexState *ls, expdesc *v) {
+ /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... |
+ constructor | FUNCTION body | suffixedexp */
+ switch (ls->t.token) {
+ case TK_FLT: {
+ init_exp(v, VKFLT, 0);
+ v->u.nval = ls->t.seminfo.r;
+ break;
+ }
+ case TK_INT: {
+ init_exp(v, VKINT, 0);
+ v->u.ival = ls->t.seminfo.i;
+ break;
+ }
+ case TK_STRING: {
+ codestring(ls, v, ls->t.seminfo.ts);
+ break;
+ }
+ case TK_NIL: {
+ init_exp(v, VNIL, 0);
+ break;
+ }
+ case TK_TRUE: {
+ init_exp(v, VTRUE, 0);
+ break;
+ }
+ case TK_FALSE: {
+ init_exp(v, VFALSE, 0);
+ break;
+ }
+ case TK_DOTS: { /* vararg */
+ FuncState *fs = ls->fs;
+ check_condition(ls, fs->f->is_vararg,
+ "cannot use '...' outside a vararg function");
+ fs->f->is_vararg = 1; /* function actually uses vararg */
+ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
+ break;
+ }
+ case '{': { /* constructor */
+ constructor(ls, v);
+ return;
+ }
+ case TK_FUNCTION: {
+ luaX_next(ls);
+ body(ls, v, 0, ls->linenumber);
+ return;
+ }
+ default: {
+ suffixedexp(ls, v);
+ return;
+ }
+ }
+ luaX_next(ls);
+}
+
+
+static UnOpr getunopr (int op) {
+ switch (op) {
+ case TK_NOT: return OPR_NOT;
+ case '-': return OPR_MINUS;
+ case '~': return OPR_BNOT;
+ case '#': return OPR_LEN;
+ default: return OPR_NOUNOPR;
+ }
+}
+
+
+static BinOpr getbinopr (int op) {
+ switch (op) {
+ case '+': return OPR_ADD;
+ case '-': return OPR_SUB;
+ case '*': return OPR_MUL;
+ case '%': return OPR_MOD;
+ case '^': return OPR_POW;
+ case '/': return OPR_DIV;
+ case TK_IDIV: return OPR_IDIV;
+ case '&': return OPR_BAND;
+ case '|': return OPR_BOR;
+ case '~': return OPR_BXOR;
+ case TK_SHL: return OPR_SHL;
+ case TK_SHR: return OPR_SHR;
+ case TK_CONCAT: return OPR_CONCAT;
+ case TK_NE: return OPR_NE;
+ case TK_EQ: return OPR_EQ;
+ case '<': return OPR_LT;
+ case TK_LE: return OPR_LE;
+ case '>': return OPR_GT;
+ case TK_GE: return OPR_GE;
+ case TK_AND: return OPR_AND;
+ case TK_OR: return OPR_OR;
+ default: return OPR_NOBINOPR;
+ }
+}
+
+
+static const struct {
+ lu_byte left; /* left priority for each binary operator */
+ lu_byte right; /* right priority */
+} priority[] = { /* ORDER OPR */
+ {10, 10}, {10, 10}, /* '+' '-' */
+ {11, 11}, {11, 11}, /* '*' '%' */
+ {14, 13}, /* '^' (right associative) */
+ {11, 11}, {11, 11}, /* '/' '//' */
+ {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */
+ {7, 7}, {7, 7}, /* '<<' '>>' */
+ {9, 8}, /* '..' (right associative) */
+ {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */
+ {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */
+ {2, 2}, {1, 1} /* and, or */
+};
+
+#define UNARY_PRIORITY 12 /* priority for unary operators */
+
+
+/*
+** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
+** where 'binop' is any binary operator with a priority higher than 'limit'
+*/
+static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
+ BinOpr op;
+ UnOpr uop;
+ enterlevel(ls);
+ uop = getunopr(ls->t.token);
+ if (uop != OPR_NOUNOPR) {
+ int line = ls->linenumber;
+ luaX_next(ls);
+ subexpr(ls, v, UNARY_PRIORITY);
+ luaK_prefix(ls->fs, uop, v, line);
+ }
+ else simpleexp(ls, v);
+ /* expand while operators have priorities higher than 'limit' */
+ op = getbinopr(ls->t.token);
+ while (op != OPR_NOBINOPR && priority[op].left > limit) {
+ expdesc v2;
+ BinOpr nextop;
+ int line = ls->linenumber;
+ luaX_next(ls);
+ luaK_infix(ls->fs, op, v);
+ /* read sub-expression with higher priority */
+ nextop = subexpr(ls, &v2, priority[op].right);
+ luaK_posfix(ls->fs, op, v, &v2, line);
+ op = nextop;
+ }
+ leavelevel(ls);
+ return op; /* return first untreated operator */
+}
+
+
+static void expr (LexState *ls, expdesc *v) {
+ subexpr(ls, v, 0);
+}
+
+/* }==================================================================== */
+
+
+
+/*
+** {======================================================================
+** Rules for Statements
+** =======================================================================
+*/
+
+
+static void block (LexState *ls) {
+ /* block -> statlist */
+ FuncState *fs = ls->fs;
+ BlockCnt bl;
+ enterblock(fs, &bl, 0);
+ statlist(ls);
+ leaveblock(fs);
+}
+
+
+/*
+** structure to chain all variables in the left-hand side of an
+** assignment
+*/
+struct LHS_assign {
+ struct LHS_assign *prev;
+ expdesc v; /* variable (global, local, upvalue, or indexed) */
+};
+
+
+/*
+** check whether, in an assignment to an upvalue/local variable, the
+** upvalue/local variable is begin used in a previous assignment to a
+** table. If so, save original upvalue/local value in a safe place and
+** use this safe copy in the previous assignment.
+*/
+static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
+ FuncState *fs = ls->fs;
+ int extra = fs->freereg; /* eventual position to save local variable */
+ int conflict = 0;
+ for (; lh; lh = lh->prev) { /* check all previous assignments */
+ if (lh->v.k == VINDEXED) { /* assigning to a table? */
+ /* table is the upvalue/local being assigned now? */
+ if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) {
+ conflict = 1;
+ lh->v.u.ind.vt = VLOCAL;
+ lh->v.u.ind.t = extra; /* previous assignment will use safe copy */
+ }
+ /* index is the local being assigned? (index cannot be upvalue) */
+ if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) {
+ conflict = 1;
+ lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */
+ }
+ }
+ }
+ if (conflict) {
+ /* copy upvalue/local value to a temporary (in position 'extra') */
+ OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
+ luaK_codeABC(fs, op, extra, v->u.info, 0);
+ luaK_reserveregs(fs, 1);
+ }
+}
+
+
+static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
+ expdesc e;
+ check_condition(ls, vkisvar(lh->v.k), "syntax error");
+ if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */
+ struct LHS_assign nv;
+ nv.prev = lh;
+ suffixedexp(ls, &nv.v);
+ if (nv.v.k != VINDEXED)
+ check_conflict(ls, lh, &nv.v);
+ checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS,
+ "C levels");
+ assignment(ls, &nv, nvars+1);
+ }
+ else { /* assignment -> '=' explist */
+ int nexps;
+ checknext(ls, '=');
+ nexps = explist(ls, &e);
+ if (nexps != nvars) {
+ adjust_assign(ls, nvars, nexps, &e);
+ if (nexps > nvars)
+ ls->fs->freereg -= nexps - nvars; /* remove extra values */
+ }
+ else {
+ luaK_setoneret(ls->fs, &e); /* close last expression */
+ luaK_storevar(ls->fs, &lh->v, &e);
+ return; /* avoid default */
+ }
+ }
+ init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */
+ luaK_storevar(ls->fs, &lh->v, &e);
+}
+
+
+static int cond (LexState *ls) {
+ /* cond -> exp */
+ expdesc v;
+ expr(ls, &v); /* read condition */
+ if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */
+ luaK_goiftrue(ls->fs, &v);
+ return v.f;
+}
+
+
+static void gotostat (LexState *ls, int pc) {
+ int line = ls->linenumber;
+ TString *label;
+ int g;
+ if (testnext(ls, TK_GOTO))
+ label = str_checkname(ls);
+ else {
+ luaX_next(ls); /* skip break */
+ label = luaS_new(ls->L, "break");
+ }
+ g = newlabelentry(ls, &ls->dyd->gt, label, line, pc);
+ findlabel(ls, g); /* close it if label already defined */
+}
+
+
+/* check for repeated labels on the same block */
+static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
+ int i;
+ for (i = fs->bl->firstlabel; i < ll->n; i++) {
+ if (eqstr(label, ll->arr[i].name)) {
+ const char *msg = luaO_pushfstring(fs->ls->L,
+ "label '%s' already defined on line %d",
+ getstr(label), ll->arr[i].line);
+ semerror(fs->ls, msg);
+ }
+ }
+}
+
+
+/* skip no-op statements */
+static void skipnoopstat (LexState *ls) {
+ while (ls->t.token == ';' || ls->t.token == TK_DBCOLON)
+ statement(ls);
+}
+
+
+static void labelstat (LexState *ls, TString *label, int line) {
+ /* label -> '::' NAME '::' */
+ FuncState *fs = ls->fs;
+ Labellist *ll = &ls->dyd->label;
+ int l; /* index of new label being created */
+ checkrepeated(fs, ll, label); /* check for repeated labels */
+ checknext(ls, TK_DBCOLON); /* skip double colon */
+ /* create new entry for this label */
+ l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
+ skipnoopstat(ls); /* skip other no-op statements */
+ if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
+ /* assume that locals are already out of scope */
+ ll->arr[l].nactvar = fs->bl->nactvar;
+ }
+ findgotos(ls, &ll->arr[l]);
+}
+
+
+static void whilestat (LexState *ls, int line) {
+ /* whilestat -> WHILE cond DO block END */
+ FuncState *fs = ls->fs;
+ int whileinit;
+ int condexit;
+ BlockCnt bl;
+ luaX_next(ls); /* skip WHILE */
+ whileinit = luaK_getlabel(fs);
+ condexit = cond(ls);
+ enterblock(fs, &bl, 1);
+ checknext(ls, TK_DO);
+ block(ls);
+ luaK_jumpto(fs, whileinit);
+ check_match(ls, TK_END, TK_WHILE, line);
+ leaveblock(fs);
+ luaK_patchtohere(fs, condexit); /* false conditions finish the loop */
+}
+
+
+static void repeatstat (LexState *ls, int line) {
+ /* repeatstat -> REPEAT block UNTIL cond */
+ int condexit;
+ FuncState *fs = ls->fs;
+ int repeat_init = luaK_getlabel(fs);
+ BlockCnt bl1, bl2;
+ enterblock(fs, &bl1, 1); /* loop block */
+ enterblock(fs, &bl2, 0); /* scope block */
+ luaX_next(ls); /* skip REPEAT */
+ statlist(ls);
+ check_match(ls, TK_UNTIL, TK_REPEAT, line);
+ condexit = cond(ls); /* read condition (inside scope block) */
+ if (bl2.upval) /* upvalues? */
+ luaK_patchclose(fs, condexit, bl2.nactvar);
+ leaveblock(fs); /* finish scope */
+ luaK_patchlist(fs, condexit, repeat_init); /* close the loop */
+ leaveblock(fs); /* finish loop */
+}
+
+
+static int exp1 (LexState *ls) {
+ expdesc e;
+ int reg;
+ expr(ls, &e);
+ luaK_exp2nextreg(ls->fs, &e);
+ lua_assert(e.k == VNONRELOC);
+ reg = e.u.info;
+ return reg;
+}
+
+
+static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
+ /* forbody -> DO block */
+ BlockCnt bl;
+ FuncState *fs = ls->fs;
+ int prep, endfor;
+ adjustlocalvars(ls, 3); /* control variables */
+ checknext(ls, TK_DO);
+ prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
+ enterblock(fs, &bl, 0); /* scope for declared variables */
+ adjustlocalvars(ls, nvars);
+ luaK_reserveregs(fs, nvars);
+ block(ls);
+ leaveblock(fs); /* end of scope for declared variables */
+ luaK_patchtohere(fs, prep);
+ if (isnum) /* numeric for? */
+ endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP);
+ else { /* generic for */
+ luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);
+ luaK_fixline(fs, line);
+ endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP);
+ }
+ luaK_patchlist(fs, endfor, prep + 1);
+ luaK_fixline(fs, line);
+}
+
+
+static void fornum (LexState *ls, TString *varname, int line) {
+ /* fornum -> NAME = exp1,exp1[,exp1] forbody */
+ FuncState *fs = ls->fs;
+ int base = fs->freereg;
+ new_localvarliteral(ls, "(for index)");
+ new_localvarliteral(ls, "(for limit)");
+ new_localvarliteral(ls, "(for step)");
+ new_localvar(ls, varname);
+ checknext(ls, '=');
+ exp1(ls); /* initial value */
+ checknext(ls, ',');
+ exp1(ls); /* limit */
+ if (testnext(ls, ','))
+ exp1(ls); /* optional step */
+ else { /* default step = 1 */
+ luaK_codek(fs, fs->freereg, luaK_intK(fs, 1));
+ luaK_reserveregs(fs, 1);
+ }
+ forbody(ls, base, line, 1, 1);
+}
+
+
+static void forlist (LexState *ls, TString *indexname) {
+ /* forlist -> NAME {,NAME} IN explist forbody */
+ FuncState *fs = ls->fs;
+ expdesc e;
+ int nvars = 4; /* gen, state, control, plus at least one declared var */
+ int line;
+ int base = fs->freereg;
+ /* create control variables */
+ new_localvarliteral(ls, "(for generator)");
+ new_localvarliteral(ls, "(for state)");
+ new_localvarliteral(ls, "(for control)");
+ /* create declared variables */
+ new_localvar(ls, indexname);
+ while (testnext(ls, ',')) {
+ new_localvar(ls, str_checkname(ls));
+ nvars++;
+ }
+ checknext(ls, TK_IN);
+ line = ls->linenumber;
+ adjust_assign(ls, 3, explist(ls, &e), &e);
+ luaK_checkstack(fs, 3); /* extra space to call generator */
+ forbody(ls, base, line, nvars - 3, 0);
+}
+
+
+static void forstat (LexState *ls, int line) {
+ /* forstat -> FOR (fornum | forlist) END */
+ FuncState *fs = ls->fs;
+ TString *varname;
+ BlockCnt bl;
+ enterblock(fs, &bl, 1); /* scope for loop and control variables */
+ luaX_next(ls); /* skip 'for' */
+ varname = str_checkname(ls); /* first variable name */
+ switch (ls->t.token) {
+ case '=': fornum(ls, varname, line); break;
+ case ',': case TK_IN: forlist(ls, varname); break;
+ default: luaX_syntaxerror(ls, "'=' or 'in' expected");
+ }
+ check_match(ls, TK_END, TK_FOR, line);
+ leaveblock(fs); /* loop scope ('break' jumps to this point) */
+}
+
+
+static void test_then_block (LexState *ls, int *escapelist) {
+ /* test_then_block -> [IF | ELSEIF] cond THEN block */
+ BlockCnt bl;
+ FuncState *fs = ls->fs;
+ expdesc v;
+ int jf; /* instruction to skip 'then' code (if condition is false) */
+ luaX_next(ls); /* skip IF or ELSEIF */
+ expr(ls, &v); /* read condition */
+ checknext(ls, TK_THEN);
+ if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) {
+ luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */
+ enterblock(fs, &bl, 0); /* must enter block before 'goto' */
+ gotostat(ls, v.t); /* handle goto/break */
+ skipnoopstat(ls); /* skip other no-op statements */
+ if (block_follow(ls, 0)) { /* 'goto' is the entire block? */
+ leaveblock(fs);
+ return; /* and that is it */
+ }
+ else /* must skip over 'then' part if condition is false */
+ jf = luaK_jump(fs);
+ }
+ else { /* regular case (not goto/break) */
+ luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */
+ enterblock(fs, &bl, 0);
+ jf = v.f;
+ }
+ statlist(ls); /* 'then' part */
+ leaveblock(fs);
+ if (ls->t.token == TK_ELSE ||
+ ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */
+ luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */
+ luaK_patchtohere(fs, jf);
+}
+
+
+static void ifstat (LexState *ls, int line) {
+ /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
+ FuncState *fs = ls->fs;
+ int escapelist = NO_JUMP; /* exit list for finished parts */
+ test_then_block(ls, &escapelist); /* IF cond THEN block */
+ while (ls->t.token == TK_ELSEIF)
+ test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */
+ if (testnext(ls, TK_ELSE))
+ block(ls); /* 'else' part */
+ check_match(ls, TK_END, TK_IF, line);
+ luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */
+}
+
+
+static void localfunc (LexState *ls) {
+ expdesc b;
+ FuncState *fs = ls->fs;
+ new_localvar(ls, str_checkname(ls)); /* new local variable */
+ adjustlocalvars(ls, 1); /* enter its scope */
+ body(ls, &b, 0, ls->linenumber); /* function created in next register */
+ /* debug information will only see the variable after this point! */
+ getlocvar(fs, b.u.info)->startpc = fs->pc;
+}
+
+
+static void localstat (LexState *ls) {
+ /* stat -> LOCAL NAME {',' NAME} ['=' explist] */
+ int nvars = 0;
+ int nexps;
+ expdesc e;
+ do {
+ new_localvar(ls, str_checkname(ls));
+ nvars++;
+ } while (testnext(ls, ','));
+ if (testnext(ls, '='))
+ nexps = explist(ls, &e);
+ else {
+ e.k = VVOID;
+ nexps = 0;
+ }
+ adjust_assign(ls, nvars, nexps, &e);
+ adjustlocalvars(ls, nvars);
+}
+
+
+static int funcname (LexState *ls, expdesc *v) {
+ /* funcname -> NAME {fieldsel} [':' NAME] */
+ int ismethod = 0;
+ singlevar(ls, v);
+ while (ls->t.token == '.')
+ fieldsel(ls, v);
+ if (ls->t.token == ':') {
+ ismethod = 1;
+ fieldsel(ls, v);
+ }
+ return ismethod;
+}
+
+
+static void funcstat (LexState *ls, int line) {
+ /* funcstat -> FUNCTION funcname body */
+ int ismethod;
+ expdesc v, b;
+ luaX_next(ls); /* skip FUNCTION */
+ ismethod = funcname(ls, &v);
+ body(ls, &b, ismethod, line);
+ luaK_storevar(ls->fs, &v, &b);
+ luaK_fixline(ls->fs, line); /* definition "happens" in the first line */
+}
+
+
+static void exprstat (LexState *ls) {
+ /* stat -> func | assignment */
+ FuncState *fs = ls->fs;
+ struct LHS_assign v;
+ suffixedexp(ls, &v.v);
+ if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */
+ v.prev = NULL;
+ assignment(ls, &v, 1);
+ }
+ else { /* stat -> func */
+ check_condition(ls, v.v.k == VCALL, "syntax error");
+ SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */
+ }
+}
+
+
+static void retstat (LexState *ls) {
+ /* stat -> RETURN [explist] [';'] */
+ FuncState *fs = ls->fs;
+ expdesc e;
+ int first, nret; /* registers with returned values */
+ if (block_follow(ls, 1) || ls->t.token == ';')
+ first = nret = 0; /* return no values */
+ else {
+ nret = explist(ls, &e); /* optional return values */
+ if (hasmultret(e.k)) {
+ luaK_setmultret(fs, &e);
+ if (e.k == VCALL && nret == 1) { /* tail call? */
+ SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
+ lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
+ }
+ first = fs->nactvar;
+ nret = LUA_MULTRET; /* return all values */
+ }
+ else {
+ if (nret == 1) /* only one single value? */
+ first = luaK_exp2anyreg(fs, &e);
+ else {
+ luaK_exp2nextreg(fs, &e); /* values must go to the stack */
+ first = fs->nactvar; /* return all active values */
+ lua_assert(nret == fs->freereg - first);
+ }
+ }
+ }
+ luaK_ret(fs, first, nret);
+ testnext(ls, ';'); /* skip optional semicolon */
+}
+
+
+static void statement (LexState *ls) {
+ int line = ls->linenumber; /* may be needed for error messages */
+ enterlevel(ls);
+ switch (ls->t.token) {
+ case ';': { /* stat -> ';' (empty statement) */
+ luaX_next(ls); /* skip ';' */
+ break;
+ }
+ case TK_IF: { /* stat -> ifstat */
+ ifstat(ls, line);
+ break;
+ }
+ case TK_WHILE: { /* stat -> whilestat */
+ whilestat(ls, line);
+ break;
+ }
+ case TK_DO: { /* stat -> DO block END */
+ luaX_next(ls); /* skip DO */
+ block(ls);
+ check_match(ls, TK_END, TK_DO, line);
+ break;
+ }
+ case TK_FOR: { /* stat -> forstat */
+ forstat(ls, line);
+ break;
+ }
+ case TK_REPEAT: { /* stat -> repeatstat */
+ repeatstat(ls, line);
+ break;
+ }
+ case TK_FUNCTION: { /* stat -> funcstat */
+ funcstat(ls, line);
+ break;
+ }
+ case TK_LOCAL: { /* stat -> localstat */
+ luaX_next(ls); /* skip LOCAL */
+ if (testnext(ls, TK_FUNCTION)) /* local function? */
+ localfunc(ls);
+ else
+ localstat(ls);
+ break;
+ }
+ case TK_DBCOLON: { /* stat -> label */
+ luaX_next(ls); /* skip double colon */
+ labelstat(ls, str_checkname(ls), line);
+ break;
+ }
+ case TK_RETURN: { /* stat -> retstat */
+ luaX_next(ls); /* skip RETURN */
+ retstat(ls);
+ break;
+ }
+ case TK_BREAK: /* stat -> breakstat */
+ case TK_GOTO: { /* stat -> 'goto' NAME */
+ gotostat(ls, luaK_jump(ls->fs));
+ break;
+ }
+ default: { /* stat -> func | assignment */
+ exprstat(ls);
+ break;
+ }
+ }
+ lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
+ ls->fs->freereg >= ls->fs->nactvar);
+ ls->fs->freereg = ls->fs->nactvar; /* free registers */
+ leavelevel(ls);
+}
+
+/* }====================================================================== */
+
+
+/*
+** compiles the main function, which is a regular vararg function with an
+** upvalue named LUA_ENV
+*/
+static void mainfunc (LexState *ls, FuncState *fs) {
+ BlockCnt bl;
+ expdesc v;
+ open_func(ls, fs, &bl);
+ fs->f->is_vararg = 2; /* main function is always declared vararg */
+ init_exp(&v, VLOCAL, 0); /* create and... */
+ newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
+ luaX_next(ls); /* read first token */
+ statlist(ls); /* parse main body */
+ check(ls, TK_EOS);
+ close_func(ls);
+}
+
+
+LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
+ Dyndata *dyd, const char *name, int firstchar) {
+ LexState lexstate;
+ FuncState funcstate;
+ LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
+ setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */
+ luaD_inctop(L);
+ lexstate.h = luaH_new(L); /* create table for scanner */
+ sethvalue(L, L->top, lexstate.h); /* anchor it */
+ luaD_inctop(L);
+ funcstate.f = cl->p = luaF_newproto(L);
+ funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
+ lua_assert(iswhite(funcstate.f)); /* do not need barrier here */
+ lexstate.buff = buff;
+ lexstate.dyd = dyd;
+ dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
+ luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar);
+ mainfunc(&lexstate, &funcstate);
+ lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
+ /* all scopes should be correctly finished */
+ lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
+ L->top--; /* remove scanner's table */
+ return cl; /* closure is on the stack, too */
+}
+
diff --git a/external/lua-5.3.3/src/lparser.h b/external/lua-5.3.3/src/lparser.h
new file mode 100644
index 0000000..02e9b03
--- /dev/null
+++ b/external/lua-5.3.3/src/lparser.h
@@ -0,0 +1,133 @@
+/*
+** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $
+** Lua Parser
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lparser_h
+#define lparser_h
+
+#include "llimits.h"
+#include "lobject.h"
+#include "lzio.h"
+
+
+/*
+** Expression and variable descriptor.
+** Code generation for variables and expressions can be delayed to allow
+** optimizations; An 'expdesc' structure describes a potentially-delayed
+** variable/expression. It has a description of its "main" value plus a
+** list of conditional jumps that can also produce its value (generated
+** by short-circuit operators 'and'/'or').
+*/
+
+/* kinds of variables/expressions */
+typedef enum {
+ VVOID, /* when 'expdesc' describes the last expression a list,
+ this kind means an empty list (so, no expression) */
+ VNIL, /* constant nil */
+ VTRUE, /* constant true */
+ VFALSE, /* constant false */
+ VK, /* constant in 'k'; info = index of constant in 'k' */
+ VKFLT, /* floating constant; nval = numerical float value */
+ VKINT, /* integer constant; nval = numerical integer value */
+ VNONRELOC, /* expression has its value in a fixed register;
+ info = result register */
+ VLOCAL, /* local variable; info = local register */
+ VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
+ VINDEXED, /* indexed variable;
+ ind.vt = whether 't' is register or upvalue;
+ ind.t = table register or upvalue;
+ ind.idx = key's R/K index */
+ VJMP, /* expression is a test/comparison;
+ info = pc of corresponding jump instruction */
+ VRELOCABLE, /* expression can put result in any register;
+ info = instruction pc */
+ VCALL, /* expression is a function call; info = instruction pc */
+ VVARARG /* vararg expression; info = instruction pc */
+} expkind;
+
+
+#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED)
+#define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL)
+
+typedef struct expdesc {
+ expkind k;
+ union {
+ lua_Integer ival; /* for VKINT */
+ lua_Number nval; /* for VKFLT */
+ int info; /* for generic use */
+ struct { /* for indexed variables (VINDEXED) */
+ short idx; /* index (R/K) */
+ lu_byte t; /* table (register or upvalue) */
+ lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
+ } ind;
+ } u;
+ int t; /* patch list of 'exit when true' */
+ int f; /* patch list of 'exit when false' */
+} expdesc;
+
+
+/* description of active local variable */
+typedef struct Vardesc {
+ short idx; /* variable index in stack */
+} Vardesc;
+
+
+/* description of pending goto statements and label statements */
+typedef struct Labeldesc {
+ TString *name; /* label identifier */
+ int pc; /* position in code */
+ int line; /* line where it appeared */
+ lu_byte nactvar; /* local level where it appears in current block */
+} Labeldesc;
+
+
+/* list of labels or gotos */
+typedef struct Labellist {
+ Labeldesc *arr; /* array */
+ int n; /* number of entries in use */
+ int size; /* array size */
+} Labellist;
+
+
+/* dynamic structures used by the parser */
+typedef struct Dyndata {
+ struct { /* list of active local variables */
+ Vardesc *arr;
+ int n;
+ int size;
+ } actvar;
+ Labellist gt; /* list of pending gotos */
+ Labellist label; /* list of active labels */
+} Dyndata;
+
+
+/* control of blocks */
+struct BlockCnt; /* defined in lparser.c */
+
+
+/* state needed to generate code for a given function */
+typedef struct FuncState {
+ Proto *f; /* current function header */
+ struct FuncState *prev; /* enclosing function */
+ struct LexState *ls; /* lexical state */
+ struct BlockCnt *bl; /* chain of current blocks */
+ int pc; /* next position to code (equivalent to 'ncode') */
+ int lasttarget; /* 'label' of last 'jump label' */
+ int jpc; /* list of pending jumps to 'pc' */
+ int nk; /* number of elements in 'k' */
+ int np; /* number of elements in 'p' */
+ int firstlocal; /* index of first local var (in Dyndata array) */
+ short nlocvars; /* number of elements in 'f->locvars' */
+ lu_byte nactvar; /* number of active local variables */
+ lu_byte nups; /* number of upvalues */
+ lu_byte freereg; /* first free register */
+} FuncState;
+
+
+LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
+ Dyndata *dyd, const char *name, int firstchar);
+
+
+#endif
diff --git a/external/lua-5.3.3/src/lprefix.h b/external/lua-5.3.3/src/lprefix.h
new file mode 100644
index 0000000..02daa83
--- /dev/null
+++ b/external/lua-5.3.3/src/lprefix.h
@@ -0,0 +1,45 @@
+/*
+** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $
+** Definitions for Lua code that must come before any other header file
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lprefix_h
+#define lprefix_h
+
+
+/*
+** Allows POSIX/XSI stuff
+*/
+#if !defined(LUA_USE_C89) /* { */
+
+#if !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE 600
+#elif _XOPEN_SOURCE == 0
+#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */
+#endif
+
+/*
+** Allows manipulation of large files in gcc and some other compilers
+*/
+#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS)
+#define _LARGEFILE_SOURCE 1
+#define _FILE_OFFSET_BITS 64
+#endif
+
+#endif /* } */
+
+
+/*
+** Windows stuff
+*/
+#if defined(_WIN32) /* { */
+
+#if !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */
+#endif
+
+#endif /* } */
+
+#endif
+
diff --git a/external/lua-5.3.3/src/lstate.c b/external/lua-5.3.3/src/lstate.c
new file mode 100644
index 0000000..9194ac3
--- /dev/null
+++ b/external/lua-5.3.3/src/lstate.c
@@ -0,0 +1,347 @@
+/*
+** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $
+** Global State
+** See Copyright Notice in lua.h
+*/
+
+#define lstate_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+
+
+#if !defined(LUAI_GCPAUSE)
+#define LUAI_GCPAUSE 200 /* 200% */
+#endif
+
+#if !defined(LUAI_GCMUL)
+#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */
+#endif
+
+
+/*
+** a macro to help the creation of a unique random seed when a state is
+** created; the seed is used to randomize hashes.
+*/
+#if !defined(luai_makeseed)
+#include <time.h>
+#define luai_makeseed() cast(unsigned int, time(NULL))
+#endif
+
+
+
+/*
+** thread state + extra space
+*/
+typedef struct LX {
+ lu_byte extra_[LUA_EXTRASPACE];
+ lua_State l;
+} LX;
+
+
+/*
+** Main thread combines a thread state and the global state
+*/
+typedef struct LG {
+ LX l;
+ global_State g;
+} LG;
+
+
+
+#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))
+
+
+/*
+** Compute an initial seed as random as possible. Rely on Address Space
+** Layout Randomization (if present) to increase randomness..
+*/
+#define addbuff(b,p,e) \
+ { size_t t = cast(size_t, e); \
+ memcpy(b + p, &t, sizeof(t)); p += sizeof(t); }
+
+static unsigned int makeseed (lua_State *L) {
+ char buff[4 * sizeof(size_t)];
+ unsigned int h = luai_makeseed();
+ int p = 0;
+ addbuff(buff, p, L); /* heap variable */
+ addbuff(buff, p, &h); /* local variable */
+ addbuff(buff, p, luaO_nilobject); /* global variable */
+ addbuff(buff, p, &lua_newstate); /* public function */
+ lua_assert(p == sizeof(buff));
+ return luaS_hash(buff, p, h);
+}
+
+
+/*
+** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
+** invariant (and avoiding underflows in 'totalbytes')
+*/
+void luaE_setdebt (global_State *g, l_mem debt) {
+ l_mem tb = gettotalbytes(g);
+ lua_assert(tb > 0);
+ if (debt < tb - MAX_LMEM)
+ debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */
+ g->totalbytes = tb - debt;
+ g->GCdebt = debt;
+}
+
+
+CallInfo *luaE_extendCI (lua_State *L) {
+ CallInfo *ci = luaM_new(L, CallInfo);
+ lua_assert(L->ci->next == NULL);
+ L->ci->next = ci;
+ ci->previous = L->ci;
+ ci->next = NULL;
+ L->nci++;
+ return ci;
+}
+
+
+/*
+** free all CallInfo structures not in use by a thread
+*/
+void luaE_freeCI (lua_State *L) {
+ CallInfo *ci = L->ci;
+ CallInfo *next = ci->next;
+ ci->next = NULL;
+ while ((ci = next) != NULL) {
+ next = ci->next;
+ luaM_free(L, ci);
+ L->nci--;
+ }
+}
+
+
+/*
+** free half of the CallInfo structures not in use by a thread
+*/
+void luaE_shrinkCI (lua_State *L) {
+ CallInfo *ci = L->ci;
+ CallInfo *next2; /* next's next */
+ /* while there are two nexts */
+ while (ci->next != NULL && (next2 = ci->next->next) != NULL) {
+ luaM_free(L, ci->next); /* free next */
+ L->nci--;
+ ci->next = next2; /* remove 'next' from the list */
+ next2->previous = ci;
+ ci = next2; /* keep next's next */
+ }
+}
+
+
+static void stack_init (lua_State *L1, lua_State *L) {
+ int i; CallInfo *ci;
+ /* initialize stack array */
+ L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue);
+ L1->stacksize = BASIC_STACK_SIZE;
+ for (i = 0; i < BASIC_STACK_SIZE; i++)
+ setnilvalue(L1->stack + i); /* erase new stack */
+ L1->top = L1->stack;
+ L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;
+ /* initialize first ci */
+ ci = &L1->base_ci;
+ ci->next = ci->previous = NULL;
+ ci->callstatus = 0;
+ ci->func = L1->top;
+ setnilvalue(L1->top++); /* 'function' entry for this 'ci' */
+ ci->top = L1->top + LUA_MINSTACK;
+ L1->ci = ci;
+}
+
+
+static void freestack (lua_State *L) {
+ if (L->stack == NULL)
+ return; /* stack not completely built yet */
+ L->ci = &L->base_ci; /* free the entire 'ci' list */
+ luaE_freeCI(L);
+ lua_assert(L->nci == 0);
+ luaM_freearray(L, L->stack, L->stacksize); /* free stack array */
+}
+
+
+/*
+** Create registry table and its predefined values
+*/
+static void init_registry (lua_State *L, global_State *g) {
+ TValue temp;
+ /* create registry */
+ Table *registry = luaH_new(L);
+ sethvalue(L, &g->l_registry, registry);
+ luaH_resize(L, registry, LUA_RIDX_LAST, 0);
+ /* registry[LUA_RIDX_MAINTHREAD] = L */
+ setthvalue(L, &temp, L); /* temp = L */
+ luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp);
+ /* registry[LUA_RIDX_GLOBALS] = table of globals */
+ sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */
+ luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp);
+}
+
+
+/*
+** open parts of the state that may cause memory-allocation errors.
+** ('g->version' != NULL flags that the state was completely build)
+*/
+static void f_luaopen (lua_State *L, void *ud) {
+ global_State *g = G(L);
+ UNUSED(ud);
+ stack_init(L, L); /* init stack */
+ init_registry(L, g);
+ luaS_init(L);
+ luaT_init(L);
+ luaX_init(L);
+ g->gcrunning = 1; /* allow gc */
+ g->version = lua_version(NULL);
+ luai_userstateopen(L);
+}
+
+
+/*
+** preinitialize a thread with consistent values without allocating
+** any memory (to avoid errors)
+*/
+static void preinit_thread (lua_State *L, global_State *g) {
+ G(L) = g;
+ L->stack = NULL;
+ L->ci = NULL;
+ L->nci = 0;
+ L->stacksize = 0;
+ L->twups = L; /* thread has no upvalues */
+ L->errorJmp = NULL;
+ L->nCcalls = 0;
+ L->hook = NULL;
+ L->hookmask = 0;
+ L->basehookcount = 0;
+ L->allowhook = 1;
+ resethookcount(L);
+ L->openupval = NULL;
+ L->nny = 1;
+ L->status = LUA_OK;
+ L->errfunc = 0;
+}
+
+
+static void close_state (lua_State *L) {
+ global_State *g = G(L);
+ luaF_close(L, L->stack); /* close all upvalues for this thread */
+ luaC_freeallobjects(L); /* collect all objects */
+ if (g->version) /* closing a fully built state? */
+ luai_userstateclose(L);
+ luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
+ freestack(L);
+ lua_assert(gettotalbytes(g) == sizeof(LG));
+ (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */
+}
+
+
+LUA_API lua_State *lua_newthread (lua_State *L) {
+ global_State *g = G(L);
+ lua_State *L1;
+ lua_lock(L);
+ luaC_checkGC(L);
+ /* create new thread */
+ L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
+ L1->marked = luaC_white(g);
+ L1->tt = LUA_TTHREAD;
+ /* link it on list 'allgc' */
+ L1->next = g->allgc;
+ g->allgc = obj2gco(L1);
+ /* anchor it on L stack */
+ setthvalue(L, L->top, L1);
+ api_incr_top(L);
+ preinit_thread(L1, g);
+ L1->hookmask = L->hookmask;
+ L1->basehookcount = L->basehookcount;
+ L1->hook = L->hook;
+ resethookcount(L1);
+ /* initialize L1 extra space */
+ memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread),
+ LUA_EXTRASPACE);
+ luai_userstatethread(L, L1);
+ stack_init(L1, L); /* init stack */
+ lua_unlock(L);
+ return L1;
+}
+
+
+void luaE_freethread (lua_State *L, lua_State *L1) {
+ LX *l = fromstate(L1);
+ luaF_close(L1, L1->stack); /* close all upvalues for this thread */
+ lua_assert(L1->openupval == NULL);
+ luai_userstatefree(L, L1);
+ freestack(L1);
+ luaM_free(L, l);
+}
+
+
+LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
+ int i;
+ lua_State *L;
+ global_State *g;
+ LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));
+ if (l == NULL) return NULL;
+ L = &l->l.l;
+ g = &l->g;
+ L->next = NULL;
+ L->tt = LUA_TTHREAD;
+ g->currentwhite = bitmask(WHITE0BIT);
+ L->marked = luaC_white(g);
+ preinit_thread(L, g);
+ g->frealloc = f;
+ g->ud = ud;
+ g->mainthread = L;
+ g->seed = makeseed(L);
+ g->gcrunning = 0; /* no GC while building state */
+ g->GCestimate = 0;
+ g->strt.size = g->strt.nuse = 0;
+ g->strt.hash = NULL;
+ setnilvalue(&g->l_registry);
+ g->panic = NULL;
+ g->version = NULL;
+ g->gcstate = GCSpause;
+ g->gckind = KGC_NORMAL;
+ g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL;
+ g->sweepgc = NULL;
+ g->gray = g->grayagain = NULL;
+ g->weak = g->ephemeron = g->allweak = NULL;
+ g->twups = NULL;
+ g->totalbytes = sizeof(LG);
+ g->GCdebt = 0;
+ g->gcfinnum = 0;
+ g->gcpause = LUAI_GCPAUSE;
+ g->gcstepmul = LUAI_GCMUL;
+ for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
+ if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
+ /* memory allocation error: free partial state */
+ close_state(L);
+ L = NULL;
+ }
+ return L;
+}
+
+
+LUA_API void lua_close (lua_State *L) {
+ L = G(L)->mainthread; /* only the main thread can be closed */
+ lua_lock(L);
+ close_state(L);
+}
+
+
diff --git a/external/lua-5.3.3/src/lstate.h b/external/lua-5.3.3/src/lstate.h
new file mode 100644
index 0000000..b3033be
--- /dev/null
+++ b/external/lua-5.3.3/src/lstate.h
@@ -0,0 +1,234 @@
+/*
+** $Id: lstate.h,v 2.130 2015/12/16 16:39:38 roberto Exp $
+** Global State
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lstate_h
+#define lstate_h
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "ltm.h"
+#include "lzio.h"
+
+
+/*
+
+** Some notes about garbage-collected objects: All objects in Lua must
+** be kept somehow accessible until being freed, so all objects always
+** belong to one (and only one) of these lists, using field 'next' of
+** the 'CommonHeader' for the link:
+**
+** 'allgc': all objects not marked for finalization;
+** 'finobj': all objects marked for finalization;
+** 'tobefnz': all objects ready to be finalized;
+** 'fixedgc': all objects that are not to be collected (currently
+** only small strings, such as reserved words).
+
+*/
+
+
+struct lua_longjmp; /* defined in ldo.c */
+
+
+/*
+** Atomic type (relative to signals) to better ensure that 'lua_sethook'
+** is thread safe
+*/
+#if !defined(l_signalT)
+#include <signal.h>
+#define l_signalT sig_atomic_t
+#endif
+
+
+/* extra stack space to handle TM calls and some other extras */
+#define EXTRA_STACK 5
+
+
+#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
+
+
+/* kinds of Garbage Collection */
+#define KGC_NORMAL 0
+#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */
+
+
+typedef struct stringtable {
+ TString **hash;
+ int nuse; /* number of elements */
+ int size;
+} stringtable;
+
+
+/*
+** Information about a call.
+** When a thread yields, 'func' is adjusted to pretend that the
+** top function has only the yielded values in its stack; in that
+** case, the actual 'func' value is saved in field 'extra'.
+** When a function calls another with a continuation, 'extra' keeps
+** the function index so that, in case of errors, the continuation
+** function can be called with the correct top.
+*/
+typedef struct CallInfo {
+ StkId func; /* function index in the stack */
+ StkId top; /* top for this function */
+ struct CallInfo *previous, *next; /* dynamic call link */
+ union {
+ struct { /* only for Lua functions */
+ StkId base; /* base for this function */
+ const Instruction *savedpc;
+ } l;
+ struct { /* only for C functions */
+ lua_KFunction k; /* continuation in case of yields */
+ ptrdiff_t old_errfunc;
+ lua_KContext ctx; /* context info. in case of yields */
+ } c;
+ } u;
+ ptrdiff_t extra;
+ short nresults; /* expected number of results from this function */
+ lu_byte callstatus;
+} CallInfo;
+
+
+/*
+** Bits in CallInfo status
+*/
+#define CIST_OAH (1<<0) /* original value of 'allowhook' */
+#define CIST_LUA (1<<1) /* call is running a Lua function */
+#define CIST_HOOKED (1<<2) /* call is running a debug hook */
+#define CIST_FRESH (1<<3) /* call is running on a fresh invocation
+ of luaV_execute */
+#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
+#define CIST_TAIL (1<<5) /* call was tail called */
+#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
+#define CIST_LEQ (1<<7) /* using __lt for __le */
+
+#define isLua(ci) ((ci)->callstatus & CIST_LUA)
+
+/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */
+#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v))
+#define getoah(st) ((st) & CIST_OAH)
+
+
+/*
+** 'global state', shared by all threads of this state
+*/
+typedef struct global_State {
+ lua_Alloc frealloc; /* function to reallocate memory */
+ void *ud; /* auxiliary data to 'frealloc' */
+ l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
+ l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
+ lu_mem GCmemtrav; /* memory traversed by the GC */
+ lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
+ stringtable strt; /* hash table for strings */
+ TValue l_registry;
+ unsigned int seed; /* randomized seed for hashes */
+ lu_byte currentwhite;
+ lu_byte gcstate; /* state of garbage collector */
+ lu_byte gckind; /* kind of GC running */
+ lu_byte gcrunning; /* true if GC is running */
+ GCObject *allgc; /* list of all collectable objects */
+ GCObject **sweepgc; /* current position of sweep in list */
+ GCObject *finobj; /* list of collectable objects with finalizers */
+ GCObject *gray; /* list of gray objects */
+ GCObject *grayagain; /* list of objects to be traversed atomically */
+ GCObject *weak; /* list of tables with weak values */
+ GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
+ GCObject *allweak; /* list of all-weak tables */
+ GCObject *tobefnz; /* list of userdata to be GC */
+ GCObject *fixedgc; /* list of objects not to be collected */
+ struct lua_State *twups; /* list of threads with open upvalues */
+ unsigned int gcfinnum; /* number of finalizers to call in each GC step */
+ int gcpause; /* size of pause between successive GCs */
+ int gcstepmul; /* GC 'granularity' */
+ lua_CFunction panic; /* to be called in unprotected errors */
+ struct lua_State *mainthread;
+ const lua_Number *version; /* pointer to version number */
+ TString *memerrmsg; /* memory-error message */
+ TString *tmname[TM_N]; /* array with tag-method names */
+ struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
+ TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
+} global_State;
+
+
+/*
+** 'per thread' state
+*/
+struct lua_State {
+ CommonHeader;
+ unsigned short nci; /* number of items in 'ci' list */
+ lu_byte status;
+ StkId top; /* first free slot in the stack */
+ global_State *l_G;
+ CallInfo *ci; /* call info for current function */
+ const Instruction *oldpc; /* last pc traced */
+ StkId stack_last; /* last free slot in the stack */
+ StkId stack; /* stack base */
+ UpVal *openupval; /* list of open upvalues in this stack */
+ GCObject *gclist;
+ struct lua_State *twups; /* list of threads with open upvalues */
+ struct lua_longjmp *errorJmp; /* current error recover point */
+ CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
+ volatile lua_Hook hook;
+ ptrdiff_t errfunc; /* current error handling function (stack index) */
+ int stacksize;
+ int basehookcount;
+ int hookcount;
+ unsigned short nny; /* number of non-yieldable calls in stack */
+ unsigned short nCcalls; /* number of nested C calls */
+ l_signalT hookmask;
+ lu_byte allowhook;
+};
+
+
+#define G(L) (L->l_G)
+
+
+/*
+** Union of all collectable objects (only for conversions)
+*/
+union GCUnion {
+ GCObject gc; /* common header */
+ struct TString ts;
+ struct Udata u;
+ union Closure cl;
+ struct Table h;
+ struct Proto p;
+ struct lua_State th; /* thread */
+};
+
+
+#define cast_u(o) cast(union GCUnion *, (o))
+
+/* macros to convert a GCObject into a specific value */
+#define gco2ts(o) \
+ check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))
+#define gco2u(o) check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u))
+#define gco2lcl(o) check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l))
+#define gco2ccl(o) check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c))
+#define gco2cl(o) \
+ check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))
+#define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h))
+#define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p))
+#define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th))
+
+
+/* macro to convert a Lua object into a GCObject */
+#define obj2gco(v) \
+ check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc)))
+
+
+/* actual number of total bytes allocated */
+#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt)
+
+LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
+LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
+LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
+LUAI_FUNC void luaE_freeCI (lua_State *L);
+LUAI_FUNC void luaE_shrinkCI (lua_State *L);
+
+
+#endif
+
diff --git a/external/lua-5.3.3/src/lstring.c b/external/lua-5.3.3/src/lstring.c
new file mode 100644
index 0000000..9351766
--- /dev/null
+++ b/external/lua-5.3.3/src/lstring.c
@@ -0,0 +1,248 @@
+/*
+** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp $
+** String table (keeps all strings handled by Lua)
+** See Copyright Notice in lua.h
+*/
+
+#define lstring_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <string.h>
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+
+
+#define MEMERRMSG "not enough memory"
+
+
+/*
+** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
+** compute its hash
+*/
+#if !defined(LUAI_HASHLIMIT)
+#define LUAI_HASHLIMIT 5
+#endif
+
+
+/*
+** equality for long strings
+*/
+int luaS_eqlngstr (TString *a, TString *b) {
+ size_t len = a->u.lnglen;
+ lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR);
+ return (a == b) || /* same instance or... */
+ ((len == b->u.lnglen) && /* equal length and ... */
+ (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
+}
+
+
+unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
+ unsigned int h = seed ^ cast(unsigned int, l);
+ size_t step = (l >> LUAI_HASHLIMIT) + 1;
+ for (; l >= step; l -= step)
+ h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
+ return h;
+}
+
+
+unsigned int luaS_hashlongstr (TString *ts) {
+ lua_assert(ts->tt == LUA_TLNGSTR);
+ if (ts->extra == 0) { /* no hash? */
+ ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash);
+ ts->extra = 1; /* now it has its hash */
+ }
+ return ts->hash;
+}
+
+
+/*
+** resizes the string table
+*/
+void luaS_resize (lua_State *L, int newsize) {
+ int i;
+ stringtable *tb = &G(L)->strt;
+ if (newsize > tb->size) { /* grow table if needed */
+ luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *);
+ for (i = tb->size; i < newsize; i++)
+ tb->hash[i] = NULL;
+ }
+ for (i = 0; i < tb->size; i++) { /* rehash */
+ TString *p = tb->hash[i];
+ tb->hash[i] = NULL;
+ while (p) { /* for each node in the list */
+ TString *hnext = p->u.hnext; /* save next */
+ unsigned int h = lmod(p->hash, newsize); /* new position */
+ p->u.hnext = tb->hash[h]; /* chain it */
+ tb->hash[h] = p;
+ p = hnext;
+ }
+ }
+ if (newsize < tb->size) { /* shrink table if needed */
+ /* vanishing slice should be empty */
+ lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL);
+ luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *);
+ }
+ tb->size = newsize;
+}
+
+
+/*
+** Clear API string cache. (Entries cannot be empty, so fill them with
+** a non-collectable string.)
+*/
+void luaS_clearcache (global_State *g) {
+ int i, j;
+ for (i = 0; i < STRCACHE_N; i++)
+ for (j = 0; j < STRCACHE_M; j++) {
+ if (iswhite(g->strcache[i][j])) /* will entry be collected? */
+ g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */
+ }
+}
+
+
+/*
+** Initialize the string table and the string cache
+*/
+void luaS_init (lua_State *L) {
+ global_State *g = G(L);
+ int i, j;
+ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
+ /* pre-create memory-error message */
+ g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
+ luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */
+ for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */
+ for (j = 0; j < STRCACHE_M; j++)
+ g->strcache[i][j] = g->memerrmsg;
+}
+
+
+
+/*
+** creates a new string object
+*/
+static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
+ TString *ts;
+ GCObject *o;
+ size_t totalsize; /* total size of TString object */
+ totalsize = sizelstring(l);
+ o = luaC_newobj(L, tag, totalsize);
+ ts = gco2ts(o);
+ ts->hash = h;
+ ts->extra = 0;
+ getstr(ts)[l] = '\0'; /* ending 0 */
+ return ts;
+}
+
+
+TString *luaS_createlngstrobj (lua_State *L, size_t l) {
+ TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed);
+ ts->u.lnglen = l;
+ return ts;
+}
+
+
+void luaS_remove (lua_State *L, TString *ts) {
+ stringtable *tb = &G(L)->strt;
+ TString **p = &tb->hash[lmod(ts->hash, tb->size)];
+ while (*p != ts) /* find previous element */
+ p = &(*p)->u.hnext;
+ *p = (*p)->u.hnext; /* remove element from its list */
+ tb->nuse--;
+}
+
+
+/*
+** checks whether short string exists and reuses it or creates a new one
+*/
+static TString *internshrstr (lua_State *L, const char *str, size_t l) {
+ TString *ts;
+ global_State *g = G(L);
+ unsigned int h = luaS_hash(str, l, g->seed);
+ TString **list = &g->strt.hash[lmod(h, g->strt.size)];
+ lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
+ for (ts = *list; ts != NULL; ts = ts->u.hnext) {
+ if (l == ts->shrlen &&
+ (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
+ /* found! */
+ if (isdead(g, ts)) /* dead (but not collected yet)? */
+ changewhite(ts); /* resurrect it */
+ return ts;
+ }
+ }
+ if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) {
+ luaS_resize(L, g->strt.size * 2);
+ list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */
+ }
+ ts = createstrobj(L, l, LUA_TSHRSTR, h);
+ memcpy(getstr(ts), str, l * sizeof(char));
+ ts->shrlen = cast_byte(l);
+ ts->u.hnext = *list;
+ *list = ts;
+ g->strt.nuse++;
+ return ts;
+}
+
+
+/*
+** new string (with explicit length)
+*/
+TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
+ if (l <= LUAI_MAXSHORTLEN) /* short string? */
+ return internshrstr(L, str, l);
+ else {
+ TString *ts;
+ if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char))
+ luaM_toobig(L);
+ ts = luaS_createlngstrobj(L, l);
+ memcpy(getstr(ts), str, l * sizeof(char));
+ return ts;
+ }
+}
+
+
+/*
+** Create or reuse a zero-terminated string, first checking in the
+** cache (using the string address as a key). The cache can contain
+** only zero-terminated strings, so it is safe to use 'strcmp' to
+** check hits.
+*/
+TString *luaS_new (lua_State *L, const char *str) {
+ unsigned int i = point2uint(str) % STRCACHE_N; /* hash */
+ int j;
+ TString **p = G(L)->strcache[i];
+ for (j = 0; j < STRCACHE_M; j++) {
+ if (strcmp(str, getstr(p[j])) == 0) /* hit? */
+ return p[j]; /* that is it */
+ }
+ /* normal route */
+ for (j = STRCACHE_M - 1; j > 0; j--)
+ p[j] = p[j - 1]; /* move out last element */
+ /* new element is first in the list */
+ p[0] = luaS_newlstr(L, str, strlen(str));
+ return p[0];
+}
+
+
+Udata *luaS_newudata (lua_State *L, size_t s) {
+ Udata *u;
+ GCObject *o;
+ if (s > MAX_SIZE - sizeof(Udata))
+ luaM_toobig(L);
+ o = luaC_newobj(L, LUA_TUSERDATA, sizeludata(s));
+ u = gco2u(o);
+ u->len = s;
+ u->metatable = NULL;
+ setuservalue(L, u, luaO_nilobject);
+ return u;
+}
+
diff --git a/external/lua-5.3.3/src/lstring.h b/external/lua-5.3.3/src/lstring.h
new file mode 100644
index 0000000..27efd20
--- /dev/null
+++ b/external/lua-5.3.3/src/lstring.h
@@ -0,0 +1,49 @@
+/*
+** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $
+** String table (keep all strings handled by Lua)
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lstring_h
+#define lstring_h
+
+#include "lgc.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char))
+
+#define sizeludata(l) (sizeof(union UUdata) + (l))
+#define sizeudata(u) sizeludata((u)->len)
+
+#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
+ (sizeof(s)/sizeof(char))-1))
+
+
+/*
+** test whether a string is a reserved word
+*/
+#define isreserved(s) ((s)->tt == LUA_TSHRSTR && (s)->extra > 0)
+
+
+/*
+** equality for short strings, which are always internalized
+*/
+#define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b))
+
+
+LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
+LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
+LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
+LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
+LUAI_FUNC void luaS_clearcache (global_State *g);
+LUAI_FUNC void luaS_init (lua_State *L);
+LUAI_FUNC void luaS_remove (lua_State *L, TString *ts);
+LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s);
+LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
+LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
+LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
+
+
+#endif
diff --git a/external/lua-5.3.3/src/lstrlib.c b/external/lua-5.3.3/src/lstrlib.c
new file mode 100644
index 0000000..12264f8
--- /dev/null
+++ b/external/lua-5.3.3/src/lstrlib.c
@@ -0,0 +1,1582 @@
+/*
+** $Id: lstrlib.c,v 1.251 2016/05/20 14:13:21 roberto Exp $
+** Standard library for string operations and pattern-matching
+** See Copyright Notice in lua.h
+*/
+
+#define lstrlib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include <ctype.h>
+#include <float.h>
+#include <limits.h>
+#include <locale.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/*
+** maximum number of captures that a pattern can do during
+** pattern-matching. This limit is arbitrary, but must fit in
+** an unsigned char.
+*/
+#if !defined(LUA_MAXCAPTURES)
+#define LUA_MAXCAPTURES 32
+#endif
+
+
+/* macro to 'unsign' a character */
+#define uchar(c) ((unsigned char)(c))
+
+
+/*
+** Some sizes are better limited to fit in 'int', but must also fit in
+** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
+*/
+#define MAX_SIZET ((size_t)(~(size_t)0))
+
+#define MAXSIZE \
+ (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))
+
+
+
+
+static int str_len (lua_State *L) {
+ size_t l;
+ luaL_checklstring(L, 1, &l);
+ lua_pushinteger(L, (lua_Integer)l);
+ return 1;
+}
+
+
+/* translate a relative string position: negative means back from end */
+static lua_Integer posrelat (lua_Integer pos, size_t len) {
+ if (pos >= 0) return pos;
+ else if (0u - (size_t)pos > len) return 0;
+ else return (lua_Integer)len + pos + 1;
+}
+
+
+static int str_sub (lua_State *L) {
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ lua_Integer start = posrelat(luaL_checkinteger(L, 2), l);
+ lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l);
+ if (start < 1) start = 1;
+ if (end > (lua_Integer)l) end = l;
+ if (start <= end)
+ lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1);
+ else lua_pushliteral(L, "");
+ return 1;
+}
+
+
+static int str_reverse (lua_State *L) {
+ size_t l, i;
+ luaL_Buffer b;
+ const char *s = luaL_checklstring(L, 1, &l);
+ char *p = luaL_buffinitsize(L, &b, l);
+ for (i = 0; i < l; i++)
+ p[i] = s[l - i - 1];
+ luaL_pushresultsize(&b, l);
+ return 1;
+}
+
+
+static int str_lower (lua_State *L) {
+ size_t l;
+ size_t i;
+ luaL_Buffer b;
+ const char *s = luaL_checklstring(L, 1, &l);
+ char *p = luaL_buffinitsize(L, &b, l);
+ for (i=0; i<l; i++)
+ p[i] = tolower(uchar(s[i]));
+ luaL_pushresultsize(&b, l);
+ return 1;
+}
+
+
+static int str_upper (lua_State *L) {
+ size_t l;
+ size_t i;
+ luaL_Buffer b;
+ const char *s = luaL_checklstring(L, 1, &l);
+ char *p = luaL_buffinitsize(L, &b, l);
+ for (i=0; i<l; i++)
+ p[i] = toupper(uchar(s[i]));
+ luaL_pushresultsize(&b, l);
+ return 1;
+}
+
+
+static int str_rep (lua_State *L) {
+ size_t l, lsep;
+ const char *s = luaL_checklstring(L, 1, &l);
+ lua_Integer n = luaL_checkinteger(L, 2);
+ const char *sep = luaL_optlstring(L, 3, "", &lsep);
+ if (n <= 0) lua_pushliteral(L, "");
+ else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */
+ return luaL_error(L, "resulting string too large");
+ else {
+ size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;
+ luaL_Buffer b;
+ char *p = luaL_buffinitsize(L, &b, totallen);
+ while (n-- > 1) { /* first n-1 copies (followed by separator) */
+ memcpy(p, s, l * sizeof(char)); p += l;
+ if (lsep > 0) { /* empty 'memcpy' is not that cheap */
+ memcpy(p, sep, lsep * sizeof(char));
+ p += lsep;
+ }
+ }
+ memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */
+ luaL_pushresultsize(&b, totallen);
+ }
+ return 1;
+}
+
+
+static int str_byte (lua_State *L) {
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l);
+ lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l);
+ int n, i;
+ if (posi < 1) posi = 1;
+ if (pose > (lua_Integer)l) pose = l;
+ if (posi > pose) return 0; /* empty interval; return no values */
+ if (pose - posi >= INT_MAX) /* arithmetic overflow? */
+ return luaL_error(L, "string slice too long");
+ n = (int)(pose - posi) + 1;
+ luaL_checkstack(L, n, "string slice too long");
+ for (i=0; i<n; i++)
+ lua_pushinteger(L, uchar(s[posi+i-1]));
+ return n;
+}
+
+
+static int str_char (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ int i;
+ luaL_Buffer b;
+ char *p = luaL_buffinitsize(L, &b, n);
+ for (i=1; i<=n; i++) {
+ lua_Integer c = luaL_checkinteger(L, i);
+ luaL_argcheck(L, uchar(c) == c, i, "value out of range");
+ p[i - 1] = uchar(c);
+ }
+ luaL_pushresultsize(&b, n);
+ return 1;
+}
+
+
+static int writer (lua_State *L, const void *b, size_t size, void *B) {
+ (void)L;
+ luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
+ return 0;
+}
+
+
+static int str_dump (lua_State *L) {
+ luaL_Buffer b;
+ int strip = lua_toboolean(L, 2);
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ lua_settop(L, 1);
+ luaL_buffinit(L,&b);
+ if (lua_dump(L, writer, &b, strip) != 0)
+ return luaL_error(L, "unable to dump given function");
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+
+/*
+** {======================================================
+** PATTERN MATCHING
+** =======================================================
+*/
+
+
+#define CAP_UNFINISHED (-1)
+#define CAP_POSITION (-2)
+
+
+typedef struct MatchState {
+ const char *src_init; /* init of source string */
+ const char *src_end; /* end ('\0') of source string */
+ const char *p_end; /* end ('\0') of pattern */
+ lua_State *L;
+ int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
+ unsigned char level; /* total number of captures (finished or unfinished) */
+ struct {
+ const char *init;
+ ptrdiff_t len;
+ } capture[LUA_MAXCAPTURES];
+} MatchState;
+
+
+/* recursive function */
+static const char *match (MatchState *ms, const char *s, const char *p);
+
+
+/* maximum recursion depth for 'match' */
+#if !defined(MAXCCALLS)
+#define MAXCCALLS 200
+#endif
+
+
+#define L_ESC '%'
+#define SPECIALS "^$*+?.([%-"
+
+
+static int check_capture (MatchState *ms, int l) {
+ l -= '1';
+ if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
+ return luaL_error(ms->L, "invalid capture index %%%d", l + 1);
+ return l;
+}
+
+
+static int capture_to_close (MatchState *ms) {
+ int level = ms->level;
+ for (level--; level>=0; level--)
+ if (ms->capture[level].len == CAP_UNFINISHED) return level;
+ return luaL_error(ms->L, "invalid pattern capture");
+}
+
+
+static const char *classend (MatchState *ms, const char *p) {
+ switch (*p++) {
+ case L_ESC: {
+ if (p == ms->p_end)
+ luaL_error(ms->L, "malformed pattern (ends with '%%')");
+ return p+1;
+ }
+ case '[': {
+ if (*p == '^') p++;
+ do { /* look for a ']' */
+ if (p == ms->p_end)
+ luaL_error(ms->L, "malformed pattern (missing ']')");
+ if (*(p++) == L_ESC && p < ms->p_end)
+ p++; /* skip escapes (e.g. '%]') */
+ } while (*p != ']');
+ return p+1;
+ }
+ default: {
+ return p;
+ }
+ }
+}
+
+
+static int match_class (int c, int cl) {
+ int res;
+ switch (tolower(cl)) {
+ case 'a' : res = isalpha(c); break;
+ case 'c' : res = iscntrl(c); break;
+ case 'd' : res = isdigit(c); break;
+ case 'g' : res = isgraph(c); break;
+ case 'l' : res = islower(c); break;
+ case 'p' : res = ispunct(c); break;
+ case 's' : res = isspace(c); break;
+ case 'u' : res = isupper(c); break;
+ case 'w' : res = isalnum(c); break;
+ case 'x' : res = isxdigit(c); break;
+ case 'z' : res = (c == 0); break; /* deprecated option */
+ default: return (cl == c);
+ }
+ return (islower(cl) ? res : !res);
+}
+
+
+static int matchbracketclass (int c, const char *p, const char *ec) {
+ int sig = 1;
+ if (*(p+1) == '^') {
+ sig = 0;
+ p++; /* skip the '^' */
+ }
+ while (++p < ec) {
+ if (*p == L_ESC) {
+ p++;
+ if (match_class(c, uchar(*p)))
+ return sig;
+ }
+ else if ((*(p+1) == '-') && (p+2 < ec)) {
+ p+=2;
+ if (uchar(*(p-2)) <= c && c <= uchar(*p))
+ return sig;
+ }
+ else if (uchar(*p) == c) return sig;
+ }
+ return !sig;
+}
+
+
+static int singlematch (MatchState *ms, const char *s, const char *p,
+ const char *ep) {
+ if (s >= ms->src_end)
+ return 0;
+ else {
+ int c = uchar(*s);
+ switch (*p) {
+ case '.': return 1; /* matches any char */
+ case L_ESC: return match_class(c, uchar(*(p+1)));
+ case '[': return matchbracketclass(c, p, ep-1);
+ default: return (uchar(*p) == c);
+ }
+ }
+}
+
+
+static const char *matchbalance (MatchState *ms, const char *s,
+ const char *p) {
+ if (p >= ms->p_end - 1)
+ luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')");
+ if (*s != *p) return NULL;
+ else {
+ int b = *p;
+ int e = *(p+1);
+ int cont = 1;
+ while (++s < ms->src_end) {
+ if (*s == e) {
+ if (--cont == 0) return s+1;
+ }
+ else if (*s == b) cont++;
+ }
+ }
+ return NULL; /* string ends out of balance */
+}
+
+
+static const char *max_expand (MatchState *ms, const char *s,
+ const char *p, const char *ep) {
+ ptrdiff_t i = 0; /* counts maximum expand for item */
+ while (singlematch(ms, s + i, p, ep))
+ i++;
+ /* keeps trying to match with the maximum repetitions */
+ while (i>=0) {
+ const char *res = match(ms, (s+i), ep+1);
+ if (res) return res;
+ i--; /* else didn't match; reduce 1 repetition to try again */
+ }
+ return NULL;
+}
+
+
+static const char *min_expand (MatchState *ms, const char *s,
+ const char *p, const char *ep) {
+ for (;;) {
+ const char *res = match(ms, s, ep+1);
+ if (res != NULL)
+ return res;
+ else if (singlematch(ms, s, p, ep))
+ s++; /* try with one more repetition */
+ else return NULL;
+ }
+}
+
+
+static const char *start_capture (MatchState *ms, const char *s,
+ const char *p, int what) {
+ const char *res;
+ int level = ms->level;
+ if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
+ ms->capture[level].init = s;
+ ms->capture[level].len = what;
+ ms->level = level+1;
+ if ((res=match(ms, s, p)) == NULL) /* match failed? */
+ ms->level--; /* undo capture */
+ return res;
+}
+
+
+static const char *end_capture (MatchState *ms, const char *s,
+ const char *p) {
+ int l = capture_to_close(ms);
+ const char *res;
+ ms->capture[l].len = s - ms->capture[l].init; /* close capture */
+ if ((res = match(ms, s, p)) == NULL) /* match failed? */
+ ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
+ return res;
+}
+
+
+static const char *match_capture (MatchState *ms, const char *s, int l) {
+ size_t len;
+ l = check_capture(ms, l);
+ len = ms->capture[l].len;
+ if ((size_t)(ms->src_end-s) >= len &&
+ memcmp(ms->capture[l].init, s, len) == 0)
+ return s+len;
+ else return NULL;
+}
+
+
+static const char *match (MatchState *ms, const char *s, const char *p) {
+ if (ms->matchdepth-- == 0)
+ luaL_error(ms->L, "pattern too complex");
+ init: /* using goto's to optimize tail recursion */
+ if (p != ms->p_end) { /* end of pattern? */
+ switch (*p) {
+ case '(': { /* start capture */
+ if (*(p + 1) == ')') /* position capture? */
+ s = start_capture(ms, s, p + 2, CAP_POSITION);
+ else
+ s = start_capture(ms, s, p + 1, CAP_UNFINISHED);
+ break;
+ }
+ case ')': { /* end capture */
+ s = end_capture(ms, s, p + 1);
+ break;
+ }
+ case '$': {
+ if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */
+ goto dflt; /* no; go to default */
+ s = (s == ms->src_end) ? s : NULL; /* check end of string */
+ break;
+ }
+ case L_ESC: { /* escaped sequences not in the format class[*+?-]? */
+ switch (*(p + 1)) {
+ case 'b': { /* balanced string? */
+ s = matchbalance(ms, s, p + 2);
+ if (s != NULL) {
+ p += 4; goto init; /* return match(ms, s, p + 4); */
+ } /* else fail (s == NULL) */
+ break;
+ }
+ case 'f': { /* frontier? */
+ const char *ep; char previous;
+ p += 2;
+ if (*p != '[')
+ luaL_error(ms->L, "missing '[' after '%%f' in pattern");
+ ep = classend(ms, p); /* points to what is next */
+ previous = (s == ms->src_init) ? '\0' : *(s - 1);
+ if (!matchbracketclass(uchar(previous), p, ep - 1) &&
+ matchbracketclass(uchar(*s), p, ep - 1)) {
+ p = ep; goto init; /* return match(ms, s, ep); */
+ }
+ s = NULL; /* match failed */
+ break;
+ }
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9': { /* capture results (%0-%9)? */
+ s = match_capture(ms, s, uchar(*(p + 1)));
+ if (s != NULL) {
+ p += 2; goto init; /* return match(ms, s, p + 2) */
+ }
+ break;
+ }
+ default: goto dflt;
+ }
+ break;
+ }
+ default: dflt: { /* pattern class plus optional suffix */
+ const char *ep = classend(ms, p); /* points to optional suffix */
+ /* does not match at least once? */
+ if (!singlematch(ms, s, p, ep)) {
+ if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */
+ p = ep + 1; goto init; /* return match(ms, s, ep + 1); */
+ }
+ else /* '+' or no suffix */
+ s = NULL; /* fail */
+ }
+ else { /* matched once */
+ switch (*ep) { /* handle optional suffix */
+ case '?': { /* optional */
+ const char *res;
+ if ((res = match(ms, s + 1, ep + 1)) != NULL)
+ s = res;
+ else {
+ p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */
+ }
+ break;
+ }
+ case '+': /* 1 or more repetitions */
+ s++; /* 1 match already done */
+ /* FALLTHROUGH */
+ case '*': /* 0 or more repetitions */
+ s = max_expand(ms, s, p, ep);
+ break;
+ case '-': /* 0 or more repetitions (minimum) */
+ s = min_expand(ms, s, p, ep);
+ break;
+ default: /* no suffix */
+ s++; p = ep; goto init; /* return match(ms, s + 1, ep); */
+ }
+ }
+ break;
+ }
+ }
+ }
+ ms->matchdepth++;
+ return s;
+}
+
+
+
+static const char *lmemfind (const char *s1, size_t l1,
+ const char *s2, size_t l2) {
+ if (l2 == 0) return s1; /* empty strings are everywhere */
+ else if (l2 > l1) return NULL; /* avoids a negative 'l1' */
+ else {
+ const char *init; /* to search for a '*s2' inside 's1' */
+ l2--; /* 1st char will be checked by 'memchr' */
+ l1 = l1-l2; /* 's2' cannot be found after that */
+ while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
+ init++; /* 1st char is already checked */
+ if (memcmp(init, s2+1, l2) == 0)
+ return init-1;
+ else { /* correct 'l1' and 's1' to try again */
+ l1 -= init-s1;
+ s1 = init;
+ }
+ }
+ return NULL; /* not found */
+ }
+}
+
+
+static void push_onecapture (MatchState *ms, int i, const char *s,
+ const char *e) {
+ if (i >= ms->level) {
+ if (i == 0) /* ms->level == 0, too */
+ lua_pushlstring(ms->L, s, e - s); /* add whole match */
+ else
+ luaL_error(ms->L, "invalid capture index %%%d", i + 1);
+ }
+ else {
+ ptrdiff_t l = ms->capture[i].len;
+ if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
+ if (l == CAP_POSITION)
+ lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
+ else
+ lua_pushlstring(ms->L, ms->capture[i].init, l);
+ }
+}
+
+
+static int push_captures (MatchState *ms, const char *s, const char *e) {
+ int i;
+ int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
+ luaL_checkstack(ms->L, nlevels, "too many captures");
+ for (i = 0; i < nlevels; i++)
+ push_onecapture(ms, i, s, e);
+ return nlevels; /* number of strings pushed */
+}
+
+
+/* check whether pattern has no special characters */
+static int nospecials (const char *p, size_t l) {
+ size_t upto = 0;
+ do {
+ if (strpbrk(p + upto, SPECIALS))
+ return 0; /* pattern has a special character */
+ upto += strlen(p + upto) + 1; /* may have more after \0 */
+ } while (upto <= l);
+ return 1; /* no special chars found */
+}
+
+
+static void prepstate (MatchState *ms, lua_State *L,
+ const char *s, size_t ls, const char *p, size_t lp) {
+ ms->L = L;
+ ms->matchdepth = MAXCCALLS;
+ ms->src_init = s;
+ ms->src_end = s + ls;
+ ms->p_end = p + lp;
+}
+
+
+static void reprepstate (MatchState *ms) {
+ ms->level = 0;
+ lua_assert(ms->matchdepth == MAXCCALLS);
+}
+
+
+static int str_find_aux (lua_State *L, int find) {
+ size_t ls, lp;
+ const char *s = luaL_checklstring(L, 1, &ls);
+ const char *p = luaL_checklstring(L, 2, &lp);
+ lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls);
+ if (init < 1) init = 1;
+ else if (init > (lua_Integer)ls + 1) { /* start after string's end? */
+ lua_pushnil(L); /* cannot find anything */
+ return 1;
+ }
+ /* explicit request or no special characters? */
+ if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) {
+ /* do a plain search */
+ const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp);
+ if (s2) {
+ lua_pushinteger(L, (s2 - s) + 1);
+ lua_pushinteger(L, (s2 - s) + lp);
+ return 2;
+ }
+ }
+ else {
+ MatchState ms;
+ const char *s1 = s + init - 1;
+ int anchor = (*p == '^');
+ if (anchor) {
+ p++; lp--; /* skip anchor character */
+ }
+ prepstate(&ms, L, s, ls, p, lp);
+ do {
+ const char *res;
+ reprepstate(&ms);
+ if ((res=match(&ms, s1, p)) != NULL) {
+ if (find) {
+ lua_pushinteger(L, (s1 - s) + 1); /* start */
+ lua_pushinteger(L, res - s); /* end */
+ return push_captures(&ms, NULL, 0) + 2;
+ }
+ else
+ return push_captures(&ms, s1, res);
+ }
+ } while (s1++ < ms.src_end && !anchor);
+ }
+ lua_pushnil(L); /* not found */
+ return 1;
+}
+
+
+static int str_find (lua_State *L) {
+ return str_find_aux(L, 1);
+}
+
+
+static int str_match (lua_State *L) {
+ return str_find_aux(L, 0);
+}
+
+
+/* state for 'gmatch' */
+typedef struct GMatchState {
+ const char *src; /* current position */
+ const char *p; /* pattern */
+ const char *lastmatch; /* end of last match */
+ MatchState ms; /* match state */
+} GMatchState;
+
+
+static int gmatch_aux (lua_State *L) {
+ GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
+ const char *src;
+ gm->ms.L = L;
+ for (src = gm->src; src <= gm->ms.src_end; src++) {
+ const char *e;
+ reprepstate(&gm->ms);
+ if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
+ gm->src = gm->lastmatch = e;
+ return push_captures(&gm->ms, src, e);
+ }
+ }
+ return 0; /* not found */
+}
+
+
+static int gmatch (lua_State *L) {
+ size_t ls, lp;
+ const char *s = luaL_checklstring(L, 1, &ls);
+ const char *p = luaL_checklstring(L, 2, &lp);
+ GMatchState *gm;
+ lua_settop(L, 2); /* keep them on closure to avoid being collected */
+ gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState));
+ prepstate(&gm->ms, L, s, ls, p, lp);
+ gm->src = s; gm->p = p; gm->lastmatch = NULL;
+ lua_pushcclosure(L, gmatch_aux, 3);
+ return 1;
+}
+
+
+static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
+ const char *e) {
+ size_t l, i;
+ lua_State *L = ms->L;
+ const char *news = lua_tolstring(L, 3, &l);
+ for (i = 0; i < l; i++) {
+ if (news[i] != L_ESC)
+ luaL_addchar(b, news[i]);
+ else {
+ i++; /* skip ESC */
+ if (!isdigit(uchar(news[i]))) {
+ if (news[i] != L_ESC)
+ luaL_error(L, "invalid use of '%c' in replacement string", L_ESC);
+ luaL_addchar(b, news[i]);
+ }
+ else if (news[i] == '0')
+ luaL_addlstring(b, s, e - s);
+ else {
+ push_onecapture(ms, news[i] - '1', s, e);
+ luaL_tolstring(L, -1, NULL); /* if number, convert it to string */
+ lua_remove(L, -2); /* remove original value */
+ luaL_addvalue(b); /* add capture to accumulated result */
+ }
+ }
+ }
+}
+
+
+static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
+ const char *e, int tr) {
+ lua_State *L = ms->L;
+ switch (tr) {
+ case LUA_TFUNCTION: {
+ int n;
+ lua_pushvalue(L, 3);
+ n = push_captures(ms, s, e);
+ lua_call(L, n, 1);
+ break;
+ }
+ case LUA_TTABLE: {
+ push_onecapture(ms, 0, s, e);
+ lua_gettable(L, 3);
+ break;
+ }
+ default: { /* LUA_TNUMBER or LUA_TSTRING */
+ add_s(ms, b, s, e);
+ return;
+ }
+ }
+ if (!lua_toboolean(L, -1)) { /* nil or false? */
+ lua_pop(L, 1);
+ lua_pushlstring(L, s, e - s); /* keep original text */
+ }
+ else if (!lua_isstring(L, -1))
+ luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));
+ luaL_addvalue(b); /* add result to accumulator */
+}
+
+
+static int str_gsub (lua_State *L) {
+ size_t srcl, lp;
+ const char *src = luaL_checklstring(L, 1, &srcl); /* subject */
+ const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
+ const char *lastmatch = NULL; /* end of last match */
+ int tr = lua_type(L, 3); /* replacement type */
+ lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
+ int anchor = (*p == '^');
+ lua_Integer n = 0; /* replacement count */
+ MatchState ms;
+ luaL_Buffer b;
+ luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
+ tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
+ "string/function/table expected");
+ luaL_buffinit(L, &b);
+ if (anchor) {
+ p++; lp--; /* skip anchor character */
+ }
+ prepstate(&ms, L, src, srcl, p, lp);
+ while (n < max_s) {
+ const char *e;
+ reprepstate(&ms); /* (re)prepare state for new match */
+ if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
+ n++;
+ add_value(&ms, &b, src, e, tr); /* add replacement to buffer */
+ src = lastmatch = e;
+ }
+ else if (src < ms.src_end) /* otherwise, skip one character */
+ luaL_addchar(&b, *src++);
+ else break; /* end of subject */
+ if (anchor) break;
+ }
+ luaL_addlstring(&b, src, ms.src_end-src);
+ luaL_pushresult(&b);
+ lua_pushinteger(L, n); /* number of substitutions */
+ return 2;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** STRING FORMAT
+** =======================================================
+*/
+
+#if !defined(lua_number2strx) /* { */
+
+/*
+** Hexadecimal floating-point formatter
+*/
+
+#include <math.h>
+
+#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
+
+
+/*
+** Number of bits that goes into the first digit. It can be any value
+** between 1 and 4; the following definition tries to align the number
+** to nibble boundaries by making what is left after that first digit a
+** multiple of 4.
+*/
+#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1)
+
+
+/*
+** Add integer part of 'x' to buffer and return new 'x'
+*/
+static lua_Number adddigit (char *buff, int n, lua_Number x) {
+ lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */
+ int d = (int)dd;
+ buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */
+ return x - dd; /* return what is left */
+}
+
+
+static int num2straux (char *buff, int sz, lua_Number x) {
+ if (x != x || x == HUGE_VAL || x == -HUGE_VAL) /* inf or NaN? */
+ return l_sprintf(buff, sz, LUA_NUMBER_FMT, x); /* equal to '%g' */
+ else if (x == 0) { /* can be -0... */
+ /* create "0" or "-0" followed by exponent */
+ return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", x);
+ }
+ else {
+ int e;
+ lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */
+ int n = 0; /* character count */
+ if (m < 0) { /* is number negative? */
+ buff[n++] = '-'; /* add signal */
+ m = -m; /* make it positive */
+ }
+ buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */
+ m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */
+ e -= L_NBFD; /* this digit goes before the radix point */
+ if (m > 0) { /* more digits? */
+ buff[n++] = lua_getlocaledecpoint(); /* add radix point */
+ do { /* add as many digits as needed */
+ m = adddigit(buff, n++, m * 16);
+ } while (m > 0);
+ }
+ n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */
+ lua_assert(n < sz);
+ return n;
+ }
+}
+
+
+static int lua_number2strx (lua_State *L, char *buff, int sz,
+ const char *fmt, lua_Number x) {
+ int n = num2straux(buff, sz, x);
+ if (fmt[SIZELENMOD] == 'A') {
+ int i;
+ for (i = 0; i < n; i++)
+ buff[i] = toupper(uchar(buff[i]));
+ }
+ else if (fmt[SIZELENMOD] != 'a')
+ luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
+ return n;
+}
+
+#endif /* } */
+
+
+/*
+** Maximum size of each formatted item. This maximum size is produced
+** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.',
+** and '\0') + number of decimal digits to represent maxfloat (which
+** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra
+** expenses", such as locale-dependent stuff)
+*/
+#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP))
+
+
+/* valid flags in a format specification */
+#define FLAGS "-+ #0"
+
+/*
+** maximum size of each format specification (such as "%-099.99d")
+*/
+#define MAX_FORMAT 32
+
+
+static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
+ luaL_addchar(b, '"');
+ while (len--) {
+ if (*s == '"' || *s == '\\' || *s == '\n') {
+ luaL_addchar(b, '\\');
+ luaL_addchar(b, *s);
+ }
+ else if (iscntrl(uchar(*s))) {
+ char buff[10];
+ if (!isdigit(uchar(*(s+1))))
+ l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
+ else
+ l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s));
+ luaL_addstring(b, buff);
+ }
+ else
+ luaL_addchar(b, *s);
+ s++;
+ }
+ luaL_addchar(b, '"');
+}
+
+
+/*
+** Ensures the 'buff' string uses a dot as the radix character.
+*/
+static void checkdp (char *buff, int nb) {
+ if (memchr(buff, '.', nb) == NULL) { /* no dot? */
+ char point = lua_getlocaledecpoint(); /* try locale point */
+ char *ppoint = memchr(buff, point, nb);
+ if (ppoint) *ppoint = '.'; /* change it to a dot */
+ }
+}
+
+
+static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
+ switch (lua_type(L, arg)) {
+ case LUA_TSTRING: {
+ size_t len;
+ const char *s = lua_tolstring(L, arg, &len);
+ addquoted(b, s, len);
+ break;
+ }
+ case LUA_TNUMBER: {
+ char *buff = luaL_prepbuffsize(b, MAX_ITEM);
+ int nb;
+ if (!lua_isinteger(L, arg)) { /* float? */
+ lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */
+ nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n);
+ checkdp(buff, nb); /* ensure it uses a dot */
+ }
+ else { /* integers */
+ lua_Integer n = lua_tointeger(L, arg);
+ const char *format = (n == LUA_MININTEGER) /* corner case? */
+ ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */
+ : LUA_INTEGER_FMT; /* else use default format */
+ nb = l_sprintf(buff, MAX_ITEM, format, n);
+ }
+ luaL_addsize(b, nb);
+ break;
+ }
+ case LUA_TNIL: case LUA_TBOOLEAN: {
+ luaL_tolstring(L, arg, NULL);
+ luaL_addvalue(b);
+ break;
+ }
+ default: {
+ luaL_argerror(L, arg, "value has no literal form");
+ }
+ }
+}
+
+
+static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
+ const char *p = strfrmt;
+ while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
+ if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char))
+ luaL_error(L, "invalid format (repeated flags)");
+ if (isdigit(uchar(*p))) p++; /* skip width */
+ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
+ if (*p == '.') {
+ p++;
+ if (isdigit(uchar(*p))) p++; /* skip precision */
+ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
+ }
+ if (isdigit(uchar(*p)))
+ luaL_error(L, "invalid format (width or precision too long)");
+ *(form++) = '%';
+ memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
+ form += (p - strfrmt) + 1;
+ *form = '\0';
+ return p;
+}
+
+
+/*
+** add length modifier into formats
+*/
+static void addlenmod (char *form, const char *lenmod) {
+ size_t l = strlen(form);
+ size_t lm = strlen(lenmod);
+ char spec = form[l - 1];
+ strcpy(form + l - 1, lenmod);
+ form[l + lm - 1] = spec;
+ form[l + lm] = '\0';
+}
+
+
+static int str_format (lua_State *L) {
+ int top = lua_gettop(L);
+ int arg = 1;
+ size_t sfl;
+ const char *strfrmt = luaL_checklstring(L, arg, &sfl);
+ const char *strfrmt_end = strfrmt+sfl;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ while (strfrmt < strfrmt_end) {
+ if (*strfrmt != L_ESC)
+ luaL_addchar(&b, *strfrmt++);
+ else if (*++strfrmt == L_ESC)
+ luaL_addchar(&b, *strfrmt++); /* %% */
+ else { /* format item */
+ char form[MAX_FORMAT]; /* to store the format ('%...') */
+ char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */
+ int nb = 0; /* number of bytes in added item */
+ if (++arg > top)
+ luaL_argerror(L, arg, "no value");
+ strfrmt = scanformat(L, strfrmt, form);
+ switch (*strfrmt++) {
+ case 'c': {
+ nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg));
+ break;
+ }
+ case 'd': case 'i':
+ case 'o': case 'u': case 'x': case 'X': {
+ lua_Integer n = luaL_checkinteger(L, arg);
+ addlenmod(form, LUA_INTEGER_FRMLEN);
+ nb = l_sprintf(buff, MAX_ITEM, form, n);
+ break;
+ }
+ case 'a': case 'A':
+ addlenmod(form, LUA_NUMBER_FRMLEN);
+ nb = lua_number2strx(L, buff, MAX_ITEM, form,
+ luaL_checknumber(L, arg));
+ break;
+ case 'e': case 'E': case 'f':
+ case 'g': case 'G': {
+ addlenmod(form, LUA_NUMBER_FRMLEN);
+ nb = l_sprintf(buff, MAX_ITEM, form, luaL_checknumber(L, arg));
+ break;
+ }
+ case 'q': {
+ addliteral(L, &b, arg);
+ break;
+ }
+ case 's': {
+ size_t l;
+ const char *s = luaL_tolstring(L, arg, &l);
+ if (form[2] == '\0') /* no modifiers? */
+ luaL_addvalue(&b); /* keep entire string */
+ else {
+ luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
+ if (!strchr(form, '.') && l >= 100) {
+ /* no precision and string is too long to be formatted */
+ luaL_addvalue(&b); /* keep entire string */
+ }
+ else { /* format the string into 'buff' */
+ nb = l_sprintf(buff, MAX_ITEM, form, s);
+ lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
+ }
+ }
+ break;
+ }
+ default: { /* also treat cases 'pnLlh' */
+ return luaL_error(L, "invalid option '%%%c' to 'format'",
+ *(strfrmt - 1));
+ }
+ }
+ lua_assert(nb < MAX_ITEM);
+ luaL_addsize(&b, nb);
+ }
+ }
+ luaL_pushresult(&b);
+ return 1;
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** PACK/UNPACK
+** =======================================================
+*/
+
+
+/* value used for padding */
+#if !defined(LUAL_PACKPADBYTE)
+#define LUAL_PACKPADBYTE 0x00
+#endif
+
+/* maximum size for the binary representation of an integer */
+#define MAXINTSIZE 16
+
+/* number of bits in a character */
+#define NB CHAR_BIT
+
+/* mask for one character (NB 1's) */
+#define MC ((1 << NB) - 1)
+
+/* size of a lua_Integer */
+#define SZINT ((int)sizeof(lua_Integer))
+
+
+/* dummy union to get native endianness */
+static const union {
+ int dummy;
+ char little; /* true iff machine is little endian */
+} nativeendian = {1};
+
+
+/* dummy structure to get native alignment requirements */
+struct cD {
+ char c;
+ union { double d; void *p; lua_Integer i; lua_Number n; } u;
+};
+
+#define MAXALIGN (offsetof(struct cD, u))
+
+
+/*
+** Union for serializing floats
+*/
+typedef union Ftypes {
+ float f;
+ double d;
+ lua_Number n;
+ char buff[5 * sizeof(lua_Number)]; /* enough for any float type */
+} Ftypes;
+
+
+/*
+** information to pack/unpack stuff
+*/
+typedef struct Header {
+ lua_State *L;
+ int islittle;
+ int maxalign;
+} Header;
+
+
+/*
+** options for pack/unpack
+*/
+typedef enum KOption {
+ Kint, /* signed integers */
+ Kuint, /* unsigned integers */
+ Kfloat, /* floating-point numbers */
+ Kchar, /* fixed-length strings */
+ Kstring, /* strings with prefixed length */
+ Kzstr, /* zero-terminated strings */
+ Kpadding, /* padding */
+ Kpaddalign, /* padding for alignment */
+ Knop /* no-op (configuration or spaces) */
+} KOption;
+
+
+/*
+** Read an integer numeral from string 'fmt' or return 'df' if
+** there is no numeral
+*/
+static int digit (int c) { return '0' <= c && c <= '9'; }
+
+static int getnum (const char **fmt, int df) {
+ if (!digit(**fmt)) /* no number? */
+ return df; /* return default value */
+ else {
+ int a = 0;
+ do {
+ a = a*10 + (*((*fmt)++) - '0');
+ } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10);
+ return a;
+ }
+}
+
+
+/*
+** Read an integer numeral and raises an error if it is larger
+** than the maximum size for integers.
+*/
+static int getnumlimit (Header *h, const char **fmt, int df) {
+ int sz = getnum(fmt, df);
+ if (sz > MAXINTSIZE || sz <= 0)
+ luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
+ sz, MAXINTSIZE);
+ return sz;
+}
+
+
+/*
+** Initialize Header
+*/
+static void initheader (lua_State *L, Header *h) {
+ h->L = L;
+ h->islittle = nativeendian.little;
+ h->maxalign = 1;
+}
+
+
+/*
+** Read and classify next option. 'size' is filled with option's size.
+*/
+static KOption getoption (Header *h, const char **fmt, int *size) {
+ int opt = *((*fmt)++);
+ *size = 0; /* default */
+ switch (opt) {
+ case 'b': *size = sizeof(char); return Kint;
+ case 'B': *size = sizeof(char); return Kuint;
+ case 'h': *size = sizeof(short); return Kint;
+ case 'H': *size = sizeof(short); return Kuint;
+ case 'l': *size = sizeof(long); return Kint;
+ case 'L': *size = sizeof(long); return Kuint;
+ case 'j': *size = sizeof(lua_Integer); return Kint;
+ case 'J': *size = sizeof(lua_Integer); return Kuint;
+ case 'T': *size = sizeof(size_t); return Kuint;
+ case 'f': *size = sizeof(float); return Kfloat;
+ case 'd': *size = sizeof(double); return Kfloat;
+ case 'n': *size = sizeof(lua_Number); return Kfloat;
+ case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
+ case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
+ case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
+ case 'c':
+ *size = getnum(fmt, -1);
+ if (*size == -1)
+ luaL_error(h->L, "missing size for format option 'c'");
+ return Kchar;
+ case 'z': return Kzstr;
+ case 'x': *size = 1; return Kpadding;
+ case 'X': return Kpaddalign;
+ case ' ': break;
+ case '<': h->islittle = 1; break;
+ case '>': h->islittle = 0; break;
+ case '=': h->islittle = nativeendian.little; break;
+ case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break;
+ default: luaL_error(h->L, "invalid format option '%c'", opt);
+ }
+ return Knop;
+}
+
+
+/*
+** Read, classify, and fill other details about the next option.
+** 'psize' is filled with option's size, 'notoalign' with its
+** alignment requirements.
+** Local variable 'size' gets the size to be aligned. (Kpadal option
+** always gets its full alignment, other options are limited by
+** the maximum alignment ('maxalign'). Kchar option needs no alignment
+** despite its size.
+*/
+static KOption getdetails (Header *h, size_t totalsize,
+ const char **fmt, int *psize, int *ntoalign) {
+ KOption opt = getoption(h, fmt, psize);
+ int align = *psize; /* usually, alignment follows size */
+ if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
+ if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
+ luaL_argerror(h->L, 1, "invalid next option for option 'X'");
+ }
+ if (align <= 1 || opt == Kchar) /* need no alignment? */
+ *ntoalign = 0;
+ else {
+ if (align > h->maxalign) /* enforce maximum alignment */
+ align = h->maxalign;
+ if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */
+ luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
+ *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
+ }
+ return opt;
+}
+
+
+/*
+** Pack integer 'n' with 'size' bytes and 'islittle' endianness.
+** The final 'if' handles the case when 'size' is larger than
+** the size of a Lua integer, correcting the extra sign-extension
+** bytes if necessary (by default they would be zeros).
+*/
+static void packint (luaL_Buffer *b, lua_Unsigned n,
+ int islittle, int size, int neg) {
+ char *buff = luaL_prepbuffsize(b, size);
+ int i;
+ buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */
+ for (i = 1; i < size; i++) {
+ n >>= NB;
+ buff[islittle ? i : size - 1 - i] = (char)(n & MC);
+ }
+ if (neg && size > SZINT) { /* negative number need sign extension? */
+ for (i = SZINT; i < size; i++) /* correct extra bytes */
+ buff[islittle ? i : size - 1 - i] = (char)MC;
+ }
+ luaL_addsize(b, size); /* add result to buffer */
+}
+
+
+/*
+** Copy 'size' bytes from 'src' to 'dest', correcting endianness if
+** given 'islittle' is different from native endianness.
+*/
+static void copywithendian (volatile char *dest, volatile const char *src,
+ int size, int islittle) {
+ if (islittle == nativeendian.little) {
+ while (size-- != 0)
+ *(dest++) = *(src++);
+ }
+ else {
+ dest += size - 1;
+ while (size-- != 0)
+ *(dest--) = *(src++);
+ }
+}
+
+
+static int str_pack (lua_State *L) {
+ luaL_Buffer b;
+ Header h;
+ const char *fmt = luaL_checkstring(L, 1); /* format string */
+ int arg = 1; /* current argument to pack */
+ size_t totalsize = 0; /* accumulate total size of result */
+ initheader(L, &h);
+ lua_pushnil(L); /* mark to separate arguments from string buffer */
+ luaL_buffinit(L, &b);
+ while (*fmt != '\0') {
+ int size, ntoalign;
+ KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
+ totalsize += ntoalign + size;
+ while (ntoalign-- > 0)
+ luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
+ arg++;
+ switch (opt) {
+ case Kint: { /* signed integers */
+ lua_Integer n = luaL_checkinteger(L, arg);
+ if (size < SZINT) { /* need overflow check? */
+ lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
+ luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
+ }
+ packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0));
+ break;
+ }
+ case Kuint: { /* unsigned integers */
+ lua_Integer n = luaL_checkinteger(L, arg);
+ if (size < SZINT) /* need overflow check? */
+ luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),
+ arg, "unsigned overflow");
+ packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
+ break;
+ }
+ case Kfloat: { /* floating-point options */
+ volatile Ftypes u;
+ char *buff = luaL_prepbuffsize(&b, size);
+ lua_Number n = luaL_checknumber(L, arg); /* get argument */
+ if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */
+ else if (size == sizeof(u.d)) u.d = (double)n;
+ else u.n = n;
+ /* move 'u' to final result, correcting endianness if needed */
+ copywithendian(buff, u.buff, size, h.islittle);
+ luaL_addsize(&b, size);
+ break;
+ }
+ case Kchar: { /* fixed-size string */
+ size_t len;
+ const char *s = luaL_checklstring(L, arg, &len);
+ luaL_argcheck(L, len <= (size_t)size, arg,
+ "string longer than given size");
+ luaL_addlstring(&b, s, len); /* add string */
+ while (len++ < (size_t)size) /* pad extra space */
+ luaL_addchar(&b, LUAL_PACKPADBYTE);
+ break;
+ }
+ case Kstring: { /* strings with length count */
+ size_t len;
+ const char *s = luaL_checklstring(L, arg, &len);
+ luaL_argcheck(L, size >= (int)sizeof(size_t) ||
+ len < ((size_t)1 << (size * NB)),
+ arg, "string length does not fit in given size");
+ packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */
+ luaL_addlstring(&b, s, len);
+ totalsize += len;
+ break;
+ }
+ case Kzstr: { /* zero-terminated string */
+ size_t len;
+ const char *s = luaL_checklstring(L, arg, &len);
+ luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros");
+ luaL_addlstring(&b, s, len);
+ luaL_addchar(&b, '\0'); /* add zero at the end */
+ totalsize += len + 1;
+ break;
+ }
+ case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */
+ case Kpaddalign: case Knop:
+ arg--; /* undo increment */
+ break;
+ }
+ }
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+static int str_packsize (lua_State *L) {
+ Header h;
+ const char *fmt = luaL_checkstring(L, 1); /* format string */
+ size_t totalsize = 0; /* accumulate total size of result */
+ initheader(L, &h);
+ while (*fmt != '\0') {
+ int size, ntoalign;
+ KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
+ size += ntoalign; /* total space used by option */
+ luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
+ "format result too large");
+ totalsize += size;
+ switch (opt) {
+ case Kstring: /* strings with length count */
+ case Kzstr: /* zero-terminated string */
+ luaL_argerror(L, 1, "variable-length format");
+ /* call never return, but to avoid warnings: *//* FALLTHROUGH */
+ default: break;
+ }
+ }
+ lua_pushinteger(L, (lua_Integer)totalsize);
+ return 1;
+}
+
+
+/*
+** Unpack an integer with 'size' bytes and 'islittle' endianness.
+** If size is smaller than the size of a Lua integer and integer
+** is signed, must do sign extension (propagating the sign to the
+** higher bits); if size is larger than the size of a Lua integer,
+** it must check the unread bytes to see whether they do not cause an
+** overflow.
+*/
+static lua_Integer unpackint (lua_State *L, const char *str,
+ int islittle, int size, int issigned) {
+ lua_Unsigned res = 0;
+ int i;
+ int limit = (size <= SZINT) ? size : SZINT;
+ for (i = limit - 1; i >= 0; i--) {
+ res <<= NB;
+ res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i];
+ }
+ if (size < SZINT) { /* real size smaller than lua_Integer? */
+ if (issigned) { /* needs sign extension? */
+ lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1);
+ res = ((res ^ mask) - mask); /* do sign extension */
+ }
+ }
+ else if (size > SZINT) { /* must check unread bytes */
+ int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;
+ for (i = limit; i < size; i++) {
+ if ((unsigned char)str[islittle ? i : size - 1 - i] != mask)
+ luaL_error(L, "%d-byte integer does not fit into Lua Integer", size);
+ }
+ }
+ return (lua_Integer)res;
+}
+
+
+static int str_unpack (lua_State *L) {
+ Header h;
+ const char *fmt = luaL_checkstring(L, 1);
+ size_t ld;
+ const char *data = luaL_checklstring(L, 2, &ld);
+ size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1;
+ int n = 0; /* number of results */
+ luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
+ initheader(L, &h);
+ while (*fmt != '\0') {
+ int size, ntoalign;
+ KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
+ if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld)
+ luaL_argerror(L, 2, "data string too short");
+ pos += ntoalign; /* skip alignment */
+ /* stack space for item + next position */
+ luaL_checkstack(L, 2, "too many results");
+ n++;
+ switch (opt) {
+ case Kint:
+ case Kuint: {
+ lua_Integer res = unpackint(L, data + pos, h.islittle, size,
+ (opt == Kint));
+ lua_pushinteger(L, res);
+ break;
+ }
+ case Kfloat: {
+ volatile Ftypes u;
+ lua_Number num;
+ copywithendian(u.buff, data + pos, size, h.islittle);
+ if (size == sizeof(u.f)) num = (lua_Number)u.f;
+ else if (size == sizeof(u.d)) num = (lua_Number)u.d;
+ else num = u.n;
+ lua_pushnumber(L, num);
+ break;
+ }
+ case Kchar: {
+ lua_pushlstring(L, data + pos, size);
+ break;
+ }
+ case Kstring: {
+ size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0);
+ luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short");
+ lua_pushlstring(L, data + pos + size, len);
+ pos += len; /* skip string */
+ break;
+ }
+ case Kzstr: {
+ size_t len = (int)strlen(data + pos);
+ lua_pushlstring(L, data + pos, len);
+ pos += len + 1; /* skip string plus final '\0' */
+ break;
+ }
+ case Kpaddalign: case Kpadding: case Knop:
+ n--; /* undo increment */
+ break;
+ }
+ pos += size;
+ }
+ lua_pushinteger(L, pos + 1); /* next position */
+ return n + 1;
+}
+
+/* }====================================================== */
+
+
+static const luaL_Reg strlib[] = {
+ {"byte", str_byte},
+ {"char", str_char},
+ {"dump", str_dump},
+ {"find", str_find},
+ {"format", str_format},
+ {"gmatch", gmatch},
+ {"gsub", str_gsub},
+ {"len", str_len},
+ {"lower", str_lower},
+ {"match", str_match},
+ {"rep", str_rep},
+ {"reverse", str_reverse},
+ {"sub", str_sub},
+ {"upper", str_upper},
+ {"pack", str_pack},
+ {"packsize", str_packsize},
+ {"unpack", str_unpack},
+ {NULL, NULL}
+};
+
+
+static void createmetatable (lua_State *L) {
+ lua_createtable(L, 0, 1); /* table to be metatable for strings */
+ lua_pushliteral(L, ""); /* dummy string */
+ lua_pushvalue(L, -2); /* copy table */
+ lua_setmetatable(L, -2); /* set table as metatable for strings */
+ lua_pop(L, 1); /* pop dummy string */
+ lua_pushvalue(L, -2); /* get string library */
+ lua_setfield(L, -2, "__index"); /* metatable.__index = string */
+ lua_pop(L, 1); /* pop metatable */
+}
+
+
+/*
+** Open string library
+*/
+LUAMOD_API int luaopen_string (lua_State *L) {
+ luaL_newlib(L, strlib);
+ createmetatable(L);
+ return 1;
+}
+
diff --git a/external/lua-5.3.3/src/ltable.c b/external/lua-5.3.3/src/ltable.c
new file mode 100644
index 0000000..7e15b71
--- /dev/null
+++ b/external/lua-5.3.3/src/ltable.c
@@ -0,0 +1,669 @@
+/*
+** $Id: ltable.c,v 2.117 2015/11/19 19:16:22 roberto Exp $
+** Lua tables (hash)
+** See Copyright Notice in lua.h
+*/
+
+#define ltable_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+/*
+** Implementation of tables (aka arrays, objects, or hash tables).
+** Tables keep its elements in two parts: an array part and a hash part.
+** Non-negative integer keys are all candidates to be kept in the array
+** part. The actual size of the array is the largest 'n' such that
+** more than half the slots between 1 and n are in use.
+** Hash uses a mix of chained scatter table with Brent's variation.
+** A main invariant of these tables is that, if an element is not
+** in its main position (i.e. the 'original' position that its hash gives
+** to it), then the colliding element is in its own main position.
+** Hence even when the load factor reaches 100%, performance remains good.
+*/
+
+#include <math.h>
+#include <limits.h>
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "lvm.h"
+
+
+/*
+** Maximum size of array part (MAXASIZE) is 2^MAXABITS. MAXABITS is
+** the largest integer such that MAXASIZE fits in an unsigned int.
+*/
+#define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1)
+#define MAXASIZE (1u << MAXABITS)
+
+/*
+** Maximum size of hash part is 2^MAXHBITS. MAXHBITS is the largest
+** integer such that 2^MAXHBITS fits in a signed int. (Note that the
+** maximum number of elements in a table, 2^MAXABITS + 2^MAXHBITS, still
+** fits comfortably in an unsigned int.)
+*/
+#define MAXHBITS (MAXABITS - 1)
+
+
+#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
+
+#define hashstr(t,str) hashpow2(t, (str)->hash)
+#define hashboolean(t,p) hashpow2(t, p)
+#define hashint(t,i) hashpow2(t, i)
+
+
+/*
+** for some types, it is better to avoid modulus by power of 2, as
+** they tend to have many 2 factors.
+*/
+#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
+
+
+#define hashpointer(t,p) hashmod(t, point2uint(p))
+
+
+#define dummynode (&dummynode_)
+
+#define isdummy(n) ((n) == dummynode)
+
+static const Node dummynode_ = {
+ {NILCONSTANT}, /* value */
+ {{NILCONSTANT, 0}} /* key */
+};
+
+
+/*
+** Hash for floating-point numbers.
+** The main computation should be just
+** n = frexp(n, &i); return (n * INT_MAX) + i
+** but there are some numerical subtleties.
+** In a two-complement representation, INT_MAX does not has an exact
+** representation as a float, but INT_MIN does; because the absolute
+** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the
+** absolute value of the product 'frexp * -INT_MIN' is smaller or equal
+** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when
+** adding 'i'; the use of '~u' (instead of '-u') avoids problems with
+** INT_MIN.
+*/
+#if !defined(l_hashfloat)
+static int l_hashfloat (lua_Number n) {
+ int i;
+ lua_Integer ni;
+ n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN);
+ if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */
+ lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL));
+ return 0;
+ }
+ else { /* normal case */
+ unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni);
+ return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u);
+ }
+}
+#endif
+
+
+/*
+** returns the 'main' position of an element in a table (that is, the index
+** of its hash value)
+*/
+static Node *mainposition (const Table *t, const TValue *key) {
+ switch (ttype(key)) {
+ case LUA_TNUMINT:
+ return hashint(t, ivalue(key));
+ case LUA_TNUMFLT:
+ return hashmod(t, l_hashfloat(fltvalue(key)));
+ case LUA_TSHRSTR:
+ return hashstr(t, tsvalue(key));
+ case LUA_TLNGSTR:
+ return hashpow2(t, luaS_hashlongstr(tsvalue(key)));
+ case LUA_TBOOLEAN:
+ return hashboolean(t, bvalue(key));
+ case LUA_TLIGHTUSERDATA:
+ return hashpointer(t, pvalue(key));
+ case LUA_TLCF:
+ return hashpointer(t, fvalue(key));
+ default:
+ lua_assert(!ttisdeadkey(key));
+ return hashpointer(t, gcvalue(key));
+ }
+}
+
+
+/*
+** returns the index for 'key' if 'key' is an appropriate key to live in
+** the array part of the table, 0 otherwise.
+*/
+static unsigned int arrayindex (const TValue *key) {
+ if (ttisinteger(key)) {
+ lua_Integer k = ivalue(key);
+ if (0 < k && (lua_Unsigned)k <= MAXASIZE)
+ return cast(unsigned int, k); /* 'key' is an appropriate array index */
+ }
+ return 0; /* 'key' did not match some condition */
+}
+
+
+/*
+** returns the index of a 'key' for table traversals. First goes all
+** elements in the array part, then elements in the hash part. The
+** beginning of a traversal is signaled by 0.
+*/
+static unsigned int findindex (lua_State *L, Table *t, StkId key) {
+ unsigned int i;
+ if (ttisnil(key)) return 0; /* first iteration */
+ i = arrayindex(key);
+ if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */
+ return i; /* yes; that's the index */
+ else {
+ int nx;
+ Node *n = mainposition(t, key);
+ for (;;) { /* check whether 'key' is somewhere in the chain */
+ /* key may be dead already, but it is ok to use it in 'next' */
+ if (luaV_rawequalobj(gkey(n), key) ||
+ (ttisdeadkey(gkey(n)) && iscollectable(key) &&
+ deadvalue(gkey(n)) == gcvalue(key))) {
+ i = cast_int(n - gnode(t, 0)); /* key index in hash table */
+ /* hash elements are numbered after array ones */
+ return (i + 1) + t->sizearray;
+ }
+ nx = gnext(n);
+ if (nx == 0)
+ luaG_runerror(L, "invalid key to 'next'"); /* key not found */
+ else n += nx;
+ }
+ }
+}
+
+
+int luaH_next (lua_State *L, Table *t, StkId key) {
+ unsigned int i = findindex(L, t, key); /* find original element */
+ for (; i < t->sizearray; i++) { /* try first array part */
+ if (!ttisnil(&t->array[i])) { /* a non-nil value? */
+ setivalue(key, i + 1);
+ setobj2s(L, key+1, &t->array[i]);
+ return 1;
+ }
+ }
+ for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */
+ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */
+ setobj2s(L, key, gkey(gnode(t, i)));
+ setobj2s(L, key+1, gval(gnode(t, i)));
+ return 1;
+ }
+ }
+ return 0; /* no more elements */
+}
+
+
+/*
+** {=============================================================
+** Rehash
+** ==============================================================
+*/
+
+/*
+** Compute the optimal size for the array part of table 't'. 'nums' is a
+** "count array" where 'nums[i]' is the number of integers in the table
+** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of
+** integer keys in the table and leaves with the number of keys that
+** will go to the array part; return the optimal size.
+*/
+static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
+ int i;
+ unsigned int twotoi; /* 2^i (candidate for optimal size) */
+ unsigned int a = 0; /* number of elements smaller than 2^i */
+ unsigned int na = 0; /* number of elements to go to array part */
+ unsigned int optimal = 0; /* optimal size for array part */
+ /* loop while keys can fill more than half of total size */
+ for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) {
+ if (nums[i] > 0) {
+ a += nums[i];
+ if (a > twotoi/2) { /* more than half elements present? */
+ optimal = twotoi; /* optimal size (till now) */
+ na = a; /* all elements up to 'optimal' will go to array part */
+ }
+ }
+ }
+ lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal);
+ *pna = na;
+ return optimal;
+}
+
+
+static int countint (const TValue *key, unsigned int *nums) {
+ unsigned int k = arrayindex(key);
+ if (k != 0) { /* is 'key' an appropriate array index? */
+ nums[luaO_ceillog2(k)]++; /* count as such */
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+/*
+** Count keys in array part of table 't': Fill 'nums[i]' with
+** number of keys that will go into corresponding slice and return
+** total number of non-nil keys.
+*/
+static unsigned int numusearray (const Table *t, unsigned int *nums) {
+ int lg;
+ unsigned int ttlg; /* 2^lg */
+ unsigned int ause = 0; /* summation of 'nums' */
+ unsigned int i = 1; /* count to traverse all array keys */
+ /* traverse each slice */
+ for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) {
+ unsigned int lc = 0; /* counter */
+ unsigned int lim = ttlg;
+ if (lim > t->sizearray) {
+ lim = t->sizearray; /* adjust upper limit */
+ if (i > lim)
+ break; /* no more elements to count */
+ }
+ /* count elements in range (2^(lg - 1), 2^lg] */
+ for (; i <= lim; i++) {
+ if (!ttisnil(&t->array[i-1]))
+ lc++;
+ }
+ nums[lg] += lc;
+ ause += lc;
+ }
+ return ause;
+}
+
+
+static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
+ int totaluse = 0; /* total number of elements */
+ int ause = 0; /* elements added to 'nums' (can go to array part) */
+ int i = sizenode(t);
+ while (i--) {
+ Node *n = &t->node[i];
+ if (!ttisnil(gval(n))) {
+ ause += countint(gkey(n), nums);
+ totaluse++;
+ }
+ }
+ *pna += ause;
+ return totaluse;
+}
+
+
+static void setarrayvector (lua_State *L, Table *t, unsigned int size) {
+ unsigned int i;
+ luaM_reallocvector(L, t->array, t->sizearray, size, TValue);
+ for (i=t->sizearray; i<size; i++)
+ setnilvalue(&t->array[i]);
+ t->sizearray = size;
+}
+
+
+static void setnodevector (lua_State *L, Table *t, unsigned int size) {
+ int lsize;
+ if (size == 0) { /* no elements to hash part? */
+ t->node = cast(Node *, dummynode); /* use common 'dummynode' */
+ lsize = 0;
+ }
+ else {
+ int i;
+ lsize = luaO_ceillog2(size);
+ if (lsize > MAXHBITS)
+ luaG_runerror(L, "table overflow");
+ size = twoto(lsize);
+ t->node = luaM_newvector(L, size, Node);
+ for (i = 0; i < (int)size; i++) {
+ Node *n = gnode(t, i);
+ gnext(n) = 0;
+ setnilvalue(wgkey(n));
+ setnilvalue(gval(n));
+ }
+ }
+ t->lsizenode = cast_byte(lsize);
+ t->lastfree = gnode(t, size); /* all positions are free */
+}
+
+
+void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
+ unsigned int nhsize) {
+ unsigned int i;
+ int j;
+ unsigned int oldasize = t->sizearray;
+ int oldhsize = t->lsizenode;
+ Node *nold = t->node; /* save old hash ... */
+ if (nasize > oldasize) /* array part must grow? */
+ setarrayvector(L, t, nasize);
+ /* create new hash part with appropriate size */
+ setnodevector(L, t, nhsize);
+ if (nasize < oldasize) { /* array part must shrink? */
+ t->sizearray = nasize;
+ /* re-insert elements from vanishing slice */
+ for (i=nasize; i<oldasize; i++) {
+ if (!ttisnil(&t->array[i]))
+ luaH_setint(L, t, i + 1, &t->array[i]);
+ }
+ /* shrink array */
+ luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
+ }
+ /* re-insert elements from hash part */
+ for (j = twoto(oldhsize) - 1; j >= 0; j--) {
+ Node *old = nold + j;
+ if (!ttisnil(gval(old))) {
+ /* doesn't need barrier/invalidate cache, as entry was
+ already present in the table */
+ setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
+ }
+ }
+ if (!isdummy(nold))
+ luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old hash */
+}
+
+
+void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
+ int nsize = isdummy(t->node) ? 0 : sizenode(t);
+ luaH_resize(L, t, nasize, nsize);
+}
+
+/*
+** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i
+*/
+static void rehash (lua_State *L, Table *t, const TValue *ek) {
+ unsigned int asize; /* optimal size for array part */
+ unsigned int na; /* number of keys in the array part */
+ unsigned int nums[MAXABITS + 1];
+ int i;
+ int totaluse;
+ for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */
+ na = numusearray(t, nums); /* count keys in array part */
+ totaluse = na; /* all those keys are integer keys */
+ totaluse += numusehash(t, nums, &na); /* count keys in hash part */
+ /* count extra key */
+ na += countint(ek, nums);
+ totaluse++;
+ /* compute new size for array part */
+ asize = computesizes(nums, &na);
+ /* resize the table to new computed sizes */
+ luaH_resize(L, t, asize, totaluse - na);
+}
+
+
+
+/*
+** }=============================================================
+*/
+
+
+Table *luaH_new (lua_State *L) {
+ GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table));
+ Table *t = gco2t(o);
+ t->metatable = NULL;
+ t->flags = cast_byte(~0);
+ t->array = NULL;
+ t->sizearray = 0;
+ setnodevector(L, t, 0);
+ return t;
+}
+
+
+void luaH_free (lua_State *L, Table *t) {
+ if (!isdummy(t->node))
+ luaM_freearray(L, t->node, cast(size_t, sizenode(t)));
+ luaM_freearray(L, t->array, t->sizearray);
+ luaM_free(L, t);
+}
+
+
+static Node *getfreepos (Table *t) {
+ while (t->lastfree > t->node) {
+ t->lastfree--;
+ if (ttisnil(gkey(t->lastfree)))
+ return t->lastfree;
+ }
+ return NULL; /* could not find a free place */
+}
+
+
+
+/*
+** inserts a new key into a hash table; first, check whether key's main
+** position is free. If not, check whether colliding node is in its main
+** position or not: if it is not, move colliding node to an empty place and
+** put new key in its main position; otherwise (colliding node is in its main
+** position), new key goes to an empty position.
+*/
+TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
+ Node *mp;
+ TValue aux;
+ if (ttisnil(key)) luaG_runerror(L, "table index is nil");
+ else if (ttisfloat(key)) {
+ lua_Integer k;
+ if (luaV_tointeger(key, &k, 0)) { /* index is int? */
+ setivalue(&aux, k);
+ key = &aux; /* insert it as an integer */
+ }
+ else if (luai_numisnan(fltvalue(key)))
+ luaG_runerror(L, "table index is NaN");
+ }
+ mp = mainposition(t, key);
+ if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */
+ Node *othern;
+ Node *f = getfreepos(t); /* get a free place */
+ if (f == NULL) { /* cannot find a free place? */
+ rehash(L, t, key); /* grow table */
+ /* whatever called 'newkey' takes care of TM cache */
+ return luaH_set(L, t, key); /* insert key into grown table */
+ }
+ lua_assert(!isdummy(f));
+ othern = mainposition(t, gkey(mp));
+ if (othern != mp) { /* is colliding node out of its main position? */
+ /* yes; move colliding node into free position */
+ while (othern + gnext(othern) != mp) /* find previous */
+ othern += gnext(othern);
+ gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */
+ *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */
+ if (gnext(mp) != 0) {
+ gnext(f) += cast_int(mp - f); /* correct 'next' */
+ gnext(mp) = 0; /* now 'mp' is free */
+ }
+ setnilvalue(gval(mp));
+ }
+ else { /* colliding node is in its own main position */
+ /* new node will go into free position */
+ if (gnext(mp) != 0)
+ gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */
+ else lua_assert(gnext(f) == 0);
+ gnext(mp) = cast_int(f - mp);
+ mp = f;
+ }
+ }
+ setnodekey(L, &mp->i_key, key);
+ luaC_barrierback(L, t, key);
+ lua_assert(ttisnil(gval(mp)));
+ return gval(mp);
+}
+
+
+/*
+** search function for integers
+*/
+const TValue *luaH_getint (Table *t, lua_Integer key) {
+ /* (1 <= key && key <= t->sizearray) */
+ if (l_castS2U(key) - 1 < t->sizearray)
+ return &t->array[key - 1];
+ else {
+ Node *n = hashint(t, key);
+ for (;;) { /* check whether 'key' is somewhere in the chain */
+ if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key)
+ return gval(n); /* that's it */
+ else {
+ int nx = gnext(n);
+ if (nx == 0) break;
+ n += nx;
+ }
+ }
+ return luaO_nilobject;
+ }
+}
+
+
+/*
+** search function for short strings
+*/
+const TValue *luaH_getshortstr (Table *t, TString *key) {
+ Node *n = hashstr(t, key);
+ lua_assert(key->tt == LUA_TSHRSTR);
+ for (;;) { /* check whether 'key' is somewhere in the chain */
+ const TValue *k = gkey(n);
+ if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))
+ return gval(n); /* that's it */
+ else {
+ int nx = gnext(n);
+ if (nx == 0)
+ return luaO_nilobject; /* not found */
+ n += nx;
+ }
+ }
+}
+
+
+/*
+** "Generic" get version. (Not that generic: not valid for integers,
+** which may be in array part, nor for floats with integral values.)
+*/
+static const TValue *getgeneric (Table *t, const TValue *key) {
+ Node *n = mainposition(t, key);
+ for (;;) { /* check whether 'key' is somewhere in the chain */
+ if (luaV_rawequalobj(gkey(n), key))
+ return gval(n); /* that's it */
+ else {
+ int nx = gnext(n);
+ if (nx == 0)
+ return luaO_nilobject; /* not found */
+ n += nx;
+ }
+ }
+}
+
+
+const TValue *luaH_getstr (Table *t, TString *key) {
+ if (key->tt == LUA_TSHRSTR)
+ return luaH_getshortstr(t, key);
+ else { /* for long strings, use generic case */
+ TValue ko;
+ setsvalue(cast(lua_State *, NULL), &ko, key);
+ return getgeneric(t, &ko);
+ }
+}
+
+
+/*
+** main search function
+*/
+const TValue *luaH_get (Table *t, const TValue *key) {
+ switch (ttype(key)) {
+ case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key));
+ case LUA_TNUMINT: return luaH_getint(t, ivalue(key));
+ case LUA_TNIL: return luaO_nilobject;
+ case LUA_TNUMFLT: {
+ lua_Integer k;
+ if (luaV_tointeger(key, &k, 0)) /* index is int? */
+ return luaH_getint(t, k); /* use specialized version */
+ /* else... */
+ } /* FALLTHROUGH */
+ default:
+ return getgeneric(t, key);
+ }
+}
+
+
+/*
+** beware: when using this function you probably need to check a GC
+** barrier and invalidate the TM cache.
+*/
+TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
+ const TValue *p = luaH_get(t, key);
+ if (p != luaO_nilobject)
+ return cast(TValue *, p);
+ else return luaH_newkey(L, t, key);
+}
+
+
+void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
+ const TValue *p = luaH_getint(t, key);
+ TValue *cell;
+ if (p != luaO_nilobject)
+ cell = cast(TValue *, p);
+ else {
+ TValue k;
+ setivalue(&k, key);
+ cell = luaH_newkey(L, t, &k);
+ }
+ setobj2t(L, cell, value);
+}
+
+
+static int unbound_search (Table *t, unsigned int j) {
+ unsigned int i = j; /* i is zero or a present index */
+ j++;
+ /* find 'i' and 'j' such that i is present and j is not */
+ while (!ttisnil(luaH_getint(t, j))) {
+ i = j;
+ if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */
+ /* table was built with bad purposes: resort to linear search */
+ i = 1;
+ while (!ttisnil(luaH_getint(t, i))) i++;
+ return i - 1;
+ }
+ j *= 2;
+ }
+ /* now do a binary search between them */
+ while (j - i > 1) {
+ unsigned int m = (i+j)/2;
+ if (ttisnil(luaH_getint(t, m))) j = m;
+ else i = m;
+ }
+ return i;
+}
+
+
+/*
+** Try to find a boundary in table 't'. A 'boundary' is an integer index
+** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
+*/
+int luaH_getn (Table *t) {
+ unsigned int j = t->sizearray;
+ if (j > 0 && ttisnil(&t->array[j - 1])) {
+ /* there is a boundary in the array part: (binary) search for it */
+ unsigned int i = 0;
+ while (j - i > 1) {
+ unsigned int m = (i+j)/2;
+ if (ttisnil(&t->array[m - 1])) j = m;
+ else i = m;
+ }
+ return i;
+ }
+ /* else must find a boundary in hash part */
+ else if (isdummy(t->node)) /* hash part is empty? */
+ return j; /* that is easy... */
+ else return unbound_search(t, j);
+}
+
+
+
+#if defined(LUA_DEBUG)
+
+Node *luaH_mainposition (const Table *t, const TValue *key) {
+ return mainposition(t, key);
+}
+
+int luaH_isdummy (Node *n) { return isdummy(n); }
+
+#endif
diff --git a/external/lua-5.3.3/src/ltable.h b/external/lua-5.3.3/src/ltable.h
new file mode 100644
index 0000000..213cc13
--- /dev/null
+++ b/external/lua-5.3.3/src/ltable.h
@@ -0,0 +1,58 @@
+/*
+** $Id: ltable.h,v 2.21 2015/11/03 15:47:30 roberto Exp $
+** Lua tables (hash)
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ltable_h
+#define ltable_h
+
+#include "lobject.h"
+
+
+#define gnode(t,i) (&(t)->node[i])
+#define gval(n) (&(n)->i_val)
+#define gnext(n) ((n)->i_key.nk.next)
+
+
+/* 'const' to avoid wrong writings that can mess up field 'next' */
+#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk))
+
+/*
+** writable version of 'gkey'; allows updates to individual fields,
+** but not to the whole (which has incompatible type)
+*/
+#define wgkey(n) (&(n)->i_key.nk)
+
+#define invalidateTMcache(t) ((t)->flags = 0)
+
+
+/* returns the key, given the value of a table entry */
+#define keyfromval(v) \
+ (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
+
+
+LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
+LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
+ TValue *value);
+LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
+LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
+LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
+LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);
+LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key);
+LUAI_FUNC Table *luaH_new (lua_State *L);
+LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
+ unsigned int nhsize);
+LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize);
+LUAI_FUNC void luaH_free (lua_State *L, Table *t);
+LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
+LUAI_FUNC int luaH_getn (Table *t);
+
+
+#if defined(LUA_DEBUG)
+LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
+LUAI_FUNC int luaH_isdummy (Node *n);
+#endif
+
+
+#endif
diff --git a/external/lua-5.3.3/src/ltablib.c b/external/lua-5.3.3/src/ltablib.c
new file mode 100644
index 0000000..98b2f87
--- /dev/null
+++ b/external/lua-5.3.3/src/ltablib.c
@@ -0,0 +1,450 @@
+/*
+** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $
+** Library for Table Manipulation
+** See Copyright Notice in lua.h
+*/
+
+#define ltablib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include <limits.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/*
+** Operations that an object must define to mimic a table
+** (some functions only need some of them)
+*/
+#define TAB_R 1 /* read */
+#define TAB_W 2 /* write */
+#define TAB_L 4 /* length */
+#define TAB_RW (TAB_R | TAB_W) /* read/write */
+
+
+#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n))
+
+
+static int checkfield (lua_State *L, const char *key, int n) {
+ lua_pushstring(L, key);
+ return (lua_rawget(L, -n) != LUA_TNIL);
+}
+
+
+/*
+** Check that 'arg' either is a table or can behave like one (that is,
+** has a metatable with the required metamethods)
+*/
+static void checktab (lua_State *L, int arg, int what) {
+ if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */
+ int n = 1; /* number of elements to pop */
+ if (lua_getmetatable(L, arg) && /* must have metatable */
+ (!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
+ (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
+ (!(what & TAB_L) || checkfield(L, "__len", ++n))) {
+ lua_pop(L, n); /* pop metatable and tested metamethods */
+ }
+ else
+ luaL_checktype(L, arg, LUA_TTABLE); /* force an error */
+ }
+}
+
+
+#if defined(LUA_COMPAT_MAXN)
+static int maxn (lua_State *L) {
+ lua_Number max = 0;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_pushnil(L); /* first key */
+ while (lua_next(L, 1)) {
+ lua_pop(L, 1); /* remove value */
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ lua_Number v = lua_tonumber(L, -1);
+ if (v > max) max = v;
+ }
+ }
+ lua_pushnumber(L, max);
+ return 1;
+}
+#endif
+
+
+static int tinsert (lua_State *L) {
+ lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
+ lua_Integer pos; /* where to insert new element */
+ switch (lua_gettop(L)) {
+ case 2: { /* called with only 2 arguments */
+ pos = e; /* insert new element at the end */
+ break;
+ }
+ case 3: {
+ lua_Integer i;
+ pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */
+ luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
+ for (i = e; i > pos; i--) { /* move up elements */
+ lua_geti(L, 1, i - 1);
+ lua_seti(L, 1, i); /* t[i] = t[i - 1] */
+ }
+ break;
+ }
+ default: {
+ return luaL_error(L, "wrong number of arguments to 'insert'");
+ }
+ }
+ lua_seti(L, 1, pos); /* t[pos] = v */
+ return 0;
+}
+
+
+static int tremove (lua_State *L) {
+ lua_Integer size = aux_getn(L, 1, TAB_RW);
+ lua_Integer pos = luaL_optinteger(L, 2, size);
+ if (pos != size) /* validate 'pos' if given */
+ luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
+ lua_geti(L, 1, pos); /* result = t[pos] */
+ for ( ; pos < size; pos++) {
+ lua_geti(L, 1, pos + 1);
+ lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */
+ }
+ lua_pushnil(L);
+ lua_seti(L, 1, pos); /* t[pos] = nil */
+ return 1;
+}
+
+
+/*
+** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever
+** possible, copy in increasing order, which is better for rehashing.
+** "possible" means destination after original range, or smaller
+** than origin, or copying to another table.
+*/
+static int tmove (lua_State *L) {
+ lua_Integer f = luaL_checkinteger(L, 2);
+ lua_Integer e = luaL_checkinteger(L, 3);
+ lua_Integer t = luaL_checkinteger(L, 4);
+ int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */
+ checktab(L, 1, TAB_R);
+ checktab(L, tt, TAB_W);
+ if (e >= f) { /* otherwise, nothing to move */
+ lua_Integer n, i;
+ luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3,
+ "too many elements to move");
+ n = e - f + 1; /* number of elements to move */
+ luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,
+ "destination wrap around");
+ if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {
+ for (i = 0; i < n; i++) {
+ lua_geti(L, 1, f + i);
+ lua_seti(L, tt, t + i);
+ }
+ }
+ else {
+ for (i = n - 1; i >= 0; i--) {
+ lua_geti(L, 1, f + i);
+ lua_seti(L, tt, t + i);
+ }
+ }
+ }
+ lua_pushvalue(L, tt); /* return destination table */
+ return 1;
+}
+
+
+static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
+ lua_geti(L, 1, i);
+ if (!lua_isstring(L, -1))
+ luaL_error(L, "invalid value (%s) at index %d in table for 'concat'",
+ luaL_typename(L, -1), i);
+ luaL_addvalue(b);
+}
+
+
+static int tconcat (lua_State *L) {
+ luaL_Buffer b;
+ lua_Integer last = aux_getn(L, 1, TAB_R);
+ size_t lsep;
+ const char *sep = luaL_optlstring(L, 2, "", &lsep);
+ lua_Integer i = luaL_optinteger(L, 3, 1);
+ last = luaL_optinteger(L, 4, last);
+ luaL_buffinit(L, &b);
+ for (; i < last; i++) {
+ addfield(L, &b, i);
+ luaL_addlstring(&b, sep, lsep);
+ }
+ if (i == last) /* add last value (if interval was not empty) */
+ addfield(L, &b, i);
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+/*
+** {======================================================
+** Pack/unpack
+** =======================================================
+*/
+
+static int pack (lua_State *L) {
+ int i;
+ int n = lua_gettop(L); /* number of elements to pack */
+ lua_createtable(L, n, 1); /* create result table */
+ lua_insert(L, 1); /* put it at index 1 */
+ for (i = n; i >= 1; i--) /* assign elements */
+ lua_seti(L, 1, i);
+ lua_pushinteger(L, n);
+ lua_setfield(L, 1, "n"); /* t.n = number of elements */
+ return 1; /* return table */
+}
+
+
+static int unpack (lua_State *L) {
+ lua_Unsigned n;
+ lua_Integer i = luaL_optinteger(L, 2, 1);
+ lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
+ if (i > e) return 0; /* empty range */
+ n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
+ if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n)))
+ return luaL_error(L, "too many results to unpack");
+ for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */
+ lua_geti(L, 1, i);
+ }
+ lua_geti(L, 1, e); /* push last element */
+ return (int)n;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** Quicksort
+** (based on 'Algorithms in MODULA-3', Robert Sedgewick;
+** Addison-Wesley, 1993.)
+** =======================================================
+*/
+
+
+/* type for array indices */
+typedef unsigned int IdxT;
+
+
+/*
+** Produce a "random" 'unsigned int' to randomize pivot choice. This
+** macro is used only when 'sort' detects a big imbalance in the result
+** of a partition. (If you don't want/need this "randomness", ~0 is a
+** good choice.)
+*/
+#if !defined(l_randomizePivot) /* { */
+
+#include <time.h>
+
+/* size of 'e' measured in number of 'unsigned int's */
+#define sof(e) (sizeof(e) / sizeof(unsigned int))
+
+/*
+** Use 'time' and 'clock' as sources of "randomness". Because we don't
+** know the types 'clock_t' and 'time_t', we cannot cast them to
+** anything without risking overflows. A safe way to use their values
+** is to copy them to an array of a known type and use the array values.
+*/
+static unsigned int l_randomizePivot (void) {
+ clock_t c = clock();
+ time_t t = time(NULL);
+ unsigned int buff[sof(c) + sof(t)];
+ unsigned int i, rnd = 0;
+ memcpy(buff, &c, sof(c) * sizeof(unsigned int));
+ memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int));
+ for (i = 0; i < sof(buff); i++)
+ rnd += buff[i];
+ return rnd;
+}
+
+#endif /* } */
+
+
+/* arrays larger than 'RANLIMIT' may use randomized pivots */
+#define RANLIMIT 100u
+
+
+static void set2 (lua_State *L, IdxT i, IdxT j) {
+ lua_seti(L, 1, i);
+ lua_seti(L, 1, j);
+}
+
+
+/*
+** Return true iff value at stack index 'a' is less than the value at
+** index 'b' (according to the order of the sort).
+*/
+static int sort_comp (lua_State *L, int a, int b) {
+ if (lua_isnil(L, 2)) /* no function? */
+ return lua_compare(L, a, b, LUA_OPLT); /* a < b */
+ else { /* function */
+ int res;
+ lua_pushvalue(L, 2); /* push function */
+ lua_pushvalue(L, a-1); /* -1 to compensate function */
+ lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */
+ lua_call(L, 2, 1); /* call function */
+ res = lua_toboolean(L, -1); /* get result */
+ lua_pop(L, 1); /* pop result */
+ return res;
+ }
+}
+
+
+/*
+** Does the partition: Pivot P is at the top of the stack.
+** precondition: a[lo] <= P == a[up-1] <= a[up],
+** so it only needs to do the partition from lo + 1 to up - 2.
+** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]
+** returns 'i'.
+*/
+static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
+ IdxT i = lo; /* will be incremented before first use */
+ IdxT j = up - 1; /* will be decremented before first use */
+ /* loop invariant: a[lo .. i] <= P <= a[j .. up] */
+ for (;;) {
+ /* next loop: repeat ++i while a[i] < P */
+ while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
+ if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */
+ luaL_error(L, "invalid order function for sorting");
+ lua_pop(L, 1); /* remove a[i] */
+ }
+ /* after the loop, a[i] >= P and a[lo .. i - 1] < P */
+ /* next loop: repeat --j while P < a[j] */
+ while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
+ if (j < i) /* j < i but a[j] > P ?? */
+ luaL_error(L, "invalid order function for sorting");
+ lua_pop(L, 1); /* remove a[j] */
+ }
+ /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */
+ if (j < i) { /* no elements out of place? */
+ /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */
+ lua_pop(L, 1); /* pop a[j] */
+ /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */
+ set2(L, up - 1, i);
+ return i;
+ }
+ /* otherwise, swap a[i] - a[j] to restore invariant and repeat */
+ set2(L, i, j);
+ }
+}
+
+
+/*
+** Choose an element in the middle (2nd-3th quarters) of [lo,up]
+** "randomized" by 'rnd'
+*/
+static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
+ IdxT r4 = (up - lo) / 4; /* range/4 */
+ IdxT p = rnd % (r4 * 2) + (lo + r4);
+ lua_assert(lo + r4 <= p && p <= up - r4);
+ return p;
+}
+
+
+/*
+** QuickSort algorithm (recursive function)
+*/
+static void auxsort (lua_State *L, IdxT lo, IdxT up,
+ unsigned int rnd) {
+ while (lo < up) { /* loop for tail recursion */
+ IdxT p; /* Pivot index */
+ IdxT n; /* to be used later */
+ /* sort elements 'lo', 'p', and 'up' */
+ lua_geti(L, 1, lo);
+ lua_geti(L, 1, up);
+ if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */
+ set2(L, lo, up); /* swap a[lo] - a[up] */
+ else
+ lua_pop(L, 2); /* remove both values */
+ if (up - lo == 1) /* only 2 elements? */
+ return; /* already sorted */
+ if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */
+ p = (lo + up)/2; /* middle element is a good pivot */
+ else /* for larger intervals, it is worth a random pivot */
+ p = choosePivot(lo, up, rnd);
+ lua_geti(L, 1, p);
+ lua_geti(L, 1, lo);
+ if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */
+ set2(L, p, lo); /* swap a[p] - a[lo] */
+ else {
+ lua_pop(L, 1); /* remove a[lo] */
+ lua_geti(L, 1, up);
+ if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */
+ set2(L, p, up); /* swap a[up] - a[p] */
+ else
+ lua_pop(L, 2);
+ }
+ if (up - lo == 2) /* only 3 elements? */
+ return; /* already sorted */
+ lua_geti(L, 1, p); /* get middle element (Pivot) */
+ lua_pushvalue(L, -1); /* push Pivot */
+ lua_geti(L, 1, up - 1); /* push a[up - 1] */
+ set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */
+ p = partition(L, lo, up);
+ /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
+ if (p - lo < up - p) { /* lower interval is smaller? */
+ auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */
+ n = p - lo; /* size of smaller interval */
+ lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */
+ }
+ else {
+ auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */
+ n = up - p; /* size of smaller interval */
+ up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
+ }
+ if ((up - lo) / 128 > n) /* partition too imbalanced? */
+ rnd = l_randomizePivot(); /* try a new randomization */
+ } /* tail call auxsort(L, lo, up, rnd) */
+}
+
+
+static int sort (lua_State *L) {
+ lua_Integer n = aux_getn(L, 1, TAB_RW);
+ if (n > 1) { /* non-trivial interval? */
+ luaL_argcheck(L, n < INT_MAX, 1, "array too big");
+ if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
+ luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */
+ lua_settop(L, 2); /* make sure there are two arguments */
+ auxsort(L, 1, (IdxT)n, 0);
+ }
+ return 0;
+}
+
+/* }====================================================== */
+
+
+static const luaL_Reg tab_funcs[] = {
+ {"concat", tconcat},
+#if defined(LUA_COMPAT_MAXN)
+ {"maxn", maxn},
+#endif
+ {"insert", tinsert},
+ {"pack", pack},
+ {"unpack", unpack},
+ {"remove", tremove},
+ {"move", tmove},
+ {"sort", sort},
+ {NULL, NULL}
+};
+
+
+LUAMOD_API int luaopen_table (lua_State *L) {
+ luaL_newlib(L, tab_funcs);
+#if defined(LUA_COMPAT_UNPACK)
+ /* _G.unpack = table.unpack */
+ lua_getfield(L, -1, "unpack");
+ lua_setglobal(L, "unpack");
+#endif
+ return 1;
+}
+
diff --git a/external/lua-5.3.3/src/ltm.c b/external/lua-5.3.3/src/ltm.c
new file mode 100644
index 0000000..4650cc2
--- /dev/null
+++ b/external/lua-5.3.3/src/ltm.c
@@ -0,0 +1,165 @@
+/*
+** $Id: ltm.c,v 2.37 2016/02/26 19:20:15 roberto Exp $
+** Tag methods
+** See Copyright Notice in lua.h
+*/
+
+#define ltm_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <string.h>
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lvm.h"
+
+
+static const char udatatypename[] = "userdata";
+
+LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = {
+ "no value",
+ "nil", "boolean", udatatypename, "number",
+ "string", "table", "function", udatatypename, "thread",
+ "proto" /* this last case is used for tests only */
+};
+
+
+void luaT_init (lua_State *L) {
+ static const char *const luaT_eventname[] = { /* ORDER TM */
+ "__index", "__newindex",
+ "__gc", "__mode", "__len", "__eq",
+ "__add", "__sub", "__mul", "__mod", "__pow",
+ "__div", "__idiv",
+ "__band", "__bor", "__bxor", "__shl", "__shr",
+ "__unm", "__bnot", "__lt", "__le",
+ "__concat", "__call"
+ };
+ int i;
+ for (i=0; i<TM_N; i++) {
+ G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
+ luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */
+ }
+}
+
+
+/*
+** function to be used with macro "fasttm": optimized for absence of
+** tag methods
+*/
+const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
+ const TValue *tm = luaH_getshortstr(events, ename);
+ lua_assert(event <= TM_EQ);
+ if (ttisnil(tm)) { /* no tag method? */
+ events->flags |= cast_byte(1u<<event); /* cache this fact */
+ return NULL;
+ }
+ else return tm;
+}
+
+
+const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
+ Table *mt;
+ switch (ttnov(o)) {
+ case LUA_TTABLE:
+ mt = hvalue(o)->metatable;
+ break;
+ case LUA_TUSERDATA:
+ mt = uvalue(o)->metatable;
+ break;
+ default:
+ mt = G(L)->mt[ttnov(o)];
+ }
+ return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject);
+}
+
+
+/*
+** Return the name of the type of an object. For tables and userdata
+** with metatable, use their '__name' metafield, if present.
+*/
+const char *luaT_objtypename (lua_State *L, const TValue *o) {
+ Table *mt;
+ if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
+ (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
+ const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name"));
+ if (ttisstring(name)) /* is '__name' a string? */
+ return getstr(tsvalue(name)); /* use it as type name */
+ }
+ return ttypename(ttnov(o)); /* else use standard type name */
+}
+
+
+void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
+ const TValue *p2, TValue *p3, int hasres) {
+ ptrdiff_t result = savestack(L, p3);
+ StkId func = L->top;
+ setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
+ setobj2s(L, func + 1, p1); /* 1st argument */
+ setobj2s(L, func + 2, p2); /* 2nd argument */
+ L->top += 3;
+ if (!hasres) /* no result? 'p3' is third argument */
+ setobj2s(L, L->top++, p3); /* 3rd argument */
+ /* metamethod may yield only when called from Lua code */
+ if (isLua(L->ci))
+ luaD_call(L, func, hasres);
+ else
+ luaD_callnoyield(L, func, hasres);
+ if (hasres) { /* if has result, move it to its place */
+ p3 = restorestack(L, result);
+ setobjs2s(L, p3, --L->top);
+ }
+}
+
+
+int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2,
+ StkId res, TMS event) {
+ const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */
+ if (ttisnil(tm))
+ tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
+ if (ttisnil(tm)) return 0;
+ luaT_callTM(L, tm, p1, p2, res, 1);
+ return 1;
+}
+
+
+void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
+ StkId res, TMS event) {
+ if (!luaT_callbinTM(L, p1, p2, res, event)) {
+ switch (event) {
+ case TM_CONCAT:
+ luaG_concaterror(L, p1, p2);
+ /* call never returns, but to avoid warnings: *//* FALLTHROUGH */
+ case TM_BAND: case TM_BOR: case TM_BXOR:
+ case TM_SHL: case TM_SHR: case TM_BNOT: {
+ lua_Number dummy;
+ if (tonumber(p1, &dummy) && tonumber(p2, &dummy))
+ luaG_tointerror(L, p1, p2);
+ else
+ luaG_opinterror(L, p1, p2, "perform bitwise operation on");
+ }
+ /* calls never return, but to avoid warnings: *//* FALLTHROUGH */
+ default:
+ luaG_opinterror(L, p1, p2, "perform arithmetic on");
+ }
+ }
+}
+
+
+int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
+ TMS event) {
+ if (!luaT_callbinTM(L, p1, p2, L->top, event))
+ return -1; /* no metamethod */
+ else
+ return !l_isfalse(L->top);
+}
+
diff --git a/external/lua-5.3.3/src/ltm.h b/external/lua-5.3.3/src/ltm.h
new file mode 100644
index 0000000..63db726
--- /dev/null
+++ b/external/lua-5.3.3/src/ltm.h
@@ -0,0 +1,76 @@
+/*
+** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $
+** Tag methods
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ltm_h
+#define ltm_h
+
+
+#include "lobject.h"
+
+
+/*
+* WARNING: if you change the order of this enumeration,
+* grep "ORDER TM" and "ORDER OP"
+*/
+typedef enum {
+ TM_INDEX,
+ TM_NEWINDEX,
+ TM_GC,
+ TM_MODE,
+ TM_LEN,
+ TM_EQ, /* last tag method with fast access */
+ TM_ADD,
+ TM_SUB,
+ TM_MUL,
+ TM_MOD,
+ TM_POW,
+ TM_DIV,
+ TM_IDIV,
+ TM_BAND,
+ TM_BOR,
+ TM_BXOR,
+ TM_SHL,
+ TM_SHR,
+ TM_UNM,
+ TM_BNOT,
+ TM_LT,
+ TM_LE,
+ TM_CONCAT,
+ TM_CALL,
+ TM_N /* number of elements in the enum */
+} TMS;
+
+
+
+#define gfasttm(g,et,e) ((et) == NULL ? NULL : \
+ ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))
+
+#define fasttm(l,et,e) gfasttm(G(l), et, e)
+
+#define ttypename(x) luaT_typenames_[(x) + 1]
+
+LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
+
+
+LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
+
+LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
+LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
+ TMS event);
+LUAI_FUNC void luaT_init (lua_State *L);
+
+LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
+ const TValue *p2, TValue *p3, int hasres);
+LUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2,
+ StkId res, TMS event);
+LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
+ StkId res, TMS event);
+LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
+ const TValue *p2, TMS event);
+
+
+
+#endif
diff --git a/external/lua-5.3.3/src/lua.c b/external/lua-5.3.3/src/lua.c
new file mode 100644
index 0000000..545d23d
--- /dev/null
+++ b/external/lua-5.3.3/src/lua.c
@@ -0,0 +1,609 @@
+/*
+** $Id: lua.c,v 1.226 2015/08/14 19:11:20 roberto Exp $
+** Lua stand-alone interpreter
+** See Copyright Notice in lua.h
+*/
+
+#define lua_c
+
+#include "lprefix.h"
+
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+#if !defined(LUA_PROMPT)
+#define LUA_PROMPT "> "
+#define LUA_PROMPT2 ">> "
+#endif
+
+#if !defined(LUA_PROGNAME)
+#define LUA_PROGNAME "lua"
+#endif
+
+#if !defined(LUA_MAXINPUT)
+#define LUA_MAXINPUT 512
+#endif
+
+#if !defined(LUA_INIT_VAR)
+#define LUA_INIT_VAR "LUA_INIT"
+#endif
+
+#define LUA_INITVARVERSION \
+ LUA_INIT_VAR "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
+
+
+/*
+** lua_stdin_is_tty detects whether the standard input is a 'tty' (that
+** is, whether we're running lua interactively).
+*/
+#if !defined(lua_stdin_is_tty) /* { */
+
+#if defined(LUA_USE_POSIX) /* { */
+
+#include <unistd.h>
+#define lua_stdin_is_tty() isatty(0)
+
+#elif defined(LUA_USE_WINDOWS) /* }{ */
+
+#include <io.h>
+#define lua_stdin_is_tty() _isatty(_fileno(stdin))
+
+#else /* }{ */
+
+/* ISO C definition */
+#define lua_stdin_is_tty() 1 /* assume stdin is a tty */
+
+#endif /* } */
+
+#endif /* } */
+
+
+/*
+** lua_readline defines how to show a prompt and then read a line from
+** the standard input.
+** lua_saveline defines how to "save" a read line in a "history".
+** lua_freeline defines how to free a line read by lua_readline.
+*/
+#if !defined(lua_readline) /* { */
+
+#if defined(LUA_USE_READLINE) /* { */
+
+#include <readline/readline.h>
+#include <readline/history.h>
+#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
+#define lua_saveline(L,line) ((void)L, add_history(line))
+#define lua_freeline(L,b) ((void)L, free(b))
+
+#else /* }{ */
+
+#define lua_readline(L,b,p) \
+ ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
+ fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */
+#define lua_saveline(L,line) { (void)L; (void)line; }
+#define lua_freeline(L,b) { (void)L; (void)b; }
+
+#endif /* } */
+
+#endif /* } */
+
+
+
+
+static lua_State *globalL = NULL;
+
+static const char *progname = LUA_PROGNAME;
+
+
+/*
+** Hook set by signal function to stop the interpreter.
+*/
+static void lstop (lua_State *L, lua_Debug *ar) {
+ (void)ar; /* unused arg. */
+ lua_sethook(L, NULL, 0, 0); /* reset hook */
+ luaL_error(L, "interrupted!");
+}
+
+
+/*
+** Function to be called at a C signal. Because a C signal cannot
+** just change a Lua state (as there is no proper synchronization),
+** this function only sets a hook that, when called, will stop the
+** interpreter.
+*/
+static void laction (int i) {
+ signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
+ lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
+}
+
+
+static void print_usage (const char *badoption) {
+ lua_writestringerror("%s: ", progname);
+ if (badoption[1] == 'e' || badoption[1] == 'l')
+ lua_writestringerror("'%s' needs argument\n", badoption);
+ else
+ lua_writestringerror("unrecognized option '%s'\n", badoption);
+ lua_writestringerror(
+ "usage: %s [options] [script [args]]\n"
+ "Available options are:\n"
+ " -e stat execute string 'stat'\n"
+ " -i enter interactive mode after executing 'script'\n"
+ " -l name require library 'name'\n"
+ " -v show version information\n"
+ " -E ignore environment variables\n"
+ " -- stop handling options\n"
+ " - stop handling options and execute stdin\n"
+ ,
+ progname);
+}
+
+
+/*
+** Prints an error message, adding the program name in front of it
+** (if present)
+*/
+static void l_message (const char *pname, const char *msg) {
+ if (pname) lua_writestringerror("%s: ", pname);
+ lua_writestringerror("%s\n", msg);
+}
+
+
+/*
+** Check whether 'status' is not OK and, if so, prints the error
+** message on the top of the stack. It assumes that the error object
+** is a string, as it was either generated by Lua or by 'msghandler'.
+*/
+static int report (lua_State *L, int status) {
+ if (status != LUA_OK) {
+ const char *msg = lua_tostring(L, -1);
+ l_message(progname, msg);
+ lua_pop(L, 1); /* remove message */
+ }
+ return status;
+}
+
+
+/*
+** Message handler used to run all chunks
+*/
+static int msghandler (lua_State *L) {
+ const char *msg = lua_tostring(L, 1);
+ if (msg == NULL) { /* is error object not a string? */
+ if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */
+ lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */
+ return 1; /* that is the message */
+ else
+ msg = lua_pushfstring(L, "(error object is a %s value)",
+ luaL_typename(L, 1));
+ }
+ luaL_traceback(L, L, msg, 1); /* append a standard traceback */
+ return 1; /* return the traceback */
+}
+
+
+/*
+** Interface to 'lua_pcall', which sets appropriate message function
+** and C-signal handler. Used to run all chunks.
+*/
+static int docall (lua_State *L, int narg, int nres) {
+ int status;
+ int base = lua_gettop(L) - narg; /* function index */
+ lua_pushcfunction(L, msghandler); /* push message handler */
+ lua_insert(L, base); /* put it under function and args */
+ globalL = L; /* to be available to 'laction' */
+ signal(SIGINT, laction); /* set C-signal handler */
+ status = lua_pcall(L, narg, nres, base);
+ signal(SIGINT, SIG_DFL); /* reset C-signal handler */
+ lua_remove(L, base); /* remove message handler from the stack */
+ return status;
+}
+
+
+static void print_version (void) {
+ lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT));
+ lua_writeline();
+}
+
+
+/*
+** Create the 'arg' table, which stores all arguments from the
+** command line ('argv'). It should be aligned so that, at index 0,
+** it has 'argv[script]', which is the script name. The arguments
+** to the script (everything after 'script') go to positive indices;
+** other arguments (before the script name) go to negative indices.
+** If there is no script name, assume interpreter's name as base.
+*/
+static void createargtable (lua_State *L, char **argv, int argc, int script) {
+ int i, narg;
+ if (script == argc) script = 0; /* no script name? */
+ narg = argc - (script + 1); /* number of positive indices */
+ lua_createtable(L, narg, script + 1);
+ for (i = 0; i < argc; i++) {
+ lua_pushstring(L, argv[i]);
+ lua_rawseti(L, -2, i - script);
+ }
+ lua_setglobal(L, "arg");
+}
+
+
+static int dochunk (lua_State *L, int status) {
+ if (status == LUA_OK) status = docall(L, 0, 0);
+ return report(L, status);
+}
+
+
+static int dofile (lua_State *L, const char *name) {
+ return dochunk(L, luaL_loadfile(L, name));
+}
+
+
+static int dostring (lua_State *L, const char *s, const char *name) {
+ return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name));
+}
+
+
+/*
+** Calls 'require(name)' and stores the result in a global variable
+** with the given name.
+*/
+static int dolibrary (lua_State *L, const char *name) {
+ int status;
+ lua_getglobal(L, "require");
+ lua_pushstring(L, name);
+ status = docall(L, 1, 1); /* call 'require(name)' */
+ if (status == LUA_OK)
+ lua_setglobal(L, name); /* global[name] = require return */
+ return report(L, status);
+}
+
+
+/*
+** Returns the string to be used as a prompt by the interpreter.
+*/
+static const char *get_prompt (lua_State *L, int firstline) {
+ const char *p;
+ lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
+ p = lua_tostring(L, -1);
+ if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
+ return p;
+}
+
+/* mark in error messages for incomplete statements */
+#define EOFMARK "<eof>"
+#define marklen (sizeof(EOFMARK)/sizeof(char) - 1)
+
+
+/*
+** Check whether 'status' signals a syntax error and the error
+** message at the top of the stack ends with the above mark for
+** incomplete statements.
+*/
+static int incomplete (lua_State *L, int status) {
+ if (status == LUA_ERRSYNTAX) {
+ size_t lmsg;
+ const char *msg = lua_tolstring(L, -1, &lmsg);
+ if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) {
+ lua_pop(L, 1);
+ return 1;
+ }
+ }
+ return 0; /* else... */
+}
+
+
+/*
+** Prompt the user, read a line, and push it into the Lua stack.
+*/
+static int pushline (lua_State *L, int firstline) {
+ char buffer[LUA_MAXINPUT];
+ char *b = buffer;
+ size_t l;
+ const char *prmt = get_prompt(L, firstline);
+ int readstatus = lua_readline(L, b, prmt);
+ if (readstatus == 0)
+ return 0; /* no input (prompt will be popped by caller) */
+ lua_pop(L, 1); /* remove prompt */
+ l = strlen(b);
+ if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
+ b[--l] = '\0'; /* remove it */
+ if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */
+ lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */
+ else
+ lua_pushlstring(L, b, l);
+ lua_freeline(L, b);
+ return 1;
+}
+
+
+/*
+** Try to compile line on the stack as 'return <line>;'; on return, stack
+** has either compiled chunk or original line (if compilation failed).
+*/
+static int addreturn (lua_State *L) {
+ const char *line = lua_tostring(L, -1); /* original line */
+ const char *retline = lua_pushfstring(L, "return %s;", line);
+ int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
+ if (status == LUA_OK) {
+ lua_remove(L, -2); /* remove modified line */
+ if (line[0] != '\0') /* non empty? */
+ lua_saveline(L, line); /* keep history */
+ }
+ else
+ lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */
+ return status;
+}
+
+
+/*
+** Read multiple lines until a complete Lua statement
+*/
+static int multiline (lua_State *L) {
+ for (;;) { /* repeat until gets a complete statement */
+ size_t len;
+ const char *line = lua_tolstring(L, 1, &len); /* get what it has */
+ int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
+ if (!incomplete(L, status) || !pushline(L, 0)) {
+ lua_saveline(L, line); /* keep history */
+ return status; /* cannot or should not try to add continuation line */
+ }
+ lua_pushliteral(L, "\n"); /* add newline... */
+ lua_insert(L, -2); /* ...between the two lines */
+ lua_concat(L, 3); /* join them */
+ }
+}
+
+
+/*
+** Read a line and try to load (compile) it first as an expression (by
+** adding "return " in front of it) and second as a statement. Return
+** the final status of load/call with the resulting function (if any)
+** in the top of the stack.
+*/
+static int loadline (lua_State *L) {
+ int status;
+ lua_settop(L, 0);
+ if (!pushline(L, 1))
+ return -1; /* no input */
+ if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
+ status = multiline(L); /* try as command, maybe with continuation lines */
+ lua_remove(L, 1); /* remove line from the stack */
+ lua_assert(lua_gettop(L) == 1);
+ return status;
+}
+
+
+/*
+** Prints (calling the Lua 'print' function) any values on the stack
+*/
+static void l_print (lua_State *L) {
+ int n = lua_gettop(L);
+ if (n > 0) { /* any result to be printed? */
+ luaL_checkstack(L, LUA_MINSTACK, "too many results to print");
+ lua_getglobal(L, "print");
+ lua_insert(L, 1);
+ if (lua_pcall(L, n, 0, 0) != LUA_OK)
+ l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)",
+ lua_tostring(L, -1)));
+ }
+}
+
+
+/*
+** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and
+** print any results.
+*/
+static void doREPL (lua_State *L) {
+ int status;
+ const char *oldprogname = progname;
+ progname = NULL; /* no 'progname' on errors in interactive mode */
+ while ((status = loadline(L)) != -1) {
+ if (status == LUA_OK)
+ status = docall(L, 0, LUA_MULTRET);
+ if (status == LUA_OK) l_print(L);
+ else report(L, status);
+ }
+ lua_settop(L, 0); /* clear stack */
+ lua_writeline();
+ progname = oldprogname;
+}
+
+
+/*
+** Push on the stack the contents of table 'arg' from 1 to #arg
+*/
+static int pushargs (lua_State *L) {
+ int i, n;
+ if (lua_getglobal(L, "arg") != LUA_TTABLE)
+ luaL_error(L, "'arg' is not a table");
+ n = (int)luaL_len(L, -1);
+ luaL_checkstack(L, n + 3, "too many arguments to script");
+ for (i = 1; i <= n; i++)
+ lua_rawgeti(L, -i, i);
+ lua_remove(L, -i); /* remove table from the stack */
+ return n;
+}
+
+
+static int handle_script (lua_State *L, char **argv) {
+ int status;
+ const char *fname = argv[0];
+ if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0)
+ fname = NULL; /* stdin */
+ status = luaL_loadfile(L, fname);
+ if (status == LUA_OK) {
+ int n = pushargs(L); /* push arguments to script */
+ status = docall(L, n, LUA_MULTRET);
+ }
+ return report(L, status);
+}
+
+
+
+/* bits of various argument indicators in 'args' */
+#define has_error 1 /* bad option */
+#define has_i 2 /* -i */
+#define has_v 4 /* -v */
+#define has_e 8 /* -e */
+#define has_E 16 /* -E */
+
+/*
+** Traverses all arguments from 'argv', returning a mask with those
+** needed before running any Lua code (or an error code if it finds
+** any invalid argument). 'first' returns the first not-handled argument
+** (either the script name or a bad argument in case of error).
+*/
+static int collectargs (char **argv, int *first) {
+ int args = 0;
+ int i;
+ for (i = 1; argv[i] != NULL; i++) {
+ *first = i;
+ if (argv[i][0] != '-') /* not an option? */
+ return args; /* stop handling options */
+ switch (argv[i][1]) { /* else check option */
+ case '-': /* '--' */
+ if (argv[i][2] != '\0') /* extra characters after '--'? */
+ return has_error; /* invalid option */
+ *first = i + 1;
+ return args;
+ case '\0': /* '-' */
+ return args; /* script "name" is '-' */
+ case 'E':
+ if (argv[i][2] != '\0') /* extra characters after 1st? */
+ return has_error; /* invalid option */
+ args |= has_E;
+ break;
+ case 'i':
+ args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */
+ case 'v':
+ if (argv[i][2] != '\0') /* extra characters after 1st? */
+ return has_error; /* invalid option */
+ args |= has_v;
+ break;
+ case 'e':
+ args |= has_e; /* FALLTHROUGH */
+ case 'l': /* both options need an argument */
+ if (argv[i][2] == '\0') { /* no concatenated argument? */
+ i++; /* try next 'argv' */
+ if (argv[i] == NULL || argv[i][0] == '-')
+ return has_error; /* no next argument or it is another option */
+ }
+ break;
+ default: /* invalid option */
+ return has_error;
+ }
+ }
+ *first = i; /* no script name */
+ return args;
+}
+
+
+/*
+** Processes options 'e' and 'l', which involve running Lua code.
+** Returns 0 if some code raises an error.
+*/
+static int runargs (lua_State *L, char **argv, int n) {
+ int i;
+ for (i = 1; i < n; i++) {
+ int option = argv[i][1];
+ lua_assert(argv[i][0] == '-'); /* already checked */
+ if (option == 'e' || option == 'l') {
+ int status;
+ const char *extra = argv[i] + 2; /* both options need an argument */
+ if (*extra == '\0') extra = argv[++i];
+ lua_assert(extra != NULL);
+ status = (option == 'e')
+ ? dostring(L, extra, "=(command line)")
+ : dolibrary(L, extra);
+ if (status != LUA_OK) return 0;
+ }
+ }
+ return 1;
+}
+
+
+static int handle_luainit (lua_State *L) {
+ const char *name = "=" LUA_INITVARVERSION;
+ const char *init = getenv(name + 1);
+ if (init == NULL) {
+ name = "=" LUA_INIT_VAR;
+ init = getenv(name + 1); /* try alternative name */
+ }
+ if (init == NULL) return LUA_OK;
+ else if (init[0] == '@')
+ return dofile(L, init+1);
+ else
+ return dostring(L, init, name);
+}
+
+
+/*
+** Main body of stand-alone interpreter (to be called in protected mode).
+** Reads the options and handles them all.
+*/
+static int pmain (lua_State *L) {
+ int argc = (int)lua_tointeger(L, 1);
+ char **argv = (char **)lua_touserdata(L, 2);
+ int script;
+ int args = collectargs(argv, &script);
+ luaL_checkversion(L); /* check that interpreter has correct version */
+ if (argv[0] && argv[0][0]) progname = argv[0];
+ if (args == has_error) { /* bad arg? */
+ print_usage(argv[script]); /* 'script' has index of bad arg. */
+ return 0;
+ }
+ if (args & has_v) /* option '-v'? */
+ print_version();
+ if (args & has_E) { /* option '-E'? */
+ lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */
+ lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
+ }
+ luaL_openlibs(L); /* open standard libraries */
+ createargtable(L, argv, argc, script); /* create table 'arg' */
+ if (!(args & has_E)) { /* no option '-E'? */
+ if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
+ return 0; /* error running LUA_INIT */
+ }
+ if (!runargs(L, argv, script)) /* execute arguments -e and -l */
+ return 0; /* something failed */
+ if (script < argc && /* execute main script (if there is one) */
+ handle_script(L, argv + script) != LUA_OK)
+ return 0;
+ if (args & has_i) /* -i option? */
+ doREPL(L); /* do read-eval-print loop */
+ else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */
+ if (lua_stdin_is_tty()) { /* running in interactive mode? */
+ print_version();
+ doREPL(L); /* do read-eval-print loop */
+ }
+ else dofile(L, NULL); /* executes stdin as a file */
+ }
+ lua_pushboolean(L, 1); /* signal no errors */
+ return 1;
+}
+
+
+int main (int argc, char **argv) {
+ int status, result;
+ lua_State *L = luaL_newstate(); /* create state */
+ if (L == NULL) {
+ l_message(argv[0], "cannot create state: not enough memory");
+ return EXIT_FAILURE;
+ }
+ lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
+ lua_pushinteger(L, argc); /* 1st argument */
+ lua_pushlightuserdata(L, argv); /* 2nd argument */
+ status = lua_pcall(L, 2, 1, 0); /* do the call */
+ result = lua_toboolean(L, -1); /* get result */
+ report(L, status);
+ lua_close(L);
+ return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
diff --git a/external/lua-5.3.3/src/lua.h b/external/lua-5.3.3/src/lua.h
new file mode 100644
index 0000000..f78899f
--- /dev/null
+++ b/external/lua-5.3.3/src/lua.h
@@ -0,0 +1,486 @@
+/*
+** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $
+** Lua - A Scripting Language
+** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
+** See Copyright Notice at the end of this file
+*/
+
+
+#ifndef lua_h
+#define lua_h
+
+#include <stdarg.h>
+#include <stddef.h>
+
+
+#include "luaconf.h"
+
+
+#define LUA_VERSION_MAJOR "5"
+#define LUA_VERSION_MINOR "3"
+#define LUA_VERSION_NUM 503
+#define LUA_VERSION_RELEASE "3"
+
+#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
+#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 Lua.org, PUC-Rio"
+#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
+
+
+/* mark for precompiled code ('<esc>Lua') */
+#define LUA_SIGNATURE "\x1bLua"
+
+/* option for multiple returns in 'lua_pcall' and 'lua_call' */
+#define LUA_MULTRET (-1)
+
+
+/*
+** Pseudo-indices
+** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
+** space after that to help overflow detection)
+*/
+#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
+#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
+
+
+/* thread status */
+#define LUA_OK 0
+#define LUA_YIELD 1
+#define LUA_ERRRUN 2
+#define LUA_ERRSYNTAX 3
+#define LUA_ERRMEM 4
+#define LUA_ERRGCMM 5
+#define LUA_ERRERR 6
+
+
+typedef struct lua_State lua_State;
+
+
+/*
+** basic types
+*/
+#define LUA_TNONE (-1)
+
+#define LUA_TNIL 0
+#define LUA_TBOOLEAN 1
+#define LUA_TLIGHTUSERDATA 2
+#define LUA_TNUMBER 3
+#define LUA_TSTRING 4
+#define LUA_TTABLE 5
+#define LUA_TFUNCTION 6
+#define LUA_TUSERDATA 7
+#define LUA_TTHREAD 8
+
+#define LUA_NUMTAGS 9
+
+
+
+/* minimum Lua stack available to a C function */
+#define LUA_MINSTACK 20
+
+
+/* predefined values in the registry */
+#define LUA_RIDX_MAINTHREAD 1
+#define LUA_RIDX_GLOBALS 2
+#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
+
+
+/* type of numbers in Lua */
+typedef LUA_NUMBER lua_Number;
+
+
+/* type for integer functions */
+typedef LUA_INTEGER lua_Integer;
+
+/* unsigned integer type */
+typedef LUA_UNSIGNED lua_Unsigned;
+
+/* type for continuation-function contexts */
+typedef LUA_KCONTEXT lua_KContext;
+
+
+/*
+** Type for C functions registered with Lua
+*/
+typedef int (*lua_CFunction) (lua_State *L);
+
+/*
+** Type for continuation functions
+*/
+typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
+
+
+/*
+** Type for functions that read/write blocks when loading/dumping Lua chunks
+*/
+typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
+
+typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);
+
+
+/*
+** Type for memory-allocation functions
+*/
+typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
+
+
+
+/*
+** generic extra include file
+*/
+#if defined(LUA_USER_H)
+#include LUA_USER_H
+#endif
+
+
+/*
+** RCS ident string
+*/
+extern const char lua_ident[];
+
+
+/*
+** state manipulation
+*/
+LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
+LUA_API void (lua_close) (lua_State *L);
+LUA_API lua_State *(lua_newthread) (lua_State *L);
+
+LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
+
+
+LUA_API const lua_Number *(lua_version) (lua_State *L);
+
+
+/*
+** basic stack manipulation
+*/
+LUA_API int (lua_absindex) (lua_State *L, int idx);
+LUA_API int (lua_gettop) (lua_State *L);
+LUA_API void (lua_settop) (lua_State *L, int idx);
+LUA_API void (lua_pushvalue) (lua_State *L, int idx);
+LUA_API void (lua_rotate) (lua_State *L, int idx, int n);
+LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx);
+LUA_API int (lua_checkstack) (lua_State *L, int n);
+
+LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
+
+
+/*
+** access functions (stack -> C)
+*/
+
+LUA_API int (lua_isnumber) (lua_State *L, int idx);
+LUA_API int (lua_isstring) (lua_State *L, int idx);
+LUA_API int (lua_iscfunction) (lua_State *L, int idx);
+LUA_API int (lua_isinteger) (lua_State *L, int idx);
+LUA_API int (lua_isuserdata) (lua_State *L, int idx);
+LUA_API int (lua_type) (lua_State *L, int idx);
+LUA_API const char *(lua_typename) (lua_State *L, int tp);
+
+LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
+LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
+LUA_API int (lua_toboolean) (lua_State *L, int idx);
+LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
+LUA_API size_t (lua_rawlen) (lua_State *L, int idx);
+LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
+LUA_API void *(lua_touserdata) (lua_State *L, int idx);
+LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
+LUA_API const void *(lua_topointer) (lua_State *L, int idx);
+
+
+/*
+** Comparison and arithmetic functions
+*/
+
+#define LUA_OPADD 0 /* ORDER TM, ORDER OP */
+#define LUA_OPSUB 1
+#define LUA_OPMUL 2
+#define LUA_OPMOD 3
+#define LUA_OPPOW 4
+#define LUA_OPDIV 5
+#define LUA_OPIDIV 6
+#define LUA_OPBAND 7
+#define LUA_OPBOR 8
+#define LUA_OPBXOR 9
+#define LUA_OPSHL 10
+#define LUA_OPSHR 11
+#define LUA_OPUNM 12
+#define LUA_OPBNOT 13
+
+LUA_API void (lua_arith) (lua_State *L, int op);
+
+#define LUA_OPEQ 0
+#define LUA_OPLT 1
+#define LUA_OPLE 2
+
+LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
+LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op);
+
+
+/*
+** push functions (C -> stack)
+*/
+LUA_API void (lua_pushnil) (lua_State *L);
+LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
+LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
+LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
+LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
+LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
+ va_list argp);
+LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
+LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
+LUA_API void (lua_pushboolean) (lua_State *L, int b);
+LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
+LUA_API int (lua_pushthread) (lua_State *L);
+
+
+/*
+** get functions (Lua -> stack)
+*/
+LUA_API int (lua_getglobal) (lua_State *L, const char *name);
+LUA_API int (lua_gettable) (lua_State *L, int idx);
+LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
+LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);
+LUA_API int (lua_rawget) (lua_State *L, int idx);
+LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
+LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
+
+LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
+LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
+LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
+LUA_API int (lua_getuservalue) (lua_State *L, int idx);
+
+
+/*
+** set functions (stack -> Lua)
+*/
+LUA_API void (lua_setglobal) (lua_State *L, const char *name);
+LUA_API void (lua_settable) (lua_State *L, int idx);
+LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
+LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n);
+LUA_API void (lua_rawset) (lua_State *L, int idx);
+LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n);
+LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p);
+LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
+LUA_API void (lua_setuservalue) (lua_State *L, int idx);
+
+
+/*
+** 'load' and 'call' functions (load and run Lua code)
+*/
+LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults,
+ lua_KContext ctx, lua_KFunction k);
+#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
+
+LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
+ lua_KContext ctx, lua_KFunction k);
+#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
+
+LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
+ const char *chunkname, const char *mode);
+
+LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
+
+
+/*
+** coroutine functions
+*/
+LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx,
+ lua_KFunction k);
+LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg);
+LUA_API int (lua_status) (lua_State *L);
+LUA_API int (lua_isyieldable) (lua_State *L);
+
+#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
+
+
+/*
+** garbage-collection function and options
+*/
+
+#define LUA_GCSTOP 0
+#define LUA_GCRESTART 1
+#define LUA_GCCOLLECT 2
+#define LUA_GCCOUNT 3
+#define LUA_GCCOUNTB 4
+#define LUA_GCSTEP 5
+#define LUA_GCSETPAUSE 6
+#define LUA_GCSETSTEPMUL 7
+#define LUA_GCISRUNNING 9
+
+LUA_API int (lua_gc) (lua_State *L, int what, int data);
+
+
+/*
+** miscellaneous functions
+*/
+
+LUA_API int (lua_error) (lua_State *L);
+
+LUA_API int (lua_next) (lua_State *L, int idx);
+
+LUA_API void (lua_concat) (lua_State *L, int n);
+LUA_API void (lua_len) (lua_State *L, int idx);
+
+LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
+
+LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
+LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
+
+
+
+/*
+** {==============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE))
+
+#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL)
+#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL)
+
+#define lua_pop(L,n) lua_settop(L, -(n)-1)
+
+#define lua_newtable(L) lua_createtable(L, 0, 0)
+
+#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
+
+#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
+
+#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
+#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
+#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
+#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
+#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
+#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
+#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
+#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
+
+#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
+
+#define lua_pushglobaltable(L) \
+ ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
+
+#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
+
+
+#define lua_insert(L,idx) lua_rotate(L, (idx), 1)
+
+#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
+
+#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))
+
+/* }============================================================== */
+
+
+/*
+** {==============================================================
+** compatibility macros for unsigned conversions
+** ===============================================================
+*/
+#if defined(LUA_COMPAT_APIINTCASTS)
+
+#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
+#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is))
+#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL)
+
+#endif
+/* }============================================================== */
+
+/*
+** {======================================================================
+** Debug API
+** =======================================================================
+*/
+
+
+/*
+** Event codes
+*/
+#define LUA_HOOKCALL 0
+#define LUA_HOOKRET 1
+#define LUA_HOOKLINE 2
+#define LUA_HOOKCOUNT 3
+#define LUA_HOOKTAILCALL 4
+
+
+/*
+** Event masks
+*/
+#define LUA_MASKCALL (1 << LUA_HOOKCALL)
+#define LUA_MASKRET (1 << LUA_HOOKRET)
+#define LUA_MASKLINE (1 << LUA_HOOKLINE)
+#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
+
+typedef struct lua_Debug lua_Debug; /* activation record */
+
+
+/* Functions to be called by the debugger in specific events */
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
+
+
+LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
+LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
+LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n);
+LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n);
+
+LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n);
+LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,
+ int fidx2, int n2);
+
+LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
+LUA_API lua_Hook (lua_gethook) (lua_State *L);
+LUA_API int (lua_gethookmask) (lua_State *L);
+LUA_API int (lua_gethookcount) (lua_State *L);
+
+
+struct lua_Debug {
+ int event;
+ const char *name; /* (n) */
+ const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */
+ const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */
+ const char *source; /* (S) */
+ int currentline; /* (l) */
+ int linedefined; /* (S) */
+ int lastlinedefined; /* (S) */
+ unsigned char nups; /* (u) number of upvalues */
+ unsigned char nparams;/* (u) number of parameters */
+ char isvararg; /* (u) */
+ char istailcall; /* (t) */
+ char short_src[LUA_IDSIZE]; /* (S) */
+ /* private part */
+ struct CallInfo *i_ci; /* active function */
+};
+
+/* }====================================================================== */
+
+
+/******************************************************************************
+* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
+*
+* 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+******************************************************************************/
+
+
+#endif
diff --git a/external/lua-5.3.3/src/lua.hpp b/external/lua-5.3.3/src/lua.hpp
new file mode 100644
index 0000000..ec417f5
--- /dev/null
+++ b/external/lua-5.3.3/src/lua.hpp
@@ -0,0 +1,9 @@
+// lua.hpp
+// Lua header files for C++
+// <<extern "C">> not supplied automatically because Lua also compiles as C++
+
+extern "C" {
+#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
+}
diff --git a/external/lua-5.3.3/src/luac.c b/external/lua-5.3.3/src/luac.c
new file mode 100644
index 0000000..c0c91d0
--- /dev/null
+++ b/external/lua-5.3.3/src/luac.c
@@ -0,0 +1,449 @@
+/*
+** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
+** Lua compiler (saves bytecodes to files; also lists bytecodes)
+** See Copyright Notice in lua.h
+*/
+
+#define luac_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lundump.h"
+
+static void PrintFunction(const Proto* f, int full);
+#define luaU_print PrintFunction
+
+#define PROGNAME "luac" /* default program name */
+#define OUTPUT PROGNAME ".out" /* default output file */
+
+static int listing=0; /* list bytecodes? */
+static int dumping=1; /* dump bytecodes? */
+static int stripping=0; /* strip debug information? */
+static char Output[]={ OUTPUT }; /* default output file name */
+static const char* output=Output; /* actual output file name */
+static const char* progname=PROGNAME; /* actual program name */
+
+static void fatal(const char* message)
+{
+ fprintf(stderr,"%s: %s\n",progname,message);
+ exit(EXIT_FAILURE);
+}
+
+static void cannot(const char* what)
+{
+ fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
+ exit(EXIT_FAILURE);
+}
+
+static void usage(const char* message)
+{
+ if (*message=='-')
+ fprintf(stderr,"%s: unrecognized option '%s'\n",progname,message);
+ else
+ fprintf(stderr,"%s: %s\n",progname,message);
+ fprintf(stderr,
+ "usage: %s [options] [filenames]\n"
+ "Available options are:\n"
+ " -l list (use -l -l for full listing)\n"
+ " -o name output to file 'name' (default is \"%s\")\n"
+ " -p parse only\n"
+ " -s strip debug information\n"
+ " -v show version information\n"
+ " -- stop handling options\n"
+ " - stop handling options and process stdin\n"
+ ,progname,Output);
+ exit(EXIT_FAILURE);
+}
+
+#define IS(s) (strcmp(argv[i],s)==0)
+
+static int doargs(int argc, char* argv[])
+{
+ int i;
+ int version=0;
+ if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
+ for (i=1; i<argc; i++)
+ {
+ if (*argv[i]!='-') /* end of options; keep it */
+ break;
+ else if (IS("--")) /* end of options; skip it */
+ {
+ ++i;
+ if (version) ++version;
+ break;
+ }
+ else if (IS("-")) /* end of options; use stdin */
+ break;
+ else if (IS("-l")) /* list */
+ ++listing;
+ else if (IS("-o")) /* output file */
+ {
+ output=argv[++i];
+ if (output==NULL || *output==0 || (*output=='-' && output[1]!=0))
+ usage("'-o' needs argument");
+ if (IS("-")) output=NULL;
+ }
+ else if (IS("-p")) /* parse only */
+ dumping=0;
+ else if (IS("-s")) /* strip debug information */
+ stripping=1;
+ else if (IS("-v")) /* show version */
+ ++version;
+ else /* unknown option */
+ usage(argv[i]);
+ }
+ if (i==argc && (listing || !dumping))
+ {
+ dumping=0;
+ argv[--i]=Output;
+ }
+ if (version)
+ {
+ printf("%s\n",LUA_COPYRIGHT);
+ if (version==argc-1) exit(EXIT_SUCCESS);
+ }
+ return i;
+}
+
+#define FUNCTION "(function()end)();"
+
+static const char* reader(lua_State *L, void *ud, size_t *size)
+{
+ UNUSED(L);
+ if ((*(int*)ud)--)
+ {
+ *size=sizeof(FUNCTION)-1;
+ return FUNCTION;
+ }
+ else
+ {
+ *size=0;
+ return NULL;
+ }
+}
+
+#define toproto(L,i) getproto(L->top+(i))
+
+static const Proto* combine(lua_State* L, int n)
+{
+ if (n==1)
+ return toproto(L,-1);
+ else
+ {
+ Proto* f;
+ int i=n;
+ if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1));
+ f=toproto(L,-1);
+ for (i=0; i<n; i++)
+ {
+ f->p[i]=toproto(L,i-n-1);
+ if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
+ }
+ f->sizelineinfo=0;
+ return f;
+ }
+}
+
+static int writer(lua_State* L, const void* p, size_t size, void* u)
+{
+ UNUSED(L);
+ return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
+}
+
+static int pmain(lua_State* L)
+{
+ int argc=(int)lua_tointeger(L,1);
+ char** argv=(char**)lua_touserdata(L,2);
+ const Proto* f;
+ int i;
+ if (!lua_checkstack(L,argc)) fatal("too many input files");
+ for (i=0; i<argc; i++)
+ {
+ const char* filename=IS("-") ? NULL : argv[i];
+ if (luaL_loadfile(L,filename)!=LUA_OK) fatal(lua_tostring(L,-1));
+ }
+ f=combine(L,argc);
+ if (listing) luaU_print(f,listing>1);
+ if (dumping)
+ {
+ FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
+ if (D==NULL) cannot("open");
+ lua_lock(L);
+ luaU_dump(L,f,writer,D,stripping);
+ lua_unlock(L);
+ if (ferror(D)) cannot("write");
+ if (fclose(D)) cannot("close");
+ }
+ return 0;
+}
+
+int main(int argc, char* argv[])
+{
+ lua_State* L;
+ int i=doargs(argc,argv);
+ argc-=i; argv+=i;
+ if (argc<=0) usage("no input files given");
+ L=luaL_newstate();
+ if (L==NULL) fatal("cannot create state: not enough memory");
+ lua_pushcfunction(L,&pmain);
+ lua_pushinteger(L,argc);
+ lua_pushlightuserdata(L,argv);
+ if (lua_pcall(L,2,0,0)!=LUA_OK) fatal(lua_tostring(L,-1));
+ lua_close(L);
+ return EXIT_SUCCESS;
+}
+
+/*
+** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
+** print bytecodes
+** See Copyright Notice in lua.h
+*/
+
+#include <ctype.h>
+#include <stdio.h>
+
+#define luac_c
+#define LUA_CORE
+
+#include "ldebug.h"
+#include "lobject.h"
+#include "lopcodes.h"
+
+#define VOID(p) ((const void*)(p))
+
+static void PrintString(const TString* ts)
+{
+ const char* s=getstr(ts);
+ size_t i,n=tsslen(ts);
+ printf("%c",'"');
+ for (i=0; i<n; i++)
+ {
+ int c=(int)(unsigned char)s[i];
+ switch (c)
+ {
+ case '"': printf("\\\""); break;
+ case '\\': printf("\\\\"); break;
+ case '\a': printf("\\a"); break;
+ case '\b': printf("\\b"); break;
+ case '\f': printf("\\f"); break;
+ case '\n': printf("\\n"); break;
+ case '\r': printf("\\r"); break;
+ case '\t': printf("\\t"); break;
+ case '\v': printf("\\v"); break;
+ default: if (isprint(c))
+ printf("%c",c);
+ else
+ printf("\\%03d",c);
+ }
+ }
+ printf("%c",'"');
+}
+
+static void PrintConstant(const Proto* f, int i)
+{
+ const TValue* o=&f->k[i];
+ switch (ttype(o))
+ {
+ case LUA_TNIL:
+ printf("nil");
+ break;
+ case LUA_TBOOLEAN:
+ printf(bvalue(o) ? "true" : "false");
+ break;
+ case LUA_TNUMFLT:
+ {
+ char buff[100];
+ sprintf(buff,LUA_NUMBER_FMT,fltvalue(o));
+ printf("%s",buff);
+ if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0");
+ break;
+ }
+ case LUA_TNUMINT:
+ printf(LUA_INTEGER_FMT,ivalue(o));
+ break;
+ case LUA_TSHRSTR: case LUA_TLNGSTR:
+ PrintString(tsvalue(o));
+ break;
+ default: /* cannot happen */
+ printf("? type=%d",ttype(o));
+ break;
+ }
+}
+
+#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
+#define MYK(x) (-1-(x))
+
+static void PrintCode(const Proto* f)
+{
+ const Instruction* code=f->code;
+ int pc,n=f->sizecode;
+ for (pc=0; pc<n; pc++)
+ {
+ Instruction i=code[pc];
+ OpCode o=GET_OPCODE(i);
+ int a=GETARG_A(i);
+ int b=GETARG_B(i);
+ int c=GETARG_C(i);
+ int ax=GETARG_Ax(i);
+ int bx=GETARG_Bx(i);
+ int sbx=GETARG_sBx(i);
+ int line=getfuncline(f,pc);
+ printf("\t%d\t",pc+1);
+ if (line>0) printf("[%d]\t",line); else printf("[-]\t");
+ printf("%-9s\t",luaP_opnames[o]);
+ switch (getOpMode(o))
+ {
+ case iABC:
+ printf("%d",a);
+ if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (MYK(INDEXK(b))) : b);
+ if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c);
+ break;
+ case iABx:
+ printf("%d",a);
+ if (getBMode(o)==OpArgK) printf(" %d",MYK(bx));
+ if (getBMode(o)==OpArgU) printf(" %d",bx);
+ break;
+ case iAsBx:
+ printf("%d %d",a,sbx);
+ break;
+ case iAx:
+ printf("%d",MYK(ax));
+ break;
+ }
+ switch (o)
+ {
+ case OP_LOADK:
+ printf("\t; "); PrintConstant(f,bx);
+ break;
+ case OP_GETUPVAL:
+ case OP_SETUPVAL:
+ printf("\t; %s",UPVALNAME(b));
+ break;
+ case OP_GETTABUP:
+ printf("\t; %s",UPVALNAME(b));
+ if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
+ break;
+ case OP_SETTABUP:
+ printf("\t; %s",UPVALNAME(a));
+ if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); }
+ if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
+ break;
+ case OP_GETTABLE:
+ case OP_SELF:
+ if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); }
+ break;
+ case OP_SETTABLE:
+ case OP_ADD:
+ case OP_SUB:
+ case OP_MUL:
+ case OP_POW:
+ case OP_DIV:
+ case OP_IDIV:
+ case OP_BAND:
+ case OP_BOR:
+ case OP_BXOR:
+ case OP_SHL:
+ case OP_SHR:
+ case OP_EQ:
+ case OP_LT:
+ case OP_LE:
+ if (ISK(b) || ISK(c))
+ {
+ printf("\t; ");
+ if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-");
+ printf(" ");
+ if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-");
+ }
+ break;
+ case OP_JMP:
+ case OP_FORLOOP:
+ case OP_FORPREP:
+ case OP_TFORLOOP:
+ printf("\t; to %d",sbx+pc+2);
+ break;
+ case OP_CLOSURE:
+ printf("\t; %p",VOID(f->p[bx]));
+ break;
+ case OP_SETLIST:
+ if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c);
+ break;
+ case OP_EXTRAARG:
+ printf("\t; "); PrintConstant(f,ax);
+ break;
+ default:
+ break;
+ }
+ printf("\n");
+ }
+}
+
+#define SS(x) ((x==1)?"":"s")
+#define S(x) (int)(x),SS(x)
+
+static void PrintHeader(const Proto* f)
+{
+ const char* s=f->source ? getstr(f->source) : "=?";
+ if (*s=='@' || *s=='=')
+ s++;
+ else if (*s==LUA_SIGNATURE[0])
+ s="(bstring)";
+ else
+ s="(string)";
+ printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n",
+ (f->linedefined==0)?"main":"function",s,
+ f->linedefined,f->lastlinedefined,
+ S(f->sizecode),VOID(f));
+ printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
+ (int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams),
+ S(f->maxstacksize),S(f->sizeupvalues));
+ printf("%d local%s, %d constant%s, %d function%s\n",
+ S(f->sizelocvars),S(f->sizek),S(f->sizep));
+}
+
+static void PrintDebug(const Proto* f)
+{
+ int i,n;
+ n=f->sizek;
+ printf("constants (%d) for %p:\n",n,VOID(f));
+ for (i=0; i<n; i++)
+ {
+ printf("\t%d\t",i+1);
+ PrintConstant(f,i);
+ printf("\n");
+ }
+ n=f->sizelocvars;
+ printf("locals (%d) for %p:\n",n,VOID(f));
+ for (i=0; i<n; i++)
+ {
+ printf("\t%d\t%s\t%d\t%d\n",
+ i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
+ }
+ n=f->sizeupvalues;
+ printf("upvalues (%d) for %p:\n",n,VOID(f));
+ for (i=0; i<n; i++)
+ {
+ printf("\t%d\t%s\t%d\t%d\n",
+ i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx);
+ }
+}
+
+static void PrintFunction(const Proto* f, int full)
+{
+ int i,n=f->sizep;
+ PrintHeader(f);
+ PrintCode(f);
+ if (full) PrintDebug(f);
+ for (i=0; i<n; i++) PrintFunction(f->p[i],full);
+}
diff --git a/external/lua-5.3.3/src/luaconf.h b/external/lua-5.3.3/src/luaconf.h
new file mode 100644
index 0000000..fd447cc
--- /dev/null
+++ b/external/lua-5.3.3/src/luaconf.h
@@ -0,0 +1,767 @@
+/*
+** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $
+** Configuration file for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef luaconf_h
+#define luaconf_h
+
+#include <limits.h>
+#include <stddef.h>
+
+
+/*
+** ===================================================================
+** Search for "@@" to find all configurable definitions.
+** ===================================================================
+*/
+
+
+/*
+** {====================================================================
+** System Configuration: macros to adapt (if needed) Lua to some
+** particular platform, for instance compiling it with 32-bit numbers or
+** restricting it to C89.
+** =====================================================================
+*/
+
+/*
+@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You
+** can also define LUA_32BITS in the make file, but changing here you
+** ensure that all software connected to Lua will be compiled with the
+** same configuration.
+*/
+/* #define LUA_32BITS */
+
+
+/*
+@@ LUA_USE_C89 controls the use of non-ISO-C89 features.
+** Define it if you want Lua to avoid the use of a few C99 features
+** or Windows-specific features on Windows.
+*/
+/* #define LUA_USE_C89 */
+
+
+/*
+** By default, Lua on Windows use (some) specific Windows features
+*/
+#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)
+#define LUA_USE_WINDOWS /* enable goodies for regular Windows */
+#endif
+
+
+#if defined(LUA_USE_WINDOWS)
+#define LUA_DL_DLL /* enable support for DLL */
+#define LUA_USE_C89 /* broadly, Windows is C89 */
+#endif
+
+
+#if defined(LUA_USE_LINUX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
+#define LUA_USE_READLINE /* needs some extra libraries */
+#endif
+
+
+#if defined(LUA_USE_MACOSX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN /* MacOS does not need -ldl */
+#define LUA_USE_READLINE /* needs an extra library: -lreadline */
+#endif
+
+
+/*
+@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
+** C89 ('long' and 'double'); Windows always has '__int64', so it does
+** not need to use this case.
+*/
+#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
+#define LUA_C89_NUMBERS
+#endif
+
+
+
+/*
+@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'.
+*/
+/* avoid undefined shifts */
+#if ((INT_MAX >> 15) >> 15) >= 1
+#define LUAI_BITSINT 32
+#else
+/* 'int' always must have at least 16 bits */
+#define LUAI_BITSINT 16
+#endif
+
+
+/*
+@@ LUA_INT_TYPE defines the type for Lua integers.
+@@ LUA_FLOAT_TYPE defines the type for Lua floats.
+** Lua should work fine with any mix of these options (if supported
+** by your C compiler). The usual configurations are 64-bit integers
+** and 'double' (the default), 32-bit integers and 'float' (for
+** restricted platforms), and 'long'/'double' (for C compilers not
+** compliant with C99, which may not have support for 'long long').
+*/
+
+/* predefined options for LUA_INT_TYPE */
+#define LUA_INT_INT 1
+#define LUA_INT_LONG 2
+#define LUA_INT_LONGLONG 3
+
+/* predefined options for LUA_FLOAT_TYPE */
+#define LUA_FLOAT_FLOAT 1
+#define LUA_FLOAT_DOUBLE 2
+#define LUA_FLOAT_LONGDOUBLE 3
+
+#if defined(LUA_32BITS) /* { */
+/*
+** 32-bit integers and 'float'
+*/
+#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
+#define LUA_INT_TYPE LUA_INT_INT
+#else /* otherwise use 'long' */
+#define LUA_INT_TYPE LUA_INT_LONG
+#endif
+#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
+
+#elif defined(LUA_C89_NUMBERS) /* }{ */
+/*
+** largest types available for C89 ('long' and 'double')
+*/
+#define LUA_INT_TYPE LUA_INT_LONG
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+
+#endif /* } */
+
+
+/*
+** default configuration for 64-bit Lua ('long long' and 'double')
+*/
+#if !defined(LUA_INT_TYPE)
+#define LUA_INT_TYPE LUA_INT_LONGLONG
+#endif
+
+#if !defined(LUA_FLOAT_TYPE)
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+#endif
+
+/* }================================================================== */
+
+
+
+
+/*
+** {==================================================================
+** Configuration for Paths.
+** ===================================================================
+*/
+
+/*
+@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
+** Lua libraries.
+@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
+** C libraries.
+** CHANGE them if your machine has a non-conventional directory
+** hierarchy or if you want to install your libraries in
+** non-conventional directories.
+*/
+#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
+#if defined(_WIN32) /* { */
+/*
+** In Windows, any exclamation mark ('!') in the path is replaced by the
+** path of the directory of the executable file of the current process.
+*/
+#define LUA_LDIR "!\\lua\\"
+#define LUA_CDIR "!\\"
+#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\"
+#define LUA_PATH_DEFAULT \
+ LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
+ LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \
+ ".\\?.lua;" ".\\?\\init.lua"
+#define LUA_CPATH_DEFAULT \
+ LUA_CDIR"?.dll;" \
+ LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
+ LUA_CDIR"loadall.dll;" ".\\?.dll"
+
+#else /* }{ */
+
+#define LUA_ROOT "/usr/local/"
+#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/"
+#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/"
+#define LUA_PATH_DEFAULT \
+ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
+ "./?.lua;" "./?/init.lua"
+#define LUA_CPATH_DEFAULT \
+ LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so"
+#endif /* } */
+
+
+/*
+@@ LUA_DIRSEP is the directory separator (for submodules).
+** CHANGE it if your machine does not use "/" as the directory separator
+** and is not Windows. (On Windows Lua automatically uses "\".)
+*/
+#if defined(_WIN32)
+#define LUA_DIRSEP "\\"
+#else
+#define LUA_DIRSEP "/"
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Marks for exported symbols in the C code
+** ===================================================================
+*/
+
+/*
+@@ LUA_API is a mark for all core API functions.
+@@ LUALIB_API is a mark for all auxiliary library functions.
+@@ LUAMOD_API is a mark for all standard library opening functions.
+** CHANGE them if you need to define those functions in some special way.
+** For instance, if you want to create one Windows DLL with the core and
+** the libraries, you may want to use the following definition (define
+** LUA_BUILD_AS_DLL to get it).
+*/
+#if defined(LUA_BUILD_AS_DLL) /* { */
+
+#if defined(LUA_CORE) || defined(LUA_LIB) /* { */
+#define LUA_API __declspec(dllexport)
+#else /* }{ */
+#define LUA_API __declspec(dllimport)
+#endif /* } */
+
+#else /* }{ */
+
+#define LUA_API extern
+
+#endif /* } */
+
+
+/* more often than not the libs go together with the core */
+#define LUALIB_API LUA_API
+#define LUAMOD_API LUALIB_API
+
+
+/*
+@@ LUAI_FUNC is a mark for all extern functions that are not to be
+** exported to outside modules.
+@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables
+** that are not to be exported to outside modules (LUAI_DDEF for
+** definitions and LUAI_DDEC for declarations).
+** CHANGE them if you need to mark them in some special way. Elf/gcc
+** (versions 3.2 and later) mark them as "hidden" to optimize access
+** when Lua is compiled as a shared library. Not all elf targets support
+** this attribute. Unfortunately, gcc does not offer a way to check
+** whether the target offers that support, and those without support
+** give a warning about it. To avoid these warnings, change to the
+** default definition.
+*/
+#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
+ defined(__ELF__) /* { */
+#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
+#else /* }{ */
+#define LUAI_FUNC extern
+#endif /* } */
+
+#define LUAI_DDEC LUAI_FUNC
+#define LUAI_DDEF /* empty */
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Compatibility with previous versions
+** ===================================================================
+*/
+
+/*
+@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2.
+@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1.
+** You can define it to get all options, or change specific options
+** to fit your specific needs.
+*/
+#if defined(LUA_COMPAT_5_2) /* { */
+
+/*
+@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
+** functions in the mathematical library.
+*/
+#define LUA_COMPAT_MATHLIB
+
+/*
+@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'.
+*/
+#define LUA_COMPAT_BITLIB
+
+/*
+@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod.
+*/
+#define LUA_COMPAT_IPAIRS
+
+/*
+@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for
+** manipulating other integer types (lua_pushunsigned, lua_tounsigned,
+** luaL_checkint, luaL_checklong, etc.)
+*/
+#define LUA_COMPAT_APIINTCASTS
+
+#endif /* } */
+
+
+#if defined(LUA_COMPAT_5_1) /* { */
+
+/* Incompatibilities from 5.2 -> 5.3 */
+#define LUA_COMPAT_MATHLIB
+#define LUA_COMPAT_APIINTCASTS
+
+/*
+@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
+** You can replace it with 'table.unpack'.
+*/
+#define LUA_COMPAT_UNPACK
+
+/*
+@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'.
+** You can replace it with 'package.searchers'.
+*/
+#define LUA_COMPAT_LOADERS
+
+/*
+@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall.
+** You can call your C function directly (with light C functions).
+*/
+#define lua_cpcall(L,f,u) \
+ (lua_pushcfunction(L, (f)), \
+ lua_pushlightuserdata(L,(u)), \
+ lua_pcall(L,1,0,0))
+
+
+/*
+@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library.
+** You can rewrite 'log10(x)' as 'log(x, 10)'.
+*/
+#define LUA_COMPAT_LOG10
+
+/*
+@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base
+** library. You can rewrite 'loadstring(s)' as 'load(s)'.
+*/
+#define LUA_COMPAT_LOADSTRING
+
+/*
+@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library.
+*/
+#define LUA_COMPAT_MAXN
+
+/*
+@@ The following macros supply trivial compatibility for some
+** changes in the API. The macros themselves document how to
+** change your code to avoid using them.
+*/
+#define lua_strlen(L,i) lua_rawlen(L, (i))
+
+#define lua_objlen(L,i) lua_rawlen(L, (i))
+
+#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
+#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
+
+/*
+@@ LUA_COMPAT_MODULE controls compatibility with previous
+** module functions 'module' (Lua) and 'luaL_register' (C).
+*/
+#define LUA_COMPAT_MODULE
+
+#endif /* } */
+
+
+/*
+@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
+@@ a float mark ('.0').
+** This macro is not on by default even in compatibility mode,
+** because this is not really an incompatibility.
+*/
+/* #define LUA_COMPAT_FLOATSTRING */
+
+/* }================================================================== */
+
+
+
+/*
+** {==================================================================
+** Configuration for Numbers.
+** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
+** satisfy your needs.
+** ===================================================================
+*/
+
+/*
+@@ LUA_NUMBER is the floating-point type used by Lua.
+@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
+@@ over a floating number.
+@@ l_mathlim(x) corrects limit name 'x' to the proper float type
+** by prefixing it with one of FLT/DBL/LDBL.
+@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
+@@ LUA_NUMBER_FMT is the format for writing floats.
+@@ lua_number2str converts a float to a string.
+@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
+@@ l_floor takes the floor of a float.
+@@ lua_str2number converts a decimal numeric string to a number.
+*/
+
+
+/* The following definitions are good for most cases here */
+
+#define l_floor(x) (l_mathop(floor)(x))
+
+#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n))
+
+/*
+@@ lua_numbertointeger converts a float number to an integer, or
+** returns 0 if float is not within the range of a lua_Integer.
+** (The range comparisons are tricky because of rounding. The tests
+** here assume a two-complement representation, where MININTEGER always
+** has an exact representation as a float; MAXINTEGER may not have one,
+** and therefore its conversion to float may have an ill-defined value.)
+*/
+#define lua_numbertointeger(n,p) \
+ ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
+ (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
+ (*(p) = (LUA_INTEGER)(n), 1))
+
+
+/* now the variable definitions */
+
+#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
+
+#define LUA_NUMBER float
+
+#define l_mathlim(n) (FLT_##n)
+
+#define LUAI_UACNUMBER double
+
+#define LUA_NUMBER_FRMLEN ""
+#define LUA_NUMBER_FMT "%.7g"
+
+#define l_mathop(op) op##f
+
+#define lua_str2number(s,p) strtof((s), (p))
+
+
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
+
+#define LUA_NUMBER long double
+
+#define l_mathlim(n) (LDBL_##n)
+
+#define LUAI_UACNUMBER long double
+
+#define LUA_NUMBER_FRMLEN "L"
+#define LUA_NUMBER_FMT "%.19Lg"
+
+#define l_mathop(op) op##l
+
+#define lua_str2number(s,p) strtold((s), (p))
+
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
+
+#define LUA_NUMBER double
+
+#define l_mathlim(n) (DBL_##n)
+
+#define LUAI_UACNUMBER double
+
+#define LUA_NUMBER_FRMLEN ""
+#define LUA_NUMBER_FMT "%.14g"
+
+#define l_mathop(op) op
+
+#define lua_str2number(s,p) strtod((s), (p))
+
+#else /* }{ */
+
+#error "numeric float type not defined"
+
+#endif /* } */
+
+
+
+/*
+@@ LUA_INTEGER is the integer type used by Lua.
+**
+@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
+**
+@@ LUAI_UACINT is the result of an 'usual argument conversion'
+@@ over a lUA_INTEGER.
+@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
+@@ LUA_INTEGER_FMT is the format for writing integers.
+@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
+@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
+@@ lua_integer2str converts an integer to a string.
+*/
+
+
+/* The following definitions are good for most cases here */
+
+#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
+#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n))
+
+#define LUAI_UACINT LUA_INTEGER
+
+/*
+** use LUAI_UACINT here to avoid problems with promotions (which
+** can turn a comparison between unsigneds into a signed comparison)
+*/
+#define LUA_UNSIGNED unsigned LUAI_UACINT
+
+
+/* now the variable definitions */
+
+#if LUA_INT_TYPE == LUA_INT_INT /* { int */
+
+#define LUA_INTEGER int
+#define LUA_INTEGER_FRMLEN ""
+
+#define LUA_MAXINTEGER INT_MAX
+#define LUA_MININTEGER INT_MIN
+
+#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
+
+#define LUA_INTEGER long
+#define LUA_INTEGER_FRMLEN "l"
+
+#define LUA_MAXINTEGER LONG_MAX
+#define LUA_MININTEGER LONG_MIN
+
+#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
+
+/* use presence of macro LLONG_MAX as proxy for C99 compliance */
+#if defined(LLONG_MAX) /* { */
+/* use ISO C99 stuff */
+
+#define LUA_INTEGER long long
+#define LUA_INTEGER_FRMLEN "ll"
+
+#define LUA_MAXINTEGER LLONG_MAX
+#define LUA_MININTEGER LLONG_MIN
+
+#elif defined(LUA_USE_WINDOWS) /* }{ */
+/* in Windows, can use specific Windows types */
+
+#define LUA_INTEGER __int64
+#define LUA_INTEGER_FRMLEN "I64"
+
+#define LUA_MAXINTEGER _I64_MAX
+#define LUA_MININTEGER _I64_MIN
+
+#else /* }{ */
+
+#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \
+ or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)"
+
+#endif /* } */
+
+#else /* }{ */
+
+#error "numeric integer type not defined"
+
+#endif /* } */
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Dependencies with C99 and other C details
+** ===================================================================
+*/
+
+/*
+@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
+** (All uses in Lua have only one format item.)
+*/
+#if !defined(LUA_USE_C89)
+#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
+#else
+#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
+#endif
+
+
+/*
+@@ lua_strx2number converts an hexadecimal numeric string to a number.
+** In C99, 'strtod' does that conversion. Otherwise, you can
+** leave 'lua_strx2number' undefined and Lua will provide its own
+** implementation.
+*/
+#if !defined(LUA_USE_C89)
+#define lua_strx2number(s,p) lua_str2number(s,p)
+#endif
+
+
+/*
+@@ lua_number2strx converts a float to an hexadecimal numeric string.
+** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
+** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
+** provide its own implementation.
+*/
+#if !defined(LUA_USE_C89)
+#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n))
+#endif
+
+
+/*
+** 'strtof' and 'opf' variants for math functions are not valid in
+** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the
+** availability of these variants. ('math.h' is already included in
+** all files that use these macros.)
+*/
+#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF))
+#undef l_mathop /* variants not available */
+#undef lua_str2number
+#define l_mathop(op) (lua_Number)op /* no variant */
+#define lua_str2number(s,p) ((lua_Number)strtod((s), (p)))
+#endif
+
+
+/*
+@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation
+** functions. It must be a numerical type; Lua will use 'intptr_t' if
+** available, otherwise it will use 'ptrdiff_t' (the nearest thing to
+** 'intptr_t' in C89)
+*/
+#define LUA_KCONTEXT ptrdiff_t
+
+#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+#if defined(INTPTR_MAX) /* even in C99 this type is optional */
+#undef LUA_KCONTEXT
+#define LUA_KCONTEXT intptr_t
+#endif
+#endif
+
+
+/*
+@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
+** Change that if you do not want to use C locales. (Code using this
+** macro must include header 'locale.h'.)
+*/
+#if !defined(lua_getlocaledecpoint)
+#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Language Variations
+** =====================================================================
+*/
+
+/*
+@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some
+** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from
+** numbers to strings. Define LUA_NOCVTS2N to turn off automatic
+** coercion from strings to numbers.
+*/
+/* #define LUA_NOCVTN2S */
+/* #define LUA_NOCVTS2N */
+
+
+/*
+@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
+** Define it as a help when debugging C code.
+*/
+#if defined(LUA_USE_APICHECK)
+#include <assert.h>
+#define luai_apicheck(l,e) assert(e)
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Macros that affect the API and must be stable (that is, must be the
+** same when you compile Lua and when you compile code that links to
+** Lua). You probably do not want/need to change them.
+** =====================================================================
+*/
+
+/*
+@@ LUAI_MAXSTACK limits the size of the Lua stack.
+** CHANGE it if you need a different limit. This limit is arbitrary;
+** its only purpose is to stop Lua from consuming unlimited stack
+** space (and to reserve some numbers for pseudo-indices).
+*/
+#if LUAI_BITSINT >= 32
+#define LUAI_MAXSTACK 1000000
+#else
+#define LUAI_MAXSTACK 15000
+#endif
+
+
+/*
+@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
+** a Lua state with very fast access.
+** CHANGE it if you need a different size.
+*/
+#define LUA_EXTRASPACE (sizeof(void *))
+
+
+/*
+@@ LUA_IDSIZE gives the maximum size for the description of the source
+@@ of a function in debug information.
+** CHANGE it if you want a different size.
+*/
+#define LUA_IDSIZE 60
+
+
+/*
+@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+** CHANGE it if it uses too much C-stack space. (For long double,
+** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a
+** smaller buffer would force a memory allocation for each call to
+** 'string.format'.)
+*/
+#if defined(LUA_FLOAT_LONGDOUBLE)
+#define LUAL_BUFFERSIZE 8192
+#else
+#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
+#endif
+
+/* }================================================================== */
+
+
+/*
+@@ LUA_QL describes how error messages quote program elements.
+** Lua does not use these macros anymore; they are here for
+** compatibility only.
+*/
+#define LUA_QL(x) "'" x "'"
+#define LUA_QS LUA_QL("%s")
+
+
+
+
+/* =================================================================== */
+
+/*
+** Local configuration. You can use this space to add your redefinitions
+** without modifying the main part of the file.
+*/
+
+
+
+
+
+#endif
+
diff --git a/external/lua-5.3.3/src/lualib.h b/external/lua-5.3.3/src/lualib.h
new file mode 100644
index 0000000..5165c0f
--- /dev/null
+++ b/external/lua-5.3.3/src/lualib.h
@@ -0,0 +1,58 @@
+/*
+** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $
+** Lua standard libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lualib_h
+#define lualib_h
+
+#include "lua.h"
+
+
+
+LUAMOD_API int (luaopen_base) (lua_State *L);
+
+#define LUA_COLIBNAME "coroutine"
+LUAMOD_API int (luaopen_coroutine) (lua_State *L);
+
+#define LUA_TABLIBNAME "table"
+LUAMOD_API int (luaopen_table) (lua_State *L);
+
+#define LUA_IOLIBNAME "io"
+LUAMOD_API int (luaopen_io) (lua_State *L);
+
+#define LUA_OSLIBNAME "os"
+LUAMOD_API int (luaopen_os) (lua_State *L);
+
+#define LUA_STRLIBNAME "string"
+LUAMOD_API int (luaopen_string) (lua_State *L);
+
+#define LUA_UTF8LIBNAME "utf8"
+LUAMOD_API int (luaopen_utf8) (lua_State *L);
+
+#define LUA_BITLIBNAME "bit32"
+LUAMOD_API int (luaopen_bit32) (lua_State *L);
+
+#define LUA_MATHLIBNAME "math"
+LUAMOD_API int (luaopen_math) (lua_State *L);
+
+#define LUA_DBLIBNAME "debug"
+LUAMOD_API int (luaopen_debug) (lua_State *L);
+
+#define LUA_LOADLIBNAME "package"
+LUAMOD_API int (luaopen_package) (lua_State *L);
+
+
+/* open all previous libraries */
+LUALIB_API void (luaL_openlibs) (lua_State *L);
+
+
+
+#if !defined(lua_assert)
+#define lua_assert(x) ((void)0)
+#endif
+
+
+#endif
diff --git a/external/lua-5.3.3/src/lundump.c b/external/lua-5.3.3/src/lundump.c
new file mode 100644
index 0000000..4080af9
--- /dev/null
+++ b/external/lua-5.3.3/src/lundump.c
@@ -0,0 +1,279 @@
+/*
+** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp $
+** load precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#define lundump_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <string.h>
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstring.h"
+#include "lundump.h"
+#include "lzio.h"
+
+
+#if !defined(luai_verifycode)
+#define luai_verifycode(L,b,f) /* empty */
+#endif
+
+
+typedef struct {
+ lua_State *L;
+ ZIO *Z;
+ const char *name;
+} LoadState;
+
+
+static l_noret error(LoadState *S, const char *why) {
+ luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why);
+ luaD_throw(S->L, LUA_ERRSYNTAX);
+}
+
+
+/*
+** All high-level loads go through LoadVector; you can change it to
+** adapt to the endianness of the input
+*/
+#define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0]))
+
+static void LoadBlock (LoadState *S, void *b, size_t size) {
+ if (luaZ_read(S->Z, b, size) != 0)
+ error(S, "truncated");
+}
+
+
+#define LoadVar(S,x) LoadVector(S,&x,1)
+
+
+static lu_byte LoadByte (LoadState *S) {
+ lu_byte x;
+ LoadVar(S, x);
+ return x;
+}
+
+
+static int LoadInt (LoadState *S) {
+ int x;
+ LoadVar(S, x);
+ return x;
+}
+
+
+static lua_Number LoadNumber (LoadState *S) {
+ lua_Number x;
+ LoadVar(S, x);
+ return x;
+}
+
+
+static lua_Integer LoadInteger (LoadState *S) {
+ lua_Integer x;
+ LoadVar(S, x);
+ return x;
+}
+
+
+static TString *LoadString (LoadState *S) {
+ size_t size = LoadByte(S);
+ if (size == 0xFF)
+ LoadVar(S, size);
+ if (size == 0)
+ return NULL;
+ else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
+ char buff[LUAI_MAXSHORTLEN];
+ LoadVector(S, buff, size);
+ return luaS_newlstr(S->L, buff, size);
+ }
+ else { /* long string */
+ TString *ts = luaS_createlngstrobj(S->L, size);
+ LoadVector(S, getstr(ts), size); /* load directly in final place */
+ return ts;
+ }
+}
+
+
+static void LoadCode (LoadState *S, Proto *f) {
+ int n = LoadInt(S);
+ f->code = luaM_newvector(S->L, n, Instruction);
+ f->sizecode = n;
+ LoadVector(S, f->code, n);
+}
+
+
+static void LoadFunction(LoadState *S, Proto *f, TString *psource);
+
+
+static void LoadConstants (LoadState *S, Proto *f) {
+ int i;
+ int n = LoadInt(S);
+ f->k = luaM_newvector(S->L, n, TValue);
+ f->sizek = n;
+ for (i = 0; i < n; i++)
+ setnilvalue(&f->k[i]);
+ for (i = 0; i < n; i++) {
+ TValue *o = &f->k[i];
+ int t = LoadByte(S);
+ switch (t) {
+ case LUA_TNIL:
+ setnilvalue(o);
+ break;
+ case LUA_TBOOLEAN:
+ setbvalue(o, LoadByte(S));
+ break;
+ case LUA_TNUMFLT:
+ setfltvalue(o, LoadNumber(S));
+ break;
+ case LUA_TNUMINT:
+ setivalue(o, LoadInteger(S));
+ break;
+ case LUA_TSHRSTR:
+ case LUA_TLNGSTR:
+ setsvalue2n(S->L, o, LoadString(S));
+ break;
+ default:
+ lua_assert(0);
+ }
+ }
+}
+
+
+static void LoadProtos (LoadState *S, Proto *f) {
+ int i;
+ int n = LoadInt(S);
+ f->p = luaM_newvector(S->L, n, Proto *);
+ f->sizep = n;
+ for (i = 0; i < n; i++)
+ f->p[i] = NULL;
+ for (i = 0; i < n; i++) {
+ f->p[i] = luaF_newproto(S->L);
+ LoadFunction(S, f->p[i], f->source);
+ }
+}
+
+
+static void LoadUpvalues (LoadState *S, Proto *f) {
+ int i, n;
+ n = LoadInt(S);
+ f->upvalues = luaM_newvector(S->L, n, Upvaldesc);
+ f->sizeupvalues = n;
+ for (i = 0; i < n; i++)
+ f->upvalues[i].name = NULL;
+ for (i = 0; i < n; i++) {
+ f->upvalues[i].instack = LoadByte(S);
+ f->upvalues[i].idx = LoadByte(S);
+ }
+}
+
+
+static void LoadDebug (LoadState *S, Proto *f) {
+ int i, n;
+ n = LoadInt(S);
+ f->lineinfo = luaM_newvector(S->L, n, int);
+ f->sizelineinfo = n;
+ LoadVector(S, f->lineinfo, n);
+ n = LoadInt(S);
+ f->locvars = luaM_newvector(S->L, n, LocVar);
+ f->sizelocvars = n;
+ for (i = 0; i < n; i++)
+ f->locvars[i].varname = NULL;
+ for (i = 0; i < n; i++) {
+ f->locvars[i].varname = LoadString(S);
+ f->locvars[i].startpc = LoadInt(S);
+ f->locvars[i].endpc = LoadInt(S);
+ }
+ n = LoadInt(S);
+ for (i = 0; i < n; i++)
+ f->upvalues[i].name = LoadString(S);
+}
+
+
+static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
+ f->source = LoadString(S);
+ if (f->source == NULL) /* no source in dump? */
+ f->source = psource; /* reuse parent's source */
+ f->linedefined = LoadInt(S);
+ f->lastlinedefined = LoadInt(S);
+ f->numparams = LoadByte(S);
+ f->is_vararg = LoadByte(S);
+ f->maxstacksize = LoadByte(S);
+ LoadCode(S, f);
+ LoadConstants(S, f);
+ LoadUpvalues(S, f);
+ LoadProtos(S, f);
+ LoadDebug(S, f);
+}
+
+
+static void checkliteral (LoadState *S, const char *s, const char *msg) {
+ char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
+ size_t len = strlen(s);
+ LoadVector(S, buff, len);
+ if (memcmp(s, buff, len) != 0)
+ error(S, msg);
+}
+
+
+static void fchecksize (LoadState *S, size_t size, const char *tname) {
+ if (LoadByte(S) != size)
+ error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname));
+}
+
+
+#define checksize(S,t) fchecksize(S,sizeof(t),#t)
+
+static void checkHeader (LoadState *S) {
+ checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */
+ if (LoadByte(S) != LUAC_VERSION)
+ error(S, "version mismatch in");
+ if (LoadByte(S) != LUAC_FORMAT)
+ error(S, "format mismatch in");
+ checkliteral(S, LUAC_DATA, "corrupted");
+ checksize(S, int);
+ checksize(S, size_t);
+ checksize(S, Instruction);
+ checksize(S, lua_Integer);
+ checksize(S, lua_Number);
+ if (LoadInteger(S) != LUAC_INT)
+ error(S, "endianness mismatch in");
+ if (LoadNumber(S) != LUAC_NUM)
+ error(S, "float format mismatch in");
+}
+
+
+/*
+** load precompiled chunk
+*/
+LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
+ LoadState S;
+ LClosure *cl;
+ if (*name == '@' || *name == '=')
+ S.name = name + 1;
+ else if (*name == LUA_SIGNATURE[0])
+ S.name = "binary string";
+ else
+ S.name = name;
+ S.L = L;
+ S.Z = Z;
+ checkHeader(&S);
+ cl = luaF_newLclosure(L, LoadByte(&S));
+ setclLvalue(L, L->top, cl);
+ luaD_inctop(L);
+ cl->p = luaF_newproto(L);
+ LoadFunction(&S, cl->p, NULL);
+ lua_assert(cl->nupvalues == cl->p->sizeupvalues);
+ luai_verifycode(L, buff, cl->p);
+ return cl;
+}
+
diff --git a/external/lua-5.3.3/src/lundump.h b/external/lua-5.3.3/src/lundump.h
new file mode 100644
index 0000000..aa5cc82
--- /dev/null
+++ b/external/lua-5.3.3/src/lundump.h
@@ -0,0 +1,32 @@
+/*
+** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $
+** load precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lundump_h
+#define lundump_h
+
+#include "llimits.h"
+#include "lobject.h"
+#include "lzio.h"
+
+
+/* data to catch conversion errors */
+#define LUAC_DATA "\x19\x93\r\n\x1a\n"
+
+#define LUAC_INT 0x5678
+#define LUAC_NUM cast_num(370.5)
+
+#define MYINT(s) (s[0]-'0')
+#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
+#define LUAC_FORMAT 0 /* this is the official format */
+
+/* load one chunk; from lundump.c */
+LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name);
+
+/* dump one chunk; from ldump.c */
+LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
+ void* data, int strip);
+
+#endif
diff --git a/external/lua-5.3.3/src/lutf8lib.c b/external/lua-5.3.3/src/lutf8lib.c
new file mode 100644
index 0000000..9042582
--- /dev/null
+++ b/external/lua-5.3.3/src/lutf8lib.c
@@ -0,0 +1,256 @@
+/*
+** $Id: lutf8lib.c,v 1.15 2015/03/28 19:16:55 roberto Exp $
+** Standard library for UTF-8 manipulation
+** See Copyright Notice in lua.h
+*/
+
+#define lutf8lib_c
+#define LUA_LIB
+
+#include "lprefix.h"
+
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+#define MAXUNICODE 0x10FFFF
+
+#define iscont(p) ((*(p) & 0xC0) == 0x80)
+
+
+/* from strlib */
+/* translate a relative string position: negative means back from end */
+static lua_Integer u_posrelat (lua_Integer pos, size_t len) {
+ if (pos >= 0) return pos;
+ else if (0u - (size_t)pos > len) return 0;
+ else return (lua_Integer)len + pos + 1;
+}
+
+
+/*
+** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid.
+*/
+static const char *utf8_decode (const char *o, int *val) {
+ static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF};
+ const unsigned char *s = (const unsigned char *)o;
+ unsigned int c = s[0];
+ unsigned int res = 0; /* final result */
+ if (c < 0x80) /* ascii? */
+ res = c;
+ else {
+ int count = 0; /* to count number of continuation bytes */
+ while (c & 0x40) { /* still have continuation bytes? */
+ int cc = s[++count]; /* read next byte */
+ if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
+ return NULL; /* invalid byte sequence */
+ res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
+ c <<= 1; /* to test next bit */
+ }
+ res |= ((c & 0x7F) << (count * 5)); /* add first byte */
+ if (count > 3 || res > MAXUNICODE || res <= limits[count])
+ return NULL; /* invalid byte sequence */
+ s += count; /* skip continuation bytes read */
+ }
+ if (val) *val = res;
+ return (const char *)s + 1; /* +1 to include first byte */
+}
+
+
+/*
+** utf8len(s [, i [, j]]) --> number of characters that start in the
+** range [i,j], or nil + current position if 's' is not well formed in
+** that interval
+*/
+static int utflen (lua_State *L) {
+ int n = 0;
+ size_t len;
+ const char *s = luaL_checklstring(L, 1, &len);
+ lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len);
+ lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len);
+ luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2,
+ "initial position out of string");
+ luaL_argcheck(L, --posj < (lua_Integer)len, 3,
+ "final position out of string");
+ while (posi <= posj) {
+ const char *s1 = utf8_decode(s + posi, NULL);
+ if (s1 == NULL) { /* conversion error? */
+ lua_pushnil(L); /* return nil ... */
+ lua_pushinteger(L, posi + 1); /* ... and current position */
+ return 2;
+ }
+ posi = s1 - s;
+ n++;
+ }
+ lua_pushinteger(L, n);
+ return 1;
+}
+
+
+/*
+** codepoint(s, [i, [j]]) -> returns codepoints for all characters
+** that start in the range [i,j]
+*/
+static int codepoint (lua_State *L) {
+ size_t len;
+ const char *s = luaL_checklstring(L, 1, &len);
+ lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len);
+ lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len);
+ int n;
+ const char *se;
+ luaL_argcheck(L, posi >= 1, 2, "out of range");
+ luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range");
+ if (posi > pose) return 0; /* empty interval; return no values */
+ if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */
+ return luaL_error(L, "string slice too long");
+ n = (int)(pose - posi) + 1;
+ luaL_checkstack(L, n, "string slice too long");
+ n = 0;
+ se = s + pose;
+ for (s += posi - 1; s < se;) {
+ int code;
+ s = utf8_decode(s, &code);
+ if (s == NULL)
+ return luaL_error(L, "invalid UTF-8 code");
+ lua_pushinteger(L, code);
+ n++;
+ }
+ return n;
+}
+
+
+static void pushutfchar (lua_State *L, int arg) {
+ lua_Integer code = luaL_checkinteger(L, arg);
+ luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range");
+ lua_pushfstring(L, "%U", (long)code);
+}
+
+
+/*
+** utfchar(n1, n2, ...) -> char(n1)..char(n2)...
+*/
+static int utfchar (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ if (n == 1) /* optimize common case of single char */
+ pushutfchar(L, 1);
+ else {
+ int i;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ for (i = 1; i <= n; i++) {
+ pushutfchar(L, i);
+ luaL_addvalue(&b);
+ }
+ luaL_pushresult(&b);
+ }
+ return 1;
+}
+
+
+/*
+** offset(s, n, [i]) -> index where n-th character counting from
+** position 'i' starts; 0 means character at 'i'.
+*/
+static int byteoffset (lua_State *L) {
+ size_t len;
+ const char *s = luaL_checklstring(L, 1, &len);
+ lua_Integer n = luaL_checkinteger(L, 2);
+ lua_Integer posi = (n >= 0) ? 1 : len + 1;
+ posi = u_posrelat(luaL_optinteger(L, 3, posi), len);
+ luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3,
+ "position out of range");
+ if (n == 0) {
+ /* find beginning of current byte sequence */
+ while (posi > 0 && iscont(s + posi)) posi--;
+ }
+ else {
+ if (iscont(s + posi))
+ luaL_error(L, "initial position is a continuation byte");
+ if (n < 0) {
+ while (n < 0 && posi > 0) { /* move back */
+ do { /* find beginning of previous character */
+ posi--;
+ } while (posi > 0 && iscont(s + posi));
+ n++;
+ }
+ }
+ else {
+ n--; /* do not move for 1st character */
+ while (n > 0 && posi < (lua_Integer)len) {
+ do { /* find beginning of next character */
+ posi++;
+ } while (iscont(s + posi)); /* (cannot pass final '\0') */
+ n--;
+ }
+ }
+ }
+ if (n == 0) /* did it find given character? */
+ lua_pushinteger(L, posi + 1);
+ else /* no such character */
+ lua_pushnil(L);
+ return 1;
+}
+
+
+static int iter_aux (lua_State *L) {
+ size_t len;
+ const char *s = luaL_checklstring(L, 1, &len);
+ lua_Integer n = lua_tointeger(L, 2) - 1;
+ if (n < 0) /* first iteration? */
+ n = 0; /* start from here */
+ else if (n < (lua_Integer)len) {
+ n++; /* skip current byte */
+ while (iscont(s + n)) n++; /* and its continuations */
+ }
+ if (n >= (lua_Integer)len)
+ return 0; /* no more codepoints */
+ else {
+ int code;
+ const char *next = utf8_decode(s + n, &code);
+ if (next == NULL || iscont(next))
+ return luaL_error(L, "invalid UTF-8 code");
+ lua_pushinteger(L, n + 1);
+ lua_pushinteger(L, code);
+ return 2;
+ }
+}
+
+
+static int iter_codes (lua_State *L) {
+ luaL_checkstring(L, 1);
+ lua_pushcfunction(L, iter_aux);
+ lua_pushvalue(L, 1);
+ lua_pushinteger(L, 0);
+ return 3;
+}
+
+
+/* pattern to match a single UTF-8 character */
+#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*"
+
+
+static const luaL_Reg funcs[] = {
+ {"offset", byteoffset},
+ {"codepoint", codepoint},
+ {"char", utfchar},
+ {"len", utflen},
+ {"codes", iter_codes},
+ /* placeholders */
+ {"charpattern", NULL},
+ {NULL, NULL}
+};
+
+
+LUAMOD_API int luaopen_utf8 (lua_State *L) {
+ luaL_newlib(L, funcs);
+ lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1);
+ lua_setfield(L, -2, "charpattern");
+ return 1;
+}
+
diff --git a/external/lua-5.3.3/src/lvm.c b/external/lua-5.3.3/src/lvm.c
new file mode 100644
index 0000000..84ade6b
--- /dev/null
+++ b/external/lua-5.3.3/src/lvm.c
@@ -0,0 +1,1322 @@
+/*
+** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $
+** Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+#define lvm_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lvm.h"
+
+
+/* limit for table tag-method chains (to avoid loops) */
+#define MAXTAGLOOP 2000
+
+
+
+/*
+** 'l_intfitsf' checks whether a given integer can be converted to a
+** float without rounding. Used in comparisons. Left undefined if
+** all integers fit in a float precisely.
+*/
+#if !defined(l_intfitsf)
+
+/* number of bits in the mantissa of a float */
+#define NBM (l_mathlim(MANT_DIG))
+
+/*
+** Check whether some integers may not fit in a float, that is, whether
+** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger).
+** (The shifts are done in parts to avoid shifting by more than the size
+** of an integer. In a worst case, NBM == 113 for long double and
+** sizeof(integer) == 32.)
+*/
+#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \
+ >> (NBM - (3 * (NBM / 4)))) > 0
+
+#define l_intfitsf(i) \
+ (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM))
+
+#endif
+
+#endif
+
+
+
+/*
+** Try to convert a value to a float. The float case is already handled
+** by the macro 'tonumber'.
+*/
+int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
+ TValue v;
+ if (ttisinteger(obj)) {
+ *n = cast_num(ivalue(obj));
+ return 1;
+ }
+ else if (cvt2num(obj) && /* string convertible to number? */
+ luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
+ *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */
+ return 1;
+ }
+ else
+ return 0; /* conversion failed */
+}
+
+
+/*
+** try to convert a value to an integer, rounding according to 'mode':
+** mode == 0: accepts only integral values
+** mode == 1: takes the floor of the number
+** mode == 2: takes the ceil of the number
+*/
+int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
+ TValue v;
+ again:
+ if (ttisfloat(obj)) {
+ lua_Number n = fltvalue(obj);
+ lua_Number f = l_floor(n);
+ if (n != f) { /* not an integral value? */
+ if (mode == 0) return 0; /* fails if mode demands integral value */
+ else if (mode > 1) /* needs ceil? */
+ f += 1; /* convert floor to ceil (remember: n != f) */
+ }
+ return lua_numbertointeger(f, p);
+ }
+ else if (ttisinteger(obj)) {
+ *p = ivalue(obj);
+ return 1;
+ }
+ else if (cvt2num(obj) &&
+ luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
+ obj = &v;
+ goto again; /* convert result from 'luaO_str2num' to an integer */
+ }
+ return 0; /* conversion failed */
+}
+
+
+/*
+** Try to convert a 'for' limit to an integer, preserving the
+** semantics of the loop.
+** (The following explanation assumes a non-negative step; it is valid
+** for negative steps mutatis mutandis.)
+** If the limit can be converted to an integer, rounding down, that is
+** it.
+** Otherwise, check whether the limit can be converted to a number. If
+** the number is too large, it is OK to set the limit as LUA_MAXINTEGER,
+** which means no limit. If the number is too negative, the loop
+** should not run, because any initial integer value is larger than the
+** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects
+** the extreme case when the initial value is LUA_MININTEGER, in which
+** case the LUA_MININTEGER limit would still run the loop once.
+*/
+static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
+ int *stopnow) {
+ *stopnow = 0; /* usually, let loops run */
+ if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */
+ lua_Number n; /* try to convert to float */
+ if (!tonumber(obj, &n)) /* cannot convert to float? */
+ return 0; /* not a number */
+ if (luai_numlt(0, n)) { /* if true, float is larger than max integer */
+ *p = LUA_MAXINTEGER;
+ if (step < 0) *stopnow = 1;
+ }
+ else { /* float is smaller than min integer */
+ *p = LUA_MININTEGER;
+ if (step >= 0) *stopnow = 1;
+ }
+ }
+ return 1;
+}
+
+
+/*
+** Finish the table access 'val = t[key]'.
+** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
+** t[k] entry (which must be nil).
+*/
+void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
+ const TValue *slot) {
+ int loop; /* counter to avoid infinite loops */
+ const TValue *tm; /* metamethod */
+ for (loop = 0; loop < MAXTAGLOOP; loop++) {
+ if (slot == NULL) { /* 't' is not a table? */
+ lua_assert(!ttistable(t));
+ tm = luaT_gettmbyobj(L, t, TM_INDEX);
+ if (ttisnil(tm))
+ luaG_typeerror(L, t, "index"); /* no metamethod */
+ /* else will try the metamethod */
+ }
+ else { /* 't' is a table */
+ lua_assert(ttisnil(slot));
+ tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
+ if (tm == NULL) { /* no metamethod? */
+ setnilvalue(val); /* result is nil */
+ return;
+ }
+ /* else will try the metamethod */
+ }
+ if (ttisfunction(tm)) { /* is metamethod a function? */
+ luaT_callTM(L, tm, t, key, val, 1); /* call it */
+ return;
+ }
+ t = tm; /* else try to access 'tm[key]' */
+ if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */
+ setobj2s(L, val, slot); /* done */
+ return;
+ }
+ /* else repeat (tail call 'luaV_finishget') */
+ }
+ luaG_runerror(L, "'__index' chain too long; possible loop");
+}
+
+
+/*
+** Finish a table assignment 't[key] = val'.
+** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points
+** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
+** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset'
+** would have done the job.)
+*/
+void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
+ StkId val, const TValue *slot) {
+ int loop; /* counter to avoid infinite loops */
+ for (loop = 0; loop < MAXTAGLOOP; loop++) {
+ const TValue *tm; /* '__newindex' metamethod */
+ if (slot != NULL) { /* is 't' a table? */
+ Table *h = hvalue(t); /* save 't' table */
+ lua_assert(ttisnil(slot)); /* old value must be nil */
+ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
+ if (tm == NULL) { /* no metamethod? */
+ if (slot == luaO_nilobject) /* no previous entry? */
+ slot = luaH_newkey(L, h, key); /* create one */
+ /* no metamethod and (now) there is an entry with given key */
+ setobj2t(L, cast(TValue *, slot), val); /* set its new value */
+ invalidateTMcache(h);
+ luaC_barrierback(L, h, val);
+ return;
+ }
+ /* else will try the metamethod */
+ }
+ else { /* not a table; check metamethod */
+ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
+ luaG_typeerror(L, t, "index");
+ }
+ /* try the metamethod */
+ if (ttisfunction(tm)) {
+ luaT_callTM(L, tm, t, key, val, 0);
+ return;
+ }
+ t = tm; /* else repeat assignment over 'tm' */
+ if (luaV_fastset(L, t, key, slot, luaH_get, val))
+ return; /* done */
+ /* else loop */
+ }
+ luaG_runerror(L, "'__newindex' chain too long; possible loop");
+}
+
+
+/*
+** Compare two strings 'ls' x 'rs', returning an integer smaller-equal-
+** -larger than zero if 'ls' is smaller-equal-larger than 'rs'.
+** The code is a little tricky because it allows '\0' in the strings
+** and it uses 'strcoll' (to respect locales) for each segments
+** of the strings.
+*/
+static int l_strcmp (const TString *ls, const TString *rs) {
+ const char *l = getstr(ls);
+ size_t ll = tsslen(ls);
+ const char *r = getstr(rs);
+ size_t lr = tsslen(rs);
+ for (;;) { /* for each segment */
+ int temp = strcoll(l, r);
+ if (temp != 0) /* not equal? */
+ return temp; /* done */
+ else { /* strings are equal up to a '\0' */
+ size_t len = strlen(l); /* index of first '\0' in both strings */
+ if (len == lr) /* 'rs' is finished? */
+ return (len == ll) ? 0 : 1; /* check 'ls' */
+ else if (len == ll) /* 'ls' is finished? */
+ return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */
+ /* both strings longer than 'len'; go on comparing after the '\0' */
+ len++;
+ l += len; ll -= len; r += len; lr -= len;
+ }
+ }
+}
+
+
+/*
+** Check whether integer 'i' is less than float 'f'. If 'i' has an
+** exact representation as a float ('l_intfitsf'), compare numbers as
+** floats. Otherwise, if 'f' is outside the range for integers, result
+** is trivial. Otherwise, compare them as integers. (When 'i' has no
+** float representation, either 'f' is "far away" from 'i' or 'f' has
+** no precision left for a fractional part; either way, how 'f' is
+** truncated is irrelevant.) When 'f' is NaN, comparisons must result
+** in false.
+*/
+static int LTintfloat (lua_Integer i, lua_Number f) {
+#if defined(l_intfitsf)
+ if (!l_intfitsf(i)) {
+ if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
+ return 1; /* f >= maxint + 1 > i */
+ else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */
+ return (i < cast(lua_Integer, f)); /* compare them as integers */
+ else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */
+ return 0;
+ }
+#endif
+ return luai_numlt(cast_num(i), f); /* compare them as floats */
+}
+
+
+/*
+** Check whether integer 'i' is less than or equal to float 'f'.
+** See comments on previous function.
+*/
+static int LEintfloat (lua_Integer i, lua_Number f) {
+#if defined(l_intfitsf)
+ if (!l_intfitsf(i)) {
+ if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
+ return 1; /* f >= maxint + 1 > i */
+ else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */
+ return (i <= cast(lua_Integer, f)); /* compare them as integers */
+ else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */
+ return 0;
+ }
+#endif
+ return luai_numle(cast_num(i), f); /* compare them as floats */
+}
+
+
+/*
+** Return 'l < r', for numbers.
+*/
+static int LTnum (const TValue *l, const TValue *r) {
+ if (ttisinteger(l)) {
+ lua_Integer li = ivalue(l);
+ if (ttisinteger(r))
+ return li < ivalue(r); /* both are integers */
+ else /* 'l' is int and 'r' is float */
+ return LTintfloat(li, fltvalue(r)); /* l < r ? */
+ }
+ else {
+ lua_Number lf = fltvalue(l); /* 'l' must be float */
+ if (ttisfloat(r))
+ return luai_numlt(lf, fltvalue(r)); /* both are float */
+ else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
+ return 0; /* NaN < i is always false */
+ else /* without NaN, (l < r) <--> not(r <= l) */
+ return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */
+ }
+}
+
+
+/*
+** Return 'l <= r', for numbers.
+*/
+static int LEnum (const TValue *l, const TValue *r) {
+ if (ttisinteger(l)) {
+ lua_Integer li = ivalue(l);
+ if (ttisinteger(r))
+ return li <= ivalue(r); /* both are integers */
+ else /* 'l' is int and 'r' is float */
+ return LEintfloat(li, fltvalue(r)); /* l <= r ? */
+ }
+ else {
+ lua_Number lf = fltvalue(l); /* 'l' must be float */
+ if (ttisfloat(r))
+ return luai_numle(lf, fltvalue(r)); /* both are float */
+ else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
+ return 0; /* NaN <= i is always false */
+ else /* without NaN, (l <= r) <--> not(r < l) */
+ return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */
+ }
+}
+
+
+/*
+** Main operation less than; return 'l < r'.
+*/
+int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
+ int res;
+ if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
+ return LTnum(l, r);
+ else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
+ return l_strcmp(tsvalue(l), tsvalue(r)) < 0;
+ else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */
+ luaG_ordererror(L, l, r); /* error */
+ return res;
+}
+
+
+/*
+** Main operation less than or equal to; return 'l <= r'. If it needs
+** a metamethod and there is no '__le', try '__lt', based on
+** l <= r iff !(r < l) (assuming a total order). If the metamethod
+** yields during this substitution, the continuation has to know
+** about it (to negate the result of r<l); bit CIST_LEQ in the call
+** status keeps that information.
+*/
+int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
+ int res;
+ if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
+ return LEnum(l, r);
+ else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
+ return l_strcmp(tsvalue(l), tsvalue(r)) <= 0;
+ else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */
+ return res;
+ else { /* try 'lt': */
+ L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
+ res = luaT_callorderTM(L, r, l, TM_LT);
+ L->ci->callstatus ^= CIST_LEQ; /* clear mark */
+ if (res < 0)
+ luaG_ordererror(L, l, r);
+ return !res; /* result is negated */
+ }
+}
+
+
+/*
+** Main operation for equality of Lua values; return 't1 == t2'.
+** L == NULL means raw equality (no metamethods)
+*/
+int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
+ const TValue *tm;
+ if (ttype(t1) != ttype(t2)) { /* not the same variant? */
+ if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER)
+ return 0; /* only numbers can be equal with different variants */
+ else { /* two numbers with different variants */
+ lua_Integer i1, i2; /* compare them as integers */
+ return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2);
+ }
+ }
+ /* values have same type and same variant */
+ switch (ttype(t1)) {
+ case LUA_TNIL: return 1;
+ case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2));
+ case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2));
+ case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */
+ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
+ case LUA_TLCF: return fvalue(t1) == fvalue(t2);
+ case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2));
+ case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2));
+ case LUA_TUSERDATA: {
+ if (uvalue(t1) == uvalue(t2)) return 1;
+ else if (L == NULL) return 0;
+ tm = fasttm(L, uvalue(t1)->metatable, TM_EQ);
+ if (tm == NULL)
+ tm = fasttm(L, uvalue(t2)->metatable, TM_EQ);
+ break; /* will try TM */
+ }
+ case LUA_TTABLE: {
+ if (hvalue(t1) == hvalue(t2)) return 1;
+ else if (L == NULL) return 0;
+ tm = fasttm(L, hvalue(t1)->metatable, TM_EQ);
+ if (tm == NULL)
+ tm = fasttm(L, hvalue(t2)->metatable, TM_EQ);
+ break; /* will try TM */
+ }
+ default:
+ return gcvalue(t1) == gcvalue(t2);
+ }
+ if (tm == NULL) /* no TM? */
+ return 0; /* objects are different */
+ luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */
+ return !l_isfalse(L->top);
+}
+
+
+/* macro used by 'luaV_concat' to ensure that element at 'o' is a string */
+#define tostring(L,o) \
+ (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1)))
+
+#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0)
+
+/* copy strings in stack from top - n up to top - 1 to buffer */
+static void copy2buff (StkId top, int n, char *buff) {
+ size_t tl = 0; /* size already copied */
+ do {
+ size_t l = vslen(top - n); /* length of string being copied */
+ memcpy(buff + tl, svalue(top - n), l * sizeof(char));
+ tl += l;
+ } while (--n > 0);
+}
+
+
+/*
+** Main operation for concatenation: concat 'total' values in the stack,
+** from 'L->top - total' up to 'L->top - 1'.
+*/
+void luaV_concat (lua_State *L, int total) {
+ lua_assert(total >= 2);
+ do {
+ StkId top = L->top;
+ int n = 2; /* number of elements handled in this pass (at least 2) */
+ if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1))
+ luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT);
+ else if (isemptystr(top - 1)) /* second operand is empty? */
+ cast_void(tostring(L, top - 2)); /* result is first operand */
+ else if (isemptystr(top - 2)) { /* first operand is an empty string? */
+ setobjs2s(L, top - 2, top - 1); /* result is second op. */
+ }
+ else {
+ /* at least two non-empty string values; get as many as possible */
+ size_t tl = vslen(top - 1);
+ TString *ts;
+ /* collect total length and number of strings */
+ for (n = 1; n < total && tostring(L, top - n - 1); n++) {
+ size_t l = vslen(top - n - 1);
+ if (l >= (MAX_SIZE/sizeof(char)) - tl)
+ luaG_runerror(L, "string length overflow");
+ tl += l;
+ }
+ if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
+ char buff[LUAI_MAXSHORTLEN];
+ copy2buff(top, n, buff); /* copy strings to buffer */
+ ts = luaS_newlstr(L, buff, tl);
+ }
+ else { /* long string; copy strings directly to final result */
+ ts = luaS_createlngstrobj(L, tl);
+ copy2buff(top, n, getstr(ts));
+ }
+ setsvalue2s(L, top - n, ts); /* create result */
+ }
+ total -= n-1; /* got 'n' strings to create 1 new */
+ L->top -= n-1; /* popped 'n' strings and pushed one */
+ } while (total > 1); /* repeat until only 1 result left */
+}
+
+
+/*
+** Main operation 'ra' = #rb'.
+*/
+void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
+ const TValue *tm;
+ switch (ttype(rb)) {
+ case LUA_TTABLE: {
+ Table *h = hvalue(rb);
+ tm = fasttm(L, h->metatable, TM_LEN);
+ if (tm) break; /* metamethod? break switch to call it */
+ setivalue(ra, luaH_getn(h)); /* else primitive len */
+ return;
+ }
+ case LUA_TSHRSTR: {
+ setivalue(ra, tsvalue(rb)->shrlen);
+ return;
+ }
+ case LUA_TLNGSTR: {
+ setivalue(ra, tsvalue(rb)->u.lnglen);
+ return;
+ }
+ default: { /* try metamethod */
+ tm = luaT_gettmbyobj(L, rb, TM_LEN);
+ if (ttisnil(tm)) /* no metamethod? */
+ luaG_typeerror(L, rb, "get length of");
+ break;
+ }
+ }
+ luaT_callTM(L, tm, rb, rb, ra, 1);
+}
+
+
+/*
+** Integer division; return 'm // n', that is, floor(m/n).
+** C division truncates its result (rounds towards zero).
+** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer,
+** otherwise 'floor(q) == trunc(q) - 1'.
+*/
+lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) {
+ if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */
+ if (n == 0)
+ luaG_runerror(L, "attempt to divide by zero");
+ return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */
+ }
+ else {
+ lua_Integer q = m / n; /* perform C division */
+ if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */
+ q -= 1; /* correct result for different rounding */
+ return q;
+ }
+}
+
+
+/*
+** Integer modulus; return 'm % n'. (Assume that C '%' with
+** negative operands follows C99 behavior. See previous comment
+** about luaV_div.)
+*/
+lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) {
+ if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */
+ if (n == 0)
+ luaG_runerror(L, "attempt to perform 'n%%0'");
+ return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */
+ }
+ else {
+ lua_Integer r = m % n;
+ if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */
+ r += n; /* correct result for different rounding */
+ return r;
+ }
+}
+
+
+/* number of bits in an integer */
+#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
+
+/*
+** Shift left operation. (Shift right just negates 'y'.)
+*/
+lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
+ if (y < 0) { /* shift right? */
+ if (y <= -NBITS) return 0;
+ else return intop(>>, x, -y);
+ }
+ else { /* shift left */
+ if (y >= NBITS) return 0;
+ else return intop(<<, x, y);
+ }
+}
+
+
+/*
+** check whether cached closure in prototype 'p' may be reused, that is,
+** whether there is a cached closure with the same upvalues needed by
+** new closure to be created.
+*/
+static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
+ LClosure *c = p->cache;
+ if (c != NULL) { /* is there a cached closure? */
+ int nup = p->sizeupvalues;
+ Upvaldesc *uv = p->upvalues;
+ int i;
+ for (i = 0; i < nup; i++) { /* check whether it has right upvalues */
+ TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v;
+ if (c->upvals[i]->v != v)
+ return NULL; /* wrong upvalue; cannot reuse closure */
+ }
+ }
+ return c; /* return cached closure (or NULL if no cached closure) */
+}
+
+
+/*
+** create a new Lua closure, push it in the stack, and initialize
+** its upvalues. Note that the closure is not cached if prototype is
+** already black (which means that 'cache' was already cleared by the
+** GC).
+*/
+static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
+ StkId ra) {
+ int nup = p->sizeupvalues;
+ Upvaldesc *uv = p->upvalues;
+ int i;
+ LClosure *ncl = luaF_newLclosure(L, nup);
+ ncl->p = p;
+ setclLvalue(L, ra, ncl); /* anchor new closure in stack */
+ for (i = 0; i < nup; i++) { /* fill in its upvalues */
+ if (uv[i].instack) /* upvalue refers to local variable? */
+ ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx);
+ else /* get upvalue from enclosing function */
+ ncl->upvals[i] = encup[uv[i].idx];
+ ncl->upvals[i]->refcount++;
+ /* new closure is white, so we do not need a barrier here */
+ }
+ if (!isblack(p)) /* cache will not break GC invariant? */
+ p->cache = ncl; /* save it on cache for reuse */
+}
+
+
+/*
+** finish execution of an opcode interrupted by an yield
+*/
+void luaV_finishOp (lua_State *L) {
+ CallInfo *ci = L->ci;
+ StkId base = ci->u.l.base;
+ Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
+ OpCode op = GET_OPCODE(inst);
+ switch (op) { /* finish its execution */
+ case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV:
+ case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR:
+ case OP_MOD: case OP_POW:
+ case OP_UNM: case OP_BNOT: case OP_LEN:
+ case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: {
+ setobjs2s(L, base + GETARG_A(inst), --L->top);
+ break;
+ }
+ case OP_LE: case OP_LT: case OP_EQ: {
+ int res = !l_isfalse(L->top - 1);
+ L->top--;
+ if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
+ lua_assert(op == OP_LE);
+ ci->callstatus ^= CIST_LEQ; /* clear mark */
+ res = !res; /* negate result */
+ }
+ lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
+ if (res != GETARG_A(inst)) /* condition failed? */
+ ci->u.l.savedpc++; /* skip jump instruction */
+ break;
+ }
+ case OP_CONCAT: {
+ StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */
+ int b = GETARG_B(inst); /* first element to concatenate */
+ int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */
+ setobj2s(L, top - 2, top); /* put TM result in proper position */
+ if (total > 1) { /* are there elements to concat? */
+ L->top = top - 1; /* top is one after last element (at top-2) */
+ luaV_concat(L, total); /* concat them (may yield again) */
+ }
+ /* move final result to final position */
+ setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1);
+ L->top = ci->top; /* restore top */
+ break;
+ }
+ case OP_TFORCALL: {
+ lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP);
+ L->top = ci->top; /* correct top */
+ break;
+ }
+ case OP_CALL: {
+ if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */
+ L->top = ci->top; /* adjust results */
+ break;
+ }
+ case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE:
+ break;
+ default: lua_assert(0);
+ }
+}
+
+
+
+
+/*
+** {==================================================================
+** Function 'luaV_execute': main interpreter loop
+** ===================================================================
+*/
+
+
+/*
+** some macros for common tasks in 'luaV_execute'
+*/
+
+
+#define RA(i) (base+GETARG_A(i))
+#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
+#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
+#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
+ ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
+#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
+ ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
+
+
+/* execute a jump instruction */
+#define dojump(ci,i,e) \
+ { int a = GETARG_A(i); \
+ if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \
+ ci->u.l.savedpc += GETARG_sBx(i) + e; }
+
+/* for test instructions, execute the jump instruction that follows it */
+#define donextjump(ci) { i = *ci->u.l.savedpc; dojump(ci, i, 1); }
+
+
+#define Protect(x) { {x;}; base = ci->u.l.base; }
+
+#define checkGC(L,c) \
+ { luaC_condGC(L, L->top = (c), /* limit of live values */ \
+ Protect(L->top = ci->top)); /* restore top */ \
+ luai_threadyield(L); }
+
+
+/* fetch an instruction and prepare its execution */
+#define vmfetch() { \
+ i = *(ci->u.l.savedpc++); \
+ if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
+ Protect(luaG_traceexec(L)); \
+ ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
+ lua_assert(base == ci->u.l.base); \
+ lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
+}
+
+#define vmdispatch(o) switch(o)
+#define vmcase(l) case l:
+#define vmbreak break
+
+
+/*
+** copy of 'luaV_gettable', but protecting the call to potential
+** metamethod (which can reallocate the stack)
+*/
+#define gettableProtected(L,t,k,v) { const TValue *slot; \
+ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
+ else Protect(luaV_finishget(L,t,k,v,slot)); }
+
+
+/* same for 'luaV_settable' */
+#define settableProtected(L,t,k,v) { const TValue *slot; \
+ if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
+ Protect(luaV_finishset(L,t,k,v,slot)); }
+
+
+
+void luaV_execute (lua_State *L) {
+ CallInfo *ci = L->ci;
+ LClosure *cl;
+ TValue *k;
+ StkId base;
+ ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */
+ newframe: /* reentry point when frame changes (call/return) */
+ lua_assert(ci == L->ci);
+ cl = clLvalue(ci->func); /* local reference to function's closure */
+ k = cl->p->k; /* local reference to function's constant table */
+ base = ci->u.l.base; /* local copy of function's base */
+ /* main loop of interpreter */
+ for (;;) {
+ Instruction i;
+ StkId ra;
+ vmfetch();
+ vmdispatch (GET_OPCODE(i)) {
+ vmcase(OP_MOVE) {
+ setobjs2s(L, ra, RB(i));
+ vmbreak;
+ }
+ vmcase(OP_LOADK) {
+ TValue *rb = k + GETARG_Bx(i);
+ setobj2s(L, ra, rb);
+ vmbreak;
+ }
+ vmcase(OP_LOADKX) {
+ TValue *rb;
+ lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
+ rb = k + GETARG_Ax(*ci->u.l.savedpc++);
+ setobj2s(L, ra, rb);
+ vmbreak;
+ }
+ vmcase(OP_LOADBOOL) {
+ setbvalue(ra, GETARG_B(i));
+ if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */
+ vmbreak;
+ }
+ vmcase(OP_LOADNIL) {
+ int b = GETARG_B(i);
+ do {
+ setnilvalue(ra++);
+ } while (b--);
+ vmbreak;
+ }
+ vmcase(OP_GETUPVAL) {
+ int b = GETARG_B(i);
+ setobj2s(L, ra, cl->upvals[b]->v);
+ vmbreak;
+ }
+ vmcase(OP_GETTABUP) {
+ TValue *upval = cl->upvals[GETARG_B(i)]->v;
+ TValue *rc = RKC(i);
+ gettableProtected(L, upval, rc, ra);
+ vmbreak;
+ }
+ vmcase(OP_GETTABLE) {
+ StkId rb = RB(i);
+ TValue *rc = RKC(i);
+ gettableProtected(L, rb, rc, ra);
+ vmbreak;
+ }
+ vmcase(OP_SETTABUP) {
+ TValue *upval = cl->upvals[GETARG_A(i)]->v;
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ settableProtected(L, upval, rb, rc);
+ vmbreak;
+ }
+ vmcase(OP_SETUPVAL) {
+ UpVal *uv = cl->upvals[GETARG_B(i)];
+ setobj(L, uv->v, ra);
+ luaC_upvalbarrier(L, uv);
+ vmbreak;
+ }
+ vmcase(OP_SETTABLE) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ settableProtected(L, ra, rb, rc);
+ vmbreak;
+ }
+ vmcase(OP_NEWTABLE) {
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ Table *t = luaH_new(L);
+ sethvalue(L, ra, t);
+ if (b != 0 || c != 0)
+ luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c));
+ checkGC(L, ra + 1);
+ vmbreak;
+ }
+ vmcase(OP_SELF) {
+ const TValue *aux;
+ StkId rb = RB(i);
+ TValue *rc = RKC(i);
+ TString *key = tsvalue(rc); /* key must be a string */
+ setobjs2s(L, ra + 1, rb);
+ if (luaV_fastget(L, rb, key, aux, luaH_getstr)) {
+ setobj2s(L, ra, aux);
+ }
+ else Protect(luaV_finishget(L, rb, rc, ra, aux));
+ vmbreak;
+ }
+ vmcase(OP_ADD) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Number nb; lua_Number nc;
+ if (ttisinteger(rb) && ttisinteger(rc)) {
+ lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
+ setivalue(ra, intop(+, ib, ic));
+ }
+ else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
+ setfltvalue(ra, luai_numadd(L, nb, nc));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); }
+ vmbreak;
+ }
+ vmcase(OP_SUB) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Number nb; lua_Number nc;
+ if (ttisinteger(rb) && ttisinteger(rc)) {
+ lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
+ setivalue(ra, intop(-, ib, ic));
+ }
+ else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
+ setfltvalue(ra, luai_numsub(L, nb, nc));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); }
+ vmbreak;
+ }
+ vmcase(OP_MUL) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Number nb; lua_Number nc;
+ if (ttisinteger(rb) && ttisinteger(rc)) {
+ lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
+ setivalue(ra, intop(*, ib, ic));
+ }
+ else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
+ setfltvalue(ra, luai_nummul(L, nb, nc));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); }
+ vmbreak;
+ }
+ vmcase(OP_DIV) { /* float division (always with floats) */
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Number nb; lua_Number nc;
+ if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
+ setfltvalue(ra, luai_numdiv(L, nb, nc));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); }
+ vmbreak;
+ }
+ vmcase(OP_BAND) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Integer ib; lua_Integer ic;
+ if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ setivalue(ra, intop(&, ib, ic));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); }
+ vmbreak;
+ }
+ vmcase(OP_BOR) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Integer ib; lua_Integer ic;
+ if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ setivalue(ra, intop(|, ib, ic));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); }
+ vmbreak;
+ }
+ vmcase(OP_BXOR) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Integer ib; lua_Integer ic;
+ if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ setivalue(ra, intop(^, ib, ic));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); }
+ vmbreak;
+ }
+ vmcase(OP_SHL) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Integer ib; lua_Integer ic;
+ if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ setivalue(ra, luaV_shiftl(ib, ic));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); }
+ vmbreak;
+ }
+ vmcase(OP_SHR) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Integer ib; lua_Integer ic;
+ if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ setivalue(ra, luaV_shiftl(ib, -ic));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); }
+ vmbreak;
+ }
+ vmcase(OP_MOD) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Number nb; lua_Number nc;
+ if (ttisinteger(rb) && ttisinteger(rc)) {
+ lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
+ setivalue(ra, luaV_mod(L, ib, ic));
+ }
+ else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
+ lua_Number m;
+ luai_nummod(L, nb, nc, m);
+ setfltvalue(ra, m);
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); }
+ vmbreak;
+ }
+ vmcase(OP_IDIV) { /* floor division */
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Number nb; lua_Number nc;
+ if (ttisinteger(rb) && ttisinteger(rc)) {
+ lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
+ setivalue(ra, luaV_div(L, ib, ic));
+ }
+ else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
+ setfltvalue(ra, luai_numidiv(L, nb, nc));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); }
+ vmbreak;
+ }
+ vmcase(OP_POW) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Number nb; lua_Number nc;
+ if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
+ setfltvalue(ra, luai_numpow(L, nb, nc));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); }
+ vmbreak;
+ }
+ vmcase(OP_UNM) {
+ TValue *rb = RB(i);
+ lua_Number nb;
+ if (ttisinteger(rb)) {
+ lua_Integer ib = ivalue(rb);
+ setivalue(ra, intop(-, 0, ib));
+ }
+ else if (tonumber(rb, &nb)) {
+ setfltvalue(ra, luai_numunm(L, nb));
+ }
+ else {
+ Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM));
+ }
+ vmbreak;
+ }
+ vmcase(OP_BNOT) {
+ TValue *rb = RB(i);
+ lua_Integer ib;
+ if (tointeger(rb, &ib)) {
+ setivalue(ra, intop(^, ~l_castS2U(0), ib));
+ }
+ else {
+ Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT));
+ }
+ vmbreak;
+ }
+ vmcase(OP_NOT) {
+ TValue *rb = RB(i);
+ int res = l_isfalse(rb); /* next assignment may change this value */
+ setbvalue(ra, res);
+ vmbreak;
+ }
+ vmcase(OP_LEN) {
+ Protect(luaV_objlen(L, ra, RB(i)));
+ vmbreak;
+ }
+ vmcase(OP_CONCAT) {
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ StkId rb;
+ L->top = base + c + 1; /* mark the end of concat operands */
+ Protect(luaV_concat(L, c - b + 1));
+ ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */
+ rb = base + b;
+ setobjs2s(L, ra, rb);
+ checkGC(L, (ra >= rb ? ra + 1 : rb));
+ L->top = ci->top; /* restore top */
+ vmbreak;
+ }
+ vmcase(OP_JMP) {
+ dojump(ci, i, 0);
+ vmbreak;
+ }
+ vmcase(OP_EQ) {
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ Protect(
+ if (luaV_equalobj(L, rb, rc) != GETARG_A(i))
+ ci->u.l.savedpc++;
+ else
+ donextjump(ci);
+ )
+ vmbreak;
+ }
+ vmcase(OP_LT) {
+ Protect(
+ if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i))
+ ci->u.l.savedpc++;
+ else
+ donextjump(ci);
+ )
+ vmbreak;
+ }
+ vmcase(OP_LE) {
+ Protect(
+ if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i))
+ ci->u.l.savedpc++;
+ else
+ donextjump(ci);
+ )
+ vmbreak;
+ }
+ vmcase(OP_TEST) {
+ if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra))
+ ci->u.l.savedpc++;
+ else
+ donextjump(ci);
+ vmbreak;
+ }
+ vmcase(OP_TESTSET) {
+ TValue *rb = RB(i);
+ if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb))
+ ci->u.l.savedpc++;
+ else {
+ setobjs2s(L, ra, rb);
+ donextjump(ci);
+ }
+ vmbreak;
+ }
+ vmcase(OP_CALL) {
+ int b = GETARG_B(i);
+ int nresults = GETARG_C(i) - 1;
+ if (b != 0) L->top = ra+b; /* else previous instruction set top */
+ if (luaD_precall(L, ra, nresults)) { /* C function? */
+ if (nresults >= 0)
+ L->top = ci->top; /* adjust results */
+ Protect((void)0); /* update 'base' */
+ }
+ else { /* Lua function */
+ ci = L->ci;
+ goto newframe; /* restart luaV_execute over new Lua function */
+ }
+ vmbreak;
+ }
+ vmcase(OP_TAILCALL) {
+ int b = GETARG_B(i);
+ if (b != 0) L->top = ra+b; /* else previous instruction set top */
+ lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
+ if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */
+ Protect((void)0); /* update 'base' */
+ }
+ else {
+ /* tail call: put called frame (n) in place of caller one (o) */
+ CallInfo *nci = L->ci; /* called frame */
+ CallInfo *oci = nci->previous; /* caller frame */
+ StkId nfunc = nci->func; /* called function */
+ StkId ofunc = oci->func; /* caller function */
+ /* last stack slot filled by 'precall' */
+ StkId lim = nci->u.l.base + getproto(nfunc)->numparams;
+ int aux;
+ /* close all upvalues from previous call */
+ if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);
+ /* move new frame into old one */
+ for (aux = 0; nfunc + aux < lim; aux++)
+ setobjs2s(L, ofunc + aux, nfunc + aux);
+ oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct base */
+ oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */
+ oci->u.l.savedpc = nci->u.l.savedpc;
+ oci->callstatus |= CIST_TAIL; /* function was tail called */
+ ci = L->ci = oci; /* remove new frame */
+ lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);
+ goto newframe; /* restart luaV_execute over new Lua function */
+ }
+ vmbreak;
+ }
+ vmcase(OP_RETURN) {
+ int b = GETARG_B(i);
+ if (cl->p->sizep > 0) luaF_close(L, base);
+ b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
+ if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */
+ return; /* external invocation: return */
+ else { /* invocation via reentry: continue execution */
+ ci = L->ci;
+ if (b) L->top = ci->top;
+ lua_assert(isLua(ci));
+ lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL);
+ goto newframe; /* restart luaV_execute over new Lua function */
+ }
+ }
+ vmcase(OP_FORLOOP) {
+ if (ttisinteger(ra)) { /* integer loop? */
+ lua_Integer step = ivalue(ra + 2);
+ lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */
+ lua_Integer limit = ivalue(ra + 1);
+ if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
+ ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
+ chgivalue(ra, idx); /* update internal index... */
+ setivalue(ra + 3, idx); /* ...and external index */
+ }
+ }
+ else { /* floating loop */
+ lua_Number step = fltvalue(ra + 2);
+ lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */
+ lua_Number limit = fltvalue(ra + 1);
+ if (luai_numlt(0, step) ? luai_numle(idx, limit)
+ : luai_numle(limit, idx)) {
+ ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
+ chgfltvalue(ra, idx); /* update internal index... */
+ setfltvalue(ra + 3, idx); /* ...and external index */
+ }
+ }
+ vmbreak;
+ }
+ vmcase(OP_FORPREP) {
+ TValue *init = ra;
+ TValue *plimit = ra + 1;
+ TValue *pstep = ra + 2;
+ lua_Integer ilimit;
+ int stopnow;
+ if (ttisinteger(init) && ttisinteger(pstep) &&
+ forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) {
+ /* all values are integer */
+ lua_Integer initv = (stopnow ? 0 : ivalue(init));
+ setivalue(plimit, ilimit);
+ setivalue(init, intop(-, initv, ivalue(pstep)));
+ }
+ else { /* try making all values floats */
+ lua_Number ninit; lua_Number nlimit; lua_Number nstep;
+ if (!tonumber(plimit, &nlimit))
+ luaG_runerror(L, "'for' limit must be a number");
+ setfltvalue(plimit, nlimit);
+ if (!tonumber(pstep, &nstep))
+ luaG_runerror(L, "'for' step must be a number");
+ setfltvalue(pstep, nstep);
+ if (!tonumber(init, &ninit))
+ luaG_runerror(L, "'for' initial value must be a number");
+ setfltvalue(init, luai_numsub(L, ninit, nstep));
+ }
+ ci->u.l.savedpc += GETARG_sBx(i);
+ vmbreak;
+ }
+ vmcase(OP_TFORCALL) {
+ StkId cb = ra + 3; /* call base */
+ setobjs2s(L, cb+2, ra+2);
+ setobjs2s(L, cb+1, ra+1);
+ setobjs2s(L, cb, ra);
+ L->top = cb + 3; /* func. + 2 args (state and index) */
+ Protect(luaD_call(L, cb, GETARG_C(i)));
+ L->top = ci->top;
+ i = *(ci->u.l.savedpc++); /* go to next instruction */
+ ra = RA(i);
+ lua_assert(GET_OPCODE(i) == OP_TFORLOOP);
+ goto l_tforloop;
+ }
+ vmcase(OP_TFORLOOP) {
+ l_tforloop:
+ if (!ttisnil(ra + 1)) { /* continue loop? */
+ setobjs2s(L, ra, ra + 1); /* save control variable */
+ ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
+ }
+ vmbreak;
+ }
+ vmcase(OP_SETLIST) {
+ int n = GETARG_B(i);
+ int c = GETARG_C(i);
+ unsigned int last;
+ Table *h;
+ if (n == 0) n = cast_int(L->top - ra) - 1;
+ if (c == 0) {
+ lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
+ c = GETARG_Ax(*ci->u.l.savedpc++);
+ }
+ h = hvalue(ra);
+ last = ((c-1)*LFIELDS_PER_FLUSH) + n;
+ if (last > h->sizearray) /* needs more space? */
+ luaH_resizearray(L, h, last); /* preallocate it at once */
+ for (; n > 0; n--) {
+ TValue *val = ra+n;
+ luaH_setint(L, h, last--, val);
+ luaC_barrierback(L, h, val);
+ }
+ L->top = ci->top; /* correct top (in case of previous open call) */
+ vmbreak;
+ }
+ vmcase(OP_CLOSURE) {
+ Proto *p = cl->p->p[GETARG_Bx(i)];
+ LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */
+ if (ncl == NULL) /* no match? */
+ pushclosure(L, p, cl->upvals, base, ra); /* create a new one */
+ else
+ setclLvalue(L, ra, ncl); /* push cashed closure */
+ checkGC(L, ra + 1);
+ vmbreak;
+ }
+ vmcase(OP_VARARG) {
+ int b = GETARG_B(i) - 1; /* required results */
+ int j;
+ int n = cast_int(base - ci->func) - cl->p->numparams - 1;
+ if (n < 0) /* less arguments than parameters? */
+ n = 0; /* no vararg arguments */
+ if (b < 0) { /* B == 0? */
+ b = n; /* get all var. arguments */
+ Protect(luaD_checkstack(L, n));
+ ra = RA(i); /* previous call may change the stack */
+ L->top = ra + n;
+ }
+ for (j = 0; j < b && j < n; j++)
+ setobjs2s(L, ra + j, base - n + j);
+ for (; j < b; j++) /* complete required results with nil */
+ setnilvalue(ra + j);
+ vmbreak;
+ }
+ vmcase(OP_EXTRAARG) {
+ lua_assert(0);
+ vmbreak;
+ }
+ }
+ }
+}
+
+/* }================================================================== */
+
diff --git a/external/lua-5.3.3/src/lvm.h b/external/lua-5.3.3/src/lvm.h
new file mode 100644
index 0000000..bcf52d2
--- /dev/null
+++ b/external/lua-5.3.3/src/lvm.h
@@ -0,0 +1,113 @@
+/*
+** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp $
+** Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lvm_h
+#define lvm_h
+
+
+#include "ldo.h"
+#include "lobject.h"
+#include "ltm.h"
+
+
+#if !defined(LUA_NOCVTN2S)
+#define cvt2str(o) ttisnumber(o)
+#else
+#define cvt2str(o) 0 /* no conversion from numbers to strings */
+#endif
+
+
+#if !defined(LUA_NOCVTS2N)
+#define cvt2num(o) ttisstring(o)
+#else
+#define cvt2num(o) 0 /* no conversion from strings to numbers */
+#endif
+
+
+/*
+** You can define LUA_FLOORN2I if you want to convert floats to integers
+** by flooring them (instead of raising an error if they are not
+** integral values)
+*/
+#if !defined(LUA_FLOORN2I)
+#define LUA_FLOORN2I 0
+#endif
+
+
+#define tonumber(o,n) \
+ (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
+
+#define tointeger(o,i) \
+ (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
+
+#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
+
+#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)
+
+
+/*
+** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
+** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
+** return 0 (meaning it will have to check metamethod) with 'slot'
+** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
+** 'f' is the raw get function to use.
+*/
+#define luaV_fastget(L,t,k,slot,f) \
+ (!ttistable(t) \
+ ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
+ : (slot = f(hvalue(t), k), /* else, do raw access */ \
+ !ttisnil(slot))) /* result not nil? */
+
+/*
+** standard implementation for 'gettable'
+*/
+#define luaV_gettable(L,t,k,v) { const TValue *slot; \
+ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
+ else luaV_finishget(L,t,k,v,slot); }
+
+
+/*
+** Fast track for set table. If 't' is a table and 't[k]' is not nil,
+** call GC barrier, do a raw 't[k]=v', and return true; otherwise,
+** return false with 'slot' equal to NULL (if 't' is not a table) or
+** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro
+** returns true, there is no need to 'invalidateTMcache', because the
+** call is not creating a new entry.
+*/
+#define luaV_fastset(L,t,k,slot,f,v) \
+ (!ttistable(t) \
+ ? (slot = NULL, 0) \
+ : (slot = f(hvalue(t), k), \
+ ttisnil(slot) ? 0 \
+ : (luaC_barrierback(L, hvalue(t), v), \
+ setobj2t(L, cast(TValue *,slot), v), \
+ 1)))
+
+
+#define luaV_settable(L,t,k,v) { const TValue *slot; \
+ if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
+ luaV_finishset(L,t,k,v,slot); }
+
+
+
+LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
+LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
+LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
+LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
+LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
+LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
+ StkId val, const TValue *slot);
+LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
+ StkId val, const TValue *slot);
+LUAI_FUNC void luaV_finishOp (lua_State *L);
+LUAI_FUNC void luaV_execute (lua_State *L);
+LUAI_FUNC void luaV_concat (lua_State *L, int total);
+LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y);
+LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y);
+LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y);
+LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb);
+
+#endif
diff --git a/external/lua-5.3.3/src/lzio.c b/external/lua-5.3.3/src/lzio.c
new file mode 100644
index 0000000..c9e1f49
--- /dev/null
+++ b/external/lua-5.3.3/src/lzio.c
@@ -0,0 +1,68 @@
+/*
+** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $
+** Buffered streams
+** See Copyright Notice in lua.h
+*/
+
+#define lzio_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <string.h>
+
+#include "lua.h"
+
+#include "llimits.h"
+#include "lmem.h"
+#include "lstate.h"
+#include "lzio.h"
+
+
+int luaZ_fill (ZIO *z) {
+ size_t size;
+ lua_State *L = z->L;
+ const char *buff;
+ lua_unlock(L);
+ buff = z->reader(L, z->data, &size);
+ lua_lock(L);
+ if (buff == NULL || size == 0)
+ return EOZ;
+ z->n = size - 1; /* discount char being returned */
+ z->p = buff;
+ return cast_uchar(*(z->p++));
+}
+
+
+void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) {
+ z->L = L;
+ z->reader = reader;
+ z->data = data;
+ z->n = 0;
+ z->p = NULL;
+}
+
+
+/* --------------------------------------------------------------- read --- */
+size_t luaZ_read (ZIO *z, void *b, size_t n) {
+ while (n) {
+ size_t m;
+ if (z->n == 0) { /* no bytes in buffer? */
+ if (luaZ_fill(z) == EOZ) /* try to read more */
+ return n; /* no more input; return number of missing bytes */
+ else {
+ z->n++; /* luaZ_fill consumed first byte; put it back */
+ z->p--;
+ }
+ }
+ m = (n <= z->n) ? n : z->n; /* min. between n and z->n */
+ memcpy(b, z->p, m);
+ z->n -= m;
+ z->p += m;
+ b = (char *)b + m;
+ n -= m;
+ }
+ return 0;
+}
+
diff --git a/external/lua-5.3.3/src/lzio.h b/external/lua-5.3.3/src/lzio.h
new file mode 100644
index 0000000..e7b6f34
--- /dev/null
+++ b/external/lua-5.3.3/src/lzio.h
@@ -0,0 +1,66 @@
+/*
+** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $
+** Buffered streams
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lzio_h
+#define lzio_h
+
+#include "lua.h"
+
+#include "lmem.h"
+
+
+#define EOZ (-1) /* end of stream */
+
+typedef struct Zio ZIO;
+
+#define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z))
+
+
+typedef struct Mbuffer {
+ char *buffer;
+ size_t n;
+ size_t buffsize;
+} Mbuffer;
+
+#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)
+
+#define luaZ_buffer(buff) ((buff)->buffer)
+#define luaZ_sizebuffer(buff) ((buff)->buffsize)
+#define luaZ_bufflen(buff) ((buff)->n)
+
+#define luaZ_buffremove(buff,i) ((buff)->n -= (i))
+#define luaZ_resetbuffer(buff) ((buff)->n = 0)
+
+
+#define luaZ_resizebuffer(L, buff, size) \
+ ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \
+ (buff)->buffsize, size), \
+ (buff)->buffsize = size)
+
+#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0)
+
+
+LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
+ void *data);
+LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */
+
+
+
+/* --------- Private Part ------------------ */
+
+struct Zio {
+ size_t n; /* bytes still unread */
+ const char *p; /* current position in buffer */
+ lua_Reader reader; /* reader function */
+ void *data; /* additional data */
+ lua_State *L; /* Lua state (for reader) */
+};
+
+
+LUAI_FUNC int luaZ_fill (ZIO *z);
+
+#endif
diff --git a/external/nettle-3.3/CMakeLists.txt b/external/nettle-3.3/CMakeLists.txt
new file mode 100644
index 0000000..72c7f86
--- /dev/null
+++ b/external/nettle-3.3/CMakeLists.txt
@@ -0,0 +1,38 @@
+add_library ( nettle STATIC
+ nettle/bignum.c
+ nettle/bignum-random.c
+ nettle/bignum-random-prime.c
+ nettle/buffer.c
+ nettle/buffer-init.c
+ nettle/gmp-glue.c
+ nettle/mini-gmp.c
+ nettle/pkcs1.c
+ nettle/pkcs1-rsa-sha256.c
+ nettle/realloc.c
+ nettle/rsa.c
+ nettle/rsa2sexp.c
+ nettle/rsa-keygen.c
+ nettle/rsa-sha256-sign.c
+ nettle/rsa-sha256-verify.c
+ nettle/rsa-sign.c
+ nettle/rsa-verify.c
+ nettle/sexp.c
+ nettle/sexp-format.c
+ nettle/sexp2bignum.c
+ nettle/sexp2rsa.c
+ nettle/sha256-compress.c
+ nettle/sha256.c
+ nettle/write-be32.c
+ )
+
+add_definitions (
+ -DNDEBUG
+ -mfpmath=sse
+ -ffast-math
+ )
+include_directories (
+ include
+ )
+
+# command: /usr/bin/clang -Wall -Wextra -DLUA_COMPAT_5_2 -fPIC -fpic -o build/release-darwin-x86_64/nettle/bignum.o -c src/nettle-3.3/nettle/bignum.c
+
diff --git a/external/nettle-3.3/nettle/bignum-random-prime.c b/external/nettle-3.3/nettle/bignum-random-prime.c
new file mode 100644
index 0000000..97d35e4
--- /dev/null
+++ b/external/nettle-3.3/nettle/bignum-random-prime.c
@@ -0,0 +1,533 @@
+/* bignum-random-prime.c
+
+ Generation of random provable primes.
+
+ Copyright (C) 2010, 2013 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef RANDOM_PRIME_VERBOSE
+#define RANDOM_PRIME_VERBOSE 0
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+
+#if RANDOM_PRIME_VERBOSE
+#include <stdio.h>
+#define VERBOSE(x) (fputs((x), stderr))
+#else
+#define VERBOSE(x)
+#endif
+
+#include "bignum.h"
+
+#include "macros.h"
+
+/* Use a table of p_2 = 3 to p_{172} = 1021, used for sieving numbers
+ of up to 20 bits. */
+
+#define NPRIMES 171
+#define TRIAL_DIV_BITS 20
+#define TRIAL_DIV_MASK ((1 << TRIAL_DIV_BITS) - 1)
+
+/* A 20-bit number x is divisible by p iff
+
+ ((x * inverse) & TRIAL_DIV_MASK) <= limit
+*/
+struct trial_div_info {
+ uint32_t inverse; /* p^{-1} (mod 2^20) */
+ uint32_t limit; /* floor( (2^20 - 1) / p) */
+};
+
+static const uint16_t
+primes[NPRIMES] = {
+ 3,5,7,11,13,17,19,23,
+ 29,31,37,41,43,47,53,59,
+ 61,67,71,73,79,83,89,97,
+ 101,103,107,109,113,127,131,137,
+ 139,149,151,157,163,167,173,179,
+ 181,191,193,197,199,211,223,227,
+ 229,233,239,241,251,257,263,269,
+ 271,277,281,283,293,307,311,313,
+ 317,331,337,347,349,353,359,367,
+ 373,379,383,389,397,401,409,419,
+ 421,431,433,439,443,449,457,461,
+ 463,467,479,487,491,499,503,509,
+ 521,523,541,547,557,563,569,571,
+ 577,587,593,599,601,607,613,617,
+ 619,631,641,643,647,653,659,661,
+ 673,677,683,691,701,709,719,727,
+ 733,739,743,751,757,761,769,773,
+ 787,797,809,811,821,823,827,829,
+ 839,853,857,859,863,877,881,883,
+ 887,907,911,919,929,937,941,947,
+ 953,967,971,977,983,991,997,1009,
+ 1013,1019,1021,
+};
+
+static const uint32_t
+prime_square[NPRIMES+1] = {
+ 9,25,49,121,169,289,361,529,
+ 841,961,1369,1681,1849,2209,2809,3481,
+ 3721,4489,5041,5329,6241,6889,7921,9409,
+ 10201,10609,11449,11881,12769,16129,17161,18769,
+ 19321,22201,22801,24649,26569,27889,29929,32041,
+ 32761,36481,37249,38809,39601,44521,49729,51529,
+ 52441,54289,57121,58081,63001,66049,69169,72361,
+ 73441,76729,78961,80089,85849,94249,96721,97969,
+ 100489,109561,113569,120409,121801,124609,128881,134689,
+ 139129,143641,146689,151321,157609,160801,167281,175561,
+ 177241,185761,187489,192721,196249,201601,208849,212521,
+ 214369,218089,229441,237169,241081,249001,253009,259081,
+ 271441,273529,292681,299209,310249,316969,323761,326041,
+ 332929,344569,351649,358801,361201,368449,375769,380689,
+ 383161,398161,410881,413449,418609,426409,434281,436921,
+ 452929,458329,466489,477481,491401,502681,516961,528529,
+ 537289,546121,552049,564001,573049,579121,591361,597529,
+ 619369,635209,654481,657721,674041,677329,683929,687241,
+ 703921,727609,734449,737881,744769,769129,776161,779689,
+ 786769,822649,829921,844561,863041,877969,885481,896809,
+ 908209,935089,942841,954529,966289,982081,994009,1018081,
+ 1026169,1038361,1042441,1L<<20
+};
+
+static const struct trial_div_info
+trial_div_table[NPRIMES] = {
+ {699051,349525},{838861,209715},{748983,149796},{953251,95325},
+ {806597,80659},{61681,61680},{772635,55188},{866215,45590},
+ {180789,36157},{1014751,33825},{793517,28339},{1023001,25575},
+ {48771,24385},{870095,22310},{217629,19784},{710899,17772},
+ {825109,17189},{281707,15650},{502135,14768},{258553,14364},
+ {464559,13273},{934875,12633},{1001449,11781},{172961,10810},
+ {176493,10381},{203607,10180},{568387,9799},{788837,9619},
+ {770193,9279},{1032063,8256},{544299,8004},{619961,7653},
+ {550691,7543},{182973,7037},{229159,6944},{427445,6678},
+ {701195,6432},{370455,6278},{90917,6061},{175739,5857},
+ {585117,5793},{225087,5489},{298817,5433},{228877,5322},
+ {442615,5269},{546651,4969},{244511,4702},{83147,4619},
+ {769261,4578},{841561,4500},{732687,4387},{978961,4350},
+ {133683,4177},{65281,4080},{629943,3986},{374213,3898},
+ {708079,3869},{280125,3785},{641833,3731},{618771,3705},
+ {930477,3578},{778747,3415},{623751,3371},{40201,3350},
+ {122389,3307},{950371,3167},{1042353,3111},{18131,3021},
+ {285429,3004},{549537,2970},{166487,2920},{294287,2857},
+ {919261,2811},{636339,2766},{900735,2737},{118605,2695},
+ {10565,2641},{188273,2614},{115369,2563},{735755,2502},
+ {458285,2490},{914767,2432},{370513,2421},{1027079,2388},
+ {629619,2366},{462401,2335},{649337,2294},{316165,2274},
+ {484655,2264},{65115,2245},{326175,2189},{1016279,2153},
+ {990915,2135},{556859,2101},{462791,2084},{844629,2060},
+ {404537,2012},{457123,2004},{577589,1938},{638347,1916},
+ {892325,1882},{182523,1862},{1002505,1842},{624371,1836},
+ {69057,1817},{210787,1786},{558769,1768},{395623,1750},
+ {992745,1744},{317855,1727},{384877,1710},{372185,1699},
+ {105027,1693},{423751,1661},{408961,1635},{908331,1630},
+ {74551,1620},{36933,1605},{617371,1591},{506045,1586},
+ {24929,1558},{529709,1548},{1042435,1535},{31867,1517},
+ {166037,1495},{928781,1478},{508975,1458},{4327,1442},
+ {779637,1430},{742091,1418},{258263,1411},{879631,1396},
+ {72029,1385},{728905,1377},{589057,1363},{348621,1356},
+ {671515,1332},{710453,1315},{84249,1296},{959363,1292},
+ {685853,1277},{467591,1274},{646643,1267},{683029,1264},
+ {439927,1249},{254461,1229},{660713,1223},{554195,1220},
+ {202911,1215},{753253,1195},{941457,1190},{776635,1187},
+ {509511,1182},{986147,1156},{768879,1151},{699431,1140},
+ {696417,1128},{86169,1119},{808997,1114},{25467,1107},
+ {201353,1100},{708087,1084},{1018339,1079},{341297,1073},
+ {434151,1066},{96287,1058},{950765,1051},{298257,1039},
+ {675933,1035},{167731,1029},{815445,1027},
+};
+
+/* Element j gives the index of the first prime of size 3+j bits */
+static uint8_t
+prime_by_size[9] = {
+ 1,3,5,10,17,30,53,96,171
+};
+
+/* Combined Miller-Rabin test to the base a, and checking the
+ conditions from Pocklington's theorem, nm1dq holds (n-1)/q, with q
+ prime. */
+static int
+miller_rabin_pocklington(mpz_t n, mpz_t nm1, mpz_t nm1dq, mpz_t a)
+{
+ mpz_t r;
+ mpz_t y;
+ int is_prime = 0;
+
+ /* Avoid the mp_bitcnt_t type for compatibility with older GMP
+ versions. */
+ unsigned k;
+ unsigned j;
+
+ VERBOSE(".");
+
+ if (mpz_even_p(n) || mpz_cmp_ui(n, 3) < 0)
+ return 0;
+
+ mpz_init(r);
+ mpz_init(y);
+
+ k = mpz_scan1(nm1, 0);
+ assert(k > 0);
+
+ mpz_fdiv_q_2exp (r, nm1, k);
+
+ mpz_powm(y, a, r, n);
+
+ if (mpz_cmp_ui(y, 1) == 0 || mpz_cmp(y, nm1) == 0)
+ goto passed_miller_rabin;
+
+ for (j = 1; j < k; j++)
+ {
+ mpz_powm_ui (y, y, 2, n);
+
+ if (mpz_cmp_ui (y, 1) == 0)
+ break;
+
+ if (mpz_cmp (y, nm1) == 0)
+ {
+ passed_miller_rabin:
+ /* We know that a^{n-1} = 1 (mod n)
+
+ Remains to check that gcd(a^{(n-1)/q} - 1, n) == 1 */
+ VERBOSE("x");
+
+ mpz_powm(y, a, nm1dq, n);
+ mpz_sub_ui(y, y, 1);
+ mpz_gcd(y, y, n);
+ is_prime = mpz_cmp_ui (y, 1) == 0;
+ VERBOSE(is_prime ? "\n" : "");
+ break;
+ }
+
+ }
+
+ mpz_clear(r);
+ mpz_clear(y);
+
+ return is_prime;
+}
+
+/* The most basic variant of Pocklingtons theorem:
+
+ Assume that q^e | (n-1), with q prime. If we can find an a such that
+
+ a^{n-1} = 1 (mod n)
+ gcd(a^{(n-1)/q} - 1, n) = 1
+
+ then any prime divisor p of n satisfies p = 1 (mod q^e).
+
+ Proof (Cohen, 8.3.2): Assume p is a prime factor of n. The central
+ idea of the proof is to consider the order, modulo p, of a. Denote
+ this by d.
+
+ a^{n-1} = 1 (mod n) implies a^{n-1} = 1 (mod p), hence d | (n-1).
+ Next, the condition gcd(a^{(n-1)/q} - 1, n) = 1 implies that
+ a^{(n-1)/q} != 1, hence d does not divide (n-1)/q. Since q is
+ prime, this means that q^e | d.
+
+ Finally, we have a^{p-1} = 1 (mod p), hence d | (p-1). So q^e | d |
+ (p-1), which gives the desired result: p = 1 (mod q^e).
+
+
+ * Variant, slightly stronger than Fact 4.59, HAC:
+
+ Assume n = 1 + 2rq, q an odd prime, r <= 2q, and
+
+ a^{n-1} = 1 (mod n)
+ gcd(a^{(n-1)/q} - 1, n) = 1
+
+ Then n is prime.
+
+ Proof: By Pocklington's theorem, any prime factor p satisfies p = 1
+ (mod q). Neither 1 or q+1 are primes, hence p >= 1 + 2q. If n is
+ composite, we have n >= (1+2q)^2. But the assumption r <= 2q
+ implies n <= 1 + 4q^2, a contradiction.
+
+ In bits, the requirement is that #n <= 2 #q, then
+
+ r = (n-1)/2q < 2^{#n - #q} <= 2^#q = 2 2^{#q-1}< 2 q
+
+
+ * Another variant with an extra test (Variant of Fact 4.42, HAC):
+
+ Assume n = 1 + 2rq, n odd, q an odd prime, 8 q^3 >= n
+
+ a^{n-1} = 1 (mod n)
+ gcd(a^{(n-1)/q} - 1, n) = 1
+
+ Also let x = floor(r / 2q), y = r mod 2q,
+
+ If y^2 - 4x is not a square, then n is prime.
+
+ Proof (adapted from Maurer, Journal of Cryptology, 8 (1995)):
+
+ Assume n is composite. There are at most two factors, both odd,
+
+ n = (1+2m_1 q)(1+2m_2 q) = 1 + 4 m_1 m_2 q^2 + 2 (m_1 + m_2) q
+
+ where we can assume m_1 >= m_2. Then the bound n <= 8 q^3 implies m_1
+ m_2 < 2q, restricting (m_1, m_2) to the domain 0 < m_2 <
+ sqrt(2q), 0 < m_1 < 2q / m_2.
+
+ We have the bound
+
+ m_1 + m_2 < 2q / m_2 + m_2 <= 2q + 1 (maximum value for m_2 = 1)
+
+ And the case m_1 = 2q, m_2 = 1 can be excluded, because it gives n
+ > 8q^3. So in fact, m_1 + m_2 < 2q.
+
+ Next, write r = (n-1)/2q = 2 m_1 m_2 q + m_1 + m_2.
+
+ If follows that m_1 + m_2 = y and m_1 m_2 = x. m_1 and m_2 are
+ thus the roots of the equation
+
+ m^2 - y m + x = 0
+
+ which has integer roots iff y^2 - 4 x is the square of an integer.
+
+ In bits, the requirement is that #n <= 3 #q, then
+
+ n < 2^#n <= 2^{3 #q} = 8 2^{3 (#q-1)} < 8 q^3
+*/
+
+/* Generate a prime number p of size bits with 2 p0q dividing (p-1).
+ p0 must be of size >= ceil(bits/3). The extra factor q can be
+ omitted (then p0 and p0q should be equal). If top_bits_set is one,
+ the topmost two bits are set to one, suitable for RSA primes. Also
+ returns r = (p-1)/p0q. */
+void
+_nettle_generate_pocklington_prime (mpz_t p, mpz_t r,
+ unsigned bits, int top_bits_set,
+ void *ctx, nettle_random_func *random,
+ const mpz_t p0,
+ const mpz_t q,
+ const mpz_t p0q)
+{
+ mpz_t r_min, r_range, pm1, a, e;
+ int need_square_test;
+ unsigned p0_bits;
+ mpz_t x, y, p04;
+
+ p0_bits = mpz_sizeinbase (p0, 2);
+
+ assert (bits <= 3*p0_bits);
+ assert (bits > p0_bits);
+
+ need_square_test = (bits > 2 * p0_bits);
+
+ mpz_init (r_min);
+ mpz_init (r_range);
+ mpz_init (pm1);
+ mpz_init (a);
+
+ if (need_square_test)
+ {
+ mpz_init (x);
+ mpz_init (y);
+ mpz_init (p04);
+ mpz_mul_2exp (p04, p0, 2);
+ }
+
+ if (q)
+ mpz_init (e);
+
+ if (top_bits_set)
+ {
+ /* i = floor (2^{bits-3} / p0q), then 3I + 3 <= r <= 4I, with I
+ - 2 possible values. */
+ mpz_set_ui (r_min, 1);
+ mpz_mul_2exp (r_min, r_min, bits-3);
+ mpz_fdiv_q (r_min, r_min, p0q);
+ mpz_sub_ui (r_range, r_min, 2);
+ mpz_mul_ui (r_min, r_min, 3);
+ mpz_add_ui (r_min, r_min, 3);
+ }
+ else
+ {
+ /* i = floor (2^{bits-2} / p0q), I + 1 <= r <= 2I */
+ mpz_set_ui (r_range, 1);
+ mpz_mul_2exp (r_range, r_range, bits-2);
+ mpz_fdiv_q (r_range, r_range, p0q);
+ mpz_add_ui (r_min, r_range, 1);
+ }
+
+ for (;;)
+ {
+ uint8_t buf[1];
+
+ nettle_mpz_random (r, ctx, random, r_range);
+ mpz_add (r, r, r_min);
+
+ /* Set p = 2*r*p0q + 1 */
+ mpz_mul_2exp(r, r, 1);
+ mpz_mul (pm1, r, p0q);
+ mpz_add_ui (p, pm1, 1);
+
+ assert(mpz_sizeinbase(p, 2) == bits);
+
+ /* Should use GMP trial division interface when that
+ materializes, we don't need any testing beyond trial
+ division. */
+ if (!mpz_probab_prime_p (p, 1))
+ continue;
+
+ random(ctx, sizeof(buf), buf);
+
+ mpz_set_ui (a, buf[0] + 2);
+
+ if (q)
+ {
+ mpz_mul (e, r, q);
+ if (!miller_rabin_pocklington(p, pm1, e, a))
+ continue;
+
+ if (need_square_test)
+ {
+ /* Our e corresponds to 2r in the theorem */
+ mpz_tdiv_qr (x, y, e, p04);
+ goto square_test;
+ }
+ }
+ else
+ {
+ if (!miller_rabin_pocklington(p, pm1, r, a))
+ continue;
+ if (need_square_test)
+ {
+ mpz_tdiv_qr (x, y, r, p04);
+ square_test:
+ /* We have r' = 2r, x = floor (r/2q) = floor(r'/2q),
+ and y' = r' - x 4q = 2 (r - x 2q) = 2y.
+
+ Then y^2 - 4x is a square iff y'^2 - 16 x is a
+ square. */
+
+ mpz_mul (y, y, y);
+ mpz_submul_ui (y, x, 16);
+ if (mpz_perfect_square_p (y))
+ continue;
+ }
+ }
+
+ /* If we passed all the tests, we have found a prime. */
+ break;
+ }
+ mpz_clear (r_min);
+ mpz_clear (r_range);
+ mpz_clear (pm1);
+ mpz_clear (a);
+
+ if (need_square_test)
+ {
+ mpz_clear (x);
+ mpz_clear (y);
+ mpz_clear (p04);
+ }
+ if (q)
+ mpz_clear (e);
+}
+
+/* Generate random prime of a given size. Maurer's algorithm (Alg.
+ 6.42 Handbook of applied cryptography), but with ratio = 1/2 (like
+ the variant in fips186-3). */
+void
+nettle_random_prime(mpz_t p, unsigned bits, int top_bits_set,
+ void *random_ctx, nettle_random_func *random,
+ void *progress_ctx, nettle_progress_func *progress)
+{
+ assert (bits >= 3);
+ if (bits <= 10)
+ {
+ unsigned first;
+ unsigned choices;
+ uint8_t buf;
+
+ assert (!top_bits_set);
+
+ random (random_ctx, sizeof(buf), &buf);
+
+ first = prime_by_size[bits-3];
+ choices = prime_by_size[bits-2] - first;
+
+ mpz_set_ui (p, primes[first + buf % choices]);
+ }
+ else if (bits <= 20)
+ {
+ unsigned long highbit;
+ uint8_t buf[3];
+ unsigned long x;
+ unsigned j;
+
+ assert (!top_bits_set);
+
+ highbit = 1L << (bits - 1);
+
+ again:
+ random (random_ctx, sizeof(buf), buf);
+ x = READ_UINT24(buf);
+ x &= (highbit - 1);
+ x |= highbit | 1;
+
+ for (j = 0; prime_square[j] <= x; j++)
+ {
+ unsigned q = x * trial_div_table[j].inverse & TRIAL_DIV_MASK;
+ if (q <= trial_div_table[j].limit)
+ goto again;
+ }
+ mpz_set_ui (p, x);
+ }
+ else
+ {
+ mpz_t q, r;
+
+ mpz_init (q);
+ mpz_init (r);
+
+ /* Bit size ceil(k/2) + 1, slightly larger than used in Alg. 4.62
+ in Handbook of Applied Cryptography (which seems to be
+ incorrect for odd k). */
+ nettle_random_prime (q, (bits+3)/2, 0, random_ctx, random,
+ progress_ctx, progress);
+
+ _nettle_generate_pocklington_prime (p, r, bits, top_bits_set,
+ random_ctx, random,
+ q, NULL, q);
+
+ if (progress)
+ progress (progress_ctx, 'x');
+
+ mpz_clear (q);
+ mpz_clear (r);
+ }
+}
diff --git a/external/nettle-3.3/nettle/bignum-random.c b/external/nettle-3.3/nettle/bignum-random.c
new file mode 100644
index 0000000..34a696f
--- /dev/null
+++ b/external/nettle-3.3/nettle/bignum-random.c
@@ -0,0 +1,96 @@
+/* bignum-random.c
+
+ Generating big random numbers
+
+ Copyright (C) 2002, 2013 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "bignum.h"
+#include "gmp-glue.h"
+
+void
+nettle_mpz_random_size(mpz_t x,
+ void *ctx, nettle_random_func *random,
+ unsigned bits)
+{
+ unsigned length = (bits + 7) / 8;
+ TMP_GMP_DECL(data, uint8_t);
+
+ TMP_GMP_ALLOC(data, length);
+
+ random(ctx, length, data);
+ nettle_mpz_set_str_256_u(x, length, data);
+
+ if (bits % 8)
+ mpz_fdiv_r_2exp(x, x, bits);
+
+ TMP_GMP_FREE(data);
+}
+
+/* Returns a random number x, 0 <= x < n */
+void
+nettle_mpz_random(mpz_t x,
+ void *ctx, nettle_random_func *random,
+ const mpz_t n)
+{
+ /* NOTE: This leaves some bias, which may be bad for DSA. A better
+ * way might be to generate a random number of mpz_sizeinbase(n, 2)
+ * bits, and loop until one smaller than n is found. */
+
+ /* From Daniel Bleichenbacher (via coderpunks):
+ *
+ * There is still a theoretical attack possible with 8 extra bits.
+ * But, the attack would need about 2^66 signatures 2^66 memory and
+ * 2^66 time (if I remember that correctly). Compare that to DSA,
+ * where the attack requires 2^22 signatures 2^40 memory and 2^64
+ * time. And of course, the numbers above are not a real threat for
+ * PGP. Using 16 extra bits (i.e. generating a 176 bit random number
+ * and reducing it modulo q) will defeat even this theoretical
+ * attack.
+ *
+ * More generally log_2(q)/8 extra bits are enough to defeat my
+ * attack. NIST also plans to update the standard.
+ */
+
+ /* Add a few bits extra, to decrease the bias from the final modulo
+ * operation. NIST FIPS 186-3 specifies 64 extra bits, for use with
+ * DSA. */
+
+ nettle_mpz_random_size(x,
+ ctx, random,
+ mpz_sizeinbase(n, 2) + 64);
+
+ mpz_fdiv_r(x, x, n);
+}
diff --git a/external/nettle-3.3/nettle/bignum.c b/external/nettle-3.3/nettle/bignum.c
new file mode 100644
index 0000000..b58726f
--- /dev/null
+++ b/external/nettle-3.3/nettle/bignum.c
@@ -0,0 +1,186 @@
+/* bignum.c
+
+ Bignum operations that are missing from gmp.
+
+ Copyright (C) 2001 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "bignum.h"
+
+/* Two's complement negation means that -x = ~x + 1, ~x = -(x+1),
+ * and we use that x = ~~x = ~(-x-1).
+ *
+ * Examples:
+ *
+ * x ~x = -x+1 ~~x = x
+ * -1 0 ff
+ * -2 1 fe
+ * -7f 7e 81
+ * -80 7f 80
+ * -81 80 ff7f
+ */
+
+/* Including extra sign bit, if needed. Also one byte for zero. */
+size_t
+nettle_mpz_sizeinbase_256_s(const mpz_t x)
+{
+ if (mpz_sgn(x) >= 0)
+ return 1 + mpz_sizeinbase(x, 2) / 8;
+ else
+ {
+ /* We'll output ~~x, so we need as many bits as for ~x */
+ size_t size;
+ mpz_t c;
+
+ mpz_init(c);
+ mpz_com(c, x); /* Same as c = - x - 1 = |x| + 1 */
+ size = 1 + mpz_sizeinbase(c,2) / 8;
+ mpz_clear(c);
+
+ return size;
+ }
+}
+
+size_t
+nettle_mpz_sizeinbase_256_u(const mpz_t x)
+{
+ return (mpz_sizeinbase(x,2) + 7) / 8;
+}
+
+static void
+nettle_mpz_to_octets(size_t length, uint8_t *s,
+ const mpz_t x, uint8_t sign)
+{
+ uint8_t *dst = s + length - 1;
+ size_t size = mpz_size(x);
+ size_t i;
+
+ for (i = 0; i<size; i++)
+ {
+ mp_limb_t limb = mpz_getlimbn(x, i);
+ size_t j;
+
+ for (j = 0; length && j < sizeof(mp_limb_t); j++)
+ {
+ *dst-- = sign ^ (limb & 0xff);
+ limb >>= 8;
+ length--;
+ }
+ }
+
+ if (length)
+ memset(s, sign, length);
+}
+
+void
+nettle_mpz_get_str_256(size_t length, uint8_t *s, const mpz_t x)
+{
+ if (!length)
+ {
+ /* x must be zero */
+ assert(!mpz_sgn(x));
+ return;
+ }
+
+ if (mpz_sgn(x) >= 0)
+ {
+ assert(nettle_mpz_sizeinbase_256_u(x) <= length);
+ nettle_mpz_to_octets(length, s, x, 0);
+ }
+ else
+ {
+ mpz_t c;
+ mpz_init(c);
+ mpz_com(c, x);
+
+ assert(nettle_mpz_sizeinbase_256_u(c) <= length);
+ nettle_mpz_to_octets(length, s, c, 0xff);
+
+ mpz_clear(c);
+ }
+}
+
+/* Converting from strings */
+
+/* mpz_import was introduced in GMP-4.1 */
+#define nettle_mpz_from_octets(x, length, s) \
+ mpz_import((x), (length), 1, 1, 0, 0, (s))
+
+void
+nettle_mpz_set_str_256_u(mpz_t x,
+ size_t length, const uint8_t *s)
+{
+ nettle_mpz_from_octets(x, length, s);
+}
+
+void
+nettle_mpz_init_set_str_256_u(mpz_t x,
+ size_t length, const uint8_t *s)
+{
+ mpz_init(x);
+ nettle_mpz_from_octets(x, length, s);
+}
+
+void
+nettle_mpz_set_str_256_s(mpz_t x,
+ size_t length, const uint8_t *s)
+{
+ if (!length)
+ {
+ mpz_set_ui(x, 0);
+ return;
+ }
+
+ nettle_mpz_from_octets(x, length, s);
+
+ if (s[0] & 0x80)
+ {
+ mpz_t t;
+
+ mpz_init_set_ui(t, 1);
+ mpz_mul_2exp(t, t, length*8);
+ mpz_sub(x, x, t);
+ mpz_clear(t);
+ }
+}
+
+void
+nettle_mpz_init_set_str_256_s(mpz_t x,
+ size_t length, const uint8_t *s)
+{
+ mpz_init(x);
+ nettle_mpz_set_str_256_s(x, length, s);
+}
diff --git a/external/nettle-3.3/nettle/bignum.h b/external/nettle-3.3/nettle/bignum.h
new file mode 100644
index 0000000..188e9e4
--- /dev/null
+++ b/external/nettle-3.3/nettle/bignum.h
@@ -0,0 +1,140 @@
+/* bignum.h
+
+ Bignum operations that are missing from gmp.
+
+ Copyright (C) 2001 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_BIGNUM_H_INCLUDED
+#define NETTLE_BIGNUM_H_INCLUDED
+
+#include "nettle-meta.h"
+
+#include "nettle-types.h"
+
+/* For NETTLE_USE_MINI_GMP */
+#include "version.h"
+
+#if NETTLE_USE_MINI_GMP
+# include "mini-gmp.h"
+
+# define GMP_NUMB_MASK (~(mp_limb_t) 0)
+
+/* Function missing in older gmp versions, and checked for with ifdef */
+# define mpz_limbs_read mpz_limbs_read
+/* Side-channel silent powm not available in mini-gmp. */
+# define mpz_powm_sec mpz_powm
+#else
+# include <gmp.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Size needed for signed encoding, including extra sign byte if
+ * necessary. */
+size_t
+nettle_mpz_sizeinbase_256_s(const mpz_t x);
+
+/* Size needed for unsigned encoding */
+size_t
+nettle_mpz_sizeinbase_256_u(const mpz_t x);
+
+/* Writes an integer as length octets, using big endian byte order,
+ * and two's complement for negative numbers. */
+void
+nettle_mpz_get_str_256(size_t length, uint8_t *s, const mpz_t x);
+
+/* Reads a big endian, two's complement, integer. */
+void
+nettle_mpz_set_str_256_s(mpz_t x,
+ size_t length, const uint8_t *s);
+
+void
+nettle_mpz_init_set_str_256_s(mpz_t x,
+ size_t length, const uint8_t *s);
+
+/* Similar, but for unsigned format. These function don't interpret
+ * the most significant bit as the sign. */
+void
+nettle_mpz_set_str_256_u(mpz_t x,
+ size_t length, const uint8_t *s);
+
+void
+nettle_mpz_init_set_str_256_u(mpz_t x,
+ size_t length, const uint8_t *s);
+
+/* Returns a uniformly distributed random number 0 <= x < 2^n */
+void
+nettle_mpz_random_size(mpz_t x,
+ void *ctx, nettle_random_func *random,
+ unsigned bits);
+
+/* Returns a number x, almost uniformly random in the range
+ * 0 <= x < n. */
+void
+nettle_mpz_random(mpz_t x,
+ void *ctx, nettle_random_func *random,
+ const mpz_t n);
+
+void
+nettle_random_prime(mpz_t p, unsigned bits, int top_bits_set,
+ void *ctx, nettle_random_func *random,
+ void *progress_ctx, nettle_progress_func *progress);
+
+void
+_nettle_generate_pocklington_prime (mpz_t p, mpz_t r,
+ unsigned bits, int top_bits_set,
+ void *ctx, nettle_random_func *random,
+ const mpz_t p0,
+ const mpz_t q,
+ const mpz_t p0q);
+
+/* sexp parsing */
+struct sexp_iterator;
+
+/* If LIMIT is non-zero, the number must be at most LIMIT bits.
+ * Implies sexp_iterator_next. */
+int
+nettle_mpz_set_sexp(mpz_t x, unsigned limit, struct sexp_iterator *i);
+
+
+/* der parsing */
+struct asn1_der_iterator;
+
+int
+nettle_asn1_der_get_bignum(struct asn1_der_iterator *iterator,
+ mpz_t x, unsigned max_bits);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_BIGNUM_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/buffer-init.c b/external/nettle-3.3/nettle/buffer-init.c
new file mode 100644
index 0000000..c953fd1
--- /dev/null
+++ b/external/nettle-3.3/nettle/buffer-init.c
@@ -0,0 +1,48 @@
+/* buffer-init.c
+
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "buffer.h"
+#include "realloc.h"
+
+/* This is in a separate file so that we don't link in realloc in
+ * programs that don't need it. */
+
+void
+nettle_buffer_init(struct nettle_buffer *buffer)
+{
+ nettle_buffer_init_realloc(buffer, NULL, nettle_realloc);
+}
diff --git a/external/nettle-3.3/nettle/buffer.c b/external/nettle-3.3/nettle/buffer.c
new file mode 100644
index 0000000..37a7275
--- /dev/null
+++ b/external/nettle-3.3/nettle/buffer.c
@@ -0,0 +1,142 @@
+/* buffer.c
+
+ A bare-bones string stream.
+
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "buffer.h"
+
+int
+nettle_buffer_grow(struct nettle_buffer *buffer,
+ size_t length)
+{
+ assert(buffer->size <= buffer->alloc);
+
+ if (buffer->size + length > buffer->alloc)
+ {
+ size_t alloc;
+ uint8_t *p;
+
+ if (!buffer->realloc)
+ return 0;
+
+ alloc = buffer->alloc * 2 + length + 100;
+ p = buffer->realloc(buffer->realloc_ctx, buffer->contents, alloc);
+ if (!p)
+ return 0;
+
+ buffer->contents = p;
+ buffer->alloc = alloc;
+ }
+ return 1;
+}
+
+void
+nettle_buffer_init_realloc(struct nettle_buffer *buffer,
+ void *realloc_ctx,
+ nettle_realloc_func *realloc)
+{
+ buffer->contents = NULL;
+ buffer->alloc = 0;
+ buffer->realloc = realloc;
+ buffer->realloc_ctx = realloc_ctx;
+ buffer->size = 0;
+}
+
+void
+nettle_buffer_init_size(struct nettle_buffer *buffer,
+ size_t length, uint8_t *space)
+{
+ buffer->contents = space;
+ buffer->alloc = length;
+ buffer->realloc = NULL;
+ buffer->realloc_ctx = NULL;
+ buffer->size = 0;
+}
+
+void
+nettle_buffer_clear(struct nettle_buffer *buffer)
+{
+ if (buffer->realloc)
+ buffer->realloc(buffer->realloc_ctx, buffer->contents, 0);
+
+ buffer->contents = NULL;
+ buffer->alloc = 0;
+ buffer->size = 0;
+}
+
+void
+nettle_buffer_reset(struct nettle_buffer *buffer)
+{
+ buffer->size = 0;
+}
+
+uint8_t *
+nettle_buffer_space(struct nettle_buffer *buffer,
+ size_t length)
+{
+ uint8_t *p;
+
+ if (!nettle_buffer_grow(buffer, length))
+ return NULL;
+
+ p = buffer->contents + buffer->size;
+ buffer->size += length;
+ return p;
+}
+
+int
+nettle_buffer_write(struct nettle_buffer *buffer,
+ size_t length, const uint8_t *data)
+{
+ uint8_t *p = nettle_buffer_space(buffer, length);
+ if (p)
+ {
+ memcpy(p, data, length);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int
+nettle_buffer_copy(struct nettle_buffer *dst,
+ const struct nettle_buffer *src)
+{
+ return nettle_buffer_write(dst, src->size, src->contents);
+}
diff --git a/external/nettle-3.3/nettle/buffer.h b/external/nettle-3.3/nettle/buffer.h
new file mode 100644
index 0000000..0e59d05
--- /dev/null
+++ b/external/nettle-3.3/nettle/buffer.h
@@ -0,0 +1,106 @@
+/* buffer.h
+
+ A bare-bones string stream.
+
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_BUFFER_H_INCLUDED
+#define NETTLE_BUFFER_H_INCLUDED
+
+#include "realloc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nettle_buffer
+{
+ uint8_t *contents;
+ /* Allocated size */
+ size_t alloc;
+
+ void *realloc_ctx;
+ nettle_realloc_func *realloc;
+
+ /* Current size */
+ size_t size;
+};
+
+/* Initializes a buffer that uses plain realloc */
+void
+nettle_buffer_init(struct nettle_buffer *buffer);
+
+void
+nettle_buffer_init_realloc(struct nettle_buffer *buffer,
+ void *realloc_ctx,
+ nettle_realloc_func *realloc);
+
+/* Initializes a buffer of fix size */
+void
+nettle_buffer_init_size(struct nettle_buffer *buffer,
+ size_t length, uint8_t *space);
+
+void
+nettle_buffer_clear(struct nettle_buffer *buffer);
+
+/* Resets the buffer, without freeing the buffer space. */
+void
+nettle_buffer_reset(struct nettle_buffer *buffer);
+
+int
+nettle_buffer_grow(struct nettle_buffer *buffer,
+ size_t length);
+
+#define NETTLE_BUFFER_PUTC(buffer, c) \
+( (((buffer)->size < (buffer)->alloc) || nettle_buffer_grow((buffer), 1)) \
+ && ((buffer)->contents[(buffer)->size++] = (c), 1) )
+
+int
+nettle_buffer_write(struct nettle_buffer *buffer,
+ size_t length, const uint8_t *data);
+
+/* Like nettle_buffer_write, but instead of copying data to the
+ * buffer, it returns a pointer to the area where the caller can copy
+ * the data. The pointer is valid only until the next call that can
+ * reallocate the buffer. */
+uint8_t *
+nettle_buffer_space(struct nettle_buffer *buffer,
+ size_t length);
+
+/* Copy the contents of SRC to the end of DST. */
+int
+nettle_buffer_copy(struct nettle_buffer *dst,
+ const struct nettle_buffer *src);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_BUFFER_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/gmp-glue.c b/external/nettle-3.3/nettle/gmp-glue.c
new file mode 100644
index 0000000..4b813b8
--- /dev/null
+++ b/external/nettle-3.3/nettle/gmp-glue.c
@@ -0,0 +1,326 @@
+/* gmp-glue.c
+
+ Copyright (C) 2013 Niels Möller
+ Copyright (C) 2013 Red Hat
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "gmp-glue.h"
+
+#if !GMP_HAVE_mpz_limbs_read
+
+/* This implementation tries to make a minimal use of GMP internals.
+ We access and _mp_size and _mp_d, but not _mp_alloc. */
+
+/* Use macros compatible with gmp-impl.h. */
+#define ABS(x) ((x) >= 0 ? (x) : -(x))
+#define PTR(x) ((x)->_mp_d)
+#define SIZ(x) ((x)->_mp_size)
+#define ABSIZ(x) ABS (SIZ (x))
+
+#define MPN_NORMALIZE(xp, xn) do { \
+ while ( (xn) > 0 && (xp)[xn-1] == 0) \
+ (xn)--; \
+ } while (0)
+
+/* NOTE: Makes an unnecessary realloc if allocation is already large
+ enough, but looking at _mp_alloc may break in future GMP
+ versions. */
+#define MPZ_REALLOC(x, n) \
+ (ABSIZ(x) >= (n) ? PTR(x) : (_mpz_realloc ((x),(n)), PTR (x)))
+
+#define MPZ_NEWALLOC MPZ_REALLOC
+
+/* Read access to mpz numbers. */
+
+/* Return limb pointer, for read-only operations. Use mpz_size to get
+ the number of limbs. */
+const mp_limb_t *
+mpz_limbs_read (mpz_srcptr x)
+{
+ return PTR (x);
+}
+
+/* Write access to mpz numbers. */
+
+/* Get a limb pointer for writing, previous contents may be
+ destroyed. */
+mp_limb_t *
+mpz_limbs_write (mpz_ptr x, mp_size_t n)
+{
+ assert (n > 0);
+ return MPZ_NEWALLOC (x, n);
+}
+
+/* Get a limb pointer for writing, previous contents is intact. */
+mp_limb_t *
+mpz_limbs_modify (mpz_ptr x, mp_size_t n)
+{
+ assert (n > 0);
+ return MPZ_REALLOC (x, n);
+}
+
+void
+mpz_limbs_finish (mpz_ptr x, mp_size_t n)
+{
+ assert (n >= 0);
+ MPN_NORMALIZE (PTR(x), n);
+
+ SIZ (x) = n;
+}
+
+/* Needs some ugly casts. */
+mpz_srcptr
+mpz_roinit_n (mpz_ptr x, const mp_limb_t *xp, mp_size_t xs)
+{
+ mp_size_t xn = ABS (xs);
+
+ MPN_NORMALIZE (xp, xn);
+
+ x->_mp_size = xs < 0 ? -xn : xn;
+ x->_mp_alloc = 0;
+ x->_mp_d = (mp_limb_t *) xp;
+ return x;
+}
+#endif /* !GMP_HAVE_mpz_limbs_read */
+
+void
+cnd_swap (mp_limb_t cnd, mp_limb_t *ap, mp_limb_t *bp, mp_size_t n)
+{
+ mp_limb_t mask = - (mp_limb_t) (cnd != 0);
+ mp_size_t i;
+ for (i = 0; i < n; i++)
+ {
+ mp_limb_t a, b, t;
+ a = ap[i];
+ b = bp[i];
+ t = (a ^ b) & mask;
+ ap[i] = a ^ t;
+ bp[i] = b ^ t;
+ }
+}
+
+/* Additional convenience functions. */
+
+int
+mpz_limbs_cmp (mpz_srcptr a, const mp_limb_t *bp, mp_size_t bn)
+{
+ mp_size_t an = mpz_size (a);
+ assert (mpz_sgn (a) >= 0);
+ assert (bn >= 0);
+
+ if (an < bn)
+ return -1;
+ if (an > bn)
+ return 1;
+ if (an == 0)
+ return 0;
+
+ return mpn_cmp (mpz_limbs_read(a), bp, an);
+}
+
+/* Get a pointer to an n limb area, for read-only operation. n must be
+ greater or equal to the current size, and the mpz is zero-padded if
+ needed. */
+const mp_limb_t *
+mpz_limbs_read_n (mpz_ptr x, mp_size_t n)
+{
+ mp_size_t xn = mpz_size (x);
+ mp_ptr xp;
+
+ assert (xn <= n);
+
+ xp = mpz_limbs_modify (x, n);
+
+ if (xn < n)
+ mpn_zero (xp + xn, n - xn);
+
+ return xp;
+}
+
+void
+mpz_limbs_copy (mp_limb_t *xp, mpz_srcptr x, mp_size_t n)
+{
+ mp_size_t xn = mpz_size (x);
+
+ assert (xn <= n);
+ mpn_copyi (xp, mpz_limbs_read (x), xn);
+ if (xn < n)
+ mpn_zero (xp + xn, n - xn);
+}
+
+void
+mpz_set_n (mpz_t r, const mp_limb_t *xp, mp_size_t xn)
+{
+ mpn_copyi (mpz_limbs_write (r, xn), xp, xn);
+ mpz_limbs_finish (r, xn);
+}
+
+void
+mpn_set_base256 (mp_limb_t *rp, mp_size_t rn,
+ const uint8_t *xp, size_t xn)
+{
+ size_t xi;
+ mp_limb_t out;
+ unsigned bits;
+ for (xi = xn, out = bits = 0; xi > 0 && rn > 0; )
+ {
+ mp_limb_t in = xp[--xi];
+ out |= (in << bits) & GMP_NUMB_MASK;
+ bits += 8;
+ if (bits >= GMP_NUMB_BITS)
+ {
+ *rp++ = out;
+ rn--;
+
+ bits -= GMP_NUMB_BITS;
+ out = in >> (8 - bits);
+ }
+ }
+ if (rn > 0)
+ {
+ *rp++ = out;
+ if (--rn > 0)
+ mpn_zero (rp, rn);
+ }
+}
+
+void
+mpn_set_base256_le (mp_limb_t *rp, mp_size_t rn,
+ const uint8_t *xp, size_t xn)
+{
+ size_t xi;
+ mp_limb_t out;
+ unsigned bits;
+ for (xi = 0, out = bits = 0; xi < xn && rn > 0; )
+ {
+ mp_limb_t in = xp[xi++];
+ out |= (in << bits) & GMP_NUMB_MASK;
+ bits += 8;
+ if (bits >= GMP_NUMB_BITS)
+ {
+ *rp++ = out;
+ rn--;
+
+ bits -= GMP_NUMB_BITS;
+ out = in >> (8 - bits);
+ }
+ }
+ if (rn > 0)
+ {
+ *rp++ = out;
+ if (--rn > 0)
+ mpn_zero (rp, rn);
+ }
+}
+
+void
+mpn_get_base256_le (uint8_t *rp, size_t rn,
+ const mp_limb_t *xp, mp_size_t xn)
+{
+ unsigned bits;
+ mp_limb_t in;
+ for (bits = in = 0; xn > 0 && rn > 0; )
+ {
+ if (bits >= 8)
+ {
+ *rp++ = in;
+ rn--;
+ in >>= 8;
+ bits -= 8;
+ }
+ else
+ {
+ uint8_t old = in;
+ in = *xp++;
+ xn--;
+ *rp++ = old | (in << bits);
+ rn--;
+ in >>= (8 - bits);
+ bits += GMP_NUMB_BITS - 8;
+ }
+ }
+ while (rn > 0)
+ {
+ *rp++ = in;
+ rn--;
+ in >>= 8;
+ }
+}
+
+mp_limb_t *
+gmp_alloc_limbs (mp_size_t n)
+{
+
+ void *(*alloc_func)(size_t);
+
+ assert (n > 0);
+
+ mp_get_memory_functions (&alloc_func, NULL, NULL);
+ return (mp_limb_t *) alloc_func ( (size_t) n * sizeof(mp_limb_t));
+}
+
+void
+gmp_free_limbs (mp_limb_t *p, mp_size_t n)
+{
+ void (*free_func)(void *, size_t);
+ assert (n > 0);
+ assert (p != 0);
+ mp_get_memory_functions (NULL, NULL, &free_func);
+
+ free_func (p, (size_t) n * sizeof(mp_limb_t));
+}
+
+void *
+gmp_alloc(size_t n)
+{
+ void *(*alloc_func)(size_t);
+ assert (n > 0);
+
+ mp_get_memory_functions(&alloc_func, NULL, NULL);
+
+ return alloc_func (n);
+}
+
+void
+gmp_free(void *p, size_t n)
+{
+ void (*free_func)(void *, size_t);
+ assert (n > 0);
+ assert (p != 0);
+ mp_get_memory_functions (NULL, NULL, &free_func);
+
+ free_func (p, (size_t) n);
+}
diff --git a/external/nettle-3.3/nettle/gmp-glue.h b/external/nettle-3.3/nettle/gmp-glue.h
new file mode 100644
index 0000000..e7a6177
--- /dev/null
+++ b/external/nettle-3.3/nettle/gmp-glue.h
@@ -0,0 +1,164 @@
+/* gmp-glue.h
+
+ Copyright (C) 2013 Niels Möller
+ Copyright (C) 2013 Red Hat
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_GMP_GLUE_H_INCLUDED
+#define NETTLE_GMP_GLUE_H_INCLUDED
+
+#include "bignum.h"
+
+#ifdef mpz_limbs_read
+#define GMP_HAVE_mpz_limbs_read 1
+#else
+#define GMP_HAVE_mpz_limbs_read 0
+#endif
+
+/* Name mangling. */
+#if !GMP_HAVE_mpz_limbs_read
+#define mpz_limbs_read _nettle_mpz_limbs_read
+#define mpz_limbs_write _nettle_mpz_limbs_write
+#define mpz_limbs_modify _nettle_mpz_limbs_modify
+#define mpz_limbs_finish _nettle_mpz_limbs_finish
+#define mpz_roinit_n _nettle_mpz_roinit_n
+#endif
+
+#define cnd_swap _nettle_cnd_swap
+#define mpz_limbs_cmp _nettle_mpz_limbs_cmp
+#define mpz_limbs_read_n _nettle_mpz_limbs_read_n
+#define mpz_limbs_copy _nettle_mpz_limbs_copy
+#define mpz_set_n _nettle_mpz_set_n
+#define mpn_set_base256 _nettle_mpn_set_base256
+#define mpn_set_base256_le _nettle_mpn_set_base256_le
+#define mpn_get_base256_le _nettle_mpn_get_base256_le
+#define gmp_alloc_limbs _nettle_gmp_alloc_limbs
+#define gmp_free_limbs _nettle_gmp_free_limbs
+#define gmp_free _nettle_gmp_free
+#define gmp_alloc _nettle_gmp_alloc
+
+#define TMP_GMP_DECL(name, type) type *name; \
+ size_t tmp_##name##_size
+#define TMP_GMP_ALLOC(name, size) do { \
+ tmp_##name##_size = (size); \
+ (name) = gmp_alloc(sizeof (*name) * (size)); \
+ } while (0)
+#define TMP_GMP_FREE(name) (gmp_free(name, tmp_##name##_size))
+
+
+/* Use only in-place operations, so we can fall back to addmul_1/submul_1 */
+#ifdef mpn_cnd_add_n
+# define cnd_add_n(cnd, rp, ap, n) mpn_cnd_add_n ((cnd), (rp), (rp), (ap), (n))
+# define cnd_sub_n(cnd, rp, ap, n) mpn_cnd_sub_n ((cnd), (rp), (rp), (ap), (n))
+#else
+# define cnd_add_n(cnd, rp, ap, n) mpn_addmul_1 ((rp), (ap), (n), (cnd) != 0)
+# define cnd_sub_n(cnd, rp, ap, n) mpn_submul_1 ((rp), (ap), (n), (cnd) != 0)
+#endif
+
+/* Some functions for interfacing between mpz and mpn code. Signs of
+ the mpz numbers are generally ignored. */
+
+#if !GMP_HAVE_mpz_limbs_read
+/* Read access to mpz numbers. */
+
+/* Return limb pointer, for read-only operations. Use mpz_size to get
+ the number of limbs. */
+const mp_limb_t *
+mpz_limbs_read (const mpz_srcptr x);
+
+/* Write access to mpz numbers. */
+
+/* Get a limb pointer for writing, previous contents may be
+ destroyed. */
+mp_limb_t *
+mpz_limbs_write (mpz_ptr x, mp_size_t n);
+
+/* Get a limb pointer for writing, previous contents is intact. */
+mp_limb_t *
+mpz_limbs_modify (mpz_ptr x, mp_size_t n);
+
+/* Update size. */
+void
+mpz_limbs_finish (mpz_ptr x, mp_size_t n);
+
+/* Using an mpn number as an mpz. Can be used for read-only access
+ only. x must not be cleared or reallocated. */
+mpz_srcptr
+mpz_roinit_n (mpz_ptr x, const mp_limb_t *xp, mp_size_t xs);
+
+#endif /* !GMP_HAVE_mpz_limbs_read */
+
+void
+cnd_swap (mp_limb_t cnd, mp_limb_t *ap, mp_limb_t *bp, mp_size_t n);
+
+/* Convenience functions */
+int
+mpz_limbs_cmp (mpz_srcptr a, const mp_limb_t *bp, mp_size_t bn);
+
+/* Get a pointer to an n limb area, for read-only operation. n must be
+ greater or equal to the current size, and the mpz is zero-padded if
+ needed. */
+const mp_limb_t *
+mpz_limbs_read_n (mpz_ptr x, mp_size_t n);
+
+/* Copy limbs, with zero-padding. */
+/* FIXME: Reorder arguments, on the theory that the first argument of
+ an _mpz_* function should be an mpz_t? Or rename to _mpz_get_limbs,
+ with argument order consistent with mpz_get_*. */
+void
+mpz_limbs_copy (mp_limb_t *xp, mpz_srcptr x, mp_size_t n);
+
+void
+mpz_set_n (mpz_t r, const mp_limb_t *xp, mp_size_t xn);
+
+/* Like mpn_set_str, but always writes rn limbs. If input is larger,
+ higher bits are ignored. */
+void
+mpn_set_base256 (mp_limb_t *rp, mp_size_t rn,
+ const uint8_t *xp, size_t xn);
+
+void
+mpn_set_base256_le (mp_limb_t *rp, mp_size_t rn,
+ const uint8_t *xp, size_t xn);
+
+void
+mpn_get_base256_le (uint8_t *rp, size_t rn,
+ const mp_limb_t *xp, mp_size_t xn);
+
+
+mp_limb_t *
+gmp_alloc_limbs (mp_size_t n);
+
+void
+gmp_free_limbs (mp_limb_t *p, mp_size_t n);
+
+void *gmp_alloc(size_t n);
+void gmp_free(void *p, size_t n);
+
+#endif /* NETTLE_GMP_GLUE_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/macros.h b/external/nettle-3.3/nettle/macros.h
new file mode 100644
index 0000000..af84841
--- /dev/null
+++ b/external/nettle-3.3/nettle/macros.h
@@ -0,0 +1,245 @@
+/* macros.h
+
+ Copyright (C) 2001, 2010 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_MACROS_H_INCLUDED
+#define NETTLE_MACROS_H_INCLUDED
+
+/* Reads a 64-bit integer, in network, big-endian, byte order */
+#define READ_UINT64(p) \
+( (((uint64_t) (p)[0]) << 56) \
+ | (((uint64_t) (p)[1]) << 48) \
+ | (((uint64_t) (p)[2]) << 40) \
+ | (((uint64_t) (p)[3]) << 32) \
+ | (((uint64_t) (p)[4]) << 24) \
+ | (((uint64_t) (p)[5]) << 16) \
+ | (((uint64_t) (p)[6]) << 8) \
+ | ((uint64_t) (p)[7]))
+
+#define WRITE_UINT64(p, i) \
+do { \
+ (p)[0] = ((i) >> 56) & 0xff; \
+ (p)[1] = ((i) >> 48) & 0xff; \
+ (p)[2] = ((i) >> 40) & 0xff; \
+ (p)[3] = ((i) >> 32) & 0xff; \
+ (p)[4] = ((i) >> 24) & 0xff; \
+ (p)[5] = ((i) >> 16) & 0xff; \
+ (p)[6] = ((i) >> 8) & 0xff; \
+ (p)[7] = (i) & 0xff; \
+} while(0)
+
+/* Reads a 32-bit integer, in network, big-endian, byte order */
+#define READ_UINT32(p) \
+( (((uint32_t) (p)[0]) << 24) \
+ | (((uint32_t) (p)[1]) << 16) \
+ | (((uint32_t) (p)[2]) << 8) \
+ | ((uint32_t) (p)[3]))
+
+#define WRITE_UINT32(p, i) \
+do { \
+ (p)[0] = ((i) >> 24) & 0xff; \
+ (p)[1] = ((i) >> 16) & 0xff; \
+ (p)[2] = ((i) >> 8) & 0xff; \
+ (p)[3] = (i) & 0xff; \
+} while(0)
+
+/* Analogous macros, for 24 and 16 bit numbers */
+#define READ_UINT24(p) \
+( (((uint32_t) (p)[0]) << 16) \
+ | (((uint32_t) (p)[1]) << 8) \
+ | ((uint32_t) (p)[2]))
+
+#define WRITE_UINT24(p, i) \
+do { \
+ (p)[0] = ((i) >> 16) & 0xff; \
+ (p)[1] = ((i) >> 8) & 0xff; \
+ (p)[2] = (i) & 0xff; \
+} while(0)
+
+#define READ_UINT16(p) \
+( (((uint32_t) (p)[0]) << 8) \
+ | ((uint32_t) (p)[1]))
+
+#define WRITE_UINT16(p, i) \
+do { \
+ (p)[0] = ((i) >> 8) & 0xff; \
+ (p)[1] = (i) & 0xff; \
+} while(0)
+
+/* And the other, little-endian, byteorder */
+#define LE_READ_UINT64(p) \
+( (((uint64_t) (p)[7]) << 56) \
+ | (((uint64_t) (p)[6]) << 48) \
+ | (((uint64_t) (p)[5]) << 40) \
+ | (((uint64_t) (p)[4]) << 32) \
+ | (((uint64_t) (p)[3]) << 24) \
+ | (((uint64_t) (p)[2]) << 16) \
+ | (((uint64_t) (p)[1]) << 8) \
+ | ((uint64_t) (p)[0]))
+
+#define LE_WRITE_UINT64(p, i) \
+do { \
+ (p)[7] = ((i) >> 56) & 0xff; \
+ (p)[6] = ((i) >> 48) & 0xff; \
+ (p)[5] = ((i) >> 40) & 0xff; \
+ (p)[4] = ((i) >> 32) & 0xff; \
+ (p)[3] = ((i) >> 24) & 0xff; \
+ (p)[2] = ((i) >> 16) & 0xff; \
+ (p)[1] = ((i) >> 8) & 0xff; \
+ (p)[0] = (i) & 0xff; \
+} while (0)
+
+#define LE_READ_UINT32(p) \
+( (((uint32_t) (p)[3]) << 24) \
+ | (((uint32_t) (p)[2]) << 16) \
+ | (((uint32_t) (p)[1]) << 8) \
+ | ((uint32_t) (p)[0]))
+
+#define LE_WRITE_UINT32(p, i) \
+do { \
+ (p)[3] = ((i) >> 24) & 0xff; \
+ (p)[2] = ((i) >> 16) & 0xff; \
+ (p)[1] = ((i) >> 8) & 0xff; \
+ (p)[0] = (i) & 0xff; \
+} while(0)
+
+/* Analogous macros, for 16 bit numbers */
+#define LE_READ_UINT16(p) \
+ ( (((uint32_t) (p)[1]) << 8) \
+ | ((uint32_t) (p)[0]))
+
+#define LE_WRITE_UINT16(p, i) \
+ do { \
+ (p)[1] = ((i) >> 8) & 0xff; \
+ (p)[0] = (i) & 0xff; \
+ } while(0)
+
+/* Macro to make it easier to loop over several blocks. */
+#define FOR_BLOCKS(length, dst, src, blocksize) \
+ assert( !((length) % (blocksize))); \
+ for (; (length); ((length) -= (blocksize), \
+ (dst) += (blocksize), \
+ (src) += (blocksize)) )
+
+/* The masking of the right shift is needed to allow n == 0 (using
+ just 32 - n and 64 - n results in undefined behaviour). Most uses
+ of these macros use a constant and non-zero rotation count. */
+#define ROTL32(n,x) (((x)<<(n)) | ((x)>>((-(n)&31))))
+
+#define ROTL64(n,x) (((x)<<(n)) | ((x)>>((-(n))&63)))
+
+/* Requires that size > 0 */
+#define INCREMENT(size, ctr) \
+ do { \
+ unsigned increment_i = (size) - 1; \
+ if (++(ctr)[increment_i] == 0) \
+ while (increment_i > 0 \
+ && ++(ctr)[--increment_i] == 0 ) \
+ ; \
+ } while (0)
+
+
+/* Helper macro for Merkle-Damgård hash functions. Assumes the context
+ structs includes the following fields:
+
+ uint8_t block[...]; // Buffer holding one block
+ unsigned int index; // Index into block
+*/
+
+/* Currently used by sha512 (and sha384) only. */
+#define MD_INCR(ctx) ((ctx)->count_high += !++(ctx)->count_low)
+
+/* Takes the compression function f as argument. NOTE: also clobbers
+ length and data. */
+#define MD_UPDATE(ctx, length, data, f, incr) \
+ do { \
+ if ((ctx)->index) \
+ { \
+ /* Try to fill partial block */ \
+ unsigned __md_left = sizeof((ctx)->block) - (ctx)->index; \
+ if ((length) < __md_left) \
+ { \
+ memcpy((ctx)->block + (ctx)->index, (data), (length)); \
+ (ctx)->index += (length); \
+ goto __md_done; /* Finished */ \
+ } \
+ else \
+ { \
+ memcpy((ctx)->block + (ctx)->index, (data), __md_left); \
+ \
+ f((ctx), (ctx)->block); \
+ (incr); \
+ \
+ (data) += __md_left; \
+ (length) -= __md_left; \
+ } \
+ } \
+ while ((length) >= sizeof((ctx)->block)) \
+ { \
+ f((ctx), (data)); \
+ (incr); \
+ \
+ (data) += sizeof((ctx)->block); \
+ (length) -= sizeof((ctx)->block); \
+ } \
+ memcpy ((ctx)->block, (data), (length)); \
+ (ctx)->index = (length); \
+ __md_done: \
+ ; \
+ } while (0)
+
+/* Pads the block to a block boundary with the bit pattern 1 0*,
+ leaving size octets for the length field at the end. If needed,
+ compresses the block and starts a new one. */
+#define MD_PAD(ctx, size, f) \
+ do { \
+ unsigned __md_i; \
+ __md_i = (ctx)->index; \
+ \
+ /* Set the first char of padding to 0x80. This is safe since there \
+ is always at least one byte free */ \
+ \
+ assert(__md_i < sizeof((ctx)->block)); \
+ (ctx)->block[__md_i++] = 0x80; \
+ \
+ if (__md_i > (sizeof((ctx)->block) - (size))) \
+ { /* No room for length in this block. Process it and \
+ pad with another one */ \
+ memset((ctx)->block + __md_i, 0, sizeof((ctx)->block) - __md_i); \
+ \
+ f((ctx), (ctx)->block); \
+ __md_i = 0; \
+ } \
+ memset((ctx)->block + __md_i, 0, \
+ sizeof((ctx)->block) - (size) - __md_i); \
+ \
+ } while (0)
+
+#endif /* NETTLE_MACROS_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/mini-gmp.c b/external/nettle-3.3/nettle/mini-gmp.c
new file mode 100644
index 0000000..e64a3da
--- /dev/null
+++ b/external/nettle-3.3/nettle/mini-gmp.c
@@ -0,0 +1,4386 @@
+/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
+
+ Contributed to the GNU project by Niels Möller
+
+Copyright 1991-1997, 1999-2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+or
+
+ * the GNU General Public License as published by the Free Software
+ Foundation; either version 3 of the License, or (at your option) any
+ later version.
+
+or both in parallel, as here.
+
+The GNU MP 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 General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library. If not,
+see https://www.gnu.org/licenses/. */
+
+/* NOTE: All functions in this file which are not declared in
+ mini-gmp.h are internal, and are not intended to be compatible
+ neither with GMP nor with future versions of mini-gmp. */
+
+/* Much of the material copied from GMP files, including: gmp-impl.h,
+ longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c,
+ mpn/generic/lshift.c, mpn/generic/mul_1.c,
+ mpn/generic/mul_basecase.c, mpn/generic/rshift.c,
+ mpn/generic/sbpi1_div_qr.c, mpn/generic/sub_n.c,
+ mpn/generic/submul_1.c. */
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mini-gmp.h"
+
+
+/* Macros */
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+
+#define GMP_LIMB_MAX (~ (mp_limb_t) 0)
+#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1))
+
+#define GMP_HLIMB_BIT ((mp_limb_t) 1 << (GMP_LIMB_BITS / 2))
+#define GMP_LLIMB_MASK (GMP_HLIMB_BIT - 1)
+
+#define GMP_ULONG_BITS (sizeof(unsigned long) * CHAR_BIT)
+#define GMP_ULONG_HIGHBIT ((unsigned long) 1 << (GMP_ULONG_BITS - 1))
+
+#define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
+#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1))
+
+#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
+#define GMP_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define gmp_assert_nocarry(x) do { \
+ mp_limb_t __cy = x; \
+ assert (__cy == 0); \
+ } while (0)
+
+#define gmp_clz(count, x) do { \
+ mp_limb_t __clz_x = (x); \
+ unsigned __clz_c; \
+ for (__clz_c = 0; \
+ (__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0; \
+ __clz_c += 8) \
+ __clz_x <<= 8; \
+ for (; (__clz_x & GMP_LIMB_HIGHBIT) == 0; __clz_c++) \
+ __clz_x <<= 1; \
+ (count) = __clz_c; \
+ } while (0)
+
+#define gmp_ctz(count, x) do { \
+ mp_limb_t __ctz_x = (x); \
+ unsigned __ctz_c = 0; \
+ gmp_clz (__ctz_c, __ctz_x & - __ctz_x); \
+ (count) = GMP_LIMB_BITS - 1 - __ctz_c; \
+ } while (0)
+
+#define gmp_add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ do { \
+ mp_limb_t __x; \
+ __x = (al) + (bl); \
+ (sh) = (ah) + (bh) + (__x < (al)); \
+ (sl) = __x; \
+ } while (0)
+
+#define gmp_sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ do { \
+ mp_limb_t __x; \
+ __x = (al) - (bl); \
+ (sh) = (ah) - (bh) - ((al) < (bl)); \
+ (sl) = __x; \
+ } while (0)
+
+#define gmp_umul_ppmm(w1, w0, u, v) \
+ do { \
+ mp_limb_t __x0, __x1, __x2, __x3; \
+ unsigned __ul, __vl, __uh, __vh; \
+ mp_limb_t __u = (u), __v = (v); \
+ \
+ __ul = __u & GMP_LLIMB_MASK; \
+ __uh = __u >> (GMP_LIMB_BITS / 2); \
+ __vl = __v & GMP_LLIMB_MASK; \
+ __vh = __v >> (GMP_LIMB_BITS / 2); \
+ \
+ __x0 = (mp_limb_t) __ul * __vl; \
+ __x1 = (mp_limb_t) __ul * __vh; \
+ __x2 = (mp_limb_t) __uh * __vl; \
+ __x3 = (mp_limb_t) __uh * __vh; \
+ \
+ __x1 += __x0 >> (GMP_LIMB_BITS / 2);/* this can't give carry */ \
+ __x1 += __x2; /* but this indeed can */ \
+ if (__x1 < __x2) /* did we get it? */ \
+ __x3 += GMP_HLIMB_BIT; /* yes, add it in the proper pos. */ \
+ \
+ (w1) = __x3 + (__x1 >> (GMP_LIMB_BITS / 2)); \
+ (w0) = (__x1 << (GMP_LIMB_BITS / 2)) + (__x0 & GMP_LLIMB_MASK); \
+ } while (0)
+
+#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di) \
+ do { \
+ mp_limb_t _qh, _ql, _r, _mask; \
+ gmp_umul_ppmm (_qh, _ql, (nh), (di)); \
+ gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl)); \
+ _r = (nl) - _qh * (d); \
+ _mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */ \
+ _qh += _mask; \
+ _r += _mask & (d); \
+ if (_r >= (d)) \
+ { \
+ _r -= (d); \
+ _qh++; \
+ } \
+ \
+ (r) = _r; \
+ (q) = _qh; \
+ } while (0)
+
+#define gmp_udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv) \
+ do { \
+ mp_limb_t _q0, _t1, _t0, _mask; \
+ gmp_umul_ppmm ((q), _q0, (n2), (dinv)); \
+ gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1)); \
+ \
+ /* Compute the two most significant limbs of n - q'd */ \
+ (r1) = (n1) - (d1) * (q); \
+ gmp_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0)); \
+ gmp_umul_ppmm (_t1, _t0, (d0), (q)); \
+ gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0); \
+ (q)++; \
+ \
+ /* Conditionally adjust q and the remainders */ \
+ _mask = - (mp_limb_t) ((r1) >= _q0); \
+ (q) += _mask; \
+ gmp_add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0)); \
+ if ((r1) >= (d1)) \
+ { \
+ if ((r1) > (d1) || (r0) >= (d0)) \
+ { \
+ (q)++; \
+ gmp_sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0)); \
+ } \
+ } \
+ } while (0)
+
+/* Swap macros. */
+#define MP_LIMB_T_SWAP(x, y) \
+ do { \
+ mp_limb_t __mp_limb_t_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mp_limb_t_swap__tmp; \
+ } while (0)
+#define MP_SIZE_T_SWAP(x, y) \
+ do { \
+ mp_size_t __mp_size_t_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mp_size_t_swap__tmp; \
+ } while (0)
+#define MP_BITCNT_T_SWAP(x,y) \
+ do { \
+ mp_bitcnt_t __mp_bitcnt_t_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mp_bitcnt_t_swap__tmp; \
+ } while (0)
+#define MP_PTR_SWAP(x, y) \
+ do { \
+ mp_ptr __mp_ptr_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mp_ptr_swap__tmp; \
+ } while (0)
+#define MP_SRCPTR_SWAP(x, y) \
+ do { \
+ mp_srcptr __mp_srcptr_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mp_srcptr_swap__tmp; \
+ } while (0)
+
+#define MPN_PTR_SWAP(xp,xs, yp,ys) \
+ do { \
+ MP_PTR_SWAP (xp, yp); \
+ MP_SIZE_T_SWAP (xs, ys); \
+ } while(0)
+#define MPN_SRCPTR_SWAP(xp,xs, yp,ys) \
+ do { \
+ MP_SRCPTR_SWAP (xp, yp); \
+ MP_SIZE_T_SWAP (xs, ys); \
+ } while(0)
+
+#define MPZ_PTR_SWAP(x, y) \
+ do { \
+ mpz_ptr __mpz_ptr_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mpz_ptr_swap__tmp; \
+ } while (0)
+#define MPZ_SRCPTR_SWAP(x, y) \
+ do { \
+ mpz_srcptr __mpz_srcptr_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mpz_srcptr_swap__tmp; \
+ } while (0)
+
+const int mp_bits_per_limb = GMP_LIMB_BITS;
+
+
+/* Memory allocation and other helper functions. */
+static void
+gmp_die (const char *msg)
+{
+ fprintf (stderr, "%s\n", msg);
+ abort();
+}
+
+static void *
+gmp_default_alloc (size_t size)
+{
+ void *p;
+
+ assert (size > 0);
+
+ p = malloc (size);
+ if (!p)
+ gmp_die("gmp_default_alloc: Virtual memory exhausted.");
+
+ return p;
+}
+
+static void *
+gmp_default_realloc (void *old, size_t old_size, size_t new_size)
+{
+ mp_ptr p;
+
+ p = realloc (old, new_size);
+
+ if (!p)
+ gmp_die("gmp_default_realoc: Virtual memory exhausted.");
+
+ return p;
+}
+
+static void
+gmp_default_free (void *p, size_t size)
+{
+ free (p);
+}
+
+static void * (*gmp_allocate_func) (size_t) = gmp_default_alloc;
+static void * (*gmp_reallocate_func) (void *, size_t, size_t) = gmp_default_realloc;
+static void (*gmp_free_func) (void *, size_t) = gmp_default_free;
+
+void
+mp_get_memory_functions (void *(**alloc_func) (size_t),
+ void *(**realloc_func) (void *, size_t, size_t),
+ void (**free_func) (void *, size_t))
+{
+ if (alloc_func)
+ *alloc_func = gmp_allocate_func;
+
+ if (realloc_func)
+ *realloc_func = gmp_reallocate_func;
+
+ if (free_func)
+ *free_func = gmp_free_func;
+}
+
+void
+mp_set_memory_functions (void *(*alloc_func) (size_t),
+ void *(*realloc_func) (void *, size_t, size_t),
+ void (*free_func) (void *, size_t))
+{
+ if (!alloc_func)
+ alloc_func = gmp_default_alloc;
+ if (!realloc_func)
+ realloc_func = gmp_default_realloc;
+ if (!free_func)
+ free_func = gmp_default_free;
+
+ gmp_allocate_func = alloc_func;
+ gmp_reallocate_func = realloc_func;
+ gmp_free_func = free_func;
+}
+
+#define gmp_xalloc(size) ((*gmp_allocate_func)((size)))
+#define gmp_free(p) ((*gmp_free_func) ((p), 0))
+
+static mp_ptr
+gmp_xalloc_limbs (mp_size_t size)
+{
+ return gmp_xalloc (size * sizeof (mp_limb_t));
+}
+
+static mp_ptr
+gmp_xrealloc_limbs (mp_ptr old, mp_size_t size)
+{
+ assert (size > 0);
+ return (*gmp_reallocate_func) (old, 0, size * sizeof (mp_limb_t));
+}
+
+
+/* MPN interface */
+
+void
+mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n)
+{
+ mp_size_t i;
+ for (i = 0; i < n; i++)
+ d[i] = s[i];
+}
+
+void
+mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n)
+{
+ while (n-- > 0)
+ d[n] = s[n];
+}
+
+int
+mpn_cmp (mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+ while (--n >= 0)
+ {
+ if (ap[n] != bp[n])
+ return ap[n] > bp[n] ? 1 : -1;
+ }
+ return 0;
+}
+
+static int
+mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+ if (an != bn)
+ return an < bn ? -1 : 1;
+ else
+ return mpn_cmp (ap, bp, an);
+}
+
+static mp_size_t
+mpn_normalized_size (mp_srcptr xp, mp_size_t n)
+{
+ for (; n > 0 && xp[n-1] == 0; n--)
+ ;
+ return n;
+}
+
+#define mpn_zero_p(xp, n) (mpn_normalized_size ((xp), (n)) == 0)
+
+void
+mpn_zero (mp_ptr rp, mp_size_t n)
+{
+ mp_size_t i;
+
+ for (i = 0; i < n; i++)
+ rp[i] = 0;
+}
+
+mp_limb_t
+mpn_add_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+ mp_size_t i;
+
+ assert (n > 0);
+ i = 0;
+ do
+ {
+ mp_limb_t r = ap[i] + b;
+ /* Carry out */
+ b = (r < b);
+ rp[i] = r;
+ }
+ while (++i < n);
+
+ return b;
+}
+
+mp_limb_t
+mpn_add_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+ mp_size_t i;
+ mp_limb_t cy;
+
+ for (i = 0, cy = 0; i < n; i++)
+ {
+ mp_limb_t a, b, r;
+ a = ap[i]; b = bp[i];
+ r = a + cy;
+ cy = (r < cy);
+ r += b;
+ cy += (r < b);
+ rp[i] = r;
+ }
+ return cy;
+}
+
+mp_limb_t
+mpn_add (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+ mp_limb_t cy;
+
+ assert (an >= bn);
+
+ cy = mpn_add_n (rp, ap, bp, bn);
+ if (an > bn)
+ cy = mpn_add_1 (rp + bn, ap + bn, an - bn, cy);
+ return cy;
+}
+
+mp_limb_t
+mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+ mp_size_t i;
+
+ assert (n > 0);
+
+ i = 0;
+ do
+ {
+ mp_limb_t a = ap[i];
+ /* Carry out */
+ mp_limb_t cy = a < b;;
+ rp[i] = a - b;
+ b = cy;
+ }
+ while (++i < n);
+
+ return b;
+}
+
+mp_limb_t
+mpn_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+ mp_size_t i;
+ mp_limb_t cy;
+
+ for (i = 0, cy = 0; i < n; i++)
+ {
+ mp_limb_t a, b;
+ a = ap[i]; b = bp[i];
+ b += cy;
+ cy = (b < cy);
+ cy += (a < b);
+ rp[i] = a - b;
+ }
+ return cy;
+}
+
+mp_limb_t
+mpn_sub (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+ mp_limb_t cy;
+
+ assert (an >= bn);
+
+ cy = mpn_sub_n (rp, ap, bp, bn);
+ if (an > bn)
+ cy = mpn_sub_1 (rp + bn, ap + bn, an - bn, cy);
+ return cy;
+}
+
+mp_limb_t
+mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+ mp_limb_t ul, cl, hpl, lpl;
+
+ assert (n >= 1);
+
+ cl = 0;
+ do
+ {
+ ul = *up++;
+ gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+ lpl += cl;
+ cl = (lpl < cl) + hpl;
+
+ *rp++ = lpl;
+ }
+ while (--n != 0);
+
+ return cl;
+}
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+ mp_limb_t ul, cl, hpl, lpl, rl;
+
+ assert (n >= 1);
+
+ cl = 0;
+ do
+ {
+ ul = *up++;
+ gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+ lpl += cl;
+ cl = (lpl < cl) + hpl;
+
+ rl = *rp;
+ lpl = rl + lpl;
+ cl += lpl < rl;
+ *rp++ = lpl;
+ }
+ while (--n != 0);
+
+ return cl;
+}
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+ mp_limb_t ul, cl, hpl, lpl, rl;
+
+ assert (n >= 1);
+
+ cl = 0;
+ do
+ {
+ ul = *up++;
+ gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+ lpl += cl;
+ cl = (lpl < cl) + hpl;
+
+ rl = *rp;
+ lpl = rl - lpl;
+ cl += lpl > rl;
+ *rp++ = lpl;
+ }
+ while (--n != 0);
+
+ return cl;
+}
+
+mp_limb_t
+mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
+{
+ assert (un >= vn);
+ assert (vn >= 1);
+
+ /* We first multiply by the low order limb. This result can be
+ stored, not added, to rp. We also avoid a loop for zeroing this
+ way. */
+
+ rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
+ rp += 1, vp += 1, vn -= 1;
+
+ /* Now accumulate the product of up[] and the next higher limb from
+ vp[]. */
+
+ while (vn >= 1)
+ {
+ rp[un] = mpn_addmul_1 (rp, up, un, vp[0]);
+ rp += 1, vp += 1, vn -= 1;
+ }
+ return rp[un - 1];
+}
+
+void
+mpn_mul_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+ mpn_mul (rp, ap, n, bp, n);
+}
+
+void
+mpn_sqr (mp_ptr rp, mp_srcptr ap, mp_size_t n)
+{
+ mpn_mul (rp, ap, n, ap, n);
+}
+
+mp_limb_t
+mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+ mp_limb_t high_limb, low_limb;
+ unsigned int tnc;
+ mp_size_t i;
+ mp_limb_t retval;
+
+ assert (n >= 1);
+ assert (cnt >= 1);
+ assert (cnt < GMP_LIMB_BITS);
+
+ up += n;
+ rp += n;
+
+ tnc = GMP_LIMB_BITS - cnt;
+ low_limb = *--up;
+ retval = low_limb >> tnc;
+ high_limb = (low_limb << cnt);
+
+ for (i = n; --i != 0;)
+ {
+ low_limb = *--up;
+ *--rp = high_limb | (low_limb >> tnc);
+ high_limb = (low_limb << cnt);
+ }
+ *--rp = high_limb;
+
+ return retval;
+}
+
+mp_limb_t
+mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+ mp_limb_t high_limb, low_limb;
+ unsigned int tnc;
+ mp_size_t i;
+ mp_limb_t retval;
+
+ assert (n >= 1);
+ assert (cnt >= 1);
+ assert (cnt < GMP_LIMB_BITS);
+
+ tnc = GMP_LIMB_BITS - cnt;
+ high_limb = *up++;
+ retval = (high_limb << tnc);
+ low_limb = high_limb >> cnt;
+
+ for (i = n; --i != 0;)
+ {
+ high_limb = *up++;
+ *rp++ = low_limb | (high_limb << tnc);
+ low_limb = high_limb >> cnt;
+ }
+ *rp = low_limb;
+
+ return retval;
+}
+
+static mp_bitcnt_t
+mpn_common_scan (mp_limb_t limb, mp_size_t i, mp_srcptr up, mp_size_t un,
+ mp_limb_t ux)
+{
+ unsigned cnt;
+
+ assert (ux == 0 || ux == GMP_LIMB_MAX);
+ assert (0 <= i && i <= un );
+
+ while (limb == 0)
+ {
+ i++;
+ if (i == un)
+ return (ux == 0 ? ~(mp_bitcnt_t) 0 : un * GMP_LIMB_BITS);
+ limb = ux ^ up[i];
+ }
+ gmp_ctz (cnt, limb);
+ return (mp_bitcnt_t) i * GMP_LIMB_BITS + cnt;
+}
+
+mp_bitcnt_t
+mpn_scan1 (mp_srcptr ptr, mp_bitcnt_t bit)
+{
+ mp_size_t i;
+ i = bit / GMP_LIMB_BITS;
+
+ return mpn_common_scan ( ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
+ i, ptr, i, 0);
+}
+
+mp_bitcnt_t
+mpn_scan0 (mp_srcptr ptr, mp_bitcnt_t bit)
+{
+ mp_size_t i;
+ i = bit / GMP_LIMB_BITS;
+
+ return mpn_common_scan (~ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
+ i, ptr, i, GMP_LIMB_MAX);
+}
+
+
+/* MPN division interface. */
+mp_limb_t
+mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
+{
+ mp_limb_t r, p, m;
+ unsigned ul, uh;
+ unsigned ql, qh;
+
+ /* First, do a 2/1 inverse. */
+ /* The inverse m is defined as floor( (B^2 - 1 - u1)/u1 ), so that 0 <
+ * B^2 - (B + m) u1 <= u1 */
+ assert (u1 >= GMP_LIMB_HIGHBIT);
+
+ ul = u1 & GMP_LLIMB_MASK;
+ uh = u1 >> (GMP_LIMB_BITS / 2);
+
+ qh = ~u1 / uh;
+ r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK;
+
+ p = (mp_limb_t) qh * ul;
+ /* Adjustment steps taken from udiv_qrnnd_c */
+ if (r < p)
+ {
+ qh--;
+ r += u1;
+ if (r >= u1) /* i.e. we didn't get carry when adding to r */
+ if (r < p)
+ {
+ qh--;
+ r += u1;
+ }
+ }
+ r -= p;
+
+ /* Do a 3/2 division (with half limb size) */
+ p = (r >> (GMP_LIMB_BITS / 2)) * qh + r;
+ ql = (p >> (GMP_LIMB_BITS / 2)) + 1;
+
+ /* By the 3/2 method, we don't need the high half limb. */
+ r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1;
+
+ if (r >= (p << (GMP_LIMB_BITS / 2)))
+ {
+ ql--;
+ r += u1;
+ }
+ m = ((mp_limb_t) qh << (GMP_LIMB_BITS / 2)) + ql;
+ if (r >= u1)
+ {
+ m++;
+ r -= u1;
+ }
+
+ if (u0 > 0)
+ {
+ mp_limb_t th, tl;
+ r = ~r;
+ r += u0;
+ if (r < u0)
+ {
+ m--;
+ if (r >= u1)
+ {
+ m--;
+ r -= u1;
+ }
+ r -= u1;
+ }
+ gmp_umul_ppmm (th, tl, u0, m);
+ r += th;
+ if (r < th)
+ {
+ m--;
+ m -= ((r > u1) | ((r == u1) & (tl > u0)));
+ }
+ }
+
+ return m;
+}
+
+struct gmp_div_inverse
+{
+ /* Normalization shift count. */
+ unsigned shift;
+ /* Normalized divisor (d0 unused for mpn_div_qr_1) */
+ mp_limb_t d1, d0;
+ /* Inverse, for 2/1 or 3/2. */
+ mp_limb_t di;
+};
+
+static void
+mpn_div_qr_1_invert (struct gmp_div_inverse *inv, mp_limb_t d)
+{
+ unsigned shift;
+
+ assert (d > 0);
+ gmp_clz (shift, d);
+ inv->shift = shift;
+ inv->d1 = d << shift;
+ inv->di = mpn_invert_limb (inv->d1);
+}
+
+static void
+mpn_div_qr_2_invert (struct gmp_div_inverse *inv,
+ mp_limb_t d1, mp_limb_t d0)
+{
+ unsigned shift;
+
+ assert (d1 > 0);
+ gmp_clz (shift, d1);
+ inv->shift = shift;
+ if (shift > 0)
+ {
+ d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
+ d0 <<= shift;
+ }
+ inv->d1 = d1;
+ inv->d0 = d0;
+ inv->di = mpn_invert_3by2 (d1, d0);
+}
+
+static void
+mpn_div_qr_invert (struct gmp_div_inverse *inv,
+ mp_srcptr dp, mp_size_t dn)
+{
+ assert (dn > 0);
+
+ if (dn == 1)
+ mpn_div_qr_1_invert (inv, dp[0]);
+ else if (dn == 2)
+ mpn_div_qr_2_invert (inv, dp[1], dp[0]);
+ else
+ {
+ unsigned shift;
+ mp_limb_t d1, d0;
+
+ d1 = dp[dn-1];
+ d0 = dp[dn-2];
+ assert (d1 > 0);
+ gmp_clz (shift, d1);
+ inv->shift = shift;
+ if (shift > 0)
+ {
+ d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
+ d0 = (d0 << shift) | (dp[dn-3] >> (GMP_LIMB_BITS - shift));
+ }
+ inv->d1 = d1;
+ inv->d0 = d0;
+ inv->di = mpn_invert_3by2 (d1, d0);
+ }
+}
+
+/* Not matching current public gmp interface, rather corresponding to
+ the sbpi1_div_* functions. */
+static mp_limb_t
+mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
+ const struct gmp_div_inverse *inv)
+{
+ mp_limb_t d, di;
+ mp_limb_t r;
+ mp_ptr tp = NULL;
+
+ if (inv->shift > 0)
+ {
+ tp = gmp_xalloc_limbs (nn);
+ r = mpn_lshift (tp, np, nn, inv->shift);
+ np = tp;
+ }
+ else
+ r = 0;
+
+ d = inv->d1;
+ di = inv->di;
+ while (nn-- > 0)
+ {
+ mp_limb_t q;
+
+ gmp_udiv_qrnnd_preinv (q, r, r, np[nn], d, di);
+ if (qp)
+ qp[nn] = q;
+ }
+ if (inv->shift > 0)
+ gmp_free (tp);
+
+ return r >> inv->shift;
+}
+
+static mp_limb_t
+mpn_div_qr_1 (mp_ptr qp, mp_srcptr np, mp_size_t nn, mp_limb_t d)
+{
+ assert (d > 0);
+
+ /* Special case for powers of two. */
+ if ((d & (d-1)) == 0)
+ {
+ mp_limb_t r = np[0] & (d-1);
+ if (qp)
+ {
+ if (d <= 1)
+ mpn_copyi (qp, np, nn);
+ else
+ {
+ unsigned shift;
+ gmp_ctz (shift, d);
+ mpn_rshift (qp, np, nn, shift);
+ }
+ }
+ return r;
+ }
+ else
+ {
+ struct gmp_div_inverse inv;
+ mpn_div_qr_1_invert (&inv, d);
+ return mpn_div_qr_1_preinv (qp, np, nn, &inv);
+ }
+}
+
+static void
+mpn_div_qr_2_preinv (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+ const struct gmp_div_inverse *inv)
+{
+ unsigned shift;
+ mp_size_t i;
+ mp_limb_t d1, d0, di, r1, r0;
+ mp_ptr tp;
+
+ assert (nn >= 2);
+ shift = inv->shift;
+ d1 = inv->d1;
+ d0 = inv->d0;
+ di = inv->di;
+
+ if (shift > 0)
+ {
+ tp = gmp_xalloc_limbs (nn);
+ r1 = mpn_lshift (tp, np, nn, shift);
+ np = tp;
+ }
+ else
+ r1 = 0;
+
+ r0 = np[nn - 1];
+
+ i = nn - 2;
+ do
+ {
+ mp_limb_t n0, q;
+ n0 = np[i];
+ gmp_udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di);
+
+ if (qp)
+ qp[i] = q;
+ }
+ while (--i >= 0);
+
+ if (shift > 0)
+ {
+ assert ((r0 << (GMP_LIMB_BITS - shift)) == 0);
+ r0 = (r0 >> shift) | (r1 << (GMP_LIMB_BITS - shift));
+ r1 >>= shift;
+
+ gmp_free (tp);
+ }
+
+ rp[1] = r1;
+ rp[0] = r0;
+}
+
+#if 0
+static void
+mpn_div_qr_2 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+ mp_limb_t d1, mp_limb_t d0)
+{
+ struct gmp_div_inverse inv;
+ assert (nn >= 2);
+
+ mpn_div_qr_2_invert (&inv, d1, d0);
+ mpn_div_qr_2_preinv (qp, rp, np, nn, &inv);
+}
+#endif
+
+static void
+mpn_div_qr_pi1 (mp_ptr qp,
+ mp_ptr np, mp_size_t nn, mp_limb_t n1,
+ mp_srcptr dp, mp_size_t dn,
+ mp_limb_t dinv)
+{
+ mp_size_t i;
+
+ mp_limb_t d1, d0;
+ mp_limb_t cy, cy1;
+ mp_limb_t q;
+
+ assert (dn > 2);
+ assert (nn >= dn);
+
+ d1 = dp[dn - 1];
+ d0 = dp[dn - 2];
+
+ assert ((d1 & GMP_LIMB_HIGHBIT) != 0);
+ /* Iteration variable is the index of the q limb.
+ *
+ * We divide <n1, np[dn-1+i], np[dn-2+i], np[dn-3+i],..., np[i]>
+ * by <d1, d0, dp[dn-3], ..., dp[0] >
+ */
+
+ i = nn - dn;
+ do
+ {
+ mp_limb_t n0 = np[dn-1+i];
+
+ if (n1 == d1 && n0 == d0)
+ {
+ q = GMP_LIMB_MAX;
+ mpn_submul_1 (np+i, dp, dn, q);
+ n1 = np[dn-1+i]; /* update n1, last loop's value will now be invalid */
+ }
+ else
+ {
+ gmp_udiv_qr_3by2 (q, n1, n0, n1, n0, np[dn-2+i], d1, d0, dinv);
+
+ cy = mpn_submul_1 (np + i, dp, dn-2, q);
+
+ cy1 = n0 < cy;
+ n0 = n0 - cy;
+ cy = n1 < cy1;
+ n1 = n1 - cy1;
+ np[dn-2+i] = n0;
+
+ if (cy != 0)
+ {
+ n1 += d1 + mpn_add_n (np + i, np + i, dp, dn - 1);
+ q--;
+ }
+ }
+
+ if (qp)
+ qp[i] = q;
+ }
+ while (--i >= 0);
+
+ np[dn - 1] = n1;
+}
+
+static void
+mpn_div_qr_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
+ mp_srcptr dp, mp_size_t dn,
+ const struct gmp_div_inverse *inv)
+{
+ assert (dn > 0);
+ assert (nn >= dn);
+
+ if (dn == 1)
+ np[0] = mpn_div_qr_1_preinv (qp, np, nn, inv);
+ else if (dn == 2)
+ mpn_div_qr_2_preinv (qp, np, np, nn, inv);
+ else
+ {
+ mp_limb_t nh;
+ unsigned shift;
+
+ assert (inv->d1 == dp[dn-1]);
+ assert (inv->d0 == dp[dn-2]);
+ assert ((inv->d1 & GMP_LIMB_HIGHBIT) != 0);
+
+ shift = inv->shift;
+ if (shift > 0)
+ nh = mpn_lshift (np, np, nn, shift);
+ else
+ nh = 0;
+
+ mpn_div_qr_pi1 (qp, np, nn, nh, dp, dn, inv->di);
+
+ if (shift > 0)
+ gmp_assert_nocarry (mpn_rshift (np, np, dn, shift));
+ }
+}
+
+static void
+mpn_div_qr (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
+{
+ struct gmp_div_inverse inv;
+ mp_ptr tp = NULL;
+
+ assert (dn > 0);
+ assert (nn >= dn);
+
+ mpn_div_qr_invert (&inv, dp, dn);
+ if (dn > 2 && inv.shift > 0)
+ {
+ tp = gmp_xalloc_limbs (dn);
+ gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift));
+ dp = tp;
+ }
+ mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv);
+ if (tp)
+ gmp_free (tp);
+}
+
+
+/* MPN base conversion. */
+static unsigned
+mpn_base_power_of_two_p (unsigned b)
+{
+ switch (b)
+ {
+ case 2: return 1;
+ case 4: return 2;
+ case 8: return 3;
+ case 16: return 4;
+ case 32: return 5;
+ case 64: return 6;
+ case 128: return 7;
+ case 256: return 8;
+ default: return 0;
+ }
+}
+
+struct mpn_base_info
+{
+ /* bb is the largest power of the base which fits in one limb, and
+ exp is the corresponding exponent. */
+ unsigned exp;
+ mp_limb_t bb;
+};
+
+static void
+mpn_get_base_info (struct mpn_base_info *info, mp_limb_t b)
+{
+ mp_limb_t m;
+ mp_limb_t p;
+ unsigned exp;
+
+ m = GMP_LIMB_MAX / b;
+ for (exp = 1, p = b; p <= m; exp++)
+ p *= b;
+
+ info->exp = exp;
+ info->bb = p;
+}
+
+static mp_bitcnt_t
+mpn_limb_size_in_base_2 (mp_limb_t u)
+{
+ unsigned shift;
+
+ assert (u > 0);
+ gmp_clz (shift, u);
+ return GMP_LIMB_BITS - shift;
+}
+
+static size_t
+mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un)
+{
+ unsigned char mask;
+ size_t sn, j;
+ mp_size_t i;
+ int shift;
+
+ sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1])
+ + bits - 1) / bits;
+
+ mask = (1U << bits) - 1;
+
+ for (i = 0, j = sn, shift = 0; j-- > 0;)
+ {
+ unsigned char digit = up[i] >> shift;
+
+ shift += bits;
+
+ if (shift >= GMP_LIMB_BITS && ++i < un)
+ {
+ shift -= GMP_LIMB_BITS;
+ digit |= up[i] << (bits - shift);
+ }
+ sp[j] = digit & mask;
+ }
+ return sn;
+}
+
+/* We generate digits from the least significant end, and reverse at
+ the end. */
+static size_t
+mpn_limb_get_str (unsigned char *sp, mp_limb_t w,
+ const struct gmp_div_inverse *binv)
+{
+ mp_size_t i;
+ for (i = 0; w > 0; i++)
+ {
+ mp_limb_t h, l, r;
+
+ h = w >> (GMP_LIMB_BITS - binv->shift);
+ l = w << binv->shift;
+
+ gmp_udiv_qrnnd_preinv (w, r, h, l, binv->d1, binv->di);
+ assert ( (r << (GMP_LIMB_BITS - binv->shift)) == 0);
+ r >>= binv->shift;
+
+ sp[i] = r;
+ }
+ return i;
+}
+
+static size_t
+mpn_get_str_other (unsigned char *sp,
+ int base, const struct mpn_base_info *info,
+ mp_ptr up, mp_size_t un)
+{
+ struct gmp_div_inverse binv;
+ size_t sn;
+ size_t i;
+
+ mpn_div_qr_1_invert (&binv, base);
+
+ sn = 0;
+
+ if (un > 1)
+ {
+ struct gmp_div_inverse bbinv;
+ mpn_div_qr_1_invert (&bbinv, info->bb);
+
+ do
+ {
+ mp_limb_t w;
+ size_t done;
+ w = mpn_div_qr_1_preinv (up, up, un, &bbinv);
+ un -= (up[un-1] == 0);
+ done = mpn_limb_get_str (sp + sn, w, &binv);
+
+ for (sn += done; done < info->exp; done++)
+ sp[sn++] = 0;
+ }
+ while (un > 1);
+ }
+ sn += mpn_limb_get_str (sp + sn, up[0], &binv);
+
+ /* Reverse order */
+ for (i = 0; 2*i + 1 < sn; i++)
+ {
+ unsigned char t = sp[i];
+ sp[i] = sp[sn - i - 1];
+ sp[sn - i - 1] = t;
+ }
+
+ return sn;
+}
+
+size_t
+mpn_get_str (unsigned char *sp, int base, mp_ptr up, mp_size_t un)
+{
+ unsigned bits;
+
+ assert (un > 0);
+ assert (up[un-1] > 0);
+
+ bits = mpn_base_power_of_two_p (base);
+ if (bits)
+ return mpn_get_str_bits (sp, bits, up, un);
+ else
+ {
+ struct mpn_base_info info;
+
+ mpn_get_base_info (&info, base);
+ return mpn_get_str_other (sp, base, &info, up, un);
+ }
+}
+
+static mp_size_t
+mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn,
+ unsigned bits)
+{
+ mp_size_t rn;
+ size_t j;
+ unsigned shift;
+
+ for (j = sn, rn = 0, shift = 0; j-- > 0; )
+ {
+ if (shift == 0)
+ {
+ rp[rn++] = sp[j];
+ shift += bits;
+ }
+ else
+ {
+ rp[rn-1] |= (mp_limb_t) sp[j] << shift;
+ shift += bits;
+ if (shift >= GMP_LIMB_BITS)
+ {
+ shift -= GMP_LIMB_BITS;
+ if (shift > 0)
+ rp[rn++] = (mp_limb_t) sp[j] >> (bits - shift);
+ }
+ }
+ }
+ rn = mpn_normalized_size (rp, rn);
+ return rn;
+}
+
+static mp_size_t
+mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn,
+ mp_limb_t b, const struct mpn_base_info *info)
+{
+ mp_size_t rn;
+ mp_limb_t w;
+ unsigned k;
+ size_t j;
+
+ k = 1 + (sn - 1) % info->exp;
+
+ j = 0;
+ w = sp[j++];
+ for (; --k > 0; )
+ w = w * b + sp[j++];
+
+ rp[0] = w;
+
+ for (rn = (w > 0); j < sn;)
+ {
+ mp_limb_t cy;
+
+ w = sp[j++];
+ for (k = 1; k < info->exp; k++)
+ w = w * b + sp[j++];
+
+ cy = mpn_mul_1 (rp, rp, rn, info->bb);
+ cy += mpn_add_1 (rp, rp, rn, w);
+ if (cy > 0)
+ rp[rn++] = cy;
+ }
+ assert (j == sn);
+
+ return rn;
+}
+
+mp_size_t
+mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base)
+{
+ unsigned bits;
+
+ if (sn == 0)
+ return 0;
+
+ bits = mpn_base_power_of_two_p (base);
+ if (bits)
+ return mpn_set_str_bits (rp, sp, sn, bits);
+ else
+ {
+ struct mpn_base_info info;
+
+ mpn_get_base_info (&info, base);
+ return mpn_set_str_other (rp, sp, sn, base, &info);
+ }
+}
+
+
+/* MPZ interface */
+void
+mpz_init (mpz_t r)
+{
+ r->_mp_alloc = 1;
+ r->_mp_size = 0;
+ r->_mp_d = gmp_xalloc_limbs (1);
+}
+
+/* The utility of this function is a bit limited, since many functions
+ assigns the result variable using mpz_swap. */
+void
+mpz_init2 (mpz_t r, mp_bitcnt_t bits)
+{
+ mp_size_t rn;
+
+ bits -= (bits != 0); /* Round down, except if 0 */
+ rn = 1 + bits / GMP_LIMB_BITS;
+
+ r->_mp_alloc = rn;
+ r->_mp_size = 0;
+ r->_mp_d = gmp_xalloc_limbs (rn);
+}
+
+void
+mpz_clear (mpz_t r)
+{
+ gmp_free (r->_mp_d);
+}
+
+static void *
+mpz_realloc (mpz_t r, mp_size_t size)
+{
+ size = GMP_MAX (size, 1);
+
+ r->_mp_d = gmp_xrealloc_limbs (r->_mp_d, size);
+ r->_mp_alloc = size;
+
+ if (GMP_ABS (r->_mp_size) > size)
+ r->_mp_size = 0;
+
+ return r->_mp_d;
+}
+
+/* Realloc for an mpz_t WHAT if it has less than NEEDED limbs. */
+#define MPZ_REALLOC(z,n) ((n) > (z)->_mp_alloc \
+ ? mpz_realloc(z,n) \
+ : (z)->_mp_d)
+
+/* MPZ assignment and basic conversions. */
+void
+mpz_set_si (mpz_t r, signed long int x)
+{
+ if (x >= 0)
+ mpz_set_ui (r, x);
+ else /* (x < 0) */
+ {
+ r->_mp_size = -1;
+ r->_mp_d[0] = GMP_NEG_CAST (unsigned long int, x);
+ }
+}
+
+void
+mpz_set_ui (mpz_t r, unsigned long int x)
+{
+ if (x > 0)
+ {
+ r->_mp_size = 1;
+ r->_mp_d[0] = x;
+ }
+ else
+ r->_mp_size = 0;
+}
+
+void
+mpz_set (mpz_t r, const mpz_t x)
+{
+ /* Allow the NOP r == x */
+ if (r != x)
+ {
+ mp_size_t n;
+ mp_ptr rp;
+
+ n = GMP_ABS (x->_mp_size);
+ rp = MPZ_REALLOC (r, n);
+
+ mpn_copyi (rp, x->_mp_d, n);
+ r->_mp_size = x->_mp_size;
+ }
+}
+
+void
+mpz_init_set_si (mpz_t r, signed long int x)
+{
+ mpz_init (r);
+ mpz_set_si (r, x);
+}
+
+void
+mpz_init_set_ui (mpz_t r, unsigned long int x)
+{
+ mpz_init (r);
+ mpz_set_ui (r, x);
+}
+
+void
+mpz_init_set (mpz_t r, const mpz_t x)
+{
+ mpz_init (r);
+ mpz_set (r, x);
+}
+
+int
+mpz_fits_slong_p (const mpz_t u)
+{
+ mp_size_t us = u->_mp_size;
+
+ if (us == 0)
+ return 1;
+ else if (us == 1)
+ return u->_mp_d[0] < GMP_LIMB_HIGHBIT;
+ else if (us == -1)
+ return u->_mp_d[0] <= GMP_LIMB_HIGHBIT;
+ else
+ return 0;
+}
+
+int
+mpz_fits_ulong_p (const mpz_t u)
+{
+ mp_size_t us = u->_mp_size;
+
+ return (us == (us > 0));
+}
+
+long int
+mpz_get_si (const mpz_t u)
+{
+ mp_size_t us = u->_mp_size;
+
+ if (us > 0)
+ return (long) (u->_mp_d[0] & ~GMP_LIMB_HIGHBIT);
+ else if (us < 0)
+ return (long) (- u->_mp_d[0] | GMP_LIMB_HIGHBIT);
+ else
+ return 0;
+}
+
+unsigned long int
+mpz_get_ui (const mpz_t u)
+{
+ return u->_mp_size == 0 ? 0 : u->_mp_d[0];
+}
+
+size_t
+mpz_size (const mpz_t u)
+{
+ return GMP_ABS (u->_mp_size);
+}
+
+mp_limb_t
+mpz_getlimbn (const mpz_t u, mp_size_t n)
+{
+ if (n >= 0 && n < GMP_ABS (u->_mp_size))
+ return u->_mp_d[n];
+ else
+ return 0;
+}
+
+void
+mpz_realloc2 (mpz_t x, mp_bitcnt_t n)
+{
+ mpz_realloc (x, 1 + (n - (n != 0)) / GMP_LIMB_BITS);
+}
+
+mp_srcptr
+mpz_limbs_read (mpz_srcptr x)
+{
+ return x->_mp_d;;
+}
+
+mp_ptr
+mpz_limbs_modify (mpz_t x, mp_size_t n)
+{
+ assert (n > 0);
+ return MPZ_REALLOC (x, n);
+}
+
+mp_ptr
+mpz_limbs_write (mpz_t x, mp_size_t n)
+{
+ return mpz_limbs_modify (x, n);
+}
+
+void
+mpz_limbs_finish (mpz_t x, mp_size_t xs)
+{
+ mp_size_t xn;
+ xn = mpn_normalized_size (x->_mp_d, GMP_ABS (xs));
+ x->_mp_size = xs < 0 ? -xn : xn;
+}
+
+mpz_srcptr
+mpz_roinit_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
+{
+ x->_mp_alloc = 0;
+ x->_mp_d = (mp_ptr) xp;
+ mpz_limbs_finish (x, xs);
+ return x;
+}
+
+
+/* Conversions and comparison to double. */
+void
+mpz_set_d (mpz_t r, double x)
+{
+ int sign;
+ mp_ptr rp;
+ mp_size_t rn, i;
+ double B;
+ double Bi;
+ mp_limb_t f;
+
+ /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is
+ zero or infinity. */
+ if (x != x || x == x * 0.5)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ sign = x < 0.0 ;
+ if (sign)
+ x = - x;
+
+ if (x < 1.0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+ B = 2.0 * (double) GMP_LIMB_HIGHBIT;
+ Bi = 1.0 / B;
+ for (rn = 1; x >= B; rn++)
+ x *= Bi;
+
+ rp = MPZ_REALLOC (r, rn);
+
+ f = (mp_limb_t) x;
+ x -= f;
+ assert (x < 1.0);
+ i = rn-1;
+ rp[i] = f;
+ while (--i >= 0)
+ {
+ x = B * x;
+ f = (mp_limb_t) x;
+ x -= f;
+ assert (x < 1.0);
+ rp[i] = f;
+ }
+
+ r->_mp_size = sign ? - rn : rn;
+}
+
+void
+mpz_init_set_d (mpz_t r, double x)
+{
+ mpz_init (r);
+ mpz_set_d (r, x);
+}
+
+double
+mpz_get_d (const mpz_t u)
+{
+ mp_size_t un;
+ double x;
+ double B = 2.0 * (double) GMP_LIMB_HIGHBIT;
+
+ un = GMP_ABS (u->_mp_size);
+
+ if (un == 0)
+ return 0.0;
+
+ x = u->_mp_d[--un];
+ while (un > 0)
+ x = B*x + u->_mp_d[--un];
+
+ if (u->_mp_size < 0)
+ x = -x;
+
+ return x;
+}
+
+int
+mpz_cmpabs_d (const mpz_t x, double d)
+{
+ mp_size_t xn;
+ double B, Bi;
+ mp_size_t i;
+
+ xn = x->_mp_size;
+ d = GMP_ABS (d);
+
+ if (xn != 0)
+ {
+ xn = GMP_ABS (xn);
+
+ B = 2.0 * (double) GMP_LIMB_HIGHBIT;
+ Bi = 1.0 / B;
+
+ /* Scale d so it can be compared with the top limb. */
+ for (i = 1; i < xn; i++)
+ d *= Bi;
+
+ if (d >= B)
+ return -1;
+
+ /* Compare floor(d) to top limb, subtract and cancel when equal. */
+ for (i = xn; i-- > 0;)
+ {
+ mp_limb_t f, xl;
+
+ f = (mp_limb_t) d;
+ xl = x->_mp_d[i];
+ if (xl > f)
+ return 1;
+ else if (xl < f)
+ return -1;
+ d = B * (d - f);
+ }
+ }
+ return - (d > 0.0);
+}
+
+int
+mpz_cmp_d (const mpz_t x, double d)
+{
+ if (x->_mp_size < 0)
+ {
+ if (d >= 0.0)
+ return -1;
+ else
+ return -mpz_cmpabs_d (x, d);
+ }
+ else
+ {
+ if (d < 0.0)
+ return 1;
+ else
+ return mpz_cmpabs_d (x, d);
+ }
+}
+
+
+/* MPZ comparisons and the like. */
+int
+mpz_sgn (const mpz_t u)
+{
+ mp_size_t usize = u->_mp_size;
+
+ return (usize > 0) - (usize < 0);
+}
+
+int
+mpz_cmp_si (const mpz_t u, long v)
+{
+ mp_size_t usize = u->_mp_size;
+
+ if (usize < -1)
+ return -1;
+ else if (v >= 0)
+ return mpz_cmp_ui (u, v);
+ else if (usize >= 0)
+ return 1;
+ else /* usize == -1 */
+ {
+ mp_limb_t ul = u->_mp_d[0];
+ if ((mp_limb_t)GMP_NEG_CAST (unsigned long int, v) < ul)
+ return -1;
+ else
+ return (mp_limb_t)GMP_NEG_CAST (unsigned long int, v) > ul;
+ }
+}
+
+int
+mpz_cmp_ui (const mpz_t u, unsigned long v)
+{
+ mp_size_t usize = u->_mp_size;
+
+ if (usize > 1)
+ return 1;
+ else if (usize < 0)
+ return -1;
+ else
+ {
+ mp_limb_t ul = (usize > 0) ? u->_mp_d[0] : 0;
+ return (ul > v) - (ul < v);
+ }
+}
+
+int
+mpz_cmp (const mpz_t a, const mpz_t b)
+{
+ mp_size_t asize = a->_mp_size;
+ mp_size_t bsize = b->_mp_size;
+
+ if (asize != bsize)
+ return (asize < bsize) ? -1 : 1;
+ else if (asize >= 0)
+ return mpn_cmp (a->_mp_d, b->_mp_d, asize);
+ else
+ return mpn_cmp (b->_mp_d, a->_mp_d, -asize);
+}
+
+int
+mpz_cmpabs_ui (const mpz_t u, unsigned long v)
+{
+ mp_size_t un = GMP_ABS (u->_mp_size);
+ mp_limb_t ul;
+
+ if (un > 1)
+ return 1;
+
+ ul = (un == 1) ? u->_mp_d[0] : 0;
+
+ return (ul > v) - (ul < v);
+}
+
+int
+mpz_cmpabs (const mpz_t u, const mpz_t v)
+{
+ return mpn_cmp4 (u->_mp_d, GMP_ABS (u->_mp_size),
+ v->_mp_d, GMP_ABS (v->_mp_size));
+}
+
+void
+mpz_abs (mpz_t r, const mpz_t u)
+{
+ if (r != u)
+ mpz_set (r, u);
+
+ r->_mp_size = GMP_ABS (r->_mp_size);
+}
+
+void
+mpz_neg (mpz_t r, const mpz_t u)
+{
+ if (r != u)
+ mpz_set (r, u);
+
+ r->_mp_size = -r->_mp_size;
+}
+
+void
+mpz_swap (mpz_t u, mpz_t v)
+{
+ MP_SIZE_T_SWAP (u->_mp_size, v->_mp_size);
+ MP_SIZE_T_SWAP (u->_mp_alloc, v->_mp_alloc);
+ MP_PTR_SWAP (u->_mp_d, v->_mp_d);
+}
+
+
+/* MPZ addition and subtraction */
+
+/* Adds to the absolute value. Returns new size, but doesn't store it. */
+static mp_size_t
+mpz_abs_add_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+ mp_size_t an;
+ mp_ptr rp;
+ mp_limb_t cy;
+
+ an = GMP_ABS (a->_mp_size);
+ if (an == 0)
+ {
+ r->_mp_d[0] = b;
+ return b > 0;
+ }
+
+ rp = MPZ_REALLOC (r, an + 1);
+
+ cy = mpn_add_1 (rp, a->_mp_d, an, b);
+ rp[an] = cy;
+ an += cy;
+
+ return an;
+}
+
+/* Subtract from the absolute value. Returns new size, (or -1 on underflow),
+ but doesn't store it. */
+static mp_size_t
+mpz_abs_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+ mp_size_t an = GMP_ABS (a->_mp_size);
+ mp_ptr rp = MPZ_REALLOC (r, an);
+
+ if (an == 0)
+ {
+ rp[0] = b;
+ return -(b > 0);
+ }
+ else if (an == 1 && a->_mp_d[0] < b)
+ {
+ rp[0] = b - a->_mp_d[0];
+ return -1;
+ }
+ else
+ {
+ gmp_assert_nocarry (mpn_sub_1 (rp, a->_mp_d, an, b));
+ return mpn_normalized_size (rp, an);
+ }
+}
+
+void
+mpz_add_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+ if (a->_mp_size >= 0)
+ r->_mp_size = mpz_abs_add_ui (r, a, b);
+ else
+ r->_mp_size = -mpz_abs_sub_ui (r, a, b);
+}
+
+void
+mpz_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+ if (a->_mp_size < 0)
+ r->_mp_size = -mpz_abs_add_ui (r, a, b);
+ else
+ r->_mp_size = mpz_abs_sub_ui (r, a, b);
+}
+
+void
+mpz_ui_sub (mpz_t r, unsigned long a, const mpz_t b)
+{
+ if (b->_mp_size < 0)
+ r->_mp_size = mpz_abs_add_ui (r, b, a);
+ else
+ r->_mp_size = -mpz_abs_sub_ui (r, b, a);
+}
+
+static mp_size_t
+mpz_abs_add (mpz_t r, const mpz_t a, const mpz_t b)
+{
+ mp_size_t an = GMP_ABS (a->_mp_size);
+ mp_size_t bn = GMP_ABS (b->_mp_size);
+ mp_ptr rp;
+ mp_limb_t cy;
+
+ if (an < bn)
+ {
+ MPZ_SRCPTR_SWAP (a, b);
+ MP_SIZE_T_SWAP (an, bn);
+ }
+
+ rp = MPZ_REALLOC (r, an + 1);
+ cy = mpn_add (rp, a->_mp_d, an, b->_mp_d, bn);
+
+ rp[an] = cy;
+
+ return an + cy;
+}
+
+static mp_size_t
+mpz_abs_sub (mpz_t r, const mpz_t a, const mpz_t b)
+{
+ mp_size_t an = GMP_ABS (a->_mp_size);
+ mp_size_t bn = GMP_ABS (b->_mp_size);
+ int cmp;
+ mp_ptr rp;
+
+ cmp = mpn_cmp4 (a->_mp_d, an, b->_mp_d, bn);
+ if (cmp > 0)
+ {
+ rp = MPZ_REALLOC (r, an);
+ gmp_assert_nocarry (mpn_sub (rp, a->_mp_d, an, b->_mp_d, bn));
+ return mpn_normalized_size (rp, an);
+ }
+ else if (cmp < 0)
+ {
+ rp = MPZ_REALLOC (r, bn);
+ gmp_assert_nocarry (mpn_sub (rp, b->_mp_d, bn, a->_mp_d, an));
+ return -mpn_normalized_size (rp, bn);
+ }
+ else
+ return 0;
+}
+
+void
+mpz_add (mpz_t r, const mpz_t a, const mpz_t b)
+{
+ mp_size_t rn;
+
+ if ( (a->_mp_size ^ b->_mp_size) >= 0)
+ rn = mpz_abs_add (r, a, b);
+ else
+ rn = mpz_abs_sub (r, a, b);
+
+ r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
+}
+
+void
+mpz_sub (mpz_t r, const mpz_t a, const mpz_t b)
+{
+ mp_size_t rn;
+
+ if ( (a->_mp_size ^ b->_mp_size) >= 0)
+ rn = mpz_abs_sub (r, a, b);
+ else
+ rn = mpz_abs_add (r, a, b);
+
+ r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
+}
+
+
+/* MPZ multiplication */
+void
+mpz_mul_si (mpz_t r, const mpz_t u, long int v)
+{
+ if (v < 0)
+ {
+ mpz_mul_ui (r, u, GMP_NEG_CAST (unsigned long int, v));
+ mpz_neg (r, r);
+ }
+ else
+ mpz_mul_ui (r, u, (unsigned long int) v);
+}
+
+void
+mpz_mul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+ mp_size_t un, us;
+ mp_ptr tp;
+ mp_limb_t cy;
+
+ us = u->_mp_size;
+
+ if (us == 0 || v == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ un = GMP_ABS (us);
+
+ tp = MPZ_REALLOC (r, un + 1);
+ cy = mpn_mul_1 (tp, u->_mp_d, un, v);
+ tp[un] = cy;
+
+ un += (cy > 0);
+ r->_mp_size = (us < 0) ? - un : un;
+}
+
+void
+mpz_mul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ int sign;
+ mp_size_t un, vn, rn;
+ mpz_t t;
+ mp_ptr tp;
+
+ un = u->_mp_size;
+ vn = v->_mp_size;
+
+ if (un == 0 || vn == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ sign = (un ^ vn) < 0;
+
+ un = GMP_ABS (un);
+ vn = GMP_ABS (vn);
+
+ mpz_init2 (t, (un + vn) * GMP_LIMB_BITS);
+
+ tp = t->_mp_d;
+ if (un >= vn)
+ mpn_mul (tp, u->_mp_d, un, v->_mp_d, vn);
+ else
+ mpn_mul (tp, v->_mp_d, vn, u->_mp_d, un);
+
+ rn = un + vn;
+ rn -= tp[rn-1] == 0;
+
+ t->_mp_size = sign ? - rn : rn;
+ mpz_swap (r, t);
+ mpz_clear (t);
+}
+
+void
+mpz_mul_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bits)
+{
+ mp_size_t un, rn;
+ mp_size_t limbs;
+ unsigned shift;
+ mp_ptr rp;
+
+ un = GMP_ABS (u->_mp_size);
+ if (un == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ limbs = bits / GMP_LIMB_BITS;
+ shift = bits % GMP_LIMB_BITS;
+
+ rn = un + limbs + (shift > 0);
+ rp = MPZ_REALLOC (r, rn);
+ if (shift > 0)
+ {
+ mp_limb_t cy = mpn_lshift (rp + limbs, u->_mp_d, un, shift);
+ rp[rn-1] = cy;
+ rn -= (cy == 0);
+ }
+ else
+ mpn_copyd (rp + limbs, u->_mp_d, un);
+
+ while (limbs > 0)
+ rp[--limbs] = 0;
+
+ r->_mp_size = (u->_mp_size < 0) ? - rn : rn;
+}
+
+void
+mpz_addmul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+ mpz_t t;
+ mpz_init (t);
+ mpz_mul_ui (t, u, v);
+ mpz_add (r, r, t);
+ mpz_clear (t);
+}
+
+void
+mpz_submul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+ mpz_t t;
+ mpz_init (t);
+ mpz_mul_ui (t, u, v);
+ mpz_sub (r, r, t);
+ mpz_clear (t);
+}
+
+void
+mpz_addmul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mpz_t t;
+ mpz_init (t);
+ mpz_mul (t, u, v);
+ mpz_add (r, r, t);
+ mpz_clear (t);
+}
+
+void
+mpz_submul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mpz_t t;
+ mpz_init (t);
+ mpz_mul (t, u, v);
+ mpz_sub (r, r, t);
+ mpz_clear (t);
+}
+
+
+/* MPZ division */
+enum mpz_div_round_mode { GMP_DIV_FLOOR, GMP_DIV_CEIL, GMP_DIV_TRUNC };
+
+/* Allows q or r to be zero. Returns 1 iff remainder is non-zero. */
+static int
+mpz_div_qr (mpz_t q, mpz_t r,
+ const mpz_t n, const mpz_t d, enum mpz_div_round_mode mode)
+{
+ mp_size_t ns, ds, nn, dn, qs;
+ ns = n->_mp_size;
+ ds = d->_mp_size;
+
+ if (ds == 0)
+ gmp_die("mpz_div_qr: Divide by zero.");
+
+ if (ns == 0)
+ {
+ if (q)
+ q->_mp_size = 0;
+ if (r)
+ r->_mp_size = 0;
+ return 0;
+ }
+
+ nn = GMP_ABS (ns);
+ dn = GMP_ABS (ds);
+
+ qs = ds ^ ns;
+
+ if (nn < dn)
+ {
+ if (mode == GMP_DIV_CEIL && qs >= 0)
+ {
+ /* q = 1, r = n - d */
+ if (r)
+ mpz_sub (r, n, d);
+ if (q)
+ mpz_set_ui (q, 1);
+ }
+ else if (mode == GMP_DIV_FLOOR && qs < 0)
+ {
+ /* q = -1, r = n + d */
+ if (r)
+ mpz_add (r, n, d);
+ if (q)
+ mpz_set_si (q, -1);
+ }
+ else
+ {
+ /* q = 0, r = d */
+ if (r)
+ mpz_set (r, n);
+ if (q)
+ q->_mp_size = 0;
+ }
+ return 1;
+ }
+ else
+ {
+ mp_ptr np, qp;
+ mp_size_t qn, rn;
+ mpz_t tq, tr;
+
+ mpz_init_set (tr, n);
+ np = tr->_mp_d;
+
+ qn = nn - dn + 1;
+
+ if (q)
+ {
+ mpz_init2 (tq, qn * GMP_LIMB_BITS);
+ qp = tq->_mp_d;
+ }
+ else
+ qp = NULL;
+
+ mpn_div_qr (qp, np, nn, d->_mp_d, dn);
+
+ if (qp)
+ {
+ qn -= (qp[qn-1] == 0);
+
+ tq->_mp_size = qs < 0 ? -qn : qn;
+ }
+ rn = mpn_normalized_size (np, dn);
+ tr->_mp_size = ns < 0 ? - rn : rn;
+
+ if (mode == GMP_DIV_FLOOR && qs < 0 && rn != 0)
+ {
+ if (q)
+ mpz_sub_ui (tq, tq, 1);
+ if (r)
+ mpz_add (tr, tr, d);
+ }
+ else if (mode == GMP_DIV_CEIL && qs >= 0 && rn != 0)
+ {
+ if (q)
+ mpz_add_ui (tq, tq, 1);
+ if (r)
+ mpz_sub (tr, tr, d);
+ }
+
+ if (q)
+ {
+ mpz_swap (tq, q);
+ mpz_clear (tq);
+ }
+ if (r)
+ mpz_swap (tr, r);
+
+ mpz_clear (tr);
+
+ return rn != 0;
+ }
+}
+
+void
+mpz_cdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, r, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, r, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, NULL, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (NULL, r, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (NULL, r, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_mod (mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (NULL, r, n, d, d->_mp_size >= 0 ? GMP_DIV_FLOOR : GMP_DIV_CEIL);
+}
+
+static void
+mpz_div_q_2exp (mpz_t q, const mpz_t u, mp_bitcnt_t bit_index,
+ enum mpz_div_round_mode mode)
+{
+ mp_size_t un, qn;
+ mp_size_t limb_cnt;
+ mp_ptr qp;
+ int adjust;
+
+ un = u->_mp_size;
+ if (un == 0)
+ {
+ q->_mp_size = 0;
+ return;
+ }
+ limb_cnt = bit_index / GMP_LIMB_BITS;
+ qn = GMP_ABS (un) - limb_cnt;
+ bit_index %= GMP_LIMB_BITS;
+
+ if (mode == ((un > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* un != 0 here. */
+ /* Note: Below, the final indexing at limb_cnt is valid because at
+ that point we have qn > 0. */
+ adjust = (qn <= 0
+ || !mpn_zero_p (u->_mp_d, limb_cnt)
+ || (u->_mp_d[limb_cnt]
+ & (((mp_limb_t) 1 << bit_index) - 1)));
+ else
+ adjust = 0;
+
+ if (qn <= 0)
+ qn = 0;
+
+ else
+ {
+ qp = MPZ_REALLOC (q, qn);
+
+ if (bit_index != 0)
+ {
+ mpn_rshift (qp, u->_mp_d + limb_cnt, qn, bit_index);
+ qn -= qp[qn - 1] == 0;
+ }
+ else
+ {
+ mpn_copyi (qp, u->_mp_d + limb_cnt, qn);
+ }
+ }
+
+ q->_mp_size = qn;
+
+ if (adjust)
+ mpz_add_ui (q, q, 1);
+ if (un < 0)
+ mpz_neg (q, q);
+}
+
+static void
+mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index,
+ enum mpz_div_round_mode mode)
+{
+ mp_size_t us, un, rn;
+ mp_ptr rp;
+ mp_limb_t mask;
+
+ us = u->_mp_size;
+ if (us == 0 || bit_index == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+ rn = (bit_index + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
+ assert (rn > 0);
+
+ rp = MPZ_REALLOC (r, rn);
+ un = GMP_ABS (us);
+
+ mask = GMP_LIMB_MAX >> (rn * GMP_LIMB_BITS - bit_index);
+
+ if (rn > un)
+ {
+ /* Quotient (with truncation) is zero, and remainder is
+ non-zero */
+ if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
+ {
+ /* Have to negate and sign extend. */
+ mp_size_t i;
+ mp_limb_t cy;
+
+ for (cy = 1, i = 0; i < un; i++)
+ {
+ mp_limb_t s = ~u->_mp_d[i] + cy;
+ cy = s < cy;
+ rp[i] = s;
+ }
+ assert (cy == 0);
+ for (; i < rn - 1; i++)
+ rp[i] = GMP_LIMB_MAX;
+
+ rp[rn-1] = mask;
+ us = -us;
+ }
+ else
+ {
+ /* Just copy */
+ if (r != u)
+ mpn_copyi (rp, u->_mp_d, un);
+
+ rn = un;
+ }
+ }
+ else
+ {
+ if (r != u)
+ mpn_copyi (rp, u->_mp_d, rn - 1);
+
+ rp[rn-1] = u->_mp_d[rn-1] & mask;
+
+ if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
+ {
+ /* If r != 0, compute 2^{bit_count} - r. */
+ mp_size_t i;
+
+ for (i = 0; i < rn && rp[i] == 0; i++)
+ ;
+ if (i < rn)
+ {
+ /* r > 0, need to flip sign. */
+ rp[i] = ~rp[i] + 1;
+ while (++i < rn)
+ rp[i] = ~rp[i];
+
+ rp[rn-1] &= mask;
+
+ /* us is not used for anything else, so we can modify it
+ here to indicate flipped sign. */
+ us = -us;
+ }
+ }
+ }
+ rn = mpn_normalized_size (rp, rn);
+ r->_mp_size = us < 0 ? -rn : rn;
+}
+
+void
+mpz_cdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_q_2exp (r, u, cnt, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_q_2exp (r, u, cnt, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_q_2exp (r, u, cnt, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_r_2exp (r, u, cnt, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_r_2exp (r, u, cnt, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_r_2exp (r, u, cnt, GMP_DIV_TRUNC);
+}
+
+void
+mpz_divexact (mpz_t q, const mpz_t n, const mpz_t d)
+{
+ gmp_assert_nocarry (mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC));
+}
+
+int
+mpz_divisible_p (const mpz_t n, const mpz_t d)
+{
+ return mpz_div_qr (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
+}
+
+int
+mpz_congruent_p (const mpz_t a, const mpz_t b, const mpz_t m)
+{
+ mpz_t t;
+ int res;
+
+ /* a == b (mod 0) iff a == b */
+ if (mpz_sgn (m) == 0)
+ return (mpz_cmp (a, b) == 0);
+
+ mpz_init (t);
+ mpz_sub (t, a, b);
+ res = mpz_divisible_p (t, m);
+ mpz_clear (t);
+
+ return res;
+}
+
+static unsigned long
+mpz_div_qr_ui (mpz_t q, mpz_t r,
+ const mpz_t n, unsigned long d, enum mpz_div_round_mode mode)
+{
+ mp_size_t ns, qn;
+ mp_ptr qp;
+ mp_limb_t rl;
+ mp_size_t rs;
+
+ ns = n->_mp_size;
+ if (ns == 0)
+ {
+ if (q)
+ q->_mp_size = 0;
+ if (r)
+ r->_mp_size = 0;
+ return 0;
+ }
+
+ qn = GMP_ABS (ns);
+ if (q)
+ qp = MPZ_REALLOC (q, qn);
+ else
+ qp = NULL;
+
+ rl = mpn_div_qr_1 (qp, n->_mp_d, qn, d);
+ assert (rl < d);
+
+ rs = rl > 0;
+ rs = (ns < 0) ? -rs : rs;
+
+ if (rl > 0 && ( (mode == GMP_DIV_FLOOR && ns < 0)
+ || (mode == GMP_DIV_CEIL && ns >= 0)))
+ {
+ if (q)
+ gmp_assert_nocarry (mpn_add_1 (qp, qp, qn, 1));
+ rl = d - rl;
+ rs = -rs;
+ }
+
+ if (r)
+ {
+ r->_mp_d[0] = rl;
+ r->_mp_size = rs;
+ }
+ if (q)
+ {
+ qn -= (qp[qn-1] == 0);
+ assert (qn == 0 || qp[qn-1] > 0);
+
+ q->_mp_size = (ns < 0) ? - qn : qn;
+ }
+
+ return rl;
+}
+
+unsigned long
+mpz_cdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, r, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, r, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, r, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_CEIL);
+}
+unsigned long
+mpz_fdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+unsigned long
+mpz_tdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_ui (const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_ui (const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_ui (const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_mod_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_divexact_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+ gmp_assert_nocarry (mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC));
+}
+
+int
+mpz_divisible_ui_p (const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
+}
+
+
+/* GCD */
+static mp_limb_t
+mpn_gcd_11 (mp_limb_t u, mp_limb_t v)
+{
+ unsigned shift;
+
+ assert ( (u | v) > 0);
+
+ if (u == 0)
+ return v;
+ else if (v == 0)
+ return u;
+
+ gmp_ctz (shift, u | v);
+
+ u >>= shift;
+ v >>= shift;
+
+ if ( (u & 1) == 0)
+ MP_LIMB_T_SWAP (u, v);
+
+ while ( (v & 1) == 0)
+ v >>= 1;
+
+ while (u != v)
+ {
+ if (u > v)
+ {
+ u -= v;
+ do
+ u >>= 1;
+ while ( (u & 1) == 0);
+ }
+ else
+ {
+ v -= u;
+ do
+ v >>= 1;
+ while ( (v & 1) == 0);
+ }
+ }
+ return u << shift;
+}
+
+unsigned long
+mpz_gcd_ui (mpz_t g, const mpz_t u, unsigned long v)
+{
+ mp_size_t un;
+
+ if (v == 0)
+ {
+ if (g)
+ mpz_abs (g, u);
+ }
+ else
+ {
+ un = GMP_ABS (u->_mp_size);
+ if (un != 0)
+ v = mpn_gcd_11 (mpn_div_qr_1 (NULL, u->_mp_d, un, v), v);
+
+ if (g)
+ mpz_set_ui (g, v);
+ }
+
+ return v;
+}
+
+static mp_bitcnt_t
+mpz_make_odd (mpz_t r)
+{
+ mp_bitcnt_t shift;
+
+ assert (r->_mp_size > 0);
+ /* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
+ shift = mpn_common_scan (r->_mp_d[0], 0, r->_mp_d, 0, 0);
+ mpz_tdiv_q_2exp (r, r, shift);
+
+ return shift;
+}
+
+void
+mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v)
+{
+ mpz_t tu, tv;
+ mp_bitcnt_t uz, vz, gz;
+
+ if (u->_mp_size == 0)
+ {
+ mpz_abs (g, v);
+ return;
+ }
+ if (v->_mp_size == 0)
+ {
+ mpz_abs (g, u);
+ return;
+ }
+
+ mpz_init (tu);
+ mpz_init (tv);
+
+ mpz_abs (tu, u);
+ uz = mpz_make_odd (tu);
+ mpz_abs (tv, v);
+ vz = mpz_make_odd (tv);
+ gz = GMP_MIN (uz, vz);
+
+ if (tu->_mp_size < tv->_mp_size)
+ mpz_swap (tu, tv);
+
+ mpz_tdiv_r (tu, tu, tv);
+ if (tu->_mp_size == 0)
+ {
+ mpz_swap (g, tv);
+ }
+ else
+ for (;;)
+ {
+ int c;
+
+ mpz_make_odd (tu);
+ c = mpz_cmp (tu, tv);
+ if (c == 0)
+ {
+ mpz_swap (g, tu);
+ break;
+ }
+ if (c < 0)
+ mpz_swap (tu, tv);
+
+ if (tv->_mp_size == 1)
+ {
+ mp_limb_t vl = tv->_mp_d[0];
+ mp_limb_t ul = mpz_tdiv_ui (tu, vl);
+ mpz_set_ui (g, mpn_gcd_11 (ul, vl));
+ break;
+ }
+ mpz_sub (tu, tu, tv);
+ }
+ mpz_clear (tu);
+ mpz_clear (tv);
+ mpz_mul_2exp (g, g, gz);
+}
+
+void
+mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v)
+{
+ mpz_t tu, tv, s0, s1, t0, t1;
+ mp_bitcnt_t uz, vz, gz;
+ mp_bitcnt_t power;
+
+ if (u->_mp_size == 0)
+ {
+ /* g = 0 u + sgn(v) v */
+ signed long sign = mpz_sgn (v);
+ mpz_abs (g, v);
+ if (s)
+ mpz_set_ui (s, 0);
+ if (t)
+ mpz_set_si (t, sign);
+ return;
+ }
+
+ if (v->_mp_size == 0)
+ {
+ /* g = sgn(u) u + 0 v */
+ signed long sign = mpz_sgn (u);
+ mpz_abs (g, u);
+ if (s)
+ mpz_set_si (s, sign);
+ if (t)
+ mpz_set_ui (t, 0);
+ return;
+ }
+
+ mpz_init (tu);
+ mpz_init (tv);
+ mpz_init (s0);
+ mpz_init (s1);
+ mpz_init (t0);
+ mpz_init (t1);
+
+ mpz_abs (tu, u);
+ uz = mpz_make_odd (tu);
+ mpz_abs (tv, v);
+ vz = mpz_make_odd (tv);
+ gz = GMP_MIN (uz, vz);
+
+ uz -= gz;
+ vz -= gz;
+
+ /* Cofactors corresponding to odd gcd. gz handled later. */
+ if (tu->_mp_size < tv->_mp_size)
+ {
+ mpz_swap (tu, tv);
+ MPZ_SRCPTR_SWAP (u, v);
+ MPZ_PTR_SWAP (s, t);
+ MP_BITCNT_T_SWAP (uz, vz);
+ }
+
+ /* Maintain
+ *
+ * u = t0 tu + t1 tv
+ * v = s0 tu + s1 tv
+ *
+ * where u and v denote the inputs with common factors of two
+ * eliminated, and det (s0, t0; s1, t1) = 2^p. Then
+ *
+ * 2^p tu = s1 u - t1 v
+ * 2^p tv = -s0 u + t0 v
+ */
+
+ /* After initial division, tu = q tv + tu', we have
+ *
+ * u = 2^uz (tu' + q tv)
+ * v = 2^vz tv
+ *
+ * or
+ *
+ * t0 = 2^uz, t1 = 2^uz q
+ * s0 = 0, s1 = 2^vz
+ */
+
+ mpz_setbit (t0, uz);
+ mpz_tdiv_qr (t1, tu, tu, tv);
+ mpz_mul_2exp (t1, t1, uz);
+
+ mpz_setbit (s1, vz);
+ power = uz + vz;
+
+ if (tu->_mp_size > 0)
+ {
+ mp_bitcnt_t shift;
+ shift = mpz_make_odd (tu);
+ mpz_mul_2exp (t0, t0, shift);
+ mpz_mul_2exp (s0, s0, shift);
+ power += shift;
+
+ for (;;)
+ {
+ int c;
+ c = mpz_cmp (tu, tv);
+ if (c == 0)
+ break;
+
+ if (c < 0)
+ {
+ /* tv = tv' + tu
+ *
+ * u = t0 tu + t1 (tv' + tu) = (t0 + t1) tu + t1 tv'
+ * v = s0 tu + s1 (tv' + tu) = (s0 + s1) tu + s1 tv' */
+
+ mpz_sub (tv, tv, tu);
+ mpz_add (t0, t0, t1);
+ mpz_add (s0, s0, s1);
+
+ shift = mpz_make_odd (tv);
+ mpz_mul_2exp (t1, t1, shift);
+ mpz_mul_2exp (s1, s1, shift);
+ }
+ else
+ {
+ mpz_sub (tu, tu, tv);
+ mpz_add (t1, t0, t1);
+ mpz_add (s1, s0, s1);
+
+ shift = mpz_make_odd (tu);
+ mpz_mul_2exp (t0, t0, shift);
+ mpz_mul_2exp (s0, s0, shift);
+ }
+ power += shift;
+ }
+ }
+
+ /* Now tv = odd part of gcd, and -s0 and t0 are corresponding
+ cofactors. */
+
+ mpz_mul_2exp (tv, tv, gz);
+ mpz_neg (s0, s0);
+
+ /* 2^p g = s0 u + t0 v. Eliminate one factor of two at a time. To
+ adjust cofactors, we need u / g and v / g */
+
+ mpz_divexact (s1, v, tv);
+ mpz_abs (s1, s1);
+ mpz_divexact (t1, u, tv);
+ mpz_abs (t1, t1);
+
+ while (power-- > 0)
+ {
+ /* s0 u + t0 v = (s0 - v/g) u - (t0 + u/g) v */
+ if (mpz_odd_p (s0) || mpz_odd_p (t0))
+ {
+ mpz_sub (s0, s0, s1);
+ mpz_add (t0, t0, t1);
+ }
+ mpz_divexact_ui (s0, s0, 2);
+ mpz_divexact_ui (t0, t0, 2);
+ }
+
+ /* Arrange so that |s| < |u| / 2g */
+ mpz_add (s1, s0, s1);
+ if (mpz_cmpabs (s0, s1) > 0)
+ {
+ mpz_swap (s0, s1);
+ mpz_sub (t0, t0, t1);
+ }
+ if (u->_mp_size < 0)
+ mpz_neg (s0, s0);
+ if (v->_mp_size < 0)
+ mpz_neg (t0, t0);
+
+ mpz_swap (g, tv);
+ if (s)
+ mpz_swap (s, s0);
+ if (t)
+ mpz_swap (t, t0);
+
+ mpz_clear (tu);
+ mpz_clear (tv);
+ mpz_clear (s0);
+ mpz_clear (s1);
+ mpz_clear (t0);
+ mpz_clear (t1);
+}
+
+void
+mpz_lcm (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mpz_t g;
+
+ if (u->_mp_size == 0 || v->_mp_size == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ mpz_init (g);
+
+ mpz_gcd (g, u, v);
+ mpz_divexact (g, u, g);
+ mpz_mul (r, g, v);
+
+ mpz_clear (g);
+ mpz_abs (r, r);
+}
+
+void
+mpz_lcm_ui (mpz_t r, const mpz_t u, unsigned long v)
+{
+ if (v == 0 || u->_mp_size == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ v /= mpz_gcd_ui (NULL, u, v);
+ mpz_mul_ui (r, u, v);
+
+ mpz_abs (r, r);
+}
+
+int
+mpz_invert (mpz_t r, const mpz_t u, const mpz_t m)
+{
+ mpz_t g, tr;
+ int invertible;
+
+ if (u->_mp_size == 0 || mpz_cmpabs_ui (m, 1) <= 0)
+ return 0;
+
+ mpz_init (g);
+ mpz_init (tr);
+
+ mpz_gcdext (g, tr, NULL, u, m);
+ invertible = (mpz_cmp_ui (g, 1) == 0);
+
+ if (invertible)
+ {
+ if (tr->_mp_size < 0)
+ {
+ if (m->_mp_size >= 0)
+ mpz_add (tr, tr, m);
+ else
+ mpz_sub (tr, tr, m);
+ }
+ mpz_swap (r, tr);
+ }
+
+ mpz_clear (g);
+ mpz_clear (tr);
+ return invertible;
+}
+
+
+/* Higher level operations (sqrt, pow and root) */
+
+void
+mpz_pow_ui (mpz_t r, const mpz_t b, unsigned long e)
+{
+ unsigned long bit;
+ mpz_t tr;
+ mpz_init_set_ui (tr, 1);
+
+ bit = GMP_ULONG_HIGHBIT;
+ do
+ {
+ mpz_mul (tr, tr, tr);
+ if (e & bit)
+ mpz_mul (tr, tr, b);
+ bit >>= 1;
+ }
+ while (bit > 0);
+
+ mpz_swap (r, tr);
+ mpz_clear (tr);
+}
+
+void
+mpz_ui_pow_ui (mpz_t r, unsigned long blimb, unsigned long e)
+{
+ mpz_t b;
+ mpz_init_set_ui (b, blimb);
+ mpz_pow_ui (r, b, e);
+ mpz_clear (b);
+}
+
+void
+mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
+{
+ mpz_t tr;
+ mpz_t base;
+ mp_size_t en, mn;
+ mp_srcptr mp;
+ struct gmp_div_inverse minv;
+ unsigned shift;
+ mp_ptr tp = NULL;
+
+ en = GMP_ABS (e->_mp_size);
+ mn = GMP_ABS (m->_mp_size);
+ if (mn == 0)
+ gmp_die ("mpz_powm: Zero modulo.");
+
+ if (en == 0)
+ {
+ mpz_set_ui (r, 1);
+ return;
+ }
+
+ mp = m->_mp_d;
+ mpn_div_qr_invert (&minv, mp, mn);
+ shift = minv.shift;
+
+ if (shift > 0)
+ {
+ /* To avoid shifts, we do all our reductions, except the final
+ one, using a *normalized* m. */
+ minv.shift = 0;
+
+ tp = gmp_xalloc_limbs (mn);
+ gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift));
+ mp = tp;
+ }
+
+ mpz_init (base);
+
+ if (e->_mp_size < 0)
+ {
+ if (!mpz_invert (base, b, m))
+ gmp_die ("mpz_powm: Negative exponent and non-invertible base.");
+ }
+ else
+ {
+ mp_size_t bn;
+ mpz_abs (base, b);
+
+ bn = base->_mp_size;
+ if (bn >= mn)
+ {
+ mpn_div_qr_preinv (NULL, base->_mp_d, base->_mp_size, mp, mn, &minv);
+ bn = mn;
+ }
+
+ /* We have reduced the absolute value. Now take care of the
+ sign. Note that we get zero represented non-canonically as
+ m. */
+ if (b->_mp_size < 0)
+ {
+ mp_ptr bp = MPZ_REALLOC (base, mn);
+ gmp_assert_nocarry (mpn_sub (bp, mp, mn, bp, bn));
+ bn = mn;
+ }
+ base->_mp_size = mpn_normalized_size (base->_mp_d, bn);
+ }
+ mpz_init_set_ui (tr, 1);
+
+ while (en-- > 0)
+ {
+ mp_limb_t w = e->_mp_d[en];
+ mp_limb_t bit;
+
+ bit = GMP_LIMB_HIGHBIT;
+ do
+ {
+ mpz_mul (tr, tr, tr);
+ if (w & bit)
+ mpz_mul (tr, tr, base);
+ if (tr->_mp_size > mn)
+ {
+ mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
+ tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
+ }
+ bit >>= 1;
+ }
+ while (bit > 0);
+ }
+
+ /* Final reduction */
+ if (tr->_mp_size >= mn)
+ {
+ minv.shift = shift;
+ mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
+ tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
+ }
+ if (tp)
+ gmp_free (tp);
+
+ mpz_swap (r, tr);
+ mpz_clear (tr);
+ mpz_clear (base);
+}
+
+void
+mpz_powm_ui (mpz_t r, const mpz_t b, unsigned long elimb, const mpz_t m)
+{
+ mpz_t e;
+ mpz_init_set_ui (e, elimb);
+ mpz_powm (r, b, e, m);
+ mpz_clear (e);
+}
+
+/* x=trunc(y^(1/z)), r=y-x^z */
+void
+mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
+{
+ int sgn;
+ mpz_t t, u;
+
+ sgn = y->_mp_size < 0;
+ if ((~z & sgn) != 0)
+ gmp_die ("mpz_rootrem: Negative argument, with even root.");
+ if (z == 0)
+ gmp_die ("mpz_rootrem: Zeroth root.");
+
+ if (mpz_cmpabs_ui (y, 1) <= 0) {
+ if (x)
+ mpz_set (x, y);
+ if (r)
+ r->_mp_size = 0;
+ return;
+ }
+
+ mpz_init (u);
+ {
+ mp_bitcnt_t tb;
+ tb = mpz_sizeinbase (y, 2) / z + 1;
+ mpz_init2 (t, tb);
+ mpz_setbit (t, tb);
+ }
+
+ if (z == 2) /* simplify sqrt loop: z-1 == 1 */
+ do {
+ mpz_swap (u, t); /* u = x */
+ mpz_tdiv_q (t, y, u); /* t = y/x */
+ mpz_add (t, t, u); /* t = y/x + x */
+ mpz_tdiv_q_2exp (t, t, 1); /* x'= (y/x + x)/2 */
+ } while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */
+ else /* z != 2 */ {
+ mpz_t v;
+
+ mpz_init (v);
+ if (sgn)
+ mpz_neg (t, t);
+
+ do {
+ mpz_swap (u, t); /* u = x */
+ mpz_pow_ui (t, u, z - 1); /* t = x^(z-1) */
+ mpz_tdiv_q (t, y, t); /* t = y/x^(z-1) */
+ mpz_mul_ui (v, u, z - 1); /* v = x*(z-1) */
+ mpz_add (t, t, v); /* t = y/x^(z-1) + x*(z-1) */
+ mpz_tdiv_q_ui (t, t, z); /* x'=(y/x^(z-1) + x*(z-1))/z */
+ } while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */
+
+ mpz_clear (v);
+ }
+
+ if (r) {
+ mpz_pow_ui (t, u, z);
+ mpz_sub (r, y, t);
+ }
+ if (x)
+ mpz_swap (x, u);
+ mpz_clear (u);
+ mpz_clear (t);
+}
+
+int
+mpz_root (mpz_t x, const mpz_t y, unsigned long z)
+{
+ int res;
+ mpz_t r;
+
+ mpz_init (r);
+ mpz_rootrem (x, r, y, z);
+ res = r->_mp_size == 0;
+ mpz_clear (r);
+
+ return res;
+}
+
+/* Compute s = floor(sqrt(u)) and r = u - s^2. Allows r == NULL */
+void
+mpz_sqrtrem (mpz_t s, mpz_t r, const mpz_t u)
+{
+ mpz_rootrem (s, r, u, 2);
+}
+
+void
+mpz_sqrt (mpz_t s, const mpz_t u)
+{
+ mpz_rootrem (s, NULL, u, 2);
+}
+
+int
+mpz_perfect_square_p (const mpz_t u)
+{
+ if (u->_mp_size <= 0)
+ return (u->_mp_size == 0);
+ else
+ return mpz_root (NULL, u, 2);
+}
+
+int
+mpn_perfect_square_p (mp_srcptr p, mp_size_t n)
+{
+ mpz_t t;
+
+ assert (n > 0);
+ assert (p [n-1] != 0);
+ return mpz_root (NULL, mpz_roinit_n (t, p, n), 2);
+}
+
+mp_size_t
+mpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr p, mp_size_t n)
+{
+ mpz_t s, r, u;
+ mp_size_t res;
+
+ assert (n > 0);
+ assert (p [n-1] != 0);
+
+ mpz_init (r);
+ mpz_init (s);
+ mpz_rootrem (s, r, mpz_roinit_n (u, p, n), 2);
+
+ assert (s->_mp_size == (n+1)/2);
+ mpn_copyd (sp, s->_mp_d, s->_mp_size);
+ mpz_clear (s);
+ res = r->_mp_size;
+ if (rp)
+ mpn_copyd (rp, r->_mp_d, res);
+ mpz_clear (r);
+ return res;
+}
+
+/* Combinatorics */
+
+void
+mpz_fac_ui (mpz_t x, unsigned long n)
+{
+ mpz_set_ui (x, n + (n == 0));
+ for (;n > 2;)
+ mpz_mul_ui (x, x, --n);
+}
+
+void
+mpz_bin_uiui (mpz_t r, unsigned long n, unsigned long k)
+{
+ mpz_t t;
+
+ mpz_set_ui (r, k <= n);
+
+ if (k > (n >> 1))
+ k = (k <= n) ? n - k : 0;
+
+ mpz_init (t);
+ mpz_fac_ui (t, k);
+
+ for (; k > 0; k--)
+ mpz_mul_ui (r, r, n--);
+
+ mpz_divexact (r, r, t);
+ mpz_clear (t);
+}
+
+
+/* Primality testing */
+static int
+gmp_millerrabin (const mpz_t n, const mpz_t nm1, mpz_t y,
+ const mpz_t q, mp_bitcnt_t k)
+{
+ assert (k > 0);
+
+ /* Caller must initialize y to the base. */
+ mpz_powm (y, y, q, n);
+
+ if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)
+ return 1;
+
+ while (--k > 0)
+ {
+ mpz_powm_ui (y, y, 2, n);
+ if (mpz_cmp (y, nm1) == 0)
+ return 1;
+ /* y == 1 means that the previous y was a non-trivial square root
+ of 1 (mod n). y == 0 means that n is a power of the base.
+ In either case, n is not prime. */
+ if (mpz_cmp_ui (y, 1) <= 0)
+ return 0;
+ }
+ return 0;
+}
+
+/* This product is 0xc0cfd797, and fits in 32 bits. */
+#define GMP_PRIME_PRODUCT \
+ (3UL*5UL*7UL*11UL*13UL*17UL*19UL*23UL*29UL)
+
+/* Bit (p+1)/2 is set, for each odd prime <= 61 */
+#define GMP_PRIME_MASK 0xc96996dcUL
+
+int
+mpz_probab_prime_p (const mpz_t n, int reps)
+{
+ mpz_t nm1;
+ mpz_t q;
+ mpz_t y;
+ mp_bitcnt_t k;
+ int is_prime;
+ int j;
+
+ /* Note that we use the absolute value of n only, for compatibility
+ with the real GMP. */
+ if (mpz_even_p (n))
+ return (mpz_cmpabs_ui (n, 2) == 0) ? 2 : 0;
+
+ /* Above test excludes n == 0 */
+ assert (n->_mp_size != 0);
+
+ if (mpz_cmpabs_ui (n, 64) < 0)
+ return (GMP_PRIME_MASK >> (n->_mp_d[0] >> 1)) & 2;
+
+ if (mpz_gcd_ui (NULL, n, GMP_PRIME_PRODUCT) != 1)
+ return 0;
+
+ /* All prime factors are >= 31. */
+ if (mpz_cmpabs_ui (n, 31*31) < 0)
+ return 2;
+
+ /* Use Miller-Rabin, with a deterministic sequence of bases, a[j] =
+ j^2 + j + 41 using Euler's polynomial. We potentially stop early,
+ if a[j] >= n - 1. Since n >= 31*31, this can happen only if reps >
+ 30 (a[30] == 971 > 31*31 == 961). */
+
+ mpz_init (nm1);
+ mpz_init (q);
+ mpz_init (y);
+
+ /* Find q and k, where q is odd and n = 1 + 2**k * q. */
+ nm1->_mp_size = mpz_abs_sub_ui (nm1, n, 1);
+ k = mpz_scan1 (nm1, 0);
+ mpz_tdiv_q_2exp (q, nm1, k);
+
+ for (j = 0, is_prime = 1; is_prime & (j < reps); j++)
+ {
+ mpz_set_ui (y, (unsigned long) j*j+j+41);
+ if (mpz_cmp (y, nm1) >= 0)
+ {
+ /* Don't try any further bases. This "early" break does not affect
+ the result for any reasonable reps value (<=5000 was tested) */
+ assert (j >= 30);
+ break;
+ }
+ is_prime = gmp_millerrabin (n, nm1, y, q, k);
+ }
+ mpz_clear (nm1);
+ mpz_clear (q);
+ mpz_clear (y);
+
+ return is_prime;
+}
+
+
+/* Logical operations and bit manipulation. */
+
+/* Numbers are treated as if represented in two's complement (and
+ infinitely sign extended). For a negative values we get the two's
+ complement from -x = ~x + 1, where ~ is bitwise complement.
+ Negation transforms
+
+ xxxx10...0
+
+ into
+
+ yyyy10...0
+
+ where yyyy is the bitwise complement of xxxx. So least significant
+ bits, up to and including the first one bit, are unchanged, and
+ the more significant bits are all complemented.
+
+ To change a bit from zero to one in a negative number, subtract the
+ corresponding power of two from the absolute value. This can never
+ underflow. To change a bit from one to zero, add the corresponding
+ power of two, and this might overflow. E.g., if x = -001111, the
+ two's complement is 110001. Clearing the least significant bit, we
+ get two's complement 110000, and -010000. */
+
+int
+mpz_tstbit (const mpz_t d, mp_bitcnt_t bit_index)
+{
+ mp_size_t limb_index;
+ unsigned shift;
+ mp_size_t ds;
+ mp_size_t dn;
+ mp_limb_t w;
+ int bit;
+
+ ds = d->_mp_size;
+ dn = GMP_ABS (ds);
+ limb_index = bit_index / GMP_LIMB_BITS;
+ if (limb_index >= dn)
+ return ds < 0;
+
+ shift = bit_index % GMP_LIMB_BITS;
+ w = d->_mp_d[limb_index];
+ bit = (w >> shift) & 1;
+
+ if (ds < 0)
+ {
+ /* d < 0. Check if any of the bits below is set: If so, our bit
+ must be complemented. */
+ if (shift > 0 && (w << (GMP_LIMB_BITS - shift)) > 0)
+ return bit ^ 1;
+ while (limb_index-- > 0)
+ if (d->_mp_d[limb_index] > 0)
+ return bit ^ 1;
+ }
+ return bit;
+}
+
+static void
+mpz_abs_add_bit (mpz_t d, mp_bitcnt_t bit_index)
+{
+ mp_size_t dn, limb_index;
+ mp_limb_t bit;
+ mp_ptr dp;
+
+ dn = GMP_ABS (d->_mp_size);
+
+ limb_index = bit_index / GMP_LIMB_BITS;
+ bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
+
+ if (limb_index >= dn)
+ {
+ mp_size_t i;
+ /* The bit should be set outside of the end of the number.
+ We have to increase the size of the number. */
+ dp = MPZ_REALLOC (d, limb_index + 1);
+
+ dp[limb_index] = bit;
+ for (i = dn; i < limb_index; i++)
+ dp[i] = 0;
+ dn = limb_index + 1;
+ }
+ else
+ {
+ mp_limb_t cy;
+
+ dp = d->_mp_d;
+
+ cy = mpn_add_1 (dp + limb_index, dp + limb_index, dn - limb_index, bit);
+ if (cy > 0)
+ {
+ dp = MPZ_REALLOC (d, dn + 1);
+ dp[dn++] = cy;
+ }
+ }
+
+ d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
+}
+
+static void
+mpz_abs_sub_bit (mpz_t d, mp_bitcnt_t bit_index)
+{
+ mp_size_t dn, limb_index;
+ mp_ptr dp;
+ mp_limb_t bit;
+
+ dn = GMP_ABS (d->_mp_size);
+ dp = d->_mp_d;
+
+ limb_index = bit_index / GMP_LIMB_BITS;
+ bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
+
+ assert (limb_index < dn);
+
+ gmp_assert_nocarry (mpn_sub_1 (dp + limb_index, dp + limb_index,
+ dn - limb_index, bit));
+ dn = mpn_normalized_size (dp, dn);
+ d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
+}
+
+void
+mpz_setbit (mpz_t d, mp_bitcnt_t bit_index)
+{
+ if (!mpz_tstbit (d, bit_index))
+ {
+ if (d->_mp_size >= 0)
+ mpz_abs_add_bit (d, bit_index);
+ else
+ mpz_abs_sub_bit (d, bit_index);
+ }
+}
+
+void
+mpz_clrbit (mpz_t d, mp_bitcnt_t bit_index)
+{
+ if (mpz_tstbit (d, bit_index))
+ {
+ if (d->_mp_size >= 0)
+ mpz_abs_sub_bit (d, bit_index);
+ else
+ mpz_abs_add_bit (d, bit_index);
+ }
+}
+
+void
+mpz_combit (mpz_t d, mp_bitcnt_t bit_index)
+{
+ if (mpz_tstbit (d, bit_index) ^ (d->_mp_size < 0))
+ mpz_abs_sub_bit (d, bit_index);
+ else
+ mpz_abs_add_bit (d, bit_index);
+}
+
+void
+mpz_com (mpz_t r, const mpz_t u)
+{
+ mpz_neg (r, u);
+ mpz_sub_ui (r, r, 1);
+}
+
+void
+mpz_and (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mp_size_t un, vn, rn, i;
+ mp_ptr up, vp, rp;
+
+ mp_limb_t ux, vx, rx;
+ mp_limb_t uc, vc, rc;
+ mp_limb_t ul, vl, rl;
+
+ un = GMP_ABS (u->_mp_size);
+ vn = GMP_ABS (v->_mp_size);
+ if (un < vn)
+ {
+ MPZ_SRCPTR_SWAP (u, v);
+ MP_SIZE_T_SWAP (un, vn);
+ }
+ if (vn == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ uc = u->_mp_size < 0;
+ vc = v->_mp_size < 0;
+ rc = uc & vc;
+
+ ux = -uc;
+ vx = -vc;
+ rx = -rc;
+
+ /* If the smaller input is positive, higher limbs don't matter. */
+ rn = vx ? un : vn;
+
+ rp = MPZ_REALLOC (r, rn + rc);
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+
+ i = 0;
+ do
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ vl = (vp[i] ^ vx) + vc;
+ vc = vl < vc;
+
+ rl = ( (ul & vl) ^ rx) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ while (++i < vn);
+ assert (vc == 0);
+
+ for (; i < rn; i++)
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ rl = ( (ul & vx) ^ rx) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ if (rc)
+ rp[rn++] = rc;
+ else
+ rn = mpn_normalized_size (rp, rn);
+
+ r->_mp_size = rx ? -rn : rn;
+}
+
+void
+mpz_ior (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mp_size_t un, vn, rn, i;
+ mp_ptr up, vp, rp;
+
+ mp_limb_t ux, vx, rx;
+ mp_limb_t uc, vc, rc;
+ mp_limb_t ul, vl, rl;
+
+ un = GMP_ABS (u->_mp_size);
+ vn = GMP_ABS (v->_mp_size);
+ if (un < vn)
+ {
+ MPZ_SRCPTR_SWAP (u, v);
+ MP_SIZE_T_SWAP (un, vn);
+ }
+ if (vn == 0)
+ {
+ mpz_set (r, u);
+ return;
+ }
+
+ uc = u->_mp_size < 0;
+ vc = v->_mp_size < 0;
+ rc = uc | vc;
+
+ ux = -uc;
+ vx = -vc;
+ rx = -rc;
+
+ /* If the smaller input is negative, by sign extension higher limbs
+ don't matter. */
+ rn = vx ? vn : un;
+
+ rp = MPZ_REALLOC (r, rn + rc);
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+
+ i = 0;
+ do
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ vl = (vp[i] ^ vx) + vc;
+ vc = vl < vc;
+
+ rl = ( (ul | vl) ^ rx) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ while (++i < vn);
+ assert (vc == 0);
+
+ for (; i < rn; i++)
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ rl = ( (ul | vx) ^ rx) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ if (rc)
+ rp[rn++] = rc;
+ else
+ rn = mpn_normalized_size (rp, rn);
+
+ r->_mp_size = rx ? -rn : rn;
+}
+
+void
+mpz_xor (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mp_size_t un, vn, i;
+ mp_ptr up, vp, rp;
+
+ mp_limb_t ux, vx, rx;
+ mp_limb_t uc, vc, rc;
+ mp_limb_t ul, vl, rl;
+
+ un = GMP_ABS (u->_mp_size);
+ vn = GMP_ABS (v->_mp_size);
+ if (un < vn)
+ {
+ MPZ_SRCPTR_SWAP (u, v);
+ MP_SIZE_T_SWAP (un, vn);
+ }
+ if (vn == 0)
+ {
+ mpz_set (r, u);
+ return;
+ }
+
+ uc = u->_mp_size < 0;
+ vc = v->_mp_size < 0;
+ rc = uc ^ vc;
+
+ ux = -uc;
+ vx = -vc;
+ rx = -rc;
+
+ rp = MPZ_REALLOC (r, un + rc);
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+
+ i = 0;
+ do
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ vl = (vp[i] ^ vx) + vc;
+ vc = vl < vc;
+
+ rl = (ul ^ vl ^ rx) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ while (++i < vn);
+ assert (vc == 0);
+
+ for (; i < un; i++)
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ rl = (ul ^ ux) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ if (rc)
+ rp[un++] = rc;
+ else
+ un = mpn_normalized_size (rp, un);
+
+ r->_mp_size = rx ? -un : un;
+}
+
+static unsigned
+gmp_popcount_limb (mp_limb_t x)
+{
+ unsigned c;
+
+ /* Do 16 bits at a time, to avoid limb-sized constants. */
+ for (c = 0; x > 0; x >>= 16)
+ {
+ unsigned w = ((x >> 1) & 0x5555) + (x & 0x5555);
+ w = ((w >> 2) & 0x3333) + (w & 0x3333);
+ w = ((w >> 4) & 0x0f0f) + (w & 0x0f0f);
+ w = (w >> 8) + (w & 0x00ff);
+ c += w;
+ }
+ return c;
+}
+
+mp_bitcnt_t
+mpn_popcount (mp_srcptr p, mp_size_t n)
+{
+ mp_size_t i;
+ mp_bitcnt_t c;
+
+ for (c = 0, i = 0; i < n; i++)
+ c += gmp_popcount_limb (p[i]);
+
+ return c;
+}
+
+mp_bitcnt_t
+mpz_popcount (const mpz_t u)
+{
+ mp_size_t un;
+
+ un = u->_mp_size;
+
+ if (un < 0)
+ return ~(mp_bitcnt_t) 0;
+
+ return mpn_popcount (u->_mp_d, un);
+}
+
+mp_bitcnt_t
+mpz_hamdist (const mpz_t u, const mpz_t v)
+{
+ mp_size_t un, vn, i;
+ mp_limb_t uc, vc, ul, vl, comp;
+ mp_srcptr up, vp;
+ mp_bitcnt_t c;
+
+ un = u->_mp_size;
+ vn = v->_mp_size;
+
+ if ( (un ^ vn) < 0)
+ return ~(mp_bitcnt_t) 0;
+
+ comp = - (uc = vc = (un < 0));
+ if (uc)
+ {
+ assert (vn < 0);
+ un = -un;
+ vn = -vn;
+ }
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+
+ if (un < vn)
+ MPN_SRCPTR_SWAP (up, un, vp, vn);
+
+ for (i = 0, c = 0; i < vn; i++)
+ {
+ ul = (up[i] ^ comp) + uc;
+ uc = ul < uc;
+
+ vl = (vp[i] ^ comp) + vc;
+ vc = vl < vc;
+
+ c += gmp_popcount_limb (ul ^ vl);
+ }
+ assert (vc == 0);
+
+ for (; i < un; i++)
+ {
+ ul = (up[i] ^ comp) + uc;
+ uc = ul < uc;
+
+ c += gmp_popcount_limb (ul ^ comp);
+ }
+
+ return c;
+}
+
+mp_bitcnt_t
+mpz_scan1 (const mpz_t u, mp_bitcnt_t starting_bit)
+{
+ mp_ptr up;
+ mp_size_t us, un, i;
+ mp_limb_t limb, ux;
+
+ us = u->_mp_size;
+ un = GMP_ABS (us);
+ i = starting_bit / GMP_LIMB_BITS;
+
+ /* Past the end there's no 1 bits for u>=0, or an immediate 1 bit
+ for u<0. Notice this test picks up any u==0 too. */
+ if (i >= un)
+ return (us >= 0 ? ~(mp_bitcnt_t) 0 : starting_bit);
+
+ up = u->_mp_d;
+ ux = 0;
+ limb = up[i];
+
+ if (starting_bit != 0)
+ {
+ if (us < 0)
+ {
+ ux = mpn_zero_p (up, i);
+ limb = ~ limb + ux;
+ ux = - (mp_limb_t) (limb >= ux);
+ }
+
+ /* Mask to 0 all bits before starting_bit, thus ignoring them. */
+ limb &= (GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS));
+ }
+
+ return mpn_common_scan (limb, i, up, un, ux);
+}
+
+mp_bitcnt_t
+mpz_scan0 (const mpz_t u, mp_bitcnt_t starting_bit)
+{
+ mp_ptr up;
+ mp_size_t us, un, i;
+ mp_limb_t limb, ux;
+
+ us = u->_mp_size;
+ ux = - (mp_limb_t) (us >= 0);
+ un = GMP_ABS (us);
+ i = starting_bit / GMP_LIMB_BITS;
+
+ /* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for
+ u<0. Notice this test picks up all cases of u==0 too. */
+ if (i >= un)
+ return (ux ? starting_bit : ~(mp_bitcnt_t) 0);
+
+ up = u->_mp_d;
+ limb = up[i] ^ ux;
+
+ if (ux == 0)
+ limb -= mpn_zero_p (up, i); /* limb = ~(~limb + zero_p) */
+
+ /* Mask all bits before starting_bit, thus ignoring them. */
+ limb &= (GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS));
+
+ return mpn_common_scan (limb, i, up, un, ux);
+}
+
+
+/* MPZ base conversion. */
+
+size_t
+mpz_sizeinbase (const mpz_t u, int base)
+{
+ mp_size_t un;
+ mp_srcptr up;
+ mp_ptr tp;
+ mp_bitcnt_t bits;
+ struct gmp_div_inverse bi;
+ size_t ndigits;
+
+ assert (base >= 2);
+ assert (base <= 36);
+
+ un = GMP_ABS (u->_mp_size);
+ if (un == 0)
+ return 1;
+
+ up = u->_mp_d;
+
+ bits = (un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]);
+ switch (base)
+ {
+ case 2:
+ return bits;
+ case 4:
+ return (bits + 1) / 2;
+ case 8:
+ return (bits + 2) / 3;
+ case 16:
+ return (bits + 3) / 4;
+ case 32:
+ return (bits + 4) / 5;
+ /* FIXME: Do something more clever for the common case of base
+ 10. */
+ }
+
+ tp = gmp_xalloc_limbs (un);
+ mpn_copyi (tp, up, un);
+ mpn_div_qr_1_invert (&bi, base);
+
+ ndigits = 0;
+ do
+ {
+ ndigits++;
+ mpn_div_qr_1_preinv (tp, tp, un, &bi);
+ un -= (tp[un-1] == 0);
+ }
+ while (un > 0);
+
+ gmp_free (tp);
+ return ndigits;
+}
+
+char *
+mpz_get_str (char *sp, int base, const mpz_t u)
+{
+ unsigned bits;
+ const char *digits;
+ mp_size_t un;
+ size_t i, sn;
+
+ if (base >= 0)
+ {
+ digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+ }
+ else
+ {
+ base = -base;
+ digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ }
+ if (base <= 1)
+ base = 10;
+ if (base > 36)
+ return NULL;
+
+ sn = 1 + mpz_sizeinbase (u, base);
+ if (!sp)
+ sp = gmp_xalloc (1 + sn);
+
+ un = GMP_ABS (u->_mp_size);
+
+ if (un == 0)
+ {
+ sp[0] = '0';
+ sp[1] = '\0';
+ return sp;
+ }
+
+ i = 0;
+
+ if (u->_mp_size < 0)
+ sp[i++] = '-';
+
+ bits = mpn_base_power_of_two_p (base);
+
+ if (bits)
+ /* Not modified in this case. */
+ sn = i + mpn_get_str_bits ((unsigned char *) sp + i, bits, u->_mp_d, un);
+ else
+ {
+ struct mpn_base_info info;
+ mp_ptr tp;
+
+ mpn_get_base_info (&info, base);
+ tp = gmp_xalloc_limbs (un);
+ mpn_copyi (tp, u->_mp_d, un);
+
+ sn = i + mpn_get_str_other ((unsigned char *) sp + i, base, &info, tp, un);
+ gmp_free (tp);
+ }
+
+ for (; i < sn; i++)
+ sp[i] = digits[(unsigned char) sp[i]];
+
+ sp[sn] = '\0';
+ return sp;
+}
+
+int
+mpz_set_str (mpz_t r, const char *sp, int base)
+{
+ unsigned bits;
+ mp_size_t rn, alloc;
+ mp_ptr rp;
+ size_t sn;
+ int sign;
+ unsigned char *dp;
+
+ assert (base == 0 || (base >= 2 && base <= 36));
+
+ while (isspace( (unsigned char) *sp))
+ sp++;
+
+ sign = (*sp == '-');
+ sp += sign;
+
+ if (base == 0)
+ {
+ if (*sp == '0')
+ {
+ sp++;
+ if (*sp == 'x' || *sp == 'X')
+ {
+ base = 16;
+ sp++;
+ }
+ else if (*sp == 'b' || *sp == 'B')
+ {
+ base = 2;
+ sp++;
+ }
+ else
+ base = 8;
+ }
+ else
+ base = 10;
+ }
+
+ sn = strlen (sp);
+ dp = gmp_xalloc (sn + (sn == 0));
+
+ for (sn = 0; *sp; sp++)
+ {
+ unsigned digit;
+
+ if (isspace ((unsigned char) *sp))
+ continue;
+ if (*sp >= '0' && *sp <= '9')
+ digit = *sp - '0';
+ else if (*sp >= 'a' && *sp <= 'z')
+ digit = *sp - 'a' + 10;
+ else if (*sp >= 'A' && *sp <= 'Z')
+ digit = *sp - 'A' + 10;
+ else
+ digit = base; /* fail */
+
+ if (digit >= base)
+ {
+ gmp_free (dp);
+ r->_mp_size = 0;
+ return -1;
+ }
+
+ dp[sn++] = digit;
+ }
+
+ bits = mpn_base_power_of_two_p (base);
+
+ if (bits > 0)
+ {
+ alloc = (sn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
+ rp = MPZ_REALLOC (r, alloc);
+ rn = mpn_set_str_bits (rp, dp, sn, bits);
+ }
+ else
+ {
+ struct mpn_base_info info;
+ mpn_get_base_info (&info, base);
+ alloc = (sn + info.exp - 1) / info.exp;
+ rp = MPZ_REALLOC (r, alloc);
+ rn = mpn_set_str_other (rp, dp, sn, base, &info);
+ }
+ assert (rn <= alloc);
+ gmp_free (dp);
+
+ r->_mp_size = sign ? - rn : rn;
+
+ return 0;
+}
+
+int
+mpz_init_set_str (mpz_t r, const char *sp, int base)
+{
+ mpz_init (r);
+ return mpz_set_str (r, sp, base);
+}
+
+size_t
+mpz_out_str (FILE *stream, int base, const mpz_t x)
+{
+ char *str;
+ size_t len;
+
+ str = mpz_get_str (NULL, base, x);
+ len = strlen (str);
+ len = fwrite (str, 1, len, stream);
+ gmp_free (str);
+ return len;
+}
+
+
+static int
+gmp_detect_endian (void)
+{
+ static const int i = 2;
+ const unsigned char *p = (const unsigned char *) &i;
+ return 1 - *p;
+}
+
+/* Import and export. Does not support nails. */
+void
+mpz_import (mpz_t r, size_t count, int order, size_t size, int endian,
+ size_t nails, const void *src)
+{
+ const unsigned char *p;
+ ptrdiff_t word_step;
+ mp_ptr rp;
+ mp_size_t rn;
+
+ /* The current (partial) limb. */
+ mp_limb_t limb;
+ /* The number of bytes already copied to this limb (starting from
+ the low end). */
+ size_t bytes;
+ /* The index where the limb should be stored, when completed. */
+ mp_size_t i;
+
+ if (nails != 0)
+ gmp_die ("mpz_import: Nails not supported.");
+
+ assert (order == 1 || order == -1);
+ assert (endian >= -1 && endian <= 1);
+
+ if (endian == 0)
+ endian = gmp_detect_endian ();
+
+ p = (unsigned char *) src;
+
+ word_step = (order != endian) ? 2 * size : 0;
+
+ /* Process bytes from the least significant end, so point p at the
+ least significant word. */
+ if (order == 1)
+ {
+ p += size * (count - 1);
+ word_step = - word_step;
+ }
+
+ /* And at least significant byte of that word. */
+ if (endian == 1)
+ p += (size - 1);
+
+ rn = (size * count + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t);
+ rp = MPZ_REALLOC (r, rn);
+
+ for (limb = 0, bytes = 0, i = 0; count > 0; count--, p += word_step)
+ {
+ size_t j;
+ for (j = 0; j < size; j++, p -= (ptrdiff_t) endian)
+ {
+ limb |= (mp_limb_t) *p << (bytes++ * CHAR_BIT);
+ if (bytes == sizeof(mp_limb_t))
+ {
+ rp[i++] = limb;
+ bytes = 0;
+ limb = 0;
+ }
+ }
+ }
+ assert (i + (bytes > 0) == rn);
+ if (limb != 0)
+ rp[i++] = limb;
+ else
+ i = mpn_normalized_size (rp, i);
+
+ r->_mp_size = i;
+}
+
+void *
+mpz_export (void *r, size_t *countp, int order, size_t size, int endian,
+ size_t nails, const mpz_t u)
+{
+ size_t count;
+ mp_size_t un;
+
+ if (nails != 0)
+ gmp_die ("mpz_import: Nails not supported.");
+
+ assert (order == 1 || order == -1);
+ assert (endian >= -1 && endian <= 1);
+ assert (size > 0 || u->_mp_size == 0);
+
+ un = u->_mp_size;
+ count = 0;
+ if (un != 0)
+ {
+ size_t k;
+ unsigned char *p;
+ ptrdiff_t word_step;
+ /* The current (partial) limb. */
+ mp_limb_t limb;
+ /* The number of bytes left to to in this limb. */
+ size_t bytes;
+ /* The index where the limb was read. */
+ mp_size_t i;
+
+ un = GMP_ABS (un);
+
+ /* Count bytes in top limb. */
+ limb = u->_mp_d[un-1];
+ assert (limb != 0);
+
+ k = 0;
+ do {
+ k++; limb >>= CHAR_BIT;
+ } while (limb != 0);
+
+ count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size;
+
+ if (!r)
+ r = gmp_xalloc (count * size);
+
+ if (endian == 0)
+ endian = gmp_detect_endian ();
+
+ p = (unsigned char *) r;
+
+ word_step = (order != endian) ? 2 * size : 0;
+
+ /* Process bytes from the least significant end, so point p at the
+ least significant word. */
+ if (order == 1)
+ {
+ p += size * (count - 1);
+ word_step = - word_step;
+ }
+
+ /* And at least significant byte of that word. */
+ if (endian == 1)
+ p += (size - 1);
+
+ for (bytes = 0, i = 0, k = 0; k < count; k++, p += word_step)
+ {
+ size_t j;
+ for (j = 0; j < size; j++, p -= (ptrdiff_t) endian)
+ {
+ if (bytes == 0)
+ {
+ if (i < un)
+ limb = u->_mp_d[i++];
+ bytes = sizeof (mp_limb_t);
+ }
+ *p = limb;
+ limb >>= CHAR_BIT;
+ bytes--;
+ }
+ }
+ assert (i == un);
+ assert (k == count);
+ }
+
+ if (countp)
+ *countp = count;
+
+ return r;
+}
diff --git a/external/nettle-3.3/nettle/mini-gmp.h b/external/nettle-3.3/nettle/mini-gmp.h
new file mode 100644
index 0000000..cdcb83b
--- /dev/null
+++ b/external/nettle-3.3/nettle/mini-gmp.h
@@ -0,0 +1,294 @@
+/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
+
+Copyright 2011-2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+or
+
+ * the GNU General Public License as published by the Free Software
+ Foundation; either version 3 of the License, or (at your option) any
+ later version.
+
+or both in parallel, as here.
+
+The GNU MP 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 General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library. If not,
+see https://www.gnu.org/licenses/. */
+
+/* About mini-gmp: This is a minimal implementation of a subset of the
+ GMP interface. It is intended for inclusion into applications which
+ have modest bignums needs, as a fallback when the real GMP library
+ is not installed.
+
+ This file defines the public interface. */
+
+#ifndef __MINI_GMP_H__
+#define __MINI_GMP_H__
+
+/* For size_t */
+#include <stddef.h>
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+void mp_set_memory_functions (void *(*) (size_t),
+ void *(*) (void *, size_t, size_t),
+ void (*) (void *, size_t));
+
+void mp_get_memory_functions (void *(**) (size_t),
+ void *(**) (void *, size_t, size_t),
+ void (**) (void *, size_t));
+
+typedef unsigned long mp_limb_t;
+typedef long mp_size_t;
+typedef unsigned long mp_bitcnt_t;
+
+typedef mp_limb_t *mp_ptr;
+typedef const mp_limb_t *mp_srcptr;
+
+typedef struct
+{
+ int _mp_alloc; /* Number of *limbs* allocated and pointed
+ to by the _mp_d field. */
+ int _mp_size; /* abs(_mp_size) is the number of limbs the
+ last field points to. If _mp_size is
+ negative this is a negative number. */
+ mp_limb_t *_mp_d; /* Pointer to the limbs. */
+} __mpz_struct;
+
+typedef __mpz_struct mpz_t[1];
+
+typedef __mpz_struct *mpz_ptr;
+typedef const __mpz_struct *mpz_srcptr;
+
+extern const int mp_bits_per_limb;
+
+void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+void mpn_zero (mp_ptr, mp_size_t);
+
+int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
+int mpn_perfect_square_p (mp_srcptr, mp_size_t);
+mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t);
+mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t);
+
+mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t);
+#define mpn_invert_limb(x) mpn_invert_3by2 ((x), 0)
+
+size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
+mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);
+
+void mpz_init (mpz_t);
+void mpz_init2 (mpz_t, mp_bitcnt_t);
+void mpz_clear (mpz_t);
+
+#define mpz_odd_p(z) (((z)->_mp_size != 0) & (int) (z)->_mp_d[0])
+#define mpz_even_p(z) (! mpz_odd_p (z))
+
+int mpz_sgn (const mpz_t);
+int mpz_cmp_si (const mpz_t, long);
+int mpz_cmp_ui (const mpz_t, unsigned long);
+int mpz_cmp (const mpz_t, const mpz_t);
+int mpz_cmpabs_ui (const mpz_t, unsigned long);
+int mpz_cmpabs (const mpz_t, const mpz_t);
+int mpz_cmp_d (const mpz_t, double);
+int mpz_cmpabs_d (const mpz_t, double);
+
+void mpz_abs (mpz_t, const mpz_t);
+void mpz_neg (mpz_t, const mpz_t);
+void mpz_swap (mpz_t, mpz_t);
+
+void mpz_add_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_add (mpz_t, const mpz_t, const mpz_t);
+void mpz_sub_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_ui_sub (mpz_t, unsigned long, const mpz_t);
+void mpz_sub (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_mul_si (mpz_t, const mpz_t, long int);
+void mpz_mul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_mul (mpz_t, const mpz_t, const mpz_t);
+void mpz_mul_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_addmul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_addmul (mpz_t, const mpz_t, const mpz_t);
+void mpz_submul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_submul (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_cdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_cdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_cdiv_r (mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_r (mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_r (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_cdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_fdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_tdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_cdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_fdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_tdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+
+void mpz_mod (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_divexact (mpz_t, const mpz_t, const mpz_t);
+
+int mpz_divisible_p (const mpz_t, const mpz_t);
+int mpz_congruent_p (const mpz_t, const mpz_t, const mpz_t);
+
+unsigned long mpz_cdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_ui (const mpz_t, unsigned long);
+unsigned long mpz_fdiv_ui (const mpz_t, unsigned long);
+unsigned long mpz_tdiv_ui (const mpz_t, unsigned long);
+
+unsigned long mpz_mod_ui (mpz_t, const mpz_t, unsigned long);
+
+void mpz_divexact_ui (mpz_t, const mpz_t, unsigned long);
+
+int mpz_divisible_ui_p (const mpz_t, unsigned long);
+
+unsigned long mpz_gcd_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_gcd (mpz_t, const mpz_t, const mpz_t);
+void mpz_gcdext (mpz_t, mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_lcm_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_lcm (mpz_t, const mpz_t, const mpz_t);
+int mpz_invert (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t);
+void mpz_sqrt (mpz_t, const mpz_t);
+int mpz_perfect_square_p (const mpz_t);
+
+void mpz_pow_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_ui_pow_ui (mpz_t, unsigned long, unsigned long);
+void mpz_powm (mpz_t, const mpz_t, const mpz_t, const mpz_t);
+void mpz_powm_ui (mpz_t, const mpz_t, unsigned long, const mpz_t);
+
+void mpz_rootrem (mpz_t, mpz_t, const mpz_t, unsigned long);
+int mpz_root (mpz_t, const mpz_t, unsigned long);
+
+void mpz_fac_ui (mpz_t, unsigned long);
+void mpz_bin_uiui (mpz_t, unsigned long, unsigned long);
+
+int mpz_probab_prime_p (const mpz_t, int);
+
+int mpz_tstbit (const mpz_t, mp_bitcnt_t);
+void mpz_setbit (mpz_t, mp_bitcnt_t);
+void mpz_clrbit (mpz_t, mp_bitcnt_t);
+void mpz_combit (mpz_t, mp_bitcnt_t);
+
+void mpz_com (mpz_t, const mpz_t);
+void mpz_and (mpz_t, const mpz_t, const mpz_t);
+void mpz_ior (mpz_t, const mpz_t, const mpz_t);
+void mpz_xor (mpz_t, const mpz_t, const mpz_t);
+
+mp_bitcnt_t mpz_popcount (const mpz_t);
+mp_bitcnt_t mpz_hamdist (const mpz_t, const mpz_t);
+mp_bitcnt_t mpz_scan0 (const mpz_t, mp_bitcnt_t);
+mp_bitcnt_t mpz_scan1 (const mpz_t, mp_bitcnt_t);
+
+int mpz_fits_slong_p (const mpz_t);
+int mpz_fits_ulong_p (const mpz_t);
+long int mpz_get_si (const mpz_t);
+unsigned long int mpz_get_ui (const mpz_t);
+double mpz_get_d (const mpz_t);
+size_t mpz_size (const mpz_t);
+mp_limb_t mpz_getlimbn (const mpz_t, mp_size_t);
+
+void mpz_realloc2 (mpz_t, mp_bitcnt_t);
+mp_srcptr mpz_limbs_read (mpz_srcptr);
+mp_ptr mpz_limbs_modify (mpz_t, mp_size_t);
+mp_ptr mpz_limbs_write (mpz_t, mp_size_t);
+void mpz_limbs_finish (mpz_t, mp_size_t);
+mpz_srcptr mpz_roinit_n (mpz_t, mp_srcptr, mp_size_t);
+
+#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }}
+
+void mpz_set_si (mpz_t, signed long int);
+void mpz_set_ui (mpz_t, unsigned long int);
+void mpz_set (mpz_t, const mpz_t);
+void mpz_set_d (mpz_t, double);
+
+void mpz_init_set_si (mpz_t, signed long int);
+void mpz_init_set_ui (mpz_t, unsigned long int);
+void mpz_init_set (mpz_t, const mpz_t);
+void mpz_init_set_d (mpz_t, double);
+
+size_t mpz_sizeinbase (const mpz_t, int);
+char *mpz_get_str (char *, int, const mpz_t);
+int mpz_set_str (mpz_t, const char *, int);
+int mpz_init_set_str (mpz_t, const char *, int);
+
+/* This long list taken from gmp.h. */
+/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4,
+ <iostream> defines EOF but not FILE. */
+#if defined (FILE) \
+ || defined (H_STDIO) \
+ || defined (_H_STDIO) /* AIX */ \
+ || defined (_STDIO_H) /* glibc, Sun, SCO */ \
+ || defined (_STDIO_H_) /* BSD, OSF */ \
+ || defined (__STDIO_H) /* Borland */ \
+ || defined (__STDIO_H__) /* IRIX */ \
+ || defined (_STDIO_INCLUDED) /* HPUX */ \
+ || defined (__dj_include_stdio_h_) /* DJGPP */ \
+ || defined (_FILE_DEFINED) /* Microsoft */ \
+ || defined (__STDIO__) /* Apple MPW MrC */ \
+ || defined (_MSL_STDIO_H) /* Metrowerks */ \
+ || defined (_STDIO_H_INCLUDED) /* QNX4 */ \
+ || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ \
+ || defined (__STDIO_LOADED) /* VMS */
+size_t mpz_out_str (FILE *, int, const mpz_t);
+#endif
+
+void mpz_import (mpz_t, size_t, int, size_t, int, size_t, const void *);
+void *mpz_export (void *, size_t *, int, size_t, int, size_t, const mpz_t);
+
+#if defined (__cplusplus)
+}
+#endif
+#endif /* __MINI_GMP_H__ */
diff --git a/external/nettle-3.3/nettle/nettle-internal.h b/external/nettle-3.3/nettle/nettle-internal.h
new file mode 100644
index 0000000..cf776fe
--- /dev/null
+++ b/external/nettle-3.3/nettle/nettle-internal.h
@@ -0,0 +1,92 @@
+/* nettle-internal.h
+
+ Things that are used only by the testsuite and benchmark, and
+ not included in the library.
+
+ Copyright (C) 2002, 2014 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_INTERNAL_H_INCLUDED
+#define NETTLE_INTERNAL_H_INCLUDED
+
+#include "nettle-meta.h"
+
+/* Temporary allocation, for systems that don't support alloca. Note
+ * that the allocation requests should always be reasonably small, so
+ * that they can fit on the stack. For non-alloca systems, we use a
+ * fix maximum size, and abort if we ever need anything larger. */
+
+#if HAVE_ALLOCA
+# define TMP_DECL(name, type, max) type *name
+# define TMP_ALLOC(name, size) (name = alloca(sizeof (*name) * (size)))
+#else /* !HAVE_ALLOCA */
+# define TMP_DECL(name, type, max) type name[max]
+# define TMP_ALLOC(name, size) \
+ do { if ((size) > (sizeof(name) / sizeof(name[0]))) abort(); } while (0)
+#endif
+
+/* Arbitrary limits which apply to systems that don't have alloca */
+#define NETTLE_MAX_HASH_BLOCK_SIZE 128
+#define NETTLE_MAX_HASH_DIGEST_SIZE 64
+#define NETTLE_MAX_SEXP_ASSOC 17
+#define NETTLE_MAX_CIPHER_BLOCK_SIZE 32
+
+/* Doesn't quite fit with the other algorithms, because of the weak
+ * keys. Weak keys are not reported, the functions will simply crash
+ * if you try to use a weak key. */
+
+extern const struct nettle_cipher nettle_des;
+extern const struct nettle_cipher nettle_des3;
+
+extern const struct nettle_cipher nettle_blowfish128;
+
+extern const struct nettle_cipher nettle_unified_aes128;
+extern const struct nettle_cipher nettle_unified_aes192;
+extern const struct nettle_cipher nettle_unified_aes256;
+
+/* Stream ciphers treated as aead algorithms with no authentication. */
+extern const struct nettle_aead nettle_arcfour128;
+extern const struct nettle_aead nettle_chacha;
+extern const struct nettle_aead nettle_salsa20;
+extern const struct nettle_aead nettle_salsa20r12;
+
+/* Glue to openssl, for comparative benchmarking. Code in
+ * examples/nettle-openssl.c. */
+extern const struct nettle_cipher nettle_openssl_aes128;
+extern const struct nettle_cipher nettle_openssl_aes192;
+extern const struct nettle_cipher nettle_openssl_aes256;
+extern const struct nettle_cipher nettle_openssl_blowfish128;
+extern const struct nettle_cipher nettle_openssl_des;
+extern const struct nettle_cipher nettle_openssl_cast128;
+extern const struct nettle_aead nettle_openssl_arcfour128;
+
+extern const struct nettle_hash nettle_openssl_md5;
+extern const struct nettle_hash nettle_openssl_sha1;
+
+#endif /* NETTLE_INTERNAL_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/nettle-meta.h b/external/nettle-3.3/nettle/nettle-meta.h
new file mode 100644
index 0000000..d27369c
--- /dev/null
+++ b/external/nettle-3.3/nettle/nettle-meta.h
@@ -0,0 +1,230 @@
+/* nettle-meta.h
+
+ Information about algorithms.
+
+ Copyright (C) 2002, 2014 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_META_H_INCLUDED
+#define NETTLE_META_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct nettle_cipher
+{
+ const char *name;
+
+ unsigned context_size;
+
+ /* Zero for stream ciphers */
+ unsigned block_size;
+
+ /* Suggested key size; other sizes are sometimes possible. */
+ unsigned key_size;
+
+ nettle_set_key_func *set_encrypt_key;
+ nettle_set_key_func *set_decrypt_key;
+
+ nettle_cipher_func *encrypt;
+ nettle_cipher_func *decrypt;
+};
+
+/* null-terminated list of ciphers implemented by this version of nettle */
+extern const struct nettle_cipher * const nettle_ciphers[];
+
+extern const struct nettle_cipher nettle_aes128;
+extern const struct nettle_cipher nettle_aes192;
+extern const struct nettle_cipher nettle_aes256;
+
+extern const struct nettle_cipher nettle_camellia128;
+extern const struct nettle_cipher nettle_camellia192;
+extern const struct nettle_cipher nettle_camellia256;
+
+extern const struct nettle_cipher nettle_cast128;
+
+extern const struct nettle_cipher nettle_serpent128;
+extern const struct nettle_cipher nettle_serpent192;
+extern const struct nettle_cipher nettle_serpent256;
+
+extern const struct nettle_cipher nettle_twofish128;
+extern const struct nettle_cipher nettle_twofish192;
+extern const struct nettle_cipher nettle_twofish256;
+
+extern const struct nettle_cipher nettle_arctwo40;
+extern const struct nettle_cipher nettle_arctwo64;
+extern const struct nettle_cipher nettle_arctwo128;
+extern const struct nettle_cipher nettle_arctwo_gutmann128;
+
+struct nettle_hash
+{
+ const char *name;
+
+ /* Size of the context struct */
+ unsigned context_size;
+
+ /* Size of digests */
+ unsigned digest_size;
+
+ /* Internal block size */
+ unsigned block_size;
+
+ nettle_hash_init_func *init;
+ nettle_hash_update_func *update;
+ nettle_hash_digest_func *digest;
+};
+
+#define _NETTLE_HASH(name, NAME) { \
+ #name, \
+ sizeof(struct name##_ctx), \
+ NAME##_DIGEST_SIZE, \
+ NAME##_BLOCK_SIZE, \
+ (nettle_hash_init_func *) name##_init, \
+ (nettle_hash_update_func *) name##_update, \
+ (nettle_hash_digest_func *) name##_digest \
+}
+
+/* null-terminated list of digests implemented by this version of nettle */
+extern const struct nettle_hash * const nettle_hashes[];
+
+extern const struct nettle_hash nettle_md2;
+extern const struct nettle_hash nettle_md4;
+extern const struct nettle_hash nettle_md5;
+extern const struct nettle_hash nettle_gosthash94;
+extern const struct nettle_hash nettle_ripemd160;
+extern const struct nettle_hash nettle_sha1;
+extern const struct nettle_hash nettle_sha224;
+extern const struct nettle_hash nettle_sha256;
+extern const struct nettle_hash nettle_sha384;
+extern const struct nettle_hash nettle_sha512;
+extern const struct nettle_hash nettle_sha512_224;
+extern const struct nettle_hash nettle_sha512_256;
+extern const struct nettle_hash nettle_sha3_224;
+extern const struct nettle_hash nettle_sha3_256;
+extern const struct nettle_hash nettle_sha3_384;
+extern const struct nettle_hash nettle_sha3_512;
+
+struct nettle_aead
+{
+ const char *name;
+
+ unsigned context_size;
+ /* Block size for encrypt and decrypt. */
+ unsigned block_size;
+ unsigned key_size;
+ unsigned nonce_size;
+ unsigned digest_size;
+
+ nettle_set_key_func *set_encrypt_key;
+ nettle_set_key_func *set_decrypt_key;
+ nettle_set_key_func *set_nonce;
+ nettle_hash_update_func *update;
+ nettle_crypt_func *encrypt;
+ nettle_crypt_func *decrypt;
+ /* FIXME: Drop length argument? */
+ nettle_hash_digest_func *digest;
+};
+
+/* null-terminated list of aead constructions implemented by this
+ version of nettle */
+extern const struct nettle_aead * const nettle_aeads[];
+
+extern const struct nettle_aead nettle_gcm_aes128;
+extern const struct nettle_aead nettle_gcm_aes192;
+extern const struct nettle_aead nettle_gcm_aes256;
+extern const struct nettle_aead nettle_gcm_camellia128;
+extern const struct nettle_aead nettle_gcm_camellia256;
+extern const struct nettle_aead nettle_eax_aes128;
+extern const struct nettle_aead nettle_chacha_poly1305;
+
+struct nettle_armor
+{
+ const char *name;
+ unsigned encode_context_size;
+ unsigned decode_context_size;
+
+ unsigned encode_final_length;
+
+ nettle_armor_init_func *encode_init;
+ nettle_armor_length_func *encode_length;
+ nettle_armor_encode_update_func *encode_update;
+ nettle_armor_encode_final_func *encode_final;
+
+ nettle_armor_init_func *decode_init;
+ nettle_armor_length_func *decode_length;
+ nettle_armor_decode_update_func *decode_update;
+ nettle_armor_decode_final_func *decode_final;
+};
+
+#define _NETTLE_ARMOR(name, NAME) { \
+ #name, \
+ sizeof(struct name##_encode_ctx), \
+ sizeof(struct name##_decode_ctx), \
+ NAME##_ENCODE_FINAL_LENGTH, \
+ (nettle_armor_init_func *) name##_encode_init, \
+ (nettle_armor_length_func *) name##_encode_length, \
+ (nettle_armor_encode_update_func *) name##_encode_update, \
+ (nettle_armor_encode_final_func *) name##_encode_final, \
+ (nettle_armor_init_func *) name##_decode_init, \
+ (nettle_armor_length_func *) name##_decode_length, \
+ (nettle_armor_decode_update_func *) name##_decode_update, \
+ (nettle_armor_decode_final_func *) name##_decode_final, \
+}
+
+#define _NETTLE_ARMOR_0(name, NAME) { \
+ #name, \
+ 0, \
+ sizeof(struct name##_decode_ctx), \
+ NAME##_ENCODE_FINAL_LENGTH, \
+ (nettle_armor_init_func *) name##_encode_init, \
+ (nettle_armor_length_func *) name##_encode_length, \
+ (nettle_armor_encode_update_func *) name##_encode_update, \
+ (nettle_armor_encode_final_func *) name##_encode_final, \
+ (nettle_armor_init_func *) name##_decode_init, \
+ (nettle_armor_length_func *) name##_decode_length, \
+ (nettle_armor_decode_update_func *) name##_decode_update, \
+ (nettle_armor_decode_final_func *) name##_decode_final, \
+}
+
+/* null-terminated list of armor schemes implemented by this version of nettle */
+extern const struct nettle_armor * const nettle_armors[];
+
+extern const struct nettle_armor nettle_base64;
+extern const struct nettle_armor nettle_base64url;
+extern const struct nettle_armor nettle_base16;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_META_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/nettle-stdint.h b/external/nettle-3.3/nettle/nettle-stdint.h
new file mode 100644
index 0000000..3298fa6
--- /dev/null
+++ b/external/nettle-3.3/nettle/nettle-stdint.h
@@ -0,0 +1,6 @@
+#ifndef __NETTLE_STDINT_H
+#define __NETTLE_STDINT_H
+
+#include <stdint.h>
+
+#endif /* __NETTLE_STDINT_H */
diff --git a/external/nettle-3.3/nettle/nettle-types.h b/external/nettle-3.3/nettle/nettle-types.h
new file mode 100644
index 0000000..8f77ea9
--- /dev/null
+++ b/external/nettle-3.3/nettle/nettle-types.h
@@ -0,0 +1,110 @@
+/* nettle-types.h
+
+ Copyright (C) 2005, 2014 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_TYPES_H
+#define NETTLE_TYPES_H
+
+/* For size_t */
+#include <stddef.h>
+
+/* Pretend these types always exists. Nettle doesn't use them. */
+#define _STDINT_HAVE_INT_FAST32_T 1
+#include "nettle-stdint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* An aligned 16-byte block. */
+union nettle_block16
+{
+ uint8_t b[16];
+ unsigned long w[16 / sizeof(unsigned long)];
+};
+
+/* Randomness. Used by key generation and dsa signature creation. */
+typedef void nettle_random_func(void *ctx,
+ size_t length, uint8_t *dst);
+
+/* Progress report function, mainly for key generation. */
+typedef void nettle_progress_func(void *ctx, int c);
+
+/* Realloc function, used by struct nettle_buffer. */
+typedef void *nettle_realloc_func(void *ctx, void *p, size_t length);
+
+/* Ciphers */
+typedef void nettle_set_key_func(void *ctx, const uint8_t *key);
+
+/* For block ciphers, const context. */
+typedef void nettle_cipher_func(const void *ctx,
+ size_t length, uint8_t *dst,
+ const uint8_t *src);
+
+
+/* Uses a void * for cipher contexts. Used for crypt operations where
+ the internal state changes during the encryption. */
+typedef void nettle_crypt_func(void *ctx,
+ size_t length, uint8_t *dst,
+ const uint8_t *src);
+
+/* Hash algorithms */
+typedef void nettle_hash_init_func(void *ctx);
+typedef void nettle_hash_update_func(void *ctx,
+ size_t length,
+ const uint8_t *src);
+typedef void nettle_hash_digest_func(void *ctx,
+ size_t length, uint8_t *dst);
+
+/* ASCII armor codecs. NOTE: Experimental and subject to change. */
+
+typedef size_t nettle_armor_length_func(size_t length);
+typedef void nettle_armor_init_func(void *ctx);
+
+typedef size_t nettle_armor_encode_update_func(void *ctx,
+ uint8_t *dst,
+ size_t src_length,
+ const uint8_t *src);
+
+typedef size_t nettle_armor_encode_final_func(void *ctx, uint8_t *dst);
+
+typedef int nettle_armor_decode_update_func(void *ctx,
+ size_t *dst_length,
+ uint8_t *dst,
+ size_t src_length,
+ const uint8_t *src);
+
+typedef int nettle_armor_decode_final_func(void *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_TYPES_H */
diff --git a/external/nettle-3.3/nettle/nettle-write.h b/external/nettle-3.3/nettle/nettle-write.h
new file mode 100644
index 0000000..54152bd
--- /dev/null
+++ b/external/nettle-3.3/nettle/nettle-write.h
@@ -0,0 +1,58 @@
+/* nettle-write.h
+
+ Internal functions to write out word-sized data to byte arrays.
+
+ Copyright (C) 2010 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_WRITE_H_INCLUDED
+#define NETTLE_WRITE_H_INCLUDED
+
+/* For size_t */
+#include <stddef.h>
+
+#include "nettle-stdint.h"
+
+/* Write the word array at SRC to the byte array at DST, using little
+ endian (le) or big endian (be) byte order, and truncating the
+ result to LENGTH bytes. */
+
+/* FIXME: Use a macro shortcut to memcpy for native endianness. */
+void
+_nettle_write_be32(size_t length, uint8_t *dst,
+ uint32_t *src);
+void
+_nettle_write_le32(size_t length, uint8_t *dst,
+ uint32_t *src);
+
+void
+_nettle_write_le64(size_t length, uint8_t *dst,
+ uint64_t *src);
+
+#endif /* NETTLE_WRITE_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/pkcs1-rsa-sha256.c b/external/nettle-3.3/nettle/pkcs1-rsa-sha256.c
new file mode 100644
index 0000000..2c2b5c0
--- /dev/null
+++ b/external/nettle-3.3/nettle/pkcs1-rsa-sha256.c
@@ -0,0 +1,120 @@
+/* pkcs1-rsa-sha256.c
+
+ PKCS stuff for rsa-sha256.
+
+ Copyright (C) 2001, 2003, 2006 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rsa.h"
+
+#include "bignum.h"
+#include "pkcs1.h"
+
+#include "gmp-glue.h"
+
+/* From RFC 3447, Public-Key Cryptography Standards (PKCS) #1: RSA
+ * Cryptography Specifications Version 2.1.
+ *
+ * id-sha256 OBJECT IDENTIFIER ::=
+ * {joint-iso-itu-t(2) country(16) us(840) organization(1)
+ * gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1}
+ */
+
+static const uint8_t
+sha256_prefix[] =
+{
+ /* 19 octets prefix, 32 octets hash, total 51 */
+ 0x30, 49, /* SEQUENCE */
+ 0x30, 13, /* SEQUENCE */
+ 0x06, 9, /* OBJECT IDENTIFIER */
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0, /* NULL */
+ 0x04, 32 /* OCTET STRING */
+ /* Here comes the raw hash value */
+};
+
+int
+pkcs1_rsa_sha256_encode(mpz_t m, size_t key_size, struct sha256_ctx *hash)
+{
+ uint8_t *p;
+ TMP_GMP_DECL(em, uint8_t);
+
+ TMP_GMP_ALLOC(em, key_size);
+
+ p = _pkcs1_signature_prefix(key_size, em,
+ sizeof(sha256_prefix),
+ sha256_prefix,
+ SHA256_DIGEST_SIZE);
+ if (p)
+ {
+ sha256_digest(hash, SHA256_DIGEST_SIZE, p);
+ nettle_mpz_set_str_256_u(m, key_size, em);
+ TMP_GMP_FREE(em);
+ return 1;
+ }
+ else
+ {
+ TMP_GMP_FREE(em);
+ return 0;
+ }
+}
+
+int
+pkcs1_rsa_sha256_encode_digest(mpz_t m, size_t key_size, const uint8_t *digest)
+{
+ uint8_t *p;
+ TMP_GMP_DECL(em, uint8_t);
+
+ TMP_GMP_ALLOC(em, key_size);
+
+ p = _pkcs1_signature_prefix(key_size, em,
+ sizeof(sha256_prefix),
+ sha256_prefix,
+ SHA256_DIGEST_SIZE);
+ if (p)
+ {
+ memcpy(p, digest, SHA256_DIGEST_SIZE);
+ nettle_mpz_set_str_256_u(m, key_size, em);
+ TMP_GMP_FREE(em);
+ return 1;
+ }
+ else
+ {
+ TMP_GMP_FREE(em);
+ return 0;
+ }
+}
diff --git a/external/nettle-3.3/nettle/pkcs1.c b/external/nettle-3.3/nettle/pkcs1.c
new file mode 100644
index 0000000..87a2d2e
--- /dev/null
+++ b/external/nettle-3.3/nettle/pkcs1.c
@@ -0,0 +1,73 @@
+/* pkcs1.c
+
+ PKCS1 embedding.
+
+ Copyright (C) 2003 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "pkcs1.h"
+
+/* Formats the PKCS#1 padding, of the form
+ *
+ * 0x00 0x01 0xff ... 0xff 0x00 id ...digest...
+ *
+ * where the 0xff ... 0xff part consists of at least 8 octets. The
+ * total size equals the octet size of n.
+ */
+uint8_t *
+_pkcs1_signature_prefix(unsigned key_size,
+ uint8_t *buffer,
+ unsigned id_size,
+ const uint8_t *id,
+ unsigned digest_size)
+{
+ unsigned j;
+
+ if (key_size < 11 + id_size + digest_size)
+ return NULL;
+
+ j = key_size - digest_size - id_size;
+
+ memcpy (buffer + j, id, id_size);
+ buffer[0] = 0;
+ buffer[1] = 1;
+ buffer[j-1] = 0;
+
+ assert(j >= 11);
+ memset(buffer + 2, 0xff, j - 3);
+
+ return buffer + j + id_size;
+}
diff --git a/external/nettle-3.3/nettle/pkcs1.h b/external/nettle-3.3/nettle/pkcs1.h
new file mode 100644
index 0000000..7391804
--- /dev/null
+++ b/external/nettle-3.3/nettle/pkcs1.h
@@ -0,0 +1,114 @@
+/* pkcs1.h
+
+ PKCS1 embedding.
+
+ Copyright (C) 2003 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_PKCS1_H_INCLUDED
+#define NETTLE_PKCS1_H_INCLUDED
+
+#include "nettle-types.h"
+#include "bignum.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define _pkcs1_signature_prefix _nettle_pkcs1_signature_prefix
+#define pkcs1_rsa_digest_encode nettle_pkcs1_rsa_digest_encode
+#define pkcs1_rsa_md5_encode nettle_pkcs1_rsa_md5_encode
+#define pkcs1_rsa_md5_encode_digest nettle_pkcs1_rsa_md5_encode_digest
+#define pkcs1_rsa_sha1_encode nettle_pkcs1_rsa_sha1_encode
+#define pkcs1_rsa_sha1_encode_digest nettle_pkcs1_rsa_sha1_encode_digest
+#define pkcs1_rsa_sha256_encode nettle_pkcs1_rsa_sha256_encode
+#define pkcs1_rsa_sha256_encode_digest nettle_pkcs1_rsa_sha256_encode_digest
+#define pkcs1_rsa_sha512_encode nettle_pkcs1_rsa_sha512_encode
+#define pkcs1_rsa_sha512_encode_digest nettle_pkcs1_rsa_sha512_encode_digest
+#define pkcs1_encrypt nettle_pkcs1_encrypt
+#define pkcs1_decrypt nettle_pkcs1_decrypt
+
+struct md5_ctx;
+struct sha1_ctx;
+struct sha256_ctx;
+struct sha512_ctx;
+
+uint8_t *
+_pkcs1_signature_prefix(unsigned key_size,
+ uint8_t *buffer,
+ unsigned id_size,
+ const uint8_t *id,
+ unsigned digest_size);
+
+int
+pkcs1_encrypt (size_t key_size,
+ /* For padding */
+ void *random_ctx, nettle_random_func *random,
+ size_t length, const uint8_t *message,
+ mpz_t m);
+
+int
+pkcs1_decrypt (size_t key_size,
+ const mpz_t m,
+ size_t *length, uint8_t *message);
+
+int
+pkcs1_rsa_digest_encode(mpz_t m, size_t key_size,
+ size_t di_length, const uint8_t *digest_info);
+
+int
+pkcs1_rsa_md5_encode(mpz_t m, size_t length, struct md5_ctx *hash);
+
+int
+pkcs1_rsa_md5_encode_digest(mpz_t m, size_t length, const uint8_t *digest);
+
+int
+pkcs1_rsa_sha1_encode(mpz_t m, size_t length, struct sha1_ctx *hash);
+
+int
+pkcs1_rsa_sha1_encode_digest(mpz_t m, size_t length, const uint8_t *digest);
+
+int
+pkcs1_rsa_sha256_encode(mpz_t m, size_t length, struct sha256_ctx *hash);
+
+int
+pkcs1_rsa_sha256_encode_digest(mpz_t m, size_t length, const uint8_t *digest);
+
+int
+pkcs1_rsa_sha512_encode(mpz_t m, size_t length, struct sha512_ctx *hash);
+
+int
+pkcs1_rsa_sha512_encode_digest(mpz_t m, size_t length, const uint8_t *digest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_PKCS1_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/realloc.c b/external/nettle-3.3/nettle/realloc.c
new file mode 100644
index 0000000..4e9a4b7
--- /dev/null
+++ b/external/nettle-3.3/nettle/realloc.c
@@ -0,0 +1,69 @@
+/* realloc.c
+
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "realloc.h"
+
+/* NOTE: Calling libc realloc with size == 0 is not required to
+ totally free the object, it is allowed to return a valid
+ pointer. */
+void *
+nettle_realloc(void *ctx, void *p, size_t length)
+{
+ if (length > 0)
+ return realloc(p, length);
+
+ free(p);
+ return NULL;
+}
+
+void *
+nettle_xrealloc(void *ctx, void *p, size_t length)
+{
+ if (length > 0)
+ {
+ void *n = realloc(p, length);
+ if (!n)
+ {
+ fprintf(stderr, "Virtual memory exhausted.\n");
+ abort();
+ }
+ return n;
+ }
+ free(p);
+ return NULL;
+}
diff --git a/external/nettle-3.3/nettle/realloc.h b/external/nettle-3.3/nettle/realloc.h
new file mode 100644
index 0000000..e696a84
--- /dev/null
+++ b/external/nettle-3.3/nettle/realloc.h
@@ -0,0 +1,48 @@
+/* realloc.h
+
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_REALLOC_H_INCLUDED
+#define NETTLE_REALLOC_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+nettle_realloc_func nettle_realloc;
+nettle_realloc_func nettle_xrealloc;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_REALLOC_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/rsa-keygen.c b/external/nettle-3.3/nettle/rsa-keygen.c
new file mode 100644
index 0000000..5260239
--- /dev/null
+++ b/external/nettle-3.3/nettle/rsa-keygen.c
@@ -0,0 +1,212 @@
+/* rsa-keygen.c
+
+ Generation of RSA keypairs
+
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "rsa.h"
+#include "bignum.h"
+
+#ifndef DEBUG
+# define DEBUG 0
+#endif
+
+#if DEBUG
+# include <stdio.h>
+#endif
+
+
+int
+rsa_generate_keypair(struct rsa_public_key *pub,
+ struct rsa_private_key *key,
+ void *random_ctx, nettle_random_func *random,
+ void *progress_ctx, nettle_progress_func *progress,
+ unsigned n_size,
+ unsigned e_size)
+{
+ mpz_t p1;
+ mpz_t q1;
+ mpz_t phi;
+ mpz_t tmp;
+
+ if (e_size)
+ {
+ /* We should choose e randomly. Is the size reasonable? */
+ if ((e_size < 16) || (e_size >= n_size) )
+ return 0;
+ }
+ else
+ {
+ /* We have a fixed e. Check that it makes sense */
+
+ /* It must be odd */
+ if (!mpz_tstbit(pub->e, 0))
+ return 0;
+
+ /* And 3 or larger */
+ if (mpz_cmp_ui(pub->e, 3) < 0)
+ return 0;
+
+ /* And size less than n */
+ if (mpz_sizeinbase(pub->e, 2) >= n_size)
+ return 0;
+ }
+
+ if (n_size < RSA_MINIMUM_N_BITS)
+ return 0;
+
+ mpz_init(p1); mpz_init(q1); mpz_init(phi); mpz_init(tmp);
+
+ /* Generate primes */
+ for (;;)
+ {
+ /* Generate p, such that gcd(p-1, e) = 1 */
+ for (;;)
+ {
+ nettle_random_prime(key->p, (n_size+1)/2, 1,
+ random_ctx, random,
+ progress_ctx, progress);
+
+ mpz_sub_ui(p1, key->p, 1);
+
+ /* If e was given, we must chose p such that p-1 has no factors in
+ * common with e. */
+ if (e_size)
+ break;
+
+ mpz_gcd(tmp, pub->e, p1);
+
+ if (mpz_cmp_ui(tmp, 1) == 0)
+ break;
+ else if (progress) progress(progress_ctx, 'c');
+ }
+
+ if (progress)
+ progress(progress_ctx, '\n');
+
+ /* Generate q, such that gcd(q-1, e) = 1 */
+ for (;;)
+ {
+ nettle_random_prime(key->q, n_size/2, 1,
+ random_ctx, random,
+ progress_ctx, progress);
+
+ /* Very unlikely. */
+ if (mpz_cmp (key->q, key->p) == 0)
+ continue;
+
+ mpz_sub_ui(q1, key->q, 1);
+
+ /* If e was given, we must chose q such that q-1 has no factors in
+ * common with e. */
+ if (e_size)
+ break;
+
+ mpz_gcd(tmp, pub->e, q1);
+
+ if (mpz_cmp_ui(tmp, 1) == 0)
+ break;
+ else if (progress) progress(progress_ctx, 'c');
+ }
+
+ /* Now we have the primes. Is the product of the right size? */
+ mpz_mul(pub->n, key->p, key->q);
+
+ assert (mpz_sizeinbase(pub->n, 2) == n_size);
+
+ if (progress)
+ progress(progress_ctx, '\n');
+
+ /* c = q^{-1} (mod p) */
+ if (mpz_invert(key->c, key->q, key->p))
+ /* This should succeed everytime. But if it doesn't,
+ * we try again. */
+ break;
+ else if (progress) progress(progress_ctx, '?');
+ }
+
+ mpz_mul(phi, p1, q1);
+
+ /* If we didn't have a given e, generate one now. */
+ if (e_size)
+ {
+ int retried = 0;
+ for (;;)
+ {
+ nettle_mpz_random_size(pub->e,
+ random_ctx, random,
+ e_size);
+
+ /* Make sure it's odd and that the most significant bit is
+ * set */
+ mpz_setbit(pub->e, 0);
+ mpz_setbit(pub->e, e_size - 1);
+
+ /* Needs gmp-3, or inverse might be negative. */
+ if (mpz_invert(key->d, pub->e, phi))
+ break;
+
+ if (progress) progress(progress_ctx, 'e');
+ retried = 1;
+ }
+ if (retried && progress)
+ progress(progress_ctx, '\n');
+ }
+ else
+ {
+ /* Must always succeed, as we already that e
+ * doesn't have any common factor with p-1 or q-1. */
+ int res = mpz_invert(key->d, pub->e, phi);
+ assert(res);
+ }
+
+ /* Done! Almost, we must compute the auxillary private values. */
+ /* a = d % (p-1) */
+ mpz_fdiv_r(key->a, key->d, p1);
+
+ /* b = d % (q-1) */
+ mpz_fdiv_r(key->b, key->d, q1);
+
+ /* c was computed earlier */
+
+ pub->size = key->size = (n_size + 7) / 8;
+ assert(pub->size >= RSA_MINIMUM_N_OCTETS);
+
+ mpz_clear(p1); mpz_clear(q1); mpz_clear(phi); mpz_clear(tmp);
+
+ return 1;
+}
diff --git a/external/nettle-3.3/nettle/rsa-sha256-sign.c b/external/nettle-3.3/nettle/rsa-sha256-sign.c
new file mode 100644
index 0000000..5daffbf
--- /dev/null
+++ b/external/nettle-3.3/nettle/rsa-sha256-sign.c
@@ -0,0 +1,77 @@
+/* rsa-sha256-sign.c
+
+ Signatures using RSA and SHA256.
+
+ Copyright (C) 2001, 2003, 2006 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "rsa.h"
+
+#include "bignum.h"
+#include "pkcs1.h"
+
+int
+rsa_sha256_sign(const struct rsa_private_key *key,
+ struct sha256_ctx *hash,
+ mpz_t s)
+{
+ if (pkcs1_rsa_sha256_encode(s, key->size, hash))
+ {
+ rsa_compute_root(key, s, s);
+ return 1;
+ }
+ else
+ {
+ mpz_set_ui(s, 0);
+ return 0;
+ }
+}
+
+int
+rsa_sha256_sign_digest(const struct rsa_private_key *key,
+ const uint8_t *digest,
+ mpz_t s)
+{
+ if (pkcs1_rsa_sha256_encode_digest(s, key->size, digest))
+ {
+ rsa_compute_root(key, s, s);
+ return 1;
+ }
+ else
+ {
+ mpz_set_ui(s, 0);
+ return 0;
+ }
+}
diff --git a/external/nettle-3.3/nettle/rsa-sha256-verify.c b/external/nettle-3.3/nettle/rsa-sha256-verify.c
new file mode 100644
index 0000000..33ecbc1
--- /dev/null
+++ b/external/nettle-3.3/nettle/rsa-sha256-verify.c
@@ -0,0 +1,79 @@
+/* rsa-sha256-verify.c
+
+ Verifying signatures created with RSA and SHA256.
+
+ Copyright (C) 2001, 2003, 2006 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "rsa.h"
+
+#include "bignum.h"
+#include "pkcs1.h"
+
+int
+rsa_sha256_verify(const struct rsa_public_key *key,
+ struct sha256_ctx *hash,
+ const mpz_t s)
+{
+ int res;
+ mpz_t m;
+
+ mpz_init(m);
+
+ res = (pkcs1_rsa_sha256_encode(m, key->size, hash)
+ &&_rsa_verify(key, m, s));
+
+ mpz_clear(m);
+
+ return res;
+}
+
+int
+rsa_sha256_verify_digest(const struct rsa_public_key *key,
+ const uint8_t *digest,
+ const mpz_t s)
+{
+ int res;
+ mpz_t m;
+
+ mpz_init(m);
+
+ res = (pkcs1_rsa_sha256_encode_digest(m, key->size, digest)
+ && _rsa_verify(key, m, s));
+
+ mpz_clear(m);
+
+ return res;
+}
diff --git a/external/nettle-3.3/nettle/rsa-sign.c b/external/nettle-3.3/nettle/rsa-sign.c
new file mode 100644
index 0000000..5cae041
--- /dev/null
+++ b/external/nettle-3.3/nettle/rsa-sign.c
@@ -0,0 +1,144 @@
+/* rsa-sign.c
+
+ Creating RSA signatures.
+
+ Copyright (C) 2001, 2003 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "rsa.h"
+
+#include "bignum.h"
+
+void
+rsa_private_key_init(struct rsa_private_key *key)
+{
+ mpz_init(key->d);
+ mpz_init(key->p);
+ mpz_init(key->q);
+ mpz_init(key->a);
+ mpz_init(key->b);
+ mpz_init(key->c);
+
+ /* Not really necessary, but it seems cleaner to initialize all the
+ * storage. */
+ key->size = 0;
+}
+
+void
+rsa_private_key_clear(struct rsa_private_key *key)
+{
+ mpz_clear(key->d);
+ mpz_clear(key->p);
+ mpz_clear(key->q);
+ mpz_clear(key->a);
+ mpz_clear(key->b);
+ mpz_clear(key->c);
+}
+
+int
+rsa_private_key_prepare(struct rsa_private_key *key)
+{
+ mpz_t n;
+
+ /* The size of the product is the sum of the sizes of the factors,
+ * or sometimes one less. It's possible but tricky to compute the
+ * size without computing the full product. */
+
+ mpz_init(n);
+ mpz_mul(n, key->p, key->q);
+
+ key->size = _rsa_check_size(n);
+
+ mpz_clear(n);
+
+ return (key->size > 0);
+}
+
+/* Computing an rsa root. */
+void
+rsa_compute_root(const struct rsa_private_key *key,
+ mpz_t x, const mpz_t m)
+{
+ mpz_t xp; /* modulo p */
+ mpz_t xq; /* modulo q */
+
+ mpz_init(xp); mpz_init(xq);
+
+ /* Compute xq = m^d % q = (m%q)^b % q */
+ mpz_fdiv_r(xq, m, key->q);
+ mpz_powm_sec(xq, xq, key->b, key->q);
+
+ /* Compute xp = m^d % p = (m%p)^a % p */
+ mpz_fdiv_r(xp, m, key->p);
+ mpz_powm_sec(xp, xp, key->a, key->p);
+
+ /* Set xp' = (xp - xq) c % p. */
+ mpz_sub(xp, xp, xq);
+ mpz_mul(xp, xp, key->c);
+ mpz_fdiv_r(xp, xp, key->p);
+
+ /* Finally, compute x = xq + q xp'
+ *
+ * To prove that this works, note that
+ *
+ * xp = x + i p,
+ * xq = x + j q,
+ * c q = 1 + k p
+ *
+ * for some integers i, j and k. Now, for some integer l,
+ *
+ * xp' = (xp - xq) c + l p
+ * = (x + i p - (x + j q)) c + l p
+ * = (i p - j q) c + l p
+ * = (i c + l) p - j (c q)
+ * = (i c + l) p - j (1 + kp)
+ * = (i c + l - j k) p - j
+ *
+ * which shows that xp' = -j (mod p). We get
+ *
+ * xq + q xp' = x + j q + (i c + l - j k) p q - j q
+ * = x + (i c + l - j k) p q
+ *
+ * so that
+ *
+ * xq + q xp' = x (mod pq)
+ *
+ * We also get 0 <= xq + q xp' < p q, because
+ *
+ * 0 <= xq < q and 0 <= xp' < p.
+ */
+ mpz_mul(x, key->q, xp);
+ mpz_add(x, x, xq);
+
+ mpz_clear(xp); mpz_clear(xq);
+}
diff --git a/external/nettle-3.3/nettle/rsa-verify.c b/external/nettle-3.3/nettle/rsa-verify.c
new file mode 100644
index 0000000..8484a85
--- /dev/null
+++ b/external/nettle-3.3/nettle/rsa-verify.c
@@ -0,0 +1,64 @@
+/* rsa-verify.c
+
+ Verifying RSA signatures.
+
+ Copyright (C) 2001, 2003 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "rsa.h"
+
+#include "bignum.h"
+
+int
+_rsa_verify(const struct rsa_public_key *key,
+ const mpz_t m,
+ const mpz_t s)
+{
+ int res;
+
+ mpz_t m1;
+
+ if ( (mpz_sgn(s) <= 0)
+ || (mpz_cmp(s, key->n) >= 0) )
+ return 0;
+
+ mpz_init(m1);
+
+ mpz_powm(m1, s, key->e, key->n);
+
+ res = !mpz_cmp(m, m1);
+
+ mpz_clear(m1);
+
+ return res;
+}
diff --git a/external/nettle-3.3/nettle/rsa.c b/external/nettle-3.3/nettle/rsa.c
new file mode 100644
index 0000000..22fae77
--- /dev/null
+++ b/external/nettle-3.3/nettle/rsa.c
@@ -0,0 +1,86 @@
+/* rsa.c
+
+ The RSA publickey algorithm.
+
+ Copyright (C) 2001 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "rsa.h"
+
+#include "bignum.h"
+
+void
+rsa_public_key_init(struct rsa_public_key *key)
+{
+ mpz_init(key->n);
+ mpz_init(key->e);
+
+ /* Not really necessary, but it seems cleaner to initialize all the
+ * storage. */
+ key->size = 0;
+}
+
+void
+rsa_public_key_clear(struct rsa_public_key *key)
+{
+ mpz_clear(key->n);
+ mpz_clear(key->e);
+}
+
+/* Computes the size, in octets, of a the modulo. Returns 0 if the
+ * modulo is too small to be useful, or otherwise appears invalid. */
+size_t
+_rsa_check_size(mpz_t n)
+{
+ /* Round upwards */
+ size_t size;
+
+ /* Even moduli are invalid, and not supported by mpz_powm_sec. */
+ if (mpz_even_p (n))
+ return 0;
+
+ size = (mpz_sizeinbase(n, 2) + 7) / 8;
+
+ if (size < RSA_MINIMUM_N_OCTETS)
+ return 0;
+
+ return size;
+}
+
+int
+rsa_public_key_prepare(struct rsa_public_key *key)
+{
+ key->size = _rsa_check_size(key->n);
+
+ return (key->size > 0);
+}
diff --git a/external/nettle-3.3/nettle/rsa.h b/external/nettle-3.3/nettle/rsa.h
new file mode 100644
index 0000000..1ceda2d
--- /dev/null
+++ b/external/nettle-3.3/nettle/rsa.h
@@ -0,0 +1,355 @@
+/* rsa.h
+
+ The RSA publickey algorithm.
+
+ Copyright (C) 2001, 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_RSA_H_INCLUDED
+#define NETTLE_RSA_H_INCLUDED
+
+#include "nettle-types.h"
+#include "bignum.h"
+
+#include "sha2.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define rsa_public_key_init nettle_rsa_public_key_init
+#define rsa_public_key_clear nettle_rsa_public_key_clear
+#define rsa_public_key_prepare nettle_rsa_public_key_prepare
+#define rsa_private_key_init nettle_rsa_private_key_init
+#define rsa_private_key_clear nettle_rsa_private_key_clear
+#define rsa_private_key_prepare nettle_rsa_private_key_prepare
+#define rsa_sha256_sign nettle_rsa_sha256_sign
+#define rsa_sha256_sign_tr nettle_rsa_sha256_sign_tr
+#define rsa_sha256_verify nettle_rsa_sha256_verify
+#define rsa_sha256_sign_digest nettle_rsa_sha256_sign_digest
+#define rsa_sha256_sign_digest_tr nettle_rsa_sha256_sign_digest_tr
+#define rsa_sha256_verify_digest nettle_rsa_sha256_verify_digest
+#define rsa_encrypt nettle_rsa_encrypt
+#define rsa_decrypt nettle_rsa_decrypt
+#define rsa_decrypt_tr nettle_rsa_decrypt_tr
+#define rsa_compute_root nettle_rsa_compute_root
+#define rsa_compute_root_tr nettle_rsa_compute_root_tr
+#define rsa_generate_keypair nettle_rsa_generate_keypair
+#define rsa_keypair_to_sexp nettle_rsa_keypair_to_sexp
+#define rsa_keypair_from_sexp_alist nettle_rsa_keypair_from_sexp_alist
+#define rsa_keypair_from_sexp nettle_rsa_keypair_from_sexp
+#define rsa_public_key_from_der_iterator nettle_rsa_public_key_from_der_iterator
+#define rsa_private_key_from_der_iterator nettle_rsa_private_key_from_der_iterator
+#define rsa_keypair_from_der nettle_rsa_keypair_from_der
+#define rsa_keypair_to_openpgp nettle_rsa_keypair_to_openpgp
+#define _rsa_verify _nettle_rsa_verify
+#define _rsa_check_size _nettle_rsa_check_size
+#define _rsa_blind _nettle_rsa_blind
+#define _rsa_unblind _nettle_rsa_unblind
+
+/* This limit is somewhat arbitrary. Technically, the smallest modulo
+ which makes sense at all is 15 = 3*5, phi(15) = 8, size 4 bits. But
+ for ridiculously small keys, not all odd e are possible (e.g., for
+ 5 bits, the only possible modulo is 3*7 = 21, phi(21) = 12, and e =
+ 3 don't work). The smallest size that makes sense with pkcs#1, and
+ which allows RSA encryption of one byte messages, is 12 octets, 89
+ bits. */
+
+#define RSA_MINIMUM_N_OCTETS 12
+#define RSA_MINIMUM_N_BITS (8*RSA_MINIMUM_N_OCTETS - 7)
+
+struct rsa_public_key
+{
+ /* Size of the modulo, in octets. This is also the size of all
+ * signatures that are created or verified with this key. */
+ size_t size;
+
+ /* Modulo */
+ mpz_t n;
+
+ /* Public exponent */
+ mpz_t e;
+};
+
+struct rsa_private_key
+{
+ size_t size;
+
+ /* d is filled in by the key generation function; otherwise it's
+ * completely unused. */
+ mpz_t d;
+
+ /* The two factors */
+ mpz_t p; mpz_t q;
+
+ /* d % (p-1), i.e. a e = 1 (mod (p-1)) */
+ mpz_t a;
+
+ /* d % (q-1), i.e. b e = 1 (mod (q-1)) */
+ mpz_t b;
+
+ /* modular inverse of q , i.e. c q = 1 (mod p) */
+ mpz_t c;
+};
+
+/* Signing a message works as follows:
+ *
+ * Store the private key in a rsa_private_key struct.
+ *
+ * Call rsa_private_key_prepare. This initializes the size attribute
+ * to the length of a signature.
+ *
+ * Initialize a hashing context, by callling
+ * md5_init
+ *
+ * Hash the message by calling
+ * md5_update
+ *
+ * Create the signature by calling
+ * rsa_md5_sign
+ *
+ * The signature is represented as a mpz_t bignum. This call also
+ * resets the hashing context.
+ *
+ * When done with the key and signature, don't forget to call
+ * mpz_clear.
+ */
+
+/* Calls mpz_init to initialize bignum storage. */
+void
+rsa_public_key_init(struct rsa_public_key *key);
+
+/* Calls mpz_clear to deallocate bignum storage. */
+void
+rsa_public_key_clear(struct rsa_public_key *key);
+
+int
+rsa_public_key_prepare(struct rsa_public_key *key);
+
+/* Calls mpz_init to initialize bignum storage. */
+void
+rsa_private_key_init(struct rsa_private_key *key);
+
+/* Calls mpz_clear to deallocate bignum storage. */
+void
+rsa_private_key_clear(struct rsa_private_key *key);
+
+int
+rsa_private_key_prepare(struct rsa_private_key *key);
+
+int
+rsa_sha256_sign(const struct rsa_private_key *key,
+ struct sha256_ctx *hash,
+ mpz_t signature);
+
+int
+rsa_sha256_sign_tr(const struct rsa_public_key *pub,
+ const struct rsa_private_key *key,
+ void *random_ctx, nettle_random_func *random,
+ struct sha256_ctx *hash,
+ mpz_t s);
+
+int
+rsa_sha256_verify(const struct rsa_public_key *key,
+ struct sha256_ctx *hash,
+ const mpz_t signature);
+
+int
+rsa_sha256_sign_digest(const struct rsa_private_key *key,
+ const uint8_t *digest,
+ mpz_t s);
+
+int
+rsa_sha256_sign_digest_tr(const struct rsa_public_key *pub,
+ const struct rsa_private_key *key,
+ void *random_ctx, nettle_random_func *random,
+ const uint8_t *digest,
+ mpz_t s);
+
+int
+rsa_sha256_verify_digest(const struct rsa_public_key *key,
+ const uint8_t *digest,
+ const mpz_t signature);
+
+/* RSA encryption, using PKCS#1 */
+/* These functions uses the v1.5 padding. What should the v2 (OAEP)
+ * functions be called? */
+
+/* Returns 1 on success, 0 on failure, which happens if the
+ * message is too long for the key. */
+int
+rsa_encrypt(const struct rsa_public_key *key,
+ /* For padding */
+ void *random_ctx, nettle_random_func *random,
+ size_t length, const uint8_t *cleartext,
+ mpz_t cipher);
+
+/* Message must point to a buffer of size *LENGTH. KEY->size is enough
+ * for all valid messages. On success, *LENGTH is updated to reflect
+ * the actual length of the message. Returns 1 on success, 0 on
+ * failure, which happens if decryption failed or if the message
+ * didn't fit. */
+int
+rsa_decrypt(const struct rsa_private_key *key,
+ size_t *length, uint8_t *cleartext,
+ const mpz_t ciphertext);
+
+/* Timing-resistant version, using randomized RSA blinding. */
+int
+rsa_decrypt_tr(const struct rsa_public_key *pub,
+ const struct rsa_private_key *key,
+ void *random_ctx, nettle_random_func *random,
+ size_t *length, uint8_t *message,
+ const mpz_t gibberish);
+
+/* Compute x, the e:th root of m. Calling it with x == m is allowed. */
+void
+rsa_compute_root(const struct rsa_private_key *key,
+ mpz_t x, const mpz_t m);
+
+/* Safer variant, using RSA blinding, and checking the result after
+ CRT. */
+int
+rsa_compute_root_tr(const struct rsa_public_key *pub,
+ const struct rsa_private_key *key,
+ void *random_ctx, nettle_random_func *random,
+ mpz_t x, const mpz_t m);
+
+/* Key generation */
+
+/* Note that the key structs must be initialized first. */
+int
+rsa_generate_keypair(struct rsa_public_key *pub,
+ struct rsa_private_key *key,
+
+ void *random_ctx, nettle_random_func *random,
+ void *progress_ctx, nettle_progress_func *progress,
+
+ /* Desired size of modulo, in bits */
+ unsigned n_size,
+
+ /* Desired size of public exponent, in bits. If
+ * zero, the passed in value pub->e is used. */
+ unsigned e_size);
+
+
+#define RSA_SIGN(key, algorithm, ctx, length, data, signature) ( \
+ algorithm##_update(ctx, length, data), \
+ rsa_##algorithm##_sign(key, ctx, signature) \
+)
+
+#define RSA_VERIFY(key, algorithm, ctx, length, data, signature) ( \
+ algorithm##_update(ctx, length, data), \
+ rsa_##algorithm##_verify(key, ctx, signature) \
+)
+
+
+/* Keys in sexp form. */
+
+struct nettle_buffer;
+
+/* Generates a public-key expression if PRIV is NULL .*/
+int
+rsa_keypair_to_sexp(struct nettle_buffer *buffer,
+ const char *algorithm_name, /* NULL means "rsa" */
+ const struct rsa_public_key *pub,
+ const struct rsa_private_key *priv);
+
+struct sexp_iterator;
+
+int
+rsa_keypair_from_sexp_alist(struct rsa_public_key *pub,
+ struct rsa_private_key *priv,
+ unsigned limit,
+ struct sexp_iterator *i);
+
+/* If PRIV is NULL, expect a public-key expression. If PUB is NULL,
+ * expect a private key expression and ignore the parts not needed for
+ * the public key. */
+/* Keys must be initialized before calling this function, as usual. */
+int
+rsa_keypair_from_sexp(struct rsa_public_key *pub,
+ struct rsa_private_key *priv,
+ unsigned limit,
+ size_t length, const uint8_t *expr);
+
+
+/* Keys in PKCS#1 format. */
+struct asn1_der_iterator;
+
+int
+rsa_public_key_from_der_iterator(struct rsa_public_key *pub,
+ unsigned limit,
+ struct asn1_der_iterator *i);
+
+int
+rsa_private_key_from_der_iterator(struct rsa_public_key *pub,
+ struct rsa_private_key *priv,
+ unsigned limit,
+ struct asn1_der_iterator *i);
+
+/* For public keys, use PRIV == NULL */
+int
+rsa_keypair_from_der(struct rsa_public_key *pub,
+ struct rsa_private_key *priv,
+ unsigned limit,
+ size_t length, const uint8_t *data);
+
+/* OpenPGP format. Experimental interface, subject to change. */
+int
+rsa_keypair_to_openpgp(struct nettle_buffer *buffer,
+ const struct rsa_public_key *pub,
+ const struct rsa_private_key *priv,
+ /* A single user id. NUL-terminated utf8. */
+ const char *userid);
+
+/* Internal functions. */
+int
+_rsa_verify(const struct rsa_public_key *key,
+ const mpz_t m,
+ const mpz_t s);
+
+size_t
+_rsa_check_size(mpz_t n);
+
+/* _rsa_blind and _rsa_unblind are deprecated, unused in the library,
+ and will likely be removed with the next ABI break. */
+void
+_rsa_blind (const struct rsa_public_key *pub,
+ void *random_ctx, nettle_random_func *random,
+ mpz_t c, mpz_t ri);
+void
+_rsa_unblind (const struct rsa_public_key *pub, mpz_t c, const mpz_t ri);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_RSA_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/rsa2sexp.c b/external/nettle-3.3/nettle/rsa2sexp.c
new file mode 100644
index 0000000..95e029b
--- /dev/null
+++ b/external/nettle-3.3/nettle/rsa2sexp.c
@@ -0,0 +1,59 @@
+/* rsa2sexp.c
+
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "rsa.h"
+
+#include "sexp.h"
+
+int
+rsa_keypair_to_sexp(struct nettle_buffer *buffer,
+ const char *algorithm_name,
+ const struct rsa_public_key *pub,
+ const struct rsa_private_key *priv)
+{
+ if (!algorithm_name)
+ algorithm_name = "rsa-pkcs1";
+
+ if (priv)
+ return sexp_format(buffer,
+ "(private-key(%0s(n%b)(e%b)"
+ "(d%b)(p%b)(q%b)(a%b)(b%b)(c%b)))",
+ algorithm_name, pub->n, pub->e,
+ priv->d, priv->p, priv->q,
+ priv->a, priv->b, priv->c);
+ else
+ return sexp_format(buffer, "(public-key(%0s(n%b)(e%b)))",
+ algorithm_name, pub->n, pub->e);
+}
diff --git a/external/nettle-3.3/nettle/sexp-format.c b/external/nettle-3.3/nettle/sexp-format.c
new file mode 100644
index 0000000..e59b8f3
--- /dev/null
+++ b/external/nettle-3.3/nettle/sexp-format.c
@@ -0,0 +1,348 @@
+/* sexp-format.c
+
+ Writing s-expressions.
+
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sexp.h"
+#include "buffer.h"
+
+#include "bignum.h"
+
+static unsigned
+format_prefix(struct nettle_buffer *buffer,
+ size_t length)
+{
+ size_t digit = 1;
+ unsigned prefix_length = 1;
+
+ for (;;)
+ {
+ size_t next = digit * 10;
+ if (next > length)
+ break;
+
+ prefix_length++;
+ digit = next;
+ }
+
+ if (buffer)
+ {
+ for (; digit; length %= digit, digit /= 10)
+ if (!NETTLE_BUFFER_PUTC(buffer, '0' + length / digit))
+ return 0;
+
+ if (!NETTLE_BUFFER_PUTC(buffer, ':'))
+ return 0;
+ }
+
+ return prefix_length + 1;
+}
+
+static size_t
+format_string(struct nettle_buffer *buffer,
+ size_t length, const uint8_t *s)
+{
+ unsigned prefix_length = format_prefix(buffer, length);
+ if (!prefix_length)
+ return 0;
+
+ if (buffer && !nettle_buffer_write(buffer, length, s))
+ return 0;
+
+ return prefix_length + length;
+}
+
+static inline size_t
+strlen_u8 (const uint8_t *s)
+{
+ return strlen((const char*) s);
+}
+
+size_t
+sexp_vformat(struct nettle_buffer *buffer, const char *format, va_list args)
+{
+ unsigned nesting = 0;
+ size_t done = 0;
+
+ for (;;)
+ switch (*format++)
+ {
+ default:
+ {
+ const char *start = format - 1;
+ size_t length = 1 + strcspn(format, "()% \t");
+ size_t output_length
+ = format_string(buffer, length, (const uint8_t *) start);
+ if (!output_length)
+ return 0;
+
+ done += output_length;
+ format = start + length;
+
+ break;
+ }
+ case ' ': case '\t':
+ break;
+
+ case '\0':
+ assert(!nesting);
+
+ return done;
+
+ case '(':
+ if (buffer && !NETTLE_BUFFER_PUTC(buffer, '('))
+ return 0;
+
+ done++;
+ nesting++;
+ break;
+
+ case ')':
+ assert (nesting);
+ if (buffer && !NETTLE_BUFFER_PUTC(buffer, ')'))
+ return 0;
+
+ done++;
+ nesting--;
+ break;
+
+ case '%':
+ {
+ int nul_flag = 0;
+
+ if (*format == '0')
+ {
+ format++;
+ nul_flag = 1;
+ }
+ switch (*format++)
+ {
+ default:
+ abort();
+
+ case '(':
+ case ')':
+ /* Allow unbalanced parenthesis */
+ if (buffer && !NETTLE_BUFFER_PUTC(buffer, format[-1]))
+ return 0;
+ done++;
+ break;
+
+ case 's':
+ {
+ const uint8_t *s;
+ size_t length;
+ size_t output_length;
+
+ if (nul_flag)
+ {
+ s = va_arg(args, const uint8_t *);
+ length = strlen_u8(s);
+ }
+ else
+ {
+ length = va_arg(args, size_t);
+ s = va_arg(args, const uint8_t *);
+ }
+
+ output_length = format_string(buffer, length, s);
+ if (!output_length)
+ return 0;
+
+ done += output_length;
+ break;
+ }
+ case 't':
+ {
+ const uint8_t *s;
+ size_t length;
+ size_t output_length;
+
+ if (nul_flag)
+ {
+ s = va_arg(args, const uint8_t *);
+ if (!s)
+ break;
+
+ length = strlen_u8(s);
+ }
+ else
+ {
+ length = va_arg(args, size_t);
+ s = va_arg(args, const uint8_t *);
+ if (!s)
+ break;
+ }
+
+ if (buffer && !NETTLE_BUFFER_PUTC(buffer, '['))
+ return 0;
+ done++;
+
+ output_length = format_string(buffer, length, s);
+
+ if (!output_length)
+ return 0;
+
+ done += output_length;
+
+ if (buffer && !NETTLE_BUFFER_PUTC(buffer, ']'))
+ return 0;
+ done++;
+
+ break;
+ }
+
+ case 'l':
+ {
+ const uint8_t *s;
+ size_t length;
+
+ if (nul_flag)
+ {
+ s = va_arg(args, const uint8_t *);
+ length = strlen_u8(s);
+ }
+ else
+ {
+ length = va_arg(args, size_t);
+ s = va_arg(args, const uint8_t *);
+ }
+
+ if (buffer && !nettle_buffer_write(buffer, length, s))
+ return 0;
+
+ done += length;
+ break;
+ }
+ case 'i':
+ {
+ uint32_t x = va_arg(args, uint32_t);
+ unsigned length;
+
+ if (x < 0x80)
+ length = 1;
+ else if (x < 0x8000L)
+ length = 2;
+ else if (x < 0x800000L)
+ length = 3;
+ else if (x < 0x80000000L)
+ length = 4;
+ else
+ length = 5;
+
+ if (buffer && !(NETTLE_BUFFER_PUTC(buffer, '0' + length)
+ && NETTLE_BUFFER_PUTC(buffer, ':')))
+ return 0;
+
+ done += (2 + length);
+
+ if (buffer)
+ switch(length)
+ {
+ case 5:
+ /* Leading byte needed for the sign. */
+ if (!NETTLE_BUFFER_PUTC(buffer, 0))
+ return 0;
+ /* Fall through */
+ case 4:
+ if (!NETTLE_BUFFER_PUTC(buffer, x >> 24))
+ return 0;
+ /* Fall through */
+ case 3:
+ if (!NETTLE_BUFFER_PUTC(buffer, (x >> 16) & 0xff))
+ return 0;
+ /* Fall through */
+ case 2:
+ if (!NETTLE_BUFFER_PUTC(buffer, (x >> 8) & 0xff))
+ return 0;
+ /* Fall through */
+ case 1:
+ if (!NETTLE_BUFFER_PUTC(buffer, x & 0xff))
+ return 0;
+ break;
+ default:
+ abort();
+ }
+ break;
+ }
+ case 'b':
+ {
+ mpz_srcptr n = va_arg(args, mpz_srcptr);
+ size_t length;
+ unsigned prefix_length;
+
+ length = nettle_mpz_sizeinbase_256_s(n);
+ prefix_length = format_prefix(buffer, length);
+ if (!prefix_length)
+ return 0;
+
+ done += prefix_length;
+
+ if (buffer)
+ {
+ uint8_t *space = nettle_buffer_space(buffer, length);
+ if (!space)
+ return 0;
+
+ nettle_mpz_get_str_256(length, space, n);
+ }
+
+ done += length;
+
+ break;
+ }
+ }
+ }
+ }
+}
+
+size_t
+sexp_format(struct nettle_buffer *buffer, const char *format, ...)
+{
+ va_list args;
+ size_t done;
+
+ va_start(args, format);
+ done = sexp_vformat(buffer, format, args);
+ va_end(args);
+
+ return done;
+}
diff --git a/external/nettle-3.3/nettle/sexp.c b/external/nettle-3.3/nettle/sexp.c
new file mode 100644
index 0000000..eb5c211
--- /dev/null
+++ b/external/nettle-3.3/nettle/sexp.c
@@ -0,0 +1,399 @@
+/* sexp.c
+
+ Parsing s-expressions.
+
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "sexp.h"
+
+#include "macros.h"
+#include "nettle-internal.h"
+
+/* Initializes the iterator, but one has to call next to get to the
+ * first element. */
+static void
+sexp_iterator_init(struct sexp_iterator *iterator,
+ unsigned length, const uint8_t *input)
+{
+ iterator->length = length;
+ iterator->buffer = input;
+ iterator->pos = 0;
+ iterator->level = 0;
+ iterator->type = SEXP_END; /* Value doesn't matter */
+ iterator->display_length = 0;
+ iterator->display = NULL;
+ iterator->atom_length = 0;
+ iterator->atom = NULL;
+}
+
+#define EMPTY(i) ((i)->pos == (i)->length)
+#define NEXT(i) ((i)->buffer[(i)->pos++])
+
+static int
+sexp_iterator_simple(struct sexp_iterator *iterator,
+ size_t *size,
+ const uint8_t **string)
+{
+ unsigned length = 0;
+ uint8_t c;
+
+ if (EMPTY(iterator)) return 0;
+ c = NEXT(iterator);
+ if (EMPTY(iterator)) return 0;
+
+ if (c >= '1' && c <= '9')
+ do
+ {
+ length = length * 10 + (c - '0');
+ if (length > (iterator->length - iterator->pos))
+ return 0;
+
+ if (EMPTY(iterator)) return 0;
+ c = NEXT(iterator);
+ }
+ while (c >= '0' && c <= '9');
+
+ else if (c == '0')
+ /* There can be only one */
+ c = NEXT(iterator);
+ else
+ return 0;
+
+ if (c != ':')
+ return 0;
+
+ *size = length;
+ *string = iterator->buffer + iterator->pos;
+ iterator->pos += length;
+
+ return 1;
+}
+
+/* All these functions return 1 on success, 0 on failure */
+
+/* Look at the current position in the data. Sets iterator->type, and
+ * ignores the old value. */
+
+static int
+sexp_iterator_parse(struct sexp_iterator *iterator)
+{
+ iterator->start = iterator->pos;
+
+ if (EMPTY(iterator))
+ {
+ if (iterator->level)
+ return 0;
+
+ iterator->type = SEXP_END;
+ return 1;
+ }
+ switch (iterator->buffer[iterator->pos])
+ {
+ case '(': /* A list */
+ iterator->type = SEXP_LIST;
+ return 1;
+
+ case ')':
+ if (!iterator->level)
+ return 0;
+
+ iterator->pos++;
+ iterator->type = SEXP_END;
+ return 1;
+
+ case '[': /* Atom with display type */
+ iterator->pos++;
+ if (!sexp_iterator_simple(iterator,
+ &iterator->display_length,
+ &iterator->display))
+ return 0;
+ if (EMPTY(iterator) || NEXT(iterator) != ']')
+ return 0;
+
+ break;
+
+ default:
+ /* Must be either a decimal digit or a syntax error.
+ * Errors are detected by sexp_iterator_simple. */
+ iterator->display_length = 0;
+ iterator->display = NULL;
+
+ break;
+ }
+
+ iterator->type = SEXP_ATOM;
+
+ return sexp_iterator_simple(iterator,
+ &iterator->atom_length,
+ &iterator->atom);
+}
+
+int
+sexp_iterator_first(struct sexp_iterator *iterator,
+ size_t length, const uint8_t *input)
+{
+ sexp_iterator_init(iterator, length, input);
+ return sexp_iterator_parse(iterator);
+}
+
+int
+sexp_iterator_next(struct sexp_iterator *iterator)
+{
+ switch (iterator->type)
+ {
+ case SEXP_END:
+ return 1;
+ case SEXP_LIST:
+ /* Skip this list */
+ return sexp_iterator_enter_list(iterator)
+ && sexp_iterator_exit_list(iterator);
+ case SEXP_ATOM:
+ /* iterator->pos should already point at the start of the next
+ * element. */
+ return sexp_iterator_parse(iterator);
+ }
+ /* If we get here, we have a bug. */
+ abort();
+}
+
+/* Current element must be a list. */
+int
+sexp_iterator_enter_list(struct sexp_iterator *iterator)
+{
+ if (iterator->type != SEXP_LIST)
+ return 0;
+
+ if (EMPTY(iterator) || NEXT(iterator) != '(')
+ /* Internal error */
+ abort();
+
+ iterator->level++;
+
+ return sexp_iterator_parse(iterator);
+}
+
+/* Skips the rest of the current list */
+int
+sexp_iterator_exit_list(struct sexp_iterator *iterator)
+{
+ if (!iterator->level)
+ return 0;
+
+ while(iterator->type != SEXP_END)
+ if (!sexp_iterator_next(iterator))
+ return 0;
+
+ iterator->level--;
+
+ return sexp_iterator_parse(iterator);
+}
+
+#if 0
+/* What's a reasonable interface for this? */
+int
+sexp_iterator_exit_lists(struct sexp_iterator *iterator,
+ unsigned level)
+{
+ assert(iterator->level >= level);
+
+ while (iterator->level > level)
+ if (!sexp_iterator_exit_list(iterator))
+ return 0;
+
+ return 1;
+}
+#endif
+
+const uint8_t *
+sexp_iterator_subexpr(struct sexp_iterator *iterator,
+ size_t *length)
+{
+ size_t start = iterator->start;
+ if (!sexp_iterator_next(iterator))
+ return 0;
+
+ *length = iterator->start - start;
+ return iterator->buffer + start;
+}
+
+int
+sexp_iterator_get_uint32(struct sexp_iterator *iterator,
+ uint32_t *x)
+{
+ if (iterator->type == SEXP_ATOM
+ && !iterator->display
+ && iterator->atom_length
+ && iterator->atom[0] < 0x80)
+ {
+ size_t length = iterator->atom_length;
+ const uint8_t *p = iterator->atom;
+
+ /* Skip leading zeros. */
+ while(length && !*p)
+ {
+ length--; p++;
+ }
+
+ switch(length)
+ {
+ case 0:
+ *x = 0;
+ break;
+ case 1:
+ *x = p[0];
+ break;
+ case 2:
+ *x = READ_UINT16(p);
+ break;
+ case 3:
+ *x = READ_UINT24(p);
+ break;
+ case 4:
+ *x = READ_UINT32(p);
+ break;
+ default:
+ return 0;
+ }
+ return sexp_iterator_next(iterator);
+ }
+ return 0;
+}
+
+int
+sexp_iterator_check_type(struct sexp_iterator *iterator,
+ const char *type)
+{
+ return (sexp_iterator_enter_list(iterator)
+ && iterator->type == SEXP_ATOM
+ && !iterator->display
+ && strlen(type) == iterator->atom_length
+ && !memcmp(type, iterator->atom, iterator->atom_length)
+ && sexp_iterator_next(iterator));
+}
+
+const char *
+sexp_iterator_check_types(struct sexp_iterator *iterator,
+ unsigned ntypes,
+ const char * const *types)
+{
+ if (sexp_iterator_enter_list(iterator)
+ && iterator->type == SEXP_ATOM
+ && !iterator->display)
+ {
+ unsigned i;
+ for (i = 0; i<ntypes; i++)
+ if (strlen(types[i]) == iterator->atom_length
+ && !memcmp(types[i], iterator->atom,
+ iterator->atom_length))
+ return sexp_iterator_next(iterator) ? types[i] : NULL;
+ }
+ return NULL;
+}
+
+int
+sexp_iterator_assoc(struct sexp_iterator *iterator,
+ unsigned nkeys,
+ const char * const *keys,
+ struct sexp_iterator *values)
+{
+ TMP_DECL(found, int, NETTLE_MAX_SEXP_ASSOC);
+ unsigned nfound;
+ unsigned i;
+
+ TMP_ALLOC(found, nkeys);
+ for (i = 0; i<nkeys; i++)
+ found[i] = 0;
+
+ nfound = 0;
+
+ for (;;)
+ {
+ switch (iterator->type)
+ {
+ case SEXP_LIST:
+
+ if (!sexp_iterator_enter_list(iterator))
+ return 0;
+
+ if (iterator->type == SEXP_ATOM
+ && !iterator->display)
+ {
+ /* Compare to the given keys */
+ for (i = 0; i<nkeys; i++)
+ {
+ /* NOTE: The strlen could be put outside of the
+ * loop */
+ if (strlen(keys[i]) == iterator->atom_length
+ && !memcmp(keys[i], iterator->atom,
+ iterator->atom_length))
+ {
+ if (found[i])
+ /* We don't allow duplicates */
+ return 0;
+
+ /* Advance to point to value */
+ if (!sexp_iterator_next(iterator))
+ return 0;
+
+ found[i] = 1;
+ nfound++;
+
+ /* Record this position. */
+ values[i] = *iterator;
+
+ break;
+ }
+ }
+ }
+ if (!sexp_iterator_exit_list(iterator))
+ return 0;
+ break;
+ case SEXP_ATOM:
+ /* Just ignore */
+ if (!sexp_iterator_next(iterator))
+ return 0;
+ break;
+
+ case SEXP_END:
+ return sexp_iterator_exit_list(iterator)
+ && (nfound == nkeys);
+
+ default:
+ abort();
+ }
+ }
+}
diff --git a/external/nettle-3.3/nettle/sexp.h b/external/nettle-3.3/nettle/sexp.h
new file mode 100644
index 0000000..58b089c
--- /dev/null
+++ b/external/nettle-3.3/nettle/sexp.h
@@ -0,0 +1,213 @@
+/* sexp.h
+
+ Parsing s-expressions.
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_SEXP_H_INCLUDED
+#define NETTLE_SEXP_H_INCLUDED
+
+#include <stdarg.h>
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define sexp_iterator_first nettle_sexp_iterator_first
+#define sexp_transport_iterator_first nettle_sexp_transport_iterator_first
+#define sexp_iterator_next nettle_sexp_iterator_next
+#define sexp_iterator_enter_list nettle_sexp_iterator_enter_list
+#define sexp_iterator_exit_list nettle_sexp_iterator_exit_list
+#define sexp_iterator_subexpr nettle_sexp_iterator_subexpr
+#define sexp_iterator_get_uint32 nettle_sexp_iterator_get_uint32
+#define sexp_iterator_check_type nettle_sexp_iterator_check_type
+#define sexp_iterator_check_types nettle_sexp_iterator_check_types
+#define sexp_iterator_assoc nettle_sexp_iterator_assoc
+#define sexp_format nettle_sexp_format
+#define sexp_vformat nettle_sexp_vformat
+#define sexp_transport_format nettle_sexp_transport_format
+#define sexp_transport_vformat nettle_sexp_transport_vformat
+#define sexp_token_chars nettle_sexp_token_chars
+
+enum sexp_type
+ { SEXP_ATOM, SEXP_LIST, SEXP_END };
+
+struct sexp_iterator
+{
+ size_t length;
+ const uint8_t *buffer;
+
+ /* Points at the start of the current sub expression. */
+ size_t start;
+ /* If type is SEXP_LIST, pos points at the start of the current
+ * element. Otherwise, it points at the end. */
+ size_t pos;
+ unsigned level;
+
+ enum sexp_type type;
+
+ size_t display_length;
+ const uint8_t *display;
+
+ size_t atom_length;
+ const uint8_t *atom;
+};
+
+
+/* All these functions return 1 on success, 0 on failure */
+
+/* Initializes the iterator. */
+int
+sexp_iterator_first(struct sexp_iterator *iterator,
+ size_t length, const uint8_t *input);
+
+/* NOTE: Decodes the input string in place */
+int
+sexp_transport_iterator_first(struct sexp_iterator *iterator,
+ size_t length, uint8_t *input);
+
+int
+sexp_iterator_next(struct sexp_iterator *iterator);
+
+/* Current element must be a list. */
+int
+sexp_iterator_enter_list(struct sexp_iterator *iterator);
+
+/* Skips the rest of the current list */
+int
+sexp_iterator_exit_list(struct sexp_iterator *iterator);
+
+#if 0
+/* Skips out of as many lists as necessary to get back to the given
+ * level. */
+int
+sexp_iterator_exit_lists(struct sexp_iterator *iterator,
+ unsigned level);
+#endif
+
+/* Gets start and length of the current subexpression. Implies
+ * sexp_iterator_next. */
+const uint8_t *
+sexp_iterator_subexpr(struct sexp_iterator *iterator,
+ size_t *length);
+
+int
+sexp_iterator_get_uint32(struct sexp_iterator *iterator,
+ uint32_t *x);
+
+
+/* Checks the type of the current expression, which should be a list
+ *
+ * (<type> ...)
+ */
+int
+sexp_iterator_check_type(struct sexp_iterator *iterator,
+ const char *type);
+
+const char *
+sexp_iterator_check_types(struct sexp_iterator *iterator,
+ unsigned ntypes,
+ const char * const *types);
+
+/* Current element must be a list. Looks up element of type
+ *
+ * (key rest...)
+ *
+ * For a matching key, the corresponding iterator is initialized
+ * pointing at the start of REST.
+ *
+ * On success, exits the current list.
+ */
+int
+sexp_iterator_assoc(struct sexp_iterator *iterator,
+ unsigned nkeys,
+ const char * const *keys,
+ struct sexp_iterator *values);
+
+
+/* Output functions. What is a reasonable API for this? It seems
+ * ugly to have to reimplement string streams. */
+
+/* Declared for real in buffer.h */
+struct nettle_buffer;
+
+/* Returns the number of output characters, or 0 on out of memory. If
+ * buffer == NULL, just compute length.
+ *
+ * Format strings can contained matched parentheses, tokens ("foo" in
+ * the format string is formatted as "3:foo"), whitespace (which
+ * separates tokens but is otherwise ignored) and the following
+ * formatting specifiers:
+ *
+ * %s String represented as size_t length, const uint8_t *data.
+ *
+ * %t Optional display type, represented as
+ * size_t display_length, const uint8_t *display,
+ * display == NULL means no display type.
+ *
+ * %i Non-negative small integer, uint32_t.
+ *
+ * %b Non-negative bignum, mpz_t.
+ *
+ * %l Literal string (no length added), typically a balanced
+ * subexpression. Represented as size_t length, const uint8_t
+ * *data.
+ *
+ * %(, %) Allows insertion of unbalanced parenthesis.
+ *
+ * Modifiers:
+ *
+ * %0 For %s, %t and %l, says that there's no length argument,
+ * instead the string is NUL-terminated, and there's only one
+ * const uint8_t * argument.
+ */
+
+size_t
+sexp_format(struct nettle_buffer *buffer,
+ const char *format, ...);
+
+size_t
+sexp_vformat(struct nettle_buffer *buffer,
+ const char *format, va_list args);
+
+size_t
+sexp_transport_format(struct nettle_buffer *buffer,
+ const char *format, ...);
+
+size_t
+sexp_transport_vformat(struct nettle_buffer *buffer,
+ const char *format, va_list args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_SEXP_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/sexp2bignum.c b/external/nettle-3.3/nettle/sexp2bignum.c
new file mode 100644
index 0000000..692ee42
--- /dev/null
+++ b/external/nettle-3.3/nettle/sexp2bignum.c
@@ -0,0 +1,60 @@
+/* sexp2bignum.c
+
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "sexp.h"
+#include "bignum.h"
+
+int
+nettle_mpz_set_sexp(mpz_t x, unsigned limit, struct sexp_iterator *i)
+{
+ if (i->type == SEXP_ATOM
+ && i->atom_length
+ && !i->display)
+ {
+ /* Allow some extra here, for leading sign octets. */
+ if (limit && (8 * i->atom_length > (16 + limit)))
+ return 0;
+
+ nettle_mpz_set_str_256_s(x, i->atom_length, i->atom);
+
+ /* FIXME: How to interpret a limit for negative numbers? */
+ if (limit && mpz_sizeinbase(x, 2) > limit)
+ return 0;
+
+ return sexp_iterator_next(i);
+ }
+ else
+ return 0;
+}
diff --git a/external/nettle-3.3/nettle/sexp2rsa.c b/external/nettle-3.3/nettle/sexp2rsa.c
new file mode 100644
index 0000000..b42a3d4
--- /dev/null
+++ b/external/nettle-3.3/nettle/sexp2rsa.c
@@ -0,0 +1,115 @@
+/* sexp2rsa.c
+
+ Copyright (C) 2002 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include "rsa.h"
+
+#include "bignum.h"
+#include "sexp.h"
+
+#define GET(x, l, v) \
+do { \
+ if (!nettle_mpz_set_sexp((x), (l), (v)) \
+ || mpz_sgn(x) <= 0) \
+ return 0; \
+} while(0)
+
+/* Iterator should point past the algorithm tag, e.g.
+ *
+ * (public-key (rsa (n |xxxx|) (e |xxxx|))
+ * ^ here
+ */
+
+int
+rsa_keypair_from_sexp_alist(struct rsa_public_key *pub,
+ struct rsa_private_key *priv,
+ unsigned limit,
+ struct sexp_iterator *i)
+{
+ static const char * const names[8]
+ = { "n", "e", "d", "p", "q", "a", "b", "c" };
+ struct sexp_iterator values[8];
+ unsigned nvalues = priv ? 8 : 2;
+
+ if (!sexp_iterator_assoc(i, nvalues, names, values))
+ return 0;
+
+ if (priv)
+ {
+ GET(priv->d, limit, &values[2]);
+ GET(priv->p, limit, &values[3]);
+ GET(priv->q, limit, &values[4]);
+ GET(priv->a, limit, &values[5]);
+ GET(priv->b, limit, &values[6]);
+ GET(priv->c, limit, &values[7]);
+
+ if (!rsa_private_key_prepare(priv))
+ return 0;
+ }
+
+ if (pub)
+ {
+ GET(pub->n, limit, &values[0]);
+ GET(pub->e, limit, &values[1]);
+
+ if (!rsa_public_key_prepare(pub))
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+rsa_keypair_from_sexp(struct rsa_public_key *pub,
+ struct rsa_private_key *priv,
+ unsigned limit,
+ size_t length, const uint8_t *expr)
+{
+ struct sexp_iterator i;
+ static const char * const names[3]
+ = { "rsa", "rsa-pkcs1", "rsa-pkcs1-sha1" };
+
+ if (!sexp_iterator_first(&i, length, expr))
+ return 0;
+
+ if (!sexp_iterator_check_type(&i, priv ? "private-key" : "public-key"))
+ return 0;
+
+ if (!sexp_iterator_check_types(&i, 3, names))
+ return 0;
+
+ return rsa_keypair_from_sexp_alist(pub, priv, limit, &i);
+}
diff --git a/external/nettle-3.3/nettle/sha2.h b/external/nettle-3.3/nettle/sha2.h
new file mode 100644
index 0000000..d0426d7
--- /dev/null
+++ b/external/nettle-3.3/nettle/sha2.h
@@ -0,0 +1,206 @@
+/* sha2.h
+
+ The sha2 family of hash functions.
+
+ Copyright (C) 2001, 2012 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_SHA2_H_INCLUDED
+#define NETTLE_SHA2_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define sha224_init nettle_sha224_init
+#define sha224_digest nettle_sha224_digest
+#define sha256_init nettle_sha256_init
+#define sha256_update nettle_sha256_update
+#define sha256_digest nettle_sha256_digest
+#define sha384_init nettle_sha384_init
+#define sha384_digest nettle_sha384_digest
+#define sha512_init nettle_sha512_init
+#define sha512_update nettle_sha512_update
+#define sha512_digest nettle_sha512_digest
+#define sha512_224_init nettle_sha512_224_init
+#define sha512_224_digest nettle_sha512_224_digest
+#define sha512_256_init nettle_sha512_256_init
+#define sha512_256_digest nettle_sha512_256_digest
+
+/* For backwards compatibility */
+#define SHA224_DATA_SIZE SHA256_BLOCK_SIZE
+#define SHA256_DATA_SIZE SHA256_BLOCK_SIZE
+#define SHA512_DATA_SIZE SHA512_BLOCK_SIZE
+#define SHA384_DATA_SIZE SHA512_BLOCK_SIZE
+
+/* SHA256 */
+
+#define SHA256_DIGEST_SIZE 32
+#define SHA256_BLOCK_SIZE 64
+
+/* Digest is kept internally as 8 32-bit words. */
+#define _SHA256_DIGEST_LENGTH 8
+
+struct sha256_ctx
+{
+ uint32_t state[_SHA256_DIGEST_LENGTH]; /* State variables */
+ uint64_t count; /* 64-bit block count */
+ uint8_t block[SHA256_BLOCK_SIZE]; /* SHA256 data buffer */
+ unsigned int index; /* index into buffer */
+};
+
+void
+sha256_init(struct sha256_ctx *ctx);
+
+void
+sha256_update(struct sha256_ctx *ctx,
+ size_t length,
+ const uint8_t *data);
+
+void
+sha256_digest(struct sha256_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+/* Internal compression function. STATE points to 8 uint32_t words,
+ DATA points to 64 bytes of input data, possibly unaligned, and K
+ points to the table of constants. */
+void
+_nettle_sha256_compress(uint32_t *state, const uint8_t *data, const uint32_t *k);
+
+
+/* SHA224, a truncated SHA256 with different initial state. */
+
+#define SHA224_DIGEST_SIZE 28
+#define SHA224_BLOCK_SIZE SHA256_BLOCK_SIZE
+#define sha224_ctx sha256_ctx
+
+void
+sha224_init(struct sha256_ctx *ctx);
+
+#define sha224_update nettle_sha256_update
+
+void
+sha224_digest(struct sha256_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+
+/* SHA512 */
+
+#define SHA512_DIGEST_SIZE 64
+#define SHA512_BLOCK_SIZE 128
+
+/* Digest is kept internally as 8 64-bit words. */
+#define _SHA512_DIGEST_LENGTH 8
+
+struct sha512_ctx
+{
+ uint64_t state[_SHA512_DIGEST_LENGTH]; /* State variables */
+ uint64_t count_low, count_high; /* 128-bit block count */
+ uint8_t block[SHA512_BLOCK_SIZE]; /* SHA512 data buffer */
+ unsigned int index; /* index into buffer */
+};
+
+void
+sha512_init(struct sha512_ctx *ctx);
+
+void
+sha512_update(struct sha512_ctx *ctx,
+ size_t length,
+ const uint8_t *data);
+
+void
+sha512_digest(struct sha512_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+/* Internal compression function. STATE points to 8 uint64_t words,
+ DATA points to 128 bytes of input data, possibly unaligned, and K
+ points to the table of constants. */
+void
+_nettle_sha512_compress(uint64_t *state, const uint8_t *data, const uint64_t *k);
+
+
+/* SHA384, a truncated SHA512 with different initial state. */
+
+#define SHA384_DIGEST_SIZE 48
+#define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE
+#define sha384_ctx sha512_ctx
+
+void
+sha384_init(struct sha512_ctx *ctx);
+
+#define sha384_update nettle_sha512_update
+
+void
+sha384_digest(struct sha512_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+
+/* SHA512_224 and SHA512_256, two truncated versions of SHA512
+ with different initial states. */
+
+#define SHA512_224_DIGEST_SIZE 28
+#define SHA512_224_BLOCK_SIZE SHA512_BLOCK_SIZE
+#define sha512_224_ctx sha512_ctx
+
+void
+sha512_224_init(struct sha512_224_ctx *ctx);
+
+#define sha512_224_update nettle_sha512_update
+
+void
+sha512_224_digest(struct sha512_224_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+#define SHA512_256_DIGEST_SIZE 32
+#define SHA512_256_BLOCK_SIZE SHA512_BLOCK_SIZE
+#define sha512_256_ctx sha512_ctx
+
+void
+sha512_256_init(struct sha512_256_ctx *ctx);
+
+#define sha512_256_update nettle_sha512_update
+
+void
+sha512_256_digest(struct sha512_256_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_SHA2_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/sha256-compress.c b/external/nettle-3.3/nettle/sha256-compress.c
new file mode 100644
index 0000000..8b82d70
--- /dev/null
+++ b/external/nettle-3.3/nettle/sha256-compress.c
@@ -0,0 +1,199 @@
+/* sha256-compress.c
+
+ The compression function of the sha256 hash function.
+
+ Copyright (C) 2001, 2010 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef SHA256_DEBUG
+# define SHA256_DEBUG 0
+#endif
+
+#if SHA256_DEBUG
+# include <stdio.h>
+# define DEBUG(i) \
+ fprintf(stderr, "%2d: %8x %8x %8x %8x %8x %8x %8x %8x\n", \
+ i, A, B, C, D ,E, F, G, H)
+#else
+# define DEBUG(i)
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sha2.h"
+
+#include "macros.h"
+
+/* A block, treated as a sequence of 32-bit words. */
+#define SHA256_DATA_LENGTH 16
+
+/* The SHA256 functions. The Choice function is the same as the SHA1
+ function f1, and the majority function is the same as the SHA1 f3
+ function. They can be optimized to save one boolean operation each
+ - thanks to Rich Schroeppel, rcs@cs.arizona.edu for discovering
+ this */
+
+/* #define Choice(x,y,z) ( ( (x) & (y) ) | ( ~(x) & (z) ) ) */
+#define Choice(x,y,z) ( (z) ^ ( (x) & ( (y) ^ (z) ) ) )
+/* #define Majority(x,y,z) ( ((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)) ) */
+#define Majority(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) )
+
+#define S0(x) (ROTL32(30,(x)) ^ ROTL32(19,(x)) ^ ROTL32(10,(x)))
+#define S1(x) (ROTL32(26,(x)) ^ ROTL32(21,(x)) ^ ROTL32(7,(x)))
+
+#define s0(x) (ROTL32(25,(x)) ^ ROTL32(14,(x)) ^ ((x) >> 3))
+#define s1(x) (ROTL32(15,(x)) ^ ROTL32(13,(x)) ^ ((x) >> 10))
+
+/* The initial expanding function. The hash function is defined over an
+ 64-word expanded input array W, where the first 16 are copies of the input
+ data, and the remaining 64 are defined by
+
+ W[ t ] = s1(W[t-2]) + W[t-7] + s0(W[i-15]) + W[i-16]
+
+ This implementation generates these values on the fly in a circular
+ buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this
+ optimization.
+*/
+
+#define EXPAND(W,i) \
+( W[(i) & 15 ] += (s1(W[((i)-2) & 15]) + W[((i)-7) & 15] + s0(W[((i)-15) & 15])) )
+
+/* The prototype SHA sub-round. The fundamental sub-round is:
+
+ T1 = h + S1(e) + Choice(e,f,g) + K[t] + W[t]
+ T2 = S0(a) + Majority(a,b,c)
+ a' = T1+T2
+ b' = a
+ c' = b
+ d' = c
+ e' = d + T1
+ f' = e
+ g' = f
+ h' = g
+
+ but this is implemented by unrolling the loop 8 times and renaming
+ the variables
+ ( h, a, b, c, d, e, f, g ) = ( a, b, c, d, e, f, g, h ) each
+ iteration. */
+
+/* It's crucial that DATA is only used once, as that argument will
+ * have side effects. */
+#define ROUND(a,b,c,d,e,f,g,h,k,data) do { \
+ h += S1(e) + Choice(e,f,g) + k + data; \
+ d += h; \
+ h += S0(a) + Majority(a,b,c); \
+ } while (0)
+
+/* For fat builds */
+#if HAVE_NATIVE_sha256_compress
+void
+_nettle_sha256_compress_c(uint32_t *state, const uint8_t *input, const uint32_t *k);
+#define _nettle_sha256_compress _nettle_sha256_compress_c
+#endif
+
+void
+_nettle_sha256_compress(uint32_t *state, const uint8_t *input, const uint32_t *k)
+{
+ uint32_t data[SHA256_DATA_LENGTH];
+ uint32_t A, B, C, D, E, F, G, H; /* Local vars */
+ unsigned i;
+ uint32_t *d;
+
+ for (i = 0; i < SHA256_DATA_LENGTH; i++, input+= 4)
+ {
+ data[i] = READ_UINT32(input);
+ }
+
+ /* Set up first buffer and local data buffer */
+ A = state[0];
+ B = state[1];
+ C = state[2];
+ D = state[3];
+ E = state[4];
+ F = state[5];
+ G = state[6];
+ H = state[7];
+
+ /* Heavy mangling */
+ /* First 16 subrounds that act on the original data */
+
+ DEBUG(-1);
+ for (i = 0, d = data; i<16; i+=8, k += 8, d+= 8)
+ {
+ ROUND(A, B, C, D, E, F, G, H, k[0], d[0]); DEBUG(i);
+ ROUND(H, A, B, C, D, E, F, G, k[1], d[1]); DEBUG(i+1);
+ ROUND(G, H, A, B, C, D, E, F, k[2], d[2]);
+ ROUND(F, G, H, A, B, C, D, E, k[3], d[3]);
+ ROUND(E, F, G, H, A, B, C, D, k[4], d[4]);
+ ROUND(D, E, F, G, H, A, B, C, k[5], d[5]);
+ ROUND(C, D, E, F, G, H, A, B, k[6], d[6]); DEBUG(i+6);
+ ROUND(B, C, D, E, F, G, H, A, k[7], d[7]); DEBUG(i+7);
+ }
+
+ for (; i<64; i += 16, k+= 16)
+ {
+ ROUND(A, B, C, D, E, F, G, H, k[ 0], EXPAND(data, 0)); DEBUG(i);
+ ROUND(H, A, B, C, D, E, F, G, k[ 1], EXPAND(data, 1)); DEBUG(i+1);
+ ROUND(G, H, A, B, C, D, E, F, k[ 2], EXPAND(data, 2)); DEBUG(i+2);
+ ROUND(F, G, H, A, B, C, D, E, k[ 3], EXPAND(data, 3)); DEBUG(i+3);
+ ROUND(E, F, G, H, A, B, C, D, k[ 4], EXPAND(data, 4)); DEBUG(i+4);
+ ROUND(D, E, F, G, H, A, B, C, k[ 5], EXPAND(data, 5)); DEBUG(i+5);
+ ROUND(C, D, E, F, G, H, A, B, k[ 6], EXPAND(data, 6)); DEBUG(i+6);
+ ROUND(B, C, D, E, F, G, H, A, k[ 7], EXPAND(data, 7)); DEBUG(i+7);
+ ROUND(A, B, C, D, E, F, G, H, k[ 8], EXPAND(data, 8)); DEBUG(i+8);
+ ROUND(H, A, B, C, D, E, F, G, k[ 9], EXPAND(data, 9)); DEBUG(i+9);
+ ROUND(G, H, A, B, C, D, E, F, k[10], EXPAND(data, 10)); DEBUG(i+10);
+ ROUND(F, G, H, A, B, C, D, E, k[11], EXPAND(data, 11)); DEBUG(i+11);
+ ROUND(E, F, G, H, A, B, C, D, k[12], EXPAND(data, 12)); DEBUG(i+12);
+ ROUND(D, E, F, G, H, A, B, C, k[13], EXPAND(data, 13)); DEBUG(i+13);
+ ROUND(C, D, E, F, G, H, A, B, k[14], EXPAND(data, 14)); DEBUG(i+14);
+ ROUND(B, C, D, E, F, G, H, A, k[15], EXPAND(data, 15)); DEBUG(i+15);
+ }
+
+ /* Update state */
+ state[0] += A;
+ state[1] += B;
+ state[2] += C;
+ state[3] += D;
+ state[4] += E;
+ state[5] += F;
+ state[6] += G;
+ state[7] += H;
+#if SHA256_DEBUG
+ fprintf(stderr, "99: %8x %8x %8x %8x %8x %8x %8x %8x\n",
+ state[0], state[1], state[2], state[3],
+ state[4], state[5], state[6], state[7]);
+#endif
+}
diff --git a/external/nettle-3.3/nettle/sha256.c b/external/nettle-3.3/nettle/sha256.c
new file mode 100644
index 0000000..0cb3559
--- /dev/null
+++ b/external/nettle-3.3/nettle/sha256.c
@@ -0,0 +1,162 @@
+/* sha256.c
+
+ The sha256 hash function.
+ See http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+
+ Copyright (C) 2001 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+/* Modelled after the sha1.c code by Peter Gutmann. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sha2.h"
+
+#include "macros.h"
+#include "nettle-write.h"
+
+/* Generated by the shadata program. */
+static const uint32_t
+K[64] =
+{
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+ 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+ 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+ 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+ 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+ 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+ 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+ 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+ 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+ 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+ 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+ 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+ 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
+};
+
+#define COMPRESS(ctx, data) (_nettle_sha256_compress((ctx)->state, (data), K))
+
+/* Initialize the SHA values */
+
+void
+sha256_init(struct sha256_ctx *ctx)
+{
+ /* Initial values, also generated by the shadata program. */
+ static const uint32_t H0[_SHA256_DIGEST_LENGTH] =
+ {
+ 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL,
+ 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL,
+ };
+
+ memcpy(ctx->state, H0, sizeof(H0));
+
+ /* Initialize bit count */
+ ctx->count = 0;
+
+ /* Initialize buffer */
+ ctx->index = 0;
+}
+
+void
+sha256_update(struct sha256_ctx *ctx,
+ size_t length, const uint8_t *data)
+{
+ MD_UPDATE (ctx, length, data, COMPRESS, ctx->count++);
+}
+
+static void
+sha256_write_digest(struct sha256_ctx *ctx,
+ size_t length,
+ uint8_t *digest)
+{
+ uint64_t bit_count;
+
+ assert(length <= SHA256_DIGEST_SIZE);
+
+ MD_PAD(ctx, 8, COMPRESS);
+
+ /* There are 512 = 2^9 bits in one block */
+ bit_count = (ctx->count << 9) | (ctx->index << 3);
+
+ /* This is slightly inefficient, as the numbers are converted to
+ big-endian format, and will be converted back by the compression
+ function. It's probably not worth the effort to fix this. */
+ WRITE_UINT64(ctx->block + (SHA256_BLOCK_SIZE - 8), bit_count);
+ COMPRESS(ctx, ctx->block);
+
+ _nettle_write_be32(length, digest, ctx->state);
+}
+
+void
+sha256_digest(struct sha256_ctx *ctx,
+ size_t length,
+ uint8_t *digest)
+{
+ sha256_write_digest(ctx, length, digest);
+ sha256_init(ctx);
+}
+
+/* sha224 variant. */
+
+void
+sha224_init(struct sha256_ctx *ctx)
+{
+ /* Initial values. Low 32 bits of the initial values for sha384. */
+ static const uint32_t H0[_SHA256_DIGEST_LENGTH] =
+ {
+ 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+ 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,
+ };
+
+ memcpy(ctx->state, H0, sizeof(H0));
+
+ /* Initialize bit count */
+ ctx->count = 0;
+
+ /* Initialize buffer */
+ ctx->index = 0;
+}
+
+void
+sha224_digest(struct sha256_ctx *ctx,
+ size_t length,
+ uint8_t *digest)
+{
+ sha256_write_digest(ctx, length, digest);
+ sha224_init(ctx);
+}
diff --git a/external/nettle-3.3/nettle/version.h b/external/nettle-3.3/nettle/version.h
new file mode 100644
index 0000000..3a1d20c
--- /dev/null
+++ b/external/nettle-3.3/nettle/version.h
@@ -0,0 +1,58 @@
+/* version.h
+
+ Information about library version.
+
+ Copyright (C) 2015 Red Hat, Inc.
+ Copyright (C) 2015 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_VERSION_H_INCLUDED
+#define NETTLE_VERSION_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Individual version numbers in decimal */
+#define NETTLE_VERSION_MAJOR 3
+#define NETTLE_VERSION_MINOR 3
+
+#define NETTLE_USE_MINI_GMP 1
+
+/* We need a preprocessor constant for GMP_NUMB_BITS, simply using
+ sizeof(mp_limb_t) * CHAR_BIT is not good enough. */
+#if NETTLE_USE_MINI_GMP
+# define GMP_NUMB_BITS (sizeof(unsigned long) * 8)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_VERSION_H_INCLUDED */
diff --git a/external/nettle-3.3/nettle/write-be32.c b/external/nettle-3.3/nettle/write-be32.c
new file mode 100644
index 0000000..7d68905
--- /dev/null
+++ b/external/nettle-3.3/nettle/write-be32.c
@@ -0,0 +1,77 @@
+/* write-be32.c
+
+ Copyright (C) 2001 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "nettle-write.h"
+
+#include "macros.h"
+
+void
+_nettle_write_be32(size_t length, uint8_t *dst,
+ uint32_t *src)
+{
+ size_t i;
+ size_t words;
+ unsigned leftover;
+
+ words = length / 4;
+ leftover = length % 4;
+
+ for (i = 0; i < words; i++, dst += 4)
+ WRITE_UINT32(dst, src[i]);
+
+ if (leftover)
+ {
+ uint32_t word;
+ unsigned j = leftover;
+
+ word = src[i];
+
+ switch (leftover)
+ {
+ default:
+ abort();
+ case 3:
+ dst[--j] = (word >> 8) & 0xff;
+ /* Fall through */
+ case 2:
+ dst[--j] = (word >> 16) & 0xff;
+ /* Fall through */
+ case 1:
+ dst[--j] = (word >> 24) & 0xff;
+ }
+ }
+}
diff --git a/external/opus-1.1.4/CMakeLists.txt b/external/opus-1.1.4/CMakeLists.txt
new file mode 100644
index 0000000..0d25ad3
--- /dev/null
+++ b/external/opus-1.1.4/CMakeLists.txt
@@ -0,0 +1,230 @@
+
+add_definitions(
+ -DFLOATING_POINT
+ -DFLOAT_APPROX
+ -DOPUS_BUILD
+ -DUSE_CODEC_OPUS
+ -DUSE_ALLOCA
+ -DHAVE_LRINTF
+ )
+
+add_library(
+ opus STATIC
+ #
+ include/opus.h
+ include/opus_custom.h
+ include/opus_defines.h
+ include/opus_multistream.h
+ include/opus_types.h
+ #
+ celt/_kiss_fft_guts.h
+ celt/arch.h
+ celt/arm/armcpu.h
+ celt/arm/fixed_armv4.h
+ celt/arm/fixed_armv5e.h
+ celt/arm/kiss_fft_armv4.h
+ celt/arm/kiss_fft_armv5e.h
+ celt/arm/pitch_arm.h
+ celt/bands.c
+ celt/bands.h
+ celt/celt.c
+ celt/celt.h
+ celt/celt_decoder.c
+ celt/celt_encoder.c
+ celt/celt_lpc.c
+ celt/celt_lpc.h
+ celt/cpu_support.h
+ celt/cwrs.c
+ celt/cwrs.h
+ celt/ecintrin.h
+ celt/entcode.c
+ celt/entcode.h
+ celt/entdec.c
+ celt/entdec.h
+ celt/entenc.c
+ celt/entenc.h
+ celt/fixed_debug.h
+ celt/fixed_generic.h
+ celt/float_cast.h
+ celt/kiss_fft.c
+ celt/kiss_fft.h
+ celt/laplace.c
+ celt/laplace.h
+ celt/mathops.c
+ celt/mathops.h
+ celt/mdct.c
+ celt/mdct.h
+ celt/mfrngcod.h
+ celt/modes.c
+ celt/modes.h
+ celt/os_support.h
+ celt/pitch.c
+ celt/pitch.h
+ celt/quant_bands.c
+ celt/quant_bands.h
+ celt/rate.c
+ celt/rate.h
+ celt/stack_alloc.h
+ celt/static_modes_fixed.h
+ celt/static_modes_float.h
+ celt/vq.c
+ celt/vq.h
+ celt/x86/pitch_sse.h
+ silk/A2NLSF.c
+ silk/API.h
+ silk/CNG.c
+ silk/HP_variable_cutoff.c
+ silk/Inlines.h
+ silk/LPC_analysis_filter.c
+ silk/LPC_inv_pred_gain.c
+ silk/LP_variable_cutoff.c
+ silk/MacroCount.h
+ silk/MacroDebug.h
+ silk/NLSF2A.c
+ silk/NLSF_VQ.c
+ silk/NLSF_VQ_weights_laroia.c
+ silk/NLSF_decode.c
+ silk/NLSF_del_dec_quant.c
+ silk/NLSF_encode.c
+ silk/NLSF_stabilize.c
+ silk/NLSF_unpack.c
+ silk/NSQ.c
+ silk/NSQ_del_dec.c
+ silk/PLC.c
+ silk/PLC.h
+ silk/SigProc_FIX.h
+ silk/VAD.c
+ silk/VQ_WMat_EC.c
+ silk/ana_filt_bank_1.c
+ silk/arm/SigProc_FIX_armv4.h
+ silk/arm/SigProc_FIX_armv5e.h
+ silk/arm/macros_armv4.h
+ silk/arm/macros_armv5e.h
+ silk/biquad_alt.c
+ silk/bwexpander.c
+ silk/bwexpander_32.c
+ silk/check_control_input.c
+ silk/code_signs.c
+ silk/control.h
+ silk/control_SNR.c
+ silk/control_audio_bandwidth.c
+ silk/control_codec.c
+ silk/debug.c
+ silk/debug.h
+ silk/dec_API.c
+ silk/decode_core.c
+ silk/decode_frame.c
+ silk/decode_indices.c
+ silk/decode_parameters.c
+ silk/decode_pitch.c
+ silk/decode_pulses.c
+ silk/decoder_set_fs.c
+ silk/define.h
+ silk/enc_API.c
+ silk/encode_indices.c
+ silk/encode_pulses.c
+ silk/errors.h
+ silk/fixed/main_FIX.h
+ silk/fixed/structs_FIX.h
+ silk/float/LPC_analysis_filter_FLP.c
+ silk/float/LPC_inv_pred_gain_FLP.c
+ silk/float/LTP_analysis_filter_FLP.c
+ silk/float/LTP_scale_ctrl_FLP.c
+ silk/float/SigProc_FLP.h
+ silk/float/apply_sine_window_FLP.c
+ silk/float/autocorrelation_FLP.c
+ silk/float/burg_modified_FLP.c
+ silk/float/bwexpander_FLP.c
+ silk/float/corrMatrix_FLP.c
+ silk/float/encode_frame_FLP.c
+ silk/float/energy_FLP.c
+ silk/float/find_LPC_FLP.c
+ silk/float/find_LTP_FLP.c
+ silk/float/find_pitch_lags_FLP.c
+ silk/float/find_pred_coefs_FLP.c
+ silk/float/inner_product_FLP.c
+ silk/float/k2a_FLP.c
+ silk/float/levinsondurbin_FLP.c
+ silk/float/main_FLP.h
+ silk/float/noise_shape_analysis_FLP.c
+ silk/float/pitch_analysis_core_FLP.c
+ silk/float/prefilter_FLP.c
+ silk/float/process_gains_FLP.c
+ silk/float/regularize_correlations_FLP.c
+ silk/float/residual_energy_FLP.c
+ silk/float/scale_copy_vector_FLP.c
+ silk/float/scale_vector_FLP.c
+ silk/float/schur_FLP.c
+ silk/float/solve_LS_FLP.c
+ silk/float/sort_FLP.c
+ silk/float/structs_FLP.h
+ silk/float/warped_autocorrelation_FLP.c
+ silk/float/wrappers_FLP.c
+ silk/gain_quant.c
+ silk/init_decoder.c
+ silk/init_encoder.c
+ silk/inner_prod_aligned.c
+ silk/interpolate.c
+ silk/lin2log.c
+ silk/log2lin.c
+ silk/macros.h
+ silk/main.h
+ silk/pitch_est_defines.h
+ silk/pitch_est_tables.c
+ silk/process_NLSFs.c
+ silk/quant_LTP_gains.c
+ silk/resampler.c
+ silk/resampler_down2.c
+ silk/resampler_down2_3.c
+ silk/resampler_private.h
+ silk/resampler_private_AR2.c
+ silk/resampler_private_IIR_FIR.c
+ silk/resampler_private_down_FIR.c
+ silk/resampler_private_up2_HQ.c
+ silk/resampler_rom.c
+ silk/resampler_rom.h
+ silk/resampler_structs.h
+ silk/shell_coder.c
+ silk/sigm_Q15.c
+ silk/sort.c
+ silk/stereo_LR_to_MS.c
+ silk/stereo_MS_to_LR.c
+ silk/stereo_decode_pred.c
+ silk/stereo_encode_pred.c
+ silk/stereo_find_predictor.c
+ silk/stereo_quant_pred.c
+ silk/structs.h
+ silk/sum_sqr_shift.c
+ silk/table_LSF_cos.c
+ silk/tables.h
+ silk/tables_LTP.c
+ silk/tables_NLSF_CB_NB_MB.c
+ silk/tables_NLSF_CB_WB.c
+ silk/tables_gain.c
+ silk/tables_other.c
+ silk/tables_pitch_lag.c
+ silk/tables_pulses_per_block.c
+ silk/tuning_parameters.h
+ silk/typedef.h
+ src/analysis.c
+ src/analysis.h
+ src/mlp.c
+ src/mlp.h
+ src/mlp_data.c
+ src/opus.c
+ src/opus_decoder.c
+ src/opus_encoder.c
+ src/opus_multistream.c
+ src/opus_multistream_decoder.c
+ src/opus_multistream_encoder.c
+ src/opus_private.h
+ src/repacketizer.c
+ src/tansig_table.h
+ )
+
+include_directories(
+ celt
+ include
+ silk
+ silk/float
+ )
diff --git a/external/opus-1.1.4/celt/CMakeLists.txt b/external/opus-1.1.4/celt/CMakeLists.txt
new file mode 100644
index 0000000..c95244c
--- /dev/null
+++ b/external/opus-1.1.4/celt/CMakeLists.txt
@@ -0,0 +1,59 @@
+# CMakeLists.txt in celt
+
+SET(CELT_SRCS
+bands.c
+celt.c
+celt_decoder.c
+celt_encoder.c
+celt_lpc.c
+cwrs.c
+entcode.c
+entdec.c
+entenc.c
+kiss_fft.c
+laplace.c
+mathops.c
+mdct.c
+modes.c
+pitch.c
+quant_bands.c
+rate.c
+vq.c
+)
+
+SET(CELT_HEADERS
+ arch.h
+ bands.h
+ celt.h
+ celt_lpc.h
+ cpu_support.h
+ cwrs.h
+ ecintrin.h
+ entcode.h
+ entdec.h
+ entenc.h
+ fixed_debug.h
+ fixed_generic.h
+ float_cast.h
+ kiss_fft.h
+ laplace.h
+ mathops.h
+ mdct.h
+ mfrngcod.h
+ modes.h
+ os_support.h
+ pitch.h
+ quant_bands.h
+ rate.h
+ stack_alloc.h
+ static_modes_fixed.h
+ static_modes_float.h
+ vq.h
+ _kiss_fft_guts.h
+ )
+
+INCLUDE_DIRECTORIES(
+ ${OPUS_INCLUDES_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include
+ )
diff --git a/external/opus-1.1.4/celt/_kiss_fft_guts.h b/external/opus-1.1.4/celt/_kiss_fft_guts.h
new file mode 100644
index 0000000..5e3d58f
--- /dev/null
+++ b/external/opus-1.1.4/celt/_kiss_fft_guts.h
@@ -0,0 +1,182 @@
+/*Copyright (c) 2003-2004, Mark Borgerding
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.*/
+
+#ifndef KISS_FFT_GUTS_H
+#define KISS_FFT_GUTS_H
+
+#define MIN(a,b) ((a)<(b) ? (a):(b))
+#define MAX(a,b) ((a)>(b) ? (a):(b))
+
+/* kiss_fft.h
+ defines kiss_fft_scalar as either short or a float type
+ and defines
+ typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
+#include "kiss_fft.h"
+
+/*
+ Explanation of macros dealing with complex math:
+
+ C_MUL(m,a,b) : m = a*b
+ C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise
+ C_SUB( res, a,b) : res = a - b
+ C_SUBFROM( res , a) : res -= a
+ C_ADDTO( res , a) : res += a
+ * */
+#ifdef FIXED_POINT
+#include "arch.h"
+
+
+#define SAMP_MAX 2147483647
+#define TWID_MAX 32767
+#define TRIG_UPSCALE 1
+
+#define SAMP_MIN -SAMP_MAX
+
+
+# define S_MUL(a,b) MULT16_32_Q15(b, a)
+
+# define C_MUL(m,a,b) \
+ do{ (m).r = SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
+ (m).i = ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0)
+
+# define C_MULC(m,a,b) \
+ do{ (m).r = ADD32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
+ (m).i = SUB32(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0)
+
+# define C_MULBYSCALAR( c, s ) \
+ do{ (c).r = S_MUL( (c).r , s ) ;\
+ (c).i = S_MUL( (c).i , s ) ; }while(0)
+
+# define DIVSCALAR(x,k) \
+ (x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 )
+
+# define C_FIXDIV(c,div) \
+ do { DIVSCALAR( (c).r , div); \
+ DIVSCALAR( (c).i , div); }while (0)
+
+#define C_ADD( res, a,b)\
+ do {(res).r=ADD32((a).r,(b).r); (res).i=ADD32((a).i,(b).i); \
+ }while(0)
+#define C_SUB( res, a,b)\
+ do {(res).r=SUB32((a).r,(b).r); (res).i=SUB32((a).i,(b).i); \
+ }while(0)
+#define C_ADDTO( res , a)\
+ do {(res).r = ADD32((res).r, (a).r); (res).i = ADD32((res).i,(a).i);\
+ }while(0)
+
+#define C_SUBFROM( res , a)\
+ do {(res).r = ADD32((res).r,(a).r); (res).i = SUB32((res).i,(a).i); \
+ }while(0)
+
+#if defined(OPUS_ARM_INLINE_ASM)
+#include "arm/kiss_fft_armv4.h"
+#endif
+
+#if defined(OPUS_ARM_INLINE_EDSP)
+#include "arm/kiss_fft_armv5e.h"
+#endif
+#if defined(MIPSr1_ASM)
+#include "mips/kiss_fft_mipsr1.h"
+#endif
+
+#else /* not FIXED_POINT*/
+
+# define S_MUL(a,b) ( (a)*(b) )
+#define C_MUL(m,a,b) \
+ do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
+ (m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
+#define C_MULC(m,a,b) \
+ do{ (m).r = (a).r*(b).r + (a).i*(b).i;\
+ (m).i = (a).i*(b).r - (a).r*(b).i; }while(0)
+
+#define C_MUL4(m,a,b) C_MUL(m,a,b)
+
+# define C_FIXDIV(c,div) /* NOOP */
+# define C_MULBYSCALAR( c, s ) \
+ do{ (c).r *= (s);\
+ (c).i *= (s); }while(0)
+#endif
+
+#ifndef CHECK_OVERFLOW_OP
+# define CHECK_OVERFLOW_OP(a,op,b) /* noop */
+#endif
+
+#ifndef C_ADD
+#define C_ADD( res, a,b)\
+ do { \
+ CHECK_OVERFLOW_OP((a).r,+,(b).r)\
+ CHECK_OVERFLOW_OP((a).i,+,(b).i)\
+ (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \
+ }while(0)
+#define C_SUB( res, a,b)\
+ do { \
+ CHECK_OVERFLOW_OP((a).r,-,(b).r)\
+ CHECK_OVERFLOW_OP((a).i,-,(b).i)\
+ (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \
+ }while(0)
+#define C_ADDTO( res , a)\
+ do { \
+ CHECK_OVERFLOW_OP((res).r,+,(a).r)\
+ CHECK_OVERFLOW_OP((res).i,+,(a).i)\
+ (res).r += (a).r; (res).i += (a).i;\
+ }while(0)
+
+#define C_SUBFROM( res , a)\
+ do {\
+ CHECK_OVERFLOW_OP((res).r,-,(a).r)\
+ CHECK_OVERFLOW_OP((res).i,-,(a).i)\
+ (res).r -= (a).r; (res).i -= (a).i; \
+ }while(0)
+#endif /* C_ADD defined */
+
+#ifdef FIXED_POINT
+/*# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase))))
+# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/
+# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase))
+# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase))
+# define HALF_OF(x) ((x)>>1)
+#elif defined(USE_SIMD)
+# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
+# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
+# define HALF_OF(x) ((x)*_mm_set1_ps(.5f))
+#else
+# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
+# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
+# define HALF_OF(x) ((x)*.5f)
+#endif
+
+#define kf_cexp(x,phase) \
+ do{ \
+ (x)->r = KISS_FFT_COS(phase);\
+ (x)->i = KISS_FFT_SIN(phase);\
+ }while(0)
+
+#define kf_cexp2(x,phase) \
+ do{ \
+ (x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\
+ (x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\
+}while(0)
+
+#endif /* KISS_FFT_GUTS_H */
diff --git a/external/opus-1.1.4/celt/arch.h b/external/opus-1.1.4/celt/arch.h
new file mode 100644
index 0000000..8ceab5f
--- /dev/null
+++ b/external/opus-1.1.4/celt/arch.h
@@ -0,0 +1,252 @@
+/* Copyright (c) 2003-2008 Jean-Marc Valin
+ Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file arch.h
+ @brief Various architecture definitions for CELT
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+# if !defined(__GNUC_PREREQ)
+# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
+# define __GNUC_PREREQ(_maj,_min) \
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
+# else
+# define __GNUC_PREREQ(_maj,_min) 0
+# endif
+# endif
+
+#define CELT_SIG_SCALE 32768.f
+
+#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__);
+#ifdef ENABLE_ASSERTIONS
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __GNUC__
+__attribute__((noreturn))
+#endif
+static OPUS_INLINE void _celt_fatal(const char *str, const char *file, int line)
+{
+ fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
+ abort();
+}
+#define celt_assert(cond) {if (!(cond)) {celt_fatal("assertion failed: " #cond);}}
+#define celt_assert2(cond, message) {if (!(cond)) {celt_fatal("assertion failed: " #cond "\n" message);}}
+#else
+#define celt_assert(cond)
+#define celt_assert2(cond, message)
+#endif
+
+#define IMUL32(a,b) ((a)*(b))
+
+#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */
+#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
+#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */
+#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
+#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */
+#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */
+#define UADD32(a,b) ((a)+(b))
+#define USUB32(a,b) ((a)-(b))
+
+/* Set this if opus_int64 is a native type of the CPU. */
+/* Assume that all LP64 architectures have fast 64-bit types; also x86_64
+ (which can be ILP32 for x32) and Win64 (which is LLP64). */
+#if defined(__x86_64__) || defined(__LP64__) || defined(_WIN64)
+#define OPUS_FAST_INT64 1
+#else
+#define OPUS_FAST_INT64 0
+#endif
+
+#define PRINT_MIPS(file)
+
+#ifdef FIXED_POINT
+
+typedef opus_int16 opus_val16;
+typedef opus_int32 opus_val32;
+
+typedef opus_val32 celt_sig;
+typedef opus_val16 celt_norm;
+typedef opus_val32 celt_ener;
+
+#define Q15ONE 32767
+
+#define SIG_SHIFT 12
+
+#define NORM_SCALING 16384
+
+#define DB_SHIFT 10
+
+#define EPSILON 1
+#define VERY_SMALL 0
+#define VERY_LARGE16 ((opus_val16)32767)
+#define Q15_ONE ((opus_val16)32767)
+
+#define SCALEIN(a) (a)
+#define SCALEOUT(a) (a)
+
+#define ABS16(x) ((x) < 0 ? (-(x)) : (x))
+#define ABS32(x) ((x) < 0 ? (-(x)) : (x))
+
+static OPUS_INLINE opus_int16 SAT16(opus_int32 x) {
+ return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x;
+}
+
+#ifdef FIXED_DEBUG
+#include "fixed_debug.h"
+#else
+
+#include "fixed_generic.h"
+
+#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR
+#include "arm/fixed_arm64.h"
+#elif OPUS_ARM_INLINE_EDSP
+#include "arm/fixed_armv5e.h"
+#elif defined (OPUS_ARM_INLINE_ASM)
+#include "arm/fixed_armv4.h"
+#elif defined (BFIN_ASM)
+#include "fixed_bfin.h"
+#elif defined (TI_C5X_ASM)
+#include "fixed_c5x.h"
+#elif defined (TI_C6X_ASM)
+#include "fixed_c6x.h"
+#endif
+
+#endif
+
+#else /* FIXED_POINT */
+
+typedef float opus_val16;
+typedef float opus_val32;
+
+typedef float celt_sig;
+typedef float celt_norm;
+typedef float celt_ener;
+
+#ifdef FLOAT_APPROX
+/* This code should reliably detect NaN/inf even when -ffast-math is used.
+ Assumes IEEE 754 format. */
+static OPUS_INLINE int celt_isnan(float x)
+{
+ union {float f; opus_uint32 i;} in;
+ in.f = x;
+ return ((in.i>>23)&0xFF)==0xFF && (in.i&0x007FFFFF)!=0;
+}
+#else
+#ifdef __FAST_MATH__
+#error Cannot build libopus with -ffast-math unless FLOAT_APPROX is defined. This could result in crashes on extreme (e.g. NaN) input
+#endif
+#define celt_isnan(x) ((x)!=(x))
+#endif
+
+#define Q15ONE 1.0f
+
+#define NORM_SCALING 1.f
+
+#define EPSILON 1e-15f
+#define VERY_SMALL 1e-30f
+#define VERY_LARGE16 1e15f
+#define Q15_ONE ((opus_val16)1.f)
+
+/* This appears to be the same speed as C99's fabsf() but it's more portable. */
+#define ABS16(x) ((float)fabs(x))
+#define ABS32(x) ((float)fabs(x))
+
+#define QCONST16(x,bits) (x)
+#define QCONST32(x,bits) (x)
+
+#define NEG16(x) (-(x))
+#define NEG32(x) (-(x))
+#define EXTRACT16(x) (x)
+#define EXTEND32(x) (x)
+#define SHR16(a,shift) (a)
+#define SHL16(a,shift) (a)
+#define SHR32(a,shift) (a)
+#define SHL32(a,shift) (a)
+#define PSHR32(a,shift) (a)
+#define VSHR32(a,shift) (a)
+
+#define PSHR(a,shift) (a)
+#define SHR(a,shift) (a)
+#define SHL(a,shift) (a)
+#define SATURATE(x,a) (x)
+#define SATURATE16(x) (x)
+
+#define ROUND16(a,shift) (a)
+#define HALF16(x) (.5f*(x))
+#define HALF32(x) (.5f*(x))
+
+#define ADD16(a,b) ((a)+(b))
+#define SUB16(a,b) ((a)-(b))
+#define ADD32(a,b) ((a)+(b))
+#define SUB32(a,b) ((a)-(b))
+#define MULT16_16_16(a,b) ((a)*(b))
+#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b))
+#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b))
+
+#define MULT16_32_Q15(a,b) ((a)*(b))
+#define MULT16_32_Q16(a,b) ((a)*(b))
+
+#define MULT32_32_Q31(a,b) ((a)*(b))
+
+#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
+#define MAC16_32_Q16(c,a,b) ((c)+(a)*(b))
+
+#define MULT16_16_Q11_32(a,b) ((a)*(b))
+#define MULT16_16_Q11(a,b) ((a)*(b))
+#define MULT16_16_Q13(a,b) ((a)*(b))
+#define MULT16_16_Q14(a,b) ((a)*(b))
+#define MULT16_16_Q15(a,b) ((a)*(b))
+#define MULT16_16_P15(a,b) ((a)*(b))
+#define MULT16_16_P13(a,b) ((a)*(b))
+#define MULT16_16_P14(a,b) ((a)*(b))
+#define MULT16_32_P16(a,b) ((a)*(b))
+
+#define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b))
+#define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b))
+
+#define SCALEIN(a) ((a)*CELT_SIG_SCALE)
+#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE))
+
+#define SIG2WORD16(x) (x)
+
+#endif /* !FIXED_POINT */
+
+#ifndef GLOBAL_STACK_SIZE
+#ifdef FIXED_POINT
+#define GLOBAL_STACK_SIZE 100000
+#else
+#define GLOBAL_STACK_SIZE 100000
+#endif
+#endif
+
+#endif /* ARCH_H */
diff --git a/external/opus-1.1.4/celt/arm/arm2gnu.pl b/external/opus-1.1.4/celt/arm/arm2gnu.pl
new file mode 100644
index 0000000..6c922ac
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/arm2gnu.pl
@@ -0,0 +1,353 @@
+#!/usr/bin/perl
+# Copyright (C) 2002-2013 Xiph.org Foundation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 COPYRIGHT OWNER
+# OR CONTRIBUTORS 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.
+
+my $bigend; # little/big endian
+my $nxstack;
+my $apple = 0;
+my $symprefix = "";
+
+$nxstack = 0;
+
+eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}'
+ if $running_under_some_shell;
+
+while ($ARGV[0] =~ /^-/) {
+ $_ = shift;
+ last if /^--$/;
+ if (/^-n$/) {
+ $nflag++;
+ next;
+ }
+ if (/^--apple$/) {
+ $apple = 1;
+ $symprefix = "_";
+ next;
+ }
+ die "I don't recognize this switch: $_\\n";
+}
+$printit++ unless $nflag;
+
+$\ = "\n"; # automatically add newline on print
+$n=0;
+
+$thumb = 0; # ARM mode by default, not Thumb.
+@proc_stack = ();
+
+printf (" .syntax unified\n");
+
+LINE:
+while (<>) {
+
+ # For ADRLs we need to add a new line after the substituted one.
+ $addPadding = 0;
+
+ # First, we do not dare to touch *anything* inside double quotes, do we?
+ # Second, if you want a dollar character in the string,
+ # insert two of them -- that's how ARM C and assembler treat strings.
+ s/^([A-Za-z_]\w*)[ \t]+DCB[ \t]*\"/$1: .ascii \"/ && do { s/\$\$/\$/g; next };
+ s/\bDCB\b[ \t]*\"/.ascii \"/ && do { s/\$\$/\$/g; next };
+ s/^(\S+)\s+RN\s+(\S+)/$1 .req r$2/ && do { s/\$\$/\$/g; next };
+ # If there's nothing on a line but a comment, don't try to apply any further
+ # substitutions (this is a cheap hack to avoid mucking up the license header)
+ s/^([ \t]*);/$1@/ && do { s/\$\$/\$/g; next };
+ # If substituted -- leave immediately !
+
+ s/@/,:/;
+ s/;/@/;
+ while ( /@.*'/ ) {
+ s/(@.*)'/$1/g;
+ }
+ s/\{FALSE\}/0/g;
+ s/\{TRUE\}/1/g;
+ s/\{(\w\w\w\w+)\}/$1/g;
+ s/\bINCLUDE[ \t]*([^ \t\n]+)/.include \"$1\"/;
+ s/\bGET[ \t]*([^ \t\n]+)/.include \"${ my $x=$1; $x =~ s|\.s|-gnu.S|; \$x }\"/;
+ s/\bIMPORT\b/.extern/;
+ s/\bEXPORT\b\s*/.global $symprefix/;
+ s/^(\s+)\[/$1IF/;
+ s/^(\s+)\|/$1ELSE/;
+ s/^(\s+)\]/$1ENDIF/;
+ s/IF *:DEF:/ .ifdef/;
+ s/IF *:LNOT: *:DEF:/ .ifndef/;
+ s/ELSE/ .else/;
+ s/ENDIF/ .endif/;
+
+ if( /\bIF\b/ ) {
+ s/\bIF\b/ .if/;
+ s/=/==/;
+ }
+ if ( $n == 2) {
+ s/\$/\\/g;
+ }
+ if ($n == 1) {
+ s/\$//g;
+ s/label//g;
+ $n = 2;
+ }
+ if ( /MACRO/ ) {
+ s/MACRO *\n/.macro/;
+ $n=1;
+ }
+ if ( /\bMEND\b/ ) {
+ s/\bMEND\b/.endm/;
+ $n=0;
+ }
+
+ # ".rdata" doesn't work in 'as' version 2.13.2, as it is ".rodata" there.
+ #
+ if ( /\bAREA\b/ ) {
+ my $align;
+ $align = "2";
+ if ( /ALIGN=(\d+)/ ) {
+ $align = $1;
+ }
+ if ( /CODE/ ) {
+ $nxstack = 1;
+ }
+ s/^(.+)CODE(.+)READONLY(.*)/ .text/;
+ s/^(.+)DATA(.+)READONLY(.*)/ .section .rdata/;
+ s/^(.+)\|\|\.data\|\|(.+)/ .data/;
+ s/^(.+)\|\|\.bss\|\|(.+)/ .bss/;
+ s/$/; .p2align $align/;
+ # Enable NEON instructions but don't produce a binary that requires
+ # ARMv7. RVCT does not have equivalent directives, so we just do this
+ # for all CODE areas.
+ if ( /.text/ ) {
+ # Separating .arch, .fpu, etc., by semicolons does not work (gas
+ # thinks the semicolon is part of the arch name, even when there's
+ # whitespace separating them). Sadly this means our line numbers
+ # won't match the original source file (we could use the .line
+ # directive, which is documented to be obsolete, but then gdb will
+ # show the wrong line in the translated source file).
+ s/$/; .arch armv7-a\n .fpu neon\n .object_arch armv4t/ unless ($apple);
+ }
+ }
+
+ s/\|\|\.constdata\$(\d+)\|\|/.L_CONST$1/; # ||.constdata$3||
+ s/\|\|\.bss\$(\d+)\|\|/.L_BSS$1/; # ||.bss$2||
+ s/\|\|\.data\$(\d+)\|\|/.L_DATA$1/; # ||.data$2||
+ s/\|\|([a-zA-Z0-9_]+)\@([a-zA-Z0-9_]+)\|\|/@ $&/;
+ s/^(\s+)\%(\s)/ .space $1/;
+
+ s/\|(.+)\.(\d+)\|/\.$1_$2/; # |L80.123| -> .L80_123
+ s/\bCODE32\b/.code 32/ && do {$thumb = 0};
+ s/\bCODE16\b/.code 16/ && do {$thumb = 1};
+ if (/\bPROC\b/)
+ {
+ my $prefix;
+ my $proc;
+ /^([A-Za-z_\.]\w+)\b/;
+ $proc = $1;
+ $prefix = "";
+ if ($proc)
+ {
+ $prefix = $prefix.sprintf("\t.type\t%s, %%function; ",$proc) unless ($apple);
+ # Make sure we $prefix isn't empty here (for the $apple case).
+ # We handle mangling the label here, make sure it doesn't match
+ # the label handling below (if $prefix would be empty).
+ $prefix = "; ";
+ push(@proc_stack, $proc);
+ s/^[A-Za-z_\.]\w+/$symprefix$&:/;
+ }
+ $prefix = $prefix."\t.thumb_func; " if ($thumb);
+ s/\bPROC\b/@ $&/;
+ $_ = $prefix.$_;
+ }
+ s/^(\s*)(S|Q|SH|U|UQ|UH)ASX\b/$1$2ADDSUBX/;
+ s/^(\s*)(S|Q|SH|U|UQ|UH)SAX\b/$1$2SUBADDX/;
+ if (/\bENDP\b/)
+ {
+ my $proc;
+ s/\bENDP\b/@ $&/;
+ $proc = pop(@proc_stack);
+ $_ = "\t.size $proc, .-$proc".$_ if ($proc && !$apple);
+ }
+ s/\bSUBT\b/@ $&/;
+ s/\bDATA\b/@ $&/; # DATA directive is deprecated -- Asm guide, p.7-25
+ s/\bKEEP\b/@ $&/;
+ s/\bEXPORTAS\b/@ $&/;
+ s/\|\|(.)+\bEQU\b/@ $&/;
+ s/\|\|([\w\$]+)\|\|/$1/;
+ s/\bENTRY\b/@ $&/;
+ s/\bASSERT\b/@ $&/;
+ s/\bGBLL\b/@ $&/;
+ s/\bGBLA\b/@ $&/;
+ s/^\W+OPT\b/@ $&/;
+ s/:OR:/|/g;
+ s/:SHL:/<</g;
+ s/:SHR:/>>/g;
+ s/:AND:/&/g;
+ s/:LAND:/&&/g;
+ s/CPSR/cpsr/;
+ s/SPSR/spsr/;
+ s/ALIGN$/.balign 4/;
+ s/ALIGN\s+([0-9x]+)$/.balign $1/;
+ s/psr_cxsf/psr_all/;
+ s/LTORG/.ltorg/;
+ s/^([A-Za-z_]\w*)[ \t]+EQU/ .set $1,/;
+ s/^([A-Za-z_]\w*)[ \t]+SETL/ .set $1,/;
+ s/^([A-Za-z_]\w*)[ \t]+SETA/ .set $1,/;
+ s/^([A-Za-z_]\w*)[ \t]+\*/ .set $1,/;
+
+ # {PC} + 0xdeadfeed --> . + 0xdeadfeed
+ s/\{PC\} \+/ \. +/;
+
+ # Single hex constant on the line !
+ #
+ # >>> NOTE <<<
+ # Double-precision floats in gcc are always mixed-endian, which means
+ # bytes in two words are little-endian, but words are big-endian.
+ # So, 0x0000deadfeed0000 would be stored as 0x0000dead at low address
+ # and 0xfeed0000 at high address.
+ #
+ s/\bDCFD\b[ \t]+0x([a-fA-F0-9]{8})([a-fA-F0-9]{8})/.long 0x$1, 0x$2/;
+ # Only decimal constants on the line, no hex !
+ s/\bDCFD\b[ \t]+([0-9\.\-]+)/.double $1/;
+
+ # Single hex constant on the line !
+# s/\bDCFS\b[ \t]+0x([a-f0-9]{8})([a-f0-9]{8})/.long 0x$1, 0x$2/;
+ # Only decimal constants on the line, no hex !
+# s/\bDCFS\b[ \t]+([0-9\.\-]+)/.double $1/;
+ s/\bDCFS[ \t]+0x/.word 0x/;
+ s/\bDCFS\b/.float/;
+
+ s/^([A-Za-z_]\w*)[ \t]+DCD/$1 .word/;
+ s/\bDCD\b/.word/;
+ s/^([A-Za-z_]\w*)[ \t]+DCW/$1 .short/;
+ s/\bDCW\b/.short/;
+ s/^([A-Za-z_]\w*)[ \t]+DCB/$1 .byte/;
+ s/\bDCB\b/.byte/;
+ s/^([A-Za-z_]\w*)[ \t]+\%/.comm $1,/;
+ s/^[A-Za-z_\.]\w+/$&:/;
+ s/^(\d+)/$1:/;
+ s/\%(\d+)/$1b_or_f/;
+ s/\%[Bb](\d+)/$1b/;
+ s/\%[Ff](\d+)/$1f/;
+ s/\%[Ff][Tt](\d+)/$1f/;
+ s/&([\dA-Fa-f]+)/0x$1/;
+ if ( /\b2_[01]+\b/ ) {
+ s/\b2_([01]+)\b/conv$1&&&&/g;
+ while ( /[01][01][01][01]&&&&/ ) {
+ s/0000&&&&/&&&&0/g;
+ s/0001&&&&/&&&&1/g;
+ s/0010&&&&/&&&&2/g;
+ s/0011&&&&/&&&&3/g;
+ s/0100&&&&/&&&&4/g;
+ s/0101&&&&/&&&&5/g;
+ s/0110&&&&/&&&&6/g;
+ s/0111&&&&/&&&&7/g;
+ s/1000&&&&/&&&&8/g;
+ s/1001&&&&/&&&&9/g;
+ s/1010&&&&/&&&&A/g;
+ s/1011&&&&/&&&&B/g;
+ s/1100&&&&/&&&&C/g;
+ s/1101&&&&/&&&&D/g;
+ s/1110&&&&/&&&&E/g;
+ s/1111&&&&/&&&&F/g;
+ }
+ s/000&&&&/&&&&0/g;
+ s/001&&&&/&&&&1/g;
+ s/010&&&&/&&&&2/g;
+ s/011&&&&/&&&&3/g;
+ s/100&&&&/&&&&4/g;
+ s/101&&&&/&&&&5/g;
+ s/110&&&&/&&&&6/g;
+ s/111&&&&/&&&&7/g;
+ s/00&&&&/&&&&0/g;
+ s/01&&&&/&&&&1/g;
+ s/10&&&&/&&&&2/g;
+ s/11&&&&/&&&&3/g;
+ s/0&&&&/&&&&0/g;
+ s/1&&&&/&&&&1/g;
+ s/conv&&&&/0x/g;
+ }
+
+ if ( /commandline/)
+ {
+ if( /-bigend/)
+ {
+ $bigend=1;
+ }
+ }
+
+ if ( /\bDCDU\b/ )
+ {
+ my $cmd=$_;
+ my $value;
+ my $prefix;
+ my $w1;
+ my $w2;
+ my $w3;
+ my $w4;
+
+ s/\s+DCDU\b/@ $&/;
+
+ $cmd =~ /\bDCDU\b\s+0x(\d+)/;
+ $value = $1;
+ $value =~ /(\w\w)(\w\w)(\w\w)(\w\w)/;
+ $w1 = $1;
+ $w2 = $2;
+ $w3 = $3;
+ $w4 = $4;
+
+ if( $bigend ne "")
+ {
+ # big endian
+ $prefix = "\t.byte\t0x".$w1.";".
+ "\t.byte\t0x".$w2.";".
+ "\t.byte\t0x".$w3.";".
+ "\t.byte\t0x".$w4."; ";
+ }
+ else
+ {
+ # little endian
+ $prefix = "\t.byte\t0x".$w4.";".
+ "\t.byte\t0x".$w3.";".
+ "\t.byte\t0x".$w2.";".
+ "\t.byte\t0x".$w1."; ";
+ }
+ $_=$prefix.$_;
+ }
+
+ if ( /\badrl\b/i )
+ {
+ s/\badrl\s+(\w+)\s*,\s*(\w+)/ldr $1,=$2/i;
+ $addPadding = 1;
+ }
+ s/\bEND\b/@ END/;
+} continue {
+ printf ("%s", $_) if $printit;
+ if ($addPadding != 0)
+ {
+ printf (" mov r0,r0\n");
+ $addPadding = 0;
+ }
+}
+#If we had a code section, mark that this object doesn't need an executable
+# stack.
+if ($nxstack && !$apple) {
+ printf (" .section\t.note.GNU-stack,\"\",\%\%progbits\n");
+}
diff --git a/external/opus-1.1.4/celt/arm/arm_celt_map.c b/external/opus-1.1.4/celt/arm/arm_celt_map.c
new file mode 100644
index 0000000..4d4d069
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/arm_celt_map.c
@@ -0,0 +1,143 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pitch.h"
+#include "kiss_fft.h"
+#include "mdct.h"
+
+#if defined(OPUS_HAVE_RTCD)
+
+# if defined(FIXED_POINT)
+# if ((defined(OPUS_ARM_MAY_HAVE_NEON) && !defined(OPUS_ARM_PRESUME_NEON)) || \
+ (defined(OPUS_ARM_MAY_HAVE_MEDIA) && !defined(OPUS_ARM_PRESUME_MEDIA)) || \
+ (defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP)))
+opus_val32 (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
+ const opus_val16 *, opus_val32 *, int , int) = {
+ celt_pitch_xcorr_c, /* ARMv4 */
+ MAY_HAVE_EDSP(celt_pitch_xcorr), /* EDSP */
+ MAY_HAVE_MEDIA(celt_pitch_xcorr), /* Media */
+ MAY_HAVE_NEON(celt_pitch_xcorr) /* NEON */
+};
+
+# endif
+# else /* !FIXED_POINT */
+# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)
+void (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
+ const opus_val16 *, opus_val32 *, int, int) = {
+ celt_pitch_xcorr_c, /* ARMv4 */
+ celt_pitch_xcorr_c, /* EDSP */
+ celt_pitch_xcorr_c, /* Media */
+ celt_pitch_xcorr_float_neon /* Neon */
+};
+# endif
+# endif /* FIXED_POINT */
+
+#if defined(FIXED_POINT) && defined(OPUS_HAVE_RTCD) && \
+ defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)
+
+void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *y,
+ opus_val32 sum[4],
+ int len
+) = {
+ xcorr_kernel_c, /* ARMv4 */
+ xcorr_kernel_c, /* EDSP */
+ xcorr_kernel_c, /* Media */
+ xcorr_kernel_neon_fixed, /* Neon */
+};
+
+#endif
+
+# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+# if defined(HAVE_ARM_NE10)
+# if defined(CUSTOM_MODES)
+int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])(kiss_fft_state *st) = {
+ opus_fft_alloc_arch_c, /* ARMv4 */
+ opus_fft_alloc_arch_c, /* EDSP */
+ opus_fft_alloc_arch_c, /* Media */
+ opus_fft_alloc_arm_neon /* Neon with NE10 library support */
+};
+
+void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])(kiss_fft_state *st) = {
+ opus_fft_free_arch_c, /* ARMv4 */
+ opus_fft_free_arch_c, /* EDSP */
+ opus_fft_free_arch_c, /* Media */
+ opus_fft_free_arm_neon /* Neon with NE10 */
+};
+# endif /* CUSTOM_MODES */
+
+void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg,
+ const kiss_fft_cpx *fin,
+ kiss_fft_cpx *fout) = {
+ opus_fft_c, /* ARMv4 */
+ opus_fft_c, /* EDSP */
+ opus_fft_c, /* Media */
+ opus_fft_neon /* Neon with NE10 */
+};
+
+void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg,
+ const kiss_fft_cpx *fin,
+ kiss_fft_cpx *fout) = {
+ opus_ifft_c, /* ARMv4 */
+ opus_ifft_c, /* EDSP */
+ opus_ifft_c, /* Media */
+ opus_ifft_neon /* Neon with NE10 */
+};
+
+void (*const CLT_MDCT_FORWARD_IMPL[OPUS_ARCHMASK+1])(const mdct_lookup *l,
+ kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 *window,
+ int overlap, int shift,
+ int stride, int arch) = {
+ clt_mdct_forward_c, /* ARMv4 */
+ clt_mdct_forward_c, /* EDSP */
+ clt_mdct_forward_c, /* Media */
+ clt_mdct_forward_neon /* Neon with NE10 */
+};
+
+void (*const CLT_MDCT_BACKWARD_IMPL[OPUS_ARCHMASK+1])(const mdct_lookup *l,
+ kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 *window,
+ int overlap, int shift,
+ int stride, int arch) = {
+ clt_mdct_backward_c, /* ARMv4 */
+ clt_mdct_backward_c, /* EDSP */
+ clt_mdct_backward_c, /* Media */
+ clt_mdct_backward_neon /* Neon with NE10 */
+};
+
+# endif /* HAVE_ARM_NE10 */
+# endif /* OPUS_ARM_MAY_HAVE_NEON_INTR */
+
+#endif /* OPUS_HAVE_RTCD */
diff --git a/external/opus-1.1.4/celt/arm/armcpu.c b/external/opus-1.1.4/celt/arm/armcpu.c
new file mode 100644
index 0000000..694a63b
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/armcpu.c
@@ -0,0 +1,185 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+/* Original code from libtheora modified to suit to Opus */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef OPUS_HAVE_RTCD
+
+#include "armcpu.h"
+#include "cpu_support.h"
+#include "os_support.h"
+#include "opus_types.h"
+#include "arch.h"
+
+#define OPUS_CPU_ARM_V4_FLAG (1<<OPUS_ARCH_ARM_V4)
+#define OPUS_CPU_ARM_EDSP_FLAG (1<<OPUS_ARCH_ARM_EDSP)
+#define OPUS_CPU_ARM_MEDIA_FLAG (1<<OPUS_ARCH_ARM_MEDIA)
+#define OPUS_CPU_ARM_NEON_FLAG (1<<OPUS_ARCH_ARM_NEON)
+
+#if defined(_MSC_VER)
+/*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/
+# define WIN32_LEAN_AND_MEAN
+# define WIN32_EXTRA_LEAN
+# include <windows.h>
+
+static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){
+ opus_uint32 flags;
+ flags=0;
+ /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit
+ * instructions via their assembled hex code.
+ * All of these instructions should be essentially nops. */
+# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \
+ || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+ __try{
+ /*PLD [r13]*/
+ __emit(0xF5DDF000);
+ flags|=OPUS_CPU_ARM_EDSP_FLAG;
+ }
+ __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
+ /*Ignore exception.*/
+ }
+# if defined(OPUS_ARM_MAY_HAVE_MEDIA) \
+ || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+ __try{
+ /*SHADD8 r3,r3,r3*/
+ __emit(0xE6333F93);
+ flags|=OPUS_CPU_ARM_MEDIA_FLAG;
+ }
+ __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
+ /*Ignore exception.*/
+ }
+# if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+ __try{
+ /*VORR q0,q0,q0*/
+ __emit(0xF2200150);
+ flags|=OPUS_CPU_ARM_NEON_FLAG;
+ }
+ __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
+ /*Ignore exception.*/
+ }
+# endif
+# endif
+# endif
+ return flags;
+}
+
+#elif defined(__linux__)
+/* Linux based */
+opus_uint32 opus_cpu_capabilities(void)
+{
+ opus_uint32 flags = 0;
+ FILE *cpuinfo;
+
+ /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on
+ * Android */
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+
+ if(cpuinfo != NULL)
+ {
+ /* 512 should be enough for anybody (it's even enough for all the flags that
+ * x86 has accumulated... so far). */
+ char buf[512];
+
+ while(fgets(buf, 512, cpuinfo) != NULL)
+ {
+# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \
+ || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+ /* Search for edsp and neon flag */
+ if(memcmp(buf, "Features", 8) == 0)
+ {
+ char *p;
+ p = strstr(buf, " edsp");
+ if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
+ flags |= OPUS_CPU_ARM_EDSP_FLAG;
+
+# if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+ p = strstr(buf, " neon");
+ if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
+ flags |= OPUS_CPU_ARM_NEON_FLAG;
+# endif
+ }
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_MEDIA) \
+ || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+ /* Search for media capabilities (>= ARMv6) */
+ if(memcmp(buf, "CPU architecture:", 17) == 0)
+ {
+ int version;
+ version = atoi(buf+17);
+
+ if(version >= 6)
+ flags |= OPUS_CPU_ARM_MEDIA_FLAG;
+ }
+# endif
+ }
+
+ fclose(cpuinfo);
+ }
+ return flags;
+}
+#else
+/* The feature registers which can tell us what the processor supports are
+ * accessible in priveleged modes only, so we can't have a general user-space
+ * detection method like on x86.*/
+# error "Configured to use ARM asm but no CPU detection method available for " \
+ "your platform. Reconfigure with --disable-rtcd (or send patches)."
+#endif
+
+int opus_select_arch(void)
+{
+ opus_uint32 flags = opus_cpu_capabilities();
+ int arch = 0;
+
+ if(!(flags & OPUS_CPU_ARM_EDSP_FLAG)) {
+ /* Asserts ensure arch values are sequential */
+ celt_assert(arch == OPUS_ARCH_ARM_V4);
+ return arch;
+ }
+ arch++;
+
+ if(!(flags & OPUS_CPU_ARM_MEDIA_FLAG)) {
+ celt_assert(arch == OPUS_ARCH_ARM_EDSP);
+ return arch;
+ }
+ arch++;
+
+ if(!(flags & OPUS_CPU_ARM_NEON_FLAG)) {
+ celt_assert(arch == OPUS_ARCH_ARM_MEDIA);
+ return arch;
+ }
+ arch++;
+
+ celt_assert(arch == OPUS_ARCH_ARM_NEON);
+ return arch;
+}
+
+#endif
diff --git a/external/opus-1.1.4/celt/arm/armcpu.h b/external/opus-1.1.4/celt/arm/armcpu.h
new file mode 100644
index 0000000..820262f
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/armcpu.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#if !defined(ARMCPU_H)
+# define ARMCPU_H
+
+# if defined(OPUS_ARM_MAY_HAVE_EDSP)
+# define MAY_HAVE_EDSP(name) name ## _edsp
+# else
+# define MAY_HAVE_EDSP(name) name ## _c
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
+# define MAY_HAVE_MEDIA(name) name ## _media
+# else
+# define MAY_HAVE_MEDIA(name) MAY_HAVE_EDSP(name)
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_NEON)
+# define MAY_HAVE_NEON(name) name ## _neon
+# else
+# define MAY_HAVE_NEON(name) MAY_HAVE_MEDIA(name)
+# endif
+
+# if defined(OPUS_ARM_PRESUME_EDSP)
+# define PRESUME_EDSP(name) name ## _edsp
+# else
+# define PRESUME_EDSP(name) name ## _c
+# endif
+
+# if defined(OPUS_ARM_PRESUME_MEDIA)
+# define PRESUME_MEDIA(name) name ## _media
+# else
+# define PRESUME_MEDIA(name) PRESUME_EDSP(name)
+# endif
+
+# if defined(OPUS_ARM_PRESUME_NEON)
+# define PRESUME_NEON(name) name ## _neon
+# else
+# define PRESUME_NEON(name) PRESUME_MEDIA(name)
+# endif
+
+# if defined(OPUS_HAVE_RTCD)
+int opus_select_arch(void);
+
+#define OPUS_ARCH_ARM_V4 (0)
+#define OPUS_ARCH_ARM_EDSP (1)
+#define OPUS_ARCH_ARM_MEDIA (2)
+#define OPUS_ARCH_ARM_NEON (3)
+
+# endif
+
+#endif
diff --git a/external/opus-1.1.4/celt/arm/armopts.s.in b/external/opus-1.1.4/celt/arm/armopts.s.in
new file mode 100644
index 0000000..3d8aaf2
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/armopts.s.in
@@ -0,0 +1,37 @@
+/* Copyright (C) 2013 Mozilla Corporation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+; Set the following to 1 if we have EDSP instructions
+; (LDRD/STRD, etc., ARMv5E and later).
+OPUS_ARM_MAY_HAVE_EDSP * @OPUS_ARM_MAY_HAVE_EDSP@
+
+; Set the following to 1 if we have ARMv6 media instructions.
+OPUS_ARM_MAY_HAVE_MEDIA * @OPUS_ARM_MAY_HAVE_MEDIA@
+
+; Set the following to 1 if we have NEON (some ARMv7)
+OPUS_ARM_MAY_HAVE_NEON * @OPUS_ARM_MAY_HAVE_NEON@
+
+END
diff --git a/external/opus-1.1.4/celt/arm/celt_ne10_fft.c b/external/opus-1.1.4/celt/arm/celt_ne10_fft.c
new file mode 100644
index 0000000..42d96a7
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/celt_ne10_fft.c
@@ -0,0 +1,174 @@
+/* Copyright (c) 2015 Xiph.Org Foundation
+ Written by Viswanath Puttagunta */
+/**
+ @file celt_ne10_fft.c
+ @brief ARM Neon optimizations for fft using NE10 library
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef SKIP_CONFIG_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#endif
+
+#include <NE10_init.h>
+#include <NE10_dsp.h>
+#include "os_support.h"
+#include "kiss_fft.h"
+#include "stack_alloc.h"
+
+#if !defined(FIXED_POINT)
+# define NE10_FFT_ALLOC_C2C_TYPE_NEON ne10_fft_alloc_c2c_float32_neon
+# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_float32_t
+# define NE10_FFT_STATE_TYPE_T ne10_fft_state_float32_t
+# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_float32
+# define NE10_FFT_CPX_TYPE_T ne10_fft_cpx_float32_t
+# define NE10_FFT_C2C_1D_TYPE_NEON ne10_fft_c2c_1d_float32_neon
+#else
+# define NE10_FFT_ALLOC_C2C_TYPE_NEON(nfft) ne10_fft_alloc_c2c_int32_neon(nfft)
+# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_int32_t
+# define NE10_FFT_STATE_TYPE_T ne10_fft_state_int32_t
+# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_int32
+# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_int32
+# define NE10_FFT_CPX_TYPE_T ne10_fft_cpx_int32_t
+# define NE10_FFT_C2C_1D_TYPE_NEON ne10_fft_c2c_1d_int32_neon
+#endif
+
+#if defined(CUSTOM_MODES)
+
+/* nfft lengths in NE10 that support scaled fft */
+# define NE10_FFTSCALED_SUPPORT_MAX 4
+static const int ne10_fft_scaled_support[NE10_FFTSCALED_SUPPORT_MAX] = {
+ 480, 240, 120, 60
+};
+
+int opus_fft_alloc_arm_neon(kiss_fft_state *st)
+{
+ int i;
+ size_t memneeded = sizeof(struct arch_fft_state);
+
+ st->arch_fft = (arch_fft_state *)opus_alloc(memneeded);
+ if (!st->arch_fft)
+ return -1;
+
+ for (i = 0; i < NE10_FFTSCALED_SUPPORT_MAX; i++) {
+ if(st->nfft == ne10_fft_scaled_support[i])
+ break;
+ }
+ if (i == NE10_FFTSCALED_SUPPORT_MAX) {
+ /* This nfft length (scaled fft) is not supported in NE10 */
+ st->arch_fft->is_supported = 0;
+ st->arch_fft->priv = NULL;
+ }
+ else {
+ st->arch_fft->is_supported = 1;
+ st->arch_fft->priv = (void *)NE10_FFT_ALLOC_C2C_TYPE_NEON(st->nfft);
+ if (st->arch_fft->priv == NULL) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void opus_fft_free_arm_neon(kiss_fft_state *st)
+{
+ NE10_FFT_CFG_TYPE_T cfg;
+
+ if (!st->arch_fft)
+ return;
+
+ cfg = (NE10_FFT_CFG_TYPE_T)st->arch_fft->priv;
+ if (cfg)
+ NE10_FFT_DESTROY_C2C_TYPE(cfg);
+ opus_free(st->arch_fft);
+}
+#endif
+
+void opus_fft_neon(const kiss_fft_state *st,
+ const kiss_fft_cpx *fin,
+ kiss_fft_cpx *fout)
+{
+ NE10_FFT_STATE_TYPE_T state;
+ NE10_FFT_CFG_TYPE_T cfg = &state;
+ VARDECL(NE10_FFT_CPX_TYPE_T, buffer);
+ SAVE_STACK;
+ ALLOC(buffer, st->nfft, NE10_FFT_CPX_TYPE_T);
+
+ if (!st->arch_fft->is_supported) {
+ /* This nfft length (scaled fft) not supported in NE10 */
+ opus_fft_c(st, fin, fout);
+ }
+ else {
+ memcpy((void *)cfg, st->arch_fft->priv, sizeof(NE10_FFT_STATE_TYPE_T));
+ state.buffer = (NE10_FFT_CPX_TYPE_T *)&buffer[0];
+#if !defined(FIXED_POINT)
+ state.is_forward_scaled = 1;
+
+ NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout,
+ (NE10_FFT_CPX_TYPE_T *)fin,
+ cfg, 0);
+#else
+ NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout,
+ (NE10_FFT_CPX_TYPE_T *)fin,
+ cfg, 0, 1);
+#endif
+ }
+ RESTORE_STACK;
+}
+
+void opus_ifft_neon(const kiss_fft_state *st,
+ const kiss_fft_cpx *fin,
+ kiss_fft_cpx *fout)
+{
+ NE10_FFT_STATE_TYPE_T state;
+ NE10_FFT_CFG_TYPE_T cfg = &state;
+ VARDECL(NE10_FFT_CPX_TYPE_T, buffer);
+ SAVE_STACK;
+ ALLOC(buffer, st->nfft, NE10_FFT_CPX_TYPE_T);
+
+ if (!st->arch_fft->is_supported) {
+ /* This nfft length (scaled fft) not supported in NE10 */
+ opus_ifft_c(st, fin, fout);
+ }
+ else {
+ memcpy((void *)cfg, st->arch_fft->priv, sizeof(NE10_FFT_STATE_TYPE_T));
+ state.buffer = (NE10_FFT_CPX_TYPE_T *)&buffer[0];
+#if !defined(FIXED_POINT)
+ state.is_backward_scaled = 0;
+
+ NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout,
+ (NE10_FFT_CPX_TYPE_T *)fin,
+ cfg, 1);
+#else
+ NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout,
+ (NE10_FFT_CPX_TYPE_T *)fin,
+ cfg, 1, 0);
+#endif
+ }
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/celt/arm/celt_ne10_mdct.c b/external/opus-1.1.4/celt/arm/celt_ne10_mdct.c
new file mode 100644
index 0000000..293c3ef
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/celt_ne10_mdct.c
@@ -0,0 +1,258 @@
+/* Copyright (c) 2015 Xiph.Org Foundation
+ Written by Viswanath Puttagunta */
+/**
+ @file celt_ne10_mdct.c
+ @brief ARM Neon optimizations for mdct using NE10 library
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef SKIP_CONFIG_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#endif
+
+#include "kiss_fft.h"
+#include "_kiss_fft_guts.h"
+#include "mdct.h"
+#include "stack_alloc.h"
+
+void clt_mdct_forward_neon(const mdct_lookup *l,
+ kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 *window,
+ int overlap, int shift, int stride, int arch)
+{
+ int i;
+ int N, N2, N4;
+ VARDECL(kiss_fft_scalar, f);
+ VARDECL(kiss_fft_cpx, f2);
+ const kiss_fft_state *st = l->kfft[shift];
+ const kiss_twiddle_scalar *trig;
+
+ SAVE_STACK;
+
+ N = l->n;
+ trig = l->trig;
+ for (i=0;i<shift;i++)
+ {
+ N >>= 1;
+ trig += N;
+ }
+ N2 = N>>1;
+ N4 = N>>2;
+
+ ALLOC(f, N2, kiss_fft_scalar);
+ ALLOC(f2, N4, kiss_fft_cpx);
+
+ /* Consider the input to be composed of four blocks: [a, b, c, d] */
+ /* Window, shuffle, fold */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1);
+ const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1);
+ kiss_fft_scalar * OPUS_RESTRICT yp = f;
+ const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1);
+ const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1;
+ for(i=0;i<((overlap+3)>>2);i++)
+ {
+ /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
+ *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2);
+ *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]);
+ xp1+=2;
+ xp2-=2;
+ wp1+=2;
+ wp2-=2;
+ }
+ wp1 = window;
+ wp2 = window+overlap-1;
+ for(;i<N4-((overlap+3)>>2);i++)
+ {
+ /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+ *yp++ = *xp2;
+ *yp++ = *xp1;
+ xp1+=2;
+ xp2-=2;
+ }
+ for(;i<N4;i++)
+ {
+ /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+ *yp++ = -MULT16_32_Q15(*wp1, xp1[-N2]) + MULT16_32_Q15(*wp2, *xp2);
+ *yp++ = MULT16_32_Q15(*wp2, *xp1) + MULT16_32_Q15(*wp1, xp2[N2]);
+ xp1+=2;
+ xp2-=2;
+ wp1+=2;
+ wp2-=2;
+ }
+ }
+ /* Pre-rotation */
+ {
+ kiss_fft_scalar * OPUS_RESTRICT yp = f;
+ const kiss_twiddle_scalar *t = &trig[0];
+ for(i=0;i<N4;i++)
+ {
+ kiss_fft_cpx yc;
+ kiss_twiddle_scalar t0, t1;
+ kiss_fft_scalar re, im, yr, yi;
+ t0 = t[i];
+ t1 = t[N4+i];
+ re = *yp++;
+ im = *yp++;
+ yr = S_MUL(re,t0) - S_MUL(im,t1);
+ yi = S_MUL(im,t0) + S_MUL(re,t1);
+ yc.r = yr;
+ yc.i = yi;
+ f2[i] = yc;
+ }
+ }
+
+ opus_fft(st, f2, (kiss_fft_cpx *)f, arch);
+
+ /* Post-rotate */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_cpx * OPUS_RESTRICT fp = (kiss_fft_cpx *)f;
+ kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+ kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1);
+ const kiss_twiddle_scalar *t = &trig[0];
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ for(i=0;i<N4;i++)
+ {
+ kiss_fft_scalar yr, yi;
+ yr = S_MUL(fp->i,t[N4+i]) - S_MUL(fp->r,t[i]);
+ yi = S_MUL(fp->r,t[N4+i]) + S_MUL(fp->i,t[i]);
+ *yp1 = yr;
+ *yp2 = yi;
+ fp++;
+ yp1 += 2*stride;
+ yp2 -= 2*stride;
+ }
+ }
+ RESTORE_STACK;
+}
+
+void clt_mdct_backward_neon(const mdct_lookup *l,
+ kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 * OPUS_RESTRICT window,
+ int overlap, int shift, int stride, int arch)
+{
+ int i;
+ int N, N2, N4;
+ VARDECL(kiss_fft_scalar, f);
+ const kiss_twiddle_scalar *trig;
+ const kiss_fft_state *st = l->kfft[shift];
+
+ N = l->n;
+ trig = l->trig;
+ for (i=0;i<shift;i++)
+ {
+ N >>= 1;
+ trig += N;
+ }
+ N2 = N>>1;
+ N4 = N>>2;
+
+ ALLOC(f, N2, kiss_fft_scalar);
+
+ /* Pre-rotate */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_scalar * OPUS_RESTRICT xp1 = in;
+ const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1);
+ kiss_fft_scalar * OPUS_RESTRICT yp = f;
+ const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0];
+ for(i=0;i<N4;i++)
+ {
+ kiss_fft_scalar yr, yi;
+ yr = S_MUL(*xp2, t[i]) + S_MUL(*xp1, t[N4+i]);
+ yi = S_MUL(*xp1, t[i]) - S_MUL(*xp2, t[N4+i]);
+ yp[2*i] = yr;
+ yp[2*i+1] = yi;
+ xp1+=2*stride;
+ xp2-=2*stride;
+ }
+ }
+
+ opus_ifft(st, (kiss_fft_cpx *)f, (kiss_fft_cpx*)(out+(overlap>>1)), arch);
+
+ /* Post-rotate and de-shuffle from both ends of the buffer at once to make
+ it in-place. */
+ {
+ kiss_fft_scalar * yp0 = out+(overlap>>1);
+ kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2;
+ const kiss_twiddle_scalar *t = &trig[0];
+ /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the
+ middle pair will be computed twice. */
+ for(i=0;i<(N4+1)>>1;i++)
+ {
+ kiss_fft_scalar re, im, yr, yi;
+ kiss_twiddle_scalar t0, t1;
+ re = yp0[0];
+ im = yp0[1];
+ t0 = t[i];
+ t1 = t[N4+i];
+ /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+ yr = S_MUL(re,t0) + S_MUL(im,t1);
+ yi = S_MUL(re,t1) - S_MUL(im,t0);
+ re = yp1[0];
+ im = yp1[1];
+ yp0[0] = yr;
+ yp1[1] = yi;
+
+ t0 = t[(N4-i-1)];
+ t1 = t[(N2-i-1)];
+ /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+ yr = S_MUL(re,t0) + S_MUL(im,t1);
+ yi = S_MUL(re,t1) - S_MUL(im,t0);
+ yp1[0] = yr;
+ yp0[1] = yi;
+ yp0 += 2;
+ yp1 -= 2;
+ }
+ }
+
+ /* Mirror on both sides for TDAC */
+ {
+ kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1;
+ kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+ const opus_val16 * OPUS_RESTRICT wp1 = window;
+ const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1;
+
+ for(i = 0; i < overlap/2; i++)
+ {
+ kiss_fft_scalar x1, x2;
+ x1 = *xp1;
+ x2 = *yp1;
+ *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1);
+ *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1);
+ wp1++;
+ wp2--;
+ }
+ }
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/celt/arm/celt_neon_intr.c b/external/opus-1.1.4/celt/arm/celt_neon_intr.c
new file mode 100644
index 0000000..47bbe3d
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/celt_neon_intr.c
@@ -0,0 +1,311 @@
+/* Copyright (c) 2014-2015 Xiph.Org Foundation
+ Written by Viswanath Puttagunta */
+/**
+ @file celt_neon_intr.c
+ @brief ARM Neon Intrinsic optimizations for celt
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <arm_neon.h>
+#include "../pitch.h"
+
+#if defined(FIXED_POINT)
+void xcorr_kernel_neon_fixed(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[4], int len)
+{
+ int j;
+ int32x4_t a = vld1q_s32(sum);
+ /* Load y[0...3] */
+ /* This requires len>0 to always be valid (which we assert in the C code). */
+ int16x4_t y0 = vld1_s16(y);
+ y += 4;
+
+ for (j = 0; j + 8 <= len; j += 8)
+ {
+ /* Load x[0...7] */
+ int16x8_t xx = vld1q_s16(x);
+ int16x4_t x0 = vget_low_s16(xx);
+ int16x4_t x4 = vget_high_s16(xx);
+ /* Load y[4...11] */
+ int16x8_t yy = vld1q_s16(y);
+ int16x4_t y4 = vget_low_s16(yy);
+ int16x4_t y8 = vget_high_s16(yy);
+ int32x4_t a0 = vmlal_lane_s16(a, y0, x0, 0);
+ int32x4_t a1 = vmlal_lane_s16(a0, y4, x4, 0);
+
+ int16x4_t y1 = vext_s16(y0, y4, 1);
+ int16x4_t y5 = vext_s16(y4, y8, 1);
+ int32x4_t a2 = vmlal_lane_s16(a1, y1, x0, 1);
+ int32x4_t a3 = vmlal_lane_s16(a2, y5, x4, 1);
+
+ int16x4_t y2 = vext_s16(y0, y4, 2);
+ int16x4_t y6 = vext_s16(y4, y8, 2);
+ int32x4_t a4 = vmlal_lane_s16(a3, y2, x0, 2);
+ int32x4_t a5 = vmlal_lane_s16(a4, y6, x4, 2);
+
+ int16x4_t y3 = vext_s16(y0, y4, 3);
+ int16x4_t y7 = vext_s16(y4, y8, 3);
+ int32x4_t a6 = vmlal_lane_s16(a5, y3, x0, 3);
+ int32x4_t a7 = vmlal_lane_s16(a6, y7, x4, 3);
+
+ y0 = y8;
+ a = a7;
+ x += 8;
+ y += 8;
+ }
+
+ for (; j < len; j++)
+ {
+ int16x4_t x0 = vld1_dup_s16(x); /* load next x */
+ int32x4_t a0 = vmlal_s16(a, y0, x0);
+
+ int16x4_t y4 = vld1_dup_s16(y); /* load next y */
+ y0 = vext_s16(y0, y4, 1);
+ a = a0;
+ x++;
+ y++;
+ }
+
+ vst1q_s32(sum, a);
+}
+
+#else
+/*
+ * Function: xcorr_kernel_neon_float
+ * ---------------------------------
+ * Computes 4 correlation values and stores them in sum[4]
+ */
+static void xcorr_kernel_neon_float(const float32_t *x, const float32_t *y,
+ float32_t sum[4], int len) {
+ float32x4_t YY[3];
+ float32x4_t YEXT[3];
+ float32x4_t XX[2];
+ float32x2_t XX_2;
+ float32x4_t SUMM;
+ const float32_t *xi = x;
+ const float32_t *yi = y;
+
+ celt_assert(len>0);
+
+ YY[0] = vld1q_f32(yi);
+ SUMM = vdupq_n_f32(0);
+
+ /* Consume 8 elements in x vector and 12 elements in y
+ * vector. However, the 12'th element never really gets
+ * touched in this loop. So, if len == 8, then we only
+ * must access y[0] to y[10]. y[11] must not be accessed
+ * hence make sure len > 8 and not len >= 8
+ */
+ while (len > 8) {
+ yi += 4;
+ YY[1] = vld1q_f32(yi);
+ yi += 4;
+ YY[2] = vld1q_f32(yi);
+
+ XX[0] = vld1q_f32(xi);
+ xi += 4;
+ XX[1] = vld1q_f32(xi);
+ xi += 4;
+
+ SUMM = vmlaq_lane_f32(SUMM, YY[0], vget_low_f32(XX[0]), 0);
+ YEXT[0] = vextq_f32(YY[0], YY[1], 1);
+ SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[0]), 1);
+ YEXT[1] = vextq_f32(YY[0], YY[1], 2);
+ SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[0]), 0);
+ YEXT[2] = vextq_f32(YY[0], YY[1], 3);
+ SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[0]), 1);
+
+ SUMM = vmlaq_lane_f32(SUMM, YY[1], vget_low_f32(XX[1]), 0);
+ YEXT[0] = vextq_f32(YY[1], YY[2], 1);
+ SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[1]), 1);
+ YEXT[1] = vextq_f32(YY[1], YY[2], 2);
+ SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[1]), 0);
+ YEXT[2] = vextq_f32(YY[1], YY[2], 3);
+ SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[1]), 1);
+
+ YY[0] = YY[2];
+ len -= 8;
+ }
+
+ /* Consume 4 elements in x vector and 8 elements in y
+ * vector. However, the 8'th element in y never really gets
+ * touched in this loop. So, if len == 4, then we only
+ * must access y[0] to y[6]. y[7] must not be accessed
+ * hence make sure len>4 and not len>=4
+ */
+ if (len > 4) {
+ yi += 4;
+ YY[1] = vld1q_f32(yi);
+
+ XX[0] = vld1q_f32(xi);
+ xi += 4;
+
+ SUMM = vmlaq_lane_f32(SUMM, YY[0], vget_low_f32(XX[0]), 0);
+ YEXT[0] = vextq_f32(YY[0], YY[1], 1);
+ SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[0]), 1);
+ YEXT[1] = vextq_f32(YY[0], YY[1], 2);
+ SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[0]), 0);
+ YEXT[2] = vextq_f32(YY[0], YY[1], 3);
+ SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[0]), 1);
+
+ YY[0] = YY[1];
+ len -= 4;
+ }
+
+ while (--len > 0) {
+ XX_2 = vld1_dup_f32(xi++);
+ SUMM = vmlaq_lane_f32(SUMM, YY[0], XX_2, 0);
+ YY[0]= vld1q_f32(++yi);
+ }
+
+ XX_2 = vld1_dup_f32(xi);
+ SUMM = vmlaq_lane_f32(SUMM, YY[0], XX_2, 0);
+
+ vst1q_f32(sum, SUMM);
+}
+
+/*
+ * Function: xcorr_kernel_neon_float_process1
+ * ---------------------------------
+ * Computes single correlation values and stores in *sum
+ */
+static void xcorr_kernel_neon_float_process1(const float32_t *x,
+ const float32_t *y, float32_t *sum, int len) {
+ float32x4_t XX[4];
+ float32x4_t YY[4];
+ float32x2_t XX_2;
+ float32x2_t YY_2;
+ float32x4_t SUMM;
+ float32x2_t SUMM_2[2];
+ const float32_t *xi = x;
+ const float32_t *yi = y;
+
+ SUMM = vdupq_n_f32(0);
+
+ /* Work on 16 values per iteration */
+ while (len >= 16) {
+ XX[0] = vld1q_f32(xi);
+ xi += 4;
+ XX[1] = vld1q_f32(xi);
+ xi += 4;
+ XX[2] = vld1q_f32(xi);
+ xi += 4;
+ XX[3] = vld1q_f32(xi);
+ xi += 4;
+
+ YY[0] = vld1q_f32(yi);
+ yi += 4;
+ YY[1] = vld1q_f32(yi);
+ yi += 4;
+ YY[2] = vld1q_f32(yi);
+ yi += 4;
+ YY[3] = vld1q_f32(yi);
+ yi += 4;
+
+ SUMM = vmlaq_f32(SUMM, YY[0], XX[0]);
+ SUMM = vmlaq_f32(SUMM, YY[1], XX[1]);
+ SUMM = vmlaq_f32(SUMM, YY[2], XX[2]);
+ SUMM = vmlaq_f32(SUMM, YY[3], XX[3]);
+ len -= 16;
+ }
+
+ /* Work on 8 values */
+ if (len >= 8) {
+ XX[0] = vld1q_f32(xi);
+ xi += 4;
+ XX[1] = vld1q_f32(xi);
+ xi += 4;
+
+ YY[0] = vld1q_f32(yi);
+ yi += 4;
+ YY[1] = vld1q_f32(yi);
+ yi += 4;
+
+ SUMM = vmlaq_f32(SUMM, YY[0], XX[0]);
+ SUMM = vmlaq_f32(SUMM, YY[1], XX[1]);
+ len -= 8;
+ }
+
+ /* Work on 4 values */
+ if (len >= 4) {
+ XX[0] = vld1q_f32(xi);
+ xi += 4;
+ YY[0] = vld1q_f32(yi);
+ yi += 4;
+ SUMM = vmlaq_f32(SUMM, YY[0], XX[0]);
+ len -= 4;
+ }
+
+ /* Start accumulating results */
+ SUMM_2[0] = vget_low_f32(SUMM);
+ if (len >= 2) {
+ /* While at it, consume 2 more values if available */
+ XX_2 = vld1_f32(xi);
+ xi += 2;
+ YY_2 = vld1_f32(yi);
+ yi += 2;
+ SUMM_2[0] = vmla_f32(SUMM_2[0], YY_2, XX_2);
+ len -= 2;
+ }
+ SUMM_2[1] = vget_high_f32(SUMM);
+ SUMM_2[0] = vadd_f32(SUMM_2[0], SUMM_2[1]);
+ SUMM_2[0] = vpadd_f32(SUMM_2[0], SUMM_2[0]);
+ /* Ok, now we have result accumulated in SUMM_2[0].0 */
+
+ if (len > 0) {
+ /* Case when you have one value left */
+ XX_2 = vld1_dup_f32(xi);
+ YY_2 = vld1_dup_f32(yi);
+ SUMM_2[0] = vmla_f32(SUMM_2[0], XX_2, YY_2);
+ }
+
+ vst1_lane_f32(sum, SUMM_2[0], 0);
+}
+
+void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y,
+ opus_val32 *xcorr, int len, int max_pitch) {
+ int i;
+ celt_assert(max_pitch > 0);
+ celt_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
+
+ for (i = 0; i < (max_pitch-3); i += 4) {
+ xcorr_kernel_neon_float((const float32_t *)_x, (const float32_t *)_y+i,
+ (float32_t *)xcorr+i, len);
+ }
+
+ /* In case max_pitch isn't multiple of 4
+ * compute single correlation value per iteration
+ */
+ for (; i < max_pitch; i++) {
+ xcorr_kernel_neon_float_process1((const float32_t *)_x,
+ (const float32_t *)_y+i, (float32_t *)xcorr+i, len);
+ }
+}
+#endif
diff --git a/external/opus-1.1.4/celt/arm/celt_pitch_xcorr_arm-gnu.S b/external/opus-1.1.4/celt/arm/celt_pitch_xcorr_arm-gnu.S
new file mode 100644
index 0000000..5b2ee55
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/celt_pitch_xcorr_arm-gnu.S
@@ -0,0 +1,551 @@
+ .syntax unified
+@ Copyright (c) 2007-2008 CSIRO
+@ Copyright (c) 2007-2009 Xiph.Org Foundation
+@ Copyright (c) 2013 Parrot
+@ Written by Aurélien Zanelli
+@
+@ Redistribution and use in source and binary forms, with or without
+@ modification, are permitted provided that the following conditions
+@ are met:
+@
+@ - Redistributions of source code must retain the above copyright
+@ notice, this list of conditions and the following disclaimer.
+@
+@ - Redistributions in binary form must reproduce the above copyright
+@ notice, this list of conditions and the following disclaimer in the
+@ documentation and/or other materials provided with the distribution.
+@
+@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+@ ``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 COPYRIGHT OWNER
+@ OR CONTRIBUTORS 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.
+
+ .text; .p2align 2; .arch armv7-a
+ .fpu neon
+ .object_arch armv4t
+
+ .include "celt/arm/armopts-gnu.S"
+
+ .if OPUS_ARM_MAY_HAVE_EDSP
+ .global celt_pitch_xcorr_edsp
+ .endif
+
+ .if OPUS_ARM_MAY_HAVE_NEON
+ .global celt_pitch_xcorr_neon
+ .endif
+
+ .if OPUS_ARM_MAY_HAVE_NEON
+
+@ Compute sum[k]=sum(x[j]*y[j+k],j=0...len-1), k=0...3
+; xcorr_kernel_neon: @ PROC
+xcorr_kernel_neon_start:
+ @ input:
+ @ r3 = int len
+ @ r4 = opus_val16 *x
+ @ r5 = opus_val16 *y
+ @ q0 = opus_val32 sum[4]
+ @ output:
+ @ q0 = opus_val32 sum[4]
+ @ preserved: r0-r3, r6-r11, d2, q4-q7, q9-q15
+ @ internal usage:
+ @ r12 = int j
+ @ d3 = y_3|y_2|y_1|y_0
+ @ q2 = y_B|y_A|y_9|y_8|y_7|y_6|y_5|y_4
+ @ q3 = x_7|x_6|x_5|x_4|x_3|x_2|x_1|x_0
+ @ q8 = scratch
+ @
+ @ Load y[0...3]
+ @ This requires len>0 to always be valid (which we assert in the C code).
+ VLD1.16 {d5}, [r5]!
+ SUBS r12, r3, #8
+ BLE xcorr_kernel_neon_process4
+@ Process 8 samples at a time.
+@ This loop loads one y value more than we actually need. Therefore we have to
+@ stop as soon as there are 8 or fewer samples left (instead of 7), to avoid
+@ reading past the end of the array.
+xcorr_kernel_neon_process8:
+ @ This loop has 19 total instructions (10 cycles to issue, minimum), with
+ @ - 2 cycles of ARM insrtuctions,
+ @ - 10 cycles of load/store/byte permute instructions, and
+ @ - 9 cycles of data processing instructions.
+ @ On a Cortex A8, we dual-issue the maximum amount (9 cycles) between the
+ @ latter two categories, meaning the whole loop should run in 10 cycles per
+ @ iteration, barring cache misses.
+ @
+ @ Load x[0...7]
+ VLD1.16 {d6, d7}, [r4]!
+ @ Unlike VMOV, VAND is a data processsing instruction (and doesn't get
+ @ assembled to VMOV, like VORR would), so it dual-issues with the prior VLD1.
+ VAND d3, d5, d5
+ SUBS r12, r12, #8
+ @ Load y[4...11]
+ VLD1.16 {d4, d5}, [r5]!
+ VMLAL.S16 q0, d3, d6[0]
+ VEXT.16 d16, d3, d4, #1
+ VMLAL.S16 q0, d4, d7[0]
+ VEXT.16 d17, d4, d5, #1
+ VMLAL.S16 q0, d16, d6[1]
+ VEXT.16 d16, d3, d4, #2
+ VMLAL.S16 q0, d17, d7[1]
+ VEXT.16 d17, d4, d5, #2
+ VMLAL.S16 q0, d16, d6[2]
+ VEXT.16 d16, d3, d4, #3
+ VMLAL.S16 q0, d17, d7[2]
+ VEXT.16 d17, d4, d5, #3
+ VMLAL.S16 q0, d16, d6[3]
+ VMLAL.S16 q0, d17, d7[3]
+ BGT xcorr_kernel_neon_process8
+@ Process 4 samples here if we have > 4 left (still reading one extra y value).
+xcorr_kernel_neon_process4:
+ ADDS r12, r12, #4
+ BLE xcorr_kernel_neon_process2
+ @ Load x[0...3]
+ VLD1.16 d6, [r4]!
+ @ Use VAND since it's a data processing instruction again.
+ VAND d4, d5, d5
+ SUB r12, r12, #4
+ @ Load y[4...7]
+ VLD1.16 d5, [r5]!
+ VMLAL.S16 q0, d4, d6[0]
+ VEXT.16 d16, d4, d5, #1
+ VMLAL.S16 q0, d16, d6[1]
+ VEXT.16 d16, d4, d5, #2
+ VMLAL.S16 q0, d16, d6[2]
+ VEXT.16 d16, d4, d5, #3
+ VMLAL.S16 q0, d16, d6[3]
+@ Process 2 samples here if we have > 2 left (still reading one extra y value).
+xcorr_kernel_neon_process2:
+ ADDS r12, r12, #2
+ BLE xcorr_kernel_neon_process1
+ @ Load x[0...1]
+ VLD2.16 {d6[],d7[]}, [r4]!
+ @ Use VAND since it's a data processing instruction again.
+ VAND d4, d5, d5
+ SUB r12, r12, #2
+ @ Load y[4...5]
+ VLD1.32 {d5[]}, [r5]!
+ VMLAL.S16 q0, d4, d6
+ VEXT.16 d16, d4, d5, #1
+ @ Replace bottom copy of {y5,y4} in d5 with {y3,y2} from d4, using VSRI
+ @ instead of VEXT, since it's a data-processing instruction.
+ VSRI.64 d5, d4, #32
+ VMLAL.S16 q0, d16, d7
+@ Process 1 sample using the extra y value we loaded above.
+xcorr_kernel_neon_process1:
+ @ Load next *x
+ VLD1.16 {d6[]}, [r4]!
+ ADDS r12, r12, #1
+ @ y[0...3] are left in d5 from prior iteration(s) (if any)
+ VMLAL.S16 q0, d5, d6
+ MOVLE pc, lr
+@ Now process 1 last sample, not reading ahead.
+ @ Load last *y
+ VLD1.16 {d4[]}, [r5]!
+ VSRI.64 d4, d5, #16
+ @ Load last *x
+ VLD1.16 {d6[]}, [r4]!
+ VMLAL.S16 q0, d4, d6
+ MOV pc, lr
+ .size xcorr_kernel_neon, .-xcorr_kernel_neon @ ENDP
+
+@ opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y,
+@ opus_val32 *xcorr, int len, int max_pitch)
+; celt_pitch_xcorr_neon: @ PROC
+ @ input:
+ @ r0 = opus_val16 *_x
+ @ r1 = opus_val16 *_y
+ @ r2 = opus_val32 *xcorr
+ @ r3 = int len
+ @ output:
+ @ r0 = int maxcorr
+ @ internal usage:
+ @ r4 = opus_val16 *x (for xcorr_kernel_neon())
+ @ r5 = opus_val16 *y (for xcorr_kernel_neon())
+ @ r6 = int max_pitch
+ @ r12 = int j
+ @ q15 = int maxcorr[4] (q15 is not used by xcorr_kernel_neon())
+ STMFD sp!, {r4-r6, lr}
+ LDR r6, [sp, #16]
+ VMOV.S32 q15, #1
+ @ if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
+ SUBS r6, r6, #4
+ BLT celt_pitch_xcorr_neon_process4_done
+celt_pitch_xcorr_neon_process4:
+ @ xcorr_kernel_neon parameters:
+ @ r3 = len, r4 = _x, r5 = _y, q0 = {0, 0, 0, 0}
+ MOV r4, r0
+ MOV r5, r1
+ VEOR q0, q0, q0
+ @ xcorr_kernel_neon only modifies r4, r5, r12, and q0...q3.
+ @ So we don't save/restore any other registers.
+ BL xcorr_kernel_neon_start
+ SUBS r6, r6, #4
+ VST1.32 {q0}, [r2]!
+ @ _y += 4
+ ADD r1, r1, #8
+ VMAX.S32 q15, q15, q0
+ @ if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
+ BGE celt_pitch_xcorr_neon_process4
+@ We have less than 4 sums left to compute.
+celt_pitch_xcorr_neon_process4_done:
+ ADDS r6, r6, #4
+ @ Reduce maxcorr to a single value
+ VMAX.S32 d30, d30, d31
+ VPMAX.S32 d30, d30, d30
+ @ if (max_pitch <= 0) goto celt_pitch_xcorr_neon_done
+ BLE celt_pitch_xcorr_neon_done
+@ Now compute each remaining sum one at a time.
+celt_pitch_xcorr_neon_process_remaining:
+ MOV r4, r0
+ MOV r5, r1
+ VMOV.I32 q0, #0
+ SUBS r12, r3, #8
+ BLT celt_pitch_xcorr_neon_process_remaining4
+@ Sum terms 8 at a time.
+celt_pitch_xcorr_neon_process_remaining_loop8:
+ @ Load x[0...7]
+ VLD1.16 {q1}, [r4]!
+ @ Load y[0...7]
+ VLD1.16 {q2}, [r5]!
+ SUBS r12, r12, #8
+ VMLAL.S16 q0, d4, d2
+ VMLAL.S16 q0, d5, d3
+ BGE celt_pitch_xcorr_neon_process_remaining_loop8
+@ Sum terms 4 at a time.
+celt_pitch_xcorr_neon_process_remaining4:
+ ADDS r12, r12, #4
+ BLT celt_pitch_xcorr_neon_process_remaining4_done
+ @ Load x[0...3]
+ VLD1.16 {d2}, [r4]!
+ @ Load y[0...3]
+ VLD1.16 {d3}, [r5]!
+ SUB r12, r12, #4
+ VMLAL.S16 q0, d3, d2
+celt_pitch_xcorr_neon_process_remaining4_done:
+ @ Reduce the sum to a single value.
+ VADD.S32 d0, d0, d1
+ VPADDL.S32 d0, d0
+ ADDS r12, r12, #4
+ BLE celt_pitch_xcorr_neon_process_remaining_loop_done
+@ Sum terms 1 at a time.
+celt_pitch_xcorr_neon_process_remaining_loop1:
+ VLD1.16 {d2[]}, [r4]!
+ VLD1.16 {d3[]}, [r5]!
+ SUBS r12, r12, #1
+ VMLAL.S16 q0, d2, d3
+ BGT celt_pitch_xcorr_neon_process_remaining_loop1
+celt_pitch_xcorr_neon_process_remaining_loop_done:
+ VST1.32 {d0[0]}, [r2]!
+ VMAX.S32 d30, d30, d0
+ SUBS r6, r6, #1
+ @ _y++
+ ADD r1, r1, #2
+ @ if (--max_pitch > 0) goto celt_pitch_xcorr_neon_process_remaining
+ BGT celt_pitch_xcorr_neon_process_remaining
+celt_pitch_xcorr_neon_done:
+ VMOV.32 r0, d30[0]
+ LDMFD sp!, {r4-r6, pc}
+ .size celt_pitch_xcorr_neon, .-celt_pitch_xcorr_neon @ ENDP
+
+ .endif
+
+ .if OPUS_ARM_MAY_HAVE_EDSP
+
+@ This will get used on ARMv7 devices without NEON, so it has been optimized
+@ to take advantage of dual-issuing where possible.
+; xcorr_kernel_edsp: @ PROC
+xcorr_kernel_edsp_start:
+ @ input:
+ @ r3 = int len
+ @ r4 = opus_val16 *_x (must be 32-bit aligned)
+ @ r5 = opus_val16 *_y (must be 32-bit aligned)
+ @ r6...r9 = opus_val32 sum[4]
+ @ output:
+ @ r6...r9 = opus_val32 sum[4]
+ @ preserved: r0-r5
+ @ internal usage
+ @ r2 = int j
+ @ r12,r14 = opus_val16 x[4]
+ @ r10,r11 = opus_val16 y[4]
+ STMFD sp!, {r2,r4,r5,lr}
+ LDR r10, [r5], #4 @ Load y[0...1]
+ SUBS r2, r3, #4 @ j = len-4
+ LDR r11, [r5], #4 @ Load y[2...3]
+ BLE xcorr_kernel_edsp_process4_done
+ LDR r12, [r4], #4 @ Load x[0...1]
+ @ Stall
+xcorr_kernel_edsp_process4:
+ @ The multiplies must issue from pipeline 0, and can't dual-issue with each
+ @ other. Every other instruction here dual-issues with a multiply, and is
+ @ thus "free". There should be no stalls in the body of the loop.
+ SMLABB r6, r12, r10, r6 @ sum[0] = MAC16_16(sum[0],x_0,y_0)
+ LDR r14, [r4], #4 @ Load x[2...3]
+ SMLABT r7, r12, r10, r7 @ sum[1] = MAC16_16(sum[1],x_0,y_1)
+ SUBS r2, r2, #4 @ j-=4
+ SMLABB r8, r12, r11, r8 @ sum[2] = MAC16_16(sum[2],x_0,y_2)
+ SMLABT r9, r12, r11, r9 @ sum[3] = MAC16_16(sum[3],x_0,y_3)
+ SMLATT r6, r12, r10, r6 @ sum[0] = MAC16_16(sum[0],x_1,y_1)
+ LDR r10, [r5], #4 @ Load y[4...5]
+ SMLATB r7, r12, r11, r7 @ sum[1] = MAC16_16(sum[1],x_1,y_2)
+ SMLATT r8, r12, r11, r8 @ sum[2] = MAC16_16(sum[2],x_1,y_3)
+ SMLATB r9, r12, r10, r9 @ sum[3] = MAC16_16(sum[3],x_1,y_4)
+ LDRGT r12, [r4], #4 @ Load x[0...1]
+ SMLABB r6, r14, r11, r6 @ sum[0] = MAC16_16(sum[0],x_2,y_2)
+ SMLABT r7, r14, r11, r7 @ sum[1] = MAC16_16(sum[1],x_2,y_3)
+ SMLABB r8, r14, r10, r8 @ sum[2] = MAC16_16(sum[2],x_2,y_4)
+ SMLABT r9, r14, r10, r9 @ sum[3] = MAC16_16(sum[3],x_2,y_5)
+ SMLATT r6, r14, r11, r6 @ sum[0] = MAC16_16(sum[0],x_3,y_3)
+ LDR r11, [r5], #4 @ Load y[6...7]
+ SMLATB r7, r14, r10, r7 @ sum[1] = MAC16_16(sum[1],x_3,y_4)
+ SMLATT r8, r14, r10, r8 @ sum[2] = MAC16_16(sum[2],x_3,y_5)
+ SMLATB r9, r14, r11, r9 @ sum[3] = MAC16_16(sum[3],x_3,y_6)
+ BGT xcorr_kernel_edsp_process4
+xcorr_kernel_edsp_process4_done:
+ ADDS r2, r2, #4
+ BLE xcorr_kernel_edsp_done
+ LDRH r12, [r4], #2 @ r12 = *x++
+ SUBS r2, r2, #1 @ j--
+ @ Stall
+ SMLABB r6, r12, r10, r6 @ sum[0] = MAC16_16(sum[0],x,y_0)
+ LDRHGT r14, [r4], #2 @ r14 = *x++
+ SMLABT r7, r12, r10, r7 @ sum[1] = MAC16_16(sum[1],x,y_1)
+ SMLABB r8, r12, r11, r8 @ sum[2] = MAC16_16(sum[2],x,y_2)
+ SMLABT r9, r12, r11, r9 @ sum[3] = MAC16_16(sum[3],x,y_3)
+ BLE xcorr_kernel_edsp_done
+ SMLABT r6, r14, r10, r6 @ sum[0] = MAC16_16(sum[0],x,y_1)
+ SUBS r2, r2, #1 @ j--
+ SMLABB r7, r14, r11, r7 @ sum[1] = MAC16_16(sum[1],x,y_2)
+ LDRH r10, [r5], #2 @ r10 = y_4 = *y++
+ SMLABT r8, r14, r11, r8 @ sum[2] = MAC16_16(sum[2],x,y_3)
+ LDRHGT r12, [r4], #2 @ r12 = *x++
+ SMLABB r9, r14, r10, r9 @ sum[3] = MAC16_16(sum[3],x,y_4)
+ BLE xcorr_kernel_edsp_done
+ SMLABB r6, r12, r11, r6 @ sum[0] = MAC16_16(sum[0],tmp,y_2)
+ CMP r2, #1 @ j--
+ SMLABT r7, r12, r11, r7 @ sum[1] = MAC16_16(sum[1],tmp,y_3)
+ LDRH r2, [r5], #2 @ r2 = y_5 = *y++
+ SMLABB r8, r12, r10, r8 @ sum[2] = MAC16_16(sum[2],tmp,y_4)
+ LDRHGT r14, [r4] @ r14 = *x
+ SMLABB r9, r12, r2, r9 @ sum[3] = MAC16_16(sum[3],tmp,y_5)
+ BLE xcorr_kernel_edsp_done
+ SMLABT r6, r14, r11, r6 @ sum[0] = MAC16_16(sum[0],tmp,y_3)
+ LDRH r11, [r5] @ r11 = y_6 = *y
+ SMLABB r7, r14, r10, r7 @ sum[1] = MAC16_16(sum[1],tmp,y_4)
+ SMLABB r8, r14, r2, r8 @ sum[2] = MAC16_16(sum[2],tmp,y_5)
+ SMLABB r9, r14, r11, r9 @ sum[3] = MAC16_16(sum[3],tmp,y_6)
+xcorr_kernel_edsp_done:
+ LDMFD sp!, {r2,r4,r5,pc}
+ .size xcorr_kernel_edsp, .-xcorr_kernel_edsp @ ENDP
+
+; celt_pitch_xcorr_edsp: @ PROC
+ @ input:
+ @ r0 = opus_val16 *_x (must be 32-bit aligned)
+ @ r1 = opus_val16 *_y (only needs to be 16-bit aligned)
+ @ r2 = opus_val32 *xcorr
+ @ r3 = int len
+ @ output:
+ @ r0 = maxcorr
+ @ internal usage
+ @ r4 = opus_val16 *x
+ @ r5 = opus_val16 *y
+ @ r6 = opus_val32 sum0
+ @ r7 = opus_val32 sum1
+ @ r8 = opus_val32 sum2
+ @ r9 = opus_val32 sum3
+ @ r1 = int max_pitch
+ @ r12 = int j
+ STMFD sp!, {r4-r11, lr}
+ MOV r5, r1
+ LDR r1, [sp, #36]
+ MOV r4, r0
+ TST r5, #3
+ @ maxcorr = 1
+ MOV r0, #1
+ BEQ celt_pitch_xcorr_edsp_process1u_done
+@ Compute one sum at the start to make y 32-bit aligned.
+ SUBS r12, r3, #4
+ @ r14 = sum = 0
+ MOV r14, #0
+ LDRH r8, [r5], #2
+ BLE celt_pitch_xcorr_edsp_process1u_loop4_done
+ LDR r6, [r4], #4
+ MOV r8, r8, LSL #16
+celt_pitch_xcorr_edsp_process1u_loop4:
+ LDR r9, [r5], #4
+ SMLABT r14, r6, r8, r14 @ sum = MAC16_16(sum, x_0, y_0)
+ LDR r7, [r4], #4
+ SMLATB r14, r6, r9, r14 @ sum = MAC16_16(sum, x_1, y_1)
+ LDR r8, [r5], #4
+ SMLABT r14, r7, r9, r14 @ sum = MAC16_16(sum, x_2, y_2)
+ SUBS r12, r12, #4 @ j-=4
+ SMLATB r14, r7, r8, r14 @ sum = MAC16_16(sum, x_3, y_3)
+ LDRGT r6, [r4], #4
+ BGT celt_pitch_xcorr_edsp_process1u_loop4
+ MOV r8, r8, LSR #16
+celt_pitch_xcorr_edsp_process1u_loop4_done:
+ ADDS r12, r12, #4
+celt_pitch_xcorr_edsp_process1u_loop1:
+ LDRHGE r6, [r4], #2
+ @ Stall
+ SMLABBGE r14, r6, r8, r14 @ sum = MAC16_16(sum, *x, *y)
+ SUBSGE r12, r12, #1
+ LDRHGT r8, [r5], #2
+ BGT celt_pitch_xcorr_edsp_process1u_loop1
+ @ Restore _x
+ SUB r4, r4, r3, LSL #1
+ @ Restore and advance _y
+ SUB r5, r5, r3, LSL #1
+ @ maxcorr = max(maxcorr, sum)
+ CMP r0, r14
+ ADD r5, r5, #2
+ MOVLT r0, r14
+ SUBS r1, r1, #1
+ @ xcorr[i] = sum
+ STR r14, [r2], #4
+ BLE celt_pitch_xcorr_edsp_done
+celt_pitch_xcorr_edsp_process1u_done:
+ @ if (max_pitch < 4) goto celt_pitch_xcorr_edsp_process2
+ SUBS r1, r1, #4
+ BLT celt_pitch_xcorr_edsp_process2
+celt_pitch_xcorr_edsp_process4:
+ @ xcorr_kernel_edsp parameters:
+ @ r3 = len, r4 = _x, r5 = _y, r6...r9 = sum[4] = {0, 0, 0, 0}
+ MOV r6, #0
+ MOV r7, #0
+ MOV r8, #0
+ MOV r9, #0
+ BL xcorr_kernel_edsp_start @ xcorr_kernel_edsp(_x, _y+i, xcorr+i, len)
+ @ maxcorr = max(maxcorr, sum0, sum1, sum2, sum3)
+ CMP r0, r6
+ @ _y+=4
+ ADD r5, r5, #8
+ MOVLT r0, r6
+ CMP r0, r7
+ MOVLT r0, r7
+ CMP r0, r8
+ MOVLT r0, r8
+ CMP r0, r9
+ MOVLT r0, r9
+ STMIA r2!, {r6-r9}
+ SUBS r1, r1, #4
+ BGE celt_pitch_xcorr_edsp_process4
+celt_pitch_xcorr_edsp_process2:
+ ADDS r1, r1, #2
+ BLT celt_pitch_xcorr_edsp_process1a
+ SUBS r12, r3, #4
+ @ {r10, r11} = {sum0, sum1} = {0, 0}
+ MOV r10, #0
+ MOV r11, #0
+ LDR r8, [r5], #4
+ BLE celt_pitch_xcorr_edsp_process2_loop_done
+ LDR r6, [r4], #4
+ LDR r9, [r5], #4
+celt_pitch_xcorr_edsp_process2_loop4:
+ SMLABB r10, r6, r8, r10 @ sum0 = MAC16_16(sum0, x_0, y_0)
+ LDR r7, [r4], #4
+ SMLABT r11, r6, r8, r11 @ sum1 = MAC16_16(sum1, x_0, y_1)
+ SUBS r12, r12, #4 @ j-=4
+ SMLATT r10, r6, r8, r10 @ sum0 = MAC16_16(sum0, x_1, y_1)
+ LDR r8, [r5], #4
+ SMLATB r11, r6, r9, r11 @ sum1 = MAC16_16(sum1, x_1, y_2)
+ LDRGT r6, [r4], #4
+ SMLABB r10, r7, r9, r10 @ sum0 = MAC16_16(sum0, x_2, y_2)
+ SMLABT r11, r7, r9, r11 @ sum1 = MAC16_16(sum1, x_2, y_3)
+ SMLATT r10, r7, r9, r10 @ sum0 = MAC16_16(sum0, x_3, y_3)
+ LDRGT r9, [r5], #4
+ SMLATB r11, r7, r8, r11 @ sum1 = MAC16_16(sum1, x_3, y_4)
+ BGT celt_pitch_xcorr_edsp_process2_loop4
+celt_pitch_xcorr_edsp_process2_loop_done:
+ ADDS r12, r12, #2
+ BLE celt_pitch_xcorr_edsp_process2_1
+ LDR r6, [r4], #4
+ @ Stall
+ SMLABB r10, r6, r8, r10 @ sum0 = MAC16_16(sum0, x_0, y_0)
+ LDR r9, [r5], #4
+ SMLABT r11, r6, r8, r11 @ sum1 = MAC16_16(sum1, x_0, y_1)
+ SUB r12, r12, #2
+ SMLATT r10, r6, r8, r10 @ sum0 = MAC16_16(sum0, x_1, y_1)
+ MOV r8, r9
+ SMLATB r11, r6, r9, r11 @ sum1 = MAC16_16(sum1, x_1, y_2)
+celt_pitch_xcorr_edsp_process2_1:
+ LDRH r6, [r4], #2
+ ADDS r12, r12, #1
+ @ Stall
+ SMLABB r10, r6, r8, r10 @ sum0 = MAC16_16(sum0, x_0, y_0)
+ LDRHGT r7, [r4], #2
+ SMLABT r11, r6, r8, r11 @ sum1 = MAC16_16(sum1, x_0, y_1)
+ BLE celt_pitch_xcorr_edsp_process2_done
+ LDRH r9, [r5], #2
+ SMLABT r10, r7, r8, r10 @ sum0 = MAC16_16(sum0, x_0, y_1)
+ SMLABB r11, r7, r9, r11 @ sum1 = MAC16_16(sum1, x_0, y_2)
+celt_pitch_xcorr_edsp_process2_done:
+ @ Restore _x
+ SUB r4, r4, r3, LSL #1
+ @ Restore and advance _y
+ SUB r5, r5, r3, LSL #1
+ @ maxcorr = max(maxcorr, sum0)
+ CMP r0, r10
+ ADD r5, r5, #2
+ MOVLT r0, r10
+ SUB r1, r1, #2
+ @ maxcorr = max(maxcorr, sum1)
+ CMP r0, r11
+ @ xcorr[i] = sum
+ STR r10, [r2], #4
+ MOVLT r0, r11
+ STR r11, [r2], #4
+celt_pitch_xcorr_edsp_process1a:
+ ADDS r1, r1, #1
+ BLT celt_pitch_xcorr_edsp_done
+ SUBS r12, r3, #4
+ @ r14 = sum = 0
+ MOV r14, #0
+ BLT celt_pitch_xcorr_edsp_process1a_loop_done
+ LDR r6, [r4], #4
+ LDR r8, [r5], #4
+ LDR r7, [r4], #4
+ LDR r9, [r5], #4
+celt_pitch_xcorr_edsp_process1a_loop4:
+ SMLABB r14, r6, r8, r14 @ sum = MAC16_16(sum, x_0, y_0)
+ SUBS r12, r12, #4 @ j-=4
+ SMLATT r14, r6, r8, r14 @ sum = MAC16_16(sum, x_1, y_1)
+ LDRGE r6, [r4], #4
+ SMLABB r14, r7, r9, r14 @ sum = MAC16_16(sum, x_2, y_2)
+ LDRGE r8, [r5], #4
+ SMLATT r14, r7, r9, r14 @ sum = MAC16_16(sum, x_3, y_3)
+ LDRGE r7, [r4], #4
+ LDRGE r9, [r5], #4
+ BGE celt_pitch_xcorr_edsp_process1a_loop4
+celt_pitch_xcorr_edsp_process1a_loop_done:
+ ADDS r12, r12, #2
+ LDRGE r6, [r4], #4
+ LDRGE r8, [r5], #4
+ @ Stall
+ SMLABBGE r14, r6, r8, r14 @ sum = MAC16_16(sum, x_0, y_0)
+ SUBGE r12, r12, #2
+ SMLATTGE r14, r6, r8, r14 @ sum = MAC16_16(sum, x_1, y_1)
+ ADDS r12, r12, #1
+ LDRHGE r6, [r4], #2
+ LDRHGE r8, [r5], #2
+ @ Stall
+ SMLABBGE r14, r6, r8, r14 @ sum = MAC16_16(sum, *x, *y)
+ @ maxcorr = max(maxcorr, sum)
+ CMP r0, r14
+ @ xcorr[i] = sum
+ STR r14, [r2], #4
+ MOVLT r0, r14
+celt_pitch_xcorr_edsp_done:
+ LDMFD sp!, {r4-r11, pc}
+ .size celt_pitch_xcorr_edsp, .-celt_pitch_xcorr_edsp @ ENDP
+
+ .endif
+
+@ END:
+ .section .note.GNU-stack,"",%progbits
diff --git a/external/opus-1.1.4/celt/arm/celt_pitch_xcorr_arm.s b/external/opus-1.1.4/celt/arm/celt_pitch_xcorr_arm.s
new file mode 100644
index 0000000..f96e0a8
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/celt_pitch_xcorr_arm.s
@@ -0,0 +1,547 @@
+; Copyright (c) 2007-2008 CSIRO
+; Copyright (c) 2007-2009 Xiph.Org Foundation
+; Copyright (c) 2013 Parrot
+; Written by Aurélien Zanelli
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+;
+; - Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+;
+; - Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in the
+; documentation and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; ``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 COPYRIGHT OWNER
+; OR CONTRIBUTORS 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.
+
+ AREA |.text|, CODE, READONLY
+
+ GET celt/arm/armopts.s
+
+IF OPUS_ARM_MAY_HAVE_EDSP
+ EXPORT celt_pitch_xcorr_edsp
+ENDIF
+
+IF OPUS_ARM_MAY_HAVE_NEON
+ EXPORT celt_pitch_xcorr_neon
+ENDIF
+
+IF OPUS_ARM_MAY_HAVE_NEON
+
+; Compute sum[k]=sum(x[j]*y[j+k],j=0...len-1), k=0...3
+xcorr_kernel_neon PROC
+xcorr_kernel_neon_start
+ ; input:
+ ; r3 = int len
+ ; r4 = opus_val16 *x
+ ; r5 = opus_val16 *y
+ ; q0 = opus_val32 sum[4]
+ ; output:
+ ; q0 = opus_val32 sum[4]
+ ; preserved: r0-r3, r6-r11, d2, q4-q7, q9-q15
+ ; internal usage:
+ ; r12 = int j
+ ; d3 = y_3|y_2|y_1|y_0
+ ; q2 = y_B|y_A|y_9|y_8|y_7|y_6|y_5|y_4
+ ; q3 = x_7|x_6|x_5|x_4|x_3|x_2|x_1|x_0
+ ; q8 = scratch
+ ;
+ ; Load y[0...3]
+ ; This requires len>0 to always be valid (which we assert in the C code).
+ VLD1.16 {d5}, [r5]!
+ SUBS r12, r3, #8
+ BLE xcorr_kernel_neon_process4
+; Process 8 samples at a time.
+; This loop loads one y value more than we actually need. Therefore we have to
+; stop as soon as there are 8 or fewer samples left (instead of 7), to avoid
+; reading past the end of the array.
+xcorr_kernel_neon_process8
+ ; This loop has 19 total instructions (10 cycles to issue, minimum), with
+ ; - 2 cycles of ARM insrtuctions,
+ ; - 10 cycles of load/store/byte permute instructions, and
+ ; - 9 cycles of data processing instructions.
+ ; On a Cortex A8, we dual-issue the maximum amount (9 cycles) between the
+ ; latter two categories, meaning the whole loop should run in 10 cycles per
+ ; iteration, barring cache misses.
+ ;
+ ; Load x[0...7]
+ VLD1.16 {d6, d7}, [r4]!
+ ; Unlike VMOV, VAND is a data processsing instruction (and doesn't get
+ ; assembled to VMOV, like VORR would), so it dual-issues with the prior VLD1.
+ VAND d3, d5, d5
+ SUBS r12, r12, #8
+ ; Load y[4...11]
+ VLD1.16 {d4, d5}, [r5]!
+ VMLAL.S16 q0, d3, d6[0]
+ VEXT.16 d16, d3, d4, #1
+ VMLAL.S16 q0, d4, d7[0]
+ VEXT.16 d17, d4, d5, #1
+ VMLAL.S16 q0, d16, d6[1]
+ VEXT.16 d16, d3, d4, #2
+ VMLAL.S16 q0, d17, d7[1]
+ VEXT.16 d17, d4, d5, #2
+ VMLAL.S16 q0, d16, d6[2]
+ VEXT.16 d16, d3, d4, #3
+ VMLAL.S16 q0, d17, d7[2]
+ VEXT.16 d17, d4, d5, #3
+ VMLAL.S16 q0, d16, d6[3]
+ VMLAL.S16 q0, d17, d7[3]
+ BGT xcorr_kernel_neon_process8
+; Process 4 samples here if we have > 4 left (still reading one extra y value).
+xcorr_kernel_neon_process4
+ ADDS r12, r12, #4
+ BLE xcorr_kernel_neon_process2
+ ; Load x[0...3]
+ VLD1.16 d6, [r4]!
+ ; Use VAND since it's a data processing instruction again.
+ VAND d4, d5, d5
+ SUB r12, r12, #4
+ ; Load y[4...7]
+ VLD1.16 d5, [r5]!
+ VMLAL.S16 q0, d4, d6[0]
+ VEXT.16 d16, d4, d5, #1
+ VMLAL.S16 q0, d16, d6[1]
+ VEXT.16 d16, d4, d5, #2
+ VMLAL.S16 q0, d16, d6[2]
+ VEXT.16 d16, d4, d5, #3
+ VMLAL.S16 q0, d16, d6[3]
+; Process 2 samples here if we have > 2 left (still reading one extra y value).
+xcorr_kernel_neon_process2
+ ADDS r12, r12, #2
+ BLE xcorr_kernel_neon_process1
+ ; Load x[0...1]
+ VLD2.16 {d6[],d7[]}, [r4]!
+ ; Use VAND since it's a data processing instruction again.
+ VAND d4, d5, d5
+ SUB r12, r12, #2
+ ; Load y[4...5]
+ VLD1.32 {d5[]}, [r5]!
+ VMLAL.S16 q0, d4, d6
+ VEXT.16 d16, d4, d5, #1
+ ; Replace bottom copy of {y5,y4} in d5 with {y3,y2} from d4, using VSRI
+ ; instead of VEXT, since it's a data-processing instruction.
+ VSRI.64 d5, d4, #32
+ VMLAL.S16 q0, d16, d7
+; Process 1 sample using the extra y value we loaded above.
+xcorr_kernel_neon_process1
+ ; Load next *x
+ VLD1.16 {d6[]}, [r4]!
+ ADDS r12, r12, #1
+ ; y[0...3] are left in d5 from prior iteration(s) (if any)
+ VMLAL.S16 q0, d5, d6
+ MOVLE pc, lr
+; Now process 1 last sample, not reading ahead.
+ ; Load last *y
+ VLD1.16 {d4[]}, [r5]!
+ VSRI.64 d4, d5, #16
+ ; Load last *x
+ VLD1.16 {d6[]}, [r4]!
+ VMLAL.S16 q0, d4, d6
+ MOV pc, lr
+ ENDP
+
+; opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y,
+; opus_val32 *xcorr, int len, int max_pitch)
+celt_pitch_xcorr_neon PROC
+ ; input:
+ ; r0 = opus_val16 *_x
+ ; r1 = opus_val16 *_y
+ ; r2 = opus_val32 *xcorr
+ ; r3 = int len
+ ; output:
+ ; r0 = int maxcorr
+ ; internal usage:
+ ; r4 = opus_val16 *x (for xcorr_kernel_neon())
+ ; r5 = opus_val16 *y (for xcorr_kernel_neon())
+ ; r6 = int max_pitch
+ ; r12 = int j
+ ; q15 = int maxcorr[4] (q15 is not used by xcorr_kernel_neon())
+ STMFD sp!, {r4-r6, lr}
+ LDR r6, [sp, #16]
+ VMOV.S32 q15, #1
+ ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
+ SUBS r6, r6, #4
+ BLT celt_pitch_xcorr_neon_process4_done
+celt_pitch_xcorr_neon_process4
+ ; xcorr_kernel_neon parameters:
+ ; r3 = len, r4 = _x, r5 = _y, q0 = {0, 0, 0, 0}
+ MOV r4, r0
+ MOV r5, r1
+ VEOR q0, q0, q0
+ ; xcorr_kernel_neon only modifies r4, r5, r12, and q0...q3.
+ ; So we don't save/restore any other registers.
+ BL xcorr_kernel_neon_start
+ SUBS r6, r6, #4
+ VST1.32 {q0}, [r2]!
+ ; _y += 4
+ ADD r1, r1, #8
+ VMAX.S32 q15, q15, q0
+ ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
+ BGE celt_pitch_xcorr_neon_process4
+; We have less than 4 sums left to compute.
+celt_pitch_xcorr_neon_process4_done
+ ADDS r6, r6, #4
+ ; Reduce maxcorr to a single value
+ VMAX.S32 d30, d30, d31
+ VPMAX.S32 d30, d30, d30
+ ; if (max_pitch <= 0) goto celt_pitch_xcorr_neon_done
+ BLE celt_pitch_xcorr_neon_done
+; Now compute each remaining sum one at a time.
+celt_pitch_xcorr_neon_process_remaining
+ MOV r4, r0
+ MOV r5, r1
+ VMOV.I32 q0, #0
+ SUBS r12, r3, #8
+ BLT celt_pitch_xcorr_neon_process_remaining4
+; Sum terms 8 at a time.
+celt_pitch_xcorr_neon_process_remaining_loop8
+ ; Load x[0...7]
+ VLD1.16 {q1}, [r4]!
+ ; Load y[0...7]
+ VLD1.16 {q2}, [r5]!
+ SUBS r12, r12, #8
+ VMLAL.S16 q0, d4, d2
+ VMLAL.S16 q0, d5, d3
+ BGE celt_pitch_xcorr_neon_process_remaining_loop8
+; Sum terms 4 at a time.
+celt_pitch_xcorr_neon_process_remaining4
+ ADDS r12, r12, #4
+ BLT celt_pitch_xcorr_neon_process_remaining4_done
+ ; Load x[0...3]
+ VLD1.16 {d2}, [r4]!
+ ; Load y[0...3]
+ VLD1.16 {d3}, [r5]!
+ SUB r12, r12, #4
+ VMLAL.S16 q0, d3, d2
+celt_pitch_xcorr_neon_process_remaining4_done
+ ; Reduce the sum to a single value.
+ VADD.S32 d0, d0, d1
+ VPADDL.S32 d0, d0
+ ADDS r12, r12, #4
+ BLE celt_pitch_xcorr_neon_process_remaining_loop_done
+; Sum terms 1 at a time.
+celt_pitch_xcorr_neon_process_remaining_loop1
+ VLD1.16 {d2[]}, [r4]!
+ VLD1.16 {d3[]}, [r5]!
+ SUBS r12, r12, #1
+ VMLAL.S16 q0, d2, d3
+ BGT celt_pitch_xcorr_neon_process_remaining_loop1
+celt_pitch_xcorr_neon_process_remaining_loop_done
+ VST1.32 {d0[0]}, [r2]!
+ VMAX.S32 d30, d30, d0
+ SUBS r6, r6, #1
+ ; _y++
+ ADD r1, r1, #2
+ ; if (--max_pitch > 0) goto celt_pitch_xcorr_neon_process_remaining
+ BGT celt_pitch_xcorr_neon_process_remaining
+celt_pitch_xcorr_neon_done
+ VMOV.32 r0, d30[0]
+ LDMFD sp!, {r4-r6, pc}
+ ENDP
+
+ENDIF
+
+IF OPUS_ARM_MAY_HAVE_EDSP
+
+; This will get used on ARMv7 devices without NEON, so it has been optimized
+; to take advantage of dual-issuing where possible.
+xcorr_kernel_edsp PROC
+xcorr_kernel_edsp_start
+ ; input:
+ ; r3 = int len
+ ; r4 = opus_val16 *_x (must be 32-bit aligned)
+ ; r5 = opus_val16 *_y (must be 32-bit aligned)
+ ; r6...r9 = opus_val32 sum[4]
+ ; output:
+ ; r6...r9 = opus_val32 sum[4]
+ ; preserved: r0-r5
+ ; internal usage
+ ; r2 = int j
+ ; r12,r14 = opus_val16 x[4]
+ ; r10,r11 = opus_val16 y[4]
+ STMFD sp!, {r2,r4,r5,lr}
+ LDR r10, [r5], #4 ; Load y[0...1]
+ SUBS r2, r3, #4 ; j = len-4
+ LDR r11, [r5], #4 ; Load y[2...3]
+ BLE xcorr_kernel_edsp_process4_done
+ LDR r12, [r4], #4 ; Load x[0...1]
+ ; Stall
+xcorr_kernel_edsp_process4
+ ; The multiplies must issue from pipeline 0, and can't dual-issue with each
+ ; other. Every other instruction here dual-issues with a multiply, and is
+ ; thus "free". There should be no stalls in the body of the loop.
+ SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_0,y_0)
+ LDR r14, [r4], #4 ; Load x[2...3]
+ SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x_0,y_1)
+ SUBS r2, r2, #4 ; j-=4
+ SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_0,y_2)
+ SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x_0,y_3)
+ SMLATT r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_1,y_1)
+ LDR r10, [r5], #4 ; Load y[4...5]
+ SMLATB r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],x_1,y_2)
+ SMLATT r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_1,y_3)
+ SMLATB r9, r12, r10, r9 ; sum[3] = MAC16_16(sum[3],x_1,y_4)
+ LDRGT r12, [r4], #4 ; Load x[0...1]
+ SMLABB r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_2,y_2)
+ SMLABT r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x_2,y_3)
+ SMLABB r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_2,y_4)
+ SMLABT r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x_2,y_5)
+ SMLATT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_3,y_3)
+ LDR r11, [r5], #4 ; Load y[6...7]
+ SMLATB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],x_3,y_4)
+ SMLATT r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_3,y_5)
+ SMLATB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],x_3,y_6)
+ BGT xcorr_kernel_edsp_process4
+xcorr_kernel_edsp_process4_done
+ ADDS r2, r2, #4
+ BLE xcorr_kernel_edsp_done
+ LDRH r12, [r4], #2 ; r12 = *x++
+ SUBS r2, r2, #1 ; j--
+ ; Stall
+ SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_0)
+ LDRHGT r14, [r4], #2 ; r14 = *x++
+ SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x,y_1)
+ SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_2)
+ SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x,y_3)
+ BLE xcorr_kernel_edsp_done
+ SMLABT r6, r14, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_1)
+ SUBS r2, r2, #1 ; j--
+ SMLABB r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x,y_2)
+ LDRH r10, [r5], #2 ; r10 = y_4 = *y++
+ SMLABT r8, r14, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_3)
+ LDRHGT r12, [r4], #2 ; r12 = *x++
+ SMLABB r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x,y_4)
+ BLE xcorr_kernel_edsp_done
+ SMLABB r6, r12, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_2)
+ CMP r2, #1 ; j--
+ SMLABT r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_3)
+ LDRH r2, [r5], #2 ; r2 = y_5 = *y++
+ SMLABB r8, r12, r10, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_4)
+ LDRHGT r14, [r4] ; r14 = *x
+ SMLABB r9, r12, r2, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_5)
+ BLE xcorr_kernel_edsp_done
+ SMLABT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_3)
+ LDRH r11, [r5] ; r11 = y_6 = *y
+ SMLABB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_4)
+ SMLABB r8, r14, r2, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_5)
+ SMLABB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_6)
+xcorr_kernel_edsp_done
+ LDMFD sp!, {r2,r4,r5,pc}
+ ENDP
+
+celt_pitch_xcorr_edsp PROC
+ ; input:
+ ; r0 = opus_val16 *_x (must be 32-bit aligned)
+ ; r1 = opus_val16 *_y (only needs to be 16-bit aligned)
+ ; r2 = opus_val32 *xcorr
+ ; r3 = int len
+ ; output:
+ ; r0 = maxcorr
+ ; internal usage
+ ; r4 = opus_val16 *x
+ ; r5 = opus_val16 *y
+ ; r6 = opus_val32 sum0
+ ; r7 = opus_val32 sum1
+ ; r8 = opus_val32 sum2
+ ; r9 = opus_val32 sum3
+ ; r1 = int max_pitch
+ ; r12 = int j
+ STMFD sp!, {r4-r11, lr}
+ MOV r5, r1
+ LDR r1, [sp, #36]
+ MOV r4, r0
+ TST r5, #3
+ ; maxcorr = 1
+ MOV r0, #1
+ BEQ celt_pitch_xcorr_edsp_process1u_done
+; Compute one sum at the start to make y 32-bit aligned.
+ SUBS r12, r3, #4
+ ; r14 = sum = 0
+ MOV r14, #0
+ LDRH r8, [r5], #2
+ BLE celt_pitch_xcorr_edsp_process1u_loop4_done
+ LDR r6, [r4], #4
+ MOV r8, r8, LSL #16
+celt_pitch_xcorr_edsp_process1u_loop4
+ LDR r9, [r5], #4
+ SMLABT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0)
+ LDR r7, [r4], #4
+ SMLATB r14, r6, r9, r14 ; sum = MAC16_16(sum, x_1, y_1)
+ LDR r8, [r5], #4
+ SMLABT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2)
+ SUBS r12, r12, #4 ; j-=4
+ SMLATB r14, r7, r8, r14 ; sum = MAC16_16(sum, x_3, y_3)
+ LDRGT r6, [r4], #4
+ BGT celt_pitch_xcorr_edsp_process1u_loop4
+ MOV r8, r8, LSR #16
+celt_pitch_xcorr_edsp_process1u_loop4_done
+ ADDS r12, r12, #4
+celt_pitch_xcorr_edsp_process1u_loop1
+ LDRHGE r6, [r4], #2
+ ; Stall
+ SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y)
+ SUBSGE r12, r12, #1
+ LDRHGT r8, [r5], #2
+ BGT celt_pitch_xcorr_edsp_process1u_loop1
+ ; Restore _x
+ SUB r4, r4, r3, LSL #1
+ ; Restore and advance _y
+ SUB r5, r5, r3, LSL #1
+ ; maxcorr = max(maxcorr, sum)
+ CMP r0, r14
+ ADD r5, r5, #2
+ MOVLT r0, r14
+ SUBS r1, r1, #1
+ ; xcorr[i] = sum
+ STR r14, [r2], #4
+ BLE celt_pitch_xcorr_edsp_done
+celt_pitch_xcorr_edsp_process1u_done
+ ; if (max_pitch < 4) goto celt_pitch_xcorr_edsp_process2
+ SUBS r1, r1, #4
+ BLT celt_pitch_xcorr_edsp_process2
+celt_pitch_xcorr_edsp_process4
+ ; xcorr_kernel_edsp parameters:
+ ; r3 = len, r4 = _x, r5 = _y, r6...r9 = sum[4] = {0, 0, 0, 0}
+ MOV r6, #0
+ MOV r7, #0
+ MOV r8, #0
+ MOV r9, #0
+ BL xcorr_kernel_edsp_start ; xcorr_kernel_edsp(_x, _y+i, xcorr+i, len)
+ ; maxcorr = max(maxcorr, sum0, sum1, sum2, sum3)
+ CMP r0, r6
+ ; _y+=4
+ ADD r5, r5, #8
+ MOVLT r0, r6
+ CMP r0, r7
+ MOVLT r0, r7
+ CMP r0, r8
+ MOVLT r0, r8
+ CMP r0, r9
+ MOVLT r0, r9
+ STMIA r2!, {r6-r9}
+ SUBS r1, r1, #4
+ BGE celt_pitch_xcorr_edsp_process4
+celt_pitch_xcorr_edsp_process2
+ ADDS r1, r1, #2
+ BLT celt_pitch_xcorr_edsp_process1a
+ SUBS r12, r3, #4
+ ; {r10, r11} = {sum0, sum1} = {0, 0}
+ MOV r10, #0
+ MOV r11, #0
+ LDR r8, [r5], #4
+ BLE celt_pitch_xcorr_edsp_process2_loop_done
+ LDR r6, [r4], #4
+ LDR r9, [r5], #4
+celt_pitch_xcorr_edsp_process2_loop4
+ SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0)
+ LDR r7, [r4], #4
+ SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1)
+ SUBS r12, r12, #4 ; j-=4
+ SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1)
+ LDR r8, [r5], #4
+ SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2)
+ LDRGT r6, [r4], #4
+ SMLABB r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_2, y_2)
+ SMLABT r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_2, y_3)
+ SMLATT r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_3, y_3)
+ LDRGT r9, [r5], #4
+ SMLATB r11, r7, r8, r11 ; sum1 = MAC16_16(sum1, x_3, y_4)
+ BGT celt_pitch_xcorr_edsp_process2_loop4
+celt_pitch_xcorr_edsp_process2_loop_done
+ ADDS r12, r12, #2
+ BLE celt_pitch_xcorr_edsp_process2_1
+ LDR r6, [r4], #4
+ ; Stall
+ SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0)
+ LDR r9, [r5], #4
+ SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1)
+ SUB r12, r12, #2
+ SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1)
+ MOV r8, r9
+ SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2)
+celt_pitch_xcorr_edsp_process2_1
+ LDRH r6, [r4], #2
+ ADDS r12, r12, #1
+ ; Stall
+ SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0)
+ LDRHGT r7, [r4], #2
+ SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1)
+ BLE celt_pitch_xcorr_edsp_process2_done
+ LDRH r9, [r5], #2
+ SMLABT r10, r7, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_1)
+ SMLABB r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_0, y_2)
+celt_pitch_xcorr_edsp_process2_done
+ ; Restore _x
+ SUB r4, r4, r3, LSL #1
+ ; Restore and advance _y
+ SUB r5, r5, r3, LSL #1
+ ; maxcorr = max(maxcorr, sum0)
+ CMP r0, r10
+ ADD r5, r5, #2
+ MOVLT r0, r10
+ SUB r1, r1, #2
+ ; maxcorr = max(maxcorr, sum1)
+ CMP r0, r11
+ ; xcorr[i] = sum
+ STR r10, [r2], #4
+ MOVLT r0, r11
+ STR r11, [r2], #4
+celt_pitch_xcorr_edsp_process1a
+ ADDS r1, r1, #1
+ BLT celt_pitch_xcorr_edsp_done
+ SUBS r12, r3, #4
+ ; r14 = sum = 0
+ MOV r14, #0
+ BLT celt_pitch_xcorr_edsp_process1a_loop_done
+ LDR r6, [r4], #4
+ LDR r8, [r5], #4
+ LDR r7, [r4], #4
+ LDR r9, [r5], #4
+celt_pitch_xcorr_edsp_process1a_loop4
+ SMLABB r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0)
+ SUBS r12, r12, #4 ; j-=4
+ SMLATT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1)
+ LDRGE r6, [r4], #4
+ SMLABB r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2)
+ LDRGE r8, [r5], #4
+ SMLATT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_3, y_3)
+ LDRGE r7, [r4], #4
+ LDRGE r9, [r5], #4
+ BGE celt_pitch_xcorr_edsp_process1a_loop4
+celt_pitch_xcorr_edsp_process1a_loop_done
+ ADDS r12, r12, #2
+ LDRGE r6, [r4], #4
+ LDRGE r8, [r5], #4
+ ; Stall
+ SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0)
+ SUBGE r12, r12, #2
+ SMLATTGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1)
+ ADDS r12, r12, #1
+ LDRHGE r6, [r4], #2
+ LDRHGE r8, [r5], #2
+ ; Stall
+ SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y)
+ ; maxcorr = max(maxcorr, sum)
+ CMP r0, r14
+ ; xcorr[i] = sum
+ STR r14, [r2], #4
+ MOVLT r0, r14
+celt_pitch_xcorr_edsp_done
+ LDMFD sp!, {r4-r11, pc}
+ ENDP
+
+ENDIF
+
+END
diff --git a/external/opus-1.1.4/celt/arm/fft_arm.h b/external/opus-1.1.4/celt/arm/fft_arm.h
new file mode 100644
index 0000000..0cb55d8
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/fft_arm.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2015 Xiph.Org Foundation
+ Written by Viswanath Puttagunta */
+/**
+ @file fft_arm.h
+ @brief ARM Neon Intrinsic optimizations for fft using NE10 library
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+
+#if !defined(FFT_ARM_H)
+#define FFT_ARM_H
+
+#include "config.h"
+#include "kiss_fft.h"
+
+#if defined(HAVE_ARM_NE10)
+
+int opus_fft_alloc_arm_neon(kiss_fft_state *st);
+void opus_fft_free_arm_neon(kiss_fft_state *st);
+
+void opus_fft_neon(const kiss_fft_state *st,
+ const kiss_fft_cpx *fin,
+ kiss_fft_cpx *fout);
+
+void opus_ifft_neon(const kiss_fft_state *st,
+ const kiss_fft_cpx *fin,
+ kiss_fft_cpx *fout);
+
+#if !defined(OPUS_HAVE_RTCD)
+#define OVERRIDE_OPUS_FFT (1)
+
+#define opus_fft_alloc_arch(_st, arch) \
+ ((void)(arch), opus_fft_alloc_arm_neon(_st))
+
+#define opus_fft_free_arch(_st, arch) \
+ ((void)(arch), opus_fft_free_arm_neon(_st))
+
+#define opus_fft(_st, _fin, _fout, arch) \
+ ((void)(arch), opus_fft_neon(_st, _fin, _fout))
+
+#define opus_ifft(_st, _fin, _fout, arch) \
+ ((void)(arch), opus_ifft_neon(_st, _fin, _fout))
+
+#endif /* OPUS_HAVE_RTCD */
+
+#endif /* HAVE_ARM_NE10 */
+
+#endif
diff --git a/external/opus-1.1.4/celt/arm/fixed_arm64.h b/external/opus-1.1.4/celt/arm/fixed_arm64.h
new file mode 100644
index 0000000..c6fbd3d
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/fixed_arm64.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2015 Vidyo */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef FIXED_ARM64_H
+#define FIXED_ARM64_H
+
+#include <arm_neon.h>
+
+#undef SIG2WORD16
+#define SIG2WORD16(x) (vqmovns_s32(PSHR32((x), SIG_SHIFT)))
+
+#endif
diff --git a/external/opus-1.1.4/celt/arm/fixed_armv4.h b/external/opus-1.1.4/celt/arm/fixed_armv4.h
new file mode 100644
index 0000000..efb3b18
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/fixed_armv4.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 2013 Xiph.Org Foundation and contributors */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef FIXED_ARMv4_H
+#define FIXED_ARMv4_H
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q16
+static OPUS_INLINE opus_val32 MULT16_32_Q16_armv4(opus_val16 a, opus_val32 b)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#MULT16_32_Q16\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(b),"r"(a<<16)
+ );
+ return rd_hi;
+}
+#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv4(a, b))
+
+
+/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q15
+static OPUS_INLINE opus_val32 MULT16_32_Q15_armv4(opus_val16 a, opus_val32 b)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#MULT16_32_Q15\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(b), "r"(a<<16)
+ );
+ /*We intentionally don't OR in the high bit of rd_lo for speed.*/
+ return rd_hi<<1;
+}
+#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv4(a, b))
+
+
+/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
+ b must fit in 31 bits.
+ Result fits in 32 bits. */
+#undef MAC16_32_Q15
+#define MAC16_32_Q15(c, a, b) ADD32(c, MULT16_32_Q15(a, b))
+
+/** 16x32 multiply, followed by a 16-bit shift right and 32-bit add.
+ Result fits in 32 bits. */
+#undef MAC16_32_Q16
+#define MAC16_32_Q16(c, a, b) ADD32(c, MULT16_32_Q16(a, b))
+
+/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */
+#undef MULT32_32_Q31
+#define MULT32_32_Q31(a,b) (opus_val32)((((opus_int64)(a)) * ((opus_int64)(b)))>>31)
+
+#endif
diff --git a/external/opus-1.1.4/celt/arm/fixed_armv5e.h b/external/opus-1.1.4/celt/arm/fixed_armv5e.h
new file mode 100644
index 0000000..36a6321
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/fixed_armv5e.h
@@ -0,0 +1,151 @@
+/* Copyright (C) 2007-2009 Xiph.Org Foundation
+ Copyright (C) 2003-2008 Jean-Marc Valin
+ Copyright (C) 2007-2008 CSIRO
+ Copyright (C) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef FIXED_ARMv5E_H
+#define FIXED_ARMv5E_H
+
+#include "fixed_armv4.h"
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q16
+static OPUS_INLINE opus_val32 MULT16_32_Q16_armv5e(opus_val16 a, opus_val32 b)
+{
+ int res;
+ __asm__(
+ "#MULT16_32_Q16\n\t"
+ "smulwb %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(b),"r"(a)
+ );
+ return res;
+}
+#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv5e(a, b))
+
+
+/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q15
+static OPUS_INLINE opus_val32 MULT16_32_Q15_armv5e(opus_val16 a, opus_val32 b)
+{
+ int res;
+ __asm__(
+ "#MULT16_32_Q15\n\t"
+ "smulwb %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(b), "r"(a)
+ );
+ return res<<1;
+}
+#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv5e(a, b))
+
+
+/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
+ b must fit in 31 bits.
+ Result fits in 32 bits. */
+#undef MAC16_32_Q15
+static OPUS_INLINE opus_val32 MAC16_32_Q15_armv5e(opus_val32 c, opus_val16 a,
+ opus_val32 b)
+{
+ int res;
+ __asm__(
+ "#MAC16_32_Q15\n\t"
+ "smlawb %0, %1, %2, %3;\n"
+ : "=r"(res)
+ : "r"(b<<1), "r"(a), "r"(c)
+ );
+ return res;
+}
+#define MAC16_32_Q15(c, a, b) (MAC16_32_Q15_armv5e(c, a, b))
+
+/** 16x32 multiply, followed by a 16-bit shift right and 32-bit add.
+ Result fits in 32 bits. */
+#undef MAC16_32_Q16
+static OPUS_INLINE opus_val32 MAC16_32_Q16_armv5e(opus_val32 c, opus_val16 a,
+ opus_val32 b)
+{
+ int res;
+ __asm__(
+ "#MAC16_32_Q16\n\t"
+ "smlawb %0, %1, %2, %3;\n"
+ : "=r"(res)
+ : "r"(b), "r"(a), "r"(c)
+ );
+ return res;
+}
+#define MAC16_32_Q16(c, a, b) (MAC16_32_Q16_armv5e(c, a, b))
+
+/** 16x16 multiply-add where the result fits in 32 bits */
+#undef MAC16_16
+static OPUS_INLINE opus_val32 MAC16_16_armv5e(opus_val32 c, opus_val16 a,
+ opus_val16 b)
+{
+ int res;
+ __asm__(
+ "#MAC16_16\n\t"
+ "smlabb %0, %1, %2, %3;\n"
+ : "=r"(res)
+ : "r"(a), "r"(b), "r"(c)
+ );
+ return res;
+}
+#define MAC16_16(c, a, b) (MAC16_16_armv5e(c, a, b))
+
+/** 16x16 multiplication where the result fits in 32 bits */
+#undef MULT16_16
+static OPUS_INLINE opus_val32 MULT16_16_armv5e(opus_val16 a, opus_val16 b)
+{
+ int res;
+ __asm__(
+ "#MULT16_16\n\t"
+ "smulbb %0, %1, %2;\n"
+ : "=r"(res)
+ : "r"(a), "r"(b)
+ );
+ return res;
+}
+#define MULT16_16(a, b) (MULT16_16_armv5e(a, b))
+
+#ifdef OPUS_ARM_INLINE_MEDIA
+
+#undef SIG2WORD16
+static OPUS_INLINE opus_val16 SIG2WORD16_armv6(opus_val32 x)
+{
+ celt_sig res;
+ __asm__(
+ "#SIG2WORD16\n\t"
+ "ssat %0, #16, %1, ASR #12\n\t"
+ : "=r"(res)
+ : "r"(x+2048)
+ );
+ return EXTRACT16(res);
+}
+#define SIG2WORD16(x) (SIG2WORD16_armv6(x))
+
+#endif /* OPUS_ARM_INLINE_MEDIA */
+
+#endif
diff --git a/external/opus-1.1.4/celt/arm/kiss_fft_armv4.h b/external/opus-1.1.4/celt/arm/kiss_fft_armv4.h
new file mode 100644
index 0000000..e4faad6
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/kiss_fft_armv4.h
@@ -0,0 +1,121 @@
+/*Copyright (c) 2013, Xiph.Org Foundation and contributors.
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.*/
+
+#ifndef KISS_FFT_ARMv4_H
+#define KISS_FFT_ARMv4_H
+
+#if !defined(KISS_FFT_GUTS_H)
+#error "This file should only be included from _kiss_fft_guts.h"
+#endif
+
+#ifdef FIXED_POINT
+
+#undef C_MUL
+#define C_MUL(m,a,b) \
+ do{ \
+ int br__; \
+ int bi__; \
+ int tt__; \
+ __asm__ __volatile__( \
+ "#C_MUL\n\t" \
+ "ldrsh %[br], [%[bp], #0]\n\t" \
+ "ldm %[ap], {r0,r1}\n\t" \
+ "ldrsh %[bi], [%[bp], #2]\n\t" \
+ "smull %[tt], %[mi], r1, %[br]\n\t" \
+ "smlal %[tt], %[mi], r0, %[bi]\n\t" \
+ "rsb %[bi], %[bi], #0\n\t" \
+ "smull %[br], %[mr], r0, %[br]\n\t" \
+ "mov %[tt], %[tt], lsr #15\n\t" \
+ "smlal %[br], %[mr], r1, %[bi]\n\t" \
+ "orr %[mi], %[tt], %[mi], lsl #17\n\t" \
+ "mov %[br], %[br], lsr #15\n\t" \
+ "orr %[mr], %[br], %[mr], lsl #17\n\t" \
+ : [mr]"=r"((m).r), [mi]"=r"((m).i), \
+ [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
+ : [ap]"r"(&(a)), [bp]"r"(&(b)) \
+ : "r0", "r1" \
+ ); \
+ } \
+ while(0)
+
+#undef C_MUL4
+#define C_MUL4(m,a,b) \
+ do{ \
+ int br__; \
+ int bi__; \
+ int tt__; \
+ __asm__ __volatile__( \
+ "#C_MUL4\n\t" \
+ "ldrsh %[br], [%[bp], #0]\n\t" \
+ "ldm %[ap], {r0,r1}\n\t" \
+ "ldrsh %[bi], [%[bp], #2]\n\t" \
+ "smull %[tt], %[mi], r1, %[br]\n\t" \
+ "smlal %[tt], %[mi], r0, %[bi]\n\t" \
+ "rsb %[bi], %[bi], #0\n\t" \
+ "smull %[br], %[mr], r0, %[br]\n\t" \
+ "mov %[tt], %[tt], lsr #17\n\t" \
+ "smlal %[br], %[mr], r1, %[bi]\n\t" \
+ "orr %[mi], %[tt], %[mi], lsl #15\n\t" \
+ "mov %[br], %[br], lsr #17\n\t" \
+ "orr %[mr], %[br], %[mr], lsl #15\n\t" \
+ : [mr]"=r"((m).r), [mi]"=r"((m).i), \
+ [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
+ : [ap]"r"(&(a)), [bp]"r"(&(b)) \
+ : "r0", "r1" \
+ ); \
+ } \
+ while(0)
+
+#undef C_MULC
+#define C_MULC(m,a,b) \
+ do{ \
+ int br__; \
+ int bi__; \
+ int tt__; \
+ __asm__ __volatile__( \
+ "#C_MULC\n\t" \
+ "ldrsh %[br], [%[bp], #0]\n\t" \
+ "ldm %[ap], {r0,r1}\n\t" \
+ "ldrsh %[bi], [%[bp], #2]\n\t" \
+ "smull %[tt], %[mr], r0, %[br]\n\t" \
+ "smlal %[tt], %[mr], r1, %[bi]\n\t" \
+ "rsb %[bi], %[bi], #0\n\t" \
+ "smull %[br], %[mi], r1, %[br]\n\t" \
+ "mov %[tt], %[tt], lsr #15\n\t" \
+ "smlal %[br], %[mi], r0, %[bi]\n\t" \
+ "orr %[mr], %[tt], %[mr], lsl #17\n\t" \
+ "mov %[br], %[br], lsr #15\n\t" \
+ "orr %[mi], %[br], %[mi], lsl #17\n\t" \
+ : [mr]"=r"((m).r), [mi]"=r"((m).i), \
+ [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
+ : [ap]"r"(&(a)), [bp]"r"(&(b)) \
+ : "r0", "r1" \
+ ); \
+ } \
+ while(0)
+
+#endif /* FIXED_POINT */
+
+#endif /* KISS_FFT_ARMv4_H */
diff --git a/external/opus-1.1.4/celt/arm/kiss_fft_armv5e.h b/external/opus-1.1.4/celt/arm/kiss_fft_armv5e.h
new file mode 100644
index 0000000..9eca183
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/kiss_fft_armv5e.h
@@ -0,0 +1,118 @@
+/*Copyright (c) 2013, Xiph.Org Foundation and contributors.
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.*/
+
+#ifndef KISS_FFT_ARMv5E_H
+#define KISS_FFT_ARMv5E_H
+
+#if !defined(KISS_FFT_GUTS_H)
+#error "This file should only be included from _kiss_fft_guts.h"
+#endif
+
+#ifdef FIXED_POINT
+
+#if defined(__thumb__)||defined(__thumb2__)
+#define LDRD_CONS "Q"
+#else
+#define LDRD_CONS "Uq"
+#endif
+
+#undef C_MUL
+#define C_MUL(m,a,b) \
+ do{ \
+ int mr1__; \
+ int mr2__; \
+ int mi__; \
+ long long aval__; \
+ int bval__; \
+ __asm__( \
+ "#C_MUL\n\t" \
+ "ldrd %[aval], %H[aval], %[ap]\n\t" \
+ "ldr %[bval], %[bp]\n\t" \
+ "smulwb %[mi], %H[aval], %[bval]\n\t" \
+ "smulwb %[mr1], %[aval], %[bval]\n\t" \
+ "smulwt %[mr2], %H[aval], %[bval]\n\t" \
+ "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \
+ : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \
+ [aval]"=&r"(aval__), [bval]"=r"(bval__) \
+ : [ap]LDRD_CONS(a), [bp]"m"(b) \
+ ); \
+ (m).r = SHL32(SUB32(mr1__, mr2__), 1); \
+ (m).i = SHL32(mi__, 1); \
+ } \
+ while(0)
+
+#undef C_MUL4
+#define C_MUL4(m,a,b) \
+ do{ \
+ int mr1__; \
+ int mr2__; \
+ int mi__; \
+ long long aval__; \
+ int bval__; \
+ __asm__( \
+ "#C_MUL4\n\t" \
+ "ldrd %[aval], %H[aval], %[ap]\n\t" \
+ "ldr %[bval], %[bp]\n\t" \
+ "smulwb %[mi], %H[aval], %[bval]\n\t" \
+ "smulwb %[mr1], %[aval], %[bval]\n\t" \
+ "smulwt %[mr2], %H[aval], %[bval]\n\t" \
+ "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \
+ : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \
+ [aval]"=&r"(aval__), [bval]"=r"(bval__) \
+ : [ap]LDRD_CONS(a), [bp]"m"(b) \
+ ); \
+ (m).r = SHR32(SUB32(mr1__, mr2__), 1); \
+ (m).i = SHR32(mi__, 1); \
+ } \
+ while(0)
+
+#undef C_MULC
+#define C_MULC(m,a,b) \
+ do{ \
+ int mr__; \
+ int mi1__; \
+ int mi2__; \
+ long long aval__; \
+ int bval__; \
+ __asm__( \
+ "#C_MULC\n\t" \
+ "ldrd %[aval], %H[aval], %[ap]\n\t" \
+ "ldr %[bval], %[bp]\n\t" \
+ "smulwb %[mr], %[aval], %[bval]\n\t" \
+ "smulwb %[mi1], %H[aval], %[bval]\n\t" \
+ "smulwt %[mi2], %[aval], %[bval]\n\t" \
+ "smlawt %[mr], %H[aval], %[bval], %[mr]\n\t" \
+ : [mr]"=r"(mr__), [mi1]"=r"(mi1__), [mi2]"=r"(mi2__), \
+ [aval]"=&r"(aval__), [bval]"=r"(bval__) \
+ : [ap]LDRD_CONS(a), [bp]"m"(b) \
+ ); \
+ (m).r = SHL32(mr__, 1); \
+ (m).i = SHL32(SUB32(mi1__, mi2__), 1); \
+ } \
+ while(0)
+
+#endif /* FIXED_POINT */
+
+#endif /* KISS_FFT_GUTS_H */
diff --git a/external/opus-1.1.4/celt/arm/mdct_arm.h b/external/opus-1.1.4/celt/arm/mdct_arm.h
new file mode 100644
index 0000000..49cbb44
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/mdct_arm.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2015 Xiph.Org Foundation
+ Written by Viswanath Puttagunta */
+/**
+ @file arm_mdct.h
+ @brief ARM Neon Intrinsic optimizations for mdct using NE10 library
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#if !defined(MDCT_ARM_H)
+#define MDCT_ARM_H
+
+#include "config.h"
+#include "mdct.h"
+
+#if defined(HAVE_ARM_NE10)
+/** Compute a forward MDCT and scale by 4/N, trashes the input array */
+void clt_mdct_forward_neon(const mdct_lookup *l, kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 *window, int overlap,
+ int shift, int stride, int arch);
+
+void clt_mdct_backward_neon(const mdct_lookup *l, kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 *window, int overlap,
+ int shift, int stride, int arch);
+
+#if !defined(OPUS_HAVE_RTCD)
+#define OVERRIDE_OPUS_MDCT (1)
+#define clt_mdct_forward(_l, _in, _out, _window, _int, _shift, _stride, _arch) \
+ clt_mdct_forward_neon(_l, _in, _out, _window, _int, _shift, _stride, _arch)
+#define clt_mdct_backward(_l, _in, _out, _window, _int, _shift, _stride, _arch) \
+ clt_mdct_backward_neon(_l, _in, _out, _window, _int, _shift, _stride, _arch)
+#endif /* OPUS_HAVE_RTCD */
+#endif /* HAVE_ARM_NE10 */
+
+#endif
diff --git a/external/opus-1.1.4/celt/arm/pitch_arm.h b/external/opus-1.1.4/celt/arm/pitch_arm.h
new file mode 100644
index 0000000..1433116
--- /dev/null
+++ b/external/opus-1.1.4/celt/arm/pitch_arm.h
@@ -0,0 +1,126 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#if !defined(PITCH_ARM_H)
+# define PITCH_ARM_H
+
+# include "armcpu.h"
+
+# if defined(FIXED_POINT)
+
+# if defined(OPUS_ARM_MAY_HAVE_NEON)
+opus_val32 celt_pitch_xcorr_neon(const opus_val16 *_x, const opus_val16 *_y,
+ opus_val32 *xcorr, int len, int max_pitch);
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
+# define celt_pitch_xcorr_media MAY_HAVE_EDSP(celt_pitch_xcorr)
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_EDSP)
+opus_val32 celt_pitch_xcorr_edsp(const opus_val16 *_x, const opus_val16 *_y,
+ opus_val32 *xcorr, int len, int max_pitch);
+# endif
+
+# if defined(OPUS_HAVE_RTCD) && \
+ ((defined(OPUS_ARM_MAY_HAVE_NEON) && !defined(OPUS_ARM_PRESUME_NEON)) || \
+ (defined(OPUS_ARM_MAY_HAVE_MEDIA) && !defined(OPUS_ARM_PRESUME_MEDIA)) || \
+ (defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP)))
+extern opus_val32
+(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
+ const opus_val16 *, opus_val32 *, int, int);
+# define OVERRIDE_PITCH_XCORR (1)
+# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
+ ((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \
+ xcorr, len, max_pitch))
+
+# elif defined(OPUS_ARM_PRESUME_EDSP) || \
+ defined(OPUS_ARM_PRESUME_MEDIA) || \
+ defined(OPUS_ARM_PRESUME_NEON)
+# define OVERRIDE_PITCH_XCORR (1)
+# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
+ ((void)(arch),PRESUME_NEON(celt_pitch_xcorr)(_x, _y, xcorr, len, max_pitch))
+
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+void xcorr_kernel_neon_fixed(
+ const opus_val16 *x,
+ const opus_val16 *y,
+ opus_val32 sum[4],
+ int len);
+# endif
+
+# if defined(OPUS_HAVE_RTCD) && \
+ (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
+
+extern void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *y,
+ opus_val32 sum[4],
+ int len);
+
+# define OVERRIDE_XCORR_KERNEL (1)
+# define xcorr_kernel(x, y, sum, len, arch) \
+ ((*XCORR_KERNEL_IMPL[(arch) & OPUS_ARCHMASK])(x, y, sum, len))
+
+# elif defined(OPUS_ARM_PRESUME_NEON_INTR)
+# define OVERRIDE_XCORR_KERNEL (1)
+# define xcorr_kernel(x, y, sum, len, arch) \
+ ((void)arch, xcorr_kernel_neon_fixed(x, y, sum, len))
+
+# endif
+
+#else /* Start !FIXED_POINT */
+/* Float case */
+#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y,
+ opus_val32 *xcorr, int len, int max_pitch);
+#endif
+
+# if defined(OPUS_HAVE_RTCD) && \
+ (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
+extern void
+(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
+ const opus_val16 *, opus_val32 *, int, int);
+
+# define OVERRIDE_PITCH_XCORR (1)
+# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
+ ((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \
+ xcorr, len, max_pitch))
+
+# elif defined(OPUS_ARM_PRESUME_NEON_INTR)
+
+# define OVERRIDE_PITCH_XCORR (1)
+# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
+ ((void)(arch),celt_pitch_xcorr_float_neon(_x, _y, xcorr, len, max_pitch))
+
+# endif
+
+#endif /* end !FIXED_POINT */
+
+#endif
diff --git a/external/opus-1.1.4/celt/bands.c b/external/opus-1.1.4/celt/bands.c
new file mode 100644
index 0000000..87eaa6c
--- /dev/null
+++ b/external/opus-1.1.4/celt/bands.c
@@ -0,0 +1,1529 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008-2009 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include "bands.h"
+#include "modes.h"
+#include "vq.h"
+#include "cwrs.h"
+#include "stack_alloc.h"
+#include "os_support.h"
+#include "mathops.h"
+#include "rate.h"
+#include "quant_bands.h"
+#include "pitch.h"
+
+int hysteresis_decision(opus_val16 val, const opus_val16 *thresholds, const opus_val16 *hysteresis, int N, int prev)
+{
+ int i;
+ for (i=0;i<N;i++)
+ {
+ if (val < thresholds[i])
+ break;
+ }
+ if (i>prev && val < thresholds[prev]+hysteresis[prev])
+ i=prev;
+ if (i<prev && val > thresholds[prev-1]-hysteresis[prev-1])
+ i=prev;
+ return i;
+}
+
+opus_uint32 celt_lcg_rand(opus_uint32 seed)
+{
+ return 1664525 * seed + 1013904223;
+}
+
+/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness
+ with this approximation is important because it has an impact on the bit allocation */
+static opus_int16 bitexact_cos(opus_int16 x)
+{
+ opus_int32 tmp;
+ opus_int16 x2;
+ tmp = (4096+((opus_int32)(x)*(x)))>>13;
+ celt_assert(tmp<=32767);
+ x2 = tmp;
+ x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2)))));
+ celt_assert(x2<=32766);
+ return 1+x2;
+}
+
+static int bitexact_log2tan(int isin,int icos)
+{
+ int lc;
+ int ls;
+ lc=EC_ILOG(icos);
+ ls=EC_ILOG(isin);
+ icos<<=15-lc;
+ isin<<=15-ls;
+ return (ls-lc)*(1<<11)
+ +FRAC_MUL16(isin, FRAC_MUL16(isin, -2597) + 7932)
+ -FRAC_MUL16(icos, FRAC_MUL16(icos, -2597) + 7932);
+}
+
+#ifdef FIXED_POINT
+/* Compute the amplitude (sqrt energy) in each of the bands */
+void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM)
+{
+ int i, c, N;
+ const opus_int16 *eBands = m->eBands;
+ N = m->shortMdctSize<<LM;
+ c=0; do {
+ for (i=0;i<end;i++)
+ {
+ int j;
+ opus_val32 maxval=0;
+ opus_val32 sum = 0;
+
+ maxval = celt_maxabs32(&X[c*N+(eBands[i]<<LM)], (eBands[i+1]-eBands[i])<<LM);
+ if (maxval > 0)
+ {
+ int shift = celt_ilog2(maxval) - 14 + (((m->logN[i]>>BITRES)+LM+1)>>1);
+ j=eBands[i]<<LM;
+ if (shift>0)
+ {
+ do {
+ sum = MAC16_16(sum, EXTRACT16(SHR32(X[j+c*N],shift)),
+ EXTRACT16(SHR32(X[j+c*N],shift)));
+ } while (++j<eBands[i+1]<<LM);
+ } else {
+ do {
+ sum = MAC16_16(sum, EXTRACT16(SHL32(X[j+c*N],-shift)),
+ EXTRACT16(SHL32(X[j+c*N],-shift)));
+ } while (++j<eBands[i+1]<<LM);
+ }
+ /* We're adding one here to ensure the normalized band isn't larger than unity norm */
+ bandE[i+c*m->nbEBands] = EPSILON+VSHR32(EXTEND32(celt_sqrt(sum)),-shift);
+ } else {
+ bandE[i+c*m->nbEBands] = EPSILON;
+ }
+ /*printf ("%f ", bandE[i+c*m->nbEBands]);*/
+ }
+ } while (++c<C);
+ /*printf ("\n");*/
+}
+
+/* Normalise each band such that the energy is one. */
+void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, celt_norm * OPUS_RESTRICT X, const celt_ener *bandE, int end, int C, int M)
+{
+ int i, c, N;
+ const opus_int16 *eBands = m->eBands;
+ N = M*m->shortMdctSize;
+ c=0; do {
+ i=0; do {
+ opus_val16 g;
+ int j,shift;
+ opus_val16 E;
+ shift = celt_zlog2(bandE[i+c*m->nbEBands])-13;
+ E = VSHR32(bandE[i+c*m->nbEBands], shift);
+ g = EXTRACT16(celt_rcp(SHL32(E,3)));
+ j=M*eBands[i]; do {
+ X[j+c*N] = MULT16_16_Q15(VSHR32(freq[j+c*N],shift-1),g);
+ } while (++j<M*eBands[i+1]);
+ } while (++i<end);
+ } while (++c<C);
+}
+
+#else /* FIXED_POINT */
+/* Compute the amplitude (sqrt energy) in each of the bands */
+void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM)
+{
+ int i, c, N;
+ const opus_int16 *eBands = m->eBands;
+ N = m->shortMdctSize<<LM;
+ c=0; do {
+ for (i=0;i<end;i++)
+ {
+ opus_val32 sum;
+ sum = 1e-27f + celt_inner_prod_c(&X[c*N+(eBands[i]<<LM)], &X[c*N+(eBands[i]<<LM)], (eBands[i+1]-eBands[i])<<LM);
+ bandE[i+c*m->nbEBands] = celt_sqrt(sum);
+ /*printf ("%f ", bandE[i+c*m->nbEBands]);*/
+ }
+ } while (++c<C);
+ /*printf ("\n");*/
+}
+
+/* Normalise each band such that the energy is one. */
+void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, celt_norm * OPUS_RESTRICT X, const celt_ener *bandE, int end, int C, int M)
+{
+ int i, c, N;
+ const opus_int16 *eBands = m->eBands;
+ N = M*m->shortMdctSize;
+ c=0; do {
+ for (i=0;i<end;i++)
+ {
+ int j;
+ opus_val16 g = 1.f/(1e-27f+bandE[i+c*m->nbEBands]);
+ for (j=M*eBands[i];j<M*eBands[i+1];j++)
+ X[j+c*N] = freq[j+c*N]*g;
+ }
+ } while (++c<C);
+}
+
+#endif /* FIXED_POINT */
+
+/* De-normalise the energy to produce the synthesis from the unit-energy bands */
+void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X,
+ celt_sig * OPUS_RESTRICT freq, const opus_val16 *bandLogE, int start,
+ int end, int M, int downsample, int silence)
+{
+ int i, N;
+ int bound;
+ celt_sig * OPUS_RESTRICT f;
+ const celt_norm * OPUS_RESTRICT x;
+ const opus_int16 *eBands = m->eBands;
+ N = M*m->shortMdctSize;
+ bound = M*eBands[end];
+ if (downsample!=1)
+ bound = IMIN(bound, N/downsample);
+ if (silence)
+ {
+ bound = 0;
+ start = end = 0;
+ }
+ f = freq;
+ x = X+M*eBands[start];
+ for (i=0;i<M*eBands[start];i++)
+ *f++ = 0;
+ for (i=start;i<end;i++)
+ {
+ int j, band_end;
+ opus_val16 g;
+ opus_val16 lg;
+#ifdef FIXED_POINT
+ int shift;
+#endif
+ j=M*eBands[i];
+ band_end = M*eBands[i+1];
+ lg = ADD16(bandLogE[i], SHL16((opus_val16)eMeans[i],6));
+#ifndef FIXED_POINT
+ g = celt_exp2(lg);
+#else
+ /* Handle the integer part of the log energy */
+ shift = 16-(lg>>DB_SHIFT);
+ if (shift>31)
+ {
+ shift=0;
+ g=0;
+ } else {
+ /* Handle the fractional part. */
+ g = celt_exp2_frac(lg&((1<<DB_SHIFT)-1));
+ }
+ /* Handle extreme gains with negative shift. */
+ if (shift<0)
+ {
+ /* For shift < -2 we'd be likely to overflow, so we're capping
+ the gain here. This shouldn't happen unless the bitstream is
+ already corrupted. */
+ if (shift < -2)
+ {
+ g = 32767;
+ shift = -2;
+ }
+ do {
+ *f++ = SHL32(MULT16_16(*x++, g), -shift);
+ } while (++j<band_end);
+ } else
+#endif
+ /* Be careful of the fixed-point "else" just above when changing this code */
+ do {
+ *f++ = SHR32(MULT16_16(*x++, g), shift);
+ } while (++j<band_end);
+ }
+ celt_assert(start <= end);
+ OPUS_CLEAR(&freq[bound], N-bound);
+}
+
+/* This prevents energy collapse for transients with multiple short MDCTs */
+void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_masks, int LM, int C, int size,
+ int start, int end, const opus_val16 *logE, const opus_val16 *prev1logE,
+ const opus_val16 *prev2logE, const int *pulses, opus_uint32 seed, int arch)
+{
+ int c, i, j, k;
+ for (i=start;i<end;i++)
+ {
+ int N0;
+ opus_val16 thresh, sqrt_1;
+ int depth;
+#ifdef FIXED_POINT
+ int shift;
+ opus_val32 thresh32;
+#endif
+
+ N0 = m->eBands[i+1]-m->eBands[i];
+ /* depth in 1/8 bits */
+ celt_assert(pulses[i]>=0);
+ depth = celt_udiv(1+pulses[i], (m->eBands[i+1]-m->eBands[i]))>>LM;
+
+#ifdef FIXED_POINT
+ thresh32 = SHR32(celt_exp2(-SHL16(depth, 10-BITRES)),1);
+ thresh = MULT16_32_Q15(QCONST16(0.5f, 15), MIN32(32767,thresh32));
+ {
+ opus_val32 t;
+ t = N0<<LM;
+ shift = celt_ilog2(t)>>1;
+ t = SHL32(t, (7-shift)<<1);
+ sqrt_1 = celt_rsqrt_norm(t);
+ }
+#else
+ thresh = .5f*celt_exp2(-.125f*depth);
+ sqrt_1 = celt_rsqrt(N0<<LM);
+#endif
+
+ c=0; do
+ {
+ celt_norm *X;
+ opus_val16 prev1;
+ opus_val16 prev2;
+ opus_val32 Ediff;
+ opus_val16 r;
+ int renormalize=0;
+ prev1 = prev1logE[c*m->nbEBands+i];
+ prev2 = prev2logE[c*m->nbEBands+i];
+ if (C==1)
+ {
+ prev1 = MAX16(prev1,prev1logE[m->nbEBands+i]);
+ prev2 = MAX16(prev2,prev2logE[m->nbEBands+i]);
+ }
+ Ediff = EXTEND32(logE[c*m->nbEBands+i])-EXTEND32(MIN16(prev1,prev2));
+ Ediff = MAX32(0, Ediff);
+
+#ifdef FIXED_POINT
+ if (Ediff < 16384)
+ {
+ opus_val32 r32 = SHR32(celt_exp2(-EXTRACT16(Ediff)),1);
+ r = 2*MIN16(16383,r32);
+ } else {
+ r = 0;
+ }
+ if (LM==3)
+ r = MULT16_16_Q14(23170, MIN32(23169, r));
+ r = SHR16(MIN16(thresh, r),1);
+ r = SHR32(MULT16_16_Q15(sqrt_1, r),shift);
+#else
+ /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because
+ short blocks don't have the same energy as long */
+ r = 2.f*celt_exp2(-Ediff);
+ if (LM==3)
+ r *= 1.41421356f;
+ r = MIN16(thresh, r);
+ r = r*sqrt_1;
+#endif
+ X = X_+c*size+(m->eBands[i]<<LM);
+ for (k=0;k<1<<LM;k++)
+ {
+ /* Detect collapse */
+ if (!(collapse_masks[i*C+c]&1<<k))
+ {
+ /* Fill with noise */
+ for (j=0;j<N0;j++)
+ {
+ seed = celt_lcg_rand(seed);
+ X[(j<<LM)+k] = (seed&0x8000 ? r : -r);
+ }
+ renormalize = 1;
+ }
+ }
+ /* We just added some energy, so we need to renormalise */
+ if (renormalize)
+ renormalise_vector(X, N0<<LM, Q15ONE, arch);
+ } while (++c<C);
+ }
+}
+
+static void intensity_stereo(const CELTMode *m, celt_norm * OPUS_RESTRICT X, const celt_norm * OPUS_RESTRICT Y, const celt_ener *bandE, int bandID, int N)
+{
+ int i = bandID;
+ int j;
+ opus_val16 a1, a2;
+ opus_val16 left, right;
+ opus_val16 norm;
+#ifdef FIXED_POINT
+ int shift = celt_zlog2(MAX32(bandE[i], bandE[i+m->nbEBands]))-13;
+#endif
+ left = VSHR32(bandE[i],shift);
+ right = VSHR32(bandE[i+m->nbEBands],shift);
+ norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right));
+ a1 = DIV32_16(SHL32(EXTEND32(left),14),norm);
+ a2 = DIV32_16(SHL32(EXTEND32(right),14),norm);
+ for (j=0;j<N;j++)
+ {
+ celt_norm r, l;
+ l = X[j];
+ r = Y[j];
+ X[j] = EXTRACT16(SHR32(MAC16_16(MULT16_16(a1, l), a2, r), 14));
+ /* Side is not encoded, no need to calculate */
+ }
+}
+
+static void stereo_split(celt_norm * OPUS_RESTRICT X, celt_norm * OPUS_RESTRICT Y, int N)
+{
+ int j;
+ for (j=0;j<N;j++)
+ {
+ opus_val32 r, l;
+ l = MULT16_16(QCONST16(.70710678f, 15), X[j]);
+ r = MULT16_16(QCONST16(.70710678f, 15), Y[j]);
+ X[j] = EXTRACT16(SHR32(ADD32(l, r), 15));
+ Y[j] = EXTRACT16(SHR32(SUB32(r, l), 15));
+ }
+}
+
+static void stereo_merge(celt_norm * OPUS_RESTRICT X, celt_norm * OPUS_RESTRICT Y, opus_val16 mid, int N, int arch)
+{
+ int j;
+ opus_val32 xp=0, side=0;
+ opus_val32 El, Er;
+ opus_val16 mid2;
+#ifdef FIXED_POINT
+ int kl, kr;
+#endif
+ opus_val32 t, lgain, rgain;
+
+ /* Compute the norm of X+Y and X-Y as |X|^2 + |Y|^2 +/- sum(xy) */
+ dual_inner_prod(Y, X, Y, N, &xp, &side, arch);
+ /* Compensating for the mid normalization */
+ xp = MULT16_32_Q15(mid, xp);
+ /* mid and side are in Q15, not Q14 like X and Y */
+ mid2 = SHR16(mid, 1);
+ El = MULT16_16(mid2, mid2) + side - 2*xp;
+ Er = MULT16_16(mid2, mid2) + side + 2*xp;
+ if (Er < QCONST32(6e-4f, 28) || El < QCONST32(6e-4f, 28))
+ {
+ OPUS_COPY(Y, X, N);
+ return;
+ }
+
+#ifdef FIXED_POINT
+ kl = celt_ilog2(El)>>1;
+ kr = celt_ilog2(Er)>>1;
+#endif
+ t = VSHR32(El, (kl-7)<<1);
+ lgain = celt_rsqrt_norm(t);
+ t = VSHR32(Er, (kr-7)<<1);
+ rgain = celt_rsqrt_norm(t);
+
+#ifdef FIXED_POINT
+ if (kl < 7)
+ kl = 7;
+ if (kr < 7)
+ kr = 7;
+#endif
+
+ for (j=0;j<N;j++)
+ {
+ celt_norm r, l;
+ /* Apply mid scaling (side is already scaled) */
+ l = MULT16_16_P15(mid, X[j]);
+ r = Y[j];
+ X[j] = EXTRACT16(PSHR32(MULT16_16(lgain, SUB16(l,r)), kl+1));
+ Y[j] = EXTRACT16(PSHR32(MULT16_16(rgain, ADD16(l,r)), kr+1));
+ }
+}
+
+/* Decide whether we should spread the pulses in the current frame */
+int spreading_decision(const CELTMode *m, const celt_norm *X, int *average,
+ int last_decision, int *hf_average, int *tapset_decision, int update_hf,
+ int end, int C, int M)
+{
+ int i, c, N0;
+ int sum = 0, nbBands=0;
+ const opus_int16 * OPUS_RESTRICT eBands = m->eBands;
+ int decision;
+ int hf_sum=0;
+
+ celt_assert(end>0);
+
+ N0 = M*m->shortMdctSize;
+
+ if (M*(eBands[end]-eBands[end-1]) <= 8)
+ return SPREAD_NONE;
+ c=0; do {
+ for (i=0;i<end;i++)
+ {
+ int j, N, tmp=0;
+ int tcount[3] = {0,0,0};
+ const celt_norm * OPUS_RESTRICT x = X+M*eBands[i]+c*N0;
+ N = M*(eBands[i+1]-eBands[i]);
+ if (N<=8)
+ continue;
+ /* Compute rough CDF of |x[j]| */
+ for (j=0;j<N;j++)
+ {
+ opus_val32 x2N; /* Q13 */
+
+ x2N = MULT16_16(MULT16_16_Q15(x[j], x[j]), N);
+ if (x2N < QCONST16(0.25f,13))
+ tcount[0]++;
+ if (x2N < QCONST16(0.0625f,13))
+ tcount[1]++;
+ if (x2N < QCONST16(0.015625f,13))
+ tcount[2]++;
+ }
+
+ /* Only include four last bands (8 kHz and up) */
+ if (i>m->nbEBands-4)
+ hf_sum += celt_udiv(32*(tcount[1]+tcount[0]), N);
+ tmp = (2*tcount[2] >= N) + (2*tcount[1] >= N) + (2*tcount[0] >= N);
+ sum += tmp*256;
+ nbBands++;
+ }
+ } while (++c<C);
+
+ if (update_hf)
+ {
+ if (hf_sum)
+ hf_sum = celt_udiv(hf_sum, C*(4-m->nbEBands+end));
+ *hf_average = (*hf_average+hf_sum)>>1;
+ hf_sum = *hf_average;
+ if (*tapset_decision==2)
+ hf_sum += 4;
+ else if (*tapset_decision==0)
+ hf_sum -= 4;
+ if (hf_sum > 22)
+ *tapset_decision=2;
+ else if (hf_sum > 18)
+ *tapset_decision=1;
+ else
+ *tapset_decision=0;
+ }
+ /*printf("%d %d %d\n", hf_sum, *hf_average, *tapset_decision);*/
+ celt_assert(nbBands>0); /* end has to be non-zero */
+ celt_assert(sum>=0);
+ sum = celt_udiv(sum, nbBands);
+ /* Recursive averaging */
+ sum = (sum+*average)>>1;
+ *average = sum;
+ /* Hysteresis */
+ sum = (3*sum + (((3-last_decision)<<7) + 64) + 2)>>2;
+ if (sum < 80)
+ {
+ decision = SPREAD_AGGRESSIVE;
+ } else if (sum < 256)
+ {
+ decision = SPREAD_NORMAL;
+ } else if (sum < 384)
+ {
+ decision = SPREAD_LIGHT;
+ } else {
+ decision = SPREAD_NONE;
+ }
+#ifdef FUZZING
+ decision = rand()&0x3;
+ *tapset_decision=rand()%3;
+#endif
+ return decision;
+}
+
+/* Indexing table for converting from natural Hadamard to ordery Hadamard
+ This is essentially a bit-reversed Gray, on top of which we've added
+ an inversion of the order because we want the DC at the end rather than
+ the beginning. The lines are for N=2, 4, 8, 16 */
+static const int ordery_table[] = {
+ 1, 0,
+ 3, 0, 2, 1,
+ 7, 0, 4, 3, 6, 1, 5, 2,
+ 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5,
+};
+
+static void deinterleave_hadamard(celt_norm *X, int N0, int stride, int hadamard)
+{
+ int i,j;
+ VARDECL(celt_norm, tmp);
+ int N;
+ SAVE_STACK;
+ N = N0*stride;
+ ALLOC(tmp, N, celt_norm);
+ celt_assert(stride>0);
+ if (hadamard)
+ {
+ const int *ordery = ordery_table+stride-2;
+ for (i=0;i<stride;i++)
+ {
+ for (j=0;j<N0;j++)
+ tmp[ordery[i]*N0+j] = X[j*stride+i];
+ }
+ } else {
+ for (i=0;i<stride;i++)
+ for (j=0;j<N0;j++)
+ tmp[i*N0+j] = X[j*stride+i];
+ }
+ OPUS_COPY(X, tmp, N);
+ RESTORE_STACK;
+}
+
+static void interleave_hadamard(celt_norm *X, int N0, int stride, int hadamard)
+{
+ int i,j;
+ VARDECL(celt_norm, tmp);
+ int N;
+ SAVE_STACK;
+ N = N0*stride;
+ ALLOC(tmp, N, celt_norm);
+ if (hadamard)
+ {
+ const int *ordery = ordery_table+stride-2;
+ for (i=0;i<stride;i++)
+ for (j=0;j<N0;j++)
+ tmp[j*stride+i] = X[ordery[i]*N0+j];
+ } else {
+ for (i=0;i<stride;i++)
+ for (j=0;j<N0;j++)
+ tmp[j*stride+i] = X[i*N0+j];
+ }
+ OPUS_COPY(X, tmp, N);
+ RESTORE_STACK;
+}
+
+void haar1(celt_norm *X, int N0, int stride)
+{
+ int i, j;
+ N0 >>= 1;
+ for (i=0;i<stride;i++)
+ for (j=0;j<N0;j++)
+ {
+ opus_val32 tmp1, tmp2;
+ tmp1 = MULT16_16(QCONST16(.70710678f,15), X[stride*2*j+i]);
+ tmp2 = MULT16_16(QCONST16(.70710678f,15), X[stride*(2*j+1)+i]);
+ X[stride*2*j+i] = EXTRACT16(PSHR32(ADD32(tmp1, tmp2), 15));
+ X[stride*(2*j+1)+i] = EXTRACT16(PSHR32(SUB32(tmp1, tmp2), 15));
+ }
+}
+
+static int compute_qn(int N, int b, int offset, int pulse_cap, int stereo)
+{
+ static const opus_int16 exp2_table8[8] =
+ {16384, 17866, 19483, 21247, 23170, 25267, 27554, 30048};
+ int qn, qb;
+ int N2 = 2*N-1;
+ if (stereo && N==2)
+ N2--;
+ /* The upper limit ensures that in a stereo split with itheta==16384, we'll
+ always have enough bits left over to code at least one pulse in the
+ side; otherwise it would collapse, since it doesn't get folded. */
+ qb = celt_sudiv(b+N2*offset, N2);
+ qb = IMIN(b-pulse_cap-(4<<BITRES), qb);
+
+ qb = IMIN(8<<BITRES, qb);
+
+ if (qb<(1<<BITRES>>1)) {
+ qn = 1;
+ } else {
+ qn = exp2_table8[qb&0x7]>>(14-(qb>>BITRES));
+ qn = (qn+1)>>1<<1;
+ }
+ celt_assert(qn <= 256);
+ return qn;
+}
+
+struct band_ctx {
+ int encode;
+ const CELTMode *m;
+ int i;
+ int intensity;
+ int spread;
+ int tf_change;
+ ec_ctx *ec;
+ opus_int32 remaining_bits;
+ const celt_ener *bandE;
+ opus_uint32 seed;
+ int arch;
+};
+
+struct split_ctx {
+ int inv;
+ int imid;
+ int iside;
+ int delta;
+ int itheta;
+ int qalloc;
+};
+
+static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx,
+ celt_norm *X, celt_norm *Y, int N, int *b, int B, int B0,
+ int LM,
+ int stereo, int *fill)
+{
+ int qn;
+ int itheta=0;
+ int delta;
+ int imid, iside;
+ int qalloc;
+ int pulse_cap;
+ int offset;
+ opus_int32 tell;
+ int inv=0;
+ int encode;
+ const CELTMode *m;
+ int i;
+ int intensity;
+ ec_ctx *ec;
+ const celt_ener *bandE;
+
+ encode = ctx->encode;
+ m = ctx->m;
+ i = ctx->i;
+ intensity = ctx->intensity;
+ ec = ctx->ec;
+ bandE = ctx->bandE;
+
+ /* Decide on the resolution to give to the split parameter theta */
+ pulse_cap = m->logN[i]+LM*(1<<BITRES);
+ offset = (pulse_cap>>1) - (stereo&&N==2 ? QTHETA_OFFSET_TWOPHASE : QTHETA_OFFSET);
+ qn = compute_qn(N, *b, offset, pulse_cap, stereo);
+ if (stereo && i>=intensity)
+ qn = 1;
+ if (encode)
+ {
+ /* theta is the atan() of the ratio between the (normalized)
+ side and mid. With just that parameter, we can re-scale both
+ mid and side because we know that 1) they have unit norm and
+ 2) they are orthogonal. */
+ itheta = stereo_itheta(X, Y, stereo, N, ctx->arch);
+ }
+ tell = ec_tell_frac(ec);
+ if (qn!=1)
+ {
+ if (encode)
+ itheta = (itheta*(opus_int32)qn+8192)>>14;
+
+ /* Entropy coding of the angle. We use a uniform pdf for the
+ time split, a step for stereo, and a triangular one for the rest. */
+ if (stereo && N>2)
+ {
+ int p0 = 3;
+ int x = itheta;
+ int x0 = qn/2;
+ int ft = p0*(x0+1) + x0;
+ /* Use a probability of p0 up to itheta=8192 and then use 1 after */
+ if (encode)
+ {
+ ec_encode(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft);
+ } else {
+ int fs;
+ fs=ec_decode(ec,ft);
+ if (fs<(x0+1)*p0)
+ x=fs/p0;
+ else
+ x=x0+1+(fs-(x0+1)*p0);
+ ec_dec_update(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft);
+ itheta = x;
+ }
+ } else if (B0>1 || stereo) {
+ /* Uniform pdf */
+ if (encode)
+ ec_enc_uint(ec, itheta, qn+1);
+ else
+ itheta = ec_dec_uint(ec, qn+1);
+ } else {
+ int fs=1, ft;
+ ft = ((qn>>1)+1)*((qn>>1)+1);
+ if (encode)
+ {
+ int fl;
+
+ fs = itheta <= (qn>>1) ? itheta + 1 : qn + 1 - itheta;
+ fl = itheta <= (qn>>1) ? itheta*(itheta + 1)>>1 :
+ ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1);
+
+ ec_encode(ec, fl, fl+fs, ft);
+ } else {
+ /* Triangular pdf */
+ int fl=0;
+ int fm;
+ fm = ec_decode(ec, ft);
+
+ if (fm < ((qn>>1)*((qn>>1) + 1)>>1))
+ {
+ itheta = (isqrt32(8*(opus_uint32)fm + 1) - 1)>>1;
+ fs = itheta + 1;
+ fl = itheta*(itheta + 1)>>1;
+ }
+ else
+ {
+ itheta = (2*(qn + 1)
+ - isqrt32(8*(opus_uint32)(ft - fm - 1) + 1))>>1;
+ fs = qn + 1 - itheta;
+ fl = ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1);
+ }
+
+ ec_dec_update(ec, fl, fl+fs, ft);
+ }
+ }
+ celt_assert(itheta>=0);
+ itheta = celt_udiv((opus_int32)itheta*16384, qn);
+ if (encode && stereo)
+ {
+ if (itheta==0)
+ intensity_stereo(m, X, Y, bandE, i, N);
+ else
+ stereo_split(X, Y, N);
+ }
+ /* NOTE: Renormalising X and Y *may* help fixed-point a bit at very high rate.
+ Let's do that at higher complexity */
+ } else if (stereo) {
+ if (encode)
+ {
+ inv = itheta > 8192;
+ if (inv)
+ {
+ int j;
+ for (j=0;j<N;j++)
+ Y[j] = -Y[j];
+ }
+ intensity_stereo(m, X, Y, bandE, i, N);
+ }
+ if (*b>2<<BITRES && ctx->remaining_bits > 2<<BITRES)
+ {
+ if (encode)
+ ec_enc_bit_logp(ec, inv, 2);
+ else
+ inv = ec_dec_bit_logp(ec, 2);
+ } else
+ inv = 0;
+ itheta = 0;
+ }
+ qalloc = ec_tell_frac(ec) - tell;
+ *b -= qalloc;
+
+ if (itheta == 0)
+ {
+ imid = 32767;
+ iside = 0;
+ *fill &= (1<<B)-1;
+ delta = -16384;
+ } else if (itheta == 16384)
+ {
+ imid = 0;
+ iside = 32767;
+ *fill &= ((1<<B)-1)<<B;
+ delta = 16384;
+ } else {
+ imid = bitexact_cos((opus_int16)itheta);
+ iside = bitexact_cos((opus_int16)(16384-itheta));
+ /* This is the mid vs side allocation that minimizes squared error
+ in that band. */
+ delta = FRAC_MUL16((N-1)<<7,bitexact_log2tan(iside,imid));
+ }
+
+ sctx->inv = inv;
+ sctx->imid = imid;
+ sctx->iside = iside;
+ sctx->delta = delta;
+ sctx->itheta = itheta;
+ sctx->qalloc = qalloc;
+}
+static unsigned quant_band_n1(struct band_ctx *ctx, celt_norm *X, celt_norm *Y, int b,
+ celt_norm *lowband_out)
+{
+#ifdef RESYNTH
+ int resynth = 1;
+#else
+ int resynth = !ctx->encode;
+#endif
+ int c;
+ int stereo;
+ celt_norm *x = X;
+ int encode;
+ ec_ctx *ec;
+
+ encode = ctx->encode;
+ ec = ctx->ec;
+
+ stereo = Y != NULL;
+ c=0; do {
+ int sign=0;
+ if (ctx->remaining_bits>=1<<BITRES)
+ {
+ if (encode)
+ {
+ sign = x[0]<0;
+ ec_enc_bits(ec, sign, 1);
+ } else {
+ sign = ec_dec_bits(ec, 1);
+ }
+ ctx->remaining_bits -= 1<<BITRES;
+ b-=1<<BITRES;
+ }
+ if (resynth)
+ x[0] = sign ? -NORM_SCALING : NORM_SCALING;
+ x = Y;
+ } while (++c<1+stereo);
+ if (lowband_out)
+ lowband_out[0] = SHR16(X[0],4);
+ return 1;
+}
+
+/* This function is responsible for encoding and decoding a mono partition.
+ It can split the band in two and transmit the energy difference with
+ the two half-bands. It can be called recursively so bands can end up being
+ split in 8 parts. */
+static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X,
+ int N, int b, int B, celt_norm *lowband,
+ int LM,
+ opus_val16 gain, int fill)
+{
+ const unsigned char *cache;
+ int q;
+ int curr_bits;
+ int imid=0, iside=0;
+ int B0=B;
+ opus_val16 mid=0, side=0;
+ unsigned cm=0;
+#ifdef RESYNTH
+ int resynth = 1;
+#else
+ int resynth = !ctx->encode;
+#endif
+ celt_norm *Y=NULL;
+ int encode;
+ const CELTMode *m;
+ int i;
+ int spread;
+ ec_ctx *ec;
+
+ encode = ctx->encode;
+ m = ctx->m;
+ i = ctx->i;
+ spread = ctx->spread;
+ ec = ctx->ec;
+
+ /* If we need 1.5 more bit than we can produce, split the band in two. */
+ cache = m->cache.bits + m->cache.index[(LM+1)*m->nbEBands+i];
+ if (LM != -1 && b > cache[cache[0]]+12 && N>2)
+ {
+ int mbits, sbits, delta;
+ int itheta;
+ int qalloc;
+ struct split_ctx sctx;
+ celt_norm *next_lowband2=NULL;
+ opus_int32 rebalance;
+
+ N >>= 1;
+ Y = X+N;
+ LM -= 1;
+ if (B==1)
+ fill = (fill&1)|(fill<<1);
+ B = (B+1)>>1;
+
+ compute_theta(ctx, &sctx, X, Y, N, &b, B, B0,
+ LM, 0, &fill);
+ imid = sctx.imid;
+ iside = sctx.iside;
+ delta = sctx.delta;
+ itheta = sctx.itheta;
+ qalloc = sctx.qalloc;
+#ifdef FIXED_POINT
+ mid = imid;
+ side = iside;
+#else
+ mid = (1.f/32768)*imid;
+ side = (1.f/32768)*iside;
+#endif
+
+ /* Give more bits to low-energy MDCTs than they would otherwise deserve */
+ if (B0>1 && (itheta&0x3fff))
+ {
+ if (itheta > 8192)
+ /* Rough approximation for pre-echo masking */
+ delta -= delta>>(4-LM);
+ else
+ /* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */
+ delta = IMIN(0, delta + (N<<BITRES>>(5-LM)));
+ }
+ mbits = IMAX(0, IMIN(b, (b-delta)/2));
+ sbits = b-mbits;
+ ctx->remaining_bits -= qalloc;
+
+ if (lowband)
+ next_lowband2 = lowband+N; /* >32-bit split case */
+
+ rebalance = ctx->remaining_bits;
+ if (mbits >= sbits)
+ {
+ cm = quant_partition(ctx, X, N, mbits, B,
+ lowband, LM,
+ MULT16_16_P15(gain,mid), fill);
+ rebalance = mbits - (rebalance-ctx->remaining_bits);
+ if (rebalance > 3<<BITRES && itheta!=0)
+ sbits += rebalance - (3<<BITRES);
+ cm |= quant_partition(ctx, Y, N, sbits, B,
+ next_lowband2, LM,
+ MULT16_16_P15(gain,side), fill>>B)<<(B0>>1);
+ } else {
+ cm = quant_partition(ctx, Y, N, sbits, B,
+ next_lowband2, LM,
+ MULT16_16_P15(gain,side), fill>>B)<<(B0>>1);
+ rebalance = sbits - (rebalance-ctx->remaining_bits);
+ if (rebalance > 3<<BITRES && itheta!=16384)
+ mbits += rebalance - (3<<BITRES);
+ cm |= quant_partition(ctx, X, N, mbits, B,
+ lowband, LM,
+ MULT16_16_P15(gain,mid), fill);
+ }
+ } else {
+ /* This is the basic no-split case */
+ q = bits2pulses(m, i, LM, b);
+ curr_bits = pulses2bits(m, i, LM, q);
+ ctx->remaining_bits -= curr_bits;
+
+ /* Ensures we can never bust the budget */
+ while (ctx->remaining_bits < 0 && q > 0)
+ {
+ ctx->remaining_bits += curr_bits;
+ q--;
+ curr_bits = pulses2bits(m, i, LM, q);
+ ctx->remaining_bits -= curr_bits;
+ }
+
+ if (q!=0)
+ {
+ int K = get_pulses(q);
+
+ /* Finally do the actual quantization */
+ if (encode)
+ {
+ cm = alg_quant(X, N, K, spread, B, ec
+#ifdef RESYNTH
+ , gain
+#endif
+ );
+ } else {
+ cm = alg_unquant(X, N, K, spread, B, ec, gain);
+ }
+ } else {
+ /* If there's no pulse, fill the band anyway */
+ int j;
+ if (resynth)
+ {
+ unsigned cm_mask;
+ /* B can be as large as 16, so this shift might overflow an int on a
+ 16-bit platform; use a long to get defined behavior.*/
+ cm_mask = (unsigned)(1UL<<B)-1;
+ fill &= cm_mask;
+ if (!fill)
+ {
+ OPUS_CLEAR(X, N);
+ } else {
+ if (lowband == NULL)
+ {
+ /* Noise */
+ for (j=0;j<N;j++)
+ {
+ ctx->seed = celt_lcg_rand(ctx->seed);
+ X[j] = (celt_norm)((opus_int32)ctx->seed>>20);
+ }
+ cm = cm_mask;
+ } else {
+ /* Folded spectrum */
+ for (j=0;j<N;j++)
+ {
+ opus_val16 tmp;
+ ctx->seed = celt_lcg_rand(ctx->seed);
+ /* About 48 dB below the "normal" folding level */
+ tmp = QCONST16(1.0f/256, 10);
+ tmp = (ctx->seed)&0x8000 ? tmp : -tmp;
+ X[j] = lowband[j]+tmp;
+ }
+ cm = fill;
+ }
+ renormalise_vector(X, N, gain, ctx->arch);
+ }
+ }
+ }
+ }
+
+ return cm;
+}
+
+
+/* This function is responsible for encoding and decoding a band for the mono case. */
+static unsigned quant_band(struct band_ctx *ctx, celt_norm *X,
+ int N, int b, int B, celt_norm *lowband,
+ int LM, celt_norm *lowband_out,
+ opus_val16 gain, celt_norm *lowband_scratch, int fill)
+{
+ int N0=N;
+ int N_B=N;
+ int N_B0;
+ int B0=B;
+ int time_divide=0;
+ int recombine=0;
+ int longBlocks;
+ unsigned cm=0;
+#ifdef RESYNTH
+ int resynth = 1;
+#else
+ int resynth = !ctx->encode;
+#endif
+ int k;
+ int encode;
+ int tf_change;
+
+ encode = ctx->encode;
+ tf_change = ctx->tf_change;
+
+ longBlocks = B0==1;
+
+ N_B = celt_udiv(N_B, B);
+
+ /* Special case for one sample */
+ if (N==1)
+ {
+ return quant_band_n1(ctx, X, NULL, b, lowband_out);
+ }
+
+ if (tf_change>0)
+ recombine = tf_change;
+ /* Band recombining to increase frequency resolution */
+
+ if (lowband_scratch && lowband && (recombine || ((N_B&1) == 0 && tf_change<0) || B0>1))
+ {
+ OPUS_COPY(lowband_scratch, lowband, N);
+ lowband = lowband_scratch;
+ }
+
+ for (k=0;k<recombine;k++)
+ {
+ static const unsigned char bit_interleave_table[16]={
+ 0,1,1,1,2,3,3,3,2,3,3,3,2,3,3,3
+ };
+ if (encode)
+ haar1(X, N>>k, 1<<k);
+ if (lowband)
+ haar1(lowband, N>>k, 1<<k);
+ fill = bit_interleave_table[fill&0xF]|bit_interleave_table[fill>>4]<<2;
+ }
+ B>>=recombine;
+ N_B<<=recombine;
+
+ /* Increasing the time resolution */
+ while ((N_B&1) == 0 && tf_change<0)
+ {
+ if (encode)
+ haar1(X, N_B, B);
+ if (lowband)
+ haar1(lowband, N_B, B);
+ fill |= fill<<B;
+ B <<= 1;
+ N_B >>= 1;
+ time_divide++;
+ tf_change++;
+ }
+ B0=B;
+ N_B0 = N_B;
+
+ /* Reorganize the samples in time order instead of frequency order */
+ if (B0>1)
+ {
+ if (encode)
+ deinterleave_hadamard(X, N_B>>recombine, B0<<recombine, longBlocks);
+ if (lowband)
+ deinterleave_hadamard(lowband, N_B>>recombine, B0<<recombine, longBlocks);
+ }
+
+ cm = quant_partition(ctx, X, N, b, B, lowband,
+ LM, gain, fill);
+
+ /* This code is used by the decoder and by the resynthesis-enabled encoder */
+ if (resynth)
+ {
+ /* Undo the sample reorganization going from time order to frequency order */
+ if (B0>1)
+ interleave_hadamard(X, N_B>>recombine, B0<<recombine, longBlocks);
+
+ /* Undo time-freq changes that we did earlier */
+ N_B = N_B0;
+ B = B0;
+ for (k=0;k<time_divide;k++)
+ {
+ B >>= 1;
+ N_B <<= 1;
+ cm |= cm>>B;
+ haar1(X, N_B, B);
+ }
+
+ for (k=0;k<recombine;k++)
+ {
+ static const unsigned char bit_deinterleave_table[16]={
+ 0x00,0x03,0x0C,0x0F,0x30,0x33,0x3C,0x3F,
+ 0xC0,0xC3,0xCC,0xCF,0xF0,0xF3,0xFC,0xFF
+ };
+ cm = bit_deinterleave_table[cm];
+ haar1(X, N0>>k, 1<<k);
+ }
+ B<<=recombine;
+
+ /* Scale output for later folding */
+ if (lowband_out)
+ {
+ int j;
+ opus_val16 n;
+ n = celt_sqrt(SHL32(EXTEND32(N0),22));
+ for (j=0;j<N0;j++)
+ lowband_out[j] = MULT16_16_Q15(n,X[j]);
+ }
+ cm &= (1<<B)-1;
+ }
+ return cm;
+}
+
+
+/* This function is responsible for encoding and decoding a band for the stereo case. */
+static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm *Y,
+ int N, int b, int B, celt_norm *lowband,
+ int LM, celt_norm *lowband_out,
+ celt_norm *lowband_scratch, int fill)
+{
+ int imid=0, iside=0;
+ int inv = 0;
+ opus_val16 mid=0, side=0;
+ unsigned cm=0;
+#ifdef RESYNTH
+ int resynth = 1;
+#else
+ int resynth = !ctx->encode;
+#endif
+ int mbits, sbits, delta;
+ int itheta;
+ int qalloc;
+ struct split_ctx sctx;
+ int orig_fill;
+ int encode;
+ ec_ctx *ec;
+
+ encode = ctx->encode;
+ ec = ctx->ec;
+
+ /* Special case for one sample */
+ if (N==1)
+ {
+ return quant_band_n1(ctx, X, Y, b, lowband_out);
+ }
+
+ orig_fill = fill;
+
+ compute_theta(ctx, &sctx, X, Y, N, &b, B, B,
+ LM, 1, &fill);
+ inv = sctx.inv;
+ imid = sctx.imid;
+ iside = sctx.iside;
+ delta = sctx.delta;
+ itheta = sctx.itheta;
+ qalloc = sctx.qalloc;
+#ifdef FIXED_POINT
+ mid = imid;
+ side = iside;
+#else
+ mid = (1.f/32768)*imid;
+ side = (1.f/32768)*iside;
+#endif
+
+ /* This is a special case for N=2 that only works for stereo and takes
+ advantage of the fact that mid and side are orthogonal to encode
+ the side with just one bit. */
+ if (N==2)
+ {
+ int c;
+ int sign=0;
+ celt_norm *x2, *y2;
+ mbits = b;
+ sbits = 0;
+ /* Only need one bit for the side. */
+ if (itheta != 0 && itheta != 16384)
+ sbits = 1<<BITRES;
+ mbits -= sbits;
+ c = itheta > 8192;
+ ctx->remaining_bits -= qalloc+sbits;
+
+ x2 = c ? Y : X;
+ y2 = c ? X : Y;
+ if (sbits)
+ {
+ if (encode)
+ {
+ /* Here we only need to encode a sign for the side. */
+ sign = x2[0]*y2[1] - x2[1]*y2[0] < 0;
+ ec_enc_bits(ec, sign, 1);
+ } else {
+ sign = ec_dec_bits(ec, 1);
+ }
+ }
+ sign = 1-2*sign;
+ /* We use orig_fill here because we want to fold the side, but if
+ itheta==16384, we'll have cleared the low bits of fill. */
+ cm = quant_band(ctx, x2, N, mbits, B, lowband,
+ LM, lowband_out, Q15ONE, lowband_scratch, orig_fill);
+ /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse),
+ and there's no need to worry about mixing with the other channel. */
+ y2[0] = -sign*x2[1];
+ y2[1] = sign*x2[0];
+ if (resynth)
+ {
+ celt_norm tmp;
+ X[0] = MULT16_16_Q15(mid, X[0]);
+ X[1] = MULT16_16_Q15(mid, X[1]);
+ Y[0] = MULT16_16_Q15(side, Y[0]);
+ Y[1] = MULT16_16_Q15(side, Y[1]);
+ tmp = X[0];
+ X[0] = SUB16(tmp,Y[0]);
+ Y[0] = ADD16(tmp,Y[0]);
+ tmp = X[1];
+ X[1] = SUB16(tmp,Y[1]);
+ Y[1] = ADD16(tmp,Y[1]);
+ }
+ } else {
+ /* "Normal" split code */
+ opus_int32 rebalance;
+
+ mbits = IMAX(0, IMIN(b, (b-delta)/2));
+ sbits = b-mbits;
+ ctx->remaining_bits -= qalloc;
+
+ rebalance = ctx->remaining_bits;
+ if (mbits >= sbits)
+ {
+ /* In stereo mode, we do not apply a scaling to the mid because we need the normalized
+ mid for folding later. */
+ cm = quant_band(ctx, X, N, mbits, B,
+ lowband, LM, lowband_out,
+ Q15ONE, lowband_scratch, fill);
+ rebalance = mbits - (rebalance-ctx->remaining_bits);
+ if (rebalance > 3<<BITRES && itheta!=0)
+ sbits += rebalance - (3<<BITRES);
+
+ /* For a stereo split, the high bits of fill are always zero, so no
+ folding will be done to the side. */
+ cm |= quant_band(ctx, Y, N, sbits, B,
+ NULL, LM, NULL,
+ side, NULL, fill>>B);
+ } else {
+ /* For a stereo split, the high bits of fill are always zero, so no
+ folding will be done to the side. */
+ cm = quant_band(ctx, Y, N, sbits, B,
+ NULL, LM, NULL,
+ side, NULL, fill>>B);
+ rebalance = sbits - (rebalance-ctx->remaining_bits);
+ if (rebalance > 3<<BITRES && itheta!=16384)
+ mbits += rebalance - (3<<BITRES);
+ /* In stereo mode, we do not apply a scaling to the mid because we need the normalized
+ mid for folding later. */
+ cm |= quant_band(ctx, X, N, mbits, B,
+ lowband, LM, lowband_out,
+ Q15ONE, lowband_scratch, fill);
+ }
+ }
+
+
+ /* This code is used by the decoder and by the resynthesis-enabled encoder */
+ if (resynth)
+ {
+ if (N!=2)
+ stereo_merge(X, Y, mid, N, ctx->arch);
+ if (inv)
+ {
+ int j;
+ for (j=0;j<N;j++)
+ Y[j] = -Y[j];
+ }
+ }
+ return cm;
+}
+
+
+void quant_all_bands(int encode, const CELTMode *m, int start, int end,
+ celt_norm *X_, celt_norm *Y_, unsigned char *collapse_masks,
+ const celt_ener *bandE, int *pulses, int shortBlocks, int spread,
+ int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits,
+ opus_int32 balance, ec_ctx *ec, int LM, int codedBands,
+ opus_uint32 *seed, int arch)
+{
+ int i;
+ opus_int32 remaining_bits;
+ const opus_int16 * OPUS_RESTRICT eBands = m->eBands;
+ celt_norm * OPUS_RESTRICT norm, * OPUS_RESTRICT norm2;
+ VARDECL(celt_norm, _norm);
+ celt_norm *lowband_scratch;
+ int B;
+ int M;
+ int lowband_offset;
+ int update_lowband = 1;
+ int C = Y_ != NULL ? 2 : 1;
+ int norm_offset;
+#ifdef RESYNTH
+ int resynth = 1;
+#else
+ int resynth = !encode;
+#endif
+ struct band_ctx ctx;
+ SAVE_STACK;
+
+ M = 1<<LM;
+ B = shortBlocks ? M : 1;
+ norm_offset = M*eBands[start];
+ /* No need to allocate norm for the last band because we don't need an
+ output in that band. */
+ ALLOC(_norm, C*(M*eBands[m->nbEBands-1]-norm_offset), celt_norm);
+ norm = _norm;
+ norm2 = norm + M*eBands[m->nbEBands-1]-norm_offset;
+ /* We can use the last band as scratch space because we don't need that
+ scratch space for the last band. */
+ lowband_scratch = X_+M*eBands[m->nbEBands-1];
+
+ lowband_offset = 0;
+ ctx.bandE = bandE;
+ ctx.ec = ec;
+ ctx.encode = encode;
+ ctx.intensity = intensity;
+ ctx.m = m;
+ ctx.seed = *seed;
+ ctx.spread = spread;
+ ctx.arch = arch;
+ for (i=start;i<end;i++)
+ {
+ opus_int32 tell;
+ int b;
+ int N;
+ opus_int32 curr_balance;
+ int effective_lowband=-1;
+ celt_norm * OPUS_RESTRICT X, * OPUS_RESTRICT Y;
+ int tf_change=0;
+ unsigned x_cm;
+ unsigned y_cm;
+ int last;
+
+ ctx.i = i;
+ last = (i==end-1);
+
+ X = X_+M*eBands[i];
+ if (Y_!=NULL)
+ Y = Y_+M*eBands[i];
+ else
+ Y = NULL;
+ N = M*eBands[i+1]-M*eBands[i];
+ tell = ec_tell_frac(ec);
+
+ /* Compute how many bits we want to allocate to this band */
+ if (i != start)
+ balance -= tell;
+ remaining_bits = total_bits-tell-1;
+ ctx.remaining_bits = remaining_bits;
+ if (i <= codedBands-1)
+ {
+ curr_balance = celt_sudiv(balance, IMIN(3, codedBands-i));
+ b = IMAX(0, IMIN(16383, IMIN(remaining_bits+1,pulses[i]+curr_balance)));
+ } else {
+ b = 0;
+ }
+
+ if (resynth && M*eBands[i]-N >= M*eBands[start] && (update_lowband || lowband_offset==0))
+ lowband_offset = i;
+
+ tf_change = tf_res[i];
+ ctx.tf_change = tf_change;
+ if (i>=m->effEBands)
+ {
+ X=norm;
+ if (Y_!=NULL)
+ Y = norm;
+ lowband_scratch = NULL;
+ }
+ if (i==end-1)
+ lowband_scratch = NULL;
+
+ /* Get a conservative estimate of the collapse_mask's for the bands we're
+ going to be folding from. */
+ if (lowband_offset != 0 && (spread!=SPREAD_AGGRESSIVE || B>1 || tf_change<0))
+ {
+ int fold_start;
+ int fold_end;
+ int fold_i;
+ /* This ensures we never repeat spectral content within one band */
+ effective_lowband = IMAX(0, M*eBands[lowband_offset]-norm_offset-N);
+ fold_start = lowband_offset;
+ while(M*eBands[--fold_start] > effective_lowband+norm_offset);
+ fold_end = lowband_offset-1;
+ while(M*eBands[++fold_end] < effective_lowband+norm_offset+N);
+ x_cm = y_cm = 0;
+ fold_i = fold_start; do {
+ x_cm |= collapse_masks[fold_i*C+0];
+ y_cm |= collapse_masks[fold_i*C+C-1];
+ } while (++fold_i<fold_end);
+ }
+ /* Otherwise, we'll be using the LCG to fold, so all blocks will (almost
+ always) be non-zero. */
+ else
+ x_cm = y_cm = (1<<B)-1;
+
+ if (dual_stereo && i==intensity)
+ {
+ int j;
+
+ /* Switch off dual stereo to do intensity. */
+ dual_stereo = 0;
+ if (resynth)
+ for (j=0;j<M*eBands[i]-norm_offset;j++)
+ norm[j] = HALF32(norm[j]+norm2[j]);
+ }
+ if (dual_stereo)
+ {
+ x_cm = quant_band(&ctx, X, N, b/2, B,
+ effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
+ last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm);
+ y_cm = quant_band(&ctx, Y, N, b/2, B,
+ effective_lowband != -1 ? norm2+effective_lowband : NULL, LM,
+ last?NULL:norm2+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, y_cm);
+ } else {
+ if (Y!=NULL)
+ {
+ x_cm = quant_band_stereo(&ctx, X, Y, N, b, B,
+ effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
+ last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, x_cm|y_cm);
+ } else {
+ x_cm = quant_band(&ctx, X, N, b, B,
+ effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
+ last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm|y_cm);
+ }
+ y_cm = x_cm;
+ }
+ collapse_masks[i*C+0] = (unsigned char)x_cm;
+ collapse_masks[i*C+C-1] = (unsigned char)y_cm;
+ balance += pulses[i] + tell;
+
+ /* Update the folding position only as long as we have 1 bit/sample depth. */
+ update_lowband = b>(N<<BITRES);
+ }
+ *seed = ctx.seed;
+
+ RESTORE_STACK;
+}
+
diff --git a/external/opus-1.1.4/celt/bands.h b/external/opus-1.1.4/celt/bands.h
new file mode 100644
index 0000000..e8bef4b
--- /dev/null
+++ b/external/opus-1.1.4/celt/bands.h
@@ -0,0 +1,120 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008-2009 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef BANDS_H
+#define BANDS_H
+
+#include "arch.h"
+#include "modes.h"
+#include "entenc.h"
+#include "entdec.h"
+#include "rate.h"
+
+/** Compute the amplitude (sqrt energy) in each of the bands
+ * @param m Mode data
+ * @param X Spectrum
+ * @param bandE Square root of the energy for each band (returned)
+ */
+void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM);
+
+/*void compute_noise_energies(const CELTMode *m, const celt_sig *X, const opus_val16 *tonality, celt_ener *bandE);*/
+
+/** Normalise each band of X such that the energy in each band is
+ equal to 1
+ * @param m Mode data
+ * @param X Spectrum (returned normalised)
+ * @param bandE Square root of the energy for each band
+ */
+void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, celt_norm * OPUS_RESTRICT X, const celt_ener *bandE, int end, int C, int M);
+
+/** Denormalise each band of X to restore full amplitude
+ * @param m Mode data
+ * @param X Spectrum (returned de-normalised)
+ * @param bandE Square root of the energy for each band
+ */
+void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X,
+ celt_sig * OPUS_RESTRICT freq, const opus_val16 *bandE, int start,
+ int end, int M, int downsample, int silence);
+
+#define SPREAD_NONE (0)
+#define SPREAD_LIGHT (1)
+#define SPREAD_NORMAL (2)
+#define SPREAD_AGGRESSIVE (3)
+
+int spreading_decision(const CELTMode *m, const celt_norm *X, int *average,
+ int last_decision, int *hf_average, int *tapset_decision, int update_hf,
+ int end, int C, int M);
+
+#ifdef MEASURE_NORM_MSE
+void measure_norm_mse(const CELTMode *m, float *X, float *X0, float *bandE, float *bandE0, int M, int N, int C);
+#endif
+
+void haar1(celt_norm *X, int N0, int stride);
+
+/** Quantisation/encoding of the residual spectrum
+ * @param encode flag that indicates whether we're encoding (1) or decoding (0)
+ * @param m Mode data
+ * @param start First band to process
+ * @param end Last band to process + 1
+ * @param X Residual (normalised)
+ * @param Y Residual (normalised) for second channel (or NULL for mono)
+ * @param collapse_masks Anti-collapse tracking mask
+ * @param bandE Square root of the energy for each band
+ * @param pulses Bit allocation (per band) for PVQ
+ * @param shortBlocks Zero for long blocks, non-zero for short blocks
+ * @param spread Amount of spreading to use
+ * @param dual_stereo Zero for MS stereo, non-zero for dual stereo
+ * @param intensity First band to use intensity stereo
+ * @param tf_res Time-frequency resolution change
+ * @param total_bits Total number of bits that can be used for the frame (including the ones already spent)
+ * @param balance Number of unallocated bits
+ * @param en Entropy coder state
+ * @param LM log2() of the number of 2.5 subframes in the frame
+ * @param codedBands Last band to receive bits + 1
+ * @param seed Random generator seed
+ * @param arch Run-time architecture (see opus_select_arch())
+ */
+void quant_all_bands(int encode, const CELTMode *m, int start, int end,
+ celt_norm * X, celt_norm * Y, unsigned char *collapse_masks,
+ const celt_ener *bandE, int *pulses, int shortBlocks, int spread,
+ int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits,
+ opus_int32 balance, ec_ctx *ec, int M, int codedBands, opus_uint32 *seed,
+ int arch);
+
+void anti_collapse(const CELTMode *m, celt_norm *X_,
+ unsigned char *collapse_masks, int LM, int C, int size, int start,
+ int end, const opus_val16 *logE, const opus_val16 *prev1logE,
+ const opus_val16 *prev2logE, const int *pulses, opus_uint32 seed,
+ int arch);
+
+opus_uint32 celt_lcg_rand(opus_uint32 seed);
+
+int hysteresis_decision(opus_val16 val, const opus_val16 *thresholds, const opus_val16 *hysteresis, int N, int prev);
+
+#endif /* BANDS_H */
diff --git a/external/opus-1.1.4/celt/celt.c b/external/opus-1.1.4/celt/celt.c
new file mode 100644
index 0000000..b121c51
--- /dev/null
+++ b/external/opus-1.1.4/celt/celt.c
@@ -0,0 +1,299 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2010 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CELT_C
+
+#include "os_support.h"
+#include "mdct.h"
+#include <math.h>
+#include "celt.h"
+#include "pitch.h"
+#include "bands.h"
+#include "modes.h"
+#include "entcode.h"
+#include "quant_bands.h"
+#include "rate.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "float_cast.h"
+#include <stdarg.h>
+#include "celt_lpc.h"
+#include "vq.h"
+
+#ifndef PACKAGE_VERSION
+#define PACKAGE_VERSION "unknown"
+#endif
+
+#if defined(MIPSr1_ASM)
+#include "mips/celt_mipsr1.h"
+#endif
+
+
+int resampling_factor(opus_int32 rate)
+{
+ int ret;
+ switch (rate)
+ {
+ case 48000:
+ ret = 1;
+ break;
+ case 24000:
+ ret = 2;
+ break;
+ case 16000:
+ ret = 3;
+ break;
+ case 12000:
+ ret = 4;
+ break;
+ case 8000:
+ ret = 6;
+ break;
+ default:
+#ifndef CUSTOM_MODES
+ celt_assert(0);
+#endif
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+#if !defined(OVERRIDE_COMB_FILTER_CONST) || defined(NON_STATIC_COMB_FILTER_CONST_C)
+/* This version should be faster on ARM */
+#ifdef OPUS_ARM_ASM
+#ifndef NON_STATIC_COMB_FILTER_CONST_C
+static
+#endif
+void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N,
+ opus_val16 g10, opus_val16 g11, opus_val16 g12)
+{
+ opus_val32 x0, x1, x2, x3, x4;
+ int i;
+ x4 = SHL32(x[-T-2], 1);
+ x3 = SHL32(x[-T-1], 1);
+ x2 = SHL32(x[-T], 1);
+ x1 = SHL32(x[-T+1], 1);
+ for (i=0;i<N-4;i+=5)
+ {
+ opus_val32 t;
+ x0=SHL32(x[i-T+2],1);
+ t = MAC16_32_Q16(x[i], g10, x2);
+ t = MAC16_32_Q16(t, g11, ADD32(x1,x3));
+ t = MAC16_32_Q16(t, g12, ADD32(x0,x4));
+ y[i] = t;
+ x4=SHL32(x[i-T+3],1);
+ t = MAC16_32_Q16(x[i+1], g10, x1);
+ t = MAC16_32_Q16(t, g11, ADD32(x0,x2));
+ t = MAC16_32_Q16(t, g12, ADD32(x4,x3));
+ y[i+1] = t;
+ x3=SHL32(x[i-T+4],1);
+ t = MAC16_32_Q16(x[i+2], g10, x0);
+ t = MAC16_32_Q16(t, g11, ADD32(x4,x1));
+ t = MAC16_32_Q16(t, g12, ADD32(x3,x2));
+ y[i+2] = t;
+ x2=SHL32(x[i-T+5],1);
+ t = MAC16_32_Q16(x[i+3], g10, x4);
+ t = MAC16_32_Q16(t, g11, ADD32(x3,x0));
+ t = MAC16_32_Q16(t, g12, ADD32(x2,x1));
+ y[i+3] = t;
+ x1=SHL32(x[i-T+6],1);
+ t = MAC16_32_Q16(x[i+4], g10, x3);
+ t = MAC16_32_Q16(t, g11, ADD32(x2,x4));
+ t = MAC16_32_Q16(t, g12, ADD32(x1,x0));
+ y[i+4] = t;
+ }
+#ifdef CUSTOM_MODES
+ for (;i<N;i++)
+ {
+ opus_val32 t;
+ x0=SHL32(x[i-T+2],1);
+ t = MAC16_32_Q16(x[i], g10, x2);
+ t = MAC16_32_Q16(t, g11, ADD32(x1,x3));
+ t = MAC16_32_Q16(t, g12, ADD32(x0,x4));
+ y[i] = t;
+ x4=x3;
+ x3=x2;
+ x2=x1;
+ x1=x0;
+ }
+#endif
+}
+#else
+#ifndef NON_STATIC_COMB_FILTER_CONST_C
+static
+#endif
+void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N,
+ opus_val16 g10, opus_val16 g11, opus_val16 g12)
+{
+ opus_val32 x0, x1, x2, x3, x4;
+ int i;
+ x4 = x[-T-2];
+ x3 = x[-T-1];
+ x2 = x[-T];
+ x1 = x[-T+1];
+ for (i=0;i<N;i++)
+ {
+ x0=x[i-T+2];
+ y[i] = x[i]
+ + MULT16_32_Q15(g10,x2)
+ + MULT16_32_Q15(g11,ADD32(x1,x3))
+ + MULT16_32_Q15(g12,ADD32(x0,x4));
+ x4=x3;
+ x3=x2;
+ x2=x1;
+ x1=x0;
+ }
+
+}
+#endif
+#endif
+
+#ifndef OVERRIDE_comb_filter
+void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
+ opus_val16 g0, opus_val16 g1, int tapset0, int tapset1,
+ const opus_val16 *window, int overlap, int arch)
+{
+ int i;
+ /* printf ("%d %d %f %f\n", T0, T1, g0, g1); */
+ opus_val16 g00, g01, g02, g10, g11, g12;
+ opus_val32 x0, x1, x2, x3, x4;
+ static const opus_val16 gains[3][3] = {
+ {QCONST16(0.3066406250f, 15), QCONST16(0.2170410156f, 15), QCONST16(0.1296386719f, 15)},
+ {QCONST16(0.4638671875f, 15), QCONST16(0.2680664062f, 15), QCONST16(0.f, 15)},
+ {QCONST16(0.7998046875f, 15), QCONST16(0.1000976562f, 15), QCONST16(0.f, 15)}};
+
+ if (g0==0 && g1==0)
+ {
+ /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+ if (x!=y)
+ OPUS_MOVE(y, x, N);
+ return;
+ }
+ g00 = MULT16_16_P15(g0, gains[tapset0][0]);
+ g01 = MULT16_16_P15(g0, gains[tapset0][1]);
+ g02 = MULT16_16_P15(g0, gains[tapset0][2]);
+ g10 = MULT16_16_P15(g1, gains[tapset1][0]);
+ g11 = MULT16_16_P15(g1, gains[tapset1][1]);
+ g12 = MULT16_16_P15(g1, gains[tapset1][2]);
+ x1 = x[-T1+1];
+ x2 = x[-T1 ];
+ x3 = x[-T1-1];
+ x4 = x[-T1-2];
+ /* If the filter didn't change, we don't need the overlap */
+ if (g0==g1 && T0==T1 && tapset0==tapset1)
+ overlap=0;
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 f;
+ x0=x[i-T1+2];
+ f = MULT16_16_Q15(window[i],window[i]);
+ y[i] = x[i]
+ + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g00),x[i-T0])
+ + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g01),ADD32(x[i-T0+1],x[i-T0-1]))
+ + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g02),ADD32(x[i-T0+2],x[i-T0-2]))
+ + MULT16_32_Q15(MULT16_16_Q15(f,g10),x2)
+ + MULT16_32_Q15(MULT16_16_Q15(f,g11),ADD32(x1,x3))
+ + MULT16_32_Q15(MULT16_16_Q15(f,g12),ADD32(x0,x4));
+ x4=x3;
+ x3=x2;
+ x2=x1;
+ x1=x0;
+
+ }
+ if (g1==0)
+ {
+ /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+ if (x!=y)
+ OPUS_MOVE(y+overlap, x+overlap, N-overlap);
+ return;
+ }
+
+ /* Compute the part with the constant filter. */
+ comb_filter_const(y+i, x+i, T1, N-i, g10, g11, g12, arch);
+}
+#endif /* OVERRIDE_comb_filter */
+
+const signed char tf_select_table[4][8] = {
+ {0, -1, 0, -1, 0,-1, 0,-1},
+ {0, -1, 0, -2, 1, 0, 1,-1},
+ {0, -2, 0, -3, 2, 0, 1,-1},
+ {0, -2, 0, -3, 3, 0, 1,-1},
+};
+
+
+void init_caps(const CELTMode *m,int *cap,int LM,int C)
+{
+ int i;
+ for (i=0;i<m->nbEBands;i++)
+ {
+ int N;
+ N=(m->eBands[i+1]-m->eBands[i])<<LM;
+ cap[i] = (m->cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2;
+ }
+}
+
+
+
+const char *opus_strerror(int error)
+{
+ static const char * const error_strings[8] = {
+ "success",
+ "invalid argument",
+ "buffer too small",
+ "internal error",
+ "corrupted stream",
+ "request not implemented",
+ "invalid state",
+ "memory allocation failed"
+ };
+ if (error > 0 || error < -7)
+ return "unknown error";
+ else
+ return error_strings[-error];
+}
+
+const char *opus_get_version_string(void)
+{
+ return "libopus " PACKAGE_VERSION
+ /* Applications may rely on the presence of this substring in the version
+ string to determine if they have a fixed-point or floating-point build
+ at runtime. */
+#ifdef FIXED_POINT
+ "-fixed"
+#endif
+#ifdef FUZZING
+ "-fuzzing"
+#endif
+ ;
+}
diff --git a/external/opus-1.1.4/celt/celt.h b/external/opus-1.1.4/celt/celt.h
new file mode 100644
index 0000000..d1f7eb6
--- /dev/null
+++ b/external/opus-1.1.4/celt/celt.h
@@ -0,0 +1,229 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/**
+ @file celt.h
+ @brief Contains all the functions for encoding and decoding audio
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef CELT_H
+#define CELT_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+#include "opus_custom.h"
+#include "entenc.h"
+#include "entdec.h"
+#include "arch.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CELTEncoder OpusCustomEncoder
+#define CELTDecoder OpusCustomDecoder
+#define CELTMode OpusCustomMode
+
+typedef struct {
+ int valid;
+ float tonality;
+ float tonality_slope;
+ float noisiness;
+ float activity;
+ float music_prob;
+ int bandwidth;
+}AnalysisInfo;
+
+#define __celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr)))
+
+#define __celt_check_analysis_ptr(ptr) ((ptr) + ((ptr) - (const AnalysisInfo*)(ptr)))
+
+/* Encoder/decoder Requests */
+
+/* Expose this option again when variable framesize actually works */
+#define OPUS_FRAMESIZE_VARIABLE 5010 /**< Optimize the frame size dynamically */
+
+
+#define CELT_SET_PREDICTION_REQUEST 10002
+/** Controls the use of interframe prediction.
+ 0=Independent frames
+ 1=Short term interframe prediction allowed
+ 2=Long term prediction allowed
+ */
+#define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_INPUT_CLIPPING_REQUEST 10004
+#define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, __opus_check_int(x)
+
+#define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007
+#define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, __opus_check_int_ptr(x)
+
+#define CELT_SET_CHANNELS_REQUEST 10008
+#define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, __opus_check_int(x)
+
+
+/* Internal */
+#define CELT_SET_START_BAND_REQUEST 10010
+#define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_END_BAND_REQUEST 10012
+#define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, __opus_check_int(x)
+
+#define CELT_GET_MODE_REQUEST 10015
+/** Get the CELTMode used by an encoder or decoder */
+#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, __celt_check_mode_ptr_ptr(x)
+
+#define CELT_SET_SIGNALLING_REQUEST 10016
+#define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_TONALITY_REQUEST 10018
+#define CELT_SET_TONALITY(x) CELT_SET_TONALITY_REQUEST, __opus_check_int(x)
+#define CELT_SET_TONALITY_SLOPE_REQUEST 10020
+#define CELT_SET_TONALITY_SLOPE(x) CELT_SET_TONALITY_SLOPE_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_ANALYSIS_REQUEST 10022
+#define CELT_SET_ANALYSIS(x) CELT_SET_ANALYSIS_REQUEST, __celt_check_analysis_ptr(x)
+
+#define OPUS_SET_LFE_REQUEST 10024
+#define OPUS_SET_LFE(x) OPUS_SET_LFE_REQUEST, __opus_check_int(x)
+
+#define OPUS_SET_ENERGY_MASK_REQUEST 10026
+#define OPUS_SET_ENERGY_MASK(x) OPUS_SET_ENERGY_MASK_REQUEST, __opus_check_val16_ptr(x)
+
+/* Encoder stuff */
+
+int celt_encoder_get_size(int channels);
+
+int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
+
+int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels,
+ int arch);
+
+
+
+/* Decoder stuff */
+
+int celt_decoder_get_size(int channels);
+
+
+int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels);
+
+int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data,
+ int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum);
+
+#define celt_encoder_ctl opus_custom_encoder_ctl
+#define celt_decoder_ctl opus_custom_decoder_ctl
+
+
+#ifdef CUSTOM_MODES
+#define OPUS_CUSTOM_NOSTATIC
+#else
+#define OPUS_CUSTOM_NOSTATIC static OPUS_INLINE
+#endif
+
+static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0};
+/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */
+static const unsigned char spread_icdf[4] = {25, 23, 2, 0};
+
+static const unsigned char tapset_icdf[3]={2,1,0};
+
+#ifdef CUSTOM_MODES
+static const unsigned char toOpusTable[20] = {
+ 0xE0, 0xE8, 0xF0, 0xF8,
+ 0xC0, 0xC8, 0xD0, 0xD8,
+ 0xA0, 0xA8, 0xB0, 0xB8,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x88, 0x90, 0x98,
+};
+
+static const unsigned char fromOpusTable[16] = {
+ 0x80, 0x88, 0x90, 0x98,
+ 0x40, 0x48, 0x50, 0x58,
+ 0x20, 0x28, 0x30, 0x38,
+ 0x00, 0x08, 0x10, 0x18
+};
+
+static OPUS_INLINE int toOpus(unsigned char c)
+{
+ int ret=0;
+ if (c<0xA0)
+ ret = toOpusTable[c>>3];
+ if (ret == 0)
+ return -1;
+ else
+ return ret|(c&0x7);
+}
+
+static OPUS_INLINE int fromOpus(unsigned char c)
+{
+ if (c<0x80)
+ return -1;
+ else
+ return fromOpusTable[(c>>3)-16] | (c&0x7);
+}
+#endif /* CUSTOM_MODES */
+
+#define COMBFILTER_MAXPERIOD 1024
+#define COMBFILTER_MINPERIOD 15
+
+extern const signed char tf_select_table[4][8];
+
+int resampling_factor(opus_int32 rate);
+
+void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
+ int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip);
+
+void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
+ opus_val16 g0, opus_val16 g1, int tapset0, int tapset1,
+ const opus_val16 *window, int overlap, int arch);
+
+#ifdef NON_STATIC_COMB_FILTER_CONST_C
+void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N,
+ opus_val16 g10, opus_val16 g11, opus_val16 g12);
+#endif
+
+#ifndef OVERRIDE_COMB_FILTER_CONST
+# define comb_filter_const(y, x, T, N, g10, g11, g12, arch) \
+ ((void)(arch),comb_filter_const_c(y, x, T, N, g10, g11, g12))
+#endif
+
+void init_caps(const CELTMode *m,int *cap,int LM,int C);
+
+#ifdef RESYNTH
+void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef, celt_sig *mem);
+void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[],
+ opus_val16 *oldBandE, int start, int effEnd, int C, int CC, int isTransient,
+ int LM, int downsample, int silence);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CELT_H */
diff --git a/external/opus-1.1.4/celt/celt_decoder.c b/external/opus-1.1.4/celt/celt_decoder.c
new file mode 100644
index 0000000..b978bb3
--- /dev/null
+++ b/external/opus-1.1.4/celt/celt_decoder.c
@@ -0,0 +1,1248 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2010 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CELT_DECODER_C
+
+#include "cpu_support.h"
+#include "os_support.h"
+#include "mdct.h"
+#include <math.h>
+#include "celt.h"
+#include "pitch.h"
+#include "bands.h"
+#include "modes.h"
+#include "entcode.h"
+#include "quant_bands.h"
+#include "rate.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "float_cast.h"
+#include <stdarg.h>
+#include "celt_lpc.h"
+#include "vq.h"
+
+#if defined(SMALL_FOOTPRINT) && defined(FIXED_POINT)
+#define NORM_ALIASING_HACK
+#endif
+/**********************************************************************/
+/* */
+/* DECODER */
+/* */
+/**********************************************************************/
+#define DECODE_BUFFER_SIZE 2048
+
+/** Decoder state
+ @brief Decoder state
+ */
+struct OpusCustomDecoder {
+ const OpusCustomMode *mode;
+ int overlap;
+ int channels;
+ int stream_channels;
+
+ int downsample;
+ int start, end;
+ int signalling;
+ int arch;
+
+ /* Everything beyond this point gets cleared on a reset */
+#define DECODER_RESET_START rng
+
+ opus_uint32 rng;
+ int error;
+ int last_pitch_index;
+ int loss_count;
+ int skip_plc;
+ int postfilter_period;
+ int postfilter_period_old;
+ opus_val16 postfilter_gain;
+ opus_val16 postfilter_gain_old;
+ int postfilter_tapset;
+ int postfilter_tapset_old;
+
+ celt_sig preemph_memD[2];
+
+ celt_sig _decode_mem[1]; /* Size = channels*(DECODE_BUFFER_SIZE+mode->overlap) */
+ /* opus_val16 lpc[], Size = channels*LPC_ORDER */
+ /* opus_val16 oldEBands[], Size = 2*mode->nbEBands */
+ /* opus_val16 oldLogE[], Size = 2*mode->nbEBands */
+ /* opus_val16 oldLogE2[], Size = 2*mode->nbEBands */
+ /* opus_val16 backgroundLogE[], Size = 2*mode->nbEBands */
+};
+
+int celt_decoder_get_size(int channels)
+{
+ const CELTMode *mode = opus_custom_mode_create(48000, 960, NULL);
+ return opus_custom_decoder_get_size(mode, channels);
+}
+
+OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_get_size(const CELTMode *mode, int channels)
+{
+ int size = sizeof(struct CELTDecoder)
+ + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig)
+ + channels*LPC_ORDER*sizeof(opus_val16)
+ + 4*2*mode->nbEBands*sizeof(opus_val16);
+ return size;
+}
+
+#ifdef CUSTOM_MODES
+CELTDecoder *opus_custom_decoder_create(const CELTMode *mode, int channels, int *error)
+{
+ int ret;
+ CELTDecoder *st = (CELTDecoder *)opus_alloc(opus_custom_decoder_get_size(mode, channels));
+ ret = opus_custom_decoder_init(st, mode, channels);
+ if (ret != OPUS_OK)
+ {
+ opus_custom_decoder_destroy(st);
+ st = NULL;
+ }
+ if (error)
+ *error = ret;
+ return st;
+}
+#endif /* CUSTOM_MODES */
+
+int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels)
+{
+ int ret;
+ ret = opus_custom_decoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels);
+ if (ret != OPUS_OK)
+ return ret;
+ st->downsample = resampling_factor(sampling_rate);
+ if (st->downsample==0)
+ return OPUS_BAD_ARG;
+ else
+ return OPUS_OK;
+}
+
+OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMode *mode, int channels)
+{
+ if (channels < 0 || channels > 2)
+ return OPUS_BAD_ARG;
+
+ if (st==NULL)
+ return OPUS_ALLOC_FAIL;
+
+ OPUS_CLEAR((char*)st, opus_custom_decoder_get_size(mode, channels));
+
+ st->mode = mode;
+ st->overlap = mode->overlap;
+ st->stream_channels = st->channels = channels;
+
+ st->downsample = 1;
+ st->start = 0;
+ st->end = st->mode->effEBands;
+ st->signalling = 1;
+ st->arch = opus_select_arch();
+
+ opus_custom_decoder_ctl(st, OPUS_RESET_STATE);
+
+ return OPUS_OK;
+}
+
+#ifdef CUSTOM_MODES
+void opus_custom_decoder_destroy(CELTDecoder *st)
+{
+ opus_free(st);
+}
+#endif /* CUSTOM_MODES */
+
+
+#ifndef RESYNTH
+static
+#endif
+void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef,
+ celt_sig *mem, int accum)
+{
+ int c;
+ int Nd;
+ int apply_downsampling=0;
+ opus_val16 coef0;
+ VARDECL(celt_sig, scratch);
+ SAVE_STACK;
+#ifndef FIXED_POINT
+ (void)accum;
+ celt_assert(accum==0);
+#endif
+ ALLOC(scratch, N, celt_sig);
+ coef0 = coef[0];
+ Nd = N/downsample;
+ c=0; do {
+ int j;
+ celt_sig * OPUS_RESTRICT x;
+ opus_val16 * OPUS_RESTRICT y;
+ celt_sig m = mem[c];
+ x =in[c];
+ y = pcm+c;
+#ifdef CUSTOM_MODES
+ if (coef[1] != 0)
+ {
+ opus_val16 coef1 = coef[1];
+ opus_val16 coef3 = coef[3];
+ for (j=0;j<N;j++)
+ {
+ celt_sig tmp = x[j] + m + VERY_SMALL;
+ m = MULT16_32_Q15(coef0, tmp)
+ - MULT16_32_Q15(coef1, x[j]);
+ tmp = SHL32(MULT16_32_Q15(coef3, tmp), 2);
+ scratch[j] = tmp;
+ }
+ apply_downsampling=1;
+ } else
+#endif
+ if (downsample>1)
+ {
+ /* Shortcut for the standard (non-custom modes) case */
+ for (j=0;j<N;j++)
+ {
+ celt_sig tmp = x[j] + m + VERY_SMALL;
+ m = MULT16_32_Q15(coef0, tmp);
+ scratch[j] = tmp;
+ }
+ apply_downsampling=1;
+ } else {
+ /* Shortcut for the standard (non-custom modes) case */
+#ifdef FIXED_POINT
+ if (accum)
+ {
+ for (j=0;j<N;j++)
+ {
+ celt_sig tmp = x[j] + m + VERY_SMALL;
+ m = MULT16_32_Q15(coef0, tmp);
+ y[j*C] = SAT16(ADD32(y[j*C], SCALEOUT(SIG2WORD16(tmp))));
+ }
+ } else
+#endif
+ {
+ for (j=0;j<N;j++)
+ {
+ celt_sig tmp = x[j] + m + VERY_SMALL;
+ m = MULT16_32_Q15(coef0, tmp);
+ y[j*C] = SCALEOUT(SIG2WORD16(tmp));
+ }
+ }
+ }
+ mem[c] = m;
+
+ if (apply_downsampling)
+ {
+ /* Perform down-sampling */
+#ifdef FIXED_POINT
+ if (accum)
+ {
+ for (j=0;j<Nd;j++)
+ y[j*C] = SAT16(ADD32(y[j*C], SCALEOUT(SIG2WORD16(scratch[j*downsample]))));
+ } else
+#endif
+ {
+ for (j=0;j<Nd;j++)
+ y[j*C] = SCALEOUT(SIG2WORD16(scratch[j*downsample]));
+ }
+ }
+ } while (++c<C);
+ RESTORE_STACK;
+}
+
+#ifndef RESYNTH
+static
+#endif
+void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[],
+ opus_val16 *oldBandE, int start, int effEnd, int C, int CC,
+ int isTransient, int LM, int downsample,
+ int silence, int arch)
+{
+ int c, i;
+ int M;
+ int b;
+ int B;
+ int N, NB;
+ int shift;
+ int nbEBands;
+ int overlap;
+ VARDECL(celt_sig, freq);
+ SAVE_STACK;
+
+ overlap = mode->overlap;
+ nbEBands = mode->nbEBands;
+ N = mode->shortMdctSize<<LM;
+ ALLOC(freq, N, celt_sig); /**< Interleaved signal MDCTs */
+ M = 1<<LM;
+
+ if (isTransient)
+ {
+ B = M;
+ NB = mode->shortMdctSize;
+ shift = mode->maxLM;
+ } else {
+ B = 1;
+ NB = mode->shortMdctSize<<LM;
+ shift = mode->maxLM-LM;
+ }
+
+ if (CC==2&&C==1)
+ {
+ /* Copying a mono streams to two channels */
+ celt_sig *freq2;
+ denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M,
+ downsample, silence);
+ /* Store a temporary copy in the output buffer because the IMDCT destroys its input. */
+ freq2 = out_syn[1]+overlap/2;
+ OPUS_COPY(freq2, freq, N);
+ for (b=0;b<B;b++)
+ clt_mdct_backward(&mode->mdct, &freq2[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch);
+ for (b=0;b<B;b++)
+ clt_mdct_backward(&mode->mdct, &freq[b], out_syn[1]+NB*b, mode->window, overlap, shift, B, arch);
+ } else if (CC==1&&C==2)
+ {
+ /* Downmixing a stereo stream to mono */
+ celt_sig *freq2;
+ freq2 = out_syn[0]+overlap/2;
+ denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M,
+ downsample, silence);
+ /* Use the output buffer as temp array before downmixing. */
+ denormalise_bands(mode, X+N, freq2, oldBandE+nbEBands, start, effEnd, M,
+ downsample, silence);
+ for (i=0;i<N;i++)
+ freq[i] = HALF32(ADD32(freq[i],freq2[i]));
+ for (b=0;b<B;b++)
+ clt_mdct_backward(&mode->mdct, &freq[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch);
+ } else {
+ /* Normal case (mono or stereo) */
+ c=0; do {
+ denormalise_bands(mode, X+c*N, freq, oldBandE+c*nbEBands, start, effEnd, M,
+ downsample, silence);
+ for (b=0;b<B;b++)
+ clt_mdct_backward(&mode->mdct, &freq[b], out_syn[c]+NB*b, mode->window, overlap, shift, B, arch);
+ } while (++c<CC);
+ }
+ RESTORE_STACK;
+}
+
+static void tf_decode(int start, int end, int isTransient, int *tf_res, int LM, ec_dec *dec)
+{
+ int i, curr, tf_select;
+ int tf_select_rsv;
+ int tf_changed;
+ int logp;
+ opus_uint32 budget;
+ opus_uint32 tell;
+
+ budget = dec->storage*8;
+ tell = ec_tell(dec);
+ logp = isTransient ? 2 : 4;
+ tf_select_rsv = LM>0 && tell+logp+1<=budget;
+ budget -= tf_select_rsv;
+ tf_changed = curr = 0;
+ for (i=start;i<end;i++)
+ {
+ if (tell+logp<=budget)
+ {
+ curr ^= ec_dec_bit_logp(dec, logp);
+ tell = ec_tell(dec);
+ tf_changed |= curr;
+ }
+ tf_res[i] = curr;
+ logp = isTransient ? 4 : 5;
+ }
+ tf_select = 0;
+ if (tf_select_rsv &&
+ tf_select_table[LM][4*isTransient+0+tf_changed] !=
+ tf_select_table[LM][4*isTransient+2+tf_changed])
+ {
+ tf_select = ec_dec_bit_logp(dec, 1);
+ }
+ for (i=start;i<end;i++)
+ {
+ tf_res[i] = tf_select_table[LM][4*isTransient+2*tf_select+tf_res[i]];
+ }
+}
+
+/* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save
+ CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The
+ current value corresponds to a pitch of 66.67 Hz. */
+#define PLC_PITCH_LAG_MAX (720)
+/* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a
+ pitch of 480 Hz. */
+#define PLC_PITCH_LAG_MIN (100)
+
+static int celt_plc_pitch_search(celt_sig *decode_mem[2], int C, int arch)
+{
+ int pitch_index;
+ VARDECL( opus_val16, lp_pitch_buf );
+ SAVE_STACK;
+ ALLOC( lp_pitch_buf, DECODE_BUFFER_SIZE>>1, opus_val16 );
+ pitch_downsample(decode_mem, lp_pitch_buf,
+ DECODE_BUFFER_SIZE, C, arch);
+ pitch_search(lp_pitch_buf+(PLC_PITCH_LAG_MAX>>1), lp_pitch_buf,
+ DECODE_BUFFER_SIZE-PLC_PITCH_LAG_MAX,
+ PLC_PITCH_LAG_MAX-PLC_PITCH_LAG_MIN, &pitch_index, arch);
+ pitch_index = PLC_PITCH_LAG_MAX-pitch_index;
+ RESTORE_STACK;
+ return pitch_index;
+}
+
+static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM)
+{
+ int c;
+ int i;
+ const int C = st->channels;
+ celt_sig *decode_mem[2];
+ celt_sig *out_syn[2];
+ opus_val16 *lpc;
+ opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE;
+ const OpusCustomMode *mode;
+ int nbEBands;
+ int overlap;
+ int start;
+ int loss_count;
+ int noise_based;
+ const opus_int16 *eBands;
+ SAVE_STACK;
+
+ mode = st->mode;
+ nbEBands = mode->nbEBands;
+ overlap = mode->overlap;
+ eBands = mode->eBands;
+
+ c=0; do {
+ decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap);
+ out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N;
+ } while (++c<C);
+ lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+overlap)*C);
+ oldBandE = lpc+C*LPC_ORDER;
+ oldLogE = oldBandE + 2*nbEBands;
+ oldLogE2 = oldLogE + 2*nbEBands;
+ backgroundLogE = oldLogE2 + 2*nbEBands;
+
+ loss_count = st->loss_count;
+ start = st->start;
+ noise_based = loss_count >= 5 || start != 0 || st->skip_plc;
+ if (noise_based)
+ {
+ /* Noise-based PLC/CNG */
+#ifdef NORM_ALIASING_HACK
+ celt_norm *X;
+#else
+ VARDECL(celt_norm, X);
+#endif
+ opus_uint32 seed;
+ int end;
+ int effEnd;
+ opus_val16 decay;
+ end = st->end;
+ effEnd = IMAX(start, IMIN(end, mode->effEBands));
+
+#ifdef NORM_ALIASING_HACK
+ /* This is an ugly hack that breaks aliasing rules and would be easily broken,
+ but it saves almost 4kB of stack. */
+ X = (celt_norm*)(out_syn[C-1]+overlap/2);
+#else
+ ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */
+#endif
+
+ /* Energy decay */
+ decay = loss_count==0 ? QCONST16(1.5f, DB_SHIFT) : QCONST16(.5f, DB_SHIFT);
+ c=0; do
+ {
+ for (i=start;i<end;i++)
+ oldBandE[c*nbEBands+i] = MAX16(backgroundLogE[c*nbEBands+i], oldBandE[c*nbEBands+i] - decay);
+ } while (++c<C);
+ seed = st->rng;
+ for (c=0;c<C;c++)
+ {
+ for (i=start;i<effEnd;i++)
+ {
+ int j;
+ int boffs;
+ int blen;
+ boffs = N*c+(eBands[i]<<LM);
+ blen = (eBands[i+1]-eBands[i])<<LM;
+ for (j=0;j<blen;j++)
+ {
+ seed = celt_lcg_rand(seed);
+ X[boffs+j] = (celt_norm)((opus_int32)seed>>20);
+ }
+ renormalise_vector(X+boffs, blen, Q15ONE, st->arch);
+ }
+ }
+ st->rng = seed;
+
+ c=0; do {
+ OPUS_MOVE(decode_mem[c], decode_mem[c]+N,
+ DECODE_BUFFER_SIZE-N+(overlap>>1));
+ } while (++c<C);
+
+ celt_synthesis(mode, X, out_syn, oldBandE, start, effEnd, C, C, 0, LM, st->downsample, 0, st->arch);
+ } else {
+ /* Pitch-based PLC */
+ const opus_val16 *window;
+ opus_val16 fade = Q15ONE;
+ int pitch_index;
+ VARDECL(opus_val32, etmp);
+ VARDECL(opus_val16, exc);
+
+ if (loss_count == 0)
+ {
+ st->last_pitch_index = pitch_index = celt_plc_pitch_search(decode_mem, C, st->arch);
+ } else {
+ pitch_index = st->last_pitch_index;
+ fade = QCONST16(.8f,15);
+ }
+
+ ALLOC(etmp, overlap, opus_val32);
+ ALLOC(exc, MAX_PERIOD, opus_val16);
+ window = mode->window;
+ c=0; do {
+ opus_val16 decay;
+ opus_val16 attenuation;
+ opus_val32 S1=0;
+ celt_sig *buf;
+ int extrapolation_offset;
+ int extrapolation_len;
+ int exc_length;
+ int j;
+
+ buf = decode_mem[c];
+ for (i=0;i<MAX_PERIOD;i++) {
+ exc[i] = ROUND16(buf[DECODE_BUFFER_SIZE-MAX_PERIOD+i], SIG_SHIFT);
+ }
+
+ if (loss_count == 0)
+ {
+ opus_val32 ac[LPC_ORDER+1];
+ /* Compute LPC coefficients for the last MAX_PERIOD samples before
+ the first loss so we can work in the excitation-filter domain. */
+ _celt_autocorr(exc, ac, window, overlap,
+ LPC_ORDER, MAX_PERIOD, st->arch);
+ /* Add a noise floor of -40 dB. */
+#ifdef FIXED_POINT
+ ac[0] += SHR32(ac[0],13);
+#else
+ ac[0] *= 1.0001f;
+#endif
+ /* Use lag windowing to stabilize the Levinson-Durbin recursion. */
+ for (i=1;i<=LPC_ORDER;i++)
+ {
+ /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
+#ifdef FIXED_POINT
+ ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
+#else
+ ac[i] -= ac[i]*(0.008f*0.008f)*i*i;
+#endif
+ }
+ _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER);
+ }
+ /* We want the excitation for 2 pitch periods in order to look for a
+ decaying signal, but we can't get more than MAX_PERIOD. */
+ exc_length = IMIN(2*pitch_index, MAX_PERIOD);
+ /* Initialize the LPC history with the samples just before the start
+ of the region for which we're computing the excitation. */
+ {
+ opus_val16 lpc_mem[LPC_ORDER];
+ for (i=0;i<LPC_ORDER;i++)
+ {
+ lpc_mem[i] =
+ ROUND16(buf[DECODE_BUFFER_SIZE-exc_length-1-i], SIG_SHIFT);
+ }
+ /* Compute the excitation for exc_length samples before the loss. */
+ celt_fir(exc+MAX_PERIOD-exc_length, lpc+c*LPC_ORDER,
+ exc+MAX_PERIOD-exc_length, exc_length, LPC_ORDER, lpc_mem, st->arch);
+ }
+
+ /* Check if the waveform is decaying, and if so how fast.
+ We do this to avoid adding energy when concealing in a segment
+ with decaying energy. */
+ {
+ opus_val32 E1=1, E2=1;
+ int decay_length;
+#ifdef FIXED_POINT
+ int shift = IMAX(0,2*celt_zlog2(celt_maxabs16(&exc[MAX_PERIOD-exc_length], exc_length))-20);
+#endif
+ decay_length = exc_length>>1;
+ for (i=0;i<decay_length;i++)
+ {
+ opus_val16 e;
+ e = exc[MAX_PERIOD-decay_length+i];
+ E1 += SHR32(MULT16_16(e, e), shift);
+ e = exc[MAX_PERIOD-2*decay_length+i];
+ E2 += SHR32(MULT16_16(e, e), shift);
+ }
+ E1 = MIN32(E1, E2);
+ decay = celt_sqrt(frac_div32(SHR32(E1, 1), E2));
+ }
+
+ /* Move the decoder memory one frame to the left to give us room to
+ add the data for the new frame. We ignore the overlap that extends
+ past the end of the buffer, because we aren't going to use it. */
+ OPUS_MOVE(buf, buf+N, DECODE_BUFFER_SIZE-N);
+
+ /* Extrapolate from the end of the excitation with a period of
+ "pitch_index", scaling down each period by an additional factor of
+ "decay". */
+ extrapolation_offset = MAX_PERIOD-pitch_index;
+ /* We need to extrapolate enough samples to cover a complete MDCT
+ window (including overlap/2 samples on both sides). */
+ extrapolation_len = N+overlap;
+ /* We also apply fading if this is not the first loss. */
+ attenuation = MULT16_16_Q15(fade, decay);
+ for (i=j=0;i<extrapolation_len;i++,j++)
+ {
+ opus_val16 tmp;
+ if (j >= pitch_index) {
+ j -= pitch_index;
+ attenuation = MULT16_16_Q15(attenuation, decay);
+ }
+ buf[DECODE_BUFFER_SIZE-N+i] =
+ SHL32(EXTEND32(MULT16_16_Q15(attenuation,
+ exc[extrapolation_offset+j])), SIG_SHIFT);
+ /* Compute the energy of the previously decoded signal whose
+ excitation we're copying. */
+ tmp = ROUND16(
+ buf[DECODE_BUFFER_SIZE-MAX_PERIOD-N+extrapolation_offset+j],
+ SIG_SHIFT);
+ S1 += SHR32(MULT16_16(tmp, tmp), 8);
+ }
+
+ {
+ opus_val16 lpc_mem[LPC_ORDER];
+ /* Copy the last decoded samples (prior to the overlap region) to
+ synthesis filter memory so we can have a continuous signal. */
+ for (i=0;i<LPC_ORDER;i++)
+ lpc_mem[i] = ROUND16(buf[DECODE_BUFFER_SIZE-N-1-i], SIG_SHIFT);
+ /* Apply the synthesis filter to convert the excitation back into
+ the signal domain. */
+ celt_iir(buf+DECODE_BUFFER_SIZE-N, lpc+c*LPC_ORDER,
+ buf+DECODE_BUFFER_SIZE-N, extrapolation_len, LPC_ORDER,
+ lpc_mem, st->arch);
+ }
+
+ /* Check if the synthesis energy is higher than expected, which can
+ happen with the signal changes during our window. If so,
+ attenuate. */
+ {
+ opus_val32 S2=0;
+ for (i=0;i<extrapolation_len;i++)
+ {
+ opus_val16 tmp = ROUND16(buf[DECODE_BUFFER_SIZE-N+i], SIG_SHIFT);
+ S2 += SHR32(MULT16_16(tmp, tmp), 8);
+ }
+ /* This checks for an "explosion" in the synthesis. */
+#ifdef FIXED_POINT
+ if (!(S1 > SHR32(S2,2)))
+#else
+ /* The float test is written this way to catch NaNs in the output
+ of the IIR filter at the same time. */
+ if (!(S1 > 0.2f*S2))
+#endif
+ {
+ for (i=0;i<extrapolation_len;i++)
+ buf[DECODE_BUFFER_SIZE-N+i] = 0;
+ } else if (S1 < S2)
+ {
+ opus_val16 ratio = celt_sqrt(frac_div32(SHR32(S1,1)+1,S2+1));
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 tmp_g = Q15ONE
+ - MULT16_16_Q15(window[i], Q15ONE-ratio);
+ buf[DECODE_BUFFER_SIZE-N+i] =
+ MULT16_32_Q15(tmp_g, buf[DECODE_BUFFER_SIZE-N+i]);
+ }
+ for (i=overlap;i<extrapolation_len;i++)
+ {
+ buf[DECODE_BUFFER_SIZE-N+i] =
+ MULT16_32_Q15(ratio, buf[DECODE_BUFFER_SIZE-N+i]);
+ }
+ }
+ }
+
+ /* Apply the pre-filter to the MDCT overlap for the next frame because
+ the post-filter will be re-applied in the decoder after the MDCT
+ overlap. */
+ comb_filter(etmp, buf+DECODE_BUFFER_SIZE,
+ st->postfilter_period, st->postfilter_period, overlap,
+ -st->postfilter_gain, -st->postfilter_gain,
+ st->postfilter_tapset, st->postfilter_tapset, NULL, 0, st->arch);
+
+ /* Simulate TDAC on the concealed audio so that it blends with the
+ MDCT of the next frame. */
+ for (i=0;i<overlap/2;i++)
+ {
+ buf[DECODE_BUFFER_SIZE+i] =
+ MULT16_32_Q15(window[i], etmp[overlap-1-i])
+ + MULT16_32_Q15(window[overlap-i-1], etmp[i]);
+ }
+ } while (++c<C);
+ }
+
+ st->loss_count = loss_count+1;
+
+ RESTORE_STACK;
+}
+
+int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data,
+ int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum)
+{
+ int c, i, N;
+ int spread_decision;
+ opus_int32 bits;
+ ec_dec _dec;
+#ifdef NORM_ALIASING_HACK
+ celt_norm *X;
+#else
+ VARDECL(celt_norm, X);
+#endif
+ VARDECL(int, fine_quant);
+ VARDECL(int, pulses);
+ VARDECL(int, cap);
+ VARDECL(int, offsets);
+ VARDECL(int, fine_priority);
+ VARDECL(int, tf_res);
+ VARDECL(unsigned char, collapse_masks);
+ celt_sig *decode_mem[2];
+ celt_sig *out_syn[2];
+ opus_val16 *lpc;
+ opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE;
+
+ int shortBlocks;
+ int isTransient;
+ int intra_ener;
+ const int CC = st->channels;
+ int LM, M;
+ int start;
+ int end;
+ int effEnd;
+ int codedBands;
+ int alloc_trim;
+ int postfilter_pitch;
+ opus_val16 postfilter_gain;
+ int intensity=0;
+ int dual_stereo=0;
+ opus_int32 total_bits;
+ opus_int32 balance;
+ opus_int32 tell;
+ int dynalloc_logp;
+ int postfilter_tapset;
+ int anti_collapse_rsv;
+ int anti_collapse_on=0;
+ int silence;
+ int C = st->stream_channels;
+ const OpusCustomMode *mode;
+ int nbEBands;
+ int overlap;
+ const opus_int16 *eBands;
+ ALLOC_STACK;
+
+ mode = st->mode;
+ nbEBands = mode->nbEBands;
+ overlap = mode->overlap;
+ eBands = mode->eBands;
+ start = st->start;
+ end = st->end;
+ frame_size *= st->downsample;
+
+ lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+overlap)*CC);
+ oldBandE = lpc+CC*LPC_ORDER;
+ oldLogE = oldBandE + 2*nbEBands;
+ oldLogE2 = oldLogE + 2*nbEBands;
+ backgroundLogE = oldLogE2 + 2*nbEBands;
+
+#ifdef CUSTOM_MODES
+ if (st->signalling && data!=NULL)
+ {
+ int data0=data[0];
+ /* Convert "standard mode" to Opus header */
+ if (mode->Fs==48000 && mode->shortMdctSize==120)
+ {
+ data0 = fromOpus(data0);
+ if (data0<0)
+ return OPUS_INVALID_PACKET;
+ }
+ st->end = end = IMAX(1, mode->effEBands-2*(data0>>5));
+ LM = (data0>>3)&0x3;
+ C = 1 + ((data0>>2)&0x1);
+ data++;
+ len--;
+ if (LM>mode->maxLM)
+ return OPUS_INVALID_PACKET;
+ if (frame_size < mode->shortMdctSize<<LM)
+ return OPUS_BUFFER_TOO_SMALL;
+ else
+ frame_size = mode->shortMdctSize<<LM;
+ } else {
+#else
+ {
+#endif
+ for (LM=0;LM<=mode->maxLM;LM++)
+ if (mode->shortMdctSize<<LM==frame_size)
+ break;
+ if (LM>mode->maxLM)
+ return OPUS_BAD_ARG;
+ }
+ M=1<<LM;
+
+ if (len<0 || len>1275 || pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ N = M*mode->shortMdctSize;
+ c=0; do {
+ decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap);
+ out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N;
+ } while (++c<CC);
+
+ effEnd = end;
+ if (effEnd > mode->effEBands)
+ effEnd = mode->effEBands;
+
+ if (data == NULL || len<=1)
+ {
+ celt_decode_lost(st, N, LM);
+ deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum);
+ RESTORE_STACK;
+ return frame_size/st->downsample;
+ }
+
+ /* Check if there are at least two packets received consecutively before
+ * turning on the pitch-based PLC */
+ st->skip_plc = st->loss_count != 0;
+
+ if (dec == NULL)
+ {
+ ec_dec_init(&_dec,(unsigned char*)data,len);
+ dec = &_dec;
+ }
+
+ if (C==1)
+ {
+ for (i=0;i<nbEBands;i++)
+ oldBandE[i]=MAX16(oldBandE[i],oldBandE[nbEBands+i]);
+ }
+
+ total_bits = len*8;
+ tell = ec_tell(dec);
+
+ if (tell >= total_bits)
+ silence = 1;
+ else if (tell==1)
+ silence = ec_dec_bit_logp(dec, 15);
+ else
+ silence = 0;
+ if (silence)
+ {
+ /* Pretend we've read all the remaining bits */
+ tell = len*8;
+ dec->nbits_total+=tell-ec_tell(dec);
+ }
+
+ postfilter_gain = 0;
+ postfilter_pitch = 0;
+ postfilter_tapset = 0;
+ if (start==0 && tell+16 <= total_bits)
+ {
+ if(ec_dec_bit_logp(dec, 1))
+ {
+ int qg, octave;
+ octave = ec_dec_uint(dec, 6);
+ postfilter_pitch = (16<<octave)+ec_dec_bits(dec, 4+octave)-1;
+ qg = ec_dec_bits(dec, 3);
+ if (ec_tell(dec)+2<=total_bits)
+ postfilter_tapset = ec_dec_icdf(dec, tapset_icdf, 2);
+ postfilter_gain = QCONST16(.09375f,15)*(qg+1);
+ }
+ tell = ec_tell(dec);
+ }
+
+ if (LM > 0 && tell+3 <= total_bits)
+ {
+ isTransient = ec_dec_bit_logp(dec, 3);
+ tell = ec_tell(dec);
+ }
+ else
+ isTransient = 0;
+
+ if (isTransient)
+ shortBlocks = M;
+ else
+ shortBlocks = 0;
+
+ /* Decode the global flags (first symbols in the stream) */
+ intra_ener = tell+3<=total_bits ? ec_dec_bit_logp(dec, 3) : 0;
+ /* Get band energies */
+ unquant_coarse_energy(mode, start, end, oldBandE,
+ intra_ener, dec, C, LM);
+
+ ALLOC(tf_res, nbEBands, int);
+ tf_decode(start, end, isTransient, tf_res, LM, dec);
+
+ tell = ec_tell(dec);
+ spread_decision = SPREAD_NORMAL;
+ if (tell+4 <= total_bits)
+ spread_decision = ec_dec_icdf(dec, spread_icdf, 5);
+
+ ALLOC(cap, nbEBands, int);
+
+ init_caps(mode,cap,LM,C);
+
+ ALLOC(offsets, nbEBands, int);
+
+ dynalloc_logp = 6;
+ total_bits<<=BITRES;
+ tell = ec_tell_frac(dec);
+ for (i=start;i<end;i++)
+ {
+ int width, quanta;
+ int dynalloc_loop_logp;
+ int boost;
+ width = C*(eBands[i+1]-eBands[i])<<LM;
+ /* quanta is 6 bits, but no more than 1 bit/sample
+ and no less than 1/8 bit/sample */
+ quanta = IMIN(width<<BITRES, IMAX(6<<BITRES, width));
+ dynalloc_loop_logp = dynalloc_logp;
+ boost = 0;
+ while (tell+(dynalloc_loop_logp<<BITRES) < total_bits && boost < cap[i])
+ {
+ int flag;
+ flag = ec_dec_bit_logp(dec, dynalloc_loop_logp);
+ tell = ec_tell_frac(dec);
+ if (!flag)
+ break;
+ boost += quanta;
+ total_bits -= quanta;
+ dynalloc_loop_logp = 1;
+ }
+ offsets[i] = boost;
+ /* Making dynalloc more likely */
+ if (boost>0)
+ dynalloc_logp = IMAX(2, dynalloc_logp-1);
+ }
+
+ ALLOC(fine_quant, nbEBands, int);
+ alloc_trim = tell+(6<<BITRES) <= total_bits ?
+ ec_dec_icdf(dec, trim_icdf, 7) : 5;
+
+ bits = (((opus_int32)len*8)<<BITRES) - ec_tell_frac(dec) - 1;
+ anti_collapse_rsv = isTransient&&LM>=2&&bits>=((LM+2)<<BITRES) ? (1<<BITRES) : 0;
+ bits -= anti_collapse_rsv;
+
+ ALLOC(pulses, nbEBands, int);
+ ALLOC(fine_priority, nbEBands, int);
+
+ codedBands = compute_allocation(mode, start, end, offsets, cap,
+ alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses,
+ fine_quant, fine_priority, C, LM, dec, 0, 0, 0);
+
+ unquant_fine_energy(mode, start, end, oldBandE, fine_quant, dec, C);
+
+ c=0; do {
+ OPUS_MOVE(decode_mem[c], decode_mem[c]+N, DECODE_BUFFER_SIZE-N+overlap/2);
+ } while (++c<CC);
+
+ /* Decode fixed codebook */
+ ALLOC(collapse_masks, C*nbEBands, unsigned char);
+
+#ifdef NORM_ALIASING_HACK
+ /* This is an ugly hack that breaks aliasing rules and would be easily broken,
+ but it saves almost 4kB of stack. */
+ X = (celt_norm*)(out_syn[CC-1]+overlap/2);
+#else
+ ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */
+#endif
+
+ quant_all_bands(0, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks,
+ NULL, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res,
+ len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng, st->arch);
+
+ if (anti_collapse_rsv > 0)
+ {
+ anti_collapse_on = ec_dec_bits(dec, 1);
+ }
+
+ unquant_energy_finalise(mode, start, end, oldBandE,
+ fine_quant, fine_priority, len*8-ec_tell(dec), dec, C);
+
+ if (anti_collapse_on)
+ anti_collapse(mode, X, collapse_masks, LM, C, N,
+ start, end, oldBandE, oldLogE, oldLogE2, pulses, st->rng, st->arch);
+
+ if (silence)
+ {
+ for (i=0;i<C*nbEBands;i++)
+ oldBandE[i] = -QCONST16(28.f,DB_SHIFT);
+ }
+
+ celt_synthesis(mode, X, out_syn, oldBandE, start, effEnd,
+ C, CC, isTransient, LM, st->downsample, silence, st->arch);
+
+ c=0; do {
+ st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD);
+ st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD);
+ comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, mode->shortMdctSize,
+ st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset,
+ mode->window, overlap, st->arch);
+ if (LM!=0)
+ comb_filter(out_syn[c]+mode->shortMdctSize, out_syn[c]+mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-mode->shortMdctSize,
+ st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset,
+ mode->window, overlap, st->arch);
+
+ } while (++c<CC);
+ st->postfilter_period_old = st->postfilter_period;
+ st->postfilter_gain_old = st->postfilter_gain;
+ st->postfilter_tapset_old = st->postfilter_tapset;
+ st->postfilter_period = postfilter_pitch;
+ st->postfilter_gain = postfilter_gain;
+ st->postfilter_tapset = postfilter_tapset;
+ if (LM!=0)
+ {
+ st->postfilter_period_old = st->postfilter_period;
+ st->postfilter_gain_old = st->postfilter_gain;
+ st->postfilter_tapset_old = st->postfilter_tapset;
+ }
+
+ if (C==1)
+ OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands);
+
+ /* In case start or end were to change */
+ if (!isTransient)
+ {
+ opus_val16 max_background_increase;
+ OPUS_COPY(oldLogE2, oldLogE, 2*nbEBands);
+ OPUS_COPY(oldLogE, oldBandE, 2*nbEBands);
+ /* In normal circumstances, we only allow the noise floor to increase by
+ up to 2.4 dB/second, but when we're in DTX, we allow up to 6 dB
+ increase for each update.*/
+ if (st->loss_count < 10)
+ max_background_increase = M*QCONST16(0.001f,DB_SHIFT);
+ else
+ max_background_increase = QCONST16(1.f,DB_SHIFT);
+ for (i=0;i<2*nbEBands;i++)
+ backgroundLogE[i] = MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]);
+ } else {
+ for (i=0;i<2*nbEBands;i++)
+ oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]);
+ }
+ c=0; do
+ {
+ for (i=0;i<start;i++)
+ {
+ oldBandE[c*nbEBands+i]=0;
+ oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+ }
+ for (i=end;i<nbEBands;i++)
+ {
+ oldBandE[c*nbEBands+i]=0;
+ oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+ }
+ } while (++c<2);
+ st->rng = dec->rng;
+
+ deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum);
+ st->loss_count = 0;
+ RESTORE_STACK;
+ if (ec_tell(dec) > 8*len)
+ return OPUS_INTERNAL_ERROR;
+ if(ec_get_error(dec))
+ st->error = 1;
+ return frame_size/st->downsample;
+}
+
+
+#ifdef CUSTOM_MODES
+
+#ifdef FIXED_POINT
+int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size)
+{
+ return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL, 0);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size)
+{
+ int j, ret, C, N;
+ VARDECL(opus_int16, out);
+ ALLOC_STACK;
+
+ if (pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ C = st->channels;
+ N = frame_size;
+
+ ALLOC(out, C*N, opus_int16);
+ ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0);
+ if (ret>0)
+ for (j=0;j<C*ret;j++)
+ pcm[j]=out[j]*(1.f/32768.f);
+
+ RESTORE_STACK;
+ return ret;
+}
+#endif /* DISABLE_FLOAT_API */
+
+#else
+
+int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size)
+{
+ return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL, 0);
+}
+
+int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size)
+{
+ int j, ret, C, N;
+ VARDECL(celt_sig, out);
+ ALLOC_STACK;
+
+ if (pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ C = st->channels;
+ N = frame_size;
+ ALLOC(out, C*N, celt_sig);
+
+ ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0);
+
+ if (ret>0)
+ for (j=0;j<C*ret;j++)
+ pcm[j] = FLOAT2INT16 (out[j]);
+
+ RESTORE_STACK;
+ return ret;
+}
+
+#endif
+#endif /* CUSTOM_MODES */
+
+int opus_custom_decoder_ctl(CELTDecoder * OPUS_RESTRICT st, int request, ...)
+{
+ va_list ap;
+
+ va_start(ap, request);
+ switch (request)
+ {
+ case CELT_SET_START_BAND_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<0 || value>=st->mode->nbEBands)
+ goto bad_arg;
+ st->start = value;
+ }
+ break;
+ case CELT_SET_END_BAND_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<1 || value>st->mode->nbEBands)
+ goto bad_arg;
+ st->end = value;
+ }
+ break;
+ case CELT_SET_CHANNELS_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<1 || value>2)
+ goto bad_arg;
+ st->stream_channels = value;
+ }
+ break;
+ case CELT_GET_AND_CLEAR_ERROR_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (value==NULL)
+ goto bad_arg;
+ *value=st->error;
+ st->error = 0;
+ }
+ break;
+ case OPUS_GET_LOOKAHEAD_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (value==NULL)
+ goto bad_arg;
+ *value = st->overlap/st->downsample;
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ int i;
+ opus_val16 *lpc, *oldBandE, *oldLogE, *oldLogE2;
+ lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*st->channels);
+ oldBandE = lpc+st->channels*LPC_ORDER;
+ oldLogE = oldBandE + 2*st->mode->nbEBands;
+ oldLogE2 = oldLogE + 2*st->mode->nbEBands;
+ OPUS_CLEAR((char*)&st->DECODER_RESET_START,
+ opus_custom_decoder_get_size(st->mode, st->channels)-
+ ((char*)&st->DECODER_RESET_START - (char*)st));
+ for (i=0;i<2*st->mode->nbEBands;i++)
+ oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT);
+ st->skip_plc = 1;
+ }
+ break;
+ case OPUS_GET_PITCH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (value==NULL)
+ goto bad_arg;
+ *value = st->postfilter_period;
+ }
+ break;
+ case CELT_GET_MODE_REQUEST:
+ {
+ const CELTMode ** value = va_arg(ap, const CELTMode**);
+ if (value==0)
+ goto bad_arg;
+ *value=st->mode;
+ }
+ break;
+ case CELT_SET_SIGNALLING_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->signalling = value;
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ opus_uint32 * value = va_arg(ap, opus_uint32 *);
+ if (value==0)
+ goto bad_arg;
+ *value=st->rng;
+ }
+ break;
+ default:
+ goto bad_request;
+ }
+ va_end(ap);
+ return OPUS_OK;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+bad_request:
+ va_end(ap);
+ return OPUS_UNIMPLEMENTED;
+}
diff --git a/external/opus-1.1.4/celt/celt_encoder.c b/external/opus-1.1.4/celt/celt_encoder.c
new file mode 100644
index 0000000..3ee7a4d
--- /dev/null
+++ b/external/opus-1.1.4/celt/celt_encoder.c
@@ -0,0 +1,2410 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2010 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CELT_ENCODER_C
+
+#include "cpu_support.h"
+#include "os_support.h"
+#include "mdct.h"
+#include <math.h>
+#include "celt.h"
+#include "pitch.h"
+#include "bands.h"
+#include "modes.h"
+#include "entcode.h"
+#include "quant_bands.h"
+#include "rate.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "float_cast.h"
+#include <stdarg.h>
+#include "celt_lpc.h"
+#include "vq.h"
+
+
+/** Encoder state
+ @brief Encoder state
+ */
+struct OpusCustomEncoder {
+ const OpusCustomMode *mode; /**< Mode used by the encoder */
+ int channels;
+ int stream_channels;
+
+ int force_intra;
+ int clip;
+ int disable_pf;
+ int complexity;
+ int upsample;
+ int start, end;
+
+ opus_int32 bitrate;
+ int vbr;
+ int signalling;
+ int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */
+ int loss_rate;
+ int lsb_depth;
+ int variable_duration;
+ int lfe;
+ int arch;
+
+ /* Everything beyond this point gets cleared on a reset */
+#define ENCODER_RESET_START rng
+
+ opus_uint32 rng;
+ int spread_decision;
+ opus_val32 delayedIntra;
+ int tonal_average;
+ int lastCodedBands;
+ int hf_average;
+ int tapset_decision;
+
+ int prefilter_period;
+ opus_val16 prefilter_gain;
+ int prefilter_tapset;
+#ifdef RESYNTH
+ int prefilter_period_old;
+ opus_val16 prefilter_gain_old;
+ int prefilter_tapset_old;
+#endif
+ int consec_transient;
+ AnalysisInfo analysis;
+
+ opus_val32 preemph_memE[2];
+ opus_val32 preemph_memD[2];
+
+ /* VBR-related parameters */
+ opus_int32 vbr_reservoir;
+ opus_int32 vbr_drift;
+ opus_int32 vbr_offset;
+ opus_int32 vbr_count;
+ opus_val32 overlap_max;
+ opus_val16 stereo_saving;
+ int intensity;
+ opus_val16 *energy_mask;
+ opus_val16 spec_avg;
+
+#ifdef RESYNTH
+ /* +MAX_PERIOD/2 to make space for overlap */
+ celt_sig syn_mem[2][2*MAX_PERIOD+MAX_PERIOD/2];
+#endif
+
+ celt_sig in_mem[1]; /* Size = channels*mode->overlap */
+ /* celt_sig prefilter_mem[], Size = channels*COMBFILTER_MAXPERIOD */
+ /* opus_val16 oldBandE[], Size = channels*mode->nbEBands */
+ /* opus_val16 oldLogE[], Size = channels*mode->nbEBands */
+ /* opus_val16 oldLogE2[], Size = channels*mode->nbEBands */
+};
+
+int celt_encoder_get_size(int channels)
+{
+ CELTMode *mode = opus_custom_mode_create(48000, 960, NULL);
+ return opus_custom_encoder_get_size(mode, channels);
+}
+
+OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int channels)
+{
+ int size = sizeof(struct CELTEncoder)
+ + (channels*mode->overlap-1)*sizeof(celt_sig) /* celt_sig in_mem[channels*mode->overlap]; */
+ + channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig) /* celt_sig prefilter_mem[channels*COMBFILTER_MAXPERIOD]; */
+ + 3*channels*mode->nbEBands*sizeof(opus_val16); /* opus_val16 oldBandE[channels*mode->nbEBands]; */
+ /* opus_val16 oldLogE[channels*mode->nbEBands]; */
+ /* opus_val16 oldLogE2[channels*mode->nbEBands]; */
+ return size;
+}
+
+#ifdef CUSTOM_MODES
+CELTEncoder *opus_custom_encoder_create(const CELTMode *mode, int channels, int *error)
+{
+ int ret;
+ CELTEncoder *st = (CELTEncoder *)opus_alloc(opus_custom_encoder_get_size(mode, channels));
+ /* init will handle the NULL case */
+ ret = opus_custom_encoder_init(st, mode, channels);
+ if (ret != OPUS_OK)
+ {
+ opus_custom_encoder_destroy(st);
+ st = NULL;
+ }
+ if (error)
+ *error = ret;
+ return st;
+}
+#endif /* CUSTOM_MODES */
+
+static int opus_custom_encoder_init_arch(CELTEncoder *st, const CELTMode *mode,
+ int channels, int arch)
+{
+ if (channels < 0 || channels > 2)
+ return OPUS_BAD_ARG;
+
+ if (st==NULL || mode==NULL)
+ return OPUS_ALLOC_FAIL;
+
+ OPUS_CLEAR((char*)st, opus_custom_encoder_get_size(mode, channels));
+
+ st->mode = mode;
+ st->stream_channels = st->channels = channels;
+
+ st->upsample = 1;
+ st->start = 0;
+ st->end = st->mode->effEBands;
+ st->signalling = 1;
+
+ st->arch = arch;
+
+ st->constrained_vbr = 1;
+ st->clip = 1;
+
+ st->bitrate = OPUS_BITRATE_MAX;
+ st->vbr = 0;
+ st->force_intra = 0;
+ st->complexity = 5;
+ st->lsb_depth=24;
+
+ opus_custom_encoder_ctl(st, OPUS_RESET_STATE);
+
+ return OPUS_OK;
+}
+
+#ifdef CUSTOM_MODES
+int opus_custom_encoder_init(CELTEncoder *st, const CELTMode *mode, int channels)
+{
+ return opus_custom_encoder_init_arch(st, mode, channels, opus_select_arch());
+}
+#endif
+
+int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels,
+ int arch)
+{
+ int ret;
+ ret = opus_custom_encoder_init_arch(st,
+ opus_custom_mode_create(48000, 960, NULL), channels, arch);
+ if (ret != OPUS_OK)
+ return ret;
+ st->upsample = resampling_factor(sampling_rate);
+ return OPUS_OK;
+}
+
+#ifdef CUSTOM_MODES
+void opus_custom_encoder_destroy(CELTEncoder *st)
+{
+ opus_free(st);
+}
+#endif /* CUSTOM_MODES */
+
+
+static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int C,
+ opus_val16 *tf_estimate, int *tf_chan)
+{
+ int i;
+ VARDECL(opus_val16, tmp);
+ opus_val32 mem0,mem1;
+ int is_transient = 0;
+ opus_int32 mask_metric = 0;
+ int c;
+ opus_val16 tf_max;
+ int len2;
+ /* Table of 6*64/x, trained on real data to minimize the average error */
+ static const unsigned char inv_table[128] = {
+ 255,255,156,110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25,
+ 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,
+ 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8,
+ 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 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, 3, 3, 3, 2,
+ };
+ SAVE_STACK;
+ ALLOC(tmp, len, opus_val16);
+
+ len2=len/2;
+ for (c=0;c<C;c++)
+ {
+ opus_val32 mean;
+ opus_int32 unmask=0;
+ opus_val32 norm;
+ opus_val16 maxE;
+ mem0=0;
+ mem1=0;
+ /* High-pass filter: (1 - 2*z^-1 + z^-2) / (1 - z^-1 + .5*z^-2) */
+ for (i=0;i<len;i++)
+ {
+ opus_val32 x,y;
+ x = SHR32(in[i+c*len],SIG_SHIFT);
+ y = ADD32(mem0, x);
+#ifdef FIXED_POINT
+ mem0 = mem1 + y - SHL32(x,1);
+ mem1 = x - SHR32(y,1);
+#else
+ mem0 = mem1 + y - 2*x;
+ mem1 = x - .5f*y;
+#endif
+ tmp[i] = EXTRACT16(SHR32(y,2));
+ /*printf("%f ", tmp[i]);*/
+ }
+ /*printf("\n");*/
+ /* First few samples are bad because we don't propagate the memory */
+ OPUS_CLEAR(tmp, 12);
+
+#ifdef FIXED_POINT
+ /* Normalize tmp to max range */
+ {
+ int shift=0;
+ shift = 14-celt_ilog2(1+celt_maxabs16(tmp, len));
+ if (shift!=0)
+ {
+ for (i=0;i<len;i++)
+ tmp[i] = SHL16(tmp[i], shift);
+ }
+ }
+#endif
+
+ mean=0;
+ mem0=0;
+ /* Grouping by two to reduce complexity */
+ /* Forward pass to compute the post-echo threshold*/
+ for (i=0;i<len2;i++)
+ {
+ opus_val16 x2 = PSHR32(MULT16_16(tmp[2*i],tmp[2*i]) + MULT16_16(tmp[2*i+1],tmp[2*i+1]),16);
+ mean += x2;
+#ifdef FIXED_POINT
+ /* FIXME: Use PSHR16() instead */
+ tmp[i] = mem0 + PSHR32(x2-mem0,4);
+#else
+ tmp[i] = mem0 + MULT16_16_P15(QCONST16(.0625f,15),x2-mem0);
+#endif
+ mem0 = tmp[i];
+ }
+
+ mem0=0;
+ maxE=0;
+ /* Backward pass to compute the pre-echo threshold */
+ for (i=len2-1;i>=0;i--)
+ {
+#ifdef FIXED_POINT
+ /* FIXME: Use PSHR16() instead */
+ tmp[i] = mem0 + PSHR32(tmp[i]-mem0,3);
+#else
+ tmp[i] = mem0 + MULT16_16_P15(QCONST16(0.125f,15),tmp[i]-mem0);
+#endif
+ mem0 = tmp[i];
+ maxE = MAX16(maxE, mem0);
+ }
+ /*for (i=0;i<len2;i++)printf("%f ", tmp[i]/mean);printf("\n");*/
+
+ /* Compute the ratio of the "frame energy" over the harmonic mean of the energy.
+ This essentially corresponds to a bitrate-normalized temporal noise-to-mask
+ ratio */
+
+ /* As a compromise with the old transient detector, frame energy is the
+ geometric mean of the energy and half the max */
+#ifdef FIXED_POINT
+ /* Costs two sqrt() to avoid overflows */
+ mean = MULT16_16(celt_sqrt(mean), celt_sqrt(MULT16_16(maxE,len2>>1)));
+#else
+ mean = celt_sqrt(mean * maxE*.5*len2);
+#endif
+ /* Inverse of the mean energy in Q15+6 */
+ norm = SHL32(EXTEND32(len2),6+14)/ADD32(EPSILON,SHR32(mean,1));
+ /* Compute harmonic mean discarding the unreliable boundaries
+ The data is smooth, so we only take 1/4th of the samples */
+ unmask=0;
+ for (i=12;i<len2-5;i+=4)
+ {
+ int id;
+#ifdef FIXED_POINT
+ id = MAX32(0,MIN32(127,MULT16_32_Q15(tmp[i]+EPSILON,norm))); /* Do not round to nearest */
+#else
+ id = (int)MAX32(0,MIN32(127,floor(64*norm*(tmp[i]+EPSILON)))); /* Do not round to nearest */
+#endif
+ unmask += inv_table[id];
+ }
+ /*printf("%d\n", unmask);*/
+ /* Normalize, compensate for the 1/4th of the sample and the factor of 6 in the inverse table */
+ unmask = 64*unmask*4/(6*(len2-17));
+ if (unmask>mask_metric)
+ {
+ *tf_chan = c;
+ mask_metric = unmask;
+ }
+ }
+ is_transient = mask_metric>200;
+
+ /* Arbitrary metric for VBR boost */
+ tf_max = MAX16(0,celt_sqrt(27*mask_metric)-42);
+ /* *tf_estimate = 1 + MIN16(1, sqrt(MAX16(0, tf_max-30))/20); */
+ *tf_estimate = celt_sqrt(MAX32(0, SHL32(MULT16_16(QCONST16(0.0069,14),MIN16(163,tf_max)),14)-QCONST32(0.139,28)));
+ /*printf("%d %f\n", tf_max, mask_metric);*/
+ RESTORE_STACK;
+#ifdef FUZZING
+ is_transient = rand()&0x1;
+#endif
+ /*printf("%d %f %d\n", is_transient, (float)*tf_estimate, tf_max);*/
+ return is_transient;
+}
+
+/* Looks for sudden increases of energy to decide whether we need to patch
+ the transient decision */
+static int patch_transient_decision(opus_val16 *newE, opus_val16 *oldE, int nbEBands,
+ int start, int end, int C)
+{
+ int i, c;
+ opus_val32 mean_diff=0;
+ opus_val16 spread_old[26];
+ /* Apply an aggressive (-6 dB/Bark) spreading function to the old frame to
+ avoid false detection caused by irrelevant bands */
+ if (C==1)
+ {
+ spread_old[start] = oldE[start];
+ for (i=start+1;i<end;i++)
+ spread_old[i] = MAX16(spread_old[i-1]-QCONST16(1.0f, DB_SHIFT), oldE[i]);
+ } else {
+ spread_old[start] = MAX16(oldE[start],oldE[start+nbEBands]);
+ for (i=start+1;i<end;i++)
+ spread_old[i] = MAX16(spread_old[i-1]-QCONST16(1.0f, DB_SHIFT),
+ MAX16(oldE[i],oldE[i+nbEBands]));
+ }
+ for (i=end-2;i>=start;i--)
+ spread_old[i] = MAX16(spread_old[i], spread_old[i+1]-QCONST16(1.0f, DB_SHIFT));
+ /* Compute mean increase */
+ c=0; do {
+ for (i=IMAX(2,start);i<end-1;i++)
+ {
+ opus_val16 x1, x2;
+ x1 = MAX16(0, newE[i + c*nbEBands]);
+ x2 = MAX16(0, spread_old[i]);
+ mean_diff = ADD32(mean_diff, EXTEND32(MAX16(0, SUB16(x1, x2))));
+ }
+ } while (++c<C);
+ mean_diff = DIV32(mean_diff, C*(end-1-IMAX(2,start)));
+ /*printf("%f %f %d\n", mean_diff, max_diff, count);*/
+ return mean_diff > QCONST16(1.f, DB_SHIFT);
+}
+
+/** Apply window and compute the MDCT for all sub-frames and
+ all channels in a frame */
+static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * OPUS_RESTRICT in,
+ celt_sig * OPUS_RESTRICT out, int C, int CC, int LM, int upsample,
+ int arch)
+{
+ const int overlap = mode->overlap;
+ int N;
+ int B;
+ int shift;
+ int i, b, c;
+ if (shortBlocks)
+ {
+ B = shortBlocks;
+ N = mode->shortMdctSize;
+ shift = mode->maxLM;
+ } else {
+ B = 1;
+ N = mode->shortMdctSize<<LM;
+ shift = mode->maxLM-LM;
+ }
+ c=0; do {
+ for (b=0;b<B;b++)
+ {
+ /* Interleaving the sub-frames while doing the MDCTs */
+ clt_mdct_forward(&mode->mdct, in+c*(B*N+overlap)+b*N,
+ &out[b+c*N*B], mode->window, overlap, shift, B,
+ arch);
+ }
+ } while (++c<CC);
+ if (CC==2&&C==1)
+ {
+ for (i=0;i<B*N;i++)
+ out[i] = ADD32(HALF32(out[i]), HALF32(out[B*N+i]));
+ }
+ if (upsample != 1)
+ {
+ c=0; do
+ {
+ int bound = B*N/upsample;
+ for (i=0;i<bound;i++)
+ out[c*B*N+i] *= upsample;
+ OPUS_CLEAR(&out[c*B*N+bound], B*N-bound);
+ } while (++c<C);
+ }
+}
+
+
+void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
+ int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip)
+{
+ int i;
+ opus_val16 coef0;
+ celt_sig m;
+ int Nu;
+
+ coef0 = coef[0];
+ m = *mem;
+
+ /* Fast path for the normal 48kHz case and no clipping */
+ if (coef[1] == 0 && upsample == 1 && !clip)
+ {
+ for (i=0;i<N;i++)
+ {
+ opus_val16 x;
+ x = SCALEIN(pcmp[CC*i]);
+ /* Apply pre-emphasis */
+ inp[i] = SHL32(x, SIG_SHIFT) - m;
+ m = SHR32(MULT16_16(coef0, x), 15-SIG_SHIFT);
+ }
+ *mem = m;
+ return;
+ }
+
+ Nu = N/upsample;
+ if (upsample!=1)
+ {
+ OPUS_CLEAR(inp, N);
+ }
+ for (i=0;i<Nu;i++)
+ inp[i*upsample] = SCALEIN(pcmp[CC*i]);
+
+#ifndef FIXED_POINT
+ if (clip)
+ {
+ /* Clip input to avoid encoding non-portable files */
+ for (i=0;i<Nu;i++)
+ inp[i*upsample] = MAX32(-65536.f, MIN32(65536.f,inp[i*upsample]));
+ }
+#else
+ (void)clip; /* Avoids a warning about clip being unused. */
+#endif
+#ifdef CUSTOM_MODES
+ if (coef[1] != 0)
+ {
+ opus_val16 coef1 = coef[1];
+ opus_val16 coef2 = coef[2];
+ for (i=0;i<N;i++)
+ {
+ celt_sig x, tmp;
+ x = inp[i];
+ /* Apply pre-emphasis */
+ tmp = MULT16_16(coef2, x);
+ inp[i] = tmp + m;
+ m = MULT16_32_Q15(coef1, inp[i]) - MULT16_32_Q15(coef0, tmp);
+ }
+ } else
+#endif
+ {
+ for (i=0;i<N;i++)
+ {
+ opus_val16 x;
+ x = inp[i];
+ /* Apply pre-emphasis */
+ inp[i] = SHL32(x, SIG_SHIFT) - m;
+ m = SHR32(MULT16_16(coef0, x), 15-SIG_SHIFT);
+ }
+ }
+ *mem = m;
+}
+
+
+
+static opus_val32 l1_metric(const celt_norm *tmp, int N, int LM, opus_val16 bias)
+{
+ int i;
+ opus_val32 L1;
+ L1 = 0;
+ for (i=0;i<N;i++)
+ L1 += EXTEND32(ABS16(tmp[i]));
+ /* When in doubt, prefer good freq resolution */
+ L1 = MAC16_32_Q15(L1, LM*bias, L1);
+ return L1;
+
+}
+
+static int tf_analysis(const CELTMode *m, int len, int isTransient,
+ int *tf_res, int lambda, celt_norm *X, int N0, int LM,
+ int *tf_sum, opus_val16 tf_estimate, int tf_chan)
+{
+ int i;
+ VARDECL(int, metric);
+ int cost0;
+ int cost1;
+ VARDECL(int, path0);
+ VARDECL(int, path1);
+ VARDECL(celt_norm, tmp);
+ VARDECL(celt_norm, tmp_1);
+ int sel;
+ int selcost[2];
+ int tf_select=0;
+ opus_val16 bias;
+
+ SAVE_STACK;
+ bias = MULT16_16_Q14(QCONST16(.04f,15), MAX16(-QCONST16(.25f,14), QCONST16(.5f,14)-tf_estimate));
+ /*printf("%f ", bias);*/
+
+ ALLOC(metric, len, int);
+ ALLOC(tmp, (m->eBands[len]-m->eBands[len-1])<<LM, celt_norm);
+ ALLOC(tmp_1, (m->eBands[len]-m->eBands[len-1])<<LM, celt_norm);
+ ALLOC(path0, len, int);
+ ALLOC(path1, len, int);
+
+ *tf_sum = 0;
+ for (i=0;i<len;i++)
+ {
+ int k, N;
+ int narrow;
+ opus_val32 L1, best_L1;
+ int best_level=0;
+ N = (m->eBands[i+1]-m->eBands[i])<<LM;
+ /* band is too narrow to be split down to LM=-1 */
+ narrow = (m->eBands[i+1]-m->eBands[i])==1;
+ OPUS_COPY(tmp, &X[tf_chan*N0 + (m->eBands[i]<<LM)], N);
+ /* Just add the right channel if we're in stereo */
+ /*if (C==2)
+ for (j=0;j<N;j++)
+ tmp[j] = ADD16(SHR16(tmp[j], 1),SHR16(X[N0+j+(m->eBands[i]<<LM)], 1));*/
+ L1 = l1_metric(tmp, N, isTransient ? LM : 0, bias);
+ best_L1 = L1;
+ /* Check the -1 case for transients */
+ if (isTransient && !narrow)
+ {
+ OPUS_COPY(tmp_1, tmp, N);
+ haar1(tmp_1, N>>LM, 1<<LM);
+ L1 = l1_metric(tmp_1, N, LM+1, bias);
+ if (L1<best_L1)
+ {
+ best_L1 = L1;
+ best_level = -1;
+ }
+ }
+ /*printf ("%f ", L1);*/
+ for (k=0;k<LM+!(isTransient||narrow);k++)
+ {
+ int B;
+
+ if (isTransient)
+ B = (LM-k-1);
+ else
+ B = k+1;
+
+ haar1(tmp, N>>k, 1<<k);
+
+ L1 = l1_metric(tmp, N, B, bias);
+
+ if (L1 < best_L1)
+ {
+ best_L1 = L1;
+ best_level = k+1;
+ }
+ }
+ /*printf ("%d ", isTransient ? LM-best_level : best_level);*/
+ /* metric is in Q1 to be able to select the mid-point (-0.5) for narrower bands */
+ if (isTransient)
+ metric[i] = 2*best_level;
+ else
+ metric[i] = -2*best_level;
+ *tf_sum += (isTransient ? LM : 0) - metric[i]/2;
+ /* For bands that can't be split to -1, set the metric to the half-way point to avoid
+ biasing the decision */
+ if (narrow && (metric[i]==0 || metric[i]==-2*LM))
+ metric[i]-=1;
+ /*printf("%d ", metric[i]);*/
+ }
+ /*printf("\n");*/
+ /* Search for the optimal tf resolution, including tf_select */
+ tf_select = 0;
+ for (sel=0;sel<2;sel++)
+ {
+ cost0 = 0;
+ cost1 = isTransient ? 0 : lambda;
+ for (i=1;i<len;i++)
+ {
+ int curr0, curr1;
+ curr0 = IMIN(cost0, cost1 + lambda);
+ curr1 = IMIN(cost0 + lambda, cost1);
+ cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+0]);
+ cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+1]);
+ }
+ cost0 = IMIN(cost0, cost1);
+ selcost[sel]=cost0;
+ }
+ /* For now, we're conservative and only allow tf_select=1 for transients.
+ * If tests confirm it's useful for non-transients, we could allow it. */
+ if (selcost[1]<selcost[0] && isTransient)
+ tf_select=1;
+ cost0 = 0;
+ cost1 = isTransient ? 0 : lambda;
+ /* Viterbi forward pass */
+ for (i=1;i<len;i++)
+ {
+ int curr0, curr1;
+ int from0, from1;
+
+ from0 = cost0;
+ from1 = cost1 + lambda;
+ if (from0 < from1)
+ {
+ curr0 = from0;
+ path0[i]= 0;
+ } else {
+ curr0 = from1;
+ path0[i]= 1;
+ }
+
+ from0 = cost0 + lambda;
+ from1 = cost1;
+ if (from0 < from1)
+ {
+ curr1 = from0;
+ path1[i]= 0;
+ } else {
+ curr1 = from1;
+ path1[i]= 1;
+ }
+ cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]);
+ cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]);
+ }
+ tf_res[len-1] = cost0 < cost1 ? 0 : 1;
+ /* Viterbi backward pass to check the decisions */
+ for (i=len-2;i>=0;i--)
+ {
+ if (tf_res[i+1] == 1)
+ tf_res[i] = path1[i+1];
+ else
+ tf_res[i] = path0[i+1];
+ }
+ /*printf("%d %f\n", *tf_sum, tf_estimate);*/
+ RESTORE_STACK;
+#ifdef FUZZING
+ tf_select = rand()&0x1;
+ tf_res[0] = rand()&0x1;
+ for (i=1;i<len;i++)
+ tf_res[i] = tf_res[i-1] ^ ((rand()&0xF) == 0);
+#endif
+ return tf_select;
+}
+
+static void tf_encode(int start, int end, int isTransient, int *tf_res, int LM, int tf_select, ec_enc *enc)
+{
+ int curr, i;
+ int tf_select_rsv;
+ int tf_changed;
+ int logp;
+ opus_uint32 budget;
+ opus_uint32 tell;
+ budget = enc->storage*8;
+ tell = ec_tell(enc);
+ logp = isTransient ? 2 : 4;
+ /* Reserve space to code the tf_select decision. */
+ tf_select_rsv = LM>0 && tell+logp+1 <= budget;
+ budget -= tf_select_rsv;
+ curr = tf_changed = 0;
+ for (i=start;i<end;i++)
+ {
+ if (tell+logp<=budget)
+ {
+ ec_enc_bit_logp(enc, tf_res[i] ^ curr, logp);
+ tell = ec_tell(enc);
+ curr = tf_res[i];
+ tf_changed |= curr;
+ }
+ else
+ tf_res[i] = curr;
+ logp = isTransient ? 4 : 5;
+ }
+ /* Only code tf_select if it would actually make a difference. */
+ if (tf_select_rsv &&
+ tf_select_table[LM][4*isTransient+0+tf_changed]!=
+ tf_select_table[LM][4*isTransient+2+tf_changed])
+ ec_enc_bit_logp(enc, tf_select, 1);
+ else
+ tf_select = 0;
+ for (i=start;i<end;i++)
+ tf_res[i] = tf_select_table[LM][4*isTransient+2*tf_select+tf_res[i]];
+ /*for(i=0;i<end;i++)printf("%d ", isTransient ? tf_res[i] : LM+tf_res[i]);printf("\n");*/
+}
+
+
+static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X,
+ const opus_val16 *bandLogE, int end, int LM, int C, int N0,
+ AnalysisInfo *analysis, opus_val16 *stereo_saving, opus_val16 tf_estimate,
+ int intensity, opus_val16 surround_trim, int arch)
+{
+ int i;
+ opus_val32 diff=0;
+ int c;
+ int trim_index;
+ opus_val16 trim = QCONST16(5.f, 8);
+ opus_val16 logXC, logXC2;
+ if (C==2)
+ {
+ opus_val16 sum = 0; /* Q10 */
+ opus_val16 minXC; /* Q10 */
+ /* Compute inter-channel correlation for low frequencies */
+ for (i=0;i<8;i++)
+ {
+ opus_val32 partial;
+ partial = celt_inner_prod(&X[m->eBands[i]<<LM], &X[N0+(m->eBands[i]<<LM)],
+ (m->eBands[i+1]-m->eBands[i])<<LM, arch);
+ sum = ADD16(sum, EXTRACT16(SHR32(partial, 18)));
+ }
+ sum = MULT16_16_Q15(QCONST16(1.f/8, 15), sum);
+ sum = MIN16(QCONST16(1.f, 10), ABS16(sum));
+ minXC = sum;
+ for (i=8;i<intensity;i++)
+ {
+ opus_val32 partial;
+ partial = celt_inner_prod(&X[m->eBands[i]<<LM], &X[N0+(m->eBands[i]<<LM)],
+ (m->eBands[i+1]-m->eBands[i])<<LM, arch);
+ minXC = MIN16(minXC, ABS16(EXTRACT16(SHR32(partial, 18))));
+ }
+ minXC = MIN16(QCONST16(1.f, 10), ABS16(minXC));
+ /*printf ("%f\n", sum);*/
+ /* mid-side savings estimations based on the LF average*/
+ logXC = celt_log2(QCONST32(1.001f, 20)-MULT16_16(sum, sum));
+ /* mid-side savings estimations based on min correlation */
+ logXC2 = MAX16(HALF16(logXC), celt_log2(QCONST32(1.001f, 20)-MULT16_16(minXC, minXC)));
+#ifdef FIXED_POINT
+ /* Compensate for Q20 vs Q14 input and convert output to Q8 */
+ logXC = PSHR32(logXC-QCONST16(6.f, DB_SHIFT),DB_SHIFT-8);
+ logXC2 = PSHR32(logXC2-QCONST16(6.f, DB_SHIFT),DB_SHIFT-8);
+#endif
+
+ trim += MAX16(-QCONST16(4.f, 8), MULT16_16_Q15(QCONST16(.75f,15),logXC));
+ *stereo_saving = MIN16(*stereo_saving + QCONST16(0.25f, 8), -HALF16(logXC2));
+ }
+
+ /* Estimate spectral tilt */
+ c=0; do {
+ for (i=0;i<end-1;i++)
+ {
+ diff += bandLogE[i+c*m->nbEBands]*(opus_int32)(2+2*i-end);
+ }
+ } while (++c<C);
+ diff /= C*(end-1);
+ /*printf("%f\n", diff);*/
+ trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8), SHR16(diff+QCONST16(1.f, DB_SHIFT),DB_SHIFT-8)/6 ));
+ trim -= SHR16(surround_trim, DB_SHIFT-8);
+ trim -= 2*SHR16(tf_estimate, 14-8);
+#ifndef DISABLE_FLOAT_API
+ if (analysis->valid)
+ {
+ trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8),
+ (opus_val16)(QCONST16(2.f, 8)*(analysis->tonality_slope+.05f))));
+ }
+#else
+ (void)analysis;
+#endif
+
+#ifdef FIXED_POINT
+ trim_index = PSHR32(trim, 8);
+#else
+ trim_index = (int)floor(.5f+trim);
+#endif
+ trim_index = IMAX(0, IMIN(10, trim_index));
+ /*printf("%d\n", trim_index);*/
+#ifdef FUZZING
+ trim_index = rand()%11;
+#endif
+ return trim_index;
+}
+
+static int stereo_analysis(const CELTMode *m, const celt_norm *X,
+ int LM, int N0)
+{
+ int i;
+ int thetas;
+ opus_val32 sumLR = EPSILON, sumMS = EPSILON;
+
+ /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */
+ for (i=0;i<13;i++)
+ {
+ int j;
+ for (j=m->eBands[i]<<LM;j<m->eBands[i+1]<<LM;j++)
+ {
+ opus_val32 L, R, M, S;
+ /* We cast to 32-bit first because of the -32768 case */
+ L = EXTEND32(X[j]);
+ R = EXTEND32(X[N0+j]);
+ M = ADD32(L, R);
+ S = SUB32(L, R);
+ sumLR = ADD32(sumLR, ADD32(ABS32(L), ABS32(R)));
+ sumMS = ADD32(sumMS, ADD32(ABS32(M), ABS32(S)));
+ }
+ }
+ sumMS = MULT16_32_Q15(QCONST16(0.707107f, 15), sumMS);
+ thetas = 13;
+ /* We don't need thetas for lower bands with LM<=1 */
+ if (LM<=1)
+ thetas -= 8;
+ return MULT16_32_Q15((m->eBands[13]<<(LM+1))+thetas, sumMS)
+ > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR);
+}
+
+#define MSWAP(a,b) do {opus_val16 tmp = a;a=b;b=tmp;} while(0)
+static opus_val16 median_of_5(const opus_val16 *x)
+{
+ opus_val16 t0, t1, t2, t3, t4;
+ t2 = x[2];
+ if (x[0] > x[1])
+ {
+ t0 = x[1];
+ t1 = x[0];
+ } else {
+ t0 = x[0];
+ t1 = x[1];
+ }
+ if (x[3] > x[4])
+ {
+ t3 = x[4];
+ t4 = x[3];
+ } else {
+ t3 = x[3];
+ t4 = x[4];
+ }
+ if (t0 > t3)
+ {
+ MSWAP(t0, t3);
+ MSWAP(t1, t4);
+ }
+ if (t2 > t1)
+ {
+ if (t1 < t3)
+ return MIN16(t2, t3);
+ else
+ return MIN16(t4, t1);
+ } else {
+ if (t2 < t3)
+ return MIN16(t1, t3);
+ else
+ return MIN16(t2, t4);
+ }
+}
+
+static opus_val16 median_of_3(const opus_val16 *x)
+{
+ opus_val16 t0, t1, t2;
+ if (x[0] > x[1])
+ {
+ t0 = x[1];
+ t1 = x[0];
+ } else {
+ t0 = x[0];
+ t1 = x[1];
+ }
+ t2 = x[2];
+ if (t1 < t2)
+ return t1;
+ else if (t0 < t2)
+ return t2;
+ else
+ return t0;
+}
+
+static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 *bandLogE2,
+ int nbEBands, int start, int end, int C, int *offsets, int lsb_depth, const opus_int16 *logN,
+ int isTransient, int vbr, int constrained_vbr, const opus_int16 *eBands, int LM,
+ int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc)
+{
+ int i, c;
+ opus_int32 tot_boost=0;
+ opus_val16 maxDepth;
+ VARDECL(opus_val16, follower);
+ VARDECL(opus_val16, noise_floor);
+ SAVE_STACK;
+ ALLOC(follower, C*nbEBands, opus_val16);
+ ALLOC(noise_floor, C*nbEBands, opus_val16);
+ OPUS_CLEAR(offsets, nbEBands);
+ /* Dynamic allocation code */
+ maxDepth=-QCONST16(31.9f, DB_SHIFT);
+ for (i=0;i<end;i++)
+ {
+ /* Noise floor must take into account eMeans, the depth, the width of the bands
+ and the preemphasis filter (approx. square of bark band ID) */
+ noise_floor[i] = MULT16_16(QCONST16(0.0625f, DB_SHIFT),logN[i])
+ +QCONST16(.5f,DB_SHIFT)+SHL16(9-lsb_depth,DB_SHIFT)-SHL16(eMeans[i],6)
+ +MULT16_16(QCONST16(.0062,DB_SHIFT),(i+5)*(i+5));
+ }
+ c=0;do
+ {
+ for (i=0;i<end;i++)
+ maxDepth = MAX16(maxDepth, bandLogE[c*nbEBands+i]-noise_floor[i]);
+ } while (++c<C);
+ /* Make sure that dynamic allocation can't make us bust the budget */
+ if (effectiveBytes > 50 && LM>=1 && !lfe)
+ {
+ int last=0;
+ c=0;do
+ {
+ opus_val16 offset;
+ opus_val16 tmp;
+ opus_val16 *f;
+ f = &follower[c*nbEBands];
+ f[0] = bandLogE2[c*nbEBands];
+ for (i=1;i<end;i++)
+ {
+ /* The last band to be at least 3 dB higher than the previous one
+ is the last we'll consider. Otherwise, we run into problems on
+ bandlimited signals. */
+ if (bandLogE2[c*nbEBands+i] > bandLogE2[c*nbEBands+i-1]+QCONST16(.5f,DB_SHIFT))
+ last=i;
+ f[i] = MIN16(f[i-1]+QCONST16(1.5f,DB_SHIFT), bandLogE2[c*nbEBands+i]);
+ }
+ for (i=last-1;i>=0;i--)
+ f[i] = MIN16(f[i], MIN16(f[i+1]+QCONST16(2.f,DB_SHIFT), bandLogE2[c*nbEBands+i]));
+
+ /* Combine with a median filter to avoid dynalloc triggering unnecessarily.
+ The "offset" value controls how conservative we are -- a higher offset
+ reduces the impact of the median filter and makes dynalloc use more bits. */
+ offset = QCONST16(1.f, DB_SHIFT);
+ for (i=2;i<end-2;i++)
+ f[i] = MAX16(f[i], median_of_5(&bandLogE2[c*nbEBands+i-2])-offset);
+ tmp = median_of_3(&bandLogE2[c*nbEBands])-offset;
+ f[0] = MAX16(f[0], tmp);
+ f[1] = MAX16(f[1], tmp);
+ tmp = median_of_3(&bandLogE2[c*nbEBands+end-3])-offset;
+ f[end-2] = MAX16(f[end-2], tmp);
+ f[end-1] = MAX16(f[end-1], tmp);
+
+ for (i=0;i<end;i++)
+ f[i] = MAX16(f[i], noise_floor[i]);
+ } while (++c<C);
+ if (C==2)
+ {
+ for (i=start;i<end;i++)
+ {
+ /* Consider 24 dB "cross-talk" */
+ follower[nbEBands+i] = MAX16(follower[nbEBands+i], follower[ i]-QCONST16(4.f,DB_SHIFT));
+ follower[ i] = MAX16(follower[ i], follower[nbEBands+i]-QCONST16(4.f,DB_SHIFT));
+ follower[i] = HALF16(MAX16(0, bandLogE[i]-follower[i]) + MAX16(0, bandLogE[nbEBands+i]-follower[nbEBands+i]));
+ }
+ } else {
+ for (i=start;i<end;i++)
+ {
+ follower[i] = MAX16(0, bandLogE[i]-follower[i]);
+ }
+ }
+ for (i=start;i<end;i++)
+ follower[i] = MAX16(follower[i], surround_dynalloc[i]);
+ /* For non-transient CBR/CVBR frames, halve the dynalloc contribution */
+ if ((!vbr || constrained_vbr)&&!isTransient)
+ {
+ for (i=start;i<end;i++)
+ follower[i] = HALF16(follower[i]);
+ }
+ for (i=start;i<end;i++)
+ {
+ int width;
+ int boost;
+ int boost_bits;
+
+ if (i<8)
+ follower[i] *= 2;
+ if (i>=12)
+ follower[i] = HALF16(follower[i]);
+ follower[i] = MIN16(follower[i], QCONST16(4, DB_SHIFT));
+
+ width = C*(eBands[i+1]-eBands[i])<<LM;
+ if (width<6)
+ {
+ boost = (int)SHR32(EXTEND32(follower[i]),DB_SHIFT);
+ boost_bits = boost*width<<BITRES;
+ } else if (width > 48) {
+ boost = (int)SHR32(EXTEND32(follower[i])*8,DB_SHIFT);
+ boost_bits = (boost*width<<BITRES)/8;
+ } else {
+ boost = (int)SHR32(EXTEND32(follower[i])*width/6,DB_SHIFT);
+ boost_bits = boost*6<<BITRES;
+ }
+ /* For CBR and non-transient CVBR frames, limit dynalloc to 1/4 of the bits */
+ if ((!vbr || (constrained_vbr&&!isTransient))
+ && (tot_boost+boost_bits)>>BITRES>>3 > effectiveBytes/4)
+ {
+ opus_int32 cap = ((effectiveBytes/4)<<BITRES<<3);
+ offsets[i] = cap-tot_boost;
+ tot_boost = cap;
+ break;
+ } else {
+ offsets[i] = boost;
+ tot_boost += boost_bits;
+ }
+ }
+ }
+ *tot_boost_ = tot_boost;
+ RESTORE_STACK;
+ return maxDepth;
+}
+
+
+static int run_prefilter(CELTEncoder *st, celt_sig *in, celt_sig *prefilter_mem, int CC, int N,
+ int prefilter_tapset, int *pitch, opus_val16 *gain, int *qgain, int enabled, int nbAvailableBytes)
+{
+ int c;
+ VARDECL(celt_sig, _pre);
+ celt_sig *pre[2];
+ const CELTMode *mode;
+ int pitch_index;
+ opus_val16 gain1;
+ opus_val16 pf_threshold;
+ int pf_on;
+ int qg;
+ int overlap;
+ SAVE_STACK;
+
+ mode = st->mode;
+ overlap = mode->overlap;
+ ALLOC(_pre, CC*(N+COMBFILTER_MAXPERIOD), celt_sig);
+
+ pre[0] = _pre;
+ pre[1] = _pre + (N+COMBFILTER_MAXPERIOD);
+
+
+ c=0; do {
+ OPUS_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD);
+ OPUS_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+overlap)+overlap, N);
+ } while (++c<CC);
+
+ if (enabled)
+ {
+ VARDECL(opus_val16, pitch_buf);
+ ALLOC(pitch_buf, (COMBFILTER_MAXPERIOD+N)>>1, opus_val16);
+
+ pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, CC, st->arch);
+ /* Don't search for the fir last 1.5 octave of the range because
+ there's too many false-positives due to short-term correlation */
+ pitch_search(pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N,
+ COMBFILTER_MAXPERIOD-3*COMBFILTER_MINPERIOD, &pitch_index,
+ st->arch);
+ pitch_index = COMBFILTER_MAXPERIOD-pitch_index;
+
+ gain1 = remove_doubling(pitch_buf, COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD,
+ N, &pitch_index, st->prefilter_period, st->prefilter_gain, st->arch);
+ if (pitch_index > COMBFILTER_MAXPERIOD-2)
+ pitch_index = COMBFILTER_MAXPERIOD-2;
+ gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1);
+ /*printf("%d %d %f %f\n", pitch_change, pitch_index, gain1, st->analysis.tonality);*/
+ if (st->loss_rate>2)
+ gain1 = HALF32(gain1);
+ if (st->loss_rate>4)
+ gain1 = HALF32(gain1);
+ if (st->loss_rate>8)
+ gain1 = 0;
+ } else {
+ gain1 = 0;
+ pitch_index = COMBFILTER_MINPERIOD;
+ }
+
+ /* Gain threshold for enabling the prefilter/postfilter */
+ pf_threshold = QCONST16(.2f,15);
+
+ /* Adjusting the threshold based on rate and continuity */
+ if (abs(pitch_index-st->prefilter_period)*10>pitch_index)
+ pf_threshold += QCONST16(.2f,15);
+ if (nbAvailableBytes<25)
+ pf_threshold += QCONST16(.1f,15);
+ if (nbAvailableBytes<35)
+ pf_threshold += QCONST16(.1f,15);
+ if (st->prefilter_gain > QCONST16(.4f,15))
+ pf_threshold -= QCONST16(.1f,15);
+ if (st->prefilter_gain > QCONST16(.55f,15))
+ pf_threshold -= QCONST16(.1f,15);
+
+ /* Hard threshold at 0.2 */
+ pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15));
+ if (gain1<pf_threshold)
+ {
+ gain1 = 0;
+ pf_on = 0;
+ qg = 0;
+ } else {
+ /*This block is not gated by a total bits check only because
+ of the nbAvailableBytes check above.*/
+ if (ABS16(gain1-st->prefilter_gain)<QCONST16(.1f,15))
+ gain1=st->prefilter_gain;
+
+#ifdef FIXED_POINT
+ qg = ((gain1+1536)>>10)/3-1;
+#else
+ qg = (int)floor(.5f+gain1*32/3)-1;
+#endif
+ qg = IMAX(0, IMIN(7, qg));
+ gain1 = QCONST16(0.09375f,15)*(qg+1);
+ pf_on = 1;
+ }
+ /*printf("%d %f\n", pitch_index, gain1);*/
+
+ c=0; do {
+ int offset = mode->shortMdctSize-overlap;
+ st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD);
+ OPUS_COPY(in+c*(N+overlap), st->in_mem+c*(overlap), overlap);
+ if (offset)
+ comb_filter(in+c*(N+overlap)+overlap, pre[c]+COMBFILTER_MAXPERIOD,
+ st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain,
+ st->prefilter_tapset, st->prefilter_tapset, NULL, 0, st->arch);
+
+ comb_filter(in+c*(N+overlap)+overlap+offset, pre[c]+COMBFILTER_MAXPERIOD+offset,
+ st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1,
+ st->prefilter_tapset, prefilter_tapset, mode->window, overlap, st->arch);
+ OPUS_COPY(st->in_mem+c*(overlap), in+c*(N+overlap)+N, overlap);
+
+ if (N>COMBFILTER_MAXPERIOD)
+ {
+ OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD, pre[c]+N, COMBFILTER_MAXPERIOD);
+ } else {
+ OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, prefilter_mem+c*COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD-N);
+ OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N);
+ }
+ } while (++c<CC);
+
+ RESTORE_STACK;
+ *gain = gain1;
+ *pitch = pitch_index;
+ *qgain = qg;
+ return pf_on;
+}
+
+static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32 base_target,
+ int LM, opus_int32 bitrate, int lastCodedBands, int C, int intensity,
+ int constrained_vbr, opus_val16 stereo_saving, int tot_boost,
+ opus_val16 tf_estimate, int pitch_change, opus_val16 maxDepth,
+ int variable_duration, int lfe, int has_surround_mask, opus_val16 surround_masking,
+ opus_val16 temporal_vbr)
+{
+ /* The target rate in 8th bits per frame */
+ opus_int32 target;
+ int coded_bins;
+ int coded_bands;
+ opus_val16 tf_calibration;
+ int nbEBands;
+ const opus_int16 *eBands;
+
+ nbEBands = mode->nbEBands;
+ eBands = mode->eBands;
+
+ coded_bands = lastCodedBands ? lastCodedBands : nbEBands;
+ coded_bins = eBands[coded_bands]<<LM;
+ if (C==2)
+ coded_bins += eBands[IMIN(intensity, coded_bands)]<<LM;
+
+ target = base_target;
+
+ /*printf("%f %f %f %f %d %d ", st->analysis.activity, st->analysis.tonality, tf_estimate, st->stereo_saving, tot_boost, coded_bands);*/
+#ifndef DISABLE_FLOAT_API
+ if (analysis->valid && analysis->activity<.4)
+ target -= (opus_int32)((coded_bins<<BITRES)*(.4f-analysis->activity));
+#endif
+ /* Stereo savings */
+ if (C==2)
+ {
+ int coded_stereo_bands;
+ int coded_stereo_dof;
+ opus_val16 max_frac;
+ coded_stereo_bands = IMIN(intensity, coded_bands);
+ coded_stereo_dof = (eBands[coded_stereo_bands]<<LM)-coded_stereo_bands;
+ /* Maximum fraction of the bits we can save if the signal is mono. */
+ max_frac = DIV32_16(MULT16_16(QCONST16(0.8f, 15), coded_stereo_dof), coded_bins);
+ stereo_saving = MIN16(stereo_saving, QCONST16(1.f, 8));
+ /*printf("%d %d %d ", coded_stereo_dof, coded_bins, tot_boost);*/
+ target -= (opus_int32)MIN32(MULT16_32_Q15(max_frac,target),
+ SHR32(MULT16_16(stereo_saving-QCONST16(0.1f,8),(coded_stereo_dof<<BITRES)),8));
+ }
+ /* Boost the rate according to dynalloc (minus the dynalloc average for calibration). */
+ target += tot_boost-(16<<LM);
+ /* Apply transient boost, compensating for average boost. */
+ tf_calibration = variable_duration==OPUS_FRAMESIZE_VARIABLE ?
+ QCONST16(0.02f,14) : QCONST16(0.04f,14);
+ target += (opus_int32)SHL32(MULT16_32_Q15(tf_estimate-tf_calibration, target),1);
+
+#ifndef DISABLE_FLOAT_API
+ /* Apply tonality boost */
+ if (analysis->valid && !lfe)
+ {
+ opus_int32 tonal_target;
+ float tonal;
+
+ /* Tonality boost (compensating for the average). */
+ tonal = MAX16(0.f,analysis->tonality-.15f)-0.09f;
+ tonal_target = target + (opus_int32)((coded_bins<<BITRES)*1.2f*tonal);
+ if (pitch_change)
+ tonal_target += (opus_int32)((coded_bins<<BITRES)*.8f);
+ /*printf("%f %f ", analysis->tonality, tonal);*/
+ target = tonal_target;
+ }
+#else
+ (void)analysis;
+ (void)pitch_change;
+#endif
+
+ if (has_surround_mask&&!lfe)
+ {
+ opus_int32 surround_target = target + (opus_int32)SHR32(MULT16_16(surround_masking,coded_bins<<BITRES), DB_SHIFT);
+ /*printf("%f %d %d %d %d %d %d ", surround_masking, coded_bins, st->end, st->intensity, surround_target, target, st->bitrate);*/
+ target = IMAX(target/4, surround_target);
+ }
+
+ {
+ opus_int32 floor_depth;
+ int bins;
+ bins = eBands[nbEBands-2]<<LM;
+ /*floor_depth = SHR32(MULT16_16((C*bins<<BITRES),celt_log2(SHL32(MAX16(1,sample_max),13))), DB_SHIFT);*/
+ floor_depth = (opus_int32)SHR32(MULT16_16((C*bins<<BITRES),maxDepth), DB_SHIFT);
+ floor_depth = IMAX(floor_depth, target>>2);
+ target = IMIN(target, floor_depth);
+ /*printf("%f %d\n", maxDepth, floor_depth);*/
+ }
+
+ if ((!has_surround_mask||lfe) && (constrained_vbr || bitrate<64000))
+ {
+ opus_val16 rate_factor = Q15ONE;
+ if (bitrate < 64000)
+ {
+#ifdef FIXED_POINT
+ rate_factor = MAX16(0,(bitrate-32000));
+#else
+ rate_factor = MAX16(0,(1.f/32768)*(bitrate-32000));
+#endif
+ }
+ if (constrained_vbr)
+ rate_factor = MIN16(rate_factor, QCONST16(0.67f, 15));
+ target = base_target + (opus_int32)MULT16_32_Q15(rate_factor, target-base_target);
+
+ }
+
+ if (!has_surround_mask && tf_estimate < QCONST16(.2f, 14))
+ {
+ opus_val16 amount;
+ opus_val16 tvbr_factor;
+ amount = MULT16_16_Q15(QCONST16(.0000031f, 30), IMAX(0, IMIN(32000, 96000-bitrate)));
+ tvbr_factor = SHR32(MULT16_16(temporal_vbr, amount), DB_SHIFT);
+ target += (opus_int32)MULT16_32_Q15(tvbr_factor, target);
+ }
+
+ /* Don't allow more than doubling the rate */
+ target = IMIN(2*base_target, target);
+
+ return target;
+}
+
+int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
+{
+ int i, c, N;
+ opus_int32 bits;
+ ec_enc _enc;
+ VARDECL(celt_sig, in);
+ VARDECL(celt_sig, freq);
+ VARDECL(celt_norm, X);
+ VARDECL(celt_ener, bandE);
+ VARDECL(opus_val16, bandLogE);
+ VARDECL(opus_val16, bandLogE2);
+ VARDECL(int, fine_quant);
+ VARDECL(opus_val16, error);
+ VARDECL(int, pulses);
+ VARDECL(int, cap);
+ VARDECL(int, offsets);
+ VARDECL(int, fine_priority);
+ VARDECL(int, tf_res);
+ VARDECL(unsigned char, collapse_masks);
+ celt_sig *prefilter_mem;
+ opus_val16 *oldBandE, *oldLogE, *oldLogE2;
+ int shortBlocks=0;
+ int isTransient=0;
+ const int CC = st->channels;
+ const int C = st->stream_channels;
+ int LM, M;
+ int tf_select;
+ int nbFilledBytes, nbAvailableBytes;
+ int start;
+ int end;
+ int effEnd;
+ int codedBands;
+ int tf_sum;
+ int alloc_trim;
+ int pitch_index=COMBFILTER_MINPERIOD;
+ opus_val16 gain1 = 0;
+ int dual_stereo=0;
+ int effectiveBytes;
+ int dynalloc_logp;
+ opus_int32 vbr_rate;
+ opus_int32 total_bits;
+ opus_int32 total_boost;
+ opus_int32 balance;
+ opus_int32 tell;
+ int prefilter_tapset=0;
+ int pf_on;
+ int anti_collapse_rsv;
+ int anti_collapse_on=0;
+ int silence=0;
+ int tf_chan = 0;
+ opus_val16 tf_estimate;
+ int pitch_change=0;
+ opus_int32 tot_boost;
+ opus_val32 sample_max;
+ opus_val16 maxDepth;
+ const OpusCustomMode *mode;
+ int nbEBands;
+ int overlap;
+ const opus_int16 *eBands;
+ int secondMdct;
+ int signalBandwidth;
+ int transient_got_disabled=0;
+ opus_val16 surround_masking=0;
+ opus_val16 temporal_vbr=0;
+ opus_val16 surround_trim = 0;
+ opus_int32 equiv_rate = 510000;
+ VARDECL(opus_val16, surround_dynalloc);
+ ALLOC_STACK;
+
+ mode = st->mode;
+ nbEBands = mode->nbEBands;
+ overlap = mode->overlap;
+ eBands = mode->eBands;
+ start = st->start;
+ end = st->end;
+ tf_estimate = 0;
+ if (nbCompressedBytes<2 || pcm==NULL)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+
+ frame_size *= st->upsample;
+ for (LM=0;LM<=mode->maxLM;LM++)
+ if (mode->shortMdctSize<<LM==frame_size)
+ break;
+ if (LM>mode->maxLM)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ M=1<<LM;
+ N = M*mode->shortMdctSize;
+
+ prefilter_mem = st->in_mem+CC*(overlap);
+ oldBandE = (opus_val16*)(st->in_mem+CC*(overlap+COMBFILTER_MAXPERIOD));
+ oldLogE = oldBandE + CC*nbEBands;
+ oldLogE2 = oldLogE + CC*nbEBands;
+
+ if (enc==NULL)
+ {
+ tell=1;
+ nbFilledBytes=0;
+ } else {
+ tell=ec_tell(enc);
+ nbFilledBytes=(tell+4)>>3;
+ }
+
+#ifdef CUSTOM_MODES
+ if (st->signalling && enc==NULL)
+ {
+ int tmp = (mode->effEBands-end)>>1;
+ end = st->end = IMAX(1, mode->effEBands-tmp);
+ compressed[0] = tmp<<5;
+ compressed[0] |= LM<<3;
+ compressed[0] |= (C==2)<<2;
+ /* Convert "standard mode" to Opus header */
+ if (mode->Fs==48000 && mode->shortMdctSize==120)
+ {
+ int c0 = toOpus(compressed[0]);
+ if (c0<0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ compressed[0] = c0;
+ }
+ compressed++;
+ nbCompressedBytes--;
+ }
+#else
+ celt_assert(st->signalling==0);
+#endif
+
+ /* Can't produce more than 1275 output bytes */
+ nbCompressedBytes = IMIN(nbCompressedBytes,1275);
+ nbAvailableBytes = nbCompressedBytes - nbFilledBytes;
+
+ if (st->vbr && st->bitrate!=OPUS_BITRATE_MAX)
+ {
+ opus_int32 den=mode->Fs>>BITRES;
+ vbr_rate=(st->bitrate*frame_size+(den>>1))/den;
+#ifdef CUSTOM_MODES
+ if (st->signalling)
+ vbr_rate -= 8<<BITRES;
+#endif
+ effectiveBytes = vbr_rate>>(3+BITRES);
+ } else {
+ opus_int32 tmp;
+ vbr_rate = 0;
+ tmp = st->bitrate*frame_size;
+ if (tell>1)
+ tmp += tell;
+ if (st->bitrate!=OPUS_BITRATE_MAX)
+ nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes,
+ (tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling));
+ effectiveBytes = nbCompressedBytes;
+ }
+ if (st->bitrate != OPUS_BITRATE_MAX)
+ equiv_rate = st->bitrate - (40*C+20)*((400>>LM) - 50);
+
+ if (enc==NULL)
+ {
+ ec_enc_init(&_enc, compressed, nbCompressedBytes);
+ enc = &_enc;
+ }
+
+ if (vbr_rate>0)
+ {
+ /* Computes the max bit-rate allowed in VBR mode to avoid violating the
+ target rate and buffering.
+ We must do this up front so that bust-prevention logic triggers
+ correctly if we don't have enough bits. */
+ if (st->constrained_vbr)
+ {
+ opus_int32 vbr_bound;
+ opus_int32 max_allowed;
+ /* We could use any multiple of vbr_rate as bound (depending on the
+ delay).
+ This is clamped to ensure we use at least two bytes if the encoder
+ was entirely empty, but to allow 0 in hybrid mode. */
+ vbr_bound = vbr_rate;
+ max_allowed = IMIN(IMAX(tell==1?2:0,
+ (vbr_rate+vbr_bound-st->vbr_reservoir)>>(BITRES+3)),
+ nbAvailableBytes);
+ if(max_allowed < nbAvailableBytes)
+ {
+ nbCompressedBytes = nbFilledBytes+max_allowed;
+ nbAvailableBytes = max_allowed;
+ ec_enc_shrink(enc, nbCompressedBytes);
+ }
+ }
+ }
+ total_bits = nbCompressedBytes*8;
+
+ effEnd = end;
+ if (effEnd > mode->effEBands)
+ effEnd = mode->effEBands;
+
+ ALLOC(in, CC*(N+overlap), celt_sig);
+
+ sample_max=MAX32(st->overlap_max, celt_maxabs16(pcm, C*(N-overlap)/st->upsample));
+ st->overlap_max=celt_maxabs16(pcm+C*(N-overlap)/st->upsample, C*overlap/st->upsample);
+ sample_max=MAX32(sample_max, st->overlap_max);
+#ifdef FIXED_POINT
+ silence = (sample_max==0);
+#else
+ silence = (sample_max <= (opus_val16)1/(1<<st->lsb_depth));
+#endif
+#ifdef FUZZING
+ if ((rand()&0x3F)==0)
+ silence = 1;
+#endif
+ if (tell==1)
+ ec_enc_bit_logp(enc, silence, 15);
+ else
+ silence=0;
+ if (silence)
+ {
+ /*In VBR mode there is no need to send more than the minimum. */
+ if (vbr_rate>0)
+ {
+ effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2);
+ total_bits=nbCompressedBytes*8;
+ nbAvailableBytes=2;
+ ec_enc_shrink(enc, nbCompressedBytes);
+ }
+ /* Pretend we've filled all the remaining bits with zeros
+ (that's what the initialiser did anyway) */
+ tell = nbCompressedBytes*8;
+ enc->nbits_total+=tell-ec_tell(enc);
+ }
+ c=0; do {
+ int need_clip=0;
+#ifndef FIXED_POINT
+ need_clip = st->clip && sample_max>65536.f;
+#endif
+ celt_preemphasis(pcm+c, in+c*(N+overlap)+overlap, N, CC, st->upsample,
+ mode->preemph, st->preemph_memE+c, need_clip);
+ } while (++c<CC);
+
+
+
+ /* Find pitch period and gain */
+ {
+ int enabled;
+ int qg;
+ enabled = ((st->lfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && start==0 && !silence && !st->disable_pf
+ && st->complexity >= 5 && !(st->consec_transient && LM!=3 && st->variable_duration==OPUS_FRAMESIZE_VARIABLE);
+
+ prefilter_tapset = st->tapset_decision;
+ pf_on = run_prefilter(st, in, prefilter_mem, CC, N, prefilter_tapset, &pitch_index, &gain1, &qg, enabled, nbAvailableBytes);
+ if ((gain1 > QCONST16(.4f,15) || st->prefilter_gain > QCONST16(.4f,15)) && (!st->analysis.valid || st->analysis.tonality > .3)
+ && (pitch_index > 1.26*st->prefilter_period || pitch_index < .79*st->prefilter_period))
+ pitch_change = 1;
+ if (pf_on==0)
+ {
+ if(start==0 && tell+16<=total_bits)
+ ec_enc_bit_logp(enc, 0, 1);
+ } else {
+ /*This block is not gated by a total bits check only because
+ of the nbAvailableBytes check above.*/
+ int octave;
+ ec_enc_bit_logp(enc, 1, 1);
+ pitch_index += 1;
+ octave = EC_ILOG(pitch_index)-5;
+ ec_enc_uint(enc, octave, 6);
+ ec_enc_bits(enc, pitch_index-(16<<octave), 4+octave);
+ pitch_index -= 1;
+ ec_enc_bits(enc, qg, 3);
+ ec_enc_icdf(enc, prefilter_tapset, tapset_icdf, 2);
+ }
+ }
+
+ isTransient = 0;
+ shortBlocks = 0;
+ if (st->complexity >= 1 && !st->lfe)
+ {
+ isTransient = transient_analysis(in, N+overlap, CC,
+ &tf_estimate, &tf_chan);
+ }
+ if (LM>0 && ec_tell(enc)+3<=total_bits)
+ {
+ if (isTransient)
+ shortBlocks = M;
+ } else {
+ isTransient = 0;
+ transient_got_disabled=1;
+ }
+
+ ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */
+ ALLOC(bandE,nbEBands*CC, celt_ener);
+ ALLOC(bandLogE,nbEBands*CC, opus_val16);
+
+ secondMdct = shortBlocks && st->complexity>=8;
+ ALLOC(bandLogE2, C*nbEBands, opus_val16);
+ if (secondMdct)
+ {
+ compute_mdcts(mode, 0, in, freq, C, CC, LM, st->upsample, st->arch);
+ compute_band_energies(mode, freq, bandE, effEnd, C, LM);
+ amp2Log2(mode, effEnd, end, bandE, bandLogE2, C);
+ for (i=0;i<C*nbEBands;i++)
+ bandLogE2[i] += HALF16(SHL16(LM, DB_SHIFT));
+ }
+
+ compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, st->arch);
+ if (CC==2&&C==1)
+ tf_chan = 0;
+ compute_band_energies(mode, freq, bandE, effEnd, C, LM);
+
+ if (st->lfe)
+ {
+ for (i=2;i<end;i++)
+ {
+ bandE[i] = IMIN(bandE[i], MULT16_32_Q15(QCONST16(1e-4f,15),bandE[0]));
+ bandE[i] = MAX32(bandE[i], EPSILON);
+ }
+ }
+ amp2Log2(mode, effEnd, end, bandE, bandLogE, C);
+
+ ALLOC(surround_dynalloc, C*nbEBands, opus_val16);
+ OPUS_CLEAR(surround_dynalloc, end);
+ /* This computes how much masking takes place between surround channels */
+ if (start==0&&st->energy_mask&&!st->lfe)
+ {
+ int mask_end;
+ int midband;
+ int count_dynalloc;
+ opus_val32 mask_avg=0;
+ opus_val32 diff=0;
+ int count=0;
+ mask_end = IMAX(2,st->lastCodedBands);
+ for (c=0;c<C;c++)
+ {
+ for(i=0;i<mask_end;i++)
+ {
+ opus_val16 mask;
+ mask = MAX16(MIN16(st->energy_mask[nbEBands*c+i],
+ QCONST16(.25f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT));
+ if (mask > 0)
+ mask = HALF16(mask);
+ mask_avg += MULT16_16(mask, eBands[i+1]-eBands[i]);
+ count += eBands[i+1]-eBands[i];
+ diff += MULT16_16(mask, 1+2*i-mask_end);
+ }
+ }
+ celt_assert(count>0);
+ mask_avg = DIV32_16(mask_avg,count);
+ mask_avg += QCONST16(.2f, DB_SHIFT);
+ diff = diff*6/(C*(mask_end-1)*(mask_end+1)*mask_end);
+ /* Again, being conservative */
+ diff = HALF32(diff);
+ diff = MAX32(MIN32(diff, QCONST32(.031f, DB_SHIFT)), -QCONST32(.031f, DB_SHIFT));
+ /* Find the band that's in the middle of the coded spectrum */
+ for (midband=0;eBands[midband+1] < eBands[mask_end]/2;midband++);
+ count_dynalloc=0;
+ for(i=0;i<mask_end;i++)
+ {
+ opus_val32 lin;
+ opus_val16 unmask;
+ lin = mask_avg + diff*(i-midband);
+ if (C==2)
+ unmask = MAX16(st->energy_mask[i], st->energy_mask[nbEBands+i]);
+ else
+ unmask = st->energy_mask[i];
+ unmask = MIN16(unmask, QCONST16(.0f, DB_SHIFT));
+ unmask -= lin;
+ if (unmask > QCONST16(.25f, DB_SHIFT))
+ {
+ surround_dynalloc[i] = unmask - QCONST16(.25f, DB_SHIFT);
+ count_dynalloc++;
+ }
+ }
+ if (count_dynalloc>=3)
+ {
+ /* If we need dynalloc in many bands, it's probably because our
+ initial masking rate was too low. */
+ mask_avg += QCONST16(.25f, DB_SHIFT);
+ if (mask_avg>0)
+ {
+ /* Something went really wrong in the original calculations,
+ disabling masking. */
+ mask_avg = 0;
+ diff = 0;
+ OPUS_CLEAR(surround_dynalloc, mask_end);
+ } else {
+ for(i=0;i<mask_end;i++)
+ surround_dynalloc[i] = MAX16(0, surround_dynalloc[i]-QCONST16(.25f, DB_SHIFT));
+ }
+ }
+ mask_avg += QCONST16(.2f, DB_SHIFT);
+ /* Convert to 1/64th units used for the trim */
+ surround_trim = 64*diff;
+ /*printf("%d %d ", mask_avg, surround_trim);*/
+ surround_masking = mask_avg;
+ }
+ /* Temporal VBR (but not for LFE) */
+ if (!st->lfe)
+ {
+ opus_val16 follow=-QCONST16(10.0f,DB_SHIFT);
+ opus_val32 frame_avg=0;
+ opus_val16 offset = shortBlocks?HALF16(SHL16(LM, DB_SHIFT)):0;
+ for(i=start;i<end;i++)
+ {
+ follow = MAX16(follow-QCONST16(1.f, DB_SHIFT), bandLogE[i]-offset);
+ if (C==2)
+ follow = MAX16(follow, bandLogE[i+nbEBands]-offset);
+ frame_avg += follow;
+ }
+ frame_avg /= (end-start);
+ temporal_vbr = SUB16(frame_avg,st->spec_avg);
+ temporal_vbr = MIN16(QCONST16(3.f, DB_SHIFT), MAX16(-QCONST16(1.5f, DB_SHIFT), temporal_vbr));
+ st->spec_avg += MULT16_16_Q15(QCONST16(.02f, 15), temporal_vbr);
+ }
+ /*for (i=0;i<21;i++)
+ printf("%f ", bandLogE[i]);
+ printf("\n");*/
+
+ if (!secondMdct)
+ {
+ OPUS_COPY(bandLogE2, bandLogE, C*nbEBands);
+ }
+
+ /* Last chance to catch any transient we might have missed in the
+ time-domain analysis */
+ if (LM>0 && ec_tell(enc)+3<=total_bits && !isTransient && st->complexity>=5 && !st->lfe)
+ {
+ if (patch_transient_decision(bandLogE, oldBandE, nbEBands, start, end, C))
+ {
+ isTransient = 1;
+ shortBlocks = M;
+ compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, st->arch);
+ compute_band_energies(mode, freq, bandE, effEnd, C, LM);
+ amp2Log2(mode, effEnd, end, bandE, bandLogE, C);
+ /* Compensate for the scaling of short vs long mdcts */
+ for (i=0;i<C*nbEBands;i++)
+ bandLogE2[i] += HALF16(SHL16(LM, DB_SHIFT));
+ tf_estimate = QCONST16(.2f,14);
+ }
+ }
+
+ if (LM>0 && ec_tell(enc)+3<=total_bits)
+ ec_enc_bit_logp(enc, isTransient, 3);
+
+ ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */
+
+ /* Band normalisation */
+ normalise_bands(mode, freq, X, bandE, effEnd, C, M);
+
+ ALLOC(tf_res, nbEBands, int);
+ /* Disable variable tf resolution for hybrid and at very low bitrate */
+ if (effectiveBytes>=15*C && start==0 && st->complexity>=2 && !st->lfe)
+ {
+ int lambda;
+ if (effectiveBytes<40)
+ lambda = 12;
+ else if (effectiveBytes<60)
+ lambda = 6;
+ else if (effectiveBytes<100)
+ lambda = 4;
+ else
+ lambda = 3;
+ lambda*=2;
+ tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, &tf_sum, tf_estimate, tf_chan);
+ for (i=effEnd;i<end;i++)
+ tf_res[i] = tf_res[effEnd-1];
+ } else {
+ tf_sum = 0;
+ for (i=0;i<end;i++)
+ tf_res[i] = isTransient;
+ tf_select=0;
+ }
+
+ ALLOC(error, C*nbEBands, opus_val16);
+ quant_coarse_energy(mode, start, end, effEnd, bandLogE,
+ oldBandE, total_bits, error, enc,
+ C, LM, nbAvailableBytes, st->force_intra,
+ &st->delayedIntra, st->complexity >= 4, st->loss_rate, st->lfe);
+
+ tf_encode(start, end, isTransient, tf_res, LM, tf_select, enc);
+
+ if (ec_tell(enc)+4<=total_bits)
+ {
+ if (st->lfe)
+ {
+ st->tapset_decision = 0;
+ st->spread_decision = SPREAD_NORMAL;
+ } else if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C || start != 0)
+ {
+ if (st->complexity == 0)
+ st->spread_decision = SPREAD_NONE;
+ else
+ st->spread_decision = SPREAD_NORMAL;
+ } else {
+ /* Disable new spreading+tapset estimator until we can show it works
+ better than the old one. So far it seems like spreading_decision()
+ works best. */
+#if 0
+ if (st->analysis.valid)
+ {
+ static const opus_val16 spread_thresholds[3] = {-QCONST16(.6f, 15), -QCONST16(.2f, 15), -QCONST16(.07f, 15)};
+ static const opus_val16 spread_histeresis[3] = {QCONST16(.15f, 15), QCONST16(.07f, 15), QCONST16(.02f, 15)};
+ static const opus_val16 tapset_thresholds[2] = {QCONST16(.0f, 15), QCONST16(.15f, 15)};
+ static const opus_val16 tapset_histeresis[2] = {QCONST16(.1f, 15), QCONST16(.05f, 15)};
+ st->spread_decision = hysteresis_decision(-st->analysis.tonality, spread_thresholds, spread_histeresis, 3, st->spread_decision);
+ st->tapset_decision = hysteresis_decision(st->analysis.tonality_slope, tapset_thresholds, tapset_histeresis, 2, st->tapset_decision);
+ } else
+#endif
+ {
+ st->spread_decision = spreading_decision(mode, X,
+ &st->tonal_average, st->spread_decision, &st->hf_average,
+ &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M);
+ }
+ /*printf("%d %d\n", st->tapset_decision, st->spread_decision);*/
+ /*printf("%f %d %f %d\n\n", st->analysis.tonality, st->spread_decision, st->analysis.tonality_slope, st->tapset_decision);*/
+ }
+ ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5);
+ }
+
+ ALLOC(offsets, nbEBands, int);
+
+ maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets,
+ st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr,
+ eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc);
+ /* For LFE, everything interesting is in the first band */
+ if (st->lfe)
+ offsets[0] = IMIN(8, effectiveBytes/3);
+ ALLOC(cap, nbEBands, int);
+ init_caps(mode,cap,LM,C);
+
+ dynalloc_logp = 6;
+ total_bits<<=BITRES;
+ total_boost = 0;
+ tell = ec_tell_frac(enc);
+ for (i=start;i<end;i++)
+ {
+ int width, quanta;
+ int dynalloc_loop_logp;
+ int boost;
+ int j;
+ width = C*(eBands[i+1]-eBands[i])<<LM;
+ /* quanta is 6 bits, but no more than 1 bit/sample
+ and no less than 1/8 bit/sample */
+ quanta = IMIN(width<<BITRES, IMAX(6<<BITRES, width));
+ dynalloc_loop_logp = dynalloc_logp;
+ boost = 0;
+ for (j = 0; tell+(dynalloc_loop_logp<<BITRES) < total_bits-total_boost
+ && boost < cap[i]; j++)
+ {
+ int flag;
+ flag = j<offsets[i];
+ ec_enc_bit_logp(enc, flag, dynalloc_loop_logp);
+ tell = ec_tell_frac(enc);
+ if (!flag)
+ break;
+ boost += quanta;
+ total_boost += quanta;
+ dynalloc_loop_logp = 1;
+ }
+ /* Making dynalloc more likely */
+ if (j)
+ dynalloc_logp = IMAX(2, dynalloc_logp-1);
+ offsets[i] = boost;
+ }
+
+ if (C==2)
+ {
+ static const opus_val16 intensity_thresholds[21]=
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 off*/
+ { 1, 2, 3, 4, 5, 6, 7, 8,16,24,36,44,50,56,62,67,72,79,88,106,134};
+ static const opus_val16 intensity_histeresis[21]=
+ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 5, 6, 8, 8};
+
+ /* Always use MS for 2.5 ms frames until we can do a better analysis */
+ if (LM!=0)
+ dual_stereo = stereo_analysis(mode, X, LM, N);
+
+ st->intensity = hysteresis_decision((opus_val16)(equiv_rate/1000),
+ intensity_thresholds, intensity_histeresis, 21, st->intensity);
+ st->intensity = IMIN(end,IMAX(start, st->intensity));
+ }
+
+ alloc_trim = 5;
+ if (tell+(6<<BITRES) <= total_bits - total_boost)
+ {
+ if (st->lfe)
+ alloc_trim = 5;
+ else
+ alloc_trim = alloc_trim_analysis(mode, X, bandLogE,
+ end, LM, C, N, &st->analysis, &st->stereo_saving, tf_estimate,
+ st->intensity, surround_trim, st->arch);
+ ec_enc_icdf(enc, alloc_trim, trim_icdf, 7);
+ tell = ec_tell_frac(enc);
+ }
+
+ /* Variable bitrate */
+ if (vbr_rate>0)
+ {
+ opus_val16 alpha;
+ opus_int32 delta;
+ /* The target rate in 8th bits per frame */
+ opus_int32 target, base_target;
+ opus_int32 min_allowed;
+ int lm_diff = mode->maxLM - LM;
+
+ /* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms.
+ The CELT allocator will just not be able to use more than that anyway. */
+ nbCompressedBytes = IMIN(nbCompressedBytes,1275>>(3-LM));
+ base_target = vbr_rate - ((40*C+20)<<BITRES);
+
+ if (st->constrained_vbr)
+ base_target += (st->vbr_offset>>lm_diff);
+
+ target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate,
+ st->lastCodedBands, C, st->intensity, st->constrained_vbr,
+ st->stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth,
+ st->variable_duration, st->lfe, st->energy_mask!=NULL, surround_masking,
+ temporal_vbr);
+
+ /* The current offset is removed from the target and the space used
+ so far is added*/
+ target=target+tell;
+ /* In VBR mode the frame size must not be reduced so much that it would
+ result in the encoder running out of bits.
+ The margin of 2 bytes ensures that none of the bust-prevention logic
+ in the decoder will have triggered so far. */
+ min_allowed = ((tell+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3)) + 2 - nbFilledBytes;
+
+ nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3);
+ nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes);
+ nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes) - nbFilledBytes;
+
+ /* By how much did we "miss" the target on that frame */
+ delta = target - vbr_rate;
+
+ target=nbAvailableBytes<<(BITRES+3);
+
+ /*If the frame is silent we don't adjust our drift, otherwise
+ the encoder will shoot to very high rates after hitting a
+ span of silence, but we do allow the bitres to refill.
+ This means that we'll undershoot our target in CVBR/VBR modes
+ on files with lots of silence. */
+ if(silence)
+ {
+ nbAvailableBytes = 2;
+ target = 2*8<<BITRES;
+ delta = 0;
+ }
+
+ if (st->vbr_count < 970)
+ {
+ st->vbr_count++;
+ alpha = celt_rcp(SHL32(EXTEND32(st->vbr_count+20),16));
+ } else
+ alpha = QCONST16(.001f,15);
+ /* How many bits have we used in excess of what we're allowed */
+ if (st->constrained_vbr)
+ st->vbr_reservoir += target - vbr_rate;
+ /*printf ("%d\n", st->vbr_reservoir);*/
+
+ /* Compute the offset we need to apply in order to reach the target */
+ if (st->constrained_vbr)
+ {
+ st->vbr_drift += (opus_int32)MULT16_32_Q15(alpha,(delta*(1<<lm_diff))-st->vbr_offset-st->vbr_drift);
+ st->vbr_offset = -st->vbr_drift;
+ }
+ /*printf ("%d\n", st->vbr_drift);*/
+
+ if (st->constrained_vbr && st->vbr_reservoir < 0)
+ {
+ /* We're under the min value -- increase rate */
+ int adjust = (-st->vbr_reservoir)/(8<<BITRES);
+ /* Unless we're just coding silence */
+ nbAvailableBytes += silence?0:adjust;
+ st->vbr_reservoir = 0;
+ /*printf ("+%d\n", adjust);*/
+ }
+ nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes);
+ /*printf("%d\n", nbCompressedBytes*50*8);*/
+ /* This moves the raw bits to take into account the new compressed size */
+ ec_enc_shrink(enc, nbCompressedBytes);
+ }
+
+ /* Bit allocation */
+ ALLOC(fine_quant, nbEBands, int);
+ ALLOC(pulses, nbEBands, int);
+ ALLOC(fine_priority, nbEBands, int);
+
+ /* bits = packet size - where we are - safety*/
+ bits = (((opus_int32)nbCompressedBytes*8)<<BITRES) - ec_tell_frac(enc) - 1;
+ anti_collapse_rsv = isTransient&&LM>=2&&bits>=((LM+2)<<BITRES) ? (1<<BITRES) : 0;
+ bits -= anti_collapse_rsv;
+ signalBandwidth = end-1;
+#ifndef DISABLE_FLOAT_API
+ if (st->analysis.valid)
+ {
+ int min_bandwidth;
+ if (equiv_rate < (opus_int32)32000*C)
+ min_bandwidth = 13;
+ else if (equiv_rate < (opus_int32)48000*C)
+ min_bandwidth = 16;
+ else if (equiv_rate < (opus_int32)60000*C)
+ min_bandwidth = 18;
+ else if (equiv_rate < (opus_int32)80000*C)
+ min_bandwidth = 19;
+ else
+ min_bandwidth = 20;
+ signalBandwidth = IMAX(st->analysis.bandwidth, min_bandwidth);
+ }
+#endif
+ if (st->lfe)
+ signalBandwidth = 1;
+ codedBands = compute_allocation(mode, start, end, offsets, cap,
+ alloc_trim, &st->intensity, &dual_stereo, bits, &balance, pulses,
+ fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands, signalBandwidth);
+ if (st->lastCodedBands)
+ st->lastCodedBands = IMIN(st->lastCodedBands+1,IMAX(st->lastCodedBands-1,codedBands));
+ else
+ st->lastCodedBands = codedBands;
+
+ quant_fine_energy(mode, start, end, oldBandE, error, fine_quant, enc, C);
+
+ /* Residual quantisation */
+ ALLOC(collapse_masks, C*nbEBands, unsigned char);
+ quant_all_bands(1, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks,
+ bandE, pulses, shortBlocks, st->spread_decision,
+ dual_stereo, st->intensity, tf_res, nbCompressedBytes*(8<<BITRES)-anti_collapse_rsv,
+ balance, enc, LM, codedBands, &st->rng, st->arch);
+
+ if (anti_collapse_rsv > 0)
+ {
+ anti_collapse_on = st->consec_transient<2;
+#ifdef FUZZING
+ anti_collapse_on = rand()&0x1;
+#endif
+ ec_enc_bits(enc, anti_collapse_on, 1);
+ }
+ quant_energy_finalise(mode, start, end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C);
+
+ if (silence)
+ {
+ for (i=0;i<C*nbEBands;i++)
+ oldBandE[i] = -QCONST16(28.f,DB_SHIFT);
+ }
+
+#ifdef RESYNTH
+ /* Re-synthesis of the coded audio if required */
+ {
+ celt_sig *out_mem[2];
+
+ if (anti_collapse_on)
+ {
+ anti_collapse(mode, X, collapse_masks, LM, C, N,
+ start, end, oldBandE, oldLogE, oldLogE2, pulses, st->rng);
+ }
+
+ c=0; do {
+ OPUS_MOVE(st->syn_mem[c], st->syn_mem[c]+N, 2*MAX_PERIOD-N+overlap/2);
+ } while (++c<CC);
+
+ c=0; do {
+ out_mem[c] = st->syn_mem[c]+2*MAX_PERIOD-N;
+ } while (++c<CC);
+
+ celt_synthesis(mode, X, out_mem, oldBandE, start, effEnd,
+ C, CC, isTransient, LM, st->upsample, silence, st->arch);
+
+ c=0; do {
+ st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD);
+ st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD);
+ comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, mode->shortMdctSize,
+ st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset,
+ mode->window, overlap);
+ if (LM!=0)
+ comb_filter(out_mem[c]+mode->shortMdctSize, out_mem[c]+mode->shortMdctSize, st->prefilter_period, pitch_index, N-mode->shortMdctSize,
+ st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset,
+ mode->window, overlap);
+ } while (++c<CC);
+
+ /* We reuse freq[] as scratch space for the de-emphasis */
+ deemphasis(out_mem, (opus_val16*)pcm, N, CC, st->upsample, mode->preemph, st->preemph_memD);
+ st->prefilter_period_old = st->prefilter_period;
+ st->prefilter_gain_old = st->prefilter_gain;
+ st->prefilter_tapset_old = st->prefilter_tapset;
+ }
+#endif
+
+ st->prefilter_period = pitch_index;
+ st->prefilter_gain = gain1;
+ st->prefilter_tapset = prefilter_tapset;
+#ifdef RESYNTH
+ if (LM!=0)
+ {
+ st->prefilter_period_old = st->prefilter_period;
+ st->prefilter_gain_old = st->prefilter_gain;
+ st->prefilter_tapset_old = st->prefilter_tapset;
+ }
+#endif
+
+ if (CC==2&&C==1) {
+ OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands);
+ }
+
+ if (!isTransient)
+ {
+ OPUS_COPY(oldLogE2, oldLogE, CC*nbEBands);
+ OPUS_COPY(oldLogE, oldBandE, CC*nbEBands);
+ } else {
+ for (i=0;i<CC*nbEBands;i++)
+ oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]);
+ }
+ /* In case start or end were to change */
+ c=0; do
+ {
+ for (i=0;i<start;i++)
+ {
+ oldBandE[c*nbEBands+i]=0;
+ oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+ }
+ for (i=end;i<nbEBands;i++)
+ {
+ oldBandE[c*nbEBands+i]=0;
+ oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+ }
+ } while (++c<CC);
+
+ if (isTransient || transient_got_disabled)
+ st->consec_transient++;
+ else
+ st->consec_transient=0;
+ st->rng = enc->rng;
+
+ /* If there's any room left (can only happen for very high rates),
+ it's already filled with zeros */
+ ec_enc_done(enc);
+
+#ifdef CUSTOM_MODES
+ if (st->signalling)
+ nbCompressedBytes++;
+#endif
+
+ RESTORE_STACK;
+ if (ec_get_error(enc))
+ return OPUS_INTERNAL_ERROR;
+ else
+ return nbCompressedBytes;
+}
+
+
+#ifdef CUSTOM_MODES
+
+#ifdef FIXED_POINT
+int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ int j, ret, C, N;
+ VARDECL(opus_int16, in);
+ ALLOC_STACK;
+
+ if (pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ C = st->channels;
+ N = frame_size;
+ ALLOC(in, C*N, opus_int16);
+
+ for (j=0;j<C*N;j++)
+ in[j] = FLOAT2INT16(pcm[j]);
+
+ ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
+#ifdef RESYNTH
+ for (j=0;j<C*N;j++)
+ ((float*)pcm)[j]=in[j]*(1.f/32768.f);
+#endif
+ RESTORE_STACK;
+ return ret;
+}
+#endif /* DISABLE_FLOAT_API */
+#else
+
+int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ int j, ret, C, N;
+ VARDECL(celt_sig, in);
+ ALLOC_STACK;
+
+ if (pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ C=st->channels;
+ N=frame_size;
+ ALLOC(in, C*N, celt_sig);
+ for (j=0;j<C*N;j++) {
+ in[j] = SCALEOUT(pcm[j]);
+ }
+
+ ret = celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
+#ifdef RESYNTH
+ for (j=0;j<C*N;j++)
+ ((opus_int16*)pcm)[j] = FLOAT2INT16(in[j]);
+#endif
+ RESTORE_STACK;
+ return ret;
+}
+
+int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
+}
+
+#endif
+
+#endif /* CUSTOM_MODES */
+
+int opus_custom_encoder_ctl(CELTEncoder * OPUS_RESTRICT st, int request, ...)
+{
+ va_list ap;
+
+ va_start(ap, request);
+ switch (request)
+ {
+ case OPUS_SET_COMPLEXITY_REQUEST:
+ {
+ int value = va_arg(ap, opus_int32);
+ if (value<0 || value>10)
+ goto bad_arg;
+ st->complexity = value;
+ }
+ break;
+ case CELT_SET_START_BAND_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<0 || value>=st->mode->nbEBands)
+ goto bad_arg;
+ st->start = value;
+ }
+ break;
+ case CELT_SET_END_BAND_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<1 || value>st->mode->nbEBands)
+ goto bad_arg;
+ st->end = value;
+ }
+ break;
+ case CELT_SET_PREDICTION_REQUEST:
+ {
+ int value = va_arg(ap, opus_int32);
+ if (value<0 || value>2)
+ goto bad_arg;
+ st->disable_pf = value<=1;
+ st->force_intra = value==0;
+ }
+ break;
+ case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+ {
+ int value = va_arg(ap, opus_int32);
+ if (value<0 || value>100)
+ goto bad_arg;
+ st->loss_rate = value;
+ }
+ break;
+ case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->constrained_vbr = value;
+ }
+ break;
+ case OPUS_SET_VBR_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->vbr = value;
+ }
+ break;
+ case OPUS_SET_BITRATE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<=500 && value!=OPUS_BITRATE_MAX)
+ goto bad_arg;
+ value = IMIN(value, 260000*st->channels);
+ st->bitrate = value;
+ }
+ break;
+ case CELT_SET_CHANNELS_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<1 || value>2)
+ goto bad_arg;
+ st->stream_channels = value;
+ }
+ break;
+ case OPUS_SET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<8 || value>24)
+ goto bad_arg;
+ st->lsb_depth=value;
+ }
+ break;
+ case OPUS_GET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ *value=st->lsb_depth;
+ }
+ break;
+ case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->variable_duration = value;
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ int i;
+ opus_val16 *oldBandE, *oldLogE, *oldLogE2;
+ oldBandE = (opus_val16*)(st->in_mem+st->channels*(st->mode->overlap+COMBFILTER_MAXPERIOD));
+ oldLogE = oldBandE + st->channels*st->mode->nbEBands;
+ oldLogE2 = oldLogE + st->channels*st->mode->nbEBands;
+ OPUS_CLEAR((char*)&st->ENCODER_RESET_START,
+ opus_custom_encoder_get_size(st->mode, st->channels)-
+ ((char*)&st->ENCODER_RESET_START - (char*)st));
+ for (i=0;i<st->channels*st->mode->nbEBands;i++)
+ oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT);
+ st->vbr_offset = 0;
+ st->delayedIntra = 1;
+ st->spread_decision = SPREAD_NORMAL;
+ st->tonal_average = 256;
+ st->hf_average = 0;
+ st->tapset_decision = 0;
+ }
+ break;
+#ifdef CUSTOM_MODES
+ case CELT_SET_INPUT_CLIPPING_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->clip = value;
+ }
+ break;
+#endif
+ case CELT_SET_SIGNALLING_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->signalling = value;
+ }
+ break;
+ case CELT_SET_ANALYSIS_REQUEST:
+ {
+ AnalysisInfo *info = va_arg(ap, AnalysisInfo *);
+ if (info)
+ OPUS_COPY(&st->analysis, info, 1);
+ }
+ break;
+ case CELT_GET_MODE_REQUEST:
+ {
+ const CELTMode ** value = va_arg(ap, const CELTMode**);
+ if (value==0)
+ goto bad_arg;
+ *value=st->mode;
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ opus_uint32 * value = va_arg(ap, opus_uint32 *);
+ if (value==0)
+ goto bad_arg;
+ *value=st->rng;
+ }
+ break;
+ case OPUS_SET_LFE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->lfe = value;
+ }
+ break;
+ case OPUS_SET_ENERGY_MASK_REQUEST:
+ {
+ opus_val16 *value = va_arg(ap, opus_val16*);
+ st->energy_mask = value;
+ }
+ break;
+ default:
+ goto bad_request;
+ }
+ va_end(ap);
+ return OPUS_OK;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+bad_request:
+ va_end(ap);
+ return OPUS_UNIMPLEMENTED;
+}
diff --git a/external/opus-1.1.4/celt/celt_lpc.c b/external/opus-1.1.4/celt/celt_lpc.c
new file mode 100644
index 0000000..b410a21
--- /dev/null
+++ b/external/opus-1.1.4/celt/celt_lpc.c
@@ -0,0 +1,314 @@
+/* Copyright (c) 2009-2010 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "celt_lpc.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "pitch.h"
+
+void _celt_lpc(
+ opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */
+const opus_val32 *ac, /* in: [0...p] autocorrelation values */
+int p
+)
+{
+ int i, j;
+ opus_val32 r;
+ opus_val32 error = ac[0];
+#ifdef FIXED_POINT
+ opus_val32 lpc[LPC_ORDER];
+#else
+ float *lpc = _lpc;
+#endif
+
+ OPUS_CLEAR(lpc, p);
+ if (ac[0] != 0)
+ {
+ for (i = 0; i < p; i++) {
+ /* Sum up this iteration's reflection coefficient */
+ opus_val32 rr = 0;
+ for (j = 0; j < i; j++)
+ rr += MULT32_32_Q31(lpc[j],ac[i - j]);
+ rr += SHR32(ac[i + 1],3);
+ r = -frac_div32(SHL32(rr,3), error);
+ /* Update LPC coefficients and total error */
+ lpc[i] = SHR32(r,3);
+ for (j = 0; j < (i+1)>>1; j++)
+ {
+ opus_val32 tmp1, tmp2;
+ tmp1 = lpc[j];
+ tmp2 = lpc[i-1-j];
+ lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2);
+ lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1);
+ }
+
+ error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error);
+ /* Bail out once we get 30 dB gain */
+#ifdef FIXED_POINT
+ if (error<SHR32(ac[0],10))
+ break;
+#else
+ if (error<.001f*ac[0])
+ break;
+#endif
+ }
+ }
+#ifdef FIXED_POINT
+ for (i=0;i<p;i++)
+ _lpc[i] = ROUND16(lpc[i],16);
+#endif
+}
+
+
+void celt_fir_c(
+ const opus_val16 *_x,
+ const opus_val16 *num,
+ opus_val16 *_y,
+ int N,
+ int ord,
+ opus_val16 *mem,
+ int arch)
+{
+ int i,j;
+ VARDECL(opus_val16, rnum);
+ VARDECL(opus_val16, x);
+ SAVE_STACK;
+
+ ALLOC(rnum, ord, opus_val16);
+ ALLOC(x, N+ord, opus_val16);
+ for(i=0;i<ord;i++)
+ rnum[i] = num[ord-i-1];
+ for(i=0;i<ord;i++)
+ x[i] = mem[ord-i-1];
+ for (i=0;i<N;i++)
+ x[i+ord]=_x[i];
+ for(i=0;i<ord;i++)
+ mem[i] = _x[N-i-1];
+#ifdef SMALL_FOOTPRINT
+ (void)arch;
+ for (i=0;i<N;i++)
+ {
+ opus_val32 sum = SHL32(EXTEND32(_x[i]), SIG_SHIFT);
+ for (j=0;j<ord;j++)
+ {
+ sum = MAC16_16(sum,rnum[j],x[i+j]);
+ }
+ _y[i] = SATURATE16(PSHR32(sum, SIG_SHIFT));
+ }
+#else
+ for (i=0;i<N-3;i+=4)
+ {
+ opus_val32 sum[4]={0,0,0,0};
+ xcorr_kernel(rnum, x+i, sum, ord, arch);
+ _y[i ] = SATURATE16(ADD32(EXTEND32(_x[i ]), PSHR32(sum[0], SIG_SHIFT)));
+ _y[i+1] = SATURATE16(ADD32(EXTEND32(_x[i+1]), PSHR32(sum[1], SIG_SHIFT)));
+ _y[i+2] = SATURATE16(ADD32(EXTEND32(_x[i+2]), PSHR32(sum[2], SIG_SHIFT)));
+ _y[i+3] = SATURATE16(ADD32(EXTEND32(_x[i+3]), PSHR32(sum[3], SIG_SHIFT)));
+ }
+ for (;i<N;i++)
+ {
+ opus_val32 sum = 0;
+ for (j=0;j<ord;j++)
+ sum = MAC16_16(sum,rnum[j],x[i+j]);
+ _y[i] = SATURATE16(ADD32(EXTEND32(_x[i]), PSHR32(sum, SIG_SHIFT)));
+ }
+#endif
+ RESTORE_STACK;
+}
+
+void celt_iir(const opus_val32 *_x,
+ const opus_val16 *den,
+ opus_val32 *_y,
+ int N,
+ int ord,
+ opus_val16 *mem,
+ int arch)
+{
+#ifdef SMALL_FOOTPRINT
+ int i,j;
+ (void)arch;
+ for (i=0;i<N;i++)
+ {
+ opus_val32 sum = _x[i];
+ for (j=0;j<ord;j++)
+ {
+ sum -= MULT16_16(den[j],mem[j]);
+ }
+ for (j=ord-1;j>=1;j--)
+ {
+ mem[j]=mem[j-1];
+ }
+ mem[0] = ROUND16(sum,SIG_SHIFT);
+ _y[i] = sum;
+ }
+#else
+ int i,j;
+ VARDECL(opus_val16, rden);
+ VARDECL(opus_val16, y);
+ SAVE_STACK;
+
+ celt_assert((ord&3)==0);
+ ALLOC(rden, ord, opus_val16);
+ ALLOC(y, N+ord, opus_val16);
+ for(i=0;i<ord;i++)
+ rden[i] = den[ord-i-1];
+ for(i=0;i<ord;i++)
+ y[i] = -mem[ord-i-1];
+ for(;i<N+ord;i++)
+ y[i]=0;
+ for (i=0;i<N-3;i+=4)
+ {
+ /* Unroll by 4 as if it were an FIR filter */
+ opus_val32 sum[4];
+ sum[0]=_x[i];
+ sum[1]=_x[i+1];
+ sum[2]=_x[i+2];
+ sum[3]=_x[i+3];
+ xcorr_kernel(rden, y+i, sum, ord, arch);
+
+ /* Patch up the result to compensate for the fact that this is an IIR */
+ y[i+ord ] = -ROUND16(sum[0],SIG_SHIFT);
+ _y[i ] = sum[0];
+ sum[1] = MAC16_16(sum[1], y[i+ord ], den[0]);
+ y[i+ord+1] = -ROUND16(sum[1],SIG_SHIFT);
+ _y[i+1] = sum[1];
+ sum[2] = MAC16_16(sum[2], y[i+ord+1], den[0]);
+ sum[2] = MAC16_16(sum[2], y[i+ord ], den[1]);
+ y[i+ord+2] = -ROUND16(sum[2],SIG_SHIFT);
+ _y[i+2] = sum[2];
+
+ sum[3] = MAC16_16(sum[3], y[i+ord+2], den[0]);
+ sum[3] = MAC16_16(sum[3], y[i+ord+1], den[1]);
+ sum[3] = MAC16_16(sum[3], y[i+ord ], den[2]);
+ y[i+ord+3] = -ROUND16(sum[3],SIG_SHIFT);
+ _y[i+3] = sum[3];
+ }
+ for (;i<N;i++)
+ {
+ opus_val32 sum = _x[i];
+ for (j=0;j<ord;j++)
+ sum -= MULT16_16(rden[j],y[i+j]);
+ y[i+ord] = ROUND16(sum,SIG_SHIFT);
+ _y[i] = sum;
+ }
+ for(i=0;i<ord;i++)
+ mem[i] = _y[N-i-1];
+ RESTORE_STACK;
+#endif
+}
+
+int _celt_autocorr(
+ const opus_val16 *x, /* in: [0...n-1] samples x */
+ opus_val32 *ac, /* out: [0...lag-1] ac values */
+ const opus_val16 *window,
+ int overlap,
+ int lag,
+ int n,
+ int arch
+ )
+{
+ opus_val32 d;
+ int i, k;
+ int fastN=n-lag;
+ int shift;
+ const opus_val16 *xptr;
+ VARDECL(opus_val16, xx);
+ SAVE_STACK;
+ ALLOC(xx, n, opus_val16);
+ celt_assert(n>0);
+ celt_assert(overlap>=0);
+ if (overlap == 0)
+ {
+ xptr = x;
+ } else {
+ for (i=0;i<n;i++)
+ xx[i] = x[i];
+ for (i=0;i<overlap;i++)
+ {
+ xx[i] = MULT16_16_Q15(x[i],window[i]);
+ xx[n-i-1] = MULT16_16_Q15(x[n-i-1],window[i]);
+ }
+ xptr = xx;
+ }
+ shift=0;
+#ifdef FIXED_POINT
+ {
+ opus_val32 ac0;
+ ac0 = 1+(n<<7);
+ if (n&1) ac0 += SHR32(MULT16_16(xptr[0],xptr[0]),9);
+ for(i=(n&1);i<n;i+=2)
+ {
+ ac0 += SHR32(MULT16_16(xptr[i],xptr[i]),9);
+ ac0 += SHR32(MULT16_16(xptr[i+1],xptr[i+1]),9);
+ }
+
+ shift = celt_ilog2(ac0)-30+10;
+ shift = (shift)/2;
+ if (shift>0)
+ {
+ for(i=0;i<n;i++)
+ xx[i] = PSHR32(xptr[i], shift);
+ xptr = xx;
+ } else
+ shift = 0;
+ }
+#endif
+ celt_pitch_xcorr(xptr, xptr, ac, fastN, lag+1, arch);
+ for (k=0;k<=lag;k++)
+ {
+ for (i = k+fastN, d = 0; i < n; i++)
+ d = MAC16_16(d, xptr[i], xptr[i-k]);
+ ac[k] += d;
+ }
+#ifdef FIXED_POINT
+ shift = 2*shift;
+ if (shift<=0)
+ ac[0] += SHL32((opus_int32)1, -shift);
+ if (ac[0] < 268435456)
+ {
+ int shift2 = 29 - EC_ILOG(ac[0]);
+ for (i=0;i<=lag;i++)
+ ac[i] = SHL32(ac[i], shift2);
+ shift -= shift2;
+ } else if (ac[0] >= 536870912)
+ {
+ int shift2=1;
+ if (ac[0] >= 1073741824)
+ shift2++;
+ for (i=0;i<=lag;i++)
+ ac[i] = SHR32(ac[i], shift2);
+ shift += shift2;
+ }
+#endif
+
+ RESTORE_STACK;
+ return shift;
+}
diff --git a/external/opus-1.1.4/celt/celt_lpc.h b/external/opus-1.1.4/celt/celt_lpc.h
new file mode 100644
index 0000000..323459e
--- /dev/null
+++ b/external/opus-1.1.4/celt/celt_lpc.h
@@ -0,0 +1,67 @@
+/* Copyright (c) 2009-2010 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef PLC_H
+#define PLC_H
+
+#include "arch.h"
+#include "cpu_support.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#include "x86/celt_lpc_sse.h"
+#endif
+
+#define LPC_ORDER 24
+
+void _celt_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p);
+
+void celt_fir_c(
+ const opus_val16 *x,
+ const opus_val16 *num,
+ opus_val16 *y,
+ int N,
+ int ord,
+ opus_val16 *mem,
+ int arch);
+
+#if !defined(OVERRIDE_CELT_FIR)
+#define celt_fir(x, num, y, N, ord, mem, arch) \
+ (celt_fir_c(x, num, y, N, ord, mem, arch))
+#endif
+
+void celt_iir(const opus_val32 *x,
+ const opus_val16 *den,
+ opus_val32 *y,
+ int N,
+ int ord,
+ opus_val16 *mem,
+ int arch);
+
+int _celt_autocorr(const opus_val16 *x, opus_val32 *ac,
+ const opus_val16 *window, int overlap, int lag, int n, int arch);
+
+#endif /* PLC_H */
diff --git a/external/opus-1.1.4/celt/cpu_support.h b/external/opus-1.1.4/celt/cpu_support.h
new file mode 100644
index 0000000..68fc606
--- /dev/null
+++ b/external/opus-1.1.4/celt/cpu_support.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef CPU_SUPPORT_H
+#define CPU_SUPPORT_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#if defined(OPUS_HAVE_RTCD) && \
+ (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR))
+#include "arm/armcpu.h"
+
+/* We currently support 4 ARM variants:
+ * arch[0] -> ARMv4
+ * arch[1] -> ARMv5E
+ * arch[2] -> ARMv6
+ * arch[3] -> NEON
+ */
+#define OPUS_ARCHMASK 3
+
+#elif (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(OPUS_X86_PRESUME_SSE)) || \
+ (defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2)) || \
+ (defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)) || \
+ (defined(OPUS_X86_MAY_HAVE_AVX) && !defined(OPUS_X86_PRESUME_AVX))
+
+#include "x86/x86cpu.h"
+/* We currently support 5 x86 variants:
+ * arch[0] -> non-sse
+ * arch[1] -> sse
+ * arch[2] -> sse2
+ * arch[3] -> sse4.1
+ * arch[4] -> avx
+ */
+#define OPUS_ARCHMASK 7
+int opus_select_arch(void);
+
+#else
+#define OPUS_ARCHMASK 0
+
+static OPUS_INLINE int opus_select_arch(void)
+{
+ return 0;
+}
+#endif
+#endif
diff --git a/external/opus-1.1.4/celt/cwrs.c b/external/opus-1.1.4/celt/cwrs.c
new file mode 100644
index 0000000..9722f0a
--- /dev/null
+++ b/external/opus-1.1.4/celt/cwrs.c
@@ -0,0 +1,715 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2007-2009 Timothy B. Terriberry
+ Written by Timothy B. Terriberry and Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "os_support.h"
+#include "cwrs.h"
+#include "mathops.h"
+#include "arch.h"
+
+#ifdef CUSTOM_MODES
+
+/*Guaranteed to return a conservatively large estimate of the binary logarithm
+ with frac bits of fractional precision.
+ Tested for all possible 32-bit inputs with frac=4, where the maximum
+ overestimation is 0.06254243 bits.*/
+int log2_frac(opus_uint32 val, int frac)
+{
+ int l;
+ l=EC_ILOG(val);
+ if(val&(val-1)){
+ /*This is (val>>l-16), but guaranteed to round up, even if adding a bias
+ before the shift would cause overflow (e.g., for 0xFFFFxxxx).
+ Doesn't work for val=0, but that case fails the test above.*/
+ if(l>16)val=((val-1)>>(l-16))+1;
+ else val<<=16-l;
+ l=(l-1)<<frac;
+ /*Note that we always need one iteration, since the rounding up above means
+ that we might need to adjust the integer part of the logarithm.*/
+ do{
+ int b;
+ b=(int)(val>>16);
+ l+=b<<frac;
+ val=(val+b)>>b;
+ val=(val*val+0x7FFF)>>15;
+ }
+ while(frac-->0);
+ /*If val is not exactly 0x8000, then we have to round up the remainder.*/
+ return l+(val>0x8000);
+ }
+ /*Exact powers of two require no rounding.*/
+ else return (l-1)<<frac;
+}
+#endif
+
+/*Although derived separately, the pulse vector coding scheme is equivalent to
+ a Pyramid Vector Quantizer \cite{Fis86}.
+ Some additional notes about an early version appear at
+ https://people.xiph.org/~tterribe/notes/cwrs.html, but the codebook ordering
+ and the definitions of some terms have evolved since that was written.
+
+ The conversion from a pulse vector to an integer index (encoding) and back
+ (decoding) is governed by two related functions, V(N,K) and U(N,K).
+
+ V(N,K) = the number of combinations, with replacement, of N items, taken K
+ at a time, when a sign bit is added to each item taken at least once (i.e.,
+ the number of N-dimensional unit pulse vectors with K pulses).
+ One way to compute this is via
+ V(N,K) = K>0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1,
+ where choose() is the binomial function.
+ A table of values for N<10 and K<10 looks like:
+ V[10][10] = {
+ {1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {1, 2, 2, 2, 2, 2, 2, 2, 2, 2},
+ {1, 4, 8, 12, 16, 20, 24, 28, 32, 36},
+ {1, 6, 18, 38, 66, 102, 146, 198, 258, 326},
+ {1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992},
+ {1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290},
+ {1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436},
+ {1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598},
+ {1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688},
+ {1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146}
+ };
+
+ U(N,K) = the number of such combinations wherein N-1 objects are taken at
+ most K-1 at a time.
+ This is given by
+ U(N,K) = sum(k=0...K-1,V(N-1,k))
+ = K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0.
+ The latter expression also makes clear that U(N,K) is half the number of such
+ combinations wherein the first object is taken at least once.
+ Although it may not be clear from either of these definitions, U(N,K) is the
+ natural function to work with when enumerating the pulse vector codebooks,
+ not V(N,K).
+ U(N,K) is not well-defined for N=0, but with the extension
+ U(0,K) = K>0 ? 0 : 1,
+ the function becomes symmetric: U(N,K) = U(K,N), with a similar table:
+ U[10][10] = {
+ {1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 3, 5, 7, 9, 11, 13, 15, 17},
+ {0, 1, 5, 13, 25, 41, 61, 85, 113, 145},
+ {0, 1, 7, 25, 63, 129, 231, 377, 575, 833},
+ {0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649},
+ {0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073},
+ {0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081},
+ {0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545},
+ {0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729}
+ };
+
+ With this extension, V(N,K) may be written in terms of U(N,K):
+ V(N,K) = U(N,K) + U(N,K+1)
+ for all N>=0, K>=0.
+ Thus U(N,K+1) represents the number of combinations where the first element
+ is positive or zero, and U(N,K) represents the number of combinations where
+ it is negative.
+ With a large enough table of U(N,K) values, we could write O(N) encoding
+ and O(min(N*log(K),N+K)) decoding routines, but such a table would be
+ prohibitively large for small embedded devices (K may be as large as 32767
+ for small N, and N may be as large as 200).
+
+ Both functions obey the same recurrence relation:
+ V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1),
+ U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1),
+ for all N>0, K>0, with different initial conditions at N=0 or K=0.
+ This allows us to construct a row of one of the tables above given the
+ previous row or the next row.
+ Thus we can derive O(NK) encoding and decoding routines with O(K) memory
+ using only addition and subtraction.
+
+ When encoding, we build up from the U(2,K) row and work our way forwards.
+ When decoding, we need to start at the U(N,K) row and work our way backwards,
+ which requires a means of computing U(N,K).
+ U(N,K) may be computed from two previous values with the same N:
+ U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2)
+ for all N>1, and since U(N,K) is symmetric, a similar relation holds for two
+ previous values with the same K:
+ U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K)
+ for all K>1.
+ This allows us to construct an arbitrary row of the U(N,K) table by starting
+ with the first two values, which are constants.
+ This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K)
+ multiplications.
+ Similar relations can be derived for V(N,K), but are not used here.
+
+ For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree
+ polynomial for fixed N.
+ The first few are
+ U(1,K) = 1,
+ U(2,K) = 2*K-1,
+ U(3,K) = (2*K-2)*K+1,
+ U(4,K) = (((4*K-6)*K+8)*K-3)/3,
+ U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3,
+ and
+ V(1,K) = 2,
+ V(2,K) = 4*K,
+ V(3,K) = 4*K*K+2,
+ V(4,K) = 8*(K*K+2)*K/3,
+ V(5,K) = ((4*K*K+20)*K*K+6)/3,
+ for all K>0.
+ This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for
+ small N (and indeed decoding is also O(N) for N<3).
+
+ @ARTICLE{Fis86,
+ author="Thomas R. Fischer",
+ title="A Pyramid Vector Quantizer",
+ journal="IEEE Transactions on Information Theory",
+ volume="IT-32",
+ number=4,
+ pages="568--583",
+ month=Jul,
+ year=1986
+ }*/
+
+#if !defined(SMALL_FOOTPRINT)
+
+/*U(N,K) = U(K,N) := N>0?K>0?U(N-1,K)+U(N,K-1)+U(N-1,K-1):0:K>0?1:0*/
+# define CELT_PVQ_U(_n,_k) (CELT_PVQ_U_ROW[IMIN(_n,_k)][IMAX(_n,_k)])
+/*V(N,K) := U(N,K)+U(N,K+1) = the number of PVQ codewords for a band of size N
+ with K pulses allocated to it.*/
+# define CELT_PVQ_V(_n,_k) (CELT_PVQ_U(_n,_k)+CELT_PVQ_U(_n,(_k)+1))
+
+/*For each V(N,K) supported, we will access element U(min(N,K+1),max(N,K+1)).
+ Thus, the number of entries in row I is the larger of the maximum number of
+ pulses we will ever allocate for a given N=I (K=128, or however many fit in
+ 32 bits, whichever is smaller), plus one, and the maximum N for which
+ K=I-1 pulses fit in 32 bits.
+ The largest band size in an Opus Custom mode is 208.
+ Otherwise, we can limit things to the set of N which can be achieved by
+ splitting a band from a standard Opus mode: 176, 144, 96, 88, 72, 64, 48,
+ 44, 36, 32, 24, 22, 18, 16, 8, 4, 2).*/
+#if defined(CUSTOM_MODES)
+static const opus_uint32 CELT_PVQ_U_DATA[1488]={
+#else
+static const opus_uint32 CELT_PVQ_U_DATA[1272]={
+#endif
+ /*N=0, K=0...176:*/
+ 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, 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,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 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,
+#endif
+ /*N=1, K=1...176:*/
+ 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, 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, 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, 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, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 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,
+#endif
+ /*N=2, K=2...176:*/
+ 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41,
+ 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79,
+ 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113,
+ 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143,
+ 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
+ 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203,
+ 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233,
+ 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263,
+ 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293,
+ 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323,
+ 325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381,
+ 383, 385, 387, 389, 391, 393, 395, 397, 399, 401, 403, 405, 407, 409, 411,
+ 413, 415,
+#endif
+ /*N=3, K=3...176:*/
+ 13, 25, 41, 61, 85, 113, 145, 181, 221, 265, 313, 365, 421, 481, 545, 613,
+ 685, 761, 841, 925, 1013, 1105, 1201, 1301, 1405, 1513, 1625, 1741, 1861,
+ 1985, 2113, 2245, 2381, 2521, 2665, 2813, 2965, 3121, 3281, 3445, 3613, 3785,
+ 3961, 4141, 4325, 4513, 4705, 4901, 5101, 5305, 5513, 5725, 5941, 6161, 6385,
+ 6613, 6845, 7081, 7321, 7565, 7813, 8065, 8321, 8581, 8845, 9113, 9385, 9661,
+ 9941, 10225, 10513, 10805, 11101, 11401, 11705, 12013, 12325, 12641, 12961,
+ 13285, 13613, 13945, 14281, 14621, 14965, 15313, 15665, 16021, 16381, 16745,
+ 17113, 17485, 17861, 18241, 18625, 19013, 19405, 19801, 20201, 20605, 21013,
+ 21425, 21841, 22261, 22685, 23113, 23545, 23981, 24421, 24865, 25313, 25765,
+ 26221, 26681, 27145, 27613, 28085, 28561, 29041, 29525, 30013, 30505, 31001,
+ 31501, 32005, 32513, 33025, 33541, 34061, 34585, 35113, 35645, 36181, 36721,
+ 37265, 37813, 38365, 38921, 39481, 40045, 40613, 41185, 41761, 42341, 42925,
+ 43513, 44105, 44701, 45301, 45905, 46513, 47125, 47741, 48361, 48985, 49613,
+ 50245, 50881, 51521, 52165, 52813, 53465, 54121, 54781, 55445, 56113, 56785,
+ 57461, 58141, 58825, 59513, 60205, 60901, 61601,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 62305, 63013, 63725, 64441, 65161, 65885, 66613, 67345, 68081, 68821, 69565,
+ 70313, 71065, 71821, 72581, 73345, 74113, 74885, 75661, 76441, 77225, 78013,
+ 78805, 79601, 80401, 81205, 82013, 82825, 83641, 84461, 85285, 86113,
+#endif
+ /*N=4, K=4...176:*/
+ 63, 129, 231, 377, 575, 833, 1159, 1561, 2047, 2625, 3303, 4089, 4991, 6017,
+ 7175, 8473, 9919, 11521, 13287, 15225, 17343, 19649, 22151, 24857, 27775,
+ 30913, 34279, 37881, 41727, 45825, 50183, 54809, 59711, 64897, 70375, 76153,
+ 82239, 88641, 95367, 102425, 109823, 117569, 125671, 134137, 142975, 152193,
+ 161799, 171801, 182207, 193025, 204263, 215929, 228031, 240577, 253575,
+ 267033, 280959, 295361, 310247, 325625, 341503, 357889, 374791, 392217,
+ 410175, 428673, 447719, 467321, 487487, 508225, 529543, 551449, 573951,
+ 597057, 620775, 645113, 670079, 695681, 721927, 748825, 776383, 804609,
+ 833511, 863097, 893375, 924353, 956039, 988441, 1021567, 1055425, 1090023,
+ 1125369, 1161471, 1198337, 1235975, 1274393, 1313599, 1353601, 1394407,
+ 1436025, 1478463, 1521729, 1565831, 1610777, 1656575, 1703233, 1750759,
+ 1799161, 1848447, 1898625, 1949703, 2001689, 2054591, 2108417, 2163175,
+ 2218873, 2275519, 2333121, 2391687, 2451225, 2511743, 2573249, 2635751,
+ 2699257, 2763775, 2829313, 2895879, 2963481, 3032127, 3101825, 3172583,
+ 3244409, 3317311, 3391297, 3466375, 3542553, 3619839, 3698241, 3777767,
+ 3858425, 3940223, 4023169, 4107271, 4192537, 4278975, 4366593, 4455399,
+ 4545401, 4636607, 4729025, 4822663, 4917529, 5013631, 5110977, 5209575,
+ 5309433, 5410559, 5512961, 5616647, 5721625, 5827903, 5935489, 6044391,
+ 6154617, 6266175, 6379073, 6493319, 6608921, 6725887, 6844225, 6963943,
+ 7085049, 7207551,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 7331457, 7456775, 7583513, 7711679, 7841281, 7972327, 8104825, 8238783,
+ 8374209, 8511111, 8649497, 8789375, 8930753, 9073639, 9218041, 9363967,
+ 9511425, 9660423, 9810969, 9963071, 10116737, 10271975, 10428793, 10587199,
+ 10747201, 10908807, 11072025, 11236863, 11403329, 11571431, 11741177,
+ 11912575,
+#endif
+ /*N=5, K=5...176:*/
+ 321, 681, 1289, 2241, 3649, 5641, 8361, 11969, 16641, 22569, 29961, 39041,
+ 50049, 63241, 78889, 97281, 118721, 143529, 172041, 204609, 241601, 283401,
+ 330409, 383041, 441729, 506921, 579081, 658689, 746241, 842249, 947241,
+ 1061761, 1186369, 1321641, 1468169, 1626561, 1797441, 1981449, 2179241,
+ 2391489, 2618881, 2862121, 3121929, 3399041, 3694209, 4008201, 4341801,
+ 4695809, 5071041, 5468329, 5888521, 6332481, 6801089, 7295241, 7815849,
+ 8363841, 8940161, 9545769, 10181641, 10848769, 11548161, 12280841, 13047849,
+ 13850241, 14689089, 15565481, 16480521, 17435329, 18431041, 19468809,
+ 20549801, 21675201, 22846209, 24064041, 25329929, 26645121, 28010881,
+ 29428489, 30899241, 32424449, 34005441, 35643561, 37340169, 39096641,
+ 40914369, 42794761, 44739241, 46749249, 48826241, 50971689, 53187081,
+ 55473921, 57833729, 60268041, 62778409, 65366401, 68033601, 70781609,
+ 73612041, 76526529, 79526721, 82614281, 85790889, 89058241, 92418049,
+ 95872041, 99421961, 103069569, 106816641, 110664969, 114616361, 118672641,
+ 122835649, 127107241, 131489289, 135983681, 140592321, 145317129, 150160041,
+ 155123009, 160208001, 165417001, 170752009, 176215041, 181808129, 187533321,
+ 193392681, 199388289, 205522241, 211796649, 218213641, 224775361, 231483969,
+ 238341641, 245350569, 252512961, 259831041, 267307049, 274943241, 282741889,
+ 290705281, 298835721, 307135529, 315607041, 324252609, 333074601, 342075401,
+ 351257409, 360623041, 370174729, 379914921, 389846081, 399970689, 410291241,
+ 420810249, 431530241, 442453761, 453583369, 464921641, 476471169, 488234561,
+ 500214441, 512413449, 524834241, 537479489, 550351881, 563454121, 576788929,
+ 590359041, 604167209, 618216201, 632508801,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 647047809, 661836041, 676876329, 692171521, 707724481, 723538089, 739615241,
+ 755958849, 772571841, 789457161, 806617769, 824056641, 841776769, 859781161,
+ 878072841, 896654849, 915530241, 934702089, 954173481, 973947521, 994027329,
+ 1014416041, 1035116809, 1056132801, 1077467201, 1099123209, 1121104041,
+ 1143412929, 1166053121, 1189027881, 1212340489, 1235994241,
+#endif
+ /*N=6, K=6...96:*/
+ 1683, 3653, 7183, 13073, 22363, 36365, 56695, 85305, 124515, 177045, 246047,
+ 335137, 448427, 590557, 766727, 982729, 1244979, 1560549, 1937199, 2383409,
+ 2908411, 3522221, 4235671, 5060441, 6009091, 7095093, 8332863, 9737793,
+ 11326283, 13115773, 15124775, 17372905, 19880915, 22670725, 25765455,
+ 29189457, 32968347, 37129037, 41699767, 46710137, 52191139, 58175189,
+ 64696159, 71789409, 79491819, 87841821, 96879431, 106646281, 117185651,
+ 128542501, 140763503, 153897073, 167993403, 183104493, 199284183, 216588185,
+ 235074115, 254801525, 275831935, 298228865, 322057867, 347386557, 374284647,
+ 402823977, 433078547, 465124549, 499040399, 534906769, 572806619, 612825229,
+ 655050231, 699571641, 746481891, 795875861, 847850911, 902506913, 959946283,
+ 1020274013, 1083597703, 1150027593, 1219676595, 1292660325, 1369097135,
+ 1449108145, 1532817275, 1620351277, 1711839767, 1807415257, 1907213187,
+ 2011371957, 2120032959,
+#if defined(CUSTOM_MODES)
+ /*...109:*/
+ 2233340609U, 2351442379U, 2474488829U, 2602633639U, 2736033641U, 2874848851U,
+ 3019242501U, 3169381071U, 3325434321U, 3487575323U, 3655980493U, 3830829623U,
+ 4012305913U,
+#endif
+ /*N=7, K=7...54*/
+ 8989, 19825, 40081, 75517, 134245, 227305, 369305, 579125, 880685, 1303777,
+ 1884961, 2668525, 3707509, 5064793, 6814249, 9041957, 11847485, 15345233,
+ 19665841, 24957661, 31388293, 39146185, 48442297, 59511829, 72616013,
+ 88043969, 106114625, 127178701, 151620757, 179861305, 212358985, 249612805,
+ 292164445, 340600625, 395555537, 457713341, 527810725, 606639529, 695049433,
+ 793950709, 904317037, 1027188385, 1163673953, 1314955181, 1482288821,
+ 1667010073, 1870535785, 2094367717,
+#if defined(CUSTOM_MODES)
+ /*...60:*/
+ 2340095869U, 2609401873U, 2904062449U, 3225952925U, 3577050821U, 3959439497U,
+#endif
+ /*N=8, K=8...37*/
+ 48639, 108545, 224143, 433905, 795455, 1392065, 2340495, 3800305, 5984767,
+ 9173505, 13726991, 20103025, 28875327, 40754369, 56610575, 77500017,
+ 104692735, 139703809, 184327311, 240673265, 311207743, 398796225, 506750351,
+ 638878193, 799538175, 993696769, 1226990095, 1505789553, 1837271615,
+ 2229491905U,
+#if defined(CUSTOM_MODES)
+ /*...40:*/
+ 2691463695U, 3233240945U, 3866006015U,
+#endif
+ /*N=9, K=9...28:*/
+ 265729, 598417, 1256465, 2485825, 4673345, 8405905, 14546705, 24331777,
+ 39490049, 62390545, 96220561, 145198913, 214828609, 312193553, 446304145,
+ 628496897, 872893441, 1196924561, 1621925137, 2173806145U,
+#if defined(CUSTOM_MODES)
+ /*...29:*/
+ 2883810113U,
+#endif
+ /*N=10, K=10...24:*/
+ 1462563, 3317445, 7059735, 14218905, 27298155, 50250765, 89129247, 152951073,
+ 254831667, 413442773, 654862247, 1014889769, 1541911931, 2300409629U,
+ 3375210671U,
+ /*N=11, K=11...19:*/
+ 8097453, 18474633, 39753273, 81270333, 158819253, 298199265, 540279585,
+ 948062325, 1616336765,
+#if defined(CUSTOM_MODES)
+ /*...20:*/
+ 2684641785U,
+#endif
+ /*N=12, K=12...18:*/
+ 45046719, 103274625, 224298231, 464387817, 921406335, 1759885185,
+ 3248227095U,
+ /*N=13, K=13...16:*/
+ 251595969, 579168825, 1267854873, 2653649025U,
+ /*N=14, K=14:*/
+ 1409933619
+};
+
+#if defined(CUSTOM_MODES)
+static const opus_uint32 *const CELT_PVQ_U_ROW[15]={
+ CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 208,CELT_PVQ_U_DATA+ 415,
+ CELT_PVQ_U_DATA+ 621,CELT_PVQ_U_DATA+ 826,CELT_PVQ_U_DATA+1030,
+ CELT_PVQ_U_DATA+1233,CELT_PVQ_U_DATA+1336,CELT_PVQ_U_DATA+1389,
+ CELT_PVQ_U_DATA+1421,CELT_PVQ_U_DATA+1441,CELT_PVQ_U_DATA+1455,
+ CELT_PVQ_U_DATA+1464,CELT_PVQ_U_DATA+1470,CELT_PVQ_U_DATA+1473
+};
+#else
+static const opus_uint32 *const CELT_PVQ_U_ROW[15]={
+ CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 176,CELT_PVQ_U_DATA+ 351,
+ CELT_PVQ_U_DATA+ 525,CELT_PVQ_U_DATA+ 698,CELT_PVQ_U_DATA+ 870,
+ CELT_PVQ_U_DATA+1041,CELT_PVQ_U_DATA+1131,CELT_PVQ_U_DATA+1178,
+ CELT_PVQ_U_DATA+1207,CELT_PVQ_U_DATA+1226,CELT_PVQ_U_DATA+1240,
+ CELT_PVQ_U_DATA+1248,CELT_PVQ_U_DATA+1254,CELT_PVQ_U_DATA+1257
+};
+#endif
+
+#if defined(CUSTOM_MODES)
+void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){
+ int k;
+ /*_maxk==0 => there's nothing to do.*/
+ celt_assert(_maxk>0);
+ _bits[0]=0;
+ for(k=1;k<=_maxk;k++)_bits[k]=log2_frac(CELT_PVQ_V(_n,k),_frac);
+}
+#endif
+
+static opus_uint32 icwrs(int _n,const int *_y){
+ opus_uint32 i;
+ int j;
+ int k;
+ celt_assert(_n>=2);
+ j=_n-1;
+ i=_y[j]<0;
+ k=abs(_y[j]);
+ do{
+ j--;
+ i+=CELT_PVQ_U(_n-j,k);
+ k+=abs(_y[j]);
+ if(_y[j]<0)i+=CELT_PVQ_U(_n-j,k+1);
+ }
+ while(j>0);
+ return i;
+}
+
+void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){
+ celt_assert(_k>0);
+ ec_enc_uint(_enc,icwrs(_n,_y),CELT_PVQ_V(_n,_k));
+}
+
+static opus_val32 cwrsi(int _n,int _k,opus_uint32 _i,int *_y){
+ opus_uint32 p;
+ int s;
+ int k0;
+ opus_int16 val;
+ opus_val32 yy=0;
+ celt_assert(_k>0);
+ celt_assert(_n>1);
+ while(_n>2){
+ opus_uint32 q;
+ /*Lots of pulses case:*/
+ if(_k>=_n){
+ const opus_uint32 *row;
+ row=CELT_PVQ_U_ROW[_n];
+ /*Are the pulses in this dimension negative?*/
+ p=row[_k+1];
+ s=-(_i>=p);
+ _i-=p&s;
+ /*Count how many pulses were placed in this dimension.*/
+ k0=_k;
+ q=row[_n];
+ if(q>_i){
+ celt_assert(p>q);
+ _k=_n;
+ do p=CELT_PVQ_U_ROW[--_k][_n];
+ while(p>_i);
+ }
+ else for(p=row[_k];p>_i;p=row[_k])_k--;
+ _i-=p;
+ val=(k0-_k+s)^s;
+ *_y++=val;
+ yy=MAC16_16(yy,val,val);
+ }
+ /*Lots of dimensions case:*/
+ else{
+ /*Are there any pulses in this dimension at all?*/
+ p=CELT_PVQ_U_ROW[_k][_n];
+ q=CELT_PVQ_U_ROW[_k+1][_n];
+ if(p<=_i&&_i<q){
+ _i-=p;
+ *_y++=0;
+ }
+ else{
+ /*Are the pulses in this dimension negative?*/
+ s=-(_i>=q);
+ _i-=q&s;
+ /*Count how many pulses were placed in this dimension.*/
+ k0=_k;
+ do p=CELT_PVQ_U_ROW[--_k][_n];
+ while(p>_i);
+ _i-=p;
+ val=(k0-_k+s)^s;
+ *_y++=val;
+ yy=MAC16_16(yy,val,val);
+ }
+ }
+ _n--;
+ }
+ /*_n==2*/
+ p=2*_k+1;
+ s=-(_i>=p);
+ _i-=p&s;
+ k0=_k;
+ _k=(_i+1)>>1;
+ if(_k)_i-=2*_k-1;
+ val=(k0-_k+s)^s;
+ *_y++=val;
+ yy=MAC16_16(yy,val,val);
+ /*_n==1*/
+ s=-(int)_i;
+ val=(_k+s)^s;
+ *_y=val;
+ yy=MAC16_16(yy,val,val);
+ return yy;
+}
+
+opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){
+ return cwrsi(_n,_k,ec_dec_uint(_dec,CELT_PVQ_V(_n,_k)),_y);
+}
+
+#else /* SMALL_FOOTPRINT */
+
+/*Computes the next row/column of any recurrence that obeys the relation
+ u[i][j]=u[i-1][j]+u[i][j-1]+u[i-1][j-1].
+ _ui0 is the base case for the new row/column.*/
+static OPUS_INLINE void unext(opus_uint32 *_ui,unsigned _len,opus_uint32 _ui0){
+ opus_uint32 ui1;
+ unsigned j;
+ /*This do-while will overrun the array if we don't have storage for at least
+ 2 values.*/
+ j=1; do {
+ ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0);
+ _ui[j-1]=_ui0;
+ _ui0=ui1;
+ } while (++j<_len);
+ _ui[j-1]=_ui0;
+}
+
+/*Computes the previous row/column of any recurrence that obeys the relation
+ u[i-1][j]=u[i][j]-u[i][j-1]-u[i-1][j-1].
+ _ui0 is the base case for the new row/column.*/
+static OPUS_INLINE void uprev(opus_uint32 *_ui,unsigned _n,opus_uint32 _ui0){
+ opus_uint32 ui1;
+ unsigned j;
+ /*This do-while will overrun the array if we don't have storage for at least
+ 2 values.*/
+ j=1; do {
+ ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0);
+ _ui[j-1]=_ui0;
+ _ui0=ui1;
+ } while (++j<_n);
+ _ui[j-1]=_ui0;
+}
+
+/*Compute V(_n,_k), as well as U(_n,0..._k+1).
+ _u: On exit, _u[i] contains U(_n,i) for i in [0..._k+1].*/
+static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){
+ opus_uint32 um2;
+ unsigned len;
+ unsigned k;
+ len=_k+2;
+ /*We require storage at least 3 values (e.g., _k>0).*/
+ celt_assert(len>=3);
+ _u[0]=0;
+ _u[1]=um2=1;
+ /*If _n==0, _u[0] should be 1 and the rest should be 0.*/
+ /*If _n==1, _u[i] should be 1 for i>1.*/
+ celt_assert(_n>=2);
+ /*If _k==0, the following do-while loop will overflow the buffer.*/
+ celt_assert(_k>0);
+ k=2;
+ do _u[k]=(k<<1)-1;
+ while(++k<len);
+ for(k=2;k<_n;k++)unext(_u+1,_k+1,1);
+ return _u[_k]+_u[_k+1];
+}
+
+/*Returns the _i'th combination of _k elements chosen from a set of size _n
+ with associated sign bits.
+ _y: Returns the vector of pulses.
+ _u: Must contain entries [0..._k+1] of row _n of U() on input.
+ Its contents will be destructively modified.*/
+static opus_val32 cwrsi(int _n,int _k,opus_uint32 _i,int *_y,opus_uint32 *_u){
+ int j;
+ opus_int16 val;
+ opus_val32 yy=0;
+ celt_assert(_n>0);
+ j=0;
+ do{
+ opus_uint32 p;
+ int s;
+ int yj;
+ p=_u[_k+1];
+ s=-(_i>=p);
+ _i-=p&s;
+ yj=_k;
+ p=_u[_k];
+ while(p>_i)p=_u[--_k];
+ _i-=p;
+ yj-=_k;
+ val=(yj+s)^s;
+ _y[j]=val;
+ yy=MAC16_16(yy,val,val);
+ uprev(_u,_k+2,0);
+ }
+ while(++j<_n);
+ return yy;
+}
+
+/*Returns the index of the given combination of K elements chosen from a set
+ of size 1 with associated sign bits.
+ _y: The vector of pulses, whose sum of absolute values is K.
+ _k: Returns K.*/
+static OPUS_INLINE opus_uint32 icwrs1(const int *_y,int *_k){
+ *_k=abs(_y[0]);
+ return _y[0]<0;
+}
+
+/*Returns the index of the given combination of K elements chosen from a set
+ of size _n with associated sign bits.
+ _y: The vector of pulses, whose sum of absolute values must be _k.
+ _nc: Returns V(_n,_k).*/
+static OPUS_INLINE opus_uint32 icwrs(int _n,int _k,opus_uint32 *_nc,const int *_y,
+ opus_uint32 *_u){
+ opus_uint32 i;
+ int j;
+ int k;
+ /*We can't unroll the first two iterations of the loop unless _n>=2.*/
+ celt_assert(_n>=2);
+ _u[0]=0;
+ for(k=1;k<=_k+1;k++)_u[k]=(k<<1)-1;
+ i=icwrs1(_y+_n-1,&k);
+ j=_n-2;
+ i+=_u[k];
+ k+=abs(_y[j]);
+ if(_y[j]<0)i+=_u[k+1];
+ while(j-->0){
+ unext(_u,_k+2,0);
+ i+=_u[k];
+ k+=abs(_y[j]);
+ if(_y[j]<0)i+=_u[k+1];
+ }
+ *_nc=_u[k]+_u[k+1];
+ return i;
+}
+
+#ifdef CUSTOM_MODES
+void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){
+ int k;
+ /*_maxk==0 => there's nothing to do.*/
+ celt_assert(_maxk>0);
+ _bits[0]=0;
+ if (_n==1)
+ {
+ for (k=1;k<=_maxk;k++)
+ _bits[k] = 1<<_frac;
+ }
+ else {
+ VARDECL(opus_uint32,u);
+ SAVE_STACK;
+ ALLOC(u,_maxk+2U,opus_uint32);
+ ncwrs_urow(_n,_maxk,u);
+ for(k=1;k<=_maxk;k++)
+ _bits[k]=log2_frac(u[k]+u[k+1],_frac);
+ RESTORE_STACK;
+ }
+}
+#endif /* CUSTOM_MODES */
+
+void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){
+ opus_uint32 i;
+ VARDECL(opus_uint32,u);
+ opus_uint32 nc;
+ SAVE_STACK;
+ celt_assert(_k>0);
+ ALLOC(u,_k+2U,opus_uint32);
+ i=icwrs(_n,_k,&nc,_y,u);
+ ec_enc_uint(_enc,i,nc);
+ RESTORE_STACK;
+}
+
+opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){
+ VARDECL(opus_uint32,u);
+ int ret;
+ SAVE_STACK;
+ celt_assert(_k>0);
+ ALLOC(u,_k+2U,opus_uint32);
+ ret = cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u);
+ RESTORE_STACK;
+ return ret;
+}
+
+#endif /* SMALL_FOOTPRINT */
diff --git a/external/opus-1.1.4/celt/cwrs.h b/external/opus-1.1.4/celt/cwrs.h
new file mode 100644
index 0000000..7cd4717
--- /dev/null
+++ b/external/opus-1.1.4/celt/cwrs.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2007-2009 Timothy B. Terriberry
+ Written by Timothy B. Terriberry and Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef CWRS_H
+#define CWRS_H
+
+#include "arch.h"
+#include "stack_alloc.h"
+#include "entenc.h"
+#include "entdec.h"
+
+#ifdef CUSTOM_MODES
+int log2_frac(opus_uint32 val, int frac);
+#endif
+
+void get_required_bits(opus_int16 *bits, int N, int K, int frac);
+
+void encode_pulses(const int *_y, int N, int K, ec_enc *enc);
+
+opus_val32 decode_pulses(int *_y, int N, int K, ec_dec *dec);
+
+#endif /* CWRS_H */
diff --git a/external/opus-1.1.4/celt/ecintrin.h b/external/opus-1.1.4/celt/ecintrin.h
new file mode 100644
index 0000000..2263cff
--- /dev/null
+++ b/external/opus-1.1.4/celt/ecintrin.h
@@ -0,0 +1,87 @@
+/* Copyright (c) 2003-2008 Timothy B. Terriberry
+ Copyright (c) 2008 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+/*Some common macros for potential platform-specific optimization.*/
+#include "opus_types.h"
+#include <math.h>
+#include <limits.h>
+#include "arch.h"
+#if !defined(_ecintrin_H)
+# define _ecintrin_H (1)
+
+/*Some specific platforms may have optimized intrinsic or OPUS_INLINE assembly
+ versions of these functions which can substantially improve performance.
+ We define macros for them to allow easy incorporation of these non-ANSI
+ features.*/
+
+/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if
+ given an appropriate architecture, but the branchless bit-twiddling versions
+ are just as fast, and do not require any special target architecture.
+ Earlier gcc versions (3.x) compiled both code to the same assembly
+ instructions, because of the way they represented ((_b)>(_a)) internally.*/
+# define EC_MINI(_a,_b) ((_a)+(((_b)-(_a))&-((_b)<(_a))))
+
+/*Count leading zeros.
+ This macro should only be used for implementing ec_ilog(), if it is defined.
+ All other code should use EC_ILOG() instead.*/
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+# include <intrin.h>
+/*In _DEBUG mode this is not an intrinsic by default.*/
+# pragma intrinsic(_BitScanReverse)
+
+static __inline int ec_bsr(unsigned long _x){
+ unsigned long ret;
+ _BitScanReverse(&ret,_x);
+ return (int)ret;
+}
+# define EC_CLZ0 (1)
+# define EC_CLZ(_x) (-ec_bsr(_x))
+#elif defined(ENABLE_TI_DSPLIB)
+# include "dsplib.h"
+# define EC_CLZ0 (31)
+# define EC_CLZ(_x) (_lnorm(_x))
+#elif __GNUC_PREREQ(3,4)
+# if INT_MAX>=2147483647
+# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT)
+# define EC_CLZ(_x) (__builtin_clz(_x))
+# elif LONG_MAX>=2147483647L
+# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT)
+# define EC_CLZ(_x) (__builtin_clzl(_x))
+# endif
+#endif
+
+#if defined(EC_CLZ)
+/*Note that __builtin_clz is not defined when _x==0, according to the gcc
+ documentation (and that of the BSR instruction that implements it on x86).
+ The majority of the time we can never pass it zero.
+ When we need to, it can be special cased.*/
+# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x))
+#else
+int ec_ilog(opus_uint32 _v);
+# define EC_ILOG(_x) (ec_ilog(_x))
+#endif
+#endif
diff --git a/external/opus-1.1.4/celt/entcode.c b/external/opus-1.1.4/celt/entcode.c
new file mode 100644
index 0000000..70f3201
--- /dev/null
+++ b/external/opus-1.1.4/celt/entcode.c
@@ -0,0 +1,153 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "entcode.h"
+#include "arch.h"
+
+#if !defined(EC_CLZ)
+/*This is a fallback for systems where we don't know how to access
+ a BSR or CLZ instruction (see ecintrin.h).
+ If you are optimizing Opus on a new platform and it has a native CLZ or
+ BZR (e.g. cell, MIPS, x86, etc) then making it available to Opus will be
+ an easy performance win.*/
+int ec_ilog(opus_uint32 _v){
+ /*On a Pentium M, this branchless version tested as the fastest on
+ 1,000,000,000 random 32-bit integers, edging out a similar version with
+ branches, and a 256-entry LUT version.*/
+ int ret;
+ int m;
+ ret=!!_v;
+ m=!!(_v&0xFFFF0000)<<4;
+ _v>>=m;
+ ret|=m;
+ m=!!(_v&0xFF00)<<3;
+ _v>>=m;
+ ret|=m;
+ m=!!(_v&0xF0)<<2;
+ _v>>=m;
+ ret|=m;
+ m=!!(_v&0xC)<<1;
+ _v>>=m;
+ ret|=m;
+ ret+=!!(_v&0x2);
+ return ret;
+}
+#endif
+
+#if 1
+/* This is a faster version of ec_tell_frac() that takes advantage
+ of the low (1/8 bit) resolution to use just a linear function
+ followed by a lookup to determine the exact transition thresholds. */
+opus_uint32 ec_tell_frac(ec_ctx *_this){
+ static const unsigned correction[8] =
+ {35733, 38967, 42495, 46340,
+ 50535, 55109, 60097, 65535};
+ opus_uint32 nbits;
+ opus_uint32 r;
+ int l;
+ unsigned b;
+ nbits=_this->nbits_total<<BITRES;
+ l=EC_ILOG(_this->rng);
+ r=_this->rng>>(l-16);
+ b = (r>>12)-8;
+ b += r>correction[b];
+ l = (l<<3)+b;
+ return nbits-l;
+}
+#else
+opus_uint32 ec_tell_frac(ec_ctx *_this){
+ opus_uint32 nbits;
+ opus_uint32 r;
+ int l;
+ int i;
+ /*To handle the non-integral number of bits still left in the encoder/decoder
+ state, we compute the worst-case number of bits of val that must be
+ encoded to ensure that the value is inside the range for any possible
+ subsequent bits.
+ The computation here is independent of val itself (the decoder does not
+ even track that value), even though the real number of bits used after
+ ec_enc_done() may be 1 smaller if rng is a power of two and the
+ corresponding trailing bits of val are all zeros.
+ If we did try to track that special case, then coding a value with a
+ probability of 1/(1<<n) might sometimes appear to use more than n bits.
+ This may help explain the surprising result that a newly initialized
+ encoder or decoder claims to have used 1 bit.*/
+ nbits=_this->nbits_total<<BITRES;
+ l=EC_ILOG(_this->rng);
+ r=_this->rng>>(l-16);
+ for(i=BITRES;i-->0;){
+ int b;
+ r=r*r>>15;
+ b=(int)(r>>16);
+ l=l<<1|b;
+ r>>=b;
+ }
+ return nbits-l;
+}
+#endif
+
+#ifdef USE_SMALL_DIV_TABLE
+/* Result of 2^32/(2*i+1), except for i=0. */
+const opus_uint32 SMALL_DIV_TABLE[129] = {
+ 0xFFFFFFFF, 0x55555555, 0x33333333, 0x24924924,
+ 0x1C71C71C, 0x1745D174, 0x13B13B13, 0x11111111,
+ 0x0F0F0F0F, 0x0D79435E, 0x0C30C30C, 0x0B21642C,
+ 0x0A3D70A3, 0x097B425E, 0x08D3DCB0, 0x08421084,
+ 0x07C1F07C, 0x07507507, 0x06EB3E45, 0x06906906,
+ 0x063E7063, 0x05F417D0, 0x05B05B05, 0x0572620A,
+ 0x05397829, 0x05050505, 0x04D4873E, 0x04A7904A,
+ 0x047DC11F, 0x0456C797, 0x04325C53, 0x04104104,
+ 0x03F03F03, 0x03D22635, 0x03B5CC0E, 0x039B0AD1,
+ 0x0381C0E0, 0x0369D036, 0x03531DEC, 0x033D91D2,
+ 0x0329161F, 0x03159721, 0x03030303, 0x02F14990,
+ 0x02E05C0B, 0x02D02D02, 0x02C0B02C, 0x02B1DA46,
+ 0x02A3A0FD, 0x0295FAD4, 0x0288DF0C, 0x027C4597,
+ 0x02702702, 0x02647C69, 0x02593F69, 0x024E6A17,
+ 0x0243F6F0, 0x0239E0D5, 0x02302302, 0x0226B902,
+ 0x021D9EAD, 0x0214D021, 0x020C49BA, 0x02040810,
+ 0x01FC07F0, 0x01F44659, 0x01ECC07B, 0x01E573AC,
+ 0x01DE5D6E, 0x01D77B65, 0x01D0CB58, 0x01CA4B30,
+ 0x01C3F8F0, 0x01BDD2B8, 0x01B7D6C3, 0x01B20364,
+ 0x01AC5701, 0x01A6D01A, 0x01A16D3F, 0x019C2D14,
+ 0x01970E4F, 0x01920FB4, 0x018D3018, 0x01886E5F,
+ 0x0183C977, 0x017F405F, 0x017AD220, 0x01767DCE,
+ 0x01724287, 0x016E1F76, 0x016A13CD, 0x01661EC6,
+ 0x01623FA7, 0x015E75BB, 0x015AC056, 0x01571ED3,
+ 0x01539094, 0x01501501, 0x014CAB88, 0x0149539E,
+ 0x01460CBC, 0x0142D662, 0x013FB013, 0x013C995A,
+ 0x013991C2, 0x013698DF, 0x0133AE45, 0x0130D190,
+ 0x012E025C, 0x012B404A, 0x01288B01, 0x0125E227,
+ 0x01234567, 0x0120B470, 0x011E2EF3, 0x011BB4A4,
+ 0x01194538, 0x0116E068, 0x011485F0, 0x0112358E,
+ 0x010FEF01, 0x010DB20A, 0x010B7E6E, 0x010953F3,
+ 0x01073260, 0x0105197F, 0x0103091B, 0x01010101
+};
+#endif
diff --git a/external/opus-1.1.4/celt/entcode.h b/external/opus-1.1.4/celt/entcode.h
new file mode 100644
index 0000000..13d6c84
--- /dev/null
+++ b/external/opus-1.1.4/celt/entcode.h
@@ -0,0 +1,152 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#if !defined(_entcode_H)
+# define _entcode_H (1)
+# include <limits.h>
+# include <stddef.h>
+# include "ecintrin.h"
+
+extern const opus_uint32 SMALL_DIV_TABLE[129];
+
+#ifdef OPUS_ARM_ASM
+#define USE_SMALL_DIV_TABLE
+#endif
+
+/*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a
+ larger type, you can speed up the decoder by using it here.*/
+typedef opus_uint32 ec_window;
+typedef struct ec_ctx ec_ctx;
+typedef struct ec_ctx ec_enc;
+typedef struct ec_ctx ec_dec;
+
+# define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT)
+
+/*The number of bits to use for the range-coded part of unsigned integers.*/
+# define EC_UINT_BITS (8)
+
+/*The resolution of fractional-precision bit usage measurements, i.e.,
+ 3 => 1/8th bits.*/
+# define BITRES 3
+
+/*The entropy encoder/decoder context.
+ We use the same structure for both, so that common functions like ec_tell()
+ can be used on either one.*/
+struct ec_ctx{
+ /*Buffered input/output.*/
+ unsigned char *buf;
+ /*The size of the buffer.*/
+ opus_uint32 storage;
+ /*The offset at which the last byte containing raw bits was read/written.*/
+ opus_uint32 end_offs;
+ /*Bits that will be read from/written at the end.*/
+ ec_window end_window;
+ /*Number of valid bits in end_window.*/
+ int nend_bits;
+ /*The total number of whole bits read/written.
+ This does not include partial bits currently in the range coder.*/
+ int nbits_total;
+ /*The offset at which the next range coder byte will be read/written.*/
+ opus_uint32 offs;
+ /*The number of values in the current range.*/
+ opus_uint32 rng;
+ /*In the decoder: the difference between the top of the current range and
+ the input value, minus one.
+ In the encoder: the low end of the current range.*/
+ opus_uint32 val;
+ /*In the decoder: the saved normalization factor from ec_decode().
+ In the encoder: the number of oustanding carry propagating symbols.*/
+ opus_uint32 ext;
+ /*A buffered input/output symbol, awaiting carry propagation.*/
+ int rem;
+ /*Nonzero if an error occurred.*/
+ int error;
+};
+
+static OPUS_INLINE opus_uint32 ec_range_bytes(ec_ctx *_this){
+ return _this->offs;
+}
+
+static OPUS_INLINE unsigned char *ec_get_buffer(ec_ctx *_this){
+ return _this->buf;
+}
+
+static OPUS_INLINE int ec_get_error(ec_ctx *_this){
+ return _this->error;
+}
+
+/*Returns the number of bits "used" by the encoded or decoded symbols so far.
+ This same number can be computed in either the encoder or the decoder, and is
+ suitable for making coding decisions.
+ Return: The number of bits.
+ This will always be slightly larger than the exact value (e.g., all
+ rounding error is in the positive direction).*/
+static OPUS_INLINE int ec_tell(ec_ctx *_this){
+ return _this->nbits_total-EC_ILOG(_this->rng);
+}
+
+/*Returns the number of bits "used" by the encoded or decoded symbols so far.
+ This same number can be computed in either the encoder or the decoder, and is
+ suitable for making coding decisions.
+ Return: The number of bits scaled by 2**BITRES.
+ This will always be slightly larger than the exact value (e.g., all
+ rounding error is in the positive direction).*/
+opus_uint32 ec_tell_frac(ec_ctx *_this);
+
+/* Tested exhaustively for all n and for 1<=d<=256 */
+static OPUS_INLINE opus_uint32 celt_udiv(opus_uint32 n, opus_uint32 d) {
+ celt_assert(d>0);
+#ifdef USE_SMALL_DIV_TABLE
+ if (d>256)
+ return n/d;
+ else {
+ opus_uint32 t, q;
+ t = EC_ILOG(d&-d);
+ q = (opus_uint64)SMALL_DIV_TABLE[d>>t]*(n>>(t-1))>>32;
+ return q+(n-q*d >= d);
+ }
+#else
+ return n/d;
+#endif
+}
+
+static OPUS_INLINE opus_int32 celt_sudiv(opus_int32 n, opus_int32 d) {
+ celt_assert(d>0);
+#ifdef USE_SMALL_DIV_TABLE
+ if (n<0)
+ return -(opus_int32)celt_udiv(-n, d);
+ else
+ return celt_udiv(n, d);
+#else
+ return n/d;
+#endif
+}
+
+#endif
diff --git a/external/opus-1.1.4/celt/entdec.c b/external/opus-1.1.4/celt/entdec.c
new file mode 100644
index 0000000..0b3433e
--- /dev/null
+++ b/external/opus-1.1.4/celt/entdec.c
@@ -0,0 +1,245 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stddef.h>
+#include "os_support.h"
+#include "arch.h"
+#include "entdec.h"
+#include "mfrngcod.h"
+
+/*A range decoder.
+ This is an entropy decoder based upon \cite{Mar79}, which is itself a
+ rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}.
+ It is very similar to arithmetic encoding, except that encoding is done with
+ digits in any base, instead of with bits, and so it is faster when using
+ larger bases (i.e.: a byte).
+ The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$
+ is the base, longer than the theoretical optimum, but to my knowledge there
+ is no published justification for this claim.
+ This only seems true when using near-infinite precision arithmetic so that
+ the process is carried out with no rounding errors.
+
+ An excellent description of implementation details is available at
+ http://www.arturocampos.com/ac_range.html
+ A recent work \cite{MNW98} which proposes several changes to arithmetic
+ encoding for efficiency actually re-discovers many of the principles
+ behind range encoding, and presents a good theoretical analysis of them.
+
+ End of stream is handled by writing out the smallest number of bits that
+ ensures that the stream will be correctly decoded regardless of the value of
+ any subsequent bits.
+ ec_tell() can be used to determine how many bits were needed to decode
+ all the symbols thus far; other data can be packed in the remaining bits of
+ the input buffer.
+ @PHDTHESIS{Pas76,
+ author="Richard Clark Pasco",
+ title="Source coding algorithms for fast data compression",
+ school="Dept. of Electrical Engineering, Stanford University",
+ address="Stanford, CA",
+ month=May,
+ year=1976
+ }
+ @INPROCEEDINGS{Mar79,
+ author="Martin, G.N.N.",
+ title="Range encoding: an algorithm for removing redundancy from a digitised
+ message",
+ booktitle="Video & Data Recording Conference",
+ year=1979,
+ address="Southampton",
+ month=Jul
+ }
+ @ARTICLE{MNW98,
+ author="Alistair Moffat and Radford Neal and Ian H. Witten",
+ title="Arithmetic Coding Revisited",
+ journal="{ACM} Transactions on Information Systems",
+ year=1998,
+ volume=16,
+ number=3,
+ pages="256--294",
+ month=Jul,
+ URL="http://www.stanford.edu/class/ee398a/handouts/papers/Moffat98ArithmCoding.pdf"
+ }*/
+
+static int ec_read_byte(ec_dec *_this){
+ return _this->offs<_this->storage?_this->buf[_this->offs++]:0;
+}
+
+static int ec_read_byte_from_end(ec_dec *_this){
+ return _this->end_offs<_this->storage?
+ _this->buf[_this->storage-++(_this->end_offs)]:0;
+}
+
+/*Normalizes the contents of val and rng so that rng lies entirely in the
+ high-order symbol.*/
+static void ec_dec_normalize(ec_dec *_this){
+ /*If the range is too small, rescale it and input some bits.*/
+ while(_this->rng<=EC_CODE_BOT){
+ int sym;
+ _this->nbits_total+=EC_SYM_BITS;
+ _this->rng<<=EC_SYM_BITS;
+ /*Use up the remaining bits from our last symbol.*/
+ sym=_this->rem;
+ /*Read the next value from the input.*/
+ _this->rem=ec_read_byte(_this);
+ /*Take the rest of the bits we need from this new symbol.*/
+ sym=(sym<<EC_SYM_BITS|_this->rem)>>(EC_SYM_BITS-EC_CODE_EXTRA);
+ /*And subtract them from val, capped to be less than EC_CODE_TOP.*/
+ _this->val=((_this->val<<EC_SYM_BITS)+(EC_SYM_MAX&~sym))&(EC_CODE_TOP-1);
+ }
+}
+
+void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage){
+ _this->buf=_buf;
+ _this->storage=_storage;
+ _this->end_offs=0;
+ _this->end_window=0;
+ _this->nend_bits=0;
+ /*This is the offset from which ec_tell() will subtract partial bits.
+ The final value after the ec_dec_normalize() call will be the same as in
+ the encoder, but we have to compensate for the bits that are added there.*/
+ _this->nbits_total=EC_CODE_BITS+1
+ -((EC_CODE_BITS-EC_CODE_EXTRA)/EC_SYM_BITS)*EC_SYM_BITS;
+ _this->offs=0;
+ _this->rng=1U<<EC_CODE_EXTRA;
+ _this->rem=ec_read_byte(_this);
+ _this->val=_this->rng-1-(_this->rem>>(EC_SYM_BITS-EC_CODE_EXTRA));
+ _this->error=0;
+ /*Normalize the interval.*/
+ ec_dec_normalize(_this);
+}
+
+unsigned ec_decode(ec_dec *_this,unsigned _ft){
+ unsigned s;
+ _this->ext=celt_udiv(_this->rng,_ft);
+ s=(unsigned)(_this->val/_this->ext);
+ return _ft-EC_MINI(s+1,_ft);
+}
+
+unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){
+ unsigned s;
+ _this->ext=_this->rng>>_bits;
+ s=(unsigned)(_this->val/_this->ext);
+ return (1U<<_bits)-EC_MINI(s+1U,1U<<_bits);
+}
+
+void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){
+ opus_uint32 s;
+ s=IMUL32(_this->ext,_ft-_fh);
+ _this->val-=s;
+ _this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s;
+ ec_dec_normalize(_this);
+}
+
+/*The probability of having a "one" is 1/(1<<_logp).*/
+int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){
+ opus_uint32 r;
+ opus_uint32 d;
+ opus_uint32 s;
+ int ret;
+ r=_this->rng;
+ d=_this->val;
+ s=r>>_logp;
+ ret=d<s;
+ if(!ret)_this->val=d-s;
+ _this->rng=ret?s:r-s;
+ ec_dec_normalize(_this);
+ return ret;
+}
+
+int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){
+ opus_uint32 r;
+ opus_uint32 d;
+ opus_uint32 s;
+ opus_uint32 t;
+ int ret;
+ s=_this->rng;
+ d=_this->val;
+ r=s>>_ftb;
+ ret=-1;
+ do{
+ t=s;
+ s=IMUL32(r,_icdf[++ret]);
+ }
+ while(d<s);
+ _this->val=d-s;
+ _this->rng=t-s;
+ ec_dec_normalize(_this);
+ return ret;
+}
+
+opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft){
+ unsigned ft;
+ unsigned s;
+ int ftb;
+ /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
+ celt_assert(_ft>1);
+ _ft--;
+ ftb=EC_ILOG(_ft);
+ if(ftb>EC_UINT_BITS){
+ opus_uint32 t;
+ ftb-=EC_UINT_BITS;
+ ft=(unsigned)(_ft>>ftb)+1;
+ s=ec_decode(_this,ft);
+ ec_dec_update(_this,s,s+1,ft);
+ t=(opus_uint32)s<<ftb|ec_dec_bits(_this,ftb);
+ if(t<=_ft)return t;
+ _this->error=1;
+ return _ft;
+ }
+ else{
+ _ft++;
+ s=ec_decode(_this,(unsigned)_ft);
+ ec_dec_update(_this,s,s+1,(unsigned)_ft);
+ return s;
+ }
+}
+
+opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){
+ ec_window window;
+ int available;
+ opus_uint32 ret;
+ window=_this->end_window;
+ available=_this->nend_bits;
+ if((unsigned)available<_bits){
+ do{
+ window|=(ec_window)ec_read_byte_from_end(_this)<<available;
+ available+=EC_SYM_BITS;
+ }
+ while(available<=EC_WINDOW_SIZE-EC_SYM_BITS);
+ }
+ ret=(opus_uint32)window&(((opus_uint32)1<<_bits)-1U);
+ window>>=_bits;
+ available-=_bits;
+ _this->end_window=window;
+ _this->nend_bits=available;
+ _this->nbits_total+=_bits;
+ return ret;
+}
diff --git a/external/opus-1.1.4/celt/entdec.h b/external/opus-1.1.4/celt/entdec.h
new file mode 100644
index 0000000..d8ab318
--- /dev/null
+++ b/external/opus-1.1.4/celt/entdec.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#if !defined(_entdec_H)
+# define _entdec_H (1)
+# include <limits.h>
+# include "entcode.h"
+
+/*Initializes the decoder.
+ _buf: The input buffer to use.
+ Return: 0 on success, or a negative value on error.*/
+void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage);
+
+/*Calculates the cumulative frequency for the next symbol.
+ This can then be fed into the probability model to determine what that
+ symbol is, and the additional frequency information required to advance to
+ the next symbol.
+ This function cannot be called more than once without a corresponding call to
+ ec_dec_update(), or decoding will not proceed correctly.
+ _ft: The total frequency of the symbols in the alphabet the next symbol was
+ encoded with.
+ Return: A cumulative frequency representing the encoded symbol.
+ If the cumulative frequency of all the symbols before the one that
+ was encoded was fl, and the cumulative frequency of all the symbols
+ up to and including the one encoded is fh, then the returned value
+ will fall in the range [fl,fh).*/
+unsigned ec_decode(ec_dec *_this,unsigned _ft);
+
+/*Equivalent to ec_decode() with _ft==1<<_bits.*/
+unsigned ec_decode_bin(ec_dec *_this,unsigned _bits);
+
+/*Advance the decoder past the next symbol using the frequency information the
+ symbol was encoded with.
+ Exactly one call to ec_decode() must have been made so that all necessary
+ intermediate calculations are performed.
+ _fl: The cumulative frequency of all symbols that come before the symbol
+ decoded.
+ _fh: The cumulative frequency of all symbols up to and including the symbol
+ decoded.
+ Together with _fl, this defines the range [_fl,_fh) in which the value
+ returned above must fall.
+ _ft: The total frequency of the symbols in the alphabet the symbol decoded
+ was encoded in.
+ This must be the same as passed to the preceding call to ec_decode().*/
+void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft);
+
+/* Decode a bit that has a 1/(1<<_logp) probability of being a one */
+int ec_dec_bit_logp(ec_dec *_this,unsigned _logp);
+
+/*Decodes a symbol given an "inverse" CDF table.
+ No call to ec_dec_update() is necessary after this call.
+ _icdf: The "inverse" CDF, such that symbol s falls in the range
+ [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb.
+ The values must be monotonically non-increasing, and the last value
+ must be 0.
+ _ftb: The number of bits of precision in the cumulative distribution.
+ Return: The decoded symbol s.*/
+int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb);
+
+/*Extracts a raw unsigned integer with a non-power-of-2 range from the stream.
+ The bits must have been encoded with ec_enc_uint().
+ No call to ec_dec_update() is necessary after this call.
+ _ft: The number of integers that can be decoded (one more than the max).
+ This must be at least one, and no more than 2**32-1.
+ Return: The decoded bits.*/
+opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft);
+
+/*Extracts a sequence of raw bits from the stream.
+ The bits must have been encoded with ec_enc_bits().
+ No call to ec_dec_update() is necessary after this call.
+ _ftb: The number of bits to extract.
+ This must be between 0 and 25, inclusive.
+ Return: The decoded bits.*/
+opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb);
+
+#endif
diff --git a/external/opus-1.1.4/celt/entenc.c b/external/opus-1.1.4/celt/entenc.c
new file mode 100644
index 0000000..f1750d2
--- /dev/null
+++ b/external/opus-1.1.4/celt/entenc.c
@@ -0,0 +1,294 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#if defined(HAVE_CONFIG_H)
+# include "config.h"
+#endif
+#include "os_support.h"
+#include "arch.h"
+#include "entenc.h"
+#include "mfrngcod.h"
+
+/*A range encoder.
+ See entdec.c and the references for implementation details \cite{Mar79,MNW98}.
+
+ @INPROCEEDINGS{Mar79,
+ author="Martin, G.N.N.",
+ title="Range encoding: an algorithm for removing redundancy from a digitised
+ message",
+ booktitle="Video \& Data Recording Conference",
+ year=1979,
+ address="Southampton",
+ month=Jul
+ }
+ @ARTICLE{MNW98,
+ author="Alistair Moffat and Radford Neal and Ian H. Witten",
+ title="Arithmetic Coding Revisited",
+ journal="{ACM} Transactions on Information Systems",
+ year=1998,
+ volume=16,
+ number=3,
+ pages="256--294",
+ month=Jul,
+ URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf"
+ }*/
+
+static int ec_write_byte(ec_enc *_this,unsigned _value){
+ if(_this->offs+_this->end_offs>=_this->storage)return -1;
+ _this->buf[_this->offs++]=(unsigned char)_value;
+ return 0;
+}
+
+static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){
+ if(_this->offs+_this->end_offs>=_this->storage)return -1;
+ _this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value;
+ return 0;
+}
+
+/*Outputs a symbol, with a carry bit.
+ If there is a potential to propagate a carry over several symbols, they are
+ buffered until it can be determined whether or not an actual carry will
+ occur.
+ If the counter for the buffered symbols overflows, then the stream becomes
+ undecodable.
+ This gives a theoretical limit of a few billion symbols in a single packet on
+ 32-bit systems.
+ The alternative is to truncate the range in order to force a carry, but
+ requires similar carry tracking in the decoder, needlessly slowing it down.*/
+static void ec_enc_carry_out(ec_enc *_this,int _c){
+ if(_c!=EC_SYM_MAX){
+ /*No further carry propagation possible, flush buffer.*/
+ int carry;
+ carry=_c>>EC_SYM_BITS;
+ /*Don't output a byte on the first write.
+ This compare should be taken care of by branch-prediction thereafter.*/
+ if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry);
+ if(_this->ext>0){
+ unsigned sym;
+ sym=(EC_SYM_MAX+carry)&EC_SYM_MAX;
+ do _this->error|=ec_write_byte(_this,sym);
+ while(--(_this->ext)>0);
+ }
+ _this->rem=_c&EC_SYM_MAX;
+ }
+ else _this->ext++;
+}
+
+static OPUS_INLINE void ec_enc_normalize(ec_enc *_this){
+ /*If the range is too small, output some bits and rescale it.*/
+ while(_this->rng<=EC_CODE_BOT){
+ ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT));
+ /*Move the next-to-high-order symbol into the high-order position.*/
+ _this->val=(_this->val<<EC_SYM_BITS)&(EC_CODE_TOP-1);
+ _this->rng<<=EC_SYM_BITS;
+ _this->nbits_total+=EC_SYM_BITS;
+ }
+}
+
+void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size){
+ _this->buf=_buf;
+ _this->end_offs=0;
+ _this->end_window=0;
+ _this->nend_bits=0;
+ /*This is the offset from which ec_tell() will subtract partial bits.*/
+ _this->nbits_total=EC_CODE_BITS+1;
+ _this->offs=0;
+ _this->rng=EC_CODE_TOP;
+ _this->rem=-1;
+ _this->val=0;
+ _this->ext=0;
+ _this->storage=_size;
+ _this->error=0;
+}
+
+void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){
+ opus_uint32 r;
+ r=celt_udiv(_this->rng,_ft);
+ if(_fl>0){
+ _this->val+=_this->rng-IMUL32(r,(_ft-_fl));
+ _this->rng=IMUL32(r,(_fh-_fl));
+ }
+ else _this->rng-=IMUL32(r,(_ft-_fh));
+ ec_enc_normalize(_this);
+}
+
+void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){
+ opus_uint32 r;
+ r=_this->rng>>_bits;
+ if(_fl>0){
+ _this->val+=_this->rng-IMUL32(r,((1U<<_bits)-_fl));
+ _this->rng=IMUL32(r,(_fh-_fl));
+ }
+ else _this->rng-=IMUL32(r,((1U<<_bits)-_fh));
+ ec_enc_normalize(_this);
+}
+
+/*The probability of having a "one" is 1/(1<<_logp).*/
+void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){
+ opus_uint32 r;
+ opus_uint32 s;
+ opus_uint32 l;
+ r=_this->rng;
+ l=_this->val;
+ s=r>>_logp;
+ r-=s;
+ if(_val)_this->val=l+r;
+ _this->rng=_val?s:r;
+ ec_enc_normalize(_this);
+}
+
+void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){
+ opus_uint32 r;
+ r=_this->rng>>_ftb;
+ if(_s>0){
+ _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]);
+ _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]);
+ }
+ else _this->rng-=IMUL32(r,_icdf[_s]);
+ ec_enc_normalize(_this);
+}
+
+void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){
+ unsigned ft;
+ unsigned fl;
+ int ftb;
+ /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
+ celt_assert(_ft>1);
+ _ft--;
+ ftb=EC_ILOG(_ft);
+ if(ftb>EC_UINT_BITS){
+ ftb-=EC_UINT_BITS;
+ ft=(_ft>>ftb)+1;
+ fl=(unsigned)(_fl>>ftb);
+ ec_encode(_this,fl,fl+1,ft);
+ ec_enc_bits(_this,_fl&(((opus_uint32)1<<ftb)-1U),ftb);
+ }
+ else ec_encode(_this,_fl,_fl+1,_ft+1);
+}
+
+void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _bits){
+ ec_window window;
+ int used;
+ window=_this->end_window;
+ used=_this->nend_bits;
+ celt_assert(_bits>0);
+ if(used+_bits>EC_WINDOW_SIZE){
+ do{
+ _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX);
+ window>>=EC_SYM_BITS;
+ used-=EC_SYM_BITS;
+ }
+ while(used>=EC_SYM_BITS);
+ }
+ window|=(ec_window)_fl<<used;
+ used+=_bits;
+ _this->end_window=window;
+ _this->nend_bits=used;
+ _this->nbits_total+=_bits;
+}
+
+void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){
+ int shift;
+ unsigned mask;
+ celt_assert(_nbits<=EC_SYM_BITS);
+ shift=EC_SYM_BITS-_nbits;
+ mask=((1<<_nbits)-1)<<shift;
+ if(_this->offs>0){
+ /*The first byte has been finalized.*/
+ _this->buf[0]=(unsigned char)((_this->buf[0]&~mask)|_val<<shift);
+ }
+ else if(_this->rem>=0){
+ /*The first byte is still awaiting carry propagation.*/
+ _this->rem=(_this->rem&~mask)|_val<<shift;
+ }
+ else if(_this->rng<=(EC_CODE_TOP>>_nbits)){
+ /*The renormalization loop has never been run.*/
+ _this->val=(_this->val&~((opus_uint32)mask<<EC_CODE_SHIFT))|
+ (opus_uint32)_val<<(EC_CODE_SHIFT+shift);
+ }
+ /*The encoder hasn't even encoded _nbits of data yet.*/
+ else _this->error=-1;
+}
+
+void ec_enc_shrink(ec_enc *_this,opus_uint32 _size){
+ celt_assert(_this->offs+_this->end_offs<=_size);
+ OPUS_MOVE(_this->buf+_size-_this->end_offs,
+ _this->buf+_this->storage-_this->end_offs,_this->end_offs);
+ _this->storage=_size;
+}
+
+void ec_enc_done(ec_enc *_this){
+ ec_window window;
+ int used;
+ opus_uint32 msk;
+ opus_uint32 end;
+ int l;
+ /*We output the minimum number of bits that ensures that the symbols encoded
+ thus far will be decoded correctly regardless of the bits that follow.*/
+ l=EC_CODE_BITS-EC_ILOG(_this->rng);
+ msk=(EC_CODE_TOP-1)>>l;
+ end=(_this->val+msk)&~msk;
+ if((end|msk)>=_this->val+_this->rng){
+ l++;
+ msk>>=1;
+ end=(_this->val+msk)&~msk;
+ }
+ while(l>0){
+ ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT));
+ end=(end<<EC_SYM_BITS)&(EC_CODE_TOP-1);
+ l-=EC_SYM_BITS;
+ }
+ /*If we have a buffered byte flush it into the output buffer.*/
+ if(_this->rem>=0||_this->ext>0)ec_enc_carry_out(_this,0);
+ /*If we have buffered extra bits, flush them as well.*/
+ window=_this->end_window;
+ used=_this->nend_bits;
+ while(used>=EC_SYM_BITS){
+ _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX);
+ window>>=EC_SYM_BITS;
+ used-=EC_SYM_BITS;
+ }
+ /*Clear any excess space and add any remaining extra bits to the last byte.*/
+ if(!_this->error){
+ OPUS_CLEAR(_this->buf+_this->offs,
+ _this->storage-_this->offs-_this->end_offs);
+ if(used>0){
+ /*If there's no range coder data at all, give up.*/
+ if(_this->end_offs>=_this->storage)_this->error=-1;
+ else{
+ l=-l;
+ /*If we've busted, don't add too many extra bits to the last byte; it
+ would corrupt the range coder data, and that's more important.*/
+ if(_this->offs+_this->end_offs>=_this->storage&&l<used){
+ window&=(1<<l)-1;
+ _this->error=-1;
+ }
+ _this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window;
+ }
+ }
+ }
+}
diff --git a/external/opus-1.1.4/celt/entenc.h b/external/opus-1.1.4/celt/entenc.h
new file mode 100644
index 0000000..796bc4d
--- /dev/null
+++ b/external/opus-1.1.4/celt/entenc.h
@@ -0,0 +1,110 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#if !defined(_entenc_H)
+# define _entenc_H (1)
+# include <stddef.h>
+# include "entcode.h"
+
+/*Initializes the encoder.
+ _buf: The buffer to store output bytes in.
+ _size: The size of the buffer, in chars.*/
+void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size);
+/*Encodes a symbol given its frequency information.
+ The frequency information must be discernable by the decoder, assuming it
+ has read only the previous symbols from the stream.
+ It is allowable to change the frequency information, or even the entire
+ source alphabet, so long as the decoder can tell from the context of the
+ previously encoded information that it is supposed to do so as well.
+ _fl: The cumulative frequency of all symbols that come before the one to be
+ encoded.
+ _fh: The cumulative frequency of all symbols up to and including the one to
+ be encoded.
+ Together with _fl, this defines the range [_fl,_fh) in which the
+ decoded value will fall.
+ _ft: The sum of the frequencies of all the symbols*/
+void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft);
+
+/*Equivalent to ec_encode() with _ft==1<<_bits.*/
+void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits);
+
+/* Encode a bit that has a 1/(1<<_logp) probability of being a one */
+void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp);
+
+/*Encodes a symbol given an "inverse" CDF table.
+ _s: The index of the symbol to encode.
+ _icdf: The "inverse" CDF, such that symbol _s falls in the range
+ [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb.
+ The values must be monotonically non-increasing, and the last value
+ must be 0.
+ _ftb: The number of bits of precision in the cumulative distribution.*/
+void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb);
+
+/*Encodes a raw unsigned integer in the stream.
+ _fl: The integer to encode.
+ _ft: The number of integers that can be encoded (one more than the max).
+ This must be at least one, and no more than 2**32-1.*/
+void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft);
+
+/*Encodes a sequence of raw bits in the stream.
+ _fl: The bits to encode.
+ _ftb: The number of bits to encode.
+ This must be between 1 and 25, inclusive.*/
+void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _ftb);
+
+/*Overwrites a few bits at the very start of an existing stream, after they
+ have already been encoded.
+ This makes it possible to have a few flags up front, where it is easy for
+ decoders to access them without parsing the whole stream, even if their
+ values are not determined until late in the encoding process, without having
+ to buffer all the intermediate symbols in the encoder.
+ In order for this to work, at least _nbits bits must have already been
+ encoded using probabilities that are an exact power of two.
+ The encoder can verify the number of encoded bits is sufficient, but cannot
+ check this latter condition.
+ _val: The bits to encode (in the least _nbits significant bits).
+ They will be decoded in order from most-significant to least.
+ _nbits: The number of bits to overwrite.
+ This must be no more than 8.*/
+void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits);
+
+/*Compacts the data to fit in the target size.
+ This moves up the raw bits at the end of the current buffer so they are at
+ the end of the new buffer size.
+ The caller must ensure that the amount of data that's already been written
+ will fit in the new size.
+ _size: The number of bytes in the new buffer.
+ This must be large enough to contain the bits already written, and
+ must be no larger than the existing size.*/
+void ec_enc_shrink(ec_enc *_this,opus_uint32 _size);
+
+/*Indicates that there are no more symbols to encode.
+ All reamining output bytes are flushed to the output buffer.
+ ec_enc_init() must be called before the encoder can be used again.*/
+void ec_enc_done(ec_enc *_this);
+
+#endif
diff --git a/external/opus-1.1.4/celt/fixed_debug.h b/external/opus-1.1.4/celt/fixed_debug.h
new file mode 100644
index 0000000..d28227f
--- /dev/null
+++ b/external/opus-1.1.4/celt/fixed_debug.h
@@ -0,0 +1,784 @@
+/* Copyright (C) 2003-2008 Jean-Marc Valin
+ Copyright (C) 2007-2012 Xiph.Org Foundation */
+/**
+ @file fixed_debug.h
+ @brief Fixed-point operations with debugging
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef FIXED_DEBUG_H
+#define FIXED_DEBUG_H
+
+#include <stdio.h>
+#include "opus_defines.h"
+
+#ifdef CELT_C
+OPUS_EXPORT opus_int64 celt_mips=0;
+#else
+extern opus_int64 celt_mips;
+#endif
+
+#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b))
+#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15))
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16))
+
+#define MULT16_32_P16(a,b) MULT16_32_PX(a,b,16)
+
+#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits))))
+#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits))))
+
+#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768)
+#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL)
+#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1))
+
+#define SHR(a,b) SHR32(a,b)
+#define PSHR(a,b) PSHR32(a,b)
+
+static OPUS_INLINE short NEG16(int x)
+{
+ int res;
+ if (!VERIFY_SHORT(x))
+ {
+ fprintf (stderr, "NEG16: input is not short: %d\n", (int)x);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = -x;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "NEG16: output is not short: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+static OPUS_INLINE int NEG32(opus_int64 x)
+{
+ opus_int64 res;
+ if (!VERIFY_INT(x))
+ {
+ fprintf (stderr, "NEG16: input is not int: %d\n", (int)x);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = -x;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "NEG16: output is not int: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#define EXTRACT16(x) EXTRACT16_(x, __FILE__, __LINE__)
+static OPUS_INLINE short EXTRACT16_(int x, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(x))
+ {
+ fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = x;
+ celt_mips++;
+ return res;
+}
+
+#define EXTEND32(x) EXTEND32_(x, __FILE__, __LINE__)
+static OPUS_INLINE int EXTEND32_(int x, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(x))
+ {
+ fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = x;
+ celt_mips++;
+ return res;
+}
+
+#define SHR16(a, shift) SHR16_(a, shift, __FILE__, __LINE__)
+static OPUS_INLINE short SHR16_(int a, int shift, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
+ {
+ fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a>>shift;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+#define SHL16(a, shift) SHL16_(a, shift, __FILE__, __LINE__)
+static OPUS_INLINE short SHL16_(int a, int shift, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
+ {
+ fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a<<shift;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "SHL16: output is not short: %d in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+
+static OPUS_INLINE int SHR32(opus_int64 a, int shift)
+{
+ opus_int64 res;
+ if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
+ {
+ fprintf (stderr, "SHR32: inputs are not int: %d %d\n", (int)a, shift);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a>>shift;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+#define SHL32(a, shift) SHL32_(a, shift, __FILE__, __LINE__)
+static OPUS_INLINE int SHL32_(opus_int64 a, int shift, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
+ {
+ fprintf (stderr, "SHL32: inputs are not int: %lld %d in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a<<shift;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "SHL32: output is not int: %lld<<%d = %lld in %s: line %d\n", a, shift, res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#define PSHR32(a,shift) (celt_mips--,SHR32(ADD32((a),(((opus_val32)(1)<<((shift))>>1))),shift))
+#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
+
+#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a))))
+#define HALF16(x) (SHR16(x,1))
+#define HALF32(x) (SHR32(x,1))
+
+//#define SHR(a,shift) ((a) >> (shift))
+//#define SHL(a,shift) ((a) << (shift))
+
+#define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE short ADD16_(int a, int b, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a+b;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+
+#define SUB16(a, b) SUB16_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE short SUB16_(int a, int b, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a-b;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+
+#define ADD32(a, b) ADD32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int ADD32_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_INT(a) || !VERIFY_INT(b))
+ {
+ fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a+b;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#define SUB32(a, b) SUB32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int SUB32_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_INT(a) || !VERIFY_INT(b))
+ {
+ fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a-b;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#undef UADD32
+#define UADD32(a, b) UADD32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE unsigned int UADD32_(opus_uint64 a, opus_uint64 b, char *file, int line)
+{
+ opus_uint64 res;
+ if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
+ {
+ fprintf (stderr, "UADD32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a+b;
+ if (!VERIFY_UINT(res))
+ {
+ fprintf (stderr, "UADD32: output is not uint32: %llu in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#undef USUB32
+#define USUB32(a, b) USUB32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE unsigned int USUB32_(opus_uint64 a, opus_uint64 b, char *file, int line)
+{
+ opus_uint64 res;
+ if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
+ {
+ fprintf (stderr, "USUB32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ if (a<b)
+ {
+ fprintf (stderr, "USUB32: inputs underflow: %llu < %llu in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a-b;
+ if (!VERIFY_UINT(res))
+ {
+ fprintf (stderr, "USUB32: output is not uint32: %llu - %llu = %llu in %s: line %d\n", a, b, res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+/* result fits in 16 bits */
+static OPUS_INLINE short MULT16_16_16(int a, int b)
+{
+ int res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a*b;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+
+#define MULT16_16(a, b) MULT16_16_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int MULT16_16_(int a, int b, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+
+#define MAC16_16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_16((a),(b))))
+
+#define MULT16_32_QX(a, b, Q) MULT16_32_QX_(a, b, Q, __FILE__, __LINE__)
+static OPUS_INLINE int MULT16_32_QX_(int a, opus_int64 b, int Q, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
+ {
+ fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ if (ABS32(b)>=((opus_val32)(1)<<(15+Q)))
+ {
+ fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = (((opus_int64)a)*(opus_int64)b) >> Q;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ if (Q==15)
+ celt_mips+=3;
+ else
+ celt_mips+=4;
+ return res;
+}
+
+#define MULT16_32_PX(a, b, Q) MULT16_32_PX_(a, b, Q, __FILE__, __LINE__)
+static OPUS_INLINE int MULT16_32_PX_(int a, opus_int64 b, int Q, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
+ {
+ fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d in %s: line %d\n\n", Q, (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ if (ABS32(b)>=((opus_int64)(1)<<(15+Q)))
+ {
+ fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n\n", Q, (int)a, (int)b,file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((((opus_int64)a)*(opus_int64)b) + (((opus_val32)(1)<<Q)>>1))>> Q;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d in %s: line %d\n\n", Q, (int)a, (int)b,(int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ if (Q==15)
+ celt_mips+=4;
+ else
+ celt_mips+=5;
+ return res;
+}
+
+#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15)
+#define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b))))
+#define MAC16_32_Q16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q16((a),(b))))
+
+static OPUS_INLINE int SATURATE(int a, int b)
+{
+ if (a>b)
+ a=b;
+ if (a<-b)
+ a = -b;
+ celt_mips+=3;
+ return a;
+}
+
+static OPUS_INLINE opus_int16 SATURATE16(opus_int32 a)
+{
+ celt_mips+=3;
+ if (a>32767)
+ return 32767;
+ else if (a<-32768)
+ return -32768;
+ else return a;
+}
+
+static OPUS_INLINE int MULT16_16_Q11_32(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res >>= 11;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=3;
+ return res;
+}
+static OPUS_INLINE short MULT16_16_Q13(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res >>= 13;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=3;
+ return res;
+}
+static OPUS_INLINE short MULT16_16_Q14(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res >>= 14;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=3;
+ return res;
+}
+
+#define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE short MULT16_16_Q15_(int a, int b, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res >>= 15;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=1;
+ return res;
+}
+
+static OPUS_INLINE short MULT16_16_P13(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res += 4096;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res >>= 13;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=4;
+ return res;
+}
+static OPUS_INLINE short MULT16_16_P14(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res += 8192;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res >>= 14;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=4;
+ return res;
+}
+static OPUS_INLINE short MULT16_16_P15(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res += 16384;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res >>= 15;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__)
+
+static OPUS_INLINE int DIV32_16_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+ opus_int64 res;
+ if (b==0)
+ {
+ fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ return 0;
+ }
+ if (!VERIFY_INT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a/b;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line);
+ if (res>32767)
+ res = 32767;
+ if (res<-32768)
+ res = -32768;
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=35;
+ return res;
+}
+
+#define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int DIV32_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+ opus_int64 res;
+ if (b==0)
+ {
+ fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ return 0;
+ }
+
+ if (!VERIFY_INT(a) || !VERIFY_INT(b))
+ {
+ fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a/b;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=70;
+ return res;
+}
+
+static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x)
+{
+ x = PSHR32(x, SIG_SHIFT);
+ x = MAX32(x, -32768);
+ x = MIN32(x, 32767);
+ return EXTRACT16(x);
+}
+#define SIG2WORD16(x) (SIG2WORD16_generic(x))
+
+
+#undef PRINT_MIPS
+#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0);
+
+#endif
diff --git a/external/opus-1.1.4/celt/fixed_generic.h b/external/opus-1.1.4/celt/fixed_generic.h
new file mode 100644
index 0000000..1cfd6d6
--- /dev/null
+++ b/external/opus-1.1.4/celt/fixed_generic.h
@@ -0,0 +1,167 @@
+/* Copyright (C) 2007-2009 Xiph.Org Foundation
+ Copyright (C) 2003-2008 Jean-Marc Valin
+ Copyright (C) 2007-2008 CSIRO */
+/**
+ @file fixed_generic.h
+ @brief Generic fixed-point operations
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef FIXED_GENERIC_H
+#define FIXED_GENERIC_H
+
+/** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */
+#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b))
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#if OPUS_FAST_INT64
+#define MULT16_32_Q16(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),16))
+#else
+#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16))
+#endif
+
+/** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */
+#if OPUS_FAST_INT64
+#define MULT16_32_P16(a,b) ((opus_val32)PSHR((opus_int64)((opus_val16)(a))*(b),16))
+#else
+#define MULT16_32_P16(a,b) ADD32(MULT16_16((a),SHR((b),16)), PSHR(MULT16_16SU((a),((b)&0x0000ffff)),16))
+#endif
+
+/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
+#if OPUS_FAST_INT64
+#define MULT16_32_Q15(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),15))
+#else
+#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15))
+#endif
+
+/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */
+#if OPUS_FAST_INT64
+#define MULT32_32_Q31(a,b) ((opus_val32)SHR((opus_int64)(a)*(opus_int64)(b),31))
+#else
+#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15))
+#endif
+
+/** Compile-time conversion of float constant to 16-bit value */
+#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits))))
+
+/** Compile-time conversion of float constant to 32-bit value */
+#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits))))
+
+/** Negate a 16-bit value */
+#define NEG16(x) (-(x))
+/** Negate a 32-bit value */
+#define NEG32(x) (-(x))
+
+/** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */
+#define EXTRACT16(x) ((opus_val16)(x))
+/** Change a 16-bit value into a 32-bit value */
+#define EXTEND32(x) ((opus_val32)(x))
+
+/** Arithmetic shift-right of a 16-bit value */
+#define SHR16(a,shift) ((a) >> (shift))
+/** Arithmetic shift-left of a 16-bit value */
+#define SHL16(a,shift) ((opus_int16)((opus_uint16)(a)<<(shift)))
+/** Arithmetic shift-right of a 32-bit value */
+#define SHR32(a,shift) ((a) >> (shift))
+/** Arithmetic shift-left of a 32-bit value */
+#define SHL32(a,shift) ((opus_int32)((opus_uint32)(a)<<(shift)))
+
+/** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */
+#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift))
+/** 32-bit arithmetic shift right where the argument can be negative */
+#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
+
+/** "RAW" macros, should not be used outside of this header file */
+#define SHR(a,shift) ((a) >> (shift))
+#define SHL(a,shift) SHL32(a,shift)
+#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift))
+#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
+
+#define SATURATE16(x) (EXTRACT16((x)>32767 ? 32767 : (x)<-32768 ? -32768 : (x)))
+
+/** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */
+#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a))))
+/** Divide by two */
+#define HALF16(x) (SHR16(x,1))
+#define HALF32(x) (SHR32(x,1))
+
+/** Add two 16-bit values */
+#define ADD16(a,b) ((opus_val16)((opus_val16)(a)+(opus_val16)(b)))
+/** Subtract two 16-bit values */
+#define SUB16(a,b) ((opus_val16)(a)-(opus_val16)(b))
+/** Add two 32-bit values */
+#define ADD32(a,b) ((opus_val32)(a)+(opus_val32)(b))
+/** Subtract two 32-bit values */
+#define SUB32(a,b) ((opus_val32)(a)-(opus_val32)(b))
+
+/** 16x16 multiplication where the result fits in 16 bits */
+#define MULT16_16_16(a,b) ((((opus_val16)(a))*((opus_val16)(b))))
+
+/* (opus_val32)(opus_val16) gives TI compiler a hint that it's 16x16->32 multiply */
+/** 16x16 multiplication where the result fits in 32 bits */
+#define MULT16_16(a,b) (((opus_val32)(opus_val16)(a))*((opus_val32)(opus_val16)(b)))
+
+/** 16x16 multiply-add where the result fits in 32 bits */
+#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
+/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
+ b must fit in 31 bits.
+ Result fits in 32 bits. */
+#define MAC16_32_Q15(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
+
+/** 16x32 multiplication, followed by a 16-bit shift right and 32-bit add.
+ Results fits in 32 bits */
+#define MAC16_32_Q16(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16)))
+
+#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
+#define MULT16_16_Q11(a,b) (SHR(MULT16_16((a),(b)),11))
+#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
+#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14))
+#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15))
+
+#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13))
+#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14))
+#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15))
+
+/** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */
+#define DIV32_16(a,b) ((opus_val16)(((opus_val32)(a))/((opus_val16)(b))))
+
+/** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */
+#define DIV32(a,b) (((opus_val32)(a))/((opus_val32)(b)))
+
+#if defined(MIPSr1_ASM)
+#include "mips/fixed_generic_mipsr1.h"
+#endif
+
+static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x)
+{
+ x = PSHR32(x, SIG_SHIFT);
+ x = MAX32(x, -32768);
+ x = MIN32(x, 32767);
+ return EXTRACT16(x);
+}
+#define SIG2WORD16(x) (SIG2WORD16_generic(x))
+
+#endif
diff --git a/external/opus-1.1.4/celt/float_cast.h b/external/opus-1.1.4/celt/float_cast.h
new file mode 100644
index 0000000..ed5a39b
--- /dev/null
+++ b/external/opus-1.1.4/celt/float_cast.h
@@ -0,0 +1,140 @@
+/* Copyright (C) 2001 Erik de Castro Lopo <erikd AT mega-nerd DOT com> */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+/* Version 1.1 */
+
+#ifndef FLOAT_CAST_H
+#define FLOAT_CAST_H
+
+
+#include "arch.h"
+
+/*============================================================================
+** On Intel Pentium processors (especially PIII and probably P4), converting
+** from float to int is very slow. To meet the C specs, the code produced by
+** most C compilers targeting Pentium needs to change the FPU rounding mode
+** before the float to int conversion is performed.
+**
+** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
+** is this flushing of the pipeline which is so slow.
+**
+** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
+** llrint and llrintf which fix this problem as a side effect.
+**
+** On Unix-like systems, the configure process should have detected the
+** presence of these functions. If they weren't found we have to replace them
+** here with a standard C cast.
+*/
+
+/*
+** The C99 prototypes for lrint and lrintf are as follows:
+**
+** long int lrintf (float x) ;
+** long int lrint (double x) ;
+*/
+
+/* The presence of the required functions are detected during the configure
+** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
+** the config.h file.
+*/
+
+#if (HAVE_LRINTF)
+
+/* These defines enable functionality introduced with the 1999 ISO C
+** standard. They must be defined before the inclusion of math.h to
+** engage them. If optimisation is enabled, these functions will be
+** inlined. With optimisation switched off, you have to link in the
+** maths library using -lm.
+*/
+
+#define _ISOC9X_SOURCE 1
+#define _ISOC99_SOURCE 1
+
+#define __USE_ISOC9X 1
+#define __USE_ISOC99 1
+
+#include <math.h>
+#define float2int(x) lrintf(x)
+
+#elif (defined(HAVE_LRINT))
+
+#define _ISOC9X_SOURCE 1
+#define _ISOC99_SOURCE 1
+
+#define __USE_ISOC9X 1
+#define __USE_ISOC99 1
+
+#include <math.h>
+#define float2int(x) lrint(x)
+
+#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_X64)
+ #include <xmmintrin.h>
+
+ __inline long int float2int(float value)
+ {
+ return _mm_cvtss_si32(_mm_load_ss(&value));
+ }
+#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_IX86)
+ #include <math.h>
+
+ /* Win32 doesn't seem to have these functions.
+ ** Therefore implement OPUS_INLINE versions of these functions here.
+ */
+
+ __inline long int
+ float2int (float flt)
+ { int intgr;
+
+ _asm
+ { fld flt
+ fistp intgr
+ } ;
+
+ return intgr ;
+ }
+
+#else
+
+#if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L)
+ /* supported by gcc in C99 mode, but not by all other compilers */
+ #warning "Don't have the functions lrint() and lrintf ()."
+ #warning "Replacing these functions with a standard C cast."
+#endif /* __STDC_VERSION__ >= 199901L */
+ #include <math.h>
+ #define float2int(flt) ((int)(floor(.5+flt)))
+#endif
+
+#ifndef DISABLE_FLOAT_API
+static OPUS_INLINE opus_int16 FLOAT2INT16(float x)
+{
+ x = x*CELT_SIG_SCALE;
+ x = MAX32(x, -32768);
+ x = MIN32(x, 32767);
+ return (opus_int16)float2int(x);
+}
+#endif /* DISABLE_FLOAT_API */
+
+#endif /* FLOAT_CAST_H */
diff --git a/external/opus-1.1.4/celt/kiss_fft.c b/external/opus-1.1.4/celt/kiss_fft.c
new file mode 100644
index 0000000..1f8fd05
--- /dev/null
+++ b/external/opus-1.1.4/celt/kiss_fft.c
@@ -0,0 +1,604 @@
+/*Copyright (c) 2003-2004, Mark Borgerding
+ Lots of modifications by Jean-Marc Valin
+ Copyright (c) 2005-2007, Xiph.Org Foundation
+ Copyright (c) 2008, Xiph.Org Foundation, CSIRO
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.*/
+
+/* This code is originally from Mark Borgerding's KISS-FFT but has been
+ heavily modified to better suit Opus */
+
+#ifndef SKIP_CONFIG_H
+# ifdef HAVE_CONFIG_H
+# include "config.h"
+# endif
+#endif
+
+#include "_kiss_fft_guts.h"
+#include "arch.h"
+#include "os_support.h"
+#include "mathops.h"
+#include "stack_alloc.h"
+
+/* The guts header contains all the multiplication and addition macros that are defined for
+ complex numbers. It also delares the kf_ internal functions.
+*/
+
+static void kf_bfly2(
+ kiss_fft_cpx * Fout,
+ int m,
+ int N
+ )
+{
+ kiss_fft_cpx * Fout2;
+ int i;
+ (void)m;
+#ifdef CUSTOM_MODES
+ if (m==1)
+ {
+ celt_assert(m==1);
+ for (i=0;i<N;i++)
+ {
+ kiss_fft_cpx t;
+ Fout2 = Fout + 1;
+ t = *Fout2;
+ C_SUB( *Fout2 , *Fout , t );
+ C_ADDTO( *Fout , t );
+ Fout += 2;
+ }
+ } else
+#endif
+ {
+ opus_val16 tw;
+ tw = QCONST16(0.7071067812f, 15);
+ /* We know that m==4 here because the radix-2 is just after a radix-4 */
+ celt_assert(m==4);
+ for (i=0;i<N;i++)
+ {
+ kiss_fft_cpx t;
+ Fout2 = Fout + 4;
+ t = Fout2[0];
+ C_SUB( Fout2[0] , Fout[0] , t );
+ C_ADDTO( Fout[0] , t );
+
+ t.r = S_MUL(Fout2[1].r+Fout2[1].i, tw);
+ t.i = S_MUL(Fout2[1].i-Fout2[1].r, tw);
+ C_SUB( Fout2[1] , Fout[1] , t );
+ C_ADDTO( Fout[1] , t );
+
+ t.r = Fout2[2].i;
+ t.i = -Fout2[2].r;
+ C_SUB( Fout2[2] , Fout[2] , t );
+ C_ADDTO( Fout[2] , t );
+
+ t.r = S_MUL(Fout2[3].i-Fout2[3].r, tw);
+ t.i = S_MUL(-Fout2[3].i-Fout2[3].r, tw);
+ C_SUB( Fout2[3] , Fout[3] , t );
+ C_ADDTO( Fout[3] , t );
+ Fout += 8;
+ }
+ }
+}
+
+static void kf_bfly4(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ int i;
+
+ if (m==1)
+ {
+ /* Degenerate case where all the twiddles are 1. */
+ for (i=0;i<N;i++)
+ {
+ kiss_fft_cpx scratch0, scratch1;
+
+ C_SUB( scratch0 , *Fout, Fout[2] );
+ C_ADDTO(*Fout, Fout[2]);
+ C_ADD( scratch1 , Fout[1] , Fout[3] );
+ C_SUB( Fout[2], *Fout, scratch1 );
+ C_ADDTO( *Fout , scratch1 );
+ C_SUB( scratch1 , Fout[1] , Fout[3] );
+
+ Fout[1].r = scratch0.r + scratch1.i;
+ Fout[1].i = scratch0.i - scratch1.r;
+ Fout[3].r = scratch0.r - scratch1.i;
+ Fout[3].i = scratch0.i + scratch1.r;
+ Fout+=4;
+ }
+ } else {
+ int j;
+ kiss_fft_cpx scratch[6];
+ const kiss_twiddle_cpx *tw1,*tw2,*tw3;
+ const int m2=2*m;
+ const int m3=3*m;
+ kiss_fft_cpx * Fout_beg = Fout;
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ tw3 = tw2 = tw1 = st->twiddles;
+ /* m is guaranteed to be a multiple of 4. */
+ for (j=0;j<m;j++)
+ {
+ C_MUL(scratch[0],Fout[m] , *tw1 );
+ C_MUL(scratch[1],Fout[m2] , *tw2 );
+ C_MUL(scratch[2],Fout[m3] , *tw3 );
+
+ C_SUB( scratch[5] , *Fout, scratch[1] );
+ C_ADDTO(*Fout, scratch[1]);
+ C_ADD( scratch[3] , scratch[0] , scratch[2] );
+ C_SUB( scratch[4] , scratch[0] , scratch[2] );
+ C_SUB( Fout[m2], *Fout, scratch[3] );
+ tw1 += fstride;
+ tw2 += fstride*2;
+ tw3 += fstride*3;
+ C_ADDTO( *Fout , scratch[3] );
+
+ Fout[m].r = scratch[5].r + scratch[4].i;
+ Fout[m].i = scratch[5].i - scratch[4].r;
+ Fout[m3].r = scratch[5].r - scratch[4].i;
+ Fout[m3].i = scratch[5].i + scratch[4].r;
+ ++Fout;
+ }
+ }
+ }
+}
+
+
+#ifndef RADIX_TWO_ONLY
+
+static void kf_bfly3(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ int i;
+ size_t k;
+ const size_t m2 = 2*m;
+ const kiss_twiddle_cpx *tw1,*tw2;
+ kiss_fft_cpx scratch[5];
+ kiss_twiddle_cpx epi3;
+
+ kiss_fft_cpx * Fout_beg = Fout;
+#ifdef FIXED_POINT
+ /*epi3.r = -16384;*/ /* Unused */
+ epi3.i = -28378;
+#else
+ epi3 = st->twiddles[fstride*m];
+#endif
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ tw1=tw2=st->twiddles;
+ /* For non-custom modes, m is guaranteed to be a multiple of 4. */
+ k=m;
+ do {
+
+ C_MUL(scratch[1],Fout[m] , *tw1);
+ C_MUL(scratch[2],Fout[m2] , *tw2);
+
+ C_ADD(scratch[3],scratch[1],scratch[2]);
+ C_SUB(scratch[0],scratch[1],scratch[2]);
+ tw1 += fstride;
+ tw2 += fstride*2;
+
+ Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
+ Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
+
+ C_MULBYSCALAR( scratch[0] , epi3.i );
+
+ C_ADDTO(*Fout,scratch[3]);
+
+ Fout[m2].r = Fout[m].r + scratch[0].i;
+ Fout[m2].i = Fout[m].i - scratch[0].r;
+
+ Fout[m].r -= scratch[0].i;
+ Fout[m].i += scratch[0].r;
+
+ ++Fout;
+ } while(--k);
+ }
+}
+
+
+#ifndef OVERRIDE_kf_bfly5
+static void kf_bfly5(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
+ int i, u;
+ kiss_fft_cpx scratch[13];
+ const kiss_twiddle_cpx *tw;
+ kiss_twiddle_cpx ya,yb;
+ kiss_fft_cpx * Fout_beg = Fout;
+
+#ifdef FIXED_POINT
+ ya.r = 10126;
+ ya.i = -31164;
+ yb.r = -26510;
+ yb.i = -19261;
+#else
+ ya = st->twiddles[fstride*m];
+ yb = st->twiddles[fstride*2*m];
+#endif
+ tw=st->twiddles;
+
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ Fout0=Fout;
+ Fout1=Fout0+m;
+ Fout2=Fout0+2*m;
+ Fout3=Fout0+3*m;
+ Fout4=Fout0+4*m;
+
+ /* For non-custom modes, m is guaranteed to be a multiple of 4. */
+ for ( u=0; u<m; ++u ) {
+ scratch[0] = *Fout0;
+
+ C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
+ C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
+ C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
+ C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
+
+ C_ADD( scratch[7],scratch[1],scratch[4]);
+ C_SUB( scratch[10],scratch[1],scratch[4]);
+ C_ADD( scratch[8],scratch[2],scratch[3]);
+ C_SUB( scratch[9],scratch[2],scratch[3]);
+
+ Fout0->r += scratch[7].r + scratch[8].r;
+ Fout0->i += scratch[7].i + scratch[8].i;
+
+ scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
+ scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
+
+ scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
+ scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
+
+ C_SUB(*Fout1,scratch[5],scratch[6]);
+ C_ADD(*Fout4,scratch[5],scratch[6]);
+
+ scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
+ scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
+ scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
+ scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
+
+ C_ADD(*Fout2,scratch[11],scratch[12]);
+ C_SUB(*Fout3,scratch[11],scratch[12]);
+
+ ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
+ }
+ }
+}
+#endif /* OVERRIDE_kf_bfly5 */
+
+
+#endif
+
+
+#ifdef CUSTOM_MODES
+
+static
+void compute_bitrev_table(
+ int Fout,
+ opus_int16 *f,
+ const size_t fstride,
+ int in_stride,
+ opus_int16 * factors,
+ const kiss_fft_state *st
+ )
+{
+ const int p=*factors++; /* the radix */
+ const int m=*factors++; /* stage's fft length/p */
+
+ /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/
+ if (m==1)
+ {
+ int j;
+ for (j=0;j<p;j++)
+ {
+ *f = Fout+j;
+ f += fstride*in_stride;
+ }
+ } else {
+ int j;
+ for (j=0;j<p;j++)
+ {
+ compute_bitrev_table( Fout , f, fstride*p, in_stride, factors,st);
+ f += fstride*in_stride;
+ Fout += m;
+ }
+ }
+}
+
+/* facbuf is populated by p1,m1,p2,m2, ...
+ where
+ p[i] * m[i] = m[i-1]
+ m0 = n */
+static
+int kf_factor(int n,opus_int16 * facbuf)
+{
+ int p=4;
+ int i;
+ int stages=0;
+ int nbak = n;
+
+ /*factor out powers of 4, powers of 2, then any remaining primes */
+ do {
+ while (n % p) {
+ switch (p) {
+ case 4: p = 2; break;
+ case 2: p = 3; break;
+ default: p += 2; break;
+ }
+ if (p>32000 || (opus_int32)p*(opus_int32)p > n)
+ p = n; /* no more factors, skip to end */
+ }
+ n /= p;
+#ifdef RADIX_TWO_ONLY
+ if (p!=2 && p != 4)
+#else
+ if (p>5)
+#endif
+ {
+ return 0;
+ }
+ facbuf[2*stages] = p;
+ if (p==2 && stages > 1)
+ {
+ facbuf[2*stages] = 4;
+ facbuf[2] = 2;
+ }
+ stages++;
+ } while (n > 1);
+ n = nbak;
+ /* Reverse the order to get the radix 4 at the end, so we can use the
+ fast degenerate case. It turns out that reversing the order also
+ improves the noise behaviour. */
+ for (i=0;i<stages/2;i++)
+ {
+ int tmp;
+ tmp = facbuf[2*i];
+ facbuf[2*i] = facbuf[2*(stages-i-1)];
+ facbuf[2*(stages-i-1)] = tmp;
+ }
+ for (i=0;i<stages;i++)
+ {
+ n /= facbuf[2*i];
+ facbuf[2*i+1] = n;
+ }
+ return 1;
+}
+
+static void compute_twiddles(kiss_twiddle_cpx *twiddles, int nfft)
+{
+ int i;
+#ifdef FIXED_POINT
+ for (i=0;i<nfft;++i) {
+ opus_val32 phase = -i;
+ kf_cexp2(twiddles+i, DIV32(SHL32(phase,17),nfft));
+ }
+#else
+ for (i=0;i<nfft;++i) {
+ const double pi=3.14159265358979323846264338327;
+ double phase = ( -2*pi /nfft ) * i;
+ kf_cexp(twiddles+i, phase );
+ }
+#endif
+}
+
+int opus_fft_alloc_arch_c(kiss_fft_state *st) {
+ (void)st;
+ return 0;
+}
+
+/*
+ *
+ * Allocates all necessary storage space for the fft and ifft.
+ * The return value is a contiguous block of memory. As such,
+ * It can be freed with free().
+ * */
+kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem,
+ const kiss_fft_state *base, int arch)
+{
+ kiss_fft_state *st=NULL;
+ size_t memneeded = sizeof(struct kiss_fft_state); /* twiddle factors*/
+
+ if ( lenmem==NULL ) {
+ st = ( kiss_fft_state*)KISS_FFT_MALLOC( memneeded );
+ }else{
+ if (mem != NULL && *lenmem >= memneeded)
+ st = (kiss_fft_state*)mem;
+ *lenmem = memneeded;
+ }
+ if (st) {
+ opus_int16 *bitrev;
+ kiss_twiddle_cpx *twiddles;
+
+ st->nfft=nfft;
+#ifdef FIXED_POINT
+ st->scale_shift = celt_ilog2(st->nfft);
+ if (st->nfft == 1<<st->scale_shift)
+ st->scale = Q15ONE;
+ else
+ st->scale = (1073741824+st->nfft/2)/st->nfft>>(15-st->scale_shift);
+#else
+ st->scale = 1.f/nfft;
+#endif
+ if (base != NULL)
+ {
+ st->twiddles = base->twiddles;
+ st->shift = 0;
+ while (st->shift < 32 && nfft<<st->shift != base->nfft)
+ st->shift++;
+ if (st->shift>=32)
+ goto fail;
+ } else {
+ st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft);
+ compute_twiddles(twiddles, nfft);
+ st->shift = -1;
+ }
+ if (!kf_factor(nfft,st->factors))
+ {
+ goto fail;
+ }
+
+ /* bitrev */
+ st->bitrev = bitrev = (opus_int16*)KISS_FFT_MALLOC(sizeof(opus_int16)*nfft);
+ if (st->bitrev==NULL)
+ goto fail;
+ compute_bitrev_table(0, bitrev, 1,1, st->factors,st);
+
+ /* Initialize architecture specific fft parameters */
+ if (opus_fft_alloc_arch(st, arch))
+ goto fail;
+ }
+ return st;
+fail:
+ opus_fft_free(st, arch);
+ return NULL;
+}
+
+kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch)
+{
+ return opus_fft_alloc_twiddles(nfft, mem, lenmem, NULL, arch);
+}
+
+void opus_fft_free_arch_c(kiss_fft_state *st) {
+ (void)st;
+}
+
+void opus_fft_free(const kiss_fft_state *cfg, int arch)
+{
+ if (cfg)
+ {
+ opus_fft_free_arch((kiss_fft_state *)cfg, arch);
+ opus_free((opus_int16*)cfg->bitrev);
+ if (cfg->shift < 0)
+ opus_free((kiss_twiddle_cpx*)cfg->twiddles);
+ opus_free((kiss_fft_state*)cfg);
+ }
+}
+
+#endif /* CUSTOM_MODES */
+
+void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout)
+{
+ int m2, m;
+ int p;
+ int L;
+ int fstride[MAXFACTORS];
+ int i;
+ int shift;
+
+ /* st->shift can be -1 */
+ shift = st->shift>0 ? st->shift : 0;
+
+ fstride[0] = 1;
+ L=0;
+ do {
+ p = st->factors[2*L];
+ m = st->factors[2*L+1];
+ fstride[L+1] = fstride[L]*p;
+ L++;
+ } while(m!=1);
+ m = st->factors[2*L-1];
+ for (i=L-1;i>=0;i--)
+ {
+ if (i!=0)
+ m2 = st->factors[2*i-1];
+ else
+ m2 = 1;
+ switch (st->factors[2*i])
+ {
+ case 2:
+ kf_bfly2(fout, m, fstride[i]);
+ break;
+ case 4:
+ kf_bfly4(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+ break;
+ #ifndef RADIX_TWO_ONLY
+ case 3:
+ kf_bfly3(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+ break;
+ case 5:
+ kf_bfly5(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+ break;
+ #endif
+ }
+ m = m2;
+ }
+}
+
+void opus_fft_c(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
+{
+ int i;
+ opus_val16 scale;
+#ifdef FIXED_POINT
+ /* Allows us to scale with MULT16_32_Q16(), which is faster than
+ MULT16_32_Q15() on ARM. */
+ int scale_shift = st->scale_shift-1;
+#endif
+ scale = st->scale;
+
+ celt_assert2 (fin != fout, "In-place FFT not supported");
+ /* Bit-reverse the input */
+ for (i=0;i<st->nfft;i++)
+ {
+ kiss_fft_cpx x = fin[i];
+ fout[st->bitrev[i]].r = SHR32(MULT16_32_Q16(scale, x.r), scale_shift);
+ fout[st->bitrev[i]].i = SHR32(MULT16_32_Q16(scale, x.i), scale_shift);
+ }
+ opus_fft_impl(st, fout);
+}
+
+
+void opus_ifft_c(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
+{
+ int i;
+ celt_assert2 (fin != fout, "In-place FFT not supported");
+ /* Bit-reverse the input */
+ for (i=0;i<st->nfft;i++)
+ fout[st->bitrev[i]] = fin[i];
+ for (i=0;i<st->nfft;i++)
+ fout[i].i = -fout[i].i;
+ opus_fft_impl(st, fout);
+ for (i=0;i<st->nfft;i++)
+ fout[i].i = -fout[i].i;
+}
diff --git a/external/opus-1.1.4/celt/kiss_fft.h b/external/opus-1.1.4/celt/kiss_fft.h
new file mode 100644
index 0000000..bffa2bf
--- /dev/null
+++ b/external/opus-1.1.4/celt/kiss_fft.h
@@ -0,0 +1,200 @@
+/*Copyright (c) 2003-2004, Mark Borgerding
+ Lots of modifications by Jean-Marc Valin
+ Copyright (c) 2005-2007, Xiph.Org Foundation
+ Copyright (c) 2008, Xiph.Org Foundation, CSIRO
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.*/
+
+#ifndef KISS_FFT_H
+#define KISS_FFT_H
+
+#include <stdlib.h>
+#include <math.h>
+#include "arch.h"
+#include "cpu_support.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef USE_SIMD
+# include <xmmintrin.h>
+# define kiss_fft_scalar __m128
+#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes)
+#else
+#define KISS_FFT_MALLOC opus_alloc
+#endif
+
+#ifdef FIXED_POINT
+#include "arch.h"
+
+# define kiss_fft_scalar opus_int32
+# define kiss_twiddle_scalar opus_int16
+
+
+#else
+# ifndef kiss_fft_scalar
+/* default is float */
+# define kiss_fft_scalar float
+# define kiss_twiddle_scalar float
+# define KF_SUFFIX _celt_single
+# endif
+#endif
+
+typedef struct {
+ kiss_fft_scalar r;
+ kiss_fft_scalar i;
+}kiss_fft_cpx;
+
+typedef struct {
+ kiss_twiddle_scalar r;
+ kiss_twiddle_scalar i;
+}kiss_twiddle_cpx;
+
+#define MAXFACTORS 8
+/* e.g. an fft of length 128 has 4 factors
+ as far as kissfft is concerned
+ 4*4*4*2
+ */
+
+typedef struct arch_fft_state{
+ int is_supported;
+ void *priv;
+} arch_fft_state;
+
+typedef struct kiss_fft_state{
+ int nfft;
+ opus_val16 scale;
+#ifdef FIXED_POINT
+ int scale_shift;
+#endif
+ int shift;
+ opus_int16 factors[2*MAXFACTORS];
+ const opus_int16 *bitrev;
+ const kiss_twiddle_cpx *twiddles;
+ arch_fft_state *arch_fft;
+} kiss_fft_state;
+
+#if defined(HAVE_ARM_NE10)
+#include "arm/fft_arm.h"
+#endif
+
+/*typedef struct kiss_fft_state* kiss_fft_cfg;*/
+
+/**
+ * opus_fft_alloc
+ *
+ * Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
+ *
+ * typical usage: kiss_fft_cfg mycfg=opus_fft_alloc(1024,0,NULL,NULL);
+ *
+ * The return value from fft_alloc is a cfg buffer used internally
+ * by the fft routine or NULL.
+ *
+ * If lenmem is NULL, then opus_fft_alloc will allocate a cfg buffer using malloc.
+ * The returned value should be free()d when done to avoid memory leaks.
+ *
+ * The state can be placed in a user supplied buffer 'mem':
+ * If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
+ * then the function places the cfg in mem and the size used in *lenmem
+ * and returns mem.
+ *
+ * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
+ * then the function returns NULL and places the minimum cfg
+ * buffer size in *lenmem.
+ * */
+
+kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base, int arch);
+
+kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch);
+
+/**
+ * opus_fft(cfg,in_out_buf)
+ *
+ * Perform an FFT on a complex input buffer.
+ * for a forward FFT,
+ * fin should be f[0] , f[1] , ... ,f[nfft-1]
+ * fout will be F[0] , F[1] , ... ,F[nfft-1]
+ * Note that each element is complex and can be accessed like
+ f[k].r and f[k].i
+ * */
+void opus_fft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
+void opus_ifft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
+
+void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout);
+void opus_ifft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout);
+
+void opus_fft_free(const kiss_fft_state *cfg, int arch);
+
+
+void opus_fft_free_arch_c(kiss_fft_state *st);
+int opus_fft_alloc_arch_c(kiss_fft_state *st);
+
+#if !defined(OVERRIDE_OPUS_FFT)
+/* Is run-time CPU detection enabled on this platform? */
+#if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10))
+
+extern int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])(
+ kiss_fft_state *st);
+
+#define opus_fft_alloc_arch(_st, arch) \
+ ((*OPUS_FFT_ALLOC_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st))
+
+extern void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])(
+ kiss_fft_state *st);
+#define opus_fft_free_arch(_st, arch) \
+ ((*OPUS_FFT_FREE_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st))
+
+extern void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg,
+ const kiss_fft_cpx *fin, kiss_fft_cpx *fout);
+#define opus_fft(_cfg, _fin, _fout, arch) \
+ ((*OPUS_FFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout))
+
+extern void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg,
+ const kiss_fft_cpx *fin, kiss_fft_cpx *fout);
+#define opus_ifft(_cfg, _fin, _fout, arch) \
+ ((*OPUS_IFFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout))
+
+#else /* else for if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */
+
+#define opus_fft_alloc_arch(_st, arch) \
+ ((void)(arch), opus_fft_alloc_arch_c(_st))
+
+#define opus_fft_free_arch(_st, arch) \
+ ((void)(arch), opus_fft_free_arch_c(_st))
+
+#define opus_fft(_cfg, _fin, _fout, arch) \
+ ((void)(arch), opus_fft_c(_cfg, _fin, _fout))
+
+#define opus_ifft(_cfg, _fin, _fout, arch) \
+ ((void)(arch), opus_ifft_c(_cfg, _fin, _fout))
+
+#endif /* end if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */
+#endif /* end if !defined(OVERRIDE_OPUS_FFT) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/celt/laplace.c b/external/opus-1.1.4/celt/laplace.c
new file mode 100644
index 0000000..a7bca87
--- /dev/null
+++ b/external/opus-1.1.4/celt/laplace.c
@@ -0,0 +1,134 @@
+/* Copyright (c) 2007 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "laplace.h"
+#include "mathops.h"
+
+/* The minimum probability of an energy delta (out of 32768). */
+#define LAPLACE_LOG_MINP (0)
+#define LAPLACE_MINP (1<<LAPLACE_LOG_MINP)
+/* The minimum number of guaranteed representable energy deltas (in one
+ direction). */
+#define LAPLACE_NMIN (16)
+
+/* When called, decay is positive and at most 11456. */
+static unsigned ec_laplace_get_freq1(unsigned fs0, int decay)
+{
+ unsigned ft;
+ ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN) - fs0;
+ return ft*(opus_int32)(16384-decay)>>15;
+}
+
+void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay)
+{
+ unsigned fl;
+ int val = *value;
+ fl = 0;
+ if (val)
+ {
+ int s;
+ int i;
+ s = -(val<0);
+ val = (val+s)^s;
+ fl = fs;
+ fs = ec_laplace_get_freq1(fs, decay);
+ /* Search the decaying part of the PDF.*/
+ for (i=1; fs > 0 && i < val; i++)
+ {
+ fs *= 2;
+ fl += fs+2*LAPLACE_MINP;
+ fs = (fs*(opus_int32)decay)>>15;
+ }
+ /* Everything beyond that has probability LAPLACE_MINP. */
+ if (!fs)
+ {
+ int di;
+ int ndi_max;
+ ndi_max = (32768-fl+LAPLACE_MINP-1)>>LAPLACE_LOG_MINP;
+ ndi_max = (ndi_max-s)>>1;
+ di = IMIN(val - i, ndi_max - 1);
+ fl += (2*di+1+s)*LAPLACE_MINP;
+ fs = IMIN(LAPLACE_MINP, 32768-fl);
+ *value = (i+di+s)^s;
+ }
+ else
+ {
+ fs += LAPLACE_MINP;
+ fl += fs&~s;
+ }
+ celt_assert(fl+fs<=32768);
+ celt_assert(fs>0);
+ }
+ ec_encode_bin(enc, fl, fl+fs, 15);
+}
+
+int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay)
+{
+ int val=0;
+ unsigned fl;
+ unsigned fm;
+ fm = ec_decode_bin(dec, 15);
+ fl = 0;
+ if (fm >= fs)
+ {
+ val++;
+ fl = fs;
+ fs = ec_laplace_get_freq1(fs, decay)+LAPLACE_MINP;
+ /* Search the decaying part of the PDF.*/
+ while(fs > LAPLACE_MINP && fm >= fl+2*fs)
+ {
+ fs *= 2;
+ fl += fs;
+ fs = ((fs-2*LAPLACE_MINP)*(opus_int32)decay)>>15;
+ fs += LAPLACE_MINP;
+ val++;
+ }
+ /* Everything beyond that has probability LAPLACE_MINP. */
+ if (fs <= LAPLACE_MINP)
+ {
+ int di;
+ di = (fm-fl)>>(LAPLACE_LOG_MINP+1);
+ val += di;
+ fl += 2*di*LAPLACE_MINP;
+ }
+ if (fm < fl+fs)
+ val = -val;
+ else
+ fl += fs;
+ }
+ celt_assert(fl<32768);
+ celt_assert(fs>0);
+ celt_assert(fl<=fm);
+ celt_assert(fm<IMIN(fl+fs,32768));
+ ec_dec_update(dec, fl, IMIN(fl+fs,32768), 32768);
+ return val;
+}
diff --git a/external/opus-1.1.4/celt/laplace.h b/external/opus-1.1.4/celt/laplace.h
new file mode 100644
index 0000000..46c14b5
--- /dev/null
+++ b/external/opus-1.1.4/celt/laplace.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2007 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#include "entenc.h"
+#include "entdec.h"
+
+/** Encode a value that is assumed to be the realisation of a
+ Laplace-distributed random process
+ @param enc Entropy encoder state
+ @param value Value to encode
+ @param fs Probability of 0, multiplied by 32768
+ @param decay Probability of the value +/- 1, multiplied by 16384
+*/
+void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay);
+
+/** Decode a value that is assumed to be the realisation of a
+ Laplace-distributed random process
+ @param dec Entropy decoder state
+ @param fs Probability of 0, multiplied by 32768
+ @param decay Probability of the value +/- 1, multiplied by 16384
+ @return Value decoded
+ */
+int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay);
diff --git a/external/opus-1.1.4/celt/mathops.c b/external/opus-1.1.4/celt/mathops.c
new file mode 100644
index 0000000..21a01f5
--- /dev/null
+++ b/external/opus-1.1.4/celt/mathops.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2002-2008 Jean-Marc Valin
+ Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file mathops.h
+ @brief Various math functions
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mathops.h"
+
+/*Compute floor(sqrt(_val)) with exact arithmetic.
+ This has been tested on all possible 32-bit inputs.*/
+unsigned isqrt32(opus_uint32 _val){
+ unsigned b;
+ unsigned g;
+ int bshift;
+ /*Uses the second method from
+ http://www.azillionmonkeys.com/qed/sqroot.html
+ The main idea is to search for the largest binary digit b such that
+ (g+b)*(g+b) <= _val, and add it to the solution g.*/
+ g=0;
+ bshift=(EC_ILOG(_val)-1)>>1;
+ b=1U<<bshift;
+ do{
+ opus_uint32 t;
+ t=(((opus_uint32)g<<1)+b)<<bshift;
+ if(t<=_val){
+ g+=b;
+ _val-=t;
+ }
+ b>>=1;
+ bshift--;
+ }
+ while(bshift>=0);
+ return g;
+}
+
+#ifdef FIXED_POINT
+
+opus_val32 frac_div32(opus_val32 a, opus_val32 b)
+{
+ opus_val16 rcp;
+ opus_val32 result, rem;
+ int shift = celt_ilog2(b)-29;
+ a = VSHR32(a,shift);
+ b = VSHR32(b,shift);
+ /* 16-bit reciprocal */
+ rcp = ROUND16(celt_rcp(ROUND16(b,16)),3);
+ result = MULT16_32_Q15(rcp, a);
+ rem = PSHR32(a,2)-MULT32_32_Q31(result, b);
+ result = ADD32(result, SHL32(MULT16_32_Q15(rcp, rem),2));
+ if (result >= 536870912) /* 2^29 */
+ return 2147483647; /* 2^31 - 1 */
+ else if (result <= -536870912) /* -2^29 */
+ return -2147483647; /* -2^31 */
+ else
+ return SHL32(result, 2);
+}
+
+/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */
+opus_val16 celt_rsqrt_norm(opus_val32 x)
+{
+ opus_val16 n;
+ opus_val16 r;
+ opus_val16 r2;
+ opus_val16 y;
+ /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */
+ n = x-32768;
+ /* Get a rough initial guess for the root.
+ The optimal minimax quadratic approximation (using relative error) is
+ r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485).
+ Coefficients here, and the final result r, are Q14.*/
+ r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713))));
+ /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14.
+ We can compute the result from n and r using Q15 multiplies with some
+ adjustment, carefully done to avoid overflow.
+ Range of y is [-1564,1594]. */
+ r2 = MULT16_16_Q15(r, r);
+ y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1);
+ /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5).
+ This yields the Q14 reciprocal square root of the Q16 x, with a maximum
+ relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a
+ peak absolute error of 2.26591/16384. */
+ return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y,
+ SUB16(MULT16_16_Q15(y, 12288), 16384))));
+}
+
+/** Sqrt approximation (QX input, QX/2 output) */
+opus_val32 celt_sqrt(opus_val32 x)
+{
+ int k;
+ opus_val16 n;
+ opus_val32 rt;
+ static const opus_val16 C[5] = {23175, 11561, -3011, 1699, -664};
+ if (x==0)
+ return 0;
+ else if (x>=1073741824)
+ return 32767;
+ k = (celt_ilog2(x)>>1)-7;
+ x = VSHR32(x, 2*k);
+ n = x-32768;
+ rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2],
+ MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4])))))))));
+ rt = VSHR32(rt,7-k);
+ return rt;
+}
+
+#define L1 32767
+#define L2 -7651
+#define L3 8277
+#define L4 -626
+
+static OPUS_INLINE opus_val16 _celt_cos_pi_2(opus_val16 x)
+{
+ opus_val16 x2;
+
+ x2 = MULT16_16_P15(x,x);
+ return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2
+ ))))))));
+}
+
+#undef L1
+#undef L2
+#undef L3
+#undef L4
+
+opus_val16 celt_cos_norm(opus_val32 x)
+{
+ x = x&0x0001ffff;
+ if (x>SHL32(EXTEND32(1), 16))
+ x = SUB32(SHL32(EXTEND32(1), 17),x);
+ if (x&0x00007fff)
+ {
+ if (x<SHL32(EXTEND32(1), 15))
+ {
+ return _celt_cos_pi_2(EXTRACT16(x));
+ } else {
+ return NEG16(_celt_cos_pi_2(EXTRACT16(65536-x)));
+ }
+ } else {
+ if (x&0x0000ffff)
+ return 0;
+ else if (x&0x0001ffff)
+ return -32767;
+ else
+ return 32767;
+ }
+}
+
+/** Reciprocal approximation (Q15 input, Q16 output) */
+opus_val32 celt_rcp(opus_val32 x)
+{
+ int i;
+ opus_val16 n;
+ opus_val16 r;
+ celt_assert2(x>0, "celt_rcp() only defined for positive values");
+ i = celt_ilog2(x);
+ /* n is Q15 with range [0,1). */
+ n = VSHR32(x,i-15)-32768;
+ /* Start with a linear approximation:
+ r = 1.8823529411764706-0.9411764705882353*n.
+ The coefficients and the result are Q14 in the range [15420,30840].*/
+ r = ADD16(30840, MULT16_16_Q15(-15420, n));
+ /* Perform two Newton iterations:
+ r -= r*((r*n)-1.Q15)
+ = r*((r*n)+(r-1.Q15)). */
+ r = SUB16(r, MULT16_16_Q15(r,
+ ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))));
+ /* We subtract an extra 1 in the second iteration to avoid overflow; it also
+ neatly compensates for truncation error in the rest of the process. */
+ r = SUB16(r, ADD16(1, MULT16_16_Q15(r,
+ ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))));
+ /* r is now the Q15 solution to 2/(n+1), with a maximum relative error
+ of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute
+ error of 1.24665/32768. */
+ return VSHR32(EXTEND32(r),i-16);
+}
+
+#endif
diff --git a/external/opus-1.1.4/celt/mathops.h b/external/opus-1.1.4/celt/mathops.h
new file mode 100644
index 0000000..a0525a9
--- /dev/null
+++ b/external/opus-1.1.4/celt/mathops.h
@@ -0,0 +1,258 @@
+/* Copyright (c) 2002-2008 Jean-Marc Valin
+ Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file mathops.h
+ @brief Various math functions
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef MATHOPS_H
+#define MATHOPS_H
+
+#include "arch.h"
+#include "entcode.h"
+#include "os_support.h"
+
+/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */
+#define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15)
+
+unsigned isqrt32(opus_uint32 _val);
+
+#ifndef OVERRIDE_CELT_MAXABS16
+static OPUS_INLINE opus_val32 celt_maxabs16(const opus_val16 *x, int len)
+{
+ int i;
+ opus_val16 maxval = 0;
+ opus_val16 minval = 0;
+ for (i=0;i<len;i++)
+ {
+ maxval = MAX16(maxval, x[i]);
+ minval = MIN16(minval, x[i]);
+ }
+ return MAX32(EXTEND32(maxval),-EXTEND32(minval));
+}
+#endif
+
+#ifndef OVERRIDE_CELT_MAXABS32
+#ifdef FIXED_POINT
+static OPUS_INLINE opus_val32 celt_maxabs32(const opus_val32 *x, int len)
+{
+ int i;
+ opus_val32 maxval = 0;
+ opus_val32 minval = 0;
+ for (i=0;i<len;i++)
+ {
+ maxval = MAX32(maxval, x[i]);
+ minval = MIN32(minval, x[i]);
+ }
+ return MAX32(maxval, -minval);
+}
+#else
+#define celt_maxabs32(x,len) celt_maxabs16(x,len)
+#endif
+#endif
+
+
+#ifndef FIXED_POINT
+
+#define PI 3.141592653f
+#define celt_sqrt(x) ((float)sqrt(x))
+#define celt_rsqrt(x) (1.f/celt_sqrt(x))
+#define celt_rsqrt_norm(x) (celt_rsqrt(x))
+#define celt_cos_norm(x) ((float)cos((.5f*PI)*(x)))
+#define celt_rcp(x) (1.f/(x))
+#define celt_div(a,b) ((a)/(b))
+#define frac_div32(a,b) ((float)(a)/(b))
+
+#ifdef FLOAT_APPROX
+
+/* Note: This assumes radix-2 floating point with the exponent at bits 23..30 and an offset of 127
+ denorm, +/- inf and NaN are *not* handled */
+
+/** Base-2 log approximation (log2(x)). */
+static OPUS_INLINE float celt_log2(float x)
+{
+ int integer;
+ float frac;
+ union {
+ float f;
+ opus_uint32 i;
+ } in;
+ in.f = x;
+ integer = (in.i>>23)-127;
+ in.i -= integer<<23;
+ frac = in.f - 1.5f;
+ frac = -0.41445418f + frac*(0.95909232f
+ + frac*(-0.33951290f + frac*0.16541097f));
+ return 1+integer+frac;
+}
+
+/** Base-2 exponential approximation (2^x). */
+static OPUS_INLINE float celt_exp2(float x)
+{
+ int integer;
+ float frac;
+ union {
+ float f;
+ opus_uint32 i;
+ } res;
+ integer = floor(x);
+ if (integer < -50)
+ return 0;
+ frac = x-integer;
+ /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */
+ res.f = 0.99992522f + frac * (0.69583354f
+ + frac * (0.22606716f + 0.078024523f*frac));
+ res.i = (res.i + (integer<<23)) & 0x7fffffff;
+ return res.f;
+}
+
+#else
+#define celt_log2(x) ((float)(1.442695040888963387*log(x)))
+#define celt_exp2(x) ((float)exp(0.6931471805599453094*(x)))
+#endif
+
+#endif
+
+#ifdef FIXED_POINT
+
+#include "os_support.h"
+
+#ifndef OVERRIDE_CELT_ILOG2
+/** Integer log in base2. Undefined for zero and negative numbers */
+static OPUS_INLINE opus_int16 celt_ilog2(opus_int32 x)
+{
+ celt_assert2(x>0, "celt_ilog2() only defined for strictly positive numbers");
+ return EC_ILOG(x)-1;
+}
+#endif
+
+
+/** Integer log in base2. Defined for zero, but not for negative numbers */
+static OPUS_INLINE opus_int16 celt_zlog2(opus_val32 x)
+{
+ return x <= 0 ? 0 : celt_ilog2(x);
+}
+
+opus_val16 celt_rsqrt_norm(opus_val32 x);
+
+opus_val32 celt_sqrt(opus_val32 x);
+
+opus_val16 celt_cos_norm(opus_val32 x);
+
+/** Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output) */
+static OPUS_INLINE opus_val16 celt_log2(opus_val32 x)
+{
+ int i;
+ opus_val16 n, frac;
+ /* -0.41509302963303146, 0.9609890551383969, -0.31836011537636605,
+ 0.15530808010959576, -0.08556153059057618 */
+ static const opus_val16 C[5] = {-6801+(1<<(13-DB_SHIFT)), 15746, -5217, 2545, -1401};
+ if (x==0)
+ return -32767;
+ i = celt_ilog2(x);
+ n = VSHR32(x,i-15)-32768-16384;
+ frac = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, C[4]))))))));
+ return SHL16(i-13,DB_SHIFT)+SHR16(frac,14-DB_SHIFT);
+}
+
+/*
+ K0 = 1
+ K1 = log(2)
+ K2 = 3-4*log(2)
+ K3 = 3*log(2) - 2
+*/
+#define D0 16383
+#define D1 22804
+#define D2 14819
+#define D3 10204
+
+static OPUS_INLINE opus_val32 celt_exp2_frac(opus_val16 x)
+{
+ opus_val16 frac;
+ frac = SHL16(x, 4);
+ return ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac))))));
+}
+/** Base-2 exponential approximation (2^x). (Q10 input, Q16 output) */
+static OPUS_INLINE opus_val32 celt_exp2(opus_val16 x)
+{
+ int integer;
+ opus_val16 frac;
+ integer = SHR16(x,10);
+ if (integer>14)
+ return 0x7f000000;
+ else if (integer < -15)
+ return 0;
+ frac = celt_exp2_frac(x-SHL16(integer,10));
+ return VSHR32(EXTEND32(frac), -integer-2);
+}
+
+opus_val32 celt_rcp(opus_val32 x);
+
+#define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b))
+
+opus_val32 frac_div32(opus_val32 a, opus_val32 b);
+
+#define M1 32767
+#define M2 -21
+#define M3 -11943
+#define M4 4936
+
+/* Atan approximation using a 4th order polynomial. Input is in Q15 format
+ and normalized by pi/4. Output is in Q15 format */
+static OPUS_INLINE opus_val16 celt_atan01(opus_val16 x)
+{
+ return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x)))))));
+}
+
+#undef M1
+#undef M2
+#undef M3
+#undef M4
+
+/* atan2() approximation valid for positive input values */
+static OPUS_INLINE opus_val16 celt_atan2p(opus_val16 y, opus_val16 x)
+{
+ if (y < x)
+ {
+ opus_val32 arg;
+ arg = celt_div(SHL32(EXTEND32(y),15),x);
+ if (arg >= 32767)
+ arg = 32767;
+ return SHR16(celt_atan01(EXTRACT16(arg)),1);
+ } else {
+ opus_val32 arg;
+ arg = celt_div(SHL32(EXTEND32(x),15),y);
+ if (arg >= 32767)
+ arg = 32767;
+ return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1);
+ }
+}
+
+#endif /* FIXED_POINT */
+#endif /* MATHOPS_H */
diff --git a/external/opus-1.1.4/celt/mdct.c b/external/opus-1.1.4/celt/mdct.c
new file mode 100644
index 0000000..5315ad1
--- /dev/null
+++ b/external/opus-1.1.4/celt/mdct.c
@@ -0,0 +1,343 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2008 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+/* This is a simple MDCT implementation that uses a N/4 complex FFT
+ to do most of the work. It should be relatively straightforward to
+ plug in pretty much and FFT here.
+
+ This replaces the Vorbis FFT (and uses the exact same API), which
+ was a bit too messy and that was ending up duplicating code
+ (might as well use the same FFT everywhere).
+
+ The algorithm is similar to (and inspired from) Fabrice Bellard's
+ MDCT implementation in FFMPEG, but has differences in signs, ordering
+ and scaling in many places.
+*/
+
+#ifndef SKIP_CONFIG_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#endif
+
+#include "mdct.h"
+#include "kiss_fft.h"
+#include "_kiss_fft_guts.h"
+#include <math.h>
+#include "os_support.h"
+#include "mathops.h"
+#include "stack_alloc.h"
+
+#if defined(MIPSr1_ASM)
+#include "mips/mdct_mipsr1.h"
+#endif
+
+
+#ifdef CUSTOM_MODES
+
+int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch)
+{
+ int i;
+ kiss_twiddle_scalar *trig;
+ int shift;
+ int N2=N>>1;
+ l->n = N;
+ l->maxshift = maxshift;
+ for (i=0;i<=maxshift;i++)
+ {
+ if (i==0)
+ l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0, arch);
+ else
+ l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0], arch);
+#ifndef ENABLE_TI_DSPLIB55
+ if (l->kfft[i]==NULL)
+ return 0;
+#endif
+ }
+ l->trig = trig = (kiss_twiddle_scalar*)opus_alloc((N-(N2>>maxshift))*sizeof(kiss_twiddle_scalar));
+ if (l->trig==NULL)
+ return 0;
+ for (shift=0;shift<=maxshift;shift++)
+ {
+ /* We have enough points that sine isn't necessary */
+#if defined(FIXED_POINT)
+#if 1
+ for (i=0;i<N2;i++)
+ trig[i] = TRIG_UPSCALE*celt_cos_norm(DIV32(ADD32(SHL32(EXTEND32(i),17),N2+16384),N));
+#else
+ for (i=0;i<N2;i++)
+ trig[i] = (kiss_twiddle_scalar)MAX32(-32767,MIN32(32767,floor(.5+32768*cos(2*M_PI*(i+.125)/N))));
+#endif
+#else
+ for (i=0;i<N2;i++)
+ trig[i] = (kiss_twiddle_scalar)cos(2*PI*(i+.125)/N);
+#endif
+ trig += N2;
+ N2 >>= 1;
+ N >>= 1;
+ }
+ return 1;
+}
+
+void clt_mdct_clear(mdct_lookup *l, int arch)
+{
+ int i;
+ for (i=0;i<=l->maxshift;i++)
+ opus_fft_free(l->kfft[i], arch);
+ opus_free((kiss_twiddle_scalar*)l->trig);
+}
+
+#endif /* CUSTOM_MODES */
+
+/* Forward MDCT trashes the input array */
+#ifndef OVERRIDE_clt_mdct_forward
+void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 *window, int overlap, int shift, int stride, int arch)
+{
+ int i;
+ int N, N2, N4;
+ VARDECL(kiss_fft_scalar, f);
+ VARDECL(kiss_fft_cpx, f2);
+ const kiss_fft_state *st = l->kfft[shift];
+ const kiss_twiddle_scalar *trig;
+ opus_val16 scale;
+#ifdef FIXED_POINT
+ /* Allows us to scale with MULT16_32_Q16(), which is faster than
+ MULT16_32_Q15() on ARM. */
+ int scale_shift = st->scale_shift-1;
+#endif
+ SAVE_STACK;
+ (void)arch;
+ scale = st->scale;
+
+ N = l->n;
+ trig = l->trig;
+ for (i=0;i<shift;i++)
+ {
+ N >>= 1;
+ trig += N;
+ }
+ N2 = N>>1;
+ N4 = N>>2;
+
+ ALLOC(f, N2, kiss_fft_scalar);
+ ALLOC(f2, N4, kiss_fft_cpx);
+
+ /* Consider the input to be composed of four blocks: [a, b, c, d] */
+ /* Window, shuffle, fold */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1);
+ const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1);
+ kiss_fft_scalar * OPUS_RESTRICT yp = f;
+ const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1);
+ const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1;
+ for(i=0;i<((overlap+3)>>2);i++)
+ {
+ /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
+ *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2);
+ *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]);
+ xp1+=2;
+ xp2-=2;
+ wp1+=2;
+ wp2-=2;
+ }
+ wp1 = window;
+ wp2 = window+overlap-1;
+ for(;i<N4-((overlap+3)>>2);i++)
+ {
+ /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+ *yp++ = *xp2;
+ *yp++ = *xp1;
+ xp1+=2;
+ xp2-=2;
+ }
+ for(;i<N4;i++)
+ {
+ /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+ *yp++ = -MULT16_32_Q15(*wp1, xp1[-N2]) + MULT16_32_Q15(*wp2, *xp2);
+ *yp++ = MULT16_32_Q15(*wp2, *xp1) + MULT16_32_Q15(*wp1, xp2[N2]);
+ xp1+=2;
+ xp2-=2;
+ wp1+=2;
+ wp2-=2;
+ }
+ }
+ /* Pre-rotation */
+ {
+ kiss_fft_scalar * OPUS_RESTRICT yp = f;
+ const kiss_twiddle_scalar *t = &trig[0];
+ for(i=0;i<N4;i++)
+ {
+ kiss_fft_cpx yc;
+ kiss_twiddle_scalar t0, t1;
+ kiss_fft_scalar re, im, yr, yi;
+ t0 = t[i];
+ t1 = t[N4+i];
+ re = *yp++;
+ im = *yp++;
+ yr = S_MUL(re,t0) - S_MUL(im,t1);
+ yi = S_MUL(im,t0) + S_MUL(re,t1);
+ yc.r = yr;
+ yc.i = yi;
+ yc.r = PSHR32(MULT16_32_Q16(scale, yc.r), scale_shift);
+ yc.i = PSHR32(MULT16_32_Q16(scale, yc.i), scale_shift);
+ f2[st->bitrev[i]] = yc;
+ }
+ }
+
+ /* N/4 complex FFT, does not downscale anymore */
+ opus_fft_impl(st, f2);
+
+ /* Post-rotate */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_cpx * OPUS_RESTRICT fp = f2;
+ kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+ kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1);
+ const kiss_twiddle_scalar *t = &trig[0];
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ for(i=0;i<N4;i++)
+ {
+ kiss_fft_scalar yr, yi;
+ yr = S_MUL(fp->i,t[N4+i]) - S_MUL(fp->r,t[i]);
+ yi = S_MUL(fp->r,t[N4+i]) + S_MUL(fp->i,t[i]);
+ *yp1 = yr;
+ *yp2 = yi;
+ fp++;
+ yp1 += 2*stride;
+ yp2 -= 2*stride;
+ }
+ }
+ RESTORE_STACK;
+}
+#endif /* OVERRIDE_clt_mdct_forward */
+
+#ifndef OVERRIDE_clt_mdct_backward
+void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch)
+{
+ int i;
+ int N, N2, N4;
+ const kiss_twiddle_scalar *trig;
+ (void) arch;
+
+ N = l->n;
+ trig = l->trig;
+ for (i=0;i<shift;i++)
+ {
+ N >>= 1;
+ trig += N;
+ }
+ N2 = N>>1;
+ N4 = N>>2;
+
+ /* Pre-rotate */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_scalar * OPUS_RESTRICT xp1 = in;
+ const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1);
+ kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1);
+ const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0];
+ const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev;
+ for(i=0;i<N4;i++)
+ {
+ int rev;
+ kiss_fft_scalar yr, yi;
+ rev = *bitrev++;
+ yr = S_MUL(*xp2, t[i]) + S_MUL(*xp1, t[N4+i]);
+ yi = S_MUL(*xp1, t[i]) - S_MUL(*xp2, t[N4+i]);
+ /* We swap real and imag because we use an FFT instead of an IFFT. */
+ yp[2*rev+1] = yr;
+ yp[2*rev] = yi;
+ /* Storing the pre-rotation directly in the bitrev order. */
+ xp1+=2*stride;
+ xp2-=2*stride;
+ }
+ }
+
+ opus_fft_impl(l->kfft[shift], (kiss_fft_cpx*)(out+(overlap>>1)));
+
+ /* Post-rotate and de-shuffle from both ends of the buffer at once to make
+ it in-place. */
+ {
+ kiss_fft_scalar * yp0 = out+(overlap>>1);
+ kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2;
+ const kiss_twiddle_scalar *t = &trig[0];
+ /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the
+ middle pair will be computed twice. */
+ for(i=0;i<(N4+1)>>1;i++)
+ {
+ kiss_fft_scalar re, im, yr, yi;
+ kiss_twiddle_scalar t0, t1;
+ /* We swap real and imag because we're using an FFT instead of an IFFT. */
+ re = yp0[1];
+ im = yp0[0];
+ t0 = t[i];
+ t1 = t[N4+i];
+ /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+ yr = S_MUL(re,t0) + S_MUL(im,t1);
+ yi = S_MUL(re,t1) - S_MUL(im,t0);
+ /* We swap real and imag because we're using an FFT instead of an IFFT. */
+ re = yp1[1];
+ im = yp1[0];
+ yp0[0] = yr;
+ yp1[1] = yi;
+
+ t0 = t[(N4-i-1)];
+ t1 = t[(N2-i-1)];
+ /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+ yr = S_MUL(re,t0) + S_MUL(im,t1);
+ yi = S_MUL(re,t1) - S_MUL(im,t0);
+ yp1[0] = yr;
+ yp0[1] = yi;
+ yp0 += 2;
+ yp1 -= 2;
+ }
+ }
+
+ /* Mirror on both sides for TDAC */
+ {
+ kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1;
+ kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+ const opus_val16 * OPUS_RESTRICT wp1 = window;
+ const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1;
+
+ for(i = 0; i < overlap/2; i++)
+ {
+ kiss_fft_scalar x1, x2;
+ x1 = *xp1;
+ x2 = *yp1;
+ *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1);
+ *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1);
+ wp1++;
+ wp2--;
+ }
+ }
+}
+#endif /* OVERRIDE_clt_mdct_backward */
diff --git a/external/opus-1.1.4/celt/mdct.h b/external/opus-1.1.4/celt/mdct.h
new file mode 100644
index 0000000..160ae4e
--- /dev/null
+++ b/external/opus-1.1.4/celt/mdct.h
@@ -0,0 +1,112 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2008 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+/* This is a simple MDCT implementation that uses a N/4 complex FFT
+ to do most of the work. It should be relatively straightforward to
+ plug in pretty much and FFT here.
+
+ This replaces the Vorbis FFT (and uses the exact same API), which
+ was a bit too messy and that was ending up duplicating code
+ (might as well use the same FFT everywhere).
+
+ The algorithm is similar to (and inspired from) Fabrice Bellard's
+ MDCT implementation in FFMPEG, but has differences in signs, ordering
+ and scaling in many places.
+*/
+
+#ifndef MDCT_H
+#define MDCT_H
+
+#include "opus_defines.h"
+#include "kiss_fft.h"
+#include "arch.h"
+
+typedef struct {
+ int n;
+ int maxshift;
+ const kiss_fft_state *kfft[4];
+ const kiss_twiddle_scalar * OPUS_RESTRICT trig;
+} mdct_lookup;
+
+#if defined(HAVE_ARM_NE10)
+#include "arm/mdct_arm.h"
+#endif
+
+
+int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch);
+void clt_mdct_clear(mdct_lookup *l, int arch);
+
+/** Compute a forward MDCT and scale by 4/N, trashes the input array */
+void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 *window, int overlap,
+ int shift, int stride, int arch);
+
+/** Compute a backward MDCT (no scaling) and performs weighted overlap-add
+ (scales implicitly by 1/2) */
+void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 * OPUS_RESTRICT window,
+ int overlap, int shift, int stride, int arch);
+
+#if !defined(OVERRIDE_OPUS_MDCT)
+/* Is run-time CPU detection enabled on this platform? */
+#if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10)
+
+extern void (*const CLT_MDCT_FORWARD_IMPL[OPUS_ARCHMASK+1])(
+ const mdct_lookup *l, kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window,
+ int overlap, int shift, int stride, int arch);
+
+#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \
+ ((*CLT_MDCT_FORWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \
+ _window, _overlap, _shift, \
+ _stride, _arch))
+
+extern void (*const CLT_MDCT_BACKWARD_IMPL[OPUS_ARCHMASK+1])(
+ const mdct_lookup *l, kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window,
+ int overlap, int shift, int stride, int arch);
+
+#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \
+ (*CLT_MDCT_BACKWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \
+ _window, _overlap, _shift, \
+ _stride, _arch)
+
+#else /* if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) */
+
+#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \
+ clt_mdct_forward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch)
+
+#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \
+ clt_mdct_backward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch)
+
+#endif /* end if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) && !defined(FIXED_POINT) */
+#endif /* end if !defined(OVERRIDE_OPUS_MDCT) */
+
+#endif
diff --git a/external/opus-1.1.4/celt/mfrngcod.h b/external/opus-1.1.4/celt/mfrngcod.h
new file mode 100644
index 0000000..809152a
--- /dev/null
+++ b/external/opus-1.1.4/celt/mfrngcod.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2001-2008 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#if !defined(_mfrngcode_H)
+# define _mfrngcode_H (1)
+# include "entcode.h"
+
+/*Constants used by the entropy encoder/decoder.*/
+
+/*The number of bits to output at a time.*/
+# define EC_SYM_BITS (8)
+/*The total number of bits in each of the state registers.*/
+# define EC_CODE_BITS (32)
+/*The maximum symbol value.*/
+# define EC_SYM_MAX ((1U<<EC_SYM_BITS)-1)
+/*Bits to shift by to move a symbol into the high-order position.*/
+# define EC_CODE_SHIFT (EC_CODE_BITS-EC_SYM_BITS-1)
+/*Carry bit of the high-order range symbol.*/
+# define EC_CODE_TOP (((opus_uint32)1U)<<(EC_CODE_BITS-1))
+/*Low-order bit of the high-order range symbol.*/
+# define EC_CODE_BOT (EC_CODE_TOP>>EC_SYM_BITS)
+/*The number of bits available for the last, partial symbol in the code field.*/
+# define EC_CODE_EXTRA ((EC_CODE_BITS-2)%EC_SYM_BITS+1)
+#endif
diff --git a/external/opus-1.1.4/celt/mips/celt_mipsr1.h b/external/opus-1.1.4/celt/mips/celt_mipsr1.h
new file mode 100644
index 0000000..e85661a
--- /dev/null
+++ b/external/opus-1.1.4/celt/mips/celt_mipsr1.h
@@ -0,0 +1,151 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2010 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef __CELT_MIPSR1_H__
+#define __CELT_MIPSR1_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CELT_C
+
+#include "os_support.h"
+#include "mdct.h"
+#include <math.h>
+#include "celt.h"
+#include "pitch.h"
+#include "bands.h"
+#include "modes.h"
+#include "entcode.h"
+#include "quant_bands.h"
+#include "rate.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "float_cast.h"
+#include <stdarg.h>
+#include "celt_lpc.h"
+#include "vq.h"
+
+#define OVERRIDE_comb_filter
+void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
+ opus_val16 g0, opus_val16 g1, int tapset0, int tapset1,
+ const opus_val16 *window, int overlap, int arch)
+{
+ int i;
+ opus_val32 x0, x1, x2, x3, x4;
+
+ (void)arch;
+
+ /* printf ("%d %d %f %f\n", T0, T1, g0, g1); */
+ opus_val16 g00, g01, g02, g10, g11, g12;
+ static const opus_val16 gains[3][3] = {
+ {QCONST16(0.3066406250f, 15), QCONST16(0.2170410156f, 15), QCONST16(0.1296386719f, 15)},
+ {QCONST16(0.4638671875f, 15), QCONST16(0.2680664062f, 15), QCONST16(0.f, 15)},
+ {QCONST16(0.7998046875f, 15), QCONST16(0.1000976562f, 15), QCONST16(0.f, 15)}};
+
+ if (g0==0 && g1==0)
+ {
+ /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+ if (x!=y)
+ OPUS_MOVE(y, x, N);
+ return;
+ }
+
+ g00 = MULT16_16_P15(g0, gains[tapset0][0]);
+ g01 = MULT16_16_P15(g0, gains[tapset0][1]);
+ g02 = MULT16_16_P15(g0, gains[tapset0][2]);
+ g10 = MULT16_16_P15(g1, gains[tapset1][0]);
+ g11 = MULT16_16_P15(g1, gains[tapset1][1]);
+ g12 = MULT16_16_P15(g1, gains[tapset1][2]);
+ x1 = x[-T1+1];
+ x2 = x[-T1 ];
+ x3 = x[-T1-1];
+ x4 = x[-T1-2];
+ /* If the filter didn't change, we don't need the overlap */
+ if (g0==g1 && T0==T1 && tapset0==tapset1)
+ overlap=0;
+
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 f;
+ opus_val32 res;
+ f = MULT16_16_Q15(window[i],window[i]);
+ x0= x[i-T1+2];
+
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15((Q15ONE-f),g00)), "r" ((int)x[i-T0]));
+
+ asm volatile("MADD $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15((Q15ONE-f),g01)), "r" ((int)ADD32(x[i-T0-1],x[i-T0+1])));
+ asm volatile("MADD $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15((Q15ONE-f),g02)), "r" ((int)ADD32(x[i-T0-2],x[i-T0+2])));
+ asm volatile("MADD $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15(f,g10)), "r" ((int)x2));
+ asm volatile("MADD $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15(f,g11)), "r" ((int)ADD32(x3,x1)));
+ asm volatile("MADD $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15(f,g12)), "r" ((int)ADD32(x4,x0)));
+
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (res): "i" (15));
+
+ y[i] = x[i] + res;
+
+ x4=x3;
+ x3=x2;
+ x2=x1;
+ x1=x0;
+ }
+
+ x4 = x[i-T1-2];
+ x3 = x[i-T1-1];
+ x2 = x[i-T1];
+ x1 = x[i-T1+1];
+
+ if (g1==0)
+ {
+ /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+ if (x!=y)
+ OPUS_MOVE(y+overlap, x+overlap, N-overlap);
+ return;
+ }
+
+ for (i=overlap;i<N;i++)
+ {
+ opus_val32 res;
+ x0=x[i-T1+2];
+
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)g10), "r" ((int)x2));
+
+ asm volatile("MADD $ac1, %0, %1" : : "r" ((int)g11), "r" ((int)ADD32(x3,x1)));
+ asm volatile("MADD $ac1, %0, %1" : : "r" ((int)g12), "r" ((int)ADD32(x4,x0)));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (res): "i" (15));
+ y[i] = x[i] + res;
+ x4=x3;
+ x3=x2;
+ x2=x1;
+ x1=x0;
+ }
+}
+
+#endif /* __CELT_MIPSR1_H__ */
diff --git a/external/opus-1.1.4/celt/mips/fixed_generic_mipsr1.h b/external/opus-1.1.4/celt/mips/fixed_generic_mipsr1.h
new file mode 100644
index 0000000..4a05efb
--- /dev/null
+++ b/external/opus-1.1.4/celt/mips/fixed_generic_mipsr1.h
@@ -0,0 +1,126 @@
+/* Copyright (C) 2007-2009 Xiph.Org Foundation
+ Copyright (C) 2003-2008 Jean-Marc Valin
+ Copyright (C) 2007-2008 CSIRO */
+/**
+ @file fixed_generic.h
+ @brief Generic fixed-point operations
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef CELT_FIXED_GENERIC_MIPSR1_H
+#define CELT_FIXED_GENERIC_MIPSR1_H
+
+#undef MULT16_32_Q15_ADD
+static inline int MULT16_32_Q15_ADD(int a, int b, int c, int d) {
+ int m;
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+ asm volatile("madd $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+ return m;
+}
+
+#undef MULT16_32_Q15_SUB
+static inline int MULT16_32_Q15_SUB(int a, int b, int c, int d) {
+ int m;
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+ asm volatile("msub $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+ return m;
+}
+
+#undef MULT16_16_Q15_ADD
+static inline int MULT16_16_Q15_ADD(int a, int b, int c, int d) {
+ int m;
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+ asm volatile("madd $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+ return m;
+}
+
+#undef MULT16_16_Q15_SUB
+static inline int MULT16_16_Q15_SUB(int a, int b, int c, int d) {
+ int m;
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+ asm volatile("msub $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+ return m;
+}
+
+
+#undef MULT16_32_Q16
+static inline int MULT16_32_Q16(int a, int b)
+{
+ int c;
+ asm volatile("MULT $ac1,%0, %1" : : "r" (a), "r" (b));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (c): "i" (16));
+ return c;
+}
+
+#undef MULT16_32_P16
+static inline int MULT16_32_P16(int a, int b)
+{
+ int c;
+ asm volatile("MULT $ac1, %0, %1" : : "r" (a), "r" (b));
+ asm volatile("EXTR_R.W %0,$ac1, %1" : "=r" (c): "i" (16));
+ return c;
+}
+
+#undef MULT16_32_Q15
+static inline int MULT16_32_Q15(int a, int b)
+{
+ int c;
+ asm volatile("MULT $ac1, %0, %1" : : "r" (a), "r" (b));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (c): "i" (15));
+ return c;
+}
+
+#undef MULT32_32_Q31
+static inline int MULT32_32_Q31(int a, int b)
+{
+ int r;
+ asm volatile("MULT $ac1, %0, %1" : : "r" (a), "r" (b));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (r): "i" (31));
+ return r;
+}
+
+#undef PSHR32
+static inline int PSHR32(int a, int shift)
+{
+ int r;
+ asm volatile ("SHRAV_R.W %0, %1, %2" :"=r" (r): "r" (a), "r" (shift));
+ return r;
+}
+
+#undef MULT16_16_P15
+static inline int MULT16_16_P15(int a, int b)
+{
+ int r;
+ asm volatile ("mul %0, %1, %2" :"=r" (r): "r" (a), "r" (b));
+ asm volatile ("SHRA_R.W %0, %1, %2" : "+r" (r): "0" (r), "i"(15));
+ return r;
+}
+
+#endif /* CELT_FIXED_GENERIC_MIPSR1_H */
diff --git a/external/opus-1.1.4/celt/mips/kiss_fft_mipsr1.h b/external/opus-1.1.4/celt/mips/kiss_fft_mipsr1.h
new file mode 100644
index 0000000..400ca4d
--- /dev/null
+++ b/external/opus-1.1.4/celt/mips/kiss_fft_mipsr1.h
@@ -0,0 +1,167 @@
+/*Copyright (c) 2013, Xiph.Org Foundation and contributors.
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.*/
+
+#ifndef KISS_FFT_MIPSR1_H
+#define KISS_FFT_MIPSR1_H
+
+#if !defined(KISS_FFT_GUTS_H)
+#error "This file should only be included from _kiss_fft_guts.h"
+#endif
+
+#ifdef FIXED_POINT
+
+#define S_MUL_ADD(a, b, c, d) (S_MUL(a,b)+S_MUL(c,d))
+#define S_MUL_SUB(a, b, c, d) (S_MUL(a,b)-S_MUL(c,d))
+
+#undef S_MUL_ADD
+static inline int S_MUL_ADD(int a, int b, int c, int d) {
+ int m;
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+ asm volatile("madd $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+ return m;
+}
+
+#undef S_MUL_SUB
+static inline int S_MUL_SUB(int a, int b, int c, int d) {
+ int m;
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+ asm volatile("msub $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+ return m;
+}
+
+#undef C_MUL
+# define C_MUL(m,a,b) (m=C_MUL_fun(a,b))
+static inline kiss_fft_cpx C_MUL_fun(kiss_fft_cpx a, kiss_twiddle_cpx b) {
+ kiss_fft_cpx m;
+
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a.r), "r" ((int)b.r));
+ asm volatile("msub $ac1, %0, %1" : : "r" ((int)a.i), "r" ((int)b.i));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m.r): "i" (15));
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a.r), "r" ((int)b.i));
+ asm volatile("madd $ac1, %0, %1" : : "r" ((int)a.i), "r" ((int)b.r));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m.i): "i" (15));
+
+ return m;
+}
+#undef C_MULC
+# define C_MULC(m,a,b) (m=C_MULC_fun(a,b))
+static inline kiss_fft_cpx C_MULC_fun(kiss_fft_cpx a, kiss_twiddle_cpx b) {
+ kiss_fft_cpx m;
+
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a.r), "r" ((int)b.r));
+ asm volatile("madd $ac1, %0, %1" : : "r" ((int)a.i), "r" ((int)b.i));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m.r): "i" (15));
+ asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a.i), "r" ((int)b.r));
+ asm volatile("msub $ac1, %0, %1" : : "r" ((int)a.r), "r" ((int)b.i));
+ asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m.i): "i" (15));
+
+ return m;
+}
+
+#endif /* FIXED_POINT */
+
+#define OVERRIDE_kf_bfly5
+static void kf_bfly5(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
+ int i, u;
+ kiss_fft_cpx scratch[13];
+
+ const kiss_twiddle_cpx *tw;
+ kiss_twiddle_cpx ya,yb;
+ kiss_fft_cpx * Fout_beg = Fout;
+
+#ifdef FIXED_POINT
+ ya.r = 10126;
+ ya.i = -31164;
+ yb.r = -26510;
+ yb.i = -19261;
+#else
+ ya = st->twiddles[fstride*m];
+ yb = st->twiddles[fstride*2*m];
+#endif
+
+ tw=st->twiddles;
+
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ Fout0=Fout;
+ Fout1=Fout0+m;
+ Fout2=Fout0+2*m;
+ Fout3=Fout0+3*m;
+ Fout4=Fout0+4*m;
+
+ /* For non-custom modes, m is guaranteed to be a multiple of 4. */
+ for ( u=0; u<m; ++u ) {
+ scratch[0] = *Fout0;
+
+
+ C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
+ C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
+ C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
+ C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
+
+ C_ADD( scratch[7],scratch[1],scratch[4]);
+ C_SUB( scratch[10],scratch[1],scratch[4]);
+ C_ADD( scratch[8],scratch[2],scratch[3]);
+ C_SUB( scratch[9],scratch[2],scratch[3]);
+
+ Fout0->r += scratch[7].r + scratch[8].r;
+ Fout0->i += scratch[7].i + scratch[8].i;
+ scratch[5].r = scratch[0].r + S_MUL_ADD(scratch[7].r,ya.r,scratch[8].r,yb.r);
+ scratch[5].i = scratch[0].i + S_MUL_ADD(scratch[7].i,ya.r,scratch[8].i,yb.r);
+
+ scratch[6].r = S_MUL_ADD(scratch[10].i,ya.i,scratch[9].i,yb.i);
+ scratch[6].i = -S_MUL_ADD(scratch[10].r,ya.i,scratch[9].r,yb.i);
+
+ C_SUB(*Fout1,scratch[5],scratch[6]);
+ C_ADD(*Fout4,scratch[5],scratch[6]);
+
+ scratch[11].r = scratch[0].r + S_MUL_ADD(scratch[7].r,yb.r,scratch[8].r,ya.r);
+ scratch[11].i = scratch[0].i + S_MUL_ADD(scratch[7].i,yb.r,scratch[8].i,ya.r);
+
+ scratch[12].r = S_MUL_SUB(scratch[9].i,ya.i,scratch[10].i,yb.i);
+ scratch[12].i = S_MUL_SUB(scratch[10].r,yb.i,scratch[9].r,ya.i);
+
+ C_ADD(*Fout2,scratch[11],scratch[12]);
+ C_SUB(*Fout3,scratch[11],scratch[12]);
+
+ ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
+ }
+ }
+}
+
+
+#endif /* KISS_FFT_MIPSR1_H */
diff --git a/external/opus-1.1.4/celt/mips/mdct_mipsr1.h b/external/opus-1.1.4/celt/mips/mdct_mipsr1.h
new file mode 100644
index 0000000..2934dab
--- /dev/null
+++ b/external/opus-1.1.4/celt/mips/mdct_mipsr1.h
@@ -0,0 +1,288 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2008 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+/* This is a simple MDCT implementation that uses a N/4 complex FFT
+ to do most of the work. It should be relatively straightforward to
+ plug in pretty much and FFT here.
+
+ This replaces the Vorbis FFT (and uses the exact same API), which
+ was a bit too messy and that was ending up duplicating code
+ (might as well use the same FFT everywhere).
+
+ The algorithm is similar to (and inspired from) Fabrice Bellard's
+ MDCT implementation in FFMPEG, but has differences in signs, ordering
+ and scaling in many places.
+*/
+#ifndef __MDCT_MIPSR1_H__
+#define __MDCT_MIPSR1_H__
+
+#ifndef SKIP_CONFIG_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#endif
+
+#include "mdct.h"
+#include "kiss_fft.h"
+#include "_kiss_fft_guts.h"
+#include <math.h>
+#include "os_support.h"
+#include "mathops.h"
+#include "stack_alloc.h"
+
+/* Forward MDCT trashes the input array */
+#define OVERRIDE_clt_mdct_forward
+void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 *window, int overlap, int shift, int stride, int arch)
+{
+ int i;
+ int N, N2, N4;
+ VARDECL(kiss_fft_scalar, f);
+ VARDECL(kiss_fft_cpx, f2);
+ const kiss_fft_state *st = l->kfft[shift];
+ const kiss_twiddle_scalar *trig;
+ opus_val16 scale;
+#ifdef FIXED_POINT
+ /* Allows us to scale with MULT16_32_Q16(), which is faster than
+ MULT16_32_Q15() on ARM. */
+ int scale_shift = st->scale_shift-1;
+#endif
+
+ (void)arch;
+
+ SAVE_STACK;
+ scale = st->scale;
+
+ N = l->n;
+ trig = l->trig;
+ for (i=0;i<shift;i++)
+ {
+ N >>= 1;
+ trig += N;
+ }
+ N2 = N>>1;
+ N4 = N>>2;
+
+ ALLOC(f, N2, kiss_fft_scalar);
+ ALLOC(f2, N4, kiss_fft_cpx);
+
+ /* Consider the input to be composed of four blocks: [a, b, c, d] */
+ /* Window, shuffle, fold */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1);
+ const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1);
+ kiss_fft_scalar * OPUS_RESTRICT yp = f;
+ const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1);
+ const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1;
+ for(i=0;i<((overlap+3)>>2);i++)
+ {
+ /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
+ *yp++ = S_MUL_ADD(*wp2, xp1[N2],*wp1,*xp2);
+ *yp++ = S_MUL_SUB(*wp1, *xp1,*wp2, xp2[-N2]);
+ xp1+=2;
+ xp2-=2;
+ wp1+=2;
+ wp2-=2;
+ }
+ wp1 = window;
+ wp2 = window+overlap-1;
+ for(;i<N4-((overlap+3)>>2);i++)
+ {
+ /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+ *yp++ = *xp2;
+ *yp++ = *xp1;
+ xp1+=2;
+ xp2-=2;
+ }
+ for(;i<N4;i++)
+ {
+ /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+ *yp++ = S_MUL_SUB(*wp2, *xp2, *wp1, xp1[-N2]);
+ *yp++ = S_MUL_ADD(*wp2, *xp1, *wp1, xp2[N2]);
+ xp1+=2;
+ xp2-=2;
+ wp1+=2;
+ wp2-=2;
+ }
+ }
+ /* Pre-rotation */
+ {
+ kiss_fft_scalar * OPUS_RESTRICT yp = f;
+ const kiss_twiddle_scalar *t = &trig[0];
+ for(i=0;i<N4;i++)
+ {
+ kiss_fft_cpx yc;
+ kiss_twiddle_scalar t0, t1;
+ kiss_fft_scalar re, im, yr, yi;
+ t0 = t[i];
+ t1 = t[N4+i];
+ re = *yp++;
+ im = *yp++;
+
+ yr = S_MUL_SUB(re,t0,im,t1);
+ yi = S_MUL_ADD(im,t0,re,t1);
+
+ yc.r = yr;
+ yc.i = yi;
+ yc.r = PSHR32(MULT16_32_Q16(scale, yc.r), scale_shift);
+ yc.i = PSHR32(MULT16_32_Q16(scale, yc.i), scale_shift);
+ f2[st->bitrev[i]] = yc;
+ }
+ }
+
+ /* N/4 complex FFT, does not downscale anymore */
+ opus_fft_impl(st, f2);
+
+ /* Post-rotate */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_cpx * OPUS_RESTRICT fp = f2;
+ kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+ kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1);
+ const kiss_twiddle_scalar *t = &trig[0];
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ for(i=0;i<N4;i++)
+ {
+ kiss_fft_scalar yr, yi;
+ yr = S_MUL_SUB(fp->i,t[N4+i] , fp->r,t[i]);
+ yi = S_MUL_ADD(fp->r,t[N4+i] ,fp->i,t[i]);
+ *yp1 = yr;
+ *yp2 = yi;
+ fp++;
+ yp1 += 2*stride;
+ yp2 -= 2*stride;
+ }
+ }
+ RESTORE_STACK;
+}
+
+#define OVERRIDE_clt_mdct_backward
+void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch)
+{
+ int i;
+ int N, N2, N4;
+ const kiss_twiddle_scalar *trig;
+
+ (void)arch;
+
+ N = l->n;
+ trig = l->trig;
+ for (i=0;i<shift;i++)
+ {
+ N >>= 1;
+ trig += N;
+ }
+ N2 = N>>1;
+ N4 = N>>2;
+
+ /* Pre-rotate */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_scalar * OPUS_RESTRICT xp1 = in;
+ const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1);
+ kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1);
+ const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0];
+ const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev;
+ for(i=0;i<N4;i++)
+ {
+ int rev;
+ kiss_fft_scalar yr, yi;
+ rev = *bitrev++;
+ yr = S_MUL_ADD(*xp2, t[i] , *xp1, t[N4+i]);
+ yi = S_MUL_SUB(*xp1, t[i] , *xp2, t[N4+i]);
+ /* We swap real and imag because we use an FFT instead of an IFFT. */
+ yp[2*rev+1] = yr;
+ yp[2*rev] = yi;
+ /* Storing the pre-rotation directly in the bitrev order. */
+ xp1+=2*stride;
+ xp2-=2*stride;
+ }
+ }
+
+ opus_fft_impl(l->kfft[shift], (kiss_fft_cpx*)(out+(overlap>>1)));
+
+ /* Post-rotate and de-shuffle from both ends of the buffer at once to make
+ it in-place. */
+ {
+ kiss_fft_scalar * OPUS_RESTRICT yp0 = out+(overlap>>1);
+ kiss_fft_scalar * OPUS_RESTRICT yp1 = out+(overlap>>1)+N2-2;
+ const kiss_twiddle_scalar *t = &trig[0];
+ /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the
+ middle pair will be computed twice. */
+ for(i=0;i<(N4+1)>>1;i++)
+ {
+ kiss_fft_scalar re, im, yr, yi;
+ kiss_twiddle_scalar t0, t1;
+ /* We swap real and imag because we're using an FFT instead of an IFFT. */
+ re = yp0[1];
+ im = yp0[0];
+ t0 = t[i];
+ t1 = t[N4+i];
+ /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+ yr = S_MUL_ADD(re,t0 , im,t1);
+ yi = S_MUL_SUB(re,t1 , im,t0);
+ /* We swap real and imag because we're using an FFT instead of an IFFT. */
+ re = yp1[1];
+ im = yp1[0];
+ yp0[0] = yr;
+ yp1[1] = yi;
+
+ t0 = t[(N4-i-1)];
+ t1 = t[(N2-i-1)];
+ /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+ yr = S_MUL_ADD(re,t0,im,t1);
+ yi = S_MUL_SUB(re,t1,im,t0);
+ yp1[0] = yr;
+ yp0[1] = yi;
+ yp0 += 2;
+ yp1 -= 2;
+ }
+ }
+
+ /* Mirror on both sides for TDAC */
+ {
+ kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1;
+ kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+ const opus_val16 * OPUS_RESTRICT wp1 = window;
+ const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1;
+
+ for(i = 0; i < overlap/2; i++)
+ {
+ kiss_fft_scalar x1, x2;
+ x1 = *xp1;
+ x2 = *yp1;
+ *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1);
+ *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1);
+ wp1++;
+ wp2--;
+ }
+ }
+}
+#endif /* __MDCT_MIPSR1_H__ */
diff --git a/external/opus-1.1.4/celt/mips/pitch_mipsr1.h b/external/opus-1.1.4/celt/mips/pitch_mipsr1.h
new file mode 100644
index 0000000..a9500af
--- /dev/null
+++ b/external/opus-1.1.4/celt/mips/pitch_mipsr1.h
@@ -0,0 +1,161 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file pitch.h
+ @brief Pitch analysis
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef PITCH_MIPSR1_H
+#define PITCH_MIPSR1_H
+
+#define OVERRIDE_DUAL_INNER_PROD
+static inline void dual_inner_prod(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
+ int N, opus_val32 *xy1, opus_val32 *xy2, int arch)
+{
+ int j;
+ opus_val32 xy01=0;
+ opus_val32 xy02=0;
+
+ (void)arch;
+
+ asm volatile("MULT $ac1, $0, $0");
+ asm volatile("MULT $ac2, $0, $0");
+ /* Compute the norm of X+Y and X-Y as |X|^2 + |Y|^2 +/- sum(xy) */
+ for (j=0;j<N;j++)
+ {
+ asm volatile("MADD $ac1, %0, %1" : : "r" ((int)x[j]), "r" ((int)y01[j]));
+ asm volatile("MADD $ac2, %0, %1" : : "r" ((int)x[j]), "r" ((int)y02[j]));
+ ++j;
+ asm volatile("MADD $ac1, %0, %1" : : "r" ((int)x[j]), "r" ((int)y01[j]));
+ asm volatile("MADD $ac2, %0, %1" : : "r" ((int)x[j]), "r" ((int)y02[j]));
+ }
+ asm volatile ("mflo %0, $ac1": "=r"(xy01));
+ asm volatile ("mflo %0, $ac2": "=r"(xy02));
+ *xy1 = xy01;
+ *xy2 = xy02;
+}
+
+static inline void xcorr_kernel_mips(const opus_val16 * x,
+ const opus_val16 * y, opus_val32 sum[4], int len)
+{
+ int j;
+ opus_val16 y_0, y_1, y_2, y_3;
+
+ opus_int64 sum_0, sum_1, sum_2, sum_3;
+ sum_0 = (opus_int64)sum[0];
+ sum_1 = (opus_int64)sum[1];
+ sum_2 = (opus_int64)sum[2];
+ sum_3 = (opus_int64)sum[3];
+
+ y_3=0; /* gcc doesn't realize that y_3 can't be used uninitialized */
+ y_0=*y++;
+ y_1=*y++;
+ y_2=*y++;
+ for (j=0;j<len-3;j+=4)
+ {
+ opus_val16 tmp;
+ tmp = *x++;
+ y_3=*y++;
+
+ sum_0 = __builtin_mips_madd( sum_0, tmp, y_0);
+ sum_1 = __builtin_mips_madd( sum_1, tmp, y_1);
+ sum_2 = __builtin_mips_madd( sum_2, tmp, y_2);
+ sum_3 = __builtin_mips_madd( sum_3, tmp, y_3);
+
+ tmp=*x++;
+ y_0=*y++;
+
+ sum_0 = __builtin_mips_madd( sum_0, tmp, y_1 );
+ sum_1 = __builtin_mips_madd( sum_1, tmp, y_2 );
+ sum_2 = __builtin_mips_madd( sum_2, tmp, y_3);
+ sum_3 = __builtin_mips_madd( sum_3, tmp, y_0);
+
+ tmp=*x++;
+ y_1=*y++;
+
+ sum_0 = __builtin_mips_madd( sum_0, tmp, y_2 );
+ sum_1 = __builtin_mips_madd( sum_1, tmp, y_3 );
+ sum_2 = __builtin_mips_madd( sum_2, tmp, y_0);
+ sum_3 = __builtin_mips_madd( sum_3, tmp, y_1);
+
+
+ tmp=*x++;
+ y_2=*y++;
+
+ sum_0 = __builtin_mips_madd( sum_0, tmp, y_3 );
+ sum_1 = __builtin_mips_madd( sum_1, tmp, y_0 );
+ sum_2 = __builtin_mips_madd( sum_2, tmp, y_1);
+ sum_3 = __builtin_mips_madd( sum_3, tmp, y_2);
+
+ }
+ if (j++<len)
+ {
+ opus_val16 tmp = *x++;
+ y_3=*y++;
+
+ sum_0 = __builtin_mips_madd( sum_0, tmp, y_0 );
+ sum_1 = __builtin_mips_madd( sum_1, tmp, y_1 );
+ sum_2 = __builtin_mips_madd( sum_2, tmp, y_2);
+ sum_3 = __builtin_mips_madd( sum_3, tmp, y_3);
+ }
+
+ if (j++<len)
+ {
+ opus_val16 tmp=*x++;
+ y_0=*y++;
+
+ sum_0 = __builtin_mips_madd( sum_0, tmp, y_1 );
+ sum_1 = __builtin_mips_madd( sum_1, tmp, y_2 );
+ sum_2 = __builtin_mips_madd( sum_2, tmp, y_3);
+ sum_3 = __builtin_mips_madd( sum_3, tmp, y_0);
+ }
+
+ if (j<len)
+ {
+ opus_val16 tmp=*x++;
+ y_1=*y++;
+
+ sum_0 = __builtin_mips_madd( sum_0, tmp, y_2 );
+ sum_1 = __builtin_mips_madd( sum_1, tmp, y_3 );
+ sum_2 = __builtin_mips_madd( sum_2, tmp, y_0);
+ sum_3 = __builtin_mips_madd( sum_3, tmp, y_1);
+
+ }
+
+ sum[0] = (opus_val32)sum_0;
+ sum[1] = (opus_val32)sum_1;
+ sum[2] = (opus_val32)sum_2;
+ sum[3] = (opus_val32)sum_3;
+}
+
+#define OVERRIDE_XCORR_KERNEL
+#define xcorr_kernel(x, y, sum, len, arch) \
+ ((void)(arch), xcorr_kernel_mips(x, y, sum, len))
+
+#endif /* PITCH_MIPSR1_H */
diff --git a/external/opus-1.1.4/celt/mips/vq_mipsr1.h b/external/opus-1.1.4/celt/mips/vq_mipsr1.h
new file mode 100644
index 0000000..54cef86
--- /dev/null
+++ b/external/opus-1.1.4/celt/mips/vq_mipsr1.h
@@ -0,0 +1,125 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef __VQ_MIPSR1_H__
+#define __VQ_MIPSR1_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mathops.h"
+#include "arch.h"
+
+static unsigned extract_collapse_mask(int *iy, int N, int B);
+static void normalise_residual(int * OPUS_RESTRICT iy, celt_norm * OPUS_RESTRICT X, int N, opus_val32 Ryy, opus_val16 gain);
+static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread);
+static void renormalise_vector_mips(celt_norm *X, int N, opus_val16 gain, int arch);
+
+#define OVERRIDE_vq_exp_rotation1
+static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s)
+{
+ int i;
+ opus_val16 ms;
+ celt_norm *Xptr;
+ Xptr = X;
+ ms = NEG16(s);
+ for (i=0;i<len-stride;i++)
+ {
+ celt_norm x1, x2;
+ x1 = Xptr[0];
+ x2 = Xptr[stride];
+ Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15));
+ *Xptr++ = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15));
+ }
+ Xptr = &X[len-2*stride-1];
+ for (i=len-2*stride-1;i>=0;i--)
+ {
+ celt_norm x1, x2;
+ x1 = Xptr[0];
+ x2 = Xptr[stride];
+ Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15));
+ *Xptr-- = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15));
+ }
+}
+
+#define OVERRIDE_renormalise_vector
+
+#define renormalise_vector(X, N, gain, arch) \
+ (renormalise_vector_mips(X, N, gain, arch))
+
+void renormalise_vector_mips(celt_norm *X, int N, opus_val16 gain, int arch)
+{
+ int i;
+#ifdef FIXED_POINT
+ int k;
+#endif
+ opus_val32 E = EPSILON;
+ opus_val16 g;
+ opus_val32 t;
+ celt_norm *xptr = X;
+ int X0, X1;
+
+ (void)arch;
+
+ asm volatile("mult $ac1, $0, $0");
+ asm volatile("MTLO %0, $ac1" : :"r" (E));
+ /*if(N %4)
+ printf("error");*/
+ for (i=0;i<N-2;i+=2)
+ {
+ X0 = (int)*xptr++;
+ asm volatile("MADD $ac1, %0, %1" : : "r" (X0), "r" (X0));
+
+ X1 = (int)*xptr++;
+ asm volatile("MADD $ac1, %0, %1" : : "r" (X1), "r" (X1));
+ }
+
+ for (;i<N;i++)
+ {
+ X0 = (int)*xptr++;
+ asm volatile("MADD $ac1, %0, %1" : : "r" (X0), "r" (X0));
+ }
+
+ asm volatile("MFLO %0, $ac1" : "=r" (E));
+#ifdef FIXED_POINT
+ k = celt_ilog2(E)>>1;
+#endif
+ t = VSHR32(E, 2*(k-7));
+ g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
+
+ xptr = X;
+ for (i=0;i<N;i++)
+ {
+ *xptr = EXTRACT16(PSHR32(MULT16_16(g, *xptr), k+1));
+ xptr++;
+ }
+ /*return celt_sqrt(E);*/
+}
+
+#endif /* __VQ_MIPSR1_H__ */
diff --git a/external/opus-1.1.4/celt/modes.c b/external/opus-1.1.4/celt/modes.c
new file mode 100644
index 0000000..911686e
--- /dev/null
+++ b/external/opus-1.1.4/celt/modes.c
@@ -0,0 +1,442 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "celt.h"
+#include "modes.h"
+#include "rate.h"
+#include "os_support.h"
+#include "stack_alloc.h"
+#include "quant_bands.h"
+#include "cpu_support.h"
+
+static const opus_int16 eband5ms[] = {
+/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100
+};
+
+/* Alternate tuning (partially derived from Vorbis) */
+#define BITALLOC_SIZE 11
+/* Bit allocation table in units of 1/32 bit/sample (0.1875 dB SNR) */
+static const unsigned char band_allocation[] = {
+/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10, 0, 0, 0, 0, 0, 0, 0, 0,
+110,100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12, 0, 0, 0, 0, 0, 0,
+118,110,103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15, 4, 0, 0, 0, 0,
+126,119,112,104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12, 1, 0, 0,
+134,127,120,114,103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10, 1,
+144,137,130,124,113,107,101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15, 1,
+152,145,138,132,123,117,111,105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20, 1,
+162,155,148,142,133,127,121,115,108,102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30, 1,
+172,165,158,152,143,137,131,125,118,112,106,100, 94, 87, 81, 75, 69, 63, 56, 45, 20,
+200,200,200,200,200,200,200,200,198,193,188,183,178,173,168,163,158,153,148,129,104,
+};
+
+#ifndef CUSTOM_MODES_ONLY
+ #ifdef FIXED_POINT
+ #include "static_modes_fixed.h"
+ #else
+ #include "static_modes_float.h"
+ #endif
+#endif /* CUSTOM_MODES_ONLY */
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+#ifdef CUSTOM_MODES
+
+/* Defining 25 critical bands for the full 0-20 kHz audio bandwidth
+ Taken from http://ccrma.stanford.edu/~jos/bbt/Bark_Frequency_Scale.html */
+#define BARK_BANDS 25
+static const opus_int16 bark_freq[BARK_BANDS+1] = {
+ 0, 100, 200, 300, 400,
+ 510, 630, 770, 920, 1080,
+ 1270, 1480, 1720, 2000, 2320,
+ 2700, 3150, 3700, 4400, 5300,
+ 6400, 7700, 9500, 12000, 15500,
+ 20000};
+
+static opus_int16 *compute_ebands(opus_int32 Fs, int frame_size, int res, int *nbEBands)
+{
+ opus_int16 *eBands;
+ int i, j, lin, low, high, nBark, offset=0;
+
+ /* All modes that have 2.5 ms short blocks use the same definition */
+ if (Fs == 400*(opus_int32)frame_size)
+ {
+ *nbEBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1;
+ eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+1));
+ for (i=0;i<*nbEBands+1;i++)
+ eBands[i] = eband5ms[i];
+ return eBands;
+ }
+ /* Find the number of critical bands supported by our sampling rate */
+ for (nBark=1;nBark<BARK_BANDS;nBark++)
+ if (bark_freq[nBark+1]*2 >= Fs)
+ break;
+
+ /* Find where the linear part ends (i.e. where the spacing is more than min_width */
+ for (lin=0;lin<nBark;lin++)
+ if (bark_freq[lin+1]-bark_freq[lin] >= res)
+ break;
+
+ low = (bark_freq[lin]+res/2)/res;
+ high = nBark-lin;
+ *nbEBands = low+high;
+ eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+2));
+
+ if (eBands==NULL)
+ return NULL;
+
+ /* Linear spacing (min_width) */
+ for (i=0;i<low;i++)
+ eBands[i] = i;
+ if (low>0)
+ offset = eBands[low-1]*res - bark_freq[lin-1];
+ /* Spacing follows critical bands */
+ for (i=0;i<high;i++)
+ {
+ int target = bark_freq[lin+i];
+ /* Round to an even value */
+ eBands[i+low] = (target+offset/2+res)/(2*res)*2;
+ offset = eBands[i+low]*res - target;
+ }
+ /* Enforce the minimum spacing at the boundary */
+ for (i=0;i<*nbEBands;i++)
+ if (eBands[i] < i)
+ eBands[i] = i;
+ /* Round to an even value */
+ eBands[*nbEBands] = (bark_freq[nBark]+res)/(2*res)*2;
+ if (eBands[*nbEBands] > frame_size)
+ eBands[*nbEBands] = frame_size;
+ for (i=1;i<*nbEBands-1;i++)
+ {
+ if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1])
+ {
+ eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2;
+ }
+ }
+ /* Remove any empty bands. */
+ for (i=j=0;i<*nbEBands;i++)
+ if(eBands[i+1]>eBands[j])
+ eBands[++j]=eBands[i+1];
+ *nbEBands=j;
+
+ for (i=1;i<*nbEBands;i++)
+ {
+ /* Every band must be smaller than the last band. */
+ celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]);
+ /* Each band must be no larger than twice the size of the previous one. */
+ celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1]));
+ }
+
+ return eBands;
+}
+
+static void compute_allocation_table(CELTMode *mode)
+{
+ int i, j;
+ unsigned char *allocVectors;
+ int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1;
+
+ mode->nbAllocVectors = BITALLOC_SIZE;
+ allocVectors = opus_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands));
+ if (allocVectors==NULL)
+ return;
+
+ /* Check for standard mode */
+ if (mode->Fs == 400*(opus_int32)mode->shortMdctSize)
+ {
+ for (i=0;i<BITALLOC_SIZE*mode->nbEBands;i++)
+ allocVectors[i] = band_allocation[i];
+ mode->allocVectors = allocVectors;
+ return;
+ }
+ /* If not the standard mode, interpolate */
+ /* Compute per-codec-band allocation from per-critical-band matrix */
+ for (i=0;i<BITALLOC_SIZE;i++)
+ {
+ for (j=0;j<mode->nbEBands;j++)
+ {
+ int k;
+ for (k=0;k<maxBands;k++)
+ {
+ if (400*(opus_int32)eband5ms[k] > mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize)
+ break;
+ }
+ if (k>maxBands-1)
+ allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1];
+ else {
+ opus_int32 a0, a1;
+ a1 = mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize - 400*(opus_int32)eband5ms[k-1];
+ a0 = 400*(opus_int32)eband5ms[k] - mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize;
+ allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1]
+ + a1*band_allocation[i*maxBands+k])/(a0+a1);
+ }
+ }
+ }
+
+ /*printf ("\n");
+ for (i=0;i<BITALLOC_SIZE;i++)
+ {
+ for (j=0;j<mode->nbEBands;j++)
+ printf ("%d ", allocVectors[i*mode->nbEBands+j]);
+ printf ("\n");
+ }
+ exit(0);*/
+
+ mode->allocVectors = allocVectors;
+}
+
+#endif /* CUSTOM_MODES */
+
+CELTMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error)
+{
+ int i;
+#ifdef CUSTOM_MODES
+ CELTMode *mode=NULL;
+ int res;
+ opus_val16 *window;
+ opus_int16 *logN;
+ int LM;
+ int arch = opus_select_arch();
+ ALLOC_STACK;
+#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA)
+ if (global_stack==NULL)
+ goto failure;
+#endif
+#endif
+
+#ifndef CUSTOM_MODES_ONLY
+ for (i=0;i<TOTAL_MODES;i++)
+ {
+ int j;
+ for (j=0;j<4;j++)
+ {
+ if (Fs == static_mode_list[i]->Fs &&
+ (frame_size<<j) == static_mode_list[i]->shortMdctSize*static_mode_list[i]->nbShortMdcts)
+ {
+ if (error)
+ *error = OPUS_OK;
+ return (CELTMode*)static_mode_list[i];
+ }
+ }
+ }
+#endif /* CUSTOM_MODES_ONLY */
+
+#ifndef CUSTOM_MODES
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+#else
+
+ /* The good thing here is that permutation of the arguments will automatically be invalid */
+
+ if (Fs < 8000 || Fs > 96000)
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0)
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ /* Frames of less than 1ms are not supported. */
+ if ((opus_int32)frame_size*1000 < Fs)
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+
+ if ((opus_int32)frame_size*75 >= Fs && (frame_size%16)==0)
+ {
+ LM = 3;
+ } else if ((opus_int32)frame_size*150 >= Fs && (frame_size%8)==0)
+ {
+ LM = 2;
+ } else if ((opus_int32)frame_size*300 >= Fs && (frame_size%4)==0)
+ {
+ LM = 1;
+ } else
+ {
+ LM = 0;
+ }
+
+ /* Shorts longer than 3.3ms are not supported. */
+ if ((opus_int32)(frame_size>>LM)*300 > Fs)
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+
+ mode = opus_alloc(sizeof(CELTMode));
+ if (mode==NULL)
+ goto failure;
+ mode->Fs = Fs;
+
+ /* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis
+ is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should
+ approximate that. */
+ if(Fs < 12000) /* 8 kHz */
+ {
+ mode->preemph[0] = QCONST16(0.3500061035f, 15);
+ mode->preemph[1] = -QCONST16(0.1799926758f, 15);
+ mode->preemph[2] = QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */
+ mode->preemph[3] = QCONST16(3.6765136719f, 13);
+ } else if(Fs < 24000) /* 16 kHz */
+ {
+ mode->preemph[0] = QCONST16(0.6000061035f, 15);
+ mode->preemph[1] = -QCONST16(0.1799926758f, 15);
+ mode->preemph[2] = QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */
+ mode->preemph[3] = QCONST16(2.2598876953f, 13);
+ } else if(Fs < 40000) /* 32 kHz */
+ {
+ mode->preemph[0] = QCONST16(0.7799987793f, 15);
+ mode->preemph[1] = -QCONST16(0.1000061035f, 15);
+ mode->preemph[2] = QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */
+ mode->preemph[3] = QCONST16(1.3333740234f, 13);
+ } else /* 48 kHz */
+ {
+ mode->preemph[0] = QCONST16(0.8500061035f, 15);
+ mode->preemph[1] = QCONST16(0.0f, 15);
+ mode->preemph[2] = QCONST16(1.f, SIG_SHIFT);
+ mode->preemph[3] = QCONST16(1.f, 13);
+ }
+
+ mode->maxLM = LM;
+ mode->nbShortMdcts = 1<<LM;
+ mode->shortMdctSize = frame_size/mode->nbShortMdcts;
+ res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize);
+
+ mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands);
+ if (mode->eBands==NULL)
+ goto failure;
+#if !defined(SMALL_FOOTPRINT)
+ /* Make sure we don't allocate a band larger than our PVQ table.
+ 208 should be enough, but let's be paranoid. */
+ if ((mode->eBands[mode->nbEBands] - mode->eBands[mode->nbEBands-1])<<LM >
+ 208) {
+ goto failure;
+ }
+#endif
+
+ mode->effEBands = mode->nbEBands;
+ while (mode->eBands[mode->effEBands] > mode->shortMdctSize)
+ mode->effEBands--;
+
+ /* Overlap must be divisible by 4 */
+ mode->overlap = ((mode->shortMdctSize>>2)<<2);
+
+ compute_allocation_table(mode);
+ if (mode->allocVectors==NULL)
+ goto failure;
+
+ window = (opus_val16*)opus_alloc(mode->overlap*sizeof(opus_val16));
+ if (window==NULL)
+ goto failure;
+
+#ifndef FIXED_POINT
+ for (i=0;i<mode->overlap;i++)
+ window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap));
+#else
+ for (i=0;i<mode->overlap;i++)
+ window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap))));
+#endif
+ mode->window = window;
+
+ logN = (opus_int16*)opus_alloc(mode->nbEBands*sizeof(opus_int16));
+ if (logN==NULL)
+ goto failure;
+
+ for (i=0;i<mode->nbEBands;i++)
+ logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES);
+ mode->logN = logN;
+
+ compute_pulse_cache(mode, mode->maxLM);
+
+ if (clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts,
+ mode->maxLM, arch) == 0)
+ goto failure;
+
+ if (error)
+ *error = OPUS_OK;
+
+ return mode;
+failure:
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ if (mode!=NULL)
+ opus_custom_mode_destroy(mode);
+ return NULL;
+#endif /* !CUSTOM_MODES */
+}
+
+#ifdef CUSTOM_MODES
+void opus_custom_mode_destroy(CELTMode *mode)
+{
+ int arch = opus_select_arch();
+
+ if (mode == NULL)
+ return;
+#ifndef CUSTOM_MODES_ONLY
+ {
+ int i;
+ for (i=0;i<TOTAL_MODES;i++)
+ {
+ if (mode == static_mode_list[i])
+ {
+ return;
+ }
+ }
+ }
+#endif /* CUSTOM_MODES_ONLY */
+ opus_free((opus_int16*)mode->eBands);
+ opus_free((opus_int16*)mode->allocVectors);
+
+ opus_free((opus_val16*)mode->window);
+ opus_free((opus_int16*)mode->logN);
+
+ opus_free((opus_int16*)mode->cache.index);
+ opus_free((unsigned char*)mode->cache.bits);
+ opus_free((unsigned char*)mode->cache.caps);
+ clt_mdct_clear(&mode->mdct, arch);
+
+ opus_free((CELTMode *)mode);
+}
+#endif
diff --git a/external/opus-1.1.4/celt/modes.h b/external/opus-1.1.4/celt/modes.h
new file mode 100644
index 0000000..be813cc
--- /dev/null
+++ b/external/opus-1.1.4/celt/modes.h
@@ -0,0 +1,75 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef MODES_H
+#define MODES_H
+
+#include "opus_types.h"
+#include "celt.h"
+#include "arch.h"
+#include "mdct.h"
+#include "entenc.h"
+#include "entdec.h"
+
+#define MAX_PERIOD 1024
+
+typedef struct {
+ int size;
+ const opus_int16 *index;
+ const unsigned char *bits;
+ const unsigned char *caps;
+} PulseCache;
+
+/** Mode definition (opaque)
+ @brief Mode definition
+ */
+struct OpusCustomMode {
+ opus_int32 Fs;
+ int overlap;
+
+ int nbEBands;
+ int effEBands;
+ opus_val16 preemph[4];
+ const opus_int16 *eBands; /**< Definition for each "pseudo-critical band" */
+
+ int maxLM;
+ int nbShortMdcts;
+ int shortMdctSize;
+
+ int nbAllocVectors; /**< Number of lines in the matrix below */
+ const unsigned char *allocVectors; /**< Number of bits in each band for several rates */
+ const opus_int16 *logN;
+
+ const opus_val16 *window;
+ mdct_lookup mdct;
+ PulseCache cache;
+};
+
+
+#endif
diff --git a/external/opus-1.1.4/celt/opus_custom_demo.c b/external/opus-1.1.4/celt/opus_custom_demo.c
new file mode 100644
index 0000000..ae41c0d
--- /dev/null
+++ b/external/opus-1.1.4/celt/opus_custom_demo.c
@@ -0,0 +1,210 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_custom.h"
+#include "arch.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#define MAX_PACKET 1275
+
+int main(int argc, char *argv[])
+{
+ int err;
+ char *inFile, *outFile;
+ FILE *fin, *fout;
+ OpusCustomMode *mode=NULL;
+ OpusCustomEncoder *enc;
+ OpusCustomDecoder *dec;
+ int len;
+ opus_int32 frame_size, channels, rate;
+ int bytes_per_packet;
+ unsigned char data[MAX_PACKET];
+ int complexity;
+#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
+ int i;
+ double rmsd = 0;
+#endif
+ int count = 0;
+ opus_int32 skip;
+ opus_int16 *in, *out;
+ if (argc != 9 && argc != 8 && argc != 7)
+ {
+ fprintf (stderr, "Usage: test_opus_custom <rate> <channels> <frame size> "
+ " <bytes per packet> [<complexity> [packet loss rate]] "
+ "<input> <output>\n");
+ return 1;
+ }
+
+ rate = (opus_int32)atol(argv[1]);
+ channels = atoi(argv[2]);
+ frame_size = atoi(argv[3]);
+ mode = opus_custom_mode_create(rate, frame_size, NULL);
+ if (mode == NULL)
+ {
+ fprintf(stderr, "failed to create a mode\n");
+ return 1;
+ }
+
+ bytes_per_packet = atoi(argv[4]);
+ if (bytes_per_packet < 0 || bytes_per_packet > MAX_PACKET)
+ {
+ fprintf (stderr, "bytes per packet must be between 0 and %d\n",
+ MAX_PACKET);
+ return 1;
+ }
+
+ inFile = argv[argc-2];
+ fin = fopen(inFile, "rb");
+ if (!fin)
+ {
+ fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
+ return 1;
+ }
+ outFile = argv[argc-1];
+ fout = fopen(outFile, "wb+");
+ if (!fout)
+ {
+ fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
+ fclose(fin);
+ return 1;
+ }
+
+ enc = opus_custom_encoder_create(mode, channels, &err);
+ if (err != 0)
+ {
+ fprintf(stderr, "Failed to create the encoder: %s\n", opus_strerror(err));
+ fclose(fin);
+ fclose(fout);
+ return 1;
+ }
+ dec = opus_custom_decoder_create(mode, channels, &err);
+ if (err != 0)
+ {
+ fprintf(stderr, "Failed to create the decoder: %s\n", opus_strerror(err));
+ fclose(fin);
+ fclose(fout);
+ return 1;
+ }
+ opus_custom_decoder_ctl(dec, OPUS_GET_LOOKAHEAD(&skip));
+
+ if (argc>7)
+ {
+ complexity=atoi(argv[5]);
+ opus_custom_encoder_ctl(enc,OPUS_SET_COMPLEXITY(complexity));
+ }
+
+ in = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16));
+ out = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16));
+
+ while (!feof(fin))
+ {
+ int ret;
+ err = fread(in, sizeof(short), frame_size*channels, fin);
+ if (feof(fin))
+ break;
+ len = opus_custom_encode(enc, in, frame_size, data, bytes_per_packet);
+ if (len <= 0)
+ fprintf (stderr, "opus_custom_encode() failed: %s\n", opus_strerror(len));
+
+ /* This is for simulating bit errors */
+#if 0
+ int errors = 0;
+ int eid = 0;
+ /* This simulates random bit error */
+ for (i=0;i<len*8;i++)
+ {
+ if (rand()%atoi(argv[8])==0)
+ {
+ if (i<64)
+ {
+ errors++;
+ eid = i;
+ }
+ data[i/8] ^= 1<<(7-(i%8));
+ }
+ }
+ if (errors == 1)
+ data[eid/8] ^= 1<<(7-(eid%8));
+ else if (errors%2 == 1)
+ data[rand()%8] ^= 1<<rand()%8;
+#endif
+
+#if 1 /* Set to zero to use the encoder's output instead */
+ /* This is to simulate packet loss */
+ if (argc==9 && rand()%1000<atoi(argv[argc-3]))
+ /*if (errors && (errors%2==0))*/
+ ret = opus_custom_decode(dec, NULL, len, out, frame_size);
+ else
+ ret = opus_custom_decode(dec, data, len, out, frame_size);
+ if (ret < 0)
+ fprintf(stderr, "opus_custom_decode() failed: %s\n", opus_strerror(ret));
+#else
+ for (i=0;i<ret*channels;i++)
+ out[i] = in[i];
+#endif
+#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
+ for (i=0;i<ret*channels;i++)
+ {
+ rmsd += (in[i]-out[i])*1.0*(in[i]-out[i]);
+ /*out[i] -= in[i];*/
+ }
+#endif
+ count++;
+ fwrite(out+skip*channels, sizeof(short), (ret-skip)*channels, fout);
+ skip = 0;
+ }
+ PRINT_MIPS(stderr);
+
+ opus_custom_encoder_destroy(enc);
+ opus_custom_decoder_destroy(dec);
+ fclose(fin);
+ fclose(fout);
+ opus_custom_mode_destroy(mode);
+ free(in);
+ free(out);
+#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
+ if (rmsd > 0)
+ {
+ rmsd = sqrt(rmsd/(1.0*frame_size*channels*count));
+ fprintf (stderr, "Error: encoder doesn't match decoder\n");
+ fprintf (stderr, "RMS mismatch is %f\n", rmsd);
+ return 1;
+ } else {
+ fprintf (stderr, "Encoder matches decoder!!\n");
+ }
+#endif
+ return 0;
+}
+
diff --git a/external/opus-1.1.4/celt/os_support.h b/external/opus-1.1.4/celt/os_support.h
new file mode 100644
index 0000000..a217197
--- /dev/null
+++ b/external/opus-1.1.4/celt/os_support.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+
+ File: os_support.h
+ This is the (tiny) OS abstraction layer. Aside from math.h, this is the
+ only place where system headers are allowed.
+
+ 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. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 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.
+*/
+
+#ifndef OS_SUPPORT_H
+#define OS_SUPPORT_H
+
+#ifdef CUSTOM_SUPPORT
+# include "custom_support.h"
+#endif
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */
+#ifndef OVERRIDE_OPUS_ALLOC
+static OPUS_INLINE void *opus_alloc (size_t size)
+{
+ return malloc(size);
+}
+#endif
+
+/** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */
+#ifndef OVERRIDE_OPUS_ALLOC_SCRATCH
+static OPUS_INLINE void *opus_alloc_scratch (size_t size)
+{
+ /* Scratch space doesn't need to be cleared */
+ return opus_alloc(size);
+}
+#endif
+
+/** Opus wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and opus_alloc */
+#ifndef OVERRIDE_OPUS_FREE
+static OPUS_INLINE void opus_free (void *ptr)
+{
+ free(ptr);
+}
+#endif
+
+/** Copy n elements from src to dst. The 0* term provides compile-time type checking */
+#ifndef OVERRIDE_OPUS_COPY
+#define OPUS_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
+#endif
+
+/** Copy n elements from src to dst, allowing overlapping regions. The 0* term
+ provides compile-time type checking */
+#ifndef OVERRIDE_OPUS_MOVE
+#define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
+#endif
+
+/** Set n elements of dst to zero */
+#ifndef OVERRIDE_OPUS_CLEAR
+#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst))))
+#endif
+
+/*#ifdef __GNUC__
+#pragma GCC poison printf sprintf
+#pragma GCC poison malloc free realloc calloc
+#endif*/
+
+#endif /* OS_SUPPORT_H */
+
diff --git a/external/opus-1.1.4/celt/pitch.c b/external/opus-1.1.4/celt/pitch.c
new file mode 100644
index 0000000..bf46e7d
--- /dev/null
+++ b/external/opus-1.1.4/celt/pitch.c
@@ -0,0 +1,557 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file pitch.c
+ @brief Pitch analysis
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pitch.h"
+#include "os_support.h"
+#include "modes.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "celt_lpc.h"
+
+static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len,
+ int max_pitch, int *best_pitch
+#ifdef FIXED_POINT
+ , int yshift, opus_val32 maxcorr
+#endif
+ )
+{
+ int i, j;
+ opus_val32 Syy=1;
+ opus_val16 best_num[2];
+ opus_val32 best_den[2];
+#ifdef FIXED_POINT
+ int xshift;
+
+ xshift = celt_ilog2(maxcorr)-14;
+#endif
+
+ best_num[0] = -1;
+ best_num[1] = -1;
+ best_den[0] = 0;
+ best_den[1] = 0;
+ best_pitch[0] = 0;
+ best_pitch[1] = 1;
+ for (j=0;j<len;j++)
+ Syy = ADD32(Syy, SHR32(MULT16_16(y[j],y[j]), yshift));
+ for (i=0;i<max_pitch;i++)
+ {
+ if (xcorr[i]>0)
+ {
+ opus_val16 num;
+ opus_val32 xcorr16;
+ xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift));
+#ifndef FIXED_POINT
+ /* Considering the range of xcorr16, this should avoid both underflows
+ and overflows (inf) when squaring xcorr16 */
+ xcorr16 *= 1e-12f;
+#endif
+ num = MULT16_16_Q15(xcorr16,xcorr16);
+ if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy))
+ {
+ if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy))
+ {
+ best_num[1] = best_num[0];
+ best_den[1] = best_den[0];
+ best_pitch[1] = best_pitch[0];
+ best_num[0] = num;
+ best_den[0] = Syy;
+ best_pitch[0] = i;
+ } else {
+ best_num[1] = num;
+ best_den[1] = Syy;
+ best_pitch[1] = i;
+ }
+ }
+ }
+ Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift);
+ Syy = MAX32(1, Syy);
+ }
+}
+
+static void celt_fir5(const opus_val16 *x,
+ const opus_val16 *num,
+ opus_val16 *y,
+ int N,
+ opus_val16 *mem)
+{
+ int i;
+ opus_val16 num0, num1, num2, num3, num4;
+ opus_val32 mem0, mem1, mem2, mem3, mem4;
+ num0=num[0];
+ num1=num[1];
+ num2=num[2];
+ num3=num[3];
+ num4=num[4];
+ mem0=mem[0];
+ mem1=mem[1];
+ mem2=mem[2];
+ mem3=mem[3];
+ mem4=mem[4];
+ for (i=0;i<N;i++)
+ {
+ opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT);
+ sum = MAC16_16(sum,num0,mem0);
+ sum = MAC16_16(sum,num1,mem1);
+ sum = MAC16_16(sum,num2,mem2);
+ sum = MAC16_16(sum,num3,mem3);
+ sum = MAC16_16(sum,num4,mem4);
+ mem4 = mem3;
+ mem3 = mem2;
+ mem2 = mem1;
+ mem1 = mem0;
+ mem0 = x[i];
+ y[i] = ROUND16(sum, SIG_SHIFT);
+ }
+ mem[0]=mem0;
+ mem[1]=mem1;
+ mem[2]=mem2;
+ mem[3]=mem3;
+ mem[4]=mem4;
+}
+
+
+void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x_lp,
+ int len, int C, int arch)
+{
+ int i;
+ opus_val32 ac[5];
+ opus_val16 tmp=Q15ONE;
+ opus_val16 lpc[4], mem[5]={0,0,0,0,0};
+ opus_val16 lpc2[5];
+ opus_val16 c1 = QCONST16(.8f,15);
+#ifdef FIXED_POINT
+ int shift;
+ opus_val32 maxabs = celt_maxabs32(x[0], len);
+ if (C==2)
+ {
+ opus_val32 maxabs_1 = celt_maxabs32(x[1], len);
+ maxabs = MAX32(maxabs, maxabs_1);
+ }
+ if (maxabs<1)
+ maxabs=1;
+ shift = celt_ilog2(maxabs)-10;
+ if (shift<0)
+ shift=0;
+ if (C==2)
+ shift++;
+#endif
+ for (i=1;i<len>>1;i++)
+ x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), shift);
+ x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), shift);
+ if (C==2)
+ {
+ for (i=1;i<len>>1;i++)
+ x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), shift);
+ x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), shift);
+ }
+
+ _celt_autocorr(x_lp, ac, NULL, 0,
+ 4, len>>1, arch);
+
+ /* Noise floor -40 dB */
+#ifdef FIXED_POINT
+ ac[0] += SHR32(ac[0],13);
+#else
+ ac[0] *= 1.0001f;
+#endif
+ /* Lag windowing */
+ for (i=1;i<=4;i++)
+ {
+ /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
+#ifdef FIXED_POINT
+ ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
+#else
+ ac[i] -= ac[i]*(.008f*i)*(.008f*i);
+#endif
+ }
+
+ _celt_lpc(lpc, ac, 4);
+ for (i=0;i<4;i++)
+ {
+ tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp);
+ lpc[i] = MULT16_16_Q15(lpc[i], tmp);
+ }
+ /* Add a zero */
+ lpc2[0] = lpc[0] + QCONST16(.8f,SIG_SHIFT);
+ lpc2[1] = lpc[1] + MULT16_16_Q15(c1,lpc[0]);
+ lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]);
+ lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]);
+ lpc2[4] = MULT16_16_Q15(c1,lpc[3]);
+ celt_fir5(x_lp, lpc2, x_lp, len>>1, mem);
+}
+
+/* Pure C implementation. */
+#ifdef FIXED_POINT
+opus_val32
+#else
+void
+#endif
+#if defined(OVERRIDE_PITCH_XCORR)
+celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y,
+ opus_val32 *xcorr, int len, int max_pitch)
+#else
+celt_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y,
+ opus_val32 *xcorr, int len, int max_pitch, int arch)
+#endif
+{
+
+#if 0 /* This is a simple version of the pitch correlation that should work
+ well on DSPs like Blackfin and TI C5x/C6x */
+ int i, j;
+#ifdef FIXED_POINT
+ opus_val32 maxcorr=1;
+#endif
+#if !defined(OVERRIDE_PITCH_XCORR)
+ (void)arch;
+#endif
+ for (i=0;i<max_pitch;i++)
+ {
+ opus_val32 sum = 0;
+ for (j=0;j<len;j++)
+ sum = MAC16_16(sum, _x[j], _y[i+j]);
+ xcorr[i] = sum;
+#ifdef FIXED_POINT
+ maxcorr = MAX32(maxcorr, sum);
+#endif
+ }
+#ifdef FIXED_POINT
+ return maxcorr;
+#endif
+
+#else /* Unrolled version of the pitch correlation -- runs faster on x86 and ARM */
+ int i;
+ /*The EDSP version requires that max_pitch is at least 1, and that _x is
+ 32-bit aligned.
+ Since it's hard to put asserts in assembly, put them here.*/
+#ifdef FIXED_POINT
+ opus_val32 maxcorr=1;
+#endif
+ celt_assert(max_pitch>0);
+ celt_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
+ for (i=0;i<max_pitch-3;i+=4)
+ {
+ opus_val32 sum[4]={0,0,0,0};
+#if defined(OVERRIDE_PITCH_XCORR)
+ xcorr_kernel_c(_x, _y+i, sum, len);
+#else
+ xcorr_kernel(_x, _y+i, sum, len, arch);
+#endif
+ xcorr[i]=sum[0];
+ xcorr[i+1]=sum[1];
+ xcorr[i+2]=sum[2];
+ xcorr[i+3]=sum[3];
+#ifdef FIXED_POINT
+ sum[0] = MAX32(sum[0], sum[1]);
+ sum[2] = MAX32(sum[2], sum[3]);
+ sum[0] = MAX32(sum[0], sum[2]);
+ maxcorr = MAX32(maxcorr, sum[0]);
+#endif
+ }
+ /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
+ for (;i<max_pitch;i++)
+ {
+ opus_val32 sum;
+#if defined(OVERRIDE_PITCH_XCORR)
+ sum = celt_inner_prod_c(_x, _y+i, len);
+#else
+ sum = celt_inner_prod(_x, _y+i, len, arch);
+#endif
+ xcorr[i] = sum;
+#ifdef FIXED_POINT
+ maxcorr = MAX32(maxcorr, sum);
+#endif
+ }
+#ifdef FIXED_POINT
+ return maxcorr;
+#endif
+#endif
+}
+
+void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTRICT y,
+ int len, int max_pitch, int *pitch, int arch)
+{
+ int i, j;
+ int lag;
+ int best_pitch[2]={0,0};
+ VARDECL(opus_val16, x_lp4);
+ VARDECL(opus_val16, y_lp4);
+ VARDECL(opus_val32, xcorr);
+#ifdef FIXED_POINT
+ opus_val32 maxcorr;
+ opus_val32 xmax, ymax;
+ int shift=0;
+#endif
+ int offset;
+
+ SAVE_STACK;
+
+ celt_assert(len>0);
+ celt_assert(max_pitch>0);
+ lag = len+max_pitch;
+
+ ALLOC(x_lp4, len>>2, opus_val16);
+ ALLOC(y_lp4, lag>>2, opus_val16);
+ ALLOC(xcorr, max_pitch>>1, opus_val32);
+
+ /* Downsample by 2 again */
+ for (j=0;j<len>>2;j++)
+ x_lp4[j] = x_lp[2*j];
+ for (j=0;j<lag>>2;j++)
+ y_lp4[j] = y[2*j];
+
+#ifdef FIXED_POINT
+ xmax = celt_maxabs16(x_lp4, len>>2);
+ ymax = celt_maxabs16(y_lp4, lag>>2);
+ shift = celt_ilog2(MAX32(1, MAX32(xmax, ymax)))-11;
+ if (shift>0)
+ {
+ for (j=0;j<len>>2;j++)
+ x_lp4[j] = SHR16(x_lp4[j], shift);
+ for (j=0;j<lag>>2;j++)
+ y_lp4[j] = SHR16(y_lp4[j], shift);
+ /* Use double the shift for a MAC */
+ shift *= 2;
+ } else {
+ shift = 0;
+ }
+#endif
+
+ /* Coarse search with 4x decimation */
+
+#ifdef FIXED_POINT
+ maxcorr =
+#endif
+ celt_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2, arch);
+
+ find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch
+#ifdef FIXED_POINT
+ , 0, maxcorr
+#endif
+ );
+
+ /* Finer search with 2x decimation */
+#ifdef FIXED_POINT
+ maxcorr=1;
+#endif
+ for (i=0;i<max_pitch>>1;i++)
+ {
+ opus_val32 sum;
+ xcorr[i] = 0;
+ if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2)
+ continue;
+#ifdef FIXED_POINT
+ sum = 0;
+ for (j=0;j<len>>1;j++)
+ sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift);
+#else
+ sum = celt_inner_prod_c(x_lp, y+i, len>>1);
+#endif
+ xcorr[i] = MAX32(-1, sum);
+#ifdef FIXED_POINT
+ maxcorr = MAX32(maxcorr, sum);
+#endif
+ }
+ find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch
+#ifdef FIXED_POINT
+ , shift+1, maxcorr
+#endif
+ );
+
+ /* Refine by pseudo-interpolation */
+ if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1)
+ {
+ opus_val32 a, b, c;
+ a = xcorr[best_pitch[0]-1];
+ b = xcorr[best_pitch[0]];
+ c = xcorr[best_pitch[0]+1];
+ if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a))
+ offset = 1;
+ else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c))
+ offset = -1;
+ else
+ offset = 0;
+ } else {
+ offset = 0;
+ }
+ *pitch = 2*best_pitch[0]-offset;
+
+ RESTORE_STACK;
+}
+
+#ifdef FIXED_POINT
+static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy)
+{
+ opus_val32 x2y2;
+ int sx, sy, shift;
+ opus_val32 g;
+ opus_val16 den;
+ if (xy == 0 || xx == 0 || yy == 0)
+ return 0;
+ sx = celt_ilog2(xx)-14;
+ sy = celt_ilog2(yy)-14;
+ shift = sx + sy;
+ x2y2 = MULT16_16_Q14(VSHR32(xx, sx), VSHR32(yy, sy));
+ if (shift & 1) {
+ if (x2y2 < 32768)
+ {
+ x2y2 <<= 1;
+ shift--;
+ } else {
+ x2y2 >>= 1;
+ shift++;
+ }
+ }
+ den = celt_rsqrt_norm(x2y2);
+ g = MULT16_32_Q15(den, xy);
+ g = VSHR32(g, (shift>>1)-1);
+ return EXTRACT16(MIN32(g, Q15ONE));
+}
+#else
+static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy)
+{
+ return xy/celt_sqrt(1+xx*yy);
+}
+#endif
+
+static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2};
+opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
+ int N, int *T0_, int prev_period, opus_val16 prev_gain, int arch)
+{
+ int k, i, T, T0;
+ opus_val16 g, g0;
+ opus_val16 pg;
+ opus_val32 xy,xx,yy,xy2;
+ opus_val32 xcorr[3];
+ opus_val32 best_xy, best_yy;
+ int offset;
+ int minperiod0;
+ VARDECL(opus_val32, yy_lookup);
+ SAVE_STACK;
+
+ minperiod0 = minperiod;
+ maxperiod /= 2;
+ minperiod /= 2;
+ *T0_ /= 2;
+ prev_period /= 2;
+ N /= 2;
+ x += maxperiod;
+ if (*T0_>=maxperiod)
+ *T0_=maxperiod-1;
+
+ T = T0 = *T0_;
+ ALLOC(yy_lookup, maxperiod+1, opus_val32);
+ dual_inner_prod(x, x, x-T0, N, &xx, &xy, arch);
+ yy_lookup[0] = xx;
+ yy=xx;
+ for (i=1;i<=maxperiod;i++)
+ {
+ yy = yy+MULT16_16(x[-i],x[-i])-MULT16_16(x[N-i],x[N-i]);
+ yy_lookup[i] = MAX32(0, yy);
+ }
+ yy = yy_lookup[T0];
+ best_xy = xy;
+ best_yy = yy;
+ g = g0 = compute_pitch_gain(xy, xx, yy);
+ /* Look for any pitch at T/k */
+ for (k=2;k<=15;k++)
+ {
+ int T1, T1b;
+ opus_val16 g1;
+ opus_val16 cont=0;
+ opus_val16 thresh;
+ T1 = celt_udiv(2*T0+k, 2*k);
+ if (T1 < minperiod)
+ break;
+ /* Look for another strong correlation at T1b */
+ if (k==2)
+ {
+ if (T1+T0>maxperiod)
+ T1b = T0;
+ else
+ T1b = T0+T1;
+ } else
+ {
+ T1b = celt_udiv(2*second_check[k]*T0+k, 2*k);
+ }
+ dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2, arch);
+ xy = HALF32(xy + xy2);
+ yy = HALF32(yy_lookup[T1] + yy_lookup[T1b]);
+ g1 = compute_pitch_gain(xy, xx, yy);
+ if (abs(T1-prev_period)<=1)
+ cont = prev_gain;
+ else if (abs(T1-prev_period)<=2 && 5*k*k < T0)
+ cont = HALF16(prev_gain);
+ else
+ cont = 0;
+ thresh = MAX16(QCONST16(.3f,15), MULT16_16_Q15(QCONST16(.7f,15),g0)-cont);
+ /* Bias against very high pitch (very short period) to avoid false-positives
+ due to short-term correlation */
+ if (T1<3*minperiod)
+ thresh = MAX16(QCONST16(.4f,15), MULT16_16_Q15(QCONST16(.85f,15),g0)-cont);
+ else if (T1<2*minperiod)
+ thresh = MAX16(QCONST16(.5f,15), MULT16_16_Q15(QCONST16(.9f,15),g0)-cont);
+ if (g1 > thresh)
+ {
+ best_xy = xy;
+ best_yy = yy;
+ T = T1;
+ g = g1;
+ }
+ }
+ best_xy = MAX32(0, best_xy);
+ if (best_yy <= best_xy)
+ pg = Q15ONE;
+ else
+ pg = SHR32(frac_div32(best_xy,best_yy+1),16);
+
+ for (k=0;k<3;k++)
+ xcorr[k] = celt_inner_prod(x, x-(T+k-1), N, arch);
+ if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0]))
+ offset = 1;
+ else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2]))
+ offset = -1;
+ else
+ offset = 0;
+ if (pg > g)
+ pg = g;
+ *T0_ = 2*T+offset;
+
+ if (*T0_<minperiod0)
+ *T0_=minperiod0;
+ RESTORE_STACK;
+ return pg;
+}
diff --git a/external/opus-1.1.4/celt/pitch.h b/external/opus-1.1.4/celt/pitch.h
new file mode 100644
index 0000000..d350353
--- /dev/null
+++ b/external/opus-1.1.4/celt/pitch.h
@@ -0,0 +1,200 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file pitch.h
+ @brief Pitch analysis
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef PITCH_H
+#define PITCH_H
+
+#include "modes.h"
+#include "cpu_support.h"
+
+#if (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT)) \
+ || ((defined(OPUS_X86_MAY_HAVE_SSE4_1) || defined(OPUS_X86_MAY_HAVE_SSE2)) && defined(FIXED_POINT))
+#include "x86/pitch_sse.h"
+#endif
+
+#if defined(MIPSr1_ASM)
+#include "mips/pitch_mipsr1.h"
+#endif
+
+#if ((defined(OPUS_ARM_ASM) && defined(FIXED_POINT)) \
+ || defined(OPUS_ARM_MAY_HAVE_NEON_INTR))
+# include "arm/pitch_arm.h"
+#endif
+
+void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x_lp,
+ int len, int C, int arch);
+
+void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTRICT y,
+ int len, int max_pitch, int *pitch, int arch);
+
+opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
+ int N, int *T0, int prev_period, opus_val16 prev_gain, int arch);
+
+
+/* OPT: This is the kernel you really want to optimize. It gets used a lot
+ by the prefilter and by the PLC. */
+static OPUS_INLINE void xcorr_kernel_c(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[4], int len)
+{
+ int j;
+ opus_val16 y_0, y_1, y_2, y_3;
+ celt_assert(len>=3);
+ y_3=0; /* gcc doesn't realize that y_3 can't be used uninitialized */
+ y_0=*y++;
+ y_1=*y++;
+ y_2=*y++;
+ for (j=0;j<len-3;j+=4)
+ {
+ opus_val16 tmp;
+ tmp = *x++;
+ y_3=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_0);
+ sum[1] = MAC16_16(sum[1],tmp,y_1);
+ sum[2] = MAC16_16(sum[2],tmp,y_2);
+ sum[3] = MAC16_16(sum[3],tmp,y_3);
+ tmp=*x++;
+ y_0=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_1);
+ sum[1] = MAC16_16(sum[1],tmp,y_2);
+ sum[2] = MAC16_16(sum[2],tmp,y_3);
+ sum[3] = MAC16_16(sum[3],tmp,y_0);
+ tmp=*x++;
+ y_1=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_2);
+ sum[1] = MAC16_16(sum[1],tmp,y_3);
+ sum[2] = MAC16_16(sum[2],tmp,y_0);
+ sum[3] = MAC16_16(sum[3],tmp,y_1);
+ tmp=*x++;
+ y_2=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_3);
+ sum[1] = MAC16_16(sum[1],tmp,y_0);
+ sum[2] = MAC16_16(sum[2],tmp,y_1);
+ sum[3] = MAC16_16(sum[3],tmp,y_2);
+ }
+ if (j++<len)
+ {
+ opus_val16 tmp = *x++;
+ y_3=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_0);
+ sum[1] = MAC16_16(sum[1],tmp,y_1);
+ sum[2] = MAC16_16(sum[2],tmp,y_2);
+ sum[3] = MAC16_16(sum[3],tmp,y_3);
+ }
+ if (j++<len)
+ {
+ opus_val16 tmp=*x++;
+ y_0=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_1);
+ sum[1] = MAC16_16(sum[1],tmp,y_2);
+ sum[2] = MAC16_16(sum[2],tmp,y_3);
+ sum[3] = MAC16_16(sum[3],tmp,y_0);
+ }
+ if (j<len)
+ {
+ opus_val16 tmp=*x++;
+ y_1=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_2);
+ sum[1] = MAC16_16(sum[1],tmp,y_3);
+ sum[2] = MAC16_16(sum[2],tmp,y_0);
+ sum[3] = MAC16_16(sum[3],tmp,y_1);
+ }
+}
+
+#ifndef OVERRIDE_XCORR_KERNEL
+#define xcorr_kernel(x, y, sum, len, arch) \
+ ((void)(arch),xcorr_kernel_c(x, y, sum, len))
+#endif /* OVERRIDE_XCORR_KERNEL */
+
+
+static OPUS_INLINE void dual_inner_prod_c(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
+ int N, opus_val32 *xy1, opus_val32 *xy2)
+{
+ int i;
+ opus_val32 xy01=0;
+ opus_val32 xy02=0;
+ for (i=0;i<N;i++)
+ {
+ xy01 = MAC16_16(xy01, x[i], y01[i]);
+ xy02 = MAC16_16(xy02, x[i], y02[i]);
+ }
+ *xy1 = xy01;
+ *xy2 = xy02;
+}
+
+#ifndef OVERRIDE_DUAL_INNER_PROD
+# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) \
+ ((void)(arch),dual_inner_prod_c(x, y01, y02, N, xy1, xy2))
+#endif
+
+/*We make sure a C version is always available for cases where the overhead of
+ vectorization and passing around an arch flag aren't worth it.*/
+static OPUS_INLINE opus_val32 celt_inner_prod_c(const opus_val16 *x,
+ const opus_val16 *y, int N)
+{
+ int i;
+ opus_val32 xy=0;
+ for (i=0;i<N;i++)
+ xy = MAC16_16(xy, x[i], y[i]);
+ return xy;
+}
+
+#if !defined(OVERRIDE_CELT_INNER_PROD)
+# define celt_inner_prod(x, y, N, arch) \
+ ((void)(arch),celt_inner_prod_c(x, y, N))
+#endif
+
+#ifdef NON_STATIC_COMB_FILTER_CONST_C
+void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N,
+ opus_val16 g10, opus_val16 g11, opus_val16 g12);
+#endif
+
+
+#ifdef FIXED_POINT
+opus_val32
+#else
+void
+#endif
+celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y,
+ opus_val32 *xcorr, int len, int max_pitch);
+
+#if !defined(OVERRIDE_PITCH_XCORR)
+#ifdef FIXED_POINT
+opus_val32
+#else
+void
+#endif
+celt_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y,
+ opus_val32 *xcorr, int len, int max_pitch, int arch);
+
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/celt/quant_bands.c b/external/opus-1.1.4/celt/quant_bands.c
new file mode 100644
index 0000000..95076e0
--- /dev/null
+++ b/external/opus-1.1.4/celt/quant_bands.c
@@ -0,0 +1,556 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "quant_bands.h"
+#include "laplace.h"
+#include <math.h>
+#include "os_support.h"
+#include "arch.h"
+#include "mathops.h"
+#include "stack_alloc.h"
+#include "rate.h"
+
+#ifdef FIXED_POINT
+/* Mean energy in each band quantized in Q4 */
+const signed char eMeans[25] = {
+ 103,100, 92, 85, 81,
+ 77, 72, 70, 78, 75,
+ 73, 71, 78, 74, 69,
+ 72, 70, 74, 76, 71,
+ 60, 60, 60, 60, 60
+};
+#else
+/* Mean energy in each band quantized in Q4 and converted back to float */
+const opus_val16 eMeans[25] = {
+ 6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f,
+ 4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f,
+ 4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f,
+ 4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f,
+ 3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f
+};
+#endif
+/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */
+#ifdef FIXED_POINT
+static const opus_val16 pred_coef[4] = {29440, 26112, 21248, 16384};
+static const opus_val16 beta_coef[4] = {30147, 22282, 12124, 6554};
+static const opus_val16 beta_intra = 4915;
+#else
+static const opus_val16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768., 16384/32768.};
+static const opus_val16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.};
+static const opus_val16 beta_intra = 4915/32768.;
+#endif
+
+/*Parameters of the Laplace-like probability models used for the coarse energy.
+ There is one pair of parameters for each frame size, prediction type
+ (inter/intra), and band number.
+ The first number of each pair is the probability of 0, and the second is the
+ decay rate, both in Q8 precision.*/
+static const unsigned char e_prob_model[4][2][42] = {
+ /*120 sample frames.*/
+ {
+ /*Inter*/
+ {
+ 72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128,
+ 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40,
+ 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11
+ },
+ /*Intra*/
+ {
+ 24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132,
+ 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66,
+ 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50
+ }
+ },
+ /*240 sample frames.*/
+ {
+ /*Inter*/
+ {
+ 83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74,
+ 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18,
+ 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9
+ },
+ /*Intra*/
+ {
+ 23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91,
+ 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60,
+ 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45
+ }
+ },
+ /*480 sample frames.*/
+ {
+ /*Inter*/
+ {
+ 61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38,
+ 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16,
+ 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10
+ },
+ /*Intra*/
+ {
+ 21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73,
+ 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55,
+ 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42
+ }
+ },
+ /*960 sample frames.*/
+ {
+ /*Inter*/
+ {
+ 42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36,
+ 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25,
+ 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15
+ },
+ /*Intra*/
+ {
+ 22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72,
+ 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52,
+ 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40
+ }
+ }
+};
+
+static const unsigned char small_energy_icdf[3]={2,1,0};
+
+static opus_val32 loss_distortion(const opus_val16 *eBands, opus_val16 *oldEBands, int start, int end, int len, int C)
+{
+ int c, i;
+ opus_val32 dist = 0;
+ c=0; do {
+ for (i=start;i<end;i++)
+ {
+ opus_val16 d = SUB16(SHR16(eBands[i+c*len], 3), SHR16(oldEBands[i+c*len], 3));
+ dist = MAC16_16(dist, d,d);
+ }
+ } while (++c<C);
+ return MIN32(200,SHR32(dist,2*DB_SHIFT-6));
+}
+
+static int quant_coarse_energy_impl(const CELTMode *m, int start, int end,
+ const opus_val16 *eBands, opus_val16 *oldEBands,
+ opus_int32 budget, opus_int32 tell,
+ const unsigned char *prob_model, opus_val16 *error, ec_enc *enc,
+ int C, int LM, int intra, opus_val16 max_decay, int lfe)
+{
+ int i, c;
+ int badness = 0;
+ opus_val32 prev[2] = {0,0};
+ opus_val16 coef;
+ opus_val16 beta;
+
+ if (tell+3 <= budget)
+ ec_enc_bit_logp(enc, intra, 3);
+ if (intra)
+ {
+ coef = 0;
+ beta = beta_intra;
+ } else {
+ beta = beta_coef[LM];
+ coef = pred_coef[LM];
+ }
+
+ /* Encode at a fixed coarse resolution */
+ for (i=start;i<end;i++)
+ {
+ c=0;
+ do {
+ int bits_left;
+ int qi, qi0;
+ opus_val32 q;
+ opus_val16 x;
+ opus_val32 f, tmp;
+ opus_val16 oldE;
+ opus_val16 decay_bound;
+ x = eBands[i+c*m->nbEBands];
+ oldE = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]);
+#ifdef FIXED_POINT
+ f = SHL32(EXTEND32(x),7) - PSHR32(MULT16_16(coef,oldE), 8) - prev[c];
+ /* Rounding to nearest integer here is really important! */
+ qi = (f+QCONST32(.5f,DB_SHIFT+7))>>(DB_SHIFT+7);
+ decay_bound = EXTRACT16(MAX32(-QCONST16(28.f,DB_SHIFT),
+ SUB32((opus_val32)oldEBands[i+c*m->nbEBands],max_decay)));
+#else
+ f = x-coef*oldE-prev[c];
+ /* Rounding to nearest integer here is really important! */
+ qi = (int)floor(.5f+f);
+ decay_bound = MAX16(-QCONST16(28.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]) - max_decay;
+#endif
+ /* Prevent the energy from going down too quickly (e.g. for bands
+ that have just one bin) */
+ if (qi < 0 && x < decay_bound)
+ {
+ qi += (int)SHR16(SUB16(decay_bound,x), DB_SHIFT);
+ if (qi > 0)
+ qi = 0;
+ }
+ qi0 = qi;
+ /* If we don't have enough bits to encode all the energy, just assume
+ something safe. */
+ tell = ec_tell(enc);
+ bits_left = budget-tell-3*C*(end-i);
+ if (i!=start && bits_left < 30)
+ {
+ if (bits_left < 24)
+ qi = IMIN(1, qi);
+ if (bits_left < 16)
+ qi = IMAX(-1, qi);
+ }
+ if (lfe && i>=2)
+ qi = IMIN(qi, 0);
+ if (budget-tell >= 15)
+ {
+ int pi;
+ pi = 2*IMIN(i,20);
+ ec_laplace_encode(enc, &qi,
+ prob_model[pi]<<7, prob_model[pi+1]<<6);
+ }
+ else if(budget-tell >= 2)
+ {
+ qi = IMAX(-1, IMIN(qi, 1));
+ ec_enc_icdf(enc, 2*qi^-(qi<0), small_energy_icdf, 2);
+ }
+ else if(budget-tell >= 1)
+ {
+ qi = IMIN(0, qi);
+ ec_enc_bit_logp(enc, -qi, 1);
+ }
+ else
+ qi = -1;
+ error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT);
+ badness += abs(qi0-qi);
+ q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT);
+
+ tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7);
+#ifdef FIXED_POINT
+ tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp);
+#endif
+ oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7);
+ prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8));
+ } while (++c < C);
+ }
+ return lfe ? 0 : badness;
+}
+
+void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
+ const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget,
+ opus_val16 *error, ec_enc *enc, int C, int LM, int nbAvailableBytes,
+ int force_intra, opus_val32 *delayedIntra, int two_pass, int loss_rate, int lfe)
+{
+ int intra;
+ opus_val16 max_decay;
+ VARDECL(opus_val16, oldEBands_intra);
+ VARDECL(opus_val16, error_intra);
+ ec_enc enc_start_state;
+ opus_uint32 tell;
+ int badness1=0;
+ opus_int32 intra_bias;
+ opus_val32 new_distortion;
+ SAVE_STACK;
+
+ intra = force_intra || (!two_pass && *delayedIntra>2*C*(end-start) && nbAvailableBytes > (end-start)*C);
+ intra_bias = (opus_int32)((budget**delayedIntra*loss_rate)/(C*512));
+ new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m->nbEBands, C);
+
+ tell = ec_tell(enc);
+ if (tell+3 > budget)
+ two_pass = intra = 0;
+
+ max_decay = QCONST16(16.f,DB_SHIFT);
+ if (end-start>10)
+ {
+#ifdef FIXED_POINT
+ max_decay = MIN32(max_decay, SHL32(EXTEND32(nbAvailableBytes),DB_SHIFT-3));
+#else
+ max_decay = MIN32(max_decay, .125f*nbAvailableBytes);
+#endif
+ }
+ if (lfe)
+ max_decay = QCONST16(3.f,DB_SHIFT);
+ enc_start_state = *enc;
+
+ ALLOC(oldEBands_intra, C*m->nbEBands, opus_val16);
+ ALLOC(error_intra, C*m->nbEBands, opus_val16);
+ OPUS_COPY(oldEBands_intra, oldEBands, C*m->nbEBands);
+
+ if (two_pass || intra)
+ {
+ badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget,
+ tell, e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe);
+ }
+
+ if (!intra)
+ {
+ unsigned char *intra_buf;
+ ec_enc enc_intra_state;
+ opus_int32 tell_intra;
+ opus_uint32 nstart_bytes;
+ opus_uint32 nintra_bytes;
+ opus_uint32 save_bytes;
+ int badness2;
+ VARDECL(unsigned char, intra_bits);
+
+ tell_intra = ec_tell_frac(enc);
+
+ enc_intra_state = *enc;
+
+ nstart_bytes = ec_range_bytes(&enc_start_state);
+ nintra_bytes = ec_range_bytes(&enc_intra_state);
+ intra_buf = ec_get_buffer(&enc_intra_state) + nstart_bytes;
+ save_bytes = nintra_bytes-nstart_bytes;
+ if (save_bytes == 0)
+ save_bytes = ALLOC_NONE;
+ ALLOC(intra_bits, save_bytes, unsigned char);
+ /* Copy bits from intra bit-stream */
+ OPUS_COPY(intra_bits, intra_buf, nintra_bytes - nstart_bytes);
+
+ *enc = enc_start_state;
+
+ badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget,
+ tell, e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe);
+
+ if (two_pass && (badness1 < badness2 || (badness1 == badness2 && ((opus_int32)ec_tell_frac(enc))+intra_bias > tell_intra)))
+ {
+ *enc = enc_intra_state;
+ /* Copy intra bits to bit-stream */
+ OPUS_COPY(intra_buf, intra_bits, nintra_bytes - nstart_bytes);
+ OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands);
+ OPUS_COPY(error, error_intra, C*m->nbEBands);
+ intra = 1;
+ }
+ } else {
+ OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands);
+ OPUS_COPY(error, error_intra, C*m->nbEBands);
+ }
+
+ if (intra)
+ *delayedIntra = new_distortion;
+ else
+ *delayedIntra = ADD32(MULT16_32_Q15(MULT16_16_Q15(pred_coef[LM], pred_coef[LM]),*delayedIntra),
+ new_distortion);
+
+ RESTORE_STACK;
+}
+
+void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C)
+{
+ int i, c;
+
+ /* Encode finer resolution */
+ for (i=start;i<end;i++)
+ {
+ opus_int16 frac = 1<<fine_quant[i];
+ if (fine_quant[i] <= 0)
+ continue;
+ c=0;
+ do {
+ int q2;
+ opus_val16 offset;
+#ifdef FIXED_POINT
+ /* Has to be without rounding */
+ q2 = (error[i+c*m->nbEBands]+QCONST16(.5f,DB_SHIFT))>>(DB_SHIFT-fine_quant[i]);
+#else
+ q2 = (int)floor((error[i+c*m->nbEBands]+.5f)*frac);
+#endif
+ if (q2 > frac-1)
+ q2 = frac-1;
+ if (q2<0)
+ q2 = 0;
+ ec_enc_bits(enc, q2, fine_quant[i]);
+#ifdef FIXED_POINT
+ offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT));
+#else
+ offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f;
+#endif
+ oldEBands[i+c*m->nbEBands] += offset;
+ error[i+c*m->nbEBands] -= offset;
+ /*printf ("%f ", error[i] - offset);*/
+ } while (++c < C);
+ }
+}
+
+void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C)
+{
+ int i, prio, c;
+
+ /* Use up the remaining bits */
+ for (prio=0;prio<2;prio++)
+ {
+ for (i=start;i<end && bits_left>=C ;i++)
+ {
+ if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio)
+ continue;
+ c=0;
+ do {
+ int q2;
+ opus_val16 offset;
+ q2 = error[i+c*m->nbEBands]<0 ? 0 : 1;
+ ec_enc_bits(enc, q2, 1);
+#ifdef FIXED_POINT
+ offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1);
+#else
+ offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384);
+#endif
+ oldEBands[i+c*m->nbEBands] += offset;
+ bits_left--;
+ } while (++c < C);
+ }
+ }
+}
+
+void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM)
+{
+ const unsigned char *prob_model = e_prob_model[LM][intra];
+ int i, c;
+ opus_val32 prev[2] = {0, 0};
+ opus_val16 coef;
+ opus_val16 beta;
+ opus_int32 budget;
+ opus_int32 tell;
+
+ if (intra)
+ {
+ coef = 0;
+ beta = beta_intra;
+ } else {
+ beta = beta_coef[LM];
+ coef = pred_coef[LM];
+ }
+
+ budget = dec->storage*8;
+
+ /* Decode at a fixed coarse resolution */
+ for (i=start;i<end;i++)
+ {
+ c=0;
+ do {
+ int qi;
+ opus_val32 q;
+ opus_val32 tmp;
+ /* It would be better to express this invariant as a
+ test on C at function entry, but that isn't enough
+ to make the static analyzer happy. */
+ celt_assert(c<2);
+ tell = ec_tell(dec);
+ if(budget-tell>=15)
+ {
+ int pi;
+ pi = 2*IMIN(i,20);
+ qi = ec_laplace_decode(dec,
+ prob_model[pi]<<7, prob_model[pi+1]<<6);
+ }
+ else if(budget-tell>=2)
+ {
+ qi = ec_dec_icdf(dec, small_energy_icdf, 2);
+ qi = (qi>>1)^-(qi&1);
+ }
+ else if(budget-tell>=1)
+ {
+ qi = -ec_dec_bit_logp(dec, 1);
+ }
+ else
+ qi = -1;
+ q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT);
+
+ oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]);
+ tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7);
+#ifdef FIXED_POINT
+ tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp);
+#endif
+ oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7);
+ prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8));
+ } while (++c < C);
+ }
+}
+
+void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C)
+{
+ int i, c;
+ /* Decode finer resolution */
+ for (i=start;i<end;i++)
+ {
+ if (fine_quant[i] <= 0)
+ continue;
+ c=0;
+ do {
+ int q2;
+ opus_val16 offset;
+ q2 = ec_dec_bits(dec, fine_quant[i]);
+#ifdef FIXED_POINT
+ offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT));
+#else
+ offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f;
+#endif
+ oldEBands[i+c*m->nbEBands] += offset;
+ } while (++c < C);
+ }
+}
+
+void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C)
+{
+ int i, prio, c;
+
+ /* Use up the remaining bits */
+ for (prio=0;prio<2;prio++)
+ {
+ for (i=start;i<end && bits_left>=C ;i++)
+ {
+ if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio)
+ continue;
+ c=0;
+ do {
+ int q2;
+ opus_val16 offset;
+ q2 = ec_dec_bits(dec, 1);
+#ifdef FIXED_POINT
+ offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1);
+#else
+ offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384);
+#endif
+ oldEBands[i+c*m->nbEBands] += offset;
+ bits_left--;
+ } while (++c < C);
+ }
+ }
+}
+
+void amp2Log2(const CELTMode *m, int effEnd, int end,
+ celt_ener *bandE, opus_val16 *bandLogE, int C)
+{
+ int c, i;
+ c=0;
+ do {
+ for (i=0;i<effEnd;i++)
+ bandLogE[i+c*m->nbEBands] =
+ celt_log2(SHL32(bandE[i+c*m->nbEBands],2))
+ - SHL16((opus_val16)eMeans[i],6);
+ for (i=effEnd;i<end;i++)
+ bandLogE[c*m->nbEBands+i] = -QCONST16(14.f,DB_SHIFT);
+ } while (++c < C);
+}
diff --git a/external/opus-1.1.4/celt/quant_bands.h b/external/opus-1.1.4/celt/quant_bands.h
new file mode 100644
index 0000000..0490bca
--- /dev/null
+++ b/external/opus-1.1.4/celt/quant_bands.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef QUANT_BANDS
+#define QUANT_BANDS
+
+#include "arch.h"
+#include "modes.h"
+#include "entenc.h"
+#include "entdec.h"
+#include "mathops.h"
+
+#ifdef FIXED_POINT
+extern const signed char eMeans[25];
+#else
+extern const opus_val16 eMeans[25];
+#endif
+
+void amp2Log2(const CELTMode *m, int effEnd, int end,
+ celt_ener *bandE, opus_val16 *bandLogE, int C);
+
+void log2Amp(const CELTMode *m, int start, int end,
+ celt_ener *eBands, const opus_val16 *oldEBands, int C);
+
+void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
+ const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget,
+ opus_val16 *error, ec_enc *enc, int C, int LM,
+ int nbAvailableBytes, int force_intra, opus_val32 *delayedIntra,
+ int two_pass, int loss_rate, int lfe);
+
+void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C);
+
+void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C);
+
+void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM);
+
+void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C);
+
+void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C);
+
+#endif /* QUANT_BANDS */
diff --git a/external/opus-1.1.4/celt/rate.c b/external/opus-1.1.4/celt/rate.c
new file mode 100644
index 0000000..7dfa5be
--- /dev/null
+++ b/external/opus-1.1.4/celt/rate.c
@@ -0,0 +1,639 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include "modes.h"
+#include "cwrs.h"
+#include "arch.h"
+#include "os_support.h"
+
+#include "entcode.h"
+#include "rate.h"
+
+static const unsigned char LOG2_FRAC_TABLE[24]={
+ 0,
+ 8,13,
+ 16,19,21,23,
+ 24,26,27,28,29,30,31,32,
+ 32,33,34,34,35,36,36,37,37
+};
+
+#ifdef CUSTOM_MODES
+
+/*Determines if V(N,K) fits in a 32-bit unsigned integer.
+ N and K are themselves limited to 15 bits.*/
+static int fits_in32(int _n, int _k)
+{
+ static const opus_int16 maxN[15] = {
+ 32767, 32767, 32767, 1476, 283, 109, 60, 40,
+ 29, 24, 20, 18, 16, 14, 13};
+ static const opus_int16 maxK[15] = {
+ 32767, 32767, 32767, 32767, 1172, 238, 95, 53,
+ 36, 27, 22, 18, 16, 15, 13};
+ if (_n>=14)
+ {
+ if (_k>=14)
+ return 0;
+ else
+ return _n <= maxN[_k];
+ } else {
+ return _k <= maxK[_n];
+ }
+}
+
+void compute_pulse_cache(CELTMode *m, int LM)
+{
+ int C;
+ int i;
+ int j;
+ int curr=0;
+ int nbEntries=0;
+ int entryN[100], entryK[100], entryI[100];
+ const opus_int16 *eBands = m->eBands;
+ PulseCache *cache = &m->cache;
+ opus_int16 *cindex;
+ unsigned char *bits;
+ unsigned char *cap;
+
+ cindex = (opus_int16 *)opus_alloc(sizeof(cache->index[0])*m->nbEBands*(LM+2));
+ cache->index = cindex;
+
+ /* Scan for all unique band sizes */
+ for (i=0;i<=LM+1;i++)
+ {
+ for (j=0;j<m->nbEBands;j++)
+ {
+ int k;
+ int N = (eBands[j+1]-eBands[j])<<i>>1;
+ cindex[i*m->nbEBands+j] = -1;
+ /* Find other bands that have the same size */
+ for (k=0;k<=i;k++)
+ {
+ int n;
+ for (n=0;n<m->nbEBands && (k!=i || n<j);n++)
+ {
+ if (N == (eBands[n+1]-eBands[n])<<k>>1)
+ {
+ cindex[i*m->nbEBands+j] = cindex[k*m->nbEBands+n];
+ break;
+ }
+ }
+ }
+ if (cache->index[i*m->nbEBands+j] == -1 && N!=0)
+ {
+ int K;
+ entryN[nbEntries] = N;
+ K = 0;
+ while (fits_in32(N,get_pulses(K+1)) && K<MAX_PSEUDO)
+ K++;
+ entryK[nbEntries] = K;
+ cindex[i*m->nbEBands+j] = curr;
+ entryI[nbEntries] = curr;
+
+ curr += K+1;
+ nbEntries++;
+ }
+ }
+ }
+ bits = (unsigned char *)opus_alloc(sizeof(unsigned char)*curr);
+ cache->bits = bits;
+ cache->size = curr;
+ /* Compute the cache for all unique sizes */
+ for (i=0;i<nbEntries;i++)
+ {
+ unsigned char *ptr = bits+entryI[i];
+ opus_int16 tmp[CELT_MAX_PULSES+1];
+ get_required_bits(tmp, entryN[i], get_pulses(entryK[i]), BITRES);
+ for (j=1;j<=entryK[i];j++)
+ ptr[j] = tmp[get_pulses(j)]-1;
+ ptr[0] = entryK[i];
+ }
+
+ /* Compute the maximum rate for each band at which we'll reliably use as
+ many bits as we ask for. */
+ cache->caps = cap = (unsigned char *)opus_alloc(sizeof(cache->caps[0])*(LM+1)*2*m->nbEBands);
+ for (i=0;i<=LM;i++)
+ {
+ for (C=1;C<=2;C++)
+ {
+ for (j=0;j<m->nbEBands;j++)
+ {
+ int N0;
+ int max_bits;
+ N0 = m->eBands[j+1]-m->eBands[j];
+ /* N=1 bands only have a sign bit and fine bits. */
+ if (N0<<i == 1)
+ max_bits = C*(1+MAX_FINE_BITS)<<BITRES;
+ else
+ {
+ const unsigned char *pcache;
+ opus_int32 num;
+ opus_int32 den;
+ int LM0;
+ int N;
+ int offset;
+ int ndof;
+ int qb;
+ int k;
+ LM0 = 0;
+ /* Even-sized bands bigger than N=2 can be split one more time.
+ As of commit 44203907 all bands >1 are even, including custom modes.*/
+ if (N0 > 2)
+ {
+ N0>>=1;
+ LM0--;
+ }
+ /* N0=1 bands can't be split down to N<2. */
+ else if (N0 <= 1)
+ {
+ LM0=IMIN(i,1);
+ N0<<=LM0;
+ }
+ /* Compute the cost for the lowest-level PVQ of a fully split
+ band. */
+ pcache = bits + cindex[(LM0+1)*m->nbEBands+j];
+ max_bits = pcache[pcache[0]]+1;
+ /* Add in the cost of coding regular splits. */
+ N = N0;
+ for(k=0;k<i-LM0;k++){
+ max_bits <<= 1;
+ /* Offset the number of qtheta bits by log2(N)/2
+ + QTHETA_OFFSET compared to their "fair share" of
+ total/N */
+ offset = ((m->logN[j]+((LM0+k)<<BITRES))>>1)-QTHETA_OFFSET;
+ /* The number of qtheta bits we'll allocate if the remainder
+ is to be max_bits.
+ The average measured cost for theta is 0.89701 times qb,
+ approximated here as 459/512. */
+ num=459*(opus_int32)((2*N-1)*offset+max_bits);
+ den=((opus_int32)(2*N-1)<<9)-459;
+ qb = IMIN((num+(den>>1))/den, 57);
+ celt_assert(qb >= 0);
+ max_bits += qb;
+ N <<= 1;
+ }
+ /* Add in the cost of a stereo split, if necessary. */
+ if (C==2)
+ {
+ max_bits <<= 1;
+ offset = ((m->logN[j]+(i<<BITRES))>>1)-(N==2?QTHETA_OFFSET_TWOPHASE:QTHETA_OFFSET);
+ ndof = 2*N-1-(N==2);
+ /* The average measured cost for theta with the step PDF is
+ 0.95164 times qb, approximated here as 487/512. */
+ num = (N==2?512:487)*(opus_int32)(max_bits+ndof*offset);
+ den = ((opus_int32)ndof<<9)-(N==2?512:487);
+ qb = IMIN((num+(den>>1))/den, (N==2?64:61));
+ celt_assert(qb >= 0);
+ max_bits += qb;
+ }
+ /* Add the fine bits we'll use. */
+ /* Compensate for the extra DoF in stereo */
+ ndof = C*N + ((C==2 && N>2) ? 1 : 0);
+ /* Offset the number of fine bits by log2(N)/2 + FINE_OFFSET
+ compared to their "fair share" of total/N */
+ offset = ((m->logN[j] + (i<<BITRES))>>1)-FINE_OFFSET;
+ /* N=2 is the only point that doesn't match the curve */
+ if (N==2)
+ offset += 1<<BITRES>>2;
+ /* The number of fine bits we'll allocate if the remainder is
+ to be max_bits. */
+ num = max_bits+ndof*offset;
+ den = (ndof-1)<<BITRES;
+ qb = IMIN((num+(den>>1))/den, MAX_FINE_BITS);
+ celt_assert(qb >= 0);
+ max_bits += C*qb<<BITRES;
+ }
+ max_bits = (4*max_bits/(C*((m->eBands[j+1]-m->eBands[j])<<i)))-64;
+ celt_assert(max_bits >= 0);
+ celt_assert(max_bits < 256);
+ *cap++ = (unsigned char)max_bits;
+ }
+ }
+ }
+}
+
+#endif /* CUSTOM_MODES */
+
+#define ALLOC_STEPS 6
+
+static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end, int skip_start,
+ const int *bits1, const int *bits2, const int *thresh, const int *cap, opus_int32 total, opus_int32 *_balance,
+ int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, int *bits,
+ int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth)
+{
+ opus_int32 psum;
+ int lo, hi;
+ int i, j;
+ int logM;
+ int stereo;
+ int codedBands=-1;
+ int alloc_floor;
+ opus_int32 left, percoeff;
+ int done;
+ opus_int32 balance;
+ SAVE_STACK;
+
+ alloc_floor = C<<BITRES;
+ stereo = C>1;
+
+ logM = LM<<BITRES;
+ lo = 0;
+ hi = 1<<ALLOC_STEPS;
+ for (i=0;i<ALLOC_STEPS;i++)
+ {
+ int mid = (lo+hi)>>1;
+ psum = 0;
+ done = 0;
+ for (j=end;j-->start;)
+ {
+ int tmp = bits1[j] + (mid*(opus_int32)bits2[j]>>ALLOC_STEPS);
+ if (tmp >= thresh[j] || done)
+ {
+ done = 1;
+ /* Don't allocate more than we can actually use */
+ psum += IMIN(tmp, cap[j]);
+ } else {
+ if (tmp >= alloc_floor)
+ psum += alloc_floor;
+ }
+ }
+ if (psum > total)
+ hi = mid;
+ else
+ lo = mid;
+ }
+ psum = 0;
+ /*printf ("interp bisection gave %d\n", lo);*/
+ done = 0;
+ for (j=end;j-->start;)
+ {
+ int tmp = bits1[j] + ((opus_int32)lo*bits2[j]>>ALLOC_STEPS);
+ if (tmp < thresh[j] && !done)
+ {
+ if (tmp >= alloc_floor)
+ tmp = alloc_floor;
+ else
+ tmp = 0;
+ } else
+ done = 1;
+ /* Don't allocate more than we can actually use */
+ tmp = IMIN(tmp, cap[j]);
+ bits[j] = tmp;
+ psum += tmp;
+ }
+
+ /* Decide which bands to skip, working backwards from the end. */
+ for (codedBands=end;;codedBands--)
+ {
+ int band_width;
+ int band_bits;
+ int rem;
+ j = codedBands-1;
+ /* Never skip the first band, nor a band that has been boosted by
+ dynalloc.
+ In the first case, we'd be coding a bit to signal we're going to waste
+ all the other bits.
+ In the second case, we'd be coding a bit to redistribute all the bits
+ we just signaled should be cocentrated in this band. */
+ if (j<=skip_start)
+ {
+ /* Give the bit we reserved to end skipping back. */
+ total += skip_rsv;
+ break;
+ }
+ /*Figure out how many left-over bits we would be adding to this band.
+ This can include bits we've stolen back from higher, skipped bands.*/
+ left = total-psum;
+ percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]);
+ left -= (m->eBands[codedBands]-m->eBands[start])*percoeff;
+ rem = IMAX(left-(m->eBands[j]-m->eBands[start]),0);
+ band_width = m->eBands[codedBands]-m->eBands[j];
+ band_bits = (int)(bits[j] + percoeff*band_width + rem);
+ /*Only code a skip decision if we're above the threshold for this band.
+ Otherwise it is force-skipped.
+ This ensures that we have enough bits to code the skip flag.*/
+ if (band_bits >= IMAX(thresh[j], alloc_floor+(1<<BITRES)))
+ {
+ if (encode)
+ {
+ /*This if() block is the only part of the allocation function that
+ is not a mandatory part of the bitstream: any bands we choose to
+ skip here must be explicitly signaled.*/
+ /*Choose a threshold with some hysteresis to keep bands from
+ fluctuating in and out.*/
+#ifdef FUZZING
+ if ((rand()&0x1) == 0)
+#else
+ if (codedBands<=start+2 || (band_bits > ((j<prev?7:9)*band_width<<LM<<BITRES)>>4 && j<=signalBandwidth))
+#endif
+ {
+ ec_enc_bit_logp(ec, 1, 1);
+ break;
+ }
+ ec_enc_bit_logp(ec, 0, 1);
+ } else if (ec_dec_bit_logp(ec, 1)) {
+ break;
+ }
+ /*We used a bit to skip this band.*/
+ psum += 1<<BITRES;
+ band_bits -= 1<<BITRES;
+ }
+ /*Reclaim the bits originally allocated to this band.*/
+ psum -= bits[j]+intensity_rsv;
+ if (intensity_rsv > 0)
+ intensity_rsv = LOG2_FRAC_TABLE[j-start];
+ psum += intensity_rsv;
+ if (band_bits >= alloc_floor)
+ {
+ /*If we have enough for a fine energy bit per channel, use it.*/
+ psum += alloc_floor;
+ bits[j] = alloc_floor;
+ } else {
+ /*Otherwise this band gets nothing at all.*/
+ bits[j] = 0;
+ }
+ }
+
+ celt_assert(codedBands > start);
+ /* Code the intensity and dual stereo parameters. */
+ if (intensity_rsv > 0)
+ {
+ if (encode)
+ {
+ *intensity = IMIN(*intensity, codedBands);
+ ec_enc_uint(ec, *intensity-start, codedBands+1-start);
+ }
+ else
+ *intensity = start+ec_dec_uint(ec, codedBands+1-start);
+ }
+ else
+ *intensity = 0;
+ if (*intensity <= start)
+ {
+ total += dual_stereo_rsv;
+ dual_stereo_rsv = 0;
+ }
+ if (dual_stereo_rsv > 0)
+ {
+ if (encode)
+ ec_enc_bit_logp(ec, *dual_stereo, 1);
+ else
+ *dual_stereo = ec_dec_bit_logp(ec, 1);
+ }
+ else
+ *dual_stereo = 0;
+
+ /* Allocate the remaining bits */
+ left = total-psum;
+ percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]);
+ left -= (m->eBands[codedBands]-m->eBands[start])*percoeff;
+ for (j=start;j<codedBands;j++)
+ bits[j] += ((int)percoeff*(m->eBands[j+1]-m->eBands[j]));
+ for (j=start;j<codedBands;j++)
+ {
+ int tmp = (int)IMIN(left, m->eBands[j+1]-m->eBands[j]);
+ bits[j] += tmp;
+ left -= tmp;
+ }
+ /*for (j=0;j<end;j++)printf("%d ", bits[j]);printf("\n");*/
+
+ balance = 0;
+ for (j=start;j<codedBands;j++)
+ {
+ int N0, N, den;
+ int offset;
+ int NClogN;
+ opus_int32 excess, bit;
+
+ celt_assert(bits[j] >= 0);
+ N0 = m->eBands[j+1]-m->eBands[j];
+ N=N0<<LM;
+ bit = (opus_int32)bits[j]+balance;
+
+ if (N>1)
+ {
+ excess = MAX32(bit-cap[j],0);
+ bits[j] = bit-excess;
+
+ /* Compensate for the extra DoF in stereo */
+ den=(C*N+ ((C==2 && N>2 && !*dual_stereo && j<*intensity) ? 1 : 0));
+
+ NClogN = den*(m->logN[j] + logM);
+
+ /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET
+ compared to their "fair share" of total/N */
+ offset = (NClogN>>1)-den*FINE_OFFSET;
+
+ /* N=2 is the only point that doesn't match the curve */
+ if (N==2)
+ offset += den<<BITRES>>2;
+
+ /* Changing the offset for allocating the second and third
+ fine energy bit */
+ if (bits[j] + offset < den*2<<BITRES)
+ offset += NClogN>>2;
+ else if (bits[j] + offset < den*3<<BITRES)
+ offset += NClogN>>3;
+
+ /* Divide with rounding */
+ ebits[j] = IMAX(0, (bits[j] + offset + (den<<(BITRES-1))));
+ ebits[j] = celt_udiv(ebits[j], den)>>BITRES;
+
+ /* Make sure not to bust */
+ if (C*ebits[j] > (bits[j]>>BITRES))
+ ebits[j] = bits[j] >> stereo >> BITRES;
+
+ /* More than that is useless because that's about as far as PVQ can go */
+ ebits[j] = IMIN(ebits[j], MAX_FINE_BITS);
+
+ /* If we rounded down or capped this band, make it a candidate for the
+ final fine energy pass */
+ fine_priority[j] = ebits[j]*(den<<BITRES) >= bits[j]+offset;
+
+ /* Remove the allocated fine bits; the rest are assigned to PVQ */
+ bits[j] -= C*ebits[j]<<BITRES;
+
+ } else {
+ /* For N=1, all bits go to fine energy except for a single sign bit */
+ excess = MAX32(0,bit-(C<<BITRES));
+ bits[j] = bit-excess;
+ ebits[j] = 0;
+ fine_priority[j] = 1;
+ }
+
+ /* Fine energy can't take advantage of the re-balancing in
+ quant_all_bands().
+ Instead, do the re-balancing here.*/
+ if(excess > 0)
+ {
+ int extra_fine;
+ int extra_bits;
+ extra_fine = IMIN(excess>>(stereo+BITRES),MAX_FINE_BITS-ebits[j]);
+ ebits[j] += extra_fine;
+ extra_bits = extra_fine*C<<BITRES;
+ fine_priority[j] = extra_bits >= excess-balance;
+ excess -= extra_bits;
+ }
+ balance = excess;
+
+ celt_assert(bits[j] >= 0);
+ celt_assert(ebits[j] >= 0);
+ }
+ /* Save any remaining bits over the cap for the rebalancing in
+ quant_all_bands(). */
+ *_balance = balance;
+
+ /* The skipped bands use all their bits for fine energy. */
+ for (;j<end;j++)
+ {
+ ebits[j] = bits[j] >> stereo >> BITRES;
+ celt_assert(C*ebits[j]<<BITRES == bits[j]);
+ bits[j] = 0;
+ fine_priority[j] = ebits[j]<1;
+ }
+ RESTORE_STACK;
+ return codedBands;
+}
+
+int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo,
+ opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth)
+{
+ int lo, hi, len, j;
+ int codedBands;
+ int skip_start;
+ int skip_rsv;
+ int intensity_rsv;
+ int dual_stereo_rsv;
+ VARDECL(int, bits1);
+ VARDECL(int, bits2);
+ VARDECL(int, thresh);
+ VARDECL(int, trim_offset);
+ SAVE_STACK;
+
+ total = IMAX(total, 0);
+ len = m->nbEBands;
+ skip_start = start;
+ /* Reserve a bit to signal the end of manually skipped bands. */
+ skip_rsv = total >= 1<<BITRES ? 1<<BITRES : 0;
+ total -= skip_rsv;
+ /* Reserve bits for the intensity and dual stereo parameters. */
+ intensity_rsv = dual_stereo_rsv = 0;
+ if (C==2)
+ {
+ intensity_rsv = LOG2_FRAC_TABLE[end-start];
+ if (intensity_rsv>total)
+ intensity_rsv = 0;
+ else
+ {
+ total -= intensity_rsv;
+ dual_stereo_rsv = total>=1<<BITRES ? 1<<BITRES : 0;
+ total -= dual_stereo_rsv;
+ }
+ }
+ ALLOC(bits1, len, int);
+ ALLOC(bits2, len, int);
+ ALLOC(thresh, len, int);
+ ALLOC(trim_offset, len, int);
+
+ for (j=start;j<end;j++)
+ {
+ /* Below this threshold, we're sure not to allocate any PVQ bits */
+ thresh[j] = IMAX((C)<<BITRES, (3*(m->eBands[j+1]-m->eBands[j])<<LM<<BITRES)>>4);
+ /* Tilt of the allocation curve */
+ trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-5-LM)*(end-j-1)
+ *(1<<(LM+BITRES))>>6;
+ /* Giving less resolution to single-coefficient bands because they get
+ more benefit from having one coarse value per coefficient*/
+ if ((m->eBands[j+1]-m->eBands[j])<<LM==1)
+ trim_offset[j] -= C<<BITRES;
+ }
+ lo = 1;
+ hi = m->nbAllocVectors - 1;
+ do
+ {
+ int done = 0;
+ int psum = 0;
+ int mid = (lo+hi) >> 1;
+ for (j=end;j-->start;)
+ {
+ int bitsj;
+ int N = m->eBands[j+1]-m->eBands[j];
+ bitsj = C*N*m->allocVectors[mid*len+j]<<LM>>2;
+ if (bitsj > 0)
+ bitsj = IMAX(0, bitsj + trim_offset[j]);
+ bitsj += offsets[j];
+ if (bitsj >= thresh[j] || done)
+ {
+ done = 1;
+ /* Don't allocate more than we can actually use */
+ psum += IMIN(bitsj, cap[j]);
+ } else {
+ if (bitsj >= C<<BITRES)
+ psum += C<<BITRES;
+ }
+ }
+ if (psum > total)
+ hi = mid - 1;
+ else
+ lo = mid + 1;
+ /*printf ("lo = %d, hi = %d\n", lo, hi);*/
+ }
+ while (lo <= hi);
+ hi = lo--;
+ /*printf ("interp between %d and %d\n", lo, hi);*/
+ for (j=start;j<end;j++)
+ {
+ int bits1j, bits2j;
+ int N = m->eBands[j+1]-m->eBands[j];
+ bits1j = C*N*m->allocVectors[lo*len+j]<<LM>>2;
+ bits2j = hi>=m->nbAllocVectors ?
+ cap[j] : C*N*m->allocVectors[hi*len+j]<<LM>>2;
+ if (bits1j > 0)
+ bits1j = IMAX(0, bits1j + trim_offset[j]);
+ if (bits2j > 0)
+ bits2j = IMAX(0, bits2j + trim_offset[j]);
+ if (lo > 0)
+ bits1j += offsets[j];
+ bits2j += offsets[j];
+ if (offsets[j]>0)
+ skip_start = j;
+ bits2j = IMAX(0,bits2j-bits1j);
+ bits1[j] = bits1j;
+ bits2[j] = bits2j;
+ }
+ codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap,
+ total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv,
+ pulses, ebits, fine_priority, C, LM, ec, encode, prev, signalBandwidth);
+ RESTORE_STACK;
+ return codedBands;
+}
+
diff --git a/external/opus-1.1.4/celt/rate.h b/external/opus-1.1.4/celt/rate.h
new file mode 100644
index 0000000..515f768
--- /dev/null
+++ b/external/opus-1.1.4/celt/rate.h
@@ -0,0 +1,101 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef RATE_H
+#define RATE_H
+
+#define MAX_PSEUDO 40
+#define LOG_MAX_PSEUDO 6
+
+#define CELT_MAX_PULSES 128
+
+#define MAX_FINE_BITS 8
+
+#define FINE_OFFSET 21
+#define QTHETA_OFFSET 4
+#define QTHETA_OFFSET_TWOPHASE 16
+
+#include "cwrs.h"
+#include "modes.h"
+
+void compute_pulse_cache(CELTMode *m, int LM);
+
+static OPUS_INLINE int get_pulses(int i)
+{
+ return i<8 ? i : (8 + (i&7)) << ((i>>3)-1);
+}
+
+static OPUS_INLINE int bits2pulses(const CELTMode *m, int band, int LM, int bits)
+{
+ int i;
+ int lo, hi;
+ const unsigned char *cache;
+
+ LM++;
+ cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band];
+
+ lo = 0;
+ hi = cache[0];
+ bits--;
+ for (i=0;i<LOG_MAX_PSEUDO;i++)
+ {
+ int mid = (lo+hi+1)>>1;
+ /* OPT: Make sure this is implemented with a conditional move */
+ if ((int)cache[mid] >= bits)
+ hi = mid;
+ else
+ lo = mid;
+ }
+ if (bits- (lo == 0 ? -1 : (int)cache[lo]) <= (int)cache[hi]-bits)
+ return lo;
+ else
+ return hi;
+}
+
+static OPUS_INLINE int pulses2bits(const CELTMode *m, int band, int LM, int pulses)
+{
+ const unsigned char *cache;
+
+ LM++;
+ cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band];
+ return pulses == 0 ? 0 : cache[pulses]+1;
+}
+
+/** Compute the pulse allocation, i.e. how many pulses will go in each
+ * band.
+ @param m mode
+ @param offsets Requested increase or decrease in the number of bits for
+ each band
+ @param total Number of bands
+ @param pulses Number of pulses per band (returned)
+ @return Total number of bits allocated
+*/
+int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stero,
+ opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth);
+
+#endif
diff --git a/external/opus-1.1.4/celt/stack_alloc.h b/external/opus-1.1.4/celt/stack_alloc.h
new file mode 100644
index 0000000..2b51c8d
--- /dev/null
+++ b/external/opus-1.1.4/celt/stack_alloc.h
@@ -0,0 +1,184 @@
+/* Copyright (C) 2002-2003 Jean-Marc Valin
+ Copyright (C) 2007-2009 Xiph.Org Foundation */
+/**
+ @file stack_alloc.h
+ @brief Temporary memory allocation on stack
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef STACK_ALLOC_H
+#define STACK_ALLOC_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#if (!defined (VAR_ARRAYS) && !defined (USE_ALLOCA) && !defined (NONTHREADSAFE_PSEUDOSTACK))
+#error "Opus requires one of VAR_ARRAYS, USE_ALLOCA, or NONTHREADSAFE_PSEUDOSTACK be defined to select the temporary allocation mode."
+#endif
+
+#ifdef USE_ALLOCA
+# ifdef WIN32
+# include <malloc.h>
+# else
+# ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# include <stdlib.h>
+# endif
+# endif
+#endif
+
+/**
+ * @def ALIGN(stack, size)
+ *
+ * Aligns the stack to a 'size' boundary
+ *
+ * @param stack Stack
+ * @param size New size boundary
+ */
+
+/**
+ * @def PUSH(stack, size, type)
+ *
+ * Allocates 'size' elements of type 'type' on the stack
+ *
+ * @param stack Stack
+ * @param size Number of elements
+ * @param type Type of element
+ */
+
+/**
+ * @def VARDECL(var)
+ *
+ * Declare variable on stack
+ *
+ * @param var Variable to declare
+ */
+
+/**
+ * @def ALLOC(var, size, type)
+ *
+ * Allocate 'size' elements of 'type' on stack
+ *
+ * @param var Name of variable to allocate
+ * @param size Number of elements
+ * @param type Type of element
+ */
+
+#if defined(VAR_ARRAYS)
+
+#define VARDECL(type, var)
+#define ALLOC(var, size, type) type var[size]
+#define SAVE_STACK
+#define RESTORE_STACK
+#define ALLOC_STACK
+/* C99 does not allow VLAs of size zero */
+#define ALLOC_NONE 1
+
+#elif defined(USE_ALLOCA)
+
+#define VARDECL(type, var) type *var
+
+# ifdef WIN32
+# define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size)))
+# else
+# define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size)))
+# endif
+
+#define SAVE_STACK
+#define RESTORE_STACK
+#define ALLOC_STACK
+#define ALLOC_NONE 0
+
+#else
+
+#ifdef CELT_C
+char *scratch_ptr=0;
+char *global_stack=0;
+#else
+extern char *global_stack;
+extern char *scratch_ptr;
+#endif /* CELT_C */
+
+#ifdef ENABLE_VALGRIND
+
+#include <valgrind/memcheck.h>
+
+#ifdef CELT_C
+char *global_stack_top=0;
+#else
+extern char *global_stack_top;
+#endif /* CELT_C */
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+#define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char))))
+#define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack))
+#define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=opus_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack;
+
+#else
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/sizeof(char)),(stack)+=(size)*(sizeof(type)/sizeof(char)),(type*)((stack)-(size)*(sizeof(type)/sizeof(char))))
+#if 0 /* Set this to 1 to instrument pseudostack usage */
+#define RESTORE_STACK (printf("%ld %s:%d\n", global_stack-scratch_ptr, __FILE__, __LINE__),global_stack = _saved_stack)
+#else
+#define RESTORE_STACK (global_stack = _saved_stack)
+#endif
+#define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? (scratch_ptr=opus_alloc_scratch(GLOBAL_STACK_SIZE)) : global_stack); _saved_stack = global_stack;
+
+#endif /* ENABLE_VALGRIND */
+
+#include "os_support.h"
+#define VARDECL(type, var) type *var
+#define ALLOC(var, size, type) var = PUSH(global_stack, size, type)
+#define SAVE_STACK char *_saved_stack = global_stack;
+#define ALLOC_NONE 0
+
+#endif /* VAR_ARRAYS */
+
+
+#ifdef ENABLE_VALGRIND
+
+#include <valgrind/memcheck.h>
+#define OPUS_CHECK_ARRAY(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
+#define OPUS_CHECK_VALUE(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
+#define OPUS_CHECK_ARRAY_COND(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
+#define OPUS_CHECK_VALUE_COND(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
+#define OPUS_PRINT_INT(value) do {fprintf(stderr, #value " = %d at %s:%d\n", value, __FILE__, __LINE__);}while(0)
+#define OPUS_FPRINTF fprintf
+
+#else
+
+static OPUS_INLINE int _opus_false(void) {return 0;}
+#define OPUS_CHECK_ARRAY(ptr, len) _opus_false()
+#define OPUS_CHECK_VALUE(value) _opus_false()
+#define OPUS_PRINT_INT(value) do{}while(0)
+#define OPUS_FPRINTF (void)
+
+#endif
+
+
+#endif /* STACK_ALLOC_H */
diff --git a/external/opus-1.1.4/celt/static_modes_fixed.h b/external/opus-1.1.4/celt/static_modes_fixed.h
new file mode 100644
index 0000000..8717d62
--- /dev/null
+++ b/external/opus-1.1.4/celt/static_modes_fixed.h
@@ -0,0 +1,892 @@
+/* The contents of this file was automatically generated by dump_modes.c
+ with arguments: 48000 960
+ It contains static definitions for some pre-defined modes. */
+#include "modes.h"
+#include "rate.h"
+
+#ifdef HAVE_ARM_NE10
+#define OVERRIDE_FFT 1
+#include "static_modes_fixed_arm_ne10.h"
+#endif
+
+#ifndef DEF_WINDOW120
+#define DEF_WINDOW120
+static const opus_val16 window120[120] = {
+2, 20, 55, 108, 178,
+266, 372, 494, 635, 792,
+966, 1157, 1365, 1590, 1831,
+2089, 2362, 2651, 2956, 3276,
+3611, 3961, 4325, 4703, 5094,
+5499, 5916, 6346, 6788, 7241,
+7705, 8179, 8663, 9156, 9657,
+10167, 10684, 11207, 11736, 12271,
+12810, 13353, 13899, 14447, 14997,
+15547, 16098, 16648, 17197, 17744,
+18287, 18827, 19363, 19893, 20418,
+20936, 21447, 21950, 22445, 22931,
+23407, 23874, 24330, 24774, 25208,
+25629, 26039, 26435, 26819, 27190,
+27548, 27893, 28224, 28541, 28845,
+29135, 29411, 29674, 29924, 30160,
+30384, 30594, 30792, 30977, 31151,
+31313, 31463, 31602, 31731, 31849,
+31958, 32057, 32148, 32229, 32303,
+32370, 32429, 32481, 32528, 32568,
+32604, 32634, 32661, 32683, 32701,
+32717, 32729, 32740, 32748, 32754,
+32758, 32762, 32764, 32766, 32767,
+32767, 32767, 32767, 32767, 32767,
+};
+#endif
+
+#ifndef DEF_LOGN400
+#define DEF_LOGN400
+static const opus_int16 logN400[21] = {
+0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, };
+#endif
+
+#ifndef DEF_PULSE_CACHE50
+#define DEF_PULSE_CACHE50
+static const opus_int16 cache_index50[105] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41,
+82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41,
+41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41,
+41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305,
+318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240,
+305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240,
+240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387,
+};
+static const unsigned char cache_bits50[392] = {
+40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28,
+31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50,
+51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65,
+66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61,
+64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92,
+94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123,
+124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94,
+97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139,
+142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35,
+28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149,
+153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225,
+229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157,
+166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63,
+86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250,
+25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180,
+185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89,
+110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41,
+74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138,
+163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214,
+228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49,
+90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47,
+87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57,
+106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187,
+224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127,
+182, 234, };
+static const unsigned char cache_caps50[168] = {
+224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185,
+178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240,
+240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160,
+160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172,
+138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207,
+204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185,
+185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39,
+207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201,
+188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204,
+204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175,
+140, 66, 40, };
+#endif
+
+#ifndef FFT_TWIDDLES48000_960
+#define FFT_TWIDDLES48000_960
+static const kiss_twiddle_cpx fft_twiddles48000_960[480] = {
+{32767, 0}, {32766, -429},
+{32757, -858}, {32743, -1287},
+{32724, -1715}, {32698, -2143},
+{32667, -2570}, {32631, -2998},
+{32588, -3425}, {32541, -3851},
+{32488, -4277}, {32429, -4701},
+{32364, -5125}, {32295, -5548},
+{32219, -5971}, {32138, -6393},
+{32051, -6813}, {31960, -7231},
+{31863, -7650}, {31760, -8067},
+{31652, -8481}, {31539, -8895},
+{31419, -9306}, {31294, -9716},
+{31165, -10126}, {31030, -10532},
+{30889, -10937}, {30743, -11340},
+{30592, -11741}, {30436, -12141},
+{30274, -12540}, {30107, -12935},
+{29936, -13328}, {29758, -13718},
+{29577, -14107}, {29390, -14493},
+{29197, -14875}, {29000, -15257},
+{28797, -15635}, {28590, -16010},
+{28379, -16384}, {28162, -16753},
+{27940, -17119}, {27714, -17484},
+{27482, -17845}, {27246, -18205},
+{27006, -18560}, {26760, -18911},
+{26510, -19260}, {26257, -19606},
+{25997, -19947}, {25734, -20286},
+{25466, -20621}, {25194, -20952},
+{24918, -21281}, {24637, -21605},
+{24353, -21926}, {24063, -22242},
+{23770, -22555}, {23473, -22865},
+{23171, -23171}, {22866, -23472},
+{22557, -23769}, {22244, -24063},
+{21927, -24352}, {21606, -24636},
+{21282, -24917}, {20954, -25194},
+{20622, -25465}, {20288, -25733},
+{19949, -25997}, {19607, -26255},
+{19261, -26509}, {18914, -26760},
+{18561, -27004}, {18205, -27246},
+{17846, -27481}, {17485, -27713},
+{17122, -27940}, {16755, -28162},
+{16385, -28378}, {16012, -28590},
+{15636, -28797}, {15258, -28999},
+{14878, -29197}, {14494, -29389},
+{14108, -29576}, {13720, -29757},
+{13329, -29934}, {12937, -30107},
+{12540, -30274}, {12142, -30435},
+{11744, -30592}, {11342, -30743},
+{10939, -30889}, {10534, -31030},
+{10127, -31164}, {9718, -31294},
+{9307, -31418}, {8895, -31537},
+{8482, -31652}, {8067, -31759},
+{7650, -31862}, {7233, -31960},
+{6815, -32051}, {6393, -32138},
+{5973, -32219}, {5549, -32294},
+{5127, -32364}, {4703, -32429},
+{4278, -32487}, {3852, -32541},
+{3426, -32588}, {2999, -32630},
+{2572, -32667}, {2144, -32698},
+{1716, -32724}, {1287, -32742},
+{860, -32757}, {430, -32766},
+{0, -32767}, {-429, -32766},
+{-858, -32757}, {-1287, -32743},
+{-1715, -32724}, {-2143, -32698},
+{-2570, -32667}, {-2998, -32631},
+{-3425, -32588}, {-3851, -32541},
+{-4277, -32488}, {-4701, -32429},
+{-5125, -32364}, {-5548, -32295},
+{-5971, -32219}, {-6393, -32138},
+{-6813, -32051}, {-7231, -31960},
+{-7650, -31863}, {-8067, -31760},
+{-8481, -31652}, {-8895, -31539},
+{-9306, -31419}, {-9716, -31294},
+{-10126, -31165}, {-10532, -31030},
+{-10937, -30889}, {-11340, -30743},
+{-11741, -30592}, {-12141, -30436},
+{-12540, -30274}, {-12935, -30107},
+{-13328, -29936}, {-13718, -29758},
+{-14107, -29577}, {-14493, -29390},
+{-14875, -29197}, {-15257, -29000},
+{-15635, -28797}, {-16010, -28590},
+{-16384, -28379}, {-16753, -28162},
+{-17119, -27940}, {-17484, -27714},
+{-17845, -27482}, {-18205, -27246},
+{-18560, -27006}, {-18911, -26760},
+{-19260, -26510}, {-19606, -26257},
+{-19947, -25997}, {-20286, -25734},
+{-20621, -25466}, {-20952, -25194},
+{-21281, -24918}, {-21605, -24637},
+{-21926, -24353}, {-22242, -24063},
+{-22555, -23770}, {-22865, -23473},
+{-23171, -23171}, {-23472, -22866},
+{-23769, -22557}, {-24063, -22244},
+{-24352, -21927}, {-24636, -21606},
+{-24917, -21282}, {-25194, -20954},
+{-25465, -20622}, {-25733, -20288},
+{-25997, -19949}, {-26255, -19607},
+{-26509, -19261}, {-26760, -18914},
+{-27004, -18561}, {-27246, -18205},
+{-27481, -17846}, {-27713, -17485},
+{-27940, -17122}, {-28162, -16755},
+{-28378, -16385}, {-28590, -16012},
+{-28797, -15636}, {-28999, -15258},
+{-29197, -14878}, {-29389, -14494},
+{-29576, -14108}, {-29757, -13720},
+{-29934, -13329}, {-30107, -12937},
+{-30274, -12540}, {-30435, -12142},
+{-30592, -11744}, {-30743, -11342},
+{-30889, -10939}, {-31030, -10534},
+{-31164, -10127}, {-31294, -9718},
+{-31418, -9307}, {-31537, -8895},
+{-31652, -8482}, {-31759, -8067},
+{-31862, -7650}, {-31960, -7233},
+{-32051, -6815}, {-32138, -6393},
+{-32219, -5973}, {-32294, -5549},
+{-32364, -5127}, {-32429, -4703},
+{-32487, -4278}, {-32541, -3852},
+{-32588, -3426}, {-32630, -2999},
+{-32667, -2572}, {-32698, -2144},
+{-32724, -1716}, {-32742, -1287},
+{-32757, -860}, {-32766, -430},
+{-32767, 0}, {-32766, 429},
+{-32757, 858}, {-32743, 1287},
+{-32724, 1715}, {-32698, 2143},
+{-32667, 2570}, {-32631, 2998},
+{-32588, 3425}, {-32541, 3851},
+{-32488, 4277}, {-32429, 4701},
+{-32364, 5125}, {-32295, 5548},
+{-32219, 5971}, {-32138, 6393},
+{-32051, 6813}, {-31960, 7231},
+{-31863, 7650}, {-31760, 8067},
+{-31652, 8481}, {-31539, 8895},
+{-31419, 9306}, {-31294, 9716},
+{-31165, 10126}, {-31030, 10532},
+{-30889, 10937}, {-30743, 11340},
+{-30592, 11741}, {-30436, 12141},
+{-30274, 12540}, {-30107, 12935},
+{-29936, 13328}, {-29758, 13718},
+{-29577, 14107}, {-29390, 14493},
+{-29197, 14875}, {-29000, 15257},
+{-28797, 15635}, {-28590, 16010},
+{-28379, 16384}, {-28162, 16753},
+{-27940, 17119}, {-27714, 17484},
+{-27482, 17845}, {-27246, 18205},
+{-27006, 18560}, {-26760, 18911},
+{-26510, 19260}, {-26257, 19606},
+{-25997, 19947}, {-25734, 20286},
+{-25466, 20621}, {-25194, 20952},
+{-24918, 21281}, {-24637, 21605},
+{-24353, 21926}, {-24063, 22242},
+{-23770, 22555}, {-23473, 22865},
+{-23171, 23171}, {-22866, 23472},
+{-22557, 23769}, {-22244, 24063},
+{-21927, 24352}, {-21606, 24636},
+{-21282, 24917}, {-20954, 25194},
+{-20622, 25465}, {-20288, 25733},
+{-19949, 25997}, {-19607, 26255},
+{-19261, 26509}, {-18914, 26760},
+{-18561, 27004}, {-18205, 27246},
+{-17846, 27481}, {-17485, 27713},
+{-17122, 27940}, {-16755, 28162},
+{-16385, 28378}, {-16012, 28590},
+{-15636, 28797}, {-15258, 28999},
+{-14878, 29197}, {-14494, 29389},
+{-14108, 29576}, {-13720, 29757},
+{-13329, 29934}, {-12937, 30107},
+{-12540, 30274}, {-12142, 30435},
+{-11744, 30592}, {-11342, 30743},
+{-10939, 30889}, {-10534, 31030},
+{-10127, 31164}, {-9718, 31294},
+{-9307, 31418}, {-8895, 31537},
+{-8482, 31652}, {-8067, 31759},
+{-7650, 31862}, {-7233, 31960},
+{-6815, 32051}, {-6393, 32138},
+{-5973, 32219}, {-5549, 32294},
+{-5127, 32364}, {-4703, 32429},
+{-4278, 32487}, {-3852, 32541},
+{-3426, 32588}, {-2999, 32630},
+{-2572, 32667}, {-2144, 32698},
+{-1716, 32724}, {-1287, 32742},
+{-860, 32757}, {-430, 32766},
+{0, 32767}, {429, 32766},
+{858, 32757}, {1287, 32743},
+{1715, 32724}, {2143, 32698},
+{2570, 32667}, {2998, 32631},
+{3425, 32588}, {3851, 32541},
+{4277, 32488}, {4701, 32429},
+{5125, 32364}, {5548, 32295},
+{5971, 32219}, {6393, 32138},
+{6813, 32051}, {7231, 31960},
+{7650, 31863}, {8067, 31760},
+{8481, 31652}, {8895, 31539},
+{9306, 31419}, {9716, 31294},
+{10126, 31165}, {10532, 31030},
+{10937, 30889}, {11340, 30743},
+{11741, 30592}, {12141, 30436},
+{12540, 30274}, {12935, 30107},
+{13328, 29936}, {13718, 29758},
+{14107, 29577}, {14493, 29390},
+{14875, 29197}, {15257, 29000},
+{15635, 28797}, {16010, 28590},
+{16384, 28379}, {16753, 28162},
+{17119, 27940}, {17484, 27714},
+{17845, 27482}, {18205, 27246},
+{18560, 27006}, {18911, 26760},
+{19260, 26510}, {19606, 26257},
+{19947, 25997}, {20286, 25734},
+{20621, 25466}, {20952, 25194},
+{21281, 24918}, {21605, 24637},
+{21926, 24353}, {22242, 24063},
+{22555, 23770}, {22865, 23473},
+{23171, 23171}, {23472, 22866},
+{23769, 22557}, {24063, 22244},
+{24352, 21927}, {24636, 21606},
+{24917, 21282}, {25194, 20954},
+{25465, 20622}, {25733, 20288},
+{25997, 19949}, {26255, 19607},
+{26509, 19261}, {26760, 18914},
+{27004, 18561}, {27246, 18205},
+{27481, 17846}, {27713, 17485},
+{27940, 17122}, {28162, 16755},
+{28378, 16385}, {28590, 16012},
+{28797, 15636}, {28999, 15258},
+{29197, 14878}, {29389, 14494},
+{29576, 14108}, {29757, 13720},
+{29934, 13329}, {30107, 12937},
+{30274, 12540}, {30435, 12142},
+{30592, 11744}, {30743, 11342},
+{30889, 10939}, {31030, 10534},
+{31164, 10127}, {31294, 9718},
+{31418, 9307}, {31537, 8895},
+{31652, 8482}, {31759, 8067},
+{31862, 7650}, {31960, 7233},
+{32051, 6815}, {32138, 6393},
+{32219, 5973}, {32294, 5549},
+{32364, 5127}, {32429, 4703},
+{32487, 4278}, {32541, 3852},
+{32588, 3426}, {32630, 2999},
+{32667, 2572}, {32698, 2144},
+{32724, 1716}, {32742, 1287},
+{32757, 860}, {32766, 430},
+};
+#ifndef FFT_BITREV480
+#define FFT_BITREV480
+static const opus_int16 fft_bitrev480[480] = {
+0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448,
+8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456,
+16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464,
+24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472,
+4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452,
+12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460,
+20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468,
+28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476,
+1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449,
+9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457,
+17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465,
+25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473,
+5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453,
+13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461,
+21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469,
+29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477,
+2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450,
+10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458,
+18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466,
+26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474,
+6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454,
+14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462,
+22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470,
+30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478,
+3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451,
+11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459,
+19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467,
+27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475,
+7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455,
+15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463,
+23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471,
+31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479,
+};
+#endif
+
+#ifndef FFT_BITREV240
+#define FFT_BITREV240
+static const opus_int16 fft_bitrev240[240] = {
+0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224,
+4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228,
+8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232,
+12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236,
+1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225,
+5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229,
+9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233,
+13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237,
+2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226,
+6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230,
+10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234,
+14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238,
+3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227,
+7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231,
+11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235,
+15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239,
+};
+#endif
+
+#ifndef FFT_BITREV120
+#define FFT_BITREV120
+static const opus_int16 fft_bitrev120[120] = {
+0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112,
+4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116,
+1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113,
+5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117,
+2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114,
+6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118,
+3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115,
+7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119,
+};
+#endif
+
+#ifndef FFT_BITREV60
+#define FFT_BITREV60
+static const opus_int16 fft_bitrev60[60] = {
+0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56,
+1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57,
+2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58,
+3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59,
+};
+#endif
+
+#ifndef FFT_STATE48000_960_0
+#define FFT_STATE48000_960_0
+static const kiss_fft_state fft_state48000_960_0 = {
+480, /* nfft */
+17476, /* scale */
+8, /* scale_shift */
+-1, /* shift */
+{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev480, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_480,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_1
+#define FFT_STATE48000_960_1
+static const kiss_fft_state fft_state48000_960_1 = {
+240, /* nfft */
+17476, /* scale */
+7, /* scale_shift */
+1, /* shift */
+{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev240, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_240,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_2
+#define FFT_STATE48000_960_2
+static const kiss_fft_state fft_state48000_960_2 = {
+120, /* nfft */
+17476, /* scale */
+6, /* scale_shift */
+2, /* shift */
+{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev120, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_120,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_3
+#define FFT_STATE48000_960_3
+static const kiss_fft_state fft_state48000_960_3 = {
+60, /* nfft */
+17476, /* scale */
+5, /* scale_shift */
+3, /* shift */
+{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev60, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_60,
+#else
+NULL,
+#endif
+};
+#endif
+
+#endif
+
+#ifndef MDCT_TWIDDLES960
+#define MDCT_TWIDDLES960
+static const opus_val16 mdct_twiddles960[1800] = {
+32767, 32767, 32767, 32766, 32765,
+32763, 32761, 32759, 32756, 32753,
+32750, 32746, 32742, 32738, 32733,
+32728, 32722, 32717, 32710, 32704,
+32697, 32690, 32682, 32674, 32666,
+32657, 32648, 32639, 32629, 32619,
+32609, 32598, 32587, 32576, 32564,
+32552, 32539, 32526, 32513, 32500,
+32486, 32472, 32457, 32442, 32427,
+32411, 32395, 32379, 32362, 32345,
+32328, 32310, 32292, 32274, 32255,
+32236, 32217, 32197, 32177, 32157,
+32136, 32115, 32093, 32071, 32049,
+32027, 32004, 31981, 31957, 31933,
+31909, 31884, 31859, 31834, 31809,
+31783, 31756, 31730, 31703, 31676,
+31648, 31620, 31592, 31563, 31534,
+31505, 31475, 31445, 31415, 31384,
+31353, 31322, 31290, 31258, 31226,
+31193, 31160, 31127, 31093, 31059,
+31025, 30990, 30955, 30920, 30884,
+30848, 30812, 30775, 30738, 30701,
+30663, 30625, 30587, 30548, 30509,
+30470, 30430, 30390, 30350, 30309,
+30269, 30227, 30186, 30144, 30102,
+30059, 30016, 29973, 29930, 29886,
+29842, 29797, 29752, 29707, 29662,
+29616, 29570, 29524, 29477, 29430,
+29383, 29335, 29287, 29239, 29190,
+29142, 29092, 29043, 28993, 28943,
+28892, 28842, 28791, 28739, 28688,
+28636, 28583, 28531, 28478, 28425,
+28371, 28317, 28263, 28209, 28154,
+28099, 28044, 27988, 27932, 27876,
+27820, 27763, 27706, 27648, 27591,
+27533, 27474, 27416, 27357, 27298,
+27238, 27178, 27118, 27058, 26997,
+26936, 26875, 26814, 26752, 26690,
+26628, 26565, 26502, 26439, 26375,
+26312, 26247, 26183, 26119, 26054,
+25988, 25923, 25857, 25791, 25725,
+25658, 25592, 25524, 25457, 25389,
+25322, 25253, 25185, 25116, 25047,
+24978, 24908, 24838, 24768, 24698,
+24627, 24557, 24485, 24414, 24342,
+24270, 24198, 24126, 24053, 23980,
+23907, 23834, 23760, 23686, 23612,
+23537, 23462, 23387, 23312, 23237,
+23161, 23085, 23009, 22932, 22856,
+22779, 22701, 22624, 22546, 22468,
+22390, 22312, 22233, 22154, 22075,
+21996, 21916, 21836, 21756, 21676,
+21595, 21515, 21434, 21352, 21271,
+21189, 21107, 21025, 20943, 20860,
+20777, 20694, 20611, 20528, 20444,
+20360, 20276, 20192, 20107, 20022,
+19937, 19852, 19767, 19681, 19595,
+19509, 19423, 19336, 19250, 19163,
+19076, 18988, 18901, 18813, 18725,
+18637, 18549, 18460, 18372, 18283,
+18194, 18104, 18015, 17925, 17835,
+17745, 17655, 17565, 17474, 17383,
+17292, 17201, 17110, 17018, 16927,
+16835, 16743, 16650, 16558, 16465,
+16372, 16279, 16186, 16093, 15999,
+15906, 15812, 15718, 15624, 15529,
+15435, 15340, 15245, 15150, 15055,
+14960, 14864, 14769, 14673, 14577,
+14481, 14385, 14288, 14192, 14095,
+13998, 13901, 13804, 13706, 13609,
+13511, 13414, 13316, 13218, 13119,
+13021, 12923, 12824, 12725, 12626,
+12527, 12428, 12329, 12230, 12130,
+12030, 11930, 11831, 11730, 11630,
+11530, 11430, 11329, 11228, 11128,
+11027, 10926, 10824, 10723, 10622,
+10520, 10419, 10317, 10215, 10113,
+10011, 9909, 9807, 9704, 9602,
+9499, 9397, 9294, 9191, 9088,
+8985, 8882, 8778, 8675, 8572,
+8468, 8364, 8261, 8157, 8053,
+7949, 7845, 7741, 7637, 7532,
+7428, 7323, 7219, 7114, 7009,
+6905, 6800, 6695, 6590, 6485,
+6380, 6274, 6169, 6064, 5958,
+5853, 5747, 5642, 5536, 5430,
+5325, 5219, 5113, 5007, 4901,
+4795, 4689, 4583, 4476, 4370,
+4264, 4157, 4051, 3945, 3838,
+3732, 3625, 3518, 3412, 3305,
+3198, 3092, 2985, 2878, 2771,
+2664, 2558, 2451, 2344, 2237,
+2130, 2023, 1916, 1809, 1702,
+1594, 1487, 1380, 1273, 1166,
+1059, 952, 844, 737, 630,
+523, 416, 308, 201, 94,
+-13, -121, -228, -335, -442,
+-550, -657, -764, -871, -978,
+-1086, -1193, -1300, -1407, -1514,
+-1621, -1728, -1835, -1942, -2049,
+-2157, -2263, -2370, -2477, -2584,
+-2691, -2798, -2905, -3012, -3118,
+-3225, -3332, -3439, -3545, -3652,
+-3758, -3865, -3971, -4078, -4184,
+-4290, -4397, -4503, -4609, -4715,
+-4821, -4927, -5033, -5139, -5245,
+-5351, -5457, -5562, -5668, -5774,
+-5879, -5985, -6090, -6195, -6301,
+-6406, -6511, -6616, -6721, -6826,
+-6931, -7036, -7140, -7245, -7349,
+-7454, -7558, -7663, -7767, -7871,
+-7975, -8079, -8183, -8287, -8390,
+-8494, -8597, -8701, -8804, -8907,
+-9011, -9114, -9217, -9319, -9422,
+-9525, -9627, -9730, -9832, -9934,
+-10037, -10139, -10241, -10342, -10444,
+-10546, -10647, -10748, -10850, -10951,
+-11052, -11153, -11253, -11354, -11455,
+-11555, -11655, -11756, -11856, -11955,
+-12055, -12155, -12254, -12354, -12453,
+-12552, -12651, -12750, -12849, -12947,
+-13046, -13144, -13242, -13340, -13438,
+-13536, -13633, -13731, -13828, -13925,
+-14022, -14119, -14216, -14312, -14409,
+-14505, -14601, -14697, -14793, -14888,
+-14984, -15079, -15174, -15269, -15364,
+-15459, -15553, -15647, -15741, -15835,
+-15929, -16023, -16116, -16210, -16303,
+-16396, -16488, -16581, -16673, -16766,
+-16858, -16949, -17041, -17133, -17224,
+-17315, -17406, -17497, -17587, -17678,
+-17768, -17858, -17948, -18037, -18127,
+-18216, -18305, -18394, -18483, -18571,
+-18659, -18747, -18835, -18923, -19010,
+-19098, -19185, -19271, -19358, -19444,
+-19531, -19617, -19702, -19788, -19873,
+-19959, -20043, -20128, -20213, -20297,
+-20381, -20465, -20549, -20632, -20715,
+-20798, -20881, -20963, -21046, -21128,
+-21210, -21291, -21373, -21454, -21535,
+-21616, -21696, -21776, -21856, -21936,
+-22016, -22095, -22174, -22253, -22331,
+-22410, -22488, -22566, -22643, -22721,
+-22798, -22875, -22951, -23028, -23104,
+-23180, -23256, -23331, -23406, -23481,
+-23556, -23630, -23704, -23778, -23852,
+-23925, -23998, -24071, -24144, -24216,
+-24288, -24360, -24432, -24503, -24574,
+-24645, -24716, -24786, -24856, -24926,
+-24995, -25064, -25133, -25202, -25270,
+-25339, -25406, -25474, -25541, -25608,
+-25675, -25742, -25808, -25874, -25939,
+-26005, -26070, -26135, -26199, -26264,
+-26327, -26391, -26455, -26518, -26581,
+-26643, -26705, -26767, -26829, -26891,
+-26952, -27013, -27073, -27133, -27193,
+-27253, -27312, -27372, -27430, -27489,
+-27547, -27605, -27663, -27720, -27777,
+-27834, -27890, -27946, -28002, -28058,
+-28113, -28168, -28223, -28277, -28331,
+-28385, -28438, -28491, -28544, -28596,
+-28649, -28701, -28752, -28803, -28854,
+-28905, -28955, -29006, -29055, -29105,
+-29154, -29203, -29251, -29299, -29347,
+-29395, -29442, -29489, -29535, -29582,
+-29628, -29673, -29719, -29764, -29808,
+-29853, -29897, -29941, -29984, -30027,
+-30070, -30112, -30154, -30196, -30238,
+-30279, -30320, -30360, -30400, -30440,
+-30480, -30519, -30558, -30596, -30635,
+-30672, -30710, -30747, -30784, -30821,
+-30857, -30893, -30929, -30964, -30999,
+-31033, -31068, -31102, -31135, -31168,
+-31201, -31234, -31266, -31298, -31330,
+-31361, -31392, -31422, -31453, -31483,
+-31512, -31541, -31570, -31599, -31627,
+-31655, -31682, -31710, -31737, -31763,
+-31789, -31815, -31841, -31866, -31891,
+-31915, -31939, -31963, -31986, -32010,
+-32032, -32055, -32077, -32099, -32120,
+-32141, -32162, -32182, -32202, -32222,
+-32241, -32260, -32279, -32297, -32315,
+-32333, -32350, -32367, -32383, -32399,
+-32415, -32431, -32446, -32461, -32475,
+-32489, -32503, -32517, -32530, -32542,
+-32555, -32567, -32579, -32590, -32601,
+-32612, -32622, -32632, -32641, -32651,
+-32659, -32668, -32676, -32684, -32692,
+-32699, -32706, -32712, -32718, -32724,
+-32729, -32734, -32739, -32743, -32747,
+-32751, -32754, -32757, -32760, -32762,
+-32764, -32765, -32767, -32767, -32767,
+32767, 32767, 32765, 32761, 32756,
+32750, 32742, 32732, 32722, 32710,
+32696, 32681, 32665, 32647, 32628,
+32608, 32586, 32562, 32538, 32512,
+32484, 32455, 32425, 32393, 32360,
+32326, 32290, 32253, 32214, 32174,
+32133, 32090, 32046, 32001, 31954,
+31906, 31856, 31805, 31753, 31700,
+31645, 31588, 31530, 31471, 31411,
+31349, 31286, 31222, 31156, 31089,
+31020, 30951, 30880, 30807, 30733,
+30658, 30582, 30504, 30425, 30345,
+30263, 30181, 30096, 30011, 29924,
+29836, 29747, 29656, 29564, 29471,
+29377, 29281, 29184, 29086, 28987,
+28886, 28784, 28681, 28577, 28471,
+28365, 28257, 28147, 28037, 27925,
+27812, 27698, 27583, 27467, 27349,
+27231, 27111, 26990, 26868, 26744,
+26620, 26494, 26367, 26239, 26110,
+25980, 25849, 25717, 25583, 25449,
+25313, 25176, 25038, 24900, 24760,
+24619, 24477, 24333, 24189, 24044,
+23898, 23751, 23602, 23453, 23303,
+23152, 22999, 22846, 22692, 22537,
+22380, 22223, 22065, 21906, 21746,
+21585, 21423, 21261, 21097, 20933,
+20767, 20601, 20434, 20265, 20096,
+19927, 19756, 19584, 19412, 19239,
+19065, 18890, 18714, 18538, 18361,
+18183, 18004, 17824, 17644, 17463,
+17281, 17098, 16915, 16731, 16546,
+16361, 16175, 15988, 15800, 15612,
+15423, 15234, 15043, 14852, 14661,
+14469, 14276, 14083, 13889, 13694,
+13499, 13303, 13107, 12910, 12713,
+12515, 12317, 12118, 11918, 11718,
+11517, 11316, 11115, 10913, 10710,
+10508, 10304, 10100, 9896, 9691,
+9486, 9281, 9075, 8869, 8662,
+8455, 8248, 8040, 7832, 7623,
+7415, 7206, 6996, 6787, 6577,
+6366, 6156, 5945, 5734, 5523,
+5311, 5100, 4888, 4675, 4463,
+4251, 4038, 3825, 3612, 3399,
+3185, 2972, 2758, 2544, 2330,
+2116, 1902, 1688, 1474, 1260,
+1045, 831, 617, 402, 188,
+-27, -241, -456, -670, -885,
+-1099, -1313, -1528, -1742, -1956,
+-2170, -2384, -2598, -2811, -3025,
+-3239, -3452, -3665, -3878, -4091,
+-4304, -4516, -4728, -4941, -5153,
+-5364, -5576, -5787, -5998, -6209,
+-6419, -6629, -6839, -7049, -7258,
+-7467, -7676, -7884, -8092, -8300,
+-8507, -8714, -8920, -9127, -9332,
+-9538, -9743, -9947, -10151, -10355,
+-10558, -10761, -10963, -11165, -11367,
+-11568, -11768, -11968, -12167, -12366,
+-12565, -12762, -12960, -13156, -13352,
+-13548, -13743, -13937, -14131, -14324,
+-14517, -14709, -14900, -15091, -15281,
+-15470, -15659, -15847, -16035, -16221,
+-16407, -16593, -16777, -16961, -17144,
+-17326, -17508, -17689, -17869, -18049,
+-18227, -18405, -18582, -18758, -18934,
+-19108, -19282, -19455, -19627, -19799,
+-19969, -20139, -20308, -20475, -20642,
+-20809, -20974, -21138, -21301, -21464,
+-21626, -21786, -21946, -22105, -22263,
+-22420, -22575, -22730, -22884, -23037,
+-23189, -23340, -23490, -23640, -23788,
+-23935, -24080, -24225, -24369, -24512,
+-24654, -24795, -24934, -25073, -25211,
+-25347, -25482, -25617, -25750, -25882,
+-26013, -26143, -26272, -26399, -26526,
+-26651, -26775, -26898, -27020, -27141,
+-27260, -27379, -27496, -27612, -27727,
+-27841, -27953, -28065, -28175, -28284,
+-28391, -28498, -28603, -28707, -28810,
+-28911, -29012, -29111, -29209, -29305,
+-29401, -29495, -29587, -29679, -29769,
+-29858, -29946, -30032, -30118, -30201,
+-30284, -30365, -30445, -30524, -30601,
+-30677, -30752, -30825, -30897, -30968,
+-31038, -31106, -31172, -31238, -31302,
+-31365, -31426, -31486, -31545, -31602,
+-31658, -31713, -31766, -31818, -31869,
+-31918, -31966, -32012, -32058, -32101,
+-32144, -32185, -32224, -32262, -32299,
+-32335, -32369, -32401, -32433, -32463,
+-32491, -32518, -32544, -32568, -32591,
+-32613, -32633, -32652, -32669, -32685,
+-32700, -32713, -32724, -32735, -32744,
+-32751, -32757, -32762, -32766, -32767,
+32767, 32764, 32755, 32741, 32720,
+32694, 32663, 32626, 32583, 32535,
+32481, 32421, 32356, 32286, 32209,
+32128, 32041, 31948, 31850, 31747,
+31638, 31523, 31403, 31278, 31148,
+31012, 30871, 30724, 30572, 30415,
+30253, 30086, 29913, 29736, 29553,
+29365, 29172, 28974, 28771, 28564,
+28351, 28134, 27911, 27684, 27452,
+27216, 26975, 26729, 26478, 26223,
+25964, 25700, 25432, 25159, 24882,
+24601, 24315, 24026, 23732, 23434,
+23133, 22827, 22517, 22204, 21886,
+21565, 21240, 20912, 20580, 20244,
+19905, 19563, 19217, 18868, 18516,
+18160, 17802, 17440, 17075, 16708,
+16338, 15964, 15588, 15210, 14829,
+14445, 14059, 13670, 13279, 12886,
+12490, 12093, 11693, 11291, 10888,
+10482, 10075, 9666, 9255, 8843,
+8429, 8014, 7597, 7180, 6760,
+6340, 5919, 5496, 5073, 4649,
+4224, 3798, 3372, 2945, 2517,
+2090, 1661, 1233, 804, 375,
+-54, -483, -911, -1340, -1768,
+-2197, -2624, -3052, -3479, -3905,
+-4330, -4755, -5179, -5602, -6024,
+-6445, -6865, -7284, -7702, -8118,
+-8533, -8946, -9358, -9768, -10177,
+-10584, -10989, -11392, -11793, -12192,
+-12589, -12984, -13377, -13767, -14155,
+-14541, -14924, -15305, -15683, -16058,
+-16430, -16800, -17167, -17531, -17892,
+-18249, -18604, -18956, -19304, -19649,
+-19990, -20329, -20663, -20994, -21322,
+-21646, -21966, -22282, -22595, -22904,
+-23208, -23509, -23806, -24099, -24387,
+-24672, -24952, -25228, -25499, -25766,
+-26029, -26288, -26541, -26791, -27035,
+-27275, -27511, -27741, -27967, -28188,
+-28405, -28616, -28823, -29024, -29221,
+-29412, -29599, -29780, -29957, -30128,
+-30294, -30455, -30611, -30761, -30906,
+-31046, -31181, -31310, -31434, -31552,
+-31665, -31773, -31875, -31972, -32063,
+-32149, -32229, -32304, -32373, -32437,
+-32495, -32547, -32594, -32635, -32671,
+-32701, -32726, -32745, -32758, -32766,
+32767, 32754, 32717, 32658, 32577,
+32473, 32348, 32200, 32029, 31837,
+31624, 31388, 31131, 30853, 30553,
+30232, 29891, 29530, 29148, 28746,
+28324, 27883, 27423, 26944, 26447,
+25931, 25398, 24847, 24279, 23695,
+23095, 22478, 21846, 21199, 20538,
+19863, 19174, 18472, 17757, 17030,
+16291, 15541, 14781, 14010, 13230,
+12441, 11643, 10837, 10024, 9204,
+8377, 7545, 6708, 5866, 5020,
+4171, 3319, 2464, 1608, 751,
+-107, -965, -1822, -2678, -3532,
+-4383, -5232, -6077, -6918, -7754,
+-8585, -9409, -10228, -11039, -11843,
+-12639, -13426, -14204, -14972, -15730,
+-16477, -17213, -17937, -18648, -19347,
+-20033, -20705, -21363, -22006, -22634,
+-23246, -23843, -24423, -24986, -25533,
+-26062, -26573, -27066, -27540, -27995,
+-28431, -28848, -29245, -29622, -29979,
+-30315, -30630, -30924, -31197, -31449,
+-31679, -31887, -32074, -32239, -32381,
+-32501, -32600, -32675, -32729, -32759,
+};
+#endif
+
+static const CELTMode mode48000_960_120 = {
+48000, /* Fs */
+120, /* overlap */
+21, /* nbEBands */
+21, /* effEBands */
+{27853, 0, 4096, 8192, }, /* preemph */
+eband5ms, /* eBands */
+3, /* maxLM */
+8, /* nbShortMdcts */
+120, /* shortMdctSize */
+11, /* nbAllocVectors */
+band_allocation, /* allocVectors */
+logN400, /* logN */
+window120, /* window */
+{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */
+{392, cache_index50, cache_bits50, cache_caps50}, /* cache */
+};
+
+/* List of all the available modes */
+#define TOTAL_MODES 1
+static const CELTMode * const static_mode_list[TOTAL_MODES] = {
+&mode48000_960_120,
+};
diff --git a/external/opus-1.1.4/celt/static_modes_fixed_arm_ne10.h b/external/opus-1.1.4/celt/static_modes_fixed_arm_ne10.h
new file mode 100644
index 0000000..b8ef0ce
--- /dev/null
+++ b/external/opus-1.1.4/celt/static_modes_fixed_arm_ne10.h
@@ -0,0 +1,388 @@
+/* The contents of this file was automatically generated by
+ * dump_mode_arm_ne10.c with arguments: 48000 960
+ * It contains static definitions for some pre-defined modes. */
+#include <NE10_init.h>
+
+#ifndef NE10_FFT_PARAMS48000_960
+#define NE10_FFT_PARAMS48000_960
+static const ne10_int32_t ne10_factors_480[64] = {
+4, 40, 4, 30, 2, 15, 5, 3, 3, 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, };
+static const ne10_int32_t ne10_factors_240[64] = {
+3, 20, 4, 15, 5, 3, 3, 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, };
+static const ne10_int32_t ne10_factors_120[64] = {
+3, 10, 2, 15, 5, 3, 3, 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, };
+static const ne10_int32_t ne10_factors_60[64] = {
+2, 5, 5, 3, 3, 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, };
+static const ne10_fft_cpx_int32_t ne10_twiddles_480[480] = {
+{0,0}, {2147483647,0}, {2147483647,0},
+{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394},
+{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496},
+{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096},
+{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152},
+{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313},
+{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424},
+{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496},
+{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268},
+{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785},
+{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172},
+{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682},
+{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313},
+{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450},
+{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067},
+{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277},
+{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424},
+{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771},
+{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994},
+{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593},
+{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968},
+{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851},
+{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394},
+{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959},
+{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516},
+{-94,-2147483647}, {-224473265,-2135719496}, {-446487060,-2100555955},
+{-663609049,-2042378281}, {-873460398,-1961823883}, {-1073741932,-1859775330},
+{-1262259116,-1737350839}, {-1436947137,-1595891268}, {-1595891628,-1436946738},
+{-1737350854,-1262259096}, {-1859775343,-1073741910}, {-1961823997,-873460141},
+{-2042378447,-663608538}, {-2100556013,-446486785}, {-2135719499,-224473240},
+{2147483647,0}, {2121044558,-335940465}, {2042378310,-663608960},
+{1913421927,-974937199}, {1737350743,-1262259248}, {1518500216,-1518500282},
+{1262259172,-1737350799}, {974937230,-1913421912}, {663608871,-2042378339},
+{335940246,-2121044593}, {-94,-2147483647}, {-335940431,-2121044564},
+{-663609049,-2042378281}, {-974937397,-1913421827}, {-1262259116,-1737350839},
+{-1518500258,-1518500240}, {-1737350854,-1262259096}, {-1913422071,-974936918},
+{-2042378447,-663608538}, {-2121044568,-335940406}, {-2147483647,188},
+{-2121044509,335940777}, {-2042378331,663608895}, {-1913421900,974937252},
+{-1737350633,1262259400}, {-1518499993,1518500506}, {-1262258813,1737351059},
+{-974936606,1913422229}, {-663609179,2042378239}, {-335940566,2121044542},
+{2147483647,0}, {2147299667,-28109693}, {2146747758,-56214570},
+{2145828015,-84309815}, {2144540595,-112390613}, {2142885719,-140452154},
+{2140863671,-168489630}, {2138474797,-196498235}, {2135719506,-224473172},
+{2132598271,-252409646}, {2129111626,-280302871}, {2125260168,-308148068},
+{2121044558,-335940465}, {2116465518,-363675300}, {2111523833,-391347822},
+{2106220349,-418953288}, {2100555974,-446486968}, {2094531681,-473944146},
+{2088148500,-501320115}, {2081407525,-528610186}, {2074309912,-555809682},
+{2066856885,-582913912}, {2059049696,-609918325}, {2050889698,-636818231},
+{2042378310,-663608960}, {2033516972,-690285983}, {2024307180,-716844791},
+{2014750533,-743280770}, {2004848691,-769589332}, {1994603329,-795766029},
+{1984016179,-821806435}, {1973089077,-847706028}, {1961823921,-873460313},
+{1950222618,-899064934}, {1938287127,-924515564}, {1926019520,-949807783},
+{1913421927,-974937199}, {1900496481,-999899565}, {1887245364,-1024690661},
+{1873670877,-1049306180}, {1859775377,-1073741851}, {1845561215,-1097993541},
+{1831030826,-1122057097}, {1816186632,-1145928502}, {1801031311,-1169603450},
+{1785567394,-1193077993}, {1769797456,-1216348214}, {1753724345,-1239409914},
+{1737350743,-1262259248}, {1720679456,-1284892300}, {1703713340,-1307305194},
+{1686455222,-1329494189}, {1668908218,-1351455280}, {1651075255,-1373184807},
+{1632959307,-1394679144}, {1614563642,-1415934412}, {1595891331,-1436947067},
+{1576945572,-1457713510}, {1557729613,-1478230181}, {1538246655,-1498493658},
+{1518500216,-1518500282}, {1498493590,-1538246721}, {1478230113,-1557729677},
+{1457713441,-1576945636}, {1436946998,-1595891394}, {1415934341,-1614563704},
+{1394679073,-1632959368}, {1373184735,-1651075315}, {1351455207,-1668908277},
+{1329494115,-1686455280}, {1307305120,-1703713397}, {1284892225,-1720679512},
+{1262259172,-1737350799}, {1239409837,-1753724400}, {1216348136,-1769797510},
+{1193077915,-1785567446}, {1169603371,-1801031362}, {1145928423,-1816186682},
+{1122057017,-1831030875}, {1097993571,-1845561197}, {1073741769,-1859775424},
+{1049305987,-1873670985}, {1024690635,-1887245378}, {999899482,-1900496524},
+{974937230,-1913421912}, {949807699,-1926019561}, {924515422,-1938287195},
+{899064965,-1950222603}, {873460227,-1961823959}, {847705824,-1973089164},
+{821806407,-1984016190}, {795765941,-1994603364}, {769589125,-2004848771},
+{743280682,-2014750566}, {716844642,-2024307233}, {690286016,-2033516961},
+{663608871,-2042378339}, {636818019,-2050889764}, {609918296,-2059049705},
+{582913822,-2066856911}, {555809715,-2074309903}, {528610126,-2081407540},
+{501319962,-2088148536}, {473944148,-2094531680}, {446486876,-2100555994},
+{418953102,-2106220386}, {391347792,-2111523838}, {363675176,-2116465540},
+{335940246,-2121044593}, {308148006,-2125260177}, {280302715,-2129111646},
+{252409648,-2132598271}, {224473078,-2135719516}, {196498046,-2138474814},
+{168489600,-2140863674}, {140452029,-2142885728}, {112390647,-2144540593},
+{84309753,-2145828017}, {56214412,-2146747762}, {28109695,-2147299667},
+{2147483647,0}, {2146747758,-56214570}, {2144540595,-112390613},
+{2140863671,-168489630}, {2135719506,-224473172}, {2129111626,-280302871},
+{2121044558,-335940465}, {2111523833,-391347822}, {2100555974,-446486968},
+{2088148500,-501320115}, {2074309912,-555809682}, {2059049696,-609918325},
+{2042378310,-663608960}, {2024307180,-716844791}, {2004848691,-769589332},
+{1984016179,-821806435}, {1961823921,-873460313}, {1938287127,-924515564},
+{1913421927,-974937199}, {1887245364,-1024690661}, {1859775377,-1073741851},
+{1831030826,-1122057097}, {1801031311,-1169603450}, {1769797456,-1216348214},
+{1737350743,-1262259248}, {1703713340,-1307305194}, {1668908218,-1351455280},
+{1632959307,-1394679144}, {1595891331,-1436947067}, {1557729613,-1478230181},
+{1518500216,-1518500282}, {1478230113,-1557729677}, {1436946998,-1595891394},
+{1394679073,-1632959368}, {1351455207,-1668908277}, {1307305120,-1703713397},
+{1262259172,-1737350799}, {1216348136,-1769797510}, {1169603371,-1801031362},
+{1122057017,-1831030875}, {1073741769,-1859775424}, {1024690635,-1887245378},
+{974937230,-1913421912}, {924515422,-1938287195}, {873460227,-1961823959},
+{821806407,-1984016190}, {769589125,-2004848771}, {716844642,-2024307233},
+{663608871,-2042378339}, {609918296,-2059049705}, {555809715,-2074309903},
+{501319962,-2088148536}, {446486876,-2100555994}, {391347792,-2111523838},
+{335940246,-2121044593}, {280302715,-2129111646}, {224473078,-2135719516},
+{168489600,-2140863674}, {112390647,-2144540593}, {56214412,-2146747762},
+{-94,-2147483647}, {-56214600,-2146747757}, {-112390835,-2144540584},
+{-168489787,-2140863659}, {-224473265,-2135719496}, {-280302901,-2129111622},
+{-335940431,-2121044564}, {-391347977,-2111523804}, {-446487060,-2100555955},
+{-501320144,-2088148493}, {-555809896,-2074309855}, {-609918476,-2059049651},
+{-663609049,-2042378281}, {-716844819,-2024307170}, {-769589300,-2004848703},
+{-821806581,-1984016118}, {-873460398,-1961823883}, {-924515591,-1938287114},
+{-974937397,-1913421827}, {-1024690575,-1887245411}, {-1073741932,-1859775330},
+{-1122057395,-1831030643}, {-1169603421,-1801031330}, {-1216348291,-1769797403},
+{-1262259116,-1737350839}, {-1307305268,-1703713283}, {-1351455453,-1668908078},
+{-1394679021,-1632959413}, {-1436947137,-1595891268}, {-1478230435,-1557729372},
+{-1518500258,-1518500240}, {-1557729742,-1478230045}, {-1595891628,-1436946738},
+{-1632959429,-1394679001}, {-1668908417,-1351455035}, {-1703713298,-1307305248},
+{-1737350854,-1262259096}, {-1769797708,-1216347848}, {-1801031344,-1169603400},
+{-1831030924,-1122056937}, {-1859775343,-1073741910}, {-1887245423,-1024690552},
+{-1913422071,-974936918}, {-1938287125,-924515568}, {-1961823997,-873460141},
+{-1984016324,-821806084}, {-2004848713,-769589276}, {-2024307264,-716844553},
+{-2042378447,-663608538}, {-2059049731,-609918206}, {-2074309994,-555809377},
+{-2088148499,-501320119}, {-2100556013,-446486785}, {-2111523902,-391347448},
+{-2121044568,-335940406}, {-2129111659,-280302621}, {-2135719499,-224473240},
+{-2140863681,-168489506}, {-2144540612,-112390298}, {-2146747758,-56214574},
+{2147483647,0}, {2145828015,-84309815}, {2140863671,-168489630},
+{2132598271,-252409646}, {2121044558,-335940465}, {2106220349,-418953288},
+{2088148500,-501320115}, {2066856885,-582913912}, {2042378310,-663608960},
+{2014750533,-743280770}, {1984016179,-821806435}, {1950222618,-899064934},
+{1913421927,-974937199}, {1873670877,-1049306180}, {1831030826,-1122057097},
+{1785567394,-1193077993}, {1737350743,-1262259248}, {1686455222,-1329494189},
+{1632959307,-1394679144}, {1576945572,-1457713510}, {1518500216,-1518500282},
+{1457713441,-1576945636}, {1394679073,-1632959368}, {1329494115,-1686455280},
+{1262259172,-1737350799}, {1193077915,-1785567446}, {1122057017,-1831030875},
+{1049305987,-1873670985}, {974937230,-1913421912}, {899064965,-1950222603},
+{821806407,-1984016190}, {743280682,-2014750566}, {663608871,-2042378339},
+{582913822,-2066856911}, {501319962,-2088148536}, {418953102,-2106220386},
+{335940246,-2121044593}, {252409648,-2132598271}, {168489600,-2140863674},
+{84309753,-2145828017}, {-94,-2147483647}, {-84309940,-2145828010},
+{-168489787,-2140863659}, {-252409834,-2132598249}, {-335940431,-2121044564},
+{-418953286,-2106220349}, {-501320144,-2088148493}, {-582914003,-2066856860},
+{-663609049,-2042378281}, {-743280858,-2014750501}, {-821806581,-1984016118},
+{-899065136,-1950222525}, {-974937397,-1913421827}, {-1049306374,-1873670768},
+{-1122057395,-1831030643}, {-1193078284,-1785567199}, {-1262259116,-1737350839},
+{-1329494061,-1686455323}, {-1394679021,-1632959413}, {-1457713485,-1576945595},
+{-1518500258,-1518500240}, {-1576945613,-1457713466}, {-1632959429,-1394679001},
+{-1686455338,-1329494041}, {-1737350854,-1262259096}, {-1785567498,-1193077837},
+{-1831030924,-1122056937}, {-1873671031,-1049305905}, {-1913422071,-974936918},
+{-1950222750,-899064648}, {-1984016324,-821806084}, {-2014750687,-743280354},
+{-2042378447,-663608538}, {-2066856867,-582913978}, {-2088148499,-501320119},
+{-2106220354,-418953261}, {-2121044568,-335940406}, {-2132598282,-252409555},
+{-2140863681,-168489506}, {-2145828021,-84309659}, {-2147483647,188},
+{-2145828006,84310034}, {-2140863651,168489881}, {-2132598237,252409928},
+{-2121044509,335940777}, {-2106220281,418953629}, {-2088148411,501320484},
+{-2066856765,582914339}, {-2042378331,663608895}, {-2014750557,743280706},
+{-1984016181,821806431}, {-1950222593,899064989}, {-1913421900,974937252},
+{-1873670848,1049306232}, {-1831030728,1122057257}, {-1785567289,1193078149},
+{-1737350633,1262259400}, {-1686455106,1329494336}, {-1632959185,1394679287},
+{-1576945358,1457713742}, {-1518499993,1518500506}, {-1457713209,1576945850},
+{-1394678735,1632959656}, {-1329493766,1686455555}, {-1262258813,1737351059},
+{-1193077546,1785567692}, {-1122056638,1831031107}, {-1049305599,1873671202},
+{-974936606,1913422229}, {-899064330,1950222896}, {-821805761,1984016458},
+{-743280025,2014750808}, {-663609179,2042378239}, {-582914134,2066856823},
+{-501320277,2088148461}, {-418953420,2106220322}, {-335940566,2121044542},
+{-252409716,2132598263}, {-168489668,2140863668}, {-84309821,2145828015},
+};
+static const ne10_fft_cpx_int32_t ne10_twiddles_240[240] = {
+{0,0}, {2147483647,0}, {2147483647,0},
+{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394},
+{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496},
+{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096},
+{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152},
+{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968},
+{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851},
+{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394},
+{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959},
+{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516},
+{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313},
+{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424},
+{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496},
+{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268},
+{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785},
+{2147483647,0}, {2042378310,-663608960}, {1737350743,-1262259248},
+{1262259172,-1737350799}, {663608871,-2042378339}, {-94,-2147483647},
+{-663609049,-2042378281}, {-1262259116,-1737350839}, {-1737350854,-1262259096},
+{-2042378447,-663608538}, {-2147483647,188}, {-2042378331,663608895},
+{-1737350633,1262259400}, {-1262258813,1737351059}, {-663609179,2042378239},
+{2147483647,0}, {2146747758,-56214570}, {2144540595,-112390613},
+{2140863671,-168489630}, {2135719506,-224473172}, {2129111626,-280302871},
+{2121044558,-335940465}, {2111523833,-391347822}, {2100555974,-446486968},
+{2088148500,-501320115}, {2074309912,-555809682}, {2059049696,-609918325},
+{2042378310,-663608960}, {2024307180,-716844791}, {2004848691,-769589332},
+{1984016179,-821806435}, {1961823921,-873460313}, {1938287127,-924515564},
+{1913421927,-974937199}, {1887245364,-1024690661}, {1859775377,-1073741851},
+{1831030826,-1122057097}, {1801031311,-1169603450}, {1769797456,-1216348214},
+{1737350743,-1262259248}, {1703713340,-1307305194}, {1668908218,-1351455280},
+{1632959307,-1394679144}, {1595891331,-1436947067}, {1557729613,-1478230181},
+{1518500216,-1518500282}, {1478230113,-1557729677}, {1436946998,-1595891394},
+{1394679073,-1632959368}, {1351455207,-1668908277}, {1307305120,-1703713397},
+{1262259172,-1737350799}, {1216348136,-1769797510}, {1169603371,-1801031362},
+{1122057017,-1831030875}, {1073741769,-1859775424}, {1024690635,-1887245378},
+{974937230,-1913421912}, {924515422,-1938287195}, {873460227,-1961823959},
+{821806407,-1984016190}, {769589125,-2004848771}, {716844642,-2024307233},
+{663608871,-2042378339}, {609918296,-2059049705}, {555809715,-2074309903},
+{501319962,-2088148536}, {446486876,-2100555994}, {391347792,-2111523838},
+{335940246,-2121044593}, {280302715,-2129111646}, {224473078,-2135719516},
+{168489600,-2140863674}, {112390647,-2144540593}, {56214412,-2146747762},
+{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172},
+{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682},
+{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313},
+{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450},
+{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067},
+{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277},
+{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424},
+{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771},
+{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994},
+{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593},
+{-94,-2147483647}, {-112390835,-2144540584}, {-224473265,-2135719496},
+{-335940431,-2121044564}, {-446487060,-2100555955}, {-555809896,-2074309855},
+{-663609049,-2042378281}, {-769589300,-2004848703}, {-873460398,-1961823883},
+{-974937397,-1913421827}, {-1073741932,-1859775330}, {-1169603421,-1801031330},
+{-1262259116,-1737350839}, {-1351455453,-1668908078}, {-1436947137,-1595891268},
+{-1518500258,-1518500240}, {-1595891628,-1436946738}, {-1668908417,-1351455035},
+{-1737350854,-1262259096}, {-1801031344,-1169603400}, {-1859775343,-1073741910},
+{-1913422071,-974936918}, {-1961823997,-873460141}, {-2004848713,-769589276},
+{-2042378447,-663608538}, {-2074309994,-555809377}, {-2100556013,-446486785},
+{-2121044568,-335940406}, {-2135719499,-224473240}, {-2144540612,-112390298},
+{2147483647,0}, {2140863671,-168489630}, {2121044558,-335940465},
+{2088148500,-501320115}, {2042378310,-663608960}, {1984016179,-821806435},
+{1913421927,-974937199}, {1831030826,-1122057097}, {1737350743,-1262259248},
+{1632959307,-1394679144}, {1518500216,-1518500282}, {1394679073,-1632959368},
+{1262259172,-1737350799}, {1122057017,-1831030875}, {974937230,-1913421912},
+{821806407,-1984016190}, {663608871,-2042378339}, {501319962,-2088148536},
+{335940246,-2121044593}, {168489600,-2140863674}, {-94,-2147483647},
+{-168489787,-2140863659}, {-335940431,-2121044564}, {-501320144,-2088148493},
+{-663609049,-2042378281}, {-821806581,-1984016118}, {-974937397,-1913421827},
+{-1122057395,-1831030643}, {-1262259116,-1737350839}, {-1394679021,-1632959413},
+{-1518500258,-1518500240}, {-1632959429,-1394679001}, {-1737350854,-1262259096},
+{-1831030924,-1122056937}, {-1913422071,-974936918}, {-1984016324,-821806084},
+{-2042378447,-663608538}, {-2088148499,-501320119}, {-2121044568,-335940406},
+{-2140863681,-168489506}, {-2147483647,188}, {-2140863651,168489881},
+{-2121044509,335940777}, {-2088148411,501320484}, {-2042378331,663608895},
+{-1984016181,821806431}, {-1913421900,974937252}, {-1831030728,1122057257},
+{-1737350633,1262259400}, {-1632959185,1394679287}, {-1518499993,1518500506},
+{-1394678735,1632959656}, {-1262258813,1737351059}, {-1122056638,1831031107},
+{-974936606,1913422229}, {-821805761,1984016458}, {-663609179,2042378239},
+{-501320277,2088148461}, {-335940566,2121044542}, {-168489668,2140863668},
+};
+static const ne10_fft_cpx_int32_t ne10_twiddles_120[120] = {
+{0,0}, {2147483647,0}, {2147483647,0},
+{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394},
+{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496},
+{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096},
+{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152},
+{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313},
+{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424},
+{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496},
+{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268},
+{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785},
+{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172},
+{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682},
+{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313},
+{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450},
+{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067},
+{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277},
+{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424},
+{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771},
+{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994},
+{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593},
+{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968},
+{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851},
+{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394},
+{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959},
+{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516},
+{-94,-2147483647}, {-224473265,-2135719496}, {-446487060,-2100555955},
+{-663609049,-2042378281}, {-873460398,-1961823883}, {-1073741932,-1859775330},
+{-1262259116,-1737350839}, {-1436947137,-1595891268}, {-1595891628,-1436946738},
+{-1737350854,-1262259096}, {-1859775343,-1073741910}, {-1961823997,-873460141},
+{-2042378447,-663608538}, {-2100556013,-446486785}, {-2135719499,-224473240},
+{2147483647,0}, {2121044558,-335940465}, {2042378310,-663608960},
+{1913421927,-974937199}, {1737350743,-1262259248}, {1518500216,-1518500282},
+{1262259172,-1737350799}, {974937230,-1913421912}, {663608871,-2042378339},
+{335940246,-2121044593}, {-94,-2147483647}, {-335940431,-2121044564},
+{-663609049,-2042378281}, {-974937397,-1913421827}, {-1262259116,-1737350839},
+{-1518500258,-1518500240}, {-1737350854,-1262259096}, {-1913422071,-974936918},
+{-2042378447,-663608538}, {-2121044568,-335940406}, {-2147483647,188},
+{-2121044509,335940777}, {-2042378331,663608895}, {-1913421900,974937252},
+{-1737350633,1262259400}, {-1518499993,1518500506}, {-1262258813,1737351059},
+{-974936606,1913422229}, {-663609179,2042378239}, {-335940566,2121044542},
+};
+static const ne10_fft_cpx_int32_t ne10_twiddles_60[60] = {
+{0,0}, {2147483647,0}, {2147483647,0},
+{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394},
+{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496},
+{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096},
+{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152},
+{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968},
+{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851},
+{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394},
+{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959},
+{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516},
+{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313},
+{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424},
+{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496},
+{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268},
+{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785},
+{2147483647,0}, {2042378310,-663608960}, {1737350743,-1262259248},
+{1262259172,-1737350799}, {663608871,-2042378339}, {-94,-2147483647},
+{-663609049,-2042378281}, {-1262259116,-1737350839}, {-1737350854,-1262259096},
+{-2042378447,-663608538}, {-2147483647,188}, {-2042378331,663608895},
+{-1737350633,1262259400}, {-1262258813,1737351059}, {-663609179,2042378239},
+};
+static const ne10_fft_state_int32_t ne10_fft_state_int32_t_480 = {
+120,
+(ne10_int32_t *)ne10_factors_480,
+(ne10_fft_cpx_int32_t *)ne10_twiddles_480,
+NULL,
+(ne10_fft_cpx_int32_t *)&ne10_twiddles_480[120],
+};
+static const arch_fft_state cfg_arch_480 = {
+1,
+(void *)&ne10_fft_state_int32_t_480,
+};
+
+static const ne10_fft_state_int32_t ne10_fft_state_int32_t_240 = {
+60,
+(ne10_int32_t *)ne10_factors_240,
+(ne10_fft_cpx_int32_t *)ne10_twiddles_240,
+NULL,
+(ne10_fft_cpx_int32_t *)&ne10_twiddles_240[60],
+};
+static const arch_fft_state cfg_arch_240 = {
+1,
+(void *)&ne10_fft_state_int32_t_240,
+};
+
+static const ne10_fft_state_int32_t ne10_fft_state_int32_t_120 = {
+30,
+(ne10_int32_t *)ne10_factors_120,
+(ne10_fft_cpx_int32_t *)ne10_twiddles_120,
+NULL,
+(ne10_fft_cpx_int32_t *)&ne10_twiddles_120[30],
+};
+static const arch_fft_state cfg_arch_120 = {
+1,
+(void *)&ne10_fft_state_int32_t_120,
+};
+
+static const ne10_fft_state_int32_t ne10_fft_state_int32_t_60 = {
+15,
+(ne10_int32_t *)ne10_factors_60,
+(ne10_fft_cpx_int32_t *)ne10_twiddles_60,
+NULL,
+(ne10_fft_cpx_int32_t *)&ne10_twiddles_60[15],
+};
+static const arch_fft_state cfg_arch_60 = {
+1,
+(void *)&ne10_fft_state_int32_t_60,
+};
+
+#endif /* end NE10_FFT_PARAMS48000_960 */
diff --git a/external/opus-1.1.4/celt/static_modes_float.h b/external/opus-1.1.4/celt/static_modes_float.h
new file mode 100644
index 0000000..e102a38
--- /dev/null
+++ b/external/opus-1.1.4/celt/static_modes_float.h
@@ -0,0 +1,888 @@
+/* The contents of this file was automatically generated by dump_modes.c
+ with arguments: 48000 960
+ It contains static definitions for some pre-defined modes. */
+#include "modes.h"
+#include "rate.h"
+
+#ifdef HAVE_ARM_NE10
+#define OVERRIDE_FFT 1
+#include "static_modes_float_arm_ne10.h"
+#endif
+
+#ifndef DEF_WINDOW120
+#define DEF_WINDOW120
+static const opus_val16 window120[120] = {
+6.7286966e-05f, 0.00060551348f, 0.0016815970f, 0.0032947962f, 0.0054439943f,
+0.0081276923f, 0.011344001f, 0.015090633f, 0.019364886f, 0.024163635f,
+0.029483315f, 0.035319905f, 0.041668911f, 0.048525347f, 0.055883718f,
+0.063737999f, 0.072081616f, 0.080907428f, 0.090207705f, 0.099974111f,
+0.11019769f, 0.12086883f, 0.13197729f, 0.14351214f, 0.15546177f,
+0.16781389f, 0.18055550f, 0.19367290f, 0.20715171f, 0.22097682f,
+0.23513243f, 0.24960208f, 0.26436860f, 0.27941419f, 0.29472040f,
+0.31026818f, 0.32603788f, 0.34200931f, 0.35816177f, 0.37447407f,
+0.39092462f, 0.40749142f, 0.42415215f, 0.44088423f, 0.45766484f,
+0.47447104f, 0.49127978f, 0.50806798f, 0.52481261f, 0.54149077f,
+0.55807973f, 0.57455701f, 0.59090049f, 0.60708841f, 0.62309951f,
+0.63891306f, 0.65450896f, 0.66986776f, 0.68497077f, 0.69980010f,
+0.71433873f, 0.72857055f, 0.74248043f, 0.75605424f, 0.76927895f,
+0.78214257f, 0.79463430f, 0.80674445f, 0.81846456f, 0.82978733f,
+0.84070669f, 0.85121779f, 0.86131698f, 0.87100183f, 0.88027111f,
+0.88912479f, 0.89756398f, 0.90559094f, 0.91320904f, 0.92042270f,
+0.92723738f, 0.93365955f, 0.93969656f, 0.94535671f, 0.95064907f,
+0.95558353f, 0.96017067f, 0.96442171f, 0.96834849f, 0.97196334f,
+0.97527906f, 0.97830883f, 0.98106616f, 0.98356480f, 0.98581869f,
+0.98784191f, 0.98964856f, 0.99125274f, 0.99266849f, 0.99390969f,
+0.99499004f, 0.99592297f, 0.99672162f, 0.99739874f, 0.99796667f,
+0.99843728f, 0.99882195f, 0.99913147f, 0.99937606f, 0.99956527f,
+0.99970802f, 0.99981248f, 0.99988613f, 0.99993565f, 0.99996697f,
+0.99998518f, 0.99999457f, 0.99999859f, 0.99999982f, 1.0000000f,
+};
+#endif
+
+#ifndef DEF_LOGN400
+#define DEF_LOGN400
+static const opus_int16 logN400[21] = {
+0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, };
+#endif
+
+#ifndef DEF_PULSE_CACHE50
+#define DEF_PULSE_CACHE50
+static const opus_int16 cache_index50[105] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41,
+82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41,
+41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41,
+41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305,
+318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240,
+305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240,
+240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387,
+};
+static const unsigned char cache_bits50[392] = {
+40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28,
+31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50,
+51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65,
+66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61,
+64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92,
+94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123,
+124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94,
+97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139,
+142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35,
+28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149,
+153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225,
+229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157,
+166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63,
+86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250,
+25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180,
+185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89,
+110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41,
+74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138,
+163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214,
+228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49,
+90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47,
+87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57,
+106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187,
+224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127,
+182, 234, };
+static const unsigned char cache_caps50[168] = {
+224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185,
+178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240,
+240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160,
+160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172,
+138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207,
+204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185,
+185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39,
+207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201,
+188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204,
+204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175,
+140, 66, 40, };
+#endif
+
+#ifndef FFT_TWIDDLES48000_960
+#define FFT_TWIDDLES48000_960
+static const kiss_twiddle_cpx fft_twiddles48000_960[480] = {
+{1.0000000f, -0.0000000f}, {0.99991433f, -0.013089596f},
+{0.99965732f, -0.026176948f}, {0.99922904f, -0.039259816f},
+{0.99862953f, -0.052335956f}, {0.99785892f, -0.065403129f},
+{0.99691733f, -0.078459096f}, {0.99580493f, -0.091501619f},
+{0.99452190f, -0.10452846f}, {0.99306846f, -0.11753740f},
+{0.99144486f, -0.13052619f}, {0.98965139f, -0.14349262f},
+{0.98768834f, -0.15643447f}, {0.98555606f, -0.16934950f},
+{0.98325491f, -0.18223553f}, {0.98078528f, -0.19509032f},
+{0.97814760f, -0.20791169f}, {0.97534232f, -0.22069744f},
+{0.97236992f, -0.23344536f}, {0.96923091f, -0.24615329f},
+{0.96592583f, -0.25881905f}, {0.96245524f, -0.27144045f},
+{0.95881973f, -0.28401534f}, {0.95501994f, -0.29654157f},
+{0.95105652f, -0.30901699f}, {0.94693013f, -0.32143947f},
+{0.94264149f, -0.33380686f}, {0.93819134f, -0.34611706f},
+{0.93358043f, -0.35836795f}, {0.92880955f, -0.37055744f},
+{0.92387953f, -0.38268343f}, {0.91879121f, -0.39474386f},
+{0.91354546f, -0.40673664f}, {0.90814317f, -0.41865974f},
+{0.90258528f, -0.43051110f}, {0.89687274f, -0.44228869f},
+{0.89100652f, -0.45399050f}, {0.88498764f, -0.46561452f},
+{0.87881711f, -0.47715876f}, {0.87249601f, -0.48862124f},
+{0.86602540f, -0.50000000f}, {0.85940641f, -0.51129309f},
+{0.85264016f, -0.52249856f}, {0.84572782f, -0.53361452f},
+{0.83867057f, -0.54463904f}, {0.83146961f, -0.55557023f},
+{0.82412619f, -0.56640624f}, {0.81664156f, -0.57714519f},
+{0.80901699f, -0.58778525f}, {0.80125381f, -0.59832460f},
+{0.79335334f, -0.60876143f}, {0.78531693f, -0.61909395f},
+{0.77714596f, -0.62932039f}, {0.76884183f, -0.63943900f},
+{0.76040597f, -0.64944805f}, {0.75183981f, -0.65934582f},
+{0.74314483f, -0.66913061f}, {0.73432251f, -0.67880075f},
+{0.72537437f, -0.68835458f}, {0.71630194f, -0.69779046f},
+{0.70710678f, -0.70710678f}, {0.69779046f, -0.71630194f},
+{0.68835458f, -0.72537437f}, {0.67880075f, -0.73432251f},
+{0.66913061f, -0.74314483f}, {0.65934582f, -0.75183981f},
+{0.64944805f, -0.76040597f}, {0.63943900f, -0.76884183f},
+{0.62932039f, -0.77714596f}, {0.61909395f, -0.78531693f},
+{0.60876143f, -0.79335334f}, {0.59832460f, -0.80125381f},
+{0.58778525f, -0.80901699f}, {0.57714519f, -0.81664156f},
+{0.56640624f, -0.82412619f}, {0.55557023f, -0.83146961f},
+{0.54463904f, -0.83867057f}, {0.53361452f, -0.84572782f},
+{0.52249856f, -0.85264016f}, {0.51129309f, -0.85940641f},
+{0.50000000f, -0.86602540f}, {0.48862124f, -0.87249601f},
+{0.47715876f, -0.87881711f}, {0.46561452f, -0.88498764f},
+{0.45399050f, -0.89100652f}, {0.44228869f, -0.89687274f},
+{0.43051110f, -0.90258528f}, {0.41865974f, -0.90814317f},
+{0.40673664f, -0.91354546f}, {0.39474386f, -0.91879121f},
+{0.38268343f, -0.92387953f}, {0.37055744f, -0.92880955f},
+{0.35836795f, -0.93358043f}, {0.34611706f, -0.93819134f},
+{0.33380686f, -0.94264149f}, {0.32143947f, -0.94693013f},
+{0.30901699f, -0.95105652f}, {0.29654157f, -0.95501994f},
+{0.28401534f, -0.95881973f}, {0.27144045f, -0.96245524f},
+{0.25881905f, -0.96592583f}, {0.24615329f, -0.96923091f},
+{0.23344536f, -0.97236992f}, {0.22069744f, -0.97534232f},
+{0.20791169f, -0.97814760f}, {0.19509032f, -0.98078528f},
+{0.18223553f, -0.98325491f}, {0.16934950f, -0.98555606f},
+{0.15643447f, -0.98768834f}, {0.14349262f, -0.98965139f},
+{0.13052619f, -0.99144486f}, {0.11753740f, -0.99306846f},
+{0.10452846f, -0.99452190f}, {0.091501619f, -0.99580493f},
+{0.078459096f, -0.99691733f}, {0.065403129f, -0.99785892f},
+{0.052335956f, -0.99862953f}, {0.039259816f, -0.99922904f},
+{0.026176948f, -0.99965732f}, {0.013089596f, -0.99991433f},
+{6.1230318e-17f, -1.0000000f}, {-0.013089596f, -0.99991433f},
+{-0.026176948f, -0.99965732f}, {-0.039259816f, -0.99922904f},
+{-0.052335956f, -0.99862953f}, {-0.065403129f, -0.99785892f},
+{-0.078459096f, -0.99691733f}, {-0.091501619f, -0.99580493f},
+{-0.10452846f, -0.99452190f}, {-0.11753740f, -0.99306846f},
+{-0.13052619f, -0.99144486f}, {-0.14349262f, -0.98965139f},
+{-0.15643447f, -0.98768834f}, {-0.16934950f, -0.98555606f},
+{-0.18223553f, -0.98325491f}, {-0.19509032f, -0.98078528f},
+{-0.20791169f, -0.97814760f}, {-0.22069744f, -0.97534232f},
+{-0.23344536f, -0.97236992f}, {-0.24615329f, -0.96923091f},
+{-0.25881905f, -0.96592583f}, {-0.27144045f, -0.96245524f},
+{-0.28401534f, -0.95881973f}, {-0.29654157f, -0.95501994f},
+{-0.30901699f, -0.95105652f}, {-0.32143947f, -0.94693013f},
+{-0.33380686f, -0.94264149f}, {-0.34611706f, -0.93819134f},
+{-0.35836795f, -0.93358043f}, {-0.37055744f, -0.92880955f},
+{-0.38268343f, -0.92387953f}, {-0.39474386f, -0.91879121f},
+{-0.40673664f, -0.91354546f}, {-0.41865974f, -0.90814317f},
+{-0.43051110f, -0.90258528f}, {-0.44228869f, -0.89687274f},
+{-0.45399050f, -0.89100652f}, {-0.46561452f, -0.88498764f},
+{-0.47715876f, -0.87881711f}, {-0.48862124f, -0.87249601f},
+{-0.50000000f, -0.86602540f}, {-0.51129309f, -0.85940641f},
+{-0.52249856f, -0.85264016f}, {-0.53361452f, -0.84572782f},
+{-0.54463904f, -0.83867057f}, {-0.55557023f, -0.83146961f},
+{-0.56640624f, -0.82412619f}, {-0.57714519f, -0.81664156f},
+{-0.58778525f, -0.80901699f}, {-0.59832460f, -0.80125381f},
+{-0.60876143f, -0.79335334f}, {-0.61909395f, -0.78531693f},
+{-0.62932039f, -0.77714596f}, {-0.63943900f, -0.76884183f},
+{-0.64944805f, -0.76040597f}, {-0.65934582f, -0.75183981f},
+{-0.66913061f, -0.74314483f}, {-0.67880075f, -0.73432251f},
+{-0.68835458f, -0.72537437f}, {-0.69779046f, -0.71630194f},
+{-0.70710678f, -0.70710678f}, {-0.71630194f, -0.69779046f},
+{-0.72537437f, -0.68835458f}, {-0.73432251f, -0.67880075f},
+{-0.74314483f, -0.66913061f}, {-0.75183981f, -0.65934582f},
+{-0.76040597f, -0.64944805f}, {-0.76884183f, -0.63943900f},
+{-0.77714596f, -0.62932039f}, {-0.78531693f, -0.61909395f},
+{-0.79335334f, -0.60876143f}, {-0.80125381f, -0.59832460f},
+{-0.80901699f, -0.58778525f}, {-0.81664156f, -0.57714519f},
+{-0.82412619f, -0.56640624f}, {-0.83146961f, -0.55557023f},
+{-0.83867057f, -0.54463904f}, {-0.84572782f, -0.53361452f},
+{-0.85264016f, -0.52249856f}, {-0.85940641f, -0.51129309f},
+{-0.86602540f, -0.50000000f}, {-0.87249601f, -0.48862124f},
+{-0.87881711f, -0.47715876f}, {-0.88498764f, -0.46561452f},
+{-0.89100652f, -0.45399050f}, {-0.89687274f, -0.44228869f},
+{-0.90258528f, -0.43051110f}, {-0.90814317f, -0.41865974f},
+{-0.91354546f, -0.40673664f}, {-0.91879121f, -0.39474386f},
+{-0.92387953f, -0.38268343f}, {-0.92880955f, -0.37055744f},
+{-0.93358043f, -0.35836795f}, {-0.93819134f, -0.34611706f},
+{-0.94264149f, -0.33380686f}, {-0.94693013f, -0.32143947f},
+{-0.95105652f, -0.30901699f}, {-0.95501994f, -0.29654157f},
+{-0.95881973f, -0.28401534f}, {-0.96245524f, -0.27144045f},
+{-0.96592583f, -0.25881905f}, {-0.96923091f, -0.24615329f},
+{-0.97236992f, -0.23344536f}, {-0.97534232f, -0.22069744f},
+{-0.97814760f, -0.20791169f}, {-0.98078528f, -0.19509032f},
+{-0.98325491f, -0.18223553f}, {-0.98555606f, -0.16934950f},
+{-0.98768834f, -0.15643447f}, {-0.98965139f, -0.14349262f},
+{-0.99144486f, -0.13052619f}, {-0.99306846f, -0.11753740f},
+{-0.99452190f, -0.10452846f}, {-0.99580493f, -0.091501619f},
+{-0.99691733f, -0.078459096f}, {-0.99785892f, -0.065403129f},
+{-0.99862953f, -0.052335956f}, {-0.99922904f, -0.039259816f},
+{-0.99965732f, -0.026176948f}, {-0.99991433f, -0.013089596f},
+{-1.0000000f, -1.2246064e-16f}, {-0.99991433f, 0.013089596f},
+{-0.99965732f, 0.026176948f}, {-0.99922904f, 0.039259816f},
+{-0.99862953f, 0.052335956f}, {-0.99785892f, 0.065403129f},
+{-0.99691733f, 0.078459096f}, {-0.99580493f, 0.091501619f},
+{-0.99452190f, 0.10452846f}, {-0.99306846f, 0.11753740f},
+{-0.99144486f, 0.13052619f}, {-0.98965139f, 0.14349262f},
+{-0.98768834f, 0.15643447f}, {-0.98555606f, 0.16934950f},
+{-0.98325491f, 0.18223553f}, {-0.98078528f, 0.19509032f},
+{-0.97814760f, 0.20791169f}, {-0.97534232f, 0.22069744f},
+{-0.97236992f, 0.23344536f}, {-0.96923091f, 0.24615329f},
+{-0.96592583f, 0.25881905f}, {-0.96245524f, 0.27144045f},
+{-0.95881973f, 0.28401534f}, {-0.95501994f, 0.29654157f},
+{-0.95105652f, 0.30901699f}, {-0.94693013f, 0.32143947f},
+{-0.94264149f, 0.33380686f}, {-0.93819134f, 0.34611706f},
+{-0.93358043f, 0.35836795f}, {-0.92880955f, 0.37055744f},
+{-0.92387953f, 0.38268343f}, {-0.91879121f, 0.39474386f},
+{-0.91354546f, 0.40673664f}, {-0.90814317f, 0.41865974f},
+{-0.90258528f, 0.43051110f}, {-0.89687274f, 0.44228869f},
+{-0.89100652f, 0.45399050f}, {-0.88498764f, 0.46561452f},
+{-0.87881711f, 0.47715876f}, {-0.87249601f, 0.48862124f},
+{-0.86602540f, 0.50000000f}, {-0.85940641f, 0.51129309f},
+{-0.85264016f, 0.52249856f}, {-0.84572782f, 0.53361452f},
+{-0.83867057f, 0.54463904f}, {-0.83146961f, 0.55557023f},
+{-0.82412619f, 0.56640624f}, {-0.81664156f, 0.57714519f},
+{-0.80901699f, 0.58778525f}, {-0.80125381f, 0.59832460f},
+{-0.79335334f, 0.60876143f}, {-0.78531693f, 0.61909395f},
+{-0.77714596f, 0.62932039f}, {-0.76884183f, 0.63943900f},
+{-0.76040597f, 0.64944805f}, {-0.75183981f, 0.65934582f},
+{-0.74314483f, 0.66913061f}, {-0.73432251f, 0.67880075f},
+{-0.72537437f, 0.68835458f}, {-0.71630194f, 0.69779046f},
+{-0.70710678f, 0.70710678f}, {-0.69779046f, 0.71630194f},
+{-0.68835458f, 0.72537437f}, {-0.67880075f, 0.73432251f},
+{-0.66913061f, 0.74314483f}, {-0.65934582f, 0.75183981f},
+{-0.64944805f, 0.76040597f}, {-0.63943900f, 0.76884183f},
+{-0.62932039f, 0.77714596f}, {-0.61909395f, 0.78531693f},
+{-0.60876143f, 0.79335334f}, {-0.59832460f, 0.80125381f},
+{-0.58778525f, 0.80901699f}, {-0.57714519f, 0.81664156f},
+{-0.56640624f, 0.82412619f}, {-0.55557023f, 0.83146961f},
+{-0.54463904f, 0.83867057f}, {-0.53361452f, 0.84572782f},
+{-0.52249856f, 0.85264016f}, {-0.51129309f, 0.85940641f},
+{-0.50000000f, 0.86602540f}, {-0.48862124f, 0.87249601f},
+{-0.47715876f, 0.87881711f}, {-0.46561452f, 0.88498764f},
+{-0.45399050f, 0.89100652f}, {-0.44228869f, 0.89687274f},
+{-0.43051110f, 0.90258528f}, {-0.41865974f, 0.90814317f},
+{-0.40673664f, 0.91354546f}, {-0.39474386f, 0.91879121f},
+{-0.38268343f, 0.92387953f}, {-0.37055744f, 0.92880955f},
+{-0.35836795f, 0.93358043f}, {-0.34611706f, 0.93819134f},
+{-0.33380686f, 0.94264149f}, {-0.32143947f, 0.94693013f},
+{-0.30901699f, 0.95105652f}, {-0.29654157f, 0.95501994f},
+{-0.28401534f, 0.95881973f}, {-0.27144045f, 0.96245524f},
+{-0.25881905f, 0.96592583f}, {-0.24615329f, 0.96923091f},
+{-0.23344536f, 0.97236992f}, {-0.22069744f, 0.97534232f},
+{-0.20791169f, 0.97814760f}, {-0.19509032f, 0.98078528f},
+{-0.18223553f, 0.98325491f}, {-0.16934950f, 0.98555606f},
+{-0.15643447f, 0.98768834f}, {-0.14349262f, 0.98965139f},
+{-0.13052619f, 0.99144486f}, {-0.11753740f, 0.99306846f},
+{-0.10452846f, 0.99452190f}, {-0.091501619f, 0.99580493f},
+{-0.078459096f, 0.99691733f}, {-0.065403129f, 0.99785892f},
+{-0.052335956f, 0.99862953f}, {-0.039259816f, 0.99922904f},
+{-0.026176948f, 0.99965732f}, {-0.013089596f, 0.99991433f},
+{-1.8369095e-16f, 1.0000000f}, {0.013089596f, 0.99991433f},
+{0.026176948f, 0.99965732f}, {0.039259816f, 0.99922904f},
+{0.052335956f, 0.99862953f}, {0.065403129f, 0.99785892f},
+{0.078459096f, 0.99691733f}, {0.091501619f, 0.99580493f},
+{0.10452846f, 0.99452190f}, {0.11753740f, 0.99306846f},
+{0.13052619f, 0.99144486f}, {0.14349262f, 0.98965139f},
+{0.15643447f, 0.98768834f}, {0.16934950f, 0.98555606f},
+{0.18223553f, 0.98325491f}, {0.19509032f, 0.98078528f},
+{0.20791169f, 0.97814760f}, {0.22069744f, 0.97534232f},
+{0.23344536f, 0.97236992f}, {0.24615329f, 0.96923091f},
+{0.25881905f, 0.96592583f}, {0.27144045f, 0.96245524f},
+{0.28401534f, 0.95881973f}, {0.29654157f, 0.95501994f},
+{0.30901699f, 0.95105652f}, {0.32143947f, 0.94693013f},
+{0.33380686f, 0.94264149f}, {0.34611706f, 0.93819134f},
+{0.35836795f, 0.93358043f}, {0.37055744f, 0.92880955f},
+{0.38268343f, 0.92387953f}, {0.39474386f, 0.91879121f},
+{0.40673664f, 0.91354546f}, {0.41865974f, 0.90814317f},
+{0.43051110f, 0.90258528f}, {0.44228869f, 0.89687274f},
+{0.45399050f, 0.89100652f}, {0.46561452f, 0.88498764f},
+{0.47715876f, 0.87881711f}, {0.48862124f, 0.87249601f},
+{0.50000000f, 0.86602540f}, {0.51129309f, 0.85940641f},
+{0.52249856f, 0.85264016f}, {0.53361452f, 0.84572782f},
+{0.54463904f, 0.83867057f}, {0.55557023f, 0.83146961f},
+{0.56640624f, 0.82412619f}, {0.57714519f, 0.81664156f},
+{0.58778525f, 0.80901699f}, {0.59832460f, 0.80125381f},
+{0.60876143f, 0.79335334f}, {0.61909395f, 0.78531693f},
+{0.62932039f, 0.77714596f}, {0.63943900f, 0.76884183f},
+{0.64944805f, 0.76040597f}, {0.65934582f, 0.75183981f},
+{0.66913061f, 0.74314483f}, {0.67880075f, 0.73432251f},
+{0.68835458f, 0.72537437f}, {0.69779046f, 0.71630194f},
+{0.70710678f, 0.70710678f}, {0.71630194f, 0.69779046f},
+{0.72537437f, 0.68835458f}, {0.73432251f, 0.67880075f},
+{0.74314483f, 0.66913061f}, {0.75183981f, 0.65934582f},
+{0.76040597f, 0.64944805f}, {0.76884183f, 0.63943900f},
+{0.77714596f, 0.62932039f}, {0.78531693f, 0.61909395f},
+{0.79335334f, 0.60876143f}, {0.80125381f, 0.59832460f},
+{0.80901699f, 0.58778525f}, {0.81664156f, 0.57714519f},
+{0.82412619f, 0.56640624f}, {0.83146961f, 0.55557023f},
+{0.83867057f, 0.54463904f}, {0.84572782f, 0.53361452f},
+{0.85264016f, 0.52249856f}, {0.85940641f, 0.51129309f},
+{0.86602540f, 0.50000000f}, {0.87249601f, 0.48862124f},
+{0.87881711f, 0.47715876f}, {0.88498764f, 0.46561452f},
+{0.89100652f, 0.45399050f}, {0.89687274f, 0.44228869f},
+{0.90258528f, 0.43051110f}, {0.90814317f, 0.41865974f},
+{0.91354546f, 0.40673664f}, {0.91879121f, 0.39474386f},
+{0.92387953f, 0.38268343f}, {0.92880955f, 0.37055744f},
+{0.93358043f, 0.35836795f}, {0.93819134f, 0.34611706f},
+{0.94264149f, 0.33380686f}, {0.94693013f, 0.32143947f},
+{0.95105652f, 0.30901699f}, {0.95501994f, 0.29654157f},
+{0.95881973f, 0.28401534f}, {0.96245524f, 0.27144045f},
+{0.96592583f, 0.25881905f}, {0.96923091f, 0.24615329f},
+{0.97236992f, 0.23344536f}, {0.97534232f, 0.22069744f},
+{0.97814760f, 0.20791169f}, {0.98078528f, 0.19509032f},
+{0.98325491f, 0.18223553f}, {0.98555606f, 0.16934950f},
+{0.98768834f, 0.15643447f}, {0.98965139f, 0.14349262f},
+{0.99144486f, 0.13052619f}, {0.99306846f, 0.11753740f},
+{0.99452190f, 0.10452846f}, {0.99580493f, 0.091501619f},
+{0.99691733f, 0.078459096f}, {0.99785892f, 0.065403129f},
+{0.99862953f, 0.052335956f}, {0.99922904f, 0.039259816f},
+{0.99965732f, 0.026176948f}, {0.99991433f, 0.013089596f},
+};
+#ifndef FFT_BITREV480
+#define FFT_BITREV480
+static const opus_int16 fft_bitrev480[480] = {
+0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448,
+8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456,
+16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464,
+24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472,
+4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452,
+12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460,
+20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468,
+28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476,
+1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449,
+9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457,
+17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465,
+25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473,
+5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453,
+13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461,
+21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469,
+29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477,
+2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450,
+10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458,
+18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466,
+26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474,
+6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454,
+14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462,
+22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470,
+30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478,
+3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451,
+11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459,
+19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467,
+27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475,
+7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455,
+15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463,
+23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471,
+31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479,
+};
+#endif
+
+#ifndef FFT_BITREV240
+#define FFT_BITREV240
+static const opus_int16 fft_bitrev240[240] = {
+0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224,
+4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228,
+8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232,
+12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236,
+1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225,
+5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229,
+9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233,
+13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237,
+2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226,
+6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230,
+10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234,
+14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238,
+3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227,
+7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231,
+11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235,
+15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239,
+};
+#endif
+
+#ifndef FFT_BITREV120
+#define FFT_BITREV120
+static const opus_int16 fft_bitrev120[120] = {
+0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112,
+4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116,
+1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113,
+5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117,
+2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114,
+6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118,
+3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115,
+7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119,
+};
+#endif
+
+#ifndef FFT_BITREV60
+#define FFT_BITREV60
+static const opus_int16 fft_bitrev60[60] = {
+0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56,
+1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57,
+2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58,
+3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59,
+};
+#endif
+
+#ifndef FFT_STATE48000_960_0
+#define FFT_STATE48000_960_0
+static const kiss_fft_state fft_state48000_960_0 = {
+480, /* nfft */
+0.002083333f, /* scale */
+-1, /* shift */
+{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev480, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_480,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_1
+#define FFT_STATE48000_960_1
+static const kiss_fft_state fft_state48000_960_1 = {
+240, /* nfft */
+0.004166667f, /* scale */
+1, /* shift */
+{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev240, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_240,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_2
+#define FFT_STATE48000_960_2
+static const kiss_fft_state fft_state48000_960_2 = {
+120, /* nfft */
+0.008333333f, /* scale */
+2, /* shift */
+{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev120, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_120,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_3
+#define FFT_STATE48000_960_3
+static const kiss_fft_state fft_state48000_960_3 = {
+60, /* nfft */
+0.016666667f, /* scale */
+3, /* shift */
+{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev60, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_60,
+#else
+NULL,
+#endif
+};
+#endif
+
+#endif
+
+#ifndef MDCT_TWIDDLES960
+#define MDCT_TWIDDLES960
+static const opus_val16 mdct_twiddles960[1800] = {
+0.99999994f, 0.99999321f, 0.99997580f, 0.99994773f, 0.99990886f,
+0.99985933f, 0.99979913f, 0.99972820f, 0.99964654f, 0.99955416f,
+0.99945110f, 0.99933738f, 0.99921292f, 0.99907774f, 0.99893188f,
+0.99877530f, 0.99860805f, 0.99843007f, 0.99824142f, 0.99804211f,
+0.99783206f, 0.99761140f, 0.99737996f, 0.99713790f, 0.99688518f,
+0.99662173f, 0.99634761f, 0.99606287f, 0.99576741f, 0.99546129f,
+0.99514455f, 0.99481714f, 0.99447906f, 0.99413031f, 0.99377096f,
+0.99340093f, 0.99302030f, 0.99262899f, 0.99222708f, 0.99181455f,
+0.99139136f, 0.99095762f, 0.99051321f, 0.99005818f, 0.98959261f,
+0.98911643f, 0.98862964f, 0.98813224f, 0.98762429f, 0.98710573f,
+0.98657662f, 0.98603696f, 0.98548669f, 0.98492593f, 0.98435456f,
+0.98377270f, 0.98318028f, 0.98257732f, 0.98196387f, 0.98133987f,
+0.98070538f, 0.98006040f, 0.97940493f, 0.97873890f, 0.97806245f,
+0.97737551f, 0.97667813f, 0.97597027f, 0.97525197f, 0.97452319f,
+0.97378403f, 0.97303438f, 0.97227436f, 0.97150391f, 0.97072303f,
+0.96993178f, 0.96913016f, 0.96831810f, 0.96749574f, 0.96666300f,
+0.96581990f, 0.96496642f, 0.96410263f, 0.96322852f, 0.96234411f,
+0.96144938f, 0.96054435f, 0.95962906f, 0.95870346f, 0.95776761f,
+0.95682150f, 0.95586514f, 0.95489854f, 0.95392174f, 0.95293468f,
+0.95193744f, 0.95093000f, 0.94991243f, 0.94888461f, 0.94784665f,
+0.94679856f, 0.94574034f, 0.94467193f, 0.94359344f, 0.94250488f,
+0.94140619f, 0.94029742f, 0.93917859f, 0.93804967f, 0.93691075f,
+0.93576175f, 0.93460274f, 0.93343377f, 0.93225473f, 0.93106574f,
+0.92986679f, 0.92865789f, 0.92743903f, 0.92621022f, 0.92497152f,
+0.92372292f, 0.92246443f, 0.92119598f, 0.91991776f, 0.91862965f,
+0.91733170f, 0.91602397f, 0.91470635f, 0.91337901f, 0.91204184f,
+0.91069490f, 0.90933824f, 0.90797186f, 0.90659571f, 0.90520984f,
+0.90381432f, 0.90240908f, 0.90099424f, 0.89956969f, 0.89813554f,
+0.89669174f, 0.89523834f, 0.89377540f, 0.89230281f, 0.89082074f,
+0.88932908f, 0.88782793f, 0.88631725f, 0.88479710f, 0.88326746f,
+0.88172835f, 0.88017982f, 0.87862182f, 0.87705445f, 0.87547767f,
+0.87389153f, 0.87229604f, 0.87069118f, 0.86907703f, 0.86745358f,
+0.86582077f, 0.86417878f, 0.86252749f, 0.86086690f, 0.85919720f,
+0.85751826f, 0.85583007f, 0.85413277f, 0.85242635f, 0.85071075f,
+0.84898609f, 0.84725231f, 0.84550947f, 0.84375757f, 0.84199661f,
+0.84022665f, 0.83844769f, 0.83665979f, 0.83486289f, 0.83305705f,
+0.83124226f, 0.82941860f, 0.82758605f, 0.82574469f, 0.82389444f,
+0.82203537f, 0.82016748f, 0.81829083f, 0.81640542f, 0.81451124f,
+0.81260836f, 0.81069672f, 0.80877650f, 0.80684757f, 0.80490994f,
+0.80296379f, 0.80100900f, 0.79904562f, 0.79707366f, 0.79509324f,
+0.79310423f, 0.79110676f, 0.78910083f, 0.78708643f, 0.78506362f,
+0.78303236f, 0.78099275f, 0.77894479f, 0.77688843f, 0.77482378f,
+0.77275085f, 0.77066964f, 0.76858020f, 0.76648247f, 0.76437658f,
+0.76226246f, 0.76014024f, 0.75800985f, 0.75587130f, 0.75372469f,
+0.75157005f, 0.74940729f, 0.74723655f, 0.74505776f, 0.74287105f,
+0.74067634f, 0.73847371f, 0.73626316f, 0.73404479f, 0.73181850f,
+0.72958434f, 0.72734243f, 0.72509271f, 0.72283524f, 0.72057003f,
+0.71829706f, 0.71601641f, 0.71372813f, 0.71143216f, 0.70912862f,
+0.70681745f, 0.70449871f, 0.70217246f, 0.69983864f, 0.69749737f,
+0.69514859f, 0.69279242f, 0.69042879f, 0.68805778f, 0.68567938f,
+0.68329364f, 0.68090063f, 0.67850029f, 0.67609268f, 0.67367786f,
+0.67125577f, 0.66882652f, 0.66639012f, 0.66394657f, 0.66149592f,
+0.65903819f, 0.65657341f, 0.65410155f, 0.65162271f, 0.64913690f,
+0.64664418f, 0.64414448f, 0.64163786f, 0.63912445f, 0.63660413f,
+0.63407701f, 0.63154310f, 0.62900239f, 0.62645501f, 0.62390089f,
+0.62134010f, 0.61877263f, 0.61619854f, 0.61361790f, 0.61103064f,
+0.60843682f, 0.60583651f, 0.60322970f, 0.60061646f, 0.59799677f,
+0.59537065f, 0.59273821f, 0.59009939f, 0.58745426f, 0.58480281f,
+0.58214509f, 0.57948118f, 0.57681108f, 0.57413477f, 0.57145232f,
+0.56876373f, 0.56606907f, 0.56336832f, 0.56066155f, 0.55794877f,
+0.55523002f, 0.55250537f, 0.54977477f, 0.54703826f, 0.54429591f,
+0.54154772f, 0.53879374f, 0.53603399f, 0.53326851f, 0.53049731f,
+0.52772039f, 0.52493787f, 0.52214974f, 0.51935595f, 0.51655668f,
+0.51375180f, 0.51094145f, 0.50812566f, 0.50530440f, 0.50247771f,
+0.49964568f, 0.49680826f, 0.49396557f, 0.49111754f, 0.48826426f,
+0.48540577f, 0.48254207f, 0.47967321f, 0.47679919f, 0.47392011f,
+0.47103590f, 0.46814668f, 0.46525243f, 0.46235323f, 0.45944905f,
+0.45653993f, 0.45362595f, 0.45070711f, 0.44778344f, 0.44485497f,
+0.44192174f, 0.43898380f, 0.43604112f, 0.43309379f, 0.43014181f,
+0.42718524f, 0.42422408f, 0.42125839f, 0.41828820f, 0.41531351f,
+0.41233435f, 0.40935081f, 0.40636289f, 0.40337059f, 0.40037400f,
+0.39737311f, 0.39436796f, 0.39135858f, 0.38834500f, 0.38532731f,
+0.38230544f, 0.37927949f, 0.37624949f, 0.37321547f, 0.37017745f,
+0.36713544f, 0.36408952f, 0.36103970f, 0.35798600f, 0.35492846f,
+0.35186714f, 0.34880206f, 0.34573323f, 0.34266070f, 0.33958447f,
+0.33650464f, 0.33342120f, 0.33033419f, 0.32724363f, 0.32414958f,
+0.32105204f, 0.31795108f, 0.31484672f, 0.31173897f, 0.30862790f,
+0.30551350f, 0.30239585f, 0.29927495f, 0.29615086f, 0.29302359f,
+0.28989318f, 0.28675964f, 0.28362307f, 0.28048345f, 0.27734083f,
+0.27419522f, 0.27104670f, 0.26789525f, 0.26474094f, 0.26158381f,
+0.25842386f, 0.25526115f, 0.25209570f, 0.24892756f, 0.24575676f,
+0.24258332f, 0.23940729f, 0.23622867f, 0.23304754f, 0.22986393f,
+0.22667783f, 0.22348931f, 0.22029841f, 0.21710514f, 0.21390954f,
+0.21071166f, 0.20751151f, 0.20430915f, 0.20110460f, 0.19789790f,
+0.19468907f, 0.19147816f, 0.18826519f, 0.18505022f, 0.18183327f,
+0.17861435f, 0.17539354f, 0.17217083f, 0.16894630f, 0.16571994f,
+0.16249183f, 0.15926196f, 0.15603039f, 0.15279715f, 0.14956227f,
+0.14632578f, 0.14308774f, 0.13984816f, 0.13660708f, 0.13336454f,
+0.13012058f, 0.12687522f, 0.12362850f, 0.12038045f, 0.11713112f,
+0.11388054f, 0.11062872f, 0.10737573f, 0.10412160f, 0.10086634f,
+0.097609997f, 0.094352618f, 0.091094226f, 0.087834857f, 0.084574550f,
+0.081313334f, 0.078051247f, 0.074788325f, 0.071524605f, 0.068260118f,
+0.064994894f, 0.061728980f, 0.058462404f, 0.055195201f, 0.051927410f,
+0.048659060f, 0.045390189f, 0.042120833f, 0.038851023f, 0.035580799f,
+0.032310195f, 0.029039243f, 0.025767982f, 0.022496443f, 0.019224664f,
+0.015952680f, 0.012680525f, 0.0094082337f, 0.0061358409f, 0.0028633832f,
+-0.00040910527f, -0.0036815894f, -0.0069540343f, -0.010226404f, -0.013498665f,
+-0.016770782f, -0.020042717f, -0.023314439f, -0.026585912f, -0.029857099f,
+-0.033127967f, -0.036398482f, -0.039668605f, -0.042938303f, -0.046207540f,
+-0.049476285f, -0.052744497f, -0.056012146f, -0.059279196f, -0.062545612f,
+-0.065811358f, -0.069076397f, -0.072340697f, -0.075604223f, -0.078866936f,
+-0.082128808f, -0.085389800f, -0.088649876f, -0.091909006f, -0.095167145f,
+-0.098424271f, -0.10168034f, -0.10493532f, -0.10818918f, -0.11144188f,
+-0.11469338f, -0.11794366f, -0.12119267f, -0.12444039f, -0.12768677f,
+-0.13093179f, -0.13417540f, -0.13741758f, -0.14065829f, -0.14389749f,
+-0.14713514f, -0.15037122f, -0.15360570f, -0.15683852f, -0.16006967f,
+-0.16329910f, -0.16652679f, -0.16975269f, -0.17297678f, -0.17619900f,
+-0.17941935f, -0.18263777f, -0.18585424f, -0.18906870f, -0.19228116f,
+-0.19549155f, -0.19869985f, -0.20190603f, -0.20511003f, -0.20831184f,
+-0.21151142f, -0.21470875f, -0.21790376f, -0.22109644f, -0.22428675f,
+-0.22747467f, -0.23066014f, -0.23384315f, -0.23702365f, -0.24020162f,
+-0.24337701f, -0.24654980f, -0.24971995f, -0.25288740f, -0.25605217f,
+-0.25921419f, -0.26237345f, -0.26552987f, -0.26868346f, -0.27183419f,
+-0.27498198f, -0.27812684f, -0.28126872f, -0.28440759f, -0.28754342f,
+-0.29067615f, -0.29380578f, -0.29693225f, -0.30005556f, -0.30317566f,
+-0.30629250f, -0.30940607f, -0.31251630f, -0.31562322f, -0.31872672f,
+-0.32182685f, -0.32492352f, -0.32801670f, -0.33110636f, -0.33419248f,
+-0.33727503f, -0.34035397f, -0.34342924f, -0.34650084f, -0.34956875f,
+-0.35263291f, -0.35569328f, -0.35874987f, -0.36180258f, -0.36485144f,
+-0.36789638f, -0.37093741f, -0.37397444f, -0.37700745f, -0.38003644f,
+-0.38306138f, -0.38608220f, -0.38909888f, -0.39211139f, -0.39511973f,
+-0.39812380f, -0.40112361f, -0.40411916f, -0.40711036f, -0.41009718f,
+-0.41307965f, -0.41605768f, -0.41903123f, -0.42200032f, -0.42496487f,
+-0.42792490f, -0.43088034f, -0.43383113f, -0.43677729f, -0.43971881f,
+-0.44265559f, -0.44558764f, -0.44851488f, -0.45143735f, -0.45435500f,
+-0.45726776f, -0.46017563f, -0.46307856f, -0.46597654f, -0.46886954f,
+-0.47175750f, -0.47464043f, -0.47751826f, -0.48039100f, -0.48325855f,
+-0.48612097f, -0.48897815f, -0.49183011f, -0.49467680f, -0.49751821f,
+-0.50035429f, -0.50318497f, -0.50601029f, -0.50883019f, -0.51164466f,
+-0.51445359f, -0.51725709f, -0.52005500f, -0.52284735f, -0.52563411f,
+-0.52841520f, -0.53119069f, -0.53396046f, -0.53672451f, -0.53948283f,
+-0.54223537f, -0.54498214f, -0.54772300f, -0.55045801f, -0.55318713f,
+-0.55591035f, -0.55862761f, -0.56133890f, -0.56404412f, -0.56674337f,
+-0.56943649f, -0.57212353f, -0.57480448f, -0.57747924f, -0.58014780f,
+-0.58281022f, -0.58546633f, -0.58811617f, -0.59075975f, -0.59339696f,
+-0.59602785f, -0.59865236f, -0.60127044f, -0.60388207f, -0.60648727f,
+-0.60908598f, -0.61167812f, -0.61426371f, -0.61684275f, -0.61941516f,
+-0.62198097f, -0.62454009f, -0.62709254f, -0.62963831f, -0.63217729f,
+-0.63470948f, -0.63723493f, -0.63975352f, -0.64226526f, -0.64477009f,
+-0.64726806f, -0.64975911f, -0.65224314f, -0.65472025f, -0.65719032f,
+-0.65965337f, -0.66210932f, -0.66455823f, -0.66700000f, -0.66943461f,
+-0.67186207f, -0.67428231f, -0.67669535f, -0.67910111f, -0.68149966f,
+-0.68389088f, -0.68627477f, -0.68865126f, -0.69102043f, -0.69338220f,
+-0.69573659f, -0.69808346f, -0.70042288f, -0.70275480f, -0.70507920f,
+-0.70739603f, -0.70970529f, -0.71200693f, -0.71430099f, -0.71658736f,
+-0.71886611f, -0.72113711f, -0.72340041f, -0.72565591f, -0.72790372f,
+-0.73014367f, -0.73237586f, -0.73460019f, -0.73681659f, -0.73902518f,
+-0.74122584f, -0.74341851f, -0.74560326f, -0.74778003f, -0.74994880f,
+-0.75210953f, -0.75426215f, -0.75640678f, -0.75854325f, -0.76067162f,
+-0.76279181f, -0.76490390f, -0.76700771f, -0.76910341f, -0.77119076f,
+-0.77326995f, -0.77534080f, -0.77740335f, -0.77945763f, -0.78150350f,
+-0.78354102f, -0.78557014f, -0.78759086f, -0.78960317f, -0.79160696f,
+-0.79360235f, -0.79558921f, -0.79756755f, -0.79953730f, -0.80149853f,
+-0.80345118f, -0.80539525f, -0.80733067f, -0.80925739f, -0.81117553f,
+-0.81308490f, -0.81498563f, -0.81687760f, -0.81876087f, -0.82063532f,
+-0.82250100f, -0.82435787f, -0.82620591f, -0.82804507f, -0.82987541f,
+-0.83169687f, -0.83350939f, -0.83531296f, -0.83710766f, -0.83889335f,
+-0.84067005f, -0.84243774f, -0.84419644f, -0.84594607f, -0.84768665f,
+-0.84941816f, -0.85114056f, -0.85285389f, -0.85455805f, -0.85625303f,
+-0.85793889f, -0.85961550f, -0.86128294f, -0.86294121f, -0.86459017f,
+-0.86622989f, -0.86786032f, -0.86948150f, -0.87109333f, -0.87269586f,
+-0.87428904f, -0.87587279f, -0.87744725f, -0.87901229f, -0.88056785f,
+-0.88211405f, -0.88365078f, -0.88517809f, -0.88669586f, -0.88820416f,
+-0.88970292f, -0.89119220f, -0.89267188f, -0.89414203f, -0.89560264f,
+-0.89705360f, -0.89849502f, -0.89992678f, -0.90134889f, -0.90276134f,
+-0.90416414f, -0.90555727f, -0.90694070f, -0.90831441f, -0.90967834f,
+-0.91103262f, -0.91237706f, -0.91371179f, -0.91503674f, -0.91635185f,
+-0.91765714f, -0.91895264f, -0.92023826f, -0.92151409f, -0.92277998f,
+-0.92403603f, -0.92528218f, -0.92651838f, -0.92774469f, -0.92896110f,
+-0.93016750f, -0.93136400f, -0.93255049f, -0.93372697f, -0.93489349f,
+-0.93604994f, -0.93719643f, -0.93833286f, -0.93945926f, -0.94057560f,
+-0.94168180f, -0.94277799f, -0.94386405f, -0.94494003f, -0.94600588f,
+-0.94706154f, -0.94810712f, -0.94914252f, -0.95016778f, -0.95118284f,
+-0.95218778f, -0.95318246f, -0.95416695f, -0.95514119f, -0.95610523f,
+-0.95705903f, -0.95800257f, -0.95893586f, -0.95985889f, -0.96077162f,
+-0.96167403f, -0.96256620f, -0.96344805f, -0.96431959f, -0.96518075f,
+-0.96603161f, -0.96687216f, -0.96770233f, -0.96852213f, -0.96933156f,
+-0.97013056f, -0.97091925f, -0.97169751f, -0.97246534f, -0.97322279f,
+-0.97396982f, -0.97470641f, -0.97543252f, -0.97614825f, -0.97685349f,
+-0.97754824f, -0.97823256f, -0.97890645f, -0.97956979f, -0.98022264f,
+-0.98086500f, -0.98149687f, -0.98211825f, -0.98272908f, -0.98332942f,
+-0.98391914f, -0.98449844f, -0.98506713f, -0.98562527f, -0.98617285f,
+-0.98670989f, -0.98723638f, -0.98775226f, -0.98825759f, -0.98875231f,
+-0.98923647f, -0.98971003f, -0.99017298f, -0.99062532f, -0.99106705f,
+-0.99149817f, -0.99191868f, -0.99232858f, -0.99272782f, -0.99311644f,
+-0.99349445f, -0.99386179f, -0.99421853f, -0.99456459f, -0.99489999f,
+-0.99522477f, -0.99553883f, -0.99584228f, -0.99613506f, -0.99641716f,
+-0.99668860f, -0.99694937f, -0.99719942f, -0.99743885f, -0.99766755f,
+-0.99788558f, -0.99809295f, -0.99828959f, -0.99847561f, -0.99865085f,
+-0.99881548f, -0.99896932f, -0.99911255f, -0.99924499f, -0.99936682f,
+-0.99947786f, -0.99957830f, -0.99966794f, -0.99974692f, -0.99981517f,
+-0.99987274f, -0.99991959f, -0.99995571f, -0.99998116f, -0.99999589f,
+0.99999964f, 0.99997288f, 0.99990326f, 0.99979085f, 0.99963558f,
+0.99943751f, 0.99919659f, 0.99891287f, 0.99858636f, 0.99821711f,
+0.99780506f, 0.99735034f, 0.99685282f, 0.99631262f, 0.99572974f,
+0.99510419f, 0.99443603f, 0.99372530f, 0.99297196f, 0.99217612f,
+0.99133772f, 0.99045694f, 0.98953366f, 0.98856801f, 0.98756003f,
+0.98650974f, 0.98541719f, 0.98428243f, 0.98310548f, 0.98188645f,
+0.98062533f, 0.97932225f, 0.97797716f, 0.97659022f, 0.97516143f,
+0.97369087f, 0.97217858f, 0.97062469f, 0.96902919f, 0.96739221f,
+0.96571374f, 0.96399397f, 0.96223283f, 0.96043050f, 0.95858705f,
+0.95670253f, 0.95477700f, 0.95281059f, 0.95080340f, 0.94875544f,
+0.94666684f, 0.94453770f, 0.94236809f, 0.94015813f, 0.93790787f,
+0.93561745f, 0.93328691f, 0.93091643f, 0.92850608f, 0.92605597f,
+0.92356616f, 0.92103678f, 0.91846794f, 0.91585976f, 0.91321236f,
+0.91052586f, 0.90780038f, 0.90503591f, 0.90223277f, 0.89939094f,
+0.89651060f, 0.89359182f, 0.89063478f, 0.88763964f, 0.88460642f,
+0.88153529f, 0.87842643f, 0.87527996f, 0.87209594f, 0.86887461f,
+0.86561602f, 0.86232042f, 0.85898781f, 0.85561842f, 0.85221243f,
+0.84876984f, 0.84529096f, 0.84177583f, 0.83822471f, 0.83463764f,
+0.83101481f, 0.82735640f, 0.82366252f, 0.81993335f, 0.81616908f,
+0.81236988f, 0.80853581f, 0.80466717f, 0.80076402f, 0.79682660f,
+0.79285502f, 0.78884947f, 0.78481019f, 0.78073722f, 0.77663082f,
+0.77249116f, 0.76831841f, 0.76411277f, 0.75987434f, 0.75560343f,
+0.75130010f, 0.74696463f, 0.74259710f, 0.73819780f, 0.73376691f,
+0.72930455f, 0.72481096f, 0.72028631f, 0.71573079f, 0.71114463f,
+0.70652801f, 0.70188117f, 0.69720417f, 0.69249737f, 0.68776089f,
+0.68299496f, 0.67819971f, 0.67337549f, 0.66852236f, 0.66364062f,
+0.65873051f, 0.65379208f, 0.64882571f, 0.64383155f, 0.63880974f,
+0.63376063f, 0.62868434f, 0.62358117f, 0.61845124f, 0.61329484f,
+0.60811216f, 0.60290343f, 0.59766883f, 0.59240872f, 0.58712316f,
+0.58181250f, 0.57647687f, 0.57111657f, 0.56573176f, 0.56032276f,
+0.55488980f, 0.54943299f, 0.54395270f, 0.53844911f, 0.53292239f,
+0.52737290f, 0.52180082f, 0.51620632f, 0.51058978f, 0.50495136f,
+0.49929130f, 0.49360985f, 0.48790723f, 0.48218375f, 0.47643960f,
+0.47067502f, 0.46489030f, 0.45908567f, 0.45326138f, 0.44741765f,
+0.44155475f, 0.43567297f, 0.42977250f, 0.42385364f, 0.41791660f,
+0.41196167f, 0.40598908f, 0.39999911f, 0.39399201f, 0.38796803f,
+0.38192743f, 0.37587047f, 0.36979741f, 0.36370850f, 0.35760403f,
+0.35148421f, 0.34534934f, 0.33919969f, 0.33303553f, 0.32685706f,
+0.32066461f, 0.31445843f, 0.30823877f, 0.30200592f, 0.29576012f,
+0.28950164f, 0.28323078f, 0.27694780f, 0.27065292f, 0.26434645f,
+0.25802869f, 0.25169984f, 0.24536023f, 0.23901010f, 0.23264973f,
+0.22627939f, 0.21989937f, 0.21350993f, 0.20711134f, 0.20070387f,
+0.19428782f, 0.18786344f, 0.18143101f, 0.17499080f, 0.16854310f,
+0.16208819f, 0.15562633f, 0.14915779f, 0.14268288f, 0.13620184f,
+0.12971498f, 0.12322257f, 0.11672486f, 0.11022217f, 0.10371475f,
+0.097202882f, 0.090686858f, 0.084166944f, 0.077643424f, 0.071116582f,
+0.064586692f, 0.058054037f, 0.051518895f, 0.044981543f, 0.038442269f,
+0.031901345f, 0.025359053f, 0.018815678f, 0.012271495f, 0.0057267868f,
+-0.00081816671f, -0.0073630852f, -0.013907688f, -0.020451695f, -0.026994826f,
+-0.033536803f, -0.040077340f, -0.046616159f, -0.053152986f, -0.059687532f,
+-0.066219524f, -0.072748676f, -0.079274714f, -0.085797355f, -0.092316322f,
+-0.098831341f, -0.10534211f, -0.11184838f, -0.11834986f, -0.12484626f,
+-0.13133731f, -0.13782275f, -0.14430228f, -0.15077563f, -0.15724251f,
+-0.16370267f, -0.17015581f, -0.17660165f, -0.18303993f, -0.18947038f,
+-0.19589271f, -0.20230664f, -0.20871192f, -0.21510825f, -0.22149536f,
+-0.22787298f, -0.23424086f, -0.24059868f, -0.24694622f, -0.25328314f,
+-0.25960925f, -0.26592422f, -0.27222782f, -0.27851975f, -0.28479972f,
+-0.29106751f, -0.29732284f, -0.30356544f, -0.30979502f, -0.31601134f,
+-0.32221413f, -0.32840309f, -0.33457801f, -0.34073856f, -0.34688455f,
+-0.35301566f, -0.35913166f, -0.36523229f, -0.37131724f, -0.37738630f,
+-0.38343921f, -0.38947567f, -0.39549544f, -0.40149832f, -0.40748394f,
+-0.41345215f, -0.41940263f, -0.42533514f, -0.43124944f, -0.43714526f,
+-0.44302234f, -0.44888046f, -0.45471936f, -0.46053877f, -0.46633846f,
+-0.47211814f, -0.47787762f, -0.48361665f, -0.48933494f, -0.49503228f,
+-0.50070840f, -0.50636309f, -0.51199609f, -0.51760709f, -0.52319598f,
+-0.52876246f, -0.53430629f, -0.53982723f, -0.54532504f, -0.55079949f,
+-0.55625033f, -0.56167740f, -0.56708032f, -0.57245898f, -0.57781315f,
+-0.58314258f, -0.58844697f, -0.59372622f, -0.59897995f, -0.60420811f,
+-0.60941035f, -0.61458647f, -0.61973625f, -0.62485951f, -0.62995601f,
+-0.63502556f, -0.64006782f, -0.64508271f, -0.65007001f, -0.65502942f,
+-0.65996075f, -0.66486382f, -0.66973841f, -0.67458433f, -0.67940134f,
+-0.68418926f, -0.68894786f, -0.69367695f, -0.69837630f, -0.70304573f,
+-0.70768511f, -0.71229410f, -0.71687263f, -0.72142041f, -0.72593731f,
+-0.73042315f, -0.73487765f, -0.73930067f, -0.74369204f, -0.74805158f,
+-0.75237900f, -0.75667429f, -0.76093709f, -0.76516730f, -0.76936477f,
+-0.77352923f, -0.77766061f, -0.78175867f, -0.78582323f, -0.78985411f,
+-0.79385114f, -0.79781419f, -0.80174309f, -0.80563760f, -0.80949765f,
+-0.81332302f, -0.81711352f, -0.82086903f, -0.82458937f, -0.82827437f,
+-0.83192390f, -0.83553779f, -0.83911592f, -0.84265804f, -0.84616417f,
+-0.84963393f, -0.85306740f, -0.85646427f, -0.85982448f, -0.86314780f,
+-0.86643422f, -0.86968350f, -0.87289548f, -0.87607014f, -0.87920725f,
+-0.88230664f, -0.88536829f, -0.88839203f, -0.89137769f, -0.89432514f,
+-0.89723432f, -0.90010506f, -0.90293723f, -0.90573072f, -0.90848541f,
+-0.91120118f, -0.91387796f, -0.91651553f, -0.91911387f, -0.92167282f,
+-0.92419231f, -0.92667222f, -0.92911243f, -0.93151283f, -0.93387336f,
+-0.93619382f, -0.93847424f, -0.94071442f, -0.94291431f, -0.94507378f,
+-0.94719279f, -0.94927126f, -0.95130903f, -0.95330608f, -0.95526224f,
+-0.95717752f, -0.95905179f, -0.96088499f, -0.96267700f, -0.96442777f,
+-0.96613729f, -0.96780539f, -0.96943200f, -0.97101706f, -0.97256058f,
+-0.97406244f, -0.97552258f, -0.97694093f, -0.97831738f, -0.97965199f,
+-0.98094457f, -0.98219514f, -0.98340368f, -0.98457009f, -0.98569429f,
+-0.98677629f, -0.98781598f, -0.98881340f, -0.98976845f, -0.99068111f,
+-0.99155134f, -0.99237907f, -0.99316430f, -0.99390697f, -0.99460709f,
+-0.99526459f, -0.99587947f, -0.99645168f, -0.99698120f, -0.99746799f,
+-0.99791211f, -0.99831343f, -0.99867201f, -0.99898779f, -0.99926084f,
+-0.99949104f, -0.99967843f, -0.99982297f, -0.99992472f, -0.99998361f,
+0.99999869f, 0.99989158f, 0.99961317f, 0.99916345f, 0.99854255f,
+0.99775058f, 0.99678761f, 0.99565387f, 0.99434954f, 0.99287480f,
+0.99122995f, 0.98941529f, 0.98743105f, 0.98527765f, 0.98295540f,
+0.98046476f, 0.97780609f, 0.97497988f, 0.97198665f, 0.96882683f,
+0.96550101f, 0.96200979f, 0.95835376f, 0.95453346f, 0.95054960f,
+0.94640291f, 0.94209403f, 0.93762374f, 0.93299282f, 0.92820197f,
+0.92325211f, 0.91814411f, 0.91287869f, 0.90745693f, 0.90187967f,
+0.89614785f, 0.89026248f, 0.88422459f, 0.87803519f, 0.87169534f,
+0.86520612f, 0.85856867f, 0.85178405f, 0.84485358f, 0.83777827f,
+0.83055943f, 0.82319832f, 0.81569612f, 0.80805415f, 0.80027372f,
+0.79235619f, 0.78430289f, 0.77611518f, 0.76779449f, 0.75934225f,
+0.75075996f, 0.74204898f, 0.73321080f, 0.72424710f, 0.71515924f,
+0.70594883f, 0.69661748f, 0.68716675f, 0.67759830f, 0.66791373f,
+0.65811473f, 0.64820296f, 0.63818014f, 0.62804794f, 0.61780810f,
+0.60746247f, 0.59701276f, 0.58646071f, 0.57580817f, 0.56505698f,
+0.55420899f, 0.54326600f, 0.53222996f, 0.52110273f, 0.50988621f,
+0.49858227f, 0.48719296f, 0.47572014f, 0.46416581f, 0.45253196f,
+0.44082057f, 0.42903364f, 0.41717321f, 0.40524128f, 0.39323992f,
+0.38117120f, 0.36903715f, 0.35683987f, 0.34458145f, 0.33226398f,
+0.31988961f, 0.30746040f, 0.29497850f, 0.28244606f, 0.26986524f,
+0.25723818f, 0.24456702f, 0.23185398f, 0.21910121f, 0.20631088f,
+0.19348522f, 0.18062639f, 0.16773662f, 0.15481812f, 0.14187308f,
+0.12890373f, 0.11591230f, 0.10290100f, 0.089872077f, 0.076827750f,
+0.063770257f, 0.050701842f, 0.037624735f, 0.024541186f, 0.011453429f,
+-0.0016362892f, -0.014725727f, -0.027812643f, -0.040894791f, -0.053969935f,
+-0.067035832f, -0.080090240f, -0.093130924f, -0.10615565f, -0.11916219f,
+-0.13214831f, -0.14511178f, -0.15805040f, -0.17096193f, -0.18384418f,
+-0.19669491f, -0.20951195f, -0.22229309f, -0.23503613f, -0.24773891f,
+-0.26039925f, -0.27301496f, -0.28558388f, -0.29810387f, -0.31057280f,
+-0.32298848f, -0.33534884f, -0.34765175f, -0.35989508f, -0.37207675f,
+-0.38419467f, -0.39624676f, -0.40823093f, -0.42014518f, -0.43198743f,
+-0.44375566f, -0.45544785f, -0.46706200f, -0.47859612f, -0.49004826f,
+-0.50141639f, -0.51269865f, -0.52389306f, -0.53499764f, -0.54601061f,
+-0.55693001f, -0.56775403f, -0.57848072f, -0.58910829f, -0.59963489f,
+-0.61005878f, -0.62037814f, -0.63059121f, -0.64069623f, -0.65069145f,
+-0.66057515f, -0.67034572f, -0.68000144f, -0.68954057f, -0.69896162f,
+-0.70826286f, -0.71744281f, -0.72649974f, -0.73543227f, -0.74423873f,
+-0.75291771f, -0.76146764f, -0.76988715f, -0.77817470f, -0.78632891f,
+-0.79434842f, -0.80223179f, -0.80997771f, -0.81758487f, -0.82505190f,
+-0.83237761f, -0.83956063f, -0.84659988f, -0.85349399f, -0.86024189f,
+-0.86684239f, -0.87329435f, -0.87959671f, -0.88574833f, -0.89174819f,
+-0.89759529f, -0.90328854f, -0.90882701f, -0.91420978f, -0.91943592f,
+-0.92450452f, -0.92941469f, -0.93416560f, -0.93875647f, -0.94318646f,
+-0.94745487f, -0.95156091f, -0.95550388f, -0.95928317f, -0.96289814f,
+-0.96634805f, -0.96963239f, -0.97275060f, -0.97570217f, -0.97848648f,
+-0.98110318f, -0.98355180f, -0.98583186f, -0.98794299f, -0.98988485f,
+-0.99165714f, -0.99325943f, -0.99469161f, -0.99595332f, -0.99704438f,
+-0.99796462f, -0.99871385f, -0.99929196f, -0.99969882f, -0.99993443f,
+0.99999464f, 0.99956632f, 0.99845290f, 0.99665523f, 0.99417448f,
+0.99101239f, 0.98717111f, 0.98265326f, 0.97746199f, 0.97160077f,
+0.96507365f, 0.95788515f, 0.95004016f, 0.94154406f, 0.93240267f,
+0.92262226f, 0.91220951f, 0.90117162f, 0.88951606f, 0.87725091f,
+0.86438453f, 0.85092574f, 0.83688372f, 0.82226819f, 0.80708915f,
+0.79135692f, 0.77508235f, 0.75827658f, 0.74095112f, 0.72311783f,
+0.70478898f, 0.68597710f, 0.66669506f, 0.64695615f, 0.62677377f,
+0.60616189f, 0.58513457f, 0.56370622f, 0.54189157f, 0.51970547f,
+0.49716324f, 0.47428027f, 0.45107225f, 0.42755505f, 0.40374488f,
+0.37965798f, 0.35531086f, 0.33072025f, 0.30590299f, 0.28087607f,
+0.25565663f, 0.23026201f, 0.20470956f, 0.17901683f, 0.15320139f,
+0.12728097f, 0.10127331f, 0.075196236f, 0.049067631f, 0.022905400f,
+-0.0032725304f, -0.029448219f, -0.055603724f, -0.081721120f, -0.10778251f,
+-0.13377003f, -0.15966587f, -0.18545228f, -0.21111161f, -0.23662624f,
+-0.26197869f, -0.28715160f, -0.31212771f, -0.33688989f, -0.36142120f,
+-0.38570482f, -0.40972409f, -0.43346253f, -0.45690393f, -0.48003218f,
+-0.50283146f, -0.52528608f, -0.54738069f, -0.56910020f, -0.59042966f,
+-0.61135447f, -0.63186026f, -0.65193301f, -0.67155898f, -0.69072473f,
+-0.70941705f, -0.72762316f, -0.74533063f, -0.76252723f, -0.77920127f,
+-0.79534131f, -0.81093621f, -0.82597536f, -0.84044844f, -0.85434550f,
+-0.86765707f, -0.88037395f, -0.89248747f, -0.90398932f, -0.91487163f,
+-0.92512697f, -0.93474823f, -0.94372886f, -0.95206273f, -0.95974404f,
+-0.96676767f, -0.97312868f, -0.97882277f, -0.98384601f, -0.98819500f,
+-0.99186671f, -0.99485862f, -0.99716878f, -0.99879545f, -0.99973762f,
+};
+#endif
+
+static const CELTMode mode48000_960_120 = {
+48000, /* Fs */
+120, /* overlap */
+21, /* nbEBands */
+21, /* effEBands */
+{0.85000610f, 0.0000000f, 1.0000000f, 1.0000000f, }, /* preemph */
+eband5ms, /* eBands */
+3, /* maxLM */
+8, /* nbShortMdcts */
+120, /* shortMdctSize */
+11, /* nbAllocVectors */
+band_allocation, /* allocVectors */
+logN400, /* logN */
+window120, /* window */
+{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */
+{392, cache_index50, cache_bits50, cache_caps50}, /* cache */
+};
+
+/* List of all the available modes */
+#define TOTAL_MODES 1
+static const CELTMode * const static_mode_list[TOTAL_MODES] = {
+&mode48000_960_120,
+};
diff --git a/external/opus-1.1.4/celt/static_modes_float_arm_ne10.h b/external/opus-1.1.4/celt/static_modes_float_arm_ne10.h
new file mode 100644
index 0000000..934a82a
--- /dev/null
+++ b/external/opus-1.1.4/celt/static_modes_float_arm_ne10.h
@@ -0,0 +1,404 @@
+/* The contents of this file was automatically generated by
+ * dump_mode_arm_ne10.c with arguments: 48000 960
+ * It contains static definitions for some pre-defined modes. */
+#include <NE10_init.h>
+
+#ifndef NE10_FFT_PARAMS48000_960
+#define NE10_FFT_PARAMS48000_960
+static const ne10_int32_t ne10_factors_480[64] = {
+4, 40, 4, 30, 2, 15, 5, 3, 3, 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, };
+static const ne10_int32_t ne10_factors_240[64] = {
+3, 20, 4, 15, 5, 3, 3, 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, };
+static const ne10_int32_t ne10_factors_120[64] = {
+3, 10, 2, 15, 5, 3, 3, 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, };
+static const ne10_int32_t ne10_factors_60[64] = {
+2, 5, 5, 3, 3, 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, };
+static const ne10_fft_cpx_float32_t ne10_twiddles_480[480] = {
+{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f},
+{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f},
+{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f},
+{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f},
+{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f},
+{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f},
+{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f},
+{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f},
+{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f},
+{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f},
+{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f},
+{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f},
+{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f},
+{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f},
+{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f},
+{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f},
+{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f},
+{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f},
+{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f},
+{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f},
+{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f},
+{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f},
+{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f},
+{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f},
+{-4.3711388e-08f,-1.0000000f}, {-0.10452851f,-0.99452192f}, {-0.20791174f,-0.97814757f},
+{-0.30901703f,-0.95105648f}, {-0.40673670f,-0.91354543f}, {-0.50000006f,-0.86602533f},
+{-0.58778518f,-0.80901700f}, {-0.66913068f,-0.74314475f}, {-0.74314493f,-0.66913044f},
+{-0.80901700f,-0.58778518f}, {-0.86602539f,-0.50000006f}, {-0.91354549f,-0.40673658f},
+{-0.95105654f,-0.30901679f}, {-0.97814763f,-0.20791161f}, {-0.99452192f,-0.10452849f},
+{1.0000000f,-0.0000000f}, {0.98768836f,-0.15643448f}, {0.95105648f,-0.30901700f},
+{0.89100653f,-0.45399052f}, {0.80901700f,-0.58778524f}, {0.70710677f,-0.70710683f},
+{0.58778524f,-0.80901700f}, {0.45399052f,-0.89100653f}, {0.30901697f,-0.95105654f},
+{0.15643437f,-0.98768836f}, {-4.3711388e-08f,-1.0000000f}, {-0.15643445f,-0.98768836f},
+{-0.30901703f,-0.95105648f}, {-0.45399061f,-0.89100647f}, {-0.58778518f,-0.80901700f},
+{-0.70710677f,-0.70710677f}, {-0.80901700f,-0.58778518f}, {-0.89100659f,-0.45399037f},
+{-0.95105654f,-0.30901679f}, {-0.98768836f,-0.15643445f}, {-1.0000000f,8.7422777e-08f},
+{-0.98768830f,0.15643461f}, {-0.95105654f,0.30901697f}, {-0.89100653f,0.45399055f},
+{-0.80901694f,0.58778536f}, {-0.70710665f,0.70710689f}, {-0.58778507f,0.80901712f},
+{-0.45399022f,0.89100665f}, {-0.30901709f,0.95105648f}, {-0.15643452f,0.98768830f},
+{1.0000000f,-0.0000000f}, {0.99991435f,-0.013089596f}, {0.99965733f,-0.026176950f},
+{0.99922901f,-0.039259817f}, {0.99862951f,-0.052335959f}, {0.99785894f,-0.065403134f},
+{0.99691731f,-0.078459099f}, {0.99580491f,-0.091501623f}, {0.99452192f,-0.10452846f},
+{0.99306846f,-0.11753740f}, {0.99144489f,-0.13052620f}, {0.98965138f,-0.14349262f},
+{0.98768836f,-0.15643448f}, {0.98555607f,-0.16934951f}, {0.98325491f,-0.18223552f},
+{0.98078525f,-0.19509032f}, {0.97814763f,-0.20791170f}, {0.97534233f,-0.22069745f},
+{0.97236991f,-0.23344538f}, {0.96923089f,-0.24615330f}, {0.96592581f,-0.25881904f},
+{0.96245521f,-0.27144045f}, {0.95881975f,-0.28401536f}, {0.95501995f,-0.29654160f},
+{0.95105648f,-0.30901700f}, {0.94693011f,-0.32143945f}, {0.94264150f,-0.33380687f},
+{0.93819129f,-0.34611708f}, {0.93358040f,-0.35836795f}, {0.92880952f,-0.37055743f},
+{0.92387956f,-0.38268346f}, {0.91879117f,-0.39474389f}, {0.91354543f,-0.40673664f},
+{0.90814316f,-0.41865975f}, {0.90258527f,-0.43051112f}, {0.89687270f,-0.44228873f},
+{0.89100653f,-0.45399052f}, {0.88498765f,-0.46561453f}, {0.87881708f,-0.47715878f},
+{0.87249601f,-0.48862126f}, {0.86602545f,-0.50000000f}, {0.85940641f,-0.51129311f},
+{0.85264015f,-0.52249855f}, {0.84572786f,-0.53361452f}, {0.83867055f,-0.54463905f},
+{0.83146960f,-0.55557024f}, {0.82412618f,-0.56640625f}, {0.81664151f,-0.57714522f},
+{0.80901700f,-0.58778524f}, {0.80125380f,-0.59832460f}, {0.79335332f,-0.60876143f},
+{0.78531694f,-0.61909395f}, {0.77714598f,-0.62932038f}, {0.76884180f,-0.63943899f},
+{0.76040596f,-0.64944810f}, {0.75183982f,-0.65934587f}, {0.74314475f,-0.66913062f},
+{0.73432249f,-0.67880076f}, {0.72537434f,-0.68835455f}, {0.71630192f,-0.69779050f},
+{0.70710677f,-0.70710683f}, {0.69779044f,-0.71630198f}, {0.68835455f,-0.72537440f},
+{0.67880070f,-0.73432255f}, {0.66913056f,-0.74314487f}, {0.65934581f,-0.75183982f},
+{0.64944804f,-0.76040596f}, {0.63943899f,-0.76884186f}, {0.62932038f,-0.77714598f},
+{0.61909395f,-0.78531694f}, {0.60876137f,-0.79335338f}, {0.59832460f,-0.80125386f},
+{0.58778524f,-0.80901700f}, {0.57714516f,-0.81664151f}, {0.56640625f,-0.82412618f},
+{0.55557019f,-0.83146960f}, {0.54463899f,-0.83867055f}, {0.53361452f,-0.84572786f},
+{0.52249849f,-0.85264015f}, {0.51129311f,-0.85940641f}, {0.49999997f,-0.86602545f},
+{0.48862118f,-0.87249601f}, {0.47715876f,-0.87881708f}, {0.46561447f,-0.88498765f},
+{0.45399052f,-0.89100653f}, {0.44228867f,-0.89687276f}, {0.43051103f,-0.90258533f},
+{0.41865975f,-0.90814316f}, {0.40673661f,-0.91354549f}, {0.39474380f,-0.91879129f},
+{0.38268343f,-0.92387956f}, {0.37055740f,-0.92880958f}, {0.35836786f,-0.93358046f},
+{0.34611705f,-0.93819135f}, {0.33380681f,-0.94264150f}, {0.32143947f,-0.94693011f},
+{0.30901697f,-0.95105654f}, {0.29654151f,-0.95501995f}, {0.28401533f,-0.95881975f},
+{0.27144039f,-0.96245527f}, {0.25881907f,-0.96592581f}, {0.24615327f,-0.96923089f},
+{0.23344530f,-0.97236991f}, {0.22069745f,-0.97534233f}, {0.20791166f,-0.97814763f},
+{0.19509023f,-0.98078531f}, {0.18223552f,-0.98325491f}, {0.16934945f,-0.98555607f},
+{0.15643437f,-0.98768836f}, {0.14349259f,-0.98965138f}, {0.13052613f,-0.99144489f},
+{0.11753740f,-0.99306846f}, {0.10452842f,-0.99452192f}, {0.091501534f,-0.99580491f},
+{0.078459084f,-0.99691731f}, {0.065403074f,-0.99785894f}, {0.052335974f,-0.99862951f},
+{0.039259788f,-0.99922901f}, {0.026176875f,-0.99965733f}, {0.013089597f,-0.99991435f},
+{1.0000000f,-0.0000000f}, {0.99965733f,-0.026176950f}, {0.99862951f,-0.052335959f},
+{0.99691731f,-0.078459099f}, {0.99452192f,-0.10452846f}, {0.99144489f,-0.13052620f},
+{0.98768836f,-0.15643448f}, {0.98325491f,-0.18223552f}, {0.97814763f,-0.20791170f},
+{0.97236991f,-0.23344538f}, {0.96592581f,-0.25881904f}, {0.95881975f,-0.28401536f},
+{0.95105648f,-0.30901700f}, {0.94264150f,-0.33380687f}, {0.93358040f,-0.35836795f},
+{0.92387956f,-0.38268346f}, {0.91354543f,-0.40673664f}, {0.90258527f,-0.43051112f},
+{0.89100653f,-0.45399052f}, {0.87881708f,-0.47715878f}, {0.86602545f,-0.50000000f},
+{0.85264015f,-0.52249855f}, {0.83867055f,-0.54463905f}, {0.82412618f,-0.56640625f},
+{0.80901700f,-0.58778524f}, {0.79335332f,-0.60876143f}, {0.77714598f,-0.62932038f},
+{0.76040596f,-0.64944810f}, {0.74314475f,-0.66913062f}, {0.72537434f,-0.68835455f},
+{0.70710677f,-0.70710683f}, {0.68835455f,-0.72537440f}, {0.66913056f,-0.74314487f},
+{0.64944804f,-0.76040596f}, {0.62932038f,-0.77714598f}, {0.60876137f,-0.79335338f},
+{0.58778524f,-0.80901700f}, {0.56640625f,-0.82412618f}, {0.54463899f,-0.83867055f},
+{0.52249849f,-0.85264015f}, {0.49999997f,-0.86602545f}, {0.47715876f,-0.87881708f},
+{0.45399052f,-0.89100653f}, {0.43051103f,-0.90258533f}, {0.40673661f,-0.91354549f},
+{0.38268343f,-0.92387956f}, {0.35836786f,-0.93358046f}, {0.33380681f,-0.94264150f},
+{0.30901697f,-0.95105654f}, {0.28401533f,-0.95881975f}, {0.25881907f,-0.96592581f},
+{0.23344530f,-0.97236991f}, {0.20791166f,-0.97814763f}, {0.18223552f,-0.98325491f},
+{0.15643437f,-0.98768836f}, {0.13052613f,-0.99144489f}, {0.10452842f,-0.99452192f},
+{0.078459084f,-0.99691731f}, {0.052335974f,-0.99862951f}, {0.026176875f,-0.99965733f},
+{-4.3711388e-08f,-1.0000000f}, {-0.026176963f,-0.99965733f}, {-0.052336060f,-0.99862951f},
+{-0.078459173f,-0.99691731f}, {-0.10452851f,-0.99452192f}, {-0.13052621f,-0.99144489f},
+{-0.15643445f,-0.98768836f}, {-0.18223560f,-0.98325491f}, {-0.20791174f,-0.97814757f},
+{-0.23344538f,-0.97236991f}, {-0.25881916f,-0.96592581f}, {-0.28401542f,-0.95881969f},
+{-0.30901703f,-0.95105648f}, {-0.33380687f,-0.94264150f}, {-0.35836795f,-0.93358040f},
+{-0.38268352f,-0.92387950f}, {-0.40673670f,-0.91354543f}, {-0.43051112f,-0.90258527f},
+{-0.45399061f,-0.89100647f}, {-0.47715873f,-0.87881708f}, {-0.50000006f,-0.86602533f},
+{-0.52249867f,-0.85264009f}, {-0.54463905f,-0.83867055f}, {-0.56640631f,-0.82412612f},
+{-0.58778518f,-0.80901700f}, {-0.60876143f,-0.79335332f}, {-0.62932050f,-0.77714586f},
+{-0.64944804f,-0.76040596f}, {-0.66913068f,-0.74314475f}, {-0.68835467f,-0.72537428f},
+{-0.70710677f,-0.70710677f}, {-0.72537446f,-0.68835449f}, {-0.74314493f,-0.66913044f},
+{-0.76040596f,-0.64944804f}, {-0.77714604f,-0.62932026f}, {-0.79335332f,-0.60876143f},
+{-0.80901700f,-0.58778518f}, {-0.82412624f,-0.56640613f}, {-0.83867055f,-0.54463899f},
+{-0.85264021f,-0.52249849f}, {-0.86602539f,-0.50000006f}, {-0.87881714f,-0.47715873f},
+{-0.89100659f,-0.45399037f}, {-0.90258527f,-0.43051112f}, {-0.91354549f,-0.40673658f},
+{-0.92387956f,-0.38268328f}, {-0.93358040f,-0.35836792f}, {-0.94264150f,-0.33380675f},
+{-0.95105654f,-0.30901679f}, {-0.95881975f,-0.28401530f}, {-0.96592587f,-0.25881892f},
+{-0.97236991f,-0.23344538f}, {-0.97814763f,-0.20791161f}, {-0.98325491f,-0.18223536f},
+{-0.98768836f,-0.15643445f}, {-0.99144489f,-0.13052608f}, {-0.99452192f,-0.10452849f},
+{-0.99691737f,-0.078459039f}, {-0.99862957f,-0.052335810f}, {-0.99965733f,-0.026176952f},
+{1.0000000f,-0.0000000f}, {0.99922901f,-0.039259817f}, {0.99691731f,-0.078459099f},
+{0.99306846f,-0.11753740f}, {0.98768836f,-0.15643448f}, {0.98078525f,-0.19509032f},
+{0.97236991f,-0.23344538f}, {0.96245521f,-0.27144045f}, {0.95105648f,-0.30901700f},
+{0.93819129f,-0.34611708f}, {0.92387956f,-0.38268346f}, {0.90814316f,-0.41865975f},
+{0.89100653f,-0.45399052f}, {0.87249601f,-0.48862126f}, {0.85264015f,-0.52249855f},
+{0.83146960f,-0.55557024f}, {0.80901700f,-0.58778524f}, {0.78531694f,-0.61909395f},
+{0.76040596f,-0.64944810f}, {0.73432249f,-0.67880076f}, {0.70710677f,-0.70710683f},
+{0.67880070f,-0.73432255f}, {0.64944804f,-0.76040596f}, {0.61909395f,-0.78531694f},
+{0.58778524f,-0.80901700f}, {0.55557019f,-0.83146960f}, {0.52249849f,-0.85264015f},
+{0.48862118f,-0.87249601f}, {0.45399052f,-0.89100653f}, {0.41865975f,-0.90814316f},
+{0.38268343f,-0.92387956f}, {0.34611705f,-0.93819135f}, {0.30901697f,-0.95105654f},
+{0.27144039f,-0.96245527f}, {0.23344530f,-0.97236991f}, {0.19509023f,-0.98078531f},
+{0.15643437f,-0.98768836f}, {0.11753740f,-0.99306846f}, {0.078459084f,-0.99691731f},
+{0.039259788f,-0.99922901f}, {-4.3711388e-08f,-1.0000000f}, {-0.039259877f,-0.99922901f},
+{-0.078459173f,-0.99691731f}, {-0.11753749f,-0.99306846f}, {-0.15643445f,-0.98768836f},
+{-0.19509032f,-0.98078525f}, {-0.23344538f,-0.97236991f}, {-0.27144048f,-0.96245521f},
+{-0.30901703f,-0.95105648f}, {-0.34611711f,-0.93819129f}, {-0.38268352f,-0.92387950f},
+{-0.41865984f,-0.90814310f}, {-0.45399061f,-0.89100647f}, {-0.48862135f,-0.87249595f},
+{-0.52249867f,-0.85264009f}, {-0.55557036f,-0.83146954f}, {-0.58778518f,-0.80901700f},
+{-0.61909389f,-0.78531694f}, {-0.64944804f,-0.76040596f}, {-0.67880076f,-0.73432249f},
+{-0.70710677f,-0.70710677f}, {-0.73432249f,-0.67880070f}, {-0.76040596f,-0.64944804f},
+{-0.78531694f,-0.61909389f}, {-0.80901700f,-0.58778518f}, {-0.83146966f,-0.55557019f},
+{-0.85264021f,-0.52249849f}, {-0.87249607f,-0.48862115f}, {-0.89100659f,-0.45399037f},
+{-0.90814322f,-0.41865960f}, {-0.92387956f,-0.38268328f}, {-0.93819135f,-0.34611690f},
+{-0.95105654f,-0.30901679f}, {-0.96245521f,-0.27144048f}, {-0.97236991f,-0.23344538f},
+{-0.98078531f,-0.19509031f}, {-0.98768836f,-0.15643445f}, {-0.99306846f,-0.11753736f},
+{-0.99691737f,-0.078459039f}, {-0.99922901f,-0.039259743f}, {-1.0000000f,8.7422777e-08f},
+{-0.99922901f,0.039259918f}, {-0.99691731f,0.078459218f}, {-0.99306846f,0.11753753f},
+{-0.98768830f,0.15643461f}, {-0.98078525f,0.19509049f}, {-0.97236985f,0.23344554f},
+{-0.96245515f,0.27144065f}, {-0.95105654f,0.30901697f}, {-0.93819135f,0.34611705f},
+{-0.92387956f,0.38268346f}, {-0.90814316f,0.41865975f}, {-0.89100653f,0.45399055f},
+{-0.87249601f,0.48862129f}, {-0.85264015f,0.52249861f}, {-0.83146960f,0.55557030f},
+{-0.80901694f,0.58778536f}, {-0.78531688f,0.61909401f}, {-0.76040590f,0.64944816f},
+{-0.73432243f,0.67880082f}, {-0.70710665f,0.70710689f}, {-0.67880058f,0.73432261f},
+{-0.64944792f,0.76040608f}, {-0.61909378f,0.78531706f}, {-0.58778507f,0.80901712f},
+{-0.55557001f,0.83146977f}, {-0.52249837f,0.85264033f}, {-0.48862100f,0.87249613f},
+{-0.45399022f,0.89100665f}, {-0.41865945f,0.90814328f}, {-0.38268313f,0.92387968f},
+{-0.34611672f,0.93819147f}, {-0.30901709f,0.95105648f}, {-0.27144054f,0.96245521f},
+{-0.23344545f,0.97236991f}, {-0.19509038f,0.98078525f}, {-0.15643452f,0.98768830f},
+{-0.11753743f,0.99306846f}, {-0.078459114f,0.99691731f}, {-0.039259821f,0.99922901f},
+};
+static const ne10_fft_cpx_float32_t ne10_twiddles_240[240] = {
+{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f},
+{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f},
+{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f},
+{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f},
+{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f},
+{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f},
+{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f},
+{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f},
+{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f},
+{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f},
+{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f},
+{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f},
+{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f},
+{1.0000000f,-0.0000000f}, {0.95105648f,-0.30901700f}, {0.80901700f,-0.58778524f},
+{0.58778524f,-0.80901700f}, {0.30901697f,-0.95105654f}, {-4.3711388e-08f,-1.0000000f},
+{-0.30901703f,-0.95105648f}, {-0.58778518f,-0.80901700f}, {-0.80901700f,-0.58778518f},
+{-0.95105654f,-0.30901679f}, {-1.0000000f,8.7422777e-08f}, {-0.95105654f,0.30901697f},
+{-0.80901694f,0.58778536f}, {-0.58778507f,0.80901712f}, {-0.30901709f,0.95105648f},
+{1.0000000f,-0.0000000f}, {0.99965733f,-0.026176950f}, {0.99862951f,-0.052335959f},
+{0.99691731f,-0.078459099f}, {0.99452192f,-0.10452846f}, {0.99144489f,-0.13052620f},
+{0.98768836f,-0.15643448f}, {0.98325491f,-0.18223552f}, {0.97814763f,-0.20791170f},
+{0.97236991f,-0.23344538f}, {0.96592581f,-0.25881904f}, {0.95881975f,-0.28401536f},
+{0.95105648f,-0.30901700f}, {0.94264150f,-0.33380687f}, {0.93358040f,-0.35836795f},
+{0.92387956f,-0.38268346f}, {0.91354543f,-0.40673664f}, {0.90258527f,-0.43051112f},
+{0.89100653f,-0.45399052f}, {0.87881708f,-0.47715878f}, {0.86602545f,-0.50000000f},
+{0.85264015f,-0.52249855f}, {0.83867055f,-0.54463905f}, {0.82412618f,-0.56640625f},
+{0.80901700f,-0.58778524f}, {0.79335332f,-0.60876143f}, {0.77714598f,-0.62932038f},
+{0.76040596f,-0.64944810f}, {0.74314475f,-0.66913062f}, {0.72537434f,-0.68835455f},
+{0.70710677f,-0.70710683f}, {0.68835455f,-0.72537440f}, {0.66913056f,-0.74314487f},
+{0.64944804f,-0.76040596f}, {0.62932038f,-0.77714598f}, {0.60876137f,-0.79335338f},
+{0.58778524f,-0.80901700f}, {0.56640625f,-0.82412618f}, {0.54463899f,-0.83867055f},
+{0.52249849f,-0.85264015f}, {0.49999997f,-0.86602545f}, {0.47715876f,-0.87881708f},
+{0.45399052f,-0.89100653f}, {0.43051103f,-0.90258533f}, {0.40673661f,-0.91354549f},
+{0.38268343f,-0.92387956f}, {0.35836786f,-0.93358046f}, {0.33380681f,-0.94264150f},
+{0.30901697f,-0.95105654f}, {0.28401533f,-0.95881975f}, {0.25881907f,-0.96592581f},
+{0.23344530f,-0.97236991f}, {0.20791166f,-0.97814763f}, {0.18223552f,-0.98325491f},
+{0.15643437f,-0.98768836f}, {0.13052613f,-0.99144489f}, {0.10452842f,-0.99452192f},
+{0.078459084f,-0.99691731f}, {0.052335974f,-0.99862951f}, {0.026176875f,-0.99965733f},
+{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f},
+{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f},
+{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f},
+{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f},
+{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f},
+{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f},
+{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f},
+{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f},
+{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f},
+{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f},
+{-4.3711388e-08f,-1.0000000f}, {-0.052336060f,-0.99862951f}, {-0.10452851f,-0.99452192f},
+{-0.15643445f,-0.98768836f}, {-0.20791174f,-0.97814757f}, {-0.25881916f,-0.96592581f},
+{-0.30901703f,-0.95105648f}, {-0.35836795f,-0.93358040f}, {-0.40673670f,-0.91354543f},
+{-0.45399061f,-0.89100647f}, {-0.50000006f,-0.86602533f}, {-0.54463905f,-0.83867055f},
+{-0.58778518f,-0.80901700f}, {-0.62932050f,-0.77714586f}, {-0.66913068f,-0.74314475f},
+{-0.70710677f,-0.70710677f}, {-0.74314493f,-0.66913044f}, {-0.77714604f,-0.62932026f},
+{-0.80901700f,-0.58778518f}, {-0.83867055f,-0.54463899f}, {-0.86602539f,-0.50000006f},
+{-0.89100659f,-0.45399037f}, {-0.91354549f,-0.40673658f}, {-0.93358040f,-0.35836792f},
+{-0.95105654f,-0.30901679f}, {-0.96592587f,-0.25881892f}, {-0.97814763f,-0.20791161f},
+{-0.98768836f,-0.15643445f}, {-0.99452192f,-0.10452849f}, {-0.99862957f,-0.052335810f},
+{1.0000000f,-0.0000000f}, {0.99691731f,-0.078459099f}, {0.98768836f,-0.15643448f},
+{0.97236991f,-0.23344538f}, {0.95105648f,-0.30901700f}, {0.92387956f,-0.38268346f},
+{0.89100653f,-0.45399052f}, {0.85264015f,-0.52249855f}, {0.80901700f,-0.58778524f},
+{0.76040596f,-0.64944810f}, {0.70710677f,-0.70710683f}, {0.64944804f,-0.76040596f},
+{0.58778524f,-0.80901700f}, {0.52249849f,-0.85264015f}, {0.45399052f,-0.89100653f},
+{0.38268343f,-0.92387956f}, {0.30901697f,-0.95105654f}, {0.23344530f,-0.97236991f},
+{0.15643437f,-0.98768836f}, {0.078459084f,-0.99691731f}, {-4.3711388e-08f,-1.0000000f},
+{-0.078459173f,-0.99691731f}, {-0.15643445f,-0.98768836f}, {-0.23344538f,-0.97236991f},
+{-0.30901703f,-0.95105648f}, {-0.38268352f,-0.92387950f}, {-0.45399061f,-0.89100647f},
+{-0.52249867f,-0.85264009f}, {-0.58778518f,-0.80901700f}, {-0.64944804f,-0.76040596f},
+{-0.70710677f,-0.70710677f}, {-0.76040596f,-0.64944804f}, {-0.80901700f,-0.58778518f},
+{-0.85264021f,-0.52249849f}, {-0.89100659f,-0.45399037f}, {-0.92387956f,-0.38268328f},
+{-0.95105654f,-0.30901679f}, {-0.97236991f,-0.23344538f}, {-0.98768836f,-0.15643445f},
+{-0.99691737f,-0.078459039f}, {-1.0000000f,8.7422777e-08f}, {-0.99691731f,0.078459218f},
+{-0.98768830f,0.15643461f}, {-0.97236985f,0.23344554f}, {-0.95105654f,0.30901697f},
+{-0.92387956f,0.38268346f}, {-0.89100653f,0.45399055f}, {-0.85264015f,0.52249861f},
+{-0.80901694f,0.58778536f}, {-0.76040590f,0.64944816f}, {-0.70710665f,0.70710689f},
+{-0.64944792f,0.76040608f}, {-0.58778507f,0.80901712f}, {-0.52249837f,0.85264033f},
+{-0.45399022f,0.89100665f}, {-0.38268313f,0.92387968f}, {-0.30901709f,0.95105648f},
+{-0.23344545f,0.97236991f}, {-0.15643452f,0.98768830f}, {-0.078459114f,0.99691731f},
+};
+static const ne10_fft_cpx_float32_t ne10_twiddles_120[120] = {
+{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f},
+{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f},
+{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f},
+{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f},
+{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f},
+{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f},
+{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f},
+{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f},
+{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f},
+{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f},
+{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f},
+{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f},
+{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f},
+{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f},
+{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f},
+{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f},
+{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f},
+{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f},
+{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f},
+{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f},
+{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f},
+{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f},
+{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f},
+{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f},
+{-4.3711388e-08f,-1.0000000f}, {-0.10452851f,-0.99452192f}, {-0.20791174f,-0.97814757f},
+{-0.30901703f,-0.95105648f}, {-0.40673670f,-0.91354543f}, {-0.50000006f,-0.86602533f},
+{-0.58778518f,-0.80901700f}, {-0.66913068f,-0.74314475f}, {-0.74314493f,-0.66913044f},
+{-0.80901700f,-0.58778518f}, {-0.86602539f,-0.50000006f}, {-0.91354549f,-0.40673658f},
+{-0.95105654f,-0.30901679f}, {-0.97814763f,-0.20791161f}, {-0.99452192f,-0.10452849f},
+{1.0000000f,-0.0000000f}, {0.98768836f,-0.15643448f}, {0.95105648f,-0.30901700f},
+{0.89100653f,-0.45399052f}, {0.80901700f,-0.58778524f}, {0.70710677f,-0.70710683f},
+{0.58778524f,-0.80901700f}, {0.45399052f,-0.89100653f}, {0.30901697f,-0.95105654f},
+{0.15643437f,-0.98768836f}, {-4.3711388e-08f,-1.0000000f}, {-0.15643445f,-0.98768836f},
+{-0.30901703f,-0.95105648f}, {-0.45399061f,-0.89100647f}, {-0.58778518f,-0.80901700f},
+{-0.70710677f,-0.70710677f}, {-0.80901700f,-0.58778518f}, {-0.89100659f,-0.45399037f},
+{-0.95105654f,-0.30901679f}, {-0.98768836f,-0.15643445f}, {-1.0000000f,8.7422777e-08f},
+{-0.98768830f,0.15643461f}, {-0.95105654f,0.30901697f}, {-0.89100653f,0.45399055f},
+{-0.80901694f,0.58778536f}, {-0.70710665f,0.70710689f}, {-0.58778507f,0.80901712f},
+{-0.45399022f,0.89100665f}, {-0.30901709f,0.95105648f}, {-0.15643452f,0.98768830f},
+};
+static const ne10_fft_cpx_float32_t ne10_twiddles_60[60] = {
+{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f},
+{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f},
+{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f},
+{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f},
+{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f},
+{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f},
+{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f},
+{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f},
+{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f},
+{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f},
+{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f},
+{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f},
+{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f},
+{1.0000000f,-0.0000000f}, {0.95105648f,-0.30901700f}, {0.80901700f,-0.58778524f},
+{0.58778524f,-0.80901700f}, {0.30901697f,-0.95105654f}, {-4.3711388e-08f,-1.0000000f},
+{-0.30901703f,-0.95105648f}, {-0.58778518f,-0.80901700f}, {-0.80901700f,-0.58778518f},
+{-0.95105654f,-0.30901679f}, {-1.0000000f,8.7422777e-08f}, {-0.95105654f,0.30901697f},
+{-0.80901694f,0.58778536f}, {-0.58778507f,0.80901712f}, {-0.30901709f,0.95105648f},
+};
+static const ne10_fft_state_float32_t ne10_fft_state_float32_t_480 = {
+120,
+(ne10_int32_t *)ne10_factors_480,
+(ne10_fft_cpx_float32_t *)ne10_twiddles_480,
+NULL,
+(ne10_fft_cpx_float32_t *)&ne10_twiddles_480[120],
+/* is_forward_scaled = true */
+(ne10_int32_t) 1,
+/* is_backward_scaled = false */
+(ne10_int32_t) 0,
+};
+static const arch_fft_state cfg_arch_480 = {
+1,
+(void *)&ne10_fft_state_float32_t_480,
+};
+
+static const ne10_fft_state_float32_t ne10_fft_state_float32_t_240 = {
+60,
+(ne10_int32_t *)ne10_factors_240,
+(ne10_fft_cpx_float32_t *)ne10_twiddles_240,
+NULL,
+(ne10_fft_cpx_float32_t *)&ne10_twiddles_240[60],
+/* is_forward_scaled = true */
+(ne10_int32_t) 1,
+/* is_backward_scaled = false */
+(ne10_int32_t) 0,
+};
+static const arch_fft_state cfg_arch_240 = {
+1,
+(void *)&ne10_fft_state_float32_t_240,
+};
+
+static const ne10_fft_state_float32_t ne10_fft_state_float32_t_120 = {
+30,
+(ne10_int32_t *)ne10_factors_120,
+(ne10_fft_cpx_float32_t *)ne10_twiddles_120,
+NULL,
+(ne10_fft_cpx_float32_t *)&ne10_twiddles_120[30],
+/* is_forward_scaled = true */
+(ne10_int32_t) 1,
+/* is_backward_scaled = false */
+(ne10_int32_t) 0,
+};
+static const arch_fft_state cfg_arch_120 = {
+1,
+(void *)&ne10_fft_state_float32_t_120,
+};
+
+static const ne10_fft_state_float32_t ne10_fft_state_float32_t_60 = {
+15,
+(ne10_int32_t *)ne10_factors_60,
+(ne10_fft_cpx_float32_t *)ne10_twiddles_60,
+NULL,
+(ne10_fft_cpx_float32_t *)&ne10_twiddles_60[15],
+/* is_forward_scaled = true */
+(ne10_int32_t) 1,
+/* is_backward_scaled = false */
+(ne10_int32_t) 0,
+};
+static const arch_fft_state cfg_arch_60 = {
+1,
+(void *)&ne10_fft_state_float32_t_60,
+};
+
+#endif /* end NE10_FFT_PARAMS48000_960 */
diff --git a/external/opus-1.1.4/celt/vq.c b/external/opus-1.1.4/celt/vq.c
new file mode 100644
index 0000000..d29f38f
--- /dev/null
+++ b/external/opus-1.1.4/celt/vq.c
@@ -0,0 +1,408 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mathops.h"
+#include "cwrs.h"
+#include "vq.h"
+#include "arch.h"
+#include "os_support.h"
+#include "bands.h"
+#include "rate.h"
+#include "pitch.h"
+
+#ifndef OVERRIDE_vq_exp_rotation1
+static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s)
+{
+ int i;
+ opus_val16 ms;
+ celt_norm *Xptr;
+ Xptr = X;
+ ms = NEG16(s);
+ for (i=0;i<len-stride;i++)
+ {
+ celt_norm x1, x2;
+ x1 = Xptr[0];
+ x2 = Xptr[stride];
+ Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15));
+ *Xptr++ = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15));
+ }
+ Xptr = &X[len-2*stride-1];
+ for (i=len-2*stride-1;i>=0;i--)
+ {
+ celt_norm x1, x2;
+ x1 = Xptr[0];
+ x2 = Xptr[stride];
+ Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15));
+ *Xptr-- = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15));
+ }
+}
+#endif /* OVERRIDE_vq_exp_rotation1 */
+
+static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread)
+{
+ static const int SPREAD_FACTOR[3]={15,10,5};
+ int i;
+ opus_val16 c, s;
+ opus_val16 gain, theta;
+ int stride2=0;
+ int factor;
+
+ if (2*K>=len || spread==SPREAD_NONE)
+ return;
+ factor = SPREAD_FACTOR[spread-1];
+
+ gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K));
+ theta = HALF16(MULT16_16_Q15(gain,gain));
+
+ c = celt_cos_norm(EXTEND32(theta));
+ s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */
+
+ if (len>=8*stride)
+ {
+ stride2 = 1;
+ /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding.
+ It's basically incrementing long as (stride2+0.5)^2 < len/stride. */
+ while ((stride2*stride2+stride2)*stride + (stride>>2) < len)
+ stride2++;
+ }
+ /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
+ extract_collapse_mask().*/
+ len = celt_udiv(len, stride);
+ for (i=0;i<stride;i++)
+ {
+ if (dir < 0)
+ {
+ if (stride2)
+ exp_rotation1(X+i*len, len, stride2, s, c);
+ exp_rotation1(X+i*len, len, 1, c, s);
+ } else {
+ exp_rotation1(X+i*len, len, 1, c, -s);
+ if (stride2)
+ exp_rotation1(X+i*len, len, stride2, s, -c);
+ }
+ }
+}
+
+/** Takes the pitch vector and the decoded residual vector, computes the gain
+ that will give ||p+g*y||=1 and mixes the residual with the pitch. */
+static void normalise_residual(int * OPUS_RESTRICT iy, celt_norm * OPUS_RESTRICT X,
+ int N, opus_val32 Ryy, opus_val16 gain)
+{
+ int i;
+#ifdef FIXED_POINT
+ int k;
+#endif
+ opus_val32 t;
+ opus_val16 g;
+
+#ifdef FIXED_POINT
+ k = celt_ilog2(Ryy)>>1;
+#endif
+ t = VSHR32(Ryy, 2*(k-7));
+ g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
+
+ i=0;
+ do
+ X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1));
+ while (++i < N);
+}
+
+static unsigned extract_collapse_mask(int *iy, int N, int B)
+{
+ unsigned collapse_mask;
+ int N0;
+ int i;
+ if (B<=1)
+ return 1;
+ /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
+ exp_rotation().*/
+ N0 = celt_udiv(N, B);
+ collapse_mask = 0;
+ i=0; do {
+ int j;
+ unsigned tmp=0;
+ j=0; do {
+ tmp |= iy[i*N0+j];
+ } while (++j<N0);
+ collapse_mask |= (tmp!=0)<<i;
+ } while (++i<B);
+ return collapse_mask;
+}
+
+unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc
+#ifdef RESYNTH
+ , opus_val16 gain
+#endif
+ )
+{
+ VARDECL(celt_norm, y);
+ VARDECL(int, iy);
+ VARDECL(opus_val16, signx);
+ int i, j;
+ opus_val16 s;
+ int pulsesLeft;
+ opus_val32 sum;
+ opus_val32 xy;
+ opus_val16 yy;
+ unsigned collapse_mask;
+ SAVE_STACK;
+
+ celt_assert2(K>0, "alg_quant() needs at least one pulse");
+ celt_assert2(N>1, "alg_quant() needs at least two dimensions");
+
+ ALLOC(y, N, celt_norm);
+ ALLOC(iy, N, int);
+ ALLOC(signx, N, opus_val16);
+
+ exp_rotation(X, N, 1, B, K, spread);
+
+ /* Get rid of the sign */
+ sum = 0;
+ j=0; do {
+ if (X[j]>0)
+ signx[j]=1;
+ else {
+ signx[j]=-1;
+ X[j]=-X[j];
+ }
+ iy[j] = 0;
+ y[j] = 0;
+ } while (++j<N);
+
+ xy = yy = 0;
+
+ pulsesLeft = K;
+
+ /* Do a pre-search by projecting on the pyramid */
+ if (K > (N>>1))
+ {
+ opus_val16 rcp;
+ j=0; do {
+ sum += X[j];
+ } while (++j<N);
+
+ /* If X is too small, just replace it with a pulse at 0 */
+#ifdef FIXED_POINT
+ if (sum <= K)
+#else
+ /* Prevents infinities and NaNs from causing too many pulses
+ to be allocated. 64 is an approximation of infinity here. */
+ if (!(sum > EPSILON && sum < 64))
+#endif
+ {
+ X[0] = QCONST16(1.f,14);
+ j=1; do
+ X[j]=0;
+ while (++j<N);
+ sum = QCONST16(1.f,14);
+ }
+ rcp = EXTRACT16(MULT16_32_Q16(K-1, celt_rcp(sum)));
+ j=0; do {
+#ifdef FIXED_POINT
+ /* It's really important to round *towards zero* here */
+ iy[j] = MULT16_16_Q15(X[j],rcp);
+#else
+ iy[j] = (int)floor(rcp*X[j]);
+#endif
+ y[j] = (celt_norm)iy[j];
+ yy = MAC16_16(yy, y[j],y[j]);
+ xy = MAC16_16(xy, X[j],y[j]);
+ y[j] *= 2;
+ pulsesLeft -= iy[j];
+ } while (++j<N);
+ }
+ celt_assert2(pulsesLeft>=1, "Allocated too many pulses in the quick pass");
+
+ /* This should never happen, but just in case it does (e.g. on silence)
+ we fill the first bin with pulses. */
+#ifdef FIXED_POINT_DEBUG
+ celt_assert2(pulsesLeft<=N+3, "Not enough pulses in the quick pass");
+#endif
+ if (pulsesLeft > N+3)
+ {
+ opus_val16 tmp = (opus_val16)pulsesLeft;
+ yy = MAC16_16(yy, tmp, tmp);
+ yy = MAC16_16(yy, tmp, y[0]);
+ iy[0] += pulsesLeft;
+ pulsesLeft=0;
+ }
+
+ s = 1;
+ for (i=0;i<pulsesLeft;i++)
+ {
+ int best_id;
+ opus_val32 best_num = -VERY_LARGE16;
+ opus_val16 best_den = 0;
+#ifdef FIXED_POINT
+ int rshift;
+#endif
+#ifdef FIXED_POINT
+ rshift = 1+celt_ilog2(K-pulsesLeft+i+1);
+#endif
+ best_id = 0;
+ /* The squared magnitude term gets added anyway, so we might as well
+ add it outside the loop */
+ yy = ADD16(yy, 1);
+ j=0;
+ do {
+ opus_val16 Rxy, Ryy;
+ /* Temporary sums of the new pulse(s) */
+ Rxy = EXTRACT16(SHR32(ADD32(xy, EXTEND32(X[j])),rshift));
+ /* We're multiplying y[j] by two so we don't have to do it here */
+ Ryy = ADD16(yy, y[j]);
+
+ /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
+ Rxy is positive because the sign is pre-computed) */
+ Rxy = MULT16_16_Q15(Rxy,Rxy);
+ /* The idea is to check for num/den >= best_num/best_den, but that way
+ we can do it without any division */
+ /* OPT: Make sure to use conditional moves here */
+ if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))
+ {
+ best_den = Ryy;
+ best_num = Rxy;
+ best_id = j;
+ }
+ } while (++j<N);
+
+ /* Updating the sums of the new pulse(s) */
+ xy = ADD32(xy, EXTEND32(X[best_id]));
+ /* We're multiplying y[j] by two so we don't have to do it here */
+ yy = ADD16(yy, y[best_id]);
+
+ /* Only now that we've made the final choice, update y/iy */
+ /* Multiplying y[j] by 2 so we don't have to do it everywhere else */
+ y[best_id] += 2*s;
+ iy[best_id]++;
+ }
+
+ /* Put the original sign back */
+ j=0;
+ do {
+ X[j] = MULT16_16(signx[j],X[j]);
+ if (signx[j] < 0)
+ iy[j] = -iy[j];
+ } while (++j<N);
+ encode_pulses(iy, N, K, enc);
+
+#ifdef RESYNTH
+ normalise_residual(iy, X, N, yy, gain);
+ exp_rotation(X, N, -1, B, K, spread);
+#endif
+
+ collapse_mask = extract_collapse_mask(iy, N, B);
+ RESTORE_STACK;
+ return collapse_mask;
+}
+
+/** Decode pulse vector and combine the result with the pitch vector to produce
+ the final normalised signal in the current band. */
+unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B,
+ ec_dec *dec, opus_val16 gain)
+{
+ opus_val32 Ryy;
+ unsigned collapse_mask;
+ VARDECL(int, iy);
+ SAVE_STACK;
+
+ celt_assert2(K>0, "alg_unquant() needs at least one pulse");
+ celt_assert2(N>1, "alg_unquant() needs at least two dimensions");
+ ALLOC(iy, N, int);
+ Ryy = decode_pulses(iy, N, K, dec);
+ normalise_residual(iy, X, N, Ryy, gain);
+ exp_rotation(X, N, -1, B, K, spread);
+ collapse_mask = extract_collapse_mask(iy, N, B);
+ RESTORE_STACK;
+ return collapse_mask;
+}
+
+#ifndef OVERRIDE_renormalise_vector
+void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch)
+{
+ int i;
+#ifdef FIXED_POINT
+ int k;
+#endif
+ opus_val32 E;
+ opus_val16 g;
+ opus_val32 t;
+ celt_norm *xptr;
+ E = EPSILON + celt_inner_prod(X, X, N, arch);
+#ifdef FIXED_POINT
+ k = celt_ilog2(E)>>1;
+#endif
+ t = VSHR32(E, 2*(k-7));
+ g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
+
+ xptr = X;
+ for (i=0;i<N;i++)
+ {
+ *xptr = EXTRACT16(PSHR32(MULT16_16(g, *xptr), k+1));
+ xptr++;
+ }
+ /*return celt_sqrt(E);*/
+}
+#endif /* OVERRIDE_renormalise_vector */
+
+int stereo_itheta(const celt_norm *X, const celt_norm *Y, int stereo, int N, int arch)
+{
+ int i;
+ int itheta;
+ opus_val16 mid, side;
+ opus_val32 Emid, Eside;
+
+ Emid = Eside = EPSILON;
+ if (stereo)
+ {
+ for (i=0;i<N;i++)
+ {
+ celt_norm m, s;
+ m = ADD16(SHR16(X[i],1),SHR16(Y[i],1));
+ s = SUB16(SHR16(X[i],1),SHR16(Y[i],1));
+ Emid = MAC16_16(Emid, m, m);
+ Eside = MAC16_16(Eside, s, s);
+ }
+ } else {
+ Emid += celt_inner_prod(X, X, N, arch);
+ Eside += celt_inner_prod(Y, Y, N, arch);
+ }
+ mid = celt_sqrt(Emid);
+ side = celt_sqrt(Eside);
+#ifdef FIXED_POINT
+ /* 0.63662 = 2/pi */
+ itheta = MULT16_16_Q15(QCONST16(0.63662f,15),celt_atan2p(side, mid));
+#else
+ itheta = (int)floor(.5f+16384*0.63662f*atan2(side,mid));
+#endif
+
+ return itheta;
+}
diff --git a/external/opus-1.1.4/celt/vq.h b/external/opus-1.1.4/celt/vq.h
new file mode 100644
index 0000000..5cfcbe5
--- /dev/null
+++ b/external/opus-1.1.4/celt/vq.h
@@ -0,0 +1,75 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file vq.h
+ @brief Vector quantisation of the residual
+ */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef VQ_H
+#define VQ_H
+
+#include "entenc.h"
+#include "entdec.h"
+#include "modes.h"
+
+#if defined(MIPSr1_ASM)
+#include "mips/vq_mipsr1.h"
+#endif
+
+
+/** Algebraic pulse-vector quantiser. The signal x is replaced by the sum of
+ * the pitch and a combination of pulses such that its norm is still equal
+ * to 1. This is the function that will typically require the most CPU.
+ * @param X Residual signal to quantise/encode (returns quantised version)
+ * @param N Number of samples to encode
+ * @param K Number of pulses to use
+ * @param enc Entropy encoder state
+ * @ret A mask indicating which blocks in the band received pulses
+*/
+unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B,
+ ec_enc *enc
+#ifdef RESYNTH
+ , opus_val16 gain
+#endif
+ );
+
+/** Algebraic pulse decoder
+ * @param X Decoded normalised spectrum (returned)
+ * @param N Number of samples to decode
+ * @param K Number of pulses to use
+ * @param dec Entropy decoder state
+ * @ret A mask indicating which blocks in the band received pulses
+ */
+unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B,
+ ec_dec *dec, opus_val16 gain);
+
+void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch);
+
+int stereo_itheta(const celt_norm *X, const celt_norm *Y, int stereo, int N, int arch);
+
+#endif /* VQ_H */
diff --git a/external/opus-1.1.4/celt/x86/celt_lpc_sse.c b/external/opus-1.1.4/celt/x86/celt_lpc_sse.c
new file mode 100644
index 0000000..67e5592
--- /dev/null
+++ b/external/opus-1.1.4/celt/x86/celt_lpc_sse.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+#include "celt_lpc.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "pitch.h"
+#include "x86cpu.h"
+
+#if defined(FIXED_POINT)
+
+void celt_fir_sse4_1(const opus_val16 *_x,
+ const opus_val16 *num,
+ opus_val16 *_y,
+ int N,
+ int ord,
+ opus_val16 *mem,
+ int arch)
+{
+ int i,j;
+ VARDECL(opus_val16, rnum);
+ VARDECL(opus_val16, x);
+
+ __m128i vecNoA;
+ opus_int32 noA ;
+ SAVE_STACK;
+
+ ALLOC(rnum, ord, opus_val16);
+ ALLOC(x, N+ord, opus_val16);
+ for(i=0;i<ord;i++)
+ rnum[i] = num[ord-i-1];
+ for(i=0;i<ord;i++)
+ x[i] = mem[ord-i-1];
+
+ for (i=0;i<N-7;i+=8)
+ {
+ x[i+ord ]=_x[i ];
+ x[i+ord+1]=_x[i+1];
+ x[i+ord+2]=_x[i+2];
+ x[i+ord+3]=_x[i+3];
+ x[i+ord+4]=_x[i+4];
+ x[i+ord+5]=_x[i+5];
+ x[i+ord+6]=_x[i+6];
+ x[i+ord+7]=_x[i+7];
+ }
+
+ for (;i<N-3;i+=4)
+ {
+ x[i+ord ]=_x[i ];
+ x[i+ord+1]=_x[i+1];
+ x[i+ord+2]=_x[i+2];
+ x[i+ord+3]=_x[i+3];
+ }
+
+ for (;i<N;i++)
+ x[i+ord]=_x[i];
+
+ for(i=0;i<ord;i++)
+ mem[i] = _x[N-i-1];
+#ifdef SMALL_FOOTPRINT
+ for (i=0;i<N;i++)
+ {
+ opus_val32 sum = SHL32(EXTEND32(_x[i]), SIG_SHIFT);
+ for (j=0;j<ord;j++)
+ {
+ sum = MAC16_16(sum,rnum[j],x[i+j]);
+ }
+ _y[i] = SATURATE16(PSHR32(sum, SIG_SHIFT));
+ }
+#else
+ noA = EXTEND32(1) << SIG_SHIFT >> 1;
+ vecNoA = _mm_set_epi32(noA, noA, noA, noA);
+
+ for (i=0;i<N-3;i+=4)
+ {
+ opus_val32 sums[4] = {0};
+ __m128i vecSum, vecX;
+
+ xcorr_kernel(rnum, x+i, sums, ord, arch);
+
+ vecSum = _mm_loadu_si128((__m128i *)sums);
+ vecSum = _mm_add_epi32(vecSum, vecNoA);
+ vecSum = _mm_srai_epi32(vecSum, SIG_SHIFT);
+ vecX = OP_CVTEPI16_EPI32_M64(_x + i);
+ vecSum = _mm_add_epi32(vecSum, vecX);
+ vecSum = _mm_packs_epi32(vecSum, vecSum);
+ _mm_storel_epi64((__m128i *)(_y + i), vecSum);
+ }
+ for (;i<N;i++)
+ {
+ opus_val32 sum = 0;
+ for (j=0;j<ord;j++)
+ sum = MAC16_16(sum, rnum[j], x[i + j]);
+ _y[i] = SATURATE16(ADD32(EXTEND32(_x[i]), PSHR32(sum, SIG_SHIFT)));
+ }
+
+#endif
+ RESTORE_STACK;
+}
+
+#endif
diff --git a/external/opus-1.1.4/celt/x86/celt_lpc_sse.h b/external/opus-1.1.4/celt/x86/celt_lpc_sse.h
new file mode 100644
index 0000000..c5ec796
--- /dev/null
+++ b/external/opus-1.1.4/celt/x86/celt_lpc_sse.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef CELT_LPC_SSE_H
+#define CELT_LPC_SSE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT)
+#define OVERRIDE_CELT_FIR
+
+void celt_fir_sse4_1(
+ const opus_val16 *x,
+ const opus_val16 *num,
+ opus_val16 *y,
+ int N,
+ int ord,
+ opus_val16 *mem,
+ int arch);
+
+#if defined(OPUS_X86_PRESUME_SSE4_1)
+#define celt_fir(x, num, y, N, ord, mem, arch) \
+ ((void)arch, celt_fir_sse4_1(x, num, y, N, ord, mem, arch))
+
+#else
+
+extern void (*const CELT_FIR_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *num,
+ opus_val16 *y,
+ int N,
+ int ord,
+ opus_val16 *mem,
+ int arch);
+
+# define celt_fir(x, num, y, N, ord, mem, arch) \
+ ((*CELT_FIR_IMPL[(arch) & OPUS_ARCHMASK])(x, num, y, N, ord, mem, arch))
+
+#endif
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/celt/x86/pitch_sse.c b/external/opus-1.1.4/celt/x86/pitch_sse.c
new file mode 100644
index 0000000..20e7312
--- /dev/null
+++ b/external/opus-1.1.4/celt/x86/pitch_sse.c
@@ -0,0 +1,185 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "macros.h"
+#include "celt_lpc.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "pitch.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT)
+
+#include <xmmintrin.h>
+#include "arch.h"
+
+void xcorr_kernel_sse(const opus_val16 *x, const opus_val16 *y, opus_val32 sum[4], int len)
+{
+ int j;
+ __m128 xsum1, xsum2;
+ xsum1 = _mm_loadu_ps(sum);
+ xsum2 = _mm_setzero_ps();
+
+ for (j = 0; j < len-3; j += 4)
+ {
+ __m128 x0 = _mm_loadu_ps(x+j);
+ __m128 yj = _mm_loadu_ps(y+j);
+ __m128 y3 = _mm_loadu_ps(y+j+3);
+
+ xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x00),yj));
+ xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x55),
+ _mm_shuffle_ps(yj,y3,0x49)));
+ xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xaa),
+ _mm_shuffle_ps(yj,y3,0x9e)));
+ xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xff),y3));
+ }
+ if (j < len)
+ {
+ xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
+ if (++j < len)
+ {
+ xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
+ if (++j < len)
+ {
+ xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
+ }
+ }
+ }
+ _mm_storeu_ps(sum,_mm_add_ps(xsum1,xsum2));
+}
+
+
+void dual_inner_prod_sse(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
+ int N, opus_val32 *xy1, opus_val32 *xy2)
+{
+ int i;
+ __m128 xsum1, xsum2;
+ xsum1 = _mm_setzero_ps();
+ xsum2 = _mm_setzero_ps();
+ for (i=0;i<N-3;i+=4)
+ {
+ __m128 xi = _mm_loadu_ps(x+i);
+ __m128 y1i = _mm_loadu_ps(y01+i);
+ __m128 y2i = _mm_loadu_ps(y02+i);
+ xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(xi, y1i));
+ xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(xi, y2i));
+ }
+ /* Horizontal sum */
+ xsum1 = _mm_add_ps(xsum1, _mm_movehl_ps(xsum1, xsum1));
+ xsum1 = _mm_add_ss(xsum1, _mm_shuffle_ps(xsum1, xsum1, 0x55));
+ _mm_store_ss(xy1, xsum1);
+ xsum2 = _mm_add_ps(xsum2, _mm_movehl_ps(xsum2, xsum2));
+ xsum2 = _mm_add_ss(xsum2, _mm_shuffle_ps(xsum2, xsum2, 0x55));
+ _mm_store_ss(xy2, xsum2);
+ for (;i<N;i++)
+ {
+ *xy1 = MAC16_16(*xy1, x[i], y01[i]);
+ *xy2 = MAC16_16(*xy2, x[i], y02[i]);
+ }
+}
+
+opus_val32 celt_inner_prod_sse(const opus_val16 *x, const opus_val16 *y,
+ int N)
+{
+ int i;
+ float xy;
+ __m128 sum;
+ sum = _mm_setzero_ps();
+ /* FIXME: We should probably go 8-way and use 2 sums. */
+ for (i=0;i<N-3;i+=4)
+ {
+ __m128 xi = _mm_loadu_ps(x+i);
+ __m128 yi = _mm_loadu_ps(y+i);
+ sum = _mm_add_ps(sum,_mm_mul_ps(xi, yi));
+ }
+ /* Horizontal sum */
+ sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
+ sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
+ _mm_store_ss(&xy, sum);
+ for (;i<N;i++)
+ {
+ xy = MAC16_16(xy, x[i], y[i]);
+ }
+ return xy;
+}
+
+void comb_filter_const_sse(opus_val32 *y, opus_val32 *x, int T, int N,
+ opus_val16 g10, opus_val16 g11, opus_val16 g12)
+{
+ int i;
+ __m128 x0v;
+ __m128 g10v, g11v, g12v;
+ g10v = _mm_load1_ps(&g10);
+ g11v = _mm_load1_ps(&g11);
+ g12v = _mm_load1_ps(&g12);
+ x0v = _mm_loadu_ps(&x[-T-2]);
+ for (i=0;i<N-3;i+=4)
+ {
+ __m128 yi, yi2, x1v, x2v, x3v, x4v;
+ const opus_val32 *xp = &x[i-T-2];
+ yi = _mm_loadu_ps(x+i);
+ x4v = _mm_loadu_ps(xp+4);
+#if 0
+ /* Slower version with all loads */
+ x1v = _mm_loadu_ps(xp+1);
+ x2v = _mm_loadu_ps(xp+2);
+ x3v = _mm_loadu_ps(xp+3);
+#else
+ x2v = _mm_shuffle_ps(x0v, x4v, 0x4e);
+ x1v = _mm_shuffle_ps(x0v, x2v, 0x99);
+ x3v = _mm_shuffle_ps(x2v, x4v, 0x99);
+#endif
+
+ yi = _mm_add_ps(yi, _mm_mul_ps(g10v,x2v));
+#if 0 /* Set to 1 to make it bit-exact with the non-SSE version */
+ yi = _mm_add_ps(yi, _mm_mul_ps(g11v,_mm_add_ps(x3v,x1v)));
+ yi = _mm_add_ps(yi, _mm_mul_ps(g12v,_mm_add_ps(x4v,x0v)));
+#else
+ /* Use partial sums */
+ yi2 = _mm_add_ps(_mm_mul_ps(g11v,_mm_add_ps(x3v,x1v)),
+ _mm_mul_ps(g12v,_mm_add_ps(x4v,x0v)));
+ yi = _mm_add_ps(yi, yi2);
+#endif
+ x0v=x4v;
+ _mm_storeu_ps(y+i, yi);
+ }
+#ifdef CUSTOM_MODES
+ for (;i<N;i++)
+ {
+ y[i] = x[i]
+ + MULT16_32_Q15(g10,x[i-T])
+ + MULT16_32_Q15(g11,ADD32(x[i-T+1],x[i-T-1]))
+ + MULT16_32_Q15(g12,ADD32(x[i-T+2],x[i-T-2]));
+ }
+#endif
+}
+
+
+#endif
diff --git a/external/opus-1.1.4/celt/x86/pitch_sse.h b/external/opus-1.1.4/celt/x86/pitch_sse.h
new file mode 100644
index 0000000..e5f87ab
--- /dev/null
+++ b/external/opus-1.1.4/celt/x86/pitch_sse.h
@@ -0,0 +1,192 @@
+/* Copyright (c) 2013 Jean-Marc Valin and John Ridges
+ Copyright (c) 2014, Cisco Systems, INC MingXiang WeiZhou MinPeng YanWang*/
+/**
+ @file pitch_sse.h
+ @brief Pitch analysis
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef PITCH_SSE_H
+#define PITCH_SSE_H
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT)
+void xcorr_kernel_sse4_1(
+ const opus_int16 *x,
+ const opus_int16 *y,
+ opus_val32 sum[4],
+ int len);
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT)
+void xcorr_kernel_sse(
+ const opus_val16 *x,
+ const opus_val16 *y,
+ opus_val32 sum[4],
+ int len);
+#endif
+
+#if defined(OPUS_X86_PRESUME_SSE4_1) && defined(FIXED_POINT)
+#define OVERRIDE_XCORR_KERNEL
+#define xcorr_kernel(x, y, sum, len, arch) \
+ ((void)arch, xcorr_kernel_sse4_1(x, y, sum, len))
+
+#elif defined(OPUS_X86_PRESUME_SSE) && !defined(FIXED_POINT)
+#define OVERRIDE_XCORR_KERNEL
+#define xcorr_kernel(x, y, sum, len, arch) \
+ ((void)arch, xcorr_kernel_sse(x, y, sum, len))
+
+#elif (defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT)) || (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT))
+
+extern void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *y,
+ opus_val32 sum[4],
+ int len);
+
+#define OVERRIDE_XCORR_KERNEL
+#define xcorr_kernel(x, y, sum, len, arch) \
+ ((*XCORR_KERNEL_IMPL[(arch) & OPUS_ARCHMASK])(x, y, sum, len))
+
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT)
+opus_val32 celt_inner_prod_sse4_1(
+ const opus_int16 *x,
+ const opus_int16 *y,
+ int N);
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE2) && defined(FIXED_POINT)
+opus_val32 celt_inner_prod_sse2(
+ const opus_int16 *x,
+ const opus_int16 *y,
+ int N);
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(FIXED_POINT)
+opus_val32 celt_inner_prod_sse(
+ const opus_val16 *x,
+ const opus_val16 *y,
+ int N);
+#endif
+
+
+#if defined(OPUS_X86_PRESUME_SSE4_1) && defined(FIXED_POINT)
+#define OVERRIDE_CELT_INNER_PROD
+#define celt_inner_prod(x, y, N, arch) \
+ ((void)arch, celt_inner_prod_sse4_1(x, y, N))
+
+#elif defined(OPUS_X86_PRESUME_SSE2) && defined(FIXED_POINT) && !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#define OVERRIDE_CELT_INNER_PROD
+#define celt_inner_prod(x, y, N, arch) \
+ ((void)arch, celt_inner_prod_sse2(x, y, N))
+
+#elif defined(OPUS_X86_PRESUME_SSE) && !defined(FIXED_POINT)
+#define OVERRIDE_CELT_INNER_PROD
+#define celt_inner_prod(x, y, N, arch) \
+ ((void)arch, celt_inner_prod_sse(x, y, N))
+
+
+#elif ((defined(OPUS_X86_MAY_HAVE_SSE4_1) || defined(OPUS_X86_MAY_HAVE_SSE2)) && defined(FIXED_POINT)) || \
+ (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT))
+
+extern opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *y,
+ int N);
+
+#define OVERRIDE_CELT_INNER_PROD
+#define celt_inner_prod(x, y, N, arch) \
+ ((*CELT_INNER_PROD_IMPL[(arch) & OPUS_ARCHMASK])(x, y, N))
+
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT)
+
+#define OVERRIDE_DUAL_INNER_PROD
+#define OVERRIDE_COMB_FILTER_CONST
+
+#undef dual_inner_prod
+#undef comb_filter_const
+
+void dual_inner_prod_sse(const opus_val16 *x,
+ const opus_val16 *y01,
+ const opus_val16 *y02,
+ int N,
+ opus_val32 *xy1,
+ opus_val32 *xy2);
+
+void comb_filter_const_sse(opus_val32 *y,
+ opus_val32 *x,
+ int T,
+ int N,
+ opus_val16 g10,
+ opus_val16 g11,
+ opus_val16 g12);
+
+
+#if defined(OPUS_X86_PRESUME_SSE)
+# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) \
+ ((void)(arch),dual_inner_prod_sse(x, y01, y02, N, xy1, xy2))
+
+# define comb_filter_const(y, x, T, N, g10, g11, g12, arch) \
+ ((void)(arch),comb_filter_const_sse(y, x, T, N, g10, g11, g12))
+#else
+
+extern void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *y01,
+ const opus_val16 *y02,
+ int N,
+ opus_val32 *xy1,
+ opus_val32 *xy2);
+
+#define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) \
+ ((*DUAL_INNER_PROD_IMPL[(arch) & OPUS_ARCHMASK])(x, y01, y02, N, xy1, xy2))
+
+extern void (*const COMB_FILTER_CONST_IMPL[OPUS_ARCHMASK + 1])(
+ opus_val32 *y,
+ opus_val32 *x,
+ int T,
+ int N,
+ opus_val16 g10,
+ opus_val16 g11,
+ opus_val16 g12);
+
+#define comb_filter_const(y, x, T, N, g10, g11, g12, arch) \
+ ((*COMB_FILTER_CONST_IMPL[(arch) & OPUS_ARCHMASK])(y, x, T, N, g10, g11, g12))
+
+#define NON_STATIC_COMB_FILTER_CONST_C
+
+#endif
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/celt/x86/pitch_sse2.c b/external/opus-1.1.4/celt/x86/pitch_sse2.c
new file mode 100644
index 0000000..a0e7d1b
--- /dev/null
+++ b/external/opus-1.1.4/celt/x86/pitch_sse2.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+
+#include "macros.h"
+#include "celt_lpc.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "pitch.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE2) && defined(FIXED_POINT)
+opus_val32 celt_inner_prod_sse2(const opus_val16 *x, const opus_val16 *y,
+ int N)
+{
+ opus_int i, dataSize16;
+ opus_int32 sum;
+
+ __m128i inVec1_76543210, inVec1_FEDCBA98, acc1;
+ __m128i inVec2_76543210, inVec2_FEDCBA98, acc2;
+
+ sum = 0;
+ dataSize16 = N & ~15;
+
+ acc1 = _mm_setzero_si128();
+ acc2 = _mm_setzero_si128();
+
+ for (i=0;i<dataSize16;i+=16)
+ {
+ inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0]));
+ inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0]));
+
+ inVec1_FEDCBA98 = _mm_loadu_si128((__m128i *)(&x[i + 8]));
+ inVec2_FEDCBA98 = _mm_loadu_si128((__m128i *)(&y[i + 8]));
+
+ inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210);
+ inVec1_FEDCBA98 = _mm_madd_epi16(inVec1_FEDCBA98, inVec2_FEDCBA98);
+
+ acc1 = _mm_add_epi32(acc1, inVec1_76543210);
+ acc2 = _mm_add_epi32(acc2, inVec1_FEDCBA98);
+ }
+
+ acc1 = _mm_add_epi32( acc1, acc2 );
+
+ if (N - i >= 8)
+ {
+ inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0]));
+ inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0]));
+
+ inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210);
+
+ acc1 = _mm_add_epi32(acc1, inVec1_76543210);
+ i += 8;
+ }
+
+ acc1 = _mm_add_epi32(acc1, _mm_unpackhi_epi64( acc1, acc1));
+ acc1 = _mm_add_epi32(acc1, _mm_shufflelo_epi16( acc1, 0x0E));
+ sum += _mm_cvtsi128_si32(acc1);
+
+ for (;i<N;i++) {
+ sum = silk_SMLABB(sum, x[i], y[i]);
+ }
+
+ return sum;
+}
+#endif
diff --git a/external/opus-1.1.4/celt/x86/pitch_sse4_1.c b/external/opus-1.1.4/celt/x86/pitch_sse4_1.c
new file mode 100644
index 0000000..a092c68
--- /dev/null
+++ b/external/opus-1.1.4/celt/x86/pitch_sse4_1.c
@@ -0,0 +1,195 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+
+#include "macros.h"
+#include "celt_lpc.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "pitch.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT)
+#include <smmintrin.h>
+#include "x86cpu.h"
+
+opus_val32 celt_inner_prod_sse4_1(const opus_val16 *x, const opus_val16 *y,
+ int N)
+{
+ opus_int i, dataSize16;
+ opus_int32 sum;
+ __m128i inVec1_76543210, inVec1_FEDCBA98, acc1;
+ __m128i inVec2_76543210, inVec2_FEDCBA98, acc2;
+ __m128i inVec1_3210, inVec2_3210;
+
+ sum = 0;
+ dataSize16 = N & ~15;
+
+ acc1 = _mm_setzero_si128();
+ acc2 = _mm_setzero_si128();
+
+ for (i=0;i<dataSize16;i+=16) {
+ inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0]));
+ inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0]));
+
+ inVec1_FEDCBA98 = _mm_loadu_si128((__m128i *)(&x[i + 8]));
+ inVec2_FEDCBA98 = _mm_loadu_si128((__m128i *)(&y[i + 8]));
+
+ inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210);
+ inVec1_FEDCBA98 = _mm_madd_epi16(inVec1_FEDCBA98, inVec2_FEDCBA98);
+
+ acc1 = _mm_add_epi32(acc1, inVec1_76543210);
+ acc2 = _mm_add_epi32(acc2, inVec1_FEDCBA98);
+ }
+
+ acc1 = _mm_add_epi32(acc1, acc2);
+
+ if (N - i >= 8)
+ {
+ inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0]));
+ inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0]));
+
+ inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210);
+
+ acc1 = _mm_add_epi32(acc1, inVec1_76543210);
+ i += 8;
+ }
+
+ if (N - i >= 4)
+ {
+ inVec1_3210 = OP_CVTEPI16_EPI32_M64(&x[i + 0]);
+ inVec2_3210 = OP_CVTEPI16_EPI32_M64(&y[i + 0]);
+
+ inVec1_3210 = _mm_mullo_epi32(inVec1_3210, inVec2_3210);
+
+ acc1 = _mm_add_epi32(acc1, inVec1_3210);
+ i += 4;
+ }
+
+ acc1 = _mm_add_epi32(acc1, _mm_unpackhi_epi64(acc1, acc1));
+ acc1 = _mm_add_epi32(acc1, _mm_shufflelo_epi16(acc1, 0x0E));
+
+ sum += _mm_cvtsi128_si32(acc1);
+
+ for (;i<N;i++)
+ {
+ sum = silk_SMLABB(sum, x[i], y[i]);
+ }
+
+ return sum;
+}
+
+void xcorr_kernel_sse4_1(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[ 4 ], int len)
+{
+ int j;
+
+ __m128i vecX, vecX0, vecX1, vecX2, vecX3;
+ __m128i vecY0, vecY1, vecY2, vecY3;
+ __m128i sum0, sum1, sum2, sum3, vecSum;
+ __m128i initSum;
+
+ celt_assert(len >= 3);
+
+ sum0 = _mm_setzero_si128();
+ sum1 = _mm_setzero_si128();
+ sum2 = _mm_setzero_si128();
+ sum3 = _mm_setzero_si128();
+
+ for (j=0;j<(len-7);j+=8)
+ {
+ vecX = _mm_loadu_si128((__m128i *)(&x[j + 0]));
+ vecY0 = _mm_loadu_si128((__m128i *)(&y[j + 0]));
+ vecY1 = _mm_loadu_si128((__m128i *)(&y[j + 1]));
+ vecY2 = _mm_loadu_si128((__m128i *)(&y[j + 2]));
+ vecY3 = _mm_loadu_si128((__m128i *)(&y[j + 3]));
+
+ sum0 = _mm_add_epi32(sum0, _mm_madd_epi16(vecX, vecY0));
+ sum1 = _mm_add_epi32(sum1, _mm_madd_epi16(vecX, vecY1));
+ sum2 = _mm_add_epi32(sum2, _mm_madd_epi16(vecX, vecY2));
+ sum3 = _mm_add_epi32(sum3, _mm_madd_epi16(vecX, vecY3));
+ }
+
+ sum0 = _mm_add_epi32(sum0, _mm_unpackhi_epi64( sum0, sum0));
+ sum0 = _mm_add_epi32(sum0, _mm_shufflelo_epi16( sum0, 0x0E));
+
+ sum1 = _mm_add_epi32(sum1, _mm_unpackhi_epi64( sum1, sum1));
+ sum1 = _mm_add_epi32(sum1, _mm_shufflelo_epi16( sum1, 0x0E));
+
+ sum2 = _mm_add_epi32(sum2, _mm_unpackhi_epi64( sum2, sum2));
+ sum2 = _mm_add_epi32(sum2, _mm_shufflelo_epi16( sum2, 0x0E));
+
+ sum3 = _mm_add_epi32(sum3, _mm_unpackhi_epi64( sum3, sum3));
+ sum3 = _mm_add_epi32(sum3, _mm_shufflelo_epi16( sum3, 0x0E));
+
+ vecSum = _mm_unpacklo_epi64(_mm_unpacklo_epi32(sum0, sum1),
+ _mm_unpacklo_epi32(sum2, sum3));
+
+ for (;j<(len-3);j+=4)
+ {
+ vecX = OP_CVTEPI16_EPI32_M64(&x[j + 0]);
+ vecX0 = _mm_shuffle_epi32(vecX, 0x00);
+ vecX1 = _mm_shuffle_epi32(vecX, 0x55);
+ vecX2 = _mm_shuffle_epi32(vecX, 0xaa);
+ vecX3 = _mm_shuffle_epi32(vecX, 0xff);
+
+ vecY0 = OP_CVTEPI16_EPI32_M64(&y[j + 0]);
+ vecY1 = OP_CVTEPI16_EPI32_M64(&y[j + 1]);
+ vecY2 = OP_CVTEPI16_EPI32_M64(&y[j + 2]);
+ vecY3 = OP_CVTEPI16_EPI32_M64(&y[j + 3]);
+
+ sum0 = _mm_mullo_epi32(vecX0, vecY0);
+ sum1 = _mm_mullo_epi32(vecX1, vecY1);
+ sum2 = _mm_mullo_epi32(vecX2, vecY2);
+ sum3 = _mm_mullo_epi32(vecX3, vecY3);
+
+ sum0 = _mm_add_epi32(sum0, sum1);
+ sum2 = _mm_add_epi32(sum2, sum3);
+ vecSum = _mm_add_epi32(vecSum, sum0);
+ vecSum = _mm_add_epi32(vecSum, sum2);
+ }
+
+ for (;j<len;j++)
+ {
+ vecX = OP_CVTEPI16_EPI32_M64(&x[j + 0]);
+ vecX0 = _mm_shuffle_epi32(vecX, 0x00);
+
+ vecY0 = OP_CVTEPI16_EPI32_M64(&y[j + 0]);
+
+ sum0 = _mm_mullo_epi32(vecX0, vecY0);
+ vecSum = _mm_add_epi32(vecSum, sum0);
+ }
+
+ initSum = _mm_loadu_si128((__m128i *)(&sum[0]));
+ initSum = _mm_add_epi32(initSum, vecSum);
+ _mm_storeu_si128((__m128i *)sum, initSum);
+}
+#endif
diff --git a/external/opus-1.1.4/celt/x86/x86_celt_map.c b/external/opus-1.1.4/celt/x86/x86_celt_map.c
new file mode 100644
index 0000000..47ba41b
--- /dev/null
+++ b/external/opus-1.1.4/celt/x86/x86_celt_map.c
@@ -0,0 +1,155 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include "x86/x86cpu.h"
+#include "celt_lpc.h"
+#include "pitch.h"
+#include "pitch_sse.h"
+
+#if defined(OPUS_HAVE_RTCD)
+
+# if defined(FIXED_POINT)
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)
+
+void (*const CELT_FIR_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *num,
+ opus_val16 *y,
+ int N,
+ int ord,
+ opus_val16 *mem,
+ int arch
+) = {
+ celt_fir_c, /* non-sse */
+ celt_fir_c,
+ celt_fir_c,
+ MAY_HAVE_SSE4_1(celt_fir), /* sse4.1 */
+ MAY_HAVE_SSE4_1(celt_fir) /* avx */
+};
+
+void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *y,
+ opus_val32 sum[4],
+ int len
+) = {
+ xcorr_kernel_c, /* non-sse */
+ xcorr_kernel_c,
+ xcorr_kernel_c,
+ MAY_HAVE_SSE4_1(xcorr_kernel), /* sse4.1 */
+ MAY_HAVE_SSE4_1(xcorr_kernel) /* avx */
+};
+
+#endif
+
+#if (defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)) || \
+ (!defined(OPUS_X86_MAY_HAVE_SSE_4_1) && defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2))
+
+opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *y,
+ int N
+) = {
+ celt_inner_prod_c, /* non-sse */
+ celt_inner_prod_c,
+ MAY_HAVE_SSE2(celt_inner_prod),
+ MAY_HAVE_SSE4_1(celt_inner_prod), /* sse4.1 */
+ MAY_HAVE_SSE4_1(celt_inner_prod) /* avx */
+};
+
+#endif
+
+# else
+
+#if defined(OPUS_X86_MAY_HAVE_SSE) && !defined(OPUS_X86_PRESUME_SSE)
+
+void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *y,
+ opus_val32 sum[4],
+ int len
+) = {
+ xcorr_kernel_c, /* non-sse */
+ MAY_HAVE_SSE(xcorr_kernel),
+ MAY_HAVE_SSE(xcorr_kernel),
+ MAY_HAVE_SSE(xcorr_kernel),
+ MAY_HAVE_SSE(xcorr_kernel)
+};
+
+opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *y,
+ int N
+) = {
+ celt_inner_prod_c, /* non-sse */
+ MAY_HAVE_SSE(celt_inner_prod),
+ MAY_HAVE_SSE(celt_inner_prod),
+ MAY_HAVE_SSE(celt_inner_prod),
+ MAY_HAVE_SSE(celt_inner_prod)
+};
+
+void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_val16 *x,
+ const opus_val16 *y01,
+ const opus_val16 *y02,
+ int N,
+ opus_val32 *xy1,
+ opus_val32 *xy2
+) = {
+ dual_inner_prod_c, /* non-sse */
+ MAY_HAVE_SSE(dual_inner_prod),
+ MAY_HAVE_SSE(dual_inner_prod),
+ MAY_HAVE_SSE(dual_inner_prod),
+ MAY_HAVE_SSE(dual_inner_prod)
+};
+
+void (*const COMB_FILTER_CONST_IMPL[OPUS_ARCHMASK + 1])(
+ opus_val32 *y,
+ opus_val32 *x,
+ int T,
+ int N,
+ opus_val16 g10,
+ opus_val16 g11,
+ opus_val16 g12
+) = {
+ comb_filter_const_c, /* non-sse */
+ MAY_HAVE_SSE(comb_filter_const),
+ MAY_HAVE_SSE(comb_filter_const),
+ MAY_HAVE_SSE(comb_filter_const),
+ MAY_HAVE_SSE(comb_filter_const)
+};
+
+
+#endif
+
+#endif
+#endif
diff --git a/external/opus-1.1.4/celt/x86/x86cpu.c b/external/opus-1.1.4/celt/x86/x86cpu.c
new file mode 100644
index 0000000..080eb25
--- /dev/null
+++ b/external/opus-1.1.4/celt/x86/x86cpu.c
@@ -0,0 +1,157 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cpu_support.h"
+#include "macros.h"
+#include "main.h"
+#include "pitch.h"
+#include "x86cpu.h"
+
+#if (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(OPUS_X86_PRESUME_SSE)) || \
+ (defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2)) || \
+ (defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)) || \
+ (defined(OPUS_X86_MAY_HAVE_AVX) && !defined(OPUS_X86_PRESUME_AVX))
+
+
+#if defined(_MSC_VER)
+
+#include <intrin.h>
+static _inline void cpuid(unsigned int CPUInfo[4], unsigned int InfoType)
+{
+ __cpuid((int*)CPUInfo, InfoType);
+}
+
+#else
+
+#if defined(CPU_INFO_BY_C)
+#include <cpuid.h>
+#endif
+
+static void cpuid(unsigned int CPUInfo[4], unsigned int InfoType)
+{
+#if defined(CPU_INFO_BY_ASM)
+#if defined(__i386__) && defined(__PIC__)
+/* %ebx is PIC register in 32-bit, so mustn't clobber it. */
+ __asm__ __volatile__ (
+ "xchg %%ebx, %1\n"
+ "cpuid\n"
+ "xchg %%ebx, %1\n":
+ "=a" (CPUInfo[0]),
+ "=r" (CPUInfo[1]),
+ "=c" (CPUInfo[2]),
+ "=d" (CPUInfo[3]) :
+ "0" (InfoType)
+ );
+#else
+ __asm__ __volatile__ (
+ "cpuid":
+ "=a" (CPUInfo[0]),
+ "=b" (CPUInfo[1]),
+ "=c" (CPUInfo[2]),
+ "=d" (CPUInfo[3]) :
+ "0" (InfoType)
+ );
+#endif
+#elif defined(CPU_INFO_BY_C)
+ __get_cpuid(InfoType, &(CPUInfo[0]), &(CPUInfo[1]), &(CPUInfo[2]), &(CPUInfo[3]));
+#endif
+}
+
+#endif
+
+typedef struct CPU_Feature{
+ /* SIMD: 128-bit */
+ int HW_SSE;
+ int HW_SSE2;
+ int HW_SSE41;
+ /* SIMD: 256-bit */
+ int HW_AVX;
+} CPU_Feature;
+
+static void opus_cpu_feature_check(CPU_Feature *cpu_feature)
+{
+ unsigned int info[4] = {0};
+ unsigned int nIds = 0;
+
+ cpuid(info, 0);
+ nIds = info[0];
+
+ if (nIds >= 1){
+ cpuid(info, 1);
+ cpu_feature->HW_SSE = (info[3] & (1 << 25)) != 0;
+ cpu_feature->HW_SSE2 = (info[3] & (1 << 26)) != 0;
+ cpu_feature->HW_SSE41 = (info[2] & (1 << 19)) != 0;
+ cpu_feature->HW_AVX = (info[2] & (1 << 28)) != 0;
+ }
+ else {
+ cpu_feature->HW_SSE = 0;
+ cpu_feature->HW_SSE2 = 0;
+ cpu_feature->HW_SSE41 = 0;
+ cpu_feature->HW_AVX = 0;
+ }
+}
+
+int opus_select_arch(void)
+{
+ CPU_Feature cpu_feature;
+ int arch;
+
+ opus_cpu_feature_check(&cpu_feature);
+
+ arch = 0;
+ if (!cpu_feature.HW_SSE)
+ {
+ return arch;
+ }
+ arch++;
+
+ if (!cpu_feature.HW_SSE2)
+ {
+ return arch;
+ }
+ arch++;
+
+ if (!cpu_feature.HW_SSE41)
+ {
+ return arch;
+ }
+ arch++;
+
+ if (!cpu_feature.HW_AVX)
+ {
+ return arch;
+ }
+ arch++;
+
+ return arch;
+}
+
+#endif
diff --git a/external/opus-1.1.4/celt/x86/x86cpu.h b/external/opus-1.1.4/celt/x86/x86cpu.h
new file mode 100644
index 0000000..04fd48a
--- /dev/null
+++ b/external/opus-1.1.4/celt/x86/x86cpu.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#if !defined(X86CPU_H)
+# define X86CPU_H
+
+# if defined(OPUS_X86_MAY_HAVE_SSE)
+# define MAY_HAVE_SSE(name) name ## _sse
+# else
+# define MAY_HAVE_SSE(name) name ## _c
+# endif
+
+# if defined(OPUS_X86_MAY_HAVE_SSE2)
+# define MAY_HAVE_SSE2(name) name ## _sse2
+# else
+# define MAY_HAVE_SSE2(name) name ## _c
+# endif
+
+# if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+# define MAY_HAVE_SSE4_1(name) name ## _sse4_1
+# else
+# define MAY_HAVE_SSE4_1(name) name ## _c
+# endif
+
+# if defined(OPUS_X86_MAY_HAVE_AVX)
+# define MAY_HAVE_AVX(name) name ## _avx
+# else
+# define MAY_HAVE_AVX(name) name ## _c
+# endif
+
+# if defined(OPUS_HAVE_RTCD)
+int opus_select_arch(void);
+# endif
+
+/*gcc appears to emit MOVDQA's to load the argument of an _mm_cvtepi8_epi32()
+ or _mm_cvtepi16_epi32() when optimizations are disabled, even though the
+ actual PMOVSXWD instruction takes an m32 or m64. Unlike a normal memory
+ reference, these require 16-byte alignment and load a full 16 bytes (instead
+ of 4 or 8), possibly reading out of bounds.
+
+ We can insert an explicit MOVD or MOVQ using _mm_cvtsi32_si128() or
+ _mm_loadl_epi64(), which should have the same semantics as an m32 or m64
+ reference in the PMOVSXWD instruction itself, but gcc is not smart enough to
+ optimize this out when optimizations ARE enabled.
+
+ Clang, in contrast, requires us to do this always for _mm_cvtepi8_epi32
+ (which is fair, since technically the compiler is always allowed to do the
+ dereference before invoking the function implementing the intrinsic).
+ However, it is smart enough to eliminate the extra MOVD instruction.
+ For _mm_cvtepi16_epi32, it does the right thing, though does *not* optimize out
+ the extra MOVQ if it's specified explicitly */
+
+# if defined(__clang__) || !defined(__OPTIMIZE__)
+# define OP_CVTEPI8_EPI32_M32(x) \
+ (_mm_cvtepi8_epi32(_mm_cvtsi32_si128(*(int *)(x))))
+# else
+# define OP_CVTEPI8_EPI32_M32(x) \
+ (_mm_cvtepi8_epi32(*(__m128i *)(x)))
+#endif
+
+# if !defined(__OPTIMIZE__)
+# define OP_CVTEPI16_EPI32_M64(x) \
+ (_mm_cvtepi16_epi32(_mm_loadl_epi64((__m128i *)(x))))
+# else
+# define OP_CVTEPI16_EPI32_M64(x) \
+ (_mm_cvtepi16_epi32(*(__m128i *)(x)))
+# endif
+
+#endif
diff --git a/external/opus-1.1.4/include/CMakeLists.txt b/external/opus-1.1.4/include/CMakeLists.txt
new file mode 100644
index 0000000..b09f477
--- /dev/null
+++ b/external/opus-1.1.4/include/CMakeLists.txt
@@ -0,0 +1,2 @@
+set( include_INCLUDE_DIR opus-1.1.4/include )
+
diff --git a/external/opus-1.1.4/include/opus.h b/external/opus-1.1.4/include/opus.h
new file mode 100644
index 0000000..5be73dd
--- /dev/null
+++ b/external/opus-1.1.4/include/opus.h
@@ -0,0 +1,981 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+/**
+ * @file opus.h
+ * @brief Opus reference implementation API
+ */
+
+#ifndef OPUS_H
+#define OPUS_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @mainpage Opus
+ *
+ * The Opus codec is designed for interactive speech and audio transmission over the Internet.
+ * It is designed by the IETF Codec Working Group and incorporates technology from
+ * Skype's SILK codec and Xiph.Org's CELT codec.
+ *
+ * The Opus codec is designed to handle a wide range of interactive audio applications,
+ * including Voice over IP, videoconferencing, in-game chat, and even remote live music
+ * performances. It can scale from low bit-rate narrowband speech to very high quality
+ * stereo music. Its main features are:
+
+ * @li Sampling rates from 8 to 48 kHz
+ * @li Bit-rates from 6 kb/s to 510 kb/s
+ * @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR)
+ * @li Audio bandwidth from narrowband to full-band
+ * @li Support for speech and music
+ * @li Support for mono and stereo
+ * @li Support for multichannel (up to 255 channels)
+ * @li Frame sizes from 2.5 ms to 60 ms
+ * @li Good loss robustness and packet loss concealment (PLC)
+ * @li Floating point and fixed-point implementation
+ *
+ * Documentation sections:
+ * @li @ref opus_encoder
+ * @li @ref opus_decoder
+ * @li @ref opus_repacketizer
+ * @li @ref opus_multistream
+ * @li @ref opus_libinfo
+ * @li @ref opus_custom
+ */
+
+/** @defgroup opus_encoder Opus Encoder
+ * @{
+ *
+ * @brief This page describes the process and functions used to encode Opus.
+ *
+ * Since Opus is a stateful codec, the encoding process starts with creating an encoder
+ * state. This can be done with:
+ *
+ * @code
+ * int error;
+ * OpusEncoder *enc;
+ * enc = opus_encoder_create(Fs, channels, application, &error);
+ * @endcode
+ *
+ * From this point, @c enc can be used for encoding an audio stream. An encoder state
+ * @b must @b not be used for more than one stream at the same time. Similarly, the encoder
+ * state @b must @b not be re-initialized for each frame.
+ *
+ * While opus_encoder_create() allocates memory for the state, it's also possible
+ * to initialize pre-allocated memory:
+ *
+ * @code
+ * int size;
+ * int error;
+ * OpusEncoder *enc;
+ * size = opus_encoder_get_size(channels);
+ * enc = malloc(size);
+ * error = opus_encoder_init(enc, Fs, channels, application);
+ * @endcode
+ *
+ * where opus_encoder_get_size() returns the required size for the encoder state. Note that
+ * future versions of this code may change the size, so no assuptions should be made about it.
+ *
+ * The encoder state is always continuous in memory and only a shallow copy is sufficient
+ * to copy it (e.g. memcpy())
+ *
+ * It is possible to change some of the encoder's settings using the opus_encoder_ctl()
+ * interface. All these settings already default to the recommended value, so they should
+ * only be changed when necessary. The most common settings one may want to change are:
+ *
+ * @code
+ * opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));
+ * opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
+ * opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type));
+ * @endcode
+ *
+ * where
+ *
+ * @arg bitrate is in bits per second (b/s)
+ * @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest
+ * @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC
+ *
+ * See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream.
+ *
+ * To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data:
+ * @code
+ * len = opus_encode(enc, audio_frame, frame_size, packet, max_packet);
+ * @endcode
+ *
+ * where
+ * <ul>
+ * <li>audio_frame is the audio data in opus_int16 (or float for opus_encode_float())</li>
+ * <li>frame_size is the duration of the frame in samples (per channel)</li>
+ * <li>packet is the byte array to which the compressed data is written</li>
+ * <li>max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended).
+ * Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.</li>
+ * </ul>
+ *
+ * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet.
+ * The return value <b>can be negative</b>, which indicates that an error has occurred. If the return value
+ * is 2 bytes or less, then the packet does not need to be transmitted (DTX).
+ *
+ * Once the encoder state if no longer needed, it can be destroyed with
+ *
+ * @code
+ * opus_encoder_destroy(enc);
+ * @endcode
+ *
+ * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(),
+ * then no action is required aside from potentially freeing the memory that was manually
+ * allocated for it (calling free(enc) for the example above)
+ *
+ */
+
+/** Opus encoder state.
+ * This contains the complete state of an Opus encoder.
+ * It is position independent and can be freely copied.
+ * @see opus_encoder_create,opus_encoder_init
+ */
+typedef struct OpusEncoder OpusEncoder;
+
+/** Gets the size of an <code>OpusEncoder</code> structure.
+ * @param[in] channels <tt>int</tt>: Number of channels.
+ * This must be 1 or 2.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);
+
+/**
+ */
+
+/** Allocates and initializes an encoder state.
+ * There are three coding modes:
+ *
+ * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice
+ * signals. It enhances the input signal by high-pass filtering and
+ * emphasizing formants and harmonics. Optionally it includes in-band
+ * forward error correction to protect against packet loss. Use this
+ * mode for typical VoIP applications. Because of the enhancement,
+ * even at high bitrates the output may sound different from the input.
+ *
+ * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most
+ * non-voice signals like music. Use this mode for music and mixed
+ * (music/voice) content, broadcast, and applications requiring less
+ * than 15 ms of coding delay.
+ *
+ * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that
+ * disables the speech-optimized mode in exchange for slightly reduced delay.
+ * This mode can only be set on an newly initialized or freshly reset encoder
+ * because it changes the codec delay.
+ *
+ * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution).
+ * @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
+ * @param [in] application <tt>int</tt>: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ * @param [out] error <tt>int*</tt>: @ref opus_errorcodes
+ * @note Regardless of the sampling rate and number channels selected, the Opus encoder
+ * can switch to a lower audio bandwidth or number of channels if the bitrate
+ * selected is too low. This also means that it is safe to always use 48 kHz stereo input
+ * and let the encoder optimize the encoding.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int application,
+ int *error
+);
+
+/** Initializes a previously allocated encoder state
+ * The memory pointed to by st must be at least the size returned by opus_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of malloc.
+ * @see opus_encoder_create(),opus_encoder_get_size()
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @param [in] st <tt>OpusEncoder*</tt>: Encoder state
+ * @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
+ * @param [in] application <tt>int</tt>: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ * @retval #OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_EXPORT int opus_encoder_init(
+ OpusEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int application
+) OPUS_ARG_NONNULL(1);
+
+/** Encodes an Opus frame.
+ * @param [in] st <tt>OpusEncoder*</tt>: Encoder state
+ * @param [in] pcm <tt>opus_int16*</tt>: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16)
+ * @param [in] frame_size <tt>int</tt>: Number of samples per channel in the
+ * input signal.
+ * This must be an Opus frame size for
+ * the encoder's sampling rate.
+ * For example, at 48 kHz the permitted
+ * values are 120, 240, 480, 960, 1920,
+ * and 2880.
+ * Passing in a duration of less than
+ * 10 ms (480 samples at 48 kHz) will
+ * prevent the encoder from using the LPC
+ * or hybrid modes.
+ * @param [out] data <tt>unsigned char*</tt>: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode(
+ OpusEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes an Opus frame from floating point input.
+ * @param [in] st <tt>OpusEncoder*</tt>: Encoder state
+ * @param [in] pcm <tt>float*</tt>: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0.
+ * Samples with a range beyond +/-1.0 are supported but will
+ * be clipped by decoders using the integer API and should
+ * only be used if it is known that the far end supports
+ * extended dynamic range.
+ * length is frame_size*channels*sizeof(float)
+ * @param [in] frame_size <tt>int</tt>: Number of samples per channel in the
+ * input signal.
+ * This must be an Opus frame size for
+ * the encoder's sampling rate.
+ * For example, at 48 kHz the permitted
+ * values are 120, 240, 480, 960, 1920,
+ * and 2880.
+ * Passing in a duration of less than
+ * 10 ms (480 samples at 48 kHz) will
+ * prevent the encoder from using the LPC
+ * or hybrid modes.
+ * @param [out] data <tt>unsigned char*</tt>: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float(
+ OpusEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Frees an <code>OpusEncoder</code> allocated by opus_encoder_create().
+ * @param[in] st <tt>OpusEncoder*</tt>: State to be freed.
+ */
+OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st);
+
+/** Perform a CTL function on an Opus encoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @param st <tt>OpusEncoder*</tt>: Encoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls or
+ * @ref opus_encoderctls.
+ * @see opus_genericctls
+ * @see opus_encoderctls
+ */
+OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+/**@}*/
+
+/** @defgroup opus_decoder Opus Decoder
+ * @{
+ *
+ * @brief This page describes the process and functions used to decode Opus.
+ *
+ * The decoding process also starts with creating a decoder
+ * state. This can be done with:
+ * @code
+ * int error;
+ * OpusDecoder *dec;
+ * dec = opus_decoder_create(Fs, channels, &error);
+ * @endcode
+ * where
+ * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000
+ * @li channels is the number of channels (1 or 2)
+ * @li error will hold the error code in case of failure (or #OPUS_OK on success)
+ * @li the return value is a newly created decoder state to be used for decoding
+ *
+ * While opus_decoder_create() allocates memory for the state, it's also possible
+ * to initialize pre-allocated memory:
+ * @code
+ * int size;
+ * int error;
+ * OpusDecoder *dec;
+ * size = opus_decoder_get_size(channels);
+ * dec = malloc(size);
+ * error = opus_decoder_init(dec, Fs, channels);
+ * @endcode
+ * where opus_decoder_get_size() returns the required size for the decoder state. Note that
+ * future versions of this code may change the size, so no assuptions should be made about it.
+ *
+ * The decoder state is always continuous in memory and only a shallow copy is sufficient
+ * to copy it (e.g. memcpy())
+ *
+ * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data:
+ * @code
+ * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0);
+ * @endcode
+ * where
+ *
+ * @li packet is the byte array containing the compressed data
+ * @li len is the exact number of bytes contained in the packet
+ * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float())
+ * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array
+ *
+ * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet.
+ * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio
+ * buffer is too small to hold the decoded audio.
+ *
+ * Opus is a stateful codec with overlapping blocks and as a result Opus
+ * packets are not coded independently of each other. Packets must be
+ * passed into the decoder serially and in the correct order for a correct
+ * decode. Lost packets can be replaced with loss concealment by calling
+ * the decoder with a null pointer and zero length for the missing packet.
+ *
+ * A single codec state may only be accessed from a single thread at
+ * a time and any required locking must be performed by the caller. Separate
+ * streams must be decoded with separate decoder states and can be decoded
+ * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK
+ * defined.
+ *
+ */
+
+/** Opus decoder state.
+ * This contains the complete state of an Opus decoder.
+ * It is position independent and can be freely copied.
+ * @see opus_decoder_create,opus_decoder_init
+ */
+typedef struct OpusDecoder OpusDecoder;
+
+/** Gets the size of an <code>OpusDecoder</code> structure.
+ * @param [in] channels <tt>int</tt>: Number of channels.
+ * This must be 1 or 2.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels);
+
+/** Allocates and initializes a decoder state.
+ * @param [in] Fs <tt>opus_int32</tt>: Sample rate to decode at (Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode
+ * @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes
+ *
+ * Internally Opus stores data at 48000 Hz, so that should be the default
+ * value for Fs. However, the decoder can efficiently decode to buffers
+ * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use
+ * data at the full sample rate, or knows the compressed data doesn't
+ * use the full frequency range, it can request decoding at a reduced
+ * rate. Likewise, the decoder is capable of filling in either mono or
+ * interleaved stereo pcm buffers, at the caller's request.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create(
+ opus_int32 Fs,
+ int channels,
+ int *error
+);
+
+/** Initializes a previously allocated decoder state.
+ * The state must be at least the size returned by opus_decoder_get_size().
+ * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @param [in] st <tt>OpusDecoder*</tt>: Decoder state.
+ * @param [in] Fs <tt>opus_int32</tt>: Sampling rate to decode to (Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode
+ * @retval #OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_EXPORT int opus_decoder_init(
+ OpusDecoder *st,
+ opus_int32 Fs,
+ int channels
+) OPUS_ARG_NONNULL(1);
+
+/** Decode an Opus packet.
+ * @param [in] st <tt>OpusDecoder*</tt>: Decoder state
+ * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len <tt>opus_int32</tt>: Number of bytes in payload*
+ * @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(opus_int16)
+ * @param [in] frame_size Number of samples per channel of available space in \a pcm.
+ * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
+ * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+ * then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+ * FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
+ * @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
+ * decoded. If no such data is available, the frame is decoded as if it were lost.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode(
+ OpusDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ opus_int16 *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode an Opus packet with floating point output.
+ * @param [in] st <tt>OpusDecoder*</tt>: Decoder state
+ * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len <tt>opus_int32</tt>: Number of bytes in payload
+ * @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(float)
+ * @param [in] frame_size Number of samples per channel of available space in \a pcm.
+ * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
+ * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+ * then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+ * FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
+ * @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
+ * decoded. If no such data is available the frame is decoded as if it were lost.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float(
+ OpusDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ float *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on an Opus decoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @param st <tt>OpusDecoder*</tt>: Decoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls or
+ * @ref opus_decoderctls.
+ * @see opus_genericctls
+ * @see opus_decoderctls
+ */
+OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/** Frees an <code>OpusDecoder</code> allocated by opus_decoder_create().
+ * @param[in] st <tt>OpusDecoder*</tt>: State to be freed.
+ */
+OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
+
+/** Parse an opus packet into one or more frames.
+ * Opus_decode will perform this operation internally so most applications do
+ * not need to use this function.
+ * This function does not copy the frames, the returned pointers are pointers into
+ * the input packet.
+ * @param [in] data <tt>char*</tt>: Opus packet to be parsed
+ * @param [in] len <tt>opus_int32</tt>: size of data
+ * @param [out] out_toc <tt>char*</tt>: TOC pointer
+ * @param [out] frames <tt>char*[48]</tt> encapsulated frames
+ * @param [out] size <tt>opus_int16[48]</tt> sizes of the encapsulated frames
+ * @param [out] payload_offset <tt>int*</tt>: returns the position of the payload within the packet (in bytes)
+ * @returns number of frames
+ */
+OPUS_EXPORT int opus_packet_parse(
+ const unsigned char *data,
+ opus_int32 len,
+ unsigned char *out_toc,
+ const unsigned char *frames[48],
+ opus_int16 size[48],
+ int *payload_offset
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Gets the bandwidth of an Opus packet.
+ * @param [in] data <tt>char*</tt>: Opus packet
+ * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass)
+ * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass)
+ * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass)
+ * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass)
+ * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass)
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples per frame from an Opus packet.
+ * @param [in] data <tt>char*</tt>: Opus packet.
+ * This must contain at least one byte of
+ * data.
+ * @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
+ * This must be a multiple of 400, or
+ * inaccurate results will be returned.
+ * @returns Number of samples per frame.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of channels from an Opus packet.
+ * @param [in] data <tt>char*</tt>: Opus packet
+ * @returns Number of channels
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of frames in an Opus packet.
+ * @param [in] packet <tt>char*</tt>: Opus packet
+ * @param [in] len <tt>opus_int32</tt>: Length of packet
+ * @returns Number of frames
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples of an Opus packet.
+ * @param [in] packet <tt>char*</tt>: Opus packet
+ * @param [in] len <tt>opus_int32</tt>: Length of packet
+ * @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
+ * This must be a multiple of 400, or
+ * inaccurate results will be returned.
+ * @returns Number of samples
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples of an Opus packet.
+ * @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
+ * @param [in] packet <tt>char*</tt>: Opus packet
+ * @param [in] len <tt>opus_int32</tt>: Length of packet
+ * @returns Number of samples
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+/** Applies soft-clipping to bring a float signal within the [-1,1] range. If
+ * the signal is already in that range, nothing is done. If there are values
+ * outside of [-1,1], then the signal is clipped as smoothly as possible to
+ * both fit in the range and avoid creating excessive distortion in the
+ * process.
+ * @param [in,out] pcm <tt>float*</tt>: Input PCM and modified PCM
+ * @param [in] frame_size <tt>int</tt> Number of samples per channel to process
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @param [in,out] softclip_mem <tt>float*</tt>: State memory for the soft clipping process (one float per channel, initialized to zero)
+ */
+OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem);
+
+
+/**@}*/
+
+/** @defgroup opus_repacketizer Repacketizer
+ * @{
+ *
+ * The repacketizer can be used to merge multiple Opus packets into a single
+ * packet or alternatively to split Opus packets that have previously been
+ * merged. Splitting valid Opus packets is always guaranteed to succeed,
+ * whereas merging valid packets only succeeds if all frames have the same
+ * mode, bandwidth, and frame size, and when the total duration of the merged
+ * packet is no more than 120 ms. The 120 ms limit comes from the
+ * specification and limits decoder memory requirements at a point where
+ * framing overhead becomes negligible.
+ *
+ * The repacketizer currently only operates on elementary Opus
+ * streams. It will not manipualte multistream packets successfully, except in
+ * the degenerate case where they consist of data from a single stream.
+ *
+ * The repacketizing process starts with creating a repacketizer state, either
+ * by calling opus_repacketizer_create() or by allocating the memory yourself,
+ * e.g.,
+ * @code
+ * OpusRepacketizer *rp;
+ * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size());
+ * if (rp != NULL)
+ * opus_repacketizer_init(rp);
+ * @endcode
+ *
+ * Then the application should submit packets with opus_repacketizer_cat(),
+ * extract new packets with opus_repacketizer_out() or
+ * opus_repacketizer_out_range(), and then reset the state for the next set of
+ * input packets via opus_repacketizer_init().
+ *
+ * For example, to split a sequence of packets into individual frames:
+ * @code
+ * unsigned char *data;
+ * int len;
+ * while (get_next_packet(&data, &len))
+ * {
+ * unsigned char out[1276];
+ * opus_int32 out_len;
+ * int nb_frames;
+ * int err;
+ * int i;
+ * err = opus_repacketizer_cat(rp, data, len);
+ * if (err != OPUS_OK)
+ * {
+ * release_packet(data);
+ * return err;
+ * }
+ * nb_frames = opus_repacketizer_get_nb_frames(rp);
+ * for (i = 0; i < nb_frames; i++)
+ * {
+ * out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out));
+ * if (out_len < 0)
+ * {
+ * release_packet(data);
+ * return (int)out_len;
+ * }
+ * output_next_packet(out, out_len);
+ * }
+ * opus_repacketizer_init(rp);
+ * release_packet(data);
+ * }
+ * @endcode
+ *
+ * Alternatively, to combine a sequence of frames into packets that each
+ * contain up to <code>TARGET_DURATION_MS</code> milliseconds of data:
+ * @code
+ * // The maximum number of packets with duration TARGET_DURATION_MS occurs
+ * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5)
+ * // packets.
+ * unsigned char *data[(TARGET_DURATION_MS*2/5)+1];
+ * opus_int32 len[(TARGET_DURATION_MS*2/5)+1];
+ * int nb_packets;
+ * unsigned char out[1277*(TARGET_DURATION_MS*2/2)];
+ * opus_int32 out_len;
+ * int prev_toc;
+ * nb_packets = 0;
+ * while (get_next_packet(data+nb_packets, len+nb_packets))
+ * {
+ * int nb_frames;
+ * int err;
+ * nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]);
+ * if (nb_frames < 1)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return nb_frames;
+ * }
+ * nb_frames += opus_repacketizer_get_nb_frames(rp);
+ * // If adding the next packet would exceed our target, or it has an
+ * // incompatible TOC sequence, output the packets we already have before
+ * // submitting it.
+ * // N.B., The nb_packets > 0 check ensures we've submitted at least one
+ * // packet since the last call to opus_repacketizer_init(). Otherwise a
+ * // single packet longer than TARGET_DURATION_MS would cause us to try to
+ * // output an (invalid) empty packet. It also ensures that prev_toc has
+ * // been set to a valid value. Additionally, len[nb_packets] > 0 is
+ * // guaranteed by the call to opus_packet_get_nb_frames() above, so the
+ * // reference to data[nb_packets][0] should be valid.
+ * if (nb_packets > 0 && (
+ * ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) ||
+ * opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames >
+ * TARGET_DURATION_MS*48))
+ * {
+ * out_len = opus_repacketizer_out(rp, out, sizeof(out));
+ * if (out_len < 0)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return (int)out_len;
+ * }
+ * output_next_packet(out, out_len);
+ * opus_repacketizer_init(rp);
+ * release_packets(data, nb_packets);
+ * data[0] = data[nb_packets];
+ * len[0] = len[nb_packets];
+ * nb_packets = 0;
+ * }
+ * err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]);
+ * if (err != OPUS_OK)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return err;
+ * }
+ * prev_toc = data[nb_packets][0];
+ * nb_packets++;
+ * }
+ * // Output the final, partial packet.
+ * if (nb_packets > 0)
+ * {
+ * out_len = opus_repacketizer_out(rp, out, sizeof(out));
+ * release_packets(data, nb_packets);
+ * if (out_len < 0)
+ * return (int)out_len;
+ * output_next_packet(out, out_len);
+ * }
+ * @endcode
+ *
+ * An alternate way of merging packets is to simply call opus_repacketizer_cat()
+ * unconditionally until it fails. At that point, the merged packet can be
+ * obtained with opus_repacketizer_out() and the input packet for which
+ * opus_repacketizer_cat() needs to be re-added to a newly reinitialized
+ * repacketizer state.
+ */
+
+typedef struct OpusRepacketizer OpusRepacketizer;
+
+/** Gets the size of an <code>OpusRepacketizer</code> structure.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void);
+
+/** (Re)initializes a previously allocated repacketizer state.
+ * The state must be at least the size returned by opus_repacketizer_get_size().
+ * This can be used for applications which use their own allocator instead of
+ * malloc().
+ * It must also be called to reset the queue of packets waiting to be
+ * repacketized, which is necessary if the maximum packet duration of 120 ms
+ * is reached or if you wish to submit packets with a different Opus
+ * configuration (coding mode, audio bandwidth, frame size, or channel count).
+ * Failure to do so will prevent a new packet from being added with
+ * opus_repacketizer_cat().
+ * @see opus_repacketizer_create
+ * @see opus_repacketizer_get_size
+ * @see opus_repacketizer_cat
+ * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to
+ * (re)initialize.
+ * @returns A pointer to the same repacketizer state that was passed in.
+ */
+OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
+
+/** Allocates memory and initializes the new repacketizer with
+ * opus_repacketizer_init().
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void);
+
+/** Frees an <code>OpusRepacketizer</code> allocated by
+ * opus_repacketizer_create().
+ * @param[in] rp <tt>OpusRepacketizer*</tt>: State to be freed.
+ */
+OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp);
+
+/** Add a packet to the current repacketizer state.
+ * This packet must match the configuration of any packets already submitted
+ * for repacketization since the last call to opus_repacketizer_init().
+ * This means that it must have the same coding mode, audio bandwidth, frame
+ * size, and channel count.
+ * This can be checked in advance by examining the top 6 bits of the first
+ * byte of the packet, and ensuring they match the top 6 bits of the first
+ * byte of any previously submitted packet.
+ * The total duration of audio in the repacketizer state also must not exceed
+ * 120 ms, the maximum duration of a single packet, after adding this packet.
+ *
+ * The contents of the current repacketizer state can be extracted into new
+ * packets using opus_repacketizer_out() or opus_repacketizer_out_range().
+ *
+ * In order to add a packet with a different configuration or to add more
+ * audio beyond 120 ms, you must clear the repacketizer state by calling
+ * opus_repacketizer_init().
+ * If a packet is too large to add to the current repacketizer state, no part
+ * of it is added, even if it contains multiple frames, some of which might
+ * fit.
+ * If you wish to be able to add parts of such packets, you should first use
+ * another repacketizer to split the packet into pieces and add them
+ * individually.
+ * @see opus_repacketizer_out_range
+ * @see opus_repacketizer_out
+ * @see opus_repacketizer_init
+ * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to which to
+ * add the packet.
+ * @param[in] data <tt>const unsigned char*</tt>: The packet data.
+ * The application must ensure
+ * this pointer remains valid
+ * until the next call to
+ * opus_repacketizer_init() or
+ * opus_repacketizer_destroy().
+ * @param len <tt>opus_int32</tt>: The number of bytes in the packet data.
+ * @returns An error code indicating whether or not the operation succeeded.
+ * @retval #OPUS_OK The packet's contents have been added to the repacketizer
+ * state.
+ * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence,
+ * the packet's TOC sequence was not compatible
+ * with previously submitted packets (because
+ * the coding mode, audio bandwidth, frame size,
+ * or channel count did not match), or adding
+ * this packet would increase the total amount of
+ * audio stored in the repacketizer state to more
+ * than 120 ms.
+ */
+OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+
+/** Construct a new packet from data previously submitted to the repacketizer
+ * state via opus_repacketizer_cat().
+ * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
+ * construct the new packet.
+ * @param begin <tt>int</tt>: The index of the first frame in the current
+ * repacketizer state to include in the output.
+ * @param end <tt>int</tt>: One past the index of the last frame in the
+ * current repacketizer state to include in the
+ * output.
+ * @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
+ * store the output packet.
+ * @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
+ * the output buffer. In order to guarantee
+ * success, this should be at least
+ * <code>1276</code> for a single frame,
+ * or for multiple frames,
+ * <code>1277*(end-begin)</code>.
+ * However, <code>1*(end-begin)</code> plus
+ * the size of all packet data submitted to
+ * the repacketizer since the last call to
+ * opus_repacketizer_init() or
+ * opus_repacketizer_create() is also
+ * sufficient, and possibly much smaller.
+ * @returns The total size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG <code>[begin,end)</code> was an invalid range of
+ * frames (begin < 0, begin >= end, or end >
+ * opus_repacketizer_get_nb_frames()).
+ * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+ * complete output packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Return the total number of frames contained in packet data submitted to
+ * the repacketizer state so far via opus_repacketizer_cat() since the last
+ * call to opus_repacketizer_init() or opus_repacketizer_create().
+ * This defines the valid range of packets that can be extracted with
+ * opus_repacketizer_out_range() or opus_repacketizer_out().
+ * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state containing the
+ * frames.
+ * @returns The total number of frames contained in the packet data submitted
+ * to the repacketizer state.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
+
+/** Construct a new packet from data previously submitted to the repacketizer
+ * state via opus_repacketizer_cat().
+ * This is a convenience routine that returns all the data submitted so far
+ * in a single packet.
+ * It is equivalent to calling
+ * @code
+ * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp),
+ * data, maxlen)
+ * @endcode
+ * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
+ * construct the new packet.
+ * @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
+ * store the output packet.
+ * @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
+ * the output buffer. In order to guarantee
+ * success, this should be at least
+ * <code>1277*opus_repacketizer_get_nb_frames(rp)</code>.
+ * However,
+ * <code>1*opus_repacketizer_get_nb_frames(rp)</code>
+ * plus the size of all packet data
+ * submitted to the repacketizer since the
+ * last call to opus_repacketizer_init() or
+ * opus_repacketizer_create() is also
+ * sufficient, and possibly much smaller.
+ * @returns The total size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+ * complete output packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1);
+
+/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence).
+ * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+ * packet to pad.
+ * @param len <tt>opus_int32</tt>: The size of the packet.
+ * This must be at least 1.
+ * @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
+ * This must be at least as large as len.
+ * @returns an error code
+ * @retval #OPUS_OK \a on success.
+ * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len);
+
+/** Remove all padding from a given Opus packet and rewrite the TOC sequence to
+ * minimize space usage.
+ * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+ * packet to strip.
+ * @param len <tt>opus_int32</tt>: The size of the packet.
+ * This must be at least 1.
+ * @returns The new size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG \a len was less than 1.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len);
+
+/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence).
+ * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+ * packet to pad.
+ * @param len <tt>opus_int32</tt>: The size of the packet.
+ * This must be at least 1.
+ * @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
+ * This must be at least 1.
+ * @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
+ * This must be at least as large as len.
+ * @returns an error code
+ * @retval #OPUS_OK \a on success.
+ * @retval #OPUS_BAD_ARG \a len was less than 1.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams);
+
+/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to
+ * minimize space usage.
+ * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+ * packet to strip.
+ * @param len <tt>opus_int32</tt>: The size of the packet.
+ * This must be at least 1.
+ * @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
+ * This must be at least 1.
+ * @returns The new size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams);
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_H */
diff --git a/external/opus-1.1.4/include/opus_custom.h b/external/opus-1.1.4/include/opus_custom.h
new file mode 100644
index 0000000..41f36bf
--- /dev/null
+++ b/external/opus-1.1.4/include/opus_custom.h
@@ -0,0 +1,342 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008-2012 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+/**
+ @file opus_custom.h
+ @brief Opus-Custom reference implementation API
+ */
+
+#ifndef OPUS_CUSTOM_H
+#define OPUS_CUSTOM_H
+
+#include "opus_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef CUSTOM_MODES
+# define OPUS_CUSTOM_EXPORT OPUS_EXPORT
+# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT
+#else
+# define OPUS_CUSTOM_EXPORT
+# ifdef OPUS_BUILD
+# define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE
+# else
+# define OPUS_CUSTOM_EXPORT_STATIC
+# endif
+#endif
+
+/** @defgroup opus_custom Opus Custom
+ * @{
+ * Opus Custom is an optional part of the Opus specification and
+ * reference implementation which uses a distinct API from the regular
+ * API and supports frame sizes that are not normally supported.\ Use
+ * of Opus Custom is discouraged for all but very special applications
+ * for which a frame size different from 2.5, 5, 10, or 20 ms is needed
+ * (for either complexity or latency reasons) and where interoperability
+ * is less important.
+ *
+ * In addition to the interoperability limitations the use of Opus custom
+ * disables a substantial chunk of the codec and generally lowers the
+ * quality available at a given bitrate. Normally when an application needs
+ * a different frame size from the codec it should buffer to match the
+ * sizes but this adds a small amount of delay which may be important
+ * in some very low latency applications. Some transports (especially
+ * constant rate RF transports) may also work best with frames of
+ * particular durations.
+ *
+ * Libopus only supports custom modes if they are enabled at compile time.
+ *
+ * The Opus Custom API is similar to the regular API but the
+ * @ref opus_encoder_create and @ref opus_decoder_create calls take
+ * an additional mode parameter which is a structure produced by
+ * a call to @ref opus_custom_mode_create. Both the encoder and decoder
+ * must create a mode using the same sample rate (fs) and frame size
+ * (frame size) so these parameters must either be signaled out of band
+ * or fixed in a particular implementation.
+ *
+ * Similar to regular Opus the custom modes support on the fly frame size
+ * switching, but the sizes available depend on the particular frame size in
+ * use. For some initial frame sizes on a single on the fly size is available.
+ */
+
+/** Contains the state of an encoder. One encoder state is needed
+ for each stream. It is initialized once at the beginning of the
+ stream. Do *not* re-initialize the state for every frame.
+ @brief Encoder state
+ */
+typedef struct OpusCustomEncoder OpusCustomEncoder;
+
+/** State of the decoder. One decoder state is needed for each stream.
+ It is initialized once at the beginning of the stream. Do *not*
+ re-initialize the state for every frame.
+ @brief Decoder state
+ */
+typedef struct OpusCustomDecoder OpusCustomDecoder;
+
+/** The mode contains all the information necessary to create an
+ encoder. Both the encoder and decoder need to be initialized
+ with exactly the same mode, otherwise the output will be
+ corrupted.
+ @brief Mode configuration
+ */
+typedef struct OpusCustomMode OpusCustomMode;
+
+/** Creates a new mode struct. This will be passed to an encoder or
+ * decoder. The mode MUST NOT BE DESTROYED until the encoders and
+ * decoders that use it are destroyed as well.
+ * @param [in] Fs <tt>int</tt>: Sampling rate (8000 to 96000 Hz)
+ * @param [in] frame_size <tt>int</tt>: Number of samples (per channel) to encode in each
+ * packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes)
+ * @param [out] error <tt>int*</tt>: Returned error code (if NULL, no error will be returned)
+ * @return A newly created mode
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error);
+
+/** Destroys a mode struct. Only call this after all encoders and
+ * decoders using this mode are destroyed as well.
+ * @param [in] mode <tt>OpusCustomMode*</tt>: Mode to be freed.
+ */
+OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode);
+
+
+#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C)
+
+/* Encoder */
+/** Gets the size of an OpusCustomEncoder structure.
+ * @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @returns size
+ */
+OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size(
+ const OpusCustomMode *mode,
+ int channels
+) OPUS_ARG_NONNULL(1);
+
+# ifdef CUSTOM_MODES
+/** Initializes a previously allocated encoder state
+ * The memory pointed to by st must be the size returned by opus_custom_encoder_get_size.
+ * This is intended for applications which use their own allocator instead of malloc.
+ * @see opus_custom_encoder_create(),opus_custom_encoder_get_size()
+ * To reset a previously initialized state use the OPUS_RESET_STATE CTL.
+ * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
+ * @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
+ * the stream (must be the same characteristics as used for the
+ * decoder)
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @return OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_CUSTOM_EXPORT int opus_custom_encoder_init(
+ OpusCustomEncoder *st,
+ const OpusCustomMode *mode,
+ int channels
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+# endif
+#endif
+
+
+/** Creates a new encoder state. Each stream needs its own encoder
+ * state (can't be shared across simultaneous streams).
+ * @param [in] mode <tt>OpusCustomMode*</tt>: Contains all the information about the characteristics of
+ * the stream (must be the same characteristics as used for the
+ * decoder)
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @param [out] error <tt>int*</tt>: Returns an error code
+ * @return Newly created encoder state.
+*/
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create(
+ const OpusCustomMode *mode,
+ int channels,
+ int *error
+) OPUS_ARG_NONNULL(1);
+
+
+/** Destroys a an encoder state.
+ * @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed.
+ */
+OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st);
+
+/** Encodes a frame of audio.
+ * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
+ * @param [in] pcm <tt>float*</tt>: PCM audio in float format, with a normal range of +/-1.0.
+ * Samples with a range beyond +/-1.0 are supported but will
+ * be clipped by decoders using the integer API and should
+ * only be used if it is known that the far end supports
+ * extended dynamic range. There must be exactly
+ * frame_size samples per channel.
+ * @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
+ * @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
+ * @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
+ * (can change from one frame to another)
+ * @return Number of bytes written to "compressed".
+ * If negative, an error has occurred (see error codes). It is IMPORTANT that
+ * the length returned be somehow transmitted to the decoder. Otherwise, no
+ * decoding is possible.
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float(
+ OpusCustomEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *compressed,
+ int maxCompressedBytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes a frame of audio.
+ * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
+ * @param [in] pcm <tt>opus_int16*</tt>: PCM audio in signed 16-bit format (native endian).
+ * There must be exactly frame_size samples per channel.
+ * @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
+ * @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
+ * @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
+ * (can change from one frame to another)
+ * @return Number of bytes written to "compressed".
+ * If negative, an error has occurred (see error codes). It is IMPORTANT that
+ * the length returned be somehow transmitted to the decoder. Otherwise, no
+ * decoding is possible.
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode(
+ OpusCustomEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *compressed,
+ int maxCompressedBytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on an Opus custom encoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @see opus_encoderctls
+ */
+OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
+
+
+#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C)
+/* Decoder */
+
+/** Gets the size of an OpusCustomDecoder structure.
+ * @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @returns size
+ */
+OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size(
+ const OpusCustomMode *mode,
+ int channels
+) OPUS_ARG_NONNULL(1);
+
+/** Initializes a previously allocated decoder state
+ * The memory pointed to by st must be the size returned by opus_custom_decoder_get_size.
+ * This is intended for applications which use their own allocator instead of malloc.
+ * @see opus_custom_decoder_create(),opus_custom_decoder_get_size()
+ * To reset a previously initialized state use the OPUS_RESET_STATE CTL.
+ * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
+ * @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
+ * the stream (must be the same characteristics as used for the
+ * encoder)
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @return OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init(
+ OpusCustomDecoder *st,
+ const OpusCustomMode *mode,
+ int channels
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+#endif
+
+
+/** Creates a new decoder state. Each stream needs its own decoder state (can't
+ * be shared across simultaneous streams).
+ * @param [in] mode <tt>OpusCustomMode</tt>: Contains all the information about the characteristics of the
+ * stream (must be the same characteristics as used for the encoder)
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @param [out] error <tt>int*</tt>: Returns an error code
+ * @return Newly created decoder state.
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create(
+ const OpusCustomMode *mode,
+ int channels,
+ int *error
+) OPUS_ARG_NONNULL(1);
+
+/** Destroys a an decoder state.
+ * @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed.
+ */
+OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st);
+
+/** Decode an opus custom frame with floating point output
+ * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
+ * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len <tt>int</tt>: Number of bytes in payload
+ * @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(float)
+ * @param [in] frame_size Number of samples per channel of available space in *pcm.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float(
+ OpusCustomDecoder *st,
+ const unsigned char *data,
+ int len,
+ float *pcm,
+ int frame_size
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode an opus custom frame
+ * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
+ * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len <tt>int</tt>: Number of bytes in payload
+ * @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(opus_int16)
+ * @param [in] frame_size Number of samples per channel of available space in *pcm.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode(
+ OpusCustomDecoder *st,
+ const unsigned char *data,
+ int len,
+ opus_int16 *pcm,
+ int frame_size
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on an Opus custom decoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @see opus_genericctls
+ */
+OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_CUSTOM_H */
diff --git a/external/opus-1.1.4/include/opus_defines.h b/external/opus-1.1.4/include/opus_defines.h
new file mode 100644
index 0000000..315412d
--- /dev/null
+++ b/external/opus-1.1.4/include/opus_defines.h
@@ -0,0 +1,753 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+/**
+ * @file opus_defines.h
+ * @brief Opus reference implementation constants
+ */
+
+#ifndef OPUS_DEFINES_H
+#define OPUS_DEFINES_H
+
+#include "opus_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup opus_errorcodes Error codes
+ * @{
+ */
+/** No error @hideinitializer*/
+#define OPUS_OK 0
+/** One or more invalid/out of range arguments @hideinitializer*/
+#define OPUS_BAD_ARG -1
+/** Not enough bytes allocated in the buffer @hideinitializer*/
+#define OPUS_BUFFER_TOO_SMALL -2
+/** An internal error was detected @hideinitializer*/
+#define OPUS_INTERNAL_ERROR -3
+/** The compressed data passed is corrupted @hideinitializer*/
+#define OPUS_INVALID_PACKET -4
+/** Invalid/unsupported request number @hideinitializer*/
+#define OPUS_UNIMPLEMENTED -5
+/** An encoder or decoder structure is invalid or already freed @hideinitializer*/
+#define OPUS_INVALID_STATE -6
+/** Memory allocation has failed @hideinitializer*/
+#define OPUS_ALLOC_FAIL -7
+/**@}*/
+
+/** @cond OPUS_INTERNAL_DOC */
+/**Export control for opus functions */
+
+#ifndef OPUS_EXPORT
+# if defined(WIN32)
+# if defined(OPUS_BUILD) && defined(DLL_EXPORT)
+# define OPUS_EXPORT __declspec(dllexport)
+# else
+# define OPUS_EXPORT
+# endif
+# elif defined(__GNUC__) && defined(OPUS_BUILD)
+# define OPUS_EXPORT __attribute__ ((visibility ("default")))
+# else
+# define OPUS_EXPORT
+# endif
+#endif
+
+# if !defined(OPUS_GNUC_PREREQ)
+# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
+# define OPUS_GNUC_PREREQ(_maj,_min) \
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
+# else
+# define OPUS_GNUC_PREREQ(_maj,_min) 0
+# endif
+# endif
+
+#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if OPUS_GNUC_PREREQ(3,0)
+# define OPUS_RESTRICT __restrict__
+# elif (defined(_MSC_VER) && _MSC_VER >= 1400)
+# define OPUS_RESTRICT __restrict
+# else
+# define OPUS_RESTRICT
+# endif
+#else
+# define OPUS_RESTRICT restrict
+#endif
+
+#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if OPUS_GNUC_PREREQ(2,7)
+# define OPUS_INLINE __inline__
+# elif (defined(_MSC_VER))
+# define OPUS_INLINE __inline
+# else
+# define OPUS_INLINE
+# endif
+#else
+# define OPUS_INLINE inline
+#endif
+
+/**Warning attributes for opus functions
+ * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out
+ * some paranoid null checks. */
+#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
+# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
+#else
+# define OPUS_WARN_UNUSED_RESULT
+#endif
+#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
+# define OPUS_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x)))
+#else
+# define OPUS_ARG_NONNULL(_x)
+#endif
+
+/** These are the actual Encoder CTL ID numbers.
+ * They should not be used directly by applications.
+ * In general, SETs should be even and GETs should be odd.*/
+#define OPUS_SET_APPLICATION_REQUEST 4000
+#define OPUS_GET_APPLICATION_REQUEST 4001
+#define OPUS_SET_BITRATE_REQUEST 4002
+#define OPUS_GET_BITRATE_REQUEST 4003
+#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004
+#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005
+#define OPUS_SET_VBR_REQUEST 4006
+#define OPUS_GET_VBR_REQUEST 4007
+#define OPUS_SET_BANDWIDTH_REQUEST 4008
+#define OPUS_GET_BANDWIDTH_REQUEST 4009
+#define OPUS_SET_COMPLEXITY_REQUEST 4010
+#define OPUS_GET_COMPLEXITY_REQUEST 4011
+#define OPUS_SET_INBAND_FEC_REQUEST 4012
+#define OPUS_GET_INBAND_FEC_REQUEST 4013
+#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014
+#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015
+#define OPUS_SET_DTX_REQUEST 4016
+#define OPUS_GET_DTX_REQUEST 4017
+#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020
+#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021
+#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022
+#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023
+#define OPUS_SET_SIGNAL_REQUEST 4024
+#define OPUS_GET_SIGNAL_REQUEST 4025
+#define OPUS_GET_LOOKAHEAD_REQUEST 4027
+/* #define OPUS_RESET_STATE 4028 */
+#define OPUS_GET_SAMPLE_RATE_REQUEST 4029
+#define OPUS_GET_FINAL_RANGE_REQUEST 4031
+#define OPUS_GET_PITCH_REQUEST 4033
+#define OPUS_SET_GAIN_REQUEST 4034
+#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */
+#define OPUS_SET_LSB_DEPTH_REQUEST 4036
+#define OPUS_GET_LSB_DEPTH_REQUEST 4037
+#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039
+#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040
+#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041
+#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042
+#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043
+
+/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
+
+/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
+#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
+#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
+#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))
+#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))
+/** @endcond */
+
+/** @defgroup opus_ctlvalues Pre-defined values for CTL interface
+ * @see opus_genericctls, opus_encoderctls
+ * @{
+ */
+/* Values for the various encoder CTLs */
+#define OPUS_AUTO -1000 /**<Auto/default setting @hideinitializer*/
+#define OPUS_BITRATE_MAX -1 /**<Maximum bitrate @hideinitializer*/
+
+/** Best for most VoIP/videoconference applications where listening quality and intelligibility matter most
+ * @hideinitializer */
+#define OPUS_APPLICATION_VOIP 2048
+/** Best for broadcast/high-fidelity application where the decoded audio should be as close as possible to the input
+ * @hideinitializer */
+#define OPUS_APPLICATION_AUDIO 2049
+/** Only use when lowest-achievable latency is what matters most. Voice-optimized modes cannot be used.
+ * @hideinitializer */
+#define OPUS_APPLICATION_RESTRICTED_LOWDELAY 2051
+
+#define OPUS_SIGNAL_VOICE 3001 /**< Signal being encoded is voice */
+#define OPUS_SIGNAL_MUSIC 3002 /**< Signal being encoded is music */
+#define OPUS_BANDWIDTH_NARROWBAND 1101 /**< 4 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_MEDIUMBAND 1102 /**< 6 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_WIDEBAND 1103 /**< 8 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_SUPERWIDEBAND 1104 /**<12 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_FULLBAND 1105 /**<20 kHz bandpass @hideinitializer*/
+
+#define OPUS_FRAMESIZE_ARG 5000 /**< Select frame size from the argument (default) */
+#define OPUS_FRAMESIZE_2_5_MS 5001 /**< Use 2.5 ms frames */
+#define OPUS_FRAMESIZE_5_MS 5002 /**< Use 5 ms frames */
+#define OPUS_FRAMESIZE_10_MS 5003 /**< Use 10 ms frames */
+#define OPUS_FRAMESIZE_20_MS 5004 /**< Use 20 ms frames */
+#define OPUS_FRAMESIZE_40_MS 5005 /**< Use 40 ms frames */
+#define OPUS_FRAMESIZE_60_MS 5006 /**< Use 60 ms frames */
+
+/**@}*/
+
+
+/** @defgroup opus_encoderctls Encoder related CTLs
+ *
+ * These are convenience macros for use with the \c opus_encode_ctl
+ * interface. They are used to generate the appropriate series of
+ * arguments for that call, passing the correct type, size and so
+ * on as expected for each particular request.
+ *
+ * Some usage examples:
+ *
+ * @code
+ * int ret;
+ * ret = opus_encoder_ctl(enc_ctx, OPUS_SET_BANDWIDTH(OPUS_AUTO));
+ * if (ret != OPUS_OK) return ret;
+ *
+ * opus_int32 rate;
+ * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&rate));
+ *
+ * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);
+ * @endcode
+ *
+ * @see opus_genericctls, opus_encoder
+ * @{
+ */
+
+/** Configures the encoder's computational complexity.
+ * The supported range is 0-10 inclusive with 10 representing the highest complexity.
+ * @see OPUS_GET_COMPLEXITY
+ * @param[in] x <tt>opus_int32</tt>: Allowed values: 0-10, inclusive.
+ *
+ * @hideinitializer */
+#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x)
+/** Gets the encoder's complexity configuration.
+ * @see OPUS_SET_COMPLEXITY
+ * @param[out] x <tt>opus_int32 *</tt>: Returns a value in the range 0-10,
+ * inclusive.
+ * @hideinitializer */
+#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the bitrate in the encoder.
+ * Rates from 500 to 512000 bits per second are meaningful, as well as the
+ * special values #OPUS_AUTO and #OPUS_BITRATE_MAX.
+ * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much
+ * rate as it can, which is useful for controlling the rate by adjusting the
+ * output buffer size.
+ * @see OPUS_GET_BITRATE
+ * @param[in] x <tt>opus_int32</tt>: Bitrate in bits per second. The default
+ * is determined based on the number of
+ * channels and the input sampling rate.
+ * @hideinitializer */
+#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x)
+/** Gets the encoder's bitrate configuration.
+ * @see OPUS_SET_BITRATE
+ * @param[out] x <tt>opus_int32 *</tt>: Returns the bitrate in bits per second.
+ * The default is determined based on the
+ * number of channels and the input
+ * sampling rate.
+ * @hideinitializer */
+#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x)
+
+/** Enables or disables variable bitrate (VBR) in the encoder.
+ * The configured bitrate may not be met exactly because frames must
+ * be an integer number of bytes in length.
+ * @see OPUS_GET_VBR
+ * @see OPUS_SET_VBR_CONSTRAINT
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>0</dt><dd>Hard CBR. For LPC/hybrid modes at very low bit-rate, this can
+ * cause noticeable quality degradation.</dd>
+ * <dt>1</dt><dd>VBR (default). The exact type of VBR is controlled by
+ * #OPUS_SET_VBR_CONSTRAINT.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x)
+/** Determine if variable bitrate (VBR) is enabled in the encoder.
+ * @see OPUS_SET_VBR
+ * @see OPUS_GET_VBR_CONSTRAINT
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>0</dt><dd>Hard CBR.</dd>
+ * <dt>1</dt><dd>VBR (default). The exact type of VBR may be retrieved via
+ * #OPUS_GET_VBR_CONSTRAINT.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x)
+
+/** Enables or disables constrained VBR in the encoder.
+ * This setting is ignored when the encoder is in CBR mode.
+ * @warning Only the MDCT mode of Opus currently heeds the constraint.
+ * Speech mode ignores it completely, hybrid mode may fail to obey it
+ * if the LPC layer uses more bitrate than the constraint would have
+ * permitted.
+ * @see OPUS_GET_VBR_CONSTRAINT
+ * @see OPUS_SET_VBR
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>0</dt><dd>Unconstrained VBR.</dd>
+ * <dt>1</dt><dd>Constrained VBR (default). This creates a maximum of one
+ * frame of buffering delay assuming a transport with a
+ * serialization speed of the nominal bitrate.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x)
+/** Determine if constrained VBR is enabled in the encoder.
+ * @see OPUS_SET_VBR_CONSTRAINT
+ * @see OPUS_GET_VBR
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>0</dt><dd>Unconstrained VBR.</dd>
+ * <dt>1</dt><dd>Constrained VBR (default).</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures mono/stereo forcing in the encoder.
+ * This can force the encoder to produce packets encoded as either mono or
+ * stereo, regardless of the format of the input audio. This is useful when
+ * the caller knows that the input signal is currently a mono source embedded
+ * in a stereo stream.
+ * @see OPUS_GET_FORCE_CHANNELS
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt><dd>Not forced (default)</dd>
+ * <dt>1</dt> <dd>Forced mono</dd>
+ * <dt>2</dt> <dd>Forced stereo</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x)
+/** Gets the encoder's forced channel configuration.
+ * @see OPUS_SET_FORCE_CHANNELS
+ * @param[out] x <tt>opus_int32 *</tt>:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt><dd>Not forced (default)</dd>
+ * <dt>1</dt> <dd>Forced mono</dd>
+ * <dt>2</dt> <dd>Forced stereo</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the maximum bandpass that the encoder will select automatically.
+ * Applications should normally use this instead of #OPUS_SET_BANDWIDTH
+ * (leaving that set to the default, #OPUS_AUTO). This allows the
+ * application to set an upper bound based on the type of input it is
+ * providing, but still gives the encoder the freedom to reduce the bandpass
+ * when the bitrate becomes too low, for better overall quality.
+ * @see OPUS_GET_MAX_BANDWIDTH
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
+ * <dt>OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
+ * <dt>OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
+ * <dt>OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+ * <dt>OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband (default)</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x)
+
+/** Gets the encoder's configured maximum allowed bandpass.
+ * @see OPUS_SET_MAX_BANDWIDTH
+ * @param[out] x <tt>opus_int32 *</tt>: Allowed values:
+ * <dl>
+ * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband (default)</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Sets the encoder's bandpass to a specific value.
+ * This prevents the encoder from automatically selecting the bandpass based
+ * on the available bitrate. If an application knows the bandpass of the input
+ * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH
+ * instead, which still gives the encoder the freedom to reduce the bandpass
+ * when the bitrate becomes too low, for better overall quality.
+ * @see OPUS_GET_BANDWIDTH
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
+ * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x)
+
+/** Configures the type of signal being encoded.
+ * This is a hint which helps the encoder's mode selection.
+ * @see OPUS_GET_SIGNAL
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
+ * <dt>#OPUS_SIGNAL_VOICE</dt><dd>Bias thresholds towards choosing LPC or Hybrid modes.</dd>
+ * <dt>#OPUS_SIGNAL_MUSIC</dt><dd>Bias thresholds towards choosing MDCT modes.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured signal type.
+ * @see OPUS_SET_SIGNAL
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
+ * <dt>#OPUS_SIGNAL_VOICE</dt><dd>Bias thresholds towards choosing LPC or Hybrid modes.</dd>
+ * <dt>#OPUS_SIGNAL_MUSIC</dt><dd>Bias thresholds towards choosing MDCT modes.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x)
+
+
+/** Configures the encoder's intended application.
+ * The initial value is a mandatory argument to the encoder_create function.
+ * @see OPUS_GET_APPLICATION
+ * @param[in] x <tt>opus_int32</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>#OPUS_APPLICATION_VOIP</dt>
+ * <dd>Process signal for improved speech intelligibility.</dd>
+ * <dt>#OPUS_APPLICATION_AUDIO</dt>
+ * <dd>Favor faithfulness to the original input.</dd>
+ * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+ * <dd>Configure the minimum possible coding delay by disabling certain modes
+ * of operation.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured application.
+ * @see OPUS_SET_APPLICATION
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>#OPUS_APPLICATION_VOIP</dt>
+ * <dd>Process signal for improved speech intelligibility.</dd>
+ * <dt>#OPUS_APPLICATION_AUDIO</dt>
+ * <dd>Favor faithfulness to the original input.</dd>
+ * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+ * <dd>Configure the minimum possible coding delay by disabling certain modes
+ * of operation.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the total samples of delay added by the entire codec.
+ * This can be queried by the encoder and then the provided number of samples can be
+ * skipped on from the start of the decoder's output to provide time aligned input
+ * and output. From the perspective of a decoding application the real data begins this many
+ * samples late.
+ *
+ * The decoder contribution to this delay is identical for all decoders, but the
+ * encoder portion of the delay may vary from implementation to implementation,
+ * version to version, or even depend on the encoder's initial configuration.
+ * Applications needing delay compensation should call this CTL rather than
+ * hard-coding a value.
+ * @param[out] x <tt>opus_int32 *</tt>: Number of lookahead samples
+ * @hideinitializer */
+#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of inband forward error correction (FEC).
+ * @note This is only applicable to the LPC layer
+ * @see OPUS_GET_INBAND_FEC
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>0</dt><dd>Disable inband FEC (default).</dd>
+ * <dt>1</dt><dd>Enable inband FEC.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
+/** Gets encoder's configured use of inband forward error correction.
+ * @see OPUS_SET_INBAND_FEC
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>0</dt><dd>Inband FEC disabled (default).</dd>
+ * <dt>1</dt><dd>Inband FEC enabled.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's expected packet loss percentage.
+ * Higher values trigger progressively more loss resistant behavior in the encoder
+ * at the expense of quality at a given bitrate in the absence of packet loss, but
+ * greater quality under loss.
+ * @see OPUS_GET_PACKET_LOSS_PERC
+ * @param[in] x <tt>opus_int32</tt>: Loss percentage in the range 0-100, inclusive (default: 0).
+ * @hideinitializer */
+#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured packet loss percentage.
+ * @see OPUS_SET_PACKET_LOSS_PERC
+ * @param[out] x <tt>opus_int32 *</tt>: Returns the configured loss percentage
+ * in the range 0-100, inclusive (default: 0).
+ * @hideinitializer */
+#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of discontinuous transmission (DTX).
+ * @note This is only applicable to the LPC layer
+ * @see OPUS_GET_DTX
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>0</dt><dd>Disable DTX (default).</dd>
+ * <dt>1</dt><dd>Enabled DTX.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x)
+/** Gets encoder's configured use of discontinuous transmission.
+ * @see OPUS_SET_DTX
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>0</dt><dd>DTX disabled (default).</dd>
+ * <dt>1</dt><dd>DTX enabled.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x)
+/** Configures the depth of signal being encoded.
+ *
+ * This is a hint which helps the encoder identify silence and near-silence.
+ * It represents the number of significant bits of linear intensity below
+ * which the signal contains ignorable quantization or other noise.
+ *
+ * For example, OPUS_SET_LSB_DEPTH(14) would be an appropriate setting
+ * for G.711 u-law input. OPUS_SET_LSB_DEPTH(16) would be appropriate
+ * for 16-bit linear pcm input with opus_encode_float().
+ *
+ * When using opus_encode() instead of opus_encode_float(), or when libopus
+ * is compiled for fixed-point, the encoder uses the minimum of the value
+ * set here and the value 16.
+ *
+ * @see OPUS_GET_LSB_DEPTH
+ * @param[in] x <tt>opus_int32</tt>: Input precision in bits, between 8 and 24
+ * (default: 24).
+ * @hideinitializer */
+#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured signal depth.
+ * @see OPUS_SET_LSB_DEPTH
+ * @param[out] x <tt>opus_int32 *</tt>: Input precision in bits, between 8 and
+ * 24 (default: 24).
+ * @hideinitializer */
+#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of variable duration frames.
+ * When variable duration is enabled, the encoder is free to use a shorter frame
+ * size than the one requested in the opus_encode*() call.
+ * It is then the user's responsibility
+ * to verify how much audio was encoded by checking the ToC byte of the encoded
+ * packet. The part of the audio that was not encoded needs to be resent to the
+ * encoder for the next call. Do not use this option unless you <b>really</b>
+ * know what you are doing.
+ * @see OPUS_GET_EXPERT_FRAME_DURATION
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>
+ * <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 5 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured use of variable duration frames.
+ * @see OPUS_SET_EXPERT_FRAME_DURATION
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>
+ * <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 5 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x)
+
+/** If set to 1, disables almost all use of prediction, making frames almost
+ * completely independent. This reduces quality.
+ * @see OPUS_GET_PREDICTION_DISABLED
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>0</dt><dd>Enable prediction (default).</dd>
+ * <dt>1</dt><dd>Disable prediction.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured prediction status.
+ * @see OPUS_SET_PREDICTION_DISABLED
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>0</dt><dd>Prediction enabled (default).</dd>
+ * <dt>1</dt><dd>Prediction disabled.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_genericctls Generic CTLs
+ *
+ * These macros are used with the \c opus_decoder_ctl and
+ * \c opus_encoder_ctl calls to generate a particular
+ * request.
+ *
+ * When called on an \c OpusDecoder they apply to that
+ * particular decoder instance. When called on an
+ * \c OpusEncoder they apply to the corresponding setting
+ * on that encoder instance, if present.
+ *
+ * Some usage examples:
+ *
+ * @code
+ * int ret;
+ * opus_int32 pitch;
+ * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch));
+ * if (ret == OPUS_OK) return ret;
+ *
+ * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);
+ * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE);
+ *
+ * opus_int32 enc_bw, dec_bw;
+ * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw));
+ * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw));
+ * if (enc_bw != dec_bw) {
+ * printf("packet bandwidth mismatch!\n");
+ * }
+ * @endcode
+ *
+ * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls
+ * @{
+ */
+
+/** Resets the codec state to be equivalent to a freshly initialized state.
+ * This should be called when switching streams in order to prevent
+ * the back to back decoding from giving different results from
+ * one at a time decoding.
+ * @hideinitializer */
+#define OPUS_RESET_STATE 4028
+
+/** Gets the final state of the codec's entropy coder.
+ * This is used for testing purposes,
+ * The encoder and decoder state should be identical after coding a payload
+ * (assuming no data corruption or software bugs)
+ *
+ * @param[out] x <tt>opus_uint32 *</tt>: Entropy coder state
+ *
+ * @hideinitializer */
+#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x)
+
+/** Gets the encoder's configured bandpass or the decoder's last bandpass.
+ * @see OPUS_SET_BANDWIDTH
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
+ * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the sampling rate the encoder or decoder was initialized with.
+ * This simply returns the <code>Fs</code> value passed to opus_encoder_init()
+ * or opus_decoder_init().
+ * @param[out] x <tt>opus_int32 *</tt>: Sampling rate of encoder or decoder.
+ * @hideinitializer
+ */
+#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_decoderctls Decoder related CTLs
+ * @see opus_genericctls, opus_encoderctls, opus_decoder
+ * @{
+ */
+
+/** Configures decoder gain adjustment.
+ * Scales the decoded output by a factor specified in Q8 dB units.
+ * This has a maximum range of -32768 to 32767 inclusive, and returns
+ * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment.
+ * This setting survives decoder reset.
+ *
+ * gain = pow(10, x/(20.0*256))
+ *
+ * @param[in] x <tt>opus_int32</tt>: Amount to scale PCM signal by in Q8 dB units.
+ * @hideinitializer */
+#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x)
+/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN
+ *
+ * @param[out] x <tt>opus_int32 *</tt>: Amount to scale PCM signal by in Q8 dB units.
+ * @hideinitializer */
+#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the duration (in samples) of the last packet successfully decoded or concealed.
+ * @param[out] x <tt>opus_int32 *</tt>: Number of samples (at current sampling rate).
+ * @hideinitializer */
+#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the pitch of the last decoded frame, if available.
+ * This can be used for any post-processing algorithm requiring the use of pitch,
+ * e.g. time stretching/shortening. If the last frame was not voiced, or if the
+ * pitch was not coded in the frame, then zero is returned.
+ *
+ * This CTL is only implemented for decoder instances.
+ *
+ * @param[out] x <tt>opus_int32 *</tt>: pitch period at 48 kHz (or 0 if not available)
+ *
+ * @hideinitializer */
+#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_libinfo Opus library information functions
+ * @{
+ */
+
+/** Converts an opus error code into a human readable string.
+ *
+ * @param[in] error <tt>int</tt>: Error number
+ * @returns Error string
+ */
+OPUS_EXPORT const char *opus_strerror(int error);
+
+/** Gets the libopus version string.
+ *
+ * Applications may look for the substring "-fixed" in the version string to
+ * determine whether they have a fixed-point or floating-point build at
+ * runtime.
+ *
+ * @returns Version string
+ */
+OPUS_EXPORT const char *opus_get_version_string(void);
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_DEFINES_H */
diff --git a/external/opus-1.1.4/include/opus_multistream.h b/external/opus-1.1.4/include/opus_multistream.h
new file mode 100644
index 0000000..3622e00
--- /dev/null
+++ b/external/opus-1.1.4/include/opus_multistream.h
@@ -0,0 +1,660 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+/**
+ * @file opus_multistream.h
+ * @brief Opus reference implementation multistream API
+ */
+
+#ifndef OPUS_MULTISTREAM_H
+#define OPUS_MULTISTREAM_H
+
+#include "opus.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @cond OPUS_INTERNAL_DOC */
+
+/** Macros to trigger compilation errors when the wrong types are provided to a
+ * CTL. */
+/**@{*/
+#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr)))
+#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr)))
+/**@}*/
+
+/** These are the actual encoder and decoder CTL ID numbers.
+ * They should not be used directly by applications.
+ * In general, SETs should be even and GETs should be odd.*/
+/**@{*/
+#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120
+#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122
+/**@}*/
+
+/** @endcond */
+
+/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs
+ *
+ * These are convenience macros that are specific to the
+ * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl()
+ * interface.
+ * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and
+ * @ref opus_decoderctls may be applied to a multistream encoder or decoder as
+ * well.
+ * In addition, you may retrieve the encoder or decoder state for an specific
+ * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or
+ * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually.
+ */
+/**@{*/
+
+/** Gets the encoder state for an individual stream of a multistream encoder.
+ * @param[in] x <tt>opus_int32</tt>: The index of the stream whose encoder you
+ * wish to retrieve.
+ * This must be non-negative and less than
+ * the <code>streams</code> parameter used
+ * to initialize the encoder.
+ * @param[out] y <tt>OpusEncoder**</tt>: Returns a pointer to the given
+ * encoder state.
+ * @retval OPUS_BAD_ARG The index of the requested stream was out of range.
+ * @hideinitializer
+ */
+#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y)
+
+/** Gets the decoder state for an individual stream of a multistream decoder.
+ * @param[in] x <tt>opus_int32</tt>: The index of the stream whose decoder you
+ * wish to retrieve.
+ * This must be non-negative and less than
+ * the <code>streams</code> parameter used
+ * to initialize the decoder.
+ * @param[out] y <tt>OpusDecoder**</tt>: Returns a pointer to the given
+ * decoder state.
+ * @retval OPUS_BAD_ARG The index of the requested stream was out of range.
+ * @hideinitializer
+ */
+#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y)
+
+/**@}*/
+
+/** @defgroup opus_multistream Opus Multistream API
+ * @{
+ *
+ * The multistream API allows individual Opus streams to be combined into a
+ * single packet, enabling support for up to 255 channels. Unlike an
+ * elementary Opus stream, the encoder and decoder must negotiate the channel
+ * configuration before the decoder can successfully interpret the data in the
+ * packets produced by the encoder. Some basic information, such as packet
+ * duration, can be computed without any special negotiation.
+ *
+ * The format for multistream Opus packets is defined in
+ * <a href="https://tools.ietf.org/html/rfc7845">RFC 7845</a>
+ * and is based on the self-delimited Opus framing described in Appendix B of
+ * <a href="https://tools.ietf.org/html/rfc6716">RFC 6716</a>.
+ * Normal Opus packets are just a degenerate case of multistream Opus packets,
+ * and can be encoded or decoded with the multistream API by setting
+ * <code>streams</code> to <code>1</code> when initializing the encoder or
+ * decoder.
+ *
+ * Multistream Opus streams can contain up to 255 elementary Opus streams.
+ * These may be either "uncoupled" or "coupled", indicating that the decoder
+ * is configured to decode them to either 1 or 2 channels, respectively.
+ * The streams are ordered so that all coupled streams appear at the
+ * beginning.
+ *
+ * A <code>mapping</code> table defines which decoded channel <code>i</code>
+ * should be used for each input/output (I/O) channel <code>j</code>. This table is
+ * typically provided as an unsigned char array.
+ * Let <code>i = mapping[j]</code> be the index for I/O channel <code>j</code>.
+ * If <code>i < 2*coupled_streams</code>, then I/O channel <code>j</code> is
+ * encoded as the left channel of stream <code>(i/2)</code> if <code>i</code>
+ * is even, or as the right channel of stream <code>(i/2)</code> if
+ * <code>i</code> is odd. Otherwise, I/O channel <code>j</code> is encoded as
+ * mono in stream <code>(i - coupled_streams)</code>, unless it has the special
+ * value 255, in which case it is omitted from the encoding entirely (the
+ * decoder will reproduce it as silence). Each value <code>i</code> must either
+ * be the special value 255 or be less than <code>streams + coupled_streams</code>.
+ *
+ * The output channels specified by the encoder
+ * should use the
+ * <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
+ * channel ordering</a>. A decoder may wish to apply an additional permutation
+ * to the mapping the encoder used to achieve a different output channel
+ * order (e.g. for outputing in WAV order).
+ *
+ * Each multistream packet contains an Opus packet for each stream, and all of
+ * the Opus packets in a single multistream packet must have the same
+ * duration. Therefore the duration of a multistream packet can be extracted
+ * from the TOC sequence of the first stream, which is located at the
+ * beginning of the packet, just like an elementary Opus stream:
+ *
+ * @code
+ * int nb_samples;
+ * int nb_frames;
+ * nb_frames = opus_packet_get_nb_frames(data, len);
+ * if (nb_frames < 1)
+ * return nb_frames;
+ * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames;
+ * @endcode
+ *
+ * The general encoding and decoding process proceeds exactly the same as in
+ * the normal @ref opus_encoder and @ref opus_decoder APIs.
+ * See their documentation for an overview of how to use the corresponding
+ * multistream functions.
+ */
+
+/** Opus multistream encoder state.
+ * This contains the complete state of a multistream Opus encoder.
+ * It is position independent and can be freely copied.
+ * @see opus_multistream_encoder_create
+ * @see opus_multistream_encoder_init
+ */
+typedef struct OpusMSEncoder OpusMSEncoder;
+
+/** Opus multistream decoder state.
+ * This contains the complete state of a multistream Opus decoder.
+ * It is position independent and can be freely copied.
+ * @see opus_multistream_decoder_create
+ * @see opus_multistream_decoder_init
+ */
+typedef struct OpusMSDecoder OpusMSDecoder;
+
+/**\name Multistream encoder functions */
+/**@{*/
+
+/** Gets the size of an OpusMSEncoder structure.
+ * @param streams <tt>int</tt>: The total number of streams to encode from the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than 255.
+ * @returns The size in bytes on success, or a negative error code
+ * (see @ref opus_errorcodes) on error.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size(
+ int streams,
+ int coupled_streams
+);
+
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_surround_encoder_get_size(
+ int channels,
+ int mapping_family
+);
+
+
+/** Allocates and initializes a multistream encoder state.
+ * Call opus_multistream_encoder_destroy() to release
+ * this object when finished.
+ * @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels <tt>int</tt>: Number of channels in the input signal.
+ * This must be at most 255.
+ * It may be greater than the number of
+ * coded channels (<code>streams +
+ * coupled_streams</code>).
+ * @param streams <tt>int</tt>: The total number of streams to encode from the
+ * input.
+ * This must be no more than the number of channels.
+ * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than the number of input channels.
+ * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+ * encoded channels to input channels, as described in
+ * @ref opus_multistream. As an extra constraint, the
+ * multistream encoder does not allow encoding coupled
+ * streams for which one channel is unused since this
+ * is never a good idea.
+ * @param application <tt>int</tt>: The target encoder application.
+ * This must be one of the following:
+ * <dl>
+ * <dt>#OPUS_APPLICATION_VOIP</dt>
+ * <dd>Process signal for improved speech intelligibility.</dd>
+ * <dt>#OPUS_APPLICATION_AUDIO</dt>
+ * <dd>Favor faithfulness to the original input.</dd>
+ * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+ * <dd>Configure the minimum possible coding delay by disabling certain modes
+ * of operation.</dd>
+ * </dl>
+ * @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error
+ * code (see @ref opus_errorcodes) on
+ * failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+/** Initialize a previously allocated multistream encoder state.
+ * The memory pointed to by \a st must be at least the size returned by
+ * opus_multistream_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of
+ * malloc.
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @see opus_multistream_encoder_create
+ * @see opus_multistream_encoder_get_size
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to initialize.
+ * @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels <tt>int</tt>: Number of channels in the input signal.
+ * This must be at most 255.
+ * It may be greater than the number of
+ * coded channels (<code>streams +
+ * coupled_streams</code>).
+ * @param streams <tt>int</tt>: The total number of streams to encode from the
+ * input.
+ * This must be no more than the number of channels.
+ * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than the number of input channels.
+ * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+ * encoded channels to input channels, as described in
+ * @ref opus_multistream. As an extra constraint, the
+ * multistream encoder does not allow encoding coupled
+ * streams for which one channel is unused since this
+ * is never a good idea.
+ * @param application <tt>int</tt>: The target encoder application.
+ * This must be one of the following:
+ * <dl>
+ * <dt>#OPUS_APPLICATION_VOIP</dt>
+ * <dd>Process signal for improved speech intelligibility.</dd>
+ * <dt>#OPUS_APPLICATION_AUDIO</dt>
+ * <dd>Favor faithfulness to the original input.</dd>
+ * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+ * <dd>Configure the minimum possible coding delay by disabling certain modes
+ * of operation.</dd>
+ * </dl>
+ * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
+ * on failure.
+ */
+OPUS_EXPORT int opus_multistream_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+OPUS_EXPORT int opus_multistream_surround_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+/** Encodes a multistream Opus frame.
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.
+ * @param[in] pcm <tt>const opus_int16*</tt>: The input signal as interleaved
+ * samples.
+ * This must contain
+ * <code>frame_size*channels</code>
+ * samples.
+ * @param frame_size <tt>int</tt>: Number of samples per channel in the input
+ * signal.
+ * This must be an Opus frame size for the
+ * encoder's sampling rate.
+ * For example, at 48 kHz the permitted values
+ * are 120, 240, 480, 960, 1920, and 2880.
+ * Passing in a duration of less than 10 ms
+ * (480 samples at 48 kHz) will prevent the
+ * encoder from using the LPC or hybrid modes.
+ * @param[out] data <tt>unsigned char*</tt>: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode(
+ OpusMSEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes a multistream Opus frame from floating point input.
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.
+ * @param[in] pcm <tt>const float*</tt>: The input signal as interleaved
+ * samples with a normal range of
+ * +/-1.0.
+ * Samples with a range beyond +/-1.0
+ * are supported but will be clipped by
+ * decoders using the integer API and
+ * should only be used if it is known
+ * that the far end supports extended
+ * dynamic range.
+ * This must contain
+ * <code>frame_size*channels</code>
+ * samples.
+ * @param frame_size <tt>int</tt>: Number of samples per channel in the input
+ * signal.
+ * This must be an Opus frame size for the
+ * encoder's sampling rate.
+ * For example, at 48 kHz the permitted values
+ * are 120, 240, 480, 960, 1920, and 2880.
+ * Passing in a duration of less than 10 ms
+ * (480 samples at 48 kHz) will prevent the
+ * encoder from using the LPC or hybrid modes.
+ * @param[out] data <tt>unsigned char*</tt>: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float(
+ OpusMSEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Frees an <code>OpusMSEncoder</code> allocated by
+ * opus_multistream_encoder_create().
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to be freed.
+ */
+OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st);
+
+/** Perform a CTL function on a multistream Opus encoder.
+ *
+ * Generally the request and subsequent arguments are generated by a
+ * convenience macro.
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls,
+ * @ref opus_encoderctls, or @ref opus_multistream_ctls.
+ * @see opus_genericctls
+ * @see opus_encoderctls
+ * @see opus_multistream_ctls
+ */
+OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/**@}*/
+
+/**\name Multistream decoder functions */
+/**@{*/
+
+/** Gets the size of an <code>OpusMSDecoder</code> structure.
+ * @param streams <tt>int</tt>: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams <tt>int</tt>: Number streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than 255.
+ * @returns The size in bytes on success, or a negative error code
+ * (see @ref opus_errorcodes) on error.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size(
+ int streams,
+ int coupled_streams
+);
+
+/** Allocates and initializes a multistream decoder state.
+ * Call opus_multistream_decoder_destroy() to release
+ * this object when finished.
+ * @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels <tt>int</tt>: Number of channels to output.
+ * This must be at most 255.
+ * It may be different from the number of coded
+ * channels (<code>streams +
+ * coupled_streams</code>).
+ * @param streams <tt>int</tt>: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than 255.
+ * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+ * coded channels to output channels, as described in
+ * @ref opus_multistream.
+ * @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error
+ * code (see @ref opus_errorcodes) on
+ * failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+/** Intialize a previously allocated decoder state object.
+ * The memory pointed to by \a st must be at least the size returned by
+ * opus_multistream_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of
+ * malloc.
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @see opus_multistream_decoder_create
+ * @see opus_multistream_deocder_get_size
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to initialize.
+ * @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels <tt>int</tt>: Number of channels to output.
+ * This must be at most 255.
+ * It may be different from the number of coded
+ * channels (<code>streams +
+ * coupled_streams</code>).
+ * @param streams <tt>int</tt>: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than 255.
+ * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+ * coded channels to output channels, as described in
+ * @ref opus_multistream.
+ * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
+ * on failure.
+ */
+OPUS_EXPORT int opus_multistream_decoder_init(
+ OpusMSDecoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+/** Decode a multistream Opus packet.
+ * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.
+ * @param[in] data <tt>const unsigned char*</tt>: Input payload.
+ * Use a <code>NULL</code>
+ * pointer to indicate packet
+ * loss.
+ * @param len <tt>opus_int32</tt>: Number of bytes in payload.
+ * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved
+ * samples.
+ * This must contain room for
+ * <code>frame_size*channels</code>
+ * samples.
+ * @param frame_size <tt>int</tt>: The number of samples per channel of
+ * available space in \a pcm.
+ * If this is less than the maximum packet duration
+ * (120 ms; 5760 for 48kHz), this function will not be capable
+ * of decoding some packets. In the case of PLC (data==NULL)
+ * or FEC (decode_fec=1), then frame_size needs to be exactly
+ * the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the
+ * next incoming packet. For the PLC and FEC cases, frame_size
+ * <b>must</b> be a multiple of 2.5 ms.
+ * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
+ * forward error correction data be decoded.
+ * If no such data is available, the frame is
+ * decoded as if it were lost.
+ * @returns Number of samples decoded on success or a negative error code
+ * (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ opus_int16 *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode a multistream Opus packet with floating point output.
+ * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.
+ * @param[in] data <tt>const unsigned char*</tt>: Input payload.
+ * Use a <code>NULL</code>
+ * pointer to indicate packet
+ * loss.
+ * @param len <tt>opus_int32</tt>: Number of bytes in payload.
+ * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved
+ * samples.
+ * This must contain room for
+ * <code>frame_size*channels</code>
+ * samples.
+ * @param frame_size <tt>int</tt>: The number of samples per channel of
+ * available space in \a pcm.
+ * If this is less than the maximum packet duration
+ * (120 ms; 5760 for 48kHz), this function will not be capable
+ * of decoding some packets. In the case of PLC (data==NULL)
+ * or FEC (decode_fec=1), then frame_size needs to be exactly
+ * the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the
+ * next incoming packet. For the PLC and FEC cases, frame_size
+ * <b>must</b> be a multiple of 2.5 ms.
+ * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
+ * forward error correction data be decoded.
+ * If no such data is available, the frame is
+ * decoded as if it were lost.
+ * @returns Number of samples decoded on success or a negative error code
+ * (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ float *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on a multistream Opus decoder.
+ *
+ * Generally the request and subsequent arguments are generated by a
+ * convenience macro.
+ * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls,
+ * @ref opus_decoderctls, or @ref opus_multistream_ctls.
+ * @see opus_genericctls
+ * @see opus_decoderctls
+ * @see opus_multistream_ctls
+ */
+OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/** Frees an <code>OpusMSDecoder</code> allocated by
+ * opus_multistream_decoder_create().
+ * @param st <tt>OpusMSDecoder</tt>: Multistream decoder state to be freed.
+ */
+OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st);
+
+/**@}*/
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_MULTISTREAM_H */
diff --git a/external/opus-1.1.4/include/opus_types.h b/external/opus-1.1.4/include/opus_types.h
new file mode 100644
index 0000000..b28e03a
--- /dev/null
+++ b/external/opus-1.1.4/include/opus_types.h
@@ -0,0 +1,159 @@
+/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */
+/* Modified by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+/* opus_types.h based on ogg_types.h from libogg */
+
+/**
+ @file opus_types.h
+ @brief Opus reference implementation types
+*/
+#ifndef OPUS_TYPES_H
+#define OPUS_TYPES_H
+
+/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */
+#if (defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H))
+#include <stdint.h>
+
+ typedef int16_t opus_int16;
+ typedef uint16_t opus_uint16;
+ typedef int32_t opus_int32;
+ typedef uint32_t opus_uint32;
+#elif defined(_WIN32)
+
+# if defined(__CYGWIN__)
+# include <_G_config.h>
+ typedef _G_int32_t opus_int32;
+ typedef _G_uint32_t opus_uint32;
+ typedef _G_int16 opus_int16;
+ typedef _G_uint16 opus_uint16;
+# elif defined(__MINGW32__)
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+# elif defined(__MWERKS__)
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+# else
+ /* MSVC/Borland */
+ typedef __int32 opus_int32;
+ typedef unsigned __int32 opus_uint32;
+ typedef __int16 opus_int16;
+ typedef unsigned __int16 opus_uint16;
+# endif
+
+#elif defined(__MACOS__)
+
+# include <sys/types.h>
+ typedef SInt16 opus_int16;
+ typedef UInt16 opus_uint16;
+ typedef SInt32 opus_int32;
+ typedef UInt32 opus_uint32;
+
+#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
+
+# include <sys/types.h>
+ typedef int16_t opus_int16;
+ typedef u_int16_t opus_uint16;
+ typedef int32_t opus_int32;
+ typedef u_int32_t opus_uint32;
+
+#elif defined(__BEOS__)
+
+ /* Be */
+# include <inttypes.h>
+ typedef int16 opus_int16;
+ typedef u_int16 opus_uint16;
+ typedef int32_t opus_int32;
+ typedef u_int32_t opus_uint32;
+
+#elif defined (__EMX__)
+
+ /* OS/2 GCC */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined (DJGPP)
+
+ /* DJGPP */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined(R5900)
+
+ /* PS2 EE */
+ typedef int opus_int32;
+ typedef unsigned opus_uint32;
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+
+#elif defined(__SYMBIAN32__)
+
+ /* Symbian GCC */
+ typedef signed short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef signed int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
+
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef long opus_int32;
+ typedef unsigned long opus_uint32;
+
+#elif defined(CONFIG_TI_C6X)
+
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#else
+
+ /* Give up, take a reasonable guess */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#endif
+
+#define opus_int int /* used for counters etc; at least 16 bits */
+#define opus_int64 long long
+#define opus_int8 signed char
+
+#define opus_uint unsigned int /* used for counters etc; at least 16 bits */
+#define opus_uint64 unsigned long long
+#define opus_uint8 unsigned char
+
+#endif /* OPUS_TYPES_H */
diff --git a/external/opus-1.1.4/silk/A2NLSF.c b/external/opus-1.1.4/silk/A2NLSF.c
new file mode 100644
index 0000000..b6e9e5f
--- /dev/null
+++ b/external/opus-1.1.4/silk/A2NLSF.c
@@ -0,0 +1,267 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+/* Conversion between prediction filter coefficients and NLSFs */
+/* Requires the order to be an even number */
+/* A piecewise linear approximation maps LSF <-> cos(LSF) */
+/* Therefore the result is not accurate NLSFs, but the two */
+/* functions are accurate inverses of each other */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "tables.h"
+
+/* Number of binary divisions, when not in low complexity mode */
+#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */
+#define MAX_ITERATIONS_A2NLSF_FIX 30
+
+/* Helper function for A2NLSF(..) */
+/* Transforms polynomials from cos(n*f) to cos(f)^n */
+static OPUS_INLINE void silk_A2NLSF_trans_poly(
+ opus_int32 *p, /* I/O Polynomial */
+ const opus_int dd /* I Polynomial order (= filter order / 2 ) */
+)
+{
+ opus_int k, n;
+
+ for( k = 2; k <= dd; k++ ) {
+ for( n = dd; n > k; n-- ) {
+ p[ n - 2 ] -= p[ n ];
+ }
+ p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 );
+ }
+}
+/* Helper function for A2NLSF(..) */
+/* Polynomial evaluation */
+static OPUS_INLINE opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16 */
+ opus_int32 *p, /* I Polynomial, Q16 */
+ const opus_int32 x, /* I Evaluation point, Q12 */
+ const opus_int dd /* I Order */
+)
+{
+ opus_int n;
+ opus_int32 x_Q16, y32;
+
+ y32 = p[ dd ]; /* Q16 */
+ x_Q16 = silk_LSHIFT( x, 4 );
+
+ if ( opus_likely( 8 == dd ) )
+ {
+ y32 = silk_SMLAWW( p[ 7 ], y32, x_Q16 );
+ y32 = silk_SMLAWW( p[ 6 ], y32, x_Q16 );
+ y32 = silk_SMLAWW( p[ 5 ], y32, x_Q16 );
+ y32 = silk_SMLAWW( p[ 4 ], y32, x_Q16 );
+ y32 = silk_SMLAWW( p[ 3 ], y32, x_Q16 );
+ y32 = silk_SMLAWW( p[ 2 ], y32, x_Q16 );
+ y32 = silk_SMLAWW( p[ 1 ], y32, x_Q16 );
+ y32 = silk_SMLAWW( p[ 0 ], y32, x_Q16 );
+ }
+ else
+ {
+ for( n = dd - 1; n >= 0; n-- ) {
+ y32 = silk_SMLAWW( p[ n ], y32, x_Q16 ); /* Q16 */
+ }
+ }
+ return y32;
+}
+
+static OPUS_INLINE void silk_A2NLSF_init(
+ const opus_int32 *a_Q16,
+ opus_int32 *P,
+ opus_int32 *Q,
+ const opus_int dd
+)
+{
+ opus_int k;
+
+ /* Convert filter coefs to even and odd polynomials */
+ P[dd] = silk_LSHIFT( 1, 16 );
+ Q[dd] = silk_LSHIFT( 1, 16 );
+ for( k = 0; k < dd; k++ ) {
+ P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; /* Q16 */
+ Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; /* Q16 */
+ }
+
+ /* Divide out zeros as we have that for even filter orders, */
+ /* z = 1 is always a root in Q, and */
+ /* z = -1 is always a root in P */
+ for( k = dd; k > 0; k-- ) {
+ P[ k - 1 ] -= P[ k ];
+ Q[ k - 1 ] += Q[ k ];
+ }
+
+ /* Transform polynomials from cos(n*f) to cos(f)^n */
+ silk_A2NLSF_trans_poly( P, dd );
+ silk_A2NLSF_trans_poly( Q, dd );
+}
+
+/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */
+/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */
+void silk_A2NLSF(
+ opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */
+ opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */
+ const opus_int d /* I Filter order (must be even) */
+)
+{
+ opus_int i, k, m, dd, root_ix, ffrac;
+ opus_int32 xlo, xhi, xmid;
+ opus_int32 ylo, yhi, ymid, thr;
+ opus_int32 nom, den;
+ opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ];
+ opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
+ opus_int32 *PQ[ 2 ];
+ opus_int32 *p;
+
+ /* Store pointers to array */
+ PQ[ 0 ] = P;
+ PQ[ 1 ] = Q;
+
+ dd = silk_RSHIFT( d, 1 );
+
+ silk_A2NLSF_init( a_Q16, P, Q, dd );
+
+ /* Find roots, alternating between P and Q */
+ p = P; /* Pointer to polynomial */
+
+ xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
+ ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+
+ if( ylo < 0 ) {
+ /* Set the first NLSF to zero and move on to the next */
+ NLSF[ 0 ] = 0;
+ p = Q; /* Pointer to polynomial */
+ ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+ root_ix = 1; /* Index of current root */
+ } else {
+ root_ix = 0; /* Index of current root */
+ }
+ k = 1; /* Loop counter */
+ i = 0; /* Counter for bandwidth expansions applied */
+ thr = 0;
+ while( 1 ) {
+ /* Evaluate polynomial */
+ xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */
+ yhi = silk_A2NLSF_eval_poly( p, xhi, dd );
+
+ /* Detect zero crossing */
+ if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) {
+ if( yhi == 0 ) {
+ /* If the root lies exactly at the end of the current */
+ /* interval, look for the next root in the next interval */
+ thr = 1;
+ } else {
+ thr = 0;
+ }
+ /* Binary division */
+ ffrac = -256;
+ for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) {
+ /* Evaluate polynomial */
+ xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 );
+ ymid = silk_A2NLSF_eval_poly( p, xmid, dd );
+
+ /* Detect zero crossing */
+ if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) {
+ /* Reduce frequency */
+ xhi = xmid;
+ yhi = ymid;
+ } else {
+ /* Increase frequency */
+ xlo = xmid;
+ ylo = ymid;
+ ffrac = silk_ADD_RSHIFT( ffrac, 128, m );
+ }
+ }
+
+ /* Interpolate */
+ if( silk_abs( ylo ) < 65536 ) {
+ /* Avoid dividing by zero */
+ den = ylo - yhi;
+ nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 );
+ if( den != 0 ) {
+ ffrac += silk_DIV32( nom, den );
+ }
+ } else {
+ /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */
+ ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) );
+ }
+ NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX );
+
+ silk_assert( NLSF[ root_ix ] >= 0 );
+
+ root_ix++; /* Next root */
+ if( root_ix >= d ) {
+ /* Found all roots */
+ break;
+ }
+ /* Alternate pointer to polynomial */
+ p = PQ[ root_ix & 1 ];
+
+ /* Evaluate polynomial */
+ xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/
+ ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 );
+ } else {
+ /* Increment loop counter */
+ k++;
+ xlo = xhi;
+ ylo = yhi;
+ thr = 0;
+
+ if( k > LSF_COS_TAB_SZ_FIX ) {
+ i++;
+ if( i > MAX_ITERATIONS_A2NLSF_FIX ) {
+ /* Set NLSFs to white spectrum and exit */
+ NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 );
+ for( k = 1; k < d; k++ ) {
+ NLSF[ k ] = (opus_int16)silk_SMULBB( k + 1, NLSF[ 0 ] );
+ }
+ return;
+ }
+
+ /* Error: Apply progressively more bandwidth expansion and run again */
+ silk_bwexpander_32( a_Q16, d, 65536 - silk_SMULBB( 10 + i, i ) ); /* 10_Q16 = 0.00015*/
+
+ silk_A2NLSF_init( a_Q16, P, Q, dd );
+ p = P; /* Pointer to polynomial */
+ xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
+ ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+ if( ylo < 0 ) {
+ /* Set the first NLSF to zero and move on to the next */
+ NLSF[ 0 ] = 0;
+ p = Q; /* Pointer to polynomial */
+ ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+ root_ix = 1; /* Index of current root */
+ } else {
+ root_ix = 0; /* Index of current root */
+ }
+ k = 1; /* Reset loop counter */
+ }
+ }
+ }
+}
diff --git a/external/opus-1.1.4/silk/API.h b/external/opus-1.1.4/silk/API.h
new file mode 100644
index 0000000..0131acb
--- /dev/null
+++ b/external/opus-1.1.4/silk/API.h
@@ -0,0 +1,134 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_API_H
+#define SILK_API_H
+
+#include "control.h"
+#include "typedef.h"
+#include "errors.h"
+#include "entenc.h"
+#include "entdec.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define SILK_MAX_FRAMES_PER_PACKET 3
+
+/* Struct for TOC (Table of Contents) */
+typedef struct {
+ opus_int VADFlag; /* Voice activity for packet */
+ opus_int VADFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* Voice activity for each frame in packet */
+ opus_int inbandFECFlag; /* Flag indicating if packet contains in-band FEC */
+} silk_TOC_struct;
+
+/****************************************/
+/* Encoder functions */
+/****************************************/
+
+/***********************************************/
+/* Get size in bytes of the Silk encoder state */
+/***********************************************/
+opus_int silk_Get_Encoder_Size( /* O Returns error code */
+ opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */
+);
+
+/*************************/
+/* Init or reset encoder */
+/*************************/
+opus_int silk_InitEncoder( /* O Returns error code */
+ void *encState, /* I/O State */
+ int arch, /* I Run-time architecture */
+ silk_EncControlStruct *encStatus /* O Encoder Status */
+);
+
+/**************************/
+/* Encode frame with Silk */
+/**************************/
+/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */
+/* encControl->payloadSize_ms is set to */
+opus_int silk_Encode( /* O Returns error code */
+ void *encState, /* I/O State */
+ silk_EncControlStruct *encControl, /* I Control status */
+ const opus_int16 *samplesIn, /* I Speech sample input vector */
+ opus_int nSamplesIn, /* I Number of samples in input vector */
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
+ const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */
+);
+
+/****************************************/
+/* Decoder functions */
+/****************************************/
+
+/***********************************************/
+/* Get size in bytes of the Silk decoder state */
+/***********************************************/
+opus_int silk_Get_Decoder_Size( /* O Returns error code */
+ opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */
+);
+
+/*************************/
+/* Init or Reset decoder */
+/*************************/
+opus_int silk_InitDecoder( /* O Returns error code */
+ void *decState /* I/O State */
+);
+
+/******************/
+/* Decode a frame */
+/******************/
+opus_int silk_Decode( /* O Returns error code */
+ void* decState, /* I/O State */
+ silk_DecControlStruct* decControl, /* I/O Control Structure */
+ opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
+ opus_int newPacketFlag, /* I Indicates first decoder call for this packet */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 *samplesOut, /* O Decoded output speech vector */
+ opus_int32 *nSamplesOut, /* O Number of samples decoded */
+ int arch /* I Run-time architecture */
+);
+
+#if 0
+/**************************************/
+/* Get table of contents for a packet */
+/**************************************/
+opus_int silk_get_TOC(
+ const opus_uint8 *payload, /* I Payload data */
+ const opus_int nBytesIn, /* I Number of input bytes */
+ const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */
+ silk_TOC_struct *Silk_TOC /* O Type of content */
+);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/silk/CMakeLists.txt b/external/opus-1.1.4/silk/CMakeLists.txt
new file mode 100644
index 0000000..932ffb4
--- /dev/null
+++ b/external/opus-1.1.4/silk/CMakeLists.txt
@@ -0,0 +1,113 @@
+# CMakeLists.txt in silk
+
+SET(SILK_SRCS
+A2NLSF.c
+ana_filt_bank_1.c
+biquad_alt.c
+bwexpander.c
+bwexpander_32.c
+check_control_input.c
+CNG.c
+code_signs.c
+control_audio_bandwidth.c
+control_codec.c
+control_SNR.c
+debug.c
+decoder_set_fs.c
+decode_core.c
+decode_frame.c
+decode_indices.c
+decode_parameters.c
+decode_pitch.c
+decode_pulses.c
+dec_API.c
+encode_indices.c
+encode_pulses.c
+enc_API.c
+gain_quant.c
+HP_variable_cutoff.c
+init_decoder.c
+init_encoder.c
+inner_prod_aligned.c
+interpolate.c
+lin2log.c
+log2lin.c
+LPC_analysis_filter.c
+LPC_inv_pred_gain.c
+LP_variable_cutoff.c
+NLSF2A.c
+NLSF_decode.c
+NLSF_del_dec_quant.c
+NLSF_encode.c
+NLSF_stabilize.c
+NLSF_unpack.c
+NLSF_VQ.c
+NLSF_VQ_weights_laroia.c
+NSQ.c
+NSQ_del_dec.c
+pitch_est_tables.c
+PLC.c
+process_NLSFs.c
+quant_LTP_gains.c
+resampler.c
+resampler_down2.c
+resampler_down2_3.c
+resampler_private_AR2.c
+resampler_private_down_FIR.c
+resampler_private_IIR_FIR.c
+resampler_private_up2_HQ.c
+resampler_rom.c
+shell_coder.c
+sigm_Q15.c
+sort.c
+stereo_decode_pred.c
+stereo_encode_pred.c
+stereo_find_predictor.c
+stereo_LR_to_MS.c
+stereo_MS_to_LR.c
+stereo_quant_pred.c
+sum_sqr_shift.c
+tables_gain.c
+tables_LTP.c
+tables_NLSF_CB_NB_MB.c
+tables_NLSF_CB_WB.c
+tables_other.c
+tables_pitch_lag.c
+tables_pulses_per_block.c
+table_LSF_cos.c
+VAD.c
+VQ_WMat_EC.c
+)
+
+SET(SILK_HEADERS
+API.h
+control.h
+debug.h
+define.h
+errors.h
+Inlines.h
+MacroCount.h
+MacroDebug.h
+macros.h
+main.h
+pitch_est_defines.h
+PLC.h
+resampler_private.h
+resampler_rom.h
+resampler_structs.h
+SigProc_FIX.h
+structs.h
+tables.h
+tuning_parameters.h
+typedef.h
+)
+
+INCLUDE_DIRECTORIES(
+ ${OPUS_INCLUDES_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../celt
+ ${CMAKE_CURRENT_SOURCE_DIR}/float
+ ${CMAKE_CURRENT_SOURCE_DIR}/fixed
+ )
+
+set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11" )
diff --git a/external/opus-1.1.4/silk/CNG.c b/external/opus-1.1.4/silk/CNG.c
new file mode 100644
index 0000000..8443ad6
--- /dev/null
+++ b/external/opus-1.1.4/silk/CNG.c
@@ -0,0 +1,184 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/* Generates excitation for CNG LPC synthesis */
+static OPUS_INLINE void silk_CNG_exc(
+ opus_int32 exc_Q14[], /* O CNG excitation signal Q10 */
+ opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */
+ opus_int length, /* I Length */
+ opus_int32 *rand_seed /* I/O Seed to random index generator */
+)
+{
+ opus_int32 seed;
+ opus_int i, idx, exc_mask;
+
+ exc_mask = CNG_BUF_MASK_MAX;
+ while( exc_mask > length ) {
+ exc_mask = silk_RSHIFT( exc_mask, 1 );
+ }
+
+ seed = *rand_seed;
+ for( i = 0; i < length; i++ ) {
+ seed = silk_RAND( seed );
+ idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask );
+ silk_assert( idx >= 0 );
+ silk_assert( idx <= CNG_BUF_MASK_MAX );
+ exc_Q14[ i ] = exc_buf_Q14[ idx ];
+ }
+ *rand_seed = seed;
+}
+
+void silk_CNG_Reset(
+ silk_decoder_state *psDec /* I/O Decoder state */
+)
+{
+ opus_int i, NLSF_step_Q15, NLSF_acc_Q15;
+
+ NLSF_step_Q15 = silk_DIV32_16( silk_int16_MAX, psDec->LPC_order + 1 );
+ NLSF_acc_Q15 = 0;
+ for( i = 0; i < psDec->LPC_order; i++ ) {
+ NLSF_acc_Q15 += NLSF_step_Q15;
+ psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15;
+ }
+ psDec->sCNG.CNG_smth_Gain_Q16 = 0;
+ psDec->sCNG.rand_seed = 3176576;
+}
+
+/* Updates CNG estimate, and applies the CNG when packet was lost */
+void silk_CNG(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[], /* I/O Signal */
+ opus_int length /* I Length of residual */
+)
+{
+ opus_int i, subfr;
+ opus_int32 LPC_pred_Q10, max_Gain_Q16, gain_Q16, gain_Q10;
+ opus_int16 A_Q12[ MAX_LPC_ORDER ];
+ silk_CNG_struct *psCNG = &psDec->sCNG;
+ SAVE_STACK;
+
+ if( psDec->fs_kHz != psCNG->fs_kHz ) {
+ /* Reset state */
+ silk_CNG_Reset( psDec );
+
+ psCNG->fs_kHz = psDec->fs_kHz;
+ }
+ if( psDec->lossCnt == 0 && psDec->prevSignalType == TYPE_NO_VOICE_ACTIVITY ) {
+ /* Update CNG parameters */
+
+ /* Smoothing of LSF's */
+ for( i = 0; i < psDec->LPC_order; i++ ) {
+ psCNG->CNG_smth_NLSF_Q15[ i ] += silk_SMULWB( (opus_int32)psDec->prevNLSF_Q15[ i ] - (opus_int32)psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 );
+ }
+ /* Find the subframe with the highest gain */
+ max_Gain_Q16 = 0;
+ subfr = 0;
+ for( i = 0; i < psDec->nb_subfr; i++ ) {
+ if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) {
+ max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ];
+ subfr = i;
+ }
+ }
+ /* Update CNG excitation buffer with excitation from this subframe */
+ silk_memmove( &psCNG->CNG_exc_buf_Q14[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q14, ( psDec->nb_subfr - 1 ) * psDec->subfr_length * sizeof( opus_int32 ) );
+ silk_memcpy( psCNG->CNG_exc_buf_Q14, &psDec->exc_Q14[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( opus_int32 ) );
+
+ /* Smooth gains */
+ for( i = 0; i < psDec->nb_subfr; i++ ) {
+ psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 );
+ }
+ }
+
+ /* Add CNG when packet is lost or during DTX */
+ if( psDec->lossCnt ) {
+ VARDECL( opus_int32, CNG_sig_Q14 );
+ ALLOC( CNG_sig_Q14, length + MAX_LPC_ORDER, opus_int32 );
+
+ /* Generate CNG excitation */
+ gain_Q16 = silk_SMULWW( psDec->sPLC.randScale_Q14, psDec->sPLC.prevGain_Q16[1] );
+ if( gain_Q16 >= (1 << 21) || psCNG->CNG_smth_Gain_Q16 > (1 << 23) ) {
+ gain_Q16 = silk_SMULTT( gain_Q16, gain_Q16 );
+ gain_Q16 = silk_SUB_LSHIFT32(silk_SMULTT( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 );
+ gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 16 );
+ } else {
+ gain_Q16 = silk_SMULWW( gain_Q16, gain_Q16 );
+ gain_Q16 = silk_SUB_LSHIFT32(silk_SMULWW( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 );
+ gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 8 );
+ }
+ gain_Q10 = silk_RSHIFT( gain_Q16, 6 );
+
+ silk_CNG_exc( CNG_sig_Q14 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, length, &psCNG->rand_seed );
+
+ /* Convert CNG NLSF to filter representation */
+ silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order );
+
+ /* Generate CNG signal, by synthesis filtering */
+ silk_memcpy( CNG_sig_Q14, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+ for( i = 0; i < length; i++ ) {
+ silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
+ if( psDec->LPC_order == 16 ) {
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] );
+ }
+
+ /* Update states */
+ CNG_sig_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q14[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 );
+
+ /* Scale with Gain and add to input signal */
+ frame[ i ] = (opus_int16)silk_ADD_SAT16( frame[ i ], silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( CNG_sig_Q14[ MAX_LPC_ORDER + i ], gain_Q10 ), 8 ) ) );
+
+ }
+ silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q14[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
+ } else {
+ silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) );
+ }
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/HP_variable_cutoff.c b/external/opus-1.1.4/silk/HP_variable_cutoff.c
new file mode 100644
index 0000000..bbe10f0
--- /dev/null
+++ b/external/opus-1.1.4/silk/HP_variable_cutoff.c
@@ -0,0 +1,77 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef FIXED_POINT
+#include "main_FIX.h"
+#else
+#include "main_FLP.h"
+#endif
+#include "tuning_parameters.h"
+
+/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
+void silk_HP_variable_cutoff(
+ silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */
+)
+{
+ opus_int quality_Q15;
+ opus_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7;
+ silk_encoder_state *psEncC1 = &state_Fxx[ 0 ].sCmn;
+
+ /* Adaptive cutoff frequency: estimate low end of pitch frequency range */
+ if( psEncC1->prevSignalType == TYPE_VOICED ) {
+ /* difference, in log domain */
+ pitch_freq_Hz_Q16 = silk_DIV32_16( silk_LSHIFT( silk_MUL( psEncC1->fs_kHz, 1000 ), 16 ), psEncC1->prevLag );
+ pitch_freq_log_Q7 = silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 );
+
+ /* adjustment based on quality */
+ quality_Q15 = psEncC1->input_quality_bands_Q15[ 0 ];
+ pitch_freq_log_Q7 = silk_SMLAWB( pitch_freq_log_Q7, silk_SMULWB( silk_LSHIFT( -quality_Q15, 2 ), quality_Q15 ),
+ pitch_freq_log_Q7 - ( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ) ) );
+
+ /* delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; */
+ delta_freq_Q7 = pitch_freq_log_Q7 - silk_RSHIFT( psEncC1->variable_HP_smth1_Q15, 8 );
+ if( delta_freq_Q7 < 0 ) {
+ /* less smoothing for decreasing pitch frequency, to track something close to the minimum */
+ delta_freq_Q7 = silk_MUL( delta_freq_Q7, 3 );
+ }
+
+ /* limit delta, to reduce impact of outliers in pitch estimation */
+ delta_freq_Q7 = silk_LIMIT_32( delta_freq_Q7, -SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) );
+
+ /* update smoother */
+ psEncC1->variable_HP_smth1_Q15 = silk_SMLAWB( psEncC1->variable_HP_smth1_Q15,
+ silk_SMULBB( psEncC1->speech_activity_Q8, delta_freq_Q7 ), SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) );
+
+ /* limit frequency range */
+ psEncC1->variable_HP_smth1_Q15 = silk_LIMIT_32( psEncC1->variable_HP_smth1_Q15,
+ silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ),
+ silk_LSHIFT( silk_lin2log( VARIABLE_HP_MAX_CUTOFF_HZ ), 8 ) );
+ }
+}
diff --git a/external/opus-1.1.4/silk/Inlines.h b/external/opus-1.1.4/silk/Inlines.h
new file mode 100644
index 0000000..ec986cd
--- /dev/null
+++ b/external/opus-1.1.4/silk/Inlines.h
@@ -0,0 +1,188 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+/*! \file silk_Inlines.h
+ * \brief silk_Inlines.h defines OPUS_INLINE signal processing functions.
+ */
+
+#ifndef SILK_FIX_INLINES_H
+#define SILK_FIX_INLINES_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* count leading zeros of opus_int64 */
+static OPUS_INLINE opus_int32 silk_CLZ64( opus_int64 in )
+{
+ opus_int32 in_upper;
+
+ in_upper = (opus_int32)silk_RSHIFT64(in, 32);
+ if (in_upper == 0) {
+ /* Search in the lower 32 bits */
+ return 32 + silk_CLZ32( (opus_int32) in );
+ } else {
+ /* Search in the upper 32 bits */
+ return silk_CLZ32( in_upper );
+ }
+}
+
+/* get number of leading zeros and fractional part (the bits right after the leading one */
+static OPUS_INLINE void silk_CLZ_FRAC(
+ opus_int32 in, /* I input */
+ opus_int32 *lz, /* O number of leading zeros */
+ opus_int32 *frac_Q7 /* O the 7 bits right after the leading one */
+)
+{
+ opus_int32 lzeros = silk_CLZ32(in);
+
+ * lz = lzeros;
+ * frac_Q7 = silk_ROR32(in, 24 - lzeros) & 0x7f;
+}
+
+/* Approximation of square root */
+/* Accuracy: < +/- 10% for output values > 15 */
+/* < +/- 2.5% for output values > 120 */
+static OPUS_INLINE opus_int32 silk_SQRT_APPROX( opus_int32 x )
+{
+ opus_int32 y, lz, frac_Q7;
+
+ if( x <= 0 ) {
+ return 0;
+ }
+
+ silk_CLZ_FRAC(x, &lz, &frac_Q7);
+
+ if( lz & 1 ) {
+ y = 32768;
+ } else {
+ y = 46214; /* 46214 = sqrt(2) * 32768 */
+ }
+
+ /* get scaling right */
+ y >>= silk_RSHIFT(lz, 1);
+
+ /* increment using fractional part of input */
+ y = silk_SMLAWB(y, y, silk_SMULBB(213, frac_Q7));
+
+ return y;
+}
+
+/* Divide two int32 values and return result as int32 in a given Q-domain */
+static OPUS_INLINE opus_int32 silk_DIV32_varQ( /* O returns a good approximation of "(a32 << Qres) / b32" */
+ const opus_int32 a32, /* I numerator (Q0) */
+ const opus_int32 b32, /* I denominator (Q0) */
+ const opus_int Qres /* I Q-domain of result (>= 0) */
+)
+{
+ opus_int a_headrm, b_headrm, lshift;
+ opus_int32 b32_inv, a32_nrm, b32_nrm, result;
+
+ silk_assert( b32 != 0 );
+ silk_assert( Qres >= 0 );
+
+ /* Compute number of bits head room and normalize inputs */
+ a_headrm = silk_CLZ32( silk_abs(a32) ) - 1;
+ a32_nrm = silk_LSHIFT(a32, a_headrm); /* Q: a_headrm */
+ b_headrm = silk_CLZ32( silk_abs(b32) ) - 1;
+ b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */
+
+ /* Inverse of b32, with 14 bits of precision */
+ b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */
+
+ /* First approximation */
+ result = silk_SMULWB(a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */
+
+ /* Compute residual by subtracting product of denominator and first approximation */
+ /* It's OK to overflow because the final value of a32_nrm should always be small */
+ a32_nrm = silk_SUB32_ovflw(a32_nrm, silk_LSHIFT_ovflw( silk_SMMUL(b32_nrm, result), 3 )); /* Q: a_headrm */
+
+ /* Refinement */
+ result = silk_SMLAWB(result, a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */
+
+ /* Convert to Qres domain */
+ lshift = 29 + a_headrm - b_headrm - Qres;
+ if( lshift < 0 ) {
+ return silk_LSHIFT_SAT32(result, -lshift);
+ } else {
+ if( lshift < 32){
+ return silk_RSHIFT(result, lshift);
+ } else {
+ /* Avoid undefined result */
+ return 0;
+ }
+ }
+}
+
+/* Invert int32 value and return result as int32 in a given Q-domain */
+static OPUS_INLINE opus_int32 silk_INVERSE32_varQ( /* O returns a good approximation of "(1 << Qres) / b32" */
+ const opus_int32 b32, /* I denominator (Q0) */
+ const opus_int Qres /* I Q-domain of result (> 0) */
+)
+{
+ opus_int b_headrm, lshift;
+ opus_int32 b32_inv, b32_nrm, err_Q32, result;
+
+ silk_assert( b32 != 0 );
+ silk_assert( Qres > 0 );
+
+ /* Compute number of bits head room and normalize input */
+ b_headrm = silk_CLZ32( silk_abs(b32) ) - 1;
+ b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */
+
+ /* Inverse of b32, with 14 bits of precision */
+ b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */
+
+ /* First approximation */
+ result = silk_LSHIFT(b32_inv, 16); /* Q: 61 - b_headrm */
+
+ /* Compute residual by subtracting product of denominator and first approximation from one */
+ err_Q32 = silk_LSHIFT( ((opus_int32)1<<29) - silk_SMULWB(b32_nrm, b32_inv), 3 ); /* Q32 */
+
+ /* Refinement */
+ result = silk_SMLAWW(result, err_Q32, b32_inv); /* Q: 61 - b_headrm */
+
+ /* Convert to Qres domain */
+ lshift = 61 - b_headrm - Qres;
+ if( lshift <= 0 ) {
+ return silk_LSHIFT_SAT32(result, -lshift);
+ } else {
+ if( lshift < 32){
+ return silk_RSHIFT(result, lshift);
+ }else{
+ /* Avoid undefined result */
+ return 0;
+ }
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_FIX_INLINES_H */
diff --git a/external/opus-1.1.4/silk/LPC_analysis_filter.c b/external/opus-1.1.4/silk/LPC_analysis_filter.c
new file mode 100644
index 0000000..2090667
--- /dev/null
+++ b/external/opus-1.1.4/silk/LPC_analysis_filter.c
@@ -0,0 +1,108 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "celt_lpc.h"
+
+/*******************************************/
+/* LPC analysis filter */
+/* NB! State is kept internally and the */
+/* filter always starts with zero state */
+/* first d output samples are set to zero */
+/*******************************************/
+
+void silk_LPC_analysis_filter(
+ opus_int16 *out, /* O Output signal */
+ const opus_int16 *in, /* I Input signal */
+ const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */
+ const opus_int32 len, /* I Signal length */
+ const opus_int32 d, /* I Filter order */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int j;
+#ifdef FIXED_POINT
+ opus_int16 mem[SILK_MAX_ORDER_LPC];
+ opus_int16 num[SILK_MAX_ORDER_LPC];
+#else
+ int ix;
+ opus_int32 out32_Q12, out32;
+ const opus_int16 *in_ptr;
+#endif
+
+ silk_assert( d >= 6 );
+ silk_assert( (d & 1) == 0 );
+ silk_assert( d <= len );
+
+#ifdef FIXED_POINT
+ silk_assert( d <= SILK_MAX_ORDER_LPC );
+ for ( j = 0; j < d; j++ ) {
+ num[ j ] = -B[ j ];
+ }
+ for (j=0;j<d;j++) {
+ mem[ j ] = in[ d - j - 1 ];
+ }
+ celt_fir( in + d, num, out + d, len - d, d, mem, arch );
+ for ( j = 0; j < d; j++ ) {
+ out[ j ] = 0;
+ }
+#else
+ (void)arch;
+ for( ix = d; ix < len; ix++ ) {
+ in_ptr = &in[ ix - 1 ];
+
+ out32_Q12 = silk_SMULBB( in_ptr[ 0 ], B[ 0 ] );
+ /* Allowing wrap around so that two wraps can cancel each other. The rare
+ cases where the result wraps around can only be triggered by invalid streams*/
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -1 ], B[ 1 ] );
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -2 ], B[ 2 ] );
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -3 ], B[ 3 ] );
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -4 ], B[ 4 ] );
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -5 ], B[ 5 ] );
+ for( j = 6; j < d; j += 2 ) {
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j ], B[ j ] );
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j - 1 ], B[ j + 1 ] );
+ }
+
+ /* Subtract prediction */
+ out32_Q12 = silk_SUB32_ovflw( silk_LSHIFT( (opus_int32)in_ptr[ 1 ], 12 ), out32_Q12 );
+
+ /* Scale to Q0 */
+ out32 = silk_RSHIFT_ROUND( out32_Q12, 12 );
+
+ /* Saturate output */
+ out[ ix ] = (opus_int16)silk_SAT16( out32 );
+ }
+
+ /* Set first d output samples to zero */
+ silk_memset( out, 0, d * sizeof( opus_int16 ) );
+#endif
+}
diff --git a/external/opus-1.1.4/silk/LPC_inv_pred_gain.c b/external/opus-1.1.4/silk/LPC_inv_pred_gain.c
new file mode 100644
index 0000000..4af89aa
--- /dev/null
+++ b/external/opus-1.1.4/silk/LPC_inv_pred_gain.c
@@ -0,0 +1,154 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+#define QA 24
+#define A_LIMIT SILK_FIX_CONST( 0.99975, QA )
+
+#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q)))
+
+/* Compute inverse of LPC prediction gain, and */
+/* test if LPC coefficients are stable (all poles within unit circle) */
+static opus_int32 LPC_inverse_pred_gain_QA( /* O Returns inverse prediction gain in energy domain, Q30 */
+ opus_int32 A_QA[ 2 ][ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */
+ const opus_int order /* I Prediction order */
+)
+{
+ opus_int k, n, mult2Q;
+ opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA;
+ opus_int32 *Aold_QA, *Anew_QA;
+
+ Anew_QA = A_QA[ order & 1 ];
+
+ invGain_Q30 = (opus_int32)1 << 30;
+ for( k = order - 1; k > 0; k-- ) {
+ /* Check for stability */
+ if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) {
+ return 0;
+ }
+
+ /* Set RC equal to negated AR coef */
+ rc_Q31 = -silk_LSHIFT( Anew_QA[ k ], 31 - QA );
+
+ /* rc_mult1_Q30 range: [ 1 : 2^30 ] */
+ rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+ silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */
+ silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) );
+
+ /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */
+ mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) );
+ rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 );
+
+ /* Update inverse gain */
+ /* invGain_Q30 range: [ 0 : 2^30 ] */
+ invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 );
+ silk_assert( invGain_Q30 >= 0 );
+ silk_assert( invGain_Q30 <= ( 1 << 30 ) );
+
+ /* Swap pointers */
+ Aold_QA = Anew_QA;
+ Anew_QA = A_QA[ k & 1 ];
+
+ /* Update AR coefficient */
+ for( n = 0; n < k; n++ ) {
+ tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 );
+ Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q );
+ }
+ }
+
+ /* Check for stability */
+ if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) {
+ return 0;
+ }
+
+ /* Set RC equal to negated AR coef */
+ rc_Q31 = -silk_LSHIFT( Anew_QA[ 0 ], 31 - QA );
+
+ /* Range: [ 1 : 2^30 ] */
+ rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+
+ /* Update inverse gain */
+ /* Range: [ 0 : 2^30 ] */
+ invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 );
+ silk_assert( invGain_Q30 >= 0 );
+ silk_assert( invGain_Q30 <= 1<<30 );
+
+ return invGain_Q30;
+}
+
+/* For input in Q12 domain */
+opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */
+ const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */
+ const opus_int order /* I Prediction order */
+)
+{
+ opus_int k;
+ opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
+ opus_int32 *Anew_QA;
+ opus_int32 DC_resp = 0;
+
+ Anew_QA = Atmp_QA[ order & 1 ];
+
+ /* Increase Q domain of the AR coefficients */
+ for( k = 0; k < order; k++ ) {
+ DC_resp += (opus_int32)A_Q12[ k ];
+ Anew_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 );
+ }
+ /* If the DC is unstable, we don't even need to do the full calculations */
+ if( DC_resp >= 4096 ) {
+ return 0;
+ }
+ return LPC_inverse_pred_gain_QA( Atmp_QA, order );
+}
+
+#ifdef FIXED_POINT
+
+/* For input in Q24 domain */
+opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */
+ const opus_int32 *A_Q24, /* I Prediction coefficients [order] */
+ const opus_int order /* I Prediction order */
+)
+{
+ opus_int k;
+ opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
+ opus_int32 *Anew_QA;
+
+ Anew_QA = Atmp_QA[ order & 1 ];
+
+ /* Increase Q domain of the AR coefficients */
+ for( k = 0; k < order; k++ ) {
+ Anew_QA[ k ] = silk_RSHIFT32( A_Q24[ k ], 24 - QA );
+ }
+
+ return LPC_inverse_pred_gain_QA( Atmp_QA, order );
+}
+#endif
diff --git a/external/opus-1.1.4/silk/LP_variable_cutoff.c b/external/opus-1.1.4/silk/LP_variable_cutoff.c
new file mode 100644
index 0000000..f639e1f
--- /dev/null
+++ b/external/opus-1.1.4/silk/LP_variable_cutoff.c
@@ -0,0 +1,135 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ Elliptic/Cauer filters designed with 0.1 dB passband ripple,
+ 80 dB minimum stopband attenuation, and
+ [0.95 : 0.15 : 0.35] normalized cut off frequencies.
+*/
+
+#include "main.h"
+
+/* Helper function, interpolates the filter taps */
+static OPUS_INLINE void silk_LP_interpolate_filter_taps(
+ opus_int32 B_Q28[ TRANSITION_NB ],
+ opus_int32 A_Q28[ TRANSITION_NA ],
+ const opus_int ind,
+ const opus_int32 fac_Q16
+)
+{
+ opus_int nb, na;
+
+ if( ind < TRANSITION_INT_NUM - 1 ) {
+ if( fac_Q16 > 0 ) {
+ if( fac_Q16 < 32768 ) { /* fac_Q16 is in range of a 16-bit int */
+ /* Piece-wise linear interpolation of B and A */
+ for( nb = 0; nb < TRANSITION_NB; nb++ ) {
+ B_Q28[ nb ] = silk_SMLAWB(
+ silk_Transition_LP_B_Q28[ ind ][ nb ],
+ silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] -
+ silk_Transition_LP_B_Q28[ ind ][ nb ],
+ fac_Q16 );
+ }
+ for( na = 0; na < TRANSITION_NA; na++ ) {
+ A_Q28[ na ] = silk_SMLAWB(
+ silk_Transition_LP_A_Q28[ ind ][ na ],
+ silk_Transition_LP_A_Q28[ ind + 1 ][ na ] -
+ silk_Transition_LP_A_Q28[ ind ][ na ],
+ fac_Q16 );
+ }
+ } else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */
+ silk_assert( fac_Q16 - ( 1 << 16 ) == silk_SAT16( fac_Q16 - ( 1 << 16 ) ) );
+ /* Piece-wise linear interpolation of B and A */
+ for( nb = 0; nb < TRANSITION_NB; nb++ ) {
+ B_Q28[ nb ] = silk_SMLAWB(
+ silk_Transition_LP_B_Q28[ ind + 1 ][ nb ],
+ silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] -
+ silk_Transition_LP_B_Q28[ ind ][ nb ],
+ fac_Q16 - ( (opus_int32)1 << 16 ) );
+ }
+ for( na = 0; na < TRANSITION_NA; na++ ) {
+ A_Q28[ na ] = silk_SMLAWB(
+ silk_Transition_LP_A_Q28[ ind + 1 ][ na ],
+ silk_Transition_LP_A_Q28[ ind + 1 ][ na ] -
+ silk_Transition_LP_A_Q28[ ind ][ na ],
+ fac_Q16 - ( (opus_int32)1 << 16 ) );
+ }
+ }
+ } else {
+ silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( opus_int32 ) );
+ silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( opus_int32 ) );
+ }
+ } else {
+ silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( opus_int32 ) );
+ silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( opus_int32 ) );
+ }
+}
+
+/* Low-pass filter with variable cutoff frequency based on */
+/* piece-wise linear interpolation between elliptic filters */
+/* Start by setting psEncC->mode <> 0; */
+/* Deactivate by setting psEncC->mode = 0; */
+void silk_LP_variable_cutoff(
+ silk_LP_state *psLP, /* I/O LP filter state */
+ opus_int16 *frame, /* I/O Low-pass filtered output signal */
+ const opus_int frame_length /* I Frame length */
+)
+{
+ opus_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0;
+ opus_int ind = 0;
+
+ silk_assert( psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES );
+
+ /* Run filter if needed */
+ if( psLP->mode != 0 ) {
+ /* Calculate index and interpolation factor for interpolation */
+#if( TRANSITION_INT_STEPS == 64 )
+ fac_Q16 = silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6 );
+#else
+ fac_Q16 = silk_DIV32_16( silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 ), TRANSITION_FRAMES );
+#endif
+ ind = silk_RSHIFT( fac_Q16, 16 );
+ fac_Q16 -= silk_LSHIFT( ind, 16 );
+
+ silk_assert( ind >= 0 );
+ silk_assert( ind < TRANSITION_INT_NUM );
+
+ /* Interpolate filter coefficients */
+ silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 );
+
+ /* Update transition frame number for next frame */
+ psLP->transition_frame_no = silk_LIMIT( psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES );
+
+ /* ARMA low-pass filtering */
+ silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 );
+ silk_biquad_alt( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length, 1);
+ }
+}
diff --git a/external/opus-1.1.4/silk/MacroCount.h b/external/opus-1.1.4/silk/MacroCount.h
new file mode 100644
index 0000000..834817d
--- /dev/null
+++ b/external/opus-1.1.4/silk/MacroCount.h
@@ -0,0 +1,718 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SIGPROCFIX_API_MACROCOUNT_H
+#define SIGPROCFIX_API_MACROCOUNT_H
+#include <stdio.h>
+
+#ifdef silk_MACRO_COUNT
+#define varDefine opus_int64 ops_count = 0;
+
+extern opus_int64 ops_count;
+
+static OPUS_INLINE opus_int64 silk_SaveCount(){
+ return(ops_count);
+}
+
+static OPUS_INLINE opus_int64 silk_SaveResetCount(){
+ opus_int64 ret;
+
+ ret = ops_count;
+ ops_count = 0;
+ return(ret);
+}
+
+static OPUS_INLINE silk_PrintCount(){
+ printf("ops_count = %d \n ", (opus_int32)ops_count);
+}
+
+#undef silk_MUL
+static OPUS_INLINE opus_int32 silk_MUL(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ ops_count += 4;
+ ret = a32 * b32;
+ return ret;
+}
+
+#undef silk_MUL_uint
+static OPUS_INLINE opus_uint32 silk_MUL_uint(opus_uint32 a32, opus_uint32 b32){
+ opus_uint32 ret;
+ ops_count += 4;
+ ret = a32 * b32;
+ return ret;
+}
+#undef silk_MLA
+static OPUS_INLINE opus_int32 silk_MLA(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 4;
+ ret = a32 + b32 * c32;
+ return ret;
+}
+
+#undef silk_MLA_uint
+static OPUS_INLINE opus_int32 silk_MLA_uint(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32){
+ opus_uint32 ret;
+ ops_count += 4;
+ ret = a32 + b32 * c32;
+ return ret;
+}
+
+#undef silk_SMULWB
+static OPUS_INLINE opus_int32 silk_SMULWB(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ ops_count += 5;
+ ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16);
+ return ret;
+}
+#undef silk_SMLAWB
+static OPUS_INLINE opus_int32 silk_SMLAWB(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 5;
+ ret = ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16)));
+ return ret;
+}
+
+#undef silk_SMULWT
+static OPUS_INLINE opus_int32 silk_SMULWT(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ ops_count += 4;
+ ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16);
+ return ret;
+}
+#undef silk_SMLAWT
+static OPUS_INLINE opus_int32 silk_SMLAWT(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 4;
+ ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16));
+ return ret;
+}
+
+#undef silk_SMULBB
+static OPUS_INLINE opus_int32 silk_SMULBB(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = (opus_int32)((opus_int16)a32) * (opus_int32)((opus_int16)b32);
+ return ret;
+}
+#undef silk_SMLABB
+static OPUS_INLINE opus_int32 silk_SMLABB(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32);
+ return ret;
+}
+
+#undef silk_SMULBT
+static OPUS_INLINE opus_int32 silk_SMULBT(opus_int32 a32, opus_int32 b32 ){
+ opus_int32 ret;
+ ops_count += 4;
+ ret = ((opus_int32)((opus_int16)a32)) * (b32 >> 16);
+ return ret;
+}
+
+#undef silk_SMLABT
+static OPUS_INLINE opus_int32 silk_SMLABT(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16);
+ return ret;
+}
+
+#undef silk_SMULTT
+static OPUS_INLINE opus_int32 silk_SMULTT(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = (a32 >> 16) * (b32 >> 16);
+ return ret;
+}
+
+#undef silk_SMLATT
+static OPUS_INLINE opus_int32 silk_SMLATT(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a32 + (b32 >> 16) * (c32 >> 16);
+ return ret;
+}
+
+
+/* multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode)*/
+#undef silk_MLA_ovflw
+#define silk_MLA_ovflw silk_MLA
+
+#undef silk_SMLABB_ovflw
+#define silk_SMLABB_ovflw silk_SMLABB
+
+#undef silk_SMLABT_ovflw
+#define silk_SMLABT_ovflw silk_SMLABT
+
+#undef silk_SMLATT_ovflw
+#define silk_SMLATT_ovflw silk_SMLATT
+
+#undef silk_SMLAWB_ovflw
+#define silk_SMLAWB_ovflw silk_SMLAWB
+
+#undef silk_SMLAWT_ovflw
+#define silk_SMLAWT_ovflw silk_SMLAWT
+
+#undef silk_SMULL
+static OPUS_INLINE opus_int64 silk_SMULL(opus_int32 a32, opus_int32 b32){
+ opus_int64 ret;
+ ops_count += 8;
+ ret = ((opus_int64)(a32) * /*(opus_int64)*/(b32));
+ return ret;
+}
+
+#undef silk_SMLAL
+static OPUS_INLINE opus_int64 silk_SMLAL(opus_int64 a64, opus_int32 b32, opus_int32 c32){
+ opus_int64 ret;
+ ops_count += 8;
+ ret = a64 + ((opus_int64)(b32) * /*(opus_int64)*/(c32));
+ return ret;
+}
+#undef silk_SMLALBB
+static OPUS_INLINE opus_int64 silk_SMLALBB(opus_int64 a64, opus_int16 b16, opus_int16 c16){
+ opus_int64 ret;
+ ops_count += 4;
+ ret = a64 + ((opus_int64)(b16) * /*(opus_int64)*/(c16));
+ return ret;
+}
+
+#undef SigProcFIX_CLZ16
+static OPUS_INLINE opus_int32 SigProcFIX_CLZ16(opus_int16 in16)
+{
+ opus_int32 out32 = 0;
+ ops_count += 10;
+ if( in16 == 0 ) {
+ return 16;
+ }
+ /* test nibbles */
+ if( in16 & 0xFF00 ) {
+ if( in16 & 0xF000 ) {
+ in16 >>= 12;
+ } else {
+ out32 += 4;
+ in16 >>= 8;
+ }
+ } else {
+ if( in16 & 0xFFF0 ) {
+ out32 += 8;
+ in16 >>= 4;
+ } else {
+ out32 += 12;
+ }
+ }
+ /* test bits and return */
+ if( in16 & 0xC ) {
+ if( in16 & 0x8 )
+ return out32 + 0;
+ else
+ return out32 + 1;
+ } else {
+ if( in16 & 0xE )
+ return out32 + 2;
+ else
+ return out32 + 3;
+ }
+}
+
+#undef SigProcFIX_CLZ32
+static OPUS_INLINE opus_int32 SigProcFIX_CLZ32(opus_int32 in32)
+{
+ /* test highest 16 bits and convert to opus_int16 */
+ ops_count += 2;
+ if( in32 & 0xFFFF0000 ) {
+ return SigProcFIX_CLZ16((opus_int16)(in32 >> 16));
+ } else {
+ return SigProcFIX_CLZ16((opus_int16)in32) + 16;
+ }
+}
+
+#undef silk_DIV32
+static OPUS_INLINE opus_int32 silk_DIV32(opus_int32 a32, opus_int32 b32){
+ ops_count += 64;
+ return a32 / b32;
+}
+
+#undef silk_DIV32_16
+static OPUS_INLINE opus_int32 silk_DIV32_16(opus_int32 a32, opus_int32 b32){
+ ops_count += 32;
+ return a32 / b32;
+}
+
+#undef silk_SAT8
+static OPUS_INLINE opus_int8 silk_SAT8(opus_int64 a){
+ opus_int8 tmp;
+ ops_count += 1;
+ tmp = (opus_int8)((a) > silk_int8_MAX ? silk_int8_MAX : \
+ ((a) < silk_int8_MIN ? silk_int8_MIN : (a)));
+ return(tmp);
+}
+
+#undef silk_SAT16
+static OPUS_INLINE opus_int16 silk_SAT16(opus_int64 a){
+ opus_int16 tmp;
+ ops_count += 1;
+ tmp = (opus_int16)((a) > silk_int16_MAX ? silk_int16_MAX : \
+ ((a) < silk_int16_MIN ? silk_int16_MIN : (a)));
+ return(tmp);
+}
+#undef silk_SAT32
+static OPUS_INLINE opus_int32 silk_SAT32(opus_int64 a){
+ opus_int32 tmp;
+ ops_count += 1;
+ tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : \
+ ((a) < silk_int32_MIN ? silk_int32_MIN : (a)));
+ return(tmp);
+}
+#undef silk_POS_SAT32
+static OPUS_INLINE opus_int32 silk_POS_SAT32(opus_int64 a){
+ opus_int32 tmp;
+ ops_count += 1;
+ tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : (a));
+ return(tmp);
+}
+
+#undef silk_ADD_POS_SAT8
+static OPUS_INLINE opus_int8 silk_ADD_POS_SAT8(opus_int64 a, opus_int64 b){
+ opus_int8 tmp;
+ ops_count += 1;
+ tmp = (opus_int8)((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b)));
+ return(tmp);
+}
+#undef silk_ADD_POS_SAT16
+static OPUS_INLINE opus_int16 silk_ADD_POS_SAT16(opus_int64 a, opus_int64 b){
+ opus_int16 tmp;
+ ops_count += 1;
+ tmp = (opus_int16)((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b)));
+ return(tmp);
+}
+
+#undef silk_ADD_POS_SAT32
+static OPUS_INLINE opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){
+ opus_int32 tmp;
+ ops_count += 1;
+ tmp = (opus_int32)((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b)));
+ return(tmp);
+}
+
+#undef silk_ADD_POS_SAT64
+static OPUS_INLINE opus_int64 silk_ADD_POS_SAT64(opus_int64 a, opus_int64 b){
+ opus_int64 tmp;
+ ops_count += 1;
+ tmp = ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b)));
+ return(tmp);
+}
+
+#undef silk_LSHIFT8
+static OPUS_INLINE opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){
+ opus_int8 ret;
+ ops_count += 1;
+ ret = a << shift;
+ return ret;
+}
+#undef silk_LSHIFT16
+static OPUS_INLINE opus_int16 silk_LSHIFT16(opus_int16 a, opus_int32 shift){
+ opus_int16 ret;
+ ops_count += 1;
+ ret = a << shift;
+ return ret;
+}
+#undef silk_LSHIFT32
+static OPUS_INLINE opus_int32 silk_LSHIFT32(opus_int32 a, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a << shift;
+ return ret;
+}
+#undef silk_LSHIFT64
+static OPUS_INLINE opus_int64 silk_LSHIFT64(opus_int64 a, opus_int shift){
+ ops_count += 1;
+ return a << shift;
+}
+
+#undef silk_LSHIFT_ovflw
+static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw(opus_int32 a, opus_int32 shift){
+ ops_count += 1;
+ return a << shift;
+}
+
+#undef silk_LSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_LSHIFT_uint(opus_uint32 a, opus_int32 shift){
+ opus_uint32 ret;
+ ops_count += 1;
+ ret = a << shift;
+ return ret;
+}
+
+#undef silk_RSHIFT8
+static OPUS_INLINE opus_int8 silk_RSHIFT8(opus_int8 a, opus_int32 shift){
+ ops_count += 1;
+ return a >> shift;
+}
+#undef silk_RSHIFT16
+static OPUS_INLINE opus_int16 silk_RSHIFT16(opus_int16 a, opus_int32 shift){
+ ops_count += 1;
+ return a >> shift;
+}
+#undef silk_RSHIFT32
+static OPUS_INLINE opus_int32 silk_RSHIFT32(opus_int32 a, opus_int32 shift){
+ ops_count += 1;
+ return a >> shift;
+}
+#undef silk_RSHIFT64
+static OPUS_INLINE opus_int64 silk_RSHIFT64(opus_int64 a, opus_int64 shift){
+ ops_count += 1;
+ return a >> shift;
+}
+
+#undef silk_RSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_RSHIFT_uint(opus_uint32 a, opus_int32 shift){
+ ops_count += 1;
+ return a >> shift;
+}
+
+#undef silk_ADD_LSHIFT
+static OPUS_INLINE opus_int32 silk_ADD_LSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a + (b << shift);
+ return ret; /* shift >= 0*/
+}
+#undef silk_ADD_LSHIFT32
+static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a + (b << shift);
+ return ret; /* shift >= 0*/
+}
+#undef silk_ADD_LSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){
+ opus_uint32 ret;
+ ops_count += 1;
+ ret = a + (b << shift);
+ return ret; /* shift >= 0*/
+}
+#undef silk_ADD_RSHIFT
+static OPUS_INLINE opus_int32 silk_ADD_RSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a + (b >> shift);
+ return ret; /* shift > 0*/
+}
+#undef silk_ADD_RSHIFT32
+static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a + (b >> shift);
+ return ret; /* shift > 0*/
+}
+#undef silk_ADD_RSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){
+ opus_uint32 ret;
+ ops_count += 1;
+ ret = a + (b >> shift);
+ return ret; /* shift > 0*/
+}
+#undef silk_SUB_LSHIFT32
+static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a - (b << shift);
+ return ret; /* shift >= 0*/
+}
+#undef silk_SUB_RSHIFT32
+static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a - (b >> shift);
+ return ret; /* shift > 0*/
+}
+
+#undef silk_RSHIFT_ROUND
+static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND(opus_int32 a, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 3;
+ ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+ return ret;
+}
+
+#undef silk_RSHIFT_ROUND64
+static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64(opus_int64 a, opus_int32 shift){
+ opus_int64 ret;
+ ops_count += 6;
+ ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+ return ret;
+}
+
+#undef silk_abs_int64
+static OPUS_INLINE opus_int64 silk_abs_int64(opus_int64 a){
+ ops_count += 1;
+ return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN*/
+}
+
+#undef silk_abs_int32
+static OPUS_INLINE opus_int32 silk_abs_int32(opus_int32 a){
+ ops_count += 1;
+ return silk_abs(a);
+}
+
+
+#undef silk_min
+static silk_min(a, b){
+ ops_count += 1;
+ return (((a) < (b)) ? (a) : (b));
+}
+#undef silk_max
+static silk_max(a, b){
+ ops_count += 1;
+ return (((a) > (b)) ? (a) : (b));
+}
+#undef silk_sign
+static silk_sign(a){
+ ops_count += 1;
+ return ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 ));
+}
+
+#undef silk_ADD16
+static OPUS_INLINE opus_int16 silk_ADD16(opus_int16 a, opus_int16 b){
+ opus_int16 ret;
+ ops_count += 1;
+ ret = a + b;
+ return ret;
+}
+
+#undef silk_ADD32
+static OPUS_INLINE opus_int32 silk_ADD32(opus_int32 a, opus_int32 b){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a + b;
+ return ret;
+}
+
+#undef silk_ADD64
+static OPUS_INLINE opus_int64 silk_ADD64(opus_int64 a, opus_int64 b){
+ opus_int64 ret;
+ ops_count += 2;
+ ret = a + b;
+ return ret;
+}
+
+#undef silk_SUB16
+static OPUS_INLINE opus_int16 silk_SUB16(opus_int16 a, opus_int16 b){
+ opus_int16 ret;
+ ops_count += 1;
+ ret = a - b;
+ return ret;
+}
+
+#undef silk_SUB32
+static OPUS_INLINE opus_int32 silk_SUB32(opus_int32 a, opus_int32 b){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a - b;
+ return ret;
+}
+
+#undef silk_SUB64
+static OPUS_INLINE opus_int64 silk_SUB64(opus_int64 a, opus_int64 b){
+ opus_int64 ret;
+ ops_count += 2;
+ ret = a - b;
+ return ret;
+}
+
+#undef silk_ADD_SAT16
+static OPUS_INLINE opus_int16 silk_ADD_SAT16( opus_int16 a16, opus_int16 b16 ) {
+ opus_int16 res;
+ /* Nb will be counted in AKP_add32 and silk_SAT16*/
+ res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) );
+ return res;
+}
+
+#undef silk_ADD_SAT32
+static OPUS_INLINE opus_int32 silk_ADD_SAT32(opus_int32 a32, opus_int32 b32){
+ opus_int32 res;
+ ops_count += 1;
+ res = ((((a32) + (b32)) & 0x80000000) == 0 ? \
+ ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \
+ ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) );
+ return res;
+}
+
+#undef silk_ADD_SAT64
+static OPUS_INLINE opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) {
+ opus_int64 res;
+ ops_count += 1;
+ res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \
+ ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \
+ ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) );
+ return res;
+}
+
+#undef silk_SUB_SAT16
+static OPUS_INLINE opus_int16 silk_SUB_SAT16( opus_int16 a16, opus_int16 b16 ) {
+ opus_int16 res;
+ silk_assert(0);
+ /* Nb will be counted in sub-macros*/
+ res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) );
+ return res;
+}
+
+#undef silk_SUB_SAT32
+static OPUS_INLINE opus_int32 silk_SUB_SAT32( opus_int32 a32, opus_int32 b32 ) {
+ opus_int32 res;
+ ops_count += 1;
+ res = ((((a32)-(b32)) & 0x80000000) == 0 ? \
+ (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \
+ ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) );
+ return res;
+}
+
+#undef silk_SUB_SAT64
+static OPUS_INLINE opus_int64 silk_SUB_SAT64( opus_int64 a64, opus_int64 b64 ) {
+ opus_int64 res;
+ ops_count += 1;
+ res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \
+ (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \
+ ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) );
+
+ return res;
+}
+
+#undef silk_SMULWW
+static OPUS_INLINE opus_int32 silk_SMULWW(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ /* Nb will be counted in sub-macros*/
+ ret = silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16));
+ return ret;
+}
+
+#undef silk_SMLAWW
+static OPUS_INLINE opus_int32 silk_SMLAWW(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ /* Nb will be counted in sub-macros*/
+ ret = silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16));
+ return ret;
+}
+
+#undef silk_min_int
+static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b)
+{
+ ops_count += 1;
+ return (((a) < (b)) ? (a) : (b));
+}
+
+#undef silk_min_16
+static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b)
+{
+ ops_count += 1;
+ return (((a) < (b)) ? (a) : (b));
+}
+#undef silk_min_32
+static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b)
+{
+ ops_count += 1;
+ return (((a) < (b)) ? (a) : (b));
+}
+#undef silk_min_64
+static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b)
+{
+ ops_count += 1;
+ return (((a) < (b)) ? (a) : (b));
+}
+
+/* silk_min() versions with typecast in the function call */
+#undef silk_max_int
+static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b)
+{
+ ops_count += 1;
+ return (((a) > (b)) ? (a) : (b));
+}
+#undef silk_max_16
+static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b)
+{
+ ops_count += 1;
+ return (((a) > (b)) ? (a) : (b));
+}
+#undef silk_max_32
+static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b)
+{
+ ops_count += 1;
+ return (((a) > (b)) ? (a) : (b));
+}
+
+#undef silk_max_64
+static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b)
+{
+ ops_count += 1;
+ return (((a) > (b)) ? (a) : (b));
+}
+
+
+#undef silk_LIMIT_int
+static OPUS_INLINE opus_int silk_LIMIT_int(opus_int a, opus_int limit1, opus_int limit2)
+{
+ opus_int ret;
+ ops_count += 6;
+
+ ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+ : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+
+ return(ret);
+}
+
+#undef silk_LIMIT_16
+static OPUS_INLINE opus_int16 silk_LIMIT_16(opus_int16 a, opus_int16 limit1, opus_int16 limit2)
+{
+ opus_int16 ret;
+ ops_count += 6;
+
+ ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+ : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+
+return(ret);
+}
+
+
+#undef silk_LIMIT_32
+static OPUS_INLINE opus_int silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2)
+{
+ opus_int32 ret;
+ ops_count += 6;
+
+ ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+ : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+ return(ret);
+}
+
+#else
+#define varDefine
+#define silk_SaveCount()
+
+#endif
+#endif
+
diff --git a/external/opus-1.1.4/silk/MacroDebug.h b/external/opus-1.1.4/silk/MacroDebug.h
new file mode 100644
index 0000000..35aedc5
--- /dev/null
+++ b/external/opus-1.1.4/silk/MacroDebug.h
@@ -0,0 +1,952 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Copyright (C) 2012 Xiph.Org Foundation
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef MACRO_DEBUG_H
+#define MACRO_DEBUG_H
+
+/* Redefine macro functions with extensive assertion in DEBUG mode.
+ As functions can't be undefined, this file can't work with SigProcFIX_MacroCount.h */
+
+#if ( defined (FIXED_DEBUG) || ( 0 && defined (_DEBUG) ) ) && !defined (silk_MACRO_COUNT)
+
+#undef silk_ADD16
+#define silk_ADD16(a,b) silk_ADD16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_ADD16_(opus_int16 a, opus_int16 b, char *file, int line){
+ opus_int16 ret;
+
+ ret = a + b;
+ if ( ret != silk_ADD_SAT16( a, b ) )
+ {
+ fprintf (stderr, "silk_ADD16(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_ADD32
+#define silk_ADD32(a,b) silk_ADD32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD32_(opus_int32 a, opus_int32 b, char *file, int line){
+ opus_int32 ret;
+
+ ret = a + b;
+ if ( ret != silk_ADD_SAT32( a, b ) )
+ {
+ fprintf (stderr, "silk_ADD32(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_ADD64
+#define silk_ADD64(a,b) silk_ADD64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_ADD64_(opus_int64 a, opus_int64 b, char *file, int line){
+ opus_int64 ret;
+
+ ret = a + b;
+ if ( ret != silk_ADD_SAT64( a, b ) )
+ {
+ fprintf (stderr, "silk_ADD64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SUB16
+#define silk_SUB16(a,b) silk_SUB16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_SUB16_(opus_int16 a, opus_int16 b, char *file, int line){
+ opus_int16 ret;
+
+ ret = a - b;
+ if ( ret != silk_SUB_SAT16( a, b ) )
+ {
+ fprintf (stderr, "silk_SUB16(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SUB32
+#define silk_SUB32(a,b) silk_SUB32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB32_(opus_int32 a, opus_int32 b, char *file, int line){
+ opus_int32 ret;
+
+ ret = a - b;
+ if ( ret != silk_SUB_SAT32( a, b ) )
+ {
+ fprintf (stderr, "silk_SUB32(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SUB64
+#define silk_SUB64(a,b) silk_SUB64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_SUB64_(opus_int64 a, opus_int64 b, char *file, int line){
+ opus_int64 ret;
+
+ ret = a - b;
+ if ( ret != silk_SUB_SAT64( a, b ) )
+ {
+ fprintf (stderr, "silk_SUB64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_ADD_SAT16
+#define silk_ADD_SAT16(a,b) silk_ADD_SAT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_ADD_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line) {
+ opus_int16 res;
+ res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) );
+ if ( res != silk_SAT16( (opus_int32)a16 + (opus_int32)b16 ) )
+ {
+ fprintf (stderr, "silk_ADD_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_ADD_SAT32
+#define silk_ADD_SAT32(a,b) silk_ADD_SAT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD_SAT32_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ opus_int32 res;
+ res = ((((opus_uint32)(a32) + (opus_uint32)(b32)) & 0x80000000) == 0 ? \
+ ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \
+ ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) );
+ if ( res != silk_SAT32( (opus_int64)a32 + (opus_int64)b32 ) )
+ {
+ fprintf (stderr, "silk_ADD_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_ADD_SAT64
+#define silk_ADD_SAT64(a,b) silk_ADD_SAT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_ADD_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line) {
+ opus_int64 res;
+ int fail = 0;
+ res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \
+ ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \
+ ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) );
+ if( res != a64 + b64 ) {
+ /* Check that we saturated to the correct extreme value */
+ if ( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) ||
+ ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ) )
+ {
+ fail = 1;
+ }
+ } else {
+ /* Saturation not necessary */
+ fail = res != a64 + b64;
+ }
+ if ( fail )
+ {
+ fprintf (stderr, "silk_ADD_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_SUB_SAT16
+#define silk_SUB_SAT16(a,b) silk_SUB_SAT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_SUB_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line ) {
+ opus_int16 res;
+ res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) );
+ if ( res != silk_SAT16( (opus_int32)a16 - (opus_int32)b16 ) )
+ {
+ fprintf (stderr, "silk_SUB_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_SUB_SAT32
+#define silk_SUB_SAT32(a,b) silk_SUB_SAT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB_SAT32_( opus_int32 a32, opus_int32 b32, char *file, int line ) {
+ opus_int32 res;
+ res = ((((opus_uint32)(a32)-(opus_uint32)(b32)) & 0x80000000) == 0 ? \
+ (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \
+ ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) );
+ if ( res != silk_SAT32( (opus_int64)a32 - (opus_int64)b32 ) )
+ {
+ fprintf (stderr, "silk_SUB_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_SUB_SAT64
+#define silk_SUB_SAT64(a,b) silk_SUB_SAT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_SUB_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line ) {
+ opus_int64 res;
+ int fail = 0;
+ res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \
+ (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \
+ ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) );
+ if( res != a64 - b64 ) {
+ /* Check that we saturated to the correct extreme value */
+ if( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) ||
+ ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ))
+ {
+ fail = 1;
+ }
+ } else {
+ /* Saturation not necessary */
+ fail = res != a64 - b64;
+ }
+ if ( fail )
+ {
+ fprintf (stderr, "silk_SUB_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_MUL
+#define silk_MUL(a,b) silk_MUL_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_MUL_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ opus_int32 ret;
+ opus_int64 ret64;
+ ret = a32 * b32;
+ ret64 = (opus_int64)a32 * (opus_int64)b32;
+ if ( (opus_int64)ret != ret64 )
+ {
+ fprintf (stderr, "silk_MUL(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_MUL_uint
+#define silk_MUL_uint(a,b) silk_MUL_uint_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_MUL_uint_(opus_uint32 a32, opus_uint32 b32, char *file, int line){
+ opus_uint32 ret;
+ ret = a32 * b32;
+ if ( (opus_uint64)ret != (opus_uint64)a32 * (opus_uint64)b32 )
+ {
+ fprintf (stderr, "silk_MUL_uint(%u, %u) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_MLA
+#define silk_MLA(a,b,c) silk_MLA_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_MLA_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = a32 + b32 * c32;
+ if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 )
+ {
+ fprintf (stderr, "silk_MLA(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_MLA_uint
+#define silk_MLA_uint(a,b,c) silk_MLA_uint_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_MLA_uint_(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32, char *file, int line){
+ opus_uint32 ret;
+ ret = a32 + b32 * c32;
+ if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 )
+ {
+ fprintf (stderr, "silk_MLA_uint(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMULWB
+#define silk_SMULWB(a,b) silk_SMULWB_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMULWB_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ opus_int32 ret;
+ ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16);
+ if ( (opus_int64)ret != ((opus_int64)a32 * (opus_int16)b32) >> 16 )
+ {
+ fprintf (stderr, "silk_SMULWB(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMLAWB
+#define silk_SMLAWB(a,b,c) silk_SMLAWB_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLAWB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = silk_ADD32( a32, silk_SMULWB( b32, c32 ) );
+ if ( silk_ADD32( a32, silk_SMULWB( b32, c32 ) ) != silk_ADD_SAT32( a32, silk_SMULWB( b32, c32 ) ) )
+ {
+ fprintf (stderr, "silk_SMLAWB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMULWT
+#define silk_SMULWT(a,b) silk_SMULWT_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMULWT_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ opus_int32 ret;
+ ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16);
+ if ( (opus_int64)ret != ((opus_int64)a32 * (b32 >> 16)) >> 16 )
+ {
+ fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMLAWT
+#define silk_SMLAWT(a,b,c) silk_SMLAWT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLAWT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16));
+ if ( (opus_int64)ret != (opus_int64)a32 + (((opus_int64)b32 * (c32 >> 16)) >> 16) )
+ {
+ fprintf (stderr, "silk_SMLAWT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMULL
+#define silk_SMULL(a,b) silk_SMULL_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_SMULL_(opus_int64 a64, opus_int64 b64, char *file, int line){
+ opus_int64 ret64;
+ int fail = 0;
+ ret64 = a64 * b64;
+ if( b64 != 0 ) {
+ fail = a64 != (ret64 / b64);
+ } else if( a64 != 0 ) {
+ fail = b64 != (ret64 / a64);
+ }
+ if ( fail )
+ {
+ fprintf (stderr, "silk_SMULL(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret64;
+}
+
+/* no checking needed for silk_SMULBB */
+#undef silk_SMLABB
+#define silk_SMLABB(a,b,c) silk_SMLABB_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLABB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32);
+ if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int16)c32 )
+ {
+ fprintf (stderr, "silk_SMLABB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+/* no checking needed for silk_SMULBT */
+#undef silk_SMLABT
+#define silk_SMLABT(a,b,c) silk_SMLABT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLABT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16);
+ if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (c32 >> 16) )
+ {
+ fprintf (stderr, "silk_SMLABT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+/* no checking needed for silk_SMULTT */
+#undef silk_SMLATT
+#define silk_SMLATT(a,b,c) silk_SMLATT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLATT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = a32 + (b32 >> 16) * (c32 >> 16);
+ if ( (opus_int64)ret != (opus_int64)a32 + (b32 >> 16) * (c32 >> 16) )
+ {
+ fprintf (stderr, "silk_SMLATT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMULWW
+#define silk_SMULWW(a,b) silk_SMULWW_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMULWW_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ opus_int32 ret, tmp1, tmp2;
+ opus_int64 ret64;
+ int fail = 0;
+
+ ret = silk_SMULWB( a32, b32 );
+ tmp1 = silk_RSHIFT_ROUND( b32, 16 );
+ tmp2 = silk_MUL( a32, tmp1 );
+
+ fail |= (opus_int64)tmp2 != (opus_int64) a32 * (opus_int64) tmp1;
+
+ tmp1 = ret;
+ ret = silk_ADD32( tmp1, tmp2 );
+ fail |= silk_ADD32( tmp1, tmp2 ) != silk_ADD_SAT32( tmp1, tmp2 );
+
+ ret64 = silk_RSHIFT64( silk_SMULL( a32, b32 ), 16 );
+ fail |= (opus_int64)ret != ret64;
+
+ if ( fail )
+ {
+ fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+
+ return ret;
+}
+
+#undef silk_SMLAWW
+#define silk_SMLAWW(a,b,c) silk_SMLAWW_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLAWW_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret, tmp;
+
+ tmp = silk_SMULWW( b32, c32 );
+ ret = silk_ADD32( a32, tmp );
+ if ( ret != silk_ADD_SAT32( a32, tmp ) )
+ {
+ fprintf (stderr, "silk_SMLAWW(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */
+#undef silk_MLA_ovflw
+#define silk_MLA_ovflw(a32, b32, c32) ((a32) + ((b32) * (c32)))
+#undef silk_SMLABB_ovflw
+#define silk_SMLABB_ovflw(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))
+
+/* no checking needed for silk_SMULL
+ no checking needed for silk_SMLAL
+ no checking needed for silk_SMLALBB
+ no checking needed for SigProcFIX_CLZ16
+ no checking needed for SigProcFIX_CLZ32*/
+
+#undef silk_DIV32
+#define silk_DIV32(a,b) silk_DIV32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_DIV32_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ if ( b32 == 0 )
+ {
+ fprintf (stderr, "silk_DIV32(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a32 / b32;
+}
+
+#undef silk_DIV32_16
+#define silk_DIV32_16(a,b) silk_DIV32_16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_DIV32_16_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ int fail = 0;
+ fail |= b32 == 0;
+ fail |= b32 > silk_int16_MAX;
+ fail |= b32 < silk_int16_MIN;
+ if ( fail )
+ {
+ fprintf (stderr, "silk_DIV32_16(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a32 / b32;
+}
+
+/* no checking needed for silk_SAT8
+ no checking needed for silk_SAT16
+ no checking needed for silk_SAT32
+ no checking needed for silk_POS_SAT32
+ no checking needed for silk_ADD_POS_SAT8
+ no checking needed for silk_ADD_POS_SAT16
+ no checking needed for silk_ADD_POS_SAT32
+ no checking needed for silk_ADD_POS_SAT64 */
+
+#undef silk_LSHIFT8
+#define silk_LSHIFT8(a,b) silk_LSHIFT8_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int8 silk_LSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){
+ opus_int8 ret;
+ int fail = 0;
+ ret = a << shift;
+ fail |= shift < 0;
+ fail |= shift >= 8;
+ fail |= (opus_int64)ret != ((opus_int64)a) << shift;
+ if ( fail )
+ {
+ fprintf (stderr, "silk_LSHIFT8(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_LSHIFT16
+#define silk_LSHIFT16(a,b) silk_LSHIFT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_LSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){
+ opus_int16 ret;
+ int fail = 0;
+ ret = a << shift;
+ fail |= shift < 0;
+ fail |= shift >= 16;
+ fail |= (opus_int64)ret != ((opus_int64)a) << shift;
+ if ( fail )
+ {
+ fprintf (stderr, "silk_LSHIFT16(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_LSHIFT32
+#define silk_LSHIFT32(a,b) silk_LSHIFT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_LSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ int fail = 0;
+ ret = a << shift;
+ fail |= shift < 0;
+ fail |= shift >= 32;
+ fail |= (opus_int64)ret != ((opus_int64)a) << shift;
+ if ( fail )
+ {
+ fprintf (stderr, "silk_LSHIFT32(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_LSHIFT64
+#define silk_LSHIFT64(a,b) silk_LSHIFT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_LSHIFT64_(opus_int64 a, opus_int shift, char *file, int line){
+ opus_int64 ret;
+ int fail = 0;
+ ret = a << shift;
+ fail |= shift < 0;
+ fail |= shift >= 64;
+ fail |= (ret>>shift) != ((opus_int64)a);
+ if ( fail )
+ {
+ fprintf (stderr, "silk_LSHIFT64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_LSHIFT_ovflw
+#define silk_LSHIFT_ovflw(a,b) silk_LSHIFT_ovflw_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw_(opus_int32 a, opus_int32 shift, char *file, int line){
+ if ( (shift < 0) || (shift >= 32) ) /* no check for overflow */
+ {
+ fprintf (stderr, "silk_LSHIFT_ovflw(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a << shift;
+}
+
+#undef silk_LSHIFT_uint
+#define silk_LSHIFT_uint(a,b) silk_LSHIFT_uint_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_LSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){
+ opus_uint32 ret;
+ ret = a << shift;
+ if ( (shift < 0) || ((opus_int64)ret != ((opus_int64)a) << shift))
+ {
+ fprintf (stderr, "silk_LSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_RSHIFT8
+#define silk_RSHITF8(a,b) silk_RSHIFT8_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int8 silk_RSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){
+ if ( (shift < 0) || (shift>=8) )
+ {
+ fprintf (stderr, "silk_RSHITF8(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a >> shift;
+}
+
+#undef silk_RSHIFT16
+#define silk_RSHITF16(a,b) silk_RSHIFT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_RSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){
+ if ( (shift < 0) || (shift>=16) )
+ {
+ fprintf (stderr, "silk_RSHITF16(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a >> shift;
+}
+
+#undef silk_RSHIFT32
+#define silk_RSHIFT32(a,b) silk_RSHIFT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_RSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){
+ if ( (shift < 0) || (shift>=32) )
+ {
+ fprintf (stderr, "silk_RSHITF32(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a >> shift;
+}
+
+#undef silk_RSHIFT64
+#define silk_RSHIFT64(a,b) silk_RSHIFT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_RSHIFT64_(opus_int64 a, opus_int64 shift, char *file, int line){
+ if ( (shift < 0) || (shift>=64) )
+ {
+ fprintf (stderr, "silk_RSHITF64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a >> shift;
+}
+
+#undef silk_RSHIFT_uint
+#define silk_RSHIFT_uint(a,b) silk_RSHIFT_uint_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_RSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){
+ if ( (shift < 0) || (shift>32) )
+ {
+ fprintf (stderr, "silk_RSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a >> shift;
+}
+
+#undef silk_ADD_LSHIFT
+#define silk_ADD_LSHIFT(a,b,c) silk_ADD_LSHIFT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE int silk_ADD_LSHIFT_(int a, int b, int shift, char *file, int line){
+ opus_int16 ret;
+ ret = a + (b << shift);
+ if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) )
+ {
+ fprintf (stderr, "silk_ADD_LSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift >= 0 */
+}
+
+#undef silk_ADD_LSHIFT32
+#define silk_ADD_LSHIFT32(a,b,c) silk_ADD_LSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ ret = a + (b << shift);
+ if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) )
+ {
+ fprintf (stderr, "silk_ADD_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift >= 0 */
+}
+
+#undef silk_ADD_LSHIFT_uint
+#define silk_ADD_LSHIFT_uint(a,b,c) silk_ADD_LSHIFT_uint_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){
+ opus_uint32 ret;
+ ret = a + (b << shift);
+ if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) )
+ {
+ fprintf (stderr, "silk_ADD_LSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift >= 0 */
+}
+
+#undef silk_ADD_RSHIFT
+#define silk_ADD_RSHIFT(a,b,c) silk_ADD_RSHIFT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE int silk_ADD_RSHIFT_(int a, int b, int shift, char *file, int line){
+ opus_int16 ret;
+ ret = a + (b >> shift);
+ if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) )
+ {
+ fprintf (stderr, "silk_ADD_RSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift > 0 */
+}
+
+#undef silk_ADD_RSHIFT32
+#define silk_ADD_RSHIFT32(a,b,c) silk_ADD_RSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ ret = a + (b >> shift);
+ if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) )
+ {
+ fprintf (stderr, "silk_ADD_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift > 0 */
+}
+
+#undef silk_ADD_RSHIFT_uint
+#define silk_ADD_RSHIFT_uint(a,b,c) silk_ADD_RSHIFT_uint_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){
+ opus_uint32 ret;
+ ret = a + (b >> shift);
+ if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) )
+ {
+ fprintf (stderr, "silk_ADD_RSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift > 0 */
+}
+
+#undef silk_SUB_LSHIFT32
+#define silk_SUB_LSHIFT32(a,b,c) silk_SUB_LSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ ret = a - (b << shift);
+ if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) << shift)) )
+ {
+ fprintf (stderr, "silk_SUB_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift >= 0 */
+}
+
+#undef silk_SUB_RSHIFT32
+#define silk_SUB_RSHIFT32(a,b,c) silk_SUB_RSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ ret = a - (b >> shift);
+ if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) >> shift)) )
+ {
+ fprintf (stderr, "silk_SUB_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift > 0 */
+}
+
+#undef silk_RSHIFT_ROUND
+#define silk_RSHIFT_ROUND(a,b) silk_RSHIFT_ROUND_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND_(opus_int32 a, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+ /* the marco definition can't handle a shift of zero */
+ if ( (shift <= 0) || (shift>31) || ((opus_int64)ret != ((opus_int64)a + ((opus_int64)1 << (shift - 1))) >> shift) )
+ {
+ fprintf (stderr, "silk_RSHIFT_ROUND(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_RSHIFT_ROUND64
+#define silk_RSHIFT_ROUND64(a,b) silk_RSHIFT_ROUND64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64_(opus_int64 a, opus_int32 shift, char *file, int line){
+ opus_int64 ret;
+ /* the marco definition can't handle a shift of zero */
+ if ( (shift <= 0) || (shift>=64) )
+ {
+ fprintf (stderr, "silk_RSHIFT_ROUND64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+ return ret;
+}
+
+/* silk_abs is used on floats also, so doesn't work... */
+/*#undef silk_abs
+static OPUS_INLINE opus_int32 silk_abs(opus_int32 a){
+ silk_assert(a != 0x80000000);
+ return (((a) > 0) ? (a) : -(a)); // Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN
+}*/
+
+#undef silk_abs_int64
+#define silk_abs_int64(a) silk_abs_int64_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_abs_int64_(opus_int64 a, char *file, int line){
+ if ( a == silk_int64_MIN )
+ {
+ fprintf (stderr, "silk_abs_int64(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */
+}
+
+#undef silk_abs_int32
+#define silk_abs_int32(a) silk_abs_int32_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_abs_int32_(opus_int32 a, char *file, int line){
+ if ( a == silk_int32_MIN )
+ {
+ fprintf (stderr, "silk_abs_int32(%d) in %s: line %d\n", a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return silk_abs(a);
+}
+
+#undef silk_CHECK_FIT8
+#define silk_CHECK_FIT8(a) silk_CHECK_FIT8_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int8 silk_CHECK_FIT8_( opus_int64 a, char *file, int line ){
+ opus_int8 ret;
+ ret = (opus_int8)a;
+ if ( (opus_int64)ret != a )
+ {
+ fprintf (stderr, "silk_CHECK_FIT8(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return( ret );
+}
+
+#undef silk_CHECK_FIT16
+#define silk_CHECK_FIT16(a) silk_CHECK_FIT16_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_CHECK_FIT16_( opus_int64 a, char *file, int line ){
+ opus_int16 ret;
+ ret = (opus_int16)a;
+ if ( (opus_int64)ret != a )
+ {
+ fprintf (stderr, "silk_CHECK_FIT16(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return( ret );
+}
+
+#undef silk_CHECK_FIT32
+#define silk_CHECK_FIT32(a) silk_CHECK_FIT32_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_CHECK_FIT32_( opus_int64 a, char *file, int line ){
+ opus_int32 ret;
+ ret = (opus_int32)a;
+ if ( (opus_int64)ret != a )
+ {
+ fprintf (stderr, "silk_CHECK_FIT32(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return( ret );
+}
+
+/* no checking for silk_NSHIFT_MUL_32_32
+ no checking for silk_NSHIFT_MUL_16_16
+ no checking needed for silk_min
+ no checking needed for silk_max
+ no checking needed for silk_sign
+*/
+
+#endif
+#endif /* MACRO_DEBUG_H */
diff --git a/external/opus-1.1.4/silk/NLSF2A.c b/external/opus-1.1.4/silk/NLSF2A.c
new file mode 100644
index 0000000..b1c559e
--- /dev/null
+++ b/external/opus-1.1.4/silk/NLSF2A.c
@@ -0,0 +1,178 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* conversion between prediction filter coefficients and LSFs */
+/* order should be even */
+/* a piecewise linear approximation maps LSF <-> cos(LSF) */
+/* therefore the result is not accurate LSFs, but the two */
+/* functions are accurate inverses of each other */
+
+#include "SigProc_FIX.h"
+#include "tables.h"
+
+#define QA 16
+
+/* helper function for NLSF2A(..) */
+static OPUS_INLINE void silk_NLSF2A_find_poly(
+ opus_int32 *out, /* O intermediate polynomial, QA [dd+1] */
+ const opus_int32 *cLSF, /* I vector of interleaved 2*cos(LSFs), QA [d] */
+ opus_int dd /* I polynomial order (= 1/2 * filter order) */
+)
+{
+ opus_int k, n;
+ opus_int32 ftmp;
+
+ out[0] = silk_LSHIFT( 1, QA );
+ out[1] = -cLSF[0];
+ for( k = 1; k < dd; k++ ) {
+ ftmp = cLSF[2*k]; /* QA*/
+ out[k+1] = silk_LSHIFT( out[k-1], 1 ) - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[k] ), QA );
+ for( n = k; n > 1; n-- ) {
+ out[n] += out[n-2] - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[n-1] ), QA );
+ }
+ out[1] -= ftmp;
+ }
+}
+
+/* compute whitening filter coefficients from normalized line spectral frequencies */
+void silk_NLSF2A(
+ opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */
+ const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */
+ const opus_int d /* I filter order (should be even) */
+)
+{
+ /* This ordering was found to maximize quality. It improves numerical accuracy of
+ silk_NLSF2A_find_poly() compared to "standard" ordering. */
+ static const unsigned char ordering16[16] = {
+ 0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1
+ };
+ static const unsigned char ordering10[10] = {
+ 0, 9, 6, 3, 4, 5, 8, 1, 2, 7
+ };
+ const unsigned char *ordering;
+ opus_int k, i, dd;
+ opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ];
+ opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
+ opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
+ opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ];
+ opus_int32 maxabs, absval, idx=0, sc_Q16;
+
+ silk_assert( LSF_COS_TAB_SZ_FIX == 128 );
+ silk_assert( d==10||d==16 );
+
+ /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */
+ ordering = d == 16 ? ordering16 : ordering10;
+ for( k = 0; k < d; k++ ) {
+ silk_assert(NLSF[k] >= 0 );
+
+ /* f_int on a scale 0-127 (rounded down) */
+ f_int = silk_RSHIFT( NLSF[k], 15 - 7 );
+
+ /* f_frac, range: 0..255 */
+ f_frac = NLSF[k] - silk_LSHIFT( f_int, 15 - 7 );
+
+ silk_assert(f_int >= 0);
+ silk_assert(f_int < LSF_COS_TAB_SZ_FIX );
+
+ /* Read start and end value from table */
+ cos_val = silk_LSFCosTab_FIX_Q12[ f_int ]; /* Q12 */
+ delta = silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val; /* Q12, with a range of 0..200 */
+
+ /* Linear interpolation */
+ cos_LSF_QA[ordering[k]] = silk_RSHIFT_ROUND( silk_LSHIFT( cos_val, 8 ) + silk_MUL( delta, f_frac ), 20 - QA ); /* QA */
+ }
+
+ dd = silk_RSHIFT( d, 1 );
+
+ /* generate even and odd polynomials using convolution */
+ silk_NLSF2A_find_poly( P, &cos_LSF_QA[ 0 ], dd );
+ silk_NLSF2A_find_poly( Q, &cos_LSF_QA[ 1 ], dd );
+
+ /* convert even and odd polynomials to opus_int32 Q12 filter coefs */
+ for( k = 0; k < dd; k++ ) {
+ Ptmp = P[ k+1 ] + P[ k ];
+ Qtmp = Q[ k+1 ] - Q[ k ];
+
+ /* the Ptmp and Qtmp values at this stage need to fit in int32 */
+ a32_QA1[ k ] = -Qtmp - Ptmp; /* QA+1 */
+ a32_QA1[ d-k-1 ] = Qtmp - Ptmp; /* QA+1 */
+ }
+
+ /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */
+ for( i = 0; i < 10; i++ ) {
+ /* Find maximum absolute value and its index */
+ maxabs = 0;
+ for( k = 0; k < d; k++ ) {
+ absval = silk_abs( a32_QA1[k] );
+ if( absval > maxabs ) {
+ maxabs = absval;
+ idx = k;
+ }
+ }
+ maxabs = silk_RSHIFT_ROUND( maxabs, QA + 1 - 12 ); /* QA+1 -> Q12 */
+
+ if( maxabs > silk_int16_MAX ) {
+ /* Reduce magnitude of prediction coefficients */
+ maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */
+ sc_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ),
+ silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) );
+ silk_bwexpander_32( a32_QA1, d, sc_Q16 );
+ } else {
+ break;
+ }
+ }
+
+ if( i == 10 ) {
+ /* Reached the last iteration, clip the coefficients */
+ for( k = 0; k < d; k++ ) {
+ a_Q12[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ) ); /* QA+1 -> Q12 */
+ a32_QA1[ k ] = silk_LSHIFT( (opus_int32)a_Q12[ k ], QA + 1 - 12 );
+ }
+ } else {
+ for( k = 0; k < d; k++ ) {
+ a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
+ }
+ }
+
+ for( i = 0; i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) {
+ if( silk_LPC_inverse_pred_gain( a_Q12, d ) < SILK_FIX_CONST( 1.0 / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
+ /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */
+ /* on the unscaled coefficients, convert to Q12 and measure again */
+ silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) );
+ for( k = 0; k < d; k++ ) {
+ a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
+ }
+ } else {
+ break;
+ }
+ }
+}
+
diff --git a/external/opus-1.1.4/silk/NLSF_VQ.c b/external/opus-1.1.4/silk/NLSF_VQ.c
new file mode 100644
index 0000000..69b6e22
--- /dev/null
+++ b/external/opus-1.1.4/silk/NLSF_VQ.c
@@ -0,0 +1,68 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */
+void silk_NLSF_VQ(
+ opus_int32 err_Q26[], /* O Quantization errors [K] */
+ const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */
+ const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */
+ const opus_int K, /* I Number of codebook vectors */
+ const opus_int LPC_order /* I Number of LPCs */
+)
+{
+ opus_int i, m;
+ opus_int32 diff_Q15, sum_error_Q30, sum_error_Q26;
+
+ silk_assert( LPC_order <= 16 );
+ silk_assert( ( LPC_order & 1 ) == 0 );
+
+ /* Loop over codebook */
+ for( i = 0; i < K; i++ ) {
+ sum_error_Q26 = 0;
+ for( m = 0; m < LPC_order; m += 2 ) {
+ /* Compute weighted squared quantization error for index m */
+ diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/
+ sum_error_Q30 = silk_SMULBB( diff_Q15, diff_Q15 );
+
+ /* Compute weighted squared quantization error for index m + 1 */
+ diff_Q15 = silk_SUB_LSHIFT32( in_Q15[m + 1], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/
+ sum_error_Q30 = silk_SMLABB( sum_error_Q30, diff_Q15, diff_Q15 );
+
+ sum_error_Q26 = silk_ADD_RSHIFT32( sum_error_Q26, sum_error_Q30, 4 );
+
+ silk_assert( sum_error_Q26 >= 0 );
+ silk_assert( sum_error_Q30 >= 0 );
+ }
+ err_Q26[ i ] = sum_error_Q26;
+ }
+}
diff --git a/external/opus-1.1.4/silk/NLSF_VQ_weights_laroia.c b/external/opus-1.1.4/silk/NLSF_VQ_weights_laroia.c
new file mode 100644
index 0000000..04894c5
--- /dev/null
+++ b/external/opus-1.1.4/silk/NLSF_VQ_weights_laroia.c
@@ -0,0 +1,80 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "define.h"
+#include "SigProc_FIX.h"
+
+/*
+R. Laroia, N. Phamdo and N. Farvardin, "Robust and Efficient Quantization of Speech LSP
+Parameters Using Structured Vector Quantization", Proc. IEEE Int. Conf. Acoust., Speech,
+Signal Processing, pp. 641-644, 1991.
+*/
+
+/* Laroia low complexity NLSF weights */
+void silk_NLSF_VQ_weights_laroia(
+ opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */
+ const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */
+ const opus_int D /* I Input vector dimension (even) */
+)
+{
+ opus_int k;
+ opus_int32 tmp1_int, tmp2_int;
+
+ silk_assert( D > 0 );
+ silk_assert( ( D & 1 ) == 0 );
+
+ /* First value */
+ tmp1_int = silk_max_int( pNLSF_Q15[ 0 ], 1 );
+ tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int );
+ tmp2_int = silk_max_int( pNLSF_Q15[ 1 ] - pNLSF_Q15[ 0 ], 1 );
+ tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int );
+ pNLSFW_Q_OUT[ 0 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+ silk_assert( pNLSFW_Q_OUT[ 0 ] > 0 );
+
+ /* Main loop */
+ for( k = 1; k < D - 1; k += 2 ) {
+ tmp1_int = silk_max_int( pNLSF_Q15[ k + 1 ] - pNLSF_Q15[ k ], 1 );
+ tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int );
+ pNLSFW_Q_OUT[ k ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+ silk_assert( pNLSFW_Q_OUT[ k ] > 0 );
+
+ tmp2_int = silk_max_int( pNLSF_Q15[ k + 2 ] - pNLSF_Q15[ k + 1 ], 1 );
+ tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int );
+ pNLSFW_Q_OUT[ k + 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+ silk_assert( pNLSFW_Q_OUT[ k + 1 ] > 0 );
+ }
+
+ /* Last value */
+ tmp1_int = silk_max_int( ( 1 << 15 ) - pNLSF_Q15[ D - 1 ], 1 );
+ tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int );
+ pNLSFW_Q_OUT[ D - 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+ silk_assert( pNLSFW_Q_OUT[ D - 1 ] > 0 );
+}
diff --git a/external/opus-1.1.4/silk/NLSF_decode.c b/external/opus-1.1.4/silk/NLSF_decode.c
new file mode 100644
index 0000000..9f71506
--- /dev/null
+++ b/external/opus-1.1.4/silk/NLSF_decode.c
@@ -0,0 +1,101 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Predictive dequantizer for NLSF residuals */
+static OPUS_INLINE void silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */
+ opus_int16 x_Q10[], /* O Output [ order ] */
+ const opus_int8 indices[], /* I Quantization indices [ order ] */
+ const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */
+ const opus_int quant_step_size_Q16, /* I Quantization step size */
+ const opus_int16 order /* I Number of input values */
+)
+{
+ opus_int i, out_Q10, pred_Q10;
+
+ out_Q10 = 0;
+ for( i = order-1; i >= 0; i-- ) {
+ pred_Q10 = silk_RSHIFT( silk_SMULBB( out_Q10, (opus_int16)pred_coef_Q8[ i ] ), 8 );
+ out_Q10 = silk_LSHIFT( indices[ i ], 10 );
+ if( out_Q10 > 0 ) {
+ out_Q10 = silk_SUB16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ } else if( out_Q10 < 0 ) {
+ out_Q10 = silk_ADD16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ }
+ out_Q10 = silk_SMLAWB( pred_Q10, (opus_int32)out_Q10, quant_step_size_Q16 );
+ x_Q10[ i ] = out_Q10;
+ }
+}
+
+
+/***********************/
+/* NLSF vector decoder */
+/***********************/
+void silk_NLSF_decode(
+ opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */
+ opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */
+ const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */
+)
+{
+ opus_int i;
+ opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+ opus_int16 ec_ix[ MAX_LPC_ORDER ];
+ opus_int16 res_Q10[ MAX_LPC_ORDER ];
+ opus_int16 W_tmp_QW[ MAX_LPC_ORDER ];
+ opus_int32 W_tmp_Q9, NLSF_Q15_tmp;
+ const opus_uint8 *pCB_element;
+
+ /* Decode first stage */
+ pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ];
+ for( i = 0; i < psNLSF_CB->order; i++ ) {
+ pNLSF_Q15[ i ] = silk_LSHIFT( (opus_int16)pCB_element[ i ], 7 );
+ }
+
+ /* Unpack entropy table indices and predictor for current CB1 index */
+ silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[ 0 ] );
+
+ /* Predictive residual dequantizer */
+ silk_NLSF_residual_dequant( res_Q10, &NLSFIndices[ 1 ], pred_Q8, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->order );
+
+ /* Weights from codebook vector */
+ silk_NLSF_VQ_weights_laroia( W_tmp_QW, pNLSF_Q15, psNLSF_CB->order );
+
+ /* Apply inverse square-rooted weights and add to output */
+ for( i = 0; i < psNLSF_CB->order; i++ ) {
+ W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) );
+ NLSF_Q15_tmp = silk_ADD32( pNLSF_Q15[ i ], silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), W_tmp_Q9 ) );
+ pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 );
+ }
+
+ /* NLSF stabilization */
+ silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order );
+}
diff --git a/external/opus-1.1.4/silk/NLSF_del_dec_quant.c b/external/opus-1.1.4/silk/NLSF_del_dec_quant.c
new file mode 100644
index 0000000..de88fee
--- /dev/null
+++ b/external/opus-1.1.4/silk/NLSF_del_dec_quant.c
@@ -0,0 +1,217 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Delayed-decision quantizer for NLSF residuals */
+opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */
+ opus_int8 indices[], /* O Quantization indices [ order ] */
+ const opus_int16 x_Q10[], /* I Input [ order ] */
+ const opus_int16 w_Q5[], /* I Weights [ order ] */
+ const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */
+ const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */
+ const opus_uint8 ec_rates_Q5[], /* I Rates [] */
+ const opus_int quant_step_size_Q16, /* I Quantization step size */
+ const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */
+ const opus_int32 mu_Q20, /* I R/D tradeoff */
+ const opus_int16 order /* I Number of input values */
+)
+{
+ opus_int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10;
+ opus_int pred_Q10, diff_Q10, rate0_Q5, rate1_Q5;
+ opus_int16 out0_Q10, out1_Q10;
+ opus_int32 RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25;
+ opus_int ind_sort[ NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int8 ind[ NLSF_QUANT_DEL_DEC_STATES ][ MAX_LPC_ORDER ];
+ opus_int16 prev_out_Q10[ 2 * NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int32 RD_Q25[ 2 * NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int32 RD_min_Q25[ NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int32 RD_max_Q25[ NLSF_QUANT_DEL_DEC_STATES ];
+ const opus_uint8 *rates_Q5;
+
+ opus_int out0_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT];
+ opus_int out1_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT];
+
+ for (i = -NLSF_QUANT_MAX_AMPLITUDE_EXT; i <= NLSF_QUANT_MAX_AMPLITUDE_EXT-1; i++)
+ {
+ out0_Q10 = silk_LSHIFT( i, 10 );
+ out1_Q10 = silk_ADD16( out0_Q10, 1024 );
+ if( i > 0 ) {
+ out0_Q10 = silk_SUB16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ } else if( i == 0 ) {
+ out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ } else if( i == -1 ) {
+ out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ } else {
+ out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ out1_Q10 = silk_ADD16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ }
+ out0_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out0_Q10, quant_step_size_Q16 ), 16 );
+ out1_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out1_Q10, quant_step_size_Q16 ), 16 );
+ }
+
+ silk_assert( (NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES-1)) == 0 ); /* must be power of two */
+
+ nStates = 1;
+ RD_Q25[ 0 ] = 0;
+ prev_out_Q10[ 0 ] = 0;
+ for( i = order - 1; ; i-- ) {
+ rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ];
+ in_Q10 = x_Q10[ i ];
+ for( j = 0; j < nStates; j++ ) {
+ pred_Q10 = silk_RSHIFT( silk_SMULBB( (opus_int16)pred_coef_Q8[ i ], prev_out_Q10[ j ] ), 8 );
+ res_Q10 = silk_SUB16( in_Q10, pred_Q10 );
+ ind_tmp = silk_RSHIFT( silk_SMULBB( inv_quant_step_size_Q6, res_Q10 ), 16 );
+ ind_tmp = silk_LIMIT( ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT-1 );
+ ind[ j ][ i ] = (opus_int8)ind_tmp;
+
+ /* compute outputs for ind_tmp and ind_tmp + 1 */
+ out0_Q10 = out0_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ];
+ out1_Q10 = out1_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ];
+
+ out0_Q10 = silk_ADD16( out0_Q10, pred_Q10 );
+ out1_Q10 = silk_ADD16( out1_Q10, pred_Q10 );
+ prev_out_Q10[ j ] = out0_Q10;
+ prev_out_Q10[ j + nStates ] = out1_Q10;
+
+ /* compute RD for ind_tmp and ind_tmp + 1 */
+ if( ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE ) {
+ if( ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE ) {
+ rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ];
+ rate1_Q5 = 280;
+ } else {
+ rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp );
+ rate1_Q5 = silk_ADD16( rate0_Q5, 43 );
+ }
+ } else if( ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE ) {
+ if( ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE ) {
+ rate0_Q5 = 280;
+ rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ];
+ } else {
+ rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp );
+ rate1_Q5 = silk_SUB16( rate0_Q5, 43 );
+ }
+ } else {
+ rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ];
+ rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ];
+ }
+ RD_tmp_Q25 = RD_Q25[ j ];
+ diff_Q10 = silk_SUB16( in_Q10, out0_Q10 );
+ RD_Q25[ j ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate0_Q5 );
+ diff_Q10 = silk_SUB16( in_Q10, out1_Q10 );
+ RD_Q25[ j + nStates ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate1_Q5 );
+ }
+
+ if( nStates <= ( NLSF_QUANT_DEL_DEC_STATES >> 1 ) ) {
+ /* double number of states and copy */
+ for( j = 0; j < nStates; j++ ) {
+ ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1;
+ }
+ nStates = silk_LSHIFT( nStates, 1 );
+ for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ ind[ j ][ i ] = ind[ j - nStates ][ i ];
+ }
+ } else if( i > 0 ) {
+ /* sort lower and upper half of RD_Q25, pairwise */
+ for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ if( RD_Q25[ j ] > RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] ) {
+ RD_max_Q25[ j ] = RD_Q25[ j ];
+ RD_min_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ];
+ RD_Q25[ j ] = RD_min_Q25[ j ];
+ RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] = RD_max_Q25[ j ];
+ /* swap prev_out values */
+ out0_Q10 = prev_out_Q10[ j ];
+ prev_out_Q10[ j ] = prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ];
+ prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ] = out0_Q10;
+ ind_sort[ j ] = j + NLSF_QUANT_DEL_DEC_STATES;
+ } else {
+ RD_min_Q25[ j ] = RD_Q25[ j ];
+ RD_max_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ];
+ ind_sort[ j ] = j;
+ }
+ }
+ /* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary */
+ /* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */
+ while( 1 ) {
+ min_max_Q25 = silk_int32_MAX;
+ max_min_Q25 = 0;
+ ind_min_max = 0;
+ ind_max_min = 0;
+ for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ if( min_max_Q25 > RD_max_Q25[ j ] ) {
+ min_max_Q25 = RD_max_Q25[ j ];
+ ind_min_max = j;
+ }
+ if( max_min_Q25 < RD_min_Q25[ j ] ) {
+ max_min_Q25 = RD_min_Q25[ j ];
+ ind_max_min = j;
+ }
+ }
+ if( min_max_Q25 >= max_min_Q25 ) {
+ break;
+ }
+ /* copy ind_min_max to ind_max_min */
+ ind_sort[ ind_max_min ] = ind_sort[ ind_min_max ] ^ NLSF_QUANT_DEL_DEC_STATES;
+ RD_Q25[ ind_max_min ] = RD_Q25[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ];
+ prev_out_Q10[ ind_max_min ] = prev_out_Q10[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ];
+ RD_min_Q25[ ind_max_min ] = 0;
+ RD_max_Q25[ ind_min_max ] = silk_int32_MAX;
+ silk_memcpy( ind[ ind_max_min ], ind[ ind_min_max ], MAX_LPC_ORDER * sizeof( opus_int8 ) );
+ }
+ /* increment index if it comes from the upper half */
+ for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 );
+ }
+ } else { /* i == 0 */
+ break;
+ }
+ }
+
+ /* last sample: find winner, copy indices and return RD value */
+ ind_tmp = 0;
+ min_Q25 = silk_int32_MAX;
+ for( j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ if( min_Q25 > RD_Q25[ j ] ) {
+ min_Q25 = RD_Q25[ j ];
+ ind_tmp = j;
+ }
+ }
+ for( j = 0; j < order; j++ ) {
+ indices[ j ] = ind[ ind_tmp & ( NLSF_QUANT_DEL_DEC_STATES - 1 ) ][ j ];
+ silk_assert( indices[ j ] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT );
+ silk_assert( indices[ j ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT );
+ }
+ indices[ 0 ] += silk_RSHIFT( ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2 );
+ silk_assert( indices[ 0 ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT );
+ silk_assert( min_Q25 >= 0 );
+ return min_Q25;
+}
diff --git a/external/opus-1.1.4/silk/NLSF_encode.c b/external/opus-1.1.4/silk/NLSF_encode.c
new file mode 100644
index 0000000..f03c3f1
--- /dev/null
+++ b/external/opus-1.1.4/silk/NLSF_encode.c
@@ -0,0 +1,137 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/***********************/
+/* NLSF vector encoder */
+/***********************/
+opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */
+ opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */
+ opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */
+ const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */
+ const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */
+ const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */
+ const opus_int nSurvivors, /* I Max survivors after first stage */
+ const opus_int signalType /* I Signal type: 0/1/2 */
+)
+{
+ opus_int i, s, ind1, bestIndex, prob_Q8, bits_q7;
+ opus_int32 W_tmp_Q9, ret;
+ VARDECL( opus_int32, err_Q26 );
+ VARDECL( opus_int32, RD_Q25 );
+ VARDECL( opus_int, tempIndices1 );
+ VARDECL( opus_int8, tempIndices2 );
+ opus_int16 res_Q15[ MAX_LPC_ORDER ];
+ opus_int16 res_Q10[ MAX_LPC_ORDER ];
+ opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ];
+ opus_int16 W_tmp_QW[ MAX_LPC_ORDER ];
+ opus_int16 W_adj_Q5[ MAX_LPC_ORDER ];
+ opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+ opus_int16 ec_ix[ MAX_LPC_ORDER ];
+ const opus_uint8 *pCB_element, *iCDF_ptr;
+ SAVE_STACK;
+
+ silk_assert( nSurvivors <= NLSF_VQ_MAX_SURVIVORS );
+ silk_assert( signalType >= 0 && signalType <= 2 );
+ silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 );
+
+ /* NLSF stabilization */
+ silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order );
+
+ /* First stage: VQ */
+ ALLOC( err_Q26, psNLSF_CB->nVectors, opus_int32 );
+ silk_NLSF_VQ( err_Q26, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->nVectors, psNLSF_CB->order );
+
+ /* Sort the quantization errors */
+ ALLOC( tempIndices1, nSurvivors, opus_int );
+ silk_insertion_sort_increasing( err_Q26, tempIndices1, psNLSF_CB->nVectors, nSurvivors );
+
+ ALLOC( RD_Q25, nSurvivors, opus_int32 );
+ ALLOC( tempIndices2, nSurvivors * MAX_LPC_ORDER, opus_int8 );
+
+ /* Loop over survivors */
+ for( s = 0; s < nSurvivors; s++ ) {
+ ind1 = tempIndices1[ s ];
+
+ /* Residual after first stage */
+ pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ];
+ for( i = 0; i < psNLSF_CB->order; i++ ) {
+ NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 );
+ res_Q15[ i ] = pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ];
+ }
+
+ /* Weights from codebook vector */
+ silk_NLSF_VQ_weights_laroia( W_tmp_QW, NLSF_tmp_Q15, psNLSF_CB->order );
+
+ /* Apply square-rooted weights */
+ for( i = 0; i < psNLSF_CB->order; i++ ) {
+ W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) );
+ res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( res_Q15[ i ], W_tmp_Q9 ), 14 );
+ }
+
+ /* Modify input weights accordingly */
+ for( i = 0; i < psNLSF_CB->order; i++ ) {
+ W_adj_Q5[ i ] = silk_DIV32_16( silk_LSHIFT( (opus_int32)pW_QW[ i ], 5 ), W_tmp_QW[ i ] );
+ }
+
+ /* Unpack entropy table indices and predictor for current CB1 index */
+ silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 );
+
+ /* Trellis quantizer */
+ RD_Q25[ s ] = silk_NLSF_del_dec_quant( &tempIndices2[ s * MAX_LPC_ORDER ], res_Q10, W_adj_Q5, pred_Q8, ec_ix,
+ psNLSF_CB->ec_Rates_Q5, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB->order );
+
+ /* Add rate for first stage */
+ iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ];
+ if( ind1 == 0 ) {
+ prob_Q8 = 256 - iCDF_ptr[ ind1 ];
+ } else {
+ prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ];
+ }
+ bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 );
+ RD_Q25[ s ] = silk_SMLABB( RD_Q25[ s ], bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) );
+ }
+
+ /* Find the lowest rate-distortion error */
+ silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 );
+
+ NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ];
+ silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) );
+
+ /* Decode */
+ silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB );
+
+ ret = RD_Q25[ 0 ];
+ RESTORE_STACK;
+ return ret;
+}
diff --git a/external/opus-1.1.4/silk/NLSF_stabilize.c b/external/opus-1.1.4/silk/NLSF_stabilize.c
new file mode 100644
index 0000000..8f3426b
--- /dev/null
+++ b/external/opus-1.1.4/silk/NLSF_stabilize.c
@@ -0,0 +1,142 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* NLSF stabilizer: */
+/* */
+/* - Moves NLSFs further apart if they are too close */
+/* - Moves NLSFs away from borders if they are too close */
+/* - High effort to achieve a modification with minimum */
+/* Euclidean distance to input vector */
+/* - Output are sorted NLSF coefficients */
+/* */
+
+#include "SigProc_FIX.h"
+
+/* Constant Definitions */
+#define MAX_LOOPS 20
+
+/* NLSF stabilizer, for a single input data vector */
+void silk_NLSF_stabilize(
+ opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */
+ const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */
+ const opus_int L /* I Number of NLSF parameters in the input vector */
+)
+{
+ opus_int i, I=0, k, loops;
+ opus_int16 center_freq_Q15;
+ opus_int32 diff_Q15, min_diff_Q15, min_center_Q15, max_center_Q15;
+
+ /* This is necessary to ensure an output within range of a opus_int16 */
+ silk_assert( NDeltaMin_Q15[L] >= 1 );
+
+ for( loops = 0; loops < MAX_LOOPS; loops++ ) {
+ /**************************/
+ /* Find smallest distance */
+ /**************************/
+ /* First element */
+ min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0];
+ I = 0;
+ /* Middle elements */
+ for( i = 1; i <= L-1; i++ ) {
+ diff_Q15 = NLSF_Q15[i] - ( NLSF_Q15[i-1] + NDeltaMin_Q15[i] );
+ if( diff_Q15 < min_diff_Q15 ) {
+ min_diff_Q15 = diff_Q15;
+ I = i;
+ }
+ }
+ /* Last element */
+ diff_Q15 = ( 1 << 15 ) - ( NLSF_Q15[L-1] + NDeltaMin_Q15[L] );
+ if( diff_Q15 < min_diff_Q15 ) {
+ min_diff_Q15 = diff_Q15;
+ I = L;
+ }
+
+ /***************************************************/
+ /* Now check if the smallest distance non-negative */
+ /***************************************************/
+ if( min_diff_Q15 >= 0 ) {
+ return;
+ }
+
+ if( I == 0 ) {
+ /* Move away from lower limit */
+ NLSF_Q15[0] = NDeltaMin_Q15[0];
+
+ } else if( I == L) {
+ /* Move away from higher limit */
+ NLSF_Q15[L-1] = ( 1 << 15 ) - NDeltaMin_Q15[L];
+
+ } else {
+ /* Find the lower extreme for the location of the current center frequency */
+ min_center_Q15 = 0;
+ for( k = 0; k < I; k++ ) {
+ min_center_Q15 += NDeltaMin_Q15[k];
+ }
+ min_center_Q15 += silk_RSHIFT( NDeltaMin_Q15[I], 1 );
+
+ /* Find the upper extreme for the location of the current center frequency */
+ max_center_Q15 = 1 << 15;
+ for( k = L; k > I; k-- ) {
+ max_center_Q15 -= NDeltaMin_Q15[k];
+ }
+ max_center_Q15 -= silk_RSHIFT( NDeltaMin_Q15[I], 1 );
+
+ /* Move apart, sorted by value, keeping the same center frequency */
+ center_freq_Q15 = (opus_int16)silk_LIMIT_32( silk_RSHIFT_ROUND( (opus_int32)NLSF_Q15[I-1] + (opus_int32)NLSF_Q15[I], 1 ),
+ min_center_Q15, max_center_Q15 );
+ NLSF_Q15[I-1] = center_freq_Q15 - silk_RSHIFT( NDeltaMin_Q15[I], 1 );
+ NLSF_Q15[I] = NLSF_Q15[I-1] + NDeltaMin_Q15[I];
+ }
+ }
+
+ /* Safe and simple fall back method, which is less ideal than the above */
+ if( loops == MAX_LOOPS )
+ {
+ /* Insertion sort (fast for already almost sorted arrays): */
+ /* Best case: O(n) for an already sorted array */
+ /* Worst case: O(n^2) for an inversely sorted array */
+ silk_insertion_sort_increasing_all_values_int16( &NLSF_Q15[0], L );
+
+ /* First NLSF should be no less than NDeltaMin[0] */
+ NLSF_Q15[0] = silk_max_int( NLSF_Q15[0], NDeltaMin_Q15[0] );
+
+ /* Keep delta_min distance between the NLSFs */
+ for( i = 1; i < L; i++ )
+ NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) );
+
+ /* Last NLSF should be no higher than 1 - NDeltaMin[L] */
+ NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] );
+
+ /* Keep NDeltaMin distance between the NLSFs */
+ for( i = L-2; i >= 0; i-- )
+ NLSF_Q15[i] = silk_min_int( NLSF_Q15[i], NLSF_Q15[i+1] - NDeltaMin_Q15[i+1] );
+ }
+}
diff --git a/external/opus-1.1.4/silk/NLSF_unpack.c b/external/opus-1.1.4/silk/NLSF_unpack.c
new file mode 100644
index 0000000..17bd23f
--- /dev/null
+++ b/external/opus-1.1.4/silk/NLSF_unpack.c
@@ -0,0 +1,55 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Unpack predictor values and indices for entropy coding tables */
+void silk_NLSF_unpack(
+ opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */
+ opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */
+ const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */
+ const opus_int CB1_index /* I Index of vector in first LSF codebook */
+)
+{
+ opus_int i;
+ opus_uint8 entry;
+ const opus_uint8 *ec_sel_ptr;
+
+ ec_sel_ptr = &psNLSF_CB->ec_sel[ CB1_index * psNLSF_CB->order / 2 ];
+ for( i = 0; i < psNLSF_CB->order; i += 2 ) {
+ entry = *ec_sel_ptr++;
+ ec_ix [ i ] = silk_SMULBB( silk_RSHIFT( entry, 1 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 );
+ pred_Q8[ i ] = psNLSF_CB->pred_Q8[ i + ( entry & 1 ) * ( psNLSF_CB->order - 1 ) ];
+ ec_ix [ i + 1 ] = silk_SMULBB( silk_RSHIFT( entry, 5 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 );
+ pred_Q8[ i + 1 ] = psNLSF_CB->pred_Q8[ i + ( silk_RSHIFT( entry, 4 ) & 1 ) * ( psNLSF_CB->order - 1 ) + 1 ];
+ }
+}
+
diff --git a/external/opus-1.1.4/silk/NSQ.c b/external/opus-1.1.4/silk/NSQ.c
new file mode 100644
index 0000000..43e3fee
--- /dev/null
+++ b/external/opus-1.1.4/silk/NSQ.c
@@ -0,0 +1,429 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+#include "NSQ.h"
+
+
+static OPUS_INLINE void silk_nsq_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ const opus_int32 x_Q3[], /* I input in Q3 */
+ opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */
+ const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I subframe number */
+ const opus_int LTP_scale_Q14, /* I */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type /* I Signal type */
+);
+
+#if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE void silk_noise_shape_quantizer(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_sc_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP state */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int shapingLPCOrder, /* I Noise shaping AR filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ int arch /* I Architecture */
+);
+#endif
+
+void silk_NSQ_c
+(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+)
+{
+ opus_int k, lag, start_idx, LSF_interpolation_flag;
+ const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13;
+ opus_int16 *pxq;
+ VARDECL( opus_int32, sLTP_Q15 );
+ VARDECL( opus_int16, sLTP );
+ opus_int32 HarmShapeFIRPacked_Q14;
+ opus_int offset_Q10;
+ VARDECL( opus_int32, x_sc_Q10 );
+ SAVE_STACK;
+
+ NSQ->rand_seed = psIndices->Seed;
+
+ /* Set unvoiced lag to the previous one, overwrite later for voiced */
+ lag = NSQ->lagPrev;
+
+ silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+ offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+
+ if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+ LSF_interpolation_flag = 0;
+ } else {
+ LSF_interpolation_flag = 1;
+ }
+
+ ALLOC( sLTP_Q15,
+ psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+ ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+ ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+ /* Set up pointers to start of sub frame */
+ NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ pxq = &NSQ->xq[ psEncC->ltp_mem_length ];
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ];
+ B_Q14 = &LTPCoef_Q14[ k * LTP_ORDER ];
+ AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Noise shape parameters */
+ silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+ HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+ HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+ NSQ->rewhite_flag = 0;
+ if( psIndices->signalType == TYPE_VOICED ) {
+ /* Voiced */
+ lag = pitchL[ k ];
+
+ /* Re-whitening */
+ if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+ /* Rewhiten with new A coefs */
+ start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+ silk_assert( start_idx > 0 );
+
+ silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+ A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
+
+ NSQ->rewhite_flag = 1;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ }
+ }
+
+ silk_nsq_scale_states( psEncC, NSQ, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType );
+
+ silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14,
+ AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10,
+ offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, psEncC->arch );
+
+ x_Q3 += psEncC->subfr_length;
+ pulses += psEncC->subfr_length;
+ pxq += psEncC->subfr_length;
+ }
+
+ /* Update lagPrev for next frame */
+ NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
+
+ /* Save quantized speech and noise shaping signals */
+ /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[ psEncC->ltp_mem_length ], psEncC->frame_length * sizeof( opus_int16 ) ) */
+ silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+ silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
+
+/***********************************/
+/* silk_noise_shape_quantizer */
+/***********************************/
+
+#if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE
+#endif
+void silk_noise_shape_quantizer(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_sc_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP state */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int shapingLPCOrder, /* I Noise shaping AR filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ int arch /* I Architecture */
+)
+{
+ opus_int i;
+ opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13;
+ opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20;
+ opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+ opus_int32 tmp1, tmp2, sLF_AR_shp_Q14;
+ opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr;
+#ifdef silk_short_prediction_create_arch_coef
+ opus_int32 a_Q12_arch[MAX_LPC_ORDER];
+#endif
+
+ shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+ pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 );
+
+ /* Set up short term AR state */
+ psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ];
+
+#ifdef silk_short_prediction_create_arch_coef
+ silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder);
+#endif
+
+ for( i = 0; i < length; i++ ) {
+ /* Generate dither */
+ NSQ->rand_seed = silk_RAND( NSQ->rand_seed );
+
+ /* Short-term prediction */
+ LPC_pred_Q10 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch);
+
+ /* Long-term prediction */
+ if( signalType == TYPE_VOICED ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q13 = 2;
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], b_Q14[ 0 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], b_Q14[ 1 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], b_Q14[ 2 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], b_Q14[ 3 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+ pred_lag_ptr++;
+ } else {
+ LTP_pred_Q13 = 0;
+ }
+
+ /* Noise shape feedback */
+ silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
+ n_AR_Q12 = silk_NSQ_noise_shape_feedback_loop(psLPC_Q14, NSQ->sAR2_Q14, AR_shp_Q13, shapingLPCOrder, arch);
+
+ n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 );
+
+ n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 );
+ n_LF_Q12 = silk_SMLAWT( n_LF_Q12, NSQ->sLF_AR_shp_Q14, LF_shp_Q14 );
+
+ silk_assert( lag > 0 || signalType != TYPE_VOICED );
+
+ /* Combine prediction and noise shaping signals */
+ tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */
+ tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */
+ if( lag > 0 ) {
+ /* Symmetric, packed FIR coefficients */
+ n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+ n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
+ n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 );
+ shp_lag_ptr++;
+
+ tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */
+ tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */
+ } else {
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */
+ }
+
+ r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */
+
+ /* Flip sign depending on dither */
+ if ( NSQ->rand_seed < 0 ) {
+ r_Q10 = -r_Q10;
+ }
+ r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+ /* Find two quantization level candidates and measure their rate-distortion */
+ q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+ q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+ if( q1_Q0 > 0 ) {
+ q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == 0 ) {
+ q1_Q10 = offset_Q10;
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == -1 ) {
+ q2_Q10 = offset_Q10;
+ q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else { /* Q1_Q0 < -1 */
+ q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+ }
+ rr_Q10 = silk_SUB32( r_Q10, q1_Q10 );
+ rd1_Q20 = silk_SMLABB( rd1_Q20, rr_Q10, rr_Q10 );
+ rr_Q10 = silk_SUB32( r_Q10, q2_Q10 );
+ rd2_Q20 = silk_SMLABB( rd2_Q20, rr_Q10, rr_Q10 );
+
+ if( rd2_Q20 < rd1_Q20 ) {
+ q1_Q10 = q2_Q10;
+ }
+
+ pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 );
+
+ /* Excitation */
+ exc_Q14 = silk_LSHIFT( q1_Q10, 4 );
+ if ( NSQ->rand_seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 );
+ xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 );
+
+ /* Scale XQ back to normal level before saving */
+ xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q14, Gain_Q10 ), 8 ) );
+
+ /* Update states */
+ psLPC_Q14++;
+ *psLPC_Q14 = xq_Q14;
+ sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, n_AR_Q12, 2 );
+ NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14;
+
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 );
+ sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 );
+ NSQ->sLTP_shp_buf_idx++;
+ NSQ->sLTP_buf_idx++;
+
+ /* Make dither dependent on quantized signal */
+ NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] );
+ }
+
+ /* Update LPC synth buffer */
+ silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+}
+
+static OPUS_INLINE void silk_nsq_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ const opus_int32 x_Q3[], /* I input in Q3 */
+ opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */
+ const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I subframe number */
+ const opus_int LTP_scale_Q14, /* I */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type /* I Signal type */
+)
+{
+ opus_int i, lag;
+ opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+
+ lag = pitchL[ subfr ];
+ inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+ silk_assert( inv_gain_Q31 != 0 );
+
+ /* Calculate gain adjustment factor */
+ if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+ gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+ } else {
+ gain_adj_Q16 = (opus_int32)1 << 16;
+ }
+
+ /* Scale input */
+ inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 );
+ for( i = 0; i < psEncC->subfr_length; i++ ) {
+ x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 );
+ }
+
+ /* Save inverse gain */
+ NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+
+ /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+ if( NSQ->rewhite_flag ) {
+ if( subfr == 0 ) {
+ /* Do LTP downscaling */
+ inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+ }
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ silk_assert( i < MAX_FRAME_LENGTH );
+ sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+ }
+ }
+
+ /* Adjust for changing gain */
+ if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+ /* Scale long-term shaping state */
+ for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+ NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+ }
+
+ /* Scale long-term prediction state */
+ if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+ }
+ }
+
+ NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 );
+
+ /* Scale short-term prediction and shaping states */
+ for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+ NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] );
+ }
+ for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+ NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] );
+ }
+ }
+}
diff --git a/external/opus-1.1.4/silk/NSQ.h b/external/opus-1.1.4/silk/NSQ.h
new file mode 100644
index 0000000..971832f
--- /dev/null
+++ b/external/opus-1.1.4/silk/NSQ.h
@@ -0,0 +1,101 @@
+/***********************************************************************
+Copyright (c) 2014 Vidyo.
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+#ifndef SILK_NSQ_H
+#define SILK_NSQ_H
+
+#include "SigProc_FIX.h"
+
+#undef silk_short_prediction_create_arch_coef
+
+static OPUS_INLINE opus_int32 silk_noise_shape_quantizer_short_prediction_c(const opus_int32 *buf32, const opus_int16 *coef16, opus_int order)
+{
+ opus_int32 out;
+ silk_assert( order == 10 || order == 16 );
+
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ out = silk_RSHIFT( order, 1 );
+ out = silk_SMLAWB( out, buf32[ 0 ], coef16[ 0 ] );
+ out = silk_SMLAWB( out, buf32[ -1 ], coef16[ 1 ] );
+ out = silk_SMLAWB( out, buf32[ -2 ], coef16[ 2 ] );
+ out = silk_SMLAWB( out, buf32[ -3 ], coef16[ 3 ] );
+ out = silk_SMLAWB( out, buf32[ -4 ], coef16[ 4 ] );
+ out = silk_SMLAWB( out, buf32[ -5 ], coef16[ 5 ] );
+ out = silk_SMLAWB( out, buf32[ -6 ], coef16[ 6 ] );
+ out = silk_SMLAWB( out, buf32[ -7 ], coef16[ 7 ] );
+ out = silk_SMLAWB( out, buf32[ -8 ], coef16[ 8 ] );
+ out = silk_SMLAWB( out, buf32[ -9 ], coef16[ 9 ] );
+
+ if( order == 16 )
+ {
+ out = silk_SMLAWB( out, buf32[ -10 ], coef16[ 10 ] );
+ out = silk_SMLAWB( out, buf32[ -11 ], coef16[ 11 ] );
+ out = silk_SMLAWB( out, buf32[ -12 ], coef16[ 12 ] );
+ out = silk_SMLAWB( out, buf32[ -13 ], coef16[ 13 ] );
+ out = silk_SMLAWB( out, buf32[ -14 ], coef16[ 14 ] );
+ out = silk_SMLAWB( out, buf32[ -15 ], coef16[ 15 ] );
+ }
+ return out;
+}
+
+#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) ((void)arch,silk_noise_shape_quantizer_short_prediction_c(in, coef, order))
+
+static OPUS_INLINE opus_int32 silk_NSQ_noise_shape_feedback_loop_c(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order)
+{
+ opus_int32 out;
+ opus_int32 tmp1, tmp2;
+ opus_int j;
+
+ tmp2 = data0[0];
+ tmp1 = data1[0];
+ data1[0] = tmp2;
+
+ out = silk_RSHIFT(order, 1);
+ out = silk_SMLAWB(out, tmp2, coef[0]);
+
+ for (j = 2; j < order; j += 2) {
+ tmp2 = data1[j - 1];
+ data1[j - 1] = tmp1;
+ out = silk_SMLAWB(out, tmp1, coef[j - 1]);
+ tmp1 = data1[j + 0];
+ data1[j + 0] = tmp2;
+ out = silk_SMLAWB(out, tmp2, coef[j]);
+ }
+ data1[order - 1] = tmp1;
+ out = silk_SMLAWB(out, tmp1, coef[order - 1]);
+ /* Q11 -> Q12 */
+ out = silk_LSHIFT32( out, 1 );
+ return out;
+}
+
+#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order))
+
+#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+#include "arm/NSQ_neon.h"
+#endif
+
+#endif /* SILK_NSQ_H */
diff --git a/external/opus-1.1.4/silk/NSQ_del_dec.c b/external/opus-1.1.4/silk/NSQ_del_dec.c
new file mode 100644
index 0000000..ab6feea
--- /dev/null
+++ b/external/opus-1.1.4/silk/NSQ_del_dec.c
@@ -0,0 +1,716 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+#include "NSQ.h"
+
+
+typedef struct {
+ opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ];
+ opus_int32 RandState[ DECISION_DELAY ];
+ opus_int32 Q_Q10[ DECISION_DELAY ];
+ opus_int32 Xq_Q14[ DECISION_DELAY ];
+ opus_int32 Pred_Q15[ DECISION_DELAY ];
+ opus_int32 Shape_Q14[ DECISION_DELAY ];
+ opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ];
+ opus_int32 LF_AR_Q14;
+ opus_int32 Seed;
+ opus_int32 SeedInit;
+ opus_int32 RD_Q10;
+} NSQ_del_dec_struct;
+
+typedef struct {
+ opus_int32 Q_Q10;
+ opus_int32 RD_Q10;
+ opus_int32 xq_Q14;
+ opus_int32 LF_AR_Q14;
+ opus_int32 sLTP_shp_Q14;
+ opus_int32 LPC_exc_Q14;
+} NSQ_sample_struct;
+
+typedef NSQ_sample_struct NSQ_sample_pair[ 2 ];
+
+#if defined(MIPSr1_ASM)
+#include "mips/NSQ_del_dec_mipsr1.h"
+#endif
+static OPUS_INLINE void silk_nsq_del_dec_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ const opus_int32 x_Q3[], /* I Input in Q3 */
+ opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */
+ const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I Subframe number */
+ opus_int nStatesDelayedDecision, /* I Number of del dec states */
+ const opus_int LTP_scale_Q14, /* I LTP state scaling */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type, /* I Signal type */
+ const opus_int decisionDelay /* I Decision delay */
+);
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP filter state */
+ opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int subfr, /* I Subframe number */
+ opus_int shapingLPCOrder, /* I Shaping LPC filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ opus_int warping_Q16, /* I */
+ opus_int nStatesDelayedDecision, /* I Number of states in decision tree */
+ opus_int *smpl_buf_idx, /* I Index to newest samples in buffers */
+ opus_int decisionDelay, /* I */
+ int arch /* I */
+);
+
+void silk_NSQ_del_dec_c(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+)
+{
+ opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr;
+ opus_int last_smple_idx, smpl_buf_idx, decisionDelay;
+ const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13;
+ opus_int16 *pxq;
+ VARDECL( opus_int32, sLTP_Q15 );
+ VARDECL( opus_int16, sLTP );
+ opus_int32 HarmShapeFIRPacked_Q14;
+ opus_int offset_Q10;
+ opus_int32 RDmin_Q10, Gain_Q10;
+ VARDECL( opus_int32, x_sc_Q10 );
+ VARDECL( opus_int32, delayedGain_Q10 );
+ VARDECL( NSQ_del_dec_struct, psDelDec );
+ NSQ_del_dec_struct *psDD;
+ SAVE_STACK;
+
+ /* Set unvoiced lag to the previous one, overwrite later for voiced */
+ lag = NSQ->lagPrev;
+
+ silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+ /* Initialize delayed decision states */
+ ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct );
+ silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) );
+ for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ psDD->Seed = ( k + psIndices->Seed ) & 3;
+ psDD->SeedInit = psDD->Seed;
+ psDD->RD_Q10 = 0;
+ psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14;
+ psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ];
+ silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) );
+ }
+
+ offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+ smpl_buf_idx = 0; /* index of oldest samples */
+
+ decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length );
+
+ /* For voiced frames limit the decision delay to lower than the pitch lag */
+ if( psIndices->signalType == TYPE_VOICED ) {
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 );
+ }
+ } else {
+ if( lag > 0 ) {
+ decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 );
+ }
+ }
+
+ if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+ LSF_interpolation_flag = 0;
+ } else {
+ LSF_interpolation_flag = 1;
+ }
+
+ ALLOC( sLTP_Q15,
+ psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+ ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+ ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+ ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 );
+ /* Set up pointers to start of sub frame */
+ pxq = &NSQ->xq[ psEncC->ltp_mem_length ];
+ NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ subfr = 0;
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ];
+ B_Q14 = &LTPCoef_Q14[ k * LTP_ORDER ];
+ AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Noise shape parameters */
+ silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+ HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+ HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+ NSQ->rewhite_flag = 0;
+ if( psIndices->signalType == TYPE_VOICED ) {
+ /* Voiced */
+ lag = pitchL[ k ];
+
+ /* Re-whitening */
+ if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+ if( k == 2 ) {
+ /* RESET DELAYED DECISIONS */
+ /* Find winner */
+ RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) {
+ if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psDelDec[ i ].RD_Q10;
+ Winner_ind = i;
+ }
+ }
+ for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) {
+ if( i != Winner_ind ) {
+ psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 );
+ silk_assert( psDelDec[ i ].RD_Q10 >= 0 );
+ }
+ }
+
+ /* Copy final part of signals from winner state to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ last_smple_idx = smpl_buf_idx + decisionDelay;
+ for( i = 0; i < decisionDelay; i++ ) {
+ last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK;
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+ }
+
+ subfr = 0;
+ }
+
+ /* Rewhiten with new A coefs */
+ start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+ silk_assert( start_idx > 0 );
+
+ silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+ A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
+
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ NSQ->rewhite_flag = 1;
+ }
+ }
+
+ silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k,
+ psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay );
+
+ silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15,
+ delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ],
+ Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder,
+ psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay, psEncC->arch );
+
+ x_Q3 += psEncC->subfr_length;
+ pulses += psEncC->subfr_length;
+ pxq += psEncC->subfr_length;
+ }
+
+ /* Find winner */
+ RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) {
+ if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psDelDec[ k ].RD_Q10;
+ Winner_ind = k;
+ }
+ }
+
+ /* Copy final part of signals from winner state to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ psIndices->Seed = psDD->SeedInit;
+ last_smple_idx = smpl_buf_idx + decisionDelay;
+ Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 );
+ for( i = 0; i < decisionDelay; i++ ) {
+ last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK;
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+ }
+ silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) );
+
+ /* Update states */
+ NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14;
+ NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
+
+ /* Save quantized speech signal */
+ /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[psEncC->ltp_mem_length], psEncC->frame_length * sizeof( opus_int16 ) ) */
+ silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+ silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+#ifndef OVERRIDE_silk_noise_shape_quantizer_del_dec
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP filter state */
+ opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int subfr, /* I Subframe number */
+ opus_int shapingLPCOrder, /* I Shaping LPC filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ opus_int warping_Q16, /* I */
+ opus_int nStatesDelayedDecision, /* I Number of states in decision tree */
+ opus_int *smpl_buf_idx, /* I Index to newest samples in buffers */
+ opus_int decisionDelay, /* I */
+ int arch /* I */
+)
+{
+ opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx;
+ opus_int32 Winner_rand_state;
+ opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14;
+ opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10;
+ opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+ opus_int32 tmp1, tmp2, sLF_AR_shp_Q14;
+ opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14;
+#ifdef silk_short_prediction_create_arch_coef
+ opus_int32 a_Q12_arch[MAX_LPC_ORDER];
+#endif
+
+ VARDECL( NSQ_sample_pair, psSampleState );
+ NSQ_del_dec_struct *psDD;
+ NSQ_sample_struct *psSS;
+ SAVE_STACK;
+
+ silk_assert( nStatesDelayedDecision > 0 );
+ ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair );
+
+ shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+ pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 );
+
+#ifdef silk_short_prediction_create_arch_coef
+ silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder);
+#endif
+
+ for( i = 0; i < length; i++ ) {
+ /* Perform common calculations used in all states */
+
+ /* Long-term prediction */
+ if( signalType == TYPE_VOICED ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q14 = 2;
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+ LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */
+ pred_lag_ptr++;
+ } else {
+ LTP_pred_Q14 = 0;
+ }
+
+ /* Long-term shaping */
+ if( lag > 0 ) {
+ /* Symmetric, packed FIR coefficients */
+ n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+ n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
+ n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */
+ shp_lag_ptr++;
+ } else {
+ n_LTP_Q14 = 0;
+ }
+
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ /* Delayed decision state */
+ psDD = &psDelDec[ k ];
+
+ /* Sample state */
+ psSS = psSampleState[ k ];
+
+ /* Generate dither */
+ psDD->Seed = silk_RAND( psDD->Seed );
+
+ /* Pointer used in short term prediction and shaping */
+ psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ];
+ /* Short-term prediction */
+ LPC_pred_Q14 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch);
+ LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */
+
+ /* Noise shape feedback */
+ silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
+ /* Output of lowpass section */
+ tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 );
+ psDD->sAR2_Q14[ 0 ] = tmp2;
+ n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 );
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] );
+ /* Loop over allpass sections */
+ for( j = 2; j < shapingLPCOrder; j += 2 ) {
+ /* Output of allpass section */
+ tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 );
+ psDD->sAR2_Q14[ j - 1 ] = tmp1;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 );
+ psDD->sAR2_Q14[ j + 0 ] = tmp2;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] );
+ }
+ psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
+
+ n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */
+ n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */
+
+ n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */
+ n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */
+ n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */
+
+ /* Input minus prediction plus noise feedback */
+ /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */
+ tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */
+ tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */
+ tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */
+
+ r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */
+
+ /* Flip sign depending on dither */
+ if ( psDD->Seed < 0 ) {
+ r_Q10 = -r_Q10;
+ }
+ r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+ /* Find two quantization level candidates and measure their rate-distortion */
+ q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+ q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+ if( q1_Q0 > 0 ) {
+ q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == 0 ) {
+ q1_Q10 = offset_Q10;
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == -1 ) {
+ q2_Q10 = offset_Q10;
+ q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else { /* q1_Q0 < -1 */
+ q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+ }
+ rr_Q10 = silk_SUB32( r_Q10, q1_Q10 );
+ rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 );
+ rr_Q10 = silk_SUB32( r_Q10, q2_Q10 );
+ rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 );
+
+ if( rd1_Q10 < rd2_Q10 ) {
+ psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+ psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+ psSS[ 0 ].Q_Q10 = q1_Q10;
+ psSS[ 1 ].Q_Q10 = q2_Q10;
+ } else {
+ psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+ psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+ psSS[ 0 ].Q_Q10 = q2_Q10;
+ psSS[ 1 ].Q_Q10 = q1_Q10;
+ }
+
+ /* Update states for best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 );
+ if ( psDD->Seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+ xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+ /* Update states */
+ sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 );
+ psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+ psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14;
+ psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14;
+ psSS[ 0 ].xq_Q14 = xq_Q14;
+
+ /* Update states for second best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 );
+ if ( psDD->Seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+ xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+ /* Update states */
+ sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 );
+ psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+ psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14;
+ psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14;
+ psSS[ 1 ].xq_Q14 = xq_Q14;
+ }
+
+ *smpl_buf_idx = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK; /* Index to newest samples */
+ last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK; /* Index to decisionDelay old samples */
+
+ /* Find winner */
+ RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( k = 1; k < nStatesDelayedDecision; k++ ) {
+ if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
+ Winner_ind = k;
+ }
+ }
+
+ /* Increase RD values of expired states */
+ Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ];
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) {
+ psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 );
+ psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 );
+ silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 );
+ }
+ }
+
+ /* Find worst in first set and best in second set */
+ RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+ RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10;
+ RDmax_ind = 0;
+ RDmin_ind = 0;
+ for( k = 1; k < nStatesDelayedDecision; k++ ) {
+ /* find worst in first set */
+ if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) {
+ RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
+ RDmax_ind = k;
+ }
+ /* find best in second set */
+ if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10;
+ RDmin_ind = k;
+ }
+ }
+
+ /* Replace a state if best from second set outperforms worst in first set */
+ if( RDmin_Q10 < RDmax_Q10 ) {
+ silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i,
+ ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) );
+ silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) );
+ }
+
+ /* Write samples from winner to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ if( subfr > 0 || i >= decisionDelay ) {
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ];
+ sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ];
+ }
+ NSQ->sLTP_shp_buf_idx++;
+ NSQ->sLTP_buf_idx++;
+
+ /* Update states */
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ psSS = &psSampleState[ k ][ 0 ];
+ psDD->LF_AR_Q14 = psSS->LF_AR_Q14;
+ psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14;
+ psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14;
+ psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10;
+ psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 );
+ psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14;
+ psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) );
+ psDD->RandState[ *smpl_buf_idx ] = psDD->Seed;
+ psDD->RD_Q10 = psSS->RD_Q10;
+ }
+ delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10;
+ }
+ /* Update LPC states */
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ }
+ RESTORE_STACK;
+}
+#endif /* OVERRIDE_silk_noise_shape_quantizer_del_dec */
+
+static OPUS_INLINE void silk_nsq_del_dec_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ const opus_int32 x_Q3[], /* I Input in Q3 */
+ opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */
+ const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I Subframe number */
+ opus_int nStatesDelayedDecision, /* I Number of del dec states */
+ const opus_int LTP_scale_Q14, /* I LTP state scaling */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type, /* I Signal type */
+ const opus_int decisionDelay /* I Decision delay */
+)
+{
+ opus_int i, k, lag;
+ opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+ NSQ_del_dec_struct *psDD;
+
+ lag = pitchL[ subfr ];
+ inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+ silk_assert( inv_gain_Q31 != 0 );
+
+ /* Calculate gain adjustment factor */
+ if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+ gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+ } else {
+ gain_adj_Q16 = (opus_int32)1 << 16;
+ }
+
+ /* Scale input */
+ inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 );
+ for( i = 0; i < psEncC->subfr_length; i++ ) {
+ x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 );
+ }
+
+ /* Save inverse gain */
+ NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+
+ /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+ if( NSQ->rewhite_flag ) {
+ if( subfr == 0 ) {
+ /* Do LTP downscaling */
+ inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+ }
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ silk_assert( i < MAX_FRAME_LENGTH );
+ sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+ }
+ }
+
+ /* Adjust for changing gain */
+ if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+ /* Scale long-term shaping state */
+ for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+ NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+ }
+
+ /* Scale long-term prediction state */
+ if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) {
+ sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+ }
+ }
+
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+
+ /* Scale scalar states */
+ psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 );
+
+ /* Scale short-term prediction and shaping states */
+ for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+ psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] );
+ }
+ for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+ psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] );
+ }
+ for( i = 0; i < DECISION_DELAY; i++ ) {
+ psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] );
+ psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] );
+ }
+ }
+ }
+}
diff --git a/external/opus-1.1.4/silk/PLC.c b/external/opus-1.1.4/silk/PLC.c
new file mode 100644
index 0000000..fb6ea88
--- /dev/null
+++ b/external/opus-1.1.4/silk/PLC.c
@@ -0,0 +1,446 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+#include "PLC.h"
+
+#define NB_ATT 2
+static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */
+static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */
+static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */
+
+static OPUS_INLINE void silk_PLC_update(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl /* I/O Decoder control */
+);
+
+static OPUS_INLINE void silk_PLC_conceal(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[], /* O LPC residual signal */
+ int arch /* I Run-time architecture */
+);
+
+
+void silk_PLC_Reset(
+ silk_decoder_state *psDec /* I/O Decoder state */
+)
+{
+ psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 );
+ psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 );
+ psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 );
+ psDec->sPLC.subfr_length = 20;
+ psDec->sPLC.nb_subfr = 2;
+}
+
+void silk_PLC(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[], /* I/O signal */
+ opus_int lost, /* I Loss flag */
+ int arch /* I Run-time architecture */
+)
+{
+ /* PLC control function */
+ if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) {
+ silk_PLC_Reset( psDec );
+ psDec->sPLC.fs_kHz = psDec->fs_kHz;
+ }
+
+ if( lost ) {
+ /****************************/
+ /* Generate Signal */
+ /****************************/
+ silk_PLC_conceal( psDec, psDecCtrl, frame, arch );
+
+ psDec->lossCnt++;
+ } else {
+ /****************************/
+ /* Update state */
+ /****************************/
+ silk_PLC_update( psDec, psDecCtrl );
+ }
+}
+
+/**************************************************/
+/* Update state of PLC */
+/**************************************************/
+static OPUS_INLINE void silk_PLC_update(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl /* I/O Decoder control */
+)
+{
+ opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14;
+ opus_int i, j;
+ silk_PLC_struct *psPLC;
+
+ psPLC = &psDec->sPLC;
+
+ /* Update parameters used in case of packet loss */
+ psDec->prevSignalType = psDec->indices.signalType;
+ LTP_Gain_Q14 = 0;
+ if( psDec->indices.signalType == TYPE_VOICED ) {
+ /* Find the parameters for the last subframe which contains a pitch pulse */
+ for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) {
+ if( j == psDec->nb_subfr ) {
+ break;
+ }
+ temp_LTP_Gain_Q14 = 0;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ];
+ }
+ if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) {
+ LTP_Gain_Q14 = temp_LTP_Gain_Q14;
+ silk_memcpy( psPLC->LTPCoef_Q14,
+ &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ],
+ LTP_ORDER * sizeof( opus_int16 ) );
+
+ psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 );
+ }
+ }
+
+ silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
+ psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14;
+
+ /* Limit LT coefs */
+ if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) {
+ opus_int scale_Q10;
+ opus_int32 tmp;
+
+ tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 );
+ scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 );
+ }
+ } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) {
+ opus_int scale_Q14;
+ opus_int32 tmp;
+
+ tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 );
+ scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 );
+ }
+ }
+ } else {
+ psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 );
+ silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ));
+ }
+
+ /* Save LPC coeficients */
+ silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
+ psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14;
+
+ /* Save last two gains */
+ silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) );
+
+ psPLC->subfr_length = psDec->subfr_length;
+ psPLC->nb_subfr = psDec->nb_subfr;
+}
+
+static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, opus_int32 *energy2, opus_int *shift2,
+ const opus_int32 *exc_Q14, const opus_int32 *prevGain_Q10, int subfr_length, int nb_subfr)
+{
+ int i, k;
+ VARDECL( opus_int16, exc_buf );
+ opus_int16 *exc_buf_ptr;
+ SAVE_STACK;
+ ALLOC( exc_buf, 2*subfr_length, opus_int16 );
+ /* Find random noise component */
+ /* Scale previous excitation signal */
+ exc_buf_ptr = exc_buf;
+ for( k = 0; k < 2; k++ ) {
+ for( i = 0; i < subfr_length; i++ ) {
+ exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT(
+ silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) );
+ }
+ exc_buf_ptr += subfr_length;
+ }
+ /* Find the subframe with lowest energy of the last two and use that as random noise generator */
+ silk_sum_sqr_shift( energy1, shift1, exc_buf, subfr_length );
+ silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length );
+ RESTORE_STACK;
+}
+
+static OPUS_INLINE void silk_PLC_conceal(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[], /* O LPC residual signal */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int i, j, k;
+ opus_int lag, idx, sLTP_buf_idx, shift1, shift2;
+ opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30;
+ opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr;
+ opus_int32 LPC_pred_Q10, LTP_pred_Q12;
+ opus_int16 rand_scale_Q14;
+ opus_int16 *B_Q14;
+ opus_int32 *sLPC_Q14_ptr;
+ opus_int16 A_Q12[ MAX_LPC_ORDER ];
+#ifdef SMALL_FOOTPRINT
+ opus_int16 *sLTP;
+#else
+ VARDECL( opus_int16, sLTP );
+#endif
+ VARDECL( opus_int32, sLTP_Q14 );
+ silk_PLC_struct *psPLC = &psDec->sPLC;
+ opus_int32 prevGain_Q10[2];
+ SAVE_STACK;
+
+ ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 );
+#ifdef SMALL_FOOTPRINT
+ /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */
+ sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length;
+#else
+ ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 );
+#endif
+
+ prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6);
+ prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6);
+
+ if( psDec->first_frame_after_reset ) {
+ silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) );
+ }
+
+ silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr);
+
+ if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) {
+ /* First sub-frame has lowest energy */
+ rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ];
+ } else {
+ /* Second sub-frame has lowest energy */
+ rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ];
+ }
+
+ /* Set up Gain to random noise component */
+ B_Q14 = psPLC->LTPCoef_Q14;
+ rand_scale_Q14 = psPLC->randScale_Q14;
+
+ /* Set up attenuation gains */
+ harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
+ if( psDec->prevSignalType == TYPE_VOICED ) {
+ rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
+ } else {
+ rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
+ }
+
+ /* LPC concealment. Apply BWE to previous LPC */
+ silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) );
+
+ /* Preload LPC coeficients to array on stack. Gives small performance gain */
+ silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
+
+ /* First Lost frame */
+ if( psDec->lossCnt == 0 ) {
+ rand_scale_Q14 = 1 << 14;
+
+ /* Reduce random noise Gain for voiced frames */
+ if( psDec->prevSignalType == TYPE_VOICED ) {
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ rand_scale_Q14 -= B_Q14[ i ];
+ }
+ rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
+ rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 );
+ } else {
+ /* Reduce random noise for unvoiced frames with high LPC gain */
+ opus_int32 invGain_Q30, down_scale_Q30;
+
+ invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order );
+
+ down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
+ down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
+ down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
+
+ rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
+ }
+ }
+
+ rand_seed = psPLC->rand_seed;
+ lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
+ sLTP_buf_idx = psDec->ltp_mem_length;
+
+ /* Rewhiten LTP state */
+ idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
+ silk_assert( idx > 0 );
+ silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch );
+ /* Scale LTP state */
+ inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 );
+ inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 );
+ for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) {
+ sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] );
+ }
+
+ /***************************/
+ /* LTP synthesis filtering */
+ /***************************/
+ for( k = 0; k < psDec->nb_subfr; k++ ) {
+ /* Set up pointer */
+ pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ for( i = 0; i < psDec->subfr_length; i++ ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q12 = 2;
+ LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] );
+ LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
+ LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
+ LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
+ LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
+ pred_lag_ptr++;
+
+ /* Generate LPC excitation */
+ rand_seed = silk_RAND( rand_seed );
+ idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
+ sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 );
+ sLTP_buf_idx++;
+ }
+
+ /* Gradually reduce LTP gain */
+ for( j = 0; j < LTP_ORDER; j++ ) {
+ B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
+ }
+ /* Gradually reduce excitation gain */
+ rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
+
+ /* Slowly increase pitch lag */
+ psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
+ psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
+ lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
+ }
+
+ /***************************/
+ /* LPC synthesis filtering */
+ /***************************/
+ sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ];
+
+ /* Copy LPC state */
+ silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+
+ silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
+ for( i = 0; i < psDec->frame_length; i++ ) {
+ /* partly unrolled */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
+ for( j = 10; j < psDec->LPC_order; j++ ) {
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
+ }
+
+ /* Add prediction to LPC excitation */
+ sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ],
+ silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ));
+
+ /* Scale with Gain */
+ frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) );
+ }
+
+ /* Save LPC state */
+ silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
+
+ /**************************************/
+ /* Update states */
+ /**************************************/
+ psPLC->rand_seed = rand_seed;
+ psPLC->randScale_Q14 = rand_scale_Q14;
+ for( i = 0; i < MAX_NB_SUBFR; i++ ) {
+ psDecCtrl->pitchL[ i ] = lag;
+ }
+ RESTORE_STACK;
+}
+
+/* Glues concealed frames with new good received frames */
+void silk_PLC_glue_frames(
+ silk_decoder_state *psDec, /* I/O decoder state */
+ opus_int16 frame[], /* I/O signal */
+ opus_int length /* I length of signal */
+)
+{
+ opus_int i, energy_shift;
+ opus_int32 energy;
+ silk_PLC_struct *psPLC;
+ psPLC = &psDec->sPLC;
+
+ if( psDec->lossCnt ) {
+ /* Calculate energy in concealed residual */
+ silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
+
+ psPLC->last_frame_lost = 1;
+ } else {
+ if( psDec->sPLC.last_frame_lost ) {
+ /* Calculate residual in decoded signal if last frame was lost */
+ silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
+
+ /* Normalize energies */
+ if( energy_shift > psPLC->conc_energy_shift ) {
+ psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
+ } else if( energy_shift < psPLC->conc_energy_shift ) {
+ energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
+ }
+
+ /* Fade in the energy difference */
+ if( energy > psPLC->conc_energy ) {
+ opus_int32 frac_Q24, LZ;
+ opus_int32 gain_Q16, slope_Q16;
+
+ LZ = silk_CLZ32( psPLC->conc_energy );
+ LZ = LZ - 1;
+ psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
+ energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
+
+ frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
+
+ gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
+ slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length );
+ /* Make slope 4x steeper to avoid missing onsets after DTX */
+ slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
+
+ for( i = 0; i < length; i++ ) {
+ frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
+ gain_Q16 += slope_Q16;
+ if( gain_Q16 > (opus_int32)1 << 16 ) {
+ break;
+ }
+ }
+ }
+ }
+ psPLC->last_frame_lost = 0;
+ }
+}
diff --git a/external/opus-1.1.4/silk/PLC.h b/external/opus-1.1.4/silk/PLC.h
new file mode 100644
index 0000000..6438f51
--- /dev/null
+++ b/external/opus-1.1.4/silk/PLC.h
@@ -0,0 +1,62 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_PLC_H
+#define SILK_PLC_H
+
+#include "main.h"
+
+#define BWE_COEF 0.99
+#define V_PITCH_GAIN_START_MIN_Q14 11469 /* 0.7 in Q14 */
+#define V_PITCH_GAIN_START_MAX_Q14 15565 /* 0.95 in Q14 */
+#define MAX_PITCH_LAG_MS 18
+#define RAND_BUF_SIZE 128
+#define RAND_BUF_MASK ( RAND_BUF_SIZE - 1 )
+#define LOG2_INV_LPC_GAIN_HIGH_THRES 3 /* 2^3 = 8 dB LPC gain */
+#define LOG2_INV_LPC_GAIN_LOW_THRES 8 /* 2^8 = 24 dB LPC gain */
+#define PITCH_DRIFT_FAC_Q16 655 /* 0.01 in Q16 */
+
+void silk_PLC_Reset(
+ silk_decoder_state *psDec /* I/O Decoder state */
+);
+
+void silk_PLC(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[], /* I/O signal */
+ opus_int lost, /* I Loss flag */
+ int arch /* I Run-time architecture */
+);
+
+void silk_PLC_glue_frames(
+ silk_decoder_state *psDec, /* I/O decoder state */
+ opus_int16 frame[], /* I/O signal */
+ opus_int length /* I length of signal */
+);
+
+#endif
+
diff --git a/external/opus-1.1.4/silk/SigProc_FIX.h b/external/opus-1.1.4/silk/SigProc_FIX.h
new file mode 100644
index 0000000..b632994
--- /dev/null
+++ b/external/opus-1.1.4/silk/SigProc_FIX.h
@@ -0,0 +1,615 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FIX_H
+#define SILK_SIGPROC_FIX_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*#define silk_MACRO_COUNT */ /* Used to enable WMOPS counting */
+
+#define SILK_MAX_ORDER_LPC 16 /* max order of the LPC analysis in schur() and k2a() */
+
+#include <string.h> /* for memset(), memcpy(), memmove() */
+#include "typedef.h"
+#include "resampler_structs.h"
+#include "macros.h"
+#include "cpu_support.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#include "x86/SigProc_FIX_sse.h"
+#endif
+
+/********************************************************************/
+/* SIGNAL PROCESSING FUNCTIONS */
+/********************************************************************/
+
+/*!
+ * Initialize/reset the resampler state for a given pair of input/output sampling rates
+*/
+opus_int silk_resampler_init(
+ silk_resampler_state_struct *S, /* I/O Resampler state */
+ opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */
+ opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */
+ opus_int forEnc /* I If 1: encoder; if 0: decoder */
+);
+
+/*!
+ * Resampler: convert from one sampling rate to another
+ */
+opus_int silk_resampler(
+ silk_resampler_state_struct *S, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+);
+
+/*!
+* Downsample 2x, mediocre quality
+*/
+void silk_resampler_down2(
+ opus_int32 *S, /* I/O State vector [ 2 ] */
+ opus_int16 *out, /* O Output signal [ len ] */
+ const opus_int16 *in, /* I Input signal [ floor(len/2) ] */
+ opus_int32 inLen /* I Number of input samples */
+);
+
+/*!
+ * Downsample by a factor 2/3, low quality
+*/
+void silk_resampler_down2_3(
+ opus_int32 *S, /* I/O State vector [ 6 ] */
+ opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */
+ const opus_int16 *in, /* I Input signal [ inLen ] */
+ opus_int32 inLen /* I Number of input samples */
+);
+
+/*!
+ * second order ARMA filter;
+ * slower than biquad() but uses more precise coefficients
+ * can handle (slowly) varying coefficients
+ */
+void silk_biquad_alt(
+ const opus_int16 *in, /* I input signal */
+ const opus_int32 *B_Q28, /* I MA coefficients [3] */
+ const opus_int32 *A_Q28, /* I AR coefficients [2] */
+ opus_int32 *S, /* I/O State vector [2] */
+ opus_int16 *out, /* O output signal */
+ const opus_int32 len, /* I signal length (must be even) */
+ opus_int stride /* I Operate on interleaved signal if > 1 */
+);
+
+/* Variable order MA prediction error filter. */
+void silk_LPC_analysis_filter(
+ opus_int16 *out, /* O Output signal */
+ const opus_int16 *in, /* I Input signal */
+ const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */
+ const opus_int32 len, /* I Signal length */
+ const opus_int32 d, /* I Filter order */
+ int arch /* I Run-time architecture */
+);
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander(
+ opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I Length of ar */
+ opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */
+);
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander_32(
+ opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I Length of ar */
+ opus_int32 chirp_Q16 /* I Chirp factor in Q16 */
+);
+
+/* Compute inverse of LPC prediction gain, and */
+/* test if LPC coefficients are stable (all poles within unit circle) */
+opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */
+ const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */
+ const opus_int order /* I Prediction order */
+);
+
+/* For input in Q24 domain */
+opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */
+ const opus_int32 *A_Q24, /* I Prediction coefficients [order] */
+ const opus_int order /* I Prediction order */
+);
+
+/* Split signal in two decimated bands using first-order allpass filters */
+void silk_ana_filt_bank_1(
+ const opus_int16 *in, /* I Input signal [N] */
+ opus_int32 *S, /* I/O State vector [2] */
+ opus_int16 *outL, /* O Low band [N/2] */
+ opus_int16 *outH, /* O High band [N/2] */
+ const opus_int32 N /* I Number of input samples */
+);
+
+/********************************************************************/
+/* SCALAR FUNCTIONS */
+/********************************************************************/
+
+/* Approximation of 128 * log2() (exact inverse of approx 2^() below) */
+/* Convert input to a log scale */
+opus_int32 silk_lin2log(
+ const opus_int32 inLin /* I input in linear scale */
+);
+
+/* Approximation of a sigmoid function */
+opus_int silk_sigm_Q15(
+ opus_int in_Q5 /* I */
+);
+
+/* Approximation of 2^() (exact inverse of approx log2() above) */
+/* Convert input to a linear scale */
+opus_int32 silk_log2lin(
+ const opus_int32 inLog_Q7 /* I input on log scale */
+);
+
+/* Compute number of bits to right shift the sum of squares of a vector */
+/* of int16s to make it fit in an int32 */
+void silk_sum_sqr_shift(
+ opus_int32 *energy, /* O Energy of x, after shifting to the right */
+ opus_int *shift, /* O Number of bits right shift applied to energy */
+ const opus_int16 *x, /* I Input vector */
+ opus_int len /* I Length of input vector */
+);
+
+/* Calculates the reflection coefficients from the correlation sequence */
+/* Faster than schur64(), but much less accurate. */
+/* uses SMLAWB(), requiring armv5E and higher. */
+opus_int32 silk_schur( /* O Returns residual energy */
+ opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */
+ const opus_int32 *c, /* I correlations [order+1] */
+ const opus_int32 order /* I prediction order */
+);
+
+/* Calculates the reflection coefficients from the correlation sequence */
+/* Slower than schur(), but more accurate. */
+/* Uses SMULL(), available on armv4 */
+opus_int32 silk_schur64( /* O returns residual energy */
+ opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */
+ const opus_int32 c[], /* I Correlations [order+1] */
+ opus_int32 order /* I Prediction order */
+);
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a(
+ opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
+ const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */
+ const opus_int32 order /* I Prediction order */
+);
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a_Q16(
+ opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
+ const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */
+ const opus_int32 order /* I Prediction order */
+);
+
+/* Apply sine window to signal vector. */
+/* Window types: */
+/* 1 -> sine window from 0 to pi/2 */
+/* 2 -> sine window from pi/2 to pi */
+/* every other sample of window is linearly interpolated, for speed */
+void silk_apply_sine_window(
+ opus_int16 px_win[], /* O Pointer to windowed signal */
+ const opus_int16 px[], /* I Pointer to input signal */
+ const opus_int win_type, /* I Selects a window type */
+ const opus_int length /* I Window length, multiple of 4 */
+);
+
+/* Compute autocorrelation */
+void silk_autocorr(
+ opus_int32 *results, /* O Result (length correlationCount) */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *inputData, /* I Input data to correlate */
+ const opus_int inputDataSize, /* I Length of input */
+ const opus_int correlationCount, /* I Number of correlation taps to compute */
+ int arch /* I Run-time architecture */
+);
+
+void silk_decode_pitch(
+ opus_int16 lagIndex, /* I */
+ opus_int8 contourIndex, /* O */
+ opus_int pitch_lags[], /* O 4 pitch values */
+ const opus_int Fs_kHz, /* I sampling frequency (kHz) */
+ const opus_int nb_subfr /* I number of sub frames */
+);
+
+opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */
+ const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
+ opus_int *pitch_out, /* O 4 pitch lag values */
+ opus_int16 *lagIndex, /* O Lag Index */
+ opus_int8 *contourIndex, /* O Pitch contour Index */
+ opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */
+ opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
+ const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */
+ const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */
+ const opus_int Fs_kHz, /* I Sample frequency (kHz) */
+ const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
+ const opus_int nb_subfr, /* I number of 5 ms subframes */
+ int arch /* I Run-time architecture */
+);
+
+/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */
+/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */
+void silk_A2NLSF(
+ opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */
+ opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */
+ const opus_int d /* I Filter order (must be even) */
+);
+
+/* compute whitening filter coefficients from normalized line spectral frequencies */
+void silk_NLSF2A(
+ opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */
+ const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */
+ const opus_int d /* I filter order (should be even) */
+);
+
+void silk_insertion_sort_increasing(
+ opus_int32 *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+);
+
+void silk_insertion_sort_decreasing_int16(
+ opus_int16 *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+);
+
+void silk_insertion_sort_increasing_all_values_int16(
+ opus_int16 *a, /* I/O Unsorted / Sorted vector */
+ const opus_int L /* I Vector length */
+);
+
+/* NLSF stabilizer, for a single input data vector */
+void silk_NLSF_stabilize(
+ opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */
+ const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */
+ const opus_int L /* I Number of NLSF parameters in the input vector */
+);
+
+/* Laroia low complexity NLSF weights */
+void silk_NLSF_VQ_weights_laroia(
+ opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */
+ const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */
+ const opus_int D /* I Input vector dimension (even) */
+);
+
+/* Compute reflection coefficients from input signal */
+void silk_burg_modified_c(
+ opus_int32 *res_nrg, /* O Residual energy */
+ opus_int *res_nrg_Q, /* O Residual energy Q value */
+ opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
+ const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
+ const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */
+ const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I Number of subframes stacked in x */
+ const opus_int D, /* I Order */
+ int arch /* I Run-time architecture */
+);
+
+/* Copy and multiply a vector by a constant */
+void silk_scale_copy_vector16(
+ opus_int16 *data_out,
+ const opus_int16 *data_in,
+ opus_int32 gain_Q16, /* I Gain in Q16 */
+ const opus_int dataSize /* I Length */
+);
+
+/* Some for the LTP related function requires Q26 to work.*/
+void silk_scale_vector32_Q26_lshift_18(
+ opus_int32 *data1, /* I/O Q0/Q18 */
+ opus_int32 gain_Q26, /* I Q26 */
+ opus_int dataSize /* I length */
+);
+
+/********************************************************************/
+/* INLINE ARM MATH */
+/********************************************************************/
+
+/* return sum( inVec1[i] * inVec2[i] ) */
+
+opus_int32 silk_inner_prod_aligned(
+ const opus_int16 *const inVec1, /* I input vector 1 */
+ const opus_int16 *const inVec2, /* I input vector 2 */
+ const opus_int len, /* I vector lengths */
+ int arch /* I Run-time architecture */
+);
+
+
+opus_int32 silk_inner_prod_aligned_scale(
+ const opus_int16 *const inVec1, /* I input vector 1 */
+ const opus_int16 *const inVec2, /* I input vector 2 */
+ const opus_int scale, /* I number of bits to shift */
+ const opus_int len /* I vector lengths */
+);
+
+opus_int64 silk_inner_prod16_aligned_64_c(
+ const opus_int16 *inVec1, /* I input vector 1 */
+ const opus_int16 *inVec2, /* I input vector 2 */
+ const opus_int len /* I vector lengths */
+);
+
+/********************************************************************/
+/* MACROS */
+/********************************************************************/
+
+/* Rotate a32 right by 'rot' bits. Negative rot values result in rotating
+ left. Output is 32bit int.
+ Note: contemporary compilers recognize the C expression below and
+ compile it into a 'ror' instruction if available. No need for OPUS_INLINE ASM! */
+static OPUS_INLINE opus_int32 silk_ROR32( opus_int32 a32, opus_int rot )
+{
+ opus_uint32 x = (opus_uint32) a32;
+ opus_uint32 r = (opus_uint32) rot;
+ opus_uint32 m = (opus_uint32) -rot;
+ if( rot == 0 ) {
+ return a32;
+ } else if( rot < 0 ) {
+ return (opus_int32) ((x << m) | (x >> (32 - m)));
+ } else {
+ return (opus_int32) ((x << (32 - r)) | (x >> r));
+ }
+}
+
+/* Allocate opus_int16 aligned to 4-byte memory address */
+#if EMBEDDED_ARM
+#define silk_DWORD_ALIGN __attribute__((aligned(4)))
+#else
+#define silk_DWORD_ALIGN
+#endif
+
+/* Useful Macros that can be adjusted to other platforms */
+#define silk_memcpy(dest, src, size) memcpy((dest), (src), (size))
+#define silk_memset(dest, src, size) memset((dest), (src), (size))
+#define silk_memmove(dest, src, size) memmove((dest), (src), (size))
+
+/* Fixed point macros */
+
+/* (a32 * b32) output have to be 32bit int */
+#define silk_MUL(a32, b32) ((a32) * (b32))
+
+/* (a32 * b32) output have to be 32bit uint */
+#define silk_MUL_uint(a32, b32) silk_MUL(a32, b32)
+
+/* a32 + (b32 * c32) output have to be 32bit int */
+#define silk_MLA(a32, b32, c32) silk_ADD32((a32),((b32) * (c32)))
+
+/* a32 + (b32 * c32) output have to be 32bit uint */
+#define silk_MLA_uint(a32, b32, c32) silk_MLA(a32, b32, c32)
+
+/* ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */
+#define silk_SMULTT(a32, b32) (((a32) >> 16) * ((b32) >> 16))
+
+/* a32 + ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */
+#define silk_SMLATT(a32, b32, c32) silk_ADD32((a32),((b32) >> 16) * ((c32) >> 16))
+
+#define silk_SMLALBB(a64, b16, c16) silk_ADD64((a64),(opus_int64)((opus_int32)(b16) * (opus_int32)(c16)))
+
+/* (a32 * b32) */
+#define silk_SMULL(a32, b32) ((opus_int64)(a32) * /*(opus_int64)*/(b32))
+
+/* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour
+ (just standard two's complement implementation-specific behaviour) */
+#define silk_ADD32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) + (opus_uint32)(b)))
+/* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour
+ (just standard two's complement implementation-specific behaviour) */
+#define silk_SUB32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) - (opus_uint32)(b)))
+
+/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */
+#define silk_MLA_ovflw(a32, b32, c32) silk_ADD32_ovflw((a32), (opus_uint32)(b32) * (opus_uint32)(c32))
+#define silk_SMLABB_ovflw(a32, b32, c32) (silk_ADD32_ovflw((a32) , ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))))
+
+#define silk_DIV32_16(a32, b16) ((opus_int32)((a32) / (b16)))
+#define silk_DIV32(a32, b32) ((opus_int32)((a32) / (b32)))
+
+/* These macros enables checking for overflow in silk_API_Debug.h*/
+#define silk_ADD16(a, b) ((a) + (b))
+#define silk_ADD32(a, b) ((a) + (b))
+#define silk_ADD64(a, b) ((a) + (b))
+
+#define silk_SUB16(a, b) ((a) - (b))
+#define silk_SUB32(a, b) ((a) - (b))
+#define silk_SUB64(a, b) ((a) - (b))
+
+#define silk_SAT8(a) ((a) > silk_int8_MAX ? silk_int8_MAX : \
+ ((a) < silk_int8_MIN ? silk_int8_MIN : (a)))
+#define silk_SAT16(a) ((a) > silk_int16_MAX ? silk_int16_MAX : \
+ ((a) < silk_int16_MIN ? silk_int16_MIN : (a)))
+#define silk_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : \
+ ((a) < silk_int32_MIN ? silk_int32_MIN : (a)))
+
+#define silk_CHECK_FIT8(a) (a)
+#define silk_CHECK_FIT16(a) (a)
+#define silk_CHECK_FIT32(a) (a)
+
+#define silk_ADD_SAT16(a, b) (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a), (b) ) )
+#define silk_ADD_SAT64(a, b) ((((a) + (b)) & 0x8000000000000000LL) == 0 ? \
+ ((((a) & (b)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a)+(b)) : \
+ ((((a) | (b)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a)+(b)) )
+
+#define silk_SUB_SAT16(a, b) (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a), (b) ) )
+#define silk_SUB_SAT64(a, b) ((((a)-(b)) & 0x8000000000000000LL) == 0 ? \
+ (( (a) & ((b)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a)-(b)) : \
+ ((((a)^0x8000000000000000LL) & (b) & 0x8000000000000000LL) ? silk_int64_MAX : (a)-(b)) )
+
+/* Saturation for positive input values */
+#define silk_POS_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : (a))
+
+/* Add with saturation for positive input values */
+#define silk_ADD_POS_SAT8(a, b) ((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b)))
+#define silk_ADD_POS_SAT16(a, b) ((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b)))
+#define silk_ADD_POS_SAT32(a, b) ((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b)))
+#define silk_ADD_POS_SAT64(a, b) ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b)))
+
+#define silk_LSHIFT8(a, shift) ((opus_int8)((opus_uint8)(a)<<(shift))) /* shift >= 0, shift < 8 */
+#define silk_LSHIFT16(a, shift) ((opus_int16)((opus_uint16)(a)<<(shift))) /* shift >= 0, shift < 16 */
+#define silk_LSHIFT32(a, shift) ((opus_int32)((opus_uint32)(a)<<(shift))) /* shift >= 0, shift < 32 */
+#define silk_LSHIFT64(a, shift) ((opus_int64)((opus_uint64)(a)<<(shift))) /* shift >= 0, shift < 64 */
+#define silk_LSHIFT(a, shift) silk_LSHIFT32(a, shift) /* shift >= 0, shift < 32 */
+
+#define silk_RSHIFT8(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 8 */
+#define silk_RSHIFT16(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 16 */
+#define silk_RSHIFT32(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 32 */
+#define silk_RSHIFT64(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 64 */
+#define silk_RSHIFT(a, shift) silk_RSHIFT32(a, shift) /* shift >= 0, shift < 32 */
+
+/* saturates before shifting */
+#define silk_LSHIFT_SAT32(a, shift) (silk_LSHIFT32( silk_LIMIT( (a), silk_RSHIFT32( silk_int32_MIN, (shift) ), \
+ silk_RSHIFT32( silk_int32_MAX, (shift) ) ), (shift) ))
+
+#define silk_LSHIFT_ovflw(a, shift) ((opus_int32)((opus_uint32)(a) << (shift))) /* shift >= 0, allowed to overflow */
+#define silk_LSHIFT_uint(a, shift) ((a) << (shift)) /* shift >= 0 */
+#define silk_RSHIFT_uint(a, shift) ((a) >> (shift)) /* shift >= 0 */
+
+#define silk_ADD_LSHIFT(a, b, shift) ((a) + silk_LSHIFT((b), (shift))) /* shift >= 0 */
+#define silk_ADD_LSHIFT32(a, b, shift) silk_ADD32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */
+#define silk_ADD_LSHIFT_uint(a, b, shift) ((a) + silk_LSHIFT_uint((b), (shift))) /* shift >= 0 */
+#define silk_ADD_RSHIFT(a, b, shift) ((a) + silk_RSHIFT((b), (shift))) /* shift >= 0 */
+#define silk_ADD_RSHIFT32(a, b, shift) silk_ADD32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */
+#define silk_ADD_RSHIFT_uint(a, b, shift) ((a) + silk_RSHIFT_uint((b), (shift))) /* shift >= 0 */
+#define silk_SUB_LSHIFT32(a, b, shift) silk_SUB32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */
+#define silk_SUB_RSHIFT32(a, b, shift) silk_SUB32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */
+
+/* Requires that shift > 0 */
+#define silk_RSHIFT_ROUND(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1)
+#define silk_RSHIFT_ROUND64(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1)
+
+/* Number of rightshift required to fit the multiplication */
+#define silk_NSHIFT_MUL_32_32(a, b) ( -(31- (32-silk_CLZ32(silk_abs(a)) + (32-silk_CLZ32(silk_abs(b))))) )
+#define silk_NSHIFT_MUL_16_16(a, b) ( -(15- (16-silk_CLZ16(silk_abs(a)) + (16-silk_CLZ16(silk_abs(b))))) )
+
+
+#define silk_min(a, b) (((a) < (b)) ? (a) : (b))
+#define silk_max(a, b) (((a) > (b)) ? (a) : (b))
+
+/* Macro to convert floating-point constants to fixed-point */
+#define SILK_FIX_CONST( C, Q ) ((opus_int32)((C) * ((opus_int64)1 << (Q)) + 0.5))
+
+/* silk_min() versions with typecast in the function call */
+static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b)
+{
+ return (((a) < (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b)
+{
+ return (((a) < (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b)
+{
+ return (((a) < (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b)
+{
+ return (((a) < (b)) ? (a) : (b));
+}
+
+/* silk_min() versions with typecast in the function call */
+static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b)
+{
+ return (((a) > (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b)
+{
+ return (((a) > (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b)
+{
+ return (((a) > (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b)
+{
+ return (((a) > (b)) ? (a) : (b));
+}
+
+#define silk_LIMIT( a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+ : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))))
+
+#define silk_LIMIT_int silk_LIMIT
+#define silk_LIMIT_16 silk_LIMIT
+#define silk_LIMIT_32 silk_LIMIT
+
+#define silk_abs(a) (((a) > 0) ? (a) : -(a)) /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */
+#define silk_abs_int(a) (((a) ^ ((a) >> (8 * sizeof(a) - 1))) - ((a) >> (8 * sizeof(a) - 1)))
+#define silk_abs_int32(a) (((a) ^ ((a) >> 31)) - ((a) >> 31))
+#define silk_abs_int64(a) (((a) > 0) ? (a) : -(a))
+
+#define silk_sign(a) ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 ))
+
+/* PSEUDO-RANDOM GENERATOR */
+/* Make sure to store the result as the seed for the next call (also in between */
+/* frames), otherwise result won't be random at all. When only using some of the */
+/* bits, take the most significant bits by right-shifting. */
+#define silk_RAND(seed) (silk_MLA_ovflw(907633515, (seed), 196314165))
+
+/* Add some multiplication functions that can be easily mapped to ARM. */
+
+/* silk_SMMUL: Signed top word multiply.
+ ARMv6 2 instruction cycles.
+ ARMv3M+ 3 instruction cycles. use SMULL and ignore LSB registers.(except xM)*/
+/*#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT(silk_SMLAL(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)), 16)*/
+/* the following seems faster on x86 */
+#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT64(silk_SMULL((a32), (b32)), 32)
+
+#if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \
+ ((void)(arch), silk_burg_modified_c(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch))
+
+#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \
+ ((void)(arch),silk_inner_prod16_aligned_64_c(inVec1, inVec2, len))
+#endif
+
+#include "Inlines.h"
+#include "MacroCount.h"
+#include "MacroDebug.h"
+
+#ifdef OPUS_ARM_INLINE_ASM
+#include "arm/SigProc_FIX_armv4.h"
+#endif
+
+#ifdef OPUS_ARM_INLINE_EDSP
+#include "arm/SigProc_FIX_armv5e.h"
+#endif
+
+#if defined(MIPSr1_ASM)
+#include "mips/sigproc_fix_mipsr1.h"
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_SIGPROC_FIX_H */
diff --git a/external/opus-1.1.4/silk/VAD.c b/external/opus-1.1.4/silk/VAD.c
new file mode 100644
index 0000000..0a782af
--- /dev/null
+++ b/external/opus-1.1.4/silk/VAD.c
@@ -0,0 +1,362 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/* Silk VAD noise level estimation */
+# if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE void silk_VAD_GetNoiseLevels(
+ const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+);
+#endif
+
+/**********************************/
+/* Initialization of the Silk VAD */
+/**********************************/
+opus_int silk_VAD_Init( /* O Return value, 0 if success */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+)
+{
+ opus_int b, ret = 0;
+
+ /* reset state memory */
+ silk_memset( psSilk_VAD, 0, sizeof( silk_VAD_state ) );
+
+ /* init noise levels */
+ /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ psSilk_VAD->NoiseLevelBias[ b ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 );
+ }
+
+ /* Initialize state */
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ psSilk_VAD->NL[ b ] = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] );
+ psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_int32_MAX, psSilk_VAD->NL[ b ] );
+ }
+ psSilk_VAD->counter = 15;
+
+ /* init smoothed energy-to-noise ratio*/
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256; /* 100 * 256 --> 20 dB SNR */
+ }
+
+ return( ret );
+}
+
+/* Weighting factors for tilt measure */
+static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 };
+
+/***************************************/
+/* Get the speech activity level in Q8 */
+/***************************************/
+opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ const opus_int16 pIn[] /* I PCM input */
+)
+{
+ opus_int SA_Q15, pSNR_dB_Q7, input_tilt;
+ opus_int decimated_framelength1, decimated_framelength2;
+ opus_int decimated_framelength;
+ opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s;
+ opus_int32 sumSquared, smooth_coef_Q16;
+ opus_int16 HPstateTmp;
+ VARDECL( opus_int16, X );
+ opus_int32 Xnrg[ VAD_N_BANDS ];
+ opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ];
+ opus_int32 speech_nrg, x_tmp;
+ opus_int X_offset[ VAD_N_BANDS ];
+ opus_int ret = 0;
+ silk_VAD_state *psSilk_VAD = &psEncC->sVAD;
+ SAVE_STACK;
+
+ /* Safety checks */
+ silk_assert( VAD_N_BANDS == 4 );
+ silk_assert( MAX_FRAME_LENGTH >= psEncC->frame_length );
+ silk_assert( psEncC->frame_length <= 512 );
+ silk_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) );
+
+ /***********************/
+ /* Filter and Decimate */
+ /***********************/
+ decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 );
+ decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 );
+ decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 );
+ /* Decimate into 4 bands:
+ 0 L 3L L 3L 5L
+ - -- - -- --
+ 8 8 2 4 4
+
+ [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz |
+
+ They're arranged to allow the minimal ( frame_length / 4 ) extra
+ scratch space during the downsampling process */
+ X_offset[ 0 ] = 0;
+ X_offset[ 1 ] = decimated_framelength + decimated_framelength2;
+ X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength;
+ X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2;
+ ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 );
+
+ /* 0-8 kHz to 0-4 kHz and 4-8 kHz */
+ silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ],
+ X, &X[ X_offset[ 3 ] ], psEncC->frame_length );
+
+ /* 0-4 kHz to 0-2 kHz and 2-4 kHz */
+ silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ],
+ X, &X[ X_offset[ 2 ] ], decimated_framelength1 );
+
+ /* 0-2 kHz to 0-1 kHz and 1-2 kHz */
+ silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ],
+ X, &X[ X_offset[ 1 ] ], decimated_framelength2 );
+
+ /*********************************************/
+ /* HP filter on lowest band (differentiator) */
+ /*********************************************/
+ X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 );
+ HPstateTmp = X[ decimated_framelength - 1 ];
+ for( i = decimated_framelength - 1; i > 0; i-- ) {
+ X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 );
+ X[ i ] -= X[ i - 1 ];
+ }
+ X[ 0 ] -= psSilk_VAD->HPstate;
+ psSilk_VAD->HPstate = HPstateTmp;
+
+ /*************************************/
+ /* Calculate the energy in each band */
+ /*************************************/
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* Find the decimated framelength in the non-uniformly divided bands */
+ decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) );
+
+ /* Split length into subframe lengths */
+ dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 );
+ dec_subframe_offset = 0;
+
+ /* Compute energy per sub-frame */
+ /* initialize with summed energy of last subframe */
+ Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ];
+ for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) {
+ sumSquared = 0;
+ for( i = 0; i < dec_subframe_length; i++ ) {
+ /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */
+ /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */
+ x_tmp = silk_RSHIFT(
+ X[ X_offset[ b ] + i + dec_subframe_offset ], 3 );
+ sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp );
+
+ /* Safety check */
+ silk_assert( sumSquared >= 0 );
+ }
+
+ /* Add/saturate summed energy of current subframe */
+ if( s < VAD_INTERNAL_SUBFRAMES - 1 ) {
+ Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared );
+ } else {
+ /* Look-ahead subframe */
+ Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) );
+ }
+
+ dec_subframe_offset += dec_subframe_length;
+ }
+ psSilk_VAD->XnrgSubfr[ b ] = sumSquared;
+ }
+
+ /********************/
+ /* Noise estimation */
+ /********************/
+ silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD );
+
+ /***********************************************/
+ /* Signal-plus-noise to noise ratio estimation */
+ /***********************************************/
+ sumSquared = 0;
+ input_tilt = 0;
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ];
+ if( speech_nrg > 0 ) {
+ /* Divide, with sufficient resolution */
+ if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) {
+ NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 );
+ } else {
+ NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 );
+ }
+
+ /* Convert to log domain */
+ SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128;
+
+ /* Sum-of-squares */
+ sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */
+
+ /* Tilt measure */
+ if( speech_nrg < ( (opus_int32)1 << 20 ) ) {
+ /* Scale down SNR value for small subband speech energies */
+ SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 );
+ }
+ input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 );
+ } else {
+ NrgToNoiseRatio_Q8[ b ] = 256;
+ }
+ }
+
+ /* Mean-of-squares */
+ sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */
+
+ /* Root-mean-square approximation, scale to dBs, and write to output pointer */
+ pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */
+
+ /*********************************/
+ /* Speech Probability Estimation */
+ /*********************************/
+ SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 );
+
+ /**************************/
+ /* Frequency Tilt Measure */
+ /**************************/
+ psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 );
+
+ /**************************************************/
+ /* Scale the sigmoid output based on power levels */
+ /**************************************************/
+ speech_nrg = 0;
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* Accumulate signal-without-noise energies, higher frequency bands have more weight */
+ speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 );
+ }
+
+ /* Power scaling */
+ if( speech_nrg <= 0 ) {
+ SA_Q15 = silk_RSHIFT( SA_Q15, 1 );
+ } else if( speech_nrg < 32768 ) {
+ if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
+ speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 16 );
+ } else {
+ speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 15 );
+ }
+
+ /* square-root */
+ speech_nrg = silk_SQRT_APPROX( speech_nrg );
+ SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 );
+ }
+
+ /* Copy the resulting speech activity in Q8 */
+ psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX );
+
+ /***********************************/
+ /* Energy Level and SNR estimation */
+ /***********************************/
+ /* Smoothing coefficient */
+ smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) );
+
+ if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
+ smooth_coef_Q16 >>= 1;
+ }
+
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* compute smoothed energy-to-noise ratio per band */
+ psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ],
+ NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 );
+
+ /* signal to noise ratio in dB per band */
+ SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 );
+ /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */
+ psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) );
+ }
+
+ RESTORE_STACK;
+ return( ret );
+}
+
+/**************************/
+/* Noise level estimation */
+/**************************/
+# if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE
+#endif
+void silk_VAD_GetNoiseLevels(
+ const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+)
+{
+ opus_int k;
+ opus_int32 nl, nrg, inv_nrg;
+ opus_int coef, min_coef;
+
+ /* Initially faster smoothing */
+ if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */
+ min_coef = silk_DIV32_16( silk_int16_MAX, silk_RSHIFT( psSilk_VAD->counter, 4 ) + 1 );
+ } else {
+ min_coef = 0;
+ }
+
+ for( k = 0; k < VAD_N_BANDS; k++ ) {
+ /* Get old noise level estimate for current band */
+ nl = psSilk_VAD->NL[ k ];
+ silk_assert( nl >= 0 );
+
+ /* Add bias */
+ nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] );
+ silk_assert( nrg > 0 );
+
+ /* Invert energies */
+ inv_nrg = silk_DIV32( silk_int32_MAX, nrg );
+ silk_assert( inv_nrg >= 0 );
+
+ /* Less update when subband energy is high */
+ if( nrg > silk_LSHIFT( nl, 3 ) ) {
+ coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3;
+ } else if( nrg < nl ) {
+ coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16;
+ } else {
+ coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 );
+ }
+
+ /* Initially faster smoothing */
+ coef = silk_max_int( coef, min_coef );
+
+ /* Smooth inverse energies */
+ psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef );
+ silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 );
+
+ /* Compute noise level by inverting again */
+ nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] );
+ silk_assert( nl >= 0 );
+
+ /* Limit noise levels (guarantee 7 bits of head room) */
+ nl = silk_min( nl, 0x00FFFFFF );
+
+ /* Store as part of state */
+ psSilk_VAD->NL[ k ] = nl;
+ }
+
+ /* Increment frame counter */
+ psSilk_VAD->counter++;
+}
diff --git a/external/opus-1.1.4/silk/VQ_WMat_EC.c b/external/opus-1.1.4/silk/VQ_WMat_EC.c
new file mode 100644
index 0000000..7983f1d
--- /dev/null
+++ b/external/opus-1.1.4/silk/VQ_WMat_EC.c
@@ -0,0 +1,120 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */
+void silk_VQ_WMat_EC_c(
+ opus_int8 *ind, /* O index of best codebook vector */
+ opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */
+ opus_int *gain_Q7, /* O sum of absolute LTP coefficients */
+ const opus_int16 *in_Q14, /* I input vector to be quantized */
+ const opus_int32 *W_Q18, /* I weighting matrix */
+ const opus_int8 *cb_Q7, /* I codebook */
+ const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */
+ const opus_uint8 *cl_Q5, /* I code length for each codebook vector */
+ const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */
+ const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ opus_int L /* I number of vectors in codebook */
+)
+{
+ opus_int k, gain_tmp_Q7;
+ const opus_int8 *cb_row_Q7;
+ opus_int16 diff_Q14[ 5 ];
+ opus_int32 sum1_Q14, sum2_Q16;
+
+ /* Loop over codebook */
+ *rate_dist_Q14 = silk_int32_MAX;
+ cb_row_Q7 = cb_Q7;
+ for( k = 0; k < L; k++ ) {
+ gain_tmp_Q7 = cb_gain_Q7[k];
+
+ diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 );
+ diff_Q14[ 1 ] = in_Q14[ 1 ] - silk_LSHIFT( cb_row_Q7[ 1 ], 7 );
+ diff_Q14[ 2 ] = in_Q14[ 2 ] - silk_LSHIFT( cb_row_Q7[ 2 ], 7 );
+ diff_Q14[ 3 ] = in_Q14[ 3 ] - silk_LSHIFT( cb_row_Q7[ 3 ], 7 );
+ diff_Q14[ 4 ] = in_Q14[ 4 ] - silk_LSHIFT( cb_row_Q7[ 4 ], 7 );
+
+ /* Weighted rate */
+ sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] );
+
+ /* Penalty for too large gain */
+ sum1_Q14 = silk_ADD_LSHIFT32( sum1_Q14, silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 10 );
+
+ silk_assert( sum1_Q14 >= 0 );
+
+ /* first row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 1 ], diff_Q14[ 1 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 2 ], diff_Q14[ 2 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 3 ], diff_Q14[ 3 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 4 ], diff_Q14[ 4 ] );
+ sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14[ 0 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 0 ] );
+
+ /* second row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 7 ], diff_Q14[ 2 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 8 ], diff_Q14[ 3 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14[ 4 ] );
+ sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 6 ], diff_Q14[ 1 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 1 ] );
+
+ /* third row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 13 ], diff_Q14[ 3 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] );
+ sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 2 ] );
+
+ /* fourth row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 19 ], diff_Q14[ 4 ] );
+ sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 3 ] );
+
+ /* last row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 24 ], diff_Q14[ 4 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 4 ] );
+
+ silk_assert( sum1_Q14 >= 0 );
+
+ /* find best */
+ if( sum1_Q14 < *rate_dist_Q14 ) {
+ *rate_dist_Q14 = sum1_Q14;
+ *ind = (opus_int8)k;
+ *gain_Q7 = gain_tmp_Q7;
+ }
+
+ /* Go to next cbk vector */
+ cb_row_Q7 += LTP_ORDER;
+ }
+}
diff --git a/external/opus-1.1.4/silk/ana_filt_bank_1.c b/external/opus-1.1.4/silk/ana_filt_bank_1.c
new file mode 100644
index 0000000..24cfb03
--- /dev/null
+++ b/external/opus-1.1.4/silk/ana_filt_bank_1.c
@@ -0,0 +1,74 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Coefficients for 2-band filter bank based on first-order allpass filters */
+static opus_int16 A_fb1_20 = 5394 << 1;
+static opus_int16 A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */
+
+/* Split signal into two decimated bands using first-order allpass filters */
+void silk_ana_filt_bank_1(
+ const opus_int16 *in, /* I Input signal [N] */
+ opus_int32 *S, /* I/O State vector [2] */
+ opus_int16 *outL, /* O Low band [N/2] */
+ opus_int16 *outH, /* O High band [N/2] */
+ const opus_int32 N /* I Number of input samples */
+)
+{
+ opus_int k, N2 = silk_RSHIFT( N, 1 );
+ opus_int32 in32, X, Y, out_1, out_2;
+
+ /* Internal variables and state are in Q10 format */
+ for( k = 0; k < N2; k++ ) {
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 );
+
+ /* All-pass section for even input sample */
+ Y = silk_SUB32( in32, S[ 0 ] );
+ X = silk_SMLAWB( Y, Y, A_fb1_21 );
+ out_1 = silk_ADD32( S[ 0 ], X );
+ S[ 0 ] = silk_ADD32( in32, X );
+
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 );
+
+ /* All-pass section for odd input sample, and add to output of previous section */
+ Y = silk_SUB32( in32, S[ 1 ] );
+ X = silk_SMULWB( Y, A_fb1_20 );
+ out_2 = silk_ADD32( S[ 1 ], X );
+ S[ 1 ] = silk_ADD32( in32, X );
+
+ /* Add/subtract, convert back to int16 and store to output */
+ outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) );
+ outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) );
+ }
+}
diff --git a/external/opus-1.1.4/silk/arm/NSQ_neon.c b/external/opus-1.1.4/silk/arm/NSQ_neon.c
new file mode 100644
index 0000000..9642529
--- /dev/null
+++ b/external/opus-1.1.4/silk/arm/NSQ_neon.c
@@ -0,0 +1,112 @@
+/***********************************************************************
+Copyright (C) 2014 Vidyo
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <arm_neon.h>
+#include "main.h"
+#include "stack_alloc.h"
+#include "NSQ.h"
+#include "celt/cpu_support.h"
+#include "celt/arm/armcpu.h"
+
+opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order)
+{
+ int32x4_t coef0 = vld1q_s32(coef32);
+ int32x4_t coef1 = vld1q_s32(coef32 + 4);
+ int32x4_t coef2 = vld1q_s32(coef32 + 8);
+ int32x4_t coef3 = vld1q_s32(coef32 + 12);
+
+ int32x4_t a0 = vld1q_s32(buf32 - 15);
+ int32x4_t a1 = vld1q_s32(buf32 - 11);
+ int32x4_t a2 = vld1q_s32(buf32 - 7);
+ int32x4_t a3 = vld1q_s32(buf32 - 3);
+
+ int32x4_t b0 = vqdmulhq_s32(coef0, a0);
+ int32x4_t b1 = vqdmulhq_s32(coef1, a1);
+ int32x4_t b2 = vqdmulhq_s32(coef2, a2);
+ int32x4_t b3 = vqdmulhq_s32(coef3, a3);
+
+ int32x4_t c0 = vaddq_s32(b0, b1);
+ int32x4_t c1 = vaddq_s32(b2, b3);
+
+ int32x4_t d = vaddq_s32(c0, c1);
+
+ int64x2_t e = vpaddlq_s32(d);
+
+ int64x1_t f = vadd_s64(vget_low_s64(e), vget_high_s64(e));
+
+ opus_int32 out = vget_lane_s32(vreinterpret_s32_s64(f), 0);
+
+ out += silk_RSHIFT( order, 1 );
+
+ return out;
+}
+
+
+opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order)
+{
+ opus_int32 out;
+ if (order == 8)
+ {
+ int32x4_t a00 = vdupq_n_s32(data0[0]);
+ int32x4_t a01 = vld1q_s32(data1); /* data1[0] ... [3] */
+
+ int32x4_t a0 = vextq_s32 (a00, a01, 3); /* data0[0] data1[0] ...[2] */
+ int32x4_t a1 = vld1q_s32(data1 + 3); /* data1[3] ... [6] */
+
+ /*TODO: Convert these once in advance instead of once per sample, like
+ silk_noise_shape_quantizer_short_prediction_neon() does.*/
+ int16x8_t coef16 = vld1q_s16(coef);
+ int32x4_t coef0 = vmovl_s16(vget_low_s16(coef16));
+ int32x4_t coef1 = vmovl_s16(vget_high_s16(coef16));
+
+ /*This is not bit-exact with the C version, since we do not drop the
+ lower 16 bits of each multiply, but wait until the end to truncate
+ precision. This is an encoder-specific calculation (and unlike
+ silk_noise_shape_quantizer_short_prediction_neon(), is not meant to
+ simulate what the decoder will do). We still could use vqdmulhq_s32()
+ like silk_noise_shape_quantizer_short_prediction_neon() and save
+ half the multiplies, but the speed difference is not large, since we
+ then need two extra adds.*/
+ int64x2_t b0 = vmull_s32(vget_low_s32(a0), vget_low_s32(coef0));
+ int64x2_t b1 = vmlal_s32(b0, vget_high_s32(a0), vget_high_s32(coef0));
+ int64x2_t b2 = vmlal_s32(b1, vget_low_s32(a1), vget_low_s32(coef1));
+ int64x2_t b3 = vmlal_s32(b2, vget_high_s32(a1), vget_high_s32(coef1));
+
+ int64x1_t c = vadd_s64(vget_low_s64(b3), vget_high_s64(b3));
+ int64x1_t cS = vrshr_n_s64(c, 15);
+ int32x2_t d = vreinterpret_s32_s64(cS);
+
+ out = vget_lane_s32(d, 0);
+ vst1q_s32(data1, a0);
+ vst1q_s32(data1 + 4, a1);
+ return out;
+ }
+ return silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order);
+}
diff --git a/external/opus-1.1.4/silk/arm/NSQ_neon.h b/external/opus-1.1.4/silk/arm/NSQ_neon.h
new file mode 100644
index 0000000..77c946a
--- /dev/null
+++ b/external/opus-1.1.4/silk/arm/NSQ_neon.h
@@ -0,0 +1,113 @@
+/***********************************************************************
+Copyright (C) 2014 Vidyo
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+#ifndef SILK_NSQ_NEON_H
+#define SILK_NSQ_NEON_H
+
+#include "cpu_support.h"
+
+#undef silk_short_prediction_create_arch_coef
+/* For vectorized calc, reverse a_Q12 coefs, convert to 32-bit, and shift for vqdmulhq_s32. */
+static OPUS_INLINE void silk_short_prediction_create_arch_coef_neon(opus_int32 *out, const opus_int16 *in, opus_int order)
+{
+ out[15] = in[0] << 15;
+ out[14] = in[1] << 15;
+ out[13] = in[2] << 15;
+ out[12] = in[3] << 15;
+ out[11] = in[4] << 15;
+ out[10] = in[5] << 15;
+ out[9] = in[6] << 15;
+ out[8] = in[7] << 15;
+ out[7] = in[8] << 15;
+ out[6] = in[9] << 15;
+
+ if (order == 16)
+ {
+ out[5] = in[10] << 15;
+ out[4] = in[11] << 15;
+ out[3] = in[12] << 15;
+ out[2] = in[13] << 15;
+ out[1] = in[14] << 15;
+ out[0] = in[15] << 15;
+ }
+ else
+ {
+ out[5] = 0;
+ out[4] = 0;
+ out[3] = 0;
+ out[2] = 0;
+ out[1] = 0;
+ out[0] = 0;
+ }
+}
+
+#if defined(OPUS_ARM_PRESUME_NEON_INTR)
+
+#define silk_short_prediction_create_arch_coef(out, in, order) \
+ (silk_short_prediction_create_arch_coef_neon(out, in, order))
+
+#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+
+#define silk_short_prediction_create_arch_coef(out, in, order) \
+ do { if (arch == OPUS_ARCH_ARM_NEON) { silk_short_prediction_create_arch_coef_neon(out, in, order); } } while (0)
+
+#endif
+
+opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order);
+
+opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order);
+
+#if defined(OPUS_ARM_PRESUME_NEON_INTR)
+#undef silk_noise_shape_quantizer_short_prediction
+#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \
+ ((void)arch,silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order))
+
+#undef silk_NSQ_noise_shape_feedback_loop
+#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_neon(data0, data1, coef, order))
+
+#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+
+/* silk_noise_shape_quantizer_short_prediction implementations take different parameters based on arch
+ (coef vs. coefRev) so can't use the usual IMPL table implementation */
+#undef silk_noise_shape_quantizer_short_prediction
+#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \
+ (arch == OPUS_ARCH_ARM_NEON ? \
+ silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order) : \
+ silk_noise_shape_quantizer_short_prediction_c(in, coef, order))
+
+extern opus_int32
+ (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])(
+ const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef,
+ opus_int order);
+
+#undef silk_NSQ_noise_shape_feedback_loop
+#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) \
+ (SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[(arch)&OPUS_ARCHMASK](data0, data1, \
+ coef, order))
+
+#endif
+
+#endif /* SILK_NSQ_NEON_H */
diff --git a/external/opus-1.1.4/silk/arm/SigProc_FIX_armv4.h b/external/opus-1.1.4/silk/arm/SigProc_FIX_armv4.h
new file mode 100644
index 0000000..ff62b1e
--- /dev/null
+++ b/external/opus-1.1.4/silk/arm/SigProc_FIX_armv4.h
@@ -0,0 +1,47 @@
+/***********************************************************************
+Copyright (C) 2013 Xiph.Org Foundation and contributors
+Copyright (c) 2013 Parrot
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FIX_ARMv4_H
+#define SILK_SIGPROC_FIX_ARMv4_H
+
+#undef silk_MLA
+static OPUS_INLINE opus_int32 silk_MLA_armv4(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ opus_int32 res;
+ __asm__(
+ "#silk_MLA\n\t"
+ "mla %0, %1, %2, %3\n\t"
+ : "=&r"(res)
+ : "r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_MLA(a, b, c) (silk_MLA_armv4(a, b, c))
+
+#endif
diff --git a/external/opus-1.1.4/silk/arm/SigProc_FIX_armv5e.h b/external/opus-1.1.4/silk/arm/SigProc_FIX_armv5e.h
new file mode 100644
index 0000000..617a09c
--- /dev/null
+++ b/external/opus-1.1.4/silk/arm/SigProc_FIX_armv5e.h
@@ -0,0 +1,61 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Copyright (c) 2013 Parrot
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FIX_ARMv5E_H
+#define SILK_SIGPROC_FIX_ARMv5E_H
+
+#undef silk_SMULTT
+static OPUS_INLINE opus_int32 silk_SMULTT_armv5e(opus_int32 a, opus_int32 b)
+{
+ opus_int32 res;
+ __asm__(
+ "#silk_SMULTT\n\t"
+ "smultt %0, %1, %2\n\t"
+ : "=r"(res)
+ : "%r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SMULTT(a, b) (silk_SMULTT_armv5e(a, b))
+
+#undef silk_SMLATT
+static OPUS_INLINE opus_int32 silk_SMLATT_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ opus_int32 res;
+ __asm__(
+ "#silk_SMLATT\n\t"
+ "smlatt %0, %1, %2, %3\n\t"
+ : "=r"(res)
+ : "%r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_SMLATT(a, b, c) (silk_SMLATT_armv5e(a, b, c))
+
+#endif
diff --git a/external/opus-1.1.4/silk/arm/arm_silk_map.c b/external/opus-1.1.4/silk/arm/arm_silk_map.c
new file mode 100644
index 0000000..9bd86a7
--- /dev/null
+++ b/external/opus-1.1.4/silk/arm/arm_silk_map.c
@@ -0,0 +1,55 @@
+/***********************************************************************
+Copyright (C) 2014 Vidyo
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "NSQ.h"
+
+#if defined(OPUS_HAVE_RTCD)
+
+# if (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && \
+ !defined(OPUS_ARM_PRESUME_NEON_INTR))
+
+/*There is no table for silk_noise_shape_quantizer_short_prediction because the
+ NEON version takes different parameters than the C version.
+ Instead RTCD is done via if statements at the call sites.
+ See NSQ_neon.h for details.*/
+
+opus_int32
+ (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])(
+ const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef,
+ opus_int order) = {
+ silk_NSQ_noise_shape_feedback_loop_c, /* ARMv4 */
+ silk_NSQ_noise_shape_feedback_loop_c, /* EDSP */
+ silk_NSQ_noise_shape_feedback_loop_c, /* Media */
+ silk_NSQ_noise_shape_feedback_loop_neon, /* NEON */
+};
+
+# endif
+
+#endif /* OPUS_HAVE_RTCD */
diff --git a/external/opus-1.1.4/silk/arm/macros_arm64.h b/external/opus-1.1.4/silk/arm/macros_arm64.h
new file mode 100644
index 0000000..ed03041
--- /dev/null
+++ b/external/opus-1.1.4/silk/arm/macros_arm64.h
@@ -0,0 +1,39 @@
+/***********************************************************************
+Copyright (C) 2015 Vidyo
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_MACROS_ARM64_H
+#define SILK_MACROS_ARM64_H
+
+#include <arm_neon.h>
+
+#undef silk_ADD_SAT32
+#define silk_ADD_SAT32(a, b) (vqadds_s32((a), (b)))
+
+#undef silk_SUB_SAT32
+#define silk_SUB_SAT32(a, b) (vqsubs_s32((a), (b)))
+
+#endif /* SILK_MACROS_ARM64_H */
diff --git a/external/opus-1.1.4/silk/arm/macros_armv4.h b/external/opus-1.1.4/silk/arm/macros_armv4.h
new file mode 100644
index 0000000..3f30e97
--- /dev/null
+++ b/external/opus-1.1.4/silk/arm/macros_armv4.h
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (C) 2013 Xiph.Org Foundation and contributors.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_MACROS_ARMv4_H
+#define SILK_MACROS_ARMv4_H
+
+/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */
+#undef silk_SMULWB
+static OPUS_INLINE opus_int32 silk_SMULWB_armv4(opus_int32 a, opus_int16 b)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#silk_SMULWB\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(a), "r"(b<<16)
+ );
+ return rd_hi;
+}
+#define silk_SMULWB(a, b) (silk_SMULWB_armv4(a, b))
+
+/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */
+#undef silk_SMLAWB
+#define silk_SMLAWB(a, b, c) ((a) + silk_SMULWB(b, c))
+
+/* (a32 * (b32 >> 16)) >> 16 */
+#undef silk_SMULWT
+static OPUS_INLINE opus_int32 silk_SMULWT_armv4(opus_int32 a, opus_int32 b)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#silk_SMULWT\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(a), "r"(b&~0xFFFF)
+ );
+ return rd_hi;
+}
+#define silk_SMULWT(a, b) (silk_SMULWT_armv4(a, b))
+
+/* a32 + (b32 * (c32 >> 16)) >> 16 */
+#undef silk_SMLAWT
+#define silk_SMLAWT(a, b, c) ((a) + silk_SMULWT(b, c))
+
+/* (a32 * b32) >> 16 */
+#undef silk_SMULWW
+static OPUS_INLINE opus_int32 silk_SMULWW_armv4(opus_int32 a, opus_int32 b)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#silk_SMULWW\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(a), "r"(b)
+ );
+ return (rd_hi<<16)+(rd_lo>>16);
+}
+#define silk_SMULWW(a, b) (silk_SMULWW_armv4(a, b))
+
+#undef silk_SMLAWW
+static OPUS_INLINE opus_int32 silk_SMLAWW_armv4(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#silk_SMLAWW\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(b), "r"(c)
+ );
+ return a+(rd_hi<<16)+(rd_lo>>16);
+}
+#define silk_SMLAWW(a, b, c) (silk_SMLAWW_armv4(a, b, c))
+
+#endif /* SILK_MACROS_ARMv4_H */
diff --git a/external/opus-1.1.4/silk/arm/macros_armv5e.h b/external/opus-1.1.4/silk/arm/macros_armv5e.h
new file mode 100644
index 0000000..aad4117
--- /dev/null
+++ b/external/opus-1.1.4/silk/arm/macros_armv5e.h
@@ -0,0 +1,213 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Copyright (c) 2013 Parrot
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_MACROS_ARMv5E_H
+#define SILK_MACROS_ARMv5E_H
+
+/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */
+#undef silk_SMULWB
+static OPUS_INLINE opus_int32 silk_SMULWB_armv5e(opus_int32 a, opus_int16 b)
+{
+ int res;
+ __asm__(
+ "#silk_SMULWB\n\t"
+ "smulwb %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SMULWB(a, b) (silk_SMULWB_armv5e(a, b))
+
+/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */
+#undef silk_SMLAWB
+static OPUS_INLINE opus_int32 silk_SMLAWB_armv5e(opus_int32 a, opus_int32 b,
+ opus_int16 c)
+{
+ int res;
+ __asm__(
+ "#silk_SMLAWB\n\t"
+ "smlawb %0, %1, %2, %3\n\t"
+ : "=r"(res)
+ : "r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_SMLAWB(a, b, c) (silk_SMLAWB_armv5e(a, b, c))
+
+/* (a32 * (b32 >> 16)) >> 16 */
+#undef silk_SMULWT
+static OPUS_INLINE opus_int32 silk_SMULWT_armv5e(opus_int32 a, opus_int32 b)
+{
+ int res;
+ __asm__(
+ "#silk_SMULWT\n\t"
+ "smulwt %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SMULWT(a, b) (silk_SMULWT_armv5e(a, b))
+
+/* a32 + (b32 * (c32 >> 16)) >> 16 */
+#undef silk_SMLAWT
+static OPUS_INLINE opus_int32 silk_SMLAWT_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ int res;
+ __asm__(
+ "#silk_SMLAWT\n\t"
+ "smlawt %0, %1, %2, %3\n\t"
+ : "=r"(res)
+ : "r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_SMLAWT(a, b, c) (silk_SMLAWT_armv5e(a, b, c))
+
+/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */
+#undef silk_SMULBB
+static OPUS_INLINE opus_int32 silk_SMULBB_armv5e(opus_int32 a, opus_int32 b)
+{
+ int res;
+ __asm__(
+ "#silk_SMULBB\n\t"
+ "smulbb %0, %1, %2\n\t"
+ : "=r"(res)
+ : "%r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SMULBB(a, b) (silk_SMULBB_armv5e(a, b))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */
+#undef silk_SMLABB
+static OPUS_INLINE opus_int32 silk_SMLABB_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ int res;
+ __asm__(
+ "#silk_SMLABB\n\t"
+ "smlabb %0, %1, %2, %3\n\t"
+ : "=r"(res)
+ : "%r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_SMLABB(a, b, c) (silk_SMLABB_armv5e(a, b, c))
+
+/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */
+#undef silk_SMULBT
+static OPUS_INLINE opus_int32 silk_SMULBT_armv5e(opus_int32 a, opus_int32 b)
+{
+ int res;
+ __asm__(
+ "#silk_SMULBT\n\t"
+ "smulbt %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SMULBT(a, b) (silk_SMULBT_armv5e(a, b))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */
+#undef silk_SMLABT
+static OPUS_INLINE opus_int32 silk_SMLABT_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ int res;
+ __asm__(
+ "#silk_SMLABT\n\t"
+ "smlabt %0, %1, %2, %3\n\t"
+ : "=r"(res)
+ : "r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_SMLABT(a, b, c) (silk_SMLABT_armv5e(a, b, c))
+
+/* add/subtract with output saturated */
+#undef silk_ADD_SAT32
+static OPUS_INLINE opus_int32 silk_ADD_SAT32_armv5e(opus_int32 a, opus_int32 b)
+{
+ int res;
+ __asm__(
+ "#silk_ADD_SAT32\n\t"
+ "qadd %0, %1, %2\n\t"
+ : "=r"(res)
+ : "%r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_ADD_SAT32(a, b) (silk_ADD_SAT32_armv5e(a, b))
+
+#undef silk_SUB_SAT32
+static OPUS_INLINE opus_int32 silk_SUB_SAT32_armv5e(opus_int32 a, opus_int32 b)
+{
+ int res;
+ __asm__(
+ "#silk_SUB_SAT32\n\t"
+ "qsub %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SUB_SAT32(a, b) (silk_SUB_SAT32_armv5e(a, b))
+
+#undef silk_CLZ16
+static OPUS_INLINE opus_int32 silk_CLZ16_armv5(opus_int16 in16)
+{
+ int res;
+ __asm__(
+ "#silk_CLZ16\n\t"
+ "clz %0, %1;\n"
+ : "=r"(res)
+ : "r"(in16<<16|0x8000)
+ );
+ return res;
+}
+#define silk_CLZ16(in16) (silk_CLZ16_armv5(in16))
+
+#undef silk_CLZ32
+static OPUS_INLINE opus_int32 silk_CLZ32_armv5(opus_int32 in32)
+{
+ int res;
+ __asm__(
+ "#silk_CLZ32\n\t"
+ "clz %0, %1\n\t"
+ : "=r"(res)
+ : "r"(in32)
+ );
+ return res;
+}
+#define silk_CLZ32(in32) (silk_CLZ32_armv5(in32))
+
+#endif /* SILK_MACROS_ARMv5E_H */
diff --git a/external/opus-1.1.4/silk/biquad_alt.c b/external/opus-1.1.4/silk/biquad_alt.c
new file mode 100644
index 0000000..d55f5ee
--- /dev/null
+++ b/external/opus-1.1.4/silk/biquad_alt.c
@@ -0,0 +1,78 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+/* *
+ * silk_biquad_alt.c *
+ * *
+ * Second order ARMA filter *
+ * Can handle slowly varying filter coefficients *
+ * */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Second order ARMA filter, alternative implementation */
+void silk_biquad_alt(
+ const opus_int16 *in, /* I input signal */
+ const opus_int32 *B_Q28, /* I MA coefficients [3] */
+ const opus_int32 *A_Q28, /* I AR coefficients [2] */
+ opus_int32 *S, /* I/O State vector [2] */
+ opus_int16 *out, /* O output signal */
+ const opus_int32 len, /* I signal length (must be even) */
+ opus_int stride /* I Operate on interleaved signal if > 1 */
+)
+{
+ /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
+ opus_int k;
+ opus_int32 inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14;
+
+ /* Negate A_Q28 values and split in two parts */
+ A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */
+ A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */
+ A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */
+ A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */
+
+ for( k = 0; k < len; k++ ) {
+ /* S[ 0 ], S[ 1 ]: Q12 */
+ inval = in[ k * stride ];
+ out32_Q14 = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 );
+
+ S[ 0 ] = S[1] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A0_L_Q28 ), 14 );
+ S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 );
+ S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval);
+
+ S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A1_L_Q28 ), 14 );
+ S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 );
+ S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval );
+
+ /* Scale back to Q0 and saturate */
+ out[ k * stride ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) );
+ }
+}
diff --git a/external/opus-1.1.4/silk/bwexpander.c b/external/opus-1.1.4/silk/bwexpander.c
new file mode 100644
index 0000000..2eb4456
--- /dev/null
+++ b/external/opus-1.1.4/silk/bwexpander.c
@@ -0,0 +1,51 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander(
+ opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I Length of ar */
+ opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */
+)
+{
+ opus_int i;
+ opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536;
+
+ /* NB: Dont use silk_SMULWB, instead of silk_RSHIFT_ROUND( silk_MUL(), 16 ), below. */
+ /* Bias in silk_SMULWB can lead to unstable filters */
+ for( i = 0; i < d - 1; i++ ) {
+ ar[ i ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ i ] ), 16 );
+ chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 );
+ }
+ ar[ d - 1 ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ d - 1 ] ), 16 );
+}
diff --git a/external/opus-1.1.4/silk/bwexpander_32.c b/external/opus-1.1.4/silk/bwexpander_32.c
new file mode 100644
index 0000000..d0010f7
--- /dev/null
+++ b/external/opus-1.1.4/silk/bwexpander_32.c
@@ -0,0 +1,50 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander_32(
+ opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I Length of ar */
+ opus_int32 chirp_Q16 /* I Chirp factor in Q16 */
+)
+{
+ opus_int i;
+ opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536;
+
+ for( i = 0; i < d - 1; i++ ) {
+ ar[ i ] = silk_SMULWW( chirp_Q16, ar[ i ] );
+ chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 );
+ }
+ ar[ d - 1 ] = silk_SMULWW( chirp_Q16, ar[ d - 1 ] );
+}
+
diff --git a/external/opus-1.1.4/silk/check_control_input.c b/external/opus-1.1.4/silk/check_control_input.c
new file mode 100644
index 0000000..b5de9ce
--- /dev/null
+++ b/external/opus-1.1.4/silk/check_control_input.c
@@ -0,0 +1,106 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "control.h"
+#include "errors.h"
+
+/* Check encoder control struct */
+opus_int check_control_input(
+ silk_EncControlStruct *encControl /* I Control structure */
+)
+{
+ silk_assert( encControl != NULL );
+
+ if( ( ( encControl->API_sampleRate != 8000 ) &&
+ ( encControl->API_sampleRate != 12000 ) &&
+ ( encControl->API_sampleRate != 16000 ) &&
+ ( encControl->API_sampleRate != 24000 ) &&
+ ( encControl->API_sampleRate != 32000 ) &&
+ ( encControl->API_sampleRate != 44100 ) &&
+ ( encControl->API_sampleRate != 48000 ) ) ||
+ ( ( encControl->desiredInternalSampleRate != 8000 ) &&
+ ( encControl->desiredInternalSampleRate != 12000 ) &&
+ ( encControl->desiredInternalSampleRate != 16000 ) ) ||
+ ( ( encControl->maxInternalSampleRate != 8000 ) &&
+ ( encControl->maxInternalSampleRate != 12000 ) &&
+ ( encControl->maxInternalSampleRate != 16000 ) ) ||
+ ( ( encControl->minInternalSampleRate != 8000 ) &&
+ ( encControl->minInternalSampleRate != 12000 ) &&
+ ( encControl->minInternalSampleRate != 16000 ) ) ||
+ ( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) ||
+ ( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) ||
+ ( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) {
+ silk_assert( 0 );
+ return SILK_ENC_FS_NOT_SUPPORTED;
+ }
+ if( encControl->payloadSize_ms != 10 &&
+ encControl->payloadSize_ms != 20 &&
+ encControl->payloadSize_ms != 40 &&
+ encControl->payloadSize_ms != 60 ) {
+ silk_assert( 0 );
+ return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
+ }
+ if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_LOSS_RATE;
+ }
+ if( encControl->useDTX < 0 || encControl->useDTX > 1 ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_DTX_SETTING;
+ }
+ if( encControl->useCBR < 0 || encControl->useCBR > 1 ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_CBR_SETTING;
+ }
+ if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_INBAND_FEC_SETTING;
+ }
+ if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+ }
+ if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+ }
+ if( encControl->nChannelsInternal > encControl->nChannelsAPI ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+ }
+ if( encControl->complexity < 0 || encControl->complexity > 10 ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_COMPLEXITY_SETTING;
+ }
+
+ return SILK_NO_ERROR;
+}
diff --git a/external/opus-1.1.4/silk/code_signs.c b/external/opus-1.1.4/silk/code_signs.c
new file mode 100644
index 0000000..dfd1dca
--- /dev/null
+++ b/external/opus-1.1.4/silk/code_signs.c
@@ -0,0 +1,115 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/*#define silk_enc_map(a) ((a) > 0 ? 1 : 0)*/
+/*#define silk_dec_map(a) ((a) > 0 ? 1 : -1)*/
+/* shifting avoids if-statement */
+#define silk_enc_map(a) ( silk_RSHIFT( (a), 15 ) + 1 )
+#define silk_dec_map(a) ( silk_LSHIFT( (a), 1 ) - 1 )
+
+/* Encodes signs of excitation */
+void silk_encode_signs(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ const opus_int8 pulses[], /* I pulse signal */
+ opus_int length, /* I length of input */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I Quantization offset type */
+ const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */
+)
+{
+ opus_int i, j, p;
+ opus_uint8 icdf[ 2 ];
+ const opus_int8 *q_ptr;
+ const opus_uint8 *icdf_ptr;
+
+ icdf[ 1 ] = 0;
+ q_ptr = pulses;
+ i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) );
+ icdf_ptr = &silk_sign_iCDF[ i ];
+ length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH );
+ for( i = 0; i < length; i++ ) {
+ p = sum_pulses[ i ];
+ if( p > 0 ) {
+ icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ];
+ for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) {
+ if( q_ptr[ j ] != 0 ) {
+ ec_enc_icdf( psRangeEnc, silk_enc_map( q_ptr[ j ]), icdf, 8 );
+ }
+ }
+ }
+ q_ptr += SHELL_CODEC_FRAME_LENGTH;
+ }
+}
+
+/* Decodes signs of excitation */
+void silk_decode_signs(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 pulses[], /* I/O pulse signal */
+ opus_int length, /* I length of input */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I Quantization offset type */
+ const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */
+)
+{
+ opus_int i, j, p;
+ opus_uint8 icdf[ 2 ];
+ opus_int16 *q_ptr;
+ const opus_uint8 *icdf_ptr;
+
+ icdf[ 1 ] = 0;
+ q_ptr = pulses;
+ i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) );
+ icdf_ptr = &silk_sign_iCDF[ i ];
+ length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH );
+ for( i = 0; i < length; i++ ) {
+ p = sum_pulses[ i ];
+ if( p > 0 ) {
+ icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ];
+ for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) {
+ if( q_ptr[ j ] > 0 ) {
+ /* attach sign */
+#if 0
+ /* conditional implementation */
+ if( ec_dec_icdf( psRangeDec, icdf, 8 ) == 0 ) {
+ q_ptr[ j ] = -q_ptr[ j ];
+ }
+#else
+ /* implementation with shift, subtraction, multiplication */
+ q_ptr[ j ] *= silk_dec_map( ec_dec_icdf( psRangeDec, icdf, 8 ) );
+#endif
+ }
+ }
+ }
+ q_ptr += SHELL_CODEC_FRAME_LENGTH;
+ }
+}
diff --git a/external/opus-1.1.4/silk/control.h b/external/opus-1.1.4/silk/control.h
new file mode 100644
index 0000000..747e542
--- /dev/null
+++ b/external/opus-1.1.4/silk/control.h
@@ -0,0 +1,142 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_CONTROL_H
+#define SILK_CONTROL_H
+
+#include "typedef.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Decoder API flags */
+#define FLAG_DECODE_NORMAL 0
+#define FLAG_PACKET_LOST 1
+#define FLAG_DECODE_LBRR 2
+
+/***********************************************/
+/* Structure for controlling encoder operation */
+/***********************************************/
+typedef struct {
+ /* I: Number of channels; 1/2 */
+ opus_int32 nChannelsAPI;
+
+ /* I: Number of channels; 1/2 */
+ opus_int32 nChannelsInternal;
+
+ /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */
+ opus_int32 API_sampleRate;
+
+ /* I: Maximum internal sampling rate in Hertz; 8000/12000/16000 */
+ opus_int32 maxInternalSampleRate;
+
+ /* I: Minimum internal sampling rate in Hertz; 8000/12000/16000 */
+ opus_int32 minInternalSampleRate;
+
+ /* I: Soft request for internal sampling rate in Hertz; 8000/12000/16000 */
+ opus_int32 desiredInternalSampleRate;
+
+ /* I: Number of samples per packet in milliseconds; 10/20/40/60 */
+ opus_int payloadSize_ms;
+
+ /* I: Bitrate during active speech in bits/second; internally limited */
+ opus_int32 bitRate;
+
+ /* I: Uplink packet loss in percent (0-100) */
+ opus_int packetLossPercentage;
+
+ /* I: Complexity mode; 0 is lowest, 10 is highest complexity */
+ opus_int complexity;
+
+ /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */
+ opus_int useInBandFEC;
+
+ /* I: Flag to enable discontinuous transmission (DTX); 0/1 */
+ opus_int useDTX;
+
+ /* I: Flag to use constant bitrate */
+ opus_int useCBR;
+
+ /* I: Maximum number of bits allowed for the frame */
+ opus_int maxBits;
+
+ /* I: Causes a smooth downmix to mono */
+ opus_int toMono;
+
+ /* I: Opus encoder is allowing us to switch bandwidth */
+ opus_int opusCanSwitch;
+
+ /* I: Make frames as independent as possible (but still use LPC) */
+ opus_int reducedDependency;
+
+ /* O: Internal sampling rate used, in Hertz; 8000/12000/16000 */
+ opus_int32 internalSampleRate;
+
+ /* O: Flag that bandwidth switching is allowed (because low voice activity) */
+ opus_int allowBandwidthSwitch;
+
+ /* O: Flag that SILK runs in WB mode without variable LP filter (use for switching between WB/SWB/FB) */
+ opus_int inWBmodeWithoutVariableLP;
+
+ /* O: Stereo width */
+ opus_int stereoWidth_Q14;
+
+ /* O: Tells the Opus encoder we're ready to switch */
+ opus_int switchReady;
+
+} silk_EncControlStruct;
+
+/**************************************************************************/
+/* Structure for controlling decoder operation and reading decoder status */
+/**************************************************************************/
+typedef struct {
+ /* I: Number of channels; 1/2 */
+ opus_int32 nChannelsAPI;
+
+ /* I: Number of channels; 1/2 */
+ opus_int32 nChannelsInternal;
+
+ /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */
+ opus_int32 API_sampleRate;
+
+ /* I: Internal sampling rate used, in Hertz; 8000/12000/16000 */
+ opus_int32 internalSampleRate;
+
+ /* I: Number of samples per packet in milliseconds; 10/20/40/60 */
+ opus_int payloadSize_ms;
+
+ /* O: Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz */
+ opus_int prevPitchLag;
+} silk_DecControlStruct;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/silk/control_SNR.c b/external/opus-1.1.4/silk/control_SNR.c
new file mode 100644
index 0000000..cee87eb
--- /dev/null
+++ b/external/opus-1.1.4/silk/control_SNR.c
@@ -0,0 +1,76 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "tuning_parameters.h"
+
+/* Control SNR of redidual quantizer */
+opus_int silk_control_SNR(
+ silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
+ opus_int32 TargetRate_bps /* I Target max bitrate (bps) */
+)
+{
+ opus_int k, ret = SILK_NO_ERROR;
+ opus_int32 frac_Q6;
+ const opus_int32 *rateTable;
+
+ /* Set bitrate/coding quality */
+ TargetRate_bps = silk_LIMIT( TargetRate_bps, MIN_TARGET_RATE_BPS, MAX_TARGET_RATE_BPS );
+ if( TargetRate_bps != psEncC->TargetRate_bps ) {
+ psEncC->TargetRate_bps = TargetRate_bps;
+
+ /* If new TargetRate_bps, translate to SNR_dB value */
+ if( psEncC->fs_kHz == 8 ) {
+ rateTable = silk_TargetRate_table_NB;
+ } else if( psEncC->fs_kHz == 12 ) {
+ rateTable = silk_TargetRate_table_MB;
+ } else {
+ rateTable = silk_TargetRate_table_WB;
+ }
+
+ /* Reduce bitrate for 10 ms modes in these calculations */
+ if( psEncC->nb_subfr == 2 ) {
+ TargetRate_bps -= REDUCE_BITRATE_10_MS_BPS;
+ }
+
+ /* Find bitrate interval in table and interpolate */
+ for( k = 1; k < TARGET_RATE_TAB_SZ; k++ ) {
+ if( TargetRate_bps <= rateTable[ k ] ) {
+ frac_Q6 = silk_DIV32( silk_LSHIFT( TargetRate_bps - rateTable[ k - 1 ], 6 ),
+ rateTable[ k ] - rateTable[ k - 1 ] );
+ psEncC->SNR_dB_Q7 = silk_LSHIFT( silk_SNR_table_Q1[ k - 1 ], 6 ) + silk_MUL( frac_Q6, silk_SNR_table_Q1[ k ] - silk_SNR_table_Q1[ k - 1 ] );
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/external/opus-1.1.4/silk/control_audio_bandwidth.c b/external/opus-1.1.4/silk/control_audio_bandwidth.c
new file mode 100644
index 0000000..4f9bc5c
--- /dev/null
+++ b/external/opus-1.1.4/silk/control_audio_bandwidth.c
@@ -0,0 +1,126 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "tuning_parameters.h"
+
+/* Control internal sampling rate */
+opus_int silk_control_audio_bandwidth(
+ silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
+ silk_EncControlStruct *encControl /* I Control structure */
+)
+{
+ opus_int fs_kHz;
+ opus_int32 fs_Hz;
+
+ fs_kHz = psEncC->fs_kHz;
+ fs_Hz = silk_SMULBB( fs_kHz, 1000 );
+ if( fs_Hz == 0 ) {
+ /* Encoder has just been initialized */
+ fs_Hz = silk_min( psEncC->desiredInternal_fs_Hz, psEncC->API_fs_Hz );
+ fs_kHz = silk_DIV32_16( fs_Hz, 1000 );
+ } else if( fs_Hz > psEncC->API_fs_Hz || fs_Hz > psEncC->maxInternal_fs_Hz || fs_Hz < psEncC->minInternal_fs_Hz ) {
+ /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */
+ fs_Hz = psEncC->API_fs_Hz;
+ fs_Hz = silk_min( fs_Hz, psEncC->maxInternal_fs_Hz );
+ fs_Hz = silk_max( fs_Hz, psEncC->minInternal_fs_Hz );
+ fs_kHz = silk_DIV32_16( fs_Hz, 1000 );
+ } else {
+ /* State machine for the internal sampling rate switching */
+ if( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES ) {
+ /* Stop transition phase */
+ psEncC->sLP.mode = 0;
+ }
+ if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) {
+ /* Check if we should switch down */
+ if( silk_SMULBB( psEncC->fs_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz )
+ {
+ /* Switch down */
+ if( psEncC->sLP.mode == 0 ) {
+ /* New transition */
+ psEncC->sLP.transition_frame_no = TRANSITION_FRAMES;
+
+ /* Reset transition filter state */
+ silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) );
+ }
+ if( encControl->opusCanSwitch ) {
+ /* Stop transition phase */
+ psEncC->sLP.mode = 0;
+
+ /* Switch to a lower sample frequency */
+ fs_kHz = psEncC->fs_kHz == 16 ? 12 : 8;
+ } else {
+ if( psEncC->sLP.transition_frame_no <= 0 ) {
+ encControl->switchReady = 1;
+ /* Make room for redundancy */
+ encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
+ } else {
+ /* Direction: down (at double speed) */
+ psEncC->sLP.mode = -2;
+ }
+ }
+ }
+ else
+ /* Check if we should switch up */
+ if( silk_SMULBB( psEncC->fs_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz )
+ {
+ /* Switch up */
+ if( encControl->opusCanSwitch ) {
+ /* Switch to a higher sample frequency */
+ fs_kHz = psEncC->fs_kHz == 8 ? 12 : 16;
+
+ /* New transition */
+ psEncC->sLP.transition_frame_no = 0;
+
+ /* Reset transition filter state */
+ silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) );
+
+ /* Direction: up */
+ psEncC->sLP.mode = 1;
+ } else {
+ if( psEncC->sLP.mode == 0 ) {
+ encControl->switchReady = 1;
+ /* Make room for redundancy */
+ encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
+ } else {
+ /* Direction: up */
+ psEncC->sLP.mode = 1;
+ }
+ }
+ } else {
+ if (psEncC->sLP.mode<0)
+ psEncC->sLP.mode = 1;
+ }
+ }
+ }
+
+ return fs_kHz;
+}
diff --git a/external/opus-1.1.4/silk/control_codec.c b/external/opus-1.1.4/silk/control_codec.c
new file mode 100644
index 0000000..044eea3
--- /dev/null
+++ b/external/opus-1.1.4/silk/control_codec.c
@@ -0,0 +1,428 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef FIXED_POINT
+#include "main_FIX.h"
+#define silk_encoder_state_Fxx silk_encoder_state_FIX
+#else
+#include "main_FLP.h"
+#define silk_encoder_state_Fxx silk_encoder_state_FLP
+#endif
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+#include "pitch_est_defines.h"
+
+static opus_int silk_setup_resamplers(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz /* I */
+);
+
+static opus_int silk_setup_fs(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz, /* I */
+ opus_int PacketSize_ms /* I */
+);
+
+static opus_int silk_setup_complexity(
+ silk_encoder_state *psEncC, /* I/O */
+ opus_int Complexity /* I */
+);
+
+static OPUS_INLINE opus_int silk_setup_LBRR(
+ silk_encoder_state *psEncC, /* I/O */
+ const opus_int32 TargetRate_bps /* I */
+);
+
+
+/* Control encoder */
+opus_int silk_control_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
+ silk_EncControlStruct *encControl, /* I Control structure */
+ const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */
+ const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
+ const opus_int channelNb, /* I Channel number */
+ const opus_int force_fs_kHz
+)
+{
+ opus_int fs_kHz, ret = 0;
+
+ psEnc->sCmn.useDTX = encControl->useDTX;
+ psEnc->sCmn.useCBR = encControl->useCBR;
+ psEnc->sCmn.API_fs_Hz = encControl->API_sampleRate;
+ psEnc->sCmn.maxInternal_fs_Hz = encControl->maxInternalSampleRate;
+ psEnc->sCmn.minInternal_fs_Hz = encControl->minInternalSampleRate;
+ psEnc->sCmn.desiredInternal_fs_Hz = encControl->desiredInternalSampleRate;
+ psEnc->sCmn.useInBandFEC = encControl->useInBandFEC;
+ psEnc->sCmn.nChannelsAPI = encControl->nChannelsAPI;
+ psEnc->sCmn.nChannelsInternal = encControl->nChannelsInternal;
+ psEnc->sCmn.allow_bandwidth_switch = allow_bw_switch;
+ psEnc->sCmn.channelNb = channelNb;
+
+ if( psEnc->sCmn.controlled_since_last_payload != 0 && psEnc->sCmn.prefillFlag == 0 ) {
+ if( psEnc->sCmn.API_fs_Hz != psEnc->sCmn.prev_API_fs_Hz && psEnc->sCmn.fs_kHz > 0 ) {
+ /* Change in API sampling rate in the middle of encoding a packet */
+ ret += silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz );
+ }
+ return ret;
+ }
+
+ /* Beyond this point we know that there are no previously coded frames in the payload buffer */
+
+ /********************************************/
+ /* Determine internal sampling rate */
+ /********************************************/
+ fs_kHz = silk_control_audio_bandwidth( &psEnc->sCmn, encControl );
+ if( force_fs_kHz ) {
+ fs_kHz = force_fs_kHz;
+ }
+ /********************************************/
+ /* Prepare resampler and buffered data */
+ /********************************************/
+ ret += silk_setup_resamplers( psEnc, fs_kHz );
+
+ /********************************************/
+ /* Set internal sampling frequency */
+ /********************************************/
+ ret += silk_setup_fs( psEnc, fs_kHz, encControl->payloadSize_ms );
+
+ /********************************************/
+ /* Set encoding complexity */
+ /********************************************/
+ ret += silk_setup_complexity( &psEnc->sCmn, encControl->complexity );
+
+ /********************************************/
+ /* Set packet loss rate measured by farend */
+ /********************************************/
+ psEnc->sCmn.PacketLoss_perc = encControl->packetLossPercentage;
+
+ /********************************************/
+ /* Set LBRR usage */
+ /********************************************/
+ ret += silk_setup_LBRR( &psEnc->sCmn, TargetRate_bps );
+
+ psEnc->sCmn.controlled_since_last_payload = 1;
+
+ return ret;
+}
+
+static opus_int silk_setup_resamplers(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz /* I */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+ SAVE_STACK;
+
+ if( psEnc->sCmn.fs_kHz != fs_kHz || psEnc->sCmn.prev_API_fs_Hz != psEnc->sCmn.API_fs_Hz )
+ {
+ if( psEnc->sCmn.fs_kHz == 0 ) {
+ /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
+ ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000, 1 );
+ } else {
+ VARDECL( opus_int16, x_buf_API_fs_Hz );
+ VARDECL( silk_resampler_state_struct, temp_resampler_state );
+#ifdef FIXED_POINT
+ opus_int16 *x_bufFIX = psEnc->x_buf;
+#else
+ VARDECL( opus_int16, x_bufFIX );
+ opus_int32 new_buf_samples;
+#endif
+ opus_int32 api_buf_samples;
+ opus_int32 old_buf_samples;
+ opus_int32 buf_length_ms;
+
+ buf_length_ms = silk_LSHIFT( psEnc->sCmn.nb_subfr * 5, 1 ) + LA_SHAPE_MS;
+ old_buf_samples = buf_length_ms * psEnc->sCmn.fs_kHz;
+
+#ifndef FIXED_POINT
+ new_buf_samples = buf_length_ms * fs_kHz;
+ ALLOC( x_bufFIX, silk_max( old_buf_samples, new_buf_samples ),
+ opus_int16 );
+ silk_float2short_array( x_bufFIX, psEnc->x_buf, old_buf_samples );
+#endif
+
+ /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */
+ ALLOC( temp_resampler_state, 1, silk_resampler_state_struct );
+ ret += silk_resampler_init( temp_resampler_state, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz, 0 );
+
+ /* Calculate number of samples to temporarily upsample */
+ api_buf_samples = buf_length_ms * silk_DIV32_16( psEnc->sCmn.API_fs_Hz, 1000 );
+
+ /* Temporary resampling of x_buf data to API_fs_Hz */
+ ALLOC( x_buf_API_fs_Hz, api_buf_samples, opus_int16 );
+ ret += silk_resampler( temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, old_buf_samples );
+
+ /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
+ ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, silk_SMULBB( fs_kHz, 1000 ), 1 );
+
+ /* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */
+ ret += silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, api_buf_samples );
+
+#ifndef FIXED_POINT
+ silk_short2float_array( psEnc->x_buf, x_bufFIX, new_buf_samples);
+#endif
+ }
+ }
+
+ psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz;
+
+ RESTORE_STACK;
+ return ret;
+}
+
+static opus_int silk_setup_fs(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz, /* I */
+ opus_int PacketSize_ms /* I */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+
+ /* Set packet size */
+ if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) {
+ if( ( PacketSize_ms != 10 ) &&
+ ( PacketSize_ms != 20 ) &&
+ ( PacketSize_ms != 40 ) &&
+ ( PacketSize_ms != 60 ) ) {
+ ret = SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
+ }
+ if( PacketSize_ms <= 10 ) {
+ psEnc->sCmn.nFramesPerPacket = 1;
+ psEnc->sCmn.nb_subfr = PacketSize_ms == 10 ? 2 : 1;
+ psEnc->sCmn.frame_length = silk_SMULBB( PacketSize_ms, fs_kHz );
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz );
+ if( psEnc->sCmn.fs_kHz == 8 ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
+ }
+ } else {
+ psEnc->sCmn.nFramesPerPacket = silk_DIV32_16( PacketSize_ms, MAX_FRAME_LENGTH_MS );
+ psEnc->sCmn.nb_subfr = MAX_NB_SUBFR;
+ psEnc->sCmn.frame_length = silk_SMULBB( 20, fs_kHz );
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz );
+ if( psEnc->sCmn.fs_kHz == 8 ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF;
+ }
+ }
+ psEnc->sCmn.PacketSize_ms = PacketSize_ms;
+ psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */
+ }
+
+ /* Set internal sampling frequency */
+ silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 );
+ silk_assert( psEnc->sCmn.nb_subfr == 2 || psEnc->sCmn.nb_subfr == 4 );
+ if( psEnc->sCmn.fs_kHz != fs_kHz ) {
+ /* reset part of the state */
+ silk_memset( &psEnc->sShape, 0, sizeof( psEnc->sShape ) );
+ silk_memset( &psEnc->sPrefilt, 0, sizeof( psEnc->sPrefilt ) );
+ silk_memset( &psEnc->sCmn.sNSQ, 0, sizeof( psEnc->sCmn.sNSQ ) );
+ silk_memset( psEnc->sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
+ silk_memset( &psEnc->sCmn.sLP.In_LP_State, 0, sizeof( psEnc->sCmn.sLP.In_LP_State ) );
+ psEnc->sCmn.inputBufIx = 0;
+ psEnc->sCmn.nFramesEncoded = 0;
+ psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */
+
+ /* Initialize non-zero parameters */
+ psEnc->sCmn.prevLag = 100;
+ psEnc->sCmn.first_frame_after_reset = 1;
+ psEnc->sPrefilt.lagPrev = 100;
+ psEnc->sShape.LastGainIndex = 10;
+ psEnc->sCmn.sNSQ.lagPrev = 100;
+ psEnc->sCmn.sNSQ.prev_gain_Q16 = 65536;
+ psEnc->sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY;
+
+ psEnc->sCmn.fs_kHz = fs_kHz;
+ if( psEnc->sCmn.fs_kHz == 8 ) {
+ if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
+ }
+ } else {
+ if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
+ }
+ }
+ if( psEnc->sCmn.fs_kHz == 8 || psEnc->sCmn.fs_kHz == 12 ) {
+ psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER;
+ psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_NB_MB;
+ } else {
+ psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER;
+ psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_WB;
+ }
+ psEnc->sCmn.subfr_length = SUB_FRAME_LENGTH_MS * fs_kHz;
+ psEnc->sCmn.frame_length = silk_SMULBB( psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr );
+ psEnc->sCmn.ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz );
+ psEnc->sCmn.la_pitch = silk_SMULBB( LA_PITCH_MS, fs_kHz );
+ psEnc->sCmn.max_pitch_lag = silk_SMULBB( 18, fs_kHz );
+ if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz );
+ } else {
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz );
+ }
+ if( psEnc->sCmn.fs_kHz == 16 ) {
+ psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_WB, 9 );
+ psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF;
+ } else if( psEnc->sCmn.fs_kHz == 12 ) {
+ psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_MB, 9 );
+ psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF;
+ } else {
+ psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_NB, 9 );
+ psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform4_iCDF;
+ }
+ }
+
+ /* Check that settings are valid */
+ silk_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length );
+
+ return ret;
+}
+
+static opus_int silk_setup_complexity(
+ silk_encoder_state *psEncC, /* I/O */
+ opus_int Complexity /* I */
+)
+{
+ opus_int ret = 0;
+
+ /* Set encoding complexity */
+ silk_assert( Complexity >= 0 && Complexity <= 10 );
+ if( Complexity < 2 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 );
+ psEncC->pitchEstimationLPCOrder = 6;
+ psEncC->shapingLPCOrder = 8;
+ psEncC->la_shape = 3 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 1;
+ psEncC->useInterpolatedNLSFs = 0;
+ psEncC->LTPQuantLowComplexity = 1;
+ psEncC->NLSF_MSVQ_Survivors = 2;
+ psEncC->warping_Q16 = 0;
+ } else if( Complexity < 4 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 );
+ psEncC->pitchEstimationLPCOrder = 8;
+ psEncC->shapingLPCOrder = 10;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 1;
+ psEncC->useInterpolatedNLSFs = 0;
+ psEncC->LTPQuantLowComplexity = 0;
+ psEncC->NLSF_MSVQ_Survivors = 4;
+ psEncC->warping_Q16 = 0;
+ } else if( Complexity < 6 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.74, 16 );
+ psEncC->pitchEstimationLPCOrder = 10;
+ psEncC->shapingLPCOrder = 12;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 2;
+ psEncC->useInterpolatedNLSFs = 1;
+ psEncC->LTPQuantLowComplexity = 0;
+ psEncC->NLSF_MSVQ_Survivors = 8;
+ psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+ } else if( Complexity < 8 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.72, 16 );
+ psEncC->pitchEstimationLPCOrder = 12;
+ psEncC->shapingLPCOrder = 14;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 3;
+ psEncC->useInterpolatedNLSFs = 1;
+ psEncC->LTPQuantLowComplexity = 0;
+ psEncC->NLSF_MSVQ_Survivors = 16;
+ psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+ } else {
+ psEncC->pitchEstimationComplexity = SILK_PE_MAX_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.7, 16 );
+ psEncC->pitchEstimationLPCOrder = 16;
+ psEncC->shapingLPCOrder = 16;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES;
+ psEncC->useInterpolatedNLSFs = 1;
+ psEncC->LTPQuantLowComplexity = 0;
+ psEncC->NLSF_MSVQ_Survivors = 32;
+ psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+ }
+
+ /* Do not allow higher pitch estimation LPC order than predict LPC order */
+ psEncC->pitchEstimationLPCOrder = silk_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder );
+ psEncC->shapeWinLength = SUB_FRAME_LENGTH_MS * psEncC->fs_kHz + 2 * psEncC->la_shape;
+ psEncC->Complexity = Complexity;
+
+ silk_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER );
+ silk_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER );
+ silk_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES );
+ silk_assert( psEncC->warping_Q16 <= 32767 );
+ silk_assert( psEncC->la_shape <= LA_SHAPE_MAX );
+ silk_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX );
+ silk_assert( psEncC->NLSF_MSVQ_Survivors <= NLSF_VQ_MAX_SURVIVORS );
+
+ return ret;
+}
+
+static OPUS_INLINE opus_int silk_setup_LBRR(
+ silk_encoder_state *psEncC, /* I/O */
+ const opus_int32 TargetRate_bps /* I */
+)
+{
+ opus_int LBRR_in_previous_packet, ret = SILK_NO_ERROR;
+ opus_int32 LBRR_rate_thres_bps;
+
+ LBRR_in_previous_packet = psEncC->LBRR_enabled;
+ psEncC->LBRR_enabled = 0;
+ if( psEncC->useInBandFEC && psEncC->PacketLoss_perc > 0 ) {
+ if( psEncC->fs_kHz == 8 ) {
+ LBRR_rate_thres_bps = LBRR_NB_MIN_RATE_BPS;
+ } else if( psEncC->fs_kHz == 12 ) {
+ LBRR_rate_thres_bps = LBRR_MB_MIN_RATE_BPS;
+ } else {
+ LBRR_rate_thres_bps = LBRR_WB_MIN_RATE_BPS;
+ }
+ LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, 125 - silk_min( psEncC->PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) );
+
+ if( TargetRate_bps > LBRR_rate_thres_bps ) {
+ /* Set gain increase for coding LBRR excitation */
+ if( LBRR_in_previous_packet == 0 ) {
+ /* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */
+ psEncC->LBRR_GainIncreases = 7;
+ } else {
+ psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 );
+ }
+ psEncC->LBRR_enabled = 1;
+ }
+ }
+
+ return ret;
+}
diff --git a/external/opus-1.1.4/silk/debug.c b/external/opus-1.1.4/silk/debug.c
new file mode 100644
index 0000000..9253faf
--- /dev/null
+++ b/external/opus-1.1.4/silk/debug.c
@@ -0,0 +1,170 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "debug.h"
+#include "SigProc_FIX.h"
+
+#if SILK_TIC_TOC
+
+#ifdef _WIN32
+
+#if (defined(_WIN32) || defined(_WINCE))
+#include <windows.h> /* timer */
+#else /* Linux or Mac*/
+#include <sys/time.h>
+#endif
+
+unsigned long silk_GetHighResolutionTime(void) /* O time in usec*/
+{
+ /* Returns a time counter in microsec */
+ /* the resolution is platform dependent */
+ /* but is typically 1.62 us resolution */
+ LARGE_INTEGER lpPerformanceCount;
+ LARGE_INTEGER lpFrequency;
+ QueryPerformanceCounter(&lpPerformanceCount);
+ QueryPerformanceFrequency(&lpFrequency);
+ return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart);
+}
+#else /* Linux or Mac*/
+unsigned long GetHighResolutionTime(void) /* O time in usec*/
+{
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ return((tv.tv_sec*1000000)+(tv.tv_usec));
+}
+#endif
+
+int silk_Timer_nTimers = 0;
+int silk_Timer_depth_ctr = 0;
+char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN];
+#ifdef WIN32
+LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX];
+#else
+unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX];
+#endif
+unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX];
+opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX];
+opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX];
+opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX];
+opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX];
+
+#ifdef WIN32
+void silk_TimerSave(char *file_name)
+{
+ if( silk_Timer_nTimers > 0 )
+ {
+ int k;
+ FILE *fp;
+ LARGE_INTEGER lpFrequency;
+ LARGE_INTEGER lpPerformanceCount1, lpPerformanceCount2;
+ int del = 0x7FFFFFFF;
+ double avg, sum_avg;
+ /* estimate overhead of calling performance counters */
+ for( k = 0; k < 1000; k++ ) {
+ QueryPerformanceCounter(&lpPerformanceCount1);
+ QueryPerformanceCounter(&lpPerformanceCount2);
+ lpPerformanceCount2.QuadPart -= lpPerformanceCount1.QuadPart;
+ if( (int)lpPerformanceCount2.LowPart < del )
+ del = lpPerformanceCount2.LowPart;
+ }
+ QueryPerformanceFrequency(&lpFrequency);
+ /* print results to file */
+ sum_avg = 0.0f;
+ for( k = 0; k < silk_Timer_nTimers; k++ ) {
+ if (silk_Timer_depth[k] == 0) {
+ sum_avg += (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart * silk_Timer_cnt[k];
+ }
+ }
+ fp = fopen(file_name, "w");
+ fprintf(fp, " min avg %% max count\n");
+ for( k = 0; k < silk_Timer_nTimers; k++ ) {
+ if (silk_Timer_depth[k] == 0) {
+ fprintf(fp, "%-28s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 1) {
+ fprintf(fp, " %-27s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 2) {
+ fprintf(fp, " %-26s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 3) {
+ fprintf(fp, " %-25s", silk_Timer_tags[k]);
+ } else {
+ fprintf(fp, " %-24s", silk_Timer_tags[k]);
+ }
+ avg = (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart;
+ fprintf(fp, "%8.2f", (1e6 * (silk_max_64(silk_Timer_min[k] - del, 0))) / lpFrequency.QuadPart);
+ fprintf(fp, "%12.2f %6.2f", avg, 100.0 * avg / sum_avg * silk_Timer_cnt[k]);
+ fprintf(fp, "%12.2f", (1e6 * (silk_max_64(silk_Timer_max[k] - del, 0))) / lpFrequency.QuadPart);
+ fprintf(fp, "%10d\n", silk_Timer_cnt[k]);
+ }
+ fprintf(fp, " microseconds\n");
+ fclose(fp);
+ }
+}
+#else
+void silk_TimerSave(char *file_name)
+{
+ if( silk_Timer_nTimers > 0 )
+ {
+ int k;
+ FILE *fp;
+ /* print results to file */
+ fp = fopen(file_name, "w");
+ fprintf(fp, " min avg max count\n");
+ for( k = 0; k < silk_Timer_nTimers; k++ )
+ {
+ if (silk_Timer_depth[k] == 0) {
+ fprintf(fp, "%-28s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 1) {
+ fprintf(fp, " %-27s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 2) {
+ fprintf(fp, " %-26s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 3) {
+ fprintf(fp, " %-25s", silk_Timer_tags[k]);
+ } else {
+ fprintf(fp, " %-24s", silk_Timer_tags[k]);
+ }
+ fprintf(fp, "%d ", silk_Timer_min[k]);
+ fprintf(fp, "%f ", (double)silk_Timer_sum[k] / (double)silk_Timer_cnt[k]);
+ fprintf(fp, "%d ", silk_Timer_max[k]);
+ fprintf(fp, "%10d\n", silk_Timer_cnt[k]);
+ }
+ fprintf(fp, " microseconds\n");
+ fclose(fp);
+ }
+}
+#endif
+
+#endif /* SILK_TIC_TOC */
+
+#if SILK_DEBUG
+FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ];
+int silk_debug_store_count = 0;
+#endif /* SILK_DEBUG */
+
diff --git a/external/opus-1.1.4/silk/debug.h b/external/opus-1.1.4/silk/debug.h
new file mode 100644
index 0000000..efb6d3e
--- /dev/null
+++ b/external/opus-1.1.4/silk/debug.h
@@ -0,0 +1,279 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_DEBUG_H
+#define SILK_DEBUG_H
+
+#include "typedef.h"
+#include <stdio.h> /* file writing */
+#include <string.h> /* strcpy, strcmp */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+unsigned long GetHighResolutionTime(void); /* O time in usec*/
+
+/* make SILK_DEBUG dependent on compiler's _DEBUG */
+#if defined _WIN32
+ #ifdef _DEBUG
+ #define SILK_DEBUG 1
+ #else
+ #define SILK_DEBUG 0
+ #endif
+
+ /* overrule the above */
+ #if 0
+ /* #define NO_ASSERTS*/
+ #undef SILK_DEBUG
+ #define SILK_DEBUG 1
+ #endif
+#else
+ #define SILK_DEBUG 0
+#endif
+
+/* Flag for using timers */
+#define SILK_TIC_TOC 0
+
+
+#if SILK_TIC_TOC
+
+#if (defined(_WIN32) || defined(_WINCE))
+#include <windows.h> /* timer */
+#else /* Linux or Mac*/
+#include <sys/time.h>
+#endif
+
+/*********************************/
+/* timer functions for profiling */
+/*********************************/
+/* example: */
+/* */
+/* TIC(LPC) */
+/* do_LPC(in_vec, order, acoef); // do LPC analysis */
+/* TOC(LPC) */
+/* */
+/* and call the following just before exiting (from main) */
+/* */
+/* silk_TimerSave("silk_TimingData.txt"); */
+/* */
+/* results are now in silk_TimingData.txt */
+
+void silk_TimerSave(char *file_name);
+
+/* max number of timers (in different locations) */
+#define silk_NUM_TIMERS_MAX 50
+/* max length of name tags in TIC(..), TOC(..) */
+#define silk_NUM_TIMERS_MAX_TAG_LEN 30
+
+extern int silk_Timer_nTimers;
+extern int silk_Timer_depth_ctr;
+extern char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN];
+#ifdef _WIN32
+extern LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX];
+#else
+extern unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX];
+#endif
+extern unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX];
+extern opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX];
+extern opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX];
+extern opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX];
+extern opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX];
+
+/* WARNING: TIC()/TOC can measure only up to 0.1 seconds at a time */
+#ifdef _WIN32
+#define TIC(TAG_NAME) { \
+ static int init = 0; \
+ static int ID = -1; \
+ if( init == 0 ) \
+ { \
+ int k; \
+ init = 1; \
+ for( k = 0; k < silk_Timer_nTimers; k++ ) { \
+ if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
+ ID = k; \
+ break; \
+ } \
+ } \
+ if (ID == -1) { \
+ ID = silk_Timer_nTimers; \
+ silk_Timer_nTimers++; \
+ silk_Timer_depth[ID] = silk_Timer_depth_ctr; \
+ strcpy(silk_Timer_tags[ID], #TAG_NAME); \
+ silk_Timer_cnt[ID] = 0; \
+ silk_Timer_sum[ID] = 0; \
+ silk_Timer_min[ID] = 0xFFFFFFFF; \
+ silk_Timer_max[ID] = 0; \
+ } \
+ } \
+ silk_Timer_depth_ctr++; \
+ QueryPerformanceCounter(&silk_Timer_start[ID]); \
+}
+#else
+#define TIC(TAG_NAME) { \
+ static int init = 0; \
+ static int ID = -1; \
+ if( init == 0 ) \
+ { \
+ int k; \
+ init = 1; \
+ for( k = 0; k < silk_Timer_nTimers; k++ ) { \
+ if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
+ ID = k; \
+ break; \
+ } \
+ } \
+ if (ID == -1) { \
+ ID = silk_Timer_nTimers; \
+ silk_Timer_nTimers++; \
+ silk_Timer_depth[ID] = silk_Timer_depth_ctr; \
+ strcpy(silk_Timer_tags[ID], #TAG_NAME); \
+ silk_Timer_cnt[ID] = 0; \
+ silk_Timer_sum[ID] = 0; \
+ silk_Timer_min[ID] = 0xFFFFFFFF; \
+ silk_Timer_max[ID] = 0; \
+ } \
+ } \
+ silk_Timer_depth_ctr++; \
+ silk_Timer_start[ID] = GetHighResolutionTime(); \
+}
+#endif
+
+#ifdef _WIN32
+#define TOC(TAG_NAME) { \
+ LARGE_INTEGER lpPerformanceCount; \
+ static int init = 0; \
+ static int ID = 0; \
+ if( init == 0 ) \
+ { \
+ int k; \
+ init = 1; \
+ for( k = 0; k < silk_Timer_nTimers; k++ ) { \
+ if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
+ ID = k; \
+ break; \
+ } \
+ } \
+ } \
+ QueryPerformanceCounter(&lpPerformanceCount); \
+ lpPerformanceCount.QuadPart -= silk_Timer_start[ID].QuadPart; \
+ if((lpPerformanceCount.QuadPart < 100000000) && \
+ (lpPerformanceCount.QuadPart >= 0)) { \
+ silk_Timer_cnt[ID]++; \
+ silk_Timer_sum[ID] += lpPerformanceCount.QuadPart; \
+ if( lpPerformanceCount.QuadPart > silk_Timer_max[ID] ) \
+ silk_Timer_max[ID] = lpPerformanceCount.QuadPart; \
+ if( lpPerformanceCount.QuadPart < silk_Timer_min[ID] ) \
+ silk_Timer_min[ID] = lpPerformanceCount.QuadPart; \
+ } \
+ silk_Timer_depth_ctr--; \
+}
+#else
+#define TOC(TAG_NAME) { \
+ unsigned long endTime; \
+ static int init = 0; \
+ static int ID = 0; \
+ if( init == 0 ) \
+ { \
+ int k; \
+ init = 1; \
+ for( k = 0; k < silk_Timer_nTimers; k++ ) { \
+ if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
+ ID = k; \
+ break; \
+ } \
+ } \
+ } \
+ endTime = GetHighResolutionTime(); \
+ endTime -= silk_Timer_start[ID]; \
+ if((endTime < 100000000) && \
+ (endTime >= 0)) { \
+ silk_Timer_cnt[ID]++; \
+ silk_Timer_sum[ID] += endTime; \
+ if( endTime > silk_Timer_max[ID] ) \
+ silk_Timer_max[ID] = endTime; \
+ if( endTime < silk_Timer_min[ID] ) \
+ silk_Timer_min[ID] = endTime; \
+ } \
+ silk_Timer_depth_ctr--; \
+}
+#endif
+
+#else /* SILK_TIC_TOC */
+
+/* define macros as empty strings */
+#define TIC(TAG_NAME)
+#define TOC(TAG_NAME)
+#define silk_TimerSave(FILE_NAME)
+
+#endif /* SILK_TIC_TOC */
+
+
+#if SILK_DEBUG
+/************************************/
+/* write data to file for debugging */
+/************************************/
+/* Example: DEBUG_STORE_DATA(testfile.pcm, &RIN[0], 160*sizeof(opus_int16)); */
+
+#define silk_NUM_STORES_MAX 100
+extern FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ];
+extern int silk_debug_store_count;
+
+/* Faster way of storing the data */
+#define DEBUG_STORE_DATA( FILE_NAME, DATA_PTR, N_BYTES ) { \
+ static opus_int init = 0, cnt = 0; \
+ static FILE **fp; \
+ if (init == 0) { \
+ init = 1; \
+ cnt = silk_debug_store_count++; \
+ silk_debug_store_fp[ cnt ] = fopen(#FILE_NAME, "wb"); \
+ } \
+ fwrite((DATA_PTR), (N_BYTES), 1, silk_debug_store_fp[ cnt ]); \
+}
+
+/* Call this at the end of main() */
+#define SILK_DEBUG_STORE_CLOSE_FILES { \
+ opus_int i; \
+ for( i = 0; i < silk_debug_store_count; i++ ) { \
+ fclose( silk_debug_store_fp[ i ] ); \
+ } \
+}
+
+#else /* SILK_DEBUG */
+
+/* define macros as empty strings */
+#define DEBUG_STORE_DATA(FILE_NAME, DATA_PTR, N_BYTES)
+#define SILK_DEBUG_STORE_CLOSE_FILES
+
+#endif /* SILK_DEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_DEBUG_H */
diff --git a/external/opus-1.1.4/silk/dec_API.c b/external/opus-1.1.4/silk/dec_API.c
new file mode 100644
index 0000000..b7d8ed4
--- /dev/null
+++ b/external/opus-1.1.4/silk/dec_API.c
@@ -0,0 +1,419 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "API.h"
+#include "main.h"
+#include "stack_alloc.h"
+#include "os_support.h"
+
+/************************/
+/* Decoder Super Struct */
+/************************/
+typedef struct {
+ silk_decoder_state channel_state[ DECODER_NUM_CHANNELS ];
+ stereo_dec_state sStereo;
+ opus_int nChannelsAPI;
+ opus_int nChannelsInternal;
+ opus_int prev_decode_only_middle;
+} silk_decoder;
+
+/*********************/
+/* Decoder functions */
+/*********************/
+
+opus_int silk_Get_Decoder_Size( /* O Returns error code */
+ opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+
+ *decSizeBytes = sizeof( silk_decoder );
+
+ return ret;
+}
+
+/* Reset decoder state */
+opus_int silk_InitDecoder( /* O Returns error code */
+ void *decState /* I/O State */
+)
+{
+ opus_int n, ret = SILK_NO_ERROR;
+ silk_decoder_state *channel_state = ((silk_decoder *)decState)->channel_state;
+
+ for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) {
+ ret = silk_init_decoder( &channel_state[ n ] );
+ }
+ silk_memset(&((silk_decoder *)decState)->sStereo, 0, sizeof(((silk_decoder *)decState)->sStereo));
+ /* Not strictly needed, but it's cleaner that way */
+ ((silk_decoder *)decState)->prev_decode_only_middle = 0;
+
+ return ret;
+}
+
+/* Decode a frame */
+opus_int silk_Decode( /* O Returns error code */
+ void* decState, /* I/O State */
+ silk_DecControlStruct* decControl, /* I/O Control Structure */
+ opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
+ opus_int newPacketFlag, /* I Indicates first decoder call for this packet */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 *samplesOut, /* O Decoded output speech vector */
+ opus_int32 *nSamplesOut, /* O Number of samples decoded */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int i, n, decode_only_middle = 0, ret = SILK_NO_ERROR;
+ opus_int32 nSamplesOutDec, LBRR_symbol;
+ opus_int16 *samplesOut1_tmp[ 2 ];
+ VARDECL( opus_int16, samplesOut1_tmp_storage1 );
+ VARDECL( opus_int16, samplesOut1_tmp_storage2 );
+ VARDECL( opus_int16, samplesOut2_tmp );
+ opus_int32 MS_pred_Q13[ 2 ] = { 0 };
+ opus_int16 *resample_out_ptr;
+ silk_decoder *psDec = ( silk_decoder * )decState;
+ silk_decoder_state *channel_state = psDec->channel_state;
+ opus_int has_side;
+ opus_int stereo_to_mono;
+ int delay_stack_alloc;
+ SAVE_STACK;
+
+ silk_assert( decControl->nChannelsInternal == 1 || decControl->nChannelsInternal == 2 );
+
+ /**********************************/
+ /* Test if first frame in payload */
+ /**********************************/
+ if( newPacketFlag ) {
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ channel_state[ n ].nFramesDecoded = 0; /* Used to count frames in packet */
+ }
+ }
+
+ /* If Mono -> Stereo transition in bitstream: init state of second channel */
+ if( decControl->nChannelsInternal > psDec->nChannelsInternal ) {
+ ret += silk_init_decoder( &channel_state[ 1 ] );
+ }
+
+ stereo_to_mono = decControl->nChannelsInternal == 1 && psDec->nChannelsInternal == 2 &&
+ ( decControl->internalSampleRate == 1000*channel_state[ 0 ].fs_kHz );
+
+ if( channel_state[ 0 ].nFramesDecoded == 0 ) {
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ opus_int fs_kHz_dec;
+ if( decControl->payloadSize_ms == 0 ) {
+ /* Assuming packet loss, use 10 ms */
+ channel_state[ n ].nFramesPerPacket = 1;
+ channel_state[ n ].nb_subfr = 2;
+ } else if( decControl->payloadSize_ms == 10 ) {
+ channel_state[ n ].nFramesPerPacket = 1;
+ channel_state[ n ].nb_subfr = 2;
+ } else if( decControl->payloadSize_ms == 20 ) {
+ channel_state[ n ].nFramesPerPacket = 1;
+ channel_state[ n ].nb_subfr = 4;
+ } else if( decControl->payloadSize_ms == 40 ) {
+ channel_state[ n ].nFramesPerPacket = 2;
+ channel_state[ n ].nb_subfr = 4;
+ } else if( decControl->payloadSize_ms == 60 ) {
+ channel_state[ n ].nFramesPerPacket = 3;
+ channel_state[ n ].nb_subfr = 4;
+ } else {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return SILK_DEC_INVALID_FRAME_SIZE;
+ }
+ fs_kHz_dec = ( decControl->internalSampleRate >> 10 ) + 1;
+ if( fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16 ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return SILK_DEC_INVALID_SAMPLING_FREQUENCY;
+ }
+ ret += silk_decoder_set_fs( &channel_state[ n ], fs_kHz_dec, decControl->API_sampleRate );
+ }
+ }
+
+ if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 && ( psDec->nChannelsAPI == 1 || psDec->nChannelsInternal == 1 ) ) {
+ silk_memset( psDec->sStereo.pred_prev_Q13, 0, sizeof( psDec->sStereo.pred_prev_Q13 ) );
+ silk_memset( psDec->sStereo.sSide, 0, sizeof( psDec->sStereo.sSide ) );
+ silk_memcpy( &channel_state[ 1 ].resampler_state, &channel_state[ 0 ].resampler_state, sizeof( silk_resampler_state_struct ) );
+ }
+ psDec->nChannelsAPI = decControl->nChannelsAPI;
+ psDec->nChannelsInternal = decControl->nChannelsInternal;
+
+ if( decControl->API_sampleRate > (opus_int32)MAX_API_FS_KHZ * 1000 || decControl->API_sampleRate < 8000 ) {
+ ret = SILK_DEC_INVALID_SAMPLING_FREQUENCY;
+ RESTORE_STACK;
+ return( ret );
+ }
+
+ if( lostFlag != FLAG_PACKET_LOST && channel_state[ 0 ].nFramesDecoded == 0 ) {
+ /* First decoder call for this payload */
+ /* Decode VAD flags and LBRR flag */
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) {
+ channel_state[ n ].VAD_flags[ i ] = ec_dec_bit_logp(psRangeDec, 1);
+ }
+ channel_state[ n ].LBRR_flag = ec_dec_bit_logp(psRangeDec, 1);
+ }
+ /* Decode LBRR flags */
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ silk_memset( channel_state[ n ].LBRR_flags, 0, sizeof( channel_state[ n ].LBRR_flags ) );
+ if( channel_state[ n ].LBRR_flag ) {
+ if( channel_state[ n ].nFramesPerPacket == 1 ) {
+ channel_state[ n ].LBRR_flags[ 0 ] = 1;
+ } else {
+ LBRR_symbol = ec_dec_icdf( psRangeDec, silk_LBRR_flags_iCDF_ptr[ channel_state[ n ].nFramesPerPacket - 2 ], 8 ) + 1;
+ for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) {
+ channel_state[ n ].LBRR_flags[ i ] = silk_RSHIFT( LBRR_symbol, i ) & 1;
+ }
+ }
+ }
+ }
+
+ if( lostFlag == FLAG_DECODE_NORMAL ) {
+ /* Regular decoding: skip all LBRR data */
+ for( i = 0; i < channel_state[ 0 ].nFramesPerPacket; i++ ) {
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ if( channel_state[ n ].LBRR_flags[ i ] ) {
+ opus_int16 pulses[ MAX_FRAME_LENGTH ];
+ opus_int condCoding;
+
+ if( decControl->nChannelsInternal == 2 && n == 0 ) {
+ silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 );
+ if( channel_state[ 1 ].LBRR_flags[ i ] == 0 ) {
+ silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle );
+ }
+ }
+ /* Use conditional coding if previous frame available */
+ if( i > 0 && channel_state[ n ].LBRR_flags[ i - 1 ] ) {
+ condCoding = CODE_CONDITIONALLY;
+ } else {
+ condCoding = CODE_INDEPENDENTLY;
+ }
+ silk_decode_indices( &channel_state[ n ], psRangeDec, i, 1, condCoding );
+ silk_decode_pulses( psRangeDec, pulses, channel_state[ n ].indices.signalType,
+ channel_state[ n ].indices.quantOffsetType, channel_state[ n ].frame_length );
+ }
+ }
+ }
+ }
+ }
+
+ /* Get MS predictor index */
+ if( decControl->nChannelsInternal == 2 ) {
+ if( lostFlag == FLAG_DECODE_NORMAL ||
+ ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 0 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 1 ) )
+ {
+ silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 );
+ /* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */
+ if( ( lostFlag == FLAG_DECODE_NORMAL && channel_state[ 1 ].VAD_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) ||
+ ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 1 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) )
+ {
+ silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle );
+ } else {
+ decode_only_middle = 0;
+ }
+ } else {
+ for( n = 0; n < 2; n++ ) {
+ MS_pred_Q13[ n ] = psDec->sStereo.pred_prev_Q13[ n ];
+ }
+ }
+ }
+
+ /* Reset side channel decoder prediction memory for first frame with side coding */
+ if( decControl->nChannelsInternal == 2 && decode_only_middle == 0 && psDec->prev_decode_only_middle == 1 ) {
+ silk_memset( psDec->channel_state[ 1 ].outBuf, 0, sizeof(psDec->channel_state[ 1 ].outBuf) );
+ silk_memset( psDec->channel_state[ 1 ].sLPC_Q14_buf, 0, sizeof(psDec->channel_state[ 1 ].sLPC_Q14_buf) );
+ psDec->channel_state[ 1 ].lagPrev = 100;
+ psDec->channel_state[ 1 ].LastGainIndex = 10;
+ psDec->channel_state[ 1 ].prevSignalType = TYPE_NO_VOICE_ACTIVITY;
+ psDec->channel_state[ 1 ].first_frame_after_reset = 1;
+ }
+
+ /* Check if the temp buffer fits into the output PCM buffer. If it fits,
+ we can delay allocating the temp buffer until after the SILK peak stack
+ usage. We need to use a < and not a <= because of the two extra samples. */
+ delay_stack_alloc = decControl->internalSampleRate*decControl->nChannelsInternal
+ < decControl->API_sampleRate*decControl->nChannelsAPI;
+ ALLOC( samplesOut1_tmp_storage1, delay_stack_alloc ? ALLOC_NONE
+ : decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 ),
+ opus_int16 );
+ if ( delay_stack_alloc )
+ {
+ samplesOut1_tmp[ 0 ] = samplesOut;
+ samplesOut1_tmp[ 1 ] = samplesOut + channel_state[ 0 ].frame_length + 2;
+ } else {
+ samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage1;
+ samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage1 + channel_state[ 0 ].frame_length + 2;
+ }
+
+ if( lostFlag == FLAG_DECODE_NORMAL ) {
+ has_side = !decode_only_middle;
+ } else {
+ has_side = !psDec->prev_decode_only_middle
+ || (decControl->nChannelsInternal == 2 && lostFlag == FLAG_DECODE_LBRR && channel_state[1].LBRR_flags[ channel_state[1].nFramesDecoded ] == 1 );
+ }
+ /* Call decoder for one frame */
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ if( n == 0 || has_side ) {
+ opus_int FrameIndex;
+ opus_int condCoding;
+
+ FrameIndex = channel_state[ 0 ].nFramesDecoded - n;
+ /* Use independent coding if no previous frame available */
+ if( FrameIndex <= 0 ) {
+ condCoding = CODE_INDEPENDENTLY;
+ } else if( lostFlag == FLAG_DECODE_LBRR ) {
+ condCoding = channel_state[ n ].LBRR_flags[ FrameIndex - 1 ] ? CODE_CONDITIONALLY : CODE_INDEPENDENTLY;
+ } else if( n > 0 && psDec->prev_decode_only_middle ) {
+ /* If we skipped a side frame in this packet, we don't
+ need LTP scaling; the LTP state is well-defined. */
+ condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING;
+ } else {
+ condCoding = CODE_CONDITIONALLY;
+ }
+ ret += silk_decode_frame( &channel_state[ n ], psRangeDec, &samplesOut1_tmp[ n ][ 2 ], &nSamplesOutDec, lostFlag, condCoding, arch);
+ } else {
+ silk_memset( &samplesOut1_tmp[ n ][ 2 ], 0, nSamplesOutDec * sizeof( opus_int16 ) );
+ }
+ channel_state[ n ].nFramesDecoded++;
+ }
+
+ if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 ) {
+ /* Convert Mid/Side to Left/Right */
+ silk_stereo_MS_to_LR( &psDec->sStereo, samplesOut1_tmp[ 0 ], samplesOut1_tmp[ 1 ], MS_pred_Q13, channel_state[ 0 ].fs_kHz, nSamplesOutDec );
+ } else {
+ /* Buffering */
+ silk_memcpy( samplesOut1_tmp[ 0 ], psDec->sStereo.sMid, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( psDec->sStereo.sMid, &samplesOut1_tmp[ 0 ][ nSamplesOutDec ], 2 * sizeof( opus_int16 ) );
+ }
+
+ /* Number of output samples */
+ *nSamplesOut = silk_DIV32( nSamplesOutDec * decControl->API_sampleRate, silk_SMULBB( channel_state[ 0 ].fs_kHz, 1000 ) );
+
+ /* Set up pointers to temp buffers */
+ ALLOC( samplesOut2_tmp,
+ decControl->nChannelsAPI == 2 ? *nSamplesOut : ALLOC_NONE, opus_int16 );
+ if( decControl->nChannelsAPI == 2 ) {
+ resample_out_ptr = samplesOut2_tmp;
+ } else {
+ resample_out_ptr = samplesOut;
+ }
+
+ ALLOC( samplesOut1_tmp_storage2, delay_stack_alloc
+ ? decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 )
+ : ALLOC_NONE,
+ opus_int16 );
+ if ( delay_stack_alloc ) {
+ OPUS_COPY(samplesOut1_tmp_storage2, samplesOut, decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2));
+ samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage2;
+ samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage2 + channel_state[ 0 ].frame_length + 2;
+ }
+ for( n = 0; n < silk_min( decControl->nChannelsAPI, decControl->nChannelsInternal ); n++ ) {
+
+ /* Resample decoded signal to API_sampleRate */
+ ret += silk_resampler( &channel_state[ n ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ n ][ 1 ], nSamplesOutDec );
+
+ /* Interleave if stereo output and stereo stream */
+ if( decControl->nChannelsAPI == 2 ) {
+ for( i = 0; i < *nSamplesOut; i++ ) {
+ samplesOut[ n + 2 * i ] = resample_out_ptr[ i ];
+ }
+ }
+ }
+
+ /* Create two channel output from mono stream */
+ if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 1 ) {
+ if ( stereo_to_mono ){
+ /* Resample right channel for newly collapsed stereo just in case
+ we weren't doing collapsing when switching to mono */
+ ret += silk_resampler( &channel_state[ 1 ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ 0 ][ 1 ], nSamplesOutDec );
+
+ for( i = 0; i < *nSamplesOut; i++ ) {
+ samplesOut[ 1 + 2 * i ] = resample_out_ptr[ i ];
+ }
+ } else {
+ for( i = 0; i < *nSamplesOut; i++ ) {
+ samplesOut[ 1 + 2 * i ] = samplesOut[ 0 + 2 * i ];
+ }
+ }
+ }
+
+ /* Export pitch lag, measured at 48 kHz sampling rate */
+ if( channel_state[ 0 ].prevSignalType == TYPE_VOICED ) {
+ int mult_tab[ 3 ] = { 6, 4, 3 };
+ decControl->prevPitchLag = channel_state[ 0 ].lagPrev * mult_tab[ ( channel_state[ 0 ].fs_kHz - 8 ) >> 2 ];
+ } else {
+ decControl->prevPitchLag = 0;
+ }
+
+ if( lostFlag == FLAG_PACKET_LOST ) {
+ /* On packet loss, remove the gain clamping to prevent having the energy "bounce back"
+ if we lose packets when the energy is going down */
+ for ( i = 0; i < psDec->nChannelsInternal; i++ )
+ psDec->channel_state[ i ].LastGainIndex = 10;
+ } else {
+ psDec->prev_decode_only_middle = decode_only_middle;
+ }
+ RESTORE_STACK;
+ return ret;
+}
+
+#if 0
+/* Getting table of contents for a packet */
+opus_int silk_get_TOC(
+ const opus_uint8 *payload, /* I Payload data */
+ const opus_int nBytesIn, /* I Number of input bytes */
+ const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */
+ silk_TOC_struct *Silk_TOC /* O Type of content */
+)
+{
+ opus_int i, flags, ret = SILK_NO_ERROR;
+
+ if( nBytesIn < 1 ) {
+ return -1;
+ }
+ if( nFramesPerPayload < 0 || nFramesPerPayload > 3 ) {
+ return -1;
+ }
+
+ silk_memset( Silk_TOC, 0, sizeof( *Silk_TOC ) );
+
+ /* For stereo, extract the flags for the mid channel */
+ flags = silk_RSHIFT( payload[ 0 ], 7 - nFramesPerPayload ) & ( silk_LSHIFT( 1, nFramesPerPayload + 1 ) - 1 );
+
+ Silk_TOC->inbandFECFlag = flags & 1;
+ for( i = nFramesPerPayload - 1; i >= 0 ; i-- ) {
+ flags = silk_RSHIFT( flags, 1 );
+ Silk_TOC->VADFlags[ i ] = flags & 1;
+ Silk_TOC->VADFlag |= flags & 1;
+ }
+
+ return ret;
+}
+#endif
diff --git a/external/opus-1.1.4/silk/decode_core.c b/external/opus-1.1.4/silk/decode_core.c
new file mode 100644
index 0000000..e569c0e
--- /dev/null
+++ b/external/opus-1.1.4/silk/decode_core.c
@@ -0,0 +1,239 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/**********************************************************/
+/* Core decoder. Performs inverse NSQ operation LTP + LPC */
+/**********************************************************/
+void silk_decode_core(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I Decoder control */
+ opus_int16 xq[], /* O Decoded speech */
+ const opus_int16 pulses[ MAX_FRAME_LENGTH ], /* I Pulse signal */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType;
+ opus_int16 *A_Q12, *B_Q14, *pxq, A_Q12_tmp[ MAX_LPC_ORDER ];
+ VARDECL( opus_int16, sLTP );
+ VARDECL( opus_int32, sLTP_Q15 );
+ opus_int32 LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10;
+ opus_int32 *pred_lag_ptr, *pexc_Q14, *pres_Q14;
+ VARDECL( opus_int32, res_Q14 );
+ VARDECL( opus_int32, sLPC_Q14 );
+ SAVE_STACK;
+
+ silk_assert( psDec->prev_gain_Q16 != 0 );
+
+ ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 );
+ ALLOC( sLTP_Q15, psDec->ltp_mem_length + psDec->frame_length, opus_int32 );
+ ALLOC( res_Q14, psDec->subfr_length, opus_int32 );
+ ALLOC( sLPC_Q14, psDec->subfr_length + MAX_LPC_ORDER, opus_int32 );
+
+ offset_Q10 = silk_Quantization_Offsets_Q10[ psDec->indices.signalType >> 1 ][ psDec->indices.quantOffsetType ];
+
+ if( psDec->indices.NLSFInterpCoef_Q2 < 1 << 2 ) {
+ NLSF_interpolation_flag = 1;
+ } else {
+ NLSF_interpolation_flag = 0;
+ }
+
+ /* Decode excitation */
+ rand_seed = psDec->indices.Seed;
+ for( i = 0; i < psDec->frame_length; i++ ) {
+ rand_seed = silk_RAND( rand_seed );
+ psDec->exc_Q14[ i ] = silk_LSHIFT( (opus_int32)pulses[ i ], 14 );
+ if( psDec->exc_Q14[ i ] > 0 ) {
+ psDec->exc_Q14[ i ] -= QUANT_LEVEL_ADJUST_Q10 << 4;
+ } else
+ if( psDec->exc_Q14[ i ] < 0 ) {
+ psDec->exc_Q14[ i ] += QUANT_LEVEL_ADJUST_Q10 << 4;
+ }
+ psDec->exc_Q14[ i ] += offset_Q10 << 4;
+ if( rand_seed < 0 ) {
+ psDec->exc_Q14[ i ] = -psDec->exc_Q14[ i ];
+ }
+
+ rand_seed = silk_ADD32_ovflw( rand_seed, pulses[ i ] );
+ }
+
+ /* Copy LPC state */
+ silk_memcpy( sLPC_Q14, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+
+ pexc_Q14 = psDec->exc_Q14;
+ pxq = xq;
+ sLTP_buf_idx = psDec->ltp_mem_length;
+ /* Loop over subframes */
+ for( k = 0; k < psDec->nb_subfr; k++ ) {
+ pres_Q14 = res_Q14;
+ A_Q12 = psDecCtrl->PredCoef_Q12[ k >> 1 ];
+
+ /* Preload LPC coeficients to array on stack. Gives small performance gain */
+ silk_memcpy( A_Q12_tmp, A_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
+ B_Q14 = &psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER ];
+ signalType = psDec->indices.signalType;
+
+ Gain_Q10 = silk_RSHIFT( psDecCtrl->Gains_Q16[ k ], 6 );
+ inv_gain_Q31 = silk_INVERSE32_varQ( psDecCtrl->Gains_Q16[ k ], 47 );
+
+ /* Calculate gain adjustment factor */
+ if( psDecCtrl->Gains_Q16[ k ] != psDec->prev_gain_Q16 ) {
+ gain_adj_Q16 = silk_DIV32_varQ( psDec->prev_gain_Q16, psDecCtrl->Gains_Q16[ k ], 16 );
+
+ /* Scale short term state */
+ for( i = 0; i < MAX_LPC_ORDER; i++ ) {
+ sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, sLPC_Q14[ i ] );
+ }
+ } else {
+ gain_adj_Q16 = (opus_int32)1 << 16;
+ }
+
+ /* Save inv_gain */
+ silk_assert( inv_gain_Q31 != 0 );
+ psDec->prev_gain_Q16 = psDecCtrl->Gains_Q16[ k ];
+
+ /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */
+ if( psDec->lossCnt && psDec->prevSignalType == TYPE_VOICED &&
+ psDec->indices.signalType != TYPE_VOICED && k < MAX_NB_SUBFR/2 ) {
+
+ silk_memset( B_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
+ B_Q14[ LTP_ORDER/2 ] = SILK_FIX_CONST( 0.25, 14 );
+
+ signalType = TYPE_VOICED;
+ psDecCtrl->pitchL[ k ] = psDec->lagPrev;
+ }
+
+ if( signalType == TYPE_VOICED ) {
+ /* Voiced */
+ lag = psDecCtrl->pitchL[ k ];
+
+ /* Re-whitening */
+ if( k == 0 || ( k == 2 && NLSF_interpolation_flag ) ) {
+ /* Rewhiten with new A coefs */
+ start_idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
+ silk_assert( start_idx > 0 );
+
+ if( k == 2 ) {
+ silk_memcpy( &psDec->outBuf[ psDec->ltp_mem_length ], xq, 2 * psDec->subfr_length * sizeof( opus_int16 ) );
+ }
+
+ silk_LPC_analysis_filter( &sLTP[ start_idx ], &psDec->outBuf[ start_idx + k * psDec->subfr_length ],
+ A_Q12, psDec->ltp_mem_length - start_idx, psDec->LPC_order, arch );
+
+ /* After rewhitening the LTP state is unscaled */
+ if( k == 0 ) {
+ /* Do LTP downscaling to reduce inter-packet dependency */
+ inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, psDecCtrl->LTP_scale_Q14 ), 2 );
+ }
+ for( i = 0; i < lag + LTP_ORDER/2; i++ ) {
+ sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWB( inv_gain_Q31, sLTP[ psDec->ltp_mem_length - i - 1 ] );
+ }
+ } else {
+ /* Update LTP state when Gain changes */
+ if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+ for( i = 0; i < lag + LTP_ORDER/2; i++ ) {
+ sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ sLTP_buf_idx - i - 1 ] );
+ }
+ }
+ }
+ }
+
+ /* Long-term prediction */
+ if( signalType == TYPE_VOICED ) {
+ /* Set up pointer */
+ pred_lag_ptr = &sLTP_Q15[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ for( i = 0; i < psDec->subfr_length; i++ ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q13 = 2;
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], B_Q14[ 0 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
+ pred_lag_ptr++;
+
+ /* Generate LPC excitation */
+ pres_Q14[ i ] = silk_ADD_LSHIFT32( pexc_Q14[ i ], LTP_pred_Q13, 1 );
+
+ /* Update states */
+ sLTP_Q15[ sLTP_buf_idx ] = silk_LSHIFT( pres_Q14[ i ], 1 );
+ sLTP_buf_idx++;
+ }
+ } else {
+ pres_Q14 = pexc_Q14;
+ }
+
+ for( i = 0; i < psDec->subfr_length; i++ ) {
+ /* Short-term prediction */
+ silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp[ 0 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp[ 1 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp[ 2 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp[ 3 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp[ 4 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp[ 5 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp[ 6 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp[ 7 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp[ 8 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] );
+ if( psDec->LPC_order == 16 ) {
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12_tmp[ 10 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12_tmp[ 11 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12_tmp[ 12 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12_tmp[ 13 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12_tmp[ 14 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12_tmp[ 15 ] );
+ }
+
+ /* Add prediction to LPC excitation */
+ sLPC_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( pres_Q14[ i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) );
+
+ /* Scale with gain */
+ pxq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14[ MAX_LPC_ORDER + i ], Gain_Q10 ), 8 ) );
+ }
+
+ /* DEBUG_STORE_DATA( dec.pcm, pxq, psDec->subfr_length * sizeof( opus_int16 ) ) */
+
+ /* Update LPC filter state */
+ silk_memcpy( sLPC_Q14, &sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
+ pexc_Q14 += psDec->subfr_length;
+ pxq += psDec->subfr_length;
+ }
+
+ /* Save LPC state */
+ silk_memcpy( psDec->sLPC_Q14_buf, sLPC_Q14, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/decode_frame.c b/external/opus-1.1.4/silk/decode_frame.c
new file mode 100644
index 0000000..a605d95
--- /dev/null
+++ b/external/opus-1.1.4/silk/decode_frame.c
@@ -0,0 +1,129 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+#include "PLC.h"
+
+/****************/
+/* Decode frame */
+/****************/
+opus_int silk_decode_frame(
+ silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 pOut[], /* O Pointer to output speech frame */
+ opus_int32 *pN, /* O Pointer to size of output frame */
+ opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ int arch /* I Run-time architecture */
+)
+{
+ VARDECL( silk_decoder_control, psDecCtrl );
+ opus_int L, mv_len, ret = 0;
+ SAVE_STACK;
+
+ L = psDec->frame_length;
+ ALLOC( psDecCtrl, 1, silk_decoder_control );
+ psDecCtrl->LTP_scale_Q14 = 0;
+
+ /* Safety checks */
+ silk_assert( L > 0 && L <= MAX_FRAME_LENGTH );
+
+ if( lostFlag == FLAG_DECODE_NORMAL ||
+ ( lostFlag == FLAG_DECODE_LBRR && psDec->LBRR_flags[ psDec->nFramesDecoded ] == 1 ) )
+ {
+ VARDECL( opus_int16, pulses );
+ ALLOC( pulses, (L + SHELL_CODEC_FRAME_LENGTH - 1) &
+ ~(SHELL_CODEC_FRAME_LENGTH - 1), opus_int16 );
+ /*********************************************/
+ /* Decode quantization indices of side info */
+ /*********************************************/
+ silk_decode_indices( psDec, psRangeDec, psDec->nFramesDecoded, lostFlag, condCoding );
+
+ /*********************************************/
+ /* Decode quantization indices of excitation */
+ /*********************************************/
+ silk_decode_pulses( psRangeDec, pulses, psDec->indices.signalType,
+ psDec->indices.quantOffsetType, psDec->frame_length );
+
+ /********************************************/
+ /* Decode parameters and pulse signal */
+ /********************************************/
+ silk_decode_parameters( psDec, psDecCtrl, condCoding );
+
+ /********************************************************/
+ /* Run inverse NSQ */
+ /********************************************************/
+ silk_decode_core( psDec, psDecCtrl, pOut, pulses, arch );
+
+ /********************************************************/
+ /* Update PLC state */
+ /********************************************************/
+ silk_PLC( psDec, psDecCtrl, pOut, 0, arch );
+
+ psDec->lossCnt = 0;
+ psDec->prevSignalType = psDec->indices.signalType;
+ silk_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 );
+
+ /* A frame has been decoded without errors */
+ psDec->first_frame_after_reset = 0;
+ } else {
+ /* Handle packet loss by extrapolation */
+ silk_PLC( psDec, psDecCtrl, pOut, 1, arch );
+ }
+
+ /*************************/
+ /* Update output buffer. */
+ /*************************/
+ silk_assert( psDec->ltp_mem_length >= psDec->frame_length );
+ mv_len = psDec->ltp_mem_length - psDec->frame_length;
+ silk_memmove( psDec->outBuf, &psDec->outBuf[ psDec->frame_length ], mv_len * sizeof(opus_int16) );
+ silk_memcpy( &psDec->outBuf[ mv_len ], pOut, psDec->frame_length * sizeof( opus_int16 ) );
+
+ /************************************************/
+ /* Comfort noise generation / estimation */
+ /************************************************/
+ silk_CNG( psDec, psDecCtrl, pOut, L );
+
+ /****************************************************************/
+ /* Ensure smooth connection of extrapolated and good frames */
+ /****************************************************************/
+ silk_PLC_glue_frames( psDec, pOut, L );
+
+ /* Update some decoder state variables */
+ psDec->lagPrev = psDecCtrl->pitchL[ psDec->nb_subfr - 1 ];
+
+ /* Set output frame length */
+ *pN = L;
+
+ RESTORE_STACK;
+ return ret;
+}
diff --git a/external/opus-1.1.4/silk/decode_indices.c b/external/opus-1.1.4/silk/decode_indices.c
new file mode 100644
index 0000000..7afe5c2
--- /dev/null
+++ b/external/opus-1.1.4/silk/decode_indices.c
@@ -0,0 +1,151 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Decode side-information parameters from payload */
+void silk_decode_indices(
+ silk_decoder_state *psDec, /* I/O State */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int FrameIndex, /* I Frame number */
+ opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i, k, Ix;
+ opus_int decode_absolute_lagIndex, delta_lagIndex;
+ opus_int16 ec_ix[ MAX_LPC_ORDER ];
+ opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+
+ /*******************************************/
+ /* Decode signal type and quantizer offset */
+ /*******************************************/
+ if( decode_LBRR || psDec->VAD_flags[ FrameIndex ] ) {
+ Ix = ec_dec_icdf( psRangeDec, silk_type_offset_VAD_iCDF, 8 ) + 2;
+ } else {
+ Ix = ec_dec_icdf( psRangeDec, silk_type_offset_no_VAD_iCDF, 8 );
+ }
+ psDec->indices.signalType = (opus_int8)silk_RSHIFT( Ix, 1 );
+ psDec->indices.quantOffsetType = (opus_int8)( Ix & 1 );
+
+ /****************/
+ /* Decode gains */
+ /****************/
+ /* First subframe */
+ if( condCoding == CODE_CONDITIONALLY ) {
+ /* Conditional coding */
+ psDec->indices.GainsIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 );
+ } else {
+ /* Independent coding, in two stages: MSB bits followed by 3 LSBs */
+ psDec->indices.GainsIndices[ 0 ] = (opus_int8)silk_LSHIFT( ec_dec_icdf( psRangeDec, silk_gain_iCDF[ psDec->indices.signalType ], 8 ), 3 );
+ psDec->indices.GainsIndices[ 0 ] += (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform8_iCDF, 8 );
+ }
+
+ /* Remaining subframes */
+ for( i = 1; i < psDec->nb_subfr; i++ ) {
+ psDec->indices.GainsIndices[ i ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 );
+ }
+
+ /**********************/
+ /* Decode LSF Indices */
+ /**********************/
+ psDec->indices.NLSFIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->CB1_iCDF[ ( psDec->indices.signalType >> 1 ) * psDec->psNLSF_CB->nVectors ], 8 );
+ silk_NLSF_unpack( ec_ix, pred_Q8, psDec->psNLSF_CB, psDec->indices.NLSFIndices[ 0 ] );
+ silk_assert( psDec->psNLSF_CB->order == psDec->LPC_order );
+ for( i = 0; i < psDec->psNLSF_CB->order; i++ ) {
+ Ix = ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+ if( Ix == 0 ) {
+ Ix -= ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 );
+ } else if( Ix == 2 * NLSF_QUANT_MAX_AMPLITUDE ) {
+ Ix += ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 );
+ }
+ psDec->indices.NLSFIndices[ i+1 ] = (opus_int8)( Ix - NLSF_QUANT_MAX_AMPLITUDE );
+ }
+
+ /* Decode LSF interpolation factor */
+ if( psDec->nb_subfr == MAX_NB_SUBFR ) {
+ psDec->indices.NLSFInterpCoef_Q2 = (opus_int8)ec_dec_icdf( psRangeDec, silk_NLSF_interpolation_factor_iCDF, 8 );
+ } else {
+ psDec->indices.NLSFInterpCoef_Q2 = 4;
+ }
+
+ if( psDec->indices.signalType == TYPE_VOICED )
+ {
+ /*********************/
+ /* Decode pitch lags */
+ /*********************/
+ /* Get lag index */
+ decode_absolute_lagIndex = 1;
+ if( condCoding == CODE_CONDITIONALLY && psDec->ec_prevSignalType == TYPE_VOICED ) {
+ /* Decode Delta index */
+ delta_lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_delta_iCDF, 8 );
+ if( delta_lagIndex > 0 ) {
+ delta_lagIndex = delta_lagIndex - 9;
+ psDec->indices.lagIndex = (opus_int16)( psDec->ec_prevLagIndex + delta_lagIndex );
+ decode_absolute_lagIndex = 0;
+ }
+ }
+ if( decode_absolute_lagIndex ) {
+ /* Absolute decoding */
+ psDec->indices.lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_lag_iCDF, 8 ) * silk_RSHIFT( psDec->fs_kHz, 1 );
+ psDec->indices.lagIndex += (opus_int16)ec_dec_icdf( psRangeDec, psDec->pitch_lag_low_bits_iCDF, 8 );
+ }
+ psDec->ec_prevLagIndex = psDec->indices.lagIndex;
+
+ /* Get countour index */
+ psDec->indices.contourIndex = (opus_int8)ec_dec_icdf( psRangeDec, psDec->pitch_contour_iCDF, 8 );
+
+ /********************/
+ /* Decode LTP gains */
+ /********************/
+ /* Decode PERIndex value */
+ psDec->indices.PERIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_per_index_iCDF, 8 );
+
+ for( k = 0; k < psDec->nb_subfr; k++ ) {
+ psDec->indices.LTPIndex[ k ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_gain_iCDF_ptrs[ psDec->indices.PERIndex ], 8 );
+ }
+
+ /**********************/
+ /* Decode LTP scaling */
+ /**********************/
+ if( condCoding == CODE_INDEPENDENTLY ) {
+ psDec->indices.LTP_scaleIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTPscale_iCDF, 8 );
+ } else {
+ psDec->indices.LTP_scaleIndex = 0;
+ }
+ }
+ psDec->ec_prevSignalType = psDec->indices.signalType;
+
+ /***************/
+ /* Decode seed */
+ /***************/
+ psDec->indices.Seed = (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform4_iCDF, 8 );
+}
diff --git a/external/opus-1.1.4/silk/decode_parameters.c b/external/opus-1.1.4/silk/decode_parameters.c
new file mode 100644
index 0000000..e345b1d
--- /dev/null
+++ b/external/opus-1.1.4/silk/decode_parameters.c
@@ -0,0 +1,115 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Decode parameters from payload */
+void silk_decode_parameters(
+ silk_decoder_state *psDec, /* I/O State */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i, k, Ix;
+ opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], pNLSF0_Q15[ MAX_LPC_ORDER ];
+ const opus_int8 *cbk_ptr_Q7;
+
+ /* Dequant Gains */
+ silk_gains_dequant( psDecCtrl->Gains_Q16, psDec->indices.GainsIndices,
+ &psDec->LastGainIndex, condCoding == CODE_CONDITIONALLY, psDec->nb_subfr );
+
+ /****************/
+ /* Decode NLSFs */
+ /****************/
+ silk_NLSF_decode( pNLSF_Q15, psDec->indices.NLSFIndices, psDec->psNLSF_CB );
+
+ /* Convert NLSF parameters to AR prediction filter coefficients */
+ silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order );
+
+ /* If just reset, e.g., because internal Fs changed, do not allow interpolation */
+ /* improves the case of packet loss in the first frame after a switch */
+ if( psDec->first_frame_after_reset == 1 ) {
+ psDec->indices.NLSFInterpCoef_Q2 = 4;
+ }
+
+ if( psDec->indices.NLSFInterpCoef_Q2 < 4 ) {
+ /* Calculation of the interpolated NLSF0 vector from the interpolation factor, */
+ /* the previous NLSF1, and the current NLSF1 */
+ for( i = 0; i < psDec->LPC_order; i++ ) {
+ pNLSF0_Q15[ i ] = psDec->prevNLSF_Q15[ i ] + silk_RSHIFT( silk_MUL( psDec->indices.NLSFInterpCoef_Q2,
+ pNLSF_Q15[ i ] - psDec->prevNLSF_Q15[ i ] ), 2 );
+ }
+
+ /* Convert NLSF parameters to AR prediction filter coefficients */
+ silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order );
+ } else {
+ /* Copy LPC coefficients for first half from second half */
+ silk_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
+ }
+
+ silk_memcpy( psDec->prevNLSF_Q15, pNLSF_Q15, psDec->LPC_order * sizeof( opus_int16 ) );
+
+ /* After a packet loss do BWE of LPC coefs */
+ if( psDec->lossCnt ) {
+ silk_bwexpander( psDecCtrl->PredCoef_Q12[ 0 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 );
+ silk_bwexpander( psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 );
+ }
+
+ if( psDec->indices.signalType == TYPE_VOICED ) {
+ /*********************/
+ /* Decode pitch lags */
+ /*********************/
+
+ /* Decode pitch values */
+ silk_decode_pitch( psDec->indices.lagIndex, psDec->indices.contourIndex, psDecCtrl->pitchL, psDec->fs_kHz, psDec->nb_subfr );
+
+ /* Decode Codebook Index */
+ cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ psDec->indices.PERIndex ]; /* set pointer to start of codebook */
+
+ for( k = 0; k < psDec->nb_subfr; k++ ) {
+ Ix = psDec->indices.LTPIndex[ k ];
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER + i ] = silk_LSHIFT( cbk_ptr_Q7[ Ix * LTP_ORDER + i ], 7 );
+ }
+ }
+
+ /**********************/
+ /* Decode LTP scaling */
+ /**********************/
+ Ix = psDec->indices.LTP_scaleIndex;
+ psDecCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ Ix ];
+ } else {
+ silk_memset( psDecCtrl->pitchL, 0, psDec->nb_subfr * sizeof( opus_int ) );
+ silk_memset( psDecCtrl->LTPCoef_Q14, 0, LTP_ORDER * psDec->nb_subfr * sizeof( opus_int16 ) );
+ psDec->indices.PERIndex = 0;
+ psDecCtrl->LTP_scale_Q14 = 0;
+ }
+}
diff --git a/external/opus-1.1.4/silk/decode_pitch.c b/external/opus-1.1.4/silk/decode_pitch.c
new file mode 100644
index 0000000..fedbc6a
--- /dev/null
+++ b/external/opus-1.1.4/silk/decode_pitch.c
@@ -0,0 +1,77 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/***********************************************************
+* Pitch analyser function
+********************************************************** */
+#include "SigProc_FIX.h"
+#include "pitch_est_defines.h"
+
+void silk_decode_pitch(
+ opus_int16 lagIndex, /* I */
+ opus_int8 contourIndex, /* O */
+ opus_int pitch_lags[], /* O 4 pitch values */
+ const opus_int Fs_kHz, /* I sampling frequency (kHz) */
+ const opus_int nb_subfr /* I number of sub frames */
+)
+{
+ opus_int lag, k, min_lag, max_lag, cbk_size;
+ const opus_int8 *Lag_CB_ptr;
+
+ if( Fs_kHz == 8 ) {
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
+ cbk_size = PE_NB_CBKS_STAGE2_EXT;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 );
+ Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
+ cbk_size = PE_NB_CBKS_STAGE2_10MS;
+ }
+ } else {
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 );
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+ }
+
+ min_lag = silk_SMULBB( PE_MIN_LAG_MS, Fs_kHz );
+ max_lag = silk_SMULBB( PE_MAX_LAG_MS, Fs_kHz );
+ lag = min_lag + lagIndex;
+
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_lags[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, contourIndex, cbk_size );
+ pitch_lags[ k ] = silk_LIMIT( pitch_lags[ k ], min_lag, max_lag );
+ }
+}
diff --git a/external/opus-1.1.4/silk/decode_pulses.c b/external/opus-1.1.4/silk/decode_pulses.c
new file mode 100644
index 0000000..d6bbec9
--- /dev/null
+++ b/external/opus-1.1.4/silk/decode_pulses.c
@@ -0,0 +1,115 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/*********************************************/
+/* Decode quantization indices of excitation */
+/*********************************************/
+void silk_decode_pulses(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 pulses[], /* O Excitation signal */
+ const opus_int signalType, /* I Sigtype */
+ const opus_int quantOffsetType, /* I quantOffsetType */
+ const opus_int frame_length /* I Frame length */
+)
+{
+ opus_int i, j, k, iter, abs_q, nLS, RateLevelIndex;
+ opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ], nLshifts[ MAX_NB_SHELL_BLOCKS ];
+ opus_int16 *pulses_ptr;
+ const opus_uint8 *cdf_ptr;
+
+ /*********************/
+ /* Decode rate level */
+ /*********************/
+ RateLevelIndex = ec_dec_icdf( psRangeDec, silk_rate_levels_iCDF[ signalType >> 1 ], 8 );
+
+ /* Calculate number of shell blocks */
+ silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH );
+ iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH );
+ if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) {
+ silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */
+ iter++;
+ }
+
+ /***************************************************/
+ /* Sum-Weighted-Pulses Decoding */
+ /***************************************************/
+ cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ];
+ for( i = 0; i < iter; i++ ) {
+ nLshifts[ i ] = 0;
+ sum_pulses[ i ] = ec_dec_icdf( psRangeDec, cdf_ptr, 8 );
+
+ /* LSB indication */
+ while( sum_pulses[ i ] == SILK_MAX_PULSES + 1 ) {
+ nLshifts[ i ]++;
+ /* When we've already got 10 LSBs, we shift the table to not allow (SILK_MAX_PULSES + 1) */
+ sum_pulses[ i ] = ec_dec_icdf( psRangeDec,
+ silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1] + ( nLshifts[ i ] == 10 ), 8 );
+ }
+ }
+
+ /***************************************************/
+ /* Shell decoding */
+ /***************************************************/
+ for( i = 0; i < iter; i++ ) {
+ if( sum_pulses[ i ] > 0 ) {
+ silk_shell_decoder( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], psRangeDec, sum_pulses[ i ] );
+ } else {
+ silk_memset( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof( pulses[0] ) );
+ }
+ }
+
+ /***************************************************/
+ /* LSB Decoding */
+ /***************************************************/
+ for( i = 0; i < iter; i++ ) {
+ if( nLshifts[ i ] > 0 ) {
+ nLS = nLshifts[ i ];
+ pulses_ptr = &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ];
+ for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
+ abs_q = pulses_ptr[ k ];
+ for( j = 0; j < nLS; j++ ) {
+ abs_q = silk_LSHIFT( abs_q, 1 );
+ abs_q += ec_dec_icdf( psRangeDec, silk_lsb_iCDF, 8 );
+ }
+ pulses_ptr[ k ] = abs_q;
+ }
+ /* Mark the number of pulses non-zero for sign decoding. */
+ sum_pulses[ i ] |= nLS << 5;
+ }
+ }
+
+ /****************************************/
+ /* Decode and add signs to pulse signal */
+ /****************************************/
+ silk_decode_signs( psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses );
+}
diff --git a/external/opus-1.1.4/silk/decoder_set_fs.c b/external/opus-1.1.4/silk/decoder_set_fs.c
new file mode 100644
index 0000000..eef0fd2
--- /dev/null
+++ b/external/opus-1.1.4/silk/decoder_set_fs.c
@@ -0,0 +1,108 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Set decoder sampling rate */
+opus_int silk_decoder_set_fs(
+ silk_decoder_state *psDec, /* I/O Decoder state pointer */
+ opus_int fs_kHz, /* I Sampling frequency (kHz) */
+ opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */
+)
+{
+ opus_int frame_length, ret = 0;
+
+ silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 );
+ silk_assert( psDec->nb_subfr == MAX_NB_SUBFR || psDec->nb_subfr == MAX_NB_SUBFR/2 );
+
+ /* New (sub)frame length */
+ psDec->subfr_length = silk_SMULBB( SUB_FRAME_LENGTH_MS, fs_kHz );
+ frame_length = silk_SMULBB( psDec->nb_subfr, psDec->subfr_length );
+
+ /* Initialize resampler when switching internal or external sampling frequency */
+ if( psDec->fs_kHz != fs_kHz || psDec->fs_API_hz != fs_API_Hz ) {
+ /* Initialize the resampler for dec_API.c preparing resampling from fs_kHz to API_fs_Hz */
+ ret += silk_resampler_init( &psDec->resampler_state, silk_SMULBB( fs_kHz, 1000 ), fs_API_Hz, 0 );
+
+ psDec->fs_API_hz = fs_API_Hz;
+ }
+
+ if( psDec->fs_kHz != fs_kHz || frame_length != psDec->frame_length ) {
+ if( fs_kHz == 8 ) {
+ if( psDec->nb_subfr == MAX_NB_SUBFR ) {
+ psDec->pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
+ } else {
+ psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
+ }
+ } else {
+ if( psDec->nb_subfr == MAX_NB_SUBFR ) {
+ psDec->pitch_contour_iCDF = silk_pitch_contour_iCDF;
+ } else {
+ psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
+ }
+ }
+ if( psDec->fs_kHz != fs_kHz ) {
+ psDec->ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz );
+ if( fs_kHz == 8 || fs_kHz == 12 ) {
+ psDec->LPC_order = MIN_LPC_ORDER;
+ psDec->psNLSF_CB = &silk_NLSF_CB_NB_MB;
+ } else {
+ psDec->LPC_order = MAX_LPC_ORDER;
+ psDec->psNLSF_CB = &silk_NLSF_CB_WB;
+ }
+ if( fs_kHz == 16 ) {
+ psDec->pitch_lag_low_bits_iCDF = silk_uniform8_iCDF;
+ } else if( fs_kHz == 12 ) {
+ psDec->pitch_lag_low_bits_iCDF = silk_uniform6_iCDF;
+ } else if( fs_kHz == 8 ) {
+ psDec->pitch_lag_low_bits_iCDF = silk_uniform4_iCDF;
+ } else {
+ /* unsupported sampling rate */
+ silk_assert( 0 );
+ }
+ psDec->first_frame_after_reset = 1;
+ psDec->lagPrev = 100;
+ psDec->LastGainIndex = 10;
+ psDec->prevSignalType = TYPE_NO_VOICE_ACTIVITY;
+ silk_memset( psDec->outBuf, 0, sizeof(psDec->outBuf));
+ silk_memset( psDec->sLPC_Q14_buf, 0, sizeof(psDec->sLPC_Q14_buf) );
+ }
+
+ psDec->fs_kHz = fs_kHz;
+ psDec->frame_length = frame_length;
+ }
+
+ /* Check that settings are valid */
+ silk_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH );
+
+ return ret;
+}
+
diff --git a/external/opus-1.1.4/silk/define.h b/external/opus-1.1.4/silk/define.h
new file mode 100644
index 0000000..19c9b00
--- /dev/null
+++ b/external/opus-1.1.4/silk/define.h
@@ -0,0 +1,235 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_DEFINE_H
+#define SILK_DEFINE_H
+
+#include "errors.h"
+#include "typedef.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Max number of encoder channels (1/2) */
+#define ENCODER_NUM_CHANNELS 2
+/* Number of decoder channels (1/2) */
+#define DECODER_NUM_CHANNELS 2
+
+#define MAX_FRAMES_PER_PACKET 3
+
+/* Limits on bitrate */
+#define MIN_TARGET_RATE_BPS 5000
+#define MAX_TARGET_RATE_BPS 80000
+#define TARGET_RATE_TAB_SZ 8
+
+/* LBRR thresholds */
+#define LBRR_NB_MIN_RATE_BPS 12000
+#define LBRR_MB_MIN_RATE_BPS 14000
+#define LBRR_WB_MIN_RATE_BPS 16000
+
+/* DTX settings */
+#define NB_SPEECH_FRAMES_BEFORE_DTX 10 /* eq 200 ms */
+#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */
+
+/* Maximum sampling frequency */
+#define MAX_FS_KHZ 16
+#define MAX_API_FS_KHZ 48
+
+/* Signal types */
+#define TYPE_NO_VOICE_ACTIVITY 0
+#define TYPE_UNVOICED 1
+#define TYPE_VOICED 2
+
+/* Conditional coding types */
+#define CODE_INDEPENDENTLY 0
+#define CODE_INDEPENDENTLY_NO_LTP_SCALING 1
+#define CODE_CONDITIONALLY 2
+
+/* Settings for stereo processing */
+#define STEREO_QUANT_TAB_SIZE 16
+#define STEREO_QUANT_SUB_STEPS 5
+#define STEREO_INTERP_LEN_MS 8 /* must be even */
+#define STEREO_RATIO_SMOOTH_COEF 0.01 /* smoothing coef for signal norms and stereo width */
+
+/* Range of pitch lag estimates */
+#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */
+#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */
+
+/* Maximum number of subframes */
+#define MAX_NB_SUBFR 4
+
+/* Number of samples per frame */
+#define LTP_MEM_LENGTH_MS 20
+#define SUB_FRAME_LENGTH_MS 5
+#define MAX_SUB_FRAME_LENGTH ( SUB_FRAME_LENGTH_MS * MAX_FS_KHZ )
+#define MAX_FRAME_LENGTH_MS ( SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR )
+#define MAX_FRAME_LENGTH ( MAX_FRAME_LENGTH_MS * MAX_FS_KHZ )
+
+/* Milliseconds of lookahead for pitch analysis */
+#define LA_PITCH_MS 2
+#define LA_PITCH_MAX ( LA_PITCH_MS * MAX_FS_KHZ )
+
+/* Order of LPC used in find pitch */
+#define MAX_FIND_PITCH_LPC_ORDER 16
+
+/* Length of LPC window used in find pitch */
+#define FIND_PITCH_LPC_WIN_MS ( 20 + (LA_PITCH_MS << 1) )
+#define FIND_PITCH_LPC_WIN_MS_2_SF ( 10 + (LA_PITCH_MS << 1) )
+#define FIND_PITCH_LPC_WIN_MAX ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ )
+
+/* Milliseconds of lookahead for noise shape analysis */
+#define LA_SHAPE_MS 5
+#define LA_SHAPE_MAX ( LA_SHAPE_MS * MAX_FS_KHZ )
+
+/* Maximum length of LPC window used in noise shape analysis */
+#define SHAPE_LPC_WIN_MAX ( 15 * MAX_FS_KHZ )
+
+/* dB level of lowest gain quantization level */
+#define MIN_QGAIN_DB 2
+/* dB level of highest gain quantization level */
+#define MAX_QGAIN_DB 88
+/* Number of gain quantization levels */
+#define N_LEVELS_QGAIN 64
+/* Max increase in gain quantization index */
+#define MAX_DELTA_GAIN_QUANT 36
+/* Max decrease in gain quantization index */
+#define MIN_DELTA_GAIN_QUANT -4
+
+/* Quantization offsets (multiples of 4) */
+#define OFFSET_VL_Q10 32
+#define OFFSET_VH_Q10 100
+#define OFFSET_UVL_Q10 100
+#define OFFSET_UVH_Q10 240
+
+#define QUANT_LEVEL_ADJUST_Q10 80
+
+/* Maximum numbers of iterations used to stabilize an LPC vector */
+#define MAX_LPC_STABILIZE_ITERATIONS 16
+#define MAX_PREDICTION_POWER_GAIN 1e4f
+#define MAX_PREDICTION_POWER_GAIN_AFTER_RESET 1e2f
+
+#define MAX_LPC_ORDER 16
+#define MIN_LPC_ORDER 10
+
+/* Find Pred Coef defines */
+#define LTP_ORDER 5
+
+/* LTP quantization settings */
+#define NB_LTP_CBKS 3
+
+/* Flag to use harmonic noise shaping */
+#define USE_HARM_SHAPING 1
+
+/* Max LPC order of noise shaping filters */
+#define MAX_SHAPE_LPC_ORDER 16
+
+#define HARM_SHAPE_FIR_TAPS 3
+
+/* Maximum number of delayed decision states */
+#define MAX_DEL_DEC_STATES 4
+
+#define LTP_BUF_LENGTH 512
+#define LTP_MASK ( LTP_BUF_LENGTH - 1 )
+
+#define DECISION_DELAY 32
+#define DECISION_DELAY_MASK ( DECISION_DELAY - 1 )
+
+/* Number of subframes for excitation entropy coding */
+#define SHELL_CODEC_FRAME_LENGTH 16
+#define LOG2_SHELL_CODEC_FRAME_LENGTH 4
+#define MAX_NB_SHELL_BLOCKS ( MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH )
+
+/* Number of rate levels, for entropy coding of excitation */
+#define N_RATE_LEVELS 10
+
+/* Maximum sum of pulses per shell coding frame */
+#define SILK_MAX_PULSES 16
+
+#define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */
+
+#if( MAX_LPC_ORDER > DECISION_DELAY )
+# define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER
+#else
+# define NSQ_LPC_BUF_LENGTH DECISION_DELAY
+#endif
+
+/***************************/
+/* Voice activity detector */
+/***************************/
+#define VAD_N_BANDS 4
+
+#define VAD_INTERNAL_SUBFRAMES_LOG2 2
+#define VAD_INTERNAL_SUBFRAMES ( 1 << VAD_INTERNAL_SUBFRAMES_LOG2 )
+
+#define VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 1024 /* Must be < 4096 */
+#define VAD_NOISE_LEVELS_BIAS 50
+
+/* Sigmoid settings */
+#define VAD_NEGATIVE_OFFSET_Q5 128 /* sigmoid is 0 at -128 */
+#define VAD_SNR_FACTOR_Q16 45000
+
+/* smoothing for SNR measurement */
+#define VAD_SNR_SMOOTH_COEF_Q18 4096
+
+/* Size of the piecewise linear cosine approximation table for the LSFs */
+#define LSF_COS_TAB_SZ_FIX 128
+
+/******************/
+/* NLSF quantizer */
+/******************/
+#define NLSF_W_Q 2
+#define NLSF_VQ_MAX_VECTORS 32
+#define NLSF_VQ_MAX_SURVIVORS 32
+#define NLSF_QUANT_MAX_AMPLITUDE 4
+#define NLSF_QUANT_MAX_AMPLITUDE_EXT 10
+#define NLSF_QUANT_LEVEL_ADJ 0.1
+#define NLSF_QUANT_DEL_DEC_STATES_LOG2 2
+#define NLSF_QUANT_DEL_DEC_STATES ( 1 << NLSF_QUANT_DEL_DEC_STATES_LOG2 )
+
+/* Transition filtering for mode switching */
+#define TRANSITION_TIME_MS 5120 /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4)*/
+#define TRANSITION_NB 3 /* Hardcoded in tables */
+#define TRANSITION_NA 2 /* Hardcoded in tables */
+#define TRANSITION_INT_NUM 5 /* Hardcoded in tables */
+#define TRANSITION_FRAMES ( TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS )
+#define TRANSITION_INT_STEPS ( TRANSITION_FRAMES / ( TRANSITION_INT_NUM - 1 ) )
+
+/* BWE factors to apply after packet loss */
+#define BWE_AFTER_LOSS_Q16 63570
+
+/* Defines for CN generation */
+#define CNG_BUF_MASK_MAX 255 /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */
+#define CNG_GAIN_SMTH_Q16 4634 /* 0.25^(1/4) */
+#define CNG_NLSF_SMTH_Q16 16348 /* 0.25 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/silk/enc_API.c b/external/opus-1.1.4/silk/enc_API.c
new file mode 100644
index 0000000..f806028
--- /dev/null
+++ b/external/opus-1.1.4/silk/enc_API.c
@@ -0,0 +1,563 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "define.h"
+#include "API.h"
+#include "control.h"
+#include "typedef.h"
+#include "stack_alloc.h"
+#include "structs.h"
+#include "tuning_parameters.h"
+#ifdef FIXED_POINT
+#include "main_FIX.h"
+#else
+#include "main_FLP.h"
+#endif
+
+/***************************************/
+/* Read control structure from encoder */
+/***************************************/
+static opus_int silk_QueryEncoder( /* O Returns error code */
+ const void *encState, /* I State */
+ silk_EncControlStruct *encStatus /* O Encoder Status */
+);
+
+/****************************************/
+/* Encoder functions */
+/****************************************/
+
+opus_int silk_Get_Encoder_Size( /* O Returns error code */
+ opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+
+ *encSizeBytes = sizeof( silk_encoder );
+
+ return ret;
+}
+
+/*************************/
+/* Init or Reset encoder */
+/*************************/
+opus_int silk_InitEncoder( /* O Returns error code */
+ void *encState, /* I/O State */
+ int arch, /* I Run-time architecture */
+ silk_EncControlStruct *encStatus /* O Encoder Status */
+)
+{
+ silk_encoder *psEnc;
+ opus_int n, ret = SILK_NO_ERROR;
+
+ psEnc = (silk_encoder *)encState;
+
+ /* Reset encoder */
+ silk_memset( psEnc, 0, sizeof( silk_encoder ) );
+ for( n = 0; n < ENCODER_NUM_CHANNELS; n++ ) {
+ if( ret += silk_init_encoder( &psEnc->state_Fxx[ n ], arch ) ) {
+ silk_assert( 0 );
+ }
+ }
+
+ psEnc->nChannelsAPI = 1;
+ psEnc->nChannelsInternal = 1;
+
+ /* Read control structure */
+ if( ret += silk_QueryEncoder( encState, encStatus ) ) {
+ silk_assert( 0 );
+ }
+
+ return ret;
+}
+
+/***************************************/
+/* Read control structure from encoder */
+/***************************************/
+static opus_int silk_QueryEncoder( /* O Returns error code */
+ const void *encState, /* I State */
+ silk_EncControlStruct *encStatus /* O Encoder Status */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+ silk_encoder_state_Fxx *state_Fxx;
+ silk_encoder *psEnc = (silk_encoder *)encState;
+
+ state_Fxx = psEnc->state_Fxx;
+
+ encStatus->nChannelsAPI = psEnc->nChannelsAPI;
+ encStatus->nChannelsInternal = psEnc->nChannelsInternal;
+ encStatus->API_sampleRate = state_Fxx[ 0 ].sCmn.API_fs_Hz;
+ encStatus->maxInternalSampleRate = state_Fxx[ 0 ].sCmn.maxInternal_fs_Hz;
+ encStatus->minInternalSampleRate = state_Fxx[ 0 ].sCmn.minInternal_fs_Hz;
+ encStatus->desiredInternalSampleRate = state_Fxx[ 0 ].sCmn.desiredInternal_fs_Hz;
+ encStatus->payloadSize_ms = state_Fxx[ 0 ].sCmn.PacketSize_ms;
+ encStatus->bitRate = state_Fxx[ 0 ].sCmn.TargetRate_bps;
+ encStatus->packetLossPercentage = state_Fxx[ 0 ].sCmn.PacketLoss_perc;
+ encStatus->complexity = state_Fxx[ 0 ].sCmn.Complexity;
+ encStatus->useInBandFEC = state_Fxx[ 0 ].sCmn.useInBandFEC;
+ encStatus->useDTX = state_Fxx[ 0 ].sCmn.useDTX;
+ encStatus->useCBR = state_Fxx[ 0 ].sCmn.useCBR;
+ encStatus->internalSampleRate = silk_SMULBB( state_Fxx[ 0 ].sCmn.fs_kHz, 1000 );
+ encStatus->allowBandwidthSwitch = state_Fxx[ 0 ].sCmn.allow_bandwidth_switch;
+ encStatus->inWBmodeWithoutVariableLP = state_Fxx[ 0 ].sCmn.fs_kHz == 16 && state_Fxx[ 0 ].sCmn.sLP.mode == 0;
+
+ return ret;
+}
+
+
+/**************************/
+/* Encode frame with Silk */
+/**************************/
+/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */
+/* encControl->payloadSize_ms is set to */
+opus_int silk_Encode( /* O Returns error code */
+ void *encState, /* I/O State */
+ silk_EncControlStruct *encControl, /* I Control status */
+ const opus_int16 *samplesIn, /* I Speech sample input vector */
+ opus_int nSamplesIn, /* I Number of samples in input vector */
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
+ const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */
+)
+{
+ opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0;
+ opus_int nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms;
+ opus_int nSamplesFromInput = 0, nSamplesFromInputMax;
+ opus_int speech_act_thr_for_switch_Q8;
+ opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol, sum;
+ silk_encoder *psEnc = ( silk_encoder * )encState;
+ VARDECL( opus_int16, buf );
+ opus_int transition, curr_block, tot_blocks;
+ SAVE_STACK;
+
+ if (encControl->reducedDependency)
+ {
+ psEnc->state_Fxx[0].sCmn.first_frame_after_reset = 1;
+ psEnc->state_Fxx[1].sCmn.first_frame_after_reset = 1;
+ }
+ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded = psEnc->state_Fxx[ 1 ].sCmn.nFramesEncoded = 0;
+
+ /* Check values in encoder control structure */
+ if( ( ret = check_control_input( encControl ) ) != 0 ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return ret;
+ }
+
+ encControl->switchReady = 0;
+
+ if( encControl->nChannelsInternal > psEnc->nChannelsInternal ) {
+ /* Mono -> Stereo transition: init state of second channel and stereo state */
+ ret += silk_init_encoder( &psEnc->state_Fxx[ 1 ], psEnc->state_Fxx[ 0 ].sCmn.arch );
+ silk_memset( psEnc->sStereo.pred_prev_Q13, 0, sizeof( psEnc->sStereo.pred_prev_Q13 ) );
+ silk_memset( psEnc->sStereo.sSide, 0, sizeof( psEnc->sStereo.sSide ) );
+ psEnc->sStereo.mid_side_amp_Q0[ 0 ] = 0;
+ psEnc->sStereo.mid_side_amp_Q0[ 1 ] = 1;
+ psEnc->sStereo.mid_side_amp_Q0[ 2 ] = 0;
+ psEnc->sStereo.mid_side_amp_Q0[ 3 ] = 1;
+ psEnc->sStereo.width_prev_Q14 = 0;
+ psEnc->sStereo.smth_width_Q14 = SILK_FIX_CONST( 1, 14 );
+ if( psEnc->nChannelsAPI == 2 ) {
+ silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof( silk_resampler_state_struct ) );
+ silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.In_HP_State, &psEnc->state_Fxx[ 0 ].sCmn.In_HP_State, sizeof( psEnc->state_Fxx[ 1 ].sCmn.In_HP_State ) );
+ }
+ }
+
+ transition = (encControl->payloadSize_ms != psEnc->state_Fxx[ 0 ].sCmn.PacketSize_ms) || (psEnc->nChannelsInternal != encControl->nChannelsInternal);
+
+ psEnc->nChannelsAPI = encControl->nChannelsAPI;
+ psEnc->nChannelsInternal = encControl->nChannelsInternal;
+
+ nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate );
+ tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1;
+ curr_block = 0;
+ if( prefillFlag ) {
+ /* Only accept input length of 10 ms */
+ if( nBlocksOf10ms != 1 ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+ }
+ /* Reset Encoder */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ ret = silk_init_encoder( &psEnc->state_Fxx[ n ], psEnc->state_Fxx[ n ].sCmn.arch );
+ silk_assert( !ret );
+ }
+ tmp_payloadSize_ms = encControl->payloadSize_ms;
+ encControl->payloadSize_ms = 10;
+ tmp_complexity = encControl->complexity;
+ encControl->complexity = 0;
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+ psEnc->state_Fxx[ n ].sCmn.prefillFlag = 1;
+ }
+ } else {
+ /* Only accept input lengths that are a multiple of 10 ms */
+ if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+ }
+ /* Make sure no more than one packet can be produced */
+ if( 1000 * (opus_int32)nSamplesIn > encControl->payloadSize_ms * encControl->API_sampleRate ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+ }
+ }
+
+ TargetRate_bps = silk_RSHIFT32( encControl->bitRate, encControl->nChannelsInternal - 1 );
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ /* Force the side channel to the same rate as the mid */
+ opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0;
+ if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, TargetRate_bps, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return ret;
+ }
+ if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) {
+ for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) {
+ psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0;
+ }
+ }
+ psEnc->state_Fxx[ n ].sCmn.inDTX = psEnc->state_Fxx[ n ].sCmn.useDTX;
+ }
+ silk_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz );
+
+ /* Input buffering/resampling and encoding */
+ nSamplesToBufferMax =
+ 10 * nBlocksOf10ms * psEnc->state_Fxx[ 0 ].sCmn.fs_kHz;
+ nSamplesFromInputMax =
+ silk_DIV32_16( nSamplesToBufferMax *
+ psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz,
+ psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 );
+ ALLOC( buf, nSamplesFromInputMax, opus_int16 );
+ while( 1 ) {
+ nSamplesToBuffer = psEnc->state_Fxx[ 0 ].sCmn.frame_length - psEnc->state_Fxx[ 0 ].sCmn.inputBufIx;
+ nSamplesToBuffer = silk_min( nSamplesToBuffer, nSamplesToBufferMax );
+ nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 );
+ /* Resample and write to buffer */
+ if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) {
+ opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
+ for( n = 0; n < nSamplesFromInput; n++ ) {
+ buf[ n ] = samplesIn[ 2 * n ];
+ }
+ /* Making sure to start both resamplers from the same state when switching from mono to stereo */
+ if( psEnc->nPrevChannelsInternal == 1 && id==0 ) {
+ silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof(psEnc->state_Fxx[ 1 ].sCmn.resampler_state));
+ }
+
+ ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+
+ nSamplesToBuffer = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx;
+ nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz );
+ for( n = 0; n < nSamplesFromInput; n++ ) {
+ buf[ n ] = samplesIn[ 2 * n + 1 ];
+ }
+ ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+
+ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx += nSamplesToBuffer;
+ } else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) {
+ /* Combine left and right channels before resampling */
+ for( n = 0; n < nSamplesFromInput; n++ ) {
+ sum = samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ];
+ buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 );
+ }
+ ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ /* On the first mono frame, average the results for the two resampler states */
+ if( psEnc->nPrevChannelsInternal == 2 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 ) {
+ ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ for( n = 0; n < psEnc->state_Fxx[ 0 ].sCmn.frame_length; n++ ) {
+ psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] =
+ silk_RSHIFT(psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ]
+ + psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx+n+2 ], 1);
+ }
+ }
+ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+ } else {
+ silk_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 );
+ silk_memcpy(buf, samplesIn, nSamplesFromInput*sizeof(opus_int16));
+ ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+ }
+
+ samplesIn += nSamplesFromInput * encControl->nChannelsAPI;
+ nSamplesIn -= nSamplesFromInput;
+
+ /* Default */
+ psEnc->allowBandwidthSwitch = 0;
+
+ /* Silk encoder */
+ if( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx >= psEnc->state_Fxx[ 0 ].sCmn.frame_length ) {
+ /* Enough data in input buffer, so encode */
+ silk_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length );
+ silk_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inputBufIx == psEnc->state_Fxx[ 1 ].sCmn.frame_length );
+
+ /* Deal with LBRR data */
+ if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 && !prefillFlag ) {
+ /* Create space at start of payload for VAD and FEC flags */
+ opus_uint8 iCDF[ 2 ] = { 0, 0 };
+ iCDF[ 0 ] = 256 - silk_RSHIFT( 256, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal );
+ ec_enc_icdf( psRangeEnc, 0, iCDF, 8 );
+
+ /* Encode any LBRR data from previous packet */
+ /* Encode LBRR flags */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ LBRR_symbol = 0;
+ for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) {
+ LBRR_symbol |= silk_LSHIFT( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ], i );
+ }
+ psEnc->state_Fxx[ n ].sCmn.LBRR_flag = LBRR_symbol > 0 ? 1 : 0;
+ if( LBRR_symbol && psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket > 1 ) {
+ ec_enc_icdf( psRangeEnc, LBRR_symbol - 1, silk_LBRR_flags_iCDF_ptr[ psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket - 2 ], 8 );
+ }
+ }
+
+ /* Code LBRR indices and excitation signals */
+ for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) {
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ if( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] ) {
+ opus_int condCoding;
+
+ if( encControl->nChannelsInternal == 2 && n == 0 ) {
+ silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ i ] );
+ /* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */
+ if( psEnc->state_Fxx[ 1 ].sCmn.LBRR_flags[ i ] == 0 ) {
+ silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ i ] );
+ }
+ }
+ /* Use conditional coding if previous frame available */
+ if( i > 0 && psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i - 1 ] ) {
+ condCoding = CODE_CONDITIONALLY;
+ } else {
+ condCoding = CODE_INDEPENDENTLY;
+ }
+ silk_encode_indices( &psEnc->state_Fxx[ n ].sCmn, psRangeEnc, i, 1, condCoding );
+ silk_encode_pulses( psRangeEnc, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].signalType, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].quantOffsetType,
+ psEnc->state_Fxx[ n ].sCmn.pulses_LBRR[ i ], psEnc->state_Fxx[ n ].sCmn.frame_length );
+ }
+ }
+ }
+
+ /* Reset LBRR flags */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ silk_memset( psEnc->state_Fxx[ n ].sCmn.LBRR_flags, 0, sizeof( psEnc->state_Fxx[ n ].sCmn.LBRR_flags ) );
+ }
+
+ psEnc->nBitsUsedLBRR = ec_tell( psRangeEnc );
+ }
+
+ silk_HP_variable_cutoff( psEnc->state_Fxx );
+
+ /* Total target bits for packet */
+ nBits = silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 );
+ /* Subtract bits used for LBRR */
+ if( !prefillFlag ) {
+ nBits -= psEnc->nBitsUsedLBRR;
+ }
+ /* Divide by number of uncoded frames left in packet */
+ nBits = silk_DIV32_16( nBits, psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket );
+ /* Convert to bits/second */
+ if( encControl->payloadSize_ms == 10 ) {
+ TargetRate_bps = silk_SMULBB( nBits, 100 );
+ } else {
+ TargetRate_bps = silk_SMULBB( nBits, 50 );
+ }
+ /* Subtract fraction of bits in excess of target in previous frames and packets */
+ TargetRate_bps -= silk_DIV32_16( silk_MUL( psEnc->nBitsExceeded, 1000 ), BITRESERVOIR_DECAY_TIME_MS );
+ if( !prefillFlag && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded > 0 ) {
+ /* Compare actual vs target bits so far in this packet */
+ opus_int32 bitsBalance = ec_tell( psRangeEnc ) - psEnc->nBitsUsedLBRR - nBits * psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
+ TargetRate_bps -= silk_DIV32_16( silk_MUL( bitsBalance, 1000 ), BITRESERVOIR_DECAY_TIME_MS );
+ }
+ /* Never exceed input bitrate */
+ TargetRate_bps = silk_LIMIT( TargetRate_bps, encControl->bitRate, 5000 );
+
+ /* Convert Left/Right to Mid/Side */
+ if( encControl->nChannelsInternal == 2 ) {
+ silk_stereo_LR_to_MS( &psEnc->sStereo, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ 2 ], &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ 2 ],
+ psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], &psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ],
+ MStargetRates_bps, TargetRate_bps, psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8, encControl->toMono,
+ psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, psEnc->state_Fxx[ 0 ].sCmn.frame_length );
+ if( psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) {
+ /* Reset side channel encoder memory for first frame with side coding */
+ if( psEnc->prev_decode_only_middle == 1 ) {
+ silk_memset( &psEnc->state_Fxx[ 1 ].sShape, 0, sizeof( psEnc->state_Fxx[ 1 ].sShape ) );
+ silk_memset( &psEnc->state_Fxx[ 1 ].sPrefilt, 0, sizeof( psEnc->state_Fxx[ 1 ].sPrefilt ) );
+ silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sNSQ, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sNSQ ) );
+ silk_memset( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15 ) );
+ silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State ) );
+ psEnc->state_Fxx[ 1 ].sCmn.prevLag = 100;
+ psEnc->state_Fxx[ 1 ].sCmn.sNSQ.lagPrev = 100;
+ psEnc->state_Fxx[ 1 ].sShape.LastGainIndex = 10;
+ psEnc->state_Fxx[ 1 ].sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY;
+ psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536;
+ psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1;
+ }
+ silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ] );
+ } else {
+ psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0;
+ }
+ if( !prefillFlag ) {
+ silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] );
+ if( psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) {
+ silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] );
+ }
+ }
+ } else {
+ /* Buffering */
+ silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) );
+ }
+ silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ] );
+
+ /* Encode */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ opus_int maxBits, useCBR;
+
+ /* Handling rate constraints */
+ maxBits = encControl->maxBits;
+ if( tot_blocks == 2 && curr_block == 0 ) {
+ maxBits = maxBits * 3 / 5;
+ } else if( tot_blocks == 3 ) {
+ if( curr_block == 0 ) {
+ maxBits = maxBits * 2 / 5;
+ } else if( curr_block == 1 ) {
+ maxBits = maxBits * 3 / 4;
+ }
+ }
+ useCBR = encControl->useCBR && curr_block == tot_blocks - 1;
+
+ if( encControl->nChannelsInternal == 1 ) {
+ channelRate_bps = TargetRate_bps;
+ } else {
+ channelRate_bps = MStargetRates_bps[ n ];
+ if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) {
+ useCBR = 0;
+ /* Give mid up to 1/2 of the max bits for that frame */
+ maxBits -= encControl->maxBits / ( tot_blocks * 2 );
+ }
+ }
+
+ if( channelRate_bps > 0 ) {
+ opus_int condCoding;
+
+ silk_control_SNR( &psEnc->state_Fxx[ n ].sCmn, channelRate_bps );
+
+ /* Use independent coding if no previous frame available */
+ if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - n <= 0 ) {
+ condCoding = CODE_INDEPENDENTLY;
+ } else if( n > 0 && psEnc->prev_decode_only_middle ) {
+ /* If we skipped a side frame in this packet, we don't
+ need LTP scaling; the LTP state is well-defined. */
+ condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING;
+ } else {
+ condCoding = CODE_CONDITIONALLY;
+ }
+ if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) {
+ silk_assert( 0 );
+ }
+ }
+ psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+ psEnc->state_Fxx[ n ].sCmn.inputBufIx = 0;
+ psEnc->state_Fxx[ n ].sCmn.nFramesEncoded++;
+ }
+ psEnc->prev_decode_only_middle = psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - 1 ];
+
+ /* Insert VAD and FEC flags at beginning of bitstream */
+ if( *nBytesOut > 0 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket) {
+ flags = 0;
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) {
+ flags = silk_LSHIFT( flags, 1 );
+ flags |= psEnc->state_Fxx[ n ].sCmn.VAD_flags[ i ];
+ }
+ flags = silk_LSHIFT( flags, 1 );
+ flags |= psEnc->state_Fxx[ n ].sCmn.LBRR_flag;
+ }
+ if( !prefillFlag ) {
+ ec_enc_patch_initial_bits( psRangeEnc, flags, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal );
+ }
+
+ /* Return zero bytes if all channels DTXed */
+ if( psEnc->state_Fxx[ 0 ].sCmn.inDTX && ( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inDTX ) ) {
+ *nBytesOut = 0;
+ }
+
+ psEnc->nBitsExceeded += *nBytesOut * 8;
+ psEnc->nBitsExceeded -= silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 );
+ psEnc->nBitsExceeded = silk_LIMIT( psEnc->nBitsExceeded, 0, 10000 );
+
+ /* Update flag indicating if bandwidth switching is allowed */
+ speech_act_thr_for_switch_Q8 = silk_SMLAWB( SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ),
+ SILK_FIX_CONST( ( 1 - SPEECH_ACTIVITY_DTX_THRES ) / MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8 ), psEnc->timeSinceSwitchAllowed_ms );
+ if( psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8 < speech_act_thr_for_switch_Q8 ) {
+ psEnc->allowBandwidthSwitch = 1;
+ psEnc->timeSinceSwitchAllowed_ms = 0;
+ } else {
+ psEnc->allowBandwidthSwitch = 0;
+ psEnc->timeSinceSwitchAllowed_ms += encControl->payloadSize_ms;
+ }
+ }
+
+ if( nSamplesIn == 0 ) {
+ break;
+ }
+ } else {
+ break;
+ }
+ curr_block++;
+ }
+
+ psEnc->nPrevChannelsInternal = encControl->nChannelsInternal;
+
+ encControl->allowBandwidthSwitch = psEnc->allowBandwidthSwitch;
+ encControl->inWBmodeWithoutVariableLP = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == 16 && psEnc->state_Fxx[ 0 ].sCmn.sLP.mode == 0;
+ encControl->internalSampleRate = silk_SMULBB( psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, 1000 );
+ encControl->stereoWidth_Q14 = encControl->toMono ? 0 : psEnc->sStereo.smth_width_Q14;
+ if( prefillFlag ) {
+ encControl->payloadSize_ms = tmp_payloadSize_ms;
+ encControl->complexity = tmp_complexity;
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+ psEnc->state_Fxx[ n ].sCmn.prefillFlag = 0;
+ }
+ }
+
+ RESTORE_STACK;
+ return ret;
+}
+
diff --git a/external/opus-1.1.4/silk/encode_indices.c b/external/opus-1.1.4/silk/encode_indices.c
new file mode 100644
index 0000000..666c8c0
--- /dev/null
+++ b/external/opus-1.1.4/silk/encode_indices.c
@@ -0,0 +1,181 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Encode side-information parameters to payload */
+void silk_encode_indices(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int FrameIndex, /* I Frame number */
+ opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i, k, typeOffset;
+ opus_int encode_absolute_lagIndex, delta_lagIndex;
+ opus_int16 ec_ix[ MAX_LPC_ORDER ];
+ opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+ const SideInfoIndices *psIndices;
+
+ if( encode_LBRR ) {
+ psIndices = &psEncC->indices_LBRR[ FrameIndex ];
+ } else {
+ psIndices = &psEncC->indices;
+ }
+
+ /*******************************************/
+ /* Encode signal type and quantizer offset */
+ /*******************************************/
+ typeOffset = 2 * psIndices->signalType + psIndices->quantOffsetType;
+ silk_assert( typeOffset >= 0 && typeOffset < 6 );
+ silk_assert( encode_LBRR == 0 || typeOffset >= 2 );
+ if( encode_LBRR || typeOffset >= 2 ) {
+ ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 );
+ } else {
+ ec_enc_icdf( psRangeEnc, typeOffset, silk_type_offset_no_VAD_iCDF, 8 );
+ }
+
+ /****************/
+ /* Encode gains */
+ /****************/
+ /* first subframe */
+ if( condCoding == CODE_CONDITIONALLY ) {
+ /* conditional coding */
+ silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 );
+ ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ], silk_delta_gain_iCDF, 8 );
+ } else {
+ /* independent coding, in two stages: MSB bits followed by 3 LSBs */
+ silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < N_LEVELS_QGAIN );
+ ec_enc_icdf( psRangeEnc, silk_RSHIFT( psIndices->GainsIndices[ 0 ], 3 ), silk_gain_iCDF[ psIndices->signalType ], 8 );
+ ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ] & 7, silk_uniform8_iCDF, 8 );
+ }
+
+ /* remaining subframes */
+ for( i = 1; i < psEncC->nb_subfr; i++ ) {
+ silk_assert( psIndices->GainsIndices[ i ] >= 0 && psIndices->GainsIndices[ i ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 );
+ ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ i ], silk_delta_gain_iCDF, 8 );
+ }
+
+ /****************/
+ /* Encode NLSFs */
+ /****************/
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ 0 ], &psEncC->psNLSF_CB->CB1_iCDF[ ( psIndices->signalType >> 1 ) * psEncC->psNLSF_CB->nVectors ], 8 );
+ silk_NLSF_unpack( ec_ix, pred_Q8, psEncC->psNLSF_CB, psIndices->NLSFIndices[ 0 ] );
+ silk_assert( psEncC->psNLSF_CB->order == psEncC->predictLPCOrder );
+ for( i = 0; i < psEncC->psNLSF_CB->order; i++ ) {
+ if( psIndices->NLSFIndices[ i+1 ] >= NLSF_QUANT_MAX_AMPLITUDE ) {
+ ec_enc_icdf( psRangeEnc, 2 * NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 );
+ } else if( psIndices->NLSFIndices[ i+1 ] <= -NLSF_QUANT_MAX_AMPLITUDE ) {
+ ec_enc_icdf( psRangeEnc, 0, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+ ec_enc_icdf( psRangeEnc, -psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 );
+ } else {
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] + NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+ }
+ }
+
+ /* Encode NLSF interpolation factor */
+ if( psEncC->nb_subfr == MAX_NB_SUBFR ) {
+ silk_assert( psIndices->NLSFInterpCoef_Q2 >= 0 && psIndices->NLSFInterpCoef_Q2 < 5 );
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFInterpCoef_Q2, silk_NLSF_interpolation_factor_iCDF, 8 );
+ }
+
+ if( psIndices->signalType == TYPE_VOICED )
+ {
+ /*********************/
+ /* Encode pitch lags */
+ /*********************/
+ /* lag index */
+ encode_absolute_lagIndex = 1;
+ if( condCoding == CODE_CONDITIONALLY && psEncC->ec_prevSignalType == TYPE_VOICED ) {
+ /* Delta Encoding */
+ delta_lagIndex = psIndices->lagIndex - psEncC->ec_prevLagIndex;
+ if( delta_lagIndex < -8 || delta_lagIndex > 11 ) {
+ delta_lagIndex = 0;
+ } else {
+ delta_lagIndex = delta_lagIndex + 9;
+ encode_absolute_lagIndex = 0; /* Only use delta */
+ }
+ silk_assert( delta_lagIndex >= 0 && delta_lagIndex < 21 );
+ ec_enc_icdf( psRangeEnc, delta_lagIndex, silk_pitch_delta_iCDF, 8 );
+ }
+ if( encode_absolute_lagIndex ) {
+ /* Absolute encoding */
+ opus_int32 pitch_high_bits, pitch_low_bits;
+ pitch_high_bits = silk_DIV32_16( psIndices->lagIndex, silk_RSHIFT( psEncC->fs_kHz, 1 ) );
+ pitch_low_bits = psIndices->lagIndex - silk_SMULBB( pitch_high_bits, silk_RSHIFT( psEncC->fs_kHz, 1 ) );
+ silk_assert( pitch_low_bits < psEncC->fs_kHz / 2 );
+ silk_assert( pitch_high_bits < 32 );
+ ec_enc_icdf( psRangeEnc, pitch_high_bits, silk_pitch_lag_iCDF, 8 );
+ ec_enc_icdf( psRangeEnc, pitch_low_bits, psEncC->pitch_lag_low_bits_iCDF, 8 );
+ }
+ psEncC->ec_prevLagIndex = psIndices->lagIndex;
+
+ /* Countour index */
+ silk_assert( psIndices->contourIndex >= 0 );
+ silk_assert( ( psIndices->contourIndex < 34 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 4 ) ||
+ ( psIndices->contourIndex < 11 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 4 ) ||
+ ( psIndices->contourIndex < 12 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 2 ) ||
+ ( psIndices->contourIndex < 3 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 2 ) );
+ ec_enc_icdf( psRangeEnc, psIndices->contourIndex, psEncC->pitch_contour_iCDF, 8 );
+
+ /********************/
+ /* Encode LTP gains */
+ /********************/
+ /* PERIndex value */
+ silk_assert( psIndices->PERIndex >= 0 && psIndices->PERIndex < 3 );
+ ec_enc_icdf( psRangeEnc, psIndices->PERIndex, silk_LTP_per_index_iCDF, 8 );
+
+ /* Codebook Indices */
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ silk_assert( psIndices->LTPIndex[ k ] >= 0 && psIndices->LTPIndex[ k ] < ( 8 << psIndices->PERIndex ) );
+ ec_enc_icdf( psRangeEnc, psIndices->LTPIndex[ k ], silk_LTP_gain_iCDF_ptrs[ psIndices->PERIndex ], 8 );
+ }
+
+ /**********************/
+ /* Encode LTP scaling */
+ /**********************/
+ if( condCoding == CODE_INDEPENDENTLY ) {
+ silk_assert( psIndices->LTP_scaleIndex >= 0 && psIndices->LTP_scaleIndex < 3 );
+ ec_enc_icdf( psRangeEnc, psIndices->LTP_scaleIndex, silk_LTPscale_iCDF, 8 );
+ }
+ silk_assert( !condCoding || psIndices->LTP_scaleIndex == 0 );
+ }
+
+ psEncC->ec_prevSignalType = psIndices->signalType;
+
+ /***************/
+ /* Encode seed */
+ /***************/
+ silk_assert( psIndices->Seed >= 0 && psIndices->Seed < 4 );
+ ec_enc_icdf( psRangeEnc, psIndices->Seed, silk_uniform4_iCDF, 8 );
+}
diff --git a/external/opus-1.1.4/silk/encode_pulses.c b/external/opus-1.1.4/silk/encode_pulses.c
new file mode 100644
index 0000000..ab00264
--- /dev/null
+++ b/external/opus-1.1.4/silk/encode_pulses.c
@@ -0,0 +1,206 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/*********************************************/
+/* Encode quantization indices of excitation */
+/*********************************************/
+
+static OPUS_INLINE opus_int combine_and_check( /* return ok */
+ opus_int *pulses_comb, /* O */
+ const opus_int *pulses_in, /* I */
+ opus_int max_pulses, /* I max value for sum of pulses */
+ opus_int len /* I number of output values */
+)
+{
+ opus_int k, sum;
+
+ for( k = 0; k < len; k++ ) {
+ sum = pulses_in[ 2 * k ] + pulses_in[ 2 * k + 1 ];
+ if( sum > max_pulses ) {
+ return 1;
+ }
+ pulses_comb[ k ] = sum;
+ }
+
+ return 0;
+}
+
+/* Encode quantization indices of excitation */
+void silk_encode_pulses(
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I quantOffsetType */
+ opus_int8 pulses[], /* I quantization indices */
+ const opus_int frame_length /* I Frame length */
+)
+{
+ opus_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0;
+ opus_int32 abs_q, minSumBits_Q5, sumBits_Q5;
+ VARDECL( opus_int, abs_pulses );
+ VARDECL( opus_int, sum_pulses );
+ VARDECL( opus_int, nRshifts );
+ opus_int pulses_comb[ 8 ];
+ opus_int *abs_pulses_ptr;
+ const opus_int8 *pulses_ptr;
+ const opus_uint8 *cdf_ptr;
+ const opus_uint8 *nBits_ptr;
+ SAVE_STACK;
+
+ silk_memset( pulses_comb, 0, 8 * sizeof( opus_int ) ); /* Fixing Valgrind reported problem*/
+
+ /****************************/
+ /* Prepare for shell coding */
+ /****************************/
+ /* Calculate number of shell blocks */
+ silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH );
+ iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH );
+ if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) {
+ silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */
+ iter++;
+ silk_memset( &pulses[ frame_length ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(opus_int8));
+ }
+
+ /* Take the absolute value of the pulses */
+ ALLOC( abs_pulses, iter * SHELL_CODEC_FRAME_LENGTH, opus_int );
+ silk_assert( !( SHELL_CODEC_FRAME_LENGTH & 3 ) );
+ for( i = 0; i < iter * SHELL_CODEC_FRAME_LENGTH; i+=4 ) {
+ abs_pulses[i+0] = ( opus_int )silk_abs( pulses[ i + 0 ] );
+ abs_pulses[i+1] = ( opus_int )silk_abs( pulses[ i + 1 ] );
+ abs_pulses[i+2] = ( opus_int )silk_abs( pulses[ i + 2 ] );
+ abs_pulses[i+3] = ( opus_int )silk_abs( pulses[ i + 3 ] );
+ }
+
+ /* Calc sum pulses per shell code frame */
+ ALLOC( sum_pulses, iter, opus_int );
+ ALLOC( nRshifts, iter, opus_int );
+ abs_pulses_ptr = abs_pulses;
+ for( i = 0; i < iter; i++ ) {
+ nRshifts[ i ] = 0;
+
+ while( 1 ) {
+ /* 1+1 -> 2 */
+ scale_down = combine_and_check( pulses_comb, abs_pulses_ptr, silk_max_pulses_table[ 0 ], 8 );
+ /* 2+2 -> 4 */
+ scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 1 ], 4 );
+ /* 4+4 -> 8 */
+ scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 2 ], 2 );
+ /* 8+8 -> 16 */
+ scale_down += combine_and_check( &sum_pulses[ i ], pulses_comb, silk_max_pulses_table[ 3 ], 1 );
+
+ if( scale_down ) {
+ /* We need to downscale the quantization signal */
+ nRshifts[ i ]++;
+ for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
+ abs_pulses_ptr[ k ] = silk_RSHIFT( abs_pulses_ptr[ k ], 1 );
+ }
+ } else {
+ /* Jump out of while(1) loop and go to next shell coding frame */
+ break;
+ }
+ }
+ abs_pulses_ptr += SHELL_CODEC_FRAME_LENGTH;
+ }
+
+ /**************/
+ /* Rate level */
+ /**************/
+ /* find rate level that leads to fewest bits for coding of pulses per block info */
+ minSumBits_Q5 = silk_int32_MAX;
+ for( k = 0; k < N_RATE_LEVELS - 1; k++ ) {
+ nBits_ptr = silk_pulses_per_block_BITS_Q5[ k ];
+ sumBits_Q5 = silk_rate_levels_BITS_Q5[ signalType >> 1 ][ k ];
+ for( i = 0; i < iter; i++ ) {
+ if( nRshifts[ i ] > 0 ) {
+ sumBits_Q5 += nBits_ptr[ SILK_MAX_PULSES + 1 ];
+ } else {
+ sumBits_Q5 += nBits_ptr[ sum_pulses[ i ] ];
+ }
+ }
+ if( sumBits_Q5 < minSumBits_Q5 ) {
+ minSumBits_Q5 = sumBits_Q5;
+ RateLevelIndex = k;
+ }
+ }
+ ec_enc_icdf( psRangeEnc, RateLevelIndex, silk_rate_levels_iCDF[ signalType >> 1 ], 8 );
+
+ /***************************************************/
+ /* Sum-Weighted-Pulses Encoding */
+ /***************************************************/
+ cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ];
+ for( i = 0; i < iter; i++ ) {
+ if( nRshifts[ i ] == 0 ) {
+ ec_enc_icdf( psRangeEnc, sum_pulses[ i ], cdf_ptr, 8 );
+ } else {
+ ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, cdf_ptr, 8 );
+ for( k = 0; k < nRshifts[ i ] - 1; k++ ) {
+ ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 );
+ }
+ ec_enc_icdf( psRangeEnc, sum_pulses[ i ], silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 );
+ }
+ }
+
+ /******************/
+ /* Shell Encoding */
+ /******************/
+ for( i = 0; i < iter; i++ ) {
+ if( sum_pulses[ i ] > 0 ) {
+ silk_shell_encoder( psRangeEnc, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] );
+ }
+ }
+
+ /****************/
+ /* LSB Encoding */
+ /****************/
+ for( i = 0; i < iter; i++ ) {
+ if( nRshifts[ i ] > 0 ) {
+ pulses_ptr = &pulses[ i * SHELL_CODEC_FRAME_LENGTH ];
+ nLS = nRshifts[ i ] - 1;
+ for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
+ abs_q = (opus_int8)silk_abs( pulses_ptr[ k ] );
+ for( j = nLS; j > 0; j-- ) {
+ bit = silk_RSHIFT( abs_q, j ) & 1;
+ ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 );
+ }
+ bit = abs_q & 1;
+ ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 );
+ }
+ }
+ }
+
+ /****************/
+ /* Encode signs */
+ /****************/
+ silk_encode_signs( psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses );
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/errors.h b/external/opus-1.1.4/silk/errors.h
new file mode 100644
index 0000000..4507080
--- /dev/null
+++ b/external/opus-1.1.4/silk/errors.h
@@ -0,0 +1,98 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_ERRORS_H
+#define SILK_ERRORS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************/
+/* Error messages */
+/******************/
+#define SILK_NO_ERROR 0
+
+/**************************/
+/* Encoder error messages */
+/**************************/
+
+/* Input length is not a multiple of 10 ms, or length is longer than the packet length */
+#define SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES -101
+
+/* Sampling frequency not 8000, 12000 or 16000 Hertz */
+#define SILK_ENC_FS_NOT_SUPPORTED -102
+
+/* Packet size not 10, 20, 40, or 60 ms */
+#define SILK_ENC_PACKET_SIZE_NOT_SUPPORTED -103
+
+/* Allocated payload buffer too short */
+#define SILK_ENC_PAYLOAD_BUF_TOO_SHORT -104
+
+/* Loss rate not between 0 and 100 percent */
+#define SILK_ENC_INVALID_LOSS_RATE -105
+
+/* Complexity setting not valid, use 0...10 */
+#define SILK_ENC_INVALID_COMPLEXITY_SETTING -106
+
+/* Inband FEC setting not valid, use 0 or 1 */
+#define SILK_ENC_INVALID_INBAND_FEC_SETTING -107
+
+/* DTX setting not valid, use 0 or 1 */
+#define SILK_ENC_INVALID_DTX_SETTING -108
+
+/* CBR setting not valid, use 0 or 1 */
+#define SILK_ENC_INVALID_CBR_SETTING -109
+
+/* Internal encoder error */
+#define SILK_ENC_INTERNAL_ERROR -110
+
+/* Internal encoder error */
+#define SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR -111
+
+/**************************/
+/* Decoder error messages */
+/**************************/
+
+/* Output sampling frequency lower than internal decoded sampling frequency */
+#define SILK_DEC_INVALID_SAMPLING_FREQUENCY -200
+
+/* Payload size exceeded the maximum allowed 1024 bytes */
+#define SILK_DEC_PAYLOAD_TOO_LARGE -201
+
+/* Payload has bit errors */
+#define SILK_DEC_PAYLOAD_ERROR -202
+
+/* Payload has bit errors */
+#define SILK_DEC_INVALID_FRAME_SIZE -203
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/silk/fixed/CMakeLists.txt b/external/opus-1.1.4/silk/fixed/CMakeLists.txt
new file mode 100644
index 0000000..a38b9db
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/CMakeLists.txt
@@ -0,0 +1,42 @@
+# CMakeLists.txt in silk/fixed
+
+SET(SILK_FIXED_SRCS
+ apply_sine_window_FIX.c
+ autocorr_FIX.c
+ burg_modified_FIX.c
+ corrMatrix_FIX.c
+ encode_frame_FIX.c
+ find_LPC_FIX.c
+ find_LTP_FIX.c
+ find_pitch_lags_FIX.c
+ find_pred_coefs_FIX.c
+ k2a_FIX.c
+ k2a_Q16_FIX.c
+ LTP_analysis_filter_FIX.c
+ LTP_scale_ctrl_FIX.c
+ noise_shape_analysis_FIX.c
+ pitch_analysis_core_FIX.c
+ prefilter_FIX.c
+ process_gains_FIX.c
+ regularize_correlations_FIX.c
+ residual_energy16_FIX.c
+ residual_energy_FIX.c
+ schur64_FIX.c
+ schur_FIX.c
+ solve_LS_FIX.c
+ vector_ops_FIX.c
+ warped_autocorrelation_FIX.c
+ )
+
+SET(SILK_FIXED_HEADERS
+ main_FIX.h
+ structs_FIX.h
+ )
+
+INCLUDE_DIRECTORIES(
+ ${OPUS_INCLUDES_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../celt
+ )
+
+ADD_LIBRARY( silk_fixed STATIC ${SILK_FIXED_HEADERS} ${SILK_FIXED_SRCS})
diff --git a/external/opus-1.1.4/silk/fixed/LTP_analysis_filter_FIX.c b/external/opus-1.1.4/silk/fixed/LTP_analysis_filter_FIX.c
new file mode 100644
index 0000000..a941908
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/LTP_analysis_filter_FIX.c
@@ -0,0 +1,85 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+void silk_LTP_analysis_filter_FIX(
+ opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */
+ const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */
+ const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */
+ const opus_int subfr_length, /* I Length of each subframe */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */
+)
+{
+ const opus_int16 *x_ptr, *x_lag_ptr;
+ opus_int16 Btmp_Q14[ LTP_ORDER ];
+ opus_int16 *LTP_res_ptr;
+ opus_int k, i, j;
+ opus_int32 LTP_est;
+
+ x_ptr = x;
+ LTP_res_ptr = LTP_res;
+ for( k = 0; k < nb_subfr; k++ ) {
+
+ x_lag_ptr = x_ptr - pitchL[ k ];
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ Btmp_Q14[ i ] = LTPCoef_Q14[ k * LTP_ORDER + i ];
+ }
+
+ /* LTP analysis FIR filter */
+ for( i = 0; i < subfr_length + pre_length; i++ ) {
+ LTP_res_ptr[ i ] = x_ptr[ i ];
+
+ /* Long-term prediction */
+ LTP_est = silk_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] );
+ for( j = 1; j < LTP_ORDER; j++ ) {
+ LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ LTP_ORDER / 2 - j ], Btmp_Q14[ j ] );
+ }
+ LTP_est = silk_RSHIFT_ROUND( LTP_est, 14 ); /* round and -> Q0*/
+
+ /* Subtract long-term prediction */
+ LTP_res_ptr[ i ] = (opus_int16)silk_SAT16( (opus_int32)x_ptr[ i ] - LTP_est );
+
+ /* Scale residual */
+ LTP_res_ptr[ i ] = silk_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] );
+
+ x_lag_ptr++;
+ }
+
+ /* Update pointers */
+ LTP_res_ptr += subfr_length + pre_length;
+ x_ptr += subfr_length;
+ }
+}
+
diff --git a/external/opus-1.1.4/silk/fixed/LTP_scale_ctrl_FIX.c b/external/opus-1.1.4/silk/fixed/LTP_scale_ctrl_FIX.c
new file mode 100644
index 0000000..3dcedef
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/LTP_scale_ctrl_FIX.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int round_loss;
+
+ if( condCoding == CODE_INDEPENDENTLY ) {
+ /* Only scale if first frame in packet */
+ round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket;
+ psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT(
+ silk_SMULWB( silk_SMULBB( round_loss, psEncCtrl->LTPredCodGain_Q7 ), SILK_FIX_CONST( 0.1, 9 ) ), 0, 2 );
+ } else {
+ /* Default is minimum scaling */
+ psEnc->sCmn.indices.LTP_scaleIndex = 0;
+ }
+ psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ];
+}
diff --git a/external/opus-1.1.4/silk/fixed/apply_sine_window_FIX.c b/external/opus-1.1.4/silk/fixed/apply_sine_window_FIX.c
new file mode 100644
index 0000000..4502b71
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/apply_sine_window_FIX.c
@@ -0,0 +1,101 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Apply sine window to signal vector. */
+/* Window types: */
+/* 1 -> sine window from 0 to pi/2 */
+/* 2 -> sine window from pi/2 to pi */
+/* Every other sample is linearly interpolated, for speed. */
+/* Window length must be between 16 and 120 (incl) and a multiple of 4. */
+
+/* Matlab code for table:
+ for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end
+*/
+static const opus_int16 freq_table_Q16[ 27 ] = {
+ 12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202,
+ 3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422,
+ 2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702,
+};
+
+void silk_apply_sine_window(
+ opus_int16 px_win[], /* O Pointer to windowed signal */
+ const opus_int16 px[], /* I Pointer to input signal */
+ const opus_int win_type, /* I Selects a window type */
+ const opus_int length /* I Window length, multiple of 4 */
+)
+{
+ opus_int k, f_Q16, c_Q16;
+ opus_int32 S0_Q16, S1_Q16;
+
+ silk_assert( win_type == 1 || win_type == 2 );
+
+ /* Length must be in a range from 16 to 120 and a multiple of 4 */
+ silk_assert( length >= 16 && length <= 120 );
+ silk_assert( ( length & 3 ) == 0 );
+
+ /* Frequency */
+ k = ( length >> 2 ) - 4;
+ silk_assert( k >= 0 && k <= 26 );
+ f_Q16 = (opus_int)freq_table_Q16[ k ];
+
+ /* Factor used for cosine approximation */
+ c_Q16 = silk_SMULWB( (opus_int32)f_Q16, -f_Q16 );
+ silk_assert( c_Q16 >= -32768 );
+
+ /* initialize state */
+ if( win_type == 1 ) {
+ /* start from 0 */
+ S0_Q16 = 0;
+ /* approximation of sin(f) */
+ S1_Q16 = f_Q16 + silk_RSHIFT( length, 3 );
+ } else {
+ /* start from 1 */
+ S0_Q16 = ( (opus_int32)1 << 16 );
+ /* approximation of cos(f) */
+ S1_Q16 = ( (opus_int32)1 << 16 ) + silk_RSHIFT( c_Q16, 1 ) + silk_RSHIFT( length, 4 );
+ }
+
+ /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */
+ /* 4 samples at a time */
+ for( k = 0; k < length; k += 4 ) {
+ px_win[ k ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] );
+ px_win[ k + 1 ] = (opus_int16)silk_SMULWB( S1_Q16, px[ k + 1] );
+ S0_Q16 = silk_SMULWB( S1_Q16, c_Q16 ) + silk_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1;
+ S0_Q16 = silk_min( S0_Q16, ( (opus_int32)1 << 16 ) );
+
+ px_win[ k + 2 ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] );
+ px_win[ k + 3 ] = (opus_int16)silk_SMULWB( S0_Q16, px[ k + 3 ] );
+ S1_Q16 = silk_SMULWB( S0_Q16, c_Q16 ) + silk_LSHIFT( S0_Q16, 1 ) - S1_Q16;
+ S1_Q16 = silk_min( S1_Q16, ( (opus_int32)1 << 16 ) );
+ }
+}
diff --git a/external/opus-1.1.4/silk/fixed/autocorr_FIX.c b/external/opus-1.1.4/silk/fixed/autocorr_FIX.c
new file mode 100644
index 0000000..de95c98
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/autocorr_FIX.c
@@ -0,0 +1,48 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "celt_lpc.h"
+
+/* Compute autocorrelation */
+void silk_autocorr(
+ opus_int32 *results, /* O Result (length correlationCount) */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *inputData, /* I Input data to correlate */
+ const opus_int inputDataSize, /* I Length of input */
+ const opus_int correlationCount, /* I Number of correlation taps to compute */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int corrCount;
+ corrCount = silk_min_int( inputDataSize, correlationCount );
+ *scale = _celt_autocorr(inputData, results, NULL, 0, corrCount-1, inputDataSize, arch);
+}
diff --git a/external/opus-1.1.4/silk/fixed/burg_modified_FIX.c b/external/opus-1.1.4/silk/fixed/burg_modified_FIX.c
new file mode 100644
index 0000000..db34829
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/burg_modified_FIX.c
@@ -0,0 +1,279 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "define.h"
+#include "tuning_parameters.h"
+#include "pitch.h"
+
+#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
+
+#define QA 25
+#define N_BITS_HEAD_ROOM 2
+#define MIN_RSHIFTS -16
+#define MAX_RSHIFTS (32 - QA)
+
+/* Compute reflection coefficients from input signal */
+void silk_burg_modified(
+ opus_int32 *res_nrg, /* O Residual energy */
+ opus_int *res_nrg_Q, /* O Residual energy Q value */
+ opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
+ const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
+ const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */
+ const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I Number of subframes stacked in x */
+ const opus_int D, /* I Order */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int k, n, s, lz, rshifts, rshifts_extra, reached_max_gain;
+ opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
+ const opus_int16 *x_ptr;
+ opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ];
+ opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ];
+ opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ];
+ opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ];
+ opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ];
+ opus_int32 xcorr[ SILK_MAX_ORDER_LPC ];
+
+ silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
+
+ /* Compute autocorrelations, added over subframes */
+ silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length );
+ if( rshifts > MAX_RSHIFTS ) {
+ C0 = silk_LSHIFT32( C0, rshifts - MAX_RSHIFTS );
+ silk_assert( C0 > 0 );
+ rshifts = MAX_RSHIFTS;
+ } else {
+ lz = silk_CLZ32( C0 ) - 1;
+ rshifts_extra = N_BITS_HEAD_ROOM - lz;
+ if( rshifts_extra > 0 ) {
+ rshifts_extra = silk_min( rshifts_extra, MAX_RSHIFTS - rshifts );
+ C0 = silk_RSHIFT32( C0, rshifts_extra );
+ } else {
+ rshifts_extra = silk_max( rshifts_extra, MIN_RSHIFTS - rshifts );
+ C0 = silk_LSHIFT32( C0, -rshifts_extra );
+ }
+ rshifts += rshifts_extra;
+ }
+ CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
+ silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+ if( rshifts > 0 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ for( n = 1; n < D + 1; n++ ) {
+ C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64(
+ silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n ), rshifts );
+ }
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ int i;
+ opus_int32 d;
+ x_ptr = x + s * subfr_length;
+ celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch );
+ for( n = 1; n < D + 1; n++ ) {
+ for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ )
+ d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] );
+ xcorr[ n - 1 ] += d;
+ }
+ for( n = 1; n < D + 1; n++ ) {
+ C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts );
+ }
+ }
+ }
+ silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+
+ /* Initialize */
+ CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
+
+ invGain_Q30 = (opus_int32)1 << 30;
+ reached_max_gain = 0;
+ for( n = 0; n < D; n++ ) {
+ /* Update first row of correlation matrix (without first element) */
+ /* Update last row of correlation matrix (without last element, stored in reversed order) */
+ /* Update C * Af */
+ /* Update C * flipud(Af) (stored in reversed order) */
+ if( rshifts > -2 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */
+ x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */
+ tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */
+ tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */
+ for( k = 0; k < n; k++ ) {
+ C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
+ C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+ Atmp_QA = Af_QA[ k ];
+ tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */
+ tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */
+ }
+ tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */
+ tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */
+ for( k = 0; k <= n; k++ ) {
+ CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */
+ CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */
+ }
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */
+ x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */
+ tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */
+ tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */
+ for( k = 0; k < n; k++ ) {
+ C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
+ C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+ Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */
+ tmp1 = silk_MLA( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */
+ tmp2 = silk_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */
+ }
+ tmp1 = -tmp1; /* Q17 */
+ tmp2 = -tmp2; /* Q17 */
+ for( k = 0; k <= n; k++ ) {
+ CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1,
+ silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */
+ CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2,
+ silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */
+ }
+ }
+ }
+
+ /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
+ tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */
+ tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */
+ num = 0; /* Q( -rshifts ) */
+ nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */
+ for( k = 0; k < n; k++ ) {
+ Atmp_QA = Af_QA[ k ];
+ lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1;
+ lz = silk_min( 32 - QA, lz );
+ Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */
+
+ tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ),
+ Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */
+ }
+ CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */
+ CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */
+ num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */
+ num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */
+
+ /* Calculate the next order reflection (parcor) coefficient */
+ if( silk_abs( num ) < nrg ) {
+ rc_Q31 = silk_DIV32_varQ( num, nrg, 31 );
+ } else {
+ rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN;
+ }
+
+ /* Update inverse prediction gain */
+ tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+ tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 );
+ if( tmp1 <= minInvGain_Q30 ) {
+ /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
+ tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */
+ rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */
+ /* Newton-Raphson iteration */
+ rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */
+ rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */
+ if( num < 0 ) {
+ /* Ensure adjusted reflection coefficients has the original sign */
+ rc_Q31 = -rc_Q31;
+ }
+ invGain_Q30 = minInvGain_Q30;
+ reached_max_gain = 1;
+ } else {
+ invGain_Q30 = tmp1;
+ }
+
+ /* Update the AR coefficients */
+ for( k = 0; k < (n + 1) >> 1; k++ ) {
+ tmp1 = Af_QA[ k ]; /* QA */
+ tmp2 = Af_QA[ n - k - 1 ]; /* QA */
+ Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */
+ Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */
+ }
+ Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */
+
+ if( reached_max_gain ) {
+ /* Reached max prediction gain; set remaining coefficients to zero and exit loop */
+ for( k = n + 1; k < D; k++ ) {
+ Af_QA[ k ] = 0;
+ }
+ break;
+ }
+
+ /* Update C * Af and C * Ab */
+ for( k = 0; k <= n + 1; k++ ) {
+ tmp1 = CAf[ k ]; /* Q( -rshifts ) */
+ tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */
+ CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */
+ CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */
+ }
+ }
+
+ if( reached_max_gain ) {
+ for( k = 0; k < D; k++ ) {
+ /* Scale coefficients */
+ A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 );
+ }
+ /* Subtract energy of preceding samples from C0 */
+ if( rshifts > 0 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D ), rshifts );
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D ), -rshifts );
+ }
+ }
+ /* Approximate residual energy */
+ *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 );
+ *res_nrg_Q = -rshifts;
+ } else {
+ /* Return residual energy */
+ nrg = CAf[ 0 ]; /* Q( -rshifts ) */
+ tmp1 = (opus_int32)1 << 16; /* Q16 */
+ for( k = 0; k < D; k++ ) {
+ Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */
+ nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */
+ tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */
+ A_Q16[ k ] = -Atmp1;
+ }
+ *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */
+ *res_nrg_Q = -rshifts;
+ }
+}
diff --git a/external/opus-1.1.4/silk/fixed/corrMatrix_FIX.c b/external/opus-1.1.4/silk/fixed/corrMatrix_FIX.c
new file mode 100644
index 0000000..c617270
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/corrMatrix_FIX.c
@@ -0,0 +1,156 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/**********************************************************************
+ * Correlation Matrix Computations for LS estimate.
+ **********************************************************************/
+
+#include "main_FIX.h"
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int16 *t, /* I Target vector [L] */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */
+ const opus_int rshifts /* I Right shifts of correlations */
+)
+{
+ opus_int lag, i;
+ const opus_int16 *ptr1, *ptr2;
+ opus_int32 inner_prod;
+
+ ptr1 = &x[ order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */
+ ptr2 = t;
+ /* Calculate X'*t */
+ if( rshifts > 0 ) {
+ /* Right shifting used */
+ for( lag = 0; lag < order; lag++ ) {
+ inner_prod = 0;
+ for( i = 0; i < L; i++ ) {
+ inner_prod += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts );
+ }
+ Xt[ lag ] = inner_prod; /* X[:,lag]'*t */
+ ptr1--; /* Go to next column of X */
+ }
+ } else {
+ silk_assert( rshifts == 0 );
+ for( lag = 0; lag < order; lag++ ) {
+ Xt[ lag ] = silk_inner_prod_aligned( ptr1, ptr2, L ); /* X[:,lag]'*t */
+ ptr1--; /* Go to next column of X */
+ }
+ }
+}
+
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ const opus_int head_room, /* I Desired headroom */
+ opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */
+ opus_int *rshifts /* I/O Right shifts of correlations */
+)
+{
+ opus_int i, j, lag, rshifts_local, head_room_rshifts;
+ opus_int32 energy;
+ const opus_int16 *ptr1, *ptr2;
+
+ /* Calculate energy to find shift used to fit in 32 bits */
+ silk_sum_sqr_shift( &energy, &rshifts_local, x, L + order - 1 );
+ /* Add shifts to get the desired head room */
+ head_room_rshifts = silk_max( head_room - silk_CLZ32( energy ), 0 );
+
+ energy = silk_RSHIFT32( energy, head_room_rshifts );
+ rshifts_local += head_room_rshifts;
+
+ /* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */
+ /* Remove contribution of first order - 1 samples */
+ for( i = 0; i < order - 1; i++ ) {
+ energy -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), rshifts_local );
+ }
+ if( rshifts_local < *rshifts ) {
+ /* Adjust energy */
+ energy = silk_RSHIFT32( energy, *rshifts - rshifts_local );
+ rshifts_local = *rshifts;
+ }
+
+ /* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */
+ /* Fill out the diagonal of the correlation matrix */
+ matrix_ptr( XX, 0, 0, order ) = energy;
+ ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */
+ for( j = 1; j < order; j++ ) {
+ energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), rshifts_local ) );
+ energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr1[ -j ] ), rshifts_local ) );
+ matrix_ptr( XX, j, j, order ) = energy;
+ }
+
+ ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */
+ /* Calculate the remaining elements of the correlation matrix */
+ if( rshifts_local > 0 ) {
+ /* Right shifting used */
+ for( lag = 1; lag < order; lag++ ) {
+ /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
+ energy = 0;
+ for( i = 0; i < L; i++ ) {
+ energy += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts_local );
+ }
+ /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
+ matrix_ptr( XX, lag, 0, order ) = energy;
+ matrix_ptr( XX, 0, lag, order ) = energy;
+ for( j = 1; j < ( order - lag ); j++ ) {
+ energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), rshifts_local ) );
+ energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr2[ -j ] ), rshifts_local ) );
+ matrix_ptr( XX, lag + j, j, order ) = energy;
+ matrix_ptr( XX, j, lag + j, order ) = energy;
+ }
+ ptr2--; /* Update pointer to first sample of next column (lag) in X */
+ }
+ } else {
+ for( lag = 1; lag < order; lag++ ) {
+ /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
+ energy = silk_inner_prod_aligned( ptr1, ptr2, L );
+ matrix_ptr( XX, lag, 0, order ) = energy;
+ matrix_ptr( XX, 0, lag, order ) = energy;
+ /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
+ for( j = 1; j < ( order - lag ); j++ ) {
+ energy = silk_SUB32( energy, silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) );
+ energy = silk_SMLABB( energy, ptr1[ -j ], ptr2[ -j ] );
+ matrix_ptr( XX, lag + j, j, order ) = energy;
+ matrix_ptr( XX, j, lag + j, order ) = energy;
+ }
+ ptr2--;/* Update pointer to first sample of next column (lag) in X */
+ }
+ }
+ *rshifts = rshifts_local;
+}
+
diff --git a/external/opus-1.1.4/silk/fixed/encode_frame_FIX.c b/external/opus-1.1.4/silk/fixed/encode_frame_FIX.c
new file mode 100644
index 0000000..b490986
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/encode_frame_FIX.c
@@ -0,0 +1,385 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */
+static OPUS_INLINE void silk_LBRR_encode_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */
+ const opus_int32 xfw_Q3[], /* I Input signal */
+ opus_int condCoding /* I The type of conditional coding used so far for this frame */
+);
+
+void silk_encode_do_VAD_FIX(
+ silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */
+)
+{
+ /****************************/
+ /* Voice Activity Detection */
+ /****************************/
+ silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1 );
+
+ /**************************************************/
+ /* Convert speech activity into VAD and DTX flags */
+ /**************************************************/
+ if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) {
+ psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY;
+ psEnc->sCmn.noSpeechCounter++;
+ if( psEnc->sCmn.noSpeechCounter < NB_SPEECH_FRAMES_BEFORE_DTX ) {
+ psEnc->sCmn.inDTX = 0;
+ } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) {
+ psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX;
+ psEnc->sCmn.inDTX = 0;
+ }
+ psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0;
+ } else {
+ psEnc->sCmn.noSpeechCounter = 0;
+ psEnc->sCmn.inDTX = 0;
+ psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+ psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+ }
+}
+
+/****************/
+/* Encode frame */
+/****************/
+opus_int silk_encode_frame_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ opus_int maxBits, /* I If > 0: maximum number of output bits */
+ opus_int useCBR /* I Flag to force constant-bitrate operation */
+)
+{
+ silk_encoder_control_FIX sEncCtrl;
+ opus_int i, iter, maxIter, found_upper, found_lower, ret = 0;
+ opus_int16 *x_frame;
+ ec_enc sRangeEnc_copy, sRangeEnc_copy2;
+ silk_nsq_state sNSQ_copy, sNSQ_copy2;
+ opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
+ opus_int32 gainsID, gainsID_lower, gainsID_upper;
+ opus_int16 gainMult_Q8;
+ opus_int16 ec_prevLagIndex_copy;
+ opus_int ec_prevSignalType_copy;
+ opus_int8 LastGainIndex_copy2;
+ SAVE_STACK;
+
+ /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */
+ LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0;
+
+ psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3;
+
+ /**************************************************************/
+ /* Set up Input Pointers, and insert frame in input buffer */
+ /*************************************************************/
+ /* start of frame to encode */
+ x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length;
+
+ /***************************************/
+ /* Ensure smooth bandwidth transitions */
+ /***************************************/
+ silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
+
+ /*******************************************/
+ /* Copy new frame to front of input buffer */
+ /*******************************************/
+ silk_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof( opus_int16 ) );
+
+ if( !psEnc->sCmn.prefillFlag ) {
+ VARDECL( opus_int32, xfw_Q3 );
+ VARDECL( opus_int16, res_pitch );
+ VARDECL( opus_uint8, ec_buf_copy );
+ opus_int16 *res_pitch_frame;
+
+ ALLOC( res_pitch,
+ psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length
+ + psEnc->sCmn.ltp_mem_length, opus_int16 );
+ /* start of pitch LPC residual frame */
+ res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length;
+
+ /*****************************************/
+ /* Find pitch lags, initial LPC analysis */
+ /*****************************************/
+ silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch );
+
+ /************************/
+ /* Noise shape analysis */
+ /************************/
+ silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, psEnc->sCmn.arch );
+
+ /***************************************************/
+ /* Find linear prediction coefficients (LPC + LTP) */
+ /***************************************************/
+ silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding );
+
+ /****************************************/
+ /* Process gains */
+ /****************************************/
+ silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding );
+
+ /*****************************************/
+ /* Prefiltering for noise shaper */
+ /*****************************************/
+ ALLOC( xfw_Q3, psEnc->sCmn.frame_length, opus_int32 );
+ silk_prefilter_FIX( psEnc, &sEncCtrl, xfw_Q3, x_frame );
+
+ /****************************************/
+ /* Low Bitrate Redundant Encoding */
+ /****************************************/
+ silk_LBRR_encode_FIX( psEnc, &sEncCtrl, xfw_Q3, condCoding );
+
+ /* Loop over quantizer and entropy coding to control bitrate */
+ maxIter = 6;
+ gainMult_Q8 = SILK_FIX_CONST( 1, 8 );
+ found_lower = 0;
+ found_upper = 0;
+ gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+ gainsID_lower = -1;
+ gainsID_upper = -1;
+ /* Copy part of the input state */
+ silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
+ silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ seed_copy = psEnc->sCmn.indices.Seed;
+ ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
+ ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
+ ALLOC( ec_buf_copy, 1275, opus_uint8 );
+ for( iter = 0; ; iter++ ) {
+ if( gainsID == gainsID_lower ) {
+ nBits = nBits_lower;
+ } else if( gainsID == gainsID_upper ) {
+ nBits = nBits_upper;
+ } else {
+ /* Restore part of the input state */
+ if( iter > 0 ) {
+ silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
+ silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) );
+ psEnc->sCmn.indices.Seed = seed_copy;
+ psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
+ psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
+ }
+
+ /*****************************************/
+ /* Noise shaping quantization */
+ /*****************************************/
+ if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+ silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses,
+ sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14,
+ sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 );
+ } else {
+ silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses,
+ sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14,
+ sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 );
+ }
+
+ /****************************************/
+ /* Encode Parameters */
+ /****************************************/
+ silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+
+ /****************************************/
+ /* Encode Excitation Signal */
+ /****************************************/
+ silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
+ psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
+
+ nBits = ec_tell( psRangeEnc );
+
+ if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
+ break;
+ }
+ }
+
+ if( iter == maxIter ) {
+ if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) {
+ /* Restore output state from earlier iteration that did meet the bitrate budget */
+ silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
+ silk_assert( sRangeEnc_copy2.offs <= 1275 );
+ silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
+ silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) );
+ psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
+ }
+ break;
+ }
+
+ if( nBits > maxBits ) {
+ if( found_lower == 0 && iter >= 2 ) {
+ /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */
+ sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 );
+ found_upper = 0;
+ gainsID_upper = -1;
+ } else {
+ found_upper = 1;
+ nBits_upper = nBits;
+ gainMult_upper = gainMult_Q8;
+ gainsID_upper = gainsID;
+ }
+ } else if( nBits < maxBits - 5 ) {
+ found_lower = 1;
+ nBits_lower = nBits;
+ gainMult_lower = gainMult_Q8;
+ if( gainsID != gainsID_lower ) {
+ gainsID_lower = gainsID;
+ /* Copy part of the output state */
+ silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+ silk_assert( psRangeEnc->offs <= 1275 );
+ silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
+ silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
+ }
+ } else {
+ /* Within 5 bits of budget: close enough */
+ break;
+ }
+
+ if( ( found_lower & found_upper ) == 0 ) {
+ /* Adjust gain according to high-rate rate/distortion curve */
+ opus_int32 gain_factor_Q16;
+ gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );
+ gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) );
+ if( nBits > maxBits ) {
+ gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) );
+ }
+ gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 );
+ } else {
+ /* Adjust gain by interpolating */
+ gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower );
+ /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
+ if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) {
+ gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 );
+ } else
+ if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) {
+ gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 );
+ }
+ }
+
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 );
+ }
+
+ /* Quantize gains */
+ psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
+ silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16,
+ &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Unique identifier of gains vector */
+ gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+ }
+ }
+
+ /* Update input buffer */
+ silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ],
+ ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) );
+
+ /* Exit without entropy coding */
+ if( psEnc->sCmn.prefillFlag ) {
+ /* No payload */
+ *pnBytesOut = 0;
+ RESTORE_STACK;
+ return ret;
+ }
+
+ /* Parameters needed for next frame */
+ psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+ psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType;
+
+ /****************************************/
+ /* Finalize payload */
+ /****************************************/
+ psEnc->sCmn.first_frame_after_reset = 0;
+ /* Payload size */
+ *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 );
+
+ RESTORE_STACK;
+ return ret;
+}
+
+/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */
+static OPUS_INLINE void silk_LBRR_encode_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */
+ const opus_int32 xfw_Q3[], /* I Input signal */
+ opus_int condCoding /* I The type of conditional coding used so far for this frame */
+)
+{
+ opus_int32 TempGains_Q16[ MAX_NB_SUBFR ];
+ SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ];
+ silk_nsq_state sNSQ_LBRR;
+
+ /*******************************************/
+ /* Control use of inband LBRR */
+ /*******************************************/
+ if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) {
+ psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+
+ /* Copy noise shaping quantizer state and quantization indices from regular encoding */
+ silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) );
+
+ /* Save original gains */
+ silk_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+
+ if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) {
+ /* First frame in packet or previous frame not LBRR coded */
+ psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex;
+
+ /* Increase Gains to get target LBRR rate */
+ psIndices_LBRR->GainsIndices[ 0 ] = psIndices_LBRR->GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases;
+ psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 );
+ }
+
+ /* Decode to get gains in sync with decoder */
+ /* Overwrite unquantized gains with quantized gains */
+ silk_gains_dequant( psEncCtrl->Gains_Q16, psIndices_LBRR->GainsIndices,
+ &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /*****************************************/
+ /* Noise shaping quantization */
+ /*****************************************/
+ if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+ silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3,
+ psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14,
+ psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14,
+ psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 );
+ } else {
+ silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3,
+ psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14,
+ psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14,
+ psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 );
+ }
+
+ /* Restore original gains */
+ silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+ }
+}
diff --git a/external/opus-1.1.4/silk/fixed/find_LPC_FIX.c b/external/opus-1.1.4/silk/fixed/find_LPC_FIX.c
new file mode 100644
index 0000000..783d32e
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/find_LPC_FIX.c
@@ -0,0 +1,151 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Finds LPC vector from correlations, and converts to NLSF */
+void silk_find_LPC_FIX(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 NLSF_Q15[], /* O NLSFs */
+ const opus_int16 x[], /* I Input signal */
+ const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */
+)
+{
+ opus_int k, subfr_length;
+ opus_int32 a_Q16[ MAX_LPC_ORDER ];
+ opus_int isInterpLower, shift;
+ opus_int32 res_nrg0, res_nrg1;
+ opus_int rshift0, rshift1;
+
+ /* Used only for LSF interpolation */
+ opus_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg;
+ opus_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q;
+ opus_int16 a_tmp_Q12[ MAX_LPC_ORDER ];
+ opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ];
+ SAVE_STACK;
+
+ subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder;
+
+ /* Default: no interpolation */
+ psEncC->indices.NLSFInterpCoef_Q2 = 4;
+
+ /* Burg AR analysis for the full frame */
+ silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder, psEncC->arch );
+
+ if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) {
+ VARDECL( opus_int16, LPC_res );
+
+ /* Optimal solution for last 10 ms */
+ silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder, psEncC->arch );
+
+ /* subtract residual energy here, as that's easier than adding it to the */
+ /* residual energy of the first 10 ms in each iteration of the search below */
+ shift = res_tmp_nrg_Q - res_nrg_Q;
+ if( shift >= 0 ) {
+ if( shift < 32 ) {
+ res_nrg = res_nrg - silk_RSHIFT( res_tmp_nrg, shift );
+ }
+ } else {
+ silk_assert( shift > -32 );
+ res_nrg = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg;
+ res_nrg_Q = res_tmp_nrg_Q;
+ }
+
+ /* Convert to NLSFs */
+ silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder );
+
+ ALLOC( LPC_res, 2 * subfr_length, opus_int16 );
+
+ /* Search over interpolation indices to find the one with lowest residual energy */
+ for( k = 3; k >= 0; k-- ) {
+ /* Interpolate NLSFs for first half */
+ silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder );
+
+ /* Convert to LPC for residual energy evaluation */
+ silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder );
+
+ /* Calculate residual energy with NLSF interpolation */
+ silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder );
+
+ silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder );
+ silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder );
+
+ /* Add subframe energies from first half frame */
+ shift = rshift0 - rshift1;
+ if( shift >= 0 ) {
+ res_nrg1 = silk_RSHIFT( res_nrg1, shift );
+ res_nrg_interp_Q = -rshift0;
+ } else {
+ res_nrg0 = silk_RSHIFT( res_nrg0, -shift );
+ res_nrg_interp_Q = -rshift1;
+ }
+ res_nrg_interp = silk_ADD32( res_nrg0, res_nrg1 );
+
+ /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */
+ shift = res_nrg_interp_Q - res_nrg_Q;
+ if( shift >= 0 ) {
+ if( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) {
+ isInterpLower = silk_TRUE;
+ } else {
+ isInterpLower = silk_FALSE;
+ }
+ } else {
+ if( -shift < 32 ) {
+ if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) {
+ isInterpLower = silk_TRUE;
+ } else {
+ isInterpLower = silk_FALSE;
+ }
+ } else {
+ isInterpLower = silk_FALSE;
+ }
+ }
+
+ /* Determine whether current interpolated NLSFs are best so far */
+ if( isInterpLower == silk_TRUE ) {
+ /* Interpolation has lower residual energy */
+ res_nrg = res_nrg_interp;
+ res_nrg_Q = res_nrg_interp_Q;
+ psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k;
+ }
+ }
+ }
+
+ if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) {
+ /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
+ silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder );
+ }
+
+ silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) );
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/fixed/find_LTP_FIX.c b/external/opus-1.1.4/silk/fixed/find_LTP_FIX.c
new file mode 100644
index 0000000..8c4d703
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/find_LTP_FIX.c
@@ -0,0 +1,244 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "tuning_parameters.h"
+
+/* Head room for correlations */
+#define LTP_CORRS_HEAD_ROOM 2
+
+void silk_fit_LTP(
+ opus_int32 LTP_coefs_Q16[ LTP_ORDER ],
+ opus_int16 LTP_coefs_Q14[ LTP_ORDER ]
+);
+
+void silk_find_LTP_FIX(
+ opus_int16 b_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */
+ opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */
+ opus_int *LTPredCodGain_Q7, /* O LTP coding gain */
+ const opus_int16 r_lpc[], /* I residual signal after LPC signal + state for first 10 ms */
+ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
+ const opus_int32 Wght_Q15[ MAX_NB_SUBFR ], /* I weights */
+ const opus_int subfr_length, /* I subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int mem_offset, /* I number of samples in LTP memory */
+ opus_int corr_rshifts[ MAX_NB_SUBFR ] /* O right shifts applied to correlations */
+)
+{
+ opus_int i, k, lshift;
+ const opus_int16 *r_ptr, *lag_ptr;
+ opus_int16 *b_Q14_ptr;
+
+ opus_int32 regu;
+ opus_int32 *WLTP_ptr;
+ opus_int32 b_Q16[ LTP_ORDER ], delta_b_Q14[ LTP_ORDER ], d_Q14[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], g_Q26;
+ opus_int32 w[ MAX_NB_SUBFR ], WLTP_max, max_abs_d_Q14, max_w_bits;
+
+ opus_int32 temp32, denom32;
+ opus_int extra_shifts;
+ opus_int rr_shifts, maxRshifts, maxRshifts_wxtra, LZs;
+ opus_int32 LPC_res_nrg, LPC_LTP_res_nrg, div_Q16;
+ opus_int32 Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ];
+ opus_int32 wd, m_Q12;
+
+ b_Q14_ptr = b_Q14;
+ WLTP_ptr = WLTP;
+ r_ptr = &r_lpc[ mem_offset ];
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 );
+
+ silk_sum_sqr_shift( &rr[ k ], &rr_shifts, r_ptr, subfr_length ); /* rr[ k ] in Q( -rr_shifts ) */
+
+ /* Assure headroom */
+ LZs = silk_CLZ32( rr[k] );
+ if( LZs < LTP_CORRS_HEAD_ROOM ) {
+ rr[ k ] = silk_RSHIFT_ROUND( rr[ k ], LTP_CORRS_HEAD_ROOM - LZs );
+ rr_shifts += ( LTP_CORRS_HEAD_ROOM - LZs );
+ }
+ corr_rshifts[ k ] = rr_shifts;
+ silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, LTP_CORRS_HEAD_ROOM, WLTP_ptr, &corr_rshifts[ k ] ); /* WLTP_fix_ptr in Q( -corr_rshifts[ k ] ) */
+
+ /* The correlation vector always has lower max abs value than rr and/or RR so head room is assured */
+ silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr, corr_rshifts[ k ] ); /* Rr_fix_ptr in Q( -corr_rshifts[ k ] ) */
+ if( corr_rshifts[ k ] > rr_shifts ) {
+ rr[ k ] = silk_RSHIFT( rr[ k ], corr_rshifts[ k ] - rr_shifts ); /* rr[ k ] in Q( -corr_rshifts[ k ] ) */
+ }
+ silk_assert( rr[ k ] >= 0 );
+
+ regu = 1;
+ regu = silk_SMLAWB( regu, rr[ k ], SILK_FIX_CONST( LTP_DAMPING/3, 16 ) );
+ regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) );
+ regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) );
+ silk_regularize_correlations_FIX( WLTP_ptr, &rr[k], regu, LTP_ORDER );
+
+ silk_solve_LDL_FIX( WLTP_ptr, LTP_ORDER, Rr, b_Q16 ); /* WLTP_fix_ptr and Rr_fix_ptr both in Q(-corr_rshifts[k]) */
+
+ /* Limit and store in Q14 */
+ silk_fit_LTP( b_Q16, b_Q14_ptr );
+
+ /* Calculate residual energy */
+ nrg[ k ] = silk_residual_energy16_covar_FIX( b_Q14_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER, 14 ); /* nrg_fix in Q( -corr_rshifts[ k ] ) */
+
+ /* temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); */
+ extra_shifts = silk_min_int( corr_rshifts[ k ], LTP_CORRS_HEAD_ROOM );
+ denom32 = silk_LSHIFT_SAT32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 + extra_shifts ) + /* Q( -corr_rshifts[ k ] + extra_shifts ) */
+ silk_RSHIFT( silk_SMULWB( (opus_int32)subfr_length, 655 ), corr_rshifts[ k ] - extra_shifts ); /* Q( -corr_rshifts[ k ] + extra_shifts ) */
+ denom32 = silk_max( denom32, 1 );
+ silk_assert( ((opus_int64)Wght_Q15[ k ] << 16 ) < silk_int32_MAX ); /* Wght always < 0.5 in Q0 */
+ temp32 = silk_DIV32( silk_LSHIFT( (opus_int32)Wght_Q15[ k ], 16 ), denom32 ); /* Q( 15 + 16 + corr_rshifts[k] - extra_shifts ) */
+ temp32 = silk_RSHIFT( temp32, 31 + corr_rshifts[ k ] - extra_shifts - 26 ); /* Q26 */
+
+ /* Limit temp such that the below scaling never wraps around */
+ WLTP_max = 0;
+ for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) {
+ WLTP_max = silk_max( WLTP_ptr[ i ], WLTP_max );
+ }
+ lshift = silk_CLZ32( WLTP_max ) - 1 - 3; /* keep 3 bits free for vq_nearest_neighbor_fix */
+ silk_assert( 26 - 18 + lshift >= 0 );
+ if( 26 - 18 + lshift < 31 ) {
+ temp32 = silk_min_32( temp32, silk_LSHIFT( (opus_int32)1, 26 - 18 + lshift ) );
+ }
+
+ silk_scale_vector32_Q26_lshift_18( WLTP_ptr, temp32, LTP_ORDER * LTP_ORDER ); /* WLTP_ptr in Q( 18 - corr_rshifts[ k ] ) */
+
+ w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER/2, LTP_ORDER/2, LTP_ORDER ); /* w in Q( 18 - corr_rshifts[ k ] ) */
+ silk_assert( w[k] >= 0 );
+
+ r_ptr += subfr_length;
+ b_Q14_ptr += LTP_ORDER;
+ WLTP_ptr += LTP_ORDER * LTP_ORDER;
+ }
+
+ maxRshifts = 0;
+ for( k = 0; k < nb_subfr; k++ ) {
+ maxRshifts = silk_max_int( corr_rshifts[ k ], maxRshifts );
+ }
+
+ /* Compute LTP coding gain */
+ if( LTPredCodGain_Q7 != NULL ) {
+ LPC_LTP_res_nrg = 0;
+ LPC_res_nrg = 0;
+ silk_assert( LTP_CORRS_HEAD_ROOM >= 2 ); /* Check that no overflow will happen when adding */
+ for( k = 0; k < nb_subfr; k++ ) {
+ LPC_res_nrg = silk_ADD32( LPC_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( rr[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */
+ LPC_LTP_res_nrg = silk_ADD32( LPC_LTP_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */
+ }
+ LPC_LTP_res_nrg = silk_max( LPC_LTP_res_nrg, 1 ); /* avoid division by zero */
+
+ div_Q16 = silk_DIV32_varQ( LPC_res_nrg, LPC_LTP_res_nrg, 16 );
+ *LTPredCodGain_Q7 = ( opus_int )silk_SMULBB( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) );
+
+ silk_assert( *LTPredCodGain_Q7 == ( opus_int )silk_SAT16( silk_MUL( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) ) ) );
+ }
+
+ /* smoothing */
+ /* d = sum( B, 1 ); */
+ b_Q14_ptr = b_Q14;
+ for( k = 0; k < nb_subfr; k++ ) {
+ d_Q14[ k ] = 0;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ d_Q14[ k ] += b_Q14_ptr[ i ];
+ }
+ b_Q14_ptr += LTP_ORDER;
+ }
+
+ /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */
+
+ /* Find maximum absolute value of d_Q14 and the bits used by w in Q0 */
+ max_abs_d_Q14 = 0;
+ max_w_bits = 0;
+ for( k = 0; k < nb_subfr; k++ ) {
+ max_abs_d_Q14 = silk_max_32( max_abs_d_Q14, silk_abs( d_Q14[ k ] ) );
+ /* w[ k ] is in Q( 18 - corr_rshifts[ k ] ) */
+ /* Find bits needed in Q( 18 - maxRshifts ) */
+ max_w_bits = silk_max_32( max_w_bits, 32 - silk_CLZ32( w[ k ] ) + corr_rshifts[ k ] - maxRshifts );
+ }
+
+ /* max_abs_d_Q14 = (5 << 15); worst case, i.e. LTP_ORDER * -silk_int16_MIN */
+ silk_assert( max_abs_d_Q14 <= ( 5 << 15 ) );
+
+ /* How many bits is needed for w*d' in Q( 18 - maxRshifts ) in the worst case, of all d_Q14's being equal to max_abs_d_Q14 */
+ extra_shifts = max_w_bits + 32 - silk_CLZ32( max_abs_d_Q14 ) - 14;
+
+ /* Subtract what we got available; bits in output var plus maxRshifts */
+ extra_shifts -= ( 32 - 1 - 2 + maxRshifts ); /* Keep sign bit free as well as 2 bits for accumulation */
+ extra_shifts = silk_max_int( extra_shifts, 0 );
+
+ maxRshifts_wxtra = maxRshifts + extra_shifts;
+
+ temp32 = silk_RSHIFT( 262, maxRshifts + extra_shifts ) + 1; /* 1e-3f in Q( 18 - (maxRshifts + extra_shifts) ) */
+ wd = 0;
+ for( k = 0; k < nb_subfr; k++ ) {
+ /* w has at least 2 bits of headroom so no overflow should happen */
+ temp32 = silk_ADD32( temp32, silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ) ); /* Q( 18 - maxRshifts_wxtra ) */
+ wd = silk_ADD32( wd, silk_LSHIFT( silk_SMULWW( silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ), d_Q14[ k ] ), 2 ) ); /* Q( 18 - maxRshifts_wxtra ) */
+ }
+ m_Q12 = silk_DIV32_varQ( wd, temp32, 12 );
+
+ b_Q14_ptr = b_Q14;
+ for( k = 0; k < nb_subfr; k++ ) {
+ /* w_fix[ k ] from Q( 18 - corr_rshifts[ k ] ) to Q( 16 ) */
+ if( 2 - corr_rshifts[k] > 0 ) {
+ temp32 = silk_RSHIFT( w[ k ], 2 - corr_rshifts[ k ] );
+ } else {
+ temp32 = silk_LSHIFT_SAT32( w[ k ], corr_rshifts[ k ] - 2 );
+ }
+
+ g_Q26 = silk_MUL(
+ silk_DIV32(
+ SILK_FIX_CONST( LTP_SMOOTHING, 26 ),
+ silk_RSHIFT( SILK_FIX_CONST( LTP_SMOOTHING, 26 ), 10 ) + temp32 ), /* Q10 */
+ silk_LSHIFT_SAT32( silk_SUB_SAT32( (opus_int32)m_Q12, silk_RSHIFT( d_Q14[ k ], 2 ) ), 4 ) ); /* Q16 */
+
+ temp32 = 0;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ delta_b_Q14[ i ] = silk_max_16( b_Q14_ptr[ i ], 1638 ); /* 1638_Q14 = 0.1_Q0 */
+ temp32 += delta_b_Q14[ i ]; /* Q14 */
+ }
+ temp32 = silk_DIV32( g_Q26, temp32 ); /* Q14 -> Q12 */
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ b_Q14_ptr[ i ] = silk_LIMIT_32( (opus_int32)b_Q14_ptr[ i ] + silk_SMULWB( silk_LSHIFT_SAT32( temp32, 4 ), delta_b_Q14[ i ] ), -16000, 28000 );
+ }
+ b_Q14_ptr += LTP_ORDER;
+ }
+}
+
+void silk_fit_LTP(
+ opus_int32 LTP_coefs_Q16[ LTP_ORDER ],
+ opus_int16 LTP_coefs_Q14[ LTP_ORDER ]
+)
+{
+ opus_int i;
+
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ LTP_coefs_Q14[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( LTP_coefs_Q16[ i ], 2 ) );
+ }
+}
diff --git a/external/opus-1.1.4/silk/fixed/find_pitch_lags_FIX.c b/external/opus-1.1.4/silk/fixed/find_pitch_lags_FIX.c
new file mode 100644
index 0000000..620f8dc
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/find_pitch_lags_FIX.c
@@ -0,0 +1,145 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Find pitch lags */
+void silk_find_pitch_lags_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int16 res[], /* O residual */
+ const opus_int16 x[], /* I Speech signal */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int buf_len, i, scale;
+ opus_int32 thrhld_Q13, res_nrg;
+ const opus_int16 *x_buf, *x_buf_ptr;
+ VARDECL( opus_int16, Wsig );
+ opus_int16 *Wsig_ptr;
+ opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ];
+ opus_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ];
+ opus_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ];
+ opus_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ];
+ SAVE_STACK;
+
+ /******************************************/
+ /* Set up buffer lengths etc based on Fs */
+ /******************************************/
+ buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length;
+
+ /* Safety check */
+ silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length );
+
+ x_buf = x - psEnc->sCmn.ltp_mem_length;
+
+ /*************************************/
+ /* Estimate LPC AR coefficients */
+ /*************************************/
+
+ /* Calculate windowed signal */
+
+ ALLOC( Wsig, psEnc->sCmn.pitch_LPC_win_length, opus_int16 );
+
+ /* First LA_LTP samples */
+ x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length;
+ Wsig_ptr = Wsig;
+ silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch );
+
+ /* Middle un - windowed samples */
+ Wsig_ptr += psEnc->sCmn.la_pitch;
+ x_buf_ptr += psEnc->sCmn.la_pitch;
+ silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( opus_int16 ) );
+
+ /* Last LA_LTP samples */
+ Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 );
+ x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 );
+ silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch );
+
+ /* Calculate autocorrelation sequence */
+ silk_autocorr( auto_corr, &scale, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1, arch );
+
+ /* Add white noise, as fraction of energy */
+ auto_corr[ 0 ] = silk_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ) + 1;
+
+ /* Calculate the reflection coefficients using schur */
+ res_nrg = silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ /* Prediction gain */
+ psEncCtrl->predGain_Q16 = silk_DIV32_varQ( auto_corr[ 0 ], silk_max_int( res_nrg, 1 ), 16 );
+
+ /* Convert reflection coefficients to prediction coefficients */
+ silk_k2a( A_Q24, rc_Q15, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ /* Convert From 32 bit Q24 to 16 bit Q12 coefs */
+ for( i = 0; i < psEnc->sCmn.pitchEstimationLPCOrder; i++ ) {
+ A_Q12[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( A_Q24[ i ], 12 ) );
+ }
+
+ /* Do BWE */
+ silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SILK_FIX_CONST( FIND_PITCH_BANDWIDTH_EXPANSION, 16 ) );
+
+ /*****************************************/
+ /* LPC analysis filtering */
+ /*****************************************/
+ silk_LPC_analysis_filter( res, x_buf, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) {
+ /* Threshold for pitch estimator */
+ thrhld_Q13 = SILK_FIX_CONST( 0.6, 13 );
+ thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.004, 13 ), psEnc->sCmn.pitchEstimationLPCOrder );
+ thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 21 ), psEnc->sCmn.speech_activity_Q8 );
+ thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.15, 13 ), silk_RSHIFT( psEnc->sCmn.prevSignalType, 1 ) );
+ thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 14 ), psEnc->sCmn.input_tilt_Q15 );
+ thrhld_Q13 = silk_SAT16( thrhld_Q13 );
+
+ /*****************************************/
+ /* Call pitch estimator */
+ /*****************************************/
+ if( silk_pitch_analysis_core( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex,
+ &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16,
+ (opus_int)thrhld_Q13, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr,
+ psEnc->sCmn.arch) == 0 )
+ {
+ psEnc->sCmn.indices.signalType = TYPE_VOICED;
+ } else {
+ psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+ }
+ } else {
+ silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) );
+ psEnc->sCmn.indices.lagIndex = 0;
+ psEnc->sCmn.indices.contourIndex = 0;
+ psEnc->LTPCorr_Q15 = 0;
+ }
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/fixed/find_pred_coefs_FIX.c b/external/opus-1.1.4/silk/fixed/find_pred_coefs_FIX.c
new file mode 100644
index 0000000..5c22f82
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/find_pred_coefs_FIX.c
@@ -0,0 +1,147 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+
+void silk_find_pred_coefs_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ const opus_int16 res_pitch[], /* I Residual from pitch analysis */
+ const opus_int16 x[], /* I Speech signal */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i;
+ opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ], Wght_Q15[ MAX_NB_SUBFR ];
+ opus_int16 NLSF_Q15[ MAX_LPC_ORDER ];
+ const opus_int16 *x_ptr;
+ opus_int16 *x_pre_ptr;
+ VARDECL( opus_int16, LPC_in_pre );
+ opus_int32 tmp, min_gain_Q16, minInvGain_Q30;
+ opus_int LTP_corrs_rshift[ MAX_NB_SUBFR ];
+ SAVE_STACK;
+
+ /* weighting for weighted least squares */
+ min_gain_Q16 = silk_int32_MAX >> 6;
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] );
+ }
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ /* Divide to Q16 */
+ silk_assert( psEncCtrl->Gains_Q16[ i ] > 0 );
+ /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */
+ invGains_Q16[ i ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 );
+
+ /* Ensure Wght_Q15 a minimum value 1 */
+ invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 363 );
+
+ /* Square the inverted gains */
+ silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) );
+ tmp = silk_SMULWB( invGains_Q16[ i ], invGains_Q16[ i ] );
+ Wght_Q15[ i ] = silk_RSHIFT( tmp, 1 );
+
+ /* Invert the inverted and normalized gains */
+ local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] );
+ }
+
+ ALLOC( LPC_in_pre,
+ psEnc->sCmn.nb_subfr * psEnc->sCmn.predictLPCOrder
+ + psEnc->sCmn.frame_length, opus_int16 );
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ VARDECL( opus_int32, WLTP );
+
+ /**********/
+ /* VOICED */
+ /**********/
+ silk_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 );
+
+ ALLOC( WLTP, psEnc->sCmn.nb_subfr * LTP_ORDER * LTP_ORDER, opus_int32 );
+
+ /* LTP analysis */
+ silk_find_LTP_FIX( psEncCtrl->LTPCoef_Q14, WLTP, &psEncCtrl->LTPredCodGain_Q7,
+ res_pitch, psEncCtrl->pitchL, Wght_Q15, psEnc->sCmn.subfr_length,
+ psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length, LTP_corrs_rshift );
+
+ /* Quantize LTP gain parameters */
+ silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex,
+ &psEnc->sCmn.sum_log_gain_Q7, WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr);
+
+ /* Control LTP scaling */
+ silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding );
+
+ /* Create LTP residual */
+ silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14,
+ psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+
+ } else {
+ /************/
+ /* UNVOICED */
+ /************/
+ /* Create signal with prepended subframes, scaled by inverse gains */
+ x_ptr = x - psEnc->sCmn.predictLPCOrder;
+ x_pre_ptr = LPC_in_pre;
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ silk_scale_copy_vector16( x_pre_ptr, x_ptr, invGains_Q16[ i ],
+ psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder );
+ x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder;
+ x_ptr += psEnc->sCmn.subfr_length;
+ }
+
+ silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) );
+ psEncCtrl->LTPredCodGain_Q7 = 0;
+ psEnc->sCmn.sum_log_gain_Q7 = 0;
+ }
+
+ /* Limit on total predictive coding gain */
+ if( psEnc->sCmn.first_frame_after_reset ) {
+ minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 );
+ } else {
+ minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, (opus_int32)psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) ); /* Q16 */
+ minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30,
+ silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ),
+ silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 );
+ }
+
+ /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */
+ silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 );
+
+ /* Quantize LSFs */
+ silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 );
+
+ /* Calculate residual energy using quantized LPC coefficients */
+ silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains,
+ psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+
+ /* Copy to prediction struct for use in next frame for interpolation */
+ silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/fixed/k2a_FIX.c b/external/opus-1.1.4/silk/fixed/k2a_FIX.c
new file mode 100644
index 0000000..5fee599
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/k2a_FIX.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a(
+ opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
+ const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */
+ const opus_int32 order /* I Prediction order */
+)
+{
+ opus_int k, n;
+ opus_int32 Atmp[ SILK_MAX_ORDER_LPC ];
+
+ for( k = 0; k < order; k++ ) {
+ for( n = 0; n < k; n++ ) {
+ Atmp[ n ] = A_Q24[ n ];
+ }
+ for( n = 0; n < k; n++ ) {
+ A_Q24[ n ] = silk_SMLAWB( A_Q24[ n ], silk_LSHIFT( Atmp[ k - n - 1 ], 1 ), rc_Q15[ k ] );
+ }
+ A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 );
+ }
+}
diff --git a/external/opus-1.1.4/silk/fixed/k2a_Q16_FIX.c b/external/opus-1.1.4/silk/fixed/k2a_Q16_FIX.c
new file mode 100644
index 0000000..3b03987
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/k2a_Q16_FIX.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a_Q16(
+ opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
+ const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */
+ const opus_int32 order /* I Prediction order */
+)
+{
+ opus_int k, n;
+ opus_int32 Atmp[ SILK_MAX_ORDER_LPC ];
+
+ for( k = 0; k < order; k++ ) {
+ for( n = 0; n < k; n++ ) {
+ Atmp[ n ] = A_Q24[ n ];
+ }
+ for( n = 0; n < k; n++ ) {
+ A_Q24[ n ] = silk_SMLAWW( A_Q24[ n ], Atmp[ k - n - 1 ], rc_Q16[ k ] );
+ }
+ A_Q24[ k ] = -silk_LSHIFT( rc_Q16[ k ], 8 );
+ }
+}
diff --git a/external/opus-1.1.4/silk/fixed/main_FIX.h b/external/opus-1.1.4/silk/fixed/main_FIX.h
new file mode 100644
index 0000000..a56ca07
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/main_FIX.h
@@ -0,0 +1,257 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_MAIN_FIX_H
+#define SILK_MAIN_FIX_H
+
+#include "SigProc_FIX.h"
+#include "structs_FIX.h"
+#include "control.h"
+#include "main.h"
+#include "PLC.h"
+#include "debug.h"
+#include "entenc.h"
+
+#ifndef FORCE_CPP_BUILD
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#endif
+
+#define silk_encoder_state_Fxx silk_encoder_state_FIX
+#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FIX
+#define silk_encode_frame_Fxx silk_encode_frame_FIX
+
+/*********************/
+/* Encoder Functions */
+/*********************/
+
+/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
+void silk_HP_variable_cutoff(
+ silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */
+);
+
+/* Encoder main function */
+void silk_encode_do_VAD_FIX(
+ silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */
+);
+
+/* Encoder main function */
+opus_int silk_encode_frame_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ opus_int maxBits, /* I If > 0: maximum number of output bits */
+ opus_int useCBR /* I Flag to force constant-bitrate operation */
+);
+
+/* Initializes the Silk encoder state */
+opus_int silk_init_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ int arch /* I Run-time architecture */
+);
+
+/* Control the Silk encoder */
+opus_int silk_control_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
+ silk_EncControlStruct *encControl, /* I Control structure */
+ const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */
+ const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
+ const opus_int channelNb, /* I Channel number */
+ const opus_int force_fs_kHz
+);
+
+/****************/
+/* Prefiltering */
+/****************/
+void silk_prefilter_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
+ const silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */
+ opus_int32 xw_Q10[], /* O Weighted signal */
+ const opus_int16 x[] /* I Speech signal */
+);
+
+/**************************/
+/* Noise shaping analysis */
+/**************************/
+/* Compute noise shaping coefficients and initial gain values */
+void silk_noise_shape_analysis_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */
+ const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */
+ const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */
+ int arch /* I Run-time architecture */
+);
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FIX(
+ opus_int32 *corr, /* O Result [order + 1] */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *input, /* I Input data to correlate */
+ const opus_int warping_Q16, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+);
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/**********************************************/
+/* Prediction Analysis */
+/**********************************************/
+/* Find pitch lags */
+void silk_find_pitch_lags_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int16 res[], /* O residual */
+ const opus_int16 x[], /* I Speech signal */
+ int arch /* I Run-time architecture */
+);
+
+/* Find LPC and LTP coefficients */
+void silk_find_pred_coefs_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ const opus_int16 res_pitch[], /* I Residual from pitch analysis */
+ const opus_int16 x[], /* I Speech signal */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/* LPC analysis */
+void silk_find_LPC_FIX(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 NLSF_Q15[], /* O NLSFs */
+ const opus_int16 x[], /* I Input signal */
+ const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */
+);
+
+/* LTP analysis */
+void silk_find_LTP_FIX(
+ opus_int16 b_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */
+ opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */
+ opus_int *LTPredCodGain_Q7, /* O LTP coding gain */
+ const opus_int16 r_lpc[], /* I residual signal after LPC signal + state for first 10 ms */
+ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
+ const opus_int32 Wght_Q15[ MAX_NB_SUBFR ], /* I weights */
+ const opus_int subfr_length, /* I subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int mem_offset, /* I number of samples in LTP memory */
+ opus_int corr_rshifts[ MAX_NB_SUBFR ] /* O right shifts applied to correlations */
+);
+
+void silk_LTP_analysis_filter_FIX(
+ opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */
+ const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */
+ const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */
+ const opus_int subfr_length, /* I Length of each subframe */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */
+);
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order */
+/* of preceding samples */
+void silk_residual_energy_FIX(
+ opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
+ opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */
+ const opus_int16 x[], /* I Input signal */
+ opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
+ const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int LPC_order /* I LPC order */
+);
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+opus_int32 silk_residual_energy16_covar_FIX(
+ const opus_int16 *c, /* I Prediction vector */
+ const opus_int32 *wXX, /* I Correlation matrix */
+ const opus_int32 *wXx, /* I Correlation vector */
+ opus_int32 wxx, /* I Signal energy */
+ opus_int D, /* I Dimension */
+ opus_int cQ /* I Q value for c vector 0 - 15 */
+);
+
+/* Processing of gains */
+void silk_process_gains_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/******************/
+/* Linear Algebra */
+/******************/
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ const opus_int head_room, /* I Desired headroom */
+ opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */
+ opus_int *rshifts /* I/O Right shifts of correlations */
+);
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int16 *t, /* I Target vector [L] */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */
+ const opus_int rshifts /* I Right shifts of correlations */
+);
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FIX(
+ opus_int32 *XX, /* I/O Correlation matrices */
+ opus_int32 *xx, /* I/O Correlation values */
+ opus_int32 noise, /* I Noise to add */
+ opus_int D /* I Dimension of XX */
+);
+
+/* Solves Ax = b, assuming A is symmetric */
+void silk_solve_LDL_FIX(
+ opus_int32 *A, /* I Pointer to symetric square matrix A */
+ opus_int M, /* I Size of matrix */
+ const opus_int32 *b, /* I Pointer to b vector */
+ opus_int32 *x_Q16 /* O Pointer to x solution vector */
+);
+
+#ifndef FORCE_CPP_BUILD
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* FORCE_CPP_BUILD */
+#endif /* SILK_MAIN_FIX_H */
diff --git a/external/opus-1.1.4/silk/fixed/noise_shape_analysis_FIX.c b/external/opus-1.1.4/silk/fixed/noise_shape_analysis_FIX.c
new file mode 100644
index 0000000..e24d2e9
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/noise_shape_analysis_FIX.c
@@ -0,0 +1,445 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */
+/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */
+/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */
+/* coefficient in an array of coefficients, for monic filters. */
+static OPUS_INLINE opus_int32 warped_gain( /* gain in Q16*/
+ const opus_int32 *coefs_Q24,
+ opus_int lambda_Q16,
+ opus_int order
+) {
+ opus_int i;
+ opus_int32 gain_Q24;
+
+ lambda_Q16 = -lambda_Q16;
+ gain_Q24 = coefs_Q24[ order - 1 ];
+ for( i = order - 2; i >= 0; i-- ) {
+ gain_Q24 = silk_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 );
+ }
+ gain_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 );
+ return silk_INVERSE32_varQ( gain_Q24, 40 );
+}
+
+/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */
+/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
+static OPUS_INLINE void limit_warped_coefs(
+ opus_int32 *coefs_syn_Q24,
+ opus_int32 *coefs_ana_Q24,
+ opus_int lambda_Q16,
+ opus_int32 limit_Q24,
+ opus_int order
+) {
+ opus_int i, iter, ind = 0;
+ opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16;
+ opus_int32 nom_Q16, den_Q24;
+
+ /* Convert to monic coefficients */
+ lambda_Q16 = -lambda_Q16;
+ for( i = order - 1; i > 0; i-- ) {
+ coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 );
+ coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 );
+ }
+ lambda_Q16 = -lambda_Q16;
+ nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 );
+ den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 );
+ gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+ den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 );
+ gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+ for( i = 0; i < order; i++ ) {
+ coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] );
+ coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] );
+ }
+
+ for( iter = 0; iter < 10; iter++ ) {
+ /* Find maximum absolute value */
+ maxabs_Q24 = -1;
+ for( i = 0; i < order; i++ ) {
+ tmp = silk_max( silk_abs_int32( coefs_syn_Q24[ i ] ), silk_abs_int32( coefs_ana_Q24[ i ] ) );
+ if( tmp > maxabs_Q24 ) {
+ maxabs_Q24 = tmp;
+ ind = i;
+ }
+ }
+ if( maxabs_Q24 <= limit_Q24 ) {
+ /* Coefficients are within range - done */
+ return;
+ }
+
+ /* Convert back to true warped coefficients */
+ for( i = 1; i < order; i++ ) {
+ coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 );
+ coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 );
+ }
+ gain_syn_Q16 = silk_INVERSE32_varQ( gain_syn_Q16, 32 );
+ gain_ana_Q16 = silk_INVERSE32_varQ( gain_ana_Q16, 32 );
+ for( i = 0; i < order; i++ ) {
+ coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] );
+ coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] );
+ }
+
+ /* Apply bandwidth expansion */
+ chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ(
+ silk_SMULWB( maxabs_Q24 - limit_Q24, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ),
+ silk_MUL( maxabs_Q24, ind + 1 ), 22 );
+ silk_bwexpander_32( coefs_syn_Q24, order, chirp_Q16 );
+ silk_bwexpander_32( coefs_ana_Q24, order, chirp_Q16 );
+
+ /* Convert to monic warped coefficients */
+ lambda_Q16 = -lambda_Q16;
+ for( i = order - 1; i > 0; i-- ) {
+ coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 );
+ coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 );
+ }
+ lambda_Q16 = -lambda_Q16;
+ nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 );
+ den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 );
+ gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+ den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 );
+ gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+ for( i = 0; i < order; i++ ) {
+ coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] );
+ coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] );
+ }
+ }
+ silk_assert( 0 );
+}
+
+/**************************************************************/
+/* Compute noise shaping coefficients and initial gain values */
+/**************************************************************/
+void silk_noise_shape_analysis_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */
+ const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */
+ const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */
+ int arch /* I Run-time architecture */
+)
+{
+ silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
+ opus_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0;
+ opus_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32;
+ opus_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7;
+ opus_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8;
+ opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ];
+ opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ];
+ opus_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ];
+ opus_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ];
+ VARDECL( opus_int16, x_windowed );
+ const opus_int16 *x_ptr, *pitch_res_ptr;
+ SAVE_STACK;
+
+ /* Point to start of first LPC analysis block */
+ x_ptr = x - psEnc->sCmn.la_shape;
+
+ /****************/
+ /* GAIN CONTROL */
+ /****************/
+ SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7;
+
+ /* Input quality is the average of the quality in the lowest two VAD bands */
+ psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ]
+ + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 );
+
+ /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */
+ psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 -
+ SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 );
+
+ /* Reduce coding SNR during low speech activity */
+ if( psEnc->sCmn.useCBR == 0 ) {
+ b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8;
+ b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 );
+ SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
+ silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/
+ silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/
+ }
+
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Reduce gains for periodic signals */
+ SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 );
+ } else {
+ /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
+ SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
+ silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ),
+ SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 );
+ }
+
+ /*************************/
+ /* SPARSENESS PROCESSING */
+ /*************************/
+ /* Set quantizer offset */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Initially set to 0; may be overruled in process_gains(..) */
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ psEncCtrl->sparseness_Q8 = 0;
+ } else {
+ /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
+ nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 );
+ energy_variation_Q7 = 0;
+ log_energy_prev_Q7 = 0;
+ pitch_res_ptr = pitch_res;
+ for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) {
+ silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples );
+ nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/
+
+ log_energy_Q7 = silk_lin2log( nrg );
+ if( k > 0 ) {
+ energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 );
+ }
+ log_energy_prev_Q7 = log_energy_Q7;
+ pitch_res_ptr += nSamples;
+ }
+
+ psEncCtrl->sparseness_Q8 = silk_RSHIFT( silk_sigm_Q15( silk_SMULWB( energy_variation_Q7 -
+ SILK_FIX_CONST( 5.0, 7 ), SILK_FIX_CONST( 0.1, 16 ) ) ), 7 );
+
+ /* Set quantization offset depending on sparseness measure */
+ if( psEncCtrl->sparseness_Q8 > SILK_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) {
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ } else {
+ psEnc->sCmn.indices.quantOffsetType = 1;
+ }
+
+ /* Increase coding SNR for sparse signals */
+ SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SILK_FIX_CONST( 0.5, 8 ) );
+ }
+
+ /*******************************/
+ /* Control bandwidth expansion */
+ /*******************************/
+ /* More BWE for signals with high prediction gain */
+ strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) );
+ BWExp1_Q16 = BWExp2_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ),
+ silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 );
+ delta_Q16 = silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - silk_SMULBB( 3, psEncCtrl->coding_quality_Q14 ),
+ SILK_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) );
+ BWExp1_Q16 = silk_SUB32( BWExp1_Q16, delta_Q16 );
+ BWExp2_Q16 = silk_ADD32( BWExp2_Q16, delta_Q16 );
+ /* BWExp1 will be applied after BWExp2, so make it relative */
+ BWExp1_Q16 = silk_DIV32_16( silk_LSHIFT( BWExp1_Q16, 14 ), silk_RSHIFT( BWExp2_Q16, 2 ) );
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
+ warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) );
+ } else {
+ warping_Q16 = 0;
+ }
+
+ /********************************************/
+ /* Compute noise shaping AR coefs and gains */
+ /********************************************/
+ ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Apply window: sine slope followed by flat part followed by cosine slope */
+ opus_int shift, slope_part, flat_part;
+ flat_part = psEnc->sCmn.fs_kHz * 3;
+ slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 );
+
+ silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part );
+ shift = slope_part;
+ silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) );
+ shift += flat_part;
+ silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part );
+
+ /* Update pointer: next LPC analysis block */
+ x_ptr += psEnc->sCmn.subfr_length;
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Calculate warped auto correlation */
+ silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder );
+ } else {
+ /* Calculate regular auto correlation */
+ silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch );
+ }
+
+ /* Add white noise, as a fraction of energy */
+ auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ),
+ SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) );
+
+ /* Calculate the reflection coefficients using schur */
+ nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder );
+ silk_assert( nrg >= 0 );
+
+ /* Convert reflection coefficients to prediction coefficients */
+ silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder );
+
+ Qnrg = -scale; /* range: -12...30*/
+ silk_assert( Qnrg >= -12 );
+ silk_assert( Qnrg <= 30 );
+
+ /* Make sure that Qnrg is an even number */
+ if( Qnrg & 1 ) {
+ Qnrg -= 1;
+ nrg >>= 1;
+ }
+
+ tmp32 = silk_SQRT_APPROX( nrg );
+ Qnrg >>= 1; /* range: -6...15*/
+
+ psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( tmp32, 16 - Qnrg );
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Adjust gain for warping */
+ gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder );
+ silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
+ if ( silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ) >= ( silk_int32_MAX >> 1 ) ) {
+ psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX;
+ } else {
+ psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
+ }
+ }
+
+ /* Bandwidth expansion for synthesis filter shaping */
+ silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 );
+
+ /* Compute noise shaping filter coefficients */
+ silk_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( opus_int32 ) );
+
+ /* Bandwidth expansion for analysis filter shaping */
+ silk_assert( BWExp1_Q16 <= SILK_FIX_CONST( 1.0, 16 ) );
+ silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 );
+
+ /* Ratio of prediction gains, in energy domain */
+ pre_nrg_Q30 = silk_LPC_inverse_pred_gain_Q24( AR2_Q24, psEnc->sCmn.shapingLPCOrder );
+ nrg = silk_LPC_inverse_pred_gain_Q24( AR1_Q24, psEnc->sCmn.shapingLPCOrder );
+
+ /*psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg;*/
+ pre_nrg_Q30 = silk_LSHIFT32( silk_SMULWB( pre_nrg_Q30, SILK_FIX_CONST( 0.7, 15 ) ), 1 );
+ psEncCtrl->GainsPre_Q14[ k ] = ( opus_int ) SILK_FIX_CONST( 0.3, 14 ) + silk_DIV32_varQ( pre_nrg_Q30, nrg, 14 );
+
+ /* Convert to monic warped prediction coefficients and limit absolute values */
+ limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder );
+
+ /* Convert from Q24 to Q13 and store in int16 */
+ for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) {
+ psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) );
+ psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) );
+ }
+ }
+
+ /*****************/
+ /* Gain tweaking */
+ /*****************/
+ /* Increase gains during low speech activity and put lower limit on gains */
+ gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) );
+ gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) );
+ silk_assert( gain_mult_Q16 > 0 );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
+ silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
+ psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 );
+ }
+
+ gain_mult_Q16 = SILK_FIX_CONST( 1.0, 16 ) + silk_RSHIFT_ROUND( silk_MLA( SILK_FIX_CONST( INPUT_TILT, 26 ),
+ psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->GainsPre_Q14[ k ] = silk_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] );
+ }
+
+ /************************************************/
+ /* Control low-frequency shaping and noise tilt */
+ /************************************************/
+ /* Less low frequency shaping for noisy inputs */
+ strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ),
+ SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) );
+ strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 );
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
+ /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
+ opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] );
+ /* Pack two coefficients in one int32 */
+ psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 );
+ psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
+ }
+ silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/
+ Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) -
+ silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ),
+ silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) );
+ } else {
+ b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/
+ /* Pack two coefficients in one int32 */
+ psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 -
+ silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 );
+ psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
+ for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ];
+ }
+ Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 );
+ }
+
+ /****************************/
+ /* HARMONIC SHAPING CONTROL */
+ /****************************/
+ /* Control boosting of harmonic frequencies */
+ HarmBoost_Q16 = silk_SMULWB( silk_SMULWB( SILK_FIX_CONST( 1.0, 17 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ),
+ psEnc->LTPCorr_Q15 ), SILK_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) );
+
+ /* More harmonic boost for noisy input signals */
+ HarmBoost_Q16 = silk_SMLAWB( HarmBoost_Q16,
+ SILK_FIX_CONST( 1.0, 16 ) - silk_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SILK_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) );
+
+ if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* More harmonic noise shaping for high bitrates or noisy input */
+ HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ),
+ SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ),
+ psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) );
+
+ /* Less harmonic noise shaping for less periodic signals */
+ HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ),
+ silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) );
+ } else {
+ HarmShapeGain_Q16 = 0;
+ }
+
+ /*************************/
+ /* Smooth over subframes */
+ /*************************/
+ for( k = 0; k < MAX_NB_SUBFR; k++ ) {
+ psShapeSt->HarmBoost_smth_Q16 =
+ silk_SMLAWB( psShapeSt->HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt->HarmBoost_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+ psShapeSt->HarmShapeGain_smth_Q16 =
+ silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+ psShapeSt->Tilt_smth_Q16 =
+ silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+
+ psEncCtrl->HarmBoost_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16, 2 );
+ psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 );
+ psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 );
+ }
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/fixed/pitch_analysis_core_FIX.c b/external/opus-1.1.4/silk/fixed/pitch_analysis_core_FIX.c
new file mode 100644
index 0000000..1641a0f
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/pitch_analysis_core_FIX.c
@@ -0,0 +1,744 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/***********************************************************
+* Pitch analyser function
+********************************************************** */
+#include "SigProc_FIX.h"
+#include "pitch_est_defines.h"
+#include "stack_alloc.h"
+#include "debug.h"
+#include "pitch.h"
+
+#define SCRATCH_SIZE 22
+#define SF_LENGTH_4KHZ ( PE_SUBFR_LENGTH_MS * 4 )
+#define SF_LENGTH_8KHZ ( PE_SUBFR_LENGTH_MS * 8 )
+#define MIN_LAG_4KHZ ( PE_MIN_LAG_MS * 4 )
+#define MIN_LAG_8KHZ ( PE_MIN_LAG_MS * 8 )
+#define MAX_LAG_4KHZ ( PE_MAX_LAG_MS * 4 )
+#define MAX_LAG_8KHZ ( PE_MAX_LAG_MS * 8 - 1 )
+#define CSTRIDE_4KHZ ( MAX_LAG_4KHZ + 1 - MIN_LAG_4KHZ )
+#define CSTRIDE_8KHZ ( MAX_LAG_8KHZ + 3 - ( MIN_LAG_8KHZ - 2 ) )
+#define D_COMP_MIN ( MIN_LAG_8KHZ - 3 )
+#define D_COMP_MAX ( MAX_LAG_8KHZ + 4 )
+#define D_COMP_STRIDE ( D_COMP_MAX - D_COMP_MIN )
+
+typedef opus_int32 silk_pe_stage3_vals[ PE_NB_STAGE3_LAGS ];
+
+/************************************************************/
+/* Internally used functions */
+/************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+ silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */
+ const opus_int16 frame[], /* I vector to correlate */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of a 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+);
+
+static void silk_P_Ana_calc_energy_st3(
+ silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */
+ const opus_int16 frame[], /* I vector to calc energy in */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of one 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity /* I Complexity setting */
+);
+
+/*************************************************************/
+/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */
+/*************************************************************/
+opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */
+ const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
+ opus_int *pitch_out, /* O 4 pitch lag values */
+ opus_int16 *lagIndex, /* O Lag Index */
+ opus_int8 *contourIndex, /* O Pitch contour Index */
+ opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */
+ opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
+ const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */
+ const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */
+ const opus_int Fs_kHz, /* I Sample frequency (kHz) */
+ const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
+ const opus_int nb_subfr, /* I number of 5 ms subframes */
+ int arch /* I Run-time architecture */
+)
+{
+ VARDECL( opus_int16, frame_8kHz );
+ VARDECL( opus_int16, frame_4kHz );
+ opus_int32 filt_state[ 6 ];
+ const opus_int16 *input_frame_ptr;
+ opus_int i, k, d, j;
+ VARDECL( opus_int16, C );
+ VARDECL( opus_int32, xcorr32 );
+ const opus_int16 *target_ptr, *basis_ptr;
+ opus_int32 cross_corr, normalizer, energy, shift, energy_basis, energy_target;
+ opus_int d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp;
+ VARDECL( opus_int16, d_comp );
+ opus_int32 sum, threshold, lag_counter;
+ opus_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new;
+ opus_int32 CC[ PE_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new;
+ VARDECL( silk_pe_stage3_vals, energies_st3 );
+ VARDECL( silk_pe_stage3_vals, cross_corr_st3 );
+ opus_int frame_length, frame_length_8kHz, frame_length_4kHz;
+ opus_int sf_length;
+ opus_int min_lag;
+ opus_int max_lag;
+ opus_int32 contour_bias_Q15, diff;
+ opus_int nb_cbk_search, cbk_size;
+ opus_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q13;
+ const opus_int8 *Lag_CB_ptr;
+ SAVE_STACK;
+ /* Check for valid sampling frequency */
+ silk_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 );
+
+ /* Check for valid complexity setting */
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ silk_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) );
+ silk_assert( search_thres2_Q13 >= 0 && search_thres2_Q13 <= (1<<13) );
+
+ /* Set up frame lengths max / min lag for the sampling frequency */
+ frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz;
+ frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4;
+ frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8;
+ sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz;
+ min_lag = PE_MIN_LAG_MS * Fs_kHz;
+ max_lag = PE_MAX_LAG_MS * Fs_kHz - 1;
+
+ /* Resample from input sampled at Fs_kHz to 8 kHz */
+ ALLOC( frame_8kHz, frame_length_8kHz, opus_int16 );
+ if( Fs_kHz == 16 ) {
+ silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
+ silk_resampler_down2( filt_state, frame_8kHz, frame, frame_length );
+ } else if( Fs_kHz == 12 ) {
+ silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) );
+ silk_resampler_down2_3( filt_state, frame_8kHz, frame, frame_length );
+ } else {
+ silk_assert( Fs_kHz == 8 );
+ silk_memcpy( frame_8kHz, frame, frame_length_8kHz * sizeof(opus_int16) );
+ }
+
+ /* Decimate again to 4 kHz */
+ silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );/* Set state to zero */
+ ALLOC( frame_4kHz, frame_length_4kHz, opus_int16 );
+ silk_resampler_down2( filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz );
+
+ /* Low-pass filter */
+ for( i = frame_length_4kHz - 1; i > 0; i-- ) {
+ frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] );
+ }
+
+ /*******************************************************************************
+ ** Scale 4 kHz signal down to prevent correlations measures from overflowing
+ ** find scaling as max scaling for each 8kHz(?) subframe
+ *******************************************************************************/
+
+ /* Inner product is calculated with different lengths, so scale for the worst case */
+ silk_sum_sqr_shift( &energy, &shift, frame_4kHz, frame_length_4kHz );
+ if( shift > 0 ) {
+ shift = silk_RSHIFT( shift, 1 );
+ for( i = 0; i < frame_length_4kHz; i++ ) {
+ frame_4kHz[ i ] = silk_RSHIFT( frame_4kHz[ i ], shift );
+ }
+ }
+
+ /******************************************************************************
+ * FIRST STAGE, operating in 4 khz
+ ******************************************************************************/
+ ALLOC( C, nb_subfr * CSTRIDE_8KHZ, opus_int16 );
+ ALLOC( xcorr32, MAX_LAG_4KHZ-MIN_LAG_4KHZ+1, opus_int32 );
+ silk_memset( C, 0, (nb_subfr >> 1) * CSTRIDE_4KHZ * sizeof( opus_int16 ) );
+ target_ptr = &frame_4kHz[ silk_LSHIFT( SF_LENGTH_4KHZ, 2 ) ];
+ for( k = 0; k < nb_subfr >> 1; k++ ) {
+ /* Check that we are within range of the array */
+ silk_assert( target_ptr >= frame_4kHz );
+ silk_assert( target_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+ basis_ptr = target_ptr - MIN_LAG_4KHZ;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_4kHz );
+ silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+ celt_pitch_xcorr( target_ptr, target_ptr - MAX_LAG_4KHZ, xcorr32, SF_LENGTH_8KHZ, MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1, arch );
+
+ /* Calculate first vector products before loop */
+ cross_corr = xcorr32[ MAX_LAG_4KHZ - MIN_LAG_4KHZ ];
+ normalizer = silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ );
+ normalizer = silk_ADD32( normalizer, silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ ) );
+ normalizer = silk_ADD32( normalizer, silk_SMULBB( SF_LENGTH_8KHZ, 4000 ) );
+
+ matrix_ptr( C, k, 0, CSTRIDE_4KHZ ) =
+ (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */
+
+ /* From now on normalizer is computed recursively */
+ for( d = MIN_LAG_4KHZ + 1; d <= MAX_LAG_4KHZ; d++ ) {
+ basis_ptr--;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_4kHz );
+ silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+ cross_corr = xcorr32[ MAX_LAG_4KHZ - d ];
+
+ /* Add contribution of new sample and remove contribution from oldest sample */
+ normalizer = silk_ADD32( normalizer,
+ silk_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) -
+ silk_SMULBB( basis_ptr[ SF_LENGTH_8KHZ ], basis_ptr[ SF_LENGTH_8KHZ ] ) );
+
+ matrix_ptr( C, k, d - MIN_LAG_4KHZ, CSTRIDE_4KHZ) =
+ (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */
+ }
+ /* Update target pointer */
+ target_ptr += SF_LENGTH_8KHZ;
+ }
+
+ /* Combine two subframes into single correlation measure and apply short-lag bias */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) {
+ sum = (opus_int32)matrix_ptr( C, 0, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ )
+ + (opus_int32)matrix_ptr( C, 1, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ); /* Q14 */
+ sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */
+ C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */
+ }
+ } else {
+ /* Only short-lag bias */
+ for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) {
+ sum = silk_LSHIFT( (opus_int32)C[ i - MIN_LAG_4KHZ ], 1 ); /* Q14 */
+ sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */
+ C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */
+ }
+ }
+
+ /* Sort */
+ length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 );
+ silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH );
+ silk_insertion_sort_decreasing_int16( C, d_srch, CSTRIDE_4KHZ,
+ length_d_srch );
+
+ /* Escape if correlation is very low already here */
+ Cmax = (opus_int)C[ 0 ]; /* Q14 */
+ if( Cmax < SILK_FIX_CONST( 0.2, 14 ) ) {
+ silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
+ *LTPCorr_Q15 = 0;
+ *lagIndex = 0;
+ *contourIndex = 0;
+ RESTORE_STACK;
+ return 1;
+ }
+
+ threshold = silk_SMULWB( search_thres1_Q16, Cmax );
+ for( i = 0; i < length_d_srch; i++ ) {
+ /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */
+ if( C[ i ] > threshold ) {
+ d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + MIN_LAG_4KHZ, 1 );
+ } else {
+ length_d_srch = i;
+ break;
+ }
+ }
+ silk_assert( length_d_srch > 0 );
+
+ ALLOC( d_comp, D_COMP_STRIDE, opus_int16 );
+ for( i = D_COMP_MIN; i < D_COMP_MAX; i++ ) {
+ d_comp[ i - D_COMP_MIN ] = 0;
+ }
+ for( i = 0; i < length_d_srch; i++ ) {
+ d_comp[ d_srch[ i ] - D_COMP_MIN ] = 1;
+ }
+
+ /* Convolution */
+ for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) {
+ d_comp[ i - D_COMP_MIN ] +=
+ d_comp[ i - 1 - D_COMP_MIN ] + d_comp[ i - 2 - D_COMP_MIN ];
+ }
+
+ length_d_srch = 0;
+ for( i = MIN_LAG_8KHZ; i < MAX_LAG_8KHZ + 1; i++ ) {
+ if( d_comp[ i + 1 - D_COMP_MIN ] > 0 ) {
+ d_srch[ length_d_srch ] = i;
+ length_d_srch++;
+ }
+ }
+
+ /* Convolution */
+ for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) {
+ d_comp[ i - D_COMP_MIN ] += d_comp[ i - 1 - D_COMP_MIN ]
+ + d_comp[ i - 2 - D_COMP_MIN ] + d_comp[ i - 3 - D_COMP_MIN ];
+ }
+
+ length_d_comp = 0;
+ for( i = MIN_LAG_8KHZ; i < D_COMP_MAX; i++ ) {
+ if( d_comp[ i - D_COMP_MIN ] > 0 ) {
+ d_comp[ length_d_comp ] = i - 2;
+ length_d_comp++;
+ }
+ }
+
+ /**********************************************************************************
+ ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation
+ *************************************************************************************/
+
+ /******************************************************************************
+ ** Scale signal down to avoid correlations measures from overflowing
+ *******************************************************************************/
+ /* find scaling as max scaling for each subframe */
+ silk_sum_sqr_shift( &energy, &shift, frame_8kHz, frame_length_8kHz );
+ if( shift > 0 ) {
+ shift = silk_RSHIFT( shift, 1 );
+ for( i = 0; i < frame_length_8kHz; i++ ) {
+ frame_8kHz[ i ] = silk_RSHIFT( frame_8kHz[ i ], shift );
+ }
+ }
+
+ /*********************************************************************************
+ * Find energy of each subframe projected onto its history, for a range of delays
+ *********************************************************************************/
+ silk_memset( C, 0, nb_subfr * CSTRIDE_8KHZ * sizeof( opus_int16 ) );
+
+ target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ];
+ for( k = 0; k < nb_subfr; k++ ) {
+
+ /* Check that we are within range of the array */
+ silk_assert( target_ptr >= frame_8kHz );
+ silk_assert( target_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz );
+
+ energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ ), 1 );
+ for( j = 0; j < length_d_comp; j++ ) {
+ d = d_comp[ j ];
+ basis_ptr = target_ptr - d;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_8kHz );
+ silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz );
+
+ cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, SF_LENGTH_8KHZ );
+ if( cross_corr > 0 ) {
+ energy_basis = silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ );
+ matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) =
+ (opus_int16)silk_DIV32_varQ( cross_corr,
+ silk_ADD32( energy_target,
+ energy_basis ),
+ 13 + 1 ); /* Q13 */
+ } else {
+ matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = 0;
+ }
+ }
+ target_ptr += SF_LENGTH_8KHZ;
+ }
+
+ /* search over lag range and lags codebook */
+ /* scale factor for lag codebook, as a function of center lag */
+
+ CCmax = silk_int32_MIN;
+ CCmax_b = silk_int32_MIN;
+
+ CBimax = 0; /* To avoid returning undefined lag values */
+ lag = -1; /* To check if lag with strong enough correlation has been found */
+
+ if( prevLag > 0 ) {
+ if( Fs_kHz == 12 ) {
+ prevLag = silk_DIV32_16( silk_LSHIFT( prevLag, 1 ), 3 );
+ } else if( Fs_kHz == 16 ) {
+ prevLag = silk_RSHIFT( prevLag, 1 );
+ }
+ prevLag_log2_Q7 = silk_lin2log( (opus_int32)prevLag );
+ } else {
+ prevLag_log2_Q7 = 0;
+ }
+ silk_assert( search_thres2_Q13 == silk_SAT16( search_thres2_Q13 ) );
+ /* Set up stage 2 codebook based on number of subframes */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ cbk_size = PE_NB_CBKS_STAGE2_EXT;
+ Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
+ if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) {
+ /* If input is 8 khz use a larger codebook here because it is last stage */
+ nb_cbk_search = PE_NB_CBKS_STAGE2_EXT;
+ } else {
+ nb_cbk_search = PE_NB_CBKS_STAGE2;
+ }
+ } else {
+ cbk_size = PE_NB_CBKS_STAGE2_10MS;
+ Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE2_10MS;
+ }
+
+ for( k = 0; k < length_d_srch; k++ ) {
+ d = d_srch[ k ];
+ for( j = 0; j < nb_cbk_search; j++ ) {
+ CC[ j ] = 0;
+ for( i = 0; i < nb_subfr; i++ ) {
+ opus_int d_subfr;
+ /* Try all codebooks */
+ d_subfr = d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size );
+ CC[ j ] = CC[ j ]
+ + (opus_int32)matrix_ptr( C, i,
+ d_subfr - ( MIN_LAG_8KHZ - 2 ),
+ CSTRIDE_8KHZ );
+ }
+ }
+ /* Find best codebook */
+ CCmax_new = silk_int32_MIN;
+ CBimax_new = 0;
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ if( CC[ i ] > CCmax_new ) {
+ CCmax_new = CC[ i ];
+ CBimax_new = i;
+ }
+ }
+
+ /* Bias towards shorter lags */
+ lag_log2_Q7 = silk_lin2log( d ); /* Q7 */
+ silk_assert( lag_log2_Q7 == silk_SAT16( lag_log2_Q7 ) );
+ silk_assert( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) ) );
+ CCmax_new_b = CCmax_new - silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ), lag_log2_Q7 ), 7 ); /* Q13 */
+
+ /* Bias towards previous lag */
+ silk_assert( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) ) );
+ if( prevLag > 0 ) {
+ delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7;
+ silk_assert( delta_lag_log2_sqr_Q7 == silk_SAT16( delta_lag_log2_sqr_Q7 ) );
+ delta_lag_log2_sqr_Q7 = silk_RSHIFT( silk_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 );
+ prev_lag_bias_Q13 = silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ), *LTPCorr_Q15 ), 15 ); /* Q13 */
+ prev_lag_bias_Q13 = silk_DIV32( silk_MUL( prev_lag_bias_Q13, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + SILK_FIX_CONST( 0.5, 7 ) );
+ CCmax_new_b -= prev_lag_bias_Q13; /* Q13 */
+ }
+
+ if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */
+ CCmax_new > silk_SMULBB( nb_subfr, search_thres2_Q13 ) && /* Correlation needs to be high enough to be voiced */
+ silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= MIN_LAG_8KHZ /* Lag must be in range */
+ ) {
+ CCmax_b = CCmax_new_b;
+ CCmax = CCmax_new;
+ lag = d;
+ CBimax = CBimax_new;
+ }
+ }
+
+ if( lag == -1 ) {
+ /* No suitable candidate found */
+ silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
+ *LTPCorr_Q15 = 0;
+ *lagIndex = 0;
+ *contourIndex = 0;
+ RESTORE_STACK;
+ return 1;
+ }
+
+ /* Output normalized correlation */
+ *LTPCorr_Q15 = (opus_int)silk_LSHIFT( silk_DIV32_16( CCmax, nb_subfr ), 2 );
+ silk_assert( *LTPCorr_Q15 >= 0 );
+
+ if( Fs_kHz > 8 ) {
+ VARDECL( opus_int16, scratch_mem );
+ /***************************************************************************/
+ /* Scale input signal down to avoid correlations measures from overflowing */
+ /***************************************************************************/
+ /* find scaling as max scaling for each subframe */
+ silk_sum_sqr_shift( &energy, &shift, frame, frame_length );
+ ALLOC( scratch_mem, shift > 0 ? frame_length : ALLOC_NONE, opus_int16 );
+ if( shift > 0 ) {
+ /* Move signal to scratch mem because the input signal should be unchanged */
+ shift = silk_RSHIFT( shift, 1 );
+ for( i = 0; i < frame_length; i++ ) {
+ scratch_mem[ i ] = silk_RSHIFT( frame[ i ], shift );
+ }
+ input_frame_ptr = scratch_mem;
+ } else {
+ input_frame_ptr = frame;
+ }
+
+ /* Search in original signal */
+
+ CBimax_old = CBimax;
+ /* Compensate for decimation */
+ silk_assert( lag == silk_SAT16( lag ) );
+ if( Fs_kHz == 12 ) {
+ lag = silk_RSHIFT( silk_SMULBB( lag, 3 ), 1 );
+ } else if( Fs_kHz == 16 ) {
+ lag = silk_LSHIFT( lag, 1 );
+ } else {
+ lag = silk_SMULBB( lag, 3 );
+ }
+
+ lag = silk_LIMIT_int( lag, min_lag, max_lag );
+ start_lag = silk_max_int( lag - 2, min_lag );
+ end_lag = silk_min_int( lag + 2, max_lag );
+ lag_new = lag; /* to avoid undefined lag */
+ CBimax = 0; /* to avoid undefined lag */
+
+ CCmax = silk_int32_MIN;
+ /* pitch lags according to second stage */
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag + 2 * silk_CB_lags_stage2[ k ][ CBimax_old ];
+ }
+
+ /* Set up codebook parameters according to complexity setting and frame length */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ } else {
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ }
+
+ /* Calculate the correlations and energies needed in stage 3 */
+ ALLOC( energies_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals );
+ ALLOC( cross_corr_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals );
+ silk_P_Ana_calc_corr_st3( cross_corr_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity, arch );
+ silk_P_Ana_calc_energy_st3( energies_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity );
+
+ lag_counter = 0;
+ silk_assert( lag == silk_SAT16( lag ) );
+ contour_bias_Q15 = silk_DIV32_16( SILK_FIX_CONST( PE_FLATCONTOUR_BIAS, 15 ), lag );
+
+ target_ptr = &input_frame_ptr[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ];
+ energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, nb_subfr * sf_length ), 1 );
+ for( d = start_lag; d <= end_lag; d++ ) {
+ for( j = 0; j < nb_cbk_search; j++ ) {
+ cross_corr = 0;
+ energy = energy_target;
+ for( k = 0; k < nb_subfr; k++ ) {
+ cross_corr = silk_ADD32( cross_corr,
+ matrix_ptr( cross_corr_st3, k, j,
+ nb_cbk_search )[ lag_counter ] );
+ energy = silk_ADD32( energy,
+ matrix_ptr( energies_st3, k, j,
+ nb_cbk_search )[ lag_counter ] );
+ silk_assert( energy >= 0 );
+ }
+ if( cross_corr > 0 ) {
+ CCmax_new = silk_DIV32_varQ( cross_corr, energy, 13 + 1 ); /* Q13 */
+ /* Reduce depending on flatness of contour */
+ diff = silk_int16_MAX - silk_MUL( contour_bias_Q15, j ); /* Q15 */
+ silk_assert( diff == silk_SAT16( diff ) );
+ CCmax_new = silk_SMULWB( CCmax_new, diff ); /* Q14 */
+ } else {
+ CCmax_new = 0;
+ }
+
+ if( CCmax_new > CCmax && ( d + silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) {
+ CCmax = CCmax_new;
+ lag_new = d;
+ CBimax = j;
+ }
+ }
+ lag_counter++;
+ }
+
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+ pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz );
+ }
+ *lagIndex = (opus_int16)( lag_new - min_lag);
+ *contourIndex = (opus_int8)CBimax;
+ } else { /* Fs_kHz == 8 */
+ /* Save Lags */
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+ pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], MIN_LAG_8KHZ, PE_MAX_LAG_MS * 8 );
+ }
+ *lagIndex = (opus_int16)( lag - MIN_LAG_8KHZ );
+ *contourIndex = (opus_int8)CBimax;
+ }
+ silk_assert( *lagIndex >= 0 );
+ /* return as voiced */
+ RESTORE_STACK;
+ return 0;
+}
+
+/***********************************************************************
+ * Calculates the correlations used in stage 3 search. In order to cover
+ * the whole lag codebook for all the searched offset lags (lag +- 2),
+ * the following correlations are needed in each sub frame:
+ *
+ * sf1: lag range [-8,...,7] total 16 correlations
+ * sf2: lag range [-4,...,4] total 9 correlations
+ * sf3: lag range [-3,....4] total 8 correltions
+ * sf4: lag range [-6,....8] total 15 correlations
+ *
+ * In total 48 correlations. The direct implementation computed in worst
+ * case 4*12*5 = 240 correlations, but more likely around 120.
+ ***********************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+ silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */
+ const opus_int16 frame[], /* I vector to correlate */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of a 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+)
+{
+ const opus_int16 *target_ptr;
+ opus_int i, j, k, lag_counter, lag_low, lag_high;
+ opus_int nb_cbk_search, delta, idx, cbk_size;
+ VARDECL( opus_int32, scratch_mem );
+ VARDECL( opus_int32, xcorr32 );
+ const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+ SAVE_STACK;
+
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+ ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 );
+ ALLOC( xcorr32, SCRATCH_SIZE, opus_int32 );
+
+ target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_counter = 0;
+
+ /* Calculate the correlations for each subframe */
+ lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 );
+ silk_assert(lag_high-lag_low+1 <= SCRATCH_SIZE);
+ celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1, arch );
+ for( j = lag_low; j <= lag_high; j++ ) {
+ silk_assert( lag_counter < SCRATCH_SIZE );
+ scratch_mem[ lag_counter ] = xcorr32[ lag_high - j ];
+ lag_counter++;
+ }
+
+ delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ /* Fill out the 3 dim array that stores the correlations for */
+ /* each code_book vector for each start lag */
+ idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+ for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+ silk_assert( idx + j < SCRATCH_SIZE );
+ silk_assert( idx + j < lag_counter );
+ matrix_ptr( cross_corr_st3, k, i, nb_cbk_search )[ j ] =
+ scratch_mem[ idx + j ];
+ }
+ }
+ target_ptr += sf_length;
+ }
+ RESTORE_STACK;
+}
+
+/********************************************************************/
+/* Calculate the energies for first two subframes. The energies are */
+/* calculated recursively. */
+/********************************************************************/
+static void silk_P_Ana_calc_energy_st3(
+ silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */
+ const opus_int16 frame[], /* I vector to calc energy in */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of one 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity /* I Complexity setting */
+)
+{
+ const opus_int16 *target_ptr, *basis_ptr;
+ opus_int32 energy;
+ opus_int k, i, j, lag_counter;
+ opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff;
+ VARDECL( opus_int32, scratch_mem );
+ const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+ SAVE_STACK;
+
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+ ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 );
+
+ target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ];
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_counter = 0;
+
+ /* Calculate the energy for first lag */
+ basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) );
+ energy = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length );
+ silk_assert( energy >= 0 );
+ scratch_mem[ lag_counter ] = energy;
+ lag_counter++;
+
+ lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 );
+ for( i = 1; i < lag_diff; i++ ) {
+ /* remove part outside new window */
+ energy -= silk_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] );
+ silk_assert( energy >= 0 );
+
+ /* add part that comes into window */
+ energy = silk_ADD_SAT32( energy, silk_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) );
+ silk_assert( energy >= 0 );
+ silk_assert( lag_counter < SCRATCH_SIZE );
+ scratch_mem[ lag_counter ] = energy;
+ lag_counter++;
+ }
+
+ delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ /* Fill out the 3 dim array that stores the correlations for */
+ /* each code_book vector for each start lag */
+ idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+ for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+ silk_assert( idx + j < SCRATCH_SIZE );
+ silk_assert( idx + j < lag_counter );
+ matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] =
+ scratch_mem[ idx + j ];
+ silk_assert(
+ matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] >= 0 );
+ }
+ }
+ target_ptr += sf_length;
+ }
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/fixed/prefilter_FIX.c b/external/opus-1.1.4/silk/fixed/prefilter_FIX.c
new file mode 100644
index 0000000..d381730
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/prefilter_FIX.c
@@ -0,0 +1,209 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Prefilter for finding Quantizer input signal */
+static OPUS_INLINE void silk_prefilt_FIX(
+ silk_prefilter_state_FIX *P, /* I/O state */
+ opus_int32 st_res_Q12[], /* I short term residual signal */
+ opus_int32 xw_Q3[], /* O prefiltered signal */
+ opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */
+ opus_int Tilt_Q14, /* I Tilt shaping coeficient */
+ opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */
+ opus_int lag, /* I Lag for harmonic shaping */
+ opus_int length /* I Length of signals */
+);
+
+void silk_warped_LPC_analysis_filter_FIX(
+ opus_int32 state[], /* I/O State [order + 1] */
+ opus_int32 res_Q2[], /* O Residual signal [length] */
+ const opus_int16 coef_Q13[], /* I Coefficients [order] */
+ const opus_int16 input[], /* I Input signal [length] */
+ const opus_int16 lambda_Q16, /* I Warping factor */
+ const opus_int length, /* I Length of input signal */
+ const opus_int order /* I Filter order (even) */
+)
+{
+ opus_int n, i;
+ opus_int32 acc_Q11, tmp1, tmp2;
+
+ /* Order must be even */
+ silk_assert( ( order & 1 ) == 0 );
+
+ for( n = 0; n < length; n++ ) {
+ /* Output of lowpass section */
+ tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 );
+ state[ 0 ] = silk_LSHIFT( input[ n ], 14 );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 );
+ state[ 1 ] = tmp2;
+ acc_Q11 = silk_RSHIFT( order, 1 );
+ acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] );
+ /* Loop over allpass sections */
+ for( i = 2; i < order; i += 2 ) {
+ /* Output of allpass section */
+ tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 );
+ state[ i ] = tmp1;
+ acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 );
+ state[ i + 1 ] = tmp2;
+ acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] );
+ }
+ state[ order ] = tmp1;
+ acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] );
+ res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 );
+ }
+}
+
+void silk_prefilter_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
+ const silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */
+ opus_int32 xw_Q3[], /* O Weighted signal */
+ const opus_int16 x[] /* I Speech signal */
+)
+{
+ silk_prefilter_state_FIX *P = &psEnc->sPrefilt;
+ opus_int j, k, lag;
+ opus_int32 tmp_32;
+ const opus_int16 *AR1_shp_Q13;
+ const opus_int16 *px;
+ opus_int32 *pxw_Q3;
+ opus_int HarmShapeGain_Q12, Tilt_Q14;
+ opus_int32 HarmShapeFIRPacked_Q12, LF_shp_Q14;
+ VARDECL( opus_int32, x_filt_Q12 );
+ VARDECL( opus_int32, st_res_Q2 );
+ opus_int16 B_Q10[ 2 ];
+ SAVE_STACK;
+
+ /* Set up pointers */
+ px = x;
+ pxw_Q3 = xw_Q3;
+ lag = P->lagPrev;
+ ALLOC( x_filt_Q12, psEnc->sCmn.subfr_length, opus_int32 );
+ ALLOC( st_res_Q2, psEnc->sCmn.subfr_length, opus_int32 );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Update Variables that change per sub frame */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ lag = psEncCtrl->pitchL[ k ];
+ }
+
+ /* Noise shape parameters */
+ HarmShapeGain_Q12 = silk_SMULWB( (opus_int32)psEncCtrl->HarmShapeGain_Q14[ k ], 16384 - psEncCtrl->HarmBoost_Q14[ k ] );
+ silk_assert( HarmShapeGain_Q12 >= 0 );
+ HarmShapeFIRPacked_Q12 = silk_RSHIFT( HarmShapeGain_Q12, 2 );
+ HarmShapeFIRPacked_Q12 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q12, 1 ), 16 );
+ Tilt_Q14 = psEncCtrl->Tilt_Q14[ k ];
+ LF_shp_Q14 = psEncCtrl->LF_shp_Q14[ k ];
+ AR1_shp_Q13 = &psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Short term FIR filtering*/
+ silk_warped_LPC_analysis_filter_FIX( P->sAR_shp, st_res_Q2, AR1_shp_Q13, px,
+ psEnc->sCmn.warping_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder );
+
+ /* Reduce (mainly) low frequencies during harmonic emphasis */
+ B_Q10[ 0 ] = silk_RSHIFT_ROUND( psEncCtrl->GainsPre_Q14[ k ], 4 );
+ tmp_32 = silk_SMLABB( SILK_FIX_CONST( INPUT_TILT, 26 ), psEncCtrl->HarmBoost_Q14[ k ], HarmShapeGain_Q12 ); /* Q26 */
+ tmp_32 = silk_SMLABB( tmp_32, psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ); /* Q26 */
+ tmp_32 = silk_SMULWB( tmp_32, -psEncCtrl->GainsPre_Q14[ k ] ); /* Q24 */
+ tmp_32 = silk_RSHIFT_ROUND( tmp_32, 14 ); /* Q10 */
+ B_Q10[ 1 ]= silk_SAT16( tmp_32 );
+ x_filt_Q12[ 0 ] = silk_MLA( silk_MUL( st_res_Q2[ 0 ], B_Q10[ 0 ] ), P->sHarmHP_Q2, B_Q10[ 1 ] );
+ for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) {
+ x_filt_Q12[ j ] = silk_MLA( silk_MUL( st_res_Q2[ j ], B_Q10[ 0 ] ), st_res_Q2[ j - 1 ], B_Q10[ 1 ] );
+ }
+ P->sHarmHP_Q2 = st_res_Q2[ psEnc->sCmn.subfr_length - 1 ];
+
+ silk_prefilt_FIX( P, x_filt_Q12, pxw_Q3, HarmShapeFIRPacked_Q12, Tilt_Q14, LF_shp_Q14, lag, psEnc->sCmn.subfr_length );
+
+ px += psEnc->sCmn.subfr_length;
+ pxw_Q3 += psEnc->sCmn.subfr_length;
+ }
+
+ P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+ RESTORE_STACK;
+}
+
+/* Prefilter for finding Quantizer input signal */
+static OPUS_INLINE void silk_prefilt_FIX(
+ silk_prefilter_state_FIX *P, /* I/O state */
+ opus_int32 st_res_Q12[], /* I short term residual signal */
+ opus_int32 xw_Q3[], /* O prefiltered signal */
+ opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */
+ opus_int Tilt_Q14, /* I Tilt shaping coeficient */
+ opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */
+ opus_int lag, /* I Lag for harmonic shaping */
+ opus_int length /* I Length of signals */
+)
+{
+ opus_int i, idx, LTP_shp_buf_idx;
+ opus_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10;
+ opus_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12;
+ opus_int16 *LTP_shp_buf;
+
+ /* To speed up use temp variables instead of using the struct */
+ LTP_shp_buf = P->sLTP_shp;
+ LTP_shp_buf_idx = P->sLTP_shp_buf_idx;
+ sLF_AR_shp_Q12 = P->sLF_AR_shp_Q12;
+ sLF_MA_shp_Q12 = P->sLF_MA_shp_Q12;
+
+ for( i = 0; i < length; i++ ) {
+ if( lag > 0 ) {
+ /* unrolled loop */
+ silk_assert( HARM_SHAPE_FIR_TAPS == 3 );
+ idx = lag + LTP_shp_buf_idx;
+ n_LTP_Q12 = silk_SMULBB( LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+ n_LTP_Q12 = silk_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+ n_LTP_Q12 = silk_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+ } else {
+ n_LTP_Q12 = 0;
+ }
+
+ n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 );
+ n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 );
+
+ sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) );
+ sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) );
+
+ LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK;
+ LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) );
+
+ xw_Q3[i] = silk_RSHIFT_ROUND( silk_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 9 );
+ }
+
+ /* Copy temp variable back to state */
+ P->sLF_AR_shp_Q12 = sLF_AR_shp_Q12;
+ P->sLF_MA_shp_Q12 = sLF_MA_shp_Q12;
+ P->sLTP_shp_buf_idx = LTP_shp_buf_idx;
+}
diff --git a/external/opus-1.1.4/silk/fixed/process_gains_FIX.c b/external/opus-1.1.4/silk/fixed/process_gains_FIX.c
new file mode 100644
index 0000000..05aba31
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/process_gains_FIX.c
@@ -0,0 +1,117 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "tuning_parameters.h"
+
+/* Processing of gains */
+void silk_process_gains_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
+ opus_int k;
+ opus_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10;
+
+ /* Gain reduction when LTP coding gain is high */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */
+ s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 );
+ }
+ }
+
+ /* Limit the quantized signal */
+ /* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */
+ InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin(
+ silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length );
+
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Soft limit on ratio residual energy and squared gains */
+ ResNrg = psEncCtrl->ResNrg[ k ];
+ ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 );
+ if( psEncCtrl->ResNrgQ[ k ] > 0 ) {
+ ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] );
+ } else {
+ if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) {
+ ResNrgPart = silk_int32_MAX;
+ } else {
+ ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] );
+ }
+ }
+ gain = psEncCtrl->Gains_Q16[ k ];
+ gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) );
+ if( gain_squared < silk_int16_MAX ) {
+ /* recalculate with higher precision */
+ gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain );
+ silk_assert( gain_squared > 0 );
+ gain = silk_SQRT_APPROX( gain_squared ); /* Q8 */
+ gain = silk_min( gain, silk_int32_MAX >> 8 );
+ psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 ); /* Q16 */
+ } else {
+ gain = silk_SQRT_APPROX( gain_squared ); /* Q0 */
+ gain = silk_min( gain, silk_int32_MAX >> 16 );
+ psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 16 ); /* Q16 */
+ }
+ }
+
+ /* Save unquantized gains and gain Index */
+ silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+ psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
+
+ /* Quantize gains */
+ silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16,
+ &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ if( psEncCtrl->LTPredCodGain_Q7 + silk_RSHIFT( psEnc->sCmn.input_tilt_Q15, 8 ) > SILK_FIX_CONST( 1.0, 7 ) ) {
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ } else {
+ psEnc->sCmn.indices.quantOffsetType = 1;
+ }
+ }
+
+ /* Quantizer boundary adjustment */
+ quant_offset_Q10 = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ];
+ psEncCtrl->Lambda_Q10 = SILK_FIX_CONST( LAMBDA_OFFSET, 10 )
+ + silk_SMULBB( SILK_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->sCmn.speech_activity_Q8 )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 );
+
+ silk_assert( psEncCtrl->Lambda_Q10 > 0 );
+ silk_assert( psEncCtrl->Lambda_Q10 < SILK_FIX_CONST( 2, 10 ) );
+}
diff --git a/external/opus-1.1.4/silk/fixed/regularize_correlations_FIX.c b/external/opus-1.1.4/silk/fixed/regularize_correlations_FIX.c
new file mode 100644
index 0000000..a2836b0
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/regularize_correlations_FIX.c
@@ -0,0 +1,47 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FIX(
+ opus_int32 *XX, /* I/O Correlation matrices */
+ opus_int32 *xx, /* I/O Correlation values */
+ opus_int32 noise, /* I Noise to add */
+ opus_int D /* I Dimension of XX */
+)
+{
+ opus_int i;
+ for( i = 0; i < D; i++ ) {
+ matrix_ptr( &XX[ 0 ], i, i, D ) = silk_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise );
+ }
+ xx[ 0 ] += noise;
+}
diff --git a/external/opus-1.1.4/silk/fixed/residual_energy16_FIX.c b/external/opus-1.1.4/silk/fixed/residual_energy16_FIX.c
new file mode 100644
index 0000000..ebffb2a
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/residual_energy16_FIX.c
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+opus_int32 silk_residual_energy16_covar_FIX(
+ const opus_int16 *c, /* I Prediction vector */
+ const opus_int32 *wXX, /* I Correlation matrix */
+ const opus_int32 *wXx, /* I Correlation vector */
+ opus_int32 wxx, /* I Signal energy */
+ opus_int D, /* I Dimension */
+ opus_int cQ /* I Q value for c vector 0 - 15 */
+)
+{
+ opus_int i, j, lshifts, Qxtra;
+ opus_int32 c_max, w_max, tmp, tmp2, nrg;
+ opus_int cn[ MAX_MATRIX_SIZE ];
+ const opus_int32 *pRow;
+
+ /* Safety checks */
+ silk_assert( D >= 0 );
+ silk_assert( D <= 16 );
+ silk_assert( cQ > 0 );
+ silk_assert( cQ < 16 );
+
+ lshifts = 16 - cQ;
+ Qxtra = lshifts;
+
+ c_max = 0;
+ for( i = 0; i < D; i++ ) {
+ c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) );
+ }
+ Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 );
+
+ w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] );
+ Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 );
+ Qxtra = silk_max_int( Qxtra, 0 );
+ for( i = 0; i < D; i++ ) {
+ cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra );
+ silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */
+ }
+ lshifts -= Qxtra;
+
+ /* Compute wxx - 2 * wXx * c */
+ tmp = 0;
+ for( i = 0; i < D; i++ ) {
+ tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] );
+ }
+ nrg = silk_RSHIFT( wxx, 1 + lshifts ) - tmp; /* Q: -lshifts - 1 */
+
+ /* Add c' * wXX * c, assuming wXX is symmetric */
+ tmp2 = 0;
+ for( i = 0; i < D; i++ ) {
+ tmp = 0;
+ pRow = &wXX[ i * D ];
+ for( j = i + 1; j < D; j++ ) {
+ tmp = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] );
+ }
+ tmp = silk_SMLAWB( tmp, silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] );
+ tmp2 = silk_SMLAWB( tmp2, tmp, cn[ i ] );
+ }
+ nrg = silk_ADD_LSHIFT32( nrg, tmp2, lshifts ); /* Q: -lshifts - 1 */
+
+ /* Keep one bit free always, because we add them for LSF interpolation */
+ if( nrg < 1 ) {
+ nrg = 1;
+ } else if( nrg > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) {
+ nrg = silk_int32_MAX >> 1;
+ } else {
+ nrg = silk_LSHIFT( nrg, lshifts + 1 ); /* Q0 */
+ }
+ return nrg;
+
+}
diff --git a/external/opus-1.1.4/silk/fixed/residual_energy_FIX.c b/external/opus-1.1.4/silk/fixed/residual_energy_FIX.c
new file mode 100644
index 0000000..105ae31
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/residual_energy_FIX.c
@@ -0,0 +1,97 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order */
+/* of preceding samples */
+void silk_residual_energy_FIX(
+ opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
+ opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */
+ const opus_int16 x[], /* I Input signal */
+ opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
+ const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int LPC_order /* I LPC order */
+)
+{
+ opus_int offset, i, j, rshift, lz1, lz2;
+ opus_int16 *LPC_res_ptr;
+ VARDECL( opus_int16, LPC_res );
+ const opus_int16 *x_ptr;
+ opus_int32 tmp32;
+ SAVE_STACK;
+
+ x_ptr = x;
+ offset = LPC_order + subfr_length;
+
+ /* Filter input to create the LPC residual for each frame half, and measure subframe energies */
+ ALLOC( LPC_res, ( MAX_NB_SUBFR >> 1 ) * offset, opus_int16 );
+ silk_assert( ( nb_subfr >> 1 ) * ( MAX_NB_SUBFR >> 1 ) == nb_subfr );
+ for( i = 0; i < nb_subfr >> 1; i++ ) {
+ /* Calculate half frame LPC residual signal including preceding samples */
+ silk_LPC_analysis_filter( LPC_res, x_ptr, a_Q12[ i ], ( MAX_NB_SUBFR >> 1 ) * offset, LPC_order );
+
+ /* Point to first subframe of the just calculated LPC residual signal */
+ LPC_res_ptr = LPC_res + LPC_order;
+ for( j = 0; j < ( MAX_NB_SUBFR >> 1 ); j++ ) {
+ /* Measure subframe energy */
+ silk_sum_sqr_shift( &nrgs[ i * ( MAX_NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length );
+
+ /* Set Q values for the measured energy */
+ nrgsQ[ i * ( MAX_NB_SUBFR >> 1 ) + j ] = -rshift;
+
+ /* Move to next subframe */
+ LPC_res_ptr += offset;
+ }
+ /* Move to next frame half */
+ x_ptr += ( MAX_NB_SUBFR >> 1 ) * offset;
+ }
+
+ /* Apply the squared subframe gains */
+ for( i = 0; i < nb_subfr; i++ ) {
+ /* Fully upscale gains and energies */
+ lz1 = silk_CLZ32( nrgs[ i ] ) - 1;
+ lz2 = silk_CLZ32( gains[ i ] ) - 1;
+
+ tmp32 = silk_LSHIFT32( gains[ i ], lz2 );
+
+ /* Find squared gains */
+ tmp32 = silk_SMMUL( tmp32, tmp32 ); /* Q( 2 * lz2 - 32 )*/
+
+ /* Scale energies */
+ nrgs[ i ] = silk_SMMUL( tmp32, silk_LSHIFT32( nrgs[ i ], lz1 ) ); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/
+ nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32;
+ }
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/fixed/schur64_FIX.c b/external/opus-1.1.4/silk/fixed/schur64_FIX.c
new file mode 100644
index 0000000..764a10e
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/schur64_FIX.c
@@ -0,0 +1,92 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Slower than schur(), but more accurate. */
+/* Uses SMULL(), available on armv4 */
+opus_int32 silk_schur64( /* O returns residual energy */
+ opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */
+ const opus_int32 c[], /* I Correlations [order+1] */
+ opus_int32 order /* I Prediction order */
+)
+{
+ opus_int k, n;
+ opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
+ opus_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31;
+
+ silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 );
+
+ /* Check for invalid input */
+ if( c[ 0 ] <= 0 ) {
+ silk_memset( rc_Q16, 0, order * sizeof( opus_int32 ) );
+ return 0;
+ }
+
+ for( k = 0; k < order + 1; k++ ) {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ];
+ }
+
+ for( k = 0; k < order; k++ ) {
+ /* Check that we won't be getting an unstable rc, otherwise stop here. */
+ if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) {
+ if ( C[ k + 1 ][ 0 ] > 0 ) {
+ rc_Q16[ k ] = -SILK_FIX_CONST( .99f, 16 );
+ } else {
+ rc_Q16[ k ] = SILK_FIX_CONST( .99f, 16 );
+ }
+ k++;
+ break;
+ }
+
+ /* Get reflection coefficient: divide two Q30 values and get result in Q31 */
+ rc_tmp_Q31 = silk_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 );
+
+ /* Save the output */
+ rc_Q16[ k ] = silk_RSHIFT_ROUND( rc_tmp_Q31, 15 );
+
+ /* Update correlations */
+ for( n = 0; n < order - k; n++ ) {
+ Ctmp1_Q30 = C[ n + k + 1 ][ 0 ];
+ Ctmp2_Q30 = C[ n ][ 1 ];
+
+ /* Multiply and add the highest int32 */
+ C[ n + k + 1 ][ 0 ] = Ctmp1_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 );
+ C[ n ][ 1 ] = Ctmp2_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 );
+ }
+ }
+
+ for(; k < order; k++ ) {
+ rc_Q16[ k ] = 0;
+ }
+
+ return silk_max_32( 1, C[ 0 ][ 1 ] );
+}
diff --git a/external/opus-1.1.4/silk/fixed/schur_FIX.c b/external/opus-1.1.4/silk/fixed/schur_FIX.c
new file mode 100644
index 0000000..c4c0ef2
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/schur_FIX.c
@@ -0,0 +1,106 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Faster than schur64(), but much less accurate. */
+/* uses SMLAWB(), requiring armv5E and higher. */
+opus_int32 silk_schur( /* O Returns residual energy */
+ opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */
+ const opus_int32 *c, /* I correlations [order+1] */
+ const opus_int32 order /* I prediction order */
+)
+{
+ opus_int k, n, lz;
+ opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
+ opus_int32 Ctmp1, Ctmp2, rc_tmp_Q15;
+
+ silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 );
+
+ /* Get number of leading zeros */
+ lz = silk_CLZ32( c[ 0 ] );
+
+ /* Copy correlations and adjust level to Q30 */
+ if( lz < 2 ) {
+ /* lz must be 1, so shift one to the right */
+ for( k = 0; k < order + 1; k++ ) {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = silk_RSHIFT( c[ k ], 1 );
+ }
+ } else if( lz > 2 ) {
+ /* Shift to the left */
+ lz -= 2;
+ for( k = 0; k < order + 1; k++ ) {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = silk_LSHIFT( c[ k ], lz );
+ }
+ } else {
+ /* No need to shift */
+ for( k = 0; k < order + 1; k++ ) {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ];
+ }
+ }
+
+ for( k = 0; k < order; k++ ) {
+ /* Check that we won't be getting an unstable rc, otherwise stop here. */
+ if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) {
+ if ( C[ k + 1 ][ 0 ] > 0 ) {
+ rc_Q15[ k ] = -SILK_FIX_CONST( .99f, 15 );
+ } else {
+ rc_Q15[ k ] = SILK_FIX_CONST( .99f, 15 );
+ }
+ k++;
+ break;
+ }
+
+ /* Get reflection coefficient */
+ rc_tmp_Q15 = -silk_DIV32_16( C[ k + 1 ][ 0 ], silk_max_32( silk_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) );
+
+ /* Clip (shouldn't happen for properly conditioned inputs) */
+ rc_tmp_Q15 = silk_SAT16( rc_tmp_Q15 );
+
+ /* Store */
+ rc_Q15[ k ] = (opus_int16)rc_tmp_Q15;
+
+ /* Update correlations */
+ for( n = 0; n < order - k; n++ ) {
+ Ctmp1 = C[ n + k + 1 ][ 0 ];
+ Ctmp2 = C[ n ][ 1 ];
+ C[ n + k + 1 ][ 0 ] = silk_SMLAWB( Ctmp1, silk_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 );
+ C[ n ][ 1 ] = silk_SMLAWB( Ctmp2, silk_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 );
+ }
+ }
+
+ for(; k < order; k++ ) {
+ rc_Q15[ k ] = 0;
+ }
+
+ /* return residual energy */
+ return silk_max_32( 1, C[ 0 ][ 1 ] );
+}
diff --git a/external/opus-1.1.4/silk/fixed/solve_LS_FIX.c b/external/opus-1.1.4/silk/fixed/solve_LS_FIX.c
new file mode 100644
index 0000000..51d7d49
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/solve_LS_FIX.c
@@ -0,0 +1,249 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/*****************************/
+/* Internal function headers */
+/*****************************/
+
+typedef struct {
+ opus_int32 Q36_part;
+ opus_int32 Q48_part;
+} inv_D_t;
+
+/* Factorize square matrix A into LDL form */
+static OPUS_INLINE void silk_LDL_factorize_FIX(
+ opus_int32 *A, /* I/O Pointer to Symetric Square Matrix */
+ opus_int M, /* I Size of Matrix */
+ opus_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */
+ inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */
+);
+
+/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveFirst_FIX(
+ const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const opus_int32 *b, /* I b Vector */
+ opus_int32 *x_Q16 /* O x Vector */
+);
+
+/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveLast_FIX(
+ const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */
+ const opus_int M, /* I Dim of Matrix equation */
+ const opus_int32 *b, /* I b Vector */
+ opus_int32 *x_Q16 /* O x Vector */
+);
+
+static OPUS_INLINE void silk_LS_divide_Q16_FIX(
+ opus_int32 T[], /* I/O Numenator vector */
+ inv_D_t *inv_D, /* I 1 / D vector */
+ opus_int M /* I dimension */
+);
+
+/* Solves Ax = b, assuming A is symmetric */
+void silk_solve_LDL_FIX(
+ opus_int32 *A, /* I Pointer to symetric square matrix A */
+ opus_int M, /* I Size of matrix */
+ const opus_int32 *b, /* I Pointer to b vector */
+ opus_int32 *x_Q16 /* O Pointer to x solution vector */
+)
+{
+ VARDECL( opus_int32, L_Q16 );
+ opus_int32 Y[ MAX_MATRIX_SIZE ];
+ inv_D_t inv_D[ MAX_MATRIX_SIZE ];
+ SAVE_STACK;
+
+ silk_assert( M <= MAX_MATRIX_SIZE );
+ ALLOC( L_Q16, M * M, opus_int32 );
+
+ /***************************************************
+ Factorize A by LDL such that A = L*D*L',
+ where L is lower triangular with ones on diagonal
+ ****************************************************/
+ silk_LDL_factorize_FIX( A, M, L_Q16, inv_D );
+
+ /****************************************************
+ * substitute D*L'*x = Y. ie:
+ L*D*L'*x = b => L*Y = b <=> Y = inv(L)*b
+ ******************************************************/
+ silk_LS_SolveFirst_FIX( L_Q16, M, b, Y );
+
+ /****************************************************
+ D*L'*x = Y <=> L'*x = inv(D)*Y, because D is
+ diagonal just multiply with 1/d_i
+ ****************************************************/
+ silk_LS_divide_Q16_FIX( Y, inv_D, M );
+
+ /****************************************************
+ x = inv(L') * inv(D) * Y
+ *****************************************************/
+ silk_LS_SolveLast_FIX( L_Q16, M, Y, x_Q16 );
+ RESTORE_STACK;
+}
+
+static OPUS_INLINE void silk_LDL_factorize_FIX(
+ opus_int32 *A, /* I/O Pointer to Symetric Square Matrix */
+ opus_int M, /* I Size of Matrix */
+ opus_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */
+ inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */
+)
+{
+ opus_int i, j, k, status, loop_count;
+ const opus_int32 *ptr1, *ptr2;
+ opus_int32 diag_min_value, tmp_32, err;
+ opus_int32 v_Q0[ MAX_MATRIX_SIZE ], D_Q0[ MAX_MATRIX_SIZE ];
+ opus_int32 one_div_diag_Q36, one_div_diag_Q40, one_div_diag_Q48;
+
+ silk_assert( M <= MAX_MATRIX_SIZE );
+
+ status = 1;
+ diag_min_value = silk_max_32( silk_SMMUL( silk_ADD_SAT32( A[ 0 ], A[ silk_SMULBB( M, M ) - 1 ] ), SILK_FIX_CONST( FIND_LTP_COND_FAC, 31 ) ), 1 << 9 );
+ for( loop_count = 0; loop_count < M && status == 1; loop_count++ ) {
+ status = 0;
+ for( j = 0; j < M; j++ ) {
+ ptr1 = matrix_adr( L_Q16, j, 0, M );
+ tmp_32 = 0;
+ for( i = 0; i < j; i++ ) {
+ v_Q0[ i ] = silk_SMULWW( D_Q0[ i ], ptr1[ i ] ); /* Q0 */
+ tmp_32 = silk_SMLAWW( tmp_32, v_Q0[ i ], ptr1[ i ] ); /* Q0 */
+ }
+ tmp_32 = silk_SUB32( matrix_ptr( A, j, j, M ), tmp_32 );
+
+ if( tmp_32 < diag_min_value ) {
+ tmp_32 = silk_SUB32( silk_SMULBB( loop_count + 1, diag_min_value ), tmp_32 );
+ /* Matrix not positive semi-definite, or ill conditioned */
+ for( i = 0; i < M; i++ ) {
+ matrix_ptr( A, i, i, M ) = silk_ADD32( matrix_ptr( A, i, i, M ), tmp_32 );
+ }
+ status = 1;
+ break;
+ }
+ D_Q0[ j ] = tmp_32; /* always < max(Correlation) */
+
+ /* two-step division */
+ one_div_diag_Q36 = silk_INVERSE32_varQ( tmp_32, 36 ); /* Q36 */
+ one_div_diag_Q40 = silk_LSHIFT( one_div_diag_Q36, 4 ); /* Q40 */
+ err = silk_SUB32( (opus_int32)1 << 24, silk_SMULWW( tmp_32, one_div_diag_Q40 ) ); /* Q24 */
+ one_div_diag_Q48 = silk_SMULWW( err, one_div_diag_Q40 ); /* Q48 */
+
+ /* Save 1/Ds */
+ inv_D[ j ].Q36_part = one_div_diag_Q36;
+ inv_D[ j ].Q48_part = one_div_diag_Q48;
+
+ matrix_ptr( L_Q16, j, j, M ) = 65536; /* 1.0 in Q16 */
+ ptr1 = matrix_adr( A, j, 0, M );
+ ptr2 = matrix_adr( L_Q16, j + 1, 0, M );
+ for( i = j + 1; i < M; i++ ) {
+ tmp_32 = 0;
+ for( k = 0; k < j; k++ ) {
+ tmp_32 = silk_SMLAWW( tmp_32, v_Q0[ k ], ptr2[ k ] ); /* Q0 */
+ }
+ tmp_32 = silk_SUB32( ptr1[ i ], tmp_32 ); /* always < max(Correlation) */
+
+ /* tmp_32 / D_Q0[j] : Divide to Q16 */
+ matrix_ptr( L_Q16, i, j, M ) = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ),
+ silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) );
+
+ /* go to next column */
+ ptr2 += M;
+ }
+ }
+ }
+
+ silk_assert( status == 0 );
+}
+
+static OPUS_INLINE void silk_LS_divide_Q16_FIX(
+ opus_int32 T[], /* I/O Numenator vector */
+ inv_D_t *inv_D, /* I 1 / D vector */
+ opus_int M /* I dimension */
+)
+{
+ opus_int i;
+ opus_int32 tmp_32;
+ opus_int32 one_div_diag_Q36, one_div_diag_Q48;
+
+ for( i = 0; i < M; i++ ) {
+ one_div_diag_Q36 = inv_D[ i ].Q36_part;
+ one_div_diag_Q48 = inv_D[ i ].Q48_part;
+
+ tmp_32 = T[ i ];
+ T[ i ] = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ), silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) );
+ }
+}
+
+/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveFirst_FIX(
+ const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const opus_int32 *b, /* I b Vector */
+ opus_int32 *x_Q16 /* O x Vector */
+)
+{
+ opus_int i, j;
+ const opus_int32 *ptr32;
+ opus_int32 tmp_32;
+
+ for( i = 0; i < M; i++ ) {
+ ptr32 = matrix_adr( L_Q16, i, 0, M );
+ tmp_32 = 0;
+ for( j = 0; j < i; j++ ) {
+ tmp_32 = silk_SMLAWW( tmp_32, ptr32[ j ], x_Q16[ j ] );
+ }
+ x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 );
+ }
+}
+
+/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveLast_FIX(
+ const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */
+ const opus_int M, /* I Dim of Matrix equation */
+ const opus_int32 *b, /* I b Vector */
+ opus_int32 *x_Q16 /* O x Vector */
+)
+{
+ opus_int i, j;
+ const opus_int32 *ptr32;
+ opus_int32 tmp_32;
+
+ for( i = M - 1; i >= 0; i-- ) {
+ ptr32 = matrix_adr( L_Q16, 0, i, M );
+ tmp_32 = 0;
+ for( j = M - 1; j > i; j-- ) {
+ tmp_32 = silk_SMLAWW( tmp_32, ptr32[ silk_SMULBB( j, M ) ], x_Q16[ j ] );
+ }
+ x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 );
+ }
+}
diff --git a/external/opus-1.1.4/silk/fixed/structs_FIX.h b/external/opus-1.1.4/silk/fixed/structs_FIX.h
new file mode 100644
index 0000000..244b479
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/structs_FIX.h
@@ -0,0 +1,133 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_STRUCTS_FIX_H
+#define SILK_STRUCTS_FIX_H
+
+#include "typedef.h"
+#include "main.h"
+#include "structs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/********************************/
+/* Noise shaping analysis state */
+/********************************/
+typedef struct {
+ opus_int8 LastGainIndex;
+ opus_int32 HarmBoost_smth_Q16;
+ opus_int32 HarmShapeGain_smth_Q16;
+ opus_int32 Tilt_smth_Q16;
+} silk_shape_state_FIX;
+
+/********************************/
+/* Prefilter state */
+/********************************/
+typedef struct {
+ opus_int16 sLTP_shp[ LTP_BUF_LENGTH ];
+ opus_int32 sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ];
+ opus_int sLTP_shp_buf_idx;
+ opus_int32 sLF_AR_shp_Q12;
+ opus_int32 sLF_MA_shp_Q12;
+ opus_int32 sHarmHP_Q2;
+ opus_int32 rand_seed;
+ opus_int lagPrev;
+} silk_prefilter_state_FIX;
+
+/********************************/
+/* Encoder state FIX */
+/********************************/
+typedef struct {
+ silk_encoder_state sCmn; /* Common struct, shared with floating-point code */
+ silk_shape_state_FIX sShape; /* Shape state */
+ silk_prefilter_state_FIX sPrefilt; /* Prefilter State */
+
+ /* Buffer for find pitch and noise shape analysis */
+ silk_DWORD_ALIGN opus_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */
+ opus_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator */
+} silk_encoder_state_FIX;
+
+/************************/
+/* Encoder control FIX */
+/************************/
+typedef struct {
+ /* Prediction and coding parameters */
+ opus_int32 Gains_Q16[ MAX_NB_SUBFR ];
+ silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+ opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ];
+ opus_int LTP_scale_Q14;
+ opus_int pitchL[ MAX_NB_SUBFR ];
+
+ /* Noise shaping parameters */
+ /* Testing */
+ silk_DWORD_ALIGN opus_int16 AR1_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ silk_DWORD_ALIGN opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */
+ opus_int GainsPre_Q14[ MAX_NB_SUBFR ];
+ opus_int HarmBoost_Q14[ MAX_NB_SUBFR ];
+ opus_int Tilt_Q14[ MAX_NB_SUBFR ];
+ opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ];
+ opus_int Lambda_Q10;
+ opus_int input_quality_Q14;
+ opus_int coding_quality_Q14;
+
+ /* measures */
+ opus_int sparseness_Q8;
+ opus_int32 predGain_Q16;
+ opus_int LTPredCodGain_Q7;
+ opus_int32 ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */
+ opus_int ResNrgQ[ MAX_NB_SUBFR ]; /* Q domain for the residual energy > 0 */
+
+ /* Parameters for CBR mode */
+ opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ];
+ opus_int8 lastGainIndexPrev;
+} silk_encoder_control_FIX;
+
+/************************/
+/* Encoder Super Struct */
+/************************/
+typedef struct {
+ silk_encoder_state_FIX state_Fxx[ ENCODER_NUM_CHANNELS ];
+ stereo_enc_state sStereo;
+ opus_int32 nBitsExceeded;
+ opus_int nChannelsAPI;
+ opus_int nChannelsInternal;
+ opus_int nPrevChannelsInternal;
+ opus_int timeSinceSwitchAllowed_ms;
+ opus_int allowBandwidthSwitch;
+ opus_int prev_decode_only_middle;
+} silk_encoder;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/silk/fixed/vector_ops_FIX.c b/external/opus-1.1.4/silk/fixed/vector_ops_FIX.c
new file mode 100644
index 0000000..509c8b3
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/vector_ops_FIX.c
@@ -0,0 +1,96 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Copy and multiply a vector by a constant */
+void silk_scale_copy_vector16(
+ opus_int16 *data_out,
+ const opus_int16 *data_in,
+ opus_int32 gain_Q16, /* I Gain in Q16 */
+ const opus_int dataSize /* I Length */
+)
+{
+ opus_int i;
+ opus_int32 tmp32;
+
+ for( i = 0; i < dataSize; i++ ) {
+ tmp32 = silk_SMULWB( gain_Q16, data_in[ i ] );
+ data_out[ i ] = (opus_int16)silk_CHECK_FIT16( tmp32 );
+ }
+}
+
+/* Multiply a vector by a constant */
+void silk_scale_vector32_Q26_lshift_18(
+ opus_int32 *data1, /* I/O Q0/Q18 */
+ opus_int32 gain_Q26, /* I Q26 */
+ opus_int dataSize /* I length */
+)
+{
+ opus_int i;
+
+ for( i = 0; i < dataSize; i++ ) {
+ data1[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_SMULL( data1[ i ], gain_Q26 ), 8 ) ); /* OUTPUT: Q18 */
+ }
+}
+
+/* sum = for(i=0;i<len;i++)inVec1[i]*inVec2[i]; --- inner product */
+/* Note for ARM asm: */
+/* * inVec1 and inVec2 should be at least 2 byte aligned. */
+/* * len should be positive 16bit integer. */
+/* * only when len>6, memory access can be reduced by half. */
+opus_int32 silk_inner_prod_aligned(
+ const opus_int16 *const inVec1, /* I input vector 1 */
+ const opus_int16 *const inVec2, /* I input vector 2 */
+ const opus_int len /* I vector lengths */
+)
+{
+ opus_int i;
+ opus_int32 sum = 0;
+ for( i = 0; i < len; i++ ) {
+ sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] );
+ }
+ return sum;
+}
+
+opus_int64 silk_inner_prod16_aligned_64(
+ const opus_int16 *inVec1, /* I input vector 1 */
+ const opus_int16 *inVec2, /* I input vector 2 */
+ const opus_int len /* I vector lengths */
+)
+{
+ opus_int i;
+ opus_int64 sum = 0;
+ for( i = 0; i < len; i++ ) {
+ sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] );
+ }
+ return sum;
+}
diff --git a/external/opus-1.1.4/silk/fixed/warped_autocorrelation_FIX.c b/external/opus-1.1.4/silk/fixed/warped_autocorrelation_FIX.c
new file mode 100644
index 0000000..a4a579b
--- /dev/null
+++ b/external/opus-1.1.4/silk/fixed/warped_autocorrelation_FIX.c
@@ -0,0 +1,88 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+#define QC 10
+#define QS 14
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FIX(
+ opus_int32 *corr, /* O Result [order + 1] */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *input, /* I Input data to correlate */
+ const opus_int warping_Q16, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+)
+{
+ opus_int n, i, lsh;
+ opus_int32 tmp1_QS, tmp2_QS;
+ opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+ opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+
+ /* Order must be even */
+ silk_assert( ( order & 1 ) == 0 );
+ silk_assert( 2 * QS - QC >= 0 );
+
+ /* Loop over samples */
+ for( n = 0; n < length; n++ ) {
+ tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS );
+ /* Loop over allpass sections */
+ for( i = 0; i < order; i += 2 ) {
+ /* Output of allpass section */
+ tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 );
+ state_QS[ i ] = tmp1_QS;
+ corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC );
+ /* Output of allpass section */
+ tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 );
+ state_QS[ i + 1 ] = tmp2_QS;
+ corr_QC[ i + 1 ] += silk_RSHIFT64( silk_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC );
+ }
+ state_QS[ order ] = tmp1_QS;
+ corr_QC[ order ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC );
+ }
+
+ lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35;
+ lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC );
+ *scale = -( QC + lsh );
+ silk_assert( *scale >= -30 && *scale <= 12 );
+ if( lsh >= 0 ) {
+ for( i = 0; i < order + 1; i++ ) {
+ corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QC[ i ], lsh ) );
+ }
+ } else {
+ for( i = 0; i < order + 1; i++ ) {
+ corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QC[ i ], -lsh ) );
+ }
+ }
+ silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/
+}
diff --git a/external/opus-1.1.4/silk/float/CMakeLists.txt b/external/opus-1.1.4/silk/float/CMakeLists.txt
new file mode 100644
index 0000000..a6e644a
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/CMakeLists.txt
@@ -0,0 +1,48 @@
+# CMakeLists.txt in silk/float
+
+SET(SILK_FLOAT_SRCS
+ apply_sine_window_FLP.c
+ autocorrelation_FLP.c
+ burg_modified_FLP.c
+ bwexpander_FLP.c
+ corrMatrix_FLP.c
+ encode_frame_FLP.c
+ energy_FLP.c
+ find_LPC_FLP.c
+ find_LTP_FLP.c
+ find_pitch_lags_FLP.c
+ find_pred_coefs_FLP.c
+ inner_product_FLP.c
+ k2a_FLP.c
+ levinsondurbin_FLP.c
+ LPC_analysis_filter_FLP.c
+ LPC_inv_pred_gain_FLP.c
+ LTP_analysis_filter_FLP.c
+ LTP_scale_ctrl_FLP.c
+ noise_shape_analysis_FLP.c
+ pitch_analysis_core_FLP.c
+ prefilter_FLP.c
+ process_gains_FLP.c
+ regularize_correlations_FLP.c
+ residual_energy_FLP.c
+ scale_copy_vector_FLP.c
+ scale_vector_FLP.c
+ schur_FLP.c
+ solve_LS_FLP.c
+ sort_FLP.c
+ warped_autocorrelation_FLP.c
+ wrappers_FLP.c
+ )
+
+SET(SILK_FLOAT_HEADERS
+ main_FLP.h
+ SigProc_FLP.h
+ structs_FLP.h
+ )
+
+INCLUDE_DIRECTORIES(
+ ${OPUS_INCLUDES_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../celt
+ )
+
diff --git a/external/opus-1.1.4/silk/float/LPC_analysis_filter_FLP.c b/external/opus-1.1.4/silk/float/LPC_analysis_filter_FLP.c
new file mode 100644
index 0000000..cae89a0
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/LPC_analysis_filter_FLP.c
@@ -0,0 +1,249 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include "main_FLP.h"
+
+/************************************************/
+/* LPC analysis filter */
+/* NB! State is kept internally and the */
+/* filter always starts with zero state */
+/* first Order output samples are set to zero */
+/************************************************/
+
+/* 16th order LPC analysis filter, does not write first 16 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter16_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length /* I Length of input signal */
+)
+{
+ opus_int ix;
+ silk_float LPC_pred;
+ const silk_float *s_ptr;
+
+ for( ix = 16; ix < length; ix++ ) {
+ s_ptr = &s[ix - 1];
+
+ /* short-term prediction */
+ LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
+ s_ptr[ -1 ] * PredCoef[ 1 ] +
+ s_ptr[ -2 ] * PredCoef[ 2 ] +
+ s_ptr[ -3 ] * PredCoef[ 3 ] +
+ s_ptr[ -4 ] * PredCoef[ 4 ] +
+ s_ptr[ -5 ] * PredCoef[ 5 ] +
+ s_ptr[ -6 ] * PredCoef[ 6 ] +
+ s_ptr[ -7 ] * PredCoef[ 7 ] +
+ s_ptr[ -8 ] * PredCoef[ 8 ] +
+ s_ptr[ -9 ] * PredCoef[ 9 ] +
+ s_ptr[ -10 ] * PredCoef[ 10 ] +
+ s_ptr[ -11 ] * PredCoef[ 11 ] +
+ s_ptr[ -12 ] * PredCoef[ 12 ] +
+ s_ptr[ -13 ] * PredCoef[ 13 ] +
+ s_ptr[ -14 ] * PredCoef[ 14 ] +
+ s_ptr[ -15 ] * PredCoef[ 15 ];
+
+ /* prediction error */
+ r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+ }
+}
+
+/* 12th order LPC analysis filter, does not write first 12 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter12_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length /* I Length of input signal */
+)
+{
+ opus_int ix;
+ silk_float LPC_pred;
+ const silk_float *s_ptr;
+
+ for( ix = 12; ix < length; ix++ ) {
+ s_ptr = &s[ix - 1];
+
+ /* short-term prediction */
+ LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
+ s_ptr[ -1 ] * PredCoef[ 1 ] +
+ s_ptr[ -2 ] * PredCoef[ 2 ] +
+ s_ptr[ -3 ] * PredCoef[ 3 ] +
+ s_ptr[ -4 ] * PredCoef[ 4 ] +
+ s_ptr[ -5 ] * PredCoef[ 5 ] +
+ s_ptr[ -6 ] * PredCoef[ 6 ] +
+ s_ptr[ -7 ] * PredCoef[ 7 ] +
+ s_ptr[ -8 ] * PredCoef[ 8 ] +
+ s_ptr[ -9 ] * PredCoef[ 9 ] +
+ s_ptr[ -10 ] * PredCoef[ 10 ] +
+ s_ptr[ -11 ] * PredCoef[ 11 ];
+
+ /* prediction error */
+ r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+ }
+}
+
+/* 10th order LPC analysis filter, does not write first 10 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter10_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length /* I Length of input signal */
+)
+{
+ opus_int ix;
+ silk_float LPC_pred;
+ const silk_float *s_ptr;
+
+ for( ix = 10; ix < length; ix++ ) {
+ s_ptr = &s[ix - 1];
+
+ /* short-term prediction */
+ LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
+ s_ptr[ -1 ] * PredCoef[ 1 ] +
+ s_ptr[ -2 ] * PredCoef[ 2 ] +
+ s_ptr[ -3 ] * PredCoef[ 3 ] +
+ s_ptr[ -4 ] * PredCoef[ 4 ] +
+ s_ptr[ -5 ] * PredCoef[ 5 ] +
+ s_ptr[ -6 ] * PredCoef[ 6 ] +
+ s_ptr[ -7 ] * PredCoef[ 7 ] +
+ s_ptr[ -8 ] * PredCoef[ 8 ] +
+ s_ptr[ -9 ] * PredCoef[ 9 ];
+
+ /* prediction error */
+ r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+ }
+}
+
+/* 8th order LPC analysis filter, does not write first 8 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter8_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length /* I Length of input signal */
+)
+{
+ opus_int ix;
+ silk_float LPC_pred;
+ const silk_float *s_ptr;
+
+ for( ix = 8; ix < length; ix++ ) {
+ s_ptr = &s[ix - 1];
+
+ /* short-term prediction */
+ LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
+ s_ptr[ -1 ] * PredCoef[ 1 ] +
+ s_ptr[ -2 ] * PredCoef[ 2 ] +
+ s_ptr[ -3 ] * PredCoef[ 3 ] +
+ s_ptr[ -4 ] * PredCoef[ 4 ] +
+ s_ptr[ -5 ] * PredCoef[ 5 ] +
+ s_ptr[ -6 ] * PredCoef[ 6 ] +
+ s_ptr[ -7 ] * PredCoef[ 7 ];
+
+ /* prediction error */
+ r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+ }
+}
+
+/* 6th order LPC analysis filter, does not write first 6 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter6_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length /* I Length of input signal */
+)
+{
+ opus_int ix;
+ silk_float LPC_pred;
+ const silk_float *s_ptr;
+
+ for( ix = 6; ix < length; ix++ ) {
+ s_ptr = &s[ix - 1];
+
+ /* short-term prediction */
+ LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
+ s_ptr[ -1 ] * PredCoef[ 1 ] +
+ s_ptr[ -2 ] * PredCoef[ 2 ] +
+ s_ptr[ -3 ] * PredCoef[ 3 ] +
+ s_ptr[ -4 ] * PredCoef[ 4 ] +
+ s_ptr[ -5 ] * PredCoef[ 5 ];
+
+ /* prediction error */
+ r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+ }
+}
+
+/************************************************/
+/* LPC analysis filter */
+/* NB! State is kept internally and the */
+/* filter always starts with zero state */
+/* first Order output samples are set to zero */
+/************************************************/
+void silk_LPC_analysis_filter_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length, /* I Length of input signal */
+ const opus_int Order /* I LPC order */
+)
+{
+ silk_assert( Order <= length );
+
+ switch( Order ) {
+ case 6:
+ silk_LPC_analysis_filter6_FLP( r_LPC, PredCoef, s, length );
+ break;
+
+ case 8:
+ silk_LPC_analysis_filter8_FLP( r_LPC, PredCoef, s, length );
+ break;
+
+ case 10:
+ silk_LPC_analysis_filter10_FLP( r_LPC, PredCoef, s, length );
+ break;
+
+ case 12:
+ silk_LPC_analysis_filter12_FLP( r_LPC, PredCoef, s, length );
+ break;
+
+ case 16:
+ silk_LPC_analysis_filter16_FLP( r_LPC, PredCoef, s, length );
+ break;
+
+ default:
+ silk_assert( 0 );
+ break;
+ }
+
+ /* Set first Order output samples to zero */
+ silk_memset( r_LPC, 0, Order * sizeof( silk_float ) );
+}
+
diff --git a/external/opus-1.1.4/silk/float/LPC_inv_pred_gain_FLP.c b/external/opus-1.1.4/silk/float/LPC_inv_pred_gain_FLP.c
new file mode 100644
index 0000000..25178ba
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/LPC_inv_pred_gain_FLP.c
@@ -0,0 +1,76 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "SigProc_FLP.h"
+
+#define RC_THRESHOLD 0.9999f
+
+/* compute inverse of LPC prediction gain, and */
+/* test if LPC coefficients are stable (all poles within unit circle) */
+/* this code is based on silk_a2k_FLP() */
+silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */
+ const silk_float *A, /* I prediction coefficients [order] */
+ opus_int32 order /* I prediction order */
+)
+{
+ opus_int k, n;
+ double invGain, rc, rc_mult1, rc_mult2;
+ silk_float Atmp[ 2 ][ SILK_MAX_ORDER_LPC ];
+ silk_float *Aold, *Anew;
+
+ Anew = Atmp[ order & 1 ];
+ silk_memcpy( Anew, A, order * sizeof(silk_float) );
+
+ invGain = 1.0;
+ for( k = order - 1; k > 0; k-- ) {
+ rc = -Anew[ k ];
+ if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) {
+ return 0.0f;
+ }
+ rc_mult1 = 1.0f - rc * rc;
+ rc_mult2 = 1.0f / rc_mult1;
+ invGain *= rc_mult1;
+ /* swap pointers */
+ Aold = Anew;
+ Anew = Atmp[ k & 1 ];
+ for( n = 0; n < k; n++ ) {
+ Anew[ n ] = (silk_float)( ( Aold[ n ] - Aold[ k - n - 1 ] * rc ) * rc_mult2 );
+ }
+ }
+ rc = -Anew[ 0 ];
+ if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) {
+ return 0.0f;
+ }
+ rc_mult1 = 1.0f - rc * rc;
+ invGain *= rc_mult1;
+ return (silk_float)invGain;
+}
diff --git a/external/opus-1.1.4/silk/float/LTP_analysis_filter_FLP.c b/external/opus-1.1.4/silk/float/LTP_analysis_filter_FLP.c
new file mode 100644
index 0000000..849b7c1
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/LTP_analysis_filter_FLP.c
@@ -0,0 +1,75 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+void silk_LTP_analysis_filter_FLP(
+ silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */
+ const silk_float *x, /* I Input signal, with preceding samples */
+ const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */
+ const opus_int subfr_length, /* I Length of each subframe */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int pre_length /* I Preceding samples for each subframe */
+)
+{
+ const silk_float *x_ptr, *x_lag_ptr;
+ silk_float Btmp[ LTP_ORDER ];
+ silk_float *LTP_res_ptr;
+ silk_float inv_gain;
+ opus_int k, i, j;
+
+ x_ptr = x;
+ LTP_res_ptr = LTP_res;
+ for( k = 0; k < nb_subfr; k++ ) {
+ x_lag_ptr = x_ptr - pitchL[ k ];
+ inv_gain = invGains[ k ];
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ Btmp[ i ] = B[ k * LTP_ORDER + i ];
+ }
+
+ /* LTP analysis FIR filter */
+ for( i = 0; i < subfr_length + pre_length; i++ ) {
+ LTP_res_ptr[ i ] = x_ptr[ i ];
+ /* Subtract long-term prediction */
+ for( j = 0; j < LTP_ORDER; j++ ) {
+ LTP_res_ptr[ i ] -= Btmp[ j ] * x_lag_ptr[ LTP_ORDER / 2 - j ];
+ }
+ LTP_res_ptr[ i ] *= inv_gain;
+ x_lag_ptr++;
+ }
+
+ /* Update pointers */
+ LTP_res_ptr += subfr_length + pre_length;
+ x_ptr += subfr_length;
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/LTP_scale_ctrl_FLP.c b/external/opus-1.1.4/silk/float/LTP_scale_ctrl_FLP.c
new file mode 100644
index 0000000..8dbe29d
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/LTP_scale_ctrl_FLP.c
@@ -0,0 +1,52 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+void silk_LTP_scale_ctrl_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int round_loss;
+
+ if( condCoding == CODE_INDEPENDENTLY ) {
+ /* Only scale if first frame in packet */
+ round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket;
+ psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( round_loss * psEncCtrl->LTPredCodGain * 0.1f, 0.0f, 2.0f );
+ } else {
+ /* Default is minimum scaling */
+ psEnc->sCmn.indices.LTP_scaleIndex = 0;
+ }
+
+ psEncCtrl->LTP_scale = (silk_float)silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ] / 16384.0f;
+}
diff --git a/external/opus-1.1.4/silk/float/SigProc_FLP.h b/external/opus-1.1.4/silk/float/SigProc_FLP.h
new file mode 100644
index 0000000..f0cb373
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/SigProc_FLP.h
@@ -0,0 +1,204 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FLP_H
+#define SILK_SIGPROC_FLP_H
+
+#include "SigProc_FIX.h"
+#include "float_cast.h"
+#include <math.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/********************************************************************/
+/* SIGNAL PROCESSING FUNCTIONS */
+/********************************************************************/
+
+/* Chirp (bw expand) LP AR filter */
+void silk_bwexpander_FLP(
+ silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I length of ar */
+ const silk_float chirp /* I chirp factor (typically in range (0..1) ) */
+);
+
+/* compute inverse of LPC prediction gain, and */
+/* test if LPC coefficients are stable (all poles within unit circle) */
+/* this code is based on silk_FLP_a2k() */
+silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */
+ const silk_float *A, /* I prediction coefficients [order] */
+ opus_int32 order /* I prediction order */
+);
+
+silk_float silk_schur_FLP( /* O returns residual energy */
+ silk_float refl_coef[], /* O reflection coefficients (length order) */
+ const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */
+ opus_int order /* I order */
+);
+
+void silk_k2a_FLP(
+ silk_float *A, /* O prediction coefficients [order] */
+ const silk_float *rc, /* I reflection coefficients [order] */
+ opus_int32 order /* I prediction order */
+);
+
+/* Solve the normal equations using the Levinson-Durbin recursion */
+silk_float silk_levinsondurbin_FLP( /* O prediction error energy */
+ silk_float A[], /* O prediction coefficients [order] */
+ const silk_float corr[], /* I input auto-correlations [order + 1] */
+ const opus_int order /* I prediction order */
+);
+
+/* compute autocorrelation */
+void silk_autocorrelation_FLP(
+ silk_float *results, /* O result (length correlationCount) */
+ const silk_float *inputData, /* I input data to correlate */
+ opus_int inputDataSize, /* I length of input */
+ opus_int correlationCount /* I number of correlation taps to compute */
+);
+
+opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */
+ const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
+ opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */
+ opus_int16 *lagIndex, /* O Lag Index */
+ opus_int8 *contourIndex, /* O Pitch contour Index */
+ silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */
+ opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
+ const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */
+ const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */
+ const opus_int Fs_kHz, /* I sample frequency (kHz) */
+ const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
+ const opus_int nb_subfr, /* I Number of 5 ms subframes */
+ int arch /* I Run-time architecture */
+);
+
+void silk_insertion_sort_decreasing_FLP(
+ silk_float *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+);
+
+/* Compute reflection coefficients from input signal */
+silk_float silk_burg_modified_FLP( /* O returns residual energy */
+ silk_float A[], /* O prediction coefficients (length order) */
+ const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */
+ const silk_float minInvGain, /* I minimum inverse prediction gain */
+ const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I number of subframes stacked in x */
+ const opus_int D /* I order */
+);
+
+/* multiply a vector by a constant */
+void silk_scale_vector_FLP(
+ silk_float *data1,
+ silk_float gain,
+ opus_int dataSize
+);
+
+/* copy and multiply a vector by a constant */
+void silk_scale_copy_vector_FLP(
+ silk_float *data_out,
+ const silk_float *data_in,
+ silk_float gain,
+ opus_int dataSize
+);
+
+/* inner product of two silk_float arrays, with result as double */
+double silk_inner_product_FLP(
+ const silk_float *data1,
+ const silk_float *data2,
+ opus_int dataSize
+);
+
+/* sum of squares of a silk_float array, with result as double */
+double silk_energy_FLP(
+ const silk_float *data,
+ opus_int dataSize
+);
+
+/********************************************************************/
+/* MACROS */
+/********************************************************************/
+
+#define PI (3.1415926536f)
+
+#define silk_min_float( a, b ) (((a) < (b)) ? (a) : (b))
+#define silk_max_float( a, b ) (((a) > (b)) ? (a) : (b))
+#define silk_abs_float( a ) ((silk_float)fabs(a))
+
+/* sigmoid function */
+static OPUS_INLINE silk_float silk_sigmoid( silk_float x )
+{
+ return (silk_float)(1.0 / (1.0 + exp(-x)));
+}
+
+/* floating-point to integer conversion (rounding) */
+static OPUS_INLINE opus_int32 silk_float2int( silk_float x )
+{
+ return (opus_int32)float2int( x );
+}
+
+/* floating-point to integer conversion (rounding) */
+static OPUS_INLINE void silk_float2short_array(
+ opus_int16 *out,
+ const silk_float *in,
+ opus_int32 length
+)
+{
+ opus_int32 k;
+ for( k = length - 1; k >= 0; k-- ) {
+ out[k] = silk_SAT16( (opus_int32)float2int( in[k] ) );
+ }
+}
+
+/* integer to floating-point conversion */
+static OPUS_INLINE void silk_short2float_array(
+ silk_float *out,
+ const opus_int16 *in,
+ opus_int32 length
+)
+{
+ opus_int32 k;
+ for( k = length - 1; k >= 0; k-- ) {
+ out[k] = (silk_float)in[k];
+ }
+}
+
+/* using log2() helps the fixed-point conversion */
+static OPUS_INLINE silk_float silk_log2( double x )
+{
+ return ( silk_float )( 3.32192809488736 * log10( x ) );
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_SIGPROC_FLP_H */
diff --git a/external/opus-1.1.4/silk/float/apply_sine_window_FLP.c b/external/opus-1.1.4/silk/float/apply_sine_window_FLP.c
new file mode 100644
index 0000000..6aae57c
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/apply_sine_window_FLP.c
@@ -0,0 +1,81 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+/* Apply sine window to signal vector */
+/* Window types: */
+/* 1 -> sine window from 0 to pi/2 */
+/* 2 -> sine window from pi/2 to pi */
+void silk_apply_sine_window_FLP(
+ silk_float px_win[], /* O Pointer to windowed signal */
+ const silk_float px[], /* I Pointer to input signal */
+ const opus_int win_type, /* I Selects a window type */
+ const opus_int length /* I Window length, multiple of 4 */
+)
+{
+ opus_int k;
+ silk_float freq, c, S0, S1;
+
+ silk_assert( win_type == 1 || win_type == 2 );
+
+ /* Length must be multiple of 4 */
+ silk_assert( ( length & 3 ) == 0 );
+
+ freq = PI / ( length + 1 );
+
+ /* Approximation of 2 * cos(f) */
+ c = 2.0f - freq * freq;
+
+ /* Initialize state */
+ if( win_type < 2 ) {
+ /* Start from 0 */
+ S0 = 0.0f;
+ /* Approximation of sin(f) */
+ S1 = freq;
+ } else {
+ /* Start from 1 */
+ S0 = 1.0f;
+ /* Approximation of cos(f) */
+ S1 = 0.5f * c;
+ }
+
+ /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */
+ /* 4 samples at a time */
+ for( k = 0; k < length; k += 4 ) {
+ px_win[ k + 0 ] = px[ k + 0 ] * 0.5f * ( S0 + S1 );
+ px_win[ k + 1 ] = px[ k + 1 ] * S1;
+ S0 = c * S1 - S0;
+ px_win[ k + 2 ] = px[ k + 2 ] * 0.5f * ( S1 + S0 );
+ px_win[ k + 3 ] = px[ k + 3 ] * S0;
+ S1 = c * S0 - S1;
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/autocorrelation_FLP.c b/external/opus-1.1.4/silk/float/autocorrelation_FLP.c
new file mode 100644
index 0000000..8b8a9e6
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/autocorrelation_FLP.c
@@ -0,0 +1,52 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "typedef.h"
+#include "SigProc_FLP.h"
+
+/* compute autocorrelation */
+void silk_autocorrelation_FLP(
+ silk_float *results, /* O result (length correlationCount) */
+ const silk_float *inputData, /* I input data to correlate */
+ opus_int inputDataSize, /* I length of input */
+ opus_int correlationCount /* I number of correlation taps to compute */
+)
+{
+ opus_int i;
+
+ if( correlationCount > inputDataSize ) {
+ correlationCount = inputDataSize;
+ }
+
+ for( i = 0; i < correlationCount; i++ ) {
+ results[ i ] = (silk_float)silk_inner_product_FLP( inputData, inputData + i, inputDataSize - i );
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/burg_modified_FLP.c b/external/opus-1.1.4/silk/float/burg_modified_FLP.c
new file mode 100644
index 0000000..ea5dc25
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/burg_modified_FLP.c
@@ -0,0 +1,186 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+#include "tuning_parameters.h"
+#include "define.h"
+
+#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384*/
+
+/* Compute reflection coefficients from input signal */
+silk_float silk_burg_modified_FLP( /* O returns residual energy */
+ silk_float A[], /* O prediction coefficients (length order) */
+ const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */
+ const silk_float minInvGain, /* I minimum inverse prediction gain */
+ const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I number of subframes stacked in x */
+ const opus_int D /* I order */
+)
+{
+ opus_int k, n, s, reached_max_gain;
+ double C0, invGain, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2;
+ const silk_float *x_ptr;
+ double C_first_row[ SILK_MAX_ORDER_LPC ], C_last_row[ SILK_MAX_ORDER_LPC ];
+ double CAf[ SILK_MAX_ORDER_LPC + 1 ], CAb[ SILK_MAX_ORDER_LPC + 1 ];
+ double Af[ SILK_MAX_ORDER_LPC ];
+
+ silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
+
+ /* Compute autocorrelations, added over subframes */
+ C0 = silk_energy_FLP( x, nb_subfr * subfr_length );
+ silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( double ) );
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ for( n = 1; n < D + 1; n++ ) {
+ C_first_row[ n - 1 ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n );
+ }
+ }
+ silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( double ) );
+
+ /* Initialize */
+ CAb[ 0 ] = CAf[ 0 ] = C0 + FIND_LPC_COND_FAC * C0 + 1e-9f;
+ invGain = 1.0f;
+ reached_max_gain = 0;
+ for( n = 0; n < D; n++ ) {
+ /* Update first row of correlation matrix (without first element) */
+ /* Update last row of correlation matrix (without last element, stored in reversed order) */
+ /* Update C * Af */
+ /* Update C * flipud(Af) (stored in reversed order) */
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ tmp1 = x_ptr[ n ];
+ tmp2 = x_ptr[ subfr_length - n - 1 ];
+ for( k = 0; k < n; k++ ) {
+ C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ];
+ C_last_row[ k ] -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ];
+ Atmp = Af[ k ];
+ tmp1 += x_ptr[ n - k - 1 ] * Atmp;
+ tmp2 += x_ptr[ subfr_length - n + k ] * Atmp;
+ }
+ for( k = 0; k <= n; k++ ) {
+ CAf[ k ] -= tmp1 * x_ptr[ n - k ];
+ CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ];
+ }
+ }
+ tmp1 = C_first_row[ n ];
+ tmp2 = C_last_row[ n ];
+ for( k = 0; k < n; k++ ) {
+ Atmp = Af[ k ];
+ tmp1 += C_last_row[ n - k - 1 ] * Atmp;
+ tmp2 += C_first_row[ n - k - 1 ] * Atmp;
+ }
+ CAf[ n + 1 ] = tmp1;
+ CAb[ n + 1 ] = tmp2;
+
+ /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
+ num = CAb[ n + 1 ];
+ nrg_b = CAb[ 0 ];
+ nrg_f = CAf[ 0 ];
+ for( k = 0; k < n; k++ ) {
+ Atmp = Af[ k ];
+ num += CAb[ n - k ] * Atmp;
+ nrg_b += CAb[ k + 1 ] * Atmp;
+ nrg_f += CAf[ k + 1 ] * Atmp;
+ }
+ silk_assert( nrg_f > 0.0 );
+ silk_assert( nrg_b > 0.0 );
+
+ /* Calculate the next order reflection (parcor) coefficient */
+ rc = -2.0 * num / ( nrg_f + nrg_b );
+ silk_assert( rc > -1.0 && rc < 1.0 );
+
+ /* Update inverse prediction gain */
+ tmp1 = invGain * ( 1.0 - rc * rc );
+ if( tmp1 <= minInvGain ) {
+ /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
+ rc = sqrt( 1.0 - minInvGain / invGain );
+ if( num > 0 ) {
+ /* Ensure adjusted reflection coefficients has the original sign */
+ rc = -rc;
+ }
+ invGain = minInvGain;
+ reached_max_gain = 1;
+ } else {
+ invGain = tmp1;
+ }
+
+ /* Update the AR coefficients */
+ for( k = 0; k < (n + 1) >> 1; k++ ) {
+ tmp1 = Af[ k ];
+ tmp2 = Af[ n - k - 1 ];
+ Af[ k ] = tmp1 + rc * tmp2;
+ Af[ n - k - 1 ] = tmp2 + rc * tmp1;
+ }
+ Af[ n ] = rc;
+
+ if( reached_max_gain ) {
+ /* Reached max prediction gain; set remaining coefficients to zero and exit loop */
+ for( k = n + 1; k < D; k++ ) {
+ Af[ k ] = 0.0;
+ }
+ break;
+ }
+
+ /* Update C * Af and C * Ab */
+ for( k = 0; k <= n + 1; k++ ) {
+ tmp1 = CAf[ k ];
+ CAf[ k ] += rc * CAb[ n - k + 1 ];
+ CAb[ n - k + 1 ] += rc * tmp1;
+ }
+ }
+
+ if( reached_max_gain ) {
+ /* Convert to silk_float */
+ for( k = 0; k < D; k++ ) {
+ A[ k ] = (silk_float)( -Af[ k ] );
+ }
+ /* Subtract energy of preceding samples from C0 */
+ for( s = 0; s < nb_subfr; s++ ) {
+ C0 -= silk_energy_FLP( x + s * subfr_length, D );
+ }
+ /* Approximate residual energy */
+ nrg_f = C0 * invGain;
+ } else {
+ /* Compute residual energy and store coefficients as silk_float */
+ nrg_f = CAf[ 0 ];
+ tmp1 = 1.0;
+ for( k = 0; k < D; k++ ) {
+ Atmp = Af[ k ];
+ nrg_f += CAf[ k + 1 ] * Atmp;
+ tmp1 += Atmp * Atmp;
+ A[ k ] = (silk_float)(-Atmp);
+ }
+ nrg_f -= FIND_LPC_COND_FAC * C0 * tmp1;
+ }
+
+ /* Return residual energy */
+ return (silk_float)nrg_f;
+}
diff --git a/external/opus-1.1.4/silk/float/bwexpander_FLP.c b/external/opus-1.1.4/silk/float/bwexpander_FLP.c
new file mode 100644
index 0000000..d55a4d7
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/bwexpander_FLP.c
@@ -0,0 +1,49 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* Chirp (bw expand) LP AR filter */
+void silk_bwexpander_FLP(
+ silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I length of ar */
+ const silk_float chirp /* I chirp factor (typically in range (0..1) ) */
+)
+{
+ opus_int i;
+ silk_float cfac = chirp;
+
+ for( i = 0; i < d - 1; i++ ) {
+ ar[ i ] *= cfac;
+ cfac *= chirp;
+ }
+ ar[ d - 1 ] *= cfac;
+}
diff --git a/external/opus-1.1.4/silk/float/corrMatrix_FLP.c b/external/opus-1.1.4/silk/float/corrMatrix_FLP.c
new file mode 100644
index 0000000..eae6a1c
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/corrMatrix_FLP.c
@@ -0,0 +1,93 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/**********************************************************************
+ * Correlation matrix computations for LS estimate.
+ **********************************************************************/
+
+#include "main_FLP.h"
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FLP(
+ const silk_float *x, /* I x vector [L+order-1] used to create X */
+ const silk_float *t, /* I Target vector [L] */
+ const opus_int L, /* I Length of vecors */
+ const opus_int Order, /* I Max lag for correlation */
+ silk_float *Xt /* O X'*t correlation vector [order] */
+)
+{
+ opus_int lag;
+ const silk_float *ptr1;
+
+ ptr1 = &x[ Order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */
+ for( lag = 0; lag < Order; lag++ ) {
+ /* Calculate X[:,lag]'*t */
+ Xt[ lag ] = (silk_float)silk_inner_product_FLP( ptr1, t, L );
+ ptr1--; /* Next column of X */
+ }
+}
+
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FLP(
+ const silk_float *x, /* I x vector [ L+order-1 ] used to create X */
+ const opus_int L, /* I Length of vectors */
+ const opus_int Order, /* I Max lag for correlation */
+ silk_float *XX /* O X'*X correlation matrix [order x order] */
+)
+{
+ opus_int j, lag;
+ double energy;
+ const silk_float *ptr1, *ptr2;
+
+ ptr1 = &x[ Order - 1 ]; /* First sample of column 0 of X */
+ energy = silk_energy_FLP( ptr1, L ); /* X[:,0]'*X[:,0] */
+ matrix_ptr( XX, 0, 0, Order ) = ( silk_float )energy;
+ for( j = 1; j < Order; j++ ) {
+ /* Calculate X[:,j]'*X[:,j] */
+ energy += ptr1[ -j ] * ptr1[ -j ] - ptr1[ L - j ] * ptr1[ L - j ];
+ matrix_ptr( XX, j, j, Order ) = ( silk_float )energy;
+ }
+
+ ptr2 = &x[ Order - 2 ]; /* First sample of column 1 of X */
+ for( lag = 1; lag < Order; lag++ ) {
+ /* Calculate X[:,0]'*X[:,lag] */
+ energy = silk_inner_product_FLP( ptr1, ptr2, L );
+ matrix_ptr( XX, lag, 0, Order ) = ( silk_float )energy;
+ matrix_ptr( XX, 0, lag, Order ) = ( silk_float )energy;
+ /* Calculate X[:,j]'*X[:,j + lag] */
+ for( j = 1; j < ( Order - lag ); j++ ) {
+ energy += ptr1[ -j ] * ptr2[ -j ] - ptr1[ L - j ] * ptr2[ L - j ];
+ matrix_ptr( XX, lag + j, j, Order ) = ( silk_float )energy;
+ matrix_ptr( XX, j, lag + j, Order ) = ( silk_float )energy;
+ }
+ ptr2--; /* Next column of X */
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/encode_frame_FLP.c b/external/opus-1.1.4/silk/float/encode_frame_FLP.c
new file mode 100644
index 0000000..2092a4d
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/encode_frame_FLP.c
@@ -0,0 +1,372 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */
+static OPUS_INLINE void silk_LBRR_encode_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float xfw[], /* I Input signal */
+ opus_int condCoding /* I The type of conditional coding used so far for this frame */
+);
+
+void silk_encode_do_VAD_FLP(
+ silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */
+)
+{
+ /****************************/
+ /* Voice Activity Detection */
+ /****************************/
+ silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch );
+
+ /**************************************************/
+ /* Convert speech activity into VAD and DTX flags */
+ /**************************************************/
+ if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) {
+ psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY;
+ psEnc->sCmn.noSpeechCounter++;
+ if( psEnc->sCmn.noSpeechCounter < NB_SPEECH_FRAMES_BEFORE_DTX ) {
+ psEnc->sCmn.inDTX = 0;
+ } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) {
+ psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX;
+ psEnc->sCmn.inDTX = 0;
+ }
+ psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0;
+ } else {
+ psEnc->sCmn.noSpeechCounter = 0;
+ psEnc->sCmn.inDTX = 0;
+ psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+ psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+ }
+}
+
+/****************/
+/* Encode frame */
+/****************/
+opus_int silk_encode_frame_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ opus_int32 *pnBytesOut, /* O Number of payload bytes; */
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ opus_int maxBits, /* I If > 0: maximum number of output bits */
+ opus_int useCBR /* I Flag to force constant-bitrate operation */
+)
+{
+ silk_encoder_control_FLP sEncCtrl;
+ opus_int i, iter, maxIter, found_upper, found_lower, ret = 0;
+ silk_float *x_frame, *res_pitch_frame;
+ silk_float xfw[ MAX_FRAME_LENGTH ];
+ silk_float res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ];
+ ec_enc sRangeEnc_copy, sRangeEnc_copy2;
+ silk_nsq_state sNSQ_copy, sNSQ_copy2;
+ opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
+ opus_int32 gainsID, gainsID_lower, gainsID_upper;
+ opus_int16 gainMult_Q8;
+ opus_int16 ec_prevLagIndex_copy;
+ opus_int ec_prevSignalType_copy;
+ opus_int8 LastGainIndex_copy2;
+ opus_int32 pGains_Q16[ MAX_NB_SUBFR ];
+ opus_uint8 ec_buf_copy[ 1275 ];
+
+ /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */
+ LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0;
+
+ psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3;
+
+ /**************************************************************/
+ /* Set up Input Pointers, and insert frame in input buffer */
+ /**************************************************************/
+ /* pointers aligned with start of frame to encode */
+ x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; /* start of frame to encode */
+ res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; /* start of pitch LPC residual frame */
+
+ /***************************************/
+ /* Ensure smooth bandwidth transitions */
+ /***************************************/
+ silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
+
+ /*******************************************/
+ /* Copy new frame to front of input buffer */
+ /*******************************************/
+ silk_short2float_array( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
+
+ /* Add tiny signal to avoid high CPU load from denormalized floating point numbers */
+ for( i = 0; i < 8; i++ ) {
+ x_frame[ LA_SHAPE_MS * psEnc->sCmn.fs_kHz + i * ( psEnc->sCmn.frame_length >> 3 ) ] += ( 1 - ( i & 2 ) ) * 1e-6f;
+ }
+
+ if( !psEnc->sCmn.prefillFlag ) {
+ /*****************************************/
+ /* Find pitch lags, initial LPC analysis */
+ /*****************************************/
+ silk_find_pitch_lags_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch );
+
+ /************************/
+ /* Noise shape analysis */
+ /************************/
+ silk_noise_shape_analysis_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame );
+
+ /***************************************************/
+ /* Find linear prediction coefficients (LPC + LTP) */
+ /***************************************************/
+ silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding );
+
+ /****************************************/
+ /* Process gains */
+ /****************************************/
+ silk_process_gains_FLP( psEnc, &sEncCtrl, condCoding );
+
+ /*****************************************/
+ /* Prefiltering for noise shaper */
+ /*****************************************/
+ silk_prefilter_FLP( psEnc, &sEncCtrl, xfw, x_frame );
+
+ /****************************************/
+ /* Low Bitrate Redundant Encoding */
+ /****************************************/
+ silk_LBRR_encode_FLP( psEnc, &sEncCtrl, xfw, condCoding );
+
+ /* Loop over quantizer and entroy coding to control bitrate */
+ maxIter = 6;
+ gainMult_Q8 = SILK_FIX_CONST( 1, 8 );
+ found_lower = 0;
+ found_upper = 0;
+ gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+ gainsID_lower = -1;
+ gainsID_upper = -1;
+ /* Copy part of the input state */
+ silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
+ silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ seed_copy = psEnc->sCmn.indices.Seed;
+ ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
+ ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
+ for( iter = 0; ; iter++ ) {
+ if( gainsID == gainsID_lower ) {
+ nBits = nBits_lower;
+ } else if( gainsID == gainsID_upper ) {
+ nBits = nBits_upper;
+ } else {
+ /* Restore part of the input state */
+ if( iter > 0 ) {
+ silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
+ silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) );
+ psEnc->sCmn.indices.Seed = seed_copy;
+ psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
+ psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
+ }
+
+ /*****************************************/
+ /* Noise shaping quantization */
+ /*****************************************/
+ silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, xfw );
+
+ /****************************************/
+ /* Encode Parameters */
+ /****************************************/
+ silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+
+ /****************************************/
+ /* Encode Excitation Signal */
+ /****************************************/
+ silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
+ psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
+
+ nBits = ec_tell( psRangeEnc );
+
+ if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
+ break;
+ }
+ }
+
+ if( iter == maxIter ) {
+ if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) {
+ /* Restore output state from earlier iteration that did meet the bitrate budget */
+ silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
+ silk_assert( sRangeEnc_copy2.offs <= 1275 );
+ silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
+ silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) );
+ psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
+ }
+ break;
+ }
+
+ if( nBits > maxBits ) {
+ if( found_lower == 0 && iter >= 2 ) {
+ /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */
+ sEncCtrl.Lambda *= 1.5f;
+ found_upper = 0;
+ gainsID_upper = -1;
+ } else {
+ found_upper = 1;
+ nBits_upper = nBits;
+ gainMult_upper = gainMult_Q8;
+ gainsID_upper = gainsID;
+ }
+ } else if( nBits < maxBits - 5 ) {
+ found_lower = 1;
+ nBits_lower = nBits;
+ gainMult_lower = gainMult_Q8;
+ if( gainsID != gainsID_lower ) {
+ gainsID_lower = gainsID;
+ /* Copy part of the output state */
+ silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+ silk_assert( psRangeEnc->offs <= 1275 );
+ silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
+ silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
+ }
+ } else {
+ /* Within 5 bits of budget: close enough */
+ break;
+ }
+
+ if( ( found_lower & found_upper ) == 0 ) {
+ /* Adjust gain according to high-rate rate/distortion curve */
+ opus_int32 gain_factor_Q16;
+ gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );
+ gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) );
+ if( nBits > maxBits ) {
+ gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) );
+ }
+ gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 );
+ } else {
+ /* Adjust gain by interpolating */
+ gainMult_Q8 = gainMult_lower + ( ( gainMult_upper - gainMult_lower ) * ( maxBits - nBits_lower ) ) / ( nBits_upper - nBits_lower );
+ /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
+ if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) {
+ gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 );
+ } else
+ if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) {
+ gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 );
+ }
+ }
+
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 );
+ }
+
+ /* Quantize gains */
+ psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
+ silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16,
+ &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Unique identifier of gains vector */
+ gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+
+ /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ sEncCtrl.Gains[ i ] = pGains_Q16[ i ] / 65536.0f;
+ }
+ }
+ }
+
+ /* Update input buffer */
+ silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ],
+ ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( silk_float ) );
+
+ /* Exit without entropy coding */
+ if( psEnc->sCmn.prefillFlag ) {
+ /* No payload */
+ *pnBytesOut = 0;
+ return ret;
+ }
+
+ /* Parameters needed for next frame */
+ psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+ psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType;
+
+ /****************************************/
+ /* Finalize payload */
+ /****************************************/
+ psEnc->sCmn.first_frame_after_reset = 0;
+ /* Payload size */
+ *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 );
+
+ return ret;
+}
+
+/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */
+static OPUS_INLINE void silk_LBRR_encode_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float xfw[], /* I Input signal */
+ opus_int condCoding /* I The type of conditional coding used so far for this frame */
+)
+{
+ opus_int k;
+ opus_int32 Gains_Q16[ MAX_NB_SUBFR ];
+ silk_float TempGains[ MAX_NB_SUBFR ];
+ SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ];
+ silk_nsq_state sNSQ_LBRR;
+
+ /*******************************************/
+ /* Control use of inband LBRR */
+ /*******************************************/
+ if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) {
+ psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+
+ /* Copy noise shaping quantizer state and quantization indices from regular encoding */
+ silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) );
+
+ /* Save original gains */
+ silk_memcpy( TempGains, psEncCtrl->Gains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) );
+
+ if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) {
+ /* First frame in packet or previous frame not LBRR coded */
+ psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex;
+
+ /* Increase Gains to get target LBRR rate */
+ psIndices_LBRR->GainsIndices[ 0 ] += psEnc->sCmn.LBRR_GainIncreases;
+ psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 );
+ }
+
+ /* Decode to get gains in sync with decoder */
+ silk_gains_dequant( Gains_Q16, psIndices_LBRR->GainsIndices,
+ &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains[ k ] = Gains_Q16[ k ] * ( 1.0f / 65536.0f );
+ }
+
+ /*****************************************/
+ /* Noise shaping quantization */
+ /*****************************************/
+ silk_NSQ_wrapper_FLP( psEnc, psEncCtrl, psIndices_LBRR, &sNSQ_LBRR,
+ psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], xfw );
+
+ /* Restore original gains */
+ silk_memcpy( psEncCtrl->Gains, TempGains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) );
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/energy_FLP.c b/external/opus-1.1.4/silk/float/energy_FLP.c
new file mode 100644
index 0000000..24b8179
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/energy_FLP.c
@@ -0,0 +1,60 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* sum of squares of a silk_float array, with result as double */
+double silk_energy_FLP(
+ const silk_float *data,
+ opus_int dataSize
+)
+{
+ opus_int i, dataSize4;
+ double result;
+
+ /* 4x unrolled loop */
+ result = 0.0;
+ dataSize4 = dataSize & 0xFFFC;
+ for( i = 0; i < dataSize4; i += 4 ) {
+ result += data[ i + 0 ] * (double)data[ i + 0 ] +
+ data[ i + 1 ] * (double)data[ i + 1 ] +
+ data[ i + 2 ] * (double)data[ i + 2 ] +
+ data[ i + 3 ] * (double)data[ i + 3 ];
+ }
+
+ /* add any remaining products */
+ for( ; i < dataSize; i++ ) {
+ result += data[ i ] * (double)data[ i ];
+ }
+
+ silk_assert( result >= 0.0 );
+ return result;
+}
diff --git a/external/opus-1.1.4/silk/float/find_LPC_FLP.c b/external/opus-1.1.4/silk/float/find_LPC_FLP.c
new file mode 100644
index 0000000..fcfe1c3
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/find_LPC_FLP.c
@@ -0,0 +1,104 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "define.h"
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/* LPC analysis */
+void silk_find_LPC_FLP(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 NLSF_Q15[], /* O NLSFs */
+ const silk_float x[], /* I Input signal */
+ const silk_float minInvGain /* I Inverse of max prediction gain */
+)
+{
+ opus_int k, subfr_length;
+ silk_float a[ MAX_LPC_ORDER ];
+
+ /* Used only for NLSF interpolation */
+ silk_float res_nrg, res_nrg_2nd, res_nrg_interp;
+ opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ];
+ silk_float a_tmp[ MAX_LPC_ORDER ];
+ silk_float LPC_res[ MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ];
+
+ subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder;
+
+ /* Default: No interpolation */
+ psEncC->indices.NLSFInterpCoef_Q2 = 4;
+
+ /* Burg AR analysis for the full frame */
+ res_nrg = silk_burg_modified_FLP( a, x, minInvGain, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder );
+
+ if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) {
+ /* Optimal solution for last 10 ms; subtract residual energy here, as that's easier than */
+ /* adding it to the residual energy of the first 10 ms in each iteration of the search below */
+ res_nrg -= silk_burg_modified_FLP( a_tmp, x + ( MAX_NB_SUBFR / 2 ) * subfr_length, minInvGain, subfr_length, MAX_NB_SUBFR / 2, psEncC->predictLPCOrder );
+
+ /* Convert to NLSFs */
+ silk_A2NLSF_FLP( NLSF_Q15, a_tmp, psEncC->predictLPCOrder );
+
+ /* Search over interpolation indices to find the one with lowest residual energy */
+ res_nrg_2nd = silk_float_MAX;
+ for( k = 3; k >= 0; k-- ) {
+ /* Interpolate NLSFs for first half */
+ silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder );
+
+ /* Convert to LPC for residual energy evaluation */
+ silk_NLSF2A_FLP( a_tmp, NLSF0_Q15, psEncC->predictLPCOrder );
+
+ /* Calculate residual energy with LSF interpolation */
+ silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, psEncC->predictLPCOrder );
+ res_nrg_interp = (silk_float)(
+ silk_energy_FLP( LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ) +
+ silk_energy_FLP( LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ) );
+
+ /* Determine whether current interpolated NLSFs are best so far */
+ if( res_nrg_interp < res_nrg ) {
+ /* Interpolation has lower residual energy */
+ res_nrg = res_nrg_interp;
+ psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k;
+ } else if( res_nrg_interp > res_nrg_2nd ) {
+ /* No reason to continue iterating - residual energies will continue to climb */
+ break;
+ }
+ res_nrg_2nd = res_nrg_interp;
+ }
+ }
+
+ if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) {
+ /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
+ silk_A2NLSF_FLP( NLSF_Q15, a, psEncC->predictLPCOrder );
+ }
+
+ silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 ||
+ ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) );
+}
diff --git a/external/opus-1.1.4/silk/float/find_LTP_FLP.c b/external/opus-1.1.4/silk/float/find_LTP_FLP.c
new file mode 100644
index 0000000..7229996
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/find_LTP_FLP.c
@@ -0,0 +1,132 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+void silk_find_LTP_FLP(
+ silk_float b[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */
+ silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */
+ silk_float *LTPredCodGain, /* O LTP coding gain */
+ const silk_float r_lpc[], /* I LPC residual */
+ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
+ const silk_float Wght[ MAX_NB_SUBFR ], /* I Weights */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int mem_offset /* I Number of samples in LTP memory */
+)
+{
+ opus_int i, k;
+ silk_float *b_ptr, temp, *WLTP_ptr;
+ silk_float LPC_res_nrg, LPC_LTP_res_nrg;
+ silk_float d[ MAX_NB_SUBFR ], m, g, delta_b[ LTP_ORDER ];
+ silk_float w[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], regu;
+ silk_float Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ];
+ const silk_float *r_ptr, *lag_ptr;
+
+ b_ptr = b;
+ WLTP_ptr = WLTP;
+ r_ptr = &r_lpc[ mem_offset ];
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 );
+
+ silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, WLTP_ptr );
+ silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr );
+
+ rr[ k ] = ( silk_float )silk_energy_FLP( r_ptr, subfr_length );
+ regu = 1.0f + rr[ k ] +
+ matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ) +
+ matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER );
+ regu *= LTP_DAMPING / 3;
+ silk_regularize_correlations_FLP( WLTP_ptr, &rr[ k ], regu, LTP_ORDER );
+ silk_solve_LDL_FLP( WLTP_ptr, LTP_ORDER, Rr, b_ptr );
+
+ /* Calculate residual energy */
+ nrg[ k ] = silk_residual_energy_covar_FLP( b_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER );
+
+ temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length );
+ silk_scale_vector_FLP( WLTP_ptr, temp, LTP_ORDER * LTP_ORDER );
+ w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER / 2, LTP_ORDER / 2, LTP_ORDER );
+
+ r_ptr += subfr_length;
+ b_ptr += LTP_ORDER;
+ WLTP_ptr += LTP_ORDER * LTP_ORDER;
+ }
+
+ /* Compute LTP coding gain */
+ if( LTPredCodGain != NULL ) {
+ LPC_LTP_res_nrg = 1e-6f;
+ LPC_res_nrg = 0.0f;
+ for( k = 0; k < nb_subfr; k++ ) {
+ LPC_res_nrg += rr[ k ] * Wght[ k ];
+ LPC_LTP_res_nrg += nrg[ k ] * Wght[ k ];
+ }
+
+ silk_assert( LPC_LTP_res_nrg > 0 );
+ *LTPredCodGain = 3.0f * silk_log2( LPC_res_nrg / LPC_LTP_res_nrg );
+ }
+
+ /* Smoothing */
+ /* d = sum( B, 1 ); */
+ b_ptr = b;
+ for( k = 0; k < nb_subfr; k++ ) {
+ d[ k ] = 0;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ d[ k ] += b_ptr[ i ];
+ }
+ b_ptr += LTP_ORDER;
+ }
+ /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */
+ temp = 1e-3f;
+ for( k = 0; k < nb_subfr; k++ ) {
+ temp += w[ k ];
+ }
+ m = 0;
+ for( k = 0; k < nb_subfr; k++ ) {
+ m += d[ k ] * w[ k ];
+ }
+ m = m / temp;
+
+ b_ptr = b;
+ for( k = 0; k < nb_subfr; k++ ) {
+ g = LTP_SMOOTHING / ( LTP_SMOOTHING + w[ k ] ) * ( m - d[ k ] );
+ temp = 0;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ delta_b[ i ] = silk_max_float( b_ptr[ i ], 0.1f );
+ temp += delta_b[ i ];
+ }
+ temp = g / temp;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ b_ptr[ i ] = b_ptr[ i ] + delta_b[ i ] * temp;
+ }
+ b_ptr += LTP_ORDER;
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/find_pitch_lags_FLP.c b/external/opus-1.1.4/silk/float/find_pitch_lags_FLP.c
new file mode 100644
index 0000000..f3b22d2
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/find_pitch_lags_FLP.c
@@ -0,0 +1,132 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+void silk_find_pitch_lags_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ silk_float res[], /* O Residual */
+ const silk_float x[], /* I Speech signal */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int buf_len;
+ silk_float thrhld, res_nrg;
+ const silk_float *x_buf_ptr, *x_buf;
+ silk_float auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ];
+ silk_float A[ MAX_FIND_PITCH_LPC_ORDER ];
+ silk_float refl_coef[ MAX_FIND_PITCH_LPC_ORDER ];
+ silk_float Wsig[ FIND_PITCH_LPC_WIN_MAX ];
+ silk_float *Wsig_ptr;
+
+ /******************************************/
+ /* Set up buffer lengths etc based on Fs */
+ /******************************************/
+ buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length;
+
+ /* Safety check */
+ silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length );
+
+ x_buf = x - psEnc->sCmn.ltp_mem_length;
+
+ /******************************************/
+ /* Estimate LPC AR coeficients */
+ /******************************************/
+
+ /* Calculate windowed signal */
+
+ /* First LA_LTP samples */
+ x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length;
+ Wsig_ptr = Wsig;
+ silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch );
+
+ /* Middle non-windowed samples */
+ Wsig_ptr += psEnc->sCmn.la_pitch;
+ x_buf_ptr += psEnc->sCmn.la_pitch;
+ silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ) ) * sizeof( silk_float ) );
+
+ /* Last LA_LTP samples */
+ Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 );
+ x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 );
+ silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch );
+
+ /* Calculate autocorrelation sequence */
+ silk_autocorrelation_FLP( auto_corr, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 );
+
+ /* Add white noise, as a fraction of the energy */
+ auto_corr[ 0 ] += auto_corr[ 0 ] * FIND_PITCH_WHITE_NOISE_FRACTION + 1;
+
+ /* Calculate the reflection coefficients using Schur */
+ res_nrg = silk_schur_FLP( refl_coef, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ /* Prediction gain */
+ psEncCtrl->predGain = auto_corr[ 0 ] / silk_max_float( res_nrg, 1.0f );
+
+ /* Convert reflection coefficients to prediction coefficients */
+ silk_k2a_FLP( A, refl_coef, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ /* Bandwidth expansion */
+ silk_bwexpander_FLP( A, psEnc->sCmn.pitchEstimationLPCOrder, FIND_PITCH_BANDWIDTH_EXPANSION );
+
+ /*****************************************/
+ /* LPC analysis filtering */
+ /*****************************************/
+ silk_LPC_analysis_filter_FLP( res, A, x_buf, buf_len, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) {
+ /* Threshold for pitch estimator */
+ thrhld = 0.6f;
+ thrhld -= 0.004f * psEnc->sCmn.pitchEstimationLPCOrder;
+ thrhld -= 0.1f * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f );
+ thrhld -= 0.15f * (psEnc->sCmn.prevSignalType >> 1);
+ thrhld -= 0.1f * psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f );
+
+ /*****************************************/
+ /* Call Pitch estimator */
+ /*****************************************/
+ if( silk_pitch_analysis_core_FLP( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex,
+ &psEnc->sCmn.indices.contourIndex, &psEnc->LTPCorr, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16 / 65536.0f,
+ thrhld, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr, arch ) == 0 )
+ {
+ psEnc->sCmn.indices.signalType = TYPE_VOICED;
+ } else {
+ psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+ }
+ } else {
+ silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) );
+ psEnc->sCmn.indices.lagIndex = 0;
+ psEnc->sCmn.indices.contourIndex = 0;
+ psEnc->LTPCorr = 0;
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/find_pred_coefs_FLP.c b/external/opus-1.1.4/silk/float/find_pred_coefs_FLP.c
new file mode 100644
index 0000000..1af4fe5
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/find_pred_coefs_FLP.c
@@ -0,0 +1,118 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+/* Find LPC and LTP coefficients */
+void silk_find_pred_coefs_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float res_pitch[], /* I Residual from pitch analysis */
+ const silk_float x[], /* I Speech signal */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i;
+ silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ];
+ silk_float invGains[ MAX_NB_SUBFR ], Wght[ MAX_NB_SUBFR ];
+ opus_int16 NLSF_Q15[ MAX_LPC_ORDER ];
+ const silk_float *x_ptr;
+ silk_float *x_pre_ptr, LPC_in_pre[ MAX_NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ];
+ silk_float minInvGain;
+
+ /* Weighting for weighted least squares */
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ silk_assert( psEncCtrl->Gains[ i ] > 0.0f );
+ invGains[ i ] = 1.0f / psEncCtrl->Gains[ i ];
+ Wght[ i ] = invGains[ i ] * invGains[ i ];
+ }
+
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /**********/
+ /* VOICED */
+ /**********/
+ silk_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 );
+
+ /* LTP analysis */
+ silk_find_LTP_FLP( psEncCtrl->LTPCoef, WLTP, &psEncCtrl->LTPredCodGain, res_pitch,
+ psEncCtrl->pitchL, Wght, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length );
+
+ /* Quantize LTP gain parameters */
+ silk_quant_LTP_gains_FLP( psEncCtrl->LTPCoef, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex,
+ &psEnc->sCmn.sum_log_gain_Q7, WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr,
+ psEnc->sCmn.arch );
+
+ /* Control LTP scaling */
+ silk_LTP_scale_ctrl_FLP( psEnc, psEncCtrl, condCoding );
+
+ /* Create LTP residual */
+ silk_LTP_analysis_filter_FLP( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef,
+ psEncCtrl->pitchL, invGains, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+ } else {
+ /************/
+ /* UNVOICED */
+ /************/
+ /* Create signal with prepended subframes, scaled by inverse gains */
+ x_ptr = x - psEnc->sCmn.predictLPCOrder;
+ x_pre_ptr = LPC_in_pre;
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ silk_scale_copy_vector_FLP( x_pre_ptr, x_ptr, invGains[ i ],
+ psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder );
+ x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder;
+ x_ptr += psEnc->sCmn.subfr_length;
+ }
+ silk_memset( psEncCtrl->LTPCoef, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( silk_float ) );
+ psEncCtrl->LTPredCodGain = 0.0f;
+ psEnc->sCmn.sum_log_gain_Q7 = 0;
+ }
+
+ /* Limit on total predictive coding gain */
+ if( psEnc->sCmn.first_frame_after_reset ) {
+ minInvGain = 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET;
+ } else {
+ minInvGain = (silk_float)pow( 2, psEncCtrl->LTPredCodGain / 3 ) / MAX_PREDICTION_POWER_GAIN;
+ minInvGain /= 0.25f + 0.75f * psEncCtrl->coding_quality;
+ }
+
+ /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */
+ silk_find_LPC_FLP( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain );
+
+ /* Quantize LSFs */
+ silk_process_NLSFs_FLP( &psEnc->sCmn, psEncCtrl->PredCoef, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 );
+
+ /* Calculate residual energy using quantized LPC coefficients */
+ silk_residual_energy_FLP( psEncCtrl->ResNrg, LPC_in_pre, psEncCtrl->PredCoef, psEncCtrl->Gains,
+ psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+
+ /* Copy to prediction struct for use in next frame for interpolation */
+ silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
+}
+
diff --git a/external/opus-1.1.4/silk/float/inner_product_FLP.c b/external/opus-1.1.4/silk/float/inner_product_FLP.c
new file mode 100644
index 0000000..029c012
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/inner_product_FLP.c
@@ -0,0 +1,60 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* inner product of two silk_float arrays, with result as double */
+double silk_inner_product_FLP(
+ const silk_float *data1,
+ const silk_float *data2,
+ opus_int dataSize
+)
+{
+ opus_int i, dataSize4;
+ double result;
+
+ /* 4x unrolled loop */
+ result = 0.0;
+ dataSize4 = dataSize & 0xFFFC;
+ for( i = 0; i < dataSize4; i += 4 ) {
+ result += data1[ i + 0 ] * (double)data2[ i + 0 ] +
+ data1[ i + 1 ] * (double)data2[ i + 1 ] +
+ data1[ i + 2 ] * (double)data2[ i + 2 ] +
+ data1[ i + 3 ] * (double)data2[ i + 3 ];
+ }
+
+ /* add any remaining products */
+ for( ; i < dataSize; i++ ) {
+ result += data1[ i ] * (double)data2[ i ];
+ }
+
+ return result;
+}
diff --git a/external/opus-1.1.4/silk/float/k2a_FLP.c b/external/opus-1.1.4/silk/float/k2a_FLP.c
new file mode 100644
index 0000000..12af4e7
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/k2a_FLP.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a_FLP(
+ silk_float *A, /* O prediction coefficients [order] */
+ const silk_float *rc, /* I reflection coefficients [order] */
+ opus_int32 order /* I prediction order */
+)
+{
+ opus_int k, n;
+ silk_float Atmp[ SILK_MAX_ORDER_LPC ];
+
+ for( k = 0; k < order; k++ ) {
+ for( n = 0; n < k; n++ ) {
+ Atmp[ n ] = A[ n ];
+ }
+ for( n = 0; n < k; n++ ) {
+ A[ n ] += Atmp[ k - n - 1 ] * rc[ k ];
+ }
+ A[ k ] = -rc[ k ];
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/levinsondurbin_FLP.c b/external/opus-1.1.4/silk/float/levinsondurbin_FLP.c
new file mode 100644
index 0000000..f0ba606
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/levinsondurbin_FLP.c
@@ -0,0 +1,81 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* Solve the normal equations using the Levinson-Durbin recursion */
+silk_float silk_levinsondurbin_FLP( /* O prediction error energy */
+ silk_float A[], /* O prediction coefficients [order] */
+ const silk_float corr[], /* I input auto-correlations [order + 1] */
+ const opus_int order /* I prediction order */
+)
+{
+ opus_int i, mHalf, m;
+ silk_float min_nrg, nrg, t, km, Atmp1, Atmp2;
+
+ min_nrg = 1e-12f * corr[ 0 ] + 1e-9f;
+ nrg = corr[ 0 ];
+ nrg = silk_max_float(min_nrg, nrg);
+ A[ 0 ] = corr[ 1 ] / nrg;
+ nrg -= A[ 0 ] * corr[ 1 ];
+ nrg = silk_max_float(min_nrg, nrg);
+
+ for( m = 1; m < order; m++ )
+ {
+ t = corr[ m + 1 ];
+ for( i = 0; i < m; i++ ) {
+ t -= A[ i ] * corr[ m - i ];
+ }
+
+ /* reflection coefficient */
+ km = t / nrg;
+
+ /* residual energy */
+ nrg -= km * t;
+ nrg = silk_max_float(min_nrg, nrg);
+
+ mHalf = m >> 1;
+ for( i = 0; i < mHalf; i++ ) {
+ Atmp1 = A[ i ];
+ Atmp2 = A[ m - i - 1 ];
+ A[ m - i - 1 ] -= km * Atmp1;
+ A[ i ] -= km * Atmp2;
+ }
+ if( m & 1 ) {
+ A[ mHalf ] -= km * A[ mHalf ];
+ }
+ A[ m ] = km;
+ }
+
+ /* return the residual energy */
+ return nrg;
+}
+
diff --git a/external/opus-1.1.4/silk/float/main_FLP.h b/external/opus-1.1.4/silk/float/main_FLP.h
new file mode 100644
index 0000000..e5a7597
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/main_FLP.h
@@ -0,0 +1,313 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_MAIN_FLP_H
+#define SILK_MAIN_FLP_H
+
+#include "SigProc_FLP.h"
+#include "SigProc_FIX.h"
+#include "structs_FLP.h"
+#include "main.h"
+#include "define.h"
+#include "debug.h"
+#include "entenc.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define silk_encoder_state_Fxx silk_encoder_state_FLP
+#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FLP
+#define silk_encode_frame_Fxx silk_encode_frame_FLP
+
+/*********************/
+/* Encoder Functions */
+/*********************/
+
+/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
+void silk_HP_variable_cutoff(
+ silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */
+);
+
+/* Encoder main function */
+void silk_encode_do_VAD_FLP(
+ silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */
+);
+
+/* Encoder main function */
+opus_int silk_encode_frame_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ opus_int32 *pnBytesOut, /* O Number of payload bytes; */
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ opus_int maxBits, /* I If > 0: maximum number of output bits */
+ opus_int useCBR /* I Flag to force constant-bitrate operation */
+);
+
+/* Initializes the Silk encoder state */
+opus_int silk_init_encoder(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ int arch /* I Run-tim architecture */
+);
+
+/* Control the Silk encoder */
+opus_int silk_control_encoder(
+ silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */
+ silk_EncControlStruct *encControl, /* I Control structure */
+ const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */
+ const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
+ const opus_int channelNb, /* I Channel number */
+ const opus_int force_fs_kHz
+);
+
+/****************/
+/* Prefiltering */
+/****************/
+void silk_prefilter_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ const silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */
+ silk_float xw[], /* O Weighted signal */
+ const silk_float x[] /* I Speech signal */
+);
+
+/**************************/
+/* Noise shaping analysis */
+/**************************/
+/* Compute noise shaping coefficients and initial gain values */
+void silk_noise_shape_analysis_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float *pitch_res, /* I LPC residual from pitch analysis */
+ const silk_float *x /* I Input signal [frame_length + la_shape] */
+);
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FLP(
+ silk_float *corr, /* O Result [order + 1] */
+ const silk_float *input, /* I Input data to correlate */
+ const silk_float warping, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+);
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/**********************************************/
+/* Prediction Analysis */
+/**********************************************/
+/* Find pitch lags */
+void silk_find_pitch_lags_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ silk_float res[], /* O Residual */
+ const silk_float x[], /* I Speech signal */
+ int arch /* I Run-time architecture */
+);
+
+/* Find LPC and LTP coefficients */
+void silk_find_pred_coefs_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float res_pitch[], /* I Residual from pitch analysis */
+ const silk_float x[], /* I Speech signal */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/* LPC analysis */
+void silk_find_LPC_FLP(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 NLSF_Q15[], /* O NLSFs */
+ const silk_float x[], /* I Input signal */
+ const silk_float minInvGain /* I Prediction gain from LTP (dB) */
+);
+
+/* LTP analysis */
+void silk_find_LTP_FLP(
+ silk_float b[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */
+ silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */
+ silk_float *LTPredCodGain, /* O LTP coding gain */
+ const silk_float r_lpc[], /* I LPC residual */
+ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
+ const silk_float Wght[ MAX_NB_SUBFR ], /* I Weights */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int mem_offset /* I Number of samples in LTP memory */
+);
+
+void silk_LTP_analysis_filter_FLP(
+ silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */
+ const silk_float *x, /* I Input signal, with preceding samples */
+ const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */
+ const opus_int subfr_length, /* I Length of each subframe */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int pre_length /* I Preceding samples for each subframe */
+);
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order */
+/* of preceding samples */
+void silk_residual_energy_FLP(
+ silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
+ const silk_float x[], /* I Input signal */
+ silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
+ const silk_float gains[], /* I Quantization gains */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int LPC_order /* I LPC order */
+);
+
+/* 16th order LPC analysis filter */
+void silk_LPC_analysis_filter_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length, /* I Length of input signal */
+ const opus_int Order /* I LPC order */
+);
+
+/* LTP tap quantizer */
+void silk_quant_LTP_gains_FLP(
+ silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (Un-)quantized LTP gains */
+ opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */
+ opus_int8 *periodicity_index, /* O Periodicity index */
+ opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */
+ const silk_float W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Error weights */
+ const opus_int mu_Q10, /* I Mu value (R/D tradeoff) */
+ const opus_int lowComplexity, /* I Flag for low complexity */
+ const opus_int nb_subfr, /* I number of subframes */
+ int arch /* I Run-time architecture */
+);
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */
+ const silk_float *c, /* I Filter coefficients */
+ silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */
+ const silk_float *wXx, /* I Weighted correlation vector */
+ const silk_float wxx, /* I Weighted correlation value */
+ const opus_int D /* I Dimension */
+);
+
+/* Processing of gains */
+void silk_process_gains_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/******************/
+/* Linear Algebra */
+/******************/
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FLP(
+ const silk_float *x, /* I x vector [ L+order-1 ] used to create X */
+ const opus_int L, /* I Length of vectors */
+ const opus_int Order, /* I Max lag for correlation */
+ silk_float *XX /* O X'*X correlation matrix [order x order] */
+);
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FLP(
+ const silk_float *x, /* I x vector [L+order-1] used to create X */
+ const silk_float *t, /* I Target vector [L] */
+ const opus_int L, /* I Length of vecors */
+ const opus_int Order, /* I Max lag for correlation */
+ silk_float *Xt /* O X'*t correlation vector [order] */
+);
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FLP(
+ silk_float *XX, /* I/O Correlation matrices */
+ silk_float *xx, /* I/O Correlation values */
+ const silk_float noise, /* I Noise energy to add */
+ const opus_int D /* I Dimension of XX */
+);
+
+/* Function to solve linear equation Ax = b, where A is an MxM symmetric matrix */
+void silk_solve_LDL_FLP(
+ silk_float *A, /* I/O Symmetric square matrix, out: reg. */
+ const opus_int M, /* I Size of matrix */
+ const silk_float *b, /* I Pointer to b vector */
+ silk_float *x /* O Pointer to x solution vector */
+);
+
+/* Apply sine window to signal vector. */
+/* Window types: */
+/* 1 -> sine window from 0 to pi/2 */
+/* 2 -> sine window from pi/2 to pi */
+void silk_apply_sine_window_FLP(
+ silk_float px_win[], /* O Pointer to windowed signal */
+ const silk_float px[], /* I Pointer to input signal */
+ const opus_int win_type, /* I Selects a window type */
+ const opus_int length /* I Window length, multiple of 4 */
+);
+
+/* Wrapper functions. Call flp / fix code */
+
+/* Convert AR filter coefficients to NLSF parameters */
+void silk_A2NLSF_FLP(
+ opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */
+ const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */
+ const opus_int LPC_order /* I LPC order */
+);
+
+/* Convert NLSF parameters to AR prediction filter coefficients */
+void silk_NLSF2A_FLP(
+ silk_float *pAR, /* O LPC coefficients [ LPC_order ] */
+ const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */
+ const opus_int LPC_order /* I LPC order */
+);
+
+/* Limit, stabilize, and quantize NLSFs */
+void silk_process_NLSFs_FLP(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */
+ opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */
+ const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */
+);
+
+/* Floating-point Silk NSQ wrapper */
+void silk_NSQ_wrapper_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ SideInfoIndices *psIndices, /* I/O Quantization indices */
+ silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const silk_float x[] /* I Prefiltered input signal */
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/silk/float/noise_shape_analysis_FLP.c b/external/opus-1.1.4/silk/float/noise_shape_analysis_FLP.c
new file mode 100644
index 0000000..65f6ea5
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/noise_shape_analysis_FLP.c
@@ -0,0 +1,365 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */
+/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */
+/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */
+/* coefficient in an array of coefficients, for monic filters. */
+static OPUS_INLINE silk_float warped_gain(
+ const silk_float *coefs,
+ silk_float lambda,
+ opus_int order
+) {
+ opus_int i;
+ silk_float gain;
+
+ lambda = -lambda;
+ gain = coefs[ order - 1 ];
+ for( i = order - 2; i >= 0; i-- ) {
+ gain = lambda * gain + coefs[ i ];
+ }
+ return (silk_float)( 1.0f / ( 1.0f - lambda * gain ) );
+}
+
+/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */
+/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
+static OPUS_INLINE void warped_true2monic_coefs(
+ silk_float *coefs_syn,
+ silk_float *coefs_ana,
+ silk_float lambda,
+ silk_float limit,
+ opus_int order
+) {
+ opus_int i, iter, ind = 0;
+ silk_float tmp, maxabs, chirp, gain_syn, gain_ana;
+
+ /* Convert to monic coefficients */
+ for( i = order - 1; i > 0; i-- ) {
+ coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ];
+ coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ];
+ }
+ gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] );
+ gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] );
+ for( i = 0; i < order; i++ ) {
+ coefs_syn[ i ] *= gain_syn;
+ coefs_ana[ i ] *= gain_ana;
+ }
+
+ /* Limit */
+ for( iter = 0; iter < 10; iter++ ) {
+ /* Find maximum absolute value */
+ maxabs = -1.0f;
+ for( i = 0; i < order; i++ ) {
+ tmp = silk_max( silk_abs_float( coefs_syn[ i ] ), silk_abs_float( coefs_ana[ i ] ) );
+ if( tmp > maxabs ) {
+ maxabs = tmp;
+ ind = i;
+ }
+ }
+ if( maxabs <= limit ) {
+ /* Coefficients are within range - done */
+ return;
+ }
+
+ /* Convert back to true warped coefficients */
+ for( i = 1; i < order; i++ ) {
+ coefs_syn[ i - 1 ] += lambda * coefs_syn[ i ];
+ coefs_ana[ i - 1 ] += lambda * coefs_ana[ i ];
+ }
+ gain_syn = 1.0f / gain_syn;
+ gain_ana = 1.0f / gain_ana;
+ for( i = 0; i < order; i++ ) {
+ coefs_syn[ i ] *= gain_syn;
+ coefs_ana[ i ] *= gain_ana;
+ }
+
+ /* Apply bandwidth expansion */
+ chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) );
+ silk_bwexpander_FLP( coefs_syn, order, chirp );
+ silk_bwexpander_FLP( coefs_ana, order, chirp );
+
+ /* Convert to monic warped coefficients */
+ for( i = order - 1; i > 0; i-- ) {
+ coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ];
+ coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ];
+ }
+ gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] );
+ gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] );
+ for( i = 0; i < order; i++ ) {
+ coefs_syn[ i ] *= gain_syn;
+ coefs_ana[ i ] *= gain_ana;
+ }
+ }
+ silk_assert( 0 );
+}
+
+/* Compute noise shaping coefficients and initial gain values */
+void silk_noise_shape_analysis_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float *pitch_res, /* I LPC residual from pitch analysis */
+ const silk_float *x /* I Input signal [frame_length + la_shape] */
+)
+{
+ silk_shape_state_FLP *psShapeSt = &psEnc->sShape;
+ opus_int k, nSamples;
+ silk_float SNR_adj_dB, HarmBoost, HarmShapeGain, Tilt;
+ silk_float nrg, pre_nrg, log_energy, log_energy_prev, energy_variation;
+ silk_float delta, BWExp1, BWExp2, gain_mult, gain_add, strength, b, warping;
+ silk_float x_windowed[ SHAPE_LPC_WIN_MAX ];
+ silk_float auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ];
+ const silk_float *x_ptr, *pitch_res_ptr;
+
+ /* Point to start of first LPC analysis block */
+ x_ptr = x - psEnc->sCmn.la_shape;
+
+ /****************/
+ /* GAIN CONTROL */
+ /****************/
+ SNR_adj_dB = psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f );
+
+ /* Input quality is the average of the quality in the lowest two VAD bands */
+ psEncCtrl->input_quality = 0.5f * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] + psEnc->sCmn.input_quality_bands_Q15[ 1 ] ) * ( 1.0f / 32768.0f );
+
+ /* Coding quality level, between 0.0 and 1.0 */
+ psEncCtrl->coding_quality = silk_sigmoid( 0.25f * ( SNR_adj_dB - 20.0f ) );
+
+ if( psEnc->sCmn.useCBR == 0 ) {
+ /* Reduce coding SNR during low speech activity */
+ b = 1.0f - psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f );
+ SNR_adj_dB -= BG_SNR_DECR_dB * psEncCtrl->coding_quality * ( 0.5f + 0.5f * psEncCtrl->input_quality ) * b * b;
+ }
+
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Reduce gains for periodic signals */
+ SNR_adj_dB += HARM_SNR_INCR_dB * psEnc->LTPCorr;
+ } else {
+ /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
+ SNR_adj_dB += ( -0.4f * psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) + 6.0f ) * ( 1.0f - psEncCtrl->input_quality );
+ }
+
+ /*************************/
+ /* SPARSENESS PROCESSING */
+ /*************************/
+ /* Set quantizer offset */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Initially set to 0; may be overruled in process_gains(..) */
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ psEncCtrl->sparseness = 0.0f;
+ } else {
+ /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
+ nSamples = 2 * psEnc->sCmn.fs_kHz;
+ energy_variation = 0.0f;
+ log_energy_prev = 0.0f;
+ pitch_res_ptr = pitch_res;
+ for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) {
+ nrg = ( silk_float )nSamples + ( silk_float )silk_energy_FLP( pitch_res_ptr, nSamples );
+ log_energy = silk_log2( nrg );
+ if( k > 0 ) {
+ energy_variation += silk_abs_float( log_energy - log_energy_prev );
+ }
+ log_energy_prev = log_energy;
+ pitch_res_ptr += nSamples;
+ }
+ psEncCtrl->sparseness = silk_sigmoid( 0.4f * ( energy_variation - 5.0f ) );
+
+ /* Set quantization offset depending on sparseness measure */
+ if( psEncCtrl->sparseness > SPARSENESS_THRESHOLD_QNT_OFFSET ) {
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ } else {
+ psEnc->sCmn.indices.quantOffsetType = 1;
+ }
+
+ /* Increase coding SNR for sparse signals */
+ SNR_adj_dB += SPARSE_SNR_INCR_dB * ( psEncCtrl->sparseness - 0.5f );
+ }
+
+ /*******************************/
+ /* Control bandwidth expansion */
+ /*******************************/
+ /* More BWE for signals with high prediction gain */
+ strength = FIND_PITCH_WHITE_NOISE_FRACTION * psEncCtrl->predGain; /* between 0.0 and 1.0 */
+ BWExp1 = BWExp2 = BANDWIDTH_EXPANSION / ( 1.0f + strength * strength );
+ delta = LOW_RATE_BANDWIDTH_EXPANSION_DELTA * ( 1.0f - 0.75f * psEncCtrl->coding_quality );
+ BWExp1 -= delta;
+ BWExp2 += delta;
+ /* BWExp1 will be applied after BWExp2, so make it relative */
+ BWExp1 /= BWExp2;
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
+ warping = (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f + 0.01f * psEncCtrl->coding_quality;
+ } else {
+ warping = 0.0f;
+ }
+
+ /********************************************/
+ /* Compute noise shaping AR coefs and gains */
+ /********************************************/
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Apply window: sine slope followed by flat part followed by cosine slope */
+ opus_int shift, slope_part, flat_part;
+ flat_part = psEnc->sCmn.fs_kHz * 3;
+ slope_part = ( psEnc->sCmn.shapeWinLength - flat_part ) / 2;
+
+ silk_apply_sine_window_FLP( x_windowed, x_ptr, 1, slope_part );
+ shift = slope_part;
+ silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(silk_float) );
+ shift += flat_part;
+ silk_apply_sine_window_FLP( x_windowed + shift, x_ptr + shift, 2, slope_part );
+
+ /* Update pointer: next LPC analysis block */
+ x_ptr += psEnc->sCmn.subfr_length;
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Calculate warped auto correlation */
+ silk_warped_autocorrelation_FLP( auto_corr, x_windowed, warping,
+ psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder );
+ } else {
+ /* Calculate regular auto correlation */
+ silk_autocorrelation_FLP( auto_corr, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 );
+ }
+
+ /* Add white noise, as a fraction of energy */
+ auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION;
+
+ /* Convert correlations to prediction coefficients, and compute residual energy */
+ nrg = silk_levinsondurbin_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], auto_corr, psEnc->sCmn.shapingLPCOrder );
+ psEncCtrl->Gains[ k ] = ( silk_float )sqrt( nrg );
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Adjust gain for warping */
+ psEncCtrl->Gains[ k ] *= warped_gain( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], warping, psEnc->sCmn.shapingLPCOrder );
+ }
+
+ /* Bandwidth expansion for synthesis filter shaping */
+ silk_bwexpander_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp2 );
+
+ /* Compute noise shaping filter coefficients */
+ silk_memcpy(
+ &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ],
+ &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ],
+ psEnc->sCmn.shapingLPCOrder * sizeof( silk_float ) );
+
+ /* Bandwidth expansion for analysis filter shaping */
+ silk_bwexpander_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp1 );
+
+ /* Ratio of prediction gains, in energy domain */
+ pre_nrg = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder );
+ nrg = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder );
+ psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg );
+
+ /* Convert to monic warped prediction coefficients and limit absolute values */
+ warped_true2monic_coefs( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ],
+ warping, 3.999f, psEnc->sCmn.shapingLPCOrder );
+ }
+
+ /*****************/
+ /* Gain tweaking */
+ /*****************/
+ /* Increase gains during low speech activity */
+ gain_mult = (silk_float)pow( 2.0f, -0.16f * SNR_adj_dB );
+ gain_add = (silk_float)pow( 2.0f, 0.16f * MIN_QGAIN_DB );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains[ k ] *= gain_mult;
+ psEncCtrl->Gains[ k ] += gain_add;
+ }
+
+ gain_mult = 1.0f + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT;
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->GainsPre[ k ] *= gain_mult;
+ }
+
+ /************************************************/
+ /* Control low-frequency shaping and noise tilt */
+ /************************************************/
+ /* Less low frequency shaping for noisy inputs */
+ strength = LOW_FREQ_SHAPING * ( 1.0f + LOW_QUALITY_LOW_FREQ_SHAPING_DECR * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] * ( 1.0f / 32768.0f ) - 1.0f ) );
+ strength *= psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f );
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
+ /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ b = 0.2f / psEnc->sCmn.fs_kHz + 3.0f / psEncCtrl->pitchL[ k ];
+ psEncCtrl->LF_MA_shp[ k ] = -1.0f + b;
+ psEncCtrl->LF_AR_shp[ k ] = 1.0f - b - b * strength;
+ }
+ Tilt = - HP_NOISE_COEF -
+ (1 - HP_NOISE_COEF) * HARM_HP_NOISE_COEF * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f );
+ } else {
+ b = 1.3f / psEnc->sCmn.fs_kHz;
+ psEncCtrl->LF_MA_shp[ 0 ] = -1.0f + b;
+ psEncCtrl->LF_AR_shp[ 0 ] = 1.0f - b - b * strength * 0.6f;
+ for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->LF_MA_shp[ k ] = psEncCtrl->LF_MA_shp[ 0 ];
+ psEncCtrl->LF_AR_shp[ k ] = psEncCtrl->LF_AR_shp[ 0 ];
+ }
+ Tilt = -HP_NOISE_COEF;
+ }
+
+ /****************************/
+ /* HARMONIC SHAPING CONTROL */
+ /****************************/
+ /* Control boosting of harmonic frequencies */
+ HarmBoost = LOW_RATE_HARMONIC_BOOST * ( 1.0f - psEncCtrl->coding_quality ) * psEnc->LTPCorr;
+
+ /* More harmonic boost for noisy input signals */
+ HarmBoost += LOW_INPUT_QUALITY_HARMONIC_BOOST * ( 1.0f - psEncCtrl->input_quality );
+
+ if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Harmonic noise shaping */
+ HarmShapeGain = HARMONIC_SHAPING;
+
+ /* More harmonic noise shaping for high bitrates or noisy input */
+ HarmShapeGain += HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING *
+ ( 1.0f - ( 1.0f - psEncCtrl->coding_quality ) * psEncCtrl->input_quality );
+
+ /* Less harmonic noise shaping for less periodic signals */
+ HarmShapeGain *= ( silk_float )sqrt( psEnc->LTPCorr );
+ } else {
+ HarmShapeGain = 0.0f;
+ }
+
+ /*************************/
+ /* Smooth over subframes */
+ /*************************/
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psShapeSt->HarmBoost_smth += SUBFR_SMTH_COEF * ( HarmBoost - psShapeSt->HarmBoost_smth );
+ psEncCtrl->HarmBoost[ k ] = psShapeSt->HarmBoost_smth;
+ psShapeSt->HarmShapeGain_smth += SUBFR_SMTH_COEF * ( HarmShapeGain - psShapeSt->HarmShapeGain_smth );
+ psEncCtrl->HarmShapeGain[ k ] = psShapeSt->HarmShapeGain_smth;
+ psShapeSt->Tilt_smth += SUBFR_SMTH_COEF * ( Tilt - psShapeSt->Tilt_smth );
+ psEncCtrl->Tilt[ k ] = psShapeSt->Tilt_smth;
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/pitch_analysis_core_FLP.c b/external/opus-1.1.4/silk/float/pitch_analysis_core_FLP.c
new file mode 100644
index 0000000..d0e637a
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/pitch_analysis_core_FLP.c
@@ -0,0 +1,630 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*****************************************************************************
+* Pitch analyser function
+******************************************************************************/
+#include "SigProc_FLP.h"
+#include "SigProc_FIX.h"
+#include "pitch_est_defines.h"
+#include "pitch.h"
+
+#define SCRATCH_SIZE 22
+
+/************************************************************/
+/* Internally used functions */
+/************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+ silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+ const silk_float frame[], /* I vector to correlate */
+ opus_int start_lag, /* I start lag */
+ opus_int sf_length, /* I sub frame length */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+);
+
+static void silk_P_Ana_calc_energy_st3(
+ silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+ const silk_float frame[], /* I vector to correlate */
+ opus_int start_lag, /* I start lag */
+ opus_int sf_length, /* I sub frame length */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity /* I Complexity setting */
+);
+
+/************************************************************/
+/* CORE PITCH ANALYSIS FUNCTION */
+/************************************************************/
+opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */
+ const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
+ opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */
+ opus_int16 *lagIndex, /* O Lag Index */
+ opus_int8 *contourIndex, /* O Pitch contour Index */
+ silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */
+ opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
+ const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */
+ const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */
+ const opus_int Fs_kHz, /* I sample frequency (kHz) */
+ const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
+ const opus_int nb_subfr, /* I Number of 5 ms subframes */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int i, k, d, j;
+ silk_float frame_8kHz[ PE_MAX_FRAME_LENGTH_MS * 8 ];
+ silk_float frame_4kHz[ PE_MAX_FRAME_LENGTH_MS * 4 ];
+ opus_int16 frame_8_FIX[ PE_MAX_FRAME_LENGTH_MS * 8 ];
+ opus_int16 frame_4_FIX[ PE_MAX_FRAME_LENGTH_MS * 4 ];
+ opus_int32 filt_state[ 6 ];
+ silk_float threshold, contour_bias;
+ silk_float C[ PE_MAX_NB_SUBFR][ (PE_MAX_LAG >> 1) + 5 ];
+ opus_val32 xcorr[ PE_MAX_LAG_MS * 4 - PE_MIN_LAG_MS * 4 + 1 ];
+ silk_float CC[ PE_NB_CBKS_STAGE2_EXT ];
+ const silk_float *target_ptr, *basis_ptr;
+ double cross_corr, normalizer, energy, energy_tmp;
+ opus_int d_srch[ PE_D_SRCH_LENGTH ];
+ opus_int16 d_comp[ (PE_MAX_LAG >> 1) + 5 ];
+ opus_int length_d_srch, length_d_comp;
+ silk_float Cmax, CCmax, CCmax_b, CCmax_new_b, CCmax_new;
+ opus_int CBimax, CBimax_new, lag, start_lag, end_lag, lag_new;
+ opus_int cbk_size;
+ silk_float lag_log2, prevLag_log2, delta_lag_log2_sqr;
+ silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ];
+ silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ];
+ opus_int lag_counter;
+ opus_int frame_length, frame_length_8kHz, frame_length_4kHz;
+ opus_int sf_length, sf_length_8kHz, sf_length_4kHz;
+ opus_int min_lag, min_lag_8kHz, min_lag_4kHz;
+ opus_int max_lag, max_lag_8kHz, max_lag_4kHz;
+ opus_int nb_cbk_search;
+ const opus_int8 *Lag_CB_ptr;
+
+ /* Check for valid sampling frequency */
+ silk_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 );
+
+ /* Check for valid complexity setting */
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ silk_assert( search_thres1 >= 0.0f && search_thres1 <= 1.0f );
+ silk_assert( search_thres2 >= 0.0f && search_thres2 <= 1.0f );
+
+ /* Set up frame lengths max / min lag for the sampling frequency */
+ frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz;
+ frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4;
+ frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8;
+ sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz;
+ sf_length_4kHz = PE_SUBFR_LENGTH_MS * 4;
+ sf_length_8kHz = PE_SUBFR_LENGTH_MS * 8;
+ min_lag = PE_MIN_LAG_MS * Fs_kHz;
+ min_lag_4kHz = PE_MIN_LAG_MS * 4;
+ min_lag_8kHz = PE_MIN_LAG_MS * 8;
+ max_lag = PE_MAX_LAG_MS * Fs_kHz - 1;
+ max_lag_4kHz = PE_MAX_LAG_MS * 4;
+ max_lag_8kHz = PE_MAX_LAG_MS * 8 - 1;
+
+ /* Resample from input sampled at Fs_kHz to 8 kHz */
+ if( Fs_kHz == 16 ) {
+ /* Resample to 16 -> 8 khz */
+ opus_int16 frame_16_FIX[ 16 * PE_MAX_FRAME_LENGTH_MS ];
+ silk_float2short_array( frame_16_FIX, frame, frame_length );
+ silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
+ silk_resampler_down2( filt_state, frame_8_FIX, frame_16_FIX, frame_length );
+ silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz );
+ } else if( Fs_kHz == 12 ) {
+ /* Resample to 12 -> 8 khz */
+ opus_int16 frame_12_FIX[ 12 * PE_MAX_FRAME_LENGTH_MS ];
+ silk_float2short_array( frame_12_FIX, frame, frame_length );
+ silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) );
+ silk_resampler_down2_3( filt_state, frame_8_FIX, frame_12_FIX, frame_length );
+ silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz );
+ } else {
+ silk_assert( Fs_kHz == 8 );
+ silk_float2short_array( frame_8_FIX, frame, frame_length_8kHz );
+ }
+
+ /* Decimate again to 4 kHz */
+ silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
+ silk_resampler_down2( filt_state, frame_4_FIX, frame_8_FIX, frame_length_8kHz );
+ silk_short2float_array( frame_4kHz, frame_4_FIX, frame_length_4kHz );
+
+ /* Low-pass filter */
+ for( i = frame_length_4kHz - 1; i > 0; i-- ) {
+ frame_4kHz[ i ] += frame_4kHz[ i - 1 ];
+ }
+
+ /******************************************************************************
+ * FIRST STAGE, operating in 4 khz
+ ******************************************************************************/
+ silk_memset(C, 0, sizeof(silk_float) * nb_subfr * ((PE_MAX_LAG >> 1) + 5));
+ target_ptr = &frame_4kHz[ silk_LSHIFT( sf_length_4kHz, 2 ) ];
+ for( k = 0; k < nb_subfr >> 1; k++ ) {
+ /* Check that we are within range of the array */
+ silk_assert( target_ptr >= frame_4kHz );
+ silk_assert( target_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
+
+ basis_ptr = target_ptr - min_lag_4kHz;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_4kHz );
+ silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
+
+ celt_pitch_xcorr( target_ptr, target_ptr-max_lag_4kHz, xcorr, sf_length_8kHz, max_lag_4kHz - min_lag_4kHz + 1, arch );
+
+ /* Calculate first vector products before loop */
+ cross_corr = xcorr[ max_lag_4kHz - min_lag_4kHz ];
+ normalizer = silk_energy_FLP( target_ptr, sf_length_8kHz ) +
+ silk_energy_FLP( basis_ptr, sf_length_8kHz ) +
+ sf_length_8kHz * 4000.0f;
+
+ C[ 0 ][ min_lag_4kHz ] += (silk_float)( 2 * cross_corr / normalizer );
+
+ /* From now on normalizer is computed recursively */
+ for( d = min_lag_4kHz + 1; d <= max_lag_4kHz; d++ ) {
+ basis_ptr--;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_4kHz );
+ silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
+
+ cross_corr = xcorr[ max_lag_4kHz - d ];
+
+ /* Add contribution of new sample and remove contribution from oldest sample */
+ normalizer +=
+ basis_ptr[ 0 ] * (double)basis_ptr[ 0 ] -
+ basis_ptr[ sf_length_8kHz ] * (double)basis_ptr[ sf_length_8kHz ];
+ C[ 0 ][ d ] += (silk_float)( 2 * cross_corr / normalizer );
+ }
+ /* Update target pointer */
+ target_ptr += sf_length_8kHz;
+ }
+
+ /* Apply short-lag bias */
+ for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) {
+ C[ 0 ][ i ] -= C[ 0 ][ i ] * i / 4096.0f;
+ }
+
+ /* Sort */
+ length_d_srch = 4 + 2 * complexity;
+ silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH );
+ silk_insertion_sort_decreasing_FLP( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch );
+
+ /* Escape if correlation is very low already here */
+ Cmax = C[ 0 ][ min_lag_4kHz ];
+ if( Cmax < 0.2f ) {
+ silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
+ *LTPCorr = 0.0f;
+ *lagIndex = 0;
+ *contourIndex = 0;
+ return 1;
+ }
+
+ threshold = search_thres1 * Cmax;
+ for( i = 0; i < length_d_srch; i++ ) {
+ /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */
+ if( C[ 0 ][ min_lag_4kHz + i ] > threshold ) {
+ d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 );
+ } else {
+ length_d_srch = i;
+ break;
+ }
+ }
+ silk_assert( length_d_srch > 0 );
+
+ for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) {
+ d_comp[ i ] = 0;
+ }
+ for( i = 0; i < length_d_srch; i++ ) {
+ d_comp[ d_srch[ i ] ] = 1;
+ }
+
+ /* Convolution */
+ for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) {
+ d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ];
+ }
+
+ length_d_srch = 0;
+ for( i = min_lag_8kHz; i < max_lag_8kHz + 1; i++ ) {
+ if( d_comp[ i + 1 ] > 0 ) {
+ d_srch[ length_d_srch ] = i;
+ length_d_srch++;
+ }
+ }
+
+ /* Convolution */
+ for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) {
+ d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ] + d_comp[ i - 3 ];
+ }
+
+ length_d_comp = 0;
+ for( i = min_lag_8kHz; i < max_lag_8kHz + 4; i++ ) {
+ if( d_comp[ i ] > 0 ) {
+ d_comp[ length_d_comp ] = (opus_int16)( i - 2 );
+ length_d_comp++;
+ }
+ }
+
+ /**********************************************************************************
+ ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation
+ *************************************************************************************/
+ /*********************************************************************************
+ * Find energy of each subframe projected onto its history, for a range of delays
+ *********************************************************************************/
+ silk_memset( C, 0, PE_MAX_NB_SUBFR*((PE_MAX_LAG >> 1) + 5) * sizeof(silk_float));
+
+ if( Fs_kHz == 8 ) {
+ target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * 8 ];
+ } else {
+ target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ];
+ }
+ for( k = 0; k < nb_subfr; k++ ) {
+ energy_tmp = silk_energy_FLP( target_ptr, sf_length_8kHz ) + 1.0;
+ for( j = 0; j < length_d_comp; j++ ) {
+ d = d_comp[ j ];
+ basis_ptr = target_ptr - d;
+ cross_corr = silk_inner_product_FLP( basis_ptr, target_ptr, sf_length_8kHz );
+ if( cross_corr > 0.0f ) {
+ energy = silk_energy_FLP( basis_ptr, sf_length_8kHz );
+ C[ k ][ d ] = (silk_float)( 2 * cross_corr / ( energy + energy_tmp ) );
+ } else {
+ C[ k ][ d ] = 0.0f;
+ }
+ }
+ target_ptr += sf_length_8kHz;
+ }
+
+ /* search over lag range and lags codebook */
+ /* scale factor for lag codebook, as a function of center lag */
+
+ CCmax = 0.0f; /* This value doesn't matter */
+ CCmax_b = -1000.0f;
+
+ CBimax = 0; /* To avoid returning undefined lag values */
+ lag = -1; /* To check if lag with strong enough correlation has been found */
+
+ if( prevLag > 0 ) {
+ if( Fs_kHz == 12 ) {
+ prevLag = silk_LSHIFT( prevLag, 1 ) / 3;
+ } else if( Fs_kHz == 16 ) {
+ prevLag = silk_RSHIFT( prevLag, 1 );
+ }
+ prevLag_log2 = silk_log2( (silk_float)prevLag );
+ } else {
+ prevLag_log2 = 0;
+ }
+
+ /* Set up stage 2 codebook based on number of subframes */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ cbk_size = PE_NB_CBKS_STAGE2_EXT;
+ Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
+ if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) {
+ /* If input is 8 khz use a larger codebook here because it is last stage */
+ nb_cbk_search = PE_NB_CBKS_STAGE2_EXT;
+ } else {
+ nb_cbk_search = PE_NB_CBKS_STAGE2;
+ }
+ } else {
+ cbk_size = PE_NB_CBKS_STAGE2_10MS;
+ Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE2_10MS;
+ }
+
+ for( k = 0; k < length_d_srch; k++ ) {
+ d = d_srch[ k ];
+ for( j = 0; j < nb_cbk_search; j++ ) {
+ CC[j] = 0.0f;
+ for( i = 0; i < nb_subfr; i++ ) {
+ /* Try all codebooks */
+ CC[ j ] += C[ i ][ d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size )];
+ }
+ }
+ /* Find best codebook */
+ CCmax_new = -1000.0f;
+ CBimax_new = 0;
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ if( CC[ i ] > CCmax_new ) {
+ CCmax_new = CC[ i ];
+ CBimax_new = i;
+ }
+ }
+
+ /* Bias towards shorter lags */
+ lag_log2 = silk_log2( (silk_float)d );
+ CCmax_new_b = CCmax_new - PE_SHORTLAG_BIAS * nb_subfr * lag_log2;
+
+ /* Bias towards previous lag */
+ if( prevLag > 0 ) {
+ delta_lag_log2_sqr = lag_log2 - prevLag_log2;
+ delta_lag_log2_sqr *= delta_lag_log2_sqr;
+ CCmax_new_b -= PE_PREVLAG_BIAS * nb_subfr * (*LTPCorr) * delta_lag_log2_sqr / ( delta_lag_log2_sqr + 0.5f );
+ }
+
+ if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */
+ CCmax_new > nb_subfr * search_thres2 /* Correlation needs to be high enough to be voiced */
+ ) {
+ CCmax_b = CCmax_new_b;
+ CCmax = CCmax_new;
+ lag = d;
+ CBimax = CBimax_new;
+ }
+ }
+
+ if( lag == -1 ) {
+ /* No suitable candidate found */
+ silk_memset( pitch_out, 0, PE_MAX_NB_SUBFR * sizeof(opus_int) );
+ *LTPCorr = 0.0f;
+ *lagIndex = 0;
+ *contourIndex = 0;
+ return 1;
+ }
+
+ /* Output normalized correlation */
+ *LTPCorr = (silk_float)( CCmax / nb_subfr );
+ silk_assert( *LTPCorr >= 0.0f );
+
+ if( Fs_kHz > 8 ) {
+ /* Search in original signal */
+
+ /* Compensate for decimation */
+ silk_assert( lag == silk_SAT16( lag ) );
+ if( Fs_kHz == 12 ) {
+ lag = silk_RSHIFT_ROUND( silk_SMULBB( lag, 3 ), 1 );
+ } else { /* Fs_kHz == 16 */
+ lag = silk_LSHIFT( lag, 1 );
+ }
+
+ lag = silk_LIMIT_int( lag, min_lag, max_lag );
+ start_lag = silk_max_int( lag - 2, min_lag );
+ end_lag = silk_min_int( lag + 2, max_lag );
+ lag_new = lag; /* to avoid undefined lag */
+ CBimax = 0; /* to avoid undefined lag */
+
+ CCmax = -1000.0f;
+
+ /* Calculate the correlations and energies needed in stage 3 */
+ silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch );
+ silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity );
+
+ lag_counter = 0;
+ silk_assert( lag == silk_SAT16( lag ) );
+ contour_bias = PE_FLATCONTOUR_BIAS / lag;
+
+ /* Set up cbk parameters according to complexity setting and frame length */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ } else {
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ }
+
+ target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ];
+ energy_tmp = silk_energy_FLP( target_ptr, nb_subfr * sf_length ) + 1.0;
+ for( d = start_lag; d <= end_lag; d++ ) {
+ for( j = 0; j < nb_cbk_search; j++ ) {
+ cross_corr = 0.0;
+ energy = energy_tmp;
+ for( k = 0; k < nb_subfr; k++ ) {
+ cross_corr += cross_corr_st3[ k ][ j ][ lag_counter ];
+ energy += energies_st3[ k ][ j ][ lag_counter ];
+ }
+ if( cross_corr > 0.0 ) {
+ CCmax_new = (silk_float)( 2 * cross_corr / energy );
+ /* Reduce depending on flatness of contour */
+ CCmax_new *= 1.0f - contour_bias * j;
+ } else {
+ CCmax_new = 0.0f;
+ }
+
+ if( CCmax_new > CCmax && ( d + (opus_int)silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) {
+ CCmax = CCmax_new;
+ lag_new = d;
+ CBimax = j;
+ }
+ }
+ lag_counter++;
+ }
+
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+ pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz );
+ }
+ *lagIndex = (opus_int16)( lag_new - min_lag );
+ *contourIndex = (opus_int8)CBimax;
+ } else { /* Fs_kHz == 8 */
+ /* Save Lags */
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+ pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag_8kHz, PE_MAX_LAG_MS * 8 );
+ }
+ *lagIndex = (opus_int16)( lag - min_lag_8kHz );
+ *contourIndex = (opus_int8)CBimax;
+ }
+ silk_assert( *lagIndex >= 0 );
+ /* return as voiced */
+ return 0;
+}
+
+/***********************************************************************
+ * Calculates the correlations used in stage 3 search. In order to cover
+ * the whole lag codebook for all the searched offset lags (lag +- 2),
+ * the following correlations are needed in each sub frame:
+ *
+ * sf1: lag range [-8,...,7] total 16 correlations
+ * sf2: lag range [-4,...,4] total 9 correlations
+ * sf3: lag range [-3,....4] total 8 correltions
+ * sf4: lag range [-6,....8] total 15 correlations
+ *
+ * In total 48 correlations. The direct implementation computed in worst
+ * case 4*12*5 = 240 correlations, but more likely around 120.
+ ***********************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+ silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+ const silk_float frame[], /* I vector to correlate */
+ opus_int start_lag, /* I start lag */
+ opus_int sf_length, /* I sub frame length */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+)
+{
+ const silk_float *target_ptr;
+ opus_int i, j, k, lag_counter, lag_low, lag_high;
+ opus_int nb_cbk_search, delta, idx, cbk_size;
+ silk_float scratch_mem[ SCRATCH_SIZE ];
+ opus_val32 xcorr[ SCRATCH_SIZE ];
+ const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+
+ target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_counter = 0;
+
+ /* Calculate the correlations for each subframe */
+ lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 );
+ silk_assert(lag_high-lag_low+1 <= SCRATCH_SIZE);
+ celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr, sf_length, lag_high - lag_low + 1, arch );
+ for( j = lag_low; j <= lag_high; j++ ) {
+ silk_assert( lag_counter < SCRATCH_SIZE );
+ scratch_mem[ lag_counter ] = xcorr[ lag_high - j ];
+ lag_counter++;
+ }
+
+ delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ /* Fill out the 3 dim array that stores the correlations for */
+ /* each code_book vector for each start lag */
+ idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+ for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+ silk_assert( idx + j < SCRATCH_SIZE );
+ silk_assert( idx + j < lag_counter );
+ cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ];
+ }
+ }
+ target_ptr += sf_length;
+ }
+}
+
+/********************************************************************/
+/* Calculate the energies for first two subframes. The energies are */
+/* calculated recursively. */
+/********************************************************************/
+static void silk_P_Ana_calc_energy_st3(
+ silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+ const silk_float frame[], /* I vector to correlate */
+ opus_int start_lag, /* I start lag */
+ opus_int sf_length, /* I sub frame length */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity /* I Complexity setting */
+)
+{
+ const silk_float *target_ptr, *basis_ptr;
+ double energy;
+ opus_int k, i, j, lag_counter;
+ opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff;
+ silk_float scratch_mem[ SCRATCH_SIZE ];
+ const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+
+ target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ];
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_counter = 0;
+
+ /* Calculate the energy for first lag */
+ basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) );
+ energy = silk_energy_FLP( basis_ptr, sf_length ) + 1e-3;
+ silk_assert( energy >= 0.0 );
+ scratch_mem[lag_counter] = (silk_float)energy;
+ lag_counter++;
+
+ lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 );
+ for( i = 1; i < lag_diff; i++ ) {
+ /* remove part outside new window */
+ energy -= basis_ptr[sf_length - i] * (double)basis_ptr[sf_length - i];
+ silk_assert( energy >= 0.0 );
+
+ /* add part that comes into window */
+ energy += basis_ptr[ -i ] * (double)basis_ptr[ -i ];
+ silk_assert( energy >= 0.0 );
+ silk_assert( lag_counter < SCRATCH_SIZE );
+ scratch_mem[lag_counter] = (silk_float)energy;
+ lag_counter++;
+ }
+
+ delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ /* Fill out the 3 dim array that stores the correlations for */
+ /* each code_book vector for each start lag */
+ idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+ for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+ silk_assert( idx + j < SCRATCH_SIZE );
+ silk_assert( idx + j < lag_counter );
+ energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ];
+ silk_assert( energies_st3[ k ][ i ][ j ] >= 0.0f );
+ }
+ }
+ target_ptr += sf_length;
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/prefilter_FLP.c b/external/opus-1.1.4/silk/float/prefilter_FLP.c
new file mode 100644
index 0000000..8bc32fb
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/prefilter_FLP.c
@@ -0,0 +1,206 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/*
+* Prefilter for finding Quantizer input signal
+*/
+static OPUS_INLINE void silk_prefilt_FLP(
+ silk_prefilter_state_FLP *P, /* I/O state */
+ silk_float st_res[], /* I */
+ silk_float xw[], /* O */
+ silk_float *HarmShapeFIR, /* I */
+ silk_float Tilt, /* I */
+ silk_float LF_MA_shp, /* I */
+ silk_float LF_AR_shp, /* I */
+ opus_int lag, /* I */
+ opus_int length /* I */
+);
+
+static void silk_warped_LPC_analysis_filter_FLP(
+ silk_float state[], /* I/O State [order + 1] */
+ silk_float res[], /* O Residual signal [length] */
+ const silk_float coef[], /* I Coefficients [order] */
+ const silk_float input[], /* I Input signal [length] */
+ const silk_float lambda, /* I Warping factor */
+ const opus_int length, /* I Length of input signal */
+ const opus_int order /* I Filter order (even) */
+)
+{
+ opus_int n, i;
+ silk_float acc, tmp1, tmp2;
+
+ /* Order must be even */
+ silk_assert( ( order & 1 ) == 0 );
+
+ for( n = 0; n < length; n++ ) {
+ /* Output of lowpass section */
+ tmp2 = state[ 0 ] + lambda * state[ 1 ];
+ state[ 0 ] = input[ n ];
+ /* Output of allpass section */
+ tmp1 = state[ 1 ] + lambda * ( state[ 2 ] - tmp2 );
+ state[ 1 ] = tmp2;
+ acc = coef[ 0 ] * tmp2;
+ /* Loop over allpass sections */
+ for( i = 2; i < order; i += 2 ) {
+ /* Output of allpass section */
+ tmp2 = state[ i ] + lambda * ( state[ i + 1 ] - tmp1 );
+ state[ i ] = tmp1;
+ acc += coef[ i - 1 ] * tmp1;
+ /* Output of allpass section */
+ tmp1 = state[ i + 1 ] + lambda * ( state[ i + 2 ] - tmp2 );
+ state[ i + 1 ] = tmp2;
+ acc += coef[ i ] * tmp2;
+ }
+ state[ order ] = tmp1;
+ acc += coef[ order - 1 ] * tmp1;
+ res[ n ] = input[ n ] - acc;
+ }
+}
+
+/*
+* silk_prefilter. Main prefilter function
+*/
+void silk_prefilter_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ const silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */
+ silk_float xw[], /* O Weighted signal */
+ const silk_float x[] /* I Speech signal */
+)
+{
+ silk_prefilter_state_FLP *P = &psEnc->sPrefilt;
+ opus_int j, k, lag;
+ silk_float HarmShapeGain, Tilt, LF_MA_shp, LF_AR_shp;
+ silk_float B[ 2 ];
+ const silk_float *AR1_shp;
+ const silk_float *px;
+ silk_float *pxw;
+ silk_float HarmShapeFIR[ 3 ];
+ silk_float st_res[ MAX_SUB_FRAME_LENGTH + MAX_LPC_ORDER ];
+
+ /* Set up pointers */
+ px = x;
+ pxw = xw;
+ lag = P->lagPrev;
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Update Variables that change per sub frame */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ lag = psEncCtrl->pitchL[ k ];
+ }
+
+ /* Noise shape parameters */
+ HarmShapeGain = psEncCtrl->HarmShapeGain[ k ] * ( 1.0f - psEncCtrl->HarmBoost[ k ] );
+ HarmShapeFIR[ 0 ] = 0.25f * HarmShapeGain;
+ HarmShapeFIR[ 1 ] = 32767.0f / 65536.0f * HarmShapeGain;
+ HarmShapeFIR[ 2 ] = 0.25f * HarmShapeGain;
+ Tilt = psEncCtrl->Tilt[ k ];
+ LF_MA_shp = psEncCtrl->LF_MA_shp[ k ];
+ LF_AR_shp = psEncCtrl->LF_AR_shp[ k ];
+ AR1_shp = &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Short term FIR filtering */
+ silk_warped_LPC_analysis_filter_FLP( P->sAR_shp, st_res, AR1_shp, px,
+ (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder );
+
+ /* Reduce (mainly) low frequencies during harmonic emphasis */
+ B[ 0 ] = psEncCtrl->GainsPre[ k ];
+ B[ 1 ] = -psEncCtrl->GainsPre[ k ] *
+ ( psEncCtrl->HarmBoost[ k ] * HarmShapeGain + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT );
+ pxw[ 0 ] = B[ 0 ] * st_res[ 0 ] + B[ 1 ] * P->sHarmHP;
+ for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) {
+ pxw[ j ] = B[ 0 ] * st_res[ j ] + B[ 1 ] * st_res[ j - 1 ];
+ }
+ P->sHarmHP = st_res[ psEnc->sCmn.subfr_length - 1 ];
+
+ silk_prefilt_FLP( P, pxw, pxw, HarmShapeFIR, Tilt, LF_MA_shp, LF_AR_shp, lag, psEnc->sCmn.subfr_length );
+
+ px += psEnc->sCmn.subfr_length;
+ pxw += psEnc->sCmn.subfr_length;
+ }
+ P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+}
+
+/*
+* Prefilter for finding Quantizer input signal
+*/
+static OPUS_INLINE void silk_prefilt_FLP(
+ silk_prefilter_state_FLP *P, /* I/O state */
+ silk_float st_res[], /* I */
+ silk_float xw[], /* O */
+ silk_float *HarmShapeFIR, /* I */
+ silk_float Tilt, /* I */
+ silk_float LF_MA_shp, /* I */
+ silk_float LF_AR_shp, /* I */
+ opus_int lag, /* I */
+ opus_int length /* I */
+)
+{
+ opus_int i;
+ opus_int idx, LTP_shp_buf_idx;
+ silk_float n_Tilt, n_LF, n_LTP;
+ silk_float sLF_AR_shp, sLF_MA_shp;
+ silk_float *LTP_shp_buf;
+
+ /* To speed up use temp variables instead of using the struct */
+ LTP_shp_buf = P->sLTP_shp;
+ LTP_shp_buf_idx = P->sLTP_shp_buf_idx;
+ sLF_AR_shp = P->sLF_AR_shp;
+ sLF_MA_shp = P->sLF_MA_shp;
+
+ for( i = 0; i < length; i++ ) {
+ if( lag > 0 ) {
+ silk_assert( HARM_SHAPE_FIR_TAPS == 3 );
+ idx = lag + LTP_shp_buf_idx;
+ n_LTP = LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ] * HarmShapeFIR[ 0 ];
+ n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ] * HarmShapeFIR[ 1 ];
+ n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ] * HarmShapeFIR[ 2 ];
+ } else {
+ n_LTP = 0;
+ }
+
+ n_Tilt = sLF_AR_shp * Tilt;
+ n_LF = sLF_AR_shp * LF_AR_shp + sLF_MA_shp * LF_MA_shp;
+
+ sLF_AR_shp = st_res[ i ] - n_Tilt;
+ sLF_MA_shp = sLF_AR_shp - n_LF;
+
+ LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK;
+ LTP_shp_buf[ LTP_shp_buf_idx ] = sLF_MA_shp;
+
+ xw[ i ] = sLF_MA_shp - n_LTP;
+ }
+ /* Copy temp variable back to state */
+ P->sLF_AR_shp = sLF_AR_shp;
+ P->sLF_MA_shp = sLF_MA_shp;
+ P->sLTP_shp_buf_idx = LTP_shp_buf_idx;
+}
diff --git a/external/opus-1.1.4/silk/float/process_gains_FLP.c b/external/opus-1.1.4/silk/float/process_gains_FLP.c
new file mode 100644
index 0000000..c0da0da
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/process_gains_FLP.c
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/* Processing of gains */
+void silk_process_gains_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ silk_shape_state_FLP *psShapeSt = &psEnc->sShape;
+ opus_int k;
+ opus_int32 pGains_Q16[ MAX_NB_SUBFR ];
+ silk_float s, InvMaxSqrVal, gain, quant_offset;
+
+ /* Gain reduction when LTP coding gain is high */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ s = 1.0f - 0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains[ k ] *= s;
+ }
+ }
+
+ /* Limit the quantized signal */
+ InvMaxSqrVal = ( silk_float )( pow( 2.0f, 0.33f * ( 21.0f - psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) ) ) / psEnc->sCmn.subfr_length );
+
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Soft limit on ratio residual energy and squared gains */
+ gain = psEncCtrl->Gains[ k ];
+ gain = ( silk_float )sqrt( gain * gain + psEncCtrl->ResNrg[ k ] * InvMaxSqrVal );
+ psEncCtrl->Gains[ k ] = silk_min_float( gain, 32767.0f );
+ }
+
+ /* Prepare gains for noise shaping quantization */
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ pGains_Q16[ k ] = (opus_int32)( psEncCtrl->Gains[ k ] * 65536.0f );
+ }
+
+ /* Save unquantized gains and gain Index */
+ silk_memcpy( psEncCtrl->GainsUnq_Q16, pGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+ psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
+
+ /* Quantize gains */
+ silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16,
+ &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains[ k ] = pGains_Q16[ k ] / 65536.0f;
+ }
+
+ /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ if( psEncCtrl->LTPredCodGain + psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ) > 1.0f ) {
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ } else {
+ psEnc->sCmn.indices.quantOffsetType = 1;
+ }
+ }
+
+ /* Quantizer boundary adjustment */
+ quant_offset = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ] / 1024.0f;
+ psEncCtrl->Lambda = LAMBDA_OFFSET
+ + LAMBDA_DELAYED_DECISIONS * psEnc->sCmn.nStatesDelayedDecision
+ + LAMBDA_SPEECH_ACT * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f )
+ + LAMBDA_INPUT_QUALITY * psEncCtrl->input_quality
+ + LAMBDA_CODING_QUALITY * psEncCtrl->coding_quality
+ + LAMBDA_QUANT_OFFSET * quant_offset;
+
+ silk_assert( psEncCtrl->Lambda > 0.0f );
+ silk_assert( psEncCtrl->Lambda < 2.0f );
+}
diff --git a/external/opus-1.1.4/silk/float/regularize_correlations_FLP.c b/external/opus-1.1.4/silk/float/regularize_correlations_FLP.c
new file mode 100644
index 0000000..df46126
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/regularize_correlations_FLP.c
@@ -0,0 +1,48 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FLP(
+ silk_float *XX, /* I/O Correlation matrices */
+ silk_float *xx, /* I/O Correlation values */
+ const silk_float noise, /* I Noise energy to add */
+ const opus_int D /* I Dimension of XX */
+)
+{
+ opus_int i;
+
+ for( i = 0; i < D; i++ ) {
+ matrix_ptr( &XX[ 0 ], i, i, D ) += noise;
+ }
+ xx[ 0 ] += noise;
+}
diff --git a/external/opus-1.1.4/silk/float/residual_energy_FLP.c b/external/opus-1.1.4/silk/float/residual_energy_FLP.c
new file mode 100644
index 0000000..b2e03a8
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/residual_energy_FLP.c
@@ -0,0 +1,117 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+#define MAX_ITERATIONS_RESIDUAL_NRG 10
+#define REGULARIZATION_FACTOR 1e-8f
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */
+ const silk_float *c, /* I Filter coefficients */
+ silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */
+ const silk_float *wXx, /* I Weighted correlation vector */
+ const silk_float wxx, /* I Weighted correlation value */
+ const opus_int D /* I Dimension */
+)
+{
+ opus_int i, j, k;
+ silk_float tmp, nrg = 0.0f, regularization;
+
+ /* Safety checks */
+ silk_assert( D >= 0 );
+
+ regularization = REGULARIZATION_FACTOR * ( wXX[ 0 ] + wXX[ D * D - 1 ] );
+ for( k = 0; k < MAX_ITERATIONS_RESIDUAL_NRG; k++ ) {
+ nrg = wxx;
+
+ tmp = 0.0f;
+ for( i = 0; i < D; i++ ) {
+ tmp += wXx[ i ] * c[ i ];
+ }
+ nrg -= 2.0f * tmp;
+
+ /* compute c' * wXX * c, assuming wXX is symmetric */
+ for( i = 0; i < D; i++ ) {
+ tmp = 0.0f;
+ for( j = i + 1; j < D; j++ ) {
+ tmp += matrix_c_ptr( wXX, i, j, D ) * c[ j ];
+ }
+ nrg += c[ i ] * ( 2.0f * tmp + matrix_c_ptr( wXX, i, i, D ) * c[ i ] );
+ }
+ if( nrg > 0 ) {
+ break;
+ } else {
+ /* Add white noise */
+ for( i = 0; i < D; i++ ) {
+ matrix_c_ptr( wXX, i, i, D ) += regularization;
+ }
+ /* Increase noise for next run */
+ regularization *= 2.0f;
+ }
+ }
+ if( k == MAX_ITERATIONS_RESIDUAL_NRG ) {
+ silk_assert( nrg == 0 );
+ nrg = 1.0f;
+ }
+
+ return nrg;
+}
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order */
+/* of preceding samples */
+void silk_residual_energy_FLP(
+ silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
+ const silk_float x[], /* I Input signal */
+ silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
+ const silk_float gains[], /* I Quantization gains */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int LPC_order /* I LPC order */
+)
+{
+ opus_int shift;
+ silk_float *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ) / 2 ];
+
+ LPC_res_ptr = LPC_res + LPC_order;
+ shift = LPC_order + subfr_length;
+
+ /* Filter input to create the LPC residual for each frame half, and measure subframe energies */
+ silk_LPC_analysis_filter_FLP( LPC_res, a[ 0 ], x + 0 * shift, 2 * shift, LPC_order );
+ nrgs[ 0 ] = ( silk_float )( gains[ 0 ] * gains[ 0 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) );
+ nrgs[ 1 ] = ( silk_float )( gains[ 1 ] * gains[ 1 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) );
+
+ if( nb_subfr == MAX_NB_SUBFR ) {
+ silk_LPC_analysis_filter_FLP( LPC_res, a[ 1 ], x + 2 * shift, 2 * shift, LPC_order );
+ nrgs[ 2 ] = ( silk_float )( gains[ 2 ] * gains[ 2 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) );
+ nrgs[ 3 ] = ( silk_float )( gains[ 3 ] * gains[ 3 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) );
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/scale_copy_vector_FLP.c b/external/opus-1.1.4/silk/float/scale_copy_vector_FLP.c
new file mode 100644
index 0000000..20db32b
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/scale_copy_vector_FLP.c
@@ -0,0 +1,57 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* copy and multiply a vector by a constant */
+void silk_scale_copy_vector_FLP(
+ silk_float *data_out,
+ const silk_float *data_in,
+ silk_float gain,
+ opus_int dataSize
+)
+{
+ opus_int i, dataSize4;
+
+ /* 4x unrolled loop */
+ dataSize4 = dataSize & 0xFFFC;
+ for( i = 0; i < dataSize4; i += 4 ) {
+ data_out[ i + 0 ] = gain * data_in[ i + 0 ];
+ data_out[ i + 1 ] = gain * data_in[ i + 1 ];
+ data_out[ i + 2 ] = gain * data_in[ i + 2 ];
+ data_out[ i + 3 ] = gain * data_in[ i + 3 ];
+ }
+
+ /* any remaining elements */
+ for( ; i < dataSize; i++ ) {
+ data_out[ i ] = gain * data_in[ i ];
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/scale_vector_FLP.c b/external/opus-1.1.4/silk/float/scale_vector_FLP.c
new file mode 100644
index 0000000..108fdcb
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/scale_vector_FLP.c
@@ -0,0 +1,56 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* multiply a vector by a constant */
+void silk_scale_vector_FLP(
+ silk_float *data1,
+ silk_float gain,
+ opus_int dataSize
+)
+{
+ opus_int i, dataSize4;
+
+ /* 4x unrolled loop */
+ dataSize4 = dataSize & 0xFFFC;
+ for( i = 0; i < dataSize4; i += 4 ) {
+ data1[ i + 0 ] *= gain;
+ data1[ i + 1 ] *= gain;
+ data1[ i + 2 ] *= gain;
+ data1[ i + 3 ] *= gain;
+ }
+
+ /* any remaining elements */
+ for( ; i < dataSize; i++ ) {
+ data1[ i ] *= gain;
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/schur_FLP.c b/external/opus-1.1.4/silk/float/schur_FLP.c
new file mode 100644
index 0000000..ee436f8
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/schur_FLP.c
@@ -0,0 +1,70 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+silk_float silk_schur_FLP( /* O returns residual energy */
+ silk_float refl_coef[], /* O reflection coefficients (length order) */
+ const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */
+ opus_int order /* I order */
+)
+{
+ opus_int k, n;
+ silk_float C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
+ silk_float Ctmp1, Ctmp2, rc_tmp;
+
+ silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 );
+
+ /* Copy correlations */
+ for( k = 0; k < order+1; k++ ) {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = auto_corr[ k ];
+ }
+
+ for( k = 0; k < order; k++ ) {
+ /* Get reflection coefficient */
+ rc_tmp = -C[ k + 1 ][ 0 ] / silk_max_float( C[ 0 ][ 1 ], 1e-9f );
+
+ /* Save the output */
+ refl_coef[ k ] = rc_tmp;
+
+ /* Update correlations */
+ for( n = 0; n < order - k; n++ ) {
+ Ctmp1 = C[ n + k + 1 ][ 0 ];
+ Ctmp2 = C[ n ][ 1 ];
+ C[ n + k + 1 ][ 0 ] = Ctmp1 + Ctmp2 * rc_tmp;
+ C[ n ][ 1 ] = Ctmp2 + Ctmp1 * rc_tmp;
+ }
+ }
+
+ /* Return residual energy */
+ return C[ 0 ][ 1 ];
+}
+
diff --git a/external/opus-1.1.4/silk/float/solve_LS_FLP.c b/external/opus-1.1.4/silk/float/solve_LS_FLP.c
new file mode 100644
index 0000000..b35f0a5
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/solve_LS_FLP.c
@@ -0,0 +1,207 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/**********************************************************************
+ * LDL Factorisation. Finds the upper triangular matrix L and the diagonal
+ * Matrix D (only the diagonal elements returned in a vector)such that
+ * the symmetric matric A is given by A = L*D*L'.
+ **********************************************************************/
+static OPUS_INLINE void silk_LDL_FLP(
+ silk_float *A, /* I/O Pointer to Symetric Square Matrix */
+ opus_int M, /* I Size of Matrix */
+ silk_float *L, /* I/O Pointer to Square Upper triangular Matrix */
+ silk_float *Dinv /* I/O Pointer to vector holding the inverse diagonal elements of D */
+);
+
+/**********************************************************************
+ * Function to solve linear equation Ax = b, when A is a MxM lower
+ * triangular matrix, with ones on the diagonal.
+ **********************************************************************/
+static OPUS_INLINE void silk_SolveWithLowerTriangularWdiagOnes_FLP(
+ const silk_float *L, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const silk_float *b, /* I b Vector */
+ silk_float *x /* O x Vector */
+);
+
+/**********************************************************************
+ * Function to solve linear equation (A^T)x = b, when A is a MxM lower
+ * triangular, with ones on the diagonal. (ie then A^T is upper triangular)
+ **********************************************************************/
+static OPUS_INLINE void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP(
+ const silk_float *L, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const silk_float *b, /* I b Vector */
+ silk_float *x /* O x Vector */
+);
+
+/**********************************************************************
+ * Function to solve linear equation Ax = b, when A is a MxM
+ * symmetric square matrix - using LDL factorisation
+ **********************************************************************/
+void silk_solve_LDL_FLP(
+ silk_float *A, /* I/O Symmetric square matrix, out: reg. */
+ const opus_int M, /* I Size of matrix */
+ const silk_float *b, /* I Pointer to b vector */
+ silk_float *x /* O Pointer to x solution vector */
+)
+{
+ opus_int i;
+ silk_float L[ MAX_MATRIX_SIZE ][ MAX_MATRIX_SIZE ];
+ silk_float T[ MAX_MATRIX_SIZE ];
+ silk_float Dinv[ MAX_MATRIX_SIZE ]; /* inverse diagonal elements of D*/
+
+ silk_assert( M <= MAX_MATRIX_SIZE );
+
+ /***************************************************
+ Factorize A by LDL such that A = L*D*(L^T),
+ where L is lower triangular with ones on diagonal
+ ****************************************************/
+ silk_LDL_FLP( A, M, &L[ 0 ][ 0 ], Dinv );
+
+ /****************************************************
+ * substitute D*(L^T) = T. ie:
+ L*D*(L^T)*x = b => L*T = b <=> T = inv(L)*b
+ ******************************************************/
+ silk_SolveWithLowerTriangularWdiagOnes_FLP( &L[ 0 ][ 0 ], M, b, T );
+
+ /****************************************************
+ D*(L^T)*x = T <=> (L^T)*x = inv(D)*T, because D is
+ diagonal just multiply with 1/d_i
+ ****************************************************/
+ for( i = 0; i < M; i++ ) {
+ T[ i ] = T[ i ] * Dinv[ i ];
+ }
+ /****************************************************
+ x = inv(L') * inv(D) * T
+ *****************************************************/
+ silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( &L[ 0 ][ 0 ], M, T, x );
+}
+
+static OPUS_INLINE void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP(
+ const silk_float *L, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const silk_float *b, /* I b Vector */
+ silk_float *x /* O x Vector */
+)
+{
+ opus_int i, j;
+ silk_float temp;
+ const silk_float *ptr1;
+
+ for( i = M - 1; i >= 0; i-- ) {
+ ptr1 = matrix_adr( L, 0, i, M );
+ temp = 0;
+ for( j = M - 1; j > i ; j-- ) {
+ temp += ptr1[ j * M ] * x[ j ];
+ }
+ temp = b[ i ] - temp;
+ x[ i ] = temp;
+ }
+}
+
+static OPUS_INLINE void silk_SolveWithLowerTriangularWdiagOnes_FLP(
+ const silk_float *L, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const silk_float *b, /* I b Vector */
+ silk_float *x /* O x Vector */
+)
+{
+ opus_int i, j;
+ silk_float temp;
+ const silk_float *ptr1;
+
+ for( i = 0; i < M; i++ ) {
+ ptr1 = matrix_adr( L, i, 0, M );
+ temp = 0;
+ for( j = 0; j < i; j++ ) {
+ temp += ptr1[ j ] * x[ j ];
+ }
+ temp = b[ i ] - temp;
+ x[ i ] = temp;
+ }
+}
+
+static OPUS_INLINE void silk_LDL_FLP(
+ silk_float *A, /* I/O Pointer to Symetric Square Matrix */
+ opus_int M, /* I Size of Matrix */
+ silk_float *L, /* I/O Pointer to Square Upper triangular Matrix */
+ silk_float *Dinv /* I/O Pointer to vector holding the inverse diagonal elements of D */
+)
+{
+ opus_int i, j, k, loop_count, err = 1;
+ silk_float *ptr1, *ptr2;
+ double temp, diag_min_value;
+ silk_float v[ MAX_MATRIX_SIZE ] = { 0 }, D[ MAX_MATRIX_SIZE ]; /* temp arrays*/
+
+ silk_assert( M <= MAX_MATRIX_SIZE );
+
+ diag_min_value = FIND_LTP_COND_FAC * 0.5f * ( A[ 0 ] + A[ M * M - 1 ] );
+ for( loop_count = 0; loop_count < M && err == 1; loop_count++ ) {
+ err = 0;
+ for( j = 0; j < M; j++ ) {
+ ptr1 = matrix_adr( L, j, 0, M );
+ temp = matrix_ptr( A, j, j, M ); /* element in row j column j*/
+ for( i = 0; i < j; i++ ) {
+ v[ i ] = ptr1[ i ] * D[ i ];
+ temp -= ptr1[ i ] * v[ i ];
+ }
+ if( temp < diag_min_value ) {
+ /* Badly conditioned matrix: add white noise and run again */
+ temp = ( loop_count + 1 ) * diag_min_value - temp;
+ for( i = 0; i < M; i++ ) {
+ matrix_ptr( A, i, i, M ) += ( silk_float )temp;
+ }
+ err = 1;
+ break;
+ }
+ D[ j ] = ( silk_float )temp;
+ Dinv[ j ] = ( silk_float )( 1.0f / temp );
+ matrix_ptr( L, j, j, M ) = 1.0f;
+
+ ptr1 = matrix_adr( A, j, 0, M );
+ ptr2 = matrix_adr( L, j + 1, 0, M);
+ for( i = j + 1; i < M; i++ ) {
+ temp = 0.0;
+ for( k = 0; k < j; k++ ) {
+ temp += ptr2[ k ] * v[ k ];
+ }
+ matrix_ptr( L, i, j, M ) = ( silk_float )( ( ptr1[ i ] - temp ) * Dinv[ j ] );
+ ptr2 += M; /* go to next column*/
+ }
+ }
+ }
+ silk_assert( err == 0 );
+}
+
diff --git a/external/opus-1.1.4/silk/float/sort_FLP.c b/external/opus-1.1.4/silk/float/sort_FLP.c
new file mode 100644
index 0000000..f08d759
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/sort_FLP.c
@@ -0,0 +1,83 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Insertion sort (fast for already almost sorted arrays): */
+/* Best case: O(n) for an already sorted array */
+/* Worst case: O(n^2) for an inversely sorted array */
+
+#include "typedef.h"
+#include "SigProc_FLP.h"
+
+void silk_insertion_sort_decreasing_FLP(
+ silk_float *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+)
+{
+ silk_float value;
+ opus_int i, j;
+
+ /* Safety checks */
+ silk_assert( K > 0 );
+ silk_assert( L > 0 );
+ silk_assert( L >= K );
+
+ /* Write start indices in index vector */
+ for( i = 0; i < K; i++ ) {
+ idx[ i ] = i;
+ }
+
+ /* Sort vector elements by value, decreasing order */
+ for( i = 1; i < K; i++ ) {
+ value = a[ i ];
+ for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+
+ /* If less than L values are asked check the remaining values, */
+ /* but only spend CPU to ensure that the K first values are correct */
+ for( i = K; i < L; i++ ) {
+ value = a[ i ];
+ if( value > a[ K - 1 ] ) {
+ for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/structs_FLP.h b/external/opus-1.1.4/silk/float/structs_FLP.h
new file mode 100644
index 0000000..14d647c
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/structs_FLP.h
@@ -0,0 +1,132 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_STRUCTS_FLP_H
+#define SILK_STRUCTS_FLP_H
+
+#include "typedef.h"
+#include "main.h"
+#include "structs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/********************************/
+/* Noise shaping analysis state */
+/********************************/
+typedef struct {
+ opus_int8 LastGainIndex;
+ silk_float HarmBoost_smth;
+ silk_float HarmShapeGain_smth;
+ silk_float Tilt_smth;
+} silk_shape_state_FLP;
+
+/********************************/
+/* Prefilter state */
+/********************************/
+typedef struct {
+ silk_float sLTP_shp[ LTP_BUF_LENGTH ];
+ silk_float sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ];
+ opus_int sLTP_shp_buf_idx;
+ silk_float sLF_AR_shp;
+ silk_float sLF_MA_shp;
+ silk_float sHarmHP;
+ opus_int32 rand_seed;
+ opus_int lagPrev;
+} silk_prefilter_state_FLP;
+
+/********************************/
+/* Encoder state FLP */
+/********************************/
+typedef struct {
+ silk_encoder_state sCmn; /* Common struct, shared with fixed-point code */
+ silk_shape_state_FLP sShape; /* Noise shaping state */
+ silk_prefilter_state_FLP sPrefilt; /* Prefilter State */
+
+ /* Buffer for find pitch and noise shape analysis */
+ silk_float x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */
+ silk_float LTPCorr; /* Normalized correlation from pitch lag estimator */
+} silk_encoder_state_FLP;
+
+/************************/
+/* Encoder control FLP */
+/************************/
+typedef struct {
+ /* Prediction and coding parameters */
+ silk_float Gains[ MAX_NB_SUBFR ];
+ silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ]; /* holds interpolated and final coefficients */
+ silk_float LTPCoef[LTP_ORDER * MAX_NB_SUBFR];
+ silk_float LTP_scale;
+ opus_int pitchL[ MAX_NB_SUBFR ];
+
+ /* Noise shaping parameters */
+ silk_float AR1[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ silk_float AR2[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ silk_float LF_MA_shp[ MAX_NB_SUBFR ];
+ silk_float LF_AR_shp[ MAX_NB_SUBFR ];
+ silk_float GainsPre[ MAX_NB_SUBFR ];
+ silk_float HarmBoost[ MAX_NB_SUBFR ];
+ silk_float Tilt[ MAX_NB_SUBFR ];
+ silk_float HarmShapeGain[ MAX_NB_SUBFR ];
+ silk_float Lambda;
+ silk_float input_quality;
+ silk_float coding_quality;
+
+ /* Measures */
+ silk_float sparseness;
+ silk_float predGain;
+ silk_float LTPredCodGain;
+ silk_float ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */
+
+ /* Parameters for CBR mode */
+ opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ];
+ opus_int8 lastGainIndexPrev;
+} silk_encoder_control_FLP;
+
+/************************/
+/* Encoder Super Struct */
+/************************/
+typedef struct {
+ silk_encoder_state_FLP state_Fxx[ ENCODER_NUM_CHANNELS ];
+ stereo_enc_state sStereo;
+ opus_int32 nBitsUsedLBRR;
+ opus_int32 nBitsExceeded;
+ opus_int nChannelsAPI;
+ opus_int nChannelsInternal;
+ opus_int nPrevChannelsInternal;
+ opus_int timeSinceSwitchAllowed_ms;
+ opus_int allowBandwidthSwitch;
+ opus_int prev_decode_only_middle;
+} silk_encoder;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/silk/float/warped_autocorrelation_FLP.c b/external/opus-1.1.4/silk/float/warped_autocorrelation_FLP.c
new file mode 100644
index 0000000..542414f
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/warped_autocorrelation_FLP.c
@@ -0,0 +1,73 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FLP(
+ silk_float *corr, /* O Result [order + 1] */
+ const silk_float *input, /* I Input data to correlate */
+ const silk_float warping, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+)
+{
+ opus_int n, i;
+ double tmp1, tmp2;
+ double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+ double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+ /* Order must be even */
+ silk_assert( ( order & 1 ) == 0 );
+
+ /* Loop over samples */
+ for( n = 0; n < length; n++ ) {
+ tmp1 = input[ n ];
+ /* Loop over allpass sections */
+ for( i = 0; i < order; i += 2 ) {
+ /* Output of allpass section */
+ tmp2 = state[ i ] + warping * ( state[ i + 1 ] - tmp1 );
+ state[ i ] = tmp1;
+ C[ i ] += state[ 0 ] * tmp1;
+ /* Output of allpass section */
+ tmp1 = state[ i + 1 ] + warping * ( state[ i + 2 ] - tmp2 );
+ state[ i + 1 ] = tmp2;
+ C[ i + 1 ] += state[ 0 ] * tmp2;
+ }
+ state[ order ] = tmp1;
+ C[ order ] += state[ 0 ] * tmp1;
+ }
+
+ /* Copy correlations in silk_float output format */
+ for( i = 0; i < order + 1; i++ ) {
+ corr[ i ] = ( silk_float )C[ i ];
+ }
+}
diff --git a/external/opus-1.1.4/silk/float/wrappers_FLP.c b/external/opus-1.1.4/silk/float/wrappers_FLP.c
new file mode 100644
index 0000000..6666b8e
--- /dev/null
+++ b/external/opus-1.1.4/silk/float/wrappers_FLP.c
@@ -0,0 +1,202 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+/* Wrappers. Calls flp / fix code */
+
+/* Convert AR filter coefficients to NLSF parameters */
+void silk_A2NLSF_FLP(
+ opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */
+ const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */
+ const opus_int LPC_order /* I LPC order */
+)
+{
+ opus_int i;
+ opus_int32 a_fix_Q16[ MAX_LPC_ORDER ];
+
+ for( i = 0; i < LPC_order; i++ ) {
+ a_fix_Q16[ i ] = silk_float2int( pAR[ i ] * 65536.0f );
+ }
+
+ silk_A2NLSF( NLSF_Q15, a_fix_Q16, LPC_order );
+}
+
+/* Convert LSF parameters to AR prediction filter coefficients */
+void silk_NLSF2A_FLP(
+ silk_float *pAR, /* O LPC coefficients [ LPC_order ] */
+ const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */
+ const opus_int LPC_order /* I LPC order */
+)
+{
+ opus_int i;
+ opus_int16 a_fix_Q12[ MAX_LPC_ORDER ];
+
+ silk_NLSF2A( a_fix_Q12, NLSF_Q15, LPC_order );
+
+ for( i = 0; i < LPC_order; i++ ) {
+ pAR[ i ] = ( silk_float )a_fix_Q12[ i ] * ( 1.0f / 4096.0f );
+ }
+}
+
+/******************************************/
+/* Floating-point NLSF processing wrapper */
+/******************************************/
+void silk_process_NLSFs_FLP(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */
+ opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */
+ const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */
+)
+{
+ opus_int i, j;
+ opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+
+ silk_process_NLSFs( psEncC, PredCoef_Q12, NLSF_Q15, prev_NLSF_Q15);
+
+ for( j = 0; j < 2; j++ ) {
+ for( i = 0; i < psEncC->predictLPCOrder; i++ ) {
+ PredCoef[ j ][ i ] = ( silk_float )PredCoef_Q12[ j ][ i ] * ( 1.0f / 4096.0f );
+ }
+ }
+}
+
+/****************************************/
+/* Floating-point Silk NSQ wrapper */
+/****************************************/
+void silk_NSQ_wrapper_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ SideInfoIndices *psIndices, /* I/O Quantization indices */
+ silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const silk_float x[] /* I Prefiltered input signal */
+)
+{
+ opus_int i, j;
+ opus_int32 x_Q3[ MAX_FRAME_LENGTH ];
+ opus_int32 Gains_Q16[ MAX_NB_SUBFR ];
+ silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+ opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ];
+ opus_int LTP_scale_Q14;
+
+ /* Noise shaping parameters */
+ opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */
+ opus_int Lambda_Q10;
+ opus_int Tilt_Q14[ MAX_NB_SUBFR ];
+ opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ];
+
+ /* Convert control struct to fix control struct */
+ /* Noise shape parameters */
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ for( j = 0; j < psEnc->sCmn.shapingLPCOrder; j++ ) {
+ AR2_Q13[ i * MAX_SHAPE_LPC_ORDER + j ] = silk_float2int( psEncCtrl->AR2[ i * MAX_SHAPE_LPC_ORDER + j ] * 8192.0f );
+ }
+ }
+
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ LF_shp_Q14[ i ] = silk_LSHIFT32( silk_float2int( psEncCtrl->LF_AR_shp[ i ] * 16384.0f ), 16 ) |
+ (opus_uint16)silk_float2int( psEncCtrl->LF_MA_shp[ i ] * 16384.0f );
+ Tilt_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->Tilt[ i ] * 16384.0f );
+ HarmShapeGain_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->HarmShapeGain[ i ] * 16384.0f );
+ }
+ Lambda_Q10 = ( opus_int )silk_float2int( psEncCtrl->Lambda * 1024.0f );
+
+ /* prediction and coding parameters */
+ for( i = 0; i < psEnc->sCmn.nb_subfr * LTP_ORDER; i++ ) {
+ LTPCoef_Q14[ i ] = (opus_int16)silk_float2int( psEncCtrl->LTPCoef[ i ] * 16384.0f );
+ }
+
+ for( j = 0; j < 2; j++ ) {
+ for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) {
+ PredCoef_Q12[ j ][ i ] = (opus_int16)silk_float2int( psEncCtrl->PredCoef[ j ][ i ] * 4096.0f );
+ }
+ }
+
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ Gains_Q16[ i ] = silk_float2int( psEncCtrl->Gains[ i ] * 65536.0f );
+ silk_assert( Gains_Q16[ i ] > 0 );
+ }
+
+ if( psIndices->signalType == TYPE_VOICED ) {
+ LTP_scale_Q14 = silk_LTPScales_table_Q14[ psIndices->LTP_scaleIndex ];
+ } else {
+ LTP_scale_Q14 = 0;
+ }
+
+ /* Convert input to fix */
+ for( i = 0; i < psEnc->sCmn.frame_length; i++ ) {
+ x_Q3[ i ] = silk_float2int( 8.0f * x[ i ] );
+ }
+
+ /* Call NSQ */
+ if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+ silk_NSQ_del_dec( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14,
+ AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14, psEnc->sCmn.arch );
+ } else {
+ silk_NSQ( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14,
+ AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14, psEnc->sCmn.arch );
+ }
+}
+
+/***********************************************/
+/* Floating-point Silk LTP quantiation wrapper */
+/***********************************************/
+void silk_quant_LTP_gains_FLP(
+ silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (Un-)quantized LTP gains */
+ opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */
+ opus_int8 *periodicity_index, /* O Periodicity index */
+ opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */
+ const silk_float W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Error weights */
+ const opus_int mu_Q10, /* I Mu value (R/D tradeoff) */
+ const opus_int lowComplexity, /* I Flag for low complexity */
+ const opus_int nb_subfr, /* I number of subframes */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int i;
+ opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ];
+ opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ];
+
+ for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) {
+ B_Q14[ i ] = (opus_int16)silk_float2int( B[ i ] * 16384.0f );
+ }
+ for( i = 0; i < nb_subfr * LTP_ORDER * LTP_ORDER; i++ ) {
+ W_Q18[ i ] = (opus_int32)silk_float2int( W[ i ] * 262144.0f );
+ }
+
+ silk_quant_LTP_gains( B_Q14, cbk_index, periodicity_index, sum_log_gain_Q7, W_Q18, mu_Q10, lowComplexity, nb_subfr, arch );
+
+ for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) {
+ B[ i ] = (silk_float)B_Q14[ i ] * ( 1.0f / 16384.0f );
+ }
+}
diff --git a/external/opus-1.1.4/silk/gain_quant.c b/external/opus-1.1.4/silk/gain_quant.c
new file mode 100644
index 0000000..64ccd06
--- /dev/null
+++ b/external/opus-1.1.4/silk/gain_quant.c
@@ -0,0 +1,141 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+#define OFFSET ( ( MIN_QGAIN_DB * 128 ) / 6 + 16 * 128 )
+#define SCALE_Q16 ( ( 65536 * ( N_LEVELS_QGAIN - 1 ) ) / ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) )
+#define INV_SCALE_Q16 ( ( 65536 * ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) / ( N_LEVELS_QGAIN - 1 ) )
+
+/* Gain scalar quantization with hysteresis, uniform on log scale */
+void silk_gains_quant(
+ opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */
+ opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */
+ opus_int8 *prev_ind, /* I/O last index in previous frame */
+ const opus_int conditional, /* I first gain is delta coded if 1 */
+ const opus_int nb_subfr /* I number of subframes */
+)
+{
+ opus_int k, double_step_size_threshold;
+
+ for( k = 0; k < nb_subfr; k++ ) {
+ /* Convert to log scale, scale, floor() */
+ ind[ k ] = silk_SMULWB( SCALE_Q16, silk_lin2log( gain_Q16[ k ] ) - OFFSET );
+
+ /* Round towards previous quantized gain (hysteresis) */
+ if( ind[ k ] < *prev_ind ) {
+ ind[ k ]++;
+ }
+ ind[ k ] = silk_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 );
+
+ /* Compute delta indices and limit */
+ if( k == 0 && conditional == 0 ) {
+ /* Full index */
+ ind[ k ] = silk_LIMIT_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1 );
+ *prev_ind = ind[ k ];
+ } else {
+ /* Delta index */
+ ind[ k ] = ind[ k ] - *prev_ind;
+
+ /* Double the quantization step size for large gain increases, so that the max gain level can be reached */
+ double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind;
+ if( ind[ k ] > double_step_size_threshold ) {
+ ind[ k ] = double_step_size_threshold + silk_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 );
+ }
+
+ ind[ k ] = silk_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT );
+
+ /* Accumulate deltas */
+ if( ind[ k ] > double_step_size_threshold ) {
+ *prev_ind += silk_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold;
+ } else {
+ *prev_ind += ind[ k ];
+ }
+
+ /* Shift to make non-negative */
+ ind[ k ] -= MIN_DELTA_GAIN_QUANT;
+ }
+
+ /* Scale and convert to linear scale */
+ gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */
+ }
+}
+
+/* Gains scalar dequantization, uniform on log scale */
+void silk_gains_dequant(
+ opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */
+ const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */
+ opus_int8 *prev_ind, /* I/O last index in previous frame */
+ const opus_int conditional, /* I first gain is delta coded if 1 */
+ const opus_int nb_subfr /* I number of subframes */
+)
+{
+ opus_int k, ind_tmp, double_step_size_threshold;
+
+ for( k = 0; k < nb_subfr; k++ ) {
+ if( k == 0 && conditional == 0 ) {
+ /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */
+ *prev_ind = silk_max_int( ind[ k ], *prev_ind - 16 );
+ } else {
+ /* Delta index */
+ ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT;
+
+ /* Accumulate deltas */
+ double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind;
+ if( ind_tmp > double_step_size_threshold ) {
+ *prev_ind += silk_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold;
+ } else {
+ *prev_ind += ind_tmp;
+ }
+ }
+ *prev_ind = silk_LIMIT_int( *prev_ind, 0, N_LEVELS_QGAIN - 1 );
+
+ /* Scale and convert to linear scale */
+ gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */
+ }
+}
+
+/* Compute unique identifier of gain indices vector */
+opus_int32 silk_gains_ID( /* O returns unique identifier of gains */
+ const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */
+ const opus_int nb_subfr /* I number of subframes */
+)
+{
+ opus_int k;
+ opus_int32 gainsID;
+
+ gainsID = 0;
+ for( k = 0; k < nb_subfr; k++ ) {
+ gainsID = silk_ADD_LSHIFT32( ind[ k ], gainsID, 8 );
+ }
+
+ return gainsID;
+}
diff --git a/external/opus-1.1.4/silk/init_decoder.c b/external/opus-1.1.4/silk/init_decoder.c
new file mode 100644
index 0000000..f887c67
--- /dev/null
+++ b/external/opus-1.1.4/silk/init_decoder.c
@@ -0,0 +1,56 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/************************/
+/* Init Decoder State */
+/************************/
+opus_int silk_init_decoder(
+ silk_decoder_state *psDec /* I/O Decoder state pointer */
+)
+{
+ /* Clear the entire encoder state, except anything copied */
+ silk_memset( psDec, 0, sizeof( silk_decoder_state ) );
+
+ /* Used to deactivate LSF interpolation */
+ psDec->first_frame_after_reset = 1;
+ psDec->prev_gain_Q16 = 65536;
+
+ /* Reset CNG state */
+ silk_CNG_Reset( psDec );
+
+ /* Reset PLC state */
+ silk_PLC_Reset( psDec );
+
+ return(0);
+}
+
diff --git a/external/opus-1.1.4/silk/init_encoder.c b/external/opus-1.1.4/silk/init_encoder.c
new file mode 100644
index 0000000..65995c3
--- /dev/null
+++ b/external/opus-1.1.4/silk/init_encoder.c
@@ -0,0 +1,64 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef FIXED_POINT
+#include "main_FIX.h"
+#else
+#include "main_FLP.h"
+#endif
+#include "tuning_parameters.h"
+#include "cpu_support.h"
+
+/*********************************/
+/* Initialize Silk Encoder state */
+/*********************************/
+opus_int silk_init_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int ret = 0;
+
+ /* Clear the entire encoder state */
+ silk_memset( psEnc, 0, sizeof( silk_encoder_state_Fxx ) );
+
+ psEnc->sCmn.arch = arch;
+
+ psEnc->sCmn.variable_HP_smth1_Q15 = silk_LSHIFT( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ), 8 );
+ psEnc->sCmn.variable_HP_smth2_Q15 = psEnc->sCmn.variable_HP_smth1_Q15;
+
+ /* Used to deactivate LSF interpolation, pitch prediction */
+ psEnc->sCmn.first_frame_after_reset = 1;
+
+ /* Initialize Silk VAD */
+ ret += silk_VAD_Init( &psEnc->sCmn.sVAD );
+
+ return ret;
+}
diff --git a/external/opus-1.1.4/silk/inner_prod_aligned.c b/external/opus-1.1.4/silk/inner_prod_aligned.c
new file mode 100644
index 0000000..257ae9e
--- /dev/null
+++ b/external/opus-1.1.4/silk/inner_prod_aligned.c
@@ -0,0 +1,47 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+opus_int32 silk_inner_prod_aligned_scale(
+ const opus_int16 *const inVec1, /* I input vector 1 */
+ const opus_int16 *const inVec2, /* I input vector 2 */
+ const opus_int scale, /* I number of bits to shift */
+ const opus_int len /* I vector lengths */
+)
+{
+ opus_int i;
+ opus_int32 sum = 0;
+ for( i = 0; i < len; i++ ) {
+ sum = silk_ADD_RSHIFT32( sum, silk_SMULBB( inVec1[ i ], inVec2[ i ] ), scale );
+ }
+ return sum;
+}
diff --git a/external/opus-1.1.4/silk/interpolate.c b/external/opus-1.1.4/silk/interpolate.c
new file mode 100644
index 0000000..1bd8ca4
--- /dev/null
+++ b/external/opus-1.1.4/silk/interpolate.c
@@ -0,0 +1,51 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Interpolate two vectors */
+void silk_interpolate(
+ opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */
+ const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */
+ const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */
+ const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */
+ const opus_int d /* I number of parameters */
+)
+{
+ opus_int i;
+
+ silk_assert( ifact_Q2 >= 0 );
+ silk_assert( ifact_Q2 <= 4 );
+
+ for( i = 0; i < d; i++ ) {
+ xi[ i ] = (opus_int16)silk_ADD_RSHIFT( x0[ i ], silk_SMULBB( x1[ i ] - x0[ i ], ifact_Q2 ), 2 );
+ }
+}
diff --git a/external/opus-1.1.4/silk/lin2log.c b/external/opus-1.1.4/silk/lin2log.c
new file mode 100644
index 0000000..d4fe515
--- /dev/null
+++ b/external/opus-1.1.4/silk/lin2log.c
@@ -0,0 +1,46 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+/* Approximation of 128 * log2() (very close inverse of silk_log2lin()) */
+/* Convert input to a log scale */
+opus_int32 silk_lin2log(
+ const opus_int32 inLin /* I input in linear scale */
+)
+{
+ opus_int32 lz, frac_Q7;
+
+ silk_CLZ_FRAC( inLin, &lz, &frac_Q7 );
+
+ /* Piece-wise parabolic approximation */
+ return silk_LSHIFT( 31 - lz, 7 ) + silk_SMLAWB( frac_Q7, silk_MUL( frac_Q7, 128 - frac_Q7 ), 179 );
+}
+
diff --git a/external/opus-1.1.4/silk/log2lin.c b/external/opus-1.1.4/silk/log2lin.c
new file mode 100644
index 0000000..b7c48e4
--- /dev/null
+++ b/external/opus-1.1.4/silk/log2lin.c
@@ -0,0 +1,58 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Approximation of 2^() (very close inverse of silk_lin2log()) */
+/* Convert input to a linear scale */
+opus_int32 silk_log2lin(
+ const opus_int32 inLog_Q7 /* I input on log scale */
+)
+{
+ opus_int32 out, frac_Q7;
+
+ if( inLog_Q7 < 0 ) {
+ return 0;
+ } else if ( inLog_Q7 >= 3967 ) {
+ return silk_int32_MAX;
+ }
+
+ out = silk_LSHIFT( 1, silk_RSHIFT( inLog_Q7, 7 ) );
+ frac_Q7 = inLog_Q7 & 0x7F;
+ if( inLog_Q7 < 2048 ) {
+ /* Piece-wise parabolic approximation */
+ out = silk_ADD_RSHIFT32( out, silk_MUL( out, silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ), 7 );
+ } else {
+ /* Piece-wise parabolic approximation */
+ out = silk_MLA( out, silk_RSHIFT( out, 7 ), silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) );
+ }
+ return out;
+}
diff --git a/external/opus-1.1.4/silk/macros.h b/external/opus-1.1.4/silk/macros.h
new file mode 100644
index 0000000..d3ca347
--- /dev/null
+++ b/external/opus-1.1.4/silk/macros.h
@@ -0,0 +1,159 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_MACROS_H
+#define SILK_MACROS_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_types.h"
+#include "opus_defines.h"
+#include "arch.h"
+
+#if OPUS_GNUC_PREREQ(3, 0)
+#define opus_likely(x) (__builtin_expect(!!(x), 1))
+#define opus_unlikely(x) (__builtin_expect(!!(x), 0))
+#else
+#define opus_likely(x) (!!(x))
+#define opus_unlikely(x) (!!(x))
+#endif
+
+/* This is an OPUS_INLINE header file for general platform. */
+
+/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */
+#if OPUS_FAST_INT64
+#define silk_SMULWB(a32, b32) ((opus_int32)(((a32) * (opus_int64)((opus_int16)(b32))) >> 16))
+#else
+#define silk_SMULWB(a32, b32) ((((a32) >> 16) * (opus_int32)((opus_int16)(b32))) + ((((a32) & 0x0000FFFF) * (opus_int32)((opus_int16)(b32))) >> 16))
+#endif
+
+/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */
+#if OPUS_FAST_INT64
+#define silk_SMLAWB(a32, b32, c32) ((opus_int32)((a32) + (((b32) * (opus_int64)((opus_int16)(c32))) >> 16)))
+#else
+#define silk_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16)))
+#endif
+
+/* (a32 * (b32 >> 16)) >> 16 */
+#if OPUS_FAST_INT64
+#define silk_SMULWT(a32, b32) ((opus_int32)(((a32) * (opus_int64)((b32) >> 16)) >> 16))
+#else
+#define silk_SMULWT(a32, b32) (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16))
+#endif
+
+/* a32 + (b32 * (c32 >> 16)) >> 16 */
+#if OPUS_FAST_INT64
+#define silk_SMLAWT(a32, b32, c32) ((opus_int32)((a32) + (((b32) * ((opus_int64)(c32) >> 16)) >> 16)))
+#else
+#define silk_SMLAWT(a32, b32, c32) ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16))
+#endif
+
+/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */
+#define silk_SMULBB(a32, b32) ((opus_int32)((opus_int16)(a32)) * (opus_int32)((opus_int16)(b32)))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */
+#define silk_SMLABB(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))
+
+/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */
+#define silk_SMULBT(a32, b32) ((opus_int32)((opus_int16)(a32)) * ((b32) >> 16))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */
+#define silk_SMLABT(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * ((c32) >> 16))
+
+/* a64 + (b32 * c32) */
+#define silk_SMLAL(a64, b32, c32) (silk_ADD64((a64), ((opus_int64)(b32) * (opus_int64)(c32))))
+
+/* (a32 * b32) >> 16 */
+#if OPUS_FAST_INT64
+#define silk_SMULWW(a32, b32) ((opus_int32)(((opus_int64)(a32) * (b32)) >> 16))
+#else
+#define silk_SMULWW(a32, b32) silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16))
+#endif
+
+/* a32 + ((b32 * c32) >> 16) */
+#if OPUS_FAST_INT64
+#define silk_SMLAWW(a32, b32, c32) ((opus_int32)((a32) + (((opus_int64)(b32) * (c32)) >> 16)))
+#else
+#define silk_SMLAWW(a32, b32, c32) silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16))
+#endif
+
+/* add/subtract with output saturated */
+#define silk_ADD_SAT32(a, b) ((((opus_uint32)(a) + (opus_uint32)(b)) & 0x80000000) == 0 ? \
+ ((((a) & (b)) & 0x80000000) != 0 ? silk_int32_MIN : (a)+(b)) : \
+ ((((a) | (b)) & 0x80000000) == 0 ? silk_int32_MAX : (a)+(b)) )
+
+#define silk_SUB_SAT32(a, b) ((((opus_uint32)(a)-(opus_uint32)(b)) & 0x80000000) == 0 ? \
+ (( (a) & ((b)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a)-(b)) : \
+ ((((a)^0x80000000) & (b) & 0x80000000) ? silk_int32_MAX : (a)-(b)) )
+
+#if defined(MIPSr1_ASM)
+#include "mips/macros_mipsr1.h"
+#endif
+
+#include "ecintrin.h"
+#ifndef OVERRIDE_silk_CLZ16
+static OPUS_INLINE opus_int32 silk_CLZ16(opus_int16 in16)
+{
+ return 32 - EC_ILOG(in16<<16|0x8000);
+}
+#endif
+
+#ifndef OVERRIDE_silk_CLZ32
+static OPUS_INLINE opus_int32 silk_CLZ32(opus_int32 in32)
+{
+ return in32 ? 32 - EC_ILOG(in32) : 32;
+}
+#endif
+
+/* Row based */
+#define matrix_ptr(Matrix_base_adr, row, column, N) \
+ (*((Matrix_base_adr) + ((row)*(N)+(column))))
+#define matrix_adr(Matrix_base_adr, row, column, N) \
+ ((Matrix_base_adr) + ((row)*(N)+(column)))
+
+/* Column based */
+#ifndef matrix_c_ptr
+# define matrix_c_ptr(Matrix_base_adr, row, column, M) \
+ (*((Matrix_base_adr) + ((row)+(M)*(column))))
+#endif
+
+#ifdef OPUS_ARM_INLINE_ASM
+#include "arm/macros_armv4.h"
+#endif
+
+#ifdef OPUS_ARM_INLINE_EDSP
+#include "arm/macros_armv5e.h"
+#endif
+
+#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR
+#include "arm/macros_arm64.h"
+#endif
+
+#endif /* SILK_MACROS_H */
+
diff --git a/external/opus-1.1.4/silk/main.h b/external/opus-1.1.4/silk/main.h
new file mode 100644
index 0000000..2f90d68
--- /dev/null
+++ b/external/opus-1.1.4/silk/main.h
@@ -0,0 +1,471 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_MAIN_H
+#define SILK_MAIN_H
+
+#include "SigProc_FIX.h"
+#include "define.h"
+#include "structs.h"
+#include "tables.h"
+#include "PLC.h"
+#include "control.h"
+#include "debug.h"
+#include "entenc.h"
+#include "entdec.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#include "x86/main_sse.h"
+#endif
+
+/* Convert Left/Right stereo signal to adaptive Mid/Side representation */
+void silk_stereo_LR_to_MS(
+ stereo_enc_state *state, /* I/O State */
+ opus_int16 x1[], /* I/O Left input signal, becomes mid signal */
+ opus_int16 x2[], /* I/O Right input signal, becomes side signal */
+ opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */
+ opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */
+ opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */
+ opus_int32 total_rate_bps, /* I Total bitrate */
+ opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */
+ opus_int toMono, /* I Last frame before a stereo->mono transition */
+ opus_int fs_kHz, /* I Sample rate (kHz) */
+ opus_int frame_length /* I Number of samples */
+);
+
+/* Convert adaptive Mid/Side representation to Left/Right stereo signal */
+void silk_stereo_MS_to_LR(
+ stereo_dec_state *state, /* I/O State */
+ opus_int16 x1[], /* I/O Left input signal, becomes mid signal */
+ opus_int16 x2[], /* I/O Right input signal, becomes side signal */
+ const opus_int32 pred_Q13[], /* I Predictors */
+ opus_int fs_kHz, /* I Samples rate (kHz) */
+ opus_int frame_length /* I Number of samples */
+);
+
+/* Find least-squares prediction gain for one signal based on another and quantize it */
+opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */
+ opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */
+ const opus_int16 x[], /* I Basis signal */
+ const opus_int16 y[], /* I Target signal */
+ opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */
+ opus_int length, /* I Number of samples */
+ opus_int smooth_coef_Q16 /* I Smoothing coefficient */
+);
+
+/* Quantize mid/side predictors */
+void silk_stereo_quant_pred(
+ opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */
+ opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */
+);
+
+/* Entropy code the mid/side quantization indices */
+void silk_stereo_encode_pred(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */
+);
+
+/* Entropy code the mid-only flag */
+void silk_stereo_encode_mid_only(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int8 mid_only_flag
+);
+
+/* Decode mid/side predictors */
+void silk_stereo_decode_pred(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int32 pred_Q13[] /* O Predictors */
+);
+
+/* Decode mid-only flag */
+void silk_stereo_decode_mid_only(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int *decode_only_mid /* O Flag that only mid channel has been coded */
+);
+
+/* Encodes signs of excitation */
+void silk_encode_signs(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ const opus_int8 pulses[], /* I pulse signal */
+ opus_int length, /* I length of input */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I Quantization offset type */
+ const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */
+);
+
+/* Decodes signs of excitation */
+void silk_decode_signs(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 pulses[], /* I/O pulse signal */
+ opus_int length, /* I length of input */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I Quantization offset type */
+ const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */
+);
+
+/* Check encoder control struct */
+opus_int check_control_input(
+ silk_EncControlStruct *encControl /* I Control structure */
+);
+
+/* Control internal sampling rate */
+opus_int silk_control_audio_bandwidth(
+ silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
+ silk_EncControlStruct *encControl /* I Control structure */
+);
+
+/* Control SNR of redidual quantizer */
+opus_int silk_control_SNR(
+ silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
+ opus_int32 TargetRate_bps /* I Target max bitrate (bps) */
+);
+
+/***************/
+/* Shell coder */
+/***************/
+
+/* Encode quantization indices of excitation */
+void silk_encode_pulses(
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I quantOffsetType */
+ opus_int8 pulses[], /* I quantization indices */
+ const opus_int frame_length /* I Frame length */
+);
+
+/* Shell encoder, operates on one shell code frame of 16 pulses */
+void silk_shell_encoder(
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */
+);
+
+/* Shell decoder, operates on one shell code frame of 16 pulses */
+void silk_shell_decoder(
+ opus_int16 *pulses0, /* O data: nonnegative pulse amplitudes */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ const opus_int pulses4 /* I number of pulses per pulse-subframe */
+);
+
+/* Gain scalar quantization with hysteresis, uniform on log scale */
+void silk_gains_quant(
+ opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */
+ opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */
+ opus_int8 *prev_ind, /* I/O last index in previous frame */
+ const opus_int conditional, /* I first gain is delta coded if 1 */
+ const opus_int nb_subfr /* I number of subframes */
+);
+
+/* Gains scalar dequantization, uniform on log scale */
+void silk_gains_dequant(
+ opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */
+ const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */
+ opus_int8 *prev_ind, /* I/O last index in previous frame */
+ const opus_int conditional, /* I first gain is delta coded if 1 */
+ const opus_int nb_subfr /* I number of subframes */
+);
+
+/* Compute unique identifier of gain indices vector */
+opus_int32 silk_gains_ID( /* O returns unique identifier of gains */
+ const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */
+ const opus_int nb_subfr /* I number of subframes */
+);
+
+/* Interpolate two vectors */
+void silk_interpolate(
+ opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */
+ const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */
+ const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */
+ const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */
+ const opus_int d /* I number of parameters */
+);
+
+/* LTP tap quantizer */
+void silk_quant_LTP_gains(
+ opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (un)quantized LTP gains */
+ opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */
+ opus_int8 *periodicity_index, /* O Periodicity Index */
+ opus_int32 *sum_gain_dB_Q7, /* I/O Cumulative max prediction gain */
+ const opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error Weights in Q18 */
+ opus_int mu_Q9, /* I Mu value (R/D tradeoff) */
+ opus_int lowComplexity, /* I Flag for low complexity */
+ const opus_int nb_subfr, /* I number of subframes */
+ int arch /* I Run-time architecture */
+);
+
+/* Entropy constrained matrix-weighted VQ, for a single input data vector */
+void silk_VQ_WMat_EC_c(
+ opus_int8 *ind, /* O index of best codebook vector */
+ opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */
+ opus_int *gain_Q7, /* O sum of absolute LTP coefficients */
+ const opus_int16 *in_Q14, /* I input vector to be quantized */
+ const opus_int32 *W_Q18, /* I weighting matrix */
+ const opus_int8 *cb_Q7, /* I codebook */
+ const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */
+ const opus_uint8 *cl_Q5, /* I code length for each codebook vector */
+ const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */
+ const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ opus_int L /* I number of vectors in codebook */
+);
+
+#if !defined(OVERRIDE_silk_VQ_WMat_EC)
+#define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+ mu_Q9, max_gain_Q7, L, arch) \
+ ((void)(arch),silk_VQ_WMat_EC_c(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+ mu_Q9, max_gain_Q7, L))
+#endif
+
+/************************************/
+/* Noise shaping quantization (NSQ) */
+/************************************/
+
+void silk_NSQ_c(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+);
+
+#if !defined(OVERRIDE_silk_NSQ)
+#define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+ ((void)(arch),silk_NSQ_c(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+#endif
+
+/* Noise shaping using delayed decision */
+void silk_NSQ_del_dec_c(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+);
+
+#if !defined(OVERRIDE_silk_NSQ_del_dec)
+#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+ ((void)(arch),silk_NSQ_del_dec_c(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+#endif
+
+/************/
+/* Silk VAD */
+/************/
+/* Initialize the Silk VAD */
+opus_int silk_VAD_Init( /* O Return value, 0 if success */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+);
+
+/* Get speech activity level in Q8 */
+opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ const opus_int16 pIn[] /* I PCM input */
+);
+
+#if !defined(OVERRIDE_silk_VAD_GetSA_Q8)
+#define silk_VAD_GetSA_Q8(psEnC, pIn, arch) ((void)(arch),silk_VAD_GetSA_Q8_c(psEnC, pIn))
+#endif
+
+/* Low-pass filter with variable cutoff frequency based on */
+/* piece-wise linear interpolation between elliptic filters */
+/* Start by setting transition_frame_no = 1; */
+void silk_LP_variable_cutoff(
+ silk_LP_state *psLP, /* I/O LP filter state */
+ opus_int16 *frame, /* I/O Low-pass filtered output signal */
+ const opus_int frame_length /* I Frame length */
+);
+
+/******************/
+/* NLSF Quantizer */
+/******************/
+/* Limit, stabilize, convert and quantize NLSFs */
+void silk_process_NLSFs(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */
+ opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */
+ const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */
+);
+
+opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */
+ opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */
+ opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */
+ const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */
+ const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */
+ const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */
+ const opus_int nSurvivors, /* I Max survivors after first stage */
+ const opus_int signalType /* I Signal type: 0/1/2 */
+);
+
+/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */
+void silk_NLSF_VQ(
+ opus_int32 err_Q26[], /* O Quantization errors [K] */
+ const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */
+ const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */
+ const opus_int K, /* I Number of codebook vectors */
+ const opus_int LPC_order /* I Number of LPCs */
+);
+
+/* Delayed-decision quantizer for NLSF residuals */
+opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */
+ opus_int8 indices[], /* O Quantization indices [ order ] */
+ const opus_int16 x_Q10[], /* I Input [ order ] */
+ const opus_int16 w_Q5[], /* I Weights [ order ] */
+ const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */
+ const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */
+ const opus_uint8 ec_rates_Q5[], /* I Rates [] */
+ const opus_int quant_step_size_Q16, /* I Quantization step size */
+ const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */
+ const opus_int32 mu_Q20, /* I R/D tradeoff */
+ const opus_int16 order /* I Number of input values */
+);
+
+/* Unpack predictor values and indices for entropy coding tables */
+void silk_NLSF_unpack(
+ opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */
+ opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */
+ const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */
+ const opus_int CB1_index /* I Index of vector in first LSF codebook */
+);
+
+/***********************/
+/* NLSF vector decoder */
+/***********************/
+void silk_NLSF_decode(
+ opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */
+ opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */
+ const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */
+);
+
+/****************************************************/
+/* Decoder Functions */
+/****************************************************/
+opus_int silk_init_decoder(
+ silk_decoder_state *psDec /* I/O Decoder state pointer */
+);
+
+/* Set decoder sampling rate */
+opus_int silk_decoder_set_fs(
+ silk_decoder_state *psDec, /* I/O Decoder state pointer */
+ opus_int fs_kHz, /* I Sampling frequency (kHz) */
+ opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */
+);
+
+/****************/
+/* Decode frame */
+/****************/
+opus_int silk_decode_frame(
+ silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 pOut[], /* O Pointer to output speech frame */
+ opus_int32 *pN, /* O Pointer to size of output frame */
+ opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ int arch /* I Run-time architecture */
+);
+
+/* Decode indices from bitstream */
+void silk_decode_indices(
+ silk_decoder_state *psDec, /* I/O State */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int FrameIndex, /* I Frame number */
+ opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/* Decode parameters from payload */
+void silk_decode_parameters(
+ silk_decoder_state *psDec, /* I/O State */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/* Core decoder. Performs inverse NSQ operation LTP + LPC */
+void silk_decode_core(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I Decoder control */
+ opus_int16 xq[], /* O Decoded speech */
+ const opus_int16 pulses[ MAX_FRAME_LENGTH ], /* I Pulse signal */
+ int arch /* I Run-time architecture */
+);
+
+/* Decode quantization indices of excitation (Shell coding) */
+void silk_decode_pulses(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 pulses[], /* O Excitation signal */
+ const opus_int signalType, /* I Sigtype */
+ const opus_int quantOffsetType, /* I quantOffsetType */
+ const opus_int frame_length /* I Frame length */
+);
+
+/******************/
+/* CNG */
+/******************/
+
+/* Reset CNG */
+void silk_CNG_Reset(
+ silk_decoder_state *psDec /* I/O Decoder state */
+);
+
+/* Updates CNG estimate, and applies the CNG when packet was lost */
+void silk_CNG(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[], /* I/O Signal */
+ opus_int length /* I Length of residual */
+);
+
+/* Encoding of various parameters */
+void silk_encode_indices(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int FrameIndex, /* I Frame number */
+ opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+#endif
diff --git a/external/opus-1.1.4/silk/mips/NSQ_del_dec_mipsr1.h b/external/opus-1.1.4/silk/mips/NSQ_del_dec_mipsr1.h
new file mode 100644
index 0000000..ad1cfe2
--- /dev/null
+++ b/external/opus-1.1.4/silk/mips/NSQ_del_dec_mipsr1.h
@@ -0,0 +1,409 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef __NSQ_DEL_DEC_MIPSR1_H__
+#define __NSQ_DEL_DEC_MIPSR1_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+#define OVERRIDE_silk_noise_shape_quantizer_del_dec
+static inline void silk_noise_shape_quantizer_del_dec(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP filter state */
+ opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int subfr, /* I Subframe number */
+ opus_int shapingLPCOrder, /* I Shaping LPC filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ opus_int warping_Q16, /* I */
+ opus_int nStatesDelayedDecision, /* I Number of states in decision tree */
+ opus_int *smpl_buf_idx, /* I Index to newest samples in buffers */
+ opus_int decisionDelay, /* I */
+ int arch /* I */
+)
+{
+ opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx;
+ opus_int32 Winner_rand_state;
+ opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14;
+ opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10;
+ opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+ opus_int32 tmp1, tmp2, sLF_AR_shp_Q14;
+ opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14;
+ NSQ_sample_struct psSampleState[ MAX_DEL_DEC_STATES ][ 2 ];
+ NSQ_del_dec_struct *psDD;
+ NSQ_sample_struct *psSS;
+ opus_int16 b_Q14_0, b_Q14_1, b_Q14_2, b_Q14_3, b_Q14_4;
+ opus_int16 a_Q12_0, a_Q12_1, a_Q12_2, a_Q12_3, a_Q12_4, a_Q12_5, a_Q12_6;
+ opus_int16 a_Q12_7, a_Q12_8, a_Q12_9, a_Q12_10, a_Q12_11, a_Q12_12, a_Q12_13;
+ opus_int16 a_Q12_14, a_Q12_15;
+
+ opus_int32 cur, prev, next;
+
+ /*Unused.*/
+ (void)arch;
+
+ //Intialize b_Q14 variables
+ b_Q14_0 = b_Q14[ 0 ];
+ b_Q14_1 = b_Q14[ 1 ];
+ b_Q14_2 = b_Q14[ 2 ];
+ b_Q14_3 = b_Q14[ 3 ];
+ b_Q14_4 = b_Q14[ 4 ];
+
+ //Intialize a_Q12 variables
+ a_Q12_0 = a_Q12[0];
+ a_Q12_1 = a_Q12[1];
+ a_Q12_2 = a_Q12[2];
+ a_Q12_3 = a_Q12[3];
+ a_Q12_4 = a_Q12[4];
+ a_Q12_5 = a_Q12[5];
+ a_Q12_6 = a_Q12[6];
+ a_Q12_7 = a_Q12[7];
+ a_Q12_8 = a_Q12[8];
+ a_Q12_9 = a_Q12[9];
+ a_Q12_10 = a_Q12[10];
+ a_Q12_11 = a_Q12[11];
+ a_Q12_12 = a_Q12[12];
+ a_Q12_13 = a_Q12[13];
+ a_Q12_14 = a_Q12[14];
+ a_Q12_15 = a_Q12[15];
+
+ long long temp64;
+
+ silk_assert( nStatesDelayedDecision > 0 );
+
+ shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+ pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 );
+
+ for( i = 0; i < length; i++ ) {
+ /* Perform common calculations used in all states */
+
+ /* Long-term prediction */
+ if( signalType == TYPE_VOICED ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ temp64 = __builtin_mips_mult(pred_lag_ptr[ 0 ], b_Q14_0 );
+ temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -1 ], b_Q14_1 );
+ temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -2 ], b_Q14_2 );
+ temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -3 ], b_Q14_3 );
+ temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -4 ], b_Q14_4 );
+ temp64 += 32768;
+ LTP_pred_Q14 = __builtin_mips_extr_w(temp64, 16);
+ LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */
+ pred_lag_ptr++;
+ } else {
+ LTP_pred_Q14 = 0;
+ }
+
+ /* Long-term shaping */
+ if( lag > 0 ) {
+ /* Symmetric, packed FIR coefficients */
+ n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+ n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
+ n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */
+ shp_lag_ptr++;
+ } else {
+ n_LTP_Q14 = 0;
+ }
+
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ /* Delayed decision state */
+ psDD = &psDelDec[ k ];
+
+ /* Sample state */
+ psSS = psSampleState[ k ];
+
+ /* Generate dither */
+ psDD->Seed = silk_RAND( psDD->Seed );
+
+ /* Pointer used in short term prediction and shaping */
+ psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ];
+ /* Short-term prediction */
+ silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 );
+ temp64 = __builtin_mips_mult(psLPC_Q14[ 0 ], a_Q12_0 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -1 ], a_Q12_1 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -2 ], a_Q12_2 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -3 ], a_Q12_3 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -4 ], a_Q12_4 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -5 ], a_Q12_5 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -6 ], a_Q12_6 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -7 ], a_Q12_7 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -8 ], a_Q12_8 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -9 ], a_Q12_9 );
+ if( predictLPCOrder == 16 ) {
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -10 ], a_Q12_10 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -11 ], a_Q12_11 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -12 ], a_Q12_12 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -13 ], a_Q12_13 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -14 ], a_Q12_14 );
+ temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -15 ], a_Q12_15 );
+ }
+ temp64 += 32768;
+ LPC_pred_Q14 = __builtin_mips_extr_w(temp64, 16);
+
+ LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */
+
+ /* Noise shape feedback */
+ silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
+ /* Output of lowpass section */
+ tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 );
+ psDD->sAR2_Q14[ 0 ] = tmp2;
+
+ temp64 = __builtin_mips_mult(tmp2, AR_shp_Q13[ 0 ] );
+
+ prev = psDD->sAR2_Q14[ 1 ];
+
+ /* Loop over allpass sections */
+ for( j = 2; j < shapingLPCOrder; j += 2 ) {
+ cur = psDD->sAR2_Q14[ j ];
+ next = psDD->sAR2_Q14[ j+1 ];
+ /* Output of allpass section */
+ tmp2 = silk_SMLAWB( prev, cur - tmp1, warping_Q16 );
+ psDD->sAR2_Q14[ j - 1 ] = tmp1;
+ temp64 = __builtin_mips_madd( temp64, tmp1, AR_shp_Q13[ j - 1 ] );
+ temp64 = __builtin_mips_madd( temp64, tmp2, AR_shp_Q13[ j ] );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( cur, next - tmp2, warping_Q16 );
+ psDD->sAR2_Q14[ j + 0 ] = tmp2;
+ prev = next;
+ }
+ psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
+ temp64 = __builtin_mips_madd( temp64, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
+ temp64 += 32768;
+ n_AR_Q14 = __builtin_mips_extr_w(temp64, 16);
+ n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */
+ n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */
+
+ n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */
+ n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */
+ n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */
+
+ /* Input minus prediction plus noise feedback */
+ /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */
+ tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */
+ tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */
+ tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */
+
+ r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */
+
+ /* Flip sign depending on dither */
+ if ( psDD->Seed < 0 ) {
+ r_Q10 = -r_Q10;
+ }
+ r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+ /* Find two quantization level candidates and measure their rate-distortion */
+ q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+ q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+ if( q1_Q0 > 0 ) {
+ q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == 0 ) {
+ q1_Q10 = offset_Q10;
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == -1 ) {
+ q2_Q10 = offset_Q10;
+ q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else { /* q1_Q0 < -1 */
+ q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+ }
+ rr_Q10 = silk_SUB32( r_Q10, q1_Q10 );
+ rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 );
+ rr_Q10 = silk_SUB32( r_Q10, q2_Q10 );
+ rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 );
+
+ if( rd1_Q10 < rd2_Q10 ) {
+ psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+ psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+ psSS[ 0 ].Q_Q10 = q1_Q10;
+ psSS[ 1 ].Q_Q10 = q2_Q10;
+ } else {
+ psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+ psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+ psSS[ 0 ].Q_Q10 = q2_Q10;
+ psSS[ 1 ].Q_Q10 = q1_Q10;
+ }
+
+ /* Update states for best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 );
+ if ( psDD->Seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+ xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+ /* Update states */
+ sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 );
+ psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+ psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14;
+ psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14;
+ psSS[ 0 ].xq_Q14 = xq_Q14;
+
+ /* Update states for second best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 );
+ if ( psDD->Seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+ xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+ /* Update states */
+ sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 );
+ psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+ psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14;
+ psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14;
+ psSS[ 1 ].xq_Q14 = xq_Q14;
+ }
+
+ *smpl_buf_idx = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK; /* Index to newest samples */
+ last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK; /* Index to decisionDelay old samples */
+
+ /* Find winner */
+ RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( k = 1; k < nStatesDelayedDecision; k++ ) {
+ if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
+ Winner_ind = k;
+ }
+ }
+
+ /* Increase RD values of expired states */
+ Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ];
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) {
+ psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 );
+ psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 );
+ silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 );
+ }
+ }
+
+ /* Find worst in first set and best in second set */
+ RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+ RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10;
+ RDmax_ind = 0;
+ RDmin_ind = 0;
+ for( k = 1; k < nStatesDelayedDecision; k++ ) {
+ /* find worst in first set */
+ if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) {
+ RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
+ RDmax_ind = k;
+ }
+ /* find best in second set */
+ if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10;
+ RDmin_ind = k;
+ }
+ }
+
+ /* Replace a state if best from second set outperforms worst in first set */
+ if( RDmin_Q10 < RDmax_Q10 ) {
+ silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i,
+ ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) );
+ silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) );
+ }
+
+ /* Write samples from winner to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ if( subfr > 0 || i >= decisionDelay ) {
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ];
+ sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ];
+ }
+ NSQ->sLTP_shp_buf_idx++;
+ NSQ->sLTP_buf_idx++;
+
+ /* Update states */
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ psSS = &psSampleState[ k ][ 0 ];
+ psDD->LF_AR_Q14 = psSS->LF_AR_Q14;
+ psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14;
+ psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14;
+ psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10;
+ psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 );
+ psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14;
+ psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) );
+ psDD->RandState[ *smpl_buf_idx ] = psDD->Seed;
+ psDD->RD_Q10 = psSS->RD_Q10;
+ }
+ delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10;
+ }
+ /* Update LPC states */
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ }
+}
+
+#endif /* __NSQ_DEL_DEC_MIPSR1_H__ */
diff --git a/external/opus-1.1.4/silk/mips/macros_mipsr1.h b/external/opus-1.1.4/silk/mips/macros_mipsr1.h
new file mode 100644
index 0000000..12ed981
--- /dev/null
+++ b/external/opus-1.1.4/silk/mips/macros_mipsr1.h
@@ -0,0 +1,92 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+
+#ifndef __SILK_MACROS_MIPSR1_H__
+#define __SILK_MACROS_MIPSR1_H__
+
+#define mips_clz(x) __builtin_clz(x)
+
+#undef silk_SMULWB
+static inline int silk_SMULWB(int a, int b)
+{
+ long long ac;
+ int c;
+
+ ac = __builtin_mips_mult(a, (opus_int32)(opus_int16)b);
+ c = __builtin_mips_extr_w(ac, 16);
+
+ return c;
+}
+
+#undef silk_SMLAWB
+#define silk_SMLAWB(a32, b32, c32) ((a32) + silk_SMULWB(b32, c32))
+
+#undef silk_SMULWW
+static inline int silk_SMULWW(int a, int b)
+{
+ long long ac;
+ int c;
+
+ ac = __builtin_mips_mult(a, b);
+ c = __builtin_mips_extr_w(ac, 16);
+
+ return c;
+}
+
+#undef silk_SMLAWW
+static inline int silk_SMLAWW(int a, int b, int c)
+{
+ long long ac;
+ int res;
+
+ ac = __builtin_mips_mult(b, c);
+ res = __builtin_mips_extr_w(ac, 16);
+ res += a;
+
+ return res;
+}
+
+#define OVERRIDE_silk_CLZ16
+static inline opus_int32 silk_CLZ16(opus_int16 in16)
+{
+ int re32;
+ opus_int32 in32 = (opus_int32 )in16;
+ re32 = mips_clz(in32);
+ re32-=16;
+ return re32;
+}
+
+#define OVERRIDE_silk_CLZ32
+static inline opus_int32 silk_CLZ32(opus_int32 in32)
+{
+ int re32;
+ re32 = mips_clz(in32);
+ return re32;
+}
+
+#endif /* __SILK_MACROS_MIPSR1_H__ */
diff --git a/external/opus-1.1.4/silk/mips/sigproc_fix_mipsr1.h b/external/opus-1.1.4/silk/mips/sigproc_fix_mipsr1.h
new file mode 100644
index 0000000..3b0a695
--- /dev/null
+++ b/external/opus-1.1.4/silk/mips/sigproc_fix_mipsr1.h
@@ -0,0 +1,65 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FIX_MIPSR1_H
+#define SILK_SIGPROC_FIX_MIPSR1_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#undef silk_SAT16
+static inline short int silk_SAT16(int a)
+{
+ int c;
+ c = __builtin_mips_shll_s_w(a, 16);
+ c = c>>16;
+
+ return c;
+}
+
+#undef silk_LSHIFT_SAT32
+static inline int silk_LSHIFT_SAT32(int a, int shift)
+{
+ int r;
+
+ r = __builtin_mips_shll_s_w(a, shift);
+
+ return r;
+}
+
+#undef silk_RSHIFT_ROUND
+static inline int silk_RSHIFT_ROUND(int a, int shift)
+{
+ int r;
+
+ r = __builtin_mips_shra_r_w(a, shift);
+ return r;
+}
+
+#endif /* SILK_SIGPROC_FIX_MIPSR1_H */
diff --git a/external/opus-1.1.4/silk/pitch_est_defines.h b/external/opus-1.1.4/silk/pitch_est_defines.h
new file mode 100644
index 0000000..e1e4b5d
--- /dev/null
+++ b/external/opus-1.1.4/silk/pitch_est_defines.h
@@ -0,0 +1,88 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_PE_DEFINES_H
+#define SILK_PE_DEFINES_H
+
+#include "SigProc_FIX.h"
+
+/********************************************************/
+/* Definitions for pitch estimator */
+/********************************************************/
+
+#define PE_MAX_FS_KHZ 16 /* Maximum sampling frequency used */
+
+#define PE_MAX_NB_SUBFR 4
+#define PE_SUBFR_LENGTH_MS 5 /* 5 ms */
+
+#define PE_LTP_MEM_LENGTH_MS ( 4 * PE_SUBFR_LENGTH_MS )
+
+#define PE_MAX_FRAME_LENGTH_MS ( PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS )
+#define PE_MAX_FRAME_LENGTH ( PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ )
+#define PE_MAX_FRAME_LENGTH_ST_1 ( PE_MAX_FRAME_LENGTH >> 2 )
+#define PE_MAX_FRAME_LENGTH_ST_2 ( PE_MAX_FRAME_LENGTH >> 1 )
+
+#define PE_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */
+#define PE_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */
+#define PE_MAX_LAG ( PE_MAX_LAG_MS * PE_MAX_FS_KHZ )
+#define PE_MIN_LAG ( PE_MIN_LAG_MS * PE_MAX_FS_KHZ )
+
+#define PE_D_SRCH_LENGTH 24
+
+#define PE_NB_STAGE3_LAGS 5
+
+#define PE_NB_CBKS_STAGE2 3
+#define PE_NB_CBKS_STAGE2_EXT 11
+
+#define PE_NB_CBKS_STAGE3_MAX 34
+#define PE_NB_CBKS_STAGE3_MID 24
+#define PE_NB_CBKS_STAGE3_MIN 16
+
+#define PE_NB_CBKS_STAGE3_10MS 12
+#define PE_NB_CBKS_STAGE2_10MS 3
+
+#define PE_SHORTLAG_BIAS 0.2f /* for logarithmic weighting */
+#define PE_PREVLAG_BIAS 0.2f /* for logarithmic weighting */
+#define PE_FLATCONTOUR_BIAS 0.05f
+
+#define SILK_PE_MIN_COMPLEX 0
+#define SILK_PE_MID_COMPLEX 1
+#define SILK_PE_MAX_COMPLEX 2
+
+/* Tables for 20 ms frames */
+extern const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ];
+extern const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ];
+extern const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ];
+extern const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ];
+
+/* Tables for 10 ms frames */
+extern const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ 3 ];
+extern const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 12 ];
+extern const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ];
+
+#endif
+
diff --git a/external/opus-1.1.4/silk/pitch_est_tables.c b/external/opus-1.1.4/silk/pitch_est_tables.c
new file mode 100644
index 0000000..81a8bac
--- /dev/null
+++ b/external/opus-1.1.4/silk/pitch_est_tables.c
@@ -0,0 +1,99 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "typedef.h"
+#include "pitch_est_defines.h"
+
+const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ PE_NB_CBKS_STAGE2_10MS ] =
+{
+ {0, 1, 0},
+ {0, 0, 1}
+};
+
+const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ PE_NB_CBKS_STAGE3_10MS ] =
+{
+ { 0, 0, 1,-1, 1,-1, 2,-2, 2,-2, 3,-3},
+ { 0, 1, 0, 1,-1, 2,-1, 2,-2, 3,-2, 3}
+};
+
+const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ] =
+{
+ {-3, 7},
+ {-2, 7}
+};
+
+const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ] =
+{
+ {0, 2,-1,-1,-1, 0, 0, 1, 1, 0, 1},
+ {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0},
+ {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
+ {0,-1, 2, 1, 0, 1, 1, 0, 0,-1,-1}
+};
+
+const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ] =
+{
+ {0, 0, 1,-1, 0, 1,-1, 0,-1, 1,-2, 2,-2,-2, 2,-3, 2, 3,-3,-4, 3,-4, 4, 4,-5, 5,-6,-5, 6,-7, 6, 5, 8,-9},
+ {0, 0, 1, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 0, 1,-1,-1, 1,-1, 2, 1,-1, 2,-2,-2, 2,-2, 2, 2, 3,-3},
+ {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,-1, 1, 0, 0, 2, 1,-1, 2,-1,-1, 2,-1, 2, 2,-1, 3,-2,-2,-2, 3},
+ {0, 1, 0, 0, 1, 0, 1,-1, 2,-1, 2,-1, 2, 3,-2, 3,-2,-2, 4, 4,-3, 5,-3,-4, 6,-4, 6, 5,-5, 8,-6,-5,-7, 9}
+};
+
+const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ] =
+{
+ /* Lags to search for low number of stage3 cbks */
+ {
+ {-5,8},
+ {-1,6},
+ {-1,6},
+ {-4,10}
+ },
+ /* Lags to search for middle number of stage3 cbks */
+ {
+ {-6,10},
+ {-2,6},
+ {-1,6},
+ {-5,10}
+ },
+ /* Lags to search for max number of stage3 cbks */
+ {
+ {-9,12},
+ {-3,7},
+ {-2,7},
+ {-7,13}
+ }
+};
+
+const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ] =
+{
+ PE_NB_CBKS_STAGE3_MIN,
+ PE_NB_CBKS_STAGE3_MID,
+ PE_NB_CBKS_STAGE3_MAX
+};
diff --git a/external/opus-1.1.4/silk/process_NLSFs.c b/external/opus-1.1.4/silk/process_NLSFs.c
new file mode 100644
index 0000000..0ab71f0
--- /dev/null
+++ b/external/opus-1.1.4/silk/process_NLSFs.c
@@ -0,0 +1,107 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Limit, stabilize, convert and quantize NLSFs */
+void silk_process_NLSFs(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */
+ opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */
+ const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */
+)
+{
+ opus_int i, doInterpolate;
+ opus_int NLSF_mu_Q20;
+ opus_int16 i_sqr_Q15;
+ opus_int16 pNLSF0_temp_Q15[ MAX_LPC_ORDER ];
+ opus_int16 pNLSFW_QW[ MAX_LPC_ORDER ];
+ opus_int16 pNLSFW0_temp_QW[ MAX_LPC_ORDER ];
+
+ silk_assert( psEncC->speech_activity_Q8 >= 0 );
+ silk_assert( psEncC->speech_activity_Q8 <= SILK_FIX_CONST( 1.0, 8 ) );
+ silk_assert( psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == ( 1 << 2 ) );
+
+ /***********************/
+ /* Calculate mu values */
+ /***********************/
+ /* NLSF_mu = 0.003 - 0.0015 * psEnc->speech_activity; */
+ NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.003, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 );
+ if( psEncC->nb_subfr == 2 ) {
+ /* Multiply by 1.5 for 10 ms packets */
+ NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 );
+ }
+
+ silk_assert( NLSF_mu_Q20 > 0 );
+ silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) );
+
+ /* Calculate NLSF weights */
+ silk_NLSF_VQ_weights_laroia( pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder );
+
+ /* Update NLSF weights for interpolated NLSFs */
+ doInterpolate = ( psEncC->useInterpolatedNLSFs == 1 ) && ( psEncC->indices.NLSFInterpCoef_Q2 < 4 );
+ if( doInterpolate ) {
+ /* Calculate the interpolated NLSF vector for the first half */
+ silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15,
+ psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder );
+
+ /* Calculate first half NLSF weights for the interpolated NLSFs */
+ silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC->predictLPCOrder );
+
+ /* Update NLSF weights with contribution from first half */
+ i_sqr_Q15 = silk_LSHIFT( silk_SMULBB( psEncC->indices.NLSFInterpCoef_Q2, psEncC->indices.NLSFInterpCoef_Q2 ), 11 );
+ for( i = 0; i < psEncC->predictLPCOrder; i++ ) {
+ pNLSFW_QW[ i ] = silk_ADD16( silk_RSHIFT( pNLSFW_QW[ i ], 1 ), silk_RSHIFT(
+ silk_SMULBB( pNLSFW0_temp_QW[ i ], i_sqr_Q15 ), 16) );
+ silk_assert( pNLSFW_QW[ i ] >= 1 );
+ }
+ }
+
+ silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW,
+ NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType );
+
+ /* Convert quantized NLSFs back to LPC coefficients */
+ silk_NLSF2A( PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder );
+
+ if( doInterpolate ) {
+ /* Calculate the interpolated, quantized LSF vector for the first half */
+ silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15,
+ psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder );
+
+ /* Convert back to LPC coefficients */
+ silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder );
+
+ } else {
+ /* Copy LPC coefficients for first half from second half */
+ silk_assert( psEncC->predictLPCOrder <= MAX_LPC_ORDER );
+ silk_memcpy( PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof( opus_int16 ) );
+ }
+}
diff --git a/external/opus-1.1.4/silk/quant_LTP_gains.c b/external/opus-1.1.4/silk/quant_LTP_gains.c
new file mode 100644
index 0000000..513a8c4
--- /dev/null
+++ b/external/opus-1.1.4/silk/quant_LTP_gains.c
@@ -0,0 +1,129 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "tuning_parameters.h"
+
+void silk_quant_LTP_gains(
+ opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (un)quantized LTP gains */
+ opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */
+ opus_int8 *periodicity_index, /* O Periodicity Index */
+ opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */
+ const opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error Weights in Q18 */
+ opus_int mu_Q9, /* I Mu value (R/D tradeoff) */
+ opus_int lowComplexity, /* I Flag for low complexity */
+ const opus_int nb_subfr, /* I number of subframes */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int j, k, cbk_size;
+ opus_int8 temp_idx[ MAX_NB_SUBFR ];
+ const opus_uint8 *cl_ptr_Q5;
+ const opus_int8 *cbk_ptr_Q7;
+ const opus_uint8 *cbk_gain_ptr_Q7;
+ const opus_int16 *b_Q14_ptr;
+ const opus_int32 *W_Q18_ptr;
+ opus_int32 rate_dist_Q14_subfr, rate_dist_Q14, min_rate_dist_Q14;
+ opus_int32 sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7, gain_Q7;
+
+ /***************************************************/
+ /* iterate over different codebooks with different */
+ /* rates/distortions, and choose best */
+ /***************************************************/
+ min_rate_dist_Q14 = silk_int32_MAX;
+ best_sum_log_gain_Q7 = 0;
+ for( k = 0; k < 3; k++ ) {
+ /* Safety margin for pitch gain control, to take into account factors
+ such as state rescaling/rewhitening. */
+ opus_int32 gain_safety = SILK_FIX_CONST( 0.4, 7 );
+
+ cl_ptr_Q5 = silk_LTP_gain_BITS_Q5_ptrs[ k ];
+ cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ k ];
+ cbk_gain_ptr_Q7 = silk_LTP_vq_gain_ptrs_Q7[ k ];
+ cbk_size = silk_LTP_vq_sizes[ k ];
+
+ /* Set up pointer to first subframe */
+ W_Q18_ptr = W_Q18;
+ b_Q14_ptr = B_Q14;
+
+ rate_dist_Q14 = 0;
+ sum_log_gain_tmp_Q7 = *sum_log_gain_Q7;
+ for( j = 0; j < nb_subfr; j++ ) {
+ max_gain_Q7 = silk_log2lin( ( SILK_FIX_CONST( MAX_SUM_LOG_GAIN_DB / 6.0, 7 ) - sum_log_gain_tmp_Q7 )
+ + SILK_FIX_CONST( 7, 7 ) ) - gain_safety;
+
+ silk_VQ_WMat_EC(
+ &temp_idx[ j ], /* O index of best codebook vector */
+ &rate_dist_Q14_subfr, /* O best weighted quantization error + mu * rate */
+ &gain_Q7, /* O sum of absolute LTP coefficients */
+ b_Q14_ptr, /* I input vector to be quantized */
+ W_Q18_ptr, /* I weighting matrix */
+ cbk_ptr_Q7, /* I codebook */
+ cbk_gain_ptr_Q7, /* I codebook effective gains */
+ cl_ptr_Q5, /* I code length for each codebook vector */
+ mu_Q9, /* I tradeoff between weighted error and rate */
+ max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ cbk_size, /* I number of vectors in codebook */
+ arch /* I Run-time architecture */
+ );
+
+ rate_dist_Q14 = silk_ADD_POS_SAT32( rate_dist_Q14, rate_dist_Q14_subfr );
+ sum_log_gain_tmp_Q7 = silk_max(0, sum_log_gain_tmp_Q7
+ + silk_lin2log( gain_safety + gain_Q7 ) - SILK_FIX_CONST( 7, 7 ));
+
+ b_Q14_ptr += LTP_ORDER;
+ W_Q18_ptr += LTP_ORDER * LTP_ORDER;
+ }
+
+ /* Avoid never finding a codebook */
+ rate_dist_Q14 = silk_min( silk_int32_MAX - 1, rate_dist_Q14 );
+
+ if( rate_dist_Q14 < min_rate_dist_Q14 ) {
+ min_rate_dist_Q14 = rate_dist_Q14;
+ *periodicity_index = (opus_int8)k;
+ silk_memcpy( cbk_index, temp_idx, nb_subfr * sizeof( opus_int8 ) );
+ best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7;
+ }
+
+ /* Break early in low-complexity mode if rate distortion is below threshold */
+ if( lowComplexity && ( rate_dist_Q14 < silk_LTP_gain_middle_avg_RD_Q14 ) ) {
+ break;
+ }
+ }
+
+ cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ];
+ for( j = 0; j < nb_subfr; j++ ) {
+ for( k = 0; k < LTP_ORDER; k++ ) {
+ B_Q14[ j * LTP_ORDER + k ] = silk_LSHIFT( cbk_ptr_Q7[ cbk_index[ j ] * LTP_ORDER + k ], 7 );
+ }
+ }
+ *sum_log_gain_Q7 = best_sum_log_gain_Q7;
+}
diff --git a/external/opus-1.1.4/silk/resampler.c b/external/opus-1.1.4/silk/resampler.c
new file mode 100644
index 0000000..374fbb3
--- /dev/null
+++ b/external/opus-1.1.4/silk/resampler.c
@@ -0,0 +1,215 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ * Matrix of resampling methods used:
+ * Fs_out (kHz)
+ * 8 12 16 24 48
+ *
+ * 8 C UF U UF UF
+ * 12 AF C UF U UF
+ * Fs_in (kHz) 16 D AF C UF UF
+ * 24 AF D AF C U
+ * 48 AF AF AF D C
+ *
+ * C -> Copy (no resampling)
+ * D -> Allpass-based 2x downsampling
+ * U -> Allpass-based 2x upsampling
+ * UF -> Allpass-based 2x upsampling followed by FIR interpolation
+ * AF -> AR2 filter followed by FIR interpolation
+ */
+
+#include "resampler_private.h"
+
+/* Tables with delay compensation values to equalize total delay for different modes */
+static const opus_int8 delay_matrix_enc[ 5 ][ 3 ] = {
+/* in \ out 8 12 16 */
+/* 8 */ { 6, 0, 3 },
+/* 12 */ { 0, 7, 3 },
+/* 16 */ { 0, 1, 10 },
+/* 24 */ { 0, 2, 6 },
+/* 48 */ { 18, 10, 12 }
+};
+
+static const opus_int8 delay_matrix_dec[ 3 ][ 5 ] = {
+/* in \ out 8 12 16 24 48 */
+/* 8 */ { 4, 0, 2, 0, 0 },
+/* 12 */ { 0, 9, 4, 7, 4 },
+/* 16 */ { 0, 3, 12, 7, 7 }
+};
+
+/* Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4] */
+#define rateID(R) ( ( ( ((R)>>12) - ((R)>16000) ) >> ((R)>24000) ) - 1 )
+
+#define USE_silk_resampler_copy (0)
+#define USE_silk_resampler_private_up2_HQ_wrapper (1)
+#define USE_silk_resampler_private_IIR_FIR (2)
+#define USE_silk_resampler_private_down_FIR (3)
+
+/* Initialize/reset the resampler state for a given pair of input/output sampling rates */
+opus_int silk_resampler_init(
+ silk_resampler_state_struct *S, /* I/O Resampler state */
+ opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */
+ opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */
+ opus_int forEnc /* I If 1: encoder; if 0: decoder */
+)
+{
+ opus_int up2x;
+
+ /* Clear state */
+ silk_memset( S, 0, sizeof( silk_resampler_state_struct ) );
+
+ /* Input checking */
+ if( forEnc ) {
+ if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 && Fs_Hz_in != 24000 && Fs_Hz_in != 48000 ) ||
+ ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 ) ) {
+ silk_assert( 0 );
+ return -1;
+ }
+ S->inputDelay = delay_matrix_enc[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ];
+ } else {
+ if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 ) ||
+ ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000 ) ) {
+ silk_assert( 0 );
+ return -1;
+ }
+ S->inputDelay = delay_matrix_dec[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ];
+ }
+
+ S->Fs_in_kHz = silk_DIV32_16( Fs_Hz_in, 1000 );
+ S->Fs_out_kHz = silk_DIV32_16( Fs_Hz_out, 1000 );
+
+ /* Number of samples processed per batch */
+ S->batchSize = S->Fs_in_kHz * RESAMPLER_MAX_BATCH_SIZE_MS;
+
+ /* Find resampler with the right sampling ratio */
+ up2x = 0;
+ if( Fs_Hz_out > Fs_Hz_in ) {
+ /* Upsample */
+ if( Fs_Hz_out == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 1 */
+ /* Special case: directly use 2x upsampler */
+ S->resampler_function = USE_silk_resampler_private_up2_HQ_wrapper;
+ } else {
+ /* Default resampler */
+ S->resampler_function = USE_silk_resampler_private_IIR_FIR;
+ up2x = 1;
+ }
+ } else if ( Fs_Hz_out < Fs_Hz_in ) {
+ /* Downsample */
+ S->resampler_function = USE_silk_resampler_private_down_FIR;
+ if( silk_MUL( Fs_Hz_out, 4 ) == silk_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 4 */
+ S->FIR_Fracs = 3;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0;
+ S->Coefs = silk_Resampler_3_4_COEFS;
+ } else if( silk_MUL( Fs_Hz_out, 3 ) == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 3 */
+ S->FIR_Fracs = 2;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0;
+ S->Coefs = silk_Resampler_2_3_COEFS;
+ } else if( silk_MUL( Fs_Hz_out, 2 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 2 */
+ S->FIR_Fracs = 1;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR1;
+ S->Coefs = silk_Resampler_1_2_COEFS;
+ } else if( silk_MUL( Fs_Hz_out, 3 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 3 */
+ S->FIR_Fracs = 1;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2;
+ S->Coefs = silk_Resampler_1_3_COEFS;
+ } else if( silk_MUL( Fs_Hz_out, 4 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 4 */
+ S->FIR_Fracs = 1;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2;
+ S->Coefs = silk_Resampler_1_4_COEFS;
+ } else if( silk_MUL( Fs_Hz_out, 6 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 6 */
+ S->FIR_Fracs = 1;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2;
+ S->Coefs = silk_Resampler_1_6_COEFS;
+ } else {
+ /* None available */
+ silk_assert( 0 );
+ return -1;
+ }
+ } else {
+ /* Input and output sampling rates are equal: copy */
+ S->resampler_function = USE_silk_resampler_copy;
+ }
+
+ /* Ratio of input/output samples */
+ S->invRatio_Q16 = silk_LSHIFT32( silk_DIV32( silk_LSHIFT32( Fs_Hz_in, 14 + up2x ), Fs_Hz_out ), 2 );
+ /* Make sure the ratio is rounded up */
+ while( silk_SMULWW( S->invRatio_Q16, Fs_Hz_out ) < silk_LSHIFT32( Fs_Hz_in, up2x ) ) {
+ S->invRatio_Q16++;
+ }
+
+ return 0;
+}
+
+/* Resampler: convert from one sampling rate to another */
+/* Input and output sampling rate are at most 48000 Hz */
+opus_int silk_resampler(
+ silk_resampler_state_struct *S, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+)
+{
+ opus_int nSamples;
+
+ /* Need at least 1 ms of input data */
+ silk_assert( inLen >= S->Fs_in_kHz );
+ /* Delay can't exceed the 1 ms of buffering */
+ silk_assert( S->inputDelay <= S->Fs_in_kHz );
+
+ nSamples = S->Fs_in_kHz - S->inputDelay;
+
+ /* Copy to delay buffer */
+ silk_memcpy( &S->delayBuf[ S->inputDelay ], in, nSamples * sizeof( opus_int16 ) );
+
+ switch( S->resampler_function ) {
+ case USE_silk_resampler_private_up2_HQ_wrapper:
+ silk_resampler_private_up2_HQ_wrapper( S, out, S->delayBuf, S->Fs_in_kHz );
+ silk_resampler_private_up2_HQ_wrapper( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz );
+ break;
+ case USE_silk_resampler_private_IIR_FIR:
+ silk_resampler_private_IIR_FIR( S, out, S->delayBuf, S->Fs_in_kHz );
+ silk_resampler_private_IIR_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz );
+ break;
+ case USE_silk_resampler_private_down_FIR:
+ silk_resampler_private_down_FIR( S, out, S->delayBuf, S->Fs_in_kHz );
+ silk_resampler_private_down_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz );
+ break;
+ default:
+ silk_memcpy( out, S->delayBuf, S->Fs_in_kHz * sizeof( opus_int16 ) );
+ silk_memcpy( &out[ S->Fs_out_kHz ], &in[ nSamples ], ( inLen - S->Fs_in_kHz ) * sizeof( opus_int16 ) );
+ }
+
+ /* Copy to delay buffer */
+ silk_memcpy( S->delayBuf, &in[ inLen - S->inputDelay ], S->inputDelay * sizeof( opus_int16 ) );
+
+ return 0;
+}
diff --git a/external/opus-1.1.4/silk/resampler_down2.c b/external/opus-1.1.4/silk/resampler_down2.c
new file mode 100644
index 0000000..cec3634
--- /dev/null
+++ b/external/opus-1.1.4/silk/resampler_down2.c
@@ -0,0 +1,74 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_rom.h"
+
+/* Downsample by a factor 2 */
+void silk_resampler_down2(
+ opus_int32 *S, /* I/O State vector [ 2 ] */
+ opus_int16 *out, /* O Output signal [ floor(len/2) ] */
+ const opus_int16 *in, /* I Input signal [ len ] */
+ opus_int32 inLen /* I Number of input samples */
+)
+{
+ opus_int32 k, len2 = silk_RSHIFT32( inLen, 1 );
+ opus_int32 in32, out32, Y, X;
+
+ silk_assert( silk_resampler_down2_0 > 0 );
+ silk_assert( silk_resampler_down2_1 < 0 );
+
+ /* Internal variables and state are in Q10 format */
+ for( k = 0; k < len2; k++ ) {
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 );
+
+ /* All-pass section for even input sample */
+ Y = silk_SUB32( in32, S[ 0 ] );
+ X = silk_SMLAWB( Y, Y, silk_resampler_down2_1 );
+ out32 = silk_ADD32( S[ 0 ], X );
+ S[ 0 ] = silk_ADD32( in32, X );
+
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 );
+
+ /* All-pass section for odd input sample, and add to output of previous section */
+ Y = silk_SUB32( in32, S[ 1 ] );
+ X = silk_SMULWB( Y, silk_resampler_down2_0 );
+ out32 = silk_ADD32( out32, S[ 1 ] );
+ out32 = silk_ADD32( out32, X );
+ S[ 1 ] = silk_ADD32( in32, X );
+
+ /* Add, convert back to int16 and store to output */
+ out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32, 11 ) );
+ }
+}
+
diff --git a/external/opus-1.1.4/silk/resampler_down2_3.c b/external/opus-1.1.4/silk/resampler_down2_3.c
new file mode 100644
index 0000000..4342614
--- /dev/null
+++ b/external/opus-1.1.4/silk/resampler_down2_3.c
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_private.h"
+#include "stack_alloc.h"
+
+#define ORDER_FIR 4
+
+/* Downsample by a factor 2/3, low quality */
+void silk_resampler_down2_3(
+ opus_int32 *S, /* I/O State vector [ 6 ] */
+ opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */
+ const opus_int16 *in, /* I Input signal [ inLen ] */
+ opus_int32 inLen /* I Number of input samples */
+)
+{
+ opus_int32 nSamplesIn, counter, res_Q6;
+ VARDECL( opus_int32, buf );
+ opus_int32 *buf_ptr;
+ SAVE_STACK;
+
+ ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 );
+
+ /* Copy buffered samples to start of buffer */
+ silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) );
+
+ /* Iterate over blocks of frameSizeIn input samples */
+ while( 1 ) {
+ nSamplesIn = silk_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN );
+
+ /* Second-order AR filter (output in Q8) */
+ silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in,
+ silk_Resampler_2_3_COEFS_LQ, nSamplesIn );
+
+ /* Interpolate filtered signal */
+ buf_ptr = buf;
+ counter = nSamplesIn;
+ while( counter > 2 ) {
+ /* Inner product */
+ res_Q6 = silk_SMULWB( buf_ptr[ 0 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] );
+
+ /* Scale down, saturate and store in output array */
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+
+ res_Q6 = silk_SMULWB( buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] );
+
+ /* Scale down, saturate and store in output array */
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+
+ buf_ptr += 3;
+ counter -= 3;
+ }
+
+ in += nSamplesIn;
+ inLen -= nSamplesIn;
+
+ if( inLen > 0 ) {
+ /* More iterations to do; copy last part of filtered signal to beginning of buffer */
+ silk_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) );
+ } else {
+ break;
+ }
+ }
+
+ /* Copy last part of filtered signal to the state for the next call */
+ silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/resampler_private.h b/external/opus-1.1.4/silk/resampler_private.h
new file mode 100644
index 0000000..422a7d9
--- /dev/null
+++ b/external/opus-1.1.4/silk/resampler_private.h
@@ -0,0 +1,88 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_RESAMPLER_PRIVATE_H
+#define SILK_RESAMPLER_PRIVATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_structs.h"
+#include "resampler_rom.h"
+
+/* Number of input samples to process in the inner loop */
+#define RESAMPLER_MAX_BATCH_SIZE_MS 10
+#define RESAMPLER_MAX_FS_KHZ 48
+#define RESAMPLER_MAX_BATCH_SIZE_IN ( RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ )
+
+/* Description: Hybrid IIR/FIR polyphase implementation of resampling */
+void silk_resampler_private_IIR_FIR(
+ void *SS, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+);
+
+/* Description: Hybrid IIR/FIR polyphase implementation of resampling */
+void silk_resampler_private_down_FIR(
+ void *SS, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+);
+
+/* Upsample by a factor 2, high quality */
+void silk_resampler_private_up2_HQ_wrapper(
+ void *SS, /* I/O Resampler state (unused) */
+ opus_int16 *out, /* O Output signal [ 2 * len ] */
+ const opus_int16 *in, /* I Input signal [ len ] */
+ opus_int32 len /* I Number of input samples */
+);
+
+/* Upsample by a factor 2, high quality */
+void silk_resampler_private_up2_HQ(
+ opus_int32 *S, /* I/O Resampler state [ 6 ] */
+ opus_int16 *out, /* O Output signal [ 2 * len ] */
+ const opus_int16 *in, /* I Input signal [ len ] */
+ opus_int32 len /* I Number of input samples */
+);
+
+/* Second order AR filter */
+void silk_resampler_private_AR2(
+ opus_int32 S[], /* I/O State vector [ 2 ] */
+ opus_int32 out_Q8[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ const opus_int16 A_Q14[], /* I AR coefficients, Q14 */
+ opus_int32 len /* I Signal length */
+);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* SILK_RESAMPLER_PRIVATE_H */
diff --git a/external/opus-1.1.4/silk/resampler_private_AR2.c b/external/opus-1.1.4/silk/resampler_private_AR2.c
new file mode 100644
index 0000000..5fff237
--- /dev/null
+++ b/external/opus-1.1.4/silk/resampler_private_AR2.c
@@ -0,0 +1,55 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_private.h"
+
+/* Second order AR filter with single delay elements */
+void silk_resampler_private_AR2(
+ opus_int32 S[], /* I/O State vector [ 2 ] */
+ opus_int32 out_Q8[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ const opus_int16 A_Q14[], /* I AR coefficients, Q14 */
+ opus_int32 len /* I Signal length */
+)
+{
+ opus_int32 k;
+ opus_int32 out32;
+
+ for( k = 0; k < len; k++ ) {
+ out32 = silk_ADD_LSHIFT32( S[ 0 ], (opus_int32)in[ k ], 8 );
+ out_Q8[ k ] = out32;
+ out32 = silk_LSHIFT( out32, 2 );
+ S[ 0 ] = silk_SMLAWB( S[ 1 ], out32, A_Q14[ 0 ] );
+ S[ 1 ] = silk_SMULWB( out32, A_Q14[ 1 ] );
+ }
+}
+
diff --git a/external/opus-1.1.4/silk/resampler_private_IIR_FIR.c b/external/opus-1.1.4/silk/resampler_private_IIR_FIR.c
new file mode 100644
index 0000000..6b2b3a2
--- /dev/null
+++ b/external/opus-1.1.4/silk/resampler_private_IIR_FIR.c
@@ -0,0 +1,107 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_private.h"
+#include "stack_alloc.h"
+
+static OPUS_INLINE opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL(
+ opus_int16 *out,
+ opus_int16 *buf,
+ opus_int32 max_index_Q16,
+ opus_int32 index_increment_Q16
+)
+{
+ opus_int32 index_Q16, res_Q15;
+ opus_int16 *buf_ptr;
+ opus_int32 table_index;
+
+ /* Interpolate upsampled signal and store in output array */
+ for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+ table_index = silk_SMULWB( index_Q16 & 0xFFFF, 12 );
+ buf_ptr = &buf[ index_Q16 >> 16 ];
+
+ res_Q15 = silk_SMULBB( buf_ptr[ 0 ], silk_resampler_frac_FIR_12[ table_index ][ 0 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 1 ], silk_resampler_frac_FIR_12[ table_index ][ 1 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 2 ], silk_resampler_frac_FIR_12[ table_index ][ 2 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 3 ], silk_resampler_frac_FIR_12[ table_index ][ 3 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 4 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 3 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 5 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 2 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 6 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 1 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 7 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 0 ] );
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q15, 15 ) );
+ }
+ return out;
+}
+/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */
+void silk_resampler_private_IIR_FIR(
+ void *SS, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+)
+{
+ silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS;
+ opus_int32 nSamplesIn;
+ opus_int32 max_index_Q16, index_increment_Q16;
+ VARDECL( opus_int16, buf );
+ SAVE_STACK;
+
+ ALLOC( buf, 2 * S->batchSize + RESAMPLER_ORDER_FIR_12, opus_int16 );
+
+ /* Copy buffered samples to start of buffer */
+ silk_memcpy( buf, S->sFIR.i16, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) );
+
+ /* Iterate over blocks of frameSizeIn input samples */
+ index_increment_Q16 = S->invRatio_Q16;
+ while( 1 ) {
+ nSamplesIn = silk_min( inLen, S->batchSize );
+
+ /* Upsample 2x */
+ silk_resampler_private_up2_HQ( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn );
+
+ max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 ); /* + 1 because 2x upsampling */
+ out = silk_resampler_private_IIR_FIR_INTERPOL( out, buf, max_index_Q16, index_increment_Q16 );
+ in += nSamplesIn;
+ inLen -= nSamplesIn;
+
+ if( inLen > 0 ) {
+ /* More iterations to do; copy last part of filtered signal to beginning of buffer */
+ silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) );
+ } else {
+ break;
+ }
+ }
+
+ /* Copy last part of filtered signal to the state for the next call */
+ silk_memcpy( S->sFIR.i16, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) );
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/resampler_private_down_FIR.c b/external/opus-1.1.4/silk/resampler_private_down_FIR.c
new file mode 100644
index 0000000..783e42b
--- /dev/null
+++ b/external/opus-1.1.4/silk/resampler_private_down_FIR.c
@@ -0,0 +1,194 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_private.h"
+#include "stack_alloc.h"
+
+static OPUS_INLINE opus_int16 *silk_resampler_private_down_FIR_INTERPOL(
+ opus_int16 *out,
+ opus_int32 *buf,
+ const opus_int16 *FIR_Coefs,
+ opus_int FIR_Order,
+ opus_int FIR_Fracs,
+ opus_int32 max_index_Q16,
+ opus_int32 index_increment_Q16
+)
+{
+ opus_int32 index_Q16, res_Q6;
+ opus_int32 *buf_ptr;
+ opus_int32 interpol_ind;
+ const opus_int16 *interpol_ptr;
+
+ switch( FIR_Order ) {
+ case RESAMPLER_DOWN_ORDER_FIR0:
+ for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+ /* Integer part gives pointer to buffered input */
+ buf_ptr = buf + silk_RSHIFT( index_Q16, 16 );
+
+ /* Fractional part gives interpolation coefficients */
+ interpol_ind = silk_SMULWB( index_Q16 & 0xFFFF, FIR_Fracs );
+
+ /* Inner product */
+ interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * interpol_ind ];
+ res_Q6 = silk_SMULWB( buf_ptr[ 0 ], interpol_ptr[ 0 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 6 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 7 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 8 ] );
+ interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * ( FIR_Fracs - 1 - interpol_ind ) ];
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 17 ], interpol_ptr[ 0 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 16 ], interpol_ptr[ 1 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 15 ], interpol_ptr[ 2 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 14 ], interpol_ptr[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 13 ], interpol_ptr[ 4 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 12 ], interpol_ptr[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 6 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 7 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 9 ], interpol_ptr[ 8 ] );
+
+ /* Scale down, saturate and store in output array */
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+ }
+ break;
+ case RESAMPLER_DOWN_ORDER_FIR1:
+ for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+ /* Integer part gives pointer to buffered input */
+ buf_ptr = buf + silk_RSHIFT( index_Q16, 16 );
+
+ /* Inner product */
+ res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 23 ] ), FIR_Coefs[ 0 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 22 ] ), FIR_Coefs[ 1 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 21 ] ), FIR_Coefs[ 2 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 20 ] ), FIR_Coefs[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 19 ] ), FIR_Coefs[ 4 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 18 ] ), FIR_Coefs[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 17 ] ), FIR_Coefs[ 6 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 16 ] ), FIR_Coefs[ 7 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 15 ] ), FIR_Coefs[ 8 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 14 ] ), FIR_Coefs[ 9 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 13 ] ), FIR_Coefs[ 10 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 12 ] ), FIR_Coefs[ 11 ] );
+
+ /* Scale down, saturate and store in output array */
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+ }
+ break;
+ case RESAMPLER_DOWN_ORDER_FIR2:
+ for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+ /* Integer part gives pointer to buffered input */
+ buf_ptr = buf + silk_RSHIFT( index_Q16, 16 );
+
+ /* Inner product */
+ res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 35 ] ), FIR_Coefs[ 0 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 34 ] ), FIR_Coefs[ 1 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 33 ] ), FIR_Coefs[ 2 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 32 ] ), FIR_Coefs[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 31 ] ), FIR_Coefs[ 4 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 30 ] ), FIR_Coefs[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 29 ] ), FIR_Coefs[ 6 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 28 ] ), FIR_Coefs[ 7 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 27 ] ), FIR_Coefs[ 8 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 26 ] ), FIR_Coefs[ 9 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 25 ] ), FIR_Coefs[ 10 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 24 ] ), FIR_Coefs[ 11 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 12 ], buf_ptr[ 23 ] ), FIR_Coefs[ 12 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 13 ], buf_ptr[ 22 ] ), FIR_Coefs[ 13 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 14 ], buf_ptr[ 21 ] ), FIR_Coefs[ 14 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 15 ], buf_ptr[ 20 ] ), FIR_Coefs[ 15 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 16 ], buf_ptr[ 19 ] ), FIR_Coefs[ 16 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 17 ], buf_ptr[ 18 ] ), FIR_Coefs[ 17 ] );
+
+ /* Scale down, saturate and store in output array */
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+ }
+ break;
+ default:
+ silk_assert( 0 );
+ }
+ return out;
+}
+
+/* Resample with a 2nd order AR filter followed by FIR interpolation */
+void silk_resampler_private_down_FIR(
+ void *SS, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+)
+{
+ silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS;
+ opus_int32 nSamplesIn;
+ opus_int32 max_index_Q16, index_increment_Q16;
+ VARDECL( opus_int32, buf );
+ const opus_int16 *FIR_Coefs;
+ SAVE_STACK;
+
+ ALLOC( buf, S->batchSize + S->FIR_Order, opus_int32 );
+
+ /* Copy buffered samples to start of buffer */
+ silk_memcpy( buf, S->sFIR.i32, S->FIR_Order * sizeof( opus_int32 ) );
+
+ FIR_Coefs = &S->Coefs[ 2 ];
+
+ /* Iterate over blocks of frameSizeIn input samples */
+ index_increment_Q16 = S->invRatio_Q16;
+ while( 1 ) {
+ nSamplesIn = silk_min( inLen, S->batchSize );
+
+ /* Second-order AR filter (output in Q8) */
+ silk_resampler_private_AR2( S->sIIR, &buf[ S->FIR_Order ], in, S->Coefs, nSamplesIn );
+
+ max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 );
+
+ /* Interpolate filtered signal */
+ out = silk_resampler_private_down_FIR_INTERPOL( out, buf, FIR_Coefs, S->FIR_Order,
+ S->FIR_Fracs, max_index_Q16, index_increment_Q16 );
+
+ in += nSamplesIn;
+ inLen -= nSamplesIn;
+
+ if( inLen > 1 ) {
+ /* More iterations to do; copy last part of filtered signal to beginning of buffer */
+ silk_memcpy( buf, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) );
+ } else {
+ break;
+ }
+ }
+
+ /* Copy last part of filtered signal to the state for the next call */
+ silk_memcpy( S->sFIR.i32, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/resampler_private_up2_HQ.c b/external/opus-1.1.4/silk/resampler_private_up2_HQ.c
new file mode 100644
index 0000000..c7ec8de
--- /dev/null
+++ b/external/opus-1.1.4/silk/resampler_private_up2_HQ.c
@@ -0,0 +1,113 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_private.h"
+
+/* Upsample by a factor 2, high quality */
+/* Uses 2nd order allpass filters for the 2x upsampling, followed by a */
+/* notch filter just above Nyquist. */
+void silk_resampler_private_up2_HQ(
+ opus_int32 *S, /* I/O Resampler state [ 6 ] */
+ opus_int16 *out, /* O Output signal [ 2 * len ] */
+ const opus_int16 *in, /* I Input signal [ len ] */
+ opus_int32 len /* I Number of input samples */
+)
+{
+ opus_int32 k;
+ opus_int32 in32, out32_1, out32_2, Y, X;
+
+ silk_assert( silk_resampler_up2_hq_0[ 0 ] > 0 );
+ silk_assert( silk_resampler_up2_hq_0[ 1 ] > 0 );
+ silk_assert( silk_resampler_up2_hq_0[ 2 ] < 0 );
+ silk_assert( silk_resampler_up2_hq_1[ 0 ] > 0 );
+ silk_assert( silk_resampler_up2_hq_1[ 1 ] > 0 );
+ silk_assert( silk_resampler_up2_hq_1[ 2 ] < 0 );
+
+ /* Internal variables and state are in Q10 format */
+ for( k = 0; k < len; k++ ) {
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ k ], 10 );
+
+ /* First all-pass section for even output sample */
+ Y = silk_SUB32( in32, S[ 0 ] );
+ X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 0 ] );
+ out32_1 = silk_ADD32( S[ 0 ], X );
+ S[ 0 ] = silk_ADD32( in32, X );
+
+ /* Second all-pass section for even output sample */
+ Y = silk_SUB32( out32_1, S[ 1 ] );
+ X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 1 ] );
+ out32_2 = silk_ADD32( S[ 1 ], X );
+ S[ 1 ] = silk_ADD32( out32_1, X );
+
+ /* Third all-pass section for even output sample */
+ Y = silk_SUB32( out32_2, S[ 2 ] );
+ X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_0[ 2 ] );
+ out32_1 = silk_ADD32( S[ 2 ], X );
+ S[ 2 ] = silk_ADD32( out32_2, X );
+
+ /* Apply gain in Q15, convert back to int16 and store to output */
+ out[ 2 * k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) );
+
+ /* First all-pass section for odd output sample */
+ Y = silk_SUB32( in32, S[ 3 ] );
+ X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 0 ] );
+ out32_1 = silk_ADD32( S[ 3 ], X );
+ S[ 3 ] = silk_ADD32( in32, X );
+
+ /* Second all-pass section for odd output sample */
+ Y = silk_SUB32( out32_1, S[ 4 ] );
+ X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 1 ] );
+ out32_2 = silk_ADD32( S[ 4 ], X );
+ S[ 4 ] = silk_ADD32( out32_1, X );
+
+ /* Third all-pass section for odd output sample */
+ Y = silk_SUB32( out32_2, S[ 5 ] );
+ X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_1[ 2 ] );
+ out32_1 = silk_ADD32( S[ 5 ], X );
+ S[ 5 ] = silk_ADD32( out32_2, X );
+
+ /* Apply gain in Q15, convert back to int16 and store to output */
+ out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) );
+ }
+}
+
+void silk_resampler_private_up2_HQ_wrapper(
+ void *SS, /* I/O Resampler state (unused) */
+ opus_int16 *out, /* O Output signal [ 2 * len ] */
+ const opus_int16 *in, /* I Input signal [ len ] */
+ opus_int32 len /* I Number of input samples */
+)
+{
+ silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS;
+ silk_resampler_private_up2_HQ( S->sIIR, out, in, len );
+}
diff --git a/external/opus-1.1.4/silk/resampler_rom.c b/external/opus-1.1.4/silk/resampler_rom.c
new file mode 100644
index 0000000..5e6b044
--- /dev/null
+++ b/external/opus-1.1.4/silk/resampler_rom.c
@@ -0,0 +1,96 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Filter coefficients for IIR/FIR polyphase resampling *
+ * Total size: 179 Words (358 Bytes) */
+
+#include "resampler_private.h"
+
+/* Matlab code for the notch filter coefficients: */
+/* B = [1, 0.147, 1]; A = [1, 0.107, 0.89]; G = 0.93; freqz(G * B, A, 2^14, 16e3); axis([0, 8000, -10, 1]) */
+/* fprintf('\t%6d, %6d, %6d, %6d\n', round(B(2)*2^16), round(-A(2)*2^16), round((1-A(3))*2^16), round(G*2^15)) */
+/* const opus_int16 silk_resampler_up2_hq_notch[ 4 ] = { 9634, -7012, 7209, 30474 }; */
+
+/* Tables with IIR and FIR coefficients for fractional downsamplers (123 Words) */
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = {
+ -20694, -13867,
+ -49, 64, 17, -157, 353, -496, 163, 11047, 22205,
+ -39, 6, 91, -170, 186, 23, -896, 6336, 19928,
+ -19, -36, 102, -89, -24, 328, -951, 2568, 15909,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = {
+ -14457, -14019,
+ 64, 128, -122, 36, 310, -768, 584, 9267, 17733,
+ 12, 128, 18, -142, 288, -117, -865, 4123, 14459,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ] = {
+ 616, -14323,
+ -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = {
+ 16102, -15162,
+ -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = {
+ 22500, -15099,
+ 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = {
+ 27540, -15257,
+ 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ] = {
+ -2797, -6507,
+ 4697, 10739,
+ 1567, 8276,
+};
+
+/* Table with interplation fractions of 1/24, 3/24, 5/24, ... , 23/24 : 23/24 (46 Words) */
+silk_DWORD_ALIGN const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ] = {
+ { 189, -600, 617, 30567 },
+ { 117, -159, -1070, 29704 },
+ { 52, 221, -2392, 28276 },
+ { -4, 529, -3350, 26341 },
+ { -48, 758, -3956, 23973 },
+ { -80, 905, -4235, 21254 },
+ { -99, 972, -4222, 18278 },
+ { -107, 967, -3957, 15143 },
+ { -103, 896, -3487, 11950 },
+ { -91, 773, -2865, 8798 },
+ { -71, 611, -2143, 5784 },
+ { -46, 425, -1375, 2996 },
+};
diff --git a/external/opus-1.1.4/silk/resampler_rom.h b/external/opus-1.1.4/silk/resampler_rom.h
new file mode 100644
index 0000000..490b338
--- /dev/null
+++ b/external/opus-1.1.4/silk/resampler_rom.h
@@ -0,0 +1,68 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_FIX_RESAMPLER_ROM_H
+#define SILK_FIX_RESAMPLER_ROM_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "typedef.h"
+#include "resampler_structs.h"
+
+#define RESAMPLER_DOWN_ORDER_FIR0 18
+#define RESAMPLER_DOWN_ORDER_FIR1 24
+#define RESAMPLER_DOWN_ORDER_FIR2 36
+#define RESAMPLER_ORDER_FIR_12 8
+
+/* Tables for 2x downsampler */
+static const opus_int16 silk_resampler_down2_0 = 9872;
+static const opus_int16 silk_resampler_down2_1 = 39809 - 65536;
+
+/* Tables for 2x upsampler, high quality */
+static const opus_int16 silk_resampler_up2_hq_0[ 3 ] = { 1746, 14986, 39083 - 65536 };
+static const opus_int16 silk_resampler_up2_hq_1[ 3 ] = { 6854, 25769, 55542 - 65536 };
+
+/* Tables with IIR and FIR coefficients for fractional downsamplers */
+extern const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ];
+extern const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ];
+extern const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ];
+extern const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ];
+extern const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ];
+extern const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ];
+extern const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ];
+
+/* Table with interplation fractions of 1/24, 3/24, ..., 23/24 */
+extern const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_FIX_RESAMPLER_ROM_H */
diff --git a/external/opus-1.1.4/silk/resampler_structs.h b/external/opus-1.1.4/silk/resampler_structs.h
new file mode 100644
index 0000000..9e9457d
--- /dev/null
+++ b/external/opus-1.1.4/silk/resampler_structs.h
@@ -0,0 +1,60 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_RESAMPLER_STRUCTS_H
+#define SILK_RESAMPLER_STRUCTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SILK_RESAMPLER_MAX_FIR_ORDER 36
+#define SILK_RESAMPLER_MAX_IIR_ORDER 6
+
+typedef struct _silk_resampler_state_struct{
+ opus_int32 sIIR[ SILK_RESAMPLER_MAX_IIR_ORDER ]; /* this must be the first element of this struct */
+ union{
+ opus_int32 i32[ SILK_RESAMPLER_MAX_FIR_ORDER ];
+ opus_int16 i16[ SILK_RESAMPLER_MAX_FIR_ORDER ];
+ } sFIR;
+ opus_int16 delayBuf[ 48 ];
+ opus_int resampler_function;
+ opus_int batchSize;
+ opus_int32 invRatio_Q16;
+ opus_int FIR_Order;
+ opus_int FIR_Fracs;
+ opus_int Fs_in_kHz;
+ opus_int Fs_out_kHz;
+ opus_int inputDelay;
+ const opus_int16 *Coefs;
+} silk_resampler_state_struct;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* SILK_RESAMPLER_STRUCTS_H */
+
diff --git a/external/opus-1.1.4/silk/shell_coder.c b/external/opus-1.1.4/silk/shell_coder.c
new file mode 100644
index 0000000..4af3414
--- /dev/null
+++ b/external/opus-1.1.4/silk/shell_coder.c
@@ -0,0 +1,151 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* shell coder; pulse-subframe length is hardcoded */
+
+static OPUS_INLINE void combine_pulses(
+ opus_int *out, /* O combined pulses vector [len] */
+ const opus_int *in, /* I input vector [2 * len] */
+ const opus_int len /* I number of OUTPUT samples */
+)
+{
+ opus_int k;
+ for( k = 0; k < len; k++ ) {
+ out[ k ] = in[ 2 * k ] + in[ 2 * k + 1 ];
+ }
+}
+
+static OPUS_INLINE void encode_split(
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ const opus_int p_child1, /* I pulse amplitude of first child subframe */
+ const opus_int p, /* I pulse amplitude of current subframe */
+ const opus_uint8 *shell_table /* I table of shell cdfs */
+)
+{
+ if( p > 0 ) {
+ ec_enc_icdf( psRangeEnc, p_child1, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 );
+ }
+}
+
+static OPUS_INLINE void decode_split(
+ opus_int16 *p_child1, /* O pulse amplitude of first child subframe */
+ opus_int16 *p_child2, /* O pulse amplitude of second child subframe */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ const opus_int p, /* I pulse amplitude of current subframe */
+ const opus_uint8 *shell_table /* I table of shell cdfs */
+)
+{
+ if( p > 0 ) {
+ p_child1[ 0 ] = ec_dec_icdf( psRangeDec, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 );
+ p_child2[ 0 ] = p - p_child1[ 0 ];
+ } else {
+ p_child1[ 0 ] = 0;
+ p_child2[ 0 ] = 0;
+ }
+}
+
+/* Shell encoder, operates on one shell code frame of 16 pulses */
+void silk_shell_encoder(
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */
+)
+{
+ opus_int pulses1[ 8 ], pulses2[ 4 ], pulses3[ 2 ], pulses4[ 1 ];
+
+ /* this function operates on one shell code frame of 16 pulses */
+ silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 );
+
+ /* tree representation per pulse-subframe */
+ combine_pulses( pulses1, pulses0, 8 );
+ combine_pulses( pulses2, pulses1, 4 );
+ combine_pulses( pulses3, pulses2, 2 );
+ combine_pulses( pulses4, pulses3, 1 );
+
+ encode_split( psRangeEnc, pulses3[ 0 ], pulses4[ 0 ], silk_shell_code_table3 );
+
+ encode_split( psRangeEnc, pulses2[ 0 ], pulses3[ 0 ], silk_shell_code_table2 );
+
+ encode_split( psRangeEnc, pulses1[ 0 ], pulses2[ 0 ], silk_shell_code_table1 );
+ encode_split( psRangeEnc, pulses0[ 0 ], pulses1[ 0 ], silk_shell_code_table0 );
+ encode_split( psRangeEnc, pulses0[ 2 ], pulses1[ 1 ], silk_shell_code_table0 );
+
+ encode_split( psRangeEnc, pulses1[ 2 ], pulses2[ 1 ], silk_shell_code_table1 );
+ encode_split( psRangeEnc, pulses0[ 4 ], pulses1[ 2 ], silk_shell_code_table0 );
+ encode_split( psRangeEnc, pulses0[ 6 ], pulses1[ 3 ], silk_shell_code_table0 );
+
+ encode_split( psRangeEnc, pulses2[ 2 ], pulses3[ 1 ], silk_shell_code_table2 );
+
+ encode_split( psRangeEnc, pulses1[ 4 ], pulses2[ 2 ], silk_shell_code_table1 );
+ encode_split( psRangeEnc, pulses0[ 8 ], pulses1[ 4 ], silk_shell_code_table0 );
+ encode_split( psRangeEnc, pulses0[ 10 ], pulses1[ 5 ], silk_shell_code_table0 );
+
+ encode_split( psRangeEnc, pulses1[ 6 ], pulses2[ 3 ], silk_shell_code_table1 );
+ encode_split( psRangeEnc, pulses0[ 12 ], pulses1[ 6 ], silk_shell_code_table0 );
+ encode_split( psRangeEnc, pulses0[ 14 ], pulses1[ 7 ], silk_shell_code_table0 );
+}
+
+
+/* Shell decoder, operates on one shell code frame of 16 pulses */
+void silk_shell_decoder(
+ opus_int16 *pulses0, /* O data: nonnegative pulse amplitudes */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ const opus_int pulses4 /* I number of pulses per pulse-subframe */
+)
+{
+ opus_int16 pulses3[ 2 ], pulses2[ 4 ], pulses1[ 8 ];
+
+ /* this function operates on one shell code frame of 16 pulses */
+ silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 );
+
+ decode_split( &pulses3[ 0 ], &pulses3[ 1 ], psRangeDec, pulses4, silk_shell_code_table3 );
+
+ decode_split( &pulses2[ 0 ], &pulses2[ 1 ], psRangeDec, pulses3[ 0 ], silk_shell_code_table2 );
+
+ decode_split( &pulses1[ 0 ], &pulses1[ 1 ], psRangeDec, pulses2[ 0 ], silk_shell_code_table1 );
+ decode_split( &pulses0[ 0 ], &pulses0[ 1 ], psRangeDec, pulses1[ 0 ], silk_shell_code_table0 );
+ decode_split( &pulses0[ 2 ], &pulses0[ 3 ], psRangeDec, pulses1[ 1 ], silk_shell_code_table0 );
+
+ decode_split( &pulses1[ 2 ], &pulses1[ 3 ], psRangeDec, pulses2[ 1 ], silk_shell_code_table1 );
+ decode_split( &pulses0[ 4 ], &pulses0[ 5 ], psRangeDec, pulses1[ 2 ], silk_shell_code_table0 );
+ decode_split( &pulses0[ 6 ], &pulses0[ 7 ], psRangeDec, pulses1[ 3 ], silk_shell_code_table0 );
+
+ decode_split( &pulses2[ 2 ], &pulses2[ 3 ], psRangeDec, pulses3[ 1 ], silk_shell_code_table2 );
+
+ decode_split( &pulses1[ 4 ], &pulses1[ 5 ], psRangeDec, pulses2[ 2 ], silk_shell_code_table1 );
+ decode_split( &pulses0[ 8 ], &pulses0[ 9 ], psRangeDec, pulses1[ 4 ], silk_shell_code_table0 );
+ decode_split( &pulses0[ 10 ], &pulses0[ 11 ], psRangeDec, pulses1[ 5 ], silk_shell_code_table0 );
+
+ decode_split( &pulses1[ 6 ], &pulses1[ 7 ], psRangeDec, pulses2[ 3 ], silk_shell_code_table1 );
+ decode_split( &pulses0[ 12 ], &pulses0[ 13 ], psRangeDec, pulses1[ 6 ], silk_shell_code_table0 );
+ decode_split( &pulses0[ 14 ], &pulses0[ 15 ], psRangeDec, pulses1[ 7 ], silk_shell_code_table0 );
+}
diff --git a/external/opus-1.1.4/silk/sigm_Q15.c b/external/opus-1.1.4/silk/sigm_Q15.c
new file mode 100644
index 0000000..3c507d2
--- /dev/null
+++ b/external/opus-1.1.4/silk/sigm_Q15.c
@@ -0,0 +1,76 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Approximate sigmoid function */
+
+#include "SigProc_FIX.h"
+
+/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */
+static const opus_int32 sigm_LUT_slope_Q10[ 6 ] = {
+ 237, 153, 73, 30, 12, 7
+};
+/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */
+static const opus_int32 sigm_LUT_pos_Q15[ 6 ] = {
+ 16384, 23955, 28861, 31213, 32178, 32548
+};
+/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */
+static const opus_int32 sigm_LUT_neg_Q15[ 6 ] = {
+ 16384, 8812, 3906, 1554, 589, 219
+};
+
+opus_int silk_sigm_Q15(
+ opus_int in_Q5 /* I */
+)
+{
+ opus_int ind;
+
+ if( in_Q5 < 0 ) {
+ /* Negative input */
+ in_Q5 = -in_Q5;
+ if( in_Q5 >= 6 * 32 ) {
+ return 0; /* Clip */
+ } else {
+ /* Linear interpolation of look up table */
+ ind = silk_RSHIFT( in_Q5, 5 );
+ return( sigm_LUT_neg_Q15[ ind ] - silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) );
+ }
+ } else {
+ /* Positive input */
+ if( in_Q5 >= 6 * 32 ) {
+ return 32767; /* clip */
+ } else {
+ /* Linear interpolation of look up table */
+ ind = silk_RSHIFT( in_Q5, 5 );
+ return( sigm_LUT_pos_Q15[ ind ] + silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) );
+ }
+ }
+}
+
diff --git a/external/opus-1.1.4/silk/sort.c b/external/opus-1.1.4/silk/sort.c
new file mode 100644
index 0000000..7187c9e
--- /dev/null
+++ b/external/opus-1.1.4/silk/sort.c
@@ -0,0 +1,154 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Insertion sort (fast for already almost sorted arrays): */
+/* Best case: O(n) for an already sorted array */
+/* Worst case: O(n^2) for an inversely sorted array */
+/* */
+/* Shell short: https://en.wikipedia.org/wiki/Shell_sort */
+
+#include "SigProc_FIX.h"
+
+void silk_insertion_sort_increasing(
+ opus_int32 *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+)
+{
+ opus_int32 value;
+ opus_int i, j;
+
+ /* Safety checks */
+ silk_assert( K > 0 );
+ silk_assert( L > 0 );
+ silk_assert( L >= K );
+
+ /* Write start indices in index vector */
+ for( i = 0; i < K; i++ ) {
+ idx[ i ] = i;
+ }
+
+ /* Sort vector elements by value, increasing order */
+ for( i = 1; i < K; i++ ) {
+ value = a[ i ];
+ for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+
+ /* If less than L values are asked for, check the remaining values, */
+ /* but only spend CPU to ensure that the K first values are correct */
+ for( i = K; i < L; i++ ) {
+ value = a[ i ];
+ if( value < a[ K - 1 ] ) {
+ for( j = K - 2; ( j >= 0 ) && ( value < a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+ }
+}
+
+#ifdef FIXED_POINT
+/* This function is only used by the fixed-point build */
+void silk_insertion_sort_decreasing_int16(
+ opus_int16 *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+)
+{
+ opus_int i, j;
+ opus_int value;
+
+ /* Safety checks */
+ silk_assert( K > 0 );
+ silk_assert( L > 0 );
+ silk_assert( L >= K );
+
+ /* Write start indices in index vector */
+ for( i = 0; i < K; i++ ) {
+ idx[ i ] = i;
+ }
+
+ /* Sort vector elements by value, decreasing order */
+ for( i = 1; i < K; i++ ) {
+ value = a[ i ];
+ for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+
+ /* If less than L values are asked for, check the remaining values, */
+ /* but only spend CPU to ensure that the K first values are correct */
+ for( i = K; i < L; i++ ) {
+ value = a[ i ];
+ if( value > a[ K - 1 ] ) {
+ for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+ }
+}
+#endif
+
+void silk_insertion_sort_increasing_all_values_int16(
+ opus_int16 *a, /* I/O Unsorted / Sorted vector */
+ const opus_int L /* I Vector length */
+)
+{
+ opus_int value;
+ opus_int i, j;
+
+ /* Safety checks */
+ silk_assert( L > 0 );
+
+ /* Sort vector elements by value, increasing order */
+ for( i = 1; i < L; i++ ) {
+ value = a[ i ];
+ for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ }
+}
diff --git a/external/opus-1.1.4/silk/stereo_LR_to_MS.c b/external/opus-1.1.4/silk/stereo_LR_to_MS.c
new file mode 100644
index 0000000..dda0298
--- /dev/null
+++ b/external/opus-1.1.4/silk/stereo_LR_to_MS.c
@@ -0,0 +1,229 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/* Convert Left/Right stereo signal to adaptive Mid/Side representation */
+void silk_stereo_LR_to_MS(
+ stereo_enc_state *state, /* I/O State */
+ opus_int16 x1[], /* I/O Left input signal, becomes mid signal */
+ opus_int16 x2[], /* I/O Right input signal, becomes side signal */
+ opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */
+ opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */
+ opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */
+ opus_int32 total_rate_bps, /* I Total bitrate */
+ opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */
+ opus_int toMono, /* I Last frame before a stereo->mono transition */
+ opus_int fs_kHz, /* I Sample rate (kHz) */
+ opus_int frame_length /* I Number of samples */
+)
+{
+ opus_int n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13;
+ opus_int32 sum, diff, smooth_coef_Q16, pred_Q13[ 2 ], pred0_Q13, pred1_Q13;
+ opus_int32 LP_ratio_Q14, HP_ratio_Q14, frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24;
+ VARDECL( opus_int16, side );
+ VARDECL( opus_int16, LP_mid );
+ VARDECL( opus_int16, HP_mid );
+ VARDECL( opus_int16, LP_side );
+ VARDECL( opus_int16, HP_side );
+ opus_int16 *mid = &x1[ -2 ];
+ SAVE_STACK;
+
+ ALLOC( side, frame_length + 2, opus_int16 );
+ /* Convert to basic mid/side signals */
+ for( n = 0; n < frame_length + 2; n++ ) {
+ sum = x1[ n - 2 ] + (opus_int32)x2[ n - 2 ];
+ diff = x1[ n - 2 ] - (opus_int32)x2[ n - 2 ];
+ mid[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 );
+ side[ n ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( diff, 1 ) );
+ }
+
+ /* Buffering */
+ silk_memcpy( mid, state->sMid, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( side, state->sSide, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( state->sMid, &mid[ frame_length ], 2 * sizeof( opus_int16 ) );
+ silk_memcpy( state->sSide, &side[ frame_length ], 2 * sizeof( opus_int16 ) );
+
+ /* LP and HP filter mid signal */
+ ALLOC( LP_mid, frame_length, opus_int16 );
+ ALLOC( HP_mid, frame_length, opus_int16 );
+ for( n = 0; n < frame_length; n++ ) {
+ sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 2 );
+ LP_mid[ n ] = sum;
+ HP_mid[ n ] = mid[ n + 1 ] - sum;
+ }
+
+ /* LP and HP filter side signal */
+ ALLOC( LP_side, frame_length, opus_int16 );
+ ALLOC( HP_side, frame_length, opus_int16 );
+ for( n = 0; n < frame_length; n++ ) {
+ sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( side[ n ] + (opus_int32)side[ n + 2 ], side[ n + 1 ], 1 ), 2 );
+ LP_side[ n ] = sum;
+ HP_side[ n ] = side[ n + 1 ] - sum;
+ }
+
+ /* Find energies and predictors */
+ is10msFrame = frame_length == 10 * fs_kHz;
+ smooth_coef_Q16 = is10msFrame ?
+ SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF / 2, 16 ) :
+ SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF, 16 );
+ smooth_coef_Q16 = silk_SMULWB( silk_SMULBB( prev_speech_act_Q8, prev_speech_act_Q8 ), smooth_coef_Q16 );
+
+ pred_Q13[ 0 ] = silk_stereo_find_predictor( &LP_ratio_Q14, LP_mid, LP_side, &state->mid_side_amp_Q0[ 0 ], frame_length, smooth_coef_Q16 );
+ pred_Q13[ 1 ] = silk_stereo_find_predictor( &HP_ratio_Q14, HP_mid, HP_side, &state->mid_side_amp_Q0[ 2 ], frame_length, smooth_coef_Q16 );
+ /* Ratio of the norms of residual and mid signals */
+ frac_Q16 = silk_SMLABB( HP_ratio_Q14, LP_ratio_Q14, 3 );
+ frac_Q16 = silk_min( frac_Q16, SILK_FIX_CONST( 1, 16 ) );
+
+ /* Determine bitrate distribution between mid and side, and possibly reduce stereo width */
+ total_rate_bps -= is10msFrame ? 1200 : 600; /* Subtract approximate bitrate for coding stereo parameters */
+ if( total_rate_bps < 1 ) {
+ total_rate_bps = 1;
+ }
+ min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 900 );
+ silk_assert( min_mid_rate_bps < 32767 );
+ /* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */
+ frac_3_Q16 = silk_MUL( 3, frac_Q16 );
+ mid_side_rates_bps[ 0 ] = silk_DIV32_varQ( total_rate_bps, SILK_FIX_CONST( 8 + 5, 16 ) + frac_3_Q16, 16+3 );
+ /* If Mid bitrate below minimum, reduce stereo width */
+ if( mid_side_rates_bps[ 0 ] < min_mid_rate_bps ) {
+ mid_side_rates_bps[ 0 ] = min_mid_rate_bps;
+ mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ];
+ /* width = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */
+ width_Q14 = silk_DIV32_varQ( silk_LSHIFT( mid_side_rates_bps[ 1 ], 1 ) - min_mid_rate_bps,
+ silk_SMULWB( SILK_FIX_CONST( 1, 16 ) + frac_3_Q16, min_mid_rate_bps ), 14+2 );
+ width_Q14 = silk_LIMIT( width_Q14, 0, SILK_FIX_CONST( 1, 14 ) );
+ } else {
+ mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ];
+ width_Q14 = SILK_FIX_CONST( 1, 14 );
+ }
+
+ /* Smoother */
+ state->smth_width_Q14 = (opus_int16)silk_SMLAWB( state->smth_width_Q14, width_Q14 - state->smth_width_Q14, smooth_coef_Q16 );
+
+ /* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */
+ *mid_only_flag = 0;
+ if( toMono ) {
+ /* Last frame before stereo->mono transition; collapse stereo width */
+ width_Q14 = 0;
+ pred_Q13[ 0 ] = 0;
+ pred_Q13[ 1 ] = 0;
+ silk_stereo_quant_pred( pred_Q13, ix );
+ } else if( state->width_prev_Q14 == 0 &&
+ ( 8 * total_rate_bps < 13 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.05, 14 ) ) )
+ {
+ /* Code as panned-mono; previous frame already had zero width */
+ /* Scale down and quantize predictors */
+ pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+ pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+ silk_stereo_quant_pred( pred_Q13, ix );
+ /* Collapse stereo width */
+ width_Q14 = 0;
+ pred_Q13[ 0 ] = 0;
+ pred_Q13[ 1 ] = 0;
+ mid_side_rates_bps[ 0 ] = total_rate_bps;
+ mid_side_rates_bps[ 1 ] = 0;
+ *mid_only_flag = 1;
+ } else if( state->width_prev_Q14 != 0 &&
+ ( 8 * total_rate_bps < 11 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.02, 14 ) ) )
+ {
+ /* Transition to zero-width stereo */
+ /* Scale down and quantize predictors */
+ pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+ pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+ silk_stereo_quant_pred( pred_Q13, ix );
+ /* Collapse stereo width */
+ width_Q14 = 0;
+ pred_Q13[ 0 ] = 0;
+ pred_Q13[ 1 ] = 0;
+ } else if( state->smth_width_Q14 > SILK_FIX_CONST( 0.95, 14 ) ) {
+ /* Full-width stereo coding */
+ silk_stereo_quant_pred( pred_Q13, ix );
+ width_Q14 = SILK_FIX_CONST( 1, 14 );
+ } else {
+ /* Reduced-width stereo coding; scale down and quantize predictors */
+ pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+ pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+ silk_stereo_quant_pred( pred_Q13, ix );
+ width_Q14 = state->smth_width_Q14;
+ }
+
+ /* Make sure to keep on encoding until the tapered output has been transmitted */
+ if( *mid_only_flag == 1 ) {
+ state->silent_side_len += frame_length - STEREO_INTERP_LEN_MS * fs_kHz;
+ if( state->silent_side_len < LA_SHAPE_MS * fs_kHz ) {
+ *mid_only_flag = 0;
+ } else {
+ /* Limit to avoid wrapping around */
+ state->silent_side_len = 10000;
+ }
+ } else {
+ state->silent_side_len = 0;
+ }
+
+ if( *mid_only_flag == 0 && mid_side_rates_bps[ 1 ] < 1 ) {
+ mid_side_rates_bps[ 1 ] = 1;
+ mid_side_rates_bps[ 0 ] = silk_max_int( 1, total_rate_bps - mid_side_rates_bps[ 1 ]);
+ }
+
+ /* Interpolate predictors and subtract prediction from side channel */
+ pred0_Q13 = -state->pred_prev_Q13[ 0 ];
+ pred1_Q13 = -state->pred_prev_Q13[ 1 ];
+ w_Q24 = silk_LSHIFT( state->width_prev_Q14, 10 );
+ denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz );
+ delta0_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 );
+ delta1_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 );
+ deltaw_Q24 = silk_LSHIFT( silk_SMULWB( width_Q14 - state->width_prev_Q14, denom_Q16 ), 10 );
+ for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) {
+ pred0_Q13 += delta0_Q13;
+ pred1_Q13 += delta1_Q13;
+ w_Q24 += deltaw_Q24;
+ sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */
+ sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */
+ sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */
+ x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+ }
+
+ pred0_Q13 = -pred_Q13[ 0 ];
+ pred1_Q13 = -pred_Q13[ 1 ];
+ w_Q24 = silk_LSHIFT( width_Q14, 10 );
+ for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) {
+ sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */
+ sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */
+ sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */
+ x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+ }
+ state->pred_prev_Q13[ 0 ] = (opus_int16)pred_Q13[ 0 ];
+ state->pred_prev_Q13[ 1 ] = (opus_int16)pred_Q13[ 1 ];
+ state->width_prev_Q14 = (opus_int16)width_Q14;
+ RESTORE_STACK;
+}
diff --git a/external/opus-1.1.4/silk/stereo_MS_to_LR.c b/external/opus-1.1.4/silk/stereo_MS_to_LR.c
new file mode 100644
index 0000000..62521a4
--- /dev/null
+++ b/external/opus-1.1.4/silk/stereo_MS_to_LR.c
@@ -0,0 +1,85 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Convert adaptive Mid/Side representation to Left/Right stereo signal */
+void silk_stereo_MS_to_LR(
+ stereo_dec_state *state, /* I/O State */
+ opus_int16 x1[], /* I/O Left input signal, becomes mid signal */
+ opus_int16 x2[], /* I/O Right input signal, becomes side signal */
+ const opus_int32 pred_Q13[], /* I Predictors */
+ opus_int fs_kHz, /* I Samples rate (kHz) */
+ opus_int frame_length /* I Number of samples */
+)
+{
+ opus_int n, denom_Q16, delta0_Q13, delta1_Q13;
+ opus_int32 sum, diff, pred0_Q13, pred1_Q13;
+
+ /* Buffering */
+ silk_memcpy( x1, state->sMid, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( x2, state->sSide, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( state->sMid, &x1[ frame_length ], 2 * sizeof( opus_int16 ) );
+ silk_memcpy( state->sSide, &x2[ frame_length ], 2 * sizeof( opus_int16 ) );
+
+ /* Interpolate predictors and add prediction to side channel */
+ pred0_Q13 = state->pred_prev_Q13[ 0 ];
+ pred1_Q13 = state->pred_prev_Q13[ 1 ];
+ denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz );
+ delta0_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 );
+ delta1_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 );
+ for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) {
+ pred0_Q13 += delta0_Q13;
+ pred1_Q13 += delta1_Q13;
+ sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */
+ sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */
+ sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */
+ x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+ }
+ pred0_Q13 = pred_Q13[ 0 ];
+ pred1_Q13 = pred_Q13[ 1 ];
+ for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) {
+ sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */
+ sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */
+ sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */
+ x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+ }
+ state->pred_prev_Q13[ 0 ] = pred_Q13[ 0 ];
+ state->pred_prev_Q13[ 1 ] = pred_Q13[ 1 ];
+
+ /* Convert to left/right signals */
+ for( n = 0; n < frame_length; n++ ) {
+ sum = x1[ n + 1 ] + (opus_int32)x2[ n + 1 ];
+ diff = x1[ n + 1 ] - (opus_int32)x2[ n + 1 ];
+ x1[ n + 1 ] = (opus_int16)silk_SAT16( sum );
+ x2[ n + 1 ] = (opus_int16)silk_SAT16( diff );
+ }
+}
diff --git a/external/opus-1.1.4/silk/stereo_decode_pred.c b/external/opus-1.1.4/silk/stereo_decode_pred.c
new file mode 100644
index 0000000..56ba392
--- /dev/null
+++ b/external/opus-1.1.4/silk/stereo_decode_pred.c
@@ -0,0 +1,73 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Decode mid/side predictors */
+void silk_stereo_decode_pred(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int32 pred_Q13[] /* O Predictors */
+)
+{
+ opus_int n, ix[ 2 ][ 3 ];
+ opus_int32 low_Q13, step_Q13;
+
+ /* Entropy decoding */
+ n = ec_dec_icdf( psRangeDec, silk_stereo_pred_joint_iCDF, 8 );
+ ix[ 0 ][ 2 ] = silk_DIV32_16( n, 5 );
+ ix[ 1 ][ 2 ] = n - 5 * ix[ 0 ][ 2 ];
+ for( n = 0; n < 2; n++ ) {
+ ix[ n ][ 0 ] = ec_dec_icdf( psRangeDec, silk_uniform3_iCDF, 8 );
+ ix[ n ][ 1 ] = ec_dec_icdf( psRangeDec, silk_uniform5_iCDF, 8 );
+ }
+
+ /* Dequantize */
+ for( n = 0; n < 2; n++ ) {
+ ix[ n ][ 0 ] += 3 * ix[ n ][ 2 ];
+ low_Q13 = silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] ];
+ step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] + 1 ] - low_Q13,
+ SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) );
+ pred_Q13[ n ] = silk_SMLABB( low_Q13, step_Q13, 2 * ix[ n ][ 1 ] + 1 );
+ }
+
+ /* Subtract second from first predictor (helps when actually applying these) */
+ pred_Q13[ 0 ] -= pred_Q13[ 1 ];
+}
+
+/* Decode mid-only flag */
+void silk_stereo_decode_mid_only(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int *decode_only_mid /* O Flag that only mid channel has been coded */
+)
+{
+ /* Decode flag that only mid channel is coded */
+ *decode_only_mid = ec_dec_icdf( psRangeDec, silk_stereo_only_code_mid_iCDF, 8 );
+}
diff --git a/external/opus-1.1.4/silk/stereo_encode_pred.c b/external/opus-1.1.4/silk/stereo_encode_pred.c
new file mode 100644
index 0000000..e6dd195
--- /dev/null
+++ b/external/opus-1.1.4/silk/stereo_encode_pred.c
@@ -0,0 +1,62 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Entropy code the mid/side quantization indices */
+void silk_stereo_encode_pred(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */
+)
+{
+ opus_int n;
+
+ /* Entropy coding */
+ n = 5 * ix[ 0 ][ 2 ] + ix[ 1 ][ 2 ];
+ silk_assert( n < 25 );
+ ec_enc_icdf( psRangeEnc, n, silk_stereo_pred_joint_iCDF, 8 );
+ for( n = 0; n < 2; n++ ) {
+ silk_assert( ix[ n ][ 0 ] < 3 );
+ silk_assert( ix[ n ][ 1 ] < STEREO_QUANT_SUB_STEPS );
+ ec_enc_icdf( psRangeEnc, ix[ n ][ 0 ], silk_uniform3_iCDF, 8 );
+ ec_enc_icdf( psRangeEnc, ix[ n ][ 1 ], silk_uniform5_iCDF, 8 );
+ }
+}
+
+/* Entropy code the mid-only flag */
+void silk_stereo_encode_mid_only(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int8 mid_only_flag
+)
+{
+ /* Encode flag that only mid channel is coded */
+ ec_enc_icdf( psRangeEnc, mid_only_flag, silk_stereo_only_code_mid_iCDF, 8 );
+}
diff --git a/external/opus-1.1.4/silk/stereo_find_predictor.c b/external/opus-1.1.4/silk/stereo_find_predictor.c
new file mode 100644
index 0000000..e30e90b
--- /dev/null
+++ b/external/opus-1.1.4/silk/stereo_find_predictor.c
@@ -0,0 +1,79 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Find least-squares prediction gain for one signal based on another and quantize it */
+opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */
+ opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */
+ const opus_int16 x[], /* I Basis signal */
+ const opus_int16 y[], /* I Target signal */
+ opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */
+ opus_int length, /* I Number of samples */
+ opus_int smooth_coef_Q16 /* I Smoothing coefficient */
+)
+{
+ opus_int scale, scale1, scale2;
+ opus_int32 nrgx, nrgy, corr, pred_Q13, pred2_Q10;
+
+ /* Find predictor */
+ silk_sum_sqr_shift( &nrgx, &scale1, x, length );
+ silk_sum_sqr_shift( &nrgy, &scale2, y, length );
+ scale = silk_max_int( scale1, scale2 );
+ scale = scale + ( scale & 1 ); /* make even */
+ nrgy = silk_RSHIFT32( nrgy, scale - scale2 );
+ nrgx = silk_RSHIFT32( nrgx, scale - scale1 );
+ nrgx = silk_max_int( nrgx, 1 );
+ corr = silk_inner_prod_aligned_scale( x, y, scale, length );
+ pred_Q13 = silk_DIV32_varQ( corr, nrgx, 13 );
+ pred_Q13 = silk_LIMIT( pred_Q13, -(1 << 14), 1 << 14 );
+ pred2_Q10 = silk_SMULWB( pred_Q13, pred_Q13 );
+
+ /* Faster update for signals with large prediction parameters */
+ smooth_coef_Q16 = (opus_int)silk_max_int( smooth_coef_Q16, silk_abs( pred2_Q10 ) );
+
+ /* Smoothed mid and residual norms */
+ silk_assert( smooth_coef_Q16 < 32768 );
+ scale = silk_RSHIFT( scale, 1 );
+ mid_res_amp_Q0[ 0 ] = silk_SMLAWB( mid_res_amp_Q0[ 0 ], silk_LSHIFT( silk_SQRT_APPROX( nrgx ), scale ) - mid_res_amp_Q0[ 0 ],
+ smooth_coef_Q16 );
+ /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */
+ nrgy = silk_SUB_LSHIFT32( nrgy, silk_SMULWB( corr, pred_Q13 ), 3 + 1 );
+ nrgy = silk_ADD_LSHIFT32( nrgy, silk_SMULWB( nrgx, pred2_Q10 ), 6 );
+ mid_res_amp_Q0[ 1 ] = silk_SMLAWB( mid_res_amp_Q0[ 1 ], silk_LSHIFT( silk_SQRT_APPROX( nrgy ), scale ) - mid_res_amp_Q0[ 1 ],
+ smooth_coef_Q16 );
+
+ /* Ratio of smoothed residual and mid norms */
+ *ratio_Q14 = silk_DIV32_varQ( mid_res_amp_Q0[ 1 ], silk_max( mid_res_amp_Q0[ 0 ], 1 ), 14 );
+ *ratio_Q14 = silk_LIMIT( *ratio_Q14, 0, 32767 );
+
+ return pred_Q13;
+}
diff --git a/external/opus-1.1.4/silk/stereo_quant_pred.c b/external/opus-1.1.4/silk/stereo_quant_pred.c
new file mode 100644
index 0000000..d4ced6c
--- /dev/null
+++ b/external/opus-1.1.4/silk/stereo_quant_pred.c
@@ -0,0 +1,73 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Quantize mid/side predictors */
+void silk_stereo_quant_pred(
+ opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */
+ opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */
+)
+{
+ opus_int i, j, n;
+ opus_int32 low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0;
+
+ /* Quantize */
+ for( n = 0; n < 2; n++ ) {
+ /* Brute-force search over quantization levels */
+ err_min_Q13 = silk_int32_MAX;
+ for( i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++ ) {
+ low_Q13 = silk_stereo_pred_quant_Q13[ i ];
+ step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ i + 1 ] - low_Q13,
+ SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) );
+ for( j = 0; j < STEREO_QUANT_SUB_STEPS; j++ ) {
+ lvl_Q13 = silk_SMLABB( low_Q13, step_Q13, 2 * j + 1 );
+ err_Q13 = silk_abs( pred_Q13[ n ] - lvl_Q13 );
+ if( err_Q13 < err_min_Q13 ) {
+ err_min_Q13 = err_Q13;
+ quant_pred_Q13 = lvl_Q13;
+ ix[ n ][ 0 ] = i;
+ ix[ n ][ 1 ] = j;
+ } else {
+ /* Error increasing, so we're past the optimum */
+ goto done;
+ }
+ }
+ }
+ done:
+ ix[ n ][ 2 ] = silk_DIV32_16( ix[ n ][ 0 ], 3 );
+ ix[ n ][ 0 ] -= ix[ n ][ 2 ] * 3;
+ pred_Q13[ n ] = quant_pred_Q13;
+ }
+
+ /* Subtract second from first predictor (helps when actually applying these) */
+ pred_Q13[ 0 ] -= pred_Q13[ 1 ];
+}
diff --git a/external/opus-1.1.4/silk/structs.h b/external/opus-1.1.4/silk/structs.h
new file mode 100644
index 0000000..827829d
--- /dev/null
+++ b/external/opus-1.1.4/silk/structs.h
@@ -0,0 +1,327 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_STRUCTS_H
+#define SILK_STRUCTS_H
+
+#include "typedef.h"
+#include "SigProc_FIX.h"
+#include "define.h"
+#include "entenc.h"
+#include "entdec.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/************************************/
+/* Noise shaping quantization state */
+/************************************/
+typedef struct {
+ opus_int16 xq[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal */
+ opus_int32 sLTP_shp_Q14[ 2 * MAX_FRAME_LENGTH ];
+ opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ];
+ opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ];
+ opus_int32 sLF_AR_shp_Q14;
+ opus_int lagPrev;
+ opus_int sLTP_buf_idx;
+ opus_int sLTP_shp_buf_idx;
+ opus_int32 rand_seed;
+ opus_int32 prev_gain_Q16;
+ opus_int rewhite_flag;
+} silk_nsq_state;
+
+/********************************/
+/* VAD state */
+/********************************/
+typedef struct {
+ opus_int32 AnaState[ 2 ]; /* Analysis filterbank state: 0-8 kHz */
+ opus_int32 AnaState1[ 2 ]; /* Analysis filterbank state: 0-4 kHz */
+ opus_int32 AnaState2[ 2 ]; /* Analysis filterbank state: 0-2 kHz */
+ opus_int32 XnrgSubfr[ VAD_N_BANDS ]; /* Subframe energies */
+ opus_int32 NrgRatioSmth_Q8[ VAD_N_BANDS ]; /* Smoothed energy level in each band */
+ opus_int16 HPstate; /* State of differentiator in the lowest band */
+ opus_int32 NL[ VAD_N_BANDS ]; /* Noise energy level in each band */
+ opus_int32 inv_NL[ VAD_N_BANDS ]; /* Inverse noise energy level in each band */
+ opus_int32 NoiseLevelBias[ VAD_N_BANDS ]; /* Noise level estimator bias/offset */
+ opus_int32 counter; /* Frame counter used in the initial phase */
+} silk_VAD_state;
+
+/* Variable cut-off low-pass filter state */
+typedef struct {
+ opus_int32 In_LP_State[ 2 ]; /* Low pass filter state */
+ opus_int32 transition_frame_no; /* Counter which is mapped to a cut-off frequency */
+ opus_int mode; /* Operating mode, <0: switch down, >0: switch up; 0: do nothing */
+} silk_LP_state;
+
+/* Structure containing NLSF codebook */
+typedef struct {
+ const opus_int16 nVectors;
+ const opus_int16 order;
+ const opus_int16 quantStepSize_Q16;
+ const opus_int16 invQuantStepSize_Q6;
+ const opus_uint8 *CB1_NLSF_Q8;
+ const opus_uint8 *CB1_iCDF;
+ const opus_uint8 *pred_Q8;
+ const opus_uint8 *ec_sel;
+ const opus_uint8 *ec_iCDF;
+ const opus_uint8 *ec_Rates_Q5;
+ const opus_int16 *deltaMin_Q15;
+} silk_NLSF_CB_struct;
+
+typedef struct {
+ opus_int16 pred_prev_Q13[ 2 ];
+ opus_int16 sMid[ 2 ];
+ opus_int16 sSide[ 2 ];
+ opus_int32 mid_side_amp_Q0[ 4 ];
+ opus_int16 smth_width_Q14;
+ opus_int16 width_prev_Q14;
+ opus_int16 silent_side_len;
+ opus_int8 predIx[ MAX_FRAMES_PER_PACKET ][ 2 ][ 3 ];
+ opus_int8 mid_only_flags[ MAX_FRAMES_PER_PACKET ];
+} stereo_enc_state;
+
+typedef struct {
+ opus_int16 pred_prev_Q13[ 2 ];
+ opus_int16 sMid[ 2 ];
+ opus_int16 sSide[ 2 ];
+} stereo_dec_state;
+
+typedef struct {
+ opus_int8 GainsIndices[ MAX_NB_SUBFR ];
+ opus_int8 LTPIndex[ MAX_NB_SUBFR ];
+ opus_int8 NLSFIndices[ MAX_LPC_ORDER + 1 ];
+ opus_int16 lagIndex;
+ opus_int8 contourIndex;
+ opus_int8 signalType;
+ opus_int8 quantOffsetType;
+ opus_int8 NLSFInterpCoef_Q2;
+ opus_int8 PERIndex;
+ opus_int8 LTP_scaleIndex;
+ opus_int8 Seed;
+} SideInfoIndices;
+
+/********************************/
+/* Encoder state */
+/********************************/
+typedef struct {
+ opus_int32 In_HP_State[ 2 ]; /* High pass filter state */
+ opus_int32 variable_HP_smth1_Q15; /* State of first smoother */
+ opus_int32 variable_HP_smth2_Q15; /* State of second smoother */
+ silk_LP_state sLP; /* Low pass filter state */
+ silk_VAD_state sVAD; /* Voice activity detector state */
+ silk_nsq_state sNSQ; /* Noise Shape Quantizer State */
+ opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ]; /* Previously quantized NLSF vector */
+ opus_int speech_activity_Q8; /* Speech activity */
+ opus_int allow_bandwidth_switch; /* Flag indicating that switching of internal bandwidth is allowed */
+ opus_int8 LBRRprevLastGainIndex;
+ opus_int8 prevSignalType;
+ opus_int prevLag;
+ opus_int pitch_LPC_win_length;
+ opus_int max_pitch_lag; /* Highest possible pitch lag (samples) */
+ opus_int32 API_fs_Hz; /* API sampling frequency (Hz) */
+ opus_int32 prev_API_fs_Hz; /* Previous API sampling frequency (Hz) */
+ opus_int maxInternal_fs_Hz; /* Maximum internal sampling frequency (Hz) */
+ opus_int minInternal_fs_Hz; /* Minimum internal sampling frequency (Hz) */
+ opus_int desiredInternal_fs_Hz; /* Soft request for internal sampling frequency (Hz) */
+ opus_int fs_kHz; /* Internal sampling frequency (kHz) */
+ opus_int nb_subfr; /* Number of 5 ms subframes in a frame */
+ opus_int frame_length; /* Frame length (samples) */
+ opus_int subfr_length; /* Subframe length (samples) */
+ opus_int ltp_mem_length; /* Length of LTP memory */
+ opus_int la_pitch; /* Look-ahead for pitch analysis (samples) */
+ opus_int la_shape; /* Look-ahead for noise shape analysis (samples) */
+ opus_int shapeWinLength; /* Window length for noise shape analysis (samples) */
+ opus_int32 TargetRate_bps; /* Target bitrate (bps) */
+ opus_int PacketSize_ms; /* Number of milliseconds to put in each packet */
+ opus_int PacketLoss_perc; /* Packet loss rate measured by farend */
+ opus_int32 frameCounter;
+ opus_int Complexity; /* Complexity setting */
+ opus_int nStatesDelayedDecision; /* Number of states in delayed decision quantization */
+ opus_int useInterpolatedNLSFs; /* Flag for using NLSF interpolation */
+ opus_int shapingLPCOrder; /* Filter order for noise shaping filters */
+ opus_int predictLPCOrder; /* Filter order for prediction filters */
+ opus_int pitchEstimationComplexity; /* Complexity level for pitch estimator */
+ opus_int pitchEstimationLPCOrder; /* Whitening filter order for pitch estimator */
+ opus_int32 pitchEstimationThreshold_Q16; /* Threshold for pitch estimator */
+ opus_int LTPQuantLowComplexity; /* Flag for low complexity LTP quantization */
+ opus_int mu_LTP_Q9; /* Rate-distortion tradeoff in LTP quantization */
+ opus_int32 sum_log_gain_Q7; /* Cumulative max prediction gain */
+ opus_int NLSF_MSVQ_Survivors; /* Number of survivors in NLSF MSVQ */
+ opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation, pitch prediction */
+ opus_int controlled_since_last_payload; /* Flag for ensuring codec_control only runs once per packet */
+ opus_int warping_Q16; /* Warping parameter for warped noise shaping */
+ opus_int useCBR; /* Flag to enable constant bitrate */
+ opus_int prefillFlag; /* Flag to indicate that only buffers are prefilled, no coding */
+ const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */
+ const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */
+ const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */
+ opus_int input_quality_bands_Q15[ VAD_N_BANDS ];
+ opus_int input_tilt_Q15;
+ opus_int SNR_dB_Q7; /* Quality setting */
+
+ opus_int8 VAD_flags[ MAX_FRAMES_PER_PACKET ];
+ opus_int8 LBRR_flag;
+ opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ];
+
+ SideInfoIndices indices;
+ opus_int8 pulses[ MAX_FRAME_LENGTH ];
+
+ int arch;
+
+ /* Input/output buffering */
+ opus_int16 inputBuf[ MAX_FRAME_LENGTH + 2 ]; /* Buffer containing input signal */
+ opus_int inputBufIx;
+ opus_int nFramesPerPacket;
+ opus_int nFramesEncoded; /* Number of frames analyzed in current packet */
+
+ opus_int nChannelsAPI;
+ opus_int nChannelsInternal;
+ opus_int channelNb;
+
+ /* Parameters For LTP scaling Control */
+ opus_int frames_since_onset;
+
+ /* Specifically for entropy coding */
+ opus_int ec_prevSignalType;
+ opus_int16 ec_prevLagIndex;
+
+ silk_resampler_state_struct resampler_state;
+
+ /* DTX */
+ opus_int useDTX; /* Flag to enable DTX */
+ opus_int inDTX; /* Flag to signal DTX period */
+ opus_int noSpeechCounter; /* Counts concecutive nonactive frames, used by DTX */
+
+ /* Inband Low Bitrate Redundancy (LBRR) data */
+ opus_int useInBandFEC; /* Saves the API setting for query */
+ opus_int LBRR_enabled; /* Depends on useInBandFRC, bitrate and packet loss rate */
+ opus_int LBRR_GainIncreases; /* Gains increment for coding LBRR frames */
+ SideInfoIndices indices_LBRR[ MAX_FRAMES_PER_PACKET ];
+ opus_int8 pulses_LBRR[ MAX_FRAMES_PER_PACKET ][ MAX_FRAME_LENGTH ];
+} silk_encoder_state;
+
+
+/* Struct for Packet Loss Concealment */
+typedef struct {
+ opus_int32 pitchL_Q8; /* Pitch lag to use for voiced concealment */
+ opus_int16 LTPCoef_Q14[ LTP_ORDER ]; /* LTP coeficients to use for voiced concealment */
+ opus_int16 prevLPC_Q12[ MAX_LPC_ORDER ];
+ opus_int last_frame_lost; /* Was previous frame lost */
+ opus_int32 rand_seed; /* Seed for unvoiced signal generation */
+ opus_int16 randScale_Q14; /* Scaling of unvoiced random signal */
+ opus_int32 conc_energy;
+ opus_int conc_energy_shift;
+ opus_int16 prevLTP_scale_Q14;
+ opus_int32 prevGain_Q16[ 2 ];
+ opus_int fs_kHz;
+ opus_int nb_subfr;
+ opus_int subfr_length;
+} silk_PLC_struct;
+
+/* Struct for CNG */
+typedef struct {
+ opus_int32 CNG_exc_buf_Q14[ MAX_FRAME_LENGTH ];
+ opus_int16 CNG_smth_NLSF_Q15[ MAX_LPC_ORDER ];
+ opus_int32 CNG_synth_state[ MAX_LPC_ORDER ];
+ opus_int32 CNG_smth_Gain_Q16;
+ opus_int32 rand_seed;
+ opus_int fs_kHz;
+} silk_CNG_struct;
+
+/********************************/
+/* Decoder state */
+/********************************/
+typedef struct {
+ opus_int32 prev_gain_Q16;
+ opus_int32 exc_Q14[ MAX_FRAME_LENGTH ];
+ opus_int32 sLPC_Q14_buf[ MAX_LPC_ORDER ];
+ opus_int16 outBuf[ MAX_FRAME_LENGTH + 2 * MAX_SUB_FRAME_LENGTH ]; /* Buffer for output signal */
+ opus_int lagPrev; /* Previous Lag */
+ opus_int8 LastGainIndex; /* Previous gain index */
+ opus_int fs_kHz; /* Sampling frequency in kHz */
+ opus_int32 fs_API_hz; /* API sample frequency (Hz) */
+ opus_int nb_subfr; /* Number of 5 ms subframes in a frame */
+ opus_int frame_length; /* Frame length (samples) */
+ opus_int subfr_length; /* Subframe length (samples) */
+ opus_int ltp_mem_length; /* Length of LTP memory */
+ opus_int LPC_order; /* LPC order */
+ opus_int16 prevNLSF_Q15[ MAX_LPC_ORDER ]; /* Used to interpolate LSFs */
+ opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation */
+ const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */
+ const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */
+
+ /* For buffering payload in case of more frames per packet */
+ opus_int nFramesDecoded;
+ opus_int nFramesPerPacket;
+
+ /* Specifically for entropy coding */
+ opus_int ec_prevSignalType;
+ opus_int16 ec_prevLagIndex;
+
+ opus_int VAD_flags[ MAX_FRAMES_PER_PACKET ];
+ opus_int LBRR_flag;
+ opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ];
+
+ silk_resampler_state_struct resampler_state;
+
+ const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */
+
+ /* Quantization indices */
+ SideInfoIndices indices;
+
+ /* CNG state */
+ silk_CNG_struct sCNG;
+
+ /* Stuff used for PLC */
+ opus_int lossCnt;
+ opus_int prevSignalType;
+
+ silk_PLC_struct sPLC;
+
+} silk_decoder_state;
+
+/************************/
+/* Decoder control */
+/************************/
+typedef struct {
+ /* Prediction and coding parameters */
+ opus_int pitchL[ MAX_NB_SUBFR ];
+ opus_int32 Gains_Q16[ MAX_NB_SUBFR ];
+ /* Holds interpolated and final coefficients, 4-byte aligned */
+ silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+ opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ];
+ opus_int LTP_scale_Q14;
+} silk_decoder_control;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/silk/sum_sqr_shift.c b/external/opus-1.1.4/silk/sum_sqr_shift.c
new file mode 100644
index 0000000..129df19
--- /dev/null
+++ b/external/opus-1.1.4/silk/sum_sqr_shift.c
@@ -0,0 +1,86 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Compute number of bits to right shift the sum of squares of a vector */
+/* of int16s to make it fit in an int32 */
+void silk_sum_sqr_shift(
+ opus_int32 *energy, /* O Energy of x, after shifting to the right */
+ opus_int *shift, /* O Number of bits right shift applied to energy */
+ const opus_int16 *x, /* I Input vector */
+ opus_int len /* I Length of input vector */
+)
+{
+ opus_int i, shft;
+ opus_int32 nrg_tmp, nrg;
+
+ nrg = 0;
+ shft = 0;
+ len--;
+ for( i = 0; i < len; i += 2 ) {
+ nrg = silk_SMLABB_ovflw( nrg, x[ i ], x[ i ] );
+ nrg = silk_SMLABB_ovflw( nrg, x[ i + 1 ], x[ i + 1 ] );
+ if( nrg < 0 ) {
+ /* Scale down */
+ nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 );
+ shft = 2;
+ i+=2;
+ break;
+ }
+ }
+ for( ; i < len; i += 2 ) {
+ nrg_tmp = silk_SMULBB( x[ i ], x[ i ] );
+ nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] );
+ nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, (opus_uint32)nrg_tmp, shft );
+ if( nrg < 0 ) {
+ /* Scale down */
+ nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 );
+ shft += 2;
+ }
+ }
+ if( i == len ) {
+ /* One sample left to process */
+ nrg_tmp = silk_SMULBB( x[ i ], x[ i ] );
+ nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft );
+ }
+
+ /* Make sure to have at least one extra leading zero (two leading zeros in total) */
+ if( nrg & 0xC0000000 ) {
+ nrg = silk_RSHIFT_uint( (opus_uint32)nrg, 2 );
+ shft += 2;
+ }
+
+ /* Output arguments */
+ *shift = shft;
+ *energy = nrg;
+}
+
diff --git a/external/opus-1.1.4/silk/table_LSF_cos.c b/external/opus-1.1.4/silk/table_LSF_cos.c
new file mode 100644
index 0000000..ec9dc63
--- /dev/null
+++ b/external/opus-1.1.4/silk/table_LSF_cos.c
@@ -0,0 +1,70 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+/* Cosine approximation table for LSF conversion */
+/* Q12 values (even) */
+const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ] = {
+ 8192, 8190, 8182, 8170,
+ 8152, 8130, 8104, 8072,
+ 8034, 7994, 7946, 7896,
+ 7840, 7778, 7714, 7644,
+ 7568, 7490, 7406, 7318,
+ 7226, 7128, 7026, 6922,
+ 6812, 6698, 6580, 6458,
+ 6332, 6204, 6070, 5934,
+ 5792, 5648, 5502, 5352,
+ 5198, 5040, 4880, 4718,
+ 4552, 4382, 4212, 4038,
+ 3862, 3684, 3502, 3320,
+ 3136, 2948, 2760, 2570,
+ 2378, 2186, 1990, 1794,
+ 1598, 1400, 1202, 1002,
+ 802, 602, 402, 202,
+ 0, -202, -402, -602,
+ -802, -1002, -1202, -1400,
+ -1598, -1794, -1990, -2186,
+ -2378, -2570, -2760, -2948,
+ -3136, -3320, -3502, -3684,
+ -3862, -4038, -4212, -4382,
+ -4552, -4718, -4880, -5040,
+ -5198, -5352, -5502, -5648,
+ -5792, -5934, -6070, -6204,
+ -6332, -6458, -6580, -6698,
+ -6812, -6922, -7026, -7128,
+ -7226, -7318, -7406, -7490,
+ -7568, -7644, -7714, -7778,
+ -7840, -7896, -7946, -7994,
+ -8034, -8072, -8104, -8130,
+ -8152, -8170, -8182, -8190,
+ -8192
+};
diff --git a/external/opus-1.1.4/silk/tables.h b/external/opus-1.1.4/silk/tables.h
new file mode 100644
index 0000000..7fea6fd
--- /dev/null
+++ b/external/opus-1.1.4/silk/tables.h
@@ -0,0 +1,122 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_TABLES_H
+#define SILK_TABLES_H
+
+#include "define.h"
+#include "structs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Entropy coding tables (with size in bytes indicated) */
+extern const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ]; /* 24 */
+extern const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ]; /* 41 */
+
+extern const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ];/* 32 */
+extern const opus_uint8 silk_pitch_delta_iCDF[ 21 ]; /* 21 */
+extern const opus_uint8 silk_pitch_contour_iCDF[ 34 ]; /* 34 */
+extern const opus_uint8 silk_pitch_contour_NB_iCDF[ 11 ]; /* 11 */
+extern const opus_uint8 silk_pitch_contour_10_ms_iCDF[ 12 ]; /* 12 */
+extern const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[ 3 ]; /* 3 */
+
+extern const opus_uint8 silk_pulses_per_block_iCDF[ N_RATE_LEVELS ][ SILK_MAX_PULSES + 2 ]; /* 180 */
+extern const opus_uint8 silk_pulses_per_block_BITS_Q5[ N_RATE_LEVELS - 1 ][ SILK_MAX_PULSES + 2 ]; /* 162 */
+
+extern const opus_uint8 silk_rate_levels_iCDF[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */
+extern const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */
+
+extern const opus_uint8 silk_max_pulses_table[ 4 ]; /* 4 */
+
+extern const opus_uint8 silk_shell_code_table0[ 152 ]; /* 152 */
+extern const opus_uint8 silk_shell_code_table1[ 152 ]; /* 152 */
+extern const opus_uint8 silk_shell_code_table2[ 152 ]; /* 152 */
+extern const opus_uint8 silk_shell_code_table3[ 152 ]; /* 152 */
+extern const opus_uint8 silk_shell_code_table_offsets[ SILK_MAX_PULSES + 1 ]; /* 17 */
+
+extern const opus_uint8 silk_lsb_iCDF[ 2 ]; /* 2 */
+
+extern const opus_uint8 silk_sign_iCDF[ 42 ]; /* 42 */
+
+extern const opus_uint8 silk_uniform3_iCDF[ 3 ]; /* 3 */
+extern const opus_uint8 silk_uniform4_iCDF[ 4 ]; /* 4 */
+extern const opus_uint8 silk_uniform5_iCDF[ 5 ]; /* 5 */
+extern const opus_uint8 silk_uniform6_iCDF[ 6 ]; /* 6 */
+extern const opus_uint8 silk_uniform8_iCDF[ 8 ]; /* 8 */
+
+extern const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ]; /* 7 */
+
+extern const opus_uint8 silk_LTP_per_index_iCDF[ 3 ]; /* 3 */
+extern const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[ NB_LTP_CBKS ]; /* 3 */
+extern const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[ NB_LTP_CBKS ]; /* 3 */
+extern const opus_int16 silk_LTP_gain_middle_avg_RD_Q14;
+extern const opus_int8 * const silk_LTP_vq_ptrs_Q7[ NB_LTP_CBKS ]; /* 168 */
+extern const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS];
+
+extern const opus_int8 silk_LTP_vq_sizes[ NB_LTP_CBKS ]; /* 3 */
+
+extern const opus_uint8 silk_LTPscale_iCDF[ 3 ]; /* 4 */
+extern const opus_int16 silk_LTPScales_table_Q14[ 3 ]; /* 6 */
+
+extern const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ]; /* 4 */
+extern const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ]; /* 2 */
+
+extern const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ]; /* 32 */
+extern const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ]; /* 25 */
+extern const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ]; /* 2 */
+
+extern const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ]; /* 10 */
+
+extern const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ]; /* 5 */
+
+extern const silk_NLSF_CB_struct silk_NLSF_CB_WB; /* 1040 */
+extern const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB; /* 728 */
+
+/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */
+extern const opus_int32 silk_TargetRate_table_NB[ TARGET_RATE_TAB_SZ ]; /* 32 */
+extern const opus_int32 silk_TargetRate_table_MB[ TARGET_RATE_TAB_SZ ]; /* 32 */
+extern const opus_int32 silk_TargetRate_table_WB[ TARGET_RATE_TAB_SZ ]; /* 32 */
+extern const opus_int16 silk_SNR_table_Q1[ TARGET_RATE_TAB_SZ ]; /* 32 */
+
+/* Quantization offsets */
+extern const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ]; /* 8 */
+
+/* Interpolation points for filter coefficients used in the bandwidth transition smoother */
+extern const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ]; /* 60 */
+extern const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ]; /* 60 */
+
+/* Rom table with cosine values */
+extern const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ]; /* 258 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/external/opus-1.1.4/silk/tables_LTP.c b/external/opus-1.1.4/silk/tables_LTP.c
new file mode 100644
index 0000000..0e6a025
--- /dev/null
+++ b/external/opus-1.1.4/silk/tables_LTP.c
@@ -0,0 +1,296 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+const opus_uint8 silk_LTP_per_index_iCDF[3] = {
+ 179, 99, 0
+};
+
+static const opus_uint8 silk_LTP_gain_iCDF_0[8] = {
+ 71, 56, 43, 30, 21, 12, 6, 0
+};
+
+static const opus_uint8 silk_LTP_gain_iCDF_1[16] = {
+ 199, 165, 144, 124, 109, 96, 84, 71,
+ 61, 51, 42, 32, 23, 15, 8, 0
+};
+
+static const opus_uint8 silk_LTP_gain_iCDF_2[32] = {
+ 241, 225, 211, 199, 187, 175, 164, 153,
+ 142, 132, 123, 114, 105, 96, 88, 80,
+ 72, 64, 57, 50, 44, 38, 33, 29,
+ 24, 20, 16, 12, 9, 5, 2, 0
+};
+
+const opus_int16 silk_LTP_gain_middle_avg_RD_Q14 = 12304;
+
+static const opus_uint8 silk_LTP_gain_BITS_Q5_0[8] = {
+ 15, 131, 138, 138, 155, 155, 173, 173
+};
+
+static const opus_uint8 silk_LTP_gain_BITS_Q5_1[16] = {
+ 69, 93, 115, 118, 131, 138, 141, 138,
+ 150, 150, 155, 150, 155, 160, 166, 160
+};
+
+static const opus_uint8 silk_LTP_gain_BITS_Q5_2[32] = {
+ 131, 128, 134, 141, 141, 141, 145, 145,
+ 145, 150, 155, 155, 155, 155, 160, 160,
+ 160, 160, 166, 166, 173, 173, 182, 192,
+ 182, 192, 192, 192, 205, 192, 205, 224
+};
+
+const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[NB_LTP_CBKS] = {
+ silk_LTP_gain_iCDF_0,
+ silk_LTP_gain_iCDF_1,
+ silk_LTP_gain_iCDF_2
+};
+
+const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[NB_LTP_CBKS] = {
+ silk_LTP_gain_BITS_Q5_0,
+ silk_LTP_gain_BITS_Q5_1,
+ silk_LTP_gain_BITS_Q5_2
+};
+
+static const opus_int8 silk_LTP_gain_vq_0[8][5] =
+{
+{
+ 4, 6, 24, 7, 5
+},
+{
+ 0, 0, 2, 0, 0
+},
+{
+ 12, 28, 41, 13, -4
+},
+{
+ -9, 15, 42, 25, 14
+},
+{
+ 1, -2, 62, 41, -9
+},
+{
+ -10, 37, 65, -4, 3
+},
+{
+ -6, 4, 66, 7, -8
+},
+{
+ 16, 14, 38, -3, 33
+}
+};
+
+static const opus_int8 silk_LTP_gain_vq_1[16][5] =
+{
+{
+ 13, 22, 39, 23, 12
+},
+{
+ -1, 36, 64, 27, -6
+},
+{
+ -7, 10, 55, 43, 17
+},
+{
+ 1, 1, 8, 1, 1
+},
+{
+ 6, -11, 74, 53, -9
+},
+{
+ -12, 55, 76, -12, 8
+},
+{
+ -3, 3, 93, 27, -4
+},
+{
+ 26, 39, 59, 3, -8
+},
+{
+ 2, 0, 77, 11, 9
+},
+{
+ -8, 22, 44, -6, 7
+},
+{
+ 40, 9, 26, 3, 9
+},
+{
+ -7, 20, 101, -7, 4
+},
+{
+ 3, -8, 42, 26, 0
+},
+{
+ -15, 33, 68, 2, 23
+},
+{
+ -2, 55, 46, -2, 15
+},
+{
+ 3, -1, 21, 16, 41
+}
+};
+
+static const opus_int8 silk_LTP_gain_vq_2[32][5] =
+{
+{
+ -6, 27, 61, 39, 5
+},
+{
+ -11, 42, 88, 4, 1
+},
+{
+ -2, 60, 65, 6, -4
+},
+{
+ -1, -5, 73, 56, 1
+},
+{
+ -9, 19, 94, 29, -9
+},
+{
+ 0, 12, 99, 6, 4
+},
+{
+ 8, -19, 102, 46, -13
+},
+{
+ 3, 2, 13, 3, 2
+},
+{
+ 9, -21, 84, 72, -18
+},
+{
+ -11, 46, 104, -22, 8
+},
+{
+ 18, 38, 48, 23, 0
+},
+{
+ -16, 70, 83, -21, 11
+},
+{
+ 5, -11, 117, 22, -8
+},
+{
+ -6, 23, 117, -12, 3
+},
+{
+ 3, -8, 95, 28, 4
+},
+{
+ -10, 15, 77, 60, -15
+},
+{
+ -1, 4, 124, 2, -4
+},
+{
+ 3, 38, 84, 24, -25
+},
+{
+ 2, 13, 42, 13, 31
+},
+{
+ 21, -4, 56, 46, -1
+},
+{
+ -1, 35, 79, -13, 19
+},
+{
+ -7, 65, 88, -9, -14
+},
+{
+ 20, 4, 81, 49, -29
+},
+{
+ 20, 0, 75, 3, -17
+},
+{
+ 5, -9, 44, 92, -8
+},
+{
+ 1, -3, 22, 69, 31
+},
+{
+ -6, 95, 41, -12, 5
+},
+{
+ 39, 67, 16, -4, 1
+},
+{
+ 0, -6, 120, 55, -36
+},
+{
+ -13, 44, 122, 4, -24
+},
+{
+ 81, 5, 11, 3, 7
+},
+{
+ 2, 0, 9, 10, 88
+}
+};
+
+const opus_int8 * const silk_LTP_vq_ptrs_Q7[NB_LTP_CBKS] = {
+ (opus_int8 *)&silk_LTP_gain_vq_0[0][0],
+ (opus_int8 *)&silk_LTP_gain_vq_1[0][0],
+ (opus_int8 *)&silk_LTP_gain_vq_2[0][0]
+};
+
+/* Maximum frequency-dependent response of the pitch taps above,
+ computed as max(abs(freqz(taps))) */
+static const opus_uint8 silk_LTP_gain_vq_0_gain[8] = {
+ 46, 2, 90, 87, 93, 91, 82, 98
+};
+
+static const opus_uint8 silk_LTP_gain_vq_1_gain[16] = {
+ 109, 120, 118, 12, 113, 115, 117, 119,
+ 99, 59, 87, 111, 63, 111, 112, 80
+};
+
+static const opus_uint8 silk_LTP_gain_vq_2_gain[32] = {
+ 126, 124, 125, 124, 129, 121, 126, 23,
+ 132, 127, 127, 127, 126, 127, 122, 133,
+ 130, 134, 101, 118, 119, 145, 126, 86,
+ 124, 120, 123, 119, 170, 173, 107, 109
+};
+
+const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS] = {
+ &silk_LTP_gain_vq_0_gain[0],
+ &silk_LTP_gain_vq_1_gain[0],
+ &silk_LTP_gain_vq_2_gain[0]
+};
+
+const opus_int8 silk_LTP_vq_sizes[NB_LTP_CBKS] = {
+ 8, 16, 32
+};
diff --git a/external/opus-1.1.4/silk/tables_NLSF_CB_NB_MB.c b/external/opus-1.1.4/silk/tables_NLSF_CB_NB_MB.c
new file mode 100644
index 0000000..8c59d20
--- /dev/null
+++ b/external/opus-1.1.4/silk/tables_NLSF_CB_NB_MB.c
@@ -0,0 +1,159 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+static const opus_uint8 silk_NLSF_CB1_NB_MB_Q8[ 320 ] = {
+ 12, 35, 60, 83, 108, 132, 157, 180,
+ 206, 228, 15, 32, 55, 77, 101, 125,
+ 151, 175, 201, 225, 19, 42, 66, 89,
+ 114, 137, 162, 184, 209, 230, 12, 25,
+ 50, 72, 97, 120, 147, 172, 200, 223,
+ 26, 44, 69, 90, 114, 135, 159, 180,
+ 205, 225, 13, 22, 53, 80, 106, 130,
+ 156, 180, 205, 228, 15, 25, 44, 64,
+ 90, 115, 142, 168, 196, 222, 19, 24,
+ 62, 82, 100, 120, 145, 168, 190, 214,
+ 22, 31, 50, 79, 103, 120, 151, 170,
+ 203, 227, 21, 29, 45, 65, 106, 124,
+ 150, 171, 196, 224, 30, 49, 75, 97,
+ 121, 142, 165, 186, 209, 229, 19, 25,
+ 52, 70, 93, 116, 143, 166, 192, 219,
+ 26, 34, 62, 75, 97, 118, 145, 167,
+ 194, 217, 25, 33, 56, 70, 91, 113,
+ 143, 165, 196, 223, 21, 34, 51, 72,
+ 97, 117, 145, 171, 196, 222, 20, 29,
+ 50, 67, 90, 117, 144, 168, 197, 221,
+ 22, 31, 48, 66, 95, 117, 146, 168,
+ 196, 222, 24, 33, 51, 77, 116, 134,
+ 158, 180, 200, 224, 21, 28, 70, 87,
+ 106, 124, 149, 170, 194, 217, 26, 33,
+ 53, 64, 83, 117, 152, 173, 204, 225,
+ 27, 34, 65, 95, 108, 129, 155, 174,
+ 210, 225, 20, 26, 72, 99, 113, 131,
+ 154, 176, 200, 219, 34, 43, 61, 78,
+ 93, 114, 155, 177, 205, 229, 23, 29,
+ 54, 97, 124, 138, 163, 179, 209, 229,
+ 30, 38, 56, 89, 118, 129, 158, 178,
+ 200, 231, 21, 29, 49, 63, 85, 111,
+ 142, 163, 193, 222, 27, 48, 77, 103,
+ 133, 158, 179, 196, 215, 232, 29, 47,
+ 74, 99, 124, 151, 176, 198, 220, 237,
+ 33, 42, 61, 76, 93, 121, 155, 174,
+ 207, 225, 29, 53, 87, 112, 136, 154,
+ 170, 188, 208, 227, 24, 30, 52, 84,
+ 131, 150, 166, 186, 203, 229, 37, 48,
+ 64, 84, 104, 118, 156, 177, 201, 230
+};
+
+static const opus_uint8 silk_NLSF_CB1_iCDF_NB_MB[ 64 ] = {
+ 212, 178, 148, 129, 108, 96, 85, 82,
+ 79, 77, 61, 59, 57, 56, 51, 49,
+ 48, 45, 42, 41, 40, 38, 36, 34,
+ 31, 30, 21, 12, 10, 3, 1, 0,
+ 255, 245, 244, 236, 233, 225, 217, 203,
+ 190, 176, 175, 161, 149, 136, 125, 114,
+ 102, 91, 81, 71, 60, 52, 43, 35,
+ 28, 20, 19, 18, 12, 11, 5, 0
+};
+
+static const opus_uint8 silk_NLSF_CB2_SELECT_NB_MB[ 160 ] = {
+ 16, 0, 0, 0, 0, 99, 66, 36,
+ 36, 34, 36, 34, 34, 34, 34, 83,
+ 69, 36, 52, 34, 116, 102, 70, 68,
+ 68, 176, 102, 68, 68, 34, 65, 85,
+ 68, 84, 36, 116, 141, 152, 139, 170,
+ 132, 187, 184, 216, 137, 132, 249, 168,
+ 185, 139, 104, 102, 100, 68, 68, 178,
+ 218, 185, 185, 170, 244, 216, 187, 187,
+ 170, 244, 187, 187, 219, 138, 103, 155,
+ 184, 185, 137, 116, 183, 155, 152, 136,
+ 132, 217, 184, 184, 170, 164, 217, 171,
+ 155, 139, 244, 169, 184, 185, 170, 164,
+ 216, 223, 218, 138, 214, 143, 188, 218,
+ 168, 244, 141, 136, 155, 170, 168, 138,
+ 220, 219, 139, 164, 219, 202, 216, 137,
+ 168, 186, 246, 185, 139, 116, 185, 219,
+ 185, 138, 100, 100, 134, 100, 102, 34,
+ 68, 68, 100, 68, 168, 203, 221, 218,
+ 168, 167, 154, 136, 104, 70, 164, 246,
+ 171, 137, 139, 137, 155, 218, 219, 139
+};
+
+static const opus_uint8 silk_NLSF_CB2_iCDF_NB_MB[ 72 ] = {
+ 255, 254, 253, 238, 14, 3, 2, 1,
+ 0, 255, 254, 252, 218, 35, 3, 2,
+ 1, 0, 255, 254, 250, 208, 59, 4,
+ 2, 1, 0, 255, 254, 246, 194, 71,
+ 10, 2, 1, 0, 255, 252, 236, 183,
+ 82, 8, 2, 1, 0, 255, 252, 235,
+ 180, 90, 17, 2, 1, 0, 255, 248,
+ 224, 171, 97, 30, 4, 1, 0, 255,
+ 254, 236, 173, 95, 37, 7, 1, 0
+};
+
+static const opus_uint8 silk_NLSF_CB2_BITS_NB_MB_Q5[ 72 ] = {
+ 255, 255, 255, 131, 6, 145, 255, 255,
+ 255, 255, 255, 236, 93, 15, 96, 255,
+ 255, 255, 255, 255, 194, 83, 25, 71,
+ 221, 255, 255, 255, 255, 162, 73, 34,
+ 66, 162, 255, 255, 255, 210, 126, 73,
+ 43, 57, 173, 255, 255, 255, 201, 125,
+ 71, 48, 58, 130, 255, 255, 255, 166,
+ 110, 73, 57, 62, 104, 210, 255, 255,
+ 251, 123, 65, 55, 68, 100, 171, 255
+};
+
+static const opus_uint8 silk_NLSF_PRED_NB_MB_Q8[ 18 ] = {
+ 179, 138, 140, 148, 151, 149, 153, 151,
+ 163, 116, 67, 82, 59, 92, 72, 100,
+ 89, 92
+};
+
+static const opus_int16 silk_NLSF_DELTA_MIN_NB_MB_Q15[ 11 ] = {
+ 250, 3, 6, 3, 3, 3, 4, 3,
+ 3, 3, 461
+};
+
+const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB =
+{
+ 32,
+ 10,
+ SILK_FIX_CONST( 0.18, 16 ),
+ SILK_FIX_CONST( 1.0 / 0.18, 6 ),
+ silk_NLSF_CB1_NB_MB_Q8,
+ silk_NLSF_CB1_iCDF_NB_MB,
+ silk_NLSF_PRED_NB_MB_Q8,
+ silk_NLSF_CB2_SELECT_NB_MB,
+ silk_NLSF_CB2_iCDF_NB_MB,
+ silk_NLSF_CB2_BITS_NB_MB_Q5,
+ silk_NLSF_DELTA_MIN_NB_MB_Q15,
+};
diff --git a/external/opus-1.1.4/silk/tables_NLSF_CB_WB.c b/external/opus-1.1.4/silk/tables_NLSF_CB_WB.c
new file mode 100644
index 0000000..50af87e
--- /dev/null
+++ b/external/opus-1.1.4/silk/tables_NLSF_CB_WB.c
@@ -0,0 +1,198 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+static const opus_uint8 silk_NLSF_CB1_WB_Q8[ 512 ] = {
+ 7, 23, 38, 54, 69, 85, 100, 116,
+ 131, 147, 162, 178, 193, 208, 223, 239,
+ 13, 25, 41, 55, 69, 83, 98, 112,
+ 127, 142, 157, 171, 187, 203, 220, 236,
+ 15, 21, 34, 51, 61, 78, 92, 106,
+ 126, 136, 152, 167, 185, 205, 225, 240,
+ 10, 21, 36, 50, 63, 79, 95, 110,
+ 126, 141, 157, 173, 189, 205, 221, 237,
+ 17, 20, 37, 51, 59, 78, 89, 107,
+ 123, 134, 150, 164, 184, 205, 224, 240,
+ 10, 15, 32, 51, 67, 81, 96, 112,
+ 129, 142, 158, 173, 189, 204, 220, 236,
+ 8, 21, 37, 51, 65, 79, 98, 113,
+ 126, 138, 155, 168, 179, 192, 209, 218,
+ 12, 15, 34, 55, 63, 78, 87, 108,
+ 118, 131, 148, 167, 185, 203, 219, 236,
+ 16, 19, 32, 36, 56, 79, 91, 108,
+ 118, 136, 154, 171, 186, 204, 220, 237,
+ 11, 28, 43, 58, 74, 89, 105, 120,
+ 135, 150, 165, 180, 196, 211, 226, 241,
+ 6, 16, 33, 46, 60, 75, 92, 107,
+ 123, 137, 156, 169, 185, 199, 214, 225,
+ 11, 19, 30, 44, 57, 74, 89, 105,
+ 121, 135, 152, 169, 186, 202, 218, 234,
+ 12, 19, 29, 46, 57, 71, 88, 100,
+ 120, 132, 148, 165, 182, 199, 216, 233,
+ 17, 23, 35, 46, 56, 77, 92, 106,
+ 123, 134, 152, 167, 185, 204, 222, 237,
+ 14, 17, 45, 53, 63, 75, 89, 107,
+ 115, 132, 151, 171, 188, 206, 221, 240,
+ 9, 16, 29, 40, 56, 71, 88, 103,
+ 119, 137, 154, 171, 189, 205, 222, 237,
+ 16, 19, 36, 48, 57, 76, 87, 105,
+ 118, 132, 150, 167, 185, 202, 218, 236,
+ 12, 17, 29, 54, 71, 81, 94, 104,
+ 126, 136, 149, 164, 182, 201, 221, 237,
+ 15, 28, 47, 62, 79, 97, 115, 129,
+ 142, 155, 168, 180, 194, 208, 223, 238,
+ 8, 14, 30, 45, 62, 78, 94, 111,
+ 127, 143, 159, 175, 192, 207, 223, 239,
+ 17, 30, 49, 62, 79, 92, 107, 119,
+ 132, 145, 160, 174, 190, 204, 220, 235,
+ 14, 19, 36, 45, 61, 76, 91, 108,
+ 121, 138, 154, 172, 189, 205, 222, 238,
+ 12, 18, 31, 45, 60, 76, 91, 107,
+ 123, 138, 154, 171, 187, 204, 221, 236,
+ 13, 17, 31, 43, 53, 70, 83, 103,
+ 114, 131, 149, 167, 185, 203, 220, 237,
+ 17, 22, 35, 42, 58, 78, 93, 110,
+ 125, 139, 155, 170, 188, 206, 224, 240,
+ 8, 15, 34, 50, 67, 83, 99, 115,
+ 131, 146, 162, 178, 193, 209, 224, 239,
+ 13, 16, 41, 66, 73, 86, 95, 111,
+ 128, 137, 150, 163, 183, 206, 225, 241,
+ 17, 25, 37, 52, 63, 75, 92, 102,
+ 119, 132, 144, 160, 175, 191, 212, 231,
+ 19, 31, 49, 65, 83, 100, 117, 133,
+ 147, 161, 174, 187, 200, 213, 227, 242,
+ 18, 31, 52, 68, 88, 103, 117, 126,
+ 138, 149, 163, 177, 192, 207, 223, 239,
+ 16, 29, 47, 61, 76, 90, 106, 119,
+ 133, 147, 161, 176, 193, 209, 224, 240,
+ 15, 21, 35, 50, 61, 73, 86, 97,
+ 110, 119, 129, 141, 175, 198, 218, 237
+};
+
+static const opus_uint8 silk_NLSF_CB1_iCDF_WB[ 64 ] = {
+ 225, 204, 201, 184, 183, 175, 158, 154,
+ 153, 135, 119, 115, 113, 110, 109, 99,
+ 98, 95, 79, 68, 52, 50, 48, 45,
+ 43, 32, 31, 27, 18, 10, 3, 0,
+ 255, 251, 235, 230, 212, 201, 196, 182,
+ 167, 166, 163, 151, 138, 124, 110, 104,
+ 90, 78, 76, 70, 69, 57, 45, 34,
+ 24, 21, 11, 6, 5, 4, 3, 0
+};
+
+static const opus_uint8 silk_NLSF_CB2_SELECT_WB[ 256 ] = {
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ 100, 102, 102, 68, 68, 36, 34, 96,
+ 164, 107, 158, 185, 180, 185, 139, 102,
+ 64, 66, 36, 34, 34, 0, 1, 32,
+ 208, 139, 141, 191, 152, 185, 155, 104,
+ 96, 171, 104, 166, 102, 102, 102, 132,
+ 1, 0, 0, 0, 0, 16, 16, 0,
+ 80, 109, 78, 107, 185, 139, 103, 101,
+ 208, 212, 141, 139, 173, 153, 123, 103,
+ 36, 0, 0, 0, 0, 0, 0, 1,
+ 48, 0, 0, 0, 0, 0, 0, 32,
+ 68, 135, 123, 119, 119, 103, 69, 98,
+ 68, 103, 120, 118, 118, 102, 71, 98,
+ 134, 136, 157, 184, 182, 153, 139, 134,
+ 208, 168, 248, 75, 189, 143, 121, 107,
+ 32, 49, 34, 34, 34, 0, 17, 2,
+ 210, 235, 139, 123, 185, 137, 105, 134,
+ 98, 135, 104, 182, 100, 183, 171, 134,
+ 100, 70, 68, 70, 66, 66, 34, 131,
+ 64, 166, 102, 68, 36, 2, 1, 0,
+ 134, 166, 102, 68, 34, 34, 66, 132,
+ 212, 246, 158, 139, 107, 107, 87, 102,
+ 100, 219, 125, 122, 137, 118, 103, 132,
+ 114, 135, 137, 105, 171, 106, 50, 34,
+ 164, 214, 141, 143, 185, 151, 121, 103,
+ 192, 34, 0, 0, 0, 0, 0, 1,
+ 208, 109, 74, 187, 134, 249, 159, 137,
+ 102, 110, 154, 118, 87, 101, 119, 101,
+ 0, 2, 0, 36, 36, 66, 68, 35,
+ 96, 164, 102, 100, 36, 0, 2, 33,
+ 167, 138, 174, 102, 100, 84, 2, 2,
+ 100, 107, 120, 119, 36, 197, 24, 0
+};
+
+static const opus_uint8 silk_NLSF_CB2_iCDF_WB[ 72 ] = {
+ 255, 254, 253, 244, 12, 3, 2, 1,
+ 0, 255, 254, 252, 224, 38, 3, 2,
+ 1, 0, 255, 254, 251, 209, 57, 4,
+ 2, 1, 0, 255, 254, 244, 195, 69,
+ 4, 2, 1, 0, 255, 251, 232, 184,
+ 84, 7, 2, 1, 0, 255, 254, 240,
+ 186, 86, 14, 2, 1, 0, 255, 254,
+ 239, 178, 91, 30, 5, 1, 0, 255,
+ 248, 227, 177, 100, 19, 2, 1, 0
+};
+
+static const opus_uint8 silk_NLSF_CB2_BITS_WB_Q5[ 72 ] = {
+ 255, 255, 255, 156, 4, 154, 255, 255,
+ 255, 255, 255, 227, 102, 15, 92, 255,
+ 255, 255, 255, 255, 213, 83, 24, 72,
+ 236, 255, 255, 255, 255, 150, 76, 33,
+ 63, 214, 255, 255, 255, 190, 121, 77,
+ 43, 55, 185, 255, 255, 255, 245, 137,
+ 71, 43, 59, 139, 255, 255, 255, 255,
+ 131, 66, 50, 66, 107, 194, 255, 255,
+ 166, 116, 76, 55, 53, 125, 255, 255
+};
+
+static const opus_uint8 silk_NLSF_PRED_WB_Q8[ 30 ] = {
+ 175, 148, 160, 176, 178, 173, 174, 164,
+ 177, 174, 196, 182, 198, 192, 182, 68,
+ 62, 66, 60, 72, 117, 85, 90, 118,
+ 136, 151, 142, 160, 142, 155
+};
+
+static const opus_int16 silk_NLSF_DELTA_MIN_WB_Q15[ 17 ] = {
+ 100, 3, 40, 3, 3, 3, 5, 14,
+ 14, 10, 11, 3, 8, 9, 7, 3,
+ 347
+};
+
+const silk_NLSF_CB_struct silk_NLSF_CB_WB =
+{
+ 32,
+ 16,
+ SILK_FIX_CONST( 0.15, 16 ),
+ SILK_FIX_CONST( 1.0 / 0.15, 6 ),
+ silk_NLSF_CB1_WB_Q8,
+ silk_NLSF_CB1_iCDF_WB,
+ silk_NLSF_PRED_WB_Q8,
+ silk_NLSF_CB2_SELECT_WB,
+ silk_NLSF_CB2_iCDF_WB,
+ silk_NLSF_CB2_BITS_WB_Q5,
+ silk_NLSF_DELTA_MIN_WB_Q15,
+};
+
diff --git a/external/opus-1.1.4/silk/tables_gain.c b/external/opus-1.1.4/silk/tables_gain.c
new file mode 100644
index 0000000..37e41d8
--- /dev/null
+++ b/external/opus-1.1.4/silk/tables_gain.c
@@ -0,0 +1,63 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ] =
+{
+{
+ 224, 112, 44, 15, 3, 2, 1, 0
+},
+{
+ 254, 237, 192, 132, 70, 23, 4, 0
+},
+{
+ 255, 252, 226, 155, 61, 11, 2, 0
+}
+};
+
+const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ] = {
+ 250, 245, 234, 203, 71, 50, 42, 38,
+ 35, 33, 31, 29, 28, 27, 26, 25,
+ 24, 23, 22, 21, 20, 19, 18, 17,
+ 16, 15, 14, 13, 12, 11, 10, 9,
+ 8, 7, 6, 5, 4, 3, 2, 1,
+ 0
+};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/external/opus-1.1.4/silk/tables_other.c b/external/opus-1.1.4/silk/tables_other.c
new file mode 100644
index 0000000..398686b
--- /dev/null
+++ b/external/opus-1.1.4/silk/tables_other.c
@@ -0,0 +1,138 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "structs.h"
+#include "define.h"
+#include "tables.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */
+const opus_int32 silk_TargetRate_table_NB[ TARGET_RATE_TAB_SZ ] = {
+ 0, 8000, 9400, 11500, 13500, 17500, 25000, MAX_TARGET_RATE_BPS
+};
+const opus_int32 silk_TargetRate_table_MB[ TARGET_RATE_TAB_SZ ] = {
+ 0, 9000, 12000, 14500, 18500, 24500, 35500, MAX_TARGET_RATE_BPS
+};
+const opus_int32 silk_TargetRate_table_WB[ TARGET_RATE_TAB_SZ ] = {
+ 0, 10500, 14000, 17000, 21500, 28500, 42000, MAX_TARGET_RATE_BPS
+};
+const opus_int16 silk_SNR_table_Q1[ TARGET_RATE_TAB_SZ ] = {
+ 18, 29, 38, 40, 46, 52, 62, 84
+};
+
+/* Tables for stereo predictor coding */
+const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ] = {
+ -13732, -10050, -8266, -7526, -6500, -5000, -2950, -820,
+ 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732
+};
+const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ] = {
+ 249, 247, 246, 245, 244,
+ 234, 210, 202, 201, 200,
+ 197, 174, 82, 59, 56,
+ 55, 54, 46, 22, 12,
+ 11, 10, 9, 7, 0
+};
+const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ] = { 64, 0 };
+
+/* Tables for LBRR flags */
+static const opus_uint8 silk_LBRR_flags_2_iCDF[ 3 ] = { 203, 150, 0 };
+static const opus_uint8 silk_LBRR_flags_3_iCDF[ 7 ] = { 215, 195, 166, 125, 110, 82, 0 };
+const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ] = {
+ silk_LBRR_flags_2_iCDF,
+ silk_LBRR_flags_3_iCDF
+};
+
+/* Table for LSB coding */
+const opus_uint8 silk_lsb_iCDF[ 2 ] = { 120, 0 };
+
+/* Tables for LTPScale */
+const opus_uint8 silk_LTPscale_iCDF[ 3 ] = { 128, 64, 0 };
+
+/* Tables for signal type and offset coding */
+const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ] = {
+ 232, 158, 10, 0
+};
+const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ] = {
+ 230, 0
+};
+
+/* Tables for NLSF interpolation factor */
+const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ] = { 243, 221, 192, 181, 0 };
+
+/* Quantization offsets */
+const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ] = {
+ { OFFSET_UVL_Q10, OFFSET_UVH_Q10 }, { OFFSET_VL_Q10, OFFSET_VH_Q10 }
+};
+
+/* Table for LTPScale */
+const opus_int16 silk_LTPScales_table_Q14[ 3 ] = { 15565, 12288, 8192 };
+
+/* Uniform entropy tables */
+const opus_uint8 silk_uniform3_iCDF[ 3 ] = { 171, 85, 0 };
+const opus_uint8 silk_uniform4_iCDF[ 4 ] = { 192, 128, 64, 0 };
+const opus_uint8 silk_uniform5_iCDF[ 5 ] = { 205, 154, 102, 51, 0 };
+const opus_uint8 silk_uniform6_iCDF[ 6 ] = { 213, 171, 128, 85, 43, 0 };
+const opus_uint8 silk_uniform8_iCDF[ 8 ] = { 224, 192, 160, 128, 96, 64, 32, 0 };
+
+const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ] = { 100, 40, 16, 7, 3, 1, 0 };
+
+/* Elliptic/Cauer filters designed with 0.1 dB passband ripple,
+ 80 dB minimum stopband attenuation, and
+ [0.95 : 0.15 : 0.35] normalized cut off frequencies. */
+
+/* Interpolation points for filter coefficients used in the bandwidth transition smoother */
+const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ] =
+{
+{ 250767114, 501534038, 250767114 },
+{ 209867381, 419732057, 209867381 },
+{ 170987846, 341967853, 170987846 },
+{ 131531482, 263046905, 131531482 },
+{ 89306658, 178584282, 89306658 }
+};
+
+/* Interpolation points for filter coefficients used in the bandwidth transition smoother */
+const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ] =
+{
+{ 506393414, 239854379 },
+{ 411067935, 169683996 },
+{ 306733530, 116694253 },
+{ 185807084, 77959395 },
+{ 35497197, 57401098 }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/external/opus-1.1.4/silk/tables_pitch_lag.c b/external/opus-1.1.4/silk/tables_pitch_lag.c
new file mode 100644
index 0000000..e80cc59
--- /dev/null
+++ b/external/opus-1.1.4/silk/tables_pitch_lag.c
@@ -0,0 +1,69 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ] = {
+ 253, 250, 244, 233, 212, 182, 150, 131,
+ 120, 110, 98, 85, 72, 60, 49, 40,
+ 32, 25, 19, 15, 13, 11, 9, 8,
+ 7, 6, 5, 4, 3, 2, 1, 0
+};
+
+const opus_uint8 silk_pitch_delta_iCDF[21] = {
+ 210, 208, 206, 203, 199, 193, 183, 168,
+ 142, 104, 74, 52, 37, 27, 20, 14,
+ 10, 6, 4, 2, 0
+};
+
+const opus_uint8 silk_pitch_contour_iCDF[34] = {
+ 223, 201, 183, 167, 152, 138, 124, 111,
+ 98, 88, 79, 70, 62, 56, 50, 44,
+ 39, 35, 31, 27, 24, 21, 18, 16,
+ 14, 12, 10, 8, 6, 4, 3, 2,
+ 1, 0
+};
+
+const opus_uint8 silk_pitch_contour_NB_iCDF[11] = {
+ 188, 176, 155, 138, 119, 97, 67, 43,
+ 26, 10, 0
+};
+
+const opus_uint8 silk_pitch_contour_10_ms_iCDF[12] = {
+ 165, 119, 80, 61, 47, 35, 27, 20,
+ 14, 9, 4, 0
+};
+
+const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[3] = {
+ 113, 63, 0
+};
+
+
diff --git a/external/opus-1.1.4/silk/tables_pulses_per_block.c b/external/opus-1.1.4/silk/tables_pulses_per_block.c
new file mode 100644
index 0000000..c7c01c8
--- /dev/null
+++ b/external/opus-1.1.4/silk/tables_pulses_per_block.c
@@ -0,0 +1,264 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+const opus_uint8 silk_max_pulses_table[ 4 ] = {
+ 8, 10, 12, 16
+};
+
+const opus_uint8 silk_pulses_per_block_iCDF[ 10 ][ 18 ] = {
+{
+ 125, 51, 26, 18, 15, 12, 11, 10,
+ 9, 8, 7, 6, 5, 4, 3, 2,
+ 1, 0
+},
+{
+ 198, 105, 45, 22, 15, 12, 11, 10,
+ 9, 8, 7, 6, 5, 4, 3, 2,
+ 1, 0
+},
+{
+ 213, 162, 116, 83, 59, 43, 32, 24,
+ 18, 15, 12, 9, 7, 6, 5, 3,
+ 2, 0
+},
+{
+ 239, 187, 116, 59, 28, 16, 11, 10,
+ 9, 8, 7, 6, 5, 4, 3, 2,
+ 1, 0
+},
+{
+ 250, 229, 188, 135, 86, 51, 30, 19,
+ 13, 10, 8, 6, 5, 4, 3, 2,
+ 1, 0
+},
+{
+ 249, 235, 213, 185, 156, 128, 103, 83,
+ 66, 53, 42, 33, 26, 21, 17, 13,
+ 10, 0
+},
+{
+ 254, 249, 235, 206, 164, 118, 77, 46,
+ 27, 16, 10, 7, 5, 4, 3, 2,
+ 1, 0
+},
+{
+ 255, 253, 249, 239, 220, 191, 156, 119,
+ 85, 57, 37, 23, 15, 10, 6, 4,
+ 2, 0
+},
+{
+ 255, 253, 251, 246, 237, 223, 203, 179,
+ 152, 124, 98, 75, 55, 40, 29, 21,
+ 15, 0
+},
+{
+ 255, 254, 253, 247, 220, 162, 106, 67,
+ 42, 28, 18, 12, 9, 6, 4, 3,
+ 2, 0
+}
+};
+
+const opus_uint8 silk_pulses_per_block_BITS_Q5[ 9 ][ 18 ] = {
+{
+ 31, 57, 107, 160, 205, 205, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255
+},
+{
+ 69, 47, 67, 111, 166, 205, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255
+},
+{
+ 82, 74, 79, 95, 109, 128, 145, 160,
+ 173, 205, 205, 205, 224, 255, 255, 224,
+ 255, 224
+},
+{
+ 125, 74, 59, 69, 97, 141, 182, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255
+},
+{
+ 173, 115, 85, 73, 76, 92, 115, 145,
+ 173, 205, 224, 224, 255, 255, 255, 255,
+ 255, 255
+},
+{
+ 166, 134, 113, 102, 101, 102, 107, 118,
+ 125, 138, 145, 155, 166, 182, 192, 192,
+ 205, 150
+},
+{
+ 224, 182, 134, 101, 83, 79, 85, 97,
+ 120, 145, 173, 205, 224, 255, 255, 255,
+ 255, 255
+},
+{
+ 255, 224, 192, 150, 120, 101, 92, 89,
+ 93, 102, 118, 134, 160, 182, 192, 224,
+ 224, 224
+},
+{
+ 255, 224, 224, 182, 155, 134, 118, 109,
+ 104, 102, 106, 111, 118, 131, 145, 160,
+ 173, 131
+}
+};
+
+const opus_uint8 silk_rate_levels_iCDF[ 2 ][ 9 ] =
+{
+{
+ 241, 190, 178, 132, 87, 74, 41, 14,
+ 0
+},
+{
+ 223, 193, 157, 140, 106, 57, 39, 18,
+ 0
+}
+};
+
+const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ 9 ] =
+{
+{
+ 131, 74, 141, 79, 80, 138, 95, 104,
+ 134
+},
+{
+ 95, 99, 91, 125, 93, 76, 123, 115,
+ 123
+}
+};
+
+const opus_uint8 silk_shell_code_table0[ 152 ] = {
+ 128, 0, 214, 42, 0, 235, 128, 21,
+ 0, 244, 184, 72, 11, 0, 248, 214,
+ 128, 42, 7, 0, 248, 225, 170, 80,
+ 25, 5, 0, 251, 236, 198, 126, 54,
+ 18, 3, 0, 250, 238, 211, 159, 82,
+ 35, 15, 5, 0, 250, 231, 203, 168,
+ 128, 88, 53, 25, 6, 0, 252, 238,
+ 216, 185, 148, 108, 71, 40, 18, 4,
+ 0, 253, 243, 225, 199, 166, 128, 90,
+ 57, 31, 13, 3, 0, 254, 246, 233,
+ 212, 183, 147, 109, 73, 44, 23, 10,
+ 2, 0, 255, 250, 240, 223, 198, 166,
+ 128, 90, 58, 33, 16, 6, 1, 0,
+ 255, 251, 244, 231, 210, 181, 146, 110,
+ 75, 46, 25, 12, 5, 1, 0, 255,
+ 253, 248, 238, 221, 196, 164, 128, 92,
+ 60, 35, 18, 8, 3, 1, 0, 255,
+ 253, 249, 242, 229, 208, 180, 146, 110,
+ 76, 48, 27, 14, 7, 3, 1, 0
+};
+
+const opus_uint8 silk_shell_code_table1[ 152 ] = {
+ 129, 0, 207, 50, 0, 236, 129, 20,
+ 0, 245, 185, 72, 10, 0, 249, 213,
+ 129, 42, 6, 0, 250, 226, 169, 87,
+ 27, 4, 0, 251, 233, 194, 130, 62,
+ 20, 4, 0, 250, 236, 207, 160, 99,
+ 47, 17, 3, 0, 255, 240, 217, 182,
+ 131, 81, 41, 11, 1, 0, 255, 254,
+ 233, 201, 159, 107, 61, 20, 2, 1,
+ 0, 255, 249, 233, 206, 170, 128, 86,
+ 50, 23, 7, 1, 0, 255, 250, 238,
+ 217, 186, 148, 108, 70, 39, 18, 6,
+ 1, 0, 255, 252, 243, 226, 200, 166,
+ 128, 90, 56, 30, 13, 4, 1, 0,
+ 255, 252, 245, 231, 209, 180, 146, 110,
+ 76, 47, 25, 11, 4, 1, 0, 255,
+ 253, 248, 237, 219, 194, 163, 128, 93,
+ 62, 37, 19, 8, 3, 1, 0, 255,
+ 254, 250, 241, 226, 205, 177, 145, 111,
+ 79, 51, 30, 15, 6, 2, 1, 0
+};
+
+const opus_uint8 silk_shell_code_table2[ 152 ] = {
+ 129, 0, 203, 54, 0, 234, 129, 23,
+ 0, 245, 184, 73, 10, 0, 250, 215,
+ 129, 41, 5, 0, 252, 232, 173, 86,
+ 24, 3, 0, 253, 240, 200, 129, 56,
+ 15, 2, 0, 253, 244, 217, 164, 94,
+ 38, 10, 1, 0, 253, 245, 226, 189,
+ 132, 71, 27, 7, 1, 0, 253, 246,
+ 231, 203, 159, 105, 56, 23, 6, 1,
+ 0, 255, 248, 235, 213, 179, 133, 85,
+ 47, 19, 5, 1, 0, 255, 254, 243,
+ 221, 194, 159, 117, 70, 37, 12, 2,
+ 1, 0, 255, 254, 248, 234, 208, 171,
+ 128, 85, 48, 22, 8, 2, 1, 0,
+ 255, 254, 250, 240, 220, 189, 149, 107,
+ 67, 36, 16, 6, 2, 1, 0, 255,
+ 254, 251, 243, 227, 201, 166, 128, 90,
+ 55, 29, 13, 5, 2, 1, 0, 255,
+ 254, 252, 246, 234, 213, 183, 147, 109,
+ 73, 43, 22, 10, 4, 2, 1, 0
+};
+
+const opus_uint8 silk_shell_code_table3[ 152 ] = {
+ 130, 0, 200, 58, 0, 231, 130, 26,
+ 0, 244, 184, 76, 12, 0, 249, 214,
+ 130, 43, 6, 0, 252, 232, 173, 87,
+ 24, 3, 0, 253, 241, 203, 131, 56,
+ 14, 2, 0, 254, 246, 221, 167, 94,
+ 35, 8, 1, 0, 254, 249, 232, 193,
+ 130, 65, 23, 5, 1, 0, 255, 251,
+ 239, 211, 162, 99, 45, 15, 4, 1,
+ 0, 255, 251, 243, 223, 186, 131, 74,
+ 33, 11, 3, 1, 0, 255, 252, 245,
+ 230, 202, 158, 105, 57, 24, 8, 2,
+ 1, 0, 255, 253, 247, 235, 214, 179,
+ 132, 84, 44, 19, 7, 2, 1, 0,
+ 255, 254, 250, 240, 223, 196, 159, 112,
+ 69, 36, 15, 6, 2, 1, 0, 255,
+ 254, 253, 245, 231, 209, 176, 136, 93,
+ 55, 27, 11, 3, 2, 1, 0, 255,
+ 254, 253, 252, 239, 221, 194, 158, 117,
+ 76, 42, 18, 4, 3, 2, 1, 0
+};
+
+const opus_uint8 silk_shell_code_table_offsets[ 17 ] = {
+ 0, 0, 2, 5, 9, 14, 20, 27,
+ 35, 44, 54, 65, 77, 90, 104, 119,
+ 135
+};
+
+const opus_uint8 silk_sign_iCDF[ 42 ] = {
+ 254, 49, 67, 77, 82, 93, 99,
+ 198, 11, 18, 24, 31, 36, 45,
+ 255, 46, 66, 78, 87, 94, 104,
+ 208, 14, 21, 32, 42, 51, 66,
+ 255, 94, 104, 109, 112, 115, 118,
+ 248, 53, 69, 80, 88, 95, 102
+};
diff --git a/external/opus-1.1.4/silk/tuning_parameters.h b/external/opus-1.1.4/silk/tuning_parameters.h
new file mode 100644
index 0000000..5b8f404
--- /dev/null
+++ b/external/opus-1.1.4/silk/tuning_parameters.h
@@ -0,0 +1,171 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_TUNING_PARAMETERS_H
+#define SILK_TUNING_PARAMETERS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Decay time for bitreservoir */
+#define BITRESERVOIR_DECAY_TIME_MS 500
+
+/*******************/
+/* Pitch estimator */
+/*******************/
+
+/* Level of noise floor for whitening filter LPC analysis in pitch analysis */
+#define FIND_PITCH_WHITE_NOISE_FRACTION 1e-3f
+
+/* Bandwidth expansion for whitening filter in pitch analysis */
+#define FIND_PITCH_BANDWIDTH_EXPANSION 0.99f
+
+/*********************/
+/* Linear prediction */
+/*********************/
+
+/* LPC analysis regularization */
+#define FIND_LPC_COND_FAC 1e-5f
+
+/* LTP analysis defines */
+#define FIND_LTP_COND_FAC 1e-5f
+#define LTP_DAMPING 0.05f
+#define LTP_SMOOTHING 0.1f
+
+/* LTP quantization settings */
+#define MU_LTP_QUANT_NB 0.03f
+#define MU_LTP_QUANT_MB 0.025f
+#define MU_LTP_QUANT_WB 0.02f
+
+/* Max cumulative LTP gain */
+#define MAX_SUM_LOG_GAIN_DB 250.0f
+
+/***********************/
+/* High pass filtering */
+/***********************/
+
+/* Smoothing parameters for low end of pitch frequency range estimation */
+#define VARIABLE_HP_SMTH_COEF1 0.1f
+#define VARIABLE_HP_SMTH_COEF2 0.015f
+#define VARIABLE_HP_MAX_DELTA_FREQ 0.4f
+
+/* Min and max cut-off frequency values (-3 dB points) */
+#define VARIABLE_HP_MIN_CUTOFF_HZ 60
+#define VARIABLE_HP_MAX_CUTOFF_HZ 100
+
+/***********/
+/* Various */
+/***********/
+
+/* VAD threshold */
+#define SPEECH_ACTIVITY_DTX_THRES 0.05f
+
+/* Speech Activity LBRR enable threshold */
+#define LBRR_SPEECH_ACTIVITY_THRES 0.3f
+
+/*************************/
+/* Perceptual parameters */
+/*************************/
+
+/* reduction in coding SNR during low speech activity */
+#define BG_SNR_DECR_dB 2.0f
+
+/* factor for reducing quantization noise during voiced speech */
+#define HARM_SNR_INCR_dB 2.0f
+
+/* factor for reducing quantization noise for unvoiced sparse signals */
+#define SPARSE_SNR_INCR_dB 2.0f
+
+/* threshold for sparseness measure above which to use lower quantization offset during unvoiced */
+#define SPARSENESS_THRESHOLD_QNT_OFFSET 0.75f
+
+/* warping control */
+#define WARPING_MULTIPLIER 0.015f
+
+/* fraction added to first autocorrelation value */
+#define SHAPE_WHITE_NOISE_FRACTION 5e-5f
+
+/* noise shaping filter chirp factor */
+#define BANDWIDTH_EXPANSION 0.95f
+
+/* difference between chirp factors for analysis and synthesis noise shaping filters at low bitrates */
+#define LOW_RATE_BANDWIDTH_EXPANSION_DELTA 0.01f
+
+/* extra harmonic boosting (signal shaping) at low bitrates */
+#define LOW_RATE_HARMONIC_BOOST 0.1f
+
+/* extra harmonic boosting (signal shaping) for noisy input signals */
+#define LOW_INPUT_QUALITY_HARMONIC_BOOST 0.1f
+
+/* harmonic noise shaping */
+#define HARMONIC_SHAPING 0.3f
+
+/* extra harmonic noise shaping for high bitrates or noisy input */
+#define HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING 0.2f
+
+/* parameter for shaping noise towards higher frequencies */
+#define HP_NOISE_COEF 0.25f
+
+/* parameter for shaping noise even more towards higher frequencies during voiced speech */
+#define HARM_HP_NOISE_COEF 0.35f
+
+/* parameter for applying a high-pass tilt to the input signal */
+#define INPUT_TILT 0.05f
+
+/* parameter for extra high-pass tilt to the input signal at high rates */
+#define HIGH_RATE_INPUT_TILT 0.1f
+
+/* parameter for reducing noise at the very low frequencies */
+#define LOW_FREQ_SHAPING 4.0f
+
+/* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */
+#define LOW_QUALITY_LOW_FREQ_SHAPING_DECR 0.5f
+
+/* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower -> more smoothing) */
+#define SUBFR_SMTH_COEF 0.4f
+
+/* parameters defining the R/D tradeoff in the residual quantizer */
+#define LAMBDA_OFFSET 1.2f
+#define LAMBDA_SPEECH_ACT -0.2f
+#define LAMBDA_DELAYED_DECISIONS -0.05f
+#define LAMBDA_INPUT_QUALITY -0.1f
+#define LAMBDA_CODING_QUALITY -0.2f
+#define LAMBDA_QUANT_OFFSET 0.8f
+
+/* Compensation in bitrate calculations for 10 ms modes */
+#define REDUCE_BITRATE_10_MS_BPS 2200
+
+/* Maximum time before allowing a bandwidth transition */
+#define MAX_BANDWIDTH_SWITCH_DELAY_MS 5000
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_TUNING_PARAMETERS_H */
diff --git a/external/opus-1.1.4/silk/typedef.h b/external/opus-1.1.4/silk/typedef.h
new file mode 100644
index 0000000..97b7e70
--- /dev/null
+++ b/external/opus-1.1.4/silk/typedef.h
@@ -0,0 +1,78 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+***********************************************************************/
+
+#ifndef SILK_TYPEDEF_H
+#define SILK_TYPEDEF_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#ifndef FIXED_POINT
+# include <float.h>
+# define silk_float float
+# define silk_float_MAX FLT_MAX
+#endif
+
+#define silk_int64_MAX ((opus_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */
+#define silk_int64_MIN ((opus_int64)0x8000000000000000LL) /* -2^63 */
+#define silk_int32_MAX 0x7FFFFFFF /* 2^31 - 1 = 2147483647 */
+#define silk_int32_MIN ((opus_int32)0x80000000) /* -2^31 = -2147483648 */
+#define silk_int16_MAX 0x7FFF /* 2^15 - 1 = 32767 */
+#define silk_int16_MIN ((opus_int16)0x8000) /* -2^15 = -32768 */
+#define silk_int8_MAX 0x7F /* 2^7 - 1 = 127 */
+#define silk_int8_MIN ((opus_int8)0x80) /* -2^7 = -128 */
+#define silk_uint8_MAX 0xFF /* 2^8 - 1 = 255 */
+
+#define silk_TRUE 1
+#define silk_FALSE 0
+
+/* assertions */
+#if (defined _WIN32 && !defined _WINCE && !defined(__GNUC__) && !defined(NO_ASSERTS))
+# ifndef silk_assert
+# include <crtdbg.h> /* ASSERTE() */
+# define silk_assert(COND) _ASSERTE(COND)
+# endif
+#else
+# ifdef ENABLE_ASSERTIONS
+# include <stdio.h>
+# include <stdlib.h>
+#define silk_fatal(str) _silk_fatal(str, __FILE__, __LINE__);
+#ifdef __GNUC__
+__attribute__((noreturn))
+#endif
+static OPUS_INLINE void _silk_fatal(const char *str, const char *file, int line)
+{
+ fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
+ abort();
+}
+# define silk_assert(COND) {if (!(COND)) {silk_fatal("assertion failed: " #COND);}}
+# else
+# define silk_assert(COND)
+# endif
+#endif
+
+#endif /* SILK_TYPEDEF_H */
diff --git a/external/opus-1.1.4/silk/x86/NSQ_del_dec_sse.c b/external/opus-1.1.4/silk/x86/NSQ_del_dec_sse.c
new file mode 100644
index 0000000..21d4a8b
--- /dev/null
+++ b/external/opus-1.1.4/silk/x86/NSQ_del_dec_sse.c
@@ -0,0 +1,857 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+#include "main.h"
+#include "celt/x86/x86cpu.h"
+
+#include "stack_alloc.h"
+
+typedef struct {
+ opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ];
+ opus_int32 RandState[ DECISION_DELAY ];
+ opus_int32 Q_Q10[ DECISION_DELAY ];
+ opus_int32 Xq_Q14[ DECISION_DELAY ];
+ opus_int32 Pred_Q15[ DECISION_DELAY ];
+ opus_int32 Shape_Q14[ DECISION_DELAY ];
+ opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ];
+ opus_int32 LF_AR_Q14;
+ opus_int32 Seed;
+ opus_int32 SeedInit;
+ opus_int32 RD_Q10;
+} NSQ_del_dec_struct;
+
+typedef struct {
+ opus_int32 Q_Q10;
+ opus_int32 RD_Q10;
+ opus_int32 xq_Q14;
+ opus_int32 LF_AR_Q14;
+ opus_int32 sLTP_shp_Q14;
+ opus_int32 LPC_exc_Q14;
+} NSQ_sample_struct;
+
+typedef NSQ_sample_struct NSQ_sample_pair[ 2 ];
+
+static OPUS_INLINE void silk_nsq_del_dec_scale_states_sse4_1(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ const opus_int32 x_Q3[], /* I Input in Q3 */
+ opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */
+ const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I Subframe number */
+ opus_int nStatesDelayedDecision, /* I Number of del dec states */
+ const opus_int LTP_scale_Q14, /* I LTP state scaling */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type, /* I Signal type */
+ const opus_int decisionDelay /* I Decision delay */
+);
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP filter state */
+ opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int subfr, /* I Subframe number */
+ opus_int shapingLPCOrder, /* I Shaping LPC filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ opus_int warping_Q16, /* I */
+ opus_int nStatesDelayedDecision, /* I Number of states in decision tree */
+ opus_int *smpl_buf_idx, /* I Index to newest samples in buffers */
+ opus_int decisionDelay /* I */
+);
+
+void silk_NSQ_del_dec_sse4_1(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+)
+{
+ opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr;
+ opus_int last_smple_idx, smpl_buf_idx, decisionDelay;
+ const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13;
+ opus_int16 *pxq;
+ VARDECL( opus_int32, sLTP_Q15 );
+ VARDECL( opus_int16, sLTP );
+ opus_int32 HarmShapeFIRPacked_Q14;
+ opus_int offset_Q10;
+ opus_int32 RDmin_Q10, Gain_Q10;
+ VARDECL( opus_int32, x_sc_Q10 );
+ VARDECL( opus_int32, delayedGain_Q10 );
+ VARDECL( NSQ_del_dec_struct, psDelDec );
+ NSQ_del_dec_struct *psDD;
+ SAVE_STACK;
+
+ /* Set unvoiced lag to the previous one, overwrite later for voiced */
+ lag = NSQ->lagPrev;
+
+ silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+ /* Initialize delayed decision states */
+ ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct );
+ silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) );
+ for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ psDD->Seed = ( k + psIndices->Seed ) & 3;
+ psDD->SeedInit = psDD->Seed;
+ psDD->RD_Q10 = 0;
+ psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14;
+ psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ];
+ silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) );
+ }
+
+ offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+ smpl_buf_idx = 0; /* index of oldest samples */
+
+ decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length );
+
+ /* For voiced frames limit the decision delay to lower than the pitch lag */
+ if( psIndices->signalType == TYPE_VOICED ) {
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 );
+ }
+ } else {
+ if( lag > 0 ) {
+ decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 );
+ }
+ }
+
+ if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+ LSF_interpolation_flag = 0;
+ } else {
+ LSF_interpolation_flag = 1;
+ }
+
+ ALLOC( sLTP_Q15,
+ psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+ ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+ ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+ ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 );
+ /* Set up pointers to start of sub frame */
+ pxq = &NSQ->xq[ psEncC->ltp_mem_length ];
+ NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ subfr = 0;
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ];
+ B_Q14 = &LTPCoef_Q14[ k * LTP_ORDER ];
+ AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Noise shape parameters */
+ silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+ HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+ HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+ NSQ->rewhite_flag = 0;
+ if( psIndices->signalType == TYPE_VOICED ) {
+ /* Voiced */
+ lag = pitchL[ k ];
+
+ /* Re-whitening */
+ if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+ if( k == 2 ) {
+ /* RESET DELAYED DECISIONS */
+ /* Find winner */
+ RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) {
+ if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psDelDec[ i ].RD_Q10;
+ Winner_ind = i;
+ }
+ }
+ for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) {
+ if( i != Winner_ind ) {
+ psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 );
+ silk_assert( psDelDec[ i ].RD_Q10 >= 0 );
+ }
+ }
+
+ /* Copy final part of signals from winner state to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ last_smple_idx = smpl_buf_idx + decisionDelay;
+ for( i = 0; i < decisionDelay; i++ ) {
+ last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK;
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+ }
+
+ subfr = 0;
+ }
+
+ /* Rewhiten with new A coefs */
+ start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+ silk_assert( start_idx > 0 );
+
+ silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+ A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
+
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ NSQ->rewhite_flag = 1;
+ }
+ }
+
+ silk_nsq_del_dec_scale_states_sse4_1( psEncC, NSQ, psDelDec, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k,
+ psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay );
+
+ silk_noise_shape_quantizer_del_dec_sse4_1( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15,
+ delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ],
+ Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder,
+ psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay );
+
+ x_Q3 += psEncC->subfr_length;
+ pulses += psEncC->subfr_length;
+ pxq += psEncC->subfr_length;
+ }
+
+ /* Find winner */
+ RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) {
+ if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psDelDec[ k ].RD_Q10;
+ Winner_ind = k;
+ }
+ }
+
+ /* Copy final part of signals from winner state to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ psIndices->Seed = psDD->SeedInit;
+ last_smple_idx = smpl_buf_idx + decisionDelay;
+ Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 );
+ for( i = 0; i < decisionDelay; i++ ) {
+ last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK;
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+ }
+ silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) );
+
+ /* Update states */
+ NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14;
+ NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
+
+ /* Save quantized speech signal */
+ /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[psEncC->ltp_mem_length], psEncC->frame_length * sizeof( opus_int16 ) ) */
+ silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+ silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP filter state */
+ opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int subfr, /* I Subframe number */
+ opus_int shapingLPCOrder, /* I Shaping LPC filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ opus_int warping_Q16, /* I */
+ opus_int nStatesDelayedDecision, /* I Number of states in decision tree */
+ opus_int *smpl_buf_idx, /* I Index to newest samples in buffers */
+ opus_int decisionDelay /* I */
+)
+{
+ opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx;
+ opus_int32 Winner_rand_state;
+ opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14;
+ opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10;
+ opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+ opus_int32 tmp1, tmp2, sLF_AR_shp_Q14;
+ opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14;
+ VARDECL( NSQ_sample_pair, psSampleState );
+ NSQ_del_dec_struct *psDD;
+ NSQ_sample_struct *psSS;
+
+ __m128i a_Q12_0123, a_Q12_4567, a_Q12_89AB, a_Q12_CDEF;
+ __m128i b_Q12_0123, b_sr_Q12_0123;
+ SAVE_STACK;
+
+ silk_assert( nStatesDelayedDecision > 0 );
+ ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair );
+
+ shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+ pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 );
+
+ a_Q12_0123 = OP_CVTEPI16_EPI32_M64( a_Q12 );
+ a_Q12_4567 = OP_CVTEPI16_EPI32_M64( a_Q12 + 4 );
+
+ if( opus_likely( predictLPCOrder == 16 ) ) {
+ a_Q12_89AB = OP_CVTEPI16_EPI32_M64( a_Q12 + 8 );
+ a_Q12_CDEF = OP_CVTEPI16_EPI32_M64( a_Q12 + 12 );
+ }
+
+ if( signalType == TYPE_VOICED ){
+ b_Q12_0123 = OP_CVTEPI16_EPI32_M64( b_Q14 );
+ b_sr_Q12_0123 = _mm_shuffle_epi32( b_Q12_0123, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+ }
+ for( i = 0; i < length; i++ ) {
+ /* Perform common calculations used in all states */
+
+ /* Long-term prediction */
+ if( signalType == TYPE_VOICED ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q14 = 2;
+ {
+ __m128i tmpa, tmpb, pred_lag_ptr_tmp;
+ pred_lag_ptr_tmp = _mm_loadu_si128( (__m128i *)(&pred_lag_ptr[ -3 ] ) );
+ pred_lag_ptr_tmp = _mm_shuffle_epi32( pred_lag_ptr_tmp, 0x1B );
+ tmpa = _mm_mul_epi32( pred_lag_ptr_tmp, b_Q12_0123 );
+ tmpa = _mm_srli_si128( tmpa, 2 );
+
+ pred_lag_ptr_tmp = _mm_shuffle_epi32( pred_lag_ptr_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) );/* equal shift right 4 bytes */
+ pred_lag_ptr_tmp = _mm_mul_epi32( pred_lag_ptr_tmp, b_sr_Q12_0123 );
+ pred_lag_ptr_tmp = _mm_srli_si128( pred_lag_ptr_tmp, 2 );
+ pred_lag_ptr_tmp = _mm_add_epi32( pred_lag_ptr_tmp, tmpa );
+
+ tmpb = _mm_shuffle_epi32( pred_lag_ptr_tmp, _MM_SHUFFLE( 0, 0, 3, 2 ) );/* equal shift right 8 bytes */
+ pred_lag_ptr_tmp = _mm_add_epi32( pred_lag_ptr_tmp, tmpb );
+ LTP_pred_Q14 += _mm_cvtsi128_si32( pred_lag_ptr_tmp );
+
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+ LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */
+ pred_lag_ptr++;
+ }
+ } else {
+ LTP_pred_Q14 = 0;
+ }
+
+ /* Long-term shaping */
+ if( lag > 0 ) {
+ /* Symmetric, packed FIR coefficients */
+ n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+ n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
+ n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */
+ shp_lag_ptr++;
+ } else {
+ n_LTP_Q14 = 0;
+ }
+ {
+ __m128i tmpa, tmpb, psLPC_Q14_tmp, a_Q12_tmp;
+
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ /* Delayed decision state */
+ psDD = &psDelDec[ k ];
+
+ /* Sample state */
+ psSS = psSampleState[ k ];
+
+ /* Generate dither */
+ psDD->Seed = silk_RAND( psDD->Seed );
+
+ /* Pointer used in short term prediction and shaping */
+ psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ];
+ /* Short-term prediction */
+ silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 );
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LPC_pred_Q14 = silk_RSHIFT( predictLPCOrder, 1 );
+
+ tmpb = _mm_setzero_si128();
+
+ /* step 1 */
+ psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -3 ] ) ); /* -3, -2 , -1, 0 */
+ psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); /* 0, -1, -2, -3 */
+ tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_0123 ); /* 0, -1, -2, -3 * 0123 -> 0*0, 2*-2 */
+
+ tmpa = _mm_srli_epi64( tmpa, 16 );
+ tmpb = _mm_add_epi32( tmpb, tmpa );
+
+ psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+ a_Q12_tmp = _mm_shuffle_epi32( a_Q12_0123, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+ psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); /* 1*-1, 3*-3 */
+ psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 );
+ tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp );
+
+ /* step 2 */
+ psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -7 ] ) );
+ psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B );
+ tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_4567 );
+ tmpa = _mm_srli_epi64( tmpa, 16 );
+ tmpb = _mm_add_epi32( tmpb, tmpa );
+
+ psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+ a_Q12_tmp = _mm_shuffle_epi32( a_Q12_4567, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+ psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp );
+ psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 );
+ tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp );
+
+ if ( opus_likely( predictLPCOrder == 16 ) )
+ {
+ /* step 3 */
+ psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -11 ] ) );
+ psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B );
+ tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_89AB );
+ tmpa = _mm_srli_epi64( tmpa, 16 );
+ tmpb = _mm_add_epi32( tmpb, tmpa );
+
+ psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+ a_Q12_tmp = _mm_shuffle_epi32( a_Q12_89AB, _MM_SHUFFLE(0, 3, 2, 1 ) );/* equal shift right 4 bytes */
+ psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp );
+ psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 );
+ tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp );
+
+ /* setp 4 */
+ psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -15 ] ) );
+ psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B );
+ tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_CDEF );
+ tmpa = _mm_srli_epi64( tmpa, 16 );
+ tmpb = _mm_add_epi32( tmpb, tmpa );
+
+ psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+ a_Q12_tmp = _mm_shuffle_epi32( a_Q12_CDEF, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+ psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp );
+ psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 );
+ tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp );
+
+ /* add at last */
+ /* equal shift right 8 bytes*/
+ tmpa = _mm_shuffle_epi32( tmpb, _MM_SHUFFLE( 0, 0, 3, 2 ) );
+ tmpb = _mm_add_epi32( tmpb, tmpa );
+ LPC_pred_Q14 += _mm_cvtsi128_si32( tmpb );
+ }
+ else
+ {
+ /* add at last */
+ tmpa = _mm_shuffle_epi32( tmpb, _MM_SHUFFLE( 0, 0, 3, 2 ) ); /* equal shift right 8 bytes*/
+ tmpb = _mm_add_epi32( tmpb, tmpa );
+ LPC_pred_Q14 += _mm_cvtsi128_si32( tmpb );
+
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -8 ], a_Q12[ 8 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -9 ], a_Q12[ 9 ] );
+ }
+
+ LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */
+
+ /* Noise shape feedback */
+ silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
+ /* Output of lowpass section */
+ tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 );
+ psDD->sAR2_Q14[ 0 ] = tmp2;
+ n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 );
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] );
+ /* Loop over allpass sections */
+ for( j = 2; j < shapingLPCOrder; j += 2 ) {
+ /* Output of allpass section */
+ tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 );
+ psDD->sAR2_Q14[ j - 1 ] = tmp1;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 );
+ psDD->sAR2_Q14[ j + 0 ] = tmp2;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] );
+ }
+ psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
+
+ n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */
+ n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */
+
+ n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */
+ n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */
+ n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */
+
+ /* Input minus prediction plus noise feedback */
+ /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */
+ tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */
+ tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */
+ tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */
+
+ r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */
+
+ /* Flip sign depending on dither */
+ if ( psDD->Seed < 0 ) {
+ r_Q10 = -r_Q10;
+ }
+ r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+ /* Find two quantization level candidates and measure their rate-distortion */
+ q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+ q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+ if( q1_Q0 > 0 ) {
+ q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == 0 ) {
+ q1_Q10 = offset_Q10;
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == -1 ) {
+ q2_Q10 = offset_Q10;
+ q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else { /* q1_Q0 < -1 */
+ q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+ }
+ rr_Q10 = silk_SUB32( r_Q10, q1_Q10 );
+ rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 );
+ rr_Q10 = silk_SUB32( r_Q10, q2_Q10 );
+ rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 );
+
+ if( rd1_Q10 < rd2_Q10 ) {
+ psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+ psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+ psSS[ 0 ].Q_Q10 = q1_Q10;
+ psSS[ 1 ].Q_Q10 = q2_Q10;
+ } else {
+ psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+ psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+ psSS[ 0 ].Q_Q10 = q2_Q10;
+ psSS[ 1 ].Q_Q10 = q1_Q10;
+ }
+
+ /* Update states for best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 );
+ if ( psDD->Seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+ xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+ /* Update states */
+ sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 );
+ psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+ psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14;
+ psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14;
+ psSS[ 0 ].xq_Q14 = xq_Q14;
+
+ /* Update states for second best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 );
+ if ( psDD->Seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+ xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+ /* Update states */
+ sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 );
+ psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+ psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14;
+ psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14;
+ psSS[ 1 ].xq_Q14 = xq_Q14;
+ }
+ }
+ *smpl_buf_idx = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK; /* Index to newest samples */
+ last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK; /* Index to decisionDelay old samples */
+
+ /* Find winner */
+ RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( k = 1; k < nStatesDelayedDecision; k++ ) {
+ if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
+ Winner_ind = k;
+ }
+ }
+
+ /* Increase RD values of expired states */
+ Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ];
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) {
+ psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 );
+ psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 );
+ silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 );
+ }
+ }
+
+ /* Find worst in first set and best in second set */
+ RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+ RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10;
+ RDmax_ind = 0;
+ RDmin_ind = 0;
+ for( k = 1; k < nStatesDelayedDecision; k++ ) {
+ /* find worst in first set */
+ if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) {
+ RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
+ RDmax_ind = k;
+ }
+ /* find best in second set */
+ if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10;
+ RDmin_ind = k;
+ }
+ }
+
+ /* Replace a state if best from second set outperforms worst in first set */
+ if( RDmin_Q10 < RDmax_Q10 ) {
+ silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i,
+ ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) );
+ silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) );
+ }
+
+ /* Write samples from winner to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ if( subfr > 0 || i >= decisionDelay ) {
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ];
+ sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ];
+ }
+ NSQ->sLTP_shp_buf_idx++;
+ NSQ->sLTP_buf_idx++;
+
+ /* Update states */
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ psSS = &psSampleState[ k ][ 0 ];
+ psDD->LF_AR_Q14 = psSS->LF_AR_Q14;
+ psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14;
+ psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14;
+ psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10;
+ psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 );
+ psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14;
+ psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) );
+ psDD->RandState[ *smpl_buf_idx ] = psDD->Seed;
+ psDD->RD_Q10 = psSS->RD_Q10;
+ }
+ delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10;
+ }
+ /* Update LPC states */
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ }
+ RESTORE_STACK;
+}
+
+static OPUS_INLINE void silk_nsq_del_dec_scale_states_sse4_1(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ const opus_int32 x_Q3[], /* I Input in Q3 */
+ opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */
+ const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I Subframe number */
+ opus_int nStatesDelayedDecision, /* I Number of del dec states */
+ const opus_int LTP_scale_Q14, /* I LTP state scaling */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type, /* I Signal type */
+ const opus_int decisionDelay /* I Decision delay */
+)
+{
+ opus_int i, k, lag;
+ opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+ NSQ_del_dec_struct *psDD;
+ __m128i xmm_inv_gain_Q23, xmm_x_Q3_x2x0, xmm_x_Q3_x3x1;
+
+ lag = pitchL[ subfr ];
+ inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+
+ silk_assert( inv_gain_Q31 != 0 );
+
+ /* Calculate gain adjustment factor */
+ if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+ gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+ } else {
+ gain_adj_Q16 = (opus_int32)1 << 16;
+ }
+
+ /* Scale input */
+ inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 );
+
+ /* prepare inv_gain_Q23 in packed 4 32-bits */
+ xmm_inv_gain_Q23 = _mm_set1_epi32(inv_gain_Q23);
+
+ for( i = 0; i < psEncC->subfr_length - 3; i += 4 ) {
+ xmm_x_Q3_x2x0 = _mm_loadu_si128( (__m128i *)(&(x_Q3[ i ] ) ) );
+ /* equal shift right 4 bytes*/
+ xmm_x_Q3_x3x1 = _mm_shuffle_epi32( xmm_x_Q3_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+ xmm_x_Q3_x2x0 = _mm_mul_epi32( xmm_x_Q3_x2x0, xmm_inv_gain_Q23 );
+ xmm_x_Q3_x3x1 = _mm_mul_epi32( xmm_x_Q3_x3x1, xmm_inv_gain_Q23 );
+
+ xmm_x_Q3_x2x0 = _mm_srli_epi64( xmm_x_Q3_x2x0, 16 );
+ xmm_x_Q3_x3x1 = _mm_slli_epi64( xmm_x_Q3_x3x1, 16 );
+
+ xmm_x_Q3_x2x0 = _mm_blend_epi16( xmm_x_Q3_x2x0, xmm_x_Q3_x3x1, 0xCC );
+
+ _mm_storeu_si128( (__m128i *)(&(x_sc_Q10[ i ])), xmm_x_Q3_x2x0 );
+ }
+
+ for( ; i < psEncC->subfr_length; i++ ) {
+ x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 );
+ }
+
+ /* Save inverse gain */
+ NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+
+ /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+ if( NSQ->rewhite_flag ) {
+ if( subfr == 0 ) {
+ /* Do LTP downscaling */
+ inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+ }
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ silk_assert( i < MAX_FRAME_LENGTH );
+ sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+ }
+ }
+
+ /* Adjust for changing gain */
+ if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+ /* Scale long-term shaping state */
+ {
+ __m128i xmm_gain_adj_Q16, xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1;
+
+ /* prepare gain_adj_Q16 in packed 4 32-bits */
+ xmm_gain_adj_Q16 = _mm_set1_epi32( gain_adj_Q16 );
+
+ for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 3; i += 4 )
+ {
+ xmm_sLTP_shp_Q14_x2x0 = _mm_loadu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ) );
+ /* equal shift right 4 bytes*/
+ xmm_sLTP_shp_Q14_x3x1 = _mm_shuffle_epi32( xmm_sLTP_shp_Q14_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+ xmm_sLTP_shp_Q14_x2x0 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x2x0, xmm_gain_adj_Q16 );
+ xmm_sLTP_shp_Q14_x3x1 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x3x1, xmm_gain_adj_Q16 );
+
+ xmm_sLTP_shp_Q14_x2x0 = _mm_srli_epi64( xmm_sLTP_shp_Q14_x2x0, 16 );
+ xmm_sLTP_shp_Q14_x3x1 = _mm_slli_epi64( xmm_sLTP_shp_Q14_x3x1, 16 );
+
+ xmm_sLTP_shp_Q14_x2x0 = _mm_blend_epi16( xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1, 0xCC );
+
+ _mm_storeu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ), xmm_sLTP_shp_Q14_x2x0 );
+ }
+
+ for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+ NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+ }
+
+ /* Scale long-term prediction state */
+ if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) {
+ sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+ }
+ }
+
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+
+ /* Scale scalar states */
+ psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 );
+
+ /* Scale short-term prediction and shaping states */
+ for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+ psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] );
+ }
+ for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+ psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] );
+ }
+ for( i = 0; i < DECISION_DELAY; i++ ) {
+ psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] );
+ psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] );
+ }
+ }
+ }
+ }
+}
diff --git a/external/opus-1.1.4/silk/x86/NSQ_sse.c b/external/opus-1.1.4/silk/x86/NSQ_sse.c
new file mode 100644
index 0000000..bb3c5f1
--- /dev/null
+++ b/external/opus-1.1.4/silk/x86/NSQ_sse.c
@@ -0,0 +1,720 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+#include "main.h"
+#include "celt/x86/x86cpu.h"
+#include "stack_alloc.h"
+
+static OPUS_INLINE void silk_nsq_scale_states_sse4_1(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ const opus_int32 x_Q3[], /* I input in Q3 */
+ opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */
+ const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I subframe number */
+ const opus_int LTP_scale_Q14, /* I */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type /* I Signal type */
+);
+
+static OPUS_INLINE void silk_noise_shape_quantizer_10_16_sse4_1(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_sc_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP state */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int32 table[][4] /* I */
+);
+
+void silk_NSQ_sse4_1(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+)
+{
+ opus_int k, lag, start_idx, LSF_interpolation_flag;
+ const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13;
+ opus_int16 *pxq;
+ VARDECL( opus_int32, sLTP_Q15 );
+ VARDECL( opus_int16, sLTP );
+ opus_int32 HarmShapeFIRPacked_Q14;
+ opus_int offset_Q10;
+ VARDECL( opus_int32, x_sc_Q10 );
+
+ opus_int32 table[ 64 ][ 4 ];
+ opus_int32 tmp1;
+ opus_int32 q1_Q10, q2_Q10, rd1_Q20, rd2_Q20;
+
+ SAVE_STACK;
+
+ NSQ->rand_seed = psIndices->Seed;
+
+ /* Set unvoiced lag to the previous one, overwrite later for voiced */
+ lag = NSQ->lagPrev;
+
+ silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+ offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+
+ /* 0 */
+ q1_Q10 = offset_Q10;
+ q2_Q10 = offset_Q10 + ( 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q20 = q1_Q10 * Lambda_Q10;
+ rd2_Q20 = q2_Q10 * Lambda_Q10;
+
+ table[ 32 ][ 0 ] = q1_Q10;
+ table[ 32 ][ 1 ] = q2_Q10;
+ table[ 32 ][ 2 ] = 2 * (q1_Q10 - q2_Q10);
+ table[ 32 ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10);
+
+ /* -1 */
+ q1_Q10 = offset_Q10 - ( 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ q2_Q10 = offset_Q10;
+ rd1_Q20 = - q1_Q10 * Lambda_Q10;
+ rd2_Q20 = q2_Q10 * Lambda_Q10;
+
+ table[ 31 ][ 0 ] = q1_Q10;
+ table[ 31 ][ 1 ] = q2_Q10;
+ table[ 31 ][ 2 ] = 2 * (q1_Q10 - q2_Q10);
+ table[ 31 ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10);
+
+ /* > 0 */
+ for (k = 1; k <= 31; k++)
+ {
+ tmp1 = offset_Q10 + silk_LSHIFT( k, 10 );
+
+ q1_Q10 = tmp1 - QUANT_LEVEL_ADJUST_Q10;
+ q2_Q10 = tmp1 - QUANT_LEVEL_ADJUST_Q10 + 1024;
+ rd1_Q20 = q1_Q10 * Lambda_Q10;
+ rd2_Q20 = q2_Q10 * Lambda_Q10;
+
+ table[ 32 + k ][ 0 ] = q1_Q10;
+ table[ 32 + k ][ 1 ] = q2_Q10;
+ table[ 32 + k ][ 2 ] = 2 * (q1_Q10 - q2_Q10);
+ table[ 32 + k ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10);
+ }
+
+ /* < -1 */
+ for (k = -32; k <= -2; k++)
+ {
+ tmp1 = offset_Q10 + silk_LSHIFT( k, 10 );
+
+ q1_Q10 = tmp1 + QUANT_LEVEL_ADJUST_Q10;
+ q2_Q10 = tmp1 + QUANT_LEVEL_ADJUST_Q10 + 1024;
+ rd1_Q20 = - q1_Q10 * Lambda_Q10;
+ rd2_Q20 = - q2_Q10 * Lambda_Q10;
+
+ table[ 32 + k ][ 0 ] = q1_Q10;
+ table[ 32 + k ][ 1 ] = q2_Q10;
+ table[ 32 + k ][ 2 ] = 2 * (q1_Q10 - q2_Q10);
+ table[ 32 + k ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10);
+ }
+
+ if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+ LSF_interpolation_flag = 0;
+ } else {
+ LSF_interpolation_flag = 1;
+ }
+
+ ALLOC( sLTP_Q15,
+ psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+ ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+ ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+ /* Set up pointers to start of sub frame */
+ NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ pxq = &NSQ->xq[ psEncC->ltp_mem_length ];
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ];
+ B_Q14 = &LTPCoef_Q14[ k * LTP_ORDER ];
+ AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Noise shape parameters */
+ silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+ HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+ HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+ NSQ->rewhite_flag = 0;
+ if( psIndices->signalType == TYPE_VOICED ) {
+ /* Voiced */
+ lag = pitchL[ k ];
+
+ /* Re-whitening */
+ if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+ /* Rewhiten with new A coefs */
+ start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+ silk_assert( start_idx > 0 );
+
+ silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+ A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
+
+ NSQ->rewhite_flag = 1;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ }
+ }
+
+ silk_nsq_scale_states_sse4_1( psEncC, NSQ, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType );
+
+ if ( opus_likely( ( 10 == psEncC->shapingLPCOrder ) && ( 16 == psEncC->predictLPCOrder) ) )
+ {
+ silk_noise_shape_quantizer_10_16_sse4_1( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14,
+ AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ],
+ offset_Q10, psEncC->subfr_length, &(table[32]) );
+ }
+ else
+ {
+ silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14,
+ AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10,
+ offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, psEncC->arch );
+ }
+
+ x_Q3 += psEncC->subfr_length;
+ pulses += psEncC->subfr_length;
+ pxq += psEncC->subfr_length;
+ }
+
+ /* Update lagPrev for next frame */
+ NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
+
+ /* Save quantized speech and noise shaping signals */
+ /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[ psEncC->ltp_mem_length ], psEncC->frame_length * sizeof( opus_int16 ) ) */
+ silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+ silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
+
+/***********************************/
+/* silk_noise_shape_quantizer_10_16 */
+/***********************************/
+static OPUS_INLINE void silk_noise_shape_quantizer_10_16_sse4_1(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_sc_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP state */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int32 table[][4] /* I */
+)
+{
+ opus_int i;
+ opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13;
+ opus_int32 n_LF_Q12, r_Q10, q1_Q0, q1_Q10, q2_Q10;
+ opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+ opus_int32 tmp1, tmp2, sLF_AR_shp_Q14;
+ opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr;
+
+ __m128i xmm_tempa, xmm_tempb;
+
+ __m128i xmm_one;
+
+ __m128i psLPC_Q14_hi_01234567, psLPC_Q14_hi_89ABCDEF;
+ __m128i psLPC_Q14_lo_01234567, psLPC_Q14_lo_89ABCDEF;
+ __m128i a_Q12_01234567, a_Q12_89ABCDEF;
+
+ __m128i sAR2_Q14_hi_76543210, sAR2_Q14_lo_76543210;
+ __m128i AR_shp_Q13_76543210;
+
+ shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+ pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 );
+
+ /* Set up short term AR state */
+ psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ];
+
+ sLF_AR_shp_Q14 = NSQ->sLF_AR_shp_Q14;
+ xq_Q14 = psLPC_Q14[ 0 ];
+ LTP_pred_Q13 = 0;
+
+ /* load a_Q12 */
+ xmm_one = _mm_set_epi8( 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14 );
+
+ /* load a_Q12[0] - a_Q12[7] */
+ a_Q12_01234567 = _mm_loadu_si128( (__m128i *)(&a_Q12[ 0 ] ) );
+ /* load a_Q12[ 8 ] - a_Q12[ 15 ] */
+ a_Q12_89ABCDEF = _mm_loadu_si128( (__m128i *)(&a_Q12[ 8 ] ) );
+
+ a_Q12_01234567 = _mm_shuffle_epi8( a_Q12_01234567, xmm_one );
+ a_Q12_89ABCDEF = _mm_shuffle_epi8( a_Q12_89ABCDEF, xmm_one );
+
+ /* load AR_shp_Q13 */
+ AR_shp_Q13_76543210 = _mm_loadu_si128( (__m128i *)(&AR_shp_Q13[0] ) );
+
+ /* load psLPC_Q14 */
+ xmm_one = _mm_set_epi8(15, 14, 11, 10, 7, 6, 3, 2, 13, 12, 9, 8, 5, 4, 1, 0 );
+
+ xmm_tempa = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[-16]) );
+ xmm_tempb = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[-12]) );
+
+ xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one );
+ xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one );
+
+ psLPC_Q14_hi_89ABCDEF = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb );
+ psLPC_Q14_lo_89ABCDEF = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb );
+
+ xmm_tempa = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -8 ]) );
+ xmm_tempb = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -4 ]) );
+
+ xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one );
+ xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one );
+
+ psLPC_Q14_hi_01234567 = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb );
+ psLPC_Q14_lo_01234567 = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb );
+
+ /* load sAR2_Q14 */
+ xmm_tempa = _mm_loadu_si128( (__m128i *)(&(NSQ->sAR2_Q14[ 0 ]) ) );
+ xmm_tempb = _mm_loadu_si128( (__m128i *)(&(NSQ->sAR2_Q14[ 4 ]) ) );
+
+ xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one );
+ xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one );
+
+ sAR2_Q14_hi_76543210 = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb );
+ sAR2_Q14_lo_76543210 = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb );
+
+ /* prepare 1 in 8 * 16bit */
+ xmm_one = _mm_set1_epi16(1);
+
+ for( i = 0; i < length; i++ )
+ {
+ /* Short-term prediction */
+ __m128i xmm_hi_07, xmm_hi_8F, xmm_lo_07, xmm_lo_8F;
+
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LPC_pred_Q10 = 8; /* silk_RSHIFT( predictLPCOrder, 1 ); */
+
+ /* shift psLPC_Q14 */
+ psLPC_Q14_hi_89ABCDEF = _mm_alignr_epi8( psLPC_Q14_hi_01234567, psLPC_Q14_hi_89ABCDEF, 2 );
+ psLPC_Q14_lo_89ABCDEF = _mm_alignr_epi8( psLPC_Q14_lo_01234567, psLPC_Q14_lo_89ABCDEF, 2 );
+
+ psLPC_Q14_hi_01234567 = _mm_srli_si128( psLPC_Q14_hi_01234567, 2 );
+ psLPC_Q14_lo_01234567 = _mm_srli_si128( psLPC_Q14_lo_01234567, 2 );
+
+ psLPC_Q14_hi_01234567 = _mm_insert_epi16( psLPC_Q14_hi_01234567, (xq_Q14 >> 16), 7 );
+ psLPC_Q14_lo_01234567 = _mm_insert_epi16( psLPC_Q14_lo_01234567, (xq_Q14), 7 );
+
+ /* high part, use pmaddwd, results in 4 32-bit */
+ xmm_hi_07 = _mm_madd_epi16( psLPC_Q14_hi_01234567, a_Q12_01234567 );
+ xmm_hi_8F = _mm_madd_epi16( psLPC_Q14_hi_89ABCDEF, a_Q12_89ABCDEF );
+
+ /* low part, use pmulhw, results in 8 16-bit, note we need simulate unsigned * signed, _mm_srai_epi16(psLPC_Q14_lo_01234567, 15) */
+ xmm_tempa = _mm_cmpgt_epi16( _mm_setzero_si128(), psLPC_Q14_lo_01234567 );
+ xmm_tempb = _mm_cmpgt_epi16( _mm_setzero_si128(), psLPC_Q14_lo_89ABCDEF );
+
+ xmm_tempa = _mm_and_si128( xmm_tempa, a_Q12_01234567 );
+ xmm_tempb = _mm_and_si128( xmm_tempb, a_Q12_89ABCDEF );
+
+ xmm_lo_07 = _mm_mulhi_epi16( psLPC_Q14_lo_01234567, a_Q12_01234567 );
+ xmm_lo_8F = _mm_mulhi_epi16( psLPC_Q14_lo_89ABCDEF, a_Q12_89ABCDEF );
+
+ xmm_lo_07 = _mm_add_epi16( xmm_lo_07, xmm_tempa );
+ xmm_lo_8F = _mm_add_epi16( xmm_lo_8F, xmm_tempb );
+
+ xmm_lo_07 = _mm_madd_epi16( xmm_lo_07, xmm_one );
+ xmm_lo_8F = _mm_madd_epi16( xmm_lo_8F, xmm_one );
+
+ /* accumulate */
+ xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_hi_8F );
+ xmm_lo_07 = _mm_add_epi32( xmm_lo_07, xmm_lo_8F );
+
+ xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_lo_07 );
+
+ xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_unpackhi_epi64(xmm_hi_07, xmm_hi_07 ) );
+ xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_shufflelo_epi16(xmm_hi_07, 0x0E ) );
+
+ LPC_pred_Q10 += _mm_cvtsi128_si32( xmm_hi_07 );
+
+ /* Long-term prediction */
+ if ( opus_likely( signalType == TYPE_VOICED ) ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q13 = 2;
+ {
+ __m128i b_Q14_3210, b_Q14_0123, pred_lag_ptr_0123;
+
+ b_Q14_3210 = OP_CVTEPI16_EPI32_M64( b_Q14 );
+ b_Q14_0123 = _mm_shuffle_epi32( b_Q14_3210, 0x1B );
+
+ /* loaded: [0] [-1] [-2] [-3] */
+ pred_lag_ptr_0123 = _mm_loadu_si128( (__m128i *)(&pred_lag_ptr[ -3 ] ) );
+ /* shuffle to [-3] [-2] [-1] [0] and to new xmm */
+ xmm_tempa = _mm_shuffle_epi32( pred_lag_ptr_0123, 0x1B );
+ /*64-bit multiply, a[2] * b[-2], a[0] * b[0] */
+ xmm_tempa = _mm_mul_epi32( xmm_tempa, b_Q14_3210 );
+ /* right shift 2 bytes (16 bits), zero extended */
+ xmm_tempa = _mm_srli_si128( xmm_tempa, 2 );
+
+ /* a[1] * b[-1], a[3] * b[-3] */
+ pred_lag_ptr_0123 = _mm_mul_epi32( pred_lag_ptr_0123, b_Q14_0123 );
+ pred_lag_ptr_0123 = _mm_srli_si128( pred_lag_ptr_0123, 2 );
+
+ pred_lag_ptr_0123 = _mm_add_epi32( pred_lag_ptr_0123, xmm_tempa );
+ /* equal shift right 8 bytes*/
+ xmm_tempa = _mm_shuffle_epi32( pred_lag_ptr_0123, _MM_SHUFFLE( 0, 0, 3, 2 ) );
+ xmm_tempa = _mm_add_epi32( xmm_tempa, pred_lag_ptr_0123 );
+
+ LTP_pred_Q13 += _mm_cvtsi128_si32( xmm_tempa );
+
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+ pred_lag_ptr++;
+ }
+ }
+
+ /* Noise shape feedback */
+ NSQ->sAR2_Q14[ 9 ] = NSQ->sAR2_Q14[ 8 ];
+ NSQ->sAR2_Q14[ 8 ] = _mm_cvtsi128_si32( _mm_srli_si128(_mm_unpackhi_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 ), 12 ) );
+
+ sAR2_Q14_hi_76543210 = _mm_slli_si128( sAR2_Q14_hi_76543210, 2 );
+ sAR2_Q14_lo_76543210 = _mm_slli_si128( sAR2_Q14_lo_76543210, 2 );
+
+ sAR2_Q14_hi_76543210 = _mm_insert_epi16( sAR2_Q14_hi_76543210, (xq_Q14 >> 16), 0 );
+ sAR2_Q14_lo_76543210 = _mm_insert_epi16( sAR2_Q14_lo_76543210, (xq_Q14), 0 );
+
+ /* high part, use pmaddwd, results in 4 32-bit */
+ xmm_hi_07 = _mm_madd_epi16( sAR2_Q14_hi_76543210, AR_shp_Q13_76543210 );
+
+ /* low part, use pmulhw, results in 8 16-bit, note we need simulate unsigned * signed,_mm_srai_epi16(sAR2_Q14_lo_76543210, 15) */
+ xmm_tempa = _mm_cmpgt_epi16( _mm_setzero_si128(), sAR2_Q14_lo_76543210 );
+ xmm_tempa = _mm_and_si128( xmm_tempa, AR_shp_Q13_76543210 );
+
+ xmm_lo_07 = _mm_mulhi_epi16( sAR2_Q14_lo_76543210, AR_shp_Q13_76543210 );
+ xmm_lo_07 = _mm_add_epi16( xmm_lo_07, xmm_tempa );
+
+ xmm_lo_07 = _mm_madd_epi16( xmm_lo_07, xmm_one );
+
+ /* accumulate */
+ xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_lo_07 );
+
+ xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_unpackhi_epi64(xmm_hi_07, xmm_hi_07 ) );
+ xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_shufflelo_epi16(xmm_hi_07, 0x0E ) );
+
+ n_AR_Q12 = 5 + _mm_cvtsi128_si32( xmm_hi_07 );
+
+ n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sAR2_Q14[ 8 ], AR_shp_Q13[ 8 ] );
+ n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sAR2_Q14[ 9 ], AR_shp_Q13[ 9 ] );
+
+ n_AR_Q12 = silk_LSHIFT32( n_AR_Q12, 1 ); /* Q11 -> Q12 */
+ n_AR_Q12 = silk_SMLAWB( n_AR_Q12, sLF_AR_shp_Q14, Tilt_Q14 );
+
+ n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 );
+ n_LF_Q12 = silk_SMLAWT( n_LF_Q12, sLF_AR_shp_Q14, LF_shp_Q14 );
+
+ silk_assert( lag > 0 || signalType != TYPE_VOICED );
+
+ /* Combine prediction and noise shaping signals */
+ tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */
+ tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */
+ if( lag > 0 ) {
+ /* Symmetric, packed FIR coefficients */
+ n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+ n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
+ n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 );
+ shp_lag_ptr++;
+
+ tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */
+ tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */
+ } else {
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */
+ }
+
+ r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */
+
+ /* Generate dither */
+ NSQ->rand_seed = silk_RAND( NSQ->rand_seed );
+
+ /* Flip sign depending on dither */
+ tmp2 = -r_Q10;
+ if ( NSQ->rand_seed < 0 ) r_Q10 = tmp2;
+
+ r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+ /* Find two quantization level candidates and measure their rate-distortion */
+ q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+ q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+
+ q1_Q10 = table[q1_Q0][0];
+ q2_Q10 = table[q1_Q0][1];
+
+ if (r_Q10 * table[q1_Q0][2] - table[q1_Q0][3] < 0)
+ {
+ q1_Q10 = q2_Q10;
+ }
+
+ pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 );
+
+ /* Excitation */
+ exc_Q14 = silk_LSHIFT( q1_Q10, 4 );
+
+ tmp2 = -exc_Q14;
+ if ( NSQ->rand_seed < 0 ) exc_Q14 = tmp2;
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 );
+ xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 );
+
+ /* Update states */
+ psLPC_Q14++;
+ *psLPC_Q14 = xq_Q14;
+ sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, n_AR_Q12, 2 );
+
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 );
+ sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 );
+ NSQ->sLTP_shp_buf_idx++;
+ NSQ->sLTP_buf_idx++;
+
+ /* Make dither dependent on quantized signal */
+ NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] );
+ }
+
+ NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14;
+
+ /* Scale XQ back to normal level before saving */
+ psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH ];
+
+ /* write back sAR2_Q14 */
+ xmm_tempa = _mm_unpackhi_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 );
+ xmm_tempb = _mm_unpacklo_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 );
+ _mm_storeu_si128( (__m128i *)(&NSQ->sAR2_Q14[ 4 ]), xmm_tempa );
+ _mm_storeu_si128( (__m128i *)(&NSQ->sAR2_Q14[ 0 ]), xmm_tempb );
+
+ /* xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psLPC_Q14[ i ], Gain_Q10 ), 8 ) ); */
+ {
+ __m128i xmm_Gain_Q10;
+ __m128i xmm_xq_Q14_3210, xmm_xq_Q14_x3x1, xmm_xq_Q14_7654, xmm_xq_Q14_x7x5;
+
+ /* prepare (1 << 7) in packed 4 32-bits */
+ xmm_tempa = _mm_set1_epi32( (1 << 7) );
+
+ /* prepare Gain_Q10 in packed 4 32-bits */
+ xmm_Gain_Q10 = _mm_set1_epi32( Gain_Q10 );
+
+ /* process xq */
+ for (i = 0; i < length - 7; i += 8)
+ {
+ xmm_xq_Q14_3210 = _mm_loadu_si128( (__m128i *)(&(psLPC_Q14[ i + 0 ] ) ) );
+ xmm_xq_Q14_7654 = _mm_loadu_si128( (__m128i *)(&(psLPC_Q14[ i + 4 ] ) ) );
+
+ /* equal shift right 4 bytes*/
+ xmm_xq_Q14_x3x1 = _mm_shuffle_epi32( xmm_xq_Q14_3210, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+ /* equal shift right 4 bytes*/
+ xmm_xq_Q14_x7x5 = _mm_shuffle_epi32( xmm_xq_Q14_7654, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+ xmm_xq_Q14_3210 = _mm_mul_epi32( xmm_xq_Q14_3210, xmm_Gain_Q10 );
+ xmm_xq_Q14_x3x1 = _mm_mul_epi32( xmm_xq_Q14_x3x1, xmm_Gain_Q10 );
+ xmm_xq_Q14_7654 = _mm_mul_epi32( xmm_xq_Q14_7654, xmm_Gain_Q10 );
+ xmm_xq_Q14_x7x5 = _mm_mul_epi32( xmm_xq_Q14_x7x5, xmm_Gain_Q10 );
+
+ xmm_xq_Q14_3210 = _mm_srli_epi64( xmm_xq_Q14_3210, 16 );
+ xmm_xq_Q14_x3x1 = _mm_slli_epi64( xmm_xq_Q14_x3x1, 16 );
+ xmm_xq_Q14_7654 = _mm_srli_epi64( xmm_xq_Q14_7654, 16 );
+ xmm_xq_Q14_x7x5 = _mm_slli_epi64( xmm_xq_Q14_x7x5, 16 );
+
+ xmm_xq_Q14_3210 = _mm_blend_epi16( xmm_xq_Q14_3210, xmm_xq_Q14_x3x1, 0xCC );
+ xmm_xq_Q14_7654 = _mm_blend_epi16( xmm_xq_Q14_7654, xmm_xq_Q14_x7x5, 0xCC );
+
+ /* silk_RSHIFT_ROUND(xq, 8) */
+ xmm_xq_Q14_3210 = _mm_add_epi32( xmm_xq_Q14_3210, xmm_tempa );
+ xmm_xq_Q14_7654 = _mm_add_epi32( xmm_xq_Q14_7654, xmm_tempa );
+
+ xmm_xq_Q14_3210 = _mm_srai_epi32( xmm_xq_Q14_3210, 8 );
+ xmm_xq_Q14_7654 = _mm_srai_epi32( xmm_xq_Q14_7654, 8 );
+
+ /* silk_SAT16 */
+ xmm_xq_Q14_3210 = _mm_packs_epi32( xmm_xq_Q14_3210, xmm_xq_Q14_7654 );
+
+ /* save to xq */
+ _mm_storeu_si128( (__m128i *)(&xq[ i ] ), xmm_xq_Q14_3210 );
+ }
+ }
+ for ( ; i < length; i++)
+ {
+ xq[i] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psLPC_Q14[ i ], Gain_Q10 ), 8 ) );
+ }
+
+ /* Update LPC synth buffer */
+ silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+}
+
+static OPUS_INLINE void silk_nsq_scale_states_sse4_1(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ const opus_int32 x_Q3[], /* I input in Q3 */
+ opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */
+ const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I subframe number */
+ const opus_int LTP_scale_Q14, /* I */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type /* I Signal type */
+)
+{
+ opus_int i, lag;
+ opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+ __m128i xmm_inv_gain_Q23, xmm_x_Q3_x2x0, xmm_x_Q3_x3x1;
+
+ lag = pitchL[ subfr ];
+ inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+ silk_assert( inv_gain_Q31 != 0 );
+
+ /* Calculate gain adjustment factor */
+ if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+ gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+ } else {
+ gain_adj_Q16 = (opus_int32)1 << 16;
+ }
+
+ /* Scale input */
+ inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 );
+
+ /* prepare inv_gain_Q23 in packed 4 32-bits */
+ xmm_inv_gain_Q23 = _mm_set1_epi32(inv_gain_Q23);
+
+ for( i = 0; i < psEncC->subfr_length - 3; i += 4 ) {
+ xmm_x_Q3_x2x0 = _mm_loadu_si128( (__m128i *)(&(x_Q3[ i ] ) ) );
+
+ /* equal shift right 4 bytes*/
+ xmm_x_Q3_x3x1 = _mm_shuffle_epi32( xmm_x_Q3_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+ xmm_x_Q3_x2x0 = _mm_mul_epi32( xmm_x_Q3_x2x0, xmm_inv_gain_Q23 );
+ xmm_x_Q3_x3x1 = _mm_mul_epi32( xmm_x_Q3_x3x1, xmm_inv_gain_Q23 );
+
+ xmm_x_Q3_x2x0 = _mm_srli_epi64( xmm_x_Q3_x2x0, 16 );
+ xmm_x_Q3_x3x1 = _mm_slli_epi64( xmm_x_Q3_x3x1, 16 );
+
+ xmm_x_Q3_x2x0 = _mm_blend_epi16( xmm_x_Q3_x2x0, xmm_x_Q3_x3x1, 0xCC );
+
+ _mm_storeu_si128( (__m128i *)(&(x_sc_Q10[ i ] ) ), xmm_x_Q3_x2x0 );
+ }
+
+ for( ; i < psEncC->subfr_length; i++ ) {
+ x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 );
+ }
+
+ /* Save inverse gain */
+ NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+
+ /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+ if( NSQ->rewhite_flag ) {
+ if( subfr == 0 ) {
+ /* Do LTP downscaling */
+ inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+ }
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ silk_assert( i < MAX_FRAME_LENGTH );
+ sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+ }
+ }
+
+ /* Adjust for changing gain */
+ if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+ /* Scale long-term shaping state */
+ __m128i xmm_gain_adj_Q16, xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1;
+
+ /* prepare gain_adj_Q16 in packed 4 32-bits */
+ xmm_gain_adj_Q16 = _mm_set1_epi32(gain_adj_Q16);
+
+ for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 3; i += 4 )
+ {
+ xmm_sLTP_shp_Q14_x2x0 = _mm_loadu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ) );
+ /* equal shift right 4 bytes*/
+ xmm_sLTP_shp_Q14_x3x1 = _mm_shuffle_epi32( xmm_sLTP_shp_Q14_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+ xmm_sLTP_shp_Q14_x2x0 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x2x0, xmm_gain_adj_Q16 );
+ xmm_sLTP_shp_Q14_x3x1 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x3x1, xmm_gain_adj_Q16 );
+
+ xmm_sLTP_shp_Q14_x2x0 = _mm_srli_epi64( xmm_sLTP_shp_Q14_x2x0, 16 );
+ xmm_sLTP_shp_Q14_x3x1 = _mm_slli_epi64( xmm_sLTP_shp_Q14_x3x1, 16 );
+
+ xmm_sLTP_shp_Q14_x2x0 = _mm_blend_epi16( xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1, 0xCC );
+
+ _mm_storeu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ), xmm_sLTP_shp_Q14_x2x0 );
+ }
+
+ for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+ NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+ }
+
+ /* Scale long-term prediction state */
+ if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+ }
+ }
+
+ NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 );
+
+ /* Scale short-term prediction and shaping states */
+ for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+ NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] );
+ }
+ for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+ NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] );
+ }
+ }
+}
diff --git a/external/opus-1.1.4/silk/x86/SigProc_FIX_sse.h b/external/opus-1.1.4/silk/x86/SigProc_FIX_sse.h
new file mode 100644
index 0000000..61efa8d
--- /dev/null
+++ b/external/opus-1.1.4/silk/x86/SigProc_FIX_sse.h
@@ -0,0 +1,94 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef SIGPROC_FIX_SSE_H
+#define SIGPROC_FIX_SSE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+void silk_burg_modified_sse4_1(
+ opus_int32 *res_nrg, /* O Residual energy */
+ opus_int *res_nrg_Q, /* O Residual energy Q value */
+ opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
+ const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
+ const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */
+ const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I Number of subframes stacked in x */
+ const opus_int D, /* I Order */
+ int arch /* I Run-time architecture */
+);
+
+#if defined(OPUS_X86_PRESUME_SSE4_1)
+#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \
+ ((void)(arch), silk_burg_modified_sse4_1(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch))
+
+#else
+
+extern void (*const SILK_BURG_MODIFIED_IMPL[OPUS_ARCHMASK + 1])(
+ opus_int32 *res_nrg, /* O Residual energy */
+ opus_int *res_nrg_Q, /* O Residual energy Q value */
+ opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
+ const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
+ const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */
+ const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I Number of subframes stacked in x */
+ const opus_int D, /* I Order */
+ int arch /* I Run-time architecture */);
+
+# define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \
+ ((*SILK_BURG_MODIFIED_IMPL[(arch) & OPUS_ARCHMASK])(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch))
+
+#endif
+
+opus_int64 silk_inner_prod16_aligned_64_sse4_1(
+ const opus_int16 *inVec1,
+ const opus_int16 *inVec2,
+ const opus_int len
+);
+
+
+#if defined(OPUS_X86_PRESUME_SSE4_1)
+
+#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \
+ ((void)(arch),silk_inner_prod16_aligned_64_sse4_1(inVec1, inVec2, len))
+
+#else
+
+extern opus_int64 (*const SILK_INNER_PROD16_ALIGNED_64_IMPL[OPUS_ARCHMASK + 1])(
+ const opus_int16 *inVec1,
+ const opus_int16 *inVec2,
+ const opus_int len);
+
+# define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \
+ ((*SILK_INNER_PROD16_ALIGNED_64_IMPL[(arch) & OPUS_ARCHMASK])(inVec1, inVec2, len))
+
+#endif
+#endif
+#endif
diff --git a/external/opus-1.1.4/silk/x86/VAD_sse.c b/external/opus-1.1.4/silk/x86/VAD_sse.c
new file mode 100644
index 0000000..4e90f44
--- /dev/null
+++ b/external/opus-1.1.4/silk/x86/VAD_sse.c
@@ -0,0 +1,277 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/* Weighting factors for tilt measure */
+static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 };
+
+/***************************************/
+/* Get the speech activity level in Q8 */
+/***************************************/
+opus_int silk_VAD_GetSA_Q8_sse4_1( /* O Return value, 0 if success */
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ const opus_int16 pIn[] /* I PCM input */
+)
+{
+ opus_int SA_Q15, pSNR_dB_Q7, input_tilt;
+ opus_int decimated_framelength1, decimated_framelength2;
+ opus_int decimated_framelength;
+ opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s;
+ opus_int32 sumSquared, smooth_coef_Q16;
+ opus_int16 HPstateTmp;
+ VARDECL( opus_int16, X );
+ opus_int32 Xnrg[ VAD_N_BANDS ];
+ opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ];
+ opus_int32 speech_nrg, x_tmp;
+ opus_int X_offset[ VAD_N_BANDS ];
+ opus_int ret = 0;
+ silk_VAD_state *psSilk_VAD = &psEncC->sVAD;
+
+ SAVE_STACK;
+
+ /* Safety checks */
+ silk_assert( VAD_N_BANDS == 4 );
+ silk_assert( MAX_FRAME_LENGTH >= psEncC->frame_length );
+ silk_assert( psEncC->frame_length <= 512 );
+ silk_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) );
+
+ /***********************/
+ /* Filter and Decimate */
+ /***********************/
+ decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 );
+ decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 );
+ decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 );
+ /* Decimate into 4 bands:
+ 0 L 3L L 3L 5L
+ - -- - -- --
+ 8 8 2 4 4
+
+ [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz |
+
+ They're arranged to allow the minimal ( frame_length / 4 ) extra
+ scratch space during the downsampling process */
+ X_offset[ 0 ] = 0;
+ X_offset[ 1 ] = decimated_framelength + decimated_framelength2;
+ X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength;
+ X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2;
+ ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 );
+
+ /* 0-8 kHz to 0-4 kHz and 4-8 kHz */
+ silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ],
+ X, &X[ X_offset[ 3 ] ], psEncC->frame_length );
+
+ /* 0-4 kHz to 0-2 kHz and 2-4 kHz */
+ silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ],
+ X, &X[ X_offset[ 2 ] ], decimated_framelength1 );
+
+ /* 0-2 kHz to 0-1 kHz and 1-2 kHz */
+ silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ],
+ X, &X[ X_offset[ 1 ] ], decimated_framelength2 );
+
+ /*********************************************/
+ /* HP filter on lowest band (differentiator) */
+ /*********************************************/
+ X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 );
+ HPstateTmp = X[ decimated_framelength - 1 ];
+ for( i = decimated_framelength - 1; i > 0; i-- ) {
+ X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 );
+ X[ i ] -= X[ i - 1 ];
+ }
+ X[ 0 ] -= psSilk_VAD->HPstate;
+ psSilk_VAD->HPstate = HPstateTmp;
+
+ /*************************************/
+ /* Calculate the energy in each band */
+ /*************************************/
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* Find the decimated framelength in the non-uniformly divided bands */
+ decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) );
+
+ /* Split length into subframe lengths */
+ dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 );
+ dec_subframe_offset = 0;
+
+ /* Compute energy per sub-frame */
+ /* initialize with summed energy of last subframe */
+ Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ];
+ for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) {
+ __m128i xmm_X, xmm_acc;
+ sumSquared = 0;
+
+ xmm_acc = _mm_setzero_si128();
+
+ for( i = 0; i < dec_subframe_length - 7; i += 8 )
+ {
+ xmm_X = _mm_loadu_si128( (__m128i *)&(X[ X_offset[ b ] + i + dec_subframe_offset ] ) );
+ xmm_X = _mm_srai_epi16( xmm_X, 3 );
+ xmm_X = _mm_madd_epi16( xmm_X, xmm_X );
+ xmm_acc = _mm_add_epi32( xmm_acc, xmm_X );
+ }
+
+ xmm_acc = _mm_add_epi32( xmm_acc, _mm_unpackhi_epi64( xmm_acc, xmm_acc ) );
+ xmm_acc = _mm_add_epi32( xmm_acc, _mm_shufflelo_epi16( xmm_acc, 0x0E ) );
+
+ sumSquared += _mm_cvtsi128_si32( xmm_acc );
+
+ for( ; i < dec_subframe_length; i++ ) {
+ /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */
+ /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */
+ x_tmp = silk_RSHIFT(
+ X[ X_offset[ b ] + i + dec_subframe_offset ], 3 );
+ sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp );
+
+ /* Safety check */
+ silk_assert( sumSquared >= 0 );
+ }
+
+ /* Add/saturate summed energy of current subframe */
+ if( s < VAD_INTERNAL_SUBFRAMES - 1 ) {
+ Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared );
+ } else {
+ /* Look-ahead subframe */
+ Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) );
+ }
+
+ dec_subframe_offset += dec_subframe_length;
+ }
+ psSilk_VAD->XnrgSubfr[ b ] = sumSquared;
+ }
+
+ /********************/
+ /* Noise estimation */
+ /********************/
+ silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD );
+
+ /***********************************************/
+ /* Signal-plus-noise to noise ratio estimation */
+ /***********************************************/
+ sumSquared = 0;
+ input_tilt = 0;
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ];
+ if( speech_nrg > 0 ) {
+ /* Divide, with sufficient resolution */
+ if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) {
+ NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 );
+ } else {
+ NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 );
+ }
+
+ /* Convert to log domain */
+ SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128;
+
+ /* Sum-of-squares */
+ sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */
+
+ /* Tilt measure */
+ if( speech_nrg < ( (opus_int32)1 << 20 ) ) {
+ /* Scale down SNR value for small subband speech energies */
+ SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 );
+ }
+ input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 );
+ } else {
+ NrgToNoiseRatio_Q8[ b ] = 256;
+ }
+ }
+
+ /* Mean-of-squares */
+ sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */
+
+ /* Root-mean-square approximation, scale to dBs, and write to output pointer */
+ pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */
+
+ /*********************************/
+ /* Speech Probability Estimation */
+ /*********************************/
+ SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 );
+
+ /**************************/
+ /* Frequency Tilt Measure */
+ /**************************/
+ psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 );
+
+ /**************************************************/
+ /* Scale the sigmoid output based on power levels */
+ /**************************************************/
+ speech_nrg = 0;
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* Accumulate signal-without-noise energies, higher frequency bands have more weight */
+ speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 );
+ }
+
+ /* Power scaling */
+ if( speech_nrg <= 0 ) {
+ SA_Q15 = silk_RSHIFT( SA_Q15, 1 );
+ } else if( speech_nrg < 32768 ) {
+ if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
+ speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 16 );
+ } else {
+ speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 15 );
+ }
+
+ /* square-root */
+ speech_nrg = silk_SQRT_APPROX( speech_nrg );
+ SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 );
+ }
+
+ /* Copy the resulting speech activity in Q8 */
+ psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX );
+
+ /***********************************/
+ /* Energy Level and SNR estimation */
+ /***********************************/
+ /* Smoothing coefficient */
+ smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) );
+
+ if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
+ smooth_coef_Q16 >>= 1;
+ }
+
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* compute smoothed energy-to-noise ratio per band */
+ psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ],
+ NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 );
+
+ /* signal to noise ratio in dB per band */
+ SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 );
+ /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */
+ psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) );
+ }
+
+ RESTORE_STACK;
+ return( ret );
+}
diff --git a/external/opus-1.1.4/silk/x86/VQ_WMat_EC_sse.c b/external/opus-1.1.4/silk/x86/VQ_WMat_EC_sse.c
new file mode 100644
index 0000000..74d6c6d
--- /dev/null
+++ b/external/opus-1.1.4/silk/x86/VQ_WMat_EC_sse.c
@@ -0,0 +1,142 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+#include "main.h"
+#include "celt/x86/x86cpu.h"
+
+/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */
+void silk_VQ_WMat_EC_sse4_1(
+ opus_int8 *ind, /* O index of best codebook vector */
+ opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */
+ opus_int *gain_Q7, /* O sum of absolute LTP coefficients */
+ const opus_int16 *in_Q14, /* I input vector to be quantized */
+ const opus_int32 *W_Q18, /* I weighting matrix */
+ const opus_int8 *cb_Q7, /* I codebook */
+ const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */
+ const opus_uint8 *cl_Q5, /* I code length for each codebook vector */
+ const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */
+ const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ opus_int L /* I number of vectors in codebook */
+)
+{
+ opus_int k, gain_tmp_Q7;
+ const opus_int8 *cb_row_Q7;
+ opus_int16 diff_Q14[ 5 ];
+ opus_int32 sum1_Q14, sum2_Q16;
+
+ __m128i C_tmp1, C_tmp2, C_tmp3, C_tmp4, C_tmp5;
+ /* Loop over codebook */
+ *rate_dist_Q14 = silk_int32_MAX;
+ cb_row_Q7 = cb_Q7;
+ for( k = 0; k < L; k++ ) {
+ gain_tmp_Q7 = cb_gain_Q7[k];
+
+ diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 );
+
+ C_tmp1 = OP_CVTEPI16_EPI32_M64( &in_Q14[ 1 ] );
+ C_tmp2 = OP_CVTEPI8_EPI32_M32( &cb_row_Q7[ 1 ] );
+ C_tmp2 = _mm_slli_epi32( C_tmp2, 7 );
+ C_tmp1 = _mm_sub_epi32( C_tmp1, C_tmp2 );
+
+ diff_Q14[ 1 ] = _mm_extract_epi16( C_tmp1, 0 );
+ diff_Q14[ 2 ] = _mm_extract_epi16( C_tmp1, 2 );
+ diff_Q14[ 3 ] = _mm_extract_epi16( C_tmp1, 4 );
+ diff_Q14[ 4 ] = _mm_extract_epi16( C_tmp1, 6 );
+
+ /* Weighted rate */
+ sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] );
+
+ /* Penalty for too large gain */
+ sum1_Q14 = silk_ADD_LSHIFT32( sum1_Q14, silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 10 );
+
+ silk_assert( sum1_Q14 >= 0 );
+
+ /* first row of W_Q18 */
+ C_tmp3 = _mm_loadu_si128( (__m128i *)(&W_Q18[ 1 ] ) );
+ C_tmp4 = _mm_mul_epi32( C_tmp3, C_tmp1 );
+ C_tmp4 = _mm_srli_si128( C_tmp4, 2 );
+
+ C_tmp1 = _mm_shuffle_epi32( C_tmp1, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* shift right 4 bytes */
+ C_tmp3 = _mm_shuffle_epi32( C_tmp3, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* shift right 4 bytes */
+
+ C_tmp5 = _mm_mul_epi32( C_tmp3, C_tmp1 );
+ C_tmp5 = _mm_srli_si128( C_tmp5, 2 );
+
+ C_tmp5 = _mm_add_epi32( C_tmp4, C_tmp5 );
+ C_tmp5 = _mm_slli_epi32( C_tmp5, 1 );
+
+ C_tmp5 = _mm_add_epi32( C_tmp5, _mm_shuffle_epi32( C_tmp5, _MM_SHUFFLE( 0, 0, 0, 2 ) ) );
+ sum2_Q16 = _mm_cvtsi128_si32( C_tmp5 );
+
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14[ 0 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 0 ] );
+
+ /* second row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 7 ], diff_Q14[ 2 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 8 ], diff_Q14[ 3 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14[ 4 ] );
+ sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 6 ], diff_Q14[ 1 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 1 ] );
+
+ /* third row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 13 ], diff_Q14[ 3 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] );
+ sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 2 ] );
+
+ /* fourth row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 19 ], diff_Q14[ 4 ] );
+ sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 3 ] );
+
+ /* last row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 24 ], diff_Q14[ 4 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 4 ] );
+
+ silk_assert( sum1_Q14 >= 0 );
+
+ /* find best */
+ if( sum1_Q14 < *rate_dist_Q14 ) {
+ *rate_dist_Q14 = sum1_Q14;
+ *ind = (opus_int8)k;
+ *gain_Q7 = gain_tmp_Q7;
+ }
+
+ /* Go to next cbk vector */
+ cb_row_Q7 += LTP_ORDER;
+ }
+}
diff --git a/external/opus-1.1.4/silk/x86/main_sse.h b/external/opus-1.1.4/silk/x86/main_sse.h
new file mode 100644
index 0000000..d8d6131
--- /dev/null
+++ b/external/opus-1.1.4/silk/x86/main_sse.h
@@ -0,0 +1,277 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifndef MAIN_SSE_H
+#define MAIN_SSE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+# if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+
+# define OVERRIDE_silk_VQ_WMat_EC
+
+void silk_VQ_WMat_EC_sse4_1(
+ opus_int8 *ind, /* O index of best codebook vector */
+ opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */
+ opus_int *gain_Q7, /* O sum of absolute LTP coefficients */
+ const opus_int16 *in_Q14, /* I input vector to be quantized */
+ const opus_int32 *W_Q18, /* I weighting matrix */
+ const opus_int8 *cb_Q7, /* I codebook */
+ const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */
+ const opus_uint8 *cl_Q5, /* I code length for each codebook vector */
+ const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */
+ const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ opus_int L /* I number of vectors in codebook */
+);
+
+#if defined OPUS_X86_PRESUME_SSE4_1
+
+#define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+ mu_Q9, max_gain_Q7, L, arch) \
+ ((void)(arch),silk_VQ_WMat_EC_sse4_1(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+ mu_Q9, max_gain_Q7, L))
+
+#else
+
+extern void (*const SILK_VQ_WMAT_EC_IMPL[OPUS_ARCHMASK + 1])(
+ opus_int8 *ind, /* O index of best codebook vector */
+ opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */
+ opus_int *gain_Q7, /* O sum of absolute LTP coefficients */
+ const opus_int16 *in_Q14, /* I input vector to be quantized */
+ const opus_int32 *W_Q18, /* I weighting matrix */
+ const opus_int8 *cb_Q7, /* I codebook */
+ const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */
+ const opus_uint8 *cl_Q5, /* I code length for each codebook vector */
+ const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */
+ const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ opus_int L /* I number of vectors in codebook */
+);
+
+# define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+ mu_Q9, max_gain_Q7, L, arch) \
+ ((*SILK_VQ_WMAT_EC_IMPL[(arch) & OPUS_ARCHMASK])(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+ mu_Q9, max_gain_Q7, L))
+
+#endif
+
+# define OVERRIDE_silk_NSQ
+
+void silk_NSQ_sse4_1(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+);
+
+#if defined OPUS_X86_PRESUME_SSE4_1
+
+#define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+ ((void)(arch),silk_NSQ_sse4_1(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+
+#else
+
+extern void (*const SILK_NSQ_IMPL[OPUS_ARCHMASK + 1])(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+);
+
+# define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+ ((*SILK_NSQ_IMPL[(arch) & OPUS_ARCHMASK])(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+
+#endif
+
+# define OVERRIDE_silk_NSQ_del_dec
+
+void silk_NSQ_del_dec_sse4_1(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+);
+
+#if defined OPUS_X86_PRESUME_SSE4_1
+
+#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+ ((void)(arch),silk_NSQ_del_dec_sse4_1(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+
+#else
+
+extern void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+);
+
+# define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+ ((*SILK_NSQ_DEL_DEC_IMPL[(arch) & OPUS_ARCHMASK])(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+ HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+
+#endif
+
+void silk_noise_shape_quantizer(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_sc_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP state */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int shapingLPCOrder, /* I Noise shaping AR filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ int arch /* I Architecture */
+);
+
+/**************************/
+/* Noise level estimation */
+/**************************/
+void silk_VAD_GetNoiseLevels(
+ const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+);
+
+# define OVERRIDE_silk_VAD_GetSA_Q8
+
+opus_int silk_VAD_GetSA_Q8_sse4_1(
+ silk_encoder_state *psEnC,
+ const opus_int16 pIn[]
+);
+
+#if defined(OPUS_X86_PRESUME_SSE4_1)
+#define silk_VAD_GetSA_Q8(psEnC, pIn, arch) ((void)(arch),silk_VAD_GetSA_Q8_sse4_1(psEnC, pIn))
+
+#else
+
+# define silk_VAD_GetSA_Q8(psEnC, pIn, arch) \
+ ((*SILK_VAD_GETSA_Q8_IMPL[(arch) & OPUS_ARCHMASK])(psEnC, pIn))
+
+extern opus_int (*const SILK_VAD_GETSA_Q8_IMPL[OPUS_ARCHMASK + 1])(
+ silk_encoder_state *psEnC,
+ const opus_int16 pIn[]);
+
+# define OVERRIDE_silk_warped_LPC_analysis_filter_FIX
+
+#endif
+
+void silk_warped_LPC_analysis_filter_FIX_sse4_1(
+ opus_int32 state[], /* I/O State [order + 1] */
+ opus_int32 res_Q2[], /* O Residual signal [length] */
+ const opus_int16 coef_Q13[], /* I Coefficients [order] */
+ const opus_int16 input[], /* I Input signal [length] */
+ const opus_int16 lambda_Q16, /* I Warping factor */
+ const opus_int length, /* I Length of input signal */
+ const opus_int order /* I Filter order (even) */
+);
+
+#if defined(OPUS_X86_PRESUME_SSE4_1)
+#define silk_warped_LPC_analysis_filter_FIX(state, res_Q2, coef_Q13, input, lambda_Q16, length, order, arch) \
+ ((void)(arch),silk_warped_LPC_analysis_filter_FIX_c(state, res_Q2, coef_Q13, input, lambda_Q16, length, order))
+
+#else
+
+extern void (*const SILK_WARPED_LPC_ANALYSIS_FILTER_FIX_IMPL[OPUS_ARCHMASK + 1])(
+ opus_int32 state[], /* I/O State [order + 1] */
+ opus_int32 res_Q2[], /* O Residual signal [length] */
+ const opus_int16 coef_Q13[], /* I Coefficients [order] */
+ const opus_int16 input[], /* I Input signal [length] */
+ const opus_int16 lambda_Q16, /* I Warping factor */
+ const opus_int length, /* I Length of input signal */
+ const opus_int order /* I Filter order (even) */
+);
+
+# define silk_warped_LPC_analysis_filter_FIX(state, res_Q2, coef_Q13, input, lambda_Q16, length, order, arch) \
+ ((*SILK_WARPED_LPC_ANALYSIS_FILTER_FIX_IMPL[(arch) & OPUS_ARCHMASK])(state, res_Q2, coef_Q13, input, lambda_Q16, length, order))
+
+#endif
+
+# endif
+#endif
diff --git a/external/opus-1.1.4/silk/x86/x86_silk_map.c b/external/opus-1.1.4/silk/x86/x86_silk_map.c
new file mode 100644
index 0000000..818841f
--- /dev/null
+++ b/external/opus-1.1.4/silk/x86/x86_silk_map.c
@@ -0,0 +1,174 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include "celt/x86/x86cpu.h"
+#include "structs.h"
+#include "SigProc_FIX.h"
+#include "pitch.h"
+#include "main.h"
+
+#if !defined(OPUS_X86_PRESUME_SSE4_1)
+
+#if defined(FIXED_POINT)
+
+#include "fixed/main_FIX.h"
+
+opus_int64 (*const SILK_INNER_PROD16_ALIGNED_64_IMPL[ OPUS_ARCHMASK + 1 ] )(
+ const opus_int16 *inVec1,
+ const opus_int16 *inVec2,
+ const opus_int len
+) = {
+ silk_inner_prod16_aligned_64_c, /* non-sse */
+ silk_inner_prod16_aligned_64_c,
+ silk_inner_prod16_aligned_64_c,
+ MAY_HAVE_SSE4_1( silk_inner_prod16_aligned_64 ), /* sse4.1 */
+ MAY_HAVE_SSE4_1( silk_inner_prod16_aligned_64 ) /* avx */
+};
+
+#endif
+
+opus_int (*const SILK_VAD_GETSA_Q8_IMPL[ OPUS_ARCHMASK + 1 ] )(
+ silk_encoder_state *psEncC,
+ const opus_int16 pIn[]
+) = {
+ silk_VAD_GetSA_Q8_c, /* non-sse */
+ silk_VAD_GetSA_Q8_c,
+ silk_VAD_GetSA_Q8_c,
+ MAY_HAVE_SSE4_1( silk_VAD_GetSA_Q8 ), /* sse4.1 */
+ MAY_HAVE_SSE4_1( silk_VAD_GetSA_Q8 ) /* avx */
+};
+
+void (*const SILK_NSQ_IMPL[ OPUS_ARCHMASK + 1 ] )(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+) = {
+ silk_NSQ_c, /* non-sse */
+ silk_NSQ_c,
+ silk_NSQ_c,
+ MAY_HAVE_SSE4_1( silk_NSQ ), /* sse4.1 */
+ MAY_HAVE_SSE4_1( silk_NSQ ) /* avx */
+};
+
+void (*const SILK_VQ_WMAT_EC_IMPL[ OPUS_ARCHMASK + 1 ] )(
+ opus_int8 *ind, /* O index of best codebook vector */
+ opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */
+ opus_int *gain_Q7, /* O sum of absolute LTP coefficients */
+ const opus_int16 *in_Q14, /* I input vector to be quantized */
+ const opus_int32 *W_Q18, /* I weighting matrix */
+ const opus_int8 *cb_Q7, /* I codebook */
+ const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */
+ const opus_uint8 *cl_Q5, /* I code length for each codebook vector */
+ const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */
+ const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ opus_int L /* I number of vectors in codebook */
+) = {
+ silk_VQ_WMat_EC_c, /* non-sse */
+ silk_VQ_WMat_EC_c,
+ silk_VQ_WMat_EC_c,
+ MAY_HAVE_SSE4_1( silk_VQ_WMat_EC ), /* sse4.1 */
+ MAY_HAVE_SSE4_1( silk_VQ_WMat_EC ) /* avx */
+};
+
+void (*const SILK_NSQ_DEL_DEC_IMPL[ OPUS_ARCHMASK + 1 ] )(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+) = {
+ silk_NSQ_del_dec_c, /* non-sse */
+ silk_NSQ_del_dec_c,
+ silk_NSQ_del_dec_c,
+ MAY_HAVE_SSE4_1( silk_NSQ_del_dec ), /* sse4.1 */
+ MAY_HAVE_SSE4_1( silk_NSQ_del_dec ) /* avx */
+};
+
+#if defined(FIXED_POINT)
+
+void (*const SILK_WARPED_LPC_ANALYSIS_FILTER_FIX_IMPL[ OPUS_ARCHMASK + 1 ] )(
+ opus_int32 state[], /* I/O State [order + 1] */
+ opus_int32 res_Q2[], /* O Residual signal [length] */
+ const opus_int16 coef_Q13[], /* I Coefficients [order] */
+ const opus_int16 input[], /* I Input signal [length] */
+ const opus_int16 lambda_Q16, /* I Warping factor */
+ const opus_int length, /* I Length of input signal */
+ const opus_int order /* I Filter order (even) */
+) = {
+ silk_warped_LPC_analysis_filter_FIX_c, /* non-sse */
+ silk_warped_LPC_analysis_filter_FIX_c,
+ silk_warped_LPC_analysis_filter_FIX_c,
+ MAY_HAVE_SSE4_1( silk_warped_LPC_analysis_filter_FIX ), /* sse4.1 */
+ MAY_HAVE_SSE4_1( silk_warped_LPC_analysis_filter_FIX ) /* avx */
+};
+
+void (*const SILK_BURG_MODIFIED_IMPL[ OPUS_ARCHMASK + 1 ] )(
+ opus_int32 *res_nrg, /* O Residual energy */
+ opus_int *res_nrg_Q, /* O Residual energy Q value */
+ opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
+ const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
+ const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */
+ const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I Number of subframes stacked in x */
+ const opus_int D, /* I Order */
+ int arch /* I Run-time architecture */
+) = {
+ silk_burg_modified_c, /* non-sse */
+ silk_burg_modified_c,
+ silk_burg_modified_c,
+ MAY_HAVE_SSE4_1( silk_burg_modified ), /* sse4.1 */
+ MAY_HAVE_SSE4_1( silk_burg_modified ) /* avx */
+};
+
+#endif
+#endif
diff --git a/external/opus-1.1.4/src/CMakeLists.txt b/external/opus-1.1.4/src/CMakeLists.txt
new file mode 100644
index 0000000..59dafa1
--- /dev/null
+++ b/external/opus-1.1.4/src/CMakeLists.txt
@@ -0,0 +1,40 @@
+# CMakeLists.txt in src
+
+SET(OPUS_HEADERS
+ ../include/opus.h
+ ../include/opus_multistream.h
+ analysis.h
+ mlp.h
+ opus_private.h
+ tansig_table.h
+ )
+
+add_library (
+ opus STATIC
+ ${OPUS_HEADERS}
+ analysis.c
+ analysis.h
+ mlp.c
+ mlp.h
+ mlp_data.c
+ opus.c
+ opus_decoder.c
+ opus_encoder.c
+ opus_multistream.c
+ opus_multistream_decoder.c
+ opus_multistream_encoder.c
+ opus_private.h
+ repacketizer.c
+ tansig_table.h
+ )
+
+INCLUDE_DIRECTORIES(
+ ${OPUS_INCLUDES_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../celt
+ ${CMAKE_CURRENT_SOURCE_DIR}/../silk
+ ${CMAKE_CURRENT_SOURCE_DIR}/../silk/fixed
+ ${CMAKE_CURRENT_SOURCE_DIR}/../silk/float
+ )
+
+ADD_LIBRARY( opus STATIC ${OPUS_HEADERS} ${OPUS_SRCS})
diff --git a/external/opus-1.1.4/src/analysis.c b/external/opus-1.1.4/src/analysis.c
new file mode 100644
index 0000000..663431a
--- /dev/null
+++ b/external/opus-1.1.4/src/analysis.c
@@ -0,0 +1,672 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 FOUNDATION OR
+ CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "kiss_fft.h"
+#include "celt.h"
+#include "modes.h"
+#include "arch.h"
+#include "quant_bands.h"
+#include <stdio.h>
+#include "analysis.h"
+#include "mlp.h"
+#include "stack_alloc.h"
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+static const float dct_table[128] = {
+ 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
+ 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
+ 0.351851f, 0.338330f, 0.311806f, 0.273300f, 0.224292f, 0.166664f, 0.102631f, 0.034654f,
+ -0.034654f,-0.102631f,-0.166664f,-0.224292f,-0.273300f,-0.311806f,-0.338330f,-0.351851f,
+ 0.346760f, 0.293969f, 0.196424f, 0.068975f,-0.068975f,-0.196424f,-0.293969f,-0.346760f,
+ -0.346760f,-0.293969f,-0.196424f,-0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.346760f,
+ 0.338330f, 0.224292f, 0.034654f,-0.166664f,-0.311806f,-0.351851f,-0.273300f,-0.102631f,
+ 0.102631f, 0.273300f, 0.351851f, 0.311806f, 0.166664f,-0.034654f,-0.224292f,-0.338330f,
+ 0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
+ 0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
+ 0.311806f, 0.034654f,-0.273300f,-0.338330f,-0.102631f, 0.224292f, 0.351851f, 0.166664f,
+ -0.166664f,-0.351851f,-0.224292f, 0.102631f, 0.338330f, 0.273300f,-0.034654f,-0.311806f,
+ 0.293969f,-0.068975f,-0.346760f,-0.196424f, 0.196424f, 0.346760f, 0.068975f,-0.293969f,
+ -0.293969f, 0.068975f, 0.346760f, 0.196424f,-0.196424f,-0.346760f,-0.068975f, 0.293969f,
+ 0.273300f,-0.166664f,-0.338330f, 0.034654f, 0.351851f, 0.102631f,-0.311806f,-0.224292f,
+ 0.224292f, 0.311806f,-0.102631f,-0.351851f,-0.034654f, 0.338330f, 0.166664f,-0.273300f,
+};
+
+static const float analysis_window[240] = {
+ 0.000043f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f,
+ 0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f,
+ 0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.020590f, 0.022490f, 0.024472f,
+ 0.026535f, 0.028679f, 0.030904f, 0.033210f, 0.035595f, 0.038060f, 0.040604f, 0.043227f,
+ 0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f,
+ 0.070297f, 0.073680f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f,
+ 0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.124080f, 0.128428f,
+ 0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.160600f, 0.165435f,
+ 0.170327f, 0.175276f, 0.180280f, 0.185340f, 0.190453f, 0.195619f, 0.200838f, 0.206107f,
+ 0.211427f, 0.216797f, 0.222215f, 0.227680f, 0.233193f, 0.238751f, 0.244353f, 0.250000f,
+ 0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.290670f, 0.296632f,
+ 0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.339280f, 0.345492f,
+ 0.351729f, 0.357992f, 0.364280f, 0.370590f, 0.376923f, 0.383277f, 0.389651f, 0.396044f,
+ 0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f,
+ 0.454249f, 0.460770f, 0.467298f, 0.473832f, 0.480370f, 0.486912f, 0.493455f, 0.500000f,
+ 0.506545f, 0.513088f, 0.519630f, 0.526168f, 0.532702f, 0.539230f, 0.545751f, 0.552264f,
+ 0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f,
+ 0.610349f, 0.616723f, 0.623077f, 0.629410f, 0.635720f, 0.642008f, 0.648271f, 0.654508f,
+ 0.660720f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f,
+ 0.709330f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.750000f,
+ 0.755647f, 0.761249f, 0.766807f, 0.772320f, 0.777785f, 0.783203f, 0.788573f, 0.793893f,
+ 0.799162f, 0.804381f, 0.809547f, 0.814660f, 0.819720f, 0.824724f, 0.829673f, 0.834565f,
+ 0.839400f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f,
+ 0.875920f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f,
+ 0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.926320f, 0.929703f, 0.933013f,
+ 0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f,
+ 0.959396f, 0.961940f, 0.964405f, 0.966790f, 0.969096f, 0.971321f, 0.973465f, 0.975528f,
+ 0.977510f, 0.979410f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f,
+ 0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f,
+ 0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1.000000f,
+};
+
+static const int tbands[NB_TBANDS+1] = {
+ 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120
+};
+
+static const int extra_bands[NB_TOT_BANDS+1] = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 160, 200
+};
+
+/*static const float tweight[NB_TBANDS+1] = {
+ .3, .4, .5, .6, .7, .8, .9, 1., 1., 1., 1., 1., 1., 1., .8, .7, .6, .5
+};*/
+
+#define NB_TONAL_SKIP_BANDS 9
+
+#define cA 0.43157974f
+#define cB 0.67848403f
+#define cC 0.08595542f
+#define cE ((float)M_PI/2)
+static OPUS_INLINE float fast_atan2f(float y, float x) {
+ float x2, y2;
+ /* Should avoid underflow on the values we'll get */
+ if (ABS16(x)+ABS16(y)<1e-9f)
+ {
+ x*=1e12f;
+ y*=1e12f;
+ }
+ x2 = x*x;
+ y2 = y*y;
+ if(x2<y2){
+ float den = (y2 + cB*x2) * (y2 + cC*x2);
+ if (den!=0)
+ return -x*y*(y2 + cA*x2) / den + (y<0 ? -cE : cE);
+ else
+ return (y<0 ? -cE : cE);
+ }else{
+ float den = (x2 + cB*y2) * (x2 + cC*y2);
+ if (den!=0)
+ return x*y*(x2 + cA*y2) / den + (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE);
+ else
+ return (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE);
+ }
+}
+
+void tonality_analysis_init(TonalityAnalysisState *tonal)
+{
+ /* Initialize reusable fields. */
+ tonal->arch = opus_select_arch();
+ /* Clear remaining fields. */
+ tonality_analysis_reset(tonal);
+}
+
+void tonality_analysis_reset(TonalityAnalysisState *tonal)
+{
+ /* Clear non-reusable fields. */
+ char *start = (char*)&tonal->TONALITY_ANALYSIS_RESET_START;
+ OPUS_CLEAR(start, sizeof(TonalityAnalysisState) - (start - (char*)tonal));
+}
+
+void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len)
+{
+ int pos;
+ int curr_lookahead;
+ float psum;
+ int i;
+
+ pos = tonal->read_pos;
+ curr_lookahead = tonal->write_pos-tonal->read_pos;
+ if (curr_lookahead<0)
+ curr_lookahead += DETECT_SIZE;
+
+ if (len > 480 && pos != tonal->write_pos)
+ {
+ pos++;
+ if (pos==DETECT_SIZE)
+ pos=0;
+ }
+ if (pos == tonal->write_pos)
+ pos--;
+ if (pos<0)
+ pos = DETECT_SIZE-1;
+ OPUS_COPY(info_out, &tonal->info[pos], 1);
+ tonal->read_subframe += len/120;
+ while (tonal->read_subframe>=4)
+ {
+ tonal->read_subframe -= 4;
+ tonal->read_pos++;
+ }
+ if (tonal->read_pos>=DETECT_SIZE)
+ tonal->read_pos-=DETECT_SIZE;
+
+ /* Compensate for the delay in the features themselves.
+ FIXME: Need a better estimate the 10 I just made up */
+ curr_lookahead = IMAX(curr_lookahead-10, 0);
+
+ psum=0;
+ /* Summing the probability of transition patterns that involve music at
+ time (DETECT_SIZE-curr_lookahead-1) */
+ for (i=0;i<DETECT_SIZE-curr_lookahead;i++)
+ psum += tonal->pmusic[i];
+ for (;i<DETECT_SIZE;i++)
+ psum += tonal->pspeech[i];
+ psum = psum*tonal->music_confidence + (1-psum)*tonal->speech_confidence;
+ /*printf("%f %f %f\n", psum, info_out->music_prob, info_out->tonality);*/
+
+ info_out->music_prob = psum;
+}
+
+static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix)
+{
+ int i, b;
+ const kiss_fft_state *kfft;
+ VARDECL(kiss_fft_cpx, in);
+ VARDECL(kiss_fft_cpx, out);
+ int N = 480, N2=240;
+ float * OPUS_RESTRICT A = tonal->angle;
+ float * OPUS_RESTRICT dA = tonal->d_angle;
+ float * OPUS_RESTRICT d2A = tonal->d2_angle;
+ VARDECL(float, tonality);
+ VARDECL(float, noisiness);
+ float band_tonality[NB_TBANDS];
+ float logE[NB_TBANDS];
+ float BFCC[8];
+ float features[25];
+ float frame_tonality;
+ float max_frame_tonality;
+ /*float tw_sum=0;*/
+ float frame_noisiness;
+ const float pi4 = (float)(M_PI*M_PI*M_PI*M_PI);
+ float slope=0;
+ float frame_stationarity;
+ float relativeE;
+ float frame_probs[2];
+ float alpha, alphaE, alphaE2;
+ float frame_loudness;
+ float bandwidth_mask;
+ int bandwidth=0;
+ float maxE = 0;
+ float noise_floor;
+ int remaining;
+ AnalysisInfo *info;
+ SAVE_STACK;
+
+ tonal->last_transition++;
+ alpha = 1.f/IMIN(20, 1+tonal->count);
+ alphaE = 1.f/IMIN(50, 1+tonal->count);
+ alphaE2 = 1.f/IMIN(1000, 1+tonal->count);
+
+ if (tonal->count<4)
+ tonal->music_prob = .5;
+ kfft = celt_mode->mdct.kfft[0];
+ if (tonal->count==0)
+ tonal->mem_fill = 240;
+ downmix(x, &tonal->inmem[tonal->mem_fill], IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C);
+ if (tonal->mem_fill+len < ANALYSIS_BUF_SIZE)
+ {
+ tonal->mem_fill += len;
+ /* Don't have enough to update the analysis */
+ RESTORE_STACK;
+ return;
+ }
+ info = &tonal->info[tonal->write_pos++];
+ if (tonal->write_pos>=DETECT_SIZE)
+ tonal->write_pos-=DETECT_SIZE;
+
+ ALLOC(in, 480, kiss_fft_cpx);
+ ALLOC(out, 480, kiss_fft_cpx);
+ ALLOC(tonality, 240, float);
+ ALLOC(noisiness, 240, float);
+ for (i=0;i<N2;i++)
+ {
+ float w = analysis_window[i];
+ in[i].r = (kiss_fft_scalar)(w*tonal->inmem[i]);
+ in[i].i = (kiss_fft_scalar)(w*tonal->inmem[N2+i]);
+ in[N-i-1].r = (kiss_fft_scalar)(w*tonal->inmem[N-i-1]);
+ in[N-i-1].i = (kiss_fft_scalar)(w*tonal->inmem[N+N2-i-1]);
+ }
+ OPUS_MOVE(tonal->inmem, tonal->inmem+ANALYSIS_BUF_SIZE-240, 240);
+ remaining = len - (ANALYSIS_BUF_SIZE-tonal->mem_fill);
+ downmix(x, &tonal->inmem[240], remaining, offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C);
+ tonal->mem_fill = 240 + remaining;
+ opus_fft(kfft, in, out, tonal->arch);
+#ifndef FIXED_POINT
+ /* If there's any NaN on the input, the entire output will be NaN, so we only need to check one value. */
+ if (celt_isnan(out[0].r))
+ {
+ info->valid = 0;
+ RESTORE_STACK;
+ return;
+ }
+#endif
+
+ for (i=1;i<N2;i++)
+ {
+ float X1r, X2r, X1i, X2i;
+ float angle, d_angle, d2_angle;
+ float angle2, d_angle2, d2_angle2;
+ float mod1, mod2, avg_mod;
+ X1r = (float)out[i].r+out[N-i].r;
+ X1i = (float)out[i].i-out[N-i].i;
+ X2r = (float)out[i].i+out[N-i].i;
+ X2i = (float)out[N-i].r-out[i].r;
+
+ angle = (float)(.5f/M_PI)*fast_atan2f(X1i, X1r);
+ d_angle = angle - A[i];
+ d2_angle = d_angle - dA[i];
+
+ angle2 = (float)(.5f/M_PI)*fast_atan2f(X2i, X2r);
+ d_angle2 = angle2 - angle;
+ d2_angle2 = d_angle2 - d_angle;
+
+ mod1 = d2_angle - (float)floor(.5+d2_angle);
+ noisiness[i] = ABS16(mod1);
+ mod1 *= mod1;
+ mod1 *= mod1;
+
+ mod2 = d2_angle2 - (float)floor(.5+d2_angle2);
+ noisiness[i] += ABS16(mod2);
+ mod2 *= mod2;
+ mod2 *= mod2;
+
+ avg_mod = .25f*(d2A[i]+2.f*mod1+mod2);
+ tonality[i] = 1.f/(1.f+40.f*16.f*pi4*avg_mod)-.015f;
+
+ A[i] = angle2;
+ dA[i] = d_angle2;
+ d2A[i] = mod2;
+ }
+
+ frame_tonality = 0;
+ max_frame_tonality = 0;
+ /*tw_sum = 0;*/
+ info->activity = 0;
+ frame_noisiness = 0;
+ frame_stationarity = 0;
+ if (!tonal->count)
+ {
+ for (b=0;b<NB_TBANDS;b++)
+ {
+ tonal->lowE[b] = 1e10;
+ tonal->highE[b] = -1e10;
+ }
+ }
+ relativeE = 0;
+ frame_loudness = 0;
+ for (b=0;b<NB_TBANDS;b++)
+ {
+ float E=0, tE=0, nE=0;
+ float L1, L2;
+ float stationarity;
+ for (i=tbands[b];i<tbands[b+1];i++)
+ {
+ float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
+ + out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
+#ifdef FIXED_POINT
+ /* FIXME: It's probably best to change the BFCC filter initial state instead */
+ binE *= 5.55e-17f;
+#endif
+ E += binE;
+ tE += binE*tonality[i];
+ nE += binE*2.f*(.5f-noisiness[i]);
+ }
+#ifndef FIXED_POINT
+ /* Check for extreme band energies that could cause NaNs later. */
+ if (!(E<1e9f) || celt_isnan(E))
+ {
+ info->valid = 0;
+ RESTORE_STACK;
+ return;
+ }
+#endif
+
+ tonal->E[tonal->E_count][b] = E;
+ frame_noisiness += nE/(1e-15f+E);
+
+ frame_loudness += (float)sqrt(E+1e-10f);
+ logE[b] = (float)log(E+1e-10f);
+ tonal->lowE[b] = MIN32(logE[b], tonal->lowE[b]+.01f);
+ tonal->highE[b] = MAX32(logE[b], tonal->highE[b]-.1f);
+ if (tonal->highE[b] < tonal->lowE[b]+1.f)
+ {
+ tonal->highE[b]+=.5f;
+ tonal->lowE[b]-=.5f;
+ }
+ relativeE += (logE[b]-tonal->lowE[b])/(1e-15f+tonal->highE[b]-tonal->lowE[b]);
+
+ L1=L2=0;
+ for (i=0;i<NB_FRAMES;i++)
+ {
+ L1 += (float)sqrt(tonal->E[i][b]);
+ L2 += tonal->E[i][b];
+ }
+
+ stationarity = MIN16(0.99f,L1/(float)sqrt(1e-15+NB_FRAMES*L2));
+ stationarity *= stationarity;
+ stationarity *= stationarity;
+ frame_stationarity += stationarity;
+ /*band_tonality[b] = tE/(1e-15+E)*/;
+ band_tonality[b] = MAX16(tE/(1e-15f+E), stationarity*tonal->prev_band_tonality[b]);
+#if 0
+ if (b>=NB_TONAL_SKIP_BANDS)
+ {
+ frame_tonality += tweight[b]*band_tonality[b];
+ tw_sum += tweight[b];
+ }
+#else
+ frame_tonality += band_tonality[b];
+ if (b>=NB_TBANDS-NB_TONAL_SKIP_BANDS)
+ frame_tonality -= band_tonality[b-NB_TBANDS+NB_TONAL_SKIP_BANDS];
+#endif
+ max_frame_tonality = MAX16(max_frame_tonality, (1.f+.03f*(b-NB_TBANDS))*frame_tonality);
+ slope += band_tonality[b]*(b-8);
+ /*printf("%f %f ", band_tonality[b], stationarity);*/
+ tonal->prev_band_tonality[b] = band_tonality[b];
+ }
+
+ bandwidth_mask = 0;
+ bandwidth = 0;
+ maxE = 0;
+ noise_floor = 5.7e-4f/(1<<(IMAX(0,lsb_depth-8)));
+#ifdef FIXED_POINT
+ noise_floor *= 1<<(15+SIG_SHIFT);
+#endif
+ noise_floor *= noise_floor;
+ for (b=0;b<NB_TOT_BANDS;b++)
+ {
+ float E=0;
+ int band_start, band_end;
+ /* Keep a margin of 300 Hz for aliasing */
+ band_start = extra_bands[b];
+ band_end = extra_bands[b+1];
+ for (i=band_start;i<band_end;i++)
+ {
+ float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
+ + out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
+ E += binE;
+ }
+ maxE = MAX32(maxE, E);
+ tonal->meanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E);
+ E = MAX32(E, tonal->meanE[b]);
+ /* Use a simple follower with 13 dB/Bark slope for spreading function */
+ bandwidth_mask = MAX32(.05f*bandwidth_mask, E);
+ /* Consider the band "active" only if all these conditions are met:
+ 1) less than 10 dB below the simple follower
+ 2) less than 90 dB below the peak band (maximal masking possible considering
+ both the ATH and the loudness-dependent slope of the spreading function)
+ 3) above the PCM quantization noise floor
+ */
+ if (E>.1*bandwidth_mask && E*1e9f > maxE && E > noise_floor*(band_end-band_start))
+ bandwidth = b;
+ }
+ if (tonal->count<=2)
+ bandwidth = 20;
+ frame_loudness = 20*(float)log10(frame_loudness);
+ tonal->Etracker = MAX32(tonal->Etracker-.03f, frame_loudness);
+ tonal->lowECount *= (1-alphaE);
+ if (frame_loudness < tonal->Etracker-30)
+ tonal->lowECount += alphaE;
+
+ for (i=0;i<8;i++)
+ {
+ float sum=0;
+ for (b=0;b<16;b++)
+ sum += dct_table[i*16+b]*logE[b];
+ BFCC[i] = sum;
+ }
+
+ frame_stationarity /= NB_TBANDS;
+ relativeE /= NB_TBANDS;
+ if (tonal->count<10)
+ relativeE = .5;
+ frame_noisiness /= NB_TBANDS;
+#if 1
+ info->activity = frame_noisiness + (1-frame_noisiness)*relativeE;
+#else
+ info->activity = .5*(1+frame_noisiness-frame_stationarity);
+#endif
+ frame_tonality = (max_frame_tonality/(NB_TBANDS-NB_TONAL_SKIP_BANDS));
+ frame_tonality = MAX16(frame_tonality, tonal->prev_tonality*.8f);
+ tonal->prev_tonality = frame_tonality;
+
+ slope /= 8*8;
+ info->tonality_slope = slope;
+
+ tonal->E_count = (tonal->E_count+1)%NB_FRAMES;
+ tonal->count++;
+ info->tonality = frame_tonality;
+
+ for (i=0;i<4;i++)
+ features[i] = -0.12299f*(BFCC[i]+tonal->mem[i+24]) + 0.49195f*(tonal->mem[i]+tonal->mem[i+16]) + 0.69693f*tonal->mem[i+8] - 1.4349f*tonal->cmean[i];
+
+ for (i=0;i<4;i++)
+ tonal->cmean[i] = (1-alpha)*tonal->cmean[i] + alpha*BFCC[i];
+
+ for (i=0;i<4;i++)
+ features[4+i] = 0.63246f*(BFCC[i]-tonal->mem[i+24]) + 0.31623f*(tonal->mem[i]-tonal->mem[i+16]);
+ for (i=0;i<3;i++)
+ features[8+i] = 0.53452f*(BFCC[i]+tonal->mem[i+24]) - 0.26726f*(tonal->mem[i]+tonal->mem[i+16]) -0.53452f*tonal->mem[i+8];
+
+ if (tonal->count > 5)
+ {
+ for (i=0;i<9;i++)
+ tonal->std[i] = (1-alpha)*tonal->std[i] + alpha*features[i]*features[i];
+ }
+
+ for (i=0;i<8;i++)
+ {
+ tonal->mem[i+24] = tonal->mem[i+16];
+ tonal->mem[i+16] = tonal->mem[i+8];
+ tonal->mem[i+8] = tonal->mem[i];
+ tonal->mem[i] = BFCC[i];
+ }
+ for (i=0;i<9;i++)
+ features[11+i] = (float)sqrt(tonal->std[i]);
+ features[20] = info->tonality;
+ features[21] = info->activity;
+ features[22] = frame_stationarity;
+ features[23] = info->tonality_slope;
+ features[24] = tonal->lowECount;
+
+#ifndef DISABLE_FLOAT_API
+ mlp_process(&net, features, frame_probs);
+ frame_probs[0] = .5f*(frame_probs[0]+1);
+ /* Curve fitting between the MLP probability and the actual probability */
+ frame_probs[0] = .01f + 1.21f*frame_probs[0]*frame_probs[0] - .23f*(float)pow(frame_probs[0], 10);
+ /* Probability of active audio (as opposed to silence) */
+ frame_probs[1] = .5f*frame_probs[1]+.5f;
+ /* Consider that silence has a 50-50 probability. */
+ frame_probs[0] = frame_probs[1]*frame_probs[0] + (1-frame_probs[1])*.5f;
+
+ /*printf("%f %f ", frame_probs[0], frame_probs[1]);*/
+ {
+ /* Probability of state transition */
+ float tau;
+ /* Represents independence of the MLP probabilities, where
+ beta=1 means fully independent. */
+ float beta;
+ /* Denormalized probability of speech (p0) and music (p1) after update */
+ float p0, p1;
+ /* Probabilities for "all speech" and "all music" */
+ float s0, m0;
+ /* Probability sum for renormalisation */
+ float psum;
+ /* Instantaneous probability of speech and music, with beta pre-applied. */
+ float speech0;
+ float music0;
+ float p, q;
+
+ /* One transition every 3 minutes of active audio */
+ tau = .00005f*frame_probs[1];
+ /* Adapt beta based on how "unexpected" the new prob is */
+ p = MAX16(.05f,MIN16(.95f,frame_probs[0]));
+ q = MAX16(.05f,MIN16(.95f,tonal->music_prob));
+ beta = .01f+.05f*ABS16(p-q)/(p*(1-q)+q*(1-p));
+ /* p0 and p1 are the probabilities of speech and music at this frame
+ using only information from previous frame and applying the
+ state transition model */
+ p0 = (1-tonal->music_prob)*(1-tau) + tonal->music_prob *tau;
+ p1 = tonal->music_prob *(1-tau) + (1-tonal->music_prob)*tau;
+ /* We apply the current probability with exponent beta to work around
+ the fact that the probability estimates aren't independent. */
+ p0 *= (float)pow(1-frame_probs[0], beta);
+ p1 *= (float)pow(frame_probs[0], beta);
+ /* Normalise the probabilities to get the Marokv probability of music. */
+ tonal->music_prob = p1/(p0+p1);
+ info->music_prob = tonal->music_prob;
+
+ /* This chunk of code deals with delayed decision. */
+ psum=1e-20f;
+ /* Instantaneous probability of speech and music, with beta pre-applied. */
+ speech0 = (float)pow(1-frame_probs[0], beta);
+ music0 = (float)pow(frame_probs[0], beta);
+ if (tonal->count==1)
+ {
+ tonal->pspeech[0]=.5;
+ tonal->pmusic [0]=.5;
+ }
+ /* Updated probability of having only speech (s0) or only music (m0),
+ before considering the new observation. */
+ s0 = tonal->pspeech[0] + tonal->pspeech[1];
+ m0 = tonal->pmusic [0] + tonal->pmusic [1];
+ /* Updates s0 and m0 with instantaneous probability. */
+ tonal->pspeech[0] = s0*(1-tau)*speech0;
+ tonal->pmusic [0] = m0*(1-tau)*music0;
+ /* Propagate the transition probabilities */
+ for (i=1;i<DETECT_SIZE-1;i++)
+ {
+ tonal->pspeech[i] = tonal->pspeech[i+1]*speech0;
+ tonal->pmusic [i] = tonal->pmusic [i+1]*music0;
+ }
+ /* Probability that the latest frame is speech, when all the previous ones were music. */
+ tonal->pspeech[DETECT_SIZE-1] = m0*tau*speech0;
+ /* Probability that the latest frame is music, when all the previous ones were speech. */
+ tonal->pmusic [DETECT_SIZE-1] = s0*tau*music0;
+
+ /* Renormalise probabilities to 1 */
+ for (i=0;i<DETECT_SIZE;i++)
+ psum += tonal->pspeech[i] + tonal->pmusic[i];
+ psum = 1.f/psum;
+ for (i=0;i<DETECT_SIZE;i++)
+ {
+ tonal->pspeech[i] *= psum;
+ tonal->pmusic [i] *= psum;
+ }
+ psum = tonal->pmusic[0];
+ for (i=1;i<DETECT_SIZE;i++)
+ psum += tonal->pspeech[i];
+
+ /* Estimate our confidence in the speech/music decisions */
+ if (frame_probs[1]>.75)
+ {
+ if (tonal->music_prob>.9)
+ {
+ float adapt;
+ adapt = 1.f/(++tonal->music_confidence_count);
+ tonal->music_confidence_count = IMIN(tonal->music_confidence_count, 500);
+ tonal->music_confidence += adapt*MAX16(-.2f,frame_probs[0]-tonal->music_confidence);
+ }
+ if (tonal->music_prob<.1)
+ {
+ float adapt;
+ adapt = 1.f/(++tonal->speech_confidence_count);
+ tonal->speech_confidence_count = IMIN(tonal->speech_confidence_count, 500);
+ tonal->speech_confidence += adapt*MIN16(.2f,frame_probs[0]-tonal->speech_confidence);
+ }
+ } else {
+ if (tonal->music_confidence_count==0)
+ tonal->music_confidence = .9f;
+ if (tonal->speech_confidence_count==0)
+ tonal->speech_confidence = .1f;
+ }
+ }
+ if (tonal->last_music != (tonal->music_prob>.5f))
+ tonal->last_transition=0;
+ tonal->last_music = tonal->music_prob>.5f;
+#else
+ info->music_prob = 0;
+#endif
+ /*for (i=0;i<25;i++)
+ printf("%f ", features[i]);
+ printf("\n");*/
+
+ info->bandwidth = bandwidth;
+ /*printf("%d %d\n", info->bandwidth, info->opus_bandwidth);*/
+ info->noisiness = frame_noisiness;
+ info->valid = 1;
+ RESTORE_STACK;
+}
+
+void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm,
+ int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs,
+ int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info)
+{
+ int offset;
+ int pcm_len;
+
+ if (analysis_pcm != NULL)
+ {
+ /* Avoid overflow/wrap-around of the analysis buffer */
+ analysis_frame_size = IMIN((DETECT_SIZE-5)*Fs/100, analysis_frame_size);
+
+ pcm_len = analysis_frame_size - analysis->analysis_offset;
+ offset = analysis->analysis_offset;
+ do {
+ tonality_analysis(analysis, celt_mode, analysis_pcm, IMIN(480, pcm_len), offset, c1, c2, C, lsb_depth, downmix);
+ offset += 480;
+ pcm_len -= 480;
+ } while (pcm_len>0);
+ analysis->analysis_offset = analysis_frame_size;
+
+ analysis->analysis_offset -= frame_size;
+ }
+
+ analysis_info->valid = 0;
+ tonality_get_info(analysis, analysis_info, frame_size);
+}
diff --git a/external/opus-1.1.4/src/analysis.h b/external/opus-1.1.4/src/analysis.h
new file mode 100644
index 0000000..9eae56a
--- /dev/null
+++ b/external/opus-1.1.4/src/analysis.h
@@ -0,0 +1,103 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 FOUNDATION OR
+ CONTRIBUTORS 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.
+*/
+
+#ifndef ANALYSIS_H
+#define ANALYSIS_H
+
+#include "celt.h"
+#include "opus_private.h"
+
+#define NB_FRAMES 8
+#define NB_TBANDS 18
+#define NB_TOT_BANDS 21
+#define ANALYSIS_BUF_SIZE 720 /* 15 ms at 48 kHz */
+
+#define DETECT_SIZE 200
+
+typedef struct {
+ int arch;
+#define TONALITY_ANALYSIS_RESET_START angle
+ float angle[240];
+ float d_angle[240];
+ float d2_angle[240];
+ opus_val32 inmem[ANALYSIS_BUF_SIZE];
+ int mem_fill; /* number of usable samples in the buffer */
+ float prev_band_tonality[NB_TBANDS];
+ float prev_tonality;
+ float E[NB_FRAMES][NB_TBANDS];
+ float lowE[NB_TBANDS];
+ float highE[NB_TBANDS];
+ float meanE[NB_TOT_BANDS];
+ float mem[32];
+ float cmean[8];
+ float std[9];
+ float music_prob;
+ float Etracker;
+ float lowECount;
+ int E_count;
+ int last_music;
+ int last_transition;
+ int count;
+ float subframe_mem[3];
+ int analysis_offset;
+ /** Probability of having speech for time i to DETECT_SIZE-1 (and music before).
+ pspeech[0] is the probability that all frames in the window are speech. */
+ float pspeech[DETECT_SIZE];
+ /** Probability of having music for time i to DETECT_SIZE-1 (and speech before).
+ pmusic[0] is the probability that all frames in the window are music. */
+ float pmusic[DETECT_SIZE];
+ float speech_confidence;
+ float music_confidence;
+ int speech_confidence_count;
+ int music_confidence_count;
+ int write_pos;
+ int read_pos;
+ int read_subframe;
+ AnalysisInfo info[DETECT_SIZE];
+} TonalityAnalysisState;
+
+/** Initialize a TonalityAnalysisState struct.
+ *
+ * This performs some possibly slow initialization steps which should
+ * not be repeated every analysis step. No allocated memory is retained
+ * by the state struct, so no cleanup call is required.
+ */
+void tonality_analysis_init(TonalityAnalysisState *analysis);
+
+/** Reset a TonalityAnalysisState stuct.
+ *
+ * Call this when there's a discontinuity in the data.
+ */
+void tonality_analysis_reset(TonalityAnalysisState *analysis);
+
+void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len);
+
+void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm,
+ int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs,
+ int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info);
+
+#endif
diff --git a/external/opus-1.1.4/src/mlp.c b/external/opus-1.1.4/src/mlp.c
new file mode 100644
index 0000000..ff9e50d
--- /dev/null
+++ b/external/opus-1.1.4/src/mlp.c
@@ -0,0 +1,145 @@
+/* Copyright (c) 2008-2011 Octasic Inc.
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 FOUNDATION OR
+ CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#include <math.h>
+#include "mlp.h"
+#include "arch.h"
+#include "tansig_table.h"
+#define MAX_NEURONS 100
+
+#if 0
+static OPUS_INLINE opus_val16 tansig_approx(opus_val32 _x) /* Q19 */
+{
+ int i;
+ opus_val16 xx; /* Q11 */
+ /*double x, y;*/
+ opus_val16 dy, yy; /* Q14 */
+ /*x = 1.9073e-06*_x;*/
+ if (_x>=QCONST32(8,19))
+ return QCONST32(1.,14);
+ if (_x<=-QCONST32(8,19))
+ return -QCONST32(1.,14);
+ xx = EXTRACT16(SHR32(_x, 8));
+ /*i = lrint(25*x);*/
+ i = SHR32(ADD32(1024,MULT16_16(25, xx)),11);
+ /*x -= .04*i;*/
+ xx -= EXTRACT16(SHR32(MULT16_16(20972,i),8));
+ /*x = xx*(1./2048);*/
+ /*y = tansig_table[250+i];*/
+ yy = tansig_table[250+i];
+ /*y = yy*(1./16384);*/
+ dy = 16384-MULT16_16_Q14(yy,yy);
+ yy = yy + MULT16_16_Q14(MULT16_16_Q11(xx,dy),(16384 - MULT16_16_Q11(yy,xx)));
+ return yy;
+}
+#else
+/*extern const float tansig_table[501];*/
+static OPUS_INLINE float tansig_approx(float x)
+{
+ int i;
+ float y, dy;
+ float sign=1;
+ /* Tests are reversed to catch NaNs */
+ if (!(x<8))
+ return 1;
+ if (!(x>-8))
+ return -1;
+#ifndef FIXED_POINT
+ /* Another check in case of -ffast-math */
+ if (celt_isnan(x))
+ return 0;
+#endif
+ if (x<0)
+ {
+ x=-x;
+ sign=-1;
+ }
+ i = (int)floor(.5f+25*x);
+ x -= .04f*i;
+ y = tansig_table[i];
+ dy = 1-y*y;
+ y = y + x*dy*(1 - y*x);
+ return sign*y;
+}
+#endif
+
+#if 0
+void mlp_process(const MLP *m, const opus_val16 *in, opus_val16 *out)
+{
+ int j;
+ opus_val16 hidden[MAX_NEURONS];
+ const opus_val16 *W = m->weights;
+ /* Copy to tmp_in */
+ for (j=0;j<m->topo[1];j++)
+ {
+ int k;
+ opus_val32 sum = SHL32(EXTEND32(*W++),8);
+ for (k=0;k<m->topo[0];k++)
+ sum = MAC16_16(sum, in[k],*W++);
+ hidden[j] = tansig_approx(sum);
+ }
+ for (j=0;j<m->topo[2];j++)
+ {
+ int k;
+ opus_val32 sum = SHL32(EXTEND32(*W++),14);
+ for (k=0;k<m->topo[1];k++)
+ sum = MAC16_16(sum, hidden[k], *W++);
+ out[j] = tansig_approx(EXTRACT16(PSHR32(sum,17)));
+ }
+}
+#else
+void mlp_process(const MLP *m, const float *in, float *out)
+{
+ int j;
+ float hidden[MAX_NEURONS];
+ const float *W = m->weights;
+ /* Copy to tmp_in */
+ for (j=0;j<m->topo[1];j++)
+ {
+ int k;
+ float sum = *W++;
+ for (k=0;k<m->topo[0];k++)
+ sum = sum + in[k]**W++;
+ hidden[j] = tansig_approx(sum);
+ }
+ for (j=0;j<m->topo[2];j++)
+ {
+ int k;
+ float sum = *W++;
+ for (k=0;k<m->topo[1];k++)
+ sum = sum + hidden[k]**W++;
+ out[j] = tansig_approx(sum);
+ }
+}
+#endif
diff --git a/external/opus-1.1.4/src/mlp.h b/external/opus-1.1.4/src/mlp.h
new file mode 100644
index 0000000..618e246
--- /dev/null
+++ b/external/opus-1.1.4/src/mlp.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2008-2011 Octasic Inc.
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 FOUNDATION OR
+ CONTRIBUTORS 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.
+*/
+
+#ifndef _MLP_H_
+#define _MLP_H_
+
+#include "arch.h"
+
+typedef struct {
+ int layers;
+ const int *topo;
+ const float *weights;
+} MLP;
+
+extern const MLP net;
+
+void mlp_process(const MLP *m, const float *in, float *out);
+
+#endif /* _MLP_H_ */
diff --git a/external/opus-1.1.4/src/mlp_data.c b/external/opus-1.1.4/src/mlp_data.c
new file mode 100644
index 0000000..c2fda4e
--- /dev/null
+++ b/external/opus-1.1.4/src/mlp_data.c
@@ -0,0 +1,109 @@
+/* The contents of this file was automatically generated by mlp_train.c
+ It contains multi-layer perceptron (MLP) weights. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mlp.h"
+
+/* RMS error was 0.138320, seed was 1361535663 */
+
+static const float weights[422] = {
+
+/* hidden layer */
+-0.0941125f, -0.302976f, -0.603555f, -0.19393f, -0.185983f,
+-0.601617f, -0.0465317f, -0.114563f, -0.103599f, -0.618938f,
+-0.317859f, -0.169949f, -0.0702885f, 0.148065f, 0.409524f,
+0.548432f, 0.367649f, -0.494393f, 0.764306f, -1.83957f,
+0.170849f, 12.786f, -1.08848f, -1.27284f, -16.2606f,
+24.1773f, -5.57454f, -0.17276f, -0.163388f, -0.224421f,
+-0.0948944f, -0.0728695f, -0.26557f, -0.100283f, -0.0515459f,
+-0.146142f, -0.120674f, -0.180655f, 0.12857f, 0.442138f,
+-0.493735f, 0.167767f, 0.206699f, -0.197567f, 0.417999f,
+1.50364f, -0.773341f, -10.0401f, 0.401872f, 2.97966f,
+15.2165f, -1.88905f, -1.19254f, 0.0285397f, -0.00405139f,
+0.0707565f, 0.00825699f, -0.0927269f, -0.010393f, -0.00428882f,
+-0.00489743f, -0.0709731f, -0.00255992f, 0.0395619f, 0.226424f,
+0.0325231f, 0.162175f, -0.100118f, 0.485789f, 0.12697f,
+0.285937f, 0.0155637f, 0.10546f, 3.05558f, 1.15059f,
+-1.00904f, -1.83088f, 3.31766f, -3.42516f, -0.119135f,
+-0.0405654f, 0.00690068f, 0.0179877f, -0.0382487f, 0.00597941f,
+-0.0183611f, 0.00190395f, -0.144322f, -0.0435671f, 0.000990594f,
+0.221087f, 0.142405f, 0.484066f, 0.404395f, 0.511955f,
+-0.237255f, 0.241742f, 0.35045f, -0.699428f, 10.3993f,
+2.6507f, -2.43459f, -4.18838f, 1.05928f, 1.71067f,
+0.00667811f, -0.0721335f, -0.0397346f, 0.0362704f, -0.11496f,
+-0.0235776f, 0.0082161f, -0.0141741f, -0.0329699f, -0.0354253f,
+0.00277404f, -0.290654f, -1.14767f, -0.319157f, -0.686544f,
+0.36897f, 0.478899f, 0.182579f, -0.411069f, 0.881104f,
+-4.60683f, 1.4697f, 0.335845f, -1.81905f, -30.1699f,
+5.55225f, 0.0019508f, -0.123576f, -0.0727332f, -0.0641597f,
+-0.0534458f, -0.108166f, -0.0937368f, -0.0697883f, -0.0275475f,
+-0.192309f, -0.110074f, 0.285375f, -0.405597f, 0.0926724f,
+-0.287881f, -0.851193f, -0.099493f, -0.233764f, -1.2852f,
+1.13611f, 3.12168f, -0.0699f, -1.86216f, 2.65292f,
+-7.31036f, 2.44776f, -0.00111802f, -0.0632786f, -0.0376296f,
+-0.149851f, 0.142963f, 0.184368f, 0.123433f, 0.0756158f,
+0.117312f, 0.0933395f, 0.0692163f, 0.0842592f, 0.0704683f,
+0.0589963f, 0.0942205f, -0.448862f, 0.0262677f, 0.270352f,
+-0.262317f, 0.172586f, 2.00227f, -0.159216f, 0.038422f,
+10.2073f, 4.15536f, -2.3407f, -0.0550265f, 0.00964792f,
+-0.141336f, 0.0274501f, 0.0343921f, -0.0487428f, 0.0950172f,
+-0.00775017f, -0.0372492f, -0.00548121f, -0.0663695f, 0.0960506f,
+-0.200008f, -0.0412827f, 0.58728f, 0.0515787f, 0.337254f,
+0.855024f, 0.668371f, -0.114904f, -3.62962f, -0.467477f,
+-0.215472f, 2.61537f, 0.406117f, -1.36373f, 0.0425394f,
+0.12208f, 0.0934502f, 0.123055f, 0.0340935f, -0.142466f,
+0.035037f, -0.0490666f, 0.0733208f, 0.0576672f, 0.123984f,
+-0.0517194f, -0.253018f, 0.590565f, 0.145849f, 0.315185f,
+0.221534f, -0.149081f, 0.216161f, -0.349575f, 24.5664f,
+-0.994196f, 0.614289f, -18.7905f, -2.83277f, -0.716801f,
+-0.347201f, 0.479515f, -0.246027f, 0.0758683f, 0.137293f,
+-0.17781f, 0.118751f, -0.00108329f, -0.237334f, 0.355732f,
+-0.12991f, -0.0547627f, -0.318576f, -0.325524f, 0.180494f,
+-0.0625604f, 0.141219f, 0.344064f, 0.37658f, -0.591772f,
+5.8427f, -0.38075f, 0.221894f, -1.41934f, -1.87943e+06f,
+1.34114f, 0.0283355f, -0.0447856f, -0.0211466f, -0.0256927f,
+0.0139618f, 0.0207934f, -0.0107666f, 0.0110969f, 0.0586069f,
+-0.0253545f, -0.0328433f, 0.11872f, -0.216943f, 0.145748f,
+0.119808f, -0.0915211f, -0.120647f, -0.0787719f, -0.143644f,
+-0.595116f, -1.152f, -1.25335f, -1.17092f, 4.34023f,
+-975268.f, -1.37033f, -0.0401123f, 0.210602f, -0.136656f,
+0.135962f, -0.0523293f, 0.0444604f, 0.0143928f, 0.00412666f,
+-0.0193003f, 0.218452f, -0.110204f, -2.02563f, 0.918238f,
+-2.45362f, 1.19542f, -0.061362f, -1.92243f, 0.308111f,
+0.49764f, 0.912356f, 0.209272f, -2.34525f, 2.19326f,
+-6.47121f, 1.69771f, -0.725123f, 0.0118929f, 0.0377944f,
+0.0554003f, 0.0226452f, -0.0704421f, -0.0300309f, 0.0122978f,
+-0.0041782f, -0.0686612f, 0.0313115f, 0.039111f, 0.364111f,
+-0.0945548f, 0.0229876f, -0.17414f, 0.329795f, 0.114714f,
+0.30022f, 0.106997f, 0.132355f, 5.79932f, 0.908058f,
+-0.905324f, -3.3561f, 0.190647f, 0.184211f, -0.673648f,
+0.231807f, -0.0586222f, 0.230752f, -0.438277f, 0.245857f,
+-0.17215f, 0.0876383f, -0.720512f, 0.162515f, 0.0170571f,
+0.101781f, 0.388477f, 1.32931f, 1.08548f, -0.936301f,
+-2.36958f, -6.71988f, -3.44376f, 2.13818f, 14.2318f,
+4.91459f, -3.09052f, -9.69191f, -0.768234f, 1.79604f,
+0.0549653f, 0.163399f, 0.0797025f, 0.0343933f, -0.0555876f,
+-0.00505673f, 0.0187258f, 0.0326628f, 0.0231486f, 0.15573f,
+0.0476223f, -0.254824f, 1.60155f, -0.801221f, 2.55496f,
+0.737629f, -1.36249f, -0.695463f, -2.44301f, -1.73188f,
+3.95279f, 1.89068f, 0.486087f, -11.3343f, 3.9416e+06f,
+
+/* output layer */
+-0.381439f, 0.12115f, -0.906927f, 2.93878f, 1.6388f,
+0.882811f, 0.874344f, 1.21726f, -0.874545f, 0.321706f,
+0.785055f, 0.946558f, -0.575066f, -3.46553f, 0.884905f,
+0.0924047f, -9.90712f, 0.391338f, 0.160103f, -2.04954f,
+4.1455f, 0.0684029f, -0.144761f, -0.285282f, 0.379244f,
+-1.1584f, -0.0277241f, -9.85f, -4.82386f, 3.71333f,
+3.87308f, 3.52558f};
+
+static const int topo[3] = {25, 15, 2};
+
+const MLP net = {
+ 3,
+ topo,
+ weights
+};
diff --git a/external/opus-1.1.4/src/opus.c b/external/opus-1.1.4/src/opus.c
new file mode 100644
index 0000000..f76f125
--- /dev/null
+++ b/external/opus-1.1.4/src/opus.c
@@ -0,0 +1,356 @@
+/* Copyright (c) 2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus.h"
+#include "opus_private.h"
+
+#ifndef DISABLE_FLOAT_API
+OPUS_EXPORT void opus_pcm_soft_clip(float *_x, int N, int C, float *declip_mem)
+{
+ int c;
+ int i;
+ float *x;
+
+ if (C<1 || N<1 || !_x || !declip_mem) return;
+
+ /* First thing: saturate everything to +/- 2 which is the highest level our
+ non-linearity can handle. At the point where the signal reaches +/-2,
+ the derivative will be zero anyway, so this doesn't introduce any
+ discontinuity in the derivative. */
+ for (i=0;i<N*C;i++)
+ _x[i] = MAX16(-2.f, MIN16(2.f, _x[i]));
+ for (c=0;c<C;c++)
+ {
+ float a;
+ float x0;
+ int curr;
+
+ x = _x+c;
+ a = declip_mem[c];
+ /* Continue applying the non-linearity from the previous frame to avoid
+ any discontinuity. */
+ for (i=0;i<N;i++)
+ {
+ if (x[i*C]*a>=0)
+ break;
+ x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
+ }
+
+ curr=0;
+ x0 = x[0];
+ while(1)
+ {
+ int start, end;
+ float maxval;
+ int special=0;
+ int peak_pos;
+ for (i=curr;i<N;i++)
+ {
+ if (x[i*C]>1 || x[i*C]<-1)
+ break;
+ }
+ if (i==N)
+ {
+ a=0;
+ break;
+ }
+ peak_pos = i;
+ start=end=i;
+ maxval=ABS16(x[i*C]);
+ /* Look for first zero crossing before clipping */
+ while (start>0 && x[i*C]*x[(start-1)*C]>=0)
+ start--;
+ /* Look for first zero crossing after clipping */
+ while (end<N && x[i*C]*x[end*C]>=0)
+ {
+ /* Look for other peaks until the next zero-crossing. */
+ if (ABS16(x[end*C])>maxval)
+ {
+ maxval = ABS16(x[end*C]);
+ peak_pos = end;
+ }
+ end++;
+ }
+ /* Detect the special case where we clip before the first zero crossing */
+ special = (start==0 && x[i*C]*x[0]>=0);
+
+ /* Compute a such that maxval + a*maxval^2 = 1 */
+ a=(maxval-1)/(maxval*maxval);
+ /* Slightly boost "a" by 2^-22. This is just enough to ensure -ffast-math
+ does not cause output values larger than +/-1, but small enough not
+ to matter even for 24-bit output. */
+ a += a*2.4e-7;
+ if (x[i*C]>0)
+ a = -a;
+ /* Apply soft clipping */
+ for (i=start;i<end;i++)
+ x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
+
+ if (special && peak_pos>=2)
+ {
+ /* Add a linear ramp from the first sample to the signal peak.
+ This avoids a discontinuity at the beginning of the frame. */
+ float delta;
+ float offset = x0-x[0];
+ delta = offset / peak_pos;
+ for (i=curr;i<peak_pos;i++)
+ {
+ offset -= delta;
+ x[i*C] += offset;
+ x[i*C] = MAX16(-1.f, MIN16(1.f, x[i*C]));
+ }
+ }
+ curr = end;
+ if (curr==N)
+ break;
+ }
+ declip_mem[c] = a;
+ }
+}
+#endif
+
+int encode_size(int size, unsigned char *data)
+{
+ if (size < 252)
+ {
+ data[0] = size;
+ return 1;
+ } else {
+ data[0] = 252+(size&0x3);
+ data[1] = (size-(int)data[0])>>2;
+ return 2;
+ }
+}
+
+static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size)
+{
+ if (len<1)
+ {
+ *size = -1;
+ return -1;
+ } else if (data[0]<252)
+ {
+ *size = data[0];
+ return 1;
+ } else if (len<2)
+ {
+ *size = -1;
+ return -1;
+ } else {
+ *size = 4*data[1] + data[0];
+ return 2;
+ }
+}
+
+int opus_packet_get_samples_per_frame(const unsigned char *data,
+ opus_int32 Fs)
+{
+ int audiosize;
+ if (data[0]&0x80)
+ {
+ audiosize = ((data[0]>>3)&0x3);
+ audiosize = (Fs<<audiosize)/400;
+ } else if ((data[0]&0x60) == 0x60)
+ {
+ audiosize = (data[0]&0x08) ? Fs/50 : Fs/100;
+ } else {
+ audiosize = ((data[0]>>3)&0x3);
+ if (audiosize == 3)
+ audiosize = Fs*60/1000;
+ else
+ audiosize = (Fs<<audiosize)/100;
+ }
+ return audiosize;
+}
+
+int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
+ int self_delimited, unsigned char *out_toc,
+ const unsigned char *frames[48], opus_int16 size[48],
+ int *payload_offset, opus_int32 *packet_offset)
+{
+ int i, bytes;
+ int count;
+ int cbr;
+ unsigned char ch, toc;
+ int framesize;
+ opus_int32 last_size;
+ opus_int32 pad = 0;
+ const unsigned char *data0 = data;
+
+ if (size==NULL || len<0)
+ return OPUS_BAD_ARG;
+ if (len==0)
+ return OPUS_INVALID_PACKET;
+
+ framesize = opus_packet_get_samples_per_frame(data, 48000);
+
+ cbr = 0;
+ toc = *data++;
+ len--;
+ last_size = len;
+ switch (toc&0x3)
+ {
+ /* One frame */
+ case 0:
+ count=1;
+ break;
+ /* Two CBR frames */
+ case 1:
+ count=2;
+ cbr = 1;
+ if (!self_delimited)
+ {
+ if (len&0x1)
+ return OPUS_INVALID_PACKET;
+ last_size = len/2;
+ /* If last_size doesn't fit in size[0], we'll catch it later */
+ size[0] = (opus_int16)last_size;
+ }
+ break;
+ /* Two VBR frames */
+ case 2:
+ count = 2;
+ bytes = parse_size(data, len, size);
+ len -= bytes;
+ if (size[0]<0 || size[0] > len)
+ return OPUS_INVALID_PACKET;
+ data += bytes;
+ last_size = len-size[0];
+ break;
+ /* Multiple CBR/VBR frames (from 0 to 120 ms) */
+ default: /*case 3:*/
+ if (len<1)
+ return OPUS_INVALID_PACKET;
+ /* Number of frames encoded in bits 0 to 5 */
+ ch = *data++;
+ count = ch&0x3F;
+ if (count <= 0 || framesize*count > 5760)
+ return OPUS_INVALID_PACKET;
+ len--;
+ /* Padding flag is bit 6 */
+ if (ch&0x40)
+ {
+ int p;
+ do {
+ int tmp;
+ if (len<=0)
+ return OPUS_INVALID_PACKET;
+ p = *data++;
+ len--;
+ tmp = p==255 ? 254: p;
+ len -= tmp;
+ pad += tmp;
+ } while (p==255);
+ }
+ if (len<0)
+ return OPUS_INVALID_PACKET;
+ /* VBR flag is bit 7 */
+ cbr = !(ch&0x80);
+ if (!cbr)
+ {
+ /* VBR case */
+ last_size = len;
+ for (i=0;i<count-1;i++)
+ {
+ bytes = parse_size(data, len, size+i);
+ len -= bytes;
+ if (size[i]<0 || size[i] > len)
+ return OPUS_INVALID_PACKET;
+ data += bytes;
+ last_size -= bytes+size[i];
+ }
+ if (last_size<0)
+ return OPUS_INVALID_PACKET;
+ } else if (!self_delimited)
+ {
+ /* CBR case */
+ last_size = len/count;
+ if (last_size*count!=len)
+ return OPUS_INVALID_PACKET;
+ for (i=0;i<count-1;i++)
+ size[i] = (opus_int16)last_size;
+ }
+ break;
+ }
+ /* Self-delimited framing has an extra size for the last frame. */
+ if (self_delimited)
+ {
+ bytes = parse_size(data, len, size+count-1);
+ len -= bytes;
+ if (size[count-1]<0 || size[count-1] > len)
+ return OPUS_INVALID_PACKET;
+ data += bytes;
+ /* For CBR packets, apply the size to all the frames. */
+ if (cbr)
+ {
+ if (size[count-1]*count > len)
+ return OPUS_INVALID_PACKET;
+ for (i=0;i<count-1;i++)
+ size[i] = size[count-1];
+ } else if (bytes+size[count-1] > last_size)
+ return OPUS_INVALID_PACKET;
+ } else
+ {
+ /* Because it's not encoded explicitly, it's possible the size of the
+ last packet (or all the packets, for the CBR case) is larger than
+ 1275. Reject them here.*/
+ if (last_size > 1275)
+ return OPUS_INVALID_PACKET;
+ size[count-1] = (opus_int16)last_size;
+ }
+
+ if (payload_offset)
+ *payload_offset = (int)(data-data0);
+
+ for (i=0;i<count;i++)
+ {
+ if (frames)
+ frames[i] = data;
+ data += size[i];
+ }
+
+ if (packet_offset)
+ *packet_offset = pad+(opus_int32)(data-data0);
+
+ if (out_toc)
+ *out_toc = toc;
+
+ return count;
+}
+
+int opus_packet_parse(const unsigned char *data, opus_int32 len,
+ unsigned char *out_toc, const unsigned char *frames[48],
+ opus_int16 size[48], int *payload_offset)
+{
+ return opus_packet_parse_impl(data, len, 0, out_toc,
+ frames, size, payload_offset, NULL);
+}
+
diff --git a/external/opus-1.1.4/src/opus_decoder.c b/external/opus-1.1.4/src/opus_decoder.c
new file mode 100644
index 0000000..080bec5
--- /dev/null
+++ b/external/opus-1.1.4/src/opus_decoder.c
@@ -0,0 +1,981 @@
+/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef OPUS_BUILD
+# error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details."
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__) && !defined(OPUS_WILL_BE_SLOW)
+# pragma message "You appear to be compiling without optimization, if so opus will be very slow."
+#endif
+
+#include <stdarg.h>
+#include "celt.h"
+#include "opus.h"
+#include "entdec.h"
+#include "modes.h"
+#include "API.h"
+#include "stack_alloc.h"
+#include "float_cast.h"
+#include "opus_private.h"
+#include "os_support.h"
+#include "structs.h"
+#include "define.h"
+#include "mathops.h"
+#include "cpu_support.h"
+
+struct OpusDecoder {
+ int celt_dec_offset;
+ int silk_dec_offset;
+ int channels;
+ opus_int32 Fs; /** Sampling rate (at the API level) */
+ silk_DecControlStruct DecControl;
+ int decode_gain;
+ int arch;
+
+ /* Everything beyond this point gets cleared on a reset */
+#define OPUS_DECODER_RESET_START stream_channels
+ int stream_channels;
+
+ int bandwidth;
+ int mode;
+ int prev_mode;
+ int frame_size;
+ int prev_redundancy;
+ int last_packet_duration;
+#ifndef FIXED_POINT
+ opus_val16 softclip_mem[2];
+#endif
+
+ opus_uint32 rangeFinal;
+};
+
+
+int opus_decoder_get_size(int channels)
+{
+ int silkDecSizeBytes, celtDecSizeBytes;
+ int ret;
+ if (channels<1 || channels > 2)
+ return 0;
+ ret = silk_Get_Decoder_Size( &silkDecSizeBytes );
+ if(ret)
+ return 0;
+ silkDecSizeBytes = align(silkDecSizeBytes);
+ celtDecSizeBytes = celt_decoder_get_size(channels);
+ return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes;
+}
+
+int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels)
+{
+ void *silk_dec;
+ CELTDecoder *celt_dec;
+ int ret, silkDecSizeBytes;
+
+ if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)
+ || (channels!=1&&channels!=2))
+ return OPUS_BAD_ARG;
+
+ OPUS_CLEAR((char*)st, opus_decoder_get_size(channels));
+ /* Initialize SILK encoder */
+ ret = silk_Get_Decoder_Size(&silkDecSizeBytes);
+ if (ret)
+ return OPUS_INTERNAL_ERROR;
+
+ silkDecSizeBytes = align(silkDecSizeBytes);
+ st->silk_dec_offset = align(sizeof(OpusDecoder));
+ st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes;
+ silk_dec = (char*)st+st->silk_dec_offset;
+ celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+ st->stream_channels = st->channels = channels;
+
+ st->Fs = Fs;
+ st->DecControl.API_sampleRate = st->Fs;
+ st->DecControl.nChannelsAPI = st->channels;
+
+ /* Reset decoder */
+ ret = silk_InitDecoder( silk_dec );
+ if(ret)return OPUS_INTERNAL_ERROR;
+
+ /* Initialize CELT decoder */
+ ret = celt_decoder_init(celt_dec, Fs, channels);
+ if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR;
+
+ celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0));
+
+ st->prev_mode = 0;
+ st->frame_size = Fs/400;
+ st->arch = opus_select_arch();
+ return OPUS_OK;
+}
+
+OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error)
+{
+ int ret;
+ OpusDecoder *st;
+ if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)
+ || (channels!=1&&channels!=2))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels));
+ if (st == NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_decoder_init(st, Fs, channels);
+ if (error)
+ *error = ret;
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ return st;
+}
+
+static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2,
+ opus_val16 *out, int overlap, int channels,
+ const opus_val16 *window, opus_int32 Fs)
+{
+ int i, c;
+ int inc = 48000/Fs;
+ for (c=0;c<channels;c++)
+ {
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+ out[i*channels+c] = SHR32(MAC16_16(MULT16_16(w,in2[i*channels+c]),
+ Q15ONE-w, in1[i*channels+c]), 15);
+ }
+ }
+}
+
+static int opus_packet_get_mode(const unsigned char *data)
+{
+ int mode;
+ if (data[0]&0x80)
+ {
+ mode = MODE_CELT_ONLY;
+ } else if ((data[0]&0x60) == 0x60)
+ {
+ mode = MODE_HYBRID;
+ } else {
+ mode = MODE_SILK_ONLY;
+ }
+ return mode;
+}
+
+static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
+{
+ void *silk_dec;
+ CELTDecoder *celt_dec;
+ int i, silk_ret=0, celt_ret=0;
+ ec_dec dec;
+ opus_int32 silk_frame_size;
+ int pcm_silk_size;
+ VARDECL(opus_int16, pcm_silk);
+ int pcm_transition_silk_size;
+ VARDECL(opus_val16, pcm_transition_silk);
+ int pcm_transition_celt_size;
+ VARDECL(opus_val16, pcm_transition_celt);
+ opus_val16 *pcm_transition=NULL;
+ int redundant_audio_size;
+ VARDECL(opus_val16, redundant_audio);
+
+ int audiosize;
+ int mode;
+ int transition=0;
+ int start_band;
+ int redundancy=0;
+ int redundancy_bytes = 0;
+ int celt_to_silk=0;
+ int c;
+ int F2_5, F5, F10, F20;
+ const opus_val16 *window;
+ opus_uint32 redundant_rng = 0;
+ int celt_accum;
+ ALLOC_STACK;
+
+ silk_dec = (char*)st+st->silk_dec_offset;
+ celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+ F20 = st->Fs/50;
+ F10 = F20>>1;
+ F5 = F10>>1;
+ F2_5 = F5>>1;
+ if (frame_size < F2_5)
+ {
+ RESTORE_STACK;
+ return OPUS_BUFFER_TOO_SMALL;
+ }
+ /* Limit frame_size to avoid excessive stack allocations. */
+ frame_size = IMIN(frame_size, st->Fs/25*3);
+ /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */
+ if (len<=1)
+ {
+ data = NULL;
+ /* In that case, don't conceal more than what the ToC says */
+ frame_size = IMIN(frame_size, st->frame_size);
+ }
+ if (data != NULL)
+ {
+ audiosize = st->frame_size;
+ mode = st->mode;
+ ec_dec_init(&dec,(unsigned char*)data,len);
+ } else {
+ audiosize = frame_size;
+ mode = st->prev_mode;
+
+ if (mode == 0)
+ {
+ /* If we haven't got any packet yet, all we can do is return zeros */
+ for (i=0;i<audiosize*st->channels;i++)
+ pcm[i] = 0;
+ RESTORE_STACK;
+ return audiosize;
+ }
+
+ /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT),
+ 10, or 20 (e.g. 12.5 or 30 ms). */
+ if (audiosize > F20)
+ {
+ do {
+ int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0);
+ if (ret<0)
+ {
+ RESTORE_STACK;
+ return ret;
+ }
+ pcm += ret*st->channels;
+ audiosize -= ret;
+ } while (audiosize > 0);
+ RESTORE_STACK;
+ return frame_size;
+ } else if (audiosize < F20)
+ {
+ if (audiosize > F10)
+ audiosize = F10;
+ else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10)
+ audiosize = F5;
+ }
+ }
+
+ /* In fixed-point, we can tell CELT to do the accumulation on top of the
+ SILK PCM buffer. This saves some stack space. */
+#ifdef FIXED_POINT
+ celt_accum = (mode != MODE_CELT_ONLY) && (frame_size >= F10);
+#else
+ celt_accum = 0;
+#endif
+
+ pcm_transition_silk_size = ALLOC_NONE;
+ pcm_transition_celt_size = ALLOC_NONE;
+ if (data!=NULL && st->prev_mode > 0 && (
+ (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy)
+ || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) )
+ )
+ {
+ transition = 1;
+ /* Decide where to allocate the stack memory for pcm_transition */
+ if (mode == MODE_CELT_ONLY)
+ pcm_transition_celt_size = F5*st->channels;
+ else
+ pcm_transition_silk_size = F5*st->channels;
+ }
+ ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16);
+ if (transition && mode == MODE_CELT_ONLY)
+ {
+ pcm_transition = pcm_transition_celt;
+ opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
+ }
+ if (audiosize > frame_size)
+ {
+ /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ } else {
+ frame_size = audiosize;
+ }
+
+ /* Don't allocate any memory when in CELT-only mode */
+ pcm_silk_size = (mode != MODE_CELT_ONLY && !celt_accum) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE;
+ ALLOC(pcm_silk, pcm_silk_size, opus_int16);
+
+ /* SILK processing */
+ if (mode != MODE_CELT_ONLY)
+ {
+ int lost_flag, decoded_samples;
+ opus_int16 *pcm_ptr;
+#ifdef FIXED_POINT
+ if (celt_accum)
+ pcm_ptr = pcm;
+ else
+#endif
+ pcm_ptr = pcm_silk;
+
+ if (st->prev_mode==MODE_CELT_ONLY)
+ silk_InitDecoder( silk_dec );
+
+ /* The SILK PLC cannot produce frames of less than 10 ms */
+ st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs);
+
+ if (data != NULL)
+ {
+ st->DecControl.nChannelsInternal = st->stream_channels;
+ if( mode == MODE_SILK_ONLY ) {
+ if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) {
+ st->DecControl.internalSampleRate = 8000;
+ } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) {
+ st->DecControl.internalSampleRate = 12000;
+ } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) {
+ st->DecControl.internalSampleRate = 16000;
+ } else {
+ st->DecControl.internalSampleRate = 16000;
+ silk_assert( 0 );
+ }
+ } else {
+ /* Hybrid mode */
+ st->DecControl.internalSampleRate = 16000;
+ }
+ }
+
+ lost_flag = data == NULL ? 1 : 2 * decode_fec;
+ decoded_samples = 0;
+ do {
+ /* Call SILK decoder */
+ int first_frame = decoded_samples == 0;
+ silk_ret = silk_Decode( silk_dec, &st->DecControl,
+ lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size, st->arch );
+ if( silk_ret ) {
+ if (lost_flag) {
+ /* PLC failure should not be fatal */
+ silk_frame_size = frame_size;
+ for (i=0;i<frame_size*st->channels;i++)
+ pcm_ptr[i] = 0;
+ } else {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ }
+ pcm_ptr += silk_frame_size * st->channels;
+ decoded_samples += silk_frame_size;
+ } while( decoded_samples < frame_size );
+ }
+
+ start_band = 0;
+ if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL
+ && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len)
+ {
+ /* Check if we have a redundant 0-8 kHz band */
+ if (mode == MODE_HYBRID)
+ redundancy = ec_dec_bit_logp(&dec, 12);
+ else
+ redundancy = 1;
+ if (redundancy)
+ {
+ celt_to_silk = ec_dec_bit_logp(&dec, 1);
+ /* redundancy_bytes will be at least two, in the non-hybrid
+ case due to the ec_tell() check above */
+ redundancy_bytes = mode==MODE_HYBRID ?
+ (opus_int32)ec_dec_uint(&dec, 256)+2 :
+ len-((ec_tell(&dec)+7)>>3);
+ len -= redundancy_bytes;
+ /* This is a sanity check. It should never happen for a valid
+ packet, so the exact behaviour is not normative. */
+ if (len*8 < ec_tell(&dec))
+ {
+ len = 0;
+ redundancy_bytes = 0;
+ redundancy = 0;
+ }
+ /* Shrink decoder because of raw bits */
+ dec.storage -= redundancy_bytes;
+ }
+ }
+ if (mode != MODE_CELT_ONLY)
+ start_band = 17;
+
+ {
+ int endband=21;
+
+ switch(st->bandwidth)
+ {
+ case OPUS_BANDWIDTH_NARROWBAND:
+ endband = 13;
+ break;
+ case OPUS_BANDWIDTH_MEDIUMBAND:
+ case OPUS_BANDWIDTH_WIDEBAND:
+ endband = 17;
+ break;
+ case OPUS_BANDWIDTH_SUPERWIDEBAND:
+ endband = 19;
+ break;
+ case OPUS_BANDWIDTH_FULLBAND:
+ endband = 21;
+ break;
+ }
+ celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband));
+ celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels));
+ }
+
+ if (redundancy)
+ {
+ transition = 0;
+ pcm_transition_silk_size=ALLOC_NONE;
+ }
+
+ ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16);
+
+ if (transition && mode != MODE_CELT_ONLY)
+ {
+ pcm_transition = pcm_transition_silk;
+ opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
+ }
+
+ /* Only allocation memory for redundancy if/when needed */
+ redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE;
+ ALLOC(redundant_audio, redundant_audio_size, opus_val16);
+
+ /* 5 ms redundant frame for CELT->SILK*/
+ if (redundancy && celt_to_silk)
+ {
+ celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
+ celt_decode_with_ec(celt_dec, data+len, redundancy_bytes,
+ redundant_audio, F5, NULL, 0);
+ celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
+ }
+
+ /* MUST be after PLC */
+ celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band));
+
+ if (mode != MODE_SILK_ONLY)
+ {
+ int celt_frame_size = IMIN(F20, frame_size);
+ /* Make sure to discard any previous CELT state */
+ if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy)
+ celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
+ /* Decode CELT */
+ celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data,
+ len, pcm, celt_frame_size, &dec, celt_accum);
+ } else {
+ unsigned char silence[2] = {0xFF, 0xFF};
+ if (!celt_accum)
+ {
+ for (i=0;i<frame_size*st->channels;i++)
+ pcm[i] = 0;
+ }
+ /* For hybrid -> SILK transitions, we let the CELT MDCT
+ do a fade-out by decoding a silence frame */
+ if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) )
+ {
+ celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
+ celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum);
+ }
+ }
+
+ if (mode != MODE_CELT_ONLY && !celt_accum)
+ {
+#ifdef FIXED_POINT
+ for (i=0;i<frame_size*st->channels;i++)
+ pcm[i] = SAT16(ADD32(pcm[i], pcm_silk[i]));
+#else
+ for (i=0;i<frame_size*st->channels;i++)
+ pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]);
+#endif
+ }
+
+ {
+ const CELTMode *celt_mode;
+ celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode));
+ window = celt_mode->window;
+ }
+
+ /* 5 ms redundant frame for SILK->CELT */
+ if (redundancy && !celt_to_silk)
+ {
+ celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
+ celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
+
+ celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0);
+ celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
+ smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5,
+ pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs);
+ }
+ if (redundancy && celt_to_silk)
+ {
+ for (c=0;c<st->channels;c++)
+ {
+ for (i=0;i<F2_5;i++)
+ pcm[st->channels*i+c] = redundant_audio[st->channels*i+c];
+ }
+ smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5,
+ pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs);
+ }
+ if (transition)
+ {
+ if (audiosize >= F5)
+ {
+ for (i=0;i<st->channels*F2_5;i++)
+ pcm[i] = pcm_transition[i];
+ smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5,
+ pcm+st->channels*F2_5, F2_5,
+ st->channels, window, st->Fs);
+ } else {
+ /* Not enough time to do a clean transition, but we do it anyway
+ This will not preserve amplitude perfectly and may introduce
+ a bit of temporal aliasing, but it shouldn't be too bad and
+ that's pretty much the best we can do. In any case, generating this
+ transition it pretty silly in the first place */
+ smooth_fade(pcm_transition, pcm,
+ pcm, F2_5,
+ st->channels, window, st->Fs);
+ }
+ }
+
+ if(st->decode_gain)
+ {
+ opus_val32 gain;
+ gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain));
+ for (i=0;i<frame_size*st->channels;i++)
+ {
+ opus_val32 x;
+ x = MULT16_32_P16(pcm[i],gain);
+ pcm[i] = SATURATE(x, 32767);
+ }
+ }
+
+ if (len <= 1)
+ st->rangeFinal = 0;
+ else
+ st->rangeFinal = dec.rng ^ redundant_rng;
+
+ st->prev_mode = mode;
+ st->prev_redundancy = redundancy && !celt_to_silk;
+
+ if (celt_ret>=0)
+ {
+ if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels))
+ OPUS_PRINT_INT(audiosize);
+ }
+
+ RESTORE_STACK;
+ return celt_ret < 0 ? celt_ret : audiosize;
+
+}
+
+int opus_decode_native(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec,
+ int self_delimited, opus_int32 *packet_offset, int soft_clip)
+{
+ int i, nb_samples;
+ int count, offset;
+ unsigned char toc;
+ int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels;
+ /* 48 x 2.5 ms = 120 ms */
+ opus_int16 size[48];
+ if (decode_fec<0 || decode_fec>1)
+ return OPUS_BAD_ARG;
+ /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
+ if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0)
+ return OPUS_BAD_ARG;
+ if (len==0 || data==NULL)
+ {
+ int pcm_count=0;
+ do {
+ int ret;
+ ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0);
+ if (ret<0)
+ return ret;
+ pcm_count += ret;
+ } while (pcm_count < frame_size);
+ celt_assert(pcm_count == frame_size);
+ if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels))
+ OPUS_PRINT_INT(pcm_count);
+ st->last_packet_duration = pcm_count;
+ return pcm_count;
+ } else if (len<0)
+ return OPUS_BAD_ARG;
+
+ packet_mode = opus_packet_get_mode(data);
+ packet_bandwidth = opus_packet_get_bandwidth(data);
+ packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
+ packet_stream_channels = opus_packet_get_nb_channels(data);
+
+ count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
+ size, &offset, packet_offset);
+ if (count<0)
+ return count;
+
+ data += offset;
+
+ if (decode_fec)
+ {
+ int duration_copy;
+ int ret;
+ /* If no FEC can be present, run the PLC (recursive call) */
+ if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY)
+ return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip);
+ /* Otherwise, run the PLC on everything except the size for which we might have FEC */
+ duration_copy = st->last_packet_duration;
+ if (frame_size-packet_frame_size!=0)
+ {
+ ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip);
+ if (ret<0)
+ {
+ st->last_packet_duration = duration_copy;
+ return ret;
+ }
+ celt_assert(ret==frame_size-packet_frame_size);
+ }
+ /* Complete with FEC */
+ st->mode = packet_mode;
+ st->bandwidth = packet_bandwidth;
+ st->frame_size = packet_frame_size;
+ st->stream_channels = packet_stream_channels;
+ ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size),
+ packet_frame_size, 1);
+ if (ret<0)
+ return ret;
+ else {
+ if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels))
+ OPUS_PRINT_INT(frame_size);
+ st->last_packet_duration = frame_size;
+ return frame_size;
+ }
+ }
+
+ if (count*packet_frame_size > frame_size)
+ return OPUS_BUFFER_TOO_SMALL;
+
+ /* Update the state as the last step to avoid updating it on an invalid packet */
+ st->mode = packet_mode;
+ st->bandwidth = packet_bandwidth;
+ st->frame_size = packet_frame_size;
+ st->stream_channels = packet_stream_channels;
+
+ nb_samples=0;
+ for (i=0;i<count;i++)
+ {
+ int ret;
+ ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0);
+ if (ret<0)
+ return ret;
+ celt_assert(ret==packet_frame_size);
+ data += size[i];
+ nb_samples += ret;
+ }
+ st->last_packet_duration = nb_samples;
+ if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels))
+ OPUS_PRINT_INT(nb_samples);
+#ifndef FIXED_POINT
+ if (soft_clip)
+ opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem);
+ else
+ st->softclip_mem[0]=st->softclip_mem[1]=0;
+#endif
+ return nb_samples;
+}
+
+#ifdef FIXED_POINT
+
+int opus_decode(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
+{
+ if(frame_size<=0)
+ return OPUS_BAD_ARG;
+ return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_decode_float(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, float *pcm, int frame_size, int decode_fec)
+{
+ VARDECL(opus_int16, out);
+ int ret, i;
+ int nb_samples;
+ ALLOC_STACK;
+
+ if(frame_size<=0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ if (data != NULL && len > 0 && !decode_fec)
+ {
+ nb_samples = opus_decoder_get_nb_samples(st, data, len);
+ if (nb_samples>0)
+ frame_size = IMIN(frame_size, nb_samples);
+ else
+ return OPUS_INVALID_PACKET;
+ }
+ ALLOC(out, frame_size*st->channels, opus_int16);
+
+ ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0);
+ if (ret > 0)
+ {
+ for (i=0;i<ret*st->channels;i++)
+ pcm[i] = (1.f/32768.f)*(out[i]);
+ }
+ RESTORE_STACK;
+ return ret;
+}
+#endif
+
+
+#else
+int opus_decode(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec)
+{
+ VARDECL(float, out);
+ int ret, i;
+ int nb_samples;
+ ALLOC_STACK;
+
+ if(frame_size<=0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+
+ if (data != NULL && len > 0 && !decode_fec)
+ {
+ nb_samples = opus_decoder_get_nb_samples(st, data, len);
+ if (nb_samples>0)
+ frame_size = IMIN(frame_size, nb_samples);
+ else
+ return OPUS_INVALID_PACKET;
+ }
+ ALLOC(out, frame_size*st->channels, float);
+
+ ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1);
+ if (ret > 0)
+ {
+ for (i=0;i<ret*st->channels;i++)
+ pcm[i] = FLOAT2INT16(out[i]);
+ }
+ RESTORE_STACK;
+ return ret;
+}
+
+int opus_decode_float(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
+{
+ if(frame_size<=0)
+ return OPUS_BAD_ARG;
+ return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
+}
+
+#endif
+
+int opus_decoder_ctl(OpusDecoder *st, int request, ...)
+{
+ int ret = OPUS_OK;
+ va_list ap;
+ void *silk_dec;
+ CELTDecoder *celt_dec;
+
+ silk_dec = (char*)st+st->silk_dec_offset;
+ celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+
+
+ va_start(ap, request);
+
+ switch (request)
+ {
+ case OPUS_GET_BANDWIDTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->bandwidth;
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->rangeFinal;
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START,
+ sizeof(OpusDecoder)-
+ ((char*)&st->OPUS_DECODER_RESET_START - (char*)st));
+
+ celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
+ silk_InitDecoder( silk_dec );
+ st->stream_channels = st->channels;
+ st->frame_size = st->Fs/400;
+ }
+ break;
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->Fs;
+ }
+ break;
+ case OPUS_GET_PITCH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ if (st->prev_mode == MODE_CELT_ONLY)
+ celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value));
+ else
+ *value = st->DecControl.prevPitchLag;
+ }
+ break;
+ case OPUS_GET_GAIN_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->decode_gain;
+ }
+ break;
+ case OPUS_SET_GAIN_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<-32768 || value>32767)
+ {
+ goto bad_arg;
+ }
+ st->decode_gain = value;
+ }
+ break;
+ case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
+ {
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->last_packet_duration;
+ }
+ break;
+ default:
+ /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
+ ret = OPUS_UNIMPLEMENTED;
+ break;
+ }
+
+ va_end(ap);
+ return ret;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+}
+
+void opus_decoder_destroy(OpusDecoder *st)
+{
+ opus_free(st);
+}
+
+
+int opus_packet_get_bandwidth(const unsigned char *data)
+{
+ int bandwidth;
+ if (data[0]&0x80)
+ {
+ bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3);
+ if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+ bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ } else if ((data[0]&0x60) == 0x60)
+ {
+ bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND :
+ OPUS_BANDWIDTH_SUPERWIDEBAND;
+ } else {
+ bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3);
+ }
+ return bandwidth;
+}
+
+int opus_packet_get_nb_channels(const unsigned char *data)
+{
+ return (data[0]&0x4) ? 2 : 1;
+}
+
+int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len)
+{
+ int count;
+ if (len<1)
+ return OPUS_BAD_ARG;
+ count = packet[0]&0x3;
+ if (count==0)
+ return 1;
+ else if (count!=3)
+ return 2;
+ else if (len<2)
+ return OPUS_INVALID_PACKET;
+ else
+ return packet[1]&0x3F;
+}
+
+int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len,
+ opus_int32 Fs)
+{
+ int samples;
+ int count = opus_packet_get_nb_frames(packet, len);
+
+ if (count<0)
+ return count;
+
+ samples = count*opus_packet_get_samples_per_frame(packet, Fs);
+ /* Can't have more than 120 ms */
+ if (samples*25 > Fs*3)
+ return OPUS_INVALID_PACKET;
+ else
+ return samples;
+}
+
+int opus_decoder_get_nb_samples(const OpusDecoder *dec,
+ const unsigned char packet[], opus_int32 len)
+{
+ return opus_packet_get_nb_samples(packet, len, dec->Fs);
+}
diff --git a/external/opus-1.1.4/src/opus_encoder.c b/external/opus-1.1.4/src/opus_encoder.c
new file mode 100644
index 0000000..9a516a8
--- /dev/null
+++ b/external/opus-1.1.4/src/opus_encoder.c
@@ -0,0 +1,2536 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include "celt.h"
+#include "entenc.h"
+#include "modes.h"
+#include "API.h"
+#include "stack_alloc.h"
+#include "float_cast.h"
+#include "opus.h"
+#include "arch.h"
+#include "pitch.h"
+#include "opus_private.h"
+#include "os_support.h"
+#include "cpu_support.h"
+#include "analysis.h"
+#include "mathops.h"
+#include "tuning_parameters.h"
+#ifdef FIXED_POINT
+#include "fixed/structs_FIX.h"
+#else
+#include "float/structs_FLP.h"
+#endif
+
+#define MAX_ENCODER_BUFFER 480
+
+typedef struct {
+ opus_val32 XX, XY, YY;
+ opus_val16 smoothed_width;
+ opus_val16 max_follower;
+} StereoWidthState;
+
+struct OpusEncoder {
+ int celt_enc_offset;
+ int silk_enc_offset;
+ silk_EncControlStruct silk_mode;
+ int application;
+ int channels;
+ int delay_compensation;
+ int force_channels;
+ int signal_type;
+ int user_bandwidth;
+ int max_bandwidth;
+ int user_forced_mode;
+ int voice_ratio;
+ opus_int32 Fs;
+ int use_vbr;
+ int vbr_constraint;
+ int variable_duration;
+ opus_int32 bitrate_bps;
+ opus_int32 user_bitrate_bps;
+ int lsb_depth;
+ int encoder_buffer;
+ int lfe;
+ int arch;
+#ifndef DISABLE_FLOAT_API
+ TonalityAnalysisState analysis;
+#endif
+
+#define OPUS_ENCODER_RESET_START stream_channels
+ int stream_channels;
+ opus_int16 hybrid_stereo_width_Q14;
+ opus_int32 variable_HP_smth2_Q15;
+ opus_val16 prev_HB_gain;
+ opus_val32 hp_mem[4];
+ int mode;
+ int prev_mode;
+ int prev_channels;
+ int prev_framesize;
+ int bandwidth;
+ int silk_bw_switch;
+ /* Sampling rate (at the API level) */
+ int first;
+ opus_val16 * energy_masking;
+ StereoWidthState width_mem;
+ opus_val16 delay_buffer[MAX_ENCODER_BUFFER*2];
+#ifndef DISABLE_FLOAT_API
+ int detected_bandwidth;
+#endif
+ opus_uint32 rangeFinal;
+};
+
+/* Transition tables for the voice and music. First column is the
+ middle (memoriless) threshold. The second column is the hysteresis
+ (difference with the middle) */
+static const opus_int32 mono_voice_bandwidth_thresholds[8] = {
+ 11000, 1000, /* NB<->MB */
+ 14000, 1000, /* MB<->WB */
+ 17000, 1000, /* WB<->SWB */
+ 21000, 2000, /* SWB<->FB */
+};
+static const opus_int32 mono_music_bandwidth_thresholds[8] = {
+ 12000, 1000, /* NB<->MB */
+ 15000, 1000, /* MB<->WB */
+ 18000, 2000, /* WB<->SWB */
+ 22000, 2000, /* SWB<->FB */
+};
+static const opus_int32 stereo_voice_bandwidth_thresholds[8] = {
+ 11000, 1000, /* NB<->MB */
+ 14000, 1000, /* MB<->WB */
+ 21000, 2000, /* WB<->SWB */
+ 28000, 2000, /* SWB<->FB */
+};
+static const opus_int32 stereo_music_bandwidth_thresholds[8] = {
+ 12000, 1000, /* NB<->MB */
+ 18000, 2000, /* MB<->WB */
+ 21000, 2000, /* WB<->SWB */
+ 30000, 2000, /* SWB<->FB */
+};
+/* Threshold bit-rates for switching between mono and stereo */
+static const opus_int32 stereo_voice_threshold = 30000;
+static const opus_int32 stereo_music_threshold = 30000;
+
+/* Threshold bit-rate for switching between SILK/hybrid and CELT-only */
+static const opus_int32 mode_thresholds[2][2] = {
+ /* voice */ /* music */
+ { 64000, 16000}, /* mono */
+ { 36000, 16000}, /* stereo */
+};
+
+int opus_encoder_get_size(int channels)
+{
+ int silkEncSizeBytes, celtEncSizeBytes;
+ int ret;
+ if (channels<1 || channels > 2)
+ return 0;
+ ret = silk_Get_Encoder_Size( &silkEncSizeBytes );
+ if (ret)
+ return 0;
+ silkEncSizeBytes = align(silkEncSizeBytes);
+ celtEncSizeBytes = celt_encoder_get_size(channels);
+ return align(sizeof(OpusEncoder))+silkEncSizeBytes+celtEncSizeBytes;
+}
+
+int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int application)
+{
+ void *silk_enc;
+ CELTEncoder *celt_enc;
+ int err;
+ int ret, silkEncSizeBytes;
+
+ if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)||
+ (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO
+ && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY))
+ return OPUS_BAD_ARG;
+
+ OPUS_CLEAR((char*)st, opus_encoder_get_size(channels));
+ /* Create SILK encoder */
+ ret = silk_Get_Encoder_Size( &silkEncSizeBytes );
+ if (ret)
+ return OPUS_BAD_ARG;
+ silkEncSizeBytes = align(silkEncSizeBytes);
+ st->silk_enc_offset = align(sizeof(OpusEncoder));
+ st->celt_enc_offset = st->silk_enc_offset+silkEncSizeBytes;
+ silk_enc = (char*)st+st->silk_enc_offset;
+ celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+
+ st->stream_channels = st->channels = channels;
+
+ st->Fs = Fs;
+
+ st->arch = opus_select_arch();
+
+ ret = silk_InitEncoder( silk_enc, st->arch, &st->silk_mode );
+ if(ret)return OPUS_INTERNAL_ERROR;
+
+ /* default SILK parameters */
+ st->silk_mode.nChannelsAPI = channels;
+ st->silk_mode.nChannelsInternal = channels;
+ st->silk_mode.API_sampleRate = st->Fs;
+ st->silk_mode.maxInternalSampleRate = 16000;
+ st->silk_mode.minInternalSampleRate = 8000;
+ st->silk_mode.desiredInternalSampleRate = 16000;
+ st->silk_mode.payloadSize_ms = 20;
+ st->silk_mode.bitRate = 25000;
+ st->silk_mode.packetLossPercentage = 0;
+ st->silk_mode.complexity = 9;
+ st->silk_mode.useInBandFEC = 0;
+ st->silk_mode.useDTX = 0;
+ st->silk_mode.useCBR = 0;
+ st->silk_mode.reducedDependency = 0;
+
+ /* Create CELT encoder */
+ /* Initialize CELT encoder */
+ err = celt_encoder_init(celt_enc, Fs, channels, st->arch);
+ if(err!=OPUS_OK)return OPUS_INTERNAL_ERROR;
+
+ celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(st->silk_mode.complexity));
+
+ st->use_vbr = 1;
+ /* Makes constrained VBR the default (safer for real-time use) */
+ st->vbr_constraint = 1;
+ st->user_bitrate_bps = OPUS_AUTO;
+ st->bitrate_bps = 3000+Fs*channels;
+ st->application = application;
+ st->signal_type = OPUS_AUTO;
+ st->user_bandwidth = OPUS_AUTO;
+ st->max_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ st->force_channels = OPUS_AUTO;
+ st->user_forced_mode = OPUS_AUTO;
+ st->voice_ratio = -1;
+ st->encoder_buffer = st->Fs/100;
+ st->lsb_depth = 24;
+ st->variable_duration = OPUS_FRAMESIZE_ARG;
+
+ /* Delay compensation of 4 ms (2.5 ms for SILK's extra look-ahead
+ + 1.5 ms for SILK resamplers and stereo prediction) */
+ st->delay_compensation = st->Fs/250;
+
+ st->hybrid_stereo_width_Q14 = 1 << 14;
+ st->prev_HB_gain = Q15ONE;
+ st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+ st->first = 1;
+ st->mode = MODE_HYBRID;
+ st->bandwidth = OPUS_BANDWIDTH_FULLBAND;
+
+#ifndef DISABLE_FLOAT_API
+ tonality_analysis_init(&st->analysis);
+#endif
+
+ return OPUS_OK;
+}
+
+static unsigned char gen_toc(int mode, int framerate, int bandwidth, int channels)
+{
+ int period;
+ unsigned char toc;
+ period = 0;
+ while (framerate < 400)
+ {
+ framerate <<= 1;
+ period++;
+ }
+ if (mode == MODE_SILK_ONLY)
+ {
+ toc = (bandwidth-OPUS_BANDWIDTH_NARROWBAND)<<5;
+ toc |= (period-2)<<3;
+ } else if (mode == MODE_CELT_ONLY)
+ {
+ int tmp = bandwidth-OPUS_BANDWIDTH_MEDIUMBAND;
+ if (tmp < 0)
+ tmp = 0;
+ toc = 0x80;
+ toc |= tmp << 5;
+ toc |= period<<3;
+ } else /* Hybrid */
+ {
+ toc = 0x60;
+ toc |= (bandwidth-OPUS_BANDWIDTH_SUPERWIDEBAND)<<4;
+ toc |= (period-2)<<3;
+ }
+ toc |= (channels==2)<<2;
+ return toc;
+}
+
+#ifndef FIXED_POINT
+static void silk_biquad_float(
+ const opus_val16 *in, /* I: Input signal */
+ const opus_int32 *B_Q28, /* I: MA coefficients [3] */
+ const opus_int32 *A_Q28, /* I: AR coefficients [2] */
+ opus_val32 *S, /* I/O: State vector [2] */
+ opus_val16 *out, /* O: Output signal */
+ const opus_int32 len, /* I: Signal length (must be even) */
+ int stride
+)
+{
+ /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
+ opus_int k;
+ opus_val32 vout;
+ opus_val32 inval;
+ opus_val32 A[2], B[3];
+
+ A[0] = (opus_val32)(A_Q28[0] * (1.f/((opus_int32)1<<28)));
+ A[1] = (opus_val32)(A_Q28[1] * (1.f/((opus_int32)1<<28)));
+ B[0] = (opus_val32)(B_Q28[0] * (1.f/((opus_int32)1<<28)));
+ B[1] = (opus_val32)(B_Q28[1] * (1.f/((opus_int32)1<<28)));
+ B[2] = (opus_val32)(B_Q28[2] * (1.f/((opus_int32)1<<28)));
+
+ /* Negate A_Q28 values and split in two parts */
+
+ for( k = 0; k < len; k++ ) {
+ /* S[ 0 ], S[ 1 ]: Q12 */
+ inval = in[ k*stride ];
+ vout = S[ 0 ] + B[0]*inval;
+
+ S[ 0 ] = S[1] - vout*A[0] + B[1]*inval;
+
+ S[ 1 ] = - vout*A[1] + B[2]*inval + VERY_SMALL;
+
+ /* Scale back to Q0 and saturate */
+ out[ k*stride ] = vout;
+ }
+}
+#endif
+
+static void hp_cutoff(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs)
+{
+ opus_int32 B_Q28[ 3 ], A_Q28[ 2 ];
+ opus_int32 Fc_Q19, r_Q28, r_Q22;
+
+ silk_assert( cutoff_Hz <= silk_int32_MAX / SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ) );
+ Fc_Q19 = silk_DIV32_16( silk_SMULBB( SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ), cutoff_Hz ), Fs/1000 );
+ silk_assert( Fc_Q19 > 0 && Fc_Q19 < 32768 );
+
+ r_Q28 = SILK_FIX_CONST( 1.0, 28 ) - silk_MUL( SILK_FIX_CONST( 0.92, 9 ), Fc_Q19 );
+
+ /* b = r * [ 1; -2; 1 ]; */
+ /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */
+ B_Q28[ 0 ] = r_Q28;
+ B_Q28[ 1 ] = silk_LSHIFT( -r_Q28, 1 );
+ B_Q28[ 2 ] = r_Q28;
+
+ /* -r * ( 2 - Fc * Fc ); */
+ r_Q22 = silk_RSHIFT( r_Q28, 6 );
+ A_Q28[ 0 ] = silk_SMULWW( r_Q22, silk_SMULWW( Fc_Q19, Fc_Q19 ) - SILK_FIX_CONST( 2.0, 22 ) );
+ A_Q28[ 1 ] = silk_SMULWW( r_Q22, r_Q22 );
+
+#ifdef FIXED_POINT
+ silk_biquad_alt( in, B_Q28, A_Q28, hp_mem, out, len, channels );
+ if( channels == 2 ) {
+ silk_biquad_alt( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels );
+ }
+#else
+ silk_biquad_float( in, B_Q28, A_Q28, hp_mem, out, len, channels );
+ if( channels == 2 ) {
+ silk_biquad_float( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels );
+ }
+#endif
+}
+
+#ifdef FIXED_POINT
+static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs)
+{
+ int c, i;
+ int shift;
+
+ /* Approximates -round(log2(4.*cutoff_Hz/Fs)) */
+ shift=celt_ilog2(Fs/(cutoff_Hz*3));
+ for (c=0;c<channels;c++)
+ {
+ for (i=0;i<len;i++)
+ {
+ opus_val32 x, tmp, y;
+ x = SHL32(EXTEND32(in[channels*i+c]), 15);
+ /* First stage */
+ tmp = x-hp_mem[2*c];
+ hp_mem[2*c] = hp_mem[2*c] + PSHR32(x - hp_mem[2*c], shift);
+ /* Second stage */
+ y = tmp - hp_mem[2*c+1];
+ hp_mem[2*c+1] = hp_mem[2*c+1] + PSHR32(tmp - hp_mem[2*c+1], shift);
+ out[channels*i+c] = EXTRACT16(SATURATE(PSHR32(y, 15), 32767));
+ }
+ }
+}
+
+#else
+static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs)
+{
+ int c, i;
+ float coef;
+
+ coef = 4.0f*cutoff_Hz/Fs;
+ for (c=0;c<channels;c++)
+ {
+ for (i=0;i<len;i++)
+ {
+ opus_val32 x, tmp, y;
+ x = in[channels*i+c];
+ /* First stage */
+ tmp = x-hp_mem[2*c];
+ hp_mem[2*c] = hp_mem[2*c] + coef*(x - hp_mem[2*c]) + VERY_SMALL;
+ /* Second stage */
+ y = tmp - hp_mem[2*c+1];
+ hp_mem[2*c+1] = hp_mem[2*c+1] + coef*(tmp - hp_mem[2*c+1]) + VERY_SMALL;
+ out[channels*i+c] = y;
+ }
+ }
+}
+#endif
+
+static void stereo_fade(const opus_val16 *in, opus_val16 *out, opus_val16 g1, opus_val16 g2,
+ int overlap48, int frame_size, int channels, const opus_val16 *window, opus_int32 Fs)
+{
+ int i;
+ int overlap;
+ int inc;
+ inc = 48000/Fs;
+ overlap=overlap48/inc;
+ g1 = Q15ONE-g1;
+ g2 = Q15ONE-g2;
+ for (i=0;i<overlap;i++)
+ {
+ opus_val32 diff;
+ opus_val16 g, w;
+ w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+ g = SHR32(MAC16_16(MULT16_16(w,g2),
+ Q15ONE-w, g1), 15);
+ diff = EXTRACT16(HALF32((opus_val32)in[i*channels] - (opus_val32)in[i*channels+1]));
+ diff = MULT16_16_Q15(g, diff);
+ out[i*channels] = out[i*channels] - diff;
+ out[i*channels+1] = out[i*channels+1] + diff;
+ }
+ for (;i<frame_size;i++)
+ {
+ opus_val32 diff;
+ diff = EXTRACT16(HALF32((opus_val32)in[i*channels] - (opus_val32)in[i*channels+1]));
+ diff = MULT16_16_Q15(g2, diff);
+ out[i*channels] = out[i*channels] - diff;
+ out[i*channels+1] = out[i*channels+1] + diff;
+ }
+}
+
+static void gain_fade(const opus_val16 *in, opus_val16 *out, opus_val16 g1, opus_val16 g2,
+ int overlap48, int frame_size, int channels, const opus_val16 *window, opus_int32 Fs)
+{
+ int i;
+ int inc;
+ int overlap;
+ int c;
+ inc = 48000/Fs;
+ overlap=overlap48/inc;
+ if (channels==1)
+ {
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 g, w;
+ w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+ g = SHR32(MAC16_16(MULT16_16(w,g2),
+ Q15ONE-w, g1), 15);
+ out[i] = MULT16_16_Q15(g, in[i]);
+ }
+ } else {
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 g, w;
+ w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+ g = SHR32(MAC16_16(MULT16_16(w,g2),
+ Q15ONE-w, g1), 15);
+ out[i*2] = MULT16_16_Q15(g, in[i*2]);
+ out[i*2+1] = MULT16_16_Q15(g, in[i*2+1]);
+ }
+ }
+ c=0;do {
+ for (i=overlap;i<frame_size;i++)
+ {
+ out[i*channels+c] = MULT16_16_Q15(g2, in[i*channels+c]);
+ }
+ }
+ while (++c<channels);
+}
+
+OpusEncoder *opus_encoder_create(opus_int32 Fs, int channels, int application, int *error)
+{
+ int ret;
+ OpusEncoder *st;
+ if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)||
+ (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO
+ && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ st = (OpusEncoder *)opus_alloc(opus_encoder_get_size(channels));
+ if (st == NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_encoder_init(st, Fs, channels, application);
+ if (error)
+ *error = ret;
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ return st;
+}
+
+static opus_int32 user_bitrate_to_bitrate(OpusEncoder *st, int frame_size, int max_data_bytes)
+{
+ if(!frame_size)frame_size=st->Fs/400;
+ if (st->user_bitrate_bps==OPUS_AUTO)
+ return 60*st->Fs/frame_size + st->Fs*st->channels;
+ else if (st->user_bitrate_bps==OPUS_BITRATE_MAX)
+ return max_data_bytes*8*st->Fs/frame_size;
+ else
+ return st->user_bitrate_bps;
+}
+
+#ifndef DISABLE_FLOAT_API
+/* Don't use more than 60 ms for the frame size analysis */
+#define MAX_DYNAMIC_FRAMESIZE 24
+/* Estimates how much the bitrate will be boosted based on the sub-frame energy */
+static float transient_boost(const float *E, const float *E_1, int LM, int maxM)
+{
+ int i;
+ int M;
+ float sumE=0, sumE_1=0;
+ float metric;
+
+ M = IMIN(maxM, (1<<LM)+1);
+ for (i=0;i<M;i++)
+ {
+ sumE += E[i];
+ sumE_1 += E_1[i];
+ }
+ metric = sumE*sumE_1/(M*M);
+ /*if (LM==3)
+ printf("%f\n", metric);*/
+ /*return metric>10 ? 1 : 0;*/
+ /*return MAX16(0,1-exp(-.25*(metric-2.)));*/
+ return MIN16(1,(float)sqrt(MAX16(0,.05f*(metric-2))));
+}
+
+/* Viterbi decoding trying to find the best frame size combination using look-ahead
+
+ State numbering:
+ 0: unused
+ 1: 2.5 ms
+ 2: 5 ms (#1)
+ 3: 5 ms (#2)
+ 4: 10 ms (#1)
+ 5: 10 ms (#2)
+ 6: 10 ms (#3)
+ 7: 10 ms (#4)
+ 8: 20 ms (#1)
+ 9: 20 ms (#2)
+ 10: 20 ms (#3)
+ 11: 20 ms (#4)
+ 12: 20 ms (#5)
+ 13: 20 ms (#6)
+ 14: 20 ms (#7)
+ 15: 20 ms (#8)
+*/
+static int transient_viterbi(const float *E, const float *E_1, int N, int frame_cost, int rate)
+{
+ int i;
+ float cost[MAX_DYNAMIC_FRAMESIZE][16];
+ int states[MAX_DYNAMIC_FRAMESIZE][16];
+ float best_cost;
+ int best_state;
+ float factor;
+ /* Take into account that we damp VBR in the 32 kb/s to 64 kb/s range. */
+ if (rate<80)
+ factor=0;
+ else if (rate>160)
+ factor=1;
+ else
+ factor = (rate-80.f)/80.f;
+ /* Makes variable framesize less aggressive at lower bitrates, but I can't
+ find any valid theoretical justification for this (other than it seems
+ to help) */
+ for (i=0;i<16;i++)
+ {
+ /* Impossible state */
+ states[0][i] = -1;
+ cost[0][i] = 1e10;
+ }
+ for (i=0;i<4;i++)
+ {
+ cost[0][1<<i] = (frame_cost + rate*(1<<i))*(1+factor*transient_boost(E, E_1, i, N+1));
+ states[0][1<<i] = i;
+ }
+ for (i=1;i<N;i++)
+ {
+ int j;
+
+ /* Follow continuations */
+ for (j=2;j<16;j++)
+ {
+ cost[i][j] = cost[i-1][j-1];
+ states[i][j] = j-1;
+ }
+
+ /* New frames */
+ for(j=0;j<4;j++)
+ {
+ int k;
+ float min_cost;
+ float curr_cost;
+ states[i][1<<j] = 1;
+ min_cost = cost[i-1][1];
+ for(k=1;k<4;k++)
+ {
+ float tmp = cost[i-1][(1<<(k+1))-1];
+ if (tmp < min_cost)
+ {
+ states[i][1<<j] = (1<<(k+1))-1;
+ min_cost = tmp;
+ }
+ }
+ curr_cost = (frame_cost + rate*(1<<j))*(1+factor*transient_boost(E+i, E_1+i, j, N-i+1));
+ cost[i][1<<j] = min_cost;
+ /* If part of the frame is outside the analysis window, only count part of the cost */
+ if (N-i < (1<<j))
+ cost[i][1<<j] += curr_cost*(float)(N-i)/(1<<j);
+ else
+ cost[i][1<<j] += curr_cost;
+ }
+ }
+
+ best_state=1;
+ best_cost = cost[N-1][1];
+ /* Find best end state (doesn't force a frame to end at N-1) */
+ for (i=2;i<16;i++)
+ {
+ if (cost[N-1][i]<best_cost)
+ {
+ best_cost = cost[N-1][i];
+ best_state = i;
+ }
+ }
+
+ /* Follow transitions back */
+ for (i=N-1;i>=0;i--)
+ {
+ /*printf("%d ", best_state);*/
+ best_state = states[i][best_state];
+ }
+ /*printf("%d\n", best_state);*/
+ return best_state;
+}
+
+static int optimize_framesize(const void *x, int len, int C, opus_int32 Fs,
+ int bitrate, opus_val16 tonality, float *mem, int buffering,
+ downmix_func downmix)
+{
+ int N;
+ int i;
+ float e[MAX_DYNAMIC_FRAMESIZE+4];
+ float e_1[MAX_DYNAMIC_FRAMESIZE+3];
+ opus_val32 memx;
+ int bestLM=0;
+ int subframe;
+ int pos;
+ int offset;
+ VARDECL(opus_val32, sub);
+
+ subframe = Fs/400;
+ ALLOC(sub, subframe, opus_val32);
+ e[0]=mem[0];
+ e_1[0]=1.f/(EPSILON+mem[0]);
+ if (buffering)
+ {
+ /* Consider the CELT delay when not in restricted-lowdelay */
+ /* We assume the buffering is between 2.5 and 5 ms */
+ offset = 2*subframe - buffering;
+ celt_assert(offset>=0 && offset <= subframe);
+ len -= offset;
+ e[1]=mem[1];
+ e_1[1]=1.f/(EPSILON+mem[1]);
+ e[2]=mem[2];
+ e_1[2]=1.f/(EPSILON+mem[2]);
+ pos = 3;
+ } else {
+ pos=1;
+ offset=0;
+ }
+ N=IMIN(len/subframe, MAX_DYNAMIC_FRAMESIZE);
+ /* Just silencing a warning, it's really initialized later */
+ memx = 0;
+ for (i=0;i<N;i++)
+ {
+ float tmp;
+ opus_val32 tmpx;
+ int j;
+ tmp=EPSILON;
+
+ downmix(x, sub, subframe, i*subframe+offset, 0, -2, C);
+ if (i==0)
+ memx = sub[0];
+ for (j=0;j<subframe;j++)
+ {
+ tmpx = sub[j];
+ tmp += (tmpx-memx)*(float)(tmpx-memx);
+ memx = tmpx;
+ }
+ e[i+pos] = tmp;
+ e_1[i+pos] = 1.f/tmp;
+ }
+ /* Hack to get 20 ms working with APPLICATION_AUDIO
+ The real problem is that the corresponding memory needs to use 1.5 ms
+ from this frame and 1 ms from the next frame */
+ e[i+pos] = e[i+pos-1];
+ if (buffering)
+ N=IMIN(MAX_DYNAMIC_FRAMESIZE, N+2);
+ bestLM = transient_viterbi(e, e_1, N, (int)((1.f+.5f*tonality)*(60*C+40)), bitrate/400);
+ mem[0] = e[1<<bestLM];
+ if (buffering)
+ {
+ mem[1] = e[(1<<bestLM)+1];
+ mem[2] = e[(1<<bestLM)+2];
+ }
+ return bestLM;
+}
+
+#endif
+
+#ifndef DISABLE_FLOAT_API
+#ifdef FIXED_POINT
+#define PCM2VAL(x) FLOAT2INT16(x)
+#else
+#define PCM2VAL(x) SCALEIN(x)
+#endif
+void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C)
+{
+ const float *x;
+ opus_val32 scale;
+ int j;
+ x = (const float *)_x;
+ for (j=0;j<subframe;j++)
+ sub[j] = PCM2VAL(x[(j+offset)*C+c1]);
+ if (c2>-1)
+ {
+ for (j=0;j<subframe;j++)
+ sub[j] += PCM2VAL(x[(j+offset)*C+c2]);
+ } else if (c2==-2)
+ {
+ int c;
+ for (c=1;c<C;c++)
+ {
+ for (j=0;j<subframe;j++)
+ sub[j] += PCM2VAL(x[(j+offset)*C+c]);
+ }
+ }
+#ifdef FIXED_POINT
+ scale = (1<<SIG_SHIFT);
+#else
+ scale = 1.f;
+#endif
+ if (C==-2)
+ scale /= C;
+ else
+ scale /= 2;
+ for (j=0;j<subframe;j++)
+ sub[j] *= scale;
+}
+#endif
+
+void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C)
+{
+ const opus_int16 *x;
+ opus_val32 scale;
+ int j;
+ x = (const opus_int16 *)_x;
+ for (j=0;j<subframe;j++)
+ sub[j] = x[(j+offset)*C+c1];
+ if (c2>-1)
+ {
+ for (j=0;j<subframe;j++)
+ sub[j] += x[(j+offset)*C+c2];
+ } else if (c2==-2)
+ {
+ int c;
+ for (c=1;c<C;c++)
+ {
+ for (j=0;j<subframe;j++)
+ sub[j] += x[(j+offset)*C+c];
+ }
+ }
+#ifdef FIXED_POINT
+ scale = (1<<SIG_SHIFT);
+#else
+ scale = 1.f/32768;
+#endif
+ if (C==-2)
+ scale /= C;
+ else
+ scale /= 2;
+ for (j=0;j<subframe;j++)
+ sub[j] *= scale;
+}
+
+opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs)
+{
+ int new_size;
+ if (frame_size<Fs/400)
+ return -1;
+ if (variable_duration == OPUS_FRAMESIZE_ARG)
+ new_size = frame_size;
+ else if (variable_duration == OPUS_FRAMESIZE_VARIABLE)
+ new_size = Fs/50;
+ else if (variable_duration >= OPUS_FRAMESIZE_2_5_MS && variable_duration <= OPUS_FRAMESIZE_60_MS)
+ new_size = IMIN(3*Fs/50, (Fs/400)<<(variable_duration-OPUS_FRAMESIZE_2_5_MS));
+ else
+ return -1;
+ if (new_size>frame_size)
+ return -1;
+ if (400*new_size!=Fs && 200*new_size!=Fs && 100*new_size!=Fs &&
+ 50*new_size!=Fs && 25*new_size!=Fs && 50*new_size!=3*Fs)
+ return -1;
+ return new_size;
+}
+
+opus_int32 compute_frame_size(const void *analysis_pcm, int frame_size,
+ int variable_duration, int C, opus_int32 Fs, int bitrate_bps,
+ int delay_compensation, downmix_func downmix
+#ifndef DISABLE_FLOAT_API
+ , float *subframe_mem
+#endif
+ )
+{
+#ifndef DISABLE_FLOAT_API
+ if (variable_duration == OPUS_FRAMESIZE_VARIABLE && frame_size >= Fs/200)
+ {
+ int LM = 3;
+ LM = optimize_framesize(analysis_pcm, frame_size, C, Fs, bitrate_bps,
+ 0, subframe_mem, delay_compensation, downmix);
+ while ((Fs/400<<LM)>frame_size)
+ LM--;
+ frame_size = (Fs/400<<LM);
+ } else
+#else
+ (void)analysis_pcm;
+ (void)C;
+ (void)bitrate_bps;
+ (void)delay_compensation;
+ (void)downmix;
+#endif
+ {
+ frame_size = frame_size_select(frame_size, variable_duration, Fs);
+ }
+ if (frame_size<0)
+ return -1;
+ return frame_size;
+}
+
+opus_val16 compute_stereo_width(const opus_val16 *pcm, int frame_size, opus_int32 Fs, StereoWidthState *mem)
+{
+ opus_val32 xx, xy, yy;
+ opus_val16 sqrt_xx, sqrt_yy;
+ opus_val16 qrrt_xx, qrrt_yy;
+ int frame_rate;
+ int i;
+ opus_val16 short_alpha;
+
+ frame_rate = Fs/frame_size;
+ short_alpha = Q15ONE - MULT16_16(25, Q15ONE)/IMAX(50,frame_rate);
+ xx=xy=yy=0;
+ /* Unroll by 4. The frame size is always a multiple of 4 *except* for
+ 2.5 ms frames at 12 kHz. Since this setting is very rare (and very
+ stupid), we just discard the last two samples. */
+ for (i=0;i<frame_size-3;i+=4)
+ {
+ opus_val32 pxx=0;
+ opus_val32 pxy=0;
+ opus_val32 pyy=0;
+ opus_val16 x, y;
+ x = pcm[2*i];
+ y = pcm[2*i+1];
+ pxx = SHR32(MULT16_16(x,x),2);
+ pxy = SHR32(MULT16_16(x,y),2);
+ pyy = SHR32(MULT16_16(y,y),2);
+ x = pcm[2*i+2];
+ y = pcm[2*i+3];
+ pxx += SHR32(MULT16_16(x,x),2);
+ pxy += SHR32(MULT16_16(x,y),2);
+ pyy += SHR32(MULT16_16(y,y),2);
+ x = pcm[2*i+4];
+ y = pcm[2*i+5];
+ pxx += SHR32(MULT16_16(x,x),2);
+ pxy += SHR32(MULT16_16(x,y),2);
+ pyy += SHR32(MULT16_16(y,y),2);
+ x = pcm[2*i+6];
+ y = pcm[2*i+7];
+ pxx += SHR32(MULT16_16(x,x),2);
+ pxy += SHR32(MULT16_16(x,y),2);
+ pyy += SHR32(MULT16_16(y,y),2);
+
+ xx += SHR32(pxx, 10);
+ xy += SHR32(pxy, 10);
+ yy += SHR32(pyy, 10);
+ }
+ mem->XX += MULT16_32_Q15(short_alpha, xx-mem->XX);
+ mem->XY += MULT16_32_Q15(short_alpha, xy-mem->XY);
+ mem->YY += MULT16_32_Q15(short_alpha, yy-mem->YY);
+ mem->XX = MAX32(0, mem->XX);
+ mem->XY = MAX32(0, mem->XY);
+ mem->YY = MAX32(0, mem->YY);
+ if (MAX32(mem->XX, mem->YY)>QCONST16(8e-4f, 18))
+ {
+ opus_val16 corr;
+ opus_val16 ldiff;
+ opus_val16 width;
+ sqrt_xx = celt_sqrt(mem->XX);
+ sqrt_yy = celt_sqrt(mem->YY);
+ qrrt_xx = celt_sqrt(sqrt_xx);
+ qrrt_yy = celt_sqrt(sqrt_yy);
+ /* Inter-channel correlation */
+ mem->XY = MIN32(mem->XY, sqrt_xx*sqrt_yy);
+ corr = SHR32(frac_div32(mem->XY,EPSILON+MULT16_16(sqrt_xx,sqrt_yy)),16);
+ /* Approximate loudness difference */
+ ldiff = MULT16_16(Q15ONE, ABS16(qrrt_xx-qrrt_yy))/(EPSILON+qrrt_xx+qrrt_yy);
+ width = MULT16_16_Q15(celt_sqrt(QCONST32(1.f,30)-MULT16_16(corr,corr)), ldiff);
+ /* Smoothing over one second */
+ mem->smoothed_width += (width-mem->smoothed_width)/frame_rate;
+ /* Peak follower */
+ mem->max_follower = MAX16(mem->max_follower-QCONST16(.02f,15)/frame_rate, mem->smoothed_width);
+ }
+ /*printf("%f %f %f %f %f ", corr/(float)Q15ONE, ldiff/(float)Q15ONE, width/(float)Q15ONE, mem->smoothed_width/(float)Q15ONE, mem->max_follower/(float)Q15ONE);*/
+ return EXTRACT16(MIN32(Q15ONE, MULT16_16(20, mem->max_follower)));
+}
+
+opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
+ unsigned char *data, opus_int32 out_data_bytes, int lsb_depth,
+ const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2,
+ int analysis_channels, downmix_func downmix, int float_api)
+{
+ void *silk_enc;
+ CELTEncoder *celt_enc;
+ int i;
+ int ret=0;
+ opus_int32 nBytes;
+ ec_enc enc;
+ int bytes_target;
+ int prefill=0;
+ int start_band = 0;
+ int redundancy = 0;
+ int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */
+ int celt_to_silk = 0;
+ VARDECL(opus_val16, pcm_buf);
+ int nb_compr_bytes;
+ int to_celt = 0;
+ opus_uint32 redundant_rng = 0;
+ int cutoff_Hz, hp_freq_smth1;
+ int voice_est; /* Probability of voice in Q7 */
+ opus_int32 equiv_rate;
+ int delay_compensation;
+ int frame_rate;
+ opus_int32 max_rate; /* Max bitrate we're allowed to use */
+ int curr_bandwidth;
+ opus_val16 HB_gain;
+ opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */
+ int total_buffer;
+ opus_val16 stereo_width;
+ const CELTMode *celt_mode;
+#ifndef DISABLE_FLOAT_API
+ AnalysisInfo analysis_info;
+ int analysis_read_pos_bak=-1;
+ int analysis_read_subframe_bak=-1;
+#endif
+ VARDECL(opus_val16, tmp_prefill);
+
+ ALLOC_STACK;
+
+ max_data_bytes = IMIN(1276, out_data_bytes);
+
+ st->rangeFinal = 0;
+ if ((!st->variable_duration && 400*frame_size != st->Fs && 200*frame_size != st->Fs && 100*frame_size != st->Fs &&
+ 50*frame_size != st->Fs && 25*frame_size != st->Fs && 50*frame_size != 3*st->Fs)
+ || (400*frame_size < st->Fs)
+ || max_data_bytes<=0
+ )
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ silk_enc = (char*)st+st->silk_enc_offset;
+ celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ delay_compensation = 0;
+ else
+ delay_compensation = st->delay_compensation;
+
+ lsb_depth = IMIN(lsb_depth, st->lsb_depth);
+
+ celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode));
+#ifndef DISABLE_FLOAT_API
+ analysis_info.valid = 0;
+#ifdef FIXED_POINT
+ if (st->silk_mode.complexity >= 10 && st->Fs==48000)
+#else
+ if (st->silk_mode.complexity >= 7 && st->Fs==48000)
+#endif
+ {
+ analysis_read_pos_bak = st->analysis.read_pos;
+ analysis_read_subframe_bak = st->analysis.read_subframe;
+ run_analysis(&st->analysis, celt_mode, analysis_pcm, analysis_size, frame_size,
+ c1, c2, analysis_channels, st->Fs,
+ lsb_depth, downmix, &analysis_info);
+ }
+#else
+ (void)analysis_pcm;
+ (void)analysis_size;
+#endif
+
+ st->voice_ratio = -1;
+
+#ifndef DISABLE_FLOAT_API
+ st->detected_bandwidth = 0;
+ if (analysis_info.valid)
+ {
+ int analysis_bandwidth;
+ if (st->signal_type == OPUS_AUTO)
+ st->voice_ratio = (int)floor(.5+100*(1-analysis_info.music_prob));
+
+ analysis_bandwidth = analysis_info.bandwidth;
+ if (analysis_bandwidth<=12)
+ st->detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ else if (analysis_bandwidth<=14)
+ st->detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ else if (analysis_bandwidth<=16)
+ st->detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ else if (analysis_bandwidth<=18)
+ st->detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+ else
+ st->detected_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ }
+#endif
+
+ if (st->channels==2 && st->force_channels!=1)
+ stereo_width = compute_stereo_width(pcm, frame_size, st->Fs, &st->width_mem);
+ else
+ stereo_width = 0;
+ total_buffer = delay_compensation;
+ st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes);
+
+ frame_rate = st->Fs/frame_size;
+ if (!st->use_vbr)
+ {
+ int cbrBytes;
+ /* Multiply by 3 to make sure the division is exact. */
+ int frame_rate3 = 3*st->Fs/frame_size;
+ /* We need to make sure that "int" values always fit in 16 bits. */
+ cbrBytes = IMIN( (3*st->bitrate_bps/8 + frame_rate3/2)/frame_rate3, max_data_bytes);
+ st->bitrate_bps = cbrBytes*(opus_int32)frame_rate3*8/3;
+ max_data_bytes = cbrBytes;
+ }
+ if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8
+ || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400)))
+ {
+ /*If the space is too low to do something useful, emit 'PLC' frames.*/
+ int tocmode = st->mode;
+ int bw = st->bandwidth == 0 ? OPUS_BANDWIDTH_NARROWBAND : st->bandwidth;
+ if (tocmode==0)
+ tocmode = MODE_SILK_ONLY;
+ if (frame_rate>100)
+ tocmode = MODE_CELT_ONLY;
+ if (frame_rate < 50)
+ tocmode = MODE_SILK_ONLY;
+ if(tocmode==MODE_SILK_ONLY&&bw>OPUS_BANDWIDTH_WIDEBAND)
+ bw=OPUS_BANDWIDTH_WIDEBAND;
+ else if (tocmode==MODE_CELT_ONLY&&bw==OPUS_BANDWIDTH_MEDIUMBAND)
+ bw=OPUS_BANDWIDTH_NARROWBAND;
+ else if (tocmode==MODE_HYBRID&&bw<=OPUS_BANDWIDTH_SUPERWIDEBAND)
+ bw=OPUS_BANDWIDTH_SUPERWIDEBAND;
+ data[0] = gen_toc(tocmode, frame_rate, bw, st->stream_channels);
+ ret = 1;
+ if (!st->use_vbr)
+ {
+ ret = opus_packet_pad(data, ret, max_data_bytes);
+ if (ret == OPUS_OK)
+ ret = max_data_bytes;
+ }
+ RESTORE_STACK;
+ return ret;
+ }
+ max_rate = frame_rate*max_data_bytes*8;
+
+ /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */
+ equiv_rate = st->bitrate_bps - (40*st->channels+20)*(st->Fs/frame_size - 50);
+
+ if (st->signal_type == OPUS_SIGNAL_VOICE)
+ voice_est = 127;
+ else if (st->signal_type == OPUS_SIGNAL_MUSIC)
+ voice_est = 0;
+ else if (st->voice_ratio >= 0)
+ {
+ voice_est = st->voice_ratio*327>>8;
+ /* For AUDIO, never be more than 90% confident of having speech */
+ if (st->application == OPUS_APPLICATION_AUDIO)
+ voice_est = IMIN(voice_est, 115);
+ } else if (st->application == OPUS_APPLICATION_VOIP)
+ voice_est = 115;
+ else
+ voice_est = 48;
+
+ if (st->force_channels!=OPUS_AUTO && st->channels == 2)
+ {
+ st->stream_channels = st->force_channels;
+ } else {
+#ifdef FUZZING
+ /* Random mono/stereo decision */
+ if (st->channels == 2 && (rand()&0x1F)==0)
+ st->stream_channels = 3-st->stream_channels;
+#else
+ /* Rate-dependent mono-stereo decision */
+ if (st->channels == 2)
+ {
+ opus_int32 stereo_threshold;
+ stereo_threshold = stereo_music_threshold + ((voice_est*voice_est*(stereo_voice_threshold-stereo_music_threshold))>>14);
+ if (st->stream_channels == 2)
+ stereo_threshold -= 1000;
+ else
+ stereo_threshold += 1000;
+ st->stream_channels = (equiv_rate > stereo_threshold) ? 2 : 1;
+ } else {
+ st->stream_channels = st->channels;
+ }
+#endif
+ }
+ equiv_rate = st->bitrate_bps - (40*st->stream_channels+20)*(st->Fs/frame_size - 50);
+
+ /* Mode selection depending on application and signal type */
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ {
+ st->mode = MODE_CELT_ONLY;
+ } else if (st->user_forced_mode == OPUS_AUTO)
+ {
+#ifdef FUZZING
+ /* Random mode switching */
+ if ((rand()&0xF)==0)
+ {
+ if ((rand()&0x1)==0)
+ st->mode = MODE_CELT_ONLY;
+ else
+ st->mode = MODE_SILK_ONLY;
+ } else {
+ if (st->prev_mode==MODE_CELT_ONLY)
+ st->mode = MODE_CELT_ONLY;
+ else
+ st->mode = MODE_SILK_ONLY;
+ }
+#else
+ opus_int32 mode_voice, mode_music;
+ opus_int32 threshold;
+
+ /* Interpolate based on stereo width */
+ mode_voice = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[0][0])
+ + MULT16_32_Q15(stereo_width,mode_thresholds[1][0]));
+ mode_music = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[1][1])
+ + MULT16_32_Q15(stereo_width,mode_thresholds[1][1]));
+ /* Interpolate based on speech/music probability */
+ threshold = mode_music + ((voice_est*voice_est*(mode_voice-mode_music))>>14);
+ /* Bias towards SILK for VoIP because of some useful features */
+ if (st->application == OPUS_APPLICATION_VOIP)
+ threshold += 8000;
+
+ /*printf("%f %d\n", stereo_width/(float)Q15ONE, threshold);*/
+ /* Hysteresis */
+ if (st->prev_mode == MODE_CELT_ONLY)
+ threshold -= 4000;
+ else if (st->prev_mode>0)
+ threshold += 4000;
+
+ st->mode = (equiv_rate >= threshold) ? MODE_CELT_ONLY: MODE_SILK_ONLY;
+
+ /* When FEC is enabled and there's enough packet loss, use SILK */
+ if (st->silk_mode.useInBandFEC && st->silk_mode.packetLossPercentage > (128-voice_est)>>4)
+ st->mode = MODE_SILK_ONLY;
+ /* When encoding voice and DTX is enabled, set the encoder to SILK mode (at least for now) */
+ if (st->silk_mode.useDTX && voice_est > 100)
+ st->mode = MODE_SILK_ONLY;
+#endif
+ } else {
+ st->mode = st->user_forced_mode;
+ }
+
+ /* Override the chosen mode to make sure we meet the requested frame size */
+ if (st->mode != MODE_CELT_ONLY && frame_size < st->Fs/100)
+ st->mode = MODE_CELT_ONLY;
+ if (st->lfe)
+ st->mode = MODE_CELT_ONLY;
+ /* If max_data_bytes represents less than 8 kb/s, switch to CELT-only mode */
+ if (max_data_bytes < (frame_rate > 50 ? 12000 : 8000)*frame_size / (st->Fs * 8))
+ st->mode = MODE_CELT_ONLY;
+
+ if (st->stream_channels == 1 && st->prev_channels ==2 && st->silk_mode.toMono==0
+ && st->mode != MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY)
+ {
+ /* Delay stereo->mono transition by two frames so that SILK can do a smooth downmix */
+ st->silk_mode.toMono = 1;
+ st->stream_channels = 2;
+ } else {
+ st->silk_mode.toMono = 0;
+ }
+
+ if (st->prev_mode > 0 &&
+ ((st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ||
+ (st->mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY)))
+ {
+ redundancy = 1;
+ celt_to_silk = (st->mode != MODE_CELT_ONLY);
+ if (!celt_to_silk)
+ {
+ /* Switch to SILK/hybrid if frame size is 10 ms or more*/
+ if (frame_size >= st->Fs/100)
+ {
+ st->mode = st->prev_mode;
+ to_celt = 1;
+ } else {
+ redundancy=0;
+ }
+ }
+ }
+ /* For the first frame at a new SILK bandwidth */
+ if (st->silk_bw_switch)
+ {
+ redundancy = 1;
+ celt_to_silk = 1;
+ st->silk_bw_switch = 0;
+ prefill=1;
+ }
+
+ if (redundancy)
+ {
+ /* Fair share of the max size allowed */
+ redundancy_bytes = IMIN(257, max_data_bytes*(opus_int32)(st->Fs/200)/(frame_size+st->Fs/200));
+ /* For VBR, target the actual bitrate (subject to the limit above) */
+ if (st->use_vbr)
+ redundancy_bytes = IMIN(redundancy_bytes, st->bitrate_bps/1600);
+ }
+
+ if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY)
+ {
+ silk_EncControlStruct dummy;
+ silk_InitEncoder( silk_enc, st->arch, &dummy);
+ prefill=1;
+ }
+
+ /* Automatic (rate-dependent) bandwidth selection */
+ if (st->mode == MODE_CELT_ONLY || st->first || st->silk_mode.allowBandwidthSwitch)
+ {
+ const opus_int32 *voice_bandwidth_thresholds, *music_bandwidth_thresholds;
+ opus_int32 bandwidth_thresholds[8];
+ int bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ opus_int32 equiv_rate2;
+
+ equiv_rate2 = equiv_rate;
+ if (st->mode != MODE_CELT_ONLY)
+ {
+ /* Adjust the threshold +/- 10% depending on complexity */
+ equiv_rate2 = equiv_rate2 * (45+st->silk_mode.complexity)/50;
+ /* CBR is less efficient by ~1 kb/s */
+ if (!st->use_vbr)
+ equiv_rate2 -= 1000;
+ }
+ if (st->channels==2 && st->force_channels!=1)
+ {
+ voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds;
+ music_bandwidth_thresholds = stereo_music_bandwidth_thresholds;
+ } else {
+ voice_bandwidth_thresholds = mono_voice_bandwidth_thresholds;
+ music_bandwidth_thresholds = mono_music_bandwidth_thresholds;
+ }
+ /* Interpolate bandwidth thresholds depending on voice estimation */
+ for (i=0;i<8;i++)
+ {
+ bandwidth_thresholds[i] = music_bandwidth_thresholds[i]
+ + ((voice_est*voice_est*(voice_bandwidth_thresholds[i]-music_bandwidth_thresholds[i]))>>14);
+ }
+ do {
+ int threshold, hysteresis;
+ threshold = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)];
+ hysteresis = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)+1];
+ if (!st->first)
+ {
+ if (st->bandwidth >= bandwidth)
+ threshold -= hysteresis;
+ else
+ threshold += hysteresis;
+ }
+ if (equiv_rate2 >= threshold)
+ break;
+ } while (--bandwidth>OPUS_BANDWIDTH_NARROWBAND);
+ st->bandwidth = bandwidth;
+ /* Prevents any transition to SWB/FB until the SILK layer has fully
+ switched to WB mode and turned the variable LP filter off */
+ if (!st->first && st->mode != MODE_CELT_ONLY && !st->silk_mode.inWBmodeWithoutVariableLP && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+ st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ }
+
+ if (st->bandwidth>st->max_bandwidth)
+ st->bandwidth = st->max_bandwidth;
+
+ if (st->user_bandwidth != OPUS_AUTO)
+ st->bandwidth = st->user_bandwidth;
+
+ /* This prevents us from using hybrid at unsafe CBR/max rates */
+ if (st->mode != MODE_CELT_ONLY && max_rate < 15000)
+ {
+ st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_WIDEBAND);
+ }
+
+ /* Prevents Opus from wasting bits on frequencies that are above
+ the Nyquist rate of the input signal */
+ if (st->Fs <= 24000 && st->bandwidth > OPUS_BANDWIDTH_SUPERWIDEBAND)
+ st->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+ if (st->Fs <= 16000 && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+ st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ if (st->Fs <= 12000 && st->bandwidth > OPUS_BANDWIDTH_MEDIUMBAND)
+ st->bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND)
+ st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+#ifndef DISABLE_FLOAT_API
+ /* Use detected bandwidth to reduce the encoded bandwidth. */
+ if (st->detected_bandwidth && st->user_bandwidth == OPUS_AUTO)
+ {
+ int min_detected_bandwidth;
+ /* Makes bandwidth detection more conservative just in case the detector
+ gets it wrong when we could have coded a high bandwidth transparently.
+ When operating in SILK/hybrid mode, we don't go below wideband to avoid
+ more complicated switches that require redundancy. */
+ if (equiv_rate <= 18000*st->stream_channels && st->mode == MODE_CELT_ONLY)
+ min_detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ else if (equiv_rate <= 24000*st->stream_channels && st->mode == MODE_CELT_ONLY)
+ min_detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ else if (equiv_rate <= 30000*st->stream_channels)
+ min_detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ else if (equiv_rate <= 44000*st->stream_channels)
+ min_detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+ else
+ min_detected_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+
+ st->detected_bandwidth = IMAX(st->detected_bandwidth, min_detected_bandwidth);
+ st->bandwidth = IMIN(st->bandwidth, st->detected_bandwidth);
+ }
+#endif
+ celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(lsb_depth));
+
+ /* CELT mode doesn't support mediumband, use wideband instead */
+ if (st->mode == MODE_CELT_ONLY && st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+ st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ if (st->lfe)
+ st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+
+ /* Can't support higher than wideband for >20 ms frames */
+ if (frame_size > st->Fs/50 && (st->mode == MODE_CELT_ONLY || st->bandwidth > OPUS_BANDWIDTH_WIDEBAND))
+ {
+ VARDECL(unsigned char, tmp_data);
+ int nb_frames;
+ int bak_mode, bak_bandwidth, bak_channels, bak_to_mono;
+ VARDECL(OpusRepacketizer, rp);
+ opus_int32 bytes_per_frame;
+ opus_int32 repacketize_len;
+
+#ifndef DISABLE_FLOAT_API
+ if (analysis_read_pos_bak!= -1)
+ {
+ st->analysis.read_pos = analysis_read_pos_bak;
+ st->analysis.read_subframe = analysis_read_subframe_bak;
+ }
+#endif
+
+ nb_frames = frame_size > st->Fs/25 ? 3 : 2;
+ bytes_per_frame = IMIN(1276,(out_data_bytes-3)/nb_frames);
+
+ ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char);
+
+ ALLOC(rp, 1, OpusRepacketizer);
+ opus_repacketizer_init(rp);
+
+ bak_mode = st->user_forced_mode;
+ bak_bandwidth = st->user_bandwidth;
+ bak_channels = st->force_channels;
+
+ st->user_forced_mode = st->mode;
+ st->user_bandwidth = st->bandwidth;
+ st->force_channels = st->stream_channels;
+ bak_to_mono = st->silk_mode.toMono;
+
+ if (bak_to_mono)
+ st->force_channels = 1;
+ else
+ st->prev_channels = st->stream_channels;
+ for (i=0;i<nb_frames;i++)
+ {
+ int tmp_len;
+ st->silk_mode.toMono = 0;
+ /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */
+ if (to_celt && i==nb_frames-1)
+ st->user_forced_mode = MODE_CELT_ONLY;
+ tmp_len = opus_encode_native(st, pcm+i*(st->channels*st->Fs/50), st->Fs/50,
+ tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth,
+ NULL, 0, c1, c2, analysis_channels, downmix, float_api);
+ if (tmp_len<0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ ret = opus_repacketizer_cat(rp, tmp_data+i*bytes_per_frame, tmp_len);
+ if (ret<0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ }
+ if (st->use_vbr)
+ repacketize_len = out_data_bytes;
+ else
+ repacketize_len = IMIN(3*st->bitrate_bps/(3*8*50/nb_frames), out_data_bytes);
+ ret = opus_repacketizer_out_range_impl(rp, 0, nb_frames, data, repacketize_len, 0, !st->use_vbr);
+ if (ret<0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ st->user_forced_mode = bak_mode;
+ st->user_bandwidth = bak_bandwidth;
+ st->force_channels = bak_channels;
+ st->silk_mode.toMono = bak_to_mono;
+ RESTORE_STACK;
+ return ret;
+ }
+ curr_bandwidth = st->bandwidth;
+
+ /* Chooses the appropriate mode for speech
+ *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */
+ if (st->mode == MODE_SILK_ONLY && curr_bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+ st->mode = MODE_HYBRID;
+ if (st->mode == MODE_HYBRID && curr_bandwidth <= OPUS_BANDWIDTH_WIDEBAND)
+ st->mode = MODE_SILK_ONLY;
+
+ /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, curr_bandwidth); */
+ bytes_target = IMIN(max_data_bytes-redundancy_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1;
+
+ data += 1;
+
+ ec_enc_init(&enc, data, max_data_bytes-1);
+
+ ALLOC(pcm_buf, (total_buffer+frame_size)*st->channels, opus_val16);
+ OPUS_COPY(pcm_buf, &st->delay_buffer[(st->encoder_buffer-total_buffer)*st->channels], total_buffer*st->channels);
+
+ if (st->mode == MODE_CELT_ONLY)
+ hp_freq_smth1 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+ else
+ hp_freq_smth1 = ((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.variable_HP_smth1_Q15;
+
+ st->variable_HP_smth2_Q15 = silk_SMLAWB( st->variable_HP_smth2_Q15,
+ hp_freq_smth1 - st->variable_HP_smth2_Q15, SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) );
+
+ /* convert from log scale to Hertz */
+ cutoff_Hz = silk_log2lin( silk_RSHIFT( st->variable_HP_smth2_Q15, 8 ) );
+
+ if (st->application == OPUS_APPLICATION_VOIP)
+ {
+ hp_cutoff(pcm, cutoff_Hz, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs);
+ } else {
+ dc_reject(pcm, 3, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs);
+ }
+#ifndef FIXED_POINT
+ if (float_api)
+ {
+ opus_val32 sum;
+ sum = celt_inner_prod(&pcm_buf[total_buffer*st->channels], &pcm_buf[total_buffer*st->channels], frame_size*st->channels, st->arch);
+ /* This should filter out both NaNs and ridiculous signals that could
+ cause NaNs further down. */
+ if (!(sum < 1e9f) || celt_isnan(sum))
+ {
+ OPUS_CLEAR(&pcm_buf[total_buffer*st->channels], frame_size*st->channels);
+ st->hp_mem[0] = st->hp_mem[1] = st->hp_mem[2] = st->hp_mem[3] = 0;
+ }
+ }
+#endif
+
+
+ /* SILK processing */
+ HB_gain = Q15ONE;
+ if (st->mode != MODE_CELT_ONLY)
+ {
+ opus_int32 total_bitRate, celt_rate;
+#ifdef FIXED_POINT
+ const opus_int16 *pcm_silk;
+#else
+ VARDECL(opus_int16, pcm_silk);
+ ALLOC(pcm_silk, st->channels*frame_size, opus_int16);
+#endif
+
+ /* Distribute bits between SILK and CELT */
+ total_bitRate = 8 * bytes_target * frame_rate;
+ if( st->mode == MODE_HYBRID ) {
+ int HB_gain_ref;
+ /* Base rate for SILK */
+ st->silk_mode.bitRate = st->stream_channels * ( 5000 + 1000 * ( st->Fs == 100 * frame_size ) );
+ if( curr_bandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND ) {
+ /* SILK gets 2/3 of the remaining bits */
+ st->silk_mode.bitRate += ( total_bitRate - st->silk_mode.bitRate ) * 2 / 3;
+ } else { /* FULLBAND */
+ /* SILK gets 3/5 of the remaining bits */
+ st->silk_mode.bitRate += ( total_bitRate - st->silk_mode.bitRate ) * 3 / 5;
+ }
+ /* Don't let SILK use more than 80% */
+ if( st->silk_mode.bitRate > total_bitRate * 4/5 ) {
+ st->silk_mode.bitRate = total_bitRate * 4/5;
+ }
+ if (!st->energy_masking)
+ {
+ /* Increasingly attenuate high band when it gets allocated fewer bits */
+ celt_rate = total_bitRate - st->silk_mode.bitRate;
+ HB_gain_ref = (curr_bandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND) ? 3000 : 3600;
+ HB_gain = SHL32((opus_val32)celt_rate, 9) / SHR32((opus_val32)celt_rate + st->stream_channels * HB_gain_ref, 6);
+ HB_gain = HB_gain < (opus_val32)Q15ONE*6/7 ? HB_gain + Q15ONE/7 : Q15ONE;
+ }
+ } else {
+ /* SILK gets all bits */
+ st->silk_mode.bitRate = total_bitRate;
+ }
+
+ /* Surround masking for SILK */
+ if (st->energy_masking && st->use_vbr && !st->lfe)
+ {
+ opus_val32 mask_sum=0;
+ opus_val16 masking_depth;
+ opus_int32 rate_offset;
+ int c;
+ int end = 17;
+ opus_int16 srate = 16000;
+ if (st->bandwidth == OPUS_BANDWIDTH_NARROWBAND)
+ {
+ end = 13;
+ srate = 8000;
+ } else if (st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+ {
+ end = 15;
+ srate = 12000;
+ }
+ for (c=0;c<st->channels;c++)
+ {
+ for(i=0;i<end;i++)
+ {
+ opus_val16 mask;
+ mask = MAX16(MIN16(st->energy_masking[21*c+i],
+ QCONST16(.5f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT));
+ if (mask > 0)
+ mask = HALF16(mask);
+ mask_sum += mask;
+ }
+ }
+ /* Conservative rate reduction, we cut the masking in half */
+ masking_depth = mask_sum / end*st->channels;
+ masking_depth += QCONST16(.2f, DB_SHIFT);
+ rate_offset = (opus_int32)PSHR32(MULT16_16(srate, masking_depth), DB_SHIFT);
+ rate_offset = MAX32(rate_offset, -2*st->silk_mode.bitRate/3);
+ /* Split the rate change between the SILK and CELT part for hybrid. */
+ if (st->bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND || st->bandwidth==OPUS_BANDWIDTH_FULLBAND)
+ st->silk_mode.bitRate += 3*rate_offset/5;
+ else
+ st->silk_mode.bitRate += rate_offset;
+ bytes_target += rate_offset * frame_size / (8 * st->Fs);
+ }
+
+ st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs;
+ st->silk_mode.nChannelsAPI = st->channels;
+ st->silk_mode.nChannelsInternal = st->stream_channels;
+ if (curr_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+ st->silk_mode.desiredInternalSampleRate = 8000;
+ } else if (curr_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+ st->silk_mode.desiredInternalSampleRate = 12000;
+ } else {
+ silk_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND );
+ st->silk_mode.desiredInternalSampleRate = 16000;
+ }
+ if( st->mode == MODE_HYBRID ) {
+ /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */
+ st->silk_mode.minInternalSampleRate = 16000;
+ } else {
+ st->silk_mode.minInternalSampleRate = 8000;
+ }
+
+ if (st->mode == MODE_SILK_ONLY)
+ {
+ opus_int32 effective_max_rate = max_rate;
+ st->silk_mode.maxInternalSampleRate = 16000;
+ if (frame_rate > 50)
+ effective_max_rate = effective_max_rate*2/3;
+ if (effective_max_rate < 13000)
+ {
+ st->silk_mode.maxInternalSampleRate = 12000;
+ st->silk_mode.desiredInternalSampleRate = IMIN(12000, st->silk_mode.desiredInternalSampleRate);
+ }
+ if (effective_max_rate < 9600)
+ {
+ st->silk_mode.maxInternalSampleRate = 8000;
+ st->silk_mode.desiredInternalSampleRate = IMIN(8000, st->silk_mode.desiredInternalSampleRate);
+ }
+ } else {
+ st->silk_mode.maxInternalSampleRate = 16000;
+ }
+
+ st->silk_mode.useCBR = !st->use_vbr;
+
+ /* Call SILK encoder for the low band */
+ nBytes = IMIN(1275, max_data_bytes-1-redundancy_bytes);
+
+ st->silk_mode.maxBits = nBytes*8;
+ /* Only allow up to 90% of the bits for hybrid mode*/
+ if (st->mode == MODE_HYBRID)
+ st->silk_mode.maxBits = (opus_int32)st->silk_mode.maxBits*9/10;
+ if (st->silk_mode.useCBR)
+ {
+ st->silk_mode.maxBits = (st->silk_mode.bitRate * frame_size / (st->Fs * 8))*8;
+ /* Reduce the initial target to make it easier to reach the CBR rate */
+ st->silk_mode.bitRate = IMAX(1, st->silk_mode.bitRate-2000);
+ }
+
+ if (prefill)
+ {
+ opus_int32 zero=0;
+ int prefill_offset;
+ /* Use a smooth onset for the SILK prefill to avoid the encoder trying to encode
+ a discontinuity. The exact location is what we need to avoid leaving any "gap"
+ in the audio when mixing with the redundant CELT frame. Here we can afford to
+ overwrite st->delay_buffer because the only thing that uses it before it gets
+ rewritten is tmp_prefill[] and even then only the part after the ramp really
+ gets used (rather than sent to the encoder and discarded) */
+ prefill_offset = st->channels*(st->encoder_buffer-st->delay_compensation-st->Fs/400);
+ gain_fade(st->delay_buffer+prefill_offset, st->delay_buffer+prefill_offset,
+ 0, Q15ONE, celt_mode->overlap, st->Fs/400, st->channels, celt_mode->window, st->Fs);
+ OPUS_CLEAR(st->delay_buffer, prefill_offset);
+#ifdef FIXED_POINT
+ pcm_silk = st->delay_buffer;
+#else
+ for (i=0;i<st->encoder_buffer*st->channels;i++)
+ pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]);
+#endif
+ silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1 );
+ }
+
+#ifdef FIXED_POINT
+ pcm_silk = pcm_buf+total_buffer*st->channels;
+#else
+ for (i=0;i<frame_size*st->channels;i++)
+ pcm_silk[i] = FLOAT2INT16(pcm_buf[total_buffer*st->channels + i]);
+#endif
+ ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 );
+ if( ret ) {
+ /*fprintf (stderr, "SILK encode error: %d\n", ret);*/
+ /* Handle error */
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ if (nBytes==0)
+ {
+ st->rangeFinal = 0;
+ data[-1] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels);
+ RESTORE_STACK;
+ return 1;
+ }
+ /* Extract SILK internal bandwidth for signaling in first byte */
+ if( st->mode == MODE_SILK_ONLY ) {
+ if( st->silk_mode.internalSampleRate == 8000 ) {
+ curr_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ } else if( st->silk_mode.internalSampleRate == 12000 ) {
+ curr_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ } else if( st->silk_mode.internalSampleRate == 16000 ) {
+ curr_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ }
+ } else {
+ silk_assert( st->silk_mode.internalSampleRate == 16000 );
+ }
+
+ st->silk_mode.opusCanSwitch = st->silk_mode.switchReady;
+ /* FIXME: How do we allocate the redundancy for CBR? */
+ if (st->silk_mode.opusCanSwitch)
+ {
+ redundancy = 1;
+ celt_to_silk = 0;
+ st->silk_bw_switch = 1;
+ }
+ }
+
+ /* CELT processing */
+ {
+ int endband=21;
+
+ switch(curr_bandwidth)
+ {
+ case OPUS_BANDWIDTH_NARROWBAND:
+ endband = 13;
+ break;
+ case OPUS_BANDWIDTH_MEDIUMBAND:
+ case OPUS_BANDWIDTH_WIDEBAND:
+ endband = 17;
+ break;
+ case OPUS_BANDWIDTH_SUPERWIDEBAND:
+ endband = 19;
+ break;
+ case OPUS_BANDWIDTH_FULLBAND:
+ endband = 21;
+ break;
+ }
+ celt_encoder_ctl(celt_enc, CELT_SET_END_BAND(endband));
+ celt_encoder_ctl(celt_enc, CELT_SET_CHANNELS(st->stream_channels));
+ }
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX));
+ if (st->mode != MODE_SILK_ONLY)
+ {
+ opus_val32 celt_pred=2;
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0));
+ /* We may still decide to disable prediction later */
+ if (st->silk_mode.reducedDependency)
+ celt_pred = 0;
+ celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(celt_pred));
+
+ if (st->mode == MODE_HYBRID)
+ {
+ int len;
+
+ len = (ec_tell(&enc)+7)>>3;
+ if (redundancy)
+ len += st->mode == MODE_HYBRID ? 3 : 1;
+ if( st->use_vbr ) {
+ nb_compr_bytes = len + bytes_target - (st->silk_mode.bitRate * frame_size) / (8 * st->Fs);
+ } else {
+ /* check if SILK used up too much */
+ nb_compr_bytes = len > bytes_target ? len : bytes_target;
+ }
+ } else {
+ if (st->use_vbr)
+ {
+ opus_int32 bonus=0;
+#ifndef DISABLE_FLOAT_API
+ if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != st->Fs/50)
+ {
+ bonus = (60*st->stream_channels+40)*(st->Fs/frame_size-50);
+ if (analysis_info.valid)
+ bonus = (opus_int32)(bonus*(1.f+.5f*analysis_info.tonality));
+ }
+#endif
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1));
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint));
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps+bonus));
+ nb_compr_bytes = max_data_bytes-1-redundancy_bytes;
+ } else {
+ nb_compr_bytes = bytes_target;
+ }
+ }
+
+ } else {
+ nb_compr_bytes = 0;
+ }
+
+ ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16);
+ if (st->mode != MODE_SILK_ONLY && st->mode != st->prev_mode && st->prev_mode > 0)
+ {
+ OPUS_COPY(tmp_prefill, &st->delay_buffer[(st->encoder_buffer-total_buffer-st->Fs/400)*st->channels], st->channels*st->Fs/400);
+ }
+
+ if (st->channels*(st->encoder_buffer-(frame_size+total_buffer)) > 0)
+ {
+ OPUS_MOVE(st->delay_buffer, &st->delay_buffer[st->channels*frame_size], st->channels*(st->encoder_buffer-frame_size-total_buffer));
+ OPUS_COPY(&st->delay_buffer[st->channels*(st->encoder_buffer-frame_size-total_buffer)],
+ &pcm_buf[0],
+ (frame_size+total_buffer)*st->channels);
+ } else {
+ OPUS_COPY(st->delay_buffer, &pcm_buf[(frame_size+total_buffer-st->encoder_buffer)*st->channels], st->encoder_buffer*st->channels);
+ }
+ /* gain_fade() and stereo_fade() need to be after the buffer copying
+ because we don't want any of this to affect the SILK part */
+ if( st->prev_HB_gain < Q15ONE || HB_gain < Q15ONE ) {
+ gain_fade(pcm_buf, pcm_buf,
+ st->prev_HB_gain, HB_gain, celt_mode->overlap, frame_size, st->channels, celt_mode->window, st->Fs);
+ }
+ st->prev_HB_gain = HB_gain;
+ if (st->mode != MODE_HYBRID || st->stream_channels==1)
+ st->silk_mode.stereoWidth_Q14 = IMIN((1<<14),2*IMAX(0,equiv_rate-30000));
+ if( !st->energy_masking && st->channels == 2 ) {
+ /* Apply stereo width reduction (at low bitrates) */
+ if( st->hybrid_stereo_width_Q14 < (1 << 14) || st->silk_mode.stereoWidth_Q14 < (1 << 14) ) {
+ opus_val16 g1, g2;
+ g1 = st->hybrid_stereo_width_Q14;
+ g2 = (opus_val16)(st->silk_mode.stereoWidth_Q14);
+#ifdef FIXED_POINT
+ g1 = g1==16384 ? Q15ONE : SHL16(g1,1);
+ g2 = g2==16384 ? Q15ONE : SHL16(g2,1);
+#else
+ g1 *= (1.f/16384);
+ g2 *= (1.f/16384);
+#endif
+ stereo_fade(pcm_buf, pcm_buf, g1, g2, celt_mode->overlap,
+ frame_size, st->channels, celt_mode->window, st->Fs);
+ st->hybrid_stereo_width_Q14 = st->silk_mode.stereoWidth_Q14;
+ }
+ }
+
+ if ( st->mode != MODE_CELT_ONLY && ec_tell(&enc)+17+20*(st->mode == MODE_HYBRID) <= 8*(max_data_bytes-1))
+ {
+ /* For SILK mode, the redundancy is inferred from the length */
+ if (st->mode == MODE_HYBRID && (redundancy || ec_tell(&enc)+37 <= 8*nb_compr_bytes))
+ ec_enc_bit_logp(&enc, redundancy, 12);
+ if (redundancy)
+ {
+ int max_redundancy;
+ ec_enc_bit_logp(&enc, celt_to_silk, 1);
+ if (st->mode == MODE_HYBRID)
+ max_redundancy = (max_data_bytes-1)-nb_compr_bytes;
+ else
+ max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+7)>>3);
+ /* Target the same bit-rate for redundancy as for the rest,
+ up to a max of 257 bytes */
+ redundancy_bytes = IMIN(max_redundancy, st->bitrate_bps/1600);
+ redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes));
+ if (st->mode == MODE_HYBRID)
+ ec_enc_uint(&enc, redundancy_bytes-2, 256);
+ }
+ } else {
+ redundancy = 0;
+ }
+
+ if (!redundancy)
+ {
+ st->silk_bw_switch = 0;
+ redundancy_bytes = 0;
+ }
+ if (st->mode != MODE_CELT_ONLY)start_band=17;
+
+ if (st->mode == MODE_SILK_ONLY)
+ {
+ ret = (ec_tell(&enc)+7)>>3;
+ ec_enc_done(&enc);
+ nb_compr_bytes = ret;
+ } else {
+ nb_compr_bytes = IMIN((max_data_bytes-1)-redundancy_bytes, nb_compr_bytes);
+ ec_enc_shrink(&enc, nb_compr_bytes);
+ }
+
+#ifndef DISABLE_FLOAT_API
+ if (redundancy || st->mode != MODE_SILK_ONLY)
+ celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(&analysis_info));
+#endif
+
+ /* 5 ms redundant frame for CELT->SILK */
+ if (redundancy && celt_to_silk)
+ {
+ int err;
+ celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0));
+ err = celt_encode_with_ec(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes, NULL);
+ if (err < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng));
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+ }
+
+ celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(start_band));
+
+ if (st->mode != MODE_SILK_ONLY)
+ {
+ if (st->mode != st->prev_mode && st->prev_mode > 0)
+ {
+ unsigned char dummy[2];
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+
+ /* Prefilling */
+ celt_encode_with_ec(celt_enc, tmp_prefill, st->Fs/400, dummy, 2, NULL);
+ celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
+ }
+ /* If false, we already busted the budget and we'll end up with a "PLC packet" */
+ if (ec_tell(&enc) <= 8*nb_compr_bytes)
+ {
+ ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc);
+ if (ret < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ /* 5 ms redundant frame for SILK->CELT */
+ if (redundancy && !celt_to_silk)
+ {
+ int err;
+ unsigned char dummy[2];
+ int N2, N4;
+ N2 = st->Fs/200;
+ N4 = st->Fs/400;
+
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+ celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
+ celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
+
+ /* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */
+ celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, dummy, 2, NULL);
+
+ err = celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes, NULL);
+ if (err < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng));
+ }
+
+
+
+ /* Signalling the mode in the first byte */
+ data--;
+ data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels);
+
+ st->rangeFinal = enc.rng ^ redundant_rng;
+
+ if (to_celt)
+ st->prev_mode = MODE_CELT_ONLY;
+ else
+ st->prev_mode = st->mode;
+ st->prev_channels = st->stream_channels;
+ st->prev_framesize = frame_size;
+
+ st->first = 0;
+
+ /* In the unlikely case that the SILK encoder busted its target, tell
+ the decoder to call the PLC */
+ if (ec_tell(&enc) > (max_data_bytes-1)*8)
+ {
+ if (max_data_bytes < 2)
+ {
+ RESTORE_STACK;
+ return OPUS_BUFFER_TOO_SMALL;
+ }
+ data[1] = 0;
+ ret = 1;
+ st->rangeFinal = 0;
+ } else if (st->mode==MODE_SILK_ONLY&&!redundancy)
+ {
+ /*When in LPC only mode it's perfectly
+ reasonable to strip off trailing zero bytes as
+ the required range decoder behavior is to
+ fill these in. This can't be done when the MDCT
+ modes are used because the decoder needs to know
+ the actual length for allocation purposes.*/
+ while(ret>2&&data[ret]==0)ret--;
+ }
+ /* Count ToC and redundancy */
+ ret += 1+redundancy_bytes;
+ if (!st->use_vbr)
+ {
+ if (opus_packet_pad(data, ret, max_data_bytes) != OPUS_OK)
+
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ ret = max_data_bytes;
+ }
+ RESTORE_STACK;
+ return ret;
+}
+
+#ifdef FIXED_POINT
+
+#ifndef DISABLE_FLOAT_API
+opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 max_data_bytes)
+{
+ int i, ret;
+ int frame_size;
+ int delay_compensation;
+ VARDECL(opus_int16, in);
+ ALLOC_STACK;
+
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ delay_compensation = 0;
+ else
+ delay_compensation = st->delay_compensation;
+ frame_size = compute_frame_size(pcm, analysis_frame_size,
+ st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+ delay_compensation, downmix_float, st->analysis.subframe_mem);
+
+ ALLOC(in, frame_size*st->channels, opus_int16);
+
+ for (i=0;i<frame_size*st->channels;i++)
+ in[i] = FLOAT2INT16(pcm[i]);
+ ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16,
+ pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1);
+ RESTORE_STACK;
+ return ret;
+}
+#endif
+
+opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 out_data_bytes)
+{
+ int frame_size;
+ int delay_compensation;
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ delay_compensation = 0;
+ else
+ delay_compensation = st->delay_compensation;
+ frame_size = compute_frame_size(pcm, analysis_frame_size,
+ st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+ delay_compensation, downmix_int
+#ifndef DISABLE_FLOAT_API
+ , st->analysis.subframe_mem
+#endif
+ );
+ return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 16,
+ pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0);
+}
+
+#else
+opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 max_data_bytes)
+{
+ int i, ret;
+ int frame_size;
+ int delay_compensation;
+ VARDECL(float, in);
+ ALLOC_STACK;
+
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ delay_compensation = 0;
+ else
+ delay_compensation = st->delay_compensation;
+ frame_size = compute_frame_size(pcm, analysis_frame_size,
+ st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+ delay_compensation, downmix_int, st->analysis.subframe_mem);
+
+ ALLOC(in, frame_size*st->channels, float);
+
+ for (i=0;i<frame_size*st->channels;i++)
+ in[i] = (1.0f/32768)*pcm[i];
+ ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16,
+ pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0);
+ RESTORE_STACK;
+ return ret;
+}
+opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 out_data_bytes)
+{
+ int frame_size;
+ int delay_compensation;
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ delay_compensation = 0;
+ else
+ delay_compensation = st->delay_compensation;
+ frame_size = compute_frame_size(pcm, analysis_frame_size,
+ st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+ delay_compensation, downmix_float, st->analysis.subframe_mem);
+ return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24,
+ pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1);
+}
+#endif
+
+
+int opus_encoder_ctl(OpusEncoder *st, int request, ...)
+{
+ int ret;
+ CELTEncoder *celt_enc;
+ va_list ap;
+
+ ret = OPUS_OK;
+ va_start(ap, request);
+
+ celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+
+ switch (request)
+ {
+ case OPUS_SET_APPLICATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if ( (value != OPUS_APPLICATION_VOIP && value != OPUS_APPLICATION_AUDIO
+ && value != OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ || (!st->first && st->application != value))
+ {
+ ret = OPUS_BAD_ARG;
+ break;
+ }
+ st->application = value;
+ }
+ break;
+ case OPUS_GET_APPLICATION_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->application;
+ }
+ break;
+ case OPUS_SET_BITRATE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX)
+ {
+ if (value <= 0)
+ goto bad_arg;
+ else if (value <= 500)
+ value = 500;
+ else if (value > (opus_int32)300000*st->channels)
+ value = (opus_int32)300000*st->channels;
+ }
+ st->user_bitrate_bps = value;
+ }
+ break;
+ case OPUS_GET_BITRATE_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = user_bitrate_to_bitrate(st, st->prev_framesize, 1276);
+ }
+ break;
+ case OPUS_SET_FORCE_CHANNELS_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if((value<1 || value>st->channels) && value != OPUS_AUTO)
+ {
+ goto bad_arg;
+ }
+ st->force_channels = value;
+ }
+ break;
+ case OPUS_GET_FORCE_CHANNELS_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->force_channels;
+ }
+ break;
+ case OPUS_SET_MAX_BANDWIDTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND)
+ {
+ goto bad_arg;
+ }
+ st->max_bandwidth = value;
+ if (st->max_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+ st->silk_mode.maxInternalSampleRate = 8000;
+ } else if (st->max_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+ st->silk_mode.maxInternalSampleRate = 12000;
+ } else {
+ st->silk_mode.maxInternalSampleRate = 16000;
+ }
+ }
+ break;
+ case OPUS_GET_MAX_BANDWIDTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->max_bandwidth;
+ }
+ break;
+ case OPUS_SET_BANDWIDTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if ((value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) && value != OPUS_AUTO)
+ {
+ goto bad_arg;
+ }
+ st->user_bandwidth = value;
+ if (st->user_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+ st->silk_mode.maxInternalSampleRate = 8000;
+ } else if (st->user_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+ st->silk_mode.maxInternalSampleRate = 12000;
+ } else {
+ st->silk_mode.maxInternalSampleRate = 16000;
+ }
+ }
+ break;
+ case OPUS_GET_BANDWIDTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->bandwidth;
+ }
+ break;
+ case OPUS_SET_DTX_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->silk_mode.useDTX = value;
+ }
+ break;
+ case OPUS_GET_DTX_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->silk_mode.useDTX;
+ }
+ break;
+ case OPUS_SET_COMPLEXITY_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>10)
+ {
+ goto bad_arg;
+ }
+ st->silk_mode.complexity = value;
+ celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(value));
+ }
+ break;
+ case OPUS_GET_COMPLEXITY_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->silk_mode.complexity;
+ }
+ break;
+ case OPUS_SET_INBAND_FEC_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->silk_mode.useInBandFEC = value;
+ }
+ break;
+ case OPUS_GET_INBAND_FEC_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->silk_mode.useInBandFEC;
+ }
+ break;
+ case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value < 0 || value > 100)
+ {
+ goto bad_arg;
+ }
+ st->silk_mode.packetLossPercentage = value;
+ celt_encoder_ctl(celt_enc, OPUS_SET_PACKET_LOSS_PERC(value));
+ }
+ break;
+ case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->silk_mode.packetLossPercentage;
+ }
+ break;
+ case OPUS_SET_VBR_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->use_vbr = value;
+ st->silk_mode.useCBR = 1-value;
+ }
+ break;
+ case OPUS_GET_VBR_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->use_vbr;
+ }
+ break;
+ case OPUS_SET_VOICE_RATIO_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<-1 || value>100)
+ {
+ goto bad_arg;
+ }
+ st->voice_ratio = value;
+ }
+ break;
+ case OPUS_GET_VOICE_RATIO_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->voice_ratio;
+ }
+ break;
+ case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->vbr_constraint = value;
+ }
+ break;
+ case OPUS_GET_VBR_CONSTRAINT_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->vbr_constraint;
+ }
+ break;
+ case OPUS_SET_SIGNAL_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value!=OPUS_AUTO && value!=OPUS_SIGNAL_VOICE && value!=OPUS_SIGNAL_MUSIC)
+ {
+ goto bad_arg;
+ }
+ st->signal_type = value;
+ }
+ break;
+ case OPUS_GET_SIGNAL_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->signal_type;
+ }
+ break;
+ case OPUS_GET_LOOKAHEAD_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->Fs/400;
+ if (st->application != OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ *value += st->delay_compensation;
+ }
+ break;
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->Fs;
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->rangeFinal;
+ }
+ break;
+ case OPUS_SET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<8 || value>24)
+ {
+ goto bad_arg;
+ }
+ st->lsb_depth=value;
+ }
+ break;
+ case OPUS_GET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->lsb_depth;
+ }
+ break;
+ case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value != OPUS_FRAMESIZE_ARG && value != OPUS_FRAMESIZE_2_5_MS &&
+ value != OPUS_FRAMESIZE_5_MS && value != OPUS_FRAMESIZE_10_MS &&
+ value != OPUS_FRAMESIZE_20_MS && value != OPUS_FRAMESIZE_40_MS &&
+ value != OPUS_FRAMESIZE_60_MS && value != OPUS_FRAMESIZE_VARIABLE)
+ {
+ goto bad_arg;
+ }
+ st->variable_duration = value;
+ celt_encoder_ctl(celt_enc, OPUS_SET_EXPERT_FRAME_DURATION(value));
+ }
+ break;
+ case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->variable_duration;
+ }
+ break;
+ case OPUS_SET_PREDICTION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value > 1 || value < 0)
+ goto bad_arg;
+ st->silk_mode.reducedDependency = value;
+ }
+ break;
+ case OPUS_GET_PREDICTION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ goto bad_arg;
+ *value = st->silk_mode.reducedDependency;
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ void *silk_enc;
+ silk_EncControlStruct dummy;
+ char *start;
+ silk_enc = (char*)st+st->silk_enc_offset;
+#ifndef DISABLE_FLOAT_API
+ tonality_analysis_reset(&st->analysis);
+#endif
+
+ start = (char*)&st->OPUS_ENCODER_RESET_START;
+ OPUS_CLEAR(start, sizeof(OpusEncoder) - (start - (char*)st));
+
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+ silk_InitEncoder( silk_enc, st->arch, &dummy );
+ st->stream_channels = st->channels;
+ st->hybrid_stereo_width_Q14 = 1 << 14;
+ st->prev_HB_gain = Q15ONE;
+ st->first = 1;
+ st->mode = MODE_HYBRID;
+ st->bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+ }
+ break;
+ case OPUS_SET_FORCE_MODE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if ((value < MODE_SILK_ONLY || value > MODE_CELT_ONLY) && value != OPUS_AUTO)
+ {
+ goto bad_arg;
+ }
+ st->user_forced_mode = value;
+ }
+ break;
+ case OPUS_SET_LFE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->lfe = value;
+ ret = celt_encoder_ctl(celt_enc, OPUS_SET_LFE(value));
+ }
+ break;
+ case OPUS_SET_ENERGY_MASK_REQUEST:
+ {
+ opus_val16 *value = va_arg(ap, opus_val16*);
+ st->energy_masking = value;
+ ret = celt_encoder_ctl(celt_enc, OPUS_SET_ENERGY_MASK(value));
+ }
+ break;
+
+ case CELT_GET_MODE_REQUEST:
+ {
+ const CELTMode ** value = va_arg(ap, const CELTMode**);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ ret = celt_encoder_ctl(celt_enc, CELT_GET_MODE(value));
+ }
+ break;
+ default:
+ /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/
+ ret = OPUS_UNIMPLEMENTED;
+ break;
+ }
+ va_end(ap);
+ return ret;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+}
+
+void opus_encoder_destroy(OpusEncoder *st)
+{
+ opus_free(st);
+}
diff --git a/external/opus-1.1.4/src/opus_multistream.c b/external/opus-1.1.4/src/opus_multistream.c
new file mode 100644
index 0000000..09c3639
--- /dev/null
+++ b/external/opus-1.1.4/src/opus_multistream.c
@@ -0,0 +1,92 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_multistream.h"
+#include "opus.h"
+#include "opus_private.h"
+#include "stack_alloc.h"
+#include <stdarg.h>
+#include "float_cast.h"
+#include "os_support.h"
+
+
+int validate_layout(const ChannelLayout *layout)
+{
+ int i, max_channel;
+
+ max_channel = layout->nb_streams+layout->nb_coupled_streams;
+ if (max_channel>255)
+ return 0;
+ for (i=0;i<layout->nb_channels;i++)
+ {
+ if (layout->mapping[i] >= max_channel && layout->mapping[i] != 255)
+ return 0;
+ }
+ return 1;
+}
+
+
+int get_left_channel(const ChannelLayout *layout, int stream_id, int prev)
+{
+ int i;
+ i = (prev<0) ? 0 : prev+1;
+ for (;i<layout->nb_channels;i++)
+ {
+ if (layout->mapping[i]==stream_id*2)
+ return i;
+ }
+ return -1;
+}
+
+int get_right_channel(const ChannelLayout *layout, int stream_id, int prev)
+{
+ int i;
+ i = (prev<0) ? 0 : prev+1;
+ for (;i<layout->nb_channels;i++)
+ {
+ if (layout->mapping[i]==stream_id*2+1)
+ return i;
+ }
+ return -1;
+}
+
+int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev)
+{
+ int i;
+ i = (prev<0) ? 0 : prev+1;
+ for (;i<layout->nb_channels;i++)
+ {
+ if (layout->mapping[i]==stream_id+layout->nb_coupled_streams)
+ return i;
+ }
+ return -1;
+}
+
diff --git a/external/opus-1.1.4/src/opus_multistream_decoder.c b/external/opus-1.1.4/src/opus_multistream_decoder.c
new file mode 100644
index 0000000..b95eaa6
--- /dev/null
+++ b/external/opus-1.1.4/src/opus_multistream_decoder.c
@@ -0,0 +1,537 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_multistream.h"
+#include "opus.h"
+#include "opus_private.h"
+#include "stack_alloc.h"
+#include <stdarg.h>
+#include "float_cast.h"
+#include "os_support.h"
+
+struct OpusMSDecoder {
+ ChannelLayout layout;
+ /* Decoder states go here */
+};
+
+
+
+
+/* DECODER */
+
+opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams)
+{
+ int coupled_size;
+ int mono_size;
+
+ if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
+ coupled_size = opus_decoder_get_size(2);
+ mono_size = opus_decoder_get_size(1);
+ return align(sizeof(OpusMSDecoder))
+ + nb_coupled_streams * align(coupled_size)
+ + (nb_streams-nb_coupled_streams) * align(mono_size);
+}
+
+int opus_multistream_decoder_init(
+ OpusMSDecoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping
+)
+{
+ int coupled_size;
+ int mono_size;
+ int i, ret;
+ char *ptr;
+
+ if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+ (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
+ return OPUS_BAD_ARG;
+
+ st->layout.nb_channels = channels;
+ st->layout.nb_streams = streams;
+ st->layout.nb_coupled_streams = coupled_streams;
+
+ for (i=0;i<st->layout.nb_channels;i++)
+ st->layout.mapping[i] = mapping[i];
+ if (!validate_layout(&st->layout))
+ return OPUS_BAD_ARG;
+
+ ptr = (char*)st + align(sizeof(OpusMSDecoder));
+ coupled_size = opus_decoder_get_size(2);
+ mono_size = opus_decoder_get_size(1);
+
+ for (i=0;i<st->layout.nb_coupled_streams;i++)
+ {
+ ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2);
+ if(ret!=OPUS_OK)return ret;
+ ptr += align(coupled_size);
+ }
+ for (;i<st->layout.nb_streams;i++)
+ {
+ ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1);
+ if(ret!=OPUS_OK)return ret;
+ ptr += align(mono_size);
+ }
+ return OPUS_OK;
+}
+
+
+OpusMSDecoder *opus_multistream_decoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int *error
+)
+{
+ int ret;
+ OpusMSDecoder *st;
+ if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+ (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams));
+ if (st==NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping);
+ if (error)
+ *error = ret;
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ return st;
+}
+
+typedef void (*opus_copy_channel_out_func)(
+ void *dst,
+ int dst_stride,
+ int dst_channel,
+ const opus_val16 *src,
+ int src_stride,
+ int frame_size
+);
+
+static int opus_multistream_packet_validate(const unsigned char *data,
+ opus_int32 len, int nb_streams, opus_int32 Fs)
+{
+ int s;
+ int count;
+ unsigned char toc;
+ opus_int16 size[48];
+ int samples=0;
+ opus_int32 packet_offset;
+
+ for (s=0;s<nb_streams;s++)
+ {
+ int tmp_samples;
+ if (len<=0)
+ return OPUS_INVALID_PACKET;
+ count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL,
+ size, NULL, &packet_offset);
+ if (count<0)
+ return count;
+ tmp_samples = opus_packet_get_nb_samples(data, packet_offset, Fs);
+ if (s!=0 && samples != tmp_samples)
+ return OPUS_INVALID_PACKET;
+ samples = tmp_samples;
+ data += packet_offset;
+ len -= packet_offset;
+ }
+ return samples;
+}
+
+static int opus_multistream_decode_native(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ void *pcm,
+ opus_copy_channel_out_func copy_channel_out,
+ int frame_size,
+ int decode_fec,
+ int soft_clip
+)
+{
+ opus_int32 Fs;
+ int coupled_size;
+ int mono_size;
+ int s, c;
+ char *ptr;
+ int do_plc=0;
+ VARDECL(opus_val16, buf);
+ ALLOC_STACK;
+
+ /* Limit frame_size to avoid excessive stack allocations. */
+ opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs));
+ frame_size = IMIN(frame_size, Fs/25*3);
+ ALLOC(buf, 2*frame_size, opus_val16);
+ ptr = (char*)st + align(sizeof(OpusMSDecoder));
+ coupled_size = opus_decoder_get_size(2);
+ mono_size = opus_decoder_get_size(1);
+
+ if (len==0)
+ do_plc = 1;
+ if (len < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ if (!do_plc && len < 2*st->layout.nb_streams-1)
+ {
+ RESTORE_STACK;
+ return OPUS_INVALID_PACKET;
+ }
+ if (!do_plc)
+ {
+ int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs);
+ if (ret < 0)
+ {
+ RESTORE_STACK;
+ return ret;
+ } else if (ret > frame_size)
+ {
+ RESTORE_STACK;
+ return OPUS_BUFFER_TOO_SMALL;
+ }
+ }
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusDecoder *dec;
+ int packet_offset, ret;
+
+ dec = (OpusDecoder*)ptr;
+ ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size);
+
+ if (!do_plc && len<=0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ packet_offset = 0;
+ ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip);
+ data += packet_offset;
+ len -= packet_offset;
+ if (ret <= 0)
+ {
+ RESTORE_STACK;
+ return ret;
+ }
+ frame_size = ret;
+ if (s < st->layout.nb_coupled_streams)
+ {
+ int chan, prev;
+ prev = -1;
+ /* Copy "left" audio to the channel(s) where it belongs */
+ while ( (chan = get_left_channel(&st->layout, s, prev)) != -1)
+ {
+ (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+ buf, 2, frame_size);
+ prev = chan;
+ }
+ prev = -1;
+ /* Copy "right" audio to the channel(s) where it belongs */
+ while ( (chan = get_right_channel(&st->layout, s, prev)) != -1)
+ {
+ (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+ buf+1, 2, frame_size);
+ prev = chan;
+ }
+ } else {
+ int chan, prev;
+ prev = -1;
+ /* Copy audio to the channel(s) where it belongs */
+ while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1)
+ {
+ (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+ buf, 1, frame_size);
+ prev = chan;
+ }
+ }
+ }
+ /* Handle muted channels */
+ for (c=0;c<st->layout.nb_channels;c++)
+ {
+ if (st->layout.mapping[c] == 255)
+ {
+ (*copy_channel_out)(pcm, st->layout.nb_channels, c,
+ NULL, 0, frame_size);
+ }
+ }
+ RESTORE_STACK;
+ return frame_size;
+}
+
+#if !defined(DISABLE_FLOAT_API)
+static void opus_copy_channel_out_float(
+ void *dst,
+ int dst_stride,
+ int dst_channel,
+ const opus_val16 *src,
+ int src_stride,
+ int frame_size
+)
+{
+ float *float_dst;
+ opus_int32 i;
+ float_dst = (float*)dst;
+ if (src != NULL)
+ {
+ for (i=0;i<frame_size;i++)
+#if defined(FIXED_POINT)
+ float_dst[i*dst_stride+dst_channel] = (1/32768.f)*src[i*src_stride];
+#else
+ float_dst[i*dst_stride+dst_channel] = src[i*src_stride];
+#endif
+ }
+ else
+ {
+ for (i=0;i<frame_size;i++)
+ float_dst[i*dst_stride+dst_channel] = 0;
+ }
+}
+#endif
+
+static void opus_copy_channel_out_short(
+ void *dst,
+ int dst_stride,
+ int dst_channel,
+ const opus_val16 *src,
+ int src_stride,
+ int frame_size
+)
+{
+ opus_int16 *short_dst;
+ opus_int32 i;
+ short_dst = (opus_int16*)dst;
+ if (src != NULL)
+ {
+ for (i=0;i<frame_size;i++)
+#if defined(FIXED_POINT)
+ short_dst[i*dst_stride+dst_channel] = src[i*src_stride];
+#else
+ short_dst[i*dst_stride+dst_channel] = FLOAT2INT16(src[i*src_stride]);
+#endif
+ }
+ else
+ {
+ for (i=0;i<frame_size;i++)
+ short_dst[i*dst_stride+dst_channel] = 0;
+ }
+}
+
+
+
+#ifdef FIXED_POINT
+int opus_multistream_decode(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ opus_int16 *pcm,
+ int frame_size,
+ int decode_fec
+)
+{
+ return opus_multistream_decode_native(st, data, len,
+ pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data,
+ opus_int32 len, float *pcm, int frame_size, int decode_fec)
+{
+ return opus_multistream_decode_native(st, data, len,
+ pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0);
+}
+#endif
+
+#else
+
+int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec)
+{
+ return opus_multistream_decode_native(st, data, len,
+ pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1);
+}
+
+int opus_multistream_decode_float(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ float *pcm,
+ int frame_size,
+ int decode_fec
+)
+{
+ return opus_multistream_decode_native(st, data, len,
+ pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0);
+}
+#endif
+
+int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
+{
+ va_list ap;
+ int coupled_size, mono_size;
+ char *ptr;
+ int ret = OPUS_OK;
+
+ va_start(ap, request);
+
+ coupled_size = opus_decoder_get_size(2);
+ mono_size = opus_decoder_get_size(1);
+ ptr = (char*)st + align(sizeof(OpusMSDecoder));
+ switch (request)
+ {
+ case OPUS_GET_BANDWIDTH_REQUEST:
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ case OPUS_GET_GAIN_REQUEST:
+ case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
+ {
+ OpusDecoder *dec;
+ /* For int32* GET params, just query the first stream */
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ dec = (OpusDecoder*)ptr;
+ ret = opus_decoder_ctl(dec, request, value);
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ int s;
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ opus_uint32 tmp;
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = 0;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusDecoder *dec;
+ dec = (OpusDecoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_decoder_ctl(dec, request, &tmp);
+ if (ret != OPUS_OK) break;
+ *value ^= tmp;
+ }
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ int s;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusDecoder *dec;
+
+ dec = (OpusDecoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_decoder_ctl(dec, OPUS_RESET_STATE);
+ if (ret != OPUS_OK)
+ break;
+ }
+ }
+ break;
+ case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST:
+ {
+ int s;
+ opus_int32 stream_id;
+ OpusDecoder **value;
+ stream_id = va_arg(ap, opus_int32);
+ if (stream_id<0 || stream_id >= st->layout.nb_streams)
+ ret = OPUS_BAD_ARG;
+ value = va_arg(ap, OpusDecoder**);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ for (s=0;s<stream_id;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ *value = (OpusDecoder*)ptr;
+ }
+ break;
+ case OPUS_SET_GAIN_REQUEST:
+ {
+ int s;
+ /* This works for int32 params */
+ opus_int32 value = va_arg(ap, opus_int32);
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusDecoder *dec;
+
+ dec = (OpusDecoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_decoder_ctl(dec, request, value);
+ if (ret != OPUS_OK)
+ break;
+ }
+ }
+ break;
+ default:
+ ret = OPUS_UNIMPLEMENTED;
+ break;
+ }
+
+ va_end(ap);
+ return ret;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+}
+
+
+void opus_multistream_decoder_destroy(OpusMSDecoder *st)
+{
+ opus_free(st);
+}
diff --git a/external/opus-1.1.4/src/opus_multistream_encoder.c b/external/opus-1.1.4/src/opus_multistream_encoder.c
new file mode 100644
index 0000000..e722e31
--- /dev/null
+++ b/external/opus-1.1.4/src/opus_multistream_encoder.c
@@ -0,0 +1,1351 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_multistream.h"
+#include "opus.h"
+#include "opus_private.h"
+#include "stack_alloc.h"
+#include <stdarg.h>
+#include "float_cast.h"
+#include "os_support.h"
+#include "mathops.h"
+#include "mdct.h"
+#include "modes.h"
+#include "bands.h"
+#include "quant_bands.h"
+#include "pitch.h"
+
+typedef struct {
+ int nb_streams;
+ int nb_coupled_streams;
+ unsigned char mapping[8];
+} VorbisLayout;
+
+/* Index is nb_channel-1*/
+static const VorbisLayout vorbis_mappings[8] = {
+ {1, 0, {0}}, /* 1: mono */
+ {1, 1, {0, 1}}, /* 2: stereo */
+ {2, 1, {0, 2, 1}}, /* 3: 1-d surround */
+ {2, 2, {0, 1, 2, 3}}, /* 4: quadraphonic surround */
+ {3, 2, {0, 4, 1, 2, 3}}, /* 5: 5-channel surround */
+ {4, 2, {0, 4, 1, 2, 3, 5}}, /* 6: 5.1 surround */
+ {4, 3, {0, 4, 1, 2, 3, 5, 6}}, /* 7: 6.1 surround */
+ {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */
+};
+
+typedef void (*opus_copy_channel_in_func)(
+ opus_val16 *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size
+);
+
+typedef enum {
+ MAPPING_TYPE_NONE,
+ MAPPING_TYPE_SURROUND
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+ , /* Do not include comma at end of enumerator list */
+ MAPPING_TYPE_AMBISONICS
+#endif
+} MappingType;
+
+struct OpusMSEncoder {
+ ChannelLayout layout;
+ int arch;
+ int lfe_stream;
+ int application;
+ int variable_duration;
+ MappingType mapping_type;
+ opus_int32 bitrate_bps;
+ float subframe_mem[3];
+ /* Encoder states go here */
+ /* then opus_val32 window_mem[channels*120]; */
+ /* then opus_val32 preemph_mem[channels]; */
+};
+
+static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st)
+{
+ int s;
+ char *ptr;
+ int coupled_size, mono_size;
+
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ /* void* cast avoids clang -Wcast-align warning */
+ return (opus_val32*)(void*)(ptr+st->layout.nb_channels*120*sizeof(opus_val32));
+}
+
+static opus_val32 *ms_get_window_mem(OpusMSEncoder *st)
+{
+ int s;
+ char *ptr;
+ int coupled_size, mono_size;
+
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ /* void* cast avoids clang -Wcast-align warning */
+ return (opus_val32*)(void*)ptr;
+}
+
+static int validate_encoder_layout(const ChannelLayout *layout)
+{
+ int s;
+ for (s=0;s<layout->nb_streams;s++)
+ {
+ if (s < layout->nb_coupled_streams)
+ {
+ if (get_left_channel(layout, s, -1)==-1)
+ return 0;
+ if (get_right_channel(layout, s, -1)==-1)
+ return 0;
+ } else {
+ if (get_mono_channel(layout, s, -1)==-1)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void channel_pos(int channels, int pos[8])
+{
+ /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */
+ if (channels==4)
+ {
+ pos[0]=1;
+ pos[1]=3;
+ pos[2]=1;
+ pos[3]=3;
+ } else if (channels==3||channels==5||channels==6)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=0;
+ } else if (channels==7)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=2;
+ pos[6]=0;
+ } else if (channels==8)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=1;
+ pos[6]=3;
+ pos[7]=0;
+ }
+}
+
+#if 1
+/* Computes a rough approximation of log2(2^a + 2^b) */
+static opus_val16 logSum(opus_val16 a, opus_val16 b)
+{
+ opus_val16 max;
+ opus_val32 diff;
+ opus_val16 frac;
+ static const opus_val16 diff_table[17] = {
+ QCONST16(0.5000000f, DB_SHIFT), QCONST16(0.2924813f, DB_SHIFT), QCONST16(0.1609640f, DB_SHIFT), QCONST16(0.0849625f, DB_SHIFT),
+ QCONST16(0.0437314f, DB_SHIFT), QCONST16(0.0221971f, DB_SHIFT), QCONST16(0.0111839f, DB_SHIFT), QCONST16(0.0056136f, DB_SHIFT),
+ QCONST16(0.0028123f, DB_SHIFT)
+ };
+ int low;
+ if (a>b)
+ {
+ max = a;
+ diff = SUB32(EXTEND32(a),EXTEND32(b));
+ } else {
+ max = b;
+ diff = SUB32(EXTEND32(b),EXTEND32(a));
+ }
+ if (!(diff < QCONST16(8.f, DB_SHIFT))) /* inverted to catch NaNs */
+ return max;
+#ifdef FIXED_POINT
+ low = SHR32(diff, DB_SHIFT-1);
+ frac = SHL16(diff - SHL16(low, DB_SHIFT-1), 16-DB_SHIFT);
+#else
+ low = (int)floor(2*diff);
+ frac = 2*diff - low;
+#endif
+ return max + diff_table[low] + MULT16_16_Q15(frac, SUB16(diff_table[low+1], diff_table[low]));
+}
+#else
+opus_val16 logSum(opus_val16 a, opus_val16 b)
+{
+ return log2(pow(4, a)+ pow(4, b))/2;
+}
+#endif
+
+void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *bandLogE, opus_val32 *mem, opus_val32 *preemph_mem,
+ int len, int overlap, int channels, int rate, opus_copy_channel_in_func copy_channel_in, int arch
+)
+{
+ int c;
+ int i;
+ int LM;
+ int pos[8] = {0};
+ int upsample;
+ int frame_size;
+ opus_val16 channel_offset;
+ opus_val32 bandE[21];
+ opus_val16 maskLogE[3][21];
+ VARDECL(opus_val32, in);
+ VARDECL(opus_val16, x);
+ VARDECL(opus_val32, freq);
+ SAVE_STACK;
+
+ upsample = resampling_factor(rate);
+ frame_size = len*upsample;
+
+ /* LM = log2(frame_size / 120) */
+ for (LM=0;LM<celt_mode->maxLM;LM++)
+ if (celt_mode->shortMdctSize<<LM==frame_size)
+ break;
+
+ ALLOC(in, frame_size+overlap, opus_val32);
+ ALLOC(x, len, opus_val16);
+ ALLOC(freq, frame_size, opus_val32);
+
+ channel_pos(channels, pos);
+
+ for (c=0;c<3;c++)
+ for (i=0;i<21;i++)
+ maskLogE[c][i] = -QCONST16(28.f, DB_SHIFT);
+
+ for (c=0;c<channels;c++)
+ {
+ OPUS_COPY(in, mem+c*overlap, overlap);
+ (*copy_channel_in)(x, 1, pcm, channels, c, len);
+ celt_preemphasis(x, in+overlap, frame_size, 1, upsample, celt_mode->preemph, preemph_mem+c, 0);
+#ifndef FIXED_POINT
+ {
+ opus_val32 sum;
+ sum = celt_inner_prod(in, in, frame_size+overlap, 0);
+ /* This should filter out both NaNs and ridiculous signals that could
+ cause NaNs further down. */
+ if (!(sum < 1e9f) || celt_isnan(sum))
+ {
+ OPUS_CLEAR(in, frame_size+overlap);
+ preemph_mem[c] = 0;
+ }
+ }
+#endif
+ clt_mdct_forward(&celt_mode->mdct, in, freq, celt_mode->window,
+ overlap, celt_mode->maxLM-LM, 1, arch);
+ if (upsample != 1)
+ {
+ int bound = len;
+ for (i=0;i<bound;i++)
+ freq[i] *= upsample;
+ for (;i<frame_size;i++)
+ freq[i] = 0;
+ }
+
+ compute_band_energies(celt_mode, freq, bandE, 21, 1, LM);
+ amp2Log2(celt_mode, 21, 21, bandE, bandLogE+21*c, 1);
+ /* Apply spreading function with -6 dB/band going up and -12 dB/band going down. */
+ for (i=1;i<21;i++)
+ bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i-1]-QCONST16(1.f, DB_SHIFT));
+ for (i=19;i>=0;i--)
+ bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i+1]-QCONST16(2.f, DB_SHIFT));
+ if (pos[c]==1)
+ {
+ for (i=0;i<21;i++)
+ maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]);
+ } else if (pos[c]==3)
+ {
+ for (i=0;i<21;i++)
+ maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]);
+ } else if (pos[c]==2)
+ {
+ for (i=0;i<21;i++)
+ {
+ maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT));
+ maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT));
+ }
+ }
+#if 0
+ for (i=0;i<21;i++)
+ printf("%f ", bandLogE[21*c+i]);
+ float sum=0;
+ for (i=0;i<21;i++)
+ sum += bandLogE[21*c+i];
+ printf("%f ", sum/21);
+#endif
+ OPUS_COPY(mem+c*overlap, in+frame_size, overlap);
+ }
+ for (i=0;i<21;i++)
+ maskLogE[1][i] = MIN32(maskLogE[0][i],maskLogE[2][i]);
+ channel_offset = HALF16(celt_log2(QCONST32(2.f,14)/(channels-1)));
+ for (c=0;c<3;c++)
+ for (i=0;i<21;i++)
+ maskLogE[c][i] += channel_offset;
+#if 0
+ for (c=0;c<3;c++)
+ {
+ for (i=0;i<21;i++)
+ printf("%f ", maskLogE[c][i]);
+ }
+#endif
+ for (c=0;c<channels;c++)
+ {
+ opus_val16 *mask;
+ if (pos[c]!=0)
+ {
+ mask = &maskLogE[pos[c]-1][0];
+ for (i=0;i<21;i++)
+ bandLogE[21*c+i] = bandLogE[21*c+i] - mask[i];
+ } else {
+ for (i=0;i<21;i++)
+ bandLogE[21*c+i] = 0;
+ }
+#if 0
+ for (i=0;i<21;i++)
+ printf("%f ", bandLogE[21*c+i]);
+ printf("\n");
+#endif
+#if 0
+ float sum=0;
+ for (i=0;i<21;i++)
+ sum += bandLogE[21*c+i];
+ printf("%f ", sum/(float)QCONST32(21.f, DB_SHIFT));
+ printf("\n");
+#endif
+ }
+ RESTORE_STACK;
+}
+
+opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams)
+{
+ int coupled_size;
+ int mono_size;
+
+ if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+ return align(sizeof(OpusMSEncoder))
+ + nb_coupled_streams * align(coupled_size)
+ + (nb_streams-nb_coupled_streams) * align(mono_size);
+}
+
+opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_family)
+{
+ int nb_streams;
+ int nb_coupled_streams;
+ opus_int32 size;
+
+ if (mapping_family==0)
+ {
+ if (channels==1)
+ {
+ nb_streams=1;
+ nb_coupled_streams=0;
+ } else if (channels==2)
+ {
+ nb_streams=1;
+ nb_coupled_streams=1;
+ } else
+ return 0;
+ } else if (mapping_family==1 && channels<=8 && channels>=1)
+ {
+ nb_streams=vorbis_mappings[channels-1].nb_streams;
+ nb_coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams;
+ } else if (mapping_family==255)
+ {
+ nb_streams=channels;
+ nb_coupled_streams=0;
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+ } else if (mapping_family==254)
+ {
+ nb_streams=channels;
+ nb_coupled_streams=0;
+#endif
+ } else
+ return 0;
+ size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams);
+ if (channels>2)
+ {
+ size += channels*(120*sizeof(opus_val32) + sizeof(opus_val32));
+ }
+ return size;
+}
+
+static int opus_multistream_encoder_init_impl(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application,
+ MappingType mapping_type
+)
+{
+ int coupled_size;
+ int mono_size;
+ int i, ret;
+ char *ptr;
+
+ if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+ (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
+ return OPUS_BAD_ARG;
+
+ st->arch = opus_select_arch();
+ st->layout.nb_channels = channels;
+ st->layout.nb_streams = streams;
+ st->layout.nb_coupled_streams = coupled_streams;
+ st->subframe_mem[0]=st->subframe_mem[1]=st->subframe_mem[2]=0;
+ if (mapping_type != MAPPING_TYPE_SURROUND)
+ st->lfe_stream = -1;
+ st->bitrate_bps = OPUS_AUTO;
+ st->application = application;
+ st->variable_duration = OPUS_FRAMESIZE_ARG;
+ for (i=0;i<st->layout.nb_channels;i++)
+ st->layout.mapping[i] = mapping[i];
+ if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout))
+ return OPUS_BAD_ARG;
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+
+ for (i=0;i<st->layout.nb_coupled_streams;i++)
+ {
+ ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application);
+ if(ret!=OPUS_OK)return ret;
+ if (i==st->lfe_stream)
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
+ ptr += align(coupled_size);
+ }
+ for (;i<st->layout.nb_streams;i++)
+ {
+ ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application);
+ if (i==st->lfe_stream)
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
+ if(ret!=OPUS_OK)return ret;
+ ptr += align(mono_size);
+ }
+ if (mapping_type == MAPPING_TYPE_SURROUND)
+ {
+ OPUS_CLEAR(ms_get_preemph_mem(st), channels);
+ OPUS_CLEAR(ms_get_window_mem(st), channels*120);
+ }
+ st->mapping_type = mapping_type;
+ return OPUS_OK;
+}
+
+int opus_multistream_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application
+)
+{
+ return opus_multistream_encoder_init_impl(st, Fs, channels, streams,
+ coupled_streams, mapping,
+ application, MAPPING_TYPE_NONE);
+}
+
+int opus_multistream_surround_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application
+)
+{
+ MappingType mapping_type;
+
+ if ((channels>255) || (channels<1))
+ return OPUS_BAD_ARG;
+ st->lfe_stream = -1;
+ if (mapping_family==0)
+ {
+ if (channels==1)
+ {
+ *streams=1;
+ *coupled_streams=0;
+ mapping[0]=0;
+ } else if (channels==2)
+ {
+ *streams=1;
+ *coupled_streams=1;
+ mapping[0]=0;
+ mapping[1]=1;
+ } else
+ return OPUS_UNIMPLEMENTED;
+ } else if (mapping_family==1 && channels<=8 && channels>=1)
+ {
+ int i;
+ *streams=vorbis_mappings[channels-1].nb_streams;
+ *coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams;
+ for (i=0;i<channels;i++)
+ mapping[i] = vorbis_mappings[channels-1].mapping[i];
+ if (channels>=6)
+ st->lfe_stream = *streams-1;
+ } else if (mapping_family==255)
+ {
+ int i;
+ *streams=channels;
+ *coupled_streams=0;
+ for(i=0;i<channels;i++)
+ mapping[i] = i;
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+ } else if (mapping_family==254)
+ {
+ int i;
+ *streams=channels;
+ *coupled_streams=0;
+ for(i=0;i<channels;i++)
+ mapping[i] = i;
+#endif
+ } else
+ return OPUS_UNIMPLEMENTED;
+
+ if (channels>2 && mapping_family==1) {
+ mapping_type = MAPPING_TYPE_SURROUND;
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+ } else if (mapping_family==254)
+ {
+ mapping_type = MAPPING_TYPE_AMBISONICS;
+#endif
+ } else
+ {
+ mapping_type = MAPPING_TYPE_NONE;
+ }
+ return opus_multistream_encoder_init_impl(st, Fs, channels, *streams,
+ *coupled_streams, mapping,
+ application, mapping_type);
+}
+
+OpusMSEncoder *opus_multistream_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application,
+ int *error
+)
+{
+ int ret;
+ OpusMSEncoder *st;
+ if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+ (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams));
+ if (st==NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application);
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ if (error)
+ *error = ret;
+ return st;
+}
+
+OpusMSEncoder *opus_multistream_surround_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application,
+ int *error
+)
+{
+ int ret;
+ opus_int32 size;
+ OpusMSEncoder *st;
+ if ((channels>255) || (channels<1))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ size = opus_multistream_surround_encoder_get_size(channels, mapping_family);
+ if (!size)
+ {
+ if (error)
+ *error = OPUS_UNIMPLEMENTED;
+ return NULL;
+ }
+ st = (OpusMSEncoder *)opus_alloc(size);
+ if (st==NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_multistream_surround_encoder_init(st, Fs, channels, mapping_family, streams, coupled_streams, mapping, application);
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ if (error)
+ *error = ret;
+ return st;
+}
+
+static void surround_rate_allocation(
+ OpusMSEncoder *st,
+ opus_int32 *rate,
+ int frame_size,
+ opus_int32 Fs
+ )
+{
+ int i;
+ opus_int32 channel_rate;
+ int stream_offset;
+ int lfe_offset;
+ int coupled_ratio; /* Q8 */
+ int lfe_ratio; /* Q8 */
+
+ if (st->bitrate_bps > st->layout.nb_channels*40000)
+ stream_offset = 20000;
+ else
+ stream_offset = st->bitrate_bps/st->layout.nb_channels/2;
+ stream_offset += 60*(Fs/frame_size-50);
+ /* We start by giving each stream (coupled or uncoupled) the same bitrate.
+ This models the main saving of coupled channels over uncoupled. */
+ /* The LFE stream is an exception to the above and gets fewer bits. */
+ lfe_offset = 3500 + 60*(Fs/frame_size-50);
+ /* Coupled streams get twice the mono rate after the first 20 kb/s. */
+ coupled_ratio = 512;
+ /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */
+ lfe_ratio = 32;
+
+ /* Compute bitrate allocation between streams */
+ if (st->bitrate_bps==OPUS_AUTO)
+ {
+ channel_rate = Fs+60*Fs/frame_size;
+ } else if (st->bitrate_bps==OPUS_BITRATE_MAX)
+ {
+ channel_rate = 300000;
+ } else {
+ int nb_lfe;
+ int nb_uncoupled;
+ int nb_coupled;
+ int total;
+ nb_lfe = (st->lfe_stream!=-1);
+ nb_coupled = st->layout.nb_coupled_streams;
+ nb_uncoupled = st->layout.nb_streams-nb_coupled-nb_lfe;
+ total = (nb_uncoupled<<8) /* mono */
+ + coupled_ratio*nb_coupled /* stereo */
+ + nb_lfe*lfe_ratio;
+ channel_rate = 256*(st->bitrate_bps-lfe_offset*nb_lfe-stream_offset*(nb_coupled+nb_uncoupled))/total;
+ }
+#ifndef FIXED_POINT
+ if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50)
+ {
+ opus_int32 bonus;
+ bonus = 60*(Fs/frame_size-50);
+ channel_rate += bonus;
+ }
+#endif
+
+ for (i=0;i<st->layout.nb_streams;i++)
+ {
+ if (i<st->layout.nb_coupled_streams)
+ rate[i] = stream_offset+(channel_rate*coupled_ratio>>8);
+ else if (i!=st->lfe_stream)
+ rate[i] = stream_offset+channel_rate;
+ else
+ rate[i] = lfe_offset+(channel_rate*lfe_ratio>>8);
+ }
+}
+
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+static void ambisonics_rate_allocation(
+ OpusMSEncoder *st,
+ opus_int32 *rate,
+ int frame_size,
+ opus_int32 Fs
+ )
+{
+ int i;
+ int non_mono_rate;
+ int total_rate;
+
+ /* The mono channel gets (rate_ratio_num / rate_ratio_den) times as many bits
+ * as all other channels */
+ const int rate_ratio_num = 4;
+ const int rate_ratio_den = 3;
+ const int num_channels = st->layout.nb_streams;
+
+ if (st->bitrate_bps==OPUS_AUTO)
+ {
+ total_rate = num_channels * (20000 + st->layout.nb_streams*(Fs+60*Fs/frame_size));
+ } else if (st->bitrate_bps==OPUS_BITRATE_MAX)
+ {
+ total_rate = num_channels * 320000;
+ } else {
+ total_rate = st->bitrate_bps;
+ }
+
+ /* Let y be the non-mono rate and let p, q be integers such that the mono
+ * channel rate is (p/q) * y.
+ * Also let T be the total bitrate to allocate. Then
+ * (n - 1) y + (p/q) y = T
+ * y = (T q) / (qn - q + p)
+ */
+ non_mono_rate =
+ total_rate * rate_ratio_den
+ / (rate_ratio_den*num_channels + rate_ratio_num - rate_ratio_den);
+
+#ifndef FIXED_POINT
+ if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50)
+ {
+ opus_int32 bonus = 60*(Fs/frame_size-50);
+ non_mono_rate += bonus;
+ }
+#endif
+
+ rate[0] = total_rate - (num_channels - 1) * non_mono_rate;
+ for (i=1;i<st->layout.nb_streams;i++)
+ {
+ rate[i] = non_mono_rate;
+ }
+}
+#endif /* ENABLE_EXPERIMENTAL_AMBISONICS */
+
+static opus_int32 rate_allocation(
+ OpusMSEncoder *st,
+ opus_int32 *rate,
+ int frame_size
+ )
+{
+ int i;
+ opus_int32 rate_sum=0;
+ opus_int32 Fs;
+ char *ptr;
+
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
+
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+ if (st->mapping_type == MAPPING_TYPE_AMBISONICS) {
+ ambisonics_rate_allocation(st, rate, frame_size, Fs);
+ } else
+#endif
+ {
+ surround_rate_allocation(st, rate, frame_size, Fs);
+ }
+
+ for (i=0;i<st->layout.nb_streams;i++)
+ {
+ rate[i] = IMAX(rate[i], 500);
+ rate_sum += rate[i];
+ }
+ return rate_sum;
+}
+
+/* Max size in case the encoder decides to return three frames */
+#define MS_FRAME_TMP (3*1275+7)
+static int opus_multistream_encode_native
+(
+ OpusMSEncoder *st,
+ opus_copy_channel_in_func copy_channel_in,
+ const void *pcm,
+ int analysis_frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes,
+ int lsb_depth,
+ downmix_func downmix,
+ int float_api
+)
+{
+ opus_int32 Fs;
+ int coupled_size;
+ int mono_size;
+ int s;
+ char *ptr;
+ int tot_size;
+ VARDECL(opus_val16, buf);
+ VARDECL(opus_val16, bandSMR);
+ unsigned char tmp_data[MS_FRAME_TMP];
+ OpusRepacketizer rp;
+ opus_int32 vbr;
+ const CELTMode *celt_mode;
+ opus_int32 bitrates[256];
+ opus_val16 bandLogE[42];
+ opus_val32 *mem = NULL;
+ opus_val32 *preemph_mem=NULL;
+ int frame_size;
+ opus_int32 rate_sum;
+ opus_int32 smallest_packet;
+ ALLOC_STACK;
+
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
+ {
+ preemph_mem = ms_get_preemph_mem(st);
+ mem = ms_get_window_mem(st);
+ }
+
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_VBR(&vbr));
+ opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode));
+
+ {
+ opus_int32 delay_compensation;
+ int channels;
+
+ channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_LOOKAHEAD(&delay_compensation));
+ delay_compensation -= Fs/400;
+ frame_size = compute_frame_size(pcm, analysis_frame_size,
+ st->variable_duration, channels, Fs, st->bitrate_bps,
+ delay_compensation, downmix
+#ifndef DISABLE_FLOAT_API
+ , st->subframe_mem
+#endif
+ );
+ }
+
+ if (400*frame_size < Fs)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ /* Validate frame_size before using it to allocate stack space.
+ This mirrors the checks in opus_encode[_float](). */
+ if (400*frame_size != Fs && 200*frame_size != Fs &&
+ 100*frame_size != Fs && 50*frame_size != Fs &&
+ 25*frame_size != Fs && 50*frame_size != 3*Fs)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+
+ /* Smallest packet the encoder can produce. */
+ smallest_packet = st->layout.nb_streams*2-1;
+ if (max_data_bytes < smallest_packet)
+ {
+ RESTORE_STACK;
+ return OPUS_BUFFER_TOO_SMALL;
+ }
+ ALLOC(buf, 2*frame_size, opus_val16);
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+
+ ALLOC(bandSMR, 21*st->layout.nb_channels, opus_val16);
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
+ {
+ surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, 120, st->layout.nb_channels, Fs, copy_channel_in, st->arch);
+ }
+
+ /* Compute bitrate allocation between streams (this could be a lot better) */
+ rate_sum = rate_allocation(st, bitrates, frame_size);
+
+ if (!vbr)
+ {
+ if (st->bitrate_bps == OPUS_AUTO)
+ {
+ max_data_bytes = IMIN(max_data_bytes, 3*rate_sum/(3*8*Fs/frame_size));
+ } else if (st->bitrate_bps != OPUS_BITRATE_MAX)
+ {
+ max_data_bytes = IMIN(max_data_bytes, IMAX(smallest_packet,
+ 3*st->bitrate_bps/(3*8*Fs/frame_size)));
+ }
+ }
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s]));
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
+ {
+ opus_int32 equiv_rate;
+ equiv_rate = st->bitrate_bps;
+ if (frame_size*50 < Fs)
+ equiv_rate -= 60*(Fs/frame_size - 50)*st->layout.nb_channels;
+ if (equiv_rate > 10000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
+ else if (equiv_rate > 7000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
+ else if (equiv_rate > 5000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
+ else
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
+ if (s < st->layout.nb_coupled_streams)
+ {
+ /* To preserve the spatial image, force stereo CELT on coupled streams */
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2));
+ }
+ }
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+ else if (st->mapping_type == MAPPING_TYPE_AMBISONICS) {
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
+ }
+#endif
+ }
+
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ /* Counting ToC */
+ tot_size = 0;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ int len;
+ int curr_max;
+ int c1, c2;
+ int ret;
+
+ opus_repacketizer_init(&rp);
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ {
+ int i;
+ int left, right;
+ left = get_left_channel(&st->layout, s, -1);
+ right = get_right_channel(&st->layout, s, -1);
+ (*copy_channel_in)(buf, 2,
+ pcm, st->layout.nb_channels, left, frame_size);
+ (*copy_channel_in)(buf+1, 2,
+ pcm, st->layout.nb_channels, right, frame_size);
+ ptr += align(coupled_size);
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
+ {
+ for (i=0;i<21;i++)
+ {
+ bandLogE[i] = bandSMR[21*left+i];
+ bandLogE[21+i] = bandSMR[21*right+i];
+ }
+ }
+ c1 = left;
+ c2 = right;
+ } else {
+ int i;
+ int chan = get_mono_channel(&st->layout, s, -1);
+ (*copy_channel_in)(buf, 1,
+ pcm, st->layout.nb_channels, chan, frame_size);
+ ptr += align(mono_size);
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
+ {
+ for (i=0;i<21;i++)
+ bandLogE[i] = bandSMR[21*chan+i];
+ }
+ c1 = chan;
+ c2 = -1;
+ }
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
+ opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE));
+ /* number of bytes left (+Toc) */
+ curr_max = max_data_bytes - tot_size;
+ /* Reserve one byte for the last stream and two for the others */
+ curr_max -= IMAX(0,2*(st->layout.nb_streams-s-1)-1);
+ curr_max = IMIN(curr_max,MS_FRAME_TMP);
+ /* Repacketizer will add one or two bytes for self-delimited frames */
+ if (s != st->layout.nb_streams-1) curr_max -= curr_max>253 ? 2 : 1;
+ if (!vbr && s == st->layout.nb_streams-1)
+ opus_encoder_ctl(enc, OPUS_SET_BITRATE(curr_max*(8*Fs/frame_size)));
+ len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth,
+ pcm, analysis_frame_size, c1, c2, st->layout.nb_channels, downmix, float_api);
+ if (len<0)
+ {
+ RESTORE_STACK;
+ return len;
+ }
+ /* We need to use the repacketizer to add the self-delimiting lengths
+ while taking into account the fact that the encoder can now return
+ more than one frame at a time (e.g. 60 ms CELT-only) */
+ ret = opus_repacketizer_cat(&rp, tmp_data, len);
+ /* If the opus_repacketizer_cat() fails, then something's seriously wrong
+ with the encoder. */
+ if (ret != OPUS_OK)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp),
+ data, max_data_bytes-tot_size, s != st->layout.nb_streams-1, !vbr && s == st->layout.nb_streams-1);
+ data += len;
+ tot_size += len;
+ }
+ /*printf("\n");*/
+ RESTORE_STACK;
+ return tot_size;
+}
+
+#if !defined(DISABLE_FLOAT_API)
+static void opus_copy_channel_in_float(
+ opus_val16 *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size
+)
+{
+ const float *float_src;
+ opus_int32 i;
+ float_src = (const float *)src;
+ for (i=0;i<frame_size;i++)
+#if defined(FIXED_POINT)
+ dst[i*dst_stride] = FLOAT2INT16(float_src[i*src_stride+src_channel]);
+#else
+ dst[i*dst_stride] = float_src[i*src_stride+src_channel];
+#endif
+}
+#endif
+
+static void opus_copy_channel_in_short(
+ opus_val16 *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size
+)
+{
+ const opus_int16 *short_src;
+ opus_int32 i;
+ short_src = (const opus_int16 *)src;
+ for (i=0;i<frame_size;i++)
+#if defined(FIXED_POINT)
+ dst[i*dst_stride] = short_src[i*src_stride+src_channel];
+#else
+ dst[i*dst_stride] = (1/32768.f)*short_src[i*src_stride+src_channel];
+#endif
+}
+
+
+#ifdef FIXED_POINT
+int opus_multistream_encode(
+ OpusMSEncoder *st,
+ const opus_val16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_short,
+ pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_multistream_encode_float(
+ OpusMSEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_float,
+ pcm, frame_size, data, max_data_bytes, 16, downmix_float, 1);
+}
+#endif
+
+#else
+
+int opus_multistream_encode_float
+(
+ OpusMSEncoder *st,
+ const opus_val16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_float,
+ pcm, frame_size, data, max_data_bytes, 24, downmix_float, 1);
+}
+
+int opus_multistream_encode(
+ OpusMSEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_short,
+ pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0);
+}
+#endif
+
+int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
+{
+ va_list ap;
+ int coupled_size, mono_size;
+ char *ptr;
+ int ret = OPUS_OK;
+
+ va_start(ap, request);
+
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ switch (request)
+ {
+ case OPUS_SET_BITRATE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<0 && value!=OPUS_AUTO && value!=OPUS_BITRATE_MAX)
+ {
+ goto bad_arg;
+ }
+ st->bitrate_bps = value;
+ }
+ break;
+ case OPUS_GET_BITRATE_REQUEST:
+ {
+ int s;
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = 0;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ opus_int32 rate;
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ opus_encoder_ctl(enc, request, &rate);
+ *value += rate;
+ }
+ }
+ break;
+ case OPUS_GET_LSB_DEPTH_REQUEST:
+ case OPUS_GET_VBR_REQUEST:
+ case OPUS_GET_APPLICATION_REQUEST:
+ case OPUS_GET_BANDWIDTH_REQUEST:
+ case OPUS_GET_COMPLEXITY_REQUEST:
+ case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
+ case OPUS_GET_DTX_REQUEST:
+ case OPUS_GET_VOICE_RATIO_REQUEST:
+ case OPUS_GET_VBR_CONSTRAINT_REQUEST:
+ case OPUS_GET_SIGNAL_REQUEST:
+ case OPUS_GET_LOOKAHEAD_REQUEST:
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ case OPUS_GET_INBAND_FEC_REQUEST:
+ case OPUS_GET_FORCE_CHANNELS_REQUEST:
+ case OPUS_GET_PREDICTION_DISABLED_REQUEST:
+ {
+ OpusEncoder *enc;
+ /* For int32* GET params, just query the first stream */
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ enc = (OpusEncoder*)ptr;
+ ret = opus_encoder_ctl(enc, request, value);
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ int s;
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ opus_uint32 tmp;
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value=0;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_encoder_ctl(enc, request, &tmp);
+ if (ret != OPUS_OK) break;
+ *value ^= tmp;
+ }
+ }
+ break;
+ case OPUS_SET_LSB_DEPTH_REQUEST:
+ case OPUS_SET_COMPLEXITY_REQUEST:
+ case OPUS_SET_VBR_REQUEST:
+ case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+ case OPUS_SET_MAX_BANDWIDTH_REQUEST:
+ case OPUS_SET_BANDWIDTH_REQUEST:
+ case OPUS_SET_SIGNAL_REQUEST:
+ case OPUS_SET_APPLICATION_REQUEST:
+ case OPUS_SET_INBAND_FEC_REQUEST:
+ case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+ case OPUS_SET_DTX_REQUEST:
+ case OPUS_SET_FORCE_MODE_REQUEST:
+ case OPUS_SET_FORCE_CHANNELS_REQUEST:
+ case OPUS_SET_PREDICTION_DISABLED_REQUEST:
+ {
+ int s;
+ /* This works for int32 params */
+ opus_int32 value = va_arg(ap, opus_int32);
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_encoder_ctl(enc, request, value);
+ if (ret != OPUS_OK)
+ break;
+ }
+ }
+ break;
+ case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST:
+ {
+ int s;
+ opus_int32 stream_id;
+ OpusEncoder **value;
+ stream_id = va_arg(ap, opus_int32);
+ if (stream_id<0 || stream_id >= st->layout.nb_streams)
+ ret = OPUS_BAD_ARG;
+ value = va_arg(ap, OpusEncoder**);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ for (s=0;s<stream_id;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ *value = (OpusEncoder*)ptr;
+ }
+ break;
+ case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->variable_duration = value;
+ }
+ break;
+ case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->variable_duration;
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ int s;
+ st->subframe_mem[0] = st->subframe_mem[1] = st->subframe_mem[2] = 0;
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
+ {
+ OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels);
+ OPUS_CLEAR(ms_get_window_mem(st), st->layout.nb_channels*120);
+ }
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_encoder_ctl(enc, OPUS_RESET_STATE);
+ if (ret != OPUS_OK)
+ break;
+ }
+ }
+ break;
+ default:
+ ret = OPUS_UNIMPLEMENTED;
+ break;
+ }
+
+ va_end(ap);
+ return ret;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+}
+
+void opus_multistream_encoder_destroy(OpusMSEncoder *st)
+{
+ opus_free(st);
+}
diff --git a/external/opus-1.1.4/src/opus_private.h b/external/opus-1.1.4/src/opus_private.h
new file mode 100644
index 0000000..3b62eed
--- /dev/null
+++ b/external/opus-1.1.4/src/opus_private.h
@@ -0,0 +1,134 @@
+/* Copyright (c) 2012 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+
+#ifndef OPUS_PRIVATE_H
+#define OPUS_PRIVATE_H
+
+#include "arch.h"
+#include "opus.h"
+#include "celt.h"
+
+#include <stddef.h> /* offsetof */
+
+struct OpusRepacketizer {
+ unsigned char toc;
+ int nb_frames;
+ const unsigned char *frames[48];
+ opus_int16 len[48];
+ int framesize;
+};
+
+typedef struct ChannelLayout {
+ int nb_channels;
+ int nb_streams;
+ int nb_coupled_streams;
+ unsigned char mapping[256];
+} ChannelLayout;
+
+int validate_layout(const ChannelLayout *layout);
+int get_left_channel(const ChannelLayout *layout, int stream_id, int prev);
+int get_right_channel(const ChannelLayout *layout, int stream_id, int prev);
+int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev);
+
+
+
+#define MODE_SILK_ONLY 1000
+#define MODE_HYBRID 1001
+#define MODE_CELT_ONLY 1002
+
+#define OPUS_SET_VOICE_RATIO_REQUEST 11018
+#define OPUS_GET_VOICE_RATIO_REQUEST 11019
+
+/** Configures the encoder's expected percentage of voice
+ * opposed to music or other signals.
+ *
+ * @note This interface is currently more aspiration than actuality. It's
+ * ultimately expected to bias an automatic signal classifier, but it currently
+ * just shifts the static bitrate to mode mapping around a little bit.
+ *
+ * @param[in] x <tt>int</tt>: Voice percentage in the range 0-100, inclusive.
+ * @hideinitializer */
+#define OPUS_SET_VOICE_RATIO(x) OPUS_SET_VOICE_RATIO_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured voice ratio value, @see OPUS_SET_VOICE_RATIO
+ *
+ * @param[out] x <tt>int*</tt>: Voice percentage in the range 0-100, inclusive.
+ * @hideinitializer */
+#define OPUS_GET_VOICE_RATIO(x) OPUS_GET_VOICE_RATIO_REQUEST, __opus_check_int_ptr(x)
+
+
+#define OPUS_SET_FORCE_MODE_REQUEST 11002
+#define OPUS_SET_FORCE_MODE(x) OPUS_SET_FORCE_MODE_REQUEST, __opus_check_int(x)
+
+typedef void (*downmix_func)(const void *, opus_val32 *, int, int, int, int, int);
+void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C);
+void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C);
+
+int encode_size(int size, unsigned char *data);
+
+opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs);
+
+opus_int32 compute_frame_size(const void *analysis_pcm, int frame_size,
+ int variable_duration, int C, opus_int32 Fs, int bitrate_bps,
+ int delay_compensation, downmix_func downmix
+#ifndef DISABLE_FLOAT_API
+ , float *subframe_mem
+#endif
+ );
+
+opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
+ unsigned char *data, opus_int32 out_data_bytes, int lsb_depth,
+ const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2,
+ int analysis_channels, downmix_func downmix, int float_api);
+
+int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len,
+ opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited,
+ opus_int32 *packet_offset, int soft_clip);
+
+/* Make sure everything is properly aligned. */
+static OPUS_INLINE int align(int i)
+{
+ struct foo {char c; union { void* p; opus_int32 i; opus_val32 v; } u;};
+
+ unsigned int alignment = offsetof(struct foo, u);
+
+ /* Optimizing compilers should optimize div and multiply into and
+ for all sensible alignment values. */
+ return ((i + alignment - 1) / alignment) * alignment;
+}
+
+int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
+ int self_delimited, unsigned char *out_toc,
+ const unsigned char *frames[48], opus_int16 size[48],
+ int *payload_offset, opus_int32 *packet_offset);
+
+opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
+ unsigned char *data, opus_int32 maxlen, int self_delimited, int pad);
+
+int pad_frame(unsigned char *data, opus_int32 len, opus_int32 new_len);
+
+#endif /* OPUS_PRIVATE_H */
diff --git a/external/opus-1.1.4/src/repacketizer.c b/external/opus-1.1.4/src/repacketizer.c
new file mode 100644
index 0000000..c80ee7f
--- /dev/null
+++ b/external/opus-1.1.4/src/repacketizer.c
@@ -0,0 +1,348 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``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 COPYRIGHT OWNER
+ OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus.h"
+#include "opus_private.h"
+#include "os_support.h"
+
+
+int opus_repacketizer_get_size(void)
+{
+ return sizeof(OpusRepacketizer);
+}
+
+OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp)
+{
+ rp->nb_frames = 0;
+ return rp;
+}
+
+OpusRepacketizer *opus_repacketizer_create(void)
+{
+ OpusRepacketizer *rp;
+ rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size());
+ if(rp==NULL)return NULL;
+ return opus_repacketizer_init(rp);
+}
+
+void opus_repacketizer_destroy(OpusRepacketizer *rp)
+{
+ opus_free(rp);
+}
+
+static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited)
+{
+ unsigned char tmp_toc;
+ int curr_nb_frames,ret;
+ /* Set of check ToC */
+ if (len<1) return OPUS_INVALID_PACKET;
+ if (rp->nb_frames == 0)
+ {
+ rp->toc = data[0];
+ rp->framesize = opus_packet_get_samples_per_frame(data, 8000);
+ } else if ((rp->toc&0xFC) != (data[0]&0xFC))
+ {
+ /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/
+ return OPUS_INVALID_PACKET;
+ }
+ curr_nb_frames = opus_packet_get_nb_frames(data, len);
+ if(curr_nb_frames<1) return OPUS_INVALID_PACKET;
+
+ /* Check the 120 ms maximum packet size */
+ if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960)
+ {
+ return OPUS_INVALID_PACKET;
+ }
+
+ ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL, NULL);
+ if(ret<1)return ret;
+
+ rp->nb_frames += curr_nb_frames;
+ return OPUS_OK;
+}
+
+int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len)
+{
+ return opus_repacketizer_cat_impl(rp, data, len, 0);
+}
+
+int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp)
+{
+ return rp->nb_frames;
+}
+
+opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
+ unsigned char *data, opus_int32 maxlen, int self_delimited, int pad)
+{
+ int i, count;
+ opus_int32 tot_size;
+ opus_int16 *len;
+ const unsigned char **frames;
+ unsigned char * ptr;
+
+ if (begin<0 || begin>=end || end>rp->nb_frames)
+ {
+ /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/
+ return OPUS_BAD_ARG;
+ }
+ count = end-begin;
+
+ len = rp->len+begin;
+ frames = rp->frames+begin;
+ if (self_delimited)
+ tot_size = 1 + (len[count-1]>=252);
+ else
+ tot_size = 0;
+
+ ptr = data;
+ if (count==1)
+ {
+ /* Code 0 */
+ tot_size += len[0]+1;
+ if (tot_size > maxlen)
+ return OPUS_BUFFER_TOO_SMALL;
+ *ptr++ = rp->toc&0xFC;
+ } else if (count==2)
+ {
+ if (len[1] == len[0])
+ {
+ /* Code 1 */
+ tot_size += 2*len[0]+1;
+ if (tot_size > maxlen)
+ return OPUS_BUFFER_TOO_SMALL;
+ *ptr++ = (rp->toc&0xFC) | 0x1;
+ } else {
+ /* Code 2 */
+ tot_size += len[0]+len[1]+2+(len[0]>=252);
+ if (tot_size > maxlen)
+ return OPUS_BUFFER_TOO_SMALL;
+ *ptr++ = (rp->toc&0xFC) | 0x2;
+ ptr += encode_size(len[0], ptr);
+ }
+ }
+ if (count > 2 || (pad && tot_size < maxlen))
+ {
+ /* Code 3 */
+ int vbr;
+ int pad_amount=0;
+
+ /* Restart the process for the padding case */
+ ptr = data;
+ if (self_delimited)
+ tot_size = 1 + (len[count-1]>=252);
+ else
+ tot_size = 0;
+ vbr = 0;
+ for (i=1;i<count;i++)
+ {
+ if (len[i] != len[0])
+ {
+ vbr=1;
+ break;
+ }
+ }
+ if (vbr)
+ {
+ tot_size += 2;
+ for (i=0;i<count-1;i++)
+ tot_size += 1 + (len[i]>=252) + len[i];
+ tot_size += len[count-1];
+
+ if (tot_size > maxlen)
+ return OPUS_BUFFER_TOO_SMALL;
+ *ptr++ = (rp->toc&0xFC) | 0x3;
+ *ptr++ = count | 0x80;
+ } else {
+ tot_size += count*len[0]+2;
+ if (tot_size > maxlen)
+ return OPUS_BUFFER_TOO_SMALL;
+ *ptr++ = (rp->toc&0xFC) | 0x3;
+ *ptr++ = count;
+ }
+ pad_amount = pad ? (maxlen-tot_size) : 0;
+ if (pad_amount != 0)
+ {
+ int nb_255s;
+ data[1] |= 0x40;
+ nb_255s = (pad_amount-1)/255;
+ for (i=0;i<nb_255s;i++)
+ *ptr++ = 255;
+ *ptr++ = pad_amount-255*nb_255s-1;
+ tot_size += pad_amount;
+ }
+ if (vbr)
+ {
+ for (i=0;i<count-1;i++)
+ ptr += encode_size(len[i], ptr);
+ }
+ }
+ if (self_delimited) {
+ int sdlen = encode_size(len[count-1], ptr);
+ ptr += sdlen;
+ }
+ /* Copy the actual data */
+ for (i=0;i<count;i++)
+ {
+ /* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place
+ padding from opus_packet_pad or opus_packet_unpad(). */
+ celt_assert(frames[i] + len[i] <= data || ptr <= frames[i]);
+ OPUS_MOVE(ptr, frames[i], len[i]);
+ ptr += len[i];
+ }
+ if (pad)
+ {
+ /* Fill padding with zeros. */
+ while (ptr<data+maxlen)
+ *ptr++=0;
+ }
+ return tot_size;
+}
+
+opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen)
+{
+ return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0);
+}
+
+opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen)
+{
+ return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0);
+}
+
+int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
+{
+ OpusRepacketizer rp;
+ opus_int32 ret;
+ if (len < 1)
+ return OPUS_BAD_ARG;
+ if (len==new_len)
+ return OPUS_OK;
+ else if (len > new_len)
+ return OPUS_BAD_ARG;
+ opus_repacketizer_init(&rp);
+ /* Moving payload to the end of the packet so we can do in-place padding */
+ OPUS_MOVE(data+new_len-len, data, len);
+ ret = opus_repacketizer_cat(&rp, data+new_len-len, len);
+ if (ret != OPUS_OK)
+ return ret;
+ ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1);
+ if (ret > 0)
+ return OPUS_OK;
+ else
+ return ret;
+}
+
+opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len)
+{
+ OpusRepacketizer rp;
+ opus_int32 ret;
+ if (len < 1)
+ return OPUS_BAD_ARG;
+ opus_repacketizer_init(&rp);
+ ret = opus_repacketizer_cat(&rp, data, len);
+ if (ret < 0)
+ return ret;
+ ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0);
+ celt_assert(ret > 0 && ret <= len);
+ return ret;
+}
+
+int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams)
+{
+ int s;
+ int count;
+ unsigned char toc;
+ opus_int16 size[48];
+ opus_int32 packet_offset;
+ opus_int32 amount;
+
+ if (len < 1)
+ return OPUS_BAD_ARG;
+ if (len==new_len)
+ return OPUS_OK;
+ else if (len > new_len)
+ return OPUS_BAD_ARG;
+ amount = new_len - len;
+ /* Seek to last stream */
+ for (s=0;s<nb_streams-1;s++)
+ {
+ if (len<=0)
+ return OPUS_INVALID_PACKET;
+ count = opus_packet_parse_impl(data, len, 1, &toc, NULL,
+ size, NULL, &packet_offset);
+ if (count<0)
+ return count;
+ data += packet_offset;
+ len -= packet_offset;
+ }
+ return opus_packet_pad(data, len, len+amount);
+}
+
+opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams)
+{
+ int s;
+ unsigned char toc;
+ opus_int16 size[48];
+ opus_int32 packet_offset;
+ OpusRepacketizer rp;
+ unsigned char *dst;
+ opus_int32 dst_len;
+
+ if (len < 1)
+ return OPUS_BAD_ARG;
+ dst = data;
+ dst_len = 0;
+ /* Unpad all frames */
+ for (s=0;s<nb_streams;s++)
+ {
+ opus_int32 ret;
+ int self_delimited = s!=nb_streams-1;
+ if (len<=0)
+ return OPUS_INVALID_PACKET;
+ opus_repacketizer_init(&rp);
+ ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
+ size, NULL, &packet_offset);
+ if (ret<0)
+ return ret;
+ ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited);
+ if (ret < 0)
+ return ret;
+ ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, dst, len, self_delimited, 0);
+ if (ret < 0)
+ return ret;
+ else
+ dst_len += ret;
+ dst += ret;
+ data += packet_offset;
+ len -= packet_offset;
+ }
+ return dst_len;
+}
+
diff --git a/external/opus-1.1.4/src/tansig_table.h b/external/opus-1.1.4/src/tansig_table.h
new file mode 100644
index 0000000..c76f844
--- /dev/null
+++ b/external/opus-1.1.4/src/tansig_table.h
@@ -0,0 +1,45 @@
+/* This file is auto-generated by gen_tables */
+
+static const float tansig_table[201] = {
+0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f,
+0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f,
+0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f,
+0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f,
+0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f,
+0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f,
+0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f,
+0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f,
+0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f,
+0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f,
+0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f,
+0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f,
+0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f,
+0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f,
+0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f,
+0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f,
+0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f,
+0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f,
+0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f,
+0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f,
+0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f,
+0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f,
+0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f,
+0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f,
+0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f,
+0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f,
+0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f,
+0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f,
+0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f,
+0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f,
+0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f,
+0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f,
+0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f,
+0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f,
+0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f,
+0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f,
+0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
+0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
+1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+1.000000f,
+};
diff --git a/external/opusfile-0.8/CMakeLists.txt b/external/opusfile-0.8/CMakeLists.txt
new file mode 100644
index 0000000..48a2850
--- /dev/null
+++ b/external/opusfile-0.8/CMakeLists.txt
@@ -0,0 +1,24 @@
+add_library(
+ opusfile STATIC
+ include/opusfile.h
+ src/http.c
+ src/info.c
+ src/internal.c
+ src/internal.h
+ src/opusfile.c
+ src/stream.c
+ src/wincerts.c
+ src/winerrno.h
+ )
+
+include_directories(
+ include
+ ${CMAKE_CURRENT_SOURCE_DIR}/../opus-1.1.4/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libogg-1.3.2/include
+ )
+
+target_link_libraries(
+ opusfile
+ opus
+ ogg
+ )
diff --git a/external/opusfile-0.8/include/opusfile.h b/external/opusfile-0.8/include/opusfile.h
new file mode 100644
index 0000000..4bf2fba
--- /dev/null
+++ b/external/opusfile-0.8/include/opusfile.h
@@ -0,0 +1,2157 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: stdio-based convenience library for opening/seeking/decoding
+ last mod: $Id: vorbisfile.h 17182 2010-04-29 03:48:32Z xiphmont $
+
+ ********************************************************************/
+#if !defined(_opusfile_h)
+# define _opusfile_h (1)
+
+/**\mainpage
+ \section Introduction
+
+ This is the documentation for the <tt>libopusfile</tt> C API.
+
+ The <tt>libopusfile</tt> package provides a convenient high-level API for
+ decoding and basic manipulation of all Ogg Opus audio streams.
+ <tt>libopusfile</tt> is implemented as a layer on top of Xiph.Org's
+ reference
+ <tt><a href="https://www.xiph.org/ogg/doc/libogg/reference.html">libogg</a></tt>
+ and
+ <tt><a href="https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/index.html">libopus</a></tt>
+ libraries.
+
+ <tt>libopusfile</tt> provides several sets of built-in routines for
+ file/stream access, and may also use custom stream I/O routines provided by
+ the embedded environment.
+ There are built-in I/O routines provided for ANSI-compliant
+ <code>stdio</code> (<code>FILE *</code>), memory buffers, and URLs
+ (including <file:> URLs, plus optionally <http:> and <https:> URLs).
+
+ \section Organization
+
+ The main API is divided into several sections:
+ - \ref stream_open_close
+ - \ref stream_info
+ - \ref stream_decoding
+ - \ref stream_seeking
+
+ Several additional sections are not tied to the main API.
+ - \ref stream_callbacks
+ - \ref header_info
+ - \ref error_codes
+
+ \section Overview
+
+ The <tt>libopusfile</tt> API always decodes files to 48&nbsp;kHz.
+ The original sample rate is not preserved by the lossy compression, though
+ it is stored in the header to allow you to resample to it after decoding
+ (the <tt>libopusfile</tt> API does not currently provide a resampler,
+ but the
+ <a href="http://www.speex.org/docs/manual/speex-manual/node7.html#SECTION00760000000000000000">the
+ Speex resampler</a> is a good choice if you need one).
+ In general, if you are playing back the audio, you should leave it at
+ 48&nbsp;kHz, provided your audio hardware supports it.
+ When decoding to a file, it may be worth resampling back to the original
+ sample rate, so as not to surprise users who might not expect the sample
+ rate to change after encoding to Opus and decoding.
+
+ Opus files can contain anywhere from 1 to 255 channels of audio.
+ The channel mappings for up to 8 channels are the same as the
+ <a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
+ mappings</a>.
+ A special stereo API can convert everything to 2 channels, making it simple
+ to support multichannel files in an application which only has stereo
+ output.
+ Although the <tt>libopusfile</tt> ABI provides support for the theoretical
+ maximum number of channels, the current implementation does not support
+ files with more than 8 channels, as they do not have well-defined channel
+ mappings.
+
+ Like all Ogg files, Opus files may be "chained".
+ That is, multiple Opus files may be combined into a single, longer file just
+ by concatenating the original files.
+ This is commonly done in internet radio streaming, as it allows the title
+ and artist to be updated each time the song changes, since each link in the
+ chain includes its own set of metadata.
+
+ <tt>libopusfile</tt> fully supports chained files.
+ It will decode the first Opus stream found in each link of a chained file
+ (ignoring any other streams that might be concurrently multiplexed with it,
+ such as a video stream).
+
+ The channel count can also change between links.
+ If your application is not prepared to deal with this, it can use the stereo
+ API to ensure the audio from all links will always get decoded into a
+ common format.
+ Since <tt>libopusfile</tt> always decodes to 48&nbsp;kHz, you do not have to
+ worry about the sample rate changing between links (as was possible with
+ Vorbis).
+ This makes application support for chained files with <tt>libopusfile</tt>
+ very easy.*/
+
+# if defined(__cplusplus)
+extern "C" {
+# endif
+
+# include <stdarg.h>
+# include <stdio.h>
+# include <ogg/ogg.h>
+# include <opus_multistream.h>
+
+/**@cond PRIVATE*/
+
+/*Enable special features for gcc and gcc-compatible compilers.*/
+# if !defined(OP_GNUC_PREREQ)
+# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
+# define OP_GNUC_PREREQ(_maj,_min) \
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
+# else
+# define OP_GNUC_PREREQ(_maj,_min) 0
+# endif
+# endif
+
+# if OP_GNUC_PREREQ(4,0)
+# pragma GCC visibility push(default)
+# endif
+
+typedef struct OpusHead OpusHead;
+typedef struct OpusTags OpusTags;
+typedef struct OpusPictureTag OpusPictureTag;
+typedef struct OpusServerInfo OpusServerInfo;
+typedef struct OpusFileCallbacks OpusFileCallbacks;
+typedef struct OggOpusFile OggOpusFile;
+
+/*Warning attributes for libopusfile functions.*/
+# if OP_GNUC_PREREQ(3,4)
+# define OP_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+# else
+# define OP_WARN_UNUSED_RESULT
+# endif
+# if OP_GNUC_PREREQ(3,4)
+# define OP_ARG_NONNULL(_x) __attribute__((__nonnull__(_x)))
+# else
+# define OP_ARG_NONNULL(_x)
+# endif
+
+/**@endcond*/
+
+/**\defgroup error_codes Error Codes*/
+/*@{*/
+/**\name List of possible error codes
+ Many of the functions in this library return a negative error code when a
+ function fails.
+ This list provides a brief explanation of the common errors.
+ See each individual function for more details on what a specific error code
+ means in that context.*/
+/*@{*/
+
+/**A request did not succeed.*/
+#define OP_FALSE (-1)
+/*Currently not used externally.*/
+#define OP_EOF (-2)
+/**There was a hole in the page sequence numbers (e.g., a page was corrupt or
+ missing).*/
+#define OP_HOLE (-3)
+/**An underlying read, seek, or tell operation failed when it should have
+ succeeded.*/
+#define OP_EREAD (-128)
+/**A <code>NULL</code> pointer was passed where one was unexpected, or an
+ internal memory allocation failed, or an internal library error was
+ encountered.*/
+#define OP_EFAULT (-129)
+/**The stream used a feature that is not implemented, such as an unsupported
+ channel family.*/
+#define OP_EIMPL (-130)
+/**One or more parameters to a function were invalid.*/
+#define OP_EINVAL (-131)
+/**A purported Ogg Opus stream did not begin with an Ogg page, a purported
+ header packet did not start with one of the required strings, "OpusHead" or
+ "OpusTags", or a link in a chained file was encountered that did not
+ contain any logical Opus streams.*/
+#define OP_ENOTFORMAT (-132)
+/**A required header packet was not properly formatted, contained illegal
+ values, or was missing altogether.*/
+#define OP_EBADHEADER (-133)
+/**The ID header contained an unrecognized version number.*/
+#define OP_EVERSION (-134)
+/*Currently not used at all.*/
+#define OP_ENOTAUDIO (-135)
+/**An audio packet failed to decode properly.
+ This is usually caused by a multistream Ogg packet where the durations of
+ the individual Opus packets contained in it are not all the same.*/
+#define OP_EBADPACKET (-136)
+/**We failed to find data we had seen before, or the bitstream structure was
+ sufficiently malformed that seeking to the target destination was
+ impossible.*/
+#define OP_EBADLINK (-137)
+/**An operation that requires seeking was requested on an unseekable stream.*/
+#define OP_ENOSEEK (-138)
+/**The first or last granule position of a link failed basic validity checks.*/
+#define OP_EBADTIMESTAMP (-139)
+
+/*@}*/
+/*@}*/
+
+/**\defgroup header_info Header Information*/
+/*@{*/
+
+/**The maximum number of channels in an Ogg Opus stream.*/
+#define OPUS_CHANNEL_COUNT_MAX (255)
+
+/**Ogg Opus bitstream information.
+ This contains the basic playback parameters for a stream, and corresponds to
+ the initial ID header packet of an Ogg Opus stream.*/
+struct OpusHead{
+ /**The Ogg Opus format version, in the range 0...255.
+ The top 4 bits represent a "major" version, and the bottom four bits
+ represent backwards-compatible "minor" revisions.
+ The current specification describes version 1.
+ This library will recognize versions up through 15 as backwards compatible
+ with the current specification.
+ An earlier draft of the specification described a version 0, but the only
+ difference between version 1 and version 0 is that version 0 did
+ not specify the semantics for handling the version field.*/
+ int version;
+ /**The number of channels, in the range 1...255.*/
+ int channel_count;
+ /**The number of samples that should be discarded from the beginning of the
+ stream.*/
+ unsigned pre_skip;
+ /**The sampling rate of the original input.
+ All Opus audio is coded at 48 kHz, and should also be decoded at 48 kHz
+ for playback (unless the target hardware does not support this sampling
+ rate).
+ However, this field may be used to resample the audio back to the original
+ sampling rate, for example, when saving the output to a file.*/
+ opus_uint32 input_sample_rate;
+ /**The gain to apply to the decoded output, in dB, as a Q8 value in the range
+ -32768...32767.
+ The <tt>libopusfile</tt> API will automatically apply this gain to the
+ decoded output before returning it, scaling it by
+ <code>pow(10,output_gain/(20.0*256))</code>.*/
+ int output_gain;
+ /**The channel mapping family, in the range 0...255.
+ Channel mapping family 0 covers mono or stereo in a single stream.
+ Channel mapping family 1 covers 1 to 8 channels in one or more streams,
+ using the Vorbis speaker assignments.
+ Channel mapping family 255 covers 1 to 255 channels in one or more
+ streams, but without any defined speaker assignment.*/
+ int mapping_family;
+ /**The number of Opus streams in each Ogg packet, in the range 1...255.*/
+ int stream_count;
+ /**The number of coupled Opus streams in each Ogg packet, in the range
+ 0...127.
+ This must satisfy <code>0 <= coupled_count <= stream_count</code> and
+ <code>coupled_count + stream_count <= 255</code>.
+ The coupled streams appear first, before all uncoupled streams, in an Ogg
+ Opus packet.*/
+ int coupled_count;
+ /**The mapping from coded stream channels to output channels.
+ Let <code>index=mapping[k]</code> be the value for channel <code>k</code>.
+ If <code>index<2*coupled_count</code>, then it refers to the left channel
+ from stream <code>(index/2)</code> if even, and the right channel from
+ stream <code>(index/2)</code> if odd.
+ Otherwise, it refers to the output of the uncoupled stream
+ <code>(index-coupled_count)</code>.*/
+ unsigned char mapping[OPUS_CHANNEL_COUNT_MAX];
+};
+
+/**The metadata from an Ogg Opus stream.
+
+ This structure holds the in-stream metadata corresponding to the 'comment'
+ header packet of an Ogg Opus stream.
+ The comment header is meant to be used much like someone jotting a quick
+ note on the label of a CD.
+ It should be a short, to the point text note that can be more than a couple
+ words, but not more than a short paragraph.
+
+ The metadata is stored as a series of (tag, value) pairs, in length-encoded
+ string vectors, using the same format as Vorbis (without the final "framing
+ bit"), Theora, and Speex, except for the packet header.
+ The first occurrence of the '=' character delimits the tag and value.
+ A particular tag may occur more than once, and order is significant.
+ The character set encoding for the strings is always UTF-8, but the tag
+ names are limited to ASCII, and treated as case-insensitive.
+ See <a href="http://www.xiph.org/vorbis/doc/v-comment.html">the Vorbis
+ comment header specification</a> for details.
+
+ In filling in this structure, <tt>libopusfile</tt> will null-terminate the
+ #user_comments strings for safety.
+ However, the bitstream format itself treats them as 8-bit clean vectors,
+ possibly containing NUL characters, so the #comment_lengths array should be
+ treated as their authoritative length.
+
+ This structure is binary and source-compatible with a
+ <code>vorbis_comment</code>, and pointers to it may be freely cast to
+ <code>vorbis_comment</code> pointers, and vice versa.
+ It is provided as a separate type to avoid introducing a compile-time
+ dependency on the libvorbis headers.*/
+struct OpusTags{
+ /**The array of comment string vectors.*/
+ char **user_comments;
+ /**An array of the corresponding length of each vector, in bytes.*/
+ int *comment_lengths;
+ /**The total number of comment streams.*/
+ int comments;
+ /**The null-terminated vendor string.
+ This identifies the software used to encode the stream.*/
+ char *vendor;
+};
+
+/**\name Picture tag image formats*/
+/*@{*/
+
+/**The MIME type was not recognized, or the image data did not match the
+ declared MIME type.*/
+#define OP_PIC_FORMAT_UNKNOWN (-1)
+/**The MIME type indicates the image data is really a URL.*/
+#define OP_PIC_FORMAT_URL (0)
+/**The image is a JPEG.*/
+#define OP_PIC_FORMAT_JPEG (1)
+/**The image is a PNG.*/
+#define OP_PIC_FORMAT_PNG (2)
+/**The image is a GIF.*/
+#define OP_PIC_FORMAT_GIF (3)
+
+/*@}*/
+
+/**The contents of a METADATA_BLOCK_PICTURE tag.*/
+struct OpusPictureTag{
+ /**The picture type according to the ID3v2 APIC frame:
+ <ol start="0">
+ <li>Other</li>
+ <li>32x32 pixels 'file icon' (PNG only)</li>
+ <li>Other file icon</li>
+ <li>Cover (front)</li>
+ <li>Cover (back)</li>
+ <li>Leaflet page</li>
+ <li>Media (e.g. label side of CD)</li>
+ <li>Lead artist/lead performer/soloist</li>
+ <li>Artist/performer</li>
+ <li>Conductor</li>
+ <li>Band/Orchestra</li>
+ <li>Composer</li>
+ <li>Lyricist/text writer</li>
+ <li>Recording Location</li>
+ <li>During recording</li>
+ <li>During performance</li>
+ <li>Movie/video screen capture</li>
+ <li>A bright colored fish</li>
+ <li>Illustration</li>
+ <li>Band/artist logotype</li>
+ <li>Publisher/Studio logotype</li>
+ </ol>
+ Others are reserved and should not be used.
+ There may only be one each of picture type 1 and 2 in a file.*/
+ opus_int32 type;
+ /**The MIME type of the picture, in printable ASCII characters 0x20-0x7E.
+ The MIME type may also be <code>"-->"</code> to signify that the data part
+ is a URL pointing to the picture instead of the picture data itself.
+ In this case, a terminating NUL is appended to the URL string in #data,
+ but #data_length is set to the length of the string excluding that
+ terminating NUL.*/
+ char *mime_type;
+ /**The description of the picture, in UTF-8.*/
+ char *description;
+ /**The width of the picture in pixels.*/
+ opus_uint32 width;
+ /**The height of the picture in pixels.*/
+ opus_uint32 height;
+ /**The color depth of the picture in bits-per-pixel (<em>not</em>
+ bits-per-channel).*/
+ opus_uint32 depth;
+ /**For indexed-color pictures (e.g., GIF), the number of colors used, or 0
+ for non-indexed pictures.*/
+ opus_uint32 colors;
+ /**The length of the picture data in bytes.*/
+ opus_uint32 data_length;
+ /**The binary picture data.*/
+ unsigned char *data;
+ /**The format of the picture data, if known.
+ One of
+ <ul>
+ <li>#OP_PIC_FORMAT_UNKNOWN,</li>
+ <li>#OP_PIC_FORMAT_URL,</li>
+ <li>#OP_PIC_FORMAT_JPEG,</li>
+ <li>#OP_PIC_FORMAT_PNG, or</li>
+ <li>#OP_PIC_FORMAT_GIF.</li>
+ </ul>*/
+ int format;
+};
+
+/**\name Functions for manipulating header data
+
+ These functions manipulate the #OpusHead and #OpusTags structures,
+ which describe the audio parameters and tag-value metadata, respectively.
+ These can be used to query the headers returned by <tt>libopusfile</tt>, or
+ to parse Opus headers from sources other than an Ogg Opus stream, provided
+ they use the same format.*/
+/*@{*/
+
+/**Parses the contents of the ID header packet of an Ogg Opus stream.
+ \param[out] _head Returns the contents of the parsed packet.
+ The contents of this structure are untouched on error.
+ This may be <code>NULL</code> to merely test the header
+ for validity.
+ \param[in] _data The contents of the ID header packet.
+ \param _len The number of bytes of data in the ID header packet.
+ \return 0 on success or a negative value on error.
+ \retval #OP_ENOTFORMAT If the data does not start with the "OpusHead"
+ string.
+ \retval #OP_EVERSION If the version field signaled a version this library
+ does not know how to parse.
+ \retval #OP_EIMPL If the channel mapping family was 255, which general
+ purpose players should not attempt to play.
+ \retval #OP_EBADHEADER If the contents of the packet otherwise violate the
+ Ogg Opus specification:
+ <ul>
+ <li>Insufficient data,</li>
+ <li>Too much data for the known minor versions,</li>
+ <li>An unrecognized channel mapping family,</li>
+ <li>Zero channels or too many channels,</li>
+ <li>Zero coded streams,</li>
+ <li>Too many coupled streams, or</li>
+ <li>An invalid channel mapping index.</li>
+ </ul>*/
+OP_WARN_UNUSED_RESULT int opus_head_parse(OpusHead *_head,
+ const unsigned char *_data,size_t _len) OP_ARG_NONNULL(2);
+
+/**Converts a granule position to a sample offset for a given Ogg Opus stream.
+ The sample offset is simply <code>_gp-_head->pre_skip</code>.
+ Granule position values smaller than OpusHead#pre_skip correspond to audio
+ that should never be played, and thus have no associated sample offset.
+ This function returns -1 for such values.
+ This function also correctly handles extremely large granule positions,
+ which may have wrapped around to a negative number when stored in a signed
+ ogg_int64_t value.
+ \param _head The #OpusHead information from the ID header of the stream.
+ \param _gp The granule position to convert.
+ \return The sample offset associated with the given granule position
+ (counting at a 48 kHz sampling rate), or the special value -1 on
+ error (i.e., the granule position was smaller than the pre-skip
+ amount).*/
+ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp)
+ OP_ARG_NONNULL(1);
+
+/**Parses the contents of the 'comment' header packet of an Ogg Opus stream.
+ \param[out] _tags An uninitialized #OpusTags structure.
+ This returns the contents of the parsed packet.
+ The contents of this structure are untouched on error.
+ This may be <code>NULL</code> to merely test the header
+ for validity.
+ \param[in] _data The contents of the 'comment' header packet.
+ \param _len The number of bytes of data in the 'info' header packet.
+ \retval 0 Success.
+ \retval #OP_ENOTFORMAT If the data does not start with the "OpusTags"
+ string.
+ \retval #OP_EBADHEADER If the contents of the packet otherwise violate the
+ Ogg Opus specification.
+ \retval #OP_EFAULT If there wasn't enough memory to store the tags.*/
+OP_WARN_UNUSED_RESULT int opus_tags_parse(OpusTags *_tags,
+ const unsigned char *_data,size_t _len) OP_ARG_NONNULL(2);
+
+/**Performs a deep copy of an #OpusTags structure.
+ \param _dst The #OpusTags structure to copy into.
+ If this function fails, the contents of this structure remain
+ untouched.
+ \param _src The #OpusTags structure to copy from.
+ \retval 0 Success.
+ \retval #OP_EFAULT If there wasn't enough memory to copy the tags.*/
+int opus_tags_copy(OpusTags *_dst,const OpusTags *_src) OP_ARG_NONNULL(1);
+
+/**Initializes an #OpusTags structure.
+ This should be called on a freshly allocated #OpusTags structure before
+ attempting to use it.
+ \param _tags The #OpusTags structure to initialize.*/
+void opus_tags_init(OpusTags *_tags) OP_ARG_NONNULL(1);
+
+/**Add a (tag, value) pair to an initialized #OpusTags structure.
+ \note Neither opus_tags_add() nor opus_tags_add_comment() support values
+ containing embedded NULs, although the bitstream format does support them.
+ To add such tags, you will need to manipulate the #OpusTags structure
+ directly.
+ \param _tags The #OpusTags structure to add the (tag, value) pair to.
+ \param _tag A NUL-terminated, case-insensitive, ASCII string containing
+ the tag to add (without an '=' character).
+ \param _value A NUL-terminated UTF-8 containing the corresponding value.
+ \return 0 on success, or a negative value on failure.
+ \retval #OP_EFAULT An internal memory allocation failed.*/
+int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2) OP_ARG_NONNULL(3);
+
+/**Add a comment to an initialized #OpusTags structure.
+ \note Neither opus_tags_add_comment() nor opus_tags_add() support comments
+ containing embedded NULs, although the bitstream format does support them.
+ To add such tags, you will need to manipulate the #OpusTags structure
+ directly.
+ \param _tags The #OpusTags structure to add the comment to.
+ \param _comment A NUL-terminated UTF-8 string containing the comment in
+ "TAG=value" form.
+ \return 0 on success, or a negative value on failure.
+ \retval #OP_EFAULT An internal memory allocation failed.*/
+int opus_tags_add_comment(OpusTags *_tags,const char *_comment)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Replace the binary suffix data at the end of the packet (if any).
+ \param _tags An initialized #OpusTags structure.
+ \param _data A buffer of binary data to append after the encoded user
+ comments.
+ The least significant bit of the first byte of this data must
+ be set (to ensure the data is preserved by other editors).
+ \param _len The number of bytes of binary data to append.
+ This may be zero to remove any existing binary suffix data.
+ \return 0 on success, or a negative value on error.
+ \retval #OP_EINVAL \a _len was negative, or \a _len was positive but
+ \a _data was <code>NULL</code> or the least significant
+ bit of the first byte was not set.
+ \retval #OP_EFAULT An internal memory allocation failed.*/
+int opus_tags_set_binary_suffix(OpusTags *_tags,
+ const unsigned char *_data,int _len) OP_ARG_NONNULL(1);
+
+/**Look up a comment value by its tag.
+ \param _tags An initialized #OpusTags structure.
+ \param _tag The tag to look up.
+ \param _count The instance of the tag.
+ The same tag can appear multiple times, each with a distinct
+ value, so an index is required to retrieve them all.
+ The order in which these values appear is significant and
+ should be preserved.
+ Use opus_tags_query_count() to get the legal range for the
+ \a _count parameter.
+ \return A pointer to the queried tag's value.
+ This points directly to data in the #OpusTags structure.
+ It should not be modified or freed by the application, and
+ modifications to the structure may invalidate the pointer.
+ \retval NULL If no matching tag is found.*/
+const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Look up the number of instances of a tag.
+ Call this first when querying for a specific tag and then iterate over the
+ number of instances with separate calls to opus_tags_query() to retrieve
+ all the values for that tag in order.
+ \param _tags An initialized #OpusTags structure.
+ \param _tag The tag to look up.
+ \return The number of instances of this particular tag.*/
+int opus_tags_query_count(const OpusTags *_tags,const char *_tag)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Retrieve the binary suffix data at the end of the packet (if any).
+ \param _tags An initialized #OpusTags structure.
+ \param[out] _len Returns the number of bytes of binary suffix data returned.
+ \return A pointer to the binary suffix data, or <code>NULL</code> if none
+ was present.*/
+const unsigned char *opus_tags_get_binary_suffix(const OpusTags *_tags,
+ int *_len) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Get the album gain from an R128_ALBUM_GAIN tag, if one was specified.
+ This searches for the first R128_ALBUM_GAIN tag with a valid signed,
+ 16-bit decimal integer value and returns the value.
+ This routine is exposed merely for convenience for applications which wish
+ to do something special with the album gain (i.e., display it).
+ If you simply wish to apply the album gain instead of the header gain, you
+ can use op_set_gain_offset() with an #OP_ALBUM_GAIN type and no offset.
+ \param _tags An initialized #OpusTags structure.
+ \param[out] _gain_q8 The album gain, in 1/256ths of a dB.
+ This will lie in the range [-32768,32767], and should
+ be applied in <em>addition</em> to the header gain.
+ On error, no value is returned, and the previous
+ contents remain unchanged.
+ \return 0 on success, or a negative value on error.
+ \retval #OP_FALSE There was no album gain available in the given tags.*/
+int opus_tags_get_album_gain(const OpusTags *_tags,int *_gain_q8)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Get the track gain from an R128_TRACK_GAIN tag, if one was specified.
+ This searches for the first R128_TRACK_GAIN tag with a valid signed,
+ 16-bit decimal integer value and returns the value.
+ This routine is exposed merely for convenience for applications which wish
+ to do something special with the track gain (i.e., display it).
+ If you simply wish to apply the track gain instead of the header gain, you
+ can use op_set_gain_offset() with an #OP_TRACK_GAIN type and no offset.
+ \param _tags An initialized #OpusTags structure.
+ \param[out] _gain_q8 The track gain, in 1/256ths of a dB.
+ This will lie in the range [-32768,32767], and should
+ be applied in <em>addition</em> to the header gain.
+ On error, no value is returned, and the previous
+ contents remain unchanged.
+ \return 0 on success, or a negative value on error.
+ \retval #OP_FALSE There was no track gain available in the given tags.*/
+int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Clears the #OpusTags structure.
+ This should be called on an #OpusTags structure after it is no longer
+ needed.
+ It will free all memory used by the structure members.
+ \param _tags The #OpusTags structure to clear.*/
+void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1);
+
+/**Check if \a _comment is an instance of a \a _tag_name tag.
+ \see opus_tagncompare
+ \param _tag_name A NUL-terminated, case-insensitive, ASCII string containing
+ the name of the tag to check for (without the terminating
+ '=' character).
+ \param _comment The comment string to check.
+ \return An integer less than, equal to, or greater than zero if \a _comment
+ is found respectively, to be less than, to match, or be greater
+ than a "tag=value" string whose tag matches \a _tag_name.*/
+int opus_tagcompare(const char *_tag_name,const char *_comment);
+
+/**Check if \a _comment is an instance of a \a _tag_name tag.
+ This version is slightly more efficient than opus_tagcompare() if the length
+ of the tag name is already known (e.g., because it is a constant).
+ \see opus_tagcompare
+ \param _tag_name A case-insensitive ASCII string containing the name of the
+ tag to check for (without the terminating '=' character).
+ \param _tag_len The number of characters in the tag name.
+ This must be non-negative.
+ \param _comment The comment string to check.
+ \return An integer less than, equal to, or greater than zero if \a _comment
+ is found respectively, to be less than, to match, or be greater
+ than a "tag=value" string whose tag matches the first \a _tag_len
+ characters of \a _tag_name.*/
+int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment);
+
+/**Parse a single METADATA_BLOCK_PICTURE tag.
+ This decodes the BASE64-encoded content of the tag and returns a structure
+ with the MIME type, description, image parameters (if known), and the
+ compressed image data.
+ If the MIME type indicates the presence of an image format we recognize
+ (JPEG, PNG, or GIF) and the actual image data contains the magic signature
+ associated with that format, then the OpusPictureTag::format field will be
+ set to the corresponding format.
+ This is provided as a convenience to avoid requiring applications to parse
+ the MIME type and/or do their own format detection for the commonly used
+ formats.
+ In this case, we also attempt to extract the image parameters directly from
+ the image data (overriding any that were present in the tag, which the
+ specification says applications are not meant to rely on).
+ The application must still provide its own support for actually decoding the
+ image data and, if applicable, retrieving that data from URLs.
+ \param[out] _pic Returns the parsed picture data.
+ No sanitation is done on the type, MIME type, or
+ description fields, so these might return invalid values.
+ The contents of this structure are left unmodified on
+ failure.
+ \param _tag The METADATA_BLOCK_PICTURE tag contents.
+ The leading "METADATA_BLOCK_PICTURE=" portion is optional,
+ to allow the function to be used on either directly on the
+ values in OpusTags::user_comments or on the return value
+ of opus_tags_query().
+ \return 0 on success or a negative value on error.
+ \retval #OP_ENOTFORMAT The METADATA_BLOCK_PICTURE contents were not valid.
+ \retval #OP_EFAULT There was not enough memory to store the picture tag
+ contents.*/
+OP_WARN_UNUSED_RESULT int opus_picture_tag_parse(OpusPictureTag *_pic,
+ const char *_tag) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Initializes an #OpusPictureTag structure.
+ This should be called on a freshly allocated #OpusPictureTag structure
+ before attempting to use it.
+ \param _pic The #OpusPictureTag structure to initialize.*/
+void opus_picture_tag_init(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
+
+/**Clears the #OpusPictureTag structure.
+ This should be called on an #OpusPictureTag structure after it is no longer
+ needed.
+ It will free all memory used by the structure members.
+ \param _pic The #OpusPictureTag structure to clear.*/
+void opus_picture_tag_clear(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
+
+/*@}*/
+
+/*@}*/
+
+/**\defgroup url_options URL Reading Options*/
+/*@{*/
+/**\name URL reading options
+ Options for op_url_stream_create() and associated functions.
+ These allow you to provide proxy configuration parameters, skip SSL
+ certificate checks, etc.
+ Options are processed in order, and if the same option is passed multiple
+ times, only the value specified by the last occurrence has an effect
+ (unless otherwise specified).
+ They may be expanded in the future.*/
+/*@{*/
+
+/**@cond PRIVATE*/
+
+/*These are the raw numbers used to define the request codes.
+ They should not be used directly.*/
+#define OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST (6464)
+#define OP_HTTP_PROXY_HOST_REQUEST (6528)
+#define OP_HTTP_PROXY_PORT_REQUEST (6592)
+#define OP_HTTP_PROXY_USER_REQUEST (6656)
+#define OP_HTTP_PROXY_PASS_REQUEST (6720)
+#define OP_GET_SERVER_INFO_REQUEST (6784)
+
+#define OP_URL_OPT(_request) ((_request)+(char *)0)
+
+/*These macros trigger compilation errors or warnings if the wrong types are
+ provided to one of the URL options.*/
+#define OP_CHECK_INT(_x) ((void)((_x)==(opus_int32)0),(opus_int32)(_x))
+#define OP_CHECK_CONST_CHAR_PTR(_x) ((_x)+((_x)-(const char *)(_x)))
+#define OP_CHECK_SERVER_INFO_PTR(_x) ((_x)+((_x)-(OpusServerInfo *)(_x)))
+
+/**@endcond*/
+
+/**HTTP/Shoutcast/Icecast server information associated with a URL.*/
+struct OpusServerInfo{
+ /**The name of the server (icy-name/ice-name).
+ This is <code>NULL</code> if there was no <code>icy-name</code> or
+ <code>ice-name</code> header.*/
+ char *name;
+ /**A short description of the server (icy-description/ice-description).
+ This is <code>NULL</code> if there was no <code>icy-description</code> or
+ <code>ice-description</code> header.*/
+ char *description;
+ /**The genre the server falls under (icy-genre/ice-genre).
+ This is <code>NULL</code> if there was no <code>icy-genre</code> or
+ <code>ice-genre</code> header.*/
+ char *genre;
+ /**The homepage for the server (icy-url/ice-url).
+ This is <code>NULL</code> if there was no <code>icy-url</code> or
+ <code>ice-url</code> header.*/
+ char *url;
+ /**The software used by the origin server (Server).
+ This is <code>NULL</code> if there was no <code>Server</code> header.*/
+ char *server;
+ /**The media type of the entity sent to the recepient (Content-Type).
+ This is <code>NULL</code> if there was no <code>Content-Type</code>
+ header.*/
+ char *content_type;
+ /**The nominal stream bitrate in kbps (icy-br/ice-bitrate).
+ This is <code>-1</code> if there was no <code>icy-br</code> or
+ <code>ice-bitrate</code> header.*/
+ opus_int32 bitrate_kbps;
+ /**Flag indicating whether the server is public (<code>1</code>) or not
+ (<code>0</code>) (icy-pub/ice-public).
+ This is <code>-1</code> if there was no <code>icy-pub</code> or
+ <code>ice-public</code> header.*/
+ int is_public;
+ /**Flag indicating whether the server is using HTTPS instead of HTTP.
+ This is <code>0</code> unless HTTPS is being used.
+ This may not match the protocol used in the original URL if there were
+ redirections.*/
+ int is_ssl;
+};
+
+/**Initializes an #OpusServerInfo structure.
+ All fields are set as if the corresponding header was not available.
+ \param _info The #OpusServerInfo structure to initialize.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.*/
+void opus_server_info_init(OpusServerInfo *_info) OP_ARG_NONNULL(1);
+
+/**Clears the #OpusServerInfo structure.
+ This should be called on an #OpusServerInfo structure after it is no longer
+ needed.
+ It will free all memory used by the structure members.
+ \param _info The #OpusServerInfo structure to clear.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.*/
+void opus_server_info_clear(OpusServerInfo *_info) OP_ARG_NONNULL(1);
+
+/**Skip the certificate check when connecting via TLS/SSL (https).
+ \param _b <code>opus_int32</code>: Whether or not to skip the certificate
+ check.
+ The check will be skipped if \a _b is non-zero, and will not be
+ skipped if \a _b is zero.
+ \hideinitializer*/
+#define OP_SSL_SKIP_CERTIFICATE_CHECK(_b) \
+ OP_URL_OPT(OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST),OP_CHECK_INT(_b)
+
+/**Proxy connections through the given host.
+ If no port is specified via #OP_HTTP_PROXY_PORT, the port number defaults
+ to 8080 (http-alt).
+ All proxy parameters are ignored for non-http and non-https URLs.
+ \param _host <code>const char *</code>: The proxy server hostname.
+ This may be <code>NULL</code> to disable the use of a proxy
+ server.
+ \hideinitializer*/
+#define OP_HTTP_PROXY_HOST(_host) \
+ OP_URL_OPT(OP_HTTP_PROXY_HOST_REQUEST),OP_CHECK_CONST_CHAR_PTR(_host)
+
+/**Use the given port when proxying connections.
+ This option only has an effect if #OP_HTTP_PROXY_HOST is specified with a
+ non-<code>NULL</code> \a _host.
+ If this option is not provided, the proxy port number defaults to 8080
+ (http-alt).
+ All proxy parameters are ignored for non-http and non-https URLs.
+ \param _port <code>opus_int32</code>: The proxy server port.
+ This must be in the range 0...65535 (inclusive), or the
+ URL function this is passed to will fail.
+ \hideinitializer*/
+#define OP_HTTP_PROXY_PORT(_port) \
+ OP_URL_OPT(OP_HTTP_PROXY_PORT_REQUEST),OP_CHECK_INT(_port)
+
+/**Use the given user name for authentication when proxying connections.
+ All proxy parameters are ignored for non-http and non-https URLs.
+ \param _user const char *: The proxy server user name.
+ This may be <code>NULL</code> to disable proxy
+ authentication.
+ A non-<code>NULL</code> value only has an effect
+ if #OP_HTTP_PROXY_HOST and #OP_HTTP_PROXY_PASS
+ are also specified with non-<code>NULL</code>
+ arguments.
+ \hideinitializer*/
+#define OP_HTTP_PROXY_USER(_user) \
+ OP_URL_OPT(OP_HTTP_PROXY_USER_REQUEST),OP_CHECK_CONST_CHAR_PTR(_user)
+
+/**Use the given password for authentication when proxying connections.
+ All proxy parameters are ignored for non-http and non-https URLs.
+ \param _pass const char *: The proxy server password.
+ This may be <code>NULL</code> to disable proxy
+ authentication.
+ A non-<code>NULL</code> value only has an effect
+ if #OP_HTTP_PROXY_HOST and #OP_HTTP_PROXY_USER
+ are also specified with non-<code>NULL</code>
+ arguments.
+ \hideinitializer*/
+#define OP_HTTP_PROXY_PASS(_pass) \
+ OP_URL_OPT(OP_HTTP_PROXY_PASS_REQUEST),OP_CHECK_CONST_CHAR_PTR(_pass)
+
+/**Parse information about the streaming server (if any) and return it.
+ Very little validation is done.
+ In particular, OpusServerInfo::url may not be a valid URL,
+ OpusServerInfo::bitrate_kbps may not really be in kbps, and
+ OpusServerInfo::content_type may not be a valid MIME type.
+ The character set of the string fields is not specified anywhere, and should
+ not be assumed to be valid UTF-8.
+ \param _info OpusServerInfo *: Returns information about the server.
+ If there is any error opening the stream, the
+ contents of this structure remain
+ unmodified.
+ On success, fills in the structure with the
+ server information that was available, if
+ any.
+ After a successful return, the contents of
+ this structure should be freed by calling
+ opus_server_info_clear().
+ \hideinitializer*/
+#define OP_GET_SERVER_INFO(_info) \
+ OP_URL_OPT(OP_GET_SERVER_INFO_REQUEST),OP_CHECK_SERVER_INFO_PTR(_info)
+
+/*@}*/
+/*@}*/
+
+/**\defgroup stream_callbacks Abstract Stream Reading Interface*/
+/*@{*/
+/**\name Functions for reading from streams
+ These functions define the interface used to read from and seek in a stream
+ of data.
+ A stream does not need to implement seeking, but the decoder will not be
+ able to seek if it does not do so.
+ These functions also include some convenience routines for working with
+ standard <code>FILE</code> pointers, complete streams stored in a single
+ block of memory, or URLs.*/
+/*@{*/
+
+/**Reads up to \a _nbytes bytes of data from \a _stream.
+ \param _stream The stream to read from.
+ \param[out] _ptr The buffer to store the data in.
+ \param _nbytes The maximum number of bytes to read.
+ This function may return fewer, though it will not
+ return zero unless it reaches end-of-file.
+ \return The number of bytes successfully read, or a negative value on
+ error.*/
+typedef int (*op_read_func)(void *_stream,unsigned char *_ptr,int _nbytes);
+
+/**Sets the position indicator for \a _stream.
+ The new position, measured in bytes, is obtained by adding \a _offset
+ bytes to the position specified by \a _whence.
+ If \a _whence is set to <code>SEEK_SET</code>, <code>SEEK_CUR</code>, or
+ <code>SEEK_END</code>, the offset is relative to the start of the stream,
+ the current position indicator, or end-of-file, respectively.
+ \retval 0 Success.
+ \retval -1 Seeking is not supported or an error occurred.
+ <code>errno</code> need not be set.*/
+typedef int (*op_seek_func)(void *_stream,opus_int64 _offset,int _whence);
+
+/**Obtains the current value of the position indicator for \a _stream.
+ \return The current position indicator.*/
+typedef opus_int64 (*op_tell_func)(void *_stream);
+
+/**Closes the underlying stream.
+ \retval 0 Success.
+ \retval EOF An error occurred.
+ <code>errno</code> need not be set.*/
+typedef int (*op_close_func)(void *_stream);
+
+/**The callbacks used to access non-<code>FILE</code> stream resources.
+ The function prototypes are basically the same as for the stdio functions
+ <code>fread()</code>, <code>fseek()</code>, <code>ftell()</code>, and
+ <code>fclose()</code>.
+ The differences are that the <code>FILE *</code> arguments have been
+ replaced with a <code>void *</code>, which is to be used as a pointer to
+ whatever internal data these functions might need, that #seek and #tell
+ take and return 64-bit offsets, and that #seek <em>must</em> return -1 if
+ the stream is unseekable.*/
+struct OpusFileCallbacks{
+ /**Used to read data from the stream.
+ This must not be <code>NULL</code>.*/
+ op_read_func read;
+ /**Used to seek in the stream.
+ This may be <code>NULL</code> if seeking is not implemented.*/
+ op_seek_func seek;
+ /**Used to return the current read position in the stream.
+ This may be <code>NULL</code> if seeking is not implemented.*/
+ op_tell_func tell;
+ /**Used to close the stream when the decoder is freed.
+ This may be <code>NULL</code> to leave the stream open.*/
+ op_close_func close;
+};
+
+/**Opens a stream with <code>fopen()</code> and fills in a set of callbacks
+ that can be used to access it.
+ This is useful to avoid writing your own portable 64-bit seeking wrappers,
+ and also avoids cross-module linking issues on Windows, where a
+ <code>FILE *</code> must be accessed by routines defined in the same module
+ that opened it.
+ \param[out] _cb The callbacks to use for this file.
+ If there is an error opening the file, nothing will be
+ filled in here.
+ \param _path The path to the file to open.
+ On Windows, this string must be UTF-8 (to allow access to
+ files whose names cannot be represented in the current
+ MBCS code page).
+ All other systems use the native character encoding.
+ \param _mode The mode to open the file in.
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_fopen(OpusFileCallbacks *_cb,
+ const char *_path,const char *_mode) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2)
+ OP_ARG_NONNULL(3);
+
+/**Opens a stream with <code>fdopen()</code> and fills in a set of callbacks
+ that can be used to access it.
+ This is useful to avoid writing your own portable 64-bit seeking wrappers,
+ and also avoids cross-module linking issues on Windows, where a
+ <code>FILE *</code> must be accessed by routines defined in the same module
+ that opened it.
+ \param[out] _cb The callbacks to use for this file.
+ If there is an error opening the file, nothing will be
+ filled in here.
+ \param _fd The file descriptor to open.
+ \param _mode The mode to open the file in.
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_fdopen(OpusFileCallbacks *_cb,
+ int _fd,const char *_mode) OP_ARG_NONNULL(1) OP_ARG_NONNULL(3);
+
+/**Opens a stream with <code>freopen()</code> and fills in a set of callbacks
+ that can be used to access it.
+ This is useful to avoid writing your own portable 64-bit seeking wrappers,
+ and also avoids cross-module linking issues on Windows, where a
+ <code>FILE *</code> must be accessed by routines defined in the same module
+ that opened it.
+ \param[out] _cb The callbacks to use for this file.
+ If there is an error opening the file, nothing will be
+ filled in here.
+ \param _path The path to the file to open.
+ On Windows, this string must be UTF-8 (to allow access
+ to files whose names cannot be represented in the
+ current MBCS code page).
+ All other systems use the native character encoding.
+ \param _mode The mode to open the file in.
+ \param _stream A stream previously returned by op_fopen(), op_fdopen(),
+ or op_freopen().
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_freopen(OpusFileCallbacks *_cb,
+ const char *_path,const char *_mode,void *_stream) OP_ARG_NONNULL(1)
+ OP_ARG_NONNULL(2) OP_ARG_NONNULL(3) OP_ARG_NONNULL(4);
+
+/**Creates a stream that reads from the given block of memory.
+ This block of memory must contain the complete stream to decode.
+ This is useful for caching small streams (e.g., sound effects) in RAM.
+ \param[out] _cb The callbacks to use for this stream.
+ If there is an error creating the stream, nothing will be
+ filled in here.
+ \param _data The block of memory to read from.
+ \param _size The size of the block of memory.
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_mem_stream_create(OpusFileCallbacks *_cb,
+ const unsigned char *_data,size_t _size) OP_ARG_NONNULL(1);
+
+/**Creates a stream that reads from the given URL.
+ This function behaves identically to op_url_stream_create(), except that it
+ takes a va_list instead of a variable number of arguments.
+ It does not call the <code>va_end</code> macro, and because it invokes the
+ <code>va_arg</code> macro, the value of \a _ap is undefined after the call.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \param[out] _cb The callbacks to use for this stream.
+ If there is an error creating the stream, nothing will
+ be filled in here.
+ \param _url The URL to read from.
+ Currently only the <file:>, <http:>, and <https:>
+ schemes are supported.
+ Both <http:> and <https:> may be disabled at compile
+ time, in which case opening such URLs will always fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped, with
+ internationalized domain names encoded in punycode,
+ before passing them to this function.
+ \param[in,out] _ap A list of the \ref url_options "optional flags" to use.
+ This is a variable-length list of options terminated
+ with <code>NULL</code>.
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_url_stream_vcreate(OpusFileCallbacks *_cb,
+ const char *_url,va_list _ap) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Creates a stream that reads from the given URL.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \param[out] _cb The callbacks to use for this stream.
+ If there is an error creating the stream, nothing will be
+ filled in here.
+ \param _url The URL to read from.
+ Currently only the <file:>, <http:>, and <https:> schemes
+ are supported.
+ Both <http:> and <https:> may be disabled at compile time,
+ in which case opening such URLs will always fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped, with
+ internationalized domain names encoded in punycode, before
+ passing them to this function.
+ \param ... The \ref url_options "optional flags" to use.
+ This is a variable-length list of options terminated with
+ <code>NULL</code>.
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_url_stream_create(OpusFileCallbacks *_cb,
+ const char *_url,...) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/*@}*/
+/*@}*/
+
+/**\defgroup stream_open_close Opening and Closing*/
+/*@{*/
+/**\name Functions for opening and closing streams
+
+ These functions allow you to test a stream to see if it is Opus, open it,
+ and close it.
+ Several flavors are provided for each of the built-in stream types, plus a
+ more general version which takes a set of application-provided callbacks.*/
+/*@{*/
+
+/**Test to see if this is an Opus stream.
+ For good results, you will need at least 57 bytes (for a pure Opus-only
+ stream).
+ Something like 512 bytes will give more reliable results for multiplexed
+ streams.
+ This function is meant to be a quick-rejection filter.
+ Its purpose is not to guarantee that a stream is a valid Opus stream, but to
+ ensure that it looks enough like Opus that it isn't going to be recognized
+ as some other format (except possibly an Opus stream that is also
+ multiplexed with other codecs, such as video).
+ \param[out] _head The parsed ID header contents.
+ You may pass <code>NULL</code> if you do not need
+ this information.
+ If the function fails, the contents of this structure
+ remain untouched.
+ \param _initial_data An initial buffer of data from the start of the
+ stream.
+ \param _initial_bytes The number of bytes in \a _initial_data.
+ \return 0 if the data appears to be Opus, or a negative value on error.
+ \retval #OP_FALSE There was not enough data to tell if this was an Opus
+ stream or not.
+ \retval #OP_EFAULT An internal memory allocation failed.
+ \retval #OP_EIMPL The stream used a feature that is not implemented,
+ such as an unsupported channel family.
+ \retval #OP_ENOTFORMAT If the data did not contain a recognizable ID
+ header for an Opus stream.
+ \retval #OP_EVERSION If the version field signaled a version this library
+ does not know how to parse.
+ \retval #OP_EBADHEADER The ID header was not properly formatted or contained
+ illegal values.*/
+int op_test(OpusHead *_head,
+ const unsigned char *_initial_data,size_t _initial_bytes);
+
+/**Open a stream from the given file path.
+ \param _path The path to the file to open.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ The failure code will be #OP_EFAULT if the file could not
+ be opened, or one of the other failure codes from
+ op_open_callbacks() otherwise.
+ \return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_open_file(const char *_path,int *_error)
+ OP_ARG_NONNULL(1);
+
+/**Open a stream from a memory buffer.
+ \param _data The memory buffer to open.
+ \param _size The number of bytes in the buffer.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ See op_open_callbacks() for a full list of failure codes.
+ \return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_open_memory(const unsigned char *_data,
+ size_t _size,int *_error);
+
+/**Open a stream from a URL.
+ This function behaves identically to op_open_url(), except that it
+ takes a va_list instead of a variable number of arguments.
+ It does not call the <code>va_end</code> macro, and because it invokes the
+ <code>va_arg</code> macro, the value of \a _ap is undefined after the call.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \param _url The URL to open.
+ Currently only the <file:>, <http:>, and <https:>
+ schemes are supported.
+ Both <http:> and <https:> may be disabled at compile
+ time, in which case opening such URLs will always
+ fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped,
+ with internationalized domain names encoded in
+ punycode, before passing them to this function.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want
+ the failure code.
+ See op_open_callbacks() for a full list of failure
+ codes.
+ \param[in,out] _ap A list of the \ref url_options "optional flags" to
+ use.
+ This is a variable-length list of options terminated
+ with <code>NULL</code>.
+ \return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_vopen_url(const char *_url,
+ int *_error,va_list _ap) OP_ARG_NONNULL(1);
+
+/**Open a stream from a URL.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \param _url The URL to open.
+ Currently only the <file:>, <http:>, and <https:> schemes
+ are supported.
+ Both <http:> and <https:> may be disabled at compile
+ time, in which case opening such URLs will always fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped, with
+ internationalized domain names encoded in punycode,
+ before passing them to this function.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ See op_open_callbacks() for a full list of failure codes.
+ \param ... The \ref url_options "optional flags" to use.
+ This is a variable-length list of options terminated with
+ <code>NULL</code>.
+ \return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url,
+ int *_error,...) OP_ARG_NONNULL(1);
+
+/**Open a stream using the given set of callbacks to access it.
+ \param _source The stream to read from (e.g., a <code>FILE *</code>).
+ \param _cb The callbacks with which to access the stream.
+ <code><a href="#op_read_func">read()</a></code> must
+ be implemented.
+ <code><a href="#op_seek_func">seek()</a></code> and
+ <code><a href="#op_tell_func">tell()</a></code> may
+ be <code>NULL</code>, or may always return -1 to
+ indicate a source is unseekable, but if
+ <code><a href="#op_seek_func">seek()</a></code> is
+ implemented and succeeds on a particular source, then
+ <code><a href="#op_tell_func">tell()</a></code> must
+ also.
+ <code><a href="#op_close_func">close()</a></code> may
+ be <code>NULL</code>, but if it is not, it will be
+ called when the \c OggOpusFile is destroyed by
+ op_free().
+ It will not be called if op_open_callbacks() fails
+ with an error.
+ \param _initial_data An initial buffer of data from the start of the
+ stream.
+ Applications can read some number of bytes from the
+ start of the stream to help identify this as an Opus
+ stream, and then provide them here to allow the
+ stream to be opened, even if it is unseekable.
+ \param _initial_bytes The number of bytes in \a _initial_data.
+ If the stream is seekable, its current position (as
+ reported by
+ <code><a href="#opus_tell_func">tell()</a></code>
+ at the start of this function) must be equal to
+ \a _initial_bytes.
+ Otherwise, seeking to absolute positions will
+ generate inconsistent results.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want
+ the failure code.
+ The failure code will be one of
+ <dl>
+ <dt>#OP_EREAD</dt>
+ <dd>An underlying read, seek, or tell operation
+ failed when it should have succeeded, or we failed
+ to find data in the stream we had seen before.</dd>
+ <dt>#OP_EFAULT</dt>
+ <dd>There was a memory allocation failure, or an
+ internal library error.</dd>
+ <dt>#OP_EIMPL</dt>
+ <dd>The stream used a feature that is not
+ implemented, such as an unsupported channel
+ family.</dd>
+ <dt>#OP_EINVAL</dt>
+ <dd><code><a href="#op_seek_func">seek()</a></code>
+ was implemented and succeeded on this source, but
+ <code><a href="#op_tell_func">tell()</a></code>
+ did not, or the starting position indicator was
+ not equal to \a _initial_bytes.</dd>
+ <dt>#OP_ENOTFORMAT</dt>
+ <dd>The stream contained a link that did not have
+ any logical Opus streams in it.</dd>
+ <dt>#OP_EBADHEADER</dt>
+ <dd>A required header packet was not properly
+ formatted, contained illegal values, or was missing
+ altogether.</dd>
+ <dt>#OP_EVERSION</dt>
+ <dd>An ID header contained an unrecognized version
+ number.</dd>
+ <dt>#OP_EBADLINK</dt>
+ <dd>We failed to find data we had seen before after
+ seeking.</dd>
+ <dt>#OP_EBADTIMESTAMP</dt>
+ <dd>The first or last timestamp in a link failed
+ basic validity checks.</dd>
+ </dl>
+ \return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.
+ <tt>libopusfile</tt> does <em>not</em> take ownership of the source
+ if the call fails.
+ The calling application is responsible for closing the source if
+ this call returns an error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_open_callbacks(void *_source,
+ const OpusFileCallbacks *_cb,const unsigned char *_initial_data,
+ size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2);
+
+/**Partially open a stream from the given file path.
+ \see op_test_callbacks
+ \param _path The path to the file to open.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ The failure code will be #OP_EFAULT if the file could not
+ be opened, or one of the other failure codes from
+ op_open_callbacks() otherwise.
+ \return A partially opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_test_file(const char *_path,int *_error)
+ OP_ARG_NONNULL(1);
+
+/**Partially open a stream from a memory buffer.
+ \see op_test_callbacks
+ \param _data The memory buffer to open.
+ \param _size The number of bytes in the buffer.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ See op_open_callbacks() for a full list of failure codes.
+ \return A partially opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_test_memory(const unsigned char *_data,
+ size_t _size,int *_error);
+
+/**Partially open a stream from a URL.
+ This function behaves identically to op_test_url(), except that it
+ takes a va_list instead of a variable number of arguments.
+ It does not call the <code>va_end</code> macro, and because it invokes the
+ <code>va_arg</code> macro, the value of \a _ap is undefined after the call.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \see op_test_url
+ \see op_test_callbacks
+ \param _url The URL to open.
+ Currently only the <file:>, <http:>, and <https:>
+ schemes are supported.
+ Both <http:> and <https:> may be disabled at compile
+ time, in which case opening such URLs will always
+ fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped,
+ with internationalized domain names encoded in
+ punycode, before passing them to this function.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want
+ the failure code.
+ See op_open_callbacks() for a full list of failure
+ codes.
+ \param[in,out] _ap A list of the \ref url_options "optional flags" to
+ use.
+ This is a variable-length list of options terminated
+ with <code>NULL</code>.
+ \return A partially opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_vtest_url(const char *_url,
+ int *_error,va_list _ap) OP_ARG_NONNULL(1);
+
+/**Partially open a stream from a URL.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \see op_test_callbacks
+ \param _url The URL to open.
+ Currently only the <file:>, <http:>, and <https:>
+ schemes are supported.
+ Both <http:> and <https:> may be disabled at compile
+ time, in which case opening such URLs will always fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped, with
+ internationalized domain names encoded in punycode,
+ before passing them to this function.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ See op_open_callbacks() for a full list of failure
+ codes.
+ \param ... The \ref url_options "optional flags" to use.
+ This is a variable-length list of options terminated
+ with <code>NULL</code>.
+ \return A partially opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url,
+ int *_error,...) OP_ARG_NONNULL(1);
+
+/**Partially open a stream using the given set of callbacks to access it.
+ This tests for Opusness and loads the headers for the first link.
+ It does not seek (although it tests for seekability).
+ You can query a partially open stream for the few pieces of basic
+ information returned by op_serialno(), op_channel_count(), op_head(), and
+ op_tags() (but only for the first link).
+ You may also determine if it is seekable via a call to op_seekable().
+ You cannot read audio from the stream, seek, get the size or duration,
+ get information from links other than the first one, or even get the total
+ number of links until you finish opening the stream with op_test_open().
+ If you do not need to do any of these things, you can dispose of it with
+ op_free() instead.
+
+ This function is provided mostly to simplify porting existing code that used
+ <tt>libvorbisfile</tt>.
+ For new code, you are likely better off using op_test() instead, which
+ is less resource-intensive, requires less data to succeed, and imposes a
+ hard limit on the amount of data it examines (important for unseekable
+ sources, where all such data must be buffered until you are sure of the
+ stream type).
+ \param _source The stream to read from (e.g., a <code>FILE *</code>).
+ \param _cb The callbacks with which to access the stream.
+ <code><a href="#op_read_func">read()</a></code> must
+ be implemented.
+ <code><a href="#op_seek_func">seek()</a></code> and
+ <code><a href="#op_tell_func">tell()</a></code> may
+ be <code>NULL</code>, or may always return -1 to
+ indicate a source is unseekable, but if
+ <code><a href="#op_seek_func">seek()</a></code> is
+ implemented and succeeds on a particular source, then
+ <code><a href="#op_tell_func">tell()</a></code> must
+ also.
+ <code><a href="#op_close_func">close()</a></code> may
+ be <code>NULL</code>, but if it is not, it will be
+ called when the \c OggOpusFile is destroyed by
+ op_free().
+ It will not be called if op_open_callbacks() fails
+ with an error.
+ \param _initial_data An initial buffer of data from the start of the
+ stream.
+ Applications can read some number of bytes from the
+ start of the stream to help identify this as an Opus
+ stream, and then provide them here to allow the
+ stream to be tested more thoroughly, even if it is
+ unseekable.
+ \param _initial_bytes The number of bytes in \a _initial_data.
+ If the stream is seekable, its current position (as
+ reported by
+ <code><a href="#opus_tell_func">tell()</a></code>
+ at the start of this function) must be equal to
+ \a _initial_bytes.
+ Otherwise, seeking to absolute positions will
+ generate inconsistent results.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want
+ the failure code.
+ See op_open_callbacks() for a full list of failure
+ codes.
+ \return A partially opened \c OggOpusFile, or <code>NULL</code> on error.
+ <tt>libopusfile</tt> does <em>not</em> take ownership of the source
+ if the call fails.
+ The calling application is responsible for closing the source if
+ this call returns an error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_test_callbacks(void *_source,
+ const OpusFileCallbacks *_cb,const unsigned char *_initial_data,
+ size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2);
+
+/**Finish opening a stream partially opened with op_test_callbacks() or one of
+ the associated convenience functions.
+ If this function fails, you are still responsible for freeing the
+ \c OggOpusFile with op_free().
+ \param _of The \c OggOpusFile to finish opening.
+ \return 0 on success, or a negative value on error.
+ \retval #OP_EREAD An underlying read, seek, or tell operation failed
+ when it should have succeeded.
+ \retval #OP_EFAULT There was a memory allocation failure, or an
+ internal library error.
+ \retval #OP_EIMPL The stream used a feature that is not implemented,
+ such as an unsupported channel family.
+ \retval #OP_EINVAL The stream was not partially opened with
+ op_test_callbacks() or one of the associated
+ convenience functions.
+ \retval #OP_ENOTFORMAT The stream contained a link that did not have any
+ logical Opus streams in it.
+ \retval #OP_EBADHEADER A required header packet was not properly
+ formatted, contained illegal values, or was
+ missing altogether.
+ \retval #OP_EVERSION An ID header contained an unrecognized version
+ number.
+ \retval #OP_EBADLINK We failed to find data we had seen before after
+ seeking.
+ \retval #OP_EBADTIMESTAMP The first or last timestamp in a link failed basic
+ validity checks.*/
+int op_test_open(OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Release all memory used by an \c OggOpusFile.
+ \param _of The \c OggOpusFile to free.*/
+void op_free(OggOpusFile *_of);
+
+/*@}*/
+/*@}*/
+
+/**\defgroup stream_info Stream Information*/
+/*@{*/
+/**\name Functions for obtaining information about streams
+
+ These functions allow you to get basic information about a stream, including
+ seekability, the number of links (for chained streams), plus the size,
+ duration, bitrate, header parameters, and meta information for each link
+ (or, where available, the stream as a whole).
+ Some of these (size, duration) are only available for seekable streams.
+ You can also query the current stream position, link, and playback time,
+ and instantaneous bitrate during playback.
+
+ Some of these functions may be used successfully on the partially open
+ streams returned by op_test_callbacks() or one of the associated
+ convenience functions.
+ Their documention will indicate so explicitly.*/
+/*@{*/
+
+/**Returns whether or not the data source being read is seekable.
+ This is true if
+ <ol>
+ <li>The <code><a href="#op_seek_func">seek()</a></code> and
+ <code><a href="#op_tell_func">tell()</a></code> callbacks are both
+ non-<code>NULL</code>,</li>
+ <li>The <code><a href="#op_seek_func">seek()</a></code> callback was
+ successfully executed at least once, and</li>
+ <li>The <code><a href="#op_tell_func">tell()</a></code> callback was
+ successfully able to report the position indicator afterwards.</li>
+ </ol>
+ This function may be called on partially-opened streams.
+ \param _of The \c OggOpusFile whose seekable status is to be returned.
+ \return A non-zero value if seekable, and 0 if unseekable.*/
+int op_seekable(const OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Returns the number of links in this chained stream.
+ This function may be called on partially-opened streams, but it will always
+ return 1.
+ The actual number of links is not known until the stream is fully opened.
+ \param _of The \c OggOpusFile from which to retrieve the link count.
+ \return For fully-open seekable sources, this returns the total number of
+ links in the whole stream, which will be at least 1.
+ For partially-open or unseekable sources, this always returns 1.*/
+int op_link_count(const OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Get the serial number of the given link in a (possibly-chained) Ogg Opus
+ stream.
+ This function may be called on partially-opened streams, but it will always
+ return the serial number of the Opus stream in the first link.
+ \param _of The \c OggOpusFile from which to retrieve the serial number.
+ \param _li The index of the link whose serial number should be retrieved.
+ Use a negative number to get the serial number of the current
+ link.
+ \return The serial number of the given link.
+ If \a _li is greater than the total number of links, this returns
+ the serial number of the last link.
+ If the source is not seekable, this always returns the serial number
+ of the current link.*/
+opus_uint32 op_serialno(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Get the channel count of the given link in a (possibly-chained) Ogg Opus
+ stream.
+ This is equivalent to <code>op_head(_of,_li)->channel_count</code>, but
+ is provided for convenience.
+ This function may be called on partially-opened streams, but it will always
+ return the channel count of the Opus stream in the first link.
+ \param _of The \c OggOpusFile from which to retrieve the channel count.
+ \param _li The index of the link whose channel count should be retrieved.
+ Use a negative number to get the channel count of the current
+ link.
+ \return The channel count of the given link.
+ If \a _li is greater than the total number of links, this returns
+ the channel count of the last link.
+ If the source is not seekable, this always returns the channel count
+ of the current link.*/
+int op_channel_count(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Get the total (compressed) size of the stream, or of an individual link in
+ a (possibly-chained) Ogg Opus stream, including all headers and Ogg muxing
+ overhead.
+ \warning If the Opus stream (or link) is concurrently multiplexed with other
+ logical streams (e.g., video), this returns the size of the entire stream
+ (or link), not just the number of bytes in the first logical Opus stream.
+ Returning the latter would require scanning the entire file.
+ \param _of The \c OggOpusFile from which to retrieve the compressed size.
+ \param _li The index of the link whose compressed size should be computed.
+ Use a negative number to get the compressed size of the entire
+ stream.
+ \return The compressed size of the entire stream if \a _li is negative, the
+ compressed size of link \a _li if it is non-negative, or a negative
+ value on error.
+ The compressed size of the entire stream may be smaller than that
+ of the underlying source if trailing garbage was detected in the
+ file.
+ \retval #OP_EINVAL The source is not seekable (so we can't know the length),
+ \a _li wasn't less than the total number of links in
+ the stream, or the stream was only partially open.*/
+opus_int64 op_raw_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Get the total PCM length (number of samples at 48 kHz) of the stream, or of
+ an individual link in a (possibly-chained) Ogg Opus stream.
+ Users looking for <code>op_time_total()</code> should use op_pcm_total()
+ instead.
+ Because timestamps in Opus are fixed at 48 kHz, there is no need for a
+ separate function to convert this to seconds (and leaving it out avoids
+ introducing floating point to the API, for those that wish to avoid it).
+ \param _of The \c OggOpusFile from which to retrieve the PCM offset.
+ \param _li The index of the link whose PCM length should be computed.
+ Use a negative number to get the PCM length of the entire stream.
+ \return The PCM length of the entire stream if \a _li is negative, the PCM
+ length of link \a _li if it is non-negative, or a negative value on
+ error.
+ \retval #OP_EINVAL The source is not seekable (so we can't know the length),
+ \a _li wasn't less than the total number of links in
+ the stream, or the stream was only partially open.*/
+ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Get the ID header information for the given link in a (possibly chained) Ogg
+ Opus stream.
+ This function may be called on partially-opened streams, but it will always
+ return the ID header information of the Opus stream in the first link.
+ \param _of The \c OggOpusFile from which to retrieve the ID header
+ information.
+ \param _li The index of the link whose ID header information should be
+ retrieved.
+ Use a negative number to get the ID header information of the
+ current link.
+ For an unseekable stream, \a _li is ignored, and the ID header
+ information for the current link is always returned, if
+ available.
+ \return The contents of the ID header for the given link.*/
+const OpusHead *op_head(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Get the comment header information for the given link in a (possibly
+ chained) Ogg Opus stream.
+ This function may be called on partially-opened streams, but it will always
+ return the tags from the Opus stream in the first link.
+ \param _of The \c OggOpusFile from which to retrieve the comment header
+ information.
+ \param _li The index of the link whose comment header information should be
+ retrieved.
+ Use a negative number to get the comment header information of
+ the current link.
+ For an unseekable stream, \a _li is ignored, and the comment
+ header information for the current link is always returned, if
+ available.
+ \return The contents of the comment header for the given link, or
+ <code>NULL</code> if this is an unseekable stream that encountered
+ an invalid link.*/
+const OpusTags *op_tags(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Retrieve the index of the current link.
+ This is the link that produced the data most recently read by
+ op_read_float() or its associated functions, or, after a seek, the link
+ that the seek target landed in.
+ Reading more data may advance the link index (even on the first read after a
+ seek).
+ \param _of The \c OggOpusFile from which to retrieve the current link index.
+ \return The index of the current link on success, or a negative value on
+ failure.
+ For seekable streams, this is a number between 0 and the value
+ returned by op_link_count().
+ For unseekable streams, this value starts at 0 and increments by one
+ each time a new link is encountered (even though op_link_count()
+ always returns 1).
+ \retval #OP_EINVAL The stream was only partially open.*/
+int op_current_link(const OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Computes the bitrate of the stream, or of an individual link in a
+ (possibly-chained) Ogg Opus stream.
+ The stream must be seekable to compute the bitrate.
+ For unseekable streams, use op_bitrate_instant() to get periodic estimates.
+ \warning If the Opus stream (or link) is concurrently multiplexed with other
+ logical streams (e.g., video), this uses the size of the entire stream (or
+ link) to compute the bitrate, not just the number of bytes in the first
+ logical Opus stream.
+ Returning the latter requires scanning the entire file, but this may be done
+ by decoding the whole file and calling op_bitrate_instant() once at the
+ end.
+ Install a trivial decoding callback with op_set_decode_callback() if you
+ wish to skip actual decoding during this process.
+ \param _of The \c OggOpusFile from which to retrieve the bitrate.
+ \param _li The index of the link whose bitrate should be computed.
+ Use a negative number to get the bitrate of the whole stream.
+ \return The bitrate on success, or a negative value on error.
+ \retval #OP_EINVAL The stream was only partially open, the stream was not
+ seekable, or \a _li was larger than the number of
+ links.*/
+opus_int32 op_bitrate(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Compute the instantaneous bitrate, measured as the ratio of bits to playable
+ samples decoded since a) the last call to op_bitrate_instant(), b) the last
+ seek, or c) the start of playback, whichever was most recent.
+ This will spike somewhat after a seek or at the start/end of a chain
+ boundary, as pre-skip, pre-roll, and end-trimming causes samples to be
+ decoded but not played.
+ \param _of The \c OggOpusFile from which to retrieve the bitrate.
+ \return The bitrate, in bits per second, or a negative value on error.
+ \retval #OP_FALSE No data has been decoded since any of the events
+ described above.
+ \retval #OP_EINVAL The stream was only partially open.*/
+opus_int32 op_bitrate_instant(OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Obtain the current value of the position indicator for \a _of.
+ \param _of The \c OggOpusFile from which to retrieve the position indicator.
+ \return The byte position that is currently being read from.
+ \retval #OP_EINVAL The stream was only partially open.*/
+opus_int64 op_raw_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Obtain the PCM offset of the next sample to be read.
+ If the stream is not properly timestamped, this might not increment by the
+ proper amount between reads, or even return monotonically increasing
+ values.
+ \param _of The \c OggOpusFile from which to retrieve the PCM offset.
+ \return The PCM offset of the next sample to be read.
+ \retval #OP_EINVAL The stream was only partially open.*/
+ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/*@}*/
+/*@}*/
+
+/**\defgroup stream_seeking Seeking*/
+/*@{*/
+/**\name Functions for seeking in Opus streams
+
+ These functions let you seek in Opus streams, if the underlying source
+ support it.
+ Seeking is implemented for all built-in stream I/O routines, though some
+ individual sources may not be seekable (pipes, live HTTP streams, or HTTP
+ streams from a server that does not support <code>Range</code> requests).
+
+ op_raw_seek() is the fastest: it is guaranteed to perform at most one
+ physical seek, but, since the target is a byte position, makes no guarantee
+ how close to a given time it will come.
+ op_pcm_seek() provides sample-accurate seeking.
+ The number of physical seeks it requires is still quite small (often 1 or
+ 2, even in highly variable bitrate streams).
+
+ Seeking in Opus requires decoding some pre-roll amount before playback to
+ allow the internal state to converge (as if recovering from packet loss).
+ This is handled internally by <tt>libopusfile</tt>, but means there is
+ little extra overhead for decoding up to the exact position requested
+ (since it must decode some amount of audio anyway).
+ It also means that decoding after seeking may not return exactly the same
+ values as would be obtained by decoding the stream straight through.
+ However, such differences are expected to be smaller than the loss
+ introduced by Opus's lossy compression.*/
+/*@{*/
+
+/**Seek to a byte offset relative to the <b>compressed</b> data.
+ This also scans packets to update the PCM cursor.
+ It will cross a logical bitstream boundary, but only if it can't get any
+ packets out of the tail of the link to which it seeks.
+ \param _of The \c OggOpusFile in which to seek.
+ \param _byte_offset The byte position to seek to.
+ \return 0 on success, or a negative error code on failure.
+ \retval #OP_EREAD The underlying seek operation failed.
+ \retval #OP_EINVAL The stream was only partially open, or the target was
+ outside the valid range for the stream.
+ \retval #OP_ENOSEEK This stream is not seekable.
+ \retval #OP_EBADLINK Failed to initialize a decoder for a stream for an
+ unknown reason.*/
+int op_raw_seek(OggOpusFile *_of,opus_int64 _byte_offset) OP_ARG_NONNULL(1);
+
+/**Seek to the specified PCM offset, such that decoding will begin at exactly
+ the requested position.
+ \param _of The \c OggOpusFile in which to seek.
+ \param _pcm_offset The PCM offset to seek to.
+ This is in samples at 48 kHz relative to the start of the
+ stream.
+ \return 0 on success, or a negative value on error.
+ \retval #OP_EREAD An underlying read or seek operation failed.
+ \retval #OP_EINVAL The stream was only partially open, or the target was
+ outside the valid range for the stream.
+ \retval #OP_ENOSEEK This stream is not seekable.
+ \retval #OP_EBADLINK We failed to find data we had seen before, or the
+ bitstream structure was sufficiently malformed that
+ seeking to the target destination was impossible.*/
+int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset) OP_ARG_NONNULL(1);
+
+/*@}*/
+/*@}*/
+
+/**\defgroup stream_decoding Decoding*/
+/*@{*/
+/**\name Functions for decoding audio data
+
+ These functions retrieve actual decoded audio data from the stream.
+ The general functions, op_read() and op_read_float() return 16-bit or
+ floating-point output, both using native endian ordering.
+ The number of channels returned can change from link to link in a chained
+ stream.
+ There are special functions, op_read_stereo() and op_read_float_stereo(),
+ which always output two channels, to simplify applications which do not
+ wish to handle multichannel audio.
+ These downmix multichannel files to two channels, so they can always return
+ samples in the same format for every link in a chained file.
+
+ If the rest of your audio processing chain can handle floating point, the
+ floating-point routines should be preferred, as they prevent clipping and
+ other issues which might be avoided entirely if, e.g., you scale down the
+ volume at some other stage.
+ However, if you intend to consume 16-bit samples directly, the conversion in
+ <tt>libopusfile</tt> provides noise-shaping dithering and, if compiled
+ against <tt>libopus</tt>&nbsp;1.1 or later, soft-clipping prevention.
+
+ <tt>libopusfile</tt> can also be configured at compile time to use the
+ fixed-point <tt>libopus</tt> API.
+ If so, <tt>libopusfile</tt>'s floating-point API may also be disabled.
+ In that configuration, nothing in <tt>libopusfile</tt> will use any
+ floating-point operations, to simplify support on devices without an
+ adequate FPU.
+
+ \warning HTTPS streams may be be vulnerable to truncation attacks if you do
+ not check the error return code from op_read_float() or its associated
+ functions.
+ If the remote peer does not close the connection gracefully (with a TLS
+ "close notify" message), these functions will return #OP_EREAD instead of 0
+ when they reach the end of the file.
+ If you are reading from an <https:> URL (particularly if seeking is not
+ supported), you should make sure to check for this error and warn the user
+ appropriately.*/
+/*@{*/
+
+/**Indicates that the decoding callback should produce signed 16-bit
+ native-endian output samples.*/
+#define OP_DEC_FORMAT_SHORT (7008)
+/**Indicates that the decoding callback should produce 32-bit native-endian
+ float samples.*/
+#define OP_DEC_FORMAT_FLOAT (7040)
+
+/**Indicates that the decoding callback did not decode anything, and that
+ <tt>libopusfile</tt> should decode normally instead.*/
+#define OP_DEC_USE_DEFAULT (6720)
+
+/**Called to decode an Opus packet.
+ This should invoke the functional equivalent of opus_multistream_decode() or
+ opus_multistream_decode_float(), except that it returns 0 on success
+ instead of the number of decoded samples (which is known a priori).
+ \param _ctx The application-provided callback context.
+ \param _decoder The decoder to use to decode the packet.
+ \param[out] _pcm The buffer to decode into.
+ This will always have enough room for \a _nchannels of
+ \a _nsamples samples, which should be placed into this
+ buffer interleaved.
+ \param _op The packet to decode.
+ This will always have its granule position set to a valid
+ value.
+ \param _nsamples The number of samples expected from the packet.
+ \param _nchannels The number of channels expected from the packet.
+ \param _format The desired sample output format.
+ This is either #OP_DEC_FORMAT_SHORT or
+ #OP_DEC_FORMAT_FLOAT.
+ \param _li The index of the link from which this packet was decoded.
+ \return A non-negative value on success, or a negative value on error.
+ Any error codes should be the same as those returned by
+ opus_multistream_decode() or opus_multistream_decode_float().
+ Success codes are as follows:
+ \retval 0 Decoding was successful.
+ The application has filled the buffer with
+ exactly <code>\a _nsamples*\a
+ _nchannels</code> samples in the requested
+ format.
+ \retval #OP_DEC_USE_DEFAULT No decoding was done.
+ <tt>libopusfile</tt> should do the decoding
+ by itself instead.*/
+typedef int (*op_decode_cb_func)(void *_ctx,OpusMSDecoder *_decoder,void *_pcm,
+ const ogg_packet *_op,int _nsamples,int _nchannels,int _format,int _li);
+
+/**Sets the packet decode callback function.
+ If set, this is called once for each packet that needs to be decoded.
+ This can be used by advanced applications to do additional processing on the
+ compressed or uncompressed data.
+ For example, an application might save the final entropy coder state for
+ debugging and testing purposes, or it might apply additional filters
+ before the downmixing, dithering, or soft-clipping performed by
+ <tt>libopusfile</tt>, so long as these filters do not introduce any
+ latency.
+
+ A call to this function is no guarantee that the audio will eventually be
+ delivered to the application.
+ <tt>libopusfile</tt> may discard some or all of the decoded audio data
+ (i.e., at the beginning or end of a link, or after a seek), however the
+ callback is still required to provide all of it.
+ \param _of The \c OggOpusFile on which to set the decode callback.
+ \param _decode_cb The callback function to call.
+ This may be <code>NULL</code> to disable calling the
+ callback.
+ \param _ctx The application-provided context pointer to pass to the
+ callback on each call.*/
+void op_set_decode_callback(OggOpusFile *_of,
+ op_decode_cb_func _decode_cb,void *_ctx) OP_ARG_NONNULL(1);
+
+/**Gain offset type that indicates that the provided offset is relative to the
+ header gain.
+ This is the default.*/
+#define OP_HEADER_GAIN (0)
+
+/**Gain offset type that indicates that the provided offset is relative to the
+ R128_ALBUM_GAIN value (if any), in addition to the header gain.*/
+#define OP_ALBUM_GAIN (3007)
+
+/**Gain offset type that indicates that the provided offset is relative to the
+ R128_TRACK_GAIN value (if any), in addition to the header gain.*/
+#define OP_TRACK_GAIN (3008)
+
+/**Gain offset type that indicates that the provided offset should be used as
+ the gain directly, without applying any the header or track gains.*/
+#define OP_ABSOLUTE_GAIN (3009)
+
+/**Sets the gain to be used for decoded output.
+ By default, the gain in the header is applied with no additional offset.
+ The total gain (including header gain and/or track gain, if applicable, and
+ this offset), will be clamped to [-32768,32767]/256 dB.
+ This is more than enough to saturate or underflow 16-bit PCM.
+ \note The new gain will not be applied to any already buffered, decoded
+ output.
+ This means you cannot change it sample-by-sample, as at best it will be
+ updated packet-by-packet.
+ It is meant for setting a target volume level, rather than applying smooth
+ fades, etc.
+ \param _of The \c OggOpusFile on which to set the gain offset.
+ \param _gain_type One of #OP_HEADER_GAIN, #OP_ALBUM_GAIN,
+ #OP_TRACK_GAIN, or #OP_ABSOLUTE_GAIN.
+ \param _gain_offset_q8 The gain offset to apply, in 1/256ths of a dB.
+ \return 0 on success or a negative value on error.
+ \retval #OP_EINVAL The \a _gain_type was unrecognized.*/
+int op_set_gain_offset(OggOpusFile *_of,
+ int _gain_type,opus_int32 _gain_offset_q8) OP_ARG_NONNULL(1);
+
+/**Sets whether or not dithering is enabled for 16-bit decoding.
+ By default, when <tt>libopusfile</tt> is compiled to use floating-point
+ internally, calling op_read() or op_read_stereo() will first decode to
+ float, and then convert to fixed-point using noise-shaping dithering.
+ This flag can be used to disable that dithering.
+ When the application uses op_read_float() or op_read_float_stereo(), or when
+ the library has been compiled to decode directly to fixed point, this flag
+ has no effect.
+ \param _of The \c OggOpusFile on which to enable or disable dithering.
+ \param _enabled A non-zero value to enable dithering, or 0 to disable it.*/
+void op_set_dither_enabled(OggOpusFile *_of,int _enabled) OP_ARG_NONNULL(1);
+
+/**Reads more samples from the stream.
+ \note Although \a _buf_size must indicate the total number of values that
+ can be stored in \a _pcm, the return value is the number of samples
+ <em>per channel</em>.
+ This is done because
+ <ol>
+ <li>The channel count cannot be known a priori (reading more samples might
+ advance us into the next link, with a different channel count), so
+ \a _buf_size cannot also be in units of samples per channel,</li>
+ <li>Returning the samples per channel matches the <code>libopus</code> API
+ as closely as we're able,</li>
+ <li>Returning the total number of values instead of samples per channel
+ would mean the caller would need a division to compute the samples per
+ channel, and might worry about the possibility of getting back samples
+ for some channels and not others, and</li>
+ <li>This approach is relatively fool-proof: if an application passes too
+ small a value to \a _buf_size, they will simply get fewer samples back,
+ and if they assume the return value is the total number of values, then
+ they will simply read too few (rather than reading too many and going
+ off the end of the buffer).</li>
+ </ol>
+ \param _of The \c OggOpusFile from which to read.
+ \param[out] _pcm A buffer in which to store the output PCM samples, as
+ signed native-endian 16-bit values at 48&nbsp;kHz
+ with a nominal range of <code>[-32768,32767)</code>.
+ Multiple channels are interleaved using the
+ <a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
+ channel ordering</a>.
+ This must have room for at least \a _buf_size values.
+ \param _buf_size The number of values that can be stored in \a _pcm.
+ It is recommended that this be large enough for at
+ least 120 ms of data at 48 kHz per channel (5760
+ values per channel).
+ Smaller buffers will simply return less data, possibly
+ consuming more memory to buffer the data internally.
+ <tt>libopusfile</tt> may return less data than
+ requested.
+ If so, there is no guarantee that the remaining data
+ in \a _pcm will be unmodified.
+ \param[out] _li The index of the link this data was decoded from.
+ You may pass <code>NULL</code> if you do not need this
+ information.
+ If this function fails (returning a negative value),
+ this parameter is left unset.
+ \return The number of samples read per channel on success, or a negative
+ value on failure.
+ The channel count can be retrieved on success by calling
+ <code>op_head(_of,*_li)</code>.
+ The number of samples returned may be 0 if the buffer was too small
+ to store even a single sample for all channels, or if end-of-file
+ was reached.
+ The list of possible failure codes follows.
+ Most of them can only be returned by unseekable, chained streams
+ that encounter a new link.
+ \retval #OP_HOLE There was a hole in the data, and some samples
+ may have been skipped.
+ Call this function again to continue decoding
+ past the hole.
+ \retval #OP_EREAD An underlying read operation failed.
+ This may signal a truncation attack from an
+ <https:> source.
+ \retval #OP_EFAULT An internal memory allocation failed.
+ \retval #OP_EIMPL An unseekable stream encountered a new link that
+ used a feature that is not implemented, such as
+ an unsupported channel family.
+ \retval #OP_EINVAL The stream was only partially open.
+ \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that
+ did not have any logical Opus streams in it.
+ \retval #OP_EBADHEADER An unseekable stream encountered a new link with a
+ required header packet that was not properly
+ formatted, contained illegal values, or was
+ missing altogether.
+ \retval #OP_EVERSION An unseekable stream encountered a new link with
+ an ID header that contained an unrecognized
+ version number.
+ \retval #OP_EBADPACKET Failed to properly decode the next packet.
+ \retval #OP_EBADLINK We failed to find data we had seen before.
+ \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with
+ a starting timestamp that failed basic validity
+ checks.*/
+OP_WARN_UNUSED_RESULT int op_read(OggOpusFile *_of,
+ opus_int16 *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1);
+
+/**Reads more samples from the stream.
+ \note Although \a _buf_size must indicate the total number of values that
+ can be stored in \a _pcm, the return value is the number of samples
+ <em>per channel</em>.
+ <ol>
+ <li>The channel count cannot be known a priori (reading more samples might
+ advance us into the next link, with a different channel count), so
+ \a _buf_size cannot also be in units of samples per channel,</li>
+ <li>Returning the samples per channel matches the <code>libopus</code> API
+ as closely as we're able,</li>
+ <li>Returning the total number of values instead of samples per channel
+ would mean the caller would need a division to compute the samples per
+ channel, and might worry about the possibility of getting back samples
+ for some channels and not others, and</li>
+ <li>This approach is relatively fool-proof: if an application passes too
+ small a value to \a _buf_size, they will simply get fewer samples back,
+ and if they assume the return value is the total number of values, then
+ they will simply read too few (rather than reading too many and going
+ off the end of the buffer).</li>
+ </ol>
+ \param _of The \c OggOpusFile from which to read.
+ \param[out] _pcm A buffer in which to store the output PCM samples as
+ signed floats at 48&nbsp;kHz with a nominal range of
+ <code>[-1.0,1.0]</code>.
+ Multiple channels are interleaved using the
+ <a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
+ channel ordering</a>.
+ This must have room for at least \a _buf_size floats.
+ \param _buf_size The number of floats that can be stored in \a _pcm.
+ It is recommended that this be large enough for at
+ least 120 ms of data at 48 kHz per channel (5760
+ samples per channel).
+ Smaller buffers will simply return less data, possibly
+ consuming more memory to buffer the data internally.
+ If less than \a _buf_size values are returned,
+ <tt>libopusfile</tt> makes no guarantee that the
+ remaining data in \a _pcm will be unmodified.
+ \param[out] _li The index of the link this data was decoded from.
+ You may pass <code>NULL</code> if you do not need this
+ information.
+ If this function fails (returning a negative value),
+ this parameter is left unset.
+ \return The number of samples read per channel on success, or a negative
+ value on failure.
+ The channel count can be retrieved on success by calling
+ <code>op_head(_of,*_li)</code>.
+ The number of samples returned may be 0 if the buffer was too small
+ to store even a single sample for all channels, or if end-of-file
+ was reached.
+ The list of possible failure codes follows.
+ Most of them can only be returned by unseekable, chained streams
+ that encounter a new link.
+ \retval #OP_HOLE There was a hole in the data, and some samples
+ may have been skipped.
+ Call this function again to continue decoding
+ past the hole.
+ \retval #OP_EREAD An underlying read operation failed.
+ This may signal a truncation attack from an
+ <https:> source.
+ \retval #OP_EFAULT An internal memory allocation failed.
+ \retval #OP_EIMPL An unseekable stream encountered a new link that
+ used a feature that is not implemented, such as
+ an unsupported channel family.
+ \retval #OP_EINVAL The stream was only partially open.
+ \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that
+ did not have any logical Opus streams in it.
+ \retval #OP_EBADHEADER An unseekable stream encountered a new link with a
+ required header packet that was not properly
+ formatted, contained illegal values, or was
+ missing altogether.
+ \retval #OP_EVERSION An unseekable stream encountered a new link with
+ an ID header that contained an unrecognized
+ version number.
+ \retval #OP_EBADPACKET Failed to properly decode the next packet.
+ \retval #OP_EBADLINK We failed to find data we had seen before.
+ \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with
+ a starting timestamp that failed basic validity
+ checks.*/
+OP_WARN_UNUSED_RESULT int op_read_float(OggOpusFile *_of,
+ float *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1);
+
+/**Reads more samples from the stream and downmixes to stereo, if necessary.
+ This function is intended for simple players that want a uniform output
+ format, even if the channel count changes between links in a chained
+ stream.
+ \note \a _buf_size indicates the total number of values that can be stored
+ in \a _pcm, while the return value is the number of samples <em>per
+ channel</em>, even though the channel count is known, for consistency with
+ op_read().
+ \param _of The \c OggOpusFile from which to read.
+ \param[out] _pcm A buffer in which to store the output PCM samples, as
+ signed native-endian 16-bit values at 48&nbsp;kHz
+ with a nominal range of <code>[-32768,32767)</code>.
+ The left and right channels are interleaved in the
+ buffer.
+ This must have room for at least \a _buf_size values.
+ \param _buf_size The number of values that can be stored in \a _pcm.
+ It is recommended that this be large enough for at
+ least 120 ms of data at 48 kHz per channel (11520
+ values total).
+ Smaller buffers will simply return less data, possibly
+ consuming more memory to buffer the data internally.
+ If less than \a _buf_size values are returned,
+ <tt>libopusfile</tt> makes no guarantee that the
+ remaining data in \a _pcm will be unmodified.
+ \return The number of samples read per channel on success, or a negative
+ value on failure.
+ The number of samples returned may be 0 if the buffer was too small
+ to store even a single sample for both channels, or if end-of-file
+ was reached.
+ The list of possible failure codes follows.
+ Most of them can only be returned by unseekable, chained streams
+ that encounter a new link.
+ \retval #OP_HOLE There was a hole in the data, and some samples
+ may have been skipped.
+ Call this function again to continue decoding
+ past the hole.
+ \retval #OP_EREAD An underlying read operation failed.
+ This may signal a truncation attack from an
+ <https:> source.
+ \retval #OP_EFAULT An internal memory allocation failed.
+ \retval #OP_EIMPL An unseekable stream encountered a new link that
+ used a feature that is not implemented, such as
+ an unsupported channel family.
+ \retval #OP_EINVAL The stream was only partially open.
+ \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that
+ did not have any logical Opus streams in it.
+ \retval #OP_EBADHEADER An unseekable stream encountered a new link with a
+ required header packet that was not properly
+ formatted, contained illegal values, or was
+ missing altogether.
+ \retval #OP_EVERSION An unseekable stream encountered a new link with
+ an ID header that contained an unrecognized
+ version number.
+ \retval #OP_EBADPACKET Failed to properly decode the next packet.
+ \retval #OP_EBADLINK We failed to find data we had seen before.
+ \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with
+ a starting timestamp that failed basic validity
+ checks.*/
+OP_WARN_UNUSED_RESULT int op_read_stereo(OggOpusFile *_of,
+ opus_int16 *_pcm,int _buf_size) OP_ARG_NONNULL(1);
+
+/**Reads more samples from the stream and downmixes to stereo, if necessary.
+ This function is intended for simple players that want a uniform output
+ format, even if the channel count changes between links in a chained
+ stream.
+ \note \a _buf_size indicates the total number of values that can be stored
+ in \a _pcm, while the return value is the number of samples <em>per
+ channel</em>, even though the channel count is known, for consistency with
+ op_read_float().
+ \param _of The \c OggOpusFile from which to read.
+ \param[out] _pcm A buffer in which to store the output PCM samples, as
+ signed floats at 48&nbsp;kHz with a nominal range of
+ <code>[-1.0,1.0]</code>.
+ The left and right channels are interleaved in the
+ buffer.
+ This must have room for at least \a _buf_size values.
+ \param _buf_size The number of values that can be stored in \a _pcm.
+ It is recommended that this be large enough for at
+ least 120 ms of data at 48 kHz per channel (11520
+ values total).
+ Smaller buffers will simply return less data, possibly
+ consuming more memory to buffer the data internally.
+ If less than \a _buf_size values are returned,
+ <tt>libopusfile</tt> makes no guarantee that the
+ remaining data in \a _pcm will be unmodified.
+ \return The number of samples read per channel on success, or a negative
+ value on failure.
+ The number of samples returned may be 0 if the buffer was too small
+ to store even a single sample for both channels, or if end-of-file
+ was reached.
+ The list of possible failure codes follows.
+ Most of them can only be returned by unseekable, chained streams
+ that encounter a new link.
+ \retval #OP_HOLE There was a hole in the data, and some samples
+ may have been skipped.
+ Call this function again to continue decoding
+ past the hole.
+ \retval #OP_EREAD An underlying read operation failed.
+ This may signal a truncation attack from an
+ <https:> source.
+ \retval #OP_EFAULT An internal memory allocation failed.
+ \retval #OP_EIMPL An unseekable stream encountered a new link that
+ used a feature that is not implemented, such as
+ an unsupported channel family.
+ \retval #OP_EINVAL The stream was only partially open.
+ \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that
+ that did not have any logical Opus streams in it.
+ \retval #OP_EBADHEADER An unseekable stream encountered a new link with a
+ required header packet that was not properly
+ formatted, contained illegal values, or was
+ missing altogether.
+ \retval #OP_EVERSION An unseekable stream encountered a new link with
+ an ID header that contained an unrecognized
+ version number.
+ \retval #OP_EBADPACKET Failed to properly decode the next packet.
+ \retval #OP_EBADLINK We failed to find data we had seen before.
+ \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with
+ a starting timestamp that failed basic validity
+ checks.*/
+OP_WARN_UNUSED_RESULT int op_read_float_stereo(OggOpusFile *_of,
+ float *_pcm,int _buf_size) OP_ARG_NONNULL(1);
+
+/*@}*/
+/*@}*/
+
+# if OP_GNUC_PREREQ(4,0)
+# pragma GCC visibility pop
+# endif
+
+# if defined(__cplusplus)
+}
+# endif
+
+#endif
diff --git a/external/opusfile-0.8/src/http.c b/external/opusfile-0.8/src/http.c
new file mode 100644
index 0000000..22d75d4
--- /dev/null
+++ b/external/opusfile-0.8/src/http.c
@@ -0,0 +1,3465 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "internal.h"
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+
+/*RFCs referenced in this file:
+ RFC 761: DOD Standard Transmission Control Protocol
+ RFC 1535: A Security Problem and Proposed Correction With Widely Deployed DNS
+ Software
+ RFC 1738: Uniform Resource Locators (URL)
+ RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0
+ RFC 2068: Hypertext Transfer Protocol -- HTTP/1.1
+ RFC 2145: Use and Interpretation of HTTP Version Numbers
+ RFC 2246: The TLS Protocol Version 1.0
+ RFC 2459: Internet X.509 Public Key Infrastructure Certificate and
+ Certificate Revocation List (CRL) Profile
+ RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
+ RFC 2617: HTTP Authentication: Basic and Digest Access Authentication
+ RFC 2817: Upgrading to TLS Within HTTP/1.1
+ RFC 2818: HTTP Over TLS
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for Internationalized
+ Domain Names in Applications (IDNA)
+ RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3987: Internationalized Resource Identifiers (IRIs)
+ RFC 4343: Domain Name System (DNS) Case Insensitivity Clarification
+ RFC 5894: Internationalized Domain Names for Applications (IDNA):
+ Background, Explanation, and Rationale
+ RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions
+ RFC 6125: Representation and Verification of Domain-Based Application Service
+ Identity within Internet Public Key Infrastructure Using X.509 (PKIX)
+ Certificates in the Context of Transport Layer Security (TLS)
+ RFC 6555: Happy Eyeballs: Success with Dual-Stack Hosts*/
+
+typedef struct OpusParsedURL OpusParsedURL;
+typedef struct OpusStringBuf OpusStringBuf;
+typedef struct OpusHTTPConn OpusHTTPConn;
+typedef struct OpusHTTPStream OpusHTTPStream;
+
+static char *op_string_range_dup(const char *_start,const char *_end){
+ size_t len;
+ char *ret;
+ OP_ASSERT(_start<=_end);
+ len=_end-_start;
+ /*This is to help avoid overflow elsewhere, later.*/
+ if(OP_UNLIKELY(len>=INT_MAX))return NULL;
+ ret=(char *)_ogg_malloc(sizeof(*ret)*(len+1));
+ if(OP_LIKELY(ret!=NULL)){
+ ret=(char *)memcpy(ret,_start,sizeof(*ret)*(len));
+ ret[len]='\0';
+ }
+ return ret;
+}
+
+static char *op_string_dup(const char *_s){
+ return op_string_range_dup(_s,_s+strlen(_s));
+}
+
+static char *op_string_tolower(char *_s){
+ int i;
+ for(i=0;_s[i]!='\0';i++){
+ int c;
+ c=_s[i];
+ if(c>='A'&&c<='Z')c+='a'-'A';
+ _s[i]=(char)c;
+ }
+ return _s;
+}
+
+/*URI character classes (from RFC 3986).*/
+#define OP_URL_ALPHA \
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+#define OP_URL_DIGIT "0123456789"
+#define OP_URL_HEXDIGIT "0123456789ABCDEFabcdef"
+/*Not a character class, but the characters allowed in <scheme>.*/
+#define OP_URL_SCHEME OP_URL_ALPHA OP_URL_DIGIT "+-."
+#define OP_URL_GEN_DELIMS "#/:?@[]"
+#define OP_URL_SUB_DELIMS "!$&'()*+,;="
+#define OP_URL_RESERVED OP_URL_GEN_DELIMS OP_URL_SUB_DELIMS
+#define OP_URL_UNRESERVED OP_URL_ALPHA OP_URL_DIGIT "-._~"
+/*Not a character class, but the characters allowed in <pct-encoded>.*/
+#define OP_URL_PCT_ENCODED "%"
+/*Not a character class or production rule, but for convenience.*/
+#define OP_URL_PCHAR_BASE \
+ OP_URL_UNRESERVED OP_URL_PCT_ENCODED OP_URL_SUB_DELIMS
+#define OP_URL_PCHAR OP_URL_PCHAR_BASE ":@"
+/*Not a character class, but the characters allowed in <userinfo> and
+ <IP-literal>.*/
+#define OP_URL_PCHAR_NA OP_URL_PCHAR_BASE ":"
+/*Not a character class, but the characters allowed in <segment-nz-nc>.*/
+#define OP_URL_PCHAR_NC OP_URL_PCHAR_BASE "@"
+/*Not a character clsss, but the characters allowed in <path>.*/
+#define OP_URL_PATH OP_URL_PCHAR "/"
+/*Not a character class, but the characters allowed in <query> / <fragment>.*/
+#define OP_URL_QUERY_FRAG OP_URL_PCHAR "/?"
+
+/*Check the <% HEXDIG HEXDIG> escapes of a URL for validity.
+ Return: 0 if valid, or a negative value on failure.*/
+static int op_validate_url_escapes(const char *_s){
+ int i;
+ for(i=0;_s[i];i++){
+ if(_s[i]=='%'){
+ if(OP_UNLIKELY(!isxdigit(_s[i+1]))
+ ||OP_UNLIKELY(!isxdigit(_s[i+2]))
+ /*RFC 3986 says %00 "should be rejected if the application is not
+ expecting to receive raw data within a component."*/
+ ||OP_UNLIKELY(_s[i+1]=='0'&&_s[i+2]=='0')){
+ return OP_FALSE;
+ }
+ i+=2;
+ }
+ }
+ return 0;
+}
+
+/*Convert a hex digit to its actual value.
+ _c: The hex digit to convert.
+ Presumed to be valid ('0'...'9', 'A'...'F', or 'a'...'f').
+ Return: The value of the digit, in the range [0,15].*/
+static int op_hex_value(int _c){
+ return _c>='a'?_c-'a'+10:_c>='A'?_c-'A'+10:_c-'0';
+}
+
+/*Unescape all the <% HEXDIG HEXDIG> sequences in a string in-place.
+ This does no validity checking.*/
+static char *op_unescape_url_component(char *_s){
+ int i;
+ int j;
+ for(i=j=0;_s[i];i++,j++){
+ if(_s[i]=='%'){
+ _s[i]=(char)(op_hex_value(_s[i+1])<<4|op_hex_value(_s[i+2]));
+ i+=2;
+ }
+ }
+ return _s;
+}
+
+/*Parse a file: URL.
+ This code is not meant to be fast: strspn() with large sets is likely to be
+ slow, but it is very convenient.
+ It is meant to be RFC 1738-compliant (as updated by RFC 3986).*/
+static const char *op_parse_file_url(const char *_src){
+ const char *scheme_end;
+ const char *path;
+ const char *path_end;
+ scheme_end=_src+strspn(_src,OP_URL_SCHEME);
+ if(OP_UNLIKELY(*scheme_end!=':')
+ ||scheme_end-_src!=4||op_strncasecmp(_src,"file",4)!=0){
+ /*Unsupported protocol.*/
+ return NULL;
+ }
+ /*Make sure all escape sequences are valid to simplify unescaping later.*/
+ if(OP_UNLIKELY(op_validate_url_escapes(scheme_end+1)<0))return NULL;
+ if(scheme_end[1]=='/'&&scheme_end[2]=='/'){
+ const char *host;
+ /*file: URLs can have a host!
+ Yeah, I was surprised, too, but that's what RFC 1738 says.
+ It also says, "The file URL scheme is unusual in that it does not specify
+ an Internet protocol or access method for such files; as such, its
+ utility in network protocols between hosts is limited," which is a mild
+ understatement.*/
+ host=scheme_end+3;
+ /*The empty host is what we expect.*/
+ if(OP_LIKELY(*host=='/'))path=host;
+ else{
+ const char *host_end;
+ char host_buf[28];
+ /*RFC 1738 says localhost "is interpreted as `the machine from which the
+ URL is being interpreted,'" so let's check for it.*/
+ host_end=host+strspn(host,OP_URL_PCHAR_BASE);
+ /*No <port> allowed.
+ This also rejects IP-Literals.*/
+ if(*host_end!='/')return NULL;
+ /*An escaped "localhost" can take at most 27 characters.*/
+ if(OP_UNLIKELY(host_end-host>27))return NULL;
+ memcpy(host_buf,host,sizeof(*host_buf)*(host_end-host));
+ host_buf[host_end-host]='\0';
+ op_unescape_url_component(host_buf);
+ op_string_tolower(host_buf);
+ /*Some other host: give up.*/
+ if(OP_UNLIKELY(strcmp(host_buf,"localhost")!=0))return NULL;
+ path=host_end;
+ }
+ }
+ else path=scheme_end+1;
+ path_end=path+strspn(path,OP_URL_PATH);
+ /*This will reject a <query> or <fragment> component, too.
+ I don't know what to do with queries, but a temporal fragment would at
+ least make sense.
+ RFC 1738 pretty clearly defines a <searchpart> that's equivalent to the
+ RFC 3986 <query> component for other schemes, but not the file: scheme,
+ so I'm going to just reject it.*/
+ if(*path_end!='\0')return NULL;
+ return path;
+}
+
+#if defined(OP_ENABLE_HTTP)
+# if defined(_WIN32)
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <openssl/ssl.h>
+# include "winerrno.h"
+
+typedef SOCKET op_sock;
+
+# define OP_INVALID_SOCKET (INVALID_SOCKET)
+
+/*Vista and later support WSAPoll(), but we don't want to rely on that.
+ Instead we re-implement it badly using select().
+ Unfortunately, they define a conflicting struct pollfd, so we only define our
+ own if it looks like that one has not already been defined.*/
+# if !defined(POLLIN)
+/*Equivalent to POLLIN.*/
+# define POLLRDNORM (0x0100)
+/*Priority band data can be read.*/
+# define POLLRDBAND (0x0200)
+/*There is data to read.*/
+# define POLLIN (POLLRDNORM|POLLRDBAND)
+/*There is urgent data to read.*/
+# define POLLPRI (0x0400)
+/*Equivalent to POLLOUT.*/
+# define POLLWRNORM (0x0010)
+/*Writing now will not block.*/
+# define POLLOUT (POLLWRNORM)
+/*Priority data may be written.*/
+# define POLLWRBAND (0x0020)
+/*Error condition (output only).*/
+# define POLLERR (0x0001)
+/*Hang up (output only).*/
+# define POLLHUP (0x0002)
+/*Invalid request: fd not open (output only).*/
+# define POLLNVAL (0x0004)
+
+struct pollfd{
+ /*File descriptor.*/
+ op_sock fd;
+ /*Requested events.*/
+ short events;
+ /*Returned events.*/
+ short revents;
+};
+# endif
+
+/*But Winsock never defines nfds_t (it's simply hard-coded to ULONG).*/
+typedef unsigned long nfds_t;
+
+/*The usage of FD_SET() below is O(N^2).
+ This is okay because select() is limited to 64 sockets in Winsock, anyway.
+ In practice, we only ever call it with one or two sockets.*/
+static int op_poll_win32(struct pollfd *_fds,nfds_t _nfds,int _timeout){
+ struct timeval tv;
+ fd_set ifds;
+ fd_set ofds;
+ fd_set efds;
+ nfds_t i;
+ int ret;
+ FD_ZERO(&ifds);
+ FD_ZERO(&ofds);
+ FD_ZERO(&efds);
+ for(i=0;i<_nfds;i++){
+ _fds[i].revents=0;
+ if(_fds[i].events&POLLIN)FD_SET(_fds[i].fd,&ifds);
+ if(_fds[i].events&POLLOUT)FD_SET(_fds[i].fd,&ofds);
+ FD_SET(_fds[i].fd,&efds);
+ }
+ if(_timeout>=0){
+ tv.tv_sec=_timeout/1000;
+ tv.tv_usec=(_timeout%1000)*1000;
+ }
+ ret=select(-1,&ifds,&ofds,&efds,_timeout<0?NULL:&tv);
+ if(ret>0){
+ for(i=0;i<_nfds;i++){
+ if(FD_ISSET(_fds[i].fd,&ifds))_fds[i].revents|=POLLIN;
+ if(FD_ISSET(_fds[i].fd,&ofds))_fds[i].revents|=POLLOUT;
+ /*This isn't correct: there are several different things that might have
+ happened to a fd in efds, but I don't know a good way to distinguish
+ them without more context from the caller.
+ It's okay, because we don't actually check any of these bits, we just
+ need _some_ bit set.*/
+ if(FD_ISSET(_fds[i].fd,&efds))_fds[i].revents|=POLLHUP;
+ }
+ }
+ return ret;
+}
+
+/*We define op_errno() to make it clear that it's not an l-value like normal
+ errno is.*/
+# define op_errno() (WSAGetLastError()?WSAGetLastError()-WSABASEERR:0)
+# define op_reset_errno() (WSASetLastError(0))
+
+/*The remaining functions don't get an op_ prefix even though they only
+ operate on sockets, because we don't use non-socket I/O here, and this
+ minimizes the changes needed to deal with Winsock.*/
+# define close(_fd) closesocket(_fd)
+/*This relies on sizeof(u_long)==sizeof(int), which is always true on both
+ Win32 and Win64.*/
+# define ioctl(_fd,_req,_arg) ioctlsocket(_fd,_req,(u_long *)(_arg))
+# define getsockopt(_fd,_level,_name,_val,_len) \
+ getsockopt(_fd,_level,_name,(char *)(_val),_len)
+# define setsockopt(_fd,_level,_name,_val,_len) \
+ setsockopt(_fd,_level,_name,(const char *)(_val),_len)
+# define poll(_fds,_nfds,_timeout) op_poll_win32(_fds,_nfds,_timeout)
+
+# if defined(_MSC_VER)
+typedef ptrdiff_t ssize_t;
+# endif
+
+/*Load certificates from the built-in certificate store.*/
+int SSL_CTX_set_default_verify_paths_win32(SSL_CTX *_ssl_ctx);
+# define SSL_CTX_set_default_verify_paths \
+ SSL_CTX_set_default_verify_paths_win32
+
+# else
+/*Normal Berkeley sockets.*/
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <arpa/inet.h>
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# include <fcntl.h>
+# include <netdb.h>
+# include <poll.h>
+# include <unistd.h>
+# include <openssl/ssl.h>
+
+typedef int op_sock;
+
+# define OP_INVALID_SOCKET (-1)
+
+# define op_errno() (errno)
+# define op_reset_errno() (errno=0)
+
+# endif
+# include <sys/timeb.h>
+# include <openssl/x509v3.h>
+
+/*The maximum number of simultaneous connections.
+ RFC 2616 says this SHOULD NOT be more than 2, but everyone on the modern web
+ ignores that (e.g., IE 8 bumped theirs up from 2 to 6, Firefox uses 15).
+ If it makes you feel better, we'll only ever actively read from one of these
+ at a time.
+ The others are kept around mainly to avoid slow-starting a new connection
+ when seeking, and time out rapidly.*/
+# define OP_NCONNS_MAX (4)
+
+/*The amount of time before we attempt to re-resolve the host.
+ This is 10 minutes, as recommended in RFC 6555 for expiring cached connection
+ results for dual-stack hosts.*/
+# define OP_RESOLVE_CACHE_TIMEOUT_MS (10*60*(opus_int32)1000)
+
+/*The number of redirections at which we give up.
+ The value here is the current default in Firefox.
+ RFC 2068 mandated a maximum of 5, but RFC 2616 relaxed that to "a client
+ SHOULD detect infinite redirection loops."
+ Fortunately, 20 is less than infinity.*/
+# define OP_REDIRECT_LIMIT (20)
+
+/*The initial size of the buffer used to read a response message (before the
+ body).*/
+# define OP_RESPONSE_SIZE_MIN (510)
+/*The maximum size of a response message (before the body).
+ Responses larger than this will be discarded.
+ I've seen a real server return 20 kB of data for a 302 Found response.
+ Increasing this beyond 32kB will cause problems on platforms with a 16-bit
+ int.*/
+# define OP_RESPONSE_SIZE_MAX (32766)
+
+/*The number of milliseconds we will allow a connection to sit idle before we
+ refuse to resurrect it.
+ Apache as of 2.2 has reduced its default timeout to 5 seconds (from 15), so
+ that's what we'll use here.*/
+# define OP_CONNECTION_IDLE_TIMEOUT_MS (5*1000)
+
+/*The number of milliseconds we will wait to send or receive data before giving
+ up.*/
+# define OP_POLL_TIMEOUT_MS (30*1000)
+
+/*We will always attempt to read ahead at least this much in preference to
+ opening a new connection.*/
+# define OP_READAHEAD_THRESH_MIN (32*(opus_int32)1024)
+
+/*The amount of data to request after a seek.
+ This is a trade-off between read throughput after a seek vs. the the ability
+ to quickly perform another seek with the same connection.*/
+# define OP_PIPELINE_CHUNK_SIZE (32*(opus_int32)1024)
+/*Subsequent chunks are requested with larger and larger sizes until they pass
+ this threshold, after which we just ask for the rest of the resource.*/
+# define OP_PIPELINE_CHUNK_SIZE_MAX (1024*(opus_int32)1024)
+/*This is the maximum number of requests we'll make with a single connection.
+ Many servers will simply disconnect after we attempt some number of requests,
+ possibly without sending a Connection: close header, meaning we won't
+ discover it until we try to read beyond the end of the current chunk.
+ We can reconnect when that happens, but this is slow.
+ Instead, we impose a limit ourselves (set to the default for Apache
+ installations and thus likely the most common value in use).*/
+# define OP_PIPELINE_MAX_REQUESTS (100)
+/*This should be the number of requests, starting from a chunk size of
+ OP_PIPELINE_CHUNK_SIZE and doubling each time, until we exceed
+ OP_PIPELINE_CHUNK_SIZE_MAX and just request the rest of the file.
+ We won't reuse a connection when seeking unless it has at least this many
+ requests left, to reduce the chances we'll have to open a new connection
+ while reading forward afterwards.*/
+# define OP_PIPELINE_MIN_REQUESTS (7)
+
+/*Is this an https URL?
+ For now we can simply check the last letter of the scheme.*/
+# define OP_URL_IS_SSL(_url) ((_url)->scheme[4]=='s')
+
+/*Does this URL use the default port for its scheme?*/
+# define OP_URL_IS_DEFAULT_PORT(_url) \
+ (!OP_URL_IS_SSL(_url)&&(_url)->port==80 \
+ ||OP_URL_IS_SSL(_url)&&(_url)->port==443)
+
+struct OpusParsedURL{
+ /*Either "http" or "https".*/
+ char *scheme;
+ /*The user name from the <userinfo> component, or NULL.*/
+ char *user;
+ /*The password from the <userinfo> component, or NULL.*/
+ char *pass;
+ /*The <host> component.
+ This may not be NULL.*/
+ char *host;
+ /*The <path> and <query> components.
+ This may not be NULL.*/
+ char *path;
+ /*The <port> component.
+ This is set to the default port if the URL did not contain one.*/
+ unsigned port;
+};
+
+/*Parse a URL.
+ This code is not meant to be fast: strspn() with large sets is likely to be
+ slow, but it is very convenient.
+ It is meant to be RFC 3986-compliant.
+ We currently do not support IRIs (Internationalized Resource Identifiers,
+ RFC 3987).
+ Callers should translate them to URIs first.*/
+static int op_parse_url_impl(OpusParsedURL *_dst,const char *_src){
+ const char *scheme_end;
+ const char *authority;
+ const char *userinfo_end;
+ const char *user;
+ const char *user_end;
+ const char *pass;
+ const char *hostport;
+ const char *hostport_end;
+ const char *host_end;
+ const char *port;
+ opus_int32 port_num;
+ const char *port_end;
+ const char *path;
+ const char *path_end;
+ const char *uri_end;
+ scheme_end=_src+strspn(_src,OP_URL_SCHEME);
+ if(OP_UNLIKELY(*scheme_end!=':')
+ ||OP_UNLIKELY(scheme_end-_src<4)||OP_UNLIKELY(scheme_end-_src>5)
+ ||OP_UNLIKELY(op_strncasecmp(_src,"https",scheme_end-_src)!=0)){
+ /*Unsupported protocol.*/
+ return OP_EIMPL;
+ }
+ if(OP_UNLIKELY(scheme_end[1]!='/')||OP_UNLIKELY(scheme_end[2]!='/')){
+ /*We require an <authority> component.*/
+ return OP_EINVAL;
+ }
+ authority=scheme_end+3;
+ /*Make sure all escape sequences are valid to simplify unescaping later.*/
+ if(OP_UNLIKELY(op_validate_url_escapes(authority)<0))return OP_EINVAL;
+ /*Look for a <userinfo> component.*/
+ userinfo_end=authority+strspn(authority,OP_URL_PCHAR_NA);
+ if(*userinfo_end=='@'){
+ /*Found one.*/
+ user=authority;
+ /*Look for a password (yes, clear-text passwords are deprecated, I know,
+ but what else are people supposed to use? use SSL if you care).*/
+ user_end=authority+strspn(authority,OP_URL_PCHAR_BASE);
+ if(*user_end==':')pass=user_end+1;
+ else pass=NULL;
+ hostport=userinfo_end+1;
+ }
+ else{
+ /*We shouldn't have to initialize user_end, but gcc is too dumb to figure
+ out that user!=NULL below means we didn't take this else branch.*/
+ user=user_end=NULL;
+ pass=NULL;
+ hostport=authority;
+ }
+ /*Try to figure out where the <host> component ends.*/
+ if(hostport[0]=='['){
+ hostport++;
+ /*We have an <IP-literal>, which can contain colons.*/
+ hostport_end=host_end=hostport+strspn(hostport,OP_URL_PCHAR_NA);
+ if(OP_UNLIKELY(*hostport_end++!=']'))return OP_EINVAL;
+ }
+ /*Currently we don't support IDNA (RFC 5894), because I don't want to deal
+ with the policy about which domains should not be internationalized to
+ avoid confusing similarities.
+ Give this API Punycode (RFC 3492) domain names instead.*/
+ else hostport_end=host_end=hostport+strspn(hostport,OP_URL_PCHAR_BASE);
+ /*TODO: Validate host.*/
+ /*Is there a port number?*/
+ port_num=-1;
+ if(*hostport_end==':'){
+ int i;
+ port=hostport_end+1;
+ port_end=port+strspn(port,OP_URL_DIGIT);
+ path=port_end;
+ /*Not part of RFC 3986, but require port numbers in the range 0...65535.*/
+ if(OP_LIKELY(port_end-port>0)){
+ while(*port=='0')port++;
+ if(OP_UNLIKELY(port_end-port>5))return OP_EINVAL;
+ port_num=0;
+ for(i=0;i<port_end-port;i++)port_num=port_num*10+port[i]-'0';
+ if(OP_UNLIKELY(port_num>65535))return OP_EINVAL;
+ }
+ }
+ else path=hostport_end;
+ path_end=path+strspn(path,OP_URL_PATH);
+ /*If the path is not empty, it must begin with a '/'.*/
+ if(OP_LIKELY(path_end>path)&&OP_UNLIKELY(path[0]!='/'))return OP_EINVAL;
+ /*Consume the <query> component, if any (right now we don't split this out
+ from the <path> component).*/
+ if(*path_end=='?')path_end=path_end+strspn(path_end,OP_URL_QUERY_FRAG);
+ /*Discard the <fragment> component, if any.
+ This doesn't get sent to the server.
+ Some day we should add support for Media Fragment URIs
+ <http://www.w3.org/TR/media-frags/>.*/
+ if(*path_end=='#')uri_end=path_end+1+strspn(path_end+1,OP_URL_QUERY_FRAG);
+ else uri_end=path_end;
+ /*If there's anything left, this was not a valid URL.*/
+ if(OP_UNLIKELY(*uri_end!='\0'))return OP_EINVAL;
+ _dst->scheme=op_string_range_dup(_src,scheme_end);
+ if(OP_UNLIKELY(_dst->scheme==NULL))return OP_EFAULT;
+ op_string_tolower(_dst->scheme);
+ if(user!=NULL){
+ _dst->user=op_string_range_dup(user,user_end);
+ if(OP_UNLIKELY(_dst->user==NULL))return OP_EFAULT;
+ op_unescape_url_component(_dst->user);
+ /*Unescaping might have created a ':' in the username.
+ That's not allowed by RFC 2617's Basic Authentication Scheme.*/
+ if(OP_UNLIKELY(strchr(_dst->user,':')!=NULL))return OP_EINVAL;
+ }
+ else _dst->user=NULL;
+ if(pass!=NULL){
+ _dst->pass=op_string_range_dup(pass,userinfo_end);
+ if(OP_UNLIKELY(_dst->pass==NULL))return OP_EFAULT;
+ op_unescape_url_component(_dst->pass);
+ }
+ else _dst->pass=NULL;
+ _dst->host=op_string_range_dup(hostport,host_end);
+ if(OP_UNLIKELY(_dst->host==NULL))return OP_EFAULT;
+ if(port_num<0){
+ if(_src[4]=='s')port_num=443;
+ else port_num=80;
+ }
+ _dst->port=(unsigned)port_num;
+ /*RFC 2616 says an empty <abs-path> component is equivalent to "/", and we
+ MUST use the latter in the Request-URI.
+ Reserve space for the slash here.*/
+ if(path==path_end||path[0]=='?')path--;
+ _dst->path=op_string_range_dup(path,path_end);
+ if(OP_UNLIKELY(_dst->path==NULL))return OP_EFAULT;
+ /*And force-set it here.*/
+ _dst->path[0]='/';
+ return 0;
+}
+
+static void op_parsed_url_init(OpusParsedURL *_url){
+ memset(_url,0,sizeof(*_url));
+}
+
+static void op_parsed_url_clear(OpusParsedURL *_url){
+ _ogg_free(_url->scheme);
+ _ogg_free(_url->user);
+ _ogg_free(_url->pass);
+ _ogg_free(_url->host);
+ _ogg_free(_url->path);
+}
+
+static int op_parse_url(OpusParsedURL *_dst,const char *_src){
+ OpusParsedURL url;
+ int ret;
+ op_parsed_url_init(&url);
+ ret=op_parse_url_impl(&url,_src);
+ if(OP_UNLIKELY(ret<0))op_parsed_url_clear(&url);
+ else *_dst=*&url;
+ return ret;
+}
+
+/*A buffer to hold growing strings.
+ The main purpose of this is to consolidate allocation checks and simplify
+ cleanup on a failed allocation.*/
+struct OpusStringBuf{
+ char *buf;
+ int nbuf;
+ int cbuf;
+};
+
+static void op_sb_init(OpusStringBuf *_sb){
+ _sb->buf=NULL;
+ _sb->nbuf=0;
+ _sb->cbuf=0;
+}
+
+static void op_sb_clear(OpusStringBuf *_sb){
+ _ogg_free(_sb->buf);
+}
+
+/*Make sure we have room for at least _capacity characters (plus 1 more for the
+ terminating NUL).*/
+static int op_sb_ensure_capacity(OpusStringBuf *_sb,int _capacity){
+ char *buf;
+ int cbuf;
+ buf=_sb->buf;
+ cbuf=_sb->cbuf;
+ if(_capacity>=cbuf-1){
+ if(OP_UNLIKELY(cbuf>INT_MAX-1>>1))return OP_EFAULT;
+ if(OP_UNLIKELY(_capacity>=INT_MAX-1))return OP_EFAULT;
+ cbuf=OP_MAX(2*cbuf+1,_capacity+1);
+ buf=_ogg_realloc(buf,sizeof(*buf)*cbuf);
+ if(OP_UNLIKELY(buf==NULL))return OP_EFAULT;
+ _sb->buf=buf;
+ _sb->cbuf=cbuf;
+ }
+ return 0;
+}
+
+/*Increase the capacity of the buffer, but not to more than _max_size
+ characters (plus 1 more for the terminating NUL).*/
+static int op_sb_grow(OpusStringBuf *_sb,int _max_size){
+ char *buf;
+ int cbuf;
+ buf=_sb->buf;
+ cbuf=_sb->cbuf;
+ OP_ASSERT(_max_size<=INT_MAX-1);
+ cbuf=cbuf<=_max_size-1>>1?2*cbuf+1:_max_size+1;
+ buf=_ogg_realloc(buf,sizeof(*buf)*cbuf);
+ if(OP_UNLIKELY(buf==NULL))return OP_EFAULT;
+ _sb->buf=buf;
+ _sb->cbuf=cbuf;
+ return 0;
+}
+
+static int op_sb_append(OpusStringBuf *_sb,const char *_s,int _len){
+ char *buf;
+ int nbuf;
+ int ret;
+ nbuf=_sb->nbuf;
+ if(OP_UNLIKELY(nbuf>INT_MAX-_len))return OP_EFAULT;
+ ret=op_sb_ensure_capacity(_sb,nbuf+_len);
+ if(OP_UNLIKELY(ret<0))return ret;
+ buf=_sb->buf;
+ memcpy(buf+nbuf,_s,sizeof(*buf)*_len);
+ nbuf+=_len;
+ buf[nbuf]='\0';
+ _sb->nbuf=nbuf;
+ return 0;
+}
+
+static int op_sb_append_string(OpusStringBuf *_sb,const char *_s){
+ return op_sb_append(_sb,_s,strlen(_s));
+}
+
+static int op_sb_append_port(OpusStringBuf *_sb,unsigned _port){
+ char port_buf[7];
+ OP_ASSERT(_port<=65535U);
+ sprintf(port_buf,":%u",_port);
+ return op_sb_append_string(_sb,port_buf);
+}
+
+static int op_sb_append_nonnegative_int64(OpusStringBuf *_sb,opus_int64 _i){
+ char digit;
+ int nbuf_start;
+ int ret;
+ OP_ASSERT(_i>=0);
+ nbuf_start=_sb->nbuf;
+ ret=0;
+ do{
+ digit='0'+_i%10;
+ ret|=op_sb_append(_sb,&digit,1);
+ _i/=10;
+ }
+ while(_i>0);
+ if(OP_LIKELY(ret>=0)){
+ char *buf;
+ int nbuf_end;
+ buf=_sb->buf;
+ nbuf_end=_sb->nbuf-1;
+ /*We've added the digits backwards.
+ Reverse them.*/
+ while(nbuf_start<nbuf_end){
+ digit=buf[nbuf_start];
+ buf[nbuf_start]=buf[nbuf_end];
+ buf[nbuf_end]=digit;
+ nbuf_start++;
+ nbuf_end--;
+ }
+ }
+ return ret;
+}
+
+static struct addrinfo *op_resolve(const char *_host,unsigned _port){
+ struct addrinfo *addrs;
+ struct addrinfo hints;
+ char service[6];
+ memset(&hints,0,sizeof(hints));
+ hints.ai_socktype=SOCK_STREAM;
+#if defined(AI_NUMERICSERV)
+ hints.ai_flags=AI_NUMERICSERV;
+#endif
+ OP_ASSERT(_port<=65535U);
+ sprintf(service,"%u",_port);
+ if(OP_LIKELY(!getaddrinfo(_host,service,&hints,&addrs)))return addrs;
+ return NULL;
+}
+
+static int op_sock_set_nonblocking(op_sock _fd,int _nonblocking){
+#if !defined(_WIN32)
+ int flags;
+ flags=fcntl(_fd,F_GETFL);
+ if(OP_UNLIKELY(flags<0))return flags;
+ if(_nonblocking)flags|=O_NONBLOCK;
+ else flags&=~O_NONBLOCK;
+ return fcntl(_fd,F_SETFL,flags);
+#else
+ return ioctl(_fd,FIONBIO,&_nonblocking);
+#endif
+}
+
+/*Disable/enable write coalescing if we can.
+ We always send whole requests at once and always parse the response headers
+ before sending another one, so normally write coalescing just causes added
+ delay.*/
+static void op_sock_set_tcp_nodelay(op_sock _fd,int _nodelay){
+# if defined(TCP_NODELAY)&&(defined(IPPROTO_TCP)||defined(SOL_TCP))
+# if defined(IPPROTO_TCP)
+# define OP_SO_LEVEL IPPROTO_TCP
+# else
+# define OP_SO_LEVEL SOL_TCP
+# endif
+ /*It doesn't really matter if this call fails, but it would be interesting
+ to hit a case where it does.*/
+ OP_ALWAYS_TRUE(!setsockopt(_fd,OP_SO_LEVEL,TCP_NODELAY,
+ &_nodelay,sizeof(_nodelay)));
+# endif
+}
+
+#if defined(_WIN32)
+static void op_init_winsock(){
+ static LONG count;
+ static WSADATA wsadata;
+ if(InterlockedIncrement(&count)==1)WSAStartup(0x0202,&wsadata);
+}
+#endif
+
+/*A single physical connection to an HTTP server.
+ We may have several of these open at once.*/
+struct OpusHTTPConn{
+ /*The current position indicator for this connection.*/
+ opus_int64 pos;
+ /*The position where the current request will end, or -1 if we're reading
+ until EOF (an unseekable stream or the initial HTTP/1.0 request).*/
+ opus_int64 end_pos;
+ /*The position where next request we've sent will start, or -1 if we haven't
+ sent the next request yet.*/
+ opus_int64 next_pos;
+ /*The end of the next request or -1 if we requested the rest of the resource.
+ This is only set to a meaningful value if next_pos is not -1.*/
+ opus_int64 next_end;
+ /*The SSL connection, if this is https.*/
+ SSL *ssl_conn;
+ /*The next connection in either the LRU or free list.*/
+ OpusHTTPConn *next;
+ /*The last time we blocked for reading from this connection.*/
+ struct timeb read_time;
+ /*The number of bytes we've read since the last time we blocked.*/
+ opus_int64 read_bytes;
+ /*The estimated throughput of this connection, in bytes/s.*/
+ opus_int64 read_rate;
+ /*The socket we're reading from.*/
+ op_sock fd;
+ /*The number of remaining requests we are allowed on this connection.*/
+ int nrequests_left;
+ /*The chunk size to use for pipelining requests.*/
+ opus_int32 chunk_size;
+};
+
+static void op_http_conn_init(OpusHTTPConn *_conn){
+ _conn->next_pos=-1;
+ _conn->ssl_conn=NULL;
+ _conn->next=NULL;
+ _conn->fd=OP_INVALID_SOCKET;
+}
+
+static void op_http_conn_clear(OpusHTTPConn *_conn){
+ if(_conn->ssl_conn!=NULL)SSL_free(_conn->ssl_conn);
+ /*SSL frees the BIO for us.*/
+ if(_conn->fd!=OP_INVALID_SOCKET)close(_conn->fd);
+}
+
+/*The global stream state.*/
+struct OpusHTTPStream{
+ /*The list of connections.*/
+ OpusHTTPConn conns[OP_NCONNS_MAX];
+ /*The context object used as a framework for TLS/SSL functions.*/
+ SSL_CTX *ssl_ctx;
+ /*The cached session to reuse for future connections.*/
+ SSL_SESSION *ssl_session;
+ /*The LRU list (ordered from MRU to LRU) of currently connected
+ connections.*/
+ OpusHTTPConn *lru_head;
+ /*The free list.*/
+ OpusHTTPConn *free_head;
+ /*The URL to connect to.*/
+ OpusParsedURL url;
+ /*Information about the address we connected to.*/
+ struct addrinfo addr_info;
+ /*The address we connected to.*/
+ union{
+ struct sockaddr s;
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+ } addr;
+ /*The last time we re-resolved the host.*/
+ struct timeb resolve_time;
+ /*A buffer used to build HTTP requests.*/
+ OpusStringBuf request;
+ /*A buffer used to build proxy CONNECT requests.*/
+ OpusStringBuf proxy_connect;
+ /*A buffer used to receive the response headers.*/
+ OpusStringBuf response;
+ /*The Content-Length, if specified, or -1 otherwise.
+ This will always be specified for seekable streams.*/
+ opus_int64 content_length;
+ /*The position indicator used when no connection is active.*/
+ opus_int64 pos;
+ /*The host we actually connected to.*/
+ char *connect_host;
+ /*The port we actually connected to.*/
+ unsigned connect_port;
+ /*The connection we're currently reading from.
+ This can be -1 if no connection is active.*/
+ int cur_conni;
+ /*Whether or not the server supports range requests.*/
+ int seekable;
+ /*Whether or not the server supports HTTP/1.1 with persistent connections.*/
+ int pipeline;
+ /*Whether or not we should skip certificate checks.*/
+ int skip_certificate_check;
+ /*The offset of the tail of the request.
+ Only the offset in the Range: header appears after this, allowing us to
+ quickly edit the request to ask for a new range.*/
+ int request_tail;
+ /*The estimated time required to open a new connection, in milliseconds.*/
+ opus_int32 connect_rate;
+};
+
+static void op_http_stream_init(OpusHTTPStream *_stream){
+ OpusHTTPConn **pnext;
+ int ci;
+ pnext=&_stream->free_head;
+ for(ci=0;ci<OP_NCONNS_MAX;ci++){
+ op_http_conn_init(_stream->conns+ci);
+ *pnext=_stream->conns+ci;
+ pnext=&_stream->conns[ci].next;
+ }
+ _stream->ssl_ctx=NULL;
+ _stream->ssl_session=NULL;
+ _stream->lru_head=NULL;
+ op_parsed_url_init(&_stream->url);
+ op_sb_init(&_stream->request);
+ op_sb_init(&_stream->proxy_connect);
+ op_sb_init(&_stream->response);
+ _stream->connect_host=NULL;
+ _stream->seekable=0;
+}
+
+/*Close the connection and move it to the free list.
+ _stream: The stream containing the free list.
+ _conn: The connection to close.
+ _pnext: The linked-list pointer currently pointing to this connection.
+ _gracefully: Whether or not to shut down cleanly.*/
+static void op_http_conn_close(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
+ OpusHTTPConn **_pnext,int _gracefully){
+ /*If we don't shut down gracefully, the server MUST NOT re-use our session
+ according to RFC 2246, because it can't tell the difference between an
+ abrupt close and a truncation attack.
+ So we shut down gracefully if we can.
+ However, we will not wait if this would block (it's not worth the savings
+ from session resumption to do so).
+ Clients (that's us) MAY resume a TLS session that ended with an incomplete
+ close, according to RFC 2818, so there's no reason to make sure the server
+ shut things down gracefully.*/
+ if(_gracefully&&_conn->ssl_conn!=NULL)SSL_shutdown(_conn->ssl_conn);
+ op_http_conn_clear(_conn);
+ _conn->next_pos=-1;
+ _conn->ssl_conn=NULL;
+ _conn->fd=OP_INVALID_SOCKET;
+ OP_ASSERT(*_pnext==_conn);
+ *_pnext=_conn->next;
+ _conn->next=_stream->free_head;
+ _stream->free_head=_conn;
+}
+
+static void op_http_stream_clear(OpusHTTPStream *_stream){
+ while(_stream->lru_head!=NULL){
+ op_http_conn_close(_stream,_stream->lru_head,&_stream->lru_head,0);
+ }
+ if(_stream->ssl_session!=NULL)SSL_SESSION_free(_stream->ssl_session);
+ if(_stream->ssl_ctx!=NULL)SSL_CTX_free(_stream->ssl_ctx);
+ op_sb_clear(&_stream->response);
+ op_sb_clear(&_stream->proxy_connect);
+ op_sb_clear(&_stream->request);
+ if(_stream->connect_host!=_stream->url.host)_ogg_free(_stream->connect_host);
+ op_parsed_url_clear(&_stream->url);
+}
+
+static int op_http_conn_write_fully(OpusHTTPConn *_conn,
+ const char *_buf,int _buf_size){
+ struct pollfd fd;
+ SSL *ssl_conn;
+ fd.fd=_conn->fd;
+ ssl_conn=_conn->ssl_conn;
+ while(_buf_size>0){
+ int err;
+ if(ssl_conn!=NULL){
+ int ret;
+ ret=SSL_write(ssl_conn,_buf,_buf_size);
+ if(ret>0){
+ /*Wrote some data.*/
+ _buf+=ret;
+ _buf_size-=ret;
+ continue;
+ }
+ /*Connection closed.*/
+ else if(ret==0)return OP_FALSE;
+ err=SSL_get_error(ssl_conn,ret);
+ /*Yes, renegotiations can cause SSL_write() to block for reading.*/
+ if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
+ else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
+ else return OP_FALSE;
+ }
+ else{
+ ssize_t ret;
+ op_reset_errno();
+ ret=send(fd.fd,_buf,_buf_size,0);
+ if(ret>0){
+ _buf+=ret;
+ _buf_size-=ret;
+ continue;
+ }
+ err=op_errno();
+ if(err!=EAGAIN&&err!=EWOULDBLOCK)return OP_FALSE;
+ fd.events=POLLOUT;
+ }
+ if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_FALSE;
+ }
+ return 0;
+}
+
+static int op_http_conn_estimate_available(OpusHTTPConn *_conn){
+ int available;
+ int ret;
+ ret=ioctl(_conn->fd,FIONREAD,&available);
+ if(ret<0)available=0;
+ /*This requires the SSL read_ahead flag to be unset to work.
+ We ignore partial records as well as the protocol overhead for any pending
+ bytes.
+ This means we might return somewhat less than can truly be read without
+ blocking (if there's a partial record).
+ This is okay, because we're using this value to estimate network transfer
+ time, and we _have_ already received those bytes.
+ We also might return slightly more (due to protocol overhead), but that's
+ small enough that it probably doesn't matter.*/
+ if(_conn->ssl_conn!=NULL)available+=SSL_pending(_conn->ssl_conn);
+ return available;
+}
+
+static opus_int32 op_time_diff_ms(const struct timeb *_end,
+ const struct timeb *_start){
+ opus_int64 dtime;
+ dtime=_end->time-(opus_int64)_start->time;
+ OP_ASSERT(_end->millitm<1000);
+ OP_ASSERT(_start->millitm<1000);
+ if(OP_UNLIKELY(dtime>(OP_INT32_MAX-1000)/1000))return OP_INT32_MAX;
+ if(OP_UNLIKELY(dtime<(OP_INT32_MIN+1000)/1000))return OP_INT32_MIN;
+ return (opus_int32)dtime*1000+_end->millitm-_start->millitm;
+}
+
+/*Update the read rate estimate for this connection.*/
+static void op_http_conn_read_rate_update(OpusHTTPConn *_conn){
+ struct timeb read_time;
+ opus_int32 read_delta_ms;
+ opus_int64 read_delta_bytes;
+ opus_int64 read_rate;
+ read_delta_bytes=_conn->read_bytes;
+ if(read_delta_bytes<=0)return;
+ ftime(&read_time);
+ read_delta_ms=op_time_diff_ms(&read_time,&_conn->read_time);
+ read_rate=_conn->read_rate;
+ read_delta_ms=OP_MAX(read_delta_ms,1);
+ read_rate+=read_delta_bytes*1000/read_delta_ms-read_rate+4>>3;
+ *&_conn->read_time=*&read_time;
+ _conn->read_bytes=0;
+ _conn->read_rate=read_rate;
+}
+
+/*Tries to read from the given connection.
+ [out] _buf: Returns the data read.
+ _buf_size: The size of the buffer.
+ _blocking: Whether or not to block until some data is retrieved.
+ Return: A positive number of bytes read on success.
+ 0: The read would block, or the connection was closed.
+ OP_EREAD: There was a fatal read error.*/
+static int op_http_conn_read(OpusHTTPConn *_conn,
+ char *_buf,int _buf_size,int _blocking){
+ struct pollfd fd;
+ SSL *ssl_conn;
+ int nread;
+ int nread_unblocked;
+ fd.fd=_conn->fd;
+ ssl_conn=_conn->ssl_conn;
+ nread=nread_unblocked=0;
+ /*RFC 2818 says "client implementations MUST treat any premature closes as
+ errors and the data received as potentially truncated," so we make very
+ sure to report read errors upwards.*/
+ do{
+ int err;
+ if(ssl_conn!=NULL){
+ int ret;
+ ret=SSL_read(ssl_conn,_buf+nread,_buf_size-nread);
+ OP_ASSERT(ret<=_buf_size-nread);
+ if(ret>0){
+ /*Read some data.
+ Keep going to see if there's more.*/
+ nread+=ret;
+ nread_unblocked+=ret;
+ continue;
+ }
+ /*If we already read some data, return it right now.*/
+ if(nread>0)break;
+ err=SSL_get_error(ssl_conn,ret);
+ if(ret==0){
+ /*Connection close.
+ Check for a clean shutdown to prevent truncation attacks.
+ This check always succeeds for SSLv2, as it has no "close notify"
+ message and thus can't verify an orderly shutdown.*/
+ return err==SSL_ERROR_ZERO_RETURN?0:OP_EREAD;
+ }
+ if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
+ /*Yes, renegotiations can cause SSL_read() to block for writing.*/
+ else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
+ /*Some other error.*/
+ else return OP_EREAD;
+ }
+ else{
+ ssize_t ret;
+ op_reset_errno();
+ ret=recv(fd.fd,_buf+nread,_buf_size-nread,0);
+ OP_ASSERT(ret<=_buf_size-nread);
+ if(ret>0){
+ /*Read some data.
+ Keep going to see if there's more.*/
+ nread+=ret;
+ nread_unblocked+=ret;
+ continue;
+ }
+ /*If we already read some data or the connection was closed, return
+ right now.*/
+ if(ret==0||nread>0)break;
+ err=op_errno();
+ if(err!=EAGAIN&&err!=EWOULDBLOCK)return OP_EREAD;
+ fd.events=POLLIN;
+ }
+ _conn->read_bytes+=nread_unblocked;
+ op_http_conn_read_rate_update(_conn);
+ nread_unblocked=0;
+ if(!_blocking)break;
+ /*Need to wait to get any data at all.*/
+ if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_EREAD;
+ }
+ while(nread<_buf_size);
+ _conn->read_bytes+=nread_unblocked;
+ return nread;
+}
+
+/*Tries to look at the pending data for a connection without consuming it.
+ [out] _buf: Returns the data at which we're peeking.
+ _buf_size: The size of the buffer.*/
+static int op_http_conn_peek(OpusHTTPConn *_conn,char *_buf,int _buf_size){
+ struct pollfd fd;
+ SSL *ssl_conn;
+ int ret;
+ fd.fd=_conn->fd;
+ ssl_conn=_conn->ssl_conn;
+ for(;;){
+ int err;
+ if(ssl_conn!=NULL){
+ ret=SSL_peek(ssl_conn,_buf,_buf_size);
+ /*Either saw some data or the connection was closed.*/
+ if(ret>=0)return ret;
+ err=SSL_get_error(ssl_conn,ret);
+ if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
+ /*Yes, renegotiations can cause SSL_peek() to block for writing.*/
+ else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
+ else return 0;
+ }
+ else{
+ op_reset_errno();
+ ret=(int)recv(fd.fd,_buf,_buf_size,MSG_PEEK);
+ /*Either saw some data or the connection was closed.*/
+ if(ret>=0)return ret;
+ err=op_errno();
+ if(err!=EAGAIN&&err!=EWOULDBLOCK)return 0;
+ fd.events=POLLIN;
+ }
+ /*Need to wait to get any data at all.*/
+ if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return 0;
+ }
+}
+
+/*When parsing response headers, RFC 2616 mandates that all lines end in CR LF.
+ However, even in the year 2012, I have seen broken servers use just a LF.
+ This is the evil that Postel's advice from RFC 761 breeds.*/
+
+/*Reads the entirety of a response to an HTTP request into the response buffer.
+ Actual parsing and validation is done later.
+ Return: The number of bytes in the response on success, OP_EREAD if the
+ connection was closed before reading any data, or another negative
+ value on any other error.*/
+static int op_http_conn_read_response(OpusHTTPConn *_conn,
+ OpusStringBuf *_response){
+ int ret;
+ _response->nbuf=0;
+ ret=op_sb_ensure_capacity(_response,OP_RESPONSE_SIZE_MIN);
+ if(OP_UNLIKELY(ret<0))return ret;
+ for(;;){
+ char *buf;
+ int size;
+ int capacity;
+ int read_limit;
+ int terminated;
+ size=_response->nbuf;
+ capacity=_response->cbuf-1;
+ if(OP_UNLIKELY(size>=capacity)){
+ ret=op_sb_grow(_response,OP_RESPONSE_SIZE_MAX);
+ if(OP_UNLIKELY(ret<0))return ret;
+ capacity=_response->cbuf-1;
+ /*The response was too large.
+ This prevents a bad server from running us out of memory.*/
+ if(OP_UNLIKELY(size>=capacity))return OP_EIMPL;
+ }
+ buf=_response->buf;
+ ret=op_http_conn_peek(_conn,buf+size,capacity-size);
+ if(OP_UNLIKELY(ret<=0))return size<=0?OP_EREAD:OP_FALSE;
+ /*We read some data.*/
+ /*Make sure the starting characters are "HTTP".
+ Otherwise we could wind up waiting forever for a response from
+ something that is not an HTTP server.*/
+ if(size<4&&op_strncasecmp(buf,"HTTP",OP_MIN(size+ret,4))!=0){
+ return OP_FALSE;
+ }
+ /*How far can we read without passing the "\r\n\r\n" terminator?*/
+ buf[size+ret]='\0';
+ terminated=0;
+ for(read_limit=OP_MAX(size-3,0);read_limit<size+ret;read_limit++){
+ /*We don't look for the leading '\r' thanks to broken servers.*/
+ if(buf[read_limit]=='\n'){
+ if(buf[read_limit+1]=='\r'&&OP_LIKELY(buf[read_limit+2]=='\n')){
+ terminated=3;
+ break;
+ }
+ /*This case is for broken servers.*/
+ else if(OP_UNLIKELY(buf[read_limit+1]=='\n')){
+ terminated=2;
+ break;
+ }
+ }
+ }
+ read_limit+=terminated;
+ OP_ASSERT(size<=read_limit);
+ OP_ASSERT(read_limit<=size+ret);
+ /*Actually consume that data.*/
+ ret=op_http_conn_read(_conn,buf+size,read_limit-size,1);
+ if(OP_UNLIKELY(ret<=0))return OP_FALSE;
+ size+=ret;
+ buf[size]='\0';
+ _response->nbuf=size;
+ /*We found the terminator and read all the data up to and including it.*/
+ if(terminated&&OP_LIKELY(size>=read_limit))return size;
+ }
+ return OP_EIMPL;
+}
+
+# define OP_HTTP_DIGIT "0123456789"
+
+/*The Reason-Phrase is not allowed to contain control characters, except
+ horizontal tab (HT: \011).*/
+# define OP_HTTP_CREASON_PHRASE \
+ "\001\002\003\004\005\006\007\010\012\013\014\015\016\017\020\021" \
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177"
+
+# define OP_HTTP_CTLS \
+ "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020" \
+ "\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177"
+
+/*This also includes '\t', but we get that from OP_HTTP_CTLS.*/
+# define OP_HTTP_SEPARATORS " \"(),/:;<=>?@[\\]{}"
+
+/*TEXT can also include LWS, but that has structure, so we parse it
+ separately.*/
+# define OP_HTTP_CTOKEN OP_HTTP_CTLS OP_HTTP_SEPARATORS
+
+/*Return: The amount of linear white space (LWS) at the start of _s.*/
+static int op_http_lwsspn(const char *_s){
+ int i;
+ for(i=0;;){
+ if(_s[0]=='\r'&&_s[1]=='\n'&&(_s[2]=='\t'||_s[2]==' '))i+=3;
+ /*This case is for broken servers.*/
+ else if(_s[0]=='\n'&&(_s[1]=='\t'||_s[1]==' '))i+=2;
+ else if(_s[i]=='\t'||_s[i]==' ')i++;
+ else return i;
+ }
+}
+
+static char *op_http_parse_status_line(int *_v1_1_compat,
+ char **_status_code,char *_response){
+ char *next;
+ char *status_code;
+ int v1_1_compat;
+ size_t d;
+ /*RFC 2616 Section 6.1 does not say that the tokens in the Status-Line cannot
+ be separated by optional LWS, but since it specifically calls out where
+ spaces are to be placed and that CR and LF are not allowed except at the
+ end, I am assuming this to be true.*/
+ /*We already validated that this starts with "HTTP"*/
+ OP_ASSERT(op_strncasecmp(_response,"HTTP",4)==0);
+ next=_response+4;
+ if(OP_UNLIKELY(*next++!='/'))return NULL;
+ d=strspn(next,OP_HTTP_DIGIT);
+ /*"Leading zeros MUST be ignored by recipients."*/
+ while(*next=='0'){
+ next++;
+ OP_ASSERT(d>0);
+ d--;
+ }
+ /*We only support version 1.x*/
+ if(OP_UNLIKELY(d!=1)||OP_UNLIKELY(*next++!='1'))return NULL;
+ if(OP_UNLIKELY(*next++!='.'))return NULL;
+ d=strspn(next,OP_HTTP_DIGIT);
+ if(OP_UNLIKELY(d<=0))return NULL;
+ /*"Leading zeros MUST be ignored by recipients."*/
+ while(*next=='0'){
+ next++;
+ OP_ASSERT(d>0);
+ d--;
+ }
+ /*We don't need to parse the version number.
+ Any non-zero digit means it's greater than 1.*/
+ v1_1_compat=d>0;
+ next+=d;
+ if(OP_UNLIKELY(*next++!=' '))return NULL;
+ status_code=next;
+ d=strspn(next,OP_HTTP_DIGIT);
+ if(OP_UNLIKELY(d!=3))return NULL;
+ next+=d;
+ /*The Reason-Phrase can be empty, but the space must be here.*/
+ if(OP_UNLIKELY(*next++!=' '))return NULL;
+ next+=strcspn(next,OP_HTTP_CREASON_PHRASE);
+ /*We are not mandating this be present thanks to broken servers.*/
+ if(OP_LIKELY(*next=='\r'))next++;
+ if(OP_UNLIKELY(*next++!='\n'))return NULL;
+ if(_v1_1_compat!=NULL)*_v1_1_compat=v1_1_compat;
+ *_status_code=status_code;
+ return next;
+}
+
+/*Get the next response header.
+ [out] _header: The header token, NUL-terminated, with leading and trailing
+ whitespace stripped, and converted to lower case (to simplify
+ case-insensitive comparisons), or NULL if there are no more
+ response headers.
+ [out] _cdr: The remaining contents of the header, excluding the initial
+ colon (':') and the terminating CRLF ("\r\n"),
+ NUL-terminated, and with leading and trailing whitespace
+ stripped, or NULL if there are no more response headers.
+ [inout] _s: On input, this points to the start of the current line of the
+ response headers.
+ On output, it points to the start of the first line following
+ this header, or NULL if there are no more response headers.
+ Return: 0 on success, or a negative value on failure.*/
+static int op_http_get_next_header(char **_header,char **_cdr,char **_s){
+ char *header;
+ char *header_end;
+ char *cdr;
+ char *cdr_end;
+ char *next;
+ size_t d;
+ next=*_s;
+ /*The second case is for broken servers.*/
+ if(next[0]=='\r'&&next[1]=='\n'||OP_UNLIKELY(next[0]=='\n')){
+ /*No more headers.*/
+ *_header=NULL;
+ *_cdr=NULL;
+ *_s=NULL;
+ return 0;
+ }
+ header=next+op_http_lwsspn(next);
+ d=strcspn(header,OP_HTTP_CTOKEN);
+ if(OP_UNLIKELY(d<=0))return OP_FALSE;
+ header_end=header+d;
+ next=header_end+op_http_lwsspn(header_end);
+ if(OP_UNLIKELY(*next++!=':'))return OP_FALSE;
+ next+=op_http_lwsspn(next);
+ cdr=next;
+ do{
+ cdr_end=next+strcspn(next,OP_HTTP_CTLS);
+ next=cdr_end+op_http_lwsspn(cdr_end);
+ }
+ while(next>cdr_end);
+ /*We are not mandating this be present thanks to broken servers.*/
+ if(OP_LIKELY(*next=='\r'))next++;
+ if(OP_UNLIKELY(*next++!='\n'))return OP_FALSE;
+ *header_end='\0';
+ *cdr_end='\0';
+ /*Field names are case-insensitive.*/
+ op_string_tolower(header);
+ *_header=header;
+ *_cdr=cdr;
+ *_s=next;
+ return 0;
+}
+
+static opus_int64 op_http_parse_nonnegative_int64(const char **_next,
+ const char *_cdr){
+ const char *next;
+ opus_int64 ret;
+ int i;
+ next=_cdr+strspn(_cdr,OP_HTTP_DIGIT);
+ *_next=next;
+ if(OP_UNLIKELY(next<=_cdr))return OP_FALSE;
+ while(*_cdr=='0')_cdr++;
+ if(OP_UNLIKELY(next-_cdr>19))return OP_EIMPL;
+ ret=0;
+ for(i=0;i<next-_cdr;i++){
+ int digit;
+ digit=_cdr[i]-'0';
+ /*Check for overflow.*/
+ if(OP_UNLIKELY(ret>(OP_INT64_MAX-9)/10+(digit<=7)))return OP_EIMPL;
+ ret=ret*10+digit;
+ }
+ return ret;
+}
+
+static opus_int64 op_http_parse_content_length(const char *_cdr){
+ const char *next;
+ opus_int64 content_length;
+ content_length=op_http_parse_nonnegative_int64(&next,_cdr);
+ if(OP_UNLIKELY(*next!='\0'))return OP_FALSE;
+ return content_length;
+}
+
+static int op_http_parse_content_range(opus_int64 *_first,opus_int64 *_last,
+ opus_int64 *_length,const char *_cdr){
+ opus_int64 first;
+ opus_int64 last;
+ opus_int64 length;
+ size_t d;
+ if(OP_UNLIKELY(op_strncasecmp(_cdr,"bytes",5)!=0))return OP_FALSE;
+ _cdr+=5;
+ d=op_http_lwsspn(_cdr);
+ if(OP_UNLIKELY(d<=0))return OP_FALSE;
+ _cdr+=d;
+ if(*_cdr!='*'){
+ first=op_http_parse_nonnegative_int64(&_cdr,_cdr);
+ if(OP_UNLIKELY(first<0))return (int)first;
+ _cdr+=op_http_lwsspn(_cdr);
+ if(*_cdr++!='-')return OP_FALSE;
+ _cdr+=op_http_lwsspn(_cdr);
+ last=op_http_parse_nonnegative_int64(&_cdr,_cdr);
+ if(OP_UNLIKELY(last<0))return (int)last;
+ _cdr+=op_http_lwsspn(_cdr);
+ }
+ else{
+ /*This is for a 416 response (Requested range not satisfiable).*/
+ first=last=-1;
+ _cdr++;
+ }
+ if(OP_UNLIKELY(*_cdr++!='/'))return OP_FALSE;
+ if(*_cdr!='*'){
+ length=op_http_parse_nonnegative_int64(&_cdr,_cdr);
+ if(OP_UNLIKELY(length<0))return (int)length;
+ }
+ else{
+ /*The total length is unspecified.*/
+ _cdr++;
+ length=-1;
+ }
+ if(OP_UNLIKELY(*_cdr!='\0'))return OP_FALSE;
+ if(OP_UNLIKELY(last<first))return OP_FALSE;
+ if(length>=0&&OP_UNLIKELY(last>=length))return OP_FALSE;
+ *_first=first;
+ *_last=last;
+ *_length=length;
+ return 0;
+}
+
+/*Parse the Connection response header and look for a "close" token.
+ Return: 1 if a "close" token is found, 0 if it's not found, and a negative
+ value on error.*/
+static int op_http_parse_connection(char *_cdr){
+ size_t d;
+ int ret;
+ ret=0;
+ for(;;){
+ d=strcspn(_cdr,OP_HTTP_CTOKEN);
+ if(OP_UNLIKELY(d<=0))return OP_FALSE;
+ if(op_strncasecmp(_cdr,"close",(int)d)==0)ret=1;
+ /*We're supposed to strip and ignore any headers mentioned in the
+ Connection header if this response is from an HTTP/1.0 server (to
+ work around forwarding of hop-by-hop headers by old proxies), but the
+ only hop-by-hop header we look at is Connection itself.
+ Everything else is a well-defined end-to-end header, and going back and
+ undoing the things we did based on already-examined headers would be
+ hard (since we only scan them once, in a destructive manner).
+ Therefore we just ignore all the other tokens.*/
+ _cdr+=d;
+ d=op_http_lwsspn(_cdr);
+ if(d<=0)break;
+ _cdr+=d;
+ }
+ return OP_UNLIKELY(*_cdr!='\0')?OP_FALSE:ret;
+}
+
+typedef int (*op_ssl_step_func)(SSL *_ssl_conn);
+
+/*Try to run an SSL function to completion (blocking if necessary).*/
+static int op_do_ssl_step(SSL *_ssl_conn,op_sock _fd,op_ssl_step_func _step){
+ struct pollfd fd;
+ fd.fd=_fd;
+ for(;;){
+ int ret;
+ int err;
+ ret=(*_step)(_ssl_conn);
+ if(ret>=0)return ret;
+ err=SSL_get_error(_ssl_conn,ret);
+ if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
+ else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
+ else return OP_FALSE;
+ if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_FALSE;
+ }
+}
+
+/*Implement a BIO type that just indicates every operation should be retried.
+ We use this when initializing an SSL connection via a proxy to allow the
+ initial handshake to proceed all the way up to the first read attempt, and
+ then return.
+ This allows the TLS client hello message to be pipelined with the HTTP
+ CONNECT request.*/
+
+static int op_bio_retry_write(BIO *_b,const char *_buf,int _num){
+ (void)_buf;
+ (void)_num;
+ BIO_clear_retry_flags(_b);
+ BIO_set_retry_write(_b);
+ return -1;
+}
+
+static int op_bio_retry_read(BIO *_b,char *_buf,int _num){
+ (void)_buf;
+ (void)_num;
+ BIO_clear_retry_flags(_b);
+ BIO_set_retry_read(_b);
+ return -1;
+}
+
+static int op_bio_retry_puts(BIO *_b,const char *_str){
+ return op_bio_retry_write(_b,_str,0);
+}
+
+static long op_bio_retry_ctrl(BIO *_b,int _cmd,long _num,void *_ptr){
+ long ret;
+ (void)_b;
+ (void)_num;
+ (void)_ptr;
+ ret=0;
+ switch(_cmd){
+ case BIO_CTRL_RESET:
+ case BIO_C_RESET_READ_REQUEST:{
+ BIO_clear_retry_flags(_b);
+ /*Fall through.*/
+ }
+ case BIO_CTRL_EOF:
+ case BIO_CTRL_SET:
+ case BIO_CTRL_SET_CLOSE:
+ case BIO_CTRL_FLUSH:
+ case BIO_CTRL_DUP:{
+ ret=1;
+ }break;
+ }
+ return ret;
+}
+
+# if OPENSSL_VERSION_NUMBER<0x10100000L
+# define BIO_set_data(_b,_ptr) ((_b)->ptr=(_ptr))
+# define BIO_set_init(_b,_init) ((_b)->init=(_init))
+# endif
+
+static int op_bio_retry_new(BIO *_b){
+ BIO_set_init(_b,1);
+# if OPENSSL_VERSION_NUMBER<0x10100000L
+ _b->num=0;
+# endif
+ BIO_set_data(_b,NULL);
+ return 1;
+}
+
+static int op_bio_retry_free(BIO *_b){
+ return _b!=NULL;
+}
+
+# if OPENSSL_VERSION_NUMBER<0x10100000L
+/*This is not const because OpenSSL doesn't allow it, even though it won't
+ write to it.*/
+static BIO_METHOD op_bio_retry_method={
+ BIO_TYPE_NULL,
+ "retry",
+ op_bio_retry_write,
+ op_bio_retry_read,
+ op_bio_retry_puts,
+ NULL,
+ op_bio_retry_ctrl,
+ op_bio_retry_new,
+ op_bio_retry_free,
+ NULL
+};
+# endif
+
+/*Establish a CONNECT tunnel and pipeline the start of the TLS handshake for
+ proxying https URL requests.*/
+static int op_http_conn_establish_tunnel(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn,op_sock _fd,SSL *_ssl_conn,BIO *_ssl_bio){
+# if OPENSSL_VERSION_NUMBER>=0x10100000L
+ BIO_METHOD *bio_retry_method;
+# endif
+ BIO *retry_bio;
+ char *status_code;
+ char *next;
+ int ret;
+ _conn->ssl_conn=NULL;
+ _conn->fd=_fd;
+ OP_ASSERT(_stream->proxy_connect.nbuf>0);
+ ret=op_http_conn_write_fully(_conn,
+ _stream->proxy_connect.buf,_stream->proxy_connect.nbuf);
+ if(OP_UNLIKELY(ret<0))return ret;
+# if OPENSSL_VERSION_NUMBER>=0x10100000L
+ bio_retry_method=BIO_meth_new(BIO_TYPE_NULL,"retry");
+ if(bio_retry_method==NULL)return OP_EFAULT;
+ BIO_meth_set_write(bio_retry_method,op_bio_retry_write);
+ BIO_meth_set_read(bio_retry_method,op_bio_retry_read);
+ BIO_meth_set_puts(bio_retry_method,op_bio_retry_puts);
+ BIO_meth_set_ctrl(bio_retry_method,op_bio_retry_ctrl);
+ BIO_meth_set_create(bio_retry_method,op_bio_retry_new);
+ BIO_meth_set_destroy(bio_retry_method,op_bio_retry_free);
+ retry_bio=BIO_new(bio_retry_method);
+ if(OP_UNLIKELY(retry_bio==NULL)){
+ BIO_meth_free(bio_retry_method);
+ return OP_EFAULT;
+ }
+# else
+ retry_bio=BIO_new(&op_bio_retry_method);
+ if(OP_UNLIKELY(retry_bio==NULL))return OP_EFAULT;
+# endif
+ SSL_set_bio(_ssl_conn,retry_bio,_ssl_bio);
+ SSL_set_connect_state(_ssl_conn);
+ /*This shouldn't succeed, since we can't read yet.*/
+ OP_ALWAYS_TRUE(SSL_connect(_ssl_conn)<0);
+ SSL_set_bio(_ssl_conn,_ssl_bio,_ssl_bio);
+# if OPENSSL_VERSION_NUMBER>=0x10100000L
+ BIO_meth_free(bio_retry_method);
+# endif
+ /*Only now do we disable write coalescing, to allow the CONNECT
+ request and the start of the TLS handshake to be combined.*/
+ op_sock_set_tcp_nodelay(_fd,1);
+ ret=op_http_conn_read_response(_conn,&_stream->response);
+ if(OP_UNLIKELY(ret<0))return ret;
+ next=op_http_parse_status_line(NULL,&status_code,_stream->response.buf);
+ /*According to RFC 2817, "Any successful (2xx) response to a
+ CONNECT request indicates that the proxy has established a
+ connection to the requested host and port.*/
+ if(OP_UNLIKELY(next==NULL)||OP_UNLIKELY(status_code[0]!='2'))return OP_FALSE;
+ return 0;
+}
+
+/*Match a host name against a host with a possible wildcard pattern according
+ to the rules of RFC 6125 Section 6.4.3.
+ Return: 0 if the pattern doesn't match, and a non-zero value if it does.*/
+static int op_http_hostname_match(const char *_host,size_t _host_len,
+ ASN1_STRING *_pattern){
+ const char *pattern;
+ size_t host_label_len;
+ size_t host_suffix_len;
+ size_t pattern_len;
+ size_t pattern_label_len;
+ size_t pattern_prefix_len;
+ size_t pattern_suffix_len;
+ pattern=(const char *)ASN1_STRING_data(_pattern);
+ pattern_len=strlen(pattern);
+ /*Check the pattern for embedded NULs.*/
+ if(OP_UNLIKELY(pattern_len!=(size_t)ASN1_STRING_length(_pattern)))return 0;
+ pattern_label_len=strcspn(pattern,".");
+ OP_ASSERT(pattern_label_len<=pattern_len);
+ pattern_prefix_len=strcspn(pattern,"*");
+ if(pattern_prefix_len>=pattern_label_len){
+ /*"The client SHOULD NOT attempt to match a presented identifier in which
+ the wildcard character comprises a label other than the left-most label
+ (e.g., do not match bar.*.example.net)." [RFC 6125 Section 6.4.3]*/
+ if(pattern_prefix_len<pattern_len)return 0;
+ /*If the pattern does not contain a wildcard in the first element, do an
+ exact match.
+ Don't use the system strcasecmp here, as that uses the locale and
+ RFC 4343 makes clear that DNS's case-insensitivity only applies to
+ the ASCII range.*/
+ return _host_len==pattern_len&&op_strncasecmp(_host,pattern,_host_len)==0;
+ }
+ /*"However, the client SHOULD NOT attempt to match a presented identifier
+ where the wildcard character is embedded within an A-label or U-label of
+ an internationalized domain name." [RFC 6125 Section 6.4.3]*/
+ if(op_strncasecmp(pattern,"xn--",4)==0)return 0;
+ host_label_len=strcspn(_host,".");
+ /*Make sure the host has at least two dots, to prevent the wildcard match
+ from being ridiculously wide.
+ We should have already checked to ensure it had at least one.*/
+ if(OP_UNLIKELY(_host[host_label_len]!='.')
+ ||strchr(_host+host_label_len+1,'.')==NULL){
+ return 0;
+ }
+ OP_ASSERT(host_label_len<_host_len);
+ /*"If the wildcard character is the only character of the left-most label in
+ the presented identifier, the client SHOULD NOT compare against anything
+ but the left-most label of the reference identifier (e.g., *.example.com
+ would match foo.example.com but not bar.foo.example.com)." [RFC 6125
+ Section 6.4.3]
+ This is really confusingly worded, as we check this by actually comparing
+ the rest of the pattern for an exact match.
+ We also use the fact that the wildcard must match at least one character,
+ so the left-most label of the hostname must be at least as large as the
+ left-most label of the pattern.*/
+ if(host_label_len<pattern_label_len)return 0;
+ OP_ASSERT(pattern[pattern_prefix_len]=='*');
+ /*"The client MAY match a presented identifier in which the wildcard
+ character is not the only character of the label (e.g., baz*.example.net
+ and *baz.example.net and b*z.example.net would be taken to match
+ baz1.example.net and foobaz.example.net and buzz.example.net,
+ respectively)." [RFC 6125 Section 6.4.3]*/
+ pattern_suffix_len=pattern_len-pattern_prefix_len-1;
+ host_suffix_len=_host_len-host_label_len
+ +pattern_label_len-pattern_prefix_len-1;
+ return pattern_suffix_len==host_suffix_len
+ &&op_strncasecmp(_host,pattern,pattern_prefix_len)==0
+ &&op_strncasecmp(_host+_host_len-host_suffix_len,
+ pattern+pattern_prefix_len+1,host_suffix_len)==0;
+}
+
+/*Convert a host to a numeric address, if possible.
+ Return: A struct addrinfo containing the address, if it was numeric, and NULL
+ otherise.*/
+static struct addrinfo *op_inet_pton(const char *_host){
+ struct addrinfo *addrs;
+ struct addrinfo hints;
+ memset(&hints,0,sizeof(hints));
+ hints.ai_socktype=SOCK_STREAM;
+ hints.ai_flags=AI_NUMERICHOST;
+ if(!getaddrinfo(_host,NULL,&hints,&addrs))return addrs;
+ return NULL;
+}
+
+/*Verify the server's hostname matches the certificate they presented using
+ the procedure from Section 6 of RFC 6125.
+ Return: 0 if the certificate doesn't match, and a non-zero value if it does.*/
+static int op_http_verify_hostname(OpusHTTPStream *_stream,SSL *_ssl_conn){
+ X509 *peer_cert;
+ STACK_OF(GENERAL_NAME) *san_names;
+ char *host;
+ size_t host_len;
+ int ret;
+ host=_stream->url.host;
+ host_len=strlen(host);
+ peer_cert=SSL_get_peer_certificate(_ssl_conn);
+ /*We set VERIFY_PEER, so we shouldn't get here without a certificate.*/
+ if(OP_UNLIKELY(peer_cert==NULL))return 0;
+ ret=0;
+ OP_ASSERT(host_len<INT_MAX);
+ /*RFC 2818 says (after correcting for Eratta 1077): "If a subjectAltName
+ extension of type dNSName is present, that MUST be used as the identity.
+ Otherwise, the (most specific) Common Name field in the Subject field of
+ the certificate MUST be used.
+ Although the use of the Common Name is existing practice, it is deprecated
+ and Certification Authorities are encouraged to use the dNSName
+ instead."
+ "Matching is performed using the matching rules specified by RFC 2459.
+ If more than one identity of a given type is present in the certificate
+ (e.g., more than one dNSName name), a match in any one of the set is
+ considered acceptable.
+ Names may contain the wildcard character * which is condered to match any
+ single domain name component or component fragment.
+ E.g., *.a.com matches foo.a.com but not bar.foo.a.com.
+ f*.com matches foo.com but not bar.com."
+ "In some cases, the URI is specified as an IP address rather than a
+ hostname.
+ In this case, the iPAddress subjectAltName must be present in the
+ certificate and must exactly match the IP in the URI."*/
+ san_names=X509_get_ext_d2i(peer_cert,NID_subject_alt_name,NULL,NULL);
+ if(san_names!=NULL){
+ struct addrinfo *addr;
+ unsigned char *ip;
+ int ip_len;
+ int nsan_names;
+ int sni;
+ /*Check to see if the host was specified as a simple IP address.*/
+ addr=op_inet_pton(host);
+ ip=NULL;
+ ip_len=0;
+ if(addr!=NULL){
+ switch(addr->ai_family){
+ case AF_INET:{
+ struct sockaddr_in *s;
+ s=(struct sockaddr_in *)addr->ai_addr;
+ OP_ASSERT(addr->ai_addrlen>=sizeof(*s));
+ ip=(unsigned char *)&s->sin_addr;
+ ip_len=sizeof(s->sin_addr);
+ }break;
+ case AF_INET6:{
+ struct sockaddr_in6 *s;
+ s=(struct sockaddr_in6 *)addr->ai_addr;
+ OP_ASSERT(addr->ai_addrlen>=sizeof(*s));
+ ip=(unsigned char *)&s->sin6_addr;
+ ip_len=sizeof(s->sin6_addr);
+ }break;
+ }
+ }
+ /*We can only verify fully-qualified domain names.
+ To quote RFC 6125: "The extracted data MUST include only information that
+ can be securely parsed out of the inputs (e.g., parsing the fully
+ qualified DNS domain name out of the "host" component (or its
+ equivalent) of a URI or deriving the application service type from the
+ scheme of a URI) ..."
+ We don't have a way to check (without relying on DNS records, which might
+ be subverted) if this address is fully-qualified.
+ This is particularly problematic when using a CONNECT tunnel, as it is
+ the server that does DNS lookup, not us.
+ However, we are certain that if the hostname has no '.', it is definitely
+ not a fully-qualified domain name (with the exception of crazy TLDs that
+ actually resolve, like "uz", but I am willing to ignore those).
+ RFC 1535 says "...in any event where a '.' exists in a specified name it
+ should be assumed to be a fully qualified domain name (FQDN) and SHOULD
+ be tried as a rooted name first."
+ That doesn't give us any security guarantees, of course (a subverted DNS
+ could fail the original query and our resolver might still retry with a
+ local domain appended).
+ If we don't have a FQDN, just set the number of names to 0, so we'll fail
+ and clean up any resources we allocated.*/
+ if(ip==NULL&&strchr(host,'.')==NULL)nsan_names=0;
+ /*RFC 2459 says there MUST be at least one, but we don't depend on it.*/
+ else nsan_names=sk_GENERAL_NAME_num(san_names);
+ for(sni=0;sni<nsan_names;sni++){
+ const GENERAL_NAME *name;
+ name=sk_GENERAL_NAME_value(san_names,sni);
+ if(ip==NULL){
+ if(name->type==GEN_DNS
+ &&op_http_hostname_match(host,host_len,name->d.dNSName)){
+ ret=1;
+ break;
+ }
+ }
+ else if(name->type==GEN_IPADD){
+ unsigned char *cert_ip;
+ /*If we do have an IP address, compare it directly.
+ RFC 6125: "When the reference identity is an IP address, the identity
+ MUST be converted to the 'network byte order' octet string
+ representation.
+ For IP Version 4, as specified in RFC 791, the octet string will
+ contain exactly four octets.
+ For IP Version 6, as specified in RFC 2460, the octet string will
+ contain exactly sixteen octets.
+ This octet string is then compared against subjectAltName values of
+ type iPAddress.
+ A match occurs if the reference identity octet string and the value
+ octet strings are identical."*/
+ cert_ip=ASN1_STRING_data(name->d.iPAddress);
+ if(ip_len==ASN1_STRING_length(name->d.iPAddress)
+ &&memcmp(ip,cert_ip,ip_len)==0){
+ ret=1;
+ break;
+ }
+ }
+ }
+ sk_GENERAL_NAME_pop_free(san_names,GENERAL_NAME_free);
+ if(addr!=NULL)freeaddrinfo(addr);
+ }
+ /*Do the same FQDN check we did above.
+ We don't do this once in advance for both cases, because in the
+ subjectAltName case we might have an IPv6 address without a dot.*/
+ else if(strchr(host,'.')!=NULL){
+ int last_cn_loc;
+ int cn_loc;
+ /*If there is no subjectAltName, match against commonName.
+ RFC 6125 says that at least one significant CA is known to issue certs
+ with multiple CNs, although it SHOULD NOT.
+ It also says: "The server's identity may also be verified by comparing
+ the reference identity to the Common Name (CN) value in the last
+ Relative Distinguished Name (RDN) of the subject field of the server's
+ certificate (where "last" refers to the DER-encoded order...)."
+ So find the last one and check it.*/
+ cn_loc=-1;
+ do{
+ last_cn_loc=cn_loc;
+ cn_loc=X509_NAME_get_index_by_NID(X509_get_subject_name(peer_cert),
+ NID_commonName,last_cn_loc);
+ }
+ while(cn_loc>=0);
+ ret=last_cn_loc>=0
+ &&op_http_hostname_match(host,host_len,
+ X509_NAME_ENTRY_get_data(
+ X509_NAME_get_entry(X509_get_subject_name(peer_cert),last_cn_loc)));
+ }
+ X509_free(peer_cert);
+ return ret;
+}
+
+/*Perform the TLS handshake on a new connection.*/
+static int op_http_conn_start_tls(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
+ op_sock _fd,SSL *_ssl_conn){
+ SSL_SESSION *ssl_session;
+ BIO *ssl_bio;
+ int skip_certificate_check;
+ int ret;
+ ssl_bio=BIO_new_socket(_fd,BIO_NOCLOSE);
+ if(OP_LIKELY(ssl_bio==NULL))return OP_FALSE;
+# if !defined(OPENSSL_NO_TLSEXT)
+ /*Support for RFC 6066 Server Name Indication.*/
+ SSL_set_tlsext_host_name(_ssl_conn,_stream->url.host);
+# endif
+ /*Resume a previous session if available.*/
+ if(_stream->ssl_session!=NULL){
+ SSL_set_session(_ssl_conn,_stream->ssl_session);
+ }
+ /*If we're proxying, establish the CONNECT tunnel.*/
+ if(_stream->proxy_connect.nbuf>0){
+ ret=op_http_conn_establish_tunnel(_stream,_conn,
+ _fd,_ssl_conn,ssl_bio);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ else{
+ /*Otherwise, just use this socket directly.*/
+ op_sock_set_tcp_nodelay(_fd,1);
+ SSL_set_bio(_ssl_conn,ssl_bio,ssl_bio);
+ SSL_set_connect_state(_ssl_conn);
+ }
+ ret=op_do_ssl_step(_ssl_conn,_fd,SSL_connect);
+ if(OP_UNLIKELY(ret<=0))return OP_FALSE;
+ ssl_session=_stream->ssl_session;
+ skip_certificate_check=_stream->skip_certificate_check;
+ if(ssl_session==NULL||!skip_certificate_check){
+ ret=op_do_ssl_step(_ssl_conn,_fd,SSL_do_handshake);
+ if(OP_UNLIKELY(ret<=0))return OP_FALSE;
+ /*OpenSSL does not do hostname verification, despite the fact that we just
+ passed it the hostname above in the call to SSL_set_tlsext_host_name(),
+ because they are morons.
+ Do it for them.*/
+ if(!skip_certificate_check&&!op_http_verify_hostname(_stream,_ssl_conn)){
+ return OP_FALSE;
+ }
+ if(ssl_session==NULL){
+ /*Save the session for later resumption.*/
+ _stream->ssl_session=SSL_get1_session(_ssl_conn);
+ }
+ }
+ _conn->ssl_conn=_ssl_conn;
+ _conn->fd=_fd;
+ _conn->nrequests_left=OP_PIPELINE_MAX_REQUESTS;
+ return 0;
+}
+
+/*Try to start a connection to the next address in the given list of a given
+ type.
+ _fd: The socket to connect with.
+ [inout] _addr: A pointer to the list of addresses.
+ This will be advanced to the first one that matches the given
+ address family (possibly the current one).
+ _ai_family: The address family to connect to.
+ Return: 1 If the connection was successful.
+ 0 If the connection is in progress.
+ OP_FALSE If the connection failed and there were no more addresses
+ left to try.
+ *_addr will be set to NULL in this case.*/
+static int op_sock_connect_next(op_sock _fd,
+ const struct addrinfo **_addr,int _ai_family){
+ const struct addrinfo *addr;
+ int err;
+ addr=*_addr;
+ for(;;){
+ /*Move to the next address of the requested type.*/
+ for(;addr!=NULL&&addr->ai_family!=_ai_family;addr=addr->ai_next);
+ *_addr=addr;
+ /*No more: failure.*/
+ if(addr==NULL)return OP_FALSE;
+ if(connect(_fd,addr->ai_addr,addr->ai_addrlen)>=0)return 1;
+ err=op_errno();
+ /*Winsock will set WSAEWOULDBLOCK.*/
+ if(OP_LIKELY(err==EINPROGRESS||err==EWOULDBLOCK))return 0;
+ addr=addr->ai_next;
+ }
+}
+
+/*The number of address families to try connecting to simultaneously.*/
+# define OP_NPROTOS (2)
+
+static int op_http_connect_impl(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
+ const struct addrinfo *_addrs,struct timeb *_start_time){
+ const struct addrinfo *addr;
+ const struct addrinfo *addrs[OP_NPROTOS];
+ struct pollfd fds[OP_NPROTOS];
+ int ai_family;
+ int nprotos;
+ int ret;
+ int pi;
+ int pj;
+ for(pi=0;pi<OP_NPROTOS;pi++)addrs[pi]=NULL;
+ /*Try connecting via both IPv4 and IPv6 simultaneously, and keep the first
+ one that succeeds.
+ Start by finding the first address from each family.
+ We order the first connection attempts in the same order the address
+ families were returned in the DNS records in accordance with RFC 6555.*/
+ for(addr=_addrs,nprotos=0;addr!=NULL&&nprotos<OP_NPROTOS;addr=addr->ai_next){
+ if(addr->ai_family==AF_INET6||addr->ai_family==AF_INET){
+ OP_ASSERT(addr->ai_addrlen<=sizeof(struct sockaddr_in6));
+ OP_ASSERT(addr->ai_addrlen<=sizeof(struct sockaddr_in));
+ /*If we've seen this address family before, skip this address for now.*/
+ for(pi=0;pi<nprotos;pi++)if(addrs[pi]->ai_family==addr->ai_family)break;
+ if(pi<nprotos)continue;
+ addrs[nprotos++]=addr;
+ }
+ }
+ /*Pop the connection off the free list and put it on the LRU list.*/
+ OP_ASSERT(_stream->free_head==_conn);
+ _stream->free_head=_conn->next;
+ _conn->next=_stream->lru_head;
+ _stream->lru_head=_conn;
+ ftime(_start_time);
+ *&_conn->read_time=*_start_time;
+ _conn->read_bytes=0;
+ _conn->read_rate=0;
+ /*Try to start a connection to each protocol.
+ RFC 6555 says it is RECOMMENDED that connection attempts be paced
+ 150...250 ms apart "to balance human factors against network load", but
+ that "stateful algorithms" (that's us) "are expected to be more
+ aggressive".
+ We are definitely more aggressive: we don't pace at all.*/
+ for(pi=0;pi<nprotos;pi++){
+ ai_family=addrs[pi]->ai_family;
+ fds[pi].fd=socket(ai_family,SOCK_STREAM,addrs[pi]->ai_protocol);
+ fds[pi].events=POLLOUT;
+ if(OP_LIKELY(fds[pi].fd!=OP_INVALID_SOCKET)){
+ if(OP_LIKELY(op_sock_set_nonblocking(fds[pi].fd,1)>=0)){
+ ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family);
+ if(OP_UNLIKELY(ret>0)){
+ /*It succeeded right away (technically possible), so stop.*/
+ nprotos=pi+1;
+ break;
+ }
+ /*Otherwise go on to the next protocol, and skip the clean-up below.*/
+ else if(ret==0)continue;
+ /*Tried all the addresses for this protocol.*/
+ }
+ /*Clean up the socket.*/
+ close(fds[pi].fd);
+ }
+ /*Remove this protocol from the list.*/
+ memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1));
+ nprotos--;
+ pi--;
+ }
+ /*Wait for one of the connections to finish.*/
+ while(pi>=nprotos&&nprotos>0&&poll(fds,nprotos,OP_POLL_TIMEOUT_MS)>0){
+ for(pi=0;pi<nprotos;pi++){
+ socklen_t errlen;
+ int err;
+ /*Still waiting...*/
+ if(!fds[pi].revents)continue;
+ errlen=sizeof(err);
+ /*Some platforms will return the pending error in &err and return 0.
+ Others will put it in errno and return -1.*/
+ ret=getsockopt(fds[pi].fd,SOL_SOCKET,SO_ERROR,&err,&errlen);
+ if(ret<0)err=op_errno();
+ /*Success!*/
+ if(err==0||err==EISCONN)break;
+ /*Move on to the next address for this protocol.*/
+ ai_family=addrs[pi]->ai_family;
+ addrs[pi]=addrs[pi]->ai_next;
+ ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family);
+ /*It succeeded right away, so stop.*/
+ if(ret>0)break;
+ /*Otherwise go on to the next protocol, and skip the clean-up below.*/
+ else if(ret==0)continue;
+ /*Tried all the addresses for this protocol.
+ Remove it from the list.*/
+ close(fds[pi].fd);
+ memmove(fds+pi,fds+pi+1,sizeof(*fds)*(nprotos-pi-1));
+ memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1));
+ nprotos--;
+ pi--;
+ }
+ }
+ /*Close all the other sockets.*/
+ for(pj=0;pj<nprotos;pj++)if(pi!=pj)close(fds[pj].fd);
+ /*If none of them succeeded, we're done.*/
+ if(pi>=nprotos)return OP_FALSE;
+ /*Save this address for future connection attempts.*/
+ if(addrs[pi]!=&_stream->addr_info){
+ memcpy(&_stream->addr_info,addrs[pi],sizeof(_stream->addr_info));
+ _stream->addr_info.ai_addr=&_stream->addr.s;
+ _stream->addr_info.ai_next=NULL;
+ memcpy(&_stream->addr,addrs[pi]->ai_addr,addrs[pi]->ai_addrlen);
+ }
+ if(OP_URL_IS_SSL(&_stream->url)){
+ SSL *ssl_conn;
+ /*Start the SSL connection.*/
+ OP_ASSERT(_stream->ssl_ctx!=NULL);
+ ssl_conn=SSL_new(_stream->ssl_ctx);
+ if(OP_LIKELY(ssl_conn!=NULL)){
+ ret=op_http_conn_start_tls(_stream,_conn,fds[pi].fd,ssl_conn);
+ if(OP_LIKELY(ret>=0))return ret;
+ SSL_free(ssl_conn);
+ }
+ close(fds[pi].fd);
+ _conn->fd=OP_INVALID_SOCKET;
+ return OP_FALSE;
+ }
+ /*Just a normal non-SSL connection.*/
+ _conn->ssl_conn=NULL;
+ _conn->fd=fds[pi].fd;
+ _conn->nrequests_left=OP_PIPELINE_MAX_REQUESTS;
+ /*Disable write coalescing.
+ We always send whole requests at once and always parse the response headers
+ before sending another one.*/
+ op_sock_set_tcp_nodelay(fds[pi].fd,1);
+ return 0;
+}
+
+static int op_http_connect(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
+ const struct addrinfo *_addrs,struct timeb *_start_time){
+ struct timeb resolve_time;
+ struct addrinfo *new_addrs;
+ int ret;
+ /*Re-resolve the host if we need to (RFC 6555 says we MUST do so
+ occasionally).*/
+ new_addrs=NULL;
+ ftime(&resolve_time);
+ if(_addrs!=&_stream->addr_info||op_time_diff_ms(&resolve_time,
+ &_stream->resolve_time)>=OP_RESOLVE_CACHE_TIMEOUT_MS){
+ new_addrs=op_resolve(_stream->connect_host,_stream->connect_port);
+ if(OP_LIKELY(new_addrs!=NULL)){
+ _addrs=new_addrs;
+ *&_stream->resolve_time=*&resolve_time;
+ }
+ else if(OP_LIKELY(_addrs==NULL))return OP_FALSE;
+ }
+ ret=op_http_connect_impl(_stream,_conn,_addrs,_start_time);
+ if(new_addrs!=NULL)freeaddrinfo(new_addrs);
+ return ret;
+}
+
+# define OP_BASE64_LENGTH(_len) (((_len)+2)/3*4)
+
+static const char BASE64_TABLE[64]={
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
+};
+
+static char *op_base64_encode(char *_dst,const char *_src,int _len){
+ unsigned s0;
+ unsigned s1;
+ unsigned s2;
+ int ngroups;
+ int i;
+ ngroups=_len/3;
+ for(i=0;i<ngroups;i++){
+ s0=_src[3*i+0];
+ s1=_src[3*i+1];
+ s2=_src[3*i+2];
+ _dst[4*i+0]=BASE64_TABLE[s0>>2];
+ _dst[4*i+1]=BASE64_TABLE[(s0&3)<<4|s1>>4];
+ _dst[4*i+2]=BASE64_TABLE[(s1&15)<<2|s2>>6];
+ _dst[4*i+3]=BASE64_TABLE[s2&63];
+ }
+ _len-=3*i;
+ if(_len==1){
+ s0=_src[3*i+0];
+ _dst[4*i+0]=BASE64_TABLE[s0>>2];
+ _dst[4*i+1]=BASE64_TABLE[(s0&3)<<4];
+ _dst[4*i+2]='=';
+ _dst[4*i+3]='=';
+ i++;
+ }
+ else if(_len==2){
+ s0=_src[3*i+0];
+ s1=_src[3*i+1];
+ _dst[4*i+0]=BASE64_TABLE[s0>>2];
+ _dst[4*i+1]=BASE64_TABLE[(s0&3)<<4|s1>>4];
+ _dst[4*i+2]=BASE64_TABLE[(s1&15)<<2];
+ _dst[4*i+3]='=';
+ i++;
+ }
+ _dst[4*i]='\0';
+ return _dst+4*i;
+}
+
+/*Construct an HTTP authorization header using RFC 2617's Basic Authentication
+ Scheme and append it to the given string buffer.*/
+static int op_sb_append_basic_auth_header(OpusStringBuf *_sb,
+ const char *_header,const char *_user,const char *_pass){
+ int user_len;
+ int pass_len;
+ int user_pass_len;
+ int base64_len;
+ int nbuf_total;
+ int ret;
+ ret=op_sb_append_string(_sb,_header);
+ ret|=op_sb_append(_sb,": Basic ",8);
+ user_len=strlen(_user);
+ pass_len=strlen(_pass);
+ if(OP_UNLIKELY(pass_len>INT_MAX-user_len))return OP_EFAULT;
+ if(OP_UNLIKELY(user_len+pass_len>(INT_MAX>>2)*3-3))return OP_EFAULT;
+ user_pass_len=user_len+1+pass_len;
+ base64_len=OP_BASE64_LENGTH(user_pass_len);
+ /*Stick "user:pass" at the end of the buffer so we can Base64 encode it
+ in-place.*/
+ nbuf_total=_sb->nbuf;
+ if(OP_UNLIKELY(base64_len>INT_MAX-nbuf_total))return OP_EFAULT;
+ nbuf_total+=base64_len;
+ ret|=op_sb_ensure_capacity(_sb,nbuf_total);
+ if(OP_UNLIKELY(ret<0))return ret;
+ _sb->nbuf=nbuf_total-user_pass_len;
+ OP_ALWAYS_TRUE(!op_sb_append(_sb,_user,user_len));
+ OP_ALWAYS_TRUE(!op_sb_append(_sb,":",1));
+ OP_ALWAYS_TRUE(!op_sb_append(_sb,_pass,pass_len));
+ op_base64_encode(_sb->buf+nbuf_total-base64_len,
+ _sb->buf+nbuf_total-user_pass_len,user_pass_len);
+ return op_sb_append(_sb,"\r\n",2);
+}
+
+static int op_http_allow_pipelining(const char *_server){
+ /*Servers known to do bad things with pipelined requests.
+ This list is taken from Gecko's nsHttpConnection::SupportsPipelining() (in
+ netwerk/protocol/http/nsHttpConnection.cpp).*/
+ static const char *BAD_SERVERS[]={
+ "EFAServer/",
+ "Microsoft-IIS/4.",
+ "Microsoft-IIS/5.",
+ "Netscape-Enterprise/3.",
+ "Netscape-Enterprise/4.",
+ "Netscape-Enterprise/5.",
+ "Netscape-Enterprise/6.",
+ "WebLogic 3.",
+ "WebLogic 4.",
+ "WebLogic 5.",
+ "WebLogic 6.",
+ "Winstone Servlet Engine v0."
+ };
+# define NBAD_SERVERS ((int)(sizeof(BAD_SERVERS)/sizeof(*BAD_SERVERS)))
+ if(*_server>='E'&&*_server<='W'){
+ int si;
+ for(si=0;si<NBAD_SERVERS;si++){
+ if(strncmp(_server,BAD_SERVERS[si],strlen(BAD_SERVERS[si]))==0){
+ return 0;
+ }
+ }
+ }
+ return 1;
+# undef NBAD_SERVERS
+}
+
+static int op_http_stream_open(OpusHTTPStream *_stream,const char *_url,
+ int _skip_certificate_check,const char *_proxy_host,unsigned _proxy_port,
+ const char *_proxy_user,const char *_proxy_pass,OpusServerInfo *_info){
+ struct addrinfo *addrs;
+ int nredirs;
+ int ret;
+#if defined(_WIN32)
+ op_init_winsock();
+#endif
+ ret=op_parse_url(&_stream->url,_url);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(_proxy_host!=NULL){
+ if(OP_UNLIKELY(_proxy_port>65535U))return OP_EINVAL;
+ _stream->connect_host=op_string_dup(_proxy_host);
+ _stream->connect_port=_proxy_port;
+ }
+ else{
+ _stream->connect_host=_stream->url.host;
+ _stream->connect_port=_stream->url.port;
+ }
+ addrs=NULL;
+ for(nredirs=0;nredirs<OP_REDIRECT_LIMIT;nredirs++){
+ OpusParsedURL next_url;
+ struct timeb start_time;
+ struct timeb end_time;
+ char *next;
+ char *status_code;
+ int minor_version_pos;
+ int v1_1_compat;
+ /*Initialize the SSL library if necessary.*/
+ if(OP_URL_IS_SSL(&_stream->url)&&_stream->ssl_ctx==NULL){
+ SSL_CTX *ssl_ctx;
+# if OPENSSL_VERSION_NUMBER<0x10100000L
+# if !defined(OPENSSL_NO_LOCKING)
+ /*The documentation says SSL_library_init() is not reentrant.
+ We don't want to add our own depenencies on a threading library, and it
+ appears that it's safe to call OpenSSL's locking functions before the
+ library is initialized, so that's what we'll do (really OpenSSL should
+ do this for us).
+ This doesn't guarantee that _other_ threads in the application aren't
+ calling SSL_library_init() at the same time, but there's not much we
+ can do about that.*/
+ CRYPTO_w_lock(CRYPTO_LOCK_SSL);
+# endif
+ SSL_library_init();
+ /*Needed to get SHA2 algorithms with old OpenSSL versions.*/
+ OpenSSL_add_ssl_algorithms();
+# if !defined(OPENSSL_NO_LOCKING)
+ CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
+# endif
+# else
+ /*Finally, OpenSSL does this for us, but as penance, it can now fail.*/
+ if(!OPENSSL_init_ssl(0,NULL))return OP_EFAULT;
+# endif
+ ssl_ctx=SSL_CTX_new(SSLv23_client_method());
+ if(ssl_ctx==NULL)return OP_EFAULT;
+ if(!_skip_certificate_check){
+ /*We don't do anything if this fails, since it just means we won't load
+ any certificates (and thus all checks will fail).
+ However, as that is probably the result of a system
+ mis-configuration, assert here to make it easier to identify.*/
+ OP_ALWAYS_TRUE(SSL_CTX_set_default_verify_paths(ssl_ctx));
+ SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL);
+ }
+ _stream->ssl_ctx=ssl_ctx;
+ _stream->skip_certificate_check=_skip_certificate_check;
+ if(_proxy_host!=NULL){
+ /*We need to establish a CONNECT tunnel to handle https proxying.
+ Build the request we'll send to do so.*/
+ _stream->proxy_connect.nbuf=0;
+ ret=op_sb_append(&_stream->proxy_connect,"CONNECT ",8);
+ ret|=op_sb_append_string(&_stream->proxy_connect,_stream->url.host);
+ ret|=op_sb_append_port(&_stream->proxy_connect,_stream->url.port);
+ /*CONNECT requires at least HTTP 1.1.*/
+ ret|=op_sb_append(&_stream->proxy_connect," HTTP/1.1\r\n",11);
+ ret|=op_sb_append(&_stream->proxy_connect,"Host: ",6);
+ ret|=op_sb_append_string(&_stream->proxy_connect,_stream->url.host);
+ /*The example in RFC 2817 Section 5.2 specifies an explicit port even
+ when connecting to the default port.
+ Given that the proxy doesn't know whether we're trying to connect to
+ an http or an https URL except by the port number, this seems like a
+ good idea.*/
+ ret|=op_sb_append_port(&_stream->proxy_connect,_stream->url.port);
+ ret|=op_sb_append(&_stream->proxy_connect,"\r\n",2);
+ ret|=op_sb_append(&_stream->proxy_connect,"User-Agent: .\r\n",15);
+ if(_proxy_user!=NULL&&_proxy_pass!=NULL){
+ ret|=op_sb_append_basic_auth_header(&_stream->proxy_connect,
+ "Proxy-Authorization",_proxy_user,_proxy_pass);
+ }
+ /*For backwards compatibility.*/
+ ret|=op_sb_append(&_stream->proxy_connect,
+ "Proxy-Connection: keep-alive\r\n",30);
+ ret|=op_sb_append(&_stream->proxy_connect,"\r\n",2);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ }
+ /*Actually make the connection.*/
+ ret=op_http_connect(_stream,_stream->conns+0,addrs,&start_time);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*Build the request to send.*/
+ _stream->request.nbuf=0;
+ ret=op_sb_append(&_stream->request,"GET ",4);
+ ret|=op_sb_append_string(&_stream->request,
+ _proxy_host!=NULL?_url:_stream->url.path);
+ /*Send HTTP/1.0 by default for maximum compatibility (so we don't have to
+ re-try if HTTP/1.1 fails, though it shouldn't, even for a 1.0 server).
+ This means we aren't conditionally compliant with RFC 2145, because we
+ violate the requirement that "An HTTP client SHOULD send a request
+ version equal to the highest version for which the client is at least
+ conditionally compliant...".
+ According to RFC 2145, that means we can't claim any compliance with any
+ IETF HTTP specification.*/
+ ret|=op_sb_append(&_stream->request," HTTP/1.0\r\n",11);
+ /*Remember where this is so we can upgrade to HTTP/1.1 if the server
+ supports it.*/
+ minor_version_pos=_stream->request.nbuf-3;
+ ret|=op_sb_append(&_stream->request,"Host: ",6);
+ ret|=op_sb_append_string(&_stream->request,_stream->url.host);
+ if(!OP_URL_IS_DEFAULT_PORT(&_stream->url)){
+ ret|=op_sb_append_port(&_stream->request,_stream->url.port);
+ }
+ ret|=op_sb_append(&_stream->request,"\r\n",2);
+ /*User-Agents have been a bad idea, so send as little as possible.
+ RFC 2616 requires at least one token in the User-Agent, which must have
+ at least one character.*/
+ ret|=op_sb_append(&_stream->request,"User-Agent: .\r\n",15);
+ if(_proxy_host!=NULL&&!OP_URL_IS_SSL(&_stream->url)
+ &&_proxy_user!=NULL&&_proxy_pass!=NULL){
+ ret|=op_sb_append_basic_auth_header(&_stream->request,
+ "Proxy-Authorization",_proxy_user,_proxy_pass);
+ }
+ if(_stream->url.user!=NULL&&_stream->url.pass!=NULL){
+ ret|=op_sb_append_basic_auth_header(&_stream->request,
+ "Authorization",_stream->url.user,_stream->url.pass);
+ }
+ /*Always send a Referer [sic] header.
+ It's common to refuse to serve a resource unless one is present.
+ We just use the relative "/" URI to suggest we came from the same domain,
+ as this is the most common check.
+ This might violate RFC 2616's mandate that the field "MUST NOT be sent if
+ the Request-URI was obtained from a source that does not have its own
+ URI, such as input from the user keyboard," but we don't really have any
+ way to know.*/
+ /*TODO: Should we update this on redirects?*/
+ ret|=op_sb_append(&_stream->request,"Referer: /\r\n",12);
+ /*Always send a Range request header to find out if we're seekable.
+ This requires an HTTP/1.1 server to succeed, but we'll still get what we
+ want with an HTTP/1.0 server that ignores this request header.*/
+ ret|=op_sb_append(&_stream->request,"Range: bytes=0-\r\n",17);
+ /*Remember where this is so we can append offsets to it later.*/
+ _stream->request_tail=_stream->request.nbuf-4;
+ ret|=op_sb_append(&_stream->request,"\r\n",2);
+ if(OP_UNLIKELY(ret<0))return ret;
+ ret=op_http_conn_write_fully(_stream->conns+0,
+ _stream->request.buf,_stream->request.nbuf);
+ if(OP_UNLIKELY(ret<0))return ret;
+ ret=op_http_conn_read_response(_stream->conns+0,&_stream->response);
+ if(OP_UNLIKELY(ret<0))return ret;
+ ftime(&end_time);
+ next=op_http_parse_status_line(&v1_1_compat,&status_code,
+ _stream->response.buf);
+ if(OP_UNLIKELY(next==NULL))return OP_FALSE;
+ if(status_code[0]=='2'){
+ opus_int64 content_length;
+ opus_int64 range_length;
+ int pipeline_supported;
+ int pipeline_disabled;
+ /*We only understand 20x codes.*/
+ if(status_code[1]!='0')return OP_FALSE;
+ content_length=-1;
+ range_length=-1;
+ /*Pipelining must be explicitly enabled.*/
+ pipeline_supported=0;
+ pipeline_disabled=0;
+ for(;;){
+ char *header;
+ char *cdr;
+ ret=op_http_get_next_header(&header,&cdr,&next);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(header==NULL)break;
+ if(strcmp(header,"content-length")==0){
+ /*Two Content-Length headers?*/
+ if(OP_UNLIKELY(content_length>=0))return OP_FALSE;
+ content_length=op_http_parse_content_length(cdr);
+ if(OP_UNLIKELY(content_length<0))return (int)content_length;
+ /*Make sure the Content-Length and Content-Range headers match.*/
+ if(range_length>=0&&OP_UNLIKELY(content_length!=range_length)){
+ return OP_FALSE;
+ }
+ }
+ else if(strcmp(header,"content-range")==0){
+ opus_int64 range_first;
+ opus_int64 range_last;
+ /*Two Content-Range headers?*/
+ if(OP_UNLIKELY(range_length>=0))return OP_FALSE;
+ ret=op_http_parse_content_range(&range_first,&range_last,
+ &range_length,cdr);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*"A response with satus code 206 (Partial Content) MUST NOT
+ include a Content-Range field with a byte-range-resp-spec of
+ '*'."*/
+ if(status_code[2]=='6'
+ &&(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))){
+ return OP_FALSE;
+ }
+ /*We asked for the entire resource.*/
+ if(range_length>=0){
+ /*Quit if we didn't get it.*/
+ if(range_last>=0&&OP_UNLIKELY(range_last!=range_length-1)){
+ return OP_FALSE;
+ }
+ }
+ /*If there was no length, use the end of the range.*/
+ else if(range_last>=0)range_length=range_last+1;
+ /*Make sure the Content-Length and Content-Range headers match.*/
+ if(content_length>=0&&OP_UNLIKELY(content_length!=range_length)){
+ return OP_FALSE;
+ }
+ }
+ else if(strcmp(header,"connection")==0){
+ /*According to RFC 2616, if an HTTP/1.1 application does not support
+ pipelining, it "MUST include the 'close' connection option in
+ every message."
+ Therefore, if we receive one in the initial response, disable
+ pipelining entirely.
+ The server still might support it (e.g., we might just have hit the
+ request limit for a temporary child process), but if it doesn't
+ and we assume it does, every time we cross a chunk boundary we'll
+ error out and reconnect, adding lots of latency.*/
+ ret=op_http_parse_connection(cdr);
+ if(OP_UNLIKELY(ret<0))return ret;
+ pipeline_disabled|=ret;
+ }
+ else if(strcmp(header,"server")==0){
+ /*If we got a Server response header, and it wasn't from a known-bad
+ server, enable pipelining, as long as it's at least HTTP/1.1.
+ According to RFC 2145, the server is supposed to respond with the
+ highest minor version number it supports unless it is known or
+ suspected that we incorrectly implement the HTTP specification.
+ So it should send back at least HTTP/1.1, despite our HTTP/1.0
+ request.*/
+ pipeline_supported=v1_1_compat;
+ if(v1_1_compat)pipeline_disabled|=!op_http_allow_pipelining(cdr);
+ if(_info!=NULL&&_info->server==NULL)_info->server=op_string_dup(cdr);
+ }
+ /*Collect station information headers if the caller requested it.
+ If there's more than one copy of a header, the first one wins.*/
+ else if(_info!=NULL){
+ if(strcmp(header,"content-type")==0){
+ if(_info->content_type==NULL){
+ _info->content_type=op_string_dup(cdr);
+ }
+ }
+ else if(header[0]=='i'&&header[1]=='c'
+ &&(header[2]=='e'||header[2]=='y')&&header[3]=='-'){
+ if(strcmp(header+4,"name")==0){
+ if(_info->name==NULL)_info->name=op_string_dup(cdr);
+ }
+ else if(strcmp(header+4,"description")==0){
+ if(_info->description==NULL)_info->description=op_string_dup(cdr);
+ }
+ else if(strcmp(header+4,"genre")==0){
+ if(_info->genre==NULL)_info->genre=op_string_dup(cdr);
+ }
+ else if(strcmp(header+4,"url")==0){
+ if(_info->url==NULL)_info->url=op_string_dup(cdr);
+ }
+ else if(strcmp(header,"icy-br")==0
+ ||strcmp(header,"ice-bitrate")==0){
+ if(_info->bitrate_kbps<0){
+ opus_int64 bitrate_kbps;
+ /*Just re-using this function to parse a random unsigned
+ integer field.*/
+ bitrate_kbps=op_http_parse_content_length(cdr);
+ if(bitrate_kbps>=0&&bitrate_kbps<=OP_INT32_MAX){
+ _info->bitrate_kbps=(opus_int32)bitrate_kbps;
+ }
+ }
+ }
+ else if(strcmp(header,"icy-pub")==0
+ ||strcmp(header,"ice-public")==0){
+ if(_info->is_public<0&&(cdr[0]=='0'||cdr[0]=='1')&&cdr[1]=='\0'){
+ _info->is_public=cdr[0]-'0';
+ }
+ }
+ }
+ }
+ }
+ switch(status_code[2]){
+ /*200 OK*/
+ case '0':break;
+ /*203 Non-Authoritative Information*/
+ case '3':break;
+ /*204 No Content*/
+ case '4':{
+ if(content_length>=0&&OP_UNLIKELY(content_length!=0)){
+ return OP_FALSE;
+ }
+ }break;
+ /*206 Partial Content*/
+ case '6':{
+ /*No Content-Range header.*/
+ if(OP_UNLIKELY(range_length<0))return OP_FALSE;
+ content_length=range_length;
+ /*The server supports range requests for this resource.
+ We can seek.*/
+ _stream->seekable=1;
+ }break;
+ /*201 Created: the response "SHOULD include an entity containing a list
+ of resource characteristics and location(s)," but not an Opus file.
+ 202 Accepted: the response "SHOULD include an indication of request's
+ current status and either a pointer to a status monitor or some
+ estimate of when the user can expect the request to be fulfilled,"
+ but not an Opus file.
+ 205 Reset Content: this "MUST NOT include an entity," meaning no Opus
+ file.
+ 207...209 are not yet defined, so we don't know how to handle them.*/
+ default:return OP_FALSE;
+ }
+ _stream->content_length=content_length;
+ _stream->pipeline=pipeline_supported&&!pipeline_disabled;
+ /*Pipelining requires HTTP/1.1 persistent connections.*/
+ if(_stream->pipeline)_stream->request.buf[minor_version_pos]='1';
+ _stream->conns[0].pos=0;
+ _stream->conns[0].end_pos=_stream->seekable?content_length:-1;
+ _stream->conns[0].chunk_size=-1;
+ _stream->cur_conni=0;
+ _stream->connect_rate=op_time_diff_ms(&end_time,&start_time);
+ _stream->connect_rate=OP_MAX(_stream->connect_rate,1);
+ if(_info!=NULL)_info->is_ssl=OP_URL_IS_SSL(&_stream->url);
+ /*The URL has been successfully opened.*/
+ return 0;
+ }
+ /*Shouldn't get 1xx; 4xx and 5xx are both failures (and we don't retry).
+ Everything else is undefined.*/
+ else if(status_code[0]!='3')return OP_FALSE;
+ /*We have some form of redirect request.*/
+ /*We only understand 30x codes.*/
+ if(status_code[1]!='0')return OP_FALSE;
+ switch(status_code[2]){
+ /*300 Multiple Choices: "If the server has a preferred choice of
+ representation, it SHOULD include the specific URI for that
+ representation in the Location field," otherwise we'll fail.*/
+ case '0':
+ /*301 Moved Permanently*/
+ case '1':
+ /*302 Found*/
+ case '2':
+ /*307 Temporary Redirect*/
+ case '7':
+ /*308 Permanent Redirect (defined by draft-reschke-http-status-308-07).*/
+ case '8':break;
+ /*305 Use Proxy: "The Location field gives the URI of the proxy."
+ TODO: This shouldn't actually be that hard to do.*/
+ case '5':return OP_EIMPL;
+ /*303 See Other: "The new URI is not a substitute reference for the
+ originally requested resource."
+ 304 Not Modified: "The 304 response MUST NOT contain a message-body."
+ 306 (Unused)
+ 309 is not yet defined, so we don't know how to handle it.*/
+ default:return OP_FALSE;
+ }
+ _url=NULL;
+ for(;;){
+ char *header;
+ char *cdr;
+ ret=op_http_get_next_header(&header,&cdr,&next);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(header==NULL)break;
+ if(strcmp(header,"location")==0&&OP_LIKELY(_url==NULL))_url=cdr;
+ }
+ if(OP_UNLIKELY(_url==NULL))return OP_FALSE;
+ ret=op_parse_url(&next_url,_url);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(_proxy_host==NULL||_stream->ssl_session!=NULL){
+ if(strcmp(_stream->url.host,next_url.host)==0
+ &&_stream->url.port==next_url.port){
+ /*Try to skip re-resolve when connecting to the same host.*/
+ addrs=&_stream->addr_info;
+ }
+ else{
+ if(_stream->ssl_session!=NULL){
+ /*Forget any cached SSL session from the last host.*/
+ SSL_SESSION_free(_stream->ssl_session);
+ _stream->ssl_session=NULL;
+ }
+ }
+ }
+ if(_proxy_host==NULL){
+ OP_ASSERT(_stream->connect_host==_stream->url.host);
+ _stream->connect_host=next_url.host;
+ _stream->connect_port=next_url.port;
+ }
+ /*Always try to skip re-resolve for proxy connections.*/
+ else addrs=&_stream->addr_info;
+ op_parsed_url_clear(&_stream->url);
+ *&_stream->url=*&next_url;
+ /*TODO: On servers/proxies that support pipelining, we might be able to
+ re-use this connection.*/
+ op_http_conn_close(_stream,_stream->conns+0,&_stream->lru_head,1);
+ }
+ /*Redirection limit reached.*/
+ return OP_FALSE;
+}
+
+static int op_http_conn_send_request(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn,opus_int64 _pos,opus_int32 _chunk_size,
+ int _try_not_to_block){
+ opus_int64 next_end;
+ int ret;
+ /*We shouldn't have another request outstanding.*/
+ OP_ASSERT(_conn->next_pos<0);
+ /*Build the request to send.*/
+ OP_ASSERT(_stream->request.nbuf>=_stream->request_tail);
+ _stream->request.nbuf=_stream->request_tail;
+ ret=op_sb_append_nonnegative_int64(&_stream->request,_pos);
+ ret|=op_sb_append(&_stream->request,"-",1);
+ if(_chunk_size>0&&OP_ADV_OFFSET(_pos,2*_chunk_size)<_stream->content_length){
+ /*We shouldn't be pipelining requests with non-HTTP/1.1 servers.*/
+ OP_ASSERT(_stream->pipeline);
+ next_end=_pos+_chunk_size;
+ ret|=op_sb_append_nonnegative_int64(&_stream->request,next_end-1);
+ /*Use a larger chunk size for our next request.*/
+ _chunk_size<<=1;
+ /*But after a while, just request the rest of the resource.*/
+ if(_chunk_size>OP_PIPELINE_CHUNK_SIZE_MAX)_chunk_size=-1;
+ }
+ else{
+ /*Either this was a non-pipelined request or we were close enough to the
+ end to just ask for the rest.*/
+ next_end=-1;
+ _chunk_size=-1;
+ }
+ ret|=op_sb_append(&_stream->request,"\r\n\r\n",4);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*If we don't want to block, check to see if there's enough space in the send
+ queue.
+ There's still a chance we might block, even if there is enough space, but
+ it's a much slimmer one.
+ Blocking at all is pretty unlikely, as we won't have any requests queued
+ when _try_not_to_block is set, so if FIONSPACE isn't available (e.g., on
+ Linux), just skip the test.*/
+ if(_try_not_to_block){
+# if defined(FIONSPACE)
+ int available;
+ ret=ioctl(_conn->fd,FIONSPACE,&available);
+ if(ret<0||available<_stream->request.nbuf)return 1;
+# endif
+ }
+ ret=op_http_conn_write_fully(_conn,
+ _stream->request.buf,_stream->request.nbuf);
+ if(OP_UNLIKELY(ret<0))return ret;
+ _conn->next_pos=_pos;
+ _conn->next_end=next_end;
+ /*Save the chunk size to use for the next request.*/
+ _conn->chunk_size=_chunk_size;
+ _conn->nrequests_left--;
+ return ret;
+}
+
+/*Handles the response to all requests after the first one.
+ Return: 1 if the connection was closed or timed out, 0 on success, or a
+ negative value on any other error.*/
+static int op_http_conn_handle_response(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn){
+ char *next;
+ char *status_code;
+ opus_int64 range_length;
+ opus_int64 next_pos;
+ opus_int64 next_end;
+ int ret;
+ ret=op_http_conn_read_response(_conn,&_stream->response);
+ /*If the server just closed the connection on us, we may have just hit a
+ connection re-use limit, so we might want to retry.*/
+ if(OP_UNLIKELY(ret<0))return ret==OP_EREAD?1:ret;
+ next=op_http_parse_status_line(NULL,&status_code,_stream->response.buf);
+ if(OP_UNLIKELY(next==NULL))return OP_FALSE;
+ /*We _need_ a 206 Partial Content response.
+ Nothing else will do.*/
+ if(strncmp(status_code,"206",3)!=0){
+ /*But on a 408 Request Timeout, we might want to re-try.*/
+ return strncmp(status_code,"408",3)==0?1:OP_FALSE;
+ }
+ next_pos=_conn->next_pos;
+ next_end=_conn->next_end;
+ range_length=-1;
+ for(;;){
+ char *header;
+ char *cdr;
+ ret=op_http_get_next_header(&header,&cdr,&next);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(header==NULL)break;
+ if(strcmp(header,"content-range")==0){
+ opus_int64 range_first;
+ opus_int64 range_last;
+ /*Two Content-Range headers?*/
+ if(OP_UNLIKELY(range_length>=0))return OP_FALSE;
+ ret=op_http_parse_content_range(&range_first,&range_last,
+ &range_length,cdr);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*"A response with satus code 206 (Partial Content) MUST NOT
+ include a Content-Range field with a byte-range-resp-spec of
+ '*'."*/
+ if(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))return OP_FALSE;
+ /*We also don't want range_last to overflow.*/
+ if(OP_UNLIKELY(range_last>=OP_INT64_MAX))return OP_FALSE;
+ range_last++;
+ /*Quit if we didn't get the offset we asked for.*/
+ if(range_first!=next_pos)return OP_FALSE;
+ if(next_end<0){
+ /*We asked for the rest of the resource.*/
+ if(range_length>=0){
+ /*Quit if we didn't get it.*/
+ if(OP_UNLIKELY(range_last!=range_length))return OP_FALSE;
+ }
+ /*If there was no length, use the end of the range.*/
+ else range_length=range_last;
+ next_end=range_last;
+ }
+ else{
+ if(range_last!=next_end)return OP_FALSE;
+ /*If there was no length, use the larger of the content length or the
+ end of this chunk.*/
+ if(range_length<0){
+ range_length=OP_MAX(range_last,_stream->content_length);
+ }
+ }
+ }
+ else if(strcmp(header,"content-length")==0){
+ opus_int64 content_length;
+ /*Validate the Content-Length header, if present, against the request we
+ made.*/
+ content_length=op_http_parse_content_length(cdr);
+ if(OP_UNLIKELY(content_length<0))return (int)content_length;
+ if(next_end<0){
+ /*If we haven't seen the Content-Range header yet and we asked for the
+ rest of the resource, set next_end, so we can make sure they match
+ when we do find the Content-Range header.*/
+ if(OP_UNLIKELY(next_pos>OP_INT64_MAX-content_length))return OP_FALSE;
+ next_end=next_pos+content_length;
+ }
+ /*Otherwise, make sure they match now.*/
+ else if(OP_UNLIKELY(next_end-next_pos!=content_length))return OP_FALSE;
+ }
+ else if(strcmp(header,"connection")==0){
+ ret=op_http_parse_connection(cdr);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*If the server told us it was going to close the connection, don't make
+ any more requests.*/
+ if(OP_UNLIKELY(ret>0))_conn->nrequests_left=0;
+ }
+ }
+ /*No Content-Range header.*/
+ if(OP_UNLIKELY(range_length<0))return OP_FALSE;
+ /*Update the content_length if necessary.*/
+ _stream->content_length=range_length;
+ _conn->pos=next_pos;
+ _conn->end_pos=next_end;
+ _conn->next_pos=-1;
+ return 0;
+}
+
+/*Open a new connection that will start reading at byte offset _pos.
+ _pos: The byte offset to start reading from.
+ _chunk_size: The number of bytes to ask for in the initial request, or -1 to
+ request the rest of the resource.
+ This may be more bytes than remain, in which case it will be
+ converted into a request for the rest.*/
+static int op_http_conn_open_pos(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn,opus_int64 _pos,opus_int32 _chunk_size){
+ struct timeb start_time;
+ struct timeb end_time;
+ opus_int32 connect_rate;
+ opus_int32 connect_time;
+ int ret;
+ ret=op_http_connect(_stream,_conn,&_stream->addr_info,&start_time);
+ if(OP_UNLIKELY(ret<0))return ret;
+ ret=op_http_conn_send_request(_stream,_conn,_pos,_chunk_size,0);
+ if(OP_UNLIKELY(ret<0))return ret;
+ ret=op_http_conn_handle_response(_stream,_conn);
+ if(OP_UNLIKELY(ret!=0))return OP_FALSE;
+ ftime(&end_time);
+ _stream->cur_conni=_conn-_stream->conns;
+ OP_ASSERT(_stream->cur_conni>=0&&_stream->cur_conni<OP_NCONNS_MAX);
+ /*The connection has been successfully opened.
+ Update the connection time estimate.*/
+ connect_time=op_time_diff_ms(&end_time,&start_time);
+ connect_rate=_stream->connect_rate;
+ connect_rate+=OP_MAX(connect_time,1)-connect_rate+8>>4;
+ _stream->connect_rate=connect_rate;
+ return 0;
+}
+
+/*Read data from the current response body.
+ If we're pipelining and we get close to the end of this response, queue
+ another request.
+ If we've reached the end of this response body, parse the next response and
+ keep going.
+ [out] _buf: Returns the data read.
+ _buf_size: The size of the buffer.
+ Return: A positive number of bytes read on success.
+ 0: The connection was closed.
+ OP_EREAD: There was a fatal read error.*/
+static int op_http_conn_read_body(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn,unsigned char *_buf,int _buf_size){
+ opus_int64 pos;
+ opus_int64 end_pos;
+ opus_int64 next_pos;
+ opus_int64 content_length;
+ int nread;
+ int pipeline;
+ int ret;
+ /*Currently this function can only be called on the LRU head.
+ Otherwise, we'd need a _pnext pointer if we needed to close the connection,
+ and re-opening it would re-organize the lists.*/
+ OP_ASSERT(_stream->lru_head==_conn);
+ /*We should have filtered out empty reads by this point.*/
+ OP_ASSERT(_buf_size>0);
+ pos=_conn->pos;
+ end_pos=_conn->end_pos;
+ next_pos=_conn->next_pos;
+ pipeline=_stream->pipeline;
+ content_length=_stream->content_length;
+ if(end_pos>=0){
+ /*Have we reached the end of the current response body?*/
+ if(pos>=end_pos){
+ OP_ASSERT(content_length>=0);
+ /*If this was the end of the stream, we're done.
+ Also return early if a non-blocking read was requested (regardless of
+ whether we might be able to parse the next response without
+ blocking).*/
+ if(content_length<=end_pos)return 0;
+ /*Otherwise, start on the next response.*/
+ if(next_pos<0){
+ /*We haven't issued another request yet.*/
+ if(!pipeline||_conn->nrequests_left<=0){
+ /*There are two ways to get here: either the server told us it was
+ going to close the connection after the last request, or we
+ thought we were reading the whole resource, but it grew while we
+ were reading it.
+ The only way the latter could have happened is if content_length
+ changed while seeking.
+ Open a new request to read the rest.*/
+ OP_ASSERT(_stream->seekable);
+ /*Try to open a new connection to read another chunk.*/
+ op_http_conn_close(_stream,_conn,&_stream->lru_head,1);
+ /*If we're not pipelining, we should be requesting the rest.*/
+ OP_ASSERT(pipeline||_conn->chunk_size==-1);
+ ret=op_http_conn_open_pos(_stream,_conn,end_pos,_conn->chunk_size);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ }
+ else{
+ /*Issue the request now (better late than never).*/
+ ret=op_http_conn_send_request(_stream,_conn,pos,_conn->chunk_size,0);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ next_pos=_conn->next_pos;
+ OP_ASSERT(next_pos>=0);
+ }
+ }
+ if(next_pos>=0){
+ /*We shouldn't be trying to read past the current request body if we're
+ seeking somewhere else.*/
+ OP_ASSERT(next_pos==end_pos);
+ ret=op_http_conn_handle_response(_stream,_conn);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ if(OP_UNLIKELY(ret>0)&&pipeline){
+ opus_int64 next_end;
+ next_end=_conn->next_end;
+ /*Our request timed out or the server closed the connection.
+ Try re-connecting.*/
+ op_http_conn_close(_stream,_conn,&_stream->lru_head,1);
+ /*Unless there's a bug, we should be able to convert
+ (next_pos,next_end) into valid (_pos,_chunk_size) parameters.*/
+ OP_ASSERT(next_end<0
+ ||next_end-next_pos>=0&&next_end-next_pos<=OP_INT32_MAX);
+ ret=op_http_conn_open_pos(_stream,_conn,next_pos,
+ next_end<0?-1:(opus_int32)(next_end-next_pos));
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ }
+ else if(OP_UNLIKELY(ret!=0))return OP_EREAD;
+ }
+ pos=_conn->pos;
+ end_pos=_conn->end_pos;
+ content_length=_stream->content_length;
+ }
+ OP_ASSERT(end_pos>pos);
+ _buf_size=OP_MIN(_buf_size,end_pos-pos);
+ }
+ nread=op_http_conn_read(_conn,(char *)_buf,_buf_size,1);
+ if(OP_UNLIKELY(nread<0))return nread;
+ pos+=nread;
+ _conn->pos=pos;
+ OP_ASSERT(end_pos<0||content_length>=0);
+ /*TODO: If nrequests_left<=0, we can't make a new request, and there will be
+ a big pause after we hit the end of the chunk while we open a new
+ connection.
+ It would be nice to be able to start that process now, but we have no way
+ to do it in the background without blocking (even if we could start it, we
+ have no guarantee the application will return control to us in a
+ sufficiently timely manner to allow us to complete it, and this is
+ uncommon enough that it's not worth using threads just for this).*/
+ if(end_pos>=0&&end_pos<content_length&&next_pos<0
+ &&pipeline&&OP_LIKELY(_conn->nrequests_left>0)){
+ opus_int64 request_thresh;
+ opus_int32 chunk_size;
+ /*Are we getting close to the end of the current response body?
+ If so, we should request more data.*/
+ request_thresh=_stream->connect_rate*_conn->read_rate>>12;
+ /*But don't commit ourselves too quickly.*/
+ chunk_size=_conn->chunk_size;
+ if(chunk_size>=0)request_thresh=OP_MIN(chunk_size>>2,request_thresh);
+ if(end_pos-pos<request_thresh){
+ ret=op_http_conn_send_request(_stream,_conn,end_pos,_conn->chunk_size,1);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ }
+ }
+ return nread;
+}
+
+static int op_http_stream_read(void *_stream,
+ unsigned char *_ptr,int _buf_size){
+ OpusHTTPStream *stream;
+ ptrdiff_t nread;
+ opus_int64 size;
+ opus_int64 pos;
+ int ci;
+ stream=(OpusHTTPStream *)_stream;
+ /*Check for an empty read.*/
+ if(_buf_size<=0)return 0;
+ ci=stream->cur_conni;
+ /*No current connection => EOF.*/
+ if(ci<0)return 0;
+ pos=stream->conns[ci].pos;
+ size=stream->content_length;
+ /*Check for EOF.*/
+ if(size>=0){
+ if(pos>=size)return 0;
+ /*Check for a short read.*/
+ if(_buf_size>size-pos)_buf_size=(int)(size-pos);
+ }
+ nread=op_http_conn_read_body(stream,stream->conns+ci,_ptr,_buf_size);
+ if(OP_UNLIKELY(nread<=0)){
+ /*We hit an error or EOF.
+ Either way, we're done with this connection.*/
+ op_http_conn_close(stream,stream->conns+ci,&stream->lru_head,1);
+ stream->cur_conni=-1;
+ stream->pos=pos;
+ }
+ return nread;
+}
+
+/*Discard data until we reach the _target position.
+ This destroys the contents of _stream->response.buf, as we need somewhere to
+ read this data, and that is a convenient place.
+ _just_read_ahead: Whether or not this is a plain fast-forward.
+ If 0, we need to issue a new request for a chunk at _target
+ and discard all the data from our current request(s).
+ Otherwise, we should be able to reach _target without
+ issuing any new requests.
+ _target: The stream position to which to read ahead.*/
+static int op_http_conn_read_ahead(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn,int _just_read_ahead,opus_int64 _target){
+ opus_int64 pos;
+ opus_int64 end_pos;
+ opus_int64 next_pos;
+ opus_int64 next_end;
+ ptrdiff_t nread;
+ int ret;
+ pos=_conn->pos;
+ end_pos=_conn->end_pos;
+ next_pos=_conn->next_pos;
+ next_end=_conn->next_end;
+ if(!_just_read_ahead){
+ /*We need to issue a new pipelined request.
+ This is the only case where we allow more than one outstanding request
+ at a time, so we need to reset next_pos (we'll restore it below if we
+ did have an outstanding request).*/
+ OP_ASSERT(_stream->pipeline);
+ _conn->next_pos=-1;
+ ret=op_http_conn_send_request(_stream,_conn,_target,
+ OP_PIPELINE_CHUNK_SIZE,0);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ /*We can reach the target position by reading forward in the current chunk.*/
+ if(_just_read_ahead&&(end_pos<0||_target<end_pos))end_pos=_target;
+ else if(next_pos>=0){
+ opus_int64 next_next_pos;
+ opus_int64 next_next_end;
+ /*We already have a request outstanding.
+ Finish off the current chunk.*/
+ while(pos<end_pos){
+ nread=op_http_conn_read(_conn,_stream->response.buf,
+ (int)OP_MIN(end_pos-pos,_stream->response.cbuf),1);
+ /*We failed to read ahead.*/
+ if(nread<=0)return OP_FALSE;
+ pos+=nread;
+ }
+ OP_ASSERT(pos==end_pos);
+ if(_just_read_ahead){
+ next_next_pos=next_next_end=-1;
+ end_pos=_target;
+ }
+ else{
+ OP_ASSERT(_conn->next_pos==_target);
+ next_next_pos=_target;
+ next_next_end=_conn->next_end;
+ _conn->next_pos=next_pos;
+ _conn->next_end=next_end;
+ end_pos=next_end;
+ }
+ ret=op_http_conn_handle_response(_stream,_conn);
+ if(OP_UNLIKELY(ret!=0))return OP_FALSE;
+ _conn->next_pos=next_next_pos;
+ _conn->next_end=next_next_end;
+ }
+ while(pos<end_pos){
+ nread=op_http_conn_read(_conn,_stream->response.buf,
+ (int)OP_MIN(end_pos-pos,_stream->response.cbuf),1);
+ /*We failed to read ahead.*/
+ if(nread<=0)return OP_FALSE;
+ pos+=nread;
+ }
+ OP_ASSERT(pos==end_pos);
+ if(!_just_read_ahead){
+ ret=op_http_conn_handle_response(_stream,_conn);
+ if(OP_UNLIKELY(ret!=0))return OP_FALSE;
+ }
+ else _conn->pos=end_pos;
+ OP_ASSERT(_conn->pos==_target);
+ return 0;
+}
+
+static int op_http_stream_seek(void *_stream,opus_int64 _offset,int _whence){
+ struct timeb seek_time;
+ OpusHTTPStream *stream;
+ OpusHTTPConn *conn;
+ OpusHTTPConn **pnext;
+ OpusHTTPConn *close_conn;
+ OpusHTTPConn **close_pnext;
+ opus_int64 content_length;
+ opus_int64 pos;
+ int pipeline;
+ int ci;
+ int ret;
+ stream=(OpusHTTPStream *)_stream;
+ if(!stream->seekable)return -1;
+ content_length=stream->content_length;
+ /*If we're seekable, we should have gotten a Content-Length.*/
+ OP_ASSERT(content_length>=0);
+ ci=stream->cur_conni;
+ pos=ci<0?content_length:stream->conns[ci].pos;
+ switch(_whence){
+ case SEEK_SET:{
+ /*Check for overflow:*/
+ if(_offset<0)return -1;
+ pos=_offset;
+ }break;
+ case SEEK_CUR:{
+ /*Check for overflow:*/
+ if(_offset<-pos||_offset>OP_INT64_MAX-pos)return -1;
+ pos+=_offset;
+ }break;
+ case SEEK_END:{
+ /*Check for overflow:*/
+ if(_offset>content_length||_offset<content_length-OP_INT64_MAX)return -1;
+ pos=content_length-_offset;
+ }break;
+ default:return -1;
+ }
+ /*Mark when we deactivated the active connection.*/
+ if(ci>=0){
+ op_http_conn_read_rate_update(stream->conns+ci);
+ *&seek_time=*&stream->conns[ci].read_time;
+ }
+ else ftime(&seek_time);
+ /*If we seeked past the end of the stream, just disable the active
+ connection.*/
+ if(pos>=content_length){
+ stream->cur_conni=-1;
+ stream->pos=pos;
+ return 0;
+ }
+ /*First try to find a connection we can use without waiting.*/
+ pnext=&stream->lru_head;
+ conn=stream->lru_head;
+ while(conn!=NULL){
+ opus_int64 conn_pos;
+ opus_int64 end_pos;
+ int available;
+ /*If this connection has been dormant too long or has made too many
+ requests, close it.
+ This is to prevent us from hitting server limits/firewall timeouts.*/
+ if(op_time_diff_ms(&seek_time,&conn->read_time)>
+ OP_CONNECTION_IDLE_TIMEOUT_MS
+ ||conn->nrequests_left<OP_PIPELINE_MIN_REQUESTS){
+ op_http_conn_close(stream,conn,pnext,1);
+ conn=*pnext;
+ continue;
+ }
+ available=op_http_conn_estimate_available(conn);
+ conn_pos=conn->pos;
+ end_pos=conn->end_pos;
+ if(conn->next_pos>=0){
+ OP_ASSERT(end_pos>=0);
+ OP_ASSERT(conn->next_pos==end_pos);
+ end_pos=conn->next_end;
+ }
+ OP_ASSERT(end_pos<0||conn_pos<=end_pos);
+ /*Can we quickly read ahead without issuing a new request or waiting for
+ any more data?
+ If we have an oustanding request, we'll over-estimate the amount of data
+ it has available (because we'll count the response headers, too), but
+ that probably doesn't matter.*/
+ if(conn_pos<=pos&&pos-conn_pos<=available&&(end_pos<0||pos<end_pos)){
+ /*Found a suitable connection to re-use.*/
+ ret=op_http_conn_read_ahead(stream,conn,1,pos);
+ if(OP_UNLIKELY(ret<0)){
+ /*The connection might have become stale, so close it and keep going.*/
+ op_http_conn_close(stream,conn,pnext,1);
+ conn=*pnext;
+ continue;
+ }
+ /*Sucessfully resurrected this connection.*/
+ *pnext=conn->next;
+ conn->next=stream->lru_head;
+ stream->lru_head=conn;
+ stream->cur_conni=conn-stream->conns;
+ return 0;
+ }
+ pnext=&conn->next;
+ conn=conn->next;
+ }
+ /*Chances are that didn't work, so now try to find one we can use by reading
+ ahead a reasonable amount and/or by issuing a new request.*/
+ close_pnext=NULL;
+ close_conn=NULL;
+ pnext=&stream->lru_head;
+ conn=stream->lru_head;
+ pipeline=stream->pipeline;
+ while(conn!=NULL){
+ opus_int64 conn_pos;
+ opus_int64 end_pos;
+ opus_int64 read_ahead_thresh;
+ int available;
+ int just_read_ahead;
+ /*Dividing by 2048 instead of 1000 scales this by nearly 1/2, biasing away
+ from connection re-use (and roughly compensating for the lag required to
+ reopen the TCP window of a connection that's been idle).
+ There's no overflow checking here, because it's vanishingly unlikely, and
+ all it would do is cause us to make poor decisions.*/
+ read_ahead_thresh=OP_MAX(OP_READAHEAD_THRESH_MIN,
+ stream->connect_rate*conn->read_rate>>11);
+ available=op_http_conn_estimate_available(conn);
+ conn_pos=conn->pos;
+ end_pos=conn->end_pos;
+ if(conn->next_pos>=0){
+ OP_ASSERT(end_pos>=0);
+ OP_ASSERT(conn->next_pos==end_pos);
+ end_pos=conn->next_end;
+ }
+ OP_ASSERT(end_pos<0||conn_pos<=end_pos);
+ /*Can we quickly read ahead without issuing a new request?*/
+ just_read_ahead=conn_pos<=pos&&pos-conn_pos-available<=read_ahead_thresh
+ &&(end_pos<0||pos<end_pos);
+ if(just_read_ahead||pipeline&&end_pos>=0
+ &&end_pos-conn_pos-available<=read_ahead_thresh){
+ /*Found a suitable connection to re-use.*/
+ ret=op_http_conn_read_ahead(stream,conn,just_read_ahead,pos);
+ if(OP_UNLIKELY(ret<0)){
+ /*The connection might have become stale, so close it and keep going.*/
+ op_http_conn_close(stream,conn,pnext,1);
+ conn=*pnext;
+ continue;
+ }
+ /*Sucessfully resurrected this connection.*/
+ *pnext=conn->next;
+ conn->next=stream->lru_head;
+ stream->lru_head=conn;
+ stream->cur_conni=conn-stream->conns;
+ return 0;
+ }
+ close_pnext=pnext;
+ close_conn=conn;
+ pnext=&conn->next;
+ conn=conn->next;
+ }
+ /*No suitable connections.
+ Open a new one.*/
+ if(stream->free_head==NULL){
+ /*All connections in use.
+ Expire one of them (we should have already picked which one when scanning
+ the list).*/
+ OP_ASSERT(close_conn!=NULL);
+ OP_ASSERT(close_pnext!=NULL);
+ op_http_conn_close(stream,close_conn,close_pnext,1);
+ }
+ OP_ASSERT(stream->free_head!=NULL);
+ conn=stream->free_head;
+ /*If we can pipeline, only request a chunk of data.
+ If we're seeking now, there's a good chance we will want to seek again
+ soon, and this avoids committing this connection to reading the rest of
+ the stream.
+ Particularly with SSL or proxies, issuing a new request on the same
+ connection can be substantially faster than opening a new one.
+ This also limits the amount of data the server will blast at us on this
+ connection if we later seek elsewhere and start reading from a different
+ connection.*/
+ ret=op_http_conn_open_pos(stream,conn,pos,
+ pipeline?OP_PIPELINE_CHUNK_SIZE:-1);
+ if(OP_UNLIKELY(ret<0)){
+ op_http_conn_close(stream,conn,&stream->lru_head,1);
+ return -1;
+ }
+ return 0;
+}
+
+static opus_int64 op_http_stream_tell(void *_stream){
+ OpusHTTPStream *stream;
+ int ci;
+ stream=(OpusHTTPStream *)_stream;
+ ci=stream->cur_conni;
+ return ci<0?stream->pos:stream->conns[ci].pos;
+}
+
+static int op_http_stream_close(void *_stream){
+ OpusHTTPStream *stream;
+ stream=(OpusHTTPStream *)_stream;
+ if(OP_LIKELY(stream!=NULL)){
+ op_http_stream_clear(stream);
+ _ogg_free(stream);
+ }
+ return 0;
+}
+
+static const OpusFileCallbacks OP_HTTP_CALLBACKS={
+ op_http_stream_read,
+ op_http_stream_seek,
+ op_http_stream_tell,
+ op_http_stream_close
+};
+#endif
+
+void opus_server_info_init(OpusServerInfo *_info){
+ _info->name=NULL;
+ _info->description=NULL;
+ _info->genre=NULL;
+ _info->url=NULL;
+ _info->server=NULL;
+ _info->content_type=NULL;
+ _info->bitrate_kbps=-1;
+ _info->is_public=-1;
+ _info->is_ssl=0;
+}
+
+void opus_server_info_clear(OpusServerInfo *_info){
+ _ogg_free(_info->content_type);
+ _ogg_free(_info->server);
+ _ogg_free(_info->url);
+ _ogg_free(_info->genre);
+ _ogg_free(_info->description);
+ _ogg_free(_info->name);
+}
+
+/*The actual URL stream creation function.
+ This one isn't extensible like the application-level interface, but because
+ it isn't public, we're free to change it in the future.*/
+static void *op_url_stream_create_impl(OpusFileCallbacks *_cb,const char *_url,
+ int _skip_certificate_check,const char *_proxy_host,unsigned _proxy_port,
+ const char *_proxy_user,const char *_proxy_pass,OpusServerInfo *_info){
+ const char *path;
+ /*Check to see if this is a valid file: URL.*/
+ path=op_parse_file_url(_url);
+ if(path!=NULL){
+ char *unescaped_path;
+ void *ret;
+ unescaped_path=op_string_dup(path);
+ if(OP_UNLIKELY(unescaped_path==NULL))return NULL;
+ ret=op_fopen(_cb,op_unescape_url_component(unescaped_path),"rb");
+ _ogg_free(unescaped_path);
+ return ret;
+ }
+#if defined(OP_ENABLE_HTTP)
+ /*If not, try http/https.*/
+ else{
+ OpusHTTPStream *stream;
+ int ret;
+ stream=(OpusHTTPStream *)_ogg_malloc(sizeof(*stream));
+ if(OP_UNLIKELY(stream==NULL))return NULL;
+ op_http_stream_init(stream);
+ ret=op_http_stream_open(stream,_url,_skip_certificate_check,
+ _proxy_host,_proxy_port,_proxy_user,_proxy_pass,_info);
+ if(OP_UNLIKELY(ret<0)){
+ op_http_stream_clear(stream);
+ _ogg_free(stream);
+ return NULL;
+ }
+ *_cb=*&OP_HTTP_CALLBACKS;
+ return stream;
+ }
+#else
+ (void)_skip_certificate_check;
+ (void)_proxy_host;
+ (void)_proxy_port;
+ (void)_proxy_user;
+ (void)_proxy_pass;
+ (void)_info;
+ return NULL;
+#endif
+}
+
+/*The actual implementation of op_url_stream_vcreate().
+ We have to do a careful dance here to avoid potential memory leaks if
+ OpusServerInfo is requested, since this function is also used by
+ op_vopen_url() and op_vtest_url().
+ Even if this function succeeds, those functions might ultimately fail.
+ If they do, they should return without having touched the OpusServerInfo
+ passed by the application.
+ Therefore, if this function succeeds and OpusServerInfo is requested, the
+ actual info will be stored in *_info and a pointer to the application's
+ storage will be placed in *_pinfo.
+ If this function fails or if the application did not request OpusServerInfo,
+ *_pinfo will be NULL.
+ Our caller is responsible for copying *_info to **_pinfo if it ultimately
+ succeeds, or for clearing *_info if it ultimately fails.*/
+void *op_url_stream_vcreate_impl(OpusFileCallbacks *_cb,
+ const char *_url,OpusServerInfo *_info,OpusServerInfo **_pinfo,va_list _ap){
+ int skip_certificate_check;
+ const char *proxy_host;
+ opus_int32 proxy_port;
+ const char *proxy_user;
+ const char *proxy_pass;
+ OpusServerInfo *pinfo;
+ skip_certificate_check=0;
+ proxy_host=NULL;
+ proxy_port=8080;
+ proxy_user=NULL;
+ proxy_pass=NULL;
+ pinfo=NULL;
+ for(;;){
+ ptrdiff_t request;
+ request=va_arg(_ap,char *)-(char *)NULL;
+ /*If we hit NULL, we're done processing options.*/
+ if(!request)break;
+ switch(request){
+ case OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST:{
+ skip_certificate_check=!!va_arg(_ap,opus_int32);
+ }break;
+ case OP_HTTP_PROXY_HOST_REQUEST:{
+ proxy_host=va_arg(_ap,const char *);
+ }break;
+ case OP_HTTP_PROXY_PORT_REQUEST:{
+ proxy_port=va_arg(_ap,opus_int32);
+ if(proxy_port<0||proxy_port>(opus_int32)65535)return NULL;
+ }break;
+ case OP_HTTP_PROXY_USER_REQUEST:{
+ proxy_user=va_arg(_ap,const char *);
+ }break;
+ case OP_HTTP_PROXY_PASS_REQUEST:{
+ proxy_pass=va_arg(_ap,const char *);
+ }break;
+ case OP_GET_SERVER_INFO_REQUEST:{
+ pinfo=va_arg(_ap,OpusServerInfo *);
+ }break;
+ /*Some unknown option.*/
+ default:return NULL;
+ }
+ }
+ /*If the caller has requested server information, proxy it to a local copy to
+ simplify error handling.*/
+ *_pinfo=NULL;
+ if(pinfo!=NULL){
+ void *ret;
+ opus_server_info_init(_info);
+ ret=op_url_stream_create_impl(_cb,_url,skip_certificate_check,
+ proxy_host,proxy_port,proxy_user,proxy_pass,_info);
+ if(ret!=NULL)*_pinfo=pinfo;
+ else opus_server_info_clear(_info);
+ return ret;
+ }
+ return op_url_stream_create_impl(_cb,_url,skip_certificate_check,
+ proxy_host,proxy_port,proxy_user,proxy_pass,NULL);
+}
+
+void *op_url_stream_vcreate(OpusFileCallbacks *_cb,
+ const char *_url,va_list _ap){
+ OpusServerInfo info;
+ OpusServerInfo *pinfo=NULL;
+ void *ret;
+ ret=op_url_stream_vcreate_impl(_cb,_url,&info,&pinfo,_ap);
+ if(pinfo!=NULL)*pinfo=*&info;
+ return ret;
+}
+
+void *op_url_stream_create(OpusFileCallbacks *_cb,
+ const char *_url,...){
+ va_list ap;
+ void *ret;
+ va_start(ap,_url);
+ ret=op_url_stream_vcreate(_cb,_url,ap);
+ va_end(ap);
+ return ret;
+}
+
+/*Convenience routines to open/test URLs in a single step.*/
+
+OggOpusFile *op_vopen_url(const char *_url,int *_error,va_list _ap){
+ OpusFileCallbacks cb;
+ OggOpusFile *of;
+ OpusServerInfo info;
+ OpusServerInfo *pinfo;
+ void *source;
+ source=op_url_stream_vcreate_impl(&cb,_url,&info,&pinfo,_ap);
+ if(OP_UNLIKELY(source==NULL)){
+ OP_ASSERT(pinfo==NULL);
+ if(_error!=NULL)*_error=OP_EFAULT;
+ return NULL;
+ }
+ of=op_open_callbacks(source,&cb,NULL,0,_error);
+ if(OP_UNLIKELY(of==NULL)){
+ if(pinfo!=NULL)opus_server_info_clear(&info);
+ (*cb.close)(source);
+ }
+ else if(pinfo!=NULL)*pinfo=*&info;
+ return of;
+}
+
+OggOpusFile *op_open_url(const char *_url,int *_error,...){
+ OggOpusFile *ret;
+ va_list ap;
+ va_start(ap,_error);
+ ret=op_vopen_url(_url,_error,ap);
+ va_end(ap);
+ return ret;
+}
+
+OggOpusFile *op_vtest_url(const char *_url,int *_error,va_list _ap){
+ OpusFileCallbacks cb;
+ OggOpusFile *of;
+ OpusServerInfo info;
+ OpusServerInfo *pinfo;
+ void *source;
+ source=op_url_stream_vcreate_impl(&cb,_url,&info,&pinfo,_ap);
+ if(OP_UNLIKELY(source==NULL)){
+ OP_ASSERT(pinfo==NULL);
+ if(_error!=NULL)*_error=OP_EFAULT;
+ return NULL;
+ }
+ of=op_test_callbacks(source,&cb,NULL,0,_error);
+ if(OP_UNLIKELY(of==NULL)){
+ if(pinfo!=NULL)opus_server_info_clear(&info);
+ (*cb.close)(source);
+ }
+ else if(pinfo!=NULL)*pinfo=*&info;
+ return of;
+}
+
+OggOpusFile *op_test_url(const char *_url,int *_error,...){
+ OggOpusFile *ret;
+ va_list ap;
+ va_start(ap,_error);
+ ret=op_vtest_url(_url,_error,ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/external/opusfile-0.8/src/info.c b/external/opusfile-0.8/src/info.c
new file mode 100644
index 0000000..c36f9a9
--- /dev/null
+++ b/external/opusfile-0.8/src/info.c
@@ -0,0 +1,758 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "internal.h"
+#include <limits.h>
+#include <string.h>
+
+static unsigned op_parse_uint16le(const unsigned char *_data){
+ return _data[0]|_data[1]<<8;
+}
+
+static int op_parse_int16le(const unsigned char *_data){
+ int ret;
+ ret=_data[0]|_data[1]<<8;
+ return (ret^0x8000)-0x8000;
+}
+
+static opus_uint32 op_parse_uint32le(const unsigned char *_data){
+ return _data[0]|(opus_uint32)_data[1]<<8|
+ (opus_uint32)_data[2]<<16|(opus_uint32)_data[3]<<24;
+}
+
+static opus_uint32 op_parse_uint32be(const unsigned char *_data){
+ return _data[3]|(opus_uint32)_data[2]<<8|
+ (opus_uint32)_data[1]<<16|(opus_uint32)_data[0]<<24;
+}
+
+int opus_head_parse(OpusHead *_head,const unsigned char *_data,size_t _len){
+ OpusHead head;
+ if(_len<8)return OP_ENOTFORMAT;
+ if(memcmp(_data,"OpusHead",8)!=0)return OP_ENOTFORMAT;
+ if(_len<9)return OP_EBADHEADER;
+ head.version=_data[8];
+ if(head.version>15)return OP_EVERSION;
+ if(_len<19)return OP_EBADHEADER;
+ head.channel_count=_data[9];
+ head.pre_skip=op_parse_uint16le(_data+10);
+ head.input_sample_rate=op_parse_uint32le(_data+12);
+ head.output_gain=op_parse_int16le(_data+16);
+ head.mapping_family=_data[18];
+ if(head.mapping_family==0){
+ if(head.channel_count<1||head.channel_count>2)return OP_EBADHEADER;
+ if(head.version<=1&&_len>19)return OP_EBADHEADER;
+ head.stream_count=1;
+ head.coupled_count=head.channel_count-1;
+ if(_head!=NULL){
+ _head->mapping[0]=0;
+ _head->mapping[1]=1;
+ }
+ }
+ else if(head.mapping_family==1){
+ size_t size;
+ int ci;
+ if(head.channel_count<1||head.channel_count>8)return OP_EBADHEADER;
+ size=21+head.channel_count;
+ if(_len<size||head.version<=1&&_len>size)return OP_EBADHEADER;
+ head.stream_count=_data[19];
+ if(head.stream_count<1)return OP_EBADHEADER;
+ head.coupled_count=_data[20];
+ if(head.coupled_count>head.stream_count)return OP_EBADHEADER;
+ for(ci=0;ci<head.channel_count;ci++){
+ if(_data[21+ci]>=head.stream_count+head.coupled_count
+ &&_data[21+ci]!=255){
+ return OP_EBADHEADER;
+ }
+ }
+ if(_head!=NULL)memcpy(_head->mapping,_data+21,head.channel_count);
+ }
+ /*General purpose players should not attempt to play back content with
+ channel mapping family 255.*/
+ else if(head.mapping_family==255)return OP_EIMPL;
+ /*No other channel mapping families are currently defined.*/
+ else return OP_EBADHEADER;
+ if(_head!=NULL)memcpy(_head,&head,head.mapping-(unsigned char *)&head);
+ return 0;
+}
+
+void opus_tags_init(OpusTags *_tags){
+ memset(_tags,0,sizeof(*_tags));
+}
+
+void opus_tags_clear(OpusTags *_tags){
+ int ncomments;
+ int ci;
+ ncomments=_tags->comments;
+ if(_tags->user_comments!=NULL)ncomments++;
+ for(ci=ncomments;ci-->0;)_ogg_free(_tags->user_comments[ci]);
+ _ogg_free(_tags->user_comments);
+ _ogg_free(_tags->comment_lengths);
+ _ogg_free(_tags->vendor);
+}
+
+/*Ensure there's room for up to _ncomments comments.*/
+static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){
+ char **user_comments;
+ int *comment_lengths;
+ int cur_ncomments;
+ char *binary_suffix_data;
+ int binary_suffix_len;
+ size_t size;
+ if(OP_UNLIKELY(_ncomments>=(size_t)INT_MAX))return OP_EFAULT;
+ size=sizeof(*_tags->comment_lengths)*(_ncomments+1);
+ if(size/sizeof(*_tags->comment_lengths)!=_ncomments+1)return OP_EFAULT;
+ cur_ncomments=_tags->comments;
+ comment_lengths=_tags->comment_lengths;
+ binary_suffix_len=comment_lengths==NULL?0:comment_lengths[cur_ncomments];
+ comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths,size);
+ if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT;
+ comment_lengths[_ncomments]=binary_suffix_len;
+ _tags->comment_lengths=comment_lengths;
+ size=sizeof(*_tags->user_comments)*(_ncomments+1);
+ if(size/sizeof(*_tags->user_comments)!=_ncomments+1)return OP_EFAULT;
+ user_comments=_tags->user_comments;
+ binary_suffix_data=user_comments==NULL?NULL:user_comments[cur_ncomments];
+ user_comments=(char **)_ogg_realloc(_tags->user_comments,size);
+ if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT;
+ user_comments[_ncomments]=binary_suffix_data;
+ _tags->user_comments=user_comments;
+ return 0;
+}
+
+/*Duplicate a (possibly non-NUL terminated) string with a known length.*/
+static char *op_strdup_with_len(const char *_s,size_t _len){
+ size_t size;
+ char *ret;
+ size=sizeof(*ret)*(_len+1);
+ if(OP_UNLIKELY(size<_len))return NULL;
+ ret=(char *)_ogg_malloc(size);
+ if(OP_LIKELY(ret!=NULL)){
+ ret=(char *)memcpy(ret,_s,sizeof(*ret)*_len);
+ ret[_len]='\0';
+ }
+ return ret;
+}
+
+/*The actual implementation of opus_tags_parse().
+ Unlike the public API, this function requires _tags to already be
+ initialized, modifies its contents before success is guaranteed, and assumes
+ the caller will clear it on error.*/
+static int opus_tags_parse_impl(OpusTags *_tags,
+ const unsigned char *_data,size_t _len){
+ opus_uint32 count;
+ size_t len;
+ int ncomments;
+ int ci;
+ len=_len;
+ if(len<8)return OP_ENOTFORMAT;
+ if(memcmp(_data,"OpusTags",8)!=0)return OP_ENOTFORMAT;
+ if(len<16)return OP_EBADHEADER;
+ _data+=8;
+ len-=8;
+ count=op_parse_uint32le(_data);
+ _data+=4;
+ len-=4;
+ if(count>len)return OP_EBADHEADER;
+ if(_tags!=NULL){
+ _tags->vendor=op_strdup_with_len((char *)_data,count);
+ if(_tags->vendor==NULL)return OP_EFAULT;
+ }
+ _data+=count;
+ len-=count;
+ if(len<4)return OP_EBADHEADER;
+ count=op_parse_uint32le(_data);
+ _data+=4;
+ len-=4;
+ /*Check to make sure there's minimally sufficient data left in the packet.*/
+ if(count>len>>2)return OP_EBADHEADER;
+ /*Check for overflow (the API limits this to an int).*/
+ if(count>(opus_uint32)INT_MAX-1)return OP_EFAULT;
+ if(_tags!=NULL){
+ int ret;
+ ret=op_tags_ensure_capacity(_tags,count);
+ if(ret<0)return ret;
+ }
+ ncomments=(int)count;
+ for(ci=0;ci<ncomments;ci++){
+ /*Check to make sure there's minimally sufficient data left in the packet.*/
+ if((size_t)(ncomments-ci)>len>>2)return OP_EBADHEADER;
+ count=op_parse_uint32le(_data);
+ _data+=4;
+ len-=4;
+ if(count>len)return OP_EBADHEADER;
+ /*Check for overflow (the API limits this to an int).*/
+ if(count>(opus_uint32)INT_MAX)return OP_EFAULT;
+ if(_tags!=NULL){
+ _tags->user_comments[ci]=op_strdup_with_len((char *)_data,count);
+ if(_tags->user_comments[ci]==NULL)return OP_EFAULT;
+ _tags->comment_lengths[ci]=(int)count;
+ _tags->comments=ci+1;
+ /*Needed by opus_tags_clear() if we fail before parsing the (optional)
+ binary metadata.*/
+ _tags->user_comments[ci+1]=NULL;
+ }
+ _data+=count;
+ len-=count;
+ }
+ if(len>0&&(_data[0]&1)){
+ if(len>(opus_uint32)INT_MAX)return OP_EFAULT;
+ if(_tags!=NULL){
+ _tags->user_comments[ncomments]=(char *)_ogg_malloc(len);
+ if(OP_UNLIKELY(_tags->user_comments[ncomments]==NULL))return OP_EFAULT;
+ memcpy(_tags->user_comments[ncomments],_data,len);
+ _tags->comment_lengths[ncomments]=(int)len;
+ }
+ }
+ return 0;
+}
+
+int opus_tags_parse(OpusTags *_tags,const unsigned char *_data,size_t _len){
+ if(_tags!=NULL){
+ OpusTags tags;
+ int ret;
+ opus_tags_init(&tags);
+ ret=opus_tags_parse_impl(&tags,_data,_len);
+ if(ret<0)opus_tags_clear(&tags);
+ else *_tags=*&tags;
+ return ret;
+ }
+ else return opus_tags_parse_impl(NULL,_data,_len);
+}
+
+/*The actual implementation of opus_tags_copy().
+ Unlike the public API, this function requires _dst to already be
+ initialized, modifies its contents before success is guaranteed, and assumes
+ the caller will clear it on error.*/
+static int opus_tags_copy_impl(OpusTags *_dst,const OpusTags *_src){
+ char *vendor;
+ int ncomments;
+ int ret;
+ int ci;
+ vendor=_src->vendor;
+ _dst->vendor=op_strdup_with_len(vendor,strlen(vendor));
+ if(OP_UNLIKELY(_dst->vendor==NULL))return OP_EFAULT;
+ ncomments=_src->comments;
+ ret=op_tags_ensure_capacity(_dst,ncomments);
+ if(OP_UNLIKELY(ret<0))return ret;
+ for(ci=0;ci<ncomments;ci++){
+ int len;
+ len=_src->comment_lengths[ci];
+ OP_ASSERT(len>=0);
+ _dst->user_comments[ci]=op_strdup_with_len(_src->user_comments[ci],len);
+ if(OP_UNLIKELY(_dst->user_comments[ci]==NULL))return OP_EFAULT;
+ _dst->comment_lengths[ci]=len;
+ _dst->comments=ci+1;
+ }
+ if(_src->comment_lengths!=NULL){
+ int len;
+ len=_src->comment_lengths[ncomments];
+ if(len>0){
+ _dst->user_comments[ncomments]=(char *)_ogg_malloc(len);
+ if(OP_UNLIKELY(_dst->user_comments[ncomments]==NULL))return OP_EFAULT;
+ memcpy(_dst->user_comments[ncomments],_src->user_comments[ncomments],len);
+ _dst->comment_lengths[ncomments]=len;
+ }
+ }
+ return 0;
+}
+
+int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){
+ OpusTags dst;
+ int ret;
+ opus_tags_init(&dst);
+ ret=opus_tags_copy_impl(&dst,_src);
+ if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst);
+ else *_dst=*&dst;
+ return 0;
+}
+
+int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){
+ char *comment;
+ int tag_len;
+ int value_len;
+ int ncomments;
+ int ret;
+ ncomments=_tags->comments;
+ ret=op_tags_ensure_capacity(_tags,ncomments+1);
+ if(OP_UNLIKELY(ret<0))return ret;
+ tag_len=strlen(_tag);
+ value_len=strlen(_value);
+ /*+2 for '=' and '\0'.*/
+ comment=(char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2));
+ if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
+ memcpy(comment,_tag,sizeof(*comment)*tag_len);
+ comment[tag_len]='=';
+ memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1));
+ _tags->user_comments[ncomments]=comment;
+ _tags->comment_lengths[ncomments]=tag_len+value_len+1;
+ _tags->comments=ncomments+1;
+ return 0;
+}
+
+int opus_tags_add_comment(OpusTags *_tags,const char *_comment){
+ char *comment;
+ int comment_len;
+ int ncomments;
+ int ret;
+ ncomments=_tags->comments;
+ ret=op_tags_ensure_capacity(_tags,ncomments+1);
+ if(OP_UNLIKELY(ret<0))return ret;
+ comment_len=(int)strlen(_comment);
+ comment=op_strdup_with_len(_comment,comment_len);
+ if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
+ _tags->user_comments[ncomments]=comment;
+ _tags->comment_lengths[ncomments]=comment_len;
+ _tags->comments=ncomments+1;
+ return 0;
+}
+
+int opus_tags_set_binary_suffix(OpusTags *_tags,
+ const unsigned char *_data,int _len){
+ unsigned char *binary_suffix_data;
+ int ncomments;
+ int ret;
+ if(_len<0||_len>0&&(_data==NULL||!(_data[0]&1)))return OP_EINVAL;
+ ncomments=_tags->comments;
+ ret=op_tags_ensure_capacity(_tags,ncomments);
+ if(OP_UNLIKELY(ret<0))return ret;
+ binary_suffix_data=
+ (unsigned char *)_ogg_realloc(_tags->user_comments[ncomments],_len);
+ if(OP_UNLIKELY(binary_suffix_data==NULL))return OP_EFAULT;
+ memcpy(binary_suffix_data,_data,_len);
+ _tags->user_comments[ncomments]=(char *)binary_suffix_data;
+ _tags->comment_lengths[ncomments]=_len;
+ return 0;
+}
+
+int opus_tagcompare(const char *_tag_name,const char *_comment){
+ return opus_tagncompare(_tag_name,strlen(_tag_name),_comment);
+}
+
+int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){
+ int ret;
+ OP_ASSERT(_tag_len>=0);
+ ret=op_strncasecmp(_tag_name,_comment,_tag_len);
+ return ret?ret:'='-_comment[_tag_len];
+}
+
+const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){
+ char **user_comments;
+ int tag_len;
+ int found;
+ int ncomments;
+ int ci;
+ tag_len=strlen(_tag);
+ ncomments=_tags->comments;
+ user_comments=_tags->user_comments;
+ found=0;
+ for(ci=0;ci<ncomments;ci++){
+ if(!opus_tagncompare(_tag,tag_len,user_comments[ci])){
+ /*We return a pointer to the data, not a copy.*/
+ if(_count==found++)return user_comments[ci]+tag_len+1;
+ }
+ }
+ /*Didn't find anything.*/
+ return NULL;
+}
+
+int opus_tags_query_count(const OpusTags *_tags,const char *_tag){
+ char **user_comments;
+ int tag_len;
+ int found;
+ int ncomments;
+ int ci;
+ tag_len=strlen(_tag);
+ ncomments=_tags->comments;
+ user_comments=_tags->user_comments;
+ found=0;
+ for(ci=0;ci<ncomments;ci++){
+ if(!opus_tagncompare(_tag,tag_len,user_comments[ci]))found++;
+ }
+ return found;
+}
+
+const unsigned char *opus_tags_get_binary_suffix(const OpusTags *_tags,
+ int *_len){
+ int ncomments;
+ int len;
+ ncomments=_tags->comments;
+ len=_tags->comment_lengths==NULL?0:_tags->comment_lengths[ncomments];
+ *_len=len;
+ OP_ASSERT(len==0||_tags->user_comments!=NULL);
+ return len>0?(const unsigned char *)_tags->user_comments[ncomments]:NULL;
+}
+
+static int opus_tags_get_gain(const OpusTags *_tags,int *_gain_q8,
+ const char *_tag_name,size_t _tag_len){
+ char **comments;
+ int ncomments;
+ int ci;
+ comments=_tags->user_comments;
+ ncomments=_tags->comments;
+ /*Look for the first valid tag with the name _tag_name and use that.*/
+ for(ci=0;ci<ncomments;ci++){
+ if(opus_tagncompare(_tag_name,_tag_len,comments[ci])==0){
+ char *p;
+ opus_int32 gain_q8;
+ int negative;
+ p=comments[ci]+_tag_len+1;
+ negative=0;
+ if(*p=='-'){
+ negative=-1;
+ p++;
+ }
+ else if(*p=='+')p++;
+ gain_q8=0;
+ while(*p>='0'&&*p<='9'){
+ gain_q8=10*gain_q8+*p-'0';
+ if(gain_q8>32767-negative)break;
+ p++;
+ }
+ /*This didn't look like a signed 16-bit decimal integer.
+ Not a valid gain tag.*/
+ if(*p!='\0')continue;
+ *_gain_q8=(int)(gain_q8+negative^negative);
+ return 0;
+ }
+ }
+ return OP_FALSE;
+}
+
+int opus_tags_get_album_gain(const OpusTags *_tags,int *_gain_q8){
+ return opus_tags_get_gain(_tags,_gain_q8,"R128_ALBUM_GAIN",15);
+}
+
+int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){
+ return opus_tags_get_gain(_tags,_gain_q8,"R128_TRACK_GAIN",15);
+}
+
+static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){
+ return _buf_sz>=11&&memcmp(_buf,"\xFF\xD8\xFF\xE0",4)==0
+ &&(_buf[4]<<8|_buf[5])>=16&&memcmp(_buf+6,"JFIF",5)==0;
+}
+
+/*Tries to extract the width, height, bits per pixel, and palette size of a
+ JPEG.
+ On failure, simply leaves its outputs unmodified.*/
+static void op_extract_jpeg_params(const unsigned char *_buf,size_t _buf_sz,
+ opus_uint32 *_width,opus_uint32 *_height,
+ opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
+ if(op_is_jpeg(_buf,_buf_sz)){
+ size_t offs;
+ offs=2;
+ for(;;){
+ size_t segment_len;
+ int marker;
+ while(offs<_buf_sz&&_buf[offs]!=0xFF)offs++;
+ while(offs<_buf_sz&&_buf[offs]==0xFF)offs++;
+ marker=_buf[offs];
+ offs++;
+ /*If we hit EOI* (end of image), or another SOI* (start of image),
+ or SOS (start of scan), then stop now.*/
+ if(offs>=_buf_sz||(marker>=0xD8&&marker<=0xDA))break;
+ /*RST* (restart markers): skip (no segment length).*/
+ else if(marker>=0xD0&&marker<=0xD7)continue;
+ /*Read the length of the marker segment.*/
+ if(_buf_sz-offs<2)break;
+ segment_len=_buf[offs]<<8|_buf[offs+1];
+ if(segment_len<2||_buf_sz-offs<segment_len)break;
+ if(marker==0xC0||(marker>0xC0&&marker<0xD0&&(marker&3)!=0)){
+ /*Found a SOFn (start of frame) marker segment:*/
+ if(segment_len>=8){
+ *_height=_buf[offs+3]<<8|_buf[offs+4];
+ *_width=_buf[offs+5]<<8|_buf[offs+6];
+ *_depth=_buf[offs+2]*_buf[offs+7];
+ *_colors=0;
+ *_has_palette=0;
+ }
+ break;
+ }
+ /*Other markers: skip the whole marker segment.*/
+ offs+=segment_len;
+ }
+ }
+}
+
+static int op_is_png(const unsigned char *_buf,size_t _buf_sz){
+ return _buf_sz>=8&&memcmp(_buf,"\x89PNG\x0D\x0A\x1A\x0A",8)==0;
+}
+
+/*Tries to extract the width, height, bits per pixel, and palette size of a
+ PNG.
+ On failure, simply leaves its outputs unmodified.*/
+static void op_extract_png_params(const unsigned char *_buf,size_t _buf_sz,
+ opus_uint32 *_width,opus_uint32 *_height,
+ opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
+ if(op_is_png(_buf,_buf_sz)){
+ size_t offs;
+ offs=8;
+ while(_buf_sz-offs>=12){
+ ogg_uint32_t chunk_len;
+ chunk_len=op_parse_uint32be(_buf+offs);
+ if(chunk_len>_buf_sz-(offs+12))break;
+ else if(chunk_len==13&&memcmp(_buf+offs+4,"IHDR",4)==0){
+ int color_type;
+ *_width=op_parse_uint32be(_buf+offs+8);
+ *_height=op_parse_uint32be(_buf+offs+12);
+ color_type=_buf[offs+17];
+ if(color_type==3){
+ *_depth=24;
+ *_has_palette=1;
+ }
+ else{
+ int sample_depth;
+ sample_depth=_buf[offs+16];
+ if(color_type==0)*_depth=sample_depth;
+ else if(color_type==2)*_depth=sample_depth*3;
+ else if(color_type==4)*_depth=sample_depth*2;
+ else if(color_type==6)*_depth=sample_depth*4;
+ *_colors=0;
+ *_has_palette=0;
+ break;
+ }
+ }
+ else if(*_has_palette>0&&memcmp(_buf+offs+4,"PLTE",4)==0){
+ *_colors=chunk_len/3;
+ break;
+ }
+ offs+=12+chunk_len;
+ }
+ }
+}
+
+static int op_is_gif(const unsigned char *_buf,size_t _buf_sz){
+ return _buf_sz>=6&&(memcmp(_buf,"GIF87a",6)==0||memcmp(_buf,"GIF89a",6)==0);
+}
+
+/*Tries to extract the width, height, bits per pixel, and palette size of a
+ GIF.
+ On failure, simply leaves its outputs unmodified.*/
+static void op_extract_gif_params(const unsigned char *_buf,size_t _buf_sz,
+ opus_uint32 *_width,opus_uint32 *_height,
+ opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
+ if(op_is_gif(_buf,_buf_sz)&&_buf_sz>=14){
+ *_width=_buf[6]|_buf[7]<<8;
+ *_height=_buf[8]|_buf[9]<<8;
+ /*libFLAC hard-codes the depth to 24.*/
+ *_depth=24;
+ *_colors=1<<((_buf[10]&7)+1);
+ *_has_palette=1;
+ }
+}
+
+/*The actual implementation of opus_picture_tag_parse().
+ Unlike the public API, this function requires _pic to already be
+ initialized, modifies its contents before success is guaranteed, and assumes
+ the caller will clear it on error.*/
+static int opus_picture_tag_parse_impl(OpusPictureTag *_pic,const char *_tag,
+ unsigned char *_buf,size_t _buf_sz,size_t _base64_sz){
+ opus_int32 picture_type;
+ opus_uint32 mime_type_length;
+ char *mime_type;
+ opus_uint32 description_length;
+ char *description;
+ opus_uint32 width;
+ opus_uint32 height;
+ opus_uint32 depth;
+ opus_uint32 colors;
+ opus_uint32 data_length;
+ opus_uint32 file_width;
+ opus_uint32 file_height;
+ opus_uint32 file_depth;
+ opus_uint32 file_colors;
+ int format;
+ int has_palette;
+ int colors_set;
+ size_t i;
+ /*Decode the BASE64 data.*/
+ for(i=0;i<_base64_sz;i++){
+ opus_uint32 value;
+ int j;
+ value=0;
+ for(j=0;j<4;j++){
+ unsigned c;
+ unsigned d;
+ c=(unsigned char)_tag[4*i+j];
+ if(c=='+')d=62;
+ else if(c=='/')d=63;
+ else if(c>='0'&&c<='9')d=52+c-'0';
+ else if(c>='a'&&c<='z')d=26+c-'a';
+ else if(c>='A'&&c<='Z')d=c-'A';
+ else if(c=='='&&3*i+j>_buf_sz)d=0;
+ else return OP_ENOTFORMAT;
+ value=value<<6|d;
+ }
+ _buf[3*i]=(unsigned char)(value>>16);
+ if(3*i+1<_buf_sz){
+ _buf[3*i+1]=(unsigned char)(value>>8);
+ if(3*i+2<_buf_sz)_buf[3*i+2]=(unsigned char)value;
+ }
+ }
+ i=0;
+ picture_type=op_parse_uint32be(_buf+i);
+ i+=4;
+ /*Extract the MIME type.*/
+ mime_type_length=op_parse_uint32be(_buf+i);
+ i+=4;
+ if(mime_type_length>_buf_sz-32)return OP_ENOTFORMAT;
+ mime_type=(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(mime_type_length+1));
+ if(mime_type==NULL)return OP_EFAULT;
+ memcpy(mime_type,_buf+i,sizeof(*mime_type)*mime_type_length);
+ mime_type[mime_type_length]='\0';
+ _pic->mime_type=mime_type;
+ i+=mime_type_length;
+ /*Extract the description string.*/
+ description_length=op_parse_uint32be(_buf+i);
+ i+=4;
+ if(description_length>_buf_sz-mime_type_length-32)return OP_ENOTFORMAT;
+ description=
+ (char *)_ogg_malloc(sizeof(*_pic->mime_type)*(description_length+1));
+ if(description==NULL)return OP_EFAULT;
+ memcpy(description,_buf+i,sizeof(*description)*description_length);
+ description[description_length]='\0';
+ _pic->description=description;
+ i+=description_length;
+ /*Extract the remaining fields.*/
+ width=op_parse_uint32be(_buf+i);
+ i+=4;
+ height=op_parse_uint32be(_buf+i);
+ i+=4;
+ depth=op_parse_uint32be(_buf+i);
+ i+=4;
+ colors=op_parse_uint32be(_buf+i);
+ i+=4;
+ /*If one of these is set, they all must be, but colors==0 is a valid value.*/
+ colors_set=width!=0||height!=0||depth!=0||colors!=0;
+ if((width==0||height==0||depth==0)&&colors_set)return OP_ENOTFORMAT;
+ data_length=op_parse_uint32be(_buf+i);
+ i+=4;
+ if(data_length>_buf_sz-i)return OP_ENOTFORMAT;
+ /*Trim extraneous data so we don't copy it below.*/
+ _buf_sz=i+data_length;
+ /*Attempt to determine the image format.*/
+ format=OP_PIC_FORMAT_UNKNOWN;
+ if(mime_type_length==3&&strcmp(mime_type,"-->")==0){
+ format=OP_PIC_FORMAT_URL;
+ /*Picture type 1 must be a 32x32 PNG.*/
+ if(picture_type==1&&(width!=0||height!=0)&&(width!=32||height!=32)){
+ return OP_ENOTFORMAT;
+ }
+ /*Append a terminating NUL for the convenience of our callers.*/
+ _buf[_buf_sz++]='\0';
+ }
+ else{
+ if(mime_type_length==10
+ &&op_strncasecmp(mime_type,"image/jpeg",mime_type_length)==0){
+ if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
+ }
+ else if(mime_type_length==9
+ &&op_strncasecmp(mime_type,"image/png",mime_type_length)==0){
+ if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
+ }
+ else if(mime_type_length==9
+ &&op_strncasecmp(mime_type,"image/gif",mime_type_length)==0){
+ if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
+ }
+ else if(mime_type_length==0||(mime_type_length==6
+ &&op_strncasecmp(mime_type,"image/",mime_type_length)==0)){
+ if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
+ else if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
+ else if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
+ }
+ file_width=file_height=file_depth=file_colors=0;
+ has_palette=-1;
+ switch(format){
+ case OP_PIC_FORMAT_JPEG:{
+ op_extract_jpeg_params(_buf+i,data_length,
+ &file_width,&file_height,&file_depth,&file_colors,&has_palette);
+ }break;
+ case OP_PIC_FORMAT_PNG:{
+ op_extract_png_params(_buf+i,data_length,
+ &file_width,&file_height,&file_depth,&file_colors,&has_palette);
+ }break;
+ case OP_PIC_FORMAT_GIF:{
+ op_extract_gif_params(_buf+i,data_length,
+ &file_width,&file_height,&file_depth,&file_colors,&has_palette);
+ }break;
+ }
+ if(has_palette>=0){
+ /*If we successfully extracted these parameters from the image, override
+ any declared values.*/
+ width=file_width;
+ height=file_height;
+ depth=file_depth;
+ colors=file_colors;
+ }
+ /*Picture type 1 must be a 32x32 PNG.*/
+ if(picture_type==1&&(format!=OP_PIC_FORMAT_PNG||width!=32||height!=32)){
+ return OP_ENOTFORMAT;
+ }
+ }
+ /*Adjust _buf_sz instead of using data_length to capture the terminating NUL
+ for URLs.*/
+ _buf_sz-=i;
+ memmove(_buf,_buf+i,sizeof(*_buf)*_buf_sz);
+ _buf=(unsigned char *)_ogg_realloc(_buf,_buf_sz);
+ if(_buf_sz>0&&_buf==NULL)return OP_EFAULT;
+ _pic->type=picture_type;
+ _pic->width=width;
+ _pic->height=height;
+ _pic->depth=depth;
+ _pic->colors=colors;
+ _pic->data_length=data_length;
+ _pic->data=_buf;
+ _pic->format=format;
+ return 0;
+}
+
+int opus_picture_tag_parse(OpusPictureTag *_pic,const char *_tag){
+ OpusPictureTag pic;
+ unsigned char *buf;
+ size_t base64_sz;
+ size_t buf_sz;
+ size_t tag_length;
+ int ret;
+ if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,_tag)==0)_tag+=23;
+ /*Figure out how much BASE64-encoded data we have.*/
+ tag_length=strlen(_tag);
+ if(tag_length&3)return OP_ENOTFORMAT;
+ base64_sz=tag_length>>2;
+ buf_sz=3*base64_sz;
+ if(buf_sz<32)return OP_ENOTFORMAT;
+ if(_tag[tag_length-1]=='=')buf_sz--;
+ if(_tag[tag_length-2]=='=')buf_sz--;
+ if(buf_sz<32)return OP_ENOTFORMAT;
+ /*Allocate an extra byte to allow appending a terminating NUL to URL data.*/
+ buf=(unsigned char *)_ogg_malloc(sizeof(*buf)*(buf_sz+1));
+ if(buf==NULL)return OP_EFAULT;
+ opus_picture_tag_init(&pic);
+ ret=opus_picture_tag_parse_impl(&pic,_tag,buf,buf_sz,base64_sz);
+ if(ret<0){
+ opus_picture_tag_clear(&pic);
+ _ogg_free(buf);
+ }
+ else *_pic=*&pic;
+ return ret;
+}
+
+void opus_picture_tag_init(OpusPictureTag *_pic){
+ memset(_pic,0,sizeof(*_pic));
+}
+
+void opus_picture_tag_clear(OpusPictureTag *_pic){
+ _ogg_free(_pic->description);
+ _ogg_free(_pic->mime_type);
+ _ogg_free(_pic->data);
+}
diff --git a/external/opusfile-0.8/src/internal.c b/external/opusfile-0.8/src/internal.c
new file mode 100644
index 0000000..96c80de
--- /dev/null
+++ b/external/opusfile-0.8/src/internal.c
@@ -0,0 +1,42 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "internal.h"
+
+#if defined(OP_ENABLE_ASSERTIONS)
+void op_fatal_impl(const char *_str,const char *_file,int _line){
+ fprintf(stderr,"Fatal (internal) error in %s, line %i: %s\n",
+ _file,_line,_str);
+ abort();
+}
+#endif
+
+/*A version of strncasecmp() that is guaranteed to only ignore the case of
+ ASCII characters.*/
+int op_strncasecmp(const char *_a,const char *_b,int _n){
+ int i;
+ for(i=0;i<_n;i++){
+ int a;
+ int b;
+ int d;
+ a=_a[i];
+ b=_b[i];
+ if(a>='a'&&a<='z')a-='a'-'A';
+ if(b>='a'&&b<='z')b-='a'-'A';
+ d=a-b;
+ if(d)return d;
+ }
+ return 0;
+}
diff --git a/external/opusfile-0.8/src/internal.h b/external/opusfile-0.8/src/internal.h
new file mode 100644
index 0000000..ee48ea3
--- /dev/null
+++ b/external/opusfile-0.8/src/internal.h
@@ -0,0 +1,254 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#if !defined(_opusfile_internal_h)
+# define _opusfile_internal_h (1)
+
+# if !defined(_REENTRANT)
+# define _REENTRANT
+# endif
+# if !defined(_GNU_SOURCE)
+# define _GNU_SOURCE
+# endif
+# if !defined(_LARGEFILE_SOURCE)
+# define _LARGEFILE_SOURCE
+# endif
+# if !defined(_LARGEFILE64_SOURCE)
+# define _LARGEFILE64_SOURCE
+# endif
+# if !defined(_FILE_OFFSET_BITS)
+# define _FILE_OFFSET_BITS 64
+# endif
+
+# include <stdlib.h>
+# include <opusfile.h>
+
+typedef struct OggOpusLink OggOpusLink;
+
+# if defined(OP_FIXED_POINT)
+
+typedef opus_int16 op_sample;
+
+# else
+
+typedef float op_sample;
+
+/*We're using this define to test for libopus 1.1 or later until libopus
+ provides a better mechanism.*/
+# if defined(OPUS_GET_EXPERT_FRAME_DURATION_REQUEST)
+/*Enable soft clipping prevention in 16-bit decodes.*/
+# define OP_SOFT_CLIP (1)
+# endif
+
+# endif
+
+# if OP_GNUC_PREREQ(4,2)
+/*Disable excessive warnings about the order of operations.*/
+# pragma GCC diagnostic ignored "-Wparentheses"
+# elif defined(_MSC_VER)
+/*Disable excessive warnings about the order of operations.*/
+# pragma warning(disable:4554)
+/*Disable warnings about "deprecated" POSIX functions.*/
+# pragma warning(disable:4996)
+# endif
+
+# if OP_GNUC_PREREQ(3,0)
+/*Another alternative is
+ (__builtin_constant_p(_x)?!!(_x):__builtin_expect(!!(_x),1))
+ but that evaluates _x multiple times, which may be bad.*/
+# define OP_LIKELY(_x) (__builtin_expect(!!(_x),1))
+# define OP_UNLIKELY(_x) (__builtin_expect(!!(_x),0))
+# else
+# define OP_LIKELY(_x) (!!(_x))
+# define OP_UNLIKELY(_x) (!!(_x))
+# endif
+
+# if defined(OP_ENABLE_ASSERTIONS)
+# if OP_GNUC_PREREQ(2,5)||__SUNPRO_C>=0x590
+__attribute__((noreturn))
+# endif
+void op_fatal_impl(const char *_str,const char *_file,int _line);
+
+# define OP_FATAL(_str) (op_fatal_impl(_str,__FILE__,__LINE__))
+
+# define OP_ASSERT(_cond) \
+ do{ \
+ if(OP_UNLIKELY(!(_cond)))OP_FATAL("assertion failed: " #_cond); \
+ } \
+ while(0)
+# define OP_ALWAYS_TRUE(_cond) OP_ASSERT(_cond)
+
+# else
+# define OP_FATAL(_str) abort()
+# define OP_ASSERT(_cond)
+# define OP_ALWAYS_TRUE(_cond) ((void)(_cond))
+# endif
+
+# define OP_INT64_MAX (2*(((ogg_int64_t)1<<62)-1)|1)
+# define OP_INT64_MIN (-OP_INT64_MAX-1)
+# define OP_INT32_MAX (2*(((ogg_int32_t)1<<30)-1)|1)
+# define OP_INT32_MIN (-OP_INT32_MAX-1)
+
+# define OP_MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
+# define OP_MAX(_a,_b) ((_a)>(_b)?(_a):(_b))
+# define OP_CLAMP(_lo,_x,_hi) (OP_MAX(_lo,OP_MIN(_x,_hi)))
+
+/*Advance a file offset by the given amount, clamping against OP_INT64_MAX.
+ This is used to advance a known offset by things like OP_CHUNK_SIZE or
+ OP_PAGE_SIZE_MAX, while making sure to avoid signed overflow.
+ It assumes that both _offset and _amount are non-negative.*/
+#define OP_ADV_OFFSET(_offset,_amount) \
+ (OP_MIN(_offset,OP_INT64_MAX-(_amount))+(_amount))
+
+/*The maximum channel count for any mapping we'll actually decode.*/
+# define OP_NCHANNELS_MAX (8)
+
+/*Initial state.*/
+# define OP_NOTOPEN (0)
+/*We've found the first Opus stream in the first link.*/
+# define OP_PARTOPEN (1)
+# define OP_OPENED (2)
+/*We've found the first Opus stream in the current link.*/
+# define OP_STREAMSET (3)
+/*We've initialized the decoder for the chosen Opus stream in the current
+ link.*/
+# define OP_INITSET (4)
+
+/*Information cached for a single link in a chained Ogg Opus file.
+ We choose the first Opus stream encountered in each link to play back (and
+ require at least one).*/
+struct OggOpusLink{
+ /*The byte offset of the first header page in this link.*/
+ opus_int64 offset;
+ /*The byte offset of the first data page from the chosen Opus stream in this
+ link (after the headers).*/
+ opus_int64 data_offset;
+ /*The byte offset of the last page from the chosen Opus stream in this link.
+ This is used when seeking to ensure we find a page before the last one, so
+ that end-trimming calculations work properly.
+ This is only valid for seekable sources.*/
+ opus_int64 end_offset;
+ /*The granule position of the last sample.
+ This is only valid for seekable sources.*/
+ ogg_int64_t pcm_end;
+ /*The granule position before the first sample.*/
+ ogg_int64_t pcm_start;
+ /*The serial number.*/
+ ogg_uint32_t serialno;
+ /*The contents of the info header.*/
+ OpusHead head;
+ /*The contents of the comment header.*/
+ OpusTags tags;
+};
+
+struct OggOpusFile{
+ /*The callbacks used to access the data source.*/
+ OpusFileCallbacks callbacks;
+ /*A FILE *, memory bufer, etc.*/
+ void *source;
+ /*Whether or not we can seek with this data source.*/
+ int seekable;
+ /*The number of links in this chained Ogg Opus file.*/
+ int nlinks;
+ /*The cached information from each link in a chained Ogg Opus file.
+ If source isn't seekable (e.g., it's a pipe), only the current link
+ appears.*/
+ OggOpusLink *links;
+ /*The number of serial numbers from a single link.*/
+ int nserialnos;
+ /*The capacity of the list of serial numbers from a single link.*/
+ int cserialnos;
+ /*Storage for the list of serial numbers from a single link.*/
+ ogg_uint32_t *serialnos;
+ /*This is the current offset of the data processed by the ogg_sync_state.
+ After a seek, this should be set to the target offset so that we can track
+ the byte offsets of subsequent pages.
+ After a call to op_get_next_page(), this will point to the first byte after
+ that page.*/
+ opus_int64 offset;
+ /*The total size of this data source, or -1 if it's unseekable.*/
+ opus_int64 end;
+ /*Used to locate pages in the data source.*/
+ ogg_sync_state oy;
+ /*One of OP_NOTOPEN, OP_PARTOPEN, OP_OPENED, OP_STREAMSET, OP_INITSET.*/
+ int ready_state;
+ /*The current link being played back.*/
+ int cur_link;
+ /*The number of decoded samples to discard from the start of decoding.*/
+ opus_int32 cur_discard_count;
+ /*The granule position of the previous packet (current packet start time).*/
+ ogg_int64_t prev_packet_gp;
+ /*The stream offset of the most recent page with completed packets, or -1.
+ This is only needed to recover continued packet data in the seeking logic,
+ when we use the current position as one of our bounds, only to later
+ discover it was the correct starting point.*/
+ opus_int64 prev_page_offset;
+ /*The number of bytes read since the last bitrate query, including framing.*/
+ opus_int64 bytes_tracked;
+ /*The number of samples decoded since the last bitrate query.*/
+ ogg_int64_t samples_tracked;
+ /*Takes physical pages and welds them into a logical stream of packets.*/
+ ogg_stream_state os;
+ /*Re-timestamped packets from a single page.
+ Buffering these relies on the undocumented libogg behavior that ogg_packet
+ pointers remain valid until the next page is submitted to the
+ ogg_stream_state they came from.*/
+ ogg_packet op[255];
+ /*The index of the next packet to return.*/
+ int op_pos;
+ /*The total number of packets available.*/
+ int op_count;
+ /*Central working state for the packet-to-PCM decoder.*/
+ OpusMSDecoder *od;
+ /*The application-provided packet decode callback.*/
+ op_decode_cb_func decode_cb;
+ /*The application-provided packet decode callback context.*/
+ void *decode_cb_ctx;
+ /*The stream count used to initialize the decoder.*/
+ int od_stream_count;
+ /*The coupled stream count used to initialize the decoder.*/
+ int od_coupled_count;
+ /*The channel count used to initialize the decoder.*/
+ int od_channel_count;
+ /*The channel mapping used to initialize the decoder.*/
+ unsigned char od_mapping[OP_NCHANNELS_MAX];
+ /*The buffered data for one decoded packet.*/
+ op_sample *od_buffer;
+ /*The current position in the decoded buffer.*/
+ int od_buffer_pos;
+ /*The number of valid samples in the decoded buffer.*/
+ int od_buffer_size;
+ /*The type of gain offset to apply.
+ One of OP_HEADER_GAIN, OP_TRACK_GAIN, or OP_ABSOLUTE_GAIN.*/
+ int gain_type;
+ /*The offset to apply to the gain.*/
+ opus_int32 gain_offset_q8;
+ /*Internal state for soft clipping and dithering float->short output.*/
+#if !defined(OP_FIXED_POINT)
+# if defined(OP_SOFT_CLIP)
+ float clip_state[OP_NCHANNELS_MAX];
+# endif
+ float dither_a[OP_NCHANNELS_MAX*4];
+ float dither_b[OP_NCHANNELS_MAX*4];
+ opus_uint32 dither_seed;
+ int dither_mute;
+ int dither_disabled;
+ /*The number of channels represented by the internal state.
+ This gets set to 0 whenever anything that would prevent state propagation
+ occurs (switching between the float/short APIs, or between the
+ stereo/multistream APIs).*/
+ int state_channel_count;
+#endif
+};
+
+int op_strncasecmp(const char *_a,const char *_b,int _n);
+
+#endif
diff --git a/external/opusfile-0.8/src/opusfile.c b/external/opusfile-0.8/src/opusfile.c
new file mode 100644
index 0000000..0d1c78e
--- /dev/null
+++ b/external/opusfile-0.8/src/opusfile.c
@@ -0,0 +1,3266 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: stdio-based convenience library for opening/seeking/decoding
+ last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $
+
+ ********************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "internal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <math.h>
+
+#include "opusfile.h"
+
+/*This implementation is largely based off of libvorbisfile.
+ All of the Ogg bits work roughly the same, though I have made some
+ "improvements" that have not been folded back there, yet.*/
+
+/*A 'chained bitstream' is an Ogg Opus bitstream that contains more than one
+ logical bitstream arranged end to end (the only form of Ogg multiplexing
+ supported by this library.
+ Grouping (parallel multiplexing) is not supported, except to the extent that
+ if there are multiple logical Ogg streams in a single link of the chain, we
+ will ignore all but the first Opus stream we find.*/
+
+/*An Ogg Opus file can be played beginning to end (streamed) without worrying
+ ahead of time about chaining (see opusdec from the opus-tools package).
+ If we have the whole file, however, and want random access
+ (seeking/scrubbing) or desire to know the total length/time of a file, we
+ need to account for the possibility of chaining.*/
+
+/*We can handle things a number of ways.
+ We can determine the entire bitstream structure right off the bat, or find
+ pieces on demand.
+ This library determines and caches structure for the entire bitstream, but
+ builds a virtual decoder on the fly when moving between links in the chain.*/
+
+/*There are also different ways to implement seeking.
+ Enough information exists in an Ogg bitstream to seek to sample-granularity
+ positions in the output.
+ Or, one can seek by picking some portion of the stream roughly in the desired
+ area if we only want coarse navigation through the stream.
+ We implement and expose both strategies.*/
+
+/*The maximum number of bytes in a page (including the page headers).*/
+#define OP_PAGE_SIZE_MAX (65307)
+/*The default amount to seek backwards per step when trying to find the
+ previous page.
+ This must be at least as large as the maximum size of a page.*/
+#define OP_CHUNK_SIZE (65536)
+/*The maximum amount to seek backwards per step when trying to find the
+ previous page.*/
+#define OP_CHUNK_SIZE_MAX (1024*(opus_int32)1024)
+/*A smaller read size is needed for low-rate streaming.*/
+#define OP_READ_SIZE (2048)
+
+int op_test(OpusHead *_head,
+ const unsigned char *_initial_data,size_t _initial_bytes){
+ ogg_sync_state oy;
+ char *data;
+ int err;
+ /*The first page of a normal Opus file will be at most 57 bytes (27 Ogg
+ page header bytes + 1 lacing value + 21 Opus header bytes + 8 channel
+ mapping bytes).
+ It will be at least 47 bytes (27 Ogg page header bytes + 1 lacing value +
+ 19 Opus header bytes using channel mapping family 0).
+ If we don't have at least that much data, give up now.*/
+ if(_initial_bytes<47)return OP_FALSE;
+ /*Only proceed if we start with the magic OggS string.
+ This is to prevent us spending a lot of time allocating memory and looking
+ for Ogg pages in non-Ogg files.*/
+ if(memcmp(_initial_data,"OggS",4)!=0)return OP_ENOTFORMAT;
+ ogg_sync_init(&oy);
+ data=ogg_sync_buffer(&oy,_initial_bytes);
+ if(data!=NULL){
+ ogg_stream_state os;
+ ogg_page og;
+ int ret;
+ memcpy(data,_initial_data,_initial_bytes);
+ ogg_sync_wrote(&oy,_initial_bytes);
+ ogg_stream_init(&os,-1);
+ err=OP_FALSE;
+ do{
+ ogg_packet op;
+ ret=ogg_sync_pageout(&oy,&og);
+ /*Ignore holes.*/
+ if(ret<0)continue;
+ /*Stop if we run out of data.*/
+ if(!ret)break;
+ ogg_stream_reset_serialno(&os,ogg_page_serialno(&og));
+ ogg_stream_pagein(&os,&og);
+ /*Only process the first packet on this page (if it's a BOS packet,
+ it's required to be the only one).*/
+ if(ogg_stream_packetout(&os,&op)==1){
+ if(op.b_o_s){
+ ret=opus_head_parse(_head,op.packet,op.bytes);
+ /*If this didn't look like Opus, keep going.*/
+ if(ret==OP_ENOTFORMAT)continue;
+ /*Otherwise we're done, one way or another.*/
+ err=ret;
+ }
+ /*We finished parsing the headers.
+ There is no Opus to be found.*/
+ else err=OP_ENOTFORMAT;
+ }
+ }
+ while(err==OP_FALSE);
+ ogg_stream_clear(&os);
+ }
+ else err=OP_EFAULT;
+ ogg_sync_clear(&oy);
+ return err;
+}
+
+/*Many, many internal helpers.
+ The intention is not to be confusing.
+ Rampant duplication and monolithic function implementation (though we do have
+ some large, omnibus functions still) would be harder to understand anyway.
+ The high level functions are last.
+ Begin grokking near the end of the file if you prefer to read things
+ top-down.*/
+
+/*The read/seek functions track absolute position within the stream.*/
+
+/*Read a little more data from the file/pipe into the ogg_sync framer.
+ _nbytes: The maximum number of bytes to read.
+ Return: A positive number of bytes read on success, 0 on end-of-file, or a
+ negative value on failure.*/
+static int op_get_data(OggOpusFile *_of,int _nbytes){
+ unsigned char *buffer;
+ int nbytes;
+ OP_ASSERT(_nbytes>0);
+ buffer=(unsigned char *)ogg_sync_buffer(&_of->oy,_nbytes);
+ nbytes=(int)(*_of->callbacks.read)(_of->source,buffer,_nbytes);
+ OP_ASSERT(nbytes<=_nbytes);
+ if(OP_LIKELY(nbytes>0))ogg_sync_wrote(&_of->oy,nbytes);
+ return nbytes;
+}
+
+/*Save a tiny smidge of verbosity to make the code more readable.*/
+static int op_seek_helper(OggOpusFile *_of,opus_int64 _offset){
+ if(_offset==_of->offset)return 0;
+ if(_of->callbacks.seek==NULL
+ ||(*_of->callbacks.seek)(_of->source,_offset,SEEK_SET)){
+ return OP_EREAD;
+ }
+ _of->offset=_offset;
+ ogg_sync_reset(&_of->oy);
+ return 0;
+}
+
+/*Get the current position indicator of the underlying source.
+ This should be the same as the value reported by tell().*/
+static opus_int64 op_position(const OggOpusFile *_of){
+ /*The current position indicator is _not_ simply offset.
+ We may also have unprocessed, buffered data in the sync state.*/
+ return _of->offset+_of->oy.fill-_of->oy.returned;
+}
+
+/*From the head of the stream, get the next page.
+ _boundary specifies if the function is allowed to fetch more data from the
+ stream (and how much) or only use internally buffered data.
+ _boundary: -1: Unbounded search.
+ 0: Read no additional data.
+ Use only cached data.
+ n: Search for the start of a new page up to file position n.
+ Return: n>=0: Found a page at absolute offset n.
+ OP_FALSE: Hit the _boundary limit.
+ OP_EREAD: An underlying read operation failed.
+ OP_BADLINK: We hit end-of-file before reaching _boundary.*/
+static opus_int64 op_get_next_page(OggOpusFile *_of,ogg_page *_og,
+ opus_int64 _boundary){
+ while(_boundary<=0||_of->offset<_boundary){
+ int more;
+ more=ogg_sync_pageseek(&_of->oy,_og);
+ /*Skipped (-more) bytes.*/
+ if(OP_UNLIKELY(more<0))_of->offset-=more;
+ else if(more==0){
+ int read_nbytes;
+ int ret;
+ /*Send more paramedics.*/
+ if(!_boundary)return OP_FALSE;
+ if(_boundary<0)read_nbytes=OP_READ_SIZE;
+ else{
+ opus_int64 position;
+ position=op_position(_of);
+ if(position>=_boundary)return OP_FALSE;
+ read_nbytes=(int)OP_MIN(_boundary-position,OP_READ_SIZE);
+ }
+ ret=op_get_data(_of,read_nbytes);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ if(OP_UNLIKELY(ret==0)){
+ /*Only fail cleanly on EOF if we didn't have a known boundary.
+ Otherwise, we should have been able to reach that boundary, and this
+ is a fatal error.*/
+ return OP_UNLIKELY(_boundary<0)?OP_FALSE:OP_EBADLINK;
+ }
+ }
+ else{
+ /*Got a page.
+ Return the page start offset and advance the internal offset past the
+ page end.*/
+ opus_int64 page_offset;
+ page_offset=_of->offset;
+ _of->offset+=more;
+ OP_ASSERT(page_offset>=0);
+ return page_offset;
+ }
+ }
+ return OP_FALSE;
+}
+
+static int op_add_serialno(const ogg_page *_og,
+ ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){
+ ogg_uint32_t *serialnos;
+ int nserialnos;
+ int cserialnos;
+ ogg_uint32_t s;
+ s=ogg_page_serialno(_og);
+ serialnos=*_serialnos;
+ nserialnos=*_nserialnos;
+ cserialnos=*_cserialnos;
+ if(OP_UNLIKELY(nserialnos>=cserialnos)){
+ if(OP_UNLIKELY(cserialnos>INT_MAX/(int)sizeof(*serialnos)-1>>1)){
+ return OP_EFAULT;
+ }
+ cserialnos=2*cserialnos+1;
+ OP_ASSERT(nserialnos<cserialnos);
+ serialnos=(ogg_uint32_t *)_ogg_realloc(serialnos,
+ sizeof(*serialnos)*cserialnos);
+ if(OP_UNLIKELY(serialnos==NULL))return OP_EFAULT;
+ }
+ serialnos[nserialnos++]=s;
+ *_serialnos=serialnos;
+ *_nserialnos=nserialnos;
+ *_cserialnos=cserialnos;
+ return 0;
+}
+
+/*Returns nonzero if found.*/
+static int op_lookup_serialno(ogg_uint32_t _s,
+ const ogg_uint32_t *_serialnos,int _nserialnos){
+ int i;
+ for(i=0;i<_nserialnos&&_serialnos[i]!=_s;i++);
+ return i<_nserialnos;
+}
+
+static int op_lookup_page_serialno(const ogg_page *_og,
+ const ogg_uint32_t *_serialnos,int _nserialnos){
+ return op_lookup_serialno(ogg_page_serialno(_og),_serialnos,_nserialnos);
+}
+
+typedef struct OpusSeekRecord OpusSeekRecord;
+
+/*We use this to remember the pages we found while enumerating the links of a
+ chained stream.
+ We keep track of the starting and ending offsets, as well as the point we
+ started searching from, so we know where to bisect.
+ We also keep the serial number, so we can tell if the page belonged to the
+ current link or not, as well as the granule position, to aid in estimating
+ the start of the link.*/
+struct OpusSeekRecord{
+ /*The earliest byte we know of such that reading forward from it causes
+ capture to be regained at this page.*/
+ opus_int64 search_start;
+ /*The offset of this page.*/
+ opus_int64 offset;
+ /*The size of this page.*/
+ opus_int32 size;
+ /*The serial number of this page.*/
+ ogg_uint32_t serialno;
+ /*The granule position of this page.*/
+ ogg_int64_t gp;
+};
+
+/*Find the last page beginning before _offset with a valid granule position.
+ There is no '_boundary' parameter as it will always have to read more data.
+ This is much dirtier than the above, as Ogg doesn't have any backward search
+ linkage.
+ This search prefers pages of the specified serial number.
+ If a page of the specified serial number is spotted during the
+ seek-back-and-read-forward, it will return the info of last page of the
+ matching serial number, instead of the very last page, unless the very last
+ page belongs to a different link than preferred serial number.
+ If no page of the specified serial number is seen, it will return the info of
+ the last page.
+ [out] _sr: Returns information about the page that was found on success.
+ _offset: The _offset before which to find a page.
+ Any page returned will consist of data entirely before _offset.
+ _serialno: The preferred serial number.
+ If a page with this serial number is found, it will be returned
+ even if another page in the same link is found closer to
+ _offset.
+ This is purely opportunistic: there is no guarantee such a page
+ will be found if it exists.
+ _serialnos: The list of serial numbers in the link that contains the
+ preferred serial number.
+ _nserialnos: The number of serial numbers in the current link.
+ Return: 0 on success, or a negative value on failure.
+ OP_EREAD: Failed to read more data (error or EOF).
+ OP_EBADLINK: We couldn't find a page even after seeking back to the
+ start of the stream.*/
+static int op_get_prev_page_serial(OggOpusFile *_of,OpusSeekRecord *_sr,
+ opus_int64 _offset,ogg_uint32_t _serialno,
+ const ogg_uint32_t *_serialnos,int _nserialnos){
+ OpusSeekRecord preferred_sr;
+ ogg_page og;
+ opus_int64 begin;
+ opus_int64 end;
+ opus_int64 original_end;
+ opus_int32 chunk_size;
+ int preferred_found;
+ original_end=end=begin=_offset;
+ preferred_found=0;
+ _offset=-1;
+ chunk_size=OP_CHUNK_SIZE;
+ do{
+ opus_int64 search_start;
+ int ret;
+ OP_ASSERT(chunk_size>=OP_PAGE_SIZE_MAX);
+ begin=OP_MAX(begin-chunk_size,0);
+ ret=op_seek_helper(_of,begin);
+ if(OP_UNLIKELY(ret<0))return ret;
+ search_start=begin;
+ while(_of->offset<end){
+ opus_int64 llret;
+ ogg_uint32_t serialno;
+ llret=op_get_next_page(_of,&og,end);
+ if(OP_UNLIKELY(llret<OP_FALSE))return (int)llret;
+ else if(llret==OP_FALSE)break;
+ serialno=ogg_page_serialno(&og);
+ /*Save the information for this page.
+ We're not interested in the page itself... just the serial number, byte
+ offset, page size, and granule position.*/
+ _sr->search_start=search_start;
+ _sr->offset=_offset=llret;
+ _sr->serialno=serialno;
+ OP_ASSERT(_of->offset-_offset>=0);
+ OP_ASSERT(_of->offset-_offset<=OP_PAGE_SIZE_MAX);
+ _sr->size=(opus_int32)(_of->offset-_offset);
+ _sr->gp=ogg_page_granulepos(&og);
+ /*If this page is from the stream we're looking for, remember it.*/
+ if(serialno==_serialno){
+ preferred_found=1;
+ *&preferred_sr=*_sr;
+ }
+ if(!op_lookup_serialno(serialno,_serialnos,_nserialnos)){
+ /*We fell off the end of the link, which means we seeked back too far
+ and shouldn't have been looking in that link to begin with.
+ If we found the preferred serial number, forget that we saw it.*/
+ preferred_found=0;
+ }
+ search_start=llret+1;
+ }
+ /*We started from the beginning of the stream and found nothing.
+ This should be impossible unless the contents of the source changed out
+ from under us after we read from it.*/
+ if(OP_UNLIKELY(!begin)&&OP_UNLIKELY(_offset<0))return OP_EBADLINK;
+ /*Bump up the chunk size.
+ This is mildly helpful when seeks are very expensive (http).*/
+ chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX);
+ /*Avoid quadratic complexity if we hit an invalid patch of the file.*/
+ end=OP_MIN(begin+OP_PAGE_SIZE_MAX-1,original_end);
+ }
+ while(_offset<0);
+ if(preferred_found)*_sr=*&preferred_sr;
+ return 0;
+}
+
+/*Find the last page beginning before _offset with the given serial number and
+ a valid granule position.
+ Unlike the above search, this continues until it finds such a page, but does
+ not stray outside the current link.
+ We could implement it (inefficiently) by calling op_get_prev_page_serial()
+ repeatedly until it returned a page that had both our preferred serial
+ number and a valid granule position, but doing it with a separate function
+ allows us to avoid repeatedly re-scanning valid pages from other streams as
+ we seek-back-and-read-forward.
+ [out] _gp: Returns the granule position of the page that was found on
+ success.
+ _offset: The _offset before which to find a page.
+ Any page returned will consist of data entirely before _offset.
+ _serialno: The target serial number.
+ _serialnos: The list of serial numbers in the link that contains the
+ preferred serial number.
+ _nserialnos: The number of serial numbers in the current link.
+ Return: The offset of the page on success, or a negative value on failure.
+ OP_EREAD: Failed to read more data (error or EOF).
+ OP_EBADLINK: We couldn't find a page even after seeking back past the
+ beginning of the link.*/
+static opus_int64 op_get_last_page(OggOpusFile *_of,ogg_int64_t *_gp,
+ opus_int64 _offset,ogg_uint32_t _serialno,
+ const ogg_uint32_t *_serialnos,int _nserialnos){
+ ogg_page og;
+ ogg_int64_t gp;
+ opus_int64 begin;
+ opus_int64 end;
+ opus_int64 original_end;
+ opus_int32 chunk_size;
+ /*The target serial number must belong to the current link.*/
+ OP_ASSERT(op_lookup_serialno(_serialno,_serialnos,_nserialnos));
+ original_end=end=begin=_offset;
+ _offset=-1;
+ /*We shouldn't have to initialize gp, but gcc is too dumb to figure out that
+ ret>=0 implies we entered the if(page_gp!=-1) block at least once.*/
+ gp=-1;
+ chunk_size=OP_CHUNK_SIZE;
+ do{
+ int left_link;
+ int ret;
+ OP_ASSERT(chunk_size>=OP_PAGE_SIZE_MAX);
+ begin=OP_MAX(begin-chunk_size,0);
+ ret=op_seek_helper(_of,begin);
+ if(OP_UNLIKELY(ret<0))return ret;
+ left_link=0;
+ while(_of->offset<end){
+ opus_int64 llret;
+ ogg_uint32_t serialno;
+ llret=op_get_next_page(_of,&og,end);
+ if(OP_UNLIKELY(llret<OP_FALSE))return llret;
+ else if(llret==OP_FALSE)break;
+ serialno=ogg_page_serialno(&og);
+ if(serialno==_serialno){
+ ogg_int64_t page_gp;
+ /*The page is from the right stream...*/
+ page_gp=ogg_page_granulepos(&og);
+ if(page_gp!=-1){
+ /*And has a valid granule position.
+ Let's remember it.*/
+ _offset=llret;
+ gp=page_gp;
+ }
+ }
+ else if(OP_UNLIKELY(!op_lookup_serialno(serialno,
+ _serialnos,_nserialnos))){
+ /*We fell off the start of the link, which means we don't need to keep
+ seeking any farther back.*/
+ left_link=1;
+ }
+ }
+ /*We started from at or before the beginning of the link and found nothing.
+ This should be impossible unless the contents of the source changed out
+ from under us after we read from it.*/
+ if((OP_UNLIKELY(left_link)||OP_UNLIKELY(!begin))&&OP_UNLIKELY(_offset<0)){
+ return OP_EBADLINK;
+ }
+ /*Bump up the chunk size.
+ This is mildly helpful when seeks are very expensive (http).*/
+ chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX);
+ /*Avoid quadratic complexity if we hit an invalid patch of the file.*/
+ end=OP_MIN(begin+OP_PAGE_SIZE_MAX-1,original_end);
+ }
+ while(_offset<0);
+ *_gp=gp;
+ return _offset;
+}
+
+/*Uses the local ogg_stream storage in _of.
+ This is important for non-streaming input sources.*/
+static int op_fetch_headers_impl(OggOpusFile *_of,OpusHead *_head,
+ OpusTags *_tags,ogg_uint32_t **_serialnos,int *_nserialnos,
+ int *_cserialnos,ogg_page *_og){
+ ogg_packet op;
+ int ret;
+ if(_serialnos!=NULL)*_nserialnos=0;
+ /*Extract the serialnos of all BOS pages plus the first set of Opus headers
+ we see in the link.*/
+ while(ogg_page_bos(_og)){
+ if(_serialnos!=NULL){
+ if(OP_UNLIKELY(op_lookup_page_serialno(_og,*_serialnos,*_nserialnos))){
+ /*A dupe serialnumber in an initial header packet set==invalid stream.*/
+ return OP_EBADHEADER;
+ }
+ ret=op_add_serialno(_og,_serialnos,_nserialnos,_cserialnos);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ if(_of->ready_state<OP_STREAMSET){
+ /*We don't have an Opus stream in this link yet, so begin prospective
+ stream setup.
+ We need a stream to get packets.*/
+ ogg_stream_reset_serialno(&_of->os,ogg_page_serialno(_og));
+ ogg_stream_pagein(&_of->os,_og);
+ if(OP_LIKELY(ogg_stream_packetout(&_of->os,&op)>0)){
+ ret=opus_head_parse(_head,op.packet,op.bytes);
+ /*Found a valid Opus header.
+ Continue setup.*/
+ if(OP_LIKELY(ret>=0))_of->ready_state=OP_STREAMSET;
+ /*If it's just a stream type we don't recognize, ignore it.
+ Everything else is fatal.*/
+ else if(ret!=OP_ENOTFORMAT)return ret;
+ }
+ /*TODO: Should a BOS page with no packets be an error?*/
+ }
+ /*Get the next page.
+ No need to clamp the boundary offset against _of->end, as all errors
+ become OP_ENOTFORMAT or OP_EBADHEADER.*/
+ if(OP_UNLIKELY(op_get_next_page(_of,_og,
+ OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){
+ return _of->ready_state<OP_STREAMSET?OP_ENOTFORMAT:OP_EBADHEADER;
+ }
+ }
+ if(OP_UNLIKELY(_of->ready_state!=OP_STREAMSET))return OP_ENOTFORMAT;
+ /*If the first non-header page belonged to our Opus stream, submit it.*/
+ if(_of->os.serialno==ogg_page_serialno(_og))ogg_stream_pagein(&_of->os,_og);
+ /*Loop getting packets.*/
+ for(;;){
+ switch(ogg_stream_packetout(&_of->os,&op)){
+ case 0:{
+ /*Loop getting pages.*/
+ for(;;){
+ /*No need to clamp the boundary offset against _of->end, as all
+ errors become OP_EBADHEADER.*/
+ if(OP_UNLIKELY(op_get_next_page(_of,_og,
+ OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){
+ return OP_EBADHEADER;
+ }
+ /*If this page belongs to the correct stream, go parse it.*/
+ if(_of->os.serialno==ogg_page_serialno(_og)){
+ ogg_stream_pagein(&_of->os,_og);
+ break;
+ }
+ /*If the link ends before we see the Opus comment header, abort.*/
+ if(OP_UNLIKELY(ogg_page_bos(_og)))return OP_EBADHEADER;
+ /*Otherwise, keep looking.*/
+ }
+ }break;
+ /*We shouldn't get a hole in the headers!*/
+ case -1:return OP_EBADHEADER;
+ default:{
+ /*Got a packet.
+ It should be the comment header.*/
+ ret=opus_tags_parse(_tags,op.packet,op.bytes);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*Make sure the page terminated at the end of the comment header.
+ If there is another packet on the page, or part of a packet, then
+ reject the stream.
+ Otherwise seekable sources won't be able to seek back to the start
+ properly.*/
+ ret=ogg_stream_packetout(&_of->os,&op);
+ if(OP_UNLIKELY(ret!=0)
+ ||OP_UNLIKELY(_og->header[_og->header_len-1]==255)){
+ /*If we fail, the caller assumes our tags are uninitialized.*/
+ opus_tags_clear(_tags);
+ return OP_EBADHEADER;
+ }
+ return 0;
+ }
+ }
+ }
+}
+
+static int op_fetch_headers(OggOpusFile *_of,OpusHead *_head,
+ OpusTags *_tags,ogg_uint32_t **_serialnos,int *_nserialnos,
+ int *_cserialnos,ogg_page *_og){
+ ogg_page og;
+ int ret;
+ if(!_og){
+ /*No need to clamp the boundary offset against _of->end, as all errors
+ become OP_ENOTFORMAT.*/
+ if(OP_UNLIKELY(op_get_next_page(_of,&og,
+ OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){
+ return OP_ENOTFORMAT;
+ }
+ _og=&og;
+ }
+ _of->ready_state=OP_OPENED;
+ ret=op_fetch_headers_impl(_of,_head,_tags,_serialnos,_nserialnos,
+ _cserialnos,_og);
+ /*Revert back from OP_STREAMSET to OP_OPENED on failure, to prevent
+ double-free of the tags in an unseekable stream.*/
+ if(OP_UNLIKELY(ret<0))_of->ready_state=OP_OPENED;
+ return ret;
+}
+
+/*Granule position manipulation routines.
+ A granule position is defined to be an unsigned 64-bit integer, with the
+ special value -1 in two's complement indicating an unset or invalid granule
+ position.
+ We are not guaranteed to have an unsigned 64-bit type, so we construct the
+ following routines that
+ a) Properly order negative numbers as larger than positive numbers, and
+ b) Check for underflow or overflow past the special -1 value.
+ This lets us operate on the full, valid range of granule positions in a
+ consistent and safe manner.
+ This full range is organized into distinct regions:
+ [ -1 (invalid) ][ 0 ... OP_INT64_MAX ][ OP_INT64_MIN ... -2 ][-1 (invalid) ]
+
+ No one should actually use granule positions so large that they're negative,
+ even if they are technically valid, as very little software handles them
+ correctly (including most of Xiph.Org's).
+ This library also refuses to support durations so large they won't fit in a
+ signed 64-bit integer (to avoid exposing this mess to the application, and
+ to simplify a good deal of internal arithmetic), so the only way to use them
+ successfully is if pcm_start is very large.
+ This means there isn't anything you can do with negative granule positions
+ that you couldn't have done with purely non-negative ones.
+ The main purpose of these routines is to allow us to think very explicitly
+ about the possible failure cases of all granule position manipulations.*/
+
+/*Safely adds a small signed integer to a valid (not -1) granule position.
+ The result can use the full 64-bit range of values (both positive and
+ negative), but will fail on overflow (wrapping past -1; wrapping past
+ OP_INT64_MAX is explicitly okay).
+ [out] _dst_gp: The resulting granule position.
+ Only modified on success.
+ _src_gp: The granule position to add to.
+ This must not be -1.
+ _delta: The amount to add.
+ This is allowed to be up to 32 bits to support the maximum
+ duration of a single Ogg page (255 packets * 120 ms per
+ packet == 1,468,800 samples at 48 kHz).
+ Return: 0 on success, or OP_EINVAL if the result would wrap around past -1.*/
+static int op_granpos_add(ogg_int64_t *_dst_gp,ogg_int64_t _src_gp,
+ opus_int32 _delta){
+ /*The code below handles this case correctly, but there's no reason we
+ should ever be called with these values, so make sure we aren't.*/
+ OP_ASSERT(_src_gp!=-1);
+ if(_delta>0){
+ /*Adding this amount to the granule position would overflow its 64-bit
+ range.*/
+ if(OP_UNLIKELY(_src_gp<0)&&OP_UNLIKELY(_src_gp>=-1-_delta))return OP_EINVAL;
+ if(OP_UNLIKELY(_src_gp>OP_INT64_MAX-_delta)){
+ /*Adding this amount to the granule position would overflow the positive
+ half of its 64-bit range.
+ Since signed overflow is undefined in C, do it in a way the compiler
+ isn't allowed to screw up.*/
+ _delta-=(opus_int32)(OP_INT64_MAX-_src_gp)+1;
+ _src_gp=OP_INT64_MIN;
+ }
+ }
+ else if(_delta<0){
+ /*Subtracting this amount from the granule position would underflow its
+ 64-bit range.*/
+ if(_src_gp>=0&&OP_UNLIKELY(_src_gp<-_delta))return OP_EINVAL;
+ if(OP_UNLIKELY(_src_gp<OP_INT64_MIN-_delta)){
+ /*Subtracting this amount from the granule position would underflow the
+ negative half of its 64-bit range.
+ Since signed underflow is undefined in C, do it in a way the compiler
+ isn't allowed to screw up.*/
+ _delta+=(opus_int32)(_src_gp-OP_INT64_MIN)+1;
+ _src_gp=OP_INT64_MAX;
+ }
+ }
+ *_dst_gp=_src_gp+_delta;
+ return 0;
+}
+
+/*Safely computes the difference between two granule positions.
+ The difference must fit in a signed 64-bit integer, or the function fails.
+ It correctly handles the case where the granule position has wrapped around
+ from positive values to negative ones.
+ [out] _delta: The difference between the granule positions.
+ Only modified on success.
+ _gp_a: The granule position to subtract from.
+ This must not be -1.
+ _gp_b: The granule position to subtract.
+ This must not be -1.
+ Return: 0 on success, or OP_EINVAL if the result would not fit in a signed
+ 64-bit integer.*/
+static int op_granpos_diff(ogg_int64_t *_delta,
+ ogg_int64_t _gp_a,ogg_int64_t _gp_b){
+ int gp_a_negative;
+ int gp_b_negative;
+ /*The code below handles these cases correctly, but there's no reason we
+ should ever be called with these values, so make sure we aren't.*/
+ OP_ASSERT(_gp_a!=-1);
+ OP_ASSERT(_gp_b!=-1);
+ gp_a_negative=OP_UNLIKELY(_gp_a<0);
+ gp_b_negative=OP_UNLIKELY(_gp_b<0);
+ if(OP_UNLIKELY(gp_a_negative^gp_b_negative)){
+ ogg_int64_t da;
+ ogg_int64_t db;
+ if(gp_a_negative){
+ /*_gp_a has wrapped to a negative value but _gp_b hasn't: the difference
+ should be positive.*/
+ /*Step 1: Handle wrapping.*/
+ /*_gp_a < 0 => da < 0.*/
+ da=(OP_INT64_MIN-_gp_a)-1;
+ /*_gp_b >= 0 => db >= 0.*/
+ db=OP_INT64_MAX-_gp_b;
+ /*Step 2: Check for overflow.*/
+ if(OP_UNLIKELY(OP_INT64_MAX+da<db))return OP_EINVAL;
+ *_delta=db-da;
+ }
+ else{
+ /*_gp_b has wrapped to a negative value but _gp_a hasn't: the difference
+ should be negative.*/
+ /*Step 1: Handle wrapping.*/
+ /*_gp_a >= 0 => da <= 0*/
+ da=_gp_a+OP_INT64_MIN;
+ /*_gp_b < 0 => db <= 0*/
+ db=OP_INT64_MIN-_gp_b;
+ /*Step 2: Check for overflow.*/
+ if(OP_UNLIKELY(da<OP_INT64_MIN-db))return OP_EINVAL;
+ *_delta=da+db;
+ }
+ }
+ else *_delta=_gp_a-_gp_b;
+ return 0;
+}
+
+static int op_granpos_cmp(ogg_int64_t _gp_a,ogg_int64_t _gp_b){
+ /*The invalid granule position -1 should behave like NaN: neither greater
+ than nor less than any other granule position, nor equal to any other
+ granule position, including itself.
+ However, that means there isn't anything we could sensibly return from this
+ function for it.*/
+ OP_ASSERT(_gp_a!=-1);
+ OP_ASSERT(_gp_b!=-1);
+ /*Handle the wrapping cases.*/
+ if(OP_UNLIKELY(_gp_a<0)){
+ if(_gp_b>=0)return 1;
+ /*Else fall through.*/
+ }
+ else if(OP_UNLIKELY(_gp_b<0))return -1;
+ /*No wrapping case.*/
+ return (_gp_a>_gp_b)-(_gp_b>_gp_a);
+}
+
+/*Returns the duration of the packet (in samples at 48 kHz), or a negative
+ value on error.*/
+static int op_get_packet_duration(const unsigned char *_data,int _len){
+ int nframes;
+ int frame_size;
+ int nsamples;
+ nframes=opus_packet_get_nb_frames(_data,_len);
+ if(OP_UNLIKELY(nframes<0))return OP_EBADPACKET;
+ frame_size=opus_packet_get_samples_per_frame(_data,48000);
+ nsamples=nframes*frame_size;
+ if(OP_UNLIKELY(nsamples>120*48))return OP_EBADPACKET;
+ return nsamples;
+}
+
+/*This function more properly belongs in info.c, but we define it here to allow
+ the static granule position manipulation functions to remain static.*/
+ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp){
+ opus_int32 pre_skip;
+ pre_skip=_head->pre_skip;
+ if(_gp!=-1&&op_granpos_add(&_gp,_gp,-pre_skip))_gp=-1;
+ return _gp;
+}
+
+/*Grab all the packets currently in the stream state, and compute their
+ durations.
+ _of->op_count is set to the number of packets collected.
+ [out] _durations: Returns the durations of the individual packets.
+ Return: The total duration of all packets, or OP_HOLE if there was a hole.*/
+static opus_int32 op_collect_audio_packets(OggOpusFile *_of,
+ int _durations[255]){
+ opus_int32 total_duration;
+ int op_count;
+ /*Count the durations of all packets in the page.*/
+ op_count=0;
+ total_duration=0;
+ for(;;){
+ int ret;
+ /*This takes advantage of undocumented libogg behavior that returned
+ ogg_packet buffers are valid at least until the next page is
+ submitted.
+ Relying on this is not too terrible, as _none_ of the Ogg memory
+ ownership/lifetime rules are well-documented.
+ But I can read its code and know this will work.*/
+ ret=ogg_stream_packetout(&_of->os,_of->op+op_count);
+ if(!ret)break;
+ if(OP_UNLIKELY(ret<0)){
+ /*We shouldn't get holes in the middle of pages.*/
+ OP_ASSERT(op_count==0);
+ /*Set the return value and break out of the loop.
+ We want to make sure op_count gets set to 0, because we've ingested a
+ page, so any previously loaded packets are now invalid.*/
+ total_duration=OP_HOLE;
+ break;
+ }
+ /*Unless libogg is broken, we can't get more than 255 packets from a
+ single page.*/
+ OP_ASSERT(op_count<255);
+ _durations[op_count]=op_get_packet_duration(_of->op[op_count].packet,
+ _of->op[op_count].bytes);
+ if(OP_LIKELY(_durations[op_count]>0)){
+ /*With at most 255 packets on a page, this can't overflow.*/
+ total_duration+=_durations[op_count++];
+ }
+ /*Ignore packets with an invalid TOC sequence.*/
+ else if(op_count>0){
+ /*But save the granule position, if there was one.*/
+ _of->op[op_count-1].granulepos=_of->op[op_count].granulepos;
+ }
+ }
+ _of->op_pos=0;
+ _of->op_count=op_count;
+ return total_duration;
+}
+
+/*Starting from current cursor position, get the initial PCM offset of the next
+ page.
+ This also validates the granule position on the first page with a completed
+ audio data packet, as required by the spec.
+ If this link is completely empty (no pages with completed packets), then this
+ function sets pcm_start=pcm_end=0 and returns the BOS page of the next link
+ (if any).
+ In the seekable case, we initialize pcm_end=-1 before calling this function,
+ so that later we can detect that the link was empty before calling
+ op_find_final_pcm_offset().
+ [inout] _link: The link for which to find pcm_start.
+ [out] _og: Returns the BOS page of the next link if this link was empty.
+ In the unseekable case, we can then feed this to
+ op_fetch_headers() to start the next link.
+ The caller may pass NULL (e.g., for seekable streams), in
+ which case this page will be discarded.
+ Return: 0 on success, 1 if there is a buffered BOS page available, or a
+ negative value on unrecoverable error.*/
+static int op_find_initial_pcm_offset(OggOpusFile *_of,
+ OggOpusLink *_link,ogg_page *_og){
+ ogg_page og;
+ opus_int64 page_offset;
+ ogg_int64_t pcm_start;
+ ogg_int64_t prev_packet_gp;
+ ogg_int64_t cur_page_gp;
+ ogg_uint32_t serialno;
+ opus_int32 total_duration;
+ int durations[255];
+ int cur_page_eos;
+ int op_count;
+ int pi;
+ if(_og==NULL)_og=&og;
+ serialno=_of->os.serialno;
+ op_count=0;
+ /*We shouldn't have to initialize total_duration, but gcc is too dumb to
+ figure out that op_count>0 implies we've been through the whole loop at
+ least once.*/
+ total_duration=0;
+ do{
+ page_offset=op_get_next_page(_of,_og,_of->end);
+ /*We should get a page unless the file is truncated or mangled.
+ Otherwise there are no audio data packets in the whole logical stream.*/
+ if(OP_UNLIKELY(page_offset<0)){
+ /*Fail if there was a read error.*/
+ if(page_offset<OP_FALSE)return (int)page_offset;
+ /*Fail if the pre-skip is non-zero, since it's asking us to skip more
+ samples than exist.*/
+ if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP;
+ /*Set pcm_end and end_offset so we can skip the call to
+ op_find_final_pcm_offset().*/
+ _link->pcm_start=_link->pcm_end=0;
+ _link->end_offset=_link->data_offset;
+ return 0;
+ }
+ /*Similarly, if we hit the next link in the chain, we've gone too far.*/
+ if(OP_UNLIKELY(ogg_page_bos(_og))){
+ if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP;
+ /*Set pcm_end and end_offset so we can skip the call to
+ op_find_final_pcm_offset().*/
+ _link->pcm_end=_link->pcm_start=0;
+ _link->end_offset=_link->data_offset;
+ /*Tell the caller we've got a buffered page for them.*/
+ return 1;
+ }
+ /*Ignore pages from other streams (not strictly necessary, because of the
+ checks in ogg_stream_pagein(), but saves some work).*/
+ if(serialno!=(ogg_uint32_t)ogg_page_serialno(_og))continue;
+ ogg_stream_pagein(&_of->os,_og);
+ /*Bitrate tracking: add the header's bytes here.
+ The body bytes are counted when we consume the packets.*/
+ _of->bytes_tracked+=_og->header_len;
+ /*Count the durations of all packets in the page.*/
+ do total_duration=op_collect_audio_packets(_of,durations);
+ /*Ignore holes.*/
+ while(OP_UNLIKELY(total_duration<0));
+ op_count=_of->op_count;
+ }
+ while(op_count<=0);
+ /*We found the first page with a completed audio data packet: actually look
+ at the granule position.
+ RFC 3533 says, "A special value of -1 (in two's complement) indicates that
+ no packets finish on this page," which does not say that a granule
+ position that is NOT -1 indicates that some packets DO finish on that page
+ (even though this was the intention, libogg itself violated this intention
+ for years before we fixed it).
+ The Ogg Opus specification only imposes its start-time requirements
+ on the granule position of the first page with completed packets,
+ so we ignore any set granule positions until then.*/
+ cur_page_gp=_of->op[op_count-1].granulepos;
+ /*But getting a packet without a valid granule position on the page is not
+ okay.*/
+ if(cur_page_gp==-1)return OP_EBADTIMESTAMP;
+ cur_page_eos=_of->op[op_count-1].e_o_s;
+ if(OP_LIKELY(!cur_page_eos)){
+ /*The EOS flag wasn't set.
+ Work backwards from the provided granule position to get the starting PCM
+ offset.*/
+ if(OP_UNLIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){
+ /*The starting granule position MUST not be smaller than the amount of
+ audio on the first page with completed packets.*/
+ return OP_EBADTIMESTAMP;
+ }
+ }
+ else{
+ /*The first page with completed packets was also the last.*/
+ if(OP_LIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){
+ /*If there's less audio on the page than indicated by the granule
+ position, then we're doing end-trimming, and the starting PCM offset
+ is zero by spec mandate.*/
+ pcm_start=0;
+ /*However, the end-trimming MUST not ask us to trim more samples than
+ exist after applying the pre-skip.*/
+ if(OP_UNLIKELY(op_granpos_cmp(cur_page_gp,_link->head.pre_skip)<0)){
+ return OP_EBADTIMESTAMP;
+ }
+ }
+ }
+ /*Timestamp the individual packets.*/
+ prev_packet_gp=pcm_start;
+ for(pi=0;pi<op_count;pi++){
+ if(cur_page_eos){
+ ogg_int64_t diff=0;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,cur_page_gp,prev_packet_gp));
+ diff=durations[pi]-diff;
+ /*If we have samples to trim...*/
+ if(diff>0){
+ /*If we trimmed the entire packet, stop (the spec says encoders
+ shouldn't do this, but we support it anyway).*/
+ if(OP_UNLIKELY(diff>durations[pi]))break;
+ _of->op[pi].granulepos=prev_packet_gp=cur_page_gp;
+ /*Move the EOS flag to this packet, if necessary, so we'll trim the
+ samples.*/
+ _of->op[pi].e_o_s=1;
+ continue;
+ }
+ }
+ /*Update the granule position as normal.*/
+ OP_ALWAYS_TRUE(!op_granpos_add(&_of->op[pi].granulepos,
+ prev_packet_gp,durations[pi]));
+ prev_packet_gp=_of->op[pi].granulepos;
+ }
+ /*Update the packet count after end-trimming.*/
+ _of->op_count=pi;
+ _of->cur_discard_count=_link->head.pre_skip;
+ _of->prev_packet_gp=_link->pcm_start=pcm_start;
+ _of->prev_page_offset=page_offset;
+ return 0;
+}
+
+/*Starting from current cursor position, get the final PCM offset of the
+ previous page.
+ This also validates the duration of the link, which, while not strictly
+ required by the spec, we need to ensure duration calculations don't
+ overflow.
+ This is only done for seekable sources.
+ We must validate that op_find_initial_pcm_offset() succeeded for this link
+ before calling this function, otherwise it will scan the entire stream
+ backwards until it reaches the start, and then fail.*/
+static int op_find_final_pcm_offset(OggOpusFile *_of,
+ const ogg_uint32_t *_serialnos,int _nserialnos,OggOpusLink *_link,
+ opus_int64 _offset,ogg_uint32_t _end_serialno,ogg_int64_t _end_gp,
+ ogg_int64_t *_total_duration){
+ ogg_int64_t total_duration;
+ ogg_int64_t duration;
+ ogg_uint32_t cur_serialno;
+ /*For the time being, fetch end PCM offset the simple way.*/
+ cur_serialno=_link->serialno;
+ if(_end_serialno!=cur_serialno||_end_gp==-1){
+ _offset=op_get_last_page(_of,&_end_gp,_offset,
+ cur_serialno,_serialnos,_nserialnos);
+ if(OP_UNLIKELY(_offset<0))return (int)_offset;
+ }
+ /*At worst we should have found the first page with completed packets.*/
+ if(OP_UNLIKELY(_offset<_link->data_offset))return OP_EBADLINK;
+ /*This implementation requires that the difference between the first and last
+ granule positions in each link be representable in a signed, 64-bit
+ number, and that each link also have at least as many samples as the
+ pre-skip requires.*/
+ if(OP_UNLIKELY(op_granpos_diff(&duration,_end_gp,_link->pcm_start)<0)
+ ||OP_UNLIKELY(duration<_link->head.pre_skip)){
+ return OP_EBADTIMESTAMP;
+ }
+ /*We also require that the total duration be representable in a signed,
+ 64-bit number.*/
+ duration-=_link->head.pre_skip;
+ total_duration=*_total_duration;
+ if(OP_UNLIKELY(OP_INT64_MAX-duration<total_duration))return OP_EBADTIMESTAMP;
+ *_total_duration=total_duration+duration;
+ _link->pcm_end=_end_gp;
+ _link->end_offset=_offset;
+ return 0;
+}
+
+/*Rescale the number _x from the range [0,_from] to [0,_to].
+ _from and _to must be positive.*/
+static opus_int64 op_rescale64(opus_int64 _x,opus_int64 _from,opus_int64 _to){
+ opus_int64 frac;
+ opus_int64 ret;
+ int i;
+ if(_x>=_from)return _to;
+ if(_x<=0)return 0;
+ frac=0;
+ for(i=0;i<63;i++){
+ frac<<=1;
+ OP_ASSERT(_x<=_from);
+ if(_x>=_from>>1){
+ _x-=_from-_x;
+ frac|=1;
+ }
+ else _x<<=1;
+ }
+ ret=0;
+ for(i=0;i<63;i++){
+ if(frac&1)ret=(ret&_to&1)+(ret>>1)+(_to>>1);
+ else ret>>=1;
+ frac>>=1;
+ }
+ return ret;
+}
+
+/*The minimum granule position spacing allowed for making predictions.
+ This corresponds to about 1 second of audio at 48 kHz for both Opus and
+ Vorbis, or one keyframe interval in Theora with the default keyframe spacing
+ of 256.*/
+#define OP_GP_SPACING_MIN (48000)
+
+/*Try to estimate the location of the next link using the current seek
+ records, assuming the initial granule position of any streams we've found is
+ 0.*/
+static opus_int64 op_predict_link_start(const OpusSeekRecord *_sr,int _nsr,
+ opus_int64 _searched,opus_int64 _end_searched,opus_int32 _bias){
+ opus_int64 bisect;
+ int sri;
+ int srj;
+ /*Require that we be at least OP_CHUNK_SIZE from the end.
+ We don't require that we be at least OP_CHUNK_SIZE from the beginning,
+ because if we are we'll just scan forward without seeking.*/
+ _end_searched-=OP_CHUNK_SIZE;
+ if(_searched>=_end_searched)return -1;
+ bisect=_end_searched;
+ for(sri=0;sri<_nsr;sri++){
+ ogg_int64_t gp1;
+ ogg_int64_t gp2_min;
+ ogg_uint32_t serialno1;
+ opus_int64 offset1;
+ /*If the granule position is negative, either it's invalid or we'd cause
+ overflow.*/
+ gp1=_sr[sri].gp;
+ if(gp1<0)continue;
+ /*We require some minimum distance between granule positions to make an
+ estimate.
+ We don't actually know what granule position scheme is being used,
+ because we have no idea what kind of stream these came from.
+ Therefore we require a minimum spacing between them, with the
+ expectation that while bitrates and granule position increments might
+ vary locally in quite complex ways, they are globally smooth.*/
+ if(OP_UNLIKELY(op_granpos_add(&gp2_min,gp1,OP_GP_SPACING_MIN)<0)){
+ /*No granule position would satisfy us.*/
+ continue;
+ }
+ offset1=_sr[sri].offset;
+ serialno1=_sr[sri].serialno;
+ for(srj=sri;srj-->0;){
+ ogg_int64_t gp2;
+ opus_int64 offset2;
+ opus_int64 num;
+ ogg_int64_t den;
+ ogg_int64_t ipart;
+ gp2=_sr[srj].gp;
+ if(gp2<gp2_min)continue;
+ /*Oh, and also make sure these came from the same stream.*/
+ if(_sr[srj].serialno!=serialno1)continue;
+ offset2=_sr[srj].offset;
+ /*For once, we can subtract with impunity.*/
+ den=gp2-gp1;
+ ipart=gp2/den;
+ num=offset2-offset1;
+ OP_ASSERT(num>0);
+ if(ipart>0&&(offset2-_searched)/ipart<num)continue;
+ offset2-=ipart*num;
+ gp2-=ipart*den;
+ offset2-=op_rescale64(gp2,den,num)-_bias;
+ if(offset2<_searched)continue;
+ bisect=OP_MIN(bisect,offset2);
+ break;
+ }
+ }
+ return bisect>=_end_searched?-1:bisect;
+}
+
+/*Finds each bitstream link, one at a time, using a bisection search.
+ This has to begin by knowing the offset of the first link's initial page.*/
+static int op_bisect_forward_serialno(OggOpusFile *_of,
+ opus_int64 _searched,OpusSeekRecord *_sr,int _csr,
+ ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){
+ ogg_page og;
+ OggOpusLink *links;
+ int nlinks;
+ int clinks;
+ ogg_uint32_t *serialnos;
+ int nserialnos;
+ ogg_int64_t total_duration;
+ int nsr;
+ int ret;
+ links=_of->links;
+ nlinks=clinks=_of->nlinks;
+ total_duration=0;
+ /*We start with one seek record, for the last page in the file.
+ We build up a list of records for places we seek to during link
+ enumeration.
+ This list is kept sorted in reverse order.
+ We only care about seek locations that were _not_ in the current link,
+ therefore we can add them one at a time to the end of the list as we
+ improve the lower bound on the location where the next link starts.*/
+ nsr=1;
+ for(;;){
+ opus_int64 end_searched;
+ opus_int64 bisect;
+ opus_int64 next;
+ opus_int64 last;
+ ogg_int64_t end_offset;
+ ogg_int64_t end_gp;
+ int sri;
+ serialnos=*_serialnos;
+ nserialnos=*_nserialnos;
+ if(OP_UNLIKELY(nlinks>=clinks)){
+ if(OP_UNLIKELY(clinks>INT_MAX-1>>1))return OP_EFAULT;
+ clinks=2*clinks+1;
+ OP_ASSERT(nlinks<clinks);
+ links=(OggOpusLink *)_ogg_realloc(links,sizeof(*links)*clinks);
+ if(OP_UNLIKELY(links==NULL))return OP_EFAULT;
+ _of->links=links;
+ }
+ /*Invariants:
+ We have the headers and serial numbers for the link beginning at 'begin'.
+ We have the offset and granule position of the last page in the file
+ (potentially not a page we care about).*/
+ /*Scan the seek records we already have to save us some bisection.*/
+ for(sri=0;sri<nsr;sri++){
+ if(op_lookup_serialno(_sr[sri].serialno,serialnos,nserialnos))break;
+ }
+ /*Is the last page in our current list of serial numbers?*/
+ if(sri<=0)break;
+ /*Last page wasn't found.
+ We have at least one more link.*/
+ last=-1;
+ end_searched=_sr[sri-1].search_start;
+ next=_sr[sri-1].offset;
+ end_gp=-1;
+ if(sri<nsr){
+ _searched=_sr[sri].offset+_sr[sri].size;
+ if(_sr[sri].serialno==links[nlinks-1].serialno){
+ end_gp=_sr[sri].gp;
+ end_offset=_sr[sri].offset;
+ }
+ }
+ nsr=sri;
+ bisect=-1;
+ /*If we've already found the end of at least one link, try to pick the
+ first bisection point at twice the average link size.
+ This is a good choice for files with lots of links that are all about the
+ same size.*/
+ if(nlinks>1){
+ opus_int64 last_offset;
+ opus_int64 avg_link_size;
+ opus_int64 upper_limit;
+ last_offset=links[nlinks-1].offset;
+ avg_link_size=last_offset/(nlinks-1);
+ upper_limit=end_searched-OP_CHUNK_SIZE-avg_link_size;
+ if(OP_LIKELY(last_offset>_searched-avg_link_size)
+ &&OP_LIKELY(last_offset<upper_limit)){
+ bisect=last_offset+avg_link_size;
+ if(OP_LIKELY(bisect<upper_limit))bisect+=avg_link_size;
+ }
+ }
+ /*We guard against garbage separating the last and first pages of two
+ links below.*/
+ while(_searched<end_searched){
+ opus_int32 next_bias;
+ /*If we don't have a better estimate, use simple bisection.*/
+ if(bisect==-1)bisect=_searched+(end_searched-_searched>>1);
+ /*If we're within OP_CHUNK_SIZE of the start, scan forward.*/
+ if(bisect-_searched<OP_CHUNK_SIZE)bisect=_searched;
+ /*Otherwise we're skipping data.
+ Forget the end page, if we saw one, as we might miss a later one.*/
+ else end_gp=-1;
+ ret=op_seek_helper(_of,bisect);
+ if(OP_UNLIKELY(ret<0))return ret;
+ last=op_get_next_page(_of,&og,_sr[nsr-1].offset);
+ if(OP_UNLIKELY(last<OP_FALSE))return (int)last;
+ next_bias=0;
+ if(last==OP_FALSE)end_searched=bisect;
+ else{
+ ogg_uint32_t serialno;
+ ogg_int64_t gp;
+ serialno=ogg_page_serialno(&og);
+ gp=ogg_page_granulepos(&og);
+ if(!op_lookup_serialno(serialno,serialnos,nserialnos)){
+ end_searched=bisect;
+ next=last;
+ /*In reality we should always have enough room, but be paranoid.*/
+ if(OP_LIKELY(nsr<_csr)){
+ _sr[nsr].search_start=bisect;
+ _sr[nsr].offset=last;
+ OP_ASSERT(_of->offset-last>=0);
+ OP_ASSERT(_of->offset-last<=OP_PAGE_SIZE_MAX);
+ _sr[nsr].size=(opus_int32)(_of->offset-last);
+ _sr[nsr].serialno=serialno;
+ _sr[nsr].gp=gp;
+ nsr++;
+ }
+ }
+ else{
+ _searched=_of->offset;
+ next_bias=OP_CHUNK_SIZE;
+ if(serialno==links[nlinks-1].serialno){
+ /*This page was from the stream we want, remember it.
+ If it's the last such page in the link, we won't have to go back
+ looking for it later.*/
+ end_gp=gp;
+ end_offset=last;
+ }
+ }
+ }
+ bisect=op_predict_link_start(_sr,nsr,_searched,end_searched,next_bias);
+ }
+ /*Bisection point found.
+ Get the final granule position of the previous link, assuming
+ op_find_initial_pcm_offset() didn't already determine the link was
+ empty.*/
+ if(OP_LIKELY(links[nlinks-1].pcm_end==-1)){
+ if(end_gp==-1){
+ /*If we don't know where the end page is, we'll have to seek back and
+ look for it, starting from the end of the link.*/
+ end_offset=next;
+ /*Also forget the last page we read.
+ It won't be available after the seek.*/
+ last=-1;
+ }
+ ret=op_find_final_pcm_offset(_of,serialnos,nserialnos,
+ links+nlinks-1,end_offset,links[nlinks-1].serialno,end_gp,
+ &total_duration);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ if(last!=next){
+ /*The last page we read was not the first page the next link.
+ Move the cursor position to the offset of that first page.
+ This only performs an actual seek if the first page of the next link
+ does not start at the end of the last page from the current Opus
+ stream with a valid granule position.*/
+ ret=op_seek_helper(_of,next);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ ret=op_fetch_headers(_of,&links[nlinks].head,&links[nlinks].tags,
+ _serialnos,_nserialnos,_cserialnos,last!=next?NULL:&og);
+ if(OP_UNLIKELY(ret<0))return ret;
+ links[nlinks].offset=next;
+ links[nlinks].data_offset=_of->offset;
+ links[nlinks].serialno=_of->os.serialno;
+ links[nlinks].pcm_end=-1;
+ /*This might consume a page from the next link, however the next bisection
+ always starts with a seek.*/
+ ret=op_find_initial_pcm_offset(_of,links+nlinks,NULL);
+ if(OP_UNLIKELY(ret<0))return ret;
+ _searched=_of->offset;
+ /*Mark the current link count so it can be cleaned up on error.*/
+ _of->nlinks=++nlinks;
+ }
+ /*Last page is in the starting serialno list, so we've reached the last link.
+ Now find the last granule position for it (if we didn't the first time we
+ looked at the end of the stream, and if op_find_initial_pcm_offset()
+ didn't already determine the link was empty).*/
+ if(OP_LIKELY(links[nlinks-1].pcm_end==-1)){
+ ret=op_find_final_pcm_offset(_of,serialnos,nserialnos,
+ links+nlinks-1,_sr[0].offset,_sr[0].serialno,_sr[0].gp,&total_duration);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ /*Trim back the links array if necessary.*/
+ links=(OggOpusLink *)_ogg_realloc(links,sizeof(*links)*nlinks);
+ if(OP_LIKELY(links!=NULL))_of->links=links;
+ /*We also don't need these anymore.*/
+ _ogg_free(*_serialnos);
+ *_serialnos=NULL;
+ *_cserialnos=*_nserialnos=0;
+ return 0;
+}
+
+static void op_update_gain(OggOpusFile *_of){
+ OpusHead *head;
+ opus_int32 gain_q8;
+ int li;
+ /*If decode isn't ready, then we'll apply the gain when we initialize the
+ decoder.*/
+ if(_of->ready_state<OP_INITSET)return;
+ gain_q8=_of->gain_offset_q8;
+ li=_of->seekable?_of->cur_link:0;
+ head=&_of->links[li].head;
+ /*We don't have to worry about overflow here because the header gain and
+ track gain must lie in the range [-32768,32767], and the user-supplied
+ offset has been pre-clamped to [-98302,98303].*/
+ switch(_of->gain_type){
+ case OP_ALBUM_GAIN:{
+ int album_gain_q8;
+ album_gain_q8=0;
+ opus_tags_get_album_gain(&_of->links[li].tags,&album_gain_q8);
+ gain_q8+=album_gain_q8;
+ gain_q8+=head->output_gain;
+ }break;
+ case OP_TRACK_GAIN:{
+ int track_gain_q8;
+ track_gain_q8=0;
+ opus_tags_get_track_gain(&_of->links[li].tags,&track_gain_q8);
+ gain_q8+=track_gain_q8;
+ gain_q8+=head->output_gain;
+ }break;
+ case OP_HEADER_GAIN:gain_q8+=head->output_gain;break;
+ case OP_ABSOLUTE_GAIN:break;
+ default:OP_ASSERT(0);
+ }
+ gain_q8=OP_CLAMP(-32768,gain_q8,32767);
+ OP_ASSERT(_of->od!=NULL);
+#if defined(OPUS_SET_GAIN)
+ opus_multistream_decoder_ctl(_of->od,OPUS_SET_GAIN(gain_q8));
+#else
+/*A fallback that works with both float and fixed-point is a bunch of work,
+ so just force people to use a sufficiently new version.
+ This is deployed well enough at this point that this shouldn't be a burden.*/
+# error "libopus 1.0.1 or later required"
+#endif
+}
+
+static int op_make_decode_ready(OggOpusFile *_of){
+ const OpusHead *head;
+ int li;
+ int stream_count;
+ int coupled_count;
+ int channel_count;
+ if(_of->ready_state>OP_STREAMSET)return 0;
+ if(OP_UNLIKELY(_of->ready_state<OP_STREAMSET))return OP_EFAULT;
+ li=_of->seekable?_of->cur_link:0;
+ head=&_of->links[li].head;
+ stream_count=head->stream_count;
+ coupled_count=head->coupled_count;
+ channel_count=head->channel_count;
+ /*Check to see if the current decoder is compatible with the current link.*/
+ if(_of->od!=NULL&&_of->od_stream_count==stream_count
+ &&_of->od_coupled_count==coupled_count&&_of->od_channel_count==channel_count
+ &&memcmp(_of->od_mapping,head->mapping,
+ sizeof(*head->mapping)*channel_count)==0){
+ opus_multistream_decoder_ctl(_of->od,OPUS_RESET_STATE);
+ }
+ else{
+ int err;
+ opus_multistream_decoder_destroy(_of->od);
+ _of->od=opus_multistream_decoder_create(48000,channel_count,
+ stream_count,coupled_count,head->mapping,&err);
+ if(_of->od==NULL)return OP_EFAULT;
+ _of->od_stream_count=stream_count;
+ _of->od_coupled_count=coupled_count;
+ _of->od_channel_count=channel_count;
+ memcpy(_of->od_mapping,head->mapping,sizeof(*head->mapping)*channel_count);
+ }
+ _of->ready_state=OP_INITSET;
+ _of->bytes_tracked=0;
+ _of->samples_tracked=0;
+#if !defined(OP_FIXED_POINT)
+ _of->state_channel_count=0;
+ /*Use the serial number for the PRNG seed to get repeatable output for
+ straight play-throughs.*/
+ _of->dither_seed=_of->links[li].serialno;
+#endif
+ op_update_gain(_of);
+ return 0;
+}
+
+static int op_open_seekable2_impl(OggOpusFile *_of){
+ /*64 seek records should be enough for anybody.
+ Actually, with a bisection search in a 63-bit range down to OP_CHUNK_SIZE
+ granularity, much more than enough.*/
+ OpusSeekRecord sr[64];
+ opus_int64 data_offset;
+ int ret;
+ /*We can seek, so set out learning all about this file.*/
+ (*_of->callbacks.seek)(_of->source,0,SEEK_END);
+ _of->offset=_of->end=(*_of->callbacks.tell)(_of->source);
+ if(OP_UNLIKELY(_of->end<0))return OP_EREAD;
+ data_offset=_of->links[0].data_offset;
+ if(OP_UNLIKELY(_of->end<data_offset))return OP_EBADLINK;
+ /*Get the offset of the last page of the physical bitstream, or, if we're
+ lucky, the last Opus page of the first link, as most Ogg Opus files will
+ contain a single logical bitstream.*/
+ ret=op_get_prev_page_serial(_of,sr,_of->end,
+ _of->links[0].serialno,_of->serialnos,_of->nserialnos);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*If there's any trailing junk, forget about it.*/
+ _of->end=sr[0].offset+sr[0].size;
+ if(OP_UNLIKELY(_of->end<data_offset))return OP_EBADLINK;
+ /*Now enumerate the bitstream structure.*/
+ return op_bisect_forward_serialno(_of,data_offset,sr,sizeof(sr)/sizeof(*sr),
+ &_of->serialnos,&_of->nserialnos,&_of->cserialnos);
+}
+
+static int op_open_seekable2(OggOpusFile *_of){
+ ogg_sync_state oy_start;
+ ogg_stream_state os_start;
+ ogg_packet *op_start;
+ opus_int64 prev_page_offset;
+ opus_int64 start_offset;
+ int start_op_count;
+ int ret;
+ /*We're partially open and have a first link header state in storage in _of.
+ Save off that stream state so we can come back to it.
+ It would be simpler to just dump all this state and seek back to
+ links[0].data_offset when we're done.
+ But we do the extra work to allow us to seek back to _exactly_ the same
+ stream position we're at now.
+ This allows, e.g., the HTTP backend to continue reading from the original
+ connection (if it's still available), instead of opening a new one.
+ This means we can open and start playing a normal Opus file with a single
+ link and reasonable packet sizes using only two HTTP requests.*/
+ start_op_count=_of->op_count;
+ /*This is a bit too large to put on the stack unconditionally.*/
+ op_start=(ogg_packet *)_ogg_malloc(sizeof(*op_start)*start_op_count);
+ if(op_start==NULL)return OP_EFAULT;
+ *&oy_start=_of->oy;
+ *&os_start=_of->os;
+ prev_page_offset=_of->prev_page_offset;
+ start_offset=_of->offset;
+ memcpy(op_start,_of->op,sizeof(*op_start)*start_op_count);
+ OP_ASSERT((*_of->callbacks.tell)(_of->source)==op_position(_of));
+ ogg_sync_init(&_of->oy);
+ ogg_stream_init(&_of->os,-1);
+ ret=op_open_seekable2_impl(_of);
+ /*Restore the old stream state.*/
+ ogg_stream_clear(&_of->os);
+ ogg_sync_clear(&_of->oy);
+ *&_of->oy=*&oy_start;
+ *&_of->os=*&os_start;
+ _of->offset=start_offset;
+ _of->op_count=start_op_count;
+ memcpy(_of->op,op_start,sizeof(*_of->op)*start_op_count);
+ _ogg_free(op_start);
+ _of->prev_packet_gp=_of->links[0].pcm_start;
+ _of->prev_page_offset=prev_page_offset;
+ _of->cur_discard_count=_of->links[0].head.pre_skip;
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*And restore the position indicator.*/
+ ret=(*_of->callbacks.seek)(_of->source,op_position(_of),SEEK_SET);
+ return OP_UNLIKELY(ret<0)?OP_EREAD:0;
+}
+
+/*Clear out the current logical bitstream decoder.*/
+static void op_decode_clear(OggOpusFile *_of){
+ /*We don't actually free the decoder.
+ We might be able to re-use it for the next link.*/
+ _of->op_count=0;
+ _of->od_buffer_size=0;
+ _of->prev_packet_gp=-1;
+ _of->prev_page_offset=-1;
+ if(!_of->seekable){
+ OP_ASSERT(_of->ready_state>=OP_INITSET);
+ opus_tags_clear(&_of->links[0].tags);
+ }
+ _of->ready_state=OP_OPENED;
+}
+
+static void op_clear(OggOpusFile *_of){
+ OggOpusLink *links;
+ _ogg_free(_of->od_buffer);
+ if(_of->od!=NULL)opus_multistream_decoder_destroy(_of->od);
+ links=_of->links;
+ if(!_of->seekable){
+ if(_of->ready_state>OP_OPENED||_of->ready_state==OP_PARTOPEN){
+ opus_tags_clear(&links[0].tags);
+ }
+ }
+ else if(OP_LIKELY(links!=NULL)){
+ int nlinks;
+ int link;
+ nlinks=_of->nlinks;
+ for(link=0;link<nlinks;link++)opus_tags_clear(&links[link].tags);
+ }
+ _ogg_free(links);
+ _ogg_free(_of->serialnos);
+ ogg_stream_clear(&_of->os);
+ ogg_sync_clear(&_of->oy);
+ if(_of->callbacks.close!=NULL)(*_of->callbacks.close)(_of->source);
+}
+
+static int op_open1(OggOpusFile *_of,
+ void *_source,const OpusFileCallbacks *_cb,
+ const unsigned char *_initial_data,size_t _initial_bytes){
+ ogg_page og;
+ ogg_page *pog;
+ int seekable;
+ int ret;
+ memset(_of,0,sizeof(*_of));
+ _of->end=-1;
+ _of->source=_source;
+ *&_of->callbacks=*_cb;
+ /*At a minimum, we need to be able to read data.*/
+ if(OP_UNLIKELY(_of->callbacks.read==NULL))return OP_EREAD;
+ /*Initialize the framing state.*/
+ ogg_sync_init(&_of->oy);
+ /*Perhaps some data was previously read into a buffer for testing against
+ other stream types.
+ Allow initialization from this previously read data (especially as we may
+ be reading from a non-seekable stream).
+ This requires copying it into a buffer allocated by ogg_sync_buffer() and
+ doesn't support seeking, so this is not a good mechanism to use for
+ decoding entire files from RAM.*/
+ if(_initial_bytes>0){
+ char *buffer;
+ buffer=ogg_sync_buffer(&_of->oy,_initial_bytes);
+ memcpy(buffer,_initial_data,_initial_bytes*sizeof(*buffer));
+ ogg_sync_wrote(&_of->oy,_initial_bytes);
+ }
+ /*Can we seek?
+ Stevens suggests the seek test is portable.*/
+ seekable=_cb->seek!=NULL&&(*_cb->seek)(_source,0,SEEK_CUR)!=-1;
+ /*If seek is implemented, tell must also be implemented.*/
+ if(seekable){
+ opus_int64 pos;
+ if(OP_UNLIKELY(_of->callbacks.tell==NULL))return OP_EINVAL;
+ pos=(*_of->callbacks.tell)(_of->source);
+ /*If the current position is not equal to the initial bytes consumed,
+ absolute seeking will not work.*/
+ if(OP_UNLIKELY(pos!=(opus_int64)_initial_bytes))return OP_EINVAL;
+ }
+ _of->seekable=seekable;
+ /*Don't seek yet.
+ Set up a 'single' (current) logical bitstream entry for partial open.*/
+ _of->links=(OggOpusLink *)_ogg_malloc(sizeof(*_of->links));
+ /*The serialno gets filled in later by op_fetch_headers().*/
+ ogg_stream_init(&_of->os,-1);
+ pog=NULL;
+ for(;;){
+ /*Fetch all BOS pages, store the Opus header and all seen serial numbers,
+ and load subsequent Opus setup headers.*/
+ ret=op_fetch_headers(_of,&_of->links[0].head,&_of->links[0].tags,
+ &_of->serialnos,&_of->nserialnos,&_of->cserialnos,pog);
+ if(OP_UNLIKELY(ret<0))break;
+ _of->nlinks=1;
+ _of->links[0].offset=0;
+ _of->links[0].data_offset=_of->offset;
+ _of->links[0].pcm_end=-1;
+ _of->links[0].serialno=_of->os.serialno;
+ /*Fetch the initial PCM offset.*/
+ ret=op_find_initial_pcm_offset(_of,_of->links,&og);
+ if(seekable||OP_LIKELY(ret<=0))break;
+ /*This link was empty, but we already have the BOS page for the next one in
+ og.
+ We can't seek, so start processing the next link right now.*/
+ opus_tags_clear(&_of->links[0].tags);
+ _of->nlinks=0;
+ if(!seekable)_of->cur_link++;
+ pog=&og;
+ }
+ if(OP_LIKELY(ret>=0))_of->ready_state=OP_PARTOPEN;
+ return ret;
+}
+
+static int op_open2(OggOpusFile *_of){
+ int ret;
+ OP_ASSERT(_of->ready_state==OP_PARTOPEN);
+ if(_of->seekable){
+ _of->ready_state=OP_OPENED;
+ ret=op_open_seekable2(_of);
+ }
+ else ret=0;
+ if(OP_LIKELY(ret>=0)){
+ /*We have buffered packets from op_find_initial_pcm_offset().
+ Move to OP_INITSET so we can use them.*/
+ _of->ready_state=OP_STREAMSET;
+ ret=op_make_decode_ready(_of);
+ if(OP_LIKELY(ret>=0))return 0;
+ }
+ /*Don't auto-close the stream on failure.*/
+ _of->callbacks.close=NULL;
+ op_clear(_of);
+ return ret;
+}
+
+OggOpusFile *op_test_callbacks(void *_source,const OpusFileCallbacks *_cb,
+ const unsigned char *_initial_data,size_t _initial_bytes,int *_error){
+ OggOpusFile *of;
+ int ret;
+ of=(OggOpusFile *)_ogg_malloc(sizeof(*of));
+ ret=OP_EFAULT;
+ if(OP_LIKELY(of!=NULL)){
+ ret=op_open1(of,_source,_cb,_initial_data,_initial_bytes);
+ if(OP_LIKELY(ret>=0)){
+ if(_error!=NULL)*_error=0;
+ return of;
+ }
+ /*Don't auto-close the stream on failure.*/
+ of->callbacks.close=NULL;
+ op_clear(of);
+ _ogg_free(of);
+ }
+ if(_error!=NULL)*_error=ret;
+ return NULL;
+}
+
+OggOpusFile *op_open_callbacks(void *_source,const OpusFileCallbacks *_cb,
+ const unsigned char *_initial_data,size_t _initial_bytes,int *_error){
+ OggOpusFile *of;
+ of=op_test_callbacks(_source,_cb,_initial_data,_initial_bytes,_error);
+ if(OP_LIKELY(of!=NULL)){
+ int ret;
+ ret=op_open2(of);
+ if(OP_LIKELY(ret>=0))return of;
+ if(_error!=NULL)*_error=ret;
+ _ogg_free(of);
+ }
+ return NULL;
+}
+
+/*Convenience routine to clean up from failure for the open functions that
+ create their own streams.*/
+static OggOpusFile *op_open_close_on_failure(void *_source,
+ const OpusFileCallbacks *_cb,int *_error){
+ OggOpusFile *of;
+ if(OP_UNLIKELY(_source==NULL)){
+ if(_error!=NULL)*_error=OP_EFAULT;
+ return NULL;
+ }
+ of=op_open_callbacks(_source,_cb,NULL,0,_error);
+ if(OP_UNLIKELY(of==NULL))(*_cb->close)(_source);
+ return of;
+}
+
+OggOpusFile *op_open_file(const char *_path,int *_error){
+ OpusFileCallbacks cb;
+ return op_open_close_on_failure(op_fopen(&cb,_path,"rb"),&cb,_error);
+}
+
+OggOpusFile *op_open_memory(const unsigned char *_data,size_t _size,
+ int *_error){
+ OpusFileCallbacks cb;
+ return op_open_close_on_failure(op_mem_stream_create(&cb,_data,_size),&cb,
+ _error);
+}
+
+/*Convenience routine to clean up from failure for the open functions that
+ create their own streams.*/
+static OggOpusFile *op_test_close_on_failure(void *_source,
+ const OpusFileCallbacks *_cb,int *_error){
+ OggOpusFile *of;
+ if(OP_UNLIKELY(_source==NULL)){
+ if(_error!=NULL)*_error=OP_EFAULT;
+ return NULL;
+ }
+ of=op_test_callbacks(_source,_cb,NULL,0,_error);
+ if(OP_UNLIKELY(of==NULL))(*_cb->close)(_source);
+ return of;
+}
+
+OggOpusFile *op_test_file(const char *_path,int *_error){
+ OpusFileCallbacks cb;
+ return op_test_close_on_failure(op_fopen(&cb,_path,"rb"),&cb,_error);
+}
+
+OggOpusFile *op_test_memory(const unsigned char *_data,size_t _size,
+ int *_error){
+ OpusFileCallbacks cb;
+ return op_test_close_on_failure(op_mem_stream_create(&cb,_data,_size),&cb,
+ _error);
+}
+
+int op_test_open(OggOpusFile *_of){
+ int ret;
+ if(OP_UNLIKELY(_of->ready_state!=OP_PARTOPEN))return OP_EINVAL;
+ ret=op_open2(_of);
+ /*op_open2() will clear this structure on failure.
+ Reset its contents to prevent double-frees in op_free().*/
+ if(OP_UNLIKELY(ret<0))memset(_of,0,sizeof(*_of));
+ return ret;
+}
+
+void op_free(OggOpusFile *_of){
+ if(OP_LIKELY(_of!=NULL)){
+ op_clear(_of);
+ _ogg_free(_of);
+ }
+}
+
+int op_seekable(const OggOpusFile *_of){
+ return _of->seekable;
+}
+
+int op_link_count(const OggOpusFile *_of){
+ return _of->nlinks;
+}
+
+ogg_uint32_t op_serialno(const OggOpusFile *_of,int _li){
+ if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1;
+ if(!_of->seekable)_li=0;
+ return _of->links[_li<0?_of->cur_link:_li].serialno;
+}
+
+int op_channel_count(const OggOpusFile *_of,int _li){
+ return op_head(_of,_li)->channel_count;
+}
+
+opus_int64 op_raw_total(const OggOpusFile *_of,int _li){
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED)
+ ||OP_UNLIKELY(!_of->seekable)
+ ||OP_UNLIKELY(_li>=_of->nlinks)){
+ return OP_EINVAL;
+ }
+ if(_li<0)return _of->end-_of->links[0].offset;
+ return (_li+1>=_of->nlinks?_of->end:_of->links[_li+1].offset)
+ -_of->links[_li].offset;
+}
+
+ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li){
+ OggOpusLink *links;
+ ogg_int64_t diff=0;
+ int nlinks;
+ nlinks=_of->nlinks;
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED)
+ ||OP_UNLIKELY(!_of->seekable)
+ ||OP_UNLIKELY(_li>=nlinks)){
+ return OP_EINVAL;
+ }
+ links=_of->links;
+ /*We verify that the granule position differences are larger than the
+ pre-skip and that the total duration does not overflow during link
+ enumeration, so we don't have to check here.*/
+ if(_li<0){
+ ogg_int64_t pcm_total;
+ int li;
+ pcm_total=0;
+ for(li=0;li<nlinks;li++){
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,
+ links[li].pcm_end,links[li].pcm_start));
+ pcm_total+=diff-links[li].head.pre_skip;
+ }
+ return pcm_total;
+ }
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,
+ links[_li].pcm_end,links[_li].pcm_start));
+ return diff-links[_li].head.pre_skip;
+}
+
+const OpusHead *op_head(const OggOpusFile *_of,int _li){
+ if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1;
+ if(!_of->seekable)_li=0;
+ return &_of->links[_li<0?_of->cur_link:_li].head;
+}
+
+const OpusTags *op_tags(const OggOpusFile *_of,int _li){
+ if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1;
+ if(!_of->seekable){
+ if(_of->ready_state<OP_STREAMSET&&_of->ready_state!=OP_PARTOPEN){
+ return NULL;
+ }
+ _li=0;
+ }
+ else if(_li<0)_li=_of->ready_state>=OP_STREAMSET?_of->cur_link:0;
+ return &_of->links[_li].tags;
+}
+
+int op_current_link(const OggOpusFile *_of){
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ return _of->cur_link;
+}
+
+/*Compute an average bitrate given a byte and sample count.
+ Return: The bitrate in bits per second.*/
+static opus_int32 op_calc_bitrate(opus_int64 _bytes,ogg_int64_t _samples){
+ /*These rates are absurd, but let's handle them anyway.*/
+ if(OP_UNLIKELY(_bytes>(OP_INT64_MAX-(_samples>>1))/(48000*8))){
+ ogg_int64_t den;
+ if(OP_UNLIKELY(_bytes/(OP_INT32_MAX/(48000*8))>=_samples)){
+ return OP_INT32_MAX;
+ }
+ den=_samples/(48000*8);
+ return (opus_int32)((_bytes+(den>>1))/den);
+ }
+ if(OP_UNLIKELY(_samples<=0))return OP_INT32_MAX;
+ /*This can't actually overflow in normal operation: even with a pre-skip of
+ 545 2.5 ms frames with 8 streams running at 1282*8+1 bytes per packet
+ (1275 byte frames + Opus framing overhead + Ogg lacing values), that all
+ produce a single sample of decoded output, we still don't top 45 Mbps.
+ The only way to get bitrates larger than that is with excessive Opus
+ padding, more encoded streams than output channels, or lots and lots of
+ Ogg pages with no packets on them.*/
+ return (opus_int32)OP_MIN((_bytes*48000*8+(_samples>>1))/_samples,
+ OP_INT32_MAX);
+}
+
+opus_int32 op_bitrate(const OggOpusFile *_of,int _li){
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED)||OP_UNLIKELY(!_of->seekable)
+ ||OP_UNLIKELY(_li>=_of->nlinks)){
+ return OP_EINVAL;
+ }
+ return op_calc_bitrate(op_raw_total(_of,_li),op_pcm_total(_of,_li));
+}
+
+opus_int32 op_bitrate_instant(OggOpusFile *_of){
+ ogg_int64_t samples_tracked;
+ opus_int32 ret;
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ samples_tracked=_of->samples_tracked;
+ if(OP_UNLIKELY(samples_tracked==0))return OP_FALSE;
+ ret=op_calc_bitrate(_of->bytes_tracked,samples_tracked);
+ _of->bytes_tracked=0;
+ _of->samples_tracked=0;
+ return ret;
+}
+
+/*Fetch and process a page.
+ This handles the case where we're at a bitstream boundary and dumps the
+ decoding machine.
+ If the decoding machine is unloaded, it loads it.
+ It also keeps prev_packet_gp up to date (seek and read both use this).
+ Return: <0) Error, OP_HOLE (lost packet), or OP_EOF.
+ 0) Got at least one audio data packet.*/
+static int op_fetch_and_process_page(OggOpusFile *_of,
+ ogg_page *_og,opus_int64 _page_offset,int _spanp,int _ignore_holes){
+ OggOpusLink *links;
+ ogg_uint32_t cur_serialno;
+ int seekable;
+ int cur_link;
+ int ret;
+ /*We shouldn't get here if we have unprocessed packets.*/
+ OP_ASSERT(_of->ready_state<OP_INITSET||_of->op_pos>=_of->op_count);
+ seekable=_of->seekable;
+ links=_of->links;
+ cur_link=seekable?_of->cur_link:0;
+ cur_serialno=links[cur_link].serialno;
+ /*Handle one page.*/
+ for(;;){
+ ogg_page og;
+ OP_ASSERT(_of->ready_state>=OP_OPENED);
+ /*If we were given a page to use, use it.*/
+ if(_og!=NULL){
+ *&og=*_og;
+ _og=NULL;
+ }
+ /*Keep reading until we get a page with the correct serialno.*/
+ else _page_offset=op_get_next_page(_of,&og,_of->end);
+ /*EOF: Leave uninitialized.*/
+ if(_page_offset<0)return _page_offset<OP_FALSE?(int)_page_offset:OP_EOF;
+ if(OP_LIKELY(_of->ready_state>=OP_STREAMSET)
+ &&cur_serialno!=(ogg_uint32_t)ogg_page_serialno(&og)){
+ /*Two possibilities:
+ 1) Another stream is multiplexed into this logical section, or*/
+ if(OP_LIKELY(!ogg_page_bos(&og)))continue;
+ /* 2) Our decoding just traversed a bitstream boundary.*/
+ if(!_spanp)return OP_EOF;
+ if(OP_LIKELY(_of->ready_state>=OP_INITSET))op_decode_clear(_of);
+ }
+ /*Bitrate tracking: add the header's bytes here.
+ The body bytes are counted when we consume the packets.*/
+ else _of->bytes_tracked+=og.header_len;
+ /*Do we need to load a new machine before submitting the page?
+ This is different in the seekable and non-seekable cases.
+ In the seekable case, we already have all the header information loaded
+ and cached.
+ We just initialize the machine with it and continue on our merry way.
+ In the non-seekable (streaming) case, we'll only be at a boundary if we
+ just left the previous logical bitstream, and we're now nominally at the
+ header of the next bitstream.*/
+ if(OP_UNLIKELY(_of->ready_state<OP_STREAMSET)){
+ if(seekable){
+ ogg_uint32_t serialno;
+ int nlinks;
+ int li;
+ serialno=ogg_page_serialno(&og);
+ /*Match the serialno to bitstream section.
+ We use this rather than offset positions to avoid problems near
+ logical bitstream boundaries.*/
+ nlinks=_of->nlinks;
+ for(li=0;li<nlinks&&links[li].serialno!=serialno;li++);
+ /*Not a desired Opus bitstream section.
+ Keep trying.*/
+ if(li>=nlinks)continue;
+ cur_serialno=serialno;
+ _of->cur_link=cur_link=li;
+ ogg_stream_reset_serialno(&_of->os,serialno);
+ _of->ready_state=OP_STREAMSET;
+ /*If we're at the start of this link, initialize the granule position
+ and pre-skip tracking.*/
+ if(_page_offset<=links[cur_link].data_offset){
+ _of->prev_packet_gp=links[cur_link].pcm_start;
+ _of->prev_page_offset=-1;
+ _of->cur_discard_count=links[cur_link].head.pre_skip;
+ /*Ignore a hole at the start of a new link (this is common for
+ streams joined in the middle) or after seeking.*/
+ _ignore_holes=1;
+ }
+ }
+ else{
+ do{
+ /*We're streaming.
+ Fetch the two header packets, build the info struct.*/
+ ret=op_fetch_headers(_of,&links[0].head,&links[0].tags,
+ NULL,NULL,NULL,&og);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*op_find_initial_pcm_offset() will suppress any initial hole for us,
+ so no need to set _ignore_holes.*/
+ ret=op_find_initial_pcm_offset(_of,links,&og);
+ if(OP_UNLIKELY(ret<0))return ret;
+ _of->links[0].serialno=cur_serialno=_of->os.serialno;
+ _of->cur_link++;
+ }
+ /*If the link was empty, keep going, because we already have the
+ BOS page of the next one in og.*/
+ while(OP_UNLIKELY(ret>0));
+ /*If we didn't get any packets out of op_find_initial_pcm_offset(),
+ keep going (this is possible if end-trimming trimmed them all).*/
+ if(_of->op_count<=0)continue;
+ /*Otherwise, we're done.
+ TODO: This resets bytes_tracked, which misses the header bytes
+ already processed by op_find_initial_pcm_offset().*/
+ ret=op_make_decode_ready(_of);
+ if(OP_UNLIKELY(ret<0))return ret;
+ return 0;
+ }
+ }
+ /*The buffered page is the data we want, and we're ready for it.
+ Add it to the stream state.*/
+ if(OP_UNLIKELY(_of->ready_state==OP_STREAMSET)){
+ ret=op_make_decode_ready(_of);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ /*Extract all the packets from the current page.*/
+ ogg_stream_pagein(&_of->os,&og);
+ if(OP_LIKELY(_of->ready_state>=OP_INITSET)){
+ opus_int32 total_duration;
+ int durations[255];
+ int op_count;
+ total_duration=op_collect_audio_packets(_of,durations);
+ if(OP_UNLIKELY(total_duration<0)){
+ /*Drain the packets from the page anyway.*/
+ total_duration=op_collect_audio_packets(_of,durations);
+ OP_ASSERT(total_duration>=0);
+ /*Report holes to the caller.*/
+ if(!_ignore_holes)return OP_HOLE;
+ }
+ op_count=_of->op_count;
+ /*If we found at least one audio data packet, compute per-packet granule
+ positions for them.*/
+ if(op_count>0){
+ ogg_int64_t diff;
+ ogg_int64_t prev_packet_gp;
+ ogg_int64_t cur_packet_gp;
+ ogg_int64_t cur_page_gp;
+ int cur_page_eos;
+ int pi;
+ cur_page_gp=_of->op[op_count-1].granulepos;
+ cur_page_eos=_of->op[op_count-1].e_o_s;
+ prev_packet_gp=_of->prev_packet_gp;
+ if(OP_UNLIKELY(prev_packet_gp==-1)){
+ opus_int32 cur_discard_count;
+ /*This is the first call after a raw seek.
+ Try to reconstruct prev_packet_gp from scratch.*/
+ OP_ASSERT(seekable);
+ if(OP_UNLIKELY(cur_page_eos)){
+ /*If the first page we hit after our seek was the EOS page, and
+ we didn't start from data_offset or before, we don't have
+ enough information to do end-trimming.
+ Proceed to the next link, rather than risk playing back some
+ samples that shouldn't have been played.*/
+ _of->op_count=0;
+ continue;
+ }
+ /*By default discard 80 ms of data after a seek, unless we seek
+ into the pre-skip region.*/
+ cur_discard_count=80*48;
+ cur_page_gp=_of->op[op_count-1].granulepos;
+ /*Try to initialize prev_packet_gp.
+ If the current page had packets but didn't have a granule
+ position, or the granule position it had was too small (both
+ illegal), just use the starting granule position for the link.*/
+ prev_packet_gp=links[cur_link].pcm_start;
+ if(OP_LIKELY(cur_page_gp!=-1)){
+ op_granpos_add(&prev_packet_gp,cur_page_gp,-total_duration);
+ }
+ if(OP_LIKELY(!op_granpos_diff(&diff,
+ prev_packet_gp,links[cur_link].pcm_start))){
+ opus_int32 pre_skip;
+ /*If we start at the beginning of the pre-skip region, or we're
+ at least 80 ms from the end of the pre-skip region, we discard
+ to the end of the pre-skip region.
+ Otherwise, we still use the 80 ms default, which will discard
+ past the end of the pre-skip region.*/
+ pre_skip=links[cur_link].head.pre_skip;
+ if(diff>=0&&diff<=OP_MAX(0,pre_skip-80*48)){
+ cur_discard_count=pre_skip-(int)diff;
+ }
+ }
+ _of->cur_discard_count=cur_discard_count;
+ }
+ if(OP_UNLIKELY(cur_page_gp==-1)){
+ /*This page had completed packets but didn't have a valid granule
+ position.
+ This is illegal, but we'll try to handle it by continuing to count
+ forwards from the previous page.*/
+ if(op_granpos_add(&cur_page_gp,prev_packet_gp,total_duration)<0){
+ /*The timestamp for this page overflowed.*/
+ cur_page_gp=links[cur_link].pcm_end;
+ }
+ }
+ /*If we hit the last page, handle end-trimming.*/
+ if(OP_UNLIKELY(cur_page_eos)
+ &&OP_LIKELY(!op_granpos_diff(&diff,cur_page_gp,prev_packet_gp))
+ &&OP_LIKELY(diff<total_duration)){
+ cur_packet_gp=prev_packet_gp;
+ for(pi=0;pi<op_count;pi++){
+ diff=durations[pi]-diff;
+ /*If we have samples to trim...*/
+ if(diff>0){
+ /*If we trimmed the entire packet, stop (the spec says encoders
+ shouldn't do this, but we support it anyway).*/
+ if(OP_UNLIKELY(diff>durations[pi]))break;
+ cur_packet_gp=cur_page_gp;
+ /*Move the EOS flag to this packet, if necessary, so we'll trim
+ the samples during decode.*/
+ _of->op[pi].e_o_s=1;
+ }
+ else{
+ /*Update the granule position as normal.*/
+ OP_ALWAYS_TRUE(!op_granpos_add(&cur_packet_gp,
+ cur_packet_gp,durations[pi]));
+ }
+ _of->op[pi].granulepos=cur_packet_gp;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,cur_page_gp,cur_packet_gp));
+ }
+ }
+ else{
+ /*Propagate timestamps to earlier packets.
+ op_granpos_add(&prev_packet_gp,prev_packet_gp,total_duration)
+ should succeed and give prev_packet_gp==cur_page_gp.
+ But we don't bother to check that, as there isn't much we can do
+ if it's not true, and it actually will not be true on the first
+ page after a seek, if there was a continued packet.
+ The only thing we guarantee is that the start and end granule
+ positions of the packets are valid, and that they are monotonic
+ within a page.
+ They might be completely out of range for this link (we'll check
+ that elsewhere), or non-monotonic between pages.*/
+ if(OP_UNLIKELY(op_granpos_add(&prev_packet_gp,
+ cur_page_gp,-total_duration)<0)){
+ /*The starting timestamp for the first packet on this page
+ underflowed.
+ This is illegal, but we ignore it.*/
+ prev_packet_gp=0;
+ }
+ for(pi=0;pi<op_count;pi++){
+ if(OP_UNLIKELY(op_granpos_add(&cur_packet_gp,
+ cur_page_gp,-total_duration)<0)){
+ /*The start timestamp for this packet underflowed.
+ This is illegal, but we ignore it.*/
+ cur_packet_gp=0;
+ }
+ total_duration-=durations[pi];
+ OP_ASSERT(total_duration>=0);
+ OP_ALWAYS_TRUE(!op_granpos_add(&cur_packet_gp,
+ cur_packet_gp,durations[pi]));
+ _of->op[pi].granulepos=cur_packet_gp;
+ }
+ OP_ASSERT(total_duration==0);
+ }
+ _of->prev_packet_gp=prev_packet_gp;
+ _of->prev_page_offset=_page_offset;
+ _of->op_count=pi;
+ /*If end-trimming didn't trim all the packets, we're done.*/
+ if(OP_LIKELY(pi>0))return 0;
+ }
+ }
+ }
+}
+
+int op_raw_seek(OggOpusFile *_of,opus_int64 _pos){
+ int ret;
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ /*Don't dump the decoder state if we can't seek.*/
+ if(OP_UNLIKELY(!_of->seekable))return OP_ENOSEEK;
+ if(OP_UNLIKELY(_pos<0)||OP_UNLIKELY(_pos>_of->end))return OP_EINVAL;
+ /*Clear out any buffered, decoded data.*/
+ op_decode_clear(_of);
+ _of->bytes_tracked=0;
+ _of->samples_tracked=0;
+ ret=op_seek_helper(_of,_pos);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ ret=op_fetch_and_process_page(_of,NULL,-1,1,1);
+ /*If we hit EOF, op_fetch_and_process_page() leaves us uninitialized.
+ Instead, jump to the end.*/
+ if(ret==OP_EOF){
+ int cur_link;
+ op_decode_clear(_of);
+ cur_link=_of->nlinks-1;
+ _of->cur_link=cur_link;
+ _of->prev_packet_gp=_of->links[cur_link].pcm_end;
+ _of->cur_discard_count=0;
+ ret=0;
+ }
+ return ret;
+}
+
+/*Convert a PCM offset relative to the start of the whole stream to a granule
+ position in an individual link.*/
+static ogg_int64_t op_get_granulepos(const OggOpusFile *_of,
+ ogg_int64_t _pcm_offset,int *_li){
+ const OggOpusLink *links;
+ ogg_int64_t duration=0;
+ int nlinks;
+ int li;
+ OP_ASSERT(_pcm_offset>=0);
+ nlinks=_of->nlinks;
+ links=_of->links;
+ for(li=0;OP_LIKELY(li<nlinks);li++){
+ ogg_int64_t pcm_start;
+ opus_int32 pre_skip;
+ pcm_start=links[li].pcm_start;
+ pre_skip=links[li].head.pre_skip;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&duration,links[li].pcm_end,pcm_start));
+ duration-=pre_skip;
+ if(_pcm_offset<duration){
+ _pcm_offset+=pre_skip;
+ if(OP_UNLIKELY(pcm_start>OP_INT64_MAX-_pcm_offset)){
+ /*Adding this amount to the granule position would overflow the positive
+ half of its 64-bit range.
+ Since signed overflow is undefined in C, do it in a way the compiler
+ isn't allowed to screw up.*/
+ _pcm_offset-=OP_INT64_MAX-pcm_start+1;
+ pcm_start=OP_INT64_MIN;
+ }
+ pcm_start+=_pcm_offset;
+ *_li=li;
+ return pcm_start;
+ }
+ _pcm_offset-=duration;
+ }
+ return -1;
+}
+
+/*A small helper to determine if an Ogg page contains data that continues onto
+ a subsequent page.*/
+static int op_page_continues(const ogg_page *_og){
+ int nlacing;
+ OP_ASSERT(_og->header_len>=27);
+ nlacing=_og->header[26];
+ OP_ASSERT(_og->header_len>=27+nlacing);
+ /*This also correctly handles the (unlikely) case of nlacing==0, because
+ 0!=255.*/
+ return _og->header[27+nlacing-1]==255;
+}
+
+/*A small helper to buffer the continued packet data from a page.*/
+static void op_buffer_continued_data(OggOpusFile *_of,ogg_page *_og){
+ ogg_packet op;
+ ogg_stream_pagein(&_of->os,_og);
+ /*Drain any packets that did end on this page (and ignore holes).
+ We only care about the continued packet data.*/
+ while(ogg_stream_packetout(&_of->os,&op));
+}
+
+/*This controls how close the target has to be to use the current stream
+ position to subdivide the initial range.
+ Two minutes seems to be a good default.*/
+#define OP_CUR_TIME_THRESH (120*48*(opus_int32)1000)
+
+/*Note: The OP_SMALL_FOOTPRINT #define doesn't (currently) save much code size,
+ but it's meant to serve as documentation for portions of the seeking
+ algorithm that are purely optional, to aid others learning from/porting this
+ code to other contexts.*/
+/*#define OP_SMALL_FOOTPRINT (1)*/
+
+/*Search within link _li for the page with the highest granule position
+ preceding (or equal to) _target_gp.
+ There is a danger here: missing pages or incorrect frame number information
+ in the bitstream could make our task impossible.
+ Account for that (and report it as an error condition).*/
+static int op_pcm_seek_page(OggOpusFile *_of,
+ ogg_int64_t _target_gp,int _li){
+ const OggOpusLink *link;
+ ogg_page og;
+ ogg_int64_t pcm_pre_skip=0;
+ ogg_int64_t pcm_start;
+ ogg_int64_t pcm_end;
+ ogg_int64_t best_gp;
+ ogg_int64_t diff = 0;
+ ogg_uint32_t serialno;
+ opus_int32 pre_skip;
+ opus_int64 begin;
+ opus_int64 end;
+ opus_int64 boundary;
+ opus_int64 best;
+ opus_int64 best_start;
+ opus_int64 page_offset;
+ opus_int64 d0;
+ opus_int64 d1;
+ opus_int64 d2;
+ int force_bisect;
+ int buffering;
+ int ret;
+ _of->bytes_tracked=0;
+ _of->samples_tracked=0;
+ link=_of->links+_li;
+ best_gp=pcm_start=link->pcm_start;
+ pcm_end=link->pcm_end;
+ serialno=link->serialno;
+ best=best_start=begin=link->data_offset;
+ page_offset=-1;
+ buffering=0;
+ /*We discard the first 80 ms of data after a seek, so seek back that much
+ farther.
+ If we can't, simply seek to the beginning of the link.*/
+ if(OP_UNLIKELY(op_granpos_add(&_target_gp,_target_gp,-80*48)<0)
+ ||OP_UNLIKELY(op_granpos_cmp(_target_gp,pcm_start)<0)){
+ _target_gp=pcm_start;
+ }
+ /*Special case seeking to the start of the link.*/
+ pre_skip=link->head.pre_skip;
+ OP_ALWAYS_TRUE(!op_granpos_add(&pcm_pre_skip,pcm_start,pre_skip));
+ if(op_granpos_cmp(_target_gp,pcm_pre_skip)<0)end=boundary=begin;
+ else{
+ end=boundary=link->end_offset;
+#if !defined(OP_SMALL_FOOTPRINT)
+ /*If we were decoding from this link, we can narrow the range a bit.*/
+ if(_li==_of->cur_link&&_of->ready_state>=OP_INITSET){
+ opus_int64 offset;
+ int op_count;
+ op_count=_of->op_count;
+ /*The only way the offset can be invalid _and_ we can fail the granule
+ position checks below is if someone changed the contents of the last
+ page since we read it.
+ We'd be within our rights to just return OP_EBADLINK in that case, but
+ we'll simply ignore the current position instead.*/
+ offset=_of->offset;
+ if(op_count>0&&OP_LIKELY(offset<=end)){
+ ogg_int64_t gp;
+ /*Make sure the timestamp is valid.
+ The granule position might be -1 if we collected the packets from a
+ page without a granule position after reporting a hole.*/
+ gp=_of->op[op_count-1].granulepos;
+ if(OP_LIKELY(gp!=-1)&&OP_LIKELY(op_granpos_cmp(pcm_start,gp)<0)
+ &&OP_LIKELY(op_granpos_cmp(pcm_end,gp)>0)){
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,gp,_target_gp));
+ /*We only actually use the current time if either
+ a) We can cut off at least half the range, or
+ b) We're seeking sufficiently close to the current position that
+ it's likely to be informative.
+ Otherwise it appears using the whole link range to estimate the
+ first seek location gives better results, on average.*/
+ if(diff<0){
+ OP_ASSERT(offset>=begin);
+ if(offset-begin>=end-begin>>1||diff>-OP_CUR_TIME_THRESH){
+ best=begin=offset;
+ best_gp=pcm_start=gp;
+ /*If we have buffered data from a continued packet, remember the
+ offset of the previous page's start, so that if we do wind up
+ having to seek back here later, we can prime the stream with
+ the continued packet data.
+ With no continued packet, we remember the end of the page.*/
+ best_start=_of->os.body_returned<_of->os.body_fill?
+ _of->prev_page_offset:best;
+ /*If there's completed packets and data in the stream state,
+ prev_page_offset should always be set.*/
+ OP_ASSERT(best_start>=0);
+ /*Buffer any continued packet data starting from here.*/
+ buffering=1;
+ }
+ }
+ else{
+ ogg_int64_t prev_page_gp=0;
+ /*We might get lucky and already have the packet with the target
+ buffered.
+ Worth checking.
+ For very small files (with all of the data in a single page,
+ generally 1 second or less), we can loop them continuously
+ without seeking at all.*/
+ OP_ALWAYS_TRUE(!op_granpos_add(&prev_page_gp,_of->op[0].granulepos,
+ -op_get_packet_duration(_of->op[0].packet,_of->op[0].bytes)));
+ if(op_granpos_cmp(prev_page_gp,_target_gp)<=0){
+ /*Don't call op_decode_clear(), because it will dump our
+ packets.*/
+ _of->op_pos=0;
+ _of->od_buffer_size=0;
+ _of->prev_packet_gp=prev_page_gp;
+ /*_of->prev_page_offset already points to the right place.*/
+ _of->ready_state=OP_STREAMSET;
+ return op_make_decode_ready(_of);
+ }
+ /*No such luck.
+ Check if we can cut off at least half the range, though.*/
+ if(offset-begin<=end-begin>>1||diff<OP_CUR_TIME_THRESH){
+ /*We really want the page start here, but this will do.*/
+ end=boundary=offset;
+ pcm_end=gp;
+ }
+ }
+ }
+ }
+ }
+#endif
+ }
+ /*This code was originally based on the "new search algorithm by HB (Nicholas
+ Vinen)" from libvorbisfile.
+ It has been modified substantially since.*/
+ op_decode_clear(_of);
+ if(!buffering)ogg_stream_reset_serialno(&_of->os,serialno);
+ _of->cur_link=_li;
+ _of->ready_state=OP_STREAMSET;
+ /*Initialize the interval size history.*/
+ d2=d1=d0=end-begin;
+ force_bisect=0;
+ while(begin<end){
+ opus_int64 bisect;
+ opus_int64 next_boundary;
+ opus_int32 chunk_size;
+ if(end-begin<OP_CHUNK_SIZE)bisect=begin;
+ else{
+ /*Update the interval size history.*/
+ d0=d1>>1;
+ d1=d2>>1;
+ d2=end-begin>>1;
+ if(force_bisect)bisect=begin+(end-begin>>1);
+ else{
+ ogg_int64_t diff2 = 0;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start));
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff2,pcm_end,pcm_start));
+ /*Take a (pretty decent) guess.*/
+ bisect=begin+op_rescale64(diff,diff2,end-begin)-OP_CHUNK_SIZE;
+ }
+ if(bisect-OP_CHUNK_SIZE<begin)bisect=begin;
+ force_bisect=0;
+ }
+ if(bisect!=_of->offset){
+ /*Discard any buffered continued packet data.*/
+ if(buffering)ogg_stream_reset(&_of->os);
+ buffering=0;
+ page_offset=-1;
+ ret=op_seek_helper(_of,bisect);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ chunk_size=OP_CHUNK_SIZE;
+ next_boundary=boundary;
+ /*Now scan forward and figure out where we landed.
+ In the ideal case, we will see a page with a granule position at or
+ before our target, followed by a page with a granule position after our
+ target (or the end of the search interval).
+ Then we can just drop out and will have all of the data we need with no
+ additional seeking.
+ If we landed too far before, or after, we'll break out and do another
+ bisection.*/
+ while(begin<end){
+ page_offset=op_get_next_page(_of,&og,boundary);
+ if(page_offset<0){
+ if(page_offset<OP_FALSE)return (int)page_offset;
+ /*There are no more pages in our interval from our stream with a valid
+ timestamp that start at position bisect or later.*/
+ /*If we scanned the whole interval, we're done.*/
+ if(bisect<=begin+1)end=begin;
+ else{
+ /*Otherwise, back up one chunk.
+ First, discard any data from a continued packet.*/
+ if(buffering)ogg_stream_reset(&_of->os);
+ buffering=0;
+ bisect=OP_MAX(bisect-chunk_size,begin);
+ ret=op_seek_helper(_of,bisect);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*Bump up the chunk size.*/
+ chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX);
+ /*If we did find a page from another stream or without a timestamp,
+ don't read past it.*/
+ boundary=next_boundary;
+ }
+ }
+ else{
+ ogg_int64_t gp;
+ int has_packets;
+ /*Save the offset of the first page we found after the seek, regardless
+ of the stream it came from or whether or not it has a timestamp.*/
+ next_boundary=OP_MIN(page_offset,next_boundary);
+ if(serialno!=(ogg_uint32_t)ogg_page_serialno(&og))continue;
+ has_packets=ogg_page_packets(&og)>0;
+ /*Force the gp to -1 (as it should be per spec) if no packets end on
+ this page.
+ Otherwise we might get confused when we try to pull out a packet
+ with that timestamp and can't find it.*/
+ gp=has_packets?ogg_page_granulepos(&og):-1;
+ if(gp==-1){
+ if(buffering){
+ if(OP_LIKELY(!has_packets))ogg_stream_pagein(&_of->os,&og);
+ else{
+ /*If packets did end on this page, but we still didn't have a
+ valid granule position (in violation of the spec!), stop
+ buffering continued packet data.
+ Otherwise we might continue past the packet we actually
+ wanted.*/
+ ogg_stream_reset(&_of->os);
+ buffering=0;
+ }
+ }
+ continue;
+ }
+ if(op_granpos_cmp(gp,_target_gp)<0){
+ /*We found a page that ends before our target.
+ Advance to the raw offset of the next page.*/
+ begin=_of->offset;
+ if(OP_UNLIKELY(op_granpos_cmp(pcm_start,gp)>0)
+ ||OP_UNLIKELY(op_granpos_cmp(pcm_end,gp)<0)){
+ /*Don't let pcm_start get out of range!
+ That could happen with an invalid timestamp.*/
+ break;
+ }
+ /*Save the byte offset of the end of the page with this granule
+ position.*/
+ best=best_start=begin;
+ /*Buffer any data from a continued packet, if necessary.
+ This avoids the need to seek back here if the next timestamp we
+ encounter while scanning forward lies after our target.*/
+ if(buffering)ogg_stream_reset(&_of->os);
+ if(op_page_continues(&og)){
+ op_buffer_continued_data(_of,&og);
+ /*If we have a continued packet, remember the offset of this
+ page's start, so that if we do wind up having to seek back here
+ later, we can prime the stream with the continued packet data.
+ With no continued packet, we remember the end of the page.*/
+ best_start=page_offset;
+ }
+ /*Then force buffering on, so that if a packet starts (but does not
+ end) on the next page, we still avoid the extra seek back.*/
+ buffering=1;
+ best_gp=pcm_start=gp;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start));
+ /*If we're more than a second away from our target, break out and
+ do another bisection.*/
+ if(diff>48000)break;
+ /*Otherwise, keep scanning forward (do NOT use begin+1).*/
+ bisect=begin;
+ }
+ else{
+ /*We found a page that ends after our target.*/
+ /*If we scanned the whole interval before we found it, we're done.*/
+ if(bisect<=begin+1)end=begin;
+ else{
+ end=bisect;
+ /*In later iterations, don't read past the first page we found.*/
+ boundary=next_boundary;
+ /*If we're not making much progress shrinking the interval size,
+ start forcing straight bisection to limit the worst case.*/
+ force_bisect=end-begin>d0*2;
+ /*Don't let pcm_end get out of range!
+ That could happen with an invalid timestamp.*/
+ if(OP_LIKELY(op_granpos_cmp(pcm_end,gp)>0)
+ &&OP_LIKELY(op_granpos_cmp(pcm_start,gp)<=0)){
+ pcm_end=gp;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ /*Found our page.*/
+ OP_ASSERT(op_granpos_cmp(best_gp,pcm_start)>=0);
+ /*Seek, if necessary.
+ If we were buffering data from a continued packet, we should be able to
+ continue to scan forward to get the rest of the data (even if
+ page_offset==-1).
+ Otherwise, we need to seek back to best_start.*/
+ if(!buffering){
+ if(best_start!=page_offset){
+ page_offset=-1;
+ ret=op_seek_helper(_of,best_start);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ if(best_start<best){
+ /*Retrieve the page at best_start, if we do not already have it.*/
+ if(page_offset<0){
+ page_offset=op_get_next_page(_of,&og,link->end_offset);
+ if(OP_UNLIKELY(page_offset<OP_FALSE))return (int)page_offset;
+ if(OP_UNLIKELY(page_offset!=best_start))return OP_EBADLINK;
+ }
+ op_buffer_continued_data(_of,&og);
+ page_offset=-1;
+ }
+ }
+ /*Update prev_packet_gp to allow per-packet granule position assignment.*/
+ _of->prev_packet_gp=best_gp;
+ _of->prev_page_offset=best_start;
+ ret=op_fetch_and_process_page(_of,page_offset<0?NULL:&og,page_offset,0,1);
+ if(OP_UNLIKELY(ret<0))return OP_EBADLINK;
+ /*Verify result.*/
+ if(OP_UNLIKELY(op_granpos_cmp(_of->prev_packet_gp,_target_gp)>0)){
+ return OP_EBADLINK;
+ }
+ /*Our caller will set cur_discard_count to handle pre-roll.*/
+ return 0;
+}
+
+int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset){
+ const OggOpusLink *link;
+ ogg_int64_t pcm_start;
+ ogg_int64_t target_gp;
+ ogg_int64_t prev_packet_gp;
+ ogg_int64_t skip;
+ ogg_int64_t diff;
+ int op_count;
+ int op_pos;
+ int ret;
+ int li;
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ if(OP_UNLIKELY(!_of->seekable))return OP_ENOSEEK;
+ if(OP_UNLIKELY(_pcm_offset<0))return OP_EINVAL;
+ target_gp=op_get_granulepos(_of,_pcm_offset,&li);
+ if(OP_UNLIKELY(target_gp==-1))return OP_EINVAL;
+ link=_of->links+li;
+ pcm_start=link->pcm_start;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&_pcm_offset,target_gp,pcm_start));
+#if !defined(OP_SMALL_FOOTPRINT)
+ /*For small (90 ms or less) forward seeks within the same link, just decode
+ forward.
+ This also optimizes the case of seeking to the current position.*/
+ if(li==_of->cur_link&&_of->ready_state>=OP_INITSET){
+ ogg_int64_t gp;
+ gp=_of->prev_packet_gp;
+ if(OP_LIKELY(gp!=-1)){
+ int nbuffered;
+ nbuffered=OP_MAX(_of->od_buffer_size-_of->od_buffer_pos,0);
+ OP_ALWAYS_TRUE(!op_granpos_add(&gp,gp,-nbuffered));
+ /*We do _not_ add cur_discard_count to gp.
+ Otherwise the total amount to discard could grow without bound, and it
+ would be better just to do a full seek.*/
+ if(OP_LIKELY(!op_granpos_diff(&diff,gp,pcm_start))){
+ ogg_int64_t discard_count;
+ discard_count=_pcm_offset-diff;
+ /*We use a threshold of 90 ms instead of 80, since 80 ms is the
+ _minimum_ we would have discarded after a full seek.
+ Assuming 20 ms frames (the default), we'd discard 90 ms on average.*/
+ if(discard_count>=0&&OP_UNLIKELY(discard_count<90*48)){
+ _of->cur_discard_count=(opus_int32)discard_count;
+ return 0;
+ }
+ }
+ }
+ }
+#endif
+ ret=op_pcm_seek_page(_of,target_gp,li);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*Now skip samples until we actually get to our target.*/
+ /*Figure out where we should skip to.*/
+ if(_pcm_offset<=link->head.pre_skip)skip=0;
+ else skip=OP_MAX(_pcm_offset-80*48,0);
+ OP_ASSERT(_pcm_offset-skip>=0);
+ OP_ASSERT(_pcm_offset-skip<OP_INT32_MAX-120*48);
+ /*Skip packets until we find one with samples past our skip target.*/
+ for(;;){
+ op_count=_of->op_count;
+ prev_packet_gp=_of->prev_packet_gp;
+ for(op_pos=_of->op_pos;op_pos<op_count;op_pos++){
+ ogg_int64_t cur_packet_gp;
+ cur_packet_gp=_of->op[op_pos].granulepos;
+ if(OP_LIKELY(!op_granpos_diff(&diff,cur_packet_gp,pcm_start))
+ &&diff>skip){
+ break;
+ }
+ prev_packet_gp=cur_packet_gp;
+ }
+ _of->prev_packet_gp=prev_packet_gp;
+ _of->op_pos=op_pos;
+ if(op_pos<op_count)break;
+ /*We skipped all the packets on this page.
+ Fetch another.*/
+ ret=op_fetch_and_process_page(_of,NULL,-1,0,1);
+ if(OP_UNLIKELY(ret<0))return OP_EBADLINK;
+ }
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,prev_packet_gp,pcm_start));
+ /*We skipped too far.
+ Either the timestamps were illegal or there was a hole in the data.*/
+ if(diff>skip)return OP_EBADLINK;
+ OP_ASSERT(_pcm_offset-diff<OP_INT32_MAX);
+ /*TODO: If there are further holes/illegal timestamps, we still won't decode
+ to the correct sample.
+ However, at least op_pcm_tell() will report the correct value immediately
+ after returning.*/
+ _of->cur_discard_count=(opus_int32)(_pcm_offset-diff);
+ return 0;
+}
+
+opus_int64 op_raw_tell(const OggOpusFile *_of){
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ return _of->offset;
+}
+
+/*Convert a granule position from a given link to a PCM offset relative to the
+ start of the whole stream.
+ For unseekable sources, this gets reset to 0 at the beginning of each link.*/
+static ogg_int64_t op_get_pcm_offset(const OggOpusFile *_of,
+ ogg_int64_t _gp,int _li){
+ const OggOpusLink *links;
+ ogg_int64_t pcm_offset;
+ ogg_int64_t delta=0;
+ int li;
+ links=_of->links;
+ pcm_offset=0;
+ OP_ASSERT(_li<_of->nlinks);
+ for(li=0;li<_li;li++){
+ OP_ALWAYS_TRUE(!op_granpos_diff(&delta,
+ links[li].pcm_end,links[li].pcm_start));
+ delta-=links[li].head.pre_skip;
+ pcm_offset+=delta;
+ }
+ OP_ASSERT(_li>=0);
+ if(_of->seekable&&OP_UNLIKELY(op_granpos_cmp(_gp,links[_li].pcm_end)>0)){
+ _gp=links[_li].pcm_end;
+ }
+ if(OP_LIKELY(op_granpos_cmp(_gp,links[_li].pcm_start)>0)){
+ if(OP_UNLIKELY(op_granpos_diff(&delta,_gp,links[_li].pcm_start)<0)){
+ /*This means an unseekable stream claimed to have a page from more than
+ 2 billion days after we joined.*/
+ OP_ASSERT(!_of->seekable);
+ return OP_INT64_MAX;
+ }
+ if(delta<links[_li].head.pre_skip)delta=0;
+ else delta-=links[_li].head.pre_skip;
+ /*In the seekable case, _gp was limited by pcm_end.
+ In the unseekable case, pcm_offset should be 0.*/
+ OP_ASSERT(pcm_offset<=OP_INT64_MAX-delta);
+ pcm_offset+=delta;
+ }
+ return pcm_offset;
+}
+
+ogg_int64_t op_pcm_tell(const OggOpusFile *_of){
+ ogg_int64_t gp;
+ int nbuffered;
+ int li;
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ gp=_of->prev_packet_gp;
+ if(gp==-1)return 0;
+ nbuffered=OP_MAX(_of->od_buffer_size-_of->od_buffer_pos,0);
+ OP_ALWAYS_TRUE(!op_granpos_add(&gp,gp,-nbuffered));
+ li=_of->seekable?_of->cur_link:0;
+ if(op_granpos_add(&gp,gp,_of->cur_discard_count)<0){
+ gp=_of->links[li].pcm_end;
+ }
+ return op_get_pcm_offset(_of,gp,li);
+}
+
+void op_set_decode_callback(OggOpusFile *_of,
+ op_decode_cb_func _decode_cb,void *_ctx){
+ _of->decode_cb=_decode_cb;
+ _of->decode_cb_ctx=_ctx;
+}
+
+int op_set_gain_offset(OggOpusFile *_of,
+ int _gain_type,opus_int32 _gain_offset_q8){
+ if(_gain_type!=OP_HEADER_GAIN&&_gain_type!=OP_ALBUM_GAIN
+ &&_gain_type!=OP_TRACK_GAIN&&_gain_type!=OP_ABSOLUTE_GAIN){
+ return OP_EINVAL;
+ }
+ _of->gain_type=_gain_type;
+ /*The sum of header gain and track gain lies in the range [-65536,65534].
+ These bounds allow the offset to set the final value to anywhere in the
+ range [-32768,32767], which is what we'll clamp it to before applying.*/
+ _of->gain_offset_q8=OP_CLAMP(-98302,_gain_offset_q8,98303);
+ op_update_gain(_of);
+ return 0;
+}
+
+void op_set_dither_enabled(OggOpusFile *_of,int _enabled){
+#if !defined(OP_FIXED_POINT)
+ _of->dither_disabled=!_enabled;
+ if(!_enabled)_of->dither_mute=65;
+#endif
+}
+
+/*Allocate the decoder scratch buffer.
+ This is done lazily, since if the user provides large enough buffers, we'll
+ never need it.*/
+static int op_init_buffer(OggOpusFile *_of){
+ int nchannels_max;
+ if(_of->seekable){
+ const OggOpusLink *links;
+ int nlinks;
+ int li;
+ links=_of->links;
+ nlinks=_of->nlinks;
+ nchannels_max=1;
+ for(li=0;li<nlinks;li++){
+ nchannels_max=OP_MAX(nchannels_max,links[li].head.channel_count);
+ }
+ }
+ else nchannels_max=OP_NCHANNELS_MAX;
+ _of->od_buffer=(op_sample *)_ogg_malloc(
+ sizeof(*_of->od_buffer)*nchannels_max*120*48);
+ if(_of->od_buffer==NULL)return OP_EFAULT;
+ return 0;
+}
+
+/*Decode a single packet into the target buffer.*/
+static int op_decode(OggOpusFile *_of,op_sample *_pcm,
+ const ogg_packet *_op,int _nsamples,int _nchannels){
+ int ret;
+ /*First we try using the application-provided decode callback.*/
+ if(_of->decode_cb!=NULL){
+#if defined(OP_FIXED_POINT)
+ ret=(*_of->decode_cb)(_of->decode_cb_ctx,_of->od,_pcm,_op,
+ _nsamples,_nchannels,OP_DEC_FORMAT_SHORT,_of->cur_link);
+#else
+ ret=(*_of->decode_cb)(_of->decode_cb_ctx,_of->od,_pcm,_op,
+ _nsamples,_nchannels,OP_DEC_FORMAT_FLOAT,_of->cur_link);
+#endif
+ }
+ else ret=OP_DEC_USE_DEFAULT;
+ /*If the application didn't want to handle decoding, do it ourselves.*/
+ if(ret==OP_DEC_USE_DEFAULT){
+#if defined(OP_FIXED_POINT)
+ ret=opus_multistream_decode(_of->od,
+ _op->packet,_op->bytes,_pcm,_nsamples,0);
+#else
+ ret=opus_multistream_decode_float(_of->od,
+ _op->packet,_op->bytes,_pcm,_nsamples,0);
+#endif
+ OP_ASSERT(ret<0||ret==_nsamples);
+ }
+ /*If the application returned a positive value other than 0 or
+ OP_DEC_USE_DEFAULT, fail.*/
+ else if(OP_UNLIKELY(ret>0))return OP_EBADPACKET;
+ if(OP_UNLIKELY(ret<0))return OP_EBADPACKET;
+ return ret;
+}
+
+/*Read more samples from the stream, using the same API as op_read() or
+ op_read_float().*/
+static int op_read_native(OggOpusFile *_of,
+ op_sample *_pcm,int _buf_size,int *_li){
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ for(;;){
+ int ret;
+ if(OP_LIKELY(_of->ready_state>=OP_INITSET)){
+ int nchannels;
+ int od_buffer_pos;
+ int nsamples;
+ int op_pos;
+ nchannels=_of->links[_of->seekable?_of->cur_link:0].head.channel_count;
+ od_buffer_pos=_of->od_buffer_pos;
+ nsamples=_of->od_buffer_size-od_buffer_pos;
+ /*If we have buffered samples, return them.*/
+ if(nsamples>0){
+ if(nsamples*nchannels>_buf_size)nsamples=_buf_size/nchannels;
+ memcpy(_pcm,_of->od_buffer+nchannels*od_buffer_pos,
+ sizeof(*_pcm)*nchannels*nsamples);
+ od_buffer_pos+=nsamples;
+ _of->od_buffer_pos=od_buffer_pos;
+ if(_li!=NULL)*_li=_of->cur_link;
+ return nsamples;
+ }
+ /*If we have buffered packets, decode one.*/
+ op_pos=_of->op_pos;
+ if(OP_LIKELY(op_pos<_of->op_count)){
+ const ogg_packet *pop;
+ ogg_int64_t diff;
+ opus_int32 cur_discard_count;
+ int duration;
+ int trimmed_duration;
+ pop=_of->op+op_pos++;
+ _of->op_pos=op_pos;
+ cur_discard_count=_of->cur_discard_count;
+ duration=op_get_packet_duration(pop->packet,pop->bytes);
+ /*We don't buffer packets with an invalid TOC sequence.*/
+ OP_ASSERT(duration>0);
+ trimmed_duration=duration;
+ /*Perform end-trimming.*/
+ if(OP_UNLIKELY(pop->e_o_s)){
+ if(OP_UNLIKELY(op_granpos_cmp(pop->granulepos,
+ _of->prev_packet_gp)<=0)){
+ trimmed_duration=0;
+ }
+ else if(OP_LIKELY(!op_granpos_diff(&diff,
+ pop->granulepos,_of->prev_packet_gp))){
+ trimmed_duration=(int)OP_MIN(diff,trimmed_duration);
+ }
+ }
+ _of->prev_packet_gp=pop->granulepos;
+ if(OP_UNLIKELY(duration*nchannels>_buf_size)){
+ op_sample *buf;
+ /*If the user's buffer is too small, decode into a scratch buffer.*/
+ buf=_of->od_buffer;
+ if(OP_UNLIKELY(buf==NULL)){
+ ret=op_init_buffer(_of);
+ if(OP_UNLIKELY(ret<0))return ret;
+ buf=_of->od_buffer;
+ }
+ ret=op_decode(_of,buf,pop,duration,nchannels);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*Perform pre-skip/pre-roll.*/
+ od_buffer_pos=(int)OP_MIN(trimmed_duration,cur_discard_count);
+ cur_discard_count-=od_buffer_pos;
+ _of->cur_discard_count=cur_discard_count;
+ _of->od_buffer_pos=od_buffer_pos;
+ _of->od_buffer_size=trimmed_duration;
+ /*Update bitrate tracking based on the actual samples we used from
+ what was decoded.*/
+ _of->bytes_tracked+=pop->bytes;
+ _of->samples_tracked+=trimmed_duration-od_buffer_pos;
+ }
+ else{
+ /*Otherwise decode directly into the user's buffer.*/
+ ret=op_decode(_of,_pcm,pop,duration,nchannels);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(OP_LIKELY(trimmed_duration>0)){
+ /*Perform pre-skip/pre-roll.*/
+ od_buffer_pos=(int)OP_MIN(trimmed_duration,cur_discard_count);
+ cur_discard_count-=od_buffer_pos;
+ _of->cur_discard_count=cur_discard_count;
+ trimmed_duration-=od_buffer_pos;
+ if(OP_LIKELY(trimmed_duration>0)
+ &&OP_UNLIKELY(od_buffer_pos>0)){
+ memmove(_pcm,_pcm+od_buffer_pos*nchannels,
+ sizeof(*_pcm)*trimmed_duration*nchannels);
+ }
+ /*Update bitrate tracking based on the actual samples we used from
+ what was decoded.*/
+ _of->bytes_tracked+=pop->bytes;
+ _of->samples_tracked+=trimmed_duration;
+ if(OP_LIKELY(trimmed_duration>0)){
+ if(_li!=NULL)*_li=_of->cur_link;
+ return trimmed_duration;
+ }
+ }
+ }
+ /*Don't grab another page yet.
+ This one might have more packets, or might have buffered data now.*/
+ continue;
+ }
+ }
+ /*Suck in another page.*/
+ ret=op_fetch_and_process_page(_of,NULL,-1,1,0);
+ if(OP_UNLIKELY(ret==OP_EOF)){
+ if(_li!=NULL)*_li=_of->cur_link;
+ return 0;
+ }
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+}
+
+/*A generic filter to apply to the decoded audio data.
+ _src is non-const because we will destructively modify the contents of the
+ source buffer that we consume in some cases.*/
+typedef int (*op_read_filter_func)(OggOpusFile *_of,void *_dst,int _dst_sz,
+ op_sample *_src,int _nsamples,int _nchannels);
+
+/*Decode some samples and then apply a custom filter to them.
+ This is used to convert to different output formats.*/
+static int op_filter_read_native(OggOpusFile *_of,void *_dst,int _dst_sz,
+ op_read_filter_func _filter,int *_li){
+ int ret;
+ /*Ensure we have some decoded samples in our buffer.*/
+ ret=op_read_native(_of,NULL,0,_li);
+ /*Now apply the filter to them.*/
+ if(OP_LIKELY(ret>=0)&&OP_LIKELY(_of->ready_state>=OP_INITSET)){
+ int od_buffer_pos;
+ od_buffer_pos=_of->od_buffer_pos;
+ ret=_of->od_buffer_size-od_buffer_pos;
+ if(OP_LIKELY(ret>0)){
+ int nchannels;
+ nchannels=_of->links[_of->seekable?_of->cur_link:0].head.channel_count;
+ ret=(*_filter)(_of,_dst,_dst_sz,
+ _of->od_buffer+nchannels*od_buffer_pos,ret,nchannels);
+ OP_ASSERT(ret>=0);
+ OP_ASSERT(ret<=_of->od_buffer_size-od_buffer_pos);
+ od_buffer_pos+=ret;
+ _of->od_buffer_pos=od_buffer_pos;
+ }
+ }
+ return ret;
+}
+
+#if !defined(OP_FIXED_POINT)||!defined(OP_DISABLE_FLOAT_API)
+
+/*Matrices for downmixing from the supported channel counts to stereo.
+ The matrices with 5 or more channels are normalized to a total volume of 2.0,
+ since most mixes sound too quiet if normalized to 1.0 (as there is generally
+ little volume in the side/rear channels).*/
+static const float OP_STEREO_DOWNMIX[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={
+ /*3.0*/
+ {
+ {0.5858F,0.0F},{0.4142F,0.4142F},{0.0F,0.5858F}
+ },
+ /*quadrophonic*/
+ {
+ {0.4226F,0.0F},{0.0F,0.4226F},{0.366F,0.2114F},{0.2114F,0.336F}
+ },
+ /*5.0*/
+ {
+ {0.651F,0.0F},{0.46F,0.46F},{0.0F,0.651F},{0.5636F,0.3254F},
+ {0.3254F,0.5636F}
+ },
+ /*5.1*/
+ {
+ {0.529F,0.0F},{0.3741F,0.3741F},{0.0F,0.529F},{0.4582F,0.2645F},
+ {0.2645F,0.4582F},{0.3741F,0.3741F}
+ },
+ /*6.1*/
+ {
+ {0.4553F,0.0F},{0.322F,0.322F},{0.0F,0.4553F},{0.3943F,0.2277F},
+ {0.2277F,0.3943F},{0.2788F,0.2788F},{0.322F,0.322F}
+ },
+ /*7.1*/
+ {
+ {0.3886F,0.0F},{0.2748F,0.2748F},{0.0F,0.3886F},{0.3366F,0.1943F},
+ {0.1943F,0.3366F},{0.3366F,0.1943F},{0.1943F,0.3366F},{0.2748F,0.2748F}
+ }
+};
+
+#endif
+
+#if defined(OP_FIXED_POINT)
+
+/*Matrices for downmixing from the supported channel counts to stereo.
+ The matrices with 5 or more channels are normalized to a total volume of 2.0,
+ since most mixes sound too quiet if normalized to 1.0 (as there is generally
+ little volume in the side/rear channels).
+ Hence we keep the coefficients in Q14, so the downmix values won't overflow a
+ 32-bit number.*/
+static const opus_int16 OP_STEREO_DOWNMIX_Q14
+ [OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={
+ /*3.0*/
+ {
+ {9598,0},{6786,6786},{0,9598}
+ },
+ /*quadrophonic*/
+ {
+ {6924,0},{0,6924},{5996,3464},{3464,5996}
+ },
+ /*5.0*/
+ {
+ {10666,0},{7537,7537},{0,10666},{9234,5331},{5331,9234}
+ },
+ /*5.1*/
+ {
+ {8668,0},{6129,6129},{0,8668},{7507,4335},{4335,7507},{6129,6129}
+ },
+ /*6.1*/
+ {
+ {7459,0},{5275,5275},{0,7459},{6460,3731},{3731,6460},{4568,4568},
+ {5275,5275}
+ },
+ /*7.1*/
+ {
+ {6368,0},{4502,4502},{0,6368},{5515,3183},{3183,5515},{5515,3183},
+ {3183,5515},{4502,4502}
+ }
+};
+
+int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){
+ return op_read_native(_of,_pcm,_buf_size,_li);
+}
+
+static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
+ op_sample *_src,int _nsamples,int _nchannels){
+ (void)_of;
+ _nsamples=OP_MIN(_nsamples,_dst_sz>>1);
+ if(_nchannels==2)memcpy(_dst,_src,_nsamples*2*sizeof(*_src));
+ else{
+ opus_int16 *dst;
+ int i;
+ dst=(opus_int16 *)_dst;
+ if(_nchannels==1){
+ for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i];
+ }
+ else{
+ for(i=0;i<_nsamples;i++){
+ opus_int32 l;
+ opus_int32 r;
+ int ci;
+ l=r=0;
+ for(ci=0;ci<_nchannels;ci++){
+ opus_int32 s;
+ s=_src[_nchannels*i+ci];
+ l+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][0]*s;
+ r+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][1]*s;
+ }
+ /*TODO: For 5 or more channels, we should do soft clipping here.*/
+ dst[2*i+0]=(opus_int16)OP_CLAMP(-32768,l+8192>>14,32767);
+ dst[2*i+1]=(opus_int16)OP_CLAMP(-32768,r+8192>>14,32767);
+ }
+ }
+ }
+ return _nsamples;
+}
+
+int op_read_stereo(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size){
+ return op_filter_read_native(_of,_pcm,_buf_size,op_stereo_filter,NULL);
+}
+
+# if !defined(OP_DISABLE_FLOAT_API)
+
+static int op_short2float_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
+ op_sample *_src,int _nsamples,int _nchannels){
+ float *dst;
+ int i;
+ (void)_of;
+ dst=(float *)_dst;
+ if(OP_UNLIKELY(_nsamples*_nchannels>_dst_sz))_nsamples=_dst_sz/_nchannels;
+ _dst_sz=_nsamples*_nchannels;
+ for(i=0;i<_dst_sz;i++)dst[i]=(1.0F/32768)*_src[i];
+ return _nsamples;
+}
+
+int op_read_float(OggOpusFile *_of,float *_pcm,int _buf_size,int *_li){
+ return op_filter_read_native(_of,_pcm,_buf_size,op_short2float_filter,_li);
+}
+
+static int op_short2float_stereo_filter(OggOpusFile *_of,
+ void *_dst,int _dst_sz,op_sample *_src,int _nsamples,int _nchannels){
+ float *dst;
+ int i;
+ dst=(float *)_dst;
+ _nsamples=OP_MIN(_nsamples,_dst_sz>>1);
+ if(_nchannels==1){
+ _nsamples=op_short2float_filter(_of,dst,_nsamples,_src,_nsamples,1);
+ for(i=_nsamples;i-->0;)dst[2*i+0]=dst[2*i+1]=dst[i];
+ }
+ else if(_nchannels<5){
+ /*For 3 or 4 channels, we can downmix in fixed point without risk of
+ clipping.*/
+ if(_nchannels>2){
+ _nsamples=op_stereo_filter(_of,_src,_nsamples*2,
+ _src,_nsamples,_nchannels);
+ }
+ return op_short2float_filter(_of,dst,_dst_sz,_src,_nsamples,2);
+ }
+ else{
+ /*For 5 or more channels, we convert to floats and then downmix (so that we
+ don't risk clipping).*/
+ for(i=0;i<_nsamples;i++){
+ float l;
+ float r;
+ int ci;
+ l=r=0;
+ for(ci=0;ci<_nchannels;ci++){
+ float s;
+ s=(1.0F/32768)*_src[_nchannels*i+ci];
+ l+=OP_STEREO_DOWNMIX[_nchannels-3][ci][0]*s;
+ r+=OP_STEREO_DOWNMIX[_nchannels-3][ci][1]*s;
+ }
+ dst[2*i+0]=l;
+ dst[2*i+1]=r;
+ }
+ }
+ return _nsamples;
+}
+
+int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){
+ return op_filter_read_native(_of,_pcm,_buf_size,
+ op_short2float_stereo_filter,NULL);
+}
+
+# endif
+
+#else
+
+# if defined(OP_HAVE_LRINTF)
+# include <math.h>
+# define op_float2int(_x) (lrintf(_x))
+# else
+# define op_float2int(_x) ((int)((_x)+((_x)<0?-0.5F:0.5F)))
+# endif
+
+/*The dithering code here is adapted from opusdec, part of opus-tools.
+ It was originally written by Greg Maxwell.*/
+
+static opus_uint32 op_rand(opus_uint32 _seed){
+ return _seed*96314165+907633515&0xFFFFFFFFU;
+}
+
+/*This implements 16-bit quantization with full triangular dither and IIR noise
+ shaping.
+ The noise shaping filters were designed by Sebastian Gesemann, and are based
+ on the LAME ATH curves with flattening to limit their peak gain to 20 dB.
+ Everyone else's noise shaping filters are mildly crazy.
+ The 48 kHz version of this filter is just a warped version of the 44.1 kHz
+ filter and probably could be improved by shifting the HF shelf up in
+ frequency a little bit, since 48 kHz has a bit more room and being more
+ conservative against bat-ears is probably more important than more noise
+ suppression.
+ This process can increase the peak level of the signal (in theory by the peak
+ error of 1.5 +20 dB, though that is unobservably rare).
+ To avoid clipping, the signal is attenuated by a couple thousandths of a dB.
+ Initially, the approach taken here was to only attenuate by the 99.9th
+ percentile, making clipping rare but not impossible (like SoX), but the
+ limited gain of the filter means that the worst case was only two
+ thousandths of a dB more, so this just uses the worst case.
+ The attenuation is probably also helpful to prevent clipping in the DAC
+ reconstruction filters or downstream resampling, in any case.*/
+
+# define OP_GAIN (32753.0F)
+
+# define OP_PRNG_GAIN (1.0F/0xFFFFFFFF)
+
+/*48 kHz noise shaping filter, sd=2.34.*/
+
+static const float OP_FCOEF_B[4]={
+ 2.2374F,-0.7339F,-0.1251F,-0.6033F
+};
+
+static const float OP_FCOEF_A[4]={
+ 0.9030F,0.0116F,-0.5853F,-0.2571F
+};
+
+static int op_float2short_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
+ float *_src,int _nsamples,int _nchannels){
+ opus_int16 *dst;
+ int ci;
+ int i;
+ dst=(opus_int16 *)_dst;
+ if(OP_UNLIKELY(_nsamples*_nchannels>_dst_sz))_nsamples=_dst_sz/_nchannels;
+# if defined(OP_SOFT_CLIP)
+ if(_of->state_channel_count!=_nchannels){
+ for(ci=0;ci<_nchannels;ci++)_of->clip_state[ci]=0;
+ }
+ opus_pcm_soft_clip(_src,_nsamples,_nchannels,_of->clip_state);
+# endif
+ if(_of->dither_disabled){
+ for(i=0;i<_nchannels*_nsamples;i++){
+ dst[i]=op_float2int(OP_CLAMP(-32768,32768.0F*_src[i],32767));
+ }
+ }
+ else{
+ opus_uint32 seed;
+ int mute;
+ seed=_of->dither_seed;
+ mute=_of->dither_mute;
+ if(_of->state_channel_count!=_nchannels)mute=65;
+ /*In order to avoid replacing digital silence with quiet dither noise, we
+ mute if the output has been silent for a while.*/
+ if(mute>64)memset(_of->dither_a,0,sizeof(*_of->dither_a)*4*_nchannels);
+ for(i=0;i<_nsamples;i++){
+ int silent;
+ silent=1;
+ for(ci=0;ci<_nchannels;ci++){
+ float r;
+ float s;
+ float err;
+ int si;
+ int j;
+ s=_src[_nchannels*i+ci];
+ silent&=s==0;
+ s*=OP_GAIN;
+ err=0;
+ for(j=0;j<4;j++){
+ err+=OP_FCOEF_B[j]*_of->dither_b[ci*4+j]
+ -OP_FCOEF_A[j]*_of->dither_a[ci*4+j];
+ }
+ for(j=3;j-->0;)_of->dither_a[ci*4+j+1]=_of->dither_a[ci*4+j];
+ for(j=3;j-->0;)_of->dither_b[ci*4+j+1]=_of->dither_b[ci*4+j];
+ _of->dither_a[ci*4]=err;
+ s-=err;
+ if(mute>16)r=0;
+ else{
+ seed=op_rand(seed);
+ r=seed*OP_PRNG_GAIN;
+ seed=op_rand(seed);
+ r-=seed*OP_PRNG_GAIN;
+ }
+ /*Clamp in float out of paranoia that the input will be > 96 dBFS and
+ wrap if the integer is clamped.*/
+ si=op_float2int(OP_CLAMP(-32768,s+r,32767));
+ dst[_nchannels*i+ci]=(opus_int16)si;
+ /*Including clipping in the noise shaping is generally disastrous: the
+ futile effort to restore the clipped energy results in more clipping.
+ However, small amounts---at the level which could normally be created
+ by dither and rounding---are harmless and can even reduce clipping
+ somewhat due to the clipping sometimes reducing the dither + rounding
+ error.*/
+ _of->dither_b[ci*4]=mute>16?0:OP_CLAMP(-1.5F,si-s,1.5F);
+ }
+ mute++;
+ if(!silent)mute=0;
+ }
+ _of->dither_mute=OP_MIN(mute,65);
+ _of->dither_seed=seed;
+ }
+ _of->state_channel_count=_nchannels;
+ return _nsamples;
+}
+
+int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){
+ return op_filter_read_native(_of,_pcm,_buf_size,op_float2short_filter,_li);
+}
+
+int op_read_float(OggOpusFile *_of,float *_pcm,int _buf_size,int *_li){
+ _of->state_channel_count=0;
+ return op_read_native(_of,_pcm,_buf_size,_li);
+}
+
+static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
+ op_sample *_src,int _nsamples,int _nchannels){
+ (void)_of;
+ _nsamples=OP_MIN(_nsamples,_dst_sz>>1);
+ if(_nchannels==2)memcpy(_dst,_src,_nsamples*2*sizeof(*_src));
+ else{
+ float *dst;
+ int i;
+ dst=(float *)_dst;
+ if(_nchannels==1){
+ for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i];
+ }
+ else{
+ for(i=0;i<_nsamples;i++){
+ float l;
+ float r;
+ int ci;
+ l=r=0;
+ for(ci=0;ci<_nchannels;ci++){
+ l+=OP_STEREO_DOWNMIX[_nchannels-3][ci][0]*_src[_nchannels*i+ci];
+ r+=OP_STEREO_DOWNMIX[_nchannels-3][ci][1]*_src[_nchannels*i+ci];
+ }
+ dst[2*i+0]=l;
+ dst[2*i+1]=r;
+ }
+ }
+ }
+ return _nsamples;
+}
+
+static int op_float2short_stereo_filter(OggOpusFile *_of,
+ void *_dst,int _dst_sz,op_sample *_src,int _nsamples,int _nchannels){
+ opus_int16 *dst;
+ dst=(opus_int16 *)_dst;
+ if(_nchannels==1){
+ int i;
+ _nsamples=op_float2short_filter(_of,dst,_dst_sz>>1,_src,_nsamples,1);
+ for(i=_nsamples;i-->0;)dst[2*i+0]=dst[2*i+1]=dst[i];
+ }
+ else{
+ if(_nchannels>2){
+ _nsamples=OP_MIN(_nsamples,_dst_sz>>1);
+ _nsamples=op_stereo_filter(_of,_src,_nsamples*2,
+ _src,_nsamples,_nchannels);
+ }
+ _nsamples=op_float2short_filter(_of,dst,_dst_sz,_src,_nsamples,2);
+ }
+ return _nsamples;
+}
+
+int op_read_stereo(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size){
+ return op_filter_read_native(_of,_pcm,_buf_size,
+ op_float2short_stereo_filter,NULL);
+}
+
+int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){
+ _of->state_channel_count=0;
+ return op_filter_read_native(_of,_pcm,_buf_size,op_stereo_filter,NULL);
+}
+
+#endif
diff --git a/external/opusfile-0.8/src/stream.c b/external/opusfile-0.8/src/stream.c
new file mode 100644
index 0000000..0238a6b
--- /dev/null
+++ b/external/opusfile-0.8/src/stream.c
@@ -0,0 +1,366 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: stdio-based convenience library for opening/seeking/decoding
+ last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $
+
+ ********************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "internal.h"
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#if defined(_WIN32)
+# include <io.h>
+#endif
+
+typedef struct OpusMemStream OpusMemStream;
+
+#define OP_MEM_SIZE_MAX (~(size_t)0>>1)
+#define OP_MEM_DIFF_MAX ((ptrdiff_t)OP_MEM_SIZE_MAX)
+
+/*The context information needed to read from a block of memory as if it were a
+ file.*/
+struct OpusMemStream{
+ /*The block of memory to read from.*/
+ const unsigned char *data;
+ /*The total size of the block.
+ This must be at most OP_MEM_SIZE_MAX to prevent signed overflow while
+ seeking.*/
+ ptrdiff_t size;
+ /*The current file position.
+ This is allowed to be set arbitrarily greater than size (i.e., past the end
+ of the block, though we will not read data past the end of the block), but
+ is not allowed to be negative (i.e., before the beginning of the block).*/
+ ptrdiff_t pos;
+};
+
+static int op_fread(void *_stream,unsigned char *_ptr,int _buf_size){
+ FILE *stream;
+ size_t ret;
+ /*Check for empty read.*/
+ if(_buf_size<=0)return 0;
+ stream=(FILE *)_stream;
+ ret=fread(_ptr,1,_buf_size,stream);
+ OP_ASSERT(ret<=(size_t)_buf_size);
+ /*If ret==0 and !feof(stream), there was a read error.*/
+ return ret>0||feof(stream)?(int)ret:OP_EREAD;
+}
+
+static int op_fseek(void *_stream,opus_int64 _offset,int _whence){
+#if defined(_WIN32)
+ /*_fseeki64() is not exposed until MSCVCRT80.
+ This is the default starting with MSVC 2005 (_MSC_VER>=1400), but we want
+ to allow linking against older MSVCRT versions for compatibility back to
+ XP without installing extra runtime libraries.
+ i686-pc-mingw32 does not have fseeko() and requires
+ __MSVCRT_VERSION__>=0x800 for _fseeki64(), which screws up linking with
+ other libraries (that don't use MSVCRT80 from MSVC 2005 by default).
+ i686-w64-mingw32 does have fseeko() and respects _FILE_OFFSET_BITS, but I
+ don't know how to detect that at compile time.
+ We could just use fseeko64() (which is available in both), but its
+ implemented using fgetpos()/fsetpos() just like this code, except without
+ the overflow checking, so we prefer our version.*/
+ opus_int64 pos;
+ /*We don't use fpos_t directly because it might be a struct if __STDC__ is
+ non-zero or _INTEGRAL_MAX_BITS < 64.
+ I'm not certain when the latter is true, but someone could in theory set
+ the former.
+ Either way, it should be binary compatible with a normal 64-bit int (this
+ assumption is not portable, but I believe it is true for MSVCRT).*/
+ OP_ASSERT(sizeof(pos)==sizeof(fpos_t));
+ /*Translate the seek to an absolute one.*/
+ if(_whence==SEEK_CUR){
+ int ret;
+ ret=fgetpos((FILE *)_stream,(fpos_t *)&pos);
+ if(ret)return ret;
+ }
+ else if(_whence==SEEK_END)pos=_filelengthi64(_fileno((FILE *)_stream));
+ else if(_whence==SEEK_SET)pos=0;
+ else return -1;
+ /*Check for errors or overflow.*/
+ if(pos<0||_offset<-pos||_offset>OP_INT64_MAX-pos)return -1;
+ pos+=_offset;
+ return fsetpos((FILE *)_stream,(fpos_t *)&pos);
+#else
+ /*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer
+ it except on Windows.*/
+ return fseeko((FILE *)_stream,(off_t)_offset,_whence);
+#endif
+}
+
+static opus_int64 op_ftell(void *_stream){
+#if defined(_WIN32)
+ /*_ftelli64() is not exposed until MSCVCRT80, and ftello()/ftello64() have
+ the same problems as fseeko()/fseeko64() in MingW.
+ See above for a more detailed explanation.*/
+ opus_int64 pos;
+ OP_ASSERT(sizeof(pos)==sizeof(fpos_t));
+ return fgetpos((FILE *)_stream,(fpos_t *)&pos)?-1:pos;
+#else
+ /*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer
+ it except on Windows.*/
+ return ftello((FILE *)_stream);
+#endif
+}
+
+static const OpusFileCallbacks OP_FILE_CALLBACKS={
+ op_fread,
+ op_fseek,
+ op_ftell,
+ (op_close_func)fclose
+};
+
+#if defined(_WIN32)
+# include <stddef.h>
+# include <errno.h>
+
+/*Windows doesn't accept UTF-8 by default, and we don't have a wchar_t API,
+ so if we just pass the path to fopen(), then there'd be no way for a user
+ of our API to open a Unicode filename.
+ Instead, we translate from UTF-8 to UTF-16 and use Windows' wchar_t API.
+ This makes this API more consistent with platforms where the character set
+ used by fopen is the same as used on disk, which is generally UTF-8, and
+ with our metadata API, which always uses UTF-8.*/
+static wchar_t *op_utf8_to_utf16(const char *_src){
+ wchar_t *dst;
+ size_t len;
+ len=strlen(_src);
+ /*Worst-case output is 1 wide character per 1 input character.*/
+ dst=(wchar_t *)_ogg_malloc(sizeof(*dst)*(len+1));
+ if(dst!=NULL){
+ size_t si;
+ size_t di;
+ for(di=si=0;si<len;si++){
+ int c0;
+ c0=(unsigned char)_src[si];
+ if(!(c0&0x80)){
+ /*Start byte says this is a 1-byte sequence.*/
+ dst[di++]=(wchar_t)c0;
+ continue;
+ }
+ else{
+ int c1;
+ /*This is safe, because c0 was not 0 and _src is NUL-terminated.*/
+ c1=(unsigned char)_src[si+1];
+ if((c1&0xC0)==0x80){
+ /*Found at least one continuation byte.*/
+ if((c0&0xE0)==0xC0){
+ wchar_t w;
+ /*Start byte says this is a 2-byte sequence.*/
+ w=(c0&0x1F)<<6|c1&0x3F;
+ if(w>=0x80U){
+ /*This is a 2-byte sequence that is not overlong.*/
+ dst[di++]=w;
+ si++;
+ continue;
+ }
+ }
+ else{
+ int c2;
+ /*This is safe, because c1 was not 0 and _src is NUL-terminated.*/
+ c2=(unsigned char)_src[si+2];
+ if((c2&0xC0)==0x80){
+ /*Found at least two continuation bytes.*/
+ if((c0&0xF0)==0xE0){
+ wchar_t w;
+ /*Start byte says this is a 3-byte sequence.*/
+ w=(c0&0xF)<<12|(c1&0x3F)<<6|c2&0x3F;
+ if(w>=0x800U&&(w<0xD800||w>=0xE000)&&w<0xFFFE){
+ /*This is a 3-byte sequence that is not overlong, not a
+ UTF-16 surrogate pair value, and not a 'not a character'
+ value.*/
+ dst[di++]=w;
+ si+=2;
+ continue;
+ }
+ }
+ else{
+ int c3;
+ /*This is safe, because c2 was not 0 and _src is
+ NUL-terminated.*/
+ c3=(unsigned char)_src[si+3];
+ if((c3&0xC0)==0x80){
+ /*Found at least three continuation bytes.*/
+ if((c0&0xF8)==0xF0){
+ opus_uint32 w;
+ /*Start byte says this is a 4-byte sequence.*/
+ w=(c0&7)<<18|(c1&0x3F)<<12|(c2&0x3F)<<6&(c3&0x3F);
+ if(w>=0x10000U&&w<0x110000U){
+ /*This is a 4-byte sequence that is not overlong and not
+ greater than the largest valid Unicode code point.
+ Convert it to a surrogate pair.*/
+ w-=0x10000;
+ dst[di++]=(wchar_t)(0xD800+(w>>10));
+ dst[di++]=(wchar_t)(0xDC00+(w&0x3FF));
+ si+=3;
+ continue;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ /*If we got here, we encountered an illegal UTF-8 sequence.*/
+ _ogg_free(dst);
+ return NULL;
+ }
+ OP_ASSERT(di<=len);
+ dst[di]='\0';
+ }
+ return dst;
+}
+
+#endif
+
+void *op_fopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode){
+ FILE *fp;
+#if !defined(_WIN32)
+ fp=fopen(_path,_mode);
+#else
+ fp=NULL;
+ if(_path==NULL||_mode==NULL)errno=EINVAL;
+ else{
+ wchar_t *wpath;
+ wchar_t *wmode;
+ wpath=op_utf8_to_utf16(_path);
+ wmode=op_utf8_to_utf16(_mode);
+ if(wmode==NULL)errno=EINVAL;
+ else if(wpath==NULL)errno=ENOENT;
+ else fp=_wfopen(wpath,wmode);
+ _ogg_free(wmode);
+ _ogg_free(wpath);
+ }
+#endif
+ if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
+ return fp;
+}
+
+void *op_fdopen(OpusFileCallbacks *_cb,int _fd,const char *_mode){
+ FILE *fp;
+ fp=fdopen(_fd,_mode);
+ if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
+ return fp;
+}
+
+void *op_freopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode,
+ void *_stream){
+ FILE *fp;
+#if !defined(_WIN32)
+ fp=freopen(_path,_mode,(FILE *)_stream);
+#else
+ fp=NULL;
+ if(_path==NULL||_mode==NULL)errno=EINVAL;
+ else{
+ wchar_t *wpath;
+ wchar_t *wmode;
+ wpath=op_utf8_to_utf16(_path);
+ wmode=op_utf8_to_utf16(_mode);
+ if(wmode==NULL)errno=EINVAL;
+ else if(wpath==NULL)errno=ENOENT;
+ else fp=_wfreopen(wpath,wmode,(FILE *)_stream);
+ _ogg_free(wmode);
+ _ogg_free(wpath);
+ }
+#endif
+ if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
+ return fp;
+}
+
+static int op_mem_read(void *_stream,unsigned char *_ptr,int _buf_size){
+ OpusMemStream *stream;
+ ptrdiff_t size;
+ ptrdiff_t pos;
+ stream=(OpusMemStream *)_stream;
+ /*Check for empty read.*/
+ if(_buf_size<=0)return 0;
+ size=stream->size;
+ pos=stream->pos;
+ /*Check for EOF.*/
+ if(pos>=size)return 0;
+ /*Check for a short read.*/
+ _buf_size=(int)OP_MIN(size-pos,_buf_size);
+ memcpy(_ptr,stream->data+pos,_buf_size);
+ pos+=_buf_size;
+ stream->pos=pos;
+ return _buf_size;
+}
+
+static int op_mem_seek(void *_stream,opus_int64 _offset,int _whence){
+ OpusMemStream *stream;
+ ptrdiff_t pos;
+ stream=(OpusMemStream *)_stream;
+ pos=stream->pos;
+ OP_ASSERT(pos>=0);
+ switch(_whence){
+ case SEEK_SET:{
+ /*Check for overflow:*/
+ if(_offset<0||_offset>OP_MEM_DIFF_MAX)return -1;
+ pos=(ptrdiff_t)_offset;
+ }break;
+ case SEEK_CUR:{
+ /*Check for overflow:*/
+ if(_offset<-pos||_offset>OP_MEM_DIFF_MAX-pos)return -1;
+ pos=(ptrdiff_t)(pos+_offset);
+ }break;
+ case SEEK_END:{
+ ptrdiff_t size;
+ size=stream->size;
+ OP_ASSERT(size>=0);
+ /*Check for overflow:*/
+ if(_offset>size||_offset<size-OP_MEM_DIFF_MAX)return -1;
+ pos=(ptrdiff_t)(size-_offset);
+ }break;
+ default:return -1;
+ }
+ stream->pos=pos;
+ return 0;
+}
+
+static opus_int64 op_mem_tell(void *_stream){
+ OpusMemStream *stream;
+ stream=(OpusMemStream *)_stream;
+ return (ogg_int64_t)stream->pos;
+}
+
+static int op_mem_close(void *_stream){
+ _ogg_free(_stream);
+ return 0;
+}
+
+static const OpusFileCallbacks OP_MEM_CALLBACKS={
+ op_mem_read,
+ op_mem_seek,
+ op_mem_tell,
+ op_mem_close
+};
+
+void *op_mem_stream_create(OpusFileCallbacks *_cb,
+ const unsigned char *_data,size_t _size){
+ OpusMemStream *stream;
+ if(_size>OP_MEM_SIZE_MAX)return NULL;
+ stream=(OpusMemStream *)_ogg_malloc(sizeof(*stream));
+ if(stream!=NULL){
+ *_cb=*&OP_MEM_CALLBACKS;
+ stream->data=_data;
+ stream->size=_size;
+ stream->pos=0;
+ }
+ return stream;
+}
diff --git a/external/opusfile-0.8/src/wincerts.c b/external/opusfile-0.8/src/wincerts.c
new file mode 100644
index 0000000..b0e35aa
--- /dev/null
+++ b/external/opusfile-0.8/src/wincerts.c
@@ -0,0 +1,171 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2013 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+
+/*This should really be part of OpenSSL, but there's been a patch [1] sitting
+ in their bugtracker for over two years that implements this, without any
+ action, so I'm giving up and re-implementing it locally.
+
+ [1] <http://rt.openssl.org/Ticket/Display.html?id=2158>*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "internal.h"
+#if defined(OP_ENABLE_HTTP)&&defined(_WIN32)
+/*You must include windows.h before wincrypt.h and x509.h.*/
+# define WIN32_LEAN_AND_MEAN
+# define WIN32_EXTRA_LEAN
+# include <windows.h>
+/*You must include wincrypt.h before x509.h, too, or X509_NAME doesn't get
+ defined properly.*/
+# include <wincrypt.h>
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# include <openssl/x509.h>
+
+static int op_capi_new(X509_LOOKUP *_lu){
+ HCERTSTORE h_store;
+ h_store=CertOpenStore(CERT_STORE_PROV_SYSTEM_A,0,0,
+ CERT_STORE_OPEN_EXISTING_FLAG|CERT_STORE_READONLY_FLAG|
+ CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_SHARE_CONTEXT_FLAG,"ROOT");
+ if(h_store!=NULL){
+ _lu->method_data=(char *)h_store;
+ return 1;
+ }
+ return 0;
+}
+
+static void op_capi_free(X509_LOOKUP *_lu){
+ HCERTSTORE h_store;
+ h_store=(HCERTSTORE)_lu->method_data;
+# if defined(OP_ENABLE_ASSERTIONS)
+ OP_ALWAYS_TRUE(CertCloseStore(h_store,CERT_CLOSE_STORE_CHECK_FLAG));
+# else
+ CertCloseStore(h_store,0);
+# endif
+}
+
+static int op_capi_retrieve_by_subject(X509_LOOKUP *_lu,int _type,
+ X509_NAME *_name,X509_OBJECT *_ret){
+ X509_OBJECT *obj;
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ obj=X509_OBJECT_retrieve_by_subject(_lu->store_ctx->objs,_type,_name);
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ if(obj!=NULL){
+ _ret->type=obj->type;
+ memcpy(&_ret->data,&obj->data,sizeof(_ret->data));
+ return 1;
+ }
+ return 0;
+}
+
+static int op_capi_get_by_subject(X509_LOOKUP *_lu,int _type,X509_NAME *_name,
+ X509_OBJECT *_ret){
+ HCERTSTORE h_store;
+ if(_name==NULL)return 0;
+ if(_name->bytes==NULL||_name->bytes->length<=0||_name->modified){
+ if(i2d_X509_NAME(_name,NULL)<0)return 0;
+ OP_ASSERT(_name->bytes->length>0);
+ }
+ h_store=(HCERTSTORE)_lu->method_data;
+ switch(_type){
+ case X509_LU_X509:{
+ CERT_NAME_BLOB find_para;
+ PCCERT_CONTEXT cert;
+ X509 *x;
+ int ret;
+ /*Although X509_NAME contains a canon_enc field, that "canonical" [1]
+ encoding was just made up by OpenSSL.
+ It doesn't correspond to any actual standard, and since it drops the
+ initial sequence header, won't be recognized by the Crypto API.
+ The assumption here is that CertFindCertificateInStore() will allow any
+ appropriate variations in the encoding when it does its comparison.
+ This is, however, emphatically not true under Wine, which just compares
+ the encodings with memcmp().
+ Most of the time things work anyway, though, and there isn't really
+ anything we can do to make the situation better.
+
+ [1] A "canonical form" is defined as the one where, if you locked 10
+ mathematicians in a room and asked them to come up with a
+ representation for something, it's the answer that 9 of them would
+ give you back.
+ I don't think OpenSSL's encoding qualifies.*/
+ find_para.cbData=_name->bytes->length;
+ find_para.pbData=(unsigned char *)_name->bytes->data;
+ cert=CertFindCertificateInStore(h_store,X509_ASN_ENCODING,0,
+ CERT_FIND_SUBJECT_NAME,&find_para,NULL);
+ if(cert==NULL)return 0;
+ x=d2i_X509(NULL,(const unsigned char **)&cert->pbCertEncoded,
+ cert->cbCertEncoded);
+ CertFreeCertificateContext(cert);
+ if(x==NULL)return 0;
+ ret=X509_STORE_add_cert(_lu->store_ctx,x);
+ X509_free(x);
+ if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
+ }break;
+ case X509_LU_CRL:{
+ CERT_INFO cert_info;
+ CERT_CONTEXT find_para;
+ PCCRL_CONTEXT crl;
+ X509_CRL *x;
+ int ret;
+ ret=op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
+ if(ret>0)return ret;
+ memset(&cert_info,0,sizeof(cert_info));
+ cert_info.Issuer.cbData=_name->bytes->length;
+ cert_info.Issuer.pbData=(unsigned char *)_name->bytes->data;
+ memset(&find_para,0,sizeof(find_para));
+ find_para.pCertInfo=&cert_info;
+ crl=CertFindCRLInStore(h_store,0,0,CRL_FIND_ISSUED_BY,&find_para,NULL);
+ if(crl==NULL)return 0;
+ x=d2i_X509_CRL(NULL,(const unsigned char **)&crl->pbCrlEncoded,
+ crl->cbCrlEncoded);
+ CertFreeCRLContext(crl);
+ if(x==NULL)return 0;
+ ret=X509_STORE_add_crl(_lu->store_ctx,x);
+ X509_CRL_free(x);
+ if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
+ }break;
+ }
+ return 0;
+}
+
+/*This is not const because OpenSSL doesn't allow it, even though it won't
+ write to it.*/
+static X509_LOOKUP_METHOD X509_LOOKUP_CAPI={
+ "Load Crypto API store into cache",
+ op_capi_new,
+ op_capi_free,
+ NULL,
+ NULL,
+ NULL,
+ op_capi_get_by_subject,
+ NULL,
+ NULL,
+ NULL
+};
+
+int SSL_CTX_set_default_verify_paths_win32(SSL_CTX *_ssl_ctx){
+ X509_STORE *store;
+ X509_LOOKUP *lu;
+ /*We intentionally do not add the normal default paths, as they are usually
+ wrong, and are just asking to be used as an exploit vector.*/
+ store=SSL_CTX_get_cert_store(_ssl_ctx);
+ OP_ASSERT(store!=NULL);
+ lu=X509_STORE_add_lookup(store,&X509_LOOKUP_CAPI);
+ if(lu==NULL)return 0;
+ ERR_clear_error();
+ return 1;
+}
+
+#endif
diff --git a/external/opusfile-0.8/src/winerrno.h b/external/opusfile-0.8/src/winerrno.h
new file mode 100644
index 0000000..32a90b4
--- /dev/null
+++ b/external/opusfile-0.8/src/winerrno.h
@@ -0,0 +1,90 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#if !defined(_opusfile_winerrno_h)
+# define _opusfile_winerrno_h (1)
+
+# include <errno.h>
+# include <winerror.h>
+
+/*These conflict with the MSVC errno.h definitions, but we don't need to use
+ the original ones in any file that deals with sockets.
+ We could map the WSA errors to the errno.h ones (most of which are only
+ available on sufficiently new versions of MSVC), but they aren't ordered the
+ same, and given how rarely we actually look at the values, I don't think
+ it's worth a lookup table.*/
+# undef EWOULDBLOCK
+# undef EINPROGRESS
+# undef EALREADY
+# undef ENOTSOCK
+# undef EDESTADDRREQ
+# undef EMSGSIZE
+# undef EPROTOTYPE
+# undef ENOPROTOOPT
+# undef EPROTONOSUPPORT
+# undef EOPNOTSUPP
+# undef EAFNOSUPPORT
+# undef EADDRINUSE
+# undef EADDRNOTAVAIL
+# undef ENETDOWN
+# undef ENETUNREACH
+# undef ENETRESET
+# undef ECONNABORTED
+# undef ECONNRESET
+# undef ENOBUFS
+# undef EISCONN
+# undef ENOTCONN
+# undef ETIMEDOUT
+# undef ECONNREFUSED
+# undef ELOOP
+# undef ENAMETOOLONG
+# undef EHOSTUNREACH
+# undef ENOTEMPTY
+
+# define EWOULDBLOCK (WSAEWOULDBLOCK-WSABASEERR)
+# define EINPROGRESS (WSAEINPROGRESS-WSABASEERR)
+# define EALREADY (WSAEALREADY-WSABASEERR)
+# define ENOTSOCK (WSAENOTSOCK-WSABASEERR)
+# define EDESTADDRREQ (WSAEDESTADDRREQ-WSABASEERR)
+# define EMSGSIZE (WSAEMSGSIZE-WSABASEERR)
+# define EPROTOTYPE (WSAEPROTOTYPE-WSABASEERR)
+# define ENOPROTOOPT (WSAENOPROTOOPT-WSABASEERR)
+# define EPROTONOSUPPORT (WSAEPROTONOSUPPORT-WSABASEERR)
+# define ESOCKTNOSUPPORT (WSAESOCKTNOSUPPORT-WSABASEERR)
+# define EOPNOTSUPP (WSAEOPNOTSUPP-WSABASEERR)
+# define EPFNOSUPPORT (WSAEPFNOSUPPORT-WSABASEERR)
+# define EAFNOSUPPORT (WSAEAFNOSUPPORT-WSABASEERR)
+# define EADDRINUSE (WSAEADDRINUSE-WSABASEERR)
+# define EADDRNOTAVAIL (WSAEADDRNOTAVAIL-WSABASEERR)
+# define ENETDOWN (WSAENETDOWN-WSABASEERR)
+# define ENETUNREACH (WSAENETUNREACH-WSABASEERR)
+# define ENETRESET (WSAENETRESET-WSABASEERR)
+# define ECONNABORTED (WSAECONNABORTED-WSABASEERR)
+# define ECONNRESET (WSAECONNRESET-WSABASEERR)
+# define ENOBUFS (WSAENOBUFS-WSABASEERR)
+# define EISCONN (WSAEISCONN-WSABASEERR)
+# define ENOTCONN (WSAENOTCONN-WSABASEERR)
+# define ESHUTDOWN (WSAESHUTDOWN-WSABASEERR)
+# define ETOOMANYREFS (WSAETOOMANYREFS-WSABASEERR)
+# define ETIMEDOUT (WSAETIMEDOUT-WSABASEERR)
+# define ECONNREFUSED (WSAECONNREFUSED-WSABASEERR)
+# define ELOOP (WSAELOOP-WSABASEERR)
+# define ENAMETOOLONG (WSAENAMETOOLONG-WSABASEERR)
+# define EHOSTDOWN (WSAEHOSTDOWN-WSABASEERR)
+# define EHOSTUNREACH (WSAEHOSTUNREACH-WSABASEERR)
+# define ENOTEMPTY (WSAENOTEMPTY-WSABASEERR)
+# define EPROCLIM (WSAEPROCLIM-WSABASEERR)
+# define EUSERS (WSAEUSERS-WSABASEERR)
+# define EDQUOT (WSAEDQUOT-WSABASEERR)
+# define ESTALE (WSAESTALE-WSABASEERR)
+# define EREMOTE (WSAEREMOTE-WSABASEERR)
+
+#endif
diff --git a/external/rapidjson/rapidjson.h b/external/rapidjson/rapidjson.h
new file mode 100644
index 0000000..33bf2a7
--- /dev/null
+++ b/external/rapidjson/rapidjson.h
@@ -0,0 +1,31 @@
+// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
+// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
+#if defined(__SSE4_2__)
+# define RAPIDJSON_SSE42
+#elif defined(__SSE2__)
+# define RAPIDJSON_SSE2
+#endif
+
+#include "rapidjson/allocators.h"
+#include "rapidjson/istreamwrapper.h"
+#include "rapidjson/reader.h"
+#include "rapidjson/document.h"
+#include "rapidjson/memorybuffer.h"
+#include "rapidjson/schema.h"
+#include "rapidjson/encodedstream.h"
+#include "rapidjson/memorystream.h"
+#include "rapidjson/stream.h"
+#include "rapidjson/encodings.h"
+#include "rapidjson/ostreamwrapper.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/pointer.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/prettywriter.h"
+#include "rapidjson/fwd.h"
+#include "rapidjson/rapidjson.h"
+
+#include "rapidjson/error/error.h"
+#include "rapidjson/error/en.h"
+
diff --git a/external/rapidjson/rapidjson/allocators.h b/external/rapidjson/rapidjson/allocators.h
new file mode 100644
index 0000000..98affe0
--- /dev/null
+++ b/external/rapidjson/rapidjson/allocators.h
@@ -0,0 +1,271 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ALLOCATORS_H_
+#define RAPIDJSON_ALLOCATORS_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Allocator
+
+/*! \class rapidjson::Allocator
+ \brief Concept for allocating, resizing and freeing memory block.
+
+ Note that Malloc() and Realloc() are non-static but Free() is static.
+
+ So if an allocator need to support Free(), it needs to put its pointer in
+ the header of memory block.
+
+\code
+concept Allocator {
+ static const bool kNeedFree; //!< Whether this allocator needs to call Free().
+
+ // Allocate a memory block.
+ // \param size of the memory block in bytes.
+ // \returns pointer to the memory block.
+ void* Malloc(size_t size);
+
+ // Resize a memory block.
+ // \param originalPtr The pointer to current memory block. Null pointer is permitted.
+ // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
+ // \param newSize the new size in bytes.
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+ // Free a memory block.
+ // \param pointer to the memory block. Null pointer is permitted.
+ static void Free(void *ptr);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// CrtAllocator
+
+//! C-runtime library allocator.
+/*! This class is just wrapper for standard C library memory routines.
+ \note implements Allocator concept
+*/
+class CrtAllocator {
+public:
+ static const bool kNeedFree = true;
+ void* Malloc(size_t size) {
+ if (size) // behavior of malloc(0) is implementation defined.
+ return std::malloc(size);
+ else
+ return NULL; // standardize to returning NULL.
+ }
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+ (void)originalSize;
+ if (newSize == 0) {
+ std::free(originalPtr);
+ return NULL;
+ }
+ return std::realloc(originalPtr, newSize);
+ }
+ static void Free(void *ptr) { std::free(ptr); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryPoolAllocator
+
+//! Default memory allocator used by the parser and DOM.
+/*! This allocator allocate memory blocks from pre-allocated memory chunks.
+
+ It does not free memory blocks. And Realloc() only allocate new memory.
+
+ The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
+
+ User may also supply a buffer as the first chunk.
+
+ If the user-buffer is full then additional chunks are allocated by BaseAllocator.
+
+ The user-buffer is not deallocated by this allocator.
+
+ \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
+ \note implements Allocator concept
+*/
+template <typename BaseAllocator = CrtAllocator>
+class MemoryPoolAllocator {
+public:
+ static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+
+ //! Constructor with chunkSize.
+ /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ }
+
+ //! Constructor with user-supplied buffer.
+ /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
+
+ The user buffer will not be deallocated when this allocator is destructed.
+
+ \param buffer User supplied buffer.
+ \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
+ \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ RAPIDJSON_ASSERT(buffer != 0);
+ RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
+ chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
+ chunkHead_->capacity = size - sizeof(ChunkHeader);
+ chunkHead_->size = 0;
+ chunkHead_->next = 0;
+ }
+
+ //! Destructor.
+ /*! This deallocates all memory chunks, excluding the user-supplied buffer.
+ */
+ ~MemoryPoolAllocator() {
+ Clear();
+ RAPIDJSON_DELETE(ownBaseAllocator_);
+ }
+
+ //! Deallocates all memory chunks, excluding the user-supplied buffer.
+ void Clear() {
+ while (chunkHead_ && chunkHead_ != userBuffer_) {
+ ChunkHeader* next = chunkHead_->next;
+ baseAllocator_->Free(chunkHead_);
+ chunkHead_ = next;
+ }
+ if (chunkHead_ && chunkHead_ == userBuffer_)
+ chunkHead_->size = 0; // Clear user buffer
+ }
+
+ //! Computes the total capacity of allocated memory chunks.
+ /*! \return total capacity in bytes.
+ */
+ size_t Capacity() const {
+ size_t capacity = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ capacity += c->capacity;
+ return capacity;
+ }
+
+ //! Computes the memory blocks allocated.
+ /*! \return total used bytes.
+ */
+ size_t Size() const {
+ size_t size = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ size += c->size;
+ return size;
+ }
+
+ //! Allocates a memory block. (concept Allocator)
+ void* Malloc(size_t size) {
+ if (!size)
+ return NULL;
+
+ size = RAPIDJSON_ALIGN(size);
+ if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
+ if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
+ return NULL;
+
+ void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
+ chunkHead_->size += size;
+ return buffer;
+ }
+
+ //! Resizes a memory block (concept Allocator)
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+ if (originalPtr == 0)
+ return Malloc(newSize);
+
+ if (newSize == 0)
+ return NULL;
+
+ originalSize = RAPIDJSON_ALIGN(originalSize);
+ newSize = RAPIDJSON_ALIGN(newSize);
+
+ // Do not shrink if new size is smaller than original
+ if (originalSize >= newSize)
+ return originalPtr;
+
+ // Simply expand it if it is the last allocation and there is sufficient space
+ if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
+ size_t increment = static_cast<size_t>(newSize - originalSize);
+ if (chunkHead_->size + increment <= chunkHead_->capacity) {
+ chunkHead_->size += increment;
+ return originalPtr;
+ }
+ }
+
+ // Realloc process: allocate and copy memory, do not free original buffer.
+ if (void* newBuffer = Malloc(newSize)) {
+ if (originalSize)
+ std::memcpy(newBuffer, originalPtr, originalSize);
+ return newBuffer;
+ }
+ else
+ return NULL;
+ }
+
+ //! Frees a memory block (concept Allocator)
+ static void Free(void *ptr) { (void)ptr; } // Do nothing
+
+private:
+ //! Copy constructor is not permitted.
+ MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
+ //! Copy assignment operator is not permitted.
+ MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
+
+ //! Creates a new chunk.
+ /*! \param capacity Capacity of the chunk in bytes.
+ \return true if success.
+ */
+ bool AddChunk(size_t capacity) {
+ if (!baseAllocator_)
+ ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
+ if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
+ chunk->capacity = capacity;
+ chunk->size = 0;
+ chunk->next = chunkHead_;
+ chunkHead_ = chunk;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
+
+ //! Chunk header for perpending to each chunk.
+ /*! Chunks are stored as a singly linked list.
+ */
+ struct ChunkHeader {
+ size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
+ size_t size; //!< Current size of allocated memory in bytes.
+ ChunkHeader *next; //!< Next chunk in the linked list.
+ };
+
+ ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+ size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
+ void *userBuffer_; //!< User supplied buffer.
+ BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
+ BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ENCODINGS_H_
diff --git a/external/rapidjson/rapidjson/document.h b/external/rapidjson/rapidjson/document.h
new file mode 100644
index 0000000..703c061
--- /dev/null
+++ b/external/rapidjson/rapidjson/document.h
@@ -0,0 +1,2592 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_DOCUMENT_H_
+#define RAPIDJSON_DOCUMENT_H_
+
+/*! \file document.h */
+
+#include "reader.h"
+#include "internal/meta.h"
+#include "internal/strfunc.h"
+#include "memorystream.h"
+#include "encodedstream.h"
+#include <new> // placement new
+#include <limits>
+
+RAPIDJSON_DIAG_PUSH
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
+#ifdef _MINWINDEF_ // see: http://stackoverflow.com/questions/22744262/cant-call-stdmax-because-minwindef-h-defines-max
+#ifndef NOMINMAX
+#pragma push_macro("min")
+#pragma push_macro("max")
+#undef min
+#undef max
+#endif
+#endif
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_OFF(effc++)
+#if __GNUC__ >= 6
+RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions
+#endif
+#endif // __GNUC__
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+#include <iterator> // std::iterator, std::random_access_iterator_tag
+#endif
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+// Forward declaration.
+template <typename Encoding, typename Allocator>
+class GenericValue;
+
+template <typename Encoding, typename Allocator, typename StackAllocator>
+class GenericDocument;
+
+//! Name-value pair in a JSON object value.
+/*!
+ This class was internal to GenericValue. It used to be a inner struct.
+ But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
+ https://code.google.com/p/rapidjson/issues/detail?id=64
+*/
+template <typename Encoding, typename Allocator>
+struct GenericMember {
+ GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
+ GenericValue<Encoding, Allocator> value; //!< value of member.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericMemberIterator
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+
+//! (Constant) member iterator for a JSON object value
+/*!
+ \tparam Const Is this a constant iterator?
+ \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
+ \tparam Allocator Allocator type for allocating memory of object, array and string.
+
+ This class implements a Random Access Iterator for GenericMember elements
+ of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].
+
+ \note This iterator implementation is mainly intended to avoid implicit
+ conversions from iterator values to \c NULL,
+ e.g. from GenericValue::FindMember.
+
+ \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
+ pointer-based implementation, if your platform doesn't provide
+ the C++ <iterator> header.
+
+ \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
+ */
+template <bool Const, typename Encoding, typename Allocator>
+class GenericMemberIterator
+ : public std::iterator<std::random_access_iterator_tag
+ , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
+
+ friend class GenericValue<Encoding,Allocator>;
+ template <bool, typename, typename> friend class GenericMemberIterator;
+
+ typedef GenericMember<Encoding,Allocator> PlainType;
+ typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
+ typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
+
+public:
+ //! Iterator type itself
+ typedef GenericMemberIterator Iterator;
+ //! Constant iterator type
+ typedef GenericMemberIterator<true,Encoding,Allocator> ConstIterator;
+ //! Non-constant iterator type
+ typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;
+
+ //! Pointer to (const) GenericMember
+ typedef typename BaseType::pointer Pointer;
+ //! Reference to (const) GenericMember
+ typedef typename BaseType::reference Reference;
+ //! Signed integer type (e.g. \c ptrdiff_t)
+ typedef typename BaseType::difference_type DifferenceType;
+
+ //! Default constructor (singular value)
+ /*! Creates an iterator pointing to no element.
+ \note All operations, except for comparisons, are undefined on such values.
+ */
+ GenericMemberIterator() : ptr_() {}
+
+ //! Iterator conversions to more const
+ /*!
+ \param it (Non-const) iterator to copy from
+
+ Allows the creation of an iterator from another GenericMemberIterator
+ that is "less const". Especially, creating a non-constant iterator
+ from a constant iterator are disabled:
+ \li const -> non-const (not ok)
+ \li const -> const (ok)
+ \li non-const -> const (ok)
+ \li non-const -> non-const (ok)
+
+ \note If the \c Const template parameter is already \c false, this
+ constructor effectively defines a regular copy-constructor.
+ Otherwise, the copy constructor is implicitly defined.
+ */
+ GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
+ Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; }
+
+ //! @name stepping
+ //@{
+ Iterator& operator++(){ ++ptr_; return *this; }
+ Iterator& operator--(){ --ptr_; return *this; }
+ Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; }
+ Iterator operator--(int){ Iterator old(*this); --ptr_; return old; }
+ //@}
+
+ //! @name increment/decrement
+ //@{
+ Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }
+ Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }
+
+ Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }
+ Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }
+ //@}
+
+ //! @name relations
+ //@{
+ bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
+ bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
+ bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
+ bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
+ bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }
+ bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }
+ //@}
+
+ //! @name dereference
+ //@{
+ Reference operator*() const { return *ptr_; }
+ Pointer operator->() const { return ptr_; }
+ Reference operator[](DifferenceType n) const { return ptr_[n]; }
+ //@}
+
+ //! Distance
+ DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }
+
+private:
+ //! Internal constructor from plain pointer
+ explicit GenericMemberIterator(Pointer p) : ptr_(p) {}
+
+ Pointer ptr_; //!< raw pointer
+};
+
+#else // RAPIDJSON_NOMEMBERITERATORCLASS
+
+// class-based member iterator implementation disabled, use plain pointers
+
+template <bool Const, typename Encoding, typename Allocator>
+struct GenericMemberIterator;
+
+//! non-const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<false,Encoding,Allocator> {
+ //! use plain pointer as iterator type
+ typedef GenericMember<Encoding,Allocator>* Iterator;
+};
+//! const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<true,Encoding,Allocator> {
+ //! use plain const pointer as iterator type
+ typedef const GenericMember<Encoding,Allocator>* Iterator;
+};
+
+#endif // RAPIDJSON_NOMEMBERITERATORCLASS
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericStringRef
+
+//! Reference to a constant string (not taking a copy)
+/*!
+ \tparam CharType character type of the string
+
+ This helper class is used to automatically infer constant string
+ references for string literals, especially from \c const \b (!)
+ character arrays.
+
+ The main use is for creating JSON string values without copying the
+ source string via an \ref Allocator. This requires that the referenced
+ string pointers have a sufficient lifetime, which exceeds the lifetime
+ of the associated GenericValue.
+
+ \b Example
+ \code
+ Value v("foo"); // ok, no need to copy & calculate length
+ const char foo[] = "foo";
+ v.SetString(foo); // ok
+
+ const char* bar = foo;
+ // Value x(bar); // not ok, can't rely on bar's lifetime
+ Value x(StringRef(bar)); // lifetime explicitly guaranteed by user
+ Value y(StringRef(bar, 3)); // ok, explicitly pass length
+ \endcode
+
+ \see StringRef, GenericValue::SetString
+*/
+template<typename CharType>
+struct GenericStringRef {
+ typedef CharType Ch; //!< character type of the string
+
+ //! Create string reference from \c const character array
+#ifndef __clang__ // -Wdocumentation
+ /*!
+ This constructor implicitly creates a constant string reference from
+ a \c const character array. It has better performance than
+ \ref StringRef(const CharType*) by inferring the string \ref length
+ from the array length, and also supports strings containing null
+ characters.
+
+ \tparam N length of the string, automatically inferred
+
+ \param str Constant character array, lifetime assumed to be longer
+ than the use of the string in e.g. a GenericValue
+
+ \post \ref s == str
+
+ \note Constant complexity.
+ \note There is a hidden, private overload to disallow references to
+ non-const character arrays to be created via this constructor.
+ By this, e.g. function-scope arrays used to be filled via
+ \c snprintf are excluded from consideration.
+ In such cases, the referenced string should be \b copied to the
+ GenericValue instead.
+ */
+#endif
+ template<SizeType N>
+ GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
+ : s(str), length(N-1) {}
+
+ //! Explicitly create string reference from \c const character pointer
+#ifndef __clang__ // -Wdocumentation
+ /*!
+ This constructor can be used to \b explicitly create a reference to
+ a constant string pointer.
+
+ \see StringRef(const CharType*)
+
+ \param str Constant character pointer, lifetime assumed to be longer
+ than the use of the string in e.g. a GenericValue
+
+ \post \ref s == str
+
+ \note There is a hidden, private overload to disallow references to
+ non-const character arrays to be created via this constructor.
+ By this, e.g. function-scope arrays used to be filled via
+ \c snprintf are excluded from consideration.
+ In such cases, the referenced string should be \b copied to the
+ GenericValue instead.
+ */
+#endif
+ explicit GenericStringRef(const CharType* str)
+ : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); }
+
+ //! Create constant string reference from pointer and length
+#ifndef __clang__ // -Wdocumentation
+ /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \param len length of the string, excluding the trailing NULL terminator
+
+ \post \ref s == str && \ref length == len
+ \note Constant complexity.
+ */
+#endif
+ GenericStringRef(const CharType* str, SizeType len)
+ : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); }
+
+ GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
+
+ //! implicit conversion to plain CharType pointer
+ operator const Ch *() const { return s; }
+
+ const Ch* const s; //!< plain CharType pointer
+ const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
+
+private:
+ //! Disallow construction from non-const array
+ template<SizeType N>
+ GenericStringRef(CharType (&str)[N]) /* = delete */;
+ //! Copy assignment operator not permitted - immutable type
+ GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */;
+};
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal". This function
+ can be used to avoid copying a character string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+ \tparam CharType Character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+
+ \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str) {
+ return GenericStringRef<CharType>(str, internal::StrLen(str));
+}
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal". This function
+ can be used to avoid copying a character string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+
+ This version has better performance with supplied length, and also
+ supports string containing null characters.
+
+ \tparam CharType character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \param length The length of source string.
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {
+ return GenericStringRef<CharType>(str, SizeType(length));
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+//! Mark a string object as constant string
+/*! Mark a string object (e.g. \c std::string) as a "string literal".
+ This function can be used to avoid copying a string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+
+ \tparam CharType character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+ \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) {
+ return GenericStringRef<CharType>(str.data(), SizeType(str.size()));
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue type traits
+namespace internal {
+
+template <typename T, typename Encoding = void, typename Allocator = void>
+struct IsGenericValueImpl : FalseType {};
+
+// select candidates according to nested encoding and allocator types
+template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>
+ : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};
+
+// helper to match arbitrary GenericValue instantiations, including derived classes
+template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// TypeHelper
+
+namespace internal {
+
+template <typename ValueType, typename T>
+struct TypeHelper {};
+
+template<typename ValueType>
+struct TypeHelper<ValueType, bool> {
+ static bool Is(const ValueType& v) { return v.IsBool(); }
+ static bool Get(const ValueType& v) { return v.GetBool(); }
+ static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); }
+ static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); }
+};
+
+template<typename ValueType>
+struct TypeHelper<ValueType, int> {
+ static bool Is(const ValueType& v) { return v.IsInt(); }
+ static int Get(const ValueType& v) { return v.GetInt(); }
+ static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); }
+ static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
+};
+
+template<typename ValueType>
+struct TypeHelper<ValueType, unsigned> {
+ static bool Is(const ValueType& v) { return v.IsUint(); }
+ static unsigned Get(const ValueType& v) { return v.GetUint(); }
+ static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); }
+ static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
+};
+
+template<typename ValueType>
+struct TypeHelper<ValueType, int64_t> {
+ static bool Is(const ValueType& v) { return v.IsInt64(); }
+ static int64_t Get(const ValueType& v) { return v.GetInt64(); }
+ static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); }
+ static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); }
+};
+
+template<typename ValueType>
+struct TypeHelper<ValueType, uint64_t> {
+ static bool Is(const ValueType& v) { return v.IsUint64(); }
+ static uint64_t Get(const ValueType& v) { return v.GetUint64(); }
+ static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); }
+ static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); }
+};
+
+template<typename ValueType>
+struct TypeHelper<ValueType, double> {
+ static bool Is(const ValueType& v) { return v.IsDouble(); }
+ static double Get(const ValueType& v) { return v.GetDouble(); }
+ static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); }
+ static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); }
+};
+
+template<typename ValueType>
+struct TypeHelper<ValueType, float> {
+ static bool Is(const ValueType& v) { return v.IsFloat(); }
+ static float Get(const ValueType& v) { return v.GetFloat(); }
+ static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); }
+ static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); }
+};
+
+template<typename ValueType>
+struct TypeHelper<ValueType, const typename ValueType::Ch*> {
+ typedef const typename ValueType::Ch* StringType;
+ static bool Is(const ValueType& v) { return v.IsString(); }
+ static StringType Get(const ValueType& v) { return v.GetString(); }
+ static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); }
+ static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
+};
+
+#if RAPIDJSON_HAS_STDSTRING
+template<typename ValueType>
+struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > {
+ typedef std::basic_string<typename ValueType::Ch> StringType;
+ static bool Is(const ValueType& v) { return v.IsString(); }
+ static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); }
+ static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
+};
+#endif
+
+template<typename ValueType>
+struct TypeHelper<ValueType, typename ValueType::Array> {
+ typedef typename ValueType::Array ArrayType;
+ static bool Is(const ValueType& v) { return v.IsArray(); }
+ static ArrayType Get(ValueType& v) { return v.GetArray(); }
+ static ValueType& Set(ValueType& v, ArrayType data) { return v = data; }
+ static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; }
+};
+
+template<typename ValueType>
+struct TypeHelper<ValueType, typename ValueType::ConstArray> {
+ typedef typename ValueType::ConstArray ArrayType;
+ static bool Is(const ValueType& v) { return v.IsArray(); }
+ static ArrayType Get(const ValueType& v) { return v.GetArray(); }
+};
+
+template<typename ValueType>
+struct TypeHelper<ValueType, typename ValueType::Object> {
+ typedef typename ValueType::Object ObjectType;
+ static bool Is(const ValueType& v) { return v.IsObject(); }
+ static ObjectType Get(ValueType& v) { return v.GetObject(); }
+ static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }
+ static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; }
+};
+
+template<typename ValueType>
+struct TypeHelper<ValueType, typename ValueType::ConstObject> {
+ typedef typename ValueType::ConstObject ObjectType;
+ static bool Is(const ValueType& v) { return v.IsObject(); }
+ static ObjectType Get(const ValueType& v) { return v.GetObject(); }
+};
+
+} // namespace internal
+
+// Forward declarations
+template <bool, typename> class GenericArray;
+template <bool, typename> class GenericObject;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue
+
+//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
+/*!
+ A JSON value can be one of 7 types. This class is a variant type supporting
+ these types.
+
+ Use the Value if UTF8 and default allocator
+
+ \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
+ \tparam Allocator Allocator type for allocating memory of object, array and string.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericValue {
+public:
+ //! Name-value pair in an object.
+ typedef GenericMember<Encoding, Allocator> Member;
+ typedef Encoding EncodingType; //!< Encoding type from template parameter.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericStringRef<Ch> StringRefType; //!< Reference to a constant string
+ typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object.
+ typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object.
+ typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
+ typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
+ typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself.
+ typedef GenericArray<false, ValueType> Array;
+ typedef GenericArray<true, ValueType> ConstArray;
+ typedef GenericObject<false, ValueType> Object;
+ typedef GenericObject<true, ValueType> ConstObject;
+
+ //!@name Constructors and destructor.
+ //@{
+
+ //! Default constructor creates a null value.
+ GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) {
+ rhs.data_.f.flags = kNullFlag; // give up contents
+ }
+#endif
+
+private:
+ //! Copy constructor is not permitted.
+ GenericValue(const GenericValue& rhs);
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Moving from a GenericDocument is not permitted.
+ template <typename StackAllocator>
+ GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
+
+ //! Move assignment from a GenericDocument is not permitted.
+ template <typename StackAllocator>
+ GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
+#endif
+
+public:
+
+ //! Constructor with JSON value type.
+ /*! This creates a Value of specified type with default content.
+ \param type Type of the value.
+ \note Default content for number is zero.
+ */
+ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
+ static const uint16_t defaultFlags[7] = {
+ kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
+ kNumberAnyFlag
+ };
+ RAPIDJSON_ASSERT(type <= kNumberType);
+ data_.f.flags = defaultFlags[type];
+
+ // Use ShortString to store empty string.
+ if (type == kStringType)
+ data_.ss.SetLength(0);
+ }
+
+ //! Explicit copy constructor (with allocator)
+ /*! Creates a copy of a Value by using the given Allocator
+ \tparam SourceAllocator allocator of \c rhs
+ \param rhs Value to copy from (read-only)
+ \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
+ \see CopyFrom()
+ */
+ template< typename SourceAllocator >
+ GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
+
+ //! Constructor for boolean value.
+ /*! \param b Boolean value
+ \note This constructor is limited to \em real boolean values and rejects
+ implicitly converted types like arbitrary pointers. Use an explicit cast
+ to \c bool, if you want to construct a boolean JSON value in such cases.
+ */
+#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
+ template <typename T>
+ explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<bool, T>))) RAPIDJSON_NOEXCEPT // See #472
+#else
+ explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
+#endif
+ : data_() {
+ // safe-guard against failing SFINAE
+ RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
+ data_.f.flags = b ? kTrueFlag : kFalseFlag;
+ }
+
+ //! Constructor for int value.
+ explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.i64 = i;
+ data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag;
+ }
+
+ //! Constructor for unsigned value.
+ explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.u64 = u;
+ data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag);
+ }
+
+ //! Constructor for int64_t value.
+ explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.i64 = i64;
+ data_.f.flags = kNumberInt64Flag;
+ if (i64 >= 0) {
+ data_.f.flags |= kNumberUint64Flag;
+ if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+ data_.f.flags |= kUintFlag;
+ if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ data_.f.flags |= kIntFlag;
+ }
+ else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ data_.f.flags |= kIntFlag;
+ }
+
+ //! Constructor for uint64_t value.
+ explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.u64 = u64;
+ data_.f.flags = kNumberUint64Flag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
+ data_.f.flags |= kInt64Flag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+ data_.f.flags |= kUintFlag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ data_.f.flags |= kIntFlag;
+ }
+
+ //! Constructor for double value.
+ explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }
+
+ //! Constructor for float value.
+ explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast<double>(f); data_.f.flags = kNumberDoubleFlag; }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Constructor for copy-string from a string object (i.e. do make a copy of string)
+ /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
+#endif
+
+ //! Constructor for Array.
+ /*!
+ \param a An array obtained by \c GetArray().
+ \note \c Array is always pass-by-value.
+ \note the source array is moved into this value and the sourec array becomes empty.
+ */
+ GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) {
+ a.value_.data_ = Data();
+ a.value_.data_.f.flags = kArrayFlag;
+ }
+
+ //! Constructor for Object.
+ /*!
+ \param o An object obtained by \c GetObject().
+ \note \c Object is always pass-by-value.
+ \note the source object is moved into this value and the sourec object becomes empty.
+ */
+ GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) {
+ o.value_.data_ = Data();
+ o.value_.data_.f.flags = kObjectFlag;
+ }
+
+ //! Destructor.
+ /*! Need to destruct elements of array, members of object, or copy-string.
+ */
+ ~GenericValue() {
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ switch(data_.f.flags) {
+ case kArrayFlag:
+ {
+ GenericValue* e = GetElementsPointer();
+ for (GenericValue* v = e; v != e + data_.a.size; ++v)
+ v->~GenericValue();
+ Allocator::Free(e);
+ }
+ break;
+
+ case kObjectFlag:
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ Allocator::Free(GetMembersPointer());
+ break;
+
+ case kCopyStringFlag:
+ Allocator::Free(const_cast<Ch*>(GetStringPointer()));
+ break;
+
+ default:
+ break; // Do nothing for other types.
+ }
+ }
+ }
+
+ //@}
+
+ //!@name Assignment operators
+ //@{
+
+ //! Assignment with move semantics.
+ /*! \param rhs Source of the assignment. It will become a null value after assignment.
+ */
+ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_ASSERT(this != &rhs);
+ this->~GenericValue();
+ RawAssign(rhs);
+ return *this;
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move assignment in C++11
+ GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {
+ return *this = rhs.Move();
+ }
+#endif
+
+ //! Assignment of constant string reference (no copy)
+ /*! \param str Constant string reference to be assigned
+ \note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
+ \see GenericStringRef, operator=(T)
+ */
+ GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {
+ GenericValue s(str);
+ return *this = s;
+ }
+
+ //! Assignment with primitive types.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param value The value to be assigned.
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref SetString(const Ch*, Allocator&) (for copying) or
+ \ref StringRef() (to explicitly mark the pointer as constant) instead.
+ All other pointer types would implicitly convert to \c bool,
+ use \ref SetBool() instead.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
+ operator=(T value) {
+ GenericValue v(value);
+ return *this = v;
+ }
+
+ //! Deep-copy assignment from Value
+ /*! Assigns a \b copy of the Value to the current Value object
+ \tparam SourceAllocator Allocator type of \c rhs
+ \param rhs Value to copy from (read-only)
+ \param allocator Allocator to use for copying
+ */
+ template <typename SourceAllocator>
+ GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
+ RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));
+ this->~GenericValue();
+ new (this) GenericValue(rhs, allocator);
+ return *this;
+ }
+
+ //! Exchange the contents of this value with those of other.
+ /*!
+ \param other Another value.
+ \note Constant complexity.
+ */
+ GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
+ GenericValue temp;
+ temp.RawAssign(*this);
+ RawAssign(other);
+ other.RawAssign(temp);
+ return *this;
+ }
+
+ //! free-standing swap function helper
+ /*!
+ Helper function to enable support for common swap implementation pattern based on \c std::swap:
+ \code
+ void swap(MyClass& a, MyClass& b) {
+ using std::swap;
+ swap(a.value, b.value);
+ // ...
+ }
+ \endcode
+ \see Swap()
+ */
+ friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
+
+ //! Prepare Value for move semantics
+ /*! \return *this */
+ GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
+ //@}
+
+ //!@name Equal-to and not-equal-to operators
+ //@{
+ //! Equal-to operator
+ /*!
+ \note If an object contains duplicated named member, comparing equality with any object is always \c false.
+ \note Linear time complexity (number of all values in the subtree and total lengths of all strings).
+ */
+ template <typename SourceAllocator>
+ bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+ typedef GenericValue<Encoding, SourceAllocator> RhsType;
+ if (GetType() != rhs.GetType())
+ return false;
+
+ switch (GetType()) {
+ case kObjectType: // Warning: O(n^2) inner-loop
+ if (data_.o.size != rhs.data_.o.size)
+ return false;
+ for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
+ typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
+ if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
+ return false;
+ }
+ return true;
+
+ case kArrayType:
+ if (data_.a.size != rhs.data_.a.size)
+ return false;
+ for (SizeType i = 0; i < data_.a.size; i++)
+ if ((*this)[i] != rhs[i])
+ return false;
+ return true;
+
+ case kStringType:
+ return StringEqual(rhs);
+
+ case kNumberType:
+ if (IsDouble() || rhs.IsDouble()) {
+ double a = GetDouble(); // May convert from integer to double.
+ double b = rhs.GetDouble(); // Ditto
+ return a >= b && a <= b; // Prevent -Wfloat-equal
+ }
+ else
+ return data_.n.u64 == rhs.data_.n.u64;
+
+ default:
+ return true;
+ }
+ }
+
+ //! Equal-to operator with const C-string pointer
+ bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Equal-to operator with string object
+ /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); }
+#endif
+
+ //! Equal-to operator with primitive types
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
+ */
+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
+
+ //! Not-equal-to operator
+ /*! \return !(*this == rhs)
+ */
+ template <typename SourceAllocator>
+ bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }
+
+ //! Not-equal-to operator with const C-string pointer
+ bool operator!=(const Ch* rhs) const { return !(*this == rhs); }
+
+ //! Not-equal-to operator with arbitrary types
+ /*! \return !(*this == rhs)
+ */
+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
+
+ //! Equal-to operator with arbitrary types (symmetric version)
+ /*! \return (rhs == lhs)
+ */
+ template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
+
+ //! Not-Equal-to operator with arbitrary types (symmetric version)
+ /*! \return !(rhs == lhs)
+ */
+ template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
+ //@}
+
+ //!@name Type
+ //@{
+
+ Type GetType() const { return static_cast<Type>(data_.f.flags & kTypeMask); }
+ bool IsNull() const { return data_.f.flags == kNullFlag; }
+ bool IsFalse() const { return data_.f.flags == kFalseFlag; }
+ bool IsTrue() const { return data_.f.flags == kTrueFlag; }
+ bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; }
+ bool IsObject() const { return data_.f.flags == kObjectFlag; }
+ bool IsArray() const { return data_.f.flags == kArrayFlag; }
+ bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }
+ bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; }
+ bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; }
+ bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; }
+ bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }
+ bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; }
+ bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }
+
+ // Checks whether a number can be losslessly converted to a double.
+ bool IsLosslessDouble() const {
+ if (!IsNumber()) return false;
+ if (IsUint64()) {
+ uint64_t u = GetUint64();
+ volatile double d = static_cast<double>(u);
+ return (d >= 0.0)
+ && (d < static_cast<double>(std::numeric_limits<uint64_t>::max()))
+ && (u == static_cast<uint64_t>(d));
+ }
+ if (IsInt64()) {
+ int64_t i = GetInt64();
+ volatile double d = static_cast<double>(i);
+ return (d >= static_cast<double>(std::numeric_limits<int64_t>::min()))
+ && (d < static_cast<double>(std::numeric_limits<int64_t>::max()))
+ && (i == static_cast<int64_t>(d));
+ }
+ return true; // double, int, uint are always lossless
+ }
+
+ // Checks whether a number is a float (possible lossy).
+ bool IsFloat() const {
+ if ((data_.f.flags & kDoubleFlag) == 0)
+ return false;
+ double d = GetDouble();
+ return d >= -3.4028234e38 && d <= 3.4028234e38;
+ }
+ // Checks whether a number can be losslessly converted to a float.
+ bool IsLosslessFloat() const {
+ if (!IsNumber()) return false;
+ double a = GetDouble();
+ if (a < static_cast<double>(-std::numeric_limits<float>::max())
+ || a > static_cast<double>(std::numeric_limits<float>::max()))
+ return false;
+ double b = static_cast<double>(static_cast<float>(a));
+ return a >= b && a <= b; // Prevent -Wfloat-equal
+ }
+
+ //@}
+
+ //!@name Null
+ //@{
+
+ GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
+
+ //@}
+
+ //!@name Bool
+ //@{
+
+ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; }
+ //!< Set boolean value
+ /*! \post IsBool() == true */
+ GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
+
+ //@}
+
+ //!@name Object
+ //@{
+
+ //! Set this value as an empty object.
+ /*! \post IsObject() == true */
+ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
+
+ //! Get the number of members in the object.
+ SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
+
+ //! Check whether the object is empty.
+ bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
+
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType))
+ \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.
+ Since 0.2, if the name is not correct, it will assert.
+ If user is unsure whether a member exists, user should use HasMember() first.
+ A better approach is to use FindMember().
+ \note Linear time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {
+ GenericValue n(StringRef(name));
+ return (*this)[n];
+ }
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam SourceAllocator Allocator of the \c name value
+
+ \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen().
+ And it can also handle strings with embedded null characters.
+
+ \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator member = FindMember(name);
+ if (member != MemberEnd())
+ return member->value;
+ else {
+ RAPIDJSON_ASSERT(false); // see above note
+
+ // This will generate -Wexit-time-destructors in clang
+ // static GenericValue NullValue;
+ // return NullValue;
+
+ // Use static buffer and placement-new to prevent destruction
+ static char buffer[sizeof(GenericValue)];
+ return *new (buffer) GenericValue();
+ }
+ }
+ template <typename SourceAllocator>
+ const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Get a value from an object associated with name (string object).
+ GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }
+ const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }
+#endif
+
+ //! Const member iterator
+ /*! \pre IsObject() == true */
+ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); }
+ //! Const \em past-the-end member iterator
+ /*! \pre IsObject() == true */
+ ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); }
+ //! Member iterator
+ /*! \pre IsObject() == true */
+ MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); }
+ //! \em Past-the-end member iterator
+ /*! \pre IsObject() == true */
+ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
+
+ //! Check whether a member exists in the object.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Check whether a member exists in the object with string object.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }
+#endif
+
+ //! Check whether a member exists in the object with GenericValue name.
+ /*!
+ This version is faster because it does not need a StrLen(). It can also handle string with null character.
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }
+
+ //! Find member by name.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+
+ \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+ the requested member doesn't exist. For consistency with e.g.
+ \c std::map, this has been changed to MemberEnd() now.
+ \note Linear time complexity.
+ */
+ MemberIterator FindMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return FindMember(n);
+ }
+
+ ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+ //! Find member by name.
+ /*!
+ This version is faster because it does not need a StrLen(). It can also handle string with null character.
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+
+ \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+ the requested member doesn't exist. For consistency with e.g.
+ \c std::map, this has been changed to MemberEnd() now.
+ \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+ MemberIterator member = MemberBegin();
+ for ( ; member != MemberEnd(); ++member)
+ if (name.StringEqual(member->name))
+ break;
+ return member;
+ }
+ template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Find member by string object name.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+ */
+ MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(GenericValue(StringRef(name))); }
+ ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(GenericValue(StringRef(name))); }
+#endif
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note The ownership of \c name and \c value will be transferred to this object on success.
+ \pre IsObject() && name.IsString()
+ \post name.IsNull() && value.IsNull()
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+
+ ObjectData& o = data_.o;
+ if (o.size >= o.capacity) {
+ if (o.capacity == 0) {
+ o.capacity = kDefaultObjectCapacity;
+ SetMembersPointer(reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member))));
+ }
+ else {
+ SizeType oldCapacity = o.capacity;
+ o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
+ SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member))));
+ }
+ }
+ Member* members = GetMembersPointer();
+ members[o.size].name.RawAssign(name);
+ members[o.size].value.RawAssign(value);
+ o.size++;
+ return *this;
+ }
+
+ //! Add a constant string value as member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Add a string object as member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {
+ GenericValue v(value, allocator);
+ return AddMember(name, v, allocator);
+ }
+#endif
+
+ //! Add any primitive value as member (name-value pair) to the object.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param name A string value as name of member.
+ \param value Value of primitive type \c T as value of member
+ \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+ AddMember(StringRefType, StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized Constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+ AddMember(GenericValue& name, T value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A constant string reference as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note The ownership of \c value will be transferred to this object on success.
+ \pre IsObject()
+ \post value.IsNull()
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+
+ //! Add a constant string value as member (name-value pair) to the object.
+ /*! \param name A constant string reference as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+ //! Add any primitive value as member (name-value pair) to the object.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param name A constant string reference as name of member.
+ \param value Value of primitive type \c T as value of member
+ \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+ AddMember(StringRefType, StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized Constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+ AddMember(StringRefType name, T value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+
+ //! Remove all members in the object.
+ /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged.
+ \note Linear time complexity.
+ */
+ void RemoveAllMembers() {
+ RAPIDJSON_ASSERT(IsObject());
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ data_.o.size = 0;
+ }
+
+ //! Remove a member in object by its name.
+ /*! \param name Name of member to be removed.
+ \return Whether the member existed.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
+ \note Linear time complexity.
+ */
+ bool RemoveMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return RemoveMember(n);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }
+#endif
+
+ template <typename SourceAllocator>
+ bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator m = FindMember(name);
+ if (m != MemberEnd()) {
+ RemoveMember(m);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ //! Remove a member in object by iterator.
+ /*! \param m member iterator (obtained by FindMember() or MemberBegin()).
+ \return the new iterator after removal.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
+ \note Constant time complexity.
+ */
+ MemberIterator RemoveMember(MemberIterator m) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(GetMembersPointer() != 0);
+ RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
+
+ MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
+ if (data_.o.size > 1 && m != last)
+ *m = *last; // Move the last one to this place
+ else
+ m->~Member(); // Only one left, just destroy
+ --data_.o.size;
+ return m;
+ }
+
+ //! Remove a member from an object by iterator.
+ /*! \param pos iterator to the member to remove
+ \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd()
+ \return Iterator following the removed element.
+ If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned.
+ \note This function preserves the relative order of the remaining object
+ members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator).
+ \note Linear time complexity.
+ */
+ MemberIterator EraseMember(ConstMemberIterator pos) {
+ return EraseMember(pos, pos +1);
+ }
+
+ //! Remove members in the range [first, last) from an object.
+ /*! \param first iterator to the first member to remove
+ \param last iterator following the last member to remove
+ \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd()
+ \return Iterator following the last removed element.
+ \note This function preserves the relative order of the remaining object
+ members.
+ \note Linear time complexity.
+ */
+ MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(GetMembersPointer() != 0);
+ RAPIDJSON_ASSERT(first >= MemberBegin());
+ RAPIDJSON_ASSERT(first <= last);
+ RAPIDJSON_ASSERT(last <= MemberEnd());
+
+ MemberIterator pos = MemberBegin() + (first - MemberBegin());
+ for (MemberIterator itr = pos; itr != last; ++itr)
+ itr->~Member();
+ std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
+ data_.o.size -= static_cast<SizeType>(last - first);
+ return pos;
+ }
+
+ //! Erase a member in object by its name.
+ /*! \param name Name of member to be removed.
+ \return Whether the member existed.
+ \note Linear time complexity.
+ */
+ bool EraseMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return EraseMember(n);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }
+#endif
+
+ template <typename SourceAllocator>
+ bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator m = FindMember(name);
+ if (m != MemberEnd()) {
+ EraseMember(m);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
+ ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
+
+ //@}
+
+ //!@name Array
+ //@{
+
+ //! Set this value as an empty array.
+ /*! \post IsArray == true */
+ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
+
+ //! Get the number of elements in array.
+ SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
+
+ //! Get the capacity of array.
+ SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
+
+ //! Check whether the array is empty.
+ bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
+
+ //! Remove all elements in the array.
+ /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
+ \note Linear time complexity.
+ */
+ void Clear() {
+ RAPIDJSON_ASSERT(IsArray());
+ GenericValue* e = GetElementsPointer();
+ for (GenericValue* v = e; v != e + data_.a.size; ++v)
+ v->~GenericValue();
+ data_.a.size = 0;
+ }
+
+ //! Get an element from array by index.
+ /*! \pre IsArray() == true
+ \param index Zero-based index of element.
+ \see operator[](T*)
+ */
+ GenericValue& operator[](SizeType index) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(index < data_.a.size);
+ return GetElementsPointer()[index];
+ }
+ const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
+
+ //! Element iterator
+ /*! \pre IsArray() == true */
+ ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); }
+ //! \em Past-the-end element iterator
+ /*! \pre IsArray() == true */
+ ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; }
+ //! Constant element iterator
+ /*! \pre IsArray() == true */
+ ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
+ //! Constant \em past-the-end element iterator
+ /*! \pre IsArray() == true */
+ ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
+
+ //! Request the array to have enough capacity to store elements.
+ /*! \param newCapacity The capacity that the array at least need to have.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note Linear time complexity.
+ */
+ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (newCapacity > data_.a.capacity) {
+ SetElementsPointer(reinterpret_cast<GenericValue*>(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue))));
+ data_.a.capacity = newCapacity;
+ }
+ return *this;
+ }
+
+ //! Append a GenericValue at the end of the array.
+ /*! \param value Value to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \post value.IsNull() == true
+ \return The value itself for fluent API.
+ \note The ownership of \c value will be transferred to this array on success.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+ \note Amortized constant time complexity.
+ */
+ GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (data_.a.size >= data_.a.capacity)
+ Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
+ GetElementsPointer()[data_.a.size++].RawAssign(value);
+ return *this;
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {
+ return PushBack(value, allocator);
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+ //! Append a constant string reference at the end of the array.
+ /*! \param value Constant string reference to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \return The value itself for fluent API.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+ \note Amortized constant time complexity.
+ \see GenericStringRef
+ */
+ GenericValue& PushBack(StringRefType value, Allocator& allocator) {
+ return (*this).template PushBack<StringRefType>(value, allocator);
+ }
+
+ //! Append a primitive value at the end of the array.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param value Value of primitive type T to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \return The value itself for fluent API.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref PushBack(GenericValue&, Allocator&) or \ref
+ PushBack(StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+ PushBack(T value, Allocator& allocator) {
+ GenericValue v(value);
+ return PushBack(v, allocator);
+ }
+
+ //! Remove the last element in the array.
+ /*!
+ \note Constant time complexity.
+ */
+ GenericValue& PopBack() {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(!Empty());
+ GetElementsPointer()[--data_.a.size].~GenericValue();
+ return *this;
+ }
+
+ //! Remove an element of array by iterator.
+ /*!
+ \param pos iterator to the element to remove
+ \pre IsArray() == true && \ref Begin() <= \c pos < \ref End()
+ \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.
+ \note Linear time complexity.
+ */
+ ValueIterator Erase(ConstValueIterator pos) {
+ return Erase(pos, pos + 1);
+ }
+
+ //! Remove elements in the range [first, last) of the array.
+ /*!
+ \param first iterator to the first element to remove
+ \param last iterator following the last element to remove
+ \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End()
+ \return Iterator following the last removed element.
+ \note Linear time complexity.
+ */
+ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(data_.a.size > 0);
+ RAPIDJSON_ASSERT(GetElementsPointer() != 0);
+ RAPIDJSON_ASSERT(first >= Begin());
+ RAPIDJSON_ASSERT(first <= last);
+ RAPIDJSON_ASSERT(last <= End());
+ ValueIterator pos = Begin() + (first - Begin());
+ for (ValueIterator itr = pos; itr != last; ++itr)
+ itr->~GenericValue();
+ std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
+ data_.a.size -= static_cast<SizeType>(last - first);
+ return pos;
+ }
+
+ Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); }
+ ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); }
+
+ //@}
+
+ //!@name Number
+ //@{
+
+ int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; }
+ unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; }
+ int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; }
+ uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; }
+
+ //! Get the value as double type.
+ /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless.
+ */
+ double GetDouble() const {
+ RAPIDJSON_ASSERT(IsNumber());
+ if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
+ if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double
+ if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
+ if ((data_.f.flags & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
+ RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
+ }
+
+ //! Get the value as float type.
+ /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless.
+ */
+ float GetFloat() const {
+ return static_cast<float>(GetDouble());
+ }
+
+ GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
+ GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; }
+ GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
+ GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
+ GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
+ GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast<double>(f)); return *this; }
+
+ //@}
+
+ //!@name String
+ //@{
+
+ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }
+
+ //! Get the length of string.
+ /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
+ */
+ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
+
+ //! Set this value as a string without copying source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string pointer.
+ \param length The length of source string, excluding the trailing null terminator.
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() == s && GetStringLength() == length
+ \see SetString(StringRefType)
+ */
+ GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }
+
+ //! Set this value as a string without copying source string.
+ /*! \param s source string reference
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() == s && GetStringLength() == s.length
+ */
+ GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }
+
+ //! Set this value as a string by copying from source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string.
+ \param length The length of source string, excluding the trailing null terminator.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+ */
+ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
+
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+ */
+ GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
+ \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
+#endif
+
+ //@}
+
+ //!@name Array
+ //@{
+
+ //! Templated version for checking whether this value is type T.
+ /*!
+ \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string<Ch>
+ */
+ template <typename T>
+ bool Is() const { return internal::TypeHelper<ValueType, T>::Is(*this); }
+
+ template <typename T>
+ T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); }
+
+ template <typename T>
+ T Get() { return internal::TypeHelper<ValueType, T>::Get(*this); }
+
+ template<typename T>
+ ValueType& Set(const T& data) { return internal::TypeHelper<ValueType, T>::Set(*this, data); }
+
+ template<typename T>
+ ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper<ValueType, T>::Set(*this, data, allocator); }
+
+ //@}
+
+ //! Generate events of this value to a Handler.
+ /*! This function adopts the GoF visitor pattern.
+ Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
+ It can also be used to deep clone this value via GenericDocument, which is also a Handler.
+ \tparam Handler type of handler.
+ \param handler An object implementing concept Handler.
+ */
+ template <typename Handler>
+ bool Accept(Handler& handler) const {
+ switch(GetType()) {
+ case kNullType: return handler.Null();
+ case kFalseType: return handler.Bool(false);
+ case kTrueType: return handler.Bool(true);
+
+ case kObjectType:
+ if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
+ return false;
+ for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
+ RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
+ if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0)))
+ return false;
+ if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))
+ return false;
+ }
+ return handler.EndObject(data_.o.size);
+
+ case kArrayType:
+ if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
+ return false;
+ for (const GenericValue* v = Begin(); v != End(); ++v)
+ if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
+ return false;
+ return handler.EndArray(data_.a.size);
+
+ case kStringType:
+ return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0);
+
+ default:
+ RAPIDJSON_ASSERT(GetType() == kNumberType);
+ if (IsDouble()) return handler.Double(data_.n.d);
+ else if (IsInt()) return handler.Int(data_.n.i.i);
+ else if (IsUint()) return handler.Uint(data_.n.u.u);
+ else if (IsInt64()) return handler.Int64(data_.n.i64);
+ else return handler.Uint64(data_.n.u64);
+ }
+ }
+
+private:
+ template <typename, typename> friend class GenericValue;
+ template <typename, typename, typename> friend class GenericDocument;
+
+ enum {
+ kBoolFlag = 0x0008,
+ kNumberFlag = 0x0010,
+ kIntFlag = 0x0020,
+ kUintFlag = 0x0040,
+ kInt64Flag = 0x0080,
+ kUint64Flag = 0x0100,
+ kDoubleFlag = 0x0200,
+ kStringFlag = 0x0400,
+ kCopyFlag = 0x0800,
+ kInlineStrFlag = 0x1000,
+
+ // Initial flags of different types.
+ kNullFlag = kNullType,
+ kTrueFlag = kTrueType | kBoolFlag,
+ kFalseFlag = kFalseType | kBoolFlag,
+ kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
+ kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
+ kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
+ kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
+ kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
+ kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
+ kConstStringFlag = kStringType | kStringFlag,
+ kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
+ kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
+ kObjectFlag = kObjectType,
+ kArrayFlag = kArrayType,
+
+ kTypeMask = 0x07
+ };
+
+ static const SizeType kDefaultArrayCapacity = 16;
+ static const SizeType kDefaultObjectCapacity = 16;
+
+ struct Flag {
+#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
+ char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer
+#elif RAPIDJSON_64BIT
+ char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes
+#else
+ char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes
+#endif
+ uint16_t flags;
+ };
+
+ struct String {
+ SizeType length;
+ SizeType hashcode; //!< reserved
+ const Ch* str;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
+ // (excluding the terminating zero) and store a value to determine the length of the contained
+ // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string
+ // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
+ // the string terminator as well. For getting the string length back from that value just use
+ // "MaxSize - str[LenPos]".
+ // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode,
+ // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings).
+ struct ShortString {
+ enum { MaxChars = sizeof(static_cast<Flag*>(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
+ Ch str[MaxChars];
+
+ inline static bool Usable(SizeType len) { return (MaxSize >= len); }
+ inline void SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize - len); }
+ inline SizeType GetLength() const { return static_cast<SizeType>(MaxSize - str[LenPos]); }
+ }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // By using proper binary layout, retrieval of different integer types do not need conversions.
+ union Number {
+#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
+ struct I {
+ int i;
+ char padding[4];
+ }i;
+ struct U {
+ unsigned u;
+ char padding2[4];
+ }u;
+#else
+ struct I {
+ char padding[4];
+ int i;
+ }i;
+ struct U {
+ char padding2[4];
+ unsigned u;
+ }u;
+#endif
+ int64_t i64;
+ uint64_t u64;
+ double d;
+ }; // 8 bytes
+
+ struct ObjectData {
+ SizeType size;
+ SizeType capacity;
+ Member* members;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ struct ArrayData {
+ SizeType size;
+ SizeType capacity;
+ GenericValue* elements;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ union Data {
+ String s;
+ ShortString ss;
+ Number n;
+ ObjectData o;
+ ArrayData a;
+ Flag f;
+ }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
+
+ RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
+ RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
+ RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
+ RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); }
+ RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
+ RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
+
+ // Initialize this value as array with initial data, without calling destructor.
+ void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
+ data_.f.flags = kArrayFlag;
+ if (count) {
+ GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
+ SetElementsPointer(e);
+ std::memcpy(e, values, count * sizeof(GenericValue));
+ }
+ else
+ SetElementsPointer(0);
+ data_.a.size = data_.a.capacity = count;
+ }
+
+ //! Initialize this value as object with initial data, without calling destructor.
+ void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
+ data_.f.flags = kObjectFlag;
+ if (count) {
+ Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
+ SetMembersPointer(m);
+ std::memcpy(m, members, count * sizeof(Member));
+ }
+ else
+ SetMembersPointer(0);
+ data_.o.size = data_.o.capacity = count;
+ }
+
+ //! Initialize this value as constant string, without calling destructor.
+ void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
+ data_.f.flags = kConstStringFlag;
+ SetStringPointer(s);
+ data_.s.length = s.length;
+ }
+
+ //! Initialize this value as copy string with initial data, without calling destructor.
+ void SetStringRaw(StringRefType s, Allocator& allocator) {
+ Ch* str = 0;
+ if (ShortString::Usable(s.length)) {
+ data_.f.flags = kShortStringFlag;
+ data_.ss.SetLength(s.length);
+ str = data_.ss.str;
+ } else {
+ data_.f.flags = kCopyStringFlag;
+ data_.s.length = s.length;
+ str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));
+ SetStringPointer(str);
+ }
+ std::memcpy(str, s, s.length * sizeof(Ch));
+ str[s.length] = '\0';
+ }
+
+ //! Assignment without calling destructor
+ void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+ data_ = rhs.data_;
+ // data_.f.flags = rhs.data_.f.flags;
+ rhs.data_.f.flags = kNullFlag;
+ }
+
+ template <typename SourceAllocator>
+ bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+ RAPIDJSON_ASSERT(IsString());
+ RAPIDJSON_ASSERT(rhs.IsString());
+
+ const SizeType len1 = GetStringLength();
+ const SizeType len2 = rhs.GetStringLength();
+ if(len1 != len2) { return false; }
+
+ const Ch* const str1 = GetString();
+ const Ch* const str2 = rhs.GetString();
+ if(str1 == str2) { return true; } // fast path for constant string
+
+ return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);
+ }
+
+ Data data_;
+};
+
+//! GenericValue with UTF8 encoding
+typedef GenericValue<UTF8<> > Value;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericDocument
+
+//! A document for parsing JSON text as DOM.
+/*!
+ \note implements Handler concept
+ \tparam Encoding Encoding for both parsing and string storage.
+ \tparam Allocator Allocator for allocating memory for the DOM
+ \tparam StackAllocator Allocator for allocating memory for stack during parsing.
+ \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>
+class GenericDocument : public GenericValue<Encoding, Allocator> {
+public:
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+
+ //! Constructor
+ /*! Creates an empty document of specified type.
+ \param type Mandatory type of object to create.
+ \param allocator Optional allocator for allocating memory.
+ \param stackCapacity Optional initial capacity of stack in bytes.
+ \param stackAllocator Optional allocator for allocating memory for stack.
+ */
+ explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
+ GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
+ {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ }
+
+ //! Constructor
+ /*! Creates an empty document which type is Null.
+ \param allocator Optional allocator for allocating memory.
+ \param stackCapacity Optional initial capacity of stack in bytes.
+ \param stackAllocator Optional allocator for allocating memory for stack.
+ */
+ GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
+ allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
+ {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+ : ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document
+ allocator_(rhs.allocator_),
+ ownAllocator_(rhs.ownAllocator_),
+ stack_(std::move(rhs.stack_)),
+ parseResult_(rhs.parseResult_)
+ {
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.parseResult_ = ParseResult();
+ }
+#endif
+
+ ~GenericDocument() {
+ Destroy();
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move assignment in C++11
+ GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+ {
+ // The cast to ValueType is necessary here, because otherwise it would
+ // attempt to call GenericValue's templated assignment operator.
+ ValueType::operator=(std::forward<ValueType>(rhs));
+
+ // Calling the destructor here would prematurely call stack_'s destructor
+ Destroy();
+
+ allocator_ = rhs.allocator_;
+ ownAllocator_ = rhs.ownAllocator_;
+ stack_ = std::move(rhs.stack_);
+ parseResult_ = rhs.parseResult_;
+
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.parseResult_ = ParseResult();
+
+ return *this;
+ }
+#endif
+
+ //! Exchange the contents of this document with those of another.
+ /*!
+ \param rhs Another document.
+ \note Constant complexity.
+ \see GenericValue::Swap
+ */
+ GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {
+ ValueType::Swap(rhs);
+ stack_.Swap(rhs.stack_);
+ internal::Swap(allocator_, rhs.allocator_);
+ internal::Swap(ownAllocator_, rhs.ownAllocator_);
+ internal::Swap(parseResult_, rhs.parseResult_);
+ return *this;
+ }
+
+ //! free-standing swap function helper
+ /*!
+ Helper function to enable support for common swap implementation pattern based on \c std::swap:
+ \code
+ void swap(MyClass& a, MyClass& b) {
+ using std::swap;
+ swap(a.doc, b.doc);
+ // ...
+ }
+ \endcode
+ \see Swap()
+ */
+ friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
+
+ //! Populate this document by a generator which produces SAX events.
+ /*! \tparam Generator A functor with <tt>bool f(Handler)</tt> prototype.
+ \param g Generator functor which sends SAX events to the parameter.
+ \return The document itself for fluent API.
+ */
+ template <typename Generator>
+ GenericDocument& Populate(Generator& g) {
+ ClearStackOnExit scope(*this);
+ if (g(*this)) {
+ RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+ ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
+ }
+ return *this;
+ }
+
+ //!@name Parse from stream
+ //!@{
+
+ //! Parse JSON text from an input stream (with Encoding conversion)
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam SourceEncoding Encoding of input stream
+ \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
+ stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
+ ClearStackOnExit scope(*this);
+ parseResult_ = reader.template Parse<parseFlags>(is, *this);
+ if (parseResult_) {
+ RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+ ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
+ }
+ return *this;
+ }
+
+ //! Parse JSON text from an input stream
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags, typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ return ParseStream<parseFlags, Encoding, InputStream>(is);
+ }
+
+ //! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
+ /*! \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
+ }
+ //!@}
+
+ //!@name Parse in-place from mutable string
+ //!@{
+
+ //! Parse JSON text from a mutable string
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \param str Mutable zero-terminated string to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& ParseInsitu(Ch* str) {
+ GenericInsituStringStream<Encoding> s(str);
+ return ParseStream<parseFlags | kParseInsituFlag>(s);
+ }
+
+ //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
+ /*! \param str Mutable zero-terminated string to be parsed.
+ \return The document itself for fluent API.
+ */
+ GenericDocument& ParseInsitu(Ch* str) {
+ return ParseInsitu<kParseDefaultFlags>(str);
+ }
+ //!@}
+
+ //!@name Parse from read-only string
+ //!@{
+
+ //! Parse JSON text from a read-only string (with Encoding conversion)
+ /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
+ \tparam SourceEncoding Transcoding from input Encoding
+ \param str Read-only zero-terminated string to be parsed.
+ */
+ template <unsigned parseFlags, typename SourceEncoding>
+ GenericDocument& Parse(const typename SourceEncoding::Ch* str) {
+ RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+ GenericStringStream<SourceEncoding> s(str);
+ return ParseStream<parseFlags, SourceEncoding>(s);
+ }
+
+ //! Parse JSON text from a read-only string
+ /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
+ \param str Read-only zero-terminated string to be parsed.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& Parse(const Ch* str) {
+ return Parse<parseFlags, Encoding>(str);
+ }
+
+ //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags)
+ /*! \param str Read-only zero-terminated string to be parsed.
+ */
+ GenericDocument& Parse(const Ch* str) {
+ return Parse<kParseDefaultFlags>(str);
+ }
+
+ template <unsigned parseFlags, typename SourceEncoding>
+ GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) {
+ RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+ MemoryStream ms(static_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));
+ EncodedInputStream<SourceEncoding, MemoryStream> is(ms);
+ ParseStream<parseFlags, SourceEncoding>(is);
+ return *this;
+ }
+
+ template <unsigned parseFlags>
+ GenericDocument& Parse(const Ch* str, size_t length) {
+ return Parse<parseFlags, Encoding>(str, length);
+ }
+
+ GenericDocument& Parse(const Ch* str, size_t length) {
+ return Parse<kParseDefaultFlags>(str, length);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ template <unsigned parseFlags, typename SourceEncoding>
+ GenericDocument& Parse(const std::basic_string<typename SourceEncoding::Ch>& str) {
+ // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t)
+ return Parse<parseFlags, SourceEncoding>(str.c_str());
+ }
+
+ template <unsigned parseFlags>
+ GenericDocument& Parse(const std::basic_string<Ch>& str) {
+ return Parse<parseFlags, Encoding>(str.c_str());
+ }
+
+ GenericDocument& Parse(const std::basic_string<Ch>& str) {
+ return Parse<kParseDefaultFlags>(str);
+ }
+#endif // RAPIDJSON_HAS_STDSTRING
+
+ //!@}
+
+ //!@name Handling parse errors
+ //!@{
+
+ //! Whether a parse error has occured in the last parsing.
+ bool HasParseError() const { return parseResult_.IsError(); }
+
+ //! Get the \ref ParseErrorCode of last parsing.
+ ParseErrorCode GetParseError() const { return parseResult_.Code(); }
+
+ //! Get the position of last parsing error in input, 0 otherwise.
+ size_t GetErrorOffset() const { return parseResult_.Offset(); }
+
+ //! Implicit conversion to get the last parse result
+#ifndef __clang // -Wdocumentation
+ /*! \return \ref ParseResult of the last parse operation
+
+ \code
+ Document doc;
+ ParseResult ok = doc.Parse(json);
+ if (!ok)
+ printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset());
+ \endcode
+ */
+#endif
+ operator ParseResult() const { return parseResult_; }
+ //!@}
+
+ //! Get the allocator of this document.
+ Allocator& GetAllocator() {
+ RAPIDJSON_ASSERT(allocator_);
+ return *allocator_;
+ }
+
+ //! Get the capacity of stack in bytes.
+ size_t GetStackCapacity() const { return stack_.GetCapacity(); }
+
+private:
+ // clear stack on any exit from ParseStream, e.g. due to exception
+ struct ClearStackOnExit {
+ explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}
+ ~ClearStackOnExit() { d_.ClearStack(); }
+ private:
+ ClearStackOnExit(const ClearStackOnExit&);
+ ClearStackOnExit& operator=(const ClearStackOnExit&);
+ GenericDocument& d_;
+ };
+
+ // callers of the following private Handler functions
+ // template <typename,typename,typename> friend class GenericReader; // for parsing
+ template <typename, typename> friend class GenericValue; // for deep copying
+
+public:
+ // Implementation of Handler
+ bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
+ bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }
+ bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
+
+ bool RawNumber(const Ch* str, SizeType length, bool copy) {
+ if (copy)
+ new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
+ else
+ new (stack_.template Push<ValueType>()) ValueType(str, length);
+ return true;
+ }
+
+ bool String(const Ch* str, SizeType length, bool copy) {
+ if (copy)
+ new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
+ else
+ new (stack_.template Push<ValueType>()) ValueType(str, length);
+ return true;
+ }
+
+ bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
+
+ bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }
+
+ bool EndObject(SizeType memberCount) {
+ typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
+ stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator());
+ return true;
+ }
+
+ bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }
+
+ bool EndArray(SizeType elementCount) {
+ ValueType* elements = stack_.template Pop<ValueType>(elementCount);
+ stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
+ return true;
+ }
+
+private:
+ //! Prohibit copying
+ GenericDocument(const GenericDocument&);
+ //! Prohibit assignment
+ GenericDocument& operator=(const GenericDocument&);
+
+ void ClearStack() {
+ if (Allocator::kNeedFree)
+ while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
+ (stack_.template Pop<ValueType>(1))->~ValueType();
+ else
+ stack_.Clear();
+ stack_.ShrinkToFit();
+ }
+
+ void Destroy() {
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
+ static const size_t kDefaultStackCapacity = 1024;
+ Allocator* allocator_;
+ Allocator* ownAllocator_;
+ internal::Stack<StackAllocator> stack_;
+ ParseResult parseResult_;
+};
+
+//! GenericDocument with UTF8 encoding
+typedef GenericDocument<UTF8<> > Document;
+
+// defined here due to the dependency on GenericDocument
+template <typename Encoding, typename Allocator>
+template <typename SourceAllocator>
+inline
+GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)
+{
+ switch (rhs.GetType()) {
+ case kObjectType:
+ case kArrayType: { // perform deep copy via SAX Handler
+ GenericDocument<Encoding,Allocator> d(&allocator);
+ rhs.Accept(d);
+ RawAssign(*d.stack_.template Pop<GenericValue>(1));
+ }
+ break;
+ case kStringType:
+ if (rhs.data_.f.flags == kConstStringFlag) {
+ data_.f.flags = rhs.data_.f.flags;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ } else {
+ SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
+ }
+ break;
+ default:
+ data_.f.flags = rhs.data_.f.flags;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ break;
+ }
+}
+
+//! Helper class for accessing Value of array type.
+/*!
+ Instance of this helper class is obtained by \c GenericValue::GetArray().
+ In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
+*/
+template <bool Const, typename ValueT>
+class GenericArray {
+public:
+ typedef GenericArray<true, ValueT> ConstArray;
+ typedef GenericArray<false, ValueT> Array;
+ typedef ValueT PlainType;
+ typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
+ typedef ValueType* ValueIterator; // This may be const or non-const iterator
+ typedef const ValueT* ConstValueIterator;
+ typedef typename ValueType::AllocatorType AllocatorType;
+ typedef typename ValueType::StringRefType StringRefType;
+
+ template <typename, typename>
+ friend class GenericValue;
+
+ GenericArray(const GenericArray& rhs) : value_(rhs.value_) {}
+ GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }
+ ~GenericArray() {}
+
+ SizeType Size() const { return value_.Size(); }
+ SizeType Capacity() const { return value_.Capacity(); }
+ bool Empty() const { return value_.Empty(); }
+ void Clear() const { value_.Clear(); }
+ ValueType& operator[](SizeType index) const { return value_[index]; }
+ ValueIterator Begin() const { return value_.Begin(); }
+ ValueIterator End() const { return value_.End(); }
+ GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; }
+ GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
+ GenericArray PopBack() const { value_.PopBack(); return *this; }
+ ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); }
+ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); }
+
+#if RAPIDJSON_HAS_CXX11_RANGE_FOR
+ ValueIterator begin() const { return value_.Begin(); }
+ ValueIterator end() const { return value_.End(); }
+#endif
+
+private:
+ GenericArray();
+ GenericArray(ValueType& value) : value_(value) {}
+ ValueType& value_;
+};
+
+//! Helper class for accessing Value of object type.
+/*!
+ Instance of this helper class is obtained by \c GenericValue::GetObject().
+ In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
+*/
+template <bool Const, typename ValueT>
+class GenericObject {
+public:
+ typedef GenericObject<true, ValueT> ConstObject;
+ typedef GenericObject<false, ValueT> Object;
+ typedef ValueT PlainType;
+ typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
+ typedef GenericMemberIterator<Const, typename ValueT::EncodingType, typename ValueT::AllocatorType> MemberIterator; // This may be const or non-const iterator
+ typedef GenericMemberIterator<true, typename ValueT::EncodingType, typename ValueT::AllocatorType> ConstMemberIterator;
+ typedef typename ValueType::AllocatorType AllocatorType;
+ typedef typename ValueType::StringRefType StringRefType;
+ typedef typename ValueType::EncodingType EncodingType;
+ typedef typename ValueType::Ch Ch;
+
+ template <typename, typename>
+ friend class GenericValue;
+
+ GenericObject(const GenericObject& rhs) : value_(rhs.value_) {}
+ GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }
+ ~GenericObject() {}
+
+ SizeType MemberCount() const { return value_.MemberCount(); }
+ bool ObjectEmpty() const { return value_.ObjectEmpty(); }
+ template <typename T> ValueType& operator[](T* name) const { return value_[name]; }
+ template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }
+#if RAPIDJSON_HAS_STDSTRING
+ ValueType& operator[](const std::basic_string<Ch>& name) const { return value_[name]; }
+#endif
+ MemberIterator MemberBegin() const { return value_.MemberBegin(); }
+ MemberIterator MemberEnd() const { return value_.MemberEnd(); }
+ bool HasMember(const Ch* name) const { return value_.HasMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+ bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }
+#endif
+ template <typename SourceAllocator> bool HasMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.HasMember(name); }
+ MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); }
+ template <typename SourceAllocator> MemberIterator FindMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.FindMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+ MemberIterator FindMember(const std::basic_string<Ch>& name) const { return value_.FindMember(name); }
+#endif
+ GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+ GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+#if RAPIDJSON_HAS_STDSTRING
+ GenericObject AddMember(ValueType& name, std::basic_string<Ch>& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+#endif
+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+ GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+ GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+ GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+ GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+ void RemoveAllMembers() { return value_.RemoveAllMembers(); }
+ bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+ bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); }
+#endif
+ template <typename SourceAllocator> bool RemoveMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.RemoveMember(name); }
+ MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); }
+ MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); }
+ MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); }
+ bool EraseMember(const Ch* name) const { return value_.EraseMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+ bool EraseMember(const std::basic_string<Ch>& name) const { return EraseMember(ValueType(StringRef(name))); }
+#endif
+ template <typename SourceAllocator> bool EraseMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.EraseMember(name); }
+
+#if RAPIDJSON_HAS_CXX11_RANGE_FOR
+ MemberIterator begin() const { return value_.MemberBegin(); }
+ MemberIterator end() const { return value_.MemberEnd(); }
+#endif
+
+private:
+ GenericObject();
+ GenericObject(ValueType& value) : value_(value) {}
+ ValueType& value_;
+};
+
+RAPIDJSON_NAMESPACE_END
+#ifdef _MINWINDEF_ // see: http://stackoverflow.com/questions/22744262/cant-call-stdmax-because-minwindef-h-defines-max
+#ifndef NOMINMAX
+#pragma pop_macro("min")
+#pragma pop_macro("max")
+#endif
+#endif
+RAPIDJSON_DIAG_POP
+
+#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/external/rapidjson/rapidjson/encodedstream.h b/external/rapidjson/rapidjson/encodedstream.h
new file mode 100644
index 0000000..1450683
--- /dev/null
+++ b/external/rapidjson/rapidjson/encodedstream.h
@@ -0,0 +1,299 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODEDSTREAM_H_
+#define RAPIDJSON_ENCODEDSTREAM_H_
+
+#include "stream.h"
+#include "memorystream.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Input byte stream wrapper with a statically bound encoding.
+/*!
+ \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+ \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
+*/
+template <typename Encoding, typename InputByteStream>
+class EncodedInputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+ typedef typename Encoding::Ch Ch;
+
+ EncodedInputStream(InputByteStream& is) : is_(is) {
+ current_ = Encoding::TakeBOM(is_);
+ }
+
+ Ch Peek() const { return current_; }
+ Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
+ size_t Tell() const { return is_.Tell(); }
+
+ // Not implemented
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ EncodedInputStream(const EncodedInputStream&);
+ EncodedInputStream& operator=(const EncodedInputStream&);
+
+ InputByteStream& is_;
+ Ch current_;
+};
+
+//! Specialized for UTF8 MemoryStream.
+template <>
+class EncodedInputStream<UTF8<>, MemoryStream> {
+public:
+ typedef UTF8<>::Ch Ch;
+
+ EncodedInputStream(MemoryStream& is) : is_(is) {
+ if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
+ if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
+ if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
+ }
+ Ch Peek() const { return is_.Peek(); }
+ Ch Take() { return is_.Take(); }
+ size_t Tell() const { return is_.Tell(); }
+
+ // Not implemented
+ void Put(Ch) {}
+ void Flush() {}
+ Ch* PutBegin() { return 0; }
+ size_t PutEnd(Ch*) { return 0; }
+
+ MemoryStream& is_;
+
+private:
+ EncodedInputStream(const EncodedInputStream&);
+ EncodedInputStream& operator=(const EncodedInputStream&);
+};
+
+//! Output byte stream wrapper with statically bound encoding.
+/*!
+ \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+ \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
+*/
+template <typename Encoding, typename OutputByteStream>
+class EncodedOutputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+ typedef typename Encoding::Ch Ch;
+
+ EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
+ if (putBOM)
+ Encoding::PutBOM(os_);
+ }
+
+ void Put(Ch c) { Encoding::Put(os_, c); }
+ void Flush() { os_.Flush(); }
+
+ // Not implemented
+ Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
+ Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ EncodedOutputStream(const EncodedOutputStream&);
+ EncodedOutputStream& operator=(const EncodedOutputStream&);
+
+ OutputByteStream& os_;
+};
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+ \tparam CharType Type of character for reading.
+ \tparam InputByteStream type of input byte stream to be wrapped.
+*/
+template <typename CharType, typename InputByteStream>
+class AutoUTFInputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+ typedef CharType Ch;
+
+ //! Constructor.
+ /*!
+ \param is input stream to be wrapped.
+ \param type UTF encoding type if it is not detected from the stream.
+ */
+ AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
+ RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
+ DetectType();
+ static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
+ takeFunc_ = f[type_];
+ current_ = takeFunc_(*is_);
+ }
+
+ UTFType GetType() const { return type_; }
+ bool HasBOM() const { return hasBOM_; }
+
+ Ch Peek() const { return current_; }
+ Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
+ size_t Tell() const { return is_->Tell(); }
+
+ // Not implemented
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ AutoUTFInputStream(const AutoUTFInputStream&);
+ AutoUTFInputStream& operator=(const AutoUTFInputStream&);
+
+ // Detect encoding type with BOM or RFC 4627
+ void DetectType() {
+ // BOM (Byte Order Mark):
+ // 00 00 FE FF UTF-32BE
+ // FF FE 00 00 UTF-32LE
+ // FE FF UTF-16BE
+ // FF FE UTF-16LE
+ // EF BB BF UTF-8
+
+ const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
+ if (!c)
+ return;
+
+ unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
+ hasBOM_ = false;
+ if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+ else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+ else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
+ else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
+ else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
+
+ // RFC 4627: Section 3
+ // "Since the first two characters of a JSON text will always be ASCII
+ // characters [RFC0020], it is possible to determine whether an octet
+ // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
+ // at the pattern of nulls in the first four octets."
+ // 00 00 00 xx UTF-32BE
+ // 00 xx 00 xx UTF-16BE
+ // xx 00 00 00 UTF-32LE
+ // xx 00 xx 00 UTF-16LE
+ // xx xx xx xx UTF-8
+
+ if (!hasBOM_) {
+ unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
+ switch (pattern) {
+ case 0x08: type_ = kUTF32BE; break;
+ case 0x0A: type_ = kUTF16BE; break;
+ case 0x01: type_ = kUTF32LE; break;
+ case 0x05: type_ = kUTF16LE; break;
+ case 0x0F: type_ = kUTF8; break;
+ default: break; // Use type defined by user.
+ }
+ }
+
+ // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+ if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+ if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+ }
+
+ typedef Ch (*TakeFunc)(InputByteStream& is);
+ InputByteStream* is_;
+ UTFType type_;
+ Ch current_;
+ TakeFunc takeFunc_;
+ bool hasBOM_;
+};
+
+//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+ \tparam CharType Type of character for writing.
+ \tparam OutputByteStream type of output byte stream to be wrapped.
+*/
+template <typename CharType, typename OutputByteStream>
+class AutoUTFOutputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+ typedef CharType Ch;
+
+ //! Constructor.
+ /*!
+ \param os output stream to be wrapped.
+ \param type UTF encoding type.
+ \param putBOM Whether to write BOM at the beginning of the stream.
+ */
+ AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
+ RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
+
+ // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+ if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+ if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+
+ static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
+ putFunc_ = f[type_];
+
+ if (putBOM)
+ PutBOM();
+ }
+
+ UTFType GetType() const { return type_; }
+
+ void Put(Ch c) { putFunc_(*os_, c); }
+ void Flush() { os_->Flush(); }
+
+ // Not implemented
+ Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
+ Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ AutoUTFOutputStream(const AutoUTFOutputStream&);
+ AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
+
+ void PutBOM() {
+ typedef void (*PutBOMFunc)(OutputByteStream&);
+ static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
+ f[type_](*os_);
+ }
+
+ typedef void (*PutFunc)(OutputByteStream&, Ch);
+
+ OutputByteStream* os_;
+ UTFType type_;
+ PutFunc putFunc_;
+};
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/external/rapidjson/rapidjson/encodings.h b/external/rapidjson/rapidjson/encodings.h
new file mode 100644
index 0000000..baa7c2b
--- /dev/null
+++ b/external/rapidjson/rapidjson/encodings.h
@@ -0,0 +1,716 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODINGS_H_
+#define RAPIDJSON_ENCODINGS_H_
+
+#include "rapidjson.h"
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+#elif defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+RAPIDJSON_DIAG_OFF(overflow)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Encoding
+
+/*! \class rapidjson::Encoding
+ \brief Concept for encoding of Unicode characters.
+
+\code
+concept Encoding {
+ typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
+
+ enum { supportUnicode = 1 }; // or 0 if not supporting unicode
+
+ //! \brief Encode a Unicode codepoint to an output stream.
+ //! \param os Output stream.
+ //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint);
+
+ //! \brief Decode a Unicode codepoint from an input stream.
+ //! \param is Input stream.
+ //! \param codepoint Output of the unicode codepoint.
+ //! \return true if a valid codepoint can be decoded from the stream.
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint);
+
+ //! \brief Validate one Unicode codepoint from an encoded stream.
+ //! \param is Input stream to obtain codepoint.
+ //! \param os Output for copying one codepoint.
+ //! \return true if it is valid.
+ //! \note This function just validating and copying the codepoint without actually decode it.
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os);
+
+ // The following functions are deal with byte streams.
+
+ //! Take a character from input byte stream, skip BOM if exist.
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is);
+
+ //! Take a character from input byte stream.
+ template <typename InputByteStream>
+ static Ch Take(InputByteStream& is);
+
+ //! Put BOM to output byte stream.
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os);
+
+ //! Put a character to output byte stream.
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, Ch c);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF8
+
+//! UTF-8 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-8
+ http://tools.ietf.org/html/rfc3629
+ \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
+ \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct UTF8 {
+ typedef CharType Ch;
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ if (codepoint <= 0x7F)
+ os.Put(static_cast<Ch>(codepoint & 0xFF));
+ else if (codepoint <= 0x7FF) {
+ os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
+ }
+ else if (codepoint <= 0xFFFF) {
+ os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ }
+
+ template<typename OutputStream>
+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ if (codepoint <= 0x7F)
+ PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
+ else if (codepoint <= 0x7FF) {
+ PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
+ }
+ else if (codepoint <= 0xFFFF) {
+ PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
+#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
+#define TAIL() COPY(); TRANS(0x70)
+ typename InputStream::Ch c = is.Take();
+ if (!(c & 0x80)) {
+ *codepoint = static_cast<unsigned char>(c);
+ return true;
+ }
+
+ unsigned char type = GetRange(static_cast<unsigned char>(c));
+ if (type >= 32) {
+ *codepoint = 0;
+ } else {
+ *codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
+ }
+ bool result = true;
+ switch (type) {
+ case 2: TAIL(); return result;
+ case 3: TAIL(); TAIL(); return result;
+ case 4: COPY(); TRANS(0x50); TAIL(); return result;
+ case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
+ case 6: TAIL(); TAIL(); TAIL(); return result;
+ case 10: COPY(); TRANS(0x20); TAIL(); return result;
+ case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+ default: return false;
+ }
+#undef COPY
+#undef TRANS
+#undef TAIL
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+#define COPY() os.Put(c = is.Take())
+#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
+#define TAIL() COPY(); TRANS(0x70)
+ Ch c;
+ COPY();
+ if (!(c & 0x80))
+ return true;
+
+ bool result = true;
+ switch (GetRange(static_cast<unsigned char>(c))) {
+ case 2: TAIL(); return result;
+ case 3: TAIL(); TAIL(); return result;
+ case 4: COPY(); TRANS(0x50); TAIL(); return result;
+ case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
+ case 6: TAIL(); TAIL(); TAIL(); return result;
+ case 10: COPY(); TRANS(0x20); TAIL(); return result;
+ case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+ default: return false;
+ }
+#undef COPY
+#undef TRANS
+#undef TAIL
+ }
+
+ static unsigned char GetRange(unsigned char c) {
+ // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+ // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
+ static const unsigned char type[] = {
+ 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,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+ 8,8,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,2,2,2,2,2,
+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+ };
+ return type[c];
+ }
+
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ typename InputByteStream::Ch c = Take(is);
+ if (static_cast<unsigned char>(c) != 0xEFu) return c;
+ c = is.Take();
+ if (static_cast<unsigned char>(c) != 0xBBu) return c;
+ c = is.Take();
+ if (static_cast<unsigned char>(c) != 0xBFu) return c;
+ c = is.Take();
+ return c;
+ }
+
+ template <typename InputByteStream>
+ static Ch Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ return static_cast<Ch>(is.Take());
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, Ch c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(c));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF16
+
+//! UTF-16 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-16
+ http://tools.ietf.org/html/rfc2781
+ \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
+ \note implements Encoding concept
+
+ \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+ For streaming, use UTF16LE and UTF16BE, which handle endianness.
+*/
+template<typename CharType = wchar_t>
+struct UTF16 {
+ typedef CharType Ch;
+ RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+ if (codepoint <= 0xFFFF) {
+ RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
+ os.Put(static_cast<typename OutputStream::Ch>(codepoint));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ unsigned v = codepoint - 0x10000;
+ os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
+ os.Put((v & 0x3FF) | 0xDC00);
+ }
+ }
+
+
+ template<typename OutputStream>
+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+ if (codepoint <= 0xFFFF) {
+ RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
+ PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ unsigned v = codepoint - 0x10000;
+ PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
+ PutUnsafe(os, (v & 0x3FF) | 0xDC00);
+ }
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+ typename InputStream::Ch c = is.Take();
+ if (c < 0xD800 || c > 0xDFFF) {
+ *codepoint = static_cast<unsigned>(c);
+ return true;
+ }
+ else if (c <= 0xDBFF) {
+ *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
+ c = is.Take();
+ *codepoint |= (static_cast<unsigned>(c) & 0x3FF);
+ *codepoint += 0x10000;
+ return c >= 0xDC00 && c <= 0xDFFF;
+ }
+ return false;
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+ typename InputStream::Ch c;
+ os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
+ if (c < 0xD800 || c > 0xDFFF)
+ return true;
+ else if (c <= 0xDBFF) {
+ os.Put(c = is.Take());
+ return c >= 0xDC00 && c <= 0xDFFF;
+ }
+ return false;
+ }
+};
+
+//! UTF-16 little endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16LE : UTF16<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ unsigned c = static_cast<uint8_t>(is.Take());
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+ return static_cast<CharType>(c);
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
+ }
+};
+
+//! UTF-16 big endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16BE : UTF16<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+ c |= static_cast<uint8_t>(is.Take());
+ return static_cast<CharType>(c);
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF32
+
+//! UTF-32 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-32
+ \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
+ \note implements Encoding concept
+
+ \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+ For streaming, use UTF32LE and UTF32BE, which handle endianness.
+*/
+template<typename CharType = unsigned>
+struct UTF32 {
+ typedef CharType Ch;
+ RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ os.Put(codepoint);
+ }
+
+ template<typename OutputStream>
+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ PutUnsafe(os, codepoint);
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+ Ch c = is.Take();
+ *codepoint = c;
+ return c <= 0x10FFFF;
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+ Ch c;
+ os.Put(c = is.Take());
+ return c <= 0x10FFFF;
+ }
+};
+
+//! UTF-32 little endian enocoding.
+template<typename CharType = unsigned>
+struct UTF32LE : UTF32<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ unsigned c = static_cast<uint8_t>(is.Take());
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
+ return static_cast<CharType>(c);
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
+ }
+};
+
+//! UTF-32 big endian encoding.
+template<typename CharType = unsigned>
+struct UTF32BE : UTF32<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
+ return static_cast<CharType>(c);
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ASCII
+
+//! ASCII encoding.
+/*! http://en.wikipedia.org/wiki/ASCII
+ \tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
+ \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct ASCII {
+ typedef CharType Ch;
+
+ enum { supportUnicode = 0 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_ASSERT(codepoint <= 0x7F);
+ os.Put(static_cast<Ch>(codepoint & 0xFF));
+ }
+
+ template<typename OutputStream>
+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_ASSERT(codepoint <= 0x7F);
+ PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+ uint8_t c = static_cast<uint8_t>(is.Take());
+ *codepoint = c;
+ return c <= 0X7F;
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+ uint8_t c = static_cast<uint8_t>(is.Take());
+ os.Put(static_cast<typename OutputStream::Ch>(c));
+ return c <= 0x7F;
+ }
+
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ uint8_t c = static_cast<uint8_t>(Take(is));
+ return static_cast<Ch>(c);
+ }
+
+ template <typename InputByteStream>
+ static Ch Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ return static_cast<Ch>(is.Take());
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ (void)os;
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, Ch c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(c));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// AutoUTF
+
+//! Runtime-specified UTF encoding type of a stream.
+enum UTFType {
+ kUTF8 = 0, //!< UTF-8.
+ kUTF16LE = 1, //!< UTF-16 little endian.
+ kUTF16BE = 2, //!< UTF-16 big endian.
+ kUTF32LE = 3, //!< UTF-32 little endian.
+ kUTF32BE = 4 //!< UTF-32 big endian.
+};
+
+//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
+/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
+*/
+template<typename CharType>
+struct AutoUTF {
+ typedef CharType Ch;
+
+ enum { supportUnicode = 1 };
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+ template<typename OutputStream>
+ RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
+ typedef void (*EncodeFunc)(OutputStream&, unsigned);
+ static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
+ (*f[os.GetType()])(os, codepoint);
+ }
+
+ template<typename OutputStream>
+ RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ typedef void (*EncodeFunc)(OutputStream&, unsigned);
+ static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
+ (*f[os.GetType()])(os, codepoint);
+ }
+
+ template <typename InputStream>
+ RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
+ typedef bool (*DecodeFunc)(InputStream&, unsigned*);
+ static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
+ return (*f[is.GetType()])(is, codepoint);
+ }
+
+ template <typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
+ static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
+ return (*f[is.GetType()])(is, os);
+ }
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Transcoder
+
+//! Encoding conversion.
+template<typename SourceEncoding, typename TargetEncoding>
+struct Transcoder {
+ //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+ unsigned codepoint;
+ if (!SourceEncoding::Decode(is, &codepoint))
+ return false;
+ TargetEncoding::Encode(os, codepoint);
+ return true;
+ }
+
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+ unsigned codepoint;
+ if (!SourceEncoding::Decode(is, &codepoint))
+ return false;
+ TargetEncoding::EncodeUnsafe(os, codepoint);
+ return true;
+ }
+
+ //! Validate one Unicode codepoint from an encoded stream.
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ return Transcode(is, os); // Since source/target encoding is different, must transcode.
+ }
+};
+
+// Forward declaration.
+template<typename Stream>
+inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
+
+//! Specialization of Transcoder with same source and target encoding.
+template<typename Encoding>
+struct Transcoder<Encoding, Encoding> {
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+ os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
+ return true;
+ }
+
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+ PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
+ return true;
+ }
+
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ return Encoding::Validate(is, os); // source/target encoding are the same
+ }
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ENCODINGS_H_
diff --git a/external/rapidjson/rapidjson/error/en.h b/external/rapidjson/rapidjson/error/en.h
new file mode 100644
index 0000000..2db838b
--- /dev/null
+++ b/external/rapidjson/rapidjson/error/en.h
@@ -0,0 +1,74 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_EN_H_
+#define RAPIDJSON_ERROR_EN_H_
+
+#include "error.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(covered-switch-default)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Maps error code of parsing into error message.
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \param parseErrorCode Error code obtained in parsing.
+ \return the error message.
+ \note User can make a copy of this function for localization.
+ Using switch-case is safer for future modification of error codes.
+*/
+inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
+ switch (parseErrorCode) {
+ case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
+
+ case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
+ case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
+
+ case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
+
+ case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
+ case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
+ case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
+
+ case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
+
+ case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
+ case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
+ case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
+ case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
+ case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
+
+ case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
+ case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
+ case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
+
+ case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
+ case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
+
+ default: return RAPIDJSON_ERROR_STRING("Unknown error.");
+ }
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ERROR_EN_H_
diff --git a/external/rapidjson/rapidjson/error/error.h b/external/rapidjson/rapidjson/error/error.h
new file mode 100644
index 0000000..95cb31a
--- /dev/null
+++ b/external/rapidjson/rapidjson/error/error.h
@@ -0,0 +1,155 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_ERROR_H_
+#define RAPIDJSON_ERROR_ERROR_H_
+
+#include "../rapidjson.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+/*! \file error.h */
+
+/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_CHARTYPE
+
+//! Character type of error messages.
+/*! \ingroup RAPIDJSON_ERRORS
+ The default character type is \c char.
+ On Windows, user can define this macro as \c TCHAR for supporting both
+ unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_CHARTYPE
+#define RAPIDJSON_ERROR_CHARTYPE char
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_STRING
+
+//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
+/*! \ingroup RAPIDJSON_ERRORS
+ By default this conversion macro does nothing.
+ On Windows, user can define this macro as \c _T(x) for supporting both
+ unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_STRING
+#define RAPIDJSON_ERROR_STRING(x) x
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseErrorCode
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+ \see GenericReader::Parse, GenericReader::GetParseErrorCode
+*/
+enum ParseErrorCode {
+ kParseErrorNone = 0, //!< No error.
+
+ kParseErrorDocumentEmpty, //!< The document is empty.
+ kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
+
+ kParseErrorValueInvalid, //!< Invalid value.
+
+ kParseErrorObjectMissName, //!< Missing a name for object member.
+ kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
+ kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
+
+ kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
+
+ kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
+ kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
+ kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
+ kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
+ kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
+
+ kParseErrorNumberTooBig, //!< Number too big to be stored in double.
+ kParseErrorNumberMissFraction, //!< Miss fraction part in number.
+ kParseErrorNumberMissExponent, //!< Miss exponent in number.
+
+ kParseErrorTermination, //!< Parsing was terminated.
+ kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
+};
+
+//! Result of parsing (wraps ParseErrorCode)
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \code
+ Document doc;
+ ParseResult ok = doc.Parse("[42]");
+ if (!ok) {
+ fprintf(stderr, "JSON parse error: %s (%u)",
+ GetParseError_En(ok.Code()), ok.Offset());
+ exit(EXIT_FAILURE);
+ }
+ \endcode
+ \see GenericReader::Parse, GenericDocument::Parse
+*/
+struct ParseResult {
+public:
+ //! Default constructor, no error.
+ ParseResult() : code_(kParseErrorNone), offset_(0) {}
+ //! Constructor to set an error.
+ ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
+
+ //! Get the error code.
+ ParseErrorCode Code() const { return code_; }
+ //! Get the error offset, if \ref IsError(), 0 otherwise.
+ size_t Offset() const { return offset_; }
+
+ //! Conversion to \c bool, returns \c true, iff !\ref IsError().
+ operator bool() const { return !IsError(); }
+ //! Whether the result is an error.
+ bool IsError() const { return code_ != kParseErrorNone; }
+
+ bool operator==(const ParseResult& that) const { return code_ == that.code_; }
+ bool operator==(ParseErrorCode code) const { return code_ == code; }
+ friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
+
+ //! Reset error code.
+ void Clear() { Set(kParseErrorNone); }
+ //! Update error code and offset.
+ void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
+
+private:
+ ParseErrorCode code_;
+ size_t offset_;
+};
+
+//! Function pointer type of GetParseError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+ This is the prototype for \c GetParseError_X(), where \c X is a locale.
+ User can dynamically change locale in runtime, e.g.:
+\code
+ GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
+ const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
+\endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ERROR_ERROR_H_
diff --git a/external/rapidjson/rapidjson/filereadstream.h b/external/rapidjson/rapidjson/filereadstream.h
new file mode 100644
index 0000000..b56ea13
--- /dev/null
+++ b/external/rapidjson/rapidjson/filereadstream.h
@@ -0,0 +1,99 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEREADSTREAM_H_
+#define RAPIDJSON_FILEREADSTREAM_H_
+
+#include "stream.h"
+#include <cstdio>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(unreachable-code)
+RAPIDJSON_DIAG_OFF(missing-noreturn)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! File byte stream for input using fread().
+/*!
+ \note implements Stream concept
+*/
+class FileReadStream {
+public:
+ typedef char Ch; //!< Character type (byte).
+
+ //! Constructor.
+ /*!
+ \param fp File pointer opened for read.
+ \param buffer user-supplied buffer.
+ \param bufferSize size of buffer in bytes. Must >=4 bytes.
+ */
+ FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
+ RAPIDJSON_ASSERT(fp_ != 0);
+ RAPIDJSON_ASSERT(bufferSize >= 4);
+ Read();
+ }
+
+ Ch Peek() const { return *current_; }
+ Ch Take() { Ch c = *current_; Read(); return c; }
+ size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
+
+ // Not implemented
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ // For encoding detection only.
+ const Ch* Peek4() const {
+ return (current_ + 4 <= bufferLast_) ? current_ : 0;
+ }
+
+private:
+ void Read() {
+ if (current_ < bufferLast_)
+ ++current_;
+ else if (!eof_) {
+ count_ += readCount_;
+ readCount_ = fread(buffer_, 1, bufferSize_, fp_);
+ bufferLast_ = buffer_ + readCount_ - 1;
+ current_ = buffer_;
+
+ if (readCount_ < bufferSize_) {
+ buffer_[readCount_] = '\0';
+ ++bufferLast_;
+ eof_ = true;
+ }
+ }
+ }
+
+ std::FILE* fp_;
+ Ch *buffer_;
+ size_t bufferSize_;
+ Ch *bufferLast_;
+ Ch *current_;
+ size_t readCount_;
+ size_t count_; //!< Number of characters read
+ bool eof_;
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/external/rapidjson/rapidjson/filewritestream.h b/external/rapidjson/rapidjson/filewritestream.h
new file mode 100644
index 0000000..6378dd6
--- /dev/null
+++ b/external/rapidjson/rapidjson/filewritestream.h
@@ -0,0 +1,104 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEWRITESTREAM_H_
+#define RAPIDJSON_FILEWRITESTREAM_H_
+
+#include "stream.h"
+#include <cstdio>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(unreachable-code)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of C file stream for input using fread().
+/*!
+ \note implements Stream concept
+*/
+class FileWriteStream {
+public:
+ typedef char Ch; //!< Character type. Only support char.
+
+ FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
+ RAPIDJSON_ASSERT(fp_ != 0);
+ }
+
+ void Put(char c) {
+ if (current_ >= bufferEnd_)
+ Flush();
+
+ *current_++ = c;
+ }
+
+ void PutN(char c, size_t n) {
+ size_t avail = static_cast<size_t>(bufferEnd_ - current_);
+ while (n > avail) {
+ std::memset(current_, c, avail);
+ current_ += avail;
+ Flush();
+ n -= avail;
+ avail = static_cast<size_t>(bufferEnd_ - current_);
+ }
+
+ if (n > 0) {
+ std::memset(current_, c, n);
+ current_ += n;
+ }
+ }
+
+ void Flush() {
+ if (current_ != buffer_) {
+ size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
+ if (result < static_cast<size_t>(current_ - buffer_)) {
+ // failure deliberately ignored at this time
+ // added to avoid warn_unused_result build errors
+ }
+ current_ = buffer_;
+ }
+ }
+
+ // Not implemented
+ char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
+ char Take() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+ char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ FileWriteStream(const FileWriteStream&);
+ FileWriteStream& operator=(const FileWriteStream&);
+
+ std::FILE* fp_;
+ char *buffer_;
+ char *bufferEnd_;
+ char *current_;
+};
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(FileWriteStream& stream, char c, size_t n) {
+ stream.PutN(c, n);
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/external/rapidjson/rapidjson/fwd.h b/external/rapidjson/rapidjson/fwd.h
new file mode 100644
index 0000000..e8104e8
--- /dev/null
+++ b/external/rapidjson/rapidjson/fwd.h
@@ -0,0 +1,151 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FWD_H_
+#define RAPIDJSON_FWD_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+// encodings.h
+
+template<typename CharType> struct UTF8;
+template<typename CharType> struct UTF16;
+template<typename CharType> struct UTF16BE;
+template<typename CharType> struct UTF16LE;
+template<typename CharType> struct UTF32;
+template<typename CharType> struct UTF32BE;
+template<typename CharType> struct UTF32LE;
+template<typename CharType> struct ASCII;
+template<typename CharType> struct AutoUTF;
+
+template<typename SourceEncoding, typename TargetEncoding>
+struct Transcoder;
+
+// allocators.h
+
+class CrtAllocator;
+
+template <typename BaseAllocator>
+class MemoryPoolAllocator;
+
+// stream.h
+
+template <typename Encoding>
+struct GenericStringStream;
+
+typedef GenericStringStream<UTF8<char> > StringStream;
+
+template <typename Encoding>
+struct GenericInsituStringStream;
+
+typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
+
+// stringbuffer.h
+
+template <typename Encoding, typename Allocator>
+class GenericStringBuffer;
+
+typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
+
+// filereadstream.h
+
+class FileReadStream;
+
+// filewritestream.h
+
+class FileWriteStream;
+
+// memorybuffer.h
+
+template <typename Allocator>
+struct GenericMemoryBuffer;
+
+typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
+
+// memorystream.h
+
+struct MemoryStream;
+
+// reader.h
+
+template<typename Encoding, typename Derived>
+struct BaseReaderHandler;
+
+template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
+class GenericReader;
+
+typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
+
+// writer.h
+
+template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
+class Writer;
+
+// prettywriter.h
+
+template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
+class PrettyWriter;
+
+// document.h
+
+template <typename Encoding, typename Allocator>
+struct GenericMember;
+
+template <bool Const, typename Encoding, typename Allocator>
+class GenericMemberIterator;
+
+template<typename CharType>
+struct GenericStringRef;
+
+template <typename Encoding, typename Allocator>
+class GenericValue;
+
+typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
+
+template <typename Encoding, typename Allocator, typename StackAllocator>
+class GenericDocument;
+
+typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
+
+// pointer.h
+
+template <typename ValueType, typename Allocator>
+class GenericPointer;
+
+typedef GenericPointer<Value, CrtAllocator> Pointer;
+
+// schema.h
+
+template <typename SchemaDocumentType>
+class IGenericRemoteSchemaDocumentProvider;
+
+template <typename ValueT, typename Allocator>
+class GenericSchemaDocument;
+
+typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
+typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
+
+template <
+ typename SchemaDocumentType,
+ typename OutputHandler,
+ typename StateAllocator>
+class GenericSchemaValidator;
+
+typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_RAPIDJSONFWD_H_
diff --git a/external/rapidjson/rapidjson/internal/biginteger.h b/external/rapidjson/rapidjson/internal/biginteger.h
new file mode 100644
index 0000000..9d3e88c
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/biginteger.h
@@ -0,0 +1,290 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_BIGINTEGER_H_
+#define RAPIDJSON_BIGINTEGER_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h> // for _umul128
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class BigInteger {
+public:
+ typedef uint64_t Type;
+
+ BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
+ std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+ }
+
+ explicit BigInteger(uint64_t u) : count_(1) {
+ digits_[0] = u;
+ }
+
+ BigInteger(const char* decimals, size_t length) : count_(1) {
+ RAPIDJSON_ASSERT(length > 0);
+ digits_[0] = 0;
+ size_t i = 0;
+ const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
+ while (length >= kMaxDigitPerIteration) {
+ AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
+ length -= kMaxDigitPerIteration;
+ i += kMaxDigitPerIteration;
+ }
+
+ if (length > 0)
+ AppendDecimal64(decimals + i, decimals + i + length);
+ }
+
+ BigInteger& operator=(const BigInteger &rhs)
+ {
+ if (this != &rhs) {
+ count_ = rhs.count_;
+ std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+ }
+ return *this;
+ }
+
+ BigInteger& operator=(uint64_t u) {
+ digits_[0] = u;
+ count_ = 1;
+ return *this;
+ }
+
+ BigInteger& operator+=(uint64_t u) {
+ Type backup = digits_[0];
+ digits_[0] += u;
+ for (size_t i = 0; i < count_ - 1; i++) {
+ if (digits_[i] >= backup)
+ return *this; // no carry
+ backup = digits_[i + 1];
+ digits_[i + 1] += 1;
+ }
+
+ // Last carry
+ if (digits_[count_ - 1] < backup)
+ PushBack(1);
+
+ return *this;
+ }
+
+ BigInteger& operator*=(uint64_t u) {
+ if (u == 0) return *this = 0;
+ if (u == 1) return *this;
+ if (*this == 1) return *this = u;
+
+ uint64_t k = 0;
+ for (size_t i = 0; i < count_; i++) {
+ uint64_t hi;
+ digits_[i] = MulAdd64(digits_[i], u, k, &hi);
+ k = hi;
+ }
+
+ if (k > 0)
+ PushBack(k);
+
+ return *this;
+ }
+
+ BigInteger& operator*=(uint32_t u) {
+ if (u == 0) return *this = 0;
+ if (u == 1) return *this;
+ if (*this == 1) return *this = u;
+
+ uint64_t k = 0;
+ for (size_t i = 0; i < count_; i++) {
+ const uint64_t c = digits_[i] >> 32;
+ const uint64_t d = digits_[i] & 0xFFFFFFFF;
+ const uint64_t uc = u * c;
+ const uint64_t ud = u * d;
+ const uint64_t p0 = ud + k;
+ const uint64_t p1 = uc + (p0 >> 32);
+ digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
+ k = p1 >> 32;
+ }
+
+ if (k > 0)
+ PushBack(k);
+
+ return *this;
+ }
+
+ BigInteger& operator<<=(size_t shift) {
+ if (IsZero() || shift == 0) return *this;
+
+ size_t offset = shift / kTypeBit;
+ size_t interShift = shift % kTypeBit;
+ RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
+
+ if (interShift == 0) {
+ std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
+ count_ += offset;
+ }
+ else {
+ digits_[count_] = 0;
+ for (size_t i = count_; i > 0; i--)
+ digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
+ digits_[offset] = digits_[0] << interShift;
+ count_ += offset;
+ if (digits_[count_])
+ count_++;
+ }
+
+ std::memset(digits_, 0, offset * sizeof(Type));
+
+ return *this;
+ }
+
+ bool operator==(const BigInteger& rhs) const {
+ return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
+ }
+
+ bool operator==(const Type rhs) const {
+ return count_ == 1 && digits_[0] == rhs;
+ }
+
+ BigInteger& MultiplyPow5(unsigned exp) {
+ static const uint32_t kPow5[12] = {
+ 5,
+ 5 * 5,
+ 5 * 5 * 5,
+ 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
+ };
+ if (exp == 0) return *this;
+ for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
+ for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
+ if (exp > 0) *this *= kPow5[exp - 1];
+ return *this;
+ }
+
+ // Compute absolute difference of this and rhs.
+ // Assume this != rhs
+ bool Difference(const BigInteger& rhs, BigInteger* out) const {
+ int cmp = Compare(rhs);
+ RAPIDJSON_ASSERT(cmp != 0);
+ const BigInteger *a, *b; // Makes a > b
+ bool ret;
+ if (cmp < 0) { a = &rhs; b = this; ret = true; }
+ else { a = this; b = &rhs; ret = false; }
+
+ Type borrow = 0;
+ for (size_t i = 0; i < a->count_; i++) {
+ Type d = a->digits_[i] - borrow;
+ if (i < b->count_)
+ d -= b->digits_[i];
+ borrow = (d > a->digits_[i]) ? 1 : 0;
+ out->digits_[i] = d;
+ if (d != 0)
+ out->count_ = i + 1;
+ }
+
+ return ret;
+ }
+
+ int Compare(const BigInteger& rhs) const {
+ if (count_ != rhs.count_)
+ return count_ < rhs.count_ ? -1 : 1;
+
+ for (size_t i = count_; i-- > 0;)
+ if (digits_[i] != rhs.digits_[i])
+ return digits_[i] < rhs.digits_[i] ? -1 : 1;
+
+ return 0;
+ }
+
+ size_t GetCount() const { return count_; }
+ Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
+ bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
+
+private:
+ void AppendDecimal64(const char* begin, const char* end) {
+ uint64_t u = ParseUint64(begin, end);
+ if (IsZero())
+ *this = u;
+ else {
+ unsigned exp = static_cast<unsigned>(end - begin);
+ (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
+ }
+ }
+
+ void PushBack(Type digit) {
+ RAPIDJSON_ASSERT(count_ < kCapacity);
+ digits_[count_++] = digit;
+ }
+
+ static uint64_t ParseUint64(const char* begin, const char* end) {
+ uint64_t r = 0;
+ for (const char* p = begin; p != end; ++p) {
+ RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
+ r = r * 10u + static_cast<unsigned>(*p - '0');
+ }
+ return r;
+ }
+
+ // Assume a * b + k < 2^128
+ static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ uint64_t low = _umul128(a, b, outHigh) + k;
+ if (low < k)
+ (*outHigh)++;
+ return low;
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+ __extension__ typedef unsigned __int128 uint128;
+ uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
+ p += k;
+ *outHigh = static_cast<uint64_t>(p >> 64);
+ return static_cast<uint64_t>(p);
+#else
+ const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
+ uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
+ x1 += (x0 >> 32); // can't give carry
+ x1 += x2;
+ if (x1 < x2)
+ x3 += (static_cast<uint64_t>(1) << 32);
+ uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
+ uint64_t hi = x3 + (x1 >> 32);
+
+ lo += k;
+ if (lo < k)
+ hi++;
+ *outHigh = hi;
+ return lo;
+#endif
+ }
+
+ static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
+ static const size_t kCapacity = kBitCount / sizeof(Type);
+ static const size_t kTypeBit = sizeof(Type) * 8;
+
+ Type digits_[kCapacity];
+ size_t count_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_BIGINTEGER_H_
diff --git a/external/rapidjson/rapidjson/internal/diyfp.h b/external/rapidjson/rapidjson/internal/diyfp.h
new file mode 100644
index 0000000..c9fefdc
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/diyfp.h
@@ -0,0 +1,258 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DIYFP_H_
+#define RAPIDJSON_DIYFP_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse64)
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+struct DiyFp {
+ DiyFp() : f(), e() {}
+
+ DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
+
+ explicit DiyFp(double d) {
+ union {
+ double d;
+ uint64_t u64;
+ } u = { d };
+
+ int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
+ uint64_t significand = (u.u64 & kDpSignificandMask);
+ if (biased_e != 0) {
+ f = significand + kDpHiddenBit;
+ e = biased_e - kDpExponentBias;
+ }
+ else {
+ f = significand;
+ e = kDpMinExponent + 1;
+ }
+ }
+
+ DiyFp operator-(const DiyFp& rhs) const {
+ return DiyFp(f - rhs.f, e);
+ }
+
+ DiyFp operator*(const DiyFp& rhs) const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ uint64_t h;
+ uint64_t l = _umul128(f, rhs.f, &h);
+ if (l & (uint64_t(1) << 63)) // rounding
+ h++;
+ return DiyFp(h, e + rhs.e + 64);
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+ __extension__ typedef unsigned __int128 uint128;
+ uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
+ uint64_t h = static_cast<uint64_t>(p >> 64);
+ uint64_t l = static_cast<uint64_t>(p);
+ if (l & (uint64_t(1) << 63)) // rounding
+ h++;
+ return DiyFp(h, e + rhs.e + 64);
+#else
+ const uint64_t M32 = 0xFFFFFFFF;
+ const uint64_t a = f >> 32;
+ const uint64_t b = f & M32;
+ const uint64_t c = rhs.f >> 32;
+ const uint64_t d = rhs.f & M32;
+ const uint64_t ac = a * c;
+ const uint64_t bc = b * c;
+ const uint64_t ad = a * d;
+ const uint64_t bd = b * d;
+ uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
+ tmp += 1U << 31; /// mult_round
+ return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
+#endif
+ }
+
+ DiyFp Normalize() const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ unsigned long index;
+ _BitScanReverse64(&index, f);
+ return DiyFp(f << (63 - index), e - (63 - index));
+#elif defined(__GNUC__) && __GNUC__ >= 4
+ int s = __builtin_clzll(f);
+ return DiyFp(f << s, e - s);
+#else
+ DiyFp res = *this;
+ while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
+ res.f <<= 1;
+ res.e--;
+ }
+ return res;
+#endif
+ }
+
+ DiyFp NormalizeBoundary() const {
+ DiyFp res = *this;
+ while (!(res.f & (kDpHiddenBit << 1))) {
+ res.f <<= 1;
+ res.e--;
+ }
+ res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
+ res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
+ return res;
+ }
+
+ void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
+ DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
+ DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
+ mi.f <<= mi.e - pl.e;
+ mi.e = pl.e;
+ *plus = pl;
+ *minus = mi;
+ }
+
+ double ToDouble() const {
+ union {
+ double d;
+ uint64_t u64;
+ }u;
+ const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
+ static_cast<uint64_t>(e + kDpExponentBias);
+ u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
+ return u.d;
+ }
+
+ static const int kDiySignificandSize = 64;
+ static const int kDpSignificandSize = 52;
+ static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
+ static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
+ static const int kDpMinExponent = -kDpExponentBias;
+ static const int kDpDenormalExponent = -kDpExponentBias + 1;
+ static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+ static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+ static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+ uint64_t f;
+ int e;
+};
+
+inline DiyFp GetCachedPowerByIndex(size_t index) {
+ // 10^-348, 10^-340, ..., 10^340
+ static const uint64_t kCachedPowers_F[] = {
+ RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
+ RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
+ RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
+ RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
+ RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
+ RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
+ RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
+ RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
+ RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
+ RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
+ RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
+ RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
+ RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
+ RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
+ RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
+ RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
+ RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
+ RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
+ RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
+ RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
+ RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
+ RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
+ RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
+ RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
+ RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
+ RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
+ RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
+ RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
+ RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
+ RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
+ RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
+ RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
+ RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
+ RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
+ RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
+ RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
+ RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
+ RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
+ RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
+ RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
+ RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
+ RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
+ RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
+ RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
+ };
+ static const int16_t kCachedPowers_E[] = {
+ -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
+ -954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
+ -688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
+ -422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
+ -157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
+ 109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
+ 375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
+ 641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
+ 907, 933, 960, 986, 1013, 1039, 1066
+ };
+ return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
+}
+
+inline DiyFp GetCachedPower(int e, int* K) {
+
+ //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
+ double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
+ int k = static_cast<int>(dk);
+ if (dk - k > 0.0)
+ k++;
+
+ unsigned index = static_cast<unsigned>((k >> 3) + 1);
+ *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
+
+ return GetCachedPowerByIndex(index);
+}
+
+inline DiyFp GetCachedPower10(int exp, int *outExp) {
+ unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
+ *outExp = -348 + static_cast<int>(index) * 8;
+ return GetCachedPowerByIndex(index);
+ }
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DIYFP_H_
diff --git a/external/rapidjson/rapidjson/internal/dtoa.h b/external/rapidjson/rapidjson/internal/dtoa.h
new file mode 100644
index 0000000..8d6350e
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/dtoa.h
@@ -0,0 +1,245 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DTOA_
+#define RAPIDJSON_DTOA_
+
+#include "itoa.h" // GetDigitsLut()
+#include "diyfp.h"
+#include "ieee754.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
+#endif
+
+inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
+ while (rest < wp_w && delta - rest >= ten_kappa &&
+ (rest + ten_kappa < wp_w || /// closer
+ wp_w - rest > rest + ten_kappa - wp_w)) {
+ buffer[len - 1]--;
+ rest += ten_kappa;
+ }
+}
+
+inline unsigned CountDecimalDigit32(uint32_t n) {
+ // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
+ if (n < 10) return 1;
+ if (n < 100) return 2;
+ if (n < 1000) return 3;
+ if (n < 10000) return 4;
+ if (n < 100000) return 5;
+ if (n < 1000000) return 6;
+ if (n < 10000000) return 7;
+ if (n < 100000000) return 8;
+ // Will not reach 10 digits in DigitGen()
+ //if (n < 1000000000) return 9;
+ //return 10;
+ return 9;
+}
+
+inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
+ static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+ const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
+ const DiyFp wp_w = Mp - W;
+ uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
+ uint64_t p2 = Mp.f & (one.f - 1);
+ unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
+ *len = 0;
+
+ while (kappa > 0) {
+ uint32_t d = 0;
+ switch (kappa) {
+ case 9: d = p1 / 100000000; p1 %= 100000000; break;
+ case 8: d = p1 / 10000000; p1 %= 10000000; break;
+ case 7: d = p1 / 1000000; p1 %= 1000000; break;
+ case 6: d = p1 / 100000; p1 %= 100000; break;
+ case 5: d = p1 / 10000; p1 %= 10000; break;
+ case 4: d = p1 / 1000; p1 %= 1000; break;
+ case 3: d = p1 / 100; p1 %= 100; break;
+ case 2: d = p1 / 10; p1 %= 10; break;
+ case 1: d = p1; p1 = 0; break;
+ default:;
+ }
+ if (d || *len)
+ buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
+ kappa--;
+ uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
+ if (tmp <= delta) {
+ *K += kappa;
+ GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
+ return;
+ }
+ }
+
+ // kappa = 0
+ for (;;) {
+ p2 *= 10;
+ delta *= 10;
+ char d = static_cast<char>(p2 >> -one.e);
+ if (d || *len)
+ buffer[(*len)++] = static_cast<char>('0' + d);
+ p2 &= one.f - 1;
+ kappa--;
+ if (p2 < delta) {
+ *K += kappa;
+ int index = -static_cast<int>(kappa);
+ GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0));
+ return;
+ }
+ }
+}
+
+inline void Grisu2(double value, char* buffer, int* length, int* K) {
+ const DiyFp v(value);
+ DiyFp w_m, w_p;
+ v.NormalizedBoundaries(&w_m, &w_p);
+
+ const DiyFp c_mk = GetCachedPower(w_p.e, K);
+ const DiyFp W = v.Normalize() * c_mk;
+ DiyFp Wp = w_p * c_mk;
+ DiyFp Wm = w_m * c_mk;
+ Wm.f++;
+ Wp.f--;
+ DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
+}
+
+inline char* WriteExponent(int K, char* buffer) {
+ if (K < 0) {
+ *buffer++ = '-';
+ K = -K;
+ }
+
+ if (K >= 100) {
+ *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
+ K %= 100;
+ const char* d = GetDigitsLut() + K * 2;
+ *buffer++ = d[0];
+ *buffer++ = d[1];
+ }
+ else if (K >= 10) {
+ const char* d = GetDigitsLut() + K * 2;
+ *buffer++ = d[0];
+ *buffer++ = d[1];
+ }
+ else
+ *buffer++ = static_cast<char>('0' + static_cast<char>(K));
+
+ return buffer;
+}
+
+inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
+ const int kk = length + k; // 10^(kk-1) <= v < 10^kk
+
+ if (0 <= k && kk <= 21) {
+ // 1234e7 -> 12340000000
+ for (int i = length; i < kk; i++)
+ buffer[i] = '0';
+ buffer[kk] = '.';
+ buffer[kk + 1] = '0';
+ return &buffer[kk + 2];
+ }
+ else if (0 < kk && kk <= 21) {
+ // 1234e-2 -> 12.34
+ std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
+ buffer[kk] = '.';
+ if (0 > k + maxDecimalPlaces) {
+ // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
+ // Remove extra trailing zeros (at least one) after truncation.
+ for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
+ if (buffer[i] != '0')
+ return &buffer[i + 1];
+ return &buffer[kk + 2]; // Reserve one zero
+ }
+ else
+ return &buffer[length + 1];
+ }
+ else if (-6 < kk && kk <= 0) {
+ // 1234e-6 -> 0.001234
+ const int offset = 2 - kk;
+ std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
+ buffer[0] = '0';
+ buffer[1] = '.';
+ for (int i = 2; i < offset; i++)
+ buffer[i] = '0';
+ if (length - kk > maxDecimalPlaces) {
+ // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
+ // Remove extra trailing zeros (at least one) after truncation.
+ for (int i = maxDecimalPlaces + 1; i > 2; i--)
+ if (buffer[i] != '0')
+ return &buffer[i + 1];
+ return &buffer[3]; // Reserve one zero
+ }
+ else
+ return &buffer[length + offset];
+ }
+ else if (kk < -maxDecimalPlaces) {
+ // Truncate to zero
+ buffer[0] = '0';
+ buffer[1] = '.';
+ buffer[2] = '0';
+ return &buffer[3];
+ }
+ else if (length == 1) {
+ // 1e30
+ buffer[1] = 'e';
+ return WriteExponent(kk - 1, &buffer[2]);
+ }
+ else {
+ // 1234e30 -> 1.234e33
+ std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
+ buffer[1] = '.';
+ buffer[length + 1] = 'e';
+ return WriteExponent(kk - 1, &buffer[0 + length + 2]);
+ }
+}
+
+inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
+ RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
+ Double d(value);
+ if (d.IsZero()) {
+ if (d.Sign())
+ *buffer++ = '-'; // -0.0, Issue #289
+ buffer[0] = '0';
+ buffer[1] = '.';
+ buffer[2] = '0';
+ return &buffer[3];
+ }
+ else {
+ if (value < 0) {
+ *buffer++ = '-';
+ value = -value;
+ }
+ int length, K;
+ Grisu2(value, buffer, &length, &K);
+ return Prettify(buffer, length, K, maxDecimalPlaces);
+ }
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DTOA_
diff --git a/external/rapidjson/rapidjson/internal/ieee754.h b/external/rapidjson/rapidjson/internal/ieee754.h
new file mode 100644
index 0000000..82bb0b9
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/ieee754.h
@@ -0,0 +1,78 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_IEEE754_
+#define RAPIDJSON_IEEE754_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class Double {
+public:
+ Double() {}
+ Double(double d) : d_(d) {}
+ Double(uint64_t u) : u_(u) {}
+
+ double Value() const { return d_; }
+ uint64_t Uint64Value() const { return u_; }
+
+ double NextPositiveDouble() const {
+ RAPIDJSON_ASSERT(!Sign());
+ return Double(u_ + 1).Value();
+ }
+
+ bool Sign() const { return (u_ & kSignMask) != 0; }
+ uint64_t Significand() const { return u_ & kSignificandMask; }
+ int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
+
+ bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
+ bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
+ bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
+ bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
+ bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
+
+ uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
+ int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
+ uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
+
+ static unsigned EffectiveSignificandSize(int order) {
+ if (order >= -1021)
+ return 53;
+ else if (order <= -1074)
+ return 0;
+ else
+ return static_cast<unsigned>(order) + 1074;
+ }
+
+private:
+ static const int kSignificandSize = 52;
+ static const int kExponentBias = 0x3FF;
+ static const int kDenormalExponent = 1 - kExponentBias;
+ static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
+ static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+ static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+ static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+ union {
+ double d_;
+ uint64_t u_;
+ };
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_IEEE754_
diff --git a/external/rapidjson/rapidjson/internal/itoa.h b/external/rapidjson/rapidjson/internal/itoa.h
new file mode 100644
index 0000000..01a4e7e
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/itoa.h
@@ -0,0 +1,304 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ITOA_
+#define RAPIDJSON_ITOA_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline const char* GetDigitsLut() {
+ static const char cDigitsLut[200] = {
+ '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
+ '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
+ '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
+ '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
+ '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
+ '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
+ '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
+ '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
+ '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
+ '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
+ };
+ return cDigitsLut;
+}
+
+inline char* u32toa(uint32_t value, char* buffer) {
+ const char* cDigitsLut = GetDigitsLut();
+
+ if (value < 10000) {
+ const uint32_t d1 = (value / 100) << 1;
+ const uint32_t d2 = (value % 100) << 1;
+
+ if (value >= 1000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 100)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 10)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ }
+ else if (value < 100000000) {
+ // value = bbbbcccc
+ const uint32_t b = value / 10000;
+ const uint32_t c = value % 10000;
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ if (value >= 10000000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 1000000)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 100000)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ }
+ else {
+ // value = aabbbbcccc in decimal
+
+ const uint32_t a = value / 100000000; // 1 to 42
+ value %= 100000000;
+
+ if (a >= 10) {
+ const unsigned i = a << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ }
+ else
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+
+ const uint32_t b = value / 10000; // 0 to 9999
+ const uint32_t c = value % 10000; // 0 to 9999
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ *buffer++ = cDigitsLut[d1];
+ *buffer++ = cDigitsLut[d1 + 1];
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ }
+ return buffer;
+}
+
+inline char* i32toa(int32_t value, char* buffer) {
+ uint32_t u = static_cast<uint32_t>(value);
+ if (value < 0) {
+ *buffer++ = '-';
+ u = ~u + 1;
+ }
+
+ return u32toa(u, buffer);
+}
+
+inline char* u64toa(uint64_t value, char* buffer) {
+ const char* cDigitsLut = GetDigitsLut();
+ const uint64_t kTen8 = 100000000;
+ const uint64_t kTen9 = kTen8 * 10;
+ const uint64_t kTen10 = kTen8 * 100;
+ const uint64_t kTen11 = kTen8 * 1000;
+ const uint64_t kTen12 = kTen8 * 10000;
+ const uint64_t kTen13 = kTen8 * 100000;
+ const uint64_t kTen14 = kTen8 * 1000000;
+ const uint64_t kTen15 = kTen8 * 10000000;
+ const uint64_t kTen16 = kTen8 * kTen8;
+
+ if (value < kTen8) {
+ uint32_t v = static_cast<uint32_t>(value);
+ if (v < 10000) {
+ const uint32_t d1 = (v / 100) << 1;
+ const uint32_t d2 = (v % 100) << 1;
+
+ if (v >= 1000)
+ *buffer++ = cDigitsLut[d1];
+ if (v >= 100)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (v >= 10)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ }
+ else {
+ // value = bbbbcccc
+ const uint32_t b = v / 10000;
+ const uint32_t c = v % 10000;
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ if (value >= 10000000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 1000000)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 100000)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ }
+ }
+ else if (value < kTen16) {
+ const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+ const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+ const uint32_t b0 = v0 / 10000;
+ const uint32_t c0 = v0 % 10000;
+
+ const uint32_t d1 = (b0 / 100) << 1;
+ const uint32_t d2 = (b0 % 100) << 1;
+
+ const uint32_t d3 = (c0 / 100) << 1;
+ const uint32_t d4 = (c0 % 100) << 1;
+
+ const uint32_t b1 = v1 / 10000;
+ const uint32_t c1 = v1 % 10000;
+
+ const uint32_t d5 = (b1 / 100) << 1;
+ const uint32_t d6 = (b1 % 100) << 1;
+
+ const uint32_t d7 = (c1 / 100) << 1;
+ const uint32_t d8 = (c1 % 100) << 1;
+
+ if (value >= kTen15)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= kTen14)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= kTen13)
+ *buffer++ = cDigitsLut[d2];
+ if (value >= kTen12)
+ *buffer++ = cDigitsLut[d2 + 1];
+ if (value >= kTen11)
+ *buffer++ = cDigitsLut[d3];
+ if (value >= kTen10)
+ *buffer++ = cDigitsLut[d3 + 1];
+ if (value >= kTen9)
+ *buffer++ = cDigitsLut[d4];
+ if (value >= kTen8)
+ *buffer++ = cDigitsLut[d4 + 1];
+
+ *buffer++ = cDigitsLut[d5];
+ *buffer++ = cDigitsLut[d5 + 1];
+ *buffer++ = cDigitsLut[d6];
+ *buffer++ = cDigitsLut[d6 + 1];
+ *buffer++ = cDigitsLut[d7];
+ *buffer++ = cDigitsLut[d7 + 1];
+ *buffer++ = cDigitsLut[d8];
+ *buffer++ = cDigitsLut[d8 + 1];
+ }
+ else {
+ const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
+ value %= kTen16;
+
+ if (a < 10)
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+ else if (a < 100) {
+ const uint32_t i = a << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ }
+ else if (a < 1000) {
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
+
+ const uint32_t i = (a % 100) << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ }
+ else {
+ const uint32_t i = (a / 100) << 1;
+ const uint32_t j = (a % 100) << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ *buffer++ = cDigitsLut[j];
+ *buffer++ = cDigitsLut[j + 1];
+ }
+
+ const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+ const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+ const uint32_t b0 = v0 / 10000;
+ const uint32_t c0 = v0 % 10000;
+
+ const uint32_t d1 = (b0 / 100) << 1;
+ const uint32_t d2 = (b0 % 100) << 1;
+
+ const uint32_t d3 = (c0 / 100) << 1;
+ const uint32_t d4 = (c0 % 100) << 1;
+
+ const uint32_t b1 = v1 / 10000;
+ const uint32_t c1 = v1 % 10000;
+
+ const uint32_t d5 = (b1 / 100) << 1;
+ const uint32_t d6 = (b1 % 100) << 1;
+
+ const uint32_t d7 = (c1 / 100) << 1;
+ const uint32_t d8 = (c1 % 100) << 1;
+
+ *buffer++ = cDigitsLut[d1];
+ *buffer++ = cDigitsLut[d1 + 1];
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ *buffer++ = cDigitsLut[d5];
+ *buffer++ = cDigitsLut[d5 + 1];
+ *buffer++ = cDigitsLut[d6];
+ *buffer++ = cDigitsLut[d6 + 1];
+ *buffer++ = cDigitsLut[d7];
+ *buffer++ = cDigitsLut[d7 + 1];
+ *buffer++ = cDigitsLut[d8];
+ *buffer++ = cDigitsLut[d8 + 1];
+ }
+
+ return buffer;
+}
+
+inline char* i64toa(int64_t value, char* buffer) {
+ uint64_t u = static_cast<uint64_t>(value);
+ if (value < 0) {
+ *buffer++ = '-';
+ u = ~u + 1;
+ }
+
+ return u64toa(u, buffer);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ITOA_
diff --git a/external/rapidjson/rapidjson/internal/meta.h b/external/rapidjson/rapidjson/internal/meta.h
new file mode 100644
index 0000000..5a9aaa4
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/meta.h
@@ -0,0 +1,181 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_META_H_
+#define RAPIDJSON_INTERNAL_META_H_
+
+#include "../rapidjson.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+#if defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(6334)
+#endif
+
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+#include <type_traits>
+#endif
+
+//@cond RAPIDJSON_INTERNAL
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
+template <typename T> struct Void { typedef void Type; };
+
+///////////////////////////////////////////////////////////////////////////////
+// BoolType, TrueType, FalseType
+//
+template <bool Cond> struct BoolType {
+ static const bool Value = Cond;
+ typedef BoolType Type;
+};
+typedef BoolType<true> TrueType;
+typedef BoolType<false> FalseType;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
+//
+
+template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
+template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
+template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
+template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
+
+template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
+template <> struct AndExprCond<true, true> : TrueType {};
+template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
+template <> struct OrExprCond<false, false> : FalseType {};
+
+template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
+template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
+template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
+template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// AddConst, MaybeAddConst, RemoveConst
+template <typename T> struct AddConst { typedef const T Type; };
+template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
+template <typename T> struct RemoveConst { typedef T Type; };
+template <typename T> struct RemoveConst<const T> { typedef T Type; };
+
+
+///////////////////////////////////////////////////////////////////////////////
+// IsSame, IsConst, IsMoreConst, IsPointer
+//
+template <typename T, typename U> struct IsSame : FalseType {};
+template <typename T> struct IsSame<T, T> : TrueType {};
+
+template <typename T> struct IsConst : FalseType {};
+template <typename T> struct IsConst<const T> : TrueType {};
+
+template <typename CT, typename T>
+struct IsMoreConst
+ : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
+ BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
+
+template <typename T> struct IsPointer : FalseType {};
+template <typename T> struct IsPointer<T*> : TrueType {};
+
+///////////////////////////////////////////////////////////////////////////////
+// IsBaseOf
+//
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+template <typename B, typename D> struct IsBaseOf
+ : BoolType< ::std::is_base_of<B,D>::value> {};
+
+#else // simplified version adopted from Boost
+
+template<typename B, typename D> struct IsBaseOfImpl {
+ RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
+ RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
+
+ typedef char (&Yes)[1];
+ typedef char (&No) [2];
+
+ template <typename T>
+ static Yes Check(const D*, T);
+ static No Check(const B*, int);
+
+ struct Host {
+ operator const B*() const;
+ operator const D*();
+ };
+
+ enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
+};
+
+template <typename B, typename D> struct IsBaseOf
+ : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
+
+#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+
+//////////////////////////////////////////////////////////////////////////
+// EnableIf / DisableIf
+//
+template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
+template <typename T> struct EnableIfCond<false, T> { /* empty */ };
+
+template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
+template <typename T> struct DisableIfCond<true, T> { /* empty */ };
+
+template <typename Condition, typename T = void>
+struct EnableIf : EnableIfCond<Condition::Value, T> {};
+
+template <typename Condition, typename T = void>
+struct DisableIf : DisableIfCond<Condition::Value, T> {};
+
+// SFINAE helpers
+struct SfinaeTag {};
+template <typename T> struct RemoveSfinaeTag;
+template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
+
+#define RAPIDJSON_REMOVEFPTR_(type) \
+ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
+ < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
+
+#define RAPIDJSON_ENABLEIF(cond) \
+ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_DISABLEIF(cond) \
+ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
+ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond), \
+ RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
+ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond), \
+ RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+//@endcond
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_META_H_
diff --git a/external/rapidjson/rapidjson/internal/pow10.h b/external/rapidjson/rapidjson/internal/pow10.h
new file mode 100644
index 0000000..02f475d
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/pow10.h
@@ -0,0 +1,55 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_POW10_
+#define RAPIDJSON_POW10_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Computes integer powers of 10 in double (10.0^n).
+/*! This function uses lookup table for fast and accurate results.
+ \param n non-negative exponent. Must <= 308.
+ \return 10.0^n
+*/
+inline double Pow10(int n) {
+ static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
+ 1e+0,
+ 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
+ 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
+ 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
+ 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+ 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
+ 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
+ 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
+ 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
+ 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
+ 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
+ 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
+ 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
+ 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
+ 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
+ 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
+ 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
+ };
+ RAPIDJSON_ASSERT(n >= 0 && n <= 308);
+ return e[n];
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_POW10_
diff --git a/external/rapidjson/rapidjson/internal/regex.h b/external/rapidjson/rapidjson/internal/regex.h
new file mode 100644
index 0000000..8530cd7
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/regex.h
@@ -0,0 +1,731 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_REGEX_H_
+#define RAPIDJSON_INTERNAL_REGEX_H_
+
+#include "../allocators.h"
+#include "../stream.h"
+#include "stack.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(implicit-fallthrough)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+#ifndef RAPIDJSON_REGEX_VERBOSE
+#define RAPIDJSON_REGEX_VERBOSE 0
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// DecodedStream
+
+template <typename SourceStream, typename Encoding>
+class DecodedStream {
+public:
+ DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
+ unsigned Peek() { return codepoint_; }
+ unsigned Take() {
+ unsigned c = codepoint_;
+ if (c) // No further decoding when '\0'
+ Decode();
+ return c;
+ }
+
+private:
+ void Decode() {
+ if (!Encoding::Decode(ss_, &codepoint_))
+ codepoint_ = 0;
+ }
+
+ SourceStream& ss_;
+ unsigned codepoint_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericRegex
+
+static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
+static const SizeType kRegexInvalidRange = ~SizeType(0);
+
+template <typename Encoding, typename Allocator>
+class GenericRegexSearch;
+
+//! Regular expression engine with subset of ECMAscript grammar.
+/*!
+ Supported regular expression syntax:
+ - \c ab Concatenation
+ - \c a|b Alternation
+ - \c a? Zero or one
+ - \c a* Zero or more
+ - \c a+ One or more
+ - \c a{3} Exactly 3 times
+ - \c a{3,} At least 3 times
+ - \c a{3,5} 3 to 5 times
+ - \c (ab) Grouping
+ - \c ^a At the beginning
+ - \c a$ At the end
+ - \c . Any character
+ - \c [abc] Character classes
+ - \c [a-c] Character class range
+ - \c [a-z0-9_] Character class combination
+ - \c [^abc] Negated character classes
+ - \c [^a-c] Negated character class range
+ - \c [\b] Backspace (U+0008)
+ - \c \\| \\\\ ... Escape characters
+ - \c \\f Form feed (U+000C)
+ - \c \\n Line feed (U+000A)
+ - \c \\r Carriage return (U+000D)
+ - \c \\t Tab (U+0009)
+ - \c \\v Vertical tab (U+000B)
+
+ \note This is a Thompson NFA engine, implemented with reference to
+ Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
+ https://swtch.com/~rsc/regexp/regexp1.html
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+class GenericRegex {
+public:
+ typedef Encoding EncodingType;
+ typedef typename Encoding::Ch Ch;
+ template <typename, typename> friend class GenericRegexSearch;
+
+ GenericRegex(const Ch* source, Allocator* allocator = 0) :
+ states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
+ anchorBegin_(), anchorEnd_()
+ {
+ GenericStringStream<Encoding> ss(source);
+ DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
+ Parse(ds);
+ }
+
+ ~GenericRegex() {}
+
+ bool IsValid() const {
+ return root_ != kRegexInvalidState;
+ }
+
+private:
+ enum Operator {
+ kZeroOrOne,
+ kZeroOrMore,
+ kOneOrMore,
+ kConcatenation,
+ kAlternation,
+ kLeftParenthesis
+ };
+
+ static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
+ static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
+ static const unsigned kRangeNegationFlag = 0x80000000;
+
+ struct Range {
+ unsigned start; //
+ unsigned end;
+ SizeType next;
+ };
+
+ struct State {
+ SizeType out; //!< Equals to kInvalid for matching state
+ SizeType out1; //!< Equals to non-kInvalid for split
+ SizeType rangeStart;
+ unsigned codepoint;
+ };
+
+ struct Frag {
+ Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
+ SizeType start;
+ SizeType out; //!< link-list of all output states
+ SizeType minIndex;
+ };
+
+ State& GetState(SizeType index) {
+ RAPIDJSON_ASSERT(index < stateCount_);
+ return states_.template Bottom<State>()[index];
+ }
+
+ const State& GetState(SizeType index) const {
+ RAPIDJSON_ASSERT(index < stateCount_);
+ return states_.template Bottom<State>()[index];
+ }
+
+ Range& GetRange(SizeType index) {
+ RAPIDJSON_ASSERT(index < rangeCount_);
+ return ranges_.template Bottom<Range>()[index];
+ }
+
+ const Range& GetRange(SizeType index) const {
+ RAPIDJSON_ASSERT(index < rangeCount_);
+ return ranges_.template Bottom<Range>()[index];
+ }
+
+ template <typename InputStream>
+ void Parse(DecodedStream<InputStream, Encoding>& ds) {
+ Allocator allocator;
+ Stack<Allocator> operandStack(&allocator, 256); // Frag
+ Stack<Allocator> operatorStack(&allocator, 256); // Operator
+ Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
+
+ *atomCountStack.template Push<unsigned>() = 0;
+
+ unsigned codepoint;
+ while (ds.Peek() != 0) {
+ switch (codepoint = ds.Take()) {
+ case '^':
+ anchorBegin_ = true;
+ break;
+
+ case '$':
+ anchorEnd_ = true;
+ break;
+
+ case '|':
+ while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+ return;
+ *operatorStack.template Push<Operator>() = kAlternation;
+ *atomCountStack.template Top<unsigned>() = 0;
+ break;
+
+ case '(':
+ *operatorStack.template Push<Operator>() = kLeftParenthesis;
+ *atomCountStack.template Push<unsigned>() = 0;
+ break;
+
+ case ')':
+ while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+ return;
+ if (operatorStack.Empty())
+ return;
+ operatorStack.template Pop<Operator>(1);
+ atomCountStack.template Pop<unsigned>(1);
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ break;
+
+ case '?':
+ if (!Eval(operandStack, kZeroOrOne))
+ return;
+ break;
+
+ case '*':
+ if (!Eval(operandStack, kZeroOrMore))
+ return;
+ break;
+
+ case '+':
+ if (!Eval(operandStack, kOneOrMore))
+ return;
+ break;
+
+ case '{':
+ {
+ unsigned n, m;
+ if (!ParseUnsigned(ds, &n))
+ return;
+
+ if (ds.Peek() == ',') {
+ ds.Take();
+ if (ds.Peek() == '}')
+ m = kInfinityQuantifier;
+ else if (!ParseUnsigned(ds, &m) || m < n)
+ return;
+ }
+ else
+ m = n;
+
+ if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
+ return;
+ ds.Take();
+ }
+ break;
+
+ case '.':
+ PushOperand(operandStack, kAnyCharacterClass);
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ break;
+
+ case '[':
+ {
+ SizeType range;
+ if (!ParseRange(ds, &range))
+ return;
+ SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
+ GetState(s).rangeStart = range;
+ *operandStack.template Push<Frag>() = Frag(s, s, s);
+ }
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ break;
+
+ case '\\': // Escape character
+ if (!CharacterEscape(ds, &codepoint))
+ return; // Unsupported escape character
+ // fall through to default
+
+ default: // Pattern character
+ PushOperand(operandStack, codepoint);
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ }
+ }
+
+ while (!operatorStack.Empty())
+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+ return;
+
+ // Link the operand to matching state.
+ if (operandStack.GetSize() == sizeof(Frag)) {
+ Frag* e = operandStack.template Pop<Frag>(1);
+ Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
+ root_ = e->start;
+
+#if RAPIDJSON_REGEX_VERBOSE
+ printf("root: %d\n", root_);
+ for (SizeType i = 0; i < stateCount_ ; i++) {
+ State& s = GetState(i);
+ printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
+ }
+ printf("\n");
+#endif
+ }
+ }
+
+ SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
+ State* s = states_.template Push<State>();
+ s->out = out;
+ s->out1 = out1;
+ s->codepoint = codepoint;
+ s->rangeStart = kRegexInvalidRange;
+ return stateCount_++;
+ }
+
+ void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
+ SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
+ *operandStack.template Push<Frag>() = Frag(s, s, s);
+ }
+
+ void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
+ if (*atomCountStack.template Top<unsigned>())
+ *operatorStack.template Push<Operator>() = kConcatenation;
+ (*atomCountStack.template Top<unsigned>())++;
+ }
+
+ SizeType Append(SizeType l1, SizeType l2) {
+ SizeType old = l1;
+ while (GetState(l1).out != kRegexInvalidState)
+ l1 = GetState(l1).out;
+ GetState(l1).out = l2;
+ return old;
+ }
+
+ void Patch(SizeType l, SizeType s) {
+ for (SizeType next; l != kRegexInvalidState; l = next) {
+ next = GetState(l).out;
+ GetState(l).out = s;
+ }
+ }
+
+ bool Eval(Stack<Allocator>& operandStack, Operator op) {
+ switch (op) {
+ case kConcatenation:
+ RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
+ {
+ Frag e2 = *operandStack.template Pop<Frag>(1);
+ Frag e1 = *operandStack.template Pop<Frag>(1);
+ Patch(e1.out, e2.start);
+ *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
+ }
+ return true;
+
+ case kAlternation:
+ if (operandStack.GetSize() >= sizeof(Frag) * 2) {
+ Frag e2 = *operandStack.template Pop<Frag>(1);
+ Frag e1 = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(e1.start, e2.start, 0);
+ *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
+ return true;
+ }
+ return false;
+
+ case kZeroOrOne:
+ if (operandStack.GetSize() >= sizeof(Frag)) {
+ Frag e = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
+ *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
+ return true;
+ }
+ return false;
+
+ case kZeroOrMore:
+ if (operandStack.GetSize() >= sizeof(Frag)) {
+ Frag e = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
+ Patch(e.out, s);
+ *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
+ return true;
+ }
+ return false;
+
+ default:
+ RAPIDJSON_ASSERT(op == kOneOrMore);
+ if (operandStack.GetSize() >= sizeof(Frag)) {
+ Frag e = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
+ Patch(e.out, s);
+ *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
+ RAPIDJSON_ASSERT(n <= m);
+ RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
+
+ if (n == 0) {
+ if (m == 0) // a{0} not support
+ return false;
+ else if (m == kInfinityQuantifier)
+ Eval(operandStack, kZeroOrMore); // a{0,} -> a*
+ else {
+ Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
+ for (unsigned i = 0; i < m - 1; i++)
+ CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
+ for (unsigned i = 0; i < m - 1; i++)
+ Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
+ }
+ return true;
+ }
+
+ for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
+ CloneTopOperand(operandStack);
+
+ if (m == kInfinityQuantifier)
+ Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
+ else if (m > n) {
+ CloneTopOperand(operandStack); // a{3,5} -> a a a a
+ Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
+ for (unsigned i = n; i < m - 1; i++)
+ CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
+ for (unsigned i = n; i < m; i++)
+ Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
+ }
+
+ for (unsigned i = 0; i < n - 1; i++)
+ Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
+
+ return true;
+ }
+
+ static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
+
+ void CloneTopOperand(Stack<Allocator>& operandStack) {
+ const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
+ SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
+ State* s = states_.template Push<State>(count);
+ memcpy(s, &GetState(src.minIndex), count * sizeof(State));
+ for (SizeType j = 0; j < count; j++) {
+ if (s[j].out != kRegexInvalidState)
+ s[j].out += count;
+ if (s[j].out1 != kRegexInvalidState)
+ s[j].out1 += count;
+ }
+ *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
+ stateCount_ += count;
+ }
+
+ template <typename InputStream>
+ bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
+ unsigned r = 0;
+ if (ds.Peek() < '0' || ds.Peek() > '9')
+ return false;
+ while (ds.Peek() >= '0' && ds.Peek() <= '9') {
+ if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
+ return false; // overflow
+ r = r * 10 + (ds.Take() - '0');
+ }
+ *u = r;
+ return true;
+ }
+
+ template <typename InputStream>
+ bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
+ bool isBegin = true;
+ bool negate = false;
+ int step = 0;
+ SizeType start = kRegexInvalidRange;
+ SizeType current = kRegexInvalidRange;
+ unsigned codepoint;
+ while ((codepoint = ds.Take()) != 0) {
+ if (isBegin) {
+ isBegin = false;
+ if (codepoint == '^') {
+ negate = true;
+ continue;
+ }
+ }
+
+ switch (codepoint) {
+ case ']':
+ if (start == kRegexInvalidRange)
+ return false; // Error: nothing inside []
+ if (step == 2) { // Add trailing '-'
+ SizeType r = NewRange('-');
+ RAPIDJSON_ASSERT(current != kRegexInvalidRange);
+ GetRange(current).next = r;
+ }
+ if (negate)
+ GetRange(start).start |= kRangeNegationFlag;
+ *range = start;
+ return true;
+
+ case '\\':
+ if (ds.Peek() == 'b') {
+ ds.Take();
+ codepoint = 0x0008; // Escape backspace character
+ }
+ else if (!CharacterEscape(ds, &codepoint))
+ return false;
+ // fall through to default
+
+ default:
+ switch (step) {
+ case 1:
+ if (codepoint == '-') {
+ step++;
+ break;
+ }
+ // fall through to step 0 for other characters
+
+ case 0:
+ {
+ SizeType r = NewRange(codepoint);
+ if (current != kRegexInvalidRange)
+ GetRange(current).next = r;
+ if (start == kRegexInvalidRange)
+ start = r;
+ current = r;
+ }
+ step = 1;
+ break;
+
+ default:
+ RAPIDJSON_ASSERT(step == 2);
+ GetRange(current).end = codepoint;
+ step = 0;
+ }
+ }
+ }
+ return false;
+ }
+
+ SizeType NewRange(unsigned codepoint) {
+ Range* r = ranges_.template Push<Range>();
+ r->start = r->end = codepoint;
+ r->next = kRegexInvalidRange;
+ return rangeCount_++;
+ }
+
+ template <typename InputStream>
+ bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
+ unsigned codepoint;
+ switch (codepoint = ds.Take()) {
+ case '^':
+ case '$':
+ case '|':
+ case '(':
+ case ')':
+ case '?':
+ case '*':
+ case '+':
+ case '.':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '\\':
+ *escapedCodepoint = codepoint; return true;
+ case 'f': *escapedCodepoint = 0x000C; return true;
+ case 'n': *escapedCodepoint = 0x000A; return true;
+ case 'r': *escapedCodepoint = 0x000D; return true;
+ case 't': *escapedCodepoint = 0x0009; return true;
+ case 'v': *escapedCodepoint = 0x000B; return true;
+ default:
+ return false; // Unsupported escape character
+ }
+ }
+
+ Stack<Allocator> states_;
+ Stack<Allocator> ranges_;
+ SizeType root_;
+ SizeType stateCount_;
+ SizeType rangeCount_;
+
+ static const unsigned kInfinityQuantifier = ~0u;
+
+ // For SearchWithAnchoring()
+ bool anchorBegin_;
+ bool anchorEnd_;
+};
+
+template <typename RegexType, typename Allocator = CrtAllocator>
+class GenericRegexSearch {
+public:
+ typedef typename RegexType::EncodingType Encoding;
+ typedef typename Encoding::Ch Ch;
+
+ GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
+ regex_(regex), allocator_(allocator), ownAllocator_(0),
+ state0_(allocator, 0), state1_(allocator, 0), stateSet_()
+ {
+ RAPIDJSON_ASSERT(regex_.IsValid());
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
+ state0_.template Reserve<SizeType>(regex_.stateCount_);
+ state1_.template Reserve<SizeType>(regex_.stateCount_);
+ }
+
+ ~GenericRegexSearch() {
+ Allocator::Free(stateSet_);
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
+ template <typename InputStream>
+ bool Match(InputStream& is) {
+ return SearchWithAnchoring(is, true, true);
+ }
+
+ bool Match(const Ch* s) {
+ GenericStringStream<Encoding> is(s);
+ return Match(is);
+ }
+
+ template <typename InputStream>
+ bool Search(InputStream& is) {
+ return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
+ }
+
+ bool Search(const Ch* s) {
+ GenericStringStream<Encoding> is(s);
+ return Search(is);
+ }
+
+private:
+ typedef typename RegexType::State State;
+ typedef typename RegexType::Range Range;
+
+ template <typename InputStream>
+ bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
+ DecodedStream<InputStream, Encoding> ds(is);
+
+ state0_.Clear();
+ Stack<Allocator> *current = &state0_, *next = &state1_;
+ const size_t stateSetSize = GetStateSetSize();
+ std::memset(stateSet_, 0, stateSetSize);
+
+ bool matched = AddState(*current, regex_.root_);
+ unsigned codepoint;
+ while (!current->Empty() && (codepoint = ds.Take()) != 0) {
+ std::memset(stateSet_, 0, stateSetSize);
+ next->Clear();
+ matched = false;
+ for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
+ const State& sr = regex_.GetState(*s);
+ if (sr.codepoint == codepoint ||
+ sr.codepoint == RegexType::kAnyCharacterClass ||
+ (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
+ {
+ matched = AddState(*next, sr.out) || matched;
+ if (!anchorEnd && matched)
+ return true;
+ }
+ if (!anchorBegin)
+ AddState(*next, regex_.root_);
+ }
+ internal::Swap(current, next);
+ }
+
+ return matched;
+ }
+
+ size_t GetStateSetSize() const {
+ return (regex_.stateCount_ + 31) / 32 * 4;
+ }
+
+ // Return whether the added states is a match state
+ bool AddState(Stack<Allocator>& l, SizeType index) {
+ RAPIDJSON_ASSERT(index != kRegexInvalidState);
+
+ const State& s = regex_.GetState(index);
+ if (s.out1 != kRegexInvalidState) { // Split
+ bool matched = AddState(l, s.out);
+ return AddState(l, s.out1) || matched;
+ }
+ else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
+ stateSet_[index >> 5] |= (1 << (index & 31));
+ *l.template PushUnsafe<SizeType>() = index;
+ }
+ return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
+ }
+
+ bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
+ bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
+ while (rangeIndex != kRegexInvalidRange) {
+ const Range& r = regex_.GetRange(rangeIndex);
+ if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
+ return yes;
+ rangeIndex = r.next;
+ }
+ return !yes;
+ }
+
+ const RegexType& regex_;
+ Allocator* allocator_;
+ Allocator* ownAllocator_;
+ Stack<Allocator> state0_;
+ Stack<Allocator> state1_;
+ uint32_t* stateSet_;
+};
+
+typedef GenericRegex<UTF8<> > Regex;
+typedef GenericRegexSearch<Regex> RegexSearch;
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_REGEX_H_
diff --git a/external/rapidjson/rapidjson/internal/stack.h b/external/rapidjson/rapidjson/internal/stack.h
new file mode 100644
index 0000000..022c9aa
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/stack.h
@@ -0,0 +1,230 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STACK_H_
+#define RAPIDJSON_INTERNAL_STACK_H_
+
+#include "../allocators.h"
+#include "swap.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// Stack
+
+//! A type-unsafe stack for storing different types of data.
+/*! \tparam Allocator Allocator for allocating stack memory.
+*/
+template <typename Allocator>
+class Stack {
+public:
+ // Optimization note: Do not allocate memory for stack_ in constructor.
+ // Do it lazily when first Push() -> Expand() -> Resize().
+ Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ Stack(Stack&& rhs)
+ : allocator_(rhs.allocator_),
+ ownAllocator_(rhs.ownAllocator_),
+ stack_(rhs.stack_),
+ stackTop_(rhs.stackTop_),
+ stackEnd_(rhs.stackEnd_),
+ initialCapacity_(rhs.initialCapacity_)
+ {
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.stack_ = 0;
+ rhs.stackTop_ = 0;
+ rhs.stackEnd_ = 0;
+ rhs.initialCapacity_ = 0;
+ }
+#endif
+
+ ~Stack() {
+ Destroy();
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ Stack& operator=(Stack&& rhs) {
+ if (&rhs != this)
+ {
+ Destroy();
+
+ allocator_ = rhs.allocator_;
+ ownAllocator_ = rhs.ownAllocator_;
+ stack_ = rhs.stack_;
+ stackTop_ = rhs.stackTop_;
+ stackEnd_ = rhs.stackEnd_;
+ initialCapacity_ = rhs.initialCapacity_;
+
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.stack_ = 0;
+ rhs.stackTop_ = 0;
+ rhs.stackEnd_ = 0;
+ rhs.initialCapacity_ = 0;
+ }
+ return *this;
+ }
+#endif
+
+ void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
+ internal::Swap(allocator_, rhs.allocator_);
+ internal::Swap(ownAllocator_, rhs.ownAllocator_);
+ internal::Swap(stack_, rhs.stack_);
+ internal::Swap(stackTop_, rhs.stackTop_);
+ internal::Swap(stackEnd_, rhs.stackEnd_);
+ internal::Swap(initialCapacity_, rhs.initialCapacity_);
+ }
+
+ void Clear() { stackTop_ = stack_; }
+
+ void ShrinkToFit() {
+ if (Empty()) {
+ // If the stack is empty, completely deallocate the memory.
+ Allocator::Free(stack_);
+ stack_ = 0;
+ stackTop_ = 0;
+ stackEnd_ = 0;
+ }
+ else
+ Resize(GetSize());
+ }
+
+ // Optimization note: try to minimize the size of this function for force inline.
+ // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
+ template<typename T>
+ RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
+ // Expand the stack if needed
+ if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
+ Expand<T>(count);
+ }
+
+ template<typename T>
+ RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
+ Reserve<T>(count);
+ return PushUnsafe<T>(count);
+ }
+
+ template<typename T>
+ RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
+ RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
+ T* ret = reinterpret_cast<T*>(stackTop_);
+ stackTop_ += sizeof(T) * count;
+ return ret;
+ }
+
+ template<typename T>
+ T* Pop(size_t count) {
+ RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
+ stackTop_ -= count * sizeof(T);
+ return reinterpret_cast<T*>(stackTop_);
+ }
+
+ template<typename T>
+ T* Top() {
+ RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+ return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+ }
+
+ template<typename T>
+ const T* Top() const {
+ RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+ return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+ }
+
+ template<typename T>
+ T* End() { return reinterpret_cast<T*>(stackTop_); }
+
+ template<typename T>
+ const T* End() const { return reinterpret_cast<T*>(stackTop_); }
+
+ template<typename T>
+ T* Bottom() { return reinterpret_cast<T*>(stack_); }
+
+ template<typename T>
+ const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
+
+ bool HasAllocator() const {
+ return allocator_ != 0;
+ }
+
+ Allocator& GetAllocator() {
+ RAPIDJSON_ASSERT(allocator_);
+ return *allocator_;
+ }
+
+ bool Empty() const { return stackTop_ == stack_; }
+ size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
+ size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
+
+private:
+ template<typename T>
+ void Expand(size_t count) {
+ // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
+ size_t newCapacity;
+ if (stack_ == 0) {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ newCapacity = initialCapacity_;
+ } else {
+ newCapacity = GetCapacity();
+ newCapacity += (newCapacity + 1) / 2;
+ }
+ size_t newSize = GetSize() + sizeof(T) * count;
+ if (newCapacity < newSize)
+ newCapacity = newSize;
+
+ Resize(newCapacity);
+ }
+
+ void Resize(size_t newCapacity) {
+ const size_t size = GetSize(); // Backup the current size
+ stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
+ stackTop_ = stack_ + size;
+ stackEnd_ = stack_ + newCapacity;
+ }
+
+ void Destroy() {
+ Allocator::Free(stack_);
+ RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
+ }
+
+ // Prohibit copy constructor & assignment operator.
+ Stack(const Stack&);
+ Stack& operator=(const Stack&);
+
+ Allocator* allocator_;
+ Allocator* ownAllocator_;
+ char *stack_;
+ char *stackTop_;
+ char *stackEnd_;
+ size_t initialCapacity_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_STACK_H_
diff --git a/external/rapidjson/rapidjson/internal/strfunc.h b/external/rapidjson/rapidjson/internal/strfunc.h
new file mode 100644
index 0000000..de41d8f
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/strfunc.h
@@ -0,0 +1,58 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
+#define RAPIDJSON_INTERNAL_STRFUNC_H_
+
+#include "../stream.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom strlen() which works on different character types.
+/*! \tparam Ch Character type (e.g. char, wchar_t, short)
+ \param s Null-terminated input string.
+ \return Number of characters in the string.
+ \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
+*/
+template <typename Ch>
+inline SizeType StrLen(const Ch* s) {
+ RAPIDJSON_ASSERT(s != 0);
+ const Ch* p = s;
+ while (*p) ++p;
+ return SizeType(p - s);
+}
+
+//! Returns number of code points in a encoded string.
+template<typename Encoding>
+bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
+ RAPIDJSON_ASSERT(s != 0);
+ RAPIDJSON_ASSERT(outCount != 0);
+ GenericStringStream<Encoding> is(s);
+ const typename Encoding::Ch* end = s + length;
+ SizeType count = 0;
+ while (is.src_ < end) {
+ unsigned codepoint;
+ if (!Encoding::Decode(is, &codepoint))
+ return false;
+ count++;
+ }
+ *outCount = count;
+ return true;
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
diff --git a/external/rapidjson/rapidjson/internal/strtod.h b/external/rapidjson/rapidjson/internal/strtod.h
new file mode 100644
index 0000000..289c413
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/strtod.h
@@ -0,0 +1,269 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_STRTOD_
+#define RAPIDJSON_STRTOD_
+
+#include "ieee754.h"
+#include "biginteger.h"
+#include "diyfp.h"
+#include "pow10.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline double FastPath(double significand, int exp) {
+ if (exp < -308)
+ return 0.0;
+ else if (exp >= 0)
+ return significand * internal::Pow10(exp);
+ else
+ return significand / internal::Pow10(-exp);
+}
+
+inline double StrtodNormalPrecision(double d, int p) {
+ if (p < -308) {
+ // Prevent expSum < -308, making Pow10(p) = 0
+ d = FastPath(d, -308);
+ d = FastPath(d, p + 308);
+ }
+ else
+ d = FastPath(d, p);
+ return d;
+}
+
+template <typename T>
+inline T Min3(T a, T b, T c) {
+ T m = a;
+ if (m > b) m = b;
+ if (m > c) m = c;
+ return m;
+}
+
+inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
+ const Double db(b);
+ const uint64_t bInt = db.IntegerSignificand();
+ const int bExp = db.IntegerExponent();
+ const int hExp = bExp - 1;
+
+ int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
+
+ // Adjust for decimal exponent
+ if (dExp >= 0) {
+ dS_Exp2 += dExp;
+ dS_Exp5 += dExp;
+ }
+ else {
+ bS_Exp2 -= dExp;
+ bS_Exp5 -= dExp;
+ hS_Exp2 -= dExp;
+ hS_Exp5 -= dExp;
+ }
+
+ // Adjust for binary exponent
+ if (bExp >= 0)
+ bS_Exp2 += bExp;
+ else {
+ dS_Exp2 -= bExp;
+ hS_Exp2 -= bExp;
+ }
+
+ // Adjust for half ulp exponent
+ if (hExp >= 0)
+ hS_Exp2 += hExp;
+ else {
+ dS_Exp2 -= hExp;
+ bS_Exp2 -= hExp;
+ }
+
+ // Remove common power of two factor from all three scaled values
+ int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
+ dS_Exp2 -= common_Exp2;
+ bS_Exp2 -= common_Exp2;
+ hS_Exp2 -= common_Exp2;
+
+ BigInteger dS = d;
+ dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
+
+ BigInteger bS(bInt);
+ bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
+
+ BigInteger hS(1);
+ hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
+
+ BigInteger delta(0);
+ dS.Difference(bS, &delta);
+
+ return delta.Compare(hS);
+}
+
+inline bool StrtodFast(double d, int p, double* result) {
+ // Use fast path for string-to-double conversion if possible
+ // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
+ if (p > 22 && p < 22 + 16) {
+ // Fast Path Cases In Disguise
+ d *= internal::Pow10(p - 22);
+ p = 22;
+ }
+
+ if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
+ *result = FastPath(d, p);
+ return true;
+ }
+ else
+ return false;
+}
+
+// Compute an approximation and see if it is within 1/2 ULP
+inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
+ uint64_t significand = 0;
+ size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
+ for (; i < length; i++) {
+ if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
+ (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
+ break;
+ significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
+ }
+
+ if (i < length && decimals[i] >= '5') // Rounding
+ significand++;
+
+ size_t remaining = length - i;
+ const unsigned kUlpShift = 3;
+ const unsigned kUlp = 1 << kUlpShift;
+ int64_t error = (remaining == 0) ? 0 : kUlp / 2;
+
+ DiyFp v(significand, 0);
+ v = v.Normalize();
+ error <<= -v.e;
+
+ const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
+
+ int actualExp;
+ DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
+ if (actualExp != dExp) {
+ static const DiyFp kPow10[] = {
+ DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
+ DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
+ DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
+ DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
+ DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
+ DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
+ DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
+ };
+ int adjustment = dExp - actualExp - 1;
+ RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
+ v = v * kPow10[adjustment];
+ if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
+ error += kUlp / 2;
+ }
+
+ v = v * cachedPower;
+
+ error += kUlp + (error == 0 ? 0 : 1);
+
+ const int oldExp = v.e;
+ v = v.Normalize();
+ error <<= oldExp - v.e;
+
+ const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
+ unsigned precisionSize = 64 - effectiveSignificandSize;
+ if (precisionSize + kUlpShift >= 64) {
+ unsigned scaleExp = (precisionSize + kUlpShift) - 63;
+ v.f >>= scaleExp;
+ v.e += scaleExp;
+ error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
+ precisionSize -= scaleExp;
+ }
+
+ DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
+ const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
+ const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
+ if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
+ rounded.f++;
+ if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
+ rounded.f >>= 1;
+ rounded.e++;
+ }
+ }
+
+ *result = rounded.ToDouble();
+
+ return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
+}
+
+inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+ const BigInteger dInt(decimals, length);
+ const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
+ Double a(approx);
+ int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
+ if (cmp < 0)
+ return a.Value(); // within half ULP
+ else if (cmp == 0) {
+ // Round towards even
+ if (a.Significand() & 1)
+ return a.NextPositiveDouble();
+ else
+ return a.Value();
+ }
+ else // adjustment
+ return a.NextPositiveDouble();
+}
+
+inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+ RAPIDJSON_ASSERT(d >= 0.0);
+ RAPIDJSON_ASSERT(length >= 1);
+
+ double result;
+ if (StrtodFast(d, p, &result))
+ return result;
+
+ // Trim leading zeros
+ while (*decimals == '0' && length > 1) {
+ length--;
+ decimals++;
+ decimalPosition--;
+ }
+
+ // Trim trailing zeros
+ while (decimals[length - 1] == '0' && length > 1) {
+ length--;
+ decimalPosition--;
+ exp++;
+ }
+
+ // Trim right-most digits
+ const int kMaxDecimalDigit = 780;
+ if (static_cast<int>(length) > kMaxDecimalDigit) {
+ int delta = (static_cast<int>(length) - kMaxDecimalDigit);
+ exp += delta;
+ decimalPosition -= static_cast<unsigned>(delta);
+ length = kMaxDecimalDigit;
+ }
+
+ // If too small, underflow to zero
+ if (int(length) + exp < -324)
+ return 0.0;
+
+ if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
+ return result;
+
+ // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
+ return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STRTOD_
diff --git a/external/rapidjson/rapidjson/internal/swap.h b/external/rapidjson/rapidjson/internal/swap.h
new file mode 100644
index 0000000..666e49f
--- /dev/null
+++ b/external/rapidjson/rapidjson/internal/swap.h
@@ -0,0 +1,46 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_SWAP_H_
+#define RAPIDJSON_INTERNAL_SWAP_H_
+
+#include "../rapidjson.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom swap() to avoid dependency on C++ <algorithm> header
+/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
+ \note This has the same semantics as std::swap().
+*/
+template <typename T>
+inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
+ T tmp = a;
+ a = b;
+ b = tmp;
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_SWAP_H_
diff --git a/external/rapidjson/rapidjson/istreamwrapper.h b/external/rapidjson/rapidjson/istreamwrapper.h
new file mode 100644
index 0000000..f5fe289
--- /dev/null
+++ b/external/rapidjson/rapidjson/istreamwrapper.h
@@ -0,0 +1,115 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
+#define RAPIDJSON_ISTREAMWRAPPER_H_
+
+#include "stream.h"
+#include <iosfwd>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
+/*!
+ The classes can be wrapped including but not limited to:
+
+ - \c std::istringstream
+ - \c std::stringstream
+ - \c std::wistringstream
+ - \c std::wstringstream
+ - \c std::ifstream
+ - \c std::fstream
+ - \c std::wifstream
+ - \c std::wfstream
+
+ \tparam StreamType Class derived from \c std::basic_istream.
+*/
+
+template <typename StreamType>
+class BasicIStreamWrapper {
+public:
+ typedef typename StreamType::char_type Ch;
+ BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
+
+ Ch Peek() const {
+ typename StreamType::int_type c = stream_.peek();
+ return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
+ }
+
+ Ch Take() {
+ typename StreamType::int_type c = stream_.get();
+ if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
+ count_++;
+ return static_cast<Ch>(c);
+ }
+ else
+ return '\0';
+ }
+
+ // tellg() may return -1 when failed. So we count by ourself.
+ size_t Tell() const { return count_; }
+
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ // For encoding detection only.
+ const Ch* Peek4() const {
+ RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
+ int i;
+ bool hasError = false;
+ for (i = 0; i < 4; ++i) {
+ typename StreamType::int_type c = stream_.get();
+ if (c == StreamType::traits_type::eof()) {
+ hasError = true;
+ stream_.clear();
+ break;
+ }
+ peekBuffer_[i] = static_cast<Ch>(c);
+ }
+ for (--i; i >= 0; --i)
+ stream_.putback(peekBuffer_[i]);
+ return !hasError ? peekBuffer_ : 0;
+ }
+
+private:
+ BasicIStreamWrapper(const BasicIStreamWrapper&);
+ BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
+
+ StreamType& stream_;
+ size_t count_; //!< Number of characters read. Note:
+ mutable Ch peekBuffer_[4];
+};
+
+typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
+typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
+
+#if defined(__clang__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ISTREAMWRAPPER_H_
diff --git a/external/rapidjson/rapidjson/memorybuffer.h b/external/rapidjson/rapidjson/memorybuffer.h
new file mode 100644
index 0000000..39bee1d
--- /dev/null
+++ b/external/rapidjson/rapidjson/memorybuffer.h
@@ -0,0 +1,70 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYBUFFER_H_
+#define RAPIDJSON_MEMORYBUFFER_H_
+
+#include "stream.h"
+#include "internal/stack.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output byte stream.
+/*!
+ This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
+
+ It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
+
+ Differences between MemoryBuffer and StringBuffer:
+ 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
+ 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
+
+ \tparam Allocator type for allocating memory buffer.
+ \note implements Stream concept
+*/
+template <typename Allocator = CrtAllocator>
+struct GenericMemoryBuffer {
+ typedef char Ch; // byte
+
+ GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+ void Flush() {}
+
+ void Clear() { stack_.Clear(); }
+ void ShrinkToFit() { stack_.ShrinkToFit(); }
+ Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+ void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+ const Ch* GetBuffer() const {
+ return stack_.template Bottom<Ch>();
+ }
+
+ size_t GetSize() const { return stack_.GetSize(); }
+
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> stack_;
+};
+
+typedef GenericMemoryBuffer<> MemoryBuffer;
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
+ std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_
diff --git a/external/rapidjson/rapidjson/memorystream.h b/external/rapidjson/rapidjson/memorystream.h
new file mode 100644
index 0000000..1d71d8a
--- /dev/null
+++ b/external/rapidjson/rapidjson/memorystream.h
@@ -0,0 +1,71 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYSTREAM_H_
+#define RAPIDJSON_MEMORYSTREAM_H_
+
+#include "stream.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(unreachable-code)
+RAPIDJSON_DIAG_OFF(missing-noreturn)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory input byte stream.
+/*!
+ This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
+
+ It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
+
+ Differences between MemoryStream and StringStream:
+ 1. StringStream has encoding but MemoryStream is a byte stream.
+ 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
+ 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
+ \note implements Stream concept
+*/
+struct MemoryStream {
+ typedef char Ch; // byte
+
+ MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
+
+ Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
+ Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
+ size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
+
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ // For encoding detection only.
+ const Ch* Peek4() const {
+ return Tell() + 4 <= size_ ? src_ : 0;
+ }
+
+ const Ch* src_; //!< Current read position.
+ const Ch* begin_; //!< Original head of the string.
+ const Ch* end_; //!< End of stream.
+ size_t size_; //!< Size of the stream.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_
diff --git a/external/rapidjson/rapidjson/msinttypes/inttypes.h b/external/rapidjson/rapidjson/msinttypes/inttypes.h
new file mode 100644
index 0000000..1811128
--- /dev/null
+++ b/external/rapidjson/rapidjson/msinttypes/inttypes.h
@@ -0,0 +1,316 @@
+// ISO C9x compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2013 Alexander Chemeris
+//
+// 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. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the product nor the names of its contributors may
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// The above software in this distribution may have been modified by
+// THL A29 Limited ("Tencent Modifications").
+// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// miloyip: VC supports inttypes.h since VC2013
+#if _MSC_VER >= 1800
+#include <inttypes.h>
+#else
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+ intmax_t quot;
+ intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8 "d"
+#define PRIi8 "i"
+#define PRIdLEAST8 "d"
+#define PRIiLEAST8 "i"
+#define PRIdFAST8 "d"
+#define PRIiFAST8 "i"
+
+#define PRId16 "hd"
+#define PRIi16 "hi"
+#define PRIdLEAST16 "hd"
+#define PRIiLEAST16 "hi"
+#define PRIdFAST16 "hd"
+#define PRIiFAST16 "hi"
+
+#define PRId32 "I32d"
+#define PRIi32 "I32i"
+#define PRIdLEAST32 "I32d"
+#define PRIiLEAST32 "I32i"
+#define PRIdFAST32 "I32d"
+#define PRIiFAST32 "I32i"
+
+#define PRId64 "I64d"
+#define PRIi64 "I64i"
+#define PRIdLEAST64 "I64d"
+#define PRIiLEAST64 "I64i"
+#define PRIdFAST64 "I64d"
+#define PRIiFAST64 "I64i"
+
+#define PRIdMAX "I64d"
+#define PRIiMAX "I64i"
+
+#define PRIdPTR "Id"
+#define PRIiPTR "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8 "o"
+#define PRIu8 "u"
+#define PRIx8 "x"
+#define PRIX8 "X"
+#define PRIoLEAST8 "o"
+#define PRIuLEAST8 "u"
+#define PRIxLEAST8 "x"
+#define PRIXLEAST8 "X"
+#define PRIoFAST8 "o"
+#define PRIuFAST8 "u"
+#define PRIxFAST8 "x"
+#define PRIXFAST8 "X"
+
+#define PRIo16 "ho"
+#define PRIu16 "hu"
+#define PRIx16 "hx"
+#define PRIX16 "hX"
+#define PRIoLEAST16 "ho"
+#define PRIuLEAST16 "hu"
+#define PRIxLEAST16 "hx"
+#define PRIXLEAST16 "hX"
+#define PRIoFAST16 "ho"
+#define PRIuFAST16 "hu"
+#define PRIxFAST16 "hx"
+#define PRIXFAST16 "hX"
+
+#define PRIo32 "I32o"
+#define PRIu32 "I32u"
+#define PRIx32 "I32x"
+#define PRIX32 "I32X"
+#define PRIoLEAST32 "I32o"
+#define PRIuLEAST32 "I32u"
+#define PRIxLEAST32 "I32x"
+#define PRIXLEAST32 "I32X"
+#define PRIoFAST32 "I32o"
+#define PRIuFAST32 "I32u"
+#define PRIxFAST32 "I32x"
+#define PRIXFAST32 "I32X"
+
+#define PRIo64 "I64o"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#define PRIX64 "I64X"
+#define PRIoLEAST64 "I64o"
+#define PRIuLEAST64 "I64u"
+#define PRIxLEAST64 "I64x"
+#define PRIXLEAST64 "I64X"
+#define PRIoFAST64 "I64o"
+#define PRIuFAST64 "I64u"
+#define PRIxFAST64 "I64x"
+#define PRIXFAST64 "I64X"
+
+#define PRIoMAX "I64o"
+#define PRIuMAX "I64u"
+#define PRIxMAX "I64x"
+#define PRIXMAX "I64X"
+
+#define PRIoPTR "Io"
+#define PRIuPTR "Iu"
+#define PRIxPTR "Ix"
+#define PRIXPTR "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8 "d"
+#define SCNi8 "i"
+#define SCNdLEAST8 "d"
+#define SCNiLEAST8 "i"
+#define SCNdFAST8 "d"
+#define SCNiFAST8 "i"
+
+#define SCNd16 "hd"
+#define SCNi16 "hi"
+#define SCNdLEAST16 "hd"
+#define SCNiLEAST16 "hi"
+#define SCNdFAST16 "hd"
+#define SCNiFAST16 "hi"
+
+#define SCNd32 "ld"
+#define SCNi32 "li"
+#define SCNdLEAST32 "ld"
+#define SCNiLEAST32 "li"
+#define SCNdFAST32 "ld"
+#define SCNiFAST32 "li"
+
+#define SCNd64 "I64d"
+#define SCNi64 "I64i"
+#define SCNdLEAST64 "I64d"
+#define SCNiLEAST64 "I64i"
+#define SCNdFAST64 "I64d"
+#define SCNiFAST64 "I64i"
+
+#define SCNdMAX "I64d"
+#define SCNiMAX "I64i"
+
+#ifdef _WIN64 // [
+# define SCNdPTR "I64d"
+# define SCNiPTR "I64i"
+#else // _WIN64 ][
+# define SCNdPTR "ld"
+# define SCNiPTR "li"
+#endif // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8 "o"
+#define SCNu8 "u"
+#define SCNx8 "x"
+#define SCNX8 "X"
+#define SCNoLEAST8 "o"
+#define SCNuLEAST8 "u"
+#define SCNxLEAST8 "x"
+#define SCNXLEAST8 "X"
+#define SCNoFAST8 "o"
+#define SCNuFAST8 "u"
+#define SCNxFAST8 "x"
+#define SCNXFAST8 "X"
+
+#define SCNo16 "ho"
+#define SCNu16 "hu"
+#define SCNx16 "hx"
+#define SCNX16 "hX"
+#define SCNoLEAST16 "ho"
+#define SCNuLEAST16 "hu"
+#define SCNxLEAST16 "hx"
+#define SCNXLEAST16 "hX"
+#define SCNoFAST16 "ho"
+#define SCNuFAST16 "hu"
+#define SCNxFAST16 "hx"
+#define SCNXFAST16 "hX"
+
+#define SCNo32 "lo"
+#define SCNu32 "lu"
+#define SCNx32 "lx"
+#define SCNX32 "lX"
+#define SCNoLEAST32 "lo"
+#define SCNuLEAST32 "lu"
+#define SCNxLEAST32 "lx"
+#define SCNXLEAST32 "lX"
+#define SCNoFAST32 "lo"
+#define SCNuFAST32 "lu"
+#define SCNxFAST32 "lx"
+#define SCNXFAST32 "lX"
+
+#define SCNo64 "I64o"
+#define SCNu64 "I64u"
+#define SCNx64 "I64x"
+#define SCNX64 "I64X"
+#define SCNoLEAST64 "I64o"
+#define SCNuLEAST64 "I64u"
+#define SCNxLEAST64 "I64x"
+#define SCNXLEAST64 "I64X"
+#define SCNoFAST64 "I64o"
+#define SCNuFAST64 "I64u"
+#define SCNxFAST64 "I64x"
+#define SCNXFAST64 "I64X"
+
+#define SCNoMAX "I64o"
+#define SCNuMAX "I64u"
+#define SCNxMAX "I64x"
+#define SCNXMAX "I64X"
+
+#ifdef _WIN64 // [
+# define SCNoPTR "I64o"
+# define SCNuPTR "I64u"
+# define SCNxPTR "I64x"
+# define SCNXPTR "I64X"
+#else // _WIN64 ][
+# define SCNoPTR "lo"
+# define SCNuPTR "lu"
+# define SCNxPTR "lx"
+# define SCNXPTR "lX"
+#endif // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+ imaxdiv_t result;
+
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+
+ if (numer < 0 && result.rem > 0) {
+ // did division wrong; must fix up
+ ++result.quot;
+ result.rem -= denom;
+ }
+
+ return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+#endif // _MSC_VER >= 1800
+
+#endif // _MSC_INTTYPES_H_ ]
diff --git a/external/rapidjson/rapidjson/msinttypes/stdint.h b/external/rapidjson/rapidjson/msinttypes/stdint.h
new file mode 100644
index 0000000..3d4477b
--- /dev/null
+++ b/external/rapidjson/rapidjson/msinttypes/stdint.h
@@ -0,0 +1,300 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2013 Alexander Chemeris
+//
+// 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. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the product nor the names of its contributors may
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// The above software in this distribution may have been modified by
+// THL A29 Limited ("Tencent Modifications").
+// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
+#if _MSC_VER >= 1600 // [
+#include <stdint.h>
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+#undef INT8_C
+#undef INT16_C
+#undef INT32_C
+#undef INT64_C
+#undef UINT8_C
+#undef UINT16_C
+#undef UINT32_C
+#undef UINT64_C
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C // [
+# define INTMAX_C INT64_C
+#endif // INTMAX_C ]
+#ifndef UINTMAX_C // [
+# define UINTMAX_C UINT64_C
+#endif // UINTMAX_C ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#else // ] _MSC_VER >= 1700 [
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler would give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#if defined(__cplusplus) && !defined(_M_ARM)
+extern "C" {
+#endif
+# include <wchar.h>
+#if defined(__cplusplus) && !defined(_M_ARM)
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef signed __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 signed int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C // [
+# define INTMAX_C INT64_C
+#endif // INTMAX_C ]
+#ifndef UINTMAX_C // [
+# define UINTMAX_C UINT64_C
+#endif // UINTMAX_C ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#endif // _MSC_VER >= 1600 ]
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/external/rapidjson/rapidjson/ostreamwrapper.h b/external/rapidjson/rapidjson/ostreamwrapper.h
new file mode 100644
index 0000000..6f4667c
--- /dev/null
+++ b/external/rapidjson/rapidjson/ostreamwrapper.h
@@ -0,0 +1,81 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_OSTREAMWRAPPER_H_
+#define RAPIDJSON_OSTREAMWRAPPER_H_
+
+#include "stream.h"
+#include <iosfwd>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
+/*!
+ The classes can be wrapped including but not limited to:
+
+ - \c std::ostringstream
+ - \c std::stringstream
+ - \c std::wpstringstream
+ - \c std::wstringstream
+ - \c std::ifstream
+ - \c std::fstream
+ - \c std::wofstream
+ - \c std::wfstream
+
+ \tparam StreamType Class derived from \c std::basic_ostream.
+*/
+
+template <typename StreamType>
+class BasicOStreamWrapper {
+public:
+ typedef typename StreamType::char_type Ch;
+ BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
+
+ void Put(Ch c) {
+ stream_.put(c);
+ }
+
+ void Flush() {
+ stream_.flush();
+ }
+
+ // Not implemented
+ char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
+ char Take() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+ char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ BasicOStreamWrapper(const BasicOStreamWrapper&);
+ BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
+
+ StreamType& stream_;
+};
+
+typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
+typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_OSTREAMWRAPPER_H_
diff --git a/external/rapidjson/rapidjson/pointer.h b/external/rapidjson/rapidjson/pointer.h
new file mode 100644
index 0000000..0206ac1
--- /dev/null
+++ b/external/rapidjson/rapidjson/pointer.h
@@ -0,0 +1,1358 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_POINTER_H_
+#define RAPIDJSON_POINTER_H_
+
+#include "document.h"
+#include "internal/itoa.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(switch-enum)
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+ \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
+*/
+enum PointerParseErrorCode {
+ kPointerParseErrorNone = 0, //!< The parse is successful
+
+ kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
+ kPointerParseErrorInvalidEscape, //!< Invalid escape
+ kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
+ kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericPointer
+
+//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
+/*!
+ This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer"
+ (https://tools.ietf.org/html/rfc6901).
+
+ A JSON pointer is for identifying a specific value in a JSON document
+ (GenericDocument). It can simplify coding of DOM tree manipulation, because it
+ can access multiple-level depth of DOM tree with single API call.
+
+ After it parses a string representation (e.g. "/foo/0" or URI fragment
+ representation (e.g. "#/foo/0") into its internal representation (tokens),
+ it can be used to resolve a specific value in multiple documents, or sub-tree
+ of documents.
+
+ Contrary to GenericValue, Pointer can be copy constructed and copy assigned.
+ Apart from assignment, a Pointer cannot be modified after construction.
+
+ Although Pointer is very convenient, please aware that constructing Pointer
+ involves parsing and dynamic memory allocation. A special constructor with user-
+ supplied tokens eliminates these.
+
+ GenericPointer depends on GenericDocument and GenericValue.
+
+ \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >
+ \tparam Allocator The allocator type for allocating memory for internal representation.
+
+ \note GenericPointer uses same encoding of ValueType.
+ However, Allocator of GenericPointer is independent of Allocator of Value.
+*/
+template <typename ValueType, typename Allocator = CrtAllocator>
+class GenericPointer {
+public:
+ typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
+ typedef typename ValueType::Ch Ch; //!< Character type from Value
+
+ //! A token is the basic units of internal representation.
+ /*!
+ A JSON pointer string representation "/foo/123" is parsed to two tokens:
+ "foo" and 123. 123 will be represented in both numeric form and string form.
+ They are resolved according to the actual value type (object or array).
+
+ For token that are not numbers, or the numeric value is out of bound
+ (greater than limits of SizeType), they are only treated as string form
+ (i.e. the token's index will be equal to kPointerInvalidIndex).
+
+ This struct is public so that user can create a Pointer without parsing and
+ allocation, using a special constructor.
+ */
+ struct Token {
+ const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character.
+ SizeType length; //!< Length of the name.
+ SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex.
+ };
+
+ //!@name Constructors and destructor.
+ //@{
+
+ //! Default constructor.
+ GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
+
+ //! Constructor that parses a string or URI fragment representation.
+ /*!
+ \param source A null-terminated, string or URI fragment representation of JSON pointer.
+ \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
+ */
+ explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ Parse(source, internal::StrLen(source));
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Constructor that parses a string or URI fragment representation.
+ /*!
+ \param source A string or URI fragment representation of JSON pointer.
+ \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
+ \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ Parse(source.c_str(), source.size());
+ }
+#endif
+
+ //! Constructor that parses a string or URI fragment representation, with length of the source string.
+ /*!
+ \param source A string or URI fragment representation of JSON pointer.
+ \param length Length of source.
+ \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
+ \note Slightly faster than the overload without length.
+ */
+ GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ Parse(source, length);
+ }
+
+ //! Constructor with user-supplied tokens.
+ /*!
+ This constructor let user supplies const array of tokens.
+ This prevents the parsing process and eliminates allocation.
+ This is preferred for memory constrained environments.
+
+ \param tokens An constant array of tokens representing the JSON pointer.
+ \param tokenCount Number of tokens.
+
+ \b Example
+ \code
+ #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
+ #define INDEX(i) { #i, sizeof(#i) - 1, i }
+
+ static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
+ static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+ // Equivalent to static const Pointer p("/foo/123");
+
+ #undef NAME
+ #undef INDEX
+ \endcode
+ */
+ GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
+
+ //! Copy constructor.
+ GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ *this = rhs;
+ }
+
+ //! Destructor.
+ ~GenericPointer() {
+ if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
+ Allocator::Free(tokens_);
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
+ //! Assignment operator.
+ GenericPointer& operator=(const GenericPointer& rhs) {
+ if (this != &rhs) {
+ // Do not delete ownAllcator
+ if (nameBuffer_)
+ Allocator::Free(tokens_);
+
+ tokenCount_ = rhs.tokenCount_;
+ parseErrorOffset_ = rhs.parseErrorOffset_;
+ parseErrorCode_ = rhs.parseErrorCode_;
+
+ if (rhs.nameBuffer_)
+ CopyFromRaw(rhs); // Normally parsed tokens.
+ else {
+ tokens_ = rhs.tokens_; // User supplied const tokens.
+ nameBuffer_ = 0;
+ }
+ }
+ return *this;
+ }
+
+ //@}
+
+ //!@name Append token
+ //@{
+
+ //! Append a token and return a new Pointer
+ /*!
+ \param token Token to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
+ GenericPointer r;
+ r.allocator_ = allocator;
+ Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);
+ std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
+ r.tokens_[tokenCount_].name = p;
+ r.tokens_[tokenCount_].length = token.length;
+ r.tokens_[tokenCount_].index = token.index;
+ return r;
+ }
+
+ //! Append a name token with length, and return a new Pointer
+ /*!
+ \param name Name to be appended.
+ \param length Length of name.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {
+ Token token = { name, length, kPointerInvalidIndex };
+ return Append(token, allocator);
+ }
+
+ //! Append a name token without length, and return a new Pointer
+ /*!
+ \param name Name (const Ch*) to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
+ Append(T* name, Allocator* allocator = 0) const {
+ return Append(name, StrLen(name), allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Append a name token, and return a new Pointer
+ /*!
+ \param name Name to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {
+ return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);
+ }
+#endif
+
+ //! Append a index token, and return a new Pointer
+ /*!
+ \param index Index to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
+ char buffer[21];
+ char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);
+ SizeType length = static_cast<SizeType>(end - buffer);
+ buffer[length] = '\0';
+
+ if (sizeof(Ch) == 1) {
+ Token token = { reinterpret_cast<Ch*>(buffer), length, index };
+ return Append(token, allocator);
+ }
+ else {
+ Ch name[21];
+ for (size_t i = 0; i <= length; i++)
+ name[i] = buffer[i];
+ Token token = { name, length, index };
+ return Append(token, allocator);
+ }
+ }
+
+ //! Append a token by value, and return a new Pointer
+ /*!
+ \param token token to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {
+ if (token.IsString())
+ return Append(token.GetString(), token.GetStringLength(), allocator);
+ else {
+ RAPIDJSON_ASSERT(token.IsUint64());
+ RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));
+ return Append(static_cast<SizeType>(token.GetUint64()), allocator);
+ }
+ }
+
+ //!@name Handling Parse Error
+ //@{
+
+ //! Check whether this is a valid pointer.
+ bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
+
+ //! Get the parsing error offset in code unit.
+ size_t GetParseErrorOffset() const { return parseErrorOffset_; }
+
+ //! Get the parsing error code.
+ PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
+
+ //@}
+
+ //! Get the allocator of this pointer.
+ Allocator& GetAllocator() { return *allocator_; }
+
+ //!@name Tokens
+ //@{
+
+ //! Get the token array (const version only).
+ const Token* GetTokens() const { return tokens_; }
+
+ //! Get the number of tokens.
+ size_t GetTokenCount() const { return tokenCount_; }
+
+ //@}
+
+ //!@name Equality/inequality operators
+ //@{
+
+ //! Equality operator.
+ /*!
+ \note When any pointers are invalid, always returns false.
+ */
+ bool operator==(const GenericPointer& rhs) const {
+ if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)
+ return false;
+
+ for (size_t i = 0; i < tokenCount_; i++) {
+ if (tokens_[i].index != rhs.tokens_[i].index ||
+ tokens_[i].length != rhs.tokens_[i].length ||
+ (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ //! Inequality operator.
+ /*!
+ \note When any pointers are invalid, always returns true.
+ */
+ bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
+
+ //@}
+
+ //!@name Stringify
+ //@{
+
+ //! Stringify the pointer into string representation.
+ /*!
+ \tparam OutputStream Type of output stream.
+ \param os The output stream.
+ */
+ template<typename OutputStream>
+ bool Stringify(OutputStream& os) const {
+ return Stringify<false, OutputStream>(os);
+ }
+
+ //! Stringify the pointer into URI fragment representation.
+ /*!
+ \tparam OutputStream Type of output stream.
+ \param os The output stream.
+ */
+ template<typename OutputStream>
+ bool StringifyUriFragment(OutputStream& os) const {
+ return Stringify<true, OutputStream>(os);
+ }
+
+ //@}
+
+ //!@name Create value
+ //@{
+
+ //! Create a value in a subtree.
+ /*!
+ If the value is not exist, it creates all parent values and a JSON Null value.
+ So it always succeed and return the newly created or existing value.
+
+ Remind that it may change types of parents according to tokens, so it
+ potentially removes previously stored values. For example, if a document
+ was an array, and "/foo" is used to create a value, then the document
+ will be changed to an object, and all existing array elements are lost.
+
+ \param root Root value of a DOM subtree to be resolved. It can be any value other than document root.
+ \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+ \param alreadyExist If non-null, it stores whether the resolved value is already exist.
+ \return The resolved newly created (a JSON Null value), or already exists value.
+ */
+ ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {
+ RAPIDJSON_ASSERT(IsValid());
+ ValueType* v = &root;
+ bool exist = true;
+ for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
+ if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
+ v->PushBack(ValueType().Move(), allocator);
+ v = &((*v)[v->Size() - 1]);
+ exist = false;
+ }
+ else {
+ if (t->index == kPointerInvalidIndex) { // must be object name
+ if (!v->IsObject())
+ v->SetObject(); // Change to Object
+ }
+ else { // object name or array index
+ if (!v->IsArray() && !v->IsObject())
+ v->SetArray(); // Change to Array
+ }
+
+ if (v->IsArray()) {
+ if (t->index >= v->Size()) {
+ v->Reserve(t->index + 1, allocator);
+ while (t->index >= v->Size())
+ v->PushBack(ValueType().Move(), allocator);
+ exist = false;
+ }
+ v = &((*v)[t->index]);
+ }
+ else {
+ typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ if (m == v->MemberEnd()) {
+ v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
+ v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end
+ exist = false;
+ }
+ else
+ v = &m->value;
+ }
+ }
+ }
+
+ if (alreadyExist)
+ *alreadyExist = exist;
+
+ return *v;
+ }
+
+ //! Creates a value in a document.
+ /*!
+ \param document A document to be resolved.
+ \param alreadyExist If non-null, it stores whether the resolved value is already exist.
+ \return The resolved newly created, or already exists value.
+ */
+ template <typename stackAllocator>
+ ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const {
+ return Create(document, document.GetAllocator(), alreadyExist);
+ }
+
+ //@}
+
+ //!@name Query value
+ //@{
+
+ //! Query a value in a subtree.
+ /*!
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
+ \return Pointer to the value if it can be resolved. Otherwise null.
+
+ \note
+ There are only 3 situations when a value cannot be resolved:
+ 1. A value in the path is not an array nor object.
+ 2. An object value does not contain the token.
+ 3. A token is out of range of an array value.
+
+ Use unresolvedTokenIndex to retrieve the token index.
+ */
+ ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
+ RAPIDJSON_ASSERT(IsValid());
+ ValueType* v = &root;
+ for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
+ switch (v->GetType()) {
+ case kObjectType:
+ {
+ typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ if (m == v->MemberEnd())
+ break;
+ v = &m->value;
+ }
+ continue;
+ case kArrayType:
+ if (t->index == kPointerInvalidIndex || t->index >= v->Size())
+ break;
+ v = &((*v)[t->index]);
+ continue;
+ default:
+ break;
+ }
+
+ // Error: unresolved token
+ if (unresolvedTokenIndex)
+ *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
+ return 0;
+ }
+ return v;
+ }
+
+ //! Query a const value in a const subtree.
+ /*!
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \return Pointer to the value if it can be resolved. Otherwise null.
+ */
+ const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
+ return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
+ }
+
+ //@}
+
+ //!@name Query a value with default
+ //@{
+
+ //! Query a value in a subtree with default value.
+ /*!
+ Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value.
+ So that this function always succeed.
+
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \param defaultValue Default value to be cloned if the value was not exists.
+ \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+ \see Create()
+ */
+ ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
+ bool alreadyExist;
+ Value& v = Create(root, allocator, &alreadyExist);
+ return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
+ }
+
+ //! Query a value in a subtree with default null-terminated string.
+ ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
+ bool alreadyExist;
+ Value& v = Create(root, allocator, &alreadyExist);
+ return alreadyExist ? v : v.SetString(defaultValue, allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Query a value in a subtree with default std::basic_string.
+ ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
+ bool alreadyExist;
+ Value& v = Create(root, allocator, &alreadyExist);
+ return alreadyExist ? v : v.SetString(defaultValue, allocator);
+ }
+#endif
+
+ //! Query a value in a subtree with default primitive value.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+ GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {
+ return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);
+ }
+
+ //! Query a value in a document with default value.
+ template <typename stackAllocator>
+ ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+
+ //! Query a value in a document with default null-terminated string.
+ template <typename stackAllocator>
+ ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Query a value in a document with default std::basic_string.
+ template <typename stackAllocator>
+ ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+#endif
+
+ //! Query a value in a document with default primitive value.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+ */
+ template <typename T, typename stackAllocator>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+ GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+
+ //@}
+
+ //!@name Set a value
+ //@{
+
+ //! Set a value in a subtree, with move semantics.
+ /*!
+ It creates all parents if they are not exist or types are different to the tokens.
+ So this function always succeeds but potentially remove existing values.
+
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \param value Value to be set.
+ \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+ \see Create()
+ */
+ ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = value;
+ }
+
+ //! Set a value in a subtree, with copy semantics.
+ ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator).CopyFrom(value, allocator);
+ }
+
+ //! Set a null-terminated string in a subtree.
+ ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = ValueType(value, allocator).Move();
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Set a std::basic_string in a subtree.
+ ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = ValueType(value, allocator).Move();
+ }
+#endif
+
+ //! Set a primitive value in a subtree.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+ Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = ValueType(value).Move();
+ }
+
+ //! Set a value in a document, with move semantics.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
+ return Create(document) = value;
+ }
+
+ //! Set a value in a document, with copy semantics.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const {
+ return Create(document).CopyFrom(value, document.GetAllocator());
+ }
+
+ //! Set a null-terminated string in a document.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const {
+ return Create(document) = ValueType(value, document.GetAllocator()).Move();
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Sets a std::basic_string in a document.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const {
+ return Create(document) = ValueType(value, document.GetAllocator()).Move();
+ }
+#endif
+
+ //! Set a primitive value in a document.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+ */
+ template <typename T, typename stackAllocator>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+ Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {
+ return Create(document) = value;
+ }
+
+ //@}
+
+ //!@name Swap a value
+ //@{
+
+ //! Swap a value with a value in a subtree.
+ /*!
+ It creates all parents if they are not exist or types are different to the tokens.
+ So this function always succeeds but potentially remove existing values.
+
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \param value Value to be swapped.
+ \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+ \see Create()
+ */
+ ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator).Swap(value);
+ }
+
+ //! Swap a value with a value in a document.
+ template <typename stackAllocator>
+ ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
+ return Create(document).Swap(value);
+ }
+
+ //@}
+
+ //! Erase a value in a subtree.
+ /*!
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \return Whether the resolved value is found and erased.
+
+ \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false.
+ */
+ bool Erase(ValueType& root) const {
+ RAPIDJSON_ASSERT(IsValid());
+ if (tokenCount_ == 0) // Cannot erase the root
+ return false;
+
+ ValueType* v = &root;
+ const Token* last = tokens_ + (tokenCount_ - 1);
+ for (const Token *t = tokens_; t != last; ++t) {
+ switch (v->GetType()) {
+ case kObjectType:
+ {
+ typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ if (m == v->MemberEnd())
+ return false;
+ v = &m->value;
+ }
+ break;
+ case kArrayType:
+ if (t->index == kPointerInvalidIndex || t->index >= v->Size())
+ return false;
+ v = &((*v)[t->index]);
+ break;
+ default:
+ return false;
+ }
+ }
+
+ switch (v->GetType()) {
+ case kObjectType:
+ return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));
+ case kArrayType:
+ if (last->index == kPointerInvalidIndex || last->index >= v->Size())
+ return false;
+ v->Erase(v->Begin() + last->index);
+ return true;
+ default:
+ return false;
+ }
+ }
+
+private:
+ //! Clone the content from rhs to this.
+ /*!
+ \param rhs Source pointer.
+ \param extraToken Extra tokens to be allocated.
+ \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated.
+ \return Start of non-occupied name buffer, for storing extra names.
+ */
+ Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {
+ if (!allocator_) // allocator is independently owned.
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+ size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
+ for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
+ nameBufferSize += t->length;
+
+ tokenCount_ = rhs.tokenCount_ + extraToken;
+ tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
+ nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
+ if (rhs.tokenCount_ > 0) {
+ std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
+ }
+ if (nameBufferSize > 0) {
+ std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
+ }
+
+ // Adjust pointers to name buffer
+ std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
+ for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
+ t->name += diff;
+
+ return nameBuffer_ + nameBufferSize;
+ }
+
+ //! Check whether a character should be percent-encoded.
+ /*!
+ According to RFC 3986 2.3 Unreserved Characters.
+ \param c The character (code unit) to be tested.
+ */
+ bool NeedPercentEncode(Ch c) const {
+ return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~');
+ }
+
+ //! Parse a JSON String or its URI fragment representation into tokens.
+#ifndef __clang__ // -Wdocumentation
+ /*!
+ \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated.
+ \param length Length of the source string.
+ \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped.
+ */
+#endif
+ void Parse(const Ch* source, size_t length) {
+ RAPIDJSON_ASSERT(source != NULL);
+ RAPIDJSON_ASSERT(nameBuffer_ == 0);
+ RAPIDJSON_ASSERT(tokens_ == 0);
+
+ // Create own allocator if user did not supply.
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+ // Count number of '/' as tokenCount
+ tokenCount_ = 0;
+ for (const Ch* s = source; s != source + length; s++)
+ if (*s == '/')
+ tokenCount_++;
+
+ Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));
+ Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
+ size_t i = 0;
+
+ // Detect if it is a URI fragment
+ bool uriFragment = false;
+ if (source[i] == '#') {
+ uriFragment = true;
+ i++;
+ }
+
+ if (i != length && source[i] != '/') {
+ parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;
+ goto error;
+ }
+
+ while (i < length) {
+ RAPIDJSON_ASSERT(source[i] == '/');
+ i++; // consumes '/'
+
+ token->name = name;
+ bool isNumber = true;
+
+ while (i < length && source[i] != '/') {
+ Ch c = source[i];
+ if (uriFragment) {
+ // Decoding percent-encoding for URI fragment
+ if (c == '%') {
+ PercentDecodeStream is(&source[i], source + length);
+ GenericInsituStringStream<EncodingType> os(name);
+ Ch* begin = os.PutBegin();
+ if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) {
+ parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding;
+ goto error;
+ }
+ size_t len = os.PutEnd(begin);
+ i += is.Tell() - 1;
+ if (len == 1)
+ c = *name;
+ else {
+ name += len;
+ isNumber = false;
+ i++;
+ continue;
+ }
+ }
+ else if (NeedPercentEncode(c)) {
+ parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode;
+ goto error;
+ }
+ }
+
+ i++;
+
+ // Escaping "~0" -> '~', "~1" -> '/'
+ if (c == '~') {
+ if (i < length) {
+ c = source[i];
+ if (c == '0') c = '~';
+ else if (c == '1') c = '/';
+ else {
+ parseErrorCode_ = kPointerParseErrorInvalidEscape;
+ goto error;
+ }
+ i++;
+ }
+ else {
+ parseErrorCode_ = kPointerParseErrorInvalidEscape;
+ goto error;
+ }
+ }
+
+ // First check for index: all of characters are digit
+ if (c < '0' || c > '9')
+ isNumber = false;
+
+ *name++ = c;
+ }
+ token->length = static_cast<SizeType>(name - token->name);
+ if (token->length == 0)
+ isNumber = false;
+ *name++ = '\0'; // Null terminator
+
+ // Second check for index: more than one digit cannot have leading zero
+ if (isNumber && token->length > 1 && token->name[0] == '0')
+ isNumber = false;
+
+ // String to SizeType conversion
+ SizeType n = 0;
+ if (isNumber) {
+ for (size_t j = 0; j < token->length; j++) {
+ SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');
+ if (m < n) { // overflow detection
+ isNumber = false;
+ break;
+ }
+ n = m;
+ }
+ }
+
+ token->index = isNumber ? n : kPointerInvalidIndex;
+ token++;
+ }
+
+ RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
+ parseErrorCode_ = kPointerParseErrorNone;
+ return;
+
+ error:
+ Allocator::Free(tokens_);
+ nameBuffer_ = 0;
+ tokens_ = 0;
+ tokenCount_ = 0;
+ parseErrorOffset_ = i;
+ return;
+ }
+
+ //! Stringify to string or URI fragment representation.
+ /*!
+ \tparam uriFragment True for stringifying to URI fragment representation. False for string representation.
+ \tparam OutputStream type of output stream.
+ \param os The output stream.
+ */
+ template<bool uriFragment, typename OutputStream>
+ bool Stringify(OutputStream& os) const {
+ RAPIDJSON_ASSERT(IsValid());
+
+ if (uriFragment)
+ os.Put('#');
+
+ for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
+ os.Put('/');
+ for (size_t j = 0; j < t->length; j++) {
+ Ch c = t->name[j];
+ if (c == '~') {
+ os.Put('~');
+ os.Put('0');
+ }
+ else if (c == '/') {
+ os.Put('~');
+ os.Put('1');
+ }
+ else if (uriFragment && NeedPercentEncode(c)) {
+ // Transcode to UTF8 sequence
+ GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]);
+ PercentEncodeStream<OutputStream> target(os);
+ if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target))
+ return false;
+ j += source.Tell() - 1;
+ }
+ else
+ os.Put(c);
+ }
+ }
+ return true;
+ }
+
+ //! A helper stream for decoding a percent-encoded sequence into code unit.
+ /*!
+ This stream decodes %XY triplet into code unit (0-255).
+ If it encounters invalid characters, it sets output code unit as 0 and
+ mark invalid, and to be checked by IsValid().
+ */
+ class PercentDecodeStream {
+ public:
+ typedef typename ValueType::Ch Ch;
+
+ //! Constructor
+ /*!
+ \param source Start of the stream
+ \param end Past-the-end of the stream.
+ */
+ PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}
+
+ Ch Take() {
+ if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet
+ valid_ = false;
+ return 0;
+ }
+ src_++;
+ Ch c = 0;
+ for (int j = 0; j < 2; j++) {
+ c = static_cast<Ch>(c << 4);
+ Ch h = *src_;
+ if (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0');
+ else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10);
+ else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10);
+ else {
+ valid_ = false;
+ return 0;
+ }
+ src_++;
+ }
+ return c;
+ }
+
+ size_t Tell() const { return static_cast<size_t>(src_ - head_); }
+ bool IsValid() const { return valid_; }
+
+ private:
+ const Ch* src_; //!< Current read position.
+ const Ch* head_; //!< Original head of the string.
+ const Ch* end_; //!< Past-the-end position.
+ bool valid_; //!< Whether the parsing is valid.
+ };
+
+ //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.
+ template <typename OutputStream>
+ class PercentEncodeStream {
+ public:
+ PercentEncodeStream(OutputStream& os) : os_(os) {}
+ void Put(char c) { // UTF-8 must be byte
+ unsigned char u = static_cast<unsigned char>(c);
+ static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ os_.Put('%');
+ os_.Put(hexDigits[u >> 4]);
+ os_.Put(hexDigits[u & 15]);
+ }
+ private:
+ OutputStream& os_;
+ };
+
+ Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
+ Allocator* ownAllocator_; //!< Allocator owned by this Pointer.
+ Ch* nameBuffer_; //!< A buffer containing all names in tokens.
+ Token* tokens_; //!< A list of tokens.
+ size_t tokenCount_; //!< Number of tokens in tokens_.
+ size_t parseErrorOffset_; //!< Offset in code unit when parsing fail.
+ PointerParseErrorCode parseErrorCode_; //!< Parsing error code.
+};
+
+//! GenericPointer for Value (UTF-8, default allocator).
+typedef GenericPointer<Value> Pointer;
+
+//!@name Helper functions for GenericPointer
+//@{
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {
+ return pointer.Create(root, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {
+ return pointer.Create(document);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
+ return pointer.Get(root, unresolvedTokenIndex);
+}
+
+template <typename T>
+const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
+ return pointer.Get(root, unresolvedTokenIndex);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
+}
+
+template <typename T, typename CharType, size_t N>
+const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+#endif
+
+template <typename T, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+#endif
+
+template <typename T, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+#endif
+
+template <typename DocumentType, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+#endif
+
+template <typename DocumentType, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+#endif
+
+template <typename T, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+#endif
+
+template <typename T, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
+ return pointer.Set(document, value);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {
+ return pointer.Set(document, value);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) {
+ return pointer.Set(document, value);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) {
+ return pointer.Set(document, value);
+}
+#endif
+
+template <typename DocumentType, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {
+ return pointer.Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+#endif
+
+template <typename DocumentType, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
+ return pointer.Swap(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
+ return pointer.Swap(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
+ return pointer.Erase(root);
+}
+
+template <typename T, typename CharType, size_t N>
+bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
+}
+
+//@}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_POINTER_H_
diff --git a/external/rapidjson/rapidjson/prettywriter.h b/external/rapidjson/rapidjson/prettywriter.h
new file mode 100644
index 0000000..abd964f
--- /dev/null
+++ b/external/rapidjson/rapidjson/prettywriter.h
@@ -0,0 +1,275 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_PRETTYWRITER_H_
+#define RAPIDJSON_PRETTYWRITER_H_
+
+#include "writer.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Combination of PrettyWriter format flags.
+/*! \see PrettyWriter::SetFormatOptions
+ */
+enum PrettyFormatOptions {
+ kFormatDefault = 0, //!< Default pretty formatting.
+ kFormatSingleLineArray = 1 //!< Format arrays on a single line.
+};
+
+//! Writer with indentation and spacing.
+/*!
+ \tparam OutputStream Type of ouptut os.
+ \tparam SourceEncoding Encoding of source string.
+ \tparam TargetEncoding Encoding of output stream.
+ \tparam StackAllocator Type of allocator for allocating memory of stack.
+*/
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
+class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
+public:
+ typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
+ typedef typename Base::Ch Ch;
+
+ //! Constructor
+ /*! \param os Output stream.
+ \param allocator User supplied allocator. If it is null, it will create a private one.
+ \param levelDepth Initial capacity of stack.
+ */
+ explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
+ Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
+
+
+ explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
+ Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ PrettyWriter(PrettyWriter&& rhs) :
+ Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
+#endif
+
+ //! Set custom indentation.
+ /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
+ \param indentCharCount Number of indent characters for each indentation level.
+ \note The default indentation is 4 spaces.
+ */
+ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
+ RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
+ indentChar_ = indentChar;
+ indentCharCount_ = indentCharCount;
+ return *this;
+ }
+
+ //! Set pretty writer formatting options.
+ /*! \param options Formatting options.
+ */
+ PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
+ formatOptions_ = options;
+ return *this;
+ }
+
+ /*! @name Implementation of Handler
+ \see Handler
+ */
+ //@{
+
+ bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
+ bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
+ bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
+ bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
+ bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
+ bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
+ bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
+
+ bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
+ RAPIDJSON_ASSERT(str != 0);
+ (void)copy;
+ PrettyPrefix(kNumberType);
+ return Base::WriteString(str, length);
+ }
+
+ bool String(const Ch* str, SizeType length, bool copy = false) {
+ RAPIDJSON_ASSERT(str != 0);
+ (void)copy;
+ PrettyPrefix(kStringType);
+ return Base::WriteString(str, length);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool String(const std::basic_string<Ch>& str) {
+ return String(str.data(), SizeType(str.size()));
+ }
+#endif
+
+ bool StartObject() {
+ PrettyPrefix(kObjectType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
+ return Base::WriteStartObject();
+ }
+
+ bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool Key(const std::basic_string<Ch>& str) {
+ return Key(str.data(), SizeType(str.size()));
+ }
+#endif
+
+ bool EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+ RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+ if (!empty) {
+ Base::os_->Put('\n');
+ WriteIndent();
+ }
+ bool ret = Base::WriteEndObject();
+ (void)ret;
+ RAPIDJSON_ASSERT(ret == true);
+ if (Base::level_stack_.Empty()) // end of json text
+ Base::os_->Flush();
+ return true;
+ }
+
+ bool StartArray() {
+ PrettyPrefix(kArrayType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
+ return Base::WriteStartArray();
+ }
+
+ bool EndArray(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+ RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+ if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
+ Base::os_->Put('\n');
+ WriteIndent();
+ }
+ bool ret = Base::WriteEndArray();
+ (void)ret;
+ RAPIDJSON_ASSERT(ret == true);
+ if (Base::level_stack_.Empty()) // end of json text
+ Base::os_->Flush();
+ return true;
+ }
+
+ //@}
+
+ /*! @name Convenience extensions */
+ //@{
+
+ //! Simpler but slower overload.
+ bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
+ bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
+
+ //@}
+
+ //! Write a raw JSON value.
+ /*!
+ For user to write a stringified JSON as a value.
+
+ \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
+ \param length Length of the json.
+ \param type Type of the root of json.
+ \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
+ */
+ bool RawValue(const Ch* json, size_t length, Type type) {
+ RAPIDJSON_ASSERT(json != 0);
+ PrettyPrefix(type);
+ return Base::WriteRawValue(json, length);
+ }
+
+protected:
+ void PrettyPrefix(Type type) {
+ (void)type;
+ if (Base::level_stack_.GetSize() != 0) { // this value is not at root
+ typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
+
+ if (level->inArray) {
+ if (level->valueCount > 0) {
+ Base::os_->Put(','); // add comma if it is not the first element in array
+ if (formatOptions_ & kFormatSingleLineArray)
+ Base::os_->Put(' ');
+ }
+
+ if (!(formatOptions_ & kFormatSingleLineArray)) {
+ Base::os_->Put('\n');
+ WriteIndent();
+ }
+ }
+ else { // in object
+ if (level->valueCount > 0) {
+ if (level->valueCount % 2 == 0) {
+ Base::os_->Put(',');
+ Base::os_->Put('\n');
+ }
+ else {
+ Base::os_->Put(':');
+ Base::os_->Put(' ');
+ }
+ }
+ else
+ Base::os_->Put('\n');
+
+ if (level->valueCount % 2 == 0)
+ WriteIndent();
+ }
+ if (!level->inArray && level->valueCount % 2 == 0)
+ RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
+ level->valueCount++;
+ }
+ else {
+ RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
+ Base::hasRoot_ = true;
+ }
+ }
+
+ void WriteIndent() {
+ size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
+ PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
+ }
+
+ Ch indentChar_;
+ unsigned indentCharCount_;
+ PrettyFormatOptions formatOptions_;
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ PrettyWriter(const PrettyWriter&);
+ PrettyWriter& operator=(const PrettyWriter&);
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/external/rapidjson/rapidjson/rapidjson.h b/external/rapidjson/rapidjson/rapidjson.h
new file mode 100644
index 0000000..053b2ce
--- /dev/null
+++ b/external/rapidjson/rapidjson/rapidjson.h
@@ -0,0 +1,615 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_RAPIDJSON_H_
+#define RAPIDJSON_RAPIDJSON_H_
+
+/*!\file rapidjson.h
+ \brief common definitions and configuration
+
+ \see RAPIDJSON_CONFIG
+ */
+
+/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration
+ \brief Configuration macros for library features
+
+ Some RapidJSON features are configurable to adapt the library to a wide
+ variety of platforms, environments and usage scenarios. Most of the
+ features can be configured in terms of overriden or predefined
+ preprocessor macros at compile-time.
+
+ Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
+
+ \note These macros should be given on the compiler command-line
+ (where applicable) to avoid inconsistent values when compiling
+ different translation units of a single application.
+ */
+
+#include <cstdlib> // malloc(), realloc(), free(), size_t
+#include <cstring> // memset(), memcpy(), memmove(), memcmp()
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_VERSION_STRING
+//
+// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
+//
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+// token stringification
+#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
+#define RAPIDJSON_DO_STRINGIFY(x) #x
+//!@endcond
+
+/*! \def RAPIDJSON_MAJOR_VERSION
+ \ingroup RAPIDJSON_CONFIG
+ \brief Major version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_MINOR_VERSION
+ \ingroup RAPIDJSON_CONFIG
+ \brief Minor version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_PATCH_VERSION
+ \ingroup RAPIDJSON_CONFIG
+ \brief Patch version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_VERSION_STRING
+ \ingroup RAPIDJSON_CONFIG
+ \brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
+*/
+#define RAPIDJSON_MAJOR_VERSION 1
+#define RAPIDJSON_MINOR_VERSION 1
+#define RAPIDJSON_PATCH_VERSION 0
+#define RAPIDJSON_VERSION_STRING \
+ RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NAMESPACE_(BEGIN|END)
+/*! \def RAPIDJSON_NAMESPACE
+ \ingroup RAPIDJSON_CONFIG
+ \brief provide custom rapidjson namespace
+
+ In order to avoid symbol clashes and/or "One Definition Rule" errors
+ between multiple inclusions of (different versions of) RapidJSON in
+ a single binary, users can customize the name of the main RapidJSON
+ namespace.
+
+ In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
+ to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple
+ levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
+ RAPIDJSON_NAMESPACE_END need to be defined as well:
+
+ \code
+ // in some .cpp file
+ #define RAPIDJSON_NAMESPACE my::rapidjson
+ #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
+ #define RAPIDJSON_NAMESPACE_END } }
+ #include "rapidjson/..."
+ \endcode
+
+ \see rapidjson
+ */
+/*! \def RAPIDJSON_NAMESPACE_BEGIN
+ \ingroup RAPIDJSON_CONFIG
+ \brief provide custom rapidjson namespace (opening expression)
+ \see RAPIDJSON_NAMESPACE
+*/
+/*! \def RAPIDJSON_NAMESPACE_END
+ \ingroup RAPIDJSON_CONFIG
+ \brief provide custom rapidjson namespace (closing expression)
+ \see RAPIDJSON_NAMESPACE
+*/
+#ifndef RAPIDJSON_NAMESPACE
+#define RAPIDJSON_NAMESPACE rapidjson
+#endif
+#ifndef RAPIDJSON_NAMESPACE_BEGIN
+#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
+#endif
+#ifndef RAPIDJSON_NAMESPACE_END
+#define RAPIDJSON_NAMESPACE_END }
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_HAS_STDSTRING
+
+#ifndef RAPIDJSON_HAS_STDSTRING
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
+#else
+#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
+#endif
+/*! \def RAPIDJSON_HAS_STDSTRING
+ \ingroup RAPIDJSON_CONFIG
+ \brief Enable RapidJSON support for \c std::string
+
+ By defining this preprocessor symbol to \c 1, several convenience functions for using
+ \ref rapidjson::GenericValue with \c std::string are enabled, especially
+ for construction and comparison.
+
+ \hideinitializer
+*/
+#endif // !defined(RAPIDJSON_HAS_STDSTRING)
+
+#if RAPIDJSON_HAS_STDSTRING
+#include <string>
+#endif // RAPIDJSON_HAS_STDSTRING
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_INT64DEFINE
+
+/*! \def RAPIDJSON_NO_INT64DEFINE
+ \ingroup RAPIDJSON_CONFIG
+ \brief Use external 64-bit integer types.
+
+ RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types
+ to be available at global scope.
+
+ If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to
+ prevent RapidJSON from defining its own types.
+*/
+#ifndef RAPIDJSON_NO_INT64DEFINE
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
+#include "msinttypes/stdint.h"
+#include "msinttypes/inttypes.h"
+#else
+// Other compilers should have this.
+#include <stdint.h>
+#include <inttypes.h>
+#endif
+//!@endcond
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_NO_INT64DEFINE
+#endif
+#endif // RAPIDJSON_NO_INT64TYPEDEF
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_FORCEINLINE
+
+#ifndef RAPIDJSON_FORCEINLINE
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#if defined(_MSC_VER) && defined(NDEBUG)
+#define RAPIDJSON_FORCEINLINE __forceinline
+#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)
+#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
+#else
+#define RAPIDJSON_FORCEINLINE
+#endif
+//!@endcond
+#endif // RAPIDJSON_FORCEINLINE
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ENDIAN
+#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
+#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
+
+//! Endianness of the machine.
+/*!
+ \def RAPIDJSON_ENDIAN
+ \ingroup RAPIDJSON_CONFIG
+
+ GCC 4.6 provided macro for detecting endianness of the target machine. But other
+ compilers may not have this. User can define RAPIDJSON_ENDIAN to either
+ \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
+
+ Default detection implemented with reference to
+ \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
+ \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
+*/
+#ifndef RAPIDJSON_ENDIAN
+// Detect with GCC 4.6's macro
+# ifdef __BYTE_ORDER__
+# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+# else
+# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# endif // __BYTE_ORDER__
+// Detect with GLIBC's endian.h
+# elif defined(__GLIBC__)
+# include <endian.h>
+# if (__BYTE_ORDER == __LITTLE_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif (__BYTE_ORDER == __BIG_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+# else
+# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# endif // __GLIBC__
+// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
+# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+// Detect with architecture macros
+# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif defined(_MSC_VER) && defined(_M_ARM)
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
+# define RAPIDJSON_ENDIAN
+# else
+# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# endif
+#endif // RAPIDJSON_ENDIAN
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_64BIT
+
+//! Whether using 64-bit architecture
+#ifndef RAPIDJSON_64BIT
+#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__)
+#define RAPIDJSON_64BIT 1
+#else
+#define RAPIDJSON_64BIT 0
+#endif
+#endif // RAPIDJSON_64BIT
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ALIGN
+
+//! Data alignment of the machine.
+/*! \ingroup RAPIDJSON_CONFIG
+ \param x pointer to align
+
+ Some machines require strict data alignment. Currently the default uses 4 bytes
+ alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
+ User can customize by defining the RAPIDJSON_ALIGN function macro.
+*/
+#ifndef RAPIDJSON_ALIGN
+#if RAPIDJSON_64BIT == 1
+#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
+#else
+#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
+#endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_UINT64_C2
+
+//! Construct a 64-bit literal by a pair of 32-bit integer.
+/*!
+ 64-bit literal with or without ULL suffix is prone to compiler warnings.
+ UINT64_C() is C macro which cause compilation problems.
+ Use this macro to define 64-bit constants by a pair of 32-bit integer.
+*/
+#ifndef RAPIDJSON_UINT64_C2
+#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_48BITPOINTER_OPTIMIZATION
+
+//! Use only lower 48-bit address for some pointers.
+/*!
+ \ingroup RAPIDJSON_CONFIG
+
+ This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
+ The higher 16-bit can be used for storing other data.
+ \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
+*/
+#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
+#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
+#else
+#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
+#endif
+#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
+
+#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
+#if RAPIDJSON_64BIT != 1
+#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
+#endif
+#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
+#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
+#else
+#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
+#define RAPIDJSON_GETPOINTER(type, p) (p)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
+
+/*! \def RAPIDJSON_SIMD
+ \ingroup RAPIDJSON_CONFIG
+ \brief Enable SSE2/SSE4.2 optimization.
+
+ RapidJSON supports optimized implementations for some parsing operations
+ based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible
+ processors.
+
+ To enable these optimizations, two different symbols can be defined;
+ \code
+ // Enable SSE2 optimization.
+ #define RAPIDJSON_SSE2
+
+ // Enable SSE4.2 optimization.
+ #define RAPIDJSON_SSE42
+ \endcode
+
+ \c RAPIDJSON_SSE42 takes precedence, if both are defined.
+
+ If any of these symbols is defined, RapidJSON defines the macro
+ \c RAPIDJSON_SIMD to indicate the availability of the optimized code.
+*/
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
+ || defined(RAPIDJSON_DOXYGEN_RUNNING)
+#define RAPIDJSON_SIMD
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_SIZETYPEDEFINE
+
+#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
+/*! \def RAPIDJSON_NO_SIZETYPEDEFINE
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-provided \c SizeType definition.
+
+ In order to avoid using 32-bit size types for indexing strings and arrays,
+ define this preprocessor symbol and provide the type rapidjson::SizeType
+ before including RapidJSON:
+ \code
+ #define RAPIDJSON_NO_SIZETYPEDEFINE
+ namespace rapidjson { typedef ::std::size_t SizeType; }
+ #include "rapidjson/..."
+ \endcode
+
+ \see rapidjson::SizeType
+*/
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_NO_SIZETYPEDEFINE
+#endif
+RAPIDJSON_NAMESPACE_BEGIN
+//! Size type (for string lengths, array sizes, etc.)
+/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
+ instead of using \c size_t. Users may override the SizeType by defining
+ \ref RAPIDJSON_NO_SIZETYPEDEFINE.
+*/
+typedef unsigned SizeType;
+RAPIDJSON_NAMESPACE_END
+#endif
+
+// always import std::size_t to rapidjson namespace
+RAPIDJSON_NAMESPACE_BEGIN
+using std::size_t;
+RAPIDJSON_NAMESPACE_END
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ASSERT
+
+//! Assertion.
+/*! \ingroup RAPIDJSON_CONFIG
+ By default, rapidjson uses C \c assert() for internal assertions.
+ User can override it by defining RAPIDJSON_ASSERT(x) macro.
+
+ \note Parsing errors are handled and can be customized by the
+ \ref RAPIDJSON_ERRORS APIs.
+*/
+#ifndef RAPIDJSON_ASSERT
+#include <cassert>
+#define RAPIDJSON_ASSERT(x) assert(x)
+#endif // RAPIDJSON_ASSERT
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_STATIC_ASSERT
+
+// Adopt from boost
+#ifndef RAPIDJSON_STATIC_ASSERT
+#ifndef __clang__
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#endif
+RAPIDJSON_NAMESPACE_BEGIN
+template <bool x> struct STATIC_ASSERTION_FAILURE;
+template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
+template<int x> struct StaticAssertTest {};
+RAPIDJSON_NAMESPACE_END
+
+#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
+#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
+#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
+
+#if defined(__GNUC__)
+#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
+#else
+#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
+#endif
+#ifndef __clang__
+//!@endcond
+#endif
+
+/*! \def RAPIDJSON_STATIC_ASSERT
+ \brief (Internal) macro to check for conditions at compile-time
+ \param x compile-time condition
+ \hideinitializer
+ */
+#define RAPIDJSON_STATIC_ASSERT(x) \
+ typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
+ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
+ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
+
+//! Compiler branching hint for expression with high probability to be true.
+/*!
+ \ingroup RAPIDJSON_CONFIG
+ \param x Boolean expression likely to be true.
+*/
+#ifndef RAPIDJSON_LIKELY
+#if defined(__GNUC__) || defined(__clang__)
+#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
+#else
+#define RAPIDJSON_LIKELY(x) (x)
+#endif
+#endif
+
+//! Compiler branching hint for expression with low probability to be true.
+/*!
+ \ingroup RAPIDJSON_CONFIG
+ \param x Boolean expression unlikely to be true.
+*/
+#ifndef RAPIDJSON_UNLIKELY
+#if defined(__GNUC__) || defined(__clang__)
+#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define RAPIDJSON_UNLIKELY(x) (x)
+#endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+
+#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
+#define RAPIDJSON_MULTILINEMACRO_END \
+} while((void)0, 0)
+
+// adopted from Boost
+#define RAPIDJSON_VERSION_CODE(x,y,z) \
+ (((x)*100000) + ((y)*100) + (z))
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
+
+#if defined(__GNUC__)
+#define RAPIDJSON_GNUC \
+ RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
+#endif
+
+#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
+
+#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
+#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
+#define RAPIDJSON_DIAG_OFF(x) \
+ RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
+
+// push/pop support in Clang and GCC>=4.6
+#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
+#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
+#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
+#else // GCC >= 4.2, < 4.6
+#define RAPIDJSON_DIAG_PUSH /* ignored */
+#define RAPIDJSON_DIAG_POP /* ignored */
+#endif
+
+#elif defined(_MSC_VER)
+
+// pragma (MSVC specific)
+#define RAPIDJSON_PRAGMA(x) __pragma(x)
+#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
+
+#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
+#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
+#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
+
+#else
+
+#define RAPIDJSON_DIAG_OFF(x) /* ignored */
+#define RAPIDJSON_DIAG_PUSH /* ignored */
+#define RAPIDJSON_DIAG_POP /* ignored */
+
+#endif // RAPIDJSON_DIAG_*
+
+///////////////////////////////////////////////////////////////////////////////
+// C++11 features
+
+#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#if defined(__clang__)
+#if __has_feature(cxx_rvalue_references) && \
+ (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
+#else
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
+#endif
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1600)
+
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
+#else
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
+#endif
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
+#if defined(__clang__)
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
+// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
+#else
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
+#endif
+#endif
+#if RAPIDJSON_HAS_CXX11_NOEXCEPT
+#define RAPIDJSON_NOEXCEPT noexcept
+#else
+#define RAPIDJSON_NOEXCEPT /* noexcept */
+#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
+
+// no automatic detection, yet
+#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
+#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
+#endif
+
+#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
+#if defined(__clang__)
+#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1700)
+#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
+#else
+#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
+#endif
+#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
+
+//!@endcond
+
+///////////////////////////////////////////////////////////////////////////////
+// new/delete
+
+#ifndef RAPIDJSON_NEW
+///! customization point for global \c new
+#define RAPIDJSON_NEW(x) new x
+#endif
+#ifndef RAPIDJSON_DELETE
+///! customization point for global \c delete
+#define RAPIDJSON_DELETE(x) delete x
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Type
+
+/*! \namespace rapidjson
+ \brief main RapidJSON namespace
+ \see RAPIDJSON_NAMESPACE
+*/
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Type of JSON value
+enum Type {
+ kNullType = 0, //!< null
+ kFalseType = 1, //!< false
+ kTrueType = 2, //!< true
+ kObjectType = 3, //!< object
+ kArrayType = 4, //!< array
+ kStringType = 5, //!< string
+ kNumberType = 6 //!< number
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/external/rapidjson/rapidjson/reader.h b/external/rapidjson/rapidjson/reader.h
new file mode 100644
index 0000000..a8cee36
--- /dev/null
+++ b/external/rapidjson/rapidjson/reader.h
@@ -0,0 +1,1865 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_READER_H_
+#define RAPIDJSON_READER_H_
+
+/*! \file reader.h */
+
+#include "allocators.h"
+#include "stream.h"
+#include "encodedstream.h"
+#include "internal/meta.h"
+#include "internal/stack.h"
+#include "internal/strtod.h"
+#include <limits>
+
+#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(_BitScanForward)
+#endif
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(old-style-cast)
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define RAPIDJSON_NOTHING /* deliberately empty */
+#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
+#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
+//!@endcond
+
+/*! \def RAPIDJSON_PARSE_ERROR_NORETURN
+ \ingroup RAPIDJSON_ERRORS
+ \brief Macro to indicate a parse error.
+ \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
+ \param offset position of the error in JSON input (\c size_t)
+
+ This macros can be used as a customization point for the internal
+ error handling mechanism of RapidJSON.
+
+ A common usage model is to throw an exception instead of requiring the
+ caller to explicitly check the \ref rapidjson::GenericReader::Parse's
+ return value:
+
+ \code
+ #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \
+ throw ParseException(parseErrorCode, #parseErrorCode, offset)
+
+ #include <stdexcept> // std::runtime_error
+ #include "rapidjson/error/error.h" // rapidjson::ParseResult
+
+ struct ParseException : std::runtime_error, rapidjson::ParseResult {
+ ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset)
+ : std::runtime_error(msg), ParseResult(code, offset) {}
+ };
+
+ #include "rapidjson/reader.h"
+ \endcode
+
+ \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse
+ */
+#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
+#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
+ SetParseError(parseErrorCode, offset); \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+/*! \def RAPIDJSON_PARSE_ERROR
+ \ingroup RAPIDJSON_ERRORS
+ \brief (Internal) macro to indicate and handle a parse error.
+ \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
+ \param offset position of the error in JSON input (\c size_t)
+
+ Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing.
+
+ \see RAPIDJSON_PARSE_ERROR_NORETURN
+ \hideinitializer
+ */
+#ifndef RAPIDJSON_PARSE_ERROR
+#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+#include "error/error.h" // ParseErrorCode, ParseResult
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseFlag
+
+/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-defined kParseDefaultFlags definition.
+
+ User can define this as any \c ParseFlag combinations.
+*/
+#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
+#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags
+#endif
+
+//! Combination of parseFlags
+/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream
+ */
+enum ParseFlag {
+ kParseNoFlags = 0, //!< No flags are set.
+ kParseInsituFlag = 1, //!< In-situ(destructive) parsing.
+ kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
+ kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
+ kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
+ kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
+ kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments.
+ kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings.
+ kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.
+ kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles.
+ kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Handler
+
+/*! \class rapidjson::Handler
+ \brief Concept for receiving events from GenericReader upon parsing.
+ The functions return true if no error occurs. If they return false,
+ the event publisher should terminate the process.
+\code
+concept Handler {
+ typename Ch;
+
+ bool Null();
+ bool Bool(bool b);
+ bool Int(int i);
+ bool Uint(unsigned i);
+ bool Int64(int64_t i);
+ bool Uint64(uint64_t i);
+ bool Double(double d);
+ /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
+ bool RawNumber(const Ch* str, SizeType length, bool copy);
+ bool String(const Ch* str, SizeType length, bool copy);
+ bool StartObject();
+ bool Key(const Ch* str, SizeType length, bool copy);
+ bool EndObject(SizeType memberCount);
+ bool StartArray();
+ bool EndArray(SizeType elementCount);
+};
+\endcode
+*/
+///////////////////////////////////////////////////////////////////////////////
+// BaseReaderHandler
+
+//! Default implementation of Handler.
+/*! This can be used as base class of any reader handler.
+ \note implements Handler concept
+*/
+template<typename Encoding = UTF8<>, typename Derived = void>
+struct BaseReaderHandler {
+ typedef typename Encoding::Ch Ch;
+
+ typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override;
+
+ bool Default() { return true; }
+ bool Null() { return static_cast<Override&>(*this).Default(); }
+ bool Bool(bool) { return static_cast<Override&>(*this).Default(); }
+ bool Int(int) { return static_cast<Override&>(*this).Default(); }
+ bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }
+ bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
+ bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }
+ bool Double(double) { return static_cast<Override&>(*this).Default(); }
+ /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
+ bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
+ bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
+ bool StartObject() { return static_cast<Override&>(*this).Default(); }
+ bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
+ bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }
+ bool StartArray() { return static_cast<Override&>(*this).Default(); }
+ bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamLocalCopy
+
+namespace internal {
+
+template<typename Stream, int = StreamTraits<Stream>::copyOptimization>
+class StreamLocalCopy;
+
+//! Do copy optimization.
+template<typename Stream>
+class StreamLocalCopy<Stream, 1> {
+public:
+ StreamLocalCopy(Stream& original) : s(original), original_(original) {}
+ ~StreamLocalCopy() { original_ = s; }
+
+ Stream s;
+
+private:
+ StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
+
+ Stream& original_;
+};
+
+//! Keep reference.
+template<typename Stream>
+class StreamLocalCopy<Stream, 0> {
+public:
+ StreamLocalCopy(Stream& original) : s(original) {}
+
+ Stream& s;
+
+private:
+ StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
+};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// SkipWhitespace
+
+//! Skip the JSON white spaces in a stream.
+/*! \param is A input stream for skipping white spaces.
+ \note This function has SSE2/SSE4.2 specialization.
+*/
+template<typename InputStream>
+void SkipWhitespace(InputStream& is) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ typename InputStream::Ch c;
+ while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t')
+ s.Take();
+}
+
+inline const char* SkipWhitespace(const char* p, const char* end) {
+ while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
+ ++p;
+ return p;
+}
+
+#ifdef RAPIDJSON_SSE42
+//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ // Fast return for single non-whitespace
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // 16-byte align to the next boundary
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // The rest of string using SIMD
+ static const char whitespace[16] = " \n\r\t";
+ const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);
+ if (r != 16) // some of characters is non-whitespace
+ return p + r;
+ }
+}
+
+inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
+ // Fast return for single non-whitespace
+ if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
+ ++p;
+ else
+ return p;
+
+ // The middle of string using SIMD
+ static const char whitespace[16] = " \n\r\t";
+ const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
+
+ for (; p <= end - 16; p += 16) {
+ const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
+ const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);
+ if (r != 16) // some of characters is non-whitespace
+ return p + r;
+ }
+
+ return SkipWhitespace(p, end);
+}
+
+#elif defined(RAPIDJSON_SSE2)
+
+//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ // Fast return for single non-whitespace
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // 16-byte align to the next boundary
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // The rest of string
+ #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
+ static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
+ #undef C16
+
+ const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
+ const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
+ const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
+ const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ __m128i x = _mm_cmpeq_epi8(s, w0);
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
+ unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
+ if (r != 0) { // some of characters may be non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ return p + offset;
+#else
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+}
+
+inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
+ // Fast return for single non-whitespace
+ if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
+ ++p;
+ else
+ return p;
+
+ // The rest of string
+ #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
+ static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
+ #undef C16
+
+ const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
+ const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
+ const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
+ const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
+
+ for (; p <= end - 16; p += 16) {
+ const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
+ __m128i x = _mm_cmpeq_epi8(s, w0);
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
+ unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
+ if (r != 0) { // some of characters may be non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ return p + offset;
+#else
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+
+ return SkipWhitespace(p, end);
+}
+
+#endif // RAPIDJSON_SSE2
+
+#ifdef RAPIDJSON_SIMD
+//! Template function specialization for InsituStringStream
+template<> inline void SkipWhitespace(InsituStringStream& is) {
+ is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
+}
+
+//! Template function specialization for StringStream
+template<> inline void SkipWhitespace(StringStream& is) {
+ is.src_ = SkipWhitespace_SIMD(is.src_);
+}
+
+template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& is) {
+ is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_);
+}
+#endif // RAPIDJSON_SIMD
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericReader
+
+//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator.
+/*! GenericReader parses JSON text from a stream, and send events synchronously to an
+ object implementing Handler concept.
+
+ It needs to allocate a stack for storing a single decoded string during
+ non-destructive parsing.
+
+ For in-situ parsing, the decoded string is directly written to the source
+ text string, no temporary buffer is required.
+
+ A GenericReader object can be reused for parsing multiple JSON text.
+
+ \tparam SourceEncoding Encoding of the input stream.
+ \tparam TargetEncoding Encoding of the parse output.
+ \tparam StackAllocator Allocator type for stack.
+*/
+template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator>
+class GenericReader {
+public:
+ typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
+
+ //! Constructor.
+ /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
+ \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
+ */
+ GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
+
+ //! Parse JSON text.
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam InputStream Type of input stream, implementing Stream concept.
+ \tparam Handler Type of handler, implementing Handler concept.
+ \param is Input stream to be parsed.
+ \param handler The handler to receive events.
+ \return Whether the parsing is successful.
+ */
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ ParseResult Parse(InputStream& is, Handler& handler) {
+ if (parseFlags & kParseIterativeFlag)
+ return IterativeParse<parseFlags>(is, handler);
+
+ parseResult_.Clear();
+
+ ClearStackOnExit scope(*this);
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+ if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ }
+ else {
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+ if (!(parseFlags & kParseStopWhenDoneFlag)) {
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+ if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ }
+ }
+ }
+
+ return parseResult_;
+ }
+
+ //! Parse JSON text (with \ref kParseDefaultFlags)
+ /*! \tparam InputStream Type of input stream, implementing Stream concept
+ \tparam Handler Type of handler, implementing Handler concept.
+ \param is Input stream to be parsed.
+ \param handler The handler to receive events.
+ \return Whether the parsing is successful.
+ */
+ template <typename InputStream, typename Handler>
+ ParseResult Parse(InputStream& is, Handler& handler) {
+ return Parse<kParseDefaultFlags>(is, handler);
+ }
+
+ //! Whether a parse error has occured in the last parsing.
+ bool HasParseError() const { return parseResult_.IsError(); }
+
+ //! Get the \ref ParseErrorCode of last parsing.
+ ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }
+
+ //! Get the position of last parsing error in input, 0 otherwise.
+ size_t GetErrorOffset() const { return parseResult_.Offset(); }
+
+protected:
+ void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); }
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ GenericReader(const GenericReader&);
+ GenericReader& operator=(const GenericReader&);
+
+ void ClearStack() { stack_.Clear(); }
+
+ // clear stack on any exit from ParseStream, e.g. due to exception
+ struct ClearStackOnExit {
+ explicit ClearStackOnExit(GenericReader& r) : r_(r) {}
+ ~ClearStackOnExit() { r_.ClearStack(); }
+ private:
+ GenericReader& r_;
+ ClearStackOnExit(const ClearStackOnExit&);
+ ClearStackOnExit& operator=(const ClearStackOnExit&);
+ };
+
+ template<unsigned parseFlags, typename InputStream>
+ void SkipWhitespaceAndComments(InputStream& is) {
+ SkipWhitespace(is);
+
+ if (parseFlags & kParseCommentsFlag) {
+ while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {
+ if (Consume(is, '*')) {
+ while (true) {
+ if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
+ RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
+ else if (Consume(is, '*')) {
+ if (Consume(is, '/'))
+ break;
+ }
+ else
+ is.Take();
+ }
+ }
+ else if (RAPIDJSON_LIKELY(Consume(is, '/')))
+ while (is.Peek() != '\0' && is.Take() != '\n') {}
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
+
+ SkipWhitespace(is);
+ }
+ }
+ }
+
+ // Parse object: { string : value, ... }
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseObject(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == '{');
+ is.Take(); // Skip '{'
+
+ if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (Consume(is, '}')) {
+ if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ }
+
+ for (SizeType memberCount = 0;;) {
+ if (RAPIDJSON_UNLIKELY(is.Peek() != '"'))
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
+
+ ParseString<parseFlags>(is, handler, true);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ ++memberCount;
+
+ switch (is.Peek()) {
+ case ',':
+ is.Take();
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ break;
+ case '}':
+ is.Take();
+ if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ default:
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy
+ }
+
+ if (parseFlags & kParseTrailingCommasFlag) {
+ if (is.Peek() == '}') {
+ if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ is.Take();
+ return;
+ }
+ }
+ }
+ }
+
+ // Parse array: [ value, ... ]
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseArray(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == '[');
+ is.Take(); // Skip '['
+
+ if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (Consume(is, ']')) {
+ if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ }
+
+ for (SizeType elementCount = 0;;) {
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ ++elementCount;
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (Consume(is, ',')) {
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ }
+ else if (Consume(is, ']')) {
+ if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
+
+ if (parseFlags & kParseTrailingCommasFlag) {
+ if (is.Peek() == ']') {
+ if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ is.Take();
+ return;
+ }
+ }
+ }
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseNull(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 'n');
+ is.Take();
+
+ if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) {
+ if (RAPIDJSON_UNLIKELY(!handler.Null()))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseTrue(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 't');
+ is.Take();
+
+ if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) {
+ if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseFalse(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 'f');
+ is.Take();
+
+ if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) {
+ if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+ }
+
+ template<typename InputStream>
+ RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) {
+ if (RAPIDJSON_LIKELY(is.Peek() == expect)) {
+ is.Take();
+ return true;
+ }
+ else
+ return false;
+ }
+
+ // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
+ template<typename InputStream>
+ unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
+ unsigned codepoint = 0;
+ for (int i = 0; i < 4; i++) {
+ Ch c = is.Peek();
+ codepoint <<= 4;
+ codepoint += static_cast<unsigned>(c);
+ if (c >= '0' && c <= '9')
+ codepoint -= '0';
+ else if (c >= 'A' && c <= 'F')
+ codepoint -= 'A' - 10;
+ else if (c >= 'a' && c <= 'f')
+ codepoint -= 'a' - 10;
+ else {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
+ }
+ is.Take();
+ }
+ return codepoint;
+ }
+
+ template <typename CharType>
+ class StackStream {
+ public:
+ typedef CharType Ch;
+
+ StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {}
+ RAPIDJSON_FORCEINLINE void Put(Ch c) {
+ *stack_.template Push<Ch>() = c;
+ ++length_;
+ }
+
+ RAPIDJSON_FORCEINLINE void* Push(SizeType count) {
+ length_ += count;
+ return stack_.template Push<Ch>(count);
+ }
+
+ size_t Length() const { return length_; }
+
+ Ch* Pop() {
+ return stack_.template Pop<Ch>(length_);
+ }
+
+ private:
+ StackStream(const StackStream&);
+ StackStream& operator=(const StackStream&);
+
+ internal::Stack<StackAllocator>& stack_;
+ SizeType length_;
+ };
+
+ // Parse string and generate String event. Different code paths for kParseInsituFlag.
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseString(InputStream& is, Handler& handler, bool isKey = false) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ RAPIDJSON_ASSERT(s.Peek() == '\"');
+ s.Take(); // Skip '\"'
+
+ bool success = false;
+ if (parseFlags & kParseInsituFlag) {
+ typename InputStream::Ch *head = s.PutBegin();
+ ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ size_t length = s.PutEnd(head) - 1;
+ RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+ const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
+ success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
+ }
+ else {
+ StackStream<typename TargetEncoding::Ch> stackStream(stack_);
+ ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
+ const typename TargetEncoding::Ch* const str = stackStream.Pop();
+ success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));
+ }
+ if (RAPIDJSON_UNLIKELY(!success))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
+ }
+
+ // Parse string to an output is
+ // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.
+ template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ static const char escape[256] = {
+ Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
+ Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
+ 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
+ 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
+ };
+#undef Z16
+//!@endcond
+
+ for (;;) {
+ // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation.
+ if (!(parseFlags & kParseValidateEncodingFlag))
+ ScanCopyUnescapedString(is, os);
+
+ Ch c = is.Peek();
+ if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
+ size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset
+ is.Take();
+ Ch e = is.Peek();
+ if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
+ is.Take();
+ os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
+ }
+ else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
+ is.Take();
+ unsigned codepoint = ParseHex4(is, escapeOffset);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
+ // Handle UTF-16 surrogate pair
+ if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
+ unsigned codepoint2 = ParseHex4(is, escapeOffset);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
+ codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
+ }
+ TEncoding::Encode(os, codepoint);
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset);
+ }
+ else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote
+ is.Take();
+ os.Put('\0'); // null-terminate the string
+ return;
+ }
+ else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
+ if (c == '\0')
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell());
+ }
+ else {
+ size_t offset = is.Tell();
+ if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
+ !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
+ !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);
+ }
+ }
+ }
+
+ template<typename InputStream, typename OutputStream>
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) {
+ // Do nothing for generic version
+ }
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+ // StringStream -> StackStream<char>
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
+ const char* p = is.src_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = p;
+ return;
+ }
+ else
+ os.Put(*p++);
+
+ // The rest of string using SIMD
+ static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+ static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+ static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+ const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+ const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ SizeType length;
+ #ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ length = offset;
+ #else
+ length = static_cast<SizeType>(__builtin_ffs(r) - 1);
+ #endif
+ char* q = reinterpret_cast<char*>(os.Push(length));
+ for (size_t i = 0; i < length; i++)
+ q[i] = p[i];
+
+ p += length;
+ break;
+ }
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);
+ }
+
+ is.src_ = p;
+ }
+
+ // InsituStringStream -> InsituStringStream
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {
+ RAPIDJSON_ASSERT(&is == &os);
+ (void)os;
+
+ if (is.src_ == is.dst_) {
+ SkipUnescapedString(is);
+ return;
+ }
+
+ char* p = is.src_;
+ char *q = is.dst_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = p;
+ is.dst_ = q;
+ return;
+ }
+ else
+ *q++ = *p++;
+
+ // The rest of string using SIMD
+ static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+ static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+ static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+ const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+ const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+ for (;; p += 16, q += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ size_t length;
+#ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ length = offset;
+#else
+ length = static_cast<size_t>(__builtin_ffs(r) - 1);
+#endif
+ for (const char* pend = p + length; p != pend; )
+ *q++ = *p++;
+ break;
+ }
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s);
+ }
+
+ is.src_ = p;
+ is.dst_ = q;
+ }
+
+ // When read/write pointers are the same for insitu stream, just skip unescaped characters
+ static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {
+ RAPIDJSON_ASSERT(is.src_ == is.dst_);
+ char* p = is.src_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ for (; p != nextAligned; p++)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = is.dst_ = p;
+ return;
+ }
+
+ // The rest of string using SIMD
+ static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+ static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+ static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+ const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+ const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ size_t length;
+#ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ length = offset;
+#else
+ length = static_cast<size_t>(__builtin_ffs(r) - 1);
+#endif
+ p += length;
+ break;
+ }
+ }
+
+ is.src_ = is.dst_ = p;
+ }
+#endif
+
+ template<typename InputStream, bool backup, bool pushOnTake>
+ class NumberStream;
+
+ template<typename InputStream>
+ class NumberStream<InputStream, false, false> {
+ public:
+ typedef typename InputStream::Ch Ch;
+
+ NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; }
+ ~NumberStream() {}
+
+ RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
+ RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
+ RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
+ RAPIDJSON_FORCEINLINE void Push(char) {}
+
+ size_t Tell() { return is.Tell(); }
+ size_t Length() { return 0; }
+ const char* Pop() { return 0; }
+
+ protected:
+ NumberStream& operator=(const NumberStream&);
+
+ InputStream& is;
+ };
+
+ template<typename InputStream>
+ class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {
+ typedef NumberStream<InputStream, false, false> Base;
+ public:
+ NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
+ ~NumberStream() {}
+
+ RAPIDJSON_FORCEINLINE Ch TakePush() {
+ stackStream.Put(static_cast<char>(Base::is.Peek()));
+ return Base::is.Take();
+ }
+
+ RAPIDJSON_FORCEINLINE void Push(char c) {
+ stackStream.Put(c);
+ }
+
+ size_t Length() { return stackStream.Length(); }
+
+ const char* Pop() {
+ stackStream.Put('\0');
+ return stackStream.Pop();
+ }
+
+ private:
+ StackStream<char> stackStream;
+ };
+
+ template<typename InputStream>
+ class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {
+ typedef NumberStream<InputStream, true, false> Base;
+ public:
+ NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
+ ~NumberStream() {}
+
+ RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
+ };
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseNumber(InputStream& is, Handler& handler) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ NumberStream<InputStream,
+ ((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
+ ((parseFlags & kParseInsituFlag) == 0) :
+ ((parseFlags & kParseFullPrecisionFlag) != 0),
+ (parseFlags & kParseNumbersAsStringsFlag) != 0 &&
+ (parseFlags & kParseInsituFlag) == 0> s(*this, copy.s);
+
+ size_t startOffset = s.Tell();
+ double d = 0.0;
+ bool useNanOrInf = false;
+
+ // Parse minus
+ bool minus = Consume(s, '-');
+
+ // Parse int: zero / ( digit1-9 *DIGIT )
+ unsigned i = 0;
+ uint64_t i64 = 0;
+ bool use64bit = false;
+ int significandDigit = 0;
+ if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) {
+ i = 0;
+ s.TakePush();
+ }
+ else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) {
+ i = static_cast<unsigned>(s.TakePush() - '0');
+
+ if (minus)
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648
+ if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) {
+ i64 = i;
+ use64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ else
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295
+ if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) {
+ i64 = i;
+ use64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ }
+ // Parse NaN or Infinity here
+ else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {
+ useNanOrInf = true;
+ if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) {
+ d = std::numeric_limits<double>::quiet_NaN();
+ }
+ else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) {
+ d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
+ if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n')
+ && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y'))))
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+
+ // Parse 64bit int
+ bool useDouble = false;
+ if (use64bit) {
+ if (minus)
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808
+ if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) {
+ d = static_cast<double>(i64);
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ else
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615
+ if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) {
+ d = static_cast<double>(i64);
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ }
+
+ // Force double for big integer
+ if (useDouble) {
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
+ d = d * 10 + (s.TakePush() - '0');
+ }
+ }
+
+ // Parse frac = decimal-point 1*DIGIT
+ int expFrac = 0;
+ size_t decimalPosition;
+ if (Consume(s, '.')) {
+ decimalPosition = s.Length();
+
+ if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
+
+ if (!useDouble) {
+#if RAPIDJSON_64BIT
+ // Use i64 to store significand in 64-bit architecture
+ if (!use64bit)
+ i64 = i;
+
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
+ break;
+ else {
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ --expFrac;
+ if (i64 != 0)
+ significandDigit++;
+ }
+ }
+
+ d = static_cast<double>(i64);
+#else
+ // Use double to store significand in 32-bit architecture
+ d = static_cast<double>(use64bit ? i64 : i);
+#endif
+ useDouble = true;
+ }
+
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (significandDigit < 17) {
+ d = d * 10.0 + (s.TakePush() - '0');
+ --expFrac;
+ if (RAPIDJSON_LIKELY(d > 0.0))
+ significandDigit++;
+ }
+ else
+ s.TakePush();
+ }
+ }
+ else
+ decimalPosition = s.Length(); // decimal position at the end of integer.
+
+ // Parse exp = e [ minus / plus ] 1*DIGIT
+ int exp = 0;
+ if (Consume(s, 'e') || Consume(s, 'E')) {
+ if (!useDouble) {
+ d = static_cast<double>(use64bit ? i64 : i);
+ useDouble = true;
+ }
+
+ bool expMinus = false;
+ if (Consume(s, '+'))
+ ;
+ else if (Consume(s, '-'))
+ expMinus = true;
+
+ if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ exp = static_cast<int>(s.Take() - '0');
+ if (expMinus) {
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ exp = exp * 10 + static_cast<int>(s.Take() - '0');
+ if (exp >= 214748364) { // Issue #313: prevent overflow exponent
+ while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent
+ s.Take();
+ }
+ }
+ }
+ else { // positive exp
+ int maxExp = 308 - expFrac;
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ exp = exp * 10 + static_cast<int>(s.Take() - '0');
+ if (RAPIDJSON_UNLIKELY(exp > maxExp))
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
+ }
+ }
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());
+
+ if (expMinus)
+ exp = -exp;
+ }
+
+ // Finish parsing, call event according to the type of number.
+ bool cont = true;
+
+ if (parseFlags & kParseNumbersAsStringsFlag) {
+ if (parseFlags & kParseInsituFlag) {
+ s.Pop(); // Pop stack no matter if it will be used or not.
+ typename InputStream::Ch* head = is.PutBegin();
+ const size_t length = s.Tell() - startOffset;
+ RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+ // unable to insert the \0 character here, it will erase the comma after this number
+ const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
+ cont = handler.RawNumber(str, SizeType(length), false);
+ }
+ else {
+ SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
+ StringStream srcStream(s.Pop());
+ StackStream<typename TargetEncoding::Ch> dstStream(stack_);
+ while (numCharsToCopy--) {
+ Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);
+ }
+ dstStream.Put('\0');
+ const typename TargetEncoding::Ch* str = dstStream.Pop();
+ const SizeType length = static_cast<SizeType>(dstStream.Length()) - 1;
+ cont = handler.RawNumber(str, SizeType(length), true);
+ }
+ }
+ else {
+ size_t length = s.Length();
+ const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
+
+ if (useDouble) {
+ int p = exp + expFrac;
+ if (parseFlags & kParseFullPrecisionFlag)
+ d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
+ else
+ d = internal::StrtodNormalPrecision(d, p);
+
+ cont = handler.Double(minus ? -d : d);
+ }
+ else if (useNanOrInf) {
+ cont = handler.Double(d);
+ }
+ else {
+ if (use64bit) {
+ if (minus)
+ cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
+ else
+ cont = handler.Uint64(i64);
+ }
+ else {
+ if (minus)
+ cont = handler.Int(static_cast<int32_t>(~i + 1));
+ else
+ cont = handler.Uint(i);
+ }
+ }
+ }
+ if (RAPIDJSON_UNLIKELY(!cont))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
+ }
+
+ // Parse any JSON value
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseValue(InputStream& is, Handler& handler) {
+ switch (is.Peek()) {
+ case 'n': ParseNull <parseFlags>(is, handler); break;
+ case 't': ParseTrue <parseFlags>(is, handler); break;
+ case 'f': ParseFalse <parseFlags>(is, handler); break;
+ case '"': ParseString<parseFlags>(is, handler); break;
+ case '{': ParseObject<parseFlags>(is, handler); break;
+ case '[': ParseArray <parseFlags>(is, handler); break;
+ default :
+ ParseNumber<parseFlags>(is, handler);
+ break;
+
+ }
+ }
+
+ // Iterative Parsing
+
+ // States
+ enum IterativeParsingState {
+ IterativeParsingStartState = 0,
+ IterativeParsingFinishState,
+ IterativeParsingErrorState,
+
+ // Object states
+ IterativeParsingObjectInitialState,
+ IterativeParsingMemberKeyState,
+ IterativeParsingKeyValueDelimiterState,
+ IterativeParsingMemberValueState,
+ IterativeParsingMemberDelimiterState,
+ IterativeParsingObjectFinishState,
+
+ // Array states
+ IterativeParsingArrayInitialState,
+ IterativeParsingElementState,
+ IterativeParsingElementDelimiterState,
+ IterativeParsingArrayFinishState,
+
+ // Single value state
+ IterativeParsingValueState
+ };
+
+ enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
+
+ // Tokens
+ enum Token {
+ LeftBracketToken = 0,
+ RightBracketToken,
+
+ LeftCurlyBracketToken,
+ RightCurlyBracketToken,
+
+ CommaToken,
+ ColonToken,
+
+ StringToken,
+ FalseToken,
+ TrueToken,
+ NullToken,
+ NumberToken,
+
+ kTokenCount
+ };
+
+ RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define N NumberToken
+#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N
+ // Maps from ASCII to Token
+ static const unsigned char tokenMap[256] = {
+ N16, // 00~0F
+ N16, // 10~1F
+ N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F
+ N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F
+ N16, // 40~4F
+ N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F
+ N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F
+ N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F
+ N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF
+ };
+#undef N
+#undef N16
+//!@endcond
+
+ if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
+ return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
+ else
+ return NumberToken;
+ }
+
+ RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
+ // current state x one lookahead token -> new state
+ static const char G[cIterativeParsingStateCount][kTokenCount] = {
+ // Start
+ {
+ IterativeParsingArrayInitialState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingValueState, // String
+ IterativeParsingValueState, // False
+ IterativeParsingValueState, // True
+ IterativeParsingValueState, // Null
+ IterativeParsingValueState // Number
+ },
+ // Finish(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // Error(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // ObjectInitial
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingObjectFinishState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberKeyState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // MemberKey
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingKeyValueDelimiterState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // KeyValueDelimiter
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push MemberValue state)
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberValueState, // String
+ IterativeParsingMemberValueState, // False
+ IterativeParsingMemberValueState, // True
+ IterativeParsingMemberValueState, // Null
+ IterativeParsingMemberValueState // Number
+ },
+ // MemberValue
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingObjectFinishState, // Right curly bracket
+ IterativeParsingMemberDelimiterState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // MemberDelimiter
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingObjectFinishState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberKeyState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // ObjectFinish(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // ArrayInitial
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push Element state)
+ IterativeParsingArrayFinishState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingElementState, // String
+ IterativeParsingElementState, // False
+ IterativeParsingElementState, // True
+ IterativeParsingElementState, // Null
+ IterativeParsingElementState // Number
+ },
+ // Element
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingArrayFinishState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingElementDelimiterState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // ElementDelimiter
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push Element state)
+ IterativeParsingArrayFinishState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingElementState, // String
+ IterativeParsingElementState, // False
+ IterativeParsingElementState, // True
+ IterativeParsingElementState, // Null
+ IterativeParsingElementState // Number
+ },
+ // ArrayFinish(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // Single Value (sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ }
+ }; // End of G
+
+ return static_cast<IterativeParsingState>(G[state][token]);
+ }
+
+ // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().
+ // May return a new state on state pop.
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {
+ (void)token;
+
+ switch (dst) {
+ case IterativeParsingErrorState:
+ return dst;
+
+ case IterativeParsingObjectInitialState:
+ case IterativeParsingArrayInitialState:
+ {
+ // Push the state(Element or MemeberValue) if we are nested in another array or value of member.
+ // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop.
+ IterativeParsingState n = src;
+ if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState)
+ n = IterativeParsingElementState;
+ else if (src == IterativeParsingKeyValueDelimiterState)
+ n = IterativeParsingMemberValueState;
+ // Push current state.
+ *stack_.template Push<SizeType>(1) = n;
+ // Initialize and push the member/element count.
+ *stack_.template Push<SizeType>(1) = 0;
+ // Call handler
+ bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray();
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ else {
+ is.Take();
+ return dst;
+ }
+ }
+
+ case IterativeParsingMemberKeyState:
+ ParseString<parseFlags>(is, handler, true);
+ if (HasParseError())
+ return IterativeParsingErrorState;
+ else
+ return dst;
+
+ case IterativeParsingKeyValueDelimiterState:
+ RAPIDJSON_ASSERT(token == ColonToken);
+ is.Take();
+ return dst;
+
+ case IterativeParsingMemberValueState:
+ // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return dst;
+
+ case IterativeParsingElementState:
+ // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return dst;
+
+ case IterativeParsingMemberDelimiterState:
+ case IterativeParsingElementDelimiterState:
+ is.Take();
+ // Update member/element count.
+ *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;
+ return dst;
+
+ case IterativeParsingObjectFinishState:
+ {
+ // Transit from delimiter is only allowed when trailing commas are enabled
+ if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ // Get member count.
+ SizeType c = *stack_.template Pop<SizeType>(1);
+ // If the object is not empty, count the last member.
+ if (src == IterativeParsingMemberValueState)
+ ++c;
+ // Restore the state.
+ IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
+ // Transit to Finish state if this is the topmost scope.
+ if (n == IterativeParsingStartState)
+ n = IterativeParsingFinishState;
+ // Call handler
+ bool hr = handler.EndObject(c);
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ else {
+ is.Take();
+ return n;
+ }
+ }
+
+ case IterativeParsingArrayFinishState:
+ {
+ // Transit from delimiter is only allowed when trailing commas are enabled
+ if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ // Get element count.
+ SizeType c = *stack_.template Pop<SizeType>(1);
+ // If the array is not empty, count the last element.
+ if (src == IterativeParsingElementState)
+ ++c;
+ // Restore the state.
+ IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
+ // Transit to Finish state if this is the topmost scope.
+ if (n == IterativeParsingStartState)
+ n = IterativeParsingFinishState;
+ // Call handler
+ bool hr = handler.EndArray(c);
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ else {
+ is.Take();
+ return n;
+ }
+ }
+
+ default:
+ // This branch is for IterativeParsingValueState actually.
+ // Use `default:` rather than
+ // `case IterativeParsingValueState:` is for code coverage.
+
+ // The IterativeParsingStartState is not enumerated in this switch-case.
+ // It is impossible for that case. And it can be caught by following assertion.
+
+ // The IterativeParsingFinishState is not enumerated in this switch-case either.
+ // It is a "derivative" state which cannot triggered from Predict() directly.
+ // Therefore it cannot happen here. And it can be caught by following assertion.
+ RAPIDJSON_ASSERT(dst == IterativeParsingValueState);
+
+ // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return IterativeParsingFinishState;
+ }
+ }
+
+ template <typename InputStream>
+ void HandleError(IterativeParsingState src, InputStream& is) {
+ if (HasParseError()) {
+ // Error flag has been set.
+ return;
+ }
+
+ switch (src) {
+ case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;
+ case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;
+ case IterativeParsingObjectInitialState:
+ case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;
+ case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
+ case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
+ case IterativeParsingKeyValueDelimiterState:
+ case IterativeParsingArrayInitialState:
+ case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return;
+ default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
+ }
+ }
+
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ ParseResult IterativeParse(InputStream& is, Handler& handler) {
+ parseResult_.Clear();
+ ClearStackOnExit scope(*this);
+ IterativeParsingState state = IterativeParsingStartState;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ while (is.Peek() != '\0') {
+ Token t = Tokenize(is.Peek());
+ IterativeParsingState n = Predict(state, t);
+ IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);
+
+ if (d == IterativeParsingErrorState) {
+ HandleError(state, is);
+ break;
+ }
+
+ state = d;
+
+ // Do not further consume streams if a root JSON has been parsed.
+ if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
+ break;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ }
+
+ // Handle the end of file.
+ if (state != IterativeParsingFinishState)
+ HandleError(state, is);
+
+ return parseResult_;
+ }
+
+ static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
+ internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
+ ParseResult parseResult_;
+}; // class GenericReader
+
+//! Reader with UTF8 encoding and default allocator.
+typedef GenericReader<UTF8<>, UTF8<> > Reader;
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_READER_H_
diff --git a/external/rapidjson/rapidjson/schema.h b/external/rapidjson/rapidjson/schema.h
new file mode 100644
index 0000000..e7af3cf
--- /dev/null
+++ b/external/rapidjson/rapidjson/schema.h
@@ -0,0 +1,2024 @@
+// Tencent is pleased to support the open source community by making RapidJSON available->
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License-> You may obtain a copy of the License at
+//
+// http://opensource->org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied-> See the License for the
+// specific language governing permissions and limitations under the License->
+
+#ifndef RAPIDJSON_SCHEMA_H_
+#define RAPIDJSON_SCHEMA_H_
+
+#include "document.h"
+#include "pointer.h"
+#include <cmath> // abs, floor
+
+#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
+#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
+#else
+#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
+#endif
+
+#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
+#define RAPIDJSON_SCHEMA_USE_STDREGEX 1
+#else
+#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
+#endif
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+#include "internal/regex.h"
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+#include <regex>
+#endif
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
+#define RAPIDJSON_SCHEMA_HAS_REGEX 1
+#else
+#define RAPIDJSON_SCHEMA_HAS_REGEX 0
+#endif
+
+#ifndef RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_SCHEMA_VERBOSE 0
+#endif
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#include "stringbuffer.h"
+#endif
+
+RAPIDJSON_DIAG_PUSH
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_OFF(weak-vtables)
+RAPIDJSON_DIAG_OFF(exit-time-destructors)
+RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
+RAPIDJSON_DIAG_OFF(variadic-macros)
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Verbose Utilities
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+
+namespace internal {
+
+inline void PrintInvalidKeyword(const char* keyword) {
+ printf("Fail keyword: %s\n", keyword);
+}
+
+inline void PrintInvalidKeyword(const wchar_t* keyword) {
+ wprintf(L"Fail keyword: %ls\n", keyword);
+}
+
+inline void PrintInvalidDocument(const char* document) {
+ printf("Fail document: %s\n\n", document);
+}
+
+inline void PrintInvalidDocument(const wchar_t* document) {
+ wprintf(L"Fail document: %ls\n\n", document);
+}
+
+inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
+ printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
+}
+
+inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
+ wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
+}
+
+} // namespace internal
+
+#endif // RAPIDJSON_SCHEMA_VERBOSE
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_INVALID_KEYWORD_RETURN
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
+#else
+#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
+#endif
+
+#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
+RAPIDJSON_MULTILINEMACRO_BEGIN\
+ context.invalidKeyword = keyword.GetString();\
+ RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
+ return false;\
+RAPIDJSON_MULTILINEMACRO_END
+
+///////////////////////////////////////////////////////////////////////////////
+// Forward declarations
+
+template <typename ValueType, typename Allocator>
+class GenericSchemaDocument;
+
+namespace internal {
+
+template <typename SchemaDocumentType>
+class Schema;
+
+///////////////////////////////////////////////////////////////////////////////
+// ISchemaValidator
+
+class ISchemaValidator {
+public:
+ virtual ~ISchemaValidator() {}
+ virtual bool IsValid() const = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ISchemaStateFactory
+
+template <typename SchemaType>
+class ISchemaStateFactory {
+public:
+ virtual ~ISchemaStateFactory() {}
+ virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
+ virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
+ virtual void* CreateHasher() = 0;
+ virtual uint64_t GetHashCode(void* hasher) = 0;
+ virtual void DestroryHasher(void* hasher) = 0;
+ virtual void* MallocState(size_t size) = 0;
+ virtual void FreeState(void* p) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Hasher
+
+// For comparison of compound value
+template<typename Encoding, typename Allocator>
+class Hasher {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
+
+ bool Null() { return WriteType(kNullType); }
+ bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
+ bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
+ bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
+ bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
+ bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
+ bool Double(double d) {
+ Number n;
+ if (d < 0) n.u.i = static_cast<int64_t>(d);
+ else n.u.u = static_cast<uint64_t>(d);
+ n.d = d;
+ return WriteNumber(n);
+ }
+
+ bool RawNumber(const Ch* str, SizeType len, bool) {
+ WriteBuffer(kNumberType, str, len * sizeof(Ch));
+ return true;
+ }
+
+ bool String(const Ch* str, SizeType len, bool) {
+ WriteBuffer(kStringType, str, len * sizeof(Ch));
+ return true;
+ }
+
+ bool StartObject() { return true; }
+ bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
+ bool EndObject(SizeType memberCount) {
+ uint64_t h = Hash(0, kObjectType);
+ uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
+ for (SizeType i = 0; i < memberCount; i++)
+ h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive
+ *stack_.template Push<uint64_t>() = h;
+ return true;
+ }
+
+ bool StartArray() { return true; }
+ bool EndArray(SizeType elementCount) {
+ uint64_t h = Hash(0, kArrayType);
+ uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
+ for (SizeType i = 0; i < elementCount; i++)
+ h = Hash(h, e[i]); // Use hash to achieve element order sensitive
+ *stack_.template Push<uint64_t>() = h;
+ return true;
+ }
+
+ bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
+
+ uint64_t GetHashCode() const {
+ RAPIDJSON_ASSERT(IsValid());
+ return *stack_.template Top<uint64_t>();
+ }
+
+private:
+ static const size_t kDefaultSize = 256;
+ struct Number {
+ union U {
+ uint64_t u;
+ int64_t i;
+ }u;
+ double d;
+ };
+
+ bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
+
+ bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
+
+ bool WriteBuffer(Type type, const void* data, size_t len) {
+ // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
+ uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);
+ const unsigned char* d = static_cast<const unsigned char*>(data);
+ for (size_t i = 0; i < len; i++)
+ h = Hash(h, d[i]);
+ *stack_.template Push<uint64_t>() = h;
+ return true;
+ }
+
+ static uint64_t Hash(uint64_t h, uint64_t d) {
+ static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
+ h ^= d;
+ h *= kPrime;
+ return h;
+ }
+
+ Stack<Allocator> stack_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// SchemaValidationContext
+
+template <typename SchemaDocumentType>
+struct SchemaValidationContext {
+ typedef Schema<SchemaDocumentType> SchemaType;
+ typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
+ typedef typename SchemaType::ValueType ValueType;
+ typedef typename ValueType::Ch Ch;
+
+ enum PatternValidatorType {
+ kPatternValidatorOnly,
+ kPatternValidatorWithProperty,
+ kPatternValidatorWithAdditionalProperty
+ };
+
+ SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) :
+ factory(f),
+ schema(s),
+ valueSchema(),
+ invalidKeyword(),
+ hasher(),
+ arrayElementHashCodes(),
+ validators(),
+ validatorCount(),
+ patternPropertiesValidators(),
+ patternPropertiesValidatorCount(),
+ patternPropertiesSchemas(),
+ patternPropertiesSchemaCount(),
+ valuePatternValidatorType(kPatternValidatorOnly),
+ propertyExist(),
+ inArray(false),
+ valueUniqueness(false),
+ arrayUniqueness(false)
+ {
+ }
+
+ ~SchemaValidationContext() {
+ if (hasher)
+ factory.DestroryHasher(hasher);
+ if (validators) {
+ for (SizeType i = 0; i < validatorCount; i++)
+ factory.DestroySchemaValidator(validators[i]);
+ factory.FreeState(validators);
+ }
+ if (patternPropertiesValidators) {
+ for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
+ factory.DestroySchemaValidator(patternPropertiesValidators[i]);
+ factory.FreeState(patternPropertiesValidators);
+ }
+ if (patternPropertiesSchemas)
+ factory.FreeState(patternPropertiesSchemas);
+ if (propertyExist)
+ factory.FreeState(propertyExist);
+ }
+
+ SchemaValidatorFactoryType& factory;
+ const SchemaType* schema;
+ const SchemaType* valueSchema;
+ const Ch* invalidKeyword;
+ void* hasher; // Only validator access
+ void* arrayElementHashCodes; // Only validator access this
+ ISchemaValidator** validators;
+ SizeType validatorCount;
+ ISchemaValidator** patternPropertiesValidators;
+ SizeType patternPropertiesValidatorCount;
+ const SchemaType** patternPropertiesSchemas;
+ SizeType patternPropertiesSchemaCount;
+ PatternValidatorType valuePatternValidatorType;
+ PatternValidatorType objectPatternValidatorType;
+ SizeType arrayElementIndex;
+ bool* propertyExist;
+ bool inArray;
+ bool valueUniqueness;
+ bool arrayUniqueness;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Schema
+
+template <typename SchemaDocumentType>
+class Schema {
+public:
+ typedef typename SchemaDocumentType::ValueType ValueType;
+ typedef typename SchemaDocumentType::AllocatorType AllocatorType;
+ typedef typename SchemaDocumentType::PointerType PointerType;
+ typedef typename ValueType::EncodingType EncodingType;
+ typedef typename EncodingType::Ch Ch;
+ typedef SchemaValidationContext<SchemaDocumentType> Context;
+ typedef Schema<SchemaDocumentType> SchemaType;
+ typedef GenericValue<EncodingType, AllocatorType> SValue;
+ friend class GenericSchemaDocument<ValueType, AllocatorType>;
+
+ Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
+ allocator_(allocator),
+ typeless_(schemaDocument->GetTypeless()),
+ enum_(),
+ enumCount_(),
+ not_(),
+ type_((1 << kTotalSchemaType) - 1), // typeless
+ validatorCount_(),
+ properties_(),
+ additionalPropertiesSchema_(),
+ patternProperties_(),
+ patternPropertyCount_(),
+ propertyCount_(),
+ minProperties_(),
+ maxProperties_(SizeType(~0)),
+ additionalProperties_(true),
+ hasDependencies_(),
+ hasRequired_(),
+ hasSchemaDependencies_(),
+ additionalItemsSchema_(),
+ itemsList_(),
+ itemsTuple_(),
+ itemsTupleCount_(),
+ minItems_(),
+ maxItems_(SizeType(~0)),
+ additionalItems_(true),
+ uniqueItems_(false),
+ pattern_(),
+ minLength_(0),
+ maxLength_(~SizeType(0)),
+ exclusiveMinimum_(false),
+ exclusiveMaximum_(false)
+ {
+ typedef typename SchemaDocumentType::ValueType ValueType;
+ typedef typename ValueType::ConstValueIterator ConstValueIterator;
+ typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
+
+ if (!value.IsObject())
+ return;
+
+ if (const ValueType* v = GetMember(value, GetTypeString())) {
+ type_ = 0;
+ if (v->IsString())
+ AddType(*v);
+ else if (v->IsArray())
+ for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
+ AddType(*itr);
+ }
+
+ if (const ValueType* v = GetMember(value, GetEnumString()))
+ if (v->IsArray() && v->Size() > 0) {
+ enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
+ for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
+ typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
+ char buffer[256 + 24];
+ MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
+ EnumHasherType h(&hasherAllocator, 256);
+ itr->Accept(h);
+ enum_[enumCount_++] = h.GetHashCode();
+ }
+ }
+
+ if (schemaDocument) {
+ AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
+ AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
+ AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
+ }
+
+ if (const ValueType* v = GetMember(value, GetNotString())) {
+ schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
+ notValidatorIndex_ = validatorCount_;
+ validatorCount_++;
+ }
+
+ // Object
+
+ const ValueType* properties = GetMember(value, GetPropertiesString());
+ const ValueType* required = GetMember(value, GetRequiredString());
+ const ValueType* dependencies = GetMember(value, GetDependenciesString());
+ {
+ // Gather properties from properties/required/dependencies
+ SValue allProperties(kArrayType);
+
+ if (properties && properties->IsObject())
+ for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
+ AddUniqueElement(allProperties, itr->name);
+
+ if (required && required->IsArray())
+ for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
+ if (itr->IsString())
+ AddUniqueElement(allProperties, *itr);
+
+ if (dependencies && dependencies->IsObject())
+ for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
+ AddUniqueElement(allProperties, itr->name);
+ if (itr->value.IsArray())
+ for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
+ if (i->IsString())
+ AddUniqueElement(allProperties, *i);
+ }
+
+ if (allProperties.Size() > 0) {
+ propertyCount_ = allProperties.Size();
+ properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
+ for (SizeType i = 0; i < propertyCount_; i++) {
+ new (&properties_[i]) Property();
+ properties_[i].name = allProperties[i];
+ properties_[i].schema = typeless_;
+ }
+ }
+ }
+
+ if (properties && properties->IsObject()) {
+ PointerType q = p.Append(GetPropertiesString(), allocator_);
+ for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
+ SizeType index;
+ if (FindPropertyIndex(itr->name, &index))
+ schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
+ }
+ }
+
+ if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
+ PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
+ patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
+ patternPropertyCount_ = 0;
+
+ for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
+ new (&patternProperties_[patternPropertyCount_]) PatternProperty();
+ patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
+ schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
+ patternPropertyCount_++;
+ }
+ }
+
+ if (required && required->IsArray())
+ for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
+ if (itr->IsString()) {
+ SizeType index;
+ if (FindPropertyIndex(*itr, &index)) {
+ properties_[index].required = true;
+ hasRequired_ = true;
+ }
+ }
+
+ if (dependencies && dependencies->IsObject()) {
+ PointerType q = p.Append(GetDependenciesString(), allocator_);
+ hasDependencies_ = true;
+ for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
+ SizeType sourceIndex;
+ if (FindPropertyIndex(itr->name, &sourceIndex)) {
+ if (itr->value.IsArray()) {
+ properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
+ std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
+ for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
+ SizeType targetIndex;
+ if (FindPropertyIndex(*targetItr, &targetIndex))
+ properties_[sourceIndex].dependencies[targetIndex] = true;
+ }
+ }
+ else if (itr->value.IsObject()) {
+ hasSchemaDependencies_ = true;
+ schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
+ properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
+ validatorCount_++;
+ }
+ }
+ }
+ }
+
+ if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
+ if (v->IsBool())
+ additionalProperties_ = v->GetBool();
+ else if (v->IsObject())
+ schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
+ }
+
+ AssignIfExist(minProperties_, value, GetMinPropertiesString());
+ AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
+
+ // Array
+ if (const ValueType* v = GetMember(value, GetItemsString())) {
+ PointerType q = p.Append(GetItemsString(), allocator_);
+ if (v->IsObject()) // List validation
+ schemaDocument->CreateSchema(&itemsList_, q, *v, document);
+ else if (v->IsArray()) { // Tuple validation
+ itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
+ SizeType index = 0;
+ for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
+ schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
+ }
+ }
+
+ AssignIfExist(minItems_, value, GetMinItemsString());
+ AssignIfExist(maxItems_, value, GetMaxItemsString());
+
+ if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
+ if (v->IsBool())
+ additionalItems_ = v->GetBool();
+ else if (v->IsObject())
+ schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
+ }
+
+ AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
+
+ // String
+ AssignIfExist(minLength_, value, GetMinLengthString());
+ AssignIfExist(maxLength_, value, GetMaxLengthString());
+
+ if (const ValueType* v = GetMember(value, GetPatternString()))
+ pattern_ = CreatePattern(*v);
+
+ // Number
+ if (const ValueType* v = GetMember(value, GetMinimumString()))
+ if (v->IsNumber())
+ minimum_.CopyFrom(*v, *allocator_);
+
+ if (const ValueType* v = GetMember(value, GetMaximumString()))
+ if (v->IsNumber())
+ maximum_.CopyFrom(*v, *allocator_);
+
+ AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
+ AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
+
+ if (const ValueType* v = GetMember(value, GetMultipleOfString()))
+ if (v->IsNumber() && v->GetDouble() > 0.0)
+ multipleOf_.CopyFrom(*v, *allocator_);
+ }
+
+ ~Schema() {
+ AllocatorType::Free(enum_);
+ if (properties_) {
+ for (SizeType i = 0; i < propertyCount_; i++)
+ properties_[i].~Property();
+ AllocatorType::Free(properties_);
+ }
+ if (patternProperties_) {
+ for (SizeType i = 0; i < patternPropertyCount_; i++)
+ patternProperties_[i].~PatternProperty();
+ AllocatorType::Free(patternProperties_);
+ }
+ AllocatorType::Free(itemsTuple_);
+#if RAPIDJSON_SCHEMA_HAS_REGEX
+ if (pattern_) {
+ pattern_->~RegexType();
+ AllocatorType::Free(pattern_);
+ }
+#endif
+ }
+
+ bool BeginValue(Context& context) const {
+ if (context.inArray) {
+ if (uniqueItems_)
+ context.valueUniqueness = true;
+
+ if (itemsList_)
+ context.valueSchema = itemsList_;
+ else if (itemsTuple_) {
+ if (context.arrayElementIndex < itemsTupleCount_)
+ context.valueSchema = itemsTuple_[context.arrayElementIndex];
+ else if (additionalItemsSchema_)
+ context.valueSchema = additionalItemsSchema_;
+ else if (additionalItems_)
+ context.valueSchema = typeless_;
+ else
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
+ }
+ else
+ context.valueSchema = typeless_;
+
+ context.arrayElementIndex++;
+ }
+ return true;
+ }
+
+ RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
+ if (context.patternPropertiesValidatorCount > 0) {
+ bool otherValid = false;
+ SizeType count = context.patternPropertiesValidatorCount;
+ if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
+ otherValid = context.patternPropertiesValidators[--count]->IsValid();
+
+ bool patternValid = true;
+ for (SizeType i = 0; i < count; i++)
+ if (!context.patternPropertiesValidators[i]->IsValid()) {
+ patternValid = false;
+ break;
+ }
+
+ if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
+ if (!patternValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+ }
+ else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
+ if (!patternValid || !otherValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+ }
+ else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+ }
+
+ if (enum_) {
+ const uint64_t h = context.factory.GetHashCode(context.hasher);
+ for (SizeType i = 0; i < enumCount_; i++)
+ if (enum_[i] == h)
+ goto foundEnum;
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
+ foundEnum:;
+ }
+
+ if (allOf_.schemas)
+ for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
+ if (!context.validators[i]->IsValid())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
+
+ if (anyOf_.schemas) {
+ for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
+ if (context.validators[i]->IsValid())
+ goto foundAny;
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
+ foundAny:;
+ }
+
+ if (oneOf_.schemas) {
+ bool oneValid = false;
+ for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
+ if (context.validators[i]->IsValid()) {
+ if (oneValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
+ else
+ oneValid = true;
+ }
+ if (!oneValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
+ }
+
+ if (not_ && context.validators[notValidatorIndex_]->IsValid())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
+
+ return true;
+ }
+
+ bool Null(Context& context) const {
+ if (!(type_ & (1 << kNullSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ return CreateParallelValidator(context);
+ }
+
+ bool Bool(Context& context, bool) const {
+ if (!(type_ & (1 << kBooleanSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ return CreateParallelValidator(context);
+ }
+
+ bool Int(Context& context, int i) const {
+ if (!CheckInt(context, i))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Uint(Context& context, unsigned u) const {
+ if (!CheckUint(context, u))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Int64(Context& context, int64_t i) const {
+ if (!CheckInt(context, i))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Uint64(Context& context, uint64_t u) const {
+ if (!CheckUint(context, u))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Double(Context& context, double d) const {
+ if (!(type_ & (1 << kNumberSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
+ return false;
+
+ if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
+ return false;
+
+ if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
+ return false;
+
+ return CreateParallelValidator(context);
+ }
+
+ bool String(Context& context, const Ch* str, SizeType length, bool) const {
+ if (!(type_ & (1 << kStringSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
+ SizeType count;
+ if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
+ if (count < minLength_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
+ if (count > maxLength_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
+ }
+ }
+
+ if (pattern_ && !IsPatternMatch(pattern_, str, length))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
+
+ return CreateParallelValidator(context);
+ }
+
+ bool StartObject(Context& context) const {
+ if (!(type_ & (1 << kObjectSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (hasDependencies_ || hasRequired_) {
+ context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
+ std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
+ }
+
+ if (patternProperties_) { // pre-allocate schema array
+ SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
+ context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
+ context.patternPropertiesSchemaCount = 0;
+ std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
+ }
+
+ return CreateParallelValidator(context);
+ }
+
+ bool Key(Context& context, const Ch* str, SizeType len, bool) const {
+ if (patternProperties_) {
+ context.patternPropertiesSchemaCount = 0;
+ for (SizeType i = 0; i < patternPropertyCount_; i++)
+ if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))
+ context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
+ }
+
+ SizeType index;
+ if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
+ if (context.patternPropertiesSchemaCount > 0) {
+ context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
+ context.valueSchema = typeless_;
+ context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
+ }
+ else
+ context.valueSchema = properties_[index].schema;
+
+ if (context.propertyExist)
+ context.propertyExist[index] = true;
+
+ return true;
+ }
+
+ if (additionalPropertiesSchema_) {
+ if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
+ context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
+ context.valueSchema = typeless_;
+ context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
+ }
+ else
+ context.valueSchema = additionalPropertiesSchema_;
+ return true;
+ }
+ else if (additionalProperties_) {
+ context.valueSchema = typeless_;
+ return true;
+ }
+
+ if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
+
+ return true;
+ }
+
+ bool EndObject(Context& context, SizeType memberCount) const {
+ if (hasRequired_)
+ for (SizeType index = 0; index < propertyCount_; index++)
+ if (properties_[index].required)
+ if (!context.propertyExist[index])
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
+
+ if (memberCount < minProperties_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
+
+ if (memberCount > maxProperties_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
+
+ if (hasDependencies_) {
+ for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
+ if (context.propertyExist[sourceIndex]) {
+ if (properties_[sourceIndex].dependencies) {
+ for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
+ if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
+ }
+ else if (properties_[sourceIndex].dependenciesSchema)
+ if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
+ }
+ }
+
+ return true;
+ }
+
+ bool StartArray(Context& context) const {
+ if (!(type_ & (1 << kArraySchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ context.arrayElementIndex = 0;
+ context.inArray = true;
+
+ return CreateParallelValidator(context);
+ }
+
+ bool EndArray(Context& context, SizeType elementCount) const {
+ context.inArray = false;
+
+ if (elementCount < minItems_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
+
+ if (elementCount > maxItems_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
+
+ return true;
+ }
+
+ // Generate functions for string literal according to Ch
+#define RAPIDJSON_STRING_(name, ...) \
+ static const ValueType& Get##name##String() {\
+ static const Ch s[] = { __VA_ARGS__, '\0' };\
+ static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\
+ return v;\
+ }
+
+ RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
+ RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
+ RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
+ RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
+ RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
+ RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
+ RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
+ RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
+ RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
+ RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
+ RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
+ RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
+ RAPIDJSON_STRING_(Not, 'n', 'o', 't')
+ RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
+ RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
+ RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
+ RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
+ RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
+ RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
+
+#undef RAPIDJSON_STRING_
+
+private:
+ enum SchemaValueType {
+ kNullSchemaType,
+ kBooleanSchemaType,
+ kObjectSchemaType,
+ kArraySchemaType,
+ kStringSchemaType,
+ kNumberSchemaType,
+ kIntegerSchemaType,
+ kTotalSchemaType
+ };
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+ typedef internal::GenericRegex<EncodingType> RegexType;
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+ typedef std::basic_regex<Ch> RegexType;
+#else
+ typedef char RegexType;
+#endif
+
+ struct SchemaArray {
+ SchemaArray() : schemas(), count() {}
+ ~SchemaArray() { AllocatorType::Free(schemas); }
+ const SchemaType** schemas;
+ SizeType begin; // begin index of context.validators
+ SizeType count;
+ };
+
+ template <typename V1, typename V2>
+ void AddUniqueElement(V1& a, const V2& v) {
+ for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
+ if (*itr == v)
+ return;
+ V1 c(v, *allocator_);
+ a.PushBack(c, *allocator_);
+ }
+
+ static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
+ typename ValueType::ConstMemberIterator itr = value.FindMember(name);
+ return itr != value.MemberEnd() ? &(itr->value) : 0;
+ }
+
+ static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
+ if (const ValueType* v = GetMember(value, name))
+ if (v->IsBool())
+ out = v->GetBool();
+ }
+
+ static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
+ if (const ValueType* v = GetMember(value, name))
+ if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
+ out = static_cast<SizeType>(v->GetUint64());
+ }
+
+ void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
+ if (const ValueType* v = GetMember(value, name)) {
+ if (v->IsArray() && v->Size() > 0) {
+ PointerType q = p.Append(name, allocator_);
+ out.count = v->Size();
+ out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
+ memset(out.schemas, 0, sizeof(Schema*)* out.count);
+ for (SizeType i = 0; i < out.count; i++)
+ schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
+ out.begin = validatorCount_;
+ validatorCount_ += out.count;
+ }
+ }
+ }
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+ template <typename ValueType>
+ RegexType* CreatePattern(const ValueType& value) {
+ if (value.IsString()) {
+ RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
+ if (!r->IsValid()) {
+ r->~RegexType();
+ AllocatorType::Free(r);
+ r = 0;
+ }
+ return r;
+ }
+ return 0;
+ }
+
+ static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
+ GenericRegexSearch<RegexType> rs(*pattern);
+ return rs.Search(str);
+ }
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+ template <typename ValueType>
+ RegexType* CreatePattern(const ValueType& value) {
+ if (value.IsString())
+ try {
+ return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
+ }
+ catch (const std::regex_error&) {
+ }
+ return 0;
+ }
+
+ static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
+ std::match_results<const Ch*> r;
+ return std::regex_search(str, str + length, r, *pattern);
+ }
+#else
+ template <typename ValueType>
+ RegexType* CreatePattern(const ValueType&) { return 0; }
+
+ static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
+#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
+
+ void AddType(const ValueType& type) {
+ if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
+ else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
+ else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
+ else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
+ else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
+ else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
+ else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
+ }
+
+ bool CreateParallelValidator(Context& context) const {
+ if (enum_ || context.arrayUniqueness)
+ context.hasher = context.factory.CreateHasher();
+
+ if (validatorCount_) {
+ RAPIDJSON_ASSERT(context.validators == 0);
+ context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
+ context.validatorCount = validatorCount_;
+
+ if (allOf_.schemas)
+ CreateSchemaValidators(context, allOf_);
+
+ if (anyOf_.schemas)
+ CreateSchemaValidators(context, anyOf_);
+
+ if (oneOf_.schemas)
+ CreateSchemaValidators(context, oneOf_);
+
+ if (not_)
+ context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
+
+ if (hasSchemaDependencies_) {
+ for (SizeType i = 0; i < propertyCount_; i++)
+ if (properties_[i].dependenciesSchema)
+ context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
+ }
+ }
+
+ return true;
+ }
+
+ void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
+ for (SizeType i = 0; i < schemas.count; i++)
+ context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
+ }
+
+ // O(n)
+ bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
+ SizeType len = name.GetStringLength();
+ const Ch* str = name.GetString();
+ for (SizeType index = 0; index < propertyCount_; index++)
+ if (properties_[index].name.GetStringLength() == len &&
+ (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
+ {
+ *outIndex = index;
+ return true;
+ }
+ return false;
+ }
+
+ bool CheckInt(Context& context, int64_t i) const {
+ if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (!minimum_.IsNull()) {
+ if (minimum_.IsInt64()) {
+ if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ }
+ else if (minimum_.IsUint64()) {
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
+ }
+ else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!maximum_.IsNull()) {
+ if (maximum_.IsInt64()) {
+ if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ }
+ else if (maximum_.IsUint64())
+ /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64()
+ else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!multipleOf_.IsNull()) {
+ if (multipleOf_.IsUint64()) {
+ if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ }
+ else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
+ return false;
+ }
+
+ return true;
+ }
+
+ bool CheckUint(Context& context, uint64_t i) const {
+ if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (!minimum_.IsNull()) {
+ if (minimum_.IsUint64()) {
+ if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ }
+ else if (minimum_.IsInt64())
+ /* do nothing */; // i >= 0 > minimum.Getint64()
+ else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!maximum_.IsNull()) {
+ if (maximum_.IsUint64()) {
+ if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ }
+ else if (maximum_.IsInt64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
+ else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!multipleOf_.IsNull()) {
+ if (multipleOf_.IsUint64()) {
+ if (i % multipleOf_.GetUint64() != 0)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ }
+ else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
+ return false;
+ }
+
+ return true;
+ }
+
+ bool CheckDoubleMinimum(Context& context, double d) const {
+ if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ return true;
+ }
+
+ bool CheckDoubleMaximum(Context& context, double d) const {
+ if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ return true;
+ }
+
+ bool CheckDoubleMultipleOf(Context& context, double d) const {
+ double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
+ double q = std::floor(a / b);
+ double r = a - q * b;
+ if (r > 0.0)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ return true;
+ }
+
+ struct Property {
+ Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
+ ~Property() { AllocatorType::Free(dependencies); }
+ SValue name;
+ const SchemaType* schema;
+ const SchemaType* dependenciesSchema;
+ SizeType dependenciesValidatorIndex;
+ bool* dependencies;
+ bool required;
+ };
+
+ struct PatternProperty {
+ PatternProperty() : schema(), pattern() {}
+ ~PatternProperty() {
+ if (pattern) {
+ pattern->~RegexType();
+ AllocatorType::Free(pattern);
+ }
+ }
+ const SchemaType* schema;
+ RegexType* pattern;
+ };
+
+ AllocatorType* allocator_;
+ const SchemaType* typeless_;
+ uint64_t* enum_;
+ SizeType enumCount_;
+ SchemaArray allOf_;
+ SchemaArray anyOf_;
+ SchemaArray oneOf_;
+ const SchemaType* not_;
+ unsigned type_; // bitmask of kSchemaType
+ SizeType validatorCount_;
+ SizeType notValidatorIndex_;
+
+ Property* properties_;
+ const SchemaType* additionalPropertiesSchema_;
+ PatternProperty* patternProperties_;
+ SizeType patternPropertyCount_;
+ SizeType propertyCount_;
+ SizeType minProperties_;
+ SizeType maxProperties_;
+ bool additionalProperties_;
+ bool hasDependencies_;
+ bool hasRequired_;
+ bool hasSchemaDependencies_;
+
+ const SchemaType* additionalItemsSchema_;
+ const SchemaType* itemsList_;
+ const SchemaType** itemsTuple_;
+ SizeType itemsTupleCount_;
+ SizeType minItems_;
+ SizeType maxItems_;
+ bool additionalItems_;
+ bool uniqueItems_;
+
+ RegexType* pattern_;
+ SizeType minLength_;
+ SizeType maxLength_;
+
+ SValue minimum_;
+ SValue maximum_;
+ SValue multipleOf_;
+ bool exclusiveMinimum_;
+ bool exclusiveMaximum_;
+};
+
+template<typename Stack, typename Ch>
+struct TokenHelper {
+ RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
+ *documentStack.template Push<Ch>() = '/';
+ char buffer[21];
+ size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
+ for (size_t i = 0; i < length; i++)
+ *documentStack.template Push<Ch>() = buffer[i];
+ }
+};
+
+// Partial specialized version for char to prevent buffer copying.
+template <typename Stack>
+struct TokenHelper<Stack, char> {
+ RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
+ if (sizeof(SizeType) == 4) {
+ char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
+ *buffer++ = '/';
+ const char* end = internal::u32toa(index, buffer);
+ documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
+ }
+ else {
+ char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
+ *buffer++ = '/';
+ const char* end = internal::u64toa(index, buffer);
+ documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
+ }
+ }
+};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// IGenericRemoteSchemaDocumentProvider
+
+template <typename SchemaDocumentType>
+class IGenericRemoteSchemaDocumentProvider {
+public:
+ typedef typename SchemaDocumentType::Ch Ch;
+
+ virtual ~IGenericRemoteSchemaDocumentProvider() {}
+ virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericSchemaDocument
+
+//! JSON schema document.
+/*!
+ A JSON schema document is a compiled version of a JSON schema.
+ It is basically a tree of internal::Schema.
+
+ \note This is an immutable class (i.e. its instance cannot be modified after construction).
+ \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
+ \tparam Allocator Allocator type for allocating memory of this document.
+*/
+template <typename ValueT, typename Allocator = CrtAllocator>
+class GenericSchemaDocument {
+public:
+ typedef ValueT ValueType;
+ typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
+ typedef Allocator AllocatorType;
+ typedef typename ValueType::EncodingType EncodingType;
+ typedef typename EncodingType::Ch Ch;
+ typedef internal::Schema<GenericSchemaDocument> SchemaType;
+ typedef GenericPointer<ValueType, Allocator> PointerType;
+ friend class internal::Schema<GenericSchemaDocument>;
+ template <typename, typename, typename>
+ friend class GenericSchemaValidator;
+
+ //! Constructor.
+ /*!
+ Compile a JSON document into schema document.
+
+ \param document A JSON document as source.
+ \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
+ \param allocator An optional allocator instance for allocating memory. Can be null.
+ */
+ explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
+ remoteProvider_(remoteProvider),
+ allocator_(allocator),
+ ownAllocator_(),
+ root_(),
+ typeless_(),
+ schemaMap_(allocator, kInitialSchemaMapSize),
+ schemaRef_(allocator, kInitialSchemaRefSize)
+ {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+ typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
+ new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0);
+
+ // Generate root schema, it will call CreateSchema() to create sub-schemas,
+ // And call AddRefSchema() if there are $ref.
+ CreateSchemaRecursive(&root_, PointerType(), document, document);
+
+ // Resolve $ref
+ while (!schemaRef_.Empty()) {
+ SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
+ if (const SchemaType* s = GetSchema(refEntry->target)) {
+ if (refEntry->schema)
+ *refEntry->schema = s;
+
+ // Create entry in map if not exist
+ if (!GetSchema(refEntry->source)) {
+ new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
+ }
+ }
+ else if (refEntry->schema)
+ *refEntry->schema = typeless_;
+
+ refEntry->~SchemaRefEntry();
+ }
+
+ RAPIDJSON_ASSERT(root_ != 0);
+
+ schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
+ remoteProvider_(rhs.remoteProvider_),
+ allocator_(rhs.allocator_),
+ ownAllocator_(rhs.ownAllocator_),
+ root_(rhs.root_),
+ typeless_(rhs.typeless_),
+ schemaMap_(std::move(rhs.schemaMap_)),
+ schemaRef_(std::move(rhs.schemaRef_))
+ {
+ rhs.remoteProvider_ = 0;
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.typeless_ = 0;
+ }
+#endif
+
+ //! Destructor
+ ~GenericSchemaDocument() {
+ while (!schemaMap_.Empty())
+ schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
+
+ if (typeless_) {
+ typeless_->~SchemaType();
+ Allocator::Free(typeless_);
+ }
+
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
+ //! Get the root schema.
+ const SchemaType& GetRoot() const { return *root_; }
+
+private:
+ //! Prohibit copying
+ GenericSchemaDocument(const GenericSchemaDocument&);
+ //! Prohibit assignment
+ GenericSchemaDocument& operator=(const GenericSchemaDocument&);
+
+ struct SchemaRefEntry {
+ SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
+ PointerType source;
+ PointerType target;
+ const SchemaType** schema;
+ };
+
+ struct SchemaEntry {
+ SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
+ ~SchemaEntry() {
+ if (owned) {
+ schema->~SchemaType();
+ Allocator::Free(schema);
+ }
+ }
+ PointerType pointer;
+ SchemaType* schema;
+ bool owned;
+ };
+
+ void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
+ if (schema)
+ *schema = typeless_;
+
+ if (v.GetType() == kObjectType) {
+ const SchemaType* s = GetSchema(pointer);
+ if (!s)
+ CreateSchema(schema, pointer, v, document);
+
+ for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
+ CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
+ }
+ else if (v.GetType() == kArrayType)
+ for (SizeType i = 0; i < v.Size(); i++)
+ CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
+ }
+
+ void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
+ RAPIDJSON_ASSERT(pointer.IsValid());
+ if (v.IsObject()) {
+ if (!HandleRefSchema(pointer, schema, v, document)) {
+ SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);
+ new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);
+ if (schema)
+ *schema = s;
+ }
+ }
+ }
+
+ bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {
+ static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
+ static const ValueType kRefValue(kRefString, 4);
+
+ typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
+ if (itr == v.MemberEnd())
+ return false;
+
+ if (itr->value.IsString()) {
+ SizeType len = itr->value.GetStringLength();
+ if (len > 0) {
+ const Ch* s = itr->value.GetString();
+ SizeType i = 0;
+ while (i < len && s[i] != '#') // Find the first #
+ i++;
+
+ if (i > 0) { // Remote reference, resolve immediately
+ if (remoteProvider_) {
+ if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
+ PointerType pointer(&s[i], len - i, allocator_);
+ if (pointer.IsValid()) {
+ if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
+ if (schema)
+ *schema = sc;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ else if (s[i] == '#') { // Local reference, defer resolution
+ PointerType pointer(&s[i], len - i, allocator_);
+ if (pointer.IsValid()) {
+ if (const ValueType* nv = pointer.Get(document))
+ if (HandleRefSchema(source, schema, *nv, document))
+ return true;
+
+ new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ const SchemaType* GetSchema(const PointerType& pointer) const {
+ for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
+ if (pointer == target->pointer)
+ return target->schema;
+ return 0;
+ }
+
+ PointerType GetPointer(const SchemaType* schema) const {
+ for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
+ if (schema == target->schema)
+ return target->pointer;
+ return PointerType();
+ }
+
+ const SchemaType* GetTypeless() const { return typeless_; }
+
+ static const size_t kInitialSchemaMapSize = 64;
+ static const size_t kInitialSchemaRefSize = 64;
+
+ IRemoteSchemaDocumentProviderType* remoteProvider_;
+ Allocator *allocator_;
+ Allocator *ownAllocator_;
+ const SchemaType* root_; //!< Root schema.
+ SchemaType* typeless_;
+ internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
+ internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref
+};
+
+//! GenericSchemaDocument using Value type.
+typedef GenericSchemaDocument<Value> SchemaDocument;
+//! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
+typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericSchemaValidator
+
+//! JSON Schema Validator.
+/*!
+ A SAX style JSON schema validator.
+ It uses a \c GenericSchemaDocument to validate SAX events.
+ It delegates the incoming SAX events to an output handler.
+ The default output handler does nothing.
+ It can be reused multiple times by calling \c Reset().
+
+ \tparam SchemaDocumentType Type of schema document.
+ \tparam OutputHandler Type of output handler. Default handler does nothing.
+ \tparam StateAllocator Allocator for storing the internal validation states.
+*/
+template <
+ typename SchemaDocumentType,
+ typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
+ typename StateAllocator = CrtAllocator>
+class GenericSchemaValidator :
+ public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
+ public internal::ISchemaValidator
+{
+public:
+ typedef typename SchemaDocumentType::SchemaType SchemaType;
+ typedef typename SchemaDocumentType::PointerType PointerType;
+ typedef typename SchemaType::EncodingType EncodingType;
+ typedef typename EncodingType::Ch Ch;
+
+ //! Constructor without output handler.
+ /*!
+ \param schemaDocument The schema document to conform to.
+ \param allocator Optional allocator for storing internal validation states.
+ \param schemaStackCapacity Optional initial capacity of schema path stack.
+ \param documentStackCapacity Optional initial capacity of document path stack.
+ */
+ GenericSchemaValidator(
+ const SchemaDocumentType& schemaDocument,
+ StateAllocator* allocator = 0,
+ size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+ size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+ :
+ schemaDocument_(&schemaDocument),
+ root_(schemaDocument.GetRoot()),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
+ schemaStack_(allocator, schemaStackCapacity),
+ documentStack_(allocator, documentStackCapacity),
+ outputHandler_(CreateNullHandler()),
+ valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+ , depth_(0)
+#endif
+ {
+ }
+
+ //! Constructor with output handler.
+ /*!
+ \param schemaDocument The schema document to conform to.
+ \param allocator Optional allocator for storing internal validation states.
+ \param schemaStackCapacity Optional initial capacity of schema path stack.
+ \param documentStackCapacity Optional initial capacity of document path stack.
+ */
+ GenericSchemaValidator(
+ const SchemaDocumentType& schemaDocument,
+ OutputHandler& outputHandler,
+ StateAllocator* allocator = 0,
+ size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+ size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+ :
+ schemaDocument_(&schemaDocument),
+ root_(schemaDocument.GetRoot()),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
+ schemaStack_(allocator, schemaStackCapacity),
+ documentStack_(allocator, documentStackCapacity),
+ outputHandler_(outputHandler),
+ nullHandler_(0),
+ valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+ , depth_(0)
+#endif
+ {
+ }
+
+ //! Destructor.
+ ~GenericSchemaValidator() {
+ Reset();
+ if (nullHandler_) {
+ nullHandler_->~OutputHandler();
+ StateAllocator::Free(nullHandler_);
+ }
+ RAPIDJSON_DELETE(ownStateAllocator_);
+ }
+
+ //! Reset the internal states.
+ void Reset() {
+ while (!schemaStack_.Empty())
+ PopSchema();
+ documentStack_.Clear();
+ valid_ = true;
+ }
+
+ //! Checks whether the current state is valid.
+ // Implementation of ISchemaValidator
+ virtual bool IsValid() const { return valid_; }
+
+ //! Gets the JSON pointer pointed to the invalid schema.
+ PointerType GetInvalidSchemaPointer() const {
+ return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
+ }
+
+ //! Gets the keyword of invalid schema.
+ const Ch* GetInvalidSchemaKeyword() const {
+ return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
+ }
+
+ //! Gets the JSON pointer pointed to the invalid value.
+ PointerType GetInvalidDocumentPointer() const {
+ return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
+ }
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
+RAPIDJSON_MULTILINEMACRO_BEGIN\
+ *documentStack_.template Push<Ch>() = '\0';\
+ documentStack_.template Pop<Ch>(1);\
+ internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
+RAPIDJSON_MULTILINEMACRO_END
+#else
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
+#endif
+
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
+ if (!valid_) return false; \
+ if (!BeginValue() || !CurrentSchema().method arg1) {\
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
+ return valid_ = false;\
+ }
+
+#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
+ for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
+ if (context->hasher)\
+ static_cast<HasherType*>(context->hasher)->method arg2;\
+ if (context->validators)\
+ for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
+ static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
+ if (context->patternPropertiesValidators)\
+ for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
+ static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
+ }
+
+#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
+ return valid_ = EndValue() && outputHandler_.method arg2
+
+#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
+ RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
+
+ bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); }
+ bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
+ bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
+ bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
+ bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
+ bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
+ bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
+ bool RawNumber(const Ch* str, SizeType length, bool copy)
+ { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
+ bool String(const Ch* str, SizeType length, bool copy)
+ { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
+
+ bool StartObject() {
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
+ return valid_ = outputHandler_.StartObject();
+ }
+
+ bool Key(const Ch* str, SizeType len, bool copy) {
+ if (!valid_) return false;
+ AppendToken(str, len);
+ if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
+ return valid_ = outputHandler_.Key(str, len, copy);
+ }
+
+ bool EndObject(SizeType memberCount) {
+ if (!valid_) return false;
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
+ if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
+ RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
+ }
+
+ bool StartArray() {
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
+ return valid_ = outputHandler_.StartArray();
+ }
+
+ bool EndArray(SizeType elementCount) {
+ if (!valid_) return false;
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
+ if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
+ RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
+ }
+
+#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
+#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
+#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
+#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
+
+ // Implementation of ISchemaStateFactory<SchemaType>
+ virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
+ return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root,
+#if RAPIDJSON_SCHEMA_VERBOSE
+ depth_ + 1,
+#endif
+ &GetStateAllocator());
+ }
+
+ virtual void DestroySchemaValidator(ISchemaValidator* validator) {
+ GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
+ v->~GenericSchemaValidator();
+ StateAllocator::Free(v);
+ }
+
+ virtual void* CreateHasher() {
+ return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
+ }
+
+ virtual uint64_t GetHashCode(void* hasher) {
+ return static_cast<HasherType*>(hasher)->GetHashCode();
+ }
+
+ virtual void DestroryHasher(void* hasher) {
+ HasherType* h = static_cast<HasherType*>(hasher);
+ h->~HasherType();
+ StateAllocator::Free(h);
+ }
+
+ virtual void* MallocState(size_t size) {
+ return GetStateAllocator().Malloc(size);
+ }
+
+ virtual void FreeState(void* p) {
+ return StateAllocator::Free(p);
+ }
+
+private:
+ typedef typename SchemaType::Context Context;
+ typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
+ typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
+
+ GenericSchemaValidator(
+ const SchemaDocumentType& schemaDocument,
+ const SchemaType& root,
+#if RAPIDJSON_SCHEMA_VERBOSE
+ unsigned depth,
+#endif
+ StateAllocator* allocator = 0,
+ size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+ size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+ :
+ schemaDocument_(&schemaDocument),
+ root_(root),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
+ schemaStack_(allocator, schemaStackCapacity),
+ documentStack_(allocator, documentStackCapacity),
+ outputHandler_(CreateNullHandler()),
+ valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+ , depth_(depth)
+#endif
+ {
+ }
+
+ StateAllocator& GetStateAllocator() {
+ if (!stateAllocator_)
+ stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator());
+ return *stateAllocator_;
+ }
+
+ bool BeginValue() {
+ if (schemaStack_.Empty())
+ PushSchema(root_);
+ else {
+ if (CurrentContext().inArray)
+ internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
+
+ if (!CurrentSchema().BeginValue(CurrentContext()))
+ return false;
+
+ SizeType count = CurrentContext().patternPropertiesSchemaCount;
+ const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
+ typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
+ bool valueUniqueness = CurrentContext().valueUniqueness;
+ RAPIDJSON_ASSERT(CurrentContext().valueSchema);
+ PushSchema(*CurrentContext().valueSchema);
+
+ if (count > 0) {
+ CurrentContext().objectPatternValidatorType = patternValidatorType;
+ ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
+ SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
+ va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
+ for (SizeType i = 0; i < count; i++)
+ va[validatorCount++] = CreateSchemaValidator(*sa[i]);
+ }
+
+ CurrentContext().arrayUniqueness = valueUniqueness;
+ }
+ return true;
+ }
+
+ bool EndValue() {
+ if (!CurrentSchema().EndValue(CurrentContext()))
+ return false;
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+ GenericStringBuffer<EncodingType> sb;
+ schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
+
+ *documentStack_.template Push<Ch>() = '\0';
+ documentStack_.template Pop<Ch>(1);
+ internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
+#endif
+
+ uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
+
+ PopSchema();
+
+ if (!schemaStack_.Empty()) {
+ Context& context = CurrentContext();
+ if (context.valueUniqueness) {
+ HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
+ if (!a)
+ CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
+ for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
+ if (itr->GetUint64() == h)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
+ a->PushBack(h, GetStateAllocator());
+ }
+ }
+
+ // Remove the last token of document pointer
+ while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
+ ;
+
+ return true;
+ }
+
+ void AppendToken(const Ch* str, SizeType len) {
+ documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
+ *documentStack_.template PushUnsafe<Ch>() = '/';
+ for (SizeType i = 0; i < len; i++) {
+ if (str[i] == '~') {
+ *documentStack_.template PushUnsafe<Ch>() = '~';
+ *documentStack_.template PushUnsafe<Ch>() = '0';
+ }
+ else if (str[i] == '/') {
+ *documentStack_.template PushUnsafe<Ch>() = '~';
+ *documentStack_.template PushUnsafe<Ch>() = '1';
+ }
+ else
+ *documentStack_.template PushUnsafe<Ch>() = str[i];
+ }
+ }
+
+ RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); }
+
+ RAPIDJSON_FORCEINLINE void PopSchema() {
+ Context* c = schemaStack_.template Pop<Context>(1);
+ if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
+ a->~HashCodeArray();
+ StateAllocator::Free(a);
+ }
+ c->~Context();
+ }
+
+ const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
+ Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
+ const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
+
+ OutputHandler& CreateNullHandler() {
+ return *(nullHandler_ = static_cast<OutputHandler*>(GetStateAllocator().Malloc(sizeof(OutputHandler))));
+ }
+
+ static const size_t kDefaultSchemaStackCapacity = 1024;
+ static const size_t kDefaultDocumentStackCapacity = 256;
+ const SchemaDocumentType* schemaDocument_;
+ const SchemaType& root_;
+ StateAllocator* stateAllocator_;
+ StateAllocator* ownStateAllocator_;
+ internal::Stack<StateAllocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
+ internal::Stack<StateAllocator> documentStack_; //!< stack to store the current path of validating document (Ch)
+ OutputHandler& outputHandler_;
+ OutputHandler* nullHandler_;
+ bool valid_;
+#if RAPIDJSON_SCHEMA_VERBOSE
+ unsigned depth_;
+#endif
+};
+
+typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
+
+///////////////////////////////////////////////////////////////////////////////
+// SchemaValidatingReader
+
+//! A helper class for parsing with validation.
+/*!
+ This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
+
+ \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam InputStream Type of input stream, implementing Stream concept.
+ \tparam SourceEncoding Encoding of the input stream.
+ \tparam SchemaDocumentType Type of schema document.
+ \tparam StackAllocator Allocator type for stack.
+*/
+template <
+ unsigned parseFlags,
+ typename InputStream,
+ typename SourceEncoding,
+ typename SchemaDocumentType = SchemaDocument,
+ typename StackAllocator = CrtAllocator>
+class SchemaValidatingReader {
+public:
+ typedef typename SchemaDocumentType::PointerType PointerType;
+ typedef typename InputStream::Ch Ch;
+
+ //! Constructor
+ /*!
+ \param is Input stream.
+ \param sd Schema document.
+ */
+ SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
+
+ template <typename Handler>
+ bool operator()(Handler& handler) {
+ GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;
+ GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
+ parseResult_ = reader.template Parse<parseFlags>(is_, validator);
+
+ isValid_ = validator.IsValid();
+ if (isValid_) {
+ invalidSchemaPointer_ = PointerType();
+ invalidSchemaKeyword_ = 0;
+ invalidDocumentPointer_ = PointerType();
+ }
+ else {
+ invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
+ invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
+ invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
+ }
+
+ return parseResult_;
+ }
+
+ const ParseResult& GetParseResult() const { return parseResult_; }
+ bool IsValid() const { return isValid_; }
+ const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
+ const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
+ const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
+
+private:
+ InputStream& is_;
+ const SchemaDocumentType& sd_;
+
+ ParseResult parseResult_;
+ PointerType invalidSchemaPointer_;
+ const Ch* invalidSchemaKeyword_;
+ PointerType invalidDocumentPointer_;
+ bool isValid_;
+};
+
+RAPIDJSON_NAMESPACE_END
+RAPIDJSON_DIAG_POP
+
+#endif // RAPIDJSON_SCHEMA_H_
diff --git a/external/rapidjson/rapidjson/stream.h b/external/rapidjson/rapidjson/stream.h
new file mode 100644
index 0000000..fef82c2
--- /dev/null
+++ b/external/rapidjson/rapidjson/stream.h
@@ -0,0 +1,179 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "rapidjson.h"
+
+#ifndef RAPIDJSON_STREAM_H_
+#define RAPIDJSON_STREAM_H_
+
+#include "encodings.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Stream
+
+/*! \class rapidjson::Stream
+ \brief Concept for reading and writing characters.
+
+ For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
+
+ For write-only stream, only need to implement Put() and Flush().
+
+\code
+concept Stream {
+ typename Ch; //!< Character type of the stream.
+
+ //! Read the current character from stream without moving the read cursor.
+ Ch Peek() const;
+
+ //! Read the current character from stream and moving the read cursor to next character.
+ Ch Take();
+
+ //! Get the current read cursor.
+ //! \return Number of characters read from start.
+ size_t Tell();
+
+ //! Begin writing operation at the current read pointer.
+ //! \return The begin writer pointer.
+ Ch* PutBegin();
+
+ //! Write a character.
+ void Put(Ch c);
+
+ //! Flush the buffer.
+ void Flush();
+
+ //! End the writing operation.
+ //! \param begin The begin write pointer returned by PutBegin().
+ //! \return Number of characters written.
+ size_t PutEnd(Ch* begin);
+}
+\endcode
+*/
+
+//! Provides additional information for stream.
+/*!
+ By using traits pattern, this type provides a default configuration for stream.
+ For custom stream, this type can be specialized for other configuration.
+ See TEST(Reader, CustomStringStream) in readertest.cpp for example.
+*/
+template<typename Stream>
+struct StreamTraits {
+ //! Whether to make local copy of stream for optimization during parsing.
+ /*!
+ By default, for safety, streams do not use local copy optimization.
+ Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
+ */
+ enum { copyOptimization = 0 };
+};
+
+//! Reserve n characters for writing to a stream.
+template<typename Stream>
+inline void PutReserve(Stream& stream, size_t count) {
+ (void)stream;
+ (void)count;
+}
+
+//! Write character to a stream, presuming buffer is reserved.
+template<typename Stream>
+inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
+ stream.Put(c);
+}
+
+//! Put N copies of a character to a stream.
+template<typename Stream, typename Ch>
+inline void PutN(Stream& stream, Ch c, size_t n) {
+ PutReserve(stream, n);
+ for (size_t i = 0; i < n; i++)
+ PutUnsafe(stream, c);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StringStream
+
+//! Read-only string stream.
+/*! \note implements Stream concept
+*/
+template <typename Encoding>
+struct GenericStringStream {
+ typedef typename Encoding::Ch Ch;
+
+ GenericStringStream(const Ch *src) : src_(src), head_(src) {}
+
+ Ch Peek() const { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() const { return static_cast<size_t>(src_ - head_); }
+
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ const Ch* src_; //!< Current read position.
+ const Ch* head_; //!< Original head of the string.
+};
+
+template <typename Encoding>
+struct StreamTraits<GenericStringStream<Encoding> > {
+ enum { copyOptimization = 1 };
+};
+
+//! String stream with UTF8 encoding.
+typedef GenericStringStream<UTF8<> > StringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// InsituStringStream
+
+//! A read-write string stream.
+/*! This string stream is particularly designed for in-situ parsing.
+ \note implements Stream concept
+*/
+template <typename Encoding>
+struct GenericInsituStringStream {
+ typedef typename Encoding::Ch Ch;
+
+ GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
+
+ // Read
+ Ch Peek() { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() { return static_cast<size_t>(src_ - head_); }
+
+ // Write
+ void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
+
+ Ch* PutBegin() { return dst_ = src_; }
+ size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
+ void Flush() {}
+
+ Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
+ void Pop(size_t count) { dst_ -= count; }
+
+ Ch* src_;
+ Ch* dst_;
+ Ch* head_;
+};
+
+template <typename Encoding>
+struct StreamTraits<GenericInsituStringStream<Encoding> > {
+ enum { copyOptimization = 1 };
+};
+
+//! Insitu string stream with UTF8 encoding.
+typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STREAM_H_
diff --git a/external/rapidjson/rapidjson/stringbuffer.h b/external/rapidjson/rapidjson/stringbuffer.h
new file mode 100644
index 0000000..4e38b82
--- /dev/null
+++ b/external/rapidjson/rapidjson/stringbuffer.h
@@ -0,0 +1,121 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_STRINGBUFFER_H_
+#define RAPIDJSON_STRINGBUFFER_H_
+
+#include "stream.h"
+#include "internal/stack.h"
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+#include "internal/stack.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output stream.
+/*!
+ \tparam Encoding Encoding of the stream.
+ \tparam Allocator type for allocating memory buffer.
+ \note implements Stream concept
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+class GenericStringBuffer {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
+ GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
+ if (&rhs != this)
+ stack_ = std::move(rhs.stack_);
+ return *this;
+ }
+#endif
+
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+ void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
+ void Flush() {}
+
+ void Clear() { stack_.Clear(); }
+ void ShrinkToFit() {
+ // Push and pop a null terminator. This is safe.
+ *stack_.template Push<Ch>() = '\0';
+ stack_.ShrinkToFit();
+ stack_.template Pop<Ch>(1);
+ }
+
+ void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
+ Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+ Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
+ void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+ const Ch* GetString() const {
+ // Push and pop a null terminator. This is safe.
+ *stack_.template Push<Ch>() = '\0';
+ stack_.template Pop<Ch>(1);
+
+ return stack_.template Bottom<Ch>();
+ }
+
+ //! Get the size of string in bytes in the string buffer.
+ size_t GetSize() const { return stack_.GetSize(); }
+
+ //! Get the length of string in Ch in the string buffer.
+ size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); }
+
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> stack_;
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ GenericStringBuffer(const GenericStringBuffer&);
+ GenericStringBuffer& operator=(const GenericStringBuffer&);
+};
+
+//! String buffer with UTF8 encoding
+typedef GenericStringBuffer<UTF8<> > StringBuffer;
+
+template<typename Encoding, typename Allocator>
+inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
+ stream.Reserve(count);
+}
+
+template<typename Encoding, typename Allocator>
+inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
+ stream.PutUnsafe(c);
+}
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
+ std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_STRINGBUFFER_H_
diff --git a/external/rapidjson/rapidjson/writer.h b/external/rapidjson/rapidjson/writer.h
new file mode 100644
index 0000000..8f6e174
--- /dev/null
+++ b/external/rapidjson/rapidjson/writer.h
@@ -0,0 +1,624 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_WRITER_H_
+#define RAPIDJSON_WRITER_H_
+
+#include "stream.h"
+#include "internal/stack.h"
+#include "internal/strfunc.h"
+#include "internal/dtoa.h"
+#include "internal/itoa.h"
+#include "stringbuffer.h"
+#include <new> // placement new
+
+#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(_BitScanForward)
+#endif
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(unreachable-code)
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// WriteFlag
+
+/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-defined kWriteDefaultFlags definition.
+
+ User can define this as any \c WriteFlag combinations.
+*/
+#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
+#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
+#endif
+
+//! Combination of writeFlags
+enum WriteFlag {
+ kWriteNoFlags = 0, //!< No flags are set.
+ kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
+ kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
+ kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
+};
+
+//! JSON writer
+/*! Writer implements the concept Handler.
+ It generates JSON text by events to an output os.
+
+ User may programmatically calls the functions of a writer to generate JSON text.
+
+ On the other side, a writer can also be passed to objects that generates events,
+
+ for example Reader::Parse() and Document::Accept().
+
+ \tparam OutputStream Type of output stream.
+ \tparam SourceEncoding Encoding of source string.
+ \tparam TargetEncoding Encoding of output stream.
+ \tparam StackAllocator Type of allocator for allocating memory of stack.
+ \note implements Handler concept
+*/
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
+class Writer {
+public:
+ typedef typename SourceEncoding::Ch Ch;
+
+ static const int kDefaultMaxDecimalPlaces = 324;
+
+ //! Constructor
+ /*! \param os Output stream.
+ \param stackAllocator User supplied allocator. If it is null, it will create a private one.
+ \param levelDepth Initial capacity of stack.
+ */
+ explicit
+ Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
+ os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
+
+ explicit
+ Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
+ os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ Writer(Writer&& rhs) :
+ os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
+ rhs.os_ = 0;
+ }
+#endif
+
+ //! Reset the writer with a new stream.
+ /*!
+ This function reset the writer with a new stream and default settings,
+ in order to make a Writer object reusable for output multiple JSONs.
+
+ \param os New output stream.
+ \code
+ Writer<OutputStream> writer(os1);
+ writer.StartObject();
+ // ...
+ writer.EndObject();
+
+ writer.Reset(os2);
+ writer.StartObject();
+ // ...
+ writer.EndObject();
+ \endcode
+ */
+ void Reset(OutputStream& os) {
+ os_ = &os;
+ hasRoot_ = false;
+ level_stack_.Clear();
+ }
+
+ //! Checks whether the output is a complete JSON.
+ /*!
+ A complete JSON has a complete root object or array.
+ */
+ bool IsComplete() const {
+ return hasRoot_ && level_stack_.Empty();
+ }
+
+ int GetMaxDecimalPlaces() const {
+ return maxDecimalPlaces_;
+ }
+
+ //! Sets the maximum number of decimal places for double output.
+ /*!
+ This setting truncates the output with specified number of decimal places.
+
+ For example,
+
+ \code
+ writer.SetMaxDecimalPlaces(3);
+ writer.StartArray();
+ writer.Double(0.12345); // "0.123"
+ writer.Double(0.0001); // "0.0"
+ writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent)
+ writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent)
+ writer.EndArray();
+ \endcode
+
+ The default setting does not truncate any decimal places. You can restore to this setting by calling
+ \code
+ writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
+ \endcode
+ */
+ void SetMaxDecimalPlaces(int maxDecimalPlaces) {
+ maxDecimalPlaces_ = maxDecimalPlaces;
+ }
+
+ /*!@name Implementation of Handler
+ \see Handler
+ */
+ //@{
+
+ bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
+ bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
+ bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
+ bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
+ bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
+ bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
+
+ //! Writes the given \c double value to the stream
+ /*!
+ \param d The value to be written.
+ \return Whether it is succeed.
+ */
+ bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
+
+ bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
+ RAPIDJSON_ASSERT(str != 0);
+ (void)copy;
+ Prefix(kNumberType);
+ return EndValue(WriteString(str, length));
+ }
+
+ bool String(const Ch* str, SizeType length, bool copy = false) {
+ RAPIDJSON_ASSERT(str != 0);
+ (void)copy;
+ Prefix(kStringType);
+ return EndValue(WriteString(str, length));
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool String(const std::basic_string<Ch>& str) {
+ return String(str.data(), SizeType(str.size()));
+ }
+#endif
+
+ bool StartObject() {
+ Prefix(kObjectType);
+ new (level_stack_.template Push<Level>()) Level(false);
+ return WriteStartObject();
+ }
+
+ bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
+
+ bool EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ return EndValue(WriteEndObject());
+ }
+
+ bool StartArray() {
+ Prefix(kArrayType);
+ new (level_stack_.template Push<Level>()) Level(true);
+ return WriteStartArray();
+ }
+
+ bool EndArray(SizeType elementCount = 0) {
+ (void)elementCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ return EndValue(WriteEndArray());
+ }
+ //@}
+
+ /*! @name Convenience extensions */
+ //@{
+
+ //! Simpler but slower overload.
+ bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
+ bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
+
+ //@}
+
+ //! Write a raw JSON value.
+ /*!
+ For user to write a stringified JSON as a value.
+
+ \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
+ \param length Length of the json.
+ \param type Type of the root of json.
+ */
+ bool RawValue(const Ch* json, size_t length, Type type) {
+ RAPIDJSON_ASSERT(json != 0);
+ Prefix(type);
+ return EndValue(WriteRawValue(json, length));
+ }
+
+protected:
+ //! Information for each nested level
+ struct Level {
+ Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
+ size_t valueCount; //!< number of values in this level
+ bool inArray; //!< true if in array, otherwise in object
+ };
+
+ static const size_t kDefaultLevelDepth = 32;
+
+ bool WriteNull() {
+ PutReserve(*os_, 4);
+ PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
+ }
+
+ bool WriteBool(bool b) {
+ if (b) {
+ PutReserve(*os_, 4);
+ PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
+ }
+ else {
+ PutReserve(*os_, 5);
+ PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
+ }
+ return true;
+ }
+
+ bool WriteInt(int i) {
+ char buffer[11];
+ const char* end = internal::i32toa(i, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (const char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteUint(unsigned u) {
+ char buffer[10];
+ const char* end = internal::u32toa(u, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (const char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteInt64(int64_t i64) {
+ char buffer[21];
+ const char* end = internal::i64toa(i64, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (const char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteUint64(uint64_t u64) {
+ char buffer[20];
+ char* end = internal::u64toa(u64, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteDouble(double d) {
+ if (internal::Double(d).IsNanOrInf()) {
+ if (!(writeFlags & kWriteNanAndInfFlag))
+ return false;
+ if (internal::Double(d).IsNan()) {
+ PutReserve(*os_, 3);
+ PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
+ return true;
+ }
+ if (internal::Double(d).Sign()) {
+ PutReserve(*os_, 9);
+ PutUnsafe(*os_, '-');
+ }
+ else
+ PutReserve(*os_, 8);
+ PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
+ PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
+ return true;
+ }
+
+ char buffer[25];
+ char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteString(const Ch* str, SizeType length) {
+ static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ static const char escape[256] = {
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ //0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
+ 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
+ Z16, Z16, // 30~4F
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
+ Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
+#undef Z16
+ };
+
+ if (TargetEncoding::supportUnicode)
+ PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
+ else
+ PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
+
+ PutUnsafe(*os_, '\"');
+ GenericStringStream<SourceEncoding> is(str);
+ while (ScanWriteUnescapedString(is, length)) {
+ const Ch c = is.Peek();
+ if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
+ // Unicode escaping
+ unsigned codepoint;
+ if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
+ return false;
+ PutUnsafe(*os_, '\\');
+ PutUnsafe(*os_, 'u');
+ if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
+ PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
+ PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
+ PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
+ PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
+ // Surrogate pair
+ unsigned s = codepoint - 0x010000;
+ unsigned lead = (s >> 10) + 0xD800;
+ unsigned trail = (s & 0x3FF) + 0xDC00;
+ PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
+ PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
+ PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
+ PutUnsafe(*os_, hexDigits[(lead ) & 15]);
+ PutUnsafe(*os_, '\\');
+ PutUnsafe(*os_, 'u');
+ PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
+ PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
+ PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
+ PutUnsafe(*os_, hexDigits[(trail ) & 15]);
+ }
+ }
+ else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
+ is.Take();
+ PutUnsafe(*os_, '\\');
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
+ if (escape[static_cast<unsigned char>(c)] == 'u') {
+ PutUnsafe(*os_, '0');
+ PutUnsafe(*os_, '0');
+ PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
+ PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
+ }
+ }
+ else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
+ Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
+ Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
+ return false;
+ }
+ PutUnsafe(*os_, '\"');
+ return true;
+ }
+
+ bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+ }
+
+ bool WriteStartObject() { os_->Put('{'); return true; }
+ bool WriteEndObject() { os_->Put('}'); return true; }
+ bool WriteStartArray() { os_->Put('['); return true; }
+ bool WriteEndArray() { os_->Put(']'); return true; }
+
+ bool WriteRawValue(const Ch* json, size_t length) {
+ PutReserve(*os_, length);
+ for (size_t i = 0; i < length; i++) {
+ RAPIDJSON_ASSERT(json[i] != '\0');
+ PutUnsafe(*os_, json[i]);
+ }
+ return true;
+ }
+
+ void Prefix(Type type) {
+ (void)type;
+ if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
+ Level* level = level_stack_.template Top<Level>();
+ if (level->valueCount > 0) {
+ if (level->inArray)
+ os_->Put(','); // add comma if it is not the first element in array
+ else // in object
+ os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
+ }
+ if (!level->inArray && level->valueCount % 2 == 0)
+ RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
+ level->valueCount++;
+ }
+ else {
+ RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
+ hasRoot_ = true;
+ }
+ }
+
+ // Flush the value if it is the top level one.
+ bool EndValue(bool ret) {
+ if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
+ os_->Flush();
+ return ret;
+ }
+
+ OutputStream* os_;
+ internal::Stack<StackAllocator> level_stack_;
+ int maxDecimalPlaces_;
+ bool hasRoot_;
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ Writer(const Writer&);
+ Writer& operator=(const Writer&);
+};
+
+// Full specialization for StringStream to prevent memory copying
+
+template<>
+inline bool Writer<StringBuffer>::WriteInt(int i) {
+ char *buffer = os_->Push(11);
+ const char* end = internal::i32toa(i, buffer);
+ os_->Pop(static_cast<size_t>(11 - (end - buffer)));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
+ char *buffer = os_->Push(10);
+ const char* end = internal::u32toa(u, buffer);
+ os_->Pop(static_cast<size_t>(10 - (end - buffer)));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
+ char *buffer = os_->Push(21);
+ const char* end = internal::i64toa(i64, buffer);
+ os_->Pop(static_cast<size_t>(21 - (end - buffer)));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
+ char *buffer = os_->Push(20);
+ const char* end = internal::u64toa(u, buffer);
+ os_->Pop(static_cast<size_t>(20 - (end - buffer)));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteDouble(double d) {
+ if (internal::Double(d).IsNanOrInf()) {
+ // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
+ if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
+ return false;
+ if (internal::Double(d).IsNan()) {
+ PutReserve(*os_, 3);
+ PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
+ return true;
+ }
+ if (internal::Double(d).Sign()) {
+ PutReserve(*os_, 9);
+ PutUnsafe(*os_, '-');
+ }
+ else
+ PutReserve(*os_, 8);
+ PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
+ PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
+ return true;
+ }
+
+ char *buffer = os_->Push(25);
+ char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
+ os_->Pop(static_cast<size_t>(25 - (end - buffer)));
+ return true;
+}
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+template<>
+inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
+ if (length < 16)
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+
+ if (!RAPIDJSON_LIKELY(is.Tell() < length))
+ return false;
+
+ const char* p = is.src_;
+ const char* end = is.head_ + length;
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
+ if (nextAligned > end)
+ return true;
+
+ while (p != nextAligned)
+ if (*p < 0x20 || *p == '\"' || *p == '\\') {
+ is.src_ = p;
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+ }
+ else
+ os_->PutUnsafe(*p++);
+
+ // The rest of string using SIMD
+ static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+ static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+ static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+ const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+ const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+ for (; p != endAligned; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ SizeType len;
+#ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ len = offset;
+#else
+ len = static_cast<SizeType>(__builtin_ffs(r) - 1);
+#endif
+ char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
+ for (size_t i = 0; i < len; i++)
+ q[i] = p[i];
+
+ p += len;
+ break;
+ }
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
+ }
+
+ is.src_ = p;
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+}
+#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/external/restclient/CMakeLists.txt b/external/restclient/CMakeLists.txt
new file mode 100644
index 0000000..4ca1f3c
--- /dev/null
+++ b/external/restclient/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_library(
+ restclient
+ restclient/connection.h
+ restclient/helpers.h
+ restclient/restclient.h
+ restclient/version.h
+ connection.cpp
+ helpers.cpp
+ restclient.cpp
+ )
diff --git a/external/restclient/LICENSE b/external/restclient/LICENSE
new file mode 100644
index 0000000..5c1358f
--- /dev/null
+++ b/external/restclient/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2010 Daniel Schauenberg
+
+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 AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/external/restclient/README.md b/external/restclient/README.md
new file mode 100644
index 0000000..aa95b6f
--- /dev/null
+++ b/external/restclient/README.md
@@ -0,0 +1,7 @@
+# Rest client for C++
+Modified from [mrtazz/restclient-cpp](https://github.com/mrtazz/restclient-cpp).
+
+## Changes:
+
+ - Added `CURL_FOLLOWURL` option.
+ - Flattened source & includes in one directory.
diff --git a/external/restclient/connection.cpp b/external/restclient/connection.cpp
new file mode 100644
index 0000000..e3adeb2
--- /dev/null
+++ b/external/restclient/connection.cpp
@@ -0,0 +1,363 @@
+/**
+ * @file connection.cpp
+ * @brief implementation of the connection class
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ */
+
+#include "restclient/connection.h"
+
+#include "../../src/client/cl_curl.h"
+#include <cstring>
+#include <string>
+#include <iostream>
+#include <map>
+#include <stdexcept>
+
+#include "restclient/restclient.h"
+#include "restclient/helpers.h"
+#include "restclient/version.h"
+
+/**
+ * @brief constructor for the Connection object
+ *
+ * @param baseUrl - base URL for the connection to use
+ *
+ */
+RestClient::Connection::Connection(const std::string baseUrl)
+ : lastRequest(), headerFields() {
+ this->curlHandle = qcurl_easy_init();
+ if (!this->curlHandle) {
+ throw std::runtime_error("Couldn't initialize curl handle");
+ }
+ this->baseUrl = baseUrl;
+ this->timeout = 0;
+ this->followRedirects = false;
+}
+
+RestClient::Connection::~Connection() {
+ if (this->curlHandle) {
+ qcurl_easy_cleanup(this->curlHandle);
+ }
+}
+
+// getters/setters
+
+/**
+ * @brief get diagnostic information about the connection object
+ *
+ * @return RestClient::Connection::Info struct
+ */
+RestClient::Connection::Info
+RestClient::Connection::GetInfo() {
+ RestClient::Connection::Info ret;
+ ret.baseUrl = this->baseUrl;
+ ret.headers = this->GetHeaders();
+ ret.timeout = this->timeout;
+ ret.basicAuth.username = this->basicAuth.username;
+ ret.basicAuth.password = this->basicAuth.password;
+ ret.customUserAgent = this->customUserAgent;
+ ret.lastRequest = this->lastRequest;
+
+ return ret;
+}
+
+/**
+ * @brief append a header to the internal map
+ *
+ * @param key for the header field
+ * @param value for the header field
+ *
+ */
+void
+RestClient::Connection::AppendHeader(const std::string& key,
+ const std::string& value) {
+ this->headerFields[key] = value;
+}
+
+/**
+ * @brief set the custom headers map. This will replace the currently
+ * configured headers with the provided ones. If you want to add additional
+ * headers, use AppendHeader()
+ *
+ * @param headers to set
+ */
+void
+RestClient::Connection::SetHeaders(RestClient::HeaderFields headers) {
+ this->headerFields = headers;
+}
+
+/**
+ * @brief get all custom headers set on the connection
+ *
+ * @returns a RestClient::HeaderFields map containing the custom headers
+ */
+RestClient::HeaderFields
+RestClient::Connection::GetHeaders() {
+ return this->headerFields;
+}
+
+/**
+ * @brief configure whether to follow redirects on this connection
+ *
+ * @param follow - boolean whether to follow redirects
+ */
+void
+RestClient::Connection::FollowRedirects(bool follow) {
+ this->followRedirects = follow;
+}
+
+/**
+ * @brief set custom user agent for connection. This gets prepended to the
+ * default restclient-cpp/RESTCLIENT_VERSION string
+ *
+ * @param userAgent - custom userAgent prefix
+ *
+ */
+void
+RestClient::Connection::SetUserAgent(const std::string& userAgent) {
+ this->customUserAgent = userAgent;
+}
+
+/**
+ * @brief set custom Certificate Authority (CA) path
+ *
+ * @param caInfoFilePath - The path to a file holding the certificates used to
+ * verify the peer with. See CURLOPT_CAINFO
+ *
+ */
+void
+RestClient::Connection::SetCAInfoFilePath(const std::string& caInfoFilePath) {
+ this->caInfoFilePath = caInfoFilePath;
+}
+
+/**
+ * @brief get the user agent to add to the request
+ *
+ * @return user agent as std::string
+ */
+std::string
+RestClient::Connection::GetUserAgent() {
+ std::string prefix;
+ if (this->customUserAgent.length() > 0) {
+ prefix = this->customUserAgent + " ";
+ }
+ return std::string(prefix + "restclient-cpp/" + RESTCLIENT_VERSION);
+}
+
+/**
+ * @brief set timeout for connection
+ *
+ * @param seconds - timeout in seconds
+ *
+ */
+void
+RestClient::Connection::SetTimeout(int seconds) {
+ this->timeout = seconds;
+}
+
+/**
+ * @brief set username and password for basic auth
+ *
+ * @param username
+ * @param password
+ *
+ */
+void
+RestClient::Connection::SetBasicAuth(const std::string& username,
+ const std::string& password) {
+ this->basicAuth.username = username;
+ this->basicAuth.password = password;
+}
+
+/**
+ * @brief helper function to get called from the actual request methods to
+ * prepare the curlHandle for transfer with generic options, perform the
+ * request and record some stats from the last request and then reset the
+ * handle with curl_easy_reset to its default state. This will keep things
+ * like connections and session ID intact but makes sure you can change
+ * parameters on the object for another request.
+ *
+ * @param uri URI to query
+ * @param ret Reference to the Response struct that should be filled
+ *
+ * @return 0 on success and 1 on error
+ */
+RestClient::Response
+RestClient::Connection::performCurlRequest(const std::string& uri) {
+ // init return type
+ RestClient::Response ret = {};
+
+ std::string url = std::string(this->baseUrl + uri);
+ std::string headerString;
+ CURLcode res = CURLE_OK;
+ curl_slist* headerList = NULL;
+
+ // FIXME:
+ // CURLOPT_FOLLOWLOCATION
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_FOLLOWLOCATION, url.c_str());
+
+ /** set query URL */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_URL, url.c_str());
+ /** set callback function */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_WRITEFUNCTION,
+ Helpers::write_callback);
+ /** set data object to pass to callback function */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_WRITEDATA, &ret);
+ /** set the header callback function */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_HEADERFUNCTION,
+ Helpers::header_callback);
+ /** callback object for headers */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_HEADERDATA, &ret);
+ /** set http headers */
+ for (HeaderFields::const_iterator it = this->headerFields.begin();
+ it != this->headerFields.end(); ++it) {
+ headerString = it->first;
+ headerString += ": ";
+ headerString += it->second;
+ headerList = qcurl_slist_append(headerList, headerString.c_str());
+ }
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_HTTPHEADER,
+ headerList);
+
+ // set basic auth if configured
+ if (this->basicAuth.username.length() > 0) {
+ std::string authString = std::string(this->basicAuth.username + ":" +
+ this->basicAuth.password);
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_USERPWD, authString.c_str());
+ }
+ /** set user agent */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_USERAGENT,
+ this->GetUserAgent().c_str());
+
+ // set timeout
+ if (this->timeout) {
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_TIMEOUT, this->timeout);
+ // dont want to get a sig alarm on timeout
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_NOSIGNAL, 1);
+ }
+ // set follow redirect
+ if (this->followRedirects == true) {
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_FOLLOWLOCATION, 1L);
+ }
+ // if provided, supply CA path
+ if (!this->caInfoFilePath.empty()) {
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_CAINFO,
+ this->caInfoFilePath.c_str());
+ }
+ res = qcurl_easy_perform(this->curlHandle);
+ if (res != CURLE_OK) {
+ if (res == CURLE_OPERATION_TIMEDOUT) {
+ ret.code = res;
+ ret.body = "Operation Timeout.";
+ } else {
+ ret.body = "Failed to query.";
+ ret.code = -1;
+ }
+ } else {
+ int64_t http_code = 0;
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_RESPONSE_CODE, &http_code);
+ ret.code = static_cast<int>(http_code);
+ }
+
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_TOTAL_TIME,
+ &this->lastRequest.totalTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_NAMELOOKUP_TIME,
+ &this->lastRequest.nameLookupTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_CONNECT_TIME,
+ &this->lastRequest.connectTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_APPCONNECT_TIME,
+ &this->lastRequest.appConnectTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_PRETRANSFER_TIME,
+ &this->lastRequest.preTransferTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_STARTTRANSFER_TIME,
+ &this->lastRequest.startTransferTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_REDIRECT_TIME,
+ &this->lastRequest.redirectTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_REDIRECT_COUNT,
+ &this->lastRequest.redirectCount);
+ // free header list
+ qcurl_slist_free_all(headerList);
+ // reset curl handle
+ qcurl_easy_reset(this->curlHandle);
+ return ret;
+}
+
+/**
+ * @brief HTTP GET method
+ *
+ * @param url to query
+ *
+ * @return response struct
+ */
+RestClient::Response
+RestClient::Connection::get(const std::string& url) {
+ return this->performCurlRequest(url);
+}
+/**
+ * @brief HTTP POST method
+ *
+ * @param url to query
+ * @param data HTTP POST body
+ *
+ * @return response struct
+ */
+RestClient::Response
+RestClient::Connection::post(const std::string& url,
+ const std::string& data) {
+ /** Now specify we want to POST data */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_POST, 1L);
+ /** set post fields */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_POSTFIELDS, data.c_str());
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_POSTFIELDSIZE, data.size());
+
+ return this->performCurlRequest(url);
+}
+/**
+ * @brief HTTP PUT method
+ *
+ * @param url to query
+ * @param data HTTP PUT body
+ *
+ * @return response struct
+ */
+RestClient::Response
+RestClient::Connection::put(const std::string& url,
+ const std::string& data) {
+ /** initialize upload object */
+ RestClient::Helpers::UploadObject up_obj;
+ up_obj.data = data.c_str();
+ up_obj.length = data.size();
+
+ /** Now specify we want to PUT data */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_PUT, 1L);
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_UPLOAD, 1L);
+ /** set read callback function */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_READFUNCTION,
+ RestClient::Helpers::read_callback);
+ /** set data object to pass to callback function */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_READDATA, &up_obj);
+ /** set data size */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_INFILESIZE,
+ static_cast<int64_t>(up_obj.length));
+
+ return this->performCurlRequest(url);
+}
+/**
+ * @brief HTTP DELETE method
+ *
+ * @param url to query
+ *
+ * @return response struct
+ */
+RestClient::Response
+RestClient::Connection::del(const std::string& url) {
+ /** we want HTTP DELETE */
+ const char* http_delete = "DELETE";
+
+ /** set HTTP DELETE METHOD */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_CUSTOMREQUEST, http_delete);
+
+ return this->performCurlRequest(url);
+}
+
diff --git a/external/restclient/helpers.cpp b/external/restclient/helpers.cpp
new file mode 100644
index 0000000..7a99edc
--- /dev/null
+++ b/external/restclient/helpers.cpp
@@ -0,0 +1,96 @@
+/**
+ * @file helpers.cpp
+ * @brief implementation of the restclient helpers
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ */
+
+#include "restclient/helpers.h"
+
+#ifdef USE_LOCAL_HEADERS
+ #include "../libcurl-7.35.0/curl/curl.h"
+#else
+ #include <curl/curl.h>
+#endif
+
+#include <cstring>
+
+#include "restclient/restclient.h"
+
+/**
+ * @brief write callback function for libcurl
+ *
+ * @param data returned data of size (size*nmemb)
+ * @param size size parameter
+ * @param nmemb memblock parameter
+ * @param userdata pointer to user data to save/work with return data
+ *
+ * @return (size * nmemb)
+ */
+size_t RestClient::Helpers::write_callback(void *data, size_t size,
+ size_t nmemb, void *userdata) {
+ RestClient::Response* r;
+ r = reinterpret_cast<RestClient::Response*>(userdata);
+ r->body.append(reinterpret_cast<char*>(data), size*nmemb);
+
+ return (size * nmemb);
+}
+
+/**
+ * @brief header callback for libcurl
+ *
+ * @param data returned (header line)
+ * @param size of data
+ * @param nmemb memblock
+ * @param userdata pointer to user data object to save headr data
+ * @return size * nmemb;
+ */
+size_t RestClient::Helpers::header_callback(void *data, size_t size,
+ size_t nmemb, void *userdata) {
+ RestClient::Response* r;
+ r = reinterpret_cast<RestClient::Response*>(userdata);
+ std::string header(reinterpret_cast<char*>(data), size*nmemb);
+ size_t seperator = header.find_first_of(":");
+ if ( std::string::npos == seperator ) {
+ // roll with non seperated headers...
+ trim(header);
+ if (0 == header.length()) {
+ return (size * nmemb); // blank line;
+ }
+ r->headers[header] = "present";
+ } else {
+ std::string key = header.substr(0, seperator);
+ trim(key);
+ std::string value = header.substr(seperator + 1);
+ trim(value);
+ r->headers[key] = value;
+ }
+
+ return (size * nmemb);
+}
+
+/**
+ * @brief read callback function for libcurl
+ *
+ * @param data pointer of max size (size*nmemb) to write data to
+ * @param size size parameter
+ * @param nmemb memblock parameter
+ * @param userdata pointer to user data to read data from
+ *
+ * @return (size * nmemb)
+ */
+size_t RestClient::Helpers::read_callback(void *data, size_t size,
+ size_t nmemb, void *userdata) {
+ /** get upload struct */
+ RestClient::Helpers::UploadObject* u;
+ u = reinterpret_cast<RestClient::Helpers::UploadObject*>(userdata);
+ /** set correct sizes */
+ size_t curl_size = size * nmemb;
+ size_t copy_size = (u->length < curl_size) ? u->length : curl_size;
+ /** copy data to buffer */
+ std::memcpy(data, u->data, copy_size);
+ /** decrement length and increment data pointer */
+ u->length -= copy_size;
+ u->data += copy_size;
+ /** return copied size */
+ return copy_size;
+}
diff --git a/external/restclient/restclient.cpp b/external/restclient/restclient.cpp
new file mode 100644
index 0000000..0138c79
--- /dev/null
+++ b/external/restclient/restclient.cpp
@@ -0,0 +1,118 @@
+/**
+ * @file restclient.cpp
+ * @brief implementation of the restclient class
+ *
+ * This just provides static wrappers around the Connection class REST
+ * methods. However since I didn't want to have to pull in a whole URI parsing
+ * library just now, the Connection constructor is passed an empty string and
+ * the full URL is passed to the REST methods. All those methods to is
+ * concatenate them anyways. So this should do for now.
+ *
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ */
+
+#include "restclient/restclient.h"
+
+#include "../../src/client/cl_curl.h"
+#ifdef USE_LOCAL_HEADERS
+ #include "../libcurl-7.35.0/curl/curl.h"
+#else
+ #include <curl/curl.h>
+#endif
+
+#include "restclient/version.h"
+#include "restclient/connection.h"
+
+/**
+ * @brief global init function. Call this before you start any threads.
+ */
+int RestClient::init() {
+#ifdef USE_CURL_DLOPEN
+ CL_cURL_Init();
+#endif
+ CURLcode res = qcurl_global_init(CURL_GLOBAL_ALL);
+ if (res == CURLE_OK) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+/**
+ * @brief global disable function. Call this before you terminate your
+ * program.
+ */
+void RestClient::disable() {
+ qcurl_global_cleanup();
+}
+
+/**
+ * @brief HTTP GET method
+ *
+ * @param url to query
+ *
+ * @return response struct
+ */
+RestClient::Response RestClient::get(const std::string& url) {
+ RestClient::Response ret;
+ RestClient::Connection *conn = new RestClient::Connection("");
+ ret = conn->get(url);
+ delete conn;
+ return ret;
+}
+
+/**
+ * @brief HTTP POST method
+ *
+ * @param url to query
+ * @param ctype content type as string
+ * @param data HTTP POST body
+ *
+ * @return response struct
+ */
+RestClient::Response RestClient::post(const std::string& url,
+ const std::string& ctype,
+ const std::string& data) {
+ RestClient::Response ret;
+ RestClient::Connection *conn = new RestClient::Connection("");
+ conn->AppendHeader("Content-Type", ctype);
+ ret = conn->post(url, data);
+ delete conn;
+ return ret;
+}
+
+/**
+ * @brief HTTP PUT method
+ *
+ * @param url to query
+ * @param ctype content type as string
+ * @param data HTTP PUT body
+ *
+ * @return response struct
+ */
+RestClient::Response RestClient::put(const std::string& url,
+ const std::string& ctype,
+ const std::string& data) {
+ RestClient::Response ret;
+ RestClient::Connection *conn = new RestClient::Connection("");
+ conn->AppendHeader("Content-Type", ctype);
+ ret = conn->put(url, data);
+ delete conn;
+ return ret;
+}
+
+/**
+ * @brief HTTP DELETE method
+ *
+ * @param url to query
+ *
+ * @return response struct
+ */
+RestClient::Response RestClient::del(const std::string& url) {
+ RestClient::Response ret;
+ RestClient::Connection *conn = new RestClient::Connection("");
+ ret = conn->del(url);
+ delete conn;
+ return ret;
+}
+
diff --git a/external/restclient/restclient/connection.h b/external/restclient/restclient/connection.h
new file mode 100644
index 0000000..475b190
--- /dev/null
+++ b/external/restclient/restclient/connection.h
@@ -0,0 +1,169 @@
+/**
+ * @file connection.h
+ * @brief header definitions for restclient-cpp connection class
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ * @version
+ * @date 2010-10-11
+ */
+
+#ifndef INCLUDE_RESTCLIENT_CPP_CONNECTION_H_
+#define INCLUDE_RESTCLIENT_CPP_CONNECTION_H_
+
+#include <string>
+#include <map>
+#include <cstdlib>
+
+#include "restclient.h"
+#include "version.h"
+
+typedef void CURL;
+/**
+ * @brief namespace for all RestClient definitions
+ */
+namespace RestClient {
+
+/**
+ * @brief Connection object for advanced usage
+ */
+class Connection {
+ public:
+ /**
+ * @struct RequestInfo
+ * @brief holds some diagnostics information
+ * about a request
+ * @var RequestInfo::totalTime
+ * Member 'totalTime' contains the total time of the last request in
+ * seconds Total time of previous transfer. See CURLINFO_TOTAL_TIME
+ * @var RequestInfo::nameLookupTime
+ * Member 'nameLookupTime' contains the time spent in DNS lookup in
+ * seconds Time from start until name resolving completed. See
+ * CURLINFO_NAMELOOKUP_TIME
+ * @var RequestInfo::connectTime
+ * Member 'connectTime' contains the time it took until Time from start
+ * until remote host or proxy completed. See CURLINFO_CONNECT_TIME
+ * @var RequestInfo::appConnectTime
+ * Member 'appConnectTime' contains the time from start until SSL/SSH
+ * handshake completed. See CURLINFO_APPCONNECT_TIME
+ * @var RequestInfo::preTransferTime
+ * Member 'preTransferTime' contains the total time from start until
+ * just before the transfer begins. See CURLINFO_PRETRANSFER_TIME
+ * @var RequestInfo::startTransferTime
+ * Member 'startTransferTime' contains the total time from start until
+ * just when the first byte is received. See CURLINFO_STARTTRANSFER_TIME
+ * @var RequestInfo::redirectTime
+ * Member 'redirectTime' contains the total time taken for all redirect
+ * steps before the final transfer. See CURLINFO_REDIRECT_TIME
+ * @var RequestInfo::redirectCount
+ * Member 'redirectCount' contains the number of redirects followed. See
+ * CURLINFO_REDIRECT_COUNT
+ */
+ typedef struct {
+ double totalTime;
+ double nameLookupTime;
+ double connectTime;
+ double appConnectTime;
+ double preTransferTime;
+ double startTransferTime;
+ double redirectTime;
+ int redirectCount;
+ } RequestInfo;
+ /**
+ * @struct Info
+ * @brief holds some diagnostics information
+ * about the connection object it came from
+ * @var Info::baseUrl
+ * Member 'baseUrl' contains the base URL for the connection object
+ * @var Info::headers
+ * Member 'headers' contains the HeaderFields map
+ * @var Info::timeout
+ * Member 'timeout' contains the configured timeout
+ * @var Info::followRedirects
+ * Member 'followRedirects' contains whether or not to follow redirects
+ * @var Info::basicAuth
+ * Member 'basicAuth' contains information about basic auth
+ * @var basicAuth::username
+ * Member 'username' contains the basic auth username
+ * @var basicAuth::password
+ * Member 'password' contains the basic auth password
+ * @var Info::customUserAgent
+ * Member 'customUserAgent' contains the custom user agent
+ * @var Info::lastRequest
+ * Member 'lastRequest' contains metrics about the last request
+ */
+ typedef struct {
+ std::string baseUrl;
+ RestClient::HeaderFields headers;
+ int timeout;
+ bool followRedirects;
+ struct {
+ std::string username;
+ std::string password;
+ } basicAuth;
+ std::string customUserAgent;
+ RequestInfo lastRequest;
+ } Info;
+
+
+ explicit Connection(const std::string baseUrl);
+ ~Connection();
+
+ // Instance configuration methods
+ // configure basic auth
+ void SetBasicAuth(const std::string& username,
+ const std::string& password);
+
+ // set connection timeout to seconds
+ void SetTimeout(int seconds);
+
+ // set whether to follow redirects
+ void FollowRedirects(bool follow);
+
+ // set custom user agent
+ // (this will result in the UA "foo/cool restclient-cpp/VERSION")
+ void SetUserAgent(const std::string& userAgent);
+
+ // set the Certificate Authority (CA) Info which is the path to file holding
+ // certificates to be used to verify peers. See CURLOPT_CAINFO
+ void SetCAInfoFilePath(const std::string& caInfoFilePath);
+
+ std::string GetUserAgent();
+
+ RestClient::Connection::Info GetInfo();
+
+ // set headers
+ void SetHeaders(RestClient::HeaderFields headers);
+
+ // get headers
+ RestClient::HeaderFields GetHeaders();
+
+ // append additional headers
+ void AppendHeader(const std::string& key,
+ const std::string& value);
+
+
+ // Basic HTTP verb methods
+ RestClient::Response get(const std::string& uri);
+ RestClient::Response post(const std::string& uri,
+ const std::string& data);
+ RestClient::Response put(const std::string& uri,
+ const std::string& data);
+ RestClient::Response del(const std::string& uri);
+
+ private:
+ CURL* curlHandle;
+ std::string baseUrl;
+ RestClient::HeaderFields headerFields;
+ int timeout;
+ bool followRedirects;
+ struct {
+ std::string username;
+ std::string password;
+ } basicAuth;
+ std::string customUserAgent;
+ std::string caInfoFilePath;
+ RequestInfo lastRequest;
+ RestClient::Response performCurlRequest(const std::string& uri);
+};
+}; // namespace RestClient
+
+#endif // INCLUDE_RESTCLIENT_CPP_CONNECTION_H_
diff --git a/external/restclient/restclient/helpers.h b/external/restclient/restclient/helpers.h
new file mode 100644
index 0000000..8695a41
--- /dev/null
+++ b/external/restclient/restclient/helpers.h
@@ -0,0 +1,74 @@
+/**
+ * @file helpers.h
+ * @brief header file for restclient-cpp helpers
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ * @version
+ * @date 2010-10-11
+ */
+
+#ifndef INCLUDE_RESTCLIENT_CPP_HELPERS_H_
+#define INCLUDE_RESTCLIENT_CPP_HELPERS_H_
+
+#include <string>
+#include <algorithm>
+#include <functional>
+
+#include "version.h"
+
+/**
+ * @brief namespace for all RestClient definitions
+ */
+namespace RestClient {
+
+/**
+ * @brief: namespace for all helper functions
+ */
+namespace Helpers {
+
+ /** @struct UploadObject
+ * @brief This structure represents the payload to upload on POST
+ * requests
+ * @var UploadObject::data
+ * Member 'data' contains the data to upload
+ * @var UploadObject::length
+ * Member 'length' contains the length of the data to upload
+ */
+ typedef struct {
+ const char* data;
+ size_t length;
+ } UploadObject;
+
+ // writedata callback function
+ size_t write_callback(void *ptr, size_t size, size_t nmemb,
+ void *userdata);
+
+ // header callback function
+ size_t header_callback(void *ptr, size_t size, size_t nmemb,
+ void *userdata);
+ // read callback function
+ size_t read_callback(void *ptr, size_t size, size_t nmemb,
+ void *userdata);
+
+ // trim from start
+ static inline std::string &ltrim(std::string &s) { // NOLINT
+ s.erase(s.begin(), std::find_if(s.begin(), s.end(),
+ std::not1(std::ptr_fun<int, int>(std::isspace))));
+ return s;
+ }
+
+ // trim from end
+ static inline std::string &rtrim(std::string &s) { // NOLINT
+ s.erase(std::find_if(s.rbegin(), s.rend(),
+ std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
+ return s;
+ }
+
+ // trim from both ends
+ static inline std::string &trim(std::string &s) { // NOLINT
+ return ltrim(rtrim(s));
+ }
+}; // namespace Helpers
+
+}; // namespace RestClient
+
+#endif // INCLUDE_RESTCLIENT_CPP_HELPERS_H_
diff --git a/external/restclient/restclient/restclient.h b/external/restclient/restclient/restclient.h
new file mode 100644
index 0000000..d6fa77c
--- /dev/null
+++ b/external/restclient/restclient/restclient.h
@@ -0,0 +1,63 @@
+/**
+ * @file restclient.h
+ * @brief libcurl wrapper for REST calls
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ * @version
+ * @date 2010-10-11
+ */
+
+#ifndef INCLUDE_RESTCLIENT_CPP_RESTCLIENT_H_
+#define INCLUDE_RESTCLIENT_CPP_RESTCLIENT_H_
+
+#include <string>
+#include <map>
+#include <cstdlib>
+
+#include "version.h"
+
+/**
+ * @brief namespace for all RestClient definitions
+ */
+namespace RestClient {
+
+/**
+ * public data definitions
+ */
+typedef std::map<std::string, std::string> HeaderFields;
+
+/** @struct Response
+ * @brief This structure represents the HTTP response data
+ * @var Response::code
+ * Member 'code' contains the HTTP response code
+ * @var Response::body
+ * Member 'body' contains the HTTP response body
+ * @var Response::headers
+ * Member 'headers' contains the HTTP response headers
+ */
+typedef struct {
+ int code;
+ std::string body;
+ HeaderFields headers;
+} Response;
+
+// init and disable functions
+int init();
+void disable();
+
+/**
+ * public methods for the simple API. These don't allow a lot of
+ * configuration but are meant for simple HTTP calls.
+ *
+ */
+Response get(const std::string& url);
+Response post(const std::string& url,
+ const std::string& content_type,
+ const std::string& data);
+Response put(const std::string& url,
+ const std::string& content_type,
+ const std::string& data);
+Response del(const std::string& url);
+
+}; // namespace RestClient
+
+#endif // INCLUDE_RESTCLIENT_CPP_RESTCLIENT_H_
diff --git a/external/restclient/restclient/version.h b/external/restclient/restclient/version.h
new file mode 100644
index 0000000..a1c4bd6
--- /dev/null
+++ b/external/restclient/restclient/version.h
@@ -0,0 +1,4 @@
+#ifndef INCLUDE_RESTCLIENT_CPP_VERSION_H_
+#define INCLUDE_RESTCLIENT_CPP_VERSION_H_
+#define RESTCLIENT_VERSION "0.4.4-dirty"
+#endif // INCLUDE_RESTCLIENT_CPP_VERSION_H_
diff --git a/external/semver/.gitignore b/external/semver/.gitignore
new file mode 100644
index 0000000..d3b8be9
--- /dev/null
+++ b/external/semver/.gitignore
@@ -0,0 +1,2 @@
+build/
+TAGS
diff --git a/external/semver/.gitmodules b/external/semver/.gitmodules
new file mode 100644
index 0000000..4a99d01
--- /dev/null
+++ b/external/semver/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "contrib/testinator"]
+ path = contrib/testinator
+ url = https://github.com/elbeno/testinator.git
+[submodule "contrib/gsl"]
+ path = contrib/gsl
+ url = https://github.com/Microsoft/GSL.git
diff --git a/external/semver/.travis.yml b/external/semver/.travis.yml
new file mode 100644
index 0000000..e8a599a
--- /dev/null
+++ b/external/semver/.travis.yml
@@ -0,0 +1,93 @@
+# adapted from https://github.com/ericniebler/range-v3
+
+language: cpp
+script: cmake
+
+matrix:
+ include:
+ - env: CLANG_VERSION=3.4 BUILD_TYPE=Debug CPP=1y SAN=On LIBCXX=On
+ os: linux
+ addons: &clang34
+ apt:
+ packages:
+ - util-linux
+ - clang-3.4
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-precise-3.4
+
+ - env: CLANG_VERSION=3.4 BUILD_TYPE=Release CPP=1y SAN=On LIBCXX=On
+ os: linux
+ addons: *clang34
+
+ - env: CLANG_VERSION=3.7 BUILD_TYPE=Debug CPP=14 SAN=Off LIBCXX=On
+ os: linux
+ addons: &clang37
+ apt:
+ packages:
+ - util-linux
+ - clang-3.7
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-precise-3.7
+
+ - env: CLANG_VERSION=3.7 BUILD_TYPE=Release CPP=14 SAN=Off LIBCXX=On
+ os: linux
+ addons: *clang37
+
+ # - env: GCC_VERSION=4.9 BUILD_TYPE=Debug CPP=14 SAN=Off LIBCXX=Off
+ # os: linux
+ # addons: &gcc49
+ # apt:
+ # packages:
+ # - g++-4.9
+ # sources:
+ # - ubuntu-toolchain-r-test
+
+ # - env: GCC_VERSION=4.9 BUILD_TYPE=Release CPP=14 SAN=Off LIBCXX=Off
+ # os: linux
+ # addons: *gcc49
+
+ - env: GCC_VERSION=5 BUILD_TYPE=Debug CPP=14 SAN=Off LIBCXX=Off
+ os: linux
+ addons: &gcc5
+ apt:
+ packages:
+ - g++-5
+ sources:
+ - ubuntu-toolchain-r-test
+
+ - env: GCC_VERSION=5 BUILD_TYPE=Release CPP=14 SAN=Off LIBCXX=Off
+ os: linux
+ addons: *gcc5
+
+before_install:
+ - export CHECKOUT_PATH=`pwd`;
+ - if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi
+ - if [ -n "$CLANG_VERSION" ]; then export CXX="clang++-${CLANG_VERSION}" CC="clang-${CLANG_VERSION}"; fi
+ - if [ "$CLANG_VERSION" == "3.4" ]; then export CXX="/usr/local/clang-3.4/bin/clang++" CC="/usr/local/clang-3.4/bin/clang"; fi
+ - if [ "$LIBCXX" == "On" ]; then sudo CXX=$CXX CC=$CC ./install_libcxx.sh; fi
+
+install:
+ - cd $CHECKOUT_PATH
+
+ - if [ ! -d build ]; then mkdir build; fi
+ - cd build
+
+ - export CXX_FLAGS=""
+ - export CXX_LINKER_FLAGS=""
+
+ - if [ -z "$BUILD_TYPE" ]; then export BUILD_TYPE=Debug; fi
+
+ - if [ -n "$CLANG_VERSION" ]; then CXX_FLAGS="${CXX_FLAGS} -D__extern_always_inline=inline"; fi
+ - if [ "$LIBCXX" == "On" ]; then CXX_FLAGS="${CXX_FLAGS} -stdlib=libc++ -I/usr/include/c++/v1/"; fi
+ - if [ "$LIBCXX" == "On" ]; then CXX_LINKER_FLAGS="${CXX_FLAGS} -L/usr/lib/ -lc++"; fi
+
+ - cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS="${CXX_FLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${CXX_LINKER_FLAGS}" -DCXX_STD=$CPP -DCI_BUILD=1
+ - make VERBOSE=1
+
+script:
+ - if [ "$BUILD_TYPE" == "Debug" ]; then ctest -VV --schedule-random; fi
+
+notifications:
+ email: false
diff --git a/external/semver/CMakeLists.txt b/external/semver/CMakeLists.txt
new file mode 100644
index 0000000..2919ee3
--- /dev/null
+++ b/external/semver/CMakeLists.txt
@@ -0,0 +1,100 @@
+cmake_minimum_required (VERSION 2.8)
+project (semver)
+
+# Includes for this project
+include_directories ("${PROJECT_SOURCE_DIR}/src/include")
+
+# Include testinator and the GSL
+include_directories ("${PROJECT_SOURCE_DIR}/contrib/testinator/src/include")
+include_directories ("${PROJECT_SOURCE_DIR}/contrib/gsl/include")
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+# Default C++ standard: C++14
+if(CXX_STD)
+else()
+ set(CXX_STD 14)
+endif()
+
+# Set up tests
+enable_testing()
+include(CTest)
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+ set(MY_CXX_FLAGS_LIST
+ )
+ string(REPLACE ";" " " MY_CXX_FLAGS "${MY_CXX_FLAGS_LIST}")
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MY_CXX_FLAGS}")
+else()
+ set(MY_CXX_FLAGS_LIST
+ -ftemplate-backtrace-limit=0
+ -ffunction-sections
+ -Wall -Wextra -Werror -pedantic-errors
+ -Wcast-align
+ -Wcast-qual
+ -Wctor-dtor-privacy
+ -Wdisabled-optimization
+ -Wformat=2
+ -Winit-self
+ -Wmissing-include-dirs
+ # -Wold-style-cast
+ -Woverloaded-virtual
+ -Wredundant-decls
+ # -Wshadow
+ # -Wsign-conversion
+ -Wsign-promo
+ -Wstrict-overflow=2
+ -Wswitch-default
+ -Wundef
+ )
+ string(REPLACE ";" " " MY_CXX_FLAGS "${MY_CXX_FLAGS_LIST}")
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++${CXX_STD} ${MY_CXX_FLAGS}")
+
+ # Debug/Release
+ set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-inline -g3 -fstack-protector-all")
+ set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -g0 -march=native -mtune=native -DNDEBUG")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage")
+endif()
+
+# Clang/GCC specifics
+if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ if(SAN)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined,integer -fno-omit-frame-pointer -fno-sanitize=unsigned-integer-overflow")
+ endif()
+elseif(CMAKE_COMPILER_IS_GNUCXX)
+endif()
+
+# Pipe separate tests into ctest
+# Adapted from https://github.com/ChaiScript/ChaiScript/blob/develop/CMakeLists.txt
+macro(ADD_INDIVIDUAL_TESTS executable type suffix)
+ set(test_path $ENV{PATH})
+ get_target_property(target_files ${executable} SOURCES)
+ foreach(source ${target_files})
+ string(REGEX MATCH .*cpp source "${source}")
+ if(source)
+ file(READ "${source}" contents)
+ string(REGEX MATCHALL "DEF_${type}[ ]*[(][ ]*[^, ]+[ ]*,[ ]*[^,) ]+[ ]*[),]" found_tests ${contents})
+ foreach(hit ${found_tests})
+ string(REGEX REPLACE "DEF_${type}[ ]*[(][ ]*([^, ]+)[ ]*,[ ]*[^,) ]+[ ]*[),]" "\\1" tname ${hit})
+ string(REGEX REPLACE "DEF_${type}[ ]*[(][ ]*[^, ]+[ ]*,[ ]*([^,) ]+)[ ]*[),]" "\\1" sname ${hit})
+ set(test_name ${executable}.${sname}.${tname}${suffix})
+ add_test(NAME ${test_name}
+ COMMAND "${executable}" --testName=${tname}${suffix} --suiteName=${sname})
+ set_tests_properties(${test_name} PROPERTIES TIMEOUT 30 ENVIRONMENT "PATH=${test_path}")
+ endforeach()
+ endif()
+ endforeach()
+endmacro()
+
+macro(ADD_TESTINATOR_TESTS executable)
+ ADD_INDIVIDUAL_TESTS(${executable} "TEST" "")
+ ADD_INDIVIDUAL_TESTS(${executable} "TIMED_TEST" "")
+ ADD_INDIVIDUAL_TESTS(${executable} "PROPERTY" "Property")
+ ADD_INDIVIDUAL_TESTS(${executable} "COMPLEXITY_PROPERTY" "ComplexityProperty")
+endmacro()
+
+add_subdirectory (src/lib)
+add_subdirectory (src/test)
+add_subdirectory (src/quickcheck)
diff --git a/external/semver/LICENSE b/external/semver/LICENSE
new file mode 100644
index 0000000..58b7258
--- /dev/null
+++ b/external/semver/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014-2016 Ben Deane
+
+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
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/external/semver/README.md b/external/semver/README.md
new file mode 100644
index 0000000..c2e1cc7
--- /dev/null
+++ b/external/semver/README.md
@@ -0,0 +1,12 @@
+# Semver
+
+A C++ class for handling semantic versioning as detailed at http://semver.org/.
+
+Bonus: experimental testing with Haskell's QuickCheck.
+
+### Status
+[![Build Status](https://travis-ci.org/elbeno/semver.svg?branch=master)](https
+://travis-ci.org/elbeno/semver)
+[![Build status](https://ci.appveyor.com/api/projects/status/ve1bvyxharcq9gv3?svg=true)](https://ci.appveyor.com/project/elbeno/semver)
+
+This project is distributed under some license. See LICENSE for details.
diff --git a/external/semver/appveyor.yml b/external/semver/appveyor.yml
new file mode 100644
index 0000000..70afe93
--- /dev/null
+++ b/external/semver/appveyor.yml
@@ -0,0 +1,35 @@
+platform:
+ - x86
+ - x64
+
+configuration:
+ - Debug
+ - Release
+
+os: Visual Studio 2015
+
+clone_folder: c:\projects\semver
+
+install:
+ - git submodule update --init --recursive
+
+build_script:
+ # show settings
+ - cmake -version
+ - echo %platform%
+ - echo %configuration%
+
+ # generate a solution file
+ - cd c:\projects\semver
+ - mkdir build
+ - cd build
+ - if "%platform%" == "x64" set cmake_platform=%platform%
+ - cmake -g "Visual Studio 14 2015" .. -DCMAKE_GENERATOR_PLATFORM=%cmake_platform%
+
+ # build it
+ - if "%platform%" == "x86" set msbuild_platform=Win32
+ - if "%platform%" == "x64" set msbuild_platform=%platform%
+ - msbuild semver.sln /p:Configuration=%configuration% /toolsversion:14.0 /p:PlatformToolset=v140 /p:Platform=%msbuild_platform%
+
+test_script:
+ - if "%configuration%" == "Debug" ctest -VV --schedule-random -C Debug
diff --git a/external/semver/install_libcxx.sh b/external/semver/install_libcxx.sh
new file mode 100644
index 0000000..dbdb579
--- /dev/null
+++ b/external/semver/install_libcxx.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# Install libc++ under travis
+# Copied from https://github.com/ericniebler/range-v3
+
+svn --quiet co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx
+mkdir libcxx/build
+(cd libcxx/build && cmake .. -DLIBCXX_CXX_ABI=libstdc++ -DLIBCXX_CXX_ABI_INCLUDE_PATHS="/usr/include/c++/4.6;/usr/include/c++/4.6/x86_64-linux-gnu")
+make -C libcxx/build cxx -j2
+sudo cp libcxx/build/lib/libc++.so.1.0 /usr/lib/
+sudo cp -r libcxx/build/include/c++/v1 /usr/include/c++/v1/
+sudo ln -sf /usr/lib/libc++.so.1.0 /usr/lib/libc++.so
+sudo ln -sf /usr/lib/libc++.so.1.0 /usr/lib/libc++.so.1
diff --git a/external/semver/src/include/semantic_version.h b/external/semver/src/include/semantic_version.h
new file mode 100644
index 0000000..a6214f9
--- /dev/null
+++ b/external/semver/src/include/semantic_version.h
@@ -0,0 +1,189 @@
+#pragma once
+
+// Semantic version - see http://semver.org/
+
+// The major difference between v1::Version and v2::Version is that v1 includes
+// the build identifier when calculating precedence of versions (see
+// http://semver.org/spec/v2.0.0-rc.1.html points 10,11) while v2 omits the
+// build identifier when calculating precedence of versions (see
+// http://semver.org/spec/v2.0.0.html points 10,11).
+
+#include <string>
+#include <ostream>
+
+namespace semver
+{
+ namespace v1
+ {
+
+ class Version
+ {
+ public:
+ // By-parts (and default) version constructor: no validation.
+ Version(
+ unsigned int major = 0,
+ unsigned int minor = 0,
+ unsigned int patch = 1,
+ const std::string& prerelease = std::string{},
+ const std::string& build = std::string{});
+
+ // Parse from a version string: no validation.
+ explicit Version(const std::string& s);
+
+ // Is a version well-formed according to the spec?
+ // The semver spec stipulates a few properties of a well-formed version:
+ // that both the dot-separated prerelease version and the build version
+ // MUST comprise only [0-9A-Za-z-]; that numerical dot-separated
+ // identifiers MUST NOT include leading zeroes; and that such identifiers
+ // MUST NOT be empty.
+ bool IsWellFormed() const;
+
+ // Parse from a version string, with validation according to the spec.
+ static Version Parse(const std::string& s, bool& wellformed);
+
+ unsigned int GetMajorVersion() const { return m_majorVersion; }
+ unsigned int GetMinorVersion() const { return m_minorVersion; }
+ unsigned int GetPatchVersion() const { return m_patchVersion; }
+
+ // Create a new version by incrementing a part of a version. Other parts
+ // will be reset to 0, per the spec.
+ Version NextMajorVersion() const;
+ Version NextMinorVersion() const;
+ Version NextPatchVersion() const;
+
+ // A version satisfies another version if it is greater than or equal to
+ // it in precedence. Additionally, pre-release versions and build versions
+ // both satisfy their corresponding normal versions, and all pre-release
+ // or build versions thereof.
+ bool Satisfies(const Version& other) const;
+
+ // Precedence is calculated by comparing the major, minor, patch,
+ // pre-release and build parts in that order. Pre-release and build
+ // strings are considered as lists of dot-separated identifiers, whereby
+ // if an identifier is numeric, it is compared as such; otherwise
+ // comparison is based on ASCII sort order.
+ friend bool operator<(const Version& a, const Version& b);
+ friend bool operator==(const Version& a, const Version& b);
+
+ // A version is output as X.Y.Z (Major.Minor.Patch)
+ // A pre-release string (eg alpha.1) may follow immediately, joined by a -
+ // A build string may follow (eg 123.f83eaa931), joined by a +
+ friend std::ostream& operator<<(std::ostream& s, const Version& v);
+
+ private:
+ unsigned int m_majorVersion = 0;
+ unsigned int m_minorVersion = 0;
+ unsigned int m_patchVersion = 1;
+ std::string m_prereleaseVersion;
+ std::string m_buildVersion;
+ };
+
+ inline bool operator!=(const Version& a, const Version& b)
+ {
+ return !(a == b);
+ }
+
+ inline bool operator>=(const Version& a, const Version& b)
+ {
+ return !(a < b);
+ }
+
+ inline bool operator<=(const Version& a, const Version& b)
+ {
+ return (a == b) || (a < b);
+ }
+
+ inline bool operator>(const Version& a, const Version& b)
+ {
+ return (a != b) && (a >= b);
+ }
+ }
+
+ inline namespace v2
+ {
+
+ class Version
+ {
+ public:
+ // By-parts (and default) version constructor: no validation.
+ Version(
+ unsigned int major = 0,
+ unsigned int minor = 0,
+ unsigned int patch = 1,
+ const std::string& prerelease = std::string{},
+ const std::string& build = std::string{});
+
+ // Parse from a version string: no validation.
+ explicit Version(const std::string& s);
+
+ // Is a version well-formed according to the spec?
+ // The semver spec stipulates a few properties of a well-formed version:
+ // that both the dot-separated prerelease version and the build version
+ // MUST comprise only [0-9A-Za-z-]; that numerical dot-separated
+ // identifiers MUST NOT include leading zeroes; and that such identifiers
+ // MUST NOT be empty.
+ bool IsWellFormed() const;
+
+ unsigned int GetMajorVersion() const { return m_majorVersion; }
+ unsigned int GetMinorVersion() const { return m_minorVersion; }
+ unsigned int GetPatchVersion() const { return m_patchVersion; }
+
+ // Create a new version by incrementing a part of a version. Other parts
+ // will be reset to 0, per the spec.
+ Version NextMajorVersion() const;
+ Version NextMinorVersion() const;
+ Version NextPatchVersion() const;
+
+ // A version satisfies another version if it is greater than or equal to
+ // it in precedence. Additionally, pre-release versions and build versions
+ // both satisfy their corresponding normal versions, and all pre-release
+ // or build versions thereof.
+ bool Satisfies(const Version& other) const;
+
+ // Precedence is calculated by comparing the major, minor, patch, and
+ // pre-release parts in that order. Pre-release strings are considered as
+ // lists of dot-separated identifiers, whereby if an identifier is
+ // numeric, it is compared as such; otherwise comparison is based on ASCII
+ // sort order. Note: according to semver v2.0.0, build version is NOT
+ // considered when determining precedence.
+ friend bool operator<(const Version& a, const Version& b);
+ friend bool operator==(const Version& a, const Version& b);
+
+ // For exact equality (as opposed to precedence equality)
+ bool Equals(const Version& other) const;
+
+ // A version is output as X.Y.Z (Major.Minor.Patch)
+ // A pre-release string (eg alpha.1) may follow immediately, joined by a -
+ // A build string may follow (eg 123.f83eaa931), joined by a +
+ friend std::ostream& operator<<(std::ostream& s, const Version& v);
+
+ private:
+ unsigned int m_majorVersion = 0;
+ unsigned int m_minorVersion = 0;
+ unsigned int m_patchVersion = 1;
+ std::string m_prereleaseVersion;
+ std::string m_buildVersion;
+ };
+
+ inline bool operator!=(const Version& a, const Version& b)
+ {
+ return !(a == b);
+ }
+
+ inline bool operator>=(const Version& a, const Version& b)
+ {
+ return !(a < b);
+ }
+
+ inline bool operator<=(const Version& a, const Version& b)
+ {
+ return (a == b) || (a < b);
+ }
+
+ inline bool operator>(const Version& a, const Version& b)
+ {
+ return (a != b) && (a >= b);
+ }
+ }
+}
+
diff --git a/external/semver/src/lib/CMakeLists.txt b/external/semver/src/lib/CMakeLists.txt
new file mode 100644
index 0000000..ad43505
--- /dev/null
+++ b/external/semver/src/lib/CMakeLists.txt
@@ -0,0 +1 @@
+add_library (${PROJECT_NAME} semantic_version_v1.cpp semantic_version_v2.cpp)
diff --git a/external/semver/src/lib/semantic_version_v1.cpp b/external/semver/src/lib/semantic_version_v1.cpp
new file mode 100644
index 0000000..4df8bef
--- /dev/null
+++ b/external/semver/src/lib/semantic_version_v1.cpp
@@ -0,0 +1,286 @@
+#include "semantic_version.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cstdlib>
+#include <sstream>
+#include <tuple>
+#include <vector>
+
+using namespace std;
+
+//------------------------------------------------------------------------------
+// From http://semver.org/ - Version 2.0.0
+
+// Pre-release versions satisfy but have a lower precedence than the associated
+// normal version.
+
+// Build versions satisfy and have a higher precedence than the associated
+// normal version.
+
+// Precedence MUST be calculated by separating the version into major, minor,
+// patch, pre-release, and build identifiers in that order. Major, minor, and
+// patch versions are always compared numerically. Pre-release and build version
+// precedence MUST be determined by comparing each dot separated identifier as
+// follows: identifiers consisting of only digits are compared numerically and
+// identifiers with letters or dashes are compared lexically in ASCII sort
+// order. Numeric identifiers always have lower precedence than non-numeric
+// identifiers. Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 <
+// 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0-rc.1+build.1 < 1.0.0 < 1.0.0+0.3.7 <
+// 1.3.7+build < 1.3.7+build.2.b8f12d7 < 1.3.7+build.11.e0f985a.
+
+namespace
+{
+ void SplitDottedString(const string& s, vector<string>& v)
+ {
+ istringstream ss(s);
+ for (string part; getline(ss, part, '.'); v.push_back(part));
+ }
+
+ int CompareIdentifiers(const string& s1, const string& s2)
+ {
+ // We need to split the dotted identifier list into individual identifiers,
+ // and treat purely numeric identifiers as the numbers they represent.
+
+ vector<string> v1;
+ SplitDottedString(s1, v1);
+
+ vector<string> v2;
+ SplitDottedString(s2, v2);
+
+ for (size_t i = 0; ; ++i)
+ {
+ // exhausted both vectors: they must be equal
+ if (i >= v1.size() && i >= v2.size())
+ {
+ return 0;
+ }
+
+ // exhausted one vector: it's the smaller one
+ if (i >= v1.size())
+ {
+ return -1;
+ }
+ if (i >= v2.size())
+ {
+ return 1;
+ }
+
+ // is either of v1[i] or v2[i] a number?
+ const string& id1 = v1[i];
+ bool id1IsNumber = all_of(id1.cbegin(), id1.cend(),
+ [] (char c) { return isdigit(c); });
+ const string& id2 = v2[i];
+ bool id2IsNumber = all_of(id2.cbegin(), id2.cend(),
+ [] (char c) { return isdigit(c); });
+
+ // if both numbers - compare them as such
+ if (id1IsNumber && id2IsNumber)
+ {
+ long num1 = atol(id1.c_str());
+ long num2 = atol(id2.c_str());
+ if (num1 - num2 != 0)
+ {
+ return num1 - num2;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ // if one is a number - that one is lesser
+ if (id1IsNumber)
+ {
+ return -1;
+ }
+ if (id2IsNumber)
+ {
+ return 1;
+ }
+ // neither are numbers: compare them
+ int c = id1.compare(id2);
+ if (c != 0)
+ {
+ return c;
+ }
+ }
+ }
+
+ bool IdentifierIsValid(const string& i)
+ {
+ vector<string> v;
+ SplitDottedString(i, v);
+
+ for (const auto& s : v)
+ {
+ // Identifiers must not be empty.
+ if (s.empty())
+ {
+ return false;
+ }
+
+ // Identifiers must contain only alphanumerics and '-'.
+ if (any_of(s.cbegin(), s.cend(),
+ [] (char c) { return !isalnum(c) && c != '-'; }))
+ {
+ return false;
+ }
+
+ // Numeric identifiers must not contain leading zeroes.
+ bool numeric = all_of(s.cbegin(), s.cend(),
+ [] (char c) { return isdigit(c); });
+ if (numeric && s[0] == '0')
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+
+namespace semver {
+ namespace v1 {
+
+//------------------------------------------------------------------------------
+Version::Version(
+ unsigned int major,
+ unsigned int minor,
+ unsigned int patch,
+ const std::string& prerelease,
+ const std::string& build)
+ : m_majorVersion(major)
+ , m_minorVersion(minor)
+ , m_patchVersion(patch)
+ , m_prereleaseVersion(prerelease)
+ , m_buildVersion(build)
+{
+}
+
+Version::Version(const string& s)
+{
+ // major.minor.patch-release+build
+
+ istringstream ss(s);
+ string part;
+
+ if (!getline(ss, part, '.')) return;
+ m_majorVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+ if (!getline(ss, part, '.')) return;
+ m_minorVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+ if (!getline(ss, part, '-')) return;
+ m_patchVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+
+ if (!getline(ss, m_prereleaseVersion, '+')) return;
+ getline(ss, m_buildVersion, '\0');
+}
+
+//------------------------------------------------------------------------------
+bool Version::IsWellFormed() const
+{
+ return IdentifierIsValid(m_prereleaseVersion)
+ && IdentifierIsValid(m_buildVersion);
+}
+
+//------------------------------------------------------------------------------
+// When incrementing versions, all lower version parts are reset.
+
+Version Version::NextMajorVersion() const
+{
+ return Version(m_majorVersion + 1, 0, 0);
+}
+
+Version Version::NextMinorVersion() const
+{
+ return Version(m_majorVersion, m_minorVersion + 1, 0);
+}
+
+Version Version::NextPatchVersion() const
+{
+ return Version(m_majorVersion, m_minorVersion, m_patchVersion + 1);
+}
+
+
+//------------------------------------------------------------------------------
+bool Version::Satisfies(const Version& other) const
+{
+ return tie(m_majorVersion, m_minorVersion, m_patchVersion) >=
+ tie(other.m_majorVersion, other.m_minorVersion, other.m_patchVersion);
+}
+
+//------------------------------------------------------------------------------
+bool operator==(const Version& a, const Version& b)
+{
+ return
+ tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion,
+ a.m_prereleaseVersion, a.m_buildVersion) ==
+ tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion,
+ b.m_prereleaseVersion, b.m_buildVersion);
+}
+
+//------------------------------------------------------------------------------
+bool operator<(const Version& a, const Version& b)
+{
+ if (tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion) <
+ tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion))
+ {
+ return true;
+ }
+
+ // pre-release version < normal version
+ if (!a.m_prereleaseVersion.empty() && b.m_prereleaseVersion.empty())
+ {
+ return true;
+ }
+ if (a.m_prereleaseVersion.empty() && !b.m_prereleaseVersion.empty())
+ {
+ return false;
+ }
+
+ int prComp = CompareIdentifiers(a.m_prereleaseVersion, b.m_prereleaseVersion);
+ if (prComp < 0)
+ {
+ return true;
+ }
+ else if (prComp == 0)
+ {
+ // build version > normal version
+ if (a.m_buildVersion.empty() && !b.m_buildVersion.empty())
+ {
+ return true;
+ }
+ if (!a.m_buildVersion.empty() && b.m_buildVersion.empty())
+ {
+ return false;
+ }
+
+ int bComp = CompareIdentifiers(a.m_buildVersion, b.m_buildVersion);
+ if (bComp < 0)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+//------------------------------------------------------------------------------
+ostream& operator<<(ostream& s, const Version& v)
+{
+ s << v.m_majorVersion
+ << '.' << v.m_minorVersion
+ << '.' << v.m_patchVersion;
+
+ if (!v.m_prereleaseVersion.empty())
+ {
+ s << '-' << v.m_prereleaseVersion;
+ }
+ if (!v.m_buildVersion.empty())
+ {
+ s << '+' << v.m_buildVersion;
+ }
+
+ return s;
+}
+
+ }
+}
diff --git a/external/semver/src/lib/semantic_version_v2.cpp b/external/semver/src/lib/semantic_version_v2.cpp
new file mode 100644
index 0000000..7bada17
--- /dev/null
+++ b/external/semver/src/lib/semantic_version_v2.cpp
@@ -0,0 +1,272 @@
+#include "semantic_version.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cstdlib>
+#include <sstream>
+#include <tuple>
+#include <vector>
+
+using namespace std;
+
+//------------------------------------------------------------------------------
+// From http://semver.org/ - Version 2.0.0
+
+// Pre-release versions satisfy but have a lower precedence than the associated
+// normal version.
+
+// Build versions satisfy and have a higher precedence than the associated
+// normal version.
+
+// Precedence MUST be calculated by separating the version into major, minor,
+// patch, pre-release, and build identifiers in that order. Major, minor, and
+// patch versions are always compared numerically. Pre-release and build version
+// precedence MUST be determined by comparing each dot separated identifier as
+// follows: identifiers consisting of only digits are compared numerically and
+// identifiers with letters or dashes are compared lexically in ASCII sort
+// order. Numeric identifiers always have lower precedence than non-numeric
+// identifiers. Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 <
+// 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0-rc.1+build.1 < 1.0.0 < 1.0.0+0.3.7 <
+// 1.3.7+build < 1.3.7+build.2.b8f12d7 < 1.3.7+build.11.e0f985a.
+
+namespace
+{
+ void SplitDottedString(const string& s, vector<string>& v)
+ {
+ istringstream ss(s);
+ for (string part; getline(ss, part, '.'); v.push_back(part));
+ }
+
+ int CompareIdentifiers(const string& s1, const string& s2)
+ {
+ // We need to split the dotted identifier list into individual identifiers,
+ // and treat purely numeric identifiers as the numbers they represent.
+
+ vector<string> v1;
+ SplitDottedString(s1, v1);
+
+ vector<string> v2;
+ SplitDottedString(s2, v2);
+
+ for (size_t i = 0; ; ++i)
+ {
+ // exhausted both vectors: they must be equal
+ if (i >= v1.size() && i >= v2.size())
+ {
+ return 0;
+ }
+
+ // exhausted one vector: it's the smaller one
+ if (i >= v1.size())
+ {
+ return -1;
+ }
+ if (i >= v2.size())
+ {
+ return 1;
+ }
+
+ // is either of v1[i] or v2[i] a number?
+ const string& id1 = v1[i];
+ bool id1IsNumber = all_of(id1.cbegin(), id1.cend(),
+ [] (char c) { return isdigit(c); });
+ const string& id2 = v2[i];
+ bool id2IsNumber = all_of(id2.cbegin(), id2.cend(),
+ [] (char c) { return isdigit(c); });
+
+ // if both numbers - compare them as such
+ if (id1IsNumber && id2IsNumber)
+ {
+ long num1 = atol(id1.c_str());
+ long num2 = atol(id2.c_str());
+ if (num1 - num2 != 0)
+ {
+ return num1 - num2;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ // if one is a number - that one is lesser
+ if (id1IsNumber)
+ {
+ return -1;
+ }
+ if (id2IsNumber)
+ {
+ return 1;
+ }
+ // neither are numbers: compare them
+ int c = id1.compare(id2);
+ if (c != 0)
+ {
+ return c;
+ }
+ }
+ }
+
+ bool IdentifierIsValid(const string& i)
+ {
+ vector<string> v;
+ SplitDottedString(i, v);
+
+ for (const auto& s : v)
+ {
+ // Identifiers must not be empty.
+ if (s.empty())
+ {
+ return false;
+ }
+
+ // Identifiers must contain only alphanumerics and '-'.
+ if (any_of(s.cbegin(), s.cend(),
+ [] (char c) { return !isalnum(c) && c != '-' && c != '.'; }))
+ {
+ return false;
+ }
+
+ // Numeric identifiers must not contain leading zeroes.
+ bool numeric = all_of(s.cbegin(), s.cend(),
+ [] (char c) { return isdigit(c); });
+ if (numeric && s[0] == '0')
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+
+namespace semver {
+ inline namespace v2 {
+
+//------------------------------------------------------------------------------
+Version::Version(
+ unsigned int major,
+ unsigned int minor,
+ unsigned int patch,
+ const std::string& prerelease,
+ const std::string& build)
+ : m_majorVersion(major)
+ , m_minorVersion(minor)
+ , m_patchVersion(patch)
+ , m_prereleaseVersion(prerelease)
+ , m_buildVersion(build)
+{
+}
+
+Version::Version(const string& s)
+{
+ // major.minor.patch-release+build
+
+ istringstream ss(s);
+ string part;
+
+ if (!getline(ss, part, '.')) return;
+ m_majorVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+ if (!getline(ss, part, '.')) return;
+ m_minorVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+ if (!getline(ss, part, '-')) return;
+ m_patchVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+
+ if (!getline(ss, m_prereleaseVersion, '+')) return;
+ getline(ss, m_buildVersion, '\0');
+}
+
+//------------------------------------------------------------------------------
+bool Version::IsWellFormed() const
+{
+ return IdentifierIsValid(m_prereleaseVersion)
+ && IdentifierIsValid(m_buildVersion);
+}
+
+//------------------------------------------------------------------------------
+// When incrementing versions, all lower version parts are reset.
+
+Version Version::NextMajorVersion() const
+{
+ return Version(m_majorVersion + 1, 0, 0);
+}
+
+Version Version::NextMinorVersion() const
+{
+ return Version(m_majorVersion, m_minorVersion + 1, 0);
+}
+
+Version Version::NextPatchVersion() const
+{
+ return Version(m_majorVersion, m_minorVersion, m_patchVersion + 1);
+}
+
+//------------------------------------------------------------------------------
+bool Version::Satisfies(const Version& other) const
+{
+ return tie(m_majorVersion, m_minorVersion, m_patchVersion) >=
+ tie(other.m_majorVersion, other.m_minorVersion, other.m_patchVersion);
+}
+
+//------------------------------------------------------------------------------
+bool operator==(const Version& a, const Version& b)
+{
+ return
+ tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion,
+ a.m_prereleaseVersion) ==
+ tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion,
+ b.m_prereleaseVersion);
+}
+
+//------------------------------------------------------------------------------
+bool operator<(const Version& a, const Version& b)
+{
+ const auto ta = tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion);
+ const auto tb = tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion);
+
+ if (ta < tb) return true;
+ if (ta > tb) return false;
+
+ // pre-release version < normal version
+ if (!a.m_prereleaseVersion.empty() && b.m_prereleaseVersion.empty())
+ {
+ return true;
+ }
+ if (a.m_prereleaseVersion.empty() && !b.m_prereleaseVersion.empty())
+ {
+ return false;
+ }
+
+ return CompareIdentifiers(a.m_prereleaseVersion, b.m_prereleaseVersion) <= 0;
+}
+
+//------------------------------------------------------------------------------
+bool Version::Equals(const Version& other) const
+{
+ return
+ tie(m_majorVersion, m_minorVersion, m_patchVersion,
+ m_prereleaseVersion, m_buildVersion) ==
+ tie(other.m_majorVersion, other.m_minorVersion, other.m_patchVersion,
+ other.m_prereleaseVersion, other.m_buildVersion);
+}
+
+//------------------------------------------------------------------------------
+ostream& operator<<(ostream& s, const Version& v)
+{
+ s << v.m_majorVersion
+ << '.' << v.m_minorVersion
+ << '.' << v.m_patchVersion;
+
+ if (!v.m_prereleaseVersion.empty())
+ {
+ s << '-' << v.m_prereleaseVersion;
+ }
+ if (!v.m_buildVersion.empty())
+ {
+ s << '+' << v.m_buildVersion;
+ }
+
+ return s;
+}
+
+ }
+}
diff --git a/external/semver/src/quickcheck/CMakeLists.txt b/external/semver/src/quickcheck/CMakeLists.txt
new file mode 100644
index 0000000..b8bb9b9
--- /dev/null
+++ b/external/semver/src/quickcheck/CMakeLists.txt
@@ -0,0 +1,29 @@
+find_program(HSC2HS hsc2hs)
+find_program(GHC ghc)
+
+if (HSC2HS AND GHC)
+
+ # the shared lib
+ add_library(${PROJECT_NAME}_ffi SHARED
+ ../lib/semantic_version_v1.cpp ../lib/semantic_version_v2.cpp semantic_version_ffi.cpp)
+ # the ffi bindings
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Semver.hs
+ MAIN_DEPENDENCY Semver.hsc
+ DEPENDS semantic_version_ffi.h
+ COMMAND ${HSC2HS} ${CMAKE_CURRENT_SOURCE_DIR}/Semver.hsc -I ${CMAKE_CURRENT_SOURCE_DIR} -o ${CMAKE_CURRENT_BINARY_DIR}/Semver.hs)
+ # the quickcheck executable
+ add_custom_command(
+ OUTPUT quickcheck_${PROJECT_NAME}
+ MAIN_DEPENDENCY Main.hs
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Semver.hs
+ DEPENDS ${PROJECT_NAME}_ffi
+ COMMAND ${GHC} --make ${CMAKE_CURRENT_SOURCE_DIR}/Main -L. -lsemver_ffi -o quickcheck_${PROJECT_NAME})
+ add_custom_target(quickcheck ALL
+ DEPENDS quickcheck_${PROJECT_NAME})
+ # pipe to ctest
+ add_test(NAME quickcheck_${PROJECT_NAME}
+ COMMAND ${CMAKE_CURRENT_BINARY_DIR}/quickcheck_${PROJECT_NAME})
+ set_tests_properties(quickcheck_${PROJECT_NAME} PROPERTIES TIMEOUT 30 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_CURRENT_BINARY_DIR}")
+
+endif()
diff --git a/external/semver/src/quickcheck/Main.hi b/external/semver/src/quickcheck/Main.hi
new file mode 100644
index 0000000..0739459
--- /dev/null
+++ b/external/semver/src/quickcheck/Main.hi
Binary files differ
diff --git a/external/semver/src/quickcheck/Main.hs b/external/semver/src/quickcheck/Main.hs
new file mode 100644
index 0000000..fc1d625
--- /dev/null
+++ b/external/semver/src/quickcheck/Main.hs
@@ -0,0 +1,80 @@
+module Main where
+
+import Semver
+import Test.QuickCheck
+
+import System.Environment
+import System.Console.GetOpt
+
+-- command line options
+data Options = Options { optVerbose :: Bool
+ , optNumTests :: Int
+ } deriving Show
+
+defaultOptions :: Options
+defaultOptions = Options { optVerbose = False
+ , optNumTests = 100
+ }
+
+options :: [OptDescr (Options -> Options)]
+options =
+ [ Option "v" ["verbose"] (NoArg (\opts -> opts { optVerbose = True }))
+ "run tests with verbose output"
+
+ , Option "n" ["numtests"] (ReqArg
+ (\d opts -> opts { optNumTests = read d })
+ "<num>")
+ "number of tests to run"
+ ]
+
+parseOpts :: [String] -> IO (Options, [String])
+parseOpts argv =
+ case getOpt Permute options argv of
+ (o, n, []) -> return (foldl (flip id) defaultOpts o, n)
+ where defaultOpts = defaultOptions
+ (_, _, errs) -> ioError (userError (concat errs ++ usageInfo header options))
+ where header = "Usage: test [options]"
+
+-- generate arbitrary Senvers
+instance Arbitrary Semver where
+ arbitrary = do
+ r1 <- arbitrary
+ r2 <- arbitrary
+ r3 <- arbitrary
+ return (Semver r1 r2 r3 "" "")
+
+-- properties
+-- a version always satisfies itself
+prop_satisfies :: Property
+prop_satisfies =
+ property $
+ \s -> satisfies s s
+
+-- a version is always less than its next {major, minor, patch} version
+prop_lessThanNext :: (Semver -> Semver) -> Property
+prop_lessThanNext f =
+ property $
+ \s -> let s' = f s in s `lessThan` s'
+
+prop_lessThanNextMajor :: Property
+prop_lessThanNextMajor = prop_lessThanNext nextMajor
+
+prop_lessThanNextMinor :: Property
+prop_lessThanNextMinor = prop_lessThanNext nextMinor
+
+prop_lessThanNextPatch :: Property
+prop_lessThanNextPatch = prop_lessThanNext nextPatch
+
+-- drive quickcheck
+main :: IO ()
+main = do
+ args <- getArgs
+ (o, _) <- parseOpts args
+ let numCheck = quickCheckWith stdArgs { maxSuccess = optNumTests o }
+ checker = if optVerbose o
+ then numCheck . verbose
+ else numCheck
+ in do checker prop_satisfies
+ checker prop_lessThanNextMajor
+ checker prop_lessThanNextMinor
+ checker prop_lessThanNextPatch
diff --git a/external/semver/src/quickcheck/Main.o b/external/semver/src/quickcheck/Main.o
new file mode 100644
index 0000000..3775e7b
--- /dev/null
+++ b/external/semver/src/quickcheck/Main.o
Binary files differ
diff --git a/external/semver/src/quickcheck/Semver.hsc b/external/semver/src/quickcheck/Semver.hsc
new file mode 100644
index 0000000..c96eb00
--- /dev/null
+++ b/external/semver/src/quickcheck/Semver.hsc
@@ -0,0 +1,87 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Semver where
+
+#include "semantic_version_ffi.h"
+
+import Foreign hiding (unsafePerformIO)
+import Foreign.C.String
+import Foreign.Storable
+import System.IO.Unsafe (unsafePerformIO)
+
+data Semver = Semver
+ { vMajor :: #{type unsigned int}
+ , vMinor :: #{type unsigned int}
+ , vPatch :: #{type unsigned int}
+ , vPrerelease :: String
+ , vBuild :: String
+ } deriving (Eq, Show)
+
+-- don't bother with the strings for now
+
+instance Storable Semver where
+ sizeOf _ = #{size semver_t}
+ alignment _ = alignment (undefined :: Word32)
+
+ peek ptr = do
+ r1 <- #{peek semver_t, major} ptr
+ r2 <- #{peek semver_t, minor} ptr
+ r3 <- #{peek semver_t, patch} ptr
+ return (Semver r1 r2 r3 "" "")
+
+ poke ptr (Semver r1 r2 r3 _ _) = do
+ #{poke semver_t, major} ptr r1
+ #{poke semver_t, minor} ptr r2
+ #{poke semver_t, patch} ptr r3
+
+-- c functions
+
+foreign import ccall "semantic_version_ffi.h satisfies"
+ c_satisfies :: Ptr Semver -> Ptr Semver -> IO Int
+foreign import ccall "semantic_version_ffi.h lessThan"
+ c_lessThan :: Ptr Semver -> Ptr Semver -> IO Int
+foreign import ccall "semantic_version_ffi.h nextMajor"
+ c_nextMajor :: Ptr Semver -> Ptr Semver -> IO ()
+foreign import ccall "semantic_version_ffi.h nextMinor"
+ c_nextMinor :: Ptr Semver -> Ptr Semver -> IO ()
+foreign import ccall "semantic_version_ffi.h nextPatch"
+ c_nextPatch :: Ptr Semver -> Ptr Semver -> IO ()
+
+-- haskell wrappers
+
+satisfies :: Semver -> Semver -> Bool
+satisfies a b =
+ unsafePerformIO $
+ alloca $ \a_ptr ->
+ alloca $ \b_ptr -> do
+ poke a_ptr a
+ poke b_ptr b
+ r <- c_satisfies a_ptr b_ptr
+ return $ if (r == 1) then True else False
+
+lessThan :: Semver -> Semver -> Bool
+lessThan a b =
+ unsafePerformIO $
+ alloca $ \a_ptr ->
+ alloca $ \b_ptr -> do
+ poke a_ptr a
+ poke b_ptr b
+ r <- c_lessThan a_ptr b_ptr
+ return $ if (r == 1) then True else False
+
+nextFunc :: (Ptr Semver -> Ptr Semver -> IO ()) -> Semver -> Semver
+nextFunc f a =
+ unsafePerformIO $
+ alloca $ \a_ptr ->
+ alloca $ \b_ptr -> do
+ poke a_ptr a
+ f a_ptr b_ptr
+ peek b_ptr
+
+nextMajor :: Semver -> Semver
+nextMajor = nextFunc c_nextMajor
+
+nextMinor :: Semver -> Semver
+nextMinor = nextFunc c_nextMinor
+
+nextPatch :: Semver -> Semver
+nextPatch = nextFunc c_nextPatch
diff --git a/external/semver/src/quickcheck/semantic_version_ffi.cpp b/external/semver/src/quickcheck/semantic_version_ffi.cpp
new file mode 100644
index 0000000..3c7d8fc
--- /dev/null
+++ b/external/semver/src/quickcheck/semantic_version_ffi.cpp
@@ -0,0 +1,58 @@
+#include "semantic_version_ffi.h"
+#include "semantic_version.h"
+
+using namespace semver;
+
+//------------------------------------------------------------------------------
+
+int satisfies(const semver_t* a, const semver_t* b)
+{
+ Version va(a->major, a->minor, a->patch,
+ a->prerelease, a->build);
+
+ Version vb(b->major, b->minor, b->patch,
+ b->prerelease, b->build);
+
+ return va.Satisfies(vb) ? 1 : 0;
+}
+
+int lessThan(const semver_t* a, const semver_t* b)
+{
+ Version va(a->major, a->minor, a->patch,
+ a->prerelease, a->build);
+
+ Version vb(b->major, b->minor, b->patch,
+ b->prerelease, b->build);
+
+ return (va < vb) ? 1 : 0;
+}
+
+void nextMajor(const semver_t* a, semver_t* b)
+{
+ Version va(a->major, a->minor, a->patch,
+ a->prerelease, a->build);
+ Version vb = va.NextMajorVersion();
+ b->major = vb.GetMajorVersion();
+ b->minor = vb.GetMinorVersion();
+ b->patch = vb.GetPatchVersion();
+}
+
+void nextMinor(const semver_t* a, semver_t* b)
+{
+ Version va(a->major, a->minor, a->patch,
+ a->prerelease, a->build);
+ Version vb = va.NextMinorVersion();
+ b->major = vb.GetMajorVersion();
+ b->minor = vb.GetMinorVersion();
+ b->patch = vb.GetPatchVersion();
+}
+
+void nextPatch(const semver_t* a, semver_t* b)
+{
+ Version va(a->major, a->minor, a->patch,
+ a->prerelease, a->build);
+ Version vb = va.NextPatchVersion();
+ b->major = vb.GetMajorVersion();
+ b->minor = vb.GetMinorVersion();
+ b->patch = vb.GetPatchVersion();
+}
diff --git a/external/semver/src/quickcheck/semantic_version_ffi.h b/external/semver/src/quickcheck/semantic_version_ffi.h
new file mode 100644
index 0000000..5a734af
--- /dev/null
+++ b/external/semver/src/quickcheck/semantic_version_ffi.h
@@ -0,0 +1,27 @@
+#pragma once
+
+// FFI for semantic version
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct Semver
+{
+ unsigned int major;
+ unsigned int minor;
+ unsigned int patch;
+ char prerelease[32];
+ char build[32];
+} semver_t;
+
+int satisfies(const semver_t* a, const semver_t* b);
+int lessThan(const semver_t* a, const semver_t* b);
+void nextMajor(const semver_t* a, semver_t* b);
+void nextMinor(const semver_t* a, semver_t* b);
+void nextPatch(const semver_t* a, semver_t* b);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/external/semver/src/test/CMakeLists.txt b/external/semver/src/test/CMakeLists.txt
new file mode 100644
index 0000000..ea04671
--- /dev/null
+++ b/external/semver/src/test/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_executable (test_${PROJECT_NAME} main.cpp)
+target_link_libraries(test_${PROJECT_NAME} ${PROJECT_NAME})
+ADD_TESTINATOR_TESTS (test_${PROJECT_NAME})
diff --git a/external/semver/src/test/main.cpp b/external/semver/src/test/main.cpp
new file mode 100644
index 0000000..47a48c5
--- /dev/null
+++ b/external/semver/src/test/main.cpp
@@ -0,0 +1,297 @@
+#include <semantic_version.h>
+
+using namespace semver;
+
+#define TESTINATOR_MAIN
+#include <testinator.h>
+
+#include <algorithm>
+#include <sstream>
+
+using namespace std;
+
+DEF_TEST(Init, SemanticVersion)
+{
+ Version v;
+ return v.GetMajorVersion() == 0
+ && v.GetMinorVersion() == 0
+ && v.GetPatchVersion() == 1;
+}
+
+DEF_TEST(NextMajor, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextMajorVersion());
+ return v2.GetMajorVersion() == 2
+ && v2.GetMinorVersion() == 0
+ && v2.GetPatchVersion() == 0;
+}
+
+DEF_TEST(NextMinor, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextMinorVersion());
+ return v2.GetMajorVersion() == 1
+ && v2.GetMinorVersion() == 3
+ && v2.GetPatchVersion() == 0;
+}
+
+DEF_TEST(NextPatch, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextPatchVersion());
+ return v2.GetMajorVersion() == 1
+ && v2.GetMinorVersion() == 2
+ && v2.GetPatchVersion() == 4;
+}
+
+DEF_TEST(LessThanMajor, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextMajorVersion());
+ return v1 < v2;
+}
+
+DEF_TEST(LessThanMinor, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextMinorVersion());
+ return v1 < v2;
+}
+
+DEF_TEST(LessThanPatch, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextPatchVersion());
+ return v1 < v2;
+}
+
+DEF_TEST(LessThanNumericString, SemanticVersion)
+{
+ Version v1(1, 2, 3, "alpha.2");
+ Version v2(1, 2, 3, "alpha.11");
+ return v1 < v2;
+}
+
+DEF_TEST(LessThanPrerelease, SemanticVersion)
+{
+ Version v1(1, 2, 3, "alpha");
+ Version v2(1, 2, 3, "beta");
+ return v1 < v2;
+}
+
+DEF_TEST(LessThanBuild, SemanticVersion)
+{
+ Version v1(1, 2, 3, "", "1");
+ Version v2(1, 2, 3, "", "2");
+ return v1 < v2;
+}
+
+DEF_TEST(PrereleaseLessThanNormal, SemanticVersion)
+{
+ Version v1(1, 2, 3, "alpha");
+ Version v2(1, 2, 3);
+ return v1 < v2;
+}
+
+DEF_TEST(NormalLessThanBuild, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(1, 2, 3, "", "1");
+ return v1 < v2;
+}
+
+DEF_TEST(PrereleaseLessThanBuild, SemanticVersion)
+{
+ Version v1(1, 2, 3, "alpha");
+ Version v2(1, 2, 3, "", "1234");
+ return v1 < v2;
+}
+
+DEF_TEST(Output, SemanticVersion)
+{
+ Version v(1, 2, 3, "alpha.2", "1234");
+ ostringstream s;
+ s << v;
+ return s.str() == "1.2.3-alpha.2+1234";
+}
+
+DEF_TEST(SameSatisfy, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+DEF_TEST(GreaterMajorSatisfy, SemanticVersion)
+{
+ Version v1(2, 0, 0);
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+DEF_TEST(GreaterMinorSatisfy, SemanticVersion)
+{
+ Version v1(1, 3, 0);
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+DEF_TEST(GreaterPatchSatisfy, SemanticVersion)
+{
+ Version v1(1, 2, 4);
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+DEF_TEST(PrereleaseSatisfy, SemanticVersion)
+{
+ Version v1(1, 2, 3, "alpha");
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+DEF_TEST(BuildSatisfy, SemanticVersion)
+{
+ Version v1(1, 2, 3, "", "1234");
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+const vector<semver::v1::Version> s_precedences_v1 =
+{
+ semver::v1::Version(1, 0, 0, "alpha"),
+ semver::v1::Version(1, 0, 0, "alpha.1"),
+ semver::v1::Version(1, 0, 0, "alpha.beta"),
+ semver::v1::Version(1, 0, 0, "beta"),
+ semver::v1::Version(1, 0, 0, "beta.2"),
+ semver::v1::Version(1, 0, 0, "beta.11"),
+ semver::v1::Version(1, 0, 0, "rc.1"),
+ semver::v1::Version(1, 0, 0, "rc.1", "build.1"),
+ semver::v1::Version(1, 0, 0),
+ semver::v1::Version(1, 0, 0, "", "0.3.7"),
+ semver::v1::Version(1, 0, 0, "", "build"),
+ semver::v1::Version(1, 0, 0, "", "build.2.b8f12d7"),
+ semver::v1::Version(1, 0, 0, "", "build.11.e0f985a")
+};
+
+DEF_TEST(Precedences_v1, SemanticVersion)
+{
+ return adjacent_find(
+ s_precedences_v1.cbegin(), s_precedences_v1.cend(),
+ [] (const auto& a, const auto& b) { return a >= b; })
+ == s_precedences_v1.end();
+}
+
+DEF_TEST(Satisfies_v1, SemanticVersion)
+{
+ return adjacent_find(
+ s_precedences_v1.cbegin(), s_precedences_v1.cend(),
+ [] (const auto& a, const auto& b) { return !b.Satisfies(a) ; })
+ == s_precedences_v1.end();
+}
+
+const vector<semver::v2::Version> s_precedences_v2 =
+{
+ semver::v2::Version(1, 0, 0, "alpha"),
+ semver::v2::Version(1, 0, 0, "alpha.1"),
+ semver::v2::Version(1, 0, 0, "alpha.beta"),
+ semver::v2::Version(1, 0, 0, "beta"),
+ semver::v2::Version(1, 0, 0, "beta.2"),
+ semver::v2::Version(1, 0, 0, "beta.11"),
+ semver::v2::Version(1, 0, 0, "rc.1"),
+ semver::v2::Version(1, 0, 0)
+};
+
+DEF_TEST(Precedences_v2, SemanticVersion)
+{
+ return adjacent_find(
+ s_precedences_v2.cbegin(), s_precedences_v2.cend(),
+ [] (const auto& a, const auto& b) { return a >= b; })
+ == s_precedences_v2.end();
+}
+
+DEF_TEST(Satisfies_v2, SemanticVersion)
+{
+ return adjacent_find(
+ s_precedences_v2.cbegin(), s_precedences_v2.cend(),
+ [] (const auto& a, const auto& b) { return !b.Satisfies(a) ; })
+ == s_precedences_v2.end();
+}
+
+DEF_TEST(PrecedenceIncludesBuild_v1, SemanticVersion)
+{
+ semver::v1::Version a(1,0,0, "", "1");
+ semver::v1::Version b(1,0,0, "", "2");
+ return a < b;
+}
+
+DEF_TEST(PrecedenceOmitsBuild_v2, SemanticVersion)
+{
+ semver::v2::Version a(1,0,0, "", "1");
+ semver::v2::Version b(1,0,0, "", "2");
+ return a == b;
+}
+
+DEF_TEST(ConstructFromString, SemanticVersion)
+{
+ Version v("1.2.3-alpha.2+build.1234");
+ ostringstream s;
+ s << v;
+ return s.str() == "1.2.3-alpha.2+build.1234";
+}
+
+DEF_TEST(WellFormed, SemanticVersion)
+{
+ Version v("1.2.3-alpha.2+build.1234");
+ return v.IsWellFormed();
+}
+
+DEF_TEST(ParseIllFormed, SemanticVersion)
+{
+ Version v("1.2.3-alpha-2+build+1234");
+ return !v.IsWellFormed();
+}
+
+namespace testinator
+{
+ template <>
+ struct Arbitrary<semver::v2::Version>
+ {
+ using Version = semver::v2::Version;
+
+ static Version generate(std::size_t g, unsigned long int s)
+ {
+ // prerelease part shouldn't contain a +
+ string pre = Arbitrary<string>::generate(g, s);
+ replace(pre.begin(), pre.end(), '+', '_');
+
+ return Version {
+ Arbitrary<unsigned int>::generate(g, s),
+ Arbitrary<unsigned int>::generate(g, s>>1),
+ Arbitrary<unsigned int>::generate(g, s>>2),
+ pre,
+ Arbitrary<string>::generate(g, s>>1)
+ };
+ }
+ static vector<Version> shrink(const Version&)
+ {
+ return vector<Version>{};
+ }
+ };
+}
+
+DEF_PROPERTY(Roundtrip, SemanticVersion, const semver::v2::Version& before)
+{
+ ostringstream s;
+ s << before;
+ Version after(s.str());
+ return after.Equals(before);
+}
+
+DEF_TEST(LessThan_Issue2, SemanticVersion)
+{
+ Version a("4.5.6");
+ Version b("1.2.3");
+ return !(a < b);
+}
diff --git a/external/sol/CMakeLists.txt b/external/sol/CMakeLists.txt
new file mode 100644
index 0000000..8654208
--- /dev/null
+++ b/external/sol/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library (
+ sol STATIC
+)
+
diff --git a/external/sol/sol.hpp b/external/sol/sol.hpp
new file mode 100644
index 0000000..d30d969
--- /dev/null
+++ b/external/sol/sol.hpp
@@ -0,0 +1,13353 @@
+// The MIT License (MIT)
+
+// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
+
+// 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 AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// This file was generated with a script.
+// Generated 2017-03-24 01:12:07.656967 UTC
+// This header was generated with sol v2.16.0 (revision 7c29964)
+// https://github.com/ThePhD/sol2
+
+#ifndef SOL_SINGLE_INCLUDE_HPP
+#define SOL_SINGLE_INCLUDE_HPP
+
+// beginning of sol.hpp
+
+#ifndef SOL_HPP
+#define SOL_HPP
+
+#if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER)
+#define SOL_INSIDE_UNREAL
+#endif // Unreal Engine 4 bullshit
+
+#ifdef SOL_INSIDE_UNREAL
+#ifdef check
+#define SOL_INSIDE_UNREAL_REMOVED_CHECK
+#undef check
+#endif
+#endif // Unreal Engine 4 Bullshit
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wconversion"
+#elif defined _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4324 ) // structure was padded due to alignment specifier
+#endif // g++
+
+// beginning of sol/state.hpp
+
+// beginning of sol/state_view.hpp
+
+// beginning of sol/error.hpp
+
+#include <stdexcept>
+#include <string>
+
+namespace sol {
+ namespace detail {
+ struct direct_error_tag {};
+ const auto direct_error = direct_error_tag{};
+ } // detail
+
+ class error : public std::runtime_error {
+ private:
+ // Because VC++ is a fuccboi
+ std::string w;
+ public:
+ error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) {}
+ error(std::string&& str) : error(detail::direct_error, "lua: error: " + std::move(str)) {}
+ error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), w(str) {}
+ error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), w(std::move(str)) {}
+
+ error(const error& e) = default;
+ error(error&& e) = default;
+ error& operator=(const error& e) = default;
+ error& operator=(error&& e) = default;
+
+ virtual const char* what() const noexcept override {
+ return w.c_str();
+ }
+ };
+
+} // sol
+
+// end of sol/error.hpp
+
+// beginning of sol/table.hpp
+
+// beginning of sol/table_core.hpp
+
+// beginning of sol/proxy.hpp
+
+// beginning of sol/traits.hpp
+
+// beginning of sol/tuple.hpp
+
+#include <tuple>
+#include <cstddef>
+
+namespace sol {
+ namespace detail {
+ using swallow = std::initializer_list<int>;
+ } // detail
+
+ template<typename... Args>
+ struct types { typedef std::make_index_sequence<sizeof...(Args)> indices; static constexpr std::size_t size() { return sizeof...(Args); } };
+ namespace meta {
+ namespace detail {
+ template<typename... Args>
+ struct tuple_types_ { typedef types<Args...> type; };
+
+ template<typename... Args>
+ struct tuple_types_<std::tuple<Args...>> { typedef types<Args...> type; };
+ } // detail
+
+ template<typename T>
+ using unqualified = std::remove_cv<std::remove_reference_t<T>>;
+
+ template<typename T>
+ using unqualified_t = typename unqualified<T>::type;
+
+ template<typename... Args>
+ using tuple_types = typename detail::tuple_types_<Args...>::type;
+
+ template<typename Arg>
+ struct pop_front_type;
+
+ template<typename Arg>
+ using pop_front_type_t = typename pop_front_type<Arg>::type;
+
+ template<typename... Args>
+ struct pop_front_type<types<Args...>> { typedef void front_type; typedef types<Args...> type; };
+
+ template<typename Arg, typename... Args>
+ struct pop_front_type<types<Arg, Args...>> { typedef Arg front_type; typedef types<Args...> type; };
+
+ template <std::size_t N, typename Tuple>
+ using tuple_element = std::tuple_element<N, unqualified_t<Tuple>>;
+
+ template <std::size_t N, typename Tuple>
+ using tuple_element_t = std::tuple_element_t<N, unqualified_t<Tuple>>;
+
+ template <std::size_t N, typename Tuple>
+ using unqualified_tuple_element = unqualified<tuple_element_t<N, Tuple>>;
+
+ template <std::size_t N, typename Tuple>
+ using unqualified_tuple_element_t = unqualified_t<tuple_element_t<N, Tuple>>;
+
+ } // meta
+} // sol
+
+// end of sol/tuple.hpp
+
+// beginning of sol/bind_traits.hpp
+
+namespace sol {
+ namespace meta {
+ namespace meta_detail {
+
+ template<class F>
+ struct check_deducible_signature {
+ struct nat {};
+ template<class G>
+ static auto test(int) -> decltype(&G::operator(), void());
+ template<class>
+ static auto test(...)->nat;
+
+ using type = std::is_void<decltype(test<F>(0))>;
+ };
+ } // meta_detail
+
+ template<class F>
+ struct has_deducible_signature : meta_detail::check_deducible_signature<F>::type { };
+
+ namespace meta_detail {
+
+ template <std::size_t I, typename T>
+ struct void_tuple_element : meta::tuple_element<I, T> {};
+
+ template <std::size_t I>
+ struct void_tuple_element<I, std::tuple<>> { typedef void type; };
+
+ template <std::size_t I, typename T>
+ using void_tuple_element_t = typename void_tuple_element<I, T>::type;
+
+ template <bool has_c_variadic, typename T, typename R, typename... Args>
+ struct basic_traits {
+ private:
+ typedef std::conditional_t<std::is_void<T>::value, int, T>& first_type;
+
+ public:
+ static const bool is_member_function = std::is_void<T>::value;
+ static const bool has_c_var_arg = has_c_variadic;
+ static const std::size_t arity = sizeof...(Args);
+ static const std::size_t free_arity = sizeof...(Args)+static_cast<std::size_t>(!std::is_void<T>::value);
+ typedef types<Args...> args_list;
+ typedef std::tuple<Args...> args_tuple;
+ typedef T object_type;
+ typedef R return_type;
+ typedef tuple_types<R> returns_list;
+ typedef R(function_type)(Args...);
+ typedef std::conditional_t<std::is_void<T>::value, args_list, types<first_type, Args...>> free_args_list;
+ typedef std::conditional_t<std::is_void<T>::value, R(Args...), R(first_type, Args...)> free_function_type;
+ typedef std::conditional_t<std::is_void<T>::value, R(*)(Args...), R(*)(first_type, Args...)> free_function_pointer_type;
+ typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
+ template<std::size_t i>
+ using arg_at = void_tuple_element_t<i, args_tuple>;
+ };
+
+ template<typename Signature, bool b = has_deducible_signature<Signature>::value>
+ struct fx_traits : basic_traits<false, void, void> {};
+
+ // Free Functions
+ template<typename R, typename... Args>
+ struct fx_traits<R(Args...), false> : basic_traits<false, void, R, Args...> {
+ typedef R(*function_pointer_type)(Args...);
+ };
+
+ template<typename R, typename... Args>
+ struct fx_traits<R(*)(Args...), false> : basic_traits<false, void, R, Args...> {
+ typedef R(*function_pointer_type)(Args...);
+ };
+
+ template<typename R, typename... Args>
+ struct fx_traits<R(Args..., ...), false> : basic_traits<true, void, R, Args...> {
+ typedef R(*function_pointer_type)(Args..., ...);
+ };
+
+ template<typename R, typename... Args>
+ struct fx_traits<R(*)(Args..., ...), false> : basic_traits<true, void, R, Args...> {
+ typedef R(*function_pointer_type)(Args..., ...);
+ };
+
+ // Member Functions
+ /* C-Style Variadics */
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args...), false> : basic_traits<false, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args...);
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args..., ...), false> : basic_traits<true, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args..., ...);
+ };
+
+ /* Const Volatile */
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args...) const, false> : basic_traits<false, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args...) const;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args..., ...) const, false> : basic_traits<true, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args..., ...) const;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args...) const volatile, false> : basic_traits<false, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args...) const volatile;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args..., ...) const volatile, false> : basic_traits<true, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args..., ...) const volatile;
+ };
+
+ /* Member Function Qualifiers */
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args...) &, false> : basic_traits<false, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args...) &;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args..., ...) &, false> : basic_traits<true, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args..., ...) &;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args...) const &, false> : basic_traits<false, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args...) const &;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args..., ...) const &, false> : basic_traits<true, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args..., ...) const &;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args...) const volatile &, false> : basic_traits<false, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args...) const volatile &;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args..., ...) const volatile &, false> : basic_traits<true, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args..., ...) const volatile &;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args...) && , false> : basic_traits<false, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args...) && ;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args..., ...) && , false> : basic_traits<true, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args..., ...) && ;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args...) const &&, false> : basic_traits<false, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args...) const &&;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args..., ...) const &&, false> : basic_traits<true, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args..., ...) const &&;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args...) const volatile &&, false> : basic_traits<false, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args...) const volatile &&;
+ };
+
+ template<typename T, typename R, typename... Args>
+ struct fx_traits<R(T::*)(Args..., ...) const volatile &&, false> : basic_traits<true, T, R, Args...> {
+ typedef R(T::* function_pointer_type)(Args..., ...) const volatile &&;
+ };
+
+ template<typename Signature>
+ struct fx_traits<Signature, true> : fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> {};
+
+ template<typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
+ struct callable_traits : fx_traits<std::decay_t<Signature>> {
+
+ };
+
+ template<typename R, typename T>
+ struct callable_traits<R(T::*), true> {
+ typedef R Arg;
+ typedef T object_type;
+ using signature_type = R(T::*);
+ static const bool is_member_function = false;
+ static const std::size_t arity = 1;
+ static const std::size_t free_arity = 2;
+ typedef std::tuple<Arg> args_tuple;
+ typedef R return_type;
+ typedef types<Arg> args_list;
+ typedef types<T, Arg> free_args_list;
+ typedef meta::tuple_types<R> returns_list;
+ typedef R(function_type)(T&, R);
+ typedef R(*function_pointer_type)(T&, R);
+ typedef R(*free_function_pointer_type)(T&, R);
+ template<std::size_t i>
+ using arg_at = void_tuple_element_t<i, args_tuple>;
+ };
+ } // meta_detail
+
+ template<typename Signature>
+ struct bind_traits : meta_detail::callable_traits<Signature> {};
+
+ template<typename Signature>
+ using function_args_t = typename bind_traits<Signature>::args_list;
+
+ template<typename Signature>
+ using function_signature_t = typename bind_traits<Signature>::signature_type;
+
+ template<typename Signature>
+ using function_return_t = typename bind_traits<Signature>::return_type;
+
+ } // meta
+} // sol
+
+// end of sol/bind_traits.hpp
+
+#include <type_traits>
+#include <memory>
+#include <functional>
+
+namespace sol {
+ template<std::size_t I>
+ using index_value = std::integral_constant<std::size_t, I>;
+
+ namespace meta {
+ template<typename T>
+ struct identity { typedef T type; };
+
+ template<typename T>
+ using identity_t = typename identity<T>::type;
+
+ template<typename... Args>
+ struct is_tuple : std::false_type { };
+
+ template<typename... Args>
+ struct is_tuple<std::tuple<Args...>> : std::true_type { };
+
+ template <typename T>
+ struct is_builtin_type : std::integral_constant<bool, std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_array<T>::value> {};
+
+ template<typename T>
+ struct unwrapped {
+ typedef T type;
+ };
+
+ template<typename T>
+ struct unwrapped<std::reference_wrapper<T>> {
+ typedef T type;
+ };
+
+ template<typename T>
+ using unwrapped_t = typename unwrapped<T>::type;
+
+ template <typename T>
+ struct unwrap_unqualified : unwrapped<unqualified_t<T>> {};
+
+ template <typename T>
+ using unwrap_unqualified_t = typename unwrap_unqualified<T>::type;
+
+ template<typename T>
+ struct remove_member_pointer;
+
+ template<typename R, typename T>
+ struct remove_member_pointer<R T::*> {
+ typedef R type;
+ };
+
+ template<typename R, typename T>
+ struct remove_member_pointer<R T::* const> {
+ typedef R type;
+ };
+
+ template<typename T>
+ using remove_member_pointer_t = remove_member_pointer<T>;
+
+ template<template<typename...> class Templ, typename T>
+ struct is_specialization_of : std::false_type { };
+ template<typename... T, template<typename...> class Templ>
+ struct is_specialization_of<Templ, Templ<T...>> : std::true_type { };
+
+ template<class T, class...>
+ struct all_same : std::true_type { };
+
+ template<class T, class U, class... Args>
+ struct all_same<T, U, Args...> : std::integral_constant <bool, std::is_same<T, U>::value && all_same<T, Args...>::value> { };
+
+ template<class T, class...>
+ struct any_same : std::false_type { };
+
+ template<class T, class U, class... Args>
+ struct any_same<T, U, Args...> : std::integral_constant <bool, std::is_same<T, U>::value || any_same<T, Args...>::value> { };
+
+ template<typename T>
+ using invoke_t = typename T::type;
+
+ template<bool B>
+ using boolean = std::integral_constant<bool, B>;
+
+ template<typename T>
+ using neg = boolean<!T::value>;
+
+ template<typename Condition, typename Then, typename Else>
+ using condition = std::conditional_t<Condition::value, Then, Else>;
+
+ template<typename... Args>
+ struct all : boolean<true> {};
+
+ template<typename T, typename... Args>
+ struct all<T, Args...> : condition<T, all<Args...>, boolean<false>> {};
+
+ template<typename... Args>
+ struct any : boolean<false> {};
+
+ template<typename T, typename... Args>
+ struct any<T, Args...> : condition<T, boolean<true>, any<Args...>> {};
+
+ enum class enable_t {
+ _
+ };
+
+ constexpr const auto enabler = enable_t::_;
+
+ template<bool value, typename T = void>
+ using disable_if_t = std::enable_if_t<!value, T>;
+
+ template<typename... Args>
+ using enable = std::enable_if_t<all<Args...>::value, enable_t>;
+
+ template<typename... Args>
+ using disable = std::enable_if_t<neg<all<Args...>>::value, enable_t>;
+
+ template<typename... Args>
+ using disable_any = std::enable_if_t<neg<any<Args...>>::value, enable_t>;
+
+ template<typename V, typename... Vs>
+ struct find_in_pack_v : boolean<false> { };
+
+ template<typename V, typename Vs1, typename... Vs>
+ struct find_in_pack_v<V, Vs1, Vs...> : any<boolean<(V::value == Vs1::value)>, find_in_pack_v<V, Vs...>> { };
+
+ namespace meta_detail {
+ template<std::size_t I, typename T, typename... Args>
+ struct index_in_pack : std::integral_constant<std::size_t, SIZE_MAX> { };
+
+ template<std::size_t I, typename T, typename T1, typename... Args>
+ struct index_in_pack<I, T, T1, Args...> : std::conditional_t<std::is_same<T, T1>::value, std::integral_constant<std::ptrdiff_t, I>, index_in_pack<I + 1, T, Args...>> { };
+ }
+
+ template<typename T, typename... Args>
+ struct index_in_pack : meta_detail::index_in_pack<0, T, Args...> { };
+
+ template<typename T, typename List>
+ struct index_in : meta_detail::index_in_pack<0, T, List> { };
+
+ template<typename T, typename... Args>
+ struct index_in<T, types<Args...>> : meta_detail::index_in_pack<0, T, Args...> { };
+
+ template<std::size_t I, typename... Args>
+ struct at_in_pack {};
+
+ template<std::size_t I, typename... Args>
+ using at_in_pack_t = typename at_in_pack<I, Args...>::type;
+
+ template<std::size_t I, typename Arg, typename... Args>
+ struct at_in_pack<I, Arg, Args...> : std::conditional<I == 0, Arg, at_in_pack_t<I - 1, Args...>> {};
+
+ template<typename Arg, typename... Args>
+ struct at_in_pack<0, Arg, Args...> { typedef Arg type; };
+
+ namespace meta_detail {
+ template<std::size_t Limit, std::size_t I, template<typename...> class Pred, typename... Ts>
+ struct count_for_pack : std::integral_constant<std::size_t, 0> {};
+ template<std::size_t Limit, std::size_t I, template<typename...> class Pred, typename T, typename... Ts>
+ struct count_for_pack<Limit, I, Pred, T, Ts...> : std::conditional_t < sizeof...(Ts) == 0 || Limit < 2,
+ std::integral_constant<std::size_t, I + static_cast<std::size_t>(Limit != 0 && Pred<T>::value)>,
+ count_for_pack<Limit - 1, I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>
+ > { };
+ template<std::size_t I, template<typename...> class Pred, typename... Ts>
+ struct count_2_for_pack : std::integral_constant<std::size_t, 0> {};
+ template<std::size_t I, template<typename...> class Pred, typename T, typename U, typename... Ts>
+ struct count_2_for_pack<I, Pred, T, U, Ts...> : std::conditional_t<sizeof...(Ts) == 0,
+ std::integral_constant<std::size_t, I + static_cast<std::size_t>(Pred<T>::value)>,
+ count_2_for_pack<I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>
+ > { };
+ } // meta_detail
+
+ template<template<typename...> class Pred, typename... Ts>
+ struct count_for_pack : meta_detail::count_for_pack<sizeof...(Ts), 0, Pred, Ts...> { };
+
+ template<template<typename...> class Pred, typename List>
+ struct count_for;
+
+ template<template<typename...> class Pred, typename... Args>
+ struct count_for<Pred, types<Args...>> : count_for_pack<Pred, Args...> {};
+
+ template<std::size_t Limit, template<typename...> class Pred, typename... Ts>
+ struct count_for_to_pack : meta_detail::count_for_pack<Limit, 0, Pred, Ts...> { };
+
+ template<template<typename...> class Pred, typename... Ts>
+ struct count_2_for_pack : meta_detail::count_2_for_pack<0, Pred, Ts...> { };
+
+ template<typename... Args>
+ struct return_type {
+ typedef std::tuple<Args...> type;
+ };
+
+ template<typename T>
+ struct return_type<T> {
+ typedef T type;
+ };
+
+ template<>
+ struct return_type<> {
+ typedef void type;
+ };
+
+ template <typename... Args>
+ using return_type_t = typename return_type<Args...>::type;
+
+ namespace meta_detail {
+ template <typename> struct always_true : std::true_type {};
+ struct is_invokable_tester {
+ template <typename Fun, typename... Args>
+ always_true<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
+ template <typename...>
+ std::false_type static test(...);
+ };
+ } // meta_detail
+
+ template <typename T>
+ struct is_invokable;
+ template <typename Fun, typename... Args>
+ struct is_invokable<Fun(Args...)> : decltype(meta_detail::is_invokable_tester::test<Fun, Args...>(0)) {};
+
+ namespace meta_detail {
+
+ template<typename T, bool isclass = std::is_class<unqualified_t<T>>::value>
+ struct is_callable : std::is_function<std::remove_pointer_t<T>> {};
+
+ template<typename T>
+ struct is_callable<T, true> {
+ using yes = char;
+ using no = struct { char s[2]; };
+
+ struct F { void operator()(); };
+ struct Derived : T, F {};
+ template<typename U, U> struct Check;
+
+ template<typename V>
+ static no test(Check<void (F::*)(), &V::operator()>*);
+
+ template<typename>
+ static yes test(...);
+
+ static const bool value = sizeof(test<Derived>(0)) == sizeof(yes);
+ };
+
+ struct has_begin_end_impl {
+ template<typename T, typename U = unqualified_t<T>,
+ typename B = decltype(std::declval<U&>().begin()),
+ typename E = decltype(std::declval<U&>().end())>
+ static std::true_type test(int);
+
+ template<typename...>
+ static std::false_type test(...);
+ };
+
+ struct has_key_value_pair_impl {
+ template<typename T, typename U = unqualified_t<T>,
+ typename V = typename U::value_type,
+ typename F = decltype(std::declval<V&>().first),
+ typename S = decltype(std::declval<V&>().second)>
+ static std::true_type test(int);
+
+ template<typename...>
+ static std::false_type test(...);
+ };
+
+ template <typename T, typename U = T, typename = decltype(std::declval<T&>() < std::declval<U&>())>
+ std::true_type supports_op_less_test(const T&);
+ std::false_type supports_op_less_test(...);
+ template <typename T, typename U = T, typename = decltype(std::declval<T&>() == std::declval<U&>())>
+ std::true_type supports_op_equal_test(const T&);
+ std::false_type supports_op_equal_test(...);
+ template <typename T, typename U = T, typename = decltype(std::declval<T&>() <= std::declval<U&>())>
+ std::true_type supports_op_less_equal_test(const T&);
+ std::false_type supports_op_less_equal_test(...);
+
+ } // meta_detail
+
+ template <typename T>
+ using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval<T&>()));
+ template <typename T>
+ using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::declval<T&>()));
+ template <typename T>
+ using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>()));
+
+ template<typename T>
+ struct is_callable : boolean<meta_detail::is_callable<T>::value> {};
+
+ template<typename T>
+ struct has_begin_end : decltype(meta_detail::has_begin_end_impl::test<T>(0)) {};
+
+ template<typename T>
+ struct has_key_value_pair : decltype(meta_detail::has_key_value_pair_impl::test<T>(0)) {};
+
+ template <typename T>
+ using is_string_constructible = any<std::is_same<unqualified_t<T>, const char*>, std::is_same<unqualified_t<T>, char>, std::is_same<unqualified_t<T>, std::string>, std::is_same<unqualified_t<T>, std::initializer_list<char>>>;
+
+ template <typename T>
+ using is_c_str = any<
+ std::is_same<std::decay_t<unqualified_t<T>>, const char*>,
+ std::is_same<std::decay_t<unqualified_t<T>>, char*>,
+ std::is_same<unqualified_t<T>, std::string>
+ >;
+
+ template <typename T>
+ struct is_move_only : all<
+ neg<std::is_reference<T>>,
+ neg<std::is_copy_constructible<unqualified_t<T>>>,
+ std::is_move_constructible<unqualified_t<T>>
+ > {};
+
+ template <typename T>
+ using is_not_move_only = neg<is_move_only<T>>;
+
+ namespace meta_detail {
+ template <typename T, meta::disable<meta::is_specialization_of<std::tuple, meta::unqualified_t<T>>> = meta::enabler>
+ decltype(auto) force_tuple(T&& x) {
+ return std::forward_as_tuple(std::forward<T>(x));
+ }
+
+ template <typename T, meta::enable<meta::is_specialization_of<std::tuple, meta::unqualified_t<T>>> = meta::enabler>
+ decltype(auto) force_tuple(T&& x) {
+ return std::forward<T>(x);
+ }
+ } // meta_detail
+
+ template <typename... X>
+ decltype(auto) tuplefy(X&&... x) {
+ return std::tuple_cat(meta_detail::force_tuple(std::forward<X>(x))...);
+ }
+ } // meta
+ namespace detail {
+ template <std::size_t I, typename Tuple>
+ decltype(auto) forward_get(Tuple&& tuple) {
+ return std::forward<meta::tuple_element_t<I, Tuple>>(std::get<I>(tuple));
+ }
+
+ template <std::size_t... I, typename Tuple>
+ auto forward_tuple_impl(std::index_sequence<I...>, Tuple&& tuple) -> decltype(std::tuple<decltype(forward_get<I>(tuple))...>(forward_get<I>(tuple)...)) {
+ return std::tuple<decltype(forward_get<I>(tuple))...>(std::move(std::get<I>(tuple))...);
+ }
+
+ template <typename Tuple>
+ auto forward_tuple(Tuple&& tuple) {
+ auto x = forward_tuple_impl(std::make_index_sequence<std::tuple_size<meta::unqualified_t<Tuple>>::value>(), std::forward<Tuple>(tuple));
+ return x;
+ }
+
+ template<typename T>
+ auto unwrap(T&& item) -> decltype(std::forward<T>(item)) {
+ return std::forward<T>(item);
+ }
+
+ template<typename T>
+ T& unwrap(std::reference_wrapper<T> arg) {
+ return arg.get();
+ }
+
+ template<typename T>
+ auto deref(T&& item) -> decltype(std::forward<T>(item)) {
+ return std::forward<T>(item);
+ }
+
+ template<typename T>
+ inline T& deref(T* item) {
+ return *item;
+ }
+
+ template<typename T, typename Dx>
+ inline std::add_lvalue_reference_t<T> deref(std::unique_ptr<T, Dx>& item) {
+ return *item;
+ }
+
+ template<typename T>
+ inline std::add_lvalue_reference_t<T> deref(std::shared_ptr<T>& item) {
+ return *item;
+ }
+
+ template<typename T, typename Dx>
+ inline std::add_lvalue_reference_t<T> deref(const std::unique_ptr<T, Dx>& item) {
+ return *item;
+ }
+
+ template<typename T>
+ inline std::add_lvalue_reference_t<T> deref(const std::shared_ptr<T>& item) {
+ return *item;
+ }
+
+ template<typename T>
+ inline T* ptr(T& val) {
+ return std::addressof(val);
+ }
+
+ template<typename T>
+ inline T* ptr(std::reference_wrapper<T> val) {
+ return std::addressof(val.get());
+ }
+
+ template<typename T>
+ inline T* ptr(T* val) {
+ return val;
+ }
+ } // detail
+} // sol
+
+// end of sol/traits.hpp
+
+// beginning of sol/object.hpp
+
+// beginning of sol/reference.hpp
+
+// beginning of sol/types.hpp
+
+// beginning of sol/optional.hpp
+
+// beginning of sol/compatibility.hpp
+
+// beginning of sol/compatibility/version.hpp
+
+#ifdef SOL_USING_CXX_LUA
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#else
+#include <lua.hpp>
+#endif // C++-compiler Lua
+
+#if defined(_WIN32) || defined(_MSC_VER)
+#ifndef SOL_CODECVT_SUPPORT
+#define SOL_CODECVT_SUPPORT 1
+#endif // sol codecvt support
+#elif defined(__GNUC__)
+#if __GNUC__ >= 5
+#ifndef SOL_CODECVT_SUPPORT
+#define SOL_CODECVT_SUPPORT 1
+#endif // codecvt support
+#endif // g++ 5.x.x (MinGW too)
+#else
+#endif // Windows/VC++ vs. g++ vs Others
+
+#ifdef LUAJIT_VERSION
+#ifndef SOL_LUAJIT
+#define SOL_LUAJIT
+#define SOL_LUAJIT_VERSION LUAJIT_VERSION_NUM
+#endif // sol luajit
+#endif // luajit
+
+#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 502
+#define SOL_LUA_VERSION LUA_VERSION_NUM
+#elif defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
+#define SOL_LUA_VERSION LUA_VERSION_NUM
+#elif !defined(LUA_VERSION_NUM)
+#define SOL_LUA_VERSION 500
+#else
+#define SOL_LUA_VERSION 502
+#endif // Lua Version 502, 501 || luajit, 500
+
+#ifdef _MSC_VER
+#ifdef _DEBUG
+#ifndef NDEBUG
+#ifndef SOL_CHECK_ARGUMENTS
+#endif // Check Arguments
+#ifndef SOL_SAFE_USERTYPE
+#define SOL_SAFE_USERTYPE
+#endif // Safe Usertypes
+#endif // NDEBUG
+#endif // Debug
+
+#ifndef _CPPUNWIND
+#ifndef SOL_NO_EXCEPTIONS
+#define SOL_NO_EXCEPTIONS 1
+#endif
+#endif // Automatic Exceptions
+
+#ifndef _CPPRTTI
+#ifndef SOL_NO_RTTI
+#define SOL_NO_RTTI 1
+#endif
+#endif // Automatic RTTI
+
+#elif defined(__GNUC__) || defined(__clang__)
+
+#ifndef NDEBUG
+#ifndef __OPTIMIZE__
+#ifndef SOL_CHECK_ARGUMENTS
+#endif // Check Arguments
+#ifndef SOL_SAFE_USERTYPE
+#define SOL_SAFE_USERTYPE
+#endif // Safe Usertypes
+#endif // g++ optimizer flag
+#endif // Not Debug
+
+#ifndef __EXCEPTIONS
+#ifndef SOL_NO_EXCEPTIONS
+#define SOL_NO_EXCEPTIONS 1
+#endif
+#endif // No Exceptions
+
+#ifndef __GXX_RTTI
+#ifndef SOL_NO_RTII
+#define SOL_NO_RTTI 1
+#endif
+#endif // No RTTI
+
+#endif // vc++ || clang++/g++
+
+#ifndef SOL_SAFE_USERTYPE
+#ifdef SOL_CHECK_ARGUMENTS
+#define SOL_SAFE_USERTYPE
+#endif // Turn on Safety for all
+#endif // Safe Usertypes
+
+// end of sol/compatibility/version.hpp
+
+#ifndef SOL_NO_COMPAT
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// beginning of sol/compatibility/5.1.0.h
+
+#ifndef SOL_5_1_0_H
+#define SOL_5_1_0_H
+
+#if SOL_LUA_VERSION == 501
+/* Lua 5.1 */
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+/* LuaJIT doesn't define these unofficial macros ... */
+#if !defined(LUAI_INT32)
+#include <limits.h>
+#if INT_MAX-20 < 32760
+#define LUAI_INT32 long
+#define LUAI_UINT32 unsigned long
+#elif INT_MAX > 2147483640L
+#define LUAI_INT32 int
+#define LUAI_UINT32 unsigned int
+#else
+#error "could not detect suitable lua_Unsigned datatype"
+#endif
+#endif
+
+/* LuaJIT does not have the updated error codes for thread status/function returns */
+#ifndef LUA_ERRGCMM
+#define LUA_ERRGCMM (LUA_ERRERR + 1)
+#endif // LUA_ERRGCMM
+
+/* LuaJIT does not support continuation contexts / return error codes? */
+#ifndef LUA_KCONTEXT
+#define LUA_KCONTEXT std::ptrdiff_t
+typedef LUA_KCONTEXT lua_KContext;
+typedef int(*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
+#endif // LUA_KCONTEXT
+
+#define LUA_OPADD 0
+#define LUA_OPSUB 1
+#define LUA_OPMUL 2
+#define LUA_OPDIV 3
+#define LUA_OPMOD 4
+#define LUA_OPPOW 5
+#define LUA_OPUNM 6
+#define LUA_OPEQ 0
+#define LUA_OPLT 1
+#define LUA_OPLE 2
+
+typedef LUAI_UINT32 lua_Unsigned;
+
+typedef struct luaL_Buffer_52 {
+ luaL_Buffer b; /* make incorrect code crash! */
+ char *ptr;
+ size_t nelems;
+ size_t capacity;
+ lua_State *L2;
+} luaL_Buffer_52;
+#define luaL_Buffer luaL_Buffer_52
+
+#define lua_tounsigned(L, i) lua_tounsignedx(L, i, NULL)
+
+#define lua_rawlen(L, i) lua_objlen(L, i)
+
+inline void lua_callk(lua_State *L, int nargs, int nresults, lua_KContext, lua_KFunction) {
+ // should probably warn the user of Lua 5.1 that continuation isn't supported...
+ lua_call(L, nargs, nresults);
+}
+inline int lua_pcallk(lua_State *L, int nargs, int nresults, int errfunc, lua_KContext, lua_KFunction) {
+ // should probably warn the user of Lua 5.1 that continuation isn't supported...
+ return lua_pcall(L, nargs, nresults, errfunc);
+}
+void lua_arith(lua_State *L, int op);
+int lua_compare(lua_State *L, int idx1, int idx2, int op);
+void lua_pushunsigned(lua_State *L, lua_Unsigned n);
+lua_Unsigned luaL_checkunsigned(lua_State *L, int i);
+lua_Unsigned lua_tounsignedx(lua_State *L, int i, int *isnum);
+lua_Unsigned luaL_optunsigned(lua_State *L, int i, lua_Unsigned def);
+lua_Integer lua_tointegerx(lua_State *L, int i, int *isnum);
+void lua_len(lua_State *L, int i);
+int luaL_len(lua_State *L, int i);
+const char *luaL_tolstring(lua_State *L, int idx, size_t *len);
+void luaL_requiref(lua_State *L, char const* modname, lua_CFunction openf, int glb);
+
+#define luaL_buffinit luaL_buffinit_52
+void luaL_buffinit(lua_State *L, luaL_Buffer_52 *B);
+
+#define luaL_prepbuffsize luaL_prepbuffsize_52
+char *luaL_prepbuffsize(luaL_Buffer_52 *B, size_t s);
+
+#define luaL_addlstring luaL_addlstring_52
+void luaL_addlstring(luaL_Buffer_52 *B, const char *s, size_t l);
+
+#define luaL_addvalue luaL_addvalue_52
+void luaL_addvalue(luaL_Buffer_52 *B);
+
+#define luaL_pushresult luaL_pushresult_52
+void luaL_pushresult(luaL_Buffer_52 *B);
+
+#undef luaL_buffinitsize
+#define luaL_buffinitsize(L, B, s) \
+ (luaL_buffinit(L, B), luaL_prepbuffsize(B, s))
+
+#undef luaL_prepbuffer
+#define luaL_prepbuffer(B) \
+ luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
+
+#undef luaL_addchar
+#define luaL_addchar(B, c) \
+ ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize(B, 1)), \
+ ((B)->ptr[(B)->nelems++] = (c)))
+
+#undef luaL_addsize
+#define luaL_addsize(B, s) \
+ ((B)->nelems += (s))
+
+#undef luaL_addstring
+#define luaL_addstring(B, s) \
+ luaL_addlstring(B, s, strlen(s))
+
+#undef luaL_pushresultsize
+#define luaL_pushresultsize(B, s) \
+ (luaL_addsize(B, s), luaL_pushresult(B))
+
+typedef struct kepler_lua_compat_get_string_view {
+ const char *s;
+ size_t size;
+} kepler_lua_compat_get_string_view;
+
+inline const char* kepler_lua_compat_get_string(lua_State* L, void* ud, size_t* size) {
+ kepler_lua_compat_get_string_view* ls = (kepler_lua_compat_get_string_view*) ud;
+ (void)L;
+ if (ls->size == 0) return NULL;
+ *size = ls->size;
+ ls->size = 0;
+ return ls->s;
+}
+
+#if !defined(SOL_LUAJIT) || (SOL_LUAJIT_VERSION < 20100)
+
+inline int luaL_loadbufferx(lua_State* L, const char* buff, size_t size, const char* name, const char*) {
+ kepler_lua_compat_get_string_view ls;
+ ls.s = buff;
+ ls.size = size;
+ return lua_load(L, kepler_lua_compat_get_string, &ls, name/*, mode*/);
+}
+
+#endif // LuaJIT 2.1.x beta and beyond
+
+#endif /* Lua 5.1 */
+
+#endif // SOL_5_1_0_H
+// end of sol/compatibility/5.1.0.h
+
+// beginning of sol/compatibility/5.0.0.h
+
+#ifndef SOL_5_0_0_H
+#define SOL_5_0_0_H
+
+#if SOL_LUA_VERSION < 501
+/* Lua 5.0 */
+
+#define LUA_QL(x) "'" x "'"
+#define LUA_QS LUA_QL("%s")
+
+#define luaL_Reg luaL_reg
+
+#define luaL_opt(L, f, n, d) \
+ (lua_isnoneornil(L, n) ? (d) : f(L, n))
+
+#define luaL_addchar(B,c) \
+ ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
+ (*(B)->p++ = (char)(c)))
+
+#endif // Lua 5.0
+
+#endif // SOL_5_0_0_H
+// end of sol/compatibility/5.0.0.h
+
+// beginning of sol/compatibility/5.x.x.h
+
+#ifndef SOL_5_X_X_H
+#define SOL_5_X_X_H
+
+#if SOL_LUA_VERSION < 502
+
+#define LUA_RIDX_GLOBALS LUA_GLOBALSINDEX
+
+#define LUA_OK 0
+
+#define lua_pushglobaltable(L) \
+ lua_pushvalue(L, LUA_GLOBALSINDEX)
+
+#define luaL_newlib(L, l) \
+ (lua_newtable((L)),luaL_setfuncs((L), (l), 0))
+
+void luaL_checkversion(lua_State *L);
+
+int lua_absindex(lua_State *L, int i);
+void lua_copy(lua_State *L, int from, int to);
+void lua_rawgetp(lua_State *L, int i, const void *p);
+void lua_rawsetp(lua_State *L, int i, const void *p);
+void *luaL_testudata(lua_State *L, int i, const char *tname);
+lua_Number lua_tonumberx(lua_State *L, int i, int *isnum);
+void lua_getuservalue(lua_State *L, int i);
+void lua_setuservalue(lua_State *L, int i);
+void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup);
+void luaL_setmetatable(lua_State *L, const char *tname);
+int luaL_getsubtable(lua_State *L, int i, const char *name);
+void luaL_traceback(lua_State *L, lua_State *L1, const char *msg, int level);
+int luaL_fileresult(lua_State *L, int stat, const char *fname);
+
+#endif // Lua 5.1 and below
+
+#endif // SOL_5_X_X_H
+// end of sol/compatibility/5.x.x.h
+
+// beginning of sol/compatibility/5.x.x.inl
+
+#ifndef SOL_5_X_X_INL
+#define SOL_5_X_X_INL
+
+// beginning of sol/compatibility/5.2.0.h
+
+#ifndef SOL_5_2_0_H
+#define SOL_5_2_0_H
+
+#if SOL_LUA_VERSION < 503
+
+inline int lua_isinteger(lua_State* L, int idx) {
+ if (lua_type(L, idx) != LUA_TNUMBER)
+ return 0;
+ // This is a very slipshod way to do the testing
+ // but lua_totingerx doesn't play ball nicely
+ // on older versions...
+ lua_Number n = lua_tonumber(L, idx);
+ lua_Integer i = lua_tointeger(L, idx);
+ if (i != n)
+ return 0;
+ // it's DEFINITELY an integer
+ return 1;
+}
+
+#endif // SOL_LUA_VERSION == 502
+#endif // SOL_5_2_0_H
+// end of sol/compatibility/5.2.0.h
+
+#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501
+
+#include <errno.h>
+
+#define PACKAGE_KEY "_sol.package"
+
+inline int lua_absindex(lua_State *L, int i) {
+ if (i < 0 && i > LUA_REGISTRYINDEX)
+ i += lua_gettop(L) + 1;
+ return i;
+}
+
+inline void lua_copy(lua_State *L, int from, int to) {
+ int abs_to = lua_absindex(L, to);
+ luaL_checkstack(L, 1, "not enough stack slots");
+ lua_pushvalue(L, from);
+ lua_replace(L, abs_to);
+}
+
+inline void lua_rawgetp(lua_State *L, int i, const void *p) {
+ int abs_i = lua_absindex(L, i);
+ lua_pushlightuserdata(L, (void*)p);
+ lua_rawget(L, abs_i);
+}
+
+inline void lua_rawsetp(lua_State *L, int i, const void *p) {
+ int abs_i = lua_absindex(L, i);
+ luaL_checkstack(L, 1, "not enough stack slots");
+ lua_pushlightuserdata(L, (void*)p);
+ lua_insert(L, -2);
+ lua_rawset(L, abs_i);
+}
+
+inline void *luaL_testudata(lua_State *L, int i, const char *tname) {
+ void *p = lua_touserdata(L, i);
+ luaL_checkstack(L, 2, "not enough stack slots");
+ if (p == NULL || !lua_getmetatable(L, i))
+ return NULL;
+ else {
+ int res = 0;
+ luaL_getmetatable(L, tname);
+ res = lua_rawequal(L, -1, -2);
+ lua_pop(L, 2);
+ if (!res)
+ p = NULL;
+ }
+ return p;
+}
+
+inline lua_Number lua_tonumberx(lua_State *L, int i, int *isnum) {
+ lua_Number n = lua_tonumber(L, i);
+ if (isnum != NULL) {
+ *isnum = (n != 0 || lua_isnumber(L, i));
+ }
+ return n;
+}
+
+inline static void push_package_table(lua_State *L) {
+ lua_pushliteral(L, PACKAGE_KEY);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ if (!lua_istable(L, -1)) {
+ lua_pop(L, 1);
+ /* try to get package table from globals */
+ lua_pushliteral(L, "package");
+ lua_rawget(L, LUA_GLOBALSINDEX);
+ if (lua_istable(L, -1)) {
+ lua_pushliteral(L, PACKAGE_KEY);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ }
+ }
+}
+
+inline void lua_getuservalue(lua_State *L, int i) {
+ luaL_checktype(L, i, LUA_TUSERDATA);
+ luaL_checkstack(L, 2, "not enough stack slots");
+ lua_getfenv(L, i);
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+ if (lua_rawequal(L, -1, -2)) {
+ lua_pop(L, 1);
+ lua_pushnil(L);
+ lua_replace(L, -2);
+ }
+ else {
+ lua_pop(L, 1);
+ push_package_table(L);
+ if (lua_rawequal(L, -1, -2)) {
+ lua_pop(L, 1);
+ lua_pushnil(L);
+ lua_replace(L, -2);
+ }
+ else
+ lua_pop(L, 1);
+ }
+}
+
+inline void lua_setuservalue(lua_State *L, int i) {
+ luaL_checktype(L, i, LUA_TUSERDATA);
+ if (lua_isnil(L, -1)) {
+ luaL_checkstack(L, 1, "not enough stack slots");
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+ lua_replace(L, -2);
+ }
+ lua_setfenv(L, i);
+}
+
+/*
+** Adapted from Lua 5.2.0
+*/
+inline void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) {
+ luaL_checkstack(L, nup + 1, "too many upvalues");
+ for (; l->name != NULL; l++) { /* fill the table with given functions */
+ int i;
+ lua_pushstring(L, l->name);
+ for (i = 0; i < nup; i++) /* copy upvalues to the top */
+ lua_pushvalue(L, -(nup + 1));
+ lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
+ lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */
+ }
+ lua_pop(L, nup); /* remove upvalues */
+}
+
+inline void luaL_setmetatable(lua_State *L, const char *tname) {
+ luaL_checkstack(L, 1, "not enough stack slots");
+ luaL_getmetatable(L, tname);
+ lua_setmetatable(L, -2);
+}
+
+inline int luaL_getsubtable(lua_State *L, int i, const char *name) {
+ int abs_i = lua_absindex(L, i);
+ luaL_checkstack(L, 3, "not enough stack slots");
+ lua_pushstring(L, name);
+ lua_gettable(L, abs_i);
+ if (lua_istable(L, -1))
+ return 1;
+ lua_pop(L, 1);
+ lua_newtable(L);
+ lua_pushstring(L, name);
+ lua_pushvalue(L, -2);
+ lua_settable(L, abs_i);
+ return 0;
+}
+
+#ifndef SOL_LUAJIT
+inline static int countlevels(lua_State *L) {
+ lua_Debug ar;
+ int li = 1, le = 1;
+ /* find an upper bound */
+ while (lua_getstack(L, le, &ar)) { li = le; le *= 2; }
+ /* do a binary search */
+ while (li < le) {
+ int m = (li + le) / 2;
+ if (lua_getstack(L, m, &ar)) li = m + 1;
+ else le = m;
+ }
+ return le - 1;
+}
+
+inline static int findfield(lua_State *L, int objidx, int level) {
+ if (level == 0 || !lua_istable(L, -1))
+ return 0; /* not found */
+ lua_pushnil(L); /* start 'next' loop */
+ while (lua_next(L, -2)) { /* for each pair in table */
+ if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */
+ if (lua_rawequal(L, objidx, -1)) { /* found object? */
+ lua_pop(L, 1); /* remove value (but keep name) */
+ return 1;
+ }
+ else if (findfield(L, objidx, level - 1)) { /* try recursively */
+ lua_remove(L, -2); /* remove table (but keep name) */
+ lua_pushliteral(L, ".");
+ lua_insert(L, -2); /* place '.' between the two names */
+ lua_concat(L, 3);
+ return 1;
+ }
+ }
+ lua_pop(L, 1); /* remove value */
+ }
+ return 0; /* not found */
+}
+
+inline static int pushglobalfuncname(lua_State *L, lua_Debug *ar) {
+ int top = lua_gettop(L);
+ lua_getinfo(L, "f", ar); /* push function */
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+ if (findfield(L, top + 1, 2)) {
+ lua_copy(L, -1, top + 1); /* move name to proper place */
+ lua_pop(L, 2); /* remove pushed values */
+ return 1;
+ }
+ else {
+ lua_settop(L, top); /* remove function and global table */
+ return 0;
+ }
+}
+
+inline static void pushfuncname(lua_State *L, lua_Debug *ar) {
+ if (*ar->namewhat != '\0') /* is there a name? */
+ lua_pushfstring(L, "function " LUA_QS, ar->name);
+ else if (*ar->what == 'm') /* main? */
+ lua_pushliteral(L, "main chunk");
+ else if (*ar->what == 'C') {
+ if (pushglobalfuncname(L, ar)) {
+ lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
+ lua_remove(L, -2); /* remove name */
+ }
+ else
+ lua_pushliteral(L, "?");
+ }
+ else
+ lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
+}
+
+#define LEVELS1 12 /* size of the first part of the stack */
+#define LEVELS2 10 /* size of the second part of the stack */
+
+inline void luaL_traceback(lua_State *L, lua_State *L1,
+ const char *msg, int level) {
+ lua_Debug ar;
+ int top = lua_gettop(L);
+ int numlevels = countlevels(L1);
+ int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
+ if (msg) lua_pushfstring(L, "%s\n", msg);
+ lua_pushliteral(L, "stack traceback:");
+ while (lua_getstack(L1, level++, &ar)) {
+ if (level == mark) { /* too many levels? */
+ lua_pushliteral(L, "\n\t..."); /* add a '...' */
+ level = numlevels - LEVELS2; /* and skip to last ones */
+ }
+ else {
+ lua_getinfo(L1, "Slnt", &ar);
+ lua_pushfstring(L, "\n\t%s:", ar.short_src);
+ if (ar.currentline > 0)
+ lua_pushfstring(L, "%d:", ar.currentline);
+ lua_pushliteral(L, " in ");
+ pushfuncname(L, &ar);
+ lua_concat(L, lua_gettop(L) - top);
+ }
+ }
+ lua_concat(L, lua_gettop(L) - top);
+}
+#endif
+
+inline const lua_Number *lua_version(lua_State *L) {
+ static const lua_Number version = LUA_VERSION_NUM;
+ if (L == NULL) return &version;
+ // TODO: wonky hacks to get at the inside of the incomplete type lua_State?
+ //else return L->l_G->version;
+ else return &version;
+}
+
+inline static void luaL_checkversion_(lua_State *L, lua_Number ver) {
+ const lua_Number* v = lua_version(L);
+ if (v != lua_version(NULL))
+ luaL_error(L, "multiple Lua VMs detected");
+ else if (*v != ver)
+ luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
+ ver, *v);
+ /* check conversions number -> integer types */
+ lua_pushnumber(L, -(lua_Number)0x1234);
+ if (lua_tointeger(L, -1) != -0x1234 ||
+ lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234)
+ luaL_error(L, "bad conversion number->int;"
+ " must recompile Lua with proper settings");
+ lua_pop(L, 1);
+}
+
+inline void luaL_checkversion(lua_State* L) {
+ luaL_checkversion_(L, LUA_VERSION_NUM);
+}
+
+#ifndef SOL_LUAJIT
+inline int luaL_fileresult(lua_State *L, int stat, const char *fname) {
+ int en = errno; /* calls to Lua API may change this value */
+ if (stat) {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ else {
+ char buf[1024];
+#if defined(__GLIBC__) || defined(_POSIX_VERSION)
+ strerror_r(en, buf, 1024);
+#else
+ strerror_s(buf, 1024, en);
+#endif
+ lua_pushnil(L);
+ if (fname)
+ lua_pushfstring(L, "%s: %s", fname, buf);
+ else
+ lua_pushstring(L, buf);
+ lua_pushnumber(L, (lua_Number)en);
+ return 3;
+ }
+}
+#endif // luajit
+#endif // Lua 5.0 or Lua 5.1
+
+#if SOL_LUA_VERSION == 501
+
+typedef LUAI_INT32 LUA_INT32;
+
+/********************************************************************/
+/* extract of 5.2's luaconf.h */
+/* detects proper defines for faster unsigned<->number conversion */
+/* see copyright notice at the end of this file */
+/********************************************************************/
+
+#if !defined(LUA_ANSI) && defined(_WIN32) && !defined(_WIN32_WCE)
+#define LUA_WIN /* enable goodies for regular Windows platforms */
+#endif
+
+#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */
+
+/* Microsoft compiler on a Pentium (32 bit) ? */
+#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */
+
+#define LUA_MSASMTRICK
+#define LUA_IEEEENDIAN 0
+#define LUA_NANTRICK
+
+/* pentium 32 bits? */
+#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */
+
+#define LUA_IEEE754TRICK
+#define LUA_IEEELL
+#define LUA_IEEEENDIAN 0
+#define LUA_NANTRICK
+
+/* pentium 64 bits? */
+#elif defined(__x86_64) /* }{ */
+
+#define LUA_IEEE754TRICK
+#define LUA_IEEEENDIAN 0
+
+#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */
+
+#define LUA_IEEE754TRICK
+#define LUA_IEEEENDIAN 1
+
+#else /* }{ */
+
+/* assume IEEE754 and a 32-bit integer type */
+#define LUA_IEEE754TRICK
+
+#endif /* } */
+
+#endif /* } */
+
+/********************************************************************/
+/* extract of 5.2's llimits.h */
+/* gives us lua_number2unsigned and lua_unsigned2number */
+/* see copyright notice just below this one here */
+/********************************************************************/
+
+/*********************************************************************
+* This file contains parts of Lua 5.2's source code:
+*
+* Copyright (C) 1994-2013 Lua.org, PUC-Rio.
+*
+* 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*********************************************************************/
+
+#if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK) /* { */
+/* trick with Microsoft assembler for X86 */
+
+#define lua_number2unsigned(i,n) \
+ {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;}
+
+#elif defined(LUA_IEEE754TRICK) /* }{ */
+/* the next trick should work on any machine using IEEE754 with
+a 32-bit int type */
+
+union compat52_luai_Cast { double l_d; LUA_INT32 l_p[2]; };
+
+#if !defined(LUA_IEEEENDIAN) /* { */
+#define LUAI_EXTRAIEEE \
+ static const union compat52_luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)};
+#define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33)
+#else
+#define LUA_IEEEENDIANLOC LUA_IEEEENDIAN
+#define LUAI_EXTRAIEEE /* empty */
+#endif /* } */
+
+#define lua_number2int32(i,n,t) \
+ { LUAI_EXTRAIEEE \
+ volatile union compat52_luai_Cast u; u.l_d = (n) + 6755399441055744.0; \
+ (i) = (t)u.l_p[LUA_IEEEENDIANLOC]; }
+
+#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned)
+
+#endif /* } */
+
+/* the following definitions always work, but may be slow */
+
+#if !defined(lua_number2unsigned) /* { */
+/* the following definition assures proper modulo behavior */
+#if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT)
+#include <math.h>
+#define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1)
+#define lua_number2unsigned(i,n) \
+ ((i)=(lua_Unsigned)((n) - floor((n)/SUPUNSIGNED)*SUPUNSIGNED))
+#else
+#define lua_number2unsigned(i,n) ((i)=(lua_Unsigned)(n))
+#endif
+#endif /* } */
+
+#if !defined(lua_unsigned2number)
+/* on several machines, coercion from unsigned to double is slow,
+so it may be worth to avoid */
+#define lua_unsigned2number(u) \
+ (((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u))
+#endif
+
+/********************************************************************/
+
+inline static void compat52_call_lua(lua_State *L, char const code[], size_t len,
+ int nargs, int nret) {
+ lua_rawgetp(L, LUA_REGISTRYINDEX, (void*)code);
+ if (lua_type(L, -1) != LUA_TFUNCTION) {
+ lua_pop(L, 1);
+ if (luaL_loadbuffer(L, code, len, "=none"))
+ lua_error(L);
+ lua_pushvalue(L, -1);
+ lua_rawsetp(L, LUA_REGISTRYINDEX, (void*)code);
+ }
+ lua_insert(L, -nargs - 1);
+ lua_call(L, nargs, nret);
+}
+
+static const char compat52_arith_code[] = {
+ "local op,a,b=...\n"
+ "if op==0 then return a+b\n"
+ "elseif op==1 then return a-b\n"
+ "elseif op==2 then return a*b\n"
+ "elseif op==3 then return a/b\n"
+ "elseif op==4 then return a%b\n"
+ "elseif op==5 then return a^b\n"
+ "elseif op==6 then return -a\n"
+ "end\n"
+};
+
+inline void lua_arith(lua_State *L, int op) {
+ if (op < LUA_OPADD || op > LUA_OPUNM)
+ luaL_error(L, "invalid 'op' argument for lua_arith");
+ luaL_checkstack(L, 5, "not enough stack slots");
+ if (op == LUA_OPUNM)
+ lua_pushvalue(L, -1);
+ lua_pushnumber(L, op);
+ lua_insert(L, -3);
+ compat52_call_lua(L, compat52_arith_code,
+ sizeof(compat52_arith_code) - 1, 3, 1);
+}
+
+static const char compat52_compare_code[] = {
+ "local a,b=...\n"
+ "return a<=b\n"
+};
+
+inline int lua_compare(lua_State *L, int idx1, int idx2, int op) {
+ int result = 0;
+ switch (op) {
+ case LUA_OPEQ:
+ return lua_equal(L, idx1, idx2);
+ case LUA_OPLT:
+ return lua_lessthan(L, idx1, idx2);
+ case LUA_OPLE:
+ luaL_checkstack(L, 5, "not enough stack slots");
+ idx1 = lua_absindex(L, idx1);
+ idx2 = lua_absindex(L, idx2);
+ lua_pushvalue(L, idx1);
+ lua_pushvalue(L, idx2);
+ compat52_call_lua(L, compat52_compare_code,
+ sizeof(compat52_compare_code) - 1, 2, 1);
+ result = lua_toboolean(L, -1);
+ lua_pop(L, 1);
+ return result;
+ default:
+ luaL_error(L, "invalid 'op' argument for lua_compare");
+ }
+ return 0;
+}
+
+inline void lua_pushunsigned(lua_State *L, lua_Unsigned n) {
+ lua_pushnumber(L, lua_unsigned2number(n));
+}
+
+inline lua_Unsigned luaL_checkunsigned(lua_State *L, int i) {
+ lua_Unsigned result;
+ lua_Number n = lua_tonumber(L, i);
+ if (n == 0 && !lua_isnumber(L, i))
+ luaL_checktype(L, i, LUA_TNUMBER);
+ lua_number2unsigned(result, n);
+ return result;
+}
+
+inline lua_Unsigned lua_tounsignedx(lua_State *L, int i, int *isnum) {
+ lua_Unsigned result;
+ lua_Number n = lua_tonumberx(L, i, isnum);
+ lua_number2unsigned(result, n);
+ return result;
+}
+
+inline lua_Unsigned luaL_optunsigned(lua_State *L, int i, lua_Unsigned def) {
+ return luaL_opt(L, luaL_checkunsigned, i, def);
+}
+
+inline lua_Integer lua_tointegerx(lua_State *L, int i, int *isnum) {
+ lua_Integer n = lua_tointeger(L, i);
+ if (isnum != NULL) {
+ *isnum = (n != 0 || lua_isnumber(L, i));
+ }
+ return n;
+}
+
+inline void lua_len(lua_State *L, int i) {
+ switch (lua_type(L, i)) {
+ case LUA_TSTRING: /* fall through */
+ case LUA_TTABLE:
+ if (!luaL_callmeta(L, i, "__len"))
+ lua_pushnumber(L, (int)lua_objlen(L, i));
+ break;
+ case LUA_TUSERDATA:
+ if (luaL_callmeta(L, i, "__len"))
+ break;
+ /* maybe fall through */
+ default:
+ luaL_error(L, "attempt to get length of a %s value",
+ lua_typename(L, lua_type(L, i)));
+ }
+}
+
+inline int luaL_len(lua_State *L, int i) {
+ int res = 0, isnum = 0;
+ luaL_checkstack(L, 1, "not enough stack slots");
+ lua_len(L, i);
+ res = (int)lua_tointegerx(L, -1, &isnum);
+ lua_pop(L, 1);
+ if (!isnum)
+ luaL_error(L, "object length is not a number");
+ return res;
+}
+
+inline const char *luaL_tolstring(lua_State *L, int idx, size_t *len) {
+ if (!luaL_callmeta(L, idx, "__tostring")) {
+ int t = lua_type(L, idx);
+ switch (t) {
+ case LUA_TNIL:
+ lua_pushliteral(L, "nil");
+ break;
+ case LUA_TSTRING:
+ case LUA_TNUMBER:
+ lua_pushvalue(L, idx);
+ break;
+ case LUA_TBOOLEAN:
+ if (lua_toboolean(L, idx))
+ lua_pushliteral(L, "true");
+ else
+ lua_pushliteral(L, "false");
+ break;
+ default:
+ lua_pushfstring(L, "%s: %p", lua_typename(L, t),
+ lua_topointer(L, idx));
+ break;
+ }
+ }
+ return lua_tolstring(L, -1, len);
+}
+
+inline void luaL_requiref(lua_State *L, char const* modname,
+ lua_CFunction openf, int glb) {
+ luaL_checkstack(L, 3, "not enough stack slots");
+ lua_pushcfunction(L, openf);
+ lua_pushstring(L, modname);
+ lua_call(L, 1, 1);
+ lua_getglobal(L, "package");
+ if (lua_istable(L, -1) == 0) {
+ lua_pop(L, 1);
+ lua_createtable(L, 0, 16);
+ lua_setglobal(L, "package");
+ lua_getglobal(L, "package");
+ }
+ lua_getfield(L, -1, "loaded");
+ if (lua_istable(L, -1) == 0) {
+ lua_pop(L, 1);
+ lua_createtable(L, 0, 1);
+ lua_setfield(L, -2, "loaded");
+ lua_getfield(L, -1, "loaded");
+ }
+ lua_replace(L, -2);
+ lua_pushvalue(L, -2);
+ lua_setfield(L, -2, modname);
+ lua_pop(L, 1);
+ if (glb) {
+ lua_pushvalue(L, -1);
+ lua_setglobal(L, modname);
+ }
+}
+
+inline void luaL_buffinit(lua_State *L, luaL_Buffer_52 *B) {
+ /* make it crash if used via pointer to a 5.1-style luaL_Buffer */
+ B->b.p = NULL;
+ B->b.L = NULL;
+ B->b.lvl = 0;
+ /* reuse the buffer from the 5.1-style luaL_Buffer though! */
+ B->ptr = B->b.buffer;
+ B->capacity = LUAL_BUFFERSIZE;
+ B->nelems = 0;
+ B->L2 = L;
+}
+
+inline char *luaL_prepbuffsize(luaL_Buffer_52 *B, size_t s) {
+ if (B->capacity - B->nelems < s) { /* needs to grow */
+ char* newptr = NULL;
+ size_t newcap = B->capacity * 2;
+ if (newcap - B->nelems < s)
+ newcap = B->nelems + s;
+ if (newcap < B->capacity) /* overflow */
+ luaL_error(B->L2, "buffer too large");
+ newptr = (char*)lua_newuserdata(B->L2, newcap);
+ memcpy(newptr, B->ptr, B->nelems);
+ if (B->ptr != B->b.buffer)
+ lua_replace(B->L2, -2); /* remove old buffer */
+ B->ptr = newptr;
+ B->capacity = newcap;
+ }
+ return B->ptr + B->nelems;
+}
+
+inline void luaL_addlstring(luaL_Buffer_52 *B, const char *s, size_t l) {
+ memcpy(luaL_prepbuffsize(B, l), s, l);
+ luaL_addsize(B, l);
+}
+
+inline void luaL_addvalue(luaL_Buffer_52 *B) {
+ size_t len = 0;
+ const char *s = lua_tolstring(B->L2, -1, &len);
+ if (!s)
+ luaL_error(B->L2, "cannot convert value to string");
+ if (B->ptr != B->b.buffer)
+ lua_insert(B->L2, -2); /* userdata buffer must be at stack top */
+ luaL_addlstring(B, s, len);
+ lua_remove(B->L2, B->ptr != B->b.buffer ? -2 : -1);
+}
+
+inline void luaL_pushresult(luaL_Buffer_52 *B) {
+ lua_pushlstring(B->L2, B->ptr, B->nelems);
+ if (B->ptr != B->b.buffer)
+ lua_replace(B->L2, -2); /* remove userdata buffer */
+}
+
+#endif /* SOL_LUA_VERSION == 501 */
+
+#endif // SOL_5_X_X_INL
+// end of sol/compatibility/5.x.x.inl
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SOL_NO_COMPAT
+
+// end of sol/compatibility.hpp
+
+// beginning of sol/in_place.hpp
+
+namespace sol {
+
+ namespace detail {
+ struct in_place_of {};
+ template <std::size_t I>
+ struct in_place_of_i {};
+ template <typename T>
+ struct in_place_of_t {};
+ } // detail
+
+ struct in_place_tag { struct init {}; constexpr in_place_tag(init) {} in_place_tag() = delete; };
+ constexpr inline in_place_tag in_place(detail::in_place_of) { return in_place_tag(in_place_tag::init()); }
+ template <typename T>
+ constexpr inline in_place_tag in_place(detail::in_place_of_t<T>) { return in_place_tag(in_place_tag::init()); }
+ template <std::size_t I>
+ constexpr inline in_place_tag in_place(detail::in_place_of_i<I>) { return in_place_tag(in_place_tag::init()); }
+
+ using in_place_t = in_place_tag(&)(detail::in_place_of);
+ template <typename T>
+ using in_place_type_t = in_place_tag(&)(detail::in_place_of_t<T>);
+ template <std::size_t I>
+ using in_place_index_t = in_place_tag(&)(detail::in_place_of_i<I>);
+
+} // sol
+
+// end of sol/in_place.hpp
+
+#if defined(SOL_USE_BOOST)
+#include <boost/optional.hpp>
+#else
+// beginning of sol/optional_implementation.hpp
+
+# ifndef SOL_OPTIONAL_IMPLEMENTATION_HPP
+# define SOL_OPTIONAL_IMPLEMENTATION_HPP
+
+# include <utility>
+# include <type_traits>
+# include <initializer_list>
+# include <cassert>
+# include <functional>
+# include <string>
+# include <stdexcept>
+#ifdef SOL_NO_EXCEPTIONS
+#include <cstdlib>
+#endif // Exceptions
+
+# define TR2_OPTIONAL_REQUIRES(...) typename ::std::enable_if<__VA_ARGS__::value, bool>::type = false
+
+# if defined __GNUC__ // NOTE: GNUC is also defined for Clang
+# if (__GNUC__ >= 5)
+# define TR2_OPTIONAL_GCC_5_0_AND_HIGHER___
+# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___
+# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)
+# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___
+# elif (__GNUC__ > 4)
+# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___
+# endif
+#
+# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)
+# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___
+# elif (__GNUC__ > 4)
+# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___
+# endif
+#
+# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1)
+# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___
+# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)
+# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___
+# elif (__GNUC__ > 4)
+# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___
+# endif
+# endif
+#
+# if defined __clang_major__
+# if (__clang_major__ == 3 && __clang_minor__ >= 5)
+# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
+# elif (__clang_major__ > 3)
+# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
+# endif
+# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
+# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_
+# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2)
+# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_
+# endif
+# endif
+#
+# if defined _MSC_VER
+# if (_MSC_VER >= 1900)
+# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___
+# endif
+# endif
+
+# if defined __clang__
+# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9)
+# define OPTIONAL_HAS_THIS_RVALUE_REFS 1
+# else
+# define OPTIONAL_HAS_THIS_RVALUE_REFS 0
+# endif
+# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___
+# define OPTIONAL_HAS_THIS_RVALUE_REFS 1
+# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___
+# define OPTIONAL_HAS_THIS_RVALUE_REFS 1
+# else
+# define OPTIONAL_HAS_THIS_RVALUE_REFS 0
+# endif
+
+# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___
+# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1
+# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr
+# else
+# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0
+# define OPTIONAL_CONSTEXPR_INIT_LIST
+# endif
+
+# if defined(TR2_OPTIONAL_MSVC_2015_AND_HIGHER___) || (defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L))
+# define OPTIONAL_HAS_MOVE_ACCESSORS 1
+# else
+# define OPTIONAL_HAS_MOVE_ACCESSORS 0
+# endif
+
+# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr
+# if defined(TR2_OPTIONAL_MSVC_2015_AND_HIGHER___) || ((defined __cplusplus) && (__cplusplus == 201103L))
+# define OPTIONAL_MUTABLE_CONSTEXPR
+# else
+# define OPTIONAL_MUTABLE_CONSTEXPR constexpr
+# endif
+
+# if defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___
+#pragma warning( push )
+#pragma warning( disable : 4814 )
+#endif
+
+namespace sol {
+
+ // BEGIN workaround for missing is_trivially_destructible
+# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___
+ // leave it: it is already there
+# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_
+ // leave it: it is already there
+# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___
+ // leave it: it is already there
+# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS
+ // leave it: the user doesn't want it
+# else
+ template <typename T>
+ using is_trivially_destructible = ::std::has_trivial_destructor<T>;
+# endif
+ // END workaround for missing is_trivially_destructible
+
+# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___)
+ // leave it; our metafunctions are already defined.
+# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_
+ // leave it; our metafunctions are already defined.
+# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___
+ // leave it: it is already there
+# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS
+ // leave it: the user doesn't want it
+# else
+
+ template <class T>
+ struct is_nothrow_move_constructible
+ {
+ constexpr static bool value = ::std::is_nothrow_constructible<T, T&&>::value;
+ };
+
+ template <class T, class U>
+ struct is_assignable
+ {
+ template <class X, class Y>
+ constexpr static bool has_assign(...) { return false; }
+
+ template <class X, class Y, size_t S = sizeof((::std::declval<X>() = ::std::declval<Y>(), true)) >
+ // the comma operator is necessary for the cases where operator= returns void
+ constexpr static bool has_assign(bool) { return true; }
+
+ constexpr static bool value = has_assign<T, U>(true);
+ };
+
+ template <class T>
+ struct is_nothrow_move_assignable
+ {
+ template <class X, bool has_any_move_assign>
+ struct has_nothrow_move_assign {
+ constexpr static bool value = false;
+ };
+
+ template <class X>
+ struct has_nothrow_move_assign<X, true> {
+ constexpr static bool value = noexcept(::std::declval<X&>() = ::std::declval<X&&>());
+ };
+
+ constexpr static bool value = has_nothrow_move_assign<T, is_assignable<T&, T&&>::value>::value;
+ };
+ // end workaround
+
+# endif
+
+ template <class T> class optional;
+
+ // 20.5.5, optional for lvalue reference types
+ template <class T> class optional<T&>;
+
+ // workaround: std utility functions aren't constexpr yet
+ template <class T> inline constexpr T&& constexpr_forward(typename ::std::remove_reference<T>::type& t) noexcept
+ {
+ return static_cast<T&&>(t);
+ }
+
+ template <class T> inline constexpr T&& constexpr_forward(typename ::std::remove_reference<T>::type&& t) noexcept
+ {
+ static_assert(!::std::is_lvalue_reference<T>::value, "!!");
+ return static_cast<T&&>(t);
+ }
+
+ template <class T> inline constexpr typename ::std::remove_reference<T>::type&& constexpr_move(T&& t) noexcept
+ {
+ return static_cast<typename ::std::remove_reference<T>::type&&>(t);
+ }
+
+#if defined NDEBUG
+# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR)
+#else
+# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR)))
+#endif
+
+ namespace detail_
+ {
+
+ // static_addressof: a constexpr version of addressof
+ template <typename T>
+ struct has_overloaded_addressof
+ {
+ template <class X>
+ constexpr static bool has_overload(...) { return false; }
+
+ template <class X, size_t S = sizeof(::std::declval<X&>().operator&()) >
+ constexpr static bool has_overload(bool) { return true; }
+
+ constexpr static bool value = has_overload<T>(true);
+ };
+
+ template <typename T, TR2_OPTIONAL_REQUIRES(!has_overloaded_addressof<T>)>
+ constexpr T* static_addressof(T& ref)
+ {
+ return &ref;
+ }
+
+ template <typename T, TR2_OPTIONAL_REQUIRES(has_overloaded_addressof<T>)>
+ T* static_addressof(T& ref)
+ {
+ return ::std::addressof(ref);
+ }
+
+ // the call to convert<A>(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A
+ template <class U>
+ constexpr U convert(U v) { return v; }
+
+ } // namespace detail_
+
+ constexpr struct trivial_init_t {} trivial_init{};
+
+ // 20.5.7, Disengaged state indicator
+ struct nullopt_t
+ {
+ struct init {};
+ constexpr explicit nullopt_t(init) {}
+ };
+ constexpr nullopt_t nullopt{ nullopt_t::init() };
+
+ // 20.5.8, class bad_optional_access
+ class bad_optional_access : public ::std::logic_error {
+ public:
+ explicit bad_optional_access(const ::std::string& what_arg) : ::std::logic_error{ what_arg } {}
+ explicit bad_optional_access(const char* what_arg) : ::std::logic_error{ what_arg } {}
+ };
+
+ template <class T>
+ struct alignas(T) optional_base {
+ char storage_[sizeof(T)];
+ bool init_;
+
+ constexpr optional_base() noexcept : storage_(), init_(false) {};
+
+ explicit optional_base(const T& v) : storage_(), init_(true) {
+ new (&storage())T(v);
+ }
+
+ explicit optional_base(T&& v) : storage_(), init_(true) {
+ new (&storage())T(constexpr_move(v));
+ }
+
+ template <class... Args> explicit optional_base(in_place_t, Args&&... args)
+ : init_(true), storage_() {
+ new (&storage())T(constexpr_forward<Args>(args)...);
+ }
+
+ template <class U, class... Args, TR2_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)>
+ explicit optional_base(in_place_t, ::std::initializer_list<U> il, Args&&... args)
+ : init_(true), storage_() {
+ new (&storage())T(il, constexpr_forward<Args>(args)...);
+ }
+#if defined __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif
+ T& storage() {
+ return *reinterpret_cast<T*>(&storage_[0]);
+ }
+
+ constexpr const T& storage() const {
+ return *reinterpret_cast<T const*>(&storage_[0]);
+ }
+#if defined __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+ ~optional_base() { if (init_) { storage().T::~T(); } }
+ };
+
+#if defined __GNUC__ && !defined TR2_OPTIONAL_GCC_5_0_AND_HIGHER___
+ // Sorry, GCC 4.x; you're just a piece of shit
+ template <typename T>
+ using constexpr_optional_base = optional_base<T>;
+#else
+ template <class T>
+ struct alignas(T) constexpr_optional_base {
+ char storage_[sizeof(T)];
+ bool init_;
+ constexpr constexpr_optional_base() noexcept : storage_(), init_(false) {}
+
+ explicit constexpr constexpr_optional_base(const T& v) : storage_(), init_(true) {
+ new (&storage())T(v);
+ }
+
+ explicit constexpr constexpr_optional_base(T&& v) : storage_(), init_(true) {
+ new (&storage())T(constexpr_move(v));
+ }
+
+ template <class... Args> explicit constexpr constexpr_optional_base(in_place_t, Args&&... args)
+ : init_(true), storage_() {
+ new (&storage())T(constexpr_forward<Args>(args)...);
+ }
+
+ template <class U, class... Args, TR2_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)>
+ OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, ::std::initializer_list<U> il, Args&&... args)
+ : init_(true), storage_() {
+ new (&storage())T(il, constexpr_forward<Args>(args)...);
+ }
+
+#if defined __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif
+ T& storage() {
+ return (*reinterpret_cast<T*>(&storage_[0]));
+ }
+
+ constexpr const T& storage() const {
+ return (*reinterpret_cast<T const*>(&storage_[0]));
+ }
+#if defined __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+ ~constexpr_optional_base() = default;
+ };
+#endif
+
+ template <class T>
+ using OptionalBase = typename ::std::conditional<
+ ::std::is_trivially_destructible<T>::value,
+ constexpr_optional_base<typename ::std::remove_const<T>::type>,
+ optional_base<typename ::std::remove_const<T>::type>
+ >::type;
+
+ template <class T>
+ class optional : private OptionalBase<T>
+ {
+ static_assert(!::std::is_same<typename ::std::decay<T>::type, nullopt_t>::value, "bad T");
+ static_assert(!::std::is_same<typename ::std::decay<T>::type, in_place_t>::value, "bad T");
+
+ constexpr bool initialized() const noexcept { return OptionalBase<T>::init_; }
+ typename ::std::remove_const<T>::type* dataptr() { return ::std::addressof(OptionalBase<T>::storage()); }
+ constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase<T>::storage()); }
+
+# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1
+ constexpr const T& contained_val() const& { return OptionalBase<T>::storage(); }
+# if OPTIONAL_HAS_MOVE_ACCESSORS == 1
+ OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return ::std::move(OptionalBase<T>::storage()); }
+ OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase<T>::storage(); }
+# else
+ T& contained_val() & { return OptionalBase<T>::storage(); }
+ T&& contained_val() && { return ::std::move(OptionalBase<T>::storage()); }
+# endif
+# else
+ constexpr const T& contained_val() const { return OptionalBase<T>::storage(); }
+ T& contained_val() { return OptionalBase<T>::storage(); }
+# endif
+
+ void clear() noexcept {
+ if (initialized()) dataptr()->T::~T();
+ OptionalBase<T>::init_ = false;
+ }
+
+ template <class... Args>
+ void initialize(Args&&... args) noexcept(noexcept(T(::std::forward<Args>(args)...)))
+ {
+ assert(!OptionalBase<T>::init_);
+ ::new (static_cast<void*>(dataptr())) T(::std::forward<Args>(args)...);
+ OptionalBase<T>::init_ = true;
+ }
+
+ template <class U, class... Args>
+ void initialize(::std::initializer_list<U> il, Args&&... args) noexcept(noexcept(T(il, ::std::forward<Args>(args)...)))
+ {
+ assert(!OptionalBase<T>::init_);
+ ::new (static_cast<void*>(dataptr())) T(il, ::std::forward<Args>(args)...);
+ OptionalBase<T>::init_ = true;
+ }
+
+ public:
+ typedef T value_type;
+
+ // 20.5.5.1, constructors
+ constexpr optional() noexcept : OptionalBase<T>() {};
+ constexpr optional(nullopt_t) noexcept : OptionalBase<T>() {};
+
+ optional(const optional& rhs)
+ : OptionalBase<T>()
+ {
+ if (rhs.initialized()) {
+ ::new (static_cast<void*>(dataptr())) T(*rhs);
+ OptionalBase<T>::init_ = true;
+ }
+ }
+
+ optional(const optional<T&>& rhs) : optional()
+ {
+ if (rhs) {
+ ::new (static_cast<void*>(dataptr())) T(*rhs);
+ OptionalBase<T>::init_ = true;
+ }
+ }
+
+ optional(optional&& rhs) noexcept(::std::is_nothrow_move_constructible<T>::value)
+ : OptionalBase<T>()
+ {
+ if (rhs.initialized()) {
+ ::new (static_cast<void*>(dataptr())) T(::std::move(*rhs));
+ OptionalBase<T>::init_ = true;
+ }
+ }
+
+ constexpr optional(const T& v) : OptionalBase<T>(v) {}
+
+ constexpr optional(T&& v) : OptionalBase<T>(constexpr_move(v)) {}
+
+ template <class... Args>
+ explicit constexpr optional(in_place_t, Args&&... args)
+ : OptionalBase<T>(in_place, constexpr_forward<Args>(args)...) {}
+
+ template <class U, class... Args, TR2_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)>
+ OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, ::std::initializer_list<U> il, Args&&... args)
+ : OptionalBase<T>(in_place, il, constexpr_forward<Args>(args)...) {}
+
+ // 20.5.4.2, Destructor
+ ~optional() = default;
+
+ // 20.5.4.3, assignment
+ optional& operator=(nullopt_t) noexcept
+ {
+ clear();
+ return *this;
+ }
+
+ optional& operator=(const optional& rhs)
+ {
+ if (initialized() == true && rhs.initialized() == false) clear();
+ else if (initialized() == false && rhs.initialized() == true) initialize(*rhs);
+ else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs;
+ return *this;
+ }
+
+ optional& operator=(optional&& rhs)
+ noexcept(::std::is_nothrow_move_assignable<T>::value && ::std::is_nothrow_move_constructible<T>::value)
+ {
+ if (initialized() == true && rhs.initialized() == false) clear();
+ else if (initialized() == false && rhs.initialized() == true) initialize(::std::move(*rhs));
+ else if (initialized() == true && rhs.initialized() == true) contained_val() = ::std::move(*rhs);
+ return *this;
+ }
+
+ template <class U>
+ auto operator=(U&& v)
+ -> typename ::std::enable_if
+ <
+ ::std::is_same<typename ::std::decay<U>::type, T>::value,
+ optional&
+ >::type
+ {
+ if (initialized()) { contained_val() = ::std::forward<U>(v); }
+ else { initialize(::std::forward<U>(v)); }
+ return *this;
+ }
+
+ template <class... Args>
+ void emplace(Args&&... args)
+ {
+ clear();
+ initialize(::std::forward<Args>(args)...);
+ }
+
+ template <class U, class... Args>
+ void emplace(::std::initializer_list<U> il, Args&&... args)
+ {
+ clear();
+ initialize<U, Args...>(il, ::std::forward<Args>(args)...);
+ }
+
+ // 20.5.4.4, Swap
+ void swap(optional<T>& rhs) noexcept(::std::is_nothrow_move_constructible<T>::value && noexcept(swap(::std::declval<T&>(), ::std::declval<T&>())))
+ {
+ if (initialized() == true && rhs.initialized() == false) { rhs.initialize(::std::move(**this)); clear(); }
+ else if (initialized() == false && rhs.initialized() == true) { initialize(::std::move(*rhs)); rhs.clear(); }
+ else if (initialized() == true && rhs.initialized() == true) { using ::std::swap; swap(**this, *rhs); }
+ }
+
+ // 20.5.4.5, Observers
+
+ explicit constexpr operator bool() const noexcept { return initialized(); }
+
+ constexpr T const* operator ->() const {
+ return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr());
+ }
+
+# if OPTIONAL_HAS_MOVE_ACCESSORS == 1
+
+ OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() {
+ assert(initialized());
+ return dataptr();
+ }
+
+ constexpr T const& operator *() const& {
+ return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val());
+ }
+
+ OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & {
+ assert(initialized());
+ return contained_val();
+ }
+
+ OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && {
+ assert(initialized());
+ return constexpr_move(contained_val());
+ }
+
+ constexpr T const& value() const& {
+ return initialized() ?
+ contained_val()
+#ifdef SOL_NO_EXCEPTIONS
+ // we can't abort here
+ // because there's no constexpr abort
+ : *(T*)nullptr;
+#else
+ : (throw bad_optional_access("bad optional access"), contained_val());
+#endif
+ }
+
+ OPTIONAL_MUTABLE_CONSTEXPR T& value() & {
+ return initialized() ?
+ contained_val()
+#ifdef SOL_NO_EXCEPTIONS
+ : *(T*)nullptr;
+#else
+ : (throw bad_optional_access("bad optional access"), contained_val());
+#endif
+ }
+
+ OPTIONAL_MUTABLE_CONSTEXPR T&& value() && {
+ return initialized() ?
+ contained_val()
+#ifdef SOL_NO_EXCEPTIONS
+ // we can't abort here
+ // because there's no constexpr abort
+ : std::move(*(T*)nullptr);
+#else
+ : (throw bad_optional_access("bad optional access"), contained_val());
+#endif
+ }
+
+# else
+
+ T* operator ->() {
+ assert(initialized());
+ return dataptr();
+ }
+
+ constexpr T const& operator *() const {
+ return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val());
+ }
+
+ T& operator *() {
+ assert(initialized());
+ return contained_val();
+ }
+
+ constexpr T const& value() const {
+ return initialized() ?
+ contained_val()
+#ifdef SOL_NO_EXCEPTIONS
+ // we can't abort here
+ // because there's no constexpr abort
+ : *(T*)nullptr;
+#else
+ : (throw bad_optional_access("bad optional access"), contained_val());
+#endif
+ }
+
+ T& value() {
+ return initialized() ?
+ contained_val()
+#ifdef SOL_NO_EXCEPTIONS
+ // we can abort here
+ // but the others are constexpr, so we can't...
+ : (std::abort(), *(T*)nullptr);
+#else
+ : (throw bad_optional_access("bad optional access"), contained_val());
+#endif
+ }
+
+# endif
+
+# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1
+
+ template <class V>
+ constexpr T value_or(V&& v) const&
+ {
+ return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v));
+ }
+
+# if OPTIONAL_HAS_MOVE_ACCESSORS == 1
+
+ template <class V>
+ OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) &&
+ {
+ return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v));
+ }
+
+# else
+
+ template <class V>
+ T value_or(V&& v) &&
+ {
+ return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v));
+ }
+
+# endif
+
+# else
+
+ template <class V>
+ constexpr T value_or(V&& v) const
+ {
+ return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v));
+ }
+
+# endif
+
+ };
+
+ template <class T>
+ class optional<T&>
+ {
+ static_assert(!::std::is_same<T, nullopt_t>::value, "bad T");
+ static_assert(!::std::is_same<T, in_place_t>::value, "bad T");
+ T* ref;
+
+ public:
+
+ // 20.5.5.1, construction/destruction
+ constexpr optional() noexcept : ref(nullptr) {}
+
+ constexpr optional(nullopt_t) noexcept : ref(nullptr) {}
+
+ constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {}
+
+ optional(T&&) = delete;
+
+ constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {}
+
+ explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {}
+
+ explicit optional(in_place_t, T&&) = delete;
+
+ ~optional() = default;
+
+ // 20.5.5.2, mutation
+ optional& operator=(nullopt_t) noexcept {
+ ref = nullptr;
+ return *this;
+ }
+
+ // optional& operator=(const optional& rhs) noexcept {
+ // ref = rhs.ref;
+ // return *this;
+ // }
+
+ // optional& operator=(optional&& rhs) noexcept {
+ // ref = rhs.ref;
+ // return *this;
+ // }
+
+ template <typename U>
+ auto operator=(U&& rhs) noexcept
+ -> typename ::std::enable_if
+ <
+ ::std::is_same<typename ::std::decay<U>::type, optional<T&>>::value,
+ optional&
+ >::type
+ {
+ ref = rhs.ref;
+ return *this;
+ }
+
+ template <typename U>
+ auto operator=(U&& rhs) noexcept
+ -> typename ::std::enable_if
+ <
+ !::std::is_same<typename ::std::decay<U>::type, optional<T&>>::value,
+ optional&
+ >::type
+ = delete;
+
+ void emplace(T& v) noexcept {
+ ref = detail_::static_addressof(v);
+ }
+
+ void emplace(T&&) = delete;
+
+ void swap(optional<T&>& rhs) noexcept
+ {
+ ::std::swap(ref, rhs.ref);
+ }
+
+ // 20.5.5.3, observers
+ constexpr T* operator->() const {
+ return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref);
+ }
+
+ constexpr T& operator*() const {
+ return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref);
+ }
+
+ constexpr T& value() const {
+#ifdef SOL_NO_EXCEPTIONS
+ return *ref;
+#else
+ return ref ? *ref
+ : (throw bad_optional_access("bad optional access"), *ref);
+#endif // Exceptions
+ }
+
+ explicit constexpr operator bool() const noexcept {
+ return ref != nullptr;
+ }
+
+ template <typename V>
+ constexpr T& value_or(V&& v) const
+ {
+ return *this ? **this : detail_::convert<T&>(constexpr_forward<V>(v));
+ }
+ };
+
+ template <class T>
+ class optional<T&&>
+ {
+ static_assert(sizeof(T) == 0, "optional rvalue references disallowed");
+ };
+
+ // 20.5.8, Relational operators
+ template <class T> constexpr bool operator==(const optional<T>& x, const optional<T>& y)
+ {
+ return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y;
+ }
+
+ template <class T> constexpr bool operator!=(const optional<T>& x, const optional<T>& y)
+ {
+ return !(x == y);
+ }
+
+ template <class T> constexpr bool operator<(const optional<T>& x, const optional<T>& y)
+ {
+ return (!y) ? false : (!x) ? true : *x < *y;
+ }
+
+ template <class T> constexpr bool operator>(const optional<T>& x, const optional<T>& y)
+ {
+ return (y < x);
+ }
+
+ template <class T> constexpr bool operator<=(const optional<T>& x, const optional<T>& y)
+ {
+ return !(y < x);
+ }
+
+ template <class T> constexpr bool operator>=(const optional<T>& x, const optional<T>& y)
+ {
+ return !(x < y);
+ }
+
+ // 20.5.9, Comparison with nullopt
+ template <class T> constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept
+ {
+ return (!x);
+ }
+
+ template <class T> constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept
+ {
+ return (!x);
+ }
+
+ template <class T> constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept
+ {
+ return bool(x);
+ }
+
+ template <class T> constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept
+ {
+ return bool(x);
+ }
+
+ template <class T> constexpr bool operator<(const optional<T>&, nullopt_t) noexcept
+ {
+ return false;
+ }
+
+ template <class T> constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept
+ {
+ return bool(x);
+ }
+
+ template <class T> constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept
+ {
+ return (!x);
+ }
+
+ template <class T> constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept
+ {
+ return true;
+ }
+
+ template <class T> constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept
+ {
+ return bool(x);
+ }
+
+ template <class T> constexpr bool operator>(nullopt_t, const optional<T>&) noexcept
+ {
+ return false;
+ }
+
+ template <class T> constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept
+ {
+ return true;
+ }
+
+ template <class T> constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept
+ {
+ return (!x);
+ }
+
+ // 20.5.10, Comparison with T
+ template <class T> constexpr bool operator==(const optional<T>& x, const T& v)
+ {
+ return bool(x) ? *x == v : false;
+ }
+
+ template <class T> constexpr bool operator==(const T& v, const optional<T>& x)
+ {
+ return bool(x) ? v == *x : false;
+ }
+
+ template <class T> constexpr bool operator!=(const optional<T>& x, const T& v)
+ {
+ return bool(x) ? *x != v : true;
+ }
+
+ template <class T> constexpr bool operator!=(const T& v, const optional<T>& x)
+ {
+ return bool(x) ? v != *x : true;
+ }
+
+ template <class T> constexpr bool operator<(const optional<T>& x, const T& v)
+ {
+ return bool(x) ? *x < v : true;
+ }
+
+ template <class T> constexpr bool operator>(const T& v, const optional<T>& x)
+ {
+ return bool(x) ? v > *x : true;
+ }
+
+ template <class T> constexpr bool operator>(const optional<T>& x, const T& v)
+ {
+ return bool(x) ? *x > v : false;
+ }
+
+ template <class T> constexpr bool operator<(const T& v, const optional<T>& x)
+ {
+ return bool(x) ? v < *x : false;
+ }
+
+ template <class T> constexpr bool operator>=(const optional<T>& x, const T& v)
+ {
+ return bool(x) ? *x >= v : false;
+ }
+
+ template <class T> constexpr bool operator<=(const T& v, const optional<T>& x)
+ {
+ return bool(x) ? v <= *x : false;
+ }
+
+ template <class T> constexpr bool operator<=(const optional<T>& x, const T& v)
+ {
+ return bool(x) ? *x <= v : true;
+ }
+
+ template <class T> constexpr bool operator>=(const T& v, const optional<T>& x)
+ {
+ return bool(x) ? v >= *x : true;
+ }
+
+ // Comparison of optional<T&> with T
+ template <class T> constexpr bool operator==(const optional<T&>& x, const T& v)
+ {
+ return bool(x) ? *x == v : false;
+ }
+
+ template <class T> constexpr bool operator==(const T& v, const optional<T&>& x)
+ {
+ return bool(x) ? v == *x : false;
+ }
+
+ template <class T> constexpr bool operator!=(const optional<T&>& x, const T& v)
+ {
+ return bool(x) ? *x != v : true;
+ }
+
+ template <class T> constexpr bool operator!=(const T& v, const optional<T&>& x)
+ {
+ return bool(x) ? v != *x : true;
+ }
+
+ template <class T> constexpr bool operator<(const optional<T&>& x, const T& v)
+ {
+ return bool(x) ? *x < v : true;
+ }
+
+ template <class T> constexpr bool operator>(const T& v, const optional<T&>& x)
+ {
+ return bool(x) ? v > *x : true;
+ }
+
+ template <class T> constexpr bool operator>(const optional<T&>& x, const T& v)
+ {
+ return bool(x) ? *x > v : false;
+ }
+
+ template <class T> constexpr bool operator<(const T& v, const optional<T&>& x)
+ {
+ return bool(x) ? v < *x : false;
+ }
+
+ template <class T> constexpr bool operator>=(const optional<T&>& x, const T& v)
+ {
+ return bool(x) ? *x >= v : false;
+ }
+
+ template <class T> constexpr bool operator<=(const T& v, const optional<T&>& x)
+ {
+ return bool(x) ? v <= *x : false;
+ }
+
+ template <class T> constexpr bool operator<=(const optional<T&>& x, const T& v)
+ {
+ return bool(x) ? *x <= v : true;
+ }
+
+ template <class T> constexpr bool operator>=(const T& v, const optional<T&>& x)
+ {
+ return bool(x) ? v >= *x : true;
+ }
+
+ // Comparison of optional<T const&> with T
+ template <class T> constexpr bool operator==(const optional<const T&>& x, const T& v)
+ {
+ return bool(x) ? *x == v : false;
+ }
+
+ template <class T> constexpr bool operator==(const T& v, const optional<const T&>& x)
+ {
+ return bool(x) ? v == *x : false;
+ }
+
+ template <class T> constexpr bool operator!=(const optional<const T&>& x, const T& v)
+ {
+ return bool(x) ? *x != v : true;
+ }
+
+ template <class T> constexpr bool operator!=(const T& v, const optional<const T&>& x)
+ {
+ return bool(x) ? v != *x : true;
+ }
+
+ template <class T> constexpr bool operator<(const optional<const T&>& x, const T& v)
+ {
+ return bool(x) ? *x < v : true;
+ }
+
+ template <class T> constexpr bool operator>(const T& v, const optional<const T&>& x)
+ {
+ return bool(x) ? v > *x : true;
+ }
+
+ template <class T> constexpr bool operator>(const optional<const T&>& x, const T& v)
+ {
+ return bool(x) ? *x > v : false;
+ }
+
+ template <class T> constexpr bool operator<(const T& v, const optional<const T&>& x)
+ {
+ return bool(x) ? v < *x : false;
+ }
+
+ template <class T> constexpr bool operator>=(const optional<const T&>& x, const T& v)
+ {
+ return bool(x) ? *x >= v : false;
+ }
+
+ template <class T> constexpr bool operator<=(const T& v, const optional<const T&>& x)
+ {
+ return bool(x) ? v <= *x : false;
+ }
+
+ template <class T> constexpr bool operator<=(const optional<const T&>& x, const T& v)
+ {
+ return bool(x) ? *x <= v : true;
+ }
+
+ template <class T> constexpr bool operator>=(const T& v, const optional<const T&>& x)
+ {
+ return bool(x) ? v >= *x : true;
+ }
+
+ // 20.5.12, Specialized algorithms
+ template <class T>
+ void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y))) {
+ x.swap(y);
+ }
+
+ template <class T>
+ constexpr optional<typename ::std::decay<T>::type> make_optional(T&& v) {
+ return optional<typename ::std::decay<T>::type>(constexpr_forward<T>(v));
+ }
+
+ template <class X>
+ constexpr optional<X&> make_optional(::std::reference_wrapper<X> v) {
+ return optional<X&>(v.get());
+ }
+
+} // namespace
+
+namespace std
+{
+ template <typename T>
+ struct hash<sol::optional<T>> {
+ typedef typename hash<T>::result_type result_type;
+ typedef sol::optional<T> argument_type;
+
+ constexpr result_type operator()(argument_type const& arg) const {
+ return arg ? ::std::hash<T>{}(*arg) : result_type{};
+ }
+ };
+
+ template <typename T>
+ struct hash<sol::optional<T&>> {
+ typedef typename hash<T>::result_type result_type;
+ typedef sol::optional<T&> argument_type;
+
+ constexpr result_type operator()(argument_type const& arg) const {
+ return arg ? ::std::hash<T>{}(*arg) : result_type{};
+ }
+ };
+}
+
+# if defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___
+#pragma warning( pop )
+#endif
+
+# undef TR2_OPTIONAL_REQUIRES
+# undef TR2_OPTIONAL_ASSERTED_EXPRESSION
+
+# endif // SOL_OPTIONAL_IMPLEMENTATION_HPP
+// end of sol/optional_implementation.hpp
+
+#endif // Boost vs. Better optional
+
+namespace sol {
+
+#if defined(SOL_USE_BOOST)
+ template <typename T>
+ using optional = boost::optional<T>;
+ using nullopt_t = boost::none_t;
+ const nullopt_t nullopt = boost::none;
+#endif // Boost vs. Better optional
+
+} // sol
+
+// end of sol/optional.hpp
+
+// beginning of sol/string_shim.hpp
+
+namespace sol {
+ namespace string_detail {
+ struct string_shim {
+ std::size_t s;
+ const char* p;
+
+ string_shim(const std::string& r) : string_shim(r.data(), r.size()) {}
+ string_shim(const char* ptr) : string_shim(ptr, std::char_traits<char>::length(ptr)) {}
+ string_shim(const char* ptr, std::size_t sz) : s(sz), p(ptr) {}
+
+ static int compare(const char* lhs_p, std::size_t lhs_sz, const char* rhs_p, std::size_t rhs_sz) {
+ int result = std::char_traits<char>::compare(lhs_p, rhs_p, lhs_sz < rhs_sz ? lhs_sz : rhs_sz);
+ if (result != 0)
+ return result;
+ if (lhs_sz < rhs_sz)
+ return -1;
+ if (lhs_sz > rhs_sz)
+ return 1;
+ return 0;
+ }
+
+ const char* c_str() const {
+ return p;
+ }
+
+ const char* data() const {
+ return p;
+ }
+
+ std::size_t size() const {
+ return s;
+ }
+
+ bool operator==(const string_shim& r) const {
+ return compare(p, s, r.data(), r.size()) == 0;
+ }
+
+ bool operator==(const char* r) const {
+ return compare(r, std::char_traits<char>::length(r), p, s) == 0;
+ }
+
+ bool operator==(const std::string& r) const {
+ return compare(r.data(), r.size(), p, s) == 0;
+ }
+
+ bool operator!=(const string_shim& r) const {
+ return !(*this == r);
+ }
+
+ bool operator!=(const char* r) const {
+ return !(*this == r);
+ }
+
+ bool operator!=(const std::string& r) const {
+ return !(*this == r);
+ }
+ };
+ }
+}
+
+// end of sol/string_shim.hpp
+
+#include <array>
+
+namespace sol {
+ namespace detail {
+#ifdef SOL_NO_EXCEPTIONS
+ template <lua_CFunction f>
+ int static_trampoline(lua_State* L) {
+ return f(L);
+ }
+
+ template <typename Fx, typename... Args>
+ int trampoline(lua_State* L, Fx&& f, Args&&... args) {
+ return f(L, std::forward<Args>(args)...);
+ }
+
+ inline int c_trampoline(lua_State* L, lua_CFunction f) {
+ return trampoline(L, f);
+ }
+#else
+ template <lua_CFunction f>
+ int static_trampoline(lua_State* L) {
+ try {
+ return f(L);
+ }
+ catch (const char *s) {
+ lua_pushstring(L, s);
+ }
+ catch (const std::exception& e) {
+ lua_pushstring(L, e.what());
+ }
+#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
+ catch (...) {
+ lua_pushstring(L, "caught (...) exception");
+ }
+#endif
+ return lua_error(L);
+ }
+
+ template <typename Fx, typename... Args>
+ int trampoline(lua_State* L, Fx&& f, Args&&... args) {
+ try {
+ return f(L, std::forward<Args>(args)...);
+ }
+ catch (const char *s) {
+ lua_pushstring(L, s);
+ }
+ catch (const std::exception& e) {
+ lua_pushstring(L, e.what());
+ }
+#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
+ catch (...) {
+ lua_pushstring(L, "caught (...) exception");
+ }
+#endif
+ return lua_error(L);
+ }
+
+ inline int c_trampoline(lua_State* L, lua_CFunction f) {
+ return trampoline(L, f);
+ }
+#endif // Exceptions vs. No Exceptions
+
+ template <typename T>
+ struct unique_usertype {};
+
+ template <typename T>
+ struct implicit_wrapper {
+ T& item;
+ implicit_wrapper(T* item) : item(*item) {}
+ implicit_wrapper(T& item) : item(item) {}
+ operator T& () {
+ return item;
+ }
+ operator T* () {
+ return std::addressof(item);
+ }
+ };
+ } // detail
+
+ struct lua_nil_t {};
+ const lua_nil_t lua_nil{};
+ inline bool operator==(lua_nil_t, lua_nil_t) { return true; }
+ inline bool operator!=(lua_nil_t, lua_nil_t) { return false; }
+#ifndef __OBJC__
+ typedef lua_nil_t nil_t;
+ const nil_t nil{};
+#endif
+
+ struct metatable_key_t {};
+ const metatable_key_t metatable_key = {};
+
+ struct no_metatable_t {};
+ const no_metatable_t no_metatable = {};
+
+ typedef std::remove_pointer_t<lua_CFunction> lua_r_CFunction;
+
+ template <typename T>
+ struct unique_usertype_traits {
+ typedef T type;
+ typedef T actual_type;
+ static const bool value = false;
+
+ template <typename U>
+ static bool is_null(U&&) {
+ return false;
+ }
+
+ template <typename U>
+ static auto get(U&& value) {
+ return std::addressof(detail::deref(value));
+ }
+ };
+
+ template <typename T>
+ struct unique_usertype_traits<std::shared_ptr<T>> {
+ typedef T type;
+ typedef std::shared_ptr<T> actual_type;
+ static const bool value = true;
+
+ static bool is_null(const actual_type& p) {
+ return p == nullptr;
+ }
+
+ static type* get(const actual_type& p) {
+ return p.get();
+ }
+ };
+
+ template <typename T, typename D>
+ struct unique_usertype_traits<std::unique_ptr<T, D>> {
+ typedef T type;
+ typedef std::unique_ptr<T, D> actual_type;
+ static const bool value = true;
+
+ static bool is_null(const actual_type& p) {
+ return p == nullptr;
+ }
+
+ static type* get(const actual_type& p) {
+ return p.get();
+ }
+ };
+
+ template <typename T>
+ struct non_null {};
+
+ template <typename... Args>
+ struct function_sig {};
+
+ struct upvalue_index {
+ int index;
+ upvalue_index(int idx) : index(lua_upvalueindex(idx)) {}
+ operator int() const { return index; }
+ };
+
+ struct raw_index {
+ int index;
+ raw_index(int i) : index(i) {}
+ operator int() const { return index; }
+ };
+
+ struct absolute_index {
+ int index;
+ absolute_index(lua_State* L, int idx) : index(lua_absindex(L, idx)) {}
+ operator int() const { return index; }
+ };
+
+ struct ref_index {
+ int index;
+ ref_index(int idx) : index(idx) {}
+ operator int() const { return index; }
+ };
+
+ struct lightuserdata_value {
+ void* value;
+ lightuserdata_value(void* data) : value(data) {}
+ operator void*() const { return value; }
+ };
+
+ struct userdata_value {
+ void* value;
+ userdata_value(void* data) : value(data) {}
+ operator void*() const { return value; }
+ };
+
+ template <typename L>
+ struct light {
+ L* value;
+
+ light(L& x) : value(std::addressof(x)) {}
+ light(L* x) : value(x) {}
+ light(void* x) : value(static_cast<L*>(x)) {}
+ operator L* () const { return value; }
+ operator L& () const { return *value; }
+ };
+
+ template <typename T>
+ auto make_light(T& l) {
+ typedef meta::unwrapped_t<std::remove_pointer_t<std::remove_pointer_t<T>>> L;
+ return light<L>(l);
+ }
+
+ template <typename U>
+ struct user {
+ U value;
+
+ user(U x) : value(std::move(x)) {}
+ operator U* () { return std::addressof(value); }
+ operator U& () { return value; }
+ operator const U& () const { return value; }
+ };
+
+ template <typename T>
+ auto make_user(T&& u) {
+ typedef meta::unwrapped_t<meta::unqualified_t<T>> U;
+ return user<U>(std::forward<T>(u));
+ }
+
+ template <typename T>
+ struct metatable_registry_key {
+ T key;
+
+ metatable_registry_key(T key) : key(std::forward<T>(key)) {}
+ };
+
+ template <typename T>
+ auto meta_registry_key(T&& key) {
+ typedef meta::unqualified_t<T> K;
+ return metatable_registry_key<K>(std::forward<T>(key));
+ }
+
+ template <typename... Upvalues>
+ struct closure {
+ lua_CFunction c_function;
+ std::tuple<Upvalues...> upvalues;
+ closure(lua_CFunction f, Upvalues... targetupvalues) : c_function(f), upvalues(std::forward<Upvalues>(targetupvalues)...) {}
+ };
+
+ template <>
+ struct closure<> {
+ lua_CFunction c_function;
+ int upvalues;
+ closure(lua_CFunction f, int upvalue_count = 0) : c_function(f), upvalues(upvalue_count) {}
+ };
+
+ typedef closure<> c_closure;
+
+ template <typename... Args>
+ closure<Args...> make_closure(lua_CFunction f, Args&&... args) {
+ return closure<Args...>(f, std::forward<Args>(args)...);
+ }
+
+ template <typename Sig, typename... Ps>
+ struct function_arguments {
+ std::tuple<Ps...> arguments;
+ template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, function_arguments>> = meta::enabler>
+ function_arguments(Arg&& arg, Args&&... args) : arguments(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
+ };
+
+ template <typename Sig = function_sig<>, typename... Args>
+ auto as_function(Args&&... args) {
+ return function_arguments<Sig, std::decay_t<Args>...>(std::forward<Args>(args)...);
+ }
+
+ template <typename Sig = function_sig<>, typename... Args>
+ auto as_function_reference(Args&&... args) {
+ return function_arguments<Sig, Args...>(std::forward<Args>(args)...);
+ }
+
+ template <typename T>
+ struct as_table_t {
+ T source;
+ template <typename... Args>
+ as_table_t(Args&&... args) : source(std::forward<Args>(args)...) {}
+
+ operator std::add_lvalue_reference_t<T> () {
+ return source;
+ }
+ };
+
+ template <typename T>
+ as_table_t<T> as_table(T&& container) {
+ return as_table_t<T>(std::forward<T>(container));
+ }
+
+ struct this_state {
+ lua_State* L;
+ operator lua_State* () const {
+ return L;
+ }
+ lua_State* operator-> () const {
+ return L;
+ }
+ };
+
+ enum class call_syntax {
+ dot = 0,
+ colon = 1
+ };
+
+ enum class call_status : int {
+ ok = LUA_OK,
+ yielded = LUA_YIELD,
+ runtime = LUA_ERRRUN,
+ memory = LUA_ERRMEM,
+ handler = LUA_ERRERR,
+ gc = LUA_ERRGCMM
+ };
+
+ enum class thread_status : int {
+ ok = LUA_OK,
+ yielded = LUA_YIELD,
+ runtime = LUA_ERRRUN,
+ memory = LUA_ERRMEM,
+ gc = LUA_ERRGCMM,
+ handler = LUA_ERRERR,
+ dead = -1,
+ };
+
+ enum class load_status : int {
+ ok = LUA_OK,
+ syntax = LUA_ERRSYNTAX,
+ memory = LUA_ERRMEM,
+ gc = LUA_ERRGCMM,
+ file = LUA_ERRFILE,
+ };
+
+ enum class type : int {
+ none = LUA_TNONE,
+ lua_nil = LUA_TNIL,
+#ifndef __OBJC__
+ nil = lua_nil,
+#endif // Objective C++ Keyword
+ string = LUA_TSTRING,
+ number = LUA_TNUMBER,
+ thread = LUA_TTHREAD,
+ boolean = LUA_TBOOLEAN,
+ function = LUA_TFUNCTION,
+ userdata = LUA_TUSERDATA,
+ lightuserdata = LUA_TLIGHTUSERDATA,
+ table = LUA_TTABLE,
+ poly = none | lua_nil | string | number | thread |
+ table | boolean | function | userdata | lightuserdata
+ };
+
+ enum class meta_function {
+ construct,
+ index,
+ new_index,
+ mode,
+ call,
+ call_function = call,
+ metatable,
+ to_string,
+ length,
+ unary_minus,
+ addition,
+ subtraction,
+ multiplication,
+ division,
+ modulus,
+ power_of,
+ involution = power_of,
+ concatenation,
+ equal_to,
+ less_than,
+ less_than_or_equal_to,
+ garbage_collect,
+ floor_division,
+ bitwise_left_shift,
+ bitwise_right_shift,
+ bitwise_not,
+ bitwise_and,
+ bitwise_or,
+ bitwise_xor,
+ pairs,
+ next
+ };
+
+ typedef meta_function meta_method;
+
+ const std::array<std::string, 2> meta_variable_names = { {
+ "__index",
+ "__newindex",
+ } };
+
+ const std::array<std::string, 29> meta_function_names = { {
+ "new",
+ "__index",
+ "__newindex",
+ "__mode",
+ "__call",
+ "__mt",
+ "__tostring",
+ "__len",
+ "__unm",
+ "__add",
+ "__sub",
+ "__mul",
+ "__div",
+ "__mod",
+ "__pow",
+ "__concat",
+ "__eq",
+ "__lt",
+ "__le",
+ "__gc",
+
+ "__idiv",
+ "__shl",
+ "__shr",
+ "__bnot",
+ "__band",
+ "__bor",
+ "__bxor",
+
+ "__pairs",
+ "__next"
+ } };
+
+ inline const std::string& name_of(meta_function mf) {
+ return meta_function_names[static_cast<int>(mf)];
+ }
+
+ inline type type_of(lua_State* L, int index) {
+ return static_cast<type>(lua_type(L, index));
+ }
+
+ inline int type_panic(lua_State* L, int index, type expected, type actual) {
+ return luaL_error(L, "stack index %d, expected %s, received %s", index,
+ expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
+ expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(actual))
+ );
+ }
+
+ // Specify this function as the handler for lua::check if you know there's nothing wrong
+ inline int no_panic(lua_State*, int, type, type) noexcept {
+ return 0;
+ }
+
+ inline void type_error(lua_State* L, int expected, int actual) {
+ luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual));
+ }
+
+ inline void type_error(lua_State* L, type expected, type actual) {
+ type_error(L, static_cast<int>(expected), static_cast<int>(actual));
+ }
+
+ inline void type_assert(lua_State* L, int index, type expected, type actual) {
+ if (expected != type::poly && expected != actual) {
+ type_panic(L, index, expected, actual);
+ }
+ }
+
+ inline void type_assert(lua_State* L, int index, type expected) {
+ type actual = type_of(L, index);
+ type_assert(L, index, expected, actual);
+ }
+
+ inline std::string type_name(lua_State* L, type t) {
+ return lua_typename(L, static_cast<int>(t));
+ }
+
+ class reference;
+ class stack_reference;
+ template <typename Table, typename Key>
+ struct proxy;
+ template<typename T>
+ class usertype;
+ template <bool, typename T>
+ class basic_table_core;
+ template <bool b>
+ using table_core = basic_table_core<b, reference>;
+ template <bool b>
+ using stack_table_core = basic_table_core<b, stack_reference>;
+ typedef table_core<false> table;
+ typedef table_core<true> global_table;
+ typedef stack_table_core<false> stack_table;
+ typedef stack_table_core<true> stack_global_table;
+ template <typename T>
+ class basic_function;
+ template <typename T>
+ class basic_protected_function;
+ using protected_function = basic_protected_function<reference>;
+ using stack_protected_function = basic_protected_function<stack_reference>;
+ using unsafe_function = basic_function<reference>;
+ using safe_function = basic_protected_function<reference>;
+ using stack_unsafe_function = basic_function<stack_reference>;
+ using stack_safe_function = basic_protected_function<stack_reference>;
+#ifdef SOL_SAFE_FUNCTIONS
+ using function = protected_function;
+ using stack_function = stack_protected_function;
+#else
+ using function = unsafe_function;
+ using stack_function = stack_unsafe_function;
+#endif
+ template <typename base_t>
+ class basic_object;
+ template <typename base_t>
+ class basic_userdata;
+ template <typename base_t>
+ class basic_lightuserdata;
+ struct variadic_args;
+ using object = basic_object<reference>;
+ using stack_object = basic_object<stack_reference>;
+ using userdata = basic_userdata<reference>;
+ using stack_userdata = basic_userdata<stack_reference>;
+ using lightuserdata = basic_lightuserdata<reference>;
+ using stack_lightuserdata = basic_lightuserdata<stack_reference>;
+ class coroutine;
+ class thread;
+ struct variadic_args;
+ struct this_state;
+
+ namespace detail {
+ template <typename T, typename = void>
+ struct lua_type_of : std::integral_constant<type, type::userdata> {};
+
+ template <>
+ struct lua_type_of<std::string> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<std::wstring> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<std::u16string> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<std::u32string> : std::integral_constant<type, type::string> {};
+
+ template <std::size_t N>
+ struct lua_type_of<char[N]> : std::integral_constant<type, type::string> {};
+
+ template <std::size_t N>
+ struct lua_type_of<wchar_t[N]> : std::integral_constant<type, type::string> {};
+
+ template <std::size_t N>
+ struct lua_type_of<char16_t[N]> : std::integral_constant<type, type::string> {};
+
+ template <std::size_t N>
+ struct lua_type_of<char32_t[N]> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<char> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<wchar_t> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<char16_t> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<char32_t> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<const char*> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<const char16_t*> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<const char32_t*> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<string_detail::string_shim> : std::integral_constant<type, type::string> {};
+
+ template <>
+ struct lua_type_of<bool> : std::integral_constant<type, type::boolean> {};
+
+ template <>
+ struct lua_type_of<lua_nil_t> : std::integral_constant<type, type::lua_nil> { };
+
+ template <>
+ struct lua_type_of<nullopt_t> : std::integral_constant<type, type::lua_nil> { };
+
+ template <>
+ struct lua_type_of<std::nullptr_t> : std::integral_constant<type, type::lua_nil> { };
+
+ template <>
+ struct lua_type_of<sol::error> : std::integral_constant<type, type::string> { };
+
+ template <bool b, typename Base>
+ struct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> { };
+
+ template <>
+ struct lua_type_of<reference> : std::integral_constant<type, type::poly> {};
+
+ template <>
+ struct lua_type_of<stack_reference> : std::integral_constant<type, type::poly> {};
+
+ template <typename Base>
+ struct lua_type_of<basic_object<Base>> : std::integral_constant<type, type::poly> {};
+
+ template <typename... Args>
+ struct lua_type_of<std::tuple<Args...>> : std::integral_constant<type, type::poly> {};
+
+ template <typename A, typename B>
+ struct lua_type_of<std::pair<A, B>> : std::integral_constant<type, type::poly> {};
+
+ template <>
+ struct lua_type_of<void*> : std::integral_constant<type, type::lightuserdata> {};
+
+ template <>
+ struct lua_type_of<lightuserdata_value> : std::integral_constant<type, type::lightuserdata> {};
+
+ template <>
+ struct lua_type_of<userdata_value> : std::integral_constant<type, type::userdata> {};
+
+ template <typename T>
+ struct lua_type_of<light<T>> : std::integral_constant<type, type::lightuserdata> {};
+
+ template <typename T>
+ struct lua_type_of<user<T>> : std::integral_constant<type, type::userdata> {};
+
+ template <typename Base>
+ struct lua_type_of<basic_lightuserdata<Base>> : std::integral_constant<type, type::lightuserdata> {};
+
+ template <typename Base>
+ struct lua_type_of<basic_userdata<Base>> : std::integral_constant<type, type::userdata> {};
+
+ template <>
+ struct lua_type_of<lua_CFunction> : std::integral_constant<type, type::function> {};
+
+ template <>
+ struct lua_type_of<std::remove_pointer_t<lua_CFunction>> : std::integral_constant<type, type::function> {};
+
+ template <typename Base>
+ struct lua_type_of<basic_function<Base>> : std::integral_constant<type, type::function> {};
+
+ template <typename Base>
+ struct lua_type_of<basic_protected_function<Base>> : std::integral_constant<type, type::function> {};
+
+ template <>
+ struct lua_type_of<coroutine> : std::integral_constant<type, type::function> {};
+
+ template <>
+ struct lua_type_of<thread> : std::integral_constant<type, type::thread> {};
+
+ template <typename Signature>
+ struct lua_type_of<std::function<Signature>> : std::integral_constant<type, type::function> {};
+
+ template <typename T>
+ struct lua_type_of<optional<T>> : std::integral_constant<type, type::poly> {};
+
+ template <>
+ struct lua_type_of<variadic_args> : std::integral_constant<type, type::poly> {};
+
+ template <>
+ struct lua_type_of<this_state> : std::integral_constant<type, type::poly> {};
+
+ template <>
+ struct lua_type_of<type> : std::integral_constant<type, type::poly> {};
+
+ template <typename T>
+ struct lua_type_of<T*> : std::integral_constant<type, type::userdata> {};
+
+ template <typename T>
+ struct lua_type_of<T, std::enable_if_t<std::is_arithmetic<T>::value>> : std::integral_constant<type, type::number> {};
+
+ template <typename T>
+ struct lua_type_of<T, std::enable_if_t<std::is_enum<T>::value>> : std::integral_constant<type, type::number> {};
+
+ template <typename T, typename C = void>
+ struct is_container : std::false_type {};
+
+ template <typename T>
+ struct is_container<T, std::enable_if_t<meta::has_begin_end<meta::unqualified_t<T>>::value>> : std::true_type {};
+
+ template <>
+ struct lua_type_of<meta_function> : std::integral_constant<type, type::string> {};
+
+ template <typename C, C v, template <typename...> class V, typename... Args>
+ struct accumulate : std::integral_constant<C, v> {};
+
+ template <typename C, C v, template <typename...> class V, typename T, typename... Args>
+ struct accumulate<C, v, V, T, Args...> : accumulate<C, v + V<T>::value, V, Args...> {};
+ } // detail
+
+ template <typename T>
+ struct is_unique_usertype : std::integral_constant<bool, unique_usertype_traits<T>::value> {};
+
+ template <typename T>
+ struct lua_type_of : detail::lua_type_of<T> {
+ typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_;
+ };
+
+ template <typename T>
+ struct lua_size : std::integral_constant<int, 1> {
+ typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_;
+ };
+
+ template <typename A, typename B>
+ struct lua_size<std::pair<A, B>> : std::integral_constant<int, lua_size<A>::value + lua_size<B>::value> { };
+
+ template <typename... Args>
+ struct lua_size<std::tuple<Args...>> : std::integral_constant<int, detail::accumulate<int, 0, lua_size, Args...>::value> { };
+
+ namespace detail {
+ template <typename...>
+ struct void_ { typedef void type; };
+ template <typename T, typename = void>
+ struct has_internal_marker_impl : std::false_type {};
+ template <typename T>
+ struct has_internal_marker_impl<T, typename void_<typename T::SOL_INTERNAL_UNSPECIALIZED_MARKER_>::type> : std::true_type {};
+
+ template <typename T>
+ struct has_internal_marker : has_internal_marker_impl<T> {};
+ }
+
+ template <typename T>
+ struct is_lua_primitive : std::integral_constant<bool,
+ type::userdata != lua_type_of<meta::unqualified_t<T>>::value
+ || ((type::userdata == lua_type_of<meta::unqualified_t<T>>::value)
+ && detail::has_internal_marker<lua_type_of<meta::unqualified_t<T>>>::value
+ && !detail::has_internal_marker<lua_size<meta::unqualified_t<T>>>::value)
+ || std::is_base_of<reference, meta::unqualified_t<T>>::value
+ || std::is_base_of<stack_reference, meta::unqualified_t<T>>::value
+ || meta::is_specialization_of<std::tuple, meta::unqualified_t<T>>::value
+ || meta::is_specialization_of<std::pair, meta::unqualified_t<T>>::value
+ > { };
+
+ template <typename T>
+ struct is_lua_reference : std::integral_constant<bool,
+ std::is_base_of<reference, meta::unqualified_t<T>>::value
+ || std::is_base_of<stack_reference, meta::unqualified_t<T>>::value
+ || meta::is_specialization_of<proxy, meta::unqualified_t<T>>::value
+ > { };
+
+ template <typename T>
+ struct is_lua_primitive<T*> : std::true_type {};
+ template <typename T>
+ struct is_lua_primitive<std::reference_wrapper<T>> : std::true_type { };
+ template <typename T>
+ struct is_lua_primitive<user<T>> : std::true_type { };
+ template <typename T>
+ struct is_lua_primitive<light<T>> : is_lua_primitive<T*> { };
+ template <typename T>
+ struct is_lua_primitive<optional<T>> : std::true_type {};
+ template <>
+ struct is_lua_primitive<userdata_value> : std::true_type {};
+ template <>
+ struct is_lua_primitive<lightuserdata_value> : std::true_type {};
+ template <typename T>
+ struct is_lua_primitive<non_null<T>> : is_lua_primitive<T*> {};
+
+ template <typename T>
+ struct is_proxy_primitive : is_lua_primitive<T> { };
+
+ template <typename T>
+ struct is_transparent_argument : std::false_type {};
+
+ template <>
+ struct is_transparent_argument<this_state> : std::true_type {};
+
+ template <>
+ struct is_transparent_argument<variadic_args> : std::true_type {};
+
+ template <typename T>
+ struct is_variadic_arguments : std::is_same<T, variadic_args> {};
+
+ template <typename Signature>
+ struct lua_bind_traits : meta::bind_traits<Signature> {
+ private:
+ typedef meta::bind_traits<Signature> base_t;
+ public:
+ typedef std::integral_constant<bool, meta::count_for<is_transparent_argument, typename base_t::args_list>::value != 0> runtime_variadics_t;
+ static const std::size_t true_arity = base_t::arity;
+ static const std::size_t arity = base_t::arity - meta::count_for<is_transparent_argument, typename base_t::args_list>::value;
+ static const std::size_t true_free_arity = base_t::free_arity;
+ static const std::size_t free_arity = base_t::free_arity - meta::count_for<is_transparent_argument, typename base_t::args_list>::value;
+ };
+
+ template <typename T>
+ struct is_table : std::false_type {};
+ template <bool x, typename T>
+ struct is_table<basic_table_core<x, T>> : std::true_type {};
+
+ template <typename T>
+ struct is_function : std::false_type {};
+ template <typename T>
+ struct is_function<basic_function<T>> : std::true_type {};
+ template <typename T>
+ struct is_function<basic_protected_function<T>> : std::true_type {};
+
+ template <typename T>
+ struct is_lightuserdata : std::false_type {};
+ template <typename T>
+ struct is_lightuserdata<basic_lightuserdata<T>> : std::true_type {};
+
+ template <typename T>
+ struct is_userdata : std::false_type {};
+ template <typename T>
+ struct is_userdata<basic_userdata<T>> : std::true_type {};
+
+ template <typename T>
+ struct is_container : detail::is_container<T>{};
+
+ template<typename T>
+ inline type type_of() {
+ return lua_type_of<meta::unqualified_t<T>>::value;
+ }
+} // sol
+
+// end of sol/types.hpp
+
+// beginning of sol/stack_reference.hpp
+
+namespace sol {
+ class stack_reference {
+ private:
+ lua_State* L = nullptr;
+ int index = 0;
+
+ protected:
+ int registry_index() const noexcept {
+ return LUA_NOREF;
+ }
+
+ public:
+ stack_reference() noexcept = default;
+ stack_reference(lua_nil_t) noexcept : stack_reference() {};
+ stack_reference(lua_State* L, int i) noexcept : L(L), index(lua_absindex(L, i)) {}
+ stack_reference(lua_State* L, absolute_index i) noexcept : L(L), index(i) {}
+ stack_reference(lua_State* L, raw_index i) noexcept : L(L), index(i) {}
+ stack_reference(lua_State* L, ref_index i) noexcept = delete;
+ stack_reference(stack_reference&& o) noexcept = default;
+ stack_reference& operator=(stack_reference&&) noexcept = default;
+ stack_reference(const stack_reference&) noexcept = default;
+ stack_reference& operator=(const stack_reference&) noexcept = default;
+
+ int push() const noexcept {
+ return push(lua_state());
+ }
+
+ int push(lua_State* Ls) const noexcept {
+ lua_pushvalue(lua_state(), index);
+ if (Ls != lua_state()) {
+ lua_xmove(lua_state(), Ls, 1);
+ }
+ return 1;
+ }
+
+ void pop() const noexcept {
+ pop(lua_state());
+ }
+
+ void pop(lua_State* Ls, int n = 1) const noexcept {
+ lua_pop(Ls, n);
+ }
+
+ int stack_index() const noexcept {
+ return index;
+ }
+
+ type get_type() const noexcept {
+ int result = lua_type(L, index);
+ return static_cast<type>(result);
+ }
+
+ lua_State* lua_state() const noexcept {
+ return L;
+ }
+
+ bool valid() const noexcept {
+ type t = get_type();
+ return t != type::lua_nil && t != type::none;
+ }
+ };
+
+ inline bool operator== (const stack_reference& l, const stack_reference& r) {
+ return lua_compare(l.lua_state(), l.stack_index(), r.stack_index(), LUA_OPEQ) == 0;
+ }
+
+ inline bool operator!= (const stack_reference& l, const stack_reference& r) {
+ return !operator==(l, r);
+ }
+} // sol
+
+// end of sol/stack_reference.hpp
+
+namespace sol {
+ namespace stack {
+ template <bool top_level>
+ struct push_popper_n {
+ lua_State* L;
+ int t;
+ push_popper_n(lua_State* luastate, int x) : L(luastate), t(x) { }
+ ~push_popper_n() { lua_pop(L, t); }
+ };
+ template <>
+ struct push_popper_n<true> {
+ push_popper_n(lua_State*, int) { }
+ };
+ template <bool top_level, typename T>
+ struct push_popper {
+ T t;
+ push_popper(T x) : t(x) { t.push(); }
+ ~push_popper() { t.pop(); }
+ };
+ template <typename T>
+ struct push_popper<true, T> {
+ push_popper(T) {}
+ ~push_popper() {}
+ };
+ template <bool top_level = false, typename T>
+ push_popper<top_level, T> push_pop(T&& x) {
+ return push_popper<top_level, T>(std::forward<T>(x));
+ }
+ template <bool top_level = false>
+ push_popper_n<top_level> pop_n(lua_State* L, int x) {
+ return push_popper_n<top_level>(L, x);
+ }
+ } // stack
+
+ namespace detail {
+ struct global_tag { } const global_{};
+ } // detail
+
+ class reference {
+ private:
+ lua_State* luastate = nullptr; // non-owning
+ int ref = LUA_NOREF;
+
+ int copy() const noexcept {
+ if (ref == LUA_NOREF)
+ return LUA_NOREF;
+ push();
+ return luaL_ref(lua_state(), LUA_REGISTRYINDEX);
+ }
+
+ protected:
+ reference(lua_State* L, detail::global_tag) noexcept : luastate(L) {
+ lua_pushglobaltable(lua_state());
+ ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
+ }
+
+ int stack_index() const noexcept {
+ return -1;
+ }
+
+ void deref() const noexcept {
+ luaL_unref(lua_state(), LUA_REGISTRYINDEX, ref);
+ }
+
+ public:
+ reference() noexcept = default;
+ reference(lua_nil_t) noexcept : reference() {}
+ reference(const stack_reference& r) noexcept : reference(r.lua_state(), r.stack_index()) {}
+ reference(stack_reference&& r) noexcept : reference(r.lua_state(), r.stack_index()) {}
+ reference(lua_State* L, int index = -1) noexcept : luastate(L) {
+ lua_pushvalue(lua_state(), index);
+ ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
+ }
+ reference(lua_State* L, ref_index index) noexcept : luastate(L) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, index.index);
+ ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
+ }
+
+ ~reference() noexcept {
+ deref();
+ }
+
+ reference(reference&& o) noexcept {
+ luastate = o.luastate;
+ ref = o.ref;
+
+ o.luastate = nullptr;
+ o.ref = LUA_NOREF;
+ }
+
+ reference& operator=(reference&& o) noexcept {
+ if (valid()) {
+ deref();
+ }
+ luastate = o.luastate;
+ ref = o.ref;
+
+ o.luastate = nullptr;
+ o.ref = LUA_NOREF;
+
+ return *this;
+ }
+
+ reference(const reference& o) noexcept {
+ luastate = o.luastate;
+ ref = o.copy();
+ }
+
+ reference& operator=(const reference& o) noexcept {
+ luastate = o.luastate;
+ deref();
+ ref = o.copy();
+ return *this;
+ }
+
+ int push() const noexcept {
+ return push(lua_state());
+ }
+
+ int push(lua_State* Ls) const noexcept {
+ lua_rawgeti(Ls, LUA_REGISTRYINDEX, ref);
+ return 1;
+ }
+
+ void pop() const noexcept {
+ pop(lua_state());
+ }
+
+ void pop(lua_State* Ls, int n = 1) const noexcept {
+ lua_pop(Ls, n);
+ }
+
+ int registry_index() const noexcept {
+ return ref;
+ }
+
+ bool valid() const noexcept {
+ return !(ref == LUA_NOREF || ref == LUA_REFNIL);
+ }
+
+ explicit operator bool() const noexcept {
+ return valid();
+ }
+
+ type get_type() const noexcept {
+ auto pp = stack::push_pop(*this);
+ int result = lua_type(lua_state(), -1);
+ return static_cast<type>(result);
+ }
+
+ lua_State* lua_state() const noexcept {
+ return luastate;
+ }
+ };
+
+ inline bool operator== (const reference& l, const reference& r) {
+ auto ppl = stack::push_pop(l);
+ auto ppr = stack::push_pop(r);
+ return lua_compare(l.lua_state(), -1, -2, LUA_OPEQ) == 1;
+ }
+
+ inline bool operator!= (const reference& l, const reference& r) {
+ return !operator==(l, r);
+ }
+} // sol
+
+// end of sol/reference.hpp
+
+// beginning of sol/stack.hpp
+
+// beginning of sol/stack_core.hpp
+
+// beginning of sol/userdata.hpp
+
+namespace sol {
+ template <typename base_t>
+ class basic_userdata : public base_t {
+ public:
+ basic_userdata() noexcept = default;
+ template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_userdata>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_t, meta::unqualified_t<T>>> = meta::enabler>
+ basic_userdata(T&& r) noexcept : base_t(std::forward<T>(r)) {
+#ifdef SOL_CHECK_ARGUMENTS
+ if (!is_userdata<meta::unqualified_t<T>>::value) {
+ auto pp = stack::push_pop(*this);
+ type_assert(base_t::lua_state(), -1, type::userdata);
+ }
+#endif // Safety
+ }
+ basic_userdata(const basic_userdata&) = default;
+ basic_userdata(basic_userdata&&) = default;
+ basic_userdata& operator=(const basic_userdata&) = default;
+ basic_userdata& operator=(basic_userdata&&) = default;
+ basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
+ basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
+ template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler>
+ basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {}
+ basic_userdata(lua_State* L, int index = -1) : base_t(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ type_assert(L, index, type::userdata);
+#endif // Safety
+ }
+ basic_userdata(lua_State* L, ref_index index) : base_t(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ auto pp = stack::push_pop(*this);
+ type_assert(L, -1, type::userdata);
+#endif // Safety
+ }
+ };
+
+ template <typename base_t>
+ class basic_lightuserdata : public base_t {
+ public:
+ basic_lightuserdata() noexcept = default;
+ template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_lightuserdata>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_t, meta::unqualified_t<T>>> = meta::enabler>
+ basic_lightuserdata(T&& r) noexcept : base_t(std::forward<T>(r)) {
+#ifdef SOL_CHECK_ARGUMENTS
+ if (!is_userdata<meta::unqualified_t<T>>::value) {
+ auto pp = stack::push_pop(*this);
+ type_assert(base_t::lua_state(), -1, type::lightuserdata);
+ }
+#endif // Safety
+ }
+ basic_lightuserdata(const basic_lightuserdata&) = default;
+ basic_lightuserdata(basic_lightuserdata&&) = default;
+ basic_lightuserdata& operator=(const basic_lightuserdata&) = default;
+ basic_lightuserdata& operator=(basic_lightuserdata&&) = default;
+ basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
+ basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
+ template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler>
+ basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {}
+ basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ type_assert(L, index, type::lightuserdata);
+#endif // Safety
+ }
+ basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ auto pp = stack::push_pop(*this);
+ type_assert(L, -1, type::lightuserdata);
+#endif // Safety
+ }
+ };
+
+} // sol
+
+// end of sol/userdata.hpp
+
+// beginning of sol/tie.hpp
+
+namespace sol {
+
+ namespace detail {
+ template <typename T>
+ struct is_speshul : std::false_type {};
+ }
+
+ template <typename T>
+ struct tie_size : std::tuple_size<T> {};
+
+ template <typename T>
+ struct is_tieable : std::integral_constant<bool, (::sol::tie_size<T>::value > 0)> {};
+
+ template <typename... Tn>
+ struct tie_t : public std::tuple<std::add_lvalue_reference_t<Tn>...> {
+ private:
+ typedef std::tuple<std::add_lvalue_reference_t<Tn>...> base_t;
+
+ template <typename T>
+ void set(std::false_type, T&& target) {
+ std::get<0>(*this) = std::forward<T>(target);
+ }
+
+ template <typename T>
+ void set(std::true_type, T&& target) {
+ typedef tie_size<meta::unqualified_t<T>> value_size;
+ typedef tie_size<std::tuple<Tn...>> tie_size;
+ typedef std::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size;
+ typedef std::make_index_sequence<indices_size::value> indices;
+ set_extra(detail::is_speshul<meta::unqualified_t<T>>(), indices(), std::forward<T>(target));
+ }
+
+ template <std::size_t... I, typename T>
+ void set_extra(std::true_type, std::index_sequence<I...>, T&& target) {
+ using std::get;
+ (void)detail::swallow{ 0,
+ (get<I>(static_cast<base_t&>(*this)) = get<I>(types<Tn...>(), target), 0)...
+ , 0 };
+ }
+
+ template <std::size_t... I, typename T>
+ void set_extra(std::false_type, std::index_sequence<I...>, T&& target) {
+ using std::get;
+ (void)detail::swallow{ 0,
+ (get<I>(static_cast<base_t&>(*this)) = get<I>(target), 0)...
+ , 0 };
+ }
+
+ public:
+ using base_t::base_t;
+
+ template <typename T>
+ tie_t& operator= (T&& value) {
+ typedef is_tieable<meta::unqualified_t<T>> tieable;
+ set(tieable(), std::forward<T>(value));
+ return *this;
+ }
+
+ };
+
+ template <typename... Tn>
+ struct tie_size< tie_t<Tn...> > : std::tuple_size< std::tuple<Tn...> > { };
+
+ namespace adl_barrier_detail {
+ template <typename... Tn>
+ inline tie_t<std::remove_reference_t<Tn>...> tie(Tn&&... argn) {
+ return tie_t<std::remove_reference_t<Tn>...>(std::forward<Tn>(argn)...);
+ }
+ }
+
+ using namespace adl_barrier_detail;
+
+} // sol
+
+// end of sol/tie.hpp
+
+// beginning of sol/stack_guard.hpp
+
+namespace sol {
+ namespace detail {
+ inline void stack_fail(int, int) {
+#ifndef SOL_NO_EXCEPTIONS
+ throw error(detail::direct_error, "imbalanced stack after operation finish");
+#else
+ // Lol, what do you want, an error printout? :3c
+ // There's no sane default here. The right way would be C-style abort(), and that's not acceptable, so
+ // hopefully someone will register their own stack_fail thing for the `fx` parameter of stack_guard.
+#endif // No Exceptions
+ }
+ } // detail
+
+ struct stack_guard {
+ lua_State* L;
+ int top;
+ std::function<void(int, int)> on_mismatch;
+
+ stack_guard(lua_State* L) : stack_guard(L, lua_gettop(L)) {}
+ stack_guard(lua_State* L, int top, std::function<void(int, int)> fx = detail::stack_fail) : L(L), top(top), on_mismatch(std::move(fx)) {}
+ bool check_stack(int modification = 0) const {
+ int bottom = lua_gettop(L) + modification;
+ if (top == bottom) {
+ return true;
+ }
+ on_mismatch(top, bottom);
+ return false;
+ }
+ ~stack_guard() {
+ check_stack();
+ }
+ };
+} // sol
+
+// end of sol/stack_guard.hpp
+
+#include <vector>
+
+namespace sol {
+ namespace detail {
+ struct as_reference_tag {};
+ template <typename T>
+ struct as_pointer_tag {};
+ template <typename T>
+ struct as_value_tag {};
+
+ using special_destruct_func = void(*)(void*);
+
+ template <typename T, typename Real>
+ inline void special_destruct(void* memory) {
+ T** pointerpointer = static_cast<T**>(memory);
+ special_destruct_func* dx = static_cast<special_destruct_func*>(static_cast<void*>(pointerpointer + 1));
+ Real* target = static_cast<Real*>(static_cast<void*>(dx + 1));
+ target->~Real();
+ }
+
+ template <typename T>
+ inline int unique_destruct(lua_State* L) {
+ void* memory = lua_touserdata(L, 1);
+ T** pointerpointer = static_cast<T**>(memory);
+ special_destruct_func& dx = *static_cast<special_destruct_func*>(static_cast<void*>(pointerpointer + 1));
+ (dx)(memory);
+ return 0;
+ }
+
+ template <typename T>
+ inline int user_alloc_destroy(lua_State* L) {
+ void* rawdata = lua_touserdata(L, 1);
+ T* data = static_cast<T*>(rawdata);
+ std::allocator<T> alloc;
+ alloc.destroy(data);
+ return 0;
+ }
+
+ template <typename T>
+ inline int usertype_alloc_destroy(lua_State* L) {
+ void* rawdata = lua_touserdata(L, 1);
+ T** pdata = static_cast<T**>(rawdata);
+ T* data = *pdata;
+ std::allocator<T> alloc{};
+ alloc.destroy(data);
+ return 0;
+ }
+
+ template <typename T>
+ void reserve(T&, std::size_t) {}
+
+ template <typename T, typename Al>
+ void reserve(std::vector<T, Al>& arr, std::size_t hint) {
+ arr.reserve(hint);
+ }
+
+ template <typename T, typename Tr, typename Al>
+ void reserve(std::basic_string<T, Tr, Al>& arr, std::size_t hint) {
+ arr.reserve(hint);
+ }
+ } // detail
+
+ namespace stack {
+
+ template<typename T, bool global = false, bool raw = false, typename = void>
+ struct field_getter;
+ template <typename T, bool global = false, bool raw = false, typename = void>
+ struct probe_field_getter;
+ template<typename T, bool global = false, bool raw = false, typename = void>
+ struct field_setter;
+ template<typename T, typename = void>
+ struct getter;
+ template<typename T, typename = void>
+ struct popper;
+ template<typename T, typename = void>
+ struct pusher;
+ template<typename T, type = lua_type_of<T>::value, typename = void>
+ struct checker;
+ template<typename T, typename = void>
+ struct check_getter;
+
+ struct probe {
+ bool success;
+ int levels;
+
+ probe(bool s, int l) : success(s), levels(l) {}
+
+ operator bool() const { return success; };
+ };
+
+ struct record {
+ int last;
+ int used;
+
+ record() : last(), used() {}
+ void use(int count) {
+ last = count;
+ used += count;
+ }
+ };
+
+ namespace stack_detail {
+ template <typename T>
+ struct strip {
+ typedef T type;
+ };
+ template <typename T>
+ struct strip<std::reference_wrapper<T>> {
+ typedef T& type;
+ };
+ template <typename T>
+ struct strip<user<T>> {
+ typedef T& type;
+ };
+ template <typename T>
+ struct strip<non_null<T>> {
+ typedef T type;
+ };
+ template <typename T>
+ using strip_t = typename strip<T>::type;
+ const bool default_check_arguments =
+#ifdef SOL_CHECK_ARGUMENTS
+ true;
+#else
+ false;
+#endif
+ template<typename T>
+ inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) {
+ return getter<meta::unqualified_t<T>>{}.get(L, index, tracking);
+ }
+ } // stack_detail
+
+ inline bool maybe_indexable(lua_State* L, int index = -1) {
+ type t = type_of(L, index);
+ return t == type::userdata || t == type::table;
+ }
+
+ template<typename T, typename... Args>
+ inline int push(lua_State* L, T&& t, Args&&... args) {
+ return pusher<meta::unqualified_t<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
+ }
+
+ // overload allows to use a pusher of a specific type, but pass in any kind of args
+ template<typename T, typename Arg, typename... Args, typename = std::enable_if_t<!std::is_same<T, Arg>::value>>
+ inline int push(lua_State* L, Arg&& arg, Args&&... args) {
+ return pusher<meta::unqualified_t<T>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
+ }
+
+ template<typename T, typename... Args>
+ inline int push_reference(lua_State* L, T&& t, Args&&... args) {
+ typedef meta::all<
+ std::is_lvalue_reference<T>,
+ meta::neg<std::is_const<T>>,
+ meta::neg<is_lua_primitive<meta::unqualified_t<T>>>,
+ meta::neg<is_unique_usertype<meta::unqualified_t<T>>>
+ > use_reference_tag;
+ return pusher<std::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::unqualified_t<T>>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
+ }
+
+ inline int multi_push(lua_State*) {
+ // do nothing
+ return 0;
+ }
+
+ template<typename T, typename... Args>
+ inline int multi_push(lua_State* L, T&& t, Args&&... args) {
+ int pushcount = push(L, std::forward<T>(t));
+ void(sol::detail::swallow{ (pushcount += sol::stack::push(L, std::forward<Args>(args)), 0)... });
+ return pushcount;
+ }
+
+ inline int multi_push_reference(lua_State*) {
+ // do nothing
+ return 0;
+ }
+
+ template<typename T, typename... Args>
+ inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) {
+ int pushcount = push_reference(L, std::forward<T>(t));
+ void(sol::detail::swallow{ (pushcount += sol::stack::push_reference(L, std::forward<Args>(args)), 0)... });
+ return pushcount;
+ }
+
+ template <typename T, typename Handler>
+ bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ typedef meta::unqualified_t<T> Tu;
+ checker<Tu> c;
+ // VC++ has a bad warning here: shut it up
+ (void)c;
+ return c.check(L, index, std::forward<Handler>(handler), tracking);
+ }
+
+ template <typename T, typename Handler>
+ bool check(lua_State* L, int index, Handler&& handler) {
+ record tracking{};
+ return check<T>(L, index, std::forward<Handler>(handler), tracking);
+ }
+
+ template <typename T>
+ bool check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
+ auto handler = no_panic;
+ return check<T>(L, index, handler);
+ }
+
+ template<typename T, typename Handler>
+ inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
+ return check_getter<meta::unqualified_t<T>>{}.get(L, index, std::forward<Handler>(handler), tracking);
+ }
+
+ template<typename T, typename Handler>
+ inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler) {
+ record tracking{};
+ return check_get<T>(L, index, handler, tracking);
+ }
+
+ template<typename T>
+ inline decltype(auto) check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
+ auto handler = no_panic;
+ return check_get<T>(L, index, handler);
+ }
+
+ namespace stack_detail {
+
+#ifdef SOL_CHECK_ARGUMENTS
+ template <typename T>
+ inline auto tagged_get(types<T>, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) {
+ auto op = check_get<T>(L, index, type_panic, tracking);
+ return *std::move(op);
+ }
+#else
+ template <typename T>
+ inline decltype(auto) tagged_get(types<T>, lua_State* L, int index, record& tracking) {
+ return stack_detail::unchecked_get<T>(L, index, tracking);
+ }
+#endif
+
+ template <typename T>
+ inline decltype(auto) tagged_get(types<optional<T>>, lua_State* L, int index, record& tracking) {
+ return stack_detail::unchecked_get<optional<T>>(L, index, tracking);
+ }
+
+ template <bool b>
+ struct check_types {
+ template <typename T, typename... Args, typename Handler>
+ static bool check(types<T, Args...>, lua_State* L, int firstargument, Handler&& handler, record& tracking) {
+ if (!stack::check<T>(L, firstargument + tracking.used, handler, tracking))
+ return false;
+ return check(types<Args...>(), L, firstargument, std::forward<Handler>(handler), tracking);
+ }
+
+ template <typename Handler>
+ static bool check(types<>, lua_State*, int, Handler&&, record&) {
+ return true;
+ }
+ };
+
+ template <>
+ struct check_types<false> {
+ template <typename... Args, typename Handler>
+ static bool check(types<Args...>, lua_State*, int, Handler&&, record&) {
+ return true;
+ }
+ };
+
+ } // stack_detail
+
+ template <bool b, typename... Args, typename Handler>
+ bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ return stack_detail::check_types<b>{}.check(types<meta::unqualified_t<Args>...>(), L, index, std::forward<Handler>(handler), tracking);
+ }
+
+ template <bool b, typename... Args, typename Handler>
+ bool multi_check(lua_State* L, int index, Handler&& handler) {
+ record tracking{};
+ return multi_check<b, Args...>(L, index, std::forward<Handler>(handler), tracking);
+ }
+
+ template <bool b, typename... Args>
+ bool multi_check(lua_State* L, int index) {
+ auto handler = no_panic;
+ return multi_check<b, Args...>(L, index, handler);
+ }
+
+ template <typename... Args, typename Handler>
+ bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ return multi_check<true, Args...>(L, index, std::forward<Handler>(handler), tracking);
+ }
+
+ template <typename... Args, typename Handler>
+ bool multi_check(lua_State* L, int index, Handler&& handler) {
+ return multi_check<true, Args...>(L, index, std::forward<Handler>(handler));
+ }
+
+ template <typename... Args>
+ bool multi_check(lua_State* L, int index) {
+ return multi_check<true, Args...>(L, index);
+ }
+
+ template<typename T>
+ inline decltype(auto) get(lua_State* L, int index, record& tracking) {
+ return stack_detail::tagged_get(types<T>(), L, index, tracking);
+ }
+
+ template<typename T>
+ inline decltype(auto) get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
+ record tracking{};
+ return get<T>(L, index, tracking);
+ }
+
+ template<typename T>
+ inline decltype(auto) pop(lua_State* L) {
+ return popper<meta::unqualified_t<T>>{}.pop(L);
+ }
+
+ template <bool global = false, bool raw = false, typename Key>
+ void get_field(lua_State* L, Key&& key) {
+ field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key));
+ }
+
+ template <bool global = false, bool raw = false, typename Key>
+ void get_field(lua_State* L, Key&& key, int tableindex) {
+ field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key), tableindex);
+ }
+
+ template <bool global = false, typename Key>
+ void raw_get_field(lua_State* L, Key&& key) {
+ get_field<global, true>(L, std::forward<Key>(key));
+ }
+
+ template <bool global = false, typename Key>
+ void raw_get_field(lua_State* L, Key&& key, int tableindex) {
+ get_field<global, true>(L, std::forward<Key>(key), tableindex);
+ }
+
+ template <bool global = false, bool raw = false, typename Key>
+ probe probe_get_field(lua_State* L, Key&& key) {
+ return probe_field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key));
+ }
+
+ template <bool global = false, bool raw = false, typename Key>
+ probe probe_get_field(lua_State* L, Key&& key, int tableindex) {
+ return probe_field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key), tableindex);
+ }
+
+ template <bool global = false, typename Key>
+ probe probe_raw_get_field(lua_State* L, Key&& key) {
+ return probe_get_field<global, true>(L, std::forward<Key>(key));
+ }
+
+ template <bool global = false, typename Key>
+ probe probe_raw_get_field(lua_State* L, Key&& key, int tableindex) {
+ return probe_get_field<global, true>(L, std::forward<Key>(key), tableindex);
+ }
+
+ template <bool global = false, bool raw = false, typename Key, typename Value>
+ void set_field(lua_State* L, Key&& key, Value&& value) {
+ field_setter<meta::unqualified_t<Key>, global, raw>{}.set(L, std::forward<Key>(key), std::forward<Value>(value));
+ }
+
+ template <bool global = false, bool raw = false, typename Key, typename Value>
+ void set_field(lua_State* L, Key&& key, Value&& value, int tableindex) {
+ field_setter<meta::unqualified_t<Key>, global, raw>{}.set(L, std::forward<Key>(key), std::forward<Value>(value), tableindex);
+ }
+
+ template <bool global = false, typename Key, typename Value>
+ void raw_set_field(lua_State* L, Key&& key, Value&& value) {
+ set_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value));
+ }
+
+ template <bool global = false, typename Key, typename Value>
+ void raw_set_field(lua_State* L, Key&& key, Value&& value, int tableindex) {
+ set_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value), tableindex);
+ }
+ } // stack
+} // sol
+
+// end of sol/stack_core.hpp
+
+// beginning of sol/stack_check.hpp
+
+// beginning of sol/usertype_traits.hpp
+
+// beginning of sol/demangle.hpp
+
+#include <cctype>
+#include <locale>
+
+namespace sol {
+ namespace detail {
+#if defined(__GNUC__) || defined(__clang__)
+ template <typename T, class seperator_mark = int>
+ inline std::string ctti_get_type_name() {
+ const static std::array<std::string, 2> removals = { { "{anonymous}", "(anonymous namespace)" } };
+ std::string name = __PRETTY_FUNCTION__;
+ std::size_t start = name.find_first_of('[');
+ start = name.find_first_of('=', start);
+ std::size_t end = name.find_last_of(']');
+ if (end == std::string::npos)
+ end = name.size();
+ if (start == std::string::npos)
+ start = 0;
+ if (start < name.size() - 1)
+ start += 1;
+ name = name.substr(start, end - start);
+ start = name.rfind("seperator_mark");
+ if (start != std::string::npos) {
+ name.erase(start - 2, name.length());
+ }
+ while (!name.empty() && std::isblank(name.front())) name.erase(name.begin());
+ while (!name.empty() && std::isblank(name.back())) name.pop_back();
+
+ for (std::size_t r = 0; r < removals.size(); ++r) {
+ auto found = name.find(removals[r]);
+ while (found != std::string::npos) {
+ name.erase(found, removals[r].size());
+ found = name.find(removals[r]);
+ }
+ }
+
+ return name;
+ }
+#elif defined(_MSC_VER)
+ template <typename T>
+ inline std::string ctti_get_type_name() {
+ const static std::array<std::string, 7> removals = { { "public:", "private:", "protected:", "struct ", "class ", "`anonymous-namespace'", "`anonymous namespace'" } };
+ std::string name = __FUNCSIG__;
+ std::size_t start = name.find("get_type_name");
+ if (start == std::string::npos)
+ start = 0;
+ else
+ start += 13;
+ if (start < name.size() - 1)
+ start += 1;
+ std::size_t end = name.find_last_of('>');
+ if (end == std::string::npos)
+ end = name.size();
+ name = name.substr(start, end - start);
+ if (name.find("struct", 0) == 0)
+ name.replace(0, 6, "", 0);
+ if (name.find("class", 0) == 0)
+ name.replace(0, 5, "", 0);
+ while (!name.empty() && std::isblank(name.front())) name.erase(name.begin());
+ while (!name.empty() && std::isblank(name.back())) name.pop_back();
+
+ for (std::size_t r = 0; r < removals.size(); ++r) {
+ auto found = name.find(removals[r]);
+ while (found != std::string::npos) {
+ name.erase(found, removals[r].size());
+ found = name.find(removals[r]);
+ }
+ }
+
+ return name;
+ }
+#else
+#error Compiler not supported for demangling
+#endif // compilers
+
+ template <typename T>
+ inline std::string demangle_once() {
+ std::string realname = ctti_get_type_name<T>();
+ return realname;
+ }
+
+ template <typename T>
+ inline std::string short_demangle_once() {
+ std::string realname = ctti_get_type_name<T>();
+ // This isn't the most complete but it'll do for now...?
+ static const std::array<std::string, 10> ops = { { "operator<", "operator<<", "operator<<=", "operator<=", "operator>", "operator>>", "operator>>=", "operator>=", "operator->", "operator->*" } };
+ int level = 0;
+ std::ptrdiff_t idx = 0;
+ for (idx = static_cast<std::ptrdiff_t>(realname.empty() ? 0 : realname.size() - 1); idx > 0; --idx) {
+ if (level == 0 && realname[idx] == ':') {
+ break;
+ }
+ bool isleft = realname[idx] == '<';
+ bool isright = realname[idx] == '>';
+ if (!isleft && !isright)
+ continue;
+ bool earlybreak = false;
+ for (const auto& op : ops) {
+ std::size_t nisop = realname.rfind(op, idx);
+ if (nisop == std::string::npos)
+ continue;
+ std::size_t nisopidx = idx - op.size() + 1;
+ if (nisop == nisopidx) {
+ idx = static_cast<std::ptrdiff_t>(nisopidx);
+ earlybreak = true;
+ }
+ break;
+ }
+ if (earlybreak) {
+ continue;
+ }
+ level += isleft ? -1 : 1;
+ }
+ if (idx > 0) {
+ realname.erase(0, realname.length() < static_cast<std::size_t>(idx) ? realname.length() : idx + 1);
+ }
+ return realname;
+ }
+
+ template <typename T>
+ inline const std::string& demangle() {
+ static const std::string d = demangle_once<T>();
+ return d;
+ }
+
+ template <typename T>
+ inline const std::string& short_demangle() {
+ static const std::string d = short_demangle_once<T>();
+ return d;
+ }
+ } // detail
+} // sol
+
+// end of sol/demangle.hpp
+
+namespace sol {
+
+ template<typename T>
+ struct usertype_traits {
+ static const std::string& name() {
+ static const std::string& n = detail::short_demangle<T>();
+ return n;
+ }
+ static const std::string& qualified_name() {
+ static const std::string& q_n = detail::demangle<T>();
+ return q_n;
+ }
+ static const std::string& metatable() {
+ static const std::string m = std::string("sol.").append(detail::demangle<T>());
+ return m;
+ }
+ static const std::string& user_metatable() {
+ static const std::string u_m = std::string("sol.").append(detail::demangle<T>()).append(".user");
+ return u_m;
+ }
+ static const std::string& user_gc_metatable() {
+ static const std::string u_g_m = std::string("sol.").append(detail::demangle<T>()).append(".user\xE2\x99\xBB");
+ return u_g_m;
+ }
+ static const std::string& gc_table() {
+ static const std::string g_t = std::string("sol.").append(detail::demangle<T>()).append(".\xE2\x99\xBB");
+ return g_t;
+ }
+ };
+
+}
+
+// end of sol/usertype_traits.hpp
+
+// beginning of sol/inheritance.hpp
+
+#include <atomic>
+
+namespace sol {
+ template <typename... Args>
+ struct base_list { };
+ template <typename... Args>
+ using bases = base_list<Args...>;
+
+ typedef bases<> base_classes_tag;
+ const auto base_classes = base_classes_tag();
+
+ namespace detail {
+
+ template <typename T>
+ struct has_derived {
+ static bool value;
+ };
+
+ template <typename T>
+ bool has_derived<T>::value = false;
+
+ inline std::size_t unique_id() {
+ static std::atomic<std::size_t> x(0);
+ return ++x;
+ }
+
+ template <typename T>
+ struct id_for {
+ static const std::size_t value;
+ };
+
+ template <typename T>
+ const std::size_t id_for<T>::value = unique_id();
+
+ inline decltype(auto) base_class_check_key() {
+ static const auto& key = "class_check";
+ return key;
+ }
+
+ inline decltype(auto) base_class_cast_key() {
+ static const auto& key = "class_cast";
+ return key;
+ }
+
+ inline decltype(auto) base_class_index_propogation_key() {
+ static const auto& key = u8"\xF0\x9F\x8C\xB2.index";
+ return key;
+ }
+
+ inline decltype(auto) base_class_new_index_propogation_key() {
+ static const auto& key = u8"\xF0\x9F\x8C\xB2.new_index";
+ return key;
+ }
+
+ template <typename T, typename... Bases>
+ struct inheritance {
+ static bool type_check_bases(types<>, std::size_t) {
+ return false;
+ }
+
+ template <typename Base, typename... Args>
+ static bool type_check_bases(types<Base, Args...>, std::size_t ti) {
+ return ti == id_for<Base>::value || type_check_bases(types<Args...>(), ti);
+ }
+
+ static bool type_check(std::size_t ti) {
+ return ti == id_for<T>::value || type_check_bases(types<Bases...>(), ti);
+ }
+
+ static void* type_cast_bases(types<>, T*, std::size_t) {
+ return nullptr;
+ }
+
+ template <typename Base, typename... Args>
+ static void* type_cast_bases(types<Base, Args...>, T* data, std::size_t ti) {
+ // Make sure to convert to T first, and then dynamic cast to the proper type
+ return ti != id_for<Base>::value ? type_cast_bases(types<Args...>(), data, ti) : static_cast<void*>(static_cast<Base*>(data));
+ }
+
+ static void* type_cast(void* voiddata, std::size_t ti) {
+ T* data = static_cast<T*>(voiddata);
+ return static_cast<void*>(ti != id_for<T>::value ? type_cast_bases(types<Bases...>(), data, ti) : data);
+ }
+ };
+
+ using inheritance_check_function = decltype(&inheritance<void>::type_check);
+ using inheritance_cast_function = decltype(&inheritance<void>::type_cast);
+
+ } // detail
+} // sol
+
+// end of sol/inheritance.hpp
+
+#include <utility>
+
+namespace sol {
+ namespace stack {
+ namespace stack_detail {
+ template <typename T, bool poptable = true>
+ inline bool check_metatable(lua_State* L, int index = -2) {
+ const auto& metakey = usertype_traits<T>::metatable();
+ luaL_getmetatable(L, &metakey[0]);
+ const type expectedmetatabletype = static_cast<type>(lua_type(L, -1));
+ if (expectedmetatabletype != type::lua_nil) {
+ if (lua_rawequal(L, -1, index) == 1) {
+ lua_pop(L, 1 + static_cast<int>(poptable));
+ return true;
+ }
+ }
+ lua_pop(L, 1);
+ return false;
+ }
+
+ template <type expected, int(*check_func)(lua_State*, int)>
+ struct basic_check {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ tracking.use(1);
+ bool success = check_func(L, index) == 1;
+ if (!success) {
+ // expected type, actual type
+ handler(L, index, expected, type_of(L, index));
+ }
+ return success;
+ }
+ };
+ } // stack_detail
+
+ template <typename T, type expected, typename>
+ struct checker {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ tracking.use(1);
+ const type indextype = type_of(L, index);
+ bool success = expected == indextype;
+ if (!success) {
+ // expected type, actual type
+ handler(L, index, expected, indextype);
+ }
+ return success;
+ }
+ };
+
+ template<typename T>
+ struct checker<T, type::number, std::enable_if_t<std::is_integral<T>::value>> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ tracking.use(1);
+ bool success = lua_isinteger(L, index) == 1;
+ if (!success) {
+ // expected type, actual type
+ handler(L, index, type::number, type_of(L, index));
+ }
+ return success;
+ }
+ };
+
+ template<typename T>
+ struct checker<T, type::number, std::enable_if_t<std::is_floating_point<T>::value>> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ tracking.use(1);
+ bool success = lua_isnumber(L, index) == 1;
+ if (!success) {
+ // expected type, actual type
+ handler(L, index, type::number, type_of(L, index));
+ }
+ return success;
+ }
+ };
+
+ template <type expected, typename C>
+ struct checker<lua_nil_t, expected, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ bool success = lua_isnil(L, index);
+ if (success) {
+ tracking.use(1);
+ return success;
+ }
+ tracking.use(0);
+ success = lua_isnone(L, index);
+ if (!success) {
+ // expected type, actual type
+ handler(L, index, expected, type_of(L, index));
+ }
+ return success;
+ }
+ };
+
+ template <type expected, typename C>
+ struct checker<nullopt_t, expected, C> : checker<lua_nil_t> {};
+
+ template <typename C>
+ struct checker<this_state, type::poly, C> {
+ template <typename Handler>
+ static bool check(lua_State*, int, Handler&&, record& tracking) {
+ tracking.use(0);
+ return true;
+ }
+ };
+
+ template <typename C>
+ struct checker<variadic_args, type::poly, C> {
+ template <typename Handler>
+ static bool check(lua_State*, int, Handler&&, record& tracking) {
+ tracking.use(0);
+ return true;
+ }
+ };
+
+ template <typename C>
+ struct checker<type, type::poly, C> {
+ template <typename Handler>
+ static bool check(lua_State*, int, Handler&&, record& tracking) {
+ tracking.use(0);
+ return true;
+ }
+ };
+
+ template <typename T, typename C>
+ struct checker<T, type::poly, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ tracking.use(1);
+ bool success = !lua_isnone(L, index);
+ if (!success) {
+ // expected type, actual type
+ handler(L, index, type::none, type_of(L, index));
+ }
+ return success;
+ }
+ };
+
+ template <typename T, typename C>
+ struct checker<T, type::lightuserdata, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ tracking.use(1);
+ type t = type_of(L, index);
+ bool success = t == type::userdata || t == type::lightuserdata;
+ if (!success) {
+ // expected type, actual type
+ handler(L, index, type::lightuserdata, t);
+ }
+ return success;
+ }
+ };
+
+ template <typename C>
+ struct checker<userdata_value, type::userdata, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ tracking.use(1);
+ type t = type_of(L, index);
+ bool success = t == type::userdata;
+ if (!success) {
+ // expected type, actual type
+ handler(L, index, type::userdata, t);
+ }
+ return success;
+ }
+ };
+
+ template <typename T, typename C>
+ struct checker<user<T>, type::userdata, C> : checker<user<T>, type::lightuserdata, C> {};
+
+ template <typename T, typename C>
+ struct checker<non_null<T>, type::userdata, C> : checker<T, lua_type_of<T>::value, C> {};
+
+ template <typename C>
+ struct checker<lua_CFunction, type::function, C> : stack_detail::basic_check<type::function, lua_iscfunction> {};
+ template <typename C>
+ struct checker<std::remove_pointer_t<lua_CFunction>, type::function, C> : checker<lua_CFunction, type::function, C> {};
+ template <typename C>
+ struct checker<c_closure, type::function, C> : checker<lua_CFunction, type::function, C> {};
+
+ template <typename T, typename C>
+ struct checker<T, type::function, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ tracking.use(1);
+ type t = type_of(L, index);
+ if (t == type::lua_nil || t == type::none || t == type::function) {
+ // allow for lua_nil to be returned
+ return true;
+ }
+ if (t != type::userdata && t != type::table) {
+ handler(L, index, type::function, t);
+ return false;
+ }
+ // Do advanced check for call-style userdata?
+ static const auto& callkey = name_of(meta_function::call);
+ if (lua_getmetatable(L, index) == 0) {
+ // No metatable, no __call key possible
+ handler(L, index, type::function, t);
+ return false;
+ }
+ if (lua_isnoneornil(L, -1)) {
+ lua_pop(L, 1);
+ handler(L, index, type::function, t);
+ return false;
+ }
+ lua_getfield(L, -1, &callkey[0]);
+ if (lua_isnoneornil(L, -1)) {
+ lua_pop(L, 2);
+ handler(L, index, type::function, t);
+ return false;
+ }
+ // has call, is definitely a function
+ lua_pop(L, 2);
+ return true;
+ }
+ };
+
+ template <typename T, typename C>
+ struct checker<T, type::table, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ tracking.use(1);
+ type t = type_of(L, index);
+ if (t == type::table) {
+ return true;
+ }
+ if (t != type::userdata) {
+ handler(L, index, type::function, t);
+ return false;
+ }
+ return true;
+ }
+ };
+
+ template <typename T, typename C>
+ struct checker<detail::as_value_tag<T>, type::userdata, C> {
+ template <typename U, typename Handler>
+ static bool check(types<U>, lua_State* L, type indextype, int index, Handler&& handler, record& tracking) {
+ tracking.use(1);
+ if (indextype != type::userdata) {
+ handler(L, index, type::userdata, indextype);
+ return false;
+ }
+ if (meta::any<std::is_same<T, lightuserdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value)
+ return true;
+ if (lua_getmetatable(L, index) == 0) {
+ return true;
+ }
+ int metatableindex = lua_gettop(L);
+ if (stack_detail::check_metatable<U>(L, metatableindex))
+ return true;
+ if (stack_detail::check_metatable<U*>(L, metatableindex))
+ return true;
+ if (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex))
+ return true;
+ bool success = false;
+ if (detail::has_derived<T>::value) {
+ auto pn = stack::pop_n(L, 1);
+ lua_pushstring(L, &detail::base_class_check_key()[0]);
+ lua_rawget(L, metatableindex);
+ if (type_of(L, -1) != type::lua_nil) {
+ void* basecastdata = lua_touserdata(L, -1);
+ detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
+ success = ic(detail::id_for<T>::value);
+ }
+ }
+ if (!success) {
+ lua_pop(L, 1);
+ handler(L, index, type::userdata, indextype);
+ return false;
+ }
+ lua_pop(L, 1);
+ return true;
+ }
+ };
+
+ template <typename T, typename C>
+ struct checker<T, type::userdata, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ const type indextype = type_of(L, index);
+ return checker<detail::as_value_tag<T>, type::userdata, C>{}.check(types<T>(), L, indextype, index, std::forward<Handler>(handler), tracking);
+ }
+ };
+
+ template <typename T, typename C>
+ struct checker<T*, type::userdata, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ const type indextype = type_of(L, index);
+ // Allow lua_nil to be transformed to nullptr
+ if (indextype == type::lua_nil) {
+ tracking.use(1);
+ return true;
+ }
+ return checker<meta::unqualified_t<T>, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler), tracking);
+ }
+ };
+
+ template<typename T>
+ struct checker<T, type::userdata, std::enable_if_t<is_unique_usertype<T>::value>> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ return checker<typename unique_usertype_traits<T>::type, type::userdata>{}.check(L, index, std::forward<Handler>(handler), tracking);
+ }
+ };
+
+ template<typename T, typename C>
+ struct checker<std::reference_wrapper<T>, type::userdata, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ return checker<T, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler), tracking);
+ }
+ };
+
+ template<typename... Args, typename C>
+ struct checker<std::tuple<Args...>, type::poly, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ return stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking);
+ }
+ };
+
+ template<typename A, typename B, typename C>
+ struct checker<std::pair<A, B>, type::poly, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
+ return stack::multi_check<A, B>(L, index, std::forward<Handler>(handler), tracking);
+ }
+ };
+
+ template<typename T, typename C>
+ struct checker<optional<T>, type::poly, C> {
+ template <typename Handler>
+ static bool check(lua_State* L, int index, Handler&&, record& tracking) {
+ type t = type_of(L, index);
+ if (t == type::none) {
+ tracking.use(0);
+ return true;
+ }
+ if (t == type::lua_nil) {
+ tracking.use(1);
+ return true;
+ }
+ return stack::check<T>(L, index, no_panic, tracking);
+ }
+ };
+ } // stack
+} // sol
+
+// end of sol/stack_check.hpp
+
+// beginning of sol/stack_get.hpp
+
+// beginning of sol/overload.hpp
+
+namespace sol {
+ template <typename... Functions>
+ struct overload_set {
+ std::tuple<Functions...> functions;
+ template <typename Arg, typename... Args, meta::disable<std::is_same<overload_set, meta::unqualified_t<Arg>>> = meta::enabler>
+ overload_set (Arg&& arg, Args&&... args) : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
+ overload_set(const overload_set&) = default;
+ overload_set(overload_set&&) = default;
+ overload_set& operator=(const overload_set&) = default;
+ overload_set& operator=(overload_set&&) = default;
+ };
+
+ template <typename... Args>
+ decltype(auto) overload(Args&&... args) {
+ return overload_set<std::decay_t<Args>...>(std::forward<Args>(args)...);
+ }
+}
+
+// end of sol/overload.hpp
+
+#ifdef SOL_CODECVT_SUPPORT
+#include <codecvt>
+#endif
+
+namespace sol {
+ namespace stack {
+
+ template<typename T, typename>
+ struct getter {
+ static T& get(lua_State* L, int index, record& tracking) {
+ return getter<sol::detail::as_value_tag<T>>{}.get(L, index, tracking);
+ }
+ };
+
+ template<typename T>
+ struct getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
+ static T get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return static_cast<T>(lua_tonumber(L, index));
+ }
+ };
+
+ template<typename T>
+ struct getter<T, std::enable_if_t<meta::all<std::is_integral<T>, std::is_signed<T>>::value>> {
+ static T get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return static_cast<T>(lua_tointeger(L, index));
+ }
+ };
+
+ template<typename T>
+ struct getter<T, std::enable_if_t<meta::all<std::is_integral<T>, std::is_unsigned<T>>::value>> {
+ static T get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return static_cast<T>(lua_tointeger(L, index));
+ }
+ };
+
+ template<typename T>
+ struct getter<T, std::enable_if_t<std::is_enum<T>::value>> {
+ static T get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return static_cast<T>(lua_tointegerx(L, index, nullptr));
+ }
+ };
+
+ template<typename T>
+ struct getter<as_table_t<T>, std::enable_if_t<!meta::has_key_value_pair<meta::unqualified_t<T>>::value>> {
+ static T get(lua_State* L, int index, record& tracking) {
+ typedef typename T::value_type V;
+ tracking.use(1);
+
+ index = lua_absindex(L, index);
+ T arr;
+ get_field<false, true>(L, static_cast<lua_Integer>(-1), index);
+ int isnum;
+ std::size_t sizehint = static_cast<std::size_t>(lua_tointegerx(L, -1, &isnum));
+ if (isnum != 0) {
+ detail::reserve(arr, sizehint);
+ }
+ lua_pop(L, 1);
+#if SOL_LUA_VERSION >= 503
+ // This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3
+ for (lua_Integer i = 0; ; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {
+ for (int vi = 0; vi < lua_size<V>::value; ++vi) {
+ type t = static_cast<type>(lua_geti(L, index, i + vi));
+ if (t == type::lua_nil) {
+ if (i == 0) {
+ continue;
+ }
+ else {
+ lua_pop(L, (vi + 1));
+ return arr;
+ }
+ }
+ }
+ arr.push_back(stack::get<V>(L, -lua_size<V>::value));
+ }
+#else
+ // Zzzz slower but necessary thanks to the lower version API and missing functions qq
+ for (lua_Integer i = 0; ; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {
+ for (int vi = 0; vi < lua_size<V>::value; ++vi) {
+ lua_pushinteger(L, i);
+ lua_gettable(L, index);
+ type t = type_of(L, -1);
+ if (t == type::lua_nil) {
+ if (i == 0) {
+ continue;
+ }
+ else {
+ lua_pop(L, (vi + 1));
+ return arr;
+ }
+ }
+ }
+ arr.push_back(stack::get<V>(L, -1));
+ }
+#endif
+ return arr;
+ }
+ };
+
+ template<typename T>
+ struct getter<as_table_t<T>, std::enable_if_t<meta::has_key_value_pair<meta::unqualified_t<T>>::value>> {
+ static T get(lua_State* L, int index, record& tracking) {
+ typedef typename T::value_type P;
+ typedef typename P::first_type K;
+ typedef typename P::second_type V;
+ tracking.use(1);
+
+ T associative;
+ index = lua_absindex(L, index);
+ lua_pushnil(L);
+ while (lua_next(L, index) != 0) {
+ decltype(auto) key = stack::check_get<K>(L, -2);
+ if (!key) {
+ lua_pop(L, 1);
+ continue;
+ }
+ associative.emplace(std::forward<decltype(*key)>(*key), stack::get<V>(L, -1));
+ lua_pop(L, 1);
+ }
+ return associative;
+ }
+ };
+
+ template<typename T>
+ struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> {
+ static T get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return T(L, index);
+ }
+ };
+
+ template<>
+ struct getter<userdata_value> {
+ static userdata_value get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return userdata_value(lua_touserdata(L, index));
+ }
+ };
+
+ template<>
+ struct getter<lightuserdata_value> {
+ static lightuserdata_value get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return lightuserdata_value(lua_touserdata(L, index));
+ }
+ };
+
+ template<typename T>
+ struct getter<light<T>> {
+ static light<T> get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return light<T>(static_cast<T*>(lua_touserdata(L, index)));
+ }
+ };
+
+ template<typename T>
+ struct getter<user<T>> {
+ static T& get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return *static_cast<T*>(lua_touserdata(L, index));
+ }
+ };
+
+ template<typename T>
+ struct getter<user<T*>> {
+ static T* get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return static_cast<T*>(lua_touserdata(L, index));
+ }
+ };
+
+ template<>
+ struct getter<type> {
+ static type get(lua_State *L, int index, record& tracking) {
+ tracking.use(1);
+ return static_cast<type>(lua_type(L, index));
+ }
+ };
+
+ template<>
+ struct getter<bool> {
+ static bool get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return lua_toboolean(L, index) != 0;
+ }
+ };
+
+ template<>
+ struct getter<std::string> {
+ static std::string get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ std::size_t len;
+ auto str = lua_tolstring(L, index, &len);
+ return std::string( str, len );
+ }
+ };
+
+ template <>
+ struct getter<string_detail::string_shim> {
+ string_detail::string_shim get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ size_t len;
+ const char* p = lua_tolstring(L, index, &len);
+ return string_detail::string_shim(p, len);
+ }
+ };
+
+ template<>
+ struct getter<const char*> {
+ static const char* get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return lua_tostring(L, index);
+ }
+ };
+
+ template<>
+ struct getter<char> {
+ static char get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ size_t len;
+ auto str = lua_tolstring(L, index, &len);
+ return len > 0 ? str[0] : '\0';
+ }
+ };
+
+#ifdef SOL_CODECVT_SUPPORT
+ template<>
+ struct getter<std::wstring> {
+ static std::wstring get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ size_t len;
+ auto str = lua_tolstring(L, index, &len);
+ if (len < 1)
+ return std::wstring();
+ if (sizeof(wchar_t) == 2) {
+ static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
+ std::wstring r = convert.from_bytes(str, str + len);
+#ifdef __MINGW32__
+ // Fuck you, MinGW, and fuck you libstdc++ for introducing this absolutely asinine bug
+ // https://sourceforge.net/p/mingw-w64/bugs/538/
+ // http://chat.stackoverflow.com/transcript/message/32271369#32271369
+ for (auto& c : r) {
+ uint8_t* b = reinterpret_cast<uint8_t*>(&c);
+ std::swap(b[0], b[1]);
+ }
+#endif
+ return r;
+ }
+ static std::wstring_convert<std::codecvt_utf8<wchar_t>> convert;
+ std::wstring r = convert.from_bytes(str, str + len);
+ return r;
+ }
+ };
+
+ template<>
+ struct getter<std::u16string> {
+ static std::u16string get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ size_t len;
+ auto str = lua_tolstring(L, index, &len);
+ if (len < 1)
+ return std::u16string();
+#ifdef _MSC_VER
+ static std::wstring_convert<std::codecvt_utf8_utf16<int16_t>, int16_t> convert;
+ auto intd = convert.from_bytes(str, str + len);
+ std::u16string r(intd.size(), '\0');
+ std::memcpy(&r[0], intd.data(), intd.size() * sizeof(char16_t));
+#else
+ static std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+ std::u16string r = convert.from_bytes(str, str + len);
+#endif // VC++ is a shit
+ return r;
+ }
+ };
+
+ template<>
+ struct getter<std::u32string> {
+ static std::u32string get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ size_t len;
+ auto str = lua_tolstring(L, index, &len);
+ if (len < 1)
+ return std::u32string();
+#ifdef _MSC_VER
+ static std::wstring_convert<std::codecvt_utf8<int32_t>, int32_t> convert;
+ auto intd = convert.from_bytes(str, str + len);
+ std::u32string r(intd.size(), '\0');
+ std::memcpy(&r[0], intd.data(), r.size() * sizeof(char32_t));
+#else
+ static std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
+ std::u32string r = convert.from_bytes(str, str + len);
+#endif // VC++ is a shit
+ return r;
+ }
+ };
+
+ template<>
+ struct getter<wchar_t> {
+ static wchar_t get(lua_State* L, int index, record& tracking) {
+ auto str = getter<std::wstring>{}.get(L, index, tracking);
+ return str.size() > 0 ? str[0] : wchar_t(0);
+ }
+ };
+
+ template<>
+ struct getter<char16_t> {
+ static char16_t get(lua_State* L, int index, record& tracking) {
+ auto str = getter<std::u16string>{}.get(L, index, tracking);
+ return str.size() > 0 ? str[0] : char16_t(0);
+ }
+ };
+
+ template<>
+ struct getter<char32_t> {
+ static char32_t get(lua_State* L, int index, record& tracking) {
+ auto str = getter<std::u32string>{}.get(L, index, tracking);
+ return str.size() > 0 ? str[0] : char32_t(0);
+ }
+ };
+#endif // codecvt header support
+
+ template<>
+ struct getter<meta_function> {
+ static meta_function get(lua_State *L, int index, record& tracking) {
+ tracking.use(1);
+ const char* name = getter<const char*>{}.get(L, index, tracking);
+ for (std::size_t i = 0; i < meta_function_names.size(); ++i)
+ if (meta_function_names[i] == name)
+ return static_cast<meta_function>(i);
+ return meta_function::construct;
+ }
+ };
+
+ template<>
+ struct getter<lua_nil_t> {
+ static lua_nil_t get(lua_State*, int, record& tracking) {
+ tracking.use(1);
+ return lua_nil;
+ }
+ };
+
+ template<>
+ struct getter<std::nullptr_t> {
+ static std::nullptr_t get(lua_State*, int, record& tracking) {
+ tracking.use(1);
+ return nullptr;
+ }
+ };
+
+ template<>
+ struct getter<nullopt_t> {
+ static nullopt_t get(lua_State*, int, record& tracking) {
+ tracking.use(1);
+ return nullopt;
+ }
+ };
+
+ template<>
+ struct getter<this_state> {
+ static this_state get(lua_State* L, int, record& tracking) {
+ tracking.use(0);
+ return this_state{ L };
+ }
+ };
+
+ template<>
+ struct getter<lua_CFunction> {
+ static lua_CFunction get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return lua_tocfunction(L, index);
+ }
+ };
+
+ template<>
+ struct getter<c_closure> {
+ static c_closure get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return c_closure(lua_tocfunction(L, index), -1);
+ }
+ };
+
+ template<>
+ struct getter<error> {
+ static error get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ size_t sz = 0;
+ const char* err = lua_tolstring(L, index, &sz);
+ if (err == nullptr) {
+ return error(detail::direct_error, "");
+ }
+ return error(detail::direct_error, std::string(err, sz));
+ }
+ };
+
+ template<>
+ struct getter<void*> {
+ static void* get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ return lua_touserdata(L, index);
+ }
+ };
+
+ template<typename T>
+ struct getter<detail::as_value_tag<T>> {
+ static T* get_no_lua_nil(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ void** pudata = static_cast<void**>(lua_touserdata(L, index));
+ void* udata = *pudata;
+ return get_no_lua_nil_from(L, udata, index, tracking);
+ }
+
+ static T* get_no_lua_nil_from(lua_State* L, void* udata, int index, record&) {
+ if (detail::has_derived<T>::value && luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) {
+ void* basecastdata = lua_touserdata(L, -1);
+ detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata;
+ // use the casting function to properly adjust the pointer for the desired T
+ udata = ic(udata, detail::id_for<T>::value);
+ lua_pop(L, 1);
+ }
+ T* obj = static_cast<T*>(udata);
+ return obj;
+ }
+
+ static T& get(lua_State* L, int index, record& tracking) {
+ return *get_no_lua_nil(L, index, tracking);
+ }
+ };
+
+ template<typename T>
+ struct getter<detail::as_pointer_tag<T>> {
+ static T* get(lua_State* L, int index, record& tracking) {
+ type t = type_of(L, index);
+ if (t == type::lua_nil) {
+ tracking.use(1);
+ return nullptr;
+ }
+ return getter<detail::as_value_tag<T>>::get_no_lua_nil(L, index, tracking);
+ }
+ };
+
+ template<typename T>
+ struct getter<non_null<T*>> {
+ static T* get(lua_State* L, int index, record& tracking) {
+ return getter<detail::as_value_tag<T>>::get_no_lua_nil(L, index, tracking);
+ }
+ };
+
+ template<typename T>
+ struct getter<T&> {
+ static T& get(lua_State* L, int index, record& tracking) {
+ return getter<detail::as_value_tag<T>>::get(L, index, tracking);
+ }
+ };
+
+ template<typename T>
+ struct getter<std::reference_wrapper<T>> {
+ static T& get(lua_State* L, int index, record& tracking) {
+ return getter<T&>{}.get(L, index, tracking);
+ }
+ };
+
+ template<typename T>
+ struct getter<T*> {
+ static T* get(lua_State* L, int index, record& tracking) {
+ return getter<detail::as_pointer_tag<T>>::get(L, index, tracking);
+ }
+ };
+
+ template<typename T>
+ struct getter<T, std::enable_if_t<is_unique_usertype<T>::value>> {
+ typedef typename unique_usertype_traits<T>::type P;
+ typedef typename unique_usertype_traits<T>::actual_type Real;
+
+ static Real& get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ P** pref = static_cast<P**>(lua_touserdata(L, index));
+ detail::special_destruct_func* fx = static_cast<detail::special_destruct_func*>(static_cast<void*>(pref + 1));
+ Real* mem = static_cast<Real*>(static_cast<void*>(fx + 1));
+ return *mem;
+ }
+ };
+
+ template<typename... Args>
+ struct getter<std::tuple<Args...>> {
+ typedef std::tuple<decltype(stack::get<Args>(nullptr, 0))...> R;
+
+ template <typename... TArgs>
+ static R apply(std::index_sequence<>, lua_State*, int, record&, TArgs&&... args) {
+ // Fuck you too, VC++
+ return R{std::forward<TArgs>(args)...};
+ }
+
+ template <std::size_t I, std::size_t... Ix, typename... TArgs>
+ static R apply(std::index_sequence<I, Ix...>, lua_State* L, int index, record& tracking, TArgs&&... args) {
+ // Fuck you too, VC++
+ typedef std::tuple_element_t<I, std::tuple<Args...>> T;
+ return apply(std::index_sequence<Ix...>(), L, index, tracking, std::forward<TArgs>(args)..., stack::get<T>(L, index + tracking.used, tracking));
+ }
+
+ static R get(lua_State* L, int index, record& tracking) {
+ return apply(std::make_index_sequence<sizeof...(Args)>(), L, index, tracking);
+ }
+ };
+
+ template<typename A, typename B>
+ struct getter<std::pair<A, B>> {
+ static decltype(auto) get(lua_State* L, int index, record& tracking) {
+ return std::pair<decltype(stack::get<A>(L, index)), decltype(stack::get<B>(L, index))>{stack::get<A>(L, index, tracking), stack::get<B>(L, index + tracking.used, tracking)};
+ }
+ };
+
+ } // stack
+} // sol
+
+// end of sol/stack_get.hpp
+
+// beginning of sol/stack_check_get.hpp
+
+namespace sol {
+ namespace stack {
+ template <typename T, typename>
+ struct check_getter {
+ typedef decltype(stack_detail::unchecked_get<T>(nullptr, 0, std::declval<record&>())) R;
+
+ template <typename Handler>
+ static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) {
+ if (!check<T>(L, index, std::forward<Handler>(handler))) {
+ tracking.use(static_cast<int>(!lua_isnone(L, index)));
+ return nullopt;
+ }
+ return stack_detail::unchecked_get<T>(L, index, tracking);
+ }
+ };
+
+ template <typename T>
+ struct check_getter<optional<T>> {
+ template <typename Handler>
+ static decltype(auto) get(lua_State* L, int index, Handler&&, record& tracking) {
+ return check_get<T>(L, index, no_panic, tracking);
+ }
+ };
+
+ template <typename T>
+ struct check_getter<T, std::enable_if_t<std::is_integral<T>::value && lua_type_of<T>::value == type::number>> {
+ template <typename Handler>
+ static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
+ int isnum = 0;
+ lua_Integer value = lua_tointegerx(L, index, &isnum);
+ if (isnum == 0) {
+ type t = type_of(L, index);
+ tracking.use(static_cast<int>(t != type::none));
+ handler(L, index, type::number, t);
+ return nullopt;
+ }
+ tracking.use(1);
+ return static_cast<T>(value);
+ }
+ };
+
+ template <typename T>
+ struct check_getter<T, std::enable_if_t<std::is_enum<T>::value && !meta::any_same<T, meta_function, type>::value>> {
+ template <typename Handler>
+ static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
+ int isnum = 0;
+ lua_Integer value = lua_tointegerx(L, index, &isnum);
+ if (isnum == 0) {
+ type t = type_of(L, index);
+ tracking.use(static_cast<int>(t != type::none));
+ handler(L, index, type::number, t);
+ return nullopt;
+ }
+ tracking.use(1);
+ return static_cast<T>(value);
+ }
+ };
+
+ template <typename T>
+ struct check_getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
+ template <typename Handler>
+ static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
+ int isnum = 0;
+ lua_Number value = lua_tonumberx(L, index, &isnum);
+ if (isnum == 0) {
+ type t = type_of(L, index);
+ tracking.use(static_cast<int>(t != type::none));
+ handler(L, index, type::number, t);
+ return nullopt;
+ }
+ tracking.use(1);
+ return static_cast<T>(value);
+ }
+ };
+
+ template <typename T>
+ struct getter<optional<T>> {
+ static decltype(auto) get(lua_State* L, int index, record& tracking) {
+ return check_get<T>(L, index, no_panic, tracking);
+ }
+ };
+ } // stack
+} // sol
+
+// end of sol/stack_check_get.hpp
+
+// beginning of sol/stack_push.hpp
+
+// beginning of sol/raii.hpp
+
+namespace sol {
+ namespace detail {
+ struct default_construct {
+ template<typename T, typename... Args>
+ static void construct(T&& obj, Args&&... args) {
+ std::allocator<meta::unqualified_t<T>> alloc{};
+ alloc.construct(obj, std::forward<Args>(args)...);
+ }
+
+ template<typename T, typename... Args>
+ void operator()(T&& obj, Args&&... args) const {
+ construct(std::forward<T>(obj), std::forward<Args>(args)...);
+ }
+ };
+
+ struct default_destruct {
+ template<typename T>
+ static void destroy(T&& obj) {
+ std::allocator<meta::unqualified_t<T>> alloc{};
+ alloc.destroy(obj);
+ }
+
+ template<typename T>
+ void operator()(T&& obj) const {
+ destroy(std::forward<T>(obj));
+ }
+ };
+
+ struct deleter {
+ template <typename T>
+ void operator()(T* p) const {
+ delete p;
+ }
+ };
+
+ template <typename T, typename Dx, typename... Args>
+ inline std::unique_ptr<T, Dx> make_unique_deleter(Args&&... args) {
+ return std::unique_ptr<T, Dx>(new T(std::forward<Args>(args)...));
+ }
+
+ template <typename Tag, typename T>
+ struct tagged {
+ T value;
+ template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, tagged>> = meta::enabler>
+ tagged(Arg&& arg, Args&&... args) : value(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
+ };
+ } // detail
+
+ template <typename... Args>
+ struct constructor_list {};
+
+ template<typename... Args>
+ using constructors = constructor_list<Args...>;
+
+ const auto default_constructor = constructors<types<>>{};
+
+ struct no_construction {};
+ const auto no_constructor = no_construction{};
+
+ struct call_construction {};
+ const auto call_constructor = call_construction{};
+
+ template <typename... Functions>
+ struct constructor_wrapper {
+ std::tuple<Functions...> functions;
+ template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, constructor_wrapper>> = meta::enabler>
+ constructor_wrapper(Arg&& arg, Args&&... args) : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
+ };
+
+ template <typename... Functions>
+ inline auto initializers(Functions&&... functions) {
+ return constructor_wrapper<std::decay_t<Functions>...>(std::forward<Functions>(functions)...);
+ }
+
+ template <typename... Functions>
+ struct factory_wrapper {
+ std::tuple<Functions...> functions;
+ template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, factory_wrapper>> = meta::enabler>
+ factory_wrapper(Arg&& arg, Args&&... args) : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
+ };
+
+ template <typename... Functions>
+ inline auto factories(Functions&&... functions) {
+ return factory_wrapper<std::decay_t<Functions>...>(std::forward<Functions>(functions)...);
+ }
+
+ template <typename Function>
+ struct destructor_wrapper {
+ Function fx;
+ destructor_wrapper(Function f) : fx(std::move(f)) {}
+ };
+
+ template <>
+ struct destructor_wrapper<void> {};
+
+ const destructor_wrapper<void> default_destructor{};
+
+ template <typename Fx>
+ inline auto destructor(Fx&& fx) {
+ return destructor_wrapper<std::decay_t<Fx>>(std::forward<Fx>(fx));
+ }
+
+} // sol
+
+// end of sol/raii.hpp
+
+#ifdef SOL_CODECVT_SUPPORT
+#endif
+
+namespace sol {
+ namespace stack {
+ template <typename T>
+ struct pusher<detail::as_value_tag<T>> {
+ template <typename F, typename... Args>
+ static int push_fx(lua_State* L, F&& f, Args&&... args) {
+ // Basically, we store all user-data like this:
+ // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new
+ // data in the first sizeof(T*) bytes, and then however many bytes it takes to
+ // do the actual object. Things that are std::ref or plain T* are stored as
+ // just the sizeof(T*), and nothing else.
+ T** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
+ T*& referencereference = *pointerpointer;
+ T* allocationtarget = reinterpret_cast<T*>(pointerpointer + 1);
+ referencereference = allocationtarget;
+ std::allocator<T> alloc{};
+ alloc.construct(allocationtarget, std::forward<Args>(args)...);
+ f();
+ return 1;
+ }
+
+ template <typename K, typename... Args>
+ static int push_keyed(lua_State* L, K&& k, Args&&... args) {
+ return push_fx(L, [&L, &k]() {
+ luaL_newmetatable(L, &k[0]);
+ lua_setmetatable(L, -2);
+ }, std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ static int push(lua_State* L, Args&&... args) {
+ return push_keyed(L, usertype_traits<T>::metatable(), std::forward<Args>(args)...);
+ }
+ };
+
+ template <typename T>
+ struct pusher<detail::as_pointer_tag<T>> {
+ template <typename F>
+ static int push_fx(lua_State* L, F&& f, T* obj) {
+ if (obj == nullptr)
+ return stack::push(L, lua_nil);
+ T** pref = static_cast<T**>(lua_newuserdata(L, sizeof(T*)));
+ *pref = obj;
+ f();
+ return 1;
+ }
+
+ template <typename K>
+ static int push_keyed(lua_State* L, K&& k, T* obj) {
+ return push_fx(L, [&L, &k]() {
+ luaL_newmetatable(L, &k[0]);
+ lua_setmetatable(L, -2);
+ }, obj);
+ }
+
+ static int push(lua_State* L, T* obj) {
+ return push_keyed(L, usertype_traits<meta::unqualified_t<T>*>::metatable(), obj);
+ }
+ };
+
+ template <>
+ struct pusher<detail::as_reference_tag> {
+ template <typename T>
+ static int push(lua_State* L, T&& obj) {
+ return stack::push(L, detail::ptr(obj));
+ }
+ };
+
+ template<typename T, typename>
+ struct pusher {
+ template <typename... Args>
+ static int push(lua_State* L, Args&&... args) {
+ return pusher<detail::as_value_tag<T>>{}.push(L, std::forward<Args>(args)...);
+ }
+ };
+
+ template<typename T>
+ struct pusher<T*, meta::disable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<meta::any<std::is_base_of<reference, meta::unqualified_t<T>>, std::is_base_of<stack_reference, meta::unqualified_t<T>>>>>::value>> {
+ template <typename... Args>
+ static int push(lua_State* L, Args&&... args) {
+ return pusher<detail::as_pointer_tag<T>>{}.push(L, std::forward<Args>(args)...);
+ }
+ };
+
+ template<typename T>
+ struct pusher<T, std::enable_if_t<is_unique_usertype<T>::value>> {
+ typedef typename unique_usertype_traits<T>::type P;
+ typedef typename unique_usertype_traits<T>::actual_type Real;
+
+ template <typename Arg, meta::enable<std::is_base_of<Real, meta::unqualified_t<Arg>>> = meta::enabler>
+ static int push(lua_State* L, Arg&& arg) {
+ if (unique_usertype_traits<T>::is_null(arg))
+ return stack::push(L, lua_nil);
+ return push_deep(L, std::forward<Arg>(arg));
+ }
+
+ template <typename Arg0, typename Arg1, typename... Args>
+ static int push(lua_State* L, Arg0&& arg0, Arg0&& arg1, Args&&... args) {
+ return push_deep(L, std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ static int push_deep(lua_State* L, Args&&... args) {
+ P** pref = static_cast<P**>(lua_newuserdata(L, sizeof(P*) + sizeof(detail::special_destruct_func) + sizeof(Real)));
+ detail::special_destruct_func* fx = static_cast<detail::special_destruct_func*>(static_cast<void*>(pref + 1));
+ Real* mem = static_cast<Real*>(static_cast<void*>(fx + 1));
+ *fx = detail::special_destruct<P, Real>;
+ detail::default_construct::construct(mem, std::forward<Args>(args)...);
+ *pref = unique_usertype_traits<T>::get(*mem);
+ if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<P>>::metatable()[0]) == 1) {
+ set_field(L, "__gc", detail::unique_destruct<P>);
+ }
+ lua_setmetatable(L, -2);
+ return 1;
+ }
+ };
+
+ template<typename T>
+ struct pusher<std::reference_wrapper<T>> {
+ static int push(lua_State* L, const std::reference_wrapper<T>& t) {
+ return stack::push(L, std::addressof(detail::deref(t.get())));
+ }
+ };
+
+ template<typename T>
+ struct pusher<T, std::enable_if_t<std::is_floating_point<T>::value>> {
+ static int push(lua_State* L, const T& value) {
+ lua_pushnumber(L, value);
+ return 1;
+ }
+ };
+
+ template<typename T>
+ struct pusher<T, std::enable_if_t<meta::all<std::is_integral<T>, std::is_signed<T>>::value>> {
+ static int push(lua_State* L, const T& value) {
+ lua_pushinteger(L, static_cast<lua_Integer>(value));
+ return 1;
+ }
+ };
+
+ template<typename T>
+ struct pusher<T, std::enable_if_t<std::is_enum<T>::value>> {
+ static int push(lua_State* L, const T& value) {
+ if (std::is_same<char, T>::value) {
+ return stack::push(L, static_cast<int>(value));
+ }
+ return stack::push(L, static_cast<std::underlying_type_t<T>>(value));
+ }
+ };
+
+ template<typename T>
+ struct pusher<T, std::enable_if_t<meta::all<std::is_integral<T>, std::is_unsigned<T>>::value>> {
+ static int push(lua_State* L, const T& value) {
+ lua_pushinteger(L, static_cast<lua_Integer>(value));
+ return 1;
+ }
+ };
+
+ template<typename T>
+ struct pusher<as_table_t<T>, std::enable_if_t<!meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>>::value>> {
+ static int push(lua_State* L, const as_table_t<T>& tablecont) {
+ auto& cont = detail::deref(detail::unwrap(tablecont.source));
+ lua_createtable(L, static_cast<int>(cont.size()), 0);
+ int tableindex = lua_gettop(L);
+ std::size_t index = 1;
+ for (const auto& i : cont) {
+#if SOL_LUA_VERSION >= 503
+ int p = stack::push(L, i);
+ for (int pi = 0; pi < p; ++pi) {
+ lua_seti(L, tableindex, static_cast<lua_Integer>(index++));
+ }
+#else
+ lua_pushinteger(L, static_cast<lua_Integer>(index));
+ int p = stack::push(L, i);
+ if (p == 1) {
+ ++index;
+ lua_settable(L, tableindex);
+ }
+ else {
+ int firstindex = tableindex + 1 + 1;
+ for (int pi = 0; pi < p; ++pi) {
+ stack::push(L, index);
+ lua_pushvalue(L, firstindex);
+ lua_settable(L, tableindex);
+ ++index;
+ ++firstindex;
+ }
+ lua_pop(L, 1 + p);
+ }
+#endif
+ }
+ // TODO: figure out a better way to do this...?
+ //set_field(L, -1, cont.size());
+ return 1;
+ }
+ };
+
+ template<typename T>
+ struct pusher<as_table_t<T>, std::enable_if_t<meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>>::value>> {
+ static int push(lua_State* L, const as_table_t<T>& tablecont) {
+ auto& cont = detail::deref(detail::unwrap(tablecont.source));
+ lua_createtable(L, static_cast<int>(cont.size()), 0);
+ int tableindex = lua_gettop(L);
+ for (const auto& pair : cont) {
+ set_field(L, pair.first, pair.second, tableindex);
+ }
+ return 1;
+ }
+ };
+
+ template<typename T>
+ struct pusher<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> {
+ static int push(lua_State* L, const T& ref) {
+ return ref.push(L);
+ }
+
+ static int push(lua_State* L, T&& ref) {
+ return ref.push(L);
+ }
+ };
+
+ template<>
+ struct pusher<bool> {
+ static int push(lua_State* L, bool b) {
+ lua_pushboolean(L, b);
+ return 1;
+ }
+ };
+
+ template<>
+ struct pusher<lua_nil_t> {
+ static int push(lua_State* L, lua_nil_t) {
+ lua_pushnil(L);
+ return 1;
+ }
+ };
+
+ template<>
+ struct pusher<metatable_key_t> {
+ static int push(lua_State* L, metatable_key_t) {
+ lua_pushlstring(L, "__mt", 4);
+ return 1;
+ }
+ };
+
+ template<>
+ struct pusher<std::remove_pointer_t<lua_CFunction>> {
+ static int push(lua_State* L, lua_CFunction func, int n = 0) {
+ lua_pushcclosure(L, func, n);
+ return 1;
+ }
+ };
+
+ template<>
+ struct pusher<lua_CFunction> {
+ static int push(lua_State* L, lua_CFunction func, int n = 0) {
+ lua_pushcclosure(L, func, n);
+ return 1;
+ }
+ };
+
+ template<>
+ struct pusher<c_closure> {
+ static int push(lua_State* L, c_closure cc) {
+ lua_pushcclosure(L, cc.c_function, cc.upvalues);
+ return 1;
+ }
+ };
+
+ template<typename Arg, typename... Args>
+ struct pusher<closure<Arg, Args...>> {
+ template <std::size_t... I, typename T>
+ static int push(std::index_sequence<I...>, lua_State* L, T&& c) {
+ int pushcount = multi_push(L, detail::forward_get<I>(c.upvalues)...);
+ return stack::push(L, c_closure(c.c_function, pushcount));
+ }
+
+ template <typename T>
+ static int push(lua_State* L, T&& c) {
+ return push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward<T>(c));
+ }
+ };
+
+ template<>
+ struct pusher<void*> {
+ static int push(lua_State* L, void* userdata) {
+ lua_pushlightuserdata(L, userdata);
+ return 1;
+ }
+ };
+
+ template<>
+ struct pusher<lightuserdata_value> {
+ static int push(lua_State* L, lightuserdata_value userdata) {
+ lua_pushlightuserdata(L, userdata);
+ return 1;
+ }
+ };
+
+ template<typename T>
+ struct pusher<light<T>> {
+ static int push(lua_State* L, light<T> l) {
+ lua_pushlightuserdata(L, static_cast<void*>(l.value));
+ return 1;
+ }
+ };
+
+ template<typename T>
+ struct pusher<user<T>> {
+ template <bool with_meta = true, typename Key, typename... Args>
+ static int push_with(lua_State* L, Key&& name, Args&&... args) {
+ // A dumb pusher
+ void* rawdata = lua_newuserdata(L, sizeof(T));
+ T* data = static_cast<T*>(rawdata);
+ std::allocator<T> alloc;
+ alloc.construct(data, std::forward<Args>(args)...);
+ if (with_meta) {
+ lua_CFunction cdel = detail::user_alloc_destroy<T>;
+ // Make sure we have a plain GC set for this data
+ if (luaL_newmetatable(L, name) != 0) {
+ lua_pushcclosure(L, cdel, 0);
+ lua_setfield(L, -2, "__gc");
+ }
+ lua_setmetatable(L, -2);
+ }
+ return 1;
+ }
+
+ template <typename Arg, typename... Args, meta::disable<meta::any_same<meta::unqualified_t<Arg>, no_metatable_t, metatable_key_t>> = meta::enabler>
+ static int push(lua_State* L, Arg&& arg, Args&&... args) {
+ const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
+ return push_with(L, name, std::forward<Arg>(arg), std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ static int push(lua_State* L, no_metatable_t, Args&&... args) {
+ const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
+ return push_with<false>(L, name, std::forward<Args>(args)...);
+ }
+
+ template <typename Key, typename... Args>
+ static int push(lua_State* L, metatable_key_t, Key&& key, Args&&... args) {
+ const auto name = &key[0];
+ return push_with<true>(L, name, std::forward<Args>(args)...);
+ }
+
+ static int push(lua_State* L, const user<T>& u) {
+ const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
+ return push_with(L, name, u.value);
+ }
+
+ static int push(lua_State* L, user<T>&& u) {
+ const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
+ return push_with(L, name, std::move(u.value));
+ }
+
+ static int push(lua_State* L, no_metatable_t, const user<T>& u) {
+ const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
+ return push_with<false>(L, name, u.value);
+ }
+
+ static int push(lua_State* L, no_metatable_t, user<T>&& u) {
+ const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
+ return push_with<false>(L, name, std::move(u.value));
+ }
+ };
+
+ template<>
+ struct pusher<userdata_value> {
+ static int push(lua_State* L, userdata_value data) {
+ void** ud = static_cast<void**>(lua_newuserdata(L, sizeof(void*)));
+ *ud = data.value;
+ return 1;
+ }
+ };
+
+ template<>
+ struct pusher<const char*> {
+ static int push_sized(lua_State* L, const char* str, std::size_t len) {
+ lua_pushlstring(L, str, len);
+ return 1;
+ }
+
+ static int push(lua_State* L, const char* str) {
+ if (str == nullptr)
+ return stack::push(L, lua_nil);
+ return push_sized(L, str, std::char_traits<char>::length(str));
+ }
+
+ static int push(lua_State* L, const char* strb, const char* stre) {
+ return push_sized(L, strb, stre - strb);
+ }
+
+ static int push(lua_State* L, const char* str, std::size_t len) {
+ return push_sized(L, str, len);
+ }
+ };
+
+ template<size_t N>
+ struct pusher<char[N]> {
+ static int push(lua_State* L, const char(&str)[N]) {
+ lua_pushlstring(L, str, N - 1);
+ return 1;
+ }
+
+ static int push(lua_State* L, const char(&str)[N], std::size_t sz) {
+ lua_pushlstring(L, str, sz);
+ return 1;
+ }
+ };
+
+ template <>
+ struct pusher<char> {
+ static int push(lua_State* L, char c) {
+ const char str[2] = { c, '\0' };
+ return stack::push(L, str, 1);
+ }
+ };
+
+ template<>
+ struct pusher<std::string> {
+ static int push(lua_State* L, const std::string& str) {
+ lua_pushlstring(L, str.c_str(), str.size());
+ return 1;
+ }
+
+ static int push(lua_State* L, const std::string& str, std::size_t sz) {
+ lua_pushlstring(L, str.c_str(), sz);
+ return 1;
+ }
+ };
+
+ template<>
+ struct pusher<meta_function> {
+ static int push(lua_State* L, meta_function m) {
+ const std::string& str = name_of(m);
+ lua_pushlstring(L, str.c_str(), str.size());
+ return 1;
+ }
+ };
+
+#ifdef SOL_CODECVT_SUPPORT
+ template<>
+ struct pusher<const wchar_t*> {
+ static int push(lua_State* L, const wchar_t* wstr) {
+ return push(L, wstr, std::char_traits<wchar_t>::length(wstr));
+ }
+
+ static int push(lua_State* L, const wchar_t* wstr, std::size_t sz) {
+ return push(L, wstr, wstr + sz);
+ }
+
+ static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) {
+ if (sizeof(wchar_t) == 2) {
+ static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
+ std::string u8str = convert.to_bytes(strb, stre);
+ return stack::push(L, u8str);
+ }
+ static std::wstring_convert<std::codecvt_utf8<wchar_t>> convert;
+ std::string u8str = convert.to_bytes(strb, stre);
+ return stack::push(L, u8str);
+ }
+ };
+
+ template<>
+ struct pusher<const char16_t*> {
+ static int push(lua_State* L, const char16_t* u16str) {
+ return push(L, u16str, std::char_traits<char16_t>::length(u16str));
+ }
+
+ static int push(lua_State* L, const char16_t* u16str, std::size_t sz) {
+ return push(L, u16str, u16str + sz);
+ }
+
+ static int push(lua_State* L, const char16_t* strb, const char16_t* stre) {
+#ifdef _MSC_VER
+ static std::wstring_convert<std::codecvt_utf8_utf16<int16_t>, int16_t> convert;
+ std::string u8str = convert.to_bytes(reinterpret_cast<const int16_t*>(strb), reinterpret_cast<const int16_t*>(stre));
+#else
+ static std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+ std::string u8str = convert.to_bytes(strb, stre);
+#endif // VC++ is a shit
+ return stack::push(L, u8str);
+ }
+ };
+
+ template<>
+ struct pusher<const char32_t*> {
+ static int push(lua_State* L, const char32_t* u32str) {
+ return push(L, u32str, u32str + std::char_traits<char32_t>::length(u32str));
+ }
+
+ static int push(lua_State* L, const char32_t* u32str, std::size_t sz) {
+ return push(L, u32str, u32str + sz);
+ }
+
+ static int push(lua_State* L, const char32_t* strb, const char32_t* stre) {
+#ifdef _MSC_VER
+ static std::wstring_convert<std::codecvt_utf8<int32_t>, int32_t> convert;
+ std::string u8str = convert.to_bytes(reinterpret_cast<const int32_t*>(strb), reinterpret_cast<const int32_t*>(stre));
+#else
+ static std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
+ std::string u8str = convert.to_bytes(strb, stre);
+#endif // VC++ is a shit
+ return stack::push(L, u8str);
+ }
+ };
+
+ template<size_t N>
+ struct pusher<wchar_t[N]> {
+ static int push(lua_State* L, const wchar_t(&str)[N]) {
+ return push(L, str, N - 1);
+ }
+
+ static int push(lua_State* L, const wchar_t(&str)[N], std::size_t sz) {
+ return stack::push<const wchar_t*>(L, str, str + sz);
+ }
+ };
+
+ template<size_t N>
+ struct pusher<char16_t[N]> {
+ static int push(lua_State* L, const char16_t(&str)[N]) {
+ return push(L, str, N - 1);
+ }
+
+ static int push(lua_State* L, const char16_t(&str)[N], std::size_t sz) {
+ return stack::push<const char16_t*>(L, str, str + sz);
+ }
+ };
+
+ template<size_t N>
+ struct pusher<char32_t[N]> {
+ static int push(lua_State* L, const char32_t(&str)[N]) {
+ return push(L, str, N - 1);
+ }
+
+ static int push(lua_State* L, const char32_t(&str)[N], std::size_t sz) {
+ return stack::push<const char32_t*>(L, str, str + sz);
+ }
+ };
+
+ template <>
+ struct pusher<wchar_t> {
+ static int push(lua_State* L, wchar_t c) {
+ const wchar_t str[2] = { c, '\0' };
+ return stack::push(L, str, 1);
+ }
+ };
+
+ template <>
+ struct pusher<char16_t> {
+ static int push(lua_State* L, char16_t c) {
+ const char16_t str[2] = { c, '\0' };
+ return stack::push(L, str, 1);
+ }
+ };
+
+ template <>
+ struct pusher<char32_t> {
+ static int push(lua_State* L, char32_t c) {
+ const char32_t str[2] = { c, '\0' };
+ return stack::push(L, str, 1);
+ }
+ };
+
+ template<>
+ struct pusher<std::wstring> {
+ static int push(lua_State* L, const std::wstring& wstr) {
+ return push(L, wstr.data(), wstr.size());
+ }
+
+ static int push(lua_State* L, const std::wstring& wstr, std::size_t sz) {
+ return stack::push(L, wstr.data(), wstr.data() + sz);
+ }
+ };
+
+ template<>
+ struct pusher<std::u16string> {
+ static int push(lua_State* L, const std::u16string& u16str) {
+ return push(L, u16str, u16str.size());
+ }
+
+ static int push(lua_State* L, const std::u16string& u16str, std::size_t sz) {
+ return stack::push(L, u16str.data(), u16str.data() + sz);
+ }
+ };
+
+ template<>
+ struct pusher<std::u32string> {
+ static int push(lua_State* L, const std::u32string& u32str) {
+ return push(L, u32str, u32str.size());
+ }
+
+ static int push(lua_State* L, const std::u32string& u32str, std::size_t sz) {
+ return stack::push(L, u32str.data(), u32str.data() + sz);
+ }
+ };
+#endif // codecvt Header Support
+
+ template<typename... Args>
+ struct pusher<std::tuple<Args...>> {
+ template <std::size_t... I, typename T>
+ static int push(std::index_sequence<I...>, lua_State* L, T&& t) {
+ int pushcount = 0;
+ (void)detail::swallow{ 0, (pushcount += stack::push(L,
+ detail::forward_get<I>(t)
+ ), 0)... };
+ return pushcount;
+ }
+
+ template <typename T>
+ static int push(lua_State* L, T&& t) {
+ return push(std::index_sequence_for<Args...>(), L, std::forward<T>(t));
+ }
+ };
+
+ template<typename A, typename B>
+ struct pusher<std::pair<A, B>> {
+ template <typename T>
+ static int push(lua_State* L, T&& t) {
+ int pushcount = stack::push(L, detail::forward_get<0>(t));
+ pushcount += stack::push(L, detail::forward_get<1>(t));
+ return pushcount;
+ }
+ };
+
+ template<typename O>
+ struct pusher<optional<O>> {
+ template <typename T>
+ static int push(lua_State* L, T&& t) {
+ if (t == nullopt) {
+ return stack::push(L, nullopt);
+ }
+ return stack::push(L, t.value());
+ }
+ };
+
+ template<>
+ struct pusher<nullopt_t> {
+ static int push(lua_State* L, nullopt_t) {
+ return stack::push(L, lua_nil);
+ }
+ };
+
+ template<>
+ struct pusher<std::nullptr_t> {
+ static int push(lua_State* L, std::nullptr_t) {
+ return stack::push(L, lua_nil);
+ }
+ };
+
+ template<>
+ struct pusher<this_state> {
+ static int push(lua_State*, const this_state&) {
+ return 0;
+ }
+ };
+ } // stack
+} // sol
+
+// end of sol/stack_push.hpp
+
+// beginning of sol/stack_pop.hpp
+
+namespace sol {
+ namespace stack {
+ template <typename T, typename>
+ struct popper {
+ inline static decltype(auto) pop(lua_State* L) {
+ record tracking{};
+ decltype(auto) r = get<T>(L, -lua_size<T>::value, tracking);
+ lua_pop(L, tracking.used);
+ return r;
+ }
+ };
+
+ template <typename T>
+ struct popper<T, std::enable_if_t<std::is_base_of<stack_reference, meta::unqualified_t<T>>::value>> {
+ static_assert(meta::neg<std::is_base_of<stack_reference, meta::unqualified_t<T>>>::value, "You cannot pop something that derives from stack_reference: it will not remain on the stack and thusly will go out of scope!");
+ };
+ } // stack
+} // sol
+
+// end of sol/stack_pop.hpp
+
+// beginning of sol/stack_field.hpp
+
+namespace sol {
+ namespace stack {
+ template <typename T, bool, bool, typename>
+ struct field_getter {
+ template <typename Key>
+ void get(lua_State* L, Key&& key, int tableindex = -2) {
+ push(L, std::forward<Key>(key));
+ lua_gettable(L, tableindex);
+ }
+ };
+
+ template <typename T, bool global, typename C>
+ struct field_getter<T, global, true, C> {
+ template <typename Key>
+ void get(lua_State* L, Key&& key, int tableindex = -2) {
+ push(L, std::forward<Key>(key));
+ lua_rawget(L, tableindex);
+ }
+ };
+
+ template <bool b, bool raw, typename C>
+ struct field_getter<metatable_key_t, b, raw, C> {
+ void get(lua_State* L, metatable_key_t, int tableindex = -1) {
+ if (lua_getmetatable(L, tableindex) == 0)
+ push(L, lua_nil);
+ }
+ };
+
+ template <typename T, bool raw>
+ struct field_getter<T, true, raw, std::enable_if_t<meta::is_c_str<T>::value>> {
+ template <typename Key>
+ void get(lua_State* L, Key&& key, int = -1) {
+ lua_getglobal(L, &key[0]);
+ }
+ };
+
+ template <typename T>
+ struct field_getter<T, false, false, std::enable_if_t<meta::is_c_str<T>::value>> {
+ template <typename Key>
+ void get(lua_State* L, Key&& key, int tableindex = -1) {
+ lua_getfield(L, tableindex, &key[0]);
+ }
+ };
+
+#if SOL_LUA_VERSION >= 503
+ template <typename T>
+ struct field_getter<T, false, false, std::enable_if_t<std::is_integral<T>::value>> {
+ template <typename Key>
+ void get(lua_State* L, Key&& key, int tableindex = -1) {
+ lua_geti(L, tableindex, static_cast<lua_Integer>(key));
+ }
+ };
+#endif // Lua 5.3.x
+
+#if SOL_LUA_VERSION >= 502
+ template <typename C>
+ struct field_getter<void*, false, true, C> {
+ void get(lua_State* L, void* key, int tableindex = -1) {
+ lua_rawgetp(L, tableindex, key);
+ }
+ };
+#endif // Lua 5.3.x
+
+ template <typename T>
+ struct field_getter<T, false, true, std::enable_if_t<std::is_integral<T>::value>> {
+ template <typename Key>
+ void get(lua_State* L, Key&& key, int tableindex = -1) {
+ lua_rawgeti(L, tableindex, static_cast<lua_Integer>(key));
+ }
+ };
+
+ template <typename... Args, bool b, bool raw, typename C>
+ struct field_getter<std::tuple<Args...>, b, raw, C> {
+ template <std::size_t... I, typename Keys>
+ void apply(std::index_sequence<0, I...>, lua_State* L, Keys&& keys, int tableindex) {
+ get_field<b, raw>(L, detail::forward_get<0>(keys), tableindex);
+ void(detail::swallow{ (get_field<false, raw>(L, detail::forward_get<I>(keys)), 0)... });
+ reference saved(L, -1);
+ lua_pop(L, static_cast<int>(sizeof...(I)));
+ saved.push();
+ }
+
+ template <typename Keys>
+ void get(lua_State* L, Keys&& keys) {
+ apply(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), lua_absindex(L, -1));
+ }
+
+ template <typename Keys>
+ void get(lua_State* L, Keys&& keys, int tableindex) {
+ apply(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), tableindex);
+ }
+ };
+
+ template <typename A, typename B, bool b, bool raw, typename C>
+ struct field_getter<std::pair<A, B>, b, raw, C> {
+ template <typename Keys>
+ void get(lua_State* L, Keys&& keys, int tableindex) {
+ get_field<b, raw>(L, detail::forward_get<0>(keys), tableindex);
+ get_field<false, raw>(L, detail::forward_get<1>(keys));
+ reference saved(L, -1);
+ lua_pop(L, static_cast<int>(2));
+ saved.push();
+ }
+
+ template <typename Keys>
+ void get(lua_State* L, Keys&& keys) {
+ get_field<b, raw>(L, detail::forward_get<0>(keys));
+ get_field<false, raw>(L, detail::forward_get<1>(keys));
+ reference saved(L, -1);
+ lua_pop(L, static_cast<int>(2));
+ saved.push();
+ }
+ };
+
+ template <typename T, bool, bool, typename>
+ struct field_setter {
+ template <typename Key, typename Value>
+ void set(lua_State* L, Key&& key, Value&& value, int tableindex = -3) {
+ push(L, std::forward<Key>(key));
+ push(L, std::forward<Value>(value));
+ lua_settable(L, tableindex);
+ }
+ };
+
+ template <typename T, bool b, typename C>
+ struct field_setter<T, b, true, C> {
+ template <typename Key, typename Value>
+ void set(lua_State* L, Key&& key, Value&& value, int tableindex = -3) {
+ push(L, std::forward<Key>(key));
+ push(L, std::forward<Value>(value));
+ lua_rawset(L, tableindex);
+ }
+ };
+
+ template <bool b, bool raw, typename C>
+ struct field_setter<metatable_key_t, b, raw, C> {
+ template <typename Value>
+ void set(lua_State* L, metatable_key_t, Value&& value, int tableindex = -2) {
+ push(L, std::forward<Value>(value));
+ lua_setmetatable(L, tableindex);
+ }
+ };
+
+ template <typename T, bool raw>
+ struct field_setter<T, true, raw, std::enable_if_t<meta::is_c_str<T>::value>> {
+ template <typename Key, typename Value>
+ void set(lua_State* L, Key&& key, Value&& value, int = -2) {
+ push(L, std::forward<Value>(value));
+ lua_setglobal(L, &key[0]);
+ }
+ };
+
+ template <typename T>
+ struct field_setter<T, false, false, std::enable_if_t<meta::is_c_str<T>::value>> {
+ template <typename Key, typename Value>
+ void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) {
+ push(L, std::forward<Value>(value));
+ lua_setfield(L, tableindex, &key[0]);
+ }
+ };
+
+#if SOL_LUA_VERSION >= 503
+ template <typename T>
+ struct field_setter<T, false, false, std::enable_if_t<std::is_integral<T>::value>> {
+ template <typename Key, typename Value>
+ void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) {
+ push(L, std::forward<Value>(value));
+ lua_seti(L, tableindex, static_cast<lua_Integer>(key));
+ }
+ };
+#endif // Lua 5.3.x
+
+ template <typename T>
+ struct field_setter<T, false, true, std::enable_if_t<std::is_integral<T>::value>> {
+ template <typename Key, typename Value>
+ void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) {
+ push(L, std::forward<Value>(value));
+ lua_rawseti(L, tableindex, static_cast<lua_Integer>(key));
+ }
+ };
+
+#if SOL_LUA_VERSION >= 502
+ template <typename C>
+ struct field_setter<void*, false, true, C> {
+ template <typename Key, typename Value>
+ void set(lua_State* L, void* key, Value&& value, int tableindex = -2) {
+ push(L, std::forward<Value>(value));
+ lua_rawsetp(L, tableindex, key);
+ }
+ };
+#endif // Lua 5.2.x
+
+ template <typename... Args, bool b, bool raw, typename C>
+ struct field_setter<std::tuple<Args...>, b, raw, C> {
+ template <bool g, std::size_t I, typename Key, typename Value>
+ void apply(std::index_sequence<I>, lua_State* L, Key&& keys, Value&& value, int tableindex) {
+ I < 1 ?
+ set_field<g, raw>(L, detail::forward_get<I>(keys), std::forward<Value>(value), tableindex) :
+ set_field<g, raw>(L, detail::forward_get<I>(keys), std::forward<Value>(value));
+ }
+
+ template <bool g, std::size_t I0, std::size_t I1, std::size_t... I, typename Keys, typename Value>
+ void apply(std::index_sequence<I0, I1, I...>, lua_State* L, Keys&& keys, Value&& value, int tableindex) {
+ I0 < 1 ? get_field<g, raw>(L, detail::forward_get<I0>(keys), tableindex) : get_field<g, raw>(L, detail::forward_get<I0>(keys), -1);
+ apply<false>(std::index_sequence<I1, I...>(), L, std::forward<Keys>(keys), std::forward<Value>(value), -1);
+ }
+
+ template <bool g, std::size_t I0, std::size_t... I, typename Keys, typename Value>
+ void top_apply(std::index_sequence<I0, I...>, lua_State* L, Keys&& keys, Value&& value, int tableindex) {
+ apply<g>(std::index_sequence<I0, I...>(), L, std::forward<Keys>(keys), std::forward<Value>(value), tableindex);
+ lua_pop(L, static_cast<int>(sizeof...(I)));
+ }
+
+ template <typename Keys, typename Value>
+ void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -3) {
+ top_apply<b>(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), std::forward<Value>(value), tableindex);
+ }
+ };
+
+ template <typename A, typename B, bool b, bool raw, typename C>
+ struct field_setter<std::pair<A, B>, b, raw, C> {
+ template <typename Keys, typename Value>
+ void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -1) {
+ get_field<b, raw>(L, detail::forward_get<0>(keys), tableindex);
+ set_field<false, raw>(L, detail::forward_get<1>(keys), std::forward<Value>(value));
+ lua_pop(L, 1);
+ }
+ };
+ } // stack
+} // sol
+
+// end of sol/stack_field.hpp
+
+// beginning of sol/stack_probe.hpp
+
+namespace sol {
+ namespace stack {
+ template <typename T, bool b, bool raw, typename>
+ struct probe_field_getter {
+ template <typename Key>
+ probe get(lua_State* L, Key&& key, int tableindex = -2) {
+ if (!b && !maybe_indexable(L, tableindex)) {
+ return probe(false, 0);
+ }
+ get_field<b, raw>(L, std::forward<Key>(key), tableindex);
+ return probe(!check<lua_nil_t>(L), 1);
+ }
+ };
+
+ template <typename A, typename B, bool b, bool raw, typename C>
+ struct probe_field_getter<std::pair<A, B>, b, raw, C> {
+ template <typename Keys>
+ probe get(lua_State* L, Keys&& keys, int tableindex = -2) {
+ if (!b && !maybe_indexable(L, tableindex)) {
+ return probe(false, 0);
+ }
+ get_field<b, raw>(L, std::get<0>(keys), tableindex);
+ if (!maybe_indexable(L)) {
+ return probe(false, 1);
+ }
+ get_field<false, raw>(L, std::get<1>(keys), tableindex);
+ return probe(!check<lua_nil_t>(L), 2);
+ }
+ };
+
+ template <typename... Args, bool b, bool raw, typename C>
+ struct probe_field_getter<std::tuple<Args...>, b, raw, C> {
+ template <std::size_t I, typename Keys>
+ probe apply(std::index_sequence<I>, int sofar, lua_State* L, Keys&& keys, int tableindex) {
+ get_field < I < 1 && b, raw>(L, std::get<I>(keys), tableindex);
+ return probe(!check<lua_nil_t>(L), sofar);
+ }
+
+ template <std::size_t I, std::size_t I1, std::size_t... In, typename Keys>
+ probe apply(std::index_sequence<I, I1, In...>, int sofar, lua_State* L, Keys&& keys, int tableindex) {
+ get_field < I < 1 && b, raw>(L, std::get<I>(keys), tableindex);
+ if (!maybe_indexable(L)) {
+ return probe(false, sofar);
+ }
+ return apply(std::index_sequence<I1, In...>(), sofar + 1, L, std::forward<Keys>(keys), -1);
+ }
+
+ template <typename Keys>
+ probe get(lua_State* L, Keys&& keys, int tableindex = -2) {
+ if (!b && !maybe_indexable(L, tableindex)) {
+ return probe(false, 0);
+ }
+ return apply(std::index_sequence_for<Args...>(), 1, L, std::forward<Keys>(keys), tableindex);
+ }
+ };
+ } // stack
+} // sol
+
+// end of sol/stack_probe.hpp
+
+#include <cstring>
+
+namespace sol {
+ namespace stack {
+ namespace stack_detail {
+ template<typename T>
+ inline int push_as_upvalues(lua_State* L, T& item) {
+ typedef std::decay_t<T> TValue;
+ const static std::size_t itemsize = sizeof(TValue);
+ const static std::size_t voidsize = sizeof(void*);
+ const static std::size_t voidsizem1 = voidsize - 1;
+ const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize;
+ typedef std::array<void*, data_t_count> data_t;
+
+ data_t data{ {} };
+ std::memcpy(&data[0], std::addressof(item), itemsize);
+ int pushcount = 0;
+ for (auto&& v : data) {
+ pushcount += push(L, lightuserdata_value(v));
+ }
+ return pushcount;
+ }
+
+ template<typename T>
+ inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 1) {
+ const static std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*);
+ typedef std::array<void*, data_t_count> data_t;
+ data_t voiddata{ {} };
+ for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) {
+ voiddata[i] = get<lightuserdata_value>(L, upvalue_index(index++));
+ }
+ return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
+ }
+
+ struct evaluator {
+ template <typename Fx, typename... Args>
+ static decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, record&, Fx&& fx, Args&&... args) {
+ return std::forward<Fx>(fx)(std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename Arg, typename... Args, std::size_t I, std::size_t... Is, typename... FxArgs>
+ static decltype(auto) eval(types<Arg, Args...>, std::index_sequence<I, Is...>, lua_State* L, int start, record& tracking, Fx&& fx, FxArgs&&... fxargs) {
+ return eval(types<Args...>(), std::index_sequence<Is...>(), L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)..., stack_detail::unchecked_get<Arg>(L, start + tracking.used, tracking));
+ }
+ };
+
+ template <bool checkargs = default_check_arguments, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
+ inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
+#ifndef _MSC_VER
+ static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention.");
+#endif // This compiler make me so fucking sad
+ multi_check<checkargs, Args...>(L, start, type_panic);
+ record tracking{};
+ return evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
+ }
+
+ template <bool checkargs = default_check_arguments, std::size_t... I, typename... Args, typename Fx, typename... FxArgs>
+ inline void call(types<void>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
+#ifndef _MSC_VER
+ static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention.");
+#endif // This compiler make me so fucking sad
+ multi_check<checkargs, Args...>(L, start, type_panic);
+ record tracking{};
+ evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
+ }
+ } // stack_detail
+
+ template <typename T>
+ int set_ref(lua_State* L, T&& arg, int tableindex = -2) {
+ push(L, std::forward<T>(arg));
+ return luaL_ref(L, tableindex);
+ }
+
+ inline void remove(lua_State* L, int index, int count) {
+ if (count < 1)
+ return;
+ int top = lua_gettop(L);
+ if (index == -1 || top == index) {
+ // Slice them right off the top
+ lua_pop(L, static_cast<int>(count));
+ return;
+ }
+
+ // Remove each item one at a time using stack operations
+ // Probably slower, maybe, haven't benchmarked,
+ // but necessary
+ if (index < 0) {
+ index = lua_gettop(L) + (index + 1);
+ }
+ int last = index + count;
+ for (int i = index; i < last; ++i) {
+ lua_remove(L, index);
+ }
+ }
+
+ template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
+ inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
+ typedef std::make_index_sequence<sizeof...(Args)> args_indices;
+ return stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
+ }
+
+ template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
+ inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
+ return call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
+ }
+
+ template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
+ inline void call(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
+ typedef std::make_index_sequence<sizeof...(Args)> args_indices;
+ stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
+ }
+
+ template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
+ inline void call(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
+ call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
+ }
+
+ template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
+ inline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
+ return call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
+ }
+
+ template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
+ inline void call_from_top(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
+ call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
+ }
+
+ template<bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
+ inline int call_into_lua(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
+ call<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
+ lua_settop(L, 0);
+ return 0;
+ }
+
+ template<bool check_args = stack_detail::default_check_arguments, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::neg<std::is_void<Ret0>>::value>>
+ inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
+ decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
+ lua_settop(L, 0);
+ return push_reference(L, std::forward<decltype(r)>(r));
+ }
+
+ template<bool check_args = stack_detail::default_check_arguments, typename Fx, typename... FxArgs>
+ inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
+ typedef lua_bind_traits<meta::unqualified_t<Fx>> traits_type;
+ typedef typename traits_type::args_list args_list;
+ typedef typename traits_type::returns_list returns_list;
+ return call_into_lua(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
+ }
+
+ inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) {
+ if (lua_gettop(L) == 0) {
+ return call_syntax::dot;
+ }
+ luaL_getmetatable(L, key.c_str());
+ auto pn = pop_n(L, 1);
+ if (lua_compare(L, -1, index, LUA_OPEQ) != 1) {
+ return call_syntax::dot;
+ }
+ return call_syntax::colon;
+ }
+
+ inline void script(lua_State* L, const std::string& code) {
+ if (luaL_dostring(L, code.c_str())) {
+ lua_error(L);
+ }
+ }
+
+ inline void script_file(lua_State* L, const std::string& filename) {
+ if (luaL_dofile(L, filename.c_str())) {
+ lua_error(L);
+ }
+ }
+
+ inline void luajit_exception_handler(lua_State* L, int(*handler)(lua_State*, lua_CFunction) = detail::c_trampoline) {
+#ifdef SOL_LUAJIT
+ lua_pushlightuserdata(L, (void*)handler);
+ auto pn = pop_n(L, 1);
+ luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON);
+#else
+ (void)L;
+ (void)handler;
+#endif
+ }
+
+ inline void luajit_exception_off(lua_State* L) {
+#ifdef SOL_LUAJIT
+ luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_OFF);
+#else
+ (void)L;
+#endif
+ }
+ } // stack
+} // sol
+
+// end of sol/stack.hpp
+
+// beginning of sol/as_args.hpp
+
+namespace sol {
+ template <typename T>
+ struct to_args_t {
+ T src;
+ };
+
+ template <typename Source>
+ auto as_args(Source&& source) {
+ return to_args_t<Source>{ std::forward<Source>(source) };
+ }
+
+ namespace stack {
+ template <typename T>
+ struct pusher<to_args_t<T>> {
+ int push(lua_State* L, const to_args_t<T>& e) {
+ int p = 0;
+ for (const auto& i : e.src) {
+ p += stack::push(L, i);
+ }
+ return p;
+ }
+ };
+ }
+} // sol
+
+// end of sol/as_args.hpp
+
+// beginning of sol/variadic_args.hpp
+
+// beginning of sol/stack_proxy.hpp
+
+// beginning of sol/function.hpp
+
+// beginning of sol/function_result.hpp
+
+// beginning of sol/proxy_base.hpp
+
+namespace sol {
+ template <typename Super>
+ struct proxy_base {
+ operator std::string() const {
+ const Super& super = *static_cast<const Super*>(static_cast<const void*>(this));
+ return super.template get<std::string>();
+ }
+
+ template<typename T, meta::enable<meta::neg<meta::is_string_constructible<T>>, is_proxy_primitive<meta::unqualified_t<T>>> = meta::enabler>
+ operator T () const {
+ const Super& super = *static_cast<const Super*>(static_cast<const void*>(this));
+ return super.template get<T>();
+ }
+
+ template<typename T, meta::enable<meta::neg<meta::is_string_constructible<T>>, meta::neg<is_proxy_primitive<meta::unqualified_t<T>>>> = meta::enabler>
+ operator T& () const {
+ const Super& super = *static_cast<const Super*>(static_cast<const void*>(this));
+ return super.template get<T&>();
+ }
+ };
+} // sol
+
+// end of sol/proxy_base.hpp
+
+#include <cstdint>
+
+namespace sol {
+ struct function_result : public proxy_base<function_result> {
+ private:
+ lua_State* L;
+ int index;
+ int returncount;
+
+ public:
+ function_result() = default;
+ function_result(lua_State* Ls, int idx = -1, int retnum = 0) : L(Ls), index(idx), returncount(retnum) {
+
+ }
+ function_result(const function_result&) = default;
+ function_result& operator=(const function_result&) = default;
+ function_result(function_result&& o) : L(o.L), index(o.index), returncount(o.returncount) {
+ // Must be manual, otherwise destructor will screw us
+ // return count being 0 is enough to keep things clean
+ // but will be thorough
+ o.L = nullptr;
+ o.index = 0;
+ o.returncount = 0;
+ }
+ function_result& operator=(function_result&& o) {
+ L = o.L;
+ index = o.index;
+ returncount = o.returncount;
+ // Must be manual, otherwise destructor will screw us
+ // return count being 0 is enough to keep things clean
+ // but will be thorough
+ o.L = nullptr;
+ o.index = 0;
+ o.returncount = 0;
+ return *this;
+ }
+
+ template<typename T>
+ decltype(auto) get() const {
+ return stack::get<T>(L, index);
+ }
+
+ call_status status() const noexcept {
+ return call_status::ok;
+ }
+
+ bool valid() const noexcept {
+ return status() == call_status::ok || status() == call_status::yielded;
+ }
+
+ lua_State* lua_state() const { return L; };
+ int stack_index() const { return index; };
+
+ ~function_result() {
+ lua_pop(L, returncount);
+ }
+ };
+} // sol
+
+// end of sol/function_result.hpp
+
+// beginning of sol/function_types.hpp
+
+// beginning of sol/function_types_core.hpp
+
+// beginning of sol/wrapper.hpp
+
+namespace sol {
+
+ template <typename F, typename = void>
+ struct wrapper {
+ typedef lua_bind_traits<F> traits_type;
+ typedef typename traits_type::args_list args_list;
+ typedef typename traits_type::args_list free_args_list;
+ typedef typename traits_type::returns_list returns_list;
+
+ template <typename... Args>
+ static decltype(auto) call(F& f, Args&&... args) {
+ return f(std::forward<Args>(args)...);
+ }
+
+ struct caller {
+ template <typename... Args>
+ decltype(auto) operator()(F& fx, Args&&... args) const {
+ return call(fx, std::forward<Args>(args)...);
+ }
+ };
+ };
+
+ template <typename F>
+ struct wrapper<F, std::enable_if_t<std::is_function<meta::unqualified_t<std::remove_pointer_t<F>>>::value>> {
+ typedef lua_bind_traits<F> traits_type;
+ typedef typename traits_type::args_list args_list;
+ typedef typename traits_type::args_list free_args_list;
+ typedef typename traits_type::returns_list returns_list;
+
+ template <F fx, typename... Args>
+ static decltype(auto) invoke(Args&&... args) {
+ return fx(std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ static decltype(auto) call(F& fx, Args&&... args) {
+ return fx(std::forward<Args>(args)...);
+ }
+
+ struct caller {
+ template <typename... Args>
+ decltype(auto) operator()(F& fx, Args&&... args) const {
+ return call(fx, std::forward<Args>(args)...);
+ }
+ };
+
+ template <F fx>
+ struct invoker {
+ template <typename... Args>
+ decltype(auto) operator()(Args&&... args) const {
+ return invoke<fx>(std::forward<Args>(args)...);
+ }
+ };
+ };
+
+ template <typename F>
+ struct wrapper<F, std::enable_if_t<std::is_member_object_pointer<meta::unqualified_t<F>>::value>> {
+ typedef lua_bind_traits<F> traits_type;
+ typedef typename traits_type::object_type object_type;
+ typedef typename traits_type::return_type return_type;
+ typedef typename traits_type::args_list args_list;
+ typedef types<object_type&, return_type> free_args_list;
+ typedef typename traits_type::returns_list returns_list;
+
+ template <F fx, typename... Args>
+ static decltype(auto) invoke(object_type& mem, Args&&... args) {
+ return (mem.*fx)(std::forward<Args>(args)...);
+ }
+
+ template <typename Fx>
+ static decltype(auto) call(Fx&& fx, object_type& mem) {
+ return (mem.*fx);
+ }
+
+ template <typename Fx, typename Arg, typename... Args>
+ static void call(Fx&& fx, object_type& mem, Arg&& arg, Args&&...) {
+ (mem.*fx) = std::forward<Arg>(arg);
+ }
+
+ struct caller {
+ template <typename Fx, typename... Args>
+ decltype(auto) operator()(Fx&& fx, object_type& mem, Args&&... args) const {
+ return call(std::forward<Fx>(fx), mem, std::forward<Args>(args)...);
+ }
+ };
+
+ template <F fx>
+ struct invoker {
+ template <typename... Args>
+ decltype(auto) operator()(Args&&... args) const {
+ return invoke<fx>(std::forward<Args>(args)...);
+ }
+ };
+ };
+
+ template <typename F, typename R, typename O, typename... FArgs>
+ struct member_function_wrapper {
+ typedef O object_type;
+ typedef lua_bind_traits<F> traits_type;
+ typedef typename traits_type::args_list args_list;
+ typedef types<object_type&, FArgs...> free_args_list;
+ typedef meta::tuple_types<R> returns_list;
+
+ template <F fx, typename... Args>
+ static R invoke(O& mem, Args&&... args) {
+ return (mem.*fx)(std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename... Args>
+ static R call(Fx&& fx, O& mem, Args&&... args) {
+ return (mem.*fx)(std::forward<Args>(args)...);
+ }
+
+ struct caller {
+ template <typename Fx, typename... Args>
+ decltype(auto) operator()(Fx&& fx, O& mem, Args&&... args) const {
+ return call(std::forward<Fx>(fx), mem, std::forward<Args>(args)...);
+ }
+ };
+
+ template <F fx>
+ struct invoker {
+ template <typename... Args>
+ decltype(auto) operator()(O& mem, Args&&... args) const {
+ return invoke<fx>(mem, std::forward<Args>(args)...);
+ }
+ };
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args...)> : public member_function_wrapper<R(O:: *)(Args...), R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args...) const> : public member_function_wrapper<R(O:: *)(Args...) const, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args...) const volatile> : public member_function_wrapper<R(O:: *)(Args...) const volatile, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args...) &> : public member_function_wrapper<R(O:: *)(Args...) &, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args...) const &> : public member_function_wrapper<R(O:: *)(Args...) const &, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args...) const volatile &> : public member_function_wrapper<R(O:: *)(Args...) const volatile &, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args..., ...) &> : public member_function_wrapper<R(O:: *)(Args..., ...) &, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args..., ...) const &> : public member_function_wrapper<R(O:: *)(Args..., ...) const &, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args..., ...) const volatile &> : public member_function_wrapper<R(O:: *)(Args..., ...) const volatile &, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args...) && > : public member_function_wrapper<R(O:: *)(Args...) &, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args...) const &&> : public member_function_wrapper<R(O:: *)(Args...) const &, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args...) const volatile &&> : public member_function_wrapper<R(O:: *)(Args...) const volatile &, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args..., ...) && > : public member_function_wrapper<R(O:: *)(Args..., ...) &, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args..., ...) const &&> : public member_function_wrapper<R(O:: *)(Args..., ...) const &, R, O, Args...> {
+
+ };
+
+ template <typename R, typename O, typename... Args>
+ struct wrapper<R(O:: *)(Args..., ...) const volatile &&> : public member_function_wrapper<R(O:: *)(Args..., ...) const volatile &, R, O, Args...> {
+
+ };
+
+} // sol
+
+// end of sol/wrapper.hpp
+
+namespace sol {
+ namespace function_detail {
+ template <typename Fx>
+ inline int call(lua_State* L) {
+ Fx& fx = stack::get<user<Fx>>(L, upvalue_index(1));
+ return fx(L);
+ }
+ } // function_detail
+} // sol
+
+// end of sol/function_types_core.hpp
+
+// beginning of sol/function_types_templated.hpp
+
+// beginning of sol/call.hpp
+
+// beginning of sol/protect.hpp
+
+namespace sol {
+
+ template <typename T>
+ struct protect_t {
+ T value;
+
+ template <typename Arg, typename... Args, meta::disable<std::is_same<protect_t, meta::unqualified_t<Arg>>> = meta::enabler>
+ protect_t(Arg&& arg, Args&&... args) : value(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
+
+ protect_t(const protect_t&) = default;
+ protect_t(protect_t&&) = default;
+ protect_t& operator=(const protect_t&) = default;
+ protect_t& operator=(protect_t&&) = default;
+
+ };
+
+ template <typename T>
+ auto protect(T&& value) {
+ return protect_t<std::decay_t<T>>(std::forward<T>(value));
+ }
+
+} // sol
+
+// end of sol/protect.hpp
+
+// beginning of sol/property.hpp
+
+namespace sol {
+
+ struct no_prop { };
+
+ template <typename R, typename W>
+ struct property_wrapper {
+ typedef std::integral_constant<bool, !std::is_void<R>::value> can_read;
+ typedef std::integral_constant<bool, !std::is_void<W>::value> can_write;
+ typedef std::conditional_t<can_read::value, R, no_prop> Read;
+ typedef std::conditional_t<can_write::value, W, no_prop> Write;
+ Read read;
+ Write write;
+
+ template <typename Rx, typename Wx>
+ property_wrapper(Rx&& r, Wx&& w) : read(std::forward<Rx>(r)), write(std::forward<Wx>(w)) {}
+ };
+
+ namespace property_detail {
+ template <typename R, typename W>
+ inline decltype(auto) property(std::true_type, R&& read, W&& write) {
+ return property_wrapper<std::decay_t<R>, std::decay_t<W>>(std::forward<R>(read), std::forward<W>(write));
+ }
+ template <typename W, typename R>
+ inline decltype(auto) property(std::false_type, W&& write, R&& read) {
+ return property_wrapper<std::decay_t<R>, std::decay_t<W>>(std::forward<R>(read), std::forward<W>(write));
+ }
+ template <typename R>
+ inline decltype(auto) property(std::true_type, R&& read) {
+ return property_wrapper<std::decay_t<R>, void>(std::forward<R>(read), no_prop());
+ }
+ template <typename W>
+ inline decltype(auto) property(std::false_type, W&& write) {
+ return property_wrapper<void, std::decay_t<W>>(no_prop(), std::forward<W>(write));
+ }
+ } // property_detail
+
+ template <typename F, typename G>
+ inline decltype(auto) property(F&& f, G&& g) {
+ typedef lua_bind_traits<meta::unqualified_t<F>> left_traits;
+ typedef lua_bind_traits<meta::unqualified_t<G>> right_traits;
+ return property_detail::property(meta::boolean<(left_traits::free_arity < right_traits::free_arity)>(), std::forward<F>(f), std::forward<G>(g));
+ }
+
+ template <typename F>
+ inline decltype(auto) property(F&& f) {
+ typedef lua_bind_traits<meta::unqualified_t<F>> left_traits;
+ return property_detail::property(meta::boolean<(left_traits::free_arity < 2)>(), std::forward<F>(f));
+ }
+
+ template <typename F>
+ inline decltype(auto) readonly_property(F&& f) {
+ return property_detail::property(std::true_type(), std::forward<F>(f));
+ }
+
+ // Allow someone to make a member variable readonly (const)
+ template <typename R, typename T>
+ inline auto readonly(R T::* v) {
+ typedef const R C;
+ return static_cast<C T::*>(v);
+ }
+
+ template <typename T>
+ struct var_wrapper {
+ T value;
+ template <typename... Args>
+ var_wrapper(Args&&... args) : value(std::forward<Args>(args)...) {}
+ var_wrapper(const var_wrapper&) = default;
+ var_wrapper(var_wrapper&&) = default;
+ var_wrapper& operator=(const var_wrapper&) = default;
+ var_wrapper& operator=(var_wrapper&&) = default;
+ };
+
+ template <typename V>
+ inline auto var(V&& v) {
+ typedef meta::unqualified_t<V> T;
+ return var_wrapper<T>(std::forward<V>(v));
+ }
+
+} // sol
+
+// end of sol/property.hpp
+
+namespace sol {
+ namespace function_detail {
+ inline int no_construction_error(lua_State* L) {
+ return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)");
+ }
+ }
+
+ namespace call_detail {
+
+ template <typename R, typename W>
+ inline auto& pick(std::true_type, property_wrapper<R, W>& f) {
+ return f.read;
+ }
+
+ template <typename R, typename W>
+ inline auto& pick(std::false_type, property_wrapper<R, W>& f) {
+ return f.write;
+ }
+
+ template <typename T, typename List>
+ struct void_call : void_call<T, meta::function_args_t<List>> {};
+
+ template <typename T, typename... Args>
+ struct void_call<T, types<Args...>> {
+ static void call(Args...) {}
+ };
+
+ template <typename T>
+ struct constructor_match {
+ T* obj;
+
+ constructor_match(T* o) : obj(o) {}
+
+ template <typename Fx, std::size_t I, typename... R, typename... Args>
+ int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
+ detail::default_construct func{};
+ return stack::call_into_lua<stack::stack_detail::default_check_arguments>(r, a, L, start, func, obj);
+ }
+ };
+
+ namespace overload_detail {
+ template <std::size_t... M, typename Match, typename... Args>
+ inline int overload_match_arity(types<>, std::index_sequence<>, std::index_sequence<M...>, Match&&, lua_State* L, int, int, Args&&...) {
+ return luaL_error(L, "sol: no matching function call takes this number of arguments and the specified types");
+ }
+
+ template <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args>
+ inline int overload_match_arity(types<Fx, Fxs...>, std::index_sequence<I, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
+ typedef lua_bind_traits<meta::unqualified_t<Fx>> traits;
+ typedef meta::tuple_types<typename traits::return_type> return_types;
+ typedef typename traits::free_args_list args_list;
+ // compile-time eliminate any functions that we know ahead of time are of improper arity
+ if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
+ return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+ if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) {
+ return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::free_arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+ stack::record tracking{};
+ if (!stack::stack_detail::check_types<true>{}.check(args_list(), L, start, no_panic, tracking)) {
+ return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+ return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
+ }
+
+ template <std::size_t... M, typename Match, typename... Args>
+ inline int overload_match_arity_single(types<>, std::index_sequence<>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
+ return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, std::size_t I, std::size_t... M, typename Match, typename... Args>
+ inline int overload_match_arity_single(types<Fx>, std::index_sequence<I>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
+ typedef lua_bind_traits<meta::unqualified_t<Fx>> traits;
+ typedef meta::tuple_types<typename traits::return_type> return_types;
+ typedef typename traits::free_args_list args_list;
+ // compile-time eliminate any functions that we know ahead of time are of improper arity
+ if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
+ return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+ if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) {
+ return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence<traits::free_arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+ return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename Fx1, typename... Fxs, std::size_t I, std::size_t I1, std::size_t... In, std::size_t... M, typename Match, typename... Args>
+ inline int overload_match_arity_single(types<Fx, Fx1, Fxs...>, std::index_sequence<I, I1, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
+ typedef lua_bind_traits<meta::unqualified_t<Fx>> traits;
+ typedef meta::tuple_types<typename traits::return_type> return_types;
+ typedef typename traits::free_args_list args_list;
+ // compile-time eliminate any functions that we know ahead of time are of improper arity
+ if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
+ return overload_match_arity(types<Fx1, Fxs...>(), std::index_sequence<I1, In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+ if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) {
+ return overload_match_arity(types<Fx1, Fxs...>(), std::index_sequence<I1, In...>(), std::index_sequence<traits::free_arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+ stack::record tracking{};
+ if (!stack::stack_detail::check_types<true>{}.check(args_list(), L, start, no_panic, tracking)) {
+ return overload_match_arity(types<Fx1, Fxs...>(), std::index_sequence<I1, In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+ return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
+ }
+ } // overload_detail
+
+ template <typename... Functions, typename Match, typename... Args>
+ inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
+ return overload_detail::overload_match_arity_single(types<Functions...>(), std::make_index_sequence<sizeof...(Functions)>(), std::index_sequence<>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+
+ template <typename... Functions, typename Match, typename... Args>
+ inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) {
+ int fxarity = lua_gettop(L) - (start - 1);
+ return overload_match_arity<Functions...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+
+ template <typename T, typename... TypeLists, typename Match, typename... Args>
+ inline int construct_match(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
+ // use same overload resolution matching as all other parts of the framework
+ return overload_match_arity<decltype(void_call<T, TypeLists>::call)...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
+ }
+
+ template <typename T, typename... TypeLists>
+ inline int construct(lua_State* L) {
+ static const auto& meta = usertype_traits<T>::metatable();
+ int argcount = lua_gettop(L);
+ call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0], 1) : call_syntax::dot;
+ argcount -= static_cast<int>(syntax);
+
+ T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
+ T*& referencepointer = *pointerpointer;
+ T* obj = reinterpret_cast<T*>(pointerpointer + 1);
+ referencepointer = obj;
+ reference userdataref(L, -1);
+ userdataref.pop();
+
+ construct_match<T, TypeLists...>(constructor_match<T>(obj), L, argcount, 1 + static_cast<int>(syntax));
+
+ userdataref.push();
+ luaL_getmetatable(L, &meta[0]);
+ if (type_of(L, -1) == type::lua_nil) {
+ lua_pop(L, 1);
+ return luaL_error(L, "sol: unable to get usertype metatable");
+ }
+
+ lua_setmetatable(L, -2);
+ return 1;
+ }
+
+ template <typename F, bool is_index, bool is_variable, bool checked, int boost, typename = void>
+ struct agnostic_lua_call_wrapper {
+ template <typename Fx, typename... Args>
+ static int call(lua_State* L, Fx&& f, Args&&... args) {
+ typedef wrapper<meta::unqualified_t<F>> wrap;
+ typedef typename wrap::returns_list returns_list;
+ typedef typename wrap::free_args_list args_list;
+ typedef typename wrap::caller caller;
+ return stack::call_into_lua<checked>(returns_list(), args_list(), L, boost + 1, caller(), std::forward<Fx>(f), std::forward<Args>(args)...);
+ }
+ };
+
+ template <typename T, bool is_variable, bool checked, int boost, typename C>
+ struct agnostic_lua_call_wrapper<var_wrapper<T>, true, is_variable, checked, boost, C> {
+ template <typename F>
+ static int call(lua_State* L, F&& f) {
+ return stack::push_reference(L, detail::unwrap(f.value));
+ }
+ };
+
+ template <typename T, bool is_variable, bool checked, int boost, typename C>
+ struct agnostic_lua_call_wrapper<var_wrapper<T>, false, is_variable, checked, boost, C> {
+ template <typename V>
+ static int call_assign(std::true_type, lua_State* L, V&& f) {
+ detail::unwrap(f.value) = stack::get<meta::unwrapped_t<T>>(L, boost + (is_variable ? 3 : 1));
+ return 0;
+ }
+
+ template <typename... Args>
+ static int call_assign(std::false_type, lua_State* L, Args&&...) {
+ return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available");
+ }
+
+ template <typename... Args>
+ static int call_const(std::false_type, lua_State* L, Args&&... args) {
+ typedef meta::unwrapped_t<T> R;
+ return call_assign(std::is_assignable<std::add_lvalue_reference_t<meta::unqualified_t<R>>, R>(), L, std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ static int call_const(std::true_type, lua_State* L, Args&&...) {
+ return luaL_error(L, "sol: cannot write to a readonly (const) variable");
+ }
+
+ template <typename V>
+ static int call(lua_State* L, V&& f) {
+ return call_const(std::is_const<meta::unwrapped_t<T>>(), L, f);
+ }
+ };
+
+ template <bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, checked, boost, C> {
+ static int call(lua_State* L, lua_r_CFunction f) {
+ return f(L);
+ }
+ };
+
+ template <bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, checked, boost, C> {
+ static int call(lua_State* L, lua_CFunction f) {
+ return f(L);
+ }
+ };
+
+ template <bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, checked, boost, C> {
+ static int call(lua_State* L, const no_prop&) {
+ return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property");
+ }
+ };
+
+ template <bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, checked, boost, C> {
+ static int call(lua_State* L, const no_construction&) {
+ return function_detail::no_construction_error(L);
+ }
+ };
+
+ template <typename... Args, bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, checked, boost, C> {
+ static int call(lua_State*, const bases<Args...>&) {
+ // Uh. How did you even call this, lul
+ return 0;
+ }
+ };
+
+ template <typename T, typename F, bool is_index, bool is_variable, bool checked = stack::stack_detail::default_check_arguments, int boost = 0, typename = void>
+ struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable, checked, boost> {};
+
+ template <typename T, typename F, bool is_index, bool is_variable, bool checked, int boost>
+ struct lua_call_wrapper<T, F, is_index, is_variable, checked, boost, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
+ typedef wrapper<meta::unqualified_t<F>> wrap;
+ typedef typename wrap::object_type object_type;
+
+ template <typename Fx>
+ static int call(lua_State* L, Fx&& f, object_type& o) {
+ typedef typename wrap::returns_list returns_list;
+ typedef typename wrap::args_list args_list;
+ typedef typename wrap::caller caller;
+ return stack::call_into_lua<checked>(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward<Fx>(f), o);
+ }
+
+ template <typename Fx>
+ static int call(lua_State* L, Fx&& f) {
+ typedef std::conditional_t<std::is_void<T>::value, object_type, T> Ta;
+#ifdef SOL_SAFE_USERTYPE
+ auto maybeo = stack::check_get<Ta*>(L, 1);
+ if (!maybeo || maybeo.value() == nullptr) {
+ return luaL_error(L, "sol: received nil for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)");
+ }
+ object_type* o = static_cast<object_type*>(maybeo.value());
+ return call(L, std::forward<Fx>(f), *o);
+#else
+ object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1));
+ return call(L, std::forward<Fx>(f), o);
+#endif // Safety
+ }
+ };
+
+ template <typename T, typename F, bool is_variable, bool checked, int boost>
+ struct lua_call_wrapper<T, F, false, is_variable, checked, boost, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
+ typedef lua_bind_traits<F> traits_type;
+ typedef wrapper<meta::unqualified_t<F>> wrap;
+ typedef typename wrap::object_type object_type;
+
+ template <typename V>
+ static int call_assign(std::true_type, lua_State* L, V&& f, object_type& o) {
+ typedef typename wrap::args_list args_list;
+ typedef typename wrap::caller caller;
+ return stack::call_into_lua<checked>(types<void>(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o);
+ }
+
+ template <typename V>
+ static int call_assign(std::true_type, lua_State* L, V&& f) {
+ typedef std::conditional_t<std::is_void<T>::value, object_type, T> Ta;
+#ifdef SOL_SAFE_USERTYPE
+ auto maybeo = stack::check_get<Ta*>(L, 1);
+ if (!maybeo || maybeo.value() == nullptr) {
+ if (is_variable) {
+ return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)");
+ }
+ return luaL_error(L, "sol: received nil for 'self' argument (pass 'self' as first argument)");
+ }
+ object_type* o = static_cast<object_type*>(maybeo.value());
+ return call_assign(std::true_type(), L, f, *o);
+#else
+ object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1));
+ return call_assign(std::true_type(), L, f, o);
+#endif // Safety
+ }
+
+ template <typename... Args>
+ static int call_assign(std::false_type, lua_State* L, Args&&...) {
+ return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available");
+ }
+
+ template <typename... Args>
+ static int call_const(std::false_type, lua_State* L, Args&&... args) {
+ typedef typename traits_type::return_type R;
+ return call_assign(std::is_assignable<std::add_lvalue_reference_t<meta::unqualified_t<R>>, R>(), L, std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ static int call_const(std::true_type, lua_State* L, Args&&...) {
+ return luaL_error(L, "sol: cannot write to a readonly (const) variable");
+ }
+
+ template <typename V>
+ static int call(lua_State* L, V&& f) {
+ return call_const(std::is_const<typename traits_type::return_type>(), L, std::forward<V>(f));
+ }
+
+ template <typename V>
+ static int call(lua_State* L, V&& f, object_type& o) {
+ return call_const(std::is_const<typename traits_type::return_type>(), L, std::forward<V>(f), o);
+ }
+ };
+
+ template <typename T, typename F, bool is_variable, bool checked, int boost>
+ struct lua_call_wrapper<T, F, true, is_variable, checked, boost, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
+ typedef lua_bind_traits<F> traits_type;
+ typedef wrapper<meta::unqualified_t<F>> wrap;
+ typedef typename wrap::object_type object_type;
+
+ template <typename V>
+ static int call(lua_State* L, V&& f, object_type& o) {
+ typedef typename wrap::returns_list returns_list;
+ typedef typename wrap::caller caller;
+ return stack::call_into_lua<checked>(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward<V>(f), o);
+ }
+
+ template <typename V>
+ static int call(lua_State* L, V&& f) {
+ typedef std::conditional_t<std::is_void<T>::value, object_type, T> Ta;
+#ifdef SOL_SAFE_USERTYPE
+ auto maybeo = stack::check_get<Ta*>(L, 1);
+ if (!maybeo || maybeo.value() == nullptr) {
+ if (is_variable) {
+ return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)");
+ }
+ return luaL_error(L, "sol: 'self' argument is lua_nil (pass 'self' as first argument)");
+ }
+ object_type* o = static_cast<object_type*>(maybeo.value());
+ return call(L, f, *o);
+#else
+ object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1));
+ return call(L, f, o);
+#endif // Safety
+ }
+ };
+
+ template <typename T, typename... Args, bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct lua_call_wrapper<T, constructor_list<Args...>, is_index, is_variable, checked, boost, C> {
+ typedef constructor_list<Args...> F;
+
+ static int call(lua_State* L, F&) {
+ const auto& metakey = usertype_traits<T>::metatable();
+ int argcount = lua_gettop(L);
+ call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0], 1) : call_syntax::dot;
+ argcount -= static_cast<int>(syntax);
+
+ T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
+ reference userdataref(L, -1);
+ T*& referencepointer = *pointerpointer;
+ T* obj = reinterpret_cast<T*>(pointerpointer + 1);
+ referencepointer = obj;
+
+ construct_match<T, Args...>(constructor_match<T>(obj), L, argcount, boost + 1 + static_cast<int>(syntax));
+
+ userdataref.push();
+ luaL_getmetatable(L, &metakey[0]);
+ if (type_of(L, -1) == type::lua_nil) {
+ lua_pop(L, 1);
+ return luaL_error(L, "sol: unable to get usertype metatable");
+ }
+
+ lua_setmetatable(L, -2);
+ return 1;
+ }
+ };
+
+ template <typename T, typename... Cxs, bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct lua_call_wrapper<T, constructor_wrapper<Cxs...>, is_index, is_variable, checked, boost, C> {
+ typedef constructor_wrapper<Cxs...> F;
+
+ struct onmatch {
+ template <typename Fx, std::size_t I, typename... R, typename... Args>
+ int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start, F& f) {
+ const auto& metakey = usertype_traits<T>::metatable();
+ T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
+ reference userdataref(L, -1);
+ T*& referencepointer = *pointerpointer;
+ T* obj = reinterpret_cast<T*>(pointerpointer + 1);
+ referencepointer = obj;
+
+ auto& func = std::get<I>(f.functions);
+ stack::call_into_lua<checked>(r, a, L, boost + start, func, detail::implicit_wrapper<T>(obj));
+
+ userdataref.push();
+ luaL_getmetatable(L, &metakey[0]);
+ if (type_of(L, -1) == type::lua_nil) {
+ lua_pop(L, 1);
+ std::string err = "sol: unable to get usertype metatable for ";
+ err += usertype_traits<T>::name();
+ return luaL_error(L, err.c_str());
+ }
+ lua_setmetatable(L, -2);
+
+ return 1;
+ }
+ };
+
+ static int call(lua_State* L, F& f) {
+ call_syntax syntax = stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0], 1);
+ int syntaxval = static_cast<int>(syntax);
+ int argcount = lua_gettop(L) - syntaxval;
+ return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
+ }
+
+ };
+
+ template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost>
+ struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, std::enable_if_t<std::is_void<Fx>::value>> {
+ typedef destructor_wrapper<Fx> F;
+
+ static int call(lua_State* L, const F&) {
+ return detail::usertype_alloc_destroy<T>(L);
+ }
+ };
+
+ template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost>
+ struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, std::enable_if_t<!std::is_void<Fx>::value>> {
+ typedef destructor_wrapper<Fx> F;
+
+ static int call(lua_State* L, const F& f) {
+ T& obj = stack::get<T>(L);
+ f.fx(detail::implicit_wrapper<T>(obj));
+ return 0;
+ }
+ };
+
+ template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, checked, boost, C> {
+ typedef overload_set<Fs...> F;
+
+ struct on_match {
+ template <typename Fx, std::size_t I, typename... R, typename... Args>
+ int operator()(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) {
+ auto& f = std::get<I>(fx.functions);
+ return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost>{}.call(L, f);
+ }
+ };
+
+ static int call(lua_State* L, F& fx) {
+ return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L), 1, fx);
+ }
+ };
+
+ template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct lua_call_wrapper<T, factory_wrapper<Fs...>, is_index, is_variable, checked, boost, C> {
+ typedef factory_wrapper<Fs...> F;
+
+ struct on_match {
+ template <typename Fx, std::size_t I, typename... R, typename... Args>
+ int operator()(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) {
+ auto& f = std::get<I>(fx.functions);
+ return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost>{}.call(L, f);
+ }
+ };
+
+ static int call(lua_State* L, F& fx) {
+ return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L) - boost, 1 + boost, fx);
+ }
+ };
+
+ template <typename T, typename R, typename W, bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct lua_call_wrapper<T, property_wrapper<R, W>, is_index, is_variable, checked, boost, C> {
+ typedef std::conditional_t<is_index, R, W> P;
+ typedef meta::unqualified_t<P> U;
+ typedef lua_bind_traits<U> traits_type;
+
+ template <typename F>
+ static int self_call(lua_State* L, F&& f) {
+ typedef wrapper<U> wrap;
+ typedef meta::unqualified_t<typename traits_type::template arg_at<0>> object_type;
+ typedef meta::pop_front_type_t<typename traits_type::free_args_list> args_list;
+ typedef T Ta;
+#ifdef SOL_SAFE_USERTYPE
+ auto maybeo = stack::check_get<Ta*>(L, 1);
+ if (!maybeo || maybeo.value() == nullptr) {
+ if (is_variable) {
+ return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)");
+ }
+ return luaL_error(L, "sol: 'self' argument is lua_nil (pass 'self' as first argument)");
+ }
+ object_type* o = static_cast<object_type*>(maybeo.value());
+#else
+ object_type* o = static_cast<object_type*>(stack::get<non_null<Ta*>>(L, 1));
+#endif // Safety
+ typedef typename wrap::returns_list returns_list;
+ typedef typename wrap::caller caller;
+ return stack::call_into_lua<checked>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, *o);
+ }
+
+ template <typename F, typename... Args>
+ static int defer_call(std::false_type, lua_State* L, F&& f, Args&&... args) {
+ return self_call(L, pick(meta::boolean<is_index>(), f), std::forward<Args>(args)...);
+ }
+
+ template <typename F, typename... Args>
+ static int defer_call(std::true_type, lua_State* L, F&& f, Args&&... args) {
+ auto& p = pick(meta::boolean<is_index>(), std::forward<F>(f));
+ return lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost>{}.call(L, p, std::forward<Args>(args)...);
+ }
+
+ template <typename F, typename... Args>
+ static int call(lua_State* L, F&& f, Args&&... args) {
+ typedef meta::any<
+ std::is_void<U>,
+ std::is_same<U, no_prop>,
+ meta::is_specialization_of<var_wrapper, U>,
+ meta::is_specialization_of<constructor_wrapper, U>,
+ meta::is_specialization_of<constructor_list, U>,
+ std::is_member_pointer<U>
+ > is_specialized;
+ return defer_call(is_specialized(), L, std::forward<F>(f), std::forward<Args>(args)...);
+ }
+ };
+
+ template <typename T, typename V, bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct lua_call_wrapper<T, protect_t<V>, is_index, is_variable, checked, boost, C> {
+ typedef protect_t<V> F;
+
+ template <typename... Args>
+ static int call(lua_State* L, F& fx, Args&&... args) {
+ return lua_call_wrapper<T, V, is_index, is_variable, true, boost>{}.call(L, fx.value, std::forward<Args>(args)...);
+ }
+ };
+
+ template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, typename C>
+ struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, C> {
+ template <typename F>
+ static int call(lua_State* L, F&& f) {
+ return lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::get<0>(f.arguments));
+ }
+ };
+
+ template <typename T, bool is_index, bool is_variable, int boost = 0, typename Fx, typename... Args>
+ inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) {
+ return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
+ }
+
+ template <typename T, bool is_index, bool is_variable, typename F>
+ inline int call_user(lua_State* L) {
+ auto& fx = stack::get<user<F>>(L, upvalue_index(1));
+ return call_wrapped<T, is_index, is_variable>(L, fx);
+ }
+
+ template <typename T, typename = void>
+ struct is_var_bind : std::false_type {};
+
+ template <typename T>
+ struct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type {};
+
+ template <>
+ struct is_var_bind<no_prop> : std::true_type {};
+
+ template <typename R, typename W>
+ struct is_var_bind<property_wrapper<R, W>> : std::true_type {};
+
+ template <typename T>
+ struct is_var_bind<var_wrapper<T>> : std::true_type {};
+ } // call_detail
+
+ template <typename T>
+ struct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> {};
+
+ template <typename T>
+ struct is_function_binding : meta::neg<is_variable_binding<T>> {};
+
+} // sol
+
+// end of sol/call.hpp
+
+namespace sol {
+ namespace function_detail {
+ template <typename F, F fx>
+ inline int call_wrapper_variable(std::false_type, lua_State* L) {
+ typedef meta::bind_traits<meta::unqualified_t<F>> traits_type;
+ typedef typename traits_type::args_list args_list;
+ typedef meta::tuple_types<typename traits_type::return_type> return_type;
+ return stack::call_into_lua(return_type(), args_list(), L, 1, fx);
+ }
+
+ template <typename R, typename V, V, typename T>
+ inline int call_set_assignable(std::false_type, T&&, lua_State* L) {
+ return luaL_error(L, "cannot write to this type: copy assignment/constructor not available");
+ }
+
+ template <typename R, typename V, V variable, typename T>
+ inline int call_set_assignable(std::true_type, lua_State* L, T&& mem) {
+ (mem.*variable) = stack::get<R>(L, 2);
+ return 0;
+ }
+
+ template <typename R, typename V, V, typename T>
+ inline int call_set_variable(std::false_type, lua_State* L, T&&) {
+ return luaL_error(L, "cannot write to a const variable");
+ }
+
+ template <typename R, typename V, V variable, typename T>
+ inline int call_set_variable(std::true_type, lua_State* L, T&& mem) {
+ return call_set_assignable<R, V, variable>(std::is_assignable<std::add_lvalue_reference_t<R>, R>(), L, std::forward<T>(mem));
+ }
+
+ template <typename V, V variable>
+ inline int call_wrapper_variable(std::true_type, lua_State* L) {
+ typedef meta::bind_traits<meta::unqualified_t<V>> traits_type;
+ typedef typename traits_type::object_type T;
+ typedef typename traits_type::return_type R;
+ auto& mem = stack::get<T>(L, 1);
+ switch (lua_gettop(L)) {
+ case 1: {
+ decltype(auto) r = (mem.*variable);
+ stack::push_reference(L, std::forward<decltype(r)>(r));
+ return 1; }
+ case 2:
+ return call_set_variable<R, V, variable>(meta::neg<std::is_const<R>>(), L, mem);
+ default:
+ return luaL_error(L, "incorrect number of arguments to member variable function call");
+ }
+ }
+
+ template <typename F, F fx>
+ inline int call_wrapper_function(std::false_type, lua_State* L) {
+ return call_wrapper_variable<F, fx>(std::is_member_object_pointer<F>(), L);
+ }
+
+ template <typename F, F fx>
+ inline int call_wrapper_function(std::true_type, lua_State* L) {
+ return call_detail::call_wrapped<void, false, false>(L, fx);
+ }
+
+ template <typename F, F fx>
+ int call_wrapper_entry(lua_State* L) {
+ return call_wrapper_function<F, fx>(std::is_member_function_pointer<meta::unqualified_t<F>>(), L);
+ }
+
+ template <typename... Fxs>
+ struct c_call_matcher {
+ template <typename Fx, std::size_t I, typename R, typename... Args>
+ int operator()(types<Fx>, index_value<I>, types<R>, types<Args...>, lua_State* L, int, int) const {
+ typedef meta::at_in_pack_t<I, Fxs...> target;
+ return target::call(L);
+ }
+ };
+
+ } // function_detail
+
+ template <typename F, F fx>
+ inline int c_call(lua_State* L) {
+#ifdef __clang__
+ return detail::trampoline(L, function_detail::call_wrapper_entry<F, fx>);
+#else
+ return detail::static_trampoline<(&function_detail::call_wrapper_entry<F, fx>)>(L);
+#endif // fuck you clang :c
+ }
+
+ template <typename F, F f>
+ struct wrap {
+ typedef F type;
+
+ static int call(lua_State* L) {
+ return c_call<type, f>(L);
+ }
+ };
+
+ template <typename... Fxs>
+ inline int c_call(lua_State* L) {
+ if (sizeof...(Fxs) < 2) {
+ return meta::at_in_pack_t<0, Fxs...>::call(L);
+ }
+ else {
+ return call_detail::overload_match_arity<typename Fxs::type...>(function_detail::c_call_matcher<Fxs...>(), L, lua_gettop(L), 1);
+ }
+ }
+
+} // sol
+
+// end of sol/function_types_templated.hpp
+
+// beginning of sol/function_types_stateless.hpp
+
+namespace sol {
+ namespace function_detail {
+ template<typename Function>
+ struct upvalue_free_function {
+ typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
+ typedef lua_bind_traits<function_type> traits_type;
+
+ static int real_call(lua_State* L) {
+ auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L);
+ function_type* fx = udata.first;
+ return call_detail::call_wrapped<void, true, false>(L, fx);
+ }
+
+ static int call(lua_State* L) {
+ return detail::static_trampoline<(&real_call)>(L);
+ }
+
+ int operator()(lua_State* L) {
+ return call(L);
+ }
+ };
+
+ template<typename T, typename Function>
+ struct upvalue_member_function {
+ typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
+ typedef lua_bind_traits<function_type> traits_type;
+
+ static int real_call(lua_State* L) {
+ // Layout:
+ // idx 1...n: verbatim data of member function pointer
+ // idx n + 1: is the object's void pointer
+ // We don't need to store the size, because the other side is templated
+ // with the same member function pointer type
+ auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
+ auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
+ function_type& memfx = memberdata.first;
+ auto& item = *objdata.first;
+ return call_detail::call_wrapped<T, true, false, -1>(L, memfx, item);
+ }
+
+ static int call(lua_State* L) {
+ return detail::static_trampoline<(&real_call)>(L);
+ }
+
+ int operator()(lua_State* L) {
+ return call(L);
+ }
+ };
+
+ template<typename T, typename Function>
+ struct upvalue_member_variable {
+ typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
+ typedef lua_bind_traits<function_type> traits_type;
+
+ static int real_call(lua_State* L) {
+ // Layout:
+ // idx 1...n: verbatim data of member variable pointer
+ // idx n + 1: is the object's void pointer
+ // We don't need to store the size, because the other side is templated
+ // with the same member function pointer type
+ auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
+ auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
+ auto& mem = *objdata.first;
+ function_type& var = memberdata.first;
+ switch (lua_gettop(L)) {
+ case 0:
+ return call_detail::call_wrapped<T, true, false, -1>(L, var, mem);
+ case 1:
+ return call_detail::call_wrapped<T, false, false, -1>(L, var, mem);
+ default:
+ return luaL_error(L, "sol: incorrect number of arguments to member variable function");
+ }
+ }
+
+ static int call(lua_State* L) {
+ return detail::static_trampoline<(&real_call)>(L);
+ }
+
+ int operator()(lua_State* L) {
+ return call(L);
+ }
+ };
+
+ template<typename T, typename Function>
+ struct upvalue_this_member_function {
+ typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
+ typedef lua_bind_traits<function_type> traits_type;
+
+ static int real_call(lua_State* L) {
+ // Layout:
+ // idx 1...n: verbatim data of member variable pointer
+ auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
+ function_type& memfx = memberdata.first;
+ return call_detail::call_wrapped<T, false, false>(L, memfx);
+ }
+
+ static int call(lua_State* L) {
+ return detail::static_trampoline<(&real_call)>(L);
+ }
+
+ int operator()(lua_State* L) {
+ return call(L);
+ }
+ };
+
+ template<typename T, typename Function>
+ struct upvalue_this_member_variable {
+ typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
+ typedef lua_bind_traits<function_type> traits_type;
+
+ static int real_call(lua_State* L) {
+ // Layout:
+ // idx 1...n: verbatim data of member variable pointer
+ auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
+ function_type& var = memberdata.first;
+ switch (lua_gettop(L)) {
+ case 1:
+ return call_detail::call_wrapped<T, true, false>(L, var);
+ case 2:
+ return call_detail::call_wrapped<T, false, false>(L, var);
+ default:
+ return luaL_error(L, "sol: incorrect number of arguments to member variable function");
+ }
+ }
+
+ static int call(lua_State* L) {
+ return detail::static_trampoline<(&real_call)>(L);
+ }
+
+ int operator()(lua_State* L) {
+ return call(L);
+ }
+ };
+ } // function_detail
+} // sol
+
+// end of sol/function_types_stateless.hpp
+
+// beginning of sol/function_types_stateful.hpp
+
+namespace sol {
+ namespace function_detail {
+ template<typename Func>
+ struct functor_function {
+ typedef meta::unwrapped_t<meta::unqualified_t<Func>> Function;
+ Function fx;
+
+ template<typename... Args>
+ functor_function(Function f, Args&&... args) : fx(std::move(f), std::forward<Args>(args)...) {}
+
+ int call(lua_State* L) {
+ return call_detail::call_wrapped<void, true, false>(L, fx);
+ }
+
+ int operator()(lua_State* L) {
+ auto f = [&](lua_State*) -> int { return this->call(L); };
+ return detail::trampoline(L, f);
+ }
+ };
+
+ template<typename T, typename Function>
+ struct member_function {
+ typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
+ typedef meta::function_return_t<function_type> return_type;
+ typedef meta::function_args_t<function_type> args_lists;
+ function_type invocation;
+ T member;
+
+ template<typename... Args>
+ member_function(function_type f, Args&&... args) : invocation(std::move(f)), member(std::forward<Args>(args)...) {}
+
+ int call(lua_State* L) {
+ return call_detail::call_wrapped<T, true, false, -1>(L, invocation, detail::unwrap(detail::deref(member)));
+ }
+
+ int operator()(lua_State* L) {
+ auto f = [&](lua_State*) -> int { return this->call(L); };
+ return detail::trampoline(L, f);
+ }
+ };
+
+ template<typename T, typename Function>
+ struct member_variable {
+ typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
+ typedef typename meta::bind_traits<function_type>::return_type return_type;
+ typedef typename meta::bind_traits<function_type>::args_list args_lists;
+ function_type var;
+ T member;
+ typedef std::add_lvalue_reference_t<meta::unwrapped_t<std::remove_reference_t<decltype(detail::deref(member))>>> M;
+
+ template<typename... Args>
+ member_variable(function_type v, Args&&... args) : var(std::move(v)), member(std::forward<Args>(args)...) {}
+
+ int call(lua_State* L) {
+ M mem = detail::unwrap(detail::deref(member));
+ switch (lua_gettop(L)) {
+ case 0:
+ return call_detail::call_wrapped<T, true, false, -1>(L, var, mem);
+ case 1:
+ return call_detail::call_wrapped<T, false, false, -1>(L, var, mem);
+ default:
+ return luaL_error(L, "sol: incorrect number of arguments to member variable function");
+ }
+ }
+
+ int operator()(lua_State* L) {
+ auto f = [&](lua_State*) -> int { return this->call(L); };
+ return detail::trampoline(L, f);
+ }
+ };
+ } // function_detail
+} // sol
+
+// end of sol/function_types_stateful.hpp
+
+// beginning of sol/function_types_overloaded.hpp
+
+namespace sol {
+ namespace function_detail {
+ template <int start_skew = 0, typename... Functions>
+ struct overloaded_function {
+ typedef std::tuple<Functions...> overload_list;
+ typedef std::make_index_sequence<sizeof...(Functions)> indices;
+ overload_list overloads;
+
+ overloaded_function(overload_list set)
+ : overloads(std::move(set)) {}
+
+ overloaded_function(Functions... fxs)
+ : overloads(fxs...) {
+
+ }
+
+ template <typename Fx, std::size_t I, typename... R, typename... Args>
+ int call(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int) {
+ auto& func = std::get<I>(overloads);
+ return call_detail::call_wrapped<void, true, false, start_skew>(L, func);
+ }
+
+ int operator()(lua_State* L) {
+ auto mfx = [&](auto&&... args) { return this->call(std::forward<decltype(args)>(args)...); };
+ return call_detail::overload_match<Functions...>(mfx, L, 1 + start_skew);
+ }
+ };
+ } // function_detail
+} // sol
+
+// end of sol/function_types_overloaded.hpp
+
+// beginning of sol/resolve.hpp
+
+namespace sol {
+
+#ifndef __clang__
+ // constexpr is fine for not-clang
+
+ namespace detail {
+ template<typename R, typename... Args, typename F, typename = std::result_of_t<meta::unqualified_t<F>(Args...)>>
+ inline constexpr auto resolve_i(types<R(Args...)>, F&&)->R(meta::unqualified_t<F>::*)(Args...) {
+ using Sig = R(Args...);
+ typedef meta::unqualified_t<F> Fu;
+ return static_cast<Sig Fu::*>(&Fu::operator());
+ }
+
+ template<typename F, typename U = meta::unqualified_t<F>>
+ inline constexpr auto resolve_f(std::true_type, F&& f)
+ -> decltype(resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f))) {
+ return resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f));
+ }
+
+ template<typename F>
+ inline constexpr void resolve_f(std::false_type, F&&) {
+ static_assert(meta::has_deducible_signature<F>::value,
+ "Cannot use no-template-parameter call with an overloaded functor: specify the signature");
+ }
+
+ template<typename F, typename U = meta::unqualified_t<F>>
+ inline constexpr auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature<U>(), std::forward<F>(f))) {
+ return resolve_f(meta::has_deducible_signature<U> {}, std::forward<F>(f));
+ }
+
+ template<typename... Args, typename F, typename R = std::result_of_t<F&(Args...)>>
+ inline constexpr auto resolve_i(types<Args...>, F&& f) -> decltype(resolve_i(types<R(Args...)>(), std::forward<F>(f))) {
+ return resolve_i(types<R(Args...)>(), std::forward<F>(f));
+ }
+
+ template<typename Sig, typename C>
+ inline constexpr Sig C::* resolve_v(std::false_type, Sig C::* mem_func_ptr) {
+ return mem_func_ptr;
+ }
+
+ template<typename Sig, typename C>
+ inline constexpr Sig C::* resolve_v(std::true_type, Sig C::* mem_variable_ptr) {
+ return mem_variable_ptr;
+ }
+ } // detail
+
+ template<typename... Args, typename R>
+ inline constexpr auto resolve(R fun_ptr(Args...))->R(*)(Args...) {
+ return fun_ptr;
+ }
+
+ template<typename Sig>
+ inline constexpr Sig* resolve(Sig* fun_ptr) {
+ return fun_ptr;
+ }
+
+ template<typename... Args, typename R, typename C>
+ inline constexpr auto resolve(R(C::*mem_ptr)(Args...))->R(C::*)(Args...) {
+ return mem_ptr;
+ }
+
+ template<typename Sig, typename C>
+ inline constexpr Sig C::* resolve(Sig C::* mem_ptr) {
+ return detail::resolve_v(std::is_member_object_pointer<Sig C::*>(), mem_ptr);
+ }
+
+ template<typename... Sig, typename F, meta::disable<std::is_function<meta::unqualified_t<F>>> = meta::enabler>
+ inline constexpr auto resolve(F&& f) -> decltype(detail::resolve_i(types<Sig...>(), std::forward<F>(f))) {
+ return detail::resolve_i(types<Sig...>(), std::forward<F>(f));
+ }
+#else
+
+ // Clang has distinct problems with constexpr arguments,
+ // so don't use the constexpr versions inside of clang.
+
+ namespace detail {
+ template<typename R, typename... Args, typename F, typename = std::result_of_t<meta::unqualified_t<F>(Args...)>>
+ inline auto resolve_i(types<R(Args...)>, F&&)->R(meta::unqualified_t<F>::*)(Args...) {
+ using Sig = R(Args...);
+ typedef meta::unqualified_t<F> Fu;
+ return static_cast<Sig Fu::*>(&Fu::operator());
+ }
+
+ template<typename F, typename U = meta::unqualified_t<F>>
+ inline auto resolve_f(std::true_type, F&& f)
+ -> decltype(resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f))) {
+ return resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f));
+ }
+
+ template<typename F>
+ inline void resolve_f(std::false_type, F&&) {
+ static_assert(meta::has_deducible_signature<F>::value,
+ "Cannot use no-template-parameter call with an overloaded functor: specify the signature");
+ }
+
+ template<typename F, typename U = meta::unqualified_t<F>>
+ inline auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature<U>(), std::forward<F>(f))) {
+ return resolve_f(meta::has_deducible_signature<U> {}, std::forward<F>(f));
+ }
+
+ template<typename... Args, typename F, typename R = std::result_of_t<F&(Args...)>>
+ inline auto resolve_i(types<Args...>, F&& f) -> decltype(resolve_i(types<R(Args...)>(), std::forward<F>(f))) {
+ return resolve_i(types<R(Args...)>(), std::forward<F>(f));
+ }
+
+ template<typename Sig, typename C>
+ inline Sig C::* resolve_v(std::false_type, Sig C::* mem_func_ptr) {
+ return mem_func_ptr;
+ }
+
+ template<typename Sig, typename C>
+ inline Sig C::* resolve_v(std::true_type, Sig C::* mem_variable_ptr) {
+ return mem_variable_ptr;
+ }
+ } // detail
+
+ template<typename... Args, typename R>
+ inline auto resolve(R fun_ptr(Args...))->R(*)(Args...) {
+ return fun_ptr;
+ }
+
+ template<typename Sig>
+ inline Sig* resolve(Sig* fun_ptr) {
+ return fun_ptr;
+ }
+
+ template<typename... Args, typename R, typename C>
+ inline auto resolve(R(C::*mem_ptr)(Args...))->R(C::*)(Args...) {
+ return mem_ptr;
+ }
+
+ template<typename Sig, typename C>
+ inline Sig C::* resolve(Sig C::* mem_ptr) {
+ return detail::resolve_v(std::is_member_object_pointer<Sig C::*>(), mem_ptr);
+ }
+
+ template<typename... Sig, typename F>
+ inline auto resolve(F&& f) -> decltype(detail::resolve_i(types<Sig...>(), std::forward<F>(f))) {
+ return detail::resolve_i(types<Sig...>(), std::forward<F>(f));
+ }
+
+#endif
+
+} // sol
+
+// end of sol/resolve.hpp
+
+namespace sol {
+ namespace function_detail {
+ template<typename T>
+ struct class_indicator {};
+
+ struct call_indicator {};
+ }
+ namespace stack {
+ template<typename... Sigs>
+ struct pusher<function_sig<Sigs...>> {
+ template <typename... Sig, typename Fx, typename... Args>
+ static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) {
+ typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
+ typedef function_detail::functor_function<clean_fx> F;
+ set_fx<F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
+ }
+
+ template <typename R, typename... A, typename Fx, typename... Args>
+ static void select_convertible(std::true_type, types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
+ using fx_ptr_t = R(*)(A...);
+ fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
+ select_function(std::true_type(), L, fxptr, std::forward<Args>(args)...);
+ }
+
+ template <typename R, typename... A, typename Fx, typename... Args>
+ static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) {
+ typedef std::decay_t<meta::unwrap_unqualified_t<Fx>> raw_fx_t;
+ typedef R(*fx_ptr_t)(A...);
+ typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible;
+ select_convertible(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename... Args>
+ static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
+ typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig;
+ select_convertible(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename T, typename... Args>
+ static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
+ typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
+ typedef function_detail::member_variable<meta::unwrap_unqualified_t<T>, clean_fx> F;
+ set_fx<F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename T, typename... Args>
+ static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
+ typedef std::decay_t<Fx> dFx;
+ dFx memfxptr(std::forward<Fx>(fx));
+ auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
+ lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
+
+ int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
+ upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
+ stack::push(L, c_closure(freefunc, upvalues));
+ }
+
+ template <typename Fx, typename... Args>
+ static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
+ select_convertible(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<function_detail::class_indicator, meta::unqualified_t<T>>> = meta::enabler>
+ static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
+ typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
+ select_reference_member_variable(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename C>
+ static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) {
+ lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call;
+ int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
+ stack::push(L, c_closure(freefunc, upvalues));
+ }
+
+ template <typename Fx>
+ static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) {
+ typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
+ lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call;
+ int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
+ stack::push(L, c_closure(freefunc, upvalues));
+ }
+
+ template <typename Fx, typename T, typename... Args>
+ static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
+ typedef std::decay_t<Fx> clean_fx;
+ typedef function_detail::member_function<meta::unwrap_unqualified_t<T>, clean_fx> F;
+ set_fx<F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename T, typename... Args>
+ static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
+ typedef std::decay_t<Fx> dFx;
+ dFx memfxptr(std::forward<Fx>(fx));
+ auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
+ lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
+
+ int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
+ upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
+ stack::push(L, c_closure(freefunc, upvalues));
+ }
+
+ template <typename Fx, typename... Args>
+ static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
+ select_member_variable(std::is_member_object_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<function_detail::class_indicator, meta::unqualified_t<T>>> = meta::enabler>
+ static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
+ typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
+ select_reference_member_function(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename C>
+ static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) {
+ lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call;
+ int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
+ stack::push(L, c_closure(freefunc, upvalues));
+ }
+
+ template <typename Fx>
+ static void select_member_function(std::true_type, lua_State* L, Fx&& fx) {
+ typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
+ lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call;
+ int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
+ stack::push(L, c_closure(freefunc, upvalues));
+ }
+
+ template <typename Fx, typename... Args>
+ static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
+ select_member_function(std::is_member_function_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename... Args>
+ static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) {
+ std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
+ lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::call;
+
+ int upvalues = stack::stack_detail::push_as_upvalues(L, target);
+ stack::push(L, c_closure(freefunc, upvalues));
+ }
+
+ static void select_function(std::true_type, lua_State* L, lua_CFunction f) {
+ stack::push(L, f);
+ }
+
+ template <typename Fx, typename... Args>
+ static void select(lua_State* L, Fx&& fx, Args&&... args) {
+ select_function(std::is_function<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
+ }
+
+ template <typename Fx, typename... Args>
+ static void set_fx(lua_State* L, Args&&... args) {
+ lua_CFunction freefunc = function_detail::call<meta::unqualified_t<Fx>>;
+
+ stack::push<user<Fx>>(L, std::forward<Args>(args)...);
+ stack::push(L, c_closure(freefunc, 1));
+ }
+
+ template<typename... Args>
+ static int push(lua_State* L, Args&&... args) {
+ // Set will always place one thing (function) on the stack
+ select(L, std::forward<Args>(args)...);
+ return 1;
+ }
+ };
+
+ template<typename T, typename... Args>
+ struct pusher<function_arguments<T, Args...>> {
+ template <std::size_t... I, typename FP>
+ static int push_func(std::index_sequence<I...>, lua_State* L, FP&& fp) {
+ return stack::push<T>(L, detail::forward_get<I>(fp.arguments)...);
+ }
+
+ static int push(lua_State* L, const function_arguments<T, Args...>& fp) {
+ return push_func(std::make_index_sequence<sizeof...(Args)>(), L, fp);
+ }
+
+ static int push(lua_State* L, function_arguments<T, Args...>&& fp) {
+ return push_func(std::make_index_sequence<sizeof...(Args)>(), L, std::move(fp));
+ }
+ };
+
+ template<typename Signature>
+ struct pusher<std::function<Signature>> {
+ static int push(lua_State* L, std::function<Signature> fx) {
+ return pusher<function_sig<Signature>>{}.push(L, std::move(fx));
+ }
+ };
+
+ template<typename Signature>
+ struct pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> {
+ template <typename F, typename... Args>
+ static int push(lua_State* L, F&& f, Args&&... args) {
+ return pusher<function_sig<>>{}.push(L, std::forward<F>(f), std::forward<Args>(args)...);
+ }
+ };
+
+ template<typename Signature>
+ struct pusher<Signature, std::enable_if_t<meta::all<std::is_function<Signature>, meta::neg<std::is_same<Signature, lua_CFunction>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>>>::value>> {
+ template <typename F>
+ static int push(lua_State* L, F&& f) {
+ return pusher<function_sig<>>{}.push(L, std::forward<F>(f));
+ }
+ };
+
+ template<typename... Functions>
+ struct pusher<overload_set<Functions...>> {
+ static int push(lua_State* L, overload_set<Functions...>&& set) {
+ typedef function_detail::overloaded_function<0, Functions...> F;
+ pusher<function_sig<>>{}.set_fx<F>(L, std::move(set.functions));
+ return 1;
+ }
+
+ static int push(lua_State* L, const overload_set<Functions...>& set) {
+ typedef function_detail::overloaded_function<0, Functions...> F;
+ pusher<function_sig<>>{}.set_fx<F>(L, set.functions);
+ return 1;
+ }
+ };
+
+ template <typename T>
+ struct pusher<protect_t<T>> {
+ static int push(lua_State* L, protect_t<T>&& pw) {
+ lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>>;
+ int closures = stack::push<user<protect_t<T>>>(L, std::move(pw.value));
+ return stack::push(L, c_closure(cf, closures));
+ }
+
+ static int push(lua_State* L, const protect_t<T>& pw) {
+ lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>>;
+ int closures = stack::push<user<protect_t<T>>>(L, pw.value);
+ return stack::push(L, c_closure(cf, closures));
+ }
+ };
+
+ template <typename F, typename G>
+ struct pusher<property_wrapper<F, G>, std::enable_if_t<!std::is_void<F>::value && !std::is_void<G>::value>> {
+ static int push(lua_State* L, property_wrapper<F, G>&& pw) {
+ return stack::push(L, sol::overload(std::move(pw.read), std::move(pw.write)));
+ }
+ static int push(lua_State* L, const property_wrapper<F, G>& pw) {
+ return stack::push(L, sol::overload(pw.read, pw.write));
+ }
+ };
+
+ template <typename F>
+ struct pusher<property_wrapper<F, void>> {
+ static int push(lua_State* L, property_wrapper<F, void>&& pw) {
+ return stack::push(L, std::move(pw.read));
+ }
+ static int push(lua_State* L, const property_wrapper<F, void>& pw) {
+ return stack::push(L, pw.read);
+ }
+ };
+
+ template <typename F>
+ struct pusher<property_wrapper<void, F>> {
+ static int push(lua_State* L, property_wrapper<void, F>&& pw) {
+ return stack::push(L, std::move(pw.write));
+ }
+ static int push(lua_State* L, const property_wrapper<void, F>& pw) {
+ return stack::push(L, pw.write);
+ }
+ };
+
+ template <typename T>
+ struct pusher<var_wrapper<T>> {
+ static int push(lua_State* L, var_wrapper<T>&& vw) {
+ return stack::push(L, std::move(vw.value));
+ }
+ static int push(lua_State* L, const var_wrapper<T>& vw) {
+ return stack::push(L, vw.value);
+ }
+ };
+
+ template <typename... Functions>
+ struct pusher<factory_wrapper<Functions...>> {
+ static int push(lua_State* L, const factory_wrapper<Functions...>& fw) {
+ typedef function_detail::overloaded_function<0, Functions...> F;
+ pusher<function_sig<>>{}.set_fx<F>(L, fw.functions);
+ return 1;
+ }
+
+ static int push(lua_State* L, factory_wrapper<Functions...>&& fw) {
+ typedef function_detail::overloaded_function<0, Functions...> F;
+ pusher<function_sig<>>{}.set_fx<F>(L, std::move(fw.functions));
+ return 1;
+ }
+
+ static int push(lua_State* L, const factory_wrapper<Functions...>& set, function_detail::call_indicator) {
+ typedef function_detail::overloaded_function<1, Functions...> F;
+ pusher<function_sig<>>{}.set_fx<F>(L, set.functions);
+ return 1;
+ }
+
+ static int push(lua_State* L, factory_wrapper<Functions...>&& set, function_detail::call_indicator) {
+ typedef function_detail::overloaded_function<1, Functions...> F;
+ pusher<function_sig<>>{}.set_fx<F>(L, std::move(set.functions));
+ return 1;
+ }
+ };
+
+ template <>
+ struct pusher<no_construction> {
+ static int push(lua_State* L, no_construction) {
+ lua_CFunction cf = &function_detail::no_construction_error;
+ return stack::push(L, cf);
+ }
+
+ static int push(lua_State* L, no_construction c, function_detail::call_indicator) {
+ return push(L, c);
+ }
+ };
+
+ template <typename T, typename... Lists>
+ struct pusher<detail::tagged<T, constructor_list<Lists...>>> {
+ static int push(lua_State* L, detail::tagged<T, constructor_list<Lists...>>) {
+ lua_CFunction cf = call_detail::construct<T, Lists...>;
+ return stack::push(L, cf);
+ }
+ };
+
+ template <typename T, typename... Fxs>
+ struct pusher<detail::tagged<T, constructor_wrapper<Fxs...>>> {
+ template <typename C>
+ static int push(lua_State* L, C&& c) {
+ lua_CFunction cf = call_detail::call_user<T, false, false, constructor_wrapper<Fxs...>>;
+ int closures = stack::push<user<constructor_wrapper<Fxs...>>>(L, std::forward<C>(c));
+ return stack::push(L, c_closure(cf, closures));
+ }
+ };
+
+ template <typename T>
+ struct pusher<detail::tagged<T, destructor_wrapper<void>>> {
+ static int push(lua_State* L, destructor_wrapper<void>) {
+ lua_CFunction cf = detail::usertype_alloc_destroy<T>;
+ return stack::push(L, cf);
+ }
+ };
+
+ template <typename T, typename Fx>
+ struct pusher<detail::tagged<T, destructor_wrapper<Fx>>> {
+ static int push(lua_State* L, destructor_wrapper<Fx> c) {
+ lua_CFunction cf = call_detail::call_user<T, false, false, destructor_wrapper<Fx>>;
+ int closures = stack::push<user<T>>(L, std::move(c));
+ return stack::push(L, c_closure(cf, closures));
+ }
+ };
+
+ } // stack
+} // sol
+
+// end of sol/function_types.hpp
+
+namespace sol {
+ template <typename base_t>
+ class basic_function : public base_t {
+ private:
+ void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const {
+ lua_callk(base_t::lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), 0, nullptr);
+ }
+
+ template<std::size_t... I, typename... Ret>
+ auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) const {
+ luacall(n, lua_size<std::tuple<Ret...>>::value);
+ return stack::pop<std::tuple<Ret...>>(base_t::lua_state());
+ }
+
+ template<std::size_t I, typename Ret>
+ Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) const {
+ luacall(n, lua_size<Ret>::value);
+ return stack::pop<Ret>(base_t::lua_state());
+ }
+
+ template <std::size_t I>
+ void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) const {
+ luacall(n, 0);
+ }
+
+ function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) const {
+ int stacksize = lua_gettop(base_t::lua_state());
+ int firstreturn = (std::max)(1, stacksize - static_cast<int>(n));
+ luacall(n, LUA_MULTRET);
+ int poststacksize = lua_gettop(base_t::lua_state());
+ int returncount = poststacksize - (firstreturn - 1);
+ return function_result(base_t::lua_state(), firstreturn, returncount);
+ }
+
+ public:
+ basic_function() = default;
+ template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_t, meta::unqualified_t<T>>> = meta::enabler>
+ basic_function(T&& r) noexcept : base_t(std::forward<T>(r)) {
+#ifdef SOL_CHECK_ARGUMENTS
+ if (!is_function<meta::unqualified_t<T>>::value) {
+ auto pp = stack::push_pop(*this);
+ stack::check<basic_function>(base_t::lua_state(), -1, type_panic);
+ }
+#endif // Safety
+ }
+ basic_function(const basic_function&) = default;
+ basic_function& operator=(const basic_function&) = default;
+ basic_function(basic_function&&) = default;
+ basic_function& operator=(basic_function&&) = default;
+ basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
+ basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {}
+ template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler>
+ basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {}
+ basic_function(lua_State* L, int index = -1) : base_t(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ stack::check<basic_function>(L, index, type_panic);
+#endif // Safety
+ }
+ basic_function(lua_State* L, ref_index index) : base_t(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ auto pp = stack::push_pop(*this);
+ stack::check<basic_function>(L, -1, type_panic);
+#endif // Safety
+ }
+
+ template<typename... Args>
+ function_result operator()(Args&&... args) const {
+ return call<>(std::forward<Args>(args)...);
+ }
+
+ template<typename... Ret, typename... Args>
+ decltype(auto) operator()(types<Ret...>, Args&&... args) const {
+ return call<Ret...>(std::forward<Args>(args)...);
+ }
+
+ template<typename... Ret, typename... Args>
+ decltype(auto) call(Args&&... args) const {
+ base_t::push();
+ int pushcount = stack::multi_push_reference(base_t::lua_state(), std::forward<Args>(args)...);
+ return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);
+ }
+ };
+
+ namespace stack {
+ template<typename Signature>
+ struct getter<std::function<Signature>> {
+ typedef meta::bind_traits<Signature> fx_t;
+ typedef typename fx_t::args_list args_lists;
+ typedef meta::tuple_types<typename fx_t::return_type> return_types;
+
+ template<typename... Args, typename... Ret>
+ static std::function<Signature> get_std_func(types<Ret...>, types<Args...>, lua_State* L, int index) {
+ sol::function f(L, index);
+ auto fx = [f, L, index](Args&&... args) -> meta::return_type_t<Ret...> {
+ return f.call<Ret...>(std::forward<Args>(args)...);
+ };
+ return std::move(fx);
+ }
+
+ template<typename... FxArgs>
+ static std::function<Signature> get_std_func(types<void>, types<FxArgs...>, lua_State* L, int index) {
+ sol::function f(L, index);
+ auto fx = [f, L, index](FxArgs&&... args) -> void {
+ f(std::forward<FxArgs>(args)...);
+ };
+ return std::move(fx);
+ }
+
+ template<typename... FxArgs>
+ static std::function<Signature> get_std_func(types<>, types<FxArgs...> t, lua_State* L, int index) {
+ return get_std_func(types<void>(), t, L, index);
+ }
+
+ static std::function<Signature> get(lua_State* L, int index, record& tracking) {
+ tracking.last = 1;
+ tracking.used += 1;
+ type t = type_of(L, index);
+ if (t == type::none || t == type::lua_nil) {
+ return nullptr;
+ }
+ return get_std_func(return_types(), args_lists(), L, index);
+ }
+ };
+ } // stack
+} // sol
+
+// end of sol/function.hpp
+
+// beginning of sol/protected_function.hpp
+
+// beginning of sol/protected_function_result.hpp
+
+namespace sol {
+ struct protected_function_result : public proxy_base<protected_function_result> {
+ private:
+ lua_State* L;
+ int index;
+ int returncount;
+ int popcount;
+ call_status err;
+
+ template <typename T>
+ decltype(auto) tagged_get(types<sol::optional<T>>) const {
+ if (!valid()) {
+ return sol::optional<T>(nullopt);
+ }
+ return stack::get<sol::optional<T>>(L, index);
+ }
+
+ template <typename T>
+ decltype(auto) tagged_get(types<T>) const {
+#ifdef SOL_CHECK_ARGUMENTS
+ if (!valid()) {
+ type_panic(L, index, type_of(L, index), type::none);
+ }
+#endif // Check Argument Safety
+ return stack::get<T>(L, index);
+ }
+
+ optional<error> tagged_get(types<optional<error>>) const {
+ if (valid()) {
+ return nullopt;
+ }
+ return error(detail::direct_error, stack::get<std::string>(L, index));
+ }
+
+ error tagged_get(types<error>) const {
+#ifdef SOL_CHECK_ARGUMENTS
+ if (valid()) {
+ type_panic(L, index, type_of(L, index), type::none);
+ }
+#endif // Check Argument Safety
+ return error(detail::direct_error, stack::get<std::string>(L, index));
+ }
+
+ public:
+ protected_function_result() = default;
+ protected_function_result(lua_State* Ls, int idx = -1, int retnum = 0, int popped = 0, call_status pferr = call_status::ok) noexcept : L(Ls), index(idx), returncount(retnum), popcount(popped), err(pferr) {
+
+ }
+ protected_function_result(const protected_function_result&) = default;
+ protected_function_result& operator=(const protected_function_result&) = default;
+ protected_function_result(protected_function_result&& o) noexcept : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) {
+ // Must be manual, otherwise destructor will screw us
+ // return count being 0 is enough to keep things clean
+ // but we will be thorough
+ o.L = nullptr;
+ o.index = 0;
+ o.returncount = 0;
+ o.popcount = 0;
+ o.err = call_status::runtime;
+ }
+ protected_function_result& operator=(protected_function_result&& o) noexcept {
+ L = o.L;
+ index = o.index;
+ returncount = o.returncount;
+ popcount = o.popcount;
+ err = o.err;
+ // Must be manual, otherwise destructor will screw us
+ // return count being 0 is enough to keep things clean
+ // but we will be thorough
+ o.L = nullptr;
+ o.index = 0;
+ o.returncount = 0;
+ o.popcount = 0;
+ o.err = call_status::runtime;
+ return *this;
+ }
+
+ call_status status() const noexcept {
+ return err;
+ }
+
+ bool valid() const noexcept {
+ return status() == call_status::ok || status() == call_status::yielded;
+ }
+
+ template<typename T>
+ decltype(auto) get() const {
+ return tagged_get(types<meta::unqualified_t<T>>());
+ }
+
+ lua_State* lua_state() const noexcept { return L; };
+ int stack_index() const noexcept { return index; };
+
+ ~protected_function_result() {
+ stack::remove(L, index, popcount);
+ }
+ };
+} // sol
+
+// end of sol/protected_function_result.hpp
+
+#include <algorithm>
+
+namespace sol {
+ namespace detail {
+ inline reference& handler_storage() {
+ static sol::reference h;
+ return h;
+ }
+
+ struct handler {
+ const reference& target;
+ int stackindex;
+ handler(const reference& target) : target(target), stackindex(0) {
+ if (target.valid()) {
+ stackindex = lua_gettop(target.lua_state()) + 1;
+ target.push();
+ }
+ }
+ bool valid() const { return stackindex != 0; }
+ ~handler() {
+ if (valid()) {
+ lua_remove(target.lua_state(), stackindex);
+ }
+ }
+ };
+ }
+
+ template <typename base_t>
+ class basic_protected_function : public base_t {
+ public:
+ static reference& get_default_handler() {
+ return detail::handler_storage();
+ }
+
+ static void set_default_handler(const reference& ref) {
+ detail::handler_storage() = ref;
+ }
+
+ static void set_default_handler(reference&& ref) {
+ detail::handler_storage() = std::move(ref);
+ }
+
+ private:
+ call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::handler& h) const {
+ return static_cast<call_status>(lua_pcallk(base_t::lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr));
+ }
+
+ template<std::size_t... I, typename... Ret>
+ auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::handler& h) const {
+ luacall(n, sizeof...(Ret), h);
+ return stack::pop<std::tuple<Ret...>>(base_t::lua_state());
+ }
+
+ template<std::size_t I, typename Ret>
+ Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::handler& h) const {
+ luacall(n, 1, h);
+ return stack::pop<Ret>(base_t::lua_state());
+ }
+
+ template <std::size_t I>
+ void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::handler& h) const {
+ luacall(n, 0, h);
+ }
+
+ protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::handler& h) const {
+ int stacksize = lua_gettop(base_t::lua_state());
+ int poststacksize = stacksize;
+ int firstreturn = 1;
+ int returncount = 0;
+ call_status code = call_status::ok;
+#ifndef SOL_NO_EXCEPTIONS
+ auto onexcept = [&](const char* error) {
+ h.stackindex = 0;
+ if (h.target.valid()) {
+ h.target.push();
+ stack::push(base_t::lua_state(), error);
+ lua_call(base_t::lua_state(), 1, 1);
+ }
+ else {
+ stack::push(base_t::lua_state(), error);
+ }
+ };
+ try {
+#endif // No Exceptions
+ firstreturn = (std::max)(1, static_cast<int>(stacksize - n - static_cast<int>(h.valid())));
+ code = luacall(n, LUA_MULTRET, h);
+ poststacksize = lua_gettop(base_t::lua_state()) - static_cast<int>(h.valid());
+ returncount = poststacksize - (firstreturn - 1);
+#ifndef SOL_NO_EXCEPTIONS
+ }
+ // Handle C++ errors thrown from C++ functions bound inside of lua
+ catch (const char* error) {
+ onexcept(error);
+ firstreturn = lua_gettop(base_t::lua_state());
+ return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime);
+ }
+ catch (const std::exception& error) {
+ onexcept(error.what());
+ firstreturn = lua_gettop(base_t::lua_state());
+ return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime);
+ }
+ catch (...) {
+ onexcept("caught (...) unknown error during protected_function call");
+ firstreturn = lua_gettop(base_t::lua_state());
+ return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime);
+ }
+#endif // No Exceptions
+ return protected_function_result(base_t::lua_state(), firstreturn, returncount, returncount, code);
+ }
+
+ public:
+ reference error_handler;
+
+ basic_protected_function() = default;
+ template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_t, meta::unqualified_t<T>>> = meta::enabler>
+ basic_protected_function(T&& r) noexcept : base_t(std::forward<T>(r)) {
+#ifdef SOL_CHECK_ARGUMENTS
+ if (!is_function<meta::unqualified_t<T>>::value) {
+ auto pp = stack::push_pop(*this);
+ stack::check<basic_protected_function>(base_t::lua_state(), -1, type_panic);
+ }
+#endif // Safety
+ }
+ basic_protected_function(const basic_protected_function&) = default;
+ basic_protected_function& operator=(const basic_protected_function&) = default;
+ basic_protected_function(basic_protected_function&&) = default;
+ basic_protected_function& operator=(basic_protected_function&&) = default;
+ basic_protected_function(const basic_function<base_t>& b, reference eh = get_default_handler()) : base_t(b), error_handler(std::move(eh)) {}
+ basic_protected_function(basic_function<base_t>&& b, reference eh = get_default_handler()) : base_t(std::move(b)), error_handler(std::move(eh)) {}
+ basic_protected_function(const stack_reference& r, reference eh = get_default_handler()) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {}
+ basic_protected_function(stack_reference&& r, reference eh = get_default_handler()) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {}
+ template <typename Super>
+ basic_protected_function(proxy_base<Super>&& p, reference eh = get_default_handler()) : basic_protected_function(p.operator basic_function<base_t>(), std::move(eh)) {}
+ template <typename Super>
+ basic_protected_function(const proxy_base<Super>& p, reference eh = get_default_handler()) : basic_protected_function(static_cast<basic_function<base_t>>(p), std::move(eh)) {}
+ template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler>
+ basic_protected_function(lua_State* L, T&& r, reference eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {}
+ basic_protected_function(lua_State* L, int index = -1, reference eh = get_default_handler()) : base_t(L, index), error_handler(std::move(eh)) {
+#ifdef SOL_CHECK_ARGUMENTS
+ stack::check<basic_protected_function>(L, index, type_panic);
+#endif // Safety
+ }
+ basic_protected_function(lua_State* L, ref_index index, reference eh = get_default_handler()) : base_t(L, index), error_handler(std::move(eh)) {
+#ifdef SOL_CHECK_ARGUMENTS
+ auto pp = stack::push_pop(*this);
+ stack::check<basic_protected_function>(L, -1, type_panic);
+#endif // Safety
+ }
+
+ template<typename... Args>
+ protected_function_result operator()(Args&&... args) const {
+ return call<>(std::forward<Args>(args)...);
+ }
+
+ template<typename... Ret, typename... Args>
+ decltype(auto) operator()(types<Ret...>, Args&&... args) const {
+ return call<Ret...>(std::forward<Args>(args)...);
+ }
+
+ template<typename... Ret, typename... Args>
+ decltype(auto) call(Args&&... args) const {
+ detail::handler h(error_handler);
+ base_t::push();
+ int pushcount = stack::multi_push_reference(base_t::lua_state(), std::forward<Args>(args)...);
+ return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
+ }
+ };
+} // sol
+
+// end of sol/protected_function.hpp
+
+namespace sol {
+ struct stack_proxy : public proxy_base<stack_proxy> {
+ private:
+ lua_State* L;
+ int index;
+
+ public:
+ stack_proxy() : L(nullptr), index(0) {}
+ stack_proxy(lua_State* L, int index) : L(L), index(index) {}
+
+ template<typename T>
+ decltype(auto) get() const {
+ return stack::get<T>(L, stack_index());
+ }
+
+ int push() const {
+ return push(L);
+ }
+
+ int push(lua_State* Ls) const {
+ lua_pushvalue(Ls, index);
+ return 1;
+ }
+
+ lua_State* lua_state() const { return L; }
+ int stack_index() const { return index; }
+
+ template<typename... Ret, typename... Args>
+ decltype(auto) call(Args&&... args) {
+ return get<function>().template call<Ret...>(std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ decltype(auto) operator()(Args&&... args) {
+ return call<>(std::forward<Args>(args)...);
+ }
+ };
+
+ namespace stack {
+ template <>
+ struct getter<stack_proxy> {
+ static stack_proxy get(lua_State* L, int index = -1) {
+ return stack_proxy(L, index);
+ }
+ };
+
+ template <>
+ struct pusher<stack_proxy> {
+ static int push(lua_State*, const stack_proxy& ref) {
+ return ref.push();
+ }
+ };
+ } // stack
+
+ namespace detail {
+ template <>
+ struct is_speshul<function_result> : std::true_type {};
+ template <>
+ struct is_speshul<protected_function_result> : std::true_type {};
+
+ template <std::size_t I, typename... Args, typename T>
+ stack_proxy get(types<Args...>, index_value<0>, index_value<I>, const T& fr) {
+ return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
+ }
+
+ template <std::size_t I, std::size_t N, typename Arg, typename... Args, typename T, meta::enable<meta::boolean<(N > 0)>> = meta::enabler>
+ stack_proxy get(types<Arg, Args...>, index_value<N>, index_value<I>, const T& fr) {
+ return get(types<Args...>(), index_value<N - 1>(), index_value<I + lua_size<Arg>::value>(), fr);
+ }
+ }
+
+ template <>
+ struct tie_size<function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
+
+ template <std::size_t I>
+ stack_proxy get(const function_result& fr) {
+ return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
+ }
+
+ template <std::size_t I, typename... Args>
+ stack_proxy get(types<Args...> t, const function_result& fr) {
+ return detail::get(t, index_value<I>(), index_value<0>(), fr);
+ }
+
+ template <>
+ struct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
+
+ template <std::size_t I>
+ stack_proxy get(const protected_function_result& fr) {
+ return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
+ }
+
+ template <std::size_t I, typename... Args>
+ stack_proxy get(types<Args...> t, const protected_function_result& fr) {
+ return detail::get(t, index_value<I>(), index_value<0>(), fr);
+ }
+} // sol
+
+// end of sol/stack_proxy.hpp
+
+#include <limits>
+#include <iterator>
+
+namespace sol {
+ template <bool is_const>
+ struct va_iterator : std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const stack_proxy, stack_proxy>, std::ptrdiff_t, std::conditional_t<is_const, const stack_proxy*, stack_proxy*>, std::conditional_t<is_const, const stack_proxy, stack_proxy>> {
+ typedef std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const stack_proxy, stack_proxy>, std::ptrdiff_t, std::conditional_t<is_const, const stack_proxy*, stack_proxy*>, std::conditional_t<is_const, const stack_proxy, stack_proxy>> base_t;
+ typedef typename base_t::reference reference;
+ typedef typename base_t::pointer pointer;
+ typedef typename base_t::value_type value_type;
+ typedef typename base_t::difference_type difference_type;
+ typedef typename base_t::iterator_category iterator_category;
+ lua_State* L;
+ int index;
+ int stacktop;
+ stack_proxy sp;
+
+ va_iterator() : L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()) {}
+ va_iterator(lua_State* luastate, int idx, int topidx) : L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) {}
+
+ reference operator*() {
+ return stack_proxy(L, index);
+ }
+
+ pointer operator->() {
+ sp = stack_proxy(L, index);
+ return &sp;
+ }
+
+ va_iterator& operator++ () {
+ ++index;
+ return *this;
+ }
+
+ va_iterator operator++ (int) {
+ auto r = *this;
+ this->operator ++();
+ return r;
+ }
+
+ va_iterator& operator-- () {
+ --index;
+ return *this;
+ }
+
+ va_iterator operator-- (int) {
+ auto r = *this;
+ this->operator --();
+ return r;
+ }
+
+ va_iterator& operator+= (difference_type idx) {
+ index += static_cast<int>(idx);
+ return *this;
+ }
+
+ va_iterator& operator-= (difference_type idx) {
+ index -= static_cast<int>(idx);
+ return *this;
+ }
+
+ difference_type operator- (const va_iterator& r) const {
+ return index - r.index;
+ }
+
+ va_iterator operator+ (difference_type idx) const {
+ va_iterator r = *this;
+ r += idx;
+ return r;
+ }
+
+ reference operator[](difference_type idx) {
+ return stack_proxy(L, index + static_cast<int>(idx));
+ }
+
+ bool operator==(const va_iterator& r) const {
+ if (stacktop == (std::numeric_limits<int>::max)()) {
+ return r.index == r.stacktop;
+ }
+ else if (r.stacktop == (std::numeric_limits<int>::max)()) {
+ return index == stacktop;
+ }
+ return index == r.index;
+ }
+
+ bool operator != (const va_iterator& r) const {
+ return !(this->operator==(r));
+ }
+
+ bool operator < (const va_iterator& r) const {
+ return index < r.index;
+ }
+
+ bool operator > (const va_iterator& r) const {
+ return index > r.index;
+ }
+
+ bool operator <= (const va_iterator& r) const {
+ return index <= r.index;
+ }
+
+ bool operator >= (const va_iterator& r) const {
+ return index >= r.index;
+ }
+ };
+
+ template <bool is_const>
+ inline va_iterator<is_const> operator+(typename va_iterator<is_const>::difference_type n, const va_iterator<is_const>& r) {
+ return r + n;
+ }
+
+ struct variadic_args {
+ private:
+ lua_State* L;
+ int index;
+ int stacktop;
+
+ public:
+ typedef stack_proxy reference_type;
+ typedef stack_proxy value_type;
+ typedef stack_proxy* pointer;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::size_t size_type;
+ typedef va_iterator<false> iterator;
+ typedef va_iterator<true> const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ variadic_args() = default;
+ variadic_args(lua_State* luastate, int stackindex = -1) : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) {}
+ variadic_args(const variadic_args&) = default;
+ variadic_args& operator=(const variadic_args&) = default;
+ variadic_args(variadic_args&& o) : L(o.L), index(o.index), stacktop(o.stacktop) {
+ // Must be manual, otherwise destructor will screw us
+ // return count being 0 is enough to keep things clean
+ // but will be thorough
+ o.L = nullptr;
+ o.index = 0;
+ o.stacktop = 0;
+ }
+ variadic_args& operator=(variadic_args&& o) {
+ L = o.L;
+ index = o.index;
+ stacktop = o.stacktop;
+ // Must be manual, otherwise destructor will screw us
+ // return count being 0 is enough to keep things clean
+ // but will be thorough
+ o.L = nullptr;
+ o.index = 0;
+ o.stacktop = 0;
+ return *this;
+ }
+
+ iterator begin() { return iterator(L, index, stacktop + 1); }
+ iterator end() { return iterator(L, stacktop + 1, stacktop + 1); }
+ const_iterator begin() const { return const_iterator(L, index, stacktop + 1); }
+ const_iterator end() const { return const_iterator(L, stacktop + 1, stacktop + 1); }
+ const_iterator cbegin() const { return begin(); }
+ const_iterator cend() const { return end(); }
+
+ reverse_iterator rbegin() { return std::reverse_iterator<iterator>(begin()); }
+ reverse_iterator rend() { return std::reverse_iterator<iterator>(end()); }
+ const_reverse_iterator rbegin() const { return std::reverse_iterator<const_iterator>(begin()); }
+ const_reverse_iterator rend() const { return std::reverse_iterator<const_iterator>(end()); }
+ const_reverse_iterator crbegin() const { return std::reverse_iterator<const_iterator>(cbegin()); }
+ const_reverse_iterator crend() const { return std::reverse_iterator<const_iterator>(cend()); }
+
+ int push() const {
+ return push(L);
+ }
+
+ int push(lua_State* target) const {
+ int pushcount = 0;
+ for (int i = index; i <= stacktop; ++i) {
+ lua_pushvalue(L, i);
+ pushcount += 1;
+ }
+ if (target != L) {
+ lua_xmove(L, target, pushcount);
+ }
+ return pushcount;
+ }
+
+ template<typename T>
+ decltype(auto) get(difference_type start = 0) const {
+ return stack::get<T>(L, index + static_cast<int>(start));
+ }
+
+ stack_proxy operator[](difference_type start) const {
+ return stack_proxy(L, index + static_cast<int>(start));
+ }
+
+ lua_State* lua_state() const { return L; };
+ int stack_index() const { return index; };
+ int leftover_count() const { return stacktop - (index - 1); }
+ int top() const { return stacktop; }
+ };
+
+ namespace stack {
+ template <>
+ struct getter<variadic_args> {
+ static variadic_args get(lua_State* L, int index, record& tracking) {
+ tracking.last = 0;
+ return variadic_args(L, index);
+ }
+ };
+
+ template <>
+ struct pusher<variadic_args> {
+ static int push(lua_State* L, const variadic_args& ref) {
+ return ref.push(L);
+ }
+ };
+ } // stack
+} // sol
+
+// end of sol/variadic_args.hpp
+
+namespace sol {
+
+ template <typename R = reference, bool should_pop = !std::is_base_of<stack_reference, R>::value, typename T>
+ R make_reference(lua_State* L, T&& value) {
+ int backpedal = stack::push(L, std::forward<T>(value));
+ R r = stack::get<R>(L, -backpedal);
+ if (should_pop) {
+ lua_pop(L, backpedal);
+ }
+ return r;
+ }
+
+ template <typename T, typename R = reference, bool should_pop = !std::is_base_of<stack_reference, R>::value, typename... Args>
+ R make_reference(lua_State* L, Args&&... args) {
+ int backpedal = stack::push<T>(L, std::forward<Args>(args)...);
+ R r = stack::get<R>(L, -backpedal);
+ if (should_pop) {
+ lua_pop(L, backpedal);
+ }
+ return r;
+ }
+
+ template <typename base_t>
+ class basic_object : public base_t {
+ private:
+ template<typename T>
+ decltype(auto) as_stack(std::true_type) const {
+ return stack::get<T>(base_t::lua_state(), base_t::stack_index());
+ }
+
+ template<typename T>
+ decltype(auto) as_stack(std::false_type) const {
+ base_t::push();
+ return stack::pop<T>(base_t::lua_state());
+ }
+
+ template<typename T>
+ bool is_stack(std::true_type) const {
+ return stack::check<T>(base_t::lua_state(), base_t::stack_index(), no_panic);
+ }
+
+ template<typename T>
+ bool is_stack(std::false_type) const {
+ int r = base_t::registry_index();
+ if (r == LUA_REFNIL)
+ return meta::any_same<meta::unqualified_t<T>, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false;
+ if (r == LUA_NOREF)
+ return false;
+ auto pp = stack::push_pop(*this);
+ return stack::check<T>(base_t::lua_state(), -1, no_panic);
+ }
+
+ template <bool invert_and_pop = false>
+ basic_object(std::integral_constant<bool, invert_and_pop>, lua_State* L, int index = -1) noexcept : base_t(L, index) {
+ if (invert_and_pop) {
+ lua_pop(L, -index);
+ }
+ }
+
+ public:
+ basic_object() noexcept = default;
+ template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_t, meta::unqualified_t<T>>> = meta::enabler>
+ basic_object(T&& r) : base_t(std::forward<T>(r)) {}
+ basic_object(lua_nil_t r) : base_t(r) {}
+ basic_object(const basic_object&) = default;
+ basic_object(basic_object&&) = default;
+ basic_object(const stack_reference& r) noexcept : basic_object(r.lua_state(), r.stack_index()) {}
+ basic_object(stack_reference&& r) noexcept : basic_object(r.lua_state(), r.stack_index()) {}
+ template <typename Super>
+ basic_object(const proxy_base<Super>& r) noexcept : basic_object(r.operator basic_object()) {}
+ template <typename Super>
+ basic_object(proxy_base<Super>&& r) noexcept : basic_object(r.operator basic_object()) {}
+ basic_object(lua_State* L, int index = -1) noexcept : base_t(L, index) {}
+ basic_object(lua_State* L, ref_index index) noexcept : base_t(L, index) {}
+ template <typename T, typename... Args>
+ basic_object(lua_State* L, in_place_type_t<T>, Args&&... args) noexcept : basic_object(std::integral_constant<bool, !std::is_base_of<stack_reference, base_t>::value>(), L, -stack::push<T>(L, std::forward<Args>(args)...)) {}
+ template <typename T, typename... Args>
+ basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept : basic_object(L, in_place<T>, std::forward<T>(arg), std::forward<Args>(args)...) {}
+ basic_object& operator=(const basic_object&) = default;
+ basic_object& operator=(basic_object&&) = default;
+ basic_object& operator=(const base_t& b) { base_t::operator=(b); return *this; }
+ basic_object& operator=(base_t&& b) { base_t::operator=(std::move(b)); return *this; }
+ template <typename Super>
+ basic_object& operator=(const proxy_base<Super>& r) { this->operator=(r.operator basic_object()); return *this; }
+ template <typename Super>
+ basic_object& operator=(proxy_base<Super>&& r) { this->operator=(r.operator basic_object()); return *this; }
+
+ template<typename T>
+ decltype(auto) as() const {
+ return as_stack<T>(std::is_same<base_t, stack_reference>());
+ }
+
+ template<typename T>
+ bool is() const {
+ return is_stack<T>(std::is_same<base_t, stack_reference>());
+ }
+ };
+
+ template <typename T>
+ object make_object(lua_State* L, T&& value) {
+ return make_reference<object, true>(L, std::forward<T>(value));
+ }
+
+ template <typename T, typename... Args>
+ object make_object(lua_State* L, Args&&... args) {
+ return make_reference<T, object, true>(L, std::forward<Args>(args)...);
+ }
+
+ inline bool operator==(const object& lhs, const lua_nil_t&) {
+ return !lhs.valid();
+ }
+
+ inline bool operator==(const lua_nil_t&, const object& rhs) {
+ return !rhs.valid();
+ }
+
+ inline bool operator!=(const object& lhs, const lua_nil_t&) {
+ return lhs.valid();
+ }
+
+ inline bool operator!=(const lua_nil_t&, const object& rhs) {
+ return rhs.valid();
+ }
+} // sol
+
+// end of sol/object.hpp
+
+namespace sol {
+ template<typename Table, typename Key>
+ struct proxy : public proxy_base<proxy<Table, Key>> {
+ private:
+ typedef meta::condition<meta::is_specialization_of<std::tuple, Key>, Key, std::tuple<meta::condition<std::is_array<meta::unqualified_t<Key>>, Key&, meta::unqualified_t<Key>>>> key_type;
+
+ template<typename T, std::size_t... I>
+ decltype(auto) tuple_get(std::index_sequence<I...>) const {
+ return tbl.template traverse_get<T>(std::get<I>(key)...);
+ }
+
+ template<std::size_t... I, typename T>
+ void tuple_set(std::index_sequence<I...>, T&& value) {
+ tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value));
+ }
+
+ public:
+ Table tbl;
+ key_type key;
+
+ template<typename T>
+ proxy(Table table, T&& k) : tbl(table), key(std::forward<T>(k)) {}
+
+ template<typename T>
+ proxy& set(T&& item) {
+ tuple_set(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>(), std::forward<T>(item));
+ return *this;
+ }
+
+ template<typename... Args>
+ proxy& set_function(Args&&... args) {
+ tbl.set_function(key, std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template<typename U, meta::enable<meta::neg<is_lua_reference<meta::unwrap_unqualified_t<U>>>, meta::is_callable<meta::unwrap_unqualified_t<U>>> = meta::enabler>
+ proxy& operator=(U&& other) {
+ return set_function(std::forward<U>(other));
+ }
+
+ template<typename U, meta::disable<meta::neg<is_lua_reference<meta::unwrap_unqualified_t<U>>>, meta::is_callable<meta::unwrap_unqualified_t<U>>> = meta::enabler>
+ proxy& operator=(U&& other) {
+ return set(std::forward<U>(other));
+ }
+
+ template<typename T>
+ decltype(auto) get() const {
+ return tuple_get<T>(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>());
+ }
+
+ template<typename T>
+ decltype(auto) get_or(T&& otherwise) const {
+ typedef decltype(get<T>()) U;
+ sol::optional<U> option = get<sol::optional<U>>();
+ if (option) {
+ return static_cast<U>(option.value());
+ }
+ return static_cast<U>(std::forward<T>(otherwise));
+ }
+
+ template<typename T, typename D>
+ decltype(auto) get_or(D&& otherwise) const {
+ sol::optional<T> option = get<sol::optional<T>>();
+ if (option) {
+ return static_cast<T>(option.value());
+ }
+ return static_cast<T>(std::forward<D>(otherwise));
+ }
+
+ template <typename K>
+ decltype(auto) operator[](K&& k) const {
+ auto keys = meta::tuplefy(key, std::forward<K>(k));
+ return proxy<Table, decltype(keys)>(tbl, std::move(keys));
+ }
+
+ template<typename... Ret, typename... Args>
+ decltype(auto) call(Args&&... args) {
+ return get<function>().template call<Ret...>(std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ decltype(auto) operator()(Args&&... args) {
+ return call<>(std::forward<Args>(args)...);
+ }
+
+ bool valid() const {
+ auto pp = stack::push_pop(tbl);
+ auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(tbl.lua_state(), key, lua_gettop(tbl.lua_state()));
+ lua_pop(tbl.lua_state(), p.levels);
+ return p;
+ }
+ };
+
+ template<typename Table, typename Key, typename T>
+ inline bool operator==(T&& left, const proxy<Table, Key>& right) {
+ typedef decltype(stack::get<T>(nullptr, 0)) U;
+ return right.template get<optional<U>>() == left;
+ }
+
+ template<typename Table, typename Key, typename T>
+ inline bool operator==(const proxy<Table, Key>& right, T&& left) {
+ typedef decltype(stack::get<T>(nullptr, 0)) U;
+ return right.template get<optional<U>>() == left;
+ }
+
+ template<typename Table, typename Key, typename T>
+ inline bool operator!=(T&& left, const proxy<Table, Key>& right) {
+ typedef decltype(stack::get<T>(nullptr, 0)) U;
+ return right.template get<optional<U>>() == left;
+ }
+
+ template<typename Table, typename Key, typename T>
+ inline bool operator!=(const proxy<Table, Key>& right, T&& left) {
+ typedef decltype(stack::get<T>(nullptr, 0)) U;
+ return right.template get<optional<U>>() == left;
+ }
+
+ template<typename Table, typename Key>
+ inline bool operator==(lua_nil_t, const proxy<Table, Key>& right) {
+ return !right.valid();
+ }
+
+ template<typename Table, typename Key>
+ inline bool operator==(const proxy<Table, Key>& right, lua_nil_t) {
+ return !right.valid();
+ }
+
+ template<typename Table, typename Key>
+ inline bool operator!=(lua_nil_t, const proxy<Table, Key>& right) {
+ return right.valid();
+ }
+
+ template<typename Table, typename Key>
+ inline bool operator!=(const proxy<Table, Key>& right, lua_nil_t) {
+ return right.valid();
+ }
+
+ namespace stack {
+ template <typename Table, typename Key>
+ struct pusher<proxy<Table, Key>> {
+ static int push(lua_State* L, const proxy<Table, Key>& p) {
+ sol::reference r = p;
+ return r.push(L);
+ }
+ };
+ } // stack
+} // sol
+
+// end of sol/proxy.hpp
+
+// beginning of sol/usertype.hpp
+
+// beginning of sol/usertype_metatable.hpp
+
+// beginning of sol/deprecate.hpp
+
+#ifndef SOL_DEPRECATED
+ #ifdef _MSC_VER
+ #define SOL_DEPRECATED __declspec(deprecated)
+ #elif __GNUC__
+ #define SOL_DEPRECATED __attribute__((deprecated))
+ #else
+ #define SOL_DEPRECATED [[deprecated]]
+ #endif // compilers
+#endif // SOL_DEPRECATED
+
+namespace sol {
+ namespace detail {
+ template <typename T>
+ struct SOL_DEPRECATED deprecate_type {
+ using type = T;
+ };
+ } // detail
+} // sol
+
+// end of sol/deprecate.hpp
+
+#include <unordered_map>
+#include <cstdio>
+
+namespace sol {
+ namespace usertype_detail {
+ typedef void(*base_walk)(lua_State*, bool&, int&, string_detail::string_shim&);
+ typedef int(*member_search)(lua_State*, void*, int);
+
+ struct call_information {
+ member_search first;
+ member_search second;
+ int runtime_target;
+
+ call_information(member_search first, member_search second) : call_information(first, second, -1) {}
+ call_information(member_search first, member_search second, int runtimetarget) : first(first), second(second), runtime_target(runtimetarget) {}
+ };
+
+ typedef std::unordered_map<std::string, call_information> mapping_t;
+ }
+
+ struct usertype_metatable_core {
+ usertype_detail::mapping_t mapping;
+ lua_CFunction indexfunc;
+ lua_CFunction newindexfunc;
+ std::vector<object> runtime;
+ bool mustindex;
+
+ usertype_metatable_core(lua_CFunction ifx, lua_CFunction nifx) :
+ mapping(), indexfunc(ifx),
+ newindexfunc(nifx), runtime(), mustindex(false)
+ {
+
+ }
+
+ usertype_metatable_core(const usertype_metatable_core&) = default;
+ usertype_metatable_core(usertype_metatable_core&&) = default;
+ usertype_metatable_core& operator=(const usertype_metatable_core&) = default;
+ usertype_metatable_core& operator=(usertype_metatable_core&&) = default;
+
+ };
+
+ namespace usertype_detail {
+ const lua_Integer toplevel_magic = static_cast<lua_Integer>(0x00020001);
+
+ struct add_destructor_tag {};
+ struct check_destructor_tag {};
+ struct verified_tag {} const verified{};
+
+ template <typename T>
+ struct is_non_factory_constructor : std::false_type {};
+
+ template <typename... Args>
+ struct is_non_factory_constructor<constructors<Args...>> : std::true_type {};
+
+ template <typename... Args>
+ struct is_non_factory_constructor<constructor_wrapper<Args...>> : std::true_type {};
+
+ template <>
+ struct is_non_factory_constructor<no_construction> : std::true_type {};
+
+ template <typename T>
+ struct is_constructor : is_non_factory_constructor<T> {};
+
+ template <typename... Args>
+ struct is_constructor<factory_wrapper<Args...>> : std::true_type {};
+
+ template <typename... Args>
+ using has_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>;
+
+ template <typename T>
+ struct is_destructor : std::false_type {};
+
+ template <typename Fx>
+ struct is_destructor<destructor_wrapper<Fx>> : std::true_type {};
+
+ template <typename... Args>
+ using has_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>;
+
+ struct no_comp {
+ template <typename A, typename B>
+ bool operator()(A&&, B&&) const {
+ return false;
+ }
+ };
+
+ inline bool is_indexer(string_detail::string_shim s) {
+ return s == name_of(meta_function::index) || s == name_of(meta_function::new_index);
+ }
+
+ inline bool is_indexer(meta_function mf) {
+ return mf == meta_function::index || mf == meta_function::new_index;
+ }
+
+ inline bool is_indexer(call_construction) {
+ return false;
+ }
+
+ inline bool is_indexer(base_classes_tag) {
+ return false;
+ }
+
+ inline auto make_shim(string_detail::string_shim s) {
+ return s;
+ }
+
+ inline auto make_shim(call_construction) {
+ return string_detail::string_shim(name_of(meta_function::call_function));
+ }
+
+ inline auto make_shim(meta_function mf) {
+ return string_detail::string_shim(name_of(mf));
+ }
+
+ inline auto make_shim(base_classes_tag) {
+ return string_detail::string_shim(detail::base_class_cast_key());
+ }
+
+ template <typename Arg>
+ inline std::string make_string(Arg&& arg) {
+ string_detail::string_shim s = make_shim(arg);
+ return std::string(s.c_str(), s.size());
+ }
+
+ template <typename N>
+ inline luaL_Reg make_reg(N&& n, lua_CFunction f) {
+ luaL_Reg l{ make_shim(std::forward<N>(n)).c_str(), f };
+ return l;
+ }
+
+ struct registrar {
+ registrar() = default;
+ registrar(const registrar&) = default;
+ registrar(registrar&&) = default;
+ registrar& operator=(const registrar&) = default;
+ registrar& operator=(registrar&&) = default;
+ virtual int push_um(lua_State* L) = 0;
+ virtual ~registrar() {}
+ };
+
+ inline int runtime_object_call(lua_State* L, void*, int runtimetarget) {
+ usertype_metatable_core& umc = stack::get<light<usertype_metatable_core>>(L, upvalue_index(2));
+ std::vector<object>& runtime = umc.runtime;
+ return stack::push(L, runtime[runtimetarget]);
+ }
+
+ template <bool is_index>
+ inline int indexing_fail(lua_State* L) {
+ if (is_index) {
+#if 0//def SOL_SAFE_USERTYPE
+ auto maybeaccessor = stack::get<optional<string_detail::string_shim>>(L, is_index ? -1 : -2);
+ string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)"));
+ return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str());
+#else
+ // With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately...
+ return stack::push(L, lua_nil);
+#endif
+ }
+ else {
+ auto maybeaccessor = stack::get<optional<string_detail::string_shim>>(L, is_index ? -1 : -2);
+ string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)"));
+ return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str());
+ }
+ }
+
+ template <typename T, bool is_simple>
+ inline int metatable_newindex(lua_State* L) {
+ int isnum = 0;
+ lua_Integer magic = lua_tointegerx(L, upvalue_index(4), &isnum);
+ if (isnum != 0 && magic == toplevel_magic) {
+ auto non_simple = [&L]() {
+ if (is_simple)
+ return;
+ usertype_metatable_core& umc = stack::get<light<usertype_metatable_core>>(L, upvalue_index(2));
+ bool mustindex = umc.mustindex;
+ if (!mustindex)
+ return;
+ std::string accessor = stack::get<std::string>(L, 2);
+ mapping_t& mapping = umc.mapping;
+ std::vector<object>& runtime = umc.runtime;
+ int target = static_cast<int>(runtime.size());
+ auto preexistingit = mapping.find(accessor);
+ if (preexistingit == mapping.cend()) {
+ runtime.emplace_back(L, 3);
+ mapping.emplace_hint(mapping.cend(), accessor, call_information(&runtime_object_call, &runtime_object_call, target));
+ }
+ else {
+ target = preexistingit->second.runtime_target;
+ runtime[target] = sol::object(L, 3);
+ preexistingit->second = call_information(&runtime_object_call, &runtime_object_call, target);
+ }
+ };
+ non_simple();
+ for (std::size_t i = 0; i < 4; lua_pop(L, 1), ++i) {
+ const char* metakey = nullptr;
+ switch (i) {
+ case 0:
+ metakey = &usertype_traits<T*>::metatable()[0];
+ break;
+ case 1:
+ metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0];
+ break;
+ case 2:
+ metakey = &usertype_traits<T>::user_metatable()[0];
+ break;
+ case 3:
+ default:
+ metakey = &usertype_traits<T>::metatable()[0];
+ break;
+ }
+ luaL_getmetatable(L, metakey);
+ int tableindex = lua_gettop(L);
+ if (type_of(L, tableindex) == type::lua_nil) {
+ continue;
+ }
+ stack::set_field<false, true>(L, stack_reference(L, 2), stack_reference(L, 3), tableindex);
+ }
+ lua_settop(L, 0);
+ return 0;
+ }
+ return indexing_fail<false>(L);
+ }
+
+ template <bool is_index, typename Base>
+ static void walk_single_base(lua_State* L, bool& found, int& ret, string_detail::string_shim&) {
+ if (found)
+ return;
+ const char* metakey = &usertype_traits<Base>::metatable()[0];
+ const char* gcmetakey = &usertype_traits<Base>::gc_table()[0];
+ const char* basewalkkey = is_index ? detail::base_class_index_propogation_key() : detail::base_class_new_index_propogation_key();
+
+ luaL_getmetatable(L, metakey);
+ if (type_of(L, -1) == type::lua_nil) {
+ lua_pop(L, 1);
+ return;
+ }
+
+ stack::get_field(L, basewalkkey);
+ if (type_of(L, -1) == type::lua_nil) {
+ lua_pop(L, 2);
+ return;
+ }
+ lua_CFunction basewalkfunc = stack::pop<lua_CFunction>(L);
+ lua_pop(L, 1);
+
+ stack::get_field<true>(L, gcmetakey);
+ int value = basewalkfunc(L);
+ if (value > -1) {
+ found = true;
+ ret = value;
+ }
+ }
+
+ template <bool is_index, typename... Bases>
+ static void walk_all_bases(lua_State* L, bool& found, int& ret, string_detail::string_shim& accessor) {
+ (void)L;
+ (void)found;
+ (void)ret;
+ (void)accessor;
+ (void)detail::swallow{ 0, (walk_single_base<is_index, Bases>(L, found, ret, accessor), 0)... };
+ }
+
+ template <typename T, typename Op>
+ inline int operator_wrap(lua_State* L) {
+ auto maybel = stack::check_get<T>(L, 1);
+ if (maybel) {
+ auto mayber = stack::check_get<T>(L, 2);
+ if (mayber) {
+ auto& l = *maybel;
+ auto& r = *mayber;
+ if (std::is_same<no_comp, Op>::value) {
+ return stack::push(L, detail::ptr(l) == detail::ptr(r));
+ }
+ else {
+ Op op;
+ return stack::push(L, (detail::ptr(l) == detail::ptr(r)) || op(detail::deref(l), detail::deref(r)));
+ }
+ }
+ }
+ return stack::push(L, false);
+ }
+
+ template <typename T, typename Op, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler>
+ inline void make_reg_op(Regs& l, int& index, const char* name) {
+ l[index] = { name, &operator_wrap<T, Op> };
+ ++index;
+ }
+
+ template <typename T, typename Op, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler>
+ inline void make_reg_op(Regs&, int&, const char*) {
+ // Do nothing if there's no support
+ }
+ } // usertype_detail
+
+ template <typename T>
+ struct clean_type {
+ typedef std::conditional_t<std::is_array<meta::unqualified_t<T>>::value, T&, std::decay_t<T>> type;
+ };
+
+ template <typename T>
+ using clean_type_t = typename clean_type<T>::type;
+
+ template <typename T, typename IndexSequence, typename... Tn>
+ struct usertype_metatable : usertype_detail::registrar {};
+
+ template <typename T, std::size_t... I, typename... Tn>
+ struct usertype_metatable<T, std::index_sequence<I...>, Tn...> : usertype_metatable_core, usertype_detail::registrar {
+ typedef std::make_index_sequence<sizeof...(I) * 2> indices;
+ typedef std::index_sequence<I...> half_indices;
+ typedef std::array<luaL_Reg, sizeof...(Tn) / 2 + 1 + 3> regs_t;
+ typedef std::tuple<Tn...> RawTuple;
+ typedef std::tuple<clean_type_t<Tn> ...> Tuple;
+ template <std::size_t Idx>
+ struct check_binding : is_variable_binding<meta::unqualified_tuple_element_t<Idx, Tuple>> {};
+ Tuple functions;
+ lua_CFunction destructfunc;
+ lua_CFunction callconstructfunc;
+ lua_CFunction indexbase;
+ lua_CFunction newindexbase;
+ usertype_detail::base_walk indexbaseclasspropogation;
+ usertype_detail::base_walk newindexbaseclasspropogation;
+ void* baseclasscheck;
+ void* baseclasscast;
+ bool secondarymeta;
+ bool hasequals;
+ bool hasless;
+ bool haslessequals;
+
+ template <std::size_t Idx, meta::enable<std::is_same<lua_CFunction, meta::unqualified_tuple_element<Idx + 1, RawTuple>>> = meta::enabler>
+ lua_CFunction make_func() const {
+ return std::get<Idx + 1>(functions);
+ }
+
+ template <std::size_t Idx, meta::disable<std::is_same<lua_CFunction, meta::unqualified_tuple_element<Idx + 1, RawTuple>>> = meta::enabler>
+ lua_CFunction make_func() const {
+ const auto& name = std::get<Idx>(functions);
+ return (usertype_detail::make_shim(name) == "__newindex") ? &call<Idx + 1, false> : &call<Idx + 1, true>;
+ }
+
+ static bool contains_variable() {
+ typedef meta::any<check_binding<(I * 2 + 1)>...> has_variables;
+ return has_variables::value;
+ }
+
+ bool contains_index() const {
+ bool idx = false;
+ (void)detail::swallow{ 0, ((idx |= usertype_detail::is_indexer(std::get<I * 2>(functions))), 0) ... };
+ return idx;
+ }
+
+ int finish_regs(regs_t& l, int& index) {
+ if (!hasless) {
+ const char* name = name_of(meta_function::less_than).c_str();
+ usertype_detail::make_reg_op<T, std::less<>, meta::supports_op_less<T>>(l, index, name);
+ }
+ if (!haslessequals) {
+ const char* name = name_of(meta_function::less_than_or_equal_to).c_str();
+ usertype_detail::make_reg_op<T, std::less_equal<>, meta::supports_op_less_equal<T>>(l, index, name);
+ }
+ if (!hasequals) {
+ const char* name = name_of(meta_function::equal_to).c_str();
+ usertype_detail::make_reg_op<T, std::conditional_t<meta::supports_op_equal<T>::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name);
+ }
+ if (destructfunc != nullptr) {
+ l[index] = { name_of(meta_function::garbage_collect).c_str(), destructfunc };
+ ++index;
+ }
+ return index;
+ }
+
+ template <std::size_t Idx, typename F>
+ void make_regs(regs_t&, int&, call_construction, F&&) {
+ callconstructfunc = call<Idx + 1>;
+ secondarymeta = true;
+ }
+
+ template <std::size_t, typename... Bases>
+ void make_regs(regs_t&, int&, base_classes_tag, bases<Bases...>) {
+ if (sizeof...(Bases) < 1) {
+ return;
+ }
+ mustindex = true;
+ (void)detail::swallow{ 0, ((detail::has_derived<Bases>::value = true), 0)... };
+
+ static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
+ static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
+ baseclasscheck = (void*)&detail::inheritance<T, Bases...>::type_check;
+ baseclasscast = (void*)&detail::inheritance<T, Bases...>::type_cast;
+ indexbaseclasspropogation = usertype_detail::walk_all_bases<true, Bases...>;
+ newindexbaseclasspropogation = usertype_detail::walk_all_bases<false, Bases...>;
+ }
+
+ template <std::size_t Idx, typename N, typename F, typename = std::enable_if_t<!meta::any_same<meta::unqualified_t<N>, base_classes_tag, call_construction>::value>>
+ void make_regs(regs_t& l, int& index, N&& n, F&&) {
+ if (is_variable_binding<meta::unqualified_t<F>>::value) {
+ return;
+ }
+ luaL_Reg reg = usertype_detail::make_reg(std::forward<N>(n), make_func<Idx>());
+ // Returnable scope
+ // That would be a neat keyword for C++
+ // returnable { ... };
+ if (reg.name == name_of(meta_function::equal_to)) {
+ hasequals = true;
+ }
+ if (reg.name == name_of(meta_function::less_than)) {
+ hasless = true;
+ }
+ if (reg.name == name_of(meta_function::less_than_or_equal_to)) {
+ haslessequals = true;
+ }
+ if (reg.name == name_of(meta_function::garbage_collect)) {
+ destructfunc = reg.func;
+ return;
+ }
+ else if (reg.name == name_of(meta_function::index)) {
+ indexfunc = reg.func;
+ mustindex = true;
+ return;
+ }
+ else if (reg.name == name_of(meta_function::new_index)) {
+ newindexfunc = reg.func;
+ mustindex = true;
+ return;
+ }
+ l[index] = reg;
+ ++index;
+ }
+
+ template <typename... Args, typename = std::enable_if_t<sizeof...(Args) == sizeof...(Tn)>>
+ usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail<true>, &usertype_detail::metatable_newindex<T, false>), usertype_detail::registrar(),
+ functions(std::forward<Args>(args)...),
+ destructfunc(nullptr), callconstructfunc(nullptr),
+ indexbase(&core_indexing_call<true>), newindexbase(&core_indexing_call<false>),
+ indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(usertype_detail::walk_all_bases<false>),
+ baseclasscheck(nullptr), baseclasscast(nullptr),
+ secondarymeta(contains_variable()),
+ hasequals(false), hasless(false), haslessequals(false) {
+ std::initializer_list<typename usertype_detail::mapping_t::value_type> ilist{ {
+ std::pair<std::string, usertype_detail::call_information>( usertype_detail::make_string(std::get<I * 2>(functions)),
+ usertype_detail::call_information(&usertype_metatable::real_find_call<I * 2, I * 2 + 1, false>,
+ &usertype_metatable::real_find_call<I * 2, I * 2 + 1, true>)
+ )
+ }... };
+ this->mapping.insert(ilist);
+ for (const auto& n : meta_function_names) {
+ this->mapping.erase(n);
+ }
+ this->mustindex = contains_variable() || contains_index();
+ }
+
+ usertype_metatable(const usertype_metatable&) = default;
+ usertype_metatable(usertype_metatable&&) = default;
+ usertype_metatable& operator=(const usertype_metatable&) = default;
+ usertype_metatable& operator=(usertype_metatable&&) = default;
+
+ template <std::size_t I0, std::size_t I1, bool is_index>
+ static int real_find_call(lua_State* L, void* um, int) {
+ auto& f = *static_cast<usertype_metatable*>(um);
+ if (is_variable_binding<decltype(std::get<I1>(f.functions))>::value) {
+ return real_call_with<I1, is_index, true>(L, f);
+ }
+ int upvalues = stack::push(L, light<usertype_metatable>(f));
+ auto cfunc = &call<I1, is_index>;
+ return stack::push(L, c_closure(cfunc, upvalues));
+ }
+
+ template <bool is_index>
+ static int real_meta_call(lua_State* L, void* um, int) {
+ auto& f = *static_cast<usertype_metatable*>(um);
+ return is_index ? f.indexfunc(L) : f.newindexfunc(L);
+ }
+
+ template <bool is_index, bool toplevel = false>
+ static int core_indexing_call(lua_State* L) {
+ usertype_metatable& f = toplevel ? stack::get<light<usertype_metatable>>(L, upvalue_index(1)) : stack::pop<light<usertype_metatable>>(L);
+ static const int keyidx = -2 + static_cast<int>(is_index);
+ if (toplevel && stack::get<type>(L, keyidx) != type::string) {
+ return is_index ? f.indexfunc(L) : f.newindexfunc(L);
+ }
+ std::string name = stack::get<std::string>(L, keyidx);
+ auto memberit = f.mapping.find(name);
+ if (memberit != f.mapping.cend()) {
+ const usertype_detail::call_information& ci = memberit->second;
+ const usertype_detail::member_search& member = is_index ? ci.second : ci.first;
+ return (member)(L, static_cast<void*>(&f), ci.runtime_target);
+ }
+ string_detail::string_shim accessor = name;
+ int ret = 0;
+ bool found = false;
+ // Otherwise, we need to do propagating calls through the bases
+ if (is_index)
+ f.indexbaseclasspropogation(L, found, ret, accessor);
+ else
+ f.newindexbaseclasspropogation(L, found, ret, accessor);
+ if (found) {
+ return ret;
+ }
+ return toplevel ? (is_index ? f.indexfunc(L) : f.newindexfunc(L)) : -1;
+ }
+
+ static int real_index_call(lua_State* L) {
+ return core_indexing_call<true, true>(L);
+ }
+
+ static int real_new_index_call(lua_State* L) {
+ return core_indexing_call<false, true>(L);
+ }
+
+ template <std::size_t Idx, bool is_index = true, bool is_variable = false>
+ static int real_call(lua_State* L) {
+ usertype_metatable& f = stack::get<light<usertype_metatable>>(L, upvalue_index(1));
+ return real_call_with<Idx, is_index, is_variable>(L, f);
+ }
+
+ template <std::size_t Idx, bool is_index = true, bool is_variable = false>
+ static int real_call_with(lua_State* L, usertype_metatable& um) {
+ typedef meta::unqualified_tuple_element_t<Idx - 1, Tuple> K;
+ typedef meta::unqualified_tuple_element_t<Idx, Tuple> F;
+ static const int boost =
+ !usertype_detail::is_non_factory_constructor<F>::value
+ && std::is_same<K, call_construction>::value ?
+ 1 : 0;
+ auto& f = std::get<Idx>(um.functions);
+ return call_detail::call_wrapped<T, is_index, is_variable, boost>(L, f);
+ }
+
+ template <std::size_t Idx, bool is_index = true, bool is_variable = false>
+ static int call(lua_State* L) {
+ return detail::static_trampoline<(&real_call<Idx, is_index, is_variable>)>(L);
+ }
+
+ template <std::size_t Idx, bool is_index = true, bool is_variable = false>
+ static int call_with(lua_State* L) {
+ return detail::static_trampoline<(&real_call_with<Idx, is_index, is_variable>)>(L);
+ }
+
+ static int index_call(lua_State* L) {
+ return detail::static_trampoline<(&real_index_call)>(L);
+ }
+
+ static int new_index_call(lua_State* L) {
+ return detail::static_trampoline<(&real_new_index_call)>(L);
+ }
+
+ virtual int push_um(lua_State* L) override {
+ return stack::push(L, std::move(*this));
+ }
+
+ ~usertype_metatable() override {
+
+ }
+ };
+
+ namespace stack {
+
+ template <typename T, std::size_t... I, typename... Args>
+ struct pusher<usertype_metatable<T, std::index_sequence<I...>, Args...>> {
+ typedef usertype_metatable<T, std::index_sequence<I...>, Args...> umt_t;
+ typedef typename umt_t::regs_t regs_t;
+
+ static umt_t& make_cleanup(lua_State* L, umt_t&& umx) {
+ // ensure some sort of uniqueness
+ static int uniqueness = 0;
+ std::string uniquegcmetakey = usertype_traits<T>::user_gc_metatable();
+ // std::to_string doesn't exist in android still, with NDK, so this bullshit
+ // is necessary
+ // thanks, Android :v
+ int appended = snprintf(nullptr, 0, "%d", uniqueness);
+ std::size_t insertionpoint = uniquegcmetakey.length() - 1;
+ uniquegcmetakey.append(appended, '\0');
+ char* uniquetarget = &uniquegcmetakey[insertionpoint];
+ snprintf(uniquetarget, uniquegcmetakey.length(), "%d", uniqueness);
+ ++uniqueness;
+
+ const char* gcmetakey = &usertype_traits<T>::gc_table()[0];
+ // Make sure userdata's memory is properly in lua first,
+ // otherwise all the light userdata we make later will become invalid
+ stack::push<user<umt_t>>(L, metatable_key, uniquegcmetakey, std::move(umx));
+ // Create the top level thing that will act as our deleter later on
+ stack_reference umt(L, -1);
+ stack::set_field<true>(L, gcmetakey, umt);
+ umt.pop();
+
+ stack::get_field<true>(L, gcmetakey);
+ return stack::pop<light<umt_t>>(L);
+ }
+
+ static int push(lua_State* L, umt_t&& umx) {
+
+ umt_t& um = make_cleanup(L, std::move(umx));
+ usertype_metatable_core& umc = um;
+ regs_t value_table{ {} };
+ int lastreg = 0;
+ (void)detail::swallow{ 0, (um.template make_regs<(I * 2)>(value_table, lastreg, std::get<(I * 2)>(um.functions), std::get<(I * 2 + 1)>(um.functions)), 0)... };
+ um.finish_regs(value_table, lastreg);
+ value_table[lastreg] = { nullptr, nullptr };
+ regs_t ref_table = value_table;
+ regs_t unique_table = value_table;
+ bool hasdestructor = !value_table.empty() && name_of(meta_function::garbage_collect) == value_table[lastreg - 1].name;
+ if (hasdestructor) {
+ ref_table[lastreg - 1] = { nullptr, nullptr };
+ unique_table[lastreg - 1] = { value_table[lastreg - 1].name, detail::unique_destruct<T> };
+ }
+
+ // Now use um
+ const bool& mustindex = umc.mustindex;
+ for (std::size_t i = 0; i < 3; ++i) {
+ // Pointer types, AKA "references" from C++
+ const char* metakey = nullptr;
+ luaL_Reg* metaregs = nullptr;
+ switch (i) {
+ case 0:
+ metakey = &usertype_traits<T*>::metatable()[0];
+ metaregs = ref_table.data();
+ break;
+ case 1:
+ metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0];
+ metaregs = unique_table.data();
+ break;
+ case 2:
+ default:
+ metakey = &usertype_traits<T>::metatable()[0];
+ metaregs = value_table.data();
+ break;
+ }
+ luaL_newmetatable(L, metakey);
+ stack_reference t(L, -1);
+ stack::push(L, make_light(um));
+ luaL_setfuncs(L, metaregs, 1);
+
+ if (um.baseclasscheck != nullptr) {
+ stack::set_field(L, detail::base_class_check_key(), um.baseclasscheck, t.stack_index());
+ }
+ if (um.baseclasscast != nullptr) {
+ stack::set_field(L, detail::base_class_cast_key(), um.baseclasscast, t.stack_index());
+ }
+
+ stack::set_field(L, detail::base_class_index_propogation_key(), make_closure(um.indexbase, make_light(um), make_light(umc)), t.stack_index());
+ stack::set_field(L, detail::base_class_new_index_propogation_key(), make_closure(um.newindexbase, make_light(um), make_light(umc)), t.stack_index());
+
+ if (mustindex) {
+ // Basic index pushing: specialize
+ // index and newindex to give variables and stuff
+ stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um), make_light(umc)), t.stack_index());
+ stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um), make_light(umc)), t.stack_index());
+ }
+ else {
+ // If there's only functions, we can use the fast index version
+ stack::set_field(L, meta_function::index, t, t.stack_index());
+ }
+ // metatable on the metatable
+ // for call constructor purposes and such
+ lua_createtable(L, 0, 3);
+ stack_reference metabehind(L, -1);
+ if (um.callconstructfunc != nullptr) {
+ stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um), make_light(umc)), metabehind.stack_index());
+ }
+ if (um.secondarymeta) {
+ stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um), make_light(umc)), metabehind.stack_index());
+ stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um), make_light(umc)), metabehind.stack_index());
+ }
+ stack::set_field(L, metatable_key, metabehind, t.stack_index());
+ metabehind.pop();
+ // We want to just leave the table
+ // in the registry only, otherwise we return it
+ t.pop();
+ }
+
+ // Now for the shim-table that actually gets assigned to the name
+ luaL_newmetatable(L, &usertype_traits<T>::user_metatable()[0]);
+ stack_reference t(L, -1);
+ stack::push(L, make_light(um));
+ luaL_setfuncs(L, value_table.data(), 1);
+ {
+ lua_createtable(L, 0, 3);
+ stack_reference metabehind(L, -1);
+ if (um.callconstructfunc != nullptr) {
+ stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um), make_light(umc)), metabehind.stack_index());
+ }
+
+ stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um), make_light(umc), 0, usertype_detail::toplevel_magic), metabehind.stack_index());
+ stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um), make_light(umc), 0, usertype_detail::toplevel_magic), metabehind.stack_index());
+
+ stack::set_field(L, metatable_key, metabehind, t.stack_index());
+ metabehind.pop();
+ }
+
+ return 1;
+ }
+ };
+
+ } // stack
+
+} // sol
+
+// end of sol/usertype_metatable.hpp
+
+// beginning of sol/simple_usertype_metatable.hpp
+
+namespace sol {
+
+ namespace usertype_detail {
+ struct variable_wrapper {
+ virtual int index(lua_State* L) = 0;
+ virtual int new_index(lua_State* L) = 0;
+ virtual ~variable_wrapper() {};
+ };
+
+ template <typename T, typename F>
+ struct callable_binding : variable_wrapper {
+ F fx;
+
+ template <typename Arg>
+ callable_binding(Arg&& arg) : fx(std::forward<Arg>(arg)) {}
+
+ virtual int index(lua_State* L) override {
+ return call_detail::call_wrapped<T, true, true>(L, fx);
+ }
+
+ virtual int new_index(lua_State* L) override {
+ return call_detail::call_wrapped<T, false, true>(L, fx);
+ }
+ };
+
+ typedef std::unordered_map<std::string, std::unique_ptr<variable_wrapper>> variable_map;
+ typedef std::unordered_map<std::string, object> function_map;
+
+ struct simple_map {
+ const char* metakey;
+ variable_map variables;
+ function_map functions;
+ base_walk indexbaseclasspropogation;
+ base_walk newindexbaseclasspropogation;
+
+ simple_map(const char* mkey, base_walk index, base_walk newindex, variable_map&& vars, function_map&& funcs) : metakey(mkey), variables(std::move(vars)), functions(std::move(funcs)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {}
+ };
+
+ template <bool is_index, bool toplevel = false>
+ inline int simple_core_indexing_call(lua_State* L) {
+ simple_map& sm = toplevel ? stack::get<user<simple_map>>(L, upvalue_index(1)) : stack::pop<user<simple_map>>(L);
+ variable_map& variables = sm.variables;
+ function_map& functions = sm.functions;
+ static const int keyidx = -2 + static_cast<int>(is_index);
+ if (toplevel) {
+ if (stack::get<type>(L, keyidx) != type::string) {
+ lua_CFunction indexingfunc = is_index ? stack::get<lua_CFunction>(L, upvalue_index(2)) : stack::get<lua_CFunction>(L, upvalue_index(3));
+ return indexingfunc(L);
+ }
+ }
+ string_detail::string_shim accessor = stack::get<string_detail::string_shim>(L, keyidx);
+ std::string accessorkey = accessor.c_str();
+ auto vit = variables.find(accessorkey);
+ if (vit != variables.cend()) {
+ auto& varwrap = *(vit->second);
+ if (is_index) {
+ return varwrap.index(L);
+ }
+ return varwrap.new_index(L);
+ }
+ auto fit = functions.find(accessorkey);
+ if (fit != functions.cend()) {
+ auto& func = (fit->second);
+ return stack::push(L, func);
+ }
+ // Check table storage first for a method that works
+ luaL_getmetatable(L, sm.metakey);
+ if (type_of(L, -1) != type::lua_nil) {
+ stack::get_field<false, true>(L, accessor.c_str(), lua_gettop(L));
+ if (type_of(L, -1) != type::lua_nil) {
+ // Woo, we found it?
+ lua_remove(L, -2);
+ return 1;
+ }
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+
+ int ret = 0;
+ bool found = false;
+ // Otherwise, we need to do propagating calls through the bases
+ if (is_index) {
+ sm.indexbaseclasspropogation(L, found, ret, accessor);
+ }
+ else {
+ sm.newindexbaseclasspropogation(L, found, ret, accessor);
+ }
+ if (found) {
+ return ret;
+ }
+ if (toplevel) {
+ lua_CFunction indexingfunc = is_index ? stack::get<lua_CFunction>(L, upvalue_index(2)) : stack::get<lua_CFunction>(L, upvalue_index(3));
+ return indexingfunc(L);
+ }
+ return -1;
+ }
+
+ inline int simple_real_index_call(lua_State* L) {
+ return simple_core_indexing_call<true, true>(L);
+ }
+
+ inline int simple_real_new_index_call(lua_State* L) {
+ return simple_core_indexing_call<false, true>(L);
+ }
+
+ inline int simple_index_call(lua_State* L) {
+ return detail::static_trampoline<(&simple_real_index_call)>(L);
+ }
+
+ inline int simple_new_index_call(lua_State* L) {
+ return detail::static_trampoline<(&simple_real_new_index_call)>(L);
+ }
+ }
+
+ struct simple_tag {} const simple{};
+
+ template <typename T>
+ struct simple_usertype_metatable : usertype_detail::registrar {
+ public:
+ usertype_detail::function_map registrations;
+ usertype_detail::variable_map varmap;
+ object callconstructfunc;
+ lua_CFunction indexfunc;
+ lua_CFunction newindexfunc;
+ lua_CFunction indexbase;
+ lua_CFunction newindexbase;
+ usertype_detail::base_walk indexbaseclasspropogation;
+ usertype_detail::base_walk newindexbaseclasspropogation;
+ void* baseclasscheck;
+ void* baseclasscast;
+ bool mustindex;
+ bool secondarymeta;
+
+ template <typename N>
+ void insert(N&& n, object&& o) {
+ std::string key = usertype_detail::make_string(std::forward<N>(n));
+ auto hint = registrations.find(key);
+ if (hint == registrations.cend()) {
+ registrations.emplace_hint(hint, std::move(key), std::move(o));
+ return;
+ }
+ hint->second = std::move(o);
+ }
+
+ template <typename N, typename F, typename... Args>
+ void insert_prepare(std::true_type, lua_State* L, N&&, F&& f, Args&&... args) {
+ object o = make_object<F>(L, std::forward<F>(f), function_detail::call_indicator(), std::forward<Args>(args)...);
+ callconstructfunc = std::move(o);
+ }
+
+ template <typename N, typename F, typename... Args>
+ void insert_prepare(std::false_type, lua_State* L, N&& n, F&& f, Args&&... args) {
+ object o = make_object<F>(L, std::forward<F>(f), std::forward<Args>(args)...);
+ insert(std::forward<N>(n), std::move(o));
+ }
+
+ template <typename N, typename F>
+ void add_member_function(std::true_type, lua_State* L, N&& n, F&& f) {
+ insert_prepare(std::is_same<meta::unqualified_t<N>, call_construction>(), L, std::forward<N>(n), std::forward<F>(f), function_detail::class_indicator<T>());
+ }
+
+ template <typename N, typename F>
+ void add_member_function(std::false_type, lua_State* L, N&& n, F&& f) {
+ insert_prepare(std::is_same<meta::unqualified_t<N>, call_construction>(), L, std::forward<N>(n), std::forward<F>(f));
+ }
+
+ template <typename N, typename F, meta::enable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler>
+ void add_function(lua_State* L, N&& n, F&& f) {
+ object o = make_object(L, as_function_reference(std::forward<F>(f)));
+ if (std::is_same<meta::unqualified_t<N>, call_construction>::value) {
+ callconstructfunc = std::move(o);
+ return;
+ }
+ insert(std::forward<N>(n), std::move(o));
+ }
+
+ template <typename N, typename F, meta::disable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler>
+ void add_function(lua_State* L, N&& n, F&& f) {
+ add_member_function(std::is_member_pointer<meta::unwrap_unqualified_t<F>>(), L, std::forward<N>(n), std::forward<F>(f));
+ }
+
+ template <typename N, typename F, meta::disable<is_variable_binding<meta::unqualified_t<F>>> = meta::enabler>
+ void add(lua_State* L, N&& n, F&& f) {
+ add_function(L, std::forward<N>(n), std::forward<F>(f));
+ }
+
+ template <typename N, typename F, meta::enable<is_variable_binding<meta::unqualified_t<F>>> = meta::enabler>
+ void add(lua_State*, N&& n, F&& f) {
+ mustindex = true;
+ secondarymeta = true;
+ std::string key = usertype_detail::make_string(std::forward<N>(n));
+ auto o = std::make_unique<usertype_detail::callable_binding<T, std::decay_t<F>>>(std::forward<F>(f));
+ auto hint = varmap.find(key);
+ if (hint == varmap.cend()) {
+ varmap.emplace_hint(hint, std::move(key), std::move(o));
+ return;
+ }
+ hint->second = std::move(o);
+ }
+
+ template <typename N, typename... Fxs>
+ void add(lua_State* L, N&& n, constructor_wrapper<Fxs...> c) {
+ object o(L, in_place<detail::tagged<T, constructor_wrapper<Fxs...>>>, std::move(c));
+ if (std::is_same<meta::unqualified_t<N>, call_construction>::value) {
+ callconstructfunc = std::move(o);
+ return;
+ }
+ insert(std::forward<N>(n), std::move(o));
+ }
+
+ template <typename N, typename... Lists>
+ void add(lua_State* L, N&& n, constructor_list<Lists...> c) {
+ object o(L, in_place<detail::tagged<T, constructor_list<Lists...>>>, std::move(c));
+ if (std::is_same<meta::unqualified_t<N>, call_construction>::value) {
+ callconstructfunc = std::move(o);
+ return;
+ }
+ insert(std::forward<N>(n), std::move(o));
+ }
+
+ template <typename N>
+ void add(lua_State* L, N&& n, destructor_wrapper<void> c) {
+ object o(L, in_place<detail::tagged<T, destructor_wrapper<void>>>, std::move(c));
+ if (std::is_same<meta::unqualified_t<N>, call_construction>::value) {
+ callconstructfunc = std::move(o);
+ return;
+ }
+ insert(std::forward<N>(n), std::move(o));
+ }
+
+ template <typename N, typename Fx>
+ void add(lua_State* L, N&& n, destructor_wrapper<Fx> c) {
+ object o(L, in_place<detail::tagged<T, destructor_wrapper<Fx>>>, std::move(c));
+ if (std::is_same<meta::unqualified_t<N>, call_construction>::value) {
+ callconstructfunc = std::move(o);
+ return;
+ }
+ insert(std::forward<N>(n), std::move(o));
+ }
+
+ template <typename... Bases>
+ void add(lua_State*, base_classes_tag, bases<Bases...>) {
+ static_assert(sizeof(usertype_detail::base_walk) <= sizeof(void*), "size of function pointer is greater than sizeof(void*); cannot work on this platform. Please file a bug report.");
+ if (sizeof...(Bases) < 1) {
+ return;
+ }
+ mustindex = true;
+ (void)detail::swallow{ 0, ((detail::has_derived<Bases>::value = true), 0)... };
+
+ static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report.");
+ static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report.");
+ baseclasscheck = (void*)&detail::inheritance<T, Bases...>::type_check;
+ baseclasscast = (void*)&detail::inheritance<T, Bases...>::type_cast;
+ indexbaseclasspropogation = usertype_detail::walk_all_bases<true, Bases...>;
+ newindexbaseclasspropogation = usertype_detail::walk_all_bases<false, Bases...>;
+ }
+
+ private:
+ template<std::size_t... I, typename Tuple>
+ simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
+ : callconstructfunc(lua_nil),
+ indexfunc(&usertype_detail::indexing_fail<true>), newindexfunc(&usertype_detail::metatable_newindex<T, true>),
+ indexbase(&usertype_detail::simple_core_indexing_call<true>), newindexbase(&usertype_detail::simple_core_indexing_call<false>),
+ indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>),
+ baseclasscheck(nullptr), baseclasscast(nullptr),
+ mustindex(false), secondarymeta(false) {
+ (void)detail::swallow{ 0,
+ (add(L, detail::forward_get<I * 2>(args), detail::forward_get<I * 2 + 1>(args)),0)...
+ };
+ }
+
+ template<typename... Args>
+ simple_usertype_metatable(lua_State* L, usertype_detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence<sizeof...(Args) / 2>(), L, std::forward_as_tuple(std::forward<Args>(args)...)) {}
+
+ template<typename... Args>
+ simple_usertype_metatable(lua_State* L, usertype_detail::add_destructor_tag, Args&&... args) : simple_usertype_metatable(L, usertype_detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) {}
+
+ template<typename... Args>
+ simple_usertype_metatable(lua_State* L, usertype_detail::check_destructor_tag, Args&&... args) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_destructible<T>, meta::neg<usertype_detail::has_destructor<Args...>>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward<Args>(args)...) {}
+
+ public:
+ simple_usertype_metatable(lua_State* L) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>>, decltype(default_constructor), usertype_detail::check_destructor_tag>()) {}
+
+ template<typename Arg, typename... Args, meta::disable_any<
+ meta::any_same<meta::unqualified_t<Arg>,
+ usertype_detail::verified_tag,
+ usertype_detail::add_destructor_tag,
+ usertype_detail::check_destructor_tag
+ >,
+ meta::is_specialization_of<constructors, meta::unqualified_t<Arg>>,
+ meta::is_specialization_of<constructor_wrapper, meta::unqualified_t<Arg>>
+ > = meta::enabler>
+ simple_usertype_metatable(lua_State* L, Arg&& arg, Args&&... args) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<usertype_detail::has_constructor<Args...>>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward<Arg>(arg), std::forward<Args>(args)...) {}
+
+ template<typename... Args, typename... CArgs>
+ simple_usertype_metatable(lua_State* L, constructors<CArgs...> constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
+
+ template<typename... Args, typename... Fxs>
+ simple_usertype_metatable(lua_State* L, constructor_wrapper<Fxs...> constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
+
+ simple_usertype_metatable(const simple_usertype_metatable&) = default;
+ simple_usertype_metatable(simple_usertype_metatable&&) = default;
+ simple_usertype_metatable& operator=(const simple_usertype_metatable&) = default;
+ simple_usertype_metatable& operator=(simple_usertype_metatable&&) = default;
+
+ virtual int push_um(lua_State* L) override {
+ return stack::push(L, std::move(*this));
+ }
+ };
+
+ namespace stack {
+ template <typename T>
+ struct pusher<simple_usertype_metatable<T>> {
+ typedef simple_usertype_metatable<T> umt_t;
+
+ static usertype_detail::simple_map& make_cleanup(lua_State* L, umt_t& umx) {
+ static int uniqueness = 0;
+ std::string uniquegcmetakey = usertype_traits<T>::user_gc_metatable();
+ // std::to_string doesn't exist in android still, with NDK, so this bullshit
+ // is necessary
+ // thanks, Android :v
+ int appended = snprintf(nullptr, 0, "%d", uniqueness);
+ std::size_t insertionpoint = uniquegcmetakey.length() - 1;
+ uniquegcmetakey.append(appended, '\0');
+ char* uniquetarget = &uniquegcmetakey[insertionpoint];
+ snprintf(uniquetarget, uniquegcmetakey.length(), "%d", uniqueness);
+ ++uniqueness;
+
+ const char* gcmetakey = &usertype_traits<T>::gc_table()[0];
+ stack::push<user<usertype_detail::simple_map>>(L, metatable_key, uniquegcmetakey, &usertype_traits<T>::metatable()[0],
+ umx.indexbaseclasspropogation, umx.newindexbaseclasspropogation,
+ std::move(umx.varmap), std::move(umx.registrations)
+ );
+ stack_reference stackvarmap(L, -1);
+ stack::set_field<true>(L, gcmetakey, stackvarmap);
+ stackvarmap.pop();
+
+ stack::get_field<true>(L, gcmetakey);
+ usertype_detail::simple_map& varmap = stack::pop<light<usertype_detail::simple_map>>(L);
+ return varmap;
+ }
+
+ static int push(lua_State* L, umt_t&& umx) {
+ auto& varmap = make_cleanup(L, umx);
+ bool hasequals = false;
+ bool hasless = false;
+ bool haslessequals = false;
+ auto register_kvp = [&](std::size_t i, stack_reference& t, const std::string& first, object& second) {
+ if (first == name_of(meta_function::equal_to)) {
+ hasequals = true;
+ }
+ else if (first == name_of(meta_function::less_than)) {
+ hasless = true;
+ }
+ else if (first == name_of(meta_function::less_than_or_equal_to)) {
+ haslessequals = true;
+ }
+ else if (first == name_of(meta_function::index)) {
+ umx.indexfunc = second.template as<lua_CFunction>();
+ }
+ else if (first == name_of(meta_function::new_index)) {
+ umx.newindexfunc = second.template as<lua_CFunction>();
+ }
+ switch (i) {
+ case 0:
+ if (first == name_of(meta_function::garbage_collect)) {
+ return;
+ }
+ break;
+ case 1:
+ if (first == name_of(meta_function::garbage_collect)) {
+ stack::set_field(L, first, detail::unique_destruct<T>, t.stack_index());
+ return;
+ }
+ break;
+ case 2:
+ default:
+ break;
+ }
+ stack::set_field(L, first, second, t.stack_index());
+ };
+ for (std::size_t i = 0; i < 3; ++i) {
+ // Pointer types, AKA "references" from C++
+ const char* metakey = nullptr;
+ switch (i) {
+ case 0:
+ metakey = &usertype_traits<T*>::metatable()[0];
+ break;
+ case 1:
+ metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0];
+ break;
+ case 2:
+ default:
+ metakey = &usertype_traits<T>::metatable()[0];
+ break;
+ }
+ luaL_newmetatable(L, metakey);
+ stack_reference t(L, -1);
+ for (auto& kvp : varmap.functions) {
+ auto& first = std::get<0>(kvp);
+ auto& second = std::get<1>(kvp);
+ register_kvp(i, t, first, second);
+ }
+ luaL_Reg opregs[4]{};
+ int opregsindex = 0;
+ if (!hasless) {
+ const char* name = name_of(meta_function::less_than).c_str();
+ usertype_detail::make_reg_op<T, std::less<>, meta::supports_op_less<T>>(opregs, opregsindex, name);
+ }
+ if (!haslessequals) {
+ const char* name = name_of(meta_function::less_than_or_equal_to).c_str();
+ usertype_detail::make_reg_op<T, std::less_equal<>, meta::supports_op_less_equal<T>>(opregs, opregsindex, name);
+ }
+ if (!hasequals) {
+ const char* name = name_of(meta_function::equal_to).c_str();
+ usertype_detail::make_reg_op<T, std::conditional_t<meta::supports_op_equal<T>::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(opregs, opregsindex, name);
+ }
+ t.push();
+ luaL_setfuncs(L, opregs, 0);
+ t.pop();
+
+ if (umx.baseclasscheck != nullptr) {
+ stack::set_field(L, detail::base_class_check_key(), umx.baseclasscheck, t.stack_index());
+ }
+ if (umx.baseclasscast != nullptr) {
+ stack::set_field(L, detail::base_class_cast_key(), umx.baseclasscast, t.stack_index());
+ }
+
+ // Base class propagation features
+ stack::set_field(L, detail::base_class_index_propogation_key(), umx.indexbase, t.stack_index());
+ stack::set_field(L, detail::base_class_new_index_propogation_key(), umx.newindexbase, t.stack_index());
+
+ if (umx.mustindex) {
+ // use indexing function
+ stack::set_field(L, meta_function::index,
+ make_closure(&usertype_detail::simple_index_call,
+ make_light(varmap),
+ umx.indexfunc,
+ umx.newindexfunc
+ ), t.stack_index());
+ stack::set_field(L, meta_function::new_index,
+ make_closure(&usertype_detail::simple_new_index_call,
+ make_light(varmap),
+ umx.indexfunc,
+ umx.newindexfunc
+ ), t.stack_index());
+ }
+ else {
+ // Metatable indexes itself
+ stack::set_field(L, meta_function::index, t, t.stack_index());
+ }
+ // metatable on the metatable
+ // for call constructor purposes and such
+ lua_createtable(L, 0, 2 * static_cast<int>(umx.secondarymeta) + static_cast<int>(umx.callconstructfunc.valid()));
+ stack_reference metabehind(L, -1);
+ if (umx.callconstructfunc.valid()) {
+ stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index());
+ }
+ if (umx.secondarymeta) {
+ stack::set_field(L, meta_function::index,
+ make_closure(&usertype_detail::simple_index_call,
+ make_light(varmap),
+ umx.indexfunc,
+ umx.newindexfunc
+ ), metabehind.stack_index());
+ stack::set_field(L, meta_function::new_index,
+ make_closure(&usertype_detail::simple_new_index_call,
+ make_light(varmap),
+ umx.indexfunc,
+ umx.newindexfunc
+ ), metabehind.stack_index());
+ }
+ stack::set_field(L, metatable_key, metabehind, t.stack_index());
+ metabehind.pop();
+
+ t.pop();
+ }
+
+ // Now for the shim-table that actually gets pushed
+ luaL_newmetatable(L, &usertype_traits<T>::user_metatable()[0]);
+ stack_reference t(L, -1);
+ for (auto& kvp : varmap.functions) {
+ auto& first = std::get<0>(kvp);
+ auto& second = std::get<1>(kvp);
+ register_kvp(2, t, first, second);
+ }
+ {
+ lua_createtable(L, 0, 2 + static_cast<int>(umx.callconstructfunc.valid()));
+ stack_reference metabehind(L, -1);
+ if (umx.callconstructfunc.valid()) {
+ stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index());
+ }
+ // use indexing function
+ stack::set_field(L, meta_function::index,
+ make_closure(&usertype_detail::simple_index_call,
+ make_light(varmap),
+ umx.indexfunc,
+ umx.newindexfunc,
+ usertype_detail::toplevel_magic
+ ), metabehind.stack_index());
+ stack::set_field(L, meta_function::new_index,
+ make_closure(&usertype_detail::simple_new_index_call,
+ make_light(varmap),
+ umx.indexfunc,
+ umx.newindexfunc,
+ usertype_detail::toplevel_magic
+ ), metabehind.stack_index());
+ stack::set_field(L, metatable_key, metabehind, t.stack_index());
+ metabehind.pop();
+ }
+
+ // Don't pop the table when we're done;
+ // return it
+ return 1;
+ }
+ };
+ } // stack
+} // sol
+
+// end of sol/simple_usertype_metatable.hpp
+
+// beginning of sol/container_usertype_metatable.hpp
+
+namespace sol {
+
+ namespace detail {
+
+ template <typename T>
+ struct has_find {
+ private:
+ typedef std::array<char, 1> one;
+ typedef std::array<char, 2> two;
+
+ template <typename C> static one test(decltype(&C::find));
+ template <typename C> static two test(...);
+
+ public:
+ static const bool value = sizeof(test<T>(0)) == sizeof(char);
+ };
+
+ template <typename T>
+ struct has_push_back {
+ private:
+ typedef std::array<char, 1> one;
+ typedef std::array<char, 2> two;
+
+ template <typename C> static one test(decltype(std::declval<C>().push_back(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
+ template <typename C> static two test(...);
+
+ public:
+ static const bool value = sizeof(test<T>(0)) == sizeof(char);
+ };
+
+ template <typename T>
+ struct has_clear {
+ private:
+ typedef std::array<char, 1> one;
+ typedef std::array<char, 2> two;
+
+ template <typename C> static one test(decltype(&C::clear));
+ template <typename C> static two test(...);
+
+ public:
+ static const bool value = sizeof(test<T>(0)) == sizeof(char);
+ };
+
+ template <typename T>
+ struct has_insert {
+ private:
+ typedef std::array<char, 1> one;
+ typedef std::array<char, 2> two;
+
+ template <typename C> static one test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
+ template <typename C> static two test(...);
+
+ public:
+ static const bool value = sizeof(test<T>(0)) == sizeof(char);
+ };
+
+ template <typename T>
+ T& get_first(const T& t) {
+ return std::forward<T>(t);
+ }
+
+ template <typename A, typename B>
+ decltype(auto) get_first(const std::pair<A, B>& t) {
+ return t.first;
+ }
+
+ template <typename C, typename I, meta::enable<has_find<meta::unqualified_t<C>>> = meta::enabler>
+ auto find(C& c, I&& i) {
+ return c.find(std::forward<I>(i));
+ }
+
+ template <typename C, typename I, meta::disable<has_find<meta::unqualified_t<C>>> = meta::enabler>
+ auto find(C& c, I&& i) {
+ using std::begin;
+ using std::end;
+ return std::find_if(begin(c), end(c), [&i](auto&& x) {
+ return i == get_first(x);
+ });
+ }
+
+ }
+
+ template <typename Raw, typename C = void>
+ struct container_usertype_metatable {
+ typedef meta::has_key_value_pair<meta::unqualified_t<Raw>> is_associative;
+ typedef meta::unqualified_t<Raw> T;
+ typedef typename T::iterator I;
+ typedef std::conditional_t<is_associative::value, typename T::value_type, std::pair<std::size_t, typename T::value_type>> KV;
+ typedef typename KV::first_type K;
+ typedef typename KV::second_type V;
+ typedef std::remove_reference_t<decltype(*std::declval<I&>())> IR;
+
+ struct iter {
+ T& source;
+ I it;
+
+ iter(T& source, I it) : source(source), it(std::move(it)) {}
+ };
+
+ static auto& get_src(lua_State* L) {
+#ifdef SOL_SAFE_USERTYPE
+ auto p = stack::check_get<T*>(L, 1);
+ if (!p || p.value() == nullptr) {
+ luaL_error(L, "sol: 'self' argument is not the proper type (pass 'self' as first argument with ':' or call on proper type)");
+ }
+ return *p.value();
+#else
+ return stack::get<T>(L, 1);
+#endif // Safe getting with error
+ }
+
+ static int real_index_call_associative(std::true_type, lua_State* L) {
+ auto k = stack::check_get<K>(L, 2);
+ if (k) {
+ auto& src = get_src(L);
+ using std::end;
+ auto it = detail::find(src, *k);
+ if (it != end(src)) {
+ auto& v = *it;
+ return stack::push_reference(L, v.second);
+ }
+ }
+ else {
+ auto maybename = stack::check_get<string_detail::string_shim>(L, 2);
+ if (maybename) {
+ auto& name = *maybename;
+ if (name == "add") {
+ return stack::push(L, &add_call);
+ }
+ else if (name == "insert") {
+ return stack::push(L, &insert_call);
+ }
+ else if (name == "clear") {
+ return stack::push(L, &clear_call);
+ }
+ }
+ }
+ return stack::push(L, lua_nil);
+ }
+
+ static int real_index_call_associative(std::false_type, lua_State* L) {
+ auto& src = get_src(L);
+ auto maybek = stack::check_get<K>(L, 2);
+ if (maybek) {
+ using std::begin;
+ auto it = begin(src);
+ K k = *maybek;
+ if (k > src.size() || k < 1) {
+ return stack::push(L, lua_nil);
+ }
+ --k;
+ std::advance(it, k);
+ return stack::push_reference(L, *it);
+ }
+ else {
+ auto maybename = stack::check_get<string_detail::string_shim>(L, 2);
+ if (maybename) {
+ auto& name = *maybename;
+ if (name == "add") {
+ return stack::push(L, &add_call);
+ }
+ else if (name == "insert") {
+ return stack::push(L, &insert_call);
+ }
+ else if (name == "clear") {
+ return stack::push(L, &clear_call);
+ }
+ }
+ }
+
+ return stack::push(L, lua_nil);
+ }
+
+ static int real_index_call(lua_State* L) {
+ return real_index_call_associative(is_associative(), L);
+ }
+
+ static int real_new_index_call_const(std::false_type, std::false_type, lua_State* L) {
+ return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)");
+ }
+
+ static int real_new_index_call_const(std::false_type, std::true_type, lua_State* L) {
+ return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)");
+ }
+
+ static int real_new_index_call_const(std::true_type, std::true_type, lua_State* L) {
+ auto& src = get_src(L);
+ auto k = stack::check_get<K>(L, 2);
+ if (k) {
+ using std::end;
+ auto it = detail::find(src, *k);
+ if (it != end(src)) {
+ auto& v = *it;
+ v.second = stack::get<V>(L, 3);
+ }
+ else {
+ src.insert(it, { std::move(*k), stack::get<V>(L, 3) });
+ }
+ }
+ return 0;
+ }
+
+ static int real_new_index_call_const(std::true_type, std::false_type, lua_State* L) {
+ auto& src = get_src(L);
+#ifdef SOL_SAFE_USERTYPE
+ auto maybek = stack::check_get<K>(L, 2);
+ if (!maybek) {
+ return 0;
+ }
+ K k = *maybek;
+#else
+ K k = stack::get<K>(L, 2);
+#endif
+ using std::begin;
+ auto it = begin(src);
+ if (k == src.size()) {
+ real_add_call_push(std::integral_constant<bool, detail::has_push_back<T>::value>(), L, src, 1);
+ return 0;
+ }
+ --k;
+ std::advance(it, k);
+ *it = stack::get<V>(L, 3);
+ return 0;
+ }
+
+ static int real_new_index_call(lua_State* L) {
+ return real_new_index_call_const(meta::neg<meta::any<std::is_const<V>, std::is_const<IR>>>(), is_associative(), L);
+ }
+
+ static int real_pairs_next_call_assoc(std::true_type, lua_State* L) {
+ using std::end;
+ iter& i = stack::get<user<iter>>(L, 1);
+ auto& source = i.source;
+ auto& it = i.it;
+ if (it == end(source)) {
+ return 0;
+ }
+ int p = stack::multi_push_reference(L, it->first, it->second);
+ std::advance(it, 1);
+ return p;
+ }
+
+ static int real_pairs_call_assoc(std::true_type, lua_State* L) {
+ auto& src = get_src(L);
+ using std::begin;
+ stack::push(L, pairs_next_call);
+ stack::push<user<iter>>(L, src, begin(src));
+ stack::push(L, 1);
+ return 3;
+ }
+
+ static int real_pairs_next_call_assoc(std::false_type, lua_State* L) {
+ using std::end;
+ iter& i = stack::get<user<iter>>(L, 1);
+ auto& source = i.source;
+ auto& it = i.it;
+ K k = stack::get<K>(L, 2);
+ if (it == end(source)) {
+ return 0;
+ }
+ int p = stack::multi_push_reference(L, k + 1, *it);
+ std::advance(it, 1);
+ return p;
+ }
+
+ static int real_pairs_call_assoc(std::false_type, lua_State* L) {
+ auto& src = get_src(L);
+ using std::begin;
+ stack::push(L, pairs_next_call);
+ stack::push<user<iter>>(L, src, begin(src));
+ stack::push(L, 0);
+ return 3;
+ }
+
+ static int real_pairs_next_call(lua_State* L) {
+ return real_pairs_next_call_assoc(is_associative(), L);
+ }
+
+ static int real_pairs_call(lua_State* L) {
+ return real_pairs_call_assoc(is_associative(), L);
+ }
+
+ static int real_length_call(lua_State*L) {
+ auto& src = get_src(L);
+ return stack::push(L, src.size());
+ }
+
+ static int real_add_call_insert(std::true_type, lua_State*L, T& src, int boost = 0) {
+ using std::end;
+ src.insert(end(src), stack::get<V>(L, 2 + boost));
+ return 0;
+ }
+
+ static int real_add_call_insert(std::false_type, lua_State*L, T&, int = 0) {
+ static const std::string& s = detail::demangle<T>();
+ return luaL_error(L, "sol: cannot call insert on type %s", s.c_str());
+ }
+
+ static int real_add_call_push(std::true_type, lua_State*L, T& src, int boost = 0) {
+ src.push_back(stack::get<V>(L, 2 + boost));
+ return 0;
+ }
+
+ static int real_add_call_push(std::false_type, lua_State*L, T& src, int boost = 0) {
+ return real_add_call_insert(std::integral_constant<bool, detail::has_insert<T>::value>(), L, src, boost);
+ }
+
+ static int real_add_call_associative(std::true_type, lua_State* L) {
+ return real_insert_call(L);
+ }
+
+ static int real_add_call_associative(std::false_type, lua_State* L) {
+ auto& src = get_src(L);
+ return real_add_call_push(std::integral_constant<bool, detail::has_push_back<T>::value>(), L, src);
+ }
+
+ static int real_add_call_capable(std::true_type, lua_State* L) {
+ return real_add_call_associative(is_associative(), L);
+ }
+
+ static int real_add_call_capable(std::false_type, lua_State* L) {
+ static const std::string& s = detail::demangle<T>();
+ return luaL_error(L, "sol: cannot call add on type %s", s.c_str());
+ }
+
+ static int real_add_call(lua_State* L) {
+ return real_add_call_capable(std::integral_constant<bool, detail::has_push_back<T>::value || detail::has_insert<T>::value>(), L);
+ }
+
+ static int real_insert_call_capable(std::false_type, std::false_type, lua_State*L) {
+ static const std::string& s = detail::demangle<T>();
+ return luaL_error(L, "sol: cannot call insert on type %s", s.c_str());
+ }
+
+ static int real_insert_call_capable(std::false_type, std::true_type, lua_State*L) {
+ return real_insert_call_capable(std::false_type(), std::false_type(), L);
+ }
+
+ static int real_insert_call_capable(std::true_type, std::false_type, lua_State* L) {
+ using std::begin;
+ auto& src = get_src(L);
+ src.insert(std::next(begin(src), stack::get<K>(L, 2)), stack::get<V>(L, 3));
+ return 0;
+ }
+
+ static int real_insert_call_capable(std::true_type, std::true_type, lua_State* L) {
+ return real_new_index_call(L);
+ }
+
+ static int real_insert_call(lua_State*L) {
+ return real_insert_call_capable(std::integral_constant<bool, detail::has_insert<T>::value>(), is_associative(), L);
+ }
+
+ static int real_clear_call_capable(std::false_type, lua_State* L) {
+ static const std::string& s = detail::demangle<T>();
+ return luaL_error(L, "sol: cannot call clear on type %s", s.c_str());
+ }
+
+ static int real_clear_call_capable(std::true_type, lua_State* L) {
+ auto& src = get_src(L);
+ src.clear();
+ return 0;
+ }
+
+ static int real_clear_call(lua_State*L) {
+ return real_clear_call_capable(std::integral_constant<bool, detail::has_clear<T>::value>(), L);
+ }
+
+ static int add_call(lua_State*L) {
+ return detail::static_trampoline<(&real_add_call)>(L);
+ }
+
+ static int insert_call(lua_State*L) {
+ return detail::static_trampoline<(&real_insert_call)>(L);
+ }
+
+ static int clear_call(lua_State*L) {
+ return detail::static_trampoline<(&real_clear_call)>(L);
+ }
+
+ static int length_call(lua_State*L) {
+ return detail::static_trampoline<(&real_length_call)>(L);
+ }
+
+ static int pairs_next_call(lua_State*L) {
+ return detail::static_trampoline<(&real_pairs_next_call)>(L);
+ }
+
+ static int pairs_call(lua_State*L) {
+ return detail::static_trampoline<(&real_pairs_call)>(L);
+ }
+
+ static int index_call(lua_State*L) {
+ return detail::static_trampoline<(&real_index_call)>(L);
+ }
+
+ static int new_index_call(lua_State*L) {
+ return detail::static_trampoline<(&real_new_index_call)>(L);
+ }
+ };
+
+ namespace stack {
+ namespace stack_detail {
+ template <typename T>
+ inline auto container_metatable() {
+ typedef container_usertype_metatable<std::remove_pointer_t<T>> meta_cumt;
+ std::array<luaL_Reg, 10> reg = { {
+ { "__index", &meta_cumt::index_call },
+ { "__newindex", &meta_cumt::new_index_call },
+ { "__pairs", &meta_cumt::pairs_call },
+ { "__ipairs", &meta_cumt::pairs_call },
+ { "__len", &meta_cumt::length_call },
+ { "clear", &meta_cumt::clear_call },
+ { "insert", &meta_cumt::insert_call },
+ { "add", &meta_cumt::add_call },
+ std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy<T> },
+ { nullptr, nullptr }
+ } };
+ return reg;
+ }
+
+ template <typename T>
+ inline auto container_metatable_behind() {
+ typedef container_usertype_metatable<std::remove_pointer_t<T>> meta_cumt;
+ std::array<luaL_Reg, 3> reg = { {
+ { "__index", &meta_cumt::index_call },
+ { "__newindex", &meta_cumt::new_index_call },
+ { nullptr, nullptr }
+ } };
+ return reg;
+ }
+
+ template <typename T>
+ struct metatable_setup {
+ lua_State* L;
+
+ metatable_setup(lua_State* L) : L(L) {}
+
+ void operator()() {
+ static const auto reg = container_metatable<T>();
+ static const auto containerreg = container_metatable_behind<T>();
+ static const char* metakey = &usertype_traits<T>::metatable()[0];
+
+ if (luaL_newmetatable(L, metakey) == 1) {
+ stack_reference metatable(L, -1);
+ luaL_setfuncs(L, reg.data(), 0);
+
+ lua_createtable(L, 0, static_cast<int>(containerreg.size()));
+ stack_reference metabehind(L, -1);
+ luaL_setfuncs(L, containerreg.data(), 0);
+
+ stack::set_field(L, metatable_key, metabehind, metatable.stack_index());
+ metabehind.pop();
+ }
+ lua_setmetatable(L, -2);
+ }
+ };
+ }
+
+ template<typename T>
+ struct pusher<T, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<meta::any<std::is_base_of<reference, meta::unqualified_t<T>>, std::is_base_of<stack_reference, meta::unqualified_t<T>>>>>::value>> {
+ static int push(lua_State* L, const T& cont) {
+ stack_detail::metatable_setup<T> fx(L);
+ return pusher<detail::as_value_tag<T>>{}.push_fx(L, fx, cont);
+ }
+
+ static int push(lua_State* L, T&& cont) {
+ stack_detail::metatable_setup<T> fx(L);
+ return pusher<detail::as_value_tag<T>>{}.push_fx(L, fx, std::move(cont));
+ }
+ };
+
+ template<typename T>
+ struct pusher<T*, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<meta::any<std::is_base_of<reference, meta::unqualified_t<T>>, std::is_base_of<stack_reference, meta::unqualified_t<T>>>>>::value>> {
+ static int push(lua_State* L, T* cont) {
+ stack_detail::metatable_setup<meta::unqualified_t<std::remove_pointer_t<T>>*> fx(L);
+ return pusher<detail::as_pointer_tag<T>>{}.push_fx(L, fx, cont);
+ }
+ };
+ } // stack
+
+} // sol
+
+// end of sol/container_usertype_metatable.hpp
+
+namespace sol {
+
+ template<typename T>
+ class usertype {
+ private:
+ std::unique_ptr<usertype_detail::registrar, detail::deleter> metatableregister;
+
+ template<typename... Args>
+ usertype(usertype_detail::verified_tag, Args&&... args) : metatableregister(detail::make_unique_deleter<usertype_metatable<T, std::make_index_sequence<sizeof...(Args) / 2>, Args...>, detail::deleter>(std::forward<Args>(args)...)) {}
+
+ template<typename... Args>
+ usertype(usertype_detail::add_destructor_tag, Args&&... args) : usertype(usertype_detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) {}
+
+ template<typename... Args>
+ usertype(usertype_detail::check_destructor_tag, Args&&... args) : usertype(meta::condition<meta::all<std::is_destructible<T>, meta::neg<usertype_detail::has_destructor<Args...>>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward<Args>(args)...) {}
+
+ public:
+
+ template<typename... Args>
+ usertype(Args&&... args) : usertype(meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<usertype_detail::has_constructor<Args...>>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward<Args>(args)...) {}
+
+ template<typename... Args, typename... CArgs>
+ usertype(constructors<CArgs...> constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
+
+ template<typename... Args, typename... Fxs>
+ usertype(constructor_wrapper<Fxs...> constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
+
+ template<typename... Args>
+ usertype(simple_tag, lua_State* L, Args&&... args) : metatableregister(detail::make_unique_deleter<simple_usertype_metatable<T>, detail::deleter>(L, std::forward<Args>(args)...)) {}
+
+ usertype_detail::registrar* registrar_data() {
+ return metatableregister.get();
+ }
+
+ int push(lua_State* L) {
+ int r = metatableregister->push_um(L);
+ metatableregister = nullptr;
+ return r;
+ }
+ };
+
+ template<typename T>
+ class simple_usertype : public usertype<T> {
+ private:
+ typedef usertype<T> base_t;
+ lua_State* state;
+
+ public:
+ template<typename... Args>
+ simple_usertype(lua_State* L, Args&&... args) : base_t(simple, L, std::forward<Args>(args)...), state(L) {}
+
+ template <typename N, typename F>
+ void set(N&& n, F&& f) {
+ auto meta = static_cast<simple_usertype_metatable<T>*>(base_t::registrar_data());
+ meta->add(state, n, f);
+ }
+ };
+
+ namespace stack {
+ template<typename T>
+ struct pusher<usertype<T>> {
+ static int push(lua_State* L, usertype<T>& user) {
+ return user.push(L);
+ }
+ };
+ } // stack
+} // sol
+
+// end of sol/usertype.hpp
+
+// beginning of sol/table_iterator.hpp
+
+namespace sol {
+
+ template <typename reference_type>
+ class basic_table_iterator : public std::iterator<std::input_iterator_tag, std::pair<object, object>> {
+ private:
+ typedef std::iterator<std::input_iterator_tag, std::pair<object, object>> base_t;
+ public:
+ typedef object key_type;
+ typedef object mapped_type;
+ typedef base_t::value_type value_type;
+ typedef base_t::iterator_category iterator_category;
+ typedef base_t::difference_type difference_type;
+ typedef base_t::pointer pointer;
+ typedef base_t::reference reference;
+ typedef const value_type& const_reference;
+
+ private:
+ std::pair<object, object> kvp;
+ reference_type ref;
+ int tableidx = 0;
+ int keyidx = 0;
+ std::ptrdiff_t idx = 0;
+
+ public:
+
+ basic_table_iterator() : keyidx(-1), idx(-1) {
+
+ }
+
+ basic_table_iterator(reference_type x) : ref(std::move(x)) {
+ ref.push();
+ tableidx = lua_gettop(ref.lua_state());
+ stack::push(ref.lua_state(), lua_nil);
+ this->operator++();
+ if (idx == -1) {
+ return;
+ }
+ --idx;
+ }
+
+ basic_table_iterator& operator++() {
+ if (idx == -1)
+ return *this;
+
+ if (lua_next(ref.lua_state(), tableidx) == 0) {
+ idx = -1;
+ keyidx = -1;
+ return *this;
+ }
+ ++idx;
+ kvp.first = object(ref.lua_state(), -2);
+ kvp.second = object(ref.lua_state(), -1);
+ lua_pop(ref.lua_state(), 1);
+ // leave key on the stack
+ keyidx = lua_gettop(ref.lua_state());
+ return *this;
+ }
+
+ basic_table_iterator operator++(int) {
+ auto saved = *this;
+ this->operator++();
+ return saved;
+ }
+
+ reference operator*() {
+ return kvp;
+ }
+
+ const_reference operator*() const {
+ return kvp;
+ }
+
+ bool operator== (const basic_table_iterator& right) const {
+ return idx == right.idx;
+ }
+
+ bool operator!= (const basic_table_iterator& right) const {
+ return idx != right.idx;
+ }
+
+ ~basic_table_iterator() {
+ if (keyidx != -1) {
+ stack::remove(ref.lua_state(), keyidx, 1);
+ }
+ if (ref.valid()) {
+ stack::remove(ref.lua_state(), tableidx, 1);
+ }
+ }
+ };
+
+} // sol
+
+// end of sol/table_iterator.hpp
+
+namespace sol {
+ namespace detail {
+ template <std::size_t n>
+ struct clean { lua_State* L; clean(lua_State* luastate) : L(luastate) {} ~clean() { lua_pop(L, static_cast<int>(n)); } };
+ struct ref_clean { lua_State* L; int& n; ref_clean(lua_State* luastate, int& n) : L(luastate), n(n) {} ~ref_clean() { lua_pop(L, static_cast<int>(n)); } };
+ inline int fail_on_newindex(lua_State* L) {
+ return luaL_error(L, "sol: cannot modify the elements of an enumeration table");
+ }
+ }
+
+ template <bool top_level, typename base_t>
+ class basic_table_core : public base_t {
+ friend class state;
+ friend class state_view;
+
+ template <typename... Args>
+ using is_global = meta::all<meta::boolean<top_level>, meta::is_c_str<Args>...>;
+
+ template<typename Fx>
+ void for_each(std::true_type, Fx&& fx) const {
+ auto pp = stack::push_pop(*this);
+ stack::push(base_t::lua_state(), lua_nil);
+ while (lua_next(base_t::lua_state(), -2)) {
+ sol::object key(base_t::lua_state(), -2);
+ sol::object value(base_t::lua_state(), -1);
+ std::pair<sol::object&, sol::object&> keyvalue(key, value);
+ auto pn = stack::pop_n(base_t::lua_state(), 1);
+ fx(keyvalue);
+ }
+ }
+
+ template<typename Fx>
+ void for_each(std::false_type, Fx&& fx) const {
+ auto pp = stack::push_pop(*this);
+ stack::push(base_t::lua_state(), lua_nil);
+ while (lua_next(base_t::lua_state(), -2)) {
+ sol::object key(base_t::lua_state(), -2);
+ sol::object value(base_t::lua_state(), -1);
+ auto pn = stack::pop_n(base_t::lua_state(), 1);
+ fx(key, value);
+ }
+ }
+
+ template<typename Ret0, typename Ret1, typename... Ret, std::size_t... I, typename Keys>
+ auto tuple_get(types<Ret0, Ret1, Ret...>, std::index_sequence<0, 1, I...>, Keys&& keys) const
+ -> decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)) {
+ typedef decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)) Tup;
+ return Tup(
+ traverse_get_optional<top_level, Ret0>(meta::is_specialization_of<sol::optional, meta::unqualified_t<Ret0>>(), detail::forward_get<0>(keys)),
+ traverse_get_optional<top_level, Ret1>(meta::is_specialization_of<sol::optional, meta::unqualified_t<Ret1>>(), detail::forward_get<1>(keys)),
+ traverse_get_optional<top_level, Ret>(meta::is_specialization_of<sol::optional, meta::unqualified_t<Ret>>(), detail::forward_get<I>(keys))...
+ );
+ }
+
+ template<typename Ret, std::size_t I, typename Keys>
+ decltype(auto) tuple_get(types<Ret>, std::index_sequence<I>, Keys&& keys) const {
+ return traverse_get_optional<top_level, Ret>(meta::is_specialization_of<sol::optional, meta::unqualified_t<Ret>>(), detail::forward_get<I>(keys));
+ }
+
+ template<typename Pairs, std::size_t... I>
+ void tuple_set(std::index_sequence<I...>, Pairs&& pairs) {
+ auto pp = stack::push_pop<top_level && (is_global<decltype(detail::forward_get<I * 2>(pairs))...>::value)>(*this);
+ void(detail::swallow{ (stack::set_field<top_level>(base_t::lua_state(),
+ detail::forward_get<I * 2>(pairs),
+ detail::forward_get<I * 2 + 1>(pairs),
+ lua_gettop(base_t::lua_state())
+ ), 0)... });
+ }
+
+ template <bool global, typename T, typename Key>
+ decltype(auto) traverse_get_deep(Key&& key) const {
+ stack::get_field<global>(base_t::lua_state(), std::forward<Key>(key));
+ return stack::get<T>(base_t::lua_state());
+ }
+
+ template <bool global, typename T, typename Key, typename... Keys>
+ decltype(auto) traverse_get_deep(Key&& key, Keys&&... keys) const {
+ stack::get_field<global>(base_t::lua_state(), std::forward<Key>(key));
+ return traverse_get_deep<false, T>(std::forward<Keys>(keys)...);
+ }
+
+ template <bool global, typename T, std::size_t I, typename Key>
+ decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key) const {
+ typedef decltype(stack::get<T>(base_t::lua_state())) R;
+ auto p = stack::probe_get_field<global>(base_t::lua_state(), std::forward<Key>(key), lua_gettop(base_t::lua_state()));
+ popcount += p.levels;
+ if (!p.success)
+ return R(nullopt);
+ return stack::get<T>(base_t::lua_state());
+ }
+
+ template <bool global, typename T, std::size_t I, typename Key, typename... Keys>
+ decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key, Keys&&... keys) const {
+ auto p = I > 0 ? stack::probe_get_field<global>(base_t::lua_state(), std::forward<Key>(key), -1) : stack::probe_get_field<global>(base_t::lua_state(), std::forward<Key>(key), lua_gettop(base_t::lua_state()));
+ popcount += p.levels;
+ if (!p.success)
+ return T(nullopt);
+ return traverse_get_deep_optional<false, T, I + 1>(popcount, std::forward<Keys>(keys)...);
+ }
+
+ template <bool global, typename T, typename... Keys>
+ decltype(auto) traverse_get_optional(std::false_type, Keys&&... keys) const {
+ detail::clean<sizeof...(Keys)> c(base_t::lua_state());
+ return traverse_get_deep<top_level, T>(std::forward<Keys>(keys)...);
+ }
+
+ template <bool global, typename T, typename... Keys>
+ decltype(auto) traverse_get_optional(std::true_type, Keys&&... keys) const {
+ int popcount = 0;
+ detail::ref_clean c(base_t::lua_state(), popcount);
+ return traverse_get_deep_optional<top_level, T, 0>(popcount, std::forward<Keys>(keys)...);
+ }
+
+ template <bool global, typename Key, typename Value>
+ void traverse_set_deep(Key&& key, Value&& value) const {
+ stack::set_field<global>(base_t::lua_state(), std::forward<Key>(key), std::forward<Value>(value));
+ }
+
+ template <bool global, typename Key, typename... Keys>
+ void traverse_set_deep(Key&& key, Keys&&... keys) const {
+ stack::get_field<global>(base_t::lua_state(), std::forward<Key>(key));
+ traverse_set_deep<false>(std::forward<Keys>(keys)...);
+ }
+
+ basic_table_core(lua_State* L, detail::global_tag t) noexcept : reference(L, t) { }
+
+ public:
+ typedef basic_table_iterator<base_t> iterator;
+ typedef iterator const_iterator;
+
+ basic_table_core() noexcept : base_t() { }
+ template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_t, meta::unqualified_t<T>>> = meta::enabler>
+ basic_table_core(T&& r) noexcept : base_t(std::forward<T>(r)) {
+#ifdef SOL_CHECK_ARGUMENTS
+ if (!is_table<meta::unqualified_t<T>>::value) {
+ auto pp = stack::push_pop(*this);
+ stack::check<basic_table_core>(base_t::lua_state(), -1, type_panic);
+ }
+#endif // Safety
+ }
+ basic_table_core(const basic_table_core&) = default;
+ basic_table_core(basic_table_core&&) = default;
+ basic_table_core& operator=(const basic_table_core&) = default;
+ basic_table_core& operator=(basic_table_core&&) = default;
+ basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
+ basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
+ template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler>
+ basic_table_core(lua_State* L, T&& r) : basic_table_core(L, sol::ref_index(r.registry_index())) {}
+ basic_table_core(lua_State* L, int index = -1) : base_t(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ stack::check<basic_table_core>(L, index, type_panic);
+#endif // Safety
+ }
+ basic_table_core(lua_State* L, ref_index index) : base_t(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ auto pp = stack::push_pop(*this);
+ stack::check<basic_table_core>(L, -1, type_panic);
+#endif // Safety
+ }
+
+ iterator begin() const {
+ return iterator(*this);
+ }
+
+ iterator end() const {
+ return iterator();
+ }
+
+ const_iterator cbegin() const {
+ return begin();
+ }
+
+ const_iterator cend() const {
+ return end();
+ }
+
+ template<typename... Ret, typename... Keys>
+ decltype(auto) get(Keys&&... keys) const {
+ static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match");
+ auto pp = stack::push_pop<is_global<Keys...>::value>(*this);
+ return tuple_get(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), std::forward_as_tuple(std::forward<Keys>(keys)...));
+ }
+
+ template<typename T, typename Key>
+ decltype(auto) get_or(Key&& key, T&& otherwise) const {
+ typedef decltype(get<T>("")) U;
+ sol::optional<U> option = get<sol::optional<U>>(std::forward<Key>(key));
+ if (option) {
+ return static_cast<U>(option.value());
+ }
+ return static_cast<U>(std::forward<T>(otherwise));
+ }
+
+ template<typename T, typename Key, typename D>
+ decltype(auto) get_or(Key&& key, D&& otherwise) const {
+ sol::optional<T> option = get<sol::optional<T>>(std::forward<Key>(key));
+ if (option) {
+ return static_cast<T>(option.value());
+ }
+ return static_cast<T>(std::forward<D>(otherwise));
+ }
+
+ template <typename T, typename... Keys>
+ decltype(auto) traverse_get(Keys&&... keys) const {
+ auto pp = stack::push_pop<is_global<Keys...>::value>(*this);
+ return traverse_get_optional<top_level, T>(meta::is_specialization_of<sol::optional, meta::unqualified_t<T>>(), std::forward<Keys>(keys)...);
+ }
+
+ template <typename... Keys>
+ basic_table_core& traverse_set(Keys&&... keys) {
+ auto pp = stack::push_pop<is_global<Keys...>::value>(*this);
+ auto pn = stack::pop_n(base_t::lua_state(), static_cast<int>(sizeof...(Keys)-2));
+ traverse_set_deep<top_level>(std::forward<Keys>(keys)...);
+ return *this;
+ }
+
+ template<typename... Args>
+ basic_table_core& set(Args&&... args) {
+ tuple_set(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...));
+ return *this;
+ }
+
+ template<typename T>
+ basic_table_core& set_usertype(usertype<T>& user) {
+ return set_usertype(usertype_traits<T>::name(), user);
+ }
+
+ template<typename Key, typename T>
+ basic_table_core& set_usertype(Key&& key, usertype<T>& user) {
+ return set(std::forward<Key>(key), user);
+ }
+
+ template<typename Class, typename... Args>
+ basic_table_core& new_usertype(const std::string& name, Args&&... args) {
+ usertype<Class> utype(std::forward<Args>(args)...);
+ set_usertype(name, utype);
+ return *this;
+ }
+
+ template<typename Class, typename CTor0, typename... CTor, typename... Args>
+ basic_table_core& new_usertype(const std::string& name, Args&&... args) {
+ constructors<types<CTor0, CTor...>> ctor{};
+ return new_usertype<Class>(name, ctor, std::forward<Args>(args)...);
+ }
+
+ template<typename Class, typename... CArgs, typename... Args>
+ basic_table_core& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
+ usertype<Class> utype(ctor, std::forward<Args>(args)...);
+ set_usertype(name, utype);
+ return *this;
+ }
+
+ template<typename Class, typename... Args>
+ basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) {
+ simple_usertype<Class> utype(base_t::lua_state(), std::forward<Args>(args)...);
+ set_usertype(name, utype);
+ return *this;
+ }
+
+ template<typename Class, typename CTor0, typename... CTor, typename... Args>
+ basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) {
+ constructors<types<CTor0, CTor...>> ctor{};
+ return new_simple_usertype<Class>(name, ctor, std::forward<Args>(args)...);
+ }
+
+ template<typename Class, typename... CArgs, typename... Args>
+ basic_table_core& new_simple_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
+ simple_usertype<Class> utype(base_t::lua_state(), ctor, std::forward<Args>(args)...);
+ set_usertype(name, utype);
+ return *this;
+ }
+
+ template<typename Class, typename... Args>
+ simple_usertype<Class> create_simple_usertype(Args&&... args) {
+ simple_usertype<Class> utype(base_t::lua_state(), std::forward<Args>(args)...);
+ return utype;
+ }
+
+ template<typename Class, typename CTor0, typename... CTor, typename... Args>
+ simple_usertype<Class> create_simple_usertype(Args&&... args) {
+ constructors<types<CTor0, CTor...>> ctor{};
+ return create_simple_usertype<Class>(ctor, std::forward<Args>(args)...);
+ }
+
+ template<typename Class, typename... CArgs, typename... Args>
+ simple_usertype<Class> create_simple_usertype(constructors<CArgs...> ctor, Args&&... args) {
+ simple_usertype<Class> utype(base_t::lua_state(), ctor, std::forward<Args>(args)...);
+ return utype;
+ }
+
+ template<bool read_only = true, typename... Args>
+ basic_table_core& new_enum(const std::string& name, Args&&... args) {
+ if (read_only) {
+ table idx = create_with(std::forward<Args>(args)...);
+ table x = create_with(
+ meta_function::new_index, detail::fail_on_newindex,
+ meta_function::index, idx
+ );
+ table target = create_named(name);
+ target[metatable_key] = x;
+ }
+ else {
+ create_named(name, std::forward<Args>(args)...);
+ }
+ return *this;
+ }
+
+ template<typename Fx>
+ void for_each(Fx&& fx) const {
+ typedef meta::is_invokable<Fx(std::pair<sol::object, sol::object>)> is_paired;
+ for_each(is_paired(), std::forward<Fx>(fx));
+ }
+
+ size_t size() const {
+ auto pp = stack::push_pop(*this);
+ lua_len(base_t::lua_state(), -1);
+ return stack::pop<size_t>(base_t::lua_state());
+ }
+
+ bool empty() const {
+ return cbegin() == cend();
+ }
+
+ template<typename T>
+ proxy<basic_table_core&, T> operator[](T&& key) & {
+ return proxy<basic_table_core&, T>(*this, std::forward<T>(key));
+ }
+
+ template<typename T>
+ proxy<const basic_table_core&, T> operator[](T&& key) const & {
+ return proxy<const basic_table_core&, T>(*this, std::forward<T>(key));
+ }
+
+ template<typename T>
+ proxy<basic_table_core, T> operator[](T&& key) && {
+ return proxy<basic_table_core, T>(*this, std::forward<T>(key));
+ }
+
+ template<typename Sig, typename Key, typename... Args>
+ basic_table_core& set_function(Key&& key, Args&&... args) {
+ set_fx(types<Sig>(), std::forward<Key>(key), std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template<typename Key, typename... Args>
+ basic_table_core& set_function(Key&& key, Args&&... args) {
+ set_fx(types<>(), std::forward<Key>(key), std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template <typename... Args>
+ basic_table_core& add(Args&&... args) {
+ auto pp = stack::push_pop(*this);
+ (void)detail::swallow{0,
+ (stack::set_ref(base_t::lua_state(), std::forward<Args>(args)), 0)...
+ };
+ return *this;
+ }
+
+ private:
+ template<typename R, typename... Args, typename Fx, typename Key, typename = std::result_of_t<Fx(Args...)>>
+ void set_fx(types<R(Args...)>, Key&& key, Fx&& fx) {
+ set_resolved_function<R(Args...)>(std::forward<Key>(key), std::forward<Fx>(fx));
+ }
+
+ template<typename Fx, typename Key, meta::enable<meta::is_specialization_of<overload_set, meta::unqualified_t<Fx>>> = meta::enabler>
+ void set_fx(types<>, Key&& key, Fx&& fx) {
+ set(std::forward<Key>(key), std::forward<Fx>(fx));
+ }
+
+ template<typename Fx, typename Key, typename... Args, meta::disable<meta::is_specialization_of<overload_set, meta::unqualified_t<Fx>>> = meta::enabler>
+ void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) {
+ set(std::forward<Key>(key), as_function_reference(std::forward<Fx>(fx), std::forward<Args>(args)...));
+ }
+
+ template<typename... Sig, typename... Args, typename Key>
+ void set_resolved_function(Key&& key, Args&&... args) {
+ set(std::forward<Key>(key), as_function_reference<function_sig<Sig...>>(std::forward<Args>(args)...));
+ }
+
+ public:
+ static inline table create(lua_State* L, int narr = 0, int nrec = 0) {
+ lua_createtable(L, narr, nrec);
+ table result(L);
+ lua_pop(L, 1);
+ return result;
+ }
+
+ template <typename Key, typename Value, typename... Args>
+ static inline table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
+ lua_createtable(L, narr, nrec);
+ table result(L);
+ result.set(std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
+ lua_pop(L, 1);
+ return result;
+ }
+
+ template <typename... Args>
+ static inline table create_with(lua_State* L, Args&&... args) {
+ static_assert(sizeof...(Args) % 2 == 0, "You must have an even number of arguments for a key, value ... list.");
+ static const int narr = static_cast<int>(meta::count_2_for_pack<std::is_integral, Args...>::value);
+ return create(L, narr, static_cast<int>((sizeof...(Args) / 2) - narr), std::forward<Args>(args)...);
+ }
+
+ table create(int narr = 0, int nrec = 0) {
+ return create(base_t::lua_state(), narr, nrec);
+ }
+
+ template <typename Key, typename Value, typename... Args>
+ table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
+ return create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
+ }
+
+ template <typename Name>
+ table create(Name&& name, int narr = 0, int nrec = 0) {
+ table x = create(base_t::lua_state(), narr, nrec);
+ this->set(std::forward<Name>(name), x);
+ return x;
+ }
+
+ template <typename Name, typename Key, typename Value, typename... Args>
+ table create(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
+ table x = create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
+ this->set(std::forward<Name>(name), x);
+ return x;
+ }
+
+ template <typename... Args>
+ table create_with(Args&&... args) {
+ return create_with(base_t::lua_state(), std::forward<Args>(args)...);
+ }
+
+ template <typename Name, typename... Args>
+ table create_named(Name&& name, Args&&... args) {
+ static const int narr = static_cast<int>(meta::count_2_for_pack<std::is_integral, Args...>::value);
+ return create(std::forward<Name>(name), narr, sizeof...(Args) / 2 - narr, std::forward<Args>(args)...);
+ }
+
+ ~basic_table_core() {
+
+ }
+ };
+} // sol
+
+// end of sol/table_core.hpp
+
+namespace sol {
+ typedef table_core<false> table;
+} // sol
+
+// end of sol/table.hpp
+
+// beginning of sol/load_result.hpp
+
+namespace sol {
+ struct load_result : public proxy_base<load_result> {
+ private:
+ lua_State* L;
+ int index;
+ int returncount;
+ int popcount;
+ load_status err;
+
+ template <typename T>
+ decltype(auto) tagged_get(types<sol::optional<T>>) const {
+ if (!valid()) {
+ return sol::optional<T>(nullopt);
+ }
+ return stack::get<sol::optional<T>>(L, index);
+ }
+
+ template <typename T>
+ decltype(auto) tagged_get(types<T>) const {
+#ifdef SOL_CHECK_ARGUMENTS
+ if (!valid()) {
+ type_panic(L, index, type_of(L, index), type::none);
+ }
+#endif // Check Argument Safety
+ return stack::get<T>(L, index);
+ }
+
+ sol::optional<sol::error> tagged_get(types<sol::optional<sol::error>>) const {
+ if (valid()) {
+ return nullopt;
+ }
+ return sol::error(detail::direct_error, stack::get<std::string>(L, index));
+ }
+
+ sol::error tagged_get(types<sol::error>) const {
+#ifdef SOL_CHECK_ARGUMENTS
+ if (valid()) {
+ type_panic(L, index, type_of(L, index), type::none);
+ }
+#endif // Check Argument Safety
+ return sol::error(detail::direct_error, stack::get<std::string>(L, index));
+ }
+
+ public:
+ load_result() = default;
+ load_result(lua_State* Ls, int stackindex = -1, int retnum = 0, int popnum = 0, load_status lerr = load_status::ok) noexcept : L(Ls), index(stackindex), returncount(retnum), popcount(popnum), err(lerr) {
+
+ }
+ load_result(const load_result&) = default;
+ load_result& operator=(const load_result&) = default;
+ load_result(load_result&& o) noexcept : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) {
+ // Must be manual, otherwise destructor will screw us
+ // return count being 0 is enough to keep things clean
+ // but we will be thorough
+ o.L = nullptr;
+ o.index = 0;
+ o.returncount = 0;
+ o.popcount = 0;
+ o.err = load_status::syntax;
+ }
+ load_result& operator=(load_result&& o) noexcept {
+ L = o.L;
+ index = o.index;
+ returncount = o.returncount;
+ popcount = o.popcount;
+ err = o.err;
+ // Must be manual, otherwise destructor will screw us
+ // return count being 0 is enough to keep things clean
+ // but we will be thorough
+ o.L = nullptr;
+ o.index = 0;
+ o.returncount = 0;
+ o.popcount = 0;
+ o.err = load_status::syntax;
+ return *this;
+ }
+
+ load_status status() const noexcept {
+ return err;
+ }
+
+ bool valid() const noexcept {
+ return status() == load_status::ok;
+ }
+
+ template<typename T>
+ T get() const {
+ return tagged_get(types<meta::unqualified_t<T>>());
+ }
+
+ template<typename... Ret, typename... Args>
+ decltype(auto) call(Args&&... args) {
+ return get<protected_function>().template call<Ret...>(std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ decltype(auto) operator()(Args&&... args) {
+ return call<>(std::forward<Args>(args)...);
+ }
+
+ lua_State* lua_state() const noexcept { return L; };
+ int stack_index() const noexcept { return index; };
+
+ ~load_result() {
+ stack::remove(L, index, popcount);
+ }
+ };
+} // sol
+
+// end of sol/load_result.hpp
+
+namespace sol {
+ enum class lib : char {
+ base,
+ package,
+ coroutine,
+ string,
+ os,
+ math,
+ table,
+ debug,
+ bit32,
+ io,
+ ffi,
+ jit,
+ utf8,
+ count
+ };
+
+ inline std::size_t total_memory_used(lua_State* L) {
+ std::size_t kb = lua_gc(L, LUA_GCCOUNT, 0);
+ kb *= 1024;
+ kb += lua_gc(L, LUA_GCCOUNTB, 0);
+ return kb;
+ }
+
+ class state_view {
+ private:
+ lua_State* L;
+ table reg;
+ global_table global;
+
+ optional<object> is_loaded_package(const std::string& key) {
+ auto loaded = reg.traverse_get<optional<object>>("_LOADED", key);
+ bool is53mod = loaded && !(loaded->is<bool>() && !loaded->as<bool>());
+ if (is53mod)
+ return loaded;
+#if SOL_LUA_VERSION <= 501
+ auto loaded51 = global.traverse_get<optional<object>>("package", "loaded", key);
+ bool is51mod = loaded51 && !(loaded51->is<bool>() && !loaded51->as<bool>());
+ if (is51mod)
+ return loaded51;
+#endif
+ return nullopt;
+ }
+
+ template <typename T>
+ void ensure_package(const std::string& key, T&& sr) {
+#if SOL_LUA_VERSION <= 501
+ auto pkg = global["package"];
+ if (!pkg.valid()) {
+ pkg = create_table_with("loaded", create_table_with(key, sr));
+ }
+ else {
+ auto ld = pkg["loaded"];
+ if (!ld.valid()) {
+ ld = create_table_with(key, sr);
+ }
+ else {
+ ld[key] = sr;
+ }
+ }
+#endif
+ auto loaded = reg["_LOADED"];
+ if (!loaded.valid()) {
+ loaded = create_table_with(key, sr);
+ }
+ else {
+ loaded[key] = sr;
+ }
+ }
+
+ template <typename Fx>
+ object require_core(const std::string& key, Fx&& action, bool create_global = true) {
+ optional<object> loaded = is_loaded_package(key);
+ if (loaded && loaded->valid())
+ return std::move(*loaded);
+ action();
+ auto sr = stack::get<stack_reference>(L);
+ if (create_global)
+ set(key, sr);
+ ensure_package(key, sr);
+ return stack::pop<object>(L);
+ }
+
+ public:
+ typedef global_table::iterator iterator;
+ typedef global_table::const_iterator const_iterator;
+
+ state_view(lua_State* Ls) :
+ L(Ls),
+ reg(Ls, LUA_REGISTRYINDEX),
+ global(Ls, detail::global_) {
+
+ }
+
+ state_view(this_state Ls) : state_view(Ls.L){
+
+ }
+
+ lua_State* lua_state() const {
+ return L;
+ }
+
+ template<typename... Args>
+ void open_libraries(Args&&... args) {
+ static_assert(meta::all_same<lib, Args...>::value, "all types must be libraries");
+ if (sizeof...(args) == 0) {
+ luaL_openlibs(L);
+ return;
+ }
+
+ lib libraries[1 + sizeof...(args)] = { lib::count, std::forward<Args>(args)... };
+
+ for (auto&& library : libraries) {
+ switch (library) {
+#if SOL_LUA_VERSION <= 501 && defined(SOL_LUAJIT)
+ case lib::coroutine:
+#endif // luajit opens coroutine base stuff
+ case lib::base:
+ luaL_requiref(L, "base", luaopen_base, 1);
+ lua_pop(L, 1);
+ break;
+ case lib::package:
+ luaL_requiref(L, "package", luaopen_package, 1);
+ lua_pop(L, 1);
+ break;
+#if !defined(SOL_LUAJIT)
+ case lib::coroutine:
+#if SOL_LUA_VERSION > 501
+ luaL_requiref(L, "coroutine", luaopen_coroutine, 1);
+ lua_pop(L, 1);
+#endif // Lua 5.2+ only
+ break;
+#endif // Not LuaJIT - comes builtin
+ case lib::string:
+ luaL_requiref(L, "string", luaopen_string, 1);
+ lua_pop(L, 1);
+ break;
+ case lib::table:
+ luaL_requiref(L, "table", luaopen_table, 1);
+ lua_pop(L, 1);
+ break;
+ case lib::math:
+ luaL_requiref(L, "math", luaopen_math, 1);
+ lua_pop(L, 1);
+ break;
+ case lib::bit32:
+#ifdef SOL_LUAJIT
+ luaL_requiref(L, "bit32", luaopen_bit, 1);
+ lua_pop(L, 1);
+#elif (SOL_LUA_VERSION == 502) || defined(LUA_COMPAT_BITLIB) || defined(LUA_COMPAT_5_2)
+ luaL_requiref(L, "bit32", luaopen_bit32, 1);
+ lua_pop(L, 1);
+#else
+#endif // Lua 5.2 only (deprecated in 5.3 (503)) (Can be turned on with Compat flags)
+ break;
+ case lib::io:
+ luaL_requiref(L, "io", luaopen_io, 1);
+ lua_pop(L, 1);
+ break;
+ case lib::os:
+ luaL_requiref(L, "os", luaopen_os, 1);
+ lua_pop(L, 1);
+ break;
+ case lib::debug:
+ luaL_requiref(L, "debug", luaopen_debug, 1);
+ lua_pop(L, 1);
+ break;
+ case lib::utf8:
+#if SOL_LUA_VERSION > 502 && !defined(SOL_LUAJIT)
+ luaL_requiref(L, "utf8", luaopen_utf8, 1);
+ lua_pop(L, 1);
+#endif // Lua 5.3+ only
+ break;
+ case lib::ffi:
+#ifdef SOL_LUAJIT
+ luaL_requiref(L, "ffi", luaopen_ffi, 1);
+ lua_pop(L, 1);
+#endif // LuaJIT only
+ break;
+ case lib::jit:
+#ifdef SOL_LUAJIT
+ luaL_requiref(L, "jit", luaopen_jit, 1);
+ lua_pop(L, 1);
+#endif // LuaJIT Only
+ break;
+ case lib::count:
+ default:
+ break;
+ }
+ }
+ }
+
+ object require(const std::string& key, lua_CFunction open_function, bool create_global = true) {
+ luaL_requiref(L, key.c_str(), open_function, create_global ? 1 : 0);
+ return stack::pop<object>(L);
+ }
+
+ object require_script(const std::string& key, const std::string& code, bool create_global = true) {
+ return require_core(key, [this, &code]() {stack::script(L, code); }, create_global);
+ }
+
+ object require_file(const std::string& key, const std::string& filename, bool create_global = true) {
+ return require_core(key, [this, &filename]() {stack::script_file(L, filename); }, create_global);
+ }
+
+ protected_function_result do_string(const std::string& code) {
+ sol::protected_function pf = load(code);
+ return pf();
+ }
+
+ protected_function_result do_file(const std::string& filename) {
+ sol::protected_function pf = load_file(filename);
+ return pf();
+ }
+
+ function_result script(const std::string& code) {
+ int index = lua_gettop(L);
+ stack::script(L, code);
+ int postindex = lua_gettop(L);
+ int returns = postindex - index;
+ return function_result(L, (std::max)(postindex - (returns - 1), 1), returns);
+ }
+
+ function_result script_file(const std::string& filename) {
+ int index = lua_gettop(L);
+ stack::script_file(L, filename);
+ int postindex = lua_gettop(L);
+ int returns = postindex - index;
+ return function_result(L, (std::max)(postindex - (returns - 1), 1), returns);
+ }
+
+ load_result load(const std::string& code) {
+ load_status x = static_cast<load_status>(luaL_loadstring(L, code.c_str()));
+ return load_result(L, lua_absindex(L, -1), 1, 1, x);
+ }
+
+ load_result load_file(const std::string& filename) {
+ load_status x = static_cast<load_status>(luaL_loadfile(L, filename.c_str()));
+ return load_result(L, lua_absindex(L, -1), 1, 1, x);
+ }
+
+ load_result load_buffer(const char *buff, size_t size, const char *name, const char* mode = nullptr) {
+ load_status x = static_cast<load_status>(luaL_loadbufferx(L, buff, size, name, mode));
+ return load_result(L, lua_absindex(L, -1), 1, 1, x);
+ }
+
+ iterator begin() const {
+ return global.begin();
+ }
+
+ iterator end() const {
+ return global.end();
+ }
+
+ const_iterator cbegin() const {
+ return global.cbegin();
+ }
+
+ const_iterator cend() const {
+ return global.cend();
+ }
+
+ global_table globals() const {
+ return global;
+ }
+
+ table registry() const {
+ return reg;
+ }
+
+ std::size_t memory_used() const {
+ return total_memory_used(lua_state());
+ }
+
+ void collect_garbage() {
+ lua_gc(lua_state(), LUA_GCCOLLECT, 0);
+ }
+
+ operator lua_State* () const {
+ return lua_state();
+ }
+
+ void set_panic(lua_CFunction panic) {
+ lua_atpanic(L, panic);
+ }
+
+ template<typename... Args, typename... Keys>
+ decltype(auto) get(Keys&&... keys) const {
+ return global.get<Args...>(std::forward<Keys>(keys)...);
+ }
+
+ template<typename T, typename Key>
+ decltype(auto) get_or(Key&& key, T&& otherwise) const {
+ return global.get_or(std::forward<Key>(key), std::forward<T>(otherwise));
+ }
+
+ template<typename T, typename Key, typename D>
+ decltype(auto) get_or(Key&& key, D&& otherwise) const {
+ return global.get_or<T>(std::forward<Key>(key), std::forward<D>(otherwise));
+ }
+
+ template<typename... Args>
+ state_view& set(Args&&... args) {
+ global.set(std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template<typename T, typename... Keys>
+ decltype(auto) traverse_get(Keys&&... keys) const {
+ return global.traverse_get<T>(std::forward<Keys>(keys)...);
+ }
+
+ template<typename... Args>
+ state_view& traverse_set(Args&&... args) {
+ global.traverse_set(std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template<typename T>
+ state_view& set_usertype(usertype<T>& user) {
+ return set_usertype(usertype_traits<T>::name(), user);
+ }
+
+ template<typename Key, typename T>
+ state_view& set_usertype(Key&& key, usertype<T>& user) {
+ global.set_usertype(std::forward<Key>(key), user);
+ return *this;
+ }
+
+ template<typename Class, typename... Args>
+ state_view& new_usertype(const std::string& name, Args&&... args) {
+ global.new_usertype<Class>(name, std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template<typename Class, typename CTor0, typename... CTor, typename... Args>
+ state_view& new_usertype(const std::string& name, Args&&... args) {
+ global.new_usertype<Class, CTor0, CTor...>(name, std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template<typename Class, typename... CArgs, typename... Args>
+ state_view& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
+ global.new_usertype<Class>(name, ctor, std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template<typename Class, typename... Args>
+ state_view& new_simple_usertype(const std::string& name, Args&&... args) {
+ global.new_simple_usertype<Class>(name, std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template<typename Class, typename CTor0, typename... CTor, typename... Args>
+ state_view& new_simple_usertype(const std::string& name, Args&&... args) {
+ global.new_simple_usertype<Class, CTor0, CTor...>(name, std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template<typename Class, typename... CArgs, typename... Args>
+ state_view& new_simple_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
+ global.new_simple_usertype<Class>(name, ctor, std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template<typename Class, typename... Args>
+ simple_usertype<Class> create_simple_usertype(Args&&... args) {
+ return global.create_simple_usertype<Class>(std::forward<Args>(args)...);
+ }
+
+ template<typename Class, typename CTor0, typename... CTor, typename... Args>
+ simple_usertype<Class> create_simple_usertype(Args&&... args) {
+ return global.create_simple_usertype<Class, CTor0, CTor...>(std::forward<Args>(args)...);
+ }
+
+ template<typename Class, typename... CArgs, typename... Args>
+ simple_usertype<Class> create_simple_usertype(constructors<CArgs...> ctor, Args&&... args) {
+ return global.create_simple_usertype<Class>(ctor, std::forward<Args>(args)...);
+ }
+
+ template<bool read_only = true, typename... Args>
+ state_view& new_enum(const std::string& name, Args&&... args) {
+ global.new_enum<read_only>(name, std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template <typename Fx>
+ void for_each(Fx&& fx) {
+ global.for_each(std::forward<Fx>(fx));
+ }
+
+ template<typename T>
+ proxy<global_table&, T> operator[](T&& key) {
+ return global[std::forward<T>(key)];
+ }
+
+ template<typename T>
+ proxy<const global_table&, T> operator[](T&& key) const {
+ return global[std::forward<T>(key)];
+ }
+
+ template<typename Sig, typename... Args, typename Key>
+ state_view& set_function(Key&& key, Args&&... args) {
+ global.set_function<Sig>(std::forward<Key>(key), std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template<typename... Args, typename Key>
+ state_view& set_function(Key&& key, Args&&... args) {
+ global.set_function(std::forward<Key>(key), std::forward<Args>(args)...);
+ return *this;
+ }
+
+ template <typename Name>
+ table create_table(Name&& name, int narr = 0, int nrec = 0) {
+ return global.create(std::forward<Name>(name), narr, nrec);
+ }
+
+ template <typename Name, typename Key, typename Value, typename... Args>
+ table create_table(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
+ return global.create(std::forward<Name>(name), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
+ }
+
+ template <typename Name, typename... Args>
+ table create_named_table(Name&& name, Args&&... args) {
+ table x = global.create_with(std::forward<Args>(args)...);
+ global.set(std::forward<Name>(name), x);
+ return x;
+ }
+
+ table create_table(int narr = 0, int nrec = 0) {
+ return create_table(lua_state(), narr, nrec);
+ }
+
+ template <typename Key, typename Value, typename... Args>
+ table create_table(int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
+ return create_table(lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ table create_table_with(Args&&... args) {
+ return create_table_with(lua_state(), std::forward<Args>(args)...);
+ }
+
+ static inline table create_table(lua_State* L, int narr = 0, int nrec = 0) {
+ return global_table::create(L, narr, nrec);
+ }
+
+ template <typename Key, typename Value, typename... Args>
+ static inline table create_table(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
+ return global_table::create(L, narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ static inline table create_table_with(lua_State* L, Args&&... args) {
+ return global_table::create_with(L, std::forward<Args>(args)...);
+ }
+ };
+} // sol
+
+// end of sol/state_view.hpp
+
+namespace sol {
+ inline int default_at_panic(lua_State* L) {
+#ifdef SOL_NO_EXCEPTIONS
+ (void)L;
+ return -1;
+#else
+ const char* message = lua_tostring(L, -1);
+ if (message) {
+ std::string err = message;
+ lua_pop(L, 1);
+ throw error(err);
+ }
+ throw error(std::string("An unexpected error occurred and forced the lua state to call atpanic"));
+#endif
+ }
+
+ inline int default_error_handler(lua_State*L) {
+ using namespace sol;
+ std::string msg = "An unknown error has triggered the default error handler";
+ optional<string_detail::string_shim> maybetopmsg = stack::check_get<string_detail::string_shim>(L, 1);
+ if (maybetopmsg) {
+ const string_detail::string_shim& topmsg = maybetopmsg.value();
+ msg.assign(topmsg.c_str(), topmsg.size());
+ }
+ luaL_traceback(L, L, msg.c_str(), 1);
+ optional<string_detail::string_shim> maybetraceback = stack::check_get<string_detail::string_shim>(L, -1);
+ if (maybetraceback) {
+ const string_detail::string_shim& traceback = maybetraceback.value();
+ msg.assign(traceback.c_str(), traceback.size());
+ }
+ return stack::push(L, msg);
+ }
+
+ class state : private std::unique_ptr<lua_State, void(*)(lua_State*)>, public state_view {
+ private:
+ typedef std::unique_ptr<lua_State, void(*)(lua_State*)> unique_base;
+ public:
+ state(lua_CFunction panic = default_at_panic) : unique_base(luaL_newstate(), lua_close),
+ state_view(unique_base::get()) {
+ set_panic(panic);
+ stack::luajit_exception_handler(unique_base::get());
+ }
+
+ state(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr) : unique_base(lua_newstate(alfunc, alpointer), lua_close),
+ state_view(unique_base::get()) {
+ set_panic(panic);
+ sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, default_error_handler));
+ stack::luajit_exception_handler(unique_base::get());
+ }
+
+ state(const state&) = delete;
+ state(state&&) = default;
+ state& operator=(const state&) = delete;
+ state& operator=(state&& that) {
+ state_view::operator=(std::move(that));
+ unique_base::operator=(std::move(that));
+ return *this;
+ }
+
+ using state_view::get;
+
+ ~state() {
+ auto& handler = protected_function::get_default_handler();
+ if (handler.lua_state() == this->lua_state()) {
+ protected_function::set_default_handler(reference());
+ }
+ }
+ };
+} // sol
+
+// end of sol/state.hpp
+
+// beginning of sol/coroutine.hpp
+
+// beginning of sol/thread.hpp
+
+namespace sol {
+ struct lua_thread_state {
+ lua_State* L;
+ operator lua_State* () const {
+ return L;
+ }
+ lua_State* operator-> () const {
+ return L;
+ }
+ };
+
+ namespace stack {
+
+ template <>
+ struct pusher<lua_thread_state> {
+ int push(lua_State*, lua_thread_state lts) {
+ lua_pushthread(lts.L);
+ return 1;
+ }
+ };
+
+ template <>
+ struct getter<lua_thread_state> {
+ lua_thread_state get(lua_State* L, int index, record& tracking) {
+ tracking.use(1);
+ lua_thread_state lts{ lua_tothread(L, index) };
+ return lts;
+ }
+ };
+
+ template <>
+ struct check_getter<lua_thread_state> {
+ template <typename Handler>
+ optional<lua_thread_state> get(lua_State* L, int index, Handler&& handler, record& tracking) {
+ lua_thread_state lts{ lua_tothread(L, index) };
+ if (lts.L == nullptr) {
+ handler(L, index, type::thread, type_of(L, index));
+ return nullopt;
+ }
+ tracking.use(1);
+ return lts;
+ }
+ };
+
+ }
+
+#if SOL_LUA_VERSION < 502
+ inline lua_State* main_thread(lua_State*, lua_State* backup_if_unsupported = nullptr) {
+ return backup_if_unsupported;
+ }
+#else
+ inline lua_State* main_thread(lua_State* L, lua_State* = nullptr) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
+ lua_thread_state s = stack::pop<lua_thread_state>(L);
+ return s.L;
+ }
+#endif // Lua 5.2+ has the main thread getter
+
+ class thread : public reference {
+ public:
+ thread() noexcept = default;
+ thread(const thread&) = default;
+ thread(thread&&) = default;
+ template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, thread>>, std::is_base_of<reference, meta::unqualified_t<T>>> = meta::enabler>
+ thread(T&& r) : reference(std::forward<T>(r)) {}
+ thread(const stack_reference& r) : thread(r.lua_state(), r.stack_index()) {};
+ thread(stack_reference&& r) : thread(r.lua_state(), r.stack_index()) {};
+ thread& operator=(const thread&) = default;
+ thread& operator=(thread&&) = default;
+ template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler>
+ thread(lua_State* L, T&& r) : thread(L, sol::ref_index(r.registry_index())) {}
+ thread(lua_State* L, int index = -1) : reference(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ type_assert(L, index, type::thread);
+#endif // Safety
+ }
+ thread(lua_State* L, ref_index index) : reference(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ auto pp = stack::push_pop(*this);
+ type_assert(L, -1, type::thread);
+#endif // Safety
+ }
+ thread(lua_State* L, lua_State* actualthread) : thread(L, lua_thread_state{ actualthread }) {}
+ thread(lua_State* L, sol::this_state actualthread) : thread(L, lua_thread_state{ actualthread.L }) {}
+ thread(lua_State* L, lua_thread_state actualthread) : reference(L, -stack::push(L, actualthread)) {
+#ifdef SOL_CHECK_ARGUMENTS
+ type_assert(L, -1, type::thread);
+#endif // Safety
+ lua_pop(L, 1);
+ }
+
+ state_view state() const {
+ return state_view(this->thread_state());
+ }
+
+ bool is_main_thread() const {
+ int ismainthread = lua_pushthread(this->thread_state());
+ lua_pop(this->thread_state(), 1);
+ return ismainthread == 1;
+ }
+
+ lua_State* thread_state() const {
+ auto pp = stack::push_pop(*this);
+ lua_State* lthread = lua_tothread(lua_state(), -1);
+ return lthread;
+ }
+
+ thread_status status() const {
+ lua_State* lthread = thread_state();
+ thread_status lstat = static_cast<thread_status>(lua_status(lthread));
+ if (lstat != thread_status::ok && lua_gettop(lthread) == 0) {
+ // No thing on the thread's stack means its dead
+ return thread_status::dead;
+ }
+ return lstat;
+ }
+
+ thread create() {
+ return create(lua_state());
+ }
+
+ static thread create(lua_State* L) {
+ lua_newthread(L);
+ thread result(L);
+ lua_pop(L, 1);
+ return result;
+ }
+ };
+} // sol
+
+// end of sol/thread.hpp
+
+namespace sol {
+ class coroutine : public reference {
+ private:
+ call_status stats = call_status::yielded;
+
+ void luacall(std::ptrdiff_t argcount, std::ptrdiff_t) {
+#if SOL_LUA_VERSION < 502
+ stats = static_cast<call_status>(lua_resume(lua_state(), static_cast<int>(argcount)));
+#else
+ stats = static_cast<call_status>(lua_resume(lua_state(), nullptr, static_cast<int>(argcount)));
+#endif // Lua 5.1 compat
+ }
+
+ template<std::size_t... I, typename... Ret>
+ auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) {
+ luacall(n, sizeof...(Ret));
+ return stack::pop<std::tuple<Ret...>>(lua_state());
+ }
+
+ template<std::size_t I, typename Ret>
+ Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) {
+ luacall(n, 1);
+ return stack::pop<Ret>(lua_state());
+ }
+
+ template <std::size_t I>
+ void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) {
+ luacall(n, 0);
+ }
+
+ protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) {
+ int stacksize = lua_gettop(lua_state());
+ int firstreturn = (std::max)(1, stacksize - static_cast<int>(n));
+ luacall(n, LUA_MULTRET);
+ int poststacksize = lua_gettop(lua_state());
+ int returncount = poststacksize - (firstreturn - 1);
+ if (error()) {
+ return protected_function_result(lua_state(), lua_absindex(lua_state(), -1), 1, returncount, status());
+ }
+ return protected_function_result(lua_state(), firstreturn, returncount, returncount, status());
+ }
+
+ public:
+ coroutine() noexcept = default;
+ coroutine(const coroutine&) noexcept = default;
+ coroutine(coroutine&&) noexcept = default;
+ coroutine& operator=(const coroutine&) noexcept = default;
+ coroutine& operator=(coroutine&&) noexcept = default;
+ template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, coroutine>>, std::is_base_of<reference, meta::unqualified_t<T>>> = meta::enabler>
+ coroutine(T&& r) : reference(std::forward<T>(r)) {}
+ coroutine(lua_nil_t r) : reference(r) {}
+ coroutine(const stack_reference& r) noexcept : coroutine(r.lua_state(), r.stack_index()) {}
+ coroutine(stack_reference&& r) noexcept : coroutine(r.lua_state(), r.stack_index()) {}
+ template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler>
+ coroutine(lua_State* L, T&& r) : coroutine(L, sol::ref_index(r.registry_index())) {}
+ coroutine(lua_State* L, int index = -1) : reference(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ stack::check<coroutine>(L, index, type_panic);
+#endif // Safety
+ }
+ coroutine(lua_State* L, ref_index index) : reference(L, index) {
+#ifdef SOL_CHECK_ARGUMENTS
+ auto pp = stack::push_pop(*this);
+ stack::check<coroutine>(L, -1, type_panic);
+#endif // Safety
+ }
+
+ call_status status() const noexcept {
+ return stats;
+ }
+
+ bool error() const noexcept {
+ call_status cs = status();
+ return cs != call_status::ok && cs != call_status::yielded;
+ }
+
+ bool runnable() const noexcept {
+ return valid()
+ && (status() == call_status::yielded);
+ }
+
+ explicit operator bool() const noexcept {
+ return runnable();
+ }
+
+ template<typename... Args>
+ protected_function_result operator()(Args&&... args) {
+ return call<>(std::forward<Args>(args)...);
+ }
+
+ template<typename... Ret, typename... Args>
+ decltype(auto) operator()(types<Ret...>, Args&&... args) {
+ return call<Ret...>(std::forward<Args>(args)...);
+ }
+
+ template<typename... Ret, typename... Args>
+ decltype(auto) call(Args&&... args) {
+ push();
+ int pushcount = stack::multi_push(lua_state(), std::forward<Args>(args)...);
+ return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);
+ }
+ };
+} // sol
+
+// end of sol/coroutine.hpp
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#elif defined _MSC_VER
+#pragma warning( push )
+#endif // g++
+
+#ifdef SOL_INSIDE_UNREAL
+#ifdef SOL_INSIDE_UNREAL_REMOVED_CHECK
+#define check(expr) { if(UNLIKELY(!(expr))) { FDebug::LogAssertFailedMessage( #expr, __FILE__, __LINE__ ); _DebugBreakAndPromptForRemote(); FDebug::AssertFailed( #expr, __FILE__, __LINE__ ); CA_ASSUME(false); } }}
+#endif
+#endif // Unreal Engine 4 Bullshit
+
+#endif // SOL_HPP
+// end of sol.hpp
+
+#endif // SOL_SINGLE_INCLUDE_HPP
diff --git a/external/zlib/CMakeLists.txt b/external/zlib/CMakeLists.txt
new file mode 100644
index 0000000..c441981
--- /dev/null
+++ b/external/zlib/CMakeLists.txt
@@ -0,0 +1,17 @@
+add_library (
+ zlib STATIC
+ adler32.c
+ crc32.c
+ crc32.h
+ inffast.c
+ inffast.h
+ inffixed.h
+ inflate.c
+ inflate.h
+ inftrees.c
+ inftrees.h
+ zconf.h
+ zlib.h
+ zutil.c
+ zutil.h
+ )
diff --git a/external/zlib/adler32.c b/external/zlib/adler32.c
new file mode 100644
index 0000000..007ba26
--- /dev/null
+++ b/external/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/external/zlib/crc32.c b/external/zlib/crc32.c
new file mode 100644
index 0000000..f658a9e
--- /dev/null
+++ b/external/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 <rbrown64@csc.com.au> 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 <stdio.h>
+# 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 <limits.h>
+# 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/external/zlib/crc32.h b/external/zlib/crc32.h
new file mode 100644
index 0000000..8053b61
--- /dev/null
+++ b/external/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/external/zlib/inffast.c b/external/zlib/inffast.c
new file mode 100644
index 0000000..11bcbb0
--- /dev/null
+++ b/external/zlib/inffast.c
@@ -0,0 +1,317 @@
+/* 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;
+}
+
+/*
+ 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/external/zlib/inffast.h b/external/zlib/inffast.h
new file mode 100644
index 0000000..1e88d2d
--- /dev/null
+++ b/external/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/external/zlib/inffixed.h b/external/zlib/inffixed.h
new file mode 100644
index 0000000..75ed4b5
--- /dev/null
+++ b/external/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/external/zlib/inflate.c b/external/zlib/inflate.c
new file mode 100644
index 0000000..792fdee
--- /dev/null
+++ b/external/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 <stdio.h>
+
+/*
+ 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/external/zlib/inflate.h b/external/zlib/inflate.h
new file mode 100644
index 0000000..07bd3e7
--- /dev/null
+++ b/external/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/external/zlib/inftrees.c b/external/zlib/inftrees.c
new file mode 100644
index 0000000..8a9c13f
--- /dev/null
+++ b/external/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/external/zlib/inftrees.h b/external/zlib/inftrees.h
new file mode 100644
index 0000000..b1104c8
--- /dev/null
+++ b/external/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/external/zlib/zconf.h b/external/zlib/zconf.h
new file mode 100644
index 0000000..9514c03
--- /dev/null
+++ b/external/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 <windows.h>
+ /* 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
+
+#ifndef _MSC_VER /* HAVE_UNISTD_H -- this line is updated by ./configure */
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* 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/external/zlib/zlib.h b/external/zlib/zlib.h
new file mode 100644
index 0000000..0228179
--- /dev/null
+++ b/external/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/external/zlib/zutil.c b/external/zlib/zutil.c
new file mode 100644
index 0000000..d55f594
--- /dev/null
+++ b/external/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/external/zlib/zutil.h b/external/zlib/zutil.h
new file mode 100644
index 0000000..b7d5eff
--- /dev/null
+++ b/external/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 <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#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 <errno.h>
+# 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 <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# 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 <malloc.h>
+# 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 <unix.h> /* 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 <stdio.h>
+ 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/make-macosx-app.sh b/make-macosx-app.sh
new file mode 100644
index 0000000..05a72bb
--- /dev/null
+++ b/make-macosx-app.sh
@@ -0,0 +1,345 @@
+#!/bin/bash
+
+# Let's make the user give us a target to work with.
+# architecture is assumed universal if not specified, and is optional.
+# if arch is defined, it we will store the .app bundle in the target arch build directory
+if [ $# == 0 ] || [ $# -gt 2 ]; then
+ echo "Usage: $0 target <arch>"
+ echo "Example: $0 release x86"
+ echo "Valid targets are:"
+ echo " release"
+ echo " debug"
+ echo
+ echo "Optional architectures are:"
+ echo " x86"
+ echo " x86_64"
+ echo
+ exit 1
+fi
+
+# validate target name
+if [ "$1" == "release" ]; then
+ TARGET_NAME="release"
+elif [ "$1" == "debug" ]; then
+ TARGET_NAME="debug"
+else
+ echo "Invalid target: $1"
+ echo "Valid targets are:"
+ echo " release"
+ echo " debug"
+ exit 1
+fi
+
+CURRENT_ARCH=""
+
+# validate the architecture if it was specified
+if [ "$2" != "" ]; then
+ if [ "$2" == "x86" ]; then
+ CURRENT_ARCH="x86"
+ elif [ "$2" == "x86_64" ]; then
+ CURRENT_ARCH="x86_64"
+ else
+ echo "Invalid architecture: $2"
+ echo "Valid architectures are:"
+ echo " x86"
+ echo " x86_64"
+ echo
+ exit 1
+ fi
+fi
+
+# symlinkArch() creates a symlink with the architecture suffix.
+# meant for universal binaries, but also handles the way this script generates
+# application bundles for a single architecture as well.
+function symlinkArch()
+{
+ EXT="dylib"
+ SEP="${3}"
+ SRCFILE="${1}"
+ DSTFILE="${2}${SEP}"
+ DSTPATH="${4}"
+
+ if [ ! -e "${DSTPATH}/${SRCFILE}.${EXT}" ]; then
+ echo "**** ERROR: missing ${SRCFILE}.${EXT} from ${MACOS}"
+ exit 1
+ fi
+
+ if [ ! -d "${DSTPATH}" ]; then
+ echo "**** ERROR: path not found ${DSTPATH}"
+ exit 1
+ fi
+
+ pushd "${DSTPATH}" > /dev/null
+
+ IS32=`file "${SRCFILE}.${EXT}" | grep "i386"`
+ IS64=`file "${SRCFILE}.${EXT}" | grep "x86_64"`
+
+ if [ "${IS32}" != "" ]; then
+ if [ ! -L "${DSTFILE}.${EXT}" ]; then
+ ln -s "${SRCFILE}.${EXT}" "${DSTFILE}.${EXT}"
+ fi
+ elif [ -L "${DSTFILE}.${EXT}" ]; then
+ rm "${DSTFILE}.${EXT}"
+ fi
+
+ if [ "${IS64}" != "" ]; then
+ if [ ! -L "${DSTFILE}.${EXT}" ]; then
+ ln -s "${SRCFILE}.${EXT}" "${DSTFILE}.${EXT}"
+ fi
+ elif [ -L "${DSTFILE}.${EXT}" ]; then
+ rm "${DSTFILE}.${EXT}"
+ fi
+
+ popd > /dev/null
+}
+
+SEARCH_ARCHS=" \
+ x86 \
+ x86_64 \
+"
+
+HAS_LIPO=`command -v lipo`
+HAS_CP=`command -v cp`
+
+# if lipo is not available, we cannot make a universal binary, print a warning
+if [ ! -x "${HAS_LIPO}" ] && [ "${CURRENT_ARCH}" == "" ]; then
+ CURRENT_ARCH=`uname -m`
+ if [ "${CURRENT_ARCH}" == "i386" ]; then CURRENT_ARCH="x86"; fi
+ echo "$0 cannot make a universal binary, falling back to architecture ${CURRENT_ARCH}"
+fi
+
+# if the optional arch parameter is used, replace SEARCH_ARCHS to only work with one
+if [ "${CURRENT_ARCH}" != "" ]; then
+ SEARCH_ARCHS="${CURRENT_ARCH}"
+fi
+
+AVAILABLE_ARCHS=""
+
+IOQ3_VERSION=`grep '^VERSION=' Makefile | sed -e 's/.*=\(.*\)/\1/'`
+IOQ3_CLIENT_ARCHS=""
+IOQ3_SERVER_ARCHS=""
+IOQ3_RENDERER_GL1_ARCHS=""
+IOQ3_RENDERER_GL2_ARCHS=""
+IOQ3_CGAME_ARCHS=""
+IOQ3_GAME_ARCHS=""
+IOQ3_UI_ARCHS=""
+IOQ3_MP_CGAME_ARCHS=""
+IOQ3_MP_GAME_ARCHS=""
+IOQ3_MP_UI_ARCHS=""
+
+BASEDIR="gpp"
+
+CGAME="cgame"
+GAME="game"
+UI="ui"
+
+RENDERER_OPENGL="renderer_opengl"
+
+DEDICATED_NAME="tremded"
+
+CGAME_NAME="${CGAME}.dylib"
+GAME_NAME="${GAME}.dylib"
+UI_NAME="${UI}.dylib"
+
+GIT_REV=$(git describe --tags)
+VMS_PK3="vms-${GIT_REV}.pk3"
+DATA_PK3="data-${GIT_REV}.pk3"
+
+RENDERER_OPENGL1_NAME="${RENDERER_OPENGL}1.dylib"
+RENDERER_OPENGL2_NAME="${RENDERER_OPENGL}2.dylib"
+
+ICNSDIR="misc"
+ICNS="Tremulous.icns"
+PKGINFO="APPLIOQ3"
+
+OBJROOT="build"
+#BUILT_PRODUCTS_DIR="${OBJROOT}/${TARGET_NAME}-darwin-${CURRENT_ARCH}"
+PRODUCT_NAME="Tremulous"
+WRAPPER_EXTENSION="app"
+WRAPPER_NAME="${PRODUCT_NAME}.${WRAPPER_EXTENSION}"
+CONTENTS_FOLDER_PATH="${WRAPPER_NAME}/Contents"
+UNLOCALIZED_RESOURCES_FOLDER_PATH="${CONTENTS_FOLDER_PATH}/Resources"
+EXECUTABLE_FOLDER_PATH="${CONTENTS_FOLDER_PATH}/MacOS"
+EXECUTABLE_NAME="tremulous"
+
+# loop through the architectures to build string lists for each universal binary
+for ARCH in $SEARCH_ARCHS; do
+ CURRENT_ARCH=${ARCH}
+ BUILT_PRODUCTS_DIR="${OBJROOT}/${TARGET_NAME}-darwin-${CURRENT_ARCH}"
+ IOQ3_CLIENT="${EXECUTABLE_NAME}"
+ IOQ3_SERVER="${DEDICATED_NAME}"
+ IOQ3_RENDERER_GL1="${RENDERER_OPENGL}1.dylib"
+ IOQ3_RENDERER_GL2="${RENDERER_OPENGL}2.dylib"
+ IOQ3_CGAME="${CGAME}.dylib"
+ IOQ3_GAME="${GAME}.dylib"
+ IOQ3_UI="${UI}.dylib"
+
+ if [ ! -d ${BUILT_PRODUCTS_DIR} ]; then
+ CURRENT_ARCH=""
+ BUILT_PRODUCTS_DIR=""
+ continue
+ fi
+
+ # executables
+ if [ -e ${BUILT_PRODUCTS_DIR}/${IOQ3_CLIENT} ]; then
+ IOQ3_CLIENT_ARCHS="${BUILT_PRODUCTS_DIR}/${IOQ3_CLIENT} ${IOQ3_CLIENT_ARCHS}"
+ VALID_ARCHS="${ARCH} ${VALID_ARCHS}"
+ else
+ continue
+ fi
+ if [ -e ${BUILT_PRODUCTS_DIR}/${IOQ3_SERVER} ]; then
+ IOQ3_SERVER_ARCHS="${BUILT_PRODUCTS_DIR}/${IOQ3_SERVER} ${IOQ3_SERVER_ARCHS}"
+ fi
+
+ # renderers
+ if [ -e ${BUILT_PRODUCTS_DIR}/${IOQ3_RENDERER_GL1} ]; then
+ IOQ3_RENDERER_GL1_ARCHS="${BUILT_PRODUCTS_DIR}/${IOQ3_RENDERER_GL1} ${IOQ3_RENDERER_GL1_ARCHS}"
+ fi
+ if [ -e ${BUILT_PRODUCTS_DIR}/${IOQ3_RENDERER_GL2} ]; then
+ IOQ3_RENDERER_GL2_ARCHS="${BUILT_PRODUCTS_DIR}/${IOQ3_RENDERER_GL2} ${IOQ3_RENDERER_GL2_ARCHS}"
+ fi
+
+ # game
+ if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_CGAME} ]; then
+ IOQ3_CGAME_ARCHS="${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_CGAME} ${IOQ3_CGAME_ARCHS}"
+ fi
+ if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_GAME} ]; then
+ IOQ3_GAME_ARCHS="${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_GAME} ${IOQ3_GAME_ARCHS}"
+ fi
+ if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_UI} ]; then
+ IOQ3_UI_ARCHS="${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_UI} ${IOQ3_UI_ARCHS}"
+ fi
+
+ #echo "valid arch: ${ARCH}"
+done
+
+# final preparations and checks before attempting to make the application bundle
+cd `dirname $0`
+
+if [ ! -f Makefile ]; then
+ echo "$0 must be run from the ioquake3 build directory `dirname $0`"
+ exit 1
+fi
+
+if [ "${IOQ3_CLIENT_ARCHS}" == "" ]; then
+ echo "$0: no ioquake3 binary architectures were found for target '${TARGET_NAME}'"
+ exit 1
+fi
+
+# set the final application bundle output directory
+if [ "${2}" == "" ]; then
+ BUILT_PRODUCTS_DIR="${OBJROOT}/${TARGET_NAME}-darwin-universal"
+ if [ ! -d ${BUILT_PRODUCTS_DIR} ]; then
+ mkdir -p ${BUILT_PRODUCTS_DIR} || exit 1;
+ fi
+else
+ BUILT_PRODUCTS_DIR="${OBJROOT}/${TARGET_NAME}-darwin-${CURRENT_ARCH}"
+fi
+
+BUNDLEBINDIR="${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}"
+
+
+# here we go
+echo "Creating bundle '${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}'"
+echo "with architectures:"
+for ARCH in ${VALID_ARCHS}; do
+ echo " ${ARCH}"
+done
+echo ""
+
+# make the application bundle directories
+if [ ! -d ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/$BASEDIR ]; then
+ mkdir -p ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/$BASEDIR || exit 1;
+fi
+if [ ! -d ${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH} ]; then
+ mkdir -p ${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH} || exit 1;
+fi
+
+# copy and generate some application bundle resources
+cp external/libs/macosx/*.dylib ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}
+cp ${ICNSDIR}/${ICNS} ${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/$ICNS || exit 1;
+cp "${BUILT_PRODUCTS_DIR}/${BASEDIR}/${VMS_PK3}" "${BUNDLEBINDIR}/${BASEDIR}/${VMS_PK3}"
+cp "${BUILT_PRODUCTS_DIR}/${BASEDIR}/${DATA_PK3}" "${BUNDLEBINDIR}/${BASEDIR}/${DATA_PK3}"
+echo -n ${PKGINFO} > ${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/PkgInfo || exit 1;
+echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>${ICNS}</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.ioquake.${PRODUCT_NAME}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${IOQ3_VERSION}</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>${IOQ3_VERSION}</string>
+ <key>CGDisableCoalescedUpdates</key>
+ <true/>
+ <key>LSMinimumSystemVersion</key>
+ <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 1999-2015 Id Software LLC, a ZeniMax Media company, ioquake3, Darklegion Development, GrangerHub, and Tremulous community contributors.</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
+" > ${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Info.plist
+
+# action takes care of generating universal binaries if lipo is available
+# otherwise, it falls back to using a simple copy, expecting the first item in
+# the second parameter list to be the desired architecture
+function action()
+{
+ COMMAND=""
+
+ if [ -x "${HAS_LIPO}" ]; then
+ COMMAND="${HAS_LIPO} -create -o"
+ $HAS_LIPO -create -o "${1}" ${2} # make sure $2 is treated as a list of files
+ elif [ -x ${HAS_CP} ]; then
+ COMMAND="${HAS_CP}"
+ SRC="${2// */}" # in case there is a list here, use only the first item
+ $HAS_CP "${SRC}" "${1}"
+ else
+ "$0 cannot create an application bundle."
+ exit 1
+ fi
+
+ #echo "${COMMAND}" "${1}" "${2}"
+}
+
+#
+# the meat of universal binary creation
+# destination file names do not have architecture suffix.
+# action will handle merging universal binaries if supported.
+# symlink appropriate architecture names for universal (fat) binary support.
+#
+
+# executables
+action ${BUNDLEBINDIR}/${EXECUTABLE_NAME} "${IOQ3_CLIENT_ARCHS}"
+action ${BUNDLEBINDIR}/${DEDICATED_NAME} "${IOQ3_SERVER_ARCHS}"
+
+# renderers
+action ${BUNDLEBINDIR}/${RENDERER_OPENGL1_NAME} "${IOQ3_RENDERER_GL1_ARCHS}"
+action ${BUNDLEBINDIR}/${RENDERER_OPENGL2_NAME} "${IOQ3_RENDERER_GL2_ARCHS}"
+#symlinkArch "${RENDERER_OPENGL}1" "${RENDERER_OPENGL}1" "_" "${BUNDLEBINDIR}"
+#symlinkArch "${RENDERER_OPENGL}2" "${RENDERER_OPENGL}2" "_" "${BUNDLEBINDIR}"
+
+# game
+action ${BUNDLEBINDIR}/${BASEDIR}/${CGAME_NAME} "${IOQ3_CGAME_ARCHS}"
+action ${BUNDLEBINDIR}/${BASEDIR}/${GAME_NAME} "${IOQ3_GAME_ARCHS}"
+action ${BUNDLEBINDIR}/${BASEDIR}/${UI_NAME} "${IOQ3_UI_ARCHS}"
+symlinkArch "${CGAME}" "${CGAME}" "" "${BUNDLEBINDIR}/${BASEDIR}"
+symlinkArch "${GAME}" "${GAME}" "" "${BUNDLEBINDIR}/${BASEDIR}"
+symlinkArch "${UI}" "${UI}" "" "${BUNDLEBINDIR}/${BASEDIR}"
diff --git a/misc/SLA-dmg.sh b/misc/SLA-dmg.sh
new file mode 100644
index 0000000..af268f3
--- /dev/null
+++ b/misc/SLA-dmg.sh
@@ -0,0 +1,73 @@
+#!/bin/bash
+#
+# This script appends the text from Q3A_EULA.txt to a .dmg as a SLA resource
+#
+# usage is './SLA-dmg.sh /path/to/Q3A_EULA.txt /path/to/ioquake3.dmg'
+#
+
+if [ "x$1" = "x" ] || [ "x$2" = "x" ]; then
+ echo "usage: ./SLA-dmg.sh /path/to/Q3A_EULA.txt /path/to/ioquake3.dmg"
+ exit 1;
+fi
+
+if [ ! -r $1 ]; then
+ echo "$1 is not a readable Q3A_EULA.txt file"
+ exit 1;
+fi
+if [ ! -w $2 ]; then
+ echo "$2 is not writable .dmg file"
+ exit 1;
+fi
+touch tmp.r
+if [ ! -w tmp.r ]; then
+ echo "Could not create temporary file tmp.r for writing"
+ exit 1;
+fi
+
+echo "
+data 'LPic' (5000) {
+ \$\"0002 0011 0003 0001 0000 0000 0002 0000\"
+ \$\"0008 0003 0000 0001 0004 0000 0004 0005\"
+ \$\"0000 000E 0006 0001 0005 0007 0000 0007\"
+ \$\"0008 0000 0047 0009 0000 0034 000A 0001\"
+ \$\"0035 000B 0001 0020 000C 0000 0011 000D\"
+ \$\"0000 005B 0004 0000 0033 000F 0001 000C\"
+ \$\"0010 0000 000B 000E 0000\"
+};
+
+data 'TEXT' (5002, \"English\") {
+" > tmp.r
+
+sed -e 's/"/\\"/g' -e 's/\(.*\)$/"\1\\n"/g' $1 >> tmp.r
+
+echo "
+};
+
+resource 'STR#' (5002, \"English\") {
+ {
+ \"English\",
+ \"Agree\",
+ \"Disagree\",
+ \"Print\",
+ \"Save...\",
+ \"IMPORTANT - Read this License Agreement carefully before clicking on \"
+ \"the \\\"Agree\\\" button. By clicking on the \\\"Agree\\\" button, you agree \"
+ \"to be bound by the terms of the License Agreement.\",
+ \"Software License Agreement\",
+ \"This text cannot be saved. This disk may be full or locked, or the \"
+ \"file may be locked.\",
+ \"Unable to print. Make sure you have selected a printer.\"
+ }
+};
+" >> tmp.r
+
+hdiutil convert -format UDCO -o tmp.dmg $2 || exit 1
+hdiutil unflatten tmp.dmg || exit 1
+/Developer/Tools/Rez /Developer/Headers/FlatCarbon/*.r tmp.r -a -o tmp.dmg \
+ || exit 1
+hdiutil flatten tmp.dmg || exit 1
+hdiutil internet-enable -yes tmp.dmg || exit 1
+mv tmp.dmg $2 || (echo "Could not copy tmp.dmg to $2" && exit 1)
+rm tmp.dmg
+rm tmp.r
+echo "SLA $1 successfully added to $2"
diff --git a/misc/Tremulous.icns b/misc/Tremulous.icns
new file mode 100644
index 0000000..c4106ac
--- /dev/null
+++ b/misc/Tremulous.icns
Binary files differ
diff --git a/misc/docker-build.sh b/misc/docker-build.sh
new file mode 100644
index 0000000..c478ab8
--- /dev/null
+++ b/misc/docker-build.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+failed=0
+
+USE_RESTCLIENT=1 USE_INTERNAL_LUA=1 make -j 2 || failed=1
+
+if [[ $failed -eq 1 ]]; then
+ echo "Build failure."
+ exit $failed
+fi
+
+./misc/download-paks.sh
+chmod -R ugo+rw build
diff --git a/misc/download-paks.sh b/misc/download-paks.sh
new file mode 100644
index 0000000..8da3c85
--- /dev/null
+++ b/misc/download-paks.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+URL="https://github.com/wtfbbqhax/tremulous-data/raw/master/"
+
+packages="
+data-1.1.0.pk3
+data-gpp1.pk3
+map-arachnid2-1.1.0.pk3
+map-atcs-1.1.0.pk3
+map-karith-1.1.0.pk3
+map-nexus6-1.1.0.pk3
+map-niveus-1.1.0.pk3
+map-transit-1.1.0.pk3
+map-tremor-1.1.0.pk3
+map-uncreation-1.1.0.pk3
+"
+
+for dir in ./build/*; do
+ if [[ ! -d $dir ]]; then
+ continue;
+ fi
+
+ # Download
+
+ if [[ $dir == "./build/release-darwin-x86_64" ]]; then
+ pushd $dir/Tremulous.app/Contents/MacOS/gpp/
+ else
+ pushd $dir/gpp
+ fi
+
+ for i in $packages; do
+ if [[ -e $package ]]; then
+ rm -f $package # only want 1 copy
+ fi
+ curl -OL $URL/$i
+ done
+
+ popd
+
+ # Repackage
+
+ pushd $dir
+
+ if [[ $dir == "./build/release-darwin-x86_64" ]]; then
+ zip -r ../$(basename $dir).zip Tremulous.app
+ else
+ zip -r ../$(basename $dir).zip gpp/*.pk3
+ fi
+
+ popd
+done
+
diff --git a/misc/entities.def b/misc/entities.def
new file mode 100644
index 0000000..e61ce16
--- /dev/null
+++ b/misc/entities.def
@@ -0,0 +1,1707 @@
+// Tremulous entity definition file for GTKRadiant
+// Tim Angus <tma@op.ath.cx> 08/09/03
+
+// Based on entities.def from GTKRadiant 1.3.11 which in turn is based on...
+// Based on draft by Suicide 20 7.30.99 and inolen 9-3-99
+// Upgraded by Eutectic: eutectic@ritualistic.com
+// (visible models added by raYGunn - paths provided by Suicide 20)
+// (terrain information added to func_group entity by Paul Jaquays)
+// Q3Map2 entitys/keys added by ydnar
+// Version: 1.5
+// Last updated: 2003-06-09
+
+//=============================================================================
+
+LIGHT ENTITY
+
+//=============================================================================
+
+
+/*QUAKED light (.65 .65 1) (-8 -8 -8) (8 8 8) LINEAR NOANGLE UNUSED1 UNUSED2 NOGRIDLIGHT
+Non-displayed point light source. The -pointscale and -scale arguments to Q3Map2 affect the brightness of these lights. The -skyscale argument affects brightness of entity sun lights.
+
+-------- KEYS --------
+_light OR light: overrides the default 300 intensity.
+
+_color: weighted RGB value of light color (default white - 1.0 1.0 1.0).
+
+target: Lights pointed at a target will be spotlights.
+
+radius: overrides the default 64 unit radius of a spotlight at the target point.
+
+-------- Q3MAP2 KEYS --------
+_sun: Set this key to 1 on a spotlight to make an infinite sun light.
+
+fade: Fades light attenuation. Only affects linear lights.
+
+scale: Scales light attentation, from SOF2/JK2. Scales the "light" value.
+
+-------- SPAWNFLAGS --------
+LINEAR: Use a linear falloff. Default is inverse distance squared (more realistic).
+
+NOANGLE: Ignore angle attenuation.
+
+NOGRIDLIGHT: Do not affect the lightgrid (dynamic entity lighting).
+*/
+
+/*QUAKED lightJunior (0 0.7 0.3) (-6 -6 -6) (6 6 6) LINEAR NOANGLE UNUSED1 UNUSED2 NOGRIDLIGHT
+
+Non-displayed point light source THAT ONLY AFFECTS ENTITIES (lightgrid). The -pointscale and -scale arguments to Q3Map2 affect the brightness of these lights. The -skyscale argument affects brightness of entity sun lights.
+
+-------- KEYS --------
+_light OR light: overrides the default 300 intensity.
+
+_color: weighted RGB value of light color (default white - 1.0 1.0 1.0).
+
+target: Lights pointed at a target will be spotlights.
+
+radius: overrides the default 64 unit radius of a spotlight at the target point.
+
+-------- Q3MAP2 KEYS --------
+_sun: Set this key to 1 on a spotlight to make an infinite sun light.
+
+fade: Fades light attenuation. Only affects linear lights.
+
+scale: Scales light attentation, from SOF2/JK2. Scales the "light" value.
+
+-------- SPAWNFLAGS --------
+LINEAR: Use a linear falloff. Default is inverse distance squared (more realistic).
+
+NOANGLE: Ignore angle attenuation.
+
+NOGRIDLIGHT: Do not affect the lightgrid (dynamic entity lighting). Setting this spawnflag will disable this light entirely.
+*/
+
+//=============================================================================
+
+FUNC_* ENTITIES
+
+//=============================================================================
+
+/*QUAKED func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
+Solid entity that oscillates back and forth in a linear motion. By default, it will have an amount of displacement in either direction equal to the dimension of the brush in the axis in which it's bobbing. Entity bobs on the Z axis (up-down) by default. It can also emit sound if the "noise" key is set. Will crush the player when blocked.
+
+-------- KEYS --------
+speed: amount of time in seconds for one complete oscillation cycle (default 4).
+
+height: sets the amount of travel of the oscillation movement (default 32).
+
+phase: sets the start offset of the oscillation cycle. Values must be 0 < phase < 1. Any integer phase value is the same as no offset (default 0).
+
+noise: path/name of .wav file to play. Use looping sounds only (eg. sound/world/drone6.wav - See Notes).
+
+model2: path/name of model to include (eg: models/mapobjects/jets/jets01.md3).
+
+origin: alternate method of setting XYZ origin of sound and .md3 model included with entity (See Notes).
+
+light: constantLight radius of .md3 model included with entity. Has no effect on the entity's brushes (default 0).
+
+color: constantLight color of .md3 model included with entity. Has no effect on the entity's brushes (default 1 1 1).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- Q3MAP2 KEYS --------
+_targetname: Used to attach a misc_model entity to this entity.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+
+-------- SPAWNFLAGS --------
+X_AXIS: entity will bob along the X axis.
+Y_AXIS: entity will bob along the Y axis.
+
+-------- NOTES --------
+In order for the sound to be emitted from the entity, it is recommended to include a brush with an origin shader at its center, otherwise the sound will not follow the entity as it moves. Setting the origin key is simply an alternate method to using an origin brush. When using the model2 key, the origin point of the model will correspond to the origin point defined by either the origin brush or the origin coordinate value.
+
+Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname").
+*/
+
+//=============================================================================
+
+/*QUAKED func_button (0 .5 .8) ?
+When a button is touched by a player, it moves in the direction set by the "angle" key, triggers all its targets, stays pressed by an amount of time set by the "wait" key, then returns to it's original position where it can be operated again.
+
+-------- KEYS --------
+angle: determines the direction in which the button will move (up = -1, down = -2).
+
+target: all entities with a matching targetname will be triggered.
+
+speed: speed of button's displacement (default 40).
+
+wait: number of seconds button stays pressed (default 1, -1 = return immediately).
+
+lip: lip remaining at end of move (default 4 units).
+
+health: (default 0) if set to any non-zero value, the button must take damage (any amount) to activate.
+
+light: constantLight radius of .md3 model included with entity. Has no effect on the entity's brushes (default 0).
+
+color: constantLight color of .md3 model included with entity. Has no effect on the entity's brushes (default 1 1 1).
+
+model2: path/name of model to include (eg: models/mapobjects/pipe/pipe02.md3).
+
+origin: alternate method of setting XYZ origin of .md3 model included with entity (See Notes).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+sound1to2: the sound played when the door, platform or button moves from state 1 to state 2.
+
+-------- Q3MAP2 KEYS --------
+_targetname: Used to attach a misc_model entity to this entity.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+
+-------- NOTES --------
+Setting the origin key is simply an alternate method to using an origin brush. When using the model2 key, the origin point of the model will correspond to the origin point defined by either the origin brush or the origin coordinate value.
+
+Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname").
+*/
+
+//=============================================================================
+
+/*QUAKED func_door (0 .5 .8) ? START_OPEN - CRUSHER
+Normal sliding door entity. By default, the door will activate when player walks close to it or when damage is inflicted to it.
+
+-------- KEYS --------
+angle: determines the opening direction of door (up = -1, down = -2).
+
+speed: determines how fast the door moves (default 100).
+
+wait: number of seconds before door returns (default 2, -1 = return immediately)
+
+lip: lip remaining at end of move (default 8)
+
+targetname: if set, a func_button or trigger is required to activate the door.
+
+health: (default 0) if set to any non-zero value, the button must take damage (any amount) to activate.
+
+dmg: damage to inflict on player when he blocks operation of door (default 4). Door will reverse direction when blocked unless CRUSHER spawnflag is set.
+
+team: assign the same team name to multiple doors that should operate together (see Notes).
+
+light: constantLight radius of .md3 model included with entity. Has no effect on the entity's brushes (default 0).
+
+color: constantLight color of .md3 model included with entity. Has no effect on the entity's brushes (default 1 1 1).
+
+model2: path/name of model to include (eg: models/mapobjects/pipe/pipe02.md3).
+
+origin: alternate method of setting XYZ origin of .md3 model included with entity (See Notes).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+sound1to2: the sound played when the door, platform or button moves from state 1 to state 2.
+
+sound2to1: the sound played when the door or platform moves from from state 2 to state 1.
+
+soundPos2: the sound played when the door or platform reaches state 2.
+
+soundPos1: the sound played when the door or platform reaches state 1.
+
+-------- Q3MAP2 KEYS --------
+_targetname: Used to attach a misc_model entity to this entity.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+
+-------- SPAWNFLAGS --------
+START_OPEN: the door will spawn in the open state and operate in reverse.
+
+CRUSHER: door will not reverse direction when blocked and will keep damaging player until he dies or gets out of the way.
+
+-------- NOTES --------
+Unlike in Quake 2, doors that touch are NOT automatically teamed. If you want doors to operate together, you have to team them manually by assigning the same team name to all of them. Setting the origin key is simply an alternate method to using an origin brush. When using the model2 key, the origin point of the model will correspond to the origin point defined by either the origin brush or the origin coordinate value.
+
+Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname").
+*/
+
+//=============================================================================
+
+/*QUAKED func_door_model (0 .5 .8) ?
+A model based door entity. By default, the door will activate when player walks close to it. The opening and closing of the door is provided by an animation in the model itself.
+
+-------- KEYS --------
+speed: determines the time taken for the door to change state in msec (default 200).
+
+wait: number of seconds before door returns (default 2)
+
+targetname: if set, a func_button or trigger is required to activate the door.
+
+health: (default 0) if set to any non-zero value, the button must take damage (any amount) to activate.
+
+team: assign the same team name to multiple doors that should operate together (see Notes).
+
+light: constantLight radius of .md3 model included with entity. Has no effect on the entity's brushes (default 0).
+
+color: constantLight color of .md3 model included with entity. Has no effect on the entity's brushes (default 1 1 1).
+
+model2: path/name of the door model (eg: models/mapobjects/pipe/pipe02.md3).
+
+modelOrigin: means of setting the origin of the model.
+
+scale: scale the model in each of the major axes (e.g. 1.0 1.0 2.0 -- twice as high as normal).
+
+animation: The first frame and number of frames in the door open animation (e.g. 0 10). This will be reversed for the close animation.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+sound1to2: the sound played when the door, platform or button moves from state 1 to state 2.
+
+sound2to1: the sound played when the door or platform moves from from state 2 to state 1.
+
+soundPos2: the sound played when the door or platform reaches state 2.
+
+soundPos1: the sound played when the door or platform reaches state 1.
+
+-------- Q3MAP2 KEYS --------
+
+_targetname: Used to attach a misc_model entity to this entity.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+
+-------- NOTES --------
+Every func_door_model needs its model to be positioned, scaled and orientated using the modelOrigin, scale and angle/angles keys repsectively.
+*/
+
+//=============================================================================
+
+/*QUAKED func_door_rotating (0 .5 .8) ? START_OPEN - CRUSHER REVERSE - X_AXIS Y_AXIS
+Rotating door entity. By default, the door will activate when player walks close toit.
+
+-------- KEYS --------
+speed: determines how fast the door moves (in degrees/second).
+
+rotatorAngle: the number of degrees through which to rotate (default 90).
+
+wait: number of seconds before door returns (default 2)
+
+targetname: if set, a func_button or trigger is required to activate the door.
+
+health: (default 0) if set to any non-zero value, the button must take damage (any amount) to activate.
+
+dmg: damage to inflict on player when he blocks operation of door (default 4). Door will reverse direction when blocked unless CRUSHER spawnflag is set.
+
+team: assign the same team name to multiple doors that should operate together (see Notes).
+
+light: constantLight radius of .md3 model included with entity. Has no effect on the entity's brushes (default 0).
+
+color: constantLight color of .md3 model included with entity. Has no effect on the entity's brushes (default 1 1 1).
+
+model2: path/name of model to include (eg: models/mapobjects/pipe/pipe02.md3).
+
+origin: alternate method of setting XYZ origin of .md3 model included with entity (See Notes).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+sound1to2: the sound played when the door, platform or button moves from state 1 to state 2.
+
+sound2to1: the sound played when the door or platform moves from from state 2 to state 1.
+
+soundPos2: the sound played when the door or platform reaches state 2.
+
+soundPos1: the sound played when the door or platform reaches state 1.
+
+-------- Q3MAP2 KEYS --------
+_targetname: Used to attach a misc_model entity to this entity.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+
+-------- SPAWNFLAGS --------
+START_OPEN: the door will spawn in the open state and operate in reverse.
+
+CRUSHER: door will not reverse direction when blocked and will keep damaging player until he dies or gets out of the way.
+
+REVERSE: the door will open the other way.
+
+X_AXIS: rotate on the X axis instead of the Z.
+
+Y_AXIS: rotate on the Y axis instead of the Z.
+
+-------- NOTES --------
+Unlike in Quake 2, doors that touch are NOT automatically teamed. If you want doors to operate together, you have to team them manually by assigning the same team name to all of them. Setting the origin key is simply an alternate method to using an origin brush. When using the model2 key, the origin point of the model will correspond to the origin point defined by either the origin brush or the origin coordinate value.
+
+Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname").
+
+You need to have an origin brush as part of this entity. The center of that brush will be the point around which it is rotated. It will rotate around the Z axis by default. You can check either the X_AXIS or Y_AXIS box to change that.
+*/
+
+//=============================================================================
+
+/*QUAKED func_group (0 .5 .8) ?
+This is not an entity as such. It is strictly an editor utility to group world brushes and patches together for convenience (selecting, moving, copying, etc). You cannot group entities with this.
+
+-------- OLD TERRAIN KEYS (note: obsolete with Q3Map2) --------
+alphamap: this is the path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+layers: this integer value is the number unique root shaders that will be use on the terrain.
+
+shader: this is the path to the metashader used to assign textures to the terrain entity.
+
+terrain: this is an on/off flag. When set to 1, the entity becomes a terrain entity. Note: unecessary when compiling with Q3Map2. See Q3Map2 keys.
+
+-------- Q3MAP2 KEYS --------
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+
+-------- NOTES --------
+The TAB key can be used to flip through the component pieces of a selected func_group entity, isolating individual components. To make a func_group into a terrain entity, refer to the Terrain Construction documentation.
+*/
+
+//=============================================================================
+
+/*QUAKED func_pendulum (0 .5 .8) ?
+Solid entity that describes a pendulum back and forth rotation movement. Rotates on the X axis by default. Pendulum frequency is a physical constant based on the length of the beam and gravity. Blocking the pendulum instantly kills a player.
+
+-------- KEYS --------
+angle: angle offset of axis of rotation from default X axis (default 0).
+
+speed: angle of swing arc in either direction from initial position (default 30).
+
+phase: sets the start offset of the swinging cycle. Values must be 0 < phase < 1. Any integer phase value is the same as no offset (default 0).
+
+noise: path/name of .wav file to play. Use looping sounds only (eg. sound/world/drone6.wav).
+
+model2: path/name of model to include (eg: models/mapobjects/jets/jets01.md3).
+
+origin: alternate method of setting XYZ origin of entity's rotation axis and .md3 model included with entity (default "0 0 0" - See Notes).
+
+light: constantLight radius of .md3 model included with entity. Has no effect on the entity's brushes (default 0).
+
+color: constantLight color of .md3 model included with entity. Has no effect on the entity's brushes (default 1 1 1).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- Q3MAP2 KEYS --------
+_targetname: Used to attach a misc_model entity to this entity.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+
+-------- NOTES --------
+You need to have an origin brush as part of this entity. The center of that brush will be the point through which the rotation axis passes. Setting the origin key is simply an alternate method to using an origin brush. Pendulum will rotate along the X axis by default. Very crude operation: pendulum cannot rotate along Z axis, the speed of swing (frequency) is not adjustable. When using the model2 key, the origin point of the model will correspond to the origin point defined by either the origin brush or the origin coordinate value.
+
+Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname").
+*/
+
+//=============================================================================
+
+/*QUAKED func_plat (0 .5 .8) ? DONT_WAIT
+Rising platform the player can ride to reach higher places. Plats must always be drawn in the raised position, so they will operate and be lighted correctly but they spawn in the lowered position. The plat will stay in the raised position until the player steps off. There are no proper sounds for this entity, only beep noises. It will spawn in the game and work properly but it sounds silly (see Notes). If DONT_WAIT is set then the platform will not wait for a client to leave before returning to its original position.
+
+-------- KEYS --------
+speed: determines how fast the plat moves (default 150).
+
+lip: lip remaining at end of move (default 16). Has no effect if "height" is set.
+
+height: if set, this will determine the total amount of vertical travel of the plat.
+
+dmg: damage to inflict on player when he blocks operation of plat (default 4). Plat will reverse direction when blocked.
+
+targetname: if set, the trigger that points to this will raise the plat each time it fires. The plat raises and comes back down a second later if no player is on it.
+
+light: constantLight radius of .md3 model included with entity. Has no effect on the entity's brushes (default 0).
+
+color: constantLight color of .md3 model included with entity. Has no effect on the entity's brushes (default 1 1 1).
+
+model2: path/name of model to include (eg: models/mapobjects/pipe/pipe02.md3).
+
+origin: alternate method of setting XYZ origin of .md3 model included with entity (See Notes).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+sound1to2: the sound played when the door, platform or button moves from state 1 to state 2.
+
+sound2to1: the sound played when the door or platform moves from from state 2 to state 1.
+
+soundPos2: the sound played when the door or platform reaches state 2.
+
+soundPos1: the sound played when the door or platform reaches state 1.
+
+-------- Q3MAP2 KEYS --------
+_targetname: Used to attach a misc_model entity to this entity.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+
+-------- NOTES --------
+By default, the total amount of vertical travel of a platform is implicitly determined by the overall vertical size of the brushes of which it's made minus the lip value. But if the "height" key is used, then the total amount of vertical travel of the plat will be exactly that value regardless of the shape and size of the plat and regardless of the value of the "lip" key. Using the "height" key is the best method for any kind of platforms and the only possible one for thin plats which need to travel vertical distances many times their own thickness. Setting the origin key is simply an alternate method to using an origin brush. When using the model2 key, the origin point of the model will correspond to the origin point defined by either the origin brush or the origin coordinate value.
+
+There is a way to make plats play proper sounds. Just create a sound\movers\plats folder under baseq3 and put 2 sounds named pt1_strt.wav and pt1_end.wav in it. Those can be the renamed sounds from the Q2 plats or renamed copies of the sound\movers\doors sounds you can extract from your pak0.pk3 file or new custom sounds if you're up to it. Thanks to Fragzilla for the tip.
+
+Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname").
+*/
+
+//=============================================================================
+
+/*QUAKED func_rotating (0 .5 .8) ? - - X_AXIS Y_AXIS
+Solid entity that rotates continuously. Rotates on the Z axis by default and requires an origin brush. It will always start on in the game and is not targetable.
+
+-------- KEYS --------
+speed: determines how fast entity rotates (default 100).
+
+noise: path/name of .wav file to play. Use looping sounds only (eg. sound/world/drone6.wav).
+
+model2: path/name of model to include (eg: models/mapobjects/bitch/fembotbig.md3).
+
+origin: alternate method of setting XYZ origin of entity's rotation axis and .md3 model included with entity (default "0 0 0" - See Notes).
+
+light: constantLight radius of .md3 model included with entity. Has no effect on the entity's brushes (default 0).
+
+color: constantLight color of .md3 model included with entity. Has no effect on the entity's brushes (default 1 1 1).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- Q3MAP2 KEYS --------
+_targetname: Used to attach a misc_model entity to this entity.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+
+-------- SPAWNFLAGS --------
+X_AXIS: entity will rotate along the X axis.
+
+Y_AXIS: entity will rotate along the Y axis.
+
+-------- NOTES --------
+You need to have an origin brush as part of this entity. The center of that brush will be the point through which the rotation axis passes. Setting the origin key is simply an alternate method to using an origin brush. It will rotate along the Z axis by default. You can check either the X_AXIS or Y_AXIS box to change that. When using the model2 key, the origin point of the model will correspond to the origin point defined by either the origin brush or the origin coordinate value.
+
+Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname").
+*/
+
+//=============================================================================
+
+/*QUAKED func_static (0 .5 .8) ?
+Static non-solid bspmodel. Can be used for conditional walls and models.
+
+-------- KEYS --------
+model2: path/name of model to include (eg: models/mapobjects/bitch/fembotbig.md3).
+
+origin: alternate method of setting XYZ origin of .md3 model included with entity (See Notes).
+
+light: constantLight radius of .md3 model included with entity. Has no effect on the entity's brushes (default 0).
+
+color: constantLight color of .md3 model included with entity. Has no effect on the entity's brushes (default 1 1 1).
+
+targetname: NOT SUPPORTED BY RENDERER - if set, a func_button or trigger can make entity disappear from the game (See Notes).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- Q3MAP2 KEYS --------
+_targetname: Used to attach a misc_model entity to this entity.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+
+-------- NOTES --------
+When using the model2 key, the origin point of the model will correspond to the origin point defined by either the origin brush or the origin coordinate value. If a model is included with a targeted func_static, the brush(es) of the entity will be removed from the game but the .md3 model won't: it will automatically be moved to the (0 0 0) world origin so you should NOT include an .md3 model to a targeted func_static.
+
+Because the map has only a single bot navigation file, func_static's cannot be used to make significant changes in game play flow between differing game types.
+
+Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname").
+*/
+
+//=============================================================================
+
+/*QUAKED func_timer (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON
+Time delay trigger that will continuously fire its targets after a preset time delay. The time delay can also be randomized. When triggered, the timer will toggle on/off.
+
+-------- KEYS --------
+wait: delay in seconds between each triggering of its targets (default 1).
+
+random: random time variance in seconds added or subtracted from "wait" delay (default 0 - see Notes).
+
+target: this points to the entities to trigger.
+
+targetname: a func_button or trigger that points to this will toggle the timer on/off when activated.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- SPAWNFLAGS --------
+START_ON: timer will start on in the game and continuously fire its targets.
+
+-------- NOTES --------
+When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random).
+*/
+
+//=============================================================================
+
+/*QUAKED func_train (0 .5 .8) ? START_OFF BLOCK_STOPS
+Trains are moving solids that follow a string of path_corner entities. Trains in Tremulous are less basic than in Q3A, they also require an origin brush (see Notes).
+
+-------- KEYS --------
+speed: speed of displacement of train (default 100 or overridden by speed value of path).
+
+target: this points to the first path_corner of the path which is also the spawn location of the train's origin.
+
+model2: path/name of model to include (eg: models/mapobjects/pipe/pipe02.md3).
+
+origin: alternate method of setting XYZ origin of the train's brush(es) and .md3 model included with entity (See Notes).
+
+light: constantLight radius of .md3 model included with entity. Has no effect on the entity's brushes (default 0).
+
+color: constantLight color of .md3 model included with entity. Has no effect on the entity's brushes (default 1 1 1).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- SPAWNFLAGS --------
+START_OFF: the train will spawn in the off state
+
+BLOCK_STOPS: with this set a train simply stops if blocked, instead of killing.
+
+-------- Q3MAP2 KEYS --------
+_targetname: Used to attach a misc_model entity to this entity.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+
+-------- NOTES --------
+1. Trains instakill anything in their path by default.
+2. Trains cannot emit sound.
+3. When BLOCK_STOPS is set, trains cannot be stopped just by getting in their way, the player must be wedged between the train and another obstacle to block it.
+
+Setting the origin key is simply an alternate method to using an origin brush. When using the model2 key, the origin point of the model will correspond to the origin point defined by either the origin brush or the origin coordinate value.
+
+Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname").*/
+
+
+
+
+//=============================================================================
+
+INFO_* ENTITIES
+
+//=============================================================================
+
+/*QUAKED info_notnull (0 .5 0) (-8 -8 -8) (8 8 8)
+Used as a positional target for entities that can use directional pointing. A target_position can be used instead of this but was kept in Q3A for legacy purposes.
+
+-------- KEYS --------
+targetname: must match the target key of entity that uses this for pointing.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+*/
+
+
+//=============================================================================
+
+/*QUAKED info_null (0 .5 0) (-8 -8 -8) (8 8 8)
+Used as a positional target for light entities to create a spotlight effect. A target_position can be used instead of this but was kept in Q3A for legacy purposes.
+
+-------- KEYS --------
+targetname: must match the target key of entity that uses this for pointing.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+*/
+
+//=============================================================================
+
+/*QUAKED info_player_intermission (1 0 1) (-8 -8 -8) (8 8 8)
+Camera for intermission screen between matches. This also automatically generates the podium for bot arena matches (see Notes). Can be aimed by setting the "angles" key or targeting an pointing to an aiming entity. Use only one per level.
+
+-------- KEYS --------
+angles: alternate "pitch, yaw, roll" angles method of aiming intermission camera (default 0 0 0).
+
+target: point this to an info_notnull or target_position entity to set the camera's pointing angles.
+
+-------- NOTES --------
+In genuine bot arena matches, the podium for the 1st, 2nd and 3rd place players at the end of the match is generated by this entity. The podium's origin will automatically be located 128 units in the direction of the camera's view and 84 units down from the y height of the view line at that point. It will also always be generated on a level plane regardless of the pointing angle of the camera so if that angle is too steep, part of the podium model might not be visible. Make sure you leave at least 106 units of free space in front of where the camera points to otherwise the podium model won't be visible at all.
+*/
+
+//=============================================================================
+
+/*QUAKED info_alien_intermission (1 0 1) (-8 -8 -8) (8 8 8)
+Camera for aliens before they spawn. Can be aimed by setting the "angles" key or targeting an pointing to an aiming entity. Use one per level.
+
+-------- KEYS --------
+angles: alternate "pitch, yaw, roll" angles method of aiming intermission camera (default 0 0 0).
+
+target: point this to an info_notnull or target_position entity to set the camera's pointing angles.
+*/
+
+//=============================================================================
+
+/*QUAKED info_human_intermission (1 0 1) (-8 -8 -8) (8 8 8)
+Camera for humans before they spawn. Can be aimed by setting the "angles" key or targeting an pointing to an aiming entity. Use one per level.
+
+-------- KEYS --------
+angles: alternate "pitch, yaw, roll" angles method of aiming intermission camera (default 0 0 0).
+
+target: point this to an info_notnull or target_position entity to set the camera's pointing angles.
+*/
+
+
+
+//=============================================================================
+
+MISC_* ENTITIES
+
+//=============================================================================
+
+/*QUAKED misc_model (1 .5 .25) (-16 -16 -16) (16 16 16)
+Generic placeholder for inserting MD3 models in game. Requires compilation of map geometry to be added to level. If the map is compiled with Q3Map2, then ASE, 3DS, OBJ and other model formats are supported.
+
+-------- KEYS --------
+angle: direction in which model will be oriented.
+
+model: path/name of model to use (eg: models/mapobjects/teleporter/teleporter.md3).
+
+-------- Q3MAP2 KEYS --------
+angles: Individual control of PITCH, YAW, and ROLL (default 0 0 0).
+
+modelscale: Floating-point value used to scale a model up or down (default 1.0).
+
+modelscale_vec: Floating-point vector used to scale a model's axes individually (default 1.0 1.0 1.0).
+
+_remap: Used to remap textures/shaders in the model. To remap all shaders to a given shader, use "*;models/mymodel/mytexture". To remap a specific shader, use "models/mymodel/old;models/mymodel/new".
+
+target: Used to attach the misc_model to a brush entity, where its "targetname" key is the same value.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on this model (if model is using lightmapped shaders) (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix.
+*/
+
+//=============================================================================
+
+/*QUAKED misc_anim_model (1 .5 .25) (-16 -16 -16) (16 16 16) TRIGGER_TOGGLE
+A little like misc_model except that it is a game entity and does not become part of the map geometry. An instance of this entity will draw an arbituary md3 in the world with an arbituary frame or with an animation.
+
+-------- KEYS --------
+angle: direction in which model will be oriented.
+
+radius: The scale of the model compared to its original size. Defaults to 1.0.
+
+animation: The guts of the entity. This is identical to an entry in an animation.cfg - Start Frame, Number of frames, Looping Frames, Frame rate. For example 0 30 30 20 will play frames 0 through 30 continously at 20 fps.
+
+model: path/name of model to use (eg: models/mapobjects/teleporter/teleporter.md3).
+
+-------- SPAWNFLAGS --------
+TRIGGER_TOGGLE: With this set triggering the entity disables the model altogether as opposed to the regular behaviour of toggling the animation.
+*/
+
+//=============================================================================
+
+/*QUAKED misc_particle_system (1 .5 .25) (-8 -8 -8) (8 8 8) SPAWN_DISABLED
+A particle system entity.
+
+-------- KEYS --------
+psName: The name of the particle system to spawn at this entity.
+
+-------- SPAWNFLAGS --------
+SPAWN_DISABLED: Spawn disabled.
+
+-------- NOTES --------
+Triggering this entity toggles it on and off.
+*/
+
+//=============================================================================
+/*QUAKED misc_light_flare (.65 .65 1) (-8 -8 -8) (8 8 8) SPAWN_DISABLED
+A light flare entity.
+
+-------- KEYS --------
+targetShaderName: The name of the shader of the light flare.
+
+radius: The radius key is a vector.
+The first component is the size of the light flare. The radius is calculated by taking the distance of the viewer from the light flare and dividing by this key, so the larger the key value, the smaller the flare. Values between 2 and 10 are sensible.
+The second component indicates the angle around the direction the flare points for which it is visible. For example a value of 90 means that you can see the flare while infront of the entity, but not when behind it. If set to zero the light flare will be visible from any angle
+The third component is similar to the first except that it specifies the size of the light source rather than the size of the light flare itself. This is useful when the higher detail flare fading modes are enabled. If this is set to the same value as the first component, fading will commence as soon as the edge of the light flare is occluded by some surface between the viewer and the flare. If it is set larger the flare will overlap the occluding surface before it begins to fade.
+
+angles: This reflects which direction the flare points. It is not important unless the second component of the radius key is employed. angles is a vector of PITCH YAW ROLL. For example a value of "90 0 0" would create a flare pointing down. ROLL is redundant in this context and can be set arbitrarily.
+
+-------- SPAWNFLAGS --------
+SPAWN_DISABLED: Spawn disabled.
+
+-------- NOTES --------
+Triggering this entity toggles it.
+*/
+
+//=============================================================================
+
+/*QUAKED misc_portal_camera (1 .5 .25) (-8 -8 -8) (8 8 8) SLOWROTATE FASTROTATE
+Portal camera. This camera is used to project its view onto a portal surface in the level through the intermediary of a misc_portal_surface entity. Use the "angles" key or target a target_position or info_notnull entity to set the camera's pointing direction.
+
+-------- KEYS --------
+angles: this sets the pitch and yaw aiming angles of the portal camera (default 0 0). Use "roll" key to set roll angle.
+
+target: point this to a target_position entity to set the camera's pointing direction.
+
+targetname: a misc_portal_surface portal surface indicator must point to this.
+
+roll: roll angle of camera. A value of 0 is upside down and 180 is the same as the player's view.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- SPAWNFLAGS --------
+SLOWROTATE: makes the portal camera rotate slowly along the roll axis.
+
+FASTROTATE: makes the portal camera rotate faster along the roll axis.
+
+NOROTATE: no rolling at all.
+
+-------- NOTES --------
+Both the setting "angles" key or "targeting a target_position" methods can be used to aim the camera. However, the target_position method is simpler. In both cases, the "roll" key must be used to set the roll angle.
+*/
+
+//=============================================================================
+
+/*QUAKED misc_portal_surface (1 .5 .25) (-8 -8 -8) (8 8 8)
+Portal surface indicator. This will "lock on" the brush face closest to it and identify as a portal. The view displayed on the portal surface is the view of the misc_portal_camera that this entity targets. Also used for mirrors (see Notes).
+
+-------- KEYS --------
+target: point this to a misc_portal_camera that "sees" the view you want to display on the portal.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- NOTES --------
+The entity must be no farther than 64 units away from the portal surface to lock onto it. To make a mirror, apply the common/mirror shader to the surface, place this entity near it but don't target a misc_portal_camera.
+*/
+
+//=============================================================================
+
+/*QUAKED misc_teleporter_dest (1 .5 .25) (-32 -32 -24) (32 32 -16)
+Teleport destination location point for trigger_teleporter entities.
+
+-------- KEYS --------
+angle: direction in which player will look when teleported.
+
+targetname: make the trigger_teleporter point to this.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+*/
+
+/*QUAKED trigger_teleport (.5 .5 .5) ? SPECTATOR SPAWN_DISABLED
+Allows client side prediction of teleportation events.
+Must point at a target_position, which will be the teleport destination.
+
+If spectator is set, only spectators can use this teleport
+Spectator teleporters are not normally placed in the editor, but are created
+automatically near doors to allow spectators to move through them
+*/
+
+
+
+//=============================================================================
+
+PATH_* ENTITIES
+
+//=============================================================================
+
+/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8)
+Path corner entity that func_trains can be made to follow.
+
+-------- KEYS --------
+target: point to next path_corner in the path.
+
+targetname: the train following the path or the previous path_corner in the path points to this.
+
+speed: speed of func_train while moving to the next path corner. This will override the speed value of the train.
+
+wait: number of seconds func_train will pause on path corner before moving to next path corner (default 0 - see Notes).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- NOTES --------
+Setting the wait key to -1 will not make the train stop on the path corner, it will simply default to 0.
+*/
+
+
+
+//=============================================================================
+
+TARGET_* ENTITIES
+
+//=============================================================================
+
+/*QUAKED target_hurt (1 0 0) (-8 -8 -8) (8 8 8)
+When triggered, this hurts the entity that caused the trigger.
+
+-------- KEYS --------
+dmg: amount of damage to deal (default: 5)
+*/
+
+/*QUAKED target_rumble (1 0 0) (-8 -8 -8) (8 8 8)
+When triggered, this initiates a level-wide rumble effect. All players are affected.
+
+-------- KEYS --------
+speed: severity of the quake (default: 100)
+
+count: duration of the quake (default: 10)
+*/
+
+/*QUAKED target_alien_win (1 0 0) (-8 -8 -8) (8 8 8)
+When triggered, this causes an unconditional win for the alien team.
+*/
+
+/*QUAKED target_human_win (1 0 0) (-8 -8 -8) (8 8 8)
+When triggered, this causes an unconditional win for the human team.
+*/
+
+/*QUAKED target_delay (0 .7 .7) (-8 -8 -8) (8 8 8)
+Time delay trigger intermediary. Like a target_relay, this can only be fired by other triggers which will cause it in turn to fire its own targets.
+
+-------- KEYS --------
+targetname: activating trigger points to this.
+
+target: this points to entities to activate when this entity is triggered.
+
+wait: delay in seconds from when this gets triggered to when it fires its own targets (default approx. 1).
+
+delay: same as wait? replaces it? WTF?...I'm confused now.
+
+random: random time variance in seconds added or subtracted from "wait" delay (default 0 - see Notes).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- NOTES --------
+When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random).
+*/
+
+//=============================================================================
+
+/*QUAKED target_kill (0 .5 0) (-8 -8 -8) (8 8 8)
+This will kill the player who activates the trigger that fires this target.
+
+-------- KEYS --------
+targetname: the activating trigger points to this.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+*/
+
+//=============================================================================
+
+/*QUAKED target_location (0 .5 0) (-8 -8 -8) (8 8 8)
+Location marker used by bots and players for team orders and team chat in the course of Teamplay games. The closest target_location in sight is used for the location. If none is in sight, the closest in distance is used.
+
+-------- KEYS --------
+message: name of the location (text string). Displayed in parentheses in front of all team chat and order messages.
+
+count: color of the location text displayed in parentheses during team chat. Set to 0-7 for color.
+ 0: white (default)
+ 1: red
+ 2: green
+ 3: yellow
+ 4: blue
+ 5: cyan
+ 6: magenta
+ 7: white
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+*/
+
+//=============================================================================
+
+/*QUAKED target_position (0 .5 0) (-8 -8 -8) (8 8 8)
+Aiming target for entities like light, misc_portal_camera and trigger_push (jump pads) in particular.
+
+-------- KEYS --------
+targetname: the entity that requires an aiming direction points to this.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- NOTES --------
+To make a jump pad, place this entity at the highest point of the jump and target it with a trigger_push entity.
+*/
+
+//=============================================================================
+
+/*QUAKED target_print (0 .5 0) (-8 -8 -8) (8 8 8) HUMAN_TEAM ALIEN_TEAM PRIVATE
+This will print a message on the center of the screen when triggered. By default, all the clients will see the message.
+
+-------- KEYS --------
+message: text string to print on screen.
+
+targetname: the activating trigger points to this.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- SPAWNFLAGS --------
+HUMAN_TEAM: only the human team players will see the message.
+ALIEN_TEAM: only the alien team players will see the message.
+PRIVATE: only the player that activates the target will see the message.
+*/
+
+//=============================================================================
+
+/*QUAKED target_push (.5 .5 .5) (-8 -8 -8) (8 8 8) BOUNCEPAD NOSOUND
+This can be used to create jump pads and launch ramps. The direction of push can be set by the "angles" key or pointing to a target_position or info_notnull entity. Unlike trigger_push, this is NOT client side predicted and must be activated by a trigger.
+
+-------- KEYS --------
+angles: this sets the pitch and yaw aiming angles of push entity (default 0 0). The roll angle does not apply.
+
+speed: speed of push (default 1000). Has no effect if entity targets an aiming entity.
+
+targetname: the activating trigger points to this. Push originates from the location of the trigger.
+
+target: this points to the aiming entity to which the player will jump.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- SPAWNFLAGS --------
+BOUNCEPAD: if set, trigger will play bounce noise instead of beep noise when activated (recommended).
+NOSOUND: if set, no sound is played at all
+
+-------- NOTES --------
+To make a jump pad or launch ramp, create a trigger_multiple where the jump must originate. Place the target_push directly above the trigger_multiple and place the target_position entity at the highest point of the jump. Target the trigger_multiple to the target_push and target the target_push to the target_position/info_notnull (or set the target_push's "angles" key). Note that the "angle" key also works.
+*/
+
+//=============================================================================
+
+/*QUAKED target_relay (0 .7 .7) (-8 -8 -8) (8 8 8) HUMAN_ONLY ALIEN_ONLY RANDOM
+This can only be activated by other triggers which will cause it in turn to activate its own targets.
+
+-------- KEYS --------
+targetname: activating trigger points to this.
+
+target: this points to entities to activate when this entity is triggered.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- SPAWNFLAGS --------
+HUMAN_ONLY: only human team players can activate trigger.
+ALIEN_ONLY: only alien team players can activate trigger.
+RANDOM: one one of the targeted entities will be triggered at random.
+*/
+
+//=============================================================================
+
+/*QUAKED target_score (0 .5 0) (-8 -8 -8) (8 8 8)
+This is used to automatically give frag points to the player who activates this. A spawn location entity like info_player_* or CTF respawn points can target this entity to give points to the player when he spawns in the game. Or a trigger can also be used to activate this. The activator of the trigger will get the points.
+
+-------- KEYS --------
+targetname: ativating entity points to this.
+
+count: number of frag points to give to player (default 1).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+*/
+
+//=============================================================================
+
+/*QUAKED target_speaker (0 .7 .7) (-8 -8 -8) (8 8 8) LOOPED_ON LOOPED_OFF GLOBAL ACTIVATOR
+Sound generating entity that plays .wav files. Normal non-looping sounds play each time the target_speaker is triggered. Looping sounds can be set to play by themselves (no activating trigger) or be toggled on/off by a trigger.
+
+-------- KEYS --------
+noise: path/name of .wav file to play (eg. sound/world/growl1.wav - see Notes).
+
+wait: delay in seconds between each time the sound is played ("random" key must be set - see Notes).
+
+random: random time variance in seconds added or subtracted from "wait" delay ("wait" key must be set - see Notes).
+
+targetname: the activating button or trigger points to this.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- SPAWNFLAGS --------
+LOOPED_ON: sound will loop and initially start on in level (will toggle on/off when triggered).
+
+LOOPED_OFF: sound will loop and initially start off in level (will toggle on/off when triggered).
+
+GLOBAL: sound will play full volume throughout the level.
+
+ACTIVATOR: sound will play only for the player that activated the target.
+
+-------- NOTES --------
+The path portion value of the "noise" key can be replaced by the implicit folder character "*" for triggered sounds that belong to a particular player model. For example, if you want to create a "bottomless pit" in which the player screams and dies when he falls into, you would place a trigger_multiple over the floor of the pit and target a target_speaker with it. Then, you would set the "noise" key to "*falling1.wav". The * character means the current player model's sound folder. So if your current player model is Visor, * = sound/player/visor, if your current player model is Sarge, * = sound/player/sarge, etc. This cool feature provides an excellent way to create "player-specific" triggered sounds in your levels.
+
+The combination of the "wait" and "random" keys can be used to play non-looping sounds without requiring an activating trigger but both keys must be used together. The value of the "random" key is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random).
+*/
+
+//=============================================================================
+
+/*QUAKED target_teleporter (0 .5 0) (-8 -8 -8) (8 8 8)
+Activating this will teleport players to the location of the targeted misc_teleporter_dest entity. Unlike trigger_teleport, this entity must be activated by a trigger and does NOT allow client prediction of events.
+
+-------- KEYS --------
+targetname: activating trigger points to this.
+
+target: this must point to a misc_teleporter_dest entity.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+*/
+
+
+
+
+//=============================================================================
+
+TEAM_* ENTITIES
+
+//=============================================================================
+
+/*QUAKED team_human_spawn (0 .2 1) (-40 -40 -4) (40 40 4)
+The human spawn point.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/telenode/telenode.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_human_armoury (0 .2 1) (-40 -40 -13) (40 40 50)
+The human armoury.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/arm/arm.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_human_dcc (0 .2 1) (-35 -35 -13) (35 35 47)
+The human defense computer.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/dcc/dcc.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_human_medistat (0 .2 1) (-35 -35 -7) (35 35 7)
+The human medical station.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/medistat/medistat.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_human_mgturret (0 .2 1) (-25 -25 -20) (25 25 20)
+The human machinegun turret.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/mgturret/turret_base.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_human_reactor (0 .2 1) (-50 -50 -15) (50 50 95)
+The human reactor.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/reactor/reactor.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_human_repeater (0 .2 1) (-15 -15 -15) (15 15 25)
+The human repeater.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/repeater/repeater.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_human_tesla (0 .2 1) (-22 -22 -40) (22 22 40)
+The human tesla generator.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/tesla/tesla.md3"
+*/
+
+//=============================================================================
+
+
+
+/*QUAKED team_alien_spawn (1 .2 0) (-15 -15 -15) (15 15 15)
+The alien spawn point.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/eggpod/eggpod.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_alien_acid_tube (1 .2 0) (-35 -35 -11) (35 35 40)
+The alien acid tube.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/acid_tube/acid_tube.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_alien_barricade (1 .2 0) (-35 -35 -15) (35 35 60)
+The alien barricade.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/barricade/barricade.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_alien_booster (1 .2 0) (-26 -26 -9) (26 26 9)
+The alien booster.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/booster/booster.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_alien_hovel (1 .2 0) (-50 -50 -20) (50 50 20)
+The alien hovel.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/hovel/hovel.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_alien_overmind (1 .2 0) (-45 -45 -15) (45 45 95)
+The alien overmind.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/overmind/overmind.md3"
+*/
+
+//=============================================================================
+
+/*QUAKED team_alien_trapper (1 .2 0) (-15 -15 -15) (15 15 15)
+The alien trapper.
+
+-------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
+model="models/buildables/trapper/trapper.md3"
+*/
+
+//=============================================================================
+
+
+
+//=============================================================================
+
+TRIGGER_* ENTITIES
+
+//=============================================================================
+
+/*QUAKED trigger_heal (.5 .5 .5) ? START_OFF SLOW
+Any player that touches this will be healed. It does heal points of healage each server frame. Targeting the trigger will toggle its effects.
+
+-------- SPAWNFLAGS --------
+START_OFF: needs to be triggered (toggle) to activate.
+
+SLOW: changes the heal rate to once per second.
+
+-------- KEYS --------
+heal: Health points to heal (default 5)
+*/
+
+/*QUAKED trigger_ammo (.5 .5 .5) ? SLOW NOENERGY NOCASE
+Any player that touches this will have the ammo for his held weapon restored. It gives ammo in chunks reflected by the key "ammo" each server frame.
+
+-------- SPAWNFLAGS --------
+SLOW: changes the ammo rate to once per second.
+
+NOENERGY: disables this entity for energy weapons.
+
+NOCASE: disables this entity for case based weapons.
+
+-------- KEYS --------
+ammo: Amount of ammo to give (default 1)
+*/
+
+/*QUAKED trigger_gravity (.5 .5 .5) ?
+The gravity (for players) within this trigger is determined by the gravity key. Targetting this entity toggles its effects.
+NOT THROUGHLY TESTED: please report whether or not this works for you.
+
+-------- KEYS --------
+gravity: The gravity within this trigger (default 800).
+*/
+
+/*QUAKED trigger_buildable (.5 .5 .5) ? SPAWN_DISABLED NEGATE
+Triggered by a buildable or subset of buildables. If no buildables key is supplied every buildable will trigger this entity.
+Targetting this entity toggles it.
+NOT THROUGHLY TESTED: please report whether or not this works for you.
+
+-------- SPAWNFLAGS --------
+SPAWN_DISABLED: needs to be triggered (toggle) to activate.
+NEGATE: negate the trigger condition.
+
+-------- KEYS --------
+target: this points to the entity to activate.
+
+buildables: a comma delimited list of buildables which will trigger this entity.
+
+wait: time in seconds until trigger becomes re-triggerable after it's been touched (default 0.2, -1 = trigger once).
+
+random: random time variance in seconds added or subtracted from "wait" delay (default 0 - see Notes).
+*/
+
+/*QUAKED trigger_class (.5 .5 .5) ? SPAWN_DISABLED NEGATE
+Triggered by a specific class or subset of classes. If no classes key is supplied every class will trigger this entity.
+Targetting this entity toggles it.
+NOT THROUGHLY TESTED: please report whether or not this works for you.
+
+-------- SPAWNFLAGS --------
+SPAWN_DISABLED: needs to be triggered (toggle) to activate.
+NEGATE: negate the trigger condition.
+
+-------- KEYS --------
+target: this points to the entity to activate.
+
+classes: a comma delimited list of classes which will trigger this entity.
+
+wait: time in seconds until trigger becomes re-triggerable after it's been touched (default 0.2, -1 = trigger once).
+
+random: random time variance in seconds added or subtracted from "wait" delay (default 0 - see Notes).
+*/
+
+/*QUAKED trigger_equipment (.5 .5 .5) ? SPAWN_DISABLED NEGATE
+Triggered by a player carrying some item (weapon or upgrade) or subset of items. If no equipment key is supplied every human will trigger this entity.
+Targetting this entity toggles it.
+NOT THROUGHLY TESTED: please report whether or not this works for you.
+
+-------- SPAWNFLAGS --------
+SPAWN_DISABLED: needs to be triggered (toggle) to activate.
+NEGATE: negate the trigger condition.
+
+-------- KEYS --------
+target: this points to the entity to activate.
+
+equipment: a comma delimited list of equipment which will trigger this entity.
+
+wait: time in seconds until trigger becomes re-triggerable after it's been touched (default 0.2, -1 = trigger once).
+
+random: random time variance in seconds added or subtracted from "wait" delay (default 0 - see Notes).
+*/
+
+//=============================================================================
+
+/*QUAKED trigger_stage (.5 .5 .5) (-8 -8 -8) (8 8 8)
+Fires its targets when the team key reaches stage key.
+
+-------- KEYS --------
+target: this points to the entity to activate.
+
+team: the team which triggers this entity; 1 for aliens, 2 for humans
+
+stage: the stage at which this entity is triggered; 1 for stage 2, 2 for stage 3
+*/
+
+//=============================================================================
+
+/*QUAKED trigger_win (.5 .5 .5) (-8 -8 -8) (8 8 8)
+Fires its targets when the team key wins.
+
+-------- KEYS --------
+target: this points to the entity to activate.
+
+team: the team which triggers this entity; 1 for aliens, 2 for humans
+*/
+
+//=============================================================================
+
+/*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
+Automatic trigger. It will fire the entities it targets as soon as it spawns in the game.
+
+-------- KEYS --------
+target: this points to the entity to activate.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+*/
+
+//=============================================================================
+
+/*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF - SILENT NO_PROTECTION SLOW
+Any player that touches this will be hurt by "dmg" points of damage once per server frame (very fast). A sizzling sound is also played while the player is being hurt.
+
+-------- KEYS --------
+dmg: number of points of damage inflicted to player per server frame (default 5 - integer values only).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- SPAWNFLAGS --------
+START_OFF needs to be triggered (toggle) for damage
+
+SILENT: supresses the sizzling sound while player is being hurt.
+
+NO_PROTECTION: player will be hurt regardless of protection (see Notes).
+
+SLOW: changes the damage rate to once per second.
+
+-------- NOTES --------
+The invulnerability power-up (item_enviro) does not protect the player from damage caused by this entity regardless of whether the NO_PROTECTION spawnflag is set or not. Triggering a trigger_hurt will have no effect if the START_OFF spawnflag is not set. A trigger_hurt always starts on in the game.
+*/
+
+//=============================================================================
+
+/*QUAKED trigger_multiple (.5 .5 .5) ?
+Variable size repeatable trigger. It will fire the entities it targets when touched by player. Can be made to operate like a trigger_once entity by setting the "wait" key to -1. It can also be activated by another trigger that targets it.
+
+-------- KEYS --------
+target: this points to the entity to activate.
+
+targetname: activating trigger points to this.
+
+wait: time in seconds until trigger becomes re-triggerable after it's been touched (default 0.2, -1 = trigger once).
+
+random: random time variance in seconds added or subtracted from "wait" delay (default 0 - see Notes).
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- NOTES --------
+When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random).
+*/
+
+//=============================================================================
+
+/*QUAKED trigger_push (.5 .5 .5) ?
+This is used to create jump pads and launch ramps. It MUST point to a target_position or info_notnull entity to work. Unlike target_push, this is client side predicted.
+
+-------- KEYS --------
+target: this points to the target_position to which the player will jump.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+
+-------- NOTES --------
+To make a jump pad or launch ramp, place the target_position/info_notnull entity at the highest point of the jump and target it with this entity.
+*/
+
+//=============================================================================
+
+/*QUAKED trigger_teleport (.5 .5 .5) ?
+Touching this will teleport players to the location of the targeted misc_teleporter_dest entity. This entity allows client prediction of events.
+
+-------- KEYS --------
+target: this must point to a misc_teleporter_dest entity.
+
+notfree: when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
+
+notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
+
+notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode).
+*/
+
+
+
+//=============================================================================
+
+WORLDSPAWN ENTITY
+
+//=============================================================================
+
+/*QUAKED worldspawn (0 0 0) ?
+Only used for the world.
+-------- KEYS --------
+message: text to print at user logon. Used for name of level.
+
+music: path/name of looping .wav file used for level's music (eg. music/sonic5.wav).
+
+humanBuildPoints: The maximum amount of power the humans can use. Defaults to 1000.
+
+humanMaxStage: The highest stage the humans are allowed to use [0/1/2]. Defaults to 2.
+humanStage2Threshold: The number of kills the humans must aquire to advance to stage 2. Defaults to 50.
+humanStage3Threshold: The number of kills the humans must aquire to advance to stage 3. Defaults to 100.
+
+alienBuildPoints: The maximum amount of sentience available to the overmind. Defaults to 1000.
+
+alienMaxStage: The highest stage the aliens are allowed to use [0/1/2]. Defaults to 2.
+alienStage2Threshold: The number of kills the aliens must aquire to advance to stage 2. Defaults to 50.
+alienStage3Threshold: The number of kills the aliens must aquire to advance to stage 3. Defaults to 100.
+
+disabledEquipment: A comma delimited list of human weapons or upgrades to disable for this map.
+disabledClasses: A comma delimited list of alien classes to disable for this map.
+disabledBuildables: A comma delimited list of buildables to disable for this map.
+
+_ambient OR ambient: Adds a constant value to overall lighting. Use is not recommended. Ambient light will have a tendency to flatten out variations in light and shade.
+
+_color: RGB value for ambient light color (default is 0 0 0).
+
+gravity: gravity of level (default is normal gravity: 800).
+
+gridsize: granularity of the lightgrid created by q3map. Value is three integers separated by spaces, representing number of units between grid points in X Y Z. Default gridsize value is 128 128 256. Use larger powers of 2 to reduce BSP size and compile time on very large maps.
+
+_blocksize: q3map always splits the BSP tree along the planes X=_blocksize*n and Y=_blocksize*n. Default _blocksize value is 1024. Increase the blocksize using larger powers of 2 to reduce compile times on very large maps with a low structural brush density.
+
+-------- Q3MAP2 KEYS --------
+_minlight: Minimum light value, levelwide. Uses the _color key to set color. Does not add unlike ambient.
+
+_minvertexlight: Minimum vertex lighting, levelwide.
+
+_mingridlight: Minimum lightgrid (dynamic entity lighting) levelwide.
+
+_keeplights: Keep light entities in the BSP. Normally stripped out by the BSP process and read from the .map file by the lighting phase.
+
+_noshadersun: Ignore q3map_sun/sun directives in sky shaders and ONLY use entity sun lights.
+
+_farplanedist: Limit on how many units the vis phase of compilation can see. Used in combination with level-wide fog, it can help reduce r_speeds on large, open maps.
+
+_foghull: Shader to use for "fog hull." Foghull shader should be a sky shader. Omit the "textures/" prefix.
+
+_lightmapscale: Floating point value scaling the resolution of lightmaps on brushes/patches in the world. Can be overridden in func_group (or other entities) (default 1.0).
+
+_cs OR _castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world.
+
+_rs OR _receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities.
+
+_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix. Overridable in entities.
+
+-------- Q3MAP2 TERRAIN KEYS --------
+_indexmap OR alphamap: Path/name for the art file used to guide the mapping of textures on the terrain surface.
+
+_layers OR layers: Integer value is the number unique root shaders that will be use on the terrain.
+
+_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
+*/
+
diff --git a/misc/last-merged-ioq3-revision b/misc/last-merged-ioq3-revision
new file mode 100644
index 0000000..c8946f2
--- /dev/null
+++ b/misc/last-merged-ioq3-revision
@@ -0,0 +1 @@
+c5c01e771a2eb01d5c6bc994fff272bf2469fb26
diff --git a/misc/make-macosx-ub.sh b/misc/make-macosx-ub.sh
new file mode 100644
index 0000000..08bd994
--- /dev/null
+++ b/misc/make-macosx-ub.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+CC=gcc-4.0
+
+cd `dirname $0`
+if [ ! -f Makefile ]; then
+ echo "This script must be run from the Tremulous build directory";
+ exit 1
+fi
+
+# we want to use the oldest available SDK for max compatiblity. However 10.4 and older
+# can not build 64bit binaries, making 10.5 the minimum version. This has been tested
+# with xcode 3.1 (xcode31_2199_developerdvd.dmg). It contains the 10.5 SDK and a decent
+# enough gcc to actually compile Tremulous
+# For PPC macs, G4's or better are required to run Tremulous.
+
+unset X86_64_SDK
+unset X86_64_CFLAGS
+unset X86_64_LDFLAGS
+unset X86_SDK
+unset X86_CFLAGS
+unset X86_LDFLAGS
+unset PPC_64_SDK
+unset PPC_CFLAGS
+unset PPC_LDFLAGS
+
+if [ -d /Developer/SDKs/MacOSX10.5.sdk ]; then
+ X86_64_SDK=/Developer/SDKs/MacOSX10.5.sdk
+ X86_64_CFLAGS="-arch x86_64 -isysroot /Developer/SDKs/MacOSX10.5.sdk \
+ -DMAC_OS_X_VERSION_MIN_REQUIRED=1050"
+ X86_64_LDFLAGS=" -mmacosx-version-min=10.5"
+
+ X86_SDK=/Developer/SDKs/MacOSX10.5.sdk
+ X86_CFLAGS="-arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk \
+ -DMAC_OS_X_VERSION_MIN_REQUIRED=1050"
+ X86_LDFLAGS=" -mmacosx-version-min=10.5"
+
+ PPC_SDK=/Developer/SDKs/MacOSX10.5.sdk
+ PPC_CFLAGS="-arch ppc -isysroot /Developer/SDKs/MacOSX10.5.sdk \
+ -DMAC_OS_X_VERSION_MIN_REQUIRED=1050"
+ PPC_LDFLAGS=" -mmacosx-version-min=10.5"
+fi
+
+if [ -z $X86_64_SDK ] || [ -z $X86_SDK ] || [ -z $PPC_SDK ]; then
+ echo "\
+ERROR: This script is for building a Universal Binary. You cannot build
+ for a different architecture unless you have the proper Mac OS X SDKs
+ installed. If you just want to to compile for your own system run
+ 'make-macosx.sh' instead of this script."
+ exit 1
+fi
+
+echo "Building X86_64 Client/Dedicated Server against \"$X86_64_SDK\""
+echo "Building X86 Client/Dedicated Server against \"$X86_SDK\""
+echo "Building PPC Client/Dedicated Server against \"$PPC_SDK\""
+echo
+
+if [ "$X86_64_SDK" != "/Developer/SDKs/MacOSX10.5.sdk" ] || \
+ [ "$X86_SDK" != "/Developer/SDKs/MacOSX10.5.sdk" ]; then
+ echo "\
+WARNING: in order to build a binary with maximum compatibility you must
+ build on Mac OS X 10.5 using Xcode 3.1 and have the MacOSX10.5
+ SDKs installed from the Xcode install disk Packages folder."
+sleep 3
+fi
+
+# For parallel make on multicore boxes...
+NCPU=`sysctl -n hw.ncpu`
+
+# x86_64 client and server
+#if [ -d build/release-release-x86_64 ]; then
+# rm -r build/release-darwin-x86_64
+#fi
+(ARCH=x86_64 CC=gcc-4.0 CFLAGS=$X86_64_CFLAGS LDFLAGS=$X86_64_LDFLAGS make -j$NCPU) || exit 1;
+
+echo;echo
+
+# x86 client and server
+#if [ -d build/release-darwin-x86 ]; then
+# rm -r build/release-darwin-x86
+#fi
+(ARCH=x86 CC=gcc-4.0 CFLAGS=$X86_CFLAGS LDFLAGS=$X86_LDFLAGS make -j$NCPU) || exit 1;
+
+echo;echo
+
+# PPC client and server
+#if [ -d build/release-darwin-ppc ]; then
+# rm -r build/release-darwin-ppc
+#fi
+(ARCH=ppc CC=gcc-4.0 CFLAGS=$PPC_CFLAGS LDFLAGS=$PPC_LDFLAGS make -j$NCPU) || exit 1;
+
+echo
+
+# use the following shell script to build a universal application bundle
+"./make-macosx-app.sh" release
diff --git a/misc/make-macosx.sh b/misc/make-macosx.sh
new file mode 100644
index 0000000..7d48736
--- /dev/null
+++ b/misc/make-macosx.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+#
+
+# Let's make the user give us a target build system
+
+if [ $# -ne 1 ]; then
+ echo "Usage: $0 target_architecture"
+ echo "Example: $0 x86"
+ echo "other valid options are x86_64 or ppc"
+ echo
+ echo "If you don't know or care about architectures please consider using make-macosx-ub.sh instead of this script."
+ exit 1
+fi
+
+if [ "$1" == "x86" ]; then
+ BUILDARCH=x86
+ DARWIN_GCC_ARCH=i386
+elif [ "$1" == "x86_64" ]; then
+ BUILDARCH=x86_64
+elif [ "$1" == "ppc" ]; then
+ BUILDARCH=ppc
+else
+ echo "Invalid architecture: $1"
+ echo "Valid architectures are x86, x86_64 or ppc"
+ exit 1
+fi
+
+if [ -z "$DARWIN_GCC_ARCH" ]; then
+ DARWIN_GCC_ARCH=${BUILDARCH}
+fi
+
+CC=gcc-4.0
+DESTDIR=build/release-darwin-${BUILDARCH}
+
+cd `dirname $0`
+if [ ! -f Makefile ]; then
+ echo "This script must be run from the Tremulous build directory"
+ exit 1
+fi
+
+# we want to use the oldest available SDK for max compatiblity. However 10.4 and older
+# can not build 64bit binaries, making 10.5 the minimum version. This has been tested
+# with xcode 3.1 (xcode31_2199_developerdvd.dmg). It contains the 10.5 SDK and a decent
+# enough gcc to actually compile Tremulous
+# For PPC macs, G4's or better are required to run Tremulous.
+
+unset ARCH_SDK
+unset ARCH_CFLAGS
+unset ARCH_LDFLAGS
+
+if [ -d /Developer/SDKs/MacOSX10.5.sdk ]; then
+ ARCH_SDK=/Developer/SDKs/MacOSX10.5.sdk
+ ARCH_CFLAGS="-arch ${DARWIN_GCC_ARCH} -isysroot /Developer/SDKs/MacOSX10.5.sdk \
+ -DMAC_OS_X_VERSION_MIN_REQUIRED=1050"
+ ARCH_LDFLAGS=" -mmacosx-version-min=10.5"
+fi
+
+
+echo "Building ${BUILDARCH} Client/Dedicated Server against \"$ARCH_SDK\""
+sleep 3
+
+if [ ! -d $DESTDIR ]; then
+ mkdir -p $DESTDIR
+fi
+
+# For parallel make on multicore boxes...
+NCPU=`sysctl -n hw.ncpu`
+
+
+# intel client and server
+#if [ -d build/release-darwin-${BUILDARCH} ]; then
+# rm -r build/release-darwin-${BUILDARCH}
+#fi
+(ARCH=${BUILDARCH} CFLAGS=$ARCH_CFLAGS LDFLAGS=$ARCH_LDFLAGS make -j$NCPU) || exit 1;
+
+# use the following shell script to build an application bundle
+"./make-macosx-app.sh" release ${BUILDARCH}
diff --git a/misc/manual.lyx b/misc/manual.lyx
new file mode 100644
index 0000000..fbb930e
--- /dev/null
+++ b/misc/manual.lyx
@@ -0,0 +1,8376 @@
+#LyX 1.3 created this file. For more info see http://www.lyx.org/
+\lyxformat 221
+\textclass article
+\language english
+\inputencoding auto
+\fontscheme pslatex
+\graphics default
+\paperfontsize default
+\spacing single
+\papersize a4paper
+\paperpackage a4
+\use_geometry 1
+\use_amsmath 0
+\use_natbib 0
+\use_numerical_citations 0
+\paperorientation portrait
+\leftmargin 2cm
+\topmargin 2cm
+\rightmargin 2cm
+\bottommargin 2cm
+\secnumdepth 3
+\tocdepth 3
+\paragraph_separation skip
+\defskip medskip
+\quotes_language english
+\quotes_times 2
+\papercolumns 1
+\papersides 1
+\paperpagestyle empty
+
+\layout Title
+
+TREMULOUS 1.1.0
+\layout Standard
+
+
+\begin_inset LatexCommand \tableofcontents{}
+
+\end_inset
+
+
+\layout Section
+
+Introduction
+\layout Standard
+
+Tremulous is a first person shooter featuring two opposing teams, humans
+ and aliens.
+ Both teams are able to build structures such as spawn points, which are
+ vital to their victory.
+ The goal of Tremulous is to eliminate the opposing team and all of their
+ spawn points.
+\layout Standard
+
+Each team in Tremulous differs fundamentally from the other.
+ The aliens are class based, with two classes initially available: the alien
+ team's builder, known as the Granger, and the Dretch, the weakest offensive
+ alien.
+ The aliens are awarded frags for killing their foes which may be used to
+ evolve into stronger classes, capable of greater and more varied maneuvers.
+ In contrast the human team is upgrade based, receiving credits for kills
+ that may be exchanged at an Armoury structure for new weapons, armour and
+ equipment.
+ Two such upgrades are available for free: a rifle and a construction kit,
+ used for building structures.
+\layout Standard
+
+During a game of Tremulous, each team occupies one of three stages of developmen
+t.
+ These stages are reached by accruing more than a specific total number
+ of kills by the whole team.
+ Each new stage unlocks new classes, upgrades and buildable structures.
+ If one team reaches a stage significantly earlier than the other team it
+ stands a better chance of defeating the opposing team.
+\layout Standard
+
+Section
+\begin_inset LatexCommand \ref{sec:Game}
+
+\end_inset
+
+ details the content of the game including the various controls that are
+ used to play.
+ Section
+\begin_inset LatexCommand \ref{sec:Technical}
+
+\end_inset
+
+ describes some technical aspects of how Tremulous works.
+ It is not necessary to read this section in order to play the game.
+\layout Section
+
+
+\begin_inset LatexCommand \label{sec:Game}
+
+\end_inset
+
+Game
+\layout Subsection
+
+Aliens
+\layout Standard
+
+Two classes are available upon joining the alien team: the Dretch and the
+ Granger.
+ As you gain kills, you may use your earned frags to evolve into higher
+ classes with the
+\noun on
+Use Structure/Evolve
+\noun default
+ button.
+ The alien team is mostly limited to melee attacks and must use stealth
+ and speed to defeat the longer range humans.
+ All aliens automatically regenerate health at a slow rate.
+\layout Subsubsection
+
+Classes
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Granger
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename granger.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="3">
+<features>
+<column alignment="left" valignment="top" rightline="true" width="0">
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Ability
+\end_inset
+</cell>
+<cell multicolumn="1" alignment="left" valignment="top" bottomline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Control
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Build
+\end_inset
+</cell>
+<cell multicolumn="1" alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Primary Attack
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Destroy Structure
+\end_inset
+</cell>
+<cell multicolumn="1" alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Deconstruct Structure
+\noun default
+ on an alien structure
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Granger
+\emph default
+ is the alien team's builder class.
+
+\noun on
+Primary Attack
+\noun default
+ will bring up a menu of structures available for building.
+ After selecting a structure a glowing outline of it will appear.
+ When this outline is green you can use the
+\noun on
+Primary Attack
+\noun default
+ button to place it.
+ The outline changes to red when the structure cannot be placed in its current
+ location.
+ To cancel placing the structure press the
+\noun on
+Secondary Attack
+\noun default
+ button.
+ To remove a placed structure use the
+\noun on
+Deconstruct Structure
+\noun default
+ button.
+ After building or deconstructing a structure a timer will appear in the
+ lower right corner of the screen.
+ Until this timer expires you cannot create or destroy another building.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Advanced Granger
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename agranger.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="6" columns="2">
+<features>
+<column alignment="left" valignment="top" rightline="true" width="0">
+<column alignment="left" valignment="top" width="0">
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Ability
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Control
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Build
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Primary Attack
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Slash
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Secondary Attack
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Lob Projectile
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Activate Upgrade
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Destroy Structure
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Deconstruct Structure
+\noun default
+on an alien structure
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Wallwalk
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Crouch
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Advanced Granger
+\emph default
+ becomes available at no cost when the alien team reaches stage two.
+ In addition to the
+\emph on
+Granger's
+\emph default
+ abilities, the
+\emph on
+Advanced Granger
+\emph default
+ can move faster, jump higher, walk on walls and attack with a slash or
+ by lobbing small projectiles with the
+\noun on
+Activate Upgrade
+\noun default
+ button.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Dretch
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename dretch.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" rightline="true" width="0">
+<column alignment="left" valignment="top" width="0">
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Ability
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Control
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Bite
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Touch a human
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Wallwalk
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Crouch
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Dretch
+\emph default
+ is the alien team's weakest offensive class.
+ Its only attack is to make forward contact with a human player or human
+ defensive structure.
+ The amount of damage dealt to a human depends on what armour they were
+ wearing and where they were hit, with headshots resulting in the most damage.
+
+\emph on
+Dretches
+\emph default
+ can also wallwalk; toggle it by pressing the
+\noun on
+Crouch
+\noun default
+ button.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Basilisk
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename basilisk.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 1
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="4" columns="2">
+<features>
+<column alignment="left" valignment="top" rightline="true" width="0">
+<column alignment="left" valignment="top" width="0">
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Ability
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Control
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Slash
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Primary Attack
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Grab
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Touch a human
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Wallwalk
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Crouch
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Basilisk
+\emph default
+ attacks by using the
+\noun on
+Primary Attack
+\noun default
+ button.
+ It can also grab human players by making contact with them at close range.
+ This freezes humans in place and, if they're not wearing a
+\emph on
+Battlesuit
+\emph default
+, restricts their ability to turn.
+ The
+\emph on
+Basilisk
+\emph default
+ can also wallwalk; toggle it by pressing the
+\noun on
+Crouch
+\noun default
+ button.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Advanced Basilisk
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename abasilisk.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 2
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="5" columns="2">
+<features>
+<column alignment="left" valignment="top" rightline="true" width="0">
+<column alignment="left" valignment="top" width="0">
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Ability
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Control
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Slash
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Primary Attack
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Gas
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Secondary Attack
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Grab
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Touch a human
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Wallwalk
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Crouch
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+In addition to the
+\emph on
+Basilisk's
+\emph default
+ abilities, the
+\emph on
+Advanced Basilisk
+\emph default
+ can spray a cloud of noxious gas that will disorient and poison affected
+ human players.
+ Humans equipped with a
+\emph on
+Battlesuit
+\emph default
+ are immune to gas.
+ Use this ability with the
+\noun on
+Secondary Attack
+\noun default
+ button.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Marauder
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename marauder.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 2
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" rightline="true" width="0">
+<column alignment="left" valignment="top" width="0">
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Ability
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Control
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Bite
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Primary Attack
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Wall Jump
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Jump into a wall while holding down
+\noun on
+Jump
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Marauder
+\emph default
+ attacks with the
+\noun on
+Primary Attack
+\noun default
+ button and has the ability to rebound off walls.
+ To use this ability jump towards a wall and hold down the
+\noun on
+Jump
+\noun default
+ button.
+ When you hit the wall you will be propelled upward and in the direction
+ opposite of the wall.
+ As long as you continue hitting walls you will continue wall jumping.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Advanced Marauder
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename amarauder.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 3
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="4" columns="2">
+<features>
+<column alignment="left" valignment="top" rightline="true" width="0">
+<column alignment="left" valignment="top" width="0">
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Ability
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Control
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Bite
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Primary Attack
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Zap
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Secondary Attack
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Wall Jump
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Jump into a wall while holding down
+\noun on
+Jump
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+In addition to the
+\emph on
+Marauder's
+\emph default
+ abilities, the
+\emph on
+Advanced Marauder
+\emph default
+ can use a chain lightning attack.
+ To use this, press the
+\noun on
+Secondary Attack
+\noun default
+ button while aiming at a nearby human or human structure.
+ If it connects the electric shock will jump to up to two other nearby targets
+ doing full damage to the first, half damage to the second and one third
+ damage to the third over a period of one second provided the attacker stays
+ within range.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Dragoon
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename dragoon.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 3
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" rightline="true" width="0">
+<column alignment="left" valignment="top" width="0">
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Ability
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Control
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Bite
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Primary Attack
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Pounce
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Hold down
+\noun on
+Secondary Attack
+\noun default
+ briefly then release
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Dragoon
+\emph default
+ attacks by either biting with the
+\noun on
+Primary Attack
+\noun default
+ button or pouncing with
+\noun on
+Secondary Attack
+\noun default
+.
+ To pounce, first hold down the
+\noun on
+Secondary Attack
+\noun default
+ button to charge up, then release to leap forward and damage anything that
+ gets in the way.
+ While charging you will be unable to jump normally and will move at a reduced
+ rate.
+ Aim up a little to fly further when pouncing.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Advanced Dragoon
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename adragoon.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 4
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 3
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="4" columns="2">
+<features>
+<column alignment="left" valignment="top" rightline="true" width="0">
+<column alignment="left" valignment="top" width="0">
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Ability
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Control
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Bite
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Primary Attack
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Pounce
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Hold down
+\noun on
+Secondary Attack
+\noun default
+ briefly then release
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Shoot Barb
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Activate Upgrade
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+In addition to the
+\emph on
+Dragoon's
+\emph default
+ abilities, the
+\emph on
+Advanced Dragoon
+\emph default
+ can fire long ranged spiked barbs with the
+\noun on
+Activate Upgrade
+\noun default
+ button.
+ Up to three of these barbs may be held in reserve and they regenerate automatic
+ally over time.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Tyrant
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename tyrant.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 5
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 3
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="4" columns="2">
+<features>
+<column alignment="left" valignment="top" rightline="true" width="0">
+<column alignment="left" valignment="top" width="0">
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Ability
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Control
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Slash
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Primary Attack
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Trample
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Hold down
+\noun on
+Secondary Attack
+\noun default
+ briefly then release
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Healing Aura
+\end_inset
+</cell>
+<cell alignment="left" valignment="top" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stand close to teammates to increase their regeneration rate
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Tyrant
+\emph default
+ attacks by either slashing with the
+\noun on
+Primary Attack
+\noun default
+ button or trampling with
+\noun on
+Secondary Attack
+\noun default
+.
+ To trample, first hold down the
+\noun on
+Secondary Attack
+\noun default
+ button while moving forward to charge up, then release to run at high speed
+ for a short time, damaging anything in your path.
+ The
+\emph on
+Tyrant
+\emph default
+ also has a healing aura that will double the regeneration rate of lower
+ class aliens within range.
+\layout Subsubsection
+
+Structures
+\layout Standard
+
+All alien structures must be built in proximity to an
+\emph on
+Egg
+\emph default
+ or an
+\emph on
+Overmind
+\emph default
+.
+ All alien structures require the presence of an
+\emph on
+ Overmind
+\emph default
+ to function.
+ All alien structures create `creep' around their bases that slows human
+ movement.
+ When destroyed, alien structures explode in a shower of acid harmful to
+ humans.
+ All structures may be built on level floors and when
+\emph on
+Advanced Grangers
+\emph default
+ become available some structures may also be built on walls and ceilings.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Overmind
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename overmind.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Sentience: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Overmind
+\emph default
+ is the collective consciousness that controls all the alien structures
+ in a map and enables aliens to evolve into higher forms.
+ There can only be one
+\emph on
+Overmind
+\emph default
+ and it must be alive before any other structures can be built.
+ If the
+\emph on
+Overmind
+\emph default
+ is destroyed then all structures besides
+\emph on
+Eggs
+\emph default
+ cease to function and every alien loses the ability to upgrade their class
+ until a new
+\emph on
+Overmind
+\emph default
+ is built.
+ The
+\emph on
+Overmind
+\emph default
+ has a limited amount of `sentience' which is distributed amongst every
+ other structure built, each having its own cost.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Egg
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename egg.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Sentience: 10
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Egg
+\emph default
+ is the most basic and important alien structure; it is from these that
+ aliens spawn into the game.
+ They are also the only structure that continues to function in the absence
+ of an
+\emph on
+Overmind
+\emph default
+.
+
+\emph on
+Eggs
+\emph default
+ may be built on ceilings.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Acid Tube
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename acidtube.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Sentience: 8
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+
+\emph on
+Acid Tubes
+\emph default
+ are the primary defensive structure for the alien team.
+ When approached by a human they eject lethal acid in all directions, even
+ over other structures.
+
+\emph on
+ Acid Tubes
+\emph default
+ may be built on walls and ceilings.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Barricade
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename barricade.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Sentience: 10
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+
+\emph on
+Barricades
+\emph default
+ are used to obstruct corridors and doorways, hindering human movement and
+ line-of-sight.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Trapper
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename trapper.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Sentience: 8
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+
+\emph on
+Trappers
+\emph default
+ fire a blob of adhesive spit at any human in their line of sight, freezing
+ them in place and, if they're not wearing a
+\emph on
+Battlesuit
+\emph default
+, restricts their ability to turn.
+
+\emph on
+ Trappers
+\emph default
+ may be built on walls and ceilings, and are rarely effective when built
+ on floors.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Booster
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename booster.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Sentience: 12
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+Any alien that touches a
+\emph on
+Booster
+\emph default
+ is provided with a poison enhancement on all their melee attacks for a
+ limited time.
+ Poison causes victims to lose health steadily over time unless they use
+ a
+\emph on
+ Medkit
+\emph default
+ or visit a
+\emph on
+Medistation
+\emph default
+.
+ Poison does not work against humans equipped with a
+\emph on
+Battlesuit
+\emph default
+.
+ The
+\emph on
+Booster
+\emph default
+ will also double the regeneration rate of any nearby aliens with the exception
+ of
+\emph on
+ Tyrants
+\emph default
+.
+ The healing aura of a
+\emph on
+ Tyrant
+\emph off
+
+\emph default
+i
+\emph off
+s not
+\emph default
+cumulative
+\emph off
+ with the healing effect of boosters.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Hovel
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename hovel.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Sentience: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 3
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+
+\emph on
+Hovels
+\emph default
+ are armored shells that
+\emph on
+Grangers
+\emph default
+ may hide in should the need arise.
+ There can only be one Hovel.
+ They may be entered and exited with the
+\noun on
+Use Structure/Evolve
+\noun default
+ button.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Hive
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename hive.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Sentience: 12
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 3
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+
+\emph on
+Hives
+\emph default
+ house millions of tiny insectoid aliens.
+ When a human approaches the structure the insects attack.
+
+\emph on
+Hives
+\emph default
+ may be built on ceilings.
+\layout Subsection
+
+Humans
+\layout Subsubsection
+
+Weapons
+\layout Standard
+
+Humans may spawn with either the
+\emph on
+Construction Kit
+\emph default
+ or the
+\emph on
+Rifle
+\emph default
+.
+ As credits are earned, humans may sell their old upgrades and purchase
+ new ones at an
+\emph on
+Armoury
+\emph default
+ structure.
+ Ammo may be refilled for normal weapons at
+\emph on
+Armouries
+\emph default
+, or at
+\emph on
+Reactors
+\emph default
+ and
+\emph on
+Repeaters
+\emph default
+ for energy weapons, all at no cost.
+ Players may only carry one weapon at a time, excluding the
+\emph on
+Blaster
+\emph default
+.
+ In general the humans rely on long range weapons to make up for their lack
+ of mobility relative to the alien team.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Construction Kit
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename ckit.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Construction Kit
+\emph default
+ is the humans' method of building structures.
+ The
+\noun on
+Primary
+\noun default
+
+\noun on
+Attack
+\noun default
+ button will bring up a menu of structures available for building.
+ After selecting a structure, a glowing outline of it will appear.
+ When this outline is green, pressing the
+\noun on
+Primary Attack
+\noun default
+ button will place it.
+ When the outline is red, the structure cannot be placed in its current
+ location.
+ To cancel placing the structure, press the
+\noun on
+Secondary Attack
+\noun default
+ button.
+ To remove a placed structure, use the
+\noun on
+Deconstruct Structure
+\noun default
+ button.
+ After building or deconstructing a structure, a timer will show up in the
+ lower right corner of the screen.
+ Until this timer expires, you cannot create, destroy or repair any structures.
+ Damaged structures may otherwise be repaired with the
+\noun on
+Secondary Attack
+\noun default
+ button.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Advanced Construction Kit
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename ackit.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+At stage two an upgraded
+\emph on
+Construction Kit
+\emph default
+ becomes available that allows the building of more advanced structures.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Blaster
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename blaster.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Blaster
+\emph default
+ is the human team's standard issue backup weapon.
+ All players spawn with one automatically and may not exchange it for another
+ weapon.
+ The
+\emph on
+Blaster
+\emph default
+ fires a weak projectile and uses no ammo.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Rifle
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename rifle.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Rifle
+\emph default
+ is the human team's most basic weapon and is available from spawning.
+ It rapidly fires moderately accurate shots with clip sizes of 30.
+ Up to 6 extra clips may be carried at a time.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Pain Saw
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename psaw.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 100
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Pain Saw
+\emph default
+ is a powerful melee weapon that emits a steady electric hum when in use.
+ It uses no ammunition.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Shotgun
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename shotgun.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 150
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Shotgun
+\emph default
+ fires 8 pellets at a wide angle and is thus best used in close quarters.
+ It holds 8 shots per clip and 3 extra clips may be carried at a time.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Las Gun
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename lasgun.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 250
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Las Gun
+\emph default
+ is similar to the
+\emph on
+Rifle
+\emph default
+ but is more powerful, accurate, slower to fire and uses no clips.
+ It is an energy weapon and so must be refilled at a
+\emph on
+Reactor
+\emph default
+ or
+\emph on
+Repeater
+\emph default
+.
+ It can hold up to 200 cells at a time, or 300 with a
+\emph on
+Battery Pack
+\emph default
+.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Mass Driver
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename mdriver.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 350
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Mass Driver
+\emph default
+ fires powerful, accurate shots at a slow rate of fire.
+ It is an energy weapon and holds 5 shots per clip, or 7 with a
+\emph on
+Battery Pack
+\emph default
+.
+ Up to 4 extra clips may be carried at a time.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Chaingun
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename chaingun.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 400
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Chaingun
+\emph default
+ is a powerful, wildly inaccurate rapid-fire weapon.
+ It holds up to 300 bullets at a time and is best used when crouching to
+ reduce its kickback.
+ Humans equipped with a
+\emph on
+Battlesuit
+\emph default
+do not experience this kickback.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Pulse Rifle
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename prifle.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 400
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Pulse Rifle
+\emph default
+ is an energy weapon that fires projectiles at high speeds.
+ It holds up to 50 cells per clip, or 75 with a
+\emph on
+Battery Pack
+\emph default
+.
+ Up to 4 extra clips may be carried at a time.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Grenade
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename grenade.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 200
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Grenade
+\emph default
+ is a hand held explosive device.
+ It is thrown for a short distance by using the
+\noun on
+Activate Upgrade
+\noun default
+ button.
+ After a brief delay it will explode and cause tremendous damage to anything
+ in its area of effect.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Flamethrower
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename flamer.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 450
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 3
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Flamethrower
+\emph default
+ is a short range incendiary weapon.
+ It holds up to 150 shots at a time and can easily damage the careless wielder.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Lucifer Cannon
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename lcannon.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 600
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 3
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Lucifer Cannon
+\emph default
+ is the human team's most devastating weapon.
+ It is an energy weapon that can hold up to 90 cells at a time, or 135 with
+ a
+\emph on
+Battery Pack
+\emph default
+.
+ By holding down the
+\noun on
+Primary Attack
+\noun default
+ button, a player may charge up a powerful, slow moving projectile with
+ splash damage.
+ The longer the attack is charged the more powerful the projectile and the
+ more ammo used.
+ If the attack is charged for too long the weapon will explode, damaging
+ the player.
+ The
+\noun on
+Secondary Attack
+\noun default
+button fires a smaller projectile that requires no charging.
+\layout Subsubsection
+
+Upgrades
+\layout Standard
+
+Human players may equip themselves with any number of the following upgrades,
+ with a few exceptions: the
+\emph on
+Jet Pack
+\emph default
+ and
+\emph on
+Battery Pack
+\emph default
+ may not be used together and the
+\emph on
+Battlesuit
+\emph default
+ may not be used with the
+\emph on
+Jet Pack
+\emph default
+,
+\emph on
+Battery Pack
+\emph default
+,
+\emph on
+Light Armour
+\emph default
+, or
+\emph on
+Helmet
+\emph default
+.
+ Only one of any type of upgrade may be carried at a time.
+ Upgrades that do not grant an intrinsic effect must be selected in the
+ player's inventory with the
+\noun on
+Next Upgrade
+\noun default
+ and
+\noun on
+Previous Upgrade
+\noun default
+ buttons and then activated with the
+\noun on
+Activate Upgrade
+\noun default
+ button.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Light Armour
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename larmour.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 70
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+
+\emph on
+Light Armour
+\emph default
+ grants the wearer improved defense to the torso and leg areas.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Helmet
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename helmet.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 90
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Helmet
+\emph default
+ improves the defense of the wearer's head and also displays a radar that
+ shows the relative positions of nearby enemies and enemy structures.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="2" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Medkit
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+
+\emph on
+Medkits
+\emph default
+ are a free holdable given to every human upon spawning and refilled at
+\emph on
+ Medistations
+\emph default
+ to players with full health.
+ They may not be refilled or exchanged at
+\emph on
+ Armouries
+\emph default
+.
+ When used with the
+\noun on
+ Activate Upgrade
+\noun default
+ button,
+\emph on
+ Medkits
+\emph default
+ immediately begin restoring health at a slow rate, gradually speeding up
+ until all damage incurred before the
+\emph on
+ Medkit
+\emph default
+ was activated is healed.
+ Additionally, if a human is poisoned, using a
+\emph on
+ Medkit
+\emph default
+ will cure the poison and confer a 30 second immunity to poison.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Battery Pack
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename battpack.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 100
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Battery Pack
+\emph default
+ increases the maximum ammo capacity of energy weapons by 50%.
+ It may not be used in conjunction with the
+\emph on
+Jet Pack
+\emph default
+.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Jet Pack
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename jetpack.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 120
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Jet Pack
+\emph default
+ grants the wearer the power of slow but unlimited flight.
+ When activated with the
+\noun on
+Activate Upgrade
+\noun default
+ button, a player may ascend or descend using the
+\noun on
+Jump
+\noun default
+ or
+\noun on
+Crouch
+\noun default
+ buttons, respectively.
+ The
+\emph on
+Jet Pack
+\emph default
+ ceases to function if there is no operational
+\emph on
+Reactor
+\emph default
+present.
+ Additionally it temporarily cuts out if the player receives any damage.
+ The
+\emph on
+Jet Pack
+\emph default
+ may not be used in conjunction with the
+\emph on
+Battery Pack
+\emph default
+.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Battlesuit
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename bsuit.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Cost: 400
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 3
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Battlesuit
+\emph default
+ provides a significant defensive boost to the wearer's entire body.
+ Due to this coverage, the
+\emph on
+Battlesuit
+\emph default
+ may not be used in conjunction with any other wearable upgrade (
+\emph on
+Light Armour
+\emph default
+,
+\emph on
+Helmet
+\emph default
+,
+\emph on
+Battery Pack
+\emph default
+, and
+\emph on
+Jet Pack
+\emph default
+).
+ Players are also prevented from crouching while wearing Battlesuits.
+\layout Subsubsection
+
+Structures
+\layout Standard
+
+All human structures must be built in proximity to a
+\emph on
+Reactor
+\emph default
+ or a
+\emph on
+Repeater
+\emph default
+.
+ With
+\emph on
+Telenodes
+\emph default
+ as the only exception, all structures require the presence of a working
+
+\emph on
+Reactor
+\emph default
+ to function.
+ All human structures explode in a powerful blast harmful to anything within
+ their radius when destroyed.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Reactor
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename reactor.jpg
+ scale 75
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Power: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Reactor
+\emph default
+ is the power source for all human structures in a map.
+ There may only be one
+\emph on
+Reactor
+\emph default
+, and it must be present before any structures other than
+\emph on
+ Repeaters
+\emph default
+ can be built.
+ If the
+\emph on
+Reactor
+\emph default
+ is destroyed then all structures besides
+\emph on
+Telenodes
+\emph default
+ cease to function.
+ The
+\emph on
+Reactor
+\emph default
+ has a limited amount of power which is distributed among every other structure
+ built, each having its own cost.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Telenode
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename telenode.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Power: 10
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Telenode
+\emph default
+ is the most basic and fundamental human structure; it is from these that
+ humans spawn into the game.
+ They are also the only structure that continues to function in the absence
+ of a
+\emph on
+ Reactor
+\emph default
+.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Machine Gun Turret
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename turret.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Power: 8
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Machine Gun Turret
+\emph default
+ is the primary defensive structure for the human team.
+ While they have a clear line of sight to an alien within their range, they
+ will track and fire at the alien until it is dead.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Tesla Generator
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename tesla.jpg
+ scale 80
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Power: 10
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 3
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+
+\emph on
+Tesla Generators
+\emph default
+ are a defensive structure that will unconditionally hit any target within
+ their range and line of sight with an electrical surge.
+ To be built and function, a
+\emph on
+Tesla Generator
+\emph default
+ requires the presence of a
+\emph on
+Defense Computer
+\emph default
+ somewhere in the map.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Armoury
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename armoury.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Power: 10
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Armoury
+\emph default
+ is an essential part of every human base, allowing upgrades beyond the
+ basic spawning equipment to be bought and exchanged.
+ It is the sole means of human advancement.
+ To use an
+\emph on
+Armoury
+\emph default
+, approach it and press the
+\noun on
+Use Structure/Evolve
+\noun default
+ button.
+ Ammo for non-energy weapons may also be acquired at no cost from an
+\emph on
+Armoury
+\emph default
+ by using the
+\noun on
+Buy Ammo
+\noun default
+ button.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Defense Computer
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename dcc.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Power: 8
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+
+\emph on
+Defense Computers
+\emph default
+ coordinate the attacks of
+\emph on
+Machine Gun Turrets
+\emph default
+, preventing them from firing at a single target when multiple targets are
+ available.
+ They are also required for the production of
+\emph on
+Tesla Generators
+\emph default
+.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Medistation
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename medistat.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Power: 8
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 1
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The
+\emph on
+Medistation
+\emph default
+ provides the only means for humans to heal themselves.
+ By standing on one, a human will quickly regenerate health up to their
+ maximum of 100.
+
+\emph on
+ Medistations
+\emph default
+ will also refill
+\emph on
+ Medkits
+\emph default
+ to humans with full health.
+ Only one person may use a
+\emph on
+Medistation
+\emph default
+ at a time.
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="3" columns="2">
+<features>
+<column alignment="left" valignment="top" width="0">
+<column alignment="right" valignment="top" width="0">
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\emph on
+Repeater
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell multicolumn="1" alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\begin_inset Graphics
+ filename repeater.jpg
+ scale 85
+
+\end_inset
+
+
+\end_inset
+</cell>
+<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Power: 0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Stage: 2
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+
+\emph on
+Repeaters
+\emph default
+ serve as power distributors that may be built anywhere not already powered,
+ even when no
+\emph on
+Reactor
+\emph default
+ is present.
+ Any other structure may be built in proximity to a working
+\emph on
+Repeater
+\emph default
+ as if it were a
+\emph on
+Reactor
+\emph default
+.
+ If a
+\emph on
+Repeater
+\emph default
+ powers nothing for 90 seconds, it will automatically self destruct.
+\layout Section
+
+
+\begin_inset LatexCommand \label{sec:Technical}
+
+\end_inset
+
+Technical
+\layout Subsection
+
+Bindings
+\layout Standard
+\align center
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="22" columns="3">
+<features islongtable="true">
+<column alignment="block" valignment="top" rightline="true" width="4cm">
+<column alignment="block" valignment="top" rightline="true" width="4cm">
+<column alignment="block" valignment="top" width="5.5cm">
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Name in menu
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Binding
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Function
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Primary Attack
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
++attack
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Use primary attack function.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Secondary Attack
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
++button5
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Use secondary attack function.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Previous Upgrade
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+weapprev
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+As human, preselect the previous upgrade in your inventory.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Next Upgrade
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+weapnext
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+As human, preselect the next upgrade in your inventory.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Activate Upgrade
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
++button2
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+As human, activate the current preselected inventory item.
+ Also used for some alien abilities.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Reload
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+reload
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+As human, reload the selected weapon.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Buy Ammo
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+buy ammo
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+As human, buy ammo from an
+\emph on
+armoury
+\emph default
+,
+\emph on
+repeater
+\emph default
+ or
+\emph on
+reactor
+\emph default
+.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Use Medkit
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+itemact medkit
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+As human, activate your
+\emph on
+Medkit
+\emph default
+.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Use Structure/Evolve
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
++button7
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+As human, use the structure in front of the player.
+ As alien, evolve into a different class.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Deconstruct Structure
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+deconstruct
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+As a builder class, deconstruct the structure in front of the player cleanly.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\noun on
+Sprint
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+boost
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Run faster.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+--
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+destroy
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+As a builder class, destroy the structure in front of the player.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+--
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+itemact <item>
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+If held, activate the specified item.
+ For weapons this will select them.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+--
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+itemdeact <item>
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+If held, deactivate the specified item.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+--
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+itemtoggle <item>
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+If held, toggle the state of the specified item.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+--
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+sell <item>
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+If held and within range of an
+\emph on
+armoury
+\emph default
+, sell the specified item.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+--
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+sell weapons
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+If within range of an
+\emph on
+armoury
+\emph default
+, sell all weapons.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+--
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+sell upgrades
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+If within range of an
+\emph on
+armoury
+\emph default
+, sell all upgrades.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+--
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+buy <item>
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+If within range of an
+\emph on
+armoury
+\emph default
+ and sufficiently wealthy, buy the specified item.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+--
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+class <class>
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Given sufficient kills, evolve to the specified class.
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+--
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+
+\series bold
+build <structure>
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+As a builder class, build the specified structure.
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+
+\series bold
+<item>
+\series default
+ --
+\emph on
+blaster, rifle, ckit, ackit, shotgun, lgun, prifle, mdriver, flamer, chaingun,
+ lcannon, psaw, gren, medkit, jetpack
+\layout Standard
+
+
+\series bold
+<class>
+\series default
+ --
+\emph on
+builder, builderupg, level0, level1, level1upg, level2, level2upg, level3,
+ level3upg, level4
+\layout Standard
+
+
+\series bold
+<structure>
+\series default
+ --
+\emph on
+eggpod, barricade, booster, acid_tube, hive, trapper, overmind, hovel, telenode,
+ medistat, mgturret, tesla, dcc, arm, reactor, repeater
+\layout Subsection
+
+Particle System
+\layout Standard
+
+Files matching the pattern scripts/*.particle are loaded as particle system
+ description files.
+ Each .particle file can contain an arbitrary number of discrete particle
+ systems, much like a .shader file can house many shaders.
+ A particle system is declared by a name followed by curly braces within
+ which the functionality of the particle system is defined.
+ For example:
+\layout LyX-Code
+
+aShinyNewParticleSystem { }
+\layout Standard
+
+Inside the particle system declaration are placed up to four particle ejectors.
+ Ejectors are identified by the keyword ejector and curly braces:
+\layout LyX-Code
+
+aShinyNewParticleSystem
+\layout LyX-Code
+
+{
+\layout LyX-Code
+
+ ejector { }
+\layout LyX-Code
+
+ ejector { }
+\layout LyX-Code
+
+ thirdPersonOnly
+\layout LyX-Code
+
+}
+\layout Standard
+
+The thirdPersonOnly keyword may be used to specify that the particle system
+ is not visible from the first person if it relates to that client.
+ The role of the particle ejector is to create some number of new particles
+ at a defined rate.
+ These attributes are controlled by the following parameters:
+\layout Itemize
+
+
+\emph on
+count <number>|infinite
+\emph default
+ - the number of particles this ejector will spawn.
+\layout Itemize
+
+
+\emph on
+delay <msec>
+\emph default
+ - the delay in msec before the ejector starts spawning.
+\layout Itemize
+
+
+\emph on
+period <initial> <final> <variance>
+\emph default
+ - the period between particle ejections.
+\layout Standard
+
+It is perfectly acceptable to have an initial period of zero.
+ In this case the number of particles specified by the count keyword will
+ be ejected at once.
+ It is not permissible to have count infinite and a period of zero for obvious
+ reasons.
+\layout Standard
+
+At ejection time each ejector creates up to four new particles based on
+ templates.
+ These are specified in the ejector section using the particle keyword:
+\layout LyX-Code
+
+aShinyNewParticleSystem
+\layout LyX-Code
+
+{
+\layout LyX-Code
+
+ ejector
+\layout LyX-Code
+
+ {
+\layout LyX-Code
+
+ particle { }
+\layout LyX-Code
+
+ particle { }
+\layout LyX-Code
+
+ count 50
+\layout LyX-Code
+
+ delay 0
+\layout LyX-Code
+
+ period 0 - 0
+\layout LyX-Code
+
+ }
+\layout LyX-Code
+
+}
+\layout Standard
+
+Each particle template has a number of attributes:
+\layout Itemize
+
+
+\emph on
+shader <fps>|sync <shader1> <shader2> ...
+ <shaderN>
+\emph default
+ - this specifies the shaders to use for the particle.
+ The frame rate can be set to a static rate or the
+\emph on
+sync
+\emph default
+ parameter can be used in which case the frame rate will be synchronised
+ to the lifetime of the particle such that the first frame is displayed
+ on birth and the last frame is displayed immediately before death.
+\layout Itemize
+
+model <model1> <model2> ...
+ <modelN> - use one of the specified models as the particle.
+ This cannot be used in conjunction with the shader keyword.
+\layout Itemize
+
+modelAnmation <firstFrame> <numFrames> <loopFrames> <fps>|sync - animation
+ parameters to use when model particles are employed.
+\layout Itemize
+
+
+\emph on
+displacement <x> <y> <z> <variance>
+\emph default
+ - a static displacement about the attachment point.
+ The
+\emph on
+variance
+\emph default
+ parameter specifies a random displacement in all axes.
+\layout Itemize
+
+
+\emph on
+normalDisplacement <displacement>
+\emph default
+ - for particle systems that have their normal set (impact particle systems
+ for example) this specifies the magnitude of a displacement along the normal.
+\layout Itemize
+
+
+\emph on
+velocityType static|static_transform|tag|cent|normal
+\emph default
+ - this specifies how the particle will compute its initial velocity.
+
+\emph on
+static
+\emph default
+ means it is specified statically in the .particle file,
+\emph on
+static_transform means the same, except that it is transformed by the orientatio
+n matrix of what it is attached to, tag
+\emph default
+ means the velocity is in the direction of the tag it is attached to,
+\emph on
+cent
+\emph default
+ means the velocity is in the direction of the cent it is attached to and
+
+\emph on
+normal
+\emph default
+ means the velocity is in the direction of the particle system normal.
+\layout Itemize
+
+
+\emph on
+velocityDir linear|point
+\emph default
+ - this specifies whether the initial velocity is computed as a simple direction
+ or as the direction towards a secondary point (defined by
+\emph on
+velocityPoint
+\emph default
+ or dynamically through
+\emph on
+velocityType cent
+\emph default
+).
+\layout Itemize
+
+
+\emph on
+velocity <x> <y> <z> <variance>
+\emph default
+ - for when
+\emph on
+velocityType
+\emph default
+
+\emph on
+static
+\emph default
+ is present this specifies the direction.
+ The
+\emph on
+variance
+\emph default
+ here is specified in degrees e.g.
+ "~5" - up to 5 degrees deviation.
+\layout Itemize
+
+
+\emph on
+velocityMagnitude <magnitude>
+\emph default
+ - the magnitude of the velocity.
+\layout Itemize
+
+
+\emph on
+velocityPoint <x> <y> <z> <variance>
+\emph default
+ - for when
+\emph on
+velocityType static
+\emph default
+ and
+\emph on
+velocityDir point
+\emph default
+ are present this specifies the point to move towards.
+\layout Itemize
+
+
+\emph on
+parentVelocityFraction <fraction>
+\emph default
+ - for when the particle system is attached to a cent this specifies the
+ fraction of the cent's velocity that is added to the particle's velocity.
+\layout Itemize
+
+
+\emph on
+accelerationType static|static_transform|tag|cent|normal
+\emph default
+ - this specifies how the particle will compute its acceleration.
+
+\emph on
+static
+\emph default
+ means it is specified statically in the .particle file,
+\emph on
+static_transform means the same, except that it is transformed by the orientatio
+n matrix of what it is attached to,
+\emph default
+
+\emph on
+tag
+\emph default
+ means the acceleration is in the direction of the tag it is attached to,
+
+\emph on
+cent
+\emph default
+ means the acceleration is in the direction of the cent it is attached to
+ and
+\emph on
+normal
+\emph default
+ means the acceleration is in the direction of the particle system normal.
+\layout Itemize
+
+
+\emph on
+accelerationDir linear|point
+\emph default
+ - this specifies whether the acceleration is computed as a simple direction
+ or as the direction towards a secondary point (defined by
+\emph on
+accelerationPoint
+\emph default
+ or dynamically through
+\emph on
+accelerationType cent
+\emph default
+).
+\layout Itemize
+
+
+\emph on
+acceleration <x> <y> <z> <variance>
+\emph default
+ - for when
+\emph on
+accelerationType
+\emph default
+ static is present this specifies the direction.
+ The
+\emph on
+variance
+\emph default
+ here is specified in degrees e.g.
+ "~5" - up to 5 degrees deviation.
+\layout Itemize
+
+
+\emph on
+accelerationMagnitude <magnitude>
+\emph default
+ - the magnitude of the acceleration.
+\layout Itemize
+
+
+\emph on
+accelerationPoint <x> <y> <z> <variance>
+\emph default
+ - for when
+\emph on
+accelerationType static
+\emph default
+ and
+\emph on
+accelerationDir point
+\emph default
+ are present this specifies the point to move towards.
+\layout Itemize
+
+
+\emph on
+bounce <fraction>|cull
+\emph default
+ - the fraction of velocity that is reflected when a particle collides.
+ If this is set to 0.0 the particle won't collide.
+ When
+\emph on
+cull
+\emph default
+ is used particles are culled as soon as they collide with objects.
+\layout Itemize
+
+bounceMark <count> <radius> <shader> - make a mark at each bounce point
+ for up to <count> bounces.
+\layout Itemize
+
+bounceSound <count> <sound> - make a sound at each bounce point for up to
+ <count> bounces.
+\layout Itemize
+
+dynamicLight <delayRadius> <initialRadius> <finalRadius> { <r> <g> <b> }
+ - attach a dynamic light to this particle.
+\layout Itemize
+
+color <delay> { <ir> <ig> <ib> } { <fr> <fg> <fb> } - color the particle
+ where <i.> refers to the initial color component and <f.> refers to the final
+ color component.
+\layout Itemize
+
+
+\emph on
+overdrawProtection
+\emph default
+ - cull particles that occupy a large amount of screen space.
+\layout Itemize
+
+
+\emph on
+realLight
+\emph default
+ - light particles using the lightgrid instead of fullbright.
+\layout Itemize
+
+
+\emph on
+cullOnStartSolid
+\emph default
+ - cull particles that are spawned inside brushes.
+\layout Itemize
+
+
+\emph on
+radius <delay> <initial> <final>
+\emph default
+ - the radius of the particle throughout its lifetime.
+ The
+\emph on
+delay
+\emph default
+ parameter specifies the time in msec before radius scaling begins.
+ The
+\emph on
+initial
+\emph default
+ and
+\emph on
+final
+\emph default
+ parameters specify the radii of the particle in quake units.
+\layout Itemize
+
+
+\emph on
+alpha <delay> <initial> <final>
+\emph default
+ - the alpha of the particle throughout its lifetime.
+ The
+\emph on
+delay
+\emph default
+ parameter specifies the time in msec before alpha scaling begins.
+ The
+\emph on
+initial
+\emph default
+ and
+\emph on
+final
+\emph default
+ parameters specify the alpha of the particle where 1.0 is totally opaque
+ and 0.0 is totally transparent.
+\layout Itemize
+
+
+\emph on
+rotation <delay> <initial> <final>
+\emph default
+ - the rotation of the particle throughout its lifetime.
+ The
+\emph on
+delay
+\emph default
+ parameter specifies the time in msec before the rotation begins.
+ The
+\emph on
+initial
+\emph default
+ and
+\emph on
+final
+\emph default
+ parameters specify the rotation of the particle in degrees.
+\layout Itemize
+
+
+\emph on
+lifeTime <time>
+\emph default
+ - the lifetime of the particle.
+\layout Itemize
+
+
+\emph on
+childSystem <particle system>
+\emph default
+ - specifies a particle system to attach to this particle.
+\layout Itemize
+
+childTrailSystem <trail system> - specifies a trail system to attach to
+ this particle.
+\layout Itemize
+
+
+\emph on
+onDeathSystem <particle system>
+\emph default
+ - specifies a particle system to spawn at the point where this particle
+ died.
+\layout Standard
+
+Except for vector components,
+\emph on
+shader fps ...
+
+\emph default
+ and
+\emph on
+period <initial <final> <variance>
+\emph default
+, every value can be specified with a random variance.
+ The syntax for this is as follows:
+\layout LyX-Code
+
+[value][~variance[%]]
+\layout Standard
+
+So the following forms are possible, where random is a random number between
+ 0.0 and 1.0 inclusive:
+\layout LyX-Code
+
+5.0 // 5.0
+\layout LyX-Code
+
+5.0~8.0 // 5.0 + ( random * 8.0 )
+\layout LyX-Code
+
+5.0~200% // 5.0 + ( random * 5.0 * 200% )
+\layout LyX-Code
+
+~7.0 // random * 7.0
+\layout Standard
+
+This allows for relatively flexible randomisation of most of the particle's
+ parameters.
+ For parameters taking an initial and final value, specifying the final
+ value as '-' will result in a final value the same as the initial value.
+\layout Standard
+
+For the purposes of map based particle systems using
+\emph on
+misc_particle_system
+\emph default
+ it is safe to ignore
+\emph on
+velocityType
+\emph default
+ and
+\emph on
+accelerationType tag|cent|normal
+\emph default
+,
+\emph on
+normalDisplacement
+\emph default
+ and
+\emph on
+parentVelocityFraction
+\emph default
+ altogether.
+\layout Standard
+
+Of course, it is not necessary to specify every parameter documented here
+ for every particle system.
+ If a parameter is not included it will usually default to zero.
+ C/C++ style comments can be used throughout.
+ There are an enormous number of possible combinations of particle systems
+ parameters and as such it is impractical to test them all.
+ For this reason it is possible that certain permutations do not behave
+ as expected or wrongly.
+ In this case you may have discovered a bug - let us know.
+ Having said this when you're having problems with a particle system make
+ sure you scroll up the console and check that it compiled OK, I've written
+ the parser to be very intolerant of error.
+\layout Standard
+
+Here is an example particle system:
+\layout LyX-Code
+
+aShinyNewParticleSystem
+\layout LyX-Code
+
+{
+\layout LyX-Code
+
+ ejector
+\layout LyX-Code
+
+ {
+\layout LyX-Code
+
+ particle
+\layout LyX-Code
+
+ {
+\layout LyX-Code
+
+ shader sync shader1 shader2
+\layout LyX-Code
+
+
+\layout LyX-Code
+
+ velocityType static
+\layout LyX-Code
+
+ velocityDir linear
+\layout LyX-Code
+
+ velocityMagnitude 200
+\layout LyX-Code
+
+ velocity 0 0 1 ~30
+\layout LyX-Code
+
+\layout LyX-Code
+
+ accelerationType static
+\layout LyX-Code
+
+ accelerationDir linear
+\layout LyX-Code
+
+ accelerationMagnitude 50
+\layout LyX-Code
+
+ acceleration 0 0 1 ~0
+\layout LyX-Code
+
+\layout LyX-Code
+
+ radius 0 10.0 50.0
+\layout LyX-Code
+
+ alpha 0 1.0 1.0
+\layout LyX-Code
+
+ rotation 0 ~360 -
+\layout LyX-Code
+
+ bounce 0.4
+\layout LyX-Code
+
+ lifeTime 1500
+\layout LyX-Code
+
+ }
+\layout LyX-Code
+
+\layout LyX-Code
+
+ count 50
+\layout LyX-Code
+
+ delay 0
+\layout LyX-Code
+
+ period 0 - 0
+\layout LyX-Code
+
+ }
+\layout LyX-Code
+
+}
+\layout Subsection
+
+Trail System
+\layout Standard
+
+Files matching the pattern scripts/*.trail are loaded as trail system description
+ files.
+ Each .trail file can contain an arbitrary number of discrete trail systems,
+ much like a .shader file can house many shaders.
+ A trail system is declared by a name followed by curly braces within which
+ the functionality of the trail system is defined.
+ For example:
+\layout LyX-Code
+
+aShinyNewTrailSystem { }
+\layout Standard
+
+Inside the particle system declaration are placed up to four trail beams.
+ Beams are identified by the keyword beam and curly braces:
+\layout LyX-Code
+
+aShinyNewTrailSystem
+\layout LyX-Code
+
+{
+\layout LyX-Code
+
+ beam { }
+\layout LyX-Code
+
+ beam { }
+\layout LyX-Code
+
+ thirdPersonOnly
+\layout LyX-Code
+
+}
+\layout Standard
+
+The thirdPersonOnly keyword may be used to specify that the trail system
+ is not visible from the first person if it relates to that client.
+ A trail beam describes the appearance of one element of the trail system:
+\layout LyX-Code
+
+\layout Itemize
+
+
+\emph on
+shader <shader> - the shader to use to texture this beam.
+\layout Itemize
+
+segments <number> - the number of quads that make up the beam.
+\layout Itemize
+
+width <frontWidth> <backWidth> - the width of the beam at the front and
+ back.
+\layout Itemize
+
+alpha <frontAlpha> <backAlpha> - the alpha of the beam at the front and
+ back.
+\layout Itemize
+
+color { <fr> <fg> <fb> } { <br> <bg> <bb> } - the color of the beam at the
+ front and back.
+\layout Itemize
+
+segmentTime <time> - how long a single segment lasts when the trail is only
+ attached at one end.
+\layout Itemize
+
+fadeOutTime <time> - how long this beam takes to fade away.
+\layout Itemize
+
+textureType [stretch <frontTC> <backTC>]|[repeat [front|back] <repeatLength>]
+ - how to texture the beam.
+ stretch causes the texture to be stretched from the front to the back using
+ the specified texture coordinates.
+ repeat causes the texture to be repeated over a specified length either
+ from the front or the back.
+
+\layout Itemize
+
+model <model1> <model2> ...
+ <modelN> - use one of the specified models as the particle.
+ This cannot be used in conjunction with the shader keyword.
+\layout Itemize
+
+modelAnmation <firstFrame> <numFrames> <loopFrames> <fps>|sync - animation
+ parameters to use when model particles are employed.
+\layout Itemize
+
+
+\emph on
+realLight
+\emph default
+ - light particles using the lightgrid instead of fullbright.
+\layout Itemize
+
+jitter <magnitude> <period> - this specifies a random jitter of the position
+ of each beam node by magnitude every period.
+\layout Itemize
+
+jitterAttachments - if this is specified the end points of the beam are
+ jittered as well as the intervening nodes.
+\layout Subsection
+
+Map Rotation System
+\layout Standard
+
+The file
+\emph on
+maprotation.cfg
+\emph default
+ is used to describe up to 16 map rotations which may be used by a Tremulous
+ server.
+ In its most simple form, the syntax is as follows:
+\layout LyX-Code
+
+mapRotation1
+\layout LyX-Code
+
+{
+\layout LyX-Code
+
+ map1
+\layout LyX-Code
+
+ map2
+\layout LyX-Code
+
+ map3
+\layout LyX-Code
+
+}
+\layout LyX-Code
+
+\layout LyX-Code
+
+mapRotation2
+\layout LyX-Code
+
+{
+\layout LyX-Code
+
+ map6
+\layout LyX-Code
+
+ map3
+\layout LyX-Code
+
+ map9
+\layout LyX-Code
+
+}
+\layout Standard
+
+This specifies two rotations, each consisting of three maps.
+ The contents of the cvar
+\emph on
+g_initialMapRotation
+\emph default
+ specifies the map rotation to start after the map the server was started
+ with has finished.
+ It is possible to specify a list of server commands to be run after a map
+ has finished:
+\layout LyX-Code
+
+mapRotation3
+\layout LyX-Code
+
+{
+\layout LyX-Code
+
+ map1
+\layout LyX-Code
+
+ {
+\layout LyX-Code
+
+ set sv_hostname
+\begin_inset Quotes eld
+\end_inset
+
+Just finished map1!
+\begin_inset Quotes erd
+\end_inset
+
+
+\layout LyX-Code
+
+ set g_teamForceBalance 0
+\layout LyX-Code
+
+ }
+\layout LyX-Code
+
+
+\layout LyX-Code
+
+ map2
+\layout LyX-Code
+
+ {
+\layout LyX-Code
+
+ set g_teamForceBalance 1
+\layout LyX-Code
+
+ }
+\layout LyX-Code
+
+\layout LyX-Code
+
+ map3
+\layout LyX-Code
+
+}
+\layout Standard
+
+Primitive logic is also available:
+\layout LyX-Code
+
+mapRotation4
+\layout LyX-Code
+
+{
+\layout LyX-Code
+
+ map1
+\layout LyX-Code
+
+ goto map3
+\layout LyX-Code
+
+\layout LyX-Code
+
+ map2
+\layout LyX-Code
+
+ if numClients > 8
+\layout LyX-Code
+
+ mapRotation3
+\layout LyX-Code
+
+\layout LyX-Code
+
+ map3
+\layout LyX-Code
+
+ if lastWin aliens
+\layout LyX-Code
+
+ mapRotation2
+\layout LyX-Code
+
+
+\layout LyX-Code
+
+ if random
+\layout LyX-Code
+
+ mapRotation1
+\layout LyX-Code
+
+}
+\layout LyX-Code
+
+\layout LyX-Code
+
+mapRotation5
+\layout LyX-Code
+
+{
+\layout LyX-Code
+
+ map1
+\layout LyX-Code
+
+ if lastWin humans
+\layout LyX-Code
+
+ map4
+\layout LyX-Code
+
+ map2
+\layout LyX-Code
+
+ map3
+\layout LyX-Code
+
+ goto map1
+\layout LyX-Code
+
+ map4
+\layout LyX-Code
+
+ map5
+\layout LyX-Code
+
+}
+\layout Standard
+
+The
+\series bold
+goto
+\series default
+ keyword is used to unconditionally branch to either another map
+\emph on
+in the current rotation
+\emph default
+ or another map rotation entirely.
+ The
+\series bold
+if
+\series default
+keyword is used in conjunction with a condition to decide whether or not
+ to branch to the specified map or rotation (as with the
+\series bold
+goto
+\series default
+ keyword).
+ The condition itself can be one of
+\series bold
+numClients <op> <number>
+\series default
+,
+\series bold
+lastWin <team>
+\series default
+or
+\series bold
+random
+\series default
+, where
+\series bold
+<op>
+\series default
+ is
+\series bold
+<
+\series default
+,
+\series bold
+>
+\series default
+ or
+\series bold
+=
+\series default
+ and
+\series bold
+<team>
+\series default
+ is
+\series bold
+aliens
+\series default
+ or
+\series bold
+humans
+\series default
+.
+ The
+\series bold
+random
+\series default
+ condition simply chooses whether or not to execute the change randomly,
+ with each outcome equally likely.
+\layout Subsection
+
+Server Administration System (g_admin)
+\layout Standard
+
+The Tremulous game code has a built-in administration system which can work
+ outside of traditional server console/rcon admin commands.
+ Instead of passwords, administration rights are granted on a unique player
+ identifier called cl_guid.
+ Because of this, day to day administration tasks (like !kick and !mute)
+ can easily be shared among a server's regular players without the risk
+ of giving those players too much power or having to share passwords.
+\layout Standard
+
+Although specific admin rights can be granted to an individual, rights are
+ primarily handed through a level system.
+ By default there are 6 levels defined (0-5).
+ Players with out any admin status are treated as level 0 with various additiona
+l rights added to each following level with level 5 having full rights.
+ You can change what rights each level has by editing the configuration
+ file (see below).
+ Levels are referenced by number, but they can also be given names.
+ There can up to 32 levels defined.
+ The number used to define the level has special significance since rights
+ are handled very heirarchically (e.g.
+ a level 4 admin can not !mute a level 5 admin since his victim has a higher
+ level).
+\layout Standard
+
+Administrator rights can granted with !setlevel command so a server operator
+ need not leave the game, edit files, restart, or even type a password to
+ adjust another player's admin status.
+ However, the configuration for this system is contained in an easy to edit
+ text file that allows a great deal of flexibility in configuring fine-grained
+ access rights for each user and/or access level.
+\layout Subsubsection
+
+Quick Start
+\layout Standard
+
+To get started, you simply need to ensure that the g_admin cvar is set to
+ the name of a writable data file (default is
+\begin_inset Quotes eld
+\end_inset
+
+admin.dat
+\begin_inset Quotes erd
+\end_inset
+
+).
+ Then connect to the server with your Tremulous client, then run the following
+ command in your client console:
+\layout LyX-Code
+
+/rcon YOUR_RCON_PASSORD !setlevel YOUR_NAME 5
+\layout Standard
+
+By default, the level 5 user is a super-user and has access to all '!' commands.
+ From that point you can use the /!help command in your client to familiarize
+ yourself with all the commands.
+\layout Subsubsection
+
+Related Cvars
+\layout Standard
+
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="5" columns="2">
+<features islongtable="true">
+<column alignment="left" valignment="top" width="0">
+<column alignment="block" valignment="top" leftline="true" width="5.5cm">
+<row>
+<cell multicolumn="1" alignment="left" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+g_admin <string>
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Set <string> to the name of the file in the fs_game directory that should
+ contain all admin data such as admin definitions and bans.
+\layout Standard
+
+If set to a blank string
+\begin_inset Quotes eld
+\end_inset
+
+
+\begin_inset Quotes erd
+\end_inset
+
+ admin commands will not be available.
+\layout Standard
+
+Example:
+\layout Standard
+
+set g_admin
+\begin_inset Quotes eld
+\end_inset
+
+admin.dat
+\begin_inset Quotes erd
+\end_inset
+
+
+\layout Standard
+
+Defaults to
+\begin_inset Quotes eld
+\end_inset
+
+admin.dat
+\begin_inset Quotes erd
+\end_inset
+
+ (off)
+\end_inset
+</cell>
+</row>
+<row topline="true" bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+g_adminLog <string>
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Set <string> to the name of the file in the fs_game directory that will
+ log all '!' commands.
+\layout Standard
+
+Defaults to
+\begin_inset Quotes eld
+\end_inset
+
+admin.log
+\begin_inset Quotes erd
+\end_inset
+
+
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+g_adminParseSay <integer>
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Set this to non-zero if you want the admin system to accept commands in
+ player chat messages.
+\layout Standard
+
+Default is 1 (on)
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+g_adminNameProtect <integer>
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Set this to non-zero if you want the admin system to lock each admin's name
+ to his cl_guid to prevent imporsonation.
+\layout Standard
+
+Default is 1 (on)
+\end_inset
+</cell>
+</row>
+<row>
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+g_adminTempBan
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+Set this to the time a player should be automatically banned
+ for when he/she is vote kicked or kicked with the !kick command.
+\layout Standard
+
+Default is 2m (two minutes)
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Subsubsection
+
+Data File Format
+\layout Standard
+
+All admin authorization, configuration, and ban information is storedin
+ the file identified with the g_admin cvar.
+ This file is plain text and each of the data elements are seperated by
+ blank lines.
+ The supported data elements are [level], [admin], [ban], and [command].
+
+\layout Standard
+
+The [level] block is used to define which admin rights a user of a particular
+ level has.
+ For example:
+\layout LyX-Code
+
+[level]
+\layout LyX-Code
+
+level = 3
+\layout LyX-Code
+
+name = Level 3 Admin
+\layout LyX-Code
+
+flags = i1ahCpPkmy
+\layout Standard
+
+This definition grants all level 3 admins all the commands identified by
+ the characters in the flags string (see flags table below).
+\layout Standard
+
+The [admin] block is used to define all players with administrative rights
+ as identified by their cl_guid.
+ These blocks are created/updated/deleted automatically when the !setlevel
+ command is used.
+ Additionally, these blocks can be used to grant special rights to specific
+ users above or below the rights given to that user's [level] definition.
+ For example:
+\layout LyX-Code
+
+[admin]
+\layout LyX-Code
+
+name = bill
+\layout LyX-Code
+
+guid = 1ABABAA74D54C3D25722E5E21121334
+\layout LyX-Code
+
+level = 3
+\layout LyX-Code
+
+flags = B-ym
+\layout Standard
+
+This grants the user bill all the rights of a level 3 user, plus the 'B'
+ flag which grants access to the !showbans command.
+ It also takes away from bill the !allready (y) command and the !mute and
+ !unmute (m) commands.
+\layout Standard
+
+The [ban] block is created with the !ban command, removed with the !unban
+ command (or when it expires), and modified with the !adjustban command.
+ Both the guid and the ip parameters are used for ban enforement.
+ The ip parameter can also be used to crudely widen the scope of the IP
+ ban.
+ For example:
+\layout LyX-Code
+
+[ban]
+\layout LyX-Code
+
+name = all !nexterholland@
+\layout LyX-Code
+
+guid = ABCABCABCABCABCABCABCABCABCABCAB
+\layout LyX-Code
+
+ip = 206.248.131.
+\layout LyX-Code
+
+reason = banned by admin
+\layout LyX-Code
+
+made = 04/18/06 19:15:35
+\layout LyX-Code
+
+expires = 0
+\layout LyX-Code
+
+banner = Fry
+\layout Standard
+
+This would prevent anyone with an IP address inside of 206.248.131.0/24 or
+ with the cl_guid ABCABCABCABCABCABCABCABCABCABCAB from connecting to the
+ server.
+ The expires field is the UNIX timestamp when the ban is no longer in effect,
+ the special case is 0 which means it never expires.
+\layout Standard
+
+The [command] block can be used to create simple ! commands.
+ The most practial use is to create certain .cfg files which change game
+ settings and allow high ranking admins to load up those settings through
+ a ! command.
+ For example:
+\layout LyX-Code
+
+[command]
+\layout LyX-Code
+
+command = havefun
+\layout LyX-Code
+
+exec = exec fun.cfg
+\layout LyX-Code
+
+desc = Load up some crazy settings/commands levels = 4 5
+\layout Standard
+
+This would allow all level 4 and 5 admins to run the command !havefun which
+ would be similar to running the command
+\begin_inset Quotes eld
+\end_inset
+
+exec fun.cfg
+\begin_inset Quotes erd
+\end_inset
+
+ on the server console.
+\layout Subsubsection
+
+Admin Flags
+\layout Standard
+
+Both the [level] and [admin] blocks have the flags parameter which is a
+ string of characters that grant access rights.
+ The following table shows the flags for built-in COMMANDS:
+\layout Standard
+
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="22" columns="2">
+<features islongtable="true">
+<column alignment="center" valignment="top" leftline="true" width="0">
+<column alignment="left" valignment="top" leftline="true" rightline="true" width="0">
+<row topline="true" bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+FLAG
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+COMMAND
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+a
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!admintest
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+y
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!allready
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+b
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!ban/!unban/!adjustban
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+c
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!cancelvote
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+h
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!help
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+k
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!kick
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+D
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!listadmins
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+i
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!listplayers
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+K
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!lock/!unlock
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+m
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!mute/!unmute
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+e
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!namelog
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+n
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!nextmap
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+V
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!passvote
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+p
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!putteam
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+G
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!readconfig
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+N
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!rename
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+r
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!restart
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+s
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!setlevel
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+B
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!showbans
+\end_inset
+</cell>
+</row>
+<row topline="true" bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+P
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!spec999
+\end_inset
+</cell>
+</row>
+<row bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+C
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!time
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+The following table shows the flags for RIGHTS:
+\layout Standard
+
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="13" columns="2">
+<features islongtable="true">
+<column alignment="center" valignment="top" leftline="true" width="0">
+<column alignment="left" valignment="top" leftline="true" rightline="true" width="0">
+<row topline="true" bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+FLAG
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+RIGHT
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+1
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+cannot be vote kicked
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+3
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+never loses credits/evo for switching teams
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+4
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+can see team chat as a spectator
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+5
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+can switch teams regardless of balance settings
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+6
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+does not need to specify a reason for kick/ban
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+7
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+can call a vote at any time regardless of g_voteLimit
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+8
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+does not need to specify a duration for a ban
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+9
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+can run commands in team chat
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+0
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+inactivity settings do not apply
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+!
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+no ! commands can be used on a player with this flag
+\end_inset
+</cell>
+</row>
+<row topline="true" bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+@
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+does not show up as an admin in the output of !listplayers
+\end_inset
+</cell>
+</row>
+<row topline="true" bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+$
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+sees additional player info in the output of !listplayers
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Standard
+
+In addition, there are 3 special case characters in the flags string:
+\layout Standard
+
+
+\begin_inset Tabular
+<lyxtabular version="3" rows="4" columns="2">
+<features islongtable="true">
+<column alignment="center" valignment="top" leftline="true" width="0">
+<column alignment="block" valignment="top" leftline="true" rightline="true" width="5.5cm">
+<row topline="true" bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+FLAG
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+MEANING
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+*
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+signifies ALL commands and rights any flags following this character are
+ negated.
+ The only exceptions are the ! and @ flags which must be given to individual
+ admins explicitly.
+\end_inset
+</cell>
+</row>
+<row topline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
++
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+any flags following this flag will be ADDED.
+ this is implied at the beginning of any flags string so it's pretty much
+ worthless.
+\end_inset
+</cell>
+</row>
+<row topline="true" bottomline="true">
+<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+-
+\end_inset
+</cell>
+<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
+\begin_inset Text
+
+\layout Standard
+
+any flags following this flag will be REMOVED.
+ this is particularly useful if you wish to remove a right from an admin
+ that has been given through that admin's [level] definition.
+\end_inset
+</cell>
+</row>
+</lyxtabular>
+
+\end_inset
+
+
+\layout Section
+\pagebreak_top
+Credits
+\layout Standard
+
+Tim
+\emph on
+'Timbo'
+\emph default
+ Angus -- Programming and Direction
+\layout Standard
+
+Nick
+\emph on
+'jex'
+\emph default
+ Jansens -- Mapping, texturing and 2D artwork
+\layout Standard
+
+Robin
+\emph on
+'OverFlow'
+\emph default
+ Marshall -- Modelling, animation and mapping
+\layout Standard
+
+Jan
+\emph on
+'Stannum'
+\emph default
+ van der Weg -- Texturing and mapping
+\layout Standard
+
+Mike
+\emph on
+'Veda'
+\emph default
+ Mcinnerney -- Modelling, animation and texturing
+\layout Standard
+
+Gordon
+\emph on
+'Godmil'
+\emph default
+ Miller -- Mapping
+\layout Standard
+
+'Who-[Soup]' -- Mapping
+\layout Standard
+
+Tristan
+\emph on
+'jhrx'
+\emph default
+ Blease -- Mapping
+\layout Standard
+
+Paul
+\emph on
+'MoP'
+\emph default
+ Greveson -- Modelling and texturing
+\layout Standard
+
+Chris
+\emph on
+'Dolby'
+\emph default
+ McCarthy -- Sound
+\layout Subsection*
+
+Special thanks
+\layout Standard
+
+Asa
+\emph on
+'Norfenstein'
+\emph default
+ Kravets -- Manual content, QA, design and balance suggestions
+\layout Standard
+
+
+\emph on
+'Crylar'
+\emph default
+ -- Concept art
+\layout Standard
+
+Yves
+\emph on
+'evillair'
+\emph default
+ Allaire -- Textures
+\layout Standard
+
+Randy
+\emph on
+'ydnar'
+\emph default
+ Reddig -- Textures
+\layout Standard
+
+Richard
+\emph on
+'R1CH'
+\emph default
+ Stanway -- Server hosting
+\layout Standard
+
+Stéphane
+\emph on
+'MEGASTeP'
+\emph default
+ Peter -- Early test server hosting
+\layout Standard
+
+Sourceforge and TARDIS -- Web hosting
+\layout Standard
+
+icculus.org -- Subversion hosting
+\layout Standard
+
+The contributors to icculus.org/quake3/ -- Various
+\layout Standard
+
+Arsonide, Bajoran, Bt, Chamooze, Crylar, Cybernetsam, dzjepp, ectox, Edo,
+ evil poop, Excalibur, FroggyQuim, Idle Wild, juice, Kai, kingping, Lava
+ Croft, MajorPain, MiDiaN, Molog, Mutemode, Norfenstein, Orc, R1CH, Ratti,
+ Ravyn, Salteh, Sandy, SharkDog, slux, Suddien, Supa, Survivor, Swie, sysrq,
+ TerrorEast, Tyler, Vitae, Woo -- Beta testers
+\layout Subsection*
+
+Also thanks
+\layout Standard
+
+babyomen, Carc, djbob, Grim, Grytviken, Gumby, heimdall, Hellbringer, Hentai,
+ Mighty_Pea, Psylo, Reaper-1, RR2D02, Saig, Smack, T-bone, The GtkRadiant
+ people, The inhabitants of Quake3World, ThePyro, TTimo, ValouR
+\layout Standard
+\align center
+
+\noun on
+Tremulous is copyright darklegion development 2005-2006
+\the_end
diff --git a/misc/merge-grangerhub-into-trem.sh b/misc/merge-grangerhub-into-trem.sh
new file mode 100644
index 0000000..05e4592
--- /dev/null
+++ b/misc/merge-grangerhub-into-trem.sh
@@ -0,0 +1,109 @@
+#! /bin/bash
+# TODO Consider rewrite in perl/python to make this a bit less crappy
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+PATCHES_DIR=${DIR}/patches
+LAST_REVISION_FILE=${DIR}/last-merged-grangerhub-revision
+LAST_REVISION_TEMP_FILE=${LAST_REVISION_FILE}.temp
+
+if [ -f ${LAST_REVISION_TEMP_FILE} ]
+then
+ LAST_REVISION=`cat ${LAST_REVISION_TEMP_FILE}`
+else
+ LAST_REVISION=`cat ${LAST_REVISION_FILE}`
+fi
+
+set -f
+# Things that exist in ioq3 which we don't want
+EXCLUSIONS="BUGS ChangeLog README ./*.txt NOTTODO TODO misc/* Makefile GNUmakefile src/sys/*"
+
+EXCLUDE_PARAMETERS=""
+for EXCLUSION in ${EXCLUSIONS}
+do
+ EXCLUDE_PARAMETERS+="--exclude=${EXCLUSION} "
+done
+
+set +f
+
+PATCHES=`ls ${PATCHES_DIR}/*.patch 2> /dev/null`
+if [ -z "${PATCHES}" ]
+then
+ echo "Fetching and generating patches..."
+ git fetch git@grangerlab.grangerhub.com:top-secret/tremulous-scribble-3.git rsakey
+
+ mkdir -p ${PATCHES_DIR}
+ git format-patch -o ${PATCHES_DIR} ${LAST_REVISION}..FETCH_HEAD
+fi
+
+if [ -d ".git/rebase-apply" ]
+then
+ echo "Failed patch detected."
+
+ git diff --quiet --exit-code
+ if [ "$?" -ne 0 ]
+ then
+ echo "Unstaged changes present; git add any that are pending:"
+ git status
+ exit 1
+ fi
+
+ PATCH=`ls ${PATCHES_DIR}/*.patch | head -n 1`
+ SHA=`cat ${PATCH} | head -n 1 | awk '{print $2;}'`
+ echo "Processing ${SHA} ${PATCH}..."
+
+ DIFF=`git diff --cached`
+ if [ -z "${DIFF}" ]
+ then
+ echo "Patch does nothing; skipping."
+ read -p "Confirm skip? "
+ git am --skip
+ else
+ read -p "Confirm resolve? "
+ git am --resolved
+ fi
+
+ if [ "$?" -ne 0 ]
+ then
+ echo "Patch failed to apply."
+ exit $?
+ fi
+
+ echo ${SHA} > ${LAST_REVISION_TEMP_FILE}
+ rm ${PATCH}
+fi
+
+PATCHES=`ls ${PATCHES_DIR}/*.patch 2> /dev/null`
+if [ -n "${PATCHES}" ]
+then
+ for PATCH in ${PATCHES}
+ do
+ SHA=`cat ${PATCH} | head -n 1 | awk '{print $2;}'`
+ echo "Processing ${SHA} ${PATCH}..."
+ cat ${PATCH} | git am ${EXCLUDE_PARAMETERS} --quiet --3way
+
+ if [ "$?" -ne 0 ]
+ then
+ echo "Patch failed to apply."
+ git status
+ exit $?
+ fi
+
+ echo ${SHA} > ${LAST_REVISION_TEMP_FILE}
+ rm ${PATCH}
+ done
+else
+ echo "Nothing to merge."
+fi
+
+# Finished merging so update the last revision marker
+if [ -f ${LAST_REVISION_TEMP_FILE} ]
+then
+ diff ${LAST_REVISION_FILE} ${LAST_REVISION_TEMP_FILE} &> /dev/null
+ if [ "$?" -ne 0 ]
+ then
+ mv ${LAST_REVISION_TEMP_FILE} ${LAST_REVISION_FILE}
+ LAST_REVISION=`cat ${LAST_REVISION_FILE}`
+ git add ${LAST_REVISION_FILE}
+ git commit -m "Merged grangerhub ${LAST_REVISION}"
+ fi
+fi
diff --git a/misc/merge-ioq3-into-trem.sh b/misc/merge-ioq3-into-trem.sh
new file mode 100644
index 0000000..7bf0a31
--- /dev/null
+++ b/misc/merge-ioq3-into-trem.sh
@@ -0,0 +1,112 @@
+#! /bin/bash
+# TODO Consider rewrite in perl/python to make this a bit less crappy
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+PATCHES_DIR=${DIR}/patches
+LAST_REVISION_FILE=${DIR}/last-merged-ioq3-revision
+LAST_REVISION_TEMP_FILE=${LAST_REVISION_FILE}.temp
+
+if [ -f ${LAST_REVISION_TEMP_FILE} ]
+then
+ LAST_REVISION=`cat ${LAST_REVISION_TEMP_FILE}`
+else
+ LAST_REVISION=`cat ${LAST_REVISION_FILE}`
+fi
+
+set -f
+# Things that exist in ioq3 which we don't want
+EXCLUSIONS="BUGS ChangeLog README ./*.txt
+ NOTTODO TODO misc/* *.mak src/cgame/*
+ src/game/* src/ui/* src/q3_ui/* src/botlib/* ui/*"
+
+EXCLUDE_PARAMETERS=""
+for EXCLUSION in ${EXCLUSIONS}
+do
+ EXCLUDE_PARAMETERS+="--exclude=${EXCLUSION} "
+done
+
+set +f
+
+PATCHES=`ls ${PATCHES_DIR}/*.patch 2> /dev/null`
+if [ -z "${PATCHES}" ]
+then
+ echo "Fetching and generating patches..."
+ git fetch https://github.com/ioquake/ioq3.git
+
+ mkdir -p ${PATCHES_DIR}
+ git format-patch -o ${PATCHES_DIR} ${LAST_REVISION}..FETCH_HEAD
+fi
+
+if [ -d ".git/rebase-apply" ]
+then
+ echo "Failed patch detected."
+
+ git diff --quiet --exit-code
+ if [ "$?" -ne 0 ]
+ then
+ echo "Unstaged changes present; git add any that are pending:"
+ git status
+ exit 1
+ fi
+
+ PATCH=`ls ${PATCHES_DIR}/*.patch | head -n 1`
+ SHA=`cat ${PATCH} | head -n 1 | awk '{print $2;}'`
+ echo "Processing ${SHA} ${PATCH}..."
+
+ DIFF=`git diff --cached`
+ if [ -z "${DIFF}" ]
+ then
+ echo "Patch does nothing; skipping."
+ read -p "Confirm skip? "
+ git am --skip
+ else
+ read -p "Confirm resolve? "
+ git am --resolved
+ fi
+
+ if [ "$?" -ne 0 ]
+ then
+ echo "Patch failed to apply."
+ exit $?
+ fi
+
+ echo ${SHA} > ${LAST_REVISION_TEMP_FILE}
+ rm ${PATCH}
+fi
+
+PATCHES=`ls ${PATCHES_DIR}/*.patch 2> /dev/null`
+if [ -n "${PATCHES}" ]
+then
+ for PATCH in ${PATCHES}
+ do
+ SHA=`cat ${PATCH} | head -n 1 | awk '{print $2;}'`
+ echo "Processing ${SHA} ${PATCH}..."
+ cat ${PATCH} | sed -e 's/\([ab]\)\/code\//\1\/src\//g' | \
+ git am ${EXCLUDE_PARAMETERS} --quiet --3way
+
+ if [ "$?" -ne 0 ]
+ then
+ echo "Patch failed to apply."
+ git status
+ exit $?
+ fi
+
+ echo ${SHA} > ${LAST_REVISION_TEMP_FILE}
+ rm ${PATCH}
+ done
+else
+ echo "Nothing to merge."
+fi
+
+# Finished merging so update the last revision marker
+if [ -f ${LAST_REVISION_TEMP_FILE} ]
+then
+ diff ${LAST_REVISION_FILE} ${LAST_REVISION_TEMP_FILE} &> /dev/null
+ if [ "$?" -ne 0 ]
+ then
+ mv ${LAST_REVISION_TEMP_FILE} ${LAST_REVISION_FILE}
+ LAST_REVISION=`cat ${LAST_REVISION_FILE}`
+ git add ${LAST_REVISION_FILE}
+ git commit -m "Merged ioq3 ${LAST_REVISION}"
+ fi
+fi
diff --git a/misc/msvc/tremulous.sln b/misc/msvc/tremulous.sln
new file mode 100644
index 0000000..8f52efc
--- /dev/null
+++ b/misc/msvc/tremulous.sln
@@ -0,0 +1,21 @@
+¿
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual C++ Express 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tremulous", "tremulous.vcproj", "{0D5316E4-B20F-4E09-8989-3B9064358F0C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0D5316E4-B20F-4E09-8989-3B9064358F0C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0D5316E4-B20F-4E09-8989-3B9064358F0C}.Debug|Win32.Build.0 = Debug|Win32
+ {0D5316E4-B20F-4E09-8989-3B9064358F0C}.Release|Win32.ActiveCfg = Release|Win32
+ {0D5316E4-B20F-4E09-8989-3B9064358F0C}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
+
diff --git a/misc/msvc/tremulous.vcproj b/misc/msvc/tremulous.vcproj
new file mode 100644
index 0000000..a592078
--- /dev/null
+++ b/misc/msvc/tremulous.vcproj
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="tremulous"
+ ProjectGUID="{0D5316E4-B20F-4E09-8989-3B9064358F0C}"
+ RootNamespace="tremulous"
+ Keyword="MakeFileProj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../build/$(ConfigurationName)-Win32-x86"
+ IntermediateDirectory="../../build/$(ConfigurationName)-Win32-x86"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="make -C ../../ debug"
+ ReBuildCommandLine="make -C ../../ clean-debug debug"
+ CleanCommandLine="make -C ../../ clean-debug"
+ Output="$(Outdir)/tremulous.x86.exe"
+ PreprocessorDefinitions=""
+ IncludeSearchPath=""
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../build/$(ConfigurationName)-Win32-x86"
+ IntermediateDirectory="../../build/$(ConfigurationName)-Win32-x86"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="make -C ../../ release"
+ ReBuildCommandLine="make -C ../../ clean-release release"
+ CleanCommandLine="make -C ../../ clean-release"
+ Output="$(Outdir)/tremulous.x86.exe"
+ PreprocessorDefinitions=""
+ IncludeSearchPath=""
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/misc/server.cfg b/misc/server.cfg
new file mode 100644
index 0000000..9cbff27
--- /dev/null
+++ b/misc/server.cfg
@@ -0,0 +1,39 @@
+//Example Tremulous 1.1 decicated server config
+
+set sv_pure 1
+
+//passwords
+set g_needpass 0
+//set g_password password //server password
+//set rconPassword password //rcon password
+
+//loading screen
+set sv_hostname "Tremulous 1.2.0 Server"
+set g_motd "http://tremulous.net/"
+
+//disallow downloads from the server
+set sv_allowdownload 0
+
+//maximum number of clients
+//greater than 24 is not recommended from a gameplay point of view
+set sv_maxclients 24
+
+//after 50 minutes, all build points are removed
+set g_suddenDeathTime 50
+//after 60 minutes, the game will end as a draw
+set timelimit 60
+
+//forces each team to have a similar number of players
+set g_teamForceBalance 1
+
+//following the first map, start this rotation
+set g_initialMapRotation rotation1
+
+//misc settings
+set pmove_fixed 0
+set sv_minRate 5000
+set sv_maxRate 15000
+set sv_minSnaps 10
+
+//start this map first
+map niveus
diff --git a/misc/travis-ci-build.sh b/misc/travis-ci-build.sh
new file mode 100644
index 0000000..9fc9bd0
--- /dev/null
+++ b/misc/travis-ci-build.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+P=$(uname | sed -e 's/_.*//' | tr '[:upper:]' '[:lower:]' | sed -e 's/\//_/g')
+PLATFORM=${PLATFORM:-$P}
+failed=0
+
+if [[ $PLATFORM == "darwin" ]]; then
+ rm -rf build
+ USE_FREETYPE=0 USE_RESTCLIENT=1 USE_INTERNAL_LUA=1 make -j 2 release || failed=1
+ ./misc/download-paks.sh
+fi
+
+if [[ $failed -eq 1 ]]; then
+ echo "Build failure."
+else
+ echo "Build successful."
+fi
+
+exit $failed
+
diff --git a/misc/tremulous-banner.jpg b/misc/tremulous-banner.jpg
new file mode 100644
index 0000000..407b07c
--- /dev/null
+++ b/misc/tremulous-banner.jpg
Binary files differ
diff --git a/misc/tremulous.ico b/misc/tremulous.ico
new file mode 100644
index 0000000..c1c847a
--- /dev/null
+++ b/misc/tremulous.ico
Binary files differ
diff --git a/misc/tremulous.xpm b/misc/tremulous.xpm
new file mode 100644
index 0000000..5e070c8
--- /dev/null
+++ b/misc/tremulous.xpm
@@ -0,0 +1,90 @@
+/* XPM */
+static char * tremulous_xpm[] = {
+"48 48 39 1",
+" c None",
+". c #0F0F0F",
+"+ c #181818",
+"@ c #000000",
+"# c #282828",
+"$ c #212121",
+"% c #060606",
+"& c #1D1D1D",
+"* c #252525",
+"= c #080808",
+"- c #0E0E0E",
+"; c #050505",
+"> c #0B0B0B",
+", c #0C0C0C",
+"' c #232323",
+") c #1F1F1F",
+"! c #030303",
+"~ c #0D0D0D",
+"{ c #040404",
+"] c #020202",
+"^ c #141414",
+"/ c #1E1E1E",
+"( c #131313",
+"_ c #111111",
+": c #010101",
+"< c #191919",
+"[ c #090909",
+"} c #292929",
+"| c #070707",
+"1 c #121212",
+"2 c #1B1B1B",
+"3 c #161616",
+"4 c #0A0A0A",
+"5 c #222222",
+"6 c #242424",
+"7 c #1A1A1A",
+"8 c #151515",
+"9 c #101010",
+"0 c #171717",
+" ",
+" ... ",
+" +@@@@@# ",
+" $@@@@@@% ",
+" &@@@@@@@@ * ",
+" =- ;@@@@@@@@> ,@- ",
+" @@' ;@@@@@@@@@ ,@@ ",
+" )@! ;@@@@@@@@@ ~@@; ",
+" ;@{ ]@@@@@@@@@~ ,@@; ",
+" ^@@] /@@@@@@@@@@@( -@@; ",
+" .@@; /@@@@@@@@@@@ -@@@/ ",
+" _@@] /@@@@@@@@@@@ #:@@@_ ",
+" @@@; /@@@@@@@@@@< :@@@- ",
+" :@@! ]@@@@@@@@@ @@@@- ",
+" $@@@; ;@@@@@@@@[ ~]@@@- ",
+" %@@@; }!@@@@@@@@- }|@@@@, ",
+" !@@@; 1@@@@@@@@@@ 2@@@@@~ ",
+" ;@@@% [@@@@@@@@@@@@@@@@, ",
+" @@@@{|||:@@@@@@@@@@@@@@!- ",
+" -@@@@@@@@@@@@@@@@@@@@@] ",
+" .@@@@@@@@@@@@@@@@@@@{ ",
+" ]@@@@@@@@@@@@@@@@@ ",
+" .@@@@@@@@@@@@@@@@ ",
+" +@@@@@@@@@@@@@@@@@@@@@@@@@@/ ",
+" =@@@@@@@@@@@@@@@@@@@@@@@@@/ ",
+" .=@@@@@@@@@@@@@@@@@@% ",
+" ,@@@@@@@@@@@@@@@@@@@@@ ",
+" 2>]@@@@@@@@@@@@@@@@@@@@@@@3 ",
+" *:@@@@@@@@@@@@@@@@@@@@@@@@@^ ",
+" @@@||| 4]@@@@@@@@@@@@@@@@@ ",
+" 556 _@@@@@@@@@@@@@@@@3 ",
+" >@@@@@@@@@@@@@@@@+ ",
+" ;@@@@@@@@@@@@@@@@@7 ",
+" &@@@@@@@@@@@@@@@@@@@+ ",
+" @@@@@@@@@@@@@@@@@@@@@/ ",
+" 8@@@@@@@@@@@@@@@[ =@@| ",
+" ;@@:::@@@@@@@@@[ %@@[ ",
+" @@9 (@@@@@@@4 =@@ ",
+" ,@@ {:@@: {@! ",
+" !@@ << 3@@0 ",
+" !@- 3@@6 ",
+" ]@( (@[ ",
+" 7@@ ]@ ",
+" 7@@ * ",
+" 7@} ",
+" 7@ ",
+" . ",
+" "};
diff --git a/scripts/README.md b/scripts/README.md
new file mode 100644
index 0000000..1da04b7
--- /dev/null
+++ b/scripts/README.md
@@ -0,0 +1,52 @@
+# Lua Scripts
+
+Scripts packaged with Tremulous. This folder will likely fill up with
+not so useful examples.
+
+Even more likely this will be the only source of documentation in the
+short term. Likely documentation will happen after the first large API
+re-organization.
+
+
+Available APIs
+==============
+
+HTTP Client
+-----------
+ - `http.del()`
+ - `http.get()`
+ - `http.post()`
+ - `http.put()`
+
+ Returns a `HttpResponse` object.
+
+```lua
+ HttpResponse::code -- HTTP status code from server
+ HttpResponse::body -- Raw response body
+```
+
+### Example
+```lua
+ print(http.get('www.google.com/search?q=' .. 'Hello World').body)
+```
+
+JSON
+----
+
+ - `rapidjson.encode()`
+ - `rapidjson.decode()`
+
+Cvar
+----
+
+ - `cvar.new(a, b, c)`
+ - `cvar.new(a, b)`
+ - `cvar.new(a)`
+
+Nettle
+------
+TBD
+
+Client
+------
+TBD
diff --git a/scripts/binds.lua b/scripts/binds.lua
new file mode 100644
index 0000000..9194b7d
--- /dev/null
+++ b/scripts/binds.lua
@@ -0,0 +1,77 @@
+--[[
+-- Key binds specified in Lua
+--]]
+
+
+player = {
+ team = cvar.new('team_teamname'),
+ stage = cvar.new('team_stage'),
+ hp = cvar.new('player_hp'),
+ kns = cvar.new('team_kns'),
+ spawns = cvar.new('team_spawns'),
+ bp = cvar.new('team_bp'),
+ maxbp = cvar.new('player_maxbp'),
+ credits = cvar.new('player_credits'),
+ score = cvar.new('player_score'),
+ deaths = cvar.new('player_deaths')
+}
+
+alien = {
+ kns = cvar.new('alien_kns'),
+ score = cvar.new('alien_score')
+}
+
+human = {
+ kns = cvar.new('human_kns'),
+ score = cvar.new('human_score')
+}
+
+function TeamSay(text)
+ client.addReliableCommand('say_team ' .. text)
+end
+
+function Screenshot()
+ draw2D = cvar.new('cg_draw2d')
+ drawGun = cvar.new('cg_drawgun')
+ _a = draw2D.value
+ _b = drawGun.value
+
+ draw2D.value = 0
+ drawGun.value = 0
+
+ client.addReliableCommand('wait 2; screenshotJPEG silent')
+
+ draw2D.value = _a
+ drawGun.value = _b
+end
+
+binds = {
+ a = bind.new('a', "teamstatus"),
+ b = bind.new('b', "script TeamSay('^5Humans have ^1' .. human.score.value .. ' ^2Aliens have ^1' .. alien.score.value)"),
+ c = bind.new('c', "script TeamSay('^5MOVE!!! I only have ^1' .. player.hp.value .. '^5HP Available')"),
+ d = bind.new('d'),
+ e = bind.new('e'),
+ f = bind.new('f'),
+ g = bind.new('g'),
+ h = bind.new('h', "buy ammo"),
+ i = bind.new('i', "+forward"),
+ j = bind.new('j', "+moveleft"),
+ k = bind.new('k', "+back"),
+ l = bind.new('l', "+moveright"),
+ m = bind.new('m', "itemact medkit"),
+ n = bind.new('n', "+button8"),
+ o = bind.new('o'),
+ p = bind.new('p'),
+ q = bind.new('q'),
+ r = bind.new('r'),
+ s = bind.new('s'),
+ t = bind.new('t'),
+ u = bind.new('u'),
+ v = bind.new('v'),
+ w = bind.new('w'),
+ x = bind.new('x'),
+ y = bind.new('y'),
+ z = bind.new('z', "screenshotJPEG silent"),
+
+ f12 = bind.new('f12', "cg_draw2d ")
+}
diff --git a/scripts/granger/lib/init.lua b/scripts/granger/lib/init.lua
new file mode 100644
index 0000000..9158d0b
--- /dev/null
+++ b/scripts/granger/lib/init.lua
@@ -0,0 +1,5 @@
+require "lib.os"
+require "lib.path"
+require "lib.string"
+require "lib.table"
+require "lib.log"
diff --git a/scripts/granger/lib/os.lua b/scripts/granger/lib/os.lua
new file mode 100644
index 0000000..66941a7
--- /dev/null
+++ b/scripts/granger/lib/os.lua
@@ -0,0 +1,222 @@
+--
+-- os.lua
+-- Additions to the OS namespace.
+-- Copyright (c) 2002-2011 Jason Perkins and the Premake project
+-- Copyright (c) 2015 Jeff Kent <jeff@jkent.net>
+--
+
+
+--
+-- Retrieve the current operating system ID string.
+--
+
+ function os.get()
+ return _OS
+ end
+
+
+
+--
+-- Check the current operating system.
+--
+
+ function os.is(id)
+ return (os.get():lower() == id:lower())
+ end
+
+
+
+--
+-- Determine if the current system is running a 64-bit architecture
+--
+
+ local _64BitHostTypes = {
+ "x86_64",
+ "ia64",
+ "amd64",
+ "ppc64",
+ "powerpc64",
+ "sparc64"
+ }
+
+ function os.is64bit()
+ -- Call the native code implementation. If this returns true then
+ -- we're 64-bit, otherwise do more checking locally
+ if (os._is64bit()) then
+ return true
+ end
+
+ -- Identify the system
+ local arch
+ if _OS == "windows" then
+ arch = os.getenv("PROCESSOR_ARCHITECTURE")
+ elseif _OS == "macosx" then
+ arch = os.outputof("echo $HOSTTYPE")
+ else
+ arch = os.outputof("uname -m")
+ end
+
+ -- Check our known 64-bit identifiers
+ arch = arch:lower()
+ for _, hosttype in ipairs(_64BitHostTypes) do
+ if arch:find(hosttype) then
+ return true
+ end
+ end
+ return false
+ end
+
+
+
+--
+-- The os.matchdirs() and os.matchfiles() functions
+--
+
+ local function domatch(result, mask, wantfiles)
+ -- need to remove extraneous path info from the mask to ensure a match
+ -- against the paths returned by the OS. Haven't come up with a good
+ -- way to do it yet, so will handle cases as they come up
+ if mask:startswith("./") then
+ mask = mask:sub(3)
+ end
+
+ -- strip off any leading directory information to find out
+ -- where the search should take place
+ local basedir = mask
+ local starpos = mask:find("%*")
+ if starpos then
+ basedir = basedir:sub(1, starpos - 1)
+ end
+ basedir = path.getdirectory(basedir)
+ if (basedir == ".") then basedir = "" end
+
+ -- recurse into subdirectories?
+ local recurse = mask:find("**", nil, true)
+
+ -- convert mask to a Lua pattern
+ mask = path.wildcards(mask)
+
+ local function matchwalker(basedir)
+ local wildcard = path.join(basedir, "*")
+
+ -- retrieve files from OS and test against mask
+ local m = os.matchstart(wildcard)
+ while (os.matchnext(m)) do
+ local isfile = os.matchisfile(m)
+ if ((wantfiles and isfile) or (not wantfiles and not isfile)) then
+ local basename = os.matchname(m)
+ local fullname = path.join(basedir, basename)
+ if basename ~= ".." and fullname:match(mask) == fullname then
+ table.insert(result, fullname)
+ end
+ end
+ end
+ os.matchdone(m)
+
+ -- check subdirectories
+ if recurse then
+ m = os.matchstart(wildcard)
+ while (os.matchnext(m)) do
+ if not os.matchisfile(m) then
+ local dirname = os.matchname(m)
+ if (not dirname:startswith(".")) then
+ matchwalker(path.join(basedir, dirname))
+ end
+ end
+ end
+ os.matchdone(m)
+ end
+ end
+
+ matchwalker(basedir)
+ end
+
+ function os.matchdirs(...)
+ local result = { }
+ for _, mask in ipairs(arg) do
+ domatch(result, mask, false)
+ end
+ return result
+ end
+
+ function os.matchfiles(...)
+ local result = { }
+ for _, mask in ipairs(arg) do
+ domatch(result, mask, true)
+ end
+ return result
+ end
+
+
+
+--
+-- An overload of the os.mkdir() function, which will create any missing
+-- subdirectories along the path.
+--
+
+ local builtin_mkdir = os.mkdir
+ function os.mkdir(p)
+ local dir = iif(p:startswith("/"), "/", "")
+ for part in p:gmatch("[^/]+") do
+ dir = dir .. part
+
+ if (part ~= "" and not path.isabsolute(part) and not os.isdir(dir)) then
+ local ok, err = builtin_mkdir(dir)
+ if (not ok) then
+ return nil, err
+ end
+ end
+
+ dir = dir .. "/"
+ end
+
+ return true
+ end
+
+
+--
+-- Run a shell command and return the output.
+--
+
+ function os.outputof(cmd)
+ local pipe = io.popen(cmd)
+ local result = pipe:read('*a')
+ pipe:close()
+ return result
+ end
+
+
+--
+-- Remove a directory, along with any contained files or subdirectories.
+--
+
+ local builtin_rmdir = os.rmdir
+ function os.rmdir(p)
+ -- recursively remove subdirectories
+ local dirs = os.matchdirs(p .. "/*")
+ for _, dname in ipairs(dirs) do
+ os.rmdir(dname)
+ end
+
+ -- remove any files
+ local files = os.matchfiles(p .. "/*")
+ for _, fname in ipairs(files) do
+ os.remove(fname)
+ end
+
+ -- remove this directory
+ builtin_rmdir(p)
+ end
+
+
+--
+-- Elevate and set _ELEVATED global
+--
+
+ _ENV._ELEVATED = false
+ local builtin_elevate = os.elevate
+ function os.elevate()
+ _ENV._ELEVATED = builtin_elevate()
+ return _ENV._ELEVATED
+ end
+
diff --git a/scripts/granger/lib/path.lua b/scripts/granger/lib/path.lua
new file mode 100644
index 0000000..7bf4b2b
--- /dev/null
+++ b/scripts/granger/lib/path.lua
@@ -0,0 +1,137 @@
+--
+-- path.lua
+-- Path manipulation functions.
+-- Copyright (c) 2002-2010 Jason Perkins and the Premake project
+--
+
+
+--
+-- Retrieve the filename portion of a path, without any extension.
+--
+
+ function path.getbasename(p)
+ local name = path.getname(p)
+ local i = name:findlast(".", true)
+ if (i) then
+ return name:sub(1, i - 1)
+ else
+ return name
+ end
+ end
+
+
+--
+-- Retrieve the directory portion of a path, or an empty string if
+-- the path does not include a directory.
+--
+
+ function path.getdirectory(p)
+ local i = p:findlast("/", true)
+ if (i) then
+ if i > 1 then i = i - 1 end
+ return p:sub(1, i)
+ else
+ return "."
+ end
+ end
+
+
+--
+-- Retrieve the drive letter, if a Windows path.
+--
+
+ function path.getdrive(p)
+ local ch1 = p:sub(1,1)
+ local ch2 = p:sub(2,2)
+ if ch2 == ":" then
+ return ch1
+ end
+ end
+
+
+
+--
+-- Retrieve the file extension.
+--
+
+ function path.getextension(p)
+ local i = p:findlast(".", true)
+ if (i) then
+ return p:sub(i)
+ else
+ return ""
+ end
+ end
+
+
+
+--
+-- Retrieve the filename portion of a path.
+--
+
+ function path.getname(p)
+ local i = p:findlast("[/\\]")
+ if (i) then
+ return p:sub(i + 1)
+ else
+ return p
+ end
+ end
+
+
+--
+-- Takes a path which is relative to one location and makes it relative
+-- to another location instead.
+--
+
+ function path.rebase(p, oldbase, newbase)
+ p = path.getabsolute(path.join(oldbase, p))
+ p = path.getrelative(newbase, p)
+ return p
+ end
+
+
+--
+-- Convert the separators in a path from one form to another. If `sep`
+-- is nil, then a platform-specific separator is used.
+--
+
+ local builtin_translate = path.translate
+
+ function path.translate(p, sep)
+ if not sep then
+ if os.is("windows") then
+ sep = "\\"
+ else
+ sep = "/"
+ end
+ end
+ return builtin_translate(p, sep)
+ end
+
+
+--
+-- Converts from a simple wildcard syntax, where * is "match any"
+-- and ** is "match recursive", to the corresponding Lua pattern.
+--
+-- @param pattern
+-- The wildcard pattern to convert.
+-- @returns
+-- The corresponding Lua pattern.
+--
+
+ function path.wildcards(pattern)
+ -- Escape characters that have special meanings in Lua patterns
+ pattern = pattern:gsub("([%+%.%-%^%$%(%)%%])", "%%%1")
+
+ -- Replace wildcard patterns with special placeholders so I don't
+ -- have competing star replacements to worry about
+ pattern = pattern:gsub("%*%*", "\001")
+ pattern = pattern:gsub("%*", "\002")
+
+ -- Replace the placeholders with their Lua patterns
+ pattern = pattern:gsub("\001", ".*")
+ pattern = pattern:gsub("\002", "[^/]*")
+
+ return pattern
+ end
diff --git a/scripts/granger/lib/string.lua b/scripts/granger/lib/string.lua
new file mode 100644
index 0000000..56fae4d
--- /dev/null
+++ b/scripts/granger/lib/string.lua
@@ -0,0 +1,50 @@
+--
+-- string.lua
+-- Additions to Lua's built-in string functions.
+-- Copyright (c) 2002-2008 Jason Perkins and the Premake project
+--
+
+
+--
+-- Returns an array of strings, each of which is a substring of s
+-- formed by splitting on boundaries formed by `pattern`.
+--
+
+ function string.explode(s, pattern, plain)
+ if (pattern == '') then return false end
+ local pos = 0
+ local arr = { }
+ for st,sp in function() return s:find(pattern, pos, plain) end do
+ table.insert(arr, s:sub(pos, st-1))
+ pos = sp + 1
+ end
+ table.insert(arr, s:sub(pos))
+ return arr
+ end
+
+
+
+--
+-- Find the last instance of a pattern in a string.
+--
+
+ function string.findlast(s, pattern, plain)
+ local curr = 0
+ repeat
+ local next = s:find(pattern, curr + 1, plain)
+ if (next) then curr = next end
+ until (not next)
+ if (curr > 0) then
+ return curr
+ end
+ end
+
+
+
+--
+-- Returns true if `haystack` starts with the sequence `needle`.
+--
+
+ function string.startswith(haystack, needle)
+ return (haystack:find(needle, 1, true) == 1)
+ end
diff --git a/scripts/granger/lib/table.lua b/scripts/granger/lib/table.lua
new file mode 100644
index 0000000..3076cb0
--- /dev/null
+++ b/scripts/granger/lib/table.lua
@@ -0,0 +1,181 @@
+--
+-- table.lua
+-- Additions to Lua's built-in table functions.
+-- Copyright (c) 2002-2008 Jason Perkins and the Premake project
+--
+
+
+--
+-- Returns true if the table contains the specified value.
+--
+
+ function table.contains(t, value)
+ for _,v in pairs(t) do
+ if (v == value) then
+ return true
+ end
+ end
+ return false
+ end
+
+
+--
+-- Enumerates an array of objects and returns a new table containing
+-- only the value of one particular field.
+--
+
+ function table.extract(arr, fname)
+ local result = { }
+ for _,v in ipairs(arr) do
+ table.insert(result, v[fname])
+ end
+ return result
+ end
+
+
+
+--
+-- Flattens a hierarchy of tables into a single array containing all
+-- of the values.
+--
+
+ function table.flatten(arr)
+ local result = { }
+
+ local function flatten(arr)
+ for _, v in ipairs(arr) do
+ if type(v) == "table" then
+ flatten(v)
+ else
+ table.insert(result, v)
+ end
+ end
+ end
+
+ flatten(arr)
+ return result
+ end
+
+
+--
+-- Merges an array of items into a string.
+--
+
+ function table.implode(arr, before, after, between)
+ local result = ""
+ for _,v in ipairs(arr) do
+ if (result ~= "" and between) then
+ result = result .. between
+ end
+ result = result .. before .. v .. after
+ end
+ return result
+ end
+
+
+--
+-- Inserts a value of array of values into a table. If the value is
+-- itself a table, its contents are enumerated and added instead. So
+-- these inputs give these outputs:
+--
+-- "x" -> { "x" }
+-- { "x", "y" } -> { "x", "y" }
+-- { "x", { "y" }} -> { "x", "y" }
+--
+
+ function table.insertflat(tbl, values)
+ if type(values) == "table" then
+ for _, value in ipairs(values) do
+ table.insertflat(tbl, value)
+ end
+ else
+ table.insert(tbl, values)
+ end
+ end
+
+
+--
+-- Returns true if the table is empty, and contains no indexed or keyed values.
+--
+
+ function table.isempty(t)
+ return next(t) == nil
+ end
+
+
+--
+-- Adds the values from one array to the end of another and
+-- returns the result.
+--
+
+ function table.join(...)
+ local result = { }
+ for _,t in ipairs(arg) do
+ if type(t) == "table" then
+ for _,v in ipairs(t) do
+ table.insert(result, v)
+ end
+ else
+ table.insert(result, t)
+ end
+ end
+ return result
+ end
+
+
+--
+-- Return a list of all keys used in a table.
+--
+
+ function table.keys(tbl)
+ local keys = {}
+ for k, _ in pairs(tbl) do
+ table.insert(keys, k)
+ end
+ return keys
+ end
+
+
+--
+-- Adds the key-value associations from one table into another
+-- and returns the resulting merged table.
+--
+
+ function table.merge(...)
+ local result = { }
+ for _,t in ipairs(arg) do
+ if type(t) == "table" then
+ for k,v in pairs(t) do
+ result[k] = v
+ end
+ else
+ error("invalid value")
+ end
+ end
+ return result
+ end
+
+
+
+--
+-- Translates the values contained in array, using the specified
+-- translation table, and returns the results in a new array.
+--
+
+ function table.translate(arr, translation)
+ local result = { }
+ for _, value in ipairs(arr) do
+ local tvalue
+ if type(translation) == "function" then
+ tvalue = translation(value)
+ else
+ tvalue = translation[value]
+ end
+ if (tvalue) then
+ table.insert(result, tvalue)
+ end
+ end
+ return result
+ end
+
+ \ No newline at end of file
diff --git a/scripts/granger/main.lua b/scripts/granger/main.lua
new file mode 100644
index 0000000..304f45a
--- /dev/null
+++ b/scripts/granger/main.lua
@@ -0,0 +1,63 @@
+--
+-- main.lua
+-- Granger main
+-- Copyright (c) 2016 Jeff Kent <jeff@jkent.net>
+--
+
+require 'scripts/granger/lib'
+
+local install_files = {}
+
+if os.is('windows') then
+ install_files = {
+ "tremulous.exe"
+ "tremded.exe"
+ "granger.exe"
+ "SDL264.dll"
+ "renderer_opengl1.dll"
+ "renderer_opengl2.dll"
+ }
+elseif os.is('linux') then
+ install_files = {
+ "tremulous"
+ "tremded"
+ "granger"
+ "renderer_opengl1.so"
+ "renderer_opengl2.so"
+ }
+elseif os.is('macosx') then
+ install_files = {
+ "tremulous"
+ "tremded"
+ "granger"
+ "libSDL2-2.0.0.dylib"
+ "renderer_opengl1.dylib"
+ "renderer_opengl2.dylib"
+ }
+else
+ os.exit(1)
+end
+
+local dst_dir = path.getdirectory('.')
+local dst_dir = path.getdirectory(_EXE_PATH)
+
+local privs = false
+for file in ipairs(install_files) do
+ local src = path.join(src_dir, file)
+ local dst = path.join(dst_dir, file)
+ if not os.access(dst, 'w') then
+ privs = true
+ end
+end
+
+if privs then
+ os.elevate()
+end
+
+for file in ipairs(install_files) do
+ local src = path.join(src_dir, file)
+ local dst = path.join(dst_dir, file)
+ os.rename(src, dst)
+end
+
+--- Copyright (C) 2015-2019 GrangerHub
diff --git a/scripts/granger/util.lua b/scripts/granger/util.lua
new file mode 100644
index 0000000..77dc476
--- /dev/null
+++ b/scripts/granger/util.lua
@@ -0,0 +1,28 @@
+--
+-- util.lua
+-- various utility functions
+-- Copyright (c) 2016 Jeff Kent <jeff@jkent.net>
+--
+
+local function hash_file(file, ctx)
+ local f = io.open(file, "r")
+ if f == nil then
+ return nil
+ end
+ repeat
+ local buf = f:read(0x10000)
+ ctx:update(buf)
+ until buf == nil
+ f:close()
+ return tostring(ctx)
+end
+
+function sha256_file(file)
+ local ctx = nettle.sha256()
+ return hash_file(file, ctx)
+end
+
+function md5_file(file)
+ local ctx = nettle.md5()
+ return hash_file(file, ctx)
+end
diff --git a/scripts/http.lua b/scripts/http.lua
new file mode 100644
index 0000000..adc565e
--- /dev/null
+++ b/scripts/http.lua
@@ -0,0 +1,40 @@
+
+
+cl_latestRelease = cvar.new("cl_latestRelease")
+
+dlurl = ""
+
+Releases = {
+ url='https://api.github.com/repos/GrangerHub/tremulous/releases'
+
+ refresh = function()
+ r = http.get(url)
+ if r.code != 200 then
+ cl_latestRelease = "ERROR:\n Server did not return OK status code"
+ return false
+ end
+ releases = rapidjson.decode(r.body)
+ most_recent = releases[1]
+ cl_latestRelease = most_recent.tag;
+ for i,asset in ipairs(most_recent.assets) do
+ dlurl = cvar.new("download_url", "", 256)
+ dlurl = asset.browser_download_url
+ end
+ return true
+ end
+
+ download = function()
+ r = http.get(download_url)
+ if r.code != 200 then
+ cvar.new("com_error") = "Download failed"
+ return false
+ end
+
+ io.open(path, "w+")
+ io.write(r.body)
+ io.close()
+
+ args = "path-to-tremulous-binary"
+ os.execute(path .. args)
+ end
+}
diff --git a/scripts/inspect.lua b/scripts/inspect.lua
new file mode 100644
index 0000000..892d91b
--- /dev/null
+++ b/scripts/inspect.lua
@@ -0,0 +1,218 @@
+-----------------------------------------------------------------------------------------------------------------------
+-- inspect.lua - v1.1.1 (2011-01)
+-- Enrique García Cota - enrique.garcia.cota [AT] gmail [DOT] com
+-- human-readable representations of tables.
+-- inspired by http://lua-users.org/wiki/TableSerialization
+-----------------------------------------------------------------------------------------------------------------------
+
+-- Apostrophizes the string if it has quotes, but not aphostrophes
+-- Otherwise, it returns a regular quoted string
+local function smartQuote(str)
+ if string.match( string.gsub(str,"[^'\"]",""), '^"+$' ) then
+ return "'" .. str .. "'"
+ end
+ return string.format("%q", str )
+end
+
+local controlCharsTranslation = {
+ ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n",
+ ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v", ["\\"] = "\\\\"
+}
+
+local function unescapeChar(c) return controlCharsTranslation[c] end
+
+local function unescape(str)
+ local result, _ = string.gsub( str, "(%c)", unescapeChar )
+ return result
+end
+
+local function isIdentifier(str)
+ return string.match( str, "^[_%a][_%a%d]*$" )
+end
+
+local function isArrayKey(k, length)
+ return type(k)=='number' and 1 <= k and k <= length
+end
+
+local function isDictionaryKey(k, length)
+ return not isArrayKey(k, length)
+end
+
+local sortOrdersByType = {
+ ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4,
+ ['function'] = 5, ['userdata'] = 6, ['thread'] = 7
+}
+
+local function sortKeys(a,b)
+ local ta, tb = type(a), type(b)
+ if ta ~= tb then return sortOrdersByType[ta] < sortOrdersByType[tb] end
+ if ta == 'string' or ta == 'number' then return a < b end
+ return false
+end
+
+local function getDictionaryKeys(t)
+ local length = #t
+ local keys = {}
+ for k,_ in pairs(t) do
+ if isDictionaryKey(k, length) then table.insert(keys,k) end
+ end
+ table.sort(keys, sortKeys)
+ return keys
+end
+
+local function getToStringResultSafely(t, mt)
+ local __tostring = type(mt) == 'table' and mt.__tostring
+ local string, status
+ if type(__tostring) == 'function' then
+ status, string = pcall(__tostring, t)
+ string = status and string or 'error: ' .. tostring(string)
+ end
+ return string
+end
+
+local Inspector = {}
+
+function Inspector:new(v, depth)
+ local inspector = {
+ buffer = {},
+ depth = depth,
+ level = 0,
+ counters = {
+ ['function'] = 0,
+ ['userdata'] = 0,
+ ['thread'] = 0,
+ ['table'] = 0
+ },
+ pools = {
+ ['function'] = setmetatable({}, {__mode = "kv"}),
+ ['userdata'] = setmetatable({}, {__mode = "kv"}),
+ ['thread'] = setmetatable({}, {__mode = "kv"}),
+ ['table'] = setmetatable({}, {__mode = "kv"})
+ }
+ }
+
+ setmetatable( inspector, {
+ __index = Inspector,
+ __tostring = function(instance) return table.concat(instance.buffer) end
+ } )
+ return inspector:putValue(v)
+end
+
+function Inspector:puts(...)
+ local args = {...}
+ for i=1, #args do
+ table.insert(self.buffer, tostring(args[i]))
+ end
+ return self
+end
+
+function Inspector:tabify()
+ self:puts("\n", string.rep(" ", self.level))
+ return self
+end
+
+function Inspector:up()
+ self.level = self.level - 1
+end
+
+function Inspector:down()
+ self.level = self.level + 1
+end
+
+function Inspector:putComma(comma)
+ if comma then self:puts(',') end
+ return true
+end
+
+function Inspector:putTable(t)
+ if self:alreadySeen(t) then
+ self:puts('<table ', self:getOrCreateCounter(t), '>')
+ elseif self.level >= self.depth then
+ self:puts('{...}')
+ else
+ self:puts('<',self:getOrCreateCounter(t),'>{')
+ self:down()
+
+ local length = #t
+ local mt = getmetatable(t)
+
+ local string = getToStringResultSafely(t, mt)
+ if type(string) == 'string' and #string > 0 then
+ self:puts(' -- ', unescape(string))
+ if length >= 1 then self:tabify() end -- tabify the array values
+ end
+
+ local comma = false
+ for i=1, length do
+ comma = self:putComma(comma)
+ self:puts(' '):putValue(t[i])
+ end
+
+ local dictKeys = getDictionaryKeys(t)
+
+ for _,k in ipairs(dictKeys) do
+ comma = self:putComma(comma)
+ self:tabify():putKey(k):puts(' = '):putValue(t[k])
+ end
+
+ if mt then
+ comma = self:putComma(comma)
+ self:tabify():puts('<metatable> = '):putValue(mt)
+ end
+ self:up()
+
+ if #dictKeys > 0 or mt then -- dictionary table. Justify closing }
+ self:tabify()
+ elseif length > 0 then -- array tables have one extra space before closing }
+ self:puts(' ')
+ end
+ self:puts('}')
+ end
+ return self
+end
+
+function Inspector:alreadySeen(v)
+ local tv = type(v)
+ return self.pools[tv][v] ~= nil
+end
+
+function Inspector:getOrCreateCounter(v)
+ local tv = type(v)
+ local current = self.pools[tv][v]
+ if not current then
+ current = self.counters[tv] + 1
+ self.counters[tv] = current
+ self.pools[tv][v] = current
+ end
+ return current
+end
+
+function Inspector:putValue(v)
+ local tv = type(v)
+
+ if tv == 'string' then
+ self:puts(smartQuote(unescape(v)))
+ elseif tv == 'number' or tv == 'boolean' or tv == 'nil' then
+ self:puts(tostring(v))
+ elseif tv == 'table' then
+ self:putTable(v)
+ else
+ self:puts('<',tv,' ',self:getOrCreateCounter(v),'>')
+ end
+ return self
+end
+
+function Inspector:putKey(k)
+ if type(k) == "string" and isIdentifier(k) then
+ return self:puts(k)
+ end
+ return self:puts( "[" ):putValue(k):puts("]")
+end
+
+local function inspect(t, depth)
+ depth = depth or 4
+ return tostring(Inspector:new(t, depth))
+end
+
+return inspect
+
diff --git a/scripts/sample-httpjson-client.lua b/scripts/sample-httpjson-client.lua
new file mode 100644
index 0000000..a733f95
--- /dev/null
+++ b/scripts/sample-httpjson-client.lua
@@ -0,0 +1,37 @@
+--[[
+ _____ _ _
+|_ _| __ ___ _ __ ___ _ _| | ___ _ _ ___ | | _ _ __ _
+ | || '__/ _ \ '_ ` _ \| | | | |/ _ \| | | / __|_____| | | | | |/ _` |
+ | || | | __/ | | | | | |_| | | (_) | |_| \__ \_____| |__| |_| | (_| |
+ |_||_| \___|_| |_| |_|\__,_|_|\___/ \__,_|___/ |_____\__,_|\__,_|
+ Victor Roemer [WTFBBQHAX]
+ Nov. 03, 2016 10:53:27AM EST
+ A sample Restful JSON Client API.
+ This sample demonstrates how to comunicate with an HTTP JSON 3rdparty
+ API in Lua script.
+ APIs demonstrated:
+ * HTTP RestClient
+ * JSON
+--]]
+
+-- GitHub API URL
+url='https://api.github.com/repos/GrangerHub/tremulous/releases'
+
+-- HTTP Get request- retrieve the raw JSON response
+txt = http.get(url)
+assert(txt.code == 200)
+
+-- Decode raw JSON response into a Lua table
+releases = rapidjson.decode(txt.body)
+
+-- GitHub returned an array of releases- The "most_recent" is item 1
+-- NOTE: Lua array indexing starts at `1` not `0`!!
+most_recent = releases[1]
+
+-- FIXME: Remove hardcoded tag_name in this test
+assert(most_recent.tag_name == "Oct-22-2016")
+
+
+for i,asset in ipairs(most_recent.assets) do
+ print(asset.browser_download_url)
+end
diff --git a/scripts/test-nettle.lua b/scripts/test-nettle.lua
new file mode 100644
index 0000000..09a96be
--- /dev/null
+++ b/scripts/test-nettle.lua
@@ -0,0 +1,24 @@
+print "nettle tests begin"
+
+empty_hash = tostring(nettle.sha256())
+
+ctx = nettle.sha256()
+ctx:update(nil)
+assert(empty_hash == tostring(ctx))
+
+ctx = nettle.sha256()
+ctx:update("Hello World!")
+ctx:update("Hello World!")
+hash = tostring(ctx)
+assert(hash == "95a5a79bf6218dd0938950acb61bca24d5809172fe6cfd7f1af4b059449e52f8")
+
+ctx = nettle.sha256()
+ctx:update("Hello World!Hello World!")
+hash = tostring(ctx)
+assert(hash == "95a5a79bf6218dd0938950acb61bca24d5809172fe6cfd7f1af4b059449e52f8")
+
+require "util"
+hash = hash_file("../../COPYING")
+assert(hash == "8177f97513213526df2cf6184d8ff986c675afb514d4e68a404010521b880643")
+
+print "nettle tests completed"
diff --git a/src/asm/matha.s b/src/asm/matha.s
new file mode 100644
index 0000000..7bdff0a
--- /dev/null
+++ b/src/asm/matha.s
@@ -0,0 +1,55 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+//
+// math.s
+// x86 assembly-language math routines.
+
+#include "qasm.h"
+
+
+#if id386
+
+ .text
+
+// TODO: rounding needed?
+// stack parameter offset
+#define val 4
+
+.globl C(Invert24To16)
+C(Invert24To16):
+
+ movl val(%esp),%ecx
+ movl $0x100,%edx // 0x10000000000 as dividend
+ cmpl %edx,%ecx
+ jle LOutOfRange
+
+ subl %eax,%eax
+ divl %ecx
+
+ ret
+
+LOutOfRange:
+ movl $0xFFFFFFFF,%eax
+ ret
+
+#endif // id386
diff --git a/src/asm/qasm-inline.h b/src/asm/qasm-inline.h
new file mode 100644
index 0000000..ed30ce6
--- /dev/null
+++ b/src/asm/qasm-inline.h
@@ -0,0 +1,41 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#ifndef __ASM_INLINE_I386__
+#define __ASM_INLINE_I386__
+
+#include "qcommon/q_platform.h"
+
+#if idx64
+ #define EAX "%%rax"
+ #define EBX "%%rbx"
+ #define ESP "%%rsp"
+ #define EDI "%%rdi"
+#else
+ #define EAX "%%eax"
+ #define EBX "%%ebx"
+ #define ESP "%%esp"
+ #define EDI "%%edi"
+#endif
+
+#endif
diff --git a/src/asm/qasm.h b/src/asm/qasm.h
new file mode 100644
index 0000000..8fbb6ee
--- /dev/null
+++ b/src/asm/qasm.h
@@ -0,0 +1,39 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#ifndef __ASM_I386__
+#define __ASM_I386__
+
+#include "qcommon/q_platform.h"
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",@progbits
+#endif
+
+#if defined(__ELF__) || defined(__WIN64__)
+#define C(label) label
+#else
+#define C(label) _##label
+#endif
+
+#endif
diff --git a/src/asm/snapvector.asm b/src/asm/snapvector.asm
new file mode 100644
index 0000000..aa5052a
--- /dev/null
+++ b/src/asm/snapvector.asm
@@ -0,0 +1,91 @@
+; ===========================================================================
+; Copyright (C) 2011 Thilo Schulz <thilo@tjps.eu>
+; Copyright (C) 2015-2019 GrangerHub
+;
+; This file is part of Tremulous.
+;
+; Tremulous is free software; you can redistribute it
+; and/or modify it under the terms of the GNU General Public License as
+; published by the Free Software Foundation; either version 3 of the License,
+; or (at your option) any later version.
+;
+; Tremulous is distributed in the hope that it will be
+; useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+;
+; ===========================================================================
+
+; MASM version of snapvector conversion function using SSE or FPU
+; assume __cdecl calling convention is being used for x86, __fastcall for x64
+;
+; function prototype:
+; void qsnapvector(vec3_t vec)
+
+IFNDEF idx64
+.686p
+.xmm
+.model flat, c
+ENDIF
+
+.data
+
+ ALIGN 16
+ ssemask DWORD 0FFFFFFFFh, 0FFFFFFFFh, 0FFFFFFFFh, 00000000h
+ ssecw DWORD 00001F80h
+
+.code
+
+IFDEF idx64
+; qsnapvector using SSE
+
+ qsnapvectorsse PROC
+ movaps xmm1, ssemask ; initialize the mask register
+ movups xmm0, [rcx] ; here is stored our vector. Read 4 values in one go
+ movaps xmm2, xmm0 ; keep a copy of the original data
+ andps xmm0, xmm1 ; set the fourth value to zero in xmm0
+ andnps xmm1, xmm2 ; copy fourth value to xmm1 and set rest to zero
+ cvtps2dq xmm0, xmm0 ; convert 4 single fp to int
+ cvtdq2ps xmm0, xmm0 ; convert 4 int to single fp
+ orps xmm0, xmm1 ; combine all 4 values again
+ movups [rcx], xmm0 ; write 3 rounded and 1 unchanged values back to memory
+ ret
+ qsnapvectorsse ENDP
+
+ELSE
+
+ qsnapvectorsse PROC
+ mov eax, dword ptr 4[esp] ; store address of vector in eax
+ movaps xmm1, ssemask ; initialize the mask register for maskmovdqu
+ movups xmm0, [eax] ; here is stored our vector. Read 4 values in one go
+ movaps xmm2, xmm0 ; keep a copy of the original data
+ andps xmm0, xmm1 ; set the fourth value to zero in xmm0
+ andnps xmm1, xmm2 ; copy fourth value to xmm1 and set rest to zero
+ cvtps2dq xmm0, xmm0 ; convert 4 single fp to int
+ cvtdq2ps xmm0, xmm0 ; convert 4 int to single fp
+ orps xmm0, xmm1 ; combine all 4 values again
+ movups [eax], xmm0 ; write 3 rounded and 1 unchanged values back to memory
+ ret
+ qsnapvectorsse ENDP
+
+ qroundx87 macro src
+ fld dword ptr src
+ fistp dword ptr src
+ fild dword ptr src
+ fstp dword ptr src
+ endm
+
+ qsnapvectorx87 PROC
+ mov eax, dword ptr 4[esp]
+ qroundx87 [eax]
+ qroundx87 4[eax]
+ qroundx87 8[eax]
+ ret
+ qsnapvectorx87 ENDP
+
+ENDIF
+
+end
diff --git a/src/asm/snapvector.c b/src/asm/snapvector.c
new file mode 100644
index 0000000..febbee0
--- /dev/null
+++ b/src/asm/snapvector.c
@@ -0,0 +1,75 @@
+/*
+===========================================================================
+Copyright (C) 2011 Thilo Schulz <thilo@tjps.eu>
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "qasm-inline.h"
+#include "qcommon/q_shared.h"
+
+/*
+ * GNU inline asm version of qsnapvector
+ * See MASM snapvector.asm for commentary
+ */
+
+static unsigned char ssemask[16] __attribute__((aligned(16))) =
+{
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00"
+};
+
+void qsnapvectorsse(vec3_t vec)
+{
+ __asm__ volatile
+ (
+ "movaps (%0), %%xmm1\n"
+ "movups (%1), %%xmm0\n"
+ "movaps %%xmm0, %%xmm2\n"
+ "andps %%xmm1, %%xmm0\n"
+ "andnps %%xmm2, %%xmm1\n"
+ "cvtps2dq %%xmm0, %%xmm0\n"
+ "cvtdq2ps %%xmm0, %%xmm0\n"
+ "orps %%xmm1, %%xmm0\n"
+ "movups %%xmm0, (%1)\n"
+ :
+ : "r" (ssemask), "r" (vec)
+ : "memory", "%xmm0", "%xmm1", "%xmm2"
+ );
+
+}
+
+#define QROUNDX87(src) \
+ "flds " src "\n" \
+ "fistpl " src "\n" \
+ "fildl " src "\n" \
+ "fstps " src "\n"
+
+void qsnapvectorx87(vec3_t vec)
+{
+ __asm__ volatile
+ (
+ QROUNDX87("(%0)")
+ QROUNDX87("4(%0)")
+ QROUNDX87("8(%0)")
+ :
+ : "r" (vec)
+ : "memory"
+ );
+}
diff --git a/src/asm/snd_mixa.s b/src/asm/snd_mixa.s
new file mode 100644
index 0000000..ebae0a4
--- /dev/null
+++ b/src/asm/snd_mixa.s
@@ -0,0 +1,217 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+//
+// snd_mixa.s
+// x86 assembly-language sound code
+//
+
+#include "qasm.h"
+
+#if id386
+
+ .text
+
+#if 0
+//----------------------------------------------------------------------
+// 8-bit sound-mixing code
+//----------------------------------------------------------------------
+
+#define ch 4+16
+#define sc 8+16
+#define count 12+16
+
+.globl C(S_PaintChannelFrom8)
+C(S_PaintChannelFrom8):
+ pushl %esi // preserve register variables
+ pushl %edi
+ pushl %ebx
+ pushl %ebp
+
+// int data;
+// short *lscale, *rscale;
+// unsigned char *sfx;
+// int i;
+
+ movl ch(%esp),%ebx
+ movl sc(%esp),%esi
+
+// if (ch->leftvol > 255)
+// ch->leftvol = 255;
+// if (ch->rightvol > 255)
+// ch->rightvol = 255;
+ movl ch_leftvol(%ebx),%eax
+ movl ch_rightvol(%ebx),%edx
+ cmpl $255,%eax
+ jna LLeftSet
+ movl $255,%eax
+LLeftSet:
+ cmpl $255,%edx
+ jna LRightSet
+ movl $255,%edx
+LRightSet:
+
+// lscale = snd_scaletable[ch->leftvol >> 3];
+// rscale = snd_scaletable[ch->rightvol >> 3];
+// sfx = (signed char *)sc->data + ch->pos;
+// ch->pos += count;
+ andl $0xF8,%eax
+ addl $20,%esi
+ movl (%esi),%esi
+ andl $0xF8,%edx
+ movl ch_pos(%ebx),%edi
+ movl count(%esp),%ecx
+ addl %edi,%esi
+ shll $7,%eax
+ addl %ecx,%edi
+ shll $7,%edx
+ movl %edi,ch_pos(%ebx)
+ addl $(C(snd_scaletable)),%eax
+ addl $(C(snd_scaletable)),%edx
+ subl %ebx,%ebx
+ movb -1(%esi,%ecx,1),%bl
+
+ testl $1,%ecx
+ jz LMix8Loop
+
+ movl (%eax,%ebx,4),%edi
+ movl (%edx,%ebx,4),%ebp
+ addl C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size),%edi
+ addl C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size),%ebp
+ movl %edi,C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size)
+ movl %ebp,C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size)
+ movb -2(%esi,%ecx,1),%bl
+
+ decl %ecx
+ jz LDone
+
+// for (i=0 ; i<count ; i++)
+// {
+LMix8Loop:
+
+// data = sfx[i];
+// paintbuffer[i].left += lscale[data];
+// paintbuffer[i].right += rscale[data];
+ movl (%eax,%ebx,4),%edi
+ movl (%edx,%ebx,4),%ebp
+ addl C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size),%edi
+ addl C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size),%ebp
+ movb -2(%esi,%ecx,1),%bl
+ movl %edi,C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size)
+ movl %ebp,C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size)
+
+ movl (%eax,%ebx,4),%edi
+ movl (%edx,%ebx,4),%ebp
+ movb -3(%esi,%ecx,1),%bl
+ addl C(paintbuffer)+psp_left-psp_size*2(,%ecx,psp_size),%edi
+ addl C(paintbuffer)+psp_right-psp_size*2(,%ecx,psp_size),%ebp
+ movl %edi,C(paintbuffer)+psp_left-psp_size*2(,%ecx,psp_size)
+ movl %ebp,C(paintbuffer)+psp_right-psp_size*2(,%ecx,psp_size)
+
+// }
+ subl $2,%ecx
+ jnz LMix8Loop
+
+LDone:
+ popl %ebp
+ popl %ebx
+ popl %edi
+ popl %esi
+
+ ret
+
+
+#endif
+
+//----------------------------------------------------------------------
+// Transfer of stereo buffer to 16-bit DMA buffer code
+//----------------------------------------------------------------------
+
+.globl C(S_WriteLinearBlastStereo16)
+C(S_WriteLinearBlastStereo16):
+ pushl %edi
+ pushl %ebx
+
+// int i;
+// int val;
+ movl C(snd_linear_count),%ecx
+ movl C(snd_p),%ebx
+ movl C(snd_out),%edi
+
+// for (i=0 ; i<snd_linear_count ; i+=2)
+// {
+LWLBLoopTop:
+
+// val = (snd_p[i]*snd_vol)>>8;
+// if (val > 0x7fff)
+// snd_out[i] = 0x7fff;
+// else if (val < (short)0x8000)
+// snd_out[i] = (short)0x8000;
+// else
+// snd_out[i] = val;
+ movl -8(%ebx,%ecx,4),%eax
+ sarl $8,%eax
+ cmpl $0x7FFF,%eax
+ jg LClampHigh
+ cmpl $0xFFFF8000,%eax
+ jnl LClampDone
+ movl $0xFFFF8000,%eax
+ jmp LClampDone
+LClampHigh:
+ movl $0x7FFF,%eax
+LClampDone:
+
+// val = (snd_p[i+1]*snd_vol)>>8;
+// if (val > 0x7fff)
+// snd_out[i+1] = 0x7fff;
+// else if (val < (short)0x8000)
+// snd_out[i+1] = (short)0x8000;
+// else
+// snd_out[i+1] = val;
+ movl -4(%ebx,%ecx,4),%edx
+ sarl $8,%edx
+ cmpl $0x7FFF,%edx
+ jg LClampHigh2
+ cmpl $0xFFFF8000,%edx
+ jnl LClampDone2
+ movl $0xFFFF8000,%edx
+ jmp LClampDone2
+LClampHigh2:
+ movl $0x7FFF,%edx
+LClampDone2:
+ shll $16,%edx
+ andl $0xFFFF,%eax
+ orl %eax,%edx
+ movl %edx,-4(%edi,%ecx,2)
+
+// }
+ subl $2,%ecx
+ jnz LWLBLoopTop
+
+// snd_p += snd_linear_count;
+
+ popl %ebx
+ popl %edi
+
+ ret
+
+#endif // id386
diff --git a/src/asm/vm_x86_64.asm b/src/asm/vm_x86_64.asm
new file mode 100644
index 0000000..692cee9
--- /dev/null
+++ b/src/asm/vm_x86_64.asm
@@ -0,0 +1,59 @@
+; ===========================================================================
+; Copyright (C) 2011 Thilo Schulz <thilo@tjps.eu>
+; Copyright (C) 2015-2019 GrangerHub
+;
+; This file is part of Tremulous.
+;
+; Tremulous is free software; you can redistribute it
+; and/or modify it under the terms of the GNU General Public License as
+; published by the Free Software Foundation; either version 3 of the License,
+; or (at your option) any later version.
+;
+; Tremulous is distributed in the hope that it will be
+; useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+;
+; ===========================================================================
+
+; Call wrapper for vm_x86 when built with MSVC in 64 bit mode,
+; since MSVC does not support inline x64 assembler code anymore.
+;
+; assumes __fastcall calling convention
+
+.code
+
+; Call to compiled code after setting up the register environment for the VM
+; prototype:
+; uint8_t qvmcall64(int *programStack, int *opStack, intptr_t *instructionPointers, byte *dataBase);
+
+qvmcall64 PROC
+ push rsi ; push non-volatile registers to stack
+ push rdi
+ push rbx
+ ; need to save pointer in rcx so we can write back the programData value to caller
+ push rcx
+
+ ; registers r8 and r9 have correct value already thanx to __fastcall
+ xor rbx, rbx ; opStackOfs starts out being 0
+ mov rdi, rdx ; opStack
+ mov esi, dword ptr [rcx] ; programStack
+
+ call qword ptr [r8] ; instructionPointers[0] is also the entry point
+
+ pop rcx
+
+ mov dword ptr [rcx], esi ; write back the programStack value
+ mov al, bl ; return opStack offset
+
+ pop rbx
+ pop rdi
+ pop rsi
+
+ ret
+qvmcall64 ENDP
+
+end
diff --git a/src/cgame/CMakeLists.txt b/src/cgame/CMakeLists.txt
new file mode 100644
index 0000000..026e6eb
--- /dev/null
+++ b/src/cgame/CMakeLists.txt
@@ -0,0 +1,83 @@
+#
+## ____ _
+## / ___|__ _ __ _ _ __ ___ ___ ___ ___ __| | ___
+##| | / _` |/ _` | '_ ` _ \ / _ \ / __/ _ \ / _` |/ _ \
+##| |__| (_| | (_| | | | | | | __/ | (_| (_) | (_| | __/
+## \____\__, |\__,_|_| |_| |_|\___| \___\___/ \__,_|\___|
+## |___/
+#
+
+set(CMAKE_INSTALL_NAME_DIR ${PROJECT_BINARY_DIR}/gpp)
+
+set(BG_SOURCE_DIR ../game)
+set(QC_SOURCE_DIR ../qcommon)
+set(UI_SOURCE_DIR ../ui)
+set(RC_SOURCE_DIR ../renderercommon)
+
+add_definitions( -DCGAME )
+
+set( CGAME_SOURCES
+ cg_main.c # Must be listed first
+ cg_public.h
+ cg_local.h
+ binaryshader.h
+ ${BG_SOURCE_DIR}/bg_lib.h
+ ${BG_SOURCE_DIR}/bg_public.h
+ ${BG_SOURCE_DIR}/bg_alloc.c
+ ${BG_SOURCE_DIR}/bg_lib.c
+ ${BG_SOURCE_DIR}/bg_misc.c
+ ${BG_SOURCE_DIR}/bg_voice.c
+ ${BG_SOURCE_DIR}/bg_pmove.c
+ ${BG_SOURCE_DIR}/bg_slidemove.c
+ cg_animation.c
+ cg_animmapobj.c
+ cg_attachment.c
+ cg_buildable.c
+ cg_consolecmds.c
+ cg_draw.c
+ cg_drawtools.c
+ cg_ents.c
+ cg_event.c
+ cg_marks.c
+ cg_particles.c
+ cg_players.c
+ cg_playerstate.c
+ cg_predict.c
+ cg_rangemarker.c
+ cg_scanner.c
+ cg_servercmds.c
+ cg_snapshot.c
+ cg_trails.c
+ cg_tutorial.c
+ cg_view.c
+ cg_weapons.c
+ #
+ ${UI_SOURCE_DIR}/ui_shared.h
+ ${UI_SOURCE_DIR}/ui_shared.c
+ #
+ ${QC_SOURCE_DIR}/q_shared.h
+ ${QC_SOURCE_DIR}/q_shared.c
+ ${QC_SOURCE_DIR}/q_math.c
+ #
+ ${RC_SOURCE_DIR}/tr_types.h
+ )
+
+add_library( cgame SHARED ${CGAME_SOURCES} cg_syscalls.c )
+
+target_include_directories(
+ cgame PUBLIC
+ ${BG_SOURCE_DIR}
+ ${QC_SOURCE_DIR}
+ ${RC_SOURCE_DIR}
+ ${UI_SOURCE_DIR}
+ )
+
+include( ${CMAKE_SOURCE_DIR}/cmake/AddQVM.cmake )
+add_qvm( cgame ${CGAME_SOURCES} cg_syscalls.asm )
+
+
+add_custom_command(
+ TARGET cgame POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${CMAKE_CURRENT_BINARY_DIR}/libcgame${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpp/cgame${CMAKE_SHARED_LIBRARY_SUFFIX}
+ )
diff --git a/src/cgame/binaryshader.h b/src/cgame/binaryshader.h
new file mode 100644
index 0000000..371f758
--- /dev/null
+++ b/src/cgame/binaryshader.h
@@ -0,0 +1,42 @@
+#ifndef BINARY_SHADER_H
+#define BINARY_SHADER_H 1
+
+typedef struct
+{
+ byte color[ 3 ];
+ qboolean drawIntersection;
+ qboolean drawFrontline;
+} cgBinaryShaderSetting_t;
+
+#define NUM_BINARY_SHADERS 256
+
+typedef struct
+{
+ qhandle_t f1;
+ qhandle_t f2;
+ qhandle_t f3;
+ qhandle_t b1;
+ qhandle_t b2;
+ qhandle_t b3;
+} cgMediaBinaryShader_t;
+
+typedef enum
+{
+ SHC_DARK_BLUE,
+ SHC_LIGHT_BLUE,
+ SHC_GREEN_CYAN,
+ SHC_VIOLET,
+ SHC_YELLOW,
+ SHC_ORANGE,
+ SHC_LIGHT_GREEN,
+ SHC_DARK_GREEN,
+ SHC_RED,
+ SHC_PINK,
+ SHC_GREY,
+ SHC_NUM_SHADER_COLORS
+} shaderColorEnum_t;
+
+extern const vec3_t cg_shaderColors[ SHC_NUM_SHADER_COLORS ];
+
+
+#endif
diff --git a/src/cgame/cg_animation.c b/src/cgame/cg_animation.c
index c370c53..78311b9 100644
--- a/src/cgame/cg_animation.c
+++ b/src/cgame/cg_animation.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -31,7 +32,7 @@ Sets cg.snap, cg.oldFrame, and cg.backlerp
cg.time should be between oldFrameTime and frameTime after exit
===============
*/
-void CG_RunLerpFrame( lerpFrame_t *lf )
+void CG_RunLerpFrame( lerpFrame_t *lf, float scale )
{
int f, numFrames;
animation_t *anim;
@@ -61,7 +62,9 @@ void CG_RunLerpFrame( lerpFrame_t *lf )
lf->frameTime = lf->oldFrameTime + anim->frameLerp;
f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
+ f *= scale;
numFrames = anim->numFrames;
+
if( anim->flipflop )
numFrames *= 2;
diff --git a/src/cgame/cg_animmapobj.c b/src/cgame/cg_animmapobj.c
index 1225314..9edbed4 100644
--- a/src/cgame/cg_animmapobj.c
+++ b/src/cgame/cg_animmapobj.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,14 +17,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
#include "cg_local.h"
-
/*
===============
CG_DoorAnimation
@@ -31,7 +31,7 @@ CG_DoorAnimation
*/
static void CG_DoorAnimation( centity_t *cent, int *old, int *now, float *backLerp )
{
- CG_RunLerpFrame( &cent->lerpFrame );
+ CG_RunLerpFrame( &cent->lerpFrame, 1.0f );
*old = cent->lerpFrame.oldFrame;
*now = cent->lerpFrame.frame;
@@ -117,7 +117,7 @@ static void CG_AMOAnimation( centity_t *cent, int *old, int *now, float *backLer
cent->lerpFrame.frameTime += delta;
}
- CG_RunLerpFrame( &cent->lerpFrame );
+ CG_RunLerpFrame( &cent->lerpFrame, 1.0f );
cent->miscTime = cg.time;
}
@@ -147,7 +147,6 @@ void CG_AnimMapObj( centity_t *cent )
memset( &ent, 0, sizeof( ent ) );
- VectorCopy( es->angles, cent->lerpAngles );
AnglesToAxis( cent->lerpAngles, ent.axis );
ent.hModel = cgs.gameModels[ es->modelindex ];
diff --git a/src/cgame/cg_attachment.c b/src/cgame/cg_attachment.c
index 0d3c8ea..2c52c06 100644
--- a/src/cgame/cg_attachment.c
+++ b/src/cgame/cg_attachment.c
@@ -1,12 +1,13 @@
/*
===========================================================================
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -15,8 +16,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
diff --git a/src/cgame/cg_buildable.c b/src/cgame/cg_buildable.c
index e678ebd..7d7596b 100644
--- a/src/cgame/cg_buildable.c
+++ b/src/cgame/cg_buildable.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,12 +17,11 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
-
#include "cg_local.h"
char *cg_buildableSoundNames[ MAX_BUILDABLE_ANIMATIONS ] =
@@ -95,6 +95,7 @@ void CG_HumanBuildableExplosion( vec3_t origin, vec3_t dir )
#define CREEP_SIZE 64.0f
+#define CREEP_DISTANCE 64.0f
/*
==================
@@ -107,7 +108,7 @@ static void CG_Creep( centity_t *cent )
float size, frac;
trace_t tr;
vec3_t temp, origin;
- int scaleUpTime = BG_FindBuildTimeForBuildable( cent->currentState.modelindex );
+ int scaleUpTime = BG_Buildable( cent->currentState.modelindex )->buildTime;
int time;
time = cent->currentState.time;
@@ -121,7 +122,7 @@ static void CG_Creep( centity_t *cent )
else
frac = 1.0f;
}
- else
+ else if( time < 0 )
{
msec = cg.time + time;
if( msec >= 0 && msec < CREEP_SCALEDOWN_TIME )
@@ -131,7 +132,7 @@ static void CG_Creep( centity_t *cent )
}
VectorCopy( cent->currentState.origin2, temp );
- VectorScale( temp, -4096, temp );
+ VectorScale( temp, -CREEP_DISTANCE, temp );
VectorAdd( temp, cent->lerpOrigin, temp );
CG_Trace( &tr, cent->lerpOrigin, NULL, NULL, temp, cent->currentState.number, MASK_PLAYERSOLID );
@@ -140,7 +141,7 @@ static void CG_Creep( centity_t *cent )
size = CREEP_SIZE * frac;
- if( size > 0.0f )
+ if( size > 0.0f && tr.fraction < 1.0f )
CG_ImpactMark( cgs.media.creepShader, origin, cent->currentState.origin2,
0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, size, qtrue );
}
@@ -168,12 +169,13 @@ static qboolean CG_ParseBuildableAnimationFile( const char *filename, buildable_
// load the file
len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if( len <= 0 )
+ if( len < 0 )
return qfalse;
- if( len >= sizeof( text ) - 1 )
+ if( len == 0 || len >= sizeof( text ) - 1 )
{
- CG_Printf( "File %s too long\n", filename );
+ trap_FS_FCloseFile( f );
+ CG_Printf( "File %s is %s\n", filename, len == 0 ? "empty" : "too long" );
return qfalse;
}
@@ -258,12 +260,13 @@ static qboolean CG_ParseBuildableSoundFile( const char *filename, buildable_t bu
// load the file
len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 )
+ if ( len < 0 )
return qfalse;
- if ( len >= sizeof( text ) - 1 )
+ if ( len == 0 || len >= sizeof( text ) - 1 )
{
- CG_Printf( "File %s too long\n", filename );
+ trap_FS_FCloseFile( f );
+ CG_Printf( "File %s is %s\n", filename, len == 0 ? "empty" : "too long" );
return qfalse;
}
@@ -335,7 +338,7 @@ void CG_InitBuildables( void )
for( i = BA_NONE + 1; i < BA_NUM_BUILDABLES; i++ )
{
- buildableName = BG_FindNameForBuildable( i );
+ buildableName = BG_Buildable( i )->name;
//animation.cfg
Com_sprintf( filename, sizeof( filename ), "models/buildables/%s/animation.cfg", buildableName );
@@ -350,7 +353,8 @@ void CG_InitBuildables( void )
//models
for( j = 0; j <= 3; j++ )
{
- if( ( modelFile = BG_FindModelsForBuildable( i, j ) ) )
+ modelFile = BG_BuildableConfig( i )->models[ j ];
+ if( strlen( modelFile ) > 0 )
cg_buildables[ i ].models[ j ] = trap_R_RegisterModel( modelFile );
}
@@ -372,7 +376,7 @@ void CG_InitBuildables( void )
else
{
//file doesn't exist - use default
- if( BG_FindTeamForBuildable( i ) == BIT_ALIENS )
+ if( BG_Buildable( i )->team == TEAM_ALIENS )
cg_buildables[ i ].sounds[ j ].sound = defaultAlienSounds[ j ];
else
cg_buildables[ i ].sounds[ j ].sound = defaultHumanSounds[ j ];
@@ -426,24 +430,15 @@ cg.time should be between oldFrameTime and frameTime after exit
*/
static void CG_RunBuildableLerpFrame( centity_t *cent )
{
- int f, numFrames;
buildable_t buildable = cent->currentState.modelindex;
lerpFrame_t *lf = &cent->lerpFrame;
- animation_t *anim;
buildableAnimNumber_t newAnimation = cent->buildableAnim & ~( ANIM_TOGGLEBIT|ANIM_FORCEBIT );
- // debugging tool to get no animations
- if( cg_animSpeed.integer == 0 )
- {
- lf->oldFrame = lf->frame = lf->backlerp = 0;
- return;
- }
-
// see if the animation sequence is switching
if( newAnimation != lf->animationNumber || !lf->animation )
{
if( cg_debugRandom.integer )
- CG_Printf( "newAnimation: %d lf->animationNumber: %d lf->animation: %d\n",
+ CG_Printf( "newAnimation: %d lf->animationNumber: %d lf->animation: 0x%p\n",
newAnimation, lf->animationNumber, lf->animation );
CG_SetBuildableLerpFrameAnimation( buildable, lf, newAnimation );
@@ -453,7 +448,7 @@ static void CG_RunBuildableLerpFrame( centity_t *cent )
{
if( cg_debugRandom.integer )
CG_Printf( "Sound for animation %d for a %s\n",
- newAnimation, BG_FindHumanNameForBuildable( buildable ) );
+ newAnimation, BG_Buildable( buildable )->humanName );
trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_AUTO,
cg_buildables[ buildable ].sounds[ newAnimation ].sound );
@@ -465,72 +460,14 @@ static void CG_RunBuildableLerpFrame( centity_t *cent )
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
cg_buildables[ buildable ].sounds[ lf->animationNumber ].sound );
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if( cg.time >= lf->frameTime )
- {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
+ CG_RunLerpFrame( lf, 1.0f );
- // get the next frame based on the animation
- anim = lf->animation;
- if( !anim->frameLerp )
- return; // shouldn't happen
-
- if ( cg.time < lf->animationTime )
- lf->frameTime = lf->animationTime; // initial lerp
- else
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
-
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- numFrames = anim->numFrames;
- if(anim->flipflop)
- numFrames *= 2;
-
- if( f >= numFrames )
- {
- f -= numFrames;
- if( anim->loopFrames )
- {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- }
- else
- {
- f = numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = cg.time;
- cent->buildableAnim = cent->currentState.torsoAnim;
- }
- }
-
- if( anim->reversed )
- lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
- else if( anim->flipflop && f >= anim->numFrames )
- lf->frame = anim->firstFrame + anim->numFrames - 1 - ( f % anim->numFrames );
- else
- lf->frame = anim->firstFrame + f;
-
- if( cg.time > lf->frameTime )
- {
- lf->frameTime = cg.time;
- if( cg_debugAnim.integer )
- CG_Printf( "Clamp lf->frameTime\n");
- }
+ // animation ended
+ if( lf->frameTime == cg.time )
+ {
+ cent->buildableAnim = cent->currentState.torsoAnim;
+ cent->buildableIdleAnim = qtrue;
}
-
- if( lf->frameTime > cg.time + 200 )
- lf->frameTime = cg.time;
-
- if( lf->oldFrameTime > cg.time )
- lf->oldFrameTime = cg.time;
-
- // calculate current lerp value
- if( lf->frameTime == lf->oldFrameTime )
- lf->backlerp = 0;
- else
- lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
}
/*
@@ -544,10 +481,13 @@ static void CG_BuildableAnimation( centity_t *cent, int *old, int *now, float *b
//if no animation is set default to idle anim
if( cent->buildableAnim == BANIM_NONE )
+ {
cent->buildableAnim = es->torsoAnim;
+ cent->buildableIdleAnim = qtrue;
+ }
//display the first frame of the construction anim if not yet spawned
- if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
+ if( !( es->eFlags & EF_B_SPAWNED ) )
{
animation_t *anim = &cg_buildables[ es->modelindex ].animations[ BANIM_CONSTRUCT1 ];
@@ -572,12 +512,23 @@ static void CG_BuildableAnimation( centity_t *cent, int *old, int *now, float *b
CG_Printf( "%d->%d l:%d t:%d %s(%d)\n",
cent->oldBuildableAnim, cent->buildableAnim,
es->legsAnim, es->torsoAnim,
- BG_FindHumanNameForBuildable( es->modelindex ), es->number );
+ BG_Buildable( es->modelindex )->humanName, es->number );
if( cent->buildableAnim == es->torsoAnim || es->legsAnim & ANIM_FORCEBIT )
+ {
cent->buildableAnim = cent->oldBuildableAnim = es->legsAnim;
+ cent->buildableIdleAnim = qfalse;
+ }
else
+ {
cent->buildableAnim = cent->oldBuildableAnim = es->torsoAnim;
+ cent->buildableIdleAnim = qtrue;
+ }
+ }
+ else if( cent->buildableIdleAnim == qtrue &&
+ cent->buildableAnim != es->torsoAnim )
+ {
+ cent->buildableAnim = es->torsoAnim;
}
CG_RunBuildableLerpFrame( cent );
@@ -588,7 +539,7 @@ static void CG_BuildableAnimation( centity_t *cent, int *old, int *now, float *b
}
}
-#define TRACE_DEPTH 64.0f
+#define TRACE_DEPTH 15.0f
/*
===============
@@ -600,8 +551,9 @@ static void CG_PositionAndOrientateBuildable( const vec3_t angles, const vec3_t
const vec3_t mins, const vec3_t maxs,
vec3_t outAxis[ 3 ], vec3_t outOrigin )
{
- vec3_t forward, start, end;
+ vec3_t forward, end;
trace_t tr;
+ float fraction;
AngleVectors( angles, forward, NULL, NULL );
VectorCopy( normal, outAxis[ 2 ] );
@@ -620,16 +572,21 @@ static void CG_PositionAndOrientateBuildable( const vec3_t angles, const vec3_t
outAxis[ 1 ][ 2 ] = -outAxis[ 1 ][ 2 ];
VectorMA( inOrigin, -TRACE_DEPTH, normal, end );
- VectorMA( inOrigin, 1.0f, normal, start );
- CG_CapTrace( &tr, start, mins, maxs, end, skipNumber, MASK_PLAYERSOLID );
- if( tr.fraction == 1.0f )
+ CG_CapTrace( &tr, inOrigin, mins, maxs, end, skipNumber,
+ CONTENTS_SOLID | CONTENTS_PLAYERCLIP );
+
+ fraction = tr.fraction;
+ if( tr.startsolid )
+ fraction = 0;
+ else if( tr.fraction == 1.0f )
{
- //erm we missed completely - try again with a box trace
- CG_Trace( &tr, start, mins, maxs, end, skipNumber, MASK_PLAYERSOLID );
+ // this is either too far off of the bbox to be useful for gameplay purposes
+ // or the model is positioned in thin air anyways.
+ fraction = 0;
}
- VectorMA( inOrigin, tr.fraction * -TRACE_DEPTH, normal, outOrigin );
+ VectorMA( inOrigin, fraction * -TRACE_DEPTH, normal, outOrigin );
}
/*
@@ -650,15 +607,18 @@ void CG_GhostBuildable( buildable_t buildable )
memset( &ent, 0, sizeof( ent ) );
- BG_FindBBoxForBuildable( buildable, mins, maxs );
+ BG_BuildableBoundingBox( buildable, mins, maxs );
BG_PositionBuildableRelativeToPlayer( ps, mins, maxs, CG_Trace, entity_origin, angles, &tr );
+ if( cg_rangeMarkerForBlueprint.integer && tr.entityNum != ENTITYNUM_NONE )
+ CG_GhostBuildableRangeMarker( buildable, entity_origin, tr.plane.normal );
+
CG_PositionAndOrientateBuildable( ps->viewangles, entity_origin, tr.plane.normal, ps->clientNum,
mins, maxs, ent.axis, ent.origin );
//offset on the Z axis if required
- VectorMA( ent.origin, BG_FindZOffsetForBuildable( buildable ), tr.plane.normal, ent.origin );
+ VectorMA( ent.origin, BG_BuildableConfig( buildable )->zOffset, tr.plane.normal, ent.origin );
VectorCopy( ent.origin, ent.lightingOrigin );
VectorCopy( ent.origin, ent.oldorigin ); // don't positionally lerp at all
@@ -671,7 +631,7 @@ void CG_GhostBuildable( buildable_t buildable )
ent.customShader = cgs.media.redBuildShader;
//rescale the model
- scale = BG_FindModelScaleForBuildable( buildable );
+ scale = BG_BuildableConfig( buildable )->modelScale;
if( scale != 1.0f )
{
@@ -696,14 +656,14 @@ CG_BuildableParticleEffects
static void CG_BuildableParticleEffects( centity_t *cent )
{
entityState_t *es = &cent->currentState;
- buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex );
- int health = es->generic1 & B_HEALTH_MASK;
- float healthFrac = (float)health / B_HEALTH_MASK;
+ team_t team = BG_Buildable( es->modelindex )->team;
+ int health = es->misc;
+ float healthFrac = (float)health / BG_Buildable( es->modelindex )->health;
- if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
+ if( !( es->eFlags & EF_B_SPAWNED ) )
return;
- if( team == BIT_HUMANS )
+ if( team == TEAM_HUMANS )
{
if( healthFrac < 0.33f && !CG_IsParticleSystemValid( &cent->buildablePS ) )
{
@@ -718,7 +678,7 @@ static void CG_BuildableParticleEffects( centity_t *cent )
else if( healthFrac >= 0.33f && CG_IsParticleSystemValid( &cent->buildablePS ) )
CG_DestroyParticleSystem( &cent->buildablePS );
}
- else if( team == BIT_ALIENS )
+ else if( team == TEAM_ALIENS )
{
if( healthFrac < 0.33f && !CG_IsParticleSystemValid( &cent->buildablePS ) )
{
@@ -736,7 +696,11 @@ static void CG_BuildableParticleEffects( centity_t *cent )
}
}
-
+/*
+==================
+CG_BuildableStatusParse
+==================
+*/
void CG_BuildableStatusParse( const char *filename, buildStat_t *bs )
{
pc_token_t token;
@@ -866,10 +830,12 @@ void CG_BuildableStatusParse( const char *filename, buildStat_t *bs )
Com_Printf("CG_BuildableStatusParse: unknown token %s in %s\n",
token.string, filename );
bs->loaded = qfalse;
+ trap_Parse_FreeSource( handle );
return;
}
}
bs->loaded = qtrue;
+ trap_Parse_FreeSource( handle );
}
#define STATUS_FADE_TIME 200
@@ -899,23 +865,30 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
qboolean visible = qfalse;
vec3_t mins, maxs;
entityState_t *hit;
+ int anim;
- if( BG_FindTeamForBuildable( es->modelindex ) == BIT_ALIENS )
+ if( BG_Buildable( es->modelindex )->team == TEAM_ALIENS )
bs = &cgs.alienBuildStat;
else
bs = &cgs.humanBuildStat;
if( !bs->loaded )
return;
-
+
d = Distance( cent->lerpOrigin, cg.refdef.vieworg );
if( d > STATUS_MAX_VIEW_DIST )
return;
-
+
Vector4Copy( bs->foreColor, color );
- // trace for center point
- BG_FindBBoxForBuildable( es->modelindex, mins, maxs );
+ // trace for center point
+ BG_BuildableBoundingBox( es->modelindex, mins, maxs );
+
+ // hack for shrunken barricades
+ anim = es->torsoAnim & ~( ANIM_FORCEBIT | ANIM_TOGGLEBIT );
+ if( es->modelindex == BA_A_BARRICADE &&
+ ( anim == BANIM_DESTROYED || !( es->eFlags & EF_B_SPAWNED ) ) )
+ maxs[ 2 ] = (int)( maxs[ 2 ] * BARRICADE_SHRINKPROP );
VectorCopy( cent->lerpOrigin, origin );
@@ -960,8 +933,8 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
hit = &cg_entities[ tr.entityNum ].currentState;
if( tr.entityNum < MAX_CLIENTS || ( hit->eType == ET_BUILDABLE &&
- ( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) ||
- BG_FindTransparentTestForBuildable( hit->modelindex ) ) ) )
+ ( !( es->eFlags & EF_B_SPAWNED ) ||
+ BG_Buildable( hit->modelindex )->transparentTest ) ) )
{
entNum = tr.entityNum;
VectorCopy( tr.endpos, trOrigin );
@@ -972,7 +945,7 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
}
// hack to make the kit obscure view
if( cg_drawGun.integer && visible &&
- cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS &&
+ cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS &&
CG_WorldToScreen( origin, &x, &y ) )
{
if( x > 450 && y > 290 )
@@ -1006,8 +979,8 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
return;
}
- health = es->generic1 & B_HEALTH_MASK;
- healthScale = (float)health / B_HEALTH_MASK;
+ health = es->misc;
+ healthScale = (float)health / BG_Buildable( es->modelindex )->health;
if( health > 0 && healthScale < 0.01f )
healthScale = 0.01f;
@@ -1024,13 +997,14 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
float picY = y;
float scale;
float subH, subY;
+ float clipX, clipY, clipW, clipH;
vec4_t frameColor;
// this is fudged to get the width/height in the cfg to be more realistic
scale = ( picH / d ) * 3;
- powered = es->generic1 & B_POWERED_TOGGLEBIT;
- marked = es->generic1 & B_MARKED_TOGGLEBIT;
+ powered = es->eFlags & EF_B_POWERED;
+ marked = es->eFlags & EF_B_MARKED;
picH *= scale;
picW *= scale;
@@ -1041,6 +1015,12 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
subH = picH - ( picH * bs->verticalMargin );
subY = picY + ( picH * 0.5f ) - ( subH * 0.5f );
+ clipW = ( 640.0f * cg_viewsize.integer ) / 100.0f;
+ clipH = ( 480.0f * cg_viewsize.integer ) / 100.0f;
+ clipX = 320.0f - ( clipW * 0.5f );
+ clipY = 240.0f - ( clipH * 0.5f );
+ CG_SetClipRegion( clipX, clipY, clipW, clipH );
+
if( bs->frameShader )
{
Vector4Copy( bs->backColor, frameColor );
@@ -1073,7 +1053,7 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
healthColor[ 3 ] = color[ 3 ];
trap_R_SetColor( healthColor );
-
+
CG_DrawPic( hX, hY, hW, hH, cgs.media.whiteShader );
trap_R_SetColor( NULL );
}
@@ -1089,7 +1069,7 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
oW *= scale;
oX -= ( oW * 0.5f );
oY -= ( oH * 0.5f );
-
+
trap_R_SetColor( frameColor );
CG_DrawPic( oX, oY, oW, oH, bs->overlayShader );
trap_R_SetColor( NULL );
@@ -1117,12 +1097,12 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
int healthMax;
int healthPoints;
- healthMax = BG_FindHealthForBuildable( es->modelindex );
+ healthMax = BG_Buildable( es->modelindex )->health;
healthPoints = (int)( healthScale * healthMax );
if( health > 0 && healthPoints < 1 )
healthPoints = 1;
- nX = picX + ( picW * 0.5f ) - 2.0f - ( ( subH * 4 ) * 0.5f );
-
+ nX = picX + ( picW * 0.5f ) - 2.0f - ( ( subH * 4 ) * 0.5f );
+
if( healthPoints > 999 )
nX -= 0.0f;
else if( healthPoints > 99 )
@@ -1131,14 +1111,21 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
nX -= subH * 1.0f;
else
nX -= subH * 1.5f;
-
+
CG_DrawField( nX, subY, 4, subH, subH, healthPoints );
}
+
trap_R_SetColor( NULL );
+ CG_ClearClipRegion( );
}
}
-static int QDECL CG_SortDistance( const void *a, const void *b )
+/*
+==================
+CG_SortDistance
+==================
+*/
+static int CG_SortDistance( const void *a, const void *b )
{
centity_t *aent, *bent;
float adist, bdist;
@@ -1157,6 +1144,48 @@ static int QDECL CG_SortDistance( const void *a, const void *b )
/*
==================
+CG_PlayerIsBuilder
+==================
+*/
+static qboolean CG_PlayerIsBuilder( buildable_t buildable )
+{
+ switch( cg.predictedPlayerState.weapon )
+ {
+ case WP_ABUILD:
+ case WP_ABUILD2:
+ case WP_HBUILD:
+ return BG_Buildable( buildable )->team ==
+ BG_Weapon( cg.predictedPlayerState.weapon )->team;
+
+ default:
+ return qfalse;
+ }
+}
+
+/*
+==================
+CG_BuildableRemovalPending
+==================
+*/
+static qboolean CG_BuildableRemovalPending( int entityNum )
+{
+ int i;
+ playerState_t *ps = &cg.snap->ps;
+
+ if( !( ps->stats[ STAT_BUILDABLE ] & SB_VALID_TOGGLEBIT ) )
+ return qfalse;
+
+ for( i = 0; i < MAX_MISC; i++ )
+ {
+ if( ps->misc[ i ] == entityNum )
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+==================
CG_DrawBuildableStatus
==================
*/
@@ -1168,30 +1197,18 @@ void CG_DrawBuildableStatus( void )
int buildableList[ MAX_ENTITIES_IN_SNAPSHOT ];
int buildables = 0;
- switch( cg.predictedPlayerState.weapon )
+ for( i = 0; i < cg.snap->numEntities; i++ )
{
- case WP_ABUILD:
- case WP_ABUILD2:
- case WP_HBUILD:
- case WP_HBUILD2:
- for( i = 0; i < cg.snap->numEntities; i++ )
- {
- cent = &cg_entities[ cg.snap->entities[ i ].number ];
- es = &cent->currentState;
-
- if( es->eType == ET_BUILDABLE &&
- BG_FindTeamForBuildable( es->modelindex ) ==
- BG_FindTeamForWeapon( cg.predictedPlayerState.weapon ) )
- buildableList[ buildables++ ] = cg.snap->entities[ i ].number;
- }
- qsort( buildableList, buildables, sizeof( int ), CG_SortDistance );
- for( i = 0; i < buildables; i++ )
- CG_BuildableStatusDisplay( &cg_entities[ buildableList[ i ] ] );
- break;
+ cent = &cg_entities[ cg.snap->entities[ i ].number ];
+ es = &cent->currentState;
- default:
- break;
+ if( es->eType == ET_BUILDABLE && CG_PlayerIsBuilder( es->modelindex ) )
+ buildableList[ buildables++ ] = cg.snap->entities[ i ].number;
}
+
+ qsort( buildableList, buildables, sizeof( int ), CG_SortDistance );
+ for( i = 0; i < buildables; i++ )
+ CG_BuildableStatusDisplay( &cg_entities[ buildableList[ i ] ] );
}
#define BUILDABLE_SOUND_PERIOD 500
@@ -1205,17 +1222,15 @@ void CG_Buildable( centity_t *cent )
{
refEntity_t ent;
entityState_t *es = &cent->currentState;
- vec3_t angles;
vec3_t surfNormal, xNormal, mins, maxs;
vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
float rotAngle;
- buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex );
+ team_t team = BG_Buildable( es->modelindex )->team;
float scale;
int health;
- float healthScale;
//must be before EF_NODRAW check
- if( team == BIT_ALIENS )
+ if( team == TEAM_ALIENS )
CG_Creep( cent );
// if set to invisible, skip
@@ -1229,37 +1244,63 @@ void CG_Buildable( centity_t *cent )
memset ( &ent, 0, sizeof( ent ) );
- VectorCopy( cent->lerpOrigin, ent.origin );
- VectorCopy( cent->lerpOrigin, ent.oldorigin );
- VectorCopy( cent->lerpOrigin, ent.lightingOrigin );
-
VectorCopy( es->origin2, surfNormal );
- VectorCopy( es->angles, angles );
- BG_FindBBoxForBuildable( es->modelindex, mins, maxs );
+ BG_BuildableBoundingBox( es->modelindex, mins, maxs );
if( es->pos.trType == TR_STATIONARY )
- CG_PositionAndOrientateBuildable( angles, ent.origin, surfNormal, es->number,
- mins, maxs, ent.axis, ent.origin );
+ {
+ // seeing as buildables rarely move, we cache the results and recalculate
+ // only if the buildable moves or changes orientation
+ if( VectorCompare( cent->buildableCache.cachedOrigin, cent->lerpOrigin ) &&
+ VectorCompare( cent->buildableCache.cachedAngles, cent->lerpAngles ) &&
+ VectorCompare( cent->buildableCache.cachedNormal, surfNormal ) &&
+ cent->buildableCache.cachedType == es->modelindex )
+ {
+ VectorCopy( cent->buildableCache.axis[ 0 ], ent.axis[ 0 ] );
+ VectorCopy( cent->buildableCache.axis[ 1 ], ent.axis[ 1 ] );
+ VectorCopy( cent->buildableCache.axis[ 2 ], ent.axis[ 2 ] );
+ VectorCopy( cent->buildableCache.origin, ent.origin );
+ }
+ else
+ {
+ CG_PositionAndOrientateBuildable( cent->lerpAngles, cent->lerpOrigin, surfNormal,
+ es->number, mins, maxs, ent.axis,
+ ent.origin );
+ VectorCopy( ent.axis[ 0 ], cent->buildableCache.axis[ 0 ] );
+ VectorCopy( ent.axis[ 1 ], cent->buildableCache.axis[ 1 ] );
+ VectorCopy( ent.axis[ 2 ], cent->buildableCache.axis[ 2 ] );
+ VectorCopy( ent.origin, cent->buildableCache.origin );
+ VectorCopy( cent->lerpOrigin, cent->buildableCache.cachedOrigin );
+ VectorCopy( cent->lerpAngles, cent->buildableCache.cachedAngles );
+ VectorCopy( surfNormal, cent->buildableCache.cachedNormal );
+ cent->buildableCache.cachedType = es->modelindex;
+ }
+ }
+ else
+ {
+ VectorCopy( cent->lerpOrigin, ent.origin );
+ AnglesToAxis( cent->lerpAngles, ent.axis );
+ }
//offset on the Z axis if required
- VectorMA( ent.origin, BG_FindZOffsetForBuildable( es->modelindex ), surfNormal, ent.origin );
+ VectorMA( ent.origin, BG_BuildableConfig( es->modelindex )->zOffset, surfNormal, ent.origin );
VectorCopy( ent.origin, ent.oldorigin ); // don't positionally lerp at all
VectorCopy( ent.origin, ent.lightingOrigin );
ent.hModel = cg_buildables[ es->modelindex ].models[ 0 ];
- if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
+ if( !( es->eFlags & EF_B_SPAWNED ) )
{
sfxHandle_t prebuildSound = cgs.media.humanBuildablePrebuild;
- if( team == BIT_HUMANS )
+ if( team == TEAM_HUMANS )
{
ent.customShader = cgs.media.humanSpawningShader;
prebuildSound = cgs.media.humanBuildablePrebuild;
}
- else if( team == BIT_ALIENS )
+ else if( team == TEAM_ALIENS )
prebuildSound = cgs.media.alienBuildablePrebuild;
trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, prebuildSound );
@@ -1268,7 +1309,7 @@ void CG_Buildable( centity_t *cent )
CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
//rescale the model
- scale = BG_FindModelScaleForBuildable( es->modelindex );
+ scale = BG_BuildableConfig( es->modelindex )->modelScale;
if( scale != 1.0f )
{
@@ -1281,6 +1322,8 @@ void CG_Buildable( centity_t *cent )
else
ent.nonNormalizedAxes = qfalse;
+ if( CG_PlayerIsBuilder( es->modelindex ) && CG_BuildableRemovalPending( es->number ) )
+ ent.customShader = cgs.media.redBuildShader;
//add to refresh list
trap_R_AddRefEntityToScene( &ent );
@@ -1324,6 +1367,9 @@ void CG_Buildable( centity_t *cent )
else
turretBarrel.nonNormalizedAxes = qfalse;
+ if( CG_PlayerIsBuilder( es->modelindex ) && CG_BuildableRemovalPending( es->number ) )
+ turretBarrel.customShader = cgs.media.redBuildShader;
+
trap_R_AddRefEntityToScene( &turretBarrel );
}
@@ -1366,6 +1412,9 @@ void CG_Buildable( centity_t *cent )
else
turretTop.nonNormalizedAxes = qfalse;
+ if( CG_PlayerIsBuilder( es->modelindex ) && CG_BuildableRemovalPending( es->number ) )
+ turretTop.customShader = cgs.media.redBuildShader;
+
trap_R_AddRefEntityToScene( &turretTop );
}
@@ -1375,7 +1424,7 @@ void CG_Buildable( centity_t *cent )
weaponInfo_t *weapon = &cg_weapons[ es->weapon ];
if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ||
- BG_FindProjTypeForBuildable( es->modelindex ) == WP_TESLAGEN )
+ BG_Buildable( es->modelindex )->turretProjType == WP_TESLAGEN )
{
if( weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ] ||
weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ] ||
@@ -1397,27 +1446,34 @@ void CG_Buildable( centity_t *cent )
trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->readySound );
}
- health = es->generic1 & B_HEALTH_MASK;
- healthScale = (float)health / B_HEALTH_MASK;
+ health = es->misc;
- if( healthScale < cent->lastBuildableHealthScale && ( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
+ if( health < cent->lastBuildableHealth &&
+ ( es->eFlags & EF_B_SPAWNED ) )
{
if( cent->lastBuildableDamageSoundTime + BUILDABLE_SOUND_PERIOD < cg.time )
{
- if( team == BIT_HUMANS )
+ if( team == TEAM_HUMANS )
{
int i = rand( ) % 4;
trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] );
}
- else if( team == BIT_ALIENS )
+ else if( team == TEAM_ALIENS )
trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage );
cent->lastBuildableDamageSoundTime = cg.time;
}
}
- cent->lastBuildableHealthScale = healthScale;
+ cent->lastBuildableHealth = health;
//smoke etc for damaged buildables
CG_BuildableParticleEffects( cent );
+
+ if ( cg_rangeMarkerForBlueprint.integer )
+ {
+ // only light up the powered buildables.
+ if ( es->eFlags & EF_B_POWERED )
+ CG_GhostBuildableRangeMarker( es->modelindex, ent.origin, surfNormal );
+ }
}
diff --git a/src/cgame/cg_consolecmds.c b/src/cgame/cg_consolecmds.c
index 68aab6c..90e2e2d 100644
--- a/src/cgame/cg_consolecmds.c
+++ b/src/cgame/cg_consolecmds.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,34 +17,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_consolecmds.c -- text commands typed in at the local console, or
// executed by a key binding
-
#include "cg_local.h"
-
-
-void CG_TargetCommand_f( void )
-{
- int targetNum;
- char test[ 4 ];
-
- targetNum = CG_CrosshairPlayer( );
- if( !targetNum )
- return;
-
- trap_Argv( 1, test, 4 );
- trap_SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
-}
-
-
-
/*
=================
CG_SizeUp_f
@@ -53,7 +36,7 @@ Keybinding command
*/
static void CG_SizeUp_f( void )
{
- trap_Cvar_Set( "cg_viewsize", va( "%i", (int)( cg_viewsize.integer + 10 ) ) );
+ trap_Cvar_Set( "cg_viewsize", va( "%i", MIN( cg_viewsize.integer + 10, 100 ) ) );
}
@@ -66,7 +49,7 @@ Keybinding command
*/
static void CG_SizeDown_f( void )
{
- trap_Cvar_Set( "cg_viewsize", va( "%i", (int)( cg_viewsize.integer - 10 ) ) );
+ trap_Cvar_Set( "cg_viewsize", va( "%i", MAX( cg_viewsize.integer - 10, 30 ) ) );
}
@@ -91,7 +74,6 @@ qboolean CG_RequestScores( void )
// the scores are more than two seconds out of data,
// so request new ones
cg.scoresRequestTime = cg.time;
- //TA: added \n SendClientCommand doesn't call flush( )?
trap_SendClientCommand( "score\n" );
return qtrue;
@@ -127,26 +109,12 @@ static void CG_ScoresDown_f( void )
{
Menu_SetFeederSelection( menuScoreboard, FEEDER_ALIENTEAM_LIST, 0, NULL );
Menu_SetFeederSelection( menuScoreboard, FEEDER_HUMANTEAM_LIST, 0, NULL );
- }
-
- if( CG_RequestScores( ) )
- {
- // leave the current scores up if they were already
- // displayed, but if this is the first hit, clear them out
- if( !cg.showScores )
- {
- if( cg_debugRandom.integer )
- CG_Printf( "CG_ScoresDown_f: scores out of date\n" );
-
- cg.showScores = qtrue;
- cg.numScores = 0;
- }
+ cg.showScores = qtrue;
}
else
{
- // show the cached contents even if they just pressed if it
- // is within two seconds
- cg.showScores = qtrue;
+ cg.showScores = qfalse;
+ cg.numScores = 0;
}
}
@@ -159,70 +127,111 @@ static void CG_ScoresUp_f( void )
}
}
-static void CG_TellTarget_f( void )
+void CG_ClientList_f( void )
{
- int clientNum;
- char command[ 128 ];
- char message[ 128 ];
+ clientInfo_t *ci;
+ int i;
+ int count = 0;
- clientNum = CG_CrosshairPlayer( );
- if( clientNum == -1 )
- return;
+ for( i = 0; i < MAX_CLIENTS; i++ )
+ {
+ ci = &cgs.clientinfo[ i ];
+ if( !ci->infoValid )
+ continue;
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "tell %i %s", clientNum, message );
- trap_SendClientCommand( command );
+ switch( ci->team )
+ {
+ case TEAM_ALIENS:
+ Com_Printf( "%2d " S_COLOR_RED "A " S_COLOR_WHITE "%s\n", i,
+ ci->name );
+ break;
+
+ case TEAM_HUMANS:
+ Com_Printf( "%2d " S_COLOR_CYAN "H " S_COLOR_WHITE "%s\n", i,
+ ci->name );
+ break;
+
+ default:
+ case TEAM_NONE:
+ case NUM_TEAMS:
+ Com_Printf( "%2d S %s\n", i, ci->name );
+ break;
+ }
+
+ count++;
+ }
+
+ Com_Printf( "Listed %2d clients\n", count );
}
-static void CG_TellAttacker_f( void )
+static void CG_VoiceMenu_f( void )
{
- int clientNum;
- char command[ 128 ];
- char message[ 128 ];
-
- clientNum = CG_LastAttacker( );
- if( clientNum == -1 )
- return;
+ char cmd[sizeof("voicemenu3")];
+
+ trap_Argv(0, cmd, sizeof(cmd));
+
+ switch (cmd[9]) {
+ default:
+ case '\0':
+ trap_Cvar_Set("ui_voicemenu", "1");
+ break;
+ case '2':
+ trap_Cvar_Set("ui_voicemenu", "2");
+ break;
+ case '3':
+ trap_Cvar_Set("ui_voicemenu", "3");
+ break;
+ };
+
+ trap_SendConsoleCommand("menu tremulous_voicecmd\n");
+}
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "tell %i %s", clientNum, message );
- trap_SendClientCommand( command );
+static void CG_UIMenu_f( void )
+{
+ trap_SendConsoleCommand( va( "menu \"%s\"\n", CG_Argv( 1 ) ) );
}
-typedef struct
+static void CG_KillMessage_f( void )
{
- char *cmd;
- void (*function)( void );
-} consoleCommand_t;
+ char msg1[ 33 * 3 + 1];
+ char msg2[ 33 * 3 + 1 ];
+ trap_Argv( 1, msg1, sizeof(msg1) );
+ trap_Argv( 2, msg2, sizeof(msg2) );
+ CG_AddToKillMsg(msg1, msg2, WP_GRENADE);
+}
static consoleCommand_t commands[ ] =
{
- { "testgun", CG_TestGun_f },
- { "testmodel", CG_TestModel_f },
+ { "+scores", CG_ScoresDown_f },
+ { "-scores", CG_ScoresUp_f },
+ { "cgame_memory", BG_MemoryInfo },
+ { "clientlist", CG_ClientList_f },
+ { "destroyTestPS", CG_DestroyTestPS_f },
+ { "destroyTestTS", CG_DestroyTestTS_f },
{ "nextframe", CG_TestModelNextFrame_f },
- { "prevframe", CG_TestModelPrevFrame_f },
{ "nextskin", CG_TestModelNextSkin_f },
+ { "prevframe", CG_TestModelPrevFrame_f },
{ "prevskin", CG_TestModelPrevSkin_f },
- { "viewpos", CG_Viewpos_f },
- { "+scores", CG_ScoresDown_f },
- { "-scores", CG_ScoresUp_f },
- { "scoresUp", CG_scrollScoresUp_f },
{ "scoresDown", CG_scrollScoresDown_f },
- { "sizeup", CG_SizeUp_f },
+ { "scoresUp", CG_scrollScoresUp_f },
{ "sizedown", CG_SizeDown_f },
- { "weapnext", CG_NextWeapon_f },
- { "weapprev", CG_PrevWeapon_f },
- { "weapon", CG_Weapon_f },
- { "tell_target", CG_TellTarget_f },
- { "tell_attacker", CG_TellAttacker_f },
- { "tcmd", CG_TargetCommand_f },
+ { "sizeup", CG_SizeUp_f },
+ { "testgun", CG_TestGun_f },
+ { "testmodel", CG_TestModel_f },
{ "testPS", CG_TestPS_f },
- { "destroyTestPS", CG_DestroyTestPS_f },
{ "testTS", CG_TestTS_f },
- { "destroyTestTS", CG_DestroyTestTS_f },
+ { "ui_menu", CG_UIMenu_f },
+ { "viewpos", CG_Viewpos_f },
+ { "voicemenu", CG_VoiceMenu_f },
+ { "voicemenu2", CG_VoiceMenu_f },
+ { "voicemenu3", CG_VoiceMenu_f },
+ { "weapnext", CG_NextWeapon_f },
+ { "weapon", CG_Weapon_f },
+ { "weapprev", CG_PrevWeapon_f },
+ { "zcp", CG_CenterPrint_f },
+ { "zkill", CG_KillMessage_f }
};
-
/*
=================
CG_ConsoleCommand
@@ -233,33 +242,81 @@ Cmd_Argc() / Cmd_Argv()
*/
qboolean CG_ConsoleCommand( void )
{
- const char *cmd;
- const char *arg1;
- int i;
+ consoleCommand_t *cmd;
- cmd = CG_Argv( 0 );
+ cmd = bsearch( CG_Argv( 0 ), commands,
+ ARRAY_LEN( commands ), sizeof( commands[ 0 ] ),
+ cmdcmp );
- //TA: ugly hacky special case
- if( !Q_stricmp( cmd, "ui_menu" ) )
- {
- arg1 = CG_Argv( 1 );
- trap_SendConsoleCommand( va( "menu %s\n", arg1 ) );
- return qtrue;
- }
+ if( !cmd )
+ return qfalse;
- for( i = 0; i < sizeof( commands ) / sizeof( commands[ 0 ] ); i++ )
- {
- if( !Q_stricmp( cmd, commands[ i ].cmd ) )
- {
- commands[ i ].function( );
- return qtrue;
- }
- }
+ cmd->function( );
+ return qtrue;
+}
- return qfalse;
+#ifndef MODULE_INTERFACE_11
+/*
+==================
+CG_CompleteCallVote_f
+==================
+*/
+void CG_CompleteCallVote_f( int argNum ) {
+ switch( argNum ) {
+ case 2:
+ trap_Field_CompleteList(
+ "["
+ "\"allowbuild\","
+ "\"cancel\","
+ "\"denybuild\","
+ "\"draw\","
+ "\"extend\","
+ "\"kick\","
+ "\"map\","
+ "\"map_restart\","
+ "\"mute\","
+ "\"nextmap\","
+ "\"poll\","
+ "\"sudden_death\","
+ "\"unmute\" ]" );
+ break;
+ }
}
+static consoleCommandCompletions_t commandCompletions[ ] =
+{
+ { "callvote", CG_CompleteCallVote_f }
+};
+
+/*
+=================
+CG_Console_CompleteArgument
+
+Try to complete the client command line argument given in
+argNum. Returns true if a completion function is found in CGAME,
+otherwise client tries another completion method.
+The string has been tokenized and can be retrieved with
+Cmd_Argc() / Cmd_Argv()
+=================
+*/
+qboolean CG_Console_CompleteArgument( int argNum )
+{
+ consoleCommandCompletions_t *cmd;
+
+ // Skip command prefix character
+ cmd = bsearch( CG_Argv( 0 ) + 1, commandCompletions,
+ ARRAY_LEN( commandCompletions ), sizeof( commandCompletions[ 0 ] ),
+ cmdcmp );
+
+ if( !cmd )
+ return qfalse;
+
+ cmd->function( argNum );
+ return qtrue;
+}
+#endif
+
/*
=================
CG_InitConsoleCommands
@@ -272,7 +329,7 @@ void CG_InitConsoleCommands( void )
{
int i;
- for( i = 0 ; i < sizeof( commands ) / sizeof( commands[ 0 ] ) ; i++ )
+ for( i = 0; i < ARRAY_LEN( commands ); i++ )
trap_AddCommand( commands[ i ].cmd );
//
@@ -280,31 +337,28 @@ void CG_InitConsoleCommands( void )
// forwarded to the server after they are not recognized locally
//
trap_AddCommand( "kill" );
+ trap_AddCommand( "ui_messagemode" );
+ trap_AddCommand( "ui_messagemode2" );
+ trap_AddCommand( "ui_messagemode3" );
+ trap_AddCommand( "ui_messagemode4" );
trap_AddCommand( "say" );
trap_AddCommand( "say_team" );
- trap_AddCommand( "tell" );
trap_AddCommand( "vsay" );
trap_AddCommand( "vsay_team" );
- trap_AddCommand( "vtell" );
- trap_AddCommand( "vtaunt" );
- trap_AddCommand( "vosay" );
- trap_AddCommand( "vosay_team" );
- trap_AddCommand( "votell" );
+ trap_AddCommand( "vsay_local" );
+ trap_AddCommand( "m" );
+ trap_AddCommand( "mt" );
trap_AddCommand( "give" );
trap_AddCommand( "god" );
trap_AddCommand( "notarget" );
trap_AddCommand( "noclip" );
trap_AddCommand( "team" );
trap_AddCommand( "follow" );
- trap_AddCommand( "levelshot" );
- trap_AddCommand( "addbot" );
trap_AddCommand( "setviewpos" );
trap_AddCommand( "callvote" );
trap_AddCommand( "vote" );
trap_AddCommand( "callteamvote" );
trap_AddCommand( "teamvote" );
- trap_AddCommand( "stats" );
- trap_AddCommand( "teamtask" );
trap_AddCommand( "class" );
trap_AddCommand( "build" );
trap_AddCommand( "buy" );
@@ -315,11 +369,6 @@ void CG_InitConsoleCommands( void )
trap_AddCommand( "itemtoggle" );
trap_AddCommand( "destroy" );
trap_AddCommand( "deconstruct" );
- trap_AddCommand( "menu" );
- trap_AddCommand( "ui_menu" );
- trap_AddCommand( "mapRotation" );
- trap_AddCommand( "stopMapRotation" );
- trap_AddCommand( "advanceMapRotation" );
- trap_AddCommand( "alienWin" );
- trap_AddCommand( "humanWin" );
+ trap_AddCommand( "ignore" );
+ trap_AddCommand( "unignore" );
}
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c
index 1a3ecae..38c9578 100644
--- a/src/cgame/cg_draw.c
+++ b/src/cgame/cg_draw.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,284 +17,84 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_draw.c -- draw all of the graphical elements during
// active (after loading) gameplay
-
#include "cg_local.h"
-#include "../ui/ui_shared.h"
+#include "ui/ui_shared.h"
-// used for scoreboard
-extern displayContextDef_t cgDC;
menuDef_t *menuScoreboard = NULL;
-int drawTeamOverlayModificationCount = -1;
-
-int sortedTeamPlayers[ TEAM_MAXOVERLAY ];
-int numSortedTeamPlayers;
-
-//TA UI
-int CG_Text_Width( const char *text, float scale, int limit )
+static void CG_AlignText( rectDef_t *rect, const char *text, float scale,
+ float w, float h,
+ int align, int valign,
+ float *x, float *y )
{
- int count,len;
- float out;
- glyphInfo_t *glyph;
- float useScale;
-// FIXME: see ui_main.c, same problem
-// const unsigned char *s = text;
- const char *s = text;
- fontInfo_t *font = &cgDC.Assets.textFont;
+ float tx, ty;
- if( scale <= cg_smallFont.value )
- font = &cgDC.Assets.smallFont;
- else if( scale > cg_bigFont.value )
- font = &cgDC.Assets.bigFont;
-
- useScale = scale * font->glyphScale;
- out = 0;
-
- if( text )
+ if( scale > 0.0f )
{
- len = strlen( text );
- if( limit > 0 && len > limit )
- len = limit;
-
- count = 0;
- while( s && *s && count < len )
- {
- if( Q_IsColorString( s ) )
- {
- s += 2;
- continue;
- }
- else
- {
- glyph = &font->glyphs[ (int)*s ];
- //TTimo: FIXME: getting nasty warnings without the cast,
- //hopefully this doesn't break the VM build
- out += glyph->xSkip;
- s++;
- count++;
- }
- }
+ w = UI_Text_Width( text, scale );
+ h = UI_Text_Height( text, scale );
}
- return out * useScale;
-}
-
-int CG_Text_Height( const char *text, float scale, int limit )
-{
- int len, count;
- float max;
- glyphInfo_t *glyph;
- float useScale;
-// TTimo: FIXME
-// const unsigned char *s = text;
- const char *s = text;
- fontInfo_t *font = &cgDC.Assets.textFont;
-
- if( scale <= cg_smallFont.value )
- font = &cgDC.Assets.smallFont;
- else if( scale > cg_bigFont.value )
- font = &cgDC.Assets.bigFont;
-
- useScale = scale * font->glyphScale;
- max = 0;
-
- if( text )
+ switch( align )
{
- len = strlen( text );
- if( limit > 0 && len > limit )
- len = limit;
-
- count = 0;
- while( s && *s && count < len )
- {
- if( Q_IsColorString( s ) )
- {
- s += 2;
- continue;
- }
- else
- {
- glyph = &font->glyphs[ (int)*s ];
- //TTimo: FIXME: getting nasty warnings without the cast,
- //hopefully this doesn't break the VM build
- if( max < glyph->height )
- max = glyph->height;
-
- s++;
- count++;
- }
- }
- }
-
- return max * useScale;
-}
+ default:
+ case ALIGN_LEFT:
+ tx = 0.0f;
+ break;
-void CG_Text_PaintChar( float x, float y, float width, float height, float scale,
- float s, float t, float s2, float t2, qhandle_t hShader )
-{
- float w, h;
- w = width * scale;
- h = height * scale;
- CG_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
-}
+ case ALIGN_RIGHT:
+ tx = rect->w - w;
+ break;
-void CG_Text_Paint( float x, float y, float scale, vec4_t color, const char *text,
- float adjust, int limit, int style )
-{
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- float useScale;
- fontInfo_t *font = &cgDC.Assets.textFont;
+ case ALIGN_CENTER:
+ tx = ( rect->w - w ) / 2.0f;
+ break;
- if( scale <= cg_smallFont.value )
- font = &cgDC.Assets.smallFont;
- else if( scale > cg_bigFont.value )
- font = &cgDC.Assets.bigFont;
+ case ALIGN_NONE:
+ tx = 0;
+ break;
+ }
- useScale = scale * font->glyphScale;
- if( text )
+ switch( valign )
{
-// TTimo: FIXME
-// const unsigned char *s = text;
- const char *s = text;
-
- trap_R_SetColor( color );
- memcpy( &newColor[ 0 ], &color[ 0 ], sizeof( vec4_t ) );
- len = strlen( text );
-
- if( limit > 0 && len > limit )
- len = limit;
-
- count = 0;
- while( s && *s && count < len )
- {
- glyph = &font->glyphs[ (int)*s ];
- //TTimo: FIXME: getting nasty warnings without the cast,
- //hopefully this doesn't break the VM build
+ default:
+ case VALIGN_BOTTOM:
+ ty = rect->h;
+ break;
- if( Q_IsColorString( s ) )
- {
- memcpy( newColor, g_color_table[ ColorIndex( *( s + 1 ) ) ], sizeof( newColor ) );
- newColor[ 3 ] = color[ 3 ];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- }
- else
- {
- float yadj = useScale * glyph->top;
- if( style == ITEM_TEXTSTYLE_SHADOWED ||
- style == ITEM_TEXTSTYLE_SHADOWEDMORE )
- {
- int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
- colorBlack[ 3 ] = newColor[ 3 ];
- trap_R_SetColor( colorBlack );
- CG_Text_PaintChar( x + ofs, y - yadj + ofs,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
-
- colorBlack[ 3 ] = 1.0;
- trap_R_SetColor( newColor );
- }
- else if( style == ITEM_TEXTSTYLE_NEON )
- {
- vec4_t glow, outer, inner, white;
-
- glow[ 0 ] = newColor[ 0 ] * 0.5;
- glow[ 1 ] = newColor[ 1 ] * 0.5;
- glow[ 2 ] = newColor[ 2 ] * 0.5;
- glow[ 3 ] = newColor[ 3 ] * 0.2;
-
- outer[ 0 ] = newColor[ 0 ];
- outer[ 1 ] = newColor[ 1 ];
- outer[ 2 ] = newColor[ 2 ];
- outer[ 3 ] = newColor[ 3 ];
-
- inner[ 0 ] = newColor[ 0 ] * 1.5 > 1.0f ? 1.0f : newColor[ 0 ] * 1.5;
- inner[ 1 ] = newColor[ 1 ] * 1.5 > 1.0f ? 1.0f : newColor[ 1 ] * 1.5;
- inner[ 2 ] = newColor[ 2 ] * 1.5 > 1.0f ? 1.0f : newColor[ 2 ] * 1.5;
- inner[ 3 ] = newColor[ 3 ];
-
- white[ 0 ] = white[ 1 ] = white[ 2 ] = white[ 3 ] = 1.0f;
-
- trap_R_SetColor( glow );
- CG_Text_PaintChar( x - 3, y - yadj - 3,
- glyph->imageWidth + 6,
- glyph->imageHeight + 6,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
-
- trap_R_SetColor( outer );
- CG_Text_PaintChar( x - 1, y - yadj - 1,
- glyph->imageWidth + 2,
- glyph->imageHeight + 2,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
-
- trap_R_SetColor( inner );
- CG_Text_PaintChar( x - 0.5, y - yadj - 0.5,
- glyph->imageWidth + 1,
- glyph->imageHeight + 1,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
-
- trap_R_SetColor( white );
- }
+ case VALIGN_TOP:
+ ty = h;
+ break;
+ case VALIGN_CENTER:
+ ty = h + ( ( rect->h - h ) / 2.0f );
+ break;
- CG_Text_PaintChar( x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
+ case VALIGN_NONE:
+ ty = 0;
+ break;
+ }
- x += ( glyph->xSkip * useScale ) + adjust;
- s++;
- count++;
- }
- }
+ if( x )
+ *x = rect->x + tx;
- trap_R_SetColor( NULL );
- }
+ if( y )
+ *y = rect->y + ty;
}
/*
==============
CG_DrawFieldPadded
-Draws large numbers for status bar and powerups
+Draws large numbers for status bar
==============
*/
static void CG_DrawFieldPadded( int x, int y, int width, int cw, int ch, int value )
@@ -307,7 +108,7 @@ static void CG_DrawFieldPadded( int x, int y, int width, int cw, int ch, int val
charWidth = CHAR_WIDTH;
if( !( charHeight = ch ) )
- charWidth = CHAR_HEIGHT;
+ charHeight = CHAR_HEIGHT;
if( width < 1 )
return;
@@ -344,7 +145,7 @@ static void CG_DrawFieldPadded( int x, int y, int width, int cw, int ch, int val
orgL = l;
- x += 2;
+ x += ( 2.0f * cgDC.aspectScale );
ptr = num;
while( *ptr && l )
@@ -373,7 +174,7 @@ static void CG_DrawFieldPadded( int x, int y, int width, int cw, int ch, int val
==============
CG_DrawField
-Draws large numbers for status bar and powerups
+Draws large numbers for status bar
==============
*/
void CG_DrawField( float x, float y, int width, float cw, float ch, int value )
@@ -387,7 +188,7 @@ void CG_DrawField( float x, float y, int width, float cw, float ch, int value )
charWidth = CHAR_WIDTH;
if( !( charHeight = ch ) )
- charWidth = CHAR_HEIGHT;
+ charHeight = CHAR_HEIGHT;
if( width < 1 )
return;
@@ -422,7 +223,7 @@ void CG_DrawField( float x, float y, int width, float cw, float ch, int value )
if( l > width )
l = width;
- x += 2 + charWidth * ( width - l );
+ x += ( 2.0f * cgDC.aspectScale ) + charWidth * ( width - l );
ptr = num;
while( *ptr && l )
@@ -440,18 +241,22 @@ void CG_DrawField( float x, float y, int width, float cw, float ch, int value )
}
static void CG_DrawProgressBar( rectDef_t *rect, vec4_t color, float scale,
- int align, int textStyle, int special, float progress )
+ int align, int textalign, int textStyle,
+ float borderSize, float progress )
{
- float rimWidth = rect->h / 20.0f;
+ float rimWidth;
float doneWidth, leftWidth;
- float tx, ty, tw, th;
+ float tx, ty;
char textBuffer[ 8 ];
- if( rimWidth < 0.6f )
- rimWidth = 0.6f;
-
- if( special >= 0.0f )
- rimWidth = special;
+ if( borderSize >= 0.0f )
+ rimWidth = borderSize;
+ else
+ {
+ rimWidth = rect->h / 20.0f;
+ if( rimWidth < 0.6f )
+ rimWidth = 0.6f;
+ }
if( progress < 0.0f )
progress = 0.0f;
@@ -464,7 +269,7 @@ static void CG_DrawProgressBar( rectDef_t *rect, vec4_t color, float scale,
trap_R_SetColor( color );
//draw rim and bar
- if( align == ITEM_ALIGN_RIGHT )
+ if( align == ALIGN_RIGHT )
{
CG_DrawPic( rect->x, rect->y, rimWidth, rect->h, cgs.media.whiteShader );
CG_DrawPic( rect->x + rimWidth, rect->y,
@@ -490,31 +295,9 @@ static void CG_DrawProgressBar( rectDef_t *rect, vec4_t color, float scale,
if( scale > 0.0 )
{
Com_sprintf( textBuffer, sizeof( textBuffer ), "%d%%", (int)( progress * 100 ) );
- tw = CG_Text_Width( textBuffer, scale, 0 );
- th = scale * 40.0f;
-
- switch( align )
- {
- case ITEM_ALIGN_LEFT:
- tx = rect->x + ( rect->w / 10.0f );
- ty = rect->y + ( rect->h / 2.0f ) + ( th / 2.0f );
- break;
-
- case ITEM_ALIGN_RIGHT:
- tx = rect->x + rect->w - ( rect->w / 10.0f ) - tw;
- ty = rect->y + ( rect->h / 2.0f ) + ( th / 2.0f );
- break;
-
- case ITEM_ALIGN_CENTER:
- tx = rect->x + ( rect->w / 2.0f ) - ( tw / 2.0f );
- ty = rect->y + ( rect->h / 2.0f ) + ( th / 2.0f );
- break;
+ CG_AlignText( rect, textBuffer, scale, 0.0f, 0.0f, textalign, VALIGN_CENTER, &tx, &ty );
- default:
- tx = ty = 0.0f;
- }
-
- CG_Text_Paint( tx, ty, scale, color, textBuffer, 0, 0, textStyle );
+ UI_Text_Paint( tx, ty, scale, color, textBuffer, 0, 0, textStyle );
}
}
@@ -539,14 +322,17 @@ static void CG_DrawPlayerCreditsValue( rectDef_t *rect, vec4_t color, qboolean p
value = ps->persistant[ PERS_CREDIT ];
if( value > -1 )
{
- if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS &&
- !CG_AtHighestClass( ) )
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
- if( cg.time - cg.lastEvolveAttempt <= NO_CREDITS_TIME )
+ if( !BG_AlienCanEvolve( cg.predictedPlayerState.stats[ STAT_CLASS ],
+ value, cgs.alienStage ) &&
+ cg.time - cg.lastEvolveAttempt <= NO_CREDITS_TIME &&
+ ( ( cg.time - cg.lastEvolveAttempt ) / 300 ) & 1 )
{
- if( ( ( cg.time - cg.lastEvolveAttempt ) / 300 ) % 2 )
- color[ 3 ] = 0.0f;
+ color[ 3 ] = 0.0f;
}
+
+ value /= ALIEN_CREDITS_PER_KILL;
}
trap_R_SetColor( color );
@@ -560,135 +346,66 @@ static void CG_DrawPlayerCreditsValue( rectDef_t *rect, vec4_t color, qboolean p
}
}
-static void CG_DrawPlayerBankValue( rectDef_t *rect, vec4_t color, qboolean padding )
+static void CG_DrawPlayerCreditsFraction( rectDef_t *rect, vec4_t color, qhandle_t shader )
{
- int value;
- playerState_t *ps;
-
- ps = &cg.snap->ps;
-
- value = ps->persistant[ PERS_BANK ];
- if( value > -1 )
- {
- trap_R_SetColor( color );
-
- if( padding )
- CG_DrawFieldPadded( rect->x, rect->y, 4, rect->w / 4, rect->h, value );
- else
- CG_DrawField( rect->x, rect->y, 1, rect->w, rect->h, value );
-
- trap_R_SetColor( NULL );
- }
-}
-
-#define HH_MIN_ALPHA 0.2f
-#define HH_MAX_ALPHA 0.8f
-#define HH_ALPHA_DIFF (HH_MAX_ALPHA-HH_MIN_ALPHA)
+ float fraction;
+ float height;
-#define AH_MIN_ALPHA 0.2f
-#define AH_MAX_ALPHA 0.8f
-#define AH_ALPHA_DIFF (AH_MAX_ALPHA-AH_MIN_ALPHA)
-
-/*
-==============
-CG_DrawPlayerStamina1
-==============
-*/
-static void CG_DrawPlayerStamina1( rectDef_t *rect, vec4_t color, qhandle_t shader )
-{
- playerState_t *ps = &cg.snap->ps;
- float stamina = ps->stats[ STAT_STAMINA ];
- float maxStaminaBy3 = (float)MAX_STAMINA / 3.0f;
- float progress;
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] != TEAM_ALIENS )
+ return;
- stamina -= ( 2 * (int)maxStaminaBy3 );
- progress = stamina / maxStaminaBy3;
+ fraction = ((float)(cg.predictedPlayerState.persistant[ PERS_CREDIT ] %
+ ALIEN_CREDITS_PER_KILL)) / ALIEN_CREDITS_PER_KILL;
- if( progress > 1.0f )
- progress = 1.0f;
- else if( progress < 0.0f )
- progress = 0.0f;
-
- color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF );
+ CG_AdjustFrom640( &rect->x, &rect->y, &rect->w, &rect->h );
+ height = rect->h * fraction;
trap_R_SetColor( color );
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
+ trap_R_DrawStretchPic( rect->x, rect->y - height + rect->h, rect->w,
+ height, 0.0f, 1.0f - fraction, 1.0f, 1.0f, shader );
trap_R_SetColor( NULL );
}
-/*
-==============
-CG_DrawPlayerStamina2
-==============
-*/
-static void CG_DrawPlayerStamina2( rectDef_t *rect, vec4_t color, qhandle_t shader )
-{
- playerState_t *ps = &cg.snap->ps;
- float stamina = ps->stats[ STAT_STAMINA ];
- float maxStaminaBy3 = (float)MAX_STAMINA / 3.0f;
- float progress;
-
- stamina -= (int)maxStaminaBy3;
- progress = stamina / maxStaminaBy3;
-
- if( progress > 1.0f )
- progress = 1.0f;
- else if( progress < 0.0f )
- progress = 0.0f;
-
- color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF );
-
- trap_R_SetColor( color );
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
- trap_R_SetColor( NULL );
-}
/*
==============
-CG_DrawPlayerStamina3
+CG_DrawPlayerStamina
==============
*/
-static void CG_DrawPlayerStamina3( rectDef_t *rect, vec4_t color, qhandle_t shader )
+static void CG_DrawPlayerStamina( int ownerDraw, rectDef_t *rect,
+ vec4_t backColor, vec4_t foreColor,
+ qhandle_t shader )
{
playerState_t *ps = &cg.snap->ps;
float stamina = ps->stats[ STAT_STAMINA ];
- float maxStaminaBy3 = (float)MAX_STAMINA / 3.0f;
+ float maxStaminaBy3 = (float)STAMINA_MAX / 3.0f;
float progress;
+ vec4_t color;
+ switch( ownerDraw )
+ {
+ case CG_PLAYER_STAMINA_1:
+ progress = ( stamina - 2 * (int)maxStaminaBy3 ) / maxStaminaBy3;
+ break;
+ case CG_PLAYER_STAMINA_2:
+ progress = ( stamina - (int)maxStaminaBy3 ) / maxStaminaBy3;
+ break;
+ case CG_PLAYER_STAMINA_3:
progress = stamina / maxStaminaBy3;
+ break;
+ case CG_PLAYER_STAMINA_4:
+ progress = ( stamina + STAMINA_MAX ) / STAMINA_MAX;
+ break;
+ default:
+ return;
+ }
if( progress > 1.0f )
progress = 1.0f;
else if( progress < 0.0f )
progress = 0.0f;
- color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF );
-
- trap_R_SetColor( color );
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
- trap_R_SetColor( NULL );
-}
-
-/*
-==============
-CG_DrawPlayerStamina4
-==============
-*/
-static void CG_DrawPlayerStamina4( rectDef_t *rect, vec4_t color, qhandle_t shader )
-{
- playerState_t *ps = &cg.snap->ps;
- float stamina = ps->stats[ STAT_STAMINA ];
- float progress;
-
- stamina += (float)MAX_STAMINA;
- progress = stamina / (float)MAX_STAMINA;
-
- if( progress > 1.0f )
- progress = 1.0f;
- else if( progress < 0.0f )
- progress = 0.0f;
-
- color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF );
+ Vector4Lerp( progress, backColor, foreColor, color );
trap_R_SetColor( color );
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
@@ -700,15 +417,28 @@ static void CG_DrawPlayerStamina4( rectDef_t *rect, vec4_t color, qhandle_t shad
CG_DrawPlayerStaminaBolt
==============
*/
-static void CG_DrawPlayerStaminaBolt( rectDef_t *rect, vec4_t color, qhandle_t shader )
+static void CG_DrawPlayerStaminaBolt( rectDef_t *rect, vec4_t backColor,
+ vec4_t foreColor, qhandle_t shader )
{
- playerState_t *ps = &cg.snap->ps;
- float stamina = ps->stats[ STAT_STAMINA ];
+ float stamina = cg.snap->ps.stats[ STAT_STAMINA ];
+ vec4_t color;
- if( stamina < 0 )
- color[ 3 ] = HH_MIN_ALPHA;
+ if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_SPEEDBOOST )
+ {
+ if( stamina >= 0 )
+ Vector4Lerp( ( sin( cg.time / 150.0f ) + 1 ) / 2,
+ backColor, foreColor, color );
+ else
+ Vector4Lerp( ( sin( cg.time / 2000.0f ) + 1 ) / 2,
+ backColor, foreColor, color );
+ }
else
- color[ 3 ] = HH_MAX_ALPHA;
+ {
+ if( stamina < 0 )
+ Vector4Copy( backColor, color );
+ else
+ Vector4Copy( foreColor, color );
+ }
trap_R_SetColor( color );
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
@@ -720,40 +450,42 @@ static void CG_DrawPlayerStaminaBolt( rectDef_t *rect, vec4_t color, qhandle_t s
CG_DrawPlayerClipsRing
==============
*/
-static void CG_DrawPlayerClipsRing( rectDef_t *rect, vec4_t color, qhandle_t shader )
+static void CG_DrawPlayerClipsRing( rectDef_t *rect, vec4_t backColor,
+ vec4_t foreColor, qhandle_t shader )
{
playerState_t *ps = &cg.snap->ps;
centity_t *cent;
float buildTime = ps->stats[ STAT_MISC ];
float progress;
float maxDelay;
+ weapon_t weapon;
+ vec4_t color;
cent = &cg_entities[ cg.snap->ps.clientNum ];
+ weapon = BG_GetPlayerWeapon( ps );
- switch( cent->currentState.weapon )
+ switch( weapon )
{
case WP_ABUILD:
case WP_ABUILD2:
case WP_HBUILD:
- case WP_HBUILD2:
- maxDelay = (float)BG_FindBuildDelayForWeapon( cent->currentState.weapon );
-
- if( buildTime > maxDelay )
- buildTime = maxDelay;
+ if( buildTime > MAXIMUM_BUILD_TIME )
+ buildTime = MAXIMUM_BUILD_TIME;
+ progress = ( MAXIMUM_BUILD_TIME - buildTime ) / MAXIMUM_BUILD_TIME;
- progress = ( maxDelay - buildTime ) / maxDelay;
-
- color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF );
+ Vector4Lerp( progress, backColor, foreColor, color );
break;
default:
if( ps->weaponstate == WEAPON_RELOADING )
{
- maxDelay = (float)BG_FindReloadTimeForWeapon( cent->currentState.weapon );
+ maxDelay = (float)BG_Weapon( cent->currentState.weapon )->reloadTime;
progress = ( maxDelay - (float)ps->weaponTime ) / maxDelay;
- color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF );
+ Vector4Lerp( progress, backColor, foreColor, color );
}
+ else
+ Com_Memcpy( color, foreColor, sizeof( color ) );
break;
}
@@ -767,24 +499,20 @@ static void CG_DrawPlayerClipsRing( rectDef_t *rect, vec4_t color, qhandle_t sha
CG_DrawPlayerBuildTimerRing
==============
*/
-static void CG_DrawPlayerBuildTimerRing( rectDef_t *rect, vec4_t color, qhandle_t shader )
+static void CG_DrawPlayerBuildTimerRing( rectDef_t *rect, vec4_t backColor,
+ vec4_t foreColor, qhandle_t shader )
{
playerState_t *ps = &cg.snap->ps;
- centity_t *cent;
float buildTime = ps->stats[ STAT_MISC ];
float progress;
- float maxDelay;
-
- cent = &cg_entities[ cg.snap->ps.clientNum ];
+ vec4_t color;
- maxDelay = (float)BG_FindBuildDelayForWeapon( cent->currentState.weapon );
+ if( buildTime > MAXIMUM_BUILD_TIME )
+ buildTime = MAXIMUM_BUILD_TIME;
- if( buildTime > maxDelay )
- buildTime = maxDelay;
+ progress = ( MAXIMUM_BUILD_TIME - buildTime ) / MAXIMUM_BUILD_TIME;
- progress = ( maxDelay - buildTime ) / maxDelay;
-
- color[ 3 ] = AH_MIN_ALPHA + ( progress * AH_ALPHA_DIFF );
+ Vector4Lerp( progress, backColor, foreColor, color );
trap_R_SetColor( color );
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
@@ -796,17 +524,14 @@ static void CG_DrawPlayerBuildTimerRing( rectDef_t *rect, vec4_t color, qhandle_
CG_DrawPlayerBoosted
==============
*/
-static void CG_DrawPlayerBoosted( rectDef_t *rect, vec4_t color, qhandle_t shader )
+static void CG_DrawPlayerBoosted( rectDef_t *rect, vec4_t backColor,
+ vec4_t foreColor, qhandle_t shader )
{
- playerState_t *ps = &cg.snap->ps;
- qboolean boosted = ps->stats[ STAT_STATE ] & SS_BOOSTED;
-
- if( boosted )
- color[ 3 ] = AH_MAX_ALPHA;
+ if( cg.snap->ps.stats[ STAT_STATE ] & SS_BOOSTED )
+ trap_R_SetColor( foreColor );
else
- color[ 3 ] = AH_MIN_ALPHA;
+ trap_R_SetColor( backColor );
- trap_R_SetColor( color );
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
trap_R_SetColor( NULL );
}
@@ -816,26 +541,20 @@ static void CG_DrawPlayerBoosted( rectDef_t *rect, vec4_t color, qhandle_t shade
CG_DrawPlayerBoosterBolt
==============
*/
-static void CG_DrawPlayerBoosterBolt( rectDef_t *rect, vec4_t color, qhandle_t shader )
+static void CG_DrawPlayerBoosterBolt( rectDef_t *rect, vec4_t backColor,
+ vec4_t foreColor, qhandle_t shader )
{
- playerState_t *ps = &cg.snap->ps;
- qboolean boosted = ps->stats[ STAT_STATE ] & SS_BOOSTED;
- vec4_t localColor;
-
- Vector4Copy( color, localColor );
-
- if( boosted )
- {
- if( ps->stats[ STAT_BOOSTTIME ] > BOOST_TIME - 3000 )
- {
- qboolean flash = ( ps->stats[ STAT_BOOSTTIME ] / 500 ) % 2;
+ vec4_t color;
- if( flash )
- localColor[ 3 ] = 1.0f;
- }
- }
+ // Flash bolts when the boost is almost out
+ if( ( cg.snap->ps.stats[ STAT_STATE ] & SS_BOOSTED ) &&
+ ( cg.snap->ps.stats[ STAT_STATE ] & SS_BOOSTEDWARNING ) )
+ Vector4Lerp( ( sin( cg.time / 100.0f ) + 1 ) / 2,
+ backColor, foreColor, color );
+ else
+ Vector4Copy( foreColor, color );
- trap_R_SetColor( localColor );
+ trap_R_SetColor( color );
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
trap_R_SetColor( NULL );
}
@@ -847,38 +566,49 @@ CG_DrawPlayerPoisonBarbs
*/
static void CG_DrawPlayerPoisonBarbs( rectDef_t *rect, vec4_t color, qhandle_t shader )
{
- playerState_t *ps = &cg.snap->ps;
- int x = rect->x;
- int y = rect->y;
- int width = rect->w;
- int height = rect->h;
- qboolean vertical;
- int iconsize, numBarbs, i;
+ qboolean vertical;
+ float x = rect->x, y = rect->y;
+ float width = rect->w, height = rect->h;
+ float diff;
+ int iconsize, numBarbs, maxBarbs;
- numBarbs = ps->ammo;
+ maxBarbs = BG_Weapon( cg.snap->ps.weapon )->maxAmmo;
+ numBarbs = cg.snap->ps.ammo;
+ if( maxBarbs <= 0 || numBarbs <= 0 )
+ return;
+
+ // adjust these first to ensure the aspect ratio of the barb image is
+ // preserved
+ CG_AdjustFrom640( &x, &y, &width, &height );
if( height > width )
{
vertical = qtrue;
iconsize = width;
+ if( maxBarbs != 1 ) // avoid division by zero
+ diff = ( height - iconsize ) / (float)( maxBarbs - 1 );
+ else
+ diff = 0; // doesn't matter, won't be used
}
- else if( height <= width )
+ else
{
vertical = qfalse;
iconsize = height;
+ if( maxBarbs != 1 )
+ diff = ( width - iconsize ) / (float)( maxBarbs - 1 );
+ else
+ diff = 0;
}
- if( color[ 3 ] != 0.0 )
- trap_R_SetColor( color );
+ trap_R_SetColor( color );
- for( i = 0; i < numBarbs; i ++ )
+ for( ; numBarbs > 0; numBarbs-- )
{
+ trap_R_DrawStretchPic( x, y, iconsize, iconsize, 0, 0, 1, 1, shader );
if( vertical )
- y += iconsize;
+ y += diff;
else
- x += iconsize;
-
- CG_DrawPic( x, y, iconsize, iconsize, shader );
+ x += diff;
}
trap_R_SetColor( NULL );
@@ -889,70 +619,83 @@ static void CG_DrawPlayerPoisonBarbs( rectDef_t *rect, vec4_t color, qhandle_t s
CG_DrawPlayerWallclimbing
==============
*/
-static void CG_DrawPlayerWallclimbing( rectDef_t *rect, vec4_t color, qhandle_t shader )
+static void CG_DrawPlayerWallclimbing( rectDef_t *rect, vec4_t backColor, vec4_t foreColor, qhandle_t shader )
{
- playerState_t *ps = &cg.snap->ps;
- qboolean ww = ps->stats[ STAT_STATE ] & SS_WALLCLIMBING;
-
- if( ww )
- color[ 3 ] = AH_MAX_ALPHA;
+ if( cg.snap->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING )
+ trap_R_SetColor( foreColor );
else
- color[ 3 ] = AH_MIN_ALPHA;
+ trap_R_SetColor( backColor );
- trap_R_SetColor( color );
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
trap_R_SetColor( NULL );
}
-static void CG_DrawPlayerStamina( rectDef_t *rect, vec4_t color, float scale,
- int align, int textStyle, int special )
-{
- playerState_t *ps = &cg.snap->ps;
- int stamina = ps->stats[ STAT_STAMINA ];
- float progress = ( (float)stamina + (float)MAX_STAMINA ) / ( (float)MAX_STAMINA * 2.0f );
-
- CG_DrawProgressBar( rect, color, scale, align, textStyle, special, progress );
-}
-
static void CG_DrawPlayerAmmoValue( rectDef_t *rect, vec4_t color )
{
- int value;
- centity_t *cent;
- playerState_t *ps;
-
- cent = &cg_entities[ cg.snap->ps.clientNum ];
- ps = &cg.snap->ps;
+ int value;
+ int valueMarked = -1;
+ qboolean bp = qfalse;
- if( cent->currentState.weapon )
+ switch( cg.snap->ps.stats[ STAT_WEAPON ] )
{
- switch( cent->currentState.weapon )
- {
- case WP_ABUILD:
- case WP_ABUILD2:
- //percentage of BP remaining
- value = cgs.alienBuildPoints;
- break;
+ case WP_NONE:
+ case WP_BLASTER:
+ return;
- case WP_HBUILD:
- case WP_HBUILD2:
- //percentage of BP remaining
- value = cgs.humanBuildPoints;
- break;
+ case WP_ABUILD:
+ case WP_ABUILD2:
+ case WP_HBUILD:
+ value = cg.snap->ps.persistant[ PERS_BP ];
+ valueMarked = cg.snap->ps.persistant[ PERS_MARKEDBP ];
+ bp = qtrue;
+ break;
- default:
- value = ps->ammo;
- break;
- }
+ default:
+ value = cg.snap->ps.ammo;
+ break;
+ }
+
+ if( value > 999 )
+ value = 999;
+ if( valueMarked > 999 )
+ valueMarked = 999;
- if( value > 999 )
- value = 999;
+ if( value > -1 )
+ {
+ float tx, ty;
+ const char *text;
+ float scale;
+ int len;
- if( value > -1 )
+ trap_R_SetColor( color );
+ if( !bp )
{
- trap_R_SetColor( color );
- CG_DrawField( rect->x, rect->y, 4, rect->w / 4, rect->h, value );
+ CG_DrawField( rect->x - 5, rect->y, 4, rect->w / 4, rect->h, value );
trap_R_SetColor( NULL );
+ return;
}
+
+ if( valueMarked > 0 )
+ text = va( "%d+(%d)", value, valueMarked );
+ else
+ text = va( "%d", value );
+
+ len = strlen( text );
+
+ if( len <= 4 )
+ scale = 0.50;
+ else if( len <= 6 )
+ scale = 0.43;
+ else if( len == 7 )
+ scale = 0.36;
+ else if( len == 8 )
+ scale = 0.33;
+ else
+ scale = 0.31;
+
+ CG_AlignText( rect, text, scale, 0.0f, 0.0f, ALIGN_RIGHT, VALIGN_CENTER, &tx, &ty );
+ UI_Text_Paint( tx + 1, ty, scale, color, text, 0, 0, ITEM_TEXTSTYLE_NORMAL );
+ trap_R_SetColor( NULL );
}
}
@@ -964,7 +707,7 @@ CG_DrawAlienSense
*/
static void CG_DrawAlienSense( rectDef_t *rect )
{
- if( BG_ClassHasAbility( cg.snap->ps.stats[ STAT_PCLASS ], SCA_ALIENSENSE ) )
+ if( BG_ClassHasAbility( cg.snap->ps.stats[ STAT_CLASS ], SCA_ALIENSENSE ) )
CG_AlienSense( rect );
}
@@ -999,19 +742,25 @@ static void CG_DrawUsableBuildable( rectDef_t *rect, qhandle_t shader, vec4_t co
es = &cg_entities[ trace.entityNum ].currentState;
- if( es->eType == ET_BUILDABLE && BG_FindUsableForBuildable( es->modelindex ) &&
- cg.predictedPlayerState.stats[ STAT_PTEAM ] == BG_FindTeamForBuildable( es->modelindex ) )
+ if( es->eType == ET_BUILDABLE && BG_Buildable( es->modelindex )->usable &&
+ cg.predictedPlayerState.stats[ STAT_TEAM ] == BG_Buildable( es->modelindex )->team )
{
//hack to prevent showing the usable buildable when you aren't carrying an energy weapon
if( ( es->modelindex == BA_H_REACTOR || es->modelindex == BA_H_REPEATER ) &&
- ( !BG_FindUsesEnergyForWeapon( cg.snap->ps.weapon ) ||
- BG_FindInfinteAmmoForWeapon( cg.snap->ps.weapon ) ) )
+ ( !BG_Weapon( cg.snap->ps.weapon )->usesEnergy ||
+ BG_Weapon( cg.snap->ps.weapon )->infiniteAmmo ) )
+ {
+ cg.nearUsableBuildable = BA_NONE;
return;
+ }
trap_R_SetColor( color );
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
trap_R_SetColor( NULL );
+ cg.nearUsableBuildable = es->modelindex;
}
+ else
+ cg.nearUsableBuildable = BA_NONE;
}
@@ -1019,221 +768,381 @@ static void CG_DrawUsableBuildable( rectDef_t *rect, qhandle_t shader, vec4_t co
static void CG_DrawPlayerBuildTimer( rectDef_t *rect, vec4_t color )
{
- float progress;
int index;
- centity_t *cent;
playerState_t *ps;
- cent = &cg_entities[ cg.snap->ps.clientNum ];
ps = &cg.snap->ps;
- if( cent->currentState.weapon )
- {
- switch( cent->currentState.weapon )
- {
- case WP_ABUILD:
- progress = (float)ps->stats[ STAT_MISC ] / (float)ABUILDER_BASE_DELAY;
- break;
-
- case WP_ABUILD2:
- progress = (float)ps->stats[ STAT_MISC ] / (float)ABUILDER_ADV_DELAY;
- break;
-
- case WP_HBUILD:
- progress = (float)ps->stats[ STAT_MISC ] / (float)HBUILD_DELAY;
- break;
-
- case WP_HBUILD2:
- progress = (float)ps->stats[ STAT_MISC ] / (float)HBUILD2_DELAY;
- break;
+ if( ps->stats[ STAT_MISC ] <= 0 )
+ return;
- default:
- return;
- break;
- }
+ switch( ps->stats[ STAT_WEAPON ] )
+ {
+ case WP_ABUILD:
+ case WP_ABUILD2:
+ case WP_HBUILD:
+ break;
- if( !ps->stats[ STAT_MISC ] )
+ default:
return;
+ }
- index = (int)( progress * 8.0f );
-
- if( index > 7 )
- index = 7;
- else if( index < 0 )
- index = 0;
-
- if( cg.time - cg.lastBuildAttempt <= BUILD_DELAY_TIME )
- {
- if( ( ( cg.time - cg.lastBuildAttempt ) / 300 ) % 2 )
- {
- color[ 0 ] = 1.0f;
- color[ 1 ] = color[ 2 ] = 0.0f;
- color[ 3 ] = 1.0f;
- }
- }
+ index = 8 * ( ps->stats[ STAT_MISC ] - 1 ) / MAXIMUM_BUILD_TIME;
+ if( index > 7 )
+ index = 7;
+ else if( index < 0 )
+ index = 0;
- trap_R_SetColor( color );
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h,
- cgs.media.buildWeaponTimerPie[ index ] );
- trap_R_SetColor( NULL );
+ if( cg.time - cg.lastBuildAttempt <= BUILD_DELAY_TIME &&
+ ( ( cg.time - cg.lastBuildAttempt ) / 300 ) % 2 )
+ {
+ color[ 0 ] = 1.0f;
+ color[ 1 ] = color[ 2 ] = 0.0f;
+ color[ 3 ] = 1.0f;
}
+
+ trap_R_SetColor( color );
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h,
+ cgs.media.buildWeaponTimerPie[ index ] );
+ trap_R_SetColor( NULL );
}
static void CG_DrawPlayerClipsValue( rectDef_t *rect, vec4_t color )
{
int value;
- centity_t *cent;
- playerState_t *ps;
-
- cent = &cg_entities[ cg.snap->ps.clientNum ];
- ps = &cg.snap->ps;
+ playerState_t *ps = &cg.snap->ps;
- if( cent->currentState.weapon )
+ switch( ps->stats[ STAT_WEAPON ] )
{
- switch( cent->currentState.weapon )
- {
- case WP_ABUILD:
- case WP_ABUILD2:
- case WP_HBUILD:
- case WP_HBUILD2:
- break;
+ case WP_NONE:
+ case WP_BLASTER:
+ case WP_ABUILD:
+ case WP_ABUILD2:
+ case WP_HBUILD:
+ return;
- default:
- value = ps->clips;
+ default:
+ value = ps->clips;
- if( value > -1 )
- {
- trap_R_SetColor( color );
- CG_DrawField( rect->x, rect->y, 4, rect->w / 4, rect->h, value );
- trap_R_SetColor( NULL );
- }
- break;
- }
+ if( value > -1 )
+ {
+ trap_R_SetColor( color );
+ CG_DrawField( rect->x, rect->y, 4, rect->w / 4, rect->h, value );
+ trap_R_SetColor( NULL );
+ }
+ break;
}
}
static void CG_DrawPlayerHealthValue( rectDef_t *rect, vec4_t color )
{
- playerState_t *ps;
- int value;
-
- ps = &cg.snap->ps;
-
- value = ps->stats[ STAT_HEALTH ];
-
trap_R_SetColor( color );
- CG_DrawField( rect->x, rect->y, 4, rect->w / 4, rect->h, value );
+ CG_DrawField( rect->x, rect->y, 4, rect->w / 4, rect->h,
+ cg.snap->ps.stats[ STAT_HEALTH ] );
trap_R_SetColor( NULL );
}
-static void CG_DrawPlayerHealthBar( rectDef_t *rect, vec4_t color, float scale,
- int align, int textStyle, int special )
-{
- playerState_t *ps;
- float total;
-
- ps = &cg.snap->ps;
-
- total = ( (float)ps->stats[ STAT_HEALTH ] / (float)ps->stats[ STAT_MAX_HEALTH ] );
- CG_DrawProgressBar( rect, color, scale, align, textStyle, special, total );
-}
-
/*
==============
CG_DrawPlayerHealthCross
==============
*/
-static void CG_DrawPlayerHealthCross( rectDef_t *rect, vec4_t color, qhandle_t shader )
+static void CG_DrawPlayerHealthCross( rectDef_t *rect, vec4_t ref_color )
{
- playerState_t *ps = &cg.snap->ps;
- int health = ps->stats[ STAT_HEALTH ];
+ qhandle_t shader;
+ vec4_t color;
+ float ref_alpha;
+
+ // Pick the current icon
+ shader = cgs.media.healthCross;
+ if( cg.snap->ps.stats[ STAT_STATE ] & SS_HEALING_3X )
+ shader = cgs.media.healthCross3X;
+ else if( cg.snap->ps.stats[ STAT_STATE ] & SS_HEALING_2X )
+ {
+ if( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ shader = cgs.media.healthCross2X;
+ else
+ shader = cgs.media.healthCrossMedkit;
+ }
+ else if( cg.snap->ps.stats[ STAT_STATE ] & SS_POISONED )
+ shader = cgs.media.healthCrossPoisoned;
- if( health < 10 )
+ // Pick the alpha value
+ Vector4Copy( ref_color, color );
+ if( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_HUMANS &&
+ cg.snap->ps.stats[ STAT_HEALTH ] < 10 )
{
color[ 0 ] = 1.0f;
color[ 1 ] = color[ 2 ] = 0.0f;
}
+ ref_alpha = ref_color[ 3 ];
+ if( cg.snap->ps.stats[ STAT_STATE ] & SS_HEALING_ACTIVE )
+ ref_alpha = 1.0f;
+
+ // Don't fade from nothing
+ if( !cg.lastHealthCross )
+ cg.lastHealthCross = shader;
+
+ // Fade the icon during transition
+ if( cg.lastHealthCross != shader )
+ {
+ cg.healthCrossFade += cg.frametime / 500.0f;
+ if( cg.healthCrossFade > 1.0f )
+ {
+ cg.healthCrossFade = 0.0f;
+ cg.lastHealthCross = shader;
+ }
+ else
+ {
+ // Fading between two icons
+ color[ 3 ] = ref_alpha * cg.healthCrossFade;
+ trap_R_SetColor( color );
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
+ color[ 3 ] = ref_alpha * ( 1.0f - cg.healthCrossFade );
+ trap_R_SetColor( color );
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg.lastHealthCross );
+ trap_R_SetColor( NULL );
+ return;
+ }
+ }
+ // Not fading, draw a single icon
+ color[ 3 ] = ref_alpha;
trap_R_SetColor( color );
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
trap_R_SetColor( NULL );
}
-static void CG_DrawProgressLabel( rectDef_t *rect, float text_x, float text_y, vec4_t color,
- float scale, int align, const char *s, float fraction )
+static float CG_ChargeProgress( void )
{
- vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f };
- float tx, tw = CG_Text_Width( s, scale, 0 );
+ float progress;
+ int min = 0, max = 0;
- switch( align )
+ if( cg.snap->ps.weapon == WP_ALEVEL3 )
{
- case ITEM_ALIGN_LEFT:
- tx = 0.0f;
- break;
+ min = LEVEL3_POUNCE_TIME_MIN;
+ max = LEVEL3_POUNCE_TIME;
+ }
+ else if( cg.snap->ps.weapon == WP_ALEVEL3_UPG )
+ {
+ min = LEVEL3_POUNCE_TIME_MIN;
+ max = LEVEL3_POUNCE_TIME_UPG;
+ }
+ else if( cg.snap->ps.weapon == WP_ALEVEL4 )
+ {
+ if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_CHARGING )
+ {
+ min = 0;
+ max = LEVEL4_TRAMPLE_DURATION;
+ }
+ else
+ {
+ min = LEVEL4_TRAMPLE_CHARGE_MIN;
+ max = LEVEL4_TRAMPLE_CHARGE_MAX;
+ }
+ }
+ else if( cg.snap->ps.weapon == WP_LUCIFER_CANNON )
+ {
+ min = LCANNON_CHARGE_TIME_MIN;
+ max = LCANNON_CHARGE_TIME_MAX;
+ }
- case ITEM_ALIGN_RIGHT:
- tx = rect->w - tw;
- break;
+ if( max - min <= 0.0f )
+ return 0.0f;
- case ITEM_ALIGN_CENTER:
- tx = ( rect->w / 2.0f ) - ( tw / 2.0f );
- break;
+ progress = ( (float)cg.predictedPlayerState.stats[ STAT_MISC ] - min ) /
+ ( max - min );
- default:
- tx = 0.0f;
+ if( progress > 1.0f )
+ return 1.0f;
+
+ if( progress < 0.0f )
+ return 0.0f;
+
+ return progress;
+}
+
+#define CHARGE_BAR_FADE_RATE 0.002f
+
+static void CG_DrawPlayerChargeBarBG( rectDef_t *rect, vec4_t ref_color,
+ qhandle_t shader )
+{
+ vec4_t color;
+
+ if( !cg_drawChargeBar.integer || cg.chargeMeterAlpha <= 0.0f )
+ return;
+
+ color[ 0 ] = ref_color[ 0 ];
+ color[ 1 ] = ref_color[ 1 ];
+ color[ 2 ] = ref_color[ 2 ];
+ color[ 3 ] = ref_color[ 3 ] * cg.chargeMeterAlpha;
+
+ // Draw meter background
+ trap_R_SetColor( color );
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
+ trap_R_SetColor( NULL );
+}
+
+// FIXME: This should come from the element info
+#define CHARGE_BAR_CAP_SIZE 3
+
+static void CG_DrawPlayerChargeBar( rectDef_t *rect, vec4_t ref_color,
+ qhandle_t shader )
+{
+ vec4_t color;
+ float x, y, width, height, cap_size, progress;
+
+ if( !cg_drawChargeBar.integer )
+ return;
+
+ // Get progress proportion and pump fade
+ progress = CG_ChargeProgress();
+ if( progress <= 0.0f )
+ {
+ cg.chargeMeterAlpha -= CHARGE_BAR_FADE_RATE * cg.frametime;
+ if( cg.chargeMeterAlpha <= 0.0f )
+ {
+ cg.chargeMeterAlpha = 0.0f;
+ return;
+ }
+ }
+ else
+ {
+ cg.chargeMeterValue = progress;
+ cg.chargeMeterAlpha += CHARGE_BAR_FADE_RATE * cg.frametime;
+ if( cg.chargeMeterAlpha > 1.0f )
+ cg.chargeMeterAlpha = 1.0f;
+ }
+
+ color[ 0 ] = ref_color[ 0 ];
+ color[ 1 ] = ref_color[ 1 ];
+ color[ 2 ] = ref_color[ 2 ];
+ color[ 3 ] = ref_color[ 3 ] * cg.chargeMeterAlpha;
+
+ // Flash red for Lucifer Cannon warning
+ if( cg.snap->ps.weapon == WP_LUCIFER_CANNON &&
+ cg.snap->ps.stats[ STAT_MISC ] >= LCANNON_CHARGE_TIME_WARN &&
+ ( cg.time & 128 ) )
+ {
+ color[ 0 ] = 1.0f;
+ color[ 1 ] = 0.0f;
+ color[ 2 ] = 0.0f;
+ }
+
+ x = rect->x;
+ y = rect->y;
+
+ // Horizontal charge bar
+ if( rect->w >= rect->h )
+ {
+ width = ( rect->w - CHARGE_BAR_CAP_SIZE * 2 ) * cg.chargeMeterValue;
+ height = rect->h;
+ CG_AdjustFrom640( &x, &y, &width, &height );
+ cap_size = CHARGE_BAR_CAP_SIZE * cgs.screenXScale;
+
+ // Draw the meter
+ trap_R_SetColor( color );
+ trap_R_DrawStretchPic( x, y, cap_size, height, 0, 0, 1, 1, shader );
+ trap_R_DrawStretchPic( x + width + cap_size, y, cap_size, height,
+ 1, 0, 0, 1, shader );
+ trap_R_DrawStretchPic( x + cap_size, y, width, height, 1, 0, 1, 1, shader );
+ trap_R_SetColor( NULL );
}
+ // Vertical charge bar
+ else
+ {
+ y += rect->h;
+ width = rect->w;
+ height = ( rect->h - CHARGE_BAR_CAP_SIZE * 2 ) * cg.chargeMeterValue;
+ CG_AdjustFrom640( &x, &y, &width, &height );
+ cap_size = CHARGE_BAR_CAP_SIZE * cgs.screenYScale;
+
+ // Draw the meter
+ trap_R_SetColor( color );
+ trap_R_DrawStretchPic( x, y - cap_size, width, cap_size,
+ 0, 1, 1, 0, shader );
+ trap_R_DrawStretchPic( x, y - height - cap_size * 2, width,
+ cap_size, 0, 0, 1, 1, shader );
+ trap_R_DrawStretchPic( x, y - height - cap_size, width, height,
+ 0, 1, 1, 1, shader );
+ trap_R_SetColor( NULL );
+ }
+}
+
+static void CG_DrawProgressLabel( rectDef_t *rect, float text_x, float text_y, vec4_t color,
+ float scale, int textalign, int textvalign,
+ const char *s, float fraction )
+{
+ vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f };
+ float tx, ty;
+
+ CG_AlignText( rect, s, scale, 0.0f, 0.0f, textalign, textvalign, &tx, &ty );
+
if( fraction < 1.0f )
- CG_Text_Paint( rect->x + text_x + tx, rect->y + text_y, scale, white,
+ UI_Text_Paint( text_x + tx, text_y + ty, scale, white,
s, 0, 0, ITEM_TEXTSTYLE_NORMAL );
else
- CG_Text_Paint( rect->x + text_x + tx, rect->y + text_y, scale, color,
+ UI_Text_Paint( text_x + tx, text_y + ty, scale, color,
s, 0, 0, ITEM_TEXTSTYLE_NEON );
}
static void CG_DrawMediaProgress( rectDef_t *rect, vec4_t color, float scale,
- int align, int textStyle, int special )
+ int align, int textalign, int textStyle,
+ float borderSize )
{
- CG_DrawProgressBar( rect, color, scale, align, textStyle, special, cg.mediaFraction );
+ CG_DrawProgressBar( rect, color, scale, align, textalign, textStyle,
+ borderSize, cg.mediaFraction );
}
static void CG_DrawMediaProgressLabel( rectDef_t *rect, float text_x, float text_y,
- vec4_t color, float scale, int align )
+ vec4_t color, float scale, int textalign, int textvalign )
{
- CG_DrawProgressLabel( rect, text_x, text_y, color, scale, align, "Map and Textures", cg.mediaFraction );
+ CG_DrawProgressLabel( rect, text_x, text_y, color, scale, textalign, textvalign,
+ "Map and Textures", cg.mediaFraction );
}
-static void CG_DrawBuildablesProgress( rectDef_t *rect, vec4_t color, float scale,
- int align, int textStyle, int special )
+static void CG_DrawBuildablesProgress( rectDef_t *rect, vec4_t color,
+ float scale, int align, int textalign,
+ int textStyle, float borderSize )
{
- CG_DrawProgressBar( rect, color, scale, align, textStyle, special, cg.buildablesFraction );
+ CG_DrawProgressBar( rect, color, scale, align, textalign, textStyle,
+ borderSize, cg.buildablesFraction );
}
static void CG_DrawBuildablesProgressLabel( rectDef_t *rect, float text_x, float text_y,
- vec4_t color, float scale, int align )
+ vec4_t color, float scale, int textalign, int textvalign )
{
- CG_DrawProgressLabel( rect, text_x, text_y, color, scale, align, "Buildable Models", cg.buildablesFraction );
+ CG_DrawProgressLabel( rect, text_x, text_y, color, scale, textalign, textvalign,
+ "Buildable Models", cg.buildablesFraction );
}
-static void CG_DrawCharModelProgress( rectDef_t *rect, vec4_t color, float scale,
- int align, int textStyle, int special )
+static void CG_DrawCharModelProgress( rectDef_t *rect, vec4_t color,
+ float scale, int align, int textalign,
+ int textStyle, float borderSize )
{
- CG_DrawProgressBar( rect, color, scale, align, textStyle, special, cg.charModelFraction );
+ CG_DrawProgressBar( rect, color, scale, align, textalign, textStyle,
+ borderSize, cg.charModelFraction );
}
static void CG_DrawCharModelProgressLabel( rectDef_t *rect, float text_x, float text_y,
- vec4_t color, float scale, int align )
+ vec4_t color, float scale, int textalign, int textvalign )
{
- CG_DrawProgressLabel( rect, text_x, text_y, color, scale, align, "Character Models", cg.charModelFraction );
+ CG_DrawProgressLabel( rect, text_x, text_y, color, scale, textalign, textvalign,
+ "Character Models", cg.charModelFraction );
}
static void CG_DrawOverallProgress( rectDef_t *rect, vec4_t color, float scale,
- int align, int textStyle, int special )
+ int align, int textalign, int textStyle,
+ float borderSize )
{
float total;
- total = ( cg.charModelFraction + cg.buildablesFraction + cg.mediaFraction ) / 3.0f;
- CG_DrawProgressBar( rect, color, scale, align, textStyle, special, total );
+ total = cg.charModelFraction + cg.buildablesFraction + cg.mediaFraction;
+ total /= 3.0f;
+
+ CG_DrawProgressBar( rect, color, scale, align, textalign, textStyle,
+ borderSize, total );
}
static void CG_DrawLevelShot( rectDef_t *rect )
@@ -1258,97 +1167,44 @@ static void CG_DrawLevelShot( rectDef_t *rect )
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, detail );
}
-static void CG_DrawLoadingString( rectDef_t *rect, float text_x, float text_y, vec4_t color,
- float scale, int align, int textStyle, const char *s )
-{
- float tw, th, tx;
- int pos, i;
- char buffer[ 1024 ];
- char *end;
-
- if( !s[ 0 ] )
- return;
-
- strcpy( buffer, s );
- tw = CG_Text_Width( s, scale, 0 );
- th = scale * 40.0f;
-
- pos = i = 0;
-
- while( pos < strlen( s ) )
- {
- strcpy( buffer, &s[ pos ] );
- tw = CG_Text_Width( buffer, scale, 0 );
-
- while( tw > rect->w )
- {
- end = strrchr( buffer, ' ' );
-
- if( end == NULL )
- break;
-
- *end = '\0';
- tw = CG_Text_Width( buffer, scale, 0 );
- }
-
- switch( align )
- {
- case ITEM_ALIGN_LEFT:
- tx = rect->x;
- break;
-
- case ITEM_ALIGN_RIGHT:
- tx = rect->x + rect->w - tw;
- break;
-
- case ITEM_ALIGN_CENTER:
- tx = rect->x + ( rect->w / 2.0f ) - ( tw / 2.0f );
- break;
-
- default:
- tx = 0.0f;
- }
-
- CG_Text_Paint( tx + text_x, rect->y + text_y + i * ( th + 3 ), scale, color,
- buffer, 0, 0, textStyle );
-
- pos += strlen( buffer ) + 1;
- i++;
- }
-}
-
static void CG_DrawLevelName( rectDef_t *rect, float text_x, float text_y,
- vec4_t color, float scale, int align, int textStyle )
+ vec4_t color, float scale,
+ int textalign, int textvalign, int textStyle )
{
const char *s;
s = CG_ConfigString( CS_MESSAGE );
- CG_DrawLoadingString( rect, text_x, text_y, color, scale, align, textStyle, s );
+ UI_DrawTextBlock( rect, text_x, text_y, color, scale, textalign, textvalign, textStyle, s );
}
static void CG_DrawMOTD( rectDef_t *rect, float text_x, float text_y,
- vec4_t color, float scale, int align, int textStyle )
+ vec4_t color, float scale,
+ int textalign, int textvalign, int textStyle )
{
const char *s;
+ char parsed[ MAX_STRING_CHARS ];
s = CG_ConfigString( CS_MOTD );
- CG_DrawLoadingString( rect, text_x, text_y, color, scale, align, textStyle, s );
+ Q_ParseNewlines( parsed, s, sizeof( parsed ) );
+
+ UI_DrawTextBlock( rect, text_x, text_y, color, scale, textalign, textvalign, textStyle, parsed );
}
static void CG_DrawHostname( rectDef_t *rect, float text_x, float text_y,
- vec4_t color, float scale, int align, int textStyle )
+ vec4_t color, float scale,
+ int textalign, int textvalign, int textStyle )
{
char buffer[ 1024 ];
const char *info;
info = CG_ConfigString( CS_SERVERINFO );
- Q_strncpyz( buffer, Info_ValueForKey( info, "sv_hostname" ), 1024 );
+ UI_EscapeEmoticons( buffer, Info_ValueForKey( info, "sv_hostname" ), sizeof( buffer ) );
Q_CleanStr( buffer );
- CG_DrawLoadingString( rect, text_x, text_y, color, scale, align, textStyle, buffer );
+ UI_DrawTextBlock( rect, text_x, text_y, color, scale, textalign, textvalign, textStyle, buffer );
}
/*
@@ -1409,30 +1265,29 @@ Draw all the status / pacifier stuff during level loading
*/
void CG_DrawLoadingScreen( void )
{
- Menu_Paint( Menus_FindByName( "Loading" ), qtrue );
+ menuDef_t *menu = Menus_FindByName( "Loading" );
+
+ Menu_Update( menu );
+ Menu_Paint( menu, qtrue );
}
float CG_GetValue( int ownerDraw )
{
- centity_t *cent;
playerState_t *ps;
+ weapon_t weapon;
- cent = &cg_entities[ cg.snap->ps.clientNum ];
ps = &cg.snap->ps;
+ weapon = BG_GetPlayerWeapon( ps );
switch( ownerDraw )
{
case CG_PLAYER_AMMO_VALUE:
- if( cent->currentState.weapon )
- {
+ if( weapon )
return ps->ammo;
- }
break;
case CG_PLAYER_CLIPS_VALUE:
- if( cent->currentState.weapon )
- {
+ if( weapon )
return ps->clips;
- }
break;
case CG_PLAYER_HEALTH:
return ps->stats[ STAT_HEALTH ];
@@ -1461,165 +1316,131 @@ static void CG_DrawKiller( rectDef_t *rect, float scale, vec4_t color,
if( cg.killerName[ 0 ] )
{
int x = rect->x + rect->w / 2;
- CG_Text_Paint( x - CG_Text_Width( CG_GetKillerText( ), scale, 0 ) / 2,
+ UI_Text_Paint( x - UI_Text_Width( CG_GetKillerText( ), scale ) / 2,
rect->y + rect->h, scale, color, CG_GetKillerText( ), 0, 0, textStyle );
}
}
-static void CG_Text_Paint_Limit( float *maxX, float x, float y, float scale,
- vec4_t color, const char* text, float adjust, int limit )
-{
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
+#define SPECTATORS_PIXELS_PER_SECOND 30.0f
- if( text )
- {
-// TTimo: FIXME
-// const unsigned char *s = text; // bk001206 - unsigned
- const char *s = text;
- float max = *maxX;
- float useScale;
- fontInfo_t *font = &cgDC.Assets.textFont;
+/*
+==================
+CG_DrawTeamSpectators
+==================
+*/
+static void CG_DrawTeamSpectators( rectDef_t *rect, float scale, int textvalign, vec4_t color, qhandle_t shader )
+{
+ float y;
+ char *text = cg.spectatorList;
+ float textWidth = UI_Text_Width( text, scale );
- if( scale <= cg_smallFont.value )
- font = &cgDC.Assets.smallFont;
- else if( scale > cg_bigFont.value )
- font = &cgDC.Assets.bigFont;
+ CG_AlignText( rect, text, scale, 0.0f, 0.0f, ALIGN_LEFT, textvalign, NULL, &y );
- useScale = scale * font->glyphScale;
- trap_R_SetColor( color );
- len = strlen( text );
+ if( textWidth > rect->w )
+ {
+ // The text is too wide to fit, so scroll it
+ int now = trap_Milliseconds( );
+ int delta = now - cg.spectatorTime;
- if( limit > 0 && len > limit )
- len = limit;
+ CG_SetClipRegion( rect->x, rect->y, rect->w, rect->h );
- count = 0;
+ UI_Text_Paint( rect->x - cg.spectatorOffset, y, scale, color, text, 0, 0, 0 );
+ UI_Text_Paint( rect->x + textWidth - cg.spectatorOffset, y, scale, color, text, 0, 0, 0 );
- while( s && *s && count < len )
- {
- glyph = &font->glyphs[ (int)*s ];
- //TTimo: FIXME: getting nasty warnings without the cast,
- //hopefully this doesn't break the VM build
+ CG_ClearClipRegion( );
- if( Q_IsColorString( s ) )
- {
- memcpy( newColor, g_color_table[ ColorIndex( *(s+1) ) ], sizeof( newColor ) );
- newColor[ 3 ] = color[ 3 ];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- }
- else
- {
- float yadj = useScale * glyph->top;
+ cg.spectatorOffset += ( delta / 1000.0f ) * SPECTATORS_PIXELS_PER_SECOND;
- if( CG_Text_Width( s, useScale, 1 ) + x > max )
- {
- *maxX = 0;
- break;
- }
+ while( cg.spectatorOffset > textWidth )
+ cg.spectatorOffset -= textWidth;
- CG_Text_PaintChar( x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
- x += ( glyph->xSkip * useScale ) + adjust;
- *maxX = x;
- count++;
- s++;
- }
- }
-
- trap_R_SetColor( NULL );
+ cg.spectatorTime = now;
+ }
+ else
+ {
+ UI_Text_Paint( rect->x, y, scale, color, text, 0, 0, 0 );
}
}
-static void CG_DrawTeamSpectators( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader )
+#define FOLLOWING_STRING "following "
+#define CHASING_STRING "chasing "
+
+/*
+==================
+CG_DrawFollow
+==================
+*/
+static void CG_DrawFollow( rectDef_t *rect, float text_x, float text_y,
+ vec4_t color, float scale, int textalign, int textvalign, int textStyle )
{
- if( cg.spectatorLen )
- {
- float maxX;
+ float tx, ty;
- if( cg.spectatorWidth == -1 )
- {
- cg.spectatorWidth = 0;
- cg.spectatorPaintX = rect->x + 1;
- cg.spectatorPaintX2 = -1;
- }
+ if( cg.snap && cg.snap->ps.pm_flags & PMF_FOLLOW )
+ {
+ char buffer[ MAX_STRING_CHARS ];
- if( cg.spectatorOffset > cg.spectatorLen )
- {
- cg.spectatorOffset = 0;
- cg.spectatorPaintX = rect->x + 1;
- cg.spectatorPaintX2 = -1;
- }
+ if( !cg.chaseFollow )
+ strcpy( buffer, FOLLOWING_STRING );
+ else
+ strcpy( buffer, CHASING_STRING );
- if( cg.time > cg.spectatorTime )
- {
- cg.spectatorTime = cg.time + 10;
+ strcat( buffer, cgs.clientinfo[ cg.snap->ps.clientNum ].name );
- if( cg.spectatorPaintX <= rect->x + 2 )
- {
- if( cg.spectatorOffset < cg.spectatorLen )
- {
- //TA: skip colour directives
- if( Q_IsColorString( &cg.spectatorList[ cg.spectatorOffset ] ) )
- cg.spectatorOffset += 2;
- else
- {
- cg.spectatorPaintX += CG_Text_Width( &cg.spectatorList[ cg.spectatorOffset ], scale, 1 ) - 1;
- cg.spectatorOffset++;
- }
- }
- else
- {
- cg.spectatorOffset = 0;
+ CG_AlignText( rect, buffer, scale, 0, 0, textalign, textvalign, &tx, &ty );
+ UI_Text_Paint( text_x + tx, text_y + ty, scale, color, buffer, 0, 0,
+ textStyle );
+ }
+}
- if( cg.spectatorPaintX2 >= 0 )
- cg.spectatorPaintX = cg.spectatorPaintX2;
- else
- cg.spectatorPaintX = rect->x + rect->w - 2;
+/*
+==================
+CG_DrawTeamLabel
+==================
+*/
+static void CG_DrawTeamLabel( rectDef_t *rect, team_t team, float text_x, float text_y,
+ vec4_t color, float scale, int textalign, int textvalign, int textStyle )
+{
+ char *t;
+ char stage[ MAX_TOKEN_CHARS ];
+ const char *s;
+ float tx, ty;
- cg.spectatorPaintX2 = -1;
- }
- }
- else
- {
- cg.spectatorPaintX--;
+ stage[ 0 ] = '\0';
- if( cg.spectatorPaintX2 >= 0 )
- cg.spectatorPaintX2--;
- }
- }
+ switch( team )
+ {
+ case TEAM_ALIENS:
+ t = "Aliens";
+ if( cg.intermissionStarted )
+ Com_sprintf( stage, MAX_TOKEN_CHARS, "(Stage %d)", cgs.alienStage + 1 );
+ break;
- maxX = rect->x + rect->w - 2;
+ case TEAM_HUMANS:
+ t = "Humans";
+ if( cg.intermissionStarted )
+ Com_sprintf( stage, MAX_TOKEN_CHARS, "(Stage %d)", cgs.humanStage + 1 );
+ break;
- CG_Text_Paint_Limit( &maxX, cg.spectatorPaintX, rect->y + rect->h - 3, scale, color,
- &cg.spectatorList[ cg.spectatorOffset ], 0, 0 );
+ default:
+ t = "";
+ break;
+ }
- if( cg.spectatorPaintX2 >= 0 )
- {
- float maxX2 = rect->x + rect->w - 2;
- CG_Text_Paint_Limit( &maxX2, cg.spectatorPaintX2, rect->y + rect->h - 3, scale,
- color, cg.spectatorList, 0, cg.spectatorOffset );
- }
+ switch( textalign )
+ {
+ default:
+ case ALIGN_LEFT:
+ s = va( "%s %s", t, stage );
+ break;
- if( cg.spectatorOffset && maxX > 0 )
- {
- // if we have an offset ( we are skipping the first part of the string ) and we fit the string
- if( cg.spectatorPaintX2 == -1 )
- cg.spectatorPaintX2 = rect->x + rect->w - 2;
- }
- else
- cg.spectatorPaintX2 = -1;
+ case ALIGN_RIGHT:
+ s = va( "%s %s", stage, t );
+ break;
}
+
+ CG_AlignText( rect, s, scale, 0.0f, 0.0f, textalign, textvalign, &tx, &ty );
+ UI_Text_Paint( text_x + tx, text_y + ty, scale, color, s, 0, 0, textStyle );
}
/*
@@ -1628,70 +1449,52 @@ CG_DrawStageReport
==================
*/
static void CG_DrawStageReport( rectDef_t *rect, float text_x, float text_y,
- vec4_t color, float scale, int align, int textStyle )
+ vec4_t color, float scale, int textalign, int textvalign, int textStyle )
{
char s[ MAX_TOKEN_CHARS ];
- int tx, w, kills;
+ float tx, ty;
- if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_NONE && !cg.intermissionStarted )
+ if( cg.intermissionStarted )
return;
- if( cg.intermissionStarted )
- {
- Com_sprintf( s, MAX_TOKEN_CHARS,
- "Stage %d" //PH34R MY MAD-LEET CODING SKILLZ
- " "
- "Stage %d",
- cgs.alienStage + 1, cgs.humanStage + 1 );
- }
- else if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_NONE )
+ return;
+
+ if( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
- kills = cgs.alienNextStageThreshold - cgs.alienKills;
+ int kills = ceil( (float)(cgs.alienNextStageThreshold - cgs.alienCredits) / ALIEN_CREDITS_PER_KILL );
+ if( kills < 0 )
+ kills = 0;
if( cgs.alienNextStageThreshold < 0 )
Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d", cgs.alienStage + 1 );
else if( kills == 1 )
- Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, %d kill for next stage",
- cgs.alienStage + 1, kills );
+ Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, 1 frag for next stage",
+ cgs.alienStage + 1 );
else
- Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, %d kills for next stage",
+ Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, %d frags for next stage",
cgs.alienStage + 1, kills );
}
- else if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ else if( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
- kills = cgs.humanNextStageThreshold - cgs.humanKills;
+ int credits = cgs.humanNextStageThreshold - cgs.humanCredits;
+
+ if( credits < 0 )
+ credits = 0;
if( cgs.humanNextStageThreshold < 0 )
Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d", cgs.humanStage + 1 );
- else if( kills == 1 )
- Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, %d kill for next stage",
- cgs.humanStage + 1, kills );
+ else if( credits == 1 )
+ Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, 1 credit for next stage",
+ cgs.humanStage + 1 );
else
- Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, %d kills for next stage",
- cgs.humanStage + 1, kills );
+ Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, %d credits for next stage",
+ cgs.humanStage + 1, credits );
}
- w = CG_Text_Width( s, scale, 0 );
-
- switch( align )
- {
- case ITEM_ALIGN_LEFT:
- tx = rect->x;
- break;
-
- case ITEM_ALIGN_RIGHT:
- tx = rect->x + rect->w - w;
- break;
-
- case ITEM_ALIGN_CENTER:
- tx = rect->x + ( rect->w / 2.0f ) - ( w / 2.0f );
- break;
-
- default:
- tx = 0.0f;
- }
+ CG_AlignText( rect, s, scale, 0.0f, 0.0f, textalign, textvalign, &tx, &ty );
- CG_Text_Paint( text_x + tx, rect->y + text_y, scale, color, s, 0, 0, textStyle );
+ UI_Text_Paint( text_x + tx, text_y + ty, scale, color, s, 0, 0, textStyle );
}
/*
@@ -1699,15 +1502,17 @@ static void CG_DrawStageReport( rectDef_t *rect, float text_x, float text_y,
CG_DrawFPS
==================
*/
-//TA: personally i think this should be longer - it should really be a cvar
#define FPS_FRAMES 20
#define FPS_STRING "fps"
static void CG_DrawFPS( rectDef_t *rect, float text_x, float text_y,
- float scale, vec4_t color, int align, int textStyle,
+ float scale, vec4_t color,
+ int textalign, int textvalign, int textStyle,
qboolean scalableText )
{
- char *s;
- int tx, w, totalWidth, strLength;
+ const char *s;
+ float tx, ty;
+ float w, h, totalWidth;
+ int strLength;
static int previousTimes[ FPS_FRAMES ];
static int index;
int i, total;
@@ -1741,27 +1546,12 @@ static void CG_DrawFPS( rectDef_t *rect, float text_x, float text_y,
fps = 1000 * FPS_FRAMES / total;
s = va( "%d", fps );
- w = CG_Text_Width( "0", scale, 0 );
+ w = UI_Text_Width( "0", scale );
+ h = UI_Text_Height( "0", scale );
strLength = CG_DrawStrlen( s );
- totalWidth = CG_Text_Width( FPS_STRING, scale, 0 ) + w * strLength;
+ totalWidth = UI_Text_Width( FPS_STRING, scale ) + w * strLength;
- switch( align )
- {
- case ITEM_ALIGN_LEFT:
- tx = rect->x;
- break;
-
- case ITEM_ALIGN_RIGHT:
- tx = rect->x + rect->w - totalWidth;
- break;
-
- case ITEM_ALIGN_CENTER:
- tx = rect->x + ( rect->w / 2.0f ) - ( totalWidth / 2.0f );
- break;
-
- default:
- tx = 0.0f;
- }
+ CG_AlignText( rect, s, 0.0f, totalWidth, h, textalign, textvalign, &tx, &ty );
if( scalableText )
{
@@ -1772,8 +1562,10 @@ static void CG_DrawFPS( rectDef_t *rect, float text_x, float text_y,
c[ 0 ] = s[ i ];
c[ 1 ] = '\0';
- CG_Text_Paint( text_x + tx + i * w, rect->y + text_y, scale, color, c, 0, 0, textStyle );
+ UI_Text_Paint( text_x + tx + i * w, text_y + ty, scale, color, c, 0, 0, textStyle );
}
+
+ UI_Text_Paint( text_x + tx + i * w, text_y + ty, scale, color, FPS_STRING, 0, 0, textStyle );
}
else
{
@@ -1781,9 +1573,6 @@ static void CG_DrawFPS( rectDef_t *rect, float text_x, float text_y,
CG_DrawField( rect->x, rect->y, 3, rect->w / 3, rect->h, fps );
trap_R_SetColor( NULL );
}
-
- if( scalableText )
- CG_Text_Paint( text_x + tx + i * w, rect->y + text_y, scale, color, FPS_STRING, 0, 0, textStyle );
}
}
@@ -1844,10 +1633,13 @@ CG_DrawTimer
=================
*/
static void CG_DrawTimer( rectDef_t *rect, float text_x, float text_y,
- float scale, vec4_t color, int align, int textStyle )
+ float scale, vec4_t color,
+ int textalign, int textvalign, int textStyle )
{
- char *s;
- int i, tx, w, totalWidth, strLength;
+ const char *s;
+ float tx, ty;
+ int i, strLength;
+ float w, h, totalWidth;
int mins, seconds, tens;
int msec;
@@ -1863,36 +1655,255 @@ static void CG_DrawTimer( rectDef_t *rect, float text_x, float text_y,
seconds -= tens * 10;
s = va( "%d:%d%d", mins, tens, seconds );
- w = CG_Text_Width( "0", scale, 0 );
+ w = UI_Text_Width( "0", scale );
+ h = UI_Text_Height( "0", scale );
strLength = CG_DrawStrlen( s );
totalWidth = w * strLength;
- switch( align )
+ CG_AlignText( rect, s, 0.0f, totalWidth, h, textalign, textvalign, &tx, &ty );
+
+ for( i = 0; i < strLength; i++ )
{
- case ITEM_ALIGN_LEFT:
- tx = rect->x;
- break;
+ char c[ 2 ];
- case ITEM_ALIGN_RIGHT:
- tx = rect->x + rect->w - totalWidth;
- break;
+ c[ 0 ] = s[ i ];
+ c[ 1 ] = '\0';
- case ITEM_ALIGN_CENTER:
- tx = rect->x + ( rect->w / 2.0f ) - ( totalWidth / 2.0f );
- break;
+ UI_Text_Paint( text_x + tx + i * w, text_y + ty, scale, color, c, 0, 0, textStyle );
+ }
+}
- default:
- tx = 0.0f;
+/*
+=================
+CG_DrawTeamOverlay
+=================
+*/
+
+typedef enum
+{
+ TEAMOVERLAY_OFF,
+ TEAMOVERLAY_ALL,
+ TEAMOVERLAY_SUPPORT,
+ TEAMOVERLAY_NEARBY,
+} teamOverlayMode_t;
+
+typedef enum
+{
+ TEAMOVERLAY_SORT_NONE,
+ TEAMOVERLAY_SORT_SCORE,
+ TEAMOVERLAY_SORT_WEAPONCLASS,
+} teamOverlaySort_t;
+
+static int QDECL SortScore( const void *a, const void *b )
+{
+ int na = *(int *)a;
+ int nb = *(int *)b;
+
+ return( cgs.clientinfo[ nb ].score - cgs.clientinfo[ na ].score );
+}
+
+static int QDECL SortWeaponClass( const void *a, const void *b )
+{
+ int out;
+ clientInfo_t *ca = cgs.clientinfo + *(int *)a;
+ clientInfo_t *cb = cgs.clientinfo + *(int *)b;
+
+ out = cb->curWeaponClass - ca->curWeaponClass;
+
+ // We want grangers on top. ckits are already on top without the special case.
+ if( ca->team == TEAM_ALIENS )
+ {
+ if( ca->curWeaponClass == PCL_ALIEN_BUILDER0_UPG ||
+ cb->curWeaponClass == PCL_ALIEN_BUILDER0_UPG ||
+ ca->curWeaponClass == PCL_ALIEN_BUILDER0 ||
+ cb->curWeaponClass == PCL_ALIEN_BUILDER0 )
+ {
+ out = -out;
+ }
}
- for( i = 0; i < strLength; i++ )
+ return( out );
+}
+
+static void CG_DrawTeamOverlay( rectDef_t *rect, float scale, vec4_t color )
+{
+ const char *s;
+ int i;
+ float x = rect->x;
+ float y;
+ clientInfo_t *ci, *pci;
+ vec4_t tcolor;
+ float iconSize = rect->h / 8.0f;
+ float leftMargin = 4.0f;
+ float iconTopMargin = 2.0f;
+ float midSep = 2.0f;
+ float backgroundWidth = rect->w;
+ float fontScale = 0.30f;
+ float vPad = 0.0f;
+ float nameWidth = 0.5f * rect->w;
+ char name[ MAX_NAME_LENGTH + 2 ];
+ int maxDisplayCount = 0;
+ int displayCount = 0;
+ float nameMaxX, nameMaxXCp;
+ float maxX = rect->x + rect->w;
+ float maxXCp = maxX;
+ weapon_t curWeapon = WP_NONE;
+ teamOverlayMode_t mode = cg_drawTeamOverlay.integer;
+ teamOverlaySort_t sort = cg_teamOverlaySortMode.integer;
+ int displayClients[ MAX_CLIENTS ];
+
+ if( cg.predictedPlayerState.pm_type == PM_SPECTATOR )
+ return;
+
+ if( mode == TEAMOVERLAY_OFF || !cg_teamOverlayMaxPlayers.integer )
+ return;
+
+ if( !cgs.teaminfoReceievedTime )
+ return;
+
+ if( cg.showScores ||
+ cg.predictedPlayerState.pm_type == PM_INTERMISSION )
+ return;
+
+ pci = cgs.clientinfo + cg.snap->ps.clientNum;
+
+ if( mode == TEAMOVERLAY_ALL || mode == TEAMOVERLAY_SUPPORT )
{
- char c[ 2 ];
+ for( i = 0; i < MAX_CLIENTS; i++ )
+ {
+ ci = cgs.clientinfo + i;
+ if( ci->infoValid && pci != ci && ci->team == pci->team )
+ {
+ if( mode == TEAMOVERLAY_ALL )
+ displayClients[ maxDisplayCount++ ] = i;
+ else
+ {
+ if( ci->curWeaponClass == PCL_ALIEN_BUILDER0 ||
+ ci->curWeaponClass == PCL_ALIEN_BUILDER0_UPG ||
+ ci->curWeaponClass == PCL_ALIEN_LEVEL1 ||
+ ci->curWeaponClass == PCL_ALIEN_LEVEL1_UPG ||
+ ci->curWeaponClass == WP_HBUILD )
+ {
+ displayClients[ maxDisplayCount++ ] = i;
+ }
+ }
+ }
+ }
+ }
+ else // find nearby
+ {
+ for( i = 0; i < cg.snap->numEntities; i++ )
+ {
+ centity_t *cent = &cg_entities[ cg.snap->entities[ i ].number ];
+ vec3_t relOrigin = { 0.0f, 0.0f, 0.0f };
+ int team = cent->currentState.misc & 0x00FF;
- c[ 0 ] = s[ i ];
- c[ 1 ] = '\0';
+ if( cent->currentState.eType != ET_PLAYER ||
+ team != pci->team ||
+ cent->currentState.eFlags & EF_DEAD )
+ {
+ continue;
+ }
+
+ VectorSubtract( cent->lerpOrigin, cg.predictedPlayerState.origin, relOrigin );
+
+ if( VectorLength( relOrigin ) < HELMET_RANGE )
+ displayClients[ maxDisplayCount++ ] = cg.snap->entities[ i ].number;
+ }
+ }
- CG_Text_Paint( text_x + tx + i * w, rect->y + text_y, scale, color, c, 0, 0, textStyle );
+ // Sort
+ if( sort == TEAMOVERLAY_SORT_SCORE )
+ {
+ qsort( displayClients, maxDisplayCount,
+ sizeof( displayClients[ 0 ] ), SortScore );
+ }
+ else if( sort == TEAMOVERLAY_SORT_WEAPONCLASS )
+ {
+ qsort( displayClients, maxDisplayCount,
+ sizeof( displayClients[ 0 ] ), SortWeaponClass );
+ }
+
+ if( maxDisplayCount > cg_teamOverlayMaxPlayers.integer )
+ maxDisplayCount = cg_teamOverlayMaxPlayers.integer;
+
+ iconSize *= scale;
+ leftMargin *= scale;
+ iconTopMargin *= scale;
+ midSep *= scale;
+ backgroundWidth *= scale;
+ fontScale *= scale;
+ nameWidth *= scale;
+
+ vPad = ( rect->h - ( (float) maxDisplayCount * iconSize ) ) / 2.0f;
+ y = rect->y + vPad;
+
+ tcolor[ 0 ] = 1.0f;
+ tcolor[ 1 ] = 1.0f;
+ tcolor[ 2 ] = 1.0f;
+ tcolor[ 3 ] = color[ 3 ];
+
+ for( i = 0; i < MAX_CLIENTS && displayCount < maxDisplayCount; i++ )
+ {
+ ci = cgs.clientinfo + displayClients[ i ];
+
+ if( !ci->infoValid || pci == ci || ci->team != pci->team )
+ continue;
+
+ Com_sprintf( name, sizeof( name ), "%s^7", ci->name );
+
+ trap_R_SetColor( color );
+ CG_DrawPic( x, y, backgroundWidth,
+ iconSize, cgs.media.teamOverlayShader );
+ trap_R_SetColor( tcolor );
+ if( ci->health <= 0 || !ci->curWeaponClass )
+ s = "";
+ else
+ {
+ if( ci->team == TEAM_HUMANS )
+ curWeapon = ci->curWeaponClass;
+ else if( ci->team == TEAM_ALIENS )
+ curWeapon = BG_Class( ci->curWeaponClass )->startWeapon;
+
+ CG_DrawPic( x + leftMargin, y, iconSize, iconSize,
+ cg_weapons[ curWeapon ].weaponIcon );
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ {
+ if( ci->upgrade != UP_NONE )
+ {
+ CG_DrawPic( x + iconSize + leftMargin, y, iconSize,
+ iconSize, cg_upgrades[ ci->upgrade ].upgradeIcon );
+ }
+ }
+ else
+ {
+ if( curWeapon == WP_ABUILD2 || curWeapon == WP_ALEVEL1_UPG ||
+ curWeapon == WP_ALEVEL2_UPG || curWeapon == WP_ALEVEL3_UPG )
+ {
+ CG_DrawPic( x + iconSize + leftMargin, y, iconSize,
+ iconSize, cgs.media.upgradeClassIconShader );
+ }
+ }
+
+ s = va( " [^%c%3d^7] ^7%s",
+ CG_GetColorCharForHealth( displayClients[ i ] ),
+ ci->health,
+ CG_ConfigString( CS_LOCATIONS + ci->location ) );
+ }
+
+ trap_R_SetColor( NULL );
+ nameMaxX = nameMaxXCp = x + 2.0f * iconSize +
+ leftMargin + midSep + nameWidth;
+ UI_Text_Paint_Limit( &nameMaxXCp, x + 2.0f * iconSize + leftMargin + midSep,
+ y + iconSize - iconTopMargin, fontScale, tcolor, name,
+ 0, 0 );
+
+ maxXCp = maxX;
+
+ UI_Text_Paint_Limit( &maxXCp, nameMaxX, y + iconSize - iconTopMargin,
+ fontScale, tcolor, s, 0, 0 );
+ y += iconSize;
+ displayCount++;
}
}
@@ -1902,17 +1913,19 @@ CG_DrawClock
=================
*/
static void CG_DrawClock( rectDef_t *rect, float text_x, float text_y,
- float scale, vec4_t color, int align, int textStyle )
+ float scale, vec4_t color,
+ int textalign, int textvalign, int textStyle )
{
- char *s;
- int i, tx, w, totalWidth, strLength;
+ const char *s;
+ float tx, ty;
+ int i, strLength;
+ float w, h, totalWidth;
qtime_t qt;
- int t;
if( !cg_drawClock.integer )
return;
- t = trap_RealTime( &qt );
+ trap_RealTime( &qt );
if( cg_drawClock.integer == 2 )
{
@@ -1936,27 +1949,12 @@ static void CG_DrawClock( rectDef_t *rect, float text_x, float text_y,
s = va( "%d%s%02d%s", h, ( qt.tm_sec % 2 ) ? ":" : " ", qt.tm_min, pm );
}
- w = CG_Text_Width( "0", scale, 0 );
+ w = UI_Text_Width( "0", scale );
+ h = UI_Text_Height( "0", scale );
strLength = CG_DrawStrlen( s );
totalWidth = w * strLength;
- switch( align )
- {
- case ITEM_ALIGN_LEFT:
- tx = rect->x;
- break;
-
- case ITEM_ALIGN_RIGHT:
- tx = rect->x + rect->w - totalWidth;
- break;
-
- case ITEM_ALIGN_CENTER:
- tx = rect->x + ( rect->w / 2.0f ) - ( totalWidth / 2.0f );
- break;
-
- default:
- tx = 0.0f;
- }
+ CG_AlignText( rect, s, 0.0f, totalWidth, h, textalign, textvalign, &tx, &ty );
for( i = 0; i < strLength; i++ )
{
@@ -1965,7 +1963,7 @@ static void CG_DrawClock( rectDef_t *rect, float text_x, float text_y,
c[ 0 ] = s[ i ];
c[ 1 ] = '\0';
- CG_Text_Paint( text_x + tx + i * w, rect->y + text_y, scale, color, c, 0, 0, textStyle );
+ UI_Text_Paint( text_x + tx + i * w, text_y + ty, scale, color, c, 0, 0, textStyle );
}
}
@@ -1975,39 +1973,90 @@ CG_DrawSnapshot
==================
*/
static void CG_DrawSnapshot( rectDef_t *rect, float text_x, float text_y,
- float scale, vec4_t color, int align, int textStyle )
+ float scale, vec4_t color,
+ int textalign, int textvalign, int textStyle )
{
- char *s;
- int w, tx;
+ const char *s;
+ float tx, ty;
if( !cg_drawSnapshot.integer )
return;
s = va( "time:%d snap:%d cmd:%d", cg.snap->serverTime,
cg.latestSnapshotNum, cgs.serverCommandSequence );
- w = CG_Text_Width( s, scale, 0 );
- switch( align )
- {
- case ITEM_ALIGN_LEFT:
- tx = rect->x;
- break;
+ CG_AlignText( rect, s, scale, 0.0f, 0.0f, textalign, textvalign, &tx, &ty );
- case ITEM_ALIGN_RIGHT:
- tx = rect->x + rect->w - w;
- break;
+ UI_Text_Paint( text_x + tx, text_y + ty, scale, color, s, 0, 0, textStyle );
+}
- case ITEM_ALIGN_CENTER:
- tx = rect->x + ( rect->w / 2.0f ) - ( w / 2.0f );
- break;
+/*
+===============================================================================
- default:
- tx = 0.0f;
- }
+KILLL MESSAGE
- CG_Text_Paint( text_x + tx, rect->y + text_y, scale, color, s, 0, 0, textStyle );
+===============================================================================
+*/
+
+/*
+==================
+CG_DrawKillMsg
+==================
+*/
+static void CG_DrawKillMsg( rectDef_t *rect, float text_x, float text_y,
+ float scale, vec4_t color,
+ int textalign, int textvalign, int textStyle )
+{
+ int i;
+ vec4_t hcolor;
+ int chatHeight;
+
+ if (cg_killMsgHeight.integer < TEAMCHAT_HEIGHT)
+ chatHeight = cg_killMsgHeight.integer;
+ else
+ chatHeight = TEAMCHAT_HEIGHT;
+
+ if (chatHeight <= 0)
+ return; // disabled
+
+ if (cgs.killMsgLastPos != cgs.killMsgPos)
+ {
+ if (cg.time - cgs.killMsgMsgTimes[cgs.killMsgLastPos % chatHeight] > cg_killMsgTime.integer)
+ cgs.killMsgLastPos++;
+
+ hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0f;
+
+ for ( i = cgs.killMsgPos - 1; i >= cgs.killMsgLastPos; i-- )
+ {
+ int x = 0, w;
+ int j = i % chatHeight;
+
+ w = UI_Text_Width( cgs.killMsgKillers[j], scale );
+ UI_Text_Paint( rect->x + TINYCHAR_WIDTH,
+ rect->y - (cgs.killMsgPos - i)*20,
+ scale, color, cgs.killMsgKillers[j],
+ 0, 0, textStyle );
+ x += w + 3;
+
+ if ( cg_weapons[cgs.killMsgWeapons[j]].weaponIcon != WP_NONE )
+ {
+ CG_DrawPic( rect->x + TINYCHAR_WIDTH + x,
+ rect->y - (cgs.killMsgPos - i)*20-15,
+ 16, 16,
+ cg_weapons[cgs.killMsgWeapons[j]].weaponIcon );
+ x += 16 + 2;
+
+ w = UI_Text_Width( cgs.killMsgVictims[j], scale );
+ UI_Text_Paint( rect->x + TINYCHAR_WIDTH + x,
+ rect->y - (cgs.killMsgPos - i)*20,
+ scale, color, cgs.killMsgVictims[j],
+ 0, 0, textStyle );
+ }
+ }
+ }
}
+
/*
===============================================================================
@@ -2080,7 +2129,7 @@ void CG_AddLagometerSnapshotInfo( snapshot_t *snap )
{
previousPings[ index++ ] = cg.snap->ping;
index = index % PING_FRAMES;
-
+
for( i = 0; i < PING_FRAMES; i++ )
{
cg.ping += previousPings[ i ];
@@ -2116,8 +2165,8 @@ static void CG_DrawDisconnect( void )
// also add text in center of screen
s = "Connection Interrupted";
- w = CG_Text_Width( s, 0.7f, 0 );
- CG_Text_Paint( 320 - w / 2, 100, 0.7f, color, s, 0, 0, ITEM_TEXTSTYLE_SHADOWED );
+ w = UI_Text_Width( s, 0.7f );
+ UI_Text_Paint( 320 - w / 2, 100, 0.7f, color, s, 0, 0, ITEM_TEXTSTYLE_SHADOWED );
// blink the icon
if( ( cg.time >> 9 ) & 1 )
@@ -2147,7 +2196,7 @@ static void CG_DrawLagometer( rectDef_t *rect, float text_x, float text_y,
int color;
vec4_t adjustedColor;
float vscale;
- vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f };
+ const char *ping;
if( cg.snap->ps.pm_type == PM_INTERMISSION )
return;
@@ -2270,81 +2319,194 @@ static void CG_DrawLagometer( rectDef_t *rect, float text_x, float text_y,
trap_R_SetColor( NULL );
if( cg_nopredict.integer || cg_synchronousClients.integer )
- CG_Text_Paint( ax, ay, 0.5, white, "snc", 0, 0, ITEM_TEXTSTYLE_NORMAL );
+ ping = "snc";
else
- {
- char *s;
-
- s = va( "%d", cg.ping );
- ax = rect->x + ( rect->w / 2.0f ) - ( CG_Text_Width( s, scale, 0 ) / 2.0f ) + text_x;
- ay = rect->y + ( rect->h / 2.0f ) + ( CG_Text_Height( s, scale, 0 ) / 2.0f ) + text_y;
+ ping = va( "%d", cg.ping );
+ ax = rect->x + ( rect->w / 2.0f ) -
+ ( UI_Text_Width( ping, scale ) / 2.0f ) + text_x;
+ ay = rect->y + ( rect->h / 2.0f ) +
+ ( UI_Text_Height( ping, scale ) / 2.0f ) + text_y;
- Vector4Copy( textColor, adjustedColor );
- adjustedColor[ 3 ] = 0.5f;
- CG_Text_Paint( ax, ay, scale, adjustedColor, s, 0, 0, ITEM_TEXTSTYLE_NORMAL );
- }
+ Vector4Copy( textColor, adjustedColor );
+ adjustedColor[ 3 ] = 0.5f;
+ UI_Text_Paint( ax, ay, scale, adjustedColor, ping, 0, 0,
+ ITEM_TEXTSTYLE_NORMAL );
CG_DrawDisconnect( );
}
+#define SPEEDOMETER_NUM_SAMPLES 4096
+#define SPEEDOMETER_NUM_DISPLAYED_SAMPLES 160
+#define SPEEDOMETER_DRAW_TEXT 0x1
+#define SPEEDOMETER_DRAW_GRAPH 0x2
+#define SPEEDOMETER_IGNORE_Z 0x4
+float speedSamples[ SPEEDOMETER_NUM_SAMPLES ];
+int speedSampleTimes[ SPEEDOMETER_NUM_SAMPLES ];
+// array indices
+int oldestSpeedSample = 0;
+int maxSpeedSample = 0;
+int maxSpeedSampleInWindow = 0;
+
/*
-==============
-CG_DrawTextBlock
-==============
+===================
+CG_AddSpeed
+
+append a speed to the sample history
+===================
*/
-static void CG_DrawTextBlock( rectDef_t *rect, float text_x, float text_y, vec4_t color,
- float scale, int align, int textStyle, const char *text,
- menuDef_t *parent, itemDef_t *textItem )
+void CG_AddSpeed( void )
{
- float x, y, w, h;
+ float speed;
+ vec3_t vel;
+ int windowTime;
+ qboolean newSpeedGteMaxSpeed, newSpeedGteMaxSpeedInWindow;
- //offset the text
- x = rect->x;
- y = rect->y;
- w = rect->w - ( 16 + ( 2 * text_x ) ); //16 to ensure text within frame
- h = rect->h;
+ VectorCopy( cg.snap->ps.velocity, vel );
- textItem->text = text;
+ if( cg_drawSpeed.integer & SPEEDOMETER_IGNORE_Z )
+ vel[ 2 ] = 0;
- textItem->parent = parent;
- memcpy( textItem->window.foreColor, color, sizeof( vec4_t ) );
- textItem->window.flags = 0;
+ speed = VectorLength( vel );
- switch( align )
+ windowTime = cg_maxSpeedTimeWindow.integer;
+ if( windowTime < 0 )
+ windowTime = 0;
+ else if( windowTime > SPEEDOMETER_NUM_SAMPLES * 1000 )
+ windowTime = SPEEDOMETER_NUM_SAMPLES * 1000;
+
+ if( ( newSpeedGteMaxSpeed = ( speed >= speedSamples[ maxSpeedSample ] ) ) )
+ maxSpeedSample = oldestSpeedSample;
+
+ if( ( newSpeedGteMaxSpeedInWindow = ( speed >= speedSamples[ maxSpeedSampleInWindow ] ) ) )
+ maxSpeedSampleInWindow = oldestSpeedSample;
+
+ speedSamples[ oldestSpeedSample ] = speed;
+ speedSampleTimes[ oldestSpeedSample ] = cg.time;
+
+ if( !newSpeedGteMaxSpeed && maxSpeedSample == oldestSpeedSample )
{
- case ITEM_ALIGN_LEFT:
- textItem->window.rect.x = x;
- break;
+ // if old max was overwritten find a new one
+ int i;
+ for( maxSpeedSample = 0, i = 1; i < SPEEDOMETER_NUM_SAMPLES; i++ )
+ {
+ if( speedSamples[ i ] > speedSamples[ maxSpeedSample ] )
+ maxSpeedSample = i;
+ }
+ }
- case ITEM_ALIGN_RIGHT:
- textItem->window.rect.x = x + w;
- break;
+ if( !newSpeedGteMaxSpeedInWindow && ( maxSpeedSampleInWindow == oldestSpeedSample ||
+ cg.time - speedSampleTimes[ maxSpeedSampleInWindow ] > windowTime ) )
+ {
+ int i;
+ do {
+ maxSpeedSampleInWindow = ( maxSpeedSampleInWindow + 1 ) % SPEEDOMETER_NUM_SAMPLES;
+ } while( cg.time - speedSampleTimes[ maxSpeedSampleInWindow ] > windowTime );
+ for( i = maxSpeedSampleInWindow; ; i = ( i + 1 ) % SPEEDOMETER_NUM_SAMPLES )
+ {
+ if( speedSamples[ i ] > speedSamples[ maxSpeedSampleInWindow ] )
+ maxSpeedSampleInWindow = i;
+ if( i == oldestSpeedSample )
+ break;
+ }
+ }
- case ITEM_ALIGN_CENTER:
- textItem->window.rect.x = x + ( w / 2 );
- break;
+ oldestSpeedSample = ( oldestSpeedSample + 1 ) % SPEEDOMETER_NUM_SAMPLES;
+}
- default:
- textItem->window.rect.x = x;
- break;
+#define SPEEDOMETER_MIN_RANGE 900
+#define SPEED_MED 1000.f
+#define SPEED_FAST 1600.f
+
+/*
+===================
+CG_DrawSpeedGraph
+===================
+*/
+static void CG_DrawSpeedGraph( rectDef_t *rect, vec4_t foreColor,
+ vec4_t backColor )
+{
+ int i;
+ float val, max, top;
+ // colour of graph is interpolated between these values
+ const vec3_t slow = { 0.0, 0.0, 1.0 };
+ const vec3_t medium = { 0.0, 1.0, 0.0 };
+ const vec3_t fast = { 1.0, 0.0, 0.0 };
+ vec4_t color;
+
+ max = speedSamples[ maxSpeedSample ];
+ if( max < SPEEDOMETER_MIN_RANGE )
+ max = SPEEDOMETER_MIN_RANGE;
+
+ trap_R_SetColor( backColor );
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.whiteShader );
+
+ Vector4Copy( foreColor, color );
+
+ for( i = 1; i < SPEEDOMETER_NUM_DISPLAYED_SAMPLES; i++ )
+ {
+ val = speedSamples[ ( oldestSpeedSample + i + SPEEDOMETER_NUM_SAMPLES -
+ SPEEDOMETER_NUM_DISPLAYED_SAMPLES ) % SPEEDOMETER_NUM_SAMPLES ];
+ if( val < SPEED_MED )
+ VectorLerp2( val / SPEED_MED, slow, medium, color );
+ else if( val < SPEED_FAST )
+ VectorLerp2( ( val - SPEED_MED ) / ( SPEED_FAST - SPEED_MED ),
+ medium, fast, color );
+ else
+ VectorCopy( fast, color );
+ trap_R_SetColor( color );
+ top = rect->y + ( 1 - val / max ) * rect->h;
+ CG_DrawPic( rect->x + ( i / (float)SPEEDOMETER_NUM_DISPLAYED_SAMPLES ) * rect->w, top,
+ rect->w / (float)SPEEDOMETER_NUM_DISPLAYED_SAMPLES, val * rect->h / max,
+ cgs.media.whiteShader );
+ }
+ trap_R_SetColor( NULL );
+}
+
+/*
+===================
+CG_DrawSpeedText
+===================
+*/
+static void CG_DrawSpeedText( rectDef_t *rect, float text_x, float text_y,
+ float scale, vec4_t foreColor )
+{
+ char speedstr[ 16 ];
+ float val;
+ vec4_t color;
+
+ VectorCopy( foreColor, color );
+ color[ 3 ] = 1;
+ if( cg.predictedPlayerState.clientNum == cg.clientNum )
+ {
+ vec3_t vel;
+ VectorCopy( cg.predictedPlayerState.velocity, vel );
+ if( cg_drawSpeed.integer & SPEEDOMETER_IGNORE_Z )
+ vel[ 2 ] = 0;
+ val = VectorLength( vel );
}
+ else
+ val = speedSamples[ ( oldestSpeedSample - 1 + SPEEDOMETER_NUM_SAMPLES ) % SPEEDOMETER_NUM_SAMPLES ];
- textItem->window.rect.y = y;
- textItem->window.rect.w = w;
- textItem->window.rect.h = h;
- textItem->window.borderSize = 0;
- textItem->textRect.x = 0;
- textItem->textRect.y = 0;
- textItem->textRect.w = 0;
- textItem->textRect.h = 0;
- textItem->textalignment = align;
- textItem->textalignx = text_x;
- textItem->textaligny = text_y;
- textItem->textscale = scale;
- textItem->textStyle = textStyle;
+ Com_sprintf( speedstr, sizeof( speedstr ), "%d / %d", (int)val, (int)speedSamples[ maxSpeedSampleInWindow ] );
- //hack to utilise existing autowrap code
- Item_Text_AutoWrapped_Paint( textItem );
+ UI_Text_Paint(
+ rect->x + ( rect->w - UI_Text_Width( speedstr, scale ) ) / 2.0f,
+ rect->y + ( rect->h + UI_Text_Height( speedstr, scale ) ) / 2.0f,
+ scale, color, speedstr, 0, 0, ITEM_TEXTSTYLE_NORMAL );
+}
+
+/*
+===================
+CG_DrawSpeed
+===================
+*/
+static void CG_DrawSpeed( rectDef_t *rect, float text_x, float text_y,
+ float scale, vec4_t foreColor, vec4_t backColor )
+{
+ if( cg_drawSpeed.integer & SPEEDOMETER_DRAW_GRAPH )
+ CG_DrawSpeedGraph( rect, foreColor, backColor );
+ if( cg_drawSpeed.integer & SPEEDOMETER_DRAW_TEXT )
+ CG_DrawSpeedText( rect, text_x, text_y, scale, foreColor );
}
/*
@@ -2353,13 +2515,9 @@ CG_DrawConsole
===================
*/
static void CG_DrawConsole( rectDef_t *rect, float text_x, float text_y, vec4_t color,
- float scale, int align, int textStyle )
+ float scale, int textalign, int textvalign, int textStyle )
{
- static menuDef_t dummyParent;
- static itemDef_t textItem;
-
- CG_DrawTextBlock( rect, text_x, text_y, color, scale, align, textStyle,
- cg.consoleText, &dummyParent, &textItem );
+ UI_DrawTextBlock( rect, text_x, text_y, color, scale, textalign, textvalign, textStyle, cg.consoleText );
}
/*
@@ -2368,16 +2526,12 @@ CG_DrawTutorial
===================
*/
static void CG_DrawTutorial( rectDef_t *rect, float text_x, float text_y, vec4_t color,
- float scale, int align, int textStyle )
+ float scale, int textalign, int textvalign, int textStyle )
{
- static menuDef_t dummyParent;
- static itemDef_t textItem;
-
if( !cg_tutorial.integer )
return;
- CG_DrawTextBlock( rect, text_x, text_y, color, scale, align, textStyle,
- CG_TutorialText( ), &dummyParent, &textItem );
+ UI_DrawTextBlock( rect, text_x, text_y, color, scale, textalign, textvalign, textStyle, CG_TutorialText( ) );
}
/*
@@ -2387,29 +2541,34 @@ CG_DrawWeaponIcon
*/
void CG_DrawWeaponIcon( rectDef_t *rect, vec4_t color )
{
- int ammo, clips, maxAmmo;
- centity_t *cent;
+ int maxAmmo;
playerState_t *ps;
+ weapon_t weapon;
- cent = &cg_entities[ cg.snap->ps.clientNum ];
ps = &cg.snap->ps;
+ weapon = BG_GetPlayerWeapon( ps );
- ammo = ps->ammo;
- clips = ps->clips;
- BG_FindAmmoForWeapon( cent->currentState.weapon, &maxAmmo, NULL );
+ maxAmmo = BG_Weapon( weapon )->maxAmmo;
// don't display if dead
if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 )
return;
- if( cent->currentState.weapon == 0 )
+ if( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS )
+ {
return;
+ }
- CG_RegisterWeapon( cent->currentState.weapon );
+ if( !cg_weapons[ weapon ].registered )
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: CG_DrawWeaponIcon: weapon %d (%s) "
+ "is not registered\n", weapon, BG_Weapon( weapon )->name );
+ return;
+ }
- if( clips == 0 && !BG_FindInfinteAmmoForWeapon( cent->currentState.weapon ) )
+ if( ps->clips == 0 && !BG_Weapon( weapon )->infiniteAmmo )
{
- float ammoPercent = (float)ammo / (float)maxAmmo;
+ float ammoPercent = (float)ps->ammo / (float)maxAmmo;
if( ammoPercent < 0.33f )
{
@@ -2418,7 +2577,9 @@ void CG_DrawWeaponIcon( rectDef_t *rect, vec4_t color )
}
}
- if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS && CG_AtHighestClass( ) )
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_ALIENS &&
+ !BG_AlienCanEvolve( cg.predictedPlayerState.stats[ STAT_CLASS ],
+ ps->persistant[ PERS_CREDIT ], cgs.alienStage ) )
{
if( cg.time - cg.lastEvolveAttempt <= NO_CREDITS_TIME )
{
@@ -2428,7 +2589,8 @@ void CG_DrawWeaponIcon( rectDef_t *rect, vec4_t color )
}
trap_R_SetColor( color );
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_weapons[ cent->currentState.weapon ].weaponIcon );
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h,
+ cg_weapons[ weapon ].weaponIcon );
trap_R_SetColor( NULL );
}
@@ -2443,50 +2605,65 @@ CROSSHAIR
*/
+
/*
=================
CG_DrawCrosshair
=================
*/
-static void CG_DrawCrosshair( void )
+static void CG_DrawCrosshair( rectDef_t *rect, vec4_t color )
{
float w, h;
qhandle_t hShader;
float x, y;
weaponInfo_t *wi;
+ weapon_t weapon;
+
+ weapon = BG_GetPlayerWeapon( &cg.snap->ps );
if( cg_drawCrosshair.integer == CROSSHAIR_ALWAYSOFF )
return;
if( cg_drawCrosshair.integer == CROSSHAIR_RANGEDONLY &&
- !BG_FindLongRangedForWeapon( cg.snap->ps.weapon ) )
- {
+ !BG_Weapon( weapon )->longRanged )
return;
- }
- if( ( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) ||
- ( cg.snap->ps.stats[ STAT_STATE ] & SS_INFESTING ) ||
- ( cg.snap->ps.stats[ STAT_STATE ] & SS_HOVELING ) )
+ if( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
return;
if( cg.renderingThirdPerson )
return;
- wi = &cg_weapons[ cg.snap->ps.weapon ];
+ if( cg.snap->ps.pm_type == PM_INTERMISSION )
+ return;
- w = h = wi->crossHairSize;
+ wi = &cg_weapons[ weapon ];
- x = cg_crosshairX.integer;
- y = cg_crosshairY.integer;
- CG_AdjustFrom640( &x, &y, &w, &h );
+ w = h = wi->crossHairSize * cg_crosshairSize.value;
+ w *= cgDC.aspectScale;
+
+ //FIXME: this still ignores the width/height of the rect, but at least it's
+ //neater than cg_crosshairX/cg_crosshairY
+ x = rect->x + ( rect->w / 2 ) - ( w / 2 );
+ y = rect->y + ( rect->h / 2 ) - ( h / 2 );
hShader = wi->crossHair;
+ //aiming at a friendly player/buildable, dim the crosshair
+ if( cg.time == cg.crosshairClientTime || cg.crosshairBuildable >= 0 )
+ {
+ int i;
+ for( i = 0; i < 3; i++ )
+ color[i] *= .5f;
+
+ }
+
if( hShader != 0 )
{
- trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * ( cg.refdef.width - w ),
- y + cg.refdef.y + 0.5 * ( cg.refdef.height - h ),
- w, h, 0, 0, 1, 1, hShader );
+
+ trap_R_SetColor( color );
+ CG_DrawPic( x, y, w, h, hShader );
+ trap_R_SetColor( NULL );
}
}
@@ -2502,7 +2679,7 @@ static void CG_ScanForCrosshairEntity( void )
trace_t trace;
vec3_t start, end;
int content;
- pTeam_t team;
+ team_t team;
VectorCopy( cg.refdef.vieworg, start );
VectorMA( start, 131072, cg.refdef.viewaxis[ 0 ], end );
@@ -2510,20 +2687,29 @@ static void CG_ScanForCrosshairEntity( void )
CG_Trace( &trace, start, vec3_origin, vec3_origin, end,
cg.snap->ps.clientNum, CONTENTS_SOLID|CONTENTS_BODY );
- if( trace.entityNum >= MAX_CLIENTS )
- return;
-
// if the player is in fog, don't show it
content = trap_CM_PointContents( trace.endpos, 0 );
if( content & CONTENTS_FOG )
return;
+ if( trace.entityNum >= MAX_CLIENTS )
+ {
+ entityState_t *s = &cg_entities[ trace.entityNum ].currentState;
+ if( s->eType == ET_BUILDABLE && BG_Buildable( s->modelindex )->team ==
+ cg.snap->ps.stats[ STAT_TEAM ] )
+ cg.crosshairBuildable = trace.entityNum;
+ else
+ cg.crosshairBuildable = -1;
+
+ return;
+ }
+
team = cgs.clientinfo[ trace.entityNum ].team;
- if( cg.snap->ps.persistant[ PERS_TEAM ] != TEAM_SPECTATOR )
+ if( cg.snap->ps.stats[ STAT_TEAM ] != TEAM_NONE )
{
//only display team names of those on the same team as this player
- if( team != cg.snap->ps.stats[ STAT_PTEAM ] )
+ if( team != cg.snap->ps.stats[ STAT_TEAM ] )
return;
}
@@ -2535,13 +2721,51 @@ static void CG_ScanForCrosshairEntity( void )
/*
=====================
+CG_DrawLocation
+=====================
+*/
+static void CG_DrawLocation( rectDef_t *rect, float scale, int textalign, vec4_t color )
+{
+ const char *location;
+ centity_t *locent;
+ float maxX;
+ float tx = rect->x, ty = rect->y;
+
+ if( cg.intermissionStarted )
+ return;
+
+ maxX = rect->x + rect->w;
+
+ locent = CG_GetPlayerLocation( );
+ if( locent )
+ location = CG_ConfigString( CS_LOCATIONS + locent->currentState.generic1 );
+ else
+ location = CG_ConfigString( CS_LOCATIONS );
+
+ // need to skip horiz. align if it's too long, but valign must be run either way
+ if( UI_Text_Width( location, scale ) < rect->w )
+ {
+ CG_AlignText( rect, location, scale, 0.0f, 0.0f, textalign, VALIGN_CENTER, &tx, &ty );
+ UI_Text_Paint( tx, ty, scale, color, location, 0, 0, ITEM_TEXTSTYLE_NORMAL );
+ }
+ else
+ {
+ CG_AlignText( rect, location, scale, 0.0f, 0.0f, ALIGN_NONE, VALIGN_CENTER, &tx, &ty );
+ UI_Text_Paint_Limit( &maxX, tx, ty, scale, color, location, 0, 0 );
+ }
+
+ trap_R_SetColor( NULL );
+}
+
+/*
+=====================
CG_DrawCrosshairNames
=====================
*/
static void CG_DrawCrosshairNames( rectDef_t *rect, float scale, int textStyle )
{
float *color;
- char *name;
+ const char *name;
float w, x;
if( !cg_drawCrosshairNames.integer )
@@ -2554,21 +2778,31 @@ static void CG_DrawCrosshairNames( rectDef_t *rect, float scale, int textStyle )
CG_ScanForCrosshairEntity( );
// draw the name of the player being looked at
- color = CG_FadeColor( cg.crosshairClientTime, 1000 );
+ color = CG_FadeColor( cg.crosshairClientTime, CROSSHAIR_CLIENT_TIMEOUT );
if( !color )
{
trap_R_SetColor( NULL );
return;
}
+ // add health from overlay info to the crosshair client name
name = cgs.clientinfo[ cg.crosshairClientNum ].name;
- w = CG_Text_Width( name, scale, 0 );
- x = rect->x + rect->w / 2;
- CG_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle );
+ if( cg_teamOverlayUserinfo.integer &&
+ cg.snap->ps.stats[ STAT_TEAM ] != TEAM_NONE &&
+ cgs.teaminfoReceievedTime &&
+ cgs.clientinfo[ cg.crosshairClientNum ].health > 0 )
+ {
+ name = va( "%s ^7[^%c%d^7]", name,
+ CG_GetColorCharForHealth( cg.crosshairClientNum ),
+ cgs.clientinfo[ cg.crosshairClientNum ].health );
+ }
+
+ w = UI_Text_Width( name, scale );
+ x = rect->x + rect->w / 2.0f;
+ UI_Text_Paint( x - w / 2.0f, rect->y + rect->h, scale, color, name, 0, 0, textStyle );
trap_R_SetColor( NULL );
}
-
/*
===============
CG_OwnerDraw
@@ -2578,14 +2812,12 @@ Draw an owner drawn item
*/
void CG_OwnerDraw( float x, float y, float w, float h, float text_x,
float text_y, int ownerDraw, int ownerDrawFlags,
- int align, float special, float scale, vec4_t color,
+ int align, int textalign, int textvalign, float borderSize,
+ float scale, vec4_t foreColor, vec4_t backColor,
qhandle_t shader, int textStyle )
{
rectDef_t rect;
- if( cg_drawStatus.integer == 0 )
- return;
-
rect.x = x;
rect.y = y;
rect.w = w;
@@ -2594,100 +2826,107 @@ void CG_OwnerDraw( float x, float y, float w, float h, float text_x,
switch( ownerDraw )
{
case CG_PLAYER_CREDITS_VALUE:
- CG_DrawPlayerCreditsValue( &rect, color, qtrue );
+ CG_DrawPlayerCreditsValue( &rect, foreColor, qtrue );
break;
- case CG_PLAYER_BANK_VALUE:
- CG_DrawPlayerBankValue( &rect, color, qtrue );
+ case CG_PLAYER_CREDITS_FRACTION:
+ CG_DrawPlayerCreditsFraction( &rect, foreColor, shader );
break;
case CG_PLAYER_CREDITS_VALUE_NOPAD:
- CG_DrawPlayerCreditsValue( &rect, color, qfalse );
- break;
- case CG_PLAYER_BANK_VALUE_NOPAD:
- CG_DrawPlayerBankValue( &rect, color, qfalse );
- break;
- case CG_PLAYER_STAMINA:
- CG_DrawPlayerStamina( &rect, color, scale, align, textStyle, special );
+ CG_DrawPlayerCreditsValue( &rect, foreColor, qfalse );
break;
case CG_PLAYER_STAMINA_1:
- CG_DrawPlayerStamina1( &rect, color, shader );
- break;
case CG_PLAYER_STAMINA_2:
- CG_DrawPlayerStamina2( &rect, color, shader );
- break;
case CG_PLAYER_STAMINA_3:
- CG_DrawPlayerStamina3( &rect, color, shader );
- break;
case CG_PLAYER_STAMINA_4:
- CG_DrawPlayerStamina4( &rect, color, shader );
+ CG_DrawPlayerStamina( ownerDraw, &rect, backColor, foreColor, shader );
break;
case CG_PLAYER_STAMINA_BOLT:
- CG_DrawPlayerStaminaBolt( &rect, color, shader );
+ CG_DrawPlayerStaminaBolt( &rect, backColor, foreColor, shader );
break;
case CG_PLAYER_AMMO_VALUE:
- CG_DrawPlayerAmmoValue( &rect, color );
+ CG_DrawPlayerAmmoValue( &rect, foreColor );
break;
case CG_PLAYER_CLIPS_VALUE:
- CG_DrawPlayerClipsValue( &rect, color );
+ CG_DrawPlayerClipsValue( &rect, foreColor );
break;
case CG_PLAYER_BUILD_TIMER:
- CG_DrawPlayerBuildTimer( &rect, color );
+ CG_DrawPlayerBuildTimer( &rect, foreColor );
break;
case CG_PLAYER_HEALTH:
- CG_DrawPlayerHealthValue( &rect, color );
- break;
- case CG_PLAYER_HEALTH_BAR:
- CG_DrawPlayerHealthBar( &rect, color, scale, align, textStyle, special );
+ CG_DrawPlayerHealthValue( &rect, foreColor );
break;
case CG_PLAYER_HEALTH_CROSS:
- CG_DrawPlayerHealthCross( &rect, color, shader );
+ CG_DrawPlayerHealthCross( &rect, foreColor );
+ break;
+ case CG_PLAYER_CHARGE_BAR_BG:
+ CG_DrawPlayerChargeBarBG( &rect, foreColor, shader );
+ break;
+ case CG_PLAYER_CHARGE_BAR:
+ CG_DrawPlayerChargeBar( &rect, foreColor, shader );
break;
case CG_PLAYER_CLIPS_RING:
- CG_DrawPlayerClipsRing( &rect, color, shader );
+ CG_DrawPlayerClipsRing( &rect, backColor, foreColor, shader );
break;
case CG_PLAYER_BUILD_TIMER_RING:
- CG_DrawPlayerBuildTimerRing( &rect, color, shader );
+ CG_DrawPlayerBuildTimerRing( &rect, backColor, foreColor, shader );
break;
case CG_PLAYER_WALLCLIMBING:
- CG_DrawPlayerWallclimbing( &rect, color, shader );
+ CG_DrawPlayerWallclimbing( &rect, backColor, foreColor, shader );
break;
case CG_PLAYER_BOOSTED:
- CG_DrawPlayerBoosted( &rect, color, shader );
+ CG_DrawPlayerBoosted( &rect, backColor, foreColor, shader );
break;
case CG_PLAYER_BOOST_BOLT:
- CG_DrawPlayerBoosterBolt( &rect, color, shader );
+ CG_DrawPlayerBoosterBolt( &rect, backColor, foreColor, shader );
break;
case CG_PLAYER_POISON_BARBS:
- CG_DrawPlayerPoisonBarbs( &rect, color, shader );
+ CG_DrawPlayerPoisonBarbs( &rect, foreColor, shader );
break;
case CG_PLAYER_ALIEN_SENSE:
CG_DrawAlienSense( &rect );
break;
case CG_PLAYER_HUMAN_SCANNER:
- CG_DrawHumanScanner( &rect, shader, color );
+ CG_DrawHumanScanner( &rect, shader, foreColor );
break;
case CG_PLAYER_USABLE_BUILDABLE:
- CG_DrawUsableBuildable( &rect, shader, color );
+ CG_DrawUsableBuildable( &rect, shader, foreColor );
break;
case CG_KILLER:
- CG_DrawKiller( &rect, scale, color, shader, textStyle );
+ CG_DrawKiller( &rect, scale, foreColor, shader, textStyle );
break;
case CG_PLAYER_SELECT:
- CG_DrawItemSelect( &rect, color );
+ CG_DrawItemSelect( &rect, foreColor );
break;
case CG_PLAYER_WEAPONICON:
- CG_DrawWeaponIcon( &rect, color );
+ CG_DrawWeaponIcon( &rect, foreColor );
break;
case CG_PLAYER_SELECTTEXT:
CG_DrawItemSelectText( &rect, scale, textStyle );
break;
case CG_SPECTATORS:
- CG_DrawTeamSpectators( &rect, scale, color, shader );
+ CG_DrawTeamSpectators( &rect, scale, textvalign, foreColor, shader );
+ break;
+ case CG_PLAYER_LOCATION:
+ CG_DrawLocation( &rect, scale, textalign, foreColor );
+ break;
+ case CG_FOLLOW:
+ CG_DrawFollow( &rect, text_x, text_y, foreColor, scale,
+ textalign, textvalign, textStyle );
break;
case CG_PLAYER_CROSSHAIRNAMES:
CG_DrawCrosshairNames( &rect, scale, textStyle );
break;
+ case CG_PLAYER_CROSSHAIR:
+ CG_DrawCrosshair( &rect, foreColor );
+ break;
case CG_STAGE_REPORT_TEXT:
- CG_DrawStageReport( &rect, text_x, text_y, color, scale, align, textStyle );
+ CG_DrawStageReport( &rect, text_x, text_y, foreColor, scale, textalign, textvalign, textStyle );
+ break;
+ case CG_ALIENS_SCORE_LABEL:
+ CG_DrawTeamLabel( &rect, TEAM_ALIENS, text_x, text_y, foreColor, scale, textalign, textvalign, textStyle );
+ break;
+ case CG_HUMANS_SCORE_LABEL:
+ CG_DrawTeamLabel( &rect, TEAM_HUMANS, text_x, text_y, foreColor, scale, textalign, textvalign, textStyle );
break;
//loading screen
@@ -2695,74 +2934,92 @@ void CG_OwnerDraw( float x, float y, float w, float h, float text_x,
CG_DrawLevelShot( &rect );
break;
case CG_LOAD_MEDIA:
- CG_DrawMediaProgress( &rect, color, scale, align, textStyle, special );
+ CG_DrawMediaProgress( &rect, foreColor, scale, align, textalign, textStyle,
+ borderSize );
break;
case CG_LOAD_MEDIA_LABEL:
- CG_DrawMediaProgressLabel( &rect, text_x, text_y, color, scale, align );
+ CG_DrawMediaProgressLabel( &rect, text_x, text_y, foreColor, scale, textalign, textvalign );
break;
case CG_LOAD_BUILDABLES:
- CG_DrawBuildablesProgress( &rect, color, scale, align, textStyle, special );
+ CG_DrawBuildablesProgress( &rect, foreColor, scale, align, textalign,
+ textStyle, borderSize );
break;
case CG_LOAD_BUILDABLES_LABEL:
- CG_DrawBuildablesProgressLabel( &rect, text_x, text_y, color, scale, align );
+ CG_DrawBuildablesProgressLabel( &rect, text_x, text_y, foreColor, scale, textalign, textvalign );
break;
case CG_LOAD_CHARMODEL:
- CG_DrawCharModelProgress( &rect, color, scale, align, textStyle, special );
+ CG_DrawCharModelProgress( &rect, foreColor, scale, align, textalign,
+ textStyle, borderSize );
break;
case CG_LOAD_CHARMODEL_LABEL:
- CG_DrawCharModelProgressLabel( &rect, text_x, text_y, color, scale, align );
+ CG_DrawCharModelProgressLabel( &rect, text_x, text_y, foreColor, scale, textalign, textvalign );
break;
case CG_LOAD_OVERALL:
- CG_DrawOverallProgress( &rect, color, scale, align, textStyle, special );
+ CG_DrawOverallProgress( &rect, foreColor, scale, align, textalign, textStyle,
+ borderSize );
break;
case CG_LOAD_LEVELNAME:
- CG_DrawLevelName( &rect, text_x, text_y, color, scale, align, textStyle );
+ CG_DrawLevelName( &rect, text_x, text_y, foreColor, scale, textalign, textvalign, textStyle );
break;
case CG_LOAD_MOTD:
- CG_DrawMOTD( &rect, text_x, text_y, color, scale, align, textStyle );
+ CG_DrawMOTD( &rect, text_x, text_y, foreColor, scale, textalign, textvalign, textStyle );
break;
case CG_LOAD_HOSTNAME:
- CG_DrawHostname( &rect, text_x, text_y, color, scale, align, textStyle );
+ CG_DrawHostname( &rect, text_x, text_y, foreColor, scale, textalign, textvalign, textStyle );
break;
case CG_FPS:
- CG_DrawFPS( &rect, text_x, text_y, scale, color, align, textStyle, qtrue );
+ CG_DrawFPS( &rect, text_x, text_y, scale, foreColor, textalign, textvalign, textStyle, qtrue );
break;
case CG_FPS_FIXED:
- CG_DrawFPS( &rect, text_x, text_y, scale, color, align, textStyle, qfalse );
+ CG_DrawFPS( &rect, text_x, text_y, scale, foreColor, textalign, textvalign, textStyle, qfalse );
break;
case CG_TIMER:
- CG_DrawTimer( &rect, text_x, text_y, scale, color, align, textStyle );
+ CG_DrawTimer( &rect, text_x, text_y, scale, foreColor, textalign, textvalign, textStyle );
break;
case CG_CLOCK:
- CG_DrawClock( &rect, text_x, text_y, scale, color, align, textStyle );
+ CG_DrawClock( &rect, text_x, text_y, scale, foreColor, textalign, textvalign, textStyle );
break;
case CG_TIMER_MINS:
- CG_DrawTimerMins( &rect, color );
+ CG_DrawTimerMins( &rect, foreColor );
break;
case CG_TIMER_SECS:
- CG_DrawTimerSecs( &rect, color );
+ CG_DrawTimerSecs( &rect, foreColor );
break;
case CG_SNAPSHOT:
- CG_DrawSnapshot( &rect, text_x, text_y, scale, color, align, textStyle );
+ CG_DrawSnapshot( &rect, text_x, text_y, scale, foreColor, textalign, textvalign, textStyle );
break;
case CG_LAGOMETER:
- CG_DrawLagometer( &rect, text_x, text_y, scale, color );
+ CG_DrawLagometer( &rect, text_x, text_y, scale, foreColor );
+ break;
+ case CG_TEAMOVERLAY:
+ CG_DrawTeamOverlay( &rect, scale, foreColor );
+ break;
+ case CG_SPEEDOMETER:
+ CG_DrawSpeed( &rect, text_x, text_y, scale, foreColor, backColor );
break;
case CG_DEMO_PLAYBACK:
- CG_DrawDemoPlayback( &rect, color, shader );
+ CG_DrawDemoPlayback( &rect, foreColor, shader );
break;
case CG_DEMO_RECORDING:
- CG_DrawDemoRecording( &rect, color, shader );
+ CG_DrawDemoRecording( &rect, foreColor, shader );
break;
case CG_CONSOLE:
- CG_DrawConsole( &rect, text_x, text_y, color, scale, align, textStyle );
+ CG_DrawConsole( &rect, text_x, text_y, foreColor, scale, textalign, textvalign, textStyle );
break;
case CG_TUTORIAL:
- CG_DrawTutorial( &rect, text_x, text_y, color, scale, align, textStyle );
+ CG_DrawTutorial( &rect, text_x, text_y, foreColor, scale, textalign, textvalign, textStyle );
+ break;
+
+ case CG_KILLFEED:
+ CG_DrawKillMsg( &rect, text_x, text_y, scale, foreColor, textalign, textvalign, textStyle );
+ break;
+
+ case CG_PLAYER_THZ_SCANNER:
+ THZ_DrawScanner( &rect );
break;
default:
@@ -2827,17 +3084,17 @@ CG_ShowTeamMenus
*/
void CG_ShowTeamMenu( void )
{
- Menus_OpenByName( "teamMenu" );
+ Menus_ActivateByName( "teamMenu" );
}
/*
==================
CG_EventHandling
-==================
- type 0 - no event handling
- 1 - team menu
- 2 - hud editor
+type 0 - no event handling
+ 1 - team menu
+ 2 - hud editor
+==================
*/
void CG_EventHandling( int type )
{
@@ -2891,14 +3148,6 @@ int CG_ClientNumFromName( const char *p )
void CG_RunMenuScript( char **args )
{
}
-
-
-void CG_GetTeamColor( vec4_t *color )
-{
- (*color)[ 0 ] = (*color)[ 2 ] = 0.0f;
- (*color)[ 1 ] = 0.17f;
- (*color)[ 3 ] = 0.25f;
-}
//END TA UI
@@ -2910,13 +3159,9 @@ CG_DrawLighting
*/
static void CG_DrawLighting( void )
{
- centity_t *cent;
-
- cent = &cg_entities[ cg.snap->ps.clientNum ];
-
//fade to black if stamina is low
- if( ( cg.snap->ps.stats[ STAT_STAMINA ] < -800 ) &&
- ( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) )
+ if( ( cg.snap->ps.stats[ STAT_STAMINA ] < STAMINA_BLACKOUT_LEVEL ) &&
+ ( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) )
{
vec4_t black = { 0, 0, 0, 0 };
black[ 3 ] = 1.0 - ( (float)( cg.snap->ps.stats[ STAT_STAMINA ] + 1000 ) / 200.0f );
@@ -2946,8 +3191,15 @@ for a few moments
void CG_CenterPrint( const char *str, int y, int charWidth )
{
char *s;
+ char newlineParsed[ MAX_STRING_CHARS ];
+ const char *wrapped;
+ static int maxWidth = (int)( ( 2.0f / 3.0f ) * (float)SCREEN_WIDTH );
+
+ Q_ParseNewlines( newlineParsed, str, sizeof( newlineParsed ) );
- Q_strncpyz( cg.centerPrint, str, sizeof( cg.centerPrint ) );
+ wrapped = Item_Text_Wrap( newlineParsed, 0.5f, maxWidth );
+
+ Q_strncpyz( cg.centerPrint, wrapped, sizeof( cg.centerPrint ) );
cg.centerPrintTime = cg.time;
cg.centerPrintY = y;
@@ -2994,9 +3246,9 @@ static void CG_DrawCenterString( void )
while( 1 )
{
- char linebuffer[ 1024 ];
+ char linebuffer[ MAX_STRING_CHARS ];
- for( l = 0; l < 50; l++ )
+ for( l = 0; l < sizeof(linebuffer) - 1; l++ )
{
if( !start[ l ] || start[ l ] == '\n' )
break;
@@ -3006,10 +3258,10 @@ static void CG_DrawCenterString( void )
linebuffer[ l ] = 0;
- w = CG_Text_Width( linebuffer, 0.5, 0 );
- h = CG_Text_Height( linebuffer, 0.5, 0 );
+ w = UI_Text_Width( linebuffer, 0.5 );
+ h = UI_Text_Height( linebuffer, 0.5 );
x = ( SCREEN_WIDTH - w ) / 2;
- CG_Text_Paint( x, y + h, 0.5, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE );
+ UI_Text_Paint( x, y + h, 0.5, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE );
y += h + 6;
while( *start && ( *start != '\n' ) )
@@ -3037,83 +3289,62 @@ static void CG_DrawCenterString( void )
CG_DrawVote
=================
*/
-static void CG_DrawVote( void )
+static void CG_DrawVote( team_t team )
{
- char *s;
+ const char *s;
int sec;
+ int offset = 0;
vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f };
- char yeskey[ 32 ], nokey[ 32 ];
+ char yeskey[ 32 ] = "", nokey[ 32 ] = "";
- if( !cgs.voteTime )
+ if( !cgs.voteTime[ team ] )
return;
// play a talk beep whenever it is modified
- if( cgs.voteModified )
+ if( cgs.voteModified[ team ] )
{
- cgs.voteModified = qfalse;
+ cgs.voteModified[ team ] = qfalse;
trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
}
- sec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000;
+ sec = ( VOTE_TIME - ( cg.time - cgs.voteTime[ team ] ) ) / 1000;
if( sec < 0 )
sec = 0;
- Q_strncpyz( yeskey, CG_KeyBinding( "vote yes" ), sizeof( yeskey ) );
- Q_strncpyz( nokey, CG_KeyBinding( "vote no" ), sizeof( nokey ) );
- s = va( "VOTE(%i): \"%s\" [%s]Yes:%i [%s]No:%i", sec, cgs.voteString,
- yeskey, cgs.voteYes, nokey, cgs.voteNo );
- CG_Text_Paint( 8, 340, 0.3f, white, s, 0, 0, ITEM_TEXTSTYLE_NORMAL );
-}
-/*
-=================
-CG_DrawTeamVote
-=================
-*/
-static void CG_DrawTeamVote( void )
-{
- char *s;
- int sec, cs_offset;
- vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f };
- char yeskey[ 32 ], nokey[ 32 ];
+ if( cg_tutorial.integer )
+ {
+ Com_sprintf( yeskey, sizeof( yeskey ), "[%s]",
+ CG_KeyBinding( va( "%svote yes", team == TEAM_NONE ? "" : "team" ) ) );
+ Com_sprintf( nokey, sizeof( nokey ), "[%s]",
+ CG_KeyBinding( va( "%svote no", team == TEAM_NONE ? "" : "team" ) ) );
+ }
- if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS )
- cs_offset = 0;
- else if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS )
- cs_offset = 1;
- else
- return;
+ if( team != TEAM_NONE )
+ offset = 80;
- if( !cgs.teamVoteTime[ cs_offset ] )
- return;
+ s = va( "%sVOTE(%i): %s",
+ team == TEAM_NONE ? "" : "TEAM", sec, cgs.voteString[ team ] );
- // play a talk beep whenever it is modified
- if ( cgs.teamVoteModified[ cs_offset ] )
- {
- cgs.teamVoteModified[ cs_offset ] = qfalse;
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- }
+ UI_Text_Paint( 8, 300 + offset, 0.3f, white, s, 0, 0,
+ ITEM_TEXTSTYLE_NORMAL );
- sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[ cs_offset ] ) ) / 1000;
+ s = va( " Called by: \"%s\"", cgs.voteCaller[ team ] );
- if( sec < 0 )
- sec = 0;
+ UI_Text_Paint( 8, 320 + offset, 0.3f, white, s, 0, 0,
+ ITEM_TEXTSTYLE_NORMAL );
- Q_strncpyz( yeskey, CG_KeyBinding( "teamvote yes" ), sizeof( yeskey ) );
- Q_strncpyz( nokey, CG_KeyBinding( "teamvote no" ), sizeof( nokey ) );
- s = va( "TEAMVOTE(%i): \"%s\" [%s]Yes:%i [%s]No:%i", sec,
- cgs.teamVoteString[ cs_offset ],
- yeskey, cgs.teamVoteYes[cs_offset],
- nokey, cgs.teamVoteNo[ cs_offset ] );
+ s = va( " %sYes:%i %sNo:%i",
+ yeskey, cgs.voteYes[ team ], nokey, cgs.voteNo[ team ] );
- CG_Text_Paint( 8, 360, 0.3f, white, s, 0, 0, ITEM_TEXTSTYLE_NORMAL );
+ UI_Text_Paint( 8, 340 + offset, 0.3f, white, s, 0, 0,
+ ITEM_TEXTSTYLE_NORMAL );
}
static qboolean CG_DrawScoreboard( void )
{
static qboolean firstTime = qtrue;
- float fade, *fadeColor;
if( menuScoreboard )
menuScoreboard->window.flags &= ~WINDOW_FORCED;
@@ -3125,13 +3356,8 @@ static qboolean CG_DrawScoreboard( void )
return qfalse;
}
- if( cg.showScores ||
- cg.predictedPlayerState.pm_type == PM_INTERMISSION )
- {
- fade = 1.0;
- fadeColor = colorWhite;
- }
- else
+ if( !cg.showScores &&
+ cg.predictedPlayerState.pm_type != PM_INTERMISSION )
{
cg.deferredPlayerLoading = 0;
cg.killerName[ 0 ] = 0;
@@ -3139,6 +3365,7 @@ static qboolean CG_DrawScoreboard( void )
return qfalse;
}
+ CG_RequestScores( );
if( menuScoreboard == NULL )
menuScoreboard = Menus_FindByName( "teamscore_menu" );
@@ -3147,10 +3374,12 @@ static qboolean CG_DrawScoreboard( void )
{
if( firstTime )
{
+ cg.spectatorTime = trap_Milliseconds();
CG_SetScoreSelection( menuScoreboard );
firstTime = qfalse;
}
+ Menu_Update( menuScoreboard );
Menu_Paint( menuScoreboard, qtrue );
}
@@ -3164,27 +3393,28 @@ CG_DrawIntermission
*/
static void CG_DrawIntermission( void )
{
- if( cg_drawStatus.integer )
- Menu_Paint( Menus_FindByName( "default_hud" ), qtrue );
+ menuDef_t *menu = Menus_FindByName( "default_hud" );
+
+ Menu_Update( menu );
+ Menu_Paint( menu, qtrue );
cg.scoreFadeTime = cg.time;
cg.scoreBoardShowing = CG_DrawScoreboard( );
}
-#define FOLLOWING_STRING "following "
-
/*
=================
-CG_DrawFollow
+CG_DrawQueue
=================
*/
-static qboolean CG_DrawFollow( void )
+static qboolean CG_DrawQueue( void )
{
float w;
vec4_t color;
- char buffer[ MAX_STRING_CHARS ];
+ int position;
+ char *ordinal, buffer[ MAX_STRING_CHARS ];
- if( !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
+ if( !( cg.snap->ps.pm_flags & PMF_QUEUED ) )
return qfalse;
color[ 0 ] = 1;
@@ -3192,66 +3422,82 @@ static qboolean CG_DrawFollow( void )
color[ 2 ] = 1;
color[ 3 ] = 1;
- strcpy( buffer, FOLLOWING_STRING );
- strcat( buffer, cgs.clientinfo[ cg.snap->ps.clientNum ].name );
+ position = cg.snap->ps.persistant[ PERS_QUEUEPOS ] + 1;
+ if( position < 1 )
+ return qfalse;
- w = CG_Text_Width( buffer, 0.7f, 0 );
- CG_Text_Paint( 320 - w / 2, 400, 0.7f, color, buffer, 0, 0, ITEM_TEXTSTYLE_SHADOWED );
+ switch( position % 100 )
+ {
+ case 11:
+ case 12:
+ case 13:
+ ordinal = "th";
+ break;
+ default:
+ switch( position % 10 )
+ {
+ case 1: ordinal = "st"; break;
+ case 2: ordinal = "nd"; break;
+ case 3: ordinal = "rd"; break;
+ default: ordinal = "th"; break;
+ }
+ break;
+ }
+
+ Com_sprintf( buffer, MAX_STRING_CHARS, "You are %d%s in the spawn queue",
+ position, ordinal );
+
+ w = UI_Text_Width( buffer, 0.7f );
+ UI_Text_Paint( 320 - w / 2, 360, 0.7f, color, buffer, 0, 0, ITEM_TEXTSTYLE_SHADOWED );
+
+ if( cg.snap->ps.persistant[ PERS_SPAWNS ] == 0 )
+ Com_sprintf( buffer, MAX_STRING_CHARS, "There are no spawns remaining" );
+ else if( cg.snap->ps.persistant[ PERS_SPAWNS ] == 1 )
+ Com_sprintf( buffer, MAX_STRING_CHARS, "There is 1 spawn remaining" );
+ else
+ Com_sprintf( buffer, MAX_STRING_CHARS, "There are %d spawns remaining",
+ cg.snap->ps.persistant[ PERS_SPAWNS ] );
+
+ w = UI_Text_Width( buffer, 0.7f );
+ UI_Text_Paint( 320 - w / 2, 400, 0.7f, color, buffer, 0, 0, ITEM_TEXTSTYLE_SHADOWED );
return qtrue;
}
+
/*
=================
-CG_DrawQueue
+CG_DrawWarmup
=================
*/
-static qboolean CG_DrawQueue( void )
+static void CG_DrawWarmup( void )
{
- float w;
- vec4_t color;
- char buffer[ MAX_STRING_CHARS ];
+ int sec = 0;
+ int w;
+ int h;
+ float size = 0.5f;
+ char text[ MAX_STRING_CHARS ] = "Warmup Time:";
- if( !( cg.snap->ps.pm_flags & PMF_QUEUED ) )
- return qfalse;
-
- color[ 0 ] = 1;
- color[ 1 ] = 1;
- color[ 2 ] = 1;
- color[ 3 ] = 1;
+ if( !cg.warmupTime )
+ return;
- Com_sprintf( buffer, MAX_STRING_CHARS, "You are in position %d of the spawn queue.",
- cg.snap->ps.persistant[ PERS_QUEUEPOS ] + 1 );
+ sec = ( cg.warmupTime - cg.time ) / 1000;
- w = CG_Text_Width( buffer, 0.7f, 0 );
- CG_Text_Paint( 320 - w / 2, 360, 0.7f, color, buffer, 0, 0, ITEM_TEXTSTYLE_SHADOWED );
+ if( sec < 0 )
+ return;
- if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- if( cgs.numAlienSpawns == 1 )
- Com_sprintf( buffer, MAX_STRING_CHARS, "There is 1 spawn remaining." );
- else
- Com_sprintf( buffer, MAX_STRING_CHARS, "There are %d spawns remaining.",
- cgs.numAlienSpawns );
- }
- else if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- if( cgs.numHumanSpawns == 1 )
- Com_sprintf( buffer, MAX_STRING_CHARS, "There is 1 spawn remaining." );
- else
- Com_sprintf( buffer, MAX_STRING_CHARS, "There are %d spawns remaining.",
- cgs.numHumanSpawns );
- }
+ w = UI_Text_Width( text, size );
+ h = UI_Text_Height( text, size );
+ UI_Text_Paint( 320 - w / 2, 200, size, colorWhite, text, 0, 0, ITEM_TEXTSTYLE_SHADOWED );
- w = CG_Text_Width( buffer, 0.7f, 0 );
- CG_Text_Paint( 320 - w / 2, 400, 0.7f, color, buffer, 0, 0, ITEM_TEXTSTYLE_SHADOWED );
+ Com_sprintf( text, sizeof( text ), "%s", sec ? va( "%d", sec ) : "FIGHT!" );
- return qtrue;
+ w = UI_Text_Width( text, size );
+ UI_Text_Paint( 320 - w / 2, 200 + 1.5f * h, size, colorWhite, text, 0, 0, ITEM_TEXTSTYLE_SHADOWED );
}
//==================================================================================
-#define SPECTATOR_STRING "SPECTATOR"
/*
=================
CG_Draw2D
@@ -3259,15 +3505,11 @@ CG_Draw2D
*/
static void CG_Draw2D( void )
{
- vec4_t color;
- float w;
- menuDef_t *menu = NULL, *defaultMenu;
+ menuDef_t *menu = NULL;
- color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 1.0f;
-
- // if we are taking a levelshot for the menu, don't draw anything
- if( cg.levelShot )
- return;
+ // fading to black if stamina runs out
+ // (only 2D that can't be disabled)
+ CG_DrawLighting( );
if( cg_draw2D.integer == 0 )
return;
@@ -3278,36 +3520,30 @@ static void CG_Draw2D( void )
return;
}
- //TA: draw the lighting effects e.g. nvg
- CG_DrawLighting( );
-
-
- defaultMenu = Menus_FindByName( "default_hud" );
-
- if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
+ if ( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_NONE
+ || (cg.snap->ps.persistant[ PERS_SPECSTATE ] == SPECTATOR_NOT
+ && cg.snap->ps.stats[ STAT_HEALTH ] > 0 ))
{
- w = CG_Text_Width( SPECTATOR_STRING, 0.7f, 0 );
- CG_Text_Paint( 320 - w / 2, 440, 0.7f, color, SPECTATOR_STRING, 0, 0, ITEM_TEXTSTYLE_SHADOWED );
+ menu = Menus_FindByName( BG_ClassConfig(
+ cg.predictedPlayerState.stats[ STAT_CLASS ] )->hudName );
+
+ CG_DrawBuildableStatus( );
}
- else
- menu = Menus_FindByName( BG_FindHudNameForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] ) );
- if( !( cg.snap->ps.stats[ STAT_STATE ] & SS_INFESTING ) &&
- !( cg.snap->ps.stats[ STAT_STATE ] & SS_HOVELING ) && menu &&
- ( cg.snap->ps.stats[ STAT_HEALTH ] > 0 ) )
+ if( !menu )
{
- CG_DrawBuildableStatus( );
- if( cg_drawStatus.integer )
- Menu_Paint( menu, qtrue );
+ menu = Menus_FindByName( "default_hud" );
- CG_DrawCrosshair( );
+ if( !menu ) // still couldn't find it
+ CG_Error( "Default HUD could not be found" );
}
- else if( cg_drawStatus.integer )
- Menu_Paint( defaultMenu, qtrue );
- CG_DrawVote( );
- CG_DrawTeamVote( );
- CG_DrawFollow( );
+ Menu_Update( menu );
+ Menu_Paint( menu, qtrue );
+
+ CG_DrawVote( TEAM_NONE );
+ CG_DrawVote( cg.predictedPlayerState.stats[ STAT_TEAM ] );
+ CG_DrawWarmup( );
CG_DrawQueue( );
// don't draw center string if scoreboard is up
@@ -3356,7 +3592,7 @@ static void CG_PainBlend( void )
float x, y, w, h;
float s1, t1, s2, t2;
- if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR || cg.intermissionStarted )
+ if( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT || cg.intermissionStarted )
return;
damage = cg.lastHealth - cg.snap->ps.stats[ STAT_HEALTH ];
@@ -3383,9 +3619,9 @@ static void CG_PainBlend( void )
return;
}
- if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
VectorSet( color, 0.43f, 0.8f, 0.37f );
- else if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ else if( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
VectorSet( color, 0.8f, 0.0f, 0.0f );
if( cg.painBlendValue > cg.painBlendTarget )
@@ -3455,6 +3691,66 @@ void CG_ResetPainBlend( void )
}
/*
+================
+CG_DrawBinaryShadersFinalPhases
+================
+*/
+static void CG_DrawBinaryShadersFinalPhases( void )
+{
+ float ss, f, l, u;
+ polyVert_t verts[ 4 ] = {
+ { { 0, 0, 0 }, { 0, 0 }, { 255, 255, 255, 255 } },
+ { { 0, 0, 0 }, { 1, 0 }, { 255, 255, 255, 255 } },
+ { { 0, 0, 0 }, { 1, 1 }, { 255, 255, 255, 255 } },
+ { { 0, 0, 0 }, { 0, 1 }, { 255, 255, 255, 255 } }
+ };
+ int i, j, k;
+
+ if( !cg.numBinaryShadersUsed )
+ return;
+
+ ss = cg_binaryShaderScreenScale.value;
+ if( ss <= 0.0f )
+ {
+ cg.numBinaryShadersUsed = 0;
+ return;
+ }
+ else if( ss > 1.0f )
+ ss = 1.0f;
+
+ ss = sqrt( ss );
+
+ f = 1.01f; // FIXME: is this a good choice to avoid near-clipping?
+ l = f * tan( DEG2RAD( cg.refdef.fov_x / 2 ) ) * ss;
+ u = f * tan( DEG2RAD( cg.refdef.fov_y / 2 ) ) * ss;
+
+ VectorMA( cg.refdef.vieworg, f, cg.refdef.viewaxis[ 0 ], verts[ 0 ].xyz );
+ VectorMA( verts[ 0 ].xyz, l, cg.refdef.viewaxis[ 1 ], verts[ 0 ].xyz );
+ VectorMA( verts[ 0 ].xyz, u, cg.refdef.viewaxis[ 2 ], verts[ 0 ].xyz );
+ VectorMA( verts[ 0 ].xyz, -2*l, cg.refdef.viewaxis[ 1 ], verts[ 1 ].xyz );
+ VectorMA( verts[ 1 ].xyz, -2*u, cg.refdef.viewaxis[ 2 ], verts[ 2 ].xyz );
+ VectorMA( verts[ 0 ].xyz, -2*u, cg.refdef.viewaxis[ 2 ], verts[ 3 ].xyz );
+
+ trap_R_AddPolyToScene( cgs.media.binaryAlpha1Shader, 4, verts );
+
+ for( i = 0; i < cg.numBinaryShadersUsed; ++i )
+ {
+ for( j = 0; j < 4; ++j )
+ {
+ for( k = 0; k < 3; ++k )
+ verts[ j ].modulate[ k ] = cg.binaryShaderSettings[ i ].color[ k ];
+ }
+
+ if( cg.binaryShaderSettings[ i ].drawFrontline )
+ trap_R_AddPolyToScene( cgs.media.binaryShaders[ i ].f3, 4, verts );
+ if( cg.binaryShaderSettings[ i ].drawIntersection )
+ trap_R_AddPolyToScene( cgs.media.binaryShaders[ i ].b3, 4, verts );
+ }
+
+ cg.numBinaryShadersUsed = 0;
+}
+
+/*
=====================
CG_DrawActive
@@ -3496,6 +3792,8 @@ void CG_DrawActive( stereoFrame_t stereoView )
VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[ 1 ],
cg.refdef.vieworg );
+ CG_DrawBinaryShadersFinalPhases( );
+
// draw 3D view
trap_R_RenderScene( &cg.refdef );
@@ -3510,6 +3808,3 @@ void CG_DrawActive( stereoFrame_t stereoView )
// draw status bar and other floating elements
CG_Draw2D( );
}
-
-
-
diff --git a/src/cgame/cg_drawtools.c b/src/cgame/cg_drawtools.c
index 06ae071..cc8533a 100644
--- a/src/cgame/cg_drawtools.c
+++ b/src/cgame/cg_drawtools.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,14 +17,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc
-
#include "cg_local.h"
/*
@@ -126,10 +126,14 @@ Coords are virtual 640x480
*/
void CG_DrawSides( float x, float y, float w, float h, float size )
{
+ float sizeY;
+
CG_AdjustFrom640( &x, &y, &w, &h );
+ sizeY = size * cgs.screenYScale;
size *= cgs.screenXScale;
- trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
- trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
+
+ trap_R_DrawStretchPic( x, y + sizeY, size, h - ( sizeY * 2.0f ), 0, 0, 0, 0, cgs.media.whiteShader );
+ trap_R_DrawStretchPic( x + w - size, y + sizeY, size, h - ( sizeY * 2.0f ), 0, 0, 0, 0, cgs.media.whiteShader );
}
void CG_DrawTopBottom( float x, float y, float w, float h, float size )
@@ -172,7 +176,34 @@ void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader
trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
}
+/*
+================
+CG_SetClipRegion
+=================
+*/
+void CG_SetClipRegion( float x, float y, float w, float h )
+{
+ vec4_t clip;
+
+ CG_AdjustFrom640( &x, &y, &w, &h );
+ clip[ 0 ] = x;
+ clip[ 1 ] = y;
+ clip[ 2 ] = x + w;
+ clip[ 3 ] = y + h;
+
+ trap_R_SetClipRegion( clip );
+}
+
+/*
+================
+CG_ClearClipRegion
+=================
+*/
+void CG_ClearClipRegion( void )
+{
+ trap_R_SetClipRegion( NULL );
+}
/*
================
@@ -321,30 +352,30 @@ CG_WorldToScreen
*/
qboolean CG_WorldToScreen( vec3_t point, float *x, float *y )
{
- vec3_t trans;
- float xc, yc;
- float px, py;
- float z;
+ vec3_t trans;
+ float xc, yc;
+ float px, py;
+ float z;
- px = tan( cg.refdef.fov_x * M_PI / 360.0 );
- py = tan( cg.refdef.fov_y * M_PI / 360.0 );
+ px = tan( cg.refdef.fov_x * M_PI / 360.0f );
+ py = tan( cg.refdef.fov_y * M_PI / 360.0f );
- VectorSubtract( point, cg.refdef.vieworg, trans );
+ VectorSubtract( point, cg.refdef.vieworg, trans );
- xc = 640.0f / 2.0f;
- yc = 480.0f / 2.0f;
+ xc = ( 640.0f * cg_viewsize.integer ) / 200.0f;
+ yc = ( 480.0f * cg_viewsize.integer ) / 200.0f;
- z = DotProduct( trans, cg.refdef.viewaxis[ 0 ] );
- if( z <= 0.001f )
- return qfalse;
+ z = DotProduct( trans, cg.refdef.viewaxis[ 0 ] );
+ if( z <= 0.001f )
+ return qfalse;
if( x )
- *x = xc - DotProduct( trans, cg.refdef.viewaxis[ 1 ] ) * xc / ( z * px );
+ *x = 320.0f - DotProduct( trans, cg.refdef.viewaxis[ 1 ] ) * xc / ( z * px );
if( y )
- *y = yc - DotProduct( trans, cg.refdef.viewaxis[ 2 ] ) * yc / ( z * py );
+ *y = 240.0f - DotProduct( trans, cg.refdef.viewaxis[ 2 ] ) * yc / ( z * py );
- return qtrue;
+ return qtrue;
}
/*
@@ -359,6 +390,7 @@ char *CG_KeyBinding( const char *bind )
int i;
key[ 0 ] = '\0';
+
// NOTE: change K_LAST_KEY to MAX_KEYS for full key support (eventually)
for( i = 0; i < K_LAST_KEY; i++ )
{
@@ -367,12 +399,41 @@ char *CG_KeyBinding( const char *bind )
{
trap_Key_KeynumToStringBuf( i, key, sizeof( key ) );
break;
- }
+ }
}
+
if( !key[ 0 ] )
{
Q_strncpyz( key, "\\", sizeof( key ) );
Q_strcat( key, sizeof( key ), bind );
}
+
return key;
}
+
+/*
+=================
+CG_GetColorCharForHealth
+=================
+*/
+char CG_GetColorCharForHealth( int clientnum )
+{
+ char health_char = '2';
+ int healthPercent;
+ int maxHealth;
+ int curWeaponClass = cgs.clientinfo[ clientnum ].curWeaponClass;
+
+ if( cgs.clientinfo[ clientnum ].team == TEAM_ALIENS )
+ maxHealth = BG_Class( curWeaponClass )->health;
+ else
+ maxHealth = BG_Class( PCL_HUMAN )->health;
+
+ healthPercent = (int) ( 100.0f * (float) cgs.clientinfo[ clientnum ].health /
+ (float) maxHealth );
+
+ if( healthPercent < 33 )
+ health_char = '1';
+ else if( healthPercent < 67 )
+ health_char = '3';
+ return health_char;
+}
diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c
index 17f1a7d..4008e56 100644
--- a/src/cgame/cg_ents.c
+++ b/src/cgame/cg_ents.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,14 +17,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_ents.c -- present snapshot entities, happens every single frame
-
#include "cg_local.h"
/*
@@ -251,7 +251,7 @@ static void CG_EntityEffects( centity_t *cent )
if( CG_IsTrailSystemValid( &cent->muzzleTS ) )
{
- //FIXME hack to prevent tesla trails reaching too far
+ //FIXME hack to prevent tesla trails reaching too far
if( cent->currentState.eType == ET_BUILDABLE )
{
vec3_t front, back;
@@ -311,6 +311,136 @@ static void CG_General( centity_t *cent )
/*
==================
+CG_WeaponDrop
+==================
+*/
+static void CG_WeaponDrop( centity_t *cent )
+{
+ refEntity_t ent;
+ entityState_t *es;
+ int msec;
+ float frac;
+ float scale;
+ weaponInfo_t *wi;
+
+ es = &cent->currentState;
+
+ if (BG_Weapon(es->modelindex) == WP_NONE)
+ {
+ CG_Printf("Bad weapon index %i on entity", es->modelindex);
+ return;
+ }
+
+ // if set to invisible, skip
+ if (es->eFlags & EF_NODRAW)
+ return;
+
+
+ // items bob up and down continuously
+ scale = 0.005 + cent->currentState.number * 0.00001;
+ cent->lerpOrigin[2] += 4 + cos( ( cg.time + 1000 ) * scale ) * 4;
+
+ memset (&ent, 0, sizeof(ent));
+
+ // autorotate at one of two speeds
+ VectorCopy( cg.autoAnglesFast, cent->lerpAngles );
+ AxisCopy( cg.autoAxisFast, ent.axis );
+// VectorCopy( cg.autoAngles, cent->lerpAngles );
+// AxisCopy( cg.autoAxis, ent.axis );
+
+ wi = &cg_weapons[ es->modelindex ];
+
+ // the weapons have their origin where they attatch to player
+ // models, so we need to offset them or they will rotate
+ // eccentricly
+
+ cent->lerpOrigin[0] -= wi->weaponMidpoint[0] * ent.axis[0][0]
+ + wi->weaponMidpoint[1] * ent.axis[1][0]
+ + wi->weaponMidpoint[2] * ent.axis[2][0];
+ cent->lerpOrigin[1] -= wi->weaponMidpoint[0] * ent.axis[0][1]
+ + wi->weaponMidpoint[1] * ent.axis[1][1]
+ + wi->weaponMidpoint[2] * ent.axis[2][1];
+ cent->lerpOrigin[2] -= wi->weaponMidpoint[0] * ent.axis[0][2]
+ + wi->weaponMidpoint[1] * ent.axis[1][2]
+ + wi->weaponMidpoint[2] * ent.axis[2][2];
+ cent->lerpOrigin[2] += 8; // an extra height boost
+
+#if 0
+ if( item->giType == IT_WEAPON && item->giTag == WP_RAILGUN ) {
+ clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum];
+ Byte4Copy( ci->c1RGBA, ent.shaderRGBA );
+ }
+#endif
+
+ ent.hModel = wi->weaponModel;
+
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+
+ ent.nonNormalizedAxes = qfalse;
+
+ // if just respawned, slowly scale up
+ msec = cg.time - cent->miscTime;
+ if ( msec >= 0 && msec < ITEM_SCALEUP_TIME )
+ {
+ frac = (float)msec / ITEM_SCALEUP_TIME;
+ VectorScale( ent.axis[0], frac, ent.axis[0] );
+ VectorScale( ent.axis[1], frac, ent.axis[1] );
+ VectorScale( ent.axis[2], frac, ent.axis[2] );
+ ent.nonNormalizedAxes = qtrue;
+ }
+ else
+ {
+ frac = 1.0;
+ }
+
+ // items without glow textures need to keep a minimum light value
+ // so they are always visible
+ ent.renderfx |= RF_MINLIGHT;
+
+ // increase the size of the weapons when they are presented as items
+ VectorScale( ent.axis[0], 1.5, ent.axis[0] );
+ VectorScale( ent.axis[1], 1.5, ent.axis[1] );
+ VectorScale( ent.axis[2], 1.5, ent.axis[2] );
+ ent.nonNormalizedAxes = qtrue;
+#ifdef MISSIONPACK
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.weaponHoverSound );
+#endif
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene(&ent);
+
+#if 0
+ if ( item->giType == IT_WEAPON && wi && wi->barrelModel )
+ {
+ refEntity_t barrel;
+ vec3_t angles;
+
+ memset( &barrel, 0, sizeof( barrel ) );
+
+ barrel.hModel = wi->barrelModel;
+
+ VectorCopy( ent.lightingOrigin, barrel.lightingOrigin );
+ barrel.shadowPlane = ent.shadowPlane;
+ barrel.renderfx = ent.renderfx;
+
+ angles[YAW] = 0;
+ angles[PITCH] = 0;
+ angles[ROLL] = 0;
+ AnglesToAxis( angles, barrel.axis );
+
+ CG_PositionRotatedEntityOnTag( &barrel, &ent, wi->weaponModel, "tag_barrel" );
+
+ barrel.nonNormalizedAxes = ent.nonNormalizedAxes;
+
+ trap_R_AddRefEntityToScene( &barrel );
+ }
+#endif
+}
+
+
+/*
+==================
CG_Speaker
Speaker entities can automatically play sounds
@@ -367,6 +497,7 @@ static void CG_LaunchMissile( centity_t *cent )
{
CG_SetAttachmentCent( &ps->attachment, cent );
CG_AttachToCent( &ps->attachment );
+ ps->charge = es->torsoAnim;
}
}
@@ -407,9 +538,6 @@ static void CG_Missile( centity_t *cent )
wim = &wi->wim[ weaponMode ];
- // calculate the axis
- VectorCopy( es->angles, cent->lerpAngles );
-
// add dynamic light
if( wim->missileDlight )
{
@@ -437,7 +565,8 @@ static void CG_Missile( centity_t *cent )
if( wim->usesSpriteMissle )
{
ent.reType = RT_SPRITE;
- ent.radius = wim->missileSpriteSize;
+ ent.radius = wim->missileSpriteSize +
+ wim->missileSpriteCharge * es->torsoAnim;
ent.rotation = 0;
ent.customShader = wim->missileSprite;
ent.shaderRGBA[ 0 ] = 0xFF;
@@ -498,6 +627,9 @@ static void CG_Mover( centity_t *cent )
s1 = &cent->currentState;
+ if( !s1->modelindex )
+ return;
+
// create the render entity
memset( &ent, 0, sizeof( ent ) );
VectorCopy( cent->lerpOrigin, ent.origin );
@@ -653,7 +785,7 @@ static void CG_LightFlare( centity_t *cent )
flare.renderfx |= RF_DEPTHHACK;
//bunch of geometry
- AngleVectors( es->angles, forward, NULL, NULL );
+ AngleVectors( cent->lerpAngles, forward, NULL, NULL );
VectorCopy( cent->lerpOrigin, flare.origin );
VectorSubtract( flare.origin, cg.refdef.vieworg, delta );
len = VectorLength( delta );
@@ -788,38 +920,28 @@ static void CG_Lev2ZapChain( centity_t *cent )
int i;
entityState_t *es;
centity_t *source = NULL, *target = NULL;
+ int entityNums[ LEVEL2_AREAZAP_MAX_TARGETS + 1 ];
+ int count;
es = &cent->currentState;
- for( i = 0; i <= 2; i++ )
+ count = BG_UnpackEntityNumbers( es, entityNums, LEVEL2_AREAZAP_MAX_TARGETS + 1 );
+
+ for( i = 1; i < count; i++ )
{
- switch( i )
+ if( i == 1 )
{
- case 0:
- if( es->time <= 0 )
- continue;
-
- source = &cg_entities[ es->misc ];
- target = &cg_entities[ es->time ];
- break;
-
- case 1:
- if( es->time2 <= 0 )
- continue;
-
- source = &cg_entities[ es->time ];
- target = &cg_entities[ es->time2 ];
- break;
-
- case 2:
- if( es->constantLight <= 0 )
- continue;
-
- source = &cg_entities[ es->time2 ];
- target = &cg_entities[ es->constantLight ];
- break;
+ // First entity is the attacker
+ source = &cg_entities[ entityNums[ 0 ] ];
+ }
+ else
+ {
+ // Subsequent zaps come from the first target
+ source = &cg_entities[ entityNums[ 1 ] ];
}
+ target = &cg_entities[ entityNums[ i ] ];
+
if( !CG_IsTrailSystemValid( &cent->level2ZapTS[ i ] ) )
cent->level2ZapTS[ i ] = CG_SpawnNewTrailSystem( cgs.media.level2ZapTS );
@@ -844,7 +966,7 @@ void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int
{
centity_t *cent;
vec3_t oldOrigin, origin, deltaOrigin;
- vec3_t oldAngles, angles, deltaAngles;
+ vec3_t oldAngles, angles;
if( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL )
{
@@ -867,7 +989,6 @@ void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int
BG_EvaluateTrajectory( &cent->currentState.apos, toTime, angles );
VectorSubtract( origin, oldOrigin, deltaOrigin );
- VectorSubtract( angles, oldAngles, deltaAngles );
VectorAdd( in, deltaOrigin, out );
@@ -947,9 +1068,10 @@ static void CG_CalcEntityLerpPositions( centity_t *cent )
return;
}
- if( cg_projectileNudge.integer > 0 &&
- cent->currentState.eType == ET_MISSILE &&
- !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
+ if( cg_projectileNudge.integer &&
+ !cg.demoPlayback &&
+ cent->currentState.eType == ET_MISSILE &&
+ !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
{
timeshift = cg.ping;
}
@@ -972,7 +1094,7 @@ static void CG_CalcEntityLerpPositions( centity_t *cent )
// don't let the projectile go through the floor
if( tr.fraction < 1.0f )
- VectorLerp( tr.fraction, lastOrigin, cent->lerpOrigin, cent->lerpOrigin );
+ VectorLerp2( tr.fraction, lastOrigin, cent->lerpOrigin, cent->lerpOrigin );
}
// adjust for riding a mover if it wasn't rolled into the predicted
@@ -984,7 +1106,6 @@ static void CG_CalcEntityLerpPositions( centity_t *cent )
}
}
-
/*
===============
CG_CEntityPVSEnter
@@ -1003,6 +1124,10 @@ static void CG_CEntityPVSEnter( centity_t *cent )
case ET_MISSILE:
CG_LaunchMissile( cent );
break;
+
+ case ET_BUILDABLE:
+ cent->lastBuildableHealth = es->misc;
+ break;
}
//clear any particle systems from previous uses of this centity_t
@@ -1034,11 +1159,10 @@ static void CG_CEntityPVSLeave( centity_t *cent )
if( cg_debugPVS.integer )
CG_Printf( "Entity %d left PVS\n", cent->currentState.number );
-
switch( es->eType )
{
case ET_LEV2_ZAP_CHAIN:
- for( i = 0; i <= 2; i++ )
+ for( i = 0; i <= LEVEL2_AREAZAP_MAX_TARGETS; i++ )
{
if( CG_IsTrailSystemValid( &cent->level2ZapTS[ i ] ) )
CG_DestroyTrailSystem( &cent->level2ZapTS[ i ] );
@@ -1069,18 +1193,23 @@ static void CG_AddCEntity( centity_t *cent )
switch( cent->currentState.eType )
{
default:
- CG_Error( "Bad entity type: %i\n", cent->currentState.eType );
+ CG_Error( "Bad entity type: %i", cent->currentState.eType );
break;
case ET_INVISIBLE:
case ET_PUSH_TRIGGER:
case ET_TELEPORT_TRIGGER:
+ case ET_LOCATION:
break;
case ET_GENERAL:
CG_General( cent );
break;
+ case ET_WEAPON_DROP:
+ CG_WeaponDrop( cent );
+ break;
+
case ET_CORPSE:
CG_Corpse( cent );
break;
@@ -1093,6 +1222,10 @@ static void CG_AddCEntity( centity_t *cent )
CG_Buildable( cent );
break;
+ case ET_RANGE_MARKER:
+ CG_RangeMarker( cent );
+ break;
+
case ET_MISSILE:
CG_Missile( cent );
break;
@@ -1253,4 +1386,3 @@ void CG_AddPacketEntities( void )
}
}
}
-
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c
index 07bcea9..3ed0ac9 100644
--- a/src/cgame/cg_event.c
+++ b/src/cgame/cg_event.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,17 +17,130 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_event.c -- handle entity events at snapshot or playerstate transitions
-
#include "cg_local.h"
/*
+=======================
+CG_AddToKillMsg
+
+=======================
+*/
+void CG_AddToKillMsg( const char* killername, const char* victimname, int icon )
+{
+ int klen, vlen, index;
+ char *kls, *vls;
+ char *k, *v;
+ int lastcolor;
+ int chatHeight;
+
+ if( cg_killMsgHeight.integer < TEAMCHAT_HEIGHT )
+ chatHeight = cg_killMsgHeight.integer;
+ else
+ chatHeight = TEAMCHAT_HEIGHT;
+
+ if( chatHeight <= 0 || cg_killMsgTime.integer <= 0 ) {
+ cgs.killMsgPos = cgs.killMsgLastPos = 0;
+ return;
+ }
+
+ index = cgs.killMsgPos % chatHeight;
+ klen = vlen = 0;
+
+ k = cgs.killMsgKillers[ index ]; *k=0;
+ v = cgs.killMsgVictims[ index ]; *v=0;
+ cgs.killMsgWeapons[ index ] = icon;
+
+ memset( k, '\0', sizeof(cgs.killMsgKillers[index]));
+ memset( v, '\0', sizeof(cgs.killMsgVictims[index]));
+ kls = vls = NULL;
+
+ lastcolor = '7';
+
+ // Killers name
+ while( *killername )
+ {
+ if( klen > TEAMCHAT_WIDTH-1 ) {
+ if( kls ) {
+ killername -= ( k - kls );
+ killername ++;
+ k -= ( k - kls );
+ }
+ *k = 0;
+
+// cgs.killMsgMsgTimes[index] = cg.time;
+ k = cgs.killMsgKillers[index];
+ *k = 0;
+ *k++ = Q_COLOR_ESCAPE;
+ *k++ = lastcolor;
+ klen = 0;
+ kls = NULL;
+ }
+
+ if( Q_IsColorString( killername ) )
+ {
+ *k++ = *killername++;
+ lastcolor = *killername;
+ *k++ = *killername++;
+ continue;
+ }
+
+ if( *killername == ' ' )
+ kls = k;
+
+ *k++ = *killername++;
+ klen++;
+ }
+
+ // Victims name
+ if (victimname)
+ while( *victimname )
+ {
+ if( vlen > TEAMCHAT_WIDTH-1 ) {
+ if( vls ) {
+ victimname -= ( v - vls );
+ victimname ++;
+ v -= ( v - vls );
+ }
+ *v = 0;
+
+ v = cgs.killMsgVictims[index];
+ *v = 0;
+ *v++ = Q_COLOR_ESCAPE;
+ *v++ = lastcolor;
+ vlen = 0;
+ vls = NULL;
+ }
+
+ if( Q_IsColorString( victimname ) )
+ {
+ *v++ = *victimname++;
+ lastcolor = *victimname;
+ *v++ = *victimname++;
+ continue;
+ }
+
+ if( *victimname == ' ' )
+ vls = v;
+
+ *v++ = *victimname++;
+ vlen++;
+ }
+
+ cgs.killMsgMsgTimes[ index ] = cg.time;
+ cgs.killMsgPos++;
+
+ if( cgs.killMsgPos - cgs.killMsgLastPos > chatHeight )
+ cgs.killMsgLastPos = cgs.killMsgPos - chatHeight;
+}
+
+/*
=============
CG_Obituary
=============
@@ -39,12 +153,13 @@ static void CG_Obituary( entityState_t *ent )
char *message2;
const char *targetInfo;
const char *attackerInfo;
- char targetName[ 32 ];
- char attackerName[ 32 ];
+ char targetName[ MAX_NAME_LENGTH ];
+ char attackerName[ MAX_NAME_LENGTH ];
char className[ 64 ];
gender_t gender;
clientInfo_t *ci;
qboolean teamKill = qfalse;
+ int icon = WP_NONE;
target = ent->otherEntityNum;
attacker = ent->otherEntityNum2;
@@ -54,6 +169,7 @@ static void CG_Obituary( entityState_t *ent )
CG_Error( "CG_Obituary: target out of range" );
ci = &cgs.clientinfo[ target ];
+ gender = ci->gender;
if( attacker < 0 || attacker >= MAX_CLIENTS )
{
@@ -72,8 +188,7 @@ static void CG_Obituary( entityState_t *ent )
if( !targetInfo )
return;
- Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof( targetName ) - 2 );
- strcat( targetName, S_COLOR_WHITE );
+ Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof( targetName ));
message2 = "";
@@ -81,9 +196,6 @@ static void CG_Obituary( entityState_t *ent )
switch( mod )
{
- case MOD_SUICIDE:
- message = "suicides";
- break;
case MOD_FALLING:
message = "fell fowl to gravity";
break;
@@ -97,7 +209,7 @@ static void CG_Obituary( entityState_t *ent )
message = "melted";
break;
case MOD_LAVA:
- message = "does a back flip into the lava";
+ message = "did a back flip into the lava";
break;
case MOD_TARGET_LASER:
message = "saw the light";
@@ -137,9 +249,8 @@ static void CG_Obituary( entityState_t *ent )
break;
}
- if( attacker == target )
+ if( !message && attacker == target )
{
- gender = ci->gender;
switch( mod )
{
case MOD_FLAMER_SPLASH:
@@ -169,6 +280,24 @@ static void CG_Obituary( entityState_t *ent )
message = "blew himself up";
break;
+ case MOD_LEVEL3_BOUNCEBALL:
+ if( gender == GENDER_FEMALE )
+ message = "sniped herself";
+ else if( gender == GENDER_NEUTER )
+ message = "sniped itself";
+ else
+ message = "sniped himself";
+ break;
+
+ case MOD_PRIFLE:
+ if( gender == GENDER_FEMALE )
+ message = "pulse rifled herself";
+ else if( gender == GENDER_NEUTER )
+ message = "pulse rifled itself";
+ else
+ message = "pulse rifled himself";
+ break;
+
default:
if( gender == GENDER_FEMALE )
message = "killed herself";
@@ -178,12 +307,12 @@ static void CG_Obituary( entityState_t *ent )
message = "killed himself";
break;
}
- }
- if( message )
- {
- CG_Printf( "%s %s.\n", targetName, message );
- return;
+ if ( cg_killMsg.integer == 2)
+ {
+ CG_AddToKillMsg(va("%s ^7%s", targetName, message), NULL, WP_NONE);
+ return;
+ }
}
// check for double client messages
@@ -194,8 +323,7 @@ static void CG_Obituary( entityState_t *ent )
}
else
{
- Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof( attackerName ) - 2);
- strcat( attackerName, S_COLOR_WHITE );
+ Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof( attackerName ));
// check for kill messages about the current clientNum
if( target == cg.snap->ps.clientNum )
Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
@@ -205,119 +333,141 @@ static void CG_Obituary( entityState_t *ent )
{
switch( mod )
{
+ //
+ // HUMANS
+ //
case MOD_PAINSAW:
+ icon = WP_PAIN_SAW;
message = "was sawn by";
break;
case MOD_BLASTER:
+ icon = WP_BLASTER;
message = "was blasted by";
break;
case MOD_MACHINEGUN:
+ icon = WP_MACHINEGUN;
message = "was machinegunned by";
break;
case MOD_CHAINGUN:
+ icon = WP_CHAINGUN;
message = "was chaingunned by";
break;
case MOD_SHOTGUN:
+ icon = WP_SHOTGUN;
message = "was gunned down by";
break;
case MOD_PRIFLE:
+ icon = WP_PULSE_RIFLE;
message = "was pulse rifled by";
break;
case MOD_MDRIVER:
+ icon = WP_MASS_DRIVER;
message = "was mass driven by";
break;
case MOD_LASGUN:
+ icon = WP_LAS_GUN;
message = "was lasgunned by";
break;
case MOD_FLAMER:
- message = "was grilled by";
- message2 = "'s flamer";
- break;
case MOD_FLAMER_SPLASH:
- message = "was toasted by";
+ icon = WP_FLAMER;
+ message = "was grilled by";
message2 = "'s flamer";
break;
case MOD_LCANNON:
+ icon = WP_LUCIFER_CANNON;
message = "felt the full force of";
message2 = "'s lucifer cannon";
break;
case MOD_LCANNON_SPLASH:
+ icon = WP_LUCIFER_CANNON;
message = "was caught in the fallout of";
message2 = "'s lucifer cannon";
break;
case MOD_GRENADE:
+ icon = WP_GRENADE;
message = "couldn't escape";
message2 = "'s grenade";
break;
+ //
+ // ALIENS
+ //
case MOD_ABUILDER_CLAW:
+ icon = WP_ABUILD;
message = "should leave";
message2 = "'s buildings alone";
break;
case MOD_LEVEL0_BITE:
+ icon = WP_ALEVEL0;
message = "was bitten by";
break;
case MOD_LEVEL1_CLAW:
+ icon = WP_ALEVEL1;
message = "was swiped by";
- Com_sprintf( className, 64, "'s %s",
- BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL1 ) );
+ Com_sprintf( className, 64, "'s %s", BG_ClassConfig( PCL_ALIEN_LEVEL1 )->humanName );
+ message2 = className;
+ break;
+ case MOD_LEVEL1_PCLOUD:
+ icon = WP_ALEVEL1;
+ message = "was gassed by";
+ Com_sprintf( className, 64, "'s %s", BG_ClassConfig( PCL_ALIEN_LEVEL1 )->humanName );
message2 = className;
break;
case MOD_LEVEL2_CLAW:
+ icon = WP_ALEVEL2;
message = "was clawed by";
- Com_sprintf( className, 64, "'s %s",
- BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL2 ) );
+ Com_sprintf( className, 64, "'s %s", BG_ClassConfig( PCL_ALIEN_LEVEL2 )->humanName );
message2 = className;
break;
case MOD_LEVEL2_ZAP:
+ icon = WP_ALEVEL2;
message = "was zapped by";
- Com_sprintf( className, 64, "'s %s",
- BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL2 ) );
+ Com_sprintf( className, 64, "'s %s", BG_ClassConfig( PCL_ALIEN_LEVEL2 )->humanName );
message2 = className;
break;
case MOD_LEVEL3_CLAW:
+ icon = WP_ALEVEL3;
message = "was chomped by";
- Com_sprintf( className, 64, "'s %s",
- BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL3 ) );
+ Com_sprintf( className, 64, "'s %s", BG_ClassConfig( PCL_ALIEN_LEVEL3 )->humanName );
message2 = className;
break;
case MOD_LEVEL3_POUNCE:
+ icon = WP_ALEVEL3;
message = "was pounced upon by";
- Com_sprintf( className, 64, "'s %s",
- BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL3 ) );
+ Com_sprintf( className, 64, "'s %s", BG_ClassConfig( PCL_ALIEN_LEVEL3 )->humanName );
message2 = className;
break;
case MOD_LEVEL3_BOUNCEBALL:
+ icon = WP_ALEVEL3;
message = "was sniped by";
- Com_sprintf( className, 64, "'s %s",
- BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL3 ) );
+ Com_sprintf( className, 64, "'s %s", BG_ClassConfig( PCL_ALIEN_LEVEL3 )->humanName );
message2 = className;
break;
case MOD_LEVEL4_CLAW:
+ icon = WP_ALEVEL4;
message = "was mauled by";
- Com_sprintf( className, 64, "'s %s",
- BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL4 ) );
+ Com_sprintf( className, 64, "'s %s", BG_ClassConfig( PCL_ALIEN_LEVEL4 )->humanName );
message2 = className;
break;
- case MOD_LEVEL4_CHARGE:
+ case MOD_LEVEL4_TRAMPLE:
+ icon = WP_ALEVEL4;
message = "should have gotten out of the way of";
- Com_sprintf( className, 64, "'s %s",
- BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL4 ) );
+ Com_sprintf( className, 64, "'s %s", BG_ClassConfig( PCL_ALIEN_LEVEL4 )->humanName );
message2 = className;
break;
-
+ case MOD_LEVEL4_CRUSH:
+ message = "was crushed under";
+ message2 = "'s weight";
+ break;
case MOD_POISON:
message = "should have used a medkit against";
message2 = "'s poison";
break;
- case MOD_LEVEL1_PCLOUD:
- message = "was gassed by";
- Com_sprintf( className, 64, "'s %s",
- BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL1 ) );
- message2 = className;
- break;
-
+ //
+ // MISC..
+ //
case MOD_TELEFRAG:
message = "tried to invade";
message2 = "'s personal space";
@@ -327,24 +477,55 @@ static void CG_Obituary( entityState_t *ent )
break;
}
- if( message )
+ if ( cg_killMsg.integer == 1)
{
- CG_Printf( "%s %s %s%s%s\n",
- targetName, message,
- ( teamKill ) ? S_COLOR_RED "TEAMMATE " S_COLOR_WHITE : "",
- attackerName, message2 );
- if( teamKill && attacker == cg.clientNum )
+ char killMessage[80];
+ if( icon > WP_NONE )
{
- CG_CenterPrint( va ( "You killed " S_COLOR_RED "TEAMMATE "
- S_COLOR_WHITE "%s", targetName ),
- SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
+ Com_sprintf(killMessage, sizeof(killMessage), "%s%s",
+ teamKill ? S_COLOR_RED"TEAMMATE "S_COLOR_WHITE:"",
+ targetName);
+ CG_AddToKillMsg(attackerName, killMessage, icon);
}
- return;
}
+ else if( message )
+ {
+ CG_Printf( "%s" S_COLOR_WHITE " %s %s%s" S_COLOR_WHITE "%s\n",
+ targetName,
+ message,
+ teamKill ? S_COLOR_RED "TEAMMATE " S_COLOR_WHITE : "",
+ attackerName,
+ message2 );
+ }
+
+ if( attacker == cg.clientNum )
+ {
+ CG_CenterPrint(va("You killed %s%s", teamKill ? S_COLOR_RED"TEAMMATE "S_COLOR_WHITE:"",
+ targetName), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
+ }
+ if ( cg_killMsg.integer != 1)
+ return;
+ }
+
+#if 0
+ switch (mod) {
+ case MOD_SLAP:
+ message = "was slapped to death";
+ break;
+ default:
+ break;
}
+#endif
// we don't know what it was
- CG_Printf( "%s died.\n", targetName );
+ if ( cg_killMsg.integer )
+ {
+ CG_AddToKillMsg(va("%s ^7%s", targetName, message), NULL, WP_NONE);
+ }
+ else
+ {
+ CG_Printf( "%s" S_COLOR_WHITE " %s\n", targetName, message );
+ }
}
//==========================================================================
@@ -382,6 +563,60 @@ void CG_PainEvent( centity_t *cent, int health )
}
/*
+=========================
+CG_Level2Zap
+=========================
+*/
+static void CG_Level2Zap( entityState_t *es )
+{
+ int i;
+ centity_t *source = NULL, *target = NULL;
+
+ if( es->misc < 0 || es->misc >= MAX_CLIENTS )
+ return;
+
+ source = &cg_entities[ es->misc ];
+ for( i = 0; i <= 2; i++ )
+ {
+ switch( i )
+ {
+ case 0:
+ if( es->time <= 0 )
+ continue;
+
+ target = &cg_entities[ es->time ];
+ break;
+
+ case 1:
+ if( es->time2 <= 0 )
+ continue;
+
+ target = &cg_entities[ es->time2 ];
+ break;
+
+ case 2:
+ if( es->constantLight <= 0 )
+ continue;
+
+ target = &cg_entities[ es->constantLight ];
+ break;
+ }
+
+ if( !CG_IsTrailSystemValid( &source->level2ZapTS[ i ] ) )
+ source->level2ZapTS[ i ] = CG_SpawnNewTrailSystem( cgs.media.level2ZapTS );
+
+ if( CG_IsTrailSystemValid( &source->level2ZapTS[ i ] ) )
+ {
+ CG_SetAttachmentCent( &source->level2ZapTS[ i ]->frontAttachment, source );
+ CG_SetAttachmentCent( &source->level2ZapTS[ i ]->backAttachment, target );
+ CG_AttachToCent( &source->level2ZapTS[ i ]->frontAttachment );
+ CG_AttachToCent( &source->level2ZapTS[ i ]->backAttachment );
+ }
+ }
+ source->level2ZapTime = cg.time;
+}
+
+/*
==============
CG_EntityEvent
@@ -389,7 +624,6 @@ An entity has an event value
also called by CG_CheckPlayerstateEvents
==============
*/
-#define DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");}
void CG_EntityEvent( centity_t *cent, vec3_t position )
{
entityState_t *es;
@@ -400,22 +634,20 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
clientInfo_t *ci;
int steptime;
- if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
+ if( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
steptime = 200;
else
- steptime = BG_FindSteptimeForClass( cg.snap->ps.stats[ STAT_PCLASS ] );
+ steptime = BG_Class( cg.snap->ps.stats[ STAT_CLASS ] )->steptime;
es = &cent->currentState;
event = es->event & ~EV_EVENT_BITS;
if( cg_debugEvents.integer )
- CG_Printf( "ent:%3i event:%3i ", es->number, event );
+ CG_Printf( "ent:%3i event:%3i %s\n", es->number, event,
+ BG_EventName( event ) );
if( !event )
- {
- DEBUGNAME("ZEROEVENT");
return;
- }
clientNum = es->clientNum;
if( clientNum < 0 || clientNum >= MAX_CLIENTS )
@@ -429,7 +661,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
// movement generated events
//
case EV_FOOTSTEP:
- DEBUGNAME( "EV_FOOTSTEP" );
if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
{
if( ci->footsteps == FOOTSTEP_CUSTOM )
@@ -442,7 +673,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_FOOTSTEP_METAL:
- DEBUGNAME( "EV_FOOTSTEP_METAL" );
if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
{
if( ci->footsteps == FOOTSTEP_CUSTOM )
@@ -455,7 +685,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_FOOTSTEP_SQUELCH:
- DEBUGNAME( "EV_FOOTSTEP_SQUELCH" );
if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
{
trap_S_StartSound( NULL, es->number, CHAN_BODY,
@@ -464,7 +693,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_FOOTSPLASH:
- DEBUGNAME( "EV_FOOTSPLASH" );
if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
{
trap_S_StartSound( NULL, es->number, CHAN_BODY,
@@ -473,7 +701,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_FOOTWADE:
- DEBUGNAME( "EV_FOOTWADE" );
if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
{
trap_S_StartSound( NULL, es->number, CHAN_BODY,
@@ -482,7 +709,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_SWIM:
- DEBUGNAME( "EV_SWIM" );
if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
{
trap_S_StartSound( NULL, es->number, CHAN_BODY,
@@ -492,45 +718,41 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
case EV_FALL_SHORT:
- DEBUGNAME( "EV_FALL_SHORT" );
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound );
if( clientNum == cg.predictedPlayerState.clientNum )
{
// smooth landing z changes
- cg.landChange = -8;
+ cg.landChange = -1 * BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->landBob;
cg.landTime = cg.time;
}
break;
case EV_FALL_MEDIUM:
- DEBUGNAME( "EV_FALL_MEDIUM" );
// use normal pain sound
trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) );
if( clientNum == cg.predictedPlayerState.clientNum )
{
// smooth landing z changes
- cg.landChange = -16;
+ cg.landChange = -2 * BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->landBob;
cg.landTime = cg.time;
}
break;
case EV_FALL_FAR:
- DEBUGNAME( "EV_FALL_FAR" );
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) );
+ trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) );
cent->pe.painTime = cg.time; // don't play a pain sound right after this
if( clientNum == cg.predictedPlayerState.clientNum )
{
// smooth landing z changes
- cg.landChange = -24;
+ cg.landChange = -3 * BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->landBob;
cg.landTime = cg.time;
}
break;
case EV_FALLING:
- DEBUGNAME( "EV_FALLING" );
trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*falling1.wav" ) );
break;
@@ -542,7 +764,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
case EV_STEPDN_8:
case EV_STEPDN_12:
case EV_STEPDN_16: // smooth out step down transitions
- DEBUGNAME( "EV_STEP" );
{
float oldStep;
int delta;
@@ -586,10 +807,9 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
}
case EV_JUMP:
- DEBUGNAME( "EV_JUMP" );
trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
- if( BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
+ if( BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_CLASS ], SCA_WALLJUMPER ) )
{
vec3_t surfNormal, refNormal = { 0.0f, 0.0f, 1.0f };
vec3_t rotAxis;
@@ -617,44 +837,36 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_LEV1_GRAB:
- DEBUGNAME( "EV_LEV1_GRAB" );
trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL1Grab );
break;
- case EV_LEV4_CHARGE_PREPARE:
- DEBUGNAME( "EV_LEV4_CHARGE_PREPARE" );
+ case EV_LEV4_TRAMPLE_PREPARE:
trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargePrepare );
break;
- case EV_LEV4_CHARGE_START:
- DEBUGNAME( "EV_LEV4_CHARGE_START" );
+ case EV_LEV4_TRAMPLE_START:
//FIXME: stop cgs.media.alienL4ChargePrepare playing here
trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargeStart );
break;
case EV_TAUNT:
- DEBUGNAME( "EV_TAUNT" );
if( !cg_noTaunt.integer )
trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
break;
case EV_WATER_TOUCH:
- DEBUGNAME( "EV_WATER_TOUCH" );
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
break;
case EV_WATER_LEAVE:
- DEBUGNAME( "EV_WATER_LEAVE" );
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
break;
case EV_WATER_UNDER:
- DEBUGNAME( "EV_WATER_UNDER" );
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
break;
case EV_WATER_CLEAR:
- DEBUGNAME( "EV_WATER_CLEAR" );
trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
break;
@@ -662,28 +874,23 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
// weapon events
//
case EV_NOAMMO:
- DEBUGNAME( "EV_NOAMMO" );
- {
- }
+ trap_S_StartSound( NULL, es->number, CHAN_WEAPON,
+ cgs.media.weaponEmptyClick );
break;
case EV_CHANGE_WEAPON:
- DEBUGNAME( "EV_CHANGE_WEAPON" );
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
break;
case EV_FIRE_WEAPON:
- DEBUGNAME( "EV_FIRE_WEAPON" );
CG_FireWeapon( cent, WPM_PRIMARY );
break;
case EV_FIRE_WEAPON2:
- DEBUGNAME( "EV_FIRE_WEAPON2" );
CG_FireWeapon( cent, WPM_SECONDARY );
break;
case EV_FIRE_WEAPON3:
- DEBUGNAME( "EV_FIRE_WEAPON3" );
CG_FireWeapon( cent, WPM_TERTIARY );
break;
@@ -693,32 +900,26 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
// other events
//
case EV_PLAYER_TELEPORT_IN:
- DEBUGNAME( "EV_PLAYER_TELEPORT_IN" );
//deprecated
break;
case EV_PLAYER_TELEPORT_OUT:
- DEBUGNAME( "EV_PLAYER_TELEPORT_OUT" );
CG_PlayerDisconnect( position );
break;
case EV_BUILD_CONSTRUCT:
- DEBUGNAME( "EV_BUILD_CONSTRUCT" );
//do something useful here
break;
case EV_BUILD_DESTROY:
- DEBUGNAME( "EV_BUILD_DESTROY" );
//do something useful here
break;
case EV_RPTUSE_SOUND:
- DEBUGNAME( "EV_RPTUSE_SOUND" );
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.repeaterUseSound );
break;
case EV_GRENADE_BOUNCE:
- DEBUGNAME( "EV_GRENADE_BOUNCE" );
if( rand( ) & 1 )
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.hardBounceSound1 );
else
@@ -729,40 +930,34 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
// missile impacts
//
case EV_MISSILE_HIT:
- DEBUGNAME( "EV_MISSILE_HIT" );
ByteToDir( es->eventParm, dir );
- CG_MissileHitPlayer( es->weapon, es->generic1, position, dir, es->otherEntityNum );
+ CG_MissileHitEntity( es->weapon, es->generic1, position, dir, es->otherEntityNum, es->torsoAnim );
break;
case EV_MISSILE_MISS:
- DEBUGNAME( "EV_MISSILE_MISS" );
ByteToDir( es->eventParm, dir );
- CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_DEFAULT );
+ CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_DEFAULT, es->torsoAnim );
break;
case EV_MISSILE_MISS_METAL:
- DEBUGNAME( "EV_MISSILE_MISS_METAL" );
ByteToDir( es->eventParm, dir );
- CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_METAL );
+ CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_METAL, es->torsoAnim );
break;
case EV_HUMAN_BUILDABLE_EXPLOSION:
- DEBUGNAME( "EV_HUMAN_BUILDABLE_EXPLOSION" );
ByteToDir( es->eventParm, dir );
CG_HumanBuildableExplosion( position, dir );
break;
case EV_ALIEN_BUILDABLE_EXPLOSION:
- DEBUGNAME( "EV_ALIEN_BUILDABLE_EXPLOSION" );
ByteToDir( es->eventParm, dir );
CG_AlienBuildableExplosion( position, dir );
break;
case EV_TESLATRAIL:
- DEBUGNAME( "EV_TESLATRAIL" );
cent->currentState.weapon = WP_TESLAGEN;
{
- centity_t *source = &cg_entities[ es->generic1 ];
+ centity_t *source = &cg_entities[ es->misc ];
centity_t *target = &cg_entities[ es->clientNum ];
vec3_t sourceOffset = { 0.0f, 0.0f, 28.0f };
@@ -785,23 +980,19 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_BULLET_HIT_WALL:
- DEBUGNAME( "EV_BULLET_HIT_WALL" );
ByteToDir( es->eventParm, dir );
CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );
break;
case EV_BULLET_HIT_FLESH:
- DEBUGNAME( "EV_BULLET_HIT_FLESH" );
CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
break;
case EV_SHOTGUN:
- DEBUGNAME( "EV_SHOTGUN" );
CG_ShotgunFire( es );
break;
case EV_GENERAL_SOUND:
- DEBUGNAME( "EV_GENERAL_SOUND" );
if( cgs.gameSounds[ es->eventParm ] )
trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );
else
@@ -812,7 +1003,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes
- DEBUGNAME( "EV_GLOBAL_SOUND" );
if( cgs.gameSounds[ es->eventParm ] )
trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
else
@@ -825,7 +1015,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
case EV_PAIN:
// local player sounds are triggered in CG_CheckLocalSounds,
// so ignore events on the player
- DEBUGNAME( "EV_PAIN" );
if( cent->currentState.number != cg.snap->ps.clientNum )
CG_PainEvent( cent, es->eventParm );
break;
@@ -833,34 +1022,28 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
case EV_DEATH1:
case EV_DEATH2:
case EV_DEATH3:
- DEBUGNAME( "EV_DEATHx" );
trap_S_StartSound( NULL, es->number, CHAN_VOICE,
CG_CustomSound( es->number, va( "*death%i.wav", event - EV_DEATH1 + 1 ) ) );
break;
case EV_OBITUARY:
- DEBUGNAME( "EV_OBITUARY" );
CG_Obituary( es );
break;
case EV_GIB_PLAYER:
- DEBUGNAME( "EV_GIB_PLAYER" );
// no gibbing
break;
case EV_STOPLOOPINGSOUND:
- DEBUGNAME( "EV_STOPLOOPINGSOUND" );
trap_S_StopLoopingSound( es->number );
es->loopSound = 0;
break;
case EV_DEBUG_LINE:
- DEBUGNAME( "EV_DEBUG_LINE" );
CG_Beam( cent );
break;
case EV_BUILD_DELAY:
- DEBUGNAME( "EV_BUILD_DELAY" );
if( clientNum == cg.predictedPlayerState.clientNum )
{
trap_S_StartLocalSound( cgs.media.buildableRepairedSound, CHAN_LOCAL_SOUND );
@@ -869,18 +1052,15 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_BUILD_REPAIR:
- DEBUGNAME( "EV_BUILD_REPAIR" );
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairSound );
break;
case EV_BUILD_REPAIRED:
- DEBUGNAME( "EV_BUILD_REPAIRED" );
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairedSound );
break;
case EV_OVERMIND_ATTACK:
- DEBUGNAME( "EV_OVERMIND_ATTACK" );
- if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
trap_S_StartLocalSound( cgs.media.alienOvermindAttack, CHAN_ANNOUNCER );
CG_CenterPrint( "The Overmind is under attack!", 200, GIANTCHAR_WIDTH * 4 );
@@ -888,8 +1068,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_OVERMIND_DYING:
- DEBUGNAME( "EV_OVERMIND_DYING" );
- if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
trap_S_StartLocalSound( cgs.media.alienOvermindDying, CHAN_ANNOUNCER );
CG_CenterPrint( "The Overmind is dying!", 200, GIANTCHAR_WIDTH * 4 );
@@ -897,17 +1076,19 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_DCC_ATTACK:
- DEBUGNAME( "EV_DCC_ATTACK" );
- if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
//trap_S_StartLocalSound( cgs.media.humanDCCAttack, CHAN_ANNOUNCER );
CG_CenterPrint( "Our base is under attack!", 200, GIANTCHAR_WIDTH * 4 );
}
break;
+ case EV_MGTURRET_SPINUP:
+ trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.turretSpinupSound );
+ break;
+
case EV_OVERMIND_SPAWNS:
- DEBUGNAME( "EV_OVERMIND_SPAWNS" );
- if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
trap_S_StartLocalSound( cgs.media.alienOvermindSpawns, CHAN_ANNOUNCER );
CG_CenterPrint( "The Overmind needs spawns!", 200, GIANTCHAR_WIDTH * 4 );
@@ -915,7 +1096,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_ALIEN_EVOLVE:
- DEBUGNAME( "EV_ALIEN_EVOLVE" );
trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienEvolveSound );
{
particleSystem_t *ps = CG_SpawnNewParticleSystem( cgs.media.alienEvolvePS );
@@ -935,7 +1115,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_ALIEN_EVOLVE_FAILED:
- DEBUGNAME( "EV_ALIEN_EVOLVE_FAILED" );
if( clientNum == cg.predictedPlayerState.clientNum )
{
//FIXME: change to "negative" sound
@@ -945,7 +1124,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_ALIEN_ACIDTUBE:
- DEBUGNAME( "EV_ALIEN_ACIDTUBE" );
{
particleSystem_t *ps = CG_SpawnNewParticleSystem( cgs.media.alienAcidTubePS );
@@ -960,18 +1138,19 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_MEDKIT_USED:
- DEBUGNAME( "EV_MEDKIT_USED" );
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.medkitUseSound );
break;
case EV_PLAYER_RESPAWN:
- DEBUGNAME( "EV_PLAYER_RESPAWN" );
if( es->number == cg.clientNum )
cg.spawnTime = cg.time;
break;
+ case EV_LEV2_ZAP:
+ CG_Level2Zap( es );
+ break;
+
default:
- DEBUGNAME( "UNKNOWN" );
CG_Error( "Unknown event: %i", event );
break;
}
@@ -1031,4 +1210,3 @@ void CG_CheckEvents( centity_t *cent )
if( oldEvent != EV_NONE )
cent->currentState.event = oldEvent;
}
-
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index ea1694b..ecdf02d 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,17 +17,18 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
-#include "../qcommon/q_shared.h"
-#include "../renderer/tr_types.h"
-#include "../game/bg_public.h"
+#include "qcommon/q_shared.h"
+#include "renderercommon/tr_types.h"
+#include "game/bg_public.h"
#include "cg_public.h"
-#include "../ui/ui_shared.h"
+#include "binaryshader.h"
+#include "ui/ui_shared.h"
// The entire cgame module is unloaded and reloaded on each level change,
// so there is NO persistant data between levels on the client side.
@@ -70,6 +72,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define CHAR_HEIGHT 48
#define TEXT_ICON_SPACE 4
+#define TEAMCHAT_WIDTH 80
+#define TEAMCHAT_HEIGHT 8
+
// very large characters
#define GIANT_WIDTH 32
#define GIANT_HEIGHT 48
@@ -79,10 +84,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define TEAM_OVERLAY_MAXNAME_WIDTH 12
#define TEAM_OVERLAY_MAXLOCATION_WIDTH 16
-#define DEFAULT_MODEL "sarge"
-#define DEFAULT_TEAM_MODEL "sarge"
-#define DEFAULT_TEAM_HEAD "sarge"
-
typedef enum
{
FOOTSTEP_NORMAL,
@@ -207,7 +208,9 @@ typedef enum
PMT_STATIC_TRANSFORM,
PMT_TAG,
PMT_CENT_ANGLES,
- PMT_NORMAL
+ PMT_NORMAL,
+ PMT_LAST_NORMAL,
+ PMT_OPPORTUNISTIC_NORMAL
} pMoveType_t;
typedef enum
@@ -253,7 +256,7 @@ typedef struct pLerpValues_s
typedef struct baseParticle_s
{
vec3_t displacement;
- float randDisplacement;
+ vec3_t randDisplacement;
float normalDisplacement;
pMoveType_t velMoveType;
@@ -282,6 +285,7 @@ typedef struct baseParticle_s
float bounceSoundCountRandFrac;
pLerpValues_t radius;
+ int physicsRadius;
pLerpValues_t alpha;
pLerpValues_t rotation;
@@ -317,6 +321,8 @@ typedef struct baseParticle_s
qboolean overdrawProtection;
qboolean realLight;
qboolean cullOnStartSolid;
+
+ float scaleWithCharge;
} baseParticle_t;
@@ -358,6 +364,11 @@ typedef struct particleSystem_s
//for PMT_NORMAL
qboolean normalValid;
vec3_t normal;
+ //for PMT_LAST_NORMAL and PMT_OPPORTUNISTIC_NORMAL
+ qboolean lastNormalIsCurrent;
+ vec3_t lastNormal;
+
+ int charge;
} particleSystem_t;
@@ -383,6 +394,8 @@ typedef struct particle_s
baseParticle_t *class;
particleEjector_t *parent;
+ particleSystem_t *childParticleSystem;
+
int birthTime;
int lifeTime;
@@ -463,7 +476,7 @@ typedef struct baseTrailBeam_s
// the time it takes for a beam to fade out (double attached only)
int fadeOutTime;
-
+
char shaderName[ MAX_QPATH ];
qhandle_t shader;
@@ -492,6 +505,7 @@ typedef struct baseTrailSystem_s
baseTrailBeam_t *beams[ MAX_BEAMS_PER_SYSTEM ];
int numBeams;
+ int lifeTime;
qboolean thirdPersonOnly;
qboolean registered; //whether or not the assets for this trail have been loaded
} baseTrailSystem_t;
@@ -503,6 +517,7 @@ typedef struct trailSystem_s
attachment_t frontAttachment;
attachment_t backAttachment;
+ int birthTime;
int destroyTime;
qboolean valid;
} trailSystem_t;
@@ -551,7 +566,7 @@ typedef struct trailBeam_s
// because corpses after respawn are outside the normal
// client numbering range
-//TA: smoothing of view and model for WW transitions
+// smoothing of view and model for WW transitions
#define MAXSMOOTHS 32
typedef struct
@@ -566,7 +581,7 @@ typedef struct
typedef struct
{
- lerpFrame_t legs, torso, flag, nonseg;
+ lerpFrame_t legs, torso, nonseg, weapon;
int painTime;
int painDirection; // flip from 0 to 1
@@ -594,6 +609,16 @@ typedef struct buildableStatus_s
qboolean visible; // Status is visble?
} buildableStatus_t;
+typedef struct buildableCache_s
+{
+ vec3_t cachedOrigin; // If any of the values differ from their
+ vec3_t cachedAngles; // cached versions, then the cache is invalid
+ vec3_t cachedNormal;
+ buildable_t cachedType;
+ vec3_t axis[ 3 ];
+ vec3_t origin;
+} buildableCache_t;
+
//=================================================
// centity_t have a direct corespondence with gentity_t in the game, but
@@ -634,12 +659,13 @@ typedef struct centity_s
lerpFrame_t lerpFrame;
- //TA:
buildableAnimNumber_t buildableAnim; //persistant anim number
buildableAnimNumber_t oldBuildableAnim; //to detect when new anims are set
+ qboolean buildableIdleAnim; //to check if new idle anim
particleSystem_t *buildablePS;
buildableStatus_t buildableStatus;
- float lastBuildableHealthScale;
+ buildableCache_t buildableCache; // so we don't recalculate things
+ float lastBuildableHealth;
int lastBuildableDamageSoundTime;
lightFlareStatus_t lfs;
@@ -656,16 +682,20 @@ typedef struct centity_s
particleSystem_t *jetPackPS;
jetPackState_t jetPackState;
+ particleSystem_t *poisonCloudedPS;
+
particleSystem_t *entityPS;
qboolean entityPSMissing;
- trailSystem_t *level2ZapTS[ 3 ];
+ trailSystem_t *level2ZapTS[ LEVEL2_AREAZAP_MAX_TARGETS ];
+ int level2ZapTime;
trailSystem_t *muzzleTS; //used for the tesla and reactor
int muzzleTSDeathTime;
qboolean valid;
- qboolean oldValid;
+ qboolean oldValid;
+ struct centity_s *nextLocation;
} centity_t;
@@ -706,41 +736,20 @@ typedef struct
{
qboolean infoValid;
- char name[ MAX_QPATH ];
- pTeam_t team;
-
- int botSkill; // 0 = not bot, 1-5 = bot
-
- vec3_t color1;
- vec3_t color2;
+ char name[ MAX_NAME_LENGTH ];
+ team_t team;
int score; // updated by score servercmds
int location; // location index for team mode
int health; // you only get this info about your teammates
- int armor;
- int curWeapon;
-
- int handicap;
- int wins, losses; // in tourney mode
-
- int teamTask; // task in teamplay (offence/defence)
- qboolean teamLeader; // true when this is a team leader
-
- int powerups; // so can display quad/flag status
-
- int medkitUsageTime;
- int invulnerabilityStartTime;
- int invulnerabilityStopTime;
-
- int breathPuffTime;
+ int upgrade;
+ int curWeaponClass; // sends current weapon for H, current class for A
// when clientinfo is changed, the loading of models/skins/sounds
// can be deferred until you are dead, to prevent hitches in
// gameplay
char modelName[ MAX_QPATH ];
char skinName[ MAX_QPATH ];
- char headModelName[ MAX_QPATH ];
- char headSkinName[ MAX_QPATH ];
qboolean newAnims; // true if using the new mission pack animations
qboolean fixedlegs; // true if legs yaw is always the same as torso yaw
@@ -771,6 +780,9 @@ typedef struct
sfxHandle_t customFootsteps[ 4 ];
sfxHandle_t customMetalFootsteps[ 4 ];
+
+ char voice[ MAX_VOICE_NAME_LEN ];
+ int voiceTime;
} clientInfo_t;
@@ -789,6 +801,7 @@ typedef struct weaponInfoMode_s
qboolean usesSpriteMissle;
qhandle_t missileSprite;
int missileSpriteSize;
+ float missileSpriteCharge;
qhandle_t missileParticleSystem;
qhandle_t missileTrailSystem;
qboolean missileRotates;
@@ -799,7 +812,6 @@ typedef struct weaponInfoMode_s
int missileAnimLooping;
sfxHandle_t firingSound;
- qboolean loopFireSound;
qhandle_t muzzleParticleSystem;
@@ -824,6 +836,13 @@ typedef struct weaponInfo_s
qhandle_t barrelModel;
qhandle_t flashModel;
+ qhandle_t weaponModel3rdPerson;
+ qhandle_t barrelModel3rdPerson;
+ qhandle_t flashModel3rdPerson;
+
+ animation_t animations[ MAX_WEAPON_ANIMATIONS ];
+ qboolean noDrift;
+
vec3_t weaponMidpoint; // so it will rotate centered instead of by tag
qhandle_t weaponIcon;
@@ -869,7 +888,6 @@ typedef struct
//======================================================================
-//TA:
typedef struct
{
vec3_t alienBuildablePos[ MAX_GENTITIES ];
@@ -906,6 +924,9 @@ typedef struct
#define NUM_SAVED_STATES ( CMD_BACKUP + 2 )
+// After this many msec the crosshair name fades out completely
+#define CROSSHAIR_CLIENT_TIMEOUT 1000
+
typedef struct
{
int clientFrame; // incremented each frame
@@ -1000,19 +1021,14 @@ typedef struct
int scoreFadeTime;
char killerName[ MAX_NAME_LENGTH ];
char spectatorList[ MAX_STRING_CHARS ]; // list of names
- int spectatorLen; // length of list
- float spectatorWidth; // width in device units
int spectatorTime; // next time to offset
- int spectatorPaintX; // current paint x
- int spectatorPaintX2; // current paint x
- int spectatorOffset; // current offset from start
- int spectatorPaintLen; // current offset from start
+ float spectatorOffset; // current offset from start
// centerprinting
int centerPrintTime;
int centerPrintCharWidth;
int centerPrintY;
- char centerPrint[ 1024 ];
+ char centerPrint[ MAX_STRING_CHARS ];
int centerPrintLines;
// low ammo warning state
@@ -1022,6 +1038,7 @@ typedef struct
int lastKillTime;
// crosshair client ID
+ int crosshairBuildable;
int crosshairClientNum;
int crosshairClientTime;
@@ -1031,7 +1048,6 @@ typedef struct
// attacking player
int attackerTime;
- int voiceTime;
// reward medals
int rewardStack;
@@ -1052,8 +1068,7 @@ typedef struct
int voiceChatBufferOut;
// warmup countdown
- int warmup;
- int warmupCount;
+ int warmupTime;
//==========================
@@ -1083,8 +1098,7 @@ typedef struct
float v_dmg_pitch;
float v_dmg_roll;
- vec3_t kick_angles; // weapon kicks
- vec3_t kick_origin;
+ qboolean chaseFollow;
// temp working variables for player view
float bobfracsin;
@@ -1099,25 +1113,25 @@ typedef struct
char testModelBarrelName[MAX_QPATH];
qboolean testGun;
- int spawnTime; //TA: fovwarp
- int weapon1Time; //TA: time when BUTTON_ATTACK went t->f f->t
- int weapon2Time; //TA: time when BUTTON_ATTACK2 went t->f f->t
- int weapon3Time; //TA: time when BUTTON_USE_HOLDABLE went t->f f->t
+ int spawnTime; // fovwarp
+ int weapon1Time; // time when BUTTON_ATTACK went t->f f->t
+ int weapon2Time; // time when BUTTON_ATTACK2 went t->f f->t
+ int weapon3Time; // time when BUTTON_USE_HOLDABLE went t->f f->t
qboolean weapon1Firing;
qboolean weapon2Firing;
qboolean weapon3Firing;
int poisonedTime;
- vec3_t lastNormal; //TA: view smoothage
- vec3_t lastVangles; //TA: view smoothage
- smooth_t sList[ MAXSMOOTHS ]; //TA: WW smoothing
+ vec3_t lastNormal; // view smoothage
+ vec3_t lastVangles; // view smoothage
+ smooth_t sList[ MAXSMOOTHS ]; // WW smoothing
- int forwardMoveTime; //TA: for struggling
+ int forwardMoveTime; // for struggling
int rightMoveTime;
int upMoveTime;
- float charModelFraction; //TA: loading percentages
+ float charModelFraction; // loading percentages
float mediaFraction;
float buildablesFraction;
@@ -1129,23 +1143,32 @@ typedef struct
int numConsoleLines;
particleSystem_t *poisonCloudPS;
+ particleSystem_t *poisonCloudedPS;
float painBlendValue;
float painBlendTarget;
+ float healBlendValue;
int lastHealth;
+ qboolean wasDeadLastFrame;
int lastPredictedCommand;
int lastServerTime;
playerState_t savedPmoveStates[ NUM_SAVED_STATES ];
int stateHead, stateTail;
int ping;
+
+ float chargeMeterAlpha;
+ float chargeMeterValue;
+ qhandle_t lastHealthCross;
+ float healthCrossFade;
+ int nearUsableBuildable;
+
+ int nextWeaponClickTime;
+ // binary shaders - by /dev/humancontroller
+ int numBinaryShadersUsed;
+ cgBinaryShaderSetting_t binaryShaderSettings[ NUM_BINARY_SHADERS ];
} cg_t;
-
-// all of the model, shader, and sound references that are
-// loaded at gamestate time are stored in cgMedia_t
-// Other media that can be tied to clients, weapons, or items are
-// stored in the clientInfo_t, itemInfo_t, weaponInfo_t, and powerupInfo_t
typedef struct
{
qhandle_t charsetShader;
@@ -1168,6 +1191,7 @@ typedef struct
qhandle_t scannerBlipShader;
qhandle_t scannerLineShader;
+ qhandle_t teamOverlayShader;
qhandle_t numberShaders[ 11 ];
@@ -1179,12 +1203,22 @@ typedef struct
qhandle_t redBuildShader;
qhandle_t humanSpawningShader;
+ // binary shaders + range markers
+ qhandle_t sphereModel;
+ qhandle_t sphericalCone64Model;
+ qhandle_t sphericalCone240Model;
+
+ qhandle_t plainColorShader;
+ qhandle_t binaryAlpha1Shader;
+ cgMediaBinaryShader_t binaryShaders[ NUM_BINARY_SHADERS ];
+
// disconnect
qhandle_t disconnectPS;
qhandle_t disconnectSound;
// sounds
sfxHandle_t tracerSound;
+ sfxHandle_t weaponEmptyClick;
sfxHandle_t selectSound;
sfxHandle_t footsteps[ FOOTSTEP_TOTAL ][ 4 ];
sfxHandle_t talkSound;
@@ -1192,6 +1226,7 @@ typedef struct
sfxHandle_t humanTalkSound;
sfxHandle_t landSound;
sfxHandle_t fallSound;
+ sfxHandle_t turretSpinupSound;
sfxHandle_t hardBounceSound1;
sfxHandle_t hardBounceSound2;
@@ -1251,6 +1286,7 @@ typedef struct
sfxHandle_t buildableRepairedSound;
qhandle_t poisonCloudPS;
+ qhandle_t poisonCloudedPS;
qhandle_t alienEvolvePS;
qhandle_t alienAcidTubePS;
@@ -1263,13 +1299,22 @@ typedef struct
qhandle_t alienBleedPS;
qhandle_t humanBleedPS;
+ qhandle_t alienBuildableBleedPS;
+ qhandle_t humanBuildableBleedPS;
+
qhandle_t teslaZapTS;
sfxHandle_t lCannonWarningSound;
+ sfxHandle_t lCannonWarningSound2;
qhandle_t buildWeaponTimerPie[ 8 ];
qhandle_t upgradeClassIconShader;
+ qhandle_t healthCross;
+ qhandle_t healthCross2X;
+ qhandle_t healthCross3X;
+ qhandle_t healthCrossMedkit;
+ qhandle_t healthCrossPoisoned;
} cgMedia_t;
typedef struct
@@ -1319,17 +1364,12 @@ typedef struct
char mapname[ MAX_QPATH ];
qboolean markDeconstruct; // Whether or not buildables are marked
- int voteTime;
- int voteYes;
- int voteNo;
- qboolean voteModified; // beep whenever changed
- char voteString[ MAX_STRING_TOKENS ];
-
- int teamVoteTime[ 2 ];
- int teamVoteYes[ 2 ];
- int teamVoteNo[ 2 ];
- qboolean teamVoteModified[ 2 ]; // beep whenever changed
- char teamVoteString[ 2 ][ MAX_STRING_TOKENS ];
+ int voteTime[ NUM_TEAMS ];
+ int voteYes[ NUM_TEAMS ];
+ int voteNo[ NUM_TEAMS ];
+ char voteCaller[ NUM_TEAMS ][ MAX_NAME_LENGTH ];
+ qboolean voteModified[ NUM_TEAMS ];// beep whenever changed
+ char voteString[ NUM_TEAMS ][ MAX_STRING_TOKENS ];
int levelStartTime;
@@ -1337,22 +1377,13 @@ typedef struct
qboolean newHud;
- int alienBuildPoints;
- int alienBuildPointsTotal;
- int humanBuildPoints;
- int humanBuildPointsTotal;
- int humanBuildPointsPowered;
-
int alienStage;
int humanStage;
- int alienKills;
- int humanKills;
+ int alienCredits;
+ int humanCredits;
int alienNextStageThreshold;
int humanNextStageThreshold;
- int numAlienSpawns;
- int numHumanSpawns;
-
//
// locally derived information from gamestate
//
@@ -1367,7 +1398,9 @@ typedef struct
clientInfo_t clientinfo[ MAX_CLIENTS ];
- //TA: corpse info
+ int teaminfoReceievedTime;
+
+ // corpse info
clientInfo_t corpseinfo[ MAX_CLIENTS ];
int cursorX;
@@ -1383,57 +1416,69 @@ typedef struct
// media
cgMedia_t media;
+
+ voice_t *voices;
+ clientList_t ignoreList;
+
+ // Kill Message
+ char killMsgKillers[ TEAMCHAT_HEIGHT ][ 33*3+1 ];
+ char killMsgVictims[ TEAMCHAT_HEIGHT ][ 33*3+1 ];
+ int killMsgWeapons[ TEAMCHAT_HEIGHT ];
+ int killMsgMsgTimes[ TEAMCHAT_HEIGHT ];
+ int killMsgPos;
+ int killMsgLastPos;
} cgs_t;
+typedef struct
+{
+ char *cmd;
+ void ( *function )( void );
+} consoleCommand_t;
+
+typedef struct
+{
+ char *cmd;
+ void (*function)( int argNum );
+} consoleCommandCompletions_t;
+
//==============================================================================
extern cgs_t cgs;
extern cg_t cg;
extern centity_t cg_entities[ MAX_GENTITIES ];
+extern displayContextDef_t cgDC;
-//TA: weapon limit expanded:
-//extern weaponInfo_t cg_weapons[MAX_WEAPONS];
extern weaponInfo_t cg_weapons[ 32 ];
-//TA: upgrade infos:
extern upgradeInfo_t cg_upgrades[ 32 ];
-//TA: buildable infos:
extern buildableInfo_t cg_buildables[ BA_NUM_BUILDABLES ];
extern markPoly_t cg_markPolys[ MAX_MARK_POLYS ];
+extern vmCvar_t cg_teslaTrailTime;
extern vmCvar_t cg_centertime;
extern vmCvar_t cg_runpitch;
extern vmCvar_t cg_runroll;
-extern vmCvar_t cg_bobup;
-extern vmCvar_t cg_bobpitch;
-extern vmCvar_t cg_bobroll;
extern vmCvar_t cg_swingSpeed;
extern vmCvar_t cg_shadows;
-extern vmCvar_t cg_gibs;
extern vmCvar_t cg_drawTimer;
extern vmCvar_t cg_drawClock;
extern vmCvar_t cg_drawFPS;
extern vmCvar_t cg_drawDemoState;
extern vmCvar_t cg_drawSnapshot;
-extern vmCvar_t cg_draw3dIcons;
-extern vmCvar_t cg_drawIcons;
-extern vmCvar_t cg_drawAmmoWarning;
+extern vmCvar_t cg_drawChargeBar;
extern vmCvar_t cg_drawCrosshair;
extern vmCvar_t cg_drawCrosshairNames;
-extern vmCvar_t cg_drawRewards;
+extern vmCvar_t cg_crosshairSize;
extern vmCvar_t cg_drawTeamOverlay;
+extern vmCvar_t cg_teamOverlaySortMode;
+extern vmCvar_t cg_teamOverlayMaxPlayers;
extern vmCvar_t cg_teamOverlayUserinfo;
-extern vmCvar_t cg_crosshairX;
-extern vmCvar_t cg_crosshairY;
-extern vmCvar_t cg_drawStatus;
extern vmCvar_t cg_draw2D;
extern vmCvar_t cg_animSpeed;
extern vmCvar_t cg_debugAnim;
extern vmCvar_t cg_debugPosition;
extern vmCvar_t cg_debugEvents;
-extern vmCvar_t cg_teslaTrailTime;
-extern vmCvar_t cg_railTrailTime;
extern vmCvar_t cg_errorDecay;
extern vmCvar_t cg_nopredict;
extern vmCvar_t cg_debugMove;
@@ -1441,65 +1486,46 @@ extern vmCvar_t cg_noPlayerAnims;
extern vmCvar_t cg_showmiss;
extern vmCvar_t cg_footsteps;
extern vmCvar_t cg_addMarks;
-extern vmCvar_t cg_brassTime;
+extern vmCvar_t cg_viewsize;
+extern vmCvar_t cg_drawGun;
extern vmCvar_t cg_gun_frame;
extern vmCvar_t cg_gun_x;
extern vmCvar_t cg_gun_y;
extern vmCvar_t cg_gun_z;
-extern vmCvar_t cg_drawGun;
-extern vmCvar_t cg_viewsize;
extern vmCvar_t cg_tracerChance;
extern vmCvar_t cg_tracerWidth;
extern vmCvar_t cg_tracerLength;
-extern vmCvar_t cg_autoswitch;
-extern vmCvar_t cg_ignore;
-extern vmCvar_t cg_simpleItems;
-extern vmCvar_t cg_fov;
-extern vmCvar_t cg_zoomFov;
-extern vmCvar_t cg_thirdPersonRange;
-extern vmCvar_t cg_thirdPersonAngle;
extern vmCvar_t cg_thirdPerson;
+extern vmCvar_t cg_thirdPersonAngle;
+extern vmCvar_t cg_thirdPersonShoulderViewMode;
+extern vmCvar_t cg_staticDeathCam;
+extern vmCvar_t cg_thirdPersonPitchFollow;
+extern vmCvar_t cg_thirdPersonRange;
extern vmCvar_t cg_stereoSeparation;
extern vmCvar_t cg_lagometer;
-extern vmCvar_t cg_drawAttacker;
+extern vmCvar_t cg_drawSpeed;
+extern vmCvar_t cg_maxSpeedTimeWindow;
extern vmCvar_t cg_synchronousClients;
extern vmCvar_t cg_stats;
-extern vmCvar_t cg_forceModel;
-extern vmCvar_t cg_buildScript;
extern vmCvar_t cg_paused;
extern vmCvar_t cg_blood;
-extern vmCvar_t cg_predictItems;
-extern vmCvar_t cg_deferPlayers;
-extern vmCvar_t cg_drawFriend;
+extern vmCvar_t cg_teamOverlayUserinfo;
extern vmCvar_t cg_teamChatsOnly;
extern vmCvar_t cg_noVoiceChats;
extern vmCvar_t cg_noVoiceText;
-extern vmCvar_t cg_scorePlum;
+extern vmCvar_t cg_hudFiles;
extern vmCvar_t cg_smoothClients;
extern vmCvar_t pmove_fixed;
extern vmCvar_t pmove_msec;
-//extern vmCvar_t cg_pmove_fixed;
-extern vmCvar_t cg_cameraOrbit;
-extern vmCvar_t cg_cameraOrbitDelay;
+extern vmCvar_t cg_cameraMode;
extern vmCvar_t cg_timescaleFadeEnd;
extern vmCvar_t cg_timescaleFadeSpeed;
extern vmCvar_t cg_timescale;
-extern vmCvar_t cg_cameraMode;
-extern vmCvar_t cg_smallFont;
-extern vmCvar_t cg_bigFont;
extern vmCvar_t cg_noTaunt;
-extern vmCvar_t cg_noProjectileTrail;
-extern vmCvar_t cg_oldRail;
-extern vmCvar_t cg_oldRocket;
-extern vmCvar_t cg_oldPlasma;
-extern vmCvar_t cg_trueLightning;
-extern vmCvar_t cg_creepRes;
extern vmCvar_t cg_drawSurfNormal;
extern vmCvar_t cg_drawBBOX;
-extern vmCvar_t cg_debugAlloc;
extern vmCvar_t cg_wwSmoothTime;
-extern vmCvar_t cg_wwFollow;
-extern vmCvar_t cg_wwToggle;
+extern vmCvar_t cg_disableBlueprintErrors;
extern vmCvar_t cg_depthSortParticles;
extern vmCvar_t cg_bounceParticles;
extern vmCvar_t cg_consoleLatency;
@@ -1508,21 +1534,38 @@ extern vmCvar_t cg_debugParticles;
extern vmCvar_t cg_debugTrails;
extern vmCvar_t cg_debugPVS;
extern vmCvar_t cg_disableWarningDialogs;
+extern vmCvar_t cg_disableUpgradeDialogs;
+extern vmCvar_t cg_disableBuildDialogs;
+extern vmCvar_t cg_disableCommandDialogs;
extern vmCvar_t cg_disableScannerPlane;
extern vmCvar_t cg_tutorial;
+extern vmCvar_t cg_rangeMarkerDrawSurface;
+extern vmCvar_t cg_rangeMarkerDrawIntersection;
+extern vmCvar_t cg_rangeMarkerDrawFrontline;
+extern vmCvar_t cg_rangeMarkerSurfaceOpacity;
+extern vmCvar_t cg_rangeMarkerLineOpacity;
+extern vmCvar_t cg_rangeMarkerLineThickness;
+extern vmCvar_t cg_rangeMarkerForBlueprint;
+extern vmCvar_t cg_rangeMarkerBuildableTypes;
+extern vmCvar_t cg_binaryShaderScreenScale;
+
extern vmCvar_t cg_painBlendUpRate;
extern vmCvar_t cg_painBlendDownRate;
extern vmCvar_t cg_painBlendMax;
extern vmCvar_t cg_painBlendScale;
extern vmCvar_t cg_painBlendZoom;
-//TA: hack to get class an carriage through to UI module
+extern vmCvar_t cg_stickySpec;
+extern vmCvar_t cg_sprintToggle;
+extern vmCvar_t cg_unlagged;
+
+extern vmCvar_t cg_debugVoices;
+
extern vmCvar_t ui_currentClass;
extern vmCvar_t ui_carriage;
extern vmCvar_t ui_stages;
extern vmCvar_t ui_dialog;
-extern vmCvar_t ui_loading;
extern vmCvar_t ui_voteActive;
extern vmCvar_t ui_alienTeamVoteActive;
extern vmCvar_t ui_humanTeamVoteActive;
@@ -1531,7 +1574,22 @@ extern vmCvar_t cg_debugRandom;
extern vmCvar_t cg_optimizePrediction;
extern vmCvar_t cg_projectileNudge;
-extern vmCvar_t cg_unlagged;
+
+extern vmCvar_t cg_voice;
+
+extern vmCvar_t cg_emoticons;
+
+extern vmCvar_t cg_chatTeamPrefix;
+
+extern vmCvar_t cg_killMsg;
+extern vmCvar_t cg_killMsgTime;
+extern vmCvar_t cg_killMsgHeight;
+
+extern vmCvar_t cg_killMsgTime;
+extern vmCvar_t cg_killMsgHeight;
+
+extern vmCvar_t thz_radar;
+extern vmCvar_t thz_radarrange;
//
// cg_main.c
@@ -1539,8 +1597,8 @@ extern vmCvar_t cg_unlagged;
const char *CG_ConfigString( int index );
const char *CG_Argv( int arg );
-void QDECL CG_Printf( const char *msg, ... );
-void QDECL CG_Error( const char *msg, ... );
+void QDECL CG_Printf( const char *msg, ... ) __attribute__ ((format (printf, 1, 2)));
+void QDECL CG_Error( const char *msg, ... ) __attribute__ ((noreturn, format (printf, 1, 2)));
void CG_StartMusic( void );
int CG_PlayerCount( void );
@@ -1554,17 +1612,22 @@ void CG_KeyEvent( int key, qboolean down );
void CG_MouseEvent( int x, int y );
void CG_EventHandling( int type );
void CG_SetScoreSelection( void *menu );
+qboolean CG_ClientIsReady( int clientNum );
void CG_BuildSpectatorString( void );
-qboolean CG_FileExists( char *filename );
+qboolean CG_FileExists( const char *filename );
void CG_RemoveNotifyLine( void );
void CG_AddNotifyText( void );
+qboolean CG_GetRangeMarkerPreferences( qboolean *drawSurface, qboolean *drawIntersection,
+ qboolean *drawFrontline, float *surfaceOpacity,
+ float *lineOpacity, float *lineThickness );
+void CG_UpdateBuildableRangeMarkerMask( void );
//
// cg_view.c
//
-void CG_addSmoothOp( vec3_t rotAxis, float rotAngle, float timeMod ); //TA
+void CG_addSmoothOp( vec3_t rotAxis, float rotAngle, float timeMod );
void CG_TestModel_f( void );
void CG_TestGun_f( void );
void CG_TestModelNextFrame_f( void );
@@ -1573,6 +1636,9 @@ void CG_TestModelNextSkin_f( void );
void CG_TestModelPrevSkin_f( void );
void CG_AddBufferedSound( sfxHandle_t sfx );
void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
+void CG_OffsetFirstPersonView( void );
+void CG_OffsetThirdPersonView( void );
+void CG_OffsetShoulderView( void );
//
@@ -1584,37 +1650,41 @@ void CG_FillRect( float x, float y, float width, float height, const floa
void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader );
void CG_DrawFadePic( float x, float y, float width, float height, vec4_t fcolor,
vec4_t tcolor, float amount, qhandle_t hShader );
+void CG_SetClipRegion( float x, float y, float w, float h );
+void CG_ClearClipRegion( void );
int CG_DrawStrlen( const char *str );
float *CG_FadeColor( int startMsec, int totalMsec );
void CG_TileClear( void );
void CG_ColorForHealth( vec4_t hcolor );
-void CG_GetColorForHealth( int health, int armor, vec4_t hcolor );
-
void CG_DrawRect( float x, float y, float width, float height, float size, const float *color );
void CG_DrawSides(float x, float y, float w, float h, float size);
void CG_DrawTopBottom(float x, float y, float w, float h, float size);
qboolean CG_WorldToScreen( vec3_t point, float *x, float *y );
char *CG_KeyBinding( const char *bind );
-
+char CG_GetColorCharForHealth( int clientnum );
+void CG_DrawSphere( const vec3_t center, float radius, int customShader, const float *shaderRGBA );
+void CG_DrawSphericalCone( const vec3_t tip, const vec3_t rotation, float radius,
+ qboolean a240, int customShader, const float *shaderRGBA );
+void CG_DrawRangeMarker( rangeMarkerType_t rmType, const vec3_t origin, const float *angles, float range,
+ qboolean drawSurface, qboolean drawIntersection, qboolean drawFrontline,
+ const vec3_t rgb, float surfaceOpacity, float lineOpacity, float lineThickness );
//
// cg_draw.c
//
-extern int sortedTeamPlayers[ TEAM_MAXOVERLAY ];
-extern int numSortedTeamPlayers;
void CG_AddLagometerFrameInfo( void );
void CG_AddLagometerSnapshotInfo( snapshot_t *snap );
+void CG_AddSpeed( void );
void CG_CenterPrint( const char *str, int y, int charWidth );
void CG_DrawActive( stereoFrame_t stereoView );
-void CG_OwnerDraw( float x, float y, float w, float h, float text_x, float text_y,
- int ownerDraw, int ownerDrawFlags, int align, float special,
- float scale, vec4_t color, qhandle_t shader, int textStyle);
-void CG_Text_Paint( float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style );
-int CG_Text_Width( const char *text, float scale, int limit );
-int CG_Text_Height( const char *text, float scale, int limit );
+void CG_OwnerDraw( float x, float y, float w, float h, float text_x,
+ float text_y, int ownerDraw, int ownerDrawFlags,
+ int align, int textalign, int textvalign,
+ float borderSize, float scale, vec4_t foreColor,
+ vec4_t backColor, qhandle_t shader, int textStyle );
float CG_GetValue(int ownerDraw);
void CG_RunMenuScript(char **args);
void CG_SetPrintString( int type, const char *p );
@@ -1633,13 +1703,12 @@ void CG_DrawField( float x, float y, int width, float cw, float ch, int v
void CG_Player( centity_t *cent );
void CG_Corpse( centity_t *cent );
void CG_ResetPlayerEntity( centity_t *cent );
-void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, int team );
void CG_NewClientInfo( int clientNum );
-void CG_PrecacheClientInfo( pClass_t class, char *model, char *skin );
+void CG_PrecacheClientInfo( class_t class, char *model, char *skin );
sfxHandle_t CG_CustomSound( int clientNum, const char *soundName );
void CG_PlayerDisconnect( vec3_t org );
void CG_Bleed( vec3_t origin, vec3_t normal, int entityNum );
-qboolean CG_AtHighestClass( void );
+centity_t *CG_GetPlayerLocation( void );
//
// cg_buildable.c
@@ -1651,11 +1720,12 @@ void CG_DrawBuildableStatus( void );
void CG_InitBuildables( void );
void CG_HumanBuildableExplosion( vec3_t origin, vec3_t dir );
void CG_AlienBuildableExplosion( vec3_t origin, vec3_t dir );
+qboolean CG_GetBuildableRangeMarkerProperties( buildable_t bType, rangeMarkerType_t *rmType, float *range, vec3_t rgb );
//
// cg_animation.c
//
-void CG_RunLerpFrame( lerpFrame_t *lf );
+void CG_RunLerpFrame( lerpFrame_t *lf, float scale );
//
// cg_animmapobj.c
@@ -1687,6 +1757,7 @@ void CG_CheckEvents( centity_t *cent );
void CG_EntityEvent( centity_t *cent, vec3_t position );
void CG_PainEvent( centity_t *cent, int health );
+void CG_AddToKillMsg( const char* killername, const char* victimname, int icon );
//
// cg_ents.c
@@ -1701,8 +1772,7 @@ void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *pare
qhandle_t parentModel, char *tagName );
void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
qhandle_t parentModel, char *tagName );
-
-
+void CG_RangeMarker( centity_t *cent );
//
@@ -1719,8 +1789,9 @@ void CG_RegisterWeapon( int weaponNum );
void CG_FireWeapon( centity_t *cent, weaponMode_t weaponMode );
void CG_MissileHitWall( weapon_t weapon, weaponMode_t weaponMode, int clientNum,
- vec3_t origin, vec3_t dir, impactSound_t soundType );
-void CG_MissileHitPlayer( weapon_t weapon, weaponMode_t weaponMode, vec3_t origin, vec3_t dir, int entityNum );
+ vec3_t origin, vec3_t dir, impactSound_t soundType, int charge );
+void CG_MissileHitEntity( weapon_t weaponNum, weaponMode_t weaponMode,
+ vec3_t origin, vec3_t dir, int entityNum, int charge );
void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum );
void CG_ShotgunFire( entityState_t *es );
@@ -1736,6 +1807,7 @@ void CG_DrawItemSelectText( rectDef_t *rect, float scale, int textStyle )
void CG_UpdateEntityPositions( void );
void CG_Scanner( rectDef_t *rect, qhandle_t shader, vec4_t color );
void CG_AlienSense( rectDef_t *rect );
+void THZ_DrawScanner( rectDef_t *rect );
//
// cg_marks.c
@@ -1757,6 +1829,7 @@ void CG_ProcessSnapshots( void );
//
// cg_consolecmds.c
//
+qboolean CG_Console_CompleteArgument( int argNum );
qboolean CG_ConsoleCommand( void );
void CG_InitConsoleCommands( void );
qboolean CG_RequestScores( void );
@@ -1768,6 +1841,8 @@ void CG_ExecuteNewServerCommands( int latestSequence );
void CG_ParseServerinfo( void );
void CG_SetConfigValues( void );
void CG_ShaderStateChanged(void);
+void CG_UnregisterCommands( void );
+void CG_CenterPrint_f( void );
//
// cg_playerstate.c
@@ -1777,14 +1852,6 @@ void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops );
void CG_CheckChangedPredictableEvents( playerState_t *ps );
//
-// cg_mem.c
-//
-void CG_InitMemory( void );
-void *CG_Alloc( int size );
-void CG_Free( void *ptr );
-void CG_DefragmentMemory( void );
-
-//
// cg_attachment.c
//
qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v );
@@ -1820,6 +1887,7 @@ qboolean CG_IsParticleSystemInfinite( particleSystem_t *ps );
qboolean CG_IsParticleSystemValid( particleSystem_t **ps );
void CG_SetParticleSystemNormal( particleSystem_t *ps, vec3_t normal );
+void CG_SetParticleSystemLastNormal( particleSystem_t *ps, const float *normal );
void CG_AddParticles( void );
@@ -1855,6 +1923,20 @@ void CG_WritePTRCode( int code );
//
const char *CG_TutorialText( void );
+// cg_main.c
+qboolean CG_GetRangeMarkerPreferences( qboolean *drawSurface, qboolean *drawIntersection,
+ qboolean *drawFrontline, float *surfaceOpacity,
+ float *lineOpacity, float *lineThickness );
+// cg_drawtools.c
+void CG_DrawRangeMarker( rangeMarkerType_t rmType, const vec3_t origin, const float *angles, float range,
+ qboolean drawSurface, qboolean drawIntersection, qboolean drawFrontline,
+ const vec3_t rgb, float surfaceOpacity, float lineOpacity, float lineThickness );
+// cg_buildable.c
+qboolean CG_GetBuildableRangeMarkerProperties( buildable_t bType, rangeMarkerType_t *rmType, float *range, vec3_t rgb );
+void CG_GhostBuildableRangeMarker( buildable_t buildable, const vec3_t origin, const vec3_t normal );
+// cg_ents.c
+void CG_RangeMarker( centity_t *cent );
+
//
//===============================================
@@ -1868,7 +1950,7 @@ const char *CG_TutorialText( void );
void trap_Print( const char *fmt );
// abort the game
-void trap_Error( const char *fmt );
+void trap_Error( const char *fmt ) __attribute__((noreturn));
// milliseconds should only be used for performance tuning, never
// for anything game related. Get time from the CG_DrawActiveFrame parameter
@@ -1888,11 +1970,11 @@ void trap_LiteralArgs( char *buffer, int bufferLength );
// filesystem access
// returns length of file
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, enum FS_Mode mode );
void trap_FS_Read( void *buffer, int len, fileHandle_t f );
void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
void trap_FS_FCloseFile( fileHandle_t f );
-void trap_FS_Seek( fileHandle_t f, long offset, fsOrigin_t origin ); // fsOrigin_t
+void trap_FS_Seek( fileHandle_t f, long offset, enum FS_Origin origin ); // fsOrigin_t
int trap_FS_GetFileList( const char *path, const char *extension,
char *listbuf, int bufsize );
@@ -1905,6 +1987,7 @@ void trap_SendConsoleCommand( const char *text );
// register a command name so the console can perform command completion.
// FIXME: replace this with a normal console command "defineCommand"?
void trap_AddCommand( const char *cmdName );
+void trap_RemoveCommand( const char *cmdName );
// send a string to the server over the network
void trap_SendClientCommand( const char *s );
@@ -1985,11 +2068,13 @@ void trap_R_AddRefEntityToScene( const refEntity_t *re );
// significant construction
void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int numPolys );
+qboolean trap_R_inPVS( const vec3_t p1, const vec3_t p2 );
void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b );
int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
void trap_R_RenderScene( const refdef_t *fd );
void trap_R_SetColor( const float *rgba ); // NULL = 1,1,1,1
+void trap_R_SetClipRegion( const float *region );
void trap_R_DrawStretchPic( float x, float y, float w, float h,
float s1, float t1, float s2, float t2, qhandle_t hShader );
void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
@@ -2180,6 +2265,8 @@ int trap_Key_GetKey( const char *binding );
void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen );
void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen );
void trap_Key_SetBinding( int keynum, const char *binding );
+void trap_Key_SetOverstrikeMode( qboolean state );
+qboolean trap_Key_GetOverstrikeMode( void );
int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits );
e_status trap_CIN_StopCinematic( int handle );
@@ -2199,9 +2286,19 @@ qboolean trap_GetEntityToken( char *buffer, int bufferSize );
int trap_GetDemoState( void );
int trap_GetDemoPos( void );
void trap_GetDemoName( char *buffer, int size );
+void trap_Field_CompleteList( char *listJson );
// cg_drawCrosshair settings
#define CROSSHAIR_ALWAYSOFF 0
#define CROSSHAIR_RANGEDONLY 1
#define CROSSHAIR_ALWAYSON 2
+// menu types for cg_disable*Dialogs
+typedef enum
+{
+ DT_INTERACTIVE, // team, class, armoury
+ DT_ARMOURYEVOLVE, // Insufficient funds et al
+ DT_BUILD, // build errors
+ DT_COMMAND, // You must be living/human/spec etc.
+
+} dialogType_t;
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index eb19dcb..7ec4ae9 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,25 +17,22 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_main.c -- initialization and primary entry point for cgame
-
#include "cg_local.h"
+#include "ui/ui_shared.h"
-#include "../ui/ui_shared.h"
// display context for new ui stuff
displayContextDef_t cgDC;
-int forceModelModificationCount = -1;
-
void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum );
void CG_Shutdown( void );
-char *CG_VoIPString( void );
+static char *CG_VoIPString( void );
/*
================
@@ -44,9 +42,7 @@ This is the only way control passes into the module.
This must be the very first function compiled into the .q3vm file
================
*/
-Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3,
- int arg4, int arg5, int arg6, int arg7,
- int arg8, int arg9, int arg10, int arg11 )
+Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2 )
{
switch( command )
{
@@ -80,9 +76,7 @@ Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3,
return 0;
case CG_MOUSE_EVENT:
- cgDC.cursorx = cgs.cursorX;
- cgDC.cursory = cgs.cursorY;
- CG_MouseEvent( arg0, arg1 );
+ // cgame doesn't care where the cursor is
return 0;
case CG_EVENT_HANDLING:
@@ -92,6 +86,9 @@ Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3,
#ifndef MODULE_INTERFACE_11
case CG_VOIP_STRING:
return (intptr_t)CG_VoIPString( );
+
+ case CG_CONSOLE_COMPLETARGUMENT:
+ return CG_Console_CompleteArgument( arg0 );
#endif
default:
@@ -107,39 +104,27 @@ cg_t cg;
cgs_t cgs;
centity_t cg_entities[ MAX_GENTITIES ];
-//TA: weapons limit expanded:
-//weaponInfo_t cg_weapons[MAX_WEAPONS];
weaponInfo_t cg_weapons[ 32 ];
upgradeInfo_t cg_upgrades[ 32 ];
buildableInfo_t cg_buildables[ BA_NUM_BUILDABLES ];
vmCvar_t cg_teslaTrailTime;
-vmCvar_t cg_railTrailTime;
vmCvar_t cg_centertime;
vmCvar_t cg_runpitch;
vmCvar_t cg_runroll;
-vmCvar_t cg_bobup;
-vmCvar_t cg_bobpitch;
-vmCvar_t cg_bobroll;
vmCvar_t cg_swingSpeed;
vmCvar_t cg_shadows;
-vmCvar_t cg_gibs;
vmCvar_t cg_drawTimer;
vmCvar_t cg_drawClock;
vmCvar_t cg_drawFPS;
vmCvar_t cg_drawDemoState;
vmCvar_t cg_drawSnapshot;
-vmCvar_t cg_draw3dIcons;
-vmCvar_t cg_drawIcons;
-vmCvar_t cg_drawAmmoWarning;
+vmCvar_t cg_drawChargeBar;
vmCvar_t cg_drawCrosshair;
vmCvar_t cg_drawCrosshairNames;
-vmCvar_t cg_drawRewards;
-vmCvar_t cg_crosshairX;
-vmCvar_t cg_crosshairY;
+vmCvar_t cg_crosshairSize;
vmCvar_t cg_draw2D;
-vmCvar_t cg_drawStatus;
vmCvar_t cg_animSpeed;
vmCvar_t cg_debugAnim;
vmCvar_t cg_debugPosition;
@@ -151,7 +136,6 @@ vmCvar_t cg_noPlayerAnims;
vmCvar_t cg_showmiss;
vmCvar_t cg_footsteps;
vmCvar_t cg_addMarks;
-vmCvar_t cg_brassTime;
vmCvar_t cg_viewsize;
vmCvar_t cg_drawGun;
vmCvar_t cg_gun_frame;
@@ -161,59 +145,41 @@ vmCvar_t cg_gun_z;
vmCvar_t cg_tracerChance;
vmCvar_t cg_tracerWidth;
vmCvar_t cg_tracerLength;
-vmCvar_t cg_autoswitch;
-vmCvar_t cg_ignore;
-vmCvar_t cg_simpleItems;
-vmCvar_t cg_fov;
-vmCvar_t cg_zoomFov;
vmCvar_t cg_thirdPerson;
-vmCvar_t cg_thirdPersonRange;
vmCvar_t cg_thirdPersonAngle;
+vmCvar_t cg_thirdPersonShoulderViewMode;
+vmCvar_t cg_staticDeathCam;
+vmCvar_t cg_thirdPersonPitchFollow;
+vmCvar_t cg_thirdPersonRange;
vmCvar_t cg_stereoSeparation;
vmCvar_t cg_lagometer;
-vmCvar_t cg_drawAttacker;
+vmCvar_t cg_drawSpeed;
+vmCvar_t cg_maxSpeedTimeWindow;
vmCvar_t cg_synchronousClients;
vmCvar_t cg_stats;
-vmCvar_t cg_buildScript;
-vmCvar_t cg_forceModel;
vmCvar_t cg_paused;
vmCvar_t cg_blood;
-vmCvar_t cg_predictItems;
-vmCvar_t cg_deferPlayers;
+vmCvar_t cg_teamChatsOnly;
vmCvar_t cg_drawTeamOverlay;
+vmCvar_t cg_teamOverlaySortMode;
+vmCvar_t cg_teamOverlayMaxPlayers;
vmCvar_t cg_teamOverlayUserinfo;
-vmCvar_t cg_drawFriend;
-vmCvar_t cg_teamChatsOnly;
+vmCvar_t cg_noPrintDuplicate;
vmCvar_t cg_noVoiceChats;
vmCvar_t cg_noVoiceText;
vmCvar_t cg_hudFiles;
-vmCvar_t cg_scorePlum;
vmCvar_t cg_smoothClients;
vmCvar_t pmove_fixed;
-//vmCvar_t cg_pmove_fixed;
vmCvar_t pmove_msec;
-vmCvar_t cg_pmove_msec;
vmCvar_t cg_cameraMode;
-vmCvar_t cg_cameraOrbit;
-vmCvar_t cg_cameraOrbitDelay;
vmCvar_t cg_timescaleFadeEnd;
vmCvar_t cg_timescaleFadeSpeed;
vmCvar_t cg_timescale;
-vmCvar_t cg_smallFont;
-vmCvar_t cg_bigFont;
vmCvar_t cg_noTaunt;
-vmCvar_t cg_noProjectileTrail;
-vmCvar_t cg_oldRail;
-vmCvar_t cg_oldRocket;
-vmCvar_t cg_oldPlasma;
-vmCvar_t cg_trueLightning;
-vmCvar_t cg_creepRes;
vmCvar_t cg_drawSurfNormal;
vmCvar_t cg_drawBBOX;
-vmCvar_t cg_debugAlloc;
vmCvar_t cg_wwSmoothTime;
-vmCvar_t cg_wwFollow;
-vmCvar_t cg_wwToggle;
+vmCvar_t cg_disableBlueprintErrors;
vmCvar_t cg_depthSortParticles;
vmCvar_t cg_bounceParticles;
vmCvar_t cg_consoleLatency;
@@ -222,21 +188,38 @@ vmCvar_t cg_debugParticles;
vmCvar_t cg_debugTrails;
vmCvar_t cg_debugPVS;
vmCvar_t cg_disableWarningDialogs;
+vmCvar_t cg_disableUpgradeDialogs;
+vmCvar_t cg_disableBuildDialogs;
+vmCvar_t cg_disableCommandDialogs;
vmCvar_t cg_disableScannerPlane;
vmCvar_t cg_tutorial;
+vmCvar_t cg_rangeMarkerDrawSurface;
+vmCvar_t cg_rangeMarkerDrawIntersection;
+vmCvar_t cg_rangeMarkerDrawFrontline;
+vmCvar_t cg_rangeMarkerSurfaceOpacity;
+vmCvar_t cg_rangeMarkerLineOpacity;
+vmCvar_t cg_rangeMarkerLineThickness;
+vmCvar_t cg_rangeMarkerForBlueprint;
+vmCvar_t cg_rangeMarkerBuildableTypes;
+vmCvar_t cg_binaryShaderScreenScale;
+
vmCvar_t cg_painBlendUpRate;
vmCvar_t cg_painBlendDownRate;
vmCvar_t cg_painBlendMax;
vmCvar_t cg_painBlendScale;
vmCvar_t cg_painBlendZoom;
-//TA: hack to get class and carriage through to UI module
+vmCvar_t cg_stickySpec;
+vmCvar_t cg_sprintToggle;
+vmCvar_t cg_unlagged;
+
+vmCvar_t cg_debugVoices;
+
vmCvar_t ui_currentClass;
vmCvar_t ui_carriage;
vmCvar_t ui_stages;
vmCvar_t ui_dialog;
-vmCvar_t ui_loading;
vmCvar_t ui_voteActive;
vmCvar_t ui_alienTeamVoteActive;
vmCvar_t ui_humanTeamVoteActive;
@@ -245,8 +228,19 @@ vmCvar_t cg_debugRandom;
vmCvar_t cg_optimizePrediction;
vmCvar_t cg_projectileNudge;
-vmCvar_t cg_unlagged;
+vmCvar_t cg_voice;
+
+vmCvar_t cg_emoticons;
+
+vmCvar_t cg_chatTeamPrefix;
+
+vmCvar_t cg_killMsg;
+vmCvar_t cg_killMsgTime;
+vmCvar_t cg_killMsgHeight;
+
+vmCvar_t thz_radar;
+vmCvar_t thz_radarrange;
typedef struct
{
@@ -258,46 +252,31 @@ typedef struct
static cvarTable_t cvarTable[ ] =
{
- { &cg_ignore, "cg_ignore", "0", 0 }, // used for debugging
- { &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE },
{ &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE },
- { &cg_zoomFov, "cg_zoomfov", "22.5", CVAR_ARCHIVE },
- { &cg_fov, "cg_fov", "90", CVAR_ARCHIVE },
{ &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE },
{ &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE },
{ &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE },
- { &cg_gibs, "cg_gibs", "1", CVAR_ARCHIVE },
{ &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE },
- { &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE },
{ &cg_drawTimer, "cg_drawTimer", "1", CVAR_ARCHIVE },
{ &cg_drawClock, "cg_drawClock", "0", CVAR_ARCHIVE },
{ &cg_drawFPS, "cg_drawFPS", "1", CVAR_ARCHIVE },
{ &cg_drawDemoState, "cg_drawDemoState", "1", CVAR_ARCHIVE },
{ &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE },
- { &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE },
- { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE },
- { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE },
- { &cg_drawAttacker, "cg_drawAttacker", "1", CVAR_ARCHIVE },
- { &cg_drawCrosshair, "cg_drawCrosshair", "1", CVAR_ARCHIVE },
+ { &cg_drawChargeBar, "cg_drawChargeBar", "1", CVAR_ARCHIVE },
+ { &cg_drawCrosshair, "cg_drawCrosshair", "2", CVAR_ARCHIVE },
{ &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
- { &cg_drawRewards, "cg_drawRewards", "1", CVAR_ARCHIVE },
- { &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE },
- { &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE },
- { &cg_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
- { &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE },
+ { &cg_crosshairSize, "cg_crosshairSize", "1", CVAR_ARCHIVE },
{ &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE },
{ &cg_lagometer, "cg_lagometer", "0", CVAR_ARCHIVE },
+ { &cg_drawSpeed, "cg_drawSpeed", "0", CVAR_ARCHIVE },
+ { &cg_maxSpeedTimeWindow, "cg_maxSpeedTimeWindow", "2000", CVAR_ARCHIVE },
{ &cg_teslaTrailTime, "cg_teslaTrailTime", "250", CVAR_ARCHIVE },
- { &cg_railTrailTime, "cg_railTrailTime", "400", CVAR_ARCHIVE },
{ &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT },
{ &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT },
{ &cg_gun_z, "cg_gunZ", "0", CVAR_CHEAT },
{ &cg_centertime, "cg_centertime", "3", CVAR_CHEAT },
{ &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE},
{ &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE },
- { &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT },
- { &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
- { &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE },
{ &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT },
{ &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },
{ &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT },
@@ -312,27 +291,31 @@ static cvarTable_t cvarTable[ ] =
{ &cg_tracerChance, "cg_tracerchance", "0.4", CVAR_CHEAT },
{ &cg_tracerWidth, "cg_tracerwidth", "1", CVAR_CHEAT },
{ &cg_tracerLength, "cg_tracerlength", "100", CVAR_CHEAT },
- { &cg_thirdPersonRange, "cg_thirdPersonRange", "40", CVAR_CHEAT },
- { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_CHEAT },
+ { &cg_thirdPersonRange, "cg_thirdPersonRange", "75", CVAR_ARCHIVE },
{ &cg_thirdPerson, "cg_thirdPerson", "0", CVAR_CHEAT },
- { &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE },
- { &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE },
- { &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE },
- { &cg_drawTeamOverlay, "cg_drawTeamOverlay", "0", CVAR_ARCHIVE },
- { &cg_teamOverlayUserinfo, "teamoverlay", "0", CVAR_ROM | CVAR_USERINFO },
+ { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_CHEAT },
+ { &cg_thirdPersonPitchFollow, "cg_thirdPersonPitchFollow", "0", 0 },
+ { &cg_thirdPersonShoulderViewMode, "cg_thirdPersonShoulderViewMode", "1", CVAR_ARCHIVE },
+ { &cg_staticDeathCam, "cg_staticDeathCam", "0", CVAR_ARCHIVE },
{ &cg_stats, "cg_stats", "0", 0 },
- { &cg_drawFriend, "cg_drawFriend", "1", CVAR_ARCHIVE },
+ { &cg_drawTeamOverlay, "cg_drawTeamOverlay", "1", CVAR_ARCHIVE },
+ { &cg_teamOverlaySortMode, "cg_teamOverlaySortMode", "1", CVAR_ARCHIVE },
+ { &cg_teamOverlayMaxPlayers, "cg_teamOverlayMaxPlayers", "8", CVAR_ARCHIVE },
+ { &cg_teamOverlayUserinfo, "teamoverlay", "1", CVAR_ARCHIVE|CVAR_USERINFO },
{ &cg_teamChatsOnly, "cg_teamChatsOnly", "0", CVAR_ARCHIVE },
+ { &cg_noPrintDuplicate, "cg_noPrintDuplicate", "0", CVAR_ARCHIVE },
{ &cg_noVoiceChats, "cg_noVoiceChats", "0", CVAR_ARCHIVE },
{ &cg_noVoiceText, "cg_noVoiceText", "0", CVAR_ARCHIVE },
- { &cg_creepRes, "cg_creepRes", "16", CVAR_ARCHIVE },
{ &cg_drawSurfNormal, "cg_drawSurfNormal", "0", CVAR_CHEAT },
{ &cg_drawBBOX, "cg_drawBBOX", "0", CVAR_CHEAT },
- { &cg_debugAlloc, "cg_debugAlloc", "0", 0 },
{ &cg_wwSmoothTime, "cg_wwSmoothTime", "300", CVAR_ARCHIVE },
- { &cg_wwFollow, "cg_wwFollow", "1", CVAR_ARCHIVE|CVAR_USERINFO },
- { &cg_wwToggle, "cg_wwToggle", "1", CVAR_ARCHIVE|CVAR_USERINFO },
+ { NULL, "cg_wwFollow", "1", CVAR_ARCHIVE|CVAR_USERINFO },
+ { NULL, "cg_wwToggle", "1", CVAR_ARCHIVE|CVAR_USERINFO },
+ { NULL, "cg_disableBlueprintErrors", "0", CVAR_ARCHIVE|CVAR_USERINFO },
+ { &cg_stickySpec, "cg_stickySpec", "1", CVAR_ARCHIVE|CVAR_USERINFO },
+ { &cg_sprintToggle, "cg_sprintToggle", "0", CVAR_ARCHIVE|CVAR_USERINFO },
{ &cg_unlagged, "cg_unlagged", "1", CVAR_ARCHIVE|CVAR_USERINFO },
+ { NULL, "cg_flySpeed", "600", CVAR_ARCHIVE|CVAR_USERINFO },
{ &cg_depthSortParticles, "cg_depthSortParticles", "1", CVAR_ARCHIVE },
{ &cg_bounceParticles, "cg_bounceParticles", "0", CVAR_ARCHIVE },
{ &cg_consoleLatency, "cg_consoleLatency", "3000", CVAR_ARCHIVE },
@@ -341,24 +324,44 @@ static cvarTable_t cvarTable[ ] =
{ &cg_debugTrails, "cg_debugTrails", "0", CVAR_CHEAT },
{ &cg_debugPVS, "cg_debugPVS", "0", CVAR_CHEAT },
{ &cg_disableWarningDialogs, "cg_disableWarningDialogs", "0", CVAR_ARCHIVE },
- { &cg_disableScannerPlane, "cg_disableScannerPlane", "0", CVAR_ARCHIVE },
+ { &cg_disableUpgradeDialogs, "cg_disableUpgradeDialogs", "0", CVAR_ARCHIVE },
+ { &cg_disableBuildDialogs, "cg_disableBuildDialogs", "0", CVAR_ARCHIVE },
+ { &cg_disableCommandDialogs, "cg_disableCommandDialogs", "0", CVAR_ARCHIVE },
+ { &cg_disableScannerPlane, "cg_disableScannerPlane", "1", CVAR_ARCHIVE },
{ &cg_tutorial, "cg_tutorial", "1", CVAR_ARCHIVE },
+
+ { &cg_rangeMarkerDrawSurface, "cg_rangeMarkerDrawSurface", "1", CVAR_ARCHIVE },
+ { &cg_rangeMarkerDrawIntersection, "cg_rangeMarkerDrawIntersection", "1", CVAR_ARCHIVE },
+ { &cg_rangeMarkerDrawFrontline, "cg_rangeMarkerDrawFrontline", "1", CVAR_ARCHIVE },
+ { &cg_rangeMarkerSurfaceOpacity, "cg_rangeMarkerSurfaceOpacity", "0.08", CVAR_ARCHIVE },
+ { &cg_rangeMarkerLineOpacity, "cg_rangeMarkerLineOpacity", "0.4", CVAR_ARCHIVE },
+ { &cg_rangeMarkerLineThickness, "cg_rangeMarkerLineThickness", "4.0", CVAR_ARCHIVE },
+ { &cg_rangeMarkerForBlueprint, "cg_rangeMarkerForBlueprint", "1", CVAR_ARCHIVE },
+ { &cg_rangeMarkerBuildableTypes, "cg_rangeMarkerBuildableTypes", "support", CVAR_ARCHIVE },
+ { NULL, "cg_buildableRangeMarkerMask", "", CVAR_USERINFO },
+ { &cg_binaryShaderScreenScale, "cg_binaryShaderScreenScale", "1.0", CVAR_ARCHIVE },
+
{ &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
+ { NULL, "cg_alienConfig", "", CVAR_ARCHIVE },
+ { NULL, "cg_humanConfig", "", CVAR_ARCHIVE },
+ { NULL, "cg_spectatorConfig", "", CVAR_ARCHIVE },
{ &cg_painBlendUpRate, "cg_painBlendUpRate", "10.0", 0 },
{ &cg_painBlendDownRate, "cg_painBlendDownRate", "0.5", 0 },
{ &cg_painBlendMax, "cg_painBlendMax", "0.7", 0 },
{ &cg_painBlendScale, "cg_painBlendScale", "7.0", 0 },
{ &cg_painBlendZoom, "cg_painBlendZoom", "0.65", 0 },
+
+ { &cg_debugVoices, "cg_debugVoices", "0", 0 },
- { &ui_currentClass, "ui_currentClass", "0", 0 },
- { &ui_carriage, "ui_carriage", "", 0 },
- { &ui_stages, "ui_stages", "0 0", 0 },
- { &ui_dialog, "ui_dialog", "Text not set", 0 },
- { &ui_loading, "ui_loading", "0", 0 },
- { &ui_voteActive, "ui_voteActive", "0", 0 },
- { &ui_humanTeamVoteActive, "ui_humanTeamVoteActive", "0", 0 },
- { &ui_alienTeamVoteActive, "ui_alienTeamVoteActive", "0", 0 },
+ // communication cvars set by the cgame to be read by ui
+ { &ui_currentClass, "ui_currentClass", "0", CVAR_ROM },
+ { &ui_carriage, "ui_carriage", "", CVAR_ROM },
+ { &ui_stages, "ui_stages", "0 0", CVAR_ROM },
+ { &ui_dialog, "ui_dialog", "Text not set", CVAR_ROM },
+ { &ui_voteActive, "ui_voteActive", "0", CVAR_ROM },
+ { &ui_humanTeamVoteActive, "ui_humanTeamVoteActive", "0", CVAR_ROM },
+ { &ui_alienTeamVoteActive, "ui_alienTeamVoteActive", "0", CVAR_ROM },
{ &cg_debugRandom, "cg_debugRandom", "0", 0 },
@@ -368,33 +371,36 @@ static cvarTable_t cvarTable[ ] =
// the following variables are created in other parts of the system,
// but we also reference them here
- { &cg_buildScript, "com_buildScript", "0", 0 }, // force loading of all possible data amd error on failures
{ &cg_paused, "cl_paused", "0", CVAR_ROM },
- { &cg_blood, "com_blood", "1", CVAR_ARCHIVE },
+ { &cg_blood, "cg_blood", "1", CVAR_ARCHIVE },
{ &cg_synchronousClients, "g_synchronousClients", "0", 0 }, // communicated by systeminfo
- { &cg_cameraOrbit, "cg_cameraOrbit", "0", CVAR_CHEAT},
- { &cg_cameraOrbitDelay, "cg_cameraOrbitDelay", "50", CVAR_ARCHIVE},
- { &cg_timescaleFadeEnd, "cg_timescaleFadeEnd", "1", 0},
- { &cg_timescaleFadeSpeed, "cg_timescaleFadeSpeed", "0", 0},
+ { &cg_timescaleFadeEnd, "cg_timescaleFadeEnd", "1", CVAR_CHEAT },
+ { &cg_timescaleFadeSpeed, "cg_timescaleFadeSpeed", "0", CVAR_CHEAT },
{ &cg_timescale, "timescale", "1", 0},
- { &cg_scorePlum, "cg_scorePlums", "1", CVAR_USERINFO | CVAR_ARCHIVE},
{ &cg_smoothClients, "cg_smoothClients", "0", CVAR_USERINFO | CVAR_ARCHIVE},
{ &cg_cameraMode, "com_cameraMode", "0", CVAR_CHEAT},
{ &pmove_fixed, "pmove_fixed", "0", 0},
{ &pmove_msec, "pmove_msec", "8", 0},
{ &cg_noTaunt, "cg_noTaunt", "0", CVAR_ARCHIVE},
- { &cg_noProjectileTrail, "cg_noProjectileTrail", "0", CVAR_ARCHIVE},
- { &cg_smallFont, "ui_smallFont", "0.2", CVAR_ARCHIVE},
- { &cg_bigFont, "ui_bigFont", "0.5", CVAR_ARCHIVE},
- { &cg_oldRail, "cg_oldRail", "1", CVAR_ARCHIVE},
- { &cg_oldRocket, "cg_oldRocket", "1", CVAR_ARCHIVE},
- { &cg_oldPlasma, "cg_oldPlasma", "1", CVAR_ARCHIVE},
- { &cg_trueLightning, "cg_trueLightning", "0.0", CVAR_ARCHIVE}
-// { &cg_pmove_fixed, "cg_pmove_fixed", "0", CVAR_USERINFO | CVAR_ARCHIVE }
+
+ { &cg_voice, "voice", "default", CVAR_USERINFO|CVAR_ARCHIVE},
+
+ { &cg_emoticons, "cg_emoticons", "1", CVAR_LATCH|CVAR_ARCHIVE},
+
+ { &cg_chatTeamPrefix, "cg_chatTeamPrefix", "1", CVAR_ARCHIVE},
+
+ { &cg_killMsg, "cg_killMsg", "1", CVAR_ARCHIVE },
+ { &cg_killMsgTime, "cg_killMsgTime", "4000", CVAR_ARCHIVE },
+ { &cg_killMsgHeight, "cg_killMsgHeight", "7", CVAR_ARCHIVE },
+
+ // Old school thz stuff
+ { &thz_radar, "thz_radar", "0", CVAR_CHEAT},
+ { &thz_radarrange, "thz_radarrange", "600", CVAR_ARCHIVE},
+
};
-static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );
+static size_t cvarTableSize = ARRAY_LEN( cvarTable );
/*
=================
@@ -413,263 +419,98 @@ void CG_RegisterCvars( void )
cv->defaultString, cv->cvarFlags );
}
- //repress standard Q3 console
- trap_Cvar_Set( "con_notifytime", "-2" );
-
// see if we are also running the server on this machine
trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) );
cgs.localServer = atoi( var );
- forceModelModificationCount = cg_forceModel.modificationCount;
-
- trap_Cvar_Register( NULL, "model", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register( NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register( NULL, "team_model", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register( NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE );
}
/*
-===================
-CG_ForceModelChange
-===================
-*/
-static void CG_ForceModelChange( void )
-{
- int i;
-
- for( i = 0; i < MAX_CLIENTS; i++ )
- {
- const char *clientInfo;
-
- clientInfo = CG_ConfigString( CS_PLAYERS + i );
-
- if( !clientInfo[ 0 ] )
- continue;
-
- CG_NewClientInfo( i );
- }
-}
-
-/*
===============
-CG_SetPVars
+CG_SetUIVars
-Set the p_* cvars
+Set some cvars used by the UI
===============
*/
-static void CG_SetPVars( void )
+static void CG_SetUIVars( void )
{
- playerState_t *ps;
+ int i;
+ char carriageCvar[ MAX_TOKEN_CHARS ];
if( !cg.snap )
return;
- ps = &cg.snap->ps;
-
- trap_Cvar_Set( "player_hp", va( "%d", ps->stats[ STAT_HEALTH ] ) );
- trap_Cvar_Set( "player_maxhp", va( "%d", ps->stats[ STAT_MAX_HEALTH ] ) );
- switch( ps->stats[ STAT_PTEAM ] )
- {
- case PTE_NONE:
- trap_Cvar_Set( "player_team", "spectator" );
- trap_Cvar_Set( "player_stage", "0" );
- trap_Cvar_Set( "player_spawns","0" );
- trap_Cvar_Set( "player_kns", "0" );
- trap_Cvar_Set( "player_bp", "0" );
- trap_Cvar_Set( "player_maxbp", "0" );
- break;
-
- case PTE_ALIENS:
- trap_Cvar_Set( "player_team", "alien" );
- trap_Cvar_Set( "player_stage", va( "%d", cgs.alienStage+1 ) );
- trap_Cvar_Set( "player_spawns",va( "%d", cgs.numAlienSpawns ));
- trap_Cvar_Set( "player_kns", va( "%d",((cgs.alienStage==2)?0:abs(cgs.alienNextStageThreshold-cgs.alienKills))));
- trap_Cvar_Set( "player_stage", va( "%d", cgs.alienStage+1 ) );
- trap_Cvar_Set( "player_bp", va( "%d", cgs.alienBuildPoints ));
- trap_Cvar_Set( "player_maxbp", va( "%d", cgs.alienBuildPointsTotal ));
- break;
-
- case PTE_HUMANS:
- trap_Cvar_Set( "player_team", "human" );
- trap_Cvar_Set( "player_stage", va( "%d", cgs.humanStage+1 ) );
- trap_Cvar_Set( "player_spawns",va( "%d", cgs.numHumanSpawns ));
- trap_Cvar_Set( "player_kns", va( "%d",((cgs.humanStage==2)?0:abs(cgs.humanNextStageThreshold-cgs.humanKills))));
- trap_Cvar_Set( "player_bp", va( "%d", cgs.humanBuildPoints ));
- trap_Cvar_Set( "player_maxbp", va( "%d", cgs.humanBuildPointsTotal ));
- break;
- }
+ *carriageCvar = 0;
- trap_Cvar_Set( "player_credits", va( "%d", ps->persistant[ PERS_CREDIT ] ) );
- trap_Cvar_Set( "player_score", va( "%d", ps->persistant[ PERS_SCORE ] ) );
- trap_Cvar_Set( "player_deaths", va( "%d", ps->persistant[ PERS_KILLED ] ) );
+ //determine what the player is carrying
+ if( BG_Weapon( cg.snap->ps.stats[ STAT_WEAPON ] )->purchasable )
+ strcat( carriageCvar, va( "W%d ", cg.snap->ps.stats[ STAT_WEAPON ] ) );
- if ( CG_LastAttacker( ) != -1 )
+ for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
{
- trap_Cvar_Set( "player_attacker", cgs.clientinfo[ CG_LastAttacker( ) ].name );
- trap_Cvar_Set( "player_attacker_hp", va( "%d", cgs.clientinfo[ CG_LastAttacker( ) ].health));
+ if( BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) &&
+ BG_Upgrade( i )->purchasable )
+ strcat( carriageCvar, va( "U%d ", i ) );
}
- else
- {
- trap_Cvar_Set( "player_attacker", "" );
- trap_Cvar_Set( "player_attacker_hp", "" );
- }
-
+ strcat( carriageCvar, "$" );
- if ( CG_CrosshairPlayer( ) != -1 )
- {
- trap_Cvar_Set( "player_crosshair", cgs.clientinfo[ CG_CrosshairPlayer( ) ].name );
- //XXX hax required
- //trap_Cvar_Set( "player_crosshair_credits", va("%d",cgs.clientinfo[CG_CrosshairPlayer( )].credits));
- }
- else
- {
- trap_Cvar_Set( "player_crosshair", "" );
- //trap_Cvar_Set( "player_crosshair_credits", "" );
- }
-
- // stages
- trap_Cvar_Set( "alien_stage", va( "%d", cgs.alienStage+1 ) );
- trap_Cvar_Set( "human_stage", va( "%d", cgs.humanStage+1 ) );
-
- // alien kills to next stage
- if( cgs.alienStage == 2 )
- trap_Cvar_Set( "alien_kns", va( "%d", 0 ) );
- else
- trap_Cvar_Set( "alien_kns", va( "%d", abs(cgs.alienNextStageThreshold - cgs.alienKills)) );
-
- // human kills to next stage
- if( cgs.humanStage == 2 )
- trap_Cvar_Set( "human_kns", va( "%d", 0 ) );
- else
- trap_Cvar_Set( "human_kns", va( "%d", abs(cgs.humanNextStageThreshold - cgs.humanKills)) );
-
- // General score information
- trap_Cvar_Set( "alien_score", va( "%d", cgs.alienKills ) );
- trap_Cvar_Set( "human_score", va( "%d", cgs.humanKills ) );
-
- // class type
- switch ( ps->stats[ STAT_PCLASS ] )
- {
- case PCL_ALIEN_BUILDER0:
- trap_Cvar_Set( "player_class", "Granger" );
- trap_Cvar_Set( "player_weapon", "Granger" );
- break;
-
- case PCL_ALIEN_BUILDER0_UPG:
- trap_Cvar_Set( "player_class", "Advanced Granger" );
- trap_Cvar_Set( "player_weapon", "Advanced Granger" );
- break;
-
- case PCL_ALIEN_LEVEL0:
- trap_Cvar_Set( "player_class", "Dretch" );
- trap_Cvar_Set( "player_weapon", "Dretch" );
- break;
-
- case PCL_ALIEN_LEVEL1:
- trap_Cvar_Set( "player_class", "Basilisk" );
- trap_Cvar_Set( "player_weapon", "Basilisk" );
- break;
-
- case PCL_ALIEN_LEVEL1_UPG:
- trap_Cvar_Set( "player_class", "Advanced Basilisk" );
- trap_Cvar_Set( "player_weapon", "Advanced Basilisk" );
- break;
-
- case PCL_ALIEN_LEVEL2:
- trap_Cvar_Set( "player_class", "Marauder" );
- trap_Cvar_Set( "player_weapon", "Marauder" );
- break;
-
- case PCL_ALIEN_LEVEL2_UPG:
- trap_Cvar_Set( "player_class", "Advanced Marauder" );
- trap_Cvar_Set( "player_weapon", "Advanced Maruder" );
- break;
-
- case PCL_ALIEN_LEVEL3:
- trap_Cvar_Set( "player_class", "Dragoon" );
- trap_Cvar_Set( "player_weapon", "Dragoon" );
- break;
-
- case PCL_ALIEN_LEVEL3_UPG:
- trap_Cvar_Set( "player_class", "Advanced Dragoon" );
- trap_Cvar_Set( "player_weapon", "Advanced Dragoon" );
- break;
-
- case PCL_ALIEN_LEVEL4:
- trap_Cvar_Set( "player_class", "Tyrant" );
- trap_Cvar_Set( "player_weapon", "Tyrant" );
- break;
-
- case PCL_HUMAN:
- trap_Cvar_Set( "player_class", "Human" );
- break;
-
- case PCL_HUMAN_BSUIT:
- trap_Cvar_Set( "player_class", "Battlesuit" );
- break;
-
- default:
- trap_Cvar_Set( "player_class", "Unknown" );
- }
-
- // weapons
- switch ( ps->weapon )
- {
- case WP_HBUILD:
- trap_Cvar_Set( "player_weapon", "Construction Kit" );
- break;
+ trap_Cvar_Set( "ui_carriage", carriageCvar );
- case WP_HBUILD2:
- trap_Cvar_Set( "player_weapon", "Advanced Construction Kit" );
- break;
-
- case WP_BLASTER:
- trap_Cvar_Set( "player_weapon", "Blaster" );
- break;
-
- case WP_MACHINEGUN:
- trap_Cvar_Set( "player_weapon", "Machine Gun" );
- break;
-
- case WP_PAIN_SAW:
- trap_Cvar_Set( "player_weapon", "Painsaw" );
- break;
+ trap_Cvar_Set( "ui_stages", va( "%d %d", cgs.alienStage, cgs.humanStage ) );
+}
- case WP_SHOTGUN:
- trap_Cvar_Set( "player_weapon", "Shotgun" );
- break;
+/*
+=================
+CG_SetPVars
+=================
+*/
+static void CG_SetPVars( void )
+{
+ playerState_t *ps;
- case WP_LAS_GUN:
- trap_Cvar_Set( "player_weapon", "Laser Gun" );
- break;
+ if( !cg.snap ) return;
+ ps = &cg.snap->ps;
- case WP_MASS_DRIVER:
- trap_Cvar_Set( "player_weapon", "Mass Driver" );
- break;
+ trap_Cvar_Set( "player_hp", va( "%d", ps->stats[ STAT_HEALTH ] ));
+ trap_Cvar_Set( "player_maxhp",va( "%d", ps->stats[ STAT_MAX_HEALTH ] ));
- case WP_CHAINGUN:
- trap_Cvar_Set( "player_weapon", "Chain Gun" );
+ switch( ps->stats[ STAT_TEAM ] )
+ {
+ case TEAM_NONE:
+ trap_Cvar_Set( "team_bp", "0" );
+ trap_Cvar_Set( "team_kns", "0" );
+ trap_Cvar_Set( "team_teamname", "spectator" );
+ trap_Cvar_Set( "team_stage", "0" );
break;
- case WP_PULSE_RIFLE:
- trap_Cvar_Set( "player_weapon", "Pulse Rifle" );
+ case TEAM_ALIENS:
+ //trap_Cvar_Set( "team_bp", va( "%d", cgs.alienBuildPoints ));
+ trap_Cvar_Set( "team_kns", va("%d", cgs.alienNextStageThreshold) );
+ trap_Cvar_Set( "team_teamname", "aliens" );
+ trap_Cvar_Set( "team_stage", va( "%d", cgs.alienStage+1 ) );
break;
- case WP_FLAMER:
- trap_Cvar_Set( "player_weapon", "Flame Thrower" );
+ case TEAM_HUMANS:
+ //trap_Cvar_Set( "team_bp", va("%d",cgs.humanBuildPoints) );
+ trap_Cvar_Set( "team_kns", va("%d",cgs.humanNextStageThreshold) );
+ trap_Cvar_Set( "team_teamname", "humans" );
+ trap_Cvar_Set( "team_stage", va( "%d", cgs.humanStage+1 ) );
break;
+ }
+
+ trap_Cvar_Set( "player_credits", va( "%d", cg.snap->ps.persistant[ PERS_CREDIT ] ) );
+ trap_Cvar_Set( "player_score", va( "%d", cg.snap->ps.persistant[ PERS_SCORE ] ) );
- case WP_LUCIFER_CANNON:
- trap_Cvar_Set( "player_weapon", "Lucifier cannon" );
- break;
+ if ( CG_LastAttacker( ) != -1 )
+ trap_Cvar_Set( "player_attackername", cgs.clientinfo[ CG_LastAttacker( ) ].name );
+ else
+ trap_Cvar_Set( "player_attackername", "" );
- case WP_GRENADE:
- trap_Cvar_Set( "player_weapon", "Grenade" );
- break;
+ if ( CG_CrosshairPlayer( ) != -1 )
+ trap_Cvar_Set( "player_crosshairname", cgs.clientinfo[ CG_CrosshairPlayer( ) ].name );
+ else
+ trap_Cvar_Set( "player_crosshairname", "" );
- default:
- trap_Cvar_Set( "player_weapon", "Unknown" );
- }
}
/*
@@ -682,19 +523,16 @@ void CG_UpdateCvars( void )
int i;
cvarTable_t *cv;
- CG_SetPVars();
+ CG_SetPVars( );
for( i = 0, cv = cvarTable; i < cvarTableSize; i++, cv++ )
- trap_Cvar_Update( cv->vmCvar );
+ if( cv->vmCvar )
+ trap_Cvar_Update( cv->vmCvar );
// check for modications here
- // if force model changed
- if( forceModelModificationCount != cg_forceModel.modificationCount )
- {
- forceModelModificationCount = cg_forceModel.modificationCount;
- CG_ForceModelChange( );
- }
+ CG_SetUIVars( );
+ CG_UpdateBuildableRangeMarkerMask();
}
@@ -715,6 +553,7 @@ int CG_LastAttacker( void )
return cg.snap->ps.persistant[ PERS_ATTACKER ];
}
+
/*
=================
CG_RemoveNotifyLine
@@ -735,10 +574,9 @@ void CG_RemoveNotifyLine( void )
cg.consoleText[ i ] = cg.consoleText[ i + offset ];
//pop up the first consoleLine
+ cg.numConsoleLines--;
for( i = 0; i < cg.numConsoleLines; i++ )
cg.consoleLines[ i ] = cg.consoleLines[ i + 1 ];
-
- cg.numConsoleLines--;
}
/*
@@ -749,6 +587,7 @@ CG_AddNotifyText
void CG_AddNotifyText( void )
{
char buffer[ BIG_INFO_STRING ];
+ int bufferLen, textLen;
trap_LiteralArgs( buffer, BIG_INFO_STRING );
@@ -759,12 +598,24 @@ void CG_AddNotifyText( void )
return;
}
+ bufferLen = strlen( buffer );
+ textLen = strlen( cg.consoleText );
+
+ // Ignore console messages that were just printed
+ if( cg_noPrintDuplicate.integer && textLen >= bufferLen &&
+ !strcmp( cg.consoleText + textLen - bufferLen, buffer ) )
+ return;
+
if( cg.numConsoleLines == MAX_CONSOLE_LINES )
+ {
CG_RemoveNotifyLine( );
+ textLen = strlen( cg.consoleText );
+ }
- Q_strcat( cg.consoleText, MAX_CONSOLE_TEXT, buffer );
+ Q_strncpyz( cg.consoleText + textLen, buffer, MAX_CONSOLE_TEXT - textLen );
cg.consoleLines[ cg.numConsoleLines ].time = cg.time;
- cg.consoleLines[ cg.numConsoleLines ].length = strlen( buffer );
+ cg.consoleLines[ cg.numConsoleLines ].length =
+ MIN( bufferLen, MAX_CONSOLE_TEXT - textLen - 1 );
cg.numConsoleLines++;
}
@@ -774,7 +625,7 @@ void QDECL CG_Printf( const char *msg, ... )
char text[ 1024 ];
va_start( argptr, msg );
- vsprintf( text, msg, argptr );
+ Q_vsnprintf( text, sizeof( text ), msg, argptr );
va_end( argptr );
trap_Print( text );
@@ -786,7 +637,7 @@ void QDECL CG_Error( const char *msg, ... )
char text[ 1024 ];
va_start( argptr, msg );
- vsprintf( text, msg, argptr );
+ Q_vsnprintf( text, sizeof( text ), msg, argptr );
va_end( argptr );
trap_Error( text );
@@ -798,7 +649,7 @@ void QDECL Com_Error( int level, const char *error, ... )
char text[1024];
va_start( argptr, error );
- vsprintf( text, error, argptr );
+ Q_vsnprintf( text, sizeof( text ), error, argptr );
va_end( argptr );
CG_Error( "%s", text );
@@ -808,9 +659,9 @@ void QDECL Com_Printf( const char *msg, ... ) {
va_list argptr;
char text[1024];
- va_start (argptr, msg);
- vsprintf (text, msg, argptr);
- va_end (argptr);
+ va_start( argptr, msg );
+ Q_vsnprintf( text, sizeof( text ), msg, argptr );
+ va_end( argptr );
CG_Printf ("%s", text);
}
@@ -841,19 +692,9 @@ CG_FileExists
Test if a specific file exists or not
=================
*/
-qboolean CG_FileExists( char *filename )
+qboolean CG_FileExists( const char *filename )
{
- fileHandle_t f;
-
- if( trap_FS_FOpenFile( filename, &f, FS_READ ) > 0 )
- {
- //file exists so close it
- trap_FS_FCloseFile( f );
-
- return qtrue;
- }
- else
- return qfalse;
+ return trap_FS_FOpenFile( filename, NULL, FS_READ );
}
/*
@@ -882,6 +723,8 @@ static void CG_RegisterSounds( void )
cgs.media.tracerSound = trap_S_RegisterSound( "sound/weapons/tracer.wav", qfalse );
cgs.media.selectSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );
+ cgs.media.turretSpinupSound = trap_S_RegisterSound( "sound/buildables/mgturret/spinup.wav", qfalse );
+ cgs.media.weaponEmptyClick = trap_S_RegisterSound( "sound/weapons/click.wav", qfalse );
cgs.media.talkSound = trap_S_RegisterSound( "sound/misc/talk.wav", qfalse );
cgs.media.alienTalkSound = trap_S_RegisterSound( "sound/misc/alien_talk.wav", qfalse );
@@ -950,6 +793,7 @@ static void CG_RegisterSounds( void )
cgs.media.buildableRepairedSound = trap_S_RegisterSound( "sound/buildables/human/repaired.wav", qfalse );
cgs.media.lCannonWarningSound = trap_S_RegisterSound( "models/weapons/lcannon/warning.wav", qfalse );
+ cgs.media.lCannonWarningSound2 = trap_S_RegisterSound( "models/weapons/lcannon/warning2.wav", qfalse );
}
@@ -1011,12 +855,14 @@ static void CG_RegisterGraphics( void )
cgs.media.scannerBlipShader = trap_R_RegisterShader( "gfx/2d/blip" );
cgs.media.scannerLineShader = trap_R_RegisterShader( "gfx/2d/stalk" );
+ cgs.media.teamOverlayShader = trap_R_RegisterShader( "gfx/2d/teamoverlay" );
+
cgs.media.tracerShader = trap_R_RegisterShader( "gfx/misc/tracer" );
cgs.media.backTileShader = trap_R_RegisterShader( "console" );
- //TA: building shaders
+ // building shaders
cgs.media.greenBuildShader = trap_R_RegisterShader("gfx/misc/greenbuild" );
cgs.media.redBuildShader = trap_R_RegisterShader("gfx/misc/redbuild" );
cgs.media.humanSpawningShader = trap_R_RegisterShader("models/buildables/telenode/rep_cyl" );
@@ -1024,8 +870,15 @@ static void CG_RegisterGraphics( void )
for( i = 0; i < 8; i++ )
cgs.media.buildWeaponTimerPie[ i ] = trap_R_RegisterShader( buildWeaponTimerPieShaders[ i ] );
+ // player health cross shaders
+ cgs.media.healthCross = trap_R_RegisterShader( "ui/assets/neutral/cross.tga" );
+ cgs.media.healthCross2X = trap_R_RegisterShader( "ui/assets/neutral/cross2.tga" );
+ cgs.media.healthCross3X = trap_R_RegisterShader( "ui/assets/neutral/cross3.tga" );
+ cgs.media.healthCrossMedkit = trap_R_RegisterShader( "ui/assets/neutral/cross_medkit.tga" );
+ cgs.media.healthCrossPoisoned = trap_R_RegisterShader( "ui/assets/neutral/cross_poison.tga" );
+
cgs.media.upgradeClassIconShader = trap_R_RegisterShader( "icons/icona_upgrade.tga" );
-
+
cgs.media.balloonShader = trap_R_RegisterShader( "gfx/sprites/chatballoon" );
cgs.media.disconnectPS = CG_RegisterParticleSystem( "disconnectPS" );
@@ -1039,6 +892,7 @@ static void CG_RegisterGraphics( void )
cgs.media.wakeMarkShader = trap_R_RegisterShader( "gfx/marks/wake" );
cgs.media.poisonCloudPS = CG_RegisterParticleSystem( "firstPersonPoisonCloudPS" );
+ cgs.media.poisonCloudedPS = CG_RegisterParticleSystem( "poisonCloudedPS" );
cgs.media.alienEvolvePS = CG_RegisterParticleSystem( "alienEvolvePS" );
cgs.media.alienAcidTubePS = CG_RegisterParticleSystem( "alienAcidTubePS" );
@@ -1051,9 +905,29 @@ static void CG_RegisterGraphics( void )
cgs.media.humanBuildableDestroyedPS = CG_RegisterParticleSystem( "humanBuildableDestroyedPS" );
cgs.media.alienBuildableDestroyedPS = CG_RegisterParticleSystem( "alienBuildableDestroyedPS" );
+ cgs.media.humanBuildableBleedPS = CG_RegisterParticleSystem( "humanBuildableBleedPS");
+ cgs.media.alienBuildableBleedPS = CG_RegisterParticleSystem( "alienBuildableBleedPS" );
+
cgs.media.alienBleedPS = CG_RegisterParticleSystem( "alienBleedPS" );
cgs.media.humanBleedPS = CG_RegisterParticleSystem( "humanBleedPS" );
+ cgs.media.sphereModel = trap_R_RegisterModel( "models/generic/sphere" );
+ cgs.media.sphericalCone64Model = trap_R_RegisterModel( "models/generic/sphericalCone64" );
+ cgs.media.sphericalCone240Model = trap_R_RegisterModel( "models/generic/sphericalCone240" );
+
+ cgs.media.plainColorShader = trap_R_RegisterShader( "gfx/plainColor" );
+ cgs.media.binaryAlpha1Shader = trap_R_RegisterShader( "gfx/binary/alpha1" );
+
+ for( i = 0; i < NUM_BINARY_SHADERS; ++i )
+ {
+ cgs.media.binaryShaders[ i ].f1 = trap_R_RegisterShader( va( "gfx/binary/%03i_F1", i ) );
+ cgs.media.binaryShaders[ i ].f2 = trap_R_RegisterShader( va( "gfx/binary/%03i_F2", i ) );
+ cgs.media.binaryShaders[ i ].f3 = trap_R_RegisterShader( va( "gfx/binary/%03i_F3", i ) );
+ cgs.media.binaryShaders[ i ].b1 = trap_R_RegisterShader( va( "gfx/binary/%03i_B1", i ) );
+ cgs.media.binaryShaders[ i ].b2 = trap_R_RegisterShader( va( "gfx/binary/%03i_B2", i ) );
+ cgs.media.binaryShaders[ i ].b3 = trap_R_RegisterShader( va( "gfx/binary/%03i_B3", i ) );
+ }
+
CG_BuildableStatusParse( "ui/assets/human/buildstat.cfg", &cgs.humanBuildStat );
CG_BuildableStatusParse( "ui/assets/alien/buildstat.cfg", &cgs.alienBuildStat );
@@ -1134,16 +1008,11 @@ void CG_BuildSpectatorString( void )
for( i = 0; i < MAX_CLIENTS; i++ )
{
- if( cgs.clientinfo[ i ].infoValid && cgs.clientinfo[ i ].team == PTE_NONE )
- Q_strcat( cg.spectatorList, sizeof( cg.spectatorList ), va( "%s " S_COLOR_WHITE, cgs.clientinfo[ i ].name ) );
- }
-
- i = strlen( cg.spectatorList );
-
- if( i != cg.spectatorLen )
- {
- cg.spectatorLen = i;
- cg.spectatorWidth = -1;
+ if( cgs.clientinfo[ i ].infoValid && cgs.clientinfo[ i ].team == TEAM_NONE )
+ {
+ Q_strcat( cg.spectatorList, sizeof( cg.spectatorList ),
+ va( S_COLOR_WHITE "%s ", cgs.clientinfo[ i ].name ) );
+ }
}
}
@@ -1164,8 +1033,8 @@ static void CG_RegisterClients( void )
//precache all the models/sounds/etc
for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ )
{
- CG_PrecacheClientInfo( i, BG_FindModelNameForClass( i ),
- BG_FindSkinNameForClass( i ) );
+ CG_PrecacheClientInfo( i, BG_ClassConfig( i )->modelName,
+ BG_ClassConfig( i )->skinName );
cg.charModelFraction = (float)i / (float)PCL_NUM_CLASSES;
trap_UpdateScreen( );
@@ -1246,8 +1115,8 @@ int CG_PlayerCount( void )
for( i = 0; i < cg.numScores; i++ )
{
- if( cg.scores[ i ].team == PTE_ALIENS ||
- cg.scores[ i ].team == PTE_HUMANS )
+ if( cg.scores[ i ].team == TEAM_ALIENS ||
+ cg.scores[ i ].team == TEAM_HUMANS )
count++;
}
@@ -1452,7 +1321,7 @@ qboolean CG_Asset_Parse( int handle )
}
}
- return qfalse; // bk001204 - why not?
+ return qfalse;
}
void CG_ParseMenu( const char *menuFile )
@@ -1545,11 +1414,11 @@ void CG_LoadMenus( const char *menuFile )
if( !f )
{
- trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
+ trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default", menuFile ) );
len = trap_FS_FOpenFile( "ui/hud.txt", &f, FS_READ );
if( !f )
- trap_Error( va( S_COLOR_RED "default menu file not found: ui/hud.txt, unable to continue!\n" ) );
+ trap_Error( va( S_COLOR_RED "default menu file not found: ui/hud.txt, unable to continue!" ) );
}
if( len >= MAX_MENUDEFFILE )
@@ -1594,13 +1463,13 @@ void CG_LoadMenus( const char *menuFile )
-static qboolean CG_OwnerDrawHandleKey( int ownerDraw, int flags, float *special, int key )
+static qboolean CG_OwnerDrawHandleKey( int ownerDraw, int key )
{
return qfalse;
}
-static int CG_FeederCount( float feederID )
+static int CG_FeederCount( int feederID )
{
int i, count = 0;
@@ -1608,7 +1477,7 @@ static int CG_FeederCount( float feederID )
{
for( i = 0; i < cg.numScores; i++ )
{
- if( cg.scores[ i ].team == PTE_ALIENS )
+ if( cg.scores[ i ].team == TEAM_ALIENS )
count++;
}
}
@@ -1616,7 +1485,7 @@ static int CG_FeederCount( float feederID )
{
for( i = 0; i < cg.numScores; i++ )
{
- if( cg.scores[ i ].team == PTE_HUMANS )
+ if( cg.scores[ i ].team == TEAM_HUMANS )
count++;
}
}
@@ -1636,9 +1505,9 @@ void CG_SetScoreSelection( void *p )
for( i = 0; i < cg.numScores; i++ )
{
- if( cg.scores[ i ].team == PTE_ALIENS )
+ if( cg.scores[ i ].team == TEAM_ALIENS )
alien++;
- else if( cg.scores[ i ].team == PTE_HUMANS )
+ else if( cg.scores[ i ].team == TEAM_HUMANS )
human++;
if( ps->clientNum == cg.scores[ i ].client )
@@ -1652,7 +1521,7 @@ void CG_SetScoreSelection( void *p )
feeder = FEEDER_ALIENTEAM_LIST;
i = alien;
- if( cg.scores[ cg.selectedScore ].team == PTE_HUMANS )
+ if( cg.scores[ cg.selectedScore ].team == TEAM_HUMANS )
{
feeder = FEEDER_HUMANTEAM_LIST;
i = human;
@@ -1684,7 +1553,16 @@ static clientInfo_t * CG_InfoFromScoreIndex( int index, int team, int *scoreInde
return &cgs.clientinfo[ cg.scores[ index ].client ];
}
-static const char *CG_FeederItemText( float feederID, int index, int column, qhandle_t *handle )
+qboolean CG_ClientIsReady( int clientNum )
+{
+ clientList_t ready;
+
+ Com_ClientListParse( &ready, CG_ConfigString( CS_CLIENTS_READY ) );
+
+ return Com_ClientListContains( &ready, clientNum );
+}
+
+static const char *CG_FeederItemText( int feederID, int index, int column, qhandle_t *handle )
{
int scoreIndex = 0;
clientInfo_t *info = NULL;
@@ -1695,19 +1573,23 @@ static const char *CG_FeederItemText( float feederID, int index, int column, qha
*handle = -1;
if( feederID == FEEDER_ALIENTEAM_LIST )
- team = PTE_ALIENS;
+ team = TEAM_ALIENS;
else if( feederID == FEEDER_HUMANTEAM_LIST )
- team = PTE_HUMANS;
+ team = TEAM_HUMANS;
info = CG_InfoFromScoreIndex( index, team, &scoreIndex );
sp = &cg.scores[ scoreIndex ];
- if( ( atoi( CG_ConfigString( CS_CLIENTS_READY ) ) & ( 1 << sp->client ) ) &&
- cg.intermissionStarted )
+ if( cg.intermissionStarted && CG_ClientIsReady( sp->client ) )
showIcons = qfalse;
- else if( cg.snap->ps.pm_type == PM_SPECTATOR || cg.snap->ps.pm_flags & PMF_FOLLOW ||
- team == cg.snap->ps.stats[ STAT_PTEAM ] || cg.intermissionStarted )
+ else if( cg.snap->ps.pm_type == PM_SPECTATOR ||
+ cg.snap->ps.pm_type == PM_NOCLIP ||
+ cg.snap->ps.pm_flags & PMF_FOLLOW ||
+ team == cg.snap->ps.stats[ STAT_TEAM ] ||
+ cg.intermissionStarted )
+ {
showIcons = qtrue;
+ }
if( info && info->infoValid )
{
@@ -1724,9 +1606,9 @@ static const char *CG_FeederItemText( float feederID, int index, int column, qha
case 1:
if( showIcons )
{
- if( sp->team == PTE_HUMANS && sp->upgrade != UP_NONE )
+ if( sp->team == TEAM_HUMANS && sp->upgrade != UP_NONE )
*handle = cg_upgrades[ sp->upgrade ].upgradeIcon;
- else if( sp->team == PTE_ALIENS )
+ else if( sp->team == TEAM_ALIENS )
{
switch( sp->weapon )
{
@@ -1745,17 +1627,16 @@ static const char *CG_FeederItemText( float feederID, int index, int column, qha
break;
case 2:
- if( ( atoi( CG_ConfigString( CS_CLIENTS_READY ) ) & ( 1 << sp->client ) ) &&
- cg.intermissionStarted )
+ if( cg.intermissionStarted && CG_ClientIsReady( sp->client ) )
return "Ready";
break;
case 3:
- return info->name;
+ return va( S_COLOR_WHITE "%s", info->name );
break;
case 4:
- return va( "%d", info->score );
+ return va( "%d", sp->score );
break;
case 5:
@@ -1764,7 +1645,7 @@ static const char *CG_FeederItemText( float feederID, int index, int column, qha
case 6:
if( sp->ping == -1 )
- return "connecting";
+ return "";
return va( "%4d", sp->ping );
break;
@@ -1774,15 +1655,15 @@ static const char *CG_FeederItemText( float feederID, int index, int column, qha
return "";
}
-static qhandle_t CG_FeederItemImage( float feederID, int index )
+static qhandle_t CG_FeederItemImage( int feederID, int index )
{
return 0;
}
-static void CG_FeederSelection( float feederID, int index )
+static void CG_FeederSelection( int feederID, int index )
{
int i, count;
- int team = ( feederID == FEEDER_ALIENTEAM_LIST ) ? PTE_ALIENS : PTE_HUMANS;
+ int team = ( feederID == FEEDER_ALIENTEAM_LIST ) ? TEAM_ALIENS : TEAM_HUMANS;
count = 0;
for( i = 0; i < cg.numScores; i++ )
@@ -1809,7 +1690,7 @@ static float CG_Cvar_Get( const char *cvar )
void CG_Text_PaintWithCursor( float x, float y, float scale, vec4_t color, const char *text,
int cursorPos, char cursor, int limit, int style )
{
- CG_Text_Paint( x, y, scale, color, text, 0, limit, style );
+ UI_Text_Paint( x, y, scale, color, text, 0, limit, style );
}
static int CG_OwnerDrawWidth( int ownerDraw, float scale )
@@ -1817,7 +1698,7 @@ static int CG_OwnerDrawWidth( int ownerDraw, float scale )
switch( ownerDraw )
{
case CG_KILLER:
- return CG_Text_Width( CG_GetKillerText( ), scale, 0 );
+ return UI_Text_Width( CG_GetKillerText( ), scale );
break;
}
@@ -1845,7 +1726,7 @@ static void CG_RunCinematicFrame( int handle )
trap_CIN_RunCinematic( handle );
}
-//TA: hack to prevent warning
+// hack to prevent warning
static qboolean CG_OwnerDrawVisible( int parameter )
{
return qfalse;
@@ -1861,13 +1742,18 @@ void CG_LoadHudMenu( void )
char buff[ 1024 ];
const char *hudSet;
+ cgDC.aspectScale = ( ( 640.0f * cgs.glconfig.vidHeight ) /
+ ( 480.0f * cgs.glconfig.vidWidth ) );
+ cgDC.xscale = cgs.glconfig.vidWidth / 640.0f;
+ cgDC.yscale = cgs.glconfig.vidHeight / 480.0f;
+
+ cgDC.smallFontScale = CG_Cvar_Get( "ui_smallFont" );
+ cgDC.bigFontScale = CG_Cvar_Get( "ui_bigFont" );
+
cgDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
cgDC.setColor = &trap_R_SetColor;
cgDC.drawHandlePic = &CG_DrawPic;
cgDC.drawStretchPic = &trap_R_DrawStretchPic;
- cgDC.drawText = &CG_Text_Paint;
- cgDC.textWidth = &CG_Text_Width;
- cgDC.textHeight = &CG_Text_Height;
cgDC.registerModel = &trap_R_RegisterModel;
cgDC.modelBounds = &trap_R_ModelBounds;
cgDC.fillRect = &CG_FillRect;
@@ -1882,13 +1768,11 @@ void CG_LoadHudMenu( void )
cgDC.getValue = &CG_GetValue;
cgDC.ownerDrawVisible = &CG_OwnerDrawVisible;
cgDC.runScript = &CG_RunMenuScript;
- cgDC.getTeamColor = &CG_GetTeamColor;
cgDC.setCVar = trap_Cvar_Set;
cgDC.getCVarString = trap_Cvar_VariableStringBuffer;
cgDC.getCVarValue = CG_Cvar_Get;
- cgDC.drawTextWithCursor = &CG_Text_PaintWithCursor;
- //cgDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
- //cgDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
+ cgDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
+ cgDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
cgDC.startLocalSound = &trap_S_StartLocalSound;
cgDC.ownerDrawHandleKey = &CG_OwnerDrawHandleKey;
cgDC.feederCount = &CG_FeederCount;
@@ -1902,6 +1786,7 @@ void CG_LoadHudMenu( void )
cgDC.Error = &Com_Error;
cgDC.Print = &Com_Printf;
cgDC.ownerDrawWidth = &CG_OwnerDrawWidth;
+ //cgDC.ownerDrawText = &CG_OwnerDrawText;
//cgDC.Pause = &CG_Pause;
cgDC.registerSound = &trap_S_RegisterSound;
cgDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
@@ -1926,6 +1811,8 @@ void CG_LoadHudMenu( void )
void CG_AssetCache( void )
{
+ int i;
+
cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
cgDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
cgDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
@@ -1935,6 +1822,21 @@ void CG_AssetCache( void )
cgDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
cgDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
cgDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
+
+ if( cg_emoticons.integer )
+ {
+ cgDC.Assets.emoticonCount = BG_LoadEmoticons( cgDC.Assets.emoticons,
+ MAX_EMOTICONS );
+ }
+ else
+ cgDC.Assets.emoticonCount = 0;
+
+ for( i = 0; i < cgDC.Assets.emoticonCount; i++ )
+ {
+ cgDC.Assets.emoticons[ i ].shader = trap_R_RegisterShaderNoMip(
+ va( "emoticons/%s_%dx1.tga", cgDC.Assets.emoticons[ i ].name,
+ cgDC.Assets.emoticons[ i ].width ) );
+ }
}
/*
@@ -1952,7 +1854,6 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
// clear everything
memset( &cgs, 0, sizeof( cgs ) );
memset( &cg, 0, sizeof( cg ) );
- memset( &cg.pmext, 0, sizeof( cg.pmext ) );
memset( cg_entities, 0, sizeof( cg_entities ) );
cg.clientNum = clientNum;
@@ -1960,45 +1861,52 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
cgs.processedSnapshotNum = serverMessageNum;
cgs.serverCommandSequence = serverCommandSequence;
+ // get the rendering configuration from the client system
+ trap_GetGlconfig( &cgs.glconfig );
+ cgs.screenXScale = cgs.glconfig.vidWidth / 640.0f;
+ cgs.screenYScale = cgs.glconfig.vidHeight / 480.0f;
+
// load a few needed things before we do any screen updates
cgs.media.whiteShader = trap_R_RegisterShader( "white" );
cgs.media.charsetShader = trap_R_RegisterShader( "gfx/2d/bigchars" );
cgs.media.outlineShader = trap_R_RegisterShader( "outline" );
- //inform UI to repress cursor whilst loading
- trap_Cvar_Set( "ui_loading", "1" );
-
- //TA: load overrides
- BG_InitClassOverrides( );
- BG_InitBuildableOverrides( );
+ // load overrides
+ BG_InitClassConfigs( );
+ BG_InitBuildableConfigs( );
BG_InitAllowedGameElements( );
- //TA: dyn memory
- CG_InitMemory( );
+ // Dynamic memory
+ BG_InitMemory( );
CG_RegisterCvars( );
CG_InitConsoleCommands( );
- //TA: moved up for LoadHudMenu
String_Init( );
- //TA: TA UI
CG_AssetCache( );
- CG_LoadHudMenu( ); // load new hud stuff
+ CG_LoadHudMenu( );
cg.weaponSelect = WP_NONE;
// old servers
- // get the rendering configuration from the client system
- trap_GetGlconfig( &cgs.glconfig );
- cgs.screenXScale = cgs.glconfig.vidWidth / 640.0;
- cgs.screenYScale = cgs.glconfig.vidHeight / 480.0;
-
// get the gamestate from the client system
trap_GetGameState( &cgs.gameState );
+ // copy vote display strings so they don't show up blank if we see
+ // the same one directly after connecting
+ Q_strncpyz( cgs.voteString[ TEAM_NONE ],
+ CG_ConfigString( CS_VOTE_STRING + TEAM_NONE ),
+ sizeof( cgs.voteString ) );
+ Q_strncpyz( cgs.voteString[ TEAM_ALIENS ],
+ CG_ConfigString( CS_VOTE_STRING + TEAM_ALIENS ),
+ sizeof( cgs.voteString[ TEAM_ALIENS ] ) );
+ Q_strncpyz( cgs.voteString[ TEAM_HUMANS ],
+ CG_ConfigString( CS_VOTE_STRING + TEAM_ALIENS ),
+ sizeof( cgs.voteString[ TEAM_HUMANS ] ) );
+
// check version
s = CG_ConfigString( CS_GAME_VERSION );
@@ -2033,8 +1941,10 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
CG_InitUpgrades( );
CG_UpdateMediaFraction( 1.0f );
- //TA:
CG_InitBuildables( );
+
+ cgs.voices = BG_VoiceInit( );
+ BG_PrintVoices( cgs.voices, cg_debugVoices.integer );
CG_RegisterClients( ); // if low on memory, some clients will be deferred
@@ -2053,8 +1963,6 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
CG_ShaderStateChanged( );
trap_S_ClearLoopingSounds( qtrue );
-
- trap_Cvar_Set( "ui_loading", "0" );
}
/*
@@ -2066,8 +1974,7 @@ Called before every level change or subsystem restart
*/
void CG_Shutdown( void )
{
- // some mods may need to do cleanup work here,
- // like closing files or archiving session data
+ CG_UnregisterCommands( );
}
/*
@@ -2075,7 +1982,7 @@ void CG_Shutdown( void )
CG_VoIPString
================
*/
-char *CG_VoIPString( void )
+static char *CG_VoIPString( void )
{
// a generous overestimate of the space needed for 0,1,2...61,62,63
static char voipString[ MAX_CLIENTS * 4 ];
@@ -2086,7 +1993,7 @@ char *CG_VoIPString( void )
if( Q_stricmp( voipSendTarget, "team" ) == 0 )
{
- int i, slen;
+ int i, slen, nlen;
for( slen = i = 0; i < cgs.maxclients; i++ )
{
if( !cgs.clientinfo[ i ].infoValid || i == cg.clientNum )
@@ -2094,14 +2001,15 @@ char *CG_VoIPString( void )
if( cgs.clientinfo[ i ].team != cgs.clientinfo[ cg.clientNum ].team )
continue;
- Com_sprintf( &voipString[ slen ], sizeof( voipString ) - slen,
- "%s%d", ( slen > 0 ) ? "," : "", i );
- slen = strlen( voipString );
- if( slen + 1 >= sizeof( voipString ) )
+ nlen = Q_snprintf( &voipString[ slen ], sizeof( voipString ) - slen,
+ "%s%d", ( slen > 0 ) ? "," : "", i );
+ if( slen + nlen + 1 >= sizeof( voipString ) )
{
CG_Printf( S_COLOR_YELLOW "WARNING: voipString overflowed\n" );
break;
}
+
+ slen += nlen;
}
// Notice that if the snprintf was truncated, slen was not updated
@@ -2119,3 +2027,26 @@ char *CG_VoIPString( void )
return voipString;
}
+
+#ifdef MODULE_INTERFACE_11
+int trap_S_SoundDuration( sfxHandle_t handle )
+{
+ return 1;
+}
+
+void trap_R_SetClipRegion( const float *region )
+{
+}
+
+static qboolean keyOverstrikeMode = qfalse;
+
+void trap_Key_SetOverstrikeMode( qboolean state )
+{
+ keyOverstrikeMode = state;
+}
+
+qboolean trap_Key_GetOverstrikeMode( void )
+{
+ return keyOverstrikeMode;
+}
+#endif
diff --git a/src/cgame/cg_marks.c b/src/cgame/cg_marks.c
index 380f1f0..a5e2351 100644
--- a/src/cgame/cg_marks.c
+++ b/src/cgame/cg_marks.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,14 +17,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_marks.c -- wall marks
-
#include "cg_local.h"
/*
@@ -286,4 +286,3 @@ void CG_AddMarks( void )
trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );
}
}
-
diff --git a/src/cgame/cg_mem.c b/src/cgame/cg_mem.c
deleted file mode 100644
index 6cf5ddd..0000000
--- a/src/cgame/cg_mem.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
-
-This file is part of Tremulous.
-
-Tremulous is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Tremulous is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "cg_local.h"
-
-#define POOLSIZE (256 * 1024)
-#define FREEMEMCOOKIE ((int)0xDEADBE3F) // Any unlikely to be used value
-#define ROUNDBITS 31 // Round to 32 bytes
-
-struct freememnode
-{
- // Size of ROUNDBITS
- int cookie, size; // Size includes node (obviously)
- struct freememnode *prev, *next;
-};
-
-static char memoryPool[ POOLSIZE ];
-static struct freememnode *freehead;
-static int freemem;
-
-void *CG_Alloc( int size )
-{
- // Find a free block and allocate.
- // Does two passes, attempts to fill same-sized free slot first.
-
- struct freememnode *fmn, *prev, *next, *smallest;
- int allocsize, smallestsize;
- char *endptr;
- int *ptr;
-
- allocsize = ( size + sizeof(int) + ROUNDBITS ) & ~ROUNDBITS; // Round to 32-byte boundary
- ptr = NULL;
-
- smallest = NULL;
- smallestsize = POOLSIZE + 1; // Guaranteed not to miss any slots :)
- for( fmn = freehead; fmn; fmn = fmn->next )
- {
- if( fmn->cookie != FREEMEMCOOKIE )
- CG_Error( "CG_Alloc: Memory corruption detected!\n" );
-
- if( fmn->size >= allocsize )
- {
- // We've got a block
- if( fmn->size == allocsize )
- {
- // Same size, just remove
-
- prev = fmn->prev;
- next = fmn->next;
- if( prev )
- prev->next = next; // Point previous node to next
- if( next )
- next->prev = prev; // Point next node to previous
- if( fmn == freehead )
- freehead = next; // Set head pointer to next
- ptr = (int *) fmn;
- break; // Stop the loop, this is fine
- }
- else
- {
- // Keep track of the smallest free slot
- if( fmn->size < smallestsize )
- {
- smallest = fmn;
- smallestsize = fmn->size;
- }
- }
- }
- }
-
- if( !ptr && smallest )
- {
- // We found a slot big enough
- smallest->size -= allocsize;
- endptr = (char *) smallest + smallest->size;
- ptr = (int *) endptr;
- }
-
- if( ptr )
- {
- freemem -= allocsize;
- if( cg_debugAlloc.integer )
- CG_Printf( "CG_Alloc of %i bytes (%i left)\n", allocsize, freemem );
- memset( ptr, 0, allocsize );
- *ptr++ = allocsize; // Store a copy of size for deallocation
- return( (void *) ptr );
- }
-
- CG_Error( "CG_Alloc: failed on allocation of %i bytes\n", size );
- return( NULL );
-}
-
-void CG_Free( void *ptr )
-{
- // Release allocated memory, add it to the free list.
-
- struct freememnode *fmn;
- char *freeend;
- int *freeptr;
-
- freeptr = ptr;
- freeptr--;
-
- freemem += *freeptr;
- if( cg_debugAlloc.integer )
- CG_Printf( "CG_Free of %i bytes (%i left)\n", *freeptr, freemem );
-
- for( fmn = freehead; fmn; fmn = fmn->next )
- {
- freeend = ((char *) fmn) + fmn->size;
- if( freeend == (char *) freeptr )
- {
- // Released block can be merged to an existing node
-
- fmn->size += *freeptr; // Add size of node.
- return;
- }
- }
- // No merging, add to head of list
-
- fmn = (struct freememnode *) freeptr;
- fmn->size = *freeptr; // Set this first to avoid corrupting *freeptr
- fmn->cookie = FREEMEMCOOKIE;
- fmn->prev = NULL;
- fmn->next = freehead;
- freehead->prev = fmn;
- freehead = fmn;
-}
-
-void CG_InitMemory( void )
-{
- // Set up the initial node
-
- freehead = (struct freememnode *) memoryPool;
- freehead->cookie = FREEMEMCOOKIE;
- freehead->size = POOLSIZE;
- freehead->next = NULL;
- freehead->prev = NULL;
- freemem = sizeof(memoryPool);
-}
-
-void CG_DefragmentMemory( void )
-{
- // If there's a frenzy of deallocation and we want to
- // allocate something big, this is useful. Otherwise...
- // not much use.
-
- struct freememnode *startfmn, *endfmn, *fmn;
-
- for( startfmn = freehead; startfmn; )
- {
- endfmn = (struct freememnode *)(((char *) startfmn) + startfmn->size);
- for( fmn = freehead; fmn; )
- {
- if( fmn->cookie != FREEMEMCOOKIE )
- CG_Error( "CG_DefragmentMemory: Memory corruption detected!\n" );
-
- if( fmn == endfmn )
- {
- // We can add fmn onto startfmn.
-
- if( fmn->prev )
- fmn->prev->next = fmn->next;
- if( fmn->next )
- {
- if( !(fmn->next->prev = fmn->prev) )
- freehead = fmn->next; // We're removing the head node
- }
- startfmn->size += fmn->size;
- memset( fmn, 0, sizeof(struct freememnode) ); // A redundant call, really.
-
- startfmn = freehead;
- endfmn = fmn = NULL; // Break out of current loop
- }
- else
- fmn = fmn->next;
- }
-
- if( endfmn )
- startfmn = startfmn->next; // endfmn acts as a 'restart' flag here
- }
-}
diff --git a/src/cgame/cg_particles.c b/src/cgame/cg_particles.c
index 80c4b23..eca9de2 100644
--- a/src/cgame/cg_particles.c
+++ b/src/cgame/cg_particles.c
@@ -1,12 +1,13 @@
/*
===========================================================================
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -15,14 +16,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_particles.c -- the particle system
-
#include "cg_local.h"
static baseParticleSystem_t baseParticleSystems[ MAX_BASEPARTICLE_SYSTEMS ];
@@ -157,6 +157,8 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
p->radius.delay = (int)CG_RandomiseValue( (float)bp->radius.delay, bp->radius.delayRandFrac );
p->radius.initial = CG_RandomiseValue( bp->radius.initial, bp->radius.initialRandFrac );
p->radius.final = CG_RandomiseValue( bp->radius.final, bp->radius.finalRandFrac );
+
+ p->radius.initial += bp->scaleWithCharge * pe->parent->charge;
p->alpha.delay = (int)CG_RandomiseValue( (float)bp->alpha.delay, bp->alpha.delayRandFrac );
p->alpha.initial = CG_RandomiseValue( bp->alpha.initial, bp->alpha.initialRandFrac );
@@ -208,7 +210,7 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
VectorAdd( p->origin, bp->displacement, p->origin );
for( j = 0; j <= 2; j++ )
- p->origin[ j ] += ( crandom( ) * bp->randDisplacement );
+ p->origin[ j ] += ( crandom( ) * bp->randDisplacement[ j ] );
switch( bp->velMoveType )
{
@@ -259,6 +261,21 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
VectorNormalize( p->velocity );
VectorMA( p->origin, bp->normalDisplacement, p->velocity, p->origin );
break;
+
+ case PMT_LAST_NORMAL:
+ VectorCopy( ps->lastNormal, p->velocity );
+ VectorNormalize( p->velocity );
+ VectorMA( p->origin, bp->normalDisplacement, p->velocity, p->origin );
+ break;
+
+ case PMT_OPPORTUNISTIC_NORMAL:
+ if( ps->lastNormalIsCurrent )
+ {
+ VectorCopy( ps->lastNormal, p->velocity );
+ VectorNormalize( p->velocity );
+ VectorMA( p->origin, bp->normalDisplacement, p->velocity, p->origin );
+ }
+ break;
}
VectorNormalize( p->velocity );
@@ -281,12 +298,18 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
//this particle has a child particle system attached
if( bp->childSystemName[ 0 ] != '\0' )
{
- particleSystem_t *ps = CG_SpawnNewParticleSystem( bp->childSystemHandle );
+ particleSystem_t *chps = CG_SpawnNewParticleSystem( bp->childSystemHandle );
- if( CG_IsParticleSystemValid( &ps ) )
+ if( CG_IsParticleSystemValid( &chps ) )
{
- CG_SetAttachmentParticle( &ps->attachment, p );
- CG_AttachToParticle( &ps->attachment );
+ CG_SetAttachmentParticle( &chps->attachment, p );
+ CG_AttachToParticle( &chps->attachment );
+ p->childParticleSystem = chps;
+
+ if( ps->lastNormalIsCurrent )
+ CG_SetParticleSystemLastNormal( chps, ps->lastNormal );
+ else
+ VectorCopy( ps->lastNormal, chps->lastNormal );
}
}
@@ -465,6 +488,9 @@ particleSystem_t *CG_SpawnNewParticleSystem( qhandle_t psHandle )
ps->valid = qtrue;
ps->lazyRemove = qfalse;
+ // use "up" as an arbitrary (non-null) "last" normal
+ VectorSet( ps->lastNormal, 0, 0, 1 );
+
for( j = 0; j < bps->numEjectors; j++ )
CG_SpawnNewParticleEjector( bps->ejectors[ j ], ps );
@@ -567,13 +593,11 @@ Parse a value and its random variance
static void CG_ParseValueAndVariance( char *token, float *value, float *variance, qboolean allowNegative )
{
char valueBuffer[ 16 ];
- char varianceBuffer[ 16 ];
char *variancePtr = NULL, *varEndPointer = NULL;
float localValue = 0.0f;
float localVariance = 0.0f;
Q_strncpyz( valueBuffer, token, sizeof( valueBuffer ) );
- Q_strncpyz( varianceBuffer, token, sizeof( varianceBuffer ) );
variancePtr = strchr( valueBuffer, '~' );
@@ -623,13 +647,96 @@ static qboolean CG_ParseColor( byte *c, char **text_p )
for( i = 0; i <= 2; i++ )
{
token = COM_Parse( text_p );
-
- if( !Q_stricmp( token, "" ) )
+ if( !*token )
return qfalse;
c[ i ] = (int)( (float)0xFF * atof_neg( token, qfalse ) );
}
+ token = COM_Parse( text_p );
+ if( strcmp( token, "}" ) )
+ {
+ CG_Printf( S_COLOR_RED "ERROR: missing '}'\n" );
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+/*
+CG_ParseParticle helpers
+*/
+static void CG_CopyLine( int *i, char *toks, size_t num, size_t size, char **text_p )
+{
+ char *token;
+
+ while( *i < num )
+ {
+ token = COM_ParseExt( text_p, qfalse );
+ if( !*token )
+ break;
+
+ Q_strncpyz( toks, token, size );
+ ( *i )++;
+
+ toks += size;
+ }
+}
+
+static qboolean CG_ParseType( pMoveType_t *pmt, char **text_p )
+{
+ char *token = COM_Parse( text_p );
+ if( !*token )
+ return qfalse;
+
+ if( !Q_stricmp( token, "static" ) )
+ *pmt = PMT_STATIC;
+ else if( !Q_stricmp( token, "static_transform" ) )
+ *pmt = PMT_STATIC_TRANSFORM;
+ else if( !Q_stricmp( token, "tag" ) )
+ *pmt = PMT_TAG;
+ else if( !Q_stricmp( token, "cent" ) )
+ *pmt = PMT_CENT_ANGLES;
+ else if( !Q_stricmp( token, "normal" ) )
+ *pmt = PMT_NORMAL;
+ else if( !Q_stricmp( token, "last_normal" ) )
+ *pmt = PMT_LAST_NORMAL;
+ else if( !Q_stricmp( token, "opportunistic_normal" ) )
+ *pmt = PMT_OPPORTUNISTIC_NORMAL;
+
+ return qtrue;
+}
+
+static qboolean CG_ParseDir( pMoveValues_t *pmv, char **text_p )
+{
+ char *token = COM_Parse( text_p );
+ if( !*token )
+ return qfalse;
+
+ if( !Q_stricmp( token, "linear" ) )
+ pmv->dirType = PMD_LINEAR;
+ else if( !Q_stricmp( token, "point" ) )
+ pmv->dirType = PMD_POINT;
+
+ return qtrue;
+}
+
+static qboolean CG_ParseFinal( pLerpValues_t *plv, char **text_p )
+{
+ char *token = COM_Parse( text_p );
+ if( !*token )
+ return qfalse;
+
+ if( !Q_stricmp( token, "-" ) )
+ {
+ plv->final = PARTICLES_SAME_AS_INITIAL;
+ plv->finalRandFrac = 0.0f;
+ }
+ else
+ {
+ CG_ParseValueAndVariance( token, &plv->final, &plv->finalRandFrac, qfalse );
+ }
+
return qtrue;
}
@@ -650,17 +757,13 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
while( 1 )
{
token = COM_Parse( text_p );
-
- if( !token )
- break;
-
- if( !Q_stricmp( token, "" ) )
+ if( !*token )
return qfalse;
if( !Q_stricmp( token, "bounce" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
if( !Q_stricmp( token, "cull" ) )
@@ -672,13 +775,9 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
}
else
{
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->bounceFrac = number;
- bp->bounceFracRandFrac = randFrac;
+ CG_ParseValueAndVariance( token, &bp->bounceFrac,
+ &bp->bounceFracRandFrac, qfalse );
}
-
- continue;
}
else if( !Q_stricmp( token, "bounceMark" ) )
{
@@ -686,27 +785,21 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->bounceMarkCount = number;
- bp->bounceMarkCountRandFrac = randFrac;
+ CG_ParseValueAndVariance( token, &bp->bounceMarkCount,
+ &bp->bounceMarkCountRandFrac, qfalse );
token = COM_Parse( text_p );
if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->bounceMarkRadius = number;
- bp->bounceMarkRadiusRandFrac = randFrac;
+ CG_ParseValueAndVariance( token, &bp->bounceMarkRadius,
+ &bp->bounceMarkRadiusRandFrac, qfalse );
token = COM_ParseExt( text_p, qfalse );
if( !*token )
break;
Q_strncpyz( bp->bounceMarkName, token, MAX_QPATH );
-
- continue;
}
else if( !Q_stricmp( token, "bounceSound" ) )
{
@@ -714,30 +807,26 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->bounceSoundCount = number;
- bp->bounceSoundCountRandFrac = randFrac;
+ CG_ParseValueAndVariance( token, &bp->bounceSoundCount,
+ &bp->bounceSoundCountRandFrac, qfalse );
token = COM_Parse( text_p );
if( !*token )
break;
Q_strncpyz( bp->bounceSoundName, token, MAX_QPATH );
-
- continue;
}
else if( !Q_stricmp( token, "shader" ) )
{
if( bp->numModels > 0 )
{
CG_Printf( S_COLOR_RED "ERROR: 'shader' not allowed in "
- "conjunction with 'model'\n", token );
+ "conjunction with 'model'\n" );
break;
}
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
if( !Q_stricmp( token, "sync" ) )
@@ -745,38 +834,20 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
else
bp->framerate = atof_neg( token, qfalse );
- token = COM_ParseExt( text_p, qfalse );
- if( !*token )
- break;
-
- while( *token && bp->numFrames < MAX_PS_SHADER_FRAMES )
- {
- Q_strncpyz( bp->shaderNames[ bp->numFrames++ ], token, MAX_QPATH );
- token = COM_ParseExt( text_p, qfalse );
- }
-
- continue;
+ CG_CopyLine( &bp->numFrames, bp->shaderNames[ 0 ],
+ ARRAY_LEN( bp->shaderNames ), MAX_QPATH, text_p );
}
else if( !Q_stricmp( token, "model" ) )
{
if( bp->numFrames > 0 )
{
CG_Printf( S_COLOR_RED "ERROR: 'model' not allowed in "
- "conjunction with 'shader'\n", token );
+ "conjunction with 'shader'\n" );
break;
}
- token = COM_ParseExt( text_p, qfalse );
- if( !*token )
- break;
-
- while( *token && bp->numModels < MAX_PS_MODELS )
- {
- Q_strncpyz( bp->modelNames[ bp->numModels++ ], token, MAX_QPATH );
- token = COM_ParseExt( text_p, qfalse );
- }
-
- continue;
+ CG_CopyLine( &bp->numModels, bp->modelNames[ 0 ],
+ ARRAY_LEN( bp->modelNames ), MAX_QPATH, text_p );
}
else if( !Q_stricmp( token, "modelAnimation" ) )
{
@@ -823,200 +894,130 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
if( fps == 0.0f )
fps = 1.0f;
- bp->modelAnimation.frameLerp = 1000 / fps;
- bp->modelAnimation.initialLerp = 1000 / fps;
+ bp->modelAnimation.frameLerp = bp->modelAnimation.initialLerp =
+ 1000 / fps;
}
-
- continue;
}
///
else if( !Q_stricmp( token, "velocityType" ) )
{
- token = COM_Parse( text_p );
- if( !token )
+ if( !CG_ParseType( &bp->velMoveType, text_p ) )
break;
-
- if( !Q_stricmp( token, "static" ) )
- bp->velMoveType = PMT_STATIC;
- else if( !Q_stricmp( token, "static_transform" ) )
- bp->velMoveType = PMT_STATIC_TRANSFORM;
- else if( !Q_stricmp( token, "tag" ) )
- bp->velMoveType = PMT_TAG;
- else if( !Q_stricmp( token, "cent" ) )
- bp->velMoveType = PMT_CENT_ANGLES;
- else if( !Q_stricmp( token, "normal" ) )
- bp->velMoveType = PMT_NORMAL;
-
- continue;
}
else if( !Q_stricmp( token, "velocityDir" ) )
{
- token = COM_Parse( text_p );
- if( !token )
+ if( !CG_ParseDir( &bp->velMoveValues, text_p ) )
break;
-
- if( !Q_stricmp( token, "linear" ) )
- bp->velMoveValues.dirType = PMD_LINEAR;
- else if( !Q_stricmp( token, "point" ) )
- bp->velMoveValues.dirType = PMD_POINT;
-
- continue;
}
else if( !Q_stricmp( token, "velocityMagnitude" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->velMoveValues.mag = number;
- bp->velMoveValues.magRandFrac = randFrac;
-
- continue;
+ CG_ParseValueAndVariance( token, &bp->velMoveValues.mag,
+ &bp->velMoveValues.magRandFrac, qtrue );
}
else if( !Q_stricmp( token, "parentVelocityFraction" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->velMoveValues.parentVelFrac = number;
- bp->velMoveValues.parentVelFracRandFrac = randFrac;
-
- continue;
+ CG_ParseValueAndVariance( token, &bp->velMoveValues.parentVelFrac,
+ &bp->velMoveValues.parentVelFracRandFrac, qfalse );
}
else if( !Q_stricmp( token, "velocity" ) )
{
for( i = 0; i <= 2; i++ )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
bp->velMoveValues.dir[ i ] = atof_neg( token, qtrue );
}
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, NULL, &randFrac, qfalse );
-
- bp->velMoveValues.dirRandAngle = randFrac;
-
- continue;
+ CG_ParseValueAndVariance( token, NULL, &bp->velMoveValues.dirRandAngle,
+ qfalse );
}
else if( !Q_stricmp( token, "velocityPoint" ) )
{
for( i = 0; i <= 2; i++ )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
bp->velMoveValues.point[ i ] = atof_neg( token, qtrue );
}
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, NULL, &randFrac, qfalse );
-
- bp->velMoveValues.pointRandAngle = randFrac;
-
- continue;
+ CG_ParseValueAndVariance( token, NULL, &bp->velMoveValues.pointRandAngle,
+ qfalse );
}
///
else if( !Q_stricmp( token, "accelerationType" ) )
{
- token = COM_Parse( text_p );
- if( !token )
+ if( !CG_ParseType( &bp->accMoveType, text_p ) )
break;
-
- if( !Q_stricmp( token, "static" ) )
- bp->accMoveType = PMT_STATIC;
- else if( !Q_stricmp( token, "static_transform" ) )
- bp->accMoveType = PMT_STATIC_TRANSFORM;
- else if( !Q_stricmp( token, "tag" ) )
- bp->accMoveType = PMT_TAG;
- else if( !Q_stricmp( token, "cent" ) )
- bp->accMoveType = PMT_CENT_ANGLES;
- else if( !Q_stricmp( token, "normal" ) )
- bp->accMoveType = PMT_NORMAL;
-
- continue;
}
else if( !Q_stricmp( token, "accelerationDir" ) )
{
- token = COM_Parse( text_p );
- if( !token )
+ if( !CG_ParseDir( &bp->accMoveValues, text_p ) )
break;
-
- if( !Q_stricmp( token, "linear" ) )
- bp->accMoveValues.dirType = PMD_LINEAR;
- else if( !Q_stricmp( token, "point" ) )
- bp->accMoveValues.dirType = PMD_POINT;
-
- continue;
}
else if( !Q_stricmp( token, "accelerationMagnitude" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->accMoveValues.mag = number;
- bp->accMoveValues.magRandFrac = randFrac;
-
- continue;
+ CG_ParseValueAndVariance( token, &bp->accMoveValues.mag,
+ &bp->accMoveValues.magRandFrac, qtrue );
}
else if( !Q_stricmp( token, "acceleration" ) )
{
for( i = 0; i <= 2; i++ )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
bp->accMoveValues.dir[ i ] = atof_neg( token, qtrue );
}
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, NULL, &randFrac, qfalse );
-
- bp->accMoveValues.dirRandAngle = randFrac;
-
- continue;
+ CG_ParseValueAndVariance( token, NULL, &bp->accMoveValues.dirRandAngle,
+ qfalse );
}
else if( !Q_stricmp( token, "accelerationPoint" ) )
{
for( i = 0; i <= 2; i++ )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
bp->accMoveValues.point[ i ] = atof_neg( token, qtrue );
}
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, NULL, &randFrac, qfalse );
-
- bp->accMoveValues.pointRandAngle = randFrac;
-
- continue;
+ CG_ParseValueAndVariance( token, NULL, &bp->accMoveValues.pointRandAngle,
+ qfalse );
}
///
else if( !Q_stricmp( token, "displacement" ) )
@@ -1024,43 +1025,45 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
for( i = 0; i <= 2; i++ )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- bp->displacement[ i ] = atof_neg( token, qtrue );
+ CG_ParseValueAndVariance( token, &bp->displacement[ i ],
+ &bp->randDisplacement[ i ], qtrue );
}
- token = COM_Parse( text_p );
- if( !token )
- break;
-
- CG_ParseValueAndVariance( token, NULL, &randFrac, qfalse );
+ // if there is another token on the same line interpret it as an
+ // additional displacement in all three directions, for compatibility
+ // with the old scripts where this was the only option
+ randFrac = 0;
+ token = COM_ParseExt( text_p, qfalse );
+ if( token )
+ CG_ParseValueAndVariance( token, NULL, &randFrac, qtrue );
- bp->randDisplacement = randFrac;
+ for( i = 0; i < 3; i++ )
+ {
+ // convert randDisplacement from proportions to absolute values
+ if( bp->displacement[ i ] != 0 )
+ bp->randDisplacement[ i ] *= bp->displacement[ i ];
- continue;
+ bp->randDisplacement[ i ] += randFrac;
+ }
}
else if( !Q_stricmp( token, "normalDisplacement" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
bp->normalDisplacement = atof_neg( token, qtrue );
-
- continue;
}
else if( !Q_stricmp( token, "overdrawProtection" ) )
{
bp->overdrawProtection = qtrue;
-
- continue;
}
else if( !Q_stricmp( token, "realLight" ) )
{
bp->realLight = qtrue;
-
- continue;
}
else if( !Q_stricmp( token, "dynamicLight" ) )
{
@@ -1070,37 +1073,20 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
+ CG_ParseValueAndVariance( token, &number, &bp->dLightRadius.delayRandFrac,
+ qfalse );
bp->dLightRadius.delay = (int)number;
- bp->dLightRadius.delayRandFrac = randFrac;
token = COM_Parse( text_p );
if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
+ CG_ParseValueAndVariance( token, &bp->dLightRadius.initial,
+ &bp->dLightRadius.initialRandFrac, qfalse );
- bp->dLightRadius.initial = number;
- bp->dLightRadius.initialRandFrac = randFrac;
-
- token = COM_Parse( text_p );
- if( !*token )
+ if( !CG_ParseFinal( &bp->dLightRadius, text_p ) )
break;
- if( !Q_stricmp( token, "-" ) )
- {
- bp->dLightRadius.final = PARTICLES_SAME_AS_INITIAL;
- bp->dLightRadius.finalRandFrac = 0.0f;
- }
- else
- {
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->dLightRadius.final = number;
- bp->dLightRadius.finalRandFrac = randFrac;
- }
-
token = COM_Parse( text_p );
if( !*token )
break;
@@ -1109,100 +1095,59 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
{
if( !CG_ParseColor( bp->dLightColor, text_p ) )
break;
-
- token = COM_Parse( text_p );
- if( Q_stricmp( token, "}" ) )
- {
- CG_Printf( S_COLOR_RED "ERROR: missing '}'\n" );
- break;
- }
}
-
- continue;
}
else if( !Q_stricmp( token, "cullOnStartSolid" ) )
{
bp->cullOnStartSolid = qtrue;
-
- continue;
}
else if( !Q_stricmp( token, "radius" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
+ CG_ParseValueAndVariance( token, &number, &bp->radius.delayRandFrac,
+ qfalse );
bp->radius.delay = (int)number;
- bp->radius.delayRandFrac = randFrac;
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->radius.initial = number;
- bp->radius.initialRandFrac = randFrac;
+ CG_ParseValueAndVariance( token, &bp->radius.initial,
+ &bp->radius.initialRandFrac, qfalse );
+ if( !CG_ParseFinal( &bp->radius, text_p ) )
+ break;
+ }
+ else if( !Q_stricmp( token, "physicsRadius" ) )
+ {
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
-
- if( !Q_stricmp( token, "-" ) )
- {
- bp->radius.final = PARTICLES_SAME_AS_INITIAL;
- bp->radius.finalRandFrac = 0.0f;
- }
- else
- {
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->radius.final = number;
- bp->radius.finalRandFrac = randFrac;
- }
-
- continue;
+
+ bp->physicsRadius = atoi( token );
}
else if( !Q_stricmp( token, "alpha" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
+ CG_ParseValueAndVariance( token, &number, &bp->alpha.delayRandFrac,
+ qfalse );
bp->alpha.delay = (int)number;
- bp->alpha.delayRandFrac = randFrac;
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->alpha.initial = number;
- bp->alpha.initialRandFrac = randFrac;
+ CG_ParseValueAndVariance( token, &bp->alpha.initial,
+ &bp->alpha.initialRandFrac, qfalse );
- token = COM_Parse( text_p );
- if( !token )
+ if( !CG_ParseFinal( &bp->alpha, text_p ) )
break;
-
- if( !Q_stricmp( token, "-" ) )
- {
- bp->alpha.final = PARTICLES_SAME_AS_INITIAL;
- bp->alpha.finalRandFrac = 0.0f;
- }
- else
- {
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
- bp->alpha.final = number;
- bp->alpha.finalRandFrac = randFrac;
- }
-
- continue;
}
else if( !Q_stricmp( token, "color" ) )
{
@@ -1210,10 +1155,9 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
+ CG_ParseValueAndVariance( token, &number, &bp->colorDelayRandFrac,
+ qfalse );
bp->colorDelay = (int)number;
- bp->colorDelayRandFrac = randFrac;
token = COM_Parse( text_p );
if( !*token )
@@ -1225,33 +1169,17 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
break;
token = COM_Parse( text_p );
- if( Q_stricmp( token, "}" ) )
- {
- CG_Printf( S_COLOR_RED "ERROR: missing '}'\n" );
- break;
- }
-
- token = COM_Parse( text_p );
if( !*token )
break;
if( !Q_stricmp( token, "-" ) )
{
- bp->finalColor[ 0 ] = bp->initialColor[ 0 ];
- bp->finalColor[ 1 ] = bp->initialColor[ 1 ];
- bp->finalColor[ 2 ] = bp->initialColor[ 2 ];
+ memcpy( bp->finalColor, bp->initialColor, sizeof( bp->finalColor ) );
}
else if( !Q_stricmp( token, "{" ) )
{
if( !CG_ParseColor( bp->finalColor, text_p ) )
break;
-
- token = COM_Parse( text_p );
- if( Q_stricmp( token, "}" ) )
- {
- CG_Printf( S_COLOR_RED "ERROR: missing '}'\n" );
- break;
- }
}
else
{
@@ -1264,90 +1192,69 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
CG_Printf( S_COLOR_RED "ERROR: missing '{'\n" );
break;
}
-
- continue;
}
else if( !Q_stricmp( token, "rotation" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
+ CG_ParseValueAndVariance( token, &number, &bp->rotation.delayRandFrac,
+ qfalse );
bp->rotation.delay = (int)number;
- bp->rotation.delayRandFrac = randFrac;
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qtrue );
-
- bp->rotation.initial = number;
- bp->rotation.initialRandFrac = randFrac;
+ CG_ParseValueAndVariance( token, &bp->rotation.initial,
+ &bp->rotation.initialRandFrac, qtrue );
- token = COM_Parse( text_p );
- if( !token )
+ if( !CG_ParseFinal( &bp->rotation, text_p ) )
break;
-
- if( !Q_stricmp( token, "-" ) )
- {
- bp->rotation.final = PARTICLES_SAME_AS_INITIAL;
- bp->rotation.finalRandFrac = 0.0f;
- }
- else
- {
- CG_ParseValueAndVariance( token, &number, &randFrac, qtrue );
-
- bp->rotation.final = number;
- bp->rotation.finalRandFrac = randFrac;
- }
-
- continue;
}
else if( !Q_stricmp( token, "lifeTime" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
+ CG_ParseValueAndVariance( token, &number, &bp->lifeTimeRandFrac, qfalse );
bp->lifeTime = (int)number;
- bp->lifeTimeRandFrac = randFrac;
continue;
}
else if( !Q_stricmp( token, "childSystem" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
Q_strncpyz( bp->childSystemName, token, MAX_QPATH );
-
- continue;
}
else if( !Q_stricmp( token, "onDeathSystem" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
Q_strncpyz( bp->onDeathSystemName, token, MAX_QPATH );
-
- continue;
}
else if( !Q_stricmp( token, "childTrailSystem" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
Q_strncpyz( bp->childTrailSystemName, token, MAX_QPATH );
+ }
+ else if( !Q_stricmp( token, "scaleWithCharge" ) )
+ {
+ token = COM_Parse( text_p );
+ if( !*token )
+ break;
- continue;
+ bp->scaleWithCharge = atof( token );
}
else if( !Q_stricmp( token, "}" ) )
return qtrue; //reached the end of this particle
@@ -1384,17 +1291,14 @@ Parse a particle ejector section
static qboolean CG_ParseParticleEjector( baseParticleEjector_t *bpe, char **text_p )
{
char *token;
- float number, randFrac;
+ float number;
// read optional parameters
while( 1 )
{
token = COM_Parse( text_p );
- if( !token )
- break;
-
- if( !Q_stricmp( token, "" ) )
+ if( !*token )
return qfalse;
if( !Q_stricmp( token, "{" ) )
@@ -1412,43 +1316,38 @@ static qboolean CG_ParseParticleEjector( baseParticleEjector_t *bpe, char **text
CG_Printf( S_COLOR_RED "ERROR: ejector has > %d particles\n", MAX_PARTICLES_PER_EJECTOR );
return qfalse;
}
- else if( numBaseParticles == MAX_BASEPARTICLES )
+
+ if( numBaseParticles == MAX_BASEPARTICLES )
{
CG_Printf( S_COLOR_RED "ERROR: maximum number of particles (%d) reached\n", MAX_BASEPARTICLES );
return qfalse;
}
- else
- {
- //start parsing particles again
- bpe->particles[ bpe->numParticles ] = &baseParticles[ numBaseParticles ];
- bpe->numParticles++;
- numBaseParticles++;
- }
- continue;
+
+ //start parsing particles again
+ bpe->particles[ bpe->numParticles ] = &baseParticles[ numBaseParticles ];
+ bpe->numParticles++;
+ numBaseParticles++;
}
else if( !Q_stricmp( token, "delay" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
+ CG_ParseValueAndVariance( token, &number, &bpe->eject.delayRandFrac,
+ qfalse );
bpe->eject.delay = (int)number;
- bpe->eject.delayRandFrac = randFrac;
-
- continue;
}
else if( !Q_stricmp( token, "period" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
bpe->eject.initial = atoi_neg( token, qfalse );
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
if( !Q_stricmp( token, "-" ) )
@@ -1457,17 +1356,15 @@ static qboolean CG_ParseParticleEjector( baseParticleEjector_t *bpe, char **text
bpe->eject.final = atoi_neg( token, qfalse );
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
CG_ParseValueAndVariance( token, NULL, &bpe->eject.randFrac, qfalse );
-
- continue;
}
else if( !Q_stricmp( token, "count" ) )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
if( !Q_stricmp( token, "infinite" ) )
@@ -1477,13 +1374,10 @@ static qboolean CG_ParseParticleEjector( baseParticleEjector_t *bpe, char **text
}
else
{
- CG_ParseValueAndVariance( token, &number, &randFrac, qfalse );
-
+ CG_ParseValueAndVariance( token, &number, &bpe->totalParticlesRandFrac,
+ qfalse );
bpe->totalParticles = (int)number;
- bpe->totalParticlesRandFrac = randFrac;
}
-
- continue;
}
else if( !Q_stricmp( token, "particle" ) ) //acceptable text
continue;
@@ -1517,10 +1411,7 @@ static qboolean CG_ParseParticleSystem( baseParticleSystem_t *bps, char **text_p
{
token = COM_Parse( text_p );
- if( !token )
- break;
-
- if( !Q_stricmp( token, "" ) )
+ if( !*token )
return qfalse;
if( !Q_stricmp( token, "{" ) )
@@ -1546,20 +1437,18 @@ static qboolean CG_ParseParticleSystem( baseParticleSystem_t *bps, char **text_p
CG_Printf( S_COLOR_RED "ERROR: particle system has > %d ejectors\n", MAX_EJECTORS_PER_SYSTEM );
return qfalse;
}
- else if( numBaseParticleEjectors == MAX_BASEPARTICLE_EJECTORS )
+
+ if( numBaseParticleEjectors == MAX_BASEPARTICLE_EJECTORS )
{
CG_Printf( S_COLOR_RED "ERROR: maximum number of particle ejectors (%d) reached\n",
MAX_BASEPARTICLE_EJECTORS );
return qfalse;
}
- else
- {
- //start parsing ejectors again
- bps->ejectors[ bps->numEjectors ] = &baseParticleEjectors[ numBaseParticleEjectors ];
- bps->numEjectors++;
- numBaseParticleEjectors++;
- }
- continue;
+
+ //start parsing ejectors again
+ bps->ejectors[ bps->numEjectors ] = &baseParticleEjectors[ numBaseParticleEjectors ];
+ bps->numEjectors++;
+ numBaseParticleEjectors++;
}
else if( !Q_stricmp( token, "thirdPersonOnly" ) )
bps->thirdPersonOnly = qtrue;
@@ -1602,12 +1491,14 @@ static qboolean CG_ParseParticleFile( const char *fileName )
// load the file
len = trap_FS_FOpenFile( fileName, &f, FS_READ );
- if( len <= 0 )
+ if( len < 0 )
return qfalse;
- if( len >= sizeof( text ) - 1 )
+ if( len == 0 || len >= sizeof( text ) - 1 )
{
- CG_Printf( S_COLOR_RED "ERROR: particle file %s too long\n", fileName );
+ trap_FS_FCloseFile( f );
+ CG_Printf( S_COLOR_RED "ERROR: particle file %s is %s\n", fileName,
+ len == 0 ? "empty" : "too long" );
return qfalse;
}
@@ -1623,23 +1514,13 @@ static qboolean CG_ParseParticleFile( const char *fileName )
{
token = COM_Parse( &text_p );
- if( !Q_stricmp( token, "" ) )
+ if( !*token )
break;
if( !Q_stricmp( token, "{" ) )
{
if( psNameSet )
{
- //check for name space clashes
- for( i = 0; i < numBaseParticleSystems; i++ )
- {
- if( !Q_stricmp( baseParticleSystems[ i ].name, psName ) )
- {
- CG_Printf( S_COLOR_RED "ERROR: a particle system is already named %s\n", psName );
- return qfalse;
- }
- }
-
Q_strncpyz( baseParticleSystems[ numBaseParticleSystems ].name, psName, MAX_QPATH );
if( !CG_ParseParticleSystem( &baseParticleSystems[ numBaseParticleSystems ], &text_p, psName ) )
@@ -1657,10 +1538,8 @@ static qboolean CG_ParseParticleFile( const char *fileName )
MAX_BASEPARTICLE_SYSTEMS );
return qfalse;
}
- else
- numBaseParticleSystems++;
- continue;
+ numBaseParticleSystems++;
}
else
{
@@ -1668,10 +1547,25 @@ static qboolean CG_ParseParticleFile( const char *fileName )
return qfalse;
}
}
-
- if( !psNameSet )
+ else if( !psNameSet )
{
Q_strncpyz( psName, token, sizeof( psName ) );
+
+ //check for name space clashes
+ for( i = 0; i < numBaseParticleSystems; i++ )
+ {
+ if( !Q_stricmp( baseParticleSystems[ i ].name, psName ) )
+ {
+ CG_Printf( S_COLOR_RED "ERROR: a particle system is already named %s\n", psName );
+ break;
+ }
+ }
+ if( i < numBaseParticleSystems )
+ {
+ SkipBracedSection( &text_p, 0 );
+ continue;
+ }
+
psNameSet = qtrue;
}
else
@@ -1810,6 +1704,31 @@ void CG_SetParticleSystemNormal( particleSystem_t *ps, vec3_t normal )
ps->normalValid = qtrue;
VectorCopy( normal, ps->normal );
VectorNormalize( ps->normal );
+
+ CG_SetParticleSystemLastNormal( ps, normal );
+}
+
+/*
+===============
+CG_SetParticleSystemLastNormal
+===============
+*/
+void CG_SetParticleSystemLastNormal( particleSystem_t *ps, const float *normal )
+{
+ if( ps == NULL || !ps->valid )
+ {
+ CG_Printf( S_COLOR_YELLOW "WARNING: tried to modify a NULL particle system\n" );
+ return;
+ }
+
+ if( normal )
+ {
+ ps->lastNormalIsCurrent = qtrue;
+ VectorCopy( normal, ps->lastNormal );
+ VectorNormalize( ps->lastNormal );
+ }
+ else
+ ps->lastNormalIsCurrent = qfalse;
}
@@ -2056,6 +1975,17 @@ static void CG_EvaluateParticlePhysics( particle_t *p )
VectorCopy( ps->normal, acceleration );
break;
+
+ case PMT_LAST_NORMAL:
+ VectorCopy( ps->lastNormal, acceleration );
+ break;
+
+ case PMT_OPPORTUNISTIC_NORMAL:
+ if( ps->lastNormalIsCurrent )
+ VectorCopy( ps->lastNormal, acceleration );
+ else
+ VectorClear( acceleration );
+ break;
}
#define MAX_ACC_RADIUS 1000.0f
@@ -2086,11 +2016,13 @@ static void CG_EvaluateParticlePhysics( particle_t *p )
acceleration );
}
- radius = CG_LerpValues( p->radius.initial,
- p->radius.final,
- CG_CalculateTimeFrac( p->birthTime,
- p->lifeTime,
- p->radius.delay ) );
+ // Some particles have a visual radius that differs from their collision radius
+ if( bp->physicsRadius )
+ radius = bp->physicsRadius;
+ else
+ radius = CG_LerpValues( p->radius.initial, p->radius.final,
+ CG_CalculateTimeFrac( p->birthTime, p->lifeTime,
+ p->radius.delay ) );
VectorSet( mins, -radius, -radius, -radius );
VectorSet( maxs, radius, radius, radius );
@@ -2121,6 +2053,8 @@ static void CG_EvaluateParticlePhysics( particle_t *p )
if( trace.fraction == 1.0f || bounce == 0.0f )
{
VectorCopy( newOrigin, p->origin );
+ if( CG_IsParticleSystemValid( &p->childParticleSystem ) )
+ CG_SetParticleSystemLastNormal( p->childParticleSystem, NULL );
return;
}
@@ -2162,6 +2096,12 @@ static void CG_EvaluateParticlePhysics( particle_t *p )
}
VectorCopy( trace.endpos, p->origin );
+
+ if( !trace.allsolid )
+ {
+ if( CG_IsParticleSystemValid( &p->childParticleSystem ) )
+ CG_SetParticleSystemLastNormal( p->childParticleSystem, trace.plane.normal );
+ }
}
@@ -2394,7 +2334,7 @@ static void CG_RenderParticle( particle_t *p )
p->lf.animation = &bp->modelAnimation;
//run animation
- CG_RunLerpFrame( &p->lf );
+ CG_RunLerpFrame( &p->lf, 1.0f );
re.oldframe = p->lf.oldFrame;
re.frame = p->lf.frame;
@@ -2505,9 +2445,8 @@ void CG_ParticleSystemEntity( centity_t *cent )
if( CG_IsParticleSystemValid( &cent->entityPS ) )
{
- CG_SetAttachmentPoint( &cent->entityPS->attachment, cent->lerpOrigin );
CG_SetAttachmentCent( &cent->entityPS->attachment, cent );
- CG_AttachToPoint( &cent->entityPS->attachment );
+ CG_AttachToCent( &cent->entityPS->attachment );
}
else
cent->entityPSMissing = qtrue;
diff --git a/src/cgame/cg_players.c b/src/cgame/cg_players.c
index 3bd0e65..16779cb 100644
--- a/src/cgame/cg_players.c
+++ b/src/cgame/cg_players.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,14 +17,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_players.c -- handle the media and animation for player entities
-
#include "cg_local.h"
char *cg_customSoundNames[ MAX_CUSTOM_SOUNDS ] =
@@ -107,12 +107,12 @@ static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci )
// load the file
len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if( len <= 0 )
+ if( len < 0 )
return qfalse;
- if( len >= sizeof( text ) - 1 )
+ if( len == 0 || len >= sizeof( text ) - 1 )
{
- CG_Printf( "File %s too long\n", filename );
+ CG_Printf( "File %s is %s\n", filename, len == 0 ? "empty" : "too long" );
trap_FS_FCloseFile( f );
return qfalse;
}
@@ -480,51 +480,17 @@ static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelN
// if any skins failed to load, return failure
if( !CG_RegisterClientSkin( ci, modelName, skinName ) )
{
- Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName );
- return qfalse;
+ Com_Printf( "Failed to load skin file: %s : %s. Loading default\n", modelName, skinName );
+ if( !CG_RegisterClientSkin( ci, modelName, "default" ) )
+ {
+ Com_Printf( S_COLOR_RED "Failed to load default skin file!\n" );
+ return qfalse;
+ }
}
- //FIXME: skins do not load without icon present. do we want icons anyway?
-/* Com_sprintf( filename, sizeof( filename ), "models/players/%s/icon_%s.tga", modelName, skinName );
- ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
- if( !ci->modelIcon )
- {
- Com_Printf( "Failed to load icon file: %s\n", filename );
- return qfalse;
- }*/
-
return qtrue;
}
-/*
-====================
-CG_ColorFromString
-====================
-*/
-static void CG_ColorFromString( const char *v, vec3_t color )
-{
- int val;
-
- VectorClear( color );
-
- val = atoi( v );
-
- if( val < 1 || val > 7 )
- {
- VectorSet( color, 1, 1, 1 );
- return;
- }
-
- if( val & 1 )
- color[ 2 ] = 1.0f;
-
- if( val & 2 )
- color[ 1 ] = 1.0f;
-
- if( val & 4 )
- color[ 0 ] = 1.0f;
-}
-
/*
===================
@@ -535,24 +501,16 @@ Load it now, taking the disk hits
*/
static void CG_LoadClientInfo( clientInfo_t *ci )
{
- const char *dir, *fallback;
+ const char *dir;
int i;
const char *s;
int clientNum;
if( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName ) )
- {
- if( cg_buildScript.integer )
- CG_Error( "CG_RegisterClientModelname( %s, %s ) failed", ci->modelName, ci->skinName );
-
- // fall back
- if( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default" ) )
- CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL );
- }
+ CG_Error( "CG_RegisterClientModelname( %s, %s ) failed", ci->modelName, ci->skinName );
// sounds
dir = ci->modelName;
- fallback = DEFAULT_MODEL;
for( i = 0; i < MAX_CUSTOM_SOUNDS; i++ )
{
@@ -578,15 +536,11 @@ static void CG_LoadClientInfo( clientInfo_t *ci )
s = cg_customSoundNames[ 0 ]; //death1
ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", dir, s + 1 ), qfalse );
- if( !ci->sounds[ i ] )
- ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", fallback, s + 1 ), qfalse );
}
}
else
{
ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", dir, s + 1 ), qfalse );
- if( !ci->sounds[ i ] )
- ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", fallback, s + 1 ), qfalse );
}
}
@@ -649,15 +603,15 @@ static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to )
CG_GetCorpseNum
======================
*/
-static int CG_GetCorpseNum( pClass_t class )
+static int CG_GetCorpseNum( class_t class )
{
int i;
clientInfo_t *match;
char *modelName;
char *skinName;
- modelName = BG_FindModelNameForClass( class );
- skinName = BG_FindSkinNameForClass( class );
+ modelName = BG_ClassConfig( class )->modelName;
+ skinName = BG_ClassConfig( class )->skinName;
for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ )
{
@@ -666,10 +620,10 @@ static int CG_GetCorpseNum( pClass_t class )
if( !match->infoValid )
continue;
- if( !Q_stricmp( modelName, match->modelName )
- && !Q_stricmp( skinName, match->skinName ) )
+ if( !Q_stricmp( modelName, match->modelName ) &&
+ !Q_stricmp( skinName, match->skinName ) )
{
- // this clientinfo is identical, so use it's handles
+ // this clientinfo is identical, so use its handles
return i;
}
}
@@ -716,7 +670,7 @@ static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci )
CG_PrecacheClientInfo
======================
*/
-void CG_PrecacheClientInfo( pClass_t class, char *model, char *skin )
+void CG_PrecacheClientInfo( class_t class, char *model, char *skin )
{
clientInfo_t *ci;
clientInfo_t newInfo;
@@ -728,19 +682,12 @@ void CG_PrecacheClientInfo( pClass_t class, char *model, char *skin )
// model
Q_strncpyz( newInfo.modelName, model, sizeof( newInfo.modelName ) );
- Q_strncpyz( newInfo.headModelName, model, sizeof( newInfo.headModelName ) );
- // modelName didn not include a skin name
+ // modelName did not include a skin name
if( !skin )
- {
Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
- Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
- }
else
- {
Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) );
- Q_strncpyz( newInfo.headSkinName, skin, sizeof( newInfo.headSkinName ) );
- }
newInfo.infoValid = qtrue;
@@ -749,6 +696,34 @@ void CG_PrecacheClientInfo( pClass_t class, char *model, char *skin )
CG_LoadClientInfo( ci );
}
+/*
+=============
+CG_StatusMessages
+
+Print messages for player status changes
+=============
+*/
+static void CG_StatusMessages( clientInfo_t *new, clientInfo_t *old )
+{
+ if( !old->infoValid )
+ return;
+
+ if( strcmp( new->name, old->name ) )
+ CG_Printf( "%s" S_COLOR_WHITE " renamed to %s\n", old->name, new->name );
+
+ if( old->team != new->team )
+ {
+ if( new->team == TEAM_NONE )
+ CG_Printf( "%s" S_COLOR_WHITE " left the %ss\n", new->name,
+ BG_TeamName( old->team ) );
+ else if( old->team == TEAM_NONE )
+ CG_Printf( "%s" S_COLOR_WHITE " joined the %ss\n", new->name,
+ BG_TeamName( new->team ) );
+ else
+ CG_Printf( "%s" S_COLOR_WHITE " left the %ss and joined the %ss\n",
+ new->name, BG_TeamName( old->team ), BG_TeamName( new->team ) );
+ }
+}
/*
======================
@@ -774,45 +749,35 @@ void CG_NewClientInfo( int clientNum )
// the old value
memset( &newInfo, 0, sizeof( newInfo ) );
-
+
// isolate the player's name
v = Info_ValueForKey( configstring, "n" );
Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );
- // colors
- v = Info_ValueForKey( configstring, "c1" );
- CG_ColorFromString( v, newInfo.color1 );
-
- v = Info_ValueForKey( configstring, "c2" );
- CG_ColorFromString( v, newInfo.color2 );
-
- // bot skill
- v = Info_ValueForKey( configstring, "skill" );
- newInfo.botSkill = atoi( v );
-
- // handicap
- v = Info_ValueForKey( configstring, "hc" );
- newInfo.handicap = atoi( v );
-
- // wins
- v = Info_ValueForKey( configstring, "w" );
- newInfo.wins = atoi( v );
-
- // losses
- v = Info_ValueForKey( configstring, "l" );
- newInfo.losses = atoi( v );
-
// team
v = Info_ValueForKey( configstring, "t" );
newInfo.team = atoi( v );
- // team task
- v = Info_ValueForKey( configstring, "tt" );
- newInfo.teamTask = atoi( v );
+ // if this is us, execute team-specific config files
+ // the spectator config is a little unreliable because it's easy to get on
+ // to the spectator team without joining it - e.g. when a new game starts.
+ // It's not a big deal because the spec config is the least important
+ // slash used anyway.
+ // I guess it's possible for someone to change teams during a restart and
+ // for that to then be missed here. But that's rare enough that people can
+ // just exec the configs manually, I think.
+ if( clientNum == cg.clientNum && ci->infoValid &&
+ ci->team != newInfo.team )
+ {
+ char config[ MAX_CVAR_VALUE_STRING ];
- // team leader
- v = Info_ValueForKey( configstring, "tl" );
- newInfo.teamLeader = atoi( v );
+ trap_Cvar_VariableStringBuffer(
+ va( "cg_%sConfig", BG_TeamName( newInfo.team ) ),
+ config, sizeof( config ) );
+
+ if( config[ 0 ] )
+ trap_SendConsoleCommand( va( "exec \"%s\"\n", config ) );
+ }
// model
v = Info_ValueForKey( configstring, "model" );
@@ -832,25 +797,11 @@ void CG_NewClientInfo( int clientNum )
*slash = 0;
}
- //CG_Printf( "NCI: %s\n", v );
-
- // head model
- v = Info_ValueForKey( configstring, "hmodel" );
- Q_strncpyz( newInfo.headModelName, v, sizeof( newInfo.headModelName ) );
+ // voice
+ v = Info_ValueForKey( configstring, "v" );
+ Q_strncpyz( newInfo.voice, v, sizeof( newInfo.voice ) );
- slash = strchr( newInfo.headModelName, '/' );
-
- if( !slash )
- {
- // modelName didn not include a skin name
- Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
- }
- else
- {
- Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );
- // truncate modelName
- *slash = 0;
- }
+ CG_StatusMessages( &newInfo, ci );
// replace whatever was there with the new one
newInfo.infoValid = qtrue;
@@ -909,90 +860,11 @@ cg.time should be between oldFrameTime and frameTime after exit
*/
static void CG_RunPlayerLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale )
{
- int f, numFrames;
- animation_t *anim;
-
- // debugging tool to get no animations
- if( cg_animSpeed.integer == 0 )
- {
- lf->oldFrame = lf->frame = lf->backlerp = 0;
- return;
- }
-
// see if the animation sequence is switching
if( newAnimation != lf->animationNumber || !lf->animation )
- {
CG_SetLerpFrameAnimation( ci, lf, newAnimation );
- }
-
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if( cg.time >= lf->frameTime )
- {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
-
- // get the next frame based on the animation
- anim = lf->animation;
- if( !anim->frameLerp )
- return; // shouldn't happen
-
- if( cg.time < lf->animationTime )
- lf->frameTime = lf->animationTime; // initial lerp
- else
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- f *= speedScale; // adjust for haste, etc
- numFrames = anim->numFrames;
-
- if( anim->flipflop )
- numFrames *= 2;
-
- if( f >= numFrames )
- {
- f -= numFrames;
- if( anim->loopFrames )
- {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- }
- else
- {
- f = numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = cg.time;
- }
- }
-
- if( anim->reversed )
- lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
- else if( anim->flipflop && f>=anim->numFrames )
- lf->frame = anim->firstFrame + anim->numFrames - 1 - ( f % anim->numFrames );
- else
- lf->frame = anim->firstFrame + f;
-
- if( cg.time > lf->frameTime )
- {
- lf->frameTime = cg.time;
-
- if( cg_debugAnim.integer )
- CG_Printf( "Clamp lf->frameTime\n" );
- }
- }
-
- if( lf->frameTime > cg.time + 200 )
- lf->frameTime = cg.time;
-
- if( lf->oldFrameTime > cg.time )
- lf->oldFrameTime = cg.time;
-
- // calculate current lerp value
- if( lf->frameTime == lf->oldFrameTime )
- lf->backlerp = 0;
- else
- lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
+ CG_RunLerpFrame( lf, speedScale );
}
@@ -1735,13 +1607,6 @@ static void CG_PlayerSprites( centity_t *cent )
CG_PlayerFloatSprite( cent, cgs.media.connectionShader );
return;
}
-
- if( cent->currentState.eFlags & EF_TALK )
- {
- // the masses have decreed this to be wrong
-/* CG_PlayerFloatSprite( cent, cgs.media.balloonShader );
- return;*/
- }
}
/*
@@ -1754,7 +1619,7 @@ Returns the Z component of the surface being shadowed
===============
*/
#define SHADOW_DISTANCE 128
-static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane, pClass_t class )
+static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane, class_t class )
{
vec3_t end, mins, maxs;
trace_t trace;
@@ -1762,7 +1627,7 @@ static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane, pClass_t c
entityState_t *es = &cent->currentState;
vec3_t surfNormal = { 0.0f, 0.0f, 1.0f };
- BG_FindBBoxForClass( class, mins, maxs, NULL, NULL, NULL );
+ BG_ClassBoundingBox( class, mins, maxs, NULL, NULL, NULL );
mins[ 2 ] = 0.0f;
maxs[ 2 ] = 2.0f;
@@ -1808,7 +1673,7 @@ static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane, pClass_t c
// without taking a spot in the cg_marks array
CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal,
cent->pe.legs.yawAngle, 0.0f, 0.0f, 0.0f, alpha, qfalse,
- 24.0f * BG_FindShadowScaleForClass( class ), qtrue );
+ 24.0f * BG_ClassConfig( class )->shadowScale, qtrue );
return qtrue;
}
@@ -1821,7 +1686,7 @@ CG_PlayerSplash
Draw a mark at the water surface
===============
*/
-static void CG_PlayerSplash( centity_t *cent, pClass_t class )
+static void CG_PlayerSplash( centity_t *cent, class_t class )
{
vec3_t start, end;
vec3_t mins, maxs;
@@ -1831,7 +1696,7 @@ static void CG_PlayerSplash( centity_t *cent, pClass_t class )
if( !cg_shadows.integer )
return;
- BG_FindBBoxForClass( class, mins, maxs, NULL, NULL, NULL );
+ BG_ClassBoundingBox( class, mins, maxs, NULL, NULL, NULL );
VectorCopy( cent->lerpOrigin, end );
end[ 2 ] += mins[ 2 ];
@@ -1861,7 +1726,7 @@ static void CG_PlayerSplash( centity_t *cent, pClass_t class )
CG_ImpactMark( cgs.media.wakeMarkShader, trace.endpos, trace.plane.normal,
cent->pe.legs.yawAngle, 1.0f, 1.0f, 1.0f, 1.0f, qfalse,
- 32.0f * BG_FindShadowScaleForClass( class ), qtrue );
+ 32.0f * BG_ClassConfig( class )->shadowScale, qtrue );
}
@@ -2012,7 +1877,7 @@ void CG_Player( centity_t *cent )
qboolean shadow = qfalse;
float shadowPlane = 0.0f;
entityState_t *es = &cent->currentState;
- pClass_t class = ( es->misc >> 8 ) & 0xFF;
+ class_t class = ( es->misc >> 8 ) & 0xFF;
float scale;
vec3_t tempAxis[ 3 ], tempAxis2[ 3 ];
vec3_t angles;
@@ -2051,7 +1916,7 @@ void CG_Player( centity_t *cent )
{
vec3_t mins, maxs;
- BG_FindBBoxForClass( class, mins, maxs, NULL, NULL, NULL );
+ BG_ClassBoundingBox( class, mins, maxs, NULL, NULL, NULL );
CG_DrawBoundingBox( cent->lerpOrigin, mins, maxs );
}
@@ -2150,7 +2015,7 @@ void CG_Player( centity_t *cent )
else
VectorCopy( es->angles2, surfNormal );
- BG_FindBBoxForClass( class, mins, maxs, NULL, NULL, NULL );
+ BG_ClassBoundingBox( class, mins, maxs, NULL, NULL, NULL );
VectorMA( legs.origin, -TRACE_DEPTH, surfNormal, end );
VectorMA( legs.origin, 1.0f, surfNormal, start );
@@ -2166,7 +2031,7 @@ void CG_Player( centity_t *cent )
}
//rescale the model
- scale = BG_FindModelScaleForClass( class );
+ scale = BG_ClassConfig( class )->modelScale;
if( scale != 1.0f )
{
@@ -2178,7 +2043,7 @@ void CG_Player( centity_t *cent )
}
//offset on the Z axis if required
- VectorMA( legs.origin, BG_FindZOffsetForClass( class ), surfNormal, legs.origin );
+ VectorMA( legs.origin, BG_ClassConfig( class )->zOffset, surfNormal, legs.origin );
VectorCopy( legs.origin, legs.lightingOrigin );
VectorCopy( legs.origin, legs.oldorigin ); // don't positionally lerp at all
@@ -2233,6 +2098,21 @@ void CG_Player( centity_t *cent )
head.renderfx = renderfx;
trap_R_AddRefEntityToScene( &head );
+
+ // if this player has been hit with poison cloud, add an effect PS
+ if( ( es->eFlags & EF_POISONCLOUDED ) &&
+ ( es->number != cg.snap->ps.clientNum || cg.renderingThirdPerson ) )
+ {
+ if( !CG_IsParticleSystemValid( &cent->poisonCloudedPS ) )
+ cent->poisonCloudedPS = CG_SpawnNewParticleSystem( cgs.media.poisonCloudedPS );
+
+ CG_SetAttachmentTag( &cent->poisonCloudedPS->attachment,
+ head, head.hModel, "tag_head" );
+ CG_SetAttachmentCent( &cent->poisonCloudedPS->attachment, cent );
+ CG_AttachToTag( &cent->poisonCloudedPS->attachment );
+ }
+ else if( CG_IsParticleSystemValid( &cent->poisonCloudedPS ) )
+ CG_DestroyParticleSystem( &cent->poisonCloudedPS );
}
//
@@ -2247,7 +2127,7 @@ void CG_Player( centity_t *cent )
}
CG_PlayerUpgrades( cent, &torso );
-
+
//sanity check that particle systems are stopped when dead
if( es->eFlags & EF_DEAD )
{
@@ -2277,7 +2157,7 @@ void CG_Corpse( centity_t *cent )
int renderfx;
qboolean shadow = qfalse;
float shadowPlane;
- vec3_t origin, liveZ, deadZ;
+ vec3_t origin, aliveZ, deadZ;
float scale;
corpseNum = CG_GetCorpseNum( es->clientNum );
@@ -2297,10 +2177,8 @@ void CG_Corpse( centity_t *cent )
memset( &head, 0, sizeof( head ) );
VectorCopy( cent->lerpOrigin, origin );
- BG_FindBBoxForClass( es->clientNum, liveZ, NULL, NULL, deadZ, NULL );
- origin[ 2 ] -= ( liveZ[ 2 ] - deadZ[ 2 ] );
-
- VectorCopy( es->angles, cent->lerpAngles );
+ BG_ClassBoundingBox( es->clientNum, aliveZ, NULL, NULL, deadZ, NULL );
+ origin[ 2 ] -= ( aliveZ[ 2 ] - deadZ[ 2 ] );
// get the rotation information
if( !ci->nonsegmented )
@@ -2364,11 +2242,11 @@ void CG_Corpse( centity_t *cent )
VectorCopy( origin, legs.lightingOrigin );
legs.shadowPlane = shadowPlane;
legs.renderfx = renderfx;
- legs.origin[ 2 ] += BG_FindZOffsetForClass( es->clientNum );
+ legs.origin[ 2 ] += BG_ClassConfig( es->clientNum )->zOffset;
VectorCopy( legs.origin, legs.oldorigin ); // don't positionally lerp at all
//rescale the model
- scale = BG_FindModelScaleForClass( es->clientNum );
+ scale = BG_ClassConfig( es->clientNum )->modelScale;
if( scale != 1.0f )
{
@@ -2379,7 +2257,6 @@ void CG_Corpse( centity_t *cent )
legs.nonNormalizedAxes = qtrue;
}
- //CG_AddRefEntityWithPowerups( &legs, es->misc, ci->team );
trap_R_AddRefEntityToScene( &legs );
// if the model failed, allow the default nullmodel to be displayed
@@ -2404,7 +2281,6 @@ void CG_Corpse( centity_t *cent )
torso.shadowPlane = shadowPlane;
torso.renderfx = renderfx;
- //CG_AddRefEntityWithPowerups( &torso, es->misc, ci->team );
trap_R_AddRefEntityToScene( &torso );
//
@@ -2423,7 +2299,6 @@ void CG_Corpse( centity_t *cent )
head.shadowPlane = shadowPlane;
head.renderfx = renderfx;
- //CG_AddRefEntityWithPowerups( &head, es->misc, ci->team );
trap_R_AddRefEntityToScene( &head );
}
}
@@ -2475,7 +2350,7 @@ void CG_ResetPlayerEntity( centity_t *cent )
cent->pe.nonseg.pitching = qfalse;
if( cg_debugPosition.integer )
- CG_Printf( "%i ResetPlayerEntity yaw=%i\n", cent->currentState.number, cent->pe.torso.yawAngle );
+ CG_Printf( "%i ResetPlayerEntity yaw=%f\n", cent->currentState.number, cent->pe.torso.yawAngle );
}
/*
@@ -2500,66 +2375,35 @@ void CG_PlayerDisconnect( vec3_t org )
}
}
-/*
-=================
-CG_Bleed
-
-This is the spurt of blood when a character gets hit
-=================
-*/
-void CG_Bleed( vec3_t origin, vec3_t normal, int entityNum )
+centity_t *CG_GetPlayerLocation( void )
{
- pTeam_t team = cgs.clientinfo[ entityNum ].team;
- qhandle_t bleedPS;
- particleSystem_t *ps;
-
- if( !cg_blood.integer )
- return;
+ int i;
+ centity_t *eloc, *best;
+ float bestlen, len;
+ vec3_t origin;
- if( team == PTE_ALIENS )
- bleedPS = cgs.media.alienBleedPS;
- else if( team == PTE_HUMANS )
- bleedPS = cgs.media.humanBleedPS;
- else
- return;
+ best = NULL;
+ bestlen = 0.0f;
- ps = CG_SpawnNewParticleSystem( bleedPS );
+ VectorCopy( cg.predictedPlayerState.origin, origin );
- if( CG_IsParticleSystemValid( &ps ) )
+ for( i = MAX_CLIENTS; i < MAX_GENTITIES; i++ )
{
- CG_SetAttachmentPoint( &ps->attachment, origin );
- CG_SetAttachmentCent( &ps->attachment, &cg_entities[ entityNum ] );
- CG_AttachToPoint( &ps->attachment );
+ eloc = &cg_entities[ i ];
+ if( !eloc->valid || eloc->currentState.eType != ET_LOCATION )
+ continue;
- CG_SetParticleSystemNormal( ps, normal );
- }
-}
+ len = DistanceSquared(origin, eloc->lerpOrigin);
-/*
-===============
-CG_AtHighestClass
+ if( best != NULL && len > bestlen )
+ continue;
-Is the local client at the highest class possible?
-===============
-*/
-qboolean CG_AtHighestClass( void )
-{
- int i;
- qboolean superiorClasses = qfalse;
+ if( !trap_R_inPVS( origin, eloc->lerpOrigin ) )
+ continue;
- for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ )
- {
- if( BG_ClassCanEvolveFromTo(
- cg.predictedPlayerState.stats[ STAT_PCLASS ], i,
- ALIEN_MAX_KILLS, 0 ) >= 0 &&
- BG_FindStagesForClass( i, cgs.alienStage ) &&
- BG_ClassIsAllowed( i ) )
- {
- superiorClasses = qtrue;
- break;
- }
+ bestlen = len;
+ best = eloc;
}
- return !superiorClasses;
+ return best;
}
-
diff --git a/src/cgame/cg_playerstate.c b/src/cgame/cg_playerstate.c
index e1bcb09..8ff9be4 100644
--- a/src/cgame/cg_playerstate.c
+++ b/src/cgame/cg_playerstate.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -26,7 +27,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// following another player or playing back a demo, it will be checked
// when the snapshot transitions like all the other entities
-
#include "cg_local.h"
/*
@@ -245,10 +245,8 @@ CG_CheckLocalSounds
*/
void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops )
{
- int reward;
-
- // don't play the sounds if the player just changed teams
- if( ps->persistant[ PERS_TEAM ] != ops->persistant[ PERS_TEAM ] )
+ // don't play the sounds if the player just spawned
+ if( ps->persistant[ PERS_SPECSTATE ] != ops->persistant[ PERS_SPECSTATE ] )
return;
// health changes of more than -1 should make pain sounds
@@ -257,14 +255,6 @@ void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops )
if( ps->stats[ STAT_HEALTH ] > 0 )
CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[ STAT_HEALTH ] );
}
-
-
- // if we are going into the intermission, don't start any voices
- if( cg.intermissionStarted )
- return;
-
- // reward sounds
- reward = qfalse;
}
@@ -301,7 +291,7 @@ void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops )
}
if( cg.snap->ps.pm_type != PM_INTERMISSION &&
- ps->persistant[ PERS_TEAM ] != TEAM_SPECTATOR )
+ ps->persistant[ PERS_SPECSTATE ] == SPECTATOR_NOT )
CG_CheckLocalSounds( ps, ops );
// run events
@@ -313,5 +303,11 @@ void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops )
cg.duckChange = ps->viewheight - ops->viewheight;
cg.duckTime = cg.time;
}
+
+ // changed team
+ if( ps->stats[ STAT_TEAM ] != ops->stats[ STAT_TEAM ] )
+ {
+ cg.lastHealthCross = 0;
+ cg.chargeMeterAlpha = 0.0f;
+ }
}
-
diff --git a/src/cgame/cg_predict.c b/src/cgame/cg_predict.c
index 03442ed..a791303 100644
--- a/src/cgame/cg_predict.c
+++ b/src/cgame/cg_predict.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -26,7 +27,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// ahead the client's movement.
// It also handles local physics interaction, like fragments bouncing off walls
-
#include "cg_local.h"
static pmove_t cg_pmove;
@@ -138,7 +138,7 @@ static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins,
bmaxs[ 2 ] = zu;
if( i == cg_numSolidEntities )
- BG_FindBBoxForClass( ( ent->misc >> 8 ) & 0xFF, bmins, bmaxs, NULL, NULL, NULL );
+ BG_ClassBoundingBox( ( ent->misc >> 8 ) & 0xFF, bmins, bmaxs, NULL, NULL, NULL );
cmodel = trap_CM_TempBoxModel( bmins, bmaxs );
VectorCopy( vec3_origin, angles );
@@ -273,7 +273,7 @@ int CG_PointContents( const vec3_t point, int passEntityNum )
if( !cmodel )
continue;
- contents |= trap_CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles );
+ contents |= trap_CM_TransformedPointContents( point, cmodel, cent->lerpOrigin, cent->lerpAngles );
}
return contents;
@@ -476,13 +476,13 @@ static int CG_IsUnacceptableError( playerState_t *ps, playerState_t *pps )
if( fabs( AngleDelta( ps->viewangles[ 0 ], pps->viewangles[ 0 ] ) ) > 1.0f ||
fabs( AngleDelta( ps->viewangles[ 1 ], pps->viewangles[ 1 ] ) ) > 1.0f ||
- fabs( AngleDelta( ps->viewangles[ 2 ], pps->viewangles[ 2 ] ) ) > 1.0f )
+ fabs( AngleDelta( ps->viewangles[ 2 ], pps->viewangles[ 2 ] ) ) > 1.0f )
{
return 12;
}
if( pps->viewheight != ps->viewheight )
- return 13;
+ return 13;
if( pps->damageEvent != ps->damageEvent ||
pps->damageYaw != ps->damageYaw ||
@@ -504,13 +504,6 @@ static int CG_IsUnacceptableError( playerState_t *ps, playerState_t *pps )
return 16;
}
- for( i = 0; i < MAX_WEAPONS; i++ )
- {
- // GH FIXME
- if( pps->ammo != ps->ammo || pps->clips != ps->clips )
- return 18;
- }
-
if( pps->generic1 != ps->generic1 ||
pps->loopSound != ps->loopSound )
{
@@ -551,7 +544,6 @@ void CG_PredictPlayerState( void )
{
int cmdNum, current, i;
playerState_t oldPlayerState;
- qboolean moved;
usercmd_t oldestCmd;
usercmd_t latestCmd;
int stateIndex = 0, predictCmd = 0;
@@ -590,12 +582,12 @@ void CG_PredictPlayerState( void )
cg_pmove.debugLevel = cg_debugMove.integer;
if( cg_pmove.ps->pm_type == PM_DEAD )
- cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
+ cg_pmove.tracemask = MASK_DEADSOLID;
else
cg_pmove.tracemask = MASK_PLAYERSOLID;
- if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
- cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies
+ if( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
+ cg_pmove.tracemask = MASK_DEADSOLID; // spectators can fly through bodies
cg_pmove.noFootsteps = 0;
@@ -638,9 +630,15 @@ void CG_PredictPlayerState( void )
}
if( pmove_msec.integer < 8 )
+ {
trap_Cvar_Set( "pmove_msec", "8" );
+ trap_Cvar_Update(&pmove_msec);
+ }
else if( pmove_msec.integer > 33 )
+ {
trap_Cvar_Set( "pmove_msec", "33" );
+ trap_Cvar_Update(&pmove_msec);
+ }
cg_pmove.pmove_fixed = pmove_fixed.integer;// | cg_pmove_fixed.integer;
cg_pmove.pmove_msec = pmove_msec.integer;
@@ -700,22 +698,22 @@ void CG_PredictPlayerState( void )
// make sure the state differences are acceptable
errorcode = CG_IsUnacceptableError( &cg.predictedPlayerState,
&cg.savedPmoveStates[ i ] );
-
+
if( errorcode )
{
if( cg_showmiss.integer )
CG_Printf("errorcode %d at %d\n", errorcode, cg.time);
break;
}
-
+
// this one is almost exact, so we'll copy it in as the starting point
*cg_pmove.ps = cg.savedPmoveStates[ i ];
// advance the head
cg.stateHead = ( i + 1 ) % NUM_SAVED_STATES;
-
+
// set the next command to predict
predictCmd = cg.lastPredictedCommand + 1;
-
+
// a saved state matched, so flag it
error = qfalse;
break;
@@ -737,9 +735,6 @@ void CG_PredictPlayerState( void )
stateIndex = cg.stateHead;
}
- // run cmds
- moved = qfalse;
-
for( cmdNum = current - CMD_BACKUP + 1; cmdNum <= current; cmdNum++ )
{
// get the command
@@ -857,8 +852,6 @@ void CG_PredictPlayerState( void )
stateIndex = ( stateIndex + 1 ) % NUM_SAVED_STATES;
}
- moved = qtrue;
-
// add push trigger movement effects
CG_TouchTriggerPrediction( );
diff --git a/src/cgame/cg_ptr.c b/src/cgame/cg_ptr.c
deleted file mode 100644
index 1881087..0000000
--- a/src/cgame/cg_ptr.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2000-2006 Tim Angus
-
-This file is part of Tremulous.
-
-Tremulous is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Tremulous is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-// cg_ptr.c -- post timeout restoration handling
-
-
-#include "cg_local.h"
-
-#define PTRC_FILE "ptrc.cfg"
-
-/*
-===============
-CG_ReadPTRCode
-
-Read a PTR code from disk
-===============
-*/
-int CG_ReadPTRCode( void )
-{
- int len;
- char text[ 16 ];
- fileHandle_t f;
-
- // load the file
- len = trap_FS_FOpenFile( PTRC_FILE, &f, FS_READ );
- if( len <= 0 )
- return 0;
-
- // should never happen - malformed write
- if( len >= sizeof( text ) - 1 )
- return 0;
-
- trap_FS_Read( text, len, f );
- text[ len ] = 0;
- trap_FS_FCloseFile( f );
-
- return atoi( text );
-}
-
-/*
-===============
-CG_WritePTRCode
-
-Write a PTR code to disk
-===============
-*/
-void CG_WritePTRCode( int code )
-{
- char text[ 16 ];
- fileHandle_t f;
-
- Com_sprintf( text, 16, "%d", code );
-
- // open file
- if( trap_FS_FOpenFile( PTRC_FILE, &f, FS_WRITE ) < 0 )
- return;
-
- // write the code
- trap_FS_Write( text, strlen( text ), f );
-
- trap_FS_FCloseFile( f );
-}
diff --git a/src/cgame/cg_public.h b/src/cgame/cg_public.h
index 543a222..eef8d40 100644
--- a/src/cgame/cg_public.h
+++ b/src/cgame/cg_public.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,51 +17,47 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
+#ifndef CGAME_PUBLIC_H
+#define CGAME_PUBLIC_H
+
+#include "qcommon/q_shared.h"
-#define CMD_BACKUP 64
-#define CMD_MASK (CMD_BACKUP - 1)
+#define CMD_BACKUP 64
+#define CMD_MASK (CMD_BACKUP - 1)
// allow a lot of command backups for very fast systems
// multiple commands may be combined into a single packet, so this
// needs to be larger than PACKET_BACKUP
-
-#define MAX_ENTITIES_IN_SNAPSHOT 256
+#define MAX_ENTITIES_IN_SNAPSHOT 256
// snapshots are a view of the server at a given time
// Snapshots are generated at regular time intervals by the server,
// but they may not be sent if a client's rate level is exceeded, or
// they may be dropped by the network.
-typedef struct
-{
- int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
- int ping;
+typedef struct {
+ int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
+ int ping;
- int serverTime; // server time the message is valid for (in msec)
+ int serverTime; // server time the message is valid for (in msec)
- byte areamask[ MAX_MAP_AREA_BYTES ]; // portalarea visibility bits
+ byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
- playerState_t ps; // complete information about the current player at this time
+ playerState_t ps; // complete information about the current player at this time
- int numEntities; // all of the entities that need to be presented
- entityState_t entities[ MAX_ENTITIES_IN_SNAPSHOT ]; // at the time of this snapshot
+ int numEntities; // all of the entities that need to be presented
+ entityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot
- int numServerCommands; // text based server commands to execute when this
- int serverCommandSequence; // snapshot becomes current
+ int numServerCommands; // text based server commands to execute when this
+ int serverCommandSequence; // snapshot becomes current
} snapshot_t;
-enum
-{
- CGAME_EVENT_NONE,
- CGAME_EVENT_TEAMMENU,
- CGAME_EVENT_SCOREBOARD,
- CGAME_EVENT_EDITHUD
-};
+enum { CGAME_EVENT_NONE, CGAME_EVENT_TEAMMENU, CGAME_EVENT_SCOREBOARD, CGAME_EVENT_EDITHUD };
/*
==================================================================
@@ -70,147 +67,146 @@ functions imported from the main executable
==================================================================
*/
-#define CGAME_IMPORT_API_VERSION 4
-
-typedef enum
-{
- CG_PRINT,
- CG_ERROR,
- CG_MILLISECONDS,
- CG_CVAR_REGISTER,
- CG_CVAR_UPDATE,
- CG_CVAR_SET,
- CG_CVAR_VARIABLESTRINGBUFFER,
- CG_ARGC,
- CG_ARGV,
- CG_ARGS,
- CG_FS_FOPENFILE,
- CG_FS_READ,
- CG_FS_WRITE,
- CG_FS_FCLOSEFILE,
- CG_SENDCONSOLECOMMAND,
- CG_ADDCOMMAND,
- CG_SENDCLIENTCOMMAND,
- CG_UPDATESCREEN,
- CG_CM_LOADMAP,
- CG_CM_NUMINLINEMODELS,
- CG_CM_INLINEMODEL,
- CG_CM_LOADMODEL,
- CG_CM_TEMPBOXMODEL,
- CG_CM_POINTCONTENTS,
- CG_CM_TRANSFORMEDPOINTCONTENTS,
- CG_CM_BOXTRACE,
- CG_CM_TRANSFORMEDBOXTRACE,
- CG_CM_MARKFRAGMENTS,
- CG_S_STARTSOUND,
- CG_S_STARTLOCALSOUND,
- CG_S_CLEARLOOPINGSOUNDS,
- CG_S_ADDLOOPINGSOUND,
- CG_S_UPDATEENTITYPOSITION,
- CG_S_RESPATIALIZE,
- CG_S_REGISTERSOUND,
- CG_S_STARTBACKGROUNDTRACK,
- CG_R_LOADWORLDMAP,
- CG_R_REGISTERMODEL,
- CG_R_REGISTERSKIN,
- CG_R_REGISTERSHADER,
- CG_R_CLEARSCENE,
- CG_R_ADDREFENTITYTOSCENE,
- CG_R_ADDPOLYTOSCENE,
- CG_R_ADDLIGHTTOSCENE,
- CG_R_RENDERSCENE,
- CG_R_SETCOLOR,
+#define CGAME_IMPORT_API_VERSION 4
+
+typedef enum {
+ CG_PRINT,
+ CG_ERROR,
+ CG_MILLISECONDS,
+ CG_CVAR_REGISTER,
+ CG_CVAR_UPDATE,
+ CG_CVAR_SET,
+ CG_CVAR_VARIABLESTRINGBUFFER,
+ CG_ARGC,
+ CG_ARGV,
+ CG_ARGS,
+ CG_FS_FOPENFILE,
+ CG_FS_READ,
+ CG_FS_WRITE,
+ CG_FS_FCLOSEFILE,
+ CG_SENDCONSOLECOMMAND,
+ CG_ADDCOMMAND,
+ CG_SENDCLIENTCOMMAND,
+ CG_UPDATESCREEN,
+ CG_CM_LOADMAP,
+ CG_CM_NUMINLINEMODELS,
+ CG_CM_INLINEMODEL,
+ CG_CM_LOADMODEL,
+ CG_CM_TEMPBOXMODEL,
+ CG_CM_POINTCONTENTS,
+ CG_CM_TRANSFORMEDPOINTCONTENTS,
+ CG_CM_BOXTRACE,
+ CG_CM_TRANSFORMEDBOXTRACE,
+ CG_CM_MARKFRAGMENTS,
+ CG_S_STARTSOUND,
+ CG_S_STARTLOCALSOUND,
+ CG_S_CLEARLOOPINGSOUNDS,
+ CG_S_ADDLOOPINGSOUND,
+ CG_S_UPDATEENTITYPOSITION,
+ CG_S_RESPATIALIZE,
+ CG_S_REGISTERSOUND,
+ CG_S_STARTBACKGROUNDTRACK,
+ CG_R_LOADWORLDMAP,
+ CG_R_REGISTERMODEL,
+ CG_R_REGISTERSKIN,
+ CG_R_REGISTERSHADER,
+ CG_R_CLEARSCENE,
+ CG_R_ADDREFENTITYTOSCENE,
+ CG_R_ADDPOLYTOSCENE,
+ CG_R_ADDLIGHTTOSCENE,
+ CG_R_RENDERSCENE,
+ CG_R_SETCOLOR,
#ifndef MODULE_INTERFACE_11
- CG_R_SETCLIPREGION,
+ CG_R_SETCLIPREGION,
#endif
- CG_R_DRAWSTRETCHPIC,
- CG_R_MODELBOUNDS,
- CG_R_LERPTAG,
- CG_GETGLCONFIG,
- CG_GETGAMESTATE,
- CG_GETCURRENTSNAPSHOTNUMBER,
- CG_GETSNAPSHOT,
- CG_GETSERVERCOMMAND,
- CG_GETCURRENTCMDNUMBER,
- CG_GETUSERCMD,
- CG_SETUSERCMDVALUE,
- CG_R_REGISTERSHADERNOMIP,
- CG_MEMORY_REMAINING,
- CG_R_REGISTERFONT,
- CG_KEY_ISDOWN,
- CG_KEY_GETCATCHER,
- CG_KEY_SETCATCHER,
- CG_KEY_GETKEY,
+ CG_R_DRAWSTRETCHPIC,
+ CG_R_MODELBOUNDS,
+ CG_R_LERPTAG,
+ CG_GETGLCONFIG,
+ CG_GETGAMESTATE,
+ CG_GETCURRENTSNAPSHOTNUMBER,
+ CG_GETSNAPSHOT,
+ CG_GETSERVERCOMMAND,
+ CG_GETCURRENTCMDNUMBER,
+ CG_GETUSERCMD,
+ CG_SETUSERCMDVALUE,
+ CG_R_REGISTERSHADERNOMIP,
+ CG_MEMORY_REMAINING,
+ CG_R_REGISTERFONT,
+ CG_KEY_ISDOWN,
+ CG_KEY_GETCATCHER,
+ CG_KEY_SETCATCHER,
+ CG_KEY_GETKEY,
#ifdef MODULE_INTERFACE_11
- CG_PARSE_ADD_GLOBAL_DEFINE,
- CG_PARSE_LOAD_SOURCE,
- CG_PARSE_FREE_SOURCE,
- CG_PARSE_READ_TOKEN,
- CG_PARSE_SOURCE_FILE_AND_LINE,
+ CG_PARSE_ADD_GLOBAL_DEFINE,
+ CG_PARSE_LOAD_SOURCE,
+ CG_PARSE_FREE_SOURCE,
+ CG_PARSE_READ_TOKEN,
+ CG_PARSE_SOURCE_FILE_AND_LINE,
#endif
- CG_S_STOPBACKGROUNDTRACK,
- CG_REAL_TIME,
- CG_SNAPVECTOR,
- CG_REMOVECOMMAND,
- CG_R_LIGHTFORPOINT,
- CG_CIN_PLAYCINEMATIC,
- CG_CIN_STOPCINEMATIC,
- CG_CIN_RUNCINEMATIC,
- CG_CIN_DRAWCINEMATIC,
- CG_CIN_SETEXTENTS,
- CG_R_REMAP_SHADER,
- CG_S_ADDREALLOOPINGSOUND,
- CG_S_STOPLOOPINGSOUND,
-
- CG_CM_TEMPCAPSULEMODEL,
- CG_CM_CAPSULETRACE,
- CG_CM_TRANSFORMEDCAPSULETRACE,
- CG_R_ADDADDITIVELIGHTTOSCENE,
- CG_GET_ENTITY_TOKEN,
- CG_R_ADDPOLYSTOSCENE,
- CG_R_INPVS,
- CG_FS_SEEK,
- CG_FS_GETFILELIST,
- CG_LITERAL_ARGS,
- CG_CM_BISPHERETRACE,
- CG_CM_TRANSFORMEDBISPHERETRACE,
- CG_GETDEMOSTATE,
- CG_GETDEMOPOS,
- CG_GETDEMONAME,
-
- CG_KEY_KEYNUMTOSTRINGBUF,
- CG_KEY_GETBINDINGBUF,
- CG_KEY_SETBINDING,
+ CG_S_STOPBACKGROUNDTRACK,
+ CG_REAL_TIME,
+ CG_SNAPVECTOR,
+ CG_REMOVECOMMAND,
+ CG_R_LIGHTFORPOINT,
+ CG_CIN_PLAYCINEMATIC,
+ CG_CIN_STOPCINEMATIC,
+ CG_CIN_RUNCINEMATIC,
+ CG_CIN_DRAWCINEMATIC,
+ CG_CIN_SETEXTENTS,
+ CG_R_REMAP_SHADER,
+ CG_S_ADDREALLOOPINGSOUND,
+ CG_S_STOPLOOPINGSOUND,
+
+ CG_CM_TEMPCAPSULEMODEL,
+ CG_CM_CAPSULETRACE,
+ CG_CM_TRANSFORMEDCAPSULETRACE,
+ CG_R_ADDADDITIVELIGHTTOSCENE,
+ CG_GET_ENTITY_TOKEN,
+ CG_R_ADDPOLYSTOSCENE,
+ CG_R_INPVS,
+ CG_FS_SEEK,
+ CG_FS_GETFILELIST,
+ CG_LITERAL_ARGS,
+ CG_CM_BISPHERETRACE,
+ CG_CM_TRANSFORMEDBISPHERETRACE,
+ CG_GETDEMOSTATE,
+ CG_GETDEMOPOS,
+ CG_GETDEMONAME,
+
+ CG_KEY_KEYNUMTOSTRINGBUF,
+ CG_KEY_GETBINDINGBUF,
+ CG_KEY_SETBINDING,
#ifndef MODULE_INTERFACE_11
- CG_PARSE_ADD_GLOBAL_DEFINE,
- CG_PARSE_LOAD_SOURCE,
- CG_PARSE_FREE_SOURCE,
- CG_PARSE_READ_TOKEN,
- CG_PARSE_SOURCE_FILE_AND_LINE,
+ CG_PARSE_ADD_GLOBAL_DEFINE,
+ CG_PARSE_LOAD_SOURCE,
+ CG_PARSE_FREE_SOURCE,
+ CG_PARSE_READ_TOKEN,
+ CG_PARSE_SOURCE_FILE_AND_LINE,
- CG_KEY_SETOVERSTRIKEMODE,
- CG_KEY_GETOVERSTRIKEMODE,
+ CG_KEY_SETOVERSTRIKEMODE,
+ CG_KEY_GETOVERSTRIKEMODE,
- CG_S_SOUNDDURATION,
+ CG_S_SOUNDDURATION,
+ CG_FIELD_COMPLETELIST,
#endif
- CG_MEMSET = 200,
- CG_MEMCPY,
- CG_STRNCPY,
- CG_SIN,
- CG_COS,
- CG_ATAN2,
- CG_SQRT,
- CG_FLOOR,
- CG_CEIL,
-
- CG_TESTPRINTINT,
- CG_TESTPRINTFLOAT,
- CG_ACOS
+ CG_MEMSET = 200,
+ CG_MEMCPY,
+ CG_STRNCPY,
+ CG_SIN,
+ CG_COS,
+ CG_ATAN2,
+ CG_SQRT,
+ CG_FLOOR,
+ CG_CEIL,
+
+ CG_TESTPRINTINT,
+ CG_TESTPRINTFLOAT,
+ CG_ACOS
} cgameImport_t;
-
/*
==================================================================
@@ -219,55 +215,62 @@ functions exported to the main executable
==================================================================
*/
-typedef enum
-{
- CG_INIT,
- // void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
- // called when the level loads or when the renderer is restarted
- // all media should be registered at this time
- // cgame will display loading status by calling SCR_Update, which
- // will call CG_DrawInformation during the loading process
- // reliableCommandSequence will be 0 on fresh loads, but higher for
- // demos, tourney restarts, or vid_restarts
-
- CG_SHUTDOWN,
- // void (*CG_Shutdown)( void );
- // oportunity to flush and close any open files
-
- CG_CONSOLE_COMMAND,
- // qboolean (*CG_ConsoleCommand)( void );
- // a console command has been issued locally that is not recognized by the
- // main game system.
- // use Cmd_Argc() / Cmd_Argv() to read the command, return qfalse if the
- // command is not known to the game
-
- CG_DRAW_ACTIVE_FRAME,
- // void (*CG_DrawActiveFrame)( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
- // Generates and draws a game scene and status information at the given time.
- // If demoPlayback is set, local movement prediction will not be enabled
-
- CG_CROSSHAIR_PLAYER,
- // int (*CG_CrosshairPlayer)( void );
-
- CG_LAST_ATTACKER,
- // int (*CG_LastAttacker)( void );
-
- CG_KEY_EVENT,
- // void (*CG_KeyEvent)( int key, qboolean down );
-
- CG_MOUSE_EVENT,
- // void (*CG_MouseEvent)( int dx, int dy );
- CG_EVENT_HANDLING,
- // void (*CG_EventHandling)(int type);
-
- CG_CONSOLE_TEXT,
- // void (*CG_ConsoleText)( void );
- // pass text that has been printed to the console to cgame
- // use Cmd_Argc() / Cmd_Argv() to read it
-
- CG_VOIP_STRING
- // char *(*CG_VoIPString)( void );
- // returns a string of comma-delimited clientnums based on cl_voipSendTarget
+typedef enum {
+ CG_INIT,
+ // void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
+ // called when the level loads or when the renderer is restarted
+ // all media should be registered at this time
+ // cgame will display loading status by calling SCR_Update, which
+ // will call CG_DrawInformation during the loading process
+ // reliableCommandSequence will be 0 on fresh loads, but higher for
+ // demos, tourney restarts, or vid_restarts
+
+ CG_SHUTDOWN,
+ // void (*CG_Shutdown)( void );
+ // oportunity to flush and close any open files
+
+ CG_CONSOLE_COMMAND,
+ // qboolean (*CG_ConsoleCommand)( void );
+ // a console command has been issued locally that is not recognized by the
+ // main game system.
+ // use Cmd_Argc() / Cmd_Argv() to read the command, return qfalse if the
+ // command is not known to the game
+
+ CG_DRAW_ACTIVE_FRAME,
+ // void (*CG_DrawActiveFrame)( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
+ // Generates and draws a game scene and status information at the given time.
+ // If demoPlayback is set, local movement prediction will not be enabled
+
+ CG_CROSSHAIR_PLAYER,
+ // int (*CG_CrosshairPlayer)( void );
+
+ CG_LAST_ATTACKER,
+ // int (*CG_LastAttacker)( void );
+
+ CG_KEY_EVENT,
+ // void (*CG_KeyEvent)( int key, qboolean down );
+
+ CG_MOUSE_EVENT,
+ // void (*CG_MouseEvent)( int dx, int dy );
+ CG_EVENT_HANDLING,
+ // void (*CG_EventHandling)(int type);
+
+ CG_CONSOLE_TEXT,
+ // void (*CG_ConsoleText)( void );
+ // pass text that has been printed to the console to cgame
+ // use Cmd_Argc() / Cmd_Argv() to read it
+
+ CG_VOIP_STRING,
+ // char *(*CG_VoIPString)( void );
+ // returns a string of comma-delimited clientnums based on cl_voipSendTarget
+
+ CG_CONSOLE_COMPLETARGUMENT
+ // qboolean (*CG_Console_CompleteArgument)( int argNum )
+ // Requests CGAME to try to complete the command line
+ // argument. argNum indicates which argument we're completing. CGAME
+ // uses trap_Argv and trap_Argc to read the command line
+ // contents. Returns true if a completion function is found in
+ // CGAME, otherwise client tries another completion method.
} cgameExport_t;
-//----------------------------------------------
+#endif
diff --git a/src/cgame/cg_rangemarker.c b/src/cgame/cg_rangemarker.c
new file mode 100644
index 0000000..2810b90
--- /dev/null
+++ b/src/cgame/cg_rangemarker.c
@@ -0,0 +1,399 @@
+#include "cg_local.h"
+
+const vec3_t cg_shaderColors[ SHC_NUM_SHADER_COLORS ] =
+{
+ { 0.0f, 0.0f, 0.75f }, // dark blue
+ { 0.3f, 0.35f, 0.625f }, // light blue
+ { 0.0f, 0.625f, 0.563f }, // green-cyan
+ { 0.313f, 0.0f, 0.625f }, // violet
+ { 0.625f, 0.625f, 0.0f }, // yellow
+ { 0.875f, 0.313f, 0.0f }, // orange
+ { 0.375f, 0.625f, 0.375f }, // light green
+ { 0.0f, 0.438f, 0.0f }, // dark green
+ { 1.0f, 0.0f, 0.0f }, // red
+ { 0.625f, 0.375f, 0.4f }, // pink
+ { 0.313f, 0.313f, 0.313f } // grey
+};
+
+/*
+================
+CG_RangeMarkerPreferences
+================
+*/
+qboolean CG_GetRangeMarkerPreferences( qboolean *drawSurface, qboolean *drawIntersection,
+ qboolean *drawFrontline, float *surfaceOpacity,
+ float *lineOpacity, float *lineThickness )
+{
+ *drawSurface = !!cg_rangeMarkerDrawSurface.integer;
+ *drawIntersection = !!cg_rangeMarkerDrawIntersection.integer;
+ *drawFrontline = !!cg_rangeMarkerDrawFrontline.integer;
+ *surfaceOpacity = cg_rangeMarkerSurfaceOpacity.value;
+ *lineOpacity = cg_rangeMarkerLineOpacity.value;
+ *lineThickness = cg_rangeMarkerLineThickness.value;
+
+ if( ( *drawSurface && *surfaceOpacity > 0.0f ) ||
+ ( ( *drawIntersection || *drawFrontline ) && *lineOpacity > 0.0f &&
+ *lineThickness > 0.0f && cg_binaryShaderScreenScale.value > 0.0f ) )
+ {
+ if( *surfaceOpacity > 1.0f )
+ *surfaceOpacity = 1.0f;
+ if( *lineOpacity > 1.0f )
+ *lineOpacity = 1.0f;
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+================
+CG_UpdateBuildableRangeMarkerMask
+================
+*/
+void CG_UpdateBuildableRangeMarkerMask( void )
+{
+ static int mc = 0;
+
+ if( cg_rangeMarkerBuildableTypes.modificationCount != mc )
+ {
+ int brmMask;
+ char buffer[ MAX_CVAR_VALUE_STRING ];
+ char *p, *q;
+ buildable_t buildable;
+
+ brmMask = 0;
+
+ if( !cg_rangeMarkerBuildableTypes.string[ 0 ] )
+ goto empty;
+
+ Q_strncpyz( buffer, cg_rangeMarkerBuildableTypes.string, sizeof( buffer ) );
+ p = &buffer[ 0 ];
+
+ for(;;)
+ {
+ q = strchr( p, ',' );
+ if( q )
+ *q = '\0';
+
+ while( *p == ' ' )
+ ++p;
+
+ buildable = BG_BuildableByName( p )->number;
+
+ if( buildable != BA_NONE )
+ {
+ brmMask |= 1 << buildable;
+ }
+ else if( !Q_stricmp( p, "all" ) )
+ {
+ brmMask |= ( 1 << BA_A_OVERMIND ) | ( 1 << BA_A_SPAWN ) |
+ ( 1 << BA_A_ACIDTUBE ) | ( 1 << BA_A_TRAPPER ) | ( 1 << BA_A_HIVE ) |
+ ( 1 << BA_H_REACTOR ) | ( 1 << BA_H_REPEATER ) | ( 1 << BA_H_DCC ) |
+ ( 1 << BA_H_MGTURRET ) | ( 1 << BA_H_TESLAGEN );
+ }
+ else
+ {
+ char *pp;
+ int only;
+
+ if( !Q_stricmpn( p, "alien", 5 ) )
+ {
+ pp = p + 5;
+ only = ( 1 << BA_A_OVERMIND ) | ( 1 << BA_A_SPAWN ) |
+ ( 1 << BA_A_ACIDTUBE ) | ( 1 << BA_A_TRAPPER ) | ( 1 << BA_A_HIVE );
+ }
+ else if( !Q_stricmpn( p, "human", 5 ) )
+ {
+ pp = p + 5;
+ only = ( 1 << BA_H_REACTOR ) | ( 1 << BA_H_REPEATER ) | ( 1 << BA_H_DCC ) |
+ ( 1 << BA_H_MGTURRET ) | ( 1 << BA_H_TESLAGEN );
+ }
+ else
+ {
+ pp = p;
+ only = ~0;
+ }
+
+ if( pp != p && !*pp )
+ {
+ brmMask |= only;
+ }
+ else if( !Q_stricmp( pp, "support" ) )
+ {
+ brmMask |= only & ( ( 1 << BA_A_OVERMIND ) | ( 1 << BA_A_SPAWN ) |
+ ( 1 << BA_H_REACTOR ) | ( 1 << BA_H_REPEATER ) | ( 1 << BA_H_DCC ) );
+ }
+ else if( !Q_stricmp( pp, "offensive" ) )
+ {
+ brmMask |= only & ( ( 1 << BA_A_ACIDTUBE ) | ( 1 << BA_A_TRAPPER ) | ( 1 << BA_A_HIVE ) |
+ ( 1 << BA_H_MGTURRET ) | ( 1 << BA_H_TESLAGEN ) );
+ }
+ else
+ Com_Printf( S_COLOR_YELLOW "WARNING: unknown buildable or group: %s\n", p );
+ }
+
+ if( q )
+ p = q + 1;
+ else
+ break;
+ }
+
+ empty:
+ trap_Cvar_Set( "cg_buildableRangeMarkerMask", va( "%i", brmMask ) );
+
+ mc = cg_rangeMarkerBuildableTypes.modificationCount;
+ }
+}
+
+// cg_drawtools.c
+//
+/*
+================
+CG_DrawSphere
+================
+*/
+void CG_DrawSphere( const vec3_t center, float radius, int customShader, const float *shaderRGBA )
+{
+ refEntity_t re;
+ memset( &re, 0, sizeof( re ) );
+
+ re.reType = RT_MODEL;
+ re.hModel = cgs.media.sphereModel;
+ re.customShader = customShader;
+ re.renderfx = RF_NOSHADOW;
+ if( shaderRGBA != NULL )
+ {
+ int i;
+ for( i = 0; i < 4; ++i )
+ re.shaderRGBA[ i ] = 255 * shaderRGBA[ i ];
+ }
+
+ VectorCopy( center, re.origin );
+
+ radius *= 0.01f;
+ VectorSet( re.axis[ 0 ], radius, 0, 0 );
+ VectorSet( re.axis[ 1 ], 0, radius, 0 );
+ VectorSet( re.axis[ 2 ], 0, 0, radius );
+ re.nonNormalizedAxes = qtrue;
+
+ trap_R_AddRefEntityToScene( &re );
+}
+
+/*
+================
+CG_DrawSphericalCone
+================
+*/
+void CG_DrawSphericalCone( const vec3_t tip, const vec3_t rotation, float radius,
+ qboolean a240, int customShader, const float *shaderRGBA )
+{
+ refEntity_t re;
+ memset( &re, 0, sizeof( re ) );
+
+ re.reType = RT_MODEL;
+ re.hModel = a240 ? cgs.media.sphericalCone240Model : cgs.media.sphericalCone64Model;
+ re.customShader = customShader;
+ re.renderfx = RF_NOSHADOW;
+ if( shaderRGBA != NULL )
+ {
+ int i;
+ for( i = 0; i < 4; ++i )
+ re.shaderRGBA[ i ] = 255 * shaderRGBA[ i ];
+ }
+
+ VectorCopy( tip, re.origin );
+
+ radius *= 0.01f;
+ AnglesToAxis( rotation, re.axis );
+ VectorScale( re.axis[ 0 ], radius, re.axis[ 0 ] );
+ VectorScale( re.axis[ 1 ], radius, re.axis[ 1 ] );
+ VectorScale( re.axis[ 2 ], radius, re.axis[ 2 ] );
+ re.nonNormalizedAxes = qtrue;
+
+ trap_R_AddRefEntityToScene( &re );
+}
+
+
+/*
+================
+CG_DrawRangeMarker
+================
+*/
+void CG_DrawRangeMarker( rangeMarkerType_t rmType, const vec3_t origin, const float *angles, float range,
+ qboolean drawSurface, qboolean drawIntersection, qboolean drawFrontline,
+ const vec3_t rgb, float surfaceOpacity, float lineOpacity, float lineThickness )
+{
+ if( drawSurface )
+ {
+ qhandle_t pcsh;
+ vec4_t rgba;
+
+ pcsh = cgs.media.plainColorShader;
+ VectorCopy( rgb, rgba );
+ rgba[ 3 ] = surfaceOpacity;
+
+ switch( rmType )
+ {
+ case RMT_SPHERE:
+ CG_DrawSphere( origin, range, pcsh, rgba );
+ break;
+ case RMT_SPHERICAL_CONE_64:
+ CG_DrawSphericalCone( origin, angles, range, qfalse, pcsh, rgba );
+ break;
+ case RMT_SPHERICAL_CONE_240:
+ CG_DrawSphericalCone( origin, angles, range, qtrue, pcsh, rgba );
+ break;
+ }
+ }
+
+ if( drawIntersection || drawFrontline )
+ {
+ const cgMediaBinaryShader_t *mbsh;
+ cgBinaryShaderSetting_t *bshs;
+ int i;
+
+ if( cg.numBinaryShadersUsed >= NUM_BINARY_SHADERS )
+ return;
+ mbsh = &cgs.media.binaryShaders[ cg.numBinaryShadersUsed ];
+
+ if( rmType == RMT_SPHERE )
+ {
+ if( range > lineThickness / 2 )
+ {
+ if( drawIntersection )
+ CG_DrawSphere( origin, range - lineThickness / 2, mbsh->b1, NULL );
+ CG_DrawSphere( origin, range - lineThickness / 2, mbsh->f2, NULL );
+ }
+
+ if( drawIntersection )
+ CG_DrawSphere( origin, range + lineThickness / 2, mbsh->b2, NULL );
+ CG_DrawSphere( origin, range + lineThickness / 2, mbsh->f1, NULL );
+ }
+ else if( rmType == RMT_SPHERICAL_CONE_64 || rmType == RMT_SPHERICAL_CONE_240 )
+ {
+ qboolean a240;
+ float f, r;
+ vec3_t forward, tip;
+
+ a240 = ( rmType == RMT_SPHERICAL_CONE_240 );
+ f = lineThickness * ( a240 ? 0.26f : 0.8f );
+ r = f + lineThickness * ( a240 ? 0.23f : 0.43f );
+ AngleVectors( angles, forward, NULL, NULL );
+
+ if( range > r )
+ {
+ VectorMA( origin, f, forward, tip );
+ if( drawIntersection )
+ CG_DrawSphericalCone( tip, angles, range - r, a240, mbsh->b1, NULL );
+ CG_DrawSphericalCone( tip, angles, range - r, a240, mbsh->f2, NULL );
+ }
+
+ VectorMA( origin, -f, forward, tip );
+ if( drawIntersection )
+ CG_DrawSphericalCone( tip, angles, range + r, a240, mbsh->b2, NULL );
+ CG_DrawSphericalCone( tip, angles, range + r, a240, mbsh->f1, NULL );
+ }
+
+ bshs = &cg.binaryShaderSettings[ cg.numBinaryShadersUsed ];
+
+ for( i = 0; i < 3; ++i )
+ bshs->color[ i ] = 255 * lineOpacity * rgb[ i ];
+ bshs->drawIntersection = drawIntersection;
+ bshs->drawFrontline = drawFrontline;
+
+ ++cg.numBinaryShadersUsed;
+ }
+}
+
+// cg_buildable.c
+
+/*
+================
+CG_BuildableRangeMarkerProperties
+================
+*/
+qboolean CG_GetBuildableRangeMarkerProperties( buildable_t bType, rangeMarkerType_t *rmType, float *range, vec3_t rgb )
+{
+ shaderColorEnum_t shc;
+
+ switch( bType )
+ {
+ case BA_A_SPAWN: *range = CREEP_BASESIZE; shc = SHC_LIGHT_GREEN; break;
+ case BA_A_OVERMIND: *range = CREEP_BASESIZE; shc = SHC_DARK_GREEN; break;
+ case BA_A_ACIDTUBE: *range = ACIDTUBE_RANGE; shc = SHC_RED; break;
+ case BA_A_TRAPPER: *range = TRAPPER_RANGE; shc = SHC_PINK; break;
+ case BA_A_HIVE: *range = HIVE_SENSE_RANGE; shc = SHC_YELLOW; break;
+ case BA_H_MGTURRET: *range = MGTURRET_RANGE; shc = SHC_ORANGE; break;
+ case BA_H_TESLAGEN: *range = TESLAGEN_RANGE; shc = SHC_VIOLET; break;
+ case BA_H_DCC: *range = DC_RANGE; shc = SHC_GREEN_CYAN; break;
+ case BA_H_REACTOR: *range = REACTOR_BASESIZE; shc = SHC_DARK_BLUE; break;
+ case BA_H_REPEATER: *range = REPEATER_BASESIZE; shc = SHC_LIGHT_BLUE; break;
+ default: return qfalse;
+ }
+
+ if( bType == BA_A_TRAPPER )
+ *rmType = RMT_SPHERICAL_CONE_64;
+ else if( bType == BA_H_MGTURRET )
+ *rmType = RMT_SPHERICAL_CONE_240;
+ else
+ *rmType = RMT_SPHERE;
+
+ VectorCopy( cg_shaderColors[ shc ], rgb );
+
+ return qtrue;
+}
+
+/*
+================
+CG_GhostBuildableRangeMarker
+================
+*/
+void CG_GhostBuildableRangeMarker( buildable_t buildable, const vec3_t origin, const vec3_t normal )
+{
+ qboolean drawS, drawI, drawF;
+ float so, lo, th;
+ rangeMarkerType_t rmType;
+ float range;
+ vec3_t rgb;
+
+ if( CG_GetRangeMarkerPreferences( &drawS, &drawI, &drawF, &so, &lo, &th ) &&
+ CG_GetBuildableRangeMarkerProperties( buildable, &rmType, &range, rgb ) )
+ {
+ vec3_t localOrigin, angles;
+
+ if( buildable == BA_A_HIVE || buildable == BA_H_TESLAGEN )
+ VectorMA( origin, BG_BuildableConfig( buildable )->maxs[ 2 ], normal, localOrigin );
+ else
+ VectorCopy( origin, localOrigin );
+
+ if( rmType != RMT_SPHERE )
+ vectoangles( normal, angles );
+
+ CG_DrawRangeMarker( rmType, localOrigin, ( rmType != RMT_SPHERE ? angles : NULL ),
+ range, drawS, drawI, drawF, rgb, so, lo, th );
+ }
+}
+
+// cg_ents.c
+
+/*
+================
+CG_RangeMarker
+================
+*/
+void CG_RangeMarker( centity_t *cent )
+{
+ qboolean drawS, drawI, drawF;
+ float so, lo, th;
+ rangeMarkerType_t rmType;
+ float range;
+ vec3_t rgb;
+
+ if( CG_GetRangeMarkerPreferences( &drawS, &drawI, &drawF, &so, &lo, &th ) &&
+ CG_GetBuildableRangeMarkerProperties( cent->currentState.modelindex, &rmType, &range, rgb ) )
+ {
+ CG_DrawRangeMarker( rmType, cent->lerpOrigin, ( rmType > 0 ? cent->lerpAngles : NULL ),
+ range, drawS, drawI, drawF, rgb, so, lo, th );
+ }
+}
+
diff --git a/src/cgame/cg_scanner.c b/src/cgame/cg_scanner.c
index 033960e..a7df030 100644
--- a/src/cgame/cg_scanner.c
+++ b/src/cgame/cg_scanner.c
@@ -1,12 +1,13 @@
/*
===========================================================================
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -15,15 +16,14 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
-
#include "cg_local.h"
-static entityPos_t entityPositions;
+static entityPos_t entityPositions;
#define HUMAN_SCANNER_UPDATE_PERIOD 700
@@ -39,7 +39,7 @@ void CG_UpdateEntityPositions( void )
centity_t *cent = NULL;
int i;
- if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
if( entityPositions.lastUpdateTime + HUMAN_SCANNER_UPDATE_PERIOD > cg.time )
return;
@@ -58,10 +58,11 @@ void CG_UpdateEntityPositions( void )
{
cent = &cg_entities[ cg.snap->entities[ i ].number ];
- if( cent->currentState.eType == ET_BUILDABLE )
+ if( cent->currentState.eType == ET_BUILDABLE &&
+ !( cent->currentState.eFlags & EF_DEAD ) )
{
- //TA: add to list of item positions (for creep)
- if( cent->currentState.modelindex2 == BIT_ALIENS )
+ // add to list of item positions (for creep)
+ if( cent->currentState.modelindex2 == TEAM_ALIENS )
{
VectorCopy( cent->lerpOrigin, entityPositions.alienBuildablePos[
entityPositions.numAlienBuildables ] );
@@ -71,7 +72,7 @@ void CG_UpdateEntityPositions( void )
if( entityPositions.numAlienBuildables < MAX_GENTITIES )
entityPositions.numAlienBuildables++;
}
- else if( cent->currentState.modelindex2 == BIT_HUMANS )
+ else if( cent->currentState.modelindex2 == TEAM_HUMANS )
{
VectorCopy( cent->lerpOrigin, entityPositions.humanBuildablePos[
entityPositions.numHumanBuildables ] );
@@ -84,7 +85,7 @@ void CG_UpdateEntityPositions( void )
{
int team = cent->currentState.misc & 0x00FF;
- if( team == PTE_ALIENS )
+ if( team == TEAM_ALIENS )
{
VectorCopy( cent->lerpOrigin, entityPositions.alienClientPos[
entityPositions.numAlienClients ] );
@@ -92,7 +93,7 @@ void CG_UpdateEntityPositions( void )
if( entityPositions.numAlienClients < MAX_CLIENTS )
entityPositions.numAlienClients++;
}
- else if( team == PTE_HUMANS )
+ else if( team == TEAM_HUMANS )
{
VectorCopy( cent->lerpOrigin, entityPositions.humanClientPos[
entityPositions.numHumanClients ] );
@@ -104,8 +105,8 @@ void CG_UpdateEntityPositions( void )
}
}
-#define STALKWIDTH 2.0f
-#define BLIPX 16.0f
+#define STALKWIDTH (2.0f * cgDC.aspectScale)
+#define BLIPX (16.0f * cgDC.aspectScale)
#define BLIPY 8.0f
#define FAR_ALPHA 0.8f
#define NEAR_ALPHA 1.2f
@@ -162,7 +163,7 @@ static void CG_DrawBlips( rectDef_t *rect, vec3_t origin, vec4_t colour )
trap_R_SetColor( NULL );
}
-#define BLIPX2 24.0f
+#define BLIPX2 (24.0f * cgDC.aspectScale)
#define BLIPY2 24.0f
/*
@@ -183,15 +184,7 @@ static void CG_DrawDir( rectDef_t *rect, vec3_t origin, vec4_t colour )
float angle;
playerState_t *ps = &cg.snap->ps;
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- {
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- VectorSet( normal, 0.0f, 0.0f, -1.0f );
- else
- VectorCopy( ps->grapplePoint, normal );
- }
- else
- VectorSet( normal, 0.0f, 0.0f, 1.0f );
+ BG_GetClientNormal( ps, normal );
AngleVectors( entityPositions.vangles, view, NULL, NULL );
@@ -363,3 +356,125 @@ void CG_Scanner( rectDef_t *rect, qhandle_t shader, vec4_t color )
CG_DrawBlips( rect, relOrigin, aIabove );
}
}
+
+void THZ_DrawScanner( rectDef_t *rect )
+{
+ vec4_t colorB = { 0.0f, 0.0f, 0.0f, 0.5f };
+ vec4_t color = { 1.0f, 1.0f, 1.0f, 0.2f };
+
+ vec4_t aliencolor = { 1.0f, 0.0f, 0.0f, 0.8f };
+ vec4_t humancolor = { 0.0f, 0.0f, 1.0f, 0.8f };
+ vec4_t buildcolor = { 0.0f, 1.0f, 1.0f, 0.8f };
+ vec4_t buildcolor2 = { 1.0f, 1.0f, 0.0f, 0.8f };
+
+ vec3_t drawOrigin = { 0.0f, 0.0f, 0.0f };
+ vec3_t origin = { 0.0f, 0.0f, 0.0f };
+ vec3_t relOrigin = { 0.0f, 0.0f, 0.0f };
+
+ static vec3_t up = { 0.0f, 0.0f, 1.0f };
+
+ int i;
+
+ if( !thz_radar.integer )
+ return;
+
+ //CG_FillRect( rect->x, rect->y, rect->w, rect->h, colorB );
+
+ // Draw cross
+ CG_FillRect( rect->x + (rect->w/2),
+ rect->y,
+ 1,
+ rect->h,
+ color );
+ CG_FillRect( rect->x,
+ rect->y+(rect->h/2),
+ rect->w,
+ 1,
+ color );
+
+ // update the player positions
+ CG_UpdateEntityPositions( );
+
+ // blips
+ VectorCopy( entityPositions.origin, origin );
+
+ // human buildables
+ for( i = 0; i < entityPositions.numHumanBuildables; i++ )
+ {
+ VectorClear( relOrigin );
+ VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin );
+
+ if( VectorLength( relOrigin ) < thz_radarrange.integer )
+ {
+ RotatePointAroundVector( drawOrigin, up, relOrigin, -entityPositions.vangles[ 1 ] - 90 );
+
+ drawOrigin[ 0 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->w);
+ drawOrigin[ 1 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->h);
+ drawOrigin[ 2 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->w);
+
+ CG_FillRect( rect->x + (rect->w / 2) + -drawOrigin[0] - 5,
+ rect->y + (rect->h / 2) + drawOrigin[1] - 5,
+ 10, 10, buildcolor );
+ }
+ }
+
+ // humans
+ for( i = 0; i < entityPositions.numHumanClients; i++ )
+ {
+ VectorClear( relOrigin );
+ VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );
+
+ if( VectorLength( relOrigin ) < thz_radarrange.integer )
+ {
+ RotatePointAroundVector( drawOrigin, up, relOrigin, -entityPositions.vangles[ 1 ] - 90 );
+
+ drawOrigin[ 0 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->w);
+ drawOrigin[ 1 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->h);
+ drawOrigin[ 2 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->w);
+
+ CG_FillRect( rect->x + (rect->w / 2) + -drawOrigin[0] -3,
+ rect->y + (rect->h / 2) + drawOrigin[1] -3,
+ 6, 6, humancolor );
+ }
+ }
+
+ // alien structures
+ for( i = 0; i < entityPositions.numAlienBuildables; i++ )
+ {
+ VectorClear( relOrigin );
+ VectorSubtract( entityPositions.alienBuildablePos[ i ], origin, relOrigin );
+
+ if( VectorLength( relOrigin ) < thz_radarrange.integer )
+ {
+ RotatePointAroundVector( drawOrigin, up, relOrigin, -entityPositions.vangles[ 1 ] - 90 );
+
+ drawOrigin[ 0 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->w);
+ drawOrigin[ 1 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->h);
+ drawOrigin[ 2 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->w);
+
+ CG_FillRect( rect->x + (rect->w / 2) + -drawOrigin[0] - 5,
+ rect->y + (rect->h / 2) + drawOrigin[1] - 5,
+ 10, 10, buildcolor2 );
+ }
+ }
+
+ // aliens
+ for( i = 0; i < entityPositions.numAlienClients; i++ )
+ {
+ VectorClear( relOrigin );
+ VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin );
+
+ if( VectorLength( relOrigin ) < thz_radarrange.integer )
+ {
+ RotatePointAroundVector( drawOrigin, up, relOrigin, -entityPositions.vangles[ 1 ] - 90 );
+
+ drawOrigin[ 0 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->w);
+ drawOrigin[ 1 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->h);
+ drawOrigin[ 2 ] /= ((float)(1.25f * (float)thz_radarrange.integer) / (float)rect->w);
+
+ CG_FillRect( rect->x + (rect->w / 2) + -drawOrigin[0] -3,
+ rect->y + (rect->h / 2) + drawOrigin[1] -3,
+ 6, 6, aliencolor );
+ }
+ }
+}
diff --git a/src/cgame/cg_servercmds.c b/src/cgame/cg_servercmds.c
index 7fb3e06..4de7586 100644
--- a/src/cgame/cg_servercmds.c
+++ b/src/cgame/cg_servercmds.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -25,7 +26,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// these are processed at snapshot transition time, so there will definately
// be a valid snapshot this frame
-
#include "cg_local.h"
/*
@@ -38,13 +38,13 @@ static void CG_ParseScores( void )
{
int i;
- cg.numScores = atoi( CG_Argv( 1 ) );
+ cg.numScores = ( trap_Argc( ) - 3 ) / 6;
if( cg.numScores > MAX_CLIENTS )
cg.numScores = MAX_CLIENTS;
- cg.teamScores[ 0 ] = atoi( CG_Argv( 2 ) );
- cg.teamScores[ 1 ] = atoi( CG_Argv( 3 ) );
+ cg.teamScores[ 0 ] = atoi( CG_Argv( 1 ) );
+ cg.teamScores[ 1 ] = atoi( CG_Argv( 2 ) );
memset( cg.scores, 0, sizeof( cg.scores ) );
@@ -54,18 +54,17 @@ static void CG_ParseScores( void )
for( i = 0; i < cg.numScores; i++ )
{
//
- cg.scores[ i ].client = atoi( CG_Argv( i * 6 + 4 ) );
- cg.scores[ i ].score = atoi( CG_Argv( i * 6 + 5 ) );
- cg.scores[ i ].ping = atoi( CG_Argv( i * 6 + 6 ) );
- cg.scores[ i ].time = atoi( CG_Argv( i * 6 + 7 ) );
- cg.scores[ i ].weapon = atoi( CG_Argv( i * 6 + 8 ) );
- cg.scores[ i ].upgrade = atoi( CG_Argv( i * 6 + 9 ) );
+ cg.scores[ i ].client = atoi( CG_Argv( i * 6 + 3 ) );
+ cg.scores[ i ].score = atoi( CG_Argv( i * 6 + 4 ) );
+ cg.scores[ i ].ping = atoi( CG_Argv( i * 6 + 5 ) );
+ cg.scores[ i ].time = atoi( CG_Argv( i * 6 + 6 ) );
+ cg.scores[ i ].weapon = atoi( CG_Argv( i * 6 + 7 ) );
+ cg.scores[ i ].upgrade = atoi( CG_Argv( i * 6 + 8 ) );
if( cg.scores[ i ].client < 0 || cg.scores[ i ].client >= MAX_CLIENTS )
cg.scores[ i ].client = 0;
cgs.clientinfo[ cg.scores[ i ].client ].score = cg.scores[ i ].score;
- cgs.clientinfo[ cg.scores[ i ].client ].powerups = 0;
cg.scores[ i ].team = cgs.clientinfo[ cg.scores[ i ].client ].team;
}
@@ -80,22 +79,33 @@ CG_ParseTeamInfo
static void CG_ParseTeamInfo( void )
{
int i;
+ int count;
int client;
- numSortedTeamPlayers = atoi( CG_Argv( 1 ) );
+ count = trap_Argc( );
- for( i = 0; i < numSortedTeamPlayers; i++ )
+ for( i = 1; i < count; i++ ) // i is also incremented when writing into cgs.clientinfo
{
- client = atoi( CG_Argv( i * 6 + 2 ) );
+ client = atoi( CG_Argv( i ) );
+
+ // wrong team? drop the remaining info
+ if( cgs.clientinfo[ client ].team != cg.snap->ps.stats[ STAT_TEAM ] )
+ return;
- sortedTeamPlayers[ i ] = client;
+ if( client < 0 || client >= MAX_CLIENTS )
+ {
+ CG_Printf( "[skipnotify]CG_ParseTeamInfo: bad client number: %d\n", client );
+ return;
+ }
- cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 6 + 3 ) );
- cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) );
- cgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) );
- cgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) );
- cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) );
+ cgs.clientinfo[ client ].location = atoi( CG_Argv( ++i ) );
+ cgs.clientinfo[ client ].health = atoi( CG_Argv( ++i ) );
+ cgs.clientinfo[ client ].curWeaponClass = atoi( CG_Argv( ++i ) );
+ if( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ cgs.clientinfo[ client ].upgrade = atoi( CG_Argv( ++i ) );
}
+
+ cgs.teaminfoReceievedTime = cg.time;
}
@@ -133,13 +143,7 @@ static void CG_ParseWarmup( void )
info = CG_ConfigString( CS_WARMUP );
warmup = atoi( info );
- cg.warmupCount = -1;
-
- if( warmup == 0 && cg.warmup )
- {
- }
-
- cg.warmup = warmup;
+ cg.warmupTime = warmup;
}
/*
@@ -151,19 +155,28 @@ Called on load to set the initial values from configure strings
*/
void CG_SetConfigValues( void )
{
- sscanf( CG_ConfigString( CS_BUILDPOINTS ),
- "%d %d %d %d %d", &cgs.alienBuildPoints,
- &cgs.alienBuildPointsTotal,
- &cgs.humanBuildPoints,
- &cgs.humanBuildPointsTotal,
- &cgs.humanBuildPointsPowered );
+ const char *alienStages = CG_ConfigString( CS_ALIEN_STAGES );
+ const char *humanStages = CG_ConfigString( CS_HUMAN_STAGES );
- sscanf( CG_ConfigString( CS_STAGES ), "%d %d %d %d %d %d", &cgs.alienStage, &cgs.humanStage,
- &cgs.alienKills, &cgs.humanKills, &cgs.alienNextStageThreshold, &cgs.humanNextStageThreshold );
- sscanf( CG_ConfigString( CS_SPAWNS ), "%d %d", &cgs.numAlienSpawns, &cgs.numHumanSpawns );
+ if( alienStages[0] )
+ {
+ sscanf( alienStages, "%d %d %d", &cgs.alienStage, &cgs.alienCredits,
+ &cgs.alienNextStageThreshold );
+ }
+ else
+ cgs.alienStage = cgs.alienCredits = cgs.alienNextStageThreshold = 0;
+
+
+ if( humanStages[0] )
+ {
+ sscanf( humanStages, "%d %d %d", &cgs.humanStage, &cgs.humanCredits,
+ &cgs.humanNextStageThreshold );
+ }
+ else
+ cgs.humanStage = cgs.humanCredits = cgs.humanNextStageThreshold = 0;
cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );
- cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );
+ cg.warmupTime = atoi( CG_ConfigString( CS_WARMUP ) );
}
@@ -224,7 +237,7 @@ CG_AnnounceAlienStageTransistion
*/
static void CG_AnnounceAlienStageTransistion( stage_t from, stage_t to )
{
- if( cg.predictedPlayerState.stats[ STAT_PTEAM ] != PTE_ALIENS )
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] != TEAM_ALIENS )
return;
trap_S_StartLocalSound( cgs.media.alienStageTransition, CHAN_ANNOUNCER );
@@ -238,7 +251,7 @@ CG_AnnounceHumanStageTransistion
*/
static void CG_AnnounceHumanStageTransistion( stage_t from, stage_t to )
{
- if( cg.predictedPlayerState.stats[ STAT_PTEAM ] != PTE_HUMANS )
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] != TEAM_HUMANS )
return;
trap_S_StartLocalSound( cgs.media.humanStageTransition, CHAN_ANNOUNCER );
@@ -272,91 +285,72 @@ static void CG_ConfigStringModified( void )
CG_ParseServerinfo( );
else if( num == CS_WARMUP )
CG_ParseWarmup( );
- else if( num == CS_BUILDPOINTS )
- sscanf( str, "%d %d %d %d %d", &cgs.alienBuildPoints,
- &cgs.alienBuildPointsTotal,
- &cgs.humanBuildPoints,
- &cgs.humanBuildPointsTotal,
- &cgs.humanBuildPointsPowered );
- else if( num == CS_STAGES )
+ else if( num == CS_ALIEN_STAGES )
{
stage_t oldAlienStage = cgs.alienStage;
- stage_t oldHumanStage = cgs.humanStage;
-
- sscanf( str, "%d %d %d %d %d %d",
- &cgs.alienStage, &cgs.humanStage,
- &cgs.alienKills, &cgs.humanKills,
- &cgs.alienNextStageThreshold, &cgs.humanNextStageThreshold );
-
- if( cgs.alienStage != oldAlienStage )
- CG_AnnounceAlienStageTransistion( oldAlienStage, cgs.alienStage );
- if( cgs.humanStage != oldHumanStage )
- CG_AnnounceHumanStageTransistion( oldHumanStage, cgs.humanStage );
- }
- else if( num == CS_SPAWNS )
- sscanf( str, "%d %d", &cgs.numAlienSpawns, &cgs.numHumanSpawns );
- else if( num == CS_LEVEL_START_TIME )
- cgs.levelStartTime = atoi( str );
- else if( num == CS_VOTE_TIME )
- {
- cgs.voteTime = atoi( str );
- cgs.voteModified = qtrue;
+ if( str[0] )
+ {
+ sscanf( str, "%d %d %d", &cgs.alienStage, &cgs.alienCredits,
+ &cgs.alienNextStageThreshold );
- if( cgs.voteTime )
- trap_Cvar_Set( "ui_voteActive", "1" );
+ if( cgs.alienStage != oldAlienStage )
+ CG_AnnounceAlienStageTransistion( oldAlienStage, cgs.alienStage );
+ }
else
- trap_Cvar_Set( "ui_voteActive", "0" );
- }
- else if( num == CS_VOTE_YES )
- {
- cgs.voteYes = atoi( str );
- cgs.voteModified = qtrue;
- }
- else if( num == CS_VOTE_NO )
- {
- cgs.voteNo = atoi( str );
- cgs.voteModified = qtrue;
+ {
+ cgs.alienStage = cgs.alienCredits = cgs.alienNextStageThreshold = 0;
+ }
}
- else if( num == CS_VOTE_STRING )
- Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) );
- else if( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1 )
+ else if( num == CS_HUMAN_STAGES )
{
- int cs_offset = num - CS_TEAMVOTE_TIME;
-
- cgs.teamVoteTime[ cs_offset ] = atoi( str );
- cgs.teamVoteModified[ cs_offset ] = qtrue;
+ stage_t oldHumanStage = cgs.humanStage;
- if( cs_offset == 0 )
+ if( str[0] )
{
- if( cgs.teamVoteTime[ cs_offset ] )
- trap_Cvar_Set( "ui_humanTeamVoteActive", "1" );
- else
- trap_Cvar_Set( "ui_humanTeamVoteActive", "0" );
+ sscanf( str, "%d %d %d", &cgs.humanStage, &cgs.humanCredits,
+ &cgs.humanNextStageThreshold );
+
+ if( cgs.humanStage != oldHumanStage )
+ CG_AnnounceHumanStageTransistion( oldHumanStage, cgs.humanStage );
}
- else if( cs_offset == 1 )
+ else
{
- if( cgs.teamVoteTime[ cs_offset ] )
- trap_Cvar_Set( "ui_alienTeamVoteActive", "1" );
- else
- trap_Cvar_Set( "ui_alienTeamVoteActive", "0" );
+ cgs.humanStage = cgs.humanCredits = cgs.humanNextStageThreshold = 0;
}
}
- else if( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1 )
+ else if( num == CS_LEVEL_START_TIME )
+ cgs.levelStartTime = atoi( str );
+ else if( num >= CS_VOTE_TIME && num < CS_VOTE_TIME + NUM_TEAMS )
{
- cgs.teamVoteYes[ num - CS_TEAMVOTE_YES ] = atoi( str );
- cgs.teamVoteModified[ num - CS_TEAMVOTE_YES ] = qtrue;
+ cgs.voteTime[ num - CS_VOTE_TIME ] = atoi( str );
+ cgs.voteModified[ num - CS_VOTE_TIME ] = qtrue;
+
+ if( num - CS_VOTE_TIME == TEAM_NONE )
+ trap_Cvar_Set( "ui_voteActive", cgs.voteTime[ TEAM_NONE ] ? "1" : "0" );
+ else if( num - CS_VOTE_TIME == TEAM_ALIENS )
+ trap_Cvar_Set( "ui_alienTeamVoteActive",
+ cgs.voteTime[ TEAM_ALIENS ] ? "1" : "0" );
+ else if( num - CS_VOTE_TIME == TEAM_HUMANS )
+ trap_Cvar_Set( "ui_humanTeamVoteActive",
+ cgs.voteTime[ TEAM_HUMANS ] ? "1" : "0" );
}
- else if( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1 )
+ else if( num >= CS_VOTE_YES && num < CS_VOTE_YES + NUM_TEAMS )
{
- cgs.teamVoteNo[ num - CS_TEAMVOTE_NO ] = atoi( str );
- cgs.teamVoteModified[ num - CS_TEAMVOTE_NO ] = qtrue;
+ cgs.voteYes[ num - CS_VOTE_YES ] = atoi( str );
+ cgs.voteModified[ num - CS_VOTE_YES ] = qtrue;
}
- else if( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1 )
+ else if( num >= CS_VOTE_NO && num < CS_VOTE_NO + NUM_TEAMS )
{
- Q_strncpyz( cgs.teamVoteString[ num - CS_TEAMVOTE_STRING ], str,
- sizeof( cgs.teamVoteString[ num - CS_TEAMVOTE_STRING ] ) );
+ cgs.voteNo[ num - CS_VOTE_NO ] = atoi( str );
+ cgs.voteModified[ num - CS_VOTE_NO ] = qtrue;
}
+ else if( num >= CS_VOTE_STRING && num < CS_VOTE_STRING + NUM_TEAMS )
+ Q_strncpyz( cgs.voteString[ num - CS_VOTE_STRING ], str,
+ sizeof( cgs.voteString[ num - CS_VOTE_STRING ] ) );
+ else if( num >= CS_VOTE_CALLER && num < CS_VOTE_CALLER + NUM_TEAMS )
+ Q_strncpyz( cgs.voteCaller[ num - CS_VOTE_CALLER ], str,
+ sizeof( cgs.voteCaller[ num - CS_VOTE_CALLER ] ) );
else if( num == CS_INTERMISSION )
cg.intermissionStarted = atoi( str );
else if( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS )
@@ -413,7 +407,7 @@ static void CG_MapRestart( void )
cg.intermissionStarted = qfalse;
- cgs.voteTime = 0;
+ cgs.voteTime[ TEAM_NONE ] = 0;
cg.mapRestart = qtrue;
@@ -423,574 +417,903 @@ static void CG_MapRestart( void )
// we really should clear more parts of cg here and stop sounds
- // play the "fight" sound if this is a restart without warmup
- if( cg.warmup == 0 )
- CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH * 2 );
-
trap_Cvar_Set( "cg_thirdPerson", "0" );
}
/*
-=================
-CG_RemoveChatEscapeChar
-=================
-*/
-static void CG_RemoveChatEscapeChar( char *text )
-{
- int i, l;
-
- l = 0;
- for( i = 0; text[ i ]; i++ )
- {
- if( text[ i ] == '\x19' )
- continue;
-
- text[ l++ ] = text[ i ];
- }
-
- text[ l ] = '\0';
-}
-
-/*
-===============
-CG_SetUIVars
-
-Set some cvars used by the UI
-===============
-*/
-static void CG_SetUIVars( void )
-{
- int i;
- char carriageCvar[ MAX_TOKEN_CHARS ];
-
- *carriageCvar = 0;
-
- //determine what the player is carrying
- for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
- {
- if( BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) &&
- BG_FindPurchasableForWeapon( i ) )
- strcat( carriageCvar, va( "W%d ", i ) );
- }
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- {
- if( BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) &&
- BG_FindPurchasableForUpgrade( i ) )
- strcat( carriageCvar, va( "U%d ", i ) );
- }
- strcat( carriageCvar, "$" );
-
- trap_Cvar_Set( "ui_carriage", carriageCvar );
-
- trap_Cvar_Set( "ui_stages", va( "%d %d", cgs.alienStage, cgs.humanStage ) );
-}
-
-
-/*
==============
CG_Menu
==============
*/
-void CG_Menu( int menu )
+void CG_Menu( int menu, int arg )
{
- const char *cmd = NULL; // command to send
- const char *longMsg = NULL; // command parameter
- const char *shortMsg = NULL; // non-modal version of message
- CG_SetUIVars( );
+ const char *cmd; // command to send
+ const char *longMsg = NULL; // command parameter
+ const char *shortMsg = NULL; // non-modal version of message
+ const char *dialog;
+ dialogType_t type = 0; // controls which cg_disable var will switch it off
+
+ switch( cg.snap->ps.stats[ STAT_TEAM ] )
+ {
+ case TEAM_ALIENS:
+ dialog = "menu tremulous_alien_dialog\n";
+ break;
+ case TEAM_HUMANS:
+ dialog = "menu tremulous_human_dialog\n";
+ break;
+ default:
+ dialog = "menu tremulous_default_dialog\n";
+ }
+ cmd = dialog;
- // string literals have static storage duration, this is safe,
- // cleaner and much more readable.
switch( menu )
{
case MN_TEAM:
cmd = "menu tremulous_teamselect\n";
+ type = DT_INTERACTIVE;
break;
case MN_A_CLASS:
cmd = "menu tremulous_alienclass\n";
+ type = DT_INTERACTIVE;
break;
case MN_H_SPAWN:
cmd = "menu tremulous_humanitem\n";
+ type = DT_INTERACTIVE;
break;
case MN_A_BUILD:
cmd = "menu tremulous_alienbuild\n";
+ type = DT_INTERACTIVE;
break;
case MN_H_BUILD:
cmd = "menu tremulous_humanbuild\n";
+ type = DT_INTERACTIVE;
break;
case MN_H_ARMOURY:
cmd = "menu tremulous_humanarmoury\n";
+ type = DT_INTERACTIVE;
+ break;
+
+ case MN_H_UNKNOWNITEM:
+ shortMsg = "Unknown item";
+ type = DT_ARMOURYEVOLVE;
break;
case MN_A_TEAMFULL:
longMsg = "The alien team has too many players. Please wait until slots "
"become available or join the human team.";
- shortMsg = "The alien team has too many players\n";
- cmd = "menu tremulous_alien_dialog\n";
+ shortMsg = "The alien team has too many players";
+ type = DT_COMMAND;
break;
case MN_H_TEAMFULL:
longMsg = "The human team has too many players. Please wait until slots "
"become available or join the alien team.";
- shortMsg = "The human team has too many players\n";
- cmd = "menu tremulous_human_dialog\n";
+ shortMsg = "The human team has too many players";
+ type = DT_COMMAND;
break;
- case MN_A_TEAMCHANGEBUILDTIMER:
- longMsg = "You cannot leave the Alien team until your build timer "
- "has expired.";
- shortMsg = "You cannot change teams until your build timer expires.\n";
- cmd = "menu tremulous_alien_dialog\n";
+ case MN_A_TEAMLOCKED:
+ longMsg = "The alien team is locked. You cannot join the aliens "
+ "at this time.";
+ shortMsg = "The alien team is locked";
+ type = DT_COMMAND;
break;
- case MN_H_TEAMCHANGEBUILDTIMER:
- longMsg = "You cannot leave the Human team until your build timer "
- "has expired.";
- shortMsg = "You cannot change teams until your build timer expires.\n";
- cmd = "menu tremulous_human_dialog\n";
+ case MN_H_TEAMLOCKED:
+ longMsg = "The human team is locked. You cannot join the humans "
+ "at this time.";
+ shortMsg = "The human team is locked";
+ type = DT_COMMAND;
+ break;
+
+ case MN_PLAYERLIMIT:
+ longMsg = "The maximum number of playing clients has been reached. "
+ "Please wait until slots become available.";
+ shortMsg = "No free player slots";
+ type = DT_COMMAND;
break;
//===============================
- case MN_H_NOROOM:
- longMsg = "There is no room to build here. Move until the buildable turns "
- "translucent green indicating a valid build location.";
- shortMsg = "There is no room to build here\n";
- cmd = "menu tremulous_human_dialog\n";
+ // Since cheating commands have no default binds, they will often be done
+ // via console. In light of this, perhaps opening a menu is
+ // counterintuitive
+ case MN_CMD_CHEAT:
+ //longMsg = "This action is considered cheating. It can only be used "
+ // "in cheat mode, which is not enabled on this server.";
+ shortMsg = "Cheats are not enabled on this server";
+ type = DT_COMMAND;
break;
- case MN_H_NOPOWER:
- longMsg = "There is no power remaining. Free up power by destroying "
- "existing buildable objects.";
- shortMsg = "There is no power remaining\n";
- cmd = "menu tremulous_human_dialog\n";
+ case MN_CMD_CHEAT_TEAM:
+ shortMsg = "Cheats are not enabled on this server, so "
+ "you may not use this command while on a team";
+ type = DT_COMMAND;
break;
- case MN_H_NOTPOWERED:
- longMsg = "This buildable is not powered. Build a Reactor and/or Repeater "
- "in order to power it.";
- shortMsg = "This buildable is not powered\n";
- cmd = "menu tremulous_human_dialog\n";
+ case MN_CMD_TEAM:
+ //longMsg = "You must be on a team to perform this action. Join the alien"
+ // "or human team and try again.";
+ shortMsg = "Join a team first";
+ type = DT_COMMAND;
break;
- case MN_H_NORMAL:
+ case MN_CMD_SPEC:
+ //longMsg = "You may not perform this action while on a team. Become a "
+ // "spectator before trying again.";
+ shortMsg = "You can only use this command when spectating";
+ type = DT_COMMAND;
+ break;
+
+ case MN_CMD_ALIEN:
+ //longMsg = "You must be on the alien team to perform this action.";
+ shortMsg = "Must be alien to use this command";
+ type = DT_COMMAND;
+ break;
+
+ case MN_CMD_HUMAN:
+ //longMsg = "You must be on the human team to perform this action.";
+ shortMsg = "Must be human to use this command";
+ type = DT_COMMAND;
+ break;
+
+ case MN_CMD_ALIVE:
+ //longMsg = "You must be alive to perform this action.";
+ shortMsg = "Must be alive to use this command";
+ type = DT_COMMAND;
+ break;
+
+
+ //===============================
+
+ case MN_B_NOROOM:
+ longMsg = "There is no room to build here. Move until the structure turns "
+ "translucent green, indicating a valid build location.";
+ shortMsg = "There is no room to build here";
+ type = DT_BUILD;
+ break;
+
+ case MN_B_NORMAL:
longMsg = "Cannot build on this surface. The surface is too steep or "
- "unsuitable to build on. Please choose another site for this "
- "structure.";
- shortMsg = "Cannot build on this surface\n";
- cmd = "menu tremulous_human_dialog\n";
+ "unsuitable for building. Please choose another site for this "
+ "structure.";
+ shortMsg = "Cannot build on this surface";
+ type = DT_BUILD;
+ break;
+
+ case MN_B_CANNOT:
+ longMsg = NULL;
+ shortMsg = "You cannot build that structure";
+ type = DT_BUILD;
+ break;
+
+ // FIXME: MN_H_ and MN_A_?
+ case MN_B_LASTSPAWN:
+ longMsg = "This action would remove your team's last spawn point, "
+ "which often quickly results in a loss. Try building more "
+ "spawns.";
+ shortMsg = "You may not deconstruct the last spawn";
+ break;
+
+ case MN_B_SUDDENDEATH:
+ longMsg = "Neither team has prevailed after a certain time and the "
+ "game has entered Sudden Death. During Sudden Death "
+ "building is not allowed.";
+ shortMsg = "Cannot build during Sudden Death";
+ type = DT_BUILD;
+ break;
+
+ case MN_B_REVOKED:
+ longMsg = "Your teammates have lost faith in your ability to build "
+ "for the team. You will not be allowed to build until your "
+ "team votes to reinstate your building rights.";
+ shortMsg = "Your building rights have been revoked";
+ type = DT_BUILD;
break;
- case MN_H_REACTOR:
- longMsg = "There can only be one Reactor. Destroy the existing one if you "
+ case MN_B_SURRENDER:
+ longMsg = "Your team has decided to admit defeat and concede the game:"
+ "traitors and cowards are not allowed to build.";
+ // too harsh?
+ shortMsg = "Building is denied to traitorous cowards";
+ break;
+
+ //===============================
+
+ case MN_H_NOBP:
+ if( cgs.markDeconstruct )
+ longMsg = "There is no power remaining. Free up power by marking "
+ "existing buildable objects.";
+ else
+ longMsg = "There is no power remaining. Free up power by deconstructing "
+ "existing buildable objects.";
+ shortMsg = "There is no power remaining";
+ type = DT_BUILD;
+ break;
+
+ case MN_H_NOTPOWERED:
+ longMsg = "This buildable is not powered. Build a Reactor and/or Repeater "
+ "in order to power it.";
+ shortMsg = "This buildable is not powered";
+ type = DT_BUILD;
+ break;
+
+ case MN_H_ONEREACTOR:
+ longMsg = "There can only be one Reactor. Deconstruct the existing one if you "
"wish to move it.";
- shortMsg = "There can only be one Reactor\n";
- cmd = "menu tremulous_human_dialog\n";
+ shortMsg = "There can only be one Reactor";
+ type = DT_BUILD;
break;
- case MN_H_REPEATER:
+ case MN_H_NOPOWERHERE:
longMsg = "There is no power here. If available, a Repeater may be used to "
"transmit power to this location.";
- shortMsg = "There is no power here\n";
- cmd = "menu tremulous_human_dialog\n";
+ shortMsg = "There is no power here";
+ type = DT_BUILD;
break;
case MN_H_NODCC:
longMsg = "There is no Defense Computer. A Defense Computer is needed to "
"build this.";
- shortMsg = "There is no Defense Computer\n";
- cmd = "menu tremulous_human_dialog\n";
- break;
-
- case MN_H_TNODEWARN:
- longMsg = "WARNING: This Telenode will not be powered. Build near a power "
- "structure to prevent seeing this message again.";
- shortMsg = "This Telenode will not be powered\n";
- cmd = "menu tremulous_human_dialog\n";
- break;
-
- case MN_H_RPTWARN:
- longMsg = "WARNING: This Repeater will not be powered as there is no parent "
- "Reactor providing power. Build a Reactor.";
- shortMsg = "This Repeater will not be powered\n";
- cmd = "menu tremulous_human_dialog\n";
+ shortMsg = "There is no Defense Computer";
+ type = DT_BUILD;
break;
- case MN_H_RPTWARN2:
+ case MN_H_RPTPOWERHERE:
longMsg = "This area already has power. A Repeater is not required here.";
- shortMsg = "This area already has power\n";
- cmd = "menu tremulous_human_dialog\n";
+ shortMsg = "This area already has power";
+ type = DT_BUILD;
break;
case MN_H_NOSLOTS:
longMsg = "You have no room to carry this. Please sell any conflicting "
"upgrades before purchasing this item.";
- shortMsg = "You have no room to carry this\n";
- cmd = "menu tremulous_human_dialog\n";
+ shortMsg = "You have no room to carry this";
+ type = DT_ARMOURYEVOLVE;
break;
case MN_H_NOFUNDS:
longMsg = "Insufficient funds. You do not have enough credits to perform "
"this action.";
- shortMsg = "Insufficient funds\n";
- cmd = "menu tremulous_human_dialog\n";
+ shortMsg = "Insufficient funds";
+ type = DT_ARMOURYEVOLVE;
break;
case MN_H_ITEMHELD:
longMsg = "You already hold this item. It is not possible to carry multiple "
"items of the same type.";
- shortMsg = "You already hold this item\n";
- cmd = "menu tremulous_human_dialog\n";
+ shortMsg = "You already hold this item";
+ type = DT_ARMOURYEVOLVE;
break;
case MN_H_NOARMOURYHERE:
longMsg = "You must be near a powered Armoury in order to purchase "
- "weapons, upgrades or non-energy ammunition.";
- shortMsg = "You must be near a powered Armoury\n";
- cmd = "menu tremulous_human_dialog\n";
+ "weapons, upgrades or ammunition.";
+ shortMsg = "You must be near a powered Armoury";
+ type = DT_ARMOURYEVOLVE;
break;
case MN_H_NOENERGYAMMOHERE:
- longMsg = "You must be near an Armoury, Reactor or Repeater in order "
- "to purchase energy ammunition.";
- shortMsg = "You must be near an Armoury, Reactor or Repeater\n";
- cmd = "menu tremulous_human_dialog\n";
+ longMsg = "You must be near a Reactor or a powered Armoury or Repeater "
+ "in order to purchase energy ammunition.";
+ shortMsg = "You must be near a Reactor or a powered Armoury or Repeater";
+ type = DT_ARMOURYEVOLVE;
break;
case MN_H_NOROOMBSUITON:
longMsg = "There is not enough room here to put on a Battle Suit. "
"Make sure you have enough head room to climb in.";
- shortMsg = "Not enough room here to put on a Battle Suit\n";
- cmd = "menu tremulous_human_dialog\n";
+ shortMsg = "Not enough room here to put on a Battle Suit";
+ type = DT_ARMOURYEVOLVE;
break;
case MN_H_NOROOMBSUITOFF:
longMsg = "There is not enough room here to take off your Battle Suit. "
"Make sure you have enough head room to climb out.";
- shortMsg = "Not enough room here to take off your Battle Suit\n";
- cmd = "menu tremulous_human_dialog\n";
+ shortMsg = "Not enough room here to take off your Battle Suit";
+ type = DT_ARMOURYEVOLVE;
break;
case MN_H_ARMOURYBUILDTIMER:
longMsg = "You are not allowed to buy or sell weapons until your "
"build timer has expired.";
- shortMsg = "You can not buy or sell weapos until your build timer "
- "expires\n";
- cmd = "menu tremulous_human_dialog\n";
+ shortMsg = "You can not buy or sell weapons until your build timer "
+ "expires";
+ type = DT_ARMOURYEVOLVE;
break;
+ case MN_H_DEADTOCLASS:
+ shortMsg = "You must be dead to use the class command";
+ type = DT_COMMAND;
+ break;
- //===============================
-
- case MN_A_NOROOM:
- longMsg = "There is no room to build here. Move until the structure turns "
- "translucent green indicating a valid build location.";
- shortMsg = "There is no room to build here\n";
- cmd = "menu tremulous_alien_dialog\n";
+ case MN_H_UNKNOWNSPAWNITEM:
+ shortMsg = "Unknown starting item";
+ type = DT_COMMAND;
break;
+ //===============================
+
case MN_A_NOCREEP:
longMsg = "There is no creep here. You must build near existing Eggs or "
"the Overmind. Alien structures will not support themselves.";
- shortMsg = "There is no creep here\n";
- cmd = "menu tremulous_alien_dialog\n";
+ shortMsg = "There is no creep here";
+ type = DT_BUILD;
break;
case MN_A_NOOVMND:
longMsg = "There is no Overmind. An Overmind must be built to control "
- "the structure you tried to place";
- shortMsg = "There is no Overmind\n";
- cmd = "menu tremulous_alien_dialog\n";
- break;
-
- case MN_A_OVERMIND:
- longMsg = "There can only be one Overmind. Destroy the existing one if you "
- "wish to move it.";
- shortMsg = "There can only be one Overmind\n";
- cmd = "menu tremulous_alien_dialog\n";
+ "the structure you tried to place.";
+ shortMsg = "There is no Overmind";
+ type = DT_BUILD;
break;
- case MN_A_HOVEL:
- longMsg = "There can only be one Hovel. Destroy the existing one if you "
+ case MN_A_ONEOVERMIND:
+ longMsg = "There can only be one Overmind. Deconstruct the existing one if you "
"wish to move it.";
- shortMsg = "There can only be one Hovel\n";
- cmd = "menu tremulous_alien_dialog\n";
+ shortMsg = "There can only be one Overmind";
+ type = DT_BUILD;
break;
- case MN_A_NOASSERT:
- longMsg = "The Overmind cannot control any more structures. Destroy existing "
+ case MN_A_NOBP:
+ longMsg = "The Overmind cannot control any more structures. Deconstruct existing "
"structures to build more.";
- shortMsg = "The Overmind cannot control any more structures\n";
- cmd = "menu tremulous_alien_dialog\n";
- break;
-
- case MN_A_SPWNWARN:
- longMsg = "WARNING: This spawn will not be controlled by an Overmind. "
- "Build an Overmind to prevent seeing this message again.";
- shortMsg = "This spawn will not be controlled by an Overmind\n";
- cmd = "menu tremulous_alien_dialog\n";
- break;
-
- case MN_A_NORMAL:
- longMsg = "Cannot build on this surface. This surface is too steep or "
- "unsuitable to build on. Please choose another site for this "
- "structure.";
- shortMsg = "Cannot build on this surface\n";
- cmd = "menu tremulous_alien_dialog\n";
+ shortMsg = "The Overmind cannot control any more structures";
+ type = DT_BUILD;
break;
case MN_A_NOEROOM:
longMsg = "There is no room to evolve here. Move away from walls or other "
- "nearby objects and try again.";
- cmd = "menu tremulous_alien_dialog\n";
- shortMsg = "There is no room to evolve here\n";
+ "nearby objects and try again.";
+ shortMsg = "There is no room to evolve here";
+ type = DT_ARMOURYEVOLVE;
break;
case MN_A_TOOCLOSE:
longMsg = "This location is too close to the enemy to evolve. Move away "
- "until you are no longer aware of the enemy's presence and try "
- "again.";
- shortMsg = "This location is too close to the enemy to evolve\n";
- cmd = "menu tremulous_alien_dialog\n";
+ "from the enemy's presence and try again.";
+ shortMsg = "This location is too close to the enemy to evolve";
+ type = DT_ARMOURYEVOLVE;
break;
case MN_A_NOOVMND_EVOLVE:
longMsg = "There is no Overmind. An Overmind must be built to allow "
"you to upgrade.";
- shortMsg = "There is no Overmind\n";
- cmd = "menu tremulous_alien_dialog\n";
+ shortMsg = "There is no Overmind";
+ type = DT_ARMOURYEVOLVE;
break;
case MN_A_EVOLVEBUILDTIMER:
- longMsg = "You cannot Evolve until your build timer has expired.";
- shortMsg = "You cannot Evolve until your build timer expires\n";
- cmd = "menu tremulous_alien_dialog\n";
+ longMsg = "You cannot evolve until your build timer has expired.";
+ shortMsg = "You cannot evolve until your build timer expires";
+ type = DT_ARMOURYEVOLVE;
break;
- case MN_A_HOVEL_OCCUPIED:
- longMsg = "This Hovel is already occupied by another builder.";
- shortMsg = "This Hovel is already occupied by another builder\n";
- cmd = "menu tremulous_alien_dialog\n";
+ case MN_A_INFEST:
+ trap_Cvar_Set( "ui_currentClass",
+ va( "%d %d", cg.snap->ps.stats[ STAT_CLASS ],
+ cg.snap->ps.persistant[ PERS_CREDIT ] ) );
+
+ cmd = "menu tremulous_alienupgrade\n";
+ type = DT_INTERACTIVE;
break;
- case MN_A_HOVEL_BLOCKED:
- longMsg = "The exit to this Hovel is currently blocked. Please wait until it "
- "becomes clear then try again.";
- shortMsg = "The exit to this Hovel is currently blocked\n";
- cmd = "menu tremulous_alien_dialog\n";
+ case MN_A_CANTEVOLVE:
+ shortMsg = va( "You cannot evolve into a %s",
+ BG_ClassConfig( arg )->humanName );
+ type = DT_ARMOURYEVOLVE;
break;
- case MN_A_HOVEL_EXIT:
- longMsg = "The exit to this Hovel would always be blocked. Please choose "
- "a more suitable location.";
- shortMsg = "The exit to this Hovel would always be blocked\n";
- cmd = "menu tremulous_alien_dialog\n";
+ case MN_A_EVOLVEWALLWALK:
+ shortMsg = "You cannot evolve while wallwalking";
+ type = DT_ARMOURYEVOLVE;
break;
- case MN_A_INFEST:
- trap_Cvar_Set( "ui_currentClass", va( "%d %d", cg.snap->ps.stats[ STAT_PCLASS ],
- cg.snap->ps.persistant[ PERS_CREDIT ] ) );
- cmd = "menu tremulous_alienupgrade\n";
+ case MN_A_UNKNOWNCLASS:
+ shortMsg = "Unknown class";
+ type = DT_ARMOURYEVOLVE;
+ break;
+
+ case MN_A_CLASSNOTSPAWN:
+ shortMsg = va( "You cannot spawn as a %s",
+ BG_ClassConfig( arg )->humanName );
+ type = DT_ARMOURYEVOLVE;
+ break;
+
+ case MN_A_CLASSNOTALLOWED:
+ shortMsg = va( "The %s is not allowed",
+ BG_ClassConfig( arg )->humanName );
+ type = DT_ARMOURYEVOLVE;
+ break;
+
+ case MN_A_CLASSNOTATSTAGE:
+ shortMsg = va( "The %s is not allowed at Stage %d",
+ BG_ClassConfig( arg )->humanName,
+ cgs.alienStage + 1 );
+ type = DT_ARMOURYEVOLVE;
break;
default:
Com_Printf( "cgame: debug: no such menu %d\n", menu );
}
+
+ if( type == DT_ARMOURYEVOLVE && cg_disableUpgradeDialogs.integer )
+ return;
- if( !cg_disableWarningDialogs.integer || !shortMsg )
- {
- // Player either wants dialog window or there's no short message
- if( cmd )
- {
- if( longMsg )
- trap_Cvar_Set( "ui_dialog", longMsg );
+ if( type == DT_BUILD && cg_disableBuildDialogs.integer )
+ return;
- trap_SendConsoleCommand( cmd );
- }
- }
- else
+ if( type == DT_COMMAND && cg_disableCommandDialogs.integer )
+ return;
+
+ if( cmd != dialog )
+ {
+ trap_SendConsoleCommand( cmd );
+ }
+ else if( longMsg && cg_disableWarningDialogs.integer == 0 )
{
- // There is short message and player wants it
- CG_Printf( shortMsg );
- }
+ trap_Cvar_Set( "ui_dialog", longMsg );
+ trap_SendConsoleCommand( cmd );
+ }
+ else if( shortMsg && cg_disableWarningDialogs.integer < 2 )
+ {
+ CG_Printf( "%s\n", shortMsg );
+ }
}
/*
=================
-CG_ServerCommand
-
-The string has been tokenized and can be retrieved with
-Cmd_Argc() / Cmd_Argv()
+CG_Say
=================
*/
-static void CG_ServerCommand( void )
+static void CG_Say( int clientNum, saymode_t mode, const char *text )
{
- const char *cmd;
- char text[ MAX_SAY_TEXT ];
+ char *name;
+ char prefix[ 11 ] = "";
+ char *ignore = "";
+ const char *location = "";
+ char *color;
+ char *maybeColon;
+
+ if( clientNum >= 0 && clientNum < MAX_CLIENTS )
+ {
+ clientInfo_t *ci = &cgs.clientinfo[ clientNum ];
+ char *tcolor = S_COLOR_WHITE;
- cmd = CG_Argv( 0 );
+ name = ci->name;
- if( !cmd[ 0 ] )
- {
- // server claimed the command
- return;
- }
+ if( ci->team == TEAM_ALIENS )
+ tcolor = S_COLOR_RED;
+ else if( ci->team == TEAM_HUMANS )
+ tcolor = S_COLOR_CYAN;
- if( !strcmp( cmd, "cp" ) )
- {
- CG_CenterPrint( CG_Argv( 1 ), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- return;
- }
+ if( cg_chatTeamPrefix.integer )
+ Com_sprintf( prefix, sizeof( prefix ), "[%s%c" S_COLOR_WHITE "] ",
+ tcolor, toupper( *( BG_TeamName( ci->team ) ) ) );
- if( !strcmp( cmd, "cs" ) )
- {
- CG_ConfigStringModified( );
- return;
+ if( ( mode == SAY_TEAM || mode == SAY_AREA ) &&
+ cg.snap->ps.pm_type != PM_INTERMISSION )
+ {
+ int locationNum;
+
+ if( clientNum == cg.snap->ps.clientNum )
+ {
+ centity_t *locent;
+
+ locent = CG_GetPlayerLocation( );
+ if( locent )
+ locationNum = locent->currentState.generic1;
+ else
+ locationNum = -1;
+ }
+ else
+ locationNum = ci->location;
+
+ if( locationNum >= 0 && locationNum < MAX_LOCATIONS )
+ {
+ const char *s = CG_ConfigString( CS_LOCATIONS + locationNum );
+
+ if( *s )
+ location = va( " (%s" S_COLOR_WHITE ")", s );
+ }
+ }
}
+ else
+ name = "console";
- if( !strcmp( cmd, "print" ) )
+ // IRC-like /me parsing
+ if( mode != SAY_RAW && Q_stricmpn( text, "/me ", 4 ) == 0 )
{
- CG_Printf( "%s", CG_Argv( 1 ) );
- return;
+ text += 4;
+ Q_strcat( prefix, sizeof( prefix ), "* " );
+ maybeColon = "";
}
+ else
+ maybeColon = ":";
- if( !strcmp( cmd, "chat" ) )
+ switch( mode )
{
- if( !cg_teamChatsOnly.integer )
- {
- Q_strncpyz( text, CG_Argv( 1 ), MAX_SAY_TEXT );
- if( Q_stricmpn( text, "[skipnotify]", 12 ) )
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- CG_RemoveChatEscapeChar( text );
+ case SAY_ALL:
+ // might already be ignored but in that case no harm is done
+ if( cg_teamChatsOnly.integer )
+ ignore = "[skipnotify]";
+
+#ifdef MODULE_INTERFACE_11
+ CG_Printf( "%s%s%s" S_COLOR_WHITE "%s " S_COLOR_GREEN "%s\n",
+ ignore, prefix, name, maybeColon, text );
+#else
+ CG_Printf( "%s%s%s" S_COLOR_WHITE "%s %c" S_COLOR_GREEN "%s\n",
+ ignore, prefix, name, maybeColon, INDENT_MARKER, text );
+#endif
+ break;
+ case SAY_TEAM:
+#ifdef MODULE_INTERFACE_11
+ CG_Printf( "%s%s(%s" S_COLOR_WHITE ")%s%s " S_COLOR_CYAN "%s\n",
+ ignore, prefix, name, location, maybeColon, text );
+#else
+ CG_Printf( "%s%s(%s" S_COLOR_WHITE ")%s%s %c" S_COLOR_CYAN "%s\n",
+ ignore, prefix, name, location, maybeColon, INDENT_MARKER, text );
+#endif
+ break;
+ case SAY_ADMINS:
+ case SAY_ADMINS_PUBLIC:
+#ifdef MODULE_INTERFACE_11
+ CG_Printf( "%s%s%s%s" S_COLOR_WHITE "%s " S_COLOR_MAGENTA "%s\n",
+ ignore, prefix,
+ ( mode == SAY_ADMINS ) ? "[ADMIN]" : "[PLAYER]",
+ name, maybeColon, text );
+#else
+ CG_Printf( "%s%s%s%s" S_COLOR_WHITE "%s %c" S_COLOR_MAGENTA "%s\n",
+ ignore, prefix,
+ ( mode == SAY_ADMINS ) ? "[ADMIN]" : "[PLAYER]",
+ name, maybeColon, INDENT_MARKER, text );
+#endif
+ break;
+ case SAY_AREA:
+#ifdef MODULE_INTERFACE_11
+ CG_Printf( "%s%s<%s" S_COLOR_WHITE ">%s%s " S_COLOR_BLUE "%s\n",
+ ignore, prefix, name, location, maybeColon, text );
+#else
+ CG_Printf( "%s%s<%s" S_COLOR_WHITE ">%s%s %c" S_COLOR_BLUE "%s\n",
+ ignore, prefix, name, location, maybeColon, INDENT_MARKER, text );
+#endif
+ break;
+ case SAY_PRIVMSG:
+ case SAY_TPRIVMSG:
+ color = ( mode == SAY_TPRIVMSG ) ? S_COLOR_CYAN : S_COLOR_GREEN;
+#ifdef MODULE_INTERFACE_11
+ CG_Printf( "%s%s[%s" S_COLOR_WHITE " -> %s" S_COLOR_WHITE "]%s %s%s\n",
+ ignore, prefix, name, cgs.clientinfo[ cg.clientNum ].name,
+ maybeColon, color, text );
+#else
+ CG_Printf( "%s%s[%s" S_COLOR_WHITE " -> %s" S_COLOR_WHITE "]%s %c%s%s\n",
+ ignore, prefix, name, cgs.clientinfo[ cg.clientNum ].name,
+ maybeColon, INDENT_MARKER, color, text );
+#endif
+ if( !ignore[0] )
+ {
+ CG_CenterPrint( va( "%sPrivate message from: " S_COLOR_WHITE "%s",
+ color, name ), 200, GIANTCHAR_WIDTH * 4 );
+ if( clientNum < 0 || clientNum >= MAX_CLIENTS )
+ clientNum = cg.clientNum;
+ CG_Printf( ">> to reply, say: /m %d [your message] <<\n", clientNum );
+ }
+ break;
+ case SAY_RAW:
CG_Printf( "%s\n", text );
- }
-
- return;
+ break;
}
- if( !strcmp( cmd, "tchat" ) )
+ switch( mode )
{
- Q_strncpyz( text, CG_Argv( 1 ), MAX_SAY_TEXT );
- if( Q_stricmpn( text, "[skipnotify]", 12 ) )
- {
- if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ case SAY_TEAM:
+ case SAY_AREA:
+ case SAY_TPRIVMSG:
+ if( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ {
trap_S_StartLocalSound( cgs.media.alienTalkSound, CHAN_LOCAL_SOUND );
- else if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ break;
+ }
+ else if( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ {
trap_S_StartLocalSound( cgs.media.humanTalkSound, CHAN_LOCAL_SOUND );
- else
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- }
- CG_RemoveChatEscapeChar( text );
- CG_Printf( "%s\n", text );
- return;
+ break;
+ }
+ default:
+ trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
}
+}
- if( !strcmp( cmd, "scores" ) )
- {
- CG_ParseScores( );
- return;
- }
+/*
+=================
+CG_VoiceTrack
- if( !strcmp( cmd, "tinfo" ) )
+return the voice indexed voice track or print errors quietly to console
+in case someone is on an unpure server and wants to know which voice pak
+is missing or incomplete
+=================
+*/
+static voiceTrack_t *CG_VoiceTrack( char *voice, int cmd, int track )
+{
+ voice_t *v;
+ voiceCmd_t *c;
+ voiceTrack_t *t;
+
+ v = BG_VoiceByName( cgs.voices, voice );
+ if( !v )
{
- CG_ParseTeamInfo( );
- return;
+ CG_Printf( "[skipnotify]WARNING: could not find voice \"%s\"\n", voice );
+ return NULL;
}
-
- if( !strcmp( cmd, "map_restart" ) )
+ c = BG_VoiceCmdByNum( v->cmds, cmd );
+ if( !c )
{
- CG_MapRestart( );
- return;
+ CG_Printf( "[skipnotify]WARNING: could not find command %d "
+ "in voice \"%s\"\n", cmd, voice );
+ return NULL;
}
-
- if( Q_stricmp( cmd, "remapShader" ) == 0 )
+ t = BG_VoiceTrackByNum( c->tracks, track );
+ if( !t )
{
- if( trap_Argc( ) == 4 )
- trap_R_RemapShader( CG_Argv( 1 ), CG_Argv( 2 ), CG_Argv( 3 ) );
+ CG_Printf( "[skipnotify]WARNING: could not find track %d for command %d in "
+ "voice \"%s\"\n", track, cmd, voice );
+ return NULL;
}
+ return t;
+}
- // clientLevelShot is sent before taking a special screenshot for
- // the menu system during development
- if( !strcmp( cmd, "clientLevelShot" ) )
- {
- cg.levelShot = qtrue;
+/*
+=================
+CG_ParseVoice
+
+voice clientNum vChan cmdNum trackNum [sayText]
+=================
+*/
+static void CG_ParseVoice( void )
+{
+ int clientNum;
+ int vChan;
+ char sayText[ MAX_SAY_TEXT] = {""};
+ voiceTrack_t *track;
+ clientInfo_t *ci;
+
+ if( trap_Argc() < 5 || trap_Argc() > 6 )
return;
- }
- //the server has triggered a menu
- if( !strcmp( cmd, "servermenu" ) )
- {
- if( trap_Argc( ) == 2 && !cg.demoPlayback )
- CG_Menu( atoi( CG_Argv( 1 ) ) );
+ if( trap_Argc() == 6 )
+ Q_strncpyz( sayText, CG_Argv( 5 ), sizeof( sayText ) );
+ clientNum = atoi( CG_Argv( 1 ) );
+ if( clientNum < 0 || clientNum >= MAX_CLIENTS )
return;
- }
- //the server thinks this client should close all menus
- if( !strcmp( cmd, "serverclosemenus" ) )
- {
- trap_SendConsoleCommand( "closemenus\n" );
+ vChan = atoi( CG_Argv( 2 ) );
+ if( vChan < 0 || vChan >= VOICE_CHAN_NUM_CHANS )
return;
- }
- //poison cloud effect needs to be reliable
- if( !strcmp( cmd, "poisoncloud" ) )
- {
- cg.poisonedTime = cg.time;
+ if( cg_teamChatsOnly.integer && vChan != VOICE_CHAN_TEAM )
+ return;
- if( CG_IsParticleSystemValid( &cg.poisonCloudPS ) )
- {
- cg.poisonCloudPS = CG_SpawnNewParticleSystem( cgs.media.poisonCloudPS );
- CG_SetAttachmentCent( &cg.poisonCloudPS->attachment, &cg.predictedPlayerEntity );
- CG_AttachToCent( &cg.poisonCloudPS->attachment );
- }
+ ci = &cgs.clientinfo[ clientNum ];
+ // this joker is still talking
+ if( ci->voiceTime > cg.time )
return;
- }
- if( !strcmp( cmd, "weaponswitch" ) )
+ track = CG_VoiceTrack( ci->voice, atoi( CG_Argv( 3 ) ), atoi( CG_Argv( 4 ) ) );
+
+ // keep track of how long the player will be speaking
+ // assume it takes 3s to say "*unintelligible gibberish*"
+ if( track )
+ ci->voiceTime = cg.time + track->duration;
+ else
+ ci->voiceTime = cg.time + 3000;
+
+ if( !sayText[ 0 ] )
{
- CG_Printf( "client weaponswitch\n" );
- if( trap_Argc( ) == 2 )
+ if( track )
+ Q_strncpyz( sayText, track->text, sizeof( sayText ) );
+ else
+ Q_strncpyz( sayText, "*unintelligible gibberish*", sizeof( sayText ) );
+ }
+
+ if( !cg_noVoiceText.integer )
+ {
+ switch( vChan )
{
- cg.weaponSelect = atoi( CG_Argv( 1 ) );
- cg.weaponSelectTime = cg.time;
+ case VOICE_CHAN_ALL:
+ CG_Say( clientNum, SAY_ALL, sayText );
+ break;
+ case VOICE_CHAN_TEAM:
+ CG_Say( clientNum, SAY_TEAM, sayText );
+ break;
+ default:
+ break;
}
+ }
+ // playing voice audio tracks disabled
+ if( cg_noVoiceChats.integer )
return;
- }
- // server requests a ptrc
- if( !strcmp( cmd, "ptrcrequest" ) )
+ // no audio track to play
+ if( !track )
+ return;
+
+ switch( vChan )
{
- int code = CG_ReadPTRCode( );
+ case VOICE_CHAN_ALL:
+ trap_S_StartLocalSound( track->track, CHAN_VOICE );
+ break;
+ case VOICE_CHAN_TEAM:
+ trap_S_StartLocalSound( track->track, CHAN_VOICE );
+ break;
+ case VOICE_CHAN_LOCAL:
+ trap_S_StartSound( NULL, clientNum, CHAN_VOICE, track->track );
+ break;
+ default:
+ break;
+ }
+}
- trap_SendClientCommand( va( "ptrcverify %d", code ) );
- return;
- }
+/*
+=================
+CG_CenterPrint_f
+=================
+*/
+void CG_CenterPrint_f( void )
+{
+ CG_CenterPrint( CG_Argv( 1 ), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
+}
+
+/*
+=================
+CG_Print_f
+=================
+*/
+static void CG_Print_f( void )
+{
+ CG_Printf( "%s", CG_Argv( 1 ) );
+}
+
+/*
+=================
+CG_Chat_f
+=================
+*/
+static void CG_Chat_f( void )
+{
+ char id[ 3 ];
+ char mode[ 3 ];
+
+ trap_Argv( 1, id, sizeof( id ) );
+ trap_Argv( 2, mode, sizeof( mode ) );
+
+ CG_Say( atoi( id ), atoi( mode ), CG_Argv( 3 ) );
+}
- // server issues a ptrc
- if( !strcmp( cmd, "ptrcissue" ) )
+/*
+=================
+CG_ServerMenu_f
+=================
+*/
+static void CG_ServerMenu_f( void )
+{
+ if( !cg.demoPlayback )
{
if( trap_Argc( ) == 2 )
- {
- int code = atoi( CG_Argv( 1 ) );
+ CG_Menu( atoi( CG_Argv( 1 ) ), 0 );
+ else if( trap_Argc( ) == 3 )
+ CG_Menu( atoi( CG_Argv( 1 ) ), atoi( CG_Argv( 2 ) ) );
+ }
+}
- CG_WritePTRCode( code );
- }
+/*
+=================
+CG_ServerCloseMenus_f
+=================
+*/
+static void CG_ServerCloseMenus_f( void )
+{
+ trap_SendConsoleCommand( "closemenus\n" );
+}
- return;
+/*
+=================
+CG_PoisonCloud_f
+=================
+*/
+static void CG_PoisonCloud_f( void )
+{
+ cg.poisonedTime = cg.time;
+
+ if( CG_IsParticleSystemValid( &cg.poisonCloudPS ) )
+ {
+ cg.poisonCloudPS = CG_SpawnNewParticleSystem( cgs.media.poisonCloudPS );
+ CG_SetAttachmentCent( &cg.poisonCloudPS->attachment, &cg.predictedPlayerEntity );
+ CG_AttachToCent( &cg.poisonCloudPS->attachment );
}
+}
+
+static char registeredCmds[ 8192 ]; // cmd1\0cmd2\0cmdn\0\0
+static size_t gcmdsOffset;
+static void CG_GameCmds_f( void )
+{
+ int i;
+ int c = trap_Argc( );
+ const char *cmd;
+ size_t len;
- // reply to ptrcverify
- if( !strcmp( cmd, "ptrcconfirm" ) )
+ for( i = 1; i < c; i++ )
{
- trap_SendConsoleCommand( "menu ptrc_popmenu\n" );
+ cmd = CG_Argv( i );
+ len = strlen( cmd ) + 1;
+ if( len + gcmdsOffset >= sizeof( registeredCmds ) - 1 )
+ {
+ CG_Printf( "AddCommand: too many commands (%d >= %d)\n",
+ (int)( len + gcmdsOffset ), (int)( sizeof( registeredCmds ) - 1 ) );
+ return;
+ }
+ trap_AddCommand( cmd );
+ strcpy( registeredCmds + gcmdsOffset, cmd );
+ gcmdsOffset += len;
+ }
+}
+void CG_UnregisterCommands( void )
+{
+ size_t len, offset = 0;
+ while( registeredCmds[ offset ] )
+ {
+ len = strlen( registeredCmds + offset );
+ trap_RemoveCommand( registeredCmds + offset );
+ offset += len + 1;
+ }
+ memset( registeredCmds, 0, 2 );
+ gcmdsOffset = 0;
+}
+
+static consoleCommand_t svcommands[ ] =
+{
+ { "chat", CG_Chat_f },
+ { "cmds", CG_GameCmds_f },
+ { "cp", CG_CenterPrint_f },
+ { "cs", CG_ConfigStringModified },
+ { "map_restart", CG_MapRestart },
+ { "poisoncloud", CG_PoisonCloud_f },
+ { "print", CG_Print_f },
+ { "scores", CG_ParseScores },
+ { "serverclosemenus", CG_ServerCloseMenus_f },
+ { "servermenu", CG_ServerMenu_f },
+ { "tinfo", CG_ParseTeamInfo },
+ { "voice", CG_ParseVoice }
+};
+
+/*
+=================
+CG_ServerCommand
+
+The string has been tokenized and can be retrieved with
+Cmd_Argc() / Cmd_Argv()
+=================
+*/
+static void CG_ServerCommand( void )
+{
+ const char *cmd;
+ consoleCommand_t *command;
+
+ cmd = CG_Argv( 0 );
+ command = bsearch( cmd, svcommands, ARRAY_LEN( svcommands ),
+ sizeof( svcommands[ 0 ] ), cmdcmp );
+
+ if( command )
+ {
+ command->function( );
return;
}
diff --git a/src/cgame/cg_snapshot.c b/src/cgame/cg_snapshot.c
index 84b419f..3316abb 100644
--- a/src/cgame/cg_snapshot.c
+++ b/src/cgame/cg_snapshot.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,15 +17,14 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_snapshot.c -- things that happen on snapshot transition,
// not necessarily every single rendered frame
-
#include "cg_local.h"
/*
@@ -41,8 +41,8 @@ static void CG_ResetEntity( centity_t *cent )
cent->trailTime = cg.snap->serverTime;
- VectorCopy( cent->currentState.origin, cent->lerpOrigin );
- VectorCopy( cent->currentState.angles, cent->lerpAngles );
+ VectorCopy( cent->currentState.pos.trBase, cent->lerpOrigin );
+ VectorCopy( cent->currentState.apos.trBase, cent->lerpAngles );
if( cent->currentState.eType == ET_PLAYER )
CG_ResetPlayerEntity( cent );
@@ -142,9 +142,6 @@ static void CG_TransitionSnapshot( void )
// execute any server string commands before transitioning entities
CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
- // if we had a map_restart, set everthing with initial
- if( !cg.snap ) { } //TA: ?
-
// clear the currentValid flag for all entities in the existing snapshot
for( i = 0; i < cg.snap->numEntities; i++ )
{
@@ -311,7 +308,7 @@ static snapshot_t *CG_ReadNextSnapshot( void )
if( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 )
{
- CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i",
+ CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i\n",
cg.latestSnapshotNum, cgs.processedSnapshotNum );
}
@@ -461,4 +458,3 @@ void CG_ProcessSnapshots( void )
if( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time )
CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
}
-
diff --git a/src/cgame/cg_syscalls.asm b/src/cgame/cg_syscalls.asm
index 2537c91..3b8ed01 100644
--- a/src/cgame/cg_syscalls.asm
+++ b/src/cgame/cg_syscalls.asm
@@ -12,7 +12,7 @@ equ trap_Argv -9
equ trap_Args -10
equ trap_FS_FOpenFile -11
equ trap_FS_Read -12
-equ trap_FS_Write -13
+equ trap_FS_Write -13
equ trap_FS_FCloseFile -14
equ trap_SendConsoleCommand -15
equ trap_AddCommand -16
@@ -106,6 +106,7 @@ equ trap_Key_SetOverstrikeMode -102
equ trap_Key_GetOverstrikeMode -103
equ trap_S_SoundDuration -104
+equ trap_Field_CompleteList -105
equ memset -201
equ memcpy -202
@@ -118,4 +119,3 @@ equ floor -208
equ ceil -209
equ testPrintInt -210
equ testPrintFloat -211
-
diff --git a/src/cgame/cg_syscalls.c b/src/cgame/cg_syscalls.c
index aa42019..6b81d64 100644
--- a/src/cgame/cg_syscalls.c
+++ b/src/cgame/cg_syscalls.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,15 +17,14 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_syscalls.c -- this file is only included when building a dll
// cg_syscalls.asm is included instead when building a qvm
-
#include "cg_local.h"
static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;
@@ -38,9 +38,9 @@ Q_EXPORT void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) )
int PASSFLOAT( float x )
{
- float floatTemp;
- floatTemp = x;
- return *(int *)&floatTemp;
+ floatint_t fi;
+ fi.f = x;
+ return fi.i;
}
void trap_Print( const char *fmt )
@@ -51,6 +51,8 @@ void trap_Print( const char *fmt )
void trap_Error( const char *fmt )
{
syscall( CG_ERROR, fmt );
+ // shut up GCC warning about returning functions, because we know better
+ exit(1);
}
int trap_Milliseconds( void )
@@ -98,7 +100,7 @@ void trap_LiteralArgs( char *buffer, int bufferLength )
syscall( CG_LITERAL_ARGS, buffer, bufferLength );
}
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode )
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, enum FS_Mode mode )
{
return syscall( CG_FS_FOPENFILE, qpath, f, mode );
}
@@ -118,7 +120,7 @@ void trap_FS_FCloseFile( fileHandle_t f )
syscall( CG_FS_FCLOSEFILE, f );
}
-void trap_FS_Seek( fileHandle_t f, long offset, fsOrigin_t origin )
+void trap_FS_Seek( fileHandle_t f, long offset, enum FS_Origin origin )
{
syscall( CG_FS_SEEK, f, offset, origin );
}
@@ -290,6 +292,13 @@ sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed )
return syscall( CG_S_REGISTERSOUND, sample, compressed );
}
+#ifndef MODULE_INTERFACE_11
+int trap_S_SoundDuration( sfxHandle_t handle )
+{
+ return syscall( CG_S_SOUNDDURATION, handle );
+}
+#endif
+
void trap_S_StartBackgroundTrack( const char *intro, const char *loop )
{
syscall( CG_S_STARTBACKGROUNDTRACK, intro, loop );
@@ -340,6 +349,11 @@ void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *
syscall( CG_R_ADDPOLYTOSCENE, hShader, numVerts, verts );
}
+qboolean trap_R_inPVS( const vec3_t p1, const vec3_t p2 )
+{
+ return syscall( CG_R_INPVS, p1, p2 );
+}
+
void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num )
{
syscall( CG_R_ADDPOLYSTOSCENE, hShader, numVerts, verts, num );
@@ -370,6 +384,13 @@ void trap_R_SetColor( const float *rgba )
syscall( CG_R_SETCOLOR, rgba );
}
+#ifndef MODULE_INTERFACE_11
+void trap_R_SetClipRegion( const float *region )
+{
+ syscall( CG_R_SETCLIPREGION, region );
+}
+#endif
+
void trap_R_DrawStretchPic( float x, float y, float w, float h,
float s1, float t1, float s2, float t2, qhandle_t hShader )
{
@@ -572,3 +593,16 @@ void trap_Key_SetBinding( int keynum, const char *binding ) {
syscall( CG_KEY_SETBINDING, keynum, binding );
}
+#ifndef MODULE_INTERFACE_11
+void trap_Key_SetOverstrikeMode( qboolean state ) {
+ syscall( CG_KEY_SETOVERSTRIKEMODE, state );
+}
+
+qboolean trap_Key_GetOverstrikeMode( void ) {
+ return syscall( CG_KEY_GETOVERSTRIKEMODE );
+}
+
+void trap_Field_CompleteList( char *listJson ) {
+ syscall( CG_FIELD_COMPLETELIST, listJson );
+}
+#endif
diff --git a/src/cgame/cg_syscalls_11.asm b/src/cgame/cg_syscalls_11.asm
index 0893ebc..13c262c 100644
--- a/src/cgame/cg_syscalls_11.asm
+++ b/src/cgame/cg_syscalls_11.asm
@@ -12,7 +12,7 @@ equ trap_Argv -9
equ trap_Args -10
equ trap_FS_FOpenFile -11
equ trap_FS_Read -12
-equ trap_FS_Write -13
+equ trap_FS_Write -13
equ trap_FS_FCloseFile -14
equ trap_SendConsoleCommand -15
equ trap_AddCommand -16
@@ -112,4 +112,3 @@ equ floor -208
equ ceil -209
equ testPrintInt -210
equ testPrintFloat -211
-
diff --git a/src/cgame/cg_trails.c b/src/cgame/cg_trails.c
index c8943ed..c7d2662 100644
--- a/src/cgame/cg_trails.c
+++ b/src/cgame/cg_trails.c
@@ -1,12 +1,13 @@
/*
===========================================================================
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -15,14 +16,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_trails.c -- the trail system
-
#include "cg_local.h"
static baseTrailSystem_t baseTrailSystems[ MAX_BASETRAIL_SYSTEMS ];
@@ -60,7 +60,7 @@ static void CG_CalculateBeamNodeProperties( trailBeam_t *tb )
if( ts->destroyTime > 0 && btb->fadeOutTime )
{
- fadeAlpha -= ( cg.time - ts->destroyTime ) / btb->fadeOutTime;
+ fadeAlpha -= (float)( cg.time - ts->destroyTime ) / btb->fadeOutTime;
if( fadeAlpha < 0.0f )
fadeAlpha = 0.0f;
@@ -559,7 +559,7 @@ static void CG_UpdateBeam( trailBeam_t *tb )
tb->lastEvalTime = cg.time;
// first make sure this beam has enough nodes
- if( ts->destroyTime <= 0 )
+ if( ts->destroyTime <= 0 || btb->fadeOutTime > 0 )
{
nodesToAdd = btb->numSegments - CG_CountBeamNodes( tb ) + 1;
@@ -898,7 +898,7 @@ static qboolean CG_ParseTrailBeam( baseTrailBeam_t *btb, char **text_p )
{
if( btb->numJitters == MAX_TRAIL_BEAM_JITTERS )
{
- CG_Printf( S_COLOR_RED "ERROR: too many jitters\n", token );
+ CG_Printf( S_COLOR_RED "ERROR: too many jitters\n" );
break;
}
@@ -1009,6 +1009,15 @@ static qboolean CG_ParseTrailSystem( baseTrailSystem_t *bts, char **text_p, cons
}
else if( !Q_stricmp( token, "thirdPersonOnly" ) )
bts->thirdPersonOnly = qtrue;
+ else if( !Q_stricmp( token, "lifeTime" ) )
+ {
+ token = COM_Parse( text_p );
+ if( !Q_stricmp( token, "" ) )
+ break;
+
+ bts->lifeTime = atoi_neg( token, qfalse );
+ continue;
+ }
else if( !Q_stricmp( token, "beam" ) ) //acceptable text
continue;
else if( !Q_stricmp( token, "}" ) )
@@ -1051,9 +1060,11 @@ static qboolean CG_ParseTrailFile( const char *fileName )
if( len <= 0 )
return qfalse;
- if( len >= sizeof( text ) - 1 )
+ if( len == 0 || len >= sizeof( text ) - 1 )
{
- CG_Printf( S_COLOR_RED "ERROR: trail file %s too long\n", fileName );
+ trap_FS_FCloseFile( f );
+ CG_Printf( S_COLOR_RED "ERROR: trail file %s is %s\n", fileName,
+ len == 0 ? "empty" : "too long" );
return qfalse;
}
@@ -1251,11 +1262,14 @@ static trailBeam_t *CG_SpawnNewTrailBeam( baseTrailBeam_t *btb,
if( cg_debugTrails.integer >= 1 )
CG_Printf( "TB %s created\n", ts->class->name );
- break;
+ return tb;
}
}
- return tb;
+ if( cg_debugTrails.integer >= 1 )
+ CG_Printf( "MAX_TRAIL_BEAMS\n" );
+
+ return NULL;
}
@@ -1291,18 +1305,22 @@ trailSystem_t *CG_SpawnNewTrailSystem( qhandle_t psHandle )
ts->valid = qtrue;
ts->destroyTime = -1;
-
+ ts->birthTime = cg.time;
+
for( j = 0; j < bts->numBeams; j++ )
CG_SpawnNewTrailBeam( bts->beams[ j ], ts );
if( cg_debugTrails.integer >= 1 )
CG_Printf( "TS %s created\n", bts->name );
- break;
+ return ts;
}
}
- return ts;
+ if( cg_debugTrails.integer >= 1 )
+ CG_Printf( "MAX_TRAIL_SYSTEMS\n" );
+
+ return NULL;
}
/*
@@ -1406,6 +1424,19 @@ static void CG_GarbageCollectTrailSystems( void )
CG_DestroyTrailSystem( &tempTS );
}
+ // lifetime expired
+ if( ts->destroyTime <= 0 && ts->class->lifeTime &&
+ ts->birthTime + ts->class->lifeTime < cg.time )
+ {
+ trailSystem_t *tempTS = ts;
+
+ CG_DestroyTrailSystem( &tempTS );
+ if( cg_debugTrails.integer >= 1 )
+ CG_Printf( "TS %s expired (born %d, lives %d, now %d)\n",
+ ts->class->name, ts->birthTime, ts->class->lifeTime,
+ cg.time );
+ }
+
if( cg_debugTrails.integer >= 1 && !ts->valid )
CG_Printf( "TS %s garbage collected\n", ts->class->name );
}
diff --git a/src/cgame/cg_tutorial.c b/src/cgame/cg_tutorial.c
index c418726..e9dbcd6 100644
--- a/src/cgame/cg_tutorial.c
+++ b/src/cgame/cg_tutorial.c
@@ -1,12 +1,13 @@
/*
===========================================================================
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -15,8 +16,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -35,7 +36,8 @@ static bind_t bindings[ ] =
{
{ "+button2", "Activate Upgrade", { -1, -1 } },
{ "+speed", "Run/Walk", { -1, -1 } },
- { "boost", "Sprint", { -1, -1 } },
+ { "+button6", "Dodge", { -1, -1 } },
+ { "+button8", "Sprint", { -1, -1 } },
{ "+moveup", "Jump", { -1, -1 } },
{ "+movedown", "Crouch", { -1, -1 } },
{ "+attack", "Primary Attack", { -1, -1 } },
@@ -49,7 +51,7 @@ static bind_t bindings[ ] =
{ "weapnext", "Next Upgrade", { -1, -1 } }
};
-static const int numBindings = sizeof( bindings ) / sizeof( bind_t );
+static const size_t numBindings = ARRAY_LEN( bindings );
/*
=================
@@ -122,9 +124,8 @@ static const char *CG_KeyNameForCommand( const char *command )
}
else
{
- Q_strncpyz( buffer, va( "\"%s\"", bindings[ i ].humanName ),
- MAX_STRING_CHARS );
- Q_strcat( buffer, MAX_STRING_CHARS, " (unbound)" );
+ Com_sprintf( buffer, MAX_STRING_CHARS, "\"%s\" (unbound)",
+ bindings[ i ].humanName );
}
return buffer;
@@ -157,12 +158,12 @@ static entityState_t *CG_BuildableInRange( playerState_t *ps, float *healthFract
if( healthFraction )
{
- health = es->generic1 & B_HEALTH_MASK;
- *healthFraction = (float)health / B_HEALTH_MASK;
+ health = es->misc;
+ *healthFraction = (float)health / BG_Buildable( es->modelindex )->health;
}
if( es->eType == ET_BUILDABLE &&
- ps->stats[ STAT_PTEAM ] == BG_FindTeamForBuildable( es->modelindex ) )
+ ps->stats[ STAT_TEAM ] == BG_Buildable( es->modelindex )->team )
return es;
else
return NULL;
@@ -183,61 +184,61 @@ static void CG_AlienBuilderText( char *text, playerState_t *ps )
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to place the %s\n",
CG_KeyNameForCommand( "+attack" ),
- BG_FindHumanNameForBuildable( buildable ) ) );
+ BG_Buildable( buildable )->humanName ) );
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to cancel placing the %s\n",
CG_KeyNameForCommand( "+button5" ),
- BG_FindHumanNameForBuildable( buildable ) ) );
+ BG_Buildable( buildable )->humanName ) );
}
else
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to build a structure\n",
CG_KeyNameForCommand( "+attack" ) ) );
+ }
- if( ( es = CG_BuildableInRange( ps, NULL ) ) )
+ if( ( es = CG_BuildableInRange( ps, NULL ) ) )
+ {
+ if( cgs.markDeconstruct )
{
- if( cgs.markDeconstruct )
+ if( es->eFlags & EF_B_MARKED )
{
- if( es->generic1 & B_MARKED_TOGGLEBIT )
- {
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to unmark this structure\n",
- CG_KeyNameForCommand( "deconstruct" ) ) );
- }
- else
- {
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to mark this structure\n",
- CG_KeyNameForCommand( "deconstruct" ) ) );
- }
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to unmark this structure for replacement\n",
+ CG_KeyNameForCommand( "deconstruct" ) ) );
}
else
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to destroy this structure\n",
+ va( "Press %s to mark this structure for replacement\n",
CG_KeyNameForCommand( "deconstruct" ) ) );
}
}
- }
-
- if( ps->stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0_UPG )
- {
- if( ( ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) == BA_NONE )
+ else
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to swipe\n",
- CG_KeyNameForCommand( "+button5" ) ) );
+ va( "Press %s to destroy this structure\n",
+ CG_KeyNameForCommand( "deconstruct" ) ) );
}
+ }
+ if( ( ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) == BA_NONE )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to swipe\n",
+ CG_KeyNameForCommand( "+button5" ) ) );
+ }
+
+ if( ps->stats[ STAT_CLASS ] == PCL_ALIEN_BUILDER0_UPG )
+ {
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to launch a projectile\n",
- CG_KeyNameForCommand( "+button2" ) ) );
+ CG_KeyNameForCommand( "+button2" ) ) );
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to walk on walls\n",
- CG_KeyNameForCommand( "+movedown" ) ) );
+ CG_KeyNameForCommand( "+movedown" ) ) );
}
}
@@ -249,7 +250,7 @@ CG_AlienLevel0Text
static void CG_AlienLevel0Text( char *text, playerState_t *ps )
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
- "Touch a human to damage it\n" );
+ "Touch humans to damage them\n" );
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to walk on walls\n",
@@ -264,13 +265,13 @@ CG_AlienLevel1Text
static void CG_AlienLevel1Text( char *text, playerState_t *ps )
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
- "Touch a human to grab it\n" );
+ "Touch humans to grab them\n" );
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to swipe\n",
CG_KeyNameForCommand( "+attack" ) ) );
- if( ps->stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL1_UPG )
+ if( ps->stats[ STAT_CLASS ] == PCL_ALIEN_LEVEL1_UPG )
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to spray poisonous gas\n",
@@ -293,7 +294,7 @@ static void CG_AlienLevel2Text( char *text, playerState_t *ps )
va( "Press %s to bite\n",
CG_KeyNameForCommand( "+attack" ) ) );
- if( ps->stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL2_UPG )
+ if( ps->stats[ STAT_CLASS ] == PCL_ALIEN_LEVEL2_UPG )
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to invoke an electrical attack\n",
@@ -316,7 +317,7 @@ static void CG_AlienLevel3Text( char *text, playerState_t *ps )
va( "Press %s to bite\n",
CG_KeyNameForCommand( "+attack" ) ) );
- if( ps->stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL3_UPG )
+ if( ps->stats[ STAT_CLASS ] == PCL_ALIEN_LEVEL3_UPG )
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to launch a projectile\n",
@@ -340,7 +341,7 @@ static void CG_AlienLevel4Text( char *text, playerState_t *ps )
CG_KeyNameForCommand( "+attack" ) ) );
Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Hold down and release %s to charge\n",
+ va( "Hold down and release %s to trample\n",
CG_KeyNameForCommand( "+button5" ) ) );
}
@@ -351,36 +352,47 @@ CG_HumanCkitText
*/
static void CG_HumanCkitText( char *text, playerState_t *ps )
{
- buildable_t buildable = ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT;
- float health;
+ buildable_t buildable = ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT;
+ entityState_t *es;
if( buildable > BA_NONE )
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to place the %s\n",
CG_KeyNameForCommand( "+attack" ),
- BG_FindHumanNameForBuildable( buildable ) ) );
+ BG_Buildable( buildable )->humanName ) );
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to cancel placing the %s\n",
CG_KeyNameForCommand( "+button5" ),
- BG_FindHumanNameForBuildable( buildable ) ) );
+ BG_Buildable( buildable )->humanName ) );
}
else
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to build a structure\n",
CG_KeyNameForCommand( "+attack" ) ) );
+ }
- if( CG_BuildableInRange( ps, &health ) )
+ if( ( es = CG_BuildableInRange( ps, NULL ) ) )
+ {
+ if( cgs.markDeconstruct )
{
- if( health < 1.0f )
+ if( es->eFlags & EF_B_MARKED )
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Hold %s to repair this structure\n",
- CG_KeyNameForCommand( "+button5" ) ) );
+ va( "Press %s to unmark this structure\n",
+ CG_KeyNameForCommand( "deconstruct" ) ) );
}
-
+ else
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to mark this structure\n",
+ CG_KeyNameForCommand( "deconstruct" ) ) );
+ }
+ }
+ else
+ {
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to destroy this structure\n",
CG_KeyNameForCommand( "deconstruct" ) ) );
@@ -396,21 +408,17 @@ CG_HumanText
static void CG_HumanText( char *text, playerState_t *ps )
{
char *name;
- int ammo, clips;
upgrade_t upgrade = UP_NONE;
- if( cg.weaponSelect <= 32 )
+ if( cg.weaponSelect < 32 )
name = cg_weapons[ cg.weaponSelect ].humanName;
- else if( cg.weaponSelect > 32 )
+ else
{
name = cg_upgrades[ cg.weaponSelect - 32 ].humanName;
upgrade = cg.weaponSelect - 32;
}
- ammo = ps->ammo;
- clips = ps->clips;
-
- if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( ps->weapon ) )
+ if( !ps->ammo && !ps->clips && !BG_Weapon( ps->weapon )->infiniteAmmo )
{
//no ammo
switch( ps->weapon )
@@ -429,7 +437,7 @@ static void CG_HumanText( char *text, playerState_t *ps )
case WP_MASS_DRIVER:
case WP_LUCIFER_CANNON:
Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Find a Reactor or Repeater and press %s for more ammo\n",
+ va( "Find an Armoury, Reactor, or Repeater and press %s for more ammo\n",
CG_KeyNameForCommand( "buy ammo" ) ) );
break;
@@ -451,14 +459,14 @@ static void CG_HumanText( char *text, playerState_t *ps )
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to fire the %s\n",
CG_KeyNameForCommand( "+attack" ),
- BG_FindHumanNameForWeapon( ps->weapon ) ) );
+ BG_Weapon( ps->weapon )->humanName ) );
break;
case WP_MASS_DRIVER:
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to fire the %s\n",
CG_KeyNameForCommand( "+attack" ),
- BG_FindHumanNameForWeapon( ps->weapon ) ) );
+ BG_Weapon( ps->weapon )->humanName ) );
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Hold %s to zoom\n",
@@ -469,7 +477,7 @@ static void CG_HumanText( char *text, playerState_t *ps )
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Hold %s to activate the %s\n",
CG_KeyNameForCommand( "+attack" ),
- BG_FindHumanNameForWeapon( ps->weapon ) ) );
+ BG_Weapon( ps->weapon )->humanName ) );
break;
case WP_LUCIFER_CANNON:
@@ -480,11 +488,10 @@ static void CG_HumanText( char *text, playerState_t *ps )
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to fire the %s\n",
CG_KeyNameForCommand( "+button5" ),
- BG_FindHumanNameForWeapon( ps->weapon ) ) );
+ BG_Weapon( ps->weapon )->humanName ) );
break;
case WP_HBUILD:
- case WP_HBUILD2:
CG_HumanCkitText( text, ps );
break;
@@ -501,7 +508,7 @@ static void CG_HumanText( char *text, playerState_t *ps )
CG_KeyNameForCommand( "weapnext" ) ) );
if( upgrade == UP_NONE ||
- ( upgrade > UP_NONE && BG_FindUsableForUpgrade( upgrade ) ) )
+ ( upgrade > UP_NONE && BG_Upgrade( upgrade )->usable ) )
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to use the %s\n",
@@ -515,16 +522,52 @@ static void CG_HumanText( char *text, playerState_t *ps )
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to use your %s\n",
CG_KeyNameForCommand( "itemact medkit" ),
- BG_FindHumanNameForUpgrade( UP_MEDKIT ) ) );
+ BG_Upgrade( UP_MEDKIT )->humanName ) );
+ }
+
+ if( ps->stats[ STAT_STAMINA ] <= STAMINA_BLACKOUT_LEVEL )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ "You are blacking out. Stop sprinting to recover stamina\n" );
+ }
+ else if( ps->stats[ STAT_STAMINA ] <= STAMINA_SLOW_LEVEL )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ "Your stamina is low. Stop sprinting to recover\n" );
+ }
+
+ switch( cg.nearUsableBuildable )
+ {
+ case BA_H_ARMOURY:
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to buy equipment upgrades at the %s. Sell your old weapon first!\n",
+ CG_KeyNameForCommand( "+button7" ),
+ BG_Buildable( cg.nearUsableBuildable )->humanName ) );
+ break;
+ case BA_H_REPEATER:
+ case BA_H_REACTOR:
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to refill your energy weapon's ammo at the %s\n",
+ CG_KeyNameForCommand( "+button7" ),
+ BG_Buildable( cg.nearUsableBuildable )->humanName ) );
+ break;
+ case BA_NONE:
+ break;
+ default:
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to use the %s\n",
+ CG_KeyNameForCommand( "+button7" ),
+ BG_Buildable( cg.nearUsableBuildable )->humanName ) );
+ break;
}
Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to use a structure\n",
- CG_KeyNameForCommand( "+button7" ) ) );
+ va( "Press %s and any direction to sprint\n",
+ CG_KeyNameForCommand( "+button8" ) ) );
Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to sprint\n",
- CG_KeyNameForCommand( "boost" ) ) );
+ va( "Press %s and back or strafe to dodge\n",
+ CG_KeyNameForCommand( "+button6" ) ) );
}
/*
@@ -534,37 +577,56 @@ CG_SpectatorText
*/
static void CG_SpectatorText( char *text, playerState_t *ps )
{
- if( cgs.clientinfo[ cg.clientNum ].team != PTE_NONE )
+ if( cgs.clientinfo[ cg.clientNum ].team != TEAM_NONE )
{
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to spawn\n", CG_KeyNameForCommand( "+attack" ) ) );
+ if( ps->pm_flags & PMF_QUEUED )
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to leave spawn queue\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
+ else
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to spawn\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
}
else
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to join a team\n", CG_KeyNameForCommand( "+attack" ) ) );
+ va( "Press %s to join a team\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
}
if( ps->pm_flags & PMF_FOLLOW )
{
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to stop following\n",
- CG_KeyNameForCommand( "+button2" ) ) );
+ if( !cg.chaseFollow )
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to switch to chase-cam spectator mode\n",
+ CG_KeyNameForCommand( "+button2" ) ) );
+ else if( cgs.clientinfo[ cg.clientNum ].team == TEAM_NONE )
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to return to free spectator mode\n",
+ CG_KeyNameForCommand( "+button2" ) ) );
+ else
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to stop following\n",
+ CG_KeyNameForCommand( "+button2" ) ) );
Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s or ", CG_KeyNameForCommand( "weapprev" ) ) );
+ va( "Press %s or ",
+ CG_KeyNameForCommand( "weapprev" ) ) );
Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "%s to change player\n", CG_KeyNameForCommand( "weapnext" ) ) );
+ va( "%s to change player\n",
+ CG_KeyNameForCommand( "weapnext" ) ) );
}
else
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to follow a %s\n", CG_KeyNameForCommand( "+button2" ),
- ( cgs.clientinfo[ cg.clientNum ].team == PTE_NONE )
- ? "player" : "teammate" ) );
+ va( "Press %s to follow a player\n",
+ CG_KeyNameForCommand( "+button2" ) ) );
}
}
+#define BINDING_REFRESH_INTERVAL 30
+
/*
===============
CG_TutorialText
@@ -576,22 +638,26 @@ const char *CG_TutorialText( void )
{
playerState_t *ps;
static char text[ MAX_TUTORIAL_TEXT ];
+ static int refreshBindings = 0;
+
+ if( refreshBindings == 0 )
+ CG_GetBindings( );
- CG_GetBindings( );
+ refreshBindings = ( refreshBindings + 1 ) % BINDING_REFRESH_INTERVAL;
text[ 0 ] = '\0';
ps = &cg.snap->ps;
if( !cg.intermissionStarted && !cg.demoPlayback )
{
- if( ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR ||
+ if( ps->persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT ||
ps->pm_flags & PMF_FOLLOW )
{
CG_SpectatorText( text, ps );
}
else if( ps->stats[ STAT_HEALTH ] > 0 )
{
- switch( ps->stats[ STAT_PCLASS ] )
+ switch( ps->stats[ STAT_CLASS ] )
{
case PCL_ALIEN_BUILDER0:
case PCL_ALIEN_BUILDER0_UPG:
@@ -622,6 +688,7 @@ const char *CG_TutorialText( void )
break;
case PCL_HUMAN:
+ case PCL_HUMAN_BSUIT:
CG_HumanText( text, ps );
break;
@@ -629,26 +696,11 @@ const char *CG_TutorialText( void )
break;
}
- if( ps->stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( ps->stats[ STAT_TEAM ] == TEAM_ALIENS )
{
- entityState_t *es = CG_BuildableInRange( ps, NULL );
-
- if( ps->stats[ STAT_STATE ] & SS_HOVELING )
- {
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to exit the hovel\n",
- CG_KeyNameForCommand( "+button7" ) ) );
- }
- else if( es && es->modelindex == BA_A_HOVEL &&
- es->generic1 & B_SPAWNED_TOGGLEBIT &&
- ( ps->stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0 ||
- ps->stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0_UPG ) )
- {
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to enter the hovel\n",
- CG_KeyNameForCommand( "+button7" ) ) );
- }
- else if( BG_UpgradeClassAvailable( ps ) )
+ if( BG_AlienCanEvolve( ps->stats[ STAT_CLASS ],
+ ps->persistant[ PERS_CREDIT ],
+ cgs.alienStage ) )
{
Q_strcat( text, MAX_TUTORIAL_TEXT,
va( "Press %s to evolve\n",
@@ -656,7 +708,23 @@ const char *CG_TutorialText( void )
}
}
}
+ }
+ else if( !cg.demoPlayback )
+ {
+ if( !CG_ClientIsReady( ps->clientNum ) )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s when ready to continue\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
+ }
+ else
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT, "Waiting for other players to be ready\n" );
+ }
+ }
+ if( !cg.demoPlayback )
+ {
Q_strcat( text, MAX_TUTORIAL_TEXT, "Press ESC for the menu" );
}
diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c
index 428f299..871b095 100644
--- a/src/cgame/cg_view.c
+++ b/src/cgame/cg_view.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,18 +17,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_view.c -- setup all the parameters (position, angle, etc)
// for a 3D rendering
-
#include "cg_local.h"
-
/*
=============================================================================
@@ -181,7 +180,7 @@ static void CG_AddTestModel( void )
return;
}
- // if testing a gun, set the origin reletive to the view origin
+ // if testing a gun, set the origin relative to the view origin
if( cg.testGun )
{
VectorCopy( cg.refdef.vieworg, cg.testModelEntity.origin );
@@ -229,21 +228,7 @@ static void CG_CalcVrect( void )
if( cg.snap->ps.pm_type == PM_INTERMISSION )
size = 100;
else
- {
- // bound normal viewsize
- if( cg_viewsize.integer < 30 )
- {
- trap_Cvar_Set( "cg_viewsize", "30" );
- size = 30;
- }
- else if( cg_viewsize.integer > 100 )
- {
- trap_Cvar_Set( "cg_viewsize","100" );
- size = 100;
- }
- else
- size = cg_viewsize.integer;
- }
+ size = cg_viewsize.integer;
cg.refdef.width = cgs.glconfig.vidWidth * size / 100;
cg.refdef.width &= ~1;
@@ -257,119 +242,282 @@ static void CG_CalcVrect( void )
//==============================================================================
-
/*
===============
CG_OffsetThirdPersonView
===============
*/
-#define FOCUS_DISTANCE 512
-static void CG_OffsetThirdPersonView( void )
+void CG_OffsetThirdPersonView( void )
{
+ int i;
vec3_t forward, right, up;
vec3_t view;
- vec3_t focusAngles;
trace_t trace;
static vec3_t mins = { -8, -8, -8 };
static vec3_t maxs = { 8, 8, 8 };
vec3_t focusPoint;
- float focusDist;
- float forwardScale, sideScale;
vec3_t surfNormal;
-
- if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING )
+ int cmdNum;
+ usercmd_t cmd, oldCmd;
+ float range;
+ vec3_t mouseInputAngles;
+ vec3_t rotationAngles;
+ vec3_t axis[ 3 ], rotaxis[ 3 ];
+ float deltaPitch;
+ static float pitch;
+ static vec3_t killerPos = { 0, 0, 0 };
+
+ // If cg_thirdpersonShoulderViewMode == 2, do shoulder view instead
+ // If cg_thirdpersonShoulderViewMode == 1, do shoulder view when chasing
+ // a wallwalker because it's really erratic to watch
+ if( ( cg_thirdPersonShoulderViewMode.integer == 2 ) ||
+ ( ( cg_thirdPersonShoulderViewMode.integer == 1 ) &&
+ ( cg.snap->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) &&
+ ( cg.snap->ps.stats[ STAT_HEALTH ] > 0 ) ) )
{
- if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- VectorSet( surfNormal, 0.0f, 0.0f, -1.0f );
- else
- VectorCopy( cg.predictedPlayerState.grapplePoint, surfNormal );
+ CG_OffsetShoulderView( );
+ return;
}
- else
- VectorSet( surfNormal, 0.0f, 0.0f, 1.0f );
+ BG_GetClientNormal( &cg.predictedPlayerState, surfNormal );
+ // Set the view origin to the class's view height
VectorMA( cg.refdef.vieworg, cg.predictedPlayerState.viewheight, surfNormal, cg.refdef.vieworg );
- VectorCopy( cg.refdefViewAngles, focusAngles );
+ // Set the focus point where the camera will look (at the player's vieworg)
+ VectorCopy( cg.refdef.vieworg, focusPoint );
- // if dead, look at killer
+ // If player is dead, we want the player to be between us and the killer
+ // so pretend that the player was looking at the killer, then place cam behind them.
if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 )
{
- focusAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ];
- cg.refdefViewAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ];
+ int killerEntNum = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ];
+
+ // already looking at ourself
+ if( killerEntNum != cg.snap->ps.clientNum )
+ {
+ vec3_t lookDirection;
+ if( cg.wasDeadLastFrame == qfalse || !cg_staticDeathCam.integer )
+ {
+ VectorCopy( cg_entities[ killerEntNum ].lerpOrigin, killerPos );
+ cg.wasDeadLastFrame = qtrue;
+ }
+ VectorSubtract( killerPos, cg.refdef.vieworg, lookDirection );
+ vectoangles( lookDirection, cg.refdefViewAngles );
+ }
}
- //if ( focusAngles[PITCH] > 45 ) {
- // focusAngles[PITCH] = 45; // don't go too far overhead
- //}
- AngleVectors( focusAngles, forward, NULL, NULL );
+ // get and rangecheck cg_thirdPersonRange
+ range = cg_thirdPersonRange.value;
+ if( range > 150.0f ) range = 150.0f;
+ if( range < 30.0f ) range = 30.0f;
+
+ // Calculate the angle of the camera's position around the player.
+ // Unless in demo, PLAYING in third person, or in dead-third-person cam, allow the player
+ // to control camera position offsets using the mouse position.
+ if( cg.demoPlayback ||
+ ( ( cg.snap->ps.pm_flags & PMF_FOLLOW ) &&
+ ( cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 ) ) )
+ {
+ // Collect our input values from the mouse.
+ cmdNum = trap_GetCurrentCmdNumber();
+ trap_GetUserCmd( cmdNum, &cmd );
+ trap_GetUserCmd( cmdNum - 1, &oldCmd );
- VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );
+ // Prevent pitch from wrapping and clamp it within a [-75, 90] range.
+ // Cgame has no access to ps.delta_angles[] here, so we need to reproduce
+ // it ourselves.
+ deltaPitch = SHORT2ANGLE( cmd.angles[ PITCH ] - oldCmd.angles[ PITCH ] );
+ if( fabs(deltaPitch) < 200.0f )
+ {
+ pitch += deltaPitch;
+ }
- VectorCopy( cg.refdef.vieworg, view );
+ mouseInputAngles[ PITCH ] = pitch;
+ mouseInputAngles[ YAW ] = -1.0f * SHORT2ANGLE( cmd.angles[ YAW ] ); // yaw is inverted
+ mouseInputAngles[ ROLL ] = 0.0f;
+
+ for( i = 0; i < 3; i++ )
+ mouseInputAngles[ i ] = AngleNormalize180( mouseInputAngles[ i ] );
- VectorMA( view, 12, surfNormal, view );
+ // Set the rotation angles to be the view angles offset by the mouse input
+ // Ignore the original pitch though; it's too jerky otherwise
+ if( !cg_thirdPersonPitchFollow.integer )
+ cg.refdefViewAngles[ PITCH ] = 0.0f;
- //cg.refdefViewAngles[PITCH] *= 0.5;
+ for( i = 0; i < 3; i++ )
+ {
+ rotationAngles[ i ] = AngleNormalize180(cg.refdefViewAngles[ i ]) + mouseInputAngles[ i ];
+ AngleNormalize180( rotationAngles[ i ] );
+ }
- AngleVectors( cg.refdefViewAngles, forward, right, up );
+ // Don't let pitch go too high/too low or the camera flips around and
+ // that's really annoying.
+ // However, when we're not on the floor or ceiling (wallwalk) pitch
+ // may not be pitch, so just let it go.
+ if( surfNormal[ 2 ] > 0.5f || surfNormal[ 2 ] < -0.5f )
+ {
+ if( rotationAngles[ PITCH ] > 85.0f )
+ rotationAngles[ PITCH ] = 85.0f;
+ else if( rotationAngles[ PITCH ] < -85.0f )
+ rotationAngles[ PITCH ] = -85.0f;
+ }
+
+ // Perform the rotations specified by rotationAngles.
+ AnglesToAxis( rotationAngles, axis );
+ if( !( cg.snap->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) ||
+ !BG_RotateAxis( cg.snap->ps.grapplePoint, axis, rotaxis, qfalse,
+ cg.snap->ps.eFlags & EF_WALLCLIMBCEILING ) )
+ AxisCopy( axis, rotaxis );
+
+ // Convert the new axis back to angles.
+ AxisToAngles( rotaxis, rotationAngles );
+ }
+ else
+ {
+ if( cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 )
+ {
+ // If we're playing the game in third person, the viewangles already
+ // take care of our mouselook, so just use them.
+ for( i = 0; i < 3; i++ )
+ rotationAngles[ i ] = cg.refdefViewAngles[ i ];
+ }
+ else // dead
+ {
+ rotationAngles[ PITCH ] = 20.0f;
+ rotationAngles[ YAW ] = cg.refdefViewAngles[ YAW ];
+ }
+ }
- forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
- sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
- VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
- VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );
+ rotationAngles[ YAW ] -= cg_thirdPersonAngle.value;
- // trace a ray from the origin to the viewpoint to make sure the view isn't
- // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything
+ // Move the camera range distance back.
+ AngleVectors( rotationAngles, forward, right, up );
+ VectorCopy( cg.refdef.vieworg, view );
+ VectorMA( view, -range, forward, view );
+ // Ensure that the current camera position isn't out of bounds and that there
+ // is nothing between the camera and the player.
if( !cg_cameraMode.integer )
{
+ // Trace a ray from the origin to the viewpoint to make sure the view isn't
+ // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything
CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
- if( trace.fraction != 1.0 )
+ if( trace.fraction != 1.0f )
{
VectorCopy( trace.endpos, view );
- view[ 2 ] += ( 1.0 - trace.fraction ) * 32;
- // try another trace to this position, because a tunnel may have the ceiling
- // close enogh that this is poking out
+ view[ 2 ] += ( 1.0f - trace.fraction ) * 32;
+ // Try another trace to this position, because a tunnel may have the ceiling
+ // close enogh that this is poking out.
CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
VectorCopy( trace.endpos, view );
}
}
+ // Set the camera position to what we calculated.
VectorCopy( view, cg.refdef.vieworg );
- // select pitch to look at focus point from vieword
- VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
- focusDist = sqrt( focusPoint[ 0 ] * focusPoint[ 0 ] + focusPoint[ 1 ] * focusPoint[ 1 ] );
- if ( focusDist < 1 ) {
- focusDist = 1; // should never happen
+ // The above checks may have moved the camera such that the existing viewangles
+ // may not still face the player. Recalculate them to do so.
+ // but if we're dead, don't bother because we'd rather see what killed us
+ if( cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 )
+ {
+ VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
+ vectoangles( focusPoint, cg.refdefViewAngles );
}
- cg.refdefViewAngles[ PITCH ] = -180 / M_PI * atan2( focusPoint[ 2 ], focusDist );
- cg.refdefViewAngles[ YAW ] -= cg_thirdPersonAngle.value;
}
+/*
+===============
+CG_OffsetShoulderView
+
+===============
+*/
+void CG_OffsetShoulderView( void )
+{
+ int i;
+ int cmdNum;
+ usercmd_t cmd, oldCmd;
+ vec3_t rotationAngles;
+ vec3_t axis[ 3 ], rotaxis[ 3 ];
+ float deltaMousePitch;
+ static float mousePitch;
+ vec3_t forward, right, up;
+ classConfig_t* classConfig;
+
+ // Ignore following pitch; it's too jerky otherwise.
+ if( !cg_thirdPersonPitchFollow.integer )
+ cg.refdefViewAngles[ PITCH ] = 0.0f;
+
+ AngleVectors( cg.refdefViewAngles, forward, right, up );
+
+ classConfig = BG_ClassConfig( cg.snap->ps.stats[ STAT_CLASS ] );
+ VectorMA( cg.refdef.vieworg, classConfig->shoulderOffsets[ 0 ], forward, cg.refdef.vieworg );
+ VectorMA( cg.refdef.vieworg, classConfig->shoulderOffsets[ 1 ], right, cg.refdef.vieworg );
+ VectorMA( cg.refdef.vieworg, classConfig->shoulderOffsets[ 2 ], up, cg.refdef.vieworg );
+
+ // If someone is playing like this, the rest is already taken care of
+ // so just get the firstperson effects and leave.
+ if( !cg.demoPlayback && !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
+ {
+ CG_OffsetFirstPersonView();
+ return;
+ }
+
+ // Get mouse input for camera rotation.
+ cmdNum = trap_GetCurrentCmdNumber();
+ trap_GetUserCmd( cmdNum, &cmd );
+ trap_GetUserCmd( cmdNum - 1, &oldCmd );
+
+ // Prevent pitch from wrapping and clamp it within a [30, -50] range.
+ // Cgame has no access to ps.delta_angles[] here, so we need to reproduce
+ // it ourselves here.
+ deltaMousePitch = SHORT2ANGLE( cmd.angles[ PITCH ] - oldCmd.angles[ PITCH ] );
+ if( fabs(deltaMousePitch) < 200.0f )
+ mousePitch += deltaMousePitch;
+
+ // Handle pitch.
+ rotationAngles[ PITCH ] = mousePitch;
+
+ rotationAngles[ PITCH ] = AngleNormalize180( rotationAngles[ PITCH ] + AngleNormalize180( cg.refdefViewAngles[ PITCH ] ) );
+ if( rotationAngles [ PITCH ] < -90.0f ) rotationAngles [ PITCH ] = -90.0f;
+ if( rotationAngles [ PITCH ] > 90.0f ) rotationAngles [ PITCH ] = 90.0f;
+
+ // Yaw and Roll are much easier.
+ rotationAngles[ YAW ] = SHORT2ANGLE( cmd.angles[ YAW ] ) + cg.refdefViewAngles[ YAW ];
+ rotationAngles[ ROLL ] = 0.0f;
+
+ // Perform the rotations.
+ AnglesToAxis( rotationAngles, axis );
+ if( !( cg.snap->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) ||
+ !BG_RotateAxis( cg.snap->ps.grapplePoint, axis, rotaxis, qfalse,
+ cg.snap->ps.eFlags & EF_WALLCLIMBCEILING ) )
+ AxisCopy( axis, rotaxis );
+
+ AxisToAngles( rotaxis, rotationAngles );
+
+ // Actually set the viewangles.
+ for( i = 0; i < 3; i++ )
+ cg.refdefViewAngles[ i ] = rotationAngles[ i ];
+
+ // Now run the first person stuff so we get various effects added.
+ CG_OffsetFirstPersonView( );
+}
+
// this causes a compiler bug on mac MrC compiler
static void CG_StepOffset( void )
{
float steptime;
- int timeDelta;
+ int timeDelta;
vec3_t normal;
playerState_t *ps = &cg.predictedPlayerState;
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- {
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- VectorSet( normal, 0.0f, 0.0f, -1.0f );
- else
- VectorCopy( ps->grapplePoint, normal );
- }
- else
- VectorSet( normal, 0.0f, 0.0f, 1.0f );
+ BG_GetClientNormal( ps, normal );
- steptime = BG_FindSteptimeForClass( ps->stats[ STAT_PCLASS ] );
+ steptime = BG_Class( ps->stats[ STAT_CLASS ] )->steptime;
// smooth out stair climbing
timeDelta = cg.time - cg.stepTime;
@@ -378,17 +526,15 @@ static void CG_StepOffset( void )
float stepChange = cg.stepChange
* (steptime - timeDelta) / steptime;
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- VectorMA( cg.refdef.vieworg, -stepChange, normal, cg.refdef.vieworg );
- else
- cg.refdef.vieworg[ 2 ] -= stepChange;
+ VectorMA( cg.refdef.vieworg, -stepChange, normal, cg.refdef.vieworg );
}
}
-#define PCLOUD_ROLL_AMPLITUDE 25.0f
-#define PCLOUD_ROLL_FREQUENCY 0.4f
-#define PCLOUD_ZOOM_AMPLITUDE 15
-#define PCLOUD_ZOOM_FREQUENCY 0.7f
+#define PCLOUD_ROLL_AMPLITUDE 25.0f
+#define PCLOUD_ROLL_FREQUENCY 0.4f
+#define PCLOUD_ZOOM_AMPLITUDE 15
+#define PCLOUD_ZOOM_FREQUENCY 0.625f // 2.5s / 4
+#define PCLOUD_DISORIENT_DURATION 2500
/*
@@ -397,7 +543,7 @@ CG_OffsetFirstPersonView
===============
*/
-static void CG_OffsetFirstPersonView( void )
+void CG_OffsetFirstPersonView( void )
{
float *origin;
float *angles;
@@ -409,19 +555,10 @@ static void CG_OffsetFirstPersonView( void )
vec3_t predictedVelocity;
int timeDelta;
float bob2;
- vec3_t normal, baseOrigin;
+ vec3_t normal;
playerState_t *ps = &cg.predictedPlayerState;
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- {
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- VectorSet( normal, 0.0f, 0.0f, -1.0f );
- else
- VectorCopy( ps->grapplePoint, normal );
- }
- else
- VectorSet( normal, 0.0f, 0.0f, 1.0f );
-
+ BG_GetClientNormal( ps, normal );
if( cg.snap->ps.pm_type == PM_INTERMISSION )
return;
@@ -429,8 +566,6 @@ static void CG_OffsetFirstPersonView( void )
origin = cg.refdef.vieworg;
angles = cg.refdefViewAngles;
- VectorCopy( origin, baseOrigin );
-
// if dead, fix the angle and don't add any kick
if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 )
{
@@ -441,9 +576,6 @@ static void CG_OffsetFirstPersonView( void )
return;
}
- // add angles based on weapon kick
- VectorAdd( angles, cg.kick_angles, angles );
-
// add angles based on damage kick
if( cg.damageTime )
{
@@ -485,10 +617,10 @@ static void CG_OffsetFirstPersonView( void )
// add angles based on bob
// bob amount is class dependant
- if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
+ if( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
bob2 = 0.0f;
else
- bob2 = BG_FindBobForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] );
+ bob2 = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->bob;
#define LEVEL4_FEEDBACK 10.0f
@@ -498,7 +630,8 @@ static void CG_OffsetFirstPersonView( void )
{
if( ps->stats[ STAT_MISC ] > 0 )
{
- float fraction = (float)ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME;
+ float fraction = (float)ps->stats[ STAT_MISC ] /
+ LEVEL4_TRAMPLE_CHARGE_MAX;
if( fraction > 1.0f )
fraction = 1.0f;
@@ -530,26 +663,24 @@ static void CG_OffsetFirstPersonView( void )
#define LEVEL3_FEEDBACK 20.0f
//provide some feedback for pouncing
- if( cg.predictedPlayerState.weapon == WP_ALEVEL3 ||
- cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG )
+ if( ( cg.predictedPlayerState.weapon == WP_ALEVEL3 ||
+ cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG ) &&
+ cg.predictedPlayerState.stats[ STAT_MISC ] > 0 )
{
- if( cg.predictedPlayerState.stats[ STAT_MISC ] > 0 )
- {
- float fraction1, fraction2;
- vec3_t forward;
-
- AngleVectors( angles, forward, NULL, NULL );
- VectorNormalize( forward );
+ float fraction1, fraction2;
+ vec3_t forward;
- fraction1 = (float)( cg.time - cg.weapon2Time ) / (float)LEVEL3_POUNCE_CHARGE_TIME;
+ AngleVectors( angles, forward, NULL, NULL );
+ VectorNormalize( forward );
- if( fraction1 > 1.0f )
- fraction1 = 1.0f;
+ fraction1 = (float)cg.predictedPlayerState.stats[ STAT_MISC ] /
+ LEVEL3_POUNCE_TIME_UPG;
+ if( fraction1 > 1.0f )
+ fraction1 = 1.0f;
- fraction2 = -sin( fraction1 * M_PI / 2 );
+ fraction2 = -sin( fraction1 * M_PI / 2 );
- VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin );
- }
+ VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin );
}
#define STRUGGLE_DIST 5.0f
@@ -562,7 +693,6 @@ static void CG_OffsetFirstPersonView( void )
usercmd_t cmd;
int cmdNum;
float fFraction, rFraction, uFraction;
- float fFraction2, rFraction2, uFraction2;
cmdNum = trap_GetCurrentCmdNumber();
trap_GetUserCmd( cmdNum, &cmd );
@@ -580,10 +710,6 @@ static void CG_OffsetFirstPersonView( void )
if( uFraction > 1.0f )
uFraction = 1.0f;
- fFraction2 = -sin( fFraction * M_PI / 2 );
- rFraction2 = -sin( rFraction * M_PI / 2 );
- uFraction2 = -sin( uFraction * M_PI / 2 );
-
if( cmd.forwardmove > 0 )
VectorMA( origin, STRUGGLE_DIST * fFraction, forward, origin );
else if( cmd.forwardmove < 0 )
@@ -606,14 +732,21 @@ static void CG_OffsetFirstPersonView( void )
cg.upMoveTime = cg.time;
}
- if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED &&
+ if( ( cg.predictedPlayerEntity.currentState.eFlags & EF_POISONCLOUDED ) &&
+ ( cg.time - cg.poisonedTime < PCLOUD_DISORIENT_DURATION) &&
!( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
{
- float fraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 2 * PCLOUD_ROLL_FREQUENCY );
- float pitchFraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 5 * PCLOUD_ROLL_FREQUENCY );
-
- fraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME );
- pitchFraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME );
+ float scale, fraction, pitchFraction;
+
+ scale = 1.0f - (float)( cg.time - cg.poisonedTime ) /
+ BG_PlayerPoisonCloudTime( &cg.predictedPlayerState );
+ if( scale < 0.0f )
+ scale = 0.0f;
+
+ fraction = sin( ( cg.time - cg.poisonedTime ) / 500.0f * M_PI * PCLOUD_ROLL_FREQUENCY ) *
+ scale;
+ pitchFraction = sin( ( cg.time - cg.poisonedTime ) / 200.0f * M_PI * PCLOUD_ROLL_FREQUENCY ) *
+ scale;
angles[ ROLL ] += fraction * PCLOUD_ROLL_AMPLITUDE;
angles[ YAW ] += fraction * PCLOUD_ROLL_AMPLITUDE;
@@ -621,17 +754,17 @@ static void CG_OffsetFirstPersonView( void )
}
// this *feels* more realisitic for humans
- if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS &&
+ ( cg.predictedPlayerState.pm_type == PM_NORMAL ||
+ cg.predictedPlayerState.pm_type == PM_JETPACK ) )
{
angles[PITCH] += cg.bobfracsin * bob2 * 0.5;
// heavy breathing effects //FIXME: sound
- if( cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 )
+ if( cg.predictedPlayerState.stats[ STAT_STAMINA ] < STAMINA_BREATHING_LEVEL )
{
- float deltaBreath = (float)(
- cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ?
- -cg.predictedPlayerState.stats[ STAT_STAMINA ] :
- cg.predictedPlayerState.stats[ STAT_STAMINA ] ) / 200.0;
+ float deltaBreath = ( cg.predictedPlayerState.stats[ STAT_STAMINA ] -
+ STAMINA_BREATHING_LEVEL ) / -250.0;
float deltaAngle = cos( (float)cg.time/150.0 ) * deltaBreath;
deltaAngle += ( deltaAngle < 0 ? -deltaAngle : deltaAngle ) * 0.5;
@@ -643,11 +776,7 @@ static void CG_OffsetFirstPersonView( void )
//===================================
// add view height
- // when wall climbing the viewheight is not straight up
- if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING )
- VectorMA( origin, ps->viewheight, normal, origin );
- else
- origin[ 2 ] += cg.predictedPlayerState.viewheight;
+ VectorMA( origin, ps->viewheight, normal, origin );
// smooth out duck height changes
timeDelta = cg.time - cg.duckTime;
@@ -663,12 +792,7 @@ static void CG_OffsetFirstPersonView( void )
if( bob > 6 )
bob = 6;
- // likewise for bob
- if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING )
- VectorMA( origin, bob, normal, origin );
- else
- origin[ 2 ] += bob;
-
+ VectorMA( origin, bob, normal, origin );
// add fall height
delta = cg.time - cg.landTime;
@@ -687,10 +811,6 @@ static void CG_OffsetFirstPersonView( void )
// add step offset
CG_StepOffset( );
-
- // add kick offset
-
- VectorAdd (origin, cg.kick_origin, origin);
}
//======================================================================
@@ -702,14 +822,17 @@ CG_CalcFov
Fixed fov at intermissions, otherwise account for fov variable and zooms.
====================
*/
-#define WAVE_AMPLITUDE 1
-#define WAVE_FREQUENCY 0.4
+#define WAVE_AMPLITUDE 1.0f
+#define WAVE_FREQUENCY 0.4f
-#define FOVWARPTIME 400.0
+#define FOVWARPTIME 400.0f
+#define BASE_FOV_Y 73.739792f // atan2( 3, 4 / tan( 90 ) )
+#define MAX_FOV_Y 120.0f
+#define MAX_FOV_WARP_Y 127.5f
static int CG_CalcFov( void )
{
- float x;
+ float y;
float phase;
float v;
int contents;
@@ -719,95 +842,114 @@ static int CG_CalcFov( void )
int inwater;
int attribFov;
usercmd_t cmd;
+ usercmd_t oldcmd;
int cmdNum;
cmdNum = trap_GetCurrentCmdNumber( );
trap_GetUserCmd( cmdNum, &cmd );
+ trap_GetUserCmd( cmdNum - 1, &oldcmd );
+
+ // switch follow modes if necessary: cycle between free -> follow -> third-person follow
+ if( cmd.buttons & BUTTON_USE_HOLDABLE && !( oldcmd.buttons & BUTTON_USE_HOLDABLE ) )
+ {
+ if ( cg.snap->ps.pm_flags & PMF_FOLLOW )
+ {
+ if( !cg.chaseFollow )
+ cg.chaseFollow = qtrue;
+ else
+ {
+ cg.chaseFollow = qfalse;
+ trap_SendClientCommand( "follow\n" );
+ }
+ }
+ else if ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
+ trap_SendClientCommand( "follow\n" );
+ }
if( cg.predictedPlayerState.pm_type == PM_INTERMISSION ||
- ( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) )
+ ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT ) ||
+ ( cg.renderingThirdPerson ) )
{
- // if in intermission, use a fixed value
- fov_x = 90;
+ // if in intermission or third person, use a fixed value
+ fov_y = BASE_FOV_Y;
}
else
{
// don't lock the fov globally - we need to be able to change it
- attribFov = BG_FindFovForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] );
- fov_x = attribFov;
+ attribFov = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->fov * 0.75f;
+ fov_y = attribFov;
- if ( fov_x < 1 )
- fov_x = 1;
- else if ( fov_x > 160 )
- fov_x = 160;
+ if ( fov_y < 1.0f )
+ fov_y = 1.0f;
+ else if ( fov_y > MAX_FOV_Y )
+ fov_y = MAX_FOV_Y;
if( cg.spawnTime > ( cg.time - FOVWARPTIME ) &&
- BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_PCLASS ], SCA_FOVWARPS ) )
+ BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_CLASS ], SCA_FOVWARPS ) )
{
- float temp, temp2;
-
- temp = (float)( cg.time - cg.spawnTime ) / FOVWARPTIME;
- temp2 = ( 170 - fov_x ) * temp;
-
- //Com_Printf( "%f %f\n", temp*100, temp2*100 );
+ float fraction = (float)( cg.time - cg.spawnTime ) / FOVWARPTIME;
- fov_x = 170 - temp2;
+ fov_y = MAX_FOV_WARP_Y - ( ( MAX_FOV_WARP_Y - fov_y ) * fraction );
}
// account for zooms
- zoomFov = BG_FindZoomFovForWeapon( cg.predictedPlayerState.weapon );
- if ( zoomFov < 1 )
- zoomFov = 1;
+ zoomFov = BG_Weapon( cg.predictedPlayerState.weapon )->zoomFov * 0.75f;
+ if ( zoomFov < 1.0f )
+ zoomFov = 1.0f;
else if ( zoomFov > attribFov )
zoomFov = attribFov;
// only do all the zoom stuff if the client CAN zoom
// FIXME: zoom control is currently hard coded to BUTTON_ATTACK2
- if( BG_WeaponCanZoom( cg.predictedPlayerState.weapon ) )
+ if( BG_Weapon( cg.predictedPlayerState.weapon )->canZoom )
{
if ( cg.zoomed )
{
f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
- if ( f > 1.0 )
- fov_x = zoomFov;
+ if ( f > 1.0f )
+ fov_y = zoomFov;
else
- fov_x = fov_x + f * ( zoomFov - fov_x );
+ fov_y = fov_y + f * ( zoomFov - fov_y );
// BUTTON_ATTACK2 isn't held so unzoom next time
if( !( cmd.buttons & BUTTON_ATTACK2 ) )
{
cg.zoomed = qfalse;
- cg.zoomTime = cg.time;
+ cg.zoomTime = MIN( cg.time,
+ cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
}
}
else
{
f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
- if ( f <= 1.0 )
- fov_x = zoomFov + f * ( fov_x - zoomFov );
+ if ( f > 1.0f )
+ fov_y = fov_y;
+ else
+ fov_y = zoomFov + f * ( fov_y - zoomFov );
// BUTTON_ATTACK2 is held so zoom next time
if( cmd.buttons & BUTTON_ATTACK2 )
{
cg.zoomed = qtrue;
- cg.zoomTime = cg.time;
+ cg.zoomTime = MIN( cg.time,
+ cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
}
}
}
}
- x = cg.refdef.width / tan( fov_x / 360 * M_PI );
- fov_y = atan2( cg.refdef.height, x );
- fov_y = fov_y * 360 / M_PI;
+ y = cg.refdef.height / tan( 0.5f * DEG2RAD( fov_y ) );
+ fov_x = atan2( cg.refdef.width, y );
+ fov_x = 2.0f * RAD2DEG( fov_x );
// warp if underwater
contents = CG_PointContents( cg.refdef.vieworg, -1 );
if( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) )
{
- phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
+ phase = cg.time / 1000.0f * WAVE_FREQUENCY * M_PI * 2.0f;
v = WAVE_AMPLITUDE * sin( phase );
fov_x += v;
fov_y -= v;
@@ -816,13 +958,16 @@ static int CG_CalcFov( void )
else
inwater = qfalse;
- if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED &&
+ if( ( cg.predictedPlayerEntity.currentState.eFlags & EF_POISONCLOUDED ) &&
+ ( cg.time - cg.poisonedTime < PCLOUD_DISORIENT_DURATION) &&
cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 &&
!( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
{
- phase = cg.time / 1000.0 * PCLOUD_ZOOM_FREQUENCY * M_PI * 2;
- v = PCLOUD_ZOOM_AMPLITUDE * sin( phase );
- v *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME );
+ float scale = 1.0f - (float)( cg.time - cg.poisonedTime ) /
+ BG_PlayerPoisonCloudTime( &cg.predictedPlayerState );
+
+ phase = ( cg.time - cg.poisonedTime ) / 1000.0f * PCLOUD_ZOOM_FREQUENCY * M_PI * 2.0f;
+ v = PCLOUD_ZOOM_AMPLITUDE * sin( phase ) * scale;
fov_x += v;
fov_y += v;
}
@@ -833,9 +978,9 @@ static int CG_CalcFov( void )
cg.refdef.fov_y = fov_y;
if( !cg.zoomed )
- cg.zoomSensitivity = 1;
+ cg.zoomSensitivity = 1.0f;
else
- cg.zoomSensitivity = cg.refdef.fov_y / 75.0;
+ cg.zoomSensitivity = cg.refdef.fov_y / 75.0f;
return inwater;
}
@@ -941,10 +1086,7 @@ static void CG_smoothWWTransitions( playerState_t *ps, const vec3_t in, vec3_t o
}
//set surfNormal
- if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) )
- VectorCopy( ps->grapplePoint, surfNormal );
- else
- VectorCopy( ceilingNormal, surfNormal );
+ BG_GetClientNormal( ps, surfNormal );
AnglesToAxis( in, inAxis );
@@ -952,7 +1094,6 @@ static void CG_smoothWWTransitions( playerState_t *ps, const vec3_t in, vec3_t o
if( !VectorCompare( surfNormal, cg.lastNormal ) )
{
//if we moving from the ceiling to the floor special case
- //( x product of colinear vectors is undefined)
if( VectorCompare( ceilingNormal, cg.lastNormal ) &&
VectorCompare( refNormal, surfNormal ) )
{
@@ -1091,7 +1232,8 @@ static int CG_CalcViewValues( void )
ps = &cg.predictedPlayerState;
// intermission view
- if( ps->pm_type == PM_INTERMISSION )
+ if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_FREEZE ||
+ ps->pm_type == PM_SPECTATOR )
{
VectorCopy( ps->origin, cg.refdef.vieworg );
VectorCopy( ps->viewangles, cg.refdefViewAngles );
@@ -1105,18 +1247,22 @@ static int CG_CalcViewValues( void )
cg.xyspeed = sqrt( ps->velocity[ 0 ] * ps->velocity[ 0 ] +
ps->velocity[ 1 ] * ps->velocity[ 1 ] );
+ // the bob velocity should't get too fast to avoid jerking
+ if( cg.xyspeed > 300.0f )
+ cg.xyspeed = 300.0f;
+
VectorCopy( ps->origin, cg.refdef.vieworg );
- if( BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) )
+ if( BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLCLIMBER ) )
CG_smoothWWTransitions( ps, ps->viewangles, cg.refdefViewAngles );
- else if( BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
+ else if( BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) )
CG_smoothWJTransitions( ps, ps->viewangles, cg.refdefViewAngles );
else
VectorCopy( ps->viewangles, cg.refdefViewAngles );
//clumsy logic, but it needs to be this way round because the CS propogation
//delay screws things up otherwise
- if( !BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
+ if( !BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) )
{
if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) )
VectorSet( cg.lastNormal, 0.0f, 0.0f, 1.0f );
@@ -1143,6 +1289,8 @@ static int CG_CalcViewValues( void )
if( CG_IsParticleSystemValid( &cg.poisonCloudPS ) )
CG_DestroyParticleSystem( &cg.poisonCloudPS );
}
+ else
+ cg.wasDeadLastFrame = qfalse;
if( cg.renderingThirdPerson )
{
@@ -1155,7 +1303,7 @@ static int CG_CalcViewValues( void )
CG_OffsetFirstPersonView( );
}
- // position eye reletive to origin
+ // position eye relative to origin
AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
if( cg.hyperspace )
@@ -1260,7 +1408,11 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo
CG_PredictPlayerState( );
// decide on third person view
- cg.renderingThirdPerson = cg_thirdPerson.integer || ( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 );
+ cg.renderingThirdPerson = ( cg_thirdPerson.integer || ( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) ||
+ ( cg.chaseFollow && cg.snap->ps.pm_flags & PMF_FOLLOW) );
+
+ // update speedometer
+ CG_AddSpeed( );
// build cg.refdef
inwater = CG_CalcViewValues( );
@@ -1335,4 +1487,3 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo
if( cg_stats.integer )
CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame );
}
-
diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c
index 9aa9f9d..fc88606 100644
--- a/src/cgame/cg_weapons.c
+++ b/src/cgame/cg_weapons.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,14 +17,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cg_weapons.c -- events and effects dealing with weapons
-
#include "cg_local.h"
/*
@@ -38,26 +38,32 @@ void CG_RegisterUpgrade( int upgradeNum )
upgradeInfo_t *upgradeInfo;
char *icon;
- upgradeInfo = &cg_upgrades[ upgradeNum ];
-
- if( upgradeNum == 0 )
+ if( upgradeNum <= UP_NONE || upgradeNum >= UP_NUM_UPGRADES )
+ {
+ CG_Error( "CG_RegisterUpgrade: out of range: %d", upgradeNum );
return;
+ }
+
+ upgradeInfo = &cg_upgrades[ upgradeNum ];
if( upgradeInfo->registered )
+ {
+ CG_Printf( "CG_RegisterUpgrade: already registered: (%d) %s\n", upgradeNum,
+ BG_Upgrade( upgradeNum )->name );
return;
+ }
- memset( upgradeInfo, 0, sizeof( *upgradeInfo ) );
upgradeInfo->registered = qtrue;
- if( !BG_FindNameForUpgrade( upgradeNum ) )
+ if( !BG_Upgrade( upgradeNum )->name[ 0 ] )
CG_Error( "Couldn't find upgrade %i", upgradeNum );
- upgradeInfo->humanName = BG_FindHumanNameForUpgrade( upgradeNum );
+ upgradeInfo->humanName = BG_Upgrade( upgradeNum )->humanName;
//la la la la la, i'm not listening!
if( upgradeNum == UP_GRENADE )
upgradeInfo->upgradeIcon = cg_weapons[ WP_GRENADE ].weaponIcon;
- else if( ( icon = BG_FindIconForUpgrade( upgradeNum ) ) )
+ else if( ( icon = BG_Upgrade( upgradeNum )->icon ) )
upgradeInfo->upgradeIcon = trap_R_RegisterShader( icon );
}
@@ -72,7 +78,7 @@ void CG_InitUpgrades( void )
{
int i;
- memset( cg_upgrades, 0, sizeof( cg_upgrades ) );
+ Com_Memset( cg_upgrades, 0, sizeof( cg_upgrades ) );
for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
CG_RegisterUpgrade( i );
@@ -80,6 +86,105 @@ void CG_InitUpgrades( void )
/*
+======================
+CG_ParseWeaponAnimationFile
+
+Read a configuration file containing animation counts and rates
+models/weapons/rifle/animation.cfg, etc
+======================
+*/
+static qboolean CG_ParseWeaponAnimationFile( const char *filename, weaponInfo_t *weapon )
+{
+ char *text_p;
+ int len;
+ int i;
+ char *token;
+ float fps;
+ char text[ 20000 ];
+ fileHandle_t f;
+ animation_t *animations;
+
+ animations = weapon->animations;
+
+ // load the file
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if( len < 0 )
+ return qfalse;
+
+ if( len == 0 || len >= sizeof( text ) - 1 )
+ {
+ trap_FS_FCloseFile( f );
+ CG_Printf( "File %s is %s\n", filename, len == 0 ? "empty" : "too long" );
+ return qfalse;
+ }
+
+ trap_FS_Read( text, len, f );
+ text[ len ] = 0;
+ trap_FS_FCloseFile( f );
+
+ // parse the text
+ text_p = text;
+
+ // read information for each frame
+ for( i = WANIM_NONE + 1; i < MAX_WEAPON_ANIMATIONS; i++ )
+ {
+
+ token = COM_Parse( &text_p );
+ if( !*token )
+ break;
+
+ if( !Q_stricmp( token, "noDrift" ) )
+ {
+ weapon->noDrift = qtrue;
+ continue;
+ }
+
+ animations[ i ].firstFrame = atoi( token );
+
+ token = COM_Parse( &text_p );
+ if( !*token )
+ break;
+
+ animations[ i ].numFrames = atoi( token );
+ animations[ i ].reversed = qfalse;
+ animations[ i ].flipflop = qfalse;
+
+ // if numFrames is negative the animation is reversed
+ if( animations[ i ].numFrames < 0 )
+ {
+ animations[ i ].numFrames = -animations[ i ].numFrames;
+ animations[ i ].reversed = qtrue;
+ }
+
+ token = COM_Parse( &text_p );
+ if ( !*token )
+ break;
+
+ animations[i].loopFrames = atoi( token );
+
+ token = COM_Parse( &text_p );
+ if( !*token )
+ break;
+
+ fps = atof( token );
+ if( fps == 0 )
+ fps = 1;
+
+ animations[ i ].frameLerp = 1000 / fps;
+ animations[ i ].initialLerp = 1000 / fps;
+ }
+
+ if( i != MAX_WEAPON_ANIMATIONS )
+ {
+ CG_Printf( "Error parsing animation file: %s\n", filename );
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+
+/*
===============
CG_ParseWeaponModeSection
@@ -141,6 +246,16 @@ static qboolean CG_ParseWeaponModeSection( weaponInfoMode_t *wim, char **text_p
continue;
}
+ else if( !Q_stricmp( token, "missileSpriteCharge" ) )
+ {
+ token = COM_Parse( text_p );
+ if( !token )
+ break;
+
+ wim->missileSpriteCharge = atof( token );
+
+ continue;
+ }
else if( !Q_stricmp( token, "missileRotates" ) )
{
wim->missileRotates = qtrue;
@@ -429,12 +544,13 @@ static qboolean CG_ParseWeaponFile( const char *filename, weaponInfo_t *wi )
// load the file
len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if( len <= 0 )
+ if( len < 0 )
return qfalse;
- if( len >= sizeof( text ) - 1 )
+ if( len == 0 || len >= sizeof( text ) - 1 )
{
- CG_Printf( "File %s too long\n", filename );
+ trap_FS_FCloseFile( f );
+ CG_Printf( "File %s is %s\n", filename, len == 0 ? "empty" : "too long" );
return qfalse;
}
@@ -517,8 +633,33 @@ static qboolean CG_ParseWeaponFile( const char *filename, weaponInfo_t *wi )
strcat( path, "_hand.md3" );
wi->handsModel = trap_R_RegisterModel( path );
- if( !wi->handsModel )
- wi->handsModel = trap_R_RegisterModel( "models/weapons2/shotgun/shotgun_hand.md3" );
+ continue;
+ }
+ else if( !Q_stricmp( token, "weaponModel3rdPerson" ) )
+ {
+ char path[ MAX_QPATH ];
+
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ wi->weaponModel3rdPerson = trap_R_RegisterModel( token );
+
+ if( !wi->weaponModel3rdPerson )
+ {
+ CG_Printf( S_COLOR_RED "ERROR: 3rd person weapon "
+ "model not found %s\n", token );
+ }
+
+ strcpy( path, token );
+ COM_StripExtension( path, path, MAX_QPATH );
+ strcat( path, "_flash.md3" );
+ wi->flashModel3rdPerson = trap_R_RegisterModel( path );
+
+ strcpy( path, token );
+ COM_StripExtension( path, path, MAX_QPATH );
+ strcat( path, "_barrel.md3" );
+ wi->barrelModel3rdPerson = trap_R_RegisterModel( path );
continue;
}
@@ -596,35 +737,42 @@ void CG_RegisterWeapon( int weaponNum )
vec3_t mins, maxs;
int i;
- weaponInfo = &cg_weapons[ weaponNum ];
-
- if( weaponNum == 0 )
+ if( weaponNum <= WP_NONE || weaponNum >= WP_NUM_WEAPONS )
+ {
+ CG_Error( "CG_RegisterWeapon: out of range: %d", weaponNum );
return;
+ }
+
+ weaponInfo = &cg_weapons[ weaponNum ];
if( weaponInfo->registered )
+ {
+ CG_Printf( "CG_RegisterWeapon: already registered: (%d) %s\n", weaponNum,
+ BG_Weapon( weaponNum )->name );
return;
+ }
- memset( weaponInfo, 0, sizeof( *weaponInfo ) );
weaponInfo->registered = qtrue;
- if( !BG_FindNameForWeapon( weaponNum ) )
+ if( !BG_Weapon( weaponNum )->name[ 0 ] )
CG_Error( "Couldn't find weapon %i", weaponNum );
- Com_sprintf( path, MAX_QPATH, "models/weapons/%s/weapon.cfg", BG_FindNameForWeapon( weaponNum ) );
+ Com_sprintf( path, MAX_QPATH, "models/weapons/%s/weapon.cfg", BG_Weapon( weaponNum )->name );
- weaponInfo->humanName = BG_FindHumanNameForWeapon( weaponNum );
+ weaponInfo->humanName = BG_Weapon( weaponNum )->humanName;
if( !CG_ParseWeaponFile( path, weaponInfo ) )
Com_Printf( S_COLOR_RED "ERROR: failed to parse %s\n", path );
+ Com_sprintf( path, MAX_QPATH, "models/weapons/%s/animation.cfg", BG_Weapon( weaponNum )->name );
+
+ if( !CG_ParseWeaponAnimationFile( path, weaponInfo ) )
+ Com_Printf( S_COLOR_RED "ERROR: failed to parse %s\n", path );
+
// calc midpoint for rotation
trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs );
for( i = 0 ; i < 3 ; i++ )
weaponInfo->weaponMidpoint[ i ] = mins[ i ] + 0.5 * ( maxs[ i ] - mins[ i ] );
-
- //FIXME:
- for( i = WPM_NONE + 1; i < WPM_NUM_WEAPONMODES; i++ )
- weaponInfo->wim[ i ].loopFireSound = qfalse;
}
/*
@@ -638,7 +786,7 @@ void CG_InitWeapons( void )
{
int i;
- memset( cg_weapons, 0, sizeof( cg_weapons ) );
+ Com_Memset( cg_weapons, 0, sizeof( cg_weapons ) );
for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
CG_RegisterWeapon( i );
@@ -656,6 +804,53 @@ VIEW WEAPON
*/
/*
+===============
+CG_SetWeaponLerpFrameAnimation
+
+may include ANIM_TOGGLEBIT
+===============
+*/
+static void CG_SetWeaponLerpFrameAnimation( weapon_t weapon, lerpFrame_t *lf, int newAnimation )
+{
+ animation_t *anim;
+
+ lf->animationNumber = newAnimation;
+ newAnimation &= ~ANIM_TOGGLEBIT;
+
+ if( newAnimation < 0 || newAnimation >= MAX_WEAPON_ANIMATIONS )
+ CG_Error( "Bad animation number: %i", newAnimation );
+
+ anim = &cg_weapons[ weapon ].animations[ newAnimation ];
+
+ lf->animation = anim;
+ lf->animationTime = lf->frameTime + anim->initialLerp;
+
+ if( cg_debugAnim.integer )
+ CG_Printf( "Anim: %i\n", newAnimation );
+}
+
+/*
+===============
+CG_WeaponAnimation
+===============
+*/
+static void CG_WeaponAnimation( centity_t *cent, int *old, int *now, float *backLerp )
+{
+ lerpFrame_t *lf = &cent->pe.weapon;
+ entityState_t *es = &cent->currentState;
+
+ // see if the animation sequence is switching
+ if( es->weaponAnim != lf->animationNumber || !lf->animation )
+ CG_SetWeaponLerpFrameAnimation( es->weapon, lf, es->weaponAnim );
+
+ CG_RunLerpFrame( lf, 1.0f );
+
+ *old = lf->oldFrame;
+ *now = lf->frame;
+ *backLerp = lf->backlerp;
+}
+
+/*
=================
CG_MapTorsoToWeaponFrame
@@ -690,10 +885,13 @@ CG_CalculateWeaponPosition
*/
static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles )
{
- float scale;
- int delta;
- float fracsin;
- float bob;
+ float scale;
+ int delta;
+ float fracsin;
+ float bob;
+ weaponInfo_t *weapon;
+
+ weapon = &cg_weapons[ cg.predictedPlayerState.weapon ];
VectorCopy( cg.refdef.vieworg, origin );
VectorCopy( cg.refdefViewAngles, angles );
@@ -706,7 +904,7 @@ static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles )
// gun angles from bobbing
// bob amount is class dependant
- bob = BG_FindBobForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] );
+ bob = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->bob;
if( bob != 0 )
{
@@ -716,7 +914,7 @@ static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles )
}
// drop the weapon when landing
- if( !BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_PCLASS ], SCA_NOWEAPONDRIFT ) )
+ if( !weapon->noDrift )
{
delta = cg.time - cg.landTime;
if( delta < LAND_DEFLECT_TIME )
@@ -795,6 +993,13 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
weaponNum = cent->currentState.weapon;
weaponMode = cent->currentState.generic1;
+ if( weaponNum <= WP_NONE || weaponNum >= WP_NUM_WEAPONS )
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: CG_AddPlayerWeapon: weapon "
+ "number %i is out of bounds", weaponNum );
+ return;
+ }
+
if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES )
weaponMode = WPM_PRIMARY;
@@ -805,16 +1010,23 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
else
firing = qfalse;
- CG_RegisterWeapon( weaponNum );
weapon = &cg_weapons[ weaponNum ];
+ if( !weapon->registered )
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: CG_AddPlayerWeapon: weapon %d (%s) "
+ "is not registered\n", weaponNum, BG_Weapon( weaponNum )->name );
+ return;
+ }
// add the weapon
- memset( &gun, 0, sizeof( gun ) );
+ Com_Memset( &gun, 0, sizeof( gun ) );
+ Com_Memset( &barrel, 0, sizeof( barrel ) );
+ Com_Memset( &flash, 0, sizeof( flash ) );
+
VectorCopy( parent->lightingOrigin, gun.lightingOrigin );
gun.shadowPlane = parent->shadowPlane;
gun.renderfx = parent->renderfx;
- // set custom shading for railgun refire rate
if( ps )
{
gun.shaderRGBA[ 0 ] = 255;
@@ -842,7 +1054,15 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
}
}
- gun.hModel = weapon->weaponModel;
+ if( !ps )
+ {
+ gun.hModel = weapon->weaponModel3rdPerson;
+
+ if( !gun.hModel )
+ gun.hModel = weapon->weaponModel;
+ }
+ else
+ gun.hModel = weapon->weaponModel;
noGunModel = ( ( !ps || cg.renderingThirdPerson ) && weapon->disableIn3rdPerson ) || !gun.hModel;
@@ -858,27 +1078,46 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound );
}
+ // Lucifer cannon charge warning beep
+ if( weaponNum == WP_LUCIFER_CANNON &&
+ ( cent->currentState.eFlags & EF_WARN_CHARGE ) &&
+ cg.snap->ps.stats[ STAT_TEAM ] != TEAM_ALIENS )
+ {
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin,
+ vec3_origin, ps ? cgs.media.lCannonWarningSound :
+ cgs.media.lCannonWarningSound2 );
+ }
+
if( !noGunModel )
{
CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon" );
+ CG_WeaponAnimation( cent, &gun.oldframe, &gun.frame, &gun.backlerp );
trap_R_AddRefEntityToScene( &gun );
+ if( !ps )
+ {
+ barrel.hModel = weapon->barrelModel3rdPerson;
+
+ if( !barrel.hModel )
+ barrel.hModel = weapon->barrelModel;
+ }
+ else
+ barrel.hModel = weapon->barrelModel;
+
// add the spinning barrel
- if( weapon->barrelModel )
+ if( barrel.hModel )
{
- memset( &barrel, 0, sizeof( barrel ) );
VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
barrel.shadowPlane = parent->shadowPlane;
barrel.renderfx = parent->renderfx;
- barrel.hModel = weapon->barrelModel;
angles[ YAW ] = 0;
angles[ PITCH ] = 0;
angles[ ROLL ] = CG_MachinegunSpinAngle( cent, firing );
AnglesToAxis( angles, barrel.axis );
- CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" );
+ CG_PositionRotatedEntityOnTag( &barrel, &gun, gun.hModel, "tag_barrel" );
trap_R_AddRefEntityToScene( &barrel );
}
@@ -892,7 +1131,7 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
if( noGunModel )
CG_SetAttachmentTag( &cent->muzzlePS->attachment, *parent, parent->hModel, "tag_weapon" );
else
- CG_SetAttachmentTag( &cent->muzzlePS->attachment, gun, weapon->weaponModel, "tag_flash" );
+ CG_SetAttachmentTag( &cent->muzzlePS->attachment, gun, gun.hModel, "tag_flash" );
}
//if the PS is infinite disable it when not firing
@@ -908,12 +1147,20 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
return;
}
- memset( &flash, 0, sizeof( flash ) );
VectorCopy( parent->lightingOrigin, flash.lightingOrigin );
flash.shadowPlane = parent->shadowPlane;
flash.renderfx = parent->renderfx;
- flash.hModel = weapon->flashModel;
+ if( !ps )
+ {
+ flash.hModel = weapon->flashModel3rdPerson;
+
+ if( !flash.hModel )
+ flash.hModel = weapon->flashModel;
+ }
+ else
+ flash.hModel = weapon->flashModel;
+
if( flash.hModel )
{
angles[ YAW ] = 0;
@@ -924,7 +1171,7 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
if( noGunModel )
CG_PositionRotatedEntityOnTag( &flash, parent, parent->hModel, "tag_weapon" );
else
- CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash" );
+ CG_PositionRotatedEntityOnTag( &flash, &gun, gun.hModel, "tag_flash" );
trap_R_AddRefEntityToScene( &flash );
}
@@ -941,7 +1188,7 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
if( noGunModel )
CG_SetAttachmentTag( &cent->muzzlePS->attachment, *parent, parent->hModel, "tag_weapon" );
else
- CG_SetAttachmentTag( &cent->muzzlePS->attachment, gun, weapon->weaponModel, "tag_flash" );
+ CG_SetAttachmentTag( &cent->muzzlePS->attachment, gun, gun.hModel, "tag_flash" );
CG_SetAttachmentCent( &cent->muzzlePS->attachment, cent );
CG_AttachToTag( &cent->muzzlePS->attachment );
@@ -970,6 +1217,9 @@ CG_AddViewWeapon
Add the weapon, and flash for the player's view
==============
*/
+
+#define WEAPON_CLICK_REPEAT 500
+
void CG_AddViewWeapon( playerState_t *ps )
{
refEntity_t hand;
@@ -981,20 +1231,23 @@ void CG_AddViewWeapon( playerState_t *ps )
weapon_t weapon = ps->weapon;
weaponMode_t weaponMode = ps->generic1;
+ // no weapon carried - can't draw it
+ if( weapon == WP_NONE )
+ return;
+
if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES )
weaponMode = WPM_PRIMARY;
- CG_RegisterWeapon( weapon );
wi = &cg_weapons[ weapon ];
- cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
-
- if( ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) ||
- ( ps->stats[ STAT_STATE ] & SS_INFESTING ) ||
- ( ps->stats[ STAT_STATE ] & SS_HOVELING ) )
+ if( !wi->registered )
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: CG_AddViewWeapon: weapon %d (%s) "
+ "is not registered\n", weapon, BG_Weapon( weapon )->name );
return;
+ }
+ cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
- // no weapon carried - can't draw it
- if( weapon == WP_NONE )
+ if( ps->persistant[PERS_SPECSTATE] != SPECTATOR_NOT )
return;
if( ps->pm_type == PM_INTERMISSION )
@@ -1004,12 +1257,6 @@ void CG_AddViewWeapon( playerState_t *ps )
if( ( ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) > BA_NONE )
CG_GhostBuildable( ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT );
- if( weapon == WP_LUCIFER_CANNON && ps->stats[ STAT_MISC ] > 0 )
- {
- if( ps->stats[ STAT_MISC ] > ( LCANNON_TOTAL_CHARGE - ( LCANNON_TOTAL_CHARGE / 3 ) ) )
- trap_S_AddLoopingSound( ps->clientNum, ps->origin, vec3_origin, cgs.media.lCannonWarningSound );
- }
-
// no gun if in third person view
if( cg.renderingThirdPerson )
return;
@@ -1052,7 +1299,7 @@ void CG_AddViewWeapon( playerState_t *ps )
else
fovOffset = 0;
- memset( &hand, 0, sizeof( hand ) );
+ Com_Memset( &hand, 0, sizeof( hand ) );
// set up gun position
CG_CalculateWeaponPosition( hand.origin, angles );
@@ -1061,12 +1308,16 @@ void CG_AddViewWeapon( playerState_t *ps )
VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[ 1 ], hand.origin );
VectorMA( hand.origin, ( cg_gun_z.value + fovOffset ), cg.refdef.viewaxis[ 2 ], hand.origin );
+ // Lucifer Cannon vibration effect
if( weapon == WP_LUCIFER_CANNON && ps->stats[ STAT_MISC ] > 0 )
{
- float fraction = (float)ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE;
+ float fraction;
- VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 0 ], hand.origin );
- VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 1 ], hand.origin );
+ fraction = (float)ps->stats[ STAT_MISC ] / LCANNON_CHARGE_TIME_MAX;
+ VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 0 ],
+ hand.origin );
+ VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 1 ],
+ hand.origin );
}
AnglesToAxis( angles, hand.axis );
@@ -1109,19 +1360,7 @@ CG_WeaponSelectable
*/
static qboolean CG_WeaponSelectable( weapon_t weapon )
{
- //int ammo, clips;
- //
- //ammo = cg.snap->ps.ammo;
- //clips = cg.snap->ps.clips
- //
- // this is a pain in the ass
- //if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( i ) )
- // return qfalse;
-
- if( !BG_InventoryContainsWeapon( weapon, cg.snap->ps.stats ) )
- return qfalse;
-
- return qtrue;
+ return BG_InventoryContainsWeapon( weapon, cg.snap->ps.stats );
}
@@ -1135,7 +1374,7 @@ static qboolean CG_UpgradeSelectable( upgrade_t upgrade )
if( !BG_InventoryContainsUpgrade( upgrade, cg.snap->ps.stats ) )
return qfalse;
- return BG_FindUsableForUpgrade( upgrade );
+ return BG_Upgrade( upgrade )->usable;
}
@@ -1149,22 +1388,19 @@ CG_DrawItemSelect
void CG_DrawItemSelect( rectDef_t *rect, vec4_t color )
{
int i;
- int x = rect->x;
- int y = rect->y;
- int width = rect->w;
- int height = rect->h;
- int iconsize;
+ float x = rect->x;
+ float y = rect->y;
+ float width = rect->w;
+ float height = rect->h;
+ float iconWidth;
+ float iconHeight;
int items[ 64 ];
+ int colinfo[ 64 ];
int numItems = 0, selectedItem = 0;
int length;
- int selectWindow;
qboolean vertical;
- centity_t *cent;
playerState_t *ps;
-
- int colinfo[ 64 ];
- cent = &cg_entities[ cg.snap->ps.clientNum ];
ps = &cg.snap->ps;
// don't display if dead
@@ -1174,109 +1410,121 @@ void CG_DrawItemSelect( rectDef_t *rect, vec4_t color )
if( !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
{
// first make sure that whatever it selected is actually selectable
- if( cg.weaponSelect <= 32 && !CG_WeaponSelectable( cg.weaponSelect ) )
- CG_NextWeapon_f( );
- else if( cg.weaponSelect > 32 && !CG_UpgradeSelectable( cg.weaponSelect - 32 ) )
- CG_NextWeapon_f( );
+ if( cg.weaponSelect < 32 )
+ {
+ if( !CG_WeaponSelectable( cg.weaponSelect ) )
+ CG_NextWeapon_f( );
+ }
+ else
+ {
+ if( !CG_UpgradeSelectable( cg.weaponSelect - 32 ) )
+ CG_NextWeapon_f( );
+ }
}
// showing weapon select clears pickup item display, but not the blend blob
cg.itemPickupTime = 0;
- if( height > width )
- {
- vertical = qtrue;
- iconsize = width;
- length = height / width;
- }
- else
- {
- vertical = qfalse;
- iconsize = height;
- length = width / height;
- }
-
- selectWindow = length / 2;
-
+ // put all weapons in the items list
for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
{
if( !BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) )
continue;
-
- {
- int ammo, clips;
-
- ammo = cg.snap->ps.ammo;
- clips = cg.snap->ps.clips;
-
- if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( i ) )
- colinfo[ numItems ] = 1;
- else
- colinfo[ numItems ] = 0;
-
- }
+
+ if( !ps->ammo && !ps->clips && !BG_Weapon( i )->infiniteAmmo )
+ colinfo[ numItems ] = 1;
+ else
+ colinfo[ numItems ] = 0;
if( i == cg.weaponSelect )
selectedItem = numItems;
- CG_RegisterWeapon( i );
+ if( !cg_weapons[ i ].registered )
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: CG_DrawItemSelect: weapon %d (%s) "
+ "is not registered\n", i, BG_Weapon( i )->name );
+ continue;
+ }
items[ numItems ] = i;
numItems++;
}
+ // put all upgrades in the weapons list
for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
{
if( !BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) )
continue;
colinfo[ numItems ] = 0;
- if( !BG_FindUsableForUpgrade ( i ) )
+ if( !BG_Upgrade( i )->usable )
colinfo[ numItems ] = 2;
-
if( i == cg.weaponSelect - 32 )
selectedItem = numItems;
- CG_RegisterUpgrade( i );
+ if( !cg_upgrades[ i ].registered )
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: CG_DrawItemSelect: upgrade %d (%s) "
+ "is not registered\n", i, BG_Upgrade( i )->name );
+ continue;
+ }
items[ numItems ] = i + 32;
numItems++;
}
+ // compute the length of the display window and determine orientation
+ vertical = height > width;
+ if( vertical )
+ {
+ iconWidth = width * cgDC.aspectScale;
+ iconHeight = width;
+ length = height / ( width * cgDC.aspectScale );
+ }
+ else
+ {
+ iconWidth = height * cgDC.aspectScale;
+ iconHeight = height;
+ length = width / ( height * cgDC.aspectScale );
+ }
+
+ // render icon ring
for( i = 0; i < length; i++ )
{
- int displacement = i - selectWindow;
- int item = displacement + selectedItem;
+ int item = i - length / 2 + selectedItem;
- if( ( item >= 0 ) && ( item < numItems ) )
+ if( item < 0 )
+ item += length;
+ else if( item >= length )
+ item -= length;
+ if( item >= 0 && item < numItems )
{
switch( colinfo[ item ] )
{
- case 0:
- color = colorCyan;
- break;
- case 1:
- color = colorRed;
- break;
- case 2:
- color = colorGray;
- break;
+ case 0:
+ color = colorCyan;
+ break;
+ case 1:
+ color = colorRed;
+ break;
+ case 2:
+ color = colorMdGrey;
+ break;
}
color[3] = 0.5;
-
trap_R_SetColor( color );
- if( items[ item ] <= 32 )
- CG_DrawPic( x, y, iconsize, iconsize, cg_weapons[ items[ item ] ].weaponIcon );
- else if( items[ item ] > 32 )
- CG_DrawPic( x, y, iconsize, iconsize, cg_upgrades[ items[ item ] - 32 ].upgradeIcon );
-
- trap_R_SetColor( NULL );
+ if( items[ item ] < 32 )
+ CG_DrawPic( x, y, iconWidth, iconHeight,
+ cg_weapons[ items[ item ] ].weaponIcon );
+ else
+ CG_DrawPic( x, y, iconWidth, iconHeight,
+ cg_upgrades[ items[ item ] - 32 ].upgradeIcon );
}
-
if( vertical )
- y += iconsize;
+ y += iconHeight;
else
- x += iconsize;
+ x += iconWidth;
}
+ trap_R_SetColor( NULL );
}
@@ -1298,29 +1546,29 @@ void CG_DrawItemSelectText( rectDef_t *rect, float scale, int textStyle )
trap_R_SetColor( color );
// draw the selected name
- if( cg.weaponSelect <= 32 )
+ if( cg.weaponSelect < 32 )
{
if( cg_weapons[ cg.weaponSelect ].registered &&
BG_InventoryContainsWeapon( cg.weaponSelect, cg.snap->ps.stats ) )
{
if( ( name = cg_weapons[ cg.weaponSelect ].humanName ) )
{
- w = CG_Text_Width( name, scale, 0 );
+ w = UI_Text_Width( name, scale );
x = rect->x + rect->w / 2;
- CG_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle );
+ UI_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle );
}
}
}
- else if( cg.weaponSelect > 32 )
+ else
{
if( cg_upgrades[ cg.weaponSelect - 32 ].registered &&
BG_InventoryContainsUpgrade( cg.weaponSelect - 32, cg.snap->ps.stats ) )
{
if( ( name = cg_upgrades[ cg.weaponSelect - 32 ].humanName ) )
{
- w = CG_Text_Width( name, scale, 0 );
+ w = UI_Text_Width( name, scale );
x = rect->x + rect->w / 2;
- CG_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle );
+ UI_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle );
}
}
}
@@ -1357,12 +1605,12 @@ void CG_NextWeapon_f( void )
if( cg.weaponSelect == 64 )
cg.weaponSelect = 0;
- if( cg.weaponSelect <= 32 )
+ if( cg.weaponSelect < 32 )
{
if( CG_WeaponSelectable( cg.weaponSelect ) )
break;
}
- else if( cg.weaponSelect > 32 )
+ else
{
if( CG_UpgradeSelectable( cg.weaponSelect - 32 ) )
break;
@@ -1401,12 +1649,12 @@ void CG_PrevWeapon_f( void )
if( cg.weaponSelect == -1 )
cg.weaponSelect = 63;
- if( cg.weaponSelect <= 32 )
+ if( cg.weaponSelect < 32 )
{
if( CG_WeaponSelectable( cg.weaponSelect ) )
break;
}
- else if( cg.weaponSelect > 32 )
+ else
{
if( CG_UpgradeSelectable( cg.weaponSelect - 32 ) )
break;
@@ -1521,7 +1769,7 @@ Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing
=================
*/
void CG_MissileHitWall( weapon_t weaponNum, weaponMode_t weaponMode, int clientNum,
- vec3_t origin, vec3_t dir, impactSound_t soundType )
+ vec3_t origin, vec3_t dir, impactSound_t soundType, int charge )
{
qhandle_t mark = 0;
qhandle_t ps = 0;
@@ -1579,6 +1827,7 @@ void CG_MissileHitWall( weapon_t weaponNum, weaponMode_t weaponMode, int clientN
CG_SetAttachmentPoint( &partSystem->attachment, origin );
CG_SetParticleSystemNormal( partSystem, dir );
CG_AttachToPoint( &partSystem->attachment );
+ partSystem->charge = charge;
}
}
@@ -1592,11 +1841,11 @@ void CG_MissileHitWall( weapon_t weaponNum, weaponMode_t weaponMode, int clientN
/*
=================
-CG_MissileHitPlayer
+CG_MissileHitEntity
=================
*/
-void CG_MissileHitPlayer( weapon_t weaponNum, weaponMode_t weaponMode,
- vec3_t origin, vec3_t dir, int entityNum )
+void CG_MissileHitEntity( weapon_t weaponNum, weaponMode_t weaponMode,
+ vec3_t origin, vec3_t dir, int entityNum, int charge )
{
vec3_t normal;
weaponInfo_t *weapon = &cg_weapons[ weaponNum ];
@@ -1610,7 +1859,25 @@ void CG_MissileHitPlayer( weapon_t weaponNum, weaponMode_t weaponMode,
weaponMode = WPM_PRIMARY;
if( weapon->wim[ weaponMode ].alwaysImpact )
- CG_MissileHitWall( weaponNum, weaponMode, 0, origin, dir, IMPACTSOUND_FLESH );
+ {
+ int sound;
+
+ if( cg_entities[ entityNum ].currentState.eType == ET_PLAYER )
+ {
+ // Players
+ sound = IMPACTSOUND_FLESH;
+ }
+ else if( cg_entities[ entityNum ].currentState.eType == ET_BUILDABLE &&
+ BG_Buildable( cg_entities[ entityNum ].currentState.modelindex )->team == TEAM_ALIENS )
+ {
+ // Alien buildables
+ sound = IMPACTSOUND_FLESH;
+ }
+ else
+ sound = IMPACTSOUND_DEFAULT;
+
+ CG_MissileHitWall( weaponNum, weaponMode, 0, origin, dir, sound, charge );
+ }
}
@@ -1772,7 +2039,7 @@ void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh,
if( flesh )
CG_Bleed( end, normal, fleshEntityNum );
else
- CG_MissileHitWall( WP_MACHINEGUN, WPM_PRIMARY, 0, end, normal, IMPACTSOUND_DEFAULT );
+ CG_MissileHitWall( WP_MACHINEGUN, WPM_PRIMARY, 0, end, normal, IMPACTSOUND_DEFAULT, 0 );
}
/*
@@ -1818,12 +2085,13 @@ static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int othe
if( !( tr.surfaceFlags & SURF_NOIMPACT ) )
{
- if( cg_entities[ tr.entityNum ].currentState.eType == ET_PLAYER )
- CG_MissileHitPlayer( WP_SHOTGUN, WPM_PRIMARY, tr.endpos, tr.plane.normal, tr.entityNum );
+ if( cg_entities[ tr.entityNum ].currentState.eType == ET_PLAYER ||
+ cg_entities[ tr.entityNum ].currentState.eType == ET_BUILDABLE )
+ CG_MissileHitEntity( WP_SHOTGUN, WPM_PRIMARY, tr.endpos, tr.plane.normal, tr.entityNum, 0 );
else if( tr.surfaceFlags & SURF_METALSTEPS )
- CG_MissileHitWall( WP_SHOTGUN, WPM_PRIMARY, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL );
+ CG_MissileHitWall( WP_SHOTGUN, WPM_PRIMARY, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL, 0 );
else
- CG_MissileHitWall( WP_SHOTGUN, WPM_PRIMARY, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT );
+ CG_MissileHitWall( WP_SHOTGUN, WPM_PRIMARY, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT, 0 );
}
}
}
@@ -1845,3 +2113,54 @@ void CG_ShotgunFire( entityState_t *es )
CG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum );
}
+/*
+=================
+CG_Bleed
+
+This is the spurt of blood when a character gets hit
+=================
+*/
+void CG_Bleed( vec3_t origin, vec3_t normal, int entityNum )
+{
+ team_t team;
+ qhandle_t bleedPS;
+ particleSystem_t *ps;
+
+ if( !cg_blood.integer )
+ return;
+
+ if( cg_entities[ entityNum ].currentState.eType == ET_PLAYER )
+ {
+ team = cgs.clientinfo[ entityNum ].team;
+ if( team == TEAM_ALIENS )
+ bleedPS = cgs.media.alienBleedPS;
+ else if( team == TEAM_HUMANS )
+ bleedPS = cgs.media.humanBleedPS;
+ else
+ return;
+ }
+ else if( cg_entities[ entityNum ].currentState.eType == ET_BUILDABLE )
+ {
+ //ew
+ team = BG_Buildable( cg_entities[ entityNum ].currentState.modelindex )->team;
+ if( team == TEAM_ALIENS )
+ bleedPS = cgs.media.alienBuildableBleedPS;
+ else if( team == TEAM_HUMANS )
+ bleedPS = cgs.media.humanBuildableBleedPS;
+ else
+ return;
+ }
+ else
+ return;
+
+ ps = CG_SpawnNewParticleSystem( bleedPS );
+
+ if( CG_IsParticleSystemValid( &ps ) )
+ {
+ CG_SetAttachmentPoint( &ps->attachment, origin );
+ CG_SetAttachmentCent( &ps->attachment, &cg_entities[ entityNum ] );
+ CG_AttachToPoint( &ps->attachment );
+
+ CG_SetParticleSystemNormal( ps, normal );
+ }
+}
diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt
new file mode 100644
index 0000000..c10fd9c
--- /dev/null
+++ b/src/client/CMakeLists.txt
@@ -0,0 +1,209 @@
+#
+## .o88b. db d888888b d88888b d8b db d888888b
+## d8P Y8 88 `88' 88' 888o 88 `~~88~~'
+## 8P 88 88 88ooooo 88V8o 88 88
+## 8b 88 88 88~~~~~ 88 V8o88 88
+## Y8b d8 88booo. .88. 88. 88 V888 88
+## `Y88P' Y88888P Y888888P Y88888P VP V8P YP
+#
+
+find_package(CURL)
+find_package(OpenGL)
+find_package(OpenAL)
+include(${CMAKE_SOURCE_DIR}/cmake/SDL2.cmake)
+
+add_definitions(
+ -DUSE_LOCAL_HEADERS
+ -DUSE_RESTCLIENT
+ -DUSE_CODEC_OPUS
+ -DUSE_OPENAL
+ -DUSE_OPENAL_DLOPEN
+ -DUSE_INTERNAL_JPEG
+ -DUSE_RENDERER_DLOPEN
+ -DNDEBUG
+ -DPRODUCT_VERSION="1.3.0 alpha"
+ ${SDL2_DEFINES}
+ )
+
+set(PARENT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
+set(EXTERNAL_DIR ${CMAKE_SOURCE_DIR}/external)
+if(APPLE)
+set(APPLE_SOURCES ${PARENT_DIR}/sys/sys_osx.mm)
+endif(APPLE)
+
+add_executable(
+ tremulous
+ #
+ ${PARENT_DIR}/asm/snapvector.c
+ #
+ cl_avi.cpp
+ cl_cgame.cpp
+ cl_cin.cpp
+ cl_console.cpp
+ cl_curl.cpp
+ cl_input.cpp
+ cl_keys.cpp
+ cl_main.cpp
+ cl_net_chan.cpp
+ cl_parse.cpp
+ cl_rest.cpp
+ cl_scrn.cpp
+ cl_ui.cpp
+ cl_updates.cpp
+ libmumblelink.cpp
+ qal.cpp
+ snd_adpcm.cpp
+ snd_codec.cpp
+ snd_codec_ogg.cpp
+ snd_codec_opus.cpp
+ snd_codec_wav.cpp
+ snd_dma.cpp
+ snd_main.cpp
+ snd_mem.cpp
+ snd_mix.cpp
+ snd_openal.cpp
+ snd_wavelet.cpp
+ #
+ ${PARENT_DIR}/qcommon/cm_load.cpp
+ ${PARENT_DIR}/qcommon/cm_patch.cpp
+ ${PARENT_DIR}/qcommon/cm_polylib.cpp
+ ${PARENT_DIR}/qcommon/cm_test.cpp
+ ${PARENT_DIR}/qcommon/cm_trace.cpp
+ ${PARENT_DIR}/qcommon/cmd.cpp
+ ${PARENT_DIR}/qcommon/common.cpp
+ ${PARENT_DIR}/qcommon/crypto.cpp
+ ${PARENT_DIR}/qcommon/cvar.cpp
+ ${PARENT_DIR}/qcommon/cvar.h
+ ${PARENT_DIR}/qcommon/files.cpp
+ ${PARENT_DIR}/qcommon/files.h
+ ${PARENT_DIR}/qcommon/huffman.cpp
+ ${PARENT_DIR}/qcommon/huffman.h
+ ${PARENT_DIR}/qcommon/ioapi.cpp
+ ${PARENT_DIR}/qcommon/md4.cpp
+ ${PARENT_DIR}/qcommon/md5.cpp
+ ${PARENT_DIR}/qcommon/msg.cpp
+ ${PARENT_DIR}/qcommon/msg.h
+ ${PARENT_DIR}/qcommon/net_chan.cpp
+ ${PARENT_DIR}/qcommon/net_ip.cpp
+ ${PARENT_DIR}/qcommon/net.h
+ ${PARENT_DIR}/qcommon/parse.cpp
+ ${PARENT_DIR}/qcommon/puff.cpp
+ ${PARENT_DIR}/qcommon/q_shared.c
+ ${PARENT_DIR}/qcommon/q3_lauxlib.cpp
+ ${PARENT_DIR}/qcommon/q_math.c
+ ${PARENT_DIR}/qcommon/unzip.cpp
+ ${PARENT_DIR}/qcommon/vm.cpp
+ ${PARENT_DIR}/qcommon/vm_interpreted.cpp
+ ${PARENT_DIR}/qcommon/vm_x86.cpp
+ #
+ ${PARENT_DIR}/sdl/sdl_input.cpp
+ ${PARENT_DIR}/sdl/sdl_snd.cpp
+ #
+ ${PARENT_DIR}/server/sv_ccmds.cpp
+ ${PARENT_DIR}/server/sv_client.cpp
+ ${PARENT_DIR}/server/sv_game.cpp
+ ${PARENT_DIR}/server/sv_init.cpp
+ ${PARENT_DIR}/server/sv_main.cpp
+ ${PARENT_DIR}/server/sv_net_chan.cpp
+ ${PARENT_DIR}/server/sv_snapshot.cpp
+ ${PARENT_DIR}/server/sv_world.cpp
+ #
+ ${PARENT_DIR}/sys/con_log.cpp
+ ${PARENT_DIR}/sys/con_tty.cpp
+ ${PARENT_DIR}/sys/sys_main.cpp
+ ${PARENT_DIR}/sys/sys_unix.cpp
+ ${PARENT_DIR}/sys/sys_shared.h
+ ${APPLE_SOURCES}
+
+ ${EXTERNAL_DIR}/semver/src/lib/semantic_version_v1.cpp
+ ${EXTERNAL_DIR}/semver/src/lib/semantic_version_v2.cpp
+ )
+
+if(APPLE)
+ # FIXME Prefixed with "lua" to prevent cmake from doing "-l-framework Cocoa"
+ set(FRAMEWORKS "-framework Cocoa -framework Security -framework OpenAL -framework IOKit")
+else(APPLE)
+ if(UNIX)
+ set(SYSLIBS dl rt)
+ endif(UNIX)
+endif(APPLE)
+
+if(NOT USE_RENDERER_DLOPEN)
+ if(USE_OPENGL1)
+ set(RENDERER_LIBRARY renderergl1)
+ endif(USE_OPENGL1)
+ set(RENDERER_LIBRARY renderergl2)
+endif(NOT USE_RENDERER_DLOPEN)
+
+target_link_libraries(
+ tremulous
+ #
+ lua
+ nettle
+ zlib
+ ogg
+ opus
+ opusfile
+ #
+ script_api
+ restclient
+ #
+ ${FRAMEWORKS}
+ ${CURL_LIBRARIES}
+ ${SDL2_LIBRARIES}
+ ${OPENGL_LIBRARIES}
+ ${OPENAL_LIBRARY}
+ ${SYSLIBS}
+ )
+
+include_directories(
+ ${PARENT_DIR}
+ ${PARENT_DIR}/qcommon
+ ${EXTERNAL_DIR}/zlib
+ ${EXTERNAL_DIR}/restclient
+ ${EXTERNAL_DIR}/rapidjson
+ ${EXTERNAL_DIR}/SDL2/include
+ ${EXTERNAL_DIR}/jpeg-8c
+ ${EXTERNAL_DIR}/libogg-1.3.2/include
+ ${EXTERNAL_DIR}/lua-5.3.3/include
+ ${EXTERNAL_DIR}/sol
+ ${EXTERNAL_DIR}/nettle-3.3
+ ${EXTERNAL_DIR}/opus-1.1.4/include
+ ${EXTERNAL_DIR}/opusfile-0.8/include
+ ${EXTERNAL_DIR}/restclient
+ ${EXTERNAL_DIR}/semver/src/include
+ ${SDL2_INCLUDE_DIRS}
+ ${OPENAL_INCLUDE_DIR}
+ )
+
+# TODO: Turn this into a macro
+if (USE_INTERNAL_SDL2)
+add_custom_command(
+ TARGET tremulous
+ POST_BUILD COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${CMAKE_SOURCE_DIR}/external/SDL2/libs/Darwin/libSDL2-2.0.0.dylib ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libSDL2-2.0.0.dylib
+ )
+endif(USE_INTERNAL_SDL2)
+
+if (USE_RENDERER_DLOPEN)
+ add_custom_command(
+ TARGET tremulous
+ POST_BUILD COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${CMAKE_BINARY_DIR}/src/renderergl1/librenderergl1${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/renderer_opengl1${CMAKE_SHARED_LIBRARY_SUFFIX}
+ )
+
+ add_custom_command(
+ TARGET tremulous
+ POST_BUILD COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${CMAKE_BINARY_DIR}/src/renderergl2/librenderergl2${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/renderer_opengl2${CMAKE_SHARED_LIBRARY_SUFFIX}
+ )
+endif(USE_RENDERER_DLOPEN)
+
+add_dependencies(
+ tremulous
+ ui
+ game
+ cgame
+ renderergl1
+ renderergl2
+ )
diff --git a/src/client/cl_avi.cpp b/src/client/cl_avi.cpp
new file mode 100644
index 0000000..d533e60
--- /dev/null
+++ b/src/client/cl_avi.cpp
@@ -0,0 +1,664 @@
+/*
+===========================================================================
+Copyright (C) 2005-2009 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "client.h"
+#include "snd_local.h"
+
+#define INDEX_FILE_EXTENSION ".index.dat"
+
+#define MAX_RIFF_CHUNKS 16
+
+typedef struct audioFormat_s
+{
+ int rate;
+ int format;
+ int channels;
+ int bits;
+
+ int sampleSize;
+ int totalBytes;
+} audioFormat_t;
+
+typedef struct aviFileData_s
+{
+ bool fileOpen;
+ fileHandle_t f;
+ char fileName[ MAX_QPATH ];
+ int fileSize;
+ int moviOffset;
+ int moviSize;
+
+ fileHandle_t idxF;
+ int numIndices;
+
+ int frameRate;
+ int framePeriod;
+ int width, height;
+ int numVideoFrames;
+ int maxRecordSize;
+ bool motionJpeg;
+
+ bool audio;
+ audioFormat_t a;
+ int numAudioFrames;
+
+ int chunkStack[ MAX_RIFF_CHUNKS ];
+ int chunkStackTop;
+
+ byte *cBuffer, *eBuffer;
+} aviFileData_t;
+
+static aviFileData_t afd;
+
+#define MAX_AVI_BUFFER 2048
+
+static byte buffer[ MAX_AVI_BUFFER ];
+static int bufIndex;
+
+/*
+===============
+SafeFS_Write
+===============
+*/
+static ID_INLINE void SafeFS_Write( const void *buffer, int len, fileHandle_t f )
+{
+ if( FS_Write( buffer, len, f ) < len )
+ Com_Error( ERR_DROP, "Failed to write avi file" );
+}
+
+/*
+===============
+WRITE_STRING
+===============
+*/
+static ID_INLINE void WRITE_STRING( const char *s )
+{
+ ::memcpy( &buffer[ bufIndex ], s, strlen( s ) );
+ bufIndex += strlen( s );
+}
+
+/*
+===============
+WRITE_4BYTES
+===============
+*/
+static ID_INLINE void WRITE_4BYTES( int x )
+{
+ buffer[ bufIndex + 0 ] = (byte)( ( x >> 0 ) & 0xFF );
+ buffer[ bufIndex + 1 ] = (byte)( ( x >> 8 ) & 0xFF );
+ buffer[ bufIndex + 2 ] = (byte)( ( x >> 16 ) & 0xFF );
+ buffer[ bufIndex + 3 ] = (byte)( ( x >> 24 ) & 0xFF );
+ bufIndex += 4;
+}
+
+/*
+===============
+WRITE_2BYTES
+===============
+*/
+static ID_INLINE void WRITE_2BYTES( int x )
+{
+ buffer[ bufIndex + 0 ] = (byte)( ( x >> 0 ) & 0xFF );
+ buffer[ bufIndex + 1 ] = (byte)( ( x >> 8 ) & 0xFF );
+ bufIndex += 2;
+}
+
+/*
+===============
+START_CHUNK
+===============
+*/
+static ID_INLINE void START_CHUNK( const char *s )
+{
+ if( afd.chunkStackTop == MAX_RIFF_CHUNKS )
+ {
+ Com_Error( ERR_DROP, "ERROR: Top of chunkstack breached" );
+ }
+
+ afd.chunkStack[ afd.chunkStackTop ] = bufIndex;
+ afd.chunkStackTop++;
+ WRITE_STRING( s );
+ WRITE_4BYTES( 0 );
+}
+
+/*
+===============
+END_CHUNK
+===============
+*/
+static ID_INLINE void END_CHUNK( void )
+{
+ int endIndex = bufIndex;
+
+ if( afd.chunkStackTop <= 0 )
+ {
+ Com_Error( ERR_DROP, "ERROR: Bottom of chunkstack breached" );
+ }
+
+ afd.chunkStackTop--;
+ bufIndex = afd.chunkStack[ afd.chunkStackTop ];
+ bufIndex += 4;
+ WRITE_4BYTES( endIndex - bufIndex - 4 );
+ bufIndex = endIndex;
+ bufIndex = PAD( bufIndex, 2 );
+}
+
+/*
+===============
+CL_WriteAVIHeader
+===============
+*/
+void CL_WriteAVIHeader( void )
+{
+ bufIndex = 0;
+ afd.chunkStackTop = 0;
+
+ START_CHUNK( "RIFF" );
+ {
+ WRITE_STRING( "AVI " );
+ {
+ START_CHUNK( "LIST" );
+ {
+ WRITE_STRING( "hdrl" );
+ WRITE_STRING( "avih" );
+ WRITE_4BYTES( 56 ); //"avih" "chunk" size
+ WRITE_4BYTES( afd.framePeriod ); //dwMicroSecPerFrame
+ WRITE_4BYTES( afd.maxRecordSize *
+ afd.frameRate ); //dwMaxBytesPerSec
+ WRITE_4BYTES( 0 ); //dwReserved1
+ WRITE_4BYTES( 0x110 ); //dwFlags bits HAS_INDEX and IS_INTERLEAVED
+ WRITE_4BYTES( afd.numVideoFrames ); //dwTotalFrames
+ WRITE_4BYTES( 0 ); //dwInitialFrame
+
+ if( afd.audio ) //dwStreams
+ WRITE_4BYTES( 2 );
+ else
+ WRITE_4BYTES( 1 );
+
+ WRITE_4BYTES( afd.maxRecordSize ); //dwSuggestedBufferSize
+ WRITE_4BYTES( afd.width ); //dwWidth
+ WRITE_4BYTES( afd.height ); //dwHeight
+ WRITE_4BYTES( 0 ); //dwReserved[ 0 ]
+ WRITE_4BYTES( 0 ); //dwReserved[ 1 ]
+ WRITE_4BYTES( 0 ); //dwReserved[ 2 ]
+ WRITE_4BYTES( 0 ); //dwReserved[ 3 ]
+
+ START_CHUNK( "LIST" );
+ {
+ WRITE_STRING( "strl" );
+ WRITE_STRING( "strh" );
+ WRITE_4BYTES( 56 ); //"strh" "chunk" size
+ WRITE_STRING( "vids" );
+
+ if( afd.motionJpeg )
+ WRITE_STRING( "MJPG" );
+ else
+ WRITE_4BYTES( 0 ); // BI_RGB
+
+ WRITE_4BYTES( 0 ); //dwFlags
+ WRITE_4BYTES( 0 ); //dwPriority
+ WRITE_4BYTES( 0 ); //dwInitialFrame
+
+ WRITE_4BYTES( 1 ); //dwTimescale
+ WRITE_4BYTES( afd.frameRate ); //dwDataRate
+ WRITE_4BYTES( 0 ); //dwStartTime
+ WRITE_4BYTES( afd.numVideoFrames ); //dwDataLength
+
+ WRITE_4BYTES( afd.maxRecordSize ); //dwSuggestedBufferSize
+ WRITE_4BYTES( -1 ); //dwQuality
+ WRITE_4BYTES( 0 ); //dwSampleSize
+ WRITE_2BYTES( 0 ); //rcFrame
+ WRITE_2BYTES( 0 ); //rcFrame
+ WRITE_2BYTES( afd.width ); //rcFrame
+ WRITE_2BYTES( afd.height ); //rcFrame
+
+ WRITE_STRING( "strf" );
+ WRITE_4BYTES( 40 ); //"strf" "chunk" size
+ WRITE_4BYTES( 40 ); //biSize
+ WRITE_4BYTES( afd.width ); //biWidth
+ WRITE_4BYTES( afd.height ); //biHeight
+ WRITE_2BYTES( 1 ); //biPlanes
+ WRITE_2BYTES( 24 ); //biBitCount
+
+ if( afd.motionJpeg ) //biCompression
+ {
+ WRITE_STRING( "MJPG" );
+ WRITE_4BYTES( afd.width *
+ afd.height ); //biSizeImage
+ }
+ else
+ {
+ WRITE_4BYTES( 0 ); // BI_RGB
+ WRITE_4BYTES( afd.width *
+ afd.height * 3 ); //biSizeImage
+ }
+
+ WRITE_4BYTES( 0 ); //biXPelsPetMeter
+ WRITE_4BYTES( 0 ); //biYPelsPetMeter
+ WRITE_4BYTES( 0 ); //biClrUsed
+ WRITE_4BYTES( 0 ); //biClrImportant
+ }
+ END_CHUNK( );
+
+ if( afd.audio )
+ {
+ START_CHUNK( "LIST" );
+ {
+ WRITE_STRING( "strl" );
+ WRITE_STRING( "strh" );
+ WRITE_4BYTES( 56 ); //"strh" "chunk" size
+ WRITE_STRING( "auds" );
+ WRITE_4BYTES( 0 ); //FCC
+ WRITE_4BYTES( 0 ); //dwFlags
+ WRITE_4BYTES( 0 ); //dwPriority
+ WRITE_4BYTES( 0 ); //dwInitialFrame
+
+ WRITE_4BYTES( afd.a.sampleSize ); //dwTimescale
+ WRITE_4BYTES( afd.a.sampleSize *
+ afd.a.rate ); //dwDataRate
+ WRITE_4BYTES( 0 ); //dwStartTime
+ WRITE_4BYTES( afd.a.totalBytes /
+ afd.a.sampleSize ); //dwDataLength
+
+ WRITE_4BYTES( 0 ); //dwSuggestedBufferSize
+ WRITE_4BYTES( -1 ); //dwQuality
+ WRITE_4BYTES( afd.a.sampleSize ); //dwSampleSize
+ WRITE_2BYTES( 0 ); //rcFrame
+ WRITE_2BYTES( 0 ); //rcFrame
+ WRITE_2BYTES( 0 ); //rcFrame
+ WRITE_2BYTES( 0 ); //rcFrame
+
+ WRITE_STRING( "strf" );
+ WRITE_4BYTES( 18 ); //"strf" "chunk" size
+ WRITE_2BYTES( afd.a.format ); //wFormatTag
+ WRITE_2BYTES( afd.a.channels ); //nChannels
+ WRITE_4BYTES( afd.a.rate ); //nSamplesPerSec
+ WRITE_4BYTES( afd.a.sampleSize *
+ afd.a.rate ); //nAvgBytesPerSec
+ WRITE_2BYTES( afd.a.sampleSize ); //nBlockAlign
+ WRITE_2BYTES( afd.a.bits ); //wBitsPerSample
+ WRITE_2BYTES( 0 ); //cbSize
+ }
+ END_CHUNK( );
+ }
+ }
+ END_CHUNK( );
+
+ afd.moviOffset = bufIndex;
+
+ START_CHUNK( "LIST" );
+ {
+ WRITE_STRING( "movi" );
+ }
+ }
+ }
+}
+
+/*
+===============
+CL_OpenAVIForWriting
+
+Creates an AVI file and gets it into a state where
+writing the actual data can begin
+===============
+*/
+bool CL_OpenAVIForWriting( const char *fileName )
+{
+ if( afd.fileOpen )
+ return false;
+
+ ::memset( &afd, 0, sizeof( aviFileData_t ) );
+
+ // Don't start if a framerate has not been chosen
+ if( cl_aviFrameRate->integer <= 0 )
+ {
+ Com_Printf( S_COLOR_RED "cl_aviFrameRate must be >= 1\n" );
+ return false;
+ }
+
+ if( ( afd.f = FS_FOpenFileWrite( fileName ) ) <= 0 )
+ return false;
+
+ if( ( afd.idxF = FS_FOpenFileWrite(
+ va( "%s" INDEX_FILE_EXTENSION, fileName ) ) ) <= 0 )
+ {
+ FS_FCloseFile( afd.f );
+ return false;
+ }
+
+ Q_strncpyz( afd.fileName, fileName, MAX_QPATH );
+
+ afd.frameRate = cl_aviFrameRate->integer;
+ afd.framePeriod = (int)( 1000000.0f / afd.frameRate );
+ afd.width = cls.glconfig.vidWidth;
+ afd.height = cls.glconfig.vidHeight;
+
+ if( cl_aviMotionJpeg->integer )
+ afd.motionJpeg = true;
+ else
+ afd.motionJpeg = false;
+
+ // Buffers only need to store RGB pixels.
+ // Allocate a bit more space for the capture buffer to account for possible
+ // padding at the end of pixel lines, and padding for alignment
+ #define MAX_PACK_LEN 16
+ afd.cBuffer = (byte*)Z_Malloc((afd.width * 3 + MAX_PACK_LEN - 1) * afd.height + MAX_PACK_LEN - 1);
+ // raw avi files have pixel lines start on 4-byte boundaries
+ afd.eBuffer = (byte*)Z_Malloc(PAD(afd.width * 3, AVI_LINE_PADDING) * afd.height);
+
+ afd.a.rate = dma.speed;
+ afd.a.format = WAV_FORMAT_PCM;
+ afd.a.channels = dma.channels;
+ afd.a.bits = dma.samplebits;
+ afd.a.sampleSize = ( afd.a.bits / 8 ) * afd.a.channels;
+
+ if( afd.a.rate % afd.frameRate )
+ {
+ int suggestRate = afd.frameRate;
+
+ while( ( afd.a.rate % suggestRate ) && suggestRate >= 1 )
+ suggestRate--;
+
+ Com_Printf( S_COLOR_YELLOW "WARNING: cl_aviFrameRate is not a divisor "
+ "of the audio rate, suggest %d\n", suggestRate );
+ }
+
+ if( !Cvar_VariableIntegerValue( "s_initsound" ) )
+ {
+ afd.audio = false;
+ }
+ else if( Q_stricmp( Cvar_VariableString( "s_backend" ), "OpenAL" ) )
+ {
+ if( afd.a.bits != 16 || afd.a.channels != 2 )
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: Audio format of %d bit/%d channels not supported",
+ afd.a.bits, afd.a.channels );
+ afd.audio = false;
+ }
+ else
+ afd.audio = true;
+ }
+ else
+ {
+ afd.audio = false;
+ Com_Printf( S_COLOR_YELLOW "WARNING: Audio capture is not supported "
+ "with OpenAL. Set s_useOpenAL to 0 for audio capture\n" );
+ }
+
+ // This doesn't write a real header, but allocates the
+ // correct amount of space at the beginning of the file
+ CL_WriteAVIHeader( );
+
+ SafeFS_Write( buffer, bufIndex, afd.f );
+ afd.fileSize = bufIndex;
+
+ bufIndex = 0;
+ START_CHUNK( "idx1" );
+ SafeFS_Write( buffer, bufIndex, afd.idxF );
+
+ afd.moviSize = 4; // For the "movi"
+ afd.fileOpen = true;
+
+ return true;
+}
+
+/*
+===============
+CL_CheckFileSize
+===============
+*/
+static bool CL_CheckFileSize( int bytesToAdd )
+{
+ unsigned int newFileSize;
+
+ newFileSize =
+ afd.fileSize + // Current file size
+ bytesToAdd + // What we want to add
+ ( afd.numIndices * 16 ) + // The index
+ 4; // The index size
+
+ // I assume all the operating systems
+ // we target can handle a 2Gb file
+ if( newFileSize > INT_MAX )
+ {
+ // Close the current file...
+ CL_CloseAVI( );
+
+ // ...And open a new one
+ CL_OpenAVIForWriting( va( "%s_", afd.fileName ) );
+
+ return true;
+ }
+
+ return false;
+}
+
+/*
+===============
+CL_WriteAVIVideoFrame
+===============
+*/
+void CL_WriteAVIVideoFrame( const byte *imageBuffer, int size )
+{
+ int chunkOffset = afd.fileSize - afd.moviOffset - 8;
+ int chunkSize = 8 + size;
+ int paddingSize = PADLEN(size, 2);
+ byte padding[ 4 ] = { 0 };
+
+ if( !afd.fileOpen )
+ return;
+
+ // Chunk header + contents + padding
+ if( CL_CheckFileSize( 8 + size + 2 ) )
+ return;
+
+ bufIndex = 0;
+ WRITE_STRING( "00dc" );
+ WRITE_4BYTES( size );
+
+ SafeFS_Write( buffer, 8, afd.f );
+ SafeFS_Write( imageBuffer, size, afd.f );
+ SafeFS_Write( padding, paddingSize, afd.f );
+ afd.fileSize += ( chunkSize + paddingSize );
+
+ afd.numVideoFrames++;
+ afd.moviSize += ( chunkSize + paddingSize );
+
+ if( size > afd.maxRecordSize )
+ afd.maxRecordSize = size;
+
+ // Index
+ bufIndex = 0;
+ WRITE_STRING( "00dc" ); //dwIdentifier
+ WRITE_4BYTES( 0x00000010 ); //dwFlags (all frames are KeyFrames)
+ WRITE_4BYTES( chunkOffset ); //dwOffset
+ WRITE_4BYTES( size ); //dwLength
+ SafeFS_Write( buffer, 16, afd.idxF );
+
+ afd.numIndices++;
+}
+
+#define PCM_BUFFER_SIZE 44100
+
+/*
+===============
+CL_WriteAVIAudioFrame
+===============
+*/
+void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size )
+{
+ static byte pcmCaptureBuffer[ PCM_BUFFER_SIZE ] = { 0 };
+ static int bytesInBuffer = 0;
+
+ if( !afd.audio )
+ return;
+
+ if( !afd.fileOpen )
+ return;
+
+ // Chunk header + contents + padding
+ if( CL_CheckFileSize( 8 + bytesInBuffer + size + 2 ) )
+ return;
+
+ if( bytesInBuffer + size > PCM_BUFFER_SIZE )
+ {
+ Com_Printf( S_COLOR_YELLOW
+ "WARNING: Audio capture buffer overflow -- truncating\n" );
+ size = PCM_BUFFER_SIZE - bytesInBuffer;
+ }
+
+ ::memcpy( &pcmCaptureBuffer[ bytesInBuffer ], pcmBuffer, size );
+ bytesInBuffer += size;
+
+ // Only write if we have a frame's worth of audio
+ if( bytesInBuffer >= (int)ceil( (float)afd.a.rate / (float)afd.frameRate ) *
+ afd.a.sampleSize )
+ {
+ int chunkOffset = afd.fileSize - afd.moviOffset - 8;
+ int chunkSize = 8 + bytesInBuffer;
+ int paddingSize = PADLEN(bytesInBuffer, 2);
+ byte padding[ 4 ] = { 0 };
+
+ bufIndex = 0;
+ WRITE_STRING( "01wb" );
+ WRITE_4BYTES( bytesInBuffer );
+
+ SafeFS_Write( buffer, 8, afd.f );
+ SafeFS_Write( pcmCaptureBuffer, bytesInBuffer, afd.f );
+ SafeFS_Write( padding, paddingSize, afd.f );
+ afd.fileSize += ( chunkSize + paddingSize );
+
+ afd.numAudioFrames++;
+ afd.moviSize += ( chunkSize + paddingSize );
+ afd.a.totalBytes += bytesInBuffer;
+
+ // Index
+ bufIndex = 0;
+ WRITE_STRING( "01wb" ); //dwIdentifier
+ WRITE_4BYTES( 0 ); //dwFlags
+ WRITE_4BYTES( chunkOffset ); //dwOffset
+ WRITE_4BYTES( bytesInBuffer ); //dwLength
+ SafeFS_Write( buffer, 16, afd.idxF );
+
+ afd.numIndices++;
+
+ bytesInBuffer = 0;
+ }
+}
+
+/*
+===============
+CL_TakeVideoFrame
+===============
+*/
+void CL_TakeVideoFrame( void )
+{
+ // AVI file isn't open
+ if( !afd.fileOpen )
+ return;
+
+ re.TakeVideoFrame( afd.width, afd.height, afd.cBuffer, afd.eBuffer, afd.motionJpeg );
+}
+
+/*
+===============
+CL_CloseAVI
+
+Closes the AVI file and writes an index chunk
+===============
+*/
+bool CL_CloseAVI( void )
+{
+ int indexRemainder;
+ int indexSize = afd.numIndices * 16;
+ const char *idxFileName = va( "%s" INDEX_FILE_EXTENSION, afd.fileName );
+
+ // AVI file isn't open
+ if( !afd.fileOpen )
+ return false;
+
+ afd.fileOpen = false;
+
+ FS_Seek( afd.idxF, 4, FS_SEEK_SET );
+ bufIndex = 0;
+ WRITE_4BYTES( indexSize );
+ SafeFS_Write( buffer, bufIndex, afd.idxF );
+ FS_FCloseFile( afd.idxF );
+
+ // Write index
+
+ // Open the temp index file
+ if( ( indexSize = FS_FOpenFileRead( idxFileName, &afd.idxF, true ) ) <= 0 )
+ {
+ FS_FCloseFile( afd.f );
+ return false;
+ }
+
+ indexRemainder = indexSize;
+
+ // Append index to end of avi file
+ while( indexRemainder > MAX_AVI_BUFFER )
+ {
+ FS_Read( buffer, MAX_AVI_BUFFER, afd.idxF );
+ SafeFS_Write( buffer, MAX_AVI_BUFFER, afd.f );
+ afd.fileSize += MAX_AVI_BUFFER;
+ indexRemainder -= MAX_AVI_BUFFER;
+ }
+ FS_Read( buffer, indexRemainder, afd.idxF );
+ SafeFS_Write( buffer, indexRemainder, afd.f );
+ afd.fileSize += indexRemainder;
+ FS_FCloseFile( afd.idxF );
+
+ // Remove temp index file
+ FS_HomeRemove( idxFileName );
+
+ // Write the real header
+ FS_Seek( afd.f, 0, FS_SEEK_SET );
+ CL_WriteAVIHeader( );
+
+ bufIndex = 4;
+ WRITE_4BYTES( afd.fileSize - 8 ); // "RIFF" size
+
+ bufIndex = afd.moviOffset + 4; // Skip "LIST"
+ WRITE_4BYTES( afd.moviSize );
+
+ SafeFS_Write( buffer, bufIndex, afd.f );
+
+ Z_Free( afd.cBuffer );
+ Z_Free( afd.eBuffer );
+ FS_FCloseFile( afd.f );
+
+ Com_Printf( "Wrote %d:%d frames to %s\n", afd.numVideoFrames, afd.numAudioFrames, afd.fileName );
+
+ return true;
+}
+
+/*
+===============
+CL_VideoRecording
+===============
+*/
+bool CL_VideoRecording( void )
+{
+ return afd.fileOpen;
+}
diff --git a/src/client/cl_cgame.cpp b/src/client/cl_cgame.cpp
new file mode 100644
index 0000000..f16dc35
--- /dev/null
+++ b/src/client/cl_cgame.cpp
@@ -0,0 +1,1172 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// cl_cgame.c -- client system interaction with client game
+
+#include "client.h"
+
+#ifdef USE_MUMBLE
+#include "libmumblelink.h"
+#endif
+#include "snd_public.h"
+
+/*
+====================
+CL_GetGameState
+====================
+*/
+static void CL_GetGameState( gameState_t *gs )
+{
+ *gs = cl.gameState;
+}
+
+/*
+====================
+CL_GetGlconfig
+====================
+*/
+static void CL_GetGlconfig( glconfig_t *glconfig )
+{
+ *glconfig = cls.glconfig;
+}
+
+
+/*
+====================
+CL_GetUserCmd
+====================
+*/
+static bool CL_GetUserCmd( int cmdNumber, usercmd_t *ucmd )
+{
+ // cmds[cmdNumber] is the last properly generated command
+
+ // can't return anything that we haven't created yet
+ if ( cmdNumber > cl.cmdNumber )
+ Com_Error( ERR_DROP, "CL_GetUserCmd: %i >= %i", cmdNumber, cl.cmdNumber );
+
+ // the usercmd has been overwritten in the wrapping
+ // buffer because it is too far out of date
+ if ( cmdNumber <= cl.cmdNumber - CMD_BACKUP )
+ return false;
+
+ *ucmd = cl.cmds[ cmdNumber & CMD_MASK ];
+
+ return true;
+}
+
+static int CL_GetCurrentCmdNumber( void )
+{
+ return cl.cmdNumber;
+}
+
+/*
+====================
+CL_GetCurrentSnapshotNumber
+====================
+*/
+static void CL_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime )
+{
+ *snapshotNumber = cl.snap.messageNum;
+ *serverTime = cl.snap.serverTime;
+}
+
+/*
+====================
+CL_GetSnapshot
+====================
+*/
+bool CL_GetSnapshot( int snapshotNumber, snapshot_t *snapshot )
+{
+ clSnapshot_t *clSnap;
+
+ if ( snapshotNumber > cl.snap.messageNum ) {
+ Com_Error( ERR_DROP, "CL_GetSnapshot: snapshotNumber > cl.snapshot.messageNum" );
+ }
+
+ // if the frame has fallen out of the circular buffer, we can't return it
+ if ( cl.snap.messageNum - snapshotNumber >= PACKET_BACKUP )
+ return false;
+
+ // if the frame is not valid, we can't return it
+ clSnap = &cl.snapshots[snapshotNumber & PACKET_MASK];
+ if ( !clSnap->valid )
+ return false;
+
+ // if the entities in the frame have fallen out of their circular buffer,
+ // we can't return it
+ if ( cl.parseEntitiesNum - clSnap->parseEntitiesNum >= MAX_PARSE_ENTITIES )
+ return false;
+
+ // write the snapshot
+ snapshot->snapFlags = clSnap->snapFlags;
+ snapshot->ping = clSnap->ping;
+ snapshot->serverTime = clSnap->serverTime;
+ ::memcpy( snapshot->areamask, clSnap->areamask, sizeof( snapshot->areamask ) );
+
+ int count = clSnap->numEntities;
+ if ( count > MAX_ENTITIES_IN_SNAPSHOT )
+ {
+ Com_DPrintf( "CL_GetSnapshot: truncated %i entities to %i\n", count, MAX_ENTITIES_IN_SNAPSHOT );
+ count = MAX_ENTITIES_IN_SNAPSHOT;
+ }
+
+ if ( cls.cgInterface == 2 )
+ {
+ alternateSnapshot_t *altSnapshot = (alternateSnapshot_t *)snapshot;
+ altSnapshot->ps = clSnap->alternatePs;
+ altSnapshot->serverCommandSequence = clSnap->serverCommandNum;
+ altSnapshot->numEntities = count;
+
+ for ( int i = 0 ; i < count ; i++ )
+ {
+ entityState_t *es = &cl.parseEntities[ ( clSnap->parseEntitiesNum + i ) & (MAX_PARSE_ENTITIES-1) ];
+ ::memcpy( &altSnapshot->entities[i], es, (size_t)&((entityState_t *)0)->weaponAnim );
+ altSnapshot->entities[i].generic1 = es->generic1;
+ }
+ }
+ else
+ {
+ snapshot->ps = clSnap->ps;
+ snapshot->serverCommandSequence = clSnap->serverCommandNum;
+ snapshot->numEntities = count;
+ for ( int i = 0 ; i < count ; i++ )
+ {
+ snapshot->entities[i] =
+ cl.parseEntities[ ( clSnap->parseEntitiesNum + i ) & (MAX_PARSE_ENTITIES-1) ];
+ }
+ }
+
+ // FIXME: configstring changes and server commands!!!
+
+ return true;
+}
+
+/*
+=====================
+CL_SetUserCmdValue
+=====================
+*/
+void CL_SetUserCmdValue( int userCmdValue, float sensitivityScale ) {
+ cl.cgameUserCmdValue = userCmdValue;
+ cl.cgameSensitivity = sensitivityScale;
+}
+
+/*
+=====================
+CL_AddCgameCommand
+=====================
+*/
+void CL_AddCgameCommand( const char *cmdName ) {
+ Cmd_AddCommand( cmdName, NULL );
+}
+
+/*
+=====================
+CL_ConfigstringModified
+=====================
+*/
+void CL_ConfigstringModified( void )
+{
+ int idx = atoi( Cmd_Argv(1) );
+ if ( idx < 0 || idx >= MAX_CONFIGSTRINGS )
+ Com_Error( ERR_DROP, "CL_ConfigstringModified: bad index %i", idx );
+
+ // get everything after "cs <num>"
+ const char* s = Cmd_ArgsFrom(2);
+ const char* old = cl.gameState.stringData + cl.gameState.stringOffsets[ idx ];
+ if ( !strcmp(old, s) )
+ return;
+
+ // build the new gameState_t
+ gameState_t oldGs = cl.gameState;
+
+ ::memset( &cl.gameState, 0, sizeof( cl.gameState ) );
+
+ // leave the first 0 for uninitialized strings
+ cl.gameState.dataCount = 1;
+
+ const char* dup;
+ for ( int i = 0 ; i < MAX_CONFIGSTRINGS ; i++ )
+ {
+ if ( i == idx )
+ dup = s;
+ else
+ dup = oldGs.stringData + oldGs.stringOffsets[ i ];
+
+ if ( !dup[0] )
+ continue; // leave with the default empty string
+
+ int len = strlen(dup);
+ if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS )
+ Com_Error(ERR_DROP, "MAX_GAMESTATE_CHARS exceeded");
+
+ // append it to the gameState string buffer
+ cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
+ ::memcpy( cl.gameState.stringData + cl.gameState.dataCount, dup, len + 1 );
+ cl.gameState.dataCount += len + 1;
+ }
+
+ if ( idx == CS_SYSTEMINFO )
+ {
+ // parse serverId and other cvars
+ CL_SystemInfoChanged();
+ }
+}
+
+
+/*
+===================
+CL_GetServerCommand
+
+Set up argc/argv for the given command
+===================
+*/
+static bool CL_GetServerCommand( int serverCommandNumber )
+{
+ const char *s;
+ const char *cmd;
+ static char bigConfigString[BIG_INFO_STRING];
+ int argc;
+
+ // if we have irretrievably lost a reliable command, drop the connection
+ if ( serverCommandNumber <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS )
+ {
+ // when a demo record was started after the client got a whole bunch of
+ // reliable commands then the client never got those first reliable commands
+ if ( clc.demoplaying )
+ return false;
+
+ Com_Error( ERR_DROP, "CL_GetServerCommand: a reliable command was cycled out" );
+ return false;
+ }
+
+ if ( serverCommandNumber > clc.serverCommandSequence )
+ {
+ Com_Error( ERR_DROP, "CL_GetServerCommand: requested a command not received" );
+ return false;
+ }
+
+ s = clc.serverCommands[ serverCommandNumber & ( MAX_RELIABLE_COMMANDS - 1 ) ];
+ clc.lastExecutedServerCommand = serverCommandNumber;
+
+ Com_DPrintf( "serverCommand: %i : %s\n", serverCommandNumber, s );
+
+rescan:
+ Cmd_TokenizeString( s );
+ cmd = Cmd_Argv(0);
+ argc = Cmd_Argc();
+
+ if ( !strcmp( cmd, "disconnect" ) )
+ {
+ // allow server to indicate why they were disconnected
+ if ( argc >= 2 )
+ Com_Error( ERR_SERVERDISCONNECT, "Server disconnected - %s", Cmd_Argv( 1 ) );
+ else
+ Com_Error( ERR_SERVERDISCONNECT, "Server disconnected" );
+ }
+
+ if ( !strcmp( cmd, "bcs0" ) )
+ {
+ Com_sprintf( bigConfigString, BIG_INFO_STRING, "cs %s \"%s", Cmd_Argv(1), Cmd_Argv(2) );
+ return false;
+ }
+
+ if ( !strcmp( cmd, "bcs1" ) )
+ {
+ s = Cmd_Argv(2);
+ if( strlen(bigConfigString) + strlen(s) >= BIG_INFO_STRING )
+ Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
+
+ strcat( bigConfigString, s );
+ return false;
+ }
+
+ if ( !strcmp( cmd, "bcs2" ) )
+ {
+ s = Cmd_Argv(2);
+ if( strlen(bigConfigString) + strlen(s) + 1 >= BIG_INFO_STRING )
+ Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
+
+ strcat( bigConfigString, s );
+ strcat( bigConfigString, "\"" );
+ s = bigConfigString;
+ goto rescan;
+ }
+
+ if ( !strcmp( cmd, "cs" ) )
+ {
+ CL_ConfigstringModified();
+ // reparse the string, because CL_ConfigstringModified may have done
+ // another Cmd_TokenizeString()
+ Cmd_TokenizeString( s );
+ return true;
+ }
+
+ if ( !strcmp( cmd, "map_restart" ) )
+ {
+ // clear notify lines and outgoing commands before passing
+ // the restart to the cgame
+ Con_ClearNotify();
+ // reparse the string, because Con_ClearNotify() may have done another
+ // Cmd_TokenizeString()
+ Cmd_TokenizeString( s );
+ ::memset( cl.cmds, 0, sizeof( cl.cmds ) );
+ return true;
+ }
+
+ // we may want to put a "connect to other server" command here
+
+ // cgame can now act on the command
+ return true;
+}
+
+
+/*
+====================
+CL_CM_LoadMap
+
+Just adds default parameters that cgame doesn't need to know about
+====================
+*/
+void CL_CM_LoadMap( const char *mapname ) {
+ int checksum;
+
+ CM_LoadMap( mapname, true, &checksum );
+}
+
+char * safe_strncpy(char *dest, const char *src, size_t n)
+{
+ char *ret = dest;
+ while (n > 0 && src[0])
+ {
+ *ret++ = *src++;
+ --n;
+ }
+ while (n > 0)
+ {
+ *ret++ = '\0';
+ --n;
+ }
+ return dest;
+}
+
+/*
+====================
+CL_ShutdonwCGame
+
+====================
+*/
+void CL_ShutdownCGame( void ) {
+ Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CGAME );
+ cls.cgameStarted = false;
+ if ( !cls.cgame ) {
+ return;
+ }
+ VM_Call( cls.cgame, CG_SHUTDOWN );
+ VM_Free( cls.cgame );
+ cls.cgame = NULL;
+}
+
+static int FloatAsInt( float f ) {
+ floatint_t fi;
+ fi.f = f;
+ return fi.i;
+}
+
+static bool probingCG = false;
+
+/*
+====================
+CL_CgameSystemCalls
+
+The cgame module is making a system call
+====================
+*/
+intptr_t CL_CgameSystemCalls( intptr_t *args )
+{
+ if( cls.cgInterface == 2 && args[0] >= CG_R_SETCLIPREGION && args[0] < CG_MEMSET )
+ {
+ if( args[0] < CG_S_STOPBACKGROUNDTRACK - 1 )
+ args[0] += 1;
+
+ else if( args[0] < CG_S_STOPBACKGROUNDTRACK + 4 )
+ args[0] += CG_PARSE_ADD_GLOBAL_DEFINE - CG_S_STOPBACKGROUNDTRACK + 1;
+
+ else if( args[0] < CG_PARSE_ADD_GLOBAL_DEFINE + 4 )
+ args[0] -= 4;
+
+ else if( args[0] >= CG_PARSE_SOURCE_FILE_AND_LINE && args[0] <= CG_S_SOUNDDURATION )
+ args[0] = CG_PARSE_SOURCE_FILE_AND_LINE - 1337 - args[0] ;
+ }
+
+ switch( args[0] )
+ {
+ case CG_PRINT:
+ Com_Printf( "%s", (const char*)VMA(1) );
+ return 0;
+ case CG_ERROR:
+ if( probingCG )
+ {
+ cls.cgInterface = 2; // this is a 1.1.0 cgame
+ return 0;
+ }
+ Com_Error( ERR_DROP, "%s", (const char*)VMA(1) );
+ return 0;
+ case CG_MILLISECONDS:
+ return Sys_Milliseconds();
+ case CG_CVAR_REGISTER:
+ Cvar_Register( (vmCvar_t*)VMA(1), (const char*)VMA(2), (const char*)VMA(3), args[4] );
+ return 0;
+ case CG_CVAR_UPDATE:
+ Cvar_Update( (vmCvar_t*)VMA(1) );
+ return 0;
+ case CG_CVAR_SET:
+ Cvar_SetSafe( (const char*)VMA(1), (const char*)VMA(2) );
+ return 0;
+ case CG_CVAR_VARIABLESTRINGBUFFER:
+ Cvar_VariableStringBuffer( (const char*)VMA(1), (char*)VMA(2), args[3] );
+ return 0;
+ case CG_ARGC:
+ return Cmd_Argc();
+ case CG_ARGV:
+ Cmd_ArgvBuffer( args[1], (char*)VMA(2), args[3] );
+ return 0;
+ case CG_ARGS:
+ Cmd_ArgsBuffer( (char*)VMA(1), args[2] );
+ return 0;
+ case CG_LITERAL_ARGS:
+ Cmd_LiteralArgsBuffer( (char*)VMA(1), args[2] );
+ return 0;
+ case CG_FS_FOPENFILE:
+ return FS_FOpenFileByMode( (const char*)VMA(1), (fileHandle_t*)VMA(2), (FS_Mode)args[3] );
+ case CG_FS_READ:
+ FS_Read( VMA(1), args[2], args[3] );
+ return 0;
+ case CG_FS_WRITE:
+ FS_Write( VMA(1), args[2], args[3] );
+ return 0;
+ case CG_FS_FCLOSEFILE:
+ FS_FCloseFile( args[1] );
+ return 0;
+ case CG_FS_SEEK:
+ return FS_Seek( (fileHandle_t)args[1], args[2], (FS_Origin)args[3] );
+ case CG_FS_GETFILELIST:
+ return FS_GetFileList( (const char*)VMA(1), (const char*)VMA(2), (char*)VMA(3), args[4] );
+ case CG_SENDCONSOLECOMMAND:
+ Cbuf_AddText( (const char*)VMA(1) );
+ return 0;
+ case CG_ADDCOMMAND:
+ CL_AddCgameCommand( (const char*)VMA(1) );
+ return 0;
+ case CG_REMOVECOMMAND:
+ Cmd_RemoveCommandSafe( (const char*)VMA(1) );
+ return 0;
+ case CG_SENDCLIENTCOMMAND:
+ CL_AddReliableCommand((const char*)VMA(1), false);
+ return 0;
+ case CG_UPDATESCREEN:
+ // this is used during lengthy level loading, so pump message loop
+ // Com_EventLoop(); // FIXME: if a server restarts here, BAD THINGS HAPPEN!
+ // We can't call Com_EventLoop here, a restart will crash and this _does_ happen
+ // if there is a map change while we are downloading at pk3.
+ // ZOID
+ SCR_UpdateScreen();
+ return 0;
+ case CG_CM_LOADMAP:
+ CL_CM_LoadMap( (const char*)VMA(1) );
+ return 0;
+ case CG_CM_NUMINLINEMODELS:
+ return CM_NumInlineModels();
+ case CG_CM_INLINEMODEL:
+ return CM_InlineModel( args[1] );
+ case CG_CM_TEMPBOXMODEL:
+ return CM_TempBoxModel( (const float*)VMA(1), (const float*)VMA(2), false );
+ case CG_CM_TEMPCAPSULEMODEL:
+ return CM_TempBoxModel( (const float*)VMA(1), (const float*)VMA(2), true );
+ case CG_CM_POINTCONTENTS:
+ return CM_PointContents( (const float*)VMA(1), args[2] );
+ case CG_CM_TRANSFORMEDPOINTCONTENTS:
+ return CM_TransformedPointContents( (const float*)VMA(1), (clipHandle_t)args[2],
+ (const float*)VMA(3), (const float*)VMA(4) );
+ case CG_CM_BOXTRACE:
+ CM_BoxTrace( (trace_t*)VMA(1), (const float*)VMA(2), (const float*)VMA(3),
+ (float*)VMA(4), (float*)VMA(5), (clipHandle_t)args[6], args[7], TT_AABB );
+ return 0;
+ case CG_CM_CAPSULETRACE:
+ CM_BoxTrace( (trace_t*)VMA(1), (const float*)VMA(2), (const float*)VMA(3),
+ (float*)VMA(4), (float*)VMA(5), (clipHandle_t)args[6], args[7], TT_CAPSULE );
+ return 0;
+ case CG_CM_TRANSFORMEDBOXTRACE:
+ CM_TransformedBoxTrace( (trace_t*)VMA(1), (const float*)VMA(2), (const float*)VMA(3),
+ (float*)VMA(4), (float*)VMA(5), (clipHandle_t)args[6], args[7],
+ (const float*)VMA(8), (const float*)VMA(9), TT_AABB );
+ return 0;
+ case CG_CM_TRANSFORMEDCAPSULETRACE:
+ CM_TransformedBoxTrace( (trace_t*)VMA(1), (const float*)VMA(2), (const float*)VMA(3),
+ (float*)VMA(4), (float*)VMA(5), (clipHandle_t)args[6], args[7],
+ (const float*)VMA(8), (const float*)VMA(9), TT_CAPSULE );
+ return 0;
+ case CG_CM_BISPHERETRACE:
+ CM_BiSphereTrace( (trace_t*)VMA(1), (const float*)VMA(2), (const float*)VMA(3), VMF(4), VMF(5), (clipHandle_t)args[6], args[7] );
+ return 0;
+ case CG_CM_TRANSFORMEDBISPHERETRACE:
+ CM_TransformedBiSphereTrace( (trace_t*)VMA(1), (const float*)VMA(2), (const float*)VMA(3),
+ VMF(4), VMF(5), (clipHandle_t)args[6], args[7], (const float*)VMA(8) );
+ return 0;
+ case CG_CM_MARKFRAGMENTS:
+ {
+ float (&arg2)[3][3] = *reinterpret_cast<float (*)[3][3]>(VMA(2));
+ return re.MarkFragments( args[1], arg2, (const float*)VMA(3), args[4], (float*)VMA(5), args[6], (markFragment_t*)VMA(7) );
+ }
+ case CG_S_STARTSOUND:
+ S_StartSound( (float*)VMA(1), args[2], args[3], (sfxHandle_t)args[4] );
+ return 0;
+ case CG_S_STARTLOCALSOUND:
+ S_StartLocalSound( (sfxHandle_t)args[1], args[2] );
+ return 0;
+ case CG_S_CLEARLOOPINGSOUNDS:
+ S_ClearLoopingSounds( (bool)args[1] );
+ return 0;
+ case CG_S_ADDLOOPINGSOUND:
+ S_AddLoopingSound( args[1], (const float*)VMA(2), (const float*)VMA(3), (sfxHandle_t)args[4] );
+ return 0;
+ case CG_S_ADDREALLOOPINGSOUND:
+ S_AddRealLoopingSound( args[1], (const float*)VMA(2), (const float*)VMA(3), (sfxHandle_t)args[4] );
+ return 0;
+ case CG_S_STOPLOOPINGSOUND:
+ S_StopLoopingSound( args[1] );
+ return 0;
+ case CG_S_UPDATEENTITYPOSITION:
+ S_UpdateEntityPosition( args[1], (const float*)VMA(2) );
+ return 0;
+ case CG_S_RESPATIALIZE:
+ {
+ float (&arg3)[3][3] = *reinterpret_cast<float (*)[3][3]>(VMA(3));
+ S_Respatialize( args[1], (const float*)VMA(2), arg3, args[4] );
+ return 0;
+ }
+ case CG_S_REGISTERSOUND:
+ return S_RegisterSound( (const char*)VMA(1), (bool)args[2] );
+ case CG_S_SOUNDDURATION:
+ return S_SoundDuration( args[1] );
+ case CG_S_STARTBACKGROUNDTRACK:
+ S_StartBackgroundTrack( (const char*)VMA(1), (const char*)VMA(2) );
+ return 0;
+ case CG_R_LOADWORLDMAP:
+ re.LoadWorld( (const char*)VMA(1) );
+ return 0;
+ case CG_R_REGISTERMODEL:
+ return re.RegisterModel( (const char*)VMA(1) );
+ case CG_R_REGISTERSKIN:
+ return re.RegisterSkin( (const char*)VMA(1) );
+ case CG_R_REGISTERSHADER:
+ return re.RegisterShader( (const char*)VMA(1) );
+ case CG_R_REGISTERSHADERNOMIP:
+ return re.RegisterShaderNoMip( (const char*)VMA(1) );
+ case CG_R_REGISTERFONT:
+ re.RegisterFont( (const char*)VMA(1), args[2], (fontInfo_t*)VMA(3));
+ return 0;
+ case CG_R_CLEARSCENE:
+ re.ClearScene();
+ return 0;
+ case CG_R_ADDREFENTITYTOSCENE:
+ re.AddRefEntityToScene( (const refEntity_t*)VMA(1) );
+ return 0;
+ case CG_R_ADDPOLYTOSCENE:
+ re.AddPolyToScene( (qhandle_t)args[1], args[2], (const polyVert_t*)VMA(3), 1 );
+ return 0;
+ case CG_R_ADDPOLYSTOSCENE:
+ re.AddPolyToScene( (qhandle_t)args[1], args[2], (const polyVert_t*)VMA(3), args[4] );
+ return 0;
+ case CG_R_LIGHTFORPOINT:
+ return re.LightForPoint( (float*)VMA(1), (float*)VMA(2), (float*)VMA(3), (float*)VMA(4) );
+ case CG_R_ADDLIGHTTOSCENE:
+ re.AddLightToScene( (const float*)VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
+ return 0;
+ case CG_R_ADDADDITIVELIGHTTOSCENE:
+ re.AddAdditiveLightToScene( (const float*)VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
+ return 0;
+ case CG_R_RENDERSCENE:
+ re.RenderScene( (const refdef_t*)VMA(1) );
+ return 0;
+ case CG_R_SETCOLOR:
+ re.SetColor( (const float*)VMA(1) );
+ return 0;
+ case CG_R_SETCLIPREGION:
+ re.SetClipRegion( (const float*)VMA(1) );
+ return 0;
+ case CG_R_DRAWSTRETCHPIC:
+ re.DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), (qhandle_t)args[9] );
+ return 0;
+ case CG_R_MODELBOUNDS:
+ re.ModelBounds( (qhandle_t)args[1], (float*)VMA(2), (float*)VMA(3) );
+ return 0;
+ case CG_R_LERPTAG:
+ return re.LerpTag( (orientation_t*)VMA(1), args[2], args[3], args[4], VMF(5), (const char*)VMA(6) );
+ case CG_GETGLCONFIG:
+ CL_GetGlconfig( (glconfig_t*)VMA(1) );
+ return 0;
+ case CG_GETGAMESTATE:
+ CL_GetGameState( (gameState_t*)VMA(1) );
+ return 0;
+ case CG_GETCURRENTSNAPSHOTNUMBER:
+ CL_GetCurrentSnapshotNumber( (int*)VMA(1), (int*)VMA(2) );
+ return 0;
+ case CG_GETSNAPSHOT:
+ return CL_GetSnapshot( args[1], (snapshot_t*)VMA(2) );
+ case CG_GETSERVERCOMMAND:
+ return CL_GetServerCommand( args[1] );
+ case CG_GETCURRENTCMDNUMBER:
+ return CL_GetCurrentCmdNumber();
+ case CG_GETUSERCMD:
+ return CL_GetUserCmd( args[1], (usercmd_t*)VMA(2) );
+ case CG_SETUSERCMDVALUE:
+ CL_SetUserCmdValue( args[1], VMF(2) );
+ return 0;
+ case CG_MEMORY_REMAINING:
+ return Hunk_MemoryRemaining();
+ case CG_KEY_ISDOWN:
+ return Key_IsDown( args[1] );
+ case CG_KEY_GETCATCHER:
+ return Key_GetCatcher();
+ case CG_KEY_SETCATCHER:
+ // don't allow the cgame module to toggle the console
+ Key_SetCatcher( ( args[1] & ~KEYCATCH_CONSOLE ) | ( Key_GetCatcher() & KEYCATCH_CONSOLE ) );
+ return 0;
+ case CG_KEY_GETKEY:
+ return Key_GetKey( (const char*)VMA(1) );
+
+ case CG_GETDEMOSTATE:
+ return CL_DemoState( );
+ case CG_GETDEMOPOS:
+ return CL_DemoPos( );
+ case CG_GETDEMONAME:
+ CL_DemoName( (char*)VMA(1), args[2] );
+ return 0;
+
+ case CG_KEY_KEYNUMTOSTRINGBUF:
+ Key_KeynumToStringBuf( args[1], (char*)VMA(2), args[3] );
+ return 0;
+ case CG_KEY_GETBINDINGBUF:
+ Key_GetBindingBuf( args[1], (char*)VMA(2), args[3] );
+ return 0;
+ case CG_KEY_SETBINDING:
+ Key_SetBinding( args[1], (const char*)VMA(2) );
+ return 0;
+
+ case CG_PARSE_ADD_GLOBAL_DEFINE:
+ return Parse_AddGlobalDefine( (char*)VMA(1) );
+ case CG_PARSE_LOAD_SOURCE:
+ return Parse_LoadSourceHandle( (const char*)VMA(1) );
+ case CG_PARSE_FREE_SOURCE:
+ return Parse_FreeSourceHandle( args[1] );
+ case CG_PARSE_READ_TOKEN:
+ return Parse_ReadTokenHandle( args[1], (pc_token_t*)VMA(2) );
+ case CG_PARSE_SOURCE_FILE_AND_LINE:
+ return Parse_SourceFileAndLine( args[1], (char*)VMA(2), (int*)VMA(3) );
+
+ case CG_KEY_SETOVERSTRIKEMODE:
+ Key_SetOverstrikeMode( (bool)args[1] );
+ return 0;
+
+ case CG_KEY_GETOVERSTRIKEMODE:
+ return Key_GetOverstrikeMode( );
+
+ case CG_FIELD_COMPLETELIST:
+ Field_CompleteList( (char*)VMA(1) );
+ return 0;
+
+ case CG_MEMSET:
+ ::memset( VMA(1), args[2], args[3] );
+ return 0;
+ case CG_MEMCPY:
+ ::memcpy( VMA(1), VMA(2), args[3] );
+ return 0;
+ case CG_STRNCPY:
+ safe_strncpy( (char*)VMA(1), (const char*)VMA(2), args[3] );
+ return args[1];
+ case CG_SIN:
+ return FloatAsInt( sin( VMF(1) ) );
+ case CG_COS:
+ return FloatAsInt( cos( VMF(1) ) );
+ case CG_ATAN2:
+ return FloatAsInt( atan2( VMF(1), VMF(2) ) );
+ case CG_SQRT:
+ return FloatAsInt( sqrt( VMF(1) ) );
+ case CG_FLOOR:
+ return FloatAsInt( floor( VMF(1) ) );
+ case CG_CEIL:
+ return FloatAsInt( ceil( VMF(1) ) );
+ case CG_ACOS:
+ return FloatAsInt( Q_acos( VMF(1) ) );
+
+ case CG_S_STOPBACKGROUNDTRACK:
+ S_StopBackgroundTrack();
+ return 0;
+
+ case CG_REAL_TIME:
+ return Com_RealTime( (qtime_t*)VMA(1) );
+ case CG_SNAPVECTOR:
+ Q_SnapVector((float*)VMA(1));
+ return 0;
+
+ case CG_CIN_PLAYCINEMATIC:
+ return CIN_PlayCinematic((const char*)VMA(1), args[2], args[3], args[4], args[5], args[6]);
+
+ case CG_CIN_STOPCINEMATIC:
+ return CIN_StopCinematic(args[1]);
+
+ case CG_CIN_RUNCINEMATIC:
+ return CIN_RunCinematic(args[1]);
+
+ case CG_CIN_DRAWCINEMATIC:
+ CIN_DrawCinematic(args[1]);
+ return 0;
+
+ case CG_CIN_SETEXTENTS:
+ CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]);
+ return 0;
+
+ case CG_R_REMAP_SHADER:
+ re.RemapShader( (const char*)VMA(1), (const char*)VMA(2), (const char*)VMA(3) );
+ return 0;
+
+ case CG_GET_ENTITY_TOKEN:
+ return re.GetEntityToken( (char*)VMA(1), args[2] );
+ case CG_R_INPVS:
+ return re.inPVS( (const float*)VMA(1), (const float*)VMA(2) );
+
+ default:
+ assert(0);
+ Com_Error( ERR_DROP, "Bad cgame system trap: %ld", (long int) args[0] );
+ }
+ return 0;
+}
+
+
+/*
+====================
+CL_InitCGame
+
+Should only be called by CL_StartHunkUsers
+====================
+*/
+void CL_InitCGame( void ) {
+ const char *info;
+ const char *mapname;
+ int t1, t2;
+ char backup[ MAX_STRING_CHARS ];
+ vmInterpret_t interpret;
+
+ t1 = Sys_Milliseconds();
+
+ // find the current mapname
+ info = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ];
+ mapname = Info_ValueForKey( info, "mapname" );
+ Com_sprintf( cl.mapname, sizeof( cl.mapname ), "maps/%s.bsp", mapname );
+
+ // load the dll or bytecode
+ interpret = (vmInterpret_t)Cvar_VariableValue("vm_cgame");
+ if(cl_connectedToPureServer)
+ {
+ // if sv_pure is set we only allow qvms to be loaded
+ if(interpret != VMI_COMPILED && interpret != VMI_BYTECODE)
+ interpret = VMI_COMPILED;
+ }
+
+ cls.cgame = VM_Create( "cgame", CL_CgameSystemCalls, interpret );
+ if ( !cls.cgame ) {
+ Com_Error( ERR_DROP, "VM_Create on cgame failed" );
+ }
+ clc.state = CA_LOADING;
+
+ Cvar_VariableStringBuffer( "cl_voipSendTarget", backup, sizeof( backup ) );
+ Cvar_Set( "cl_voipSendTarget", "" );
+
+ // Probe 1.1 or gpp cgame
+ cls.cgInterface = 0;
+ probingCG = true;
+ VM_Call( cls.cgame, CG_VOIP_STRING );
+ probingCG = false;
+
+ Cvar_Set( "cl_voipSendTarget", backup );
+
+ if ( ( clc.netchan.alternateProtocol == 2 ) != ( cls.cgInterface == 2 ) ) {
+ Com_Error( ERR_DROP, "%s protocol %i, but a cgame module using the %s interface was found",
+ ( clc.demoplaying ? "Demo was recorded using" : "Server uses" ),
+ ( clc.netchan.alternateProtocol == 0 ? PROTOCOL_VERSION : clc.netchan.alternateProtocol == 1 ? 70 : 69 ),
+ ( cls.cgInterface == 2 ? "1.1" : "non-1.1" ) );
+ }
+
+ // init for this gamestate
+ // use the lastExecutedServerCommand instead of the serverCommandSequence
+ // otherwise server commands sent just before a gamestate are dropped
+ VM_Call( cls.cgame, CG_INIT, clc.serverMessageSequence, clc.lastExecutedServerCommand, clc.clientNum );
+
+ // reset any CVAR_CHEAT cvars registered by cgame
+ if ( !clc.demoplaying && !cl_connectedToCheatServer )
+ Cvar_SetCheatState();
+
+ // we will send a usercmd this frame, which
+ // will cause the server to send us the first snapshot
+ clc.state = CA_PRIMED;
+
+ t2 = Sys_Milliseconds();
+
+ Com_Printf( "CL_InitCGame: %5.2f seconds\n", (t2-t1)/1000.0 );
+
+ // have the renderer touch all its images, so they are present
+ // on the card even if the driver does deferred loading
+ re.EndRegistration();
+
+ // make sure everything is paged in
+ if (!Sys_LowPhysicalMemory()) {
+ Com_TouchMemory();
+
+ CL_ProtocolSpecificCommandsInit();
+ }
+
+ // clear anything that got printed
+ Con_ClearNotify ();
+}
+
+
+/*
+====================
+CL_GameCommand
+
+See if the current console command is claimed by the cgame
+====================
+*/
+bool CL_GameCommand( void )
+{
+ if ( !cls.cgame )
+ return false;
+
+ return (bool)VM_Call( cls.cgame, CG_CONSOLE_COMMAND );
+}
+
+/*
+====================
+CL_GameConsoleText
+====================
+*/
+void CL_GameConsoleText( void )
+{
+ if ( !cls.cgame )
+ return;
+
+ VM_Call( cls.cgame, CG_CONSOLE_TEXT );
+}
+
+/*
+=====================
+CL_CGameRendering
+=====================
+*/
+void CL_CGameRendering( stereoFrame_t stereo )
+{
+ VM_Call( cls.cgame, CG_DRAW_ACTIVE_FRAME, cl.serverTime, stereo, clc.demoplaying );
+ VM_Debug( 0 );
+}
+
+
+/*
+=================
+CL_AdjustTimeDelta
+
+Adjust the clients view of server time.
+
+We attempt to have cl.serverTime exactly equal the server's view
+of time plus the timeNudge, but with variable latencies over
+the internet it will often need to drift a bit to match conditions.
+
+Our ideal time would be to have the adjusted time approach, but not pass,
+the very latest snapshot.
+
+Adjustments are only made when a new snapshot arrives with a rational
+latency, which keeps the adjustment process framerate independent and
+prevents massive overadjustment during times of significant packet loss
+or bursted delayed packets.
+=================
+*/
+
+#define RESET_TIME 500
+
+void CL_AdjustTimeDelta( void ) {
+ int newDelta;
+ int deltaDelta;
+
+ cl.newSnapshots = false;
+
+ // the delta never drifts when replaying a demo
+ if ( clc.demoplaying ) {
+ return;
+ }
+
+ newDelta = cl.snap.serverTime - cls.realtime;
+ deltaDelta = abs( newDelta - cl.serverTimeDelta );
+
+ if ( deltaDelta > RESET_TIME ) {
+ cl.serverTimeDelta = newDelta;
+ cl.oldServerTime = cl.snap.serverTime; // FIXME: is this a problem for cgame?
+ cl.serverTime = cl.snap.serverTime;
+ if ( cl_showTimeDelta->integer ) {
+ Com_Printf( "<RESET> " );
+ }
+ } else if ( deltaDelta > 100 ) {
+ // fast adjust, cut the difference in half
+ if ( cl_showTimeDelta->integer ) {
+ Com_Printf( "<FAST> " );
+ }
+ cl.serverTimeDelta = ( cl.serverTimeDelta + newDelta ) >> 1;
+ } else {
+ // slow drift adjust, only move 1 or 2 msec
+
+ // if any of the frames between this and the previous snapshot
+ // had to be extrapolated, nudge our sense of time back a little
+ // the granularity of +1 / -2 is too high for timescale modified frametimes
+ if ( com_timescale->value == 0 || com_timescale->value == 1 ) {
+ if ( cl.extrapolatedSnapshot ) {
+ cl.extrapolatedSnapshot = false;
+ cl.serverTimeDelta -= 2;
+ } else {
+ // otherwise, move our sense of time forward to minimize total latency
+ cl.serverTimeDelta++;
+ }
+ }
+ }
+
+ if ( cl_showTimeDelta->integer ) {
+ Com_Printf( "%i ", cl.serverTimeDelta );
+ }
+}
+
+
+/*
+==================
+CL_FirstSnapshot
+==================
+*/
+void CL_FirstSnapshot( void ) {
+ // ignore snapshots that don't have entities
+ if ( cl.snap.snapFlags & SNAPFLAG_NOT_ACTIVE ) {
+ return;
+ }
+ clc.state = CA_ACTIVE;
+
+ // set the timedelta so we are exactly on this first frame
+ cl.serverTimeDelta = cl.snap.serverTime - cls.realtime;
+ cl.oldServerTime = cl.snap.serverTime;
+
+ clc.timeDemoBaseTime = cl.snap.serverTime;
+
+ // if this is the first frame of active play,
+ // execute the contents of activeAction now
+ // this is to allow scripting a timedemo to start right
+ // after loading
+ if ( cl_activeAction->string[0] ) {
+ Cbuf_AddText( cl_activeAction->string );
+ Cvar_Set( "activeAction", "" );
+ }
+
+#ifdef USE_MUMBLE
+ if ((cl_useMumble->integer) && !mumble_islinked()) {
+ int ret = mumble_link(CLIENT_WINDOW_TITLE);
+ Com_Printf("Mumble: Linking to Mumble application %s\n", ret==0?"ok":"failed");
+ }
+#endif
+
+#ifdef USE_VOIP
+ if (!clc.voipCodecInitialized) {
+ int i;
+ int error;
+
+ clc.opusEncoder = opus_encoder_create(48000, 1, OPUS_APPLICATION_VOIP, &error);
+
+ if ( error ) {
+ Com_DPrintf("VoIP: Error opus_encoder_create %d\n", error);
+ return;
+ }
+
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ clc.opusDecoder[i] = opus_decoder_create(48000, 1, &error);
+ if ( error ) {
+ Com_DPrintf("VoIP: Error opus_decoder_create(%d) %d\n", i, error);
+ return;
+ }
+ clc.voipIgnore[i] = false;
+ clc.voipGain[i] = 1.0f;
+ }
+ clc.voipCodecInitialized = true;
+ clc.voipMuteAll = false;
+ Cmd_AddCommand ("voip", CL_Voip_f);
+ Cvar_Set("cl_voipSendTarget", "spatial");
+ ::memset(clc.voipTargets, ~0, sizeof(clc.voipTargets));
+ }
+#endif
+}
+
+/*
+==================
+CL_SetCGameTime
+==================
+*/
+void CL_SetCGameTime( void ) {
+ // getting a valid frame message ends the connection process
+ if ( clc.state != CA_ACTIVE ) {
+ if ( clc.state != CA_PRIMED ) {
+ return;
+ }
+ if ( clc.demoplaying ) {
+ // we shouldn't get the first snapshot on the same frame
+ // as the gamestate, because it causes a bad time skip
+ if ( !clc.firstDemoFrameSkipped ) {
+ clc.firstDemoFrameSkipped = true;
+ return;
+ }
+ CL_ReadDemoMessage();
+ }
+ if ( cl.newSnapshots ) {
+ cl.newSnapshots = false;
+ CL_FirstSnapshot();
+ }
+ if ( clc.state != CA_ACTIVE ) {
+ return;
+ }
+ }
+
+ // if we have gotten to this point, cl.snap is guaranteed to be valid
+ if ( !cl.snap.valid ) {
+ Com_Error( ERR_DROP, "CL_SetCGameTime: !cl.snap.valid" );
+ }
+
+ // allow pause in single player
+ if ( sv_paused->integer && CL_CheckPaused() && com_sv_running->integer ) {
+ // paused
+ return;
+ }
+
+ if ( cl.snap.serverTime < cl.oldFrameServerTime ) {
+ Com_Error( ERR_DROP, "cl.snap.serverTime < cl.oldFrameServerTime" );
+ }
+ cl.oldFrameServerTime = cl.snap.serverTime;
+
+
+ // get our current view of time
+
+ if ( clc.demoplaying && cl_freezeDemo->integer ) {
+ // cl_freezeDemo is used to lock a demo in place for single frame advances
+
+ } else {
+ // cl_timeNudge is a user adjustable cvar that allows more
+ // or less latency to be added in the interest of better
+ // smoothness or better responsiveness.
+ int tn;
+
+ tn = cl_timeNudge->integer;
+ if (tn<-30) {
+ tn = -30;
+ } else if (tn>30) {
+ tn = 30;
+ }
+
+ cl.serverTime = cls.realtime + cl.serverTimeDelta - tn;
+
+ // guarantee that time will never flow backwards, even if
+ // serverTimeDelta made an adjustment or cl_timeNudge was changed
+ if ( cl.serverTime < cl.oldServerTime ) {
+ cl.serverTime = cl.oldServerTime;
+ }
+ cl.oldServerTime = cl.serverTime;
+
+ // note if we are almost past the latest frame (without timeNudge),
+ // so we will try and adjust back a bit when the next snapshot arrives
+ if ( cls.realtime + cl.serverTimeDelta >= cl.snap.serverTime - 5 ) {
+ cl.extrapolatedSnapshot = true;
+ }
+ }
+
+ // if we have gotten new snapshots, drift serverTimeDelta
+ // don't do this every frame, or a period of packet loss would
+ // make a huge adjustment
+ if ( cl.newSnapshots ) {
+ CL_AdjustTimeDelta();
+ }
+
+ if ( !clc.demoplaying ) {
+ return;
+ }
+
+ // if we are playing a demo back, we can just keep reading
+ // messages from the demo file until the cgame definately
+ // has valid snapshots to interpolate between
+
+ // a timedemo will always use a deterministic set of time samples
+ // no matter what speed machine it is run on,
+ // while a normal demo may have different time samples
+ // each time it is played back
+ if ( cl_timedemo->integer ) {
+ int now = Sys_Milliseconds( );
+ int frameDuration;
+
+ if (!clc.timeDemoStart) {
+ clc.timeDemoStart = clc.timeDemoLastFrame = now;
+ clc.timeDemoMinDuration = INT_MAX;
+ clc.timeDemoMaxDuration = 0;
+ }
+
+ frameDuration = now - clc.timeDemoLastFrame;
+ clc.timeDemoLastFrame = now;
+
+ // Ignore the first measurement as it'll always be 0
+ if( clc.timeDemoFrames > 0 )
+ {
+ if( frameDuration > clc.timeDemoMaxDuration )
+ clc.timeDemoMaxDuration = frameDuration;
+
+ if( frameDuration < clc.timeDemoMinDuration )
+ clc.timeDemoMinDuration = frameDuration;
+
+ // 255 ms = about 4fps
+ if( frameDuration > UCHAR_MAX )
+ frameDuration = UCHAR_MAX;
+
+ clc.timeDemoDurations[ ( clc.timeDemoFrames - 1 ) %
+ MAX_TIMEDEMO_DURATIONS ] = frameDuration;
+ }
+
+ clc.timeDemoFrames++;
+ cl.serverTime = clc.timeDemoBaseTime + clc.timeDemoFrames * 50;
+ }
+
+ while ( cl.serverTime >= cl.snap.serverTime ) {
+ // feed another messag, which should change
+ // the contents of cl.snap
+ CL_ReadDemoMessage();
+ if ( clc.state != CA_ACTIVE ) {
+ return; // end of demo
+ }
+ }
+}
diff --git a/src/client/cl_cin.cpp b/src/client/cl_cin.cpp
new file mode 100644
index 0000000..6326e89
--- /dev/null
+++ b/src/client/cl_cin.cpp
@@ -0,0 +1,1937 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+/*****************************************************************************
+ * name: cl_cin.c
+ *
+ * desc: video and cinematic playback
+ *
+ * $Archive: /MissionPack/code/client/cl_cin.c $
+ *
+ * cl_glconfig.hwtype trtypes 3dfx/ragepro need 256x256
+ *
+ *****************************************************************************/
+
+#include "client.h"
+#include "snd_local.h"
+
+#define MAXSIZE 8
+#define MINSIZE 4
+
+#define DEFAULT_CIN_WIDTH 512
+#define DEFAULT_CIN_HEIGHT 512
+
+#define ROQ_QUAD 0x1000
+#define ROQ_QUAD_INFO 0x1001
+#define ROQ_CODEBOOK 0x1002
+#define ROQ_QUAD_VQ 0x1011
+#define ROQ_QUAD_JPEG 0x1012
+#define ROQ_QUAD_HANG 0x1013
+#define ROQ_PACKET 0x1030
+#define ZA_SOUND_MONO 0x1020
+#define ZA_SOUND_STEREO 0x1021
+
+#define MAX_VIDEO_HANDLES 16
+
+static void RoQ_init(void);
+
+/******************************************************************************
+*
+* Class: trFMV
+*
+* Description: RoQ/RnR manipulation routines
+* not entirely complete for first run
+*
+******************************************************************************/
+
+static long ROQ_YY_tab[256];
+static long ROQ_UB_tab[256];
+static long ROQ_UG_tab[256];
+static long ROQ_VG_tab[256];
+static long ROQ_VR_tab[256];
+static unsigned short vq2[256 * 16 * 4];
+static unsigned short vq4[256 * 64 * 4];
+static unsigned short vq8[256 * 256 * 4];
+
+struct cinematics_t
+{
+ byte linbuf[DEFAULT_CIN_WIDTH * DEFAULT_CIN_HEIGHT * 4 * 2];
+ byte file[65536];
+ short sqrTable[256];
+
+ int mcomp[256];
+ byte *qStatus[2][32768];
+
+ long oldXOff;
+ long oldYOff;
+ long oldysize;
+ long oldxsize;
+
+ int currentHandle;
+};
+
+struct cin_cache
+{
+ char fileName[MAX_OSPATH];
+
+ int CIN_WIDTH;
+ int CIN_HEIGHT;
+
+ int xpos;
+ int ypos;
+ int width;
+ int height;
+
+ bool looping;
+ bool holdAtEnd;
+ bool dirty;
+ bool alterGameState;
+ bool silent;
+ bool shader;
+
+ fileHandle_t iFile;
+ e_status status;
+
+ int startTime;
+ int lastTime;
+ long tfps;
+ long RoQPlayed;
+ long ROQSize;
+ unsigned int RoQFrameSize;
+ long onQuad;
+ long numQuads;
+ long samplesPerLine;
+ unsigned int roq_id;
+ long screenDelta;
+
+ void (*VQ0)(byte *status, void *qdata);
+ void (*VQ1)(byte *status, void *qdata);
+ void (*VQNormal)(byte *status, void *qdata);
+ void (*VQBuffer)(byte *status, void *qdata);
+
+ long samplesPerPixel; // defaults to 2
+ byte *gray;
+ unsigned int xsize, ysize, maxsize, minsize;
+
+ bool half;
+ bool smootheddouble;
+ bool inMemory;
+ long normalBuffer0;
+ long roq_flags;
+ long roqF0;
+ long roqF1;
+ long t[2];
+ long roqFPS;
+ int playonwalls;
+ byte *buf;
+ long drawX;
+ long drawY;
+};
+
+static cinematics_t cin;
+static cin_cache cinTable[MAX_VIDEO_HANDLES];
+static int currentHandle = -1;
+static int CL_handle = -1;
+
+extern int s_soundtime; // sample PAIRS
+
+void CIN_CloseAllVideos(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_VIDEO_HANDLES; i++)
+ {
+ if (cinTable[i].fileName[0] != 0)
+ {
+ CIN_StopCinematic(i);
+ }
+ }
+}
+
+static int CIN_HandleForVideo(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_VIDEO_HANDLES; i++)
+ {
+ if (cinTable[i].fileName[0] == 0)
+ {
+ return i;
+ }
+ }
+ Com_Error(ERR_DROP, "CIN_HandleForVideo: none free");
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// RllSetupTable
+//
+// Allocates and initializes the square table.
+//
+// Parameters: None
+//
+// Returns: Nothing
+//-----------------------------------------------------------------------------
+static void RllSetupTable(void)
+{
+ int z;
+
+ for (z = 0; z < 128; z++)
+ {
+ cin.sqrTable[z] = (short)(z * z);
+ cin.sqrTable[z + 128] = (short)(-cin.sqrTable[z]);
+ }
+}
+
+#if 0
+//-----------------------------------------------------------------------------
+// RllDecodeMonoToMono
+//
+// Decode mono source data into a mono buffer.
+//
+// Parameters: from -> buffer holding encoded data
+// to -> buffer to hold decoded data
+// size = number of bytes of input (= # of shorts of output)
+// signedOutput = 0 for unsigned output, non-zero for signed output
+// flag = flags from asset header
+//
+// Returns: Number of samples placed in output buffer
+//-----------------------------------------------------------------------------
+long RllDecodeMonoToMono(unsigned char *from, short *to, unsigned int size, char signedOutput, unsigned short flag)
+{
+ unsigned int z;
+ int prev;
+
+ if (signedOutput)
+ prev = flag - 0x8000;
+ else
+ prev = flag;
+
+ for (z = 0; z < size; z++)
+ {
+ prev = to[z] = (short)(prev + cin.sqrTable[from[z]]);
+ }
+ return size; //*sizeof(short));
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// RllDecodeMonoToStereo
+//
+// Decode mono source data into a stereo buffer. Output is 4 times the number
+// of bytes in the input.
+//
+// Parameters: from -> buffer holding encoded data
+// to -> buffer to hold decoded data
+// size = number of bytes of input (= 1/4 # of bytes of output)
+// signedOutput = 0 for unsigned output, non-zero for signed output
+// flag = flags from asset header
+//
+// Returns: Number of samples placed in output buffer
+//-----------------------------------------------------------------------------
+static long RllDecodeMonoToStereo(unsigned char *from, short *to, unsigned int size, char signedOutput, unsigned short flag)
+{
+ unsigned int z;
+ int prev;
+
+ if (signedOutput)
+ prev = flag - 0x8000;
+ else
+ prev = flag;
+
+ for (z = 0; z < size; z++)
+ {
+ prev = (short)(prev + cin.sqrTable[from[z]]);
+ to[z * 2 + 0] = to[z * 2 + 1] = (short)(prev);
+ }
+
+ return size; // * 2 * sizeof(short));
+}
+
+//-----------------------------------------------------------------------------
+// RllDecodeStereoToStereo
+//
+// Decode stereo source data into a stereo buffer.
+//
+// Parameters: from -> buffer holding encoded data
+// to -> buffer to hold decoded data
+// size = number of bytes of input (= 1/2 # of bytes of output)
+// signedOutput = 0 for unsigned output, non-zero for signed output
+// flag = flags from asset header
+//
+// Returns: Number of samples placed in output buffer
+//-----------------------------------------------------------------------------
+static long RllDecodeStereoToStereo(unsigned char *from, short *to, unsigned int size, char signedOutput, unsigned short flag)
+{
+ unsigned int z;
+ unsigned char *zz = from;
+ int prevL, prevR;
+
+ if (signedOutput)
+ {
+ prevL = (flag & 0xff00) - 0x8000;
+ prevR = ((flag & 0x00ff) << 8) - 0x8000;
+ }
+ else
+ {
+ prevL = flag & 0xff00;
+ prevR = (flag & 0x00ff) << 8;
+ }
+
+ for (z = 0; z < size; z += 2)
+ {
+ prevL = (short)(prevL + cin.sqrTable[*zz++]);
+ prevR = (short)(prevR + cin.sqrTable[*zz++]);
+ to[z + 0] = (short)(prevL);
+ to[z + 1] = (short)(prevR);
+ }
+
+ return (size >> 1); //*sizeof(short));
+}
+
+#if 0
+//-----------------------------------------------------------------------------
+// RllDecodeStereoToMono
+//
+// Decode stereo source data into a mono buffer.
+//
+// Parameters: from -> buffer holding encoded data
+// to -> buffer to hold decoded data
+// size = number of bytes of input (= # of bytes of output)
+// signedOutput = 0 for unsigned output, non-zero for signed output
+// flag = flags from asset header
+//
+// Returns: Number of samples placed in output buffer
+//-----------------------------------------------------------------------------
+long RllDecodeStereoToMono(unsigned char *from, short *to, unsigned int size, char signedOutput, unsigned short flag)
+{
+ unsigned int z;
+ int prevL, prevR;
+
+ if (signedOutput)
+ {
+ prevL = (flag & 0xff00) - 0x8000;
+ prevR = ((flag & 0x00ff) << 8) - 0x8000;
+ }
+ else
+ {
+ prevL = flag & 0xff00;
+ prevR = (flag & 0x00ff) << 8;
+ }
+
+ for (z = 0; z < size; z += 1)
+ {
+ prevL = prevL + cin.sqrTable[from[z * 2]];
+ prevR = prevR + cin.sqrTable[from[z * 2 + 1]];
+ to[z] = (short)((prevL + prevR) / 2);
+ }
+
+ return size;
+}
+#endif
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void move8_32(byte *src, byte *dst, int spl)
+{
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ {
+ memcpy(dst, src, 32);
+ src += spl;
+ dst += spl;
+ }
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void move4_32(byte *src, byte *dst, int spl)
+{
+ int i;
+
+ for (i = 0; i < 4; ++i)
+ {
+ memcpy(dst, src, 16);
+ src += spl;
+ dst += spl;
+ }
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void blit8_32(byte *src, byte *dst, int spl)
+{
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ {
+ memcpy(dst, src, 32);
+ src += 32;
+ dst += spl;
+ }
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+static void blit4_32(byte *src, byte *dst, int spl)
+{
+ int i;
+
+ for (i = 0; i < 4; ++i)
+ {
+ memmove(dst, src, 16);
+ src += 16;
+ dst += spl;
+ }
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void blit2_32(byte *src, byte *dst, int spl)
+{
+ memcpy(dst, src, 8);
+ memcpy(dst + spl, src + 8, 8);
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void blitVQQuad32fs(byte **status, unsigned char *data)
+{
+ unsigned short newd, celdata, code;
+ unsigned int index, i;
+ int spl;
+
+ newd = 0;
+ celdata = 0;
+ index = 0;
+
+ spl = cinTable[currentHandle].samplesPerLine;
+
+ do
+ {
+ if (!newd)
+ {
+ newd = 7;
+ celdata = data[0] + data[1] * 256;
+ data += 2;
+ }
+ else
+ {
+ newd--;
+ }
+
+ code = (unsigned short)(celdata & 0xc000);
+ celdata <<= 2;
+
+ switch (code)
+ {
+ case 0x8000: // vq code
+ blit8_32((byte *)&vq8[(*data) * 128], status[index], spl);
+ data++;
+ index += 5;
+ break;
+ case 0xc000: // drop
+ index++; // skip 8x8
+ for (i = 0; i < 4; i++)
+ {
+ if (!newd)
+ {
+ newd = 7;
+ celdata = data[0] + data[1] * 256;
+ data += 2;
+ }
+ else
+ {
+ newd--;
+ }
+
+ code = (unsigned short)(celdata & 0xc000);
+ celdata <<= 2;
+
+ switch (code)
+ { // code in top two bits of code
+ case 0x8000: // 4x4 vq code
+ blit4_32((byte *)&vq4[(*data) * 32], status[index], spl);
+ data++;
+ break;
+ case 0xc000: // 2x2 vq code
+ blit2_32((byte *)&vq2[(*data) * 8], status[index], spl);
+ data++;
+ blit2_32((byte *)&vq2[(*data) * 8], status[index] + 8, spl);
+ data++;
+ blit2_32((byte *)&vq2[(*data) * 8], status[index] + spl * 2, spl);
+ data++;
+ blit2_32((byte *)&vq2[(*data) * 8], status[index] + spl * 2 + 8, spl);
+ data++;
+ break;
+ case 0x4000: // motion compensation
+ move4_32(status[index] + cin.mcomp[(*data)], status[index], spl);
+ data++;
+ break;
+ }
+ index++;
+ }
+ break;
+ case 0x4000: // motion compensation
+ move8_32(status[index] + cin.mcomp[(*data)], status[index], spl);
+ data++;
+ index += 5;
+ break;
+ case 0x0000:
+ index += 5;
+ break;
+ }
+ } while (status[index] != NULL);
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void ROQ_GenYUVTables(void)
+{
+ float t_ub, t_vr, t_ug, t_vg;
+ long i;
+
+ t_ub = (1.77200f / 2.0f) * (float)(1 << 6) + 0.5f;
+ t_vr = (1.40200f / 2.0f) * (float)(1 << 6) + 0.5f;
+ t_ug = (0.34414f / 2.0f) * (float)(1 << 6) + 0.5f;
+ t_vg = (0.71414f / 2.0f) * (float)(1 << 6) + 0.5f;
+ for (i = 0; i < 256; i++)
+ {
+ float x = (float)(2 * i - 255);
+
+ ROQ_UB_tab[i] = (long)((t_ub * x) + (1 << 5));
+ ROQ_VR_tab[i] = (long)((t_vr * x) + (1 << 5));
+ ROQ_UG_tab[i] = (long)((-t_ug * x));
+ ROQ_VG_tab[i] = (long)((-t_vg * x) + (1 << 5));
+ ROQ_YY_tab[i] = (long)((i << 6) | (i >> 2));
+ }
+}
+
+#define VQ2TO4(a, b, c, d) \
+ { \
+ *c++ = a[0]; \
+ *d++ = a[0]; \
+ *d++ = a[0]; \
+ *c++ = a[1]; \
+ *d++ = a[1]; \
+ *d++ = a[1]; \
+ *c++ = b[0]; \
+ *d++ = b[0]; \
+ *d++ = b[0]; \
+ *c++ = b[1]; \
+ *d++ = b[1]; \
+ *d++ = b[1]; \
+ *d++ = a[0]; \
+ *d++ = a[0]; \
+ *d++ = a[1]; \
+ *d++ = a[1]; \
+ *d++ = b[0]; \
+ *d++ = b[0]; \
+ *d++ = b[1]; \
+ *d++ = b[1]; \
+ a += 2; \
+ b += 2; \
+ }
+
+#define VQ2TO2(a, b, c, d) \
+ { \
+ *c++ = *a; \
+ *d++ = *a; \
+ *d++ = *a; \
+ *c++ = *b; \
+ *d++ = *b; \
+ *d++ = *b; \
+ *d++ = *a; \
+ *d++ = *a; \
+ *d++ = *b; \
+ *d++ = *b; \
+ a++; \
+ b++; \
+ }
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static unsigned short yuv_to_rgb(long y, long u, long v)
+{
+ long r, g, b, YY = (long)(ROQ_YY_tab[(y)]);
+
+ r = (YY + ROQ_VR_tab[v]) >> 9;
+ g = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 8;
+ b = (YY + ROQ_UB_tab[u]) >> 9;
+
+ if (r < 0) r = 0;
+ if (g < 0) g = 0;
+ if (b < 0) b = 0;
+ if (r > 31) r = 31;
+ if (g > 63) g = 63;
+ if (b > 31) b = 31;
+
+ return (unsigned short)((r << 11) + (g << 5) + (b));
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+static unsigned int yuv_to_rgb24(long y, long u, long v)
+{
+ long r, g, b, YY = (long)(ROQ_YY_tab[(y)]);
+
+ r = (YY + ROQ_VR_tab[v]) >> 6;
+ g = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 6;
+ b = (YY + ROQ_UB_tab[u]) >> 6;
+
+ if (r < 0) r = 0;
+ if (g < 0) g = 0;
+ if (b < 0) b = 0;
+ if (r > 255) r = 255;
+ if (g > 255) g = 255;
+ if (b > 255) b = 255;
+
+ return LittleLong((r) | (g << 8) | (b << 16) | (255 << 24));
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void decodeCodeBook(byte *input, unsigned short roq_flags)
+{
+ long i, j, two, four;
+ unsigned short *aptr, *bptr, *cptr, *dptr;
+ long y0, y1, y2, y3, cr, cb;
+ byte *bbptr, *baptr, *bcptr, *bdptr;
+ union {
+ unsigned int *i;
+ unsigned short *s;
+ } iaptr, ibptr, icptr, idptr;
+
+ if (!roq_flags)
+ {
+ two = four = 256;
+ }
+ else
+ {
+ two = roq_flags >> 8;
+ if (!two) two = 256;
+ four = roq_flags & 0xff;
+ }
+
+ four *= 2;
+
+ bptr = (unsigned short *)vq2;
+
+ if (!cinTable[currentHandle].half)
+ {
+ if (!cinTable[currentHandle].smootheddouble)
+ {
+ //
+ // normal height
+ //
+ if (cinTable[currentHandle].samplesPerPixel == 2)
+ {
+ for (i = 0; i < two; i++)
+ {
+ y0 = (long)*input++;
+ y1 = (long)*input++;
+ y2 = (long)*input++;
+ y3 = (long)*input++;
+ cr = (long)*input++;
+ cb = (long)*input++;
+ *bptr++ = yuv_to_rgb(y0, cr, cb);
+ *bptr++ = yuv_to_rgb(y1, cr, cb);
+ *bptr++ = yuv_to_rgb(y2, cr, cb);
+ *bptr++ = yuv_to_rgb(y3, cr, cb);
+ }
+
+ cptr = (unsigned short *)vq4;
+ dptr = (unsigned short *)vq8;
+
+ for (i = 0; i < four; i++)
+ {
+ aptr = (unsigned short *)vq2 + (*input++) * 4;
+ bptr = (unsigned short *)vq2 + (*input++) * 4;
+ for (j = 0; j < 2; j++) VQ2TO4(aptr, bptr, cptr, dptr);
+ }
+ }
+ else if (cinTable[currentHandle].samplesPerPixel == 4)
+ {
+ ibptr.s = bptr;
+ for (i = 0; i < two; i++)
+ {
+ y0 = (long)*input++;
+ y1 = (long)*input++;
+ y2 = (long)*input++;
+ y3 = (long)*input++;
+ cr = (long)*input++;
+ cb = (long)*input++;
+ *ibptr.i++ = yuv_to_rgb24(y0, cr, cb);
+ *ibptr.i++ = yuv_to_rgb24(y1, cr, cb);
+ *ibptr.i++ = yuv_to_rgb24(y2, cr, cb);
+ *ibptr.i++ = yuv_to_rgb24(y3, cr, cb);
+ }
+
+ icptr.s = vq4;
+ idptr.s = vq8;
+
+ for (i = 0; i < four; i++)
+ {
+ iaptr.s = vq2;
+ iaptr.i += (*input++) * 4;
+ ibptr.s = vq2;
+ ibptr.i += (*input++) * 4;
+ for (j = 0; j < 2; j++) VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
+ }
+ }
+ else if (cinTable[currentHandle].samplesPerPixel == 1)
+ {
+ bbptr = (byte *)bptr;
+ for (i = 0; i < two; i++)
+ {
+ *bbptr++ = cinTable[currentHandle].gray[*input++];
+ *bbptr++ = cinTable[currentHandle].gray[*input++];
+ *bbptr++ = cinTable[currentHandle].gray[*input++];
+ *bbptr++ = cinTable[currentHandle].gray[*input];
+ input += 3;
+ }
+
+ bcptr = (byte *)vq4;
+ bdptr = (byte *)vq8;
+
+ for (i = 0; i < four; i++)
+ {
+ baptr = (byte *)vq2 + (*input++) * 4;
+ bbptr = (byte *)vq2 + (*input++) * 4;
+ for (j = 0; j < 2; j++) VQ2TO4(baptr, bbptr, bcptr, bdptr);
+ }
+ }
+ }
+ else
+ {
+ //
+ // double height, smoothed
+ //
+ if (cinTable[currentHandle].samplesPerPixel == 2)
+ {
+ for (i = 0; i < two; i++)
+ {
+ y0 = (long)*input++;
+ y1 = (long)*input++;
+ y2 = (long)*input++;
+ y3 = (long)*input++;
+ cr = (long)*input++;
+ cb = (long)*input++;
+ *bptr++ = yuv_to_rgb(y0, cr, cb);
+ *bptr++ = yuv_to_rgb(y1, cr, cb);
+ *bptr++ = yuv_to_rgb(((y0 * 3) + y2) / 4, cr, cb);
+ *bptr++ = yuv_to_rgb(((y1 * 3) + y3) / 4, cr, cb);
+ *bptr++ = yuv_to_rgb((y0 + (y2 * 3)) / 4, cr, cb);
+ *bptr++ = yuv_to_rgb((y1 + (y3 * 3)) / 4, cr, cb);
+ *bptr++ = yuv_to_rgb(y2, cr, cb);
+ *bptr++ = yuv_to_rgb(y3, cr, cb);
+ }
+
+ cptr = (unsigned short *)vq4;
+ dptr = (unsigned short *)vq8;
+
+ for (i = 0; i < four; i++)
+ {
+ aptr = (unsigned short *)vq2 + (*input++) * 8;
+ bptr = (unsigned short *)vq2 + (*input++) * 8;
+ for (j = 0; j < 2; j++)
+ {
+ VQ2TO4(aptr, bptr, cptr, dptr);
+ VQ2TO4(aptr, bptr, cptr, dptr);
+ }
+ }
+ }
+ else if (cinTable[currentHandle].samplesPerPixel == 4)
+ {
+ ibptr.s = bptr;
+ for (i = 0; i < two; i++)
+ {
+ y0 = (long)*input++;
+ y1 = (long)*input++;
+ y2 = (long)*input++;
+ y3 = (long)*input++;
+ cr = (long)*input++;
+ cb = (long)*input++;
+ *ibptr.i++ = yuv_to_rgb24(y0, cr, cb);
+ *ibptr.i++ = yuv_to_rgb24(y1, cr, cb);
+ *ibptr.i++ = yuv_to_rgb24(((y0 * 3) + y2) / 4, cr, cb);
+ *ibptr.i++ = yuv_to_rgb24(((y1 * 3) + y3) / 4, cr, cb);
+ *ibptr.i++ = yuv_to_rgb24((y0 + (y2 * 3)) / 4, cr, cb);
+ *ibptr.i++ = yuv_to_rgb24((y1 + (y3 * 3)) / 4, cr, cb);
+ *ibptr.i++ = yuv_to_rgb24(y2, cr, cb);
+ *ibptr.i++ = yuv_to_rgb24(y3, cr, cb);
+ }
+
+ icptr.s = vq4;
+ idptr.s = vq8;
+
+ for (i = 0; i < four; i++)
+ {
+ iaptr.s = vq2;
+ iaptr.i += (*input++) * 8;
+ ibptr.s = vq2;
+ ibptr.i += (*input++) * 8;
+ for (j = 0; j < 2; j++)
+ {
+ VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
+ VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
+ }
+ }
+ }
+ else if (cinTable[currentHandle].samplesPerPixel == 1)
+ {
+ bbptr = (byte *)bptr;
+ for (i = 0; i < two; i++)
+ {
+ y0 = (long)*input++;
+ y1 = (long)*input++;
+ y2 = (long)*input++;
+ y3 = (long)*input;
+ input += 3;
+ *bbptr++ = cinTable[currentHandle].gray[y0];
+ *bbptr++ = cinTable[currentHandle].gray[y1];
+ *bbptr++ = cinTable[currentHandle].gray[((y0 * 3) + y2) / 4];
+ *bbptr++ = cinTable[currentHandle].gray[((y1 * 3) + y3) / 4];
+ *bbptr++ = cinTable[currentHandle].gray[(y0 + (y2 * 3)) / 4];
+ *bbptr++ = cinTable[currentHandle].gray[(y1 + (y3 * 3)) / 4];
+ *bbptr++ = cinTable[currentHandle].gray[y2];
+ *bbptr++ = cinTable[currentHandle].gray[y3];
+ }
+
+ bcptr = (byte *)vq4;
+ bdptr = (byte *)vq8;
+
+ for (i = 0; i < four; i++)
+ {
+ baptr = (byte *)vq2 + (*input++) * 8;
+ bbptr = (byte *)vq2 + (*input++) * 8;
+ for (j = 0; j < 2; j++)
+ {
+ VQ2TO4(baptr, bbptr, bcptr, bdptr);
+ VQ2TO4(baptr, bbptr, bcptr, bdptr);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ //
+ // 1/4 screen
+ //
+ if (cinTable[currentHandle].samplesPerPixel == 2)
+ {
+ for (i = 0; i < two; i++)
+ {
+ y0 = (long)*input;
+ input += 2;
+ y2 = (long)*input;
+ input += 2;
+ cr = (long)*input++;
+ cb = (long)*input++;
+ *bptr++ = yuv_to_rgb(y0, cr, cb);
+ *bptr++ = yuv_to_rgb(y2, cr, cb);
+ }
+
+ cptr = (unsigned short *)vq4;
+ dptr = (unsigned short *)vq8;
+
+ for (i = 0; i < four; i++)
+ {
+ aptr = (unsigned short *)vq2 + (*input++) * 2;
+ bptr = (unsigned short *)vq2 + (*input++) * 2;
+ for (j = 0; j < 2; j++)
+ {
+ VQ2TO2(aptr, bptr, cptr, dptr);
+ }
+ }
+ }
+ else if (cinTable[currentHandle].samplesPerPixel == 1)
+ {
+ bbptr = (byte *)bptr;
+
+ for (i = 0; i < two; i++)
+ {
+ *bbptr++ = cinTable[currentHandle].gray[*input];
+ input += 2;
+ *bbptr++ = cinTable[currentHandle].gray[*input];
+ input += 4;
+ }
+
+ bcptr = (byte *)vq4;
+ bdptr = (byte *)vq8;
+
+ for (i = 0; i < four; i++)
+ {
+ baptr = (byte *)vq2 + (*input++) * 2;
+ bbptr = (byte *)vq2 + (*input++) * 2;
+ for (j = 0; j < 2; j++)
+ {
+ VQ2TO2(baptr, bbptr, bcptr, bdptr);
+ }
+ }
+ }
+ else if (cinTable[currentHandle].samplesPerPixel == 4)
+ {
+ ibptr.s = bptr;
+ for (i = 0; i < two; i++)
+ {
+ y0 = (long)*input;
+ input += 2;
+ y2 = (long)*input;
+ input += 2;
+ cr = (long)*input++;
+ cb = (long)*input++;
+ *ibptr.i++ = yuv_to_rgb24(y0, cr, cb);
+ *ibptr.i++ = yuv_to_rgb24(y2, cr, cb);
+ }
+
+ icptr.s = vq4;
+ idptr.s = vq8;
+
+ for (i = 0; i < four; i++)
+ {
+ iaptr.s = vq2;
+ iaptr.i += (*input++) * 2;
+ ibptr.s = vq2 + (*input++) * 2;
+ ibptr.i += (*input++) * 2;
+ for (j = 0; j < 2; j++)
+ {
+ VQ2TO2(iaptr.i, ibptr.i, icptr.i, idptr.i);
+ }
+ }
+ }
+ }
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void recurseQuad(long startX, long startY, long quadSize, long xOff, long yOff)
+{
+ byte *scroff;
+ long bigx, bigy, lowx, lowy, useY;
+ long offset;
+
+ offset = cinTable[currentHandle].screenDelta;
+
+ lowx = lowy = 0;
+ bigx = cinTable[currentHandle].xsize;
+ bigy = cinTable[currentHandle].ysize;
+
+ if (bigx > cinTable[currentHandle].CIN_WIDTH) bigx = cinTable[currentHandle].CIN_WIDTH;
+ if (bigy > cinTable[currentHandle].CIN_HEIGHT) bigy = cinTable[currentHandle].CIN_HEIGHT;
+
+ if ((startX >= lowx) && (startX + quadSize) <= (bigx) && (startY + quadSize) <= (bigy) && (startY >= lowy) &&
+ quadSize <= MAXSIZE)
+ {
+ useY = startY;
+ scroff = cin.linbuf +
+ (useY + ((cinTable[currentHandle].CIN_HEIGHT - bigy) >> 1) + yOff) *
+ (cinTable[currentHandle].samplesPerLine) +
+ (((startX + xOff)) * cinTable[currentHandle].samplesPerPixel);
+
+ cin.qStatus[0][cinTable[currentHandle].onQuad] = scroff;
+ cin.qStatus[1][cinTable[currentHandle].onQuad++] = scroff + offset;
+ }
+
+ if (quadSize != MINSIZE)
+ {
+ quadSize >>= 1;
+ recurseQuad(startX, startY, quadSize, xOff, yOff);
+ recurseQuad(startX + quadSize, startY, quadSize, xOff, yOff);
+ recurseQuad(startX, startY + quadSize, quadSize, xOff, yOff);
+ recurseQuad(startX + quadSize, startY + quadSize, quadSize, xOff, yOff);
+ }
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void setupQuad(long xOff, long yOff)
+{
+ long numQuadCels, i, x, y;
+ byte *temp;
+
+ if (xOff == cin.oldXOff && yOff == cin.oldYOff && cinTable[currentHandle].ysize == cin.oldysize &&
+ cinTable[currentHandle].xsize == cin.oldxsize)
+ {
+ return;
+ }
+
+ cin.oldXOff = xOff;
+ cin.oldYOff = yOff;
+ cin.oldysize = cinTable[currentHandle].ysize;
+ cin.oldxsize = cinTable[currentHandle].xsize;
+
+ numQuadCels = (cinTable[currentHandle].xsize * cinTable[currentHandle].ysize) / (16);
+ numQuadCels += numQuadCels / 4;
+ numQuadCels += 64; // for overflow
+
+ cinTable[currentHandle].onQuad = 0;
+
+ for (y = 0; y < (long)cinTable[currentHandle].ysize; y += 16)
+ for (x = 0; x < (long)cinTable[currentHandle].xsize; x += 16) recurseQuad(x, y, 16, xOff, yOff);
+
+ temp = NULL;
+
+ for (i = (numQuadCels - 64); i < numQuadCels; i++)
+ {
+ cin.qStatus[0][i] = temp; // eoq
+ cin.qStatus[1][i] = temp; // eoq
+ }
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void readQuadInfo(byte *qData)
+{
+ if (currentHandle < 0) return;
+
+ cinTable[currentHandle].xsize = qData[0] + qData[1] * 256;
+ cinTable[currentHandle].ysize = qData[2] + qData[3] * 256;
+ cinTable[currentHandle].maxsize = qData[4] + qData[5] * 256;
+ cinTable[currentHandle].minsize = qData[6] + qData[7] * 256;
+
+ cinTable[currentHandle].CIN_HEIGHT = cinTable[currentHandle].ysize;
+ cinTable[currentHandle].CIN_WIDTH = cinTable[currentHandle].xsize;
+
+ cinTable[currentHandle].samplesPerLine =
+ cinTable[currentHandle].CIN_WIDTH * cinTable[currentHandle].samplesPerPixel;
+ cinTable[currentHandle].screenDelta = cinTable[currentHandle].CIN_HEIGHT * cinTable[currentHandle].samplesPerLine;
+
+ cinTable[currentHandle].half = false;
+ cinTable[currentHandle].smootheddouble = false;
+
+ cinTable[currentHandle].VQ0 = cinTable[currentHandle].VQNormal;
+ cinTable[currentHandle].VQ1 = cinTable[currentHandle].VQBuffer;
+
+ cinTable[currentHandle].t[0] = cinTable[currentHandle].screenDelta;
+ cinTable[currentHandle].t[1] = -cinTable[currentHandle].screenDelta;
+
+ cinTable[currentHandle].drawX = cinTable[currentHandle].CIN_WIDTH;
+ cinTable[currentHandle].drawY = cinTable[currentHandle].CIN_HEIGHT;
+
+ // rage pro is very slow at 512 wide textures, voodoo can't do it at all
+ if (cls.glconfig.hardwareType == GLHW_RAGEPRO || cls.glconfig.maxTextureSize <= 256)
+ {
+ if (cinTable[currentHandle].drawX > 256)
+ {
+ cinTable[currentHandle].drawX = 256;
+ }
+ if (cinTable[currentHandle].drawY > 256)
+ {
+ cinTable[currentHandle].drawY = 256;
+ }
+ if (cinTable[currentHandle].CIN_WIDTH != 256 || cinTable[currentHandle].CIN_HEIGHT != 256)
+ {
+ Com_Printf("HACK: approxmimating cinematic for Rage Pro or Voodoo\n");
+ }
+ }
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void RoQPrepMcomp(long xoff, long yoff)
+{
+ long i, j, x, y, temp, temp2;
+
+ i = cinTable[currentHandle].samplesPerLine;
+ j = cinTable[currentHandle].samplesPerPixel;
+ if (cinTable[currentHandle].xsize == (cinTable[currentHandle].ysize * 4) && !cinTable[currentHandle].half)
+ {
+ j = j + j;
+ i = i + i;
+ }
+
+ for (y = 0; y < 16; y++)
+ {
+ temp2 = (y + yoff - 8) * i;
+ for (x = 0; x < 16; x++)
+ {
+ temp = (x + xoff - 8) * j;
+ cin.mcomp[(x * 16) + y] = cinTable[currentHandle].normalBuffer0 - (temp2 + temp);
+ }
+ }
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void initRoQ(void)
+{
+ if (currentHandle < 0) return;
+
+ cinTable[currentHandle].VQNormal = (void (*)(byte *, void *))blitVQQuad32fs;
+ cinTable[currentHandle].VQBuffer = (void (*)(byte *, void *))blitVQQuad32fs;
+ cinTable[currentHandle].samplesPerPixel = 4;
+ ROQ_GenYUVTables();
+ RllSetupTable();
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+/*
+static byte* RoQFetchInterlaced( byte *source ) {
+ int x, *src, *dst;
+
+ if (currentHandle < 0) return NULL;
+
+ src = (int *)source;
+ dst = (int *)cinTable[currentHandle].buf2;
+
+ for(x=0;x<256*256;x++) {
+ *dst = *src;
+ dst++; src += 2;
+ }
+ return cinTable[currentHandle].buf2;
+}
+*/
+static void RoQReset(void)
+{
+ if (currentHandle < 0) return;
+
+ FS_FCloseFile(cinTable[currentHandle].iFile);
+ FS_FOpenFileRead(cinTable[currentHandle].fileName, &cinTable[currentHandle].iFile, true);
+ // let the background thread start reading ahead
+ FS_Read(cin.file, 16, cinTable[currentHandle].iFile);
+ RoQ_init();
+ cinTable[currentHandle].status = FMV_LOOPED;
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void RoQInterrupt(void)
+{
+ byte *framedata;
+ short sbuf[32768];
+ int ssize;
+
+ if (currentHandle < 0) return;
+
+ FS_Read(cin.file, cinTable[currentHandle].RoQFrameSize + 8, cinTable[currentHandle].iFile);
+ if (cinTable[currentHandle].RoQPlayed >= cinTable[currentHandle].ROQSize)
+ {
+ if (cinTable[currentHandle].holdAtEnd == false)
+ {
+ if (cinTable[currentHandle].looping)
+ {
+ RoQReset();
+ }
+ else
+ {
+ cinTable[currentHandle].status = FMV_EOF;
+ }
+ }
+ else
+ {
+ cinTable[currentHandle].status = FMV_IDLE;
+ }
+ return;
+ }
+
+ framedata = cin.file;
+//
+// new frame is ready
+//
+redump:
+ switch (cinTable[currentHandle].roq_id)
+ {
+ case ROQ_QUAD_VQ:
+ if ((cinTable[currentHandle].numQuads & 1))
+ {
+ cinTable[currentHandle].normalBuffer0 = cinTable[currentHandle].t[1];
+ RoQPrepMcomp(cinTable[currentHandle].roqF0, cinTable[currentHandle].roqF1);
+ cinTable[currentHandle].VQ1((byte *)cin.qStatus[1], framedata);
+ cinTable[currentHandle].buf = cin.linbuf + cinTable[currentHandle].screenDelta;
+ }
+ else
+ {
+ cinTable[currentHandle].normalBuffer0 = cinTable[currentHandle].t[0];
+ RoQPrepMcomp(cinTable[currentHandle].roqF0, cinTable[currentHandle].roqF1);
+ cinTable[currentHandle].VQ0((byte *)cin.qStatus[0], framedata);
+ cinTable[currentHandle].buf = cin.linbuf;
+ }
+ if (cinTable[currentHandle].numQuads == 0)
+ { // first frame
+ ::memcpy(cin.linbuf + cinTable[currentHandle].screenDelta, cin.linbuf,
+ cinTable[currentHandle].samplesPerLine * cinTable[currentHandle].ysize);
+ }
+ cinTable[currentHandle].numQuads++;
+ cinTable[currentHandle].dirty = true;
+ break;
+ case ROQ_CODEBOOK:
+ decodeCodeBook(framedata, (unsigned short)cinTable[currentHandle].roq_flags);
+ break;
+ case ZA_SOUND_MONO:
+ if (!cinTable[currentHandle].silent)
+ {
+ ssize = RllDecodeMonoToStereo(framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0,
+ (unsigned short)cinTable[currentHandle].roq_flags);
+ S_RawSamples(0, ssize, 22050, 2, 1, (byte *)sbuf, 1.0f, -1);
+ }
+ break;
+ case ZA_SOUND_STEREO:
+ if (!cinTable[currentHandle].silent)
+ {
+ if (cinTable[currentHandle].numQuads == -1)
+ {
+ S_Update();
+ s_rawend[0] = s_soundtime;
+ }
+ ssize = RllDecodeStereoToStereo(framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0,
+ (unsigned short)cinTable[currentHandle].roq_flags);
+ S_RawSamples(0, ssize, 22050, 2, 2, (byte *)sbuf, 1.0f, -1);
+ }
+ break;
+ case ROQ_QUAD_INFO:
+ if (cinTable[currentHandle].numQuads == -1)
+ {
+ readQuadInfo(framedata);
+ setupQuad(0, 0);
+ cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds();
+ }
+ if (cinTable[currentHandle].numQuads != 1) cinTable[currentHandle].numQuads = 0;
+ break;
+ case ROQ_PACKET:
+ cinTable[currentHandle].inMemory = (bool)cinTable[currentHandle].roq_flags;
+ cinTable[currentHandle].RoQFrameSize = 0; // for header
+ break;
+ case ROQ_QUAD_HANG:
+ cinTable[currentHandle].RoQFrameSize = 0;
+ break;
+ case ROQ_QUAD_JPEG:
+ break;
+ default:
+ cinTable[currentHandle].status = FMV_EOF;
+ break;
+ }
+ //
+ // read in next frame data
+ //
+ if (cinTable[currentHandle].RoQPlayed >= cinTable[currentHandle].ROQSize)
+ {
+ if (cinTable[currentHandle].holdAtEnd == false)
+ {
+ if (cinTable[currentHandle].looping)
+ {
+ RoQReset();
+ }
+ else
+ {
+ cinTable[currentHandle].status = FMV_EOF;
+ }
+ }
+ else
+ {
+ cinTable[currentHandle].status = FMV_IDLE;
+ }
+ return;
+ }
+
+ framedata += cinTable[currentHandle].RoQFrameSize;
+ cinTable[currentHandle].roq_id = framedata[0] + framedata[1] * 256;
+ cinTable[currentHandle].RoQFrameSize = framedata[2] + framedata[3] * 256 + framedata[4] * 65536;
+ cinTable[currentHandle].roq_flags = framedata[6] + framedata[7] * 256;
+ cinTable[currentHandle].roqF0 = (signed char)framedata[7];
+ cinTable[currentHandle].roqF1 = (signed char)framedata[6];
+
+ if (cinTable[currentHandle].RoQFrameSize > 65536 || cinTable[currentHandle].roq_id == 0x1084)
+ {
+ Com_DPrintf("roq_size>65536||roq_id==0x1084\n");
+ cinTable[currentHandle].status = FMV_EOF;
+ if (cinTable[currentHandle].looping)
+ {
+ RoQReset();
+ }
+ return;
+ }
+ if (cinTable[currentHandle].inMemory && (cinTable[currentHandle].status != FMV_EOF))
+ {
+ cinTable[currentHandle].inMemory = false;
+ framedata += 8;
+ goto redump;
+ }
+ //
+ // one more frame hits the dust
+ //
+ // assert(cinTable[currentHandle].RoQFrameSize <= 65536);
+ // r = FS_Read( cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile );
+ cinTable[currentHandle].RoQPlayed += cinTable[currentHandle].RoQFrameSize + 8;
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void RoQ_init(void)
+{
+ cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds();
+
+ cinTable[currentHandle].RoQPlayed = 24;
+
+ /* get frame rate */
+ cinTable[currentHandle].roqFPS = cin.file[6] + cin.file[7] * 256;
+
+ if (!cinTable[currentHandle].roqFPS) cinTable[currentHandle].roqFPS = 30;
+
+ cinTable[currentHandle].numQuads = -1;
+
+ cinTable[currentHandle].roq_id = cin.file[8] + cin.file[9] * 256;
+ cinTable[currentHandle].RoQFrameSize = cin.file[10] + cin.file[11] * 256 + cin.file[12] * 65536;
+ cinTable[currentHandle].roq_flags = cin.file[14] + cin.file[15] * 256;
+
+ if (cinTable[currentHandle].RoQFrameSize > 65536 || !cinTable[currentHandle].RoQFrameSize)
+ {
+ return;
+ }
+}
+
+/******************************************************************************
+*
+* Function:
+*
+* Description:
+*
+******************************************************************************/
+
+static void RoQShutdown(void)
+{
+ const char *s;
+
+ if (!cinTable[currentHandle].buf)
+ {
+ return;
+ }
+
+ if (cinTable[currentHandle].status == FMV_IDLE)
+ {
+ return;
+ }
+ Com_DPrintf("finished cinematic\n");
+ cinTable[currentHandle].status = FMV_IDLE;
+
+ if (cinTable[currentHandle].iFile)
+ {
+ FS_FCloseFile(cinTable[currentHandle].iFile);
+ cinTable[currentHandle].iFile = 0;
+ }
+
+ if (cinTable[currentHandle].alterGameState)
+ {
+ clc.state = CA_DISCONNECTED;
+ // we can't just do a vstr nextmap, because
+ // if we are aborting the intro cinematic with
+ // a devmap command, nextmap would be valid by
+ // the time it was referenced
+ s = Cvar_VariableString("nextmap");
+ if (s[0])
+ {
+ Cbuf_ExecuteText(EXEC_APPEND, va("%s\n", s));
+ Cvar_Set("nextmap", "");
+ }
+ CL_handle = -1;
+
+ CL_ProtocolSpecificCommandsInit();
+ }
+ cinTable[currentHandle].fileName[0] = 0;
+ currentHandle = -1;
+}
+
+/*
+==================
+CIN_StopCinematic
+==================
+*/
+e_status CIN_StopCinematic(int handle)
+{
+ if (handle < 0 || handle >= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return FMV_EOF;
+ currentHandle = handle;
+
+ Com_DPrintf("trFMV::stop(), closing %s\n", cinTable[currentHandle].fileName);
+
+ if (!cinTable[currentHandle].buf)
+ {
+ return FMV_EOF;
+ }
+
+ if (cinTable[currentHandle].alterGameState)
+ {
+ if (clc.state != CA_CINEMATIC)
+ {
+ return cinTable[currentHandle].status;
+ }
+ }
+ cinTable[currentHandle].status = FMV_EOF;
+ RoQShutdown();
+
+ return FMV_EOF;
+}
+
+/*
+==================
+CIN_RunCinematic
+
+Fetch and decompress the pending frame
+==================
+*/
+
+e_status CIN_RunCinematic(int handle)
+{
+ int start = 0;
+ int thisTime = 0;
+
+ if (handle < 0 || handle >= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return FMV_EOF;
+
+ if (cin.currentHandle != handle)
+ {
+ currentHandle = handle;
+ cin.currentHandle = currentHandle;
+ cinTable[currentHandle].status = FMV_EOF;
+ RoQReset();
+ }
+
+ if (cinTable[handle].playonwalls < -1)
+ {
+ return cinTable[handle].status;
+ }
+
+ currentHandle = handle;
+
+ if (cinTable[currentHandle].alterGameState)
+ {
+ if (clc.state != CA_CINEMATIC)
+ {
+ return cinTable[currentHandle].status;
+ }
+ }
+
+ if (cinTable[currentHandle].status == FMV_IDLE)
+ {
+ return cinTable[currentHandle].status;
+ }
+
+ thisTime = CL_ScaledMilliseconds();
+ if (cinTable[currentHandle].shader && (abs(thisTime - cinTable[currentHandle].lastTime)) > 100)
+ {
+ cinTable[currentHandle].startTime += thisTime - cinTable[currentHandle].lastTime;
+ }
+ cinTable[currentHandle].tfps = (((CL_ScaledMilliseconds() - cinTable[currentHandle].startTime) * 3) / 100);
+
+ start = cinTable[currentHandle].startTime;
+ while ((cinTable[currentHandle].tfps != cinTable[currentHandle].numQuads) &&
+ (cinTable[currentHandle].status == FMV_PLAY))
+ {
+ RoQInterrupt();
+ if (start != cinTable[currentHandle].startTime)
+ {
+ cinTable[currentHandle].tfps = (((CL_ScaledMilliseconds() - cinTable[currentHandle].startTime) * 3) / 100);
+ start = cinTable[currentHandle].startTime;
+ }
+ }
+
+ cinTable[currentHandle].lastTime = thisTime;
+
+ if (cinTable[currentHandle].status == FMV_LOOPED)
+ {
+ cinTable[currentHandle].status = FMV_PLAY;
+ }
+
+ if (cinTable[currentHandle].status == FMV_EOF)
+ {
+ if (cinTable[currentHandle].looping)
+ {
+ RoQReset();
+ }
+ else
+ {
+ RoQShutdown();
+ return FMV_EOF;
+ }
+ }
+
+ return cinTable[currentHandle].status;
+}
+
+void CIN_SetExtents(int handle, int x, int y, int w, int h)
+{
+ if (handle < 0 || handle >= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return;
+ cinTable[handle].xpos = x;
+ cinTable[handle].ypos = y;
+ cinTable[handle].width = w;
+ cinTable[handle].height = h;
+ cinTable[handle].dirty = true;
+}
+
+static void CIN_SetLooping(int handle, bool loop)
+{
+ if (handle < 0 || handle >= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return;
+ cinTable[handle].looping = loop;
+}
+
+/*
+==================
+CIN_PlayCinematic
+==================
+*/
+int CIN_PlayCinematic(const char *arg, int x, int y, int w, int h, int systemBits)
+{
+ unsigned short RoQID;
+ char name[MAX_OSPATH];
+ int i;
+
+ if (strstr(arg, "/") == NULL && strstr(arg, "\\") == NULL)
+ {
+ Com_sprintf(name, sizeof(name), "video/%s", arg);
+ }
+ else
+ {
+ Com_sprintf(name, sizeof(name), "%s", arg);
+ }
+
+ if (!(systemBits & CIN_system))
+ {
+ for (i = 0; i < MAX_VIDEO_HANDLES; i++)
+ {
+ if (!strcmp(cinTable[i].fileName, name))
+ {
+ return i;
+ }
+ }
+ }
+
+ Com_DPrintf("CIN_PlayCinematic( %s )\n", arg);
+
+ ::memset(&cin, 0, sizeof(cinematics_t));
+ currentHandle = CIN_HandleForVideo();
+
+ cin.currentHandle = currentHandle;
+
+ strcpy(cinTable[currentHandle].fileName, name);
+
+ cinTable[currentHandle].ROQSize = 0;
+ cinTable[currentHandle].ROQSize =
+ FS_FOpenFileRead(cinTable[currentHandle].fileName, &cinTable[currentHandle].iFile, true);
+
+ if (cinTable[currentHandle].ROQSize <= 0)
+ {
+ Com_DPrintf("play(%s), ROQSize<=0\n", arg);
+ cinTable[currentHandle].fileName[0] = 0;
+ return -1;
+ }
+
+ CIN_SetExtents(currentHandle, x, y, w, h);
+ CIN_SetLooping(currentHandle, ((systemBits & CIN_loop) != 0));
+
+ cinTable[currentHandle].CIN_HEIGHT = DEFAULT_CIN_HEIGHT;
+ cinTable[currentHandle].CIN_WIDTH = DEFAULT_CIN_WIDTH;
+ cinTable[currentHandle].holdAtEnd = (systemBits & CIN_hold) != 0;
+ cinTable[currentHandle].alterGameState = (systemBits & CIN_system) != 0;
+ cinTable[currentHandle].playonwalls = 1;
+ cinTable[currentHandle].silent = (systemBits & CIN_silent) != 0;
+ cinTable[currentHandle].shader = (systemBits & CIN_shader) != 0;
+
+ if (cinTable[currentHandle].alterGameState)
+ {
+ // close the menu
+ if (cls.ui)
+ {
+ VM_Call(cls.ui, UI_SET_ACTIVE_MENU - cls.uiInterface == 2 ? 2 : 0, UIMENU_NONE);
+ }
+ }
+ else
+ {
+ cinTable[currentHandle].playonwalls = cl_inGameVideo->integer;
+ }
+
+ initRoQ();
+
+ FS_Read(cin.file, 16, cinTable[currentHandle].iFile);
+
+ RoQID = (unsigned short)(cin.file[0]) + (unsigned short)(cin.file[1]) * 256;
+ if (RoQID == 0x1084)
+ {
+ RoQ_init();
+ // FS_Read (cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile);
+
+ cinTable[currentHandle].status = FMV_PLAY;
+ Com_DPrintf("trFMV::play(), playing %s\n", arg);
+
+ if (cinTable[currentHandle].alterGameState)
+ {
+ clc.state = CA_CINEMATIC;
+ }
+
+ if (!cinTable[currentHandle].silent)
+ {
+ s_rawend[0] = s_soundtime;
+ }
+
+ return currentHandle;
+ }
+ Com_DPrintf("trFMV::play(), invalid RoQ ID\n");
+
+ RoQShutdown();
+ return -1;
+}
+
+/*
+==================
+CIN_ResampleCinematic
+
+Resample cinematic to 256x256 and store in buf2
+==================
+*/
+static void CIN_ResampleCinematic(int handle, int *buf2)
+{
+ int ix, iy, *buf3, xm, ym, ll;
+ byte *buf;
+
+ buf = cinTable[handle].buf;
+
+ xm = cinTable[handle].CIN_WIDTH / 256;
+ ym = cinTable[handle].CIN_HEIGHT / 256;
+ ll = 8;
+ if (cinTable[handle].CIN_WIDTH == 512)
+ {
+ ll = 9;
+ }
+
+ buf3 = (int *)buf;
+ if (xm == 2 && ym == 2)
+ {
+ byte *bc2, *bc3;
+ int ic, iiy;
+
+ bc2 = (byte *)buf2;
+ bc3 = (byte *)buf3;
+ for (iy = 0; iy < 256; iy++)
+ {
+ iiy = iy << 12;
+ for (ix = 0; ix < 2048; ix += 8)
+ {
+ for (ic = ix; ic < (ix + 4); ic++)
+ {
+ *bc2 = (bc3[iiy + ic] + bc3[iiy + 4 + ic] + bc3[iiy + 2048 + ic] + bc3[iiy + 2048 + 4 + ic]) >> 2;
+ bc2++;
+ }
+ }
+ }
+ }
+ else if (xm == 2 && ym == 1)
+ {
+ byte *bc2, *bc3;
+ int ic, iiy;
+
+ bc2 = (byte *)buf2;
+ bc3 = (byte *)buf3;
+ for (iy = 0; iy < 256; iy++)
+ {
+ iiy = iy << 11;
+ for (ix = 0; ix < 2048; ix += 8)
+ {
+ for (ic = ix; ic < (ix + 4); ic++)
+ {
+ *bc2 = (bc3[iiy + ic] + bc3[iiy + 4 + ic]) >> 1;
+ bc2++;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (iy = 0; iy < 256; iy++)
+ {
+ for (ix = 0; ix < 256; ix++)
+ {
+ buf2[(iy << 8) + ix] = buf3[((iy * ym) << ll) + (ix * xm)];
+ }
+ }
+ }
+}
+
+/*
+==================
+CIN_DrawCinematic
+==================
+*/
+void CIN_DrawCinematic(int handle)
+{
+ float x, y, w, h;
+ byte *buf;
+
+ if (handle < 0 || handle >= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return;
+
+ if (!cinTable[handle].buf)
+ {
+ return;
+ }
+
+ x = cinTable[handle].xpos;
+ y = cinTable[handle].ypos;
+ w = cinTable[handle].width;
+ h = cinTable[handle].height;
+ buf = cinTable[handle].buf;
+ SCR_AdjustFrom640(&x, &y, &w, &h);
+
+ if (cinTable[handle].dirty &&
+ (cinTable[handle].CIN_WIDTH != cinTable[handle].drawX
+ || cinTable[handle].CIN_HEIGHT != cinTable[handle].drawY))
+ {
+ int *buf2 = (int *)Hunk_AllocateTempMemory(256 * 256 * 4);
+
+ CIN_ResampleCinematic(handle, buf2);
+
+ re.DrawStretchRaw(x, y, w, h, 256, 256, (byte *)buf2, handle, true);
+ cinTable[handle].dirty = false;
+ Hunk_FreeTempMemory(buf2);
+ return;
+ }
+
+ re.DrawStretchRaw(x, y, w, h, cinTable[handle].drawX, cinTable[handle].drawY,
+ buf, handle, cinTable[handle].dirty);
+
+ cinTable[handle].dirty = false;
+}
+
+void CL_PlayCinematic_f(void)
+{
+ int bits = CIN_system;
+
+ Com_DPrintf("CL_PlayCinematic_f\n");
+ if (clc.state == CA_CINEMATIC)
+ {
+ SCR_StopCinematic();
+ }
+
+ const char *arg = Cmd_Argv(1);
+ const char *s = Cmd_Argv(2);
+
+ if ((s && s[0] == '1') || Q_stricmp(arg, "demoend.roq") == 0 || Q_stricmp(arg, "end.roq") == 0)
+ {
+ bits |= CIN_hold;
+ }
+ if (s && s[0] == '2')
+ {
+ bits |= CIN_loop;
+ }
+
+ S_StopAllSounds();
+
+ CL_handle = CIN_PlayCinematic(arg, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, bits);
+ if (CL_handle >= 0)
+ {
+ do
+ {
+ SCR_RunCinematic();
+ } while (cinTable[currentHandle].buf == NULL &&
+ cinTable[currentHandle].status == FMV_PLAY); // wait for first frame (load codebook and sound)
+ }
+}
+
+void SCR_DrawCinematic(void)
+{
+ if (CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES)
+ {
+ CIN_DrawCinematic(CL_handle);
+ }
+}
+
+void SCR_RunCinematic(void)
+{
+ if (CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES)
+ {
+ CIN_RunCinematic(CL_handle);
+ }
+}
+
+void SCR_StopCinematic(void)
+{
+ if (CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES)
+ {
+ CIN_StopCinematic(CL_handle);
+ S_StopAllSounds();
+ CL_handle = -1;
+ }
+}
+
+void CIN_UploadCinematic(int handle)
+{
+ if (handle >= 0 && handle < MAX_VIDEO_HANDLES)
+ {
+ if (!cinTable[handle].buf)
+ {
+ return;
+ }
+ if (cinTable[handle].playonwalls <= 0 && cinTable[handle].dirty)
+ {
+ if (cinTable[handle].playonwalls == 0)
+ {
+ cinTable[handle].playonwalls = -1;
+ }
+ else
+ {
+ if (cinTable[handle].playonwalls == -1)
+ {
+ cinTable[handle].playonwalls = -2;
+ }
+ else
+ {
+ cinTable[handle].dirty = false;
+ }
+ }
+ }
+
+ // Resample the video if needed
+ if (cinTable[handle].dirty && (cinTable[handle].CIN_WIDTH != cinTable[handle].drawX ||
+ cinTable[handle].CIN_HEIGHT != cinTable[handle].drawY))
+ {
+ int *buf2 = (int *)Hunk_AllocateTempMemory(256 * 256 * 4);
+
+ CIN_ResampleCinematic(handle, buf2);
+
+ re.UploadCinematic(
+ cinTable[handle].CIN_WIDTH, cinTable[handle].CIN_HEIGHT, 256, 256, (byte *)buf2, handle, true);
+ cinTable[handle].dirty = false;
+ Hunk_FreeTempMemory(buf2);
+ }
+ else
+ {
+ // Upload video at normal resolution
+ re.UploadCinematic(cinTable[handle].CIN_WIDTH, cinTable[handle].CIN_HEIGHT, cinTable[handle].drawX,
+ cinTable[handle].drawY, cinTable[handle].buf, handle, cinTable[handle].dirty);
+ cinTable[handle].dirty = false;
+ }
+
+ if (cl_inGameVideo->integer == 0 && cinTable[handle].playonwalls == 1)
+ {
+ cinTable[handle].playonwalls--;
+ }
+ else if (cl_inGameVideo->integer != 0 && cinTable[handle].playonwalls != 1)
+ {
+ cinTable[handle].playonwalls = 1;
+ }
+ }
+}
diff --git a/src/client/cl_console.cpp b/src/client/cl_console.cpp
new file mode 100644
index 0000000..e3e928c
--- /dev/null
+++ b/src/client/cl_console.cpp
@@ -0,0 +1,877 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// console.c
+
+#include "client.h"
+
+#include "qcommon/cdefs.h"
+
+int g_console_field_width = 78;
+
+
+#define NUM_CON_TIMES 4
+
+#define CON_TEXTSIZE 163840
+typedef struct {
+ bool initialized;
+
+ short text[CON_TEXTSIZE];
+ int current; // line where next message will be printed
+ int x; // offset in current line for next print
+ int display; // bottom of console displays this line
+
+ int linewidth; // characters across screen
+ int totallines; // total lines in console scrollback
+
+ float xadjust; // for wide aspect screens
+
+ float displayFrac; // aproaches finalFrac at scr_conspeed
+ float finalFrac; // 0.0 to 1.0 lines of console to display
+
+ int vislines; // in scanlines
+
+ vec4_t color;
+} console_t;
+
+console_t con;
+
+cvar_t *con_conspeed;
+cvar_t *con_height;
+cvar_t *con_useShader;
+cvar_t *con_colorRed;
+cvar_t *con_colorGreen;
+cvar_t *con_colorBlue;
+cvar_t *con_colorAlpha;
+cvar_t *con_versionStr;
+
+#define DEFAULT_CONSOLE_WIDTH 78
+
+
+/*
+================
+Con_ToggleConsole_f
+================
+*/
+void Con_ToggleConsole_f (void) {
+ // Can't toggle the console when it's the only thing available
+ if ( clc.state == CA_DISCONNECTED && Key_GetCatcher( ) == KEYCATCH_CONSOLE ) {
+ return;
+ }
+
+ Field_Clear( &g_consoleField );
+ g_consoleField.widthInChars = g_console_field_width;
+
+ Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_CONSOLE );
+}
+
+/*
+===================
+Con_ToggleMenu_f
+===================
+*/
+void Con_ToggleMenu_f( void ) {
+ CL_KeyEvent( K_ESCAPE, true, Sys_Milliseconds() );
+ CL_KeyEvent( K_ESCAPE, false, Sys_Milliseconds() );
+}
+
+/*
+===================
+Con_MessageMode_f
+===================
+-*/
+void Con_MessageMode_f (void) {
+ chat_playerNum = -1;
+ chat_team = false;
+ chat_admins = false;
+ chat_clans = false;
+ Field_Clear( &chatField );
+ chatField.widthInChars = 30;
+
+ Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
+}
+
+/*
+====================
+Con_MessageMode2_f
+====================
+*/
+void Con_MessageMode2_f (void) {
+ chat_playerNum = -1;
+ chat_team = true;
+ chat_admins = false;
+ chat_clans = false;
+ Field_Clear( &chatField );
+ chatField.widthInChars = 25;
+ Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
+}
+
+/*
+===================
+Con_MessageMode3_f
+===================
+*/
+void Con_MessageMode3_f (void) {
+ chat_playerNum = VM_Call( cls.cgame, CG_CROSSHAIR_PLAYER );
+ if ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) {
+ chat_playerNum = -1;
+ return;
+ }
+ chat_team = false;
+ chat_admins = false;
+ chat_clans = false;
+ Field_Clear( &chatField );
+ chatField.widthInChars = 30;
+ Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
+}
+
+/*
+=====================
+Con_MessageMode4_f
+=====================
+*/
+void Con_MessageMode4_f (void) {
+ chat_playerNum = VM_Call( cls.cgame, CG_LAST_ATTACKER );
+ if ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) {
+ chat_playerNum = -1;
+ return;
+ }
+ chat_team = false;
+ chat_admins = false;
+ chat_clans = false;
+ Field_Clear( &chatField );
+ chatField.widthInChars = 30;
+ Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
+}
+
+/*
+================
+Con_MessageMode5_f
+================
+*/
+void Con_MessageMode5_f (void) {
+ int i;
+ chat_playerNum = -1;
+ chat_team = false;
+ chat_admins = true;
+ chat_clans = false;
+ Field_Clear( &chatField );
+ chatField.widthInChars = 25;
+ Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
+}
+
+/*
+================
+Con_MessageMode6_f
+================
+*/
+void Con_MessageMode6_f (void) {
+ int i;
+ chat_playerNum = -1;
+ chat_team = false;
+ chat_admins = false;
+ chat_clans = true;
+ Field_Clear( &chatField );
+ chatField.widthInChars = 25;
+ Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
+}
+
+/*
+================
+Con_Clear_f
+================
+*/
+void Con_Clear_f (void) {
+ int i;
+
+ for ( i = 0 ; i < CON_TEXTSIZE ; i++ ) {
+ con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
+ }
+
+ Con_Bottom(); // go to end
+}
+
+
+/*
+================
+Con_Dump_f
+
+Save the console contents out to a file
+================
+*/
+void Con_Dump_f (void)
+{
+ int l, x, i;
+ short *line;
+ fileHandle_t f;
+ int bufferlen;
+ char *buffer;
+ char filename[MAX_QPATH];
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("usage: condump <filename>\n");
+ return;
+ }
+
+ Q_strncpyz( filename, Cmd_Argv( 1 ), sizeof( filename ) );
+ COM_DefaultExtension( filename, sizeof( filename ), ".txt" );
+
+ if (!COM_CompareExtension(filename, ".txt"))
+ {
+ Com_Printf("Con_Dump_f: Only the \".txt\" extension is supported by this command!\n");
+ return;
+ }
+
+ f = FS_FOpenFileWrite( filename );
+ if (!f)
+ {
+ Com_Printf("ERROR: couldn't open %s.\n", filename);
+ return;
+ }
+
+ Com_Printf("Dumped console text to %s.\n", filename );
+
+ // skip empty lines
+ for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
+ {
+ line = con.text + (l%con.totallines)*con.linewidth;
+ for (x=0 ; x<con.linewidth ; x++)
+ if ((line[x] & 0xff) != ' ')
+ break;
+ if (x != con.linewidth)
+ break;
+ }
+
+#ifdef _WIN32
+ bufferlen = con.linewidth + 3 * sizeof ( char );
+#else
+ bufferlen = con.linewidth + 2 * sizeof ( char );
+#endif
+
+ buffer = (char*)Hunk_AllocateTempMemory( bufferlen );
+
+ // write the remaining lines
+ buffer[bufferlen-1] = 0;
+ for ( ; l <= con.current ; l++)
+ {
+ line = con.text + (l%con.totallines)*con.linewidth;
+ for(i=0; i<con.linewidth; i++)
+ buffer[i] = line[i] & 0xff;
+ for (x=con.linewidth-1 ; x>=0 ; x--)
+ {
+ if (buffer[x] == ' ')
+ buffer[x] = 0;
+ else
+ break;
+ }
+#ifdef _WIN32
+ Q_strcat(buffer, bufferlen, "\r\n");
+#else
+ Q_strcat(buffer, bufferlen, "\n");
+#endif
+ FS_Write(buffer, strlen(buffer), f);
+ }
+
+ Hunk_FreeTempMemory( buffer );
+ FS_FCloseFile( f );
+}
+
+
+/*
+================
+Con_ClearNotify
+================
+*/
+void Con_ClearNotify( void ) {
+ Cmd_TokenizeString( NULL );
+ CL_GameConsoleText( );
+}
+
+
+
+/*
+================
+Con_CheckResize
+
+If the line width has changed, reformat the buffer.
+================
+*/
+void Con_CheckResize (void)
+{
+ int i, j, width, oldwidth, oldtotallines, numlines, numchars;
+ short tbuf[CON_TEXTSIZE];
+
+ width = (SCREEN_WIDTH / SMALLCHAR_WIDTH) - 2;
+
+ if (width == con.linewidth)
+ return;
+
+ if (width < 1) // video hasn't been initialized yet
+ {
+ width = DEFAULT_CONSOLE_WIDTH;
+ con.linewidth = width;
+ con.totallines = CON_TEXTSIZE / con.linewidth;
+ for(i=0; i<CON_TEXTSIZE; i++)
+
+ con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
+ }
+ else
+ {
+ oldwidth = con.linewidth;
+ con.linewidth = width;
+ oldtotallines = con.totallines;
+ con.totallines = CON_TEXTSIZE / con.linewidth;
+ numlines = oldtotallines;
+
+ if (con.totallines < numlines)
+ numlines = con.totallines;
+
+ numchars = oldwidth;
+
+ if (con.linewidth < numchars)
+ numchars = con.linewidth;
+
+ ::memcpy(tbuf, con.text, CON_TEXTSIZE * sizeof(short));
+ for(i=0; i<CON_TEXTSIZE; i++)
+
+ con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
+
+
+ for (i=0 ; i<numlines ; i++)
+ {
+ for (j=0 ; j<numchars ; j++)
+ {
+ con.text[(con.totallines - 1 - i) * con.linewidth + j] =
+ tbuf[((con.current - i + oldtotallines) %
+ oldtotallines) * oldwidth + j];
+ }
+ }
+ }
+
+ con.current = con.totallines - 1;
+ con.display = con.current;
+}
+
+/*
+==================
+Cmd_CompleteTxtName
+==================
+*/
+void Cmd_CompleteTxtName( char *args UNUSED, int argNum ) {
+ if( argNum == 2 ) {
+ Field_CompleteFilename( "", "txt", false, true );
+ }
+}
+
+/*
+================
+Con_MessageModesInit
+================
+*/
+void Con_MessageModesInit(void) {
+ if( clc.netchan.alternateProtocol == 2 )
+ {
+ // add the client side message modes for 1.1 servers
+ if( !Cmd_CommadExists( "messagemode" ) )
+ Cmd_AddCommand ("messagemode", Con_MessageMode_f);
+ if( !Cmd_CommadExists( "messagemode2" ) )
+ Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
+ if( !Cmd_CommadExists( "messagemode3" ) )
+ Cmd_AddCommand ("messagemode3", Con_MessageMode3_f);
+ if( !Cmd_CommadExists( "messagemode4" ) )
+ Cmd_AddCommand ("messagemode4", Con_MessageMode4_f);
+ if( !Cmd_CommadExists( "messagemode5" ) )
+ Cmd_AddCommand ("messagemode5", Con_MessageMode5_f);
+ if( !Cmd_CommadExists( "messagemode6" ) )
+ Cmd_AddCommand ("messagemode6", Con_MessageMode6_f);
+ } else
+ {
+ // remove the client side message modes for non-1.1 servers
+ Cmd_RemoveCommand("messagemode");
+ Cmd_RemoveCommand("messagemode2");
+ Cmd_RemoveCommand("messagemode3");
+ Cmd_RemoveCommand("messagemode4");
+ Cmd_RemoveCommand("messagemode5");
+ Cmd_RemoveCommand("messagemode6");
+ }
+}
+
+/*
+================
+Con_Init
+================
+*/
+void Con_Init (void) {
+ int i;
+
+ con_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
+ con_useShader = Cvar_Get ("scr_useShader", "1", CVAR_ARCHIVE);
+ con_height = Cvar_Get ("scr_height", "50", CVAR_ARCHIVE);
+ con_colorRed = Cvar_Get ("scr_colorRed", "0", CVAR_ARCHIVE);
+ con_colorBlue = Cvar_Get ("scr_colorBlue", "0", CVAR_ARCHIVE);
+ con_colorGreen = Cvar_Get ("scr_colorGreen", "0", CVAR_ARCHIVE);
+ con_colorAlpha = Cvar_Get ("scr_colorAlpha", ".8", CVAR_ARCHIVE);
+ con_versionStr = Cvar_Get ("scr_versionString", Q3_VERSION, CVAR_ARCHIVE);
+
+ Field_Clear( &g_consoleField );
+ g_consoleField.widthInChars = g_console_field_width;
+ for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
+ Field_Clear( &historyEditLines[i] );
+ historyEditLines[i].widthInChars = g_console_field_width;
+ }
+ CL_LoadConsoleHistory( );
+ if( clc.netchan.alternateProtocol == 2 )
+ {
+ Cmd_AddCommand ("messagemode", Con_MessageMode_f);
+ Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
+ Cmd_AddCommand ("messagemode3", Con_MessageMode3_f);
+ Cmd_AddCommand ("messagemode4", Con_MessageMode4_f);
+ Cmd_AddCommand ("messagemode5", Con_MessageMode5_f);
+ Cmd_AddCommand ("messagemode6", Con_MessageMode6_f);
+ }
+
+ Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
+ Cmd_AddCommand ("togglemenu", Con_ToggleMenu_f);
+ Cmd_AddCommand ("clear", Con_Clear_f);
+ Cmd_AddCommand ("condump", Con_Dump_f);
+ Cmd_SetCommandCompletionFunc( "condump", Cmd_CompleteTxtName );
+}
+
+/*
+================
+Con_Shutdown
+================
+*/
+void Con_Shutdown(void)
+{
+ Cmd_RemoveCommand("toggleconsole");
+ Cmd_RemoveCommand("togglemenu");
+ Cmd_RemoveCommand("clear");
+ Cmd_RemoveCommand("condump");
+}
+
+/*
+===============
+Con_Linefeed
+===============
+*/
+void Con_Linefeed(void)
+{
+ int i;
+
+ con.x = 0;
+
+ if (con.display == con.current)
+ con.display++;
+
+ con.current++;
+
+ for(i=0; i<con.linewidth; i++)
+ con.text[(con.current%con.totallines)*con.linewidth+i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
+}
+
+/*
+================
+CL_ConsolePrint
+
+Handles cursor positioning, line wrapping, etc
+All console printing must go through this in order to be logged to disk
+If no console is visible, the text will appear at the top of the game window
+================
+*/
+void CL_ConsolePrint( const char *txt )
+{
+ int y, l;
+ unsigned char c;
+ unsigned short color;
+ bool skipnotify = false; // NERVE - SMF
+
+ // TTimo - prefix for text that shows up in console but not in notify
+ // backported from RTCW
+ if ( !Q_strncmp( txt, "[skipnotify]", 12 ) ) {
+ skipnotify = true;
+ txt += 12;
+ }
+
+ // for some demos we don't want to ever show anything on the console
+ if ( cl_noprint && cl_noprint->integer )
+ return;
+
+ if (!con.initialized) {
+ con.color[0] =
+ con.color[1] =
+ con.color[2] =
+ con.color[3] = 1.0f;
+ con.linewidth = -1;
+ Con_CheckResize ();
+ con.initialized = true;
+ }
+
+ if( !skipnotify && !(Key_GetCatcher( ) & KEYCATCH_CONSOLE) )
+ {
+ Cmd_SaveCmdContext( );
+
+ // feed the text to cgame
+ Cmd_TokenizeString( txt );
+ CL_GameConsoleText( );
+
+ Cmd_RestoreCmdContext( );
+ }
+
+ color = ColorIndex(COLOR_WHITE);
+
+ while ( (c = *((unsigned char *)txt)) != 0 )
+ {
+ if ( Q_IsColorString( txt ) )
+ {
+ color = ColorIndex( *(txt+1) );
+ txt += 2;
+ continue;
+ }
+
+ // count word length
+ for (l=0 ; l< con.linewidth ; l++)
+ {
+ if ( txt[l] <= ' ')
+ break;
+ }
+
+ // word wrap
+ if (l != con.linewidth && (con.x + l >= con.linewidth) )
+ Con_Linefeed();
+
+ txt++;
+
+ switch (c)
+ {
+ case INDENT_MARKER:
+ break;
+ case '\n':
+ Con_Linefeed();
+ break;
+ case '\r':
+ con.x = 0;
+ break;
+ default: // display character and advance
+ y = con.current % con.totallines;
+ con.text[y*con.linewidth+con.x] = (color << 8) | c;
+ con.x++;
+ if(con.x >= con.linewidth)
+ Con_Linefeed();
+ break;
+ }
+ }
+}
+
+
+/*
+==============================================================================
+
+DRAWING
+
+==============================================================================
+*/
+
+
+/*
+================
+Con_DrawInput
+
+Draw the editline after a ] prompt
+================
+*/
+static void Con_DrawInput (void)
+{
+ int y;
+
+ if ( clc.state != CA_DISCONNECTED && !(Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ) {
+ return;
+ }
+
+ y = con.vislines - ( SMALLCHAR_HEIGHT * 2 );
+
+ re.SetColor( con.color );
+
+ SCR_DrawSmallChar( con.xadjust + 1 * SMALLCHAR_WIDTH, y, ']' );
+
+ Field_Draw( &g_consoleField,
+ con.xadjust + 2 * SMALLCHAR_WIDTH,
+ y,
+ SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH,
+ true, true );
+}
+
+/*
+================
+Con_DrawSolidConsole
+
+Draws the console with the solid background
+================
+*/
+static void Con_DrawSolidConsole( float frac )
+{
+ int i, x, y;
+ int rows;
+ short *text;
+ int row;
+ int lines;
+ int currentColor;
+ vec4_t color;
+
+ lines = cls.glconfig.vidHeight * frac;
+ if (lines <= 0)
+ return;
+
+ if (lines > cls.glconfig.vidHeight )
+ lines = cls.glconfig.vidHeight;
+
+ // on wide screens, we will center the text
+ con.xadjust = 0;
+ SCR_AdjustFrom640( &con.xadjust, NULL, NULL, NULL );
+
+ // draw the background
+ y = frac * SCREEN_HEIGHT;
+ if ( y < 1 )
+ {
+ y = 0;
+ }
+ else if (con_useShader->integer)
+ {
+ SCR_DrawPic(0, 0, SCREEN_WIDTH, y, cls.consoleShader);
+ }
+ else
+ {
+ color[0] = con_colorRed->value;
+ color[1] = con_colorGreen->value;
+ color[2] = con_colorBlue->value;
+ color[3] = con_colorAlpha->value;
+ SCR_FillRect(0, 0, SCREEN_WIDTH, y, color);
+ }
+
+ color[0] = 1;
+ color[1] = 0;
+ color[2] = 0;
+ color[3] = 1;
+ SCR_FillRect(0, y, SCREEN_WIDTH, 2, color);
+
+
+ // draw the version number
+
+ re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
+
+ i = strlen( Q3_VERSION );
+
+ for (x=0 ; x<i ; x++) {
+ SCR_DrawSmallChar( cls.glconfig.vidWidth - ( i - x + 1 ) * SMALLCHAR_WIDTH,
+ lines - SMALLCHAR_HEIGHT, Q3_VERSION[x] );
+ }
+
+ // draw the text
+ con.vislines = lines;
+ rows = (lines-SMALLCHAR_HEIGHT)/SMALLCHAR_HEIGHT; // rows of text to draw
+
+ y = lines - (SMALLCHAR_HEIGHT*3);
+
+ // draw from the bottom up
+ if (con.display != con.current)
+ {
+ // draw arrows to show the buffer is backscrolled
+ re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
+ for (x=0 ; x<con.linewidth ; x+=4)
+ SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, '^' );
+ y -= SMALLCHAR_HEIGHT;
+ rows--;
+ }
+
+ row = con.display;
+
+ if ( con.x == 0 ) {
+ row--;
+ }
+
+ currentColor = 7;
+ re.SetColor( g_color_table[currentColor] );
+
+ for (i=0 ; i<rows ; i++, y -= SMALLCHAR_HEIGHT, row--)
+ {
+ if (row < 0)
+ break;
+ if (con.current - row >= con.totallines) {
+ // past scrollback wrap point
+ continue;
+ }
+
+ text = con.text + (row % con.totallines)*con.linewidth;
+
+ for (x=0 ; x<con.linewidth ; x++) {
+ if ( ( text[x] & 0xff ) == ' ' ) {
+ continue;
+ }
+
+ if ( ColorIndexForNumber( text[x]>>8 ) != currentColor ) {
+ currentColor = ColorIndexForNumber( text[x]>>8 );
+ re.SetColor( g_color_table[currentColor] );
+ }
+ SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff );
+ }
+ }
+
+ // draw the input prompt, user text, and cursor if desired
+ Con_DrawInput ();
+
+ re.SetColor( NULL );
+}
+
+
+
+/*
+==================
+Con_DrawConsole
+==================
+*/
+void Con_DrawConsole( void ) {
+ // check for console width changes from a vid mode change
+ Con_CheckResize ();
+
+ // if disconnected, render console full screen
+ if ( clc.state == CA_DISCONNECTED ) {
+ if ( !( Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME)) ) {
+ Con_DrawSolidConsole( 1.0 );
+ return;
+ }
+ }
+
+ // draw the chat line
+ if( clc.netchan.alternateProtocol == 2 &&
+ ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) )
+ {
+ int skip;
+
+ if( chatField.buffer[0] == '/' ||
+ chatField.buffer[0] == '\\' )
+ {
+ SCR_DrawBigString( 8, 232, "Command:", 1.0f, qfalse );
+ skip = 10;
+ }
+ else if( chat_team )
+ {
+ SCR_DrawBigString( 8, 232, "Team Say:", 1.0f, qfalse );
+ skip = 11;
+ }
+ else if( chat_admins )
+ {
+ SCR_DrawBigString( 8, 232, "Admin Say:", 1.0f, qfalse );
+ skip = 11;
+ }
+ else if( chat_clans )
+ {
+ SCR_DrawBigString( 8, 232, "Clan Say:", 1.0f, qfalse );
+ skip = 11;
+ }
+ else
+ {
+ SCR_DrawBigString( 8, 232, "Say:", 1.0f, qfalse );
+ skip = 5;
+ }
+
+ Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, 232,
+ SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue, qtrue );
+ }
+
+ if ( con.displayFrac ) {
+ Con_DrawSolidConsole( con.displayFrac );
+ }
+
+ if( Key_GetCatcher( ) & ( KEYCATCH_UI | KEYCATCH_CGAME ) )
+ return;
+}
+//================================================================
+
+/*
+==================
+Con_RunConsole
+
+Scroll it up or down
+==================
+*/
+void Con_RunConsole (void) {
+ // decide on the destination height of the console
+ if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE )
+ con.finalFrac = MAX(0.10, 0.01 * con_height->integer);
+ else
+ con.finalFrac = 0; // none visible
+
+ // scroll towards the destination height
+ if (con.finalFrac < con.displayFrac)
+ {
+ con.displayFrac -= con_conspeed->value*cls.realFrametime*0.001;
+ if (con.finalFrac > con.displayFrac)
+ con.displayFrac = con.finalFrac;
+
+ }
+ else if (con.finalFrac > con.displayFrac)
+ {
+ con.displayFrac += con_conspeed->value*cls.realFrametime*0.001;
+ if (con.finalFrac < con.displayFrac)
+ con.displayFrac = con.finalFrac;
+ }
+
+}
+
+
+void Con_PageUp( void ) {
+ con.display -= 2;
+ if ( con.current - con.display >= con.totallines ) {
+ con.display = con.current - con.totallines + 1;
+ }
+}
+
+void Con_PageDown( void ) {
+ con.display += 2;
+ if (con.display > con.current) {
+ con.display = con.current;
+ }
+}
+
+void Con_Top( void ) {
+ con.display = con.totallines;
+ if ( con.current - con.display >= con.totallines ) {
+ con.display = con.current - con.totallines + 1;
+ }
+}
+
+void Con_Bottom( void ) {
+ con.display = con.current;
+}
+
+
+void Con_Close( void ) {
+ if ( !com_cl_running->integer ) {
+ return;
+ }
+ Field_Clear( &g_consoleField );
+ Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CONSOLE );
+ con.finalFrac = 0; // none visible
+ con.displayFrac = 0;
+}
diff --git a/src/client/cl_curl.cpp b/src/client/cl_curl.cpp
new file mode 100644
index 0000000..0c81985
--- /dev/null
+++ b/src/client/cl_curl.cpp
@@ -0,0 +1,364 @@
+/*
+===========================================================================
+Copyright (C) 2006 Tony J. White (tjw@tjw.org)
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "client.h"
+
+#ifdef USE_CURL_DLOPEN
+#include "sys/sys_loadlib.h"
+
+cvar_t *cl_cURLLib;
+
+char* (*qcurl_version)(void);
+
+CURL* (*qcurl_easy_init)(void);
+CURLcode (*qcurl_easy_setopt)(CURL *curl, CURLoption option, ...);
+CURLcode (*qcurl_easy_perform)(CURL *curl);
+void (*qcurl_easy_cleanup)(CURL *curl);
+CURLcode (*qcurl_easy_getinfo)(CURL *curl, CURLINFO info, ...);
+CURL* (*qcurl_easy_duphandle)(CURL *curl);
+void (*qcurl_easy_reset)(CURL *curl);
+const char *(*qcurl_easy_strerror)(CURLcode);
+
+CURLM* (*qcurl_multi_init)(void);
+CURLMcode (*qcurl_multi_add_handle)(CURLM*, CURL*curl_handle);
+CURLMcode (*qcurl_multi_remove_handle)(CURLM*, CURL*);
+CURLMcode (*qcurl_multi_fdset)(CURLM*, fd_set* read_set, fd_set* write_set, fd_set* exc_set, int*);
+CURLMcode (*qcurl_multi_perform)(CURLM*, int*);
+CURLMcode (*qcurl_multi_cleanup)(CURLM*);
+CURLMsg *(*qcurl_multi_info_read)(CURLM*, int*);
+const char *(*qcurl_multi_strerror)(CURLMcode);
+
+struct curl_slist* (*qcurl_slist_append)(struct curl_slist*, const char*);
+void (*qcurl_slist_free_all)(struct curl_slist*);
+
+CURLcode (*qcurl_global_init)(long);
+void (*qcurl_global_cleanup)(void);
+
+
+static void *cURLLib = NULL;
+
+/*
+=================
+GPA
+=================
+*/
+static void *GPA(const char *str)
+{
+ void* rv = Sys_LoadFunction(cURLLib, str);
+ if(!rv)
+ {
+ Com_Printf("Can't load symbol %s\n", str);
+ clc.cURLEnabled = false;
+ return NULL;
+ }
+ else
+ {
+ Com_DPrintf("Loaded symbol %s (0x%p)\n", str, rv);
+ return rv;
+ }
+}
+#endif /* USE_CURL_DLOPEN */
+
+/*
+=================
+CL_cURL_Init
+=================
+*/
+bool CL_cURL_Init()
+{
+#ifdef USE_CURL_DLOPEN
+ cl_cURLLib = Cvar_Get("cl_cURLLib", DEFAULT_CURL_LIB, CVAR_ARCHIVE | CVAR_PROTECTED);
+
+ if(cURLLib)
+ return true;
+
+ Com_Printf("Loading \"%s\"...", cl_cURLLib->string);
+ if( !(cURLLib = Sys_LoadDll(cl_cURLLib->string, true)) )
+ {
+#ifdef ALTERNATE_CURL_LIB
+ // On some linux distributions there is no libcurl.so.3, but only libcurl.so.4. That one works too.
+ if( !(cURLLib = Sys_LoadDll(ALTERNATE_CURL_LIB, true)) )
+#endif
+ return false;
+ }
+
+ clc.cURLEnabled = true;
+
+ qcurl_version = (decltype(qcurl_version)) GPA("curl_version");
+
+ qcurl_easy_init = (decltype(qcurl_easy_init)) GPA("curl_easy_init");
+ qcurl_easy_setopt = (decltype(qcurl_easy_setopt)) GPA("curl_easy_setopt");
+ qcurl_easy_perform = (decltype(qcurl_easy_perform)) GPA("curl_easy_perform");
+ qcurl_easy_cleanup = (decltype(qcurl_easy_cleanup)) GPA("curl_easy_cleanup");
+ qcurl_easy_getinfo = (decltype(qcurl_easy_getinfo)) GPA("curl_easy_getinfo");
+ qcurl_easy_duphandle = (decltype(qcurl_easy_duphandle)) GPA("curl_easy_duphandle");
+ qcurl_easy_reset = (decltype(qcurl_easy_reset)) GPA("curl_easy_reset");
+ qcurl_easy_strerror = (decltype(qcurl_easy_strerror)) GPA("curl_easy_strerror");
+
+ qcurl_multi_init = (decltype(qcurl_multi_init)) GPA("curl_multi_init");
+ qcurl_multi_add_handle = (decltype(qcurl_multi_add_handle)) GPA("curl_multi_add_handle");
+ qcurl_multi_remove_handle = (decltype(qcurl_multi_remove_handle)) GPA("curl_multi_remove_handle");
+ qcurl_multi_fdset = (decltype(qcurl_multi_fdset)) GPA("curl_multi_fdset");
+ qcurl_multi_perform = (decltype(qcurl_multi_perform)) GPA("curl_multi_perform");
+ qcurl_multi_cleanup = (decltype(qcurl_multi_cleanup)) GPA("curl_multi_cleanup");
+ qcurl_multi_info_read = (decltype(qcurl_multi_info_read)) GPA("curl_multi_info_read");
+ qcurl_multi_strerror = (decltype(qcurl_multi_strerror)) GPA("curl_multi_strerror");
+ qcurl_slist_append = (decltype(qcurl_slist_append)) GPA("curl_slist_append");
+ qcurl_slist_free_all = (decltype(qcurl_slist_free_all)) GPA("curl_slist_free_all");
+ qcurl_global_init = (decltype(qcurl_global_init)) GPA("curl_global_init");
+ qcurl_global_cleanup = (decltype(qcurl_global_cleanup)) GPA("curl_global_cleanup");
+
+ if(!clc.cURLEnabled)
+ {
+ CL_cURL_Shutdown();
+ Com_Printf("FAIL One or more symbols not found\n");
+ return false;
+ }
+ Com_Printf("OK\n");
+
+ return true;
+#else
+ clc.cURLEnabled = true;
+ return true;
+#endif /* USE_CURL_DLOPEN */
+}
+
+/*
+=================
+CL_cURL_Shutdown
+=================
+*/
+void CL_cURL_Shutdown( void )
+{
+ CL_cURL_Cleanup();
+#ifdef USE_CURL_DLOPEN
+ if(cURLLib)
+ {
+ Sys_UnloadLibrary(cURLLib);
+ cURLLib = NULL;
+ }
+ qcurl_easy_init = NULL;
+ qcurl_easy_setopt = NULL;
+ qcurl_easy_perform = NULL;
+ qcurl_easy_cleanup = NULL;
+ qcurl_easy_getinfo = NULL;
+ qcurl_easy_duphandle = NULL;
+ qcurl_easy_reset = NULL;
+
+ qcurl_multi_init = NULL;
+ qcurl_multi_add_handle = NULL;
+ qcurl_multi_remove_handle = NULL;
+ qcurl_multi_fdset = NULL;
+ qcurl_multi_perform = NULL;
+ qcurl_multi_cleanup = NULL;
+ qcurl_multi_info_read = NULL;
+ qcurl_multi_strerror = NULL;
+#endif /* USE_CURL_DLOPEN */
+}
+
+void CL_cURL_Cleanup(void)
+{
+ if(clc.downloadCURLM) {
+ CURLMcode result;
+
+ if(clc.downloadCURL) {
+ result = qcurl_multi_remove_handle(clc.downloadCURLM,
+ clc.downloadCURL);
+ if(result != CURLM_OK) {
+ Com_DPrintf("qcurl_multi_remove_handle failed: %s\n", qcurl_multi_strerror(result));
+ }
+ qcurl_easy_cleanup(clc.downloadCURL);
+ }
+ result = qcurl_multi_cleanup(clc.downloadCURLM);
+ if(result != CURLM_OK) {
+ Com_DPrintf("CL_cURL_Cleanup: qcurl_multi_cleanup failed: %s\n", qcurl_multi_strerror(result));
+ }
+ clc.downloadCURLM = NULL;
+ clc.downloadCURL = NULL;
+ }
+ else if(clc.downloadCURL) {
+ qcurl_easy_cleanup(clc.downloadCURL);
+ clc.downloadCURL = NULL;
+ }
+}
+
+static int CL_cURL_CallbackProgress( void *dummy, double dltotal, double dlnow,
+ double ultotal, double ulnow )
+{
+ clc.downloadSize = (int)dltotal;
+ Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
+ clc.downloadCount = (int)dlnow;
+ Cvar_SetValue( "cl_downloadCount", clc.downloadCount );
+ return 0;
+}
+
+static size_t CL_cURL_CallbackWrite(void *buffer, size_t size, size_t nmemb,
+ void *stream)
+{
+ FS_Write( buffer, size*nmemb, ((fileHandle_t*)stream)[0] );
+ return size*nmemb;
+}
+
+CURLcode qcurl_easy_setopt_warn(CURL *curl, CURLoption option, ...)
+{
+ CURLcode result;
+
+ va_list argp;
+ va_start(argp, option);
+
+ if(option < CURLOPTTYPE_OBJECTPOINT) {
+ long longValue = va_arg(argp, long);
+ result = qcurl_easy_setopt(curl, option, longValue);
+ } else if(option < CURLOPTTYPE_OFF_T) {
+ void *pointerValue = va_arg(argp, void *);
+ result = qcurl_easy_setopt(curl, option, pointerValue);
+ } else {
+ curl_off_t offsetValue = va_arg(argp, curl_off_t);
+ result = qcurl_easy_setopt(curl, option, offsetValue);
+ }
+
+ if(result != CURLE_OK) {
+ Com_DPrintf("qcurl_easy_setopt failed: %s\n", qcurl_easy_strerror(result));
+ }
+ va_end(argp);
+
+ return result;
+}
+
+void CL_cURL_BeginDownload( const char *localName, const char *remoteURL )
+{
+ CURLMcode result;
+
+ clc.cURLUsed = true;
+ Com_Printf("URL: %s\n", remoteURL);
+ Com_DPrintf("***** CL_cURL_BeginDownload *****\n"
+ "Localname: %s\n"
+ "RemoteURL: %s\n"
+ "****************************\n", localName, remoteURL);
+ CL_cURL_Cleanup();
+ Q_strncpyz(clc.downloadURL, remoteURL, sizeof(clc.downloadURL));
+ Q_strncpyz(clc.downloadName, localName, sizeof(clc.downloadName));
+ Com_sprintf(clc.downloadTempName, sizeof(clc.downloadTempName),
+ "%s.tmp", localName);
+
+ // Set so UI gets access to it
+ Cvar_Set("cl_downloadName", localName);
+ Cvar_Set("cl_downloadSize", "0");
+ Cvar_Set("cl_downloadCount", "0");
+ Cvar_SetValue("cl_downloadTime", cls.realtime);
+
+ clc.downloadBlock = 0; // Starting new file
+ clc.downloadCount = 0;
+
+ clc.downloadCURL = qcurl_easy_init();
+ if(!clc.downloadCURL) {
+ Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_easy_init() "
+ "failed");
+ return;
+ }
+ clc.download = FS_SV_FOpenFileWrite(clc.downloadTempName);
+ if(!clc.download) {
+ Com_Error(ERR_DROP, "CL_cURL_BeginDownload: failed to open "
+ "%s for writing", clc.downloadTempName);
+ return;
+ }
+
+ if(com_developer->integer)
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_VERBOSE, 1);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_URL, clc.downloadURL);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_TRANSFERTEXT, 0);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_REFERER, va("Tremulous://%s", NET_AdrToString(clc.serverAddress)));
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_USERAGENT, va("%s %s", Q3_VERSION, qcurl_version()));
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_WRITEFUNCTION, CL_cURL_CallbackWrite);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_WRITEDATA, &clc.download);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_NOPROGRESS, 0);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_PROGRESSFUNCTION, CL_cURL_CallbackProgress);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_PROGRESSDATA, NULL);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_FAILONERROR, 1);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_FOLLOWLOCATION, 1);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_MAXREDIRS, 5);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | CURLPROTO_FTPS );
+ clc.downloadCURLM = qcurl_multi_init();
+ if(!clc.downloadCURLM)
+ {
+ qcurl_easy_cleanup(clc.downloadCURL);
+ clc.downloadCURL = NULL;
+ Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_multi_init() "
+ "failed");
+ return;
+ }
+
+ result = qcurl_multi_add_handle(clc.downloadCURLM, clc.downloadCURL);
+ if(result != CURLM_OK)
+ {
+ qcurl_easy_cleanup(clc.downloadCURL);
+ clc.downloadCURL = NULL;
+ Com_Error(ERR_DROP,"CL_cURL_BeginDownload: qcurl_multi_add_handle() failed: %s", qcurl_multi_strerror(result));
+ return;
+ }
+
+ if(!(clc.sv_allowDownload & DLF_NO_DISCONNECT) && !clc.cURLDisconnected)
+ {
+ CL_AddReliableCommand("disconnect", true);
+ CL_WritePacket();
+ CL_WritePacket();
+ CL_WritePacket();
+ clc.cURLDisconnected = true;
+ }
+}
+
+void CL_cURL_PerformDownload(void)
+{
+ CURLMcode res;
+ CURLMsg *msg;
+ int c;
+ int i = 0;
+
+ res = qcurl_multi_perform(clc.downloadCURLM, &c);
+ while(res == CURLM_CALL_MULTI_PERFORM && i < 100) {
+ res = qcurl_multi_perform(clc.downloadCURLM, &c);
+ i++;
+ }
+ if(res == CURLM_CALL_MULTI_PERFORM)
+ return;
+ msg = qcurl_multi_info_read(clc.downloadCURLM, &c);
+ if(msg == NULL) {
+ return;
+ }
+ FS_FCloseFile(clc.download);
+ if(msg->msg == CURLMSG_DONE && msg->data.result == CURLE_OK) {
+ FS_SV_Rename(clc.downloadTempName, clc.downloadName, false);
+ clc.downloadRestart = true;
+ }
+ else {
+ long code;
+
+ qcurl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &code);
+ Com_Error(ERR_DROP, "Download Error: %s Code: %ld URL: %s",
+ qcurl_easy_strerror(msg->data.result),
+ code, clc.downloadURL);
+ }
+
+ CL_NextDownload();
+}
diff --git a/src/client/cl_curl.h b/src/client/cl_curl.h
new file mode 100644
index 0000000..2e3b4e3
--- /dev/null
+++ b/src/client/cl_curl.h
@@ -0,0 +1,101 @@
+/*
+===========================================================================
+Copyright (C) 2006 Tony J. White (tjw@tjw.org)
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifndef __QCURL_H__
+#define __QCURL_H__
+
+#ifdef USE_LOCAL_HEADERS
+#include "curl/curl.h"
+#else
+#include <curl/curl.h>
+#endif
+
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+#ifdef USE_CURL_DLOPEN
+#ifdef _WIN32
+ #define DEFAULT_CURL_LIB "libcurl-4.dll"
+ #define ALTERNATE_CURL_LIB "libcurl-3.dll"
+#elif defined(__APPLE__)
+ #define DEFAULT_CURL_LIB "libcurl.dylib"
+#else
+ #define DEFAULT_CURL_LIB "libcurl.so.4"
+ #define ALTERNATE_CURL_LIB "libcurl.so.3"
+#endif
+
+extern cvar_t *cl_cURLLib;
+
+extern char* (*qcurl_version)(void);
+extern CURL* (*qcurl_easy_init)(void);
+extern CURLcode (*qcurl_easy_setopt)(CURL *curl, CURLoption option, ...);
+extern CURLcode (*qcurl_easy_perform)(CURL *curl);
+extern void (*qcurl_easy_cleanup)(CURL *curl);
+extern CURLcode (*qcurl_easy_getinfo)(CURL *curl, CURLINFO info, ...);
+extern void (*qcurl_easy_reset)(CURL *curl);
+extern const char* (*qcurl_easy_strerror)(CURLcode);
+extern CURLM* (*qcurl_multi_init)(void);
+extern CURLMcode (*qcurl_multi_add_handle)(CURLM *multi_handle, CURL *curl_handle);
+extern CURLMcode (*qcurl_multi_remove_handle)(CURLM *multi_handle, CURL *curl_handle);
+extern CURLMcode (*qcurl_multi_fdset)(CURLM *multi_handle, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd);
+extern CURLMcode (*qcurl_multi_perform)(CURLM *multi_handle, int *running_handles);
+extern CURLMcode (*qcurl_multi_cleanup)(CURLM *multi_handle);
+extern CURLMsg* (*qcurl_multi_info_read)(CURLM *multi_handle, int *msgs_in_queue);
+extern const char* (*qcurl_multi_strerror)(CURLMcode);
+extern struct curl_slist* (*qcurl_slist_append)(struct curl_slist *, const char *);
+extern void (*qcurl_slist_free_all)(struct curl_slist *);
+extern CURLcode (*qcurl_global_init)(long flags);
+extern void (*qcurl_global_cleanup)(void);
+
+#else
+#define qcurl_version curl_version
+#define qcurl_easy_init curl_easy_init
+#define qcurl_easy_setopt curl_easy_setopt
+#define qcurl_easy_perform curl_easy_perform
+#define qcurl_easy_cleanup curl_easy_cleanup
+#define qcurl_easy_getinfo curl_easy_getinfo
+#define qcurl_easy_duphandle curl_easy_duphandle
+#define qcurl_easy_reset curl_easy_reset
+#define qcurl_easy_strerror curl_easy_strerror
+#define qcurl_multi_init curl_multi_init
+#define qcurl_multi_add_handle curl_multi_add_handle
+#define qcurl_multi_remove_handle curl_multi_remove_handle
+#define qcurl_multi_fdset curl_multi_fdset
+#define qcurl_multi_perform curl_multi_perform
+#define qcurl_multi_cleanup curl_multi_cleanup
+#define qcurl_multi_info_read curl_multi_info_read
+#define qcurl_multi_strerror curl_multi_strerror
+#define qcurl_slist_append curl_slist_append
+#define qcurl_slist_free_all curl_slist_free_all
+#define qcurl_global_init curl_global_init
+#define qcurl_global_cleanup curl_global_cleanup
+#endif
+
+bool CL_cURL_Init( void );
+void CL_cURL_Shutdown( void );
+void CL_cURL_BeginDownload( const char *localName, const char *remoteURL );
+void CL_cURL_PerformDownload( void );
+void CL_cURL_Cleanup( void );
+
+#endif // __QCURL_H__
diff --git a/src/client/cl_input.cpp b/src/client/cl_input.cpp
new file mode 100644
index 0000000..e134646
--- /dev/null
+++ b/src/client/cl_input.cpp
@@ -0,0 +1,1194 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// cl.input.c -- builds an intended movement command to send to the server
+
+#include "client.h"
+
+unsigned frame_msec;
+int old_com_frameTime;
+
+/*
+===============================================================================
+
+KEY BUTTONS
+
+Continuous button event tracking is complicated by the fact that two different
+input sources (say, mouse button 1 and the control key) can both press the
+same button, but the button should only be released when both of the
+pressing key have been released.
+
+When a key event issues a button command (+forward, +attack, etc), it appends
+its key number as argv(1) so it can be matched up with the release.
+
+argv(2) will be set to the time the event happened, which allows exact
+control even at low framerates when the down and up events may both get qued
+at the same time.
+
+===============================================================================
+*/
+
+kbutton_t in_left, in_right, in_forward, in_back;
+kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
+kbutton_t in_strafe, in_speed;
+kbutton_t in_up, in_down;
+
+#ifdef USE_VOIP
+kbutton_t in_voiprecord;
+#endif
+
+kbutton_t in_buttons[16];
+
+bool in_mlooking;
+
+static void IN_CenterView(void)
+{
+ cl.viewangles[PITCH] = -SHORT2ANGLE( (clc.netchan.alternateProtocol == 2
+ ? cl.snap.alternatePs.delta_angles
+ : cl.snap.ps.delta_angles)[PITCH] );
+}
+
+static void IN_MLookDown(void)
+{
+ in_mlooking = true;
+}
+
+static void IN_MLookUp(void)
+{
+ in_mlooking = false;
+ if (!cl_freelook->integer)
+ {
+ IN_CenterView();
+ }
+}
+
+static void IN_KeyDown(kbutton_t *b)
+{
+ int k;
+
+ const char *c = Cmd_Argv(1);
+ if (c[0])
+ {
+ k = atoi(c);
+ }
+ else
+ {
+ k = -1; // typed manually at the console for continuous down
+ }
+
+ if (k == b->down[0] || k == b->down[1])
+ {
+ return; // repeating key
+ }
+
+ if (!b->down[0])
+ {
+ b->down[0] = k;
+ }
+ else if (!b->down[1])
+ {
+ b->down[1] = k;
+ }
+ else
+ {
+ Com_Printf("Three keys down for a button!\n");
+ return;
+ }
+
+ if (b->active)
+ {
+ return; // still down
+ }
+
+ // save timestamp for partial frame summing
+ c = Cmd_Argv(2);
+ b->downtime = atoi(c);
+
+ b->active = true;
+ b->wasPressed = true;
+}
+
+static void IN_KeyUp(kbutton_t *b)
+{
+ int k;
+ unsigned uptime;
+
+ const char *c = Cmd_Argv(1);
+ if (c[0])
+ {
+ k = atoi(c);
+ }
+ else
+ {
+ // typed manually at the console, assume for unsticking, so clear all
+ b->down[0] = b->down[1] = 0;
+ b->active = false;
+ return;
+ }
+
+ if (b->down[0] == k)
+ {
+ b->down[0] = 0;
+ }
+ else if (b->down[1] == k)
+ {
+ b->down[1] = 0;
+ }
+ else
+ {
+ return; // key up without coresponding down (menu pass through)
+ }
+ if (b->down[0] || b->down[1])
+ {
+ return; // some other key is still holding it down
+ }
+
+ b->active = false;
+
+ // save timestamp for partial frame summing
+ c = Cmd_Argv(2);
+ uptime = atoi(c);
+ if (uptime)
+ {
+ b->msec += uptime - b->downtime;
+ }
+ else
+ {
+ b->msec += frame_msec / 2;
+ }
+
+ b->active = false;
+}
+
+/*
+===============
+CL_KeyState
+
+Returns the fraction of the frame that the key was down
+===============
+*/
+static float CL_KeyState(kbutton_t *key)
+{
+ float val;
+ int msec;
+
+ msec = key->msec;
+ key->msec = 0;
+
+ if (key->active)
+ {
+ // still down
+ if (!key->downtime)
+ {
+ msec = com_frameTime;
+ }
+ else
+ {
+ msec += com_frameTime - key->downtime;
+ }
+ key->downtime = com_frameTime;
+ }
+
+#if 0
+ if (msec) {
+ Com_Printf ("%i ", msec);
+ }
+#endif
+
+ val = (float)msec / frame_msec;
+ if (val < 0)
+ {
+ val = 0;
+ }
+ if (val > 1)
+ {
+ val = 1;
+ }
+
+ return val;
+}
+
+static void IN_UpDown(void) { IN_KeyDown(&in_up); }
+static void IN_UpUp(void) { IN_KeyUp(&in_up); }
+static void IN_DownDown(void) { IN_KeyDown(&in_down); }
+static void IN_DownUp(void) { IN_KeyUp(&in_down); }
+static void IN_LeftDown(void) { IN_KeyDown(&in_left); }
+static void IN_LeftUp(void) { IN_KeyUp(&in_left); }
+static void IN_RightDown(void) { IN_KeyDown(&in_right); }
+static void IN_RightUp(void) { IN_KeyUp(&in_right); }
+static void IN_ForwardDown(void) { IN_KeyDown(&in_forward); }
+static void IN_ForwardUp(void) { IN_KeyUp(&in_forward); }
+static void IN_BackDown(void) { IN_KeyDown(&in_back); }
+static void IN_BackUp(void) { IN_KeyUp(&in_back); }
+static void IN_LookupDown(void) { IN_KeyDown(&in_lookup); }
+static void IN_LookupUp(void) { IN_KeyUp(&in_lookup); }
+static void IN_LookdownDown(void) { IN_KeyDown(&in_lookdown); }
+static void IN_LookdownUp(void) { IN_KeyUp(&in_lookdown); }
+static void IN_MoveleftDown(void) { IN_KeyDown(&in_moveleft); }
+static void IN_MoveleftUp(void) { IN_KeyUp(&in_moveleft); }
+static void IN_MoverightDown(void) { IN_KeyDown(&in_moveright); }
+static void IN_MoverightUp(void) { IN_KeyUp(&in_moveright); }
+static void IN_SpeedDown(void) { IN_KeyDown(&in_speed); }
+static void IN_SpeedUp(void) { IN_KeyUp(&in_speed); }
+static void IN_StrafeDown(void) { IN_KeyDown(&in_strafe); }
+static void IN_StrafeUp(void) { IN_KeyUp(&in_strafe); }
+
+#ifdef USE_VOIP
+static void IN_VoipRecordDown(void)
+{
+ IN_KeyDown(&in_voiprecord);
+ Cvar_Set("cl_voipSend", "1");
+}
+
+static void IN_VoipRecordUp(void)
+{
+ IN_KeyUp(&in_voiprecord);
+ Cvar_Set("cl_voipSend", "0");
+}
+#endif
+
+static void IN_Button0Down(void) { IN_KeyDown(&in_buttons[0]); }
+static void IN_Button0Up(void) { IN_KeyUp(&in_buttons[0]); }
+static void IN_Button1Down(void) { IN_KeyDown(&in_buttons[1]); }
+static void IN_Button1Up(void) { IN_KeyUp(&in_buttons[1]); }
+static void IN_Button2Down(void) { IN_KeyDown(&in_buttons[2]); }
+static void IN_Button2Up(void) { IN_KeyUp(&in_buttons[2]); }
+static void IN_Button3Down(void) { IN_KeyDown(&in_buttons[3]); }
+static void IN_Button3Up(void) { IN_KeyUp(&in_buttons[3]); }
+static void IN_Button4Down(void) { IN_KeyDown(&in_buttons[4]); }
+static void IN_Button4Up(void) { IN_KeyUp(&in_buttons[4]); }
+static void IN_Button5Down(void) { IN_KeyDown(&in_buttons[5]); }
+static void IN_Button5Up(void) { IN_KeyUp(&in_buttons[5]); }
+static void IN_Button6Down(void) { IN_KeyDown(&in_buttons[6]); }
+static void IN_Button6Up(void) { IN_KeyUp(&in_buttons[6]); }
+static void IN_Button7Down(void) { IN_KeyDown(&in_buttons[7]); }
+static void IN_Button7Up(void) { IN_KeyUp(&in_buttons[7]); }
+static void IN_Button8Down(void) { IN_KeyDown(&in_buttons[8]); }
+static void IN_Button8Up(void) { IN_KeyUp(&in_buttons[8]); }
+static void IN_Button9Down(void) { IN_KeyDown(&in_buttons[9]); }
+static void IN_Button9Up(void) { IN_KeyUp(&in_buttons[9]); }
+static void IN_Button10Down(void) { IN_KeyDown(&in_buttons[10]); }
+static void IN_Button10Up(void) { IN_KeyUp(&in_buttons[10]); }
+static void IN_Button11Down(void) { IN_KeyDown(&in_buttons[11]); }
+static void IN_Button11Up(void) { IN_KeyUp(&in_buttons[11]); }
+static void IN_Button12Down(void) { IN_KeyDown(&in_buttons[12]); }
+static void IN_Button12Up(void) { IN_KeyUp(&in_buttons[12]); }
+static void IN_Button13Down(void) { IN_KeyDown(&in_buttons[13]); }
+static void IN_Button13Up(void) { IN_KeyUp(&in_buttons[13]); }
+static void IN_Button14Down(void) { IN_KeyDown(&in_buttons[14]); }
+static void IN_Button14Up(void) { IN_KeyUp(&in_buttons[14]); }
+static void IN_Button15Down(void) { IN_KeyDown(&in_buttons[15]); }
+static void IN_Button15Up(void) { IN_KeyUp(&in_buttons[15]); }
+
+//==========================================================================
+
+cvar_t *cl_yawspeed;
+cvar_t *cl_pitchspeed;
+
+cvar_t *cl_run;
+
+cvar_t *cl_anglespeedkey;
+
+/*
+================
+CL_AdjustAngles
+
+Moves the local angle positions
+================
+*/
+static void CL_AdjustAngles(void)
+{
+ float speed;
+
+ if (in_speed.active)
+ {
+ speed = 0.001 * cls.frametime * cl_anglespeedkey->value;
+ }
+ else
+ {
+ speed = 0.001 * cls.frametime;
+ }
+
+ if (!in_strafe.active)
+ {
+ cl.viewangles[YAW] -= speed * cl_yawspeed->value * CL_KeyState(&in_right);
+ cl.viewangles[YAW] += speed * cl_yawspeed->value * CL_KeyState(&in_left);
+ }
+
+ cl.viewangles[PITCH] -= speed * cl_pitchspeed->value * CL_KeyState(&in_lookup);
+ cl.viewangles[PITCH] += speed * cl_pitchspeed->value * CL_KeyState(&in_lookdown);
+}
+
+/*
+================
+CL_KeyMove
+
+Sets the usercmd_t based on key states
+================
+*/
+static void CL_KeyMove(usercmd_t *cmd)
+{
+ int movespeed;
+ int forward, side, up;
+
+ //
+ // adjust for speed key / running
+ // the walking flag is to keep animations consistant
+ // even during acceleration and develeration
+ //
+ if (in_speed.active ^ cl_run->integer)
+ {
+ movespeed = 127;
+ cmd->buttons &= ~BUTTON_WALKING;
+ }
+ else
+ {
+ cmd->buttons |= BUTTON_WALKING;
+ movespeed = 64;
+ }
+
+ forward = 0;
+ side = 0;
+ up = 0;
+ if (in_strafe.active)
+ {
+ side += movespeed * CL_KeyState(&in_right);
+ side -= movespeed * CL_KeyState(&in_left);
+ }
+
+ side += movespeed * CL_KeyState(&in_moveright);
+ side -= movespeed * CL_KeyState(&in_moveleft);
+
+ up += movespeed * CL_KeyState(&in_up);
+ up -= movespeed * CL_KeyState(&in_down);
+
+ forward += movespeed * CL_KeyState(&in_forward);
+ forward -= movespeed * CL_KeyState(&in_back);
+
+ cmd->forwardmove = ClampChar(forward);
+ cmd->rightmove = ClampChar(side);
+ cmd->upmove = ClampChar(up);
+}
+
+/*
+=================
+CL_MouseEvent
+=================
+*/
+void CL_MouseEvent(int dx, int dy, int time)
+{
+ if (Key_GetCatcher() & KEYCATCH_UI)
+ {
+ VM_Call(cls.ui, UI_MOUSE_EVENT, dx, dy);
+ }
+ else if (Key_GetCatcher() & KEYCATCH_CGAME)
+ {
+ VM_Call(cls.cgame, CG_MOUSE_EVENT, dx, dy);
+ }
+ else
+ {
+ cl.mouseDx[cl.mouseIndex] += dx;
+ cl.mouseDy[cl.mouseIndex] += dy;
+ }
+}
+
+/*
+=================
+CL_JoystickEvent
+
+Joystick values stay set until changed
+=================
+*/
+void CL_JoystickEvent(int axis, int value, int time)
+{
+ if (axis < 0 || axis >= MAX_JOYSTICK_AXIS)
+ {
+ Com_Error(ERR_DROP, "CL_JoystickEvent: bad axis %i", axis);
+ }
+ cl.joystickAxis[axis] = value;
+}
+
+/*
+=================
+CL_JoystickMove
+=================
+*/
+static void CL_JoystickMove(usercmd_t *cmd)
+{
+ float anglespeed;
+
+ float yaw = j_yaw->value * cl.joystickAxis[j_yaw_axis->integer];
+ float right = j_side->value * cl.joystickAxis[j_side_axis->integer];
+ float forward = j_forward->value * cl.joystickAxis[j_forward_axis->integer];
+ float pitch = j_pitch->value * cl.joystickAxis[j_pitch_axis->integer];
+ float up = j_up->value * cl.joystickAxis[j_up_axis->integer];
+
+ if (!(in_speed.active ^ cl_run->integer))
+ {
+ cmd->buttons |= BUTTON_WALKING;
+ }
+
+ if (in_speed.active)
+ {
+ anglespeed = 0.001 * cls.frametime * cl_anglespeedkey->value;
+ }
+ else
+ {
+ anglespeed = 0.001 * cls.frametime;
+ }
+
+ if (!in_strafe.active)
+ {
+ cl.viewangles[YAW] += anglespeed * yaw;
+ cmd->rightmove = ClampChar(cmd->rightmove + (int)right);
+ }
+ else
+ {
+ cl.viewangles[YAW] += anglespeed * right;
+ cmd->rightmove = ClampChar(cmd->rightmove + (int)yaw);
+ }
+
+ if (in_mlooking)
+ {
+ cl.viewangles[PITCH] += anglespeed * forward;
+ cmd->forwardmove = ClampChar(cmd->forwardmove + (int)pitch);
+ }
+ else
+ {
+ cl.viewangles[PITCH] += anglespeed * pitch;
+ cmd->forwardmove = ClampChar(cmd->forwardmove + (int)forward);
+ }
+
+ cmd->upmove = ClampChar(cmd->upmove + (int)up);
+}
+
+/*
+=================
+CL_MouseMove
+=================
+*/
+
+static void CL_MouseMove(usercmd_t *cmd)
+{
+ float mx, my;
+
+ // allow mouse smoothing
+ if (m_filter->integer)
+ {
+ mx = (cl.mouseDx[0] + cl.mouseDx[1]) * 0.5f;
+ my = (cl.mouseDy[0] + cl.mouseDy[1]) * 0.5f;
+ }
+ else
+ {
+ mx = cl.mouseDx[cl.mouseIndex];
+ my = cl.mouseDy[cl.mouseIndex];
+ }
+
+ cl.mouseIndex ^= 1;
+ cl.mouseDx[cl.mouseIndex] = 0;
+ cl.mouseDy[cl.mouseIndex] = 0;
+
+ if (mx == 0.0f && my == 0.0f) return;
+
+ if (cl_mouseAccel->value != 0.0f)
+ {
+ if (cl_mouseAccelStyle->integer == 0)
+ {
+ float accelSensitivity;
+ float rate;
+
+ rate = sqrt(mx * mx + my * my) / (float)frame_msec;
+
+ accelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value;
+ mx *= accelSensitivity;
+ my *= accelSensitivity;
+
+ if (cl_showMouseRate->integer) Com_Printf("rate: %f, accelSensitivity: %f\n", rate, accelSensitivity);
+ }
+ else
+ {
+ float rate[2];
+ float power[2];
+
+ // sensitivity remains pretty much unchanged at low speeds
+ // cl_mouseAccel is a power value to how the acceleration is shaped
+ // cl_mouseAccelOffset is the rate for which the acceleration will have doubled the non accelerated
+ // amplification
+ // NOTE: decouple the config cvars for independent acceleration setup along X and Y?
+
+ rate[0] = fabs(mx) / (float)frame_msec;
+ rate[1] = fabs(my) / (float)frame_msec;
+ power[0] = powf(rate[0] / cl_mouseAccelOffset->value, cl_mouseAccel->value);
+ power[1] = powf(rate[1] / cl_mouseAccelOffset->value, cl_mouseAccel->value);
+
+ mx = cl_sensitivity->value * (mx + ((mx < 0) ? -power[0] : power[0]) * cl_mouseAccelOffset->value);
+ my = cl_sensitivity->value * (my + ((my < 0) ? -power[1] : power[1]) * cl_mouseAccelOffset->value);
+
+ if (cl_showMouseRate->integer)
+ Com_Printf("ratex: %f, ratey: %f, powx: %f, powy: %f\n", rate[0], rate[1], power[0], power[1]);
+ }
+ }
+ else
+ {
+ mx *= cl_sensitivity->value;
+ my *= cl_sensitivity->value;
+ }
+
+ // ingame FOV
+ mx *= cl.cgameSensitivity;
+ my *= cl.cgameSensitivity;
+
+ // add mouse X/Y movement to cmd
+ if (in_strafe.active)
+ cmd->rightmove = ClampChar(cmd->rightmove + m_side->value * mx);
+ else
+ cl.viewangles[YAW] -= m_yaw->value * mx;
+
+ if ((in_mlooking || cl_freelook->integer) && !in_strafe.active)
+ cl.viewangles[PITCH] += m_pitch->value * my;
+ else
+ cmd->forwardmove = ClampChar(cmd->forwardmove - m_forward->value * my);
+}
+
+/*
+==============
+CL_CmdButtons
+==============
+*/
+static void CL_CmdButtons(usercmd_t *cmd)
+{
+ int i;
+
+ //
+ // figure button bits
+ // send a button bit even if the key was pressed and released in
+ // less than a frame
+ //
+ for (i = 0; i < 15; i++)
+ {
+ if (in_buttons[i].active || in_buttons[i].wasPressed)
+ {
+ cmd->buttons |= 1 << i;
+ }
+ in_buttons[i].wasPressed = false;
+ }
+
+ if (Key_GetCatcher())
+ {
+ cmd->buttons |= BUTTON_TALK;
+ }
+
+ // allow the game to know if any key at all is
+ // currently pressed, even if it isn't bound to anything
+ if (anykeydown && Key_GetCatcher() == 0)
+ {
+ cmd->buttons |= BUTTON_ANY;
+ }
+}
+
+/*
+==============
+CL_FinishMove
+==============
+*/
+static void CL_FinishMove(usercmd_t *cmd)
+{
+ int i;
+
+ // copy the state that the cgame is currently sending
+ cmd->weapon = cl.cgameUserCmdValue;
+
+ // send the current server time so the amount of movement
+ // can be determined without allowing cheating
+ cmd->serverTime = cl.serverTime;
+
+ for (i = 0; i < 3; i++)
+ {
+ cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
+ }
+}
+
+/*
+=================
+CL_CreateCmd
+=================
+*/
+static usercmd_t CL_CreateCmd(void)
+{
+ usercmd_t cmd;
+ vec3_t oldAngles;
+
+ VectorCopy(cl.viewangles, oldAngles);
+
+ // keyboard angle adjustment
+ CL_AdjustAngles();
+
+ ::memset(&cmd, 0, sizeof(cmd));
+
+ CL_CmdButtons(&cmd);
+
+ // get basic movement from keyboard
+ CL_KeyMove(&cmd);
+
+ // get basic movement from mouse
+ CL_MouseMove(&cmd);
+
+ // get basic movement from joystick
+ CL_JoystickMove(&cmd);
+
+ // check to make sure the angles haven't wrapped
+ if (cl.viewangles[PITCH] - oldAngles[PITCH] > 90)
+ {
+ cl.viewangles[PITCH] = oldAngles[PITCH] + 90;
+ }
+ else if (oldAngles[PITCH] - cl.viewangles[PITCH] > 90)
+ {
+ cl.viewangles[PITCH] = oldAngles[PITCH] - 90;
+ }
+
+ // store out the final values
+ CL_FinishMove(&cmd);
+
+ // draw debug graphs of turning for mouse testing
+ if (cl_debugMove->integer)
+ {
+ if (cl_debugMove->integer == 1)
+ {
+ SCR_DebugGraph(fabs(cl.viewangles[YAW] - oldAngles[YAW]));
+ }
+ if (cl_debugMove->integer == 2)
+ {
+ SCR_DebugGraph(fabs(cl.viewangles[PITCH] - oldAngles[PITCH]));
+ }
+ }
+
+ return cmd;
+}
+
+/*
+=================
+CL_CreateNewCommands
+
+Create a new usercmd_t structure for this frame
+=================
+*/
+static void CL_CreateNewCommands(void)
+{
+ int cmdNum;
+
+ // no need to create usercmds until we have a gamestate
+ if (clc.state < CA_PRIMED)
+ {
+ return;
+ }
+
+ frame_msec = com_frameTime - old_com_frameTime;
+
+ // if running over 1000fps, act as if each frame is 1ms
+ // prevents divisions by zero
+ if (frame_msec < 1)
+ {
+ frame_msec = 1;
+ }
+
+ // if running less than 5fps, truncate the extra time to prevent
+ // unexpected moves after a hitch
+ if (frame_msec > 200)
+ {
+ frame_msec = 200;
+ }
+ old_com_frameTime = com_frameTime;
+
+ // generate a command for this frame
+ cl.cmdNumber++;
+ cmdNum = cl.cmdNumber & CMD_MASK;
+ cl.cmds[cmdNum] = CL_CreateCmd();
+}
+
+/*
+=================
+CL_ReadyToSendPacket
+
+Returns false if we are over the maxpackets limit
+and should choke back the bandwidth a bit by not sending
+a packet this frame. All the commands will still get
+delivered in the next packet, but saving a header and
+getting more delta compression will reduce total bandwidth.
+=================
+*/
+static bool CL_ReadyToSendPacket(void)
+{
+ int oldPacketNum;
+ int delta;
+
+ // don't send anything if playing back a demo
+ if (clc.demoplaying || clc.state == CA_CINEMATIC)
+ {
+ return false;
+ }
+
+ // If we are downloading, we send no less than 50ms between packets
+ if (*clc.downloadTempName && cls.realtime - clc.lastPacketSentTime < 50)
+ {
+ return false;
+ }
+
+ // if we don't have a valid gamestate yet, only send
+ // one packet a second
+ if (clc.state != CA_ACTIVE && clc.state != CA_PRIMED && !*clc.downloadTempName &&
+ cls.realtime - clc.lastPacketSentTime < 1000)
+ {
+ return false;
+ }
+
+ // send every frame for loopbacks
+ if (clc.netchan.remoteAddress.type == NA_LOOPBACK)
+ {
+ return true;
+ }
+
+ // send every frame for LAN
+ if (cl_lanForcePackets->integer && Sys_IsLANAddress(clc.netchan.remoteAddress))
+ {
+ return true;
+ }
+
+ // check for exceeding cl_maxpackets
+ if (cl_maxpackets->integer < 15)
+ {
+ Cvar_Set("cl_maxpackets", "15");
+ }
+ else if (cl_maxpackets->integer > 125)
+ {
+ Cvar_Set("cl_maxpackets", "125");
+ }
+ oldPacketNum = (clc.netchan.outgoingSequence - 1) & PACKET_MASK;
+ delta = cls.realtime - cl.outPackets[oldPacketNum].p_realtime;
+ if (delta < 1000 / cl_maxpackets->integer)
+ {
+ // the accumulated commands will go out in the next packet
+ return false;
+ }
+
+ return true;
+}
+
+/*
+===================
+CL_WritePacket
+
+Create and send the command packet to the server
+Including both the reliable commands and the usercmds
+
+During normal gameplay, a client packet will contain something like:
+
+4 sequence number
+2 qport
+4 serverid
+4 acknowledged sequence number
+4 clc.serverCommandSequence
+<optional reliable commands>
+1 clc_move or clc_moveNoDelta
+1 command count
+<count * usercmds>
+
+===================
+*/
+void CL_WritePacket(void)
+{
+ msg_t buf;
+ byte data[MAX_MSGLEN];
+ int i, j;
+ usercmd_t *cmd, *oldcmd;
+ usercmd_t nullcmd;
+ int packetNum;
+ int oldPacketNum;
+ int count, key;
+
+ // don't send anything if playing back a demo
+ if (clc.demoplaying || clc.state == CA_CINEMATIC)
+ {
+ return;
+ }
+
+ ::memset(&nullcmd, 0, sizeof(nullcmd));
+ oldcmd = &nullcmd;
+
+ MSG_Init(&buf, data, sizeof(data));
+
+ MSG_Bitstream(&buf);
+ // write the current serverId so the server
+ // can tell if this is from the current gameState
+ MSG_WriteLong(&buf, cl.serverId);
+
+ // write the last message we received, which can
+ // be used for delta compression, and is also used
+ // to tell if we dropped a gamestate
+ MSG_WriteLong(&buf, clc.serverMessageSequence);
+
+ // write the last reliable message we received
+ MSG_WriteLong(&buf, clc.serverCommandSequence);
+
+ // write any unacknowledged clientCommands
+ for (i = clc.reliableAcknowledge + 1; i <= clc.reliableSequence; i++)
+ {
+ MSG_WriteByte(&buf, clc_clientCommand);
+ MSG_WriteLong(&buf, i);
+ MSG_WriteString(&buf, clc.reliableCommands[i & (MAX_RELIABLE_COMMANDS - 1)]);
+ }
+
+ // we want to send all the usercmds that were generated in the last
+ // few packet, so even if a couple packets are dropped in a row,
+ // all the cmds will make it to the server
+ if (cl_packetdup->integer < 0)
+ {
+ Cvar_Set("cl_packetdup", "0");
+ }
+ else if (cl_packetdup->integer > 5)
+ {
+ Cvar_Set("cl_packetdup", "5");
+ }
+ oldPacketNum = (clc.netchan.outgoingSequence - 1 - cl_packetdup->integer) & PACKET_MASK;
+ count = cl.cmdNumber - cl.outPackets[oldPacketNum].p_cmdNumber;
+ if (count > MAX_PACKET_USERCMDS)
+ {
+ count = MAX_PACKET_USERCMDS;
+ Com_Printf("MAX_PACKET_USERCMDS\n");
+ }
+
+#ifdef USE_VOIP
+ if (clc.voipOutgoingDataSize > 0)
+ {
+ if ((clc.voipFlags & VOIP_SPATIAL) || Com_IsVoipTarget(clc.voipTargets, sizeof(clc.voipTargets), -1))
+ {
+ if (clc.netchan.alternateProtocol != 0)
+ {
+ MSG_WriteByte(&buf, clc_EOF);
+ }
+ MSG_WriteByte(&buf, clc_voipSpeex);
+ if (clc.netchan.alternateProtocol != 0)
+ {
+ MSG_WriteByte(&buf, clc_voipSpeex + 1);
+ }
+ MSG_WriteByte(&buf, clc.voipOutgoingGeneration);
+ MSG_WriteLong(&buf, clc.voipOutgoingSequence);
+ MSG_WriteByte(&buf, clc.voipOutgoingDataFrames);
+ if (clc.netchan.alternateProtocol == 0)
+ {
+ MSG_WriteData(&buf, clc.voipTargets, sizeof(clc.voipTargets));
+ MSG_WriteByte(&buf, clc.voipFlags);
+ }
+ else
+ {
+ MSG_WriteLong(&buf, clc.voipTargets[0] | (clc.voipTargets[1] << 8) | (clc.voipTargets[2] << 16) |
+ ((clc.voipTargets[3] & 0x7F) << 24));
+ MSG_WriteLong(&buf, (clc.voipTargets[3] >> 7) | (clc.voipTargets[4] << 1) | (clc.voipTargets[5] << 9) |
+ (clc.voipTargets[6] << 17) | ((clc.voipTargets[7] & 0x3F) << 25));
+ MSG_WriteLong(&buf, clc.voipTargets[7] >> 6);
+ }
+ MSG_WriteShort(&buf, clc.voipOutgoingDataSize);
+ MSG_WriteData(&buf, clc.voipOutgoingData, clc.voipOutgoingDataSize);
+
+ // If we're recording a demo, we have to fake a server packet with
+ // this VoIP data so it gets to disk; the server doesn't send it
+ // back to us, and we might as well eliminate concerns about dropped
+ // and misordered packets here.
+ if (clc.demorecording && !clc.demowaiting)
+ {
+ const int voipSize = clc.voipOutgoingDataSize;
+ msg_t fakemsg;
+ byte fakedata[MAX_MSGLEN];
+ MSG_Init(&fakemsg, fakedata, sizeof(fakedata));
+ MSG_Bitstream(&fakemsg);
+ MSG_WriteLong(&fakemsg, clc.reliableAcknowledge);
+ MSG_WriteByte(&fakemsg, svc_voipOpus);
+ MSG_WriteShort(&fakemsg, clc.clientNum);
+ MSG_WriteByte(&fakemsg, clc.voipOutgoingGeneration);
+ MSG_WriteLong(&fakemsg, clc.voipOutgoingSequence);
+ MSG_WriteByte(&fakemsg, clc.voipOutgoingDataFrames);
+ MSG_WriteShort(&fakemsg, clc.voipOutgoingDataSize);
+ if (clc.netchan.alternateProtocol == 0)
+ {
+ MSG_WriteBits(&fakemsg, clc.voipFlags, VOIP_FLAGCNT);
+ }
+ MSG_WriteData(&fakemsg, clc.voipOutgoingData, voipSize);
+ MSG_WriteByte(&fakemsg, svc_EOF);
+ CL_WriteDemoMessage(&fakemsg, 0);
+ }
+
+ clc.voipOutgoingSequence += clc.voipOutgoingDataFrames;
+ clc.voipOutgoingDataSize = 0;
+ clc.voipOutgoingDataFrames = 0;
+ }
+ else
+ {
+ // We have data, but no targets. Silently discard all data
+ clc.voipOutgoingDataSize = 0;
+ clc.voipOutgoingDataFrames = 0;
+ }
+ }
+#endif
+
+ if (count >= 1)
+ {
+ if (cl_showSend->integer)
+ {
+ Com_Printf("(%i)", count);
+ }
+
+ // begin a client move command
+ if (cl_nodelta->integer || !cl.snap.valid || clc.demowaiting || clc.serverMessageSequence != cl.snap.messageNum)
+ {
+ MSG_WriteByte(&buf, clc_moveNoDelta);
+ }
+ else
+ {
+ MSG_WriteByte(&buf, clc_move);
+ }
+
+ // write the command count
+ MSG_WriteByte(&buf, count);
+
+ // use the checksum feed in the key
+ key = clc.checksumFeed;
+ // also use the message acknowledge
+ key ^= clc.serverMessageSequence;
+ // also use the last acknowledged server command in the key
+ key ^= MSG_HashKey(clc.netchan.alternateProtocol,
+ clc.serverCommands[clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS - 1)], 32);
+
+ // write all the commands, including the predicted command
+ for (i = 0; i < count; i++)
+ {
+ j = (cl.cmdNumber - count + i + 1) & CMD_MASK;
+ cmd = &cl.cmds[j];
+ MSG_WriteDeltaUsercmdKey(&buf, key, oldcmd, cmd);
+ oldcmd = cmd;
+ }
+ }
+
+ //
+ // deliver the message
+ //
+ packetNum = clc.netchan.outgoingSequence & PACKET_MASK;
+ cl.outPackets[packetNum].p_realtime = cls.realtime;
+ cl.outPackets[packetNum].p_serverTime = oldcmd->serverTime;
+ cl.outPackets[packetNum].p_cmdNumber = cl.cmdNumber;
+ clc.lastPacketSentTime = cls.realtime;
+
+ if (cl_showSend->integer)
+ {
+ Com_Printf("%i ", buf.cursize);
+ }
+
+ CL_Netchan_Transmit(&clc.netchan, &buf);
+}
+
+/*
+=================
+CL_SendCmd
+
+Called every frame to builds and sends a command packet to the server.
+=================
+*/
+void CL_SendCmd(void)
+{
+ // don't send any message if not connected
+ if (clc.state < CA_CONNECTED)
+ {
+ return;
+ }
+
+ // don't send commands if paused
+ if (com_sv_running->integer && sv_paused->integer && cl_paused->integer)
+ {
+ return;
+ }
+
+ // we create commands even if a demo is playing,
+ CL_CreateNewCommands();
+
+ // don't send a packet if the last packet was sent too recently
+ if (!CL_ReadyToSendPacket())
+ {
+ if (cl_showSend->integer)
+ {
+ Com_Printf(". ");
+ }
+ return;
+ }
+
+ CL_WritePacket();
+}
+
+/*
+============
+CL_InitInput
+============
+*/
+void CL_InitInput(void)
+{
+ Cmd_AddCommand("centerview", IN_CenterView);
+
+ Cmd_AddCommand("+moveup", IN_UpDown);
+ Cmd_AddCommand("-moveup", IN_UpUp);
+ Cmd_AddCommand("+movedown", IN_DownDown);
+ Cmd_AddCommand("-movedown", IN_DownUp);
+ Cmd_AddCommand("+left", IN_LeftDown);
+ Cmd_AddCommand("-left", IN_LeftUp);
+ Cmd_AddCommand("+right", IN_RightDown);
+ Cmd_AddCommand("-right", IN_RightUp);
+ Cmd_AddCommand("+forward", IN_ForwardDown);
+ Cmd_AddCommand("-forward", IN_ForwardUp);
+ Cmd_AddCommand("+back", IN_BackDown);
+ Cmd_AddCommand("-back", IN_BackUp);
+ Cmd_AddCommand("+lookup", IN_LookupDown);
+ Cmd_AddCommand("-lookup", IN_LookupUp);
+ Cmd_AddCommand("+lookdown", IN_LookdownDown);
+ Cmd_AddCommand("-lookdown", IN_LookdownUp);
+ Cmd_AddCommand("+strafe", IN_StrafeDown);
+ Cmd_AddCommand("-strafe", IN_StrafeUp);
+ Cmd_AddCommand("+moveleft", IN_MoveleftDown);
+ Cmd_AddCommand("-moveleft", IN_MoveleftUp);
+ Cmd_AddCommand("+moveright", IN_MoverightDown);
+ Cmd_AddCommand("-moveright", IN_MoverightUp);
+ Cmd_AddCommand("+speed", IN_SpeedDown);
+ Cmd_AddCommand("-speed", IN_SpeedUp);
+ Cmd_AddCommand("+attack", IN_Button0Down);
+ Cmd_AddCommand("-attack", IN_Button0Up);
+ Cmd_AddCommand("+button0", IN_Button0Down);
+ Cmd_AddCommand("-button0", IN_Button0Up);
+ Cmd_AddCommand("+button1", IN_Button1Down);
+ Cmd_AddCommand("-button1", IN_Button1Up);
+ Cmd_AddCommand("+button2", IN_Button2Down);
+ Cmd_AddCommand("-button2", IN_Button2Up);
+ Cmd_AddCommand("+button3", IN_Button3Down);
+ Cmd_AddCommand("-button3", IN_Button3Up);
+ Cmd_AddCommand("+button4", IN_Button4Down);
+ Cmd_AddCommand("-button4", IN_Button4Up);
+ Cmd_AddCommand("+button5", IN_Button5Down);
+ Cmd_AddCommand("-button5", IN_Button5Up);
+ Cmd_AddCommand("+button6", IN_Button6Down);
+ Cmd_AddCommand("-button6", IN_Button6Up);
+ Cmd_AddCommand("+button7", IN_Button7Down);
+ Cmd_AddCommand("-button7", IN_Button7Up);
+ Cmd_AddCommand("+button8", IN_Button8Down);
+ Cmd_AddCommand("-button8", IN_Button8Up);
+ Cmd_AddCommand("+button9", IN_Button9Down);
+ Cmd_AddCommand("-button9", IN_Button9Up);
+ Cmd_AddCommand("+button10", IN_Button10Down);
+ Cmd_AddCommand("-button10", IN_Button10Up);
+ Cmd_AddCommand("+button11", IN_Button11Down);
+ Cmd_AddCommand("-button11", IN_Button11Up);
+ Cmd_AddCommand("+button12", IN_Button12Down);
+ Cmd_AddCommand("-button12", IN_Button12Up);
+ Cmd_AddCommand("+button13", IN_Button13Down);
+ Cmd_AddCommand("-button13", IN_Button13Up);
+ Cmd_AddCommand("+button14", IN_Button14Down);
+ Cmd_AddCommand("-button14", IN_Button14Up);
+ Cmd_AddCommand("+mlook", IN_MLookDown);
+ Cmd_AddCommand("-mlook", IN_MLookUp);
+
+#ifdef USE_VOIP
+ Cmd_AddCommand("+voiprecord", IN_VoipRecordDown);
+ Cmd_AddCommand("-voiprecord", IN_VoipRecordUp);
+#endif
+
+ cl_nodelta = Cvar_Get("cl_nodelta", "0", 0);
+ cl_debugMove = Cvar_Get("cl_debugMove", "0", 0);
+}
+
+/*
+============
+CL_ShutdownInput
+============
+*/
+void CL_ShutdownInput(void)
+{
+ Cmd_RemoveCommand("centerview");
+
+ Cmd_RemoveCommand("+moveup");
+ Cmd_RemoveCommand("-moveup");
+ Cmd_RemoveCommand("+movedown");
+ Cmd_RemoveCommand("-movedown");
+ Cmd_RemoveCommand("+left");
+ Cmd_RemoveCommand("-left");
+ Cmd_RemoveCommand("+right");
+ Cmd_RemoveCommand("-right");
+ Cmd_RemoveCommand("+forward");
+ Cmd_RemoveCommand("-forward");
+ Cmd_RemoveCommand("+back");
+ Cmd_RemoveCommand("-back");
+ Cmd_RemoveCommand("+lookup");
+ Cmd_RemoveCommand("-lookup");
+ Cmd_RemoveCommand("+lookdown");
+ Cmd_RemoveCommand("-lookdown");
+ Cmd_RemoveCommand("+strafe");
+ Cmd_RemoveCommand("-strafe");
+ Cmd_RemoveCommand("+moveleft");
+ Cmd_RemoveCommand("-moveleft");
+ Cmd_RemoveCommand("+moveright");
+ Cmd_RemoveCommand("-moveright");
+ Cmd_RemoveCommand("+speed");
+ Cmd_RemoveCommand("-speed");
+ Cmd_RemoveCommand("+attack");
+ Cmd_RemoveCommand("-attack");
+ Cmd_RemoveCommand("+button0");
+ Cmd_RemoveCommand("-button0");
+ Cmd_RemoveCommand("+button1");
+ Cmd_RemoveCommand("-button1");
+ Cmd_RemoveCommand("+button2");
+ Cmd_RemoveCommand("-button2");
+ Cmd_RemoveCommand("+button3");
+ Cmd_RemoveCommand("-button3");
+ Cmd_RemoveCommand("+button4");
+ Cmd_RemoveCommand("-button4");
+ Cmd_RemoveCommand("+button5");
+ Cmd_RemoveCommand("-button5");
+ Cmd_RemoveCommand("+button6");
+ Cmd_RemoveCommand("-button6");
+ Cmd_RemoveCommand("+button7");
+ Cmd_RemoveCommand("-button7");
+ Cmd_RemoveCommand("+button8");
+ Cmd_RemoveCommand("-button8");
+ Cmd_RemoveCommand("+button9");
+ Cmd_RemoveCommand("-button9");
+ Cmd_RemoveCommand("+button10");
+ Cmd_RemoveCommand("-button10");
+ Cmd_RemoveCommand("+button11");
+ Cmd_RemoveCommand("-button11");
+ Cmd_RemoveCommand("+button12");
+ Cmd_RemoveCommand("-button12");
+ Cmd_RemoveCommand("+button13");
+ Cmd_RemoveCommand("-button13");
+ Cmd_RemoveCommand("+button14");
+ Cmd_RemoveCommand("-button14");
+ Cmd_RemoveCommand("+mlook");
+ Cmd_RemoveCommand("-mlook");
+
+#ifdef USE_VOIP
+ Cmd_RemoveCommand("+voiprecord");
+ Cmd_RemoveCommand("-voiprecord");
+#endif
+}
diff --git a/src/client/cl_keys.cpp b/src/client/cl_keys.cpp
new file mode 100644
index 0000000..82f5666
--- /dev/null
+++ b/src/client/cl_keys.cpp
@@ -0,0 +1,1665 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "client.h"
+
+/*
+
+key up events are sent even if in console mode
+
+*/
+
+field_t historyEditLines[COMMAND_HISTORY];
+
+int nextHistoryLine; // the last line in the history buffer, not masked
+int historyLine; // the line being displayed from history buffer will be <= nextHistoryLine
+
+field_t g_consoleField;
+
+field_t chatField;
+bool chat_team;
+bool chat_admins;
+bool chat_clans;
+int chat_playerNum;
+
+bool key_overstrikeMode;
+
+int anykeydown;
+qkey_t keys[MAX_KEYS];
+
+struct keyname_t {
+ const char* name;
+ int keynum;
+};
+
+// names not in this list can either be lowercase ascii, or '0xnn' hex sequences
+keyname_t keynames[] =
+{
+ {"TAB", K_TAB},
+ {"ENTER", K_ENTER},
+ {"ESCAPE", K_ESCAPE},
+ {"SPACE", K_SPACE},
+ {"BACKSPACE", K_BACKSPACE},
+ {"UPARROW", K_UPARROW},
+ {"DOWNARROW", K_DOWNARROW},
+ {"LEFTARROW", K_LEFTARROW},
+ {"RIGHTARROW", K_RIGHTARROW},
+
+ {"ALT", K_ALT},
+ {"CTRL", K_CTRL},
+ {"SHIFT", K_SHIFT},
+
+ {"COMMAND", K_COMMAND},
+
+ {"CAPSLOCK", K_CAPSLOCK},
+
+ {"F1", K_F1},
+ {"F2", K_F2},
+ {"F3", K_F3},
+ {"F4", K_F4},
+ {"F5", K_F5},
+ {"F6", K_F6},
+ {"F7", K_F7},
+ {"F8", K_F8},
+ {"F9", K_F9},
+ {"F10", K_F10},
+ {"F11", K_F11},
+ {"F12", K_F12},
+ {"F13", K_F13},
+ {"F14", K_F14},
+ {"F15", K_F15},
+
+ {"INS", K_INS},
+ {"DEL", K_DEL},
+ {"PGDN", K_PGDN},
+ {"PGUP", K_PGUP},
+ {"HOME", K_HOME},
+ {"END", K_END},
+
+ {"MOUSE1", K_MOUSE1},
+ {"MOUSE2", K_MOUSE2},
+ {"MOUSE3", K_MOUSE3},
+ {"MOUSE4", K_MOUSE4},
+ {"MOUSE5", K_MOUSE5},
+
+ {"MWHEELUP", K_MWHEELUP },
+ {"MWHEELDOWN", K_MWHEELDOWN },
+
+ {"JOY1", K_JOY1},
+ {"JOY2", K_JOY2},
+ {"JOY3", K_JOY3},
+ {"JOY4", K_JOY4},
+ {"JOY5", K_JOY5},
+ {"JOY6", K_JOY6},
+ {"JOY7", K_JOY7},
+ {"JOY8", K_JOY8},
+ {"JOY9", K_JOY9},
+ {"JOY10", K_JOY10},
+ {"JOY11", K_JOY11},
+ {"JOY12", K_JOY12},
+ {"JOY13", K_JOY13},
+ {"JOY14", K_JOY14},
+ {"JOY15", K_JOY15},
+ {"JOY16", K_JOY16},
+ {"JOY17", K_JOY17},
+ {"JOY18", K_JOY18},
+ {"JOY19", K_JOY19},
+ {"JOY20", K_JOY20},
+ {"JOY21", K_JOY21},
+ {"JOY22", K_JOY22},
+ {"JOY23", K_JOY23},
+ {"JOY24", K_JOY24},
+ {"JOY25", K_JOY25},
+ {"JOY26", K_JOY26},
+ {"JOY27", K_JOY27},
+ {"JOY28", K_JOY28},
+ {"JOY29", K_JOY29},
+ {"JOY30", K_JOY30},
+ {"JOY31", K_JOY31},
+ {"JOY32", K_JOY32},
+
+ {"AUX1", K_AUX1},
+ {"AUX2", K_AUX2},
+ {"AUX3", K_AUX3},
+ {"AUX4", K_AUX4},
+ {"AUX5", K_AUX5},
+ {"AUX6", K_AUX6},
+ {"AUX7", K_AUX7},
+ {"AUX8", K_AUX8},
+ {"AUX9", K_AUX9},
+ {"AUX10", K_AUX10},
+ {"AUX11", K_AUX11},
+ {"AUX12", K_AUX12},
+ {"AUX13", K_AUX13},
+ {"AUX14", K_AUX14},
+ {"AUX15", K_AUX15},
+ {"AUX16", K_AUX16},
+
+ {"KP_HOME", K_KP_HOME },
+ {"KP_UPARROW", K_KP_UPARROW },
+ {"KP_PGUP", K_KP_PGUP },
+ {"KP_LEFTARROW", K_KP_LEFTARROW },
+ {"KP_5", K_KP_5 },
+ {"KP_RIGHTARROW", K_KP_RIGHTARROW },
+ {"KP_END", K_KP_END },
+ {"KP_DOWNARROW", K_KP_DOWNARROW },
+ {"KP_PGDN", K_KP_PGDN },
+ {"KP_ENTER", K_KP_ENTER },
+ {"KP_INS", K_KP_INS },
+ {"KP_DEL", K_KP_DEL },
+ {"KP_SLASH", K_KP_SLASH },
+ {"KP_MINUS", K_KP_MINUS },
+ {"KP_PLUS", K_KP_PLUS },
+ {"KP_NUMLOCK", K_KP_NUMLOCK },
+ {"KP_STAR", K_KP_STAR },
+ {"KP_EQUALS", K_KP_EQUALS },
+
+ {"PAUSE", K_PAUSE},
+
+ {"SEMICOLON", ';'}, // because a raw semicolon seperates commands
+
+ {"WORLD_0", K_WORLD_0},
+ {"WORLD_1", K_WORLD_1},
+ {"WORLD_2", K_WORLD_2},
+ {"WORLD_3", K_WORLD_3},
+ {"WORLD_4", K_WORLD_4},
+ {"WORLD_5", K_WORLD_5},
+ {"WORLD_6", K_WORLD_6},
+ {"WORLD_7", K_WORLD_7},
+ {"WORLD_8", K_WORLD_8},
+ {"WORLD_9", K_WORLD_9},
+ {"WORLD_10", K_WORLD_10},
+ {"WORLD_11", K_WORLD_11},
+ {"WORLD_12", K_WORLD_12},
+ {"WORLD_13", K_WORLD_13},
+ {"WORLD_14", K_WORLD_14},
+ {"WORLD_15", K_WORLD_15},
+ {"WORLD_16", K_WORLD_16},
+ {"WORLD_17", K_WORLD_17},
+ {"WORLD_18", K_WORLD_18},
+ {"WORLD_19", K_WORLD_19},
+ {"WORLD_20", K_WORLD_20},
+ {"WORLD_21", K_WORLD_21},
+ {"WORLD_22", K_WORLD_22},
+ {"WORLD_23", K_WORLD_23},
+ {"WORLD_24", K_WORLD_24},
+ {"WORLD_25", K_WORLD_25},
+ {"WORLD_26", K_WORLD_26},
+ {"WORLD_27", K_WORLD_27},
+ {"WORLD_28", K_WORLD_28},
+ {"WORLD_29", K_WORLD_29},
+ {"WORLD_30", K_WORLD_30},
+ {"WORLD_31", K_WORLD_31},
+ {"WORLD_32", K_WORLD_32},
+ {"WORLD_33", K_WORLD_33},
+ {"WORLD_34", K_WORLD_34},
+ {"WORLD_35", K_WORLD_35},
+ {"WORLD_36", K_WORLD_36},
+ {"WORLD_37", K_WORLD_37},
+ {"WORLD_38", K_WORLD_38},
+ {"WORLD_39", K_WORLD_39},
+ {"WORLD_40", K_WORLD_40},
+ {"WORLD_41", K_WORLD_41},
+ {"WORLD_42", K_WORLD_42},
+ {"WORLD_43", K_WORLD_43},
+ {"WORLD_44", K_WORLD_44},
+ {"WORLD_45", K_WORLD_45},
+ {"WORLD_46", K_WORLD_46},
+ {"WORLD_47", K_WORLD_47},
+ {"WORLD_48", K_WORLD_48},
+ {"WORLD_49", K_WORLD_49},
+ {"WORLD_50", K_WORLD_50},
+ {"WORLD_51", K_WORLD_51},
+ {"WORLD_52", K_WORLD_52},
+ {"WORLD_53", K_WORLD_53},
+ {"WORLD_54", K_WORLD_54},
+ {"WORLD_55", K_WORLD_55},
+ {"WORLD_56", K_WORLD_56},
+ {"WORLD_57", K_WORLD_57},
+ {"WORLD_58", K_WORLD_58},
+ {"WORLD_59", K_WORLD_59},
+ {"WORLD_60", K_WORLD_60},
+ {"WORLD_61", K_WORLD_61},
+ {"WORLD_62", K_WORLD_62},
+ {"WORLD_63", K_WORLD_63},
+ {"WORLD_64", K_WORLD_64},
+ {"WORLD_65", K_WORLD_65},
+ {"WORLD_66", K_WORLD_66},
+ {"WORLD_67", K_WORLD_67},
+ {"WORLD_68", K_WORLD_68},
+ {"WORLD_69", K_WORLD_69},
+ {"WORLD_70", K_WORLD_70},
+ {"WORLD_71", K_WORLD_71},
+ {"WORLD_72", K_WORLD_72},
+ {"WORLD_73", K_WORLD_73},
+ {"WORLD_74", K_WORLD_74},
+ {"WORLD_75", K_WORLD_75},
+ {"WORLD_76", K_WORLD_76},
+ {"WORLD_77", K_WORLD_77},
+ {"WORLD_78", K_WORLD_78},
+ {"WORLD_79", K_WORLD_79},
+ {"WORLD_80", K_WORLD_80},
+ {"WORLD_81", K_WORLD_81},
+ {"WORLD_82", K_WORLD_82},
+ {"WORLD_83", K_WORLD_83},
+ {"WORLD_84", K_WORLD_84},
+ {"WORLD_85", K_WORLD_85},
+ {"WORLD_86", K_WORLD_86},
+ {"WORLD_87", K_WORLD_87},
+ {"WORLD_88", K_WORLD_88},
+ {"WORLD_89", K_WORLD_89},
+ {"WORLD_90", K_WORLD_90},
+ {"WORLD_91", K_WORLD_91},
+ {"WORLD_92", K_WORLD_92},
+ {"WORLD_93", K_WORLD_93},
+ {"WORLD_94", K_WORLD_94},
+ {"WORLD_95", K_WORLD_95},
+
+ {"WINDOWS", K_SUPER},
+ {"COMPOSE", K_COMPOSE},
+ {"MODE", K_MODE},
+ {"HELP", K_HELP},
+ {"PRINT", K_PRINT},
+ {"SYSREQ", K_SYSREQ},
+ {"SCROLLOCK", K_SCROLLOCK },
+ {"BREAK", K_BREAK},
+ {"MENU", K_MENU},
+ {"POWER", K_POWER},
+ {"EURO", K_EURO},
+ {"UNDO", K_UNDO},
+
+ {"PAD0_A", K_PAD0_A },
+ {"PAD0_B", K_PAD0_B },
+ {"PAD0_X", K_PAD0_X },
+ {"PAD0_Y", K_PAD0_Y },
+ {"PAD0_BACK", K_PAD0_BACK },
+ {"PAD0_GUIDE", K_PAD0_GUIDE },
+ {"PAD0_START", K_PAD0_START },
+ {"PAD0_LEFTSTICK_CLICK", K_PAD0_LEFTSTICK_CLICK },
+ {"PAD0_RIGHTSTICK_CLICK", K_PAD0_RIGHTSTICK_CLICK },
+ {"PAD0_LEFTSHOULDER", K_PAD0_LEFTSHOULDER },
+ {"PAD0_RIGHTSHOULDER", K_PAD0_RIGHTSHOULDER },
+ {"PAD0_DPAD_UP", K_PAD0_DPAD_UP },
+ {"PAD0_DPAD_DOWN", K_PAD0_DPAD_DOWN },
+ {"PAD0_DPAD_LEFT", K_PAD0_DPAD_LEFT },
+ {"PAD0_DPAD_RIGHT", K_PAD0_DPAD_RIGHT },
+
+ {"PAD0_LEFTSTICK_LEFT", K_PAD0_LEFTSTICK_LEFT },
+ {"PAD0_LEFTSTICK_RIGHT", K_PAD0_LEFTSTICK_RIGHT },
+ {"PAD0_LEFTSTICK_UP", K_PAD0_LEFTSTICK_UP },
+ {"PAD0_LEFTSTICK_DOWN", K_PAD0_LEFTSTICK_DOWN },
+ {"PAD0_RIGHTSTICK_LEFT", K_PAD0_RIGHTSTICK_LEFT },
+ {"PAD0_RIGHTSTICK_RIGHT", K_PAD0_RIGHTSTICK_RIGHT },
+ {"PAD0_RIGHTSTICK_UP", K_PAD0_RIGHTSTICK_UP },
+ {"PAD0_RIGHTSTICK_DOWN", K_PAD0_RIGHTSTICK_DOWN },
+ {"PAD0_LEFTTRIGGER", K_PAD0_LEFTTRIGGER },
+ {"PAD0_RIGHTTRIGGER", K_PAD0_RIGHTTRIGGER },
+
+ {NULL,0}
+};
+
+/*
+=============================================================================
+
+EDIT FIELDS
+
+=============================================================================
+*/
+
+
+/*
+===================
+Field_Draw
+
+Handles horizontal scrolling and cursor blinking
+x, y, and width are in pixels
+===================
+*/
+static void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size,
+ bool showCursor, bool noColorEscape )
+{
+ int len;
+ int drawLen;
+ int prestep;
+ int cursorChar;
+ char str[MAX_STRING_CHARS];
+ int i;
+
+ drawLen = edit->widthInChars - 1; // - 1 so there is always a space for the cursor
+ len = strlen( edit->buffer );
+
+ // guarantee that cursor will be visible
+ if ( len <= drawLen ) {
+ prestep = 0;
+ } else {
+ if ( edit->scroll + drawLen > len ) {
+ edit->scroll = len - drawLen;
+ if ( edit->scroll < 0 ) {
+ edit->scroll = 0;
+ }
+ }
+ prestep = edit->scroll;
+ }
+
+ if ( prestep + drawLen > len ) {
+ drawLen = len - prestep;
+ }
+
+ // extract <drawLen> characters from the field at <prestep>
+ if ( drawLen >= MAX_STRING_CHARS ) {
+ Com_Error( ERR_DROP, "drawLen >= MAX_STRING_CHARS" );
+ }
+
+ ::memcpy( str, edit->buffer + prestep, drawLen );
+ str[ drawLen ] = 0;
+
+ // draw it
+ if ( size == SMALLCHAR_WIDTH ) {
+ float color[4];
+
+ color[0] = color[1] = color[2] = color[3] = 1.0;
+ SCR_DrawSmallStringExt( x, y, str, color, false, noColorEscape );
+ } else {
+ // draw big string with drop shadow
+ SCR_DrawBigString( x, y, str, 1.0, noColorEscape );
+ }
+
+ // draw the cursor
+ if ( showCursor ) {
+ if ( (int)( cls.realtime >> 8 ) & 1 ) {
+ return; // off blink
+ }
+
+ if ( key_overstrikeMode ) {
+ cursorChar = 11;
+ } else {
+ cursorChar = 10;
+ }
+
+ i = drawLen - strlen( str );
+
+ if ( size == SMALLCHAR_WIDTH ) {
+ SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar );
+ } else {
+ str[0] = cursorChar;
+ str[1] = 0;
+ SCR_DrawBigString( x + ( edit->cursor - prestep - i ) * size, y, str, 1.0, false );
+
+ }
+ }
+}
+
+void Field_Draw( field_t *edit, int x, int y, int width, bool showCursor, bool noColorEscape )
+{
+ Field_VariableSizeDraw( edit, x, y, width, SMALLCHAR_WIDTH, showCursor, noColorEscape );
+}
+
+void Field_BigDraw( field_t *edit, int x, int y, int width, bool showCursor, bool noColorEscape )
+{
+ Field_VariableSizeDraw( edit, x, y, width, BIGCHAR_WIDTH, showCursor, noColorEscape );
+}
+
+/*
+================
+Field_Paste
+================
+*/
+static void Field_Paste( field_t *edit )
+{
+ char *cbd;
+ int pasteLen, i;
+
+ cbd = Sys_GetClipboardData();
+
+ if ( !cbd ) {
+ return;
+ }
+
+ // send as if typed, so insert / overstrike works properly
+ pasteLen = strlen( cbd );
+ for ( i = 0 ; i < pasteLen ; i++ ) {
+ Field_CharEvent( edit, cbd[i] );
+ }
+
+ Z_Free( cbd );
+}
+
+/*
+=================
+Field_KeyDownEvent
+
+Performs the basic line editing functions for the console,
+in-game talk, and menu fields
+
+Key events are used for non-printable characters, others are gotten from char events.
+=================
+*/
+void Field_KeyDownEvent( field_t *edit, int key )
+{
+ int len;
+
+ // shift-insert is paste
+ if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keys[K_SHIFT].down )
+ {
+ Field_Paste( edit );
+ return;
+ }
+
+ key = tolower( key );
+ len = strlen( edit->buffer );
+
+ switch ( key )
+ {
+ case K_DEL:
+ if ( edit->cursor < len )
+ {
+ memmove( edit->buffer + edit->cursor,
+ edit->buffer + edit->cursor + 1,
+ len - edit->cursor );
+ }
+ break;
+
+ case K_RIGHTARROW:
+ if ( edit->cursor < len ) {
+ edit->cursor++;
+ }
+ break;
+
+ case K_LEFTARROW:
+ if ( edit->cursor > 0 ) {
+ edit->cursor--;
+ }
+ break;
+
+ case K_HOME:
+ edit->cursor = 0;
+ break;
+
+ case K_END:
+ edit->cursor = len;
+ break;
+
+ case K_INS:
+ key_overstrikeMode = !key_overstrikeMode;
+ break;
+
+ default:
+ break;
+ }
+
+ // Change scroll if cursor is no longer visible
+ if ( edit->cursor < edit->scroll )
+ {
+ edit->scroll = edit->cursor;
+ }
+ else if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
+ {
+ edit->scroll = edit->cursor - edit->widthInChars + 1;
+ }
+}
+
+/*
+==================
+Field_CharEvent
+==================
+*/
+void Field_CharEvent( field_t *edit, int ch )
+{
+ int len;
+
+ if ( ch == 'v' - 'a' + 1 ) { // ctrl-v is paste
+ Field_Paste( edit );
+ return;
+ }
+
+ if ( ch == 'c' - 'a' + 1 ) { // ctrl-c clears the field
+ Field_Clear( edit );
+ return;
+ }
+
+ len = strlen( edit->buffer );
+
+ if ( ch == 'h' - 'a' + 1 ) { // ctrl-h is backspace
+ if ( edit->cursor > 0 ) {
+ memmove( edit->buffer + edit->cursor - 1,
+ edit->buffer + edit->cursor, len + 1 - edit->cursor );
+ edit->cursor--;
+ if ( edit->cursor < edit->scroll )
+ {
+ edit->scroll--;
+ }
+ }
+ return;
+ }
+
+ if ( ch == 'a' - 'a' + 1 ) { // ctrl-a is home
+ edit->cursor = 0;
+ edit->scroll = 0;
+ return;
+ }
+
+ if ( ch == 'e' - 'a' + 1 ) { // ctrl-e is end
+ edit->cursor = len;
+ edit->scroll = edit->cursor - edit->widthInChars;
+ return;
+ }
+
+ //
+ // ignore any other non printable chars
+ //
+ if ( ch < 32 ) {
+ return;
+ }
+
+ if ( key_overstrikeMode ) {
+ // - 2 to leave room for the leading slash and trailing \0
+ if ( edit->cursor == MAX_EDIT_LINE - 2 )
+ return;
+ edit->buffer[edit->cursor] = ch;
+ edit->cursor++;
+ } else { // insert mode
+ // - 2 to leave room for the leading slash and trailing \0
+ if ( len == MAX_EDIT_LINE - 2 ) {
+ return; // all full
+ }
+ memmove( edit->buffer + edit->cursor + 1,
+ edit->buffer + edit->cursor, len + 1 - edit->cursor );
+ edit->buffer[edit->cursor] = ch;
+ edit->cursor++;
+ }
+
+
+ if ( edit->cursor >= edit->widthInChars ) {
+ edit->scroll++;
+ }
+
+ if ( edit->cursor == len + 1) {
+ edit->buffer[edit->cursor] = 0;
+ }
+}
+
+/*
+=============================================================================
+
+CONSOLE LINE EDITING
+
+==============================================================================
+*/
+
+/*
+====================
+Console_Key
+
+Handles history and console scrollback
+====================
+*/
+static void Console_Key(int key)
+{
+ // ctrl-L clears screen
+ if ( key == 'l' && keys[K_CTRL].down )
+ {
+ Cbuf_AddText ("clear\n");
+ return;
+ }
+
+ // enter finishes the line
+ if ( key == K_ENTER || key == K_KP_ENTER )
+ {
+ // if not in the game explicitly prepend a slash if needed
+ if ( clc.state != CA_ACTIVE
+ && g_consoleField.buffer[0]
+ && g_consoleField.buffer[0] != '\\'
+ && g_consoleField.buffer[0] != '/' )
+ {
+ char temp[MAX_EDIT_LINE-1];
+
+ Q_strncpyz( temp, g_consoleField.buffer, sizeof( temp ) );
+ Com_sprintf( g_consoleField.buffer, sizeof( g_consoleField.buffer ), "\\%s", temp );
+ g_consoleField.cursor++;
+ }
+
+ Com_Printf ( "]%s\n", g_consoleField.buffer );
+
+ // leading slash is an explicit command
+ if ( g_consoleField.buffer[0] == '\\' || g_consoleField.buffer[0] == '/' )
+ {
+ Cbuf_AddText( g_consoleField.buffer+1 ); // valid command
+ Cbuf_AddText ("\n");
+ }
+ else
+ {
+ // other text will be chat messages
+ if ( !g_consoleField.buffer[0] )
+ {
+ return; // empty lines just scroll the console without adding to history
+ }
+ else
+ {
+ Cbuf_AddText ("cmd say ");
+ Cbuf_AddText( g_consoleField.buffer );
+ Cbuf_AddText ("\n");
+ }
+ }
+
+ // copy line to history buffer
+ historyEditLines[nextHistoryLine % COMMAND_HISTORY] = g_consoleField;
+ nextHistoryLine++;
+ historyLine = nextHistoryLine;
+
+ Field_Clear( &g_consoleField );
+
+ g_consoleField.widthInChars = g_console_field_width;
+
+ CL_SaveConsoleHistory( );
+
+ if ( clc.state == CA_DISCONNECTED ) {
+ SCR_UpdateScreen (); // force an update, because the command
+ } // may take some time
+ return;
+ }
+
+ // command completion
+
+ if (key == K_TAB) {
+ Field_AutoComplete(&g_consoleField);
+ return;
+ }
+
+ // command history (ctrl-p ctrl-n for unix style)
+
+ if ( (key == K_MWHEELUP && keys[K_SHIFT].down) || ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
+ ( ( tolower(key) == 'p' ) && keys[K_CTRL].down ) ) {
+ if ( nextHistoryLine - historyLine < COMMAND_HISTORY
+ && historyLine > 0 ) {
+ historyLine--;
+ }
+ g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
+ return;
+ }
+
+ if ( (key == K_MWHEELDOWN && keys[K_SHIFT].down) || ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
+ ( ( tolower(key) == 'n' ) && keys[K_CTRL].down ) ) {
+ historyLine++;
+ if (historyLine >= nextHistoryLine) {
+ historyLine = nextHistoryLine;
+ Field_Clear( &g_consoleField );
+ g_consoleField.widthInChars = g_console_field_width;
+ return;
+ }
+ g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
+ return;
+ }
+
+ // console scrolling
+ if ( key == K_PGUP ) {
+ Con_PageUp();
+ return;
+ }
+
+ if ( key == K_PGDN) {
+ Con_PageDown();
+ return;
+ }
+
+ if ( key == K_MWHEELUP) { //----(SA) added some mousewheel functionality to the console
+ Con_PageUp();
+ if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
+ Con_PageUp();
+ Con_PageUp();
+ }
+ return;
+ }
+
+ if ( key == K_MWHEELDOWN) { //----(SA) added some mousewheel functionality to the console
+ Con_PageDown();
+ if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
+ Con_PageDown();
+ Con_PageDown();
+ }
+ return;
+ }
+
+ // ctrl-home = top of console
+ if ( key == K_HOME && keys[K_CTRL].down ) {
+ Con_Top();
+ return;
+ }
+
+ // ctrl-end = bottom of console
+ if ( key == K_END && keys[K_CTRL].down ) {
+ Con_Bottom();
+ return;
+ }
+
+ // pass to the normal editline routine
+ Field_KeyDownEvent( &g_consoleField, key );
+}
+//============================================================================
+
+
+
+/*
+=================
+Message_Key
+
+In game talk message
+=================
+*/
+static void Message_Key( int key ) {
+
+ char buffer[MAX_STRING_CHARS];
+
+ if (key == K_ESCAPE) {
+ Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_MESSAGE );
+ Field_Clear( &chatField);
+ return;
+ }
+
+ if ( key == K_ENTER || key == K_KP_ENTER ) {
+ if ( chatField.buffer[0] && clc.state == CA_ACTIVE ){
+
+ if( chatField.buffer[0] == '/' ||
+ chatField.buffer[0] == '\\' )
+ {
+ Com_sprintf( buffer, sizeof( buffer ), "%s\n", &chatField.buffer[1] );
+ }
+
+ else if (chat_playerNum != -1 ) {
+ Com_sprintf( buffer, sizeof( buffer ),
+ "tell %i \"%s\"\n",
+ chat_playerNum,
+ chatField.buffer );
+ }
+ else if (chat_team) {
+ Com_sprintf( buffer, sizeof( buffer ),
+ "say_team \"%s\"\n",
+ chatField.buffer );
+ }
+ else if (chat_admins) {
+ Com_sprintf( buffer, sizeof( buffer ),
+ "a \"%s\"\n",
+ chatField.buffer );
+ }
+ else if (chat_clans) {
+ char clantagDecolored[ 32 ];
+
+ Q_strncpyz( clantagDecolored, cl_clantag->string,
+ sizeof(clantagDecolored) );
+ Q_CleanStr( clantagDecolored );
+
+ if( strlen(clantagDecolored) > 2 && strlen(clantagDecolored) < 11 ) {
+ Com_sprintf( buffer, sizeof( buffer ),
+ "m \"%s\" \"%s\"\n", clantagDecolored,
+ chatField.buffer );
+ } else {
+ //string isnt long enough
+ Com_Printf (
+ "^3Error:your cl_clantag has to be Between 3 and 10 chars long. current value is:^7 %s^7\n",
+ clantagDecolored );
+ return;
+ }
+ }
+ else {
+ Com_sprintf( buffer, sizeof( buffer ),
+ "say \"%s\"\n", chatField.buffer );
+ }
+
+ CL_AddReliableCommand( buffer, false );
+ }
+ Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_MESSAGE );
+ Field_Clear( &chatField );
+ return;
+ }
+
+ Field_KeyDownEvent( &chatField, key);
+}
+
+//============================================================================
+
+
+bool Key_GetOverstrikeMode( void )
+{
+ return key_overstrikeMode;
+}
+
+
+void Key_SetOverstrikeMode( bool state )
+{
+ key_overstrikeMode = state;
+}
+
+
+/*
+===================
+Key_IsDown
+===================
+*/
+bool Key_IsDown( int keynum )
+{
+ if ( keynum < 0 || keynum >= MAX_KEYS )
+ return false;
+
+ return keys[keynum].down;
+}
+
+/*
+===================
+Key_StringToKeynum
+
+Returns a key number to be used to index keys[] by looking at
+the given string. Single ascii characters return themselves, while
+the K_* names are matched up.
+
+0x11 will be interpreted as raw hex, which will allow new controlers
+
+to be configured even if they don't have defined names.
+===================
+*/
+int Key_StringToKeynum( const char *str ) {
+ keyname_t *kn;
+
+ if ( !str || !str[0] ) {
+ return -1;
+ }
+ if ( !str[1] ) {
+ return tolower( str[0] );
+ }
+
+ // check for hex code
+ if ( strlen( str ) == 4 ) {
+ int n = Com_HexStrToInt( str );
+
+ if ( n >= 0 ) {
+ return n;
+ }
+ }
+
+ // scan for a text match
+ for ( kn=keynames ; kn->name ; kn++ ) {
+ if ( !Q_stricmp( str,kn->name ) )
+ return kn->keynum;
+ }
+
+ return -1;
+}
+
+/*
+===================
+Key_KeynumToString
+
+Returns a string (either a single ascii char, a K_* name, or a 0x11 hex string) for the
+given keynum.
+===================
+*/
+const char *Key_KeynumToString( int keynum ) {
+ keyname_t *kn;
+ static char tinystr[5];
+ int i, j;
+
+ if ( keynum == -1 ) {
+ return "<KEY NOT FOUND>";
+ }
+
+ if ( keynum < 0 || keynum >= MAX_KEYS ) {
+ return "<OUT OF RANGE>";
+ }
+
+ // check for printable ascii (don't use quote)
+ if ( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' ) {
+ tinystr[0] = keynum;
+ tinystr[1] = 0;
+ return tinystr;
+ }
+
+ // check for a key string
+ for ( kn=keynames ; kn->name ; kn++ ) {
+ if (keynum == kn->keynum) {
+ return kn->name;
+ }
+ }
+
+ // make a hex string
+ i = keynum >> 4;
+ j = keynum & 15;
+
+ tinystr[0] = '0';
+ tinystr[1] = 'x';
+ tinystr[2] = i > 9 ? i - 10 + 'a' : i + '0';
+ tinystr[3] = j > 9 ? j - 10 + 'a' : j + '0';
+ tinystr[4] = 0;
+
+ return tinystr;
+}
+
+
+/*
+===================
+Key_SetBinding
+===================
+*/
+void Key_SetBinding( int keynum, const char *binding ) {
+ if ( keynum < 0 || keynum >= MAX_KEYS ) {
+ return;
+ }
+
+ // free old bindings
+ if ( keys[ keynum ].binding ) {
+ Z_Free( keys[ keynum ].binding );
+ }
+
+ // allocate memory for new binding
+ keys[keynum].binding = CopyString( binding );
+
+ // consider this like modifying an archived cvar, so the
+ // file write will be triggered at the next oportunity
+ cvar_modifiedFlags |= CVAR_ARCHIVE;
+}
+
+
+/*
+===================
+Key_GetBinding
+===================
+*/
+const char *Key_GetBinding( int keynum ) {
+ if ( keynum < 0 || keynum >= MAX_KEYS ) {
+ return "";
+ }
+
+ return keys[ keynum ].binding;
+}
+
+/*
+===================
+Key_GetKey
+===================
+*/
+
+int Key_GetKey(const char *binding) {
+ int i;
+
+ if (binding) {
+ for (i=0 ; i < MAX_KEYS ; i++) {
+ if (keys[i].binding && Q_stricmp(binding, keys[i].binding) == 0) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+===================
+Key_Unbind_f
+===================
+*/
+void Key_Unbind_f (void)
+{
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("unbind <key> : remove commands from a key\n");
+ return;
+ }
+
+ int b = Key_StringToKeynum(Cmd_Argv(1));
+ if ( b == -1 )
+ {
+ Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
+ return;
+ }
+
+ Key_SetBinding (b, "");
+}
+
+/*
+===================
+Key_Unbindall_f
+===================
+*/
+void Key_Unbindall_f (void)
+{
+ int i;
+
+ for (i=0 ; i < MAX_KEYS; i++)
+ if (keys[i].binding)
+ Key_SetBinding (i, "");
+}
+
+
+/*
+===================
+Key_Bind_f
+===================
+*/
+void Key_Bind_f (void)
+{
+ int i, c, b;
+ char cmd[1024];
+
+ c = Cmd_Argc();
+
+ if (c < 2)
+ {
+ Com_Printf ("bind <key> [command] : attach a command to a key\n");
+ return;
+ }
+ b = Key_StringToKeynum (Cmd_Argv(1));
+ if (b==-1)
+ {
+ Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
+ return;
+ }
+
+ if (c == 2)
+ {
+ if (keys[b].binding && keys[b].binding[0])
+ Com_Printf ("\"%s\" = \"%s\"\n", Key_KeynumToString(b), keys[b].binding );
+ else
+ Com_Printf ("\"%s\" is not bound\n", Key_KeynumToString(b) );
+ return;
+ }
+
+// copy the rest of the command line
+ cmd[0] = 0; // start out with a null string
+ for (i=2 ; i< c ; i++)
+ {
+ strcat (cmd, Cmd_Argv(i));
+ if (i != (c-1))
+ strcat (cmd, " ");
+ }
+
+ Key_SetBinding (b, cmd);
+}
+
+/*
+============
+Key_WriteBindings
+
+Writes lines containing "bind key value"
+============
+*/
+void Key_WriteBindings( fileHandle_t f ) {
+ int i;
+
+ FS_Printf (f, "unbindall\n" );
+
+ for (i=0 ; i<MAX_KEYS ; i++) {
+ if (keys[i].binding && keys[i].binding[0] ) {
+ FS_Printf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keys[i].binding);
+
+ }
+
+ }
+}
+
+
+/*
+============
+Key_Bindlist_f
+
+============
+*/
+void Key_Bindlist_f( void ) {
+ int i;
+
+ for ( i = 0 ; i < MAX_KEYS ; i++ ) {
+ if ( keys[i].binding && keys[i].binding[0] ) {
+ Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i), keys[i].binding );
+ }
+ }
+}
+
+/*
+============
+Key_KeynameCompletion
+============
+*/
+void Key_KeynameCompletion( void(*callback)(const char *s) ) {
+ int i;
+
+ for( i = 0; keynames[ i ].name != NULL; i++ )
+ callback( keynames[ i ].name );
+}
+
+/*
+====================
+Key_CompleteUnbind
+====================
+*/
+static void Key_CompleteUnbind( char *args, int argNum )
+{
+ if( argNum == 2 )
+ {
+ // Skip "unbind "
+ char *p = Com_SkipTokens( args, 1, " " );
+
+ if( p > args )
+ Field_CompleteKeyname( );
+ }
+}
+
+/*
+====================
+Key_CompleteBind
+====================
+*/
+static void Key_CompleteBind( char *args, int argNum )
+{
+ char *p;
+
+ if( argNum == 2 )
+ {
+ // Skip "bind "
+ p = Com_SkipTokens( args, 1, " " );
+
+ if( p > args )
+ Field_CompleteKeyname( );
+ }
+ else if( argNum >= 3 )
+ {
+ // Skip "bind <key> "
+ p = Com_SkipTokens( args, 2, " " );
+
+ if( p > args )
+ Field_CompleteCommand( p, true, true );
+ }
+}
+
+/*
+===================
+CL_InitKeyCommands
+===================
+*/
+void CL_InitKeyCommands( void )
+{
+ // register our functions
+ Cmd_AddCommand ("bind",Key_Bind_f);
+ Cmd_SetCommandCompletionFunc( "bind", Key_CompleteBind );
+ Cmd_AddCommand ("unbind",Key_Unbind_f);
+ Cmd_SetCommandCompletionFunc( "unbind", Key_CompleteUnbind );
+ Cmd_AddCommand ("unbindall",Key_Unbindall_f);
+ Cmd_AddCommand ("bindlist",Key_Bindlist_f);
+}
+
+/*
+===================
+CL_BindUICommand
+
+Returns true if bind command should be executed while user interface is shown
+===================
+*/
+static bool CL_BindUICommand( const char *cmd )
+{
+ if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE )
+ return false;
+
+ if ( !Q_stricmp( cmd, "toggleconsole" ) )
+ return true;
+ if ( !Q_stricmp( cmd, "togglemenu" ) )
+ return true;
+
+ return false;
+}
+
+/*
+===================
+CL_ParseBinding
+
+Execute the commands in the bind string
+===================
+*/
+static void CL_ParseBinding( int key, bool down, unsigned time )
+{
+ char buf[ MAX_STRING_CHARS ], *p = buf, *end;
+ bool allCommands, allowUpCmds;
+
+ if( clc.state == CA_DISCONNECTED && Key_GetCatcher( ) == 0 )
+ return;
+ if( !keys[key].binding || !keys[key].binding[0] )
+ return;
+ Q_strncpyz( buf, keys[key].binding, sizeof( buf ) );
+
+ // run all bind commands if console, ui, etc aren't reading keys
+ allCommands = ( Key_GetCatcher( ) == 0 );
+
+ // allow button up commands if in game even if key catcher is set
+ allowUpCmds = ( clc.state != CA_DISCONNECTED );
+
+ while( 1 )
+ {
+ while( isspace( *p ) )
+ p++;
+ end = strchr( p, ';' );
+ if( end )
+ *end = '\0';
+ if( *p == '+' )
+ {
+ // button commands add keynum and time as parameters
+ // so that multiple sources can be discriminated and
+ // subframe corrected
+ if ( allCommands || ( allowUpCmds && !down ) ) {
+ char cmd[1024];
+ Com_sprintf( cmd, sizeof( cmd ), "%c%s %d %d\n",
+ ( down ) ? '+' : '-', p + 1, key, time );
+ Cbuf_AddText( cmd );
+ }
+ }
+ else if( down )
+ {
+ // normal commands only execute on key press
+ if ( allCommands || CL_BindUICommand( p ) ) {
+ Cbuf_AddText( p );
+ Cbuf_AddText( "\n" );
+ }
+ }
+ if( !end )
+ break;
+ p = end + 1;
+ }
+}
+
+/*
+===================
+CL_KeyDownEvent
+
+Called by CL_KeyEvent to handle a keypress
+===================
+*/
+static void CL_KeyDownEvent( int key, unsigned time )
+{
+ keys[key].down = true;
+ keys[key].repeats++;
+ if( keys[key].repeats == 1 )
+ anykeydown++;
+
+ if( keys[K_ALT].down && key == K_ENTER )
+ {
+ Cvar_SetValue( "r_fullscreen",
+ !Cvar_VariableIntegerValue( "r_fullscreen" ) );
+ return;
+ }
+
+ // console key is hardcoded, so the user can never unbind it
+ if( key == K_CONSOLE || ( keys[K_SHIFT].down && key == K_ESCAPE ) )
+ {
+ Con_ToggleConsole_f ();
+ Key_ClearStates ();
+ return;
+ }
+
+
+ // keys can still be used for bound actions
+ if ( ( key < 128 || key == K_MOUSE1 ) &&
+ ( clc.demoplaying || clc.state == CA_CINEMATIC ) && Key_GetCatcher( ) == 0 ) {
+
+ if (Cvar_VariableValue ("com_cameraMode") == 0) {
+ if( clc.demoplaying && key != K_ESCAPE ) {
+ // avoid accidental stopping of demos from pressing a random key by opening the console
+ Con_ToggleConsole_f ();
+ Key_ClearStates ();
+ return;
+ }
+ Cvar_Set ("nextdemo","");
+ key = K_ESCAPE;
+ }
+ }
+
+ // escape is always handled special
+ if ( key == K_ESCAPE ) {
+ if ( clc.netchan.alternateProtocol == 2 &&
+ ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) ) {
+ // clear message mode
+ Message_Key( key );
+ return;
+ }
+
+ // escape always gets out of CGAME stuff
+ if (Key_GetCatcher( ) & KEYCATCH_CGAME) {
+ Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CGAME );
+ VM_Call (cls.cgame, CG_EVENT_HANDLING, CGAME_EVENT_NONE);
+ return;
+ }
+
+ if ( !( Key_GetCatcher( ) & KEYCATCH_UI ) ) {
+ if ( clc.state == CA_ACTIVE && !clc.demoplaying ) {
+ VM_Call( cls.ui, UI_SET_ACTIVE_MENU - ( cls.uiInterface == 2 ? 2 : 0 ), UIMENU_INGAME );
+ }
+ else if ( clc.state != CA_DISCONNECTED ) {
+ CL_Disconnect_f();
+ S_StopAllSounds();
+ VM_Call( cls.ui, UI_SET_ACTIVE_MENU - ( cls.uiInterface == 2 ? 2 : 0 ), UIMENU_MAIN );
+ }
+ return;
+ }
+
+ VM_Call( cls.ui, UI_KEY_EVENT, key, true );
+ return;
+ }
+
+ // send the bound action
+ CL_ParseBinding( key, true, time );
+
+ // distribute the key down event to the apropriate handler
+ if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) {
+ Console_Key( key );
+ } else if ( Key_GetCatcher( ) & KEYCATCH_UI ) {
+ if ( cls.ui ) {
+ VM_Call( cls.ui, UI_KEY_EVENT, key, true );
+ }
+ } else if ( Key_GetCatcher( ) & KEYCATCH_CGAME ) {
+ if ( cls.cgame ) {
+ VM_Call( cls.cgame, CG_KEY_EVENT, key, true );
+ }
+ } else if ( clc.netchan.alternateProtocol == 2 &&
+ ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) ) {
+ Message_Key( key );
+ } else if ( clc.state == CA_DISCONNECTED ) {
+ Console_Key( key );
+ }
+}
+
+/*
+===================
+CL_KeyUpEvent
+
+Called by CL_KeyEvent to handle a keyrelease
+===================
+*/
+static void CL_KeyUpEvent( int key, unsigned time )
+{
+ keys[key].repeats = 0;
+ keys[key].down = false;
+ anykeydown--;
+
+ if (anykeydown < 0) {
+ anykeydown = 0;
+ }
+
+ // don't process key-up events for the console key
+ if ( key == K_CONSOLE || ( key == K_ESCAPE && keys[K_SHIFT].down ) )
+ return;
+
+ //
+ // key up events only perform actions if the game key binding is
+ // a button command (leading + sign). These will be processed even in
+ // console mode and menu mode, to keep the character from continuing
+ // an action started before a mode switch.
+ //
+ CL_ParseBinding( key, false, time );
+
+ if ( Key_GetCatcher( ) & KEYCATCH_UI && cls.ui ) {
+ VM_Call( cls.ui, UI_KEY_EVENT, key, false );
+ } else if ( Key_GetCatcher( ) & KEYCATCH_CGAME && cls.cgame ) {
+ VM_Call( cls.cgame, CG_KEY_EVENT, key, false );
+ }
+}
+
+/*
+===================
+CL_KeyEvent
+
+Called by the system for both key up and key down events
+===================
+*/
+void CL_KeyEvent(int key, bool down, unsigned time)
+{
+ if( down )
+ CL_KeyDownEvent( key, time );
+ else
+ CL_KeyUpEvent( key, time );
+}
+
+/*
+===================
+CL_CharEvent
+
+Normal keyboard characters, already shifted / capslocked / etc
+===================
+*/
+void CL_CharEvent( int key )
+{
+ // delete is not a printable character and is otherwise handled by
+ // Field_KeyDownEvent
+ if ( key == 127 )
+ return;
+
+ // distribute the key down event to the apropriate handler
+ if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE )
+ Field_CharEvent( &g_consoleField, key );
+
+ else if ( Key_GetCatcher( ) & KEYCATCH_UI )
+ VM_Call( cls.ui, UI_KEY_EVENT, key | K_CHAR_FLAG, true );
+
+ else if ( clc.netchan.alternateProtocol == 2 &&
+ ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) )
+ Field_CharEvent( &chatField, key );
+
+ else if ( clc.state == CA_DISCONNECTED )
+ Field_CharEvent( &g_consoleField, key );
+}
+
+
+/*
+===================
+Key_ClearStates
+===================
+*/
+void Key_ClearStates(void)
+{
+ anykeydown = 0;
+
+ for ( int i = 0 ; i < MAX_KEYS ; i++ )
+ {
+ if ( keys[i].down )
+ CL_KeyEvent( i, false, 0 );
+
+ keys[i].down = 0;
+ keys[i].repeats = 0;
+ }
+}
+
+/*
+====================
+Key_KeynumToStringBuf
+====================
+*/
+void Key_KeynumToStringBuf( int keynum, char *buf, int buflen )
+{
+ Q_strncpyz( buf, Key_KeynumToString( keynum ), buflen );
+}
+
+/*
+====================
+Key_GetBindingBuf
+====================
+*/
+void Key_GetBindingBuf( int keynum, char *buf, int buflen )
+{
+ const char* value = Key_GetBinding( keynum );
+ if ( value )
+ {
+ Q_strncpyz( buf, value, buflen );
+ }
+ else
+ {
+ *buf = 0;
+ }
+}
+
+static int keyCatchers = 0;
+
+/*
+====================
+Key_GetCatcher
+====================
+*/
+int Key_GetCatcher( void )
+{
+ return keyCatchers;
+}
+
+/*
+====================
+Key_SetCatcher
+====================
+*/
+void Key_SetCatcher( int catcher )
+{
+ // If the catcher state is changing, clear all key states
+ if( catcher != keyCatchers )
+ Key_ClearStates( );
+
+ keyCatchers = catcher;
+}
+
+// This must not exceed MAX_CMD_LINE
+#define MAX_CONSOLE_SAVE_BUFFER 1024
+#define CONSOLE_HISTORY_FILE "q3history"
+static char consoleSaveBuffer[ MAX_CONSOLE_SAVE_BUFFER ];
+static int consoleSaveBufferSize = 0;
+
+/*
+================
+CL_LoadConsoleHistory
+
+Load the console history from cl_consoleHistory
+================
+*/
+void CL_LoadConsoleHistory( void )
+{
+ char *token, *text_p;
+ int i, numChars, numLines = 0;
+ fileHandle_t f;
+
+ consoleSaveBufferSize = FS_FOpenFileRead( CONSOLE_HISTORY_FILE, &f, false );
+ if( !f )
+ {
+ Com_Printf( "Couldn't read %s.\n", CONSOLE_HISTORY_FILE );
+ return;
+ }
+
+ if( consoleSaveBufferSize <= MAX_CONSOLE_SAVE_BUFFER &&
+ FS_Read( consoleSaveBuffer, consoleSaveBufferSize, f ) == consoleSaveBufferSize )
+ {
+ text_p = consoleSaveBuffer;
+
+ for( i = COMMAND_HISTORY - 1; i >= 0; i-- )
+ {
+ if( !*( token = COM_Parse( &text_p ) ) )
+ break;
+
+ historyEditLines[ i ].cursor = atoi( token );
+
+ if( !*( token = COM_Parse( &text_p ) ) )
+ break;
+
+ historyEditLines[ i ].scroll = atoi( token );
+
+ if( !*( token = COM_Parse( &text_p ) ) )
+ break;
+
+ numChars = atoi( token );
+ text_p++;
+ if( numChars > ( strlen( consoleSaveBuffer ) - ( text_p - consoleSaveBuffer ) ) )
+ {
+ Com_DPrintf( S_COLOR_YELLOW "WARNING: probable corrupt history\n" );
+ break;
+ }
+ ::memcpy( historyEditLines[ i ].buffer, text_p, numChars );
+ historyEditLines[ i ].buffer[ numChars ] = '\0';
+ text_p += numChars;
+
+ numLines++;
+ }
+
+ memmove( &historyEditLines[ 0 ], &historyEditLines[ i + 1 ],
+ numLines * sizeof( field_t ) );
+ for( i = numLines; i < COMMAND_HISTORY; i++ )
+ Field_Clear( &historyEditLines[ i ] );
+
+ historyLine = nextHistoryLine = numLines;
+ }
+ else
+ Com_Printf( "Couldn't read %s.\n", CONSOLE_HISTORY_FILE );
+
+ FS_FCloseFile( f );
+}
+
+/*
+================
+CL_SaveConsoleHistory
+
+Save the console history into the cvar cl_consoleHistory
+so that it persists across invocations of q3
+================
+*/
+void CL_SaveConsoleHistory( void )
+{
+ int i;
+ int lineLength, saveBufferLength, additionalLength;
+ fileHandle_t f;
+
+ consoleSaveBuffer[ 0 ] = '\0';
+
+ i = ( nextHistoryLine - 1 ) % COMMAND_HISTORY;
+ do
+ {
+ if( historyEditLines[ i ].buffer[ 0 ] )
+ {
+ lineLength = strlen( historyEditLines[ i ].buffer );
+ saveBufferLength = strlen( consoleSaveBuffer );
+
+ //ICK
+ additionalLength = lineLength + strlen( "999 999 999 " );
+
+ if( saveBufferLength + additionalLength < MAX_CONSOLE_SAVE_BUFFER )
+ {
+ Q_strcat( consoleSaveBuffer, MAX_CONSOLE_SAVE_BUFFER,
+ va( "%d %d %d %s ",
+ historyEditLines[ i ].cursor,
+ historyEditLines[ i ].scroll,
+ lineLength,
+ historyEditLines[ i ].buffer ) );
+ }
+ else
+ break;
+ }
+ i = ( i - 1 + COMMAND_HISTORY ) % COMMAND_HISTORY;
+ }
+ while( i != ( nextHistoryLine - 1 ) % COMMAND_HISTORY );
+
+ consoleSaveBufferSize = strlen( consoleSaveBuffer );
+
+ f = FS_FOpenFileWrite( CONSOLE_HISTORY_FILE );
+ if( !f )
+ {
+ Com_Printf( "Couldn't write %s.\n", CONSOLE_HISTORY_FILE );
+ return;
+ }
+
+ if( FS_Write( consoleSaveBuffer, consoleSaveBufferSize, f ) < consoleSaveBufferSize )
+ Com_Printf( "Couldn't write %s.\n", CONSOLE_HISTORY_FILE );
+
+ FS_FCloseFile( f );
+}
diff --git a/src/client/cl_main.cpp b/src/client/cl_main.cpp
new file mode 100644
index 0000000..8b33acd
--- /dev/null
+++ b/src/client/cl_main.cpp
@@ -0,0 +1,5083 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// cl_main.c -- client main loop
+
+#include "client.h"
+
+#ifndef _WIN32
+#include <sys/stat.h>
+#endif
+
+#include <climits>
+
+#include "sys/sys_loadlib.h"
+#include "sys/sys_local.h"
+
+#include "cl_updates.h"
+#ifdef USE_MUMBLE
+#include "libmumblelink.h"
+#endif
+
+#ifdef USE_MUMBLE
+cvar_t *cl_useMumble;
+cvar_t *cl_mumbleScale;
+#endif
+
+#ifdef USE_VOIP
+cvar_t *cl_voipUseVAD;
+cvar_t *cl_voipVADThreshold;
+cvar_t *cl_voipSend;
+cvar_t *cl_voipSendTarget;
+cvar_t *cl_voipGainDuringCapture;
+cvar_t *cl_voipCaptureMult;
+cvar_t *cl_voipShowMeter;
+cvar_t *cl_voipProtocol;
+cvar_t *cl_voip;
+#endif
+
+#ifdef USE_RENDERER_DLOPEN
+cvar_t *cl_renderer;
+#endif
+
+cvar_t *cl_nodelta;
+cvar_t *cl_debugMove;
+
+cvar_t *cl_noprint;
+cvar_t *cl_motd;
+
+cvar_t *rcon_client_password;
+cvar_t *rconAddress;
+
+cvar_t *cl_timeout;
+cvar_t *cl_maxpackets;
+cvar_t *cl_packetdup;
+cvar_t *cl_timeNudge;
+cvar_t *cl_showTimeDelta;
+cvar_t *cl_freezeDemo;
+
+cvar_t *cl_shownet;
+cvar_t *cl_showSend;
+cvar_t *cl_timedemo;
+cvar_t *cl_timedemoLog;
+cvar_t *cl_autoRecordDemo;
+cvar_t *cl_aviFrameRate;
+cvar_t *cl_aviMotionJpeg;
+cvar_t *cl_forceavidemo;
+
+cvar_t *cl_freelook;
+cvar_t *cl_sensitivity;
+
+cvar_t *cl_mouseAccel;
+cvar_t *cl_mouseAccelOffset;
+cvar_t *cl_mouseAccelStyle;
+cvar_t *cl_showMouseRate;
+
+cvar_t *m_pitch;
+cvar_t *m_yaw;
+cvar_t *m_forward;
+cvar_t *m_side;
+cvar_t *m_filter;
+
+cvar_t *j_pitch;
+cvar_t *j_yaw;
+cvar_t *j_forward;
+cvar_t *j_side;
+cvar_t *j_up;
+cvar_t *j_pitch_axis;
+cvar_t *j_yaw_axis;
+cvar_t *j_forward_axis;
+cvar_t *j_side_axis;
+cvar_t *j_up_axis;
+
+cvar_t *cl_activeAction;
+
+cvar_t *cl_motdString;
+
+cvar_t *cl_allowDownload;
+cvar_t *com_downloadPrompt;
+cvar_t *cl_conXOffset;
+cvar_t *cl_inGameVideo;
+
+cvar_t *cl_serverStatusResendTime;
+
+cvar_t *cl_lanForcePackets;
+
+cvar_t *cl_guidServerUniq;
+
+cvar_t *cl_clantag;
+
+cvar_t *cl_consoleKeys;
+
+cvar_t *cl_rate;
+
+cvar_t *cl_rsaAuth;
+
+clientActive_t cl;
+clientConnection_t clc;
+clientStatic_t cls;
+
+char cl_reconnectArgs[MAX_OSPATH];
+char cl_oldGame[MAX_QPATH];
+bool cl_oldGameSet;
+
+// Structure containing functions exported from refresh DLL
+refexport_t re;
+#ifdef USE_RENDERER_DLOPEN
+static void *rendererLib = NULL;
+#endif
+
+ping_t cl_pinglist[MAX_PINGREQUESTS];
+
+typedef struct serverStatus_s {
+ char string[BIG_INFO_STRING];
+ netadr_t address;
+ int time, startTime;
+ bool pending;
+ bool print;
+ bool retrieved;
+} serverStatus_t;
+
+serverStatus_t cl_serverStatusList[MAX_SERVERSTATUSREQUESTS];
+
+static void CL_InitRef(void);
+
+#if defined __USEA3D && defined __A3D_GEOM
+void hA3Dg_ExportRenderGeom(refexport_t *incoming_re);
+#endif
+
+static bool noGameRestart = false;
+
+static void CL_DownloadUpdate_f() { CL_DownloadRelease(); }
+
+static void CL_InstallUpdate_f()
+{
+ if (Cmd_Argc() > 1)
+ CL_ExecuteInstaller();
+ else
+ CL_ExecuteInstaller();
+}
+
+static void CL_CheckForUpdate_f() { CL_GetLatestRelease(); }
+
+static void CL_BrowseHomepath_f() { FS_BrowseHomepath(); }
+
+static void CL_BrowseDemos_f() { FS_OpenBaseGamePath( "demos/" ); }
+
+static void CL_BrowseScreenShots_f() { FS_OpenBaseGamePath( "screenshots/" ); }
+
+#ifdef USE_MUMBLE
+static void CL_UpdateMumble(void)
+{
+ vec3_t pos, forward, up;
+ float scale = cl_mumbleScale->value;
+ float tmp;
+
+ if (!cl_useMumble->integer) return;
+
+ // !!! FIXME: not sure if this is even close to correct.
+ if (clc.netchan.alternateProtocol == 2)
+ {
+ AngleVectors(cl.snap.alternatePs.viewangles, forward, NULL, up);
+
+ pos[0] = cl.snap.alternatePs.origin[0] * scale;
+ pos[1] = cl.snap.alternatePs.origin[2] * scale;
+ pos[2] = cl.snap.alternatePs.origin[1] * scale;
+ }
+ else
+ {
+ AngleVectors(cl.snap.ps.viewangles, forward, NULL, up);
+
+ pos[0] = cl.snap.ps.origin[0] * scale;
+ pos[1] = cl.snap.ps.origin[2] * scale;
+ pos[2] = cl.snap.ps.origin[1] * scale;
+ }
+
+ tmp = forward[1];
+ forward[1] = forward[2];
+ forward[2] = tmp;
+
+ tmp = up[1];
+ up[1] = up[2];
+ up[2] = tmp;
+
+ if (cl_useMumble->integer > 1)
+ {
+ fprintf(stderr, "%f %f %f, %f %f %f, %f %f %f\n",
+ pos[0], pos[1], pos[2],
+ forward[0], forward[1], forward[2],
+ up[0], up[1], up[2]);
+ }
+
+ mumble_update_coordinates(pos, forward, up);
+}
+#endif
+
+#ifdef USE_VOIP
+static void CL_UpdateVoipIgnore(const char *idstr, bool ignore)
+{
+ if ((*idstr >= '0') && (*idstr <= '9'))
+ {
+ const int id = atoi(idstr);
+ if ((id >= 0) && (id < MAX_CLIENTS))
+ {
+ clc.voipIgnore[id] = ignore;
+ CL_AddReliableCommand(va("voip %s %d", ignore ? "ignore" : "unignore", id), false);
+ Com_Printf("VoIP: %s ignoring player #%d\n", ignore ? "Now" : "No longer", id);
+ return;
+ }
+ }
+ Com_Printf("VoIP: invalid player ID#\n");
+}
+
+static void CL_UpdateVoipGain(const char *idstr, float gain)
+{
+ if ((*idstr >= '0') && (*idstr <= '9'))
+ {
+ const int id = atoi(idstr);
+ if (gain < 0.0f) gain = 0.0f;
+ if ((id >= 0) && (id < MAX_CLIENTS))
+ {
+ clc.voipGain[id] = gain;
+ Com_Printf("VoIP: player #%d gain now set to %f\n", id, gain);
+ }
+ }
+}
+
+void CL_Voip_f(void)
+{
+ const char *cmd = Cmd_Argv(1);
+ const char *reason = NULL;
+
+ if (clc.state != CA_ACTIVE)
+ reason = "Not connected to a server";
+ else if (!clc.voipCodecInitialized)
+ reason = "Voip codec not initialized";
+ else if (!clc.voipEnabled)
+ reason = "Server doesn't support VoIP";
+
+ if (reason != NULL)
+ {
+ Com_Printf("VoIP: command ignored: %s\n", reason);
+ return;
+ }
+
+ if (strcmp(cmd, "ignore") == 0)
+ {
+ CL_UpdateVoipIgnore(Cmd_Argv(2), true);
+ }
+ else if (strcmp(cmd, "unignore") == 0)
+ {
+ CL_UpdateVoipIgnore(Cmd_Argv(2), false);
+ }
+ else if (strcmp(cmd, "gain") == 0)
+ {
+ if (Cmd_Argc() > 3)
+ {
+ CL_UpdateVoipGain(Cmd_Argv(2), atof(Cmd_Argv(3)));
+ }
+ else if (Q_isanumber(Cmd_Argv(2)))
+ {
+ int id = atoi(Cmd_Argv(2));
+ if (id >= 0 && id < MAX_CLIENTS)
+ {
+ Com_Printf(
+ "VoIP: current gain for player #%d "
+ "is %f\n",
+ id, clc.voipGain[id]);
+ }
+ else
+ {
+ Com_Printf("VoIP: invalid player ID#\n");
+ }
+ }
+ else
+ {
+ Com_Printf("usage: voip gain <playerID#> [value]\n");
+ }
+ }
+ else if (strcmp(cmd, "muteall") == 0)
+ {
+ Com_Printf("VoIP: muting incoming voice\n");
+ CL_AddReliableCommand("voip muteall", false);
+ clc.voipMuteAll = true;
+ }
+ else if (strcmp(cmd, "unmuteall") == 0)
+ {
+ Com_Printf("VoIP: unmuting incoming voice\n");
+ CL_AddReliableCommand("voip unmuteall", false);
+ clc.voipMuteAll = false;
+ }
+ else
+ {
+ Com_Printf(
+ "usage: voip [un]ignore <playerID#>\n"
+ " voip [un]muteall\n"
+ " voip gain <playerID#> [value]\n");
+ }
+}
+
+static void CL_VoipNewGeneration(void)
+{
+ // don't have a zero generation so new clients won't match, and don't
+ // wrap to negative so MSG_ReadLong() doesn't "fail."
+ clc.voipOutgoingGeneration++;
+ if (clc.voipOutgoingGeneration <= 0) clc.voipOutgoingGeneration = 1;
+ clc.voipPower = 0.0f;
+ clc.voipOutgoingSequence = 0;
+
+ opus_encoder_ctl(clc.opusEncoder, OPUS_RESET_STATE);
+}
+
+/*
+===============
+CL_VoipParseTargets
+
+sets clc.voipTargets according to cl_voipSendTarget
+Generally we don't want who's listening to change during a transmission,
+so this is only called when the key is first pressed
+===============
+*/
+static void CL_VoipParseTargets(void)
+{
+ const char *target = cl_voipSendTarget->string;
+ char *end;
+ int val;
+
+ ::memset(clc.voipTargets, 0, sizeof(clc.voipTargets));
+ clc.voipFlags &= ~VOIP_SPATIAL;
+
+ while (target)
+ {
+ while (*target == ',' || *target == ' ') target++;
+
+ if (!*target) break;
+
+ if (isdigit(*target))
+ {
+ val = strtol(target, &end, 10);
+ target = end;
+ }
+ else
+ {
+ if (!Q_stricmpn(target, "all", 3))
+ {
+ ::memset(clc.voipTargets, ~0, sizeof(clc.voipTargets));
+ return;
+ }
+ if (!Q_stricmpn(target, "spatial", 7))
+ {
+ clc.voipFlags |= VOIP_SPATIAL;
+ target += 7;
+ continue;
+ }
+ else
+ {
+ if (!Q_stricmpn(target, "attacker", 8))
+ {
+ val = VM_Call(cls.cgame, CG_LAST_ATTACKER);
+ target += 8;
+ }
+ else if (!Q_stricmpn(target, "crosshair", 9))
+ {
+ val = VM_Call(cls.cgame, CG_CROSSHAIR_PLAYER);
+ target += 9;
+ }
+ else
+ {
+ while (*target && *target != ',' && *target != ' ') target++;
+
+ continue;
+ }
+
+ if (val < 0) continue;
+ }
+ }
+
+ if (val < 0 || val >= MAX_CLIENTS)
+ {
+ Com_Printf(S_COLOR_YELLOW
+ "WARNING: VoIP "
+ "target %d is not a valid client "
+ "number\n",
+ val);
+
+ continue;
+ }
+
+ clc.voipTargets[val / 8] |= 1 << (val % 8);
+ }
+}
+
+/*
+===============
+CL_CaptureVoip
+
+Record more audio from the hardware if required and encode it into Opus
+ data for later transmission.
+===============
+*/
+static void CL_CaptureVoip(void)
+{
+ const float audioMult = cl_voipCaptureMult->value;
+ const bool useVad = (cl_voipUseVAD->integer != 0);
+ bool initialFrame = false;
+ bool finalFrame = false;
+
+#if USE_MUMBLE
+ // if we're using Mumble, don't try to handle VoIP transmission ourselves.
+ if (cl_useMumble->integer) return;
+#endif
+
+ // If your data rate is too low, you'll get Connection Interrupted warnings
+ // when VoIP packets arrive, even if you have a broadband connection.
+ // This might work on rates lower than 25000, but for safety's sake, we'll
+ // just demand it. Who doesn't have at least a DSL line now, anyhow? If
+ // you don't, you don't need VoIP. :)
+ if (cl_voip->modified || cl_rate->modified)
+ {
+ if ((cl_voip->integer) && (cl_rate->integer < 25000))
+ {
+ Com_Printf(S_COLOR_YELLOW "Your network rate is too slow for VoIP.\n");
+ Com_Printf("Set 'Data Rate' to 'LAN/Cable/xDSL' in 'Setup/System/Network'.\n");
+ Com_Printf("Until then, VoIP is disabled.\n");
+ Cvar_Set("cl_voip", "0");
+ }
+ Cvar_Set("cl_voipProtocol", cl_voip->integer ? "opus" : "");
+ cl_voip->modified = false;
+ cl_rate->modified = false;
+ }
+
+ if (!clc.voipCodecInitialized) return; // just in case this gets called at a bad time.
+
+ if (clc.voipOutgoingDataSize > 0) return; // packet is pending transmission, don't record more yet.
+
+ if (cl_voipUseVAD->modified)
+ {
+ Cvar_Set("cl_voipSend", (useVad) ? "1" : "0");
+ cl_voipUseVAD->modified = false;
+ }
+
+ if ((useVad) && (!cl_voipSend->integer)) Cvar_Set("cl_voipSend", "1"); // lots of things reset this.
+
+ if (cl_voipSend->modified)
+ {
+ bool dontCapture = false;
+ if (clc.state != CA_ACTIVE)
+ dontCapture = true; // not connected to a server.
+ else if (!clc.voipEnabled)
+ dontCapture = true; // server doesn't support VoIP.
+ else if (clc.demoplaying)
+ dontCapture = true; // playing back a demo.
+ else if (cl_voip->integer == 0)
+ dontCapture = true; // client has VoIP support disabled.
+ else if (audioMult == 0.0f)
+ dontCapture = true; // basically silenced incoming audio.
+
+ cl_voipSend->modified = false;
+
+ if (dontCapture)
+ {
+ Cvar_Set("cl_voipSend", "0");
+ return;
+ }
+
+ if (cl_voipSend->integer)
+ {
+ initialFrame = true;
+ }
+ else
+ {
+ finalFrame = true;
+ }
+ }
+
+ // try to get more audio data from the sound card...
+
+ if (initialFrame)
+ {
+ S_MasterGain(Com_Clamp(0.0f, 1.0f, cl_voipGainDuringCapture->value));
+ S_StartCapture();
+ CL_VoipNewGeneration();
+ CL_VoipParseTargets();
+ }
+
+ if ((cl_voipSend->integer) || (finalFrame))
+ { // user wants to capture audio?
+ int samples = S_AvailableCaptureSamples();
+ const int packetSamples = (finalFrame) ? VOIP_MAX_FRAME_SAMPLES : VOIP_MAX_PACKET_SAMPLES;
+
+ // enough data buffered in audio hardware to process yet?
+ if (samples >= packetSamples)
+ {
+ // audio capture is always MONO16.
+ static int16_t sampbuffer[VOIP_MAX_PACKET_SAMPLES];
+ float voipPower = 0.0f;
+ int voipFrames;
+ int i, bytes;
+
+ if (samples > VOIP_MAX_PACKET_SAMPLES) samples = VOIP_MAX_PACKET_SAMPLES;
+
+ // !!! FIXME: maybe separate recording from encoding, so voipPower
+ // !!! FIXME: updates faster than 4Hz?
+
+ samples -= samples % VOIP_MAX_FRAME_SAMPLES;
+ if (samples != 120 && samples != 240 && samples != 480 && samples != 960 && samples != 1920 &&
+ samples != 2880)
+ {
+ Com_Printf("Voip: bad number of samples %d\n", samples);
+ return;
+ }
+ voipFrames = samples / VOIP_MAX_FRAME_SAMPLES;
+
+ S_Capture(samples, (byte *)sampbuffer); // grab from audio card.
+
+ // check the "power" of this packet...
+ for (i = 0; i < samples; i++)
+ {
+ const float flsamp = (float)sampbuffer[i];
+ const float s = fabs(flsamp);
+ voipPower += s * s;
+ sampbuffer[i] = (int16_t)((flsamp)*audioMult);
+ }
+
+ // encode raw audio samples into Opus data...
+ bytes = opus_encode(clc.opusEncoder, sampbuffer, samples, (unsigned char *)clc.voipOutgoingData,
+ sizeof(clc.voipOutgoingData));
+ if (bytes <= 0)
+ {
+ Com_DPrintf("VoIP: Error encoding %d samples\n", samples);
+ bytes = 0;
+ }
+
+ clc.voipPower = (voipPower / (32768.0f * 32768.0f * ((float)samples))) * 100.0f;
+
+ if ((useVad) && (clc.voipPower < cl_voipVADThreshold->value))
+ {
+ CL_VoipNewGeneration(); // no "talk" for at least 1/4 second.
+ }
+ else
+ {
+ clc.voipOutgoingDataSize = bytes;
+ clc.voipOutgoingDataFrames = voipFrames;
+
+ Com_DPrintf("VoIP: Send %d frames, %d bytes, %f power\n", voipFrames, bytes, clc.voipPower);
+
+#if 0
+ static FILE *encio = NULL;
+ if (encio == NULL) encio = fopen("voip-outgoing-encoded.bin", "wb");
+ if (encio != NULL) { fwrite(clc.voipOutgoingData, bytes, 1, encio); fflush(encio); }
+ static FILE *decio = NULL;
+ if (decio == NULL) decio = fopen("voip-outgoing-decoded.bin", "wb");
+ if (decio != NULL) { fwrite(sampbuffer, voipFrames * VOIP_MAX_FRAME_SAMPLES * 2, 1, decio); fflush(decio); }
+#endif
+ }
+ }
+ }
+
+ // User requested we stop recording, and we've now processed the last of
+ // any previously-buffered data. Pause the capture device, etc.
+ if (finalFrame)
+ {
+ S_StopCapture();
+ S_MasterGain(1.0f);
+ clc.voipPower = 0.0f; // force this value so it doesn't linger.
+ }
+}
+#endif
+
+/*
+=======================================================================
+
+CLIENT RELIABLE COMMAND COMMUNICATION
+
+=======================================================================
+*/
+
+/*
+======================
+CL_AddReliableCommand
+
+The given command will be transmitted to the server, and is gauranteed to
+not have future usercmd_t executed before it is executed
+======================
+*/
+void CL_AddReliableCommand(const char *cmd, bool isDisconnectCmd)
+{
+ int unacknowledged = clc.reliableSequence - clc.reliableAcknowledge;
+
+ // if we would be losing an old command that hasn't been acknowledged,
+ // we must drop the connection
+ // also leave one slot open for the disconnect command in this case.
+
+ if ((isDisconnectCmd && unacknowledged > MAX_RELIABLE_COMMANDS) ||
+ (!isDisconnectCmd && unacknowledged >= MAX_RELIABLE_COMMANDS))
+ {
+ if (com_errorEntered)
+ return;
+ else
+ Com_Error(ERR_DROP, "Client command overflow");
+ }
+
+ Q_strncpyz(
+ clc.reliableCommands[++clc.reliableSequence & (MAX_RELIABLE_COMMANDS - 1)], cmd, sizeof(*clc.reliableCommands));
+}
+
+/*
+=======================================================================
+
+CLIENT SIDE DEMO RECORDING
+
+=======================================================================
+*/
+
+/*
+====================
+CL_WriteDemoMessage
+
+Dumps the current net message, prefixed by the length
+====================
+*/
+void CL_WriteDemoMessage(msg_t *msg, int headerBytes)
+{
+ int len, swlen;
+
+ // write the packet sequence
+ len = clc.serverMessageSequence;
+ swlen = LittleLong(len);
+ FS_Write(&swlen, 4, clc.demofile);
+ // skip the packet sequencing information
+ len = msg->cursize - headerBytes;
+ swlen = LittleLong(len);
+ FS_Write(&swlen, 4, clc.demofile);
+ FS_Write(msg->data + headerBytes, len, clc.demofile);
+}
+
+/*
+====================
+CL_StopRecording_f
+
+stop recording a demo
+====================
+*/
+void CL_StopRecord_f(void)
+{
+ int len;
+
+ if (!clc.demorecording)
+ {
+ Com_Printf("Not recording a demo.\n");
+ return;
+ }
+
+ // finish up
+ len = -1;
+ FS_Write(&len, 4, clc.demofile);
+ FS_Write(&len, 4, clc.demofile);
+ FS_FCloseFile(clc.demofile);
+ clc.demofile = 0;
+ clc.demorecording = false;
+ clc.spDemoRecording = false;
+ Com_Printf("Stopped demo.\n");
+}
+
+/*
+==================
+CL_DemoFilename
+==================
+*/
+static void CL_DemoFilename(int number, char *fileName, int fileNameSize)
+{
+ int a, b, c, d;
+
+ if (number < 0 || number > 9999) number = 9999;
+
+ a = number / 1000;
+ number -= a * 1000;
+ b = number / 100;
+ number -= b * 100;
+ c = number / 10;
+ number -= c * 10;
+ d = number;
+
+ Com_sprintf(fileName, fileNameSize, "demo%i%i%i%i", a, b, c, d);
+}
+
+/*
+====================
+CL_Record_f
+
+record <demoname>
+
+Begins recording a demo from the current position
+====================
+*/
+static char demoName[MAX_QPATH]; // compiler bug workaround
+
+static void CL_Record_f(void)
+{
+ char name[MAX_OSPATH];
+ byte bufData[MAX_MSGLEN];
+ msg_t buf;
+ int i;
+ int len;
+ entityState_t *ent;
+ entityState_t nullstate;
+
+ if (Cmd_Argc() > 2)
+ {
+ Com_Printf("record <demoname>\n");
+ return;
+ }
+
+ if (clc.demorecording)
+ {
+ if (!clc.spDemoRecording)
+ {
+ Com_Printf("Already recording.\n");
+ }
+ return;
+ }
+
+ if (clc.state != CA_ACTIVE)
+ {
+ Com_Printf("You must be in a level to record.\n");
+ return;
+ }
+
+ // sync 0 doesn't prevent recording, so not forcing it off .. everyone does g_sync 1 ; record ; g_sync 0 ..
+ if (NET_IsLocalAddress(clc.serverAddress) && !Cvar_VariableValue("g_synchronousClients"))
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: You should set 'g_synchronousClients 1' for smoother demo recording\n");
+ }
+
+ if (Cmd_Argc() == 2)
+ {
+ const char *s = Cmd_Argv(1);
+ Q_strncpyz(demoName, s, sizeof(demoName));
+ Com_sprintf(
+ name, sizeof(name),
+ "demos/%s.%s%d", demoName, DEMOEXT,
+ (clc.netchan.alternateProtocol == 0 ?
+ PROTOCOL_VERSION : clc.netchan.alternateProtocol == 1 ? 70 : 69));
+ }
+ else
+ {
+ int number;
+
+ // scan for a free demo name
+ for (number = 0; number <= 9999; number++)
+ {
+ CL_DemoFilename(number, demoName, sizeof(demoName));
+ Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, PROTOCOL_VERSION);
+
+ if (!FS_FileExists(name)) break; // file doesn't exist
+ }
+ }
+
+ // open the demo file
+
+ Com_Printf("recording to %s.\n", name);
+ clc.demofile = FS_FOpenFileWrite(name);
+ if (!clc.demofile)
+ {
+ Com_Printf("ERROR: couldn't open.\n");
+ return;
+ }
+ clc.demorecording = true;
+ if (Cvar_VariableValue("ui_recordSPDemo"))
+ {
+ clc.spDemoRecording = true;
+ }
+ else
+ {
+ clc.spDemoRecording = false;
+ }
+
+ Q_strncpyz(clc.demoName, demoName, sizeof(clc.demoName));
+
+ // don't start saving messages until a non-delta compressed message is received
+ clc.demowaiting = true;
+
+ // write out the gamestate message
+ MSG_Init(&buf, bufData, sizeof(bufData));
+ MSG_Bitstream(&buf);
+
+ // NOTE, MRE: all server->client messages now acknowledge
+ MSG_WriteLong(&buf, clc.reliableSequence);
+
+ MSG_WriteByte(&buf, svc_gamestate);
+ MSG_WriteLong(&buf, clc.serverCommandSequence);
+
+ // configstrings
+ for (i = 0; i < MAX_CONFIGSTRINGS; i++)
+ {
+ if (!cl.gameState.stringOffsets[i])
+ {
+ continue;
+ }
+ const char *s = cl.gameState.stringData + cl.gameState.stringOffsets[i];
+ MSG_WriteByte(&buf, svc_configstring);
+ MSG_WriteShort(&buf, i);
+ MSG_WriteBigString(&buf, s);
+ }
+
+ // baselines
+ ::memset(&nullstate, 0, sizeof(nullstate));
+ for (i = 0; i < MAX_GENTITIES; i++)
+ {
+ ent = &cl.entityBaselines[i];
+ if (!ent->number)
+ {
+ continue;
+ }
+ MSG_WriteByte(&buf, svc_baseline);
+ MSG_WriteDeltaEntity(clc.netchan.alternateProtocol, &buf, &nullstate, ent, true);
+ }
+
+ MSG_WriteByte(&buf, svc_EOF);
+
+ // finished writing the gamestate stuff
+
+ // write the client num
+ MSG_WriteLong(&buf, clc.clientNum);
+ // write the checksum feed
+ MSG_WriteLong(&buf, clc.checksumFeed);
+
+ // finished writing the client packet
+ MSG_WriteByte(&buf, svc_EOF);
+
+ // write it to the demo file
+ len = LittleLong(clc.serverMessageSequence - 1);
+ FS_Write(&len, 4, clc.demofile);
+
+ len = LittleLong(buf.cursize);
+ FS_Write(&len, 4, clc.demofile);
+ FS_Write(buf.data, buf.cursize, clc.demofile);
+
+ // the rest of the demo file will be copied from net messages
+}
+
+/*
+=======================================================================
+
+CLIENT SIDE DEMO PLAYBACK
+
+=======================================================================
+*/
+
+/*
+=================
+CL_DemoFrameDurationSDev
+=================
+*/
+static float CL_DemoFrameDurationSDev(void)
+{
+ int i;
+ int numFrames;
+ float mean = 0.0f;
+ float variance = 0.0f;
+
+ if ((clc.timeDemoFrames - 1) > MAX_TIMEDEMO_DURATIONS)
+ numFrames = MAX_TIMEDEMO_DURATIONS;
+ else
+ numFrames = clc.timeDemoFrames - 1;
+
+ for (i = 0; i < numFrames; i++) mean += clc.timeDemoDurations[i];
+ mean /= numFrames;
+
+ for (i = 0; i < numFrames; i++)
+ {
+ float x = clc.timeDemoDurations[i];
+
+ variance += ((x - mean) * (x - mean));
+ }
+ variance /= numFrames;
+
+ return sqrt(variance);
+}
+
+/*
+=================
+CL_DemoCompleted
+=================
+*/
+void CL_DemoCompleted(void)
+{
+ char buffer[MAX_STRING_CHARS];
+
+ if (cl_timedemo && cl_timedemo->integer)
+ {
+ int time;
+
+ time = Sys_Milliseconds() - clc.timeDemoStart;
+ if (time > 0)
+ {
+ // Millisecond times are frame durations:
+ // minimum/average/maximum/std deviation
+ Com_sprintf(buffer, sizeof(buffer), "%i frames %3.1f seconds %3.1f fps %d.0/%.1f/%d.0/%.1f ms\n",
+ clc.timeDemoFrames, time / 1000.0, clc.timeDemoFrames * 1000.0 / time, clc.timeDemoMinDuration,
+ time / (float)clc.timeDemoFrames, clc.timeDemoMaxDuration, CL_DemoFrameDurationSDev());
+ Com_Printf("%s", buffer);
+
+ // Write a log of all the frame durations
+ if (cl_timedemoLog && strlen(cl_timedemoLog->string) > 0)
+ {
+ int i;
+ int numFrames;
+ fileHandle_t f;
+
+ if ((clc.timeDemoFrames - 1) > MAX_TIMEDEMO_DURATIONS)
+ numFrames = MAX_TIMEDEMO_DURATIONS;
+ else
+ numFrames = clc.timeDemoFrames - 1;
+
+ f = FS_FOpenFileWrite(cl_timedemoLog->string);
+ if (f)
+ {
+ FS_Printf(f, "# %s", buffer);
+
+ for (i = 0; i < numFrames; i++) FS_Printf(f, "%d\n", clc.timeDemoDurations[i]);
+
+ FS_FCloseFile(f);
+ Com_Printf("%s written\n", cl_timedemoLog->string);
+ }
+ else
+ {
+ Com_Printf("Couldn't open %s for writing\n", cl_timedemoLog->string);
+ }
+ }
+ }
+ }
+
+ CL_Disconnect(true);
+ CL_NextDemo();
+}
+
+/*
+=================
+CL_ReadDemoMessage
+=================
+*/
+void CL_ReadDemoMessage(void)
+{
+ int r;
+ msg_t buf;
+ byte bufData[MAX_MSGLEN];
+ int s;
+
+ if (!clc.demofile)
+ {
+ CL_DemoCompleted();
+ return;
+ }
+
+ // get the sequence number
+ r = FS_Read(&s, 4, clc.demofile);
+ if (r != 4)
+ {
+ CL_DemoCompleted();
+ return;
+ }
+ clc.serverMessageSequence = LittleLong(s);
+
+ // init the message
+ MSG_Init(&buf, bufData, sizeof(bufData));
+
+ // get the length
+ r = FS_Read(&buf.cursize, 4, clc.demofile);
+ if (r != 4)
+ {
+ CL_DemoCompleted();
+ return;
+ }
+ buf.cursize = LittleLong(buf.cursize);
+ if (buf.cursize == -1)
+ {
+ CL_DemoCompleted();
+ return;
+ }
+ if (buf.cursize > buf.maxsize)
+ {
+ Com_Error(ERR_DROP, "CL_ReadDemoMessage: demoMsglen > MAX_MSGLEN");
+ }
+ r = FS_Read(buf.data, buf.cursize, clc.demofile);
+ if (r != buf.cursize)
+ {
+ Com_Printf("Demo file was truncated.\n");
+ CL_DemoCompleted();
+ return;
+ }
+
+ clc.lastPacketTime = cls.realtime;
+ buf.readcount = 0;
+ CL_ParseServerMessage(&buf);
+}
+
+/*
+====================
+CL_WalkDemoExt
+====================
+*/
+static int CL_WalkDemoExt(const char *arg, char *name, int *demofile)
+{
+ int i;
+ *demofile = 0;
+
+ Com_sprintf(name, MAX_OSPATH, "demos/%s.%s%d", arg, DEMOEXT, PROTOCOL_VERSION);
+ FS_FOpenFileRead(name, demofile, true);
+
+ if (*demofile)
+ {
+ Com_Printf("Demo file: %s\n", name);
+ return PROTOCOL_VERSION;
+ }
+
+ Com_Printf("Not found: %s\n", name);
+
+ for (i = 0; demo_protocols[i]; ++i)
+ {
+ if (demo_protocols[i] == PROTOCOL_VERSION) continue;
+
+ Com_sprintf(name, MAX_OSPATH, "demos/%s.%s%d", arg, DEMOEXT, demo_protocols[i]);
+ FS_FOpenFileRead(name, demofile, true);
+ if (*demofile)
+ {
+ Com_Printf("Demo file: %s\n", name);
+
+ return demo_protocols[i];
+ }
+ else
+ Com_Printf("Not found: %s\n", name);
+ }
+
+ return -1;
+}
+
+/*
+====================
+CL_CompleteDemoName
+====================
+*/
+static void CL_CompleteDemoName(char *args, int argNum)
+{
+ if (argNum == 2)
+ {
+ char demoExt[16];
+
+ Com_sprintf(demoExt, sizeof(demoExt), ".%s%d", DEMOEXT, PROTOCOL_VERSION);
+ Field_CompleteFilename("demos", demoExt, true, true);
+ }
+}
+
+/*
+====================
+CL_PlayDemo_f
+
+demo <demoname>
+
+====================
+*/
+void CL_PlayDemo_f(void)
+{
+ char name[MAX_OSPATH];
+ const char *ext_test;
+ int protocol, i;
+ char retry[MAX_OSPATH];
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf("demo <demoname>\n");
+ return;
+ }
+
+ // make sure a local server is killed
+ // 2 means don't force disconnect of local client
+ Cvar_Set("sv_killserver", "2");
+
+ // open the demo file
+ const char *arg = Cmd_Argv(1);
+
+ CL_Disconnect(true);
+
+ // check for an extension .DEMOEXT_?? (?? is protocol)
+ ext_test = strrchr(arg, '.');
+
+ if (ext_test && !Q_stricmpn(ext_test + 1, DEMOEXT, ARRAY_LEN(DEMOEXT) - 1))
+ {
+ protocol = atoi(ext_test + ARRAY_LEN(DEMOEXT));
+
+ for (i = 0; demo_protocols[i]; i++)
+ {
+ if (demo_protocols[i] == protocol) break;
+ }
+
+ if (demo_protocols[i] || protocol == PROTOCOL_VERSION)
+ {
+ Com_sprintf(name, sizeof(name), "demos/%s", arg);
+ FS_FOpenFileRead(name, &clc.demofile, true);
+ }
+ else
+ {
+ int len;
+
+ Com_Printf("Protocol %d not supported for demos\n", protocol);
+ len = ext_test - arg;
+
+ if (len >= ARRAY_LEN(retry)) len = ARRAY_LEN(retry) - 1;
+
+ Q_strncpyz(retry, arg, len + 1);
+ retry[len] = '\0';
+ protocol = CL_WalkDemoExt(retry, name, &clc.demofile);
+ }
+ }
+ else
+ protocol = CL_WalkDemoExt(arg, name, &clc.demofile);
+
+ if (!clc.demofile)
+ {
+ Com_Error(ERR_DROP, "couldn't open %s", name);
+ return;
+ }
+ Q_strncpyz(clc.demoName, arg, sizeof(clc.demoName));
+
+ clc.state = CA_CONNECTED;
+ clc.demoplaying = true;
+ Q_strncpyz(clc.servername, arg, sizeof(clc.servername));
+ clc.netchan.alternateProtocol = (protocol == 69 ? 2 : protocol == 70 ? 1 : 0);
+
+ // read demo messages until connected
+ while (clc.state >= CA_CONNECTED && clc.state < CA_PRIMED)
+ {
+ CL_ReadDemoMessage();
+ }
+ // don't get the first snapshot this frame, to prevent the long
+ // time from the gamestate load from messing causing a time skip
+ clc.firstDemoFrameSkipped = false;
+}
+
+/*
+====================
+CL_StartDemoLoop
+
+Closing the main menu will restart the demo loop
+====================
+*/
+static void CL_StartDemoLoop(void)
+{
+ // start the demo loop again
+ Cbuf_AddText("d1\n");
+ Key_SetCatcher(Key_GetCatcher() & KEYCATCH_CONSOLE);
+}
+
+/*
+==================
+CL_NextDemo
+
+Called when a demo or cinematic finishes
+If the "nextdemo" cvar is set, that command will be issued
+==================
+*/
+void CL_NextDemo(void)
+{
+ char v[MAX_STRING_CHARS];
+
+ Q_strncpyz(v, Cvar_VariableString("nextdemo"), sizeof(v));
+ v[MAX_STRING_CHARS - 1] = 0;
+ Com_DPrintf("CL_NextDemo: %s\n", v);
+ if (!v[0])
+ {
+ return;
+ }
+
+ Cvar_Set("nextdemo", "");
+ Cbuf_AddText(v);
+ Cbuf_AddText("\n");
+ Cbuf_Execute();
+}
+
+/*
+==================
+CL_DemoState
+
+Returns the current state of the demo system
+==================
+*/
+demoState_t CL_DemoState(void)
+{
+ if (clc.demoplaying)
+ {
+ return DS_PLAYBACK;
+ }
+ else if (clc.demorecording)
+ {
+ return DS_RECORDING;
+ }
+ else
+ {
+ return DS_NONE;
+ }
+}
+
+/*
+==================
+CL_DemoPos
+
+Returns the current position of the demo
+==================
+*/
+int CL_DemoPos(void)
+{
+ if (clc.demoplaying || clc.demorecording)
+ {
+ return FS_FTell(clc.demofile);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/*
+==================
+CL_DemoName
+
+Returns the name of the demo
+==================
+*/
+void CL_DemoName(char *buffer, int size)
+{
+ if (clc.demoplaying || clc.demorecording)
+ {
+ Q_strncpyz(buffer, clc.demoName, size);
+ }
+ else if (size >= 1)
+ {
+ buffer[0] = '\0';
+ }
+}
+
+//======================================================================
+
+/*
+=====================
+CL_ClearState
+
+Called before parsing a gamestate
+=====================
+*/
+void CL_ClearState(void)
+{
+ // S_StopAllSounds();
+
+ ::memset(&cl, 0, sizeof(cl));
+}
+
+/*
+====================
+CL_UpdateGUID
+
+update cl_guid using QKEY_FILE and optional prefix
+====================
+*/
+static void CL_UpdateGUID(const char *prefix, int prefix_len)
+{
+ fileHandle_t f;
+ int len;
+
+ len = FS_SV_FOpenFileRead(QKEY_FILE, &f);
+ FS_FCloseFile(f);
+
+ if (len != QKEY_SIZE)
+ Cvar_Set("cl_guid", "");
+ else
+ Cvar_Set("cl_guid", Com_MD5File(QKEY_FILE, QKEY_SIZE, prefix, prefix_len));
+}
+
+static void CL_OldGame(void)
+{
+ if (cl_oldGameSet)
+ {
+ // change back to previous fs_game
+ cl_oldGameSet = false;
+ Cvar_Set2("fs_game", cl_oldGame, true);
+ FS_ConditionalRestart(clc.checksumFeed, false);
+ }
+}
+
+/*
+=====================
+CL_Disconnect
+
+Called when a connection, demo, or cinematic is being terminated.
+Goes from a connected state to either a menu state or a console state
+Sends a disconnect message to the server
+This is also called on Com_Error and Com_Quit, so it shouldn't cause any errors
+=====================
+*/
+void CL_Disconnect(bool showMainMenu)
+{
+ if (!com_cl_running || !com_cl_running->integer)
+ {
+ return;
+ }
+
+ // shutting down the client so enter full screen ui mode
+ Cvar_Set("r_uiFullScreen", "1");
+
+ if (clc.demorecording)
+ {
+ CL_StopRecord_f();
+ }
+
+ if (clc.download)
+ {
+ FS_FCloseFile(clc.download);
+ clc.download = 0;
+ }
+ *clc.downloadTempName = *clc.downloadName = 0;
+ Cvar_Set("cl_downloadName", "");
+
+#ifdef USE_MUMBLE
+ if (cl_useMumble->integer && mumble_islinked())
+ {
+ Com_Printf("Mumble: Unlinking from Mumble application\n");
+ mumble_unlink();
+ }
+#endif
+
+#ifdef USE_VOIP
+ if (cl_voipSend->integer)
+ {
+ int tmp = cl_voipUseVAD->integer;
+ cl_voipUseVAD->integer = 0; // disable this for a moment.
+ clc.voipOutgoingDataSize = 0; // dump any pending VoIP transmission.
+ Cvar_Set("cl_voipSend", "0");
+ CL_CaptureVoip(); // clean up any state...
+ cl_voipUseVAD->integer = tmp;
+ }
+
+ if (clc.voipCodecInitialized)
+ {
+ int i;
+ opus_encoder_destroy(clc.opusEncoder);
+ for (i = 0; i < MAX_CLIENTS; i++)
+ {
+ opus_decoder_destroy(clc.opusDecoder[i]);
+ }
+ }
+ Cmd_RemoveCommand("voip");
+#endif
+
+ if (clc.demofile)
+ {
+ FS_FCloseFile(clc.demofile);
+ clc.demofile = 0;
+ }
+
+ if (cls.ui && showMainMenu)
+ {
+ VM_Call(cls.ui, UI_SET_ACTIVE_MENU - (cls.uiInterface == 2 ? 2 : 0), UIMENU_NONE);
+ }
+
+ SCR_StopCinematic();
+ S_ClearSoundBuffer();
+
+ // send a disconnect message to the server
+ // send it a few times in case one is dropped
+ if (clc.state >= CA_CONNECTED)
+ {
+ CL_AddReliableCommand("disconnect", true);
+ CL_WritePacket();
+ CL_WritePacket();
+ CL_WritePacket();
+ }
+
+ // Remove pure paks
+ FS_PureServerSetLoadedPaks("", "");
+ FS_PureServerSetReferencedPaks("", "");
+
+ CL_ClearState();
+
+ // wipe the client connection
+ ::memset(&clc, 0, sizeof(clc));
+
+ clc.state = CA_DISCONNECTED;
+
+ CL_ProtocolSpecificCommandsInit();
+
+ // allow cheats locally
+ Cvar_Set("sv_cheats", "1");
+
+ // not connected to a pure server anymore
+ cl_connectedToPureServer = false;
+
+#ifdef USE_VOIP
+ // not connected to voip server anymore.
+ clc.voipEnabled = false;
+#endif
+
+ // Stop recording any video
+ if (CL_VideoRecording())
+ {
+ // Finish rendering current frame
+ SCR_UpdateScreen();
+ CL_CloseAVI();
+ }
+
+ CL_UpdateGUID(NULL, 0);
+
+ if (!noGameRestart)
+ CL_OldGame();
+ else
+ noGameRestart = false;
+}
+
+/*
+===================
+CL_ForwardCommandToServer
+
+adds the current command line as a clientCommand
+things like godmode, noclip, etc, are commands directed to the server,
+so when they are typed in at the console, they will need to be forwarded.
+===================
+*/
+void CL_ForwardCommandToServer(const char *string)
+{
+ const char *cmd = Cmd_Argv(0);
+
+ // ignore key up commands
+ if (cmd[0] == '-')
+ {
+ return;
+ }
+
+ if (clc.demoplaying || clc.state < CA_CONNECTED || cmd[0] == '+')
+ {
+ Com_Printf("Unknown command \"%s" S_COLOR_WHITE "\"\n", cmd);
+ return;
+ }
+
+ if (Cmd_Argc() > 1)
+ {
+ CL_AddReliableCommand(string, false);
+ }
+ else
+ {
+ CL_AddReliableCommand(cmd, false);
+ }
+}
+
+/*
+===================
+CL_RequestMotd
+
+===================
+*/
+static void CL_RequestMotd(void)
+{
+ char info[MAX_INFO_STRING];
+
+ if (!cl_motd->integer)
+ {
+ return;
+ }
+ Com_Printf("Resolving %s\n", MASTER_SERVER_NAME);
+
+ switch (NET_StringToAdr(MASTER_SERVER_NAME, &cls.updateServer, NA_UNSPEC))
+ {
+ case 0:
+ Com_Printf("Couldn't resolve master address\n");
+ return;
+
+ case 2:
+ cls.updateServer.port = BigShort(PORT_MASTER);
+ default:
+ break;
+ }
+
+ Com_Printf("%s resolved to %s\n", MASTER_SERVER_NAME, NET_AdrToStringwPort(cls.updateServer));
+
+ info[0] = 0;
+
+ Com_sprintf(cls.updateChallenge, sizeof(cls.updateChallenge), "%i", ((rand() << 16) ^ rand()) ^ Com_Milliseconds());
+
+ Info_SetValueForKey(info, "challenge", cls.updateChallenge);
+
+ NET_OutOfBandPrint(NS_CLIENT, cls.updateServer, "getmotd%s", info);
+}
+
+/*
+======================================================================
+
+CONSOLE COMMANDS
+
+======================================================================
+*/
+
+/*
+==================
+CL_ShowIP_f
+==================
+*/
+static void CL_ShowIP_f(void) { Sys_ShowIP(); }
+
+/*
+==================
+CL_ForwardToServer_f
+==================
+*/
+static void CL_ForwardToServer_f(void)
+{
+ if (clc.state != CA_ACTIVE || clc.demoplaying)
+ {
+ Com_Printf("Not connected to a server.\n");
+ return;
+ }
+
+ // don't forward the first argument
+ if (Cmd_Argc() > 1)
+ {
+ CL_AddReliableCommand(Cmd_Args(), false);
+ }
+}
+
+/*
+==================
+CL_Disconnect_f
+==================
+*/
+void CL_Disconnect_f(void)
+{
+ SCR_StopCinematic();
+ if (clc.state != CA_DISCONNECTED && clc.state != CA_CINEMATIC)
+ {
+ Com_Error(ERR_DISCONNECT, "Disconnected from server");
+ }
+}
+
+/*
+================
+CL_Reconnect_f
+
+================
+*/
+static void CL_Reconnect_f(void)
+{
+ if (!strlen(cl_reconnectArgs)) return;
+ Cbuf_AddText(va("connect %s\n", cl_reconnectArgs));
+}
+
+/*
+================
+CL_Connect_f
+
+================
+*/
+void CL_Connect_f(void)
+{
+ const char *server;
+ int alternateProtocol;
+ const char *serverString;
+ int argc = Cmd_Argc();
+ netadrtype_t family = NA_UNSPEC;
+
+ if (argc < 2 || argc > 4)
+ {
+ Com_Printf("usage: connect [-4|-6] server [-g|-1]\n");
+ return;
+ }
+
+ alternateProtocol = 0;
+ if (argc == 2)
+ {
+ }
+ else if (!strcmp(Cmd_Argv(argc - 1), "-g"))
+ {
+ alternateProtocol = 1;
+ --argc;
+ }
+ else if (!strcmp(Cmd_Argv(argc - 1), "-1"))
+ {
+ alternateProtocol = 2;
+ --argc;
+ }
+ else if (argc == 4)
+ {
+ --argc;
+ }
+
+ if (argc == 2)
+ server = Cmd_Argv(1);
+ else
+ {
+ if (!strcmp(Cmd_Argv(1), "-4"))
+ family = NA_IP;
+ else if (!strcmp(Cmd_Argv(1), "-6"))
+ family = NA_IP6;
+ else
+ Com_Printf("warning: only -4 or -6 as address type understood.\n");
+
+ server = Cmd_Argv(2);
+ }
+
+ // save arguments for reconnect
+ Q_strncpyz(cl_reconnectArgs, Cmd_Args(), sizeof(cl_reconnectArgs));
+
+ // clear any previous "server full" type messages
+ clc.serverMessage[0] = 0;
+
+ if (com_sv_running->integer && !strcmp(server, "localhost"))
+ {
+ // if running a local server, kill it
+ SV_Shutdown("Server quit");
+ }
+
+ // make sure a local server is killed
+ Cvar_Set("sv_killserver", "1");
+ SV_Frame(0);
+
+ noGameRestart = true;
+ CL_Disconnect(true);
+
+ Q_strncpyz(clc.servername, server, sizeof(clc.servername));
+
+ if (!NET_StringToAdr(clc.servername, &clc.serverAddress, family))
+ {
+ Com_Printf("Bad server address\n");
+ clc.state = CA_DISCONNECTED;
+ CL_ProtocolSpecificCommandsInit();
+ return;
+ }
+ if (clc.serverAddress.port == 0)
+ {
+ clc.serverAddress.port = BigShort(PORT_SERVER);
+ }
+ clc.serverAddress.alternateProtocol = alternateProtocol;
+
+ serverString = NET_AdrToStringwPort(clc.serverAddress);
+
+ Com_Printf("%s resolved to %s\n", clc.servername, serverString);
+
+ if (cl_guidServerUniq->integer)
+ CL_UpdateGUID(serverString, strlen(serverString));
+ else
+ CL_UpdateGUID(NULL, 0);
+
+ clc.challenge2[0] = '\0';
+ clc.sendSignature = false;
+
+ // if we aren't playing on a lan, we need to authenticate
+ // with the cd key
+ if (NET_IsLocalAddress(clc.serverAddress))
+ {
+ clc.state = CA_CHALLENGING;
+ clc.sendSignature = true;
+ }
+ else
+ {
+ clc.state = CA_CONNECTING;
+
+ // Set a client challenge number that ideally is mirrored back by the server.
+ clc.challenge = ((rand() << 16) ^ rand()) ^ Com_Milliseconds();
+ }
+
+ Key_SetCatcher(Key_GetCatcher() & KEYCATCH_CONSOLE);
+ clc.connectTime = -99999; // CL_CheckForResend() will fire immediately
+ clc.connectPacketCount = 0;
+}
+
+#define MAX_RCON_MESSAGE 1024
+
+/*
+==================
+CL_CompleteRcon
+==================
+*/
+static void CL_CompleteRcon(char *args, int argNum)
+{
+ if (argNum == 2)
+ {
+ // Skip "rcon "
+ char *p = Com_SkipTokens(args, 1, " ");
+
+ if (p > args) Field_CompleteCommand(p, true, true);
+ }
+}
+
+/*
+=====================
+CL_Rcon_f
+
+ Send the rest of the command line over as
+ an unconnected command.
+=====================
+*/
+static void CL_Rcon_f(void)
+{
+ char message[MAX_RCON_MESSAGE];
+ netadr_t to;
+
+ if (!rcon_client_password->string[0])
+ {
+ Com_Printf(
+ "You must set 'rconpassword' before\n"
+ "issuing an rcon command.\n");
+ return;
+ }
+
+ message[0] = -1;
+ message[1] = -1;
+ message[2] = -1;
+ message[3] = -1;
+ message[4] = 0;
+
+ Q_strcat(message, MAX_RCON_MESSAGE, "rcon ");
+
+ Q_strcat(message, MAX_RCON_MESSAGE, rcon_client_password->string);
+ Q_strcat(message, MAX_RCON_MESSAGE, " ");
+
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543
+ Q_strcat(message, MAX_RCON_MESSAGE, Cmd_Cmd() + 5);
+
+ if (clc.state >= CA_CONNECTED)
+ {
+ to = clc.netchan.remoteAddress;
+ }
+ else
+ {
+ if (!strlen(rconAddress->string))
+ {
+ Com_Printf(
+ "You must either be connected,\n"
+ "or set the 'rconAddress' cvar\n"
+ "to issue rcon commands\n");
+
+ return;
+ }
+ NET_StringToAdr(rconAddress->string, &to, NA_UNSPEC);
+ if (to.port == 0)
+ {
+ to.port = BigShort(PORT_SERVER);
+ }
+ }
+
+ NET_SendPacket(NS_CLIENT, strlen(message) + 1, message, to);
+}
+
+/*
+=================
+CL_SendPureChecksums
+=================
+*/
+static void CL_SendPureChecksums(void)
+{
+ char cMsg[MAX_INFO_VALUE];
+
+ // if we are pure we need to send back a command with our referenced pk3 checksums
+ Com_sprintf(cMsg, sizeof(cMsg), "cp %d %s", cl.serverId, FS_ReferencedPakPureChecksums());
+
+ CL_AddReliableCommand(cMsg, false);
+}
+
+/*
+=================
+CL_ResetPureClientAtServer
+=================
+*/
+static void CL_ResetPureClientAtServer(void) { CL_AddReliableCommand("vdr", false); }
+
+/*
+=================
+CL_Snd_Restart
+
+Restart the sound subsystem
+=================
+*/
+static void CL_Snd_Shutdown(void)
+{
+ S_Shutdown();
+ cls.soundStarted = false;
+}
+/*
+==================
+CL_PK3List_f
+==================
+*/
+static void CL_OpenedPK3List_f(void) { Com_Printf("Opened PK3 Names: %s\n", FS_LoadedPakNames(false)); }
+
+/*
+==================
+CL_PureList_f
+==================
+*/
+static void CL_ReferencedPK3List_f(void) { Com_Printf("Referenced PK3 Names: %s\n", FS_ReferencedPakNames(false)); }
+
+/*
+==================
+CL_Configstrings_f
+==================
+*/
+static void CL_Configstrings_f(void)
+{
+ int i;
+ int ofs;
+
+ if (clc.state != CA_ACTIVE)
+ {
+ Com_Printf("Not connected to a server.\n");
+ return;
+ }
+
+ for (i = 0; i < MAX_CONFIGSTRINGS; i++)
+ {
+ ofs = cl.gameState.stringOffsets[i];
+ if (!ofs)
+ {
+ continue;
+ }
+ Com_Printf("%4i: %s\n", i, cl.gameState.stringData + ofs);
+ }
+}
+
+/*
+==============
+CL_Clientinfo_f
+==============
+*/
+static void CL_Clientinfo_f(void)
+{
+ Com_Printf("--------- Client Information ---------\n");
+ Com_Printf("state: %i\n", clc.state);
+ Com_Printf("Server: %s\n", clc.servername);
+ Com_Printf("User info settings:\n");
+ Info_Print(Cvar_InfoString(CVAR_USERINFO));
+ Com_Printf("--------------------------------------\n");
+}
+
+//====================================================================
+
+/*
+=================
+CL_DownloadsComplete
+
+Called when all downloading has been completed
+=================
+*/
+static void CL_DownloadsComplete(void)
+{
+ Com_Printf("Downloads complete\n");
+
+ // if we downloaded with cURL
+ if (clc.cURLUsed)
+ {
+ clc.cURLUsed = false;
+ CL_cURL_Shutdown();
+ if (clc.cURLDisconnected)
+ {
+ if (clc.downloadRestart)
+ {
+ if (!clc.activeCURLNotGameRelated) FS_Restart(clc.checksumFeed);
+ clc.downloadRestart = false;
+ }
+ clc.cURLDisconnected = false;
+ if (!clc.activeCURLNotGameRelated) CL_Reconnect_f();
+ return;
+ }
+ }
+
+ // if we downloaded files we need to restart the file system
+ if (clc.downloadRestart)
+ {
+ clc.downloadRestart = false;
+
+ FS_Restart(clc.checksumFeed); // We possibly downloaded a pak, restart the file system to load it
+
+ // inform the server so we get new gamestate info
+ CL_AddReliableCommand("donedl", false);
+
+ // by sending the donedl command we request a new gamestate
+ // so we don't want to load stuff yet
+ return;
+ }
+ else
+ {
+ FS_ClearPakReferences(0);
+ }
+
+ // let the client game init and load data
+ clc.state = CA_LOADING;
+
+ // Pump the loop, this may change gamestate!
+ Com_EventLoop();
+
+ // if the gamestate was changed by calling Com_EventLoop
+ // then we loaded everything already and we don't want to do it again.
+ if (clc.state != CA_LOADING)
+ {
+ return;
+ }
+
+ // starting to load a map so we get out of full screen ui mode
+ Cvar_Set("r_uiFullScreen", "0");
+
+ // flush client memory and start loading stuff
+ // this will also (re)load the UI
+ // if this is a local client then only the client part of the hunk
+ // will be cleared, note that this is done after the hunk mark has been set
+ CL_FlushMemory();
+
+ // initialize the CGame
+ cls.cgameStarted = true;
+ CL_InitCGame();
+
+ // set pure checksums
+ CL_SendPureChecksums();
+
+ CL_WritePacket();
+ CL_WritePacket();
+ CL_WritePacket();
+}
+
+/*
+=================
+CL_BeginDownload
+
+Requests a file to download from the server. Stores it in the current
+game directory.
+=================
+*/
+static void CL_BeginDownload(const char *localName, const char *remoteName)
+{
+ Com_DPrintf(
+ "***** CL_BeginDownload *****\n"
+ "Localname: %s\n"
+ "Remotename: %s\n"
+ "****************************\n",
+ localName, remoteName);
+
+ Q_strncpyz(clc.downloadName, localName, sizeof(clc.downloadName));
+ Com_sprintf(clc.downloadTempName, sizeof(clc.downloadTempName), "%s.tmp", localName);
+
+ // Set so UI gets access to it
+ Cvar_Set("cl_downloadName", remoteName);
+ Cvar_Set("cl_downloadSize", "0");
+ Cvar_Set("cl_downloadCount", "0");
+ Cvar_SetValue("cl_downloadTime", cls.realtime);
+
+ clc.downloadBlock = 0; // Starting new file
+ clc.downloadCount = 0;
+
+ // Stop any errant looping sounds that may be playing
+ S_ClearLoopingSounds(true);
+
+ CL_AddReliableCommand(va("download %s", remoteName), false);
+}
+
+/*
+=================
+CL_NextDownload
+
+A download completed or failed
+=================
+*/
+void CL_NextDownload(void)
+{
+ char *s;
+ char *remoteName, *localName;
+ bool useCURL = false;
+ int prompt;
+
+ // A download has finished, check whether this matches a referenced checksum
+ if (*clc.downloadName && !clc.activeCURLNotGameRelated)
+ {
+ char *zippath = FS_BuildOSPath(Cvar_VariableString("fs_homepath"), clc.downloadName, "");
+ zippath[strlen(zippath) - 1] = '\0';
+
+ if (!FS_CompareZipChecksum(zippath)) Com_Error(ERR_DROP, "Incorrect checksum for file: %s", clc.downloadName);
+ }
+
+ *clc.downloadTempName = *clc.downloadName = 0;
+ Cvar_Set("cl_downloadName", "");
+
+ // We are looking to start a download here
+ if (*clc.downloadList)
+ {
+ // Prompt if we do not allow automatic downloads
+ prompt = com_downloadPrompt->integer;
+ if (!(prompt & DLP_TYPE_MASK) && !(cl_allowDownload->integer & DLF_ENABLE))
+ {
+ char files[MAX_INFO_STRING] = "";
+ char *name, *head;
+ const char *pure_msg;
+ const char *url_msg = "";
+ int i = 0, others = 0, swap = 0, max_list = 12;
+
+ // Set the download URL message
+ if ((clc.sv_allowDownload & DLF_ENABLE) && !(clc.sv_allowDownload & DLF_NO_REDIRECT))
+ {
+ url_msg = va("The server redirects to the following URL:\n%s", clc.sv_dlURL);
+ max_list -= 6;
+ }
+
+ // Make a pretty version of the download list
+ name = clc.downloadList;
+ if (*name == '@') name++;
+
+ do
+ {
+ // Copy remote name
+ head = name;
+ while (*head && *head != '@') head++;
+
+ swap = *head;
+ *head = 0;
+
+ if (i++ < max_list)
+ {
+ if (i > 1) Q_strcat(files, sizeof(files), ", ");
+ Q_strcat(files, sizeof(files), name);
+ }
+ else
+ {
+ others++;
+ }
+
+ *head = swap;
+ if (!swap) break;
+
+ // Skip local name
+ head++;
+ while (*head && *head != '@') head++;
+
+ name = head + 1;
+ } while (*head);
+
+ if (others)
+ {
+ Q_strcat(files, sizeof(files), va("(%d other file%s)\n", others, others > 1 ? "s" : ""));
+ }
+
+ // Set the pure message
+ if (cl_connectedToPureServer)
+ {
+ if (!(clc.sv_allowDownload & DLF_ENABLE) ||
+ ((clc.sv_allowDownload & DLF_NO_UDP) && (clc.sv_allowDownload & DLF_NO_REDIRECT)))
+ {
+ pure_msg =
+ "You are missing files required by the server. "
+ "The server does not allow downloading. "
+ "You must install these files manually:";
+ }
+ else
+ {
+ pure_msg =
+ "You are missing files required by the server. "
+ "You must download these files or disconnect:";
+ }
+ }
+ else
+ {
+ pure_msg =
+ "You are missing optional files provided by the "
+ "server. You may not need them to play but can "
+ "choose to download them anyway:";
+ }
+
+ Cvar_Set("com_downloadPromptText", va("%s\n\n%s\n%s", pure_msg, files, url_msg));
+ Cvar_Set("com_downloadPrompt", va("%d", DLP_SHOW));
+ return;
+ }
+
+ if (!(prompt & DLP_PROMPTED)) Cvar_Set("com_downloadPrompt", va("%d", prompt | DLP_PROMPTED));
+
+ prompt &= DLP_TYPE_MASK;
+
+ s = clc.downloadList;
+
+ // format is:
+ // @remotename@localname@remotename@localname, etc.
+
+ if (*s == '@') s++;
+ remoteName = s;
+
+ if ((s = strchr(s, '@')) == NULL)
+ {
+ CL_DownloadsComplete();
+ return;
+ }
+
+ *s++ = 0;
+ localName = s;
+ if ((s = strchr(s, '@')) != NULL)
+ *s++ = 0;
+ else
+ s = localName + strlen(localName); // point at the nul byte
+
+ if (((cl_allowDownload->integer & DLF_ENABLE) && !(cl_allowDownload->integer & DLF_NO_REDIRECT)) ||
+ prompt == DLP_CURL)
+ {
+ Com_Printf("Trying CURL download: %s; %s\n", localName, remoteName);
+ if (clc.sv_allowDownload & DLF_NO_REDIRECT)
+ {
+ Com_Printf(
+ "WARNING: server does not "
+ "allow download redirection "
+ "(sv_allowDownload is %d)\n",
+ clc.sv_allowDownload);
+ }
+ else if (!*clc.sv_dlURL)
+ {
+ Com_Printf(
+ "WARNING: server allows "
+ "download redirection, but does not "
+ "have sv_dlURL set\n");
+ }
+ else if (!CL_cURL_Init())
+ {
+ Com_Printf(
+ "WARNING: could not load "
+ "cURL library\n");
+ }
+ else
+ {
+ CL_cURL_BeginDownload(localName, va("%s/%s", clc.sv_dlURL, remoteName));
+ useCURL = true;
+ }
+ }
+ else if (!(clc.sv_allowDownload & DLF_NO_REDIRECT))
+ {
+ Com_Printf(
+ "WARNING: server allows download "
+ "redirection, but it disabled by client "
+ "configuration (cl_allowDownload is %d)\n",
+ cl_allowDownload->integer);
+ }
+ if (!useCURL)
+ {
+ Com_Printf("Trying UDP download: %s; %s\n", localName, remoteName);
+
+ if ((!(cl_allowDownload->integer & DLF_ENABLE) || (cl_allowDownload->integer & DLF_NO_UDP)) &&
+ prompt != DLP_UDP)
+ {
+ if (cl_connectedToPureServer)
+ {
+ Com_Error(ERR_DROP,
+ "Automatic downloads are "
+ "disabled on your client (cl_allowDownload is %d). "
+ "You can enable automatic downloads in the Options "
+ "menu.",
+ cl_allowDownload->integer);
+ return;
+ }
+
+ Com_Printf("WARNING: UDP downloads are disabled.\n");
+ CL_DownloadsComplete();
+ return;
+ }
+ else
+ {
+ CL_BeginDownload(localName, remoteName);
+ }
+ }
+ clc.downloadRestart = true;
+
+ // move over the rest
+ memmove(clc.downloadList, s, strlen(s) + 1);
+
+ return;
+ }
+
+ CL_DownloadsComplete();
+}
+
+/*
+=================
+CL_InitDownloads
+
+After receiving a valid game state, we valid the cgame and local zip files here
+and determine if we need to download them
+=================
+*/
+void CL_InitDownloads(void)
+{
+ if (FS_ComparePaks(clc.downloadList, sizeof(clc.downloadList), true))
+ {
+ Com_Printf("Need paks: %s\n", clc.downloadList);
+
+ Cvar_Set("com_downloadPrompt", "0");
+ if (*clc.downloadList)
+ {
+ // if autodownloading is not enabled on the server
+ clc.state = CA_CONNECTED;
+ *clc.downloadTempName = *clc.downloadName = 0;
+ Cvar_Set("cl_downloadName", "");
+ CL_NextDownload();
+ return;
+ }
+ }
+ CL_DownloadsComplete();
+}
+
+/*
+===============
+CL_UnloadRSAKeypair
+===============
+*/
+static void CL_UnloadRSAKeypair(void)
+{
+ rsa_public_key_clear(&cls.rsa.public_key);
+ rsa_private_key_clear(&cls.rsa.private_key);
+}
+
+/*
+===============
+CL_WriteRSAPublicKey
+===============
+*/
+static bool CL_WriteRSAPublicKey(void)
+{
+ struct nettle_buffer key_buffer;
+ fileHandle_t f;
+
+ f = FS_SV_FOpenFileWrite(RSA_PUBLIC_KEY_FILE);
+ if (!f) return false;
+
+ nettle_buffer_init(&key_buffer);
+ if (!rsa_keypair_to_sexp(&key_buffer, NULL, &cls.rsa.public_key, NULL))
+ {
+ FS_FCloseFile(f);
+ nettle_buffer_clear(&key_buffer);
+ return false;
+ }
+
+ FS_Write(key_buffer.contents, key_buffer.size, f);
+ FS_FCloseFile(f);
+
+ nettle_buffer_clear(&key_buffer);
+ return true;
+}
+
+/*
+===============
+CL_WriteRSAPrivateKey
+===============
+*/
+static bool CL_WriteRSAPrivateKey(void)
+{
+ struct nettle_buffer key_buffer;
+ fileHandle_t f;
+
+#ifndef _WIN32
+ int old_umask = umask(0377);
+#endif
+ f = FS_SV_FOpenFileWrite(RSA_PRIVATE_KEY_FILE);
+#ifndef _WIN32
+ umask(old_umask);
+#endif
+ if (!f) return false;
+
+ nettle_buffer_init(&key_buffer);
+ if (!rsa_keypair_to_sexp(&key_buffer, NULL, &cls.rsa.public_key, &cls.rsa.private_key))
+ {
+ FS_FCloseFile(f);
+ nettle_buffer_clear(&key_buffer);
+ return false;
+ }
+
+ FS_Write(key_buffer.contents, key_buffer.size, f);
+ FS_FCloseFile(f);
+
+ nettle_buffer_clear(&key_buffer);
+ return true;
+}
+
+/*
+===============
+CL_GenerateRSAKeypair
+
+public_key and private_key must already be inititalized before calling this
+function. This is done by CL_LoadRSAKeypair.
+===============
+*/
+static void CL_GenerateRSAKeypair(void)
+{
+ mpz_set_ui(cls.rsa.public_key.e, RSA_PUBLIC_EXPONENT);
+
+ int success = rsa_generate_keypair(
+ &cls.rsa.public_key, &cls.rsa.private_key, NULL, qnettle_random, NULL, NULL, RSA_KEY_LENGTH, 0);
+ if (success)
+ if (CL_WriteRSAPrivateKey())
+ if (CL_WriteRSAPublicKey())
+ {
+ Com_Printf("RSA keypair generated\n");
+ return;
+ }
+
+ // failure
+ CL_UnloadRSAKeypair();
+ Com_Printf("Error generating RSA keypair, setting cl_rsaAuth to 0\n");
+ Cvar_Set("cl_rsaAuth", "0");
+}
+
+/*
+===============
+CL_LoadRSAKeypair
+
+Attempt to load RSA keys from RSA_PRIVATE_KEY_FILE
+If this fails, generate a new keypair
+===============
+*/
+static void CL_LoadRSAKeypair(void)
+{
+ int len;
+ fileHandle_t f;
+ uint8_t *buf;
+
+ rsa_public_key_init(&cls.rsa.public_key);
+ rsa_private_key_init(&cls.rsa.private_key);
+
+ Com_DPrintf("Loading RSA private key from %s\n", RSA_PRIVATE_KEY_FILE);
+
+ len = FS_SV_FOpenFileRead(RSA_PRIVATE_KEY_FILE, &f);
+ if (!f)
+ {
+ Com_DPrintf("RSA private key not found, generating\n");
+ CL_GenerateRSAKeypair();
+ return;
+ }
+
+ if (len < 1)
+ {
+ Com_DPrintf("RSA private key empty, generating\n");
+ FS_FCloseFile(f);
+ CL_GenerateRSAKeypair();
+ return;
+ }
+
+ buf = (uint8_t *)Z_Malloc(len);
+ FS_Read(buf, len, f);
+ FS_FCloseFile(f);
+
+ if (!rsa_keypair_from_sexp(&cls.rsa.public_key, &cls.rsa.private_key, 0, len, buf))
+ {
+ memset(buf, 0, len);
+ Z_Free(buf);
+ CL_UnloadRSAKeypair();
+ Com_Error(ERR_FATAL, "Invalid RSA private key found.");
+ return;
+ }
+
+ memset(buf, 0, len);
+ Z_Free(buf);
+
+ len = FS_SV_FOpenFileRead(RSA_PUBLIC_KEY_FILE, &f);
+ if (!f || len < 1) CL_WriteRSAPublicKey();
+ if (f) FS_FCloseFile(f);
+
+ Com_DPrintf("RSA private key loaded\n");
+}
+
+/*
+=================
+CL_CheckForResend
+
+Resend a connect message if the last one has timed out
+=================
+*/
+static void CL_CheckForResend(void)
+{
+ int port;
+ char info[MAX_INFO_STRING];
+ char data[MAX_MSGLEN];
+
+ // don't send anything if playing back a demo
+ if (clc.demoplaying)
+ {
+ return;
+ }
+
+ // resend if we haven't gotten a reply yet
+ if (clc.state != CA_CONNECTING && clc.state != CA_CHALLENGING)
+ {
+ return;
+ }
+
+ if (cls.realtime - clc.connectTime < RETRANSMIT_TIMEOUT)
+ {
+ return;
+ }
+
+ clc.connectTime = cls.realtime; // for retransmit requests
+ clc.connectPacketCount++;
+
+ switch (clc.state)
+ {
+ case CA_CONNECTING:
+ // requesting a challenge
+
+ // The challenge request shall be followed by a client challenge so no malicious server can hijack this
+ // connection.
+ // Add the gamename so the server knows we're running the correct game or can reject the client
+ // with a meaningful message
+ if (clc.serverAddress.alternateProtocol == 2)
+ {
+ Com_sprintf(data, sizeof(data), "getchallenge");
+ }
+ else if (clc.serverAddress.alternateProtocol == 1)
+ {
+ Com_sprintf(data, sizeof(data), "getchallenge %d", clc.challenge);
+ }
+ else
+ Com_sprintf(data, sizeof(data), "getchallenge %d %s", clc.challenge, com_gamename->string);
+
+ NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "%s", data);
+ break;
+
+ case CA_CHALLENGING:
+ // sending back the challenge
+ port = Cvar_VariableValue("net_qport");
+
+ Q_strncpyz(info, Cvar_InfoString(CVAR_USERINFO), sizeof(info));
+ Info_SetValueForKey(info, "protocol",
+ va("%i",
+ (clc.serverAddress.alternateProtocol == 0 ? PROTOCOL_VERSION
+ : clc.serverAddress.alternateProtocol == 1 ? 70 : 69)));
+ Info_SetValueForKey(info, "qport", va("%i", port));
+ Info_SetValueForKey(info, "challenge", va("%i", clc.challenge));
+
+ if (cl_rsaAuth->integer && clc.sendSignature)
+ {
+ char public_key[RSA_STRING_LENGTH];
+ char signature[RSA_STRING_LENGTH];
+ struct sha256_ctx sha256_hash;
+ mpz_t n;
+
+ Info_SetValueForKey(info, "challenge2", clc.challenge2);
+
+ sha256_init(&sha256_hash);
+ sha256_update(&sha256_hash, strlen(info), (uint8_t *)info);
+
+ mpz_init(n);
+ rsa_sha256_sign(&cls.rsa.private_key, &sha256_hash, n);
+ mpz_get_str(signature, 16, n);
+ mpz_clear(n);
+
+ mpz_get_str(public_key, 16, cls.rsa.public_key.n);
+
+ Com_sprintf(data, sizeof(data), "connect \"%s\" %s %s", info, public_key, signature);
+ }
+ else
+ {
+ Com_sprintf(data, sizeof(data), "connect \"%s\"", info);
+ }
+
+ NET_OutOfBandData(NS_CLIENT, clc.serverAddress, (byte *)data, strlen(data));
+ // the most current userinfo has been sent, so watch for any
+ // newer changes to userinfo variables
+ cvar_modifiedFlags &= ~CVAR_USERINFO;
+ break;
+
+ default:
+ Com_Error(ERR_FATAL, "CL_CheckForResend: bad clc.state");
+ }
+}
+
+/*
+=====================
+CL_MapLoading
+
+A local server is starting to load a map, so update the
+screen to let the user know about it, then dump all client
+memory on the hunk from cgame, ui, and renderer
+=====================
+*/
+void CL_MapLoading(void)
+{
+ if (com_dedicated->integer)
+ {
+ clc.state = CA_DISCONNECTED;
+ Key_SetCatcher(KEYCATCH_CONSOLE);
+ CL_ProtocolSpecificCommandsInit();
+ return;
+ }
+
+ if (!com_cl_running->integer)
+ {
+ return;
+ }
+
+ Key_SetCatcher(Key_GetCatcher() & KEYCATCH_CONSOLE);
+
+ // if we are already connected to the local host, stay connected
+ if (clc.state >= CA_CONNECTED && !Q_stricmp(clc.servername, "localhost"))
+ {
+ clc.state = CA_CONNECTED; // so the connect screen is drawn
+ ::memset(cls.updateInfoString, 0, sizeof(cls.updateInfoString));
+ ::memset(clc.serverMessage, 0, sizeof(clc.serverMessage));
+ ::memset(&cl.gameState, 0, sizeof(cl.gameState));
+ clc.lastPacketSentTime = -9999;
+ SCR_UpdateScreen();
+ }
+ else
+ {
+ CL_Disconnect(true);
+ Q_strncpyz(clc.servername, "localhost", sizeof(clc.servername));
+ clc.state = CA_CHALLENGING; // so the connect screen is drawn
+ Key_SetCatcher(Key_GetCatcher() & KEYCATCH_CONSOLE);
+ SCR_UpdateScreen();
+ clc.connectTime = -RETRANSMIT_TIMEOUT;
+ NET_StringToAdr(clc.servername, &clc.serverAddress, NA_UNSPEC);
+ // we don't need a challenge on the localhost
+
+ CL_CheckForResend();
+ }
+}
+
+/*
+===================
+CL_MotdPacket
+
+===================
+*/
+static void CL_MotdPacket(netadr_t from, const char *info)
+{
+ const char *v;
+
+ // if not from our server, ignore it
+ if (!NET_CompareAdr(from, cls.updateServer))
+ {
+ Com_DPrintf("MOTD packet from unexpected source\n");
+ return;
+ }
+
+ Com_DPrintf("MOTD packet: %s\n", info);
+ while (*info != '\\') info++;
+
+ // check challenge
+ v = Info_ValueForKey(info, "challenge");
+ if (strcmp(v, cls.updateChallenge))
+ {
+ Com_DPrintf(
+ "MOTD packet mismatched challenge: "
+ "'%s' != '%s'\n",
+ v, cls.updateChallenge);
+ return;
+ }
+
+ v = Info_ValueForKey(info, "motd");
+
+ Q_strncpyz(cls.updateInfoString, info, sizeof(cls.updateInfoString));
+ Cvar_Set("cl_motdString", v);
+}
+
+/*
+===================
+CL_InitServerInfo
+===================
+*/
+static void CL_InitServerInfo(serverInfo_t *server, netadr_t *address)
+{
+ server->adr = *address;
+ server->clients = 0;
+ server->hostName[0] = '\0';
+ server->mapName[0] = '\0';
+ server->label[0] = '\0';
+ server->maxClients = 0;
+ server->maxPing = 0;
+ server->minPing = 0;
+ server->ping = -1;
+ server->game[0] = '\0';
+ server->gameType = 0;
+ server->netType = 0;
+}
+
+/*
+===================
+CL_GSRSequenceInformation
+
+Parses this packet's index and the number of packets from a master server's
+response. Updates the packet count and returns the index. Advances the data
+pointer as appropriate (but only when parsing was successful)
+
+The sequencing information isn't terribly useful at present (we can skip
+duplicate packets, but we don't bother to make sure we've got all of them).
+===================
+*/
+static int CL_GSRSequenceInformation(int alternateProtocol, byte **data)
+{
+ char *p = (char *)*data, *e;
+ int ind, num;
+ // '\0'-delimited fields: this packet's index, total number of packets
+ if (*p++ != '\0') return -1;
+
+ ind = strtol(p, (char **)&e, 10);
+ if (*e++ != '\0') return -1;
+
+ num = strtol(e, (char **)&p, 10);
+ if (*p++ != '\0') return -1;
+
+ if (num <= 0 || ind <= 0 || ind > num) return -1; // nonsensical response
+
+ if (cls.numAlternateMasterPackets[alternateProtocol] > 0 && num != cls.numAlternateMasterPackets[alternateProtocol])
+ {
+ // Assume we sent two getservers and somehow they changed in
+ // between - only use the results that arrive later
+ Com_DPrintf("Master changed its mind about%s packet count!\n",
+ (alternateProtocol == 0 ? "" : alternateProtocol == 1 ? " alternate-1" : " alternate-2"));
+ cls.receivedAlternateMasterPackets[alternateProtocol] = 0;
+ // cls.numglobalservers = 0;
+ // cls.numGlobalServerAddresses = 0;
+ }
+ cls.numAlternateMasterPackets[alternateProtocol] = num;
+
+ // successfully parsed
+ *data = (byte *)p;
+ return ind;
+}
+
+/*
+===================
+CL_GSRFeaturedLabel
+
+Parses from the data an arbitrary text string labelling the servers in the
+following getserversresponse packet.
+The result is copied to *buf, and *data is advanced as appropriate
+===================
+*/
+static void CL_GSRFeaturedLabel(byte **data, char *buf, int size)
+{
+ char *l = buf;
+
+ // copy until '\0' which indicates field break
+ // or slash which indicates beginning of server list
+ while (**data && **data != '\\' && **data != '/')
+ {
+ if (l < &buf[size - 1])
+ *l = **data;
+ else if (l == &buf[size - 1])
+ Com_DPrintf(S_COLOR_YELLOW
+ "Warning: "
+ "CL_GSRFeaturedLabel: overflow\n");
+ l++, (*data)++;
+ }
+
+ if (l < &buf[size - 1])
+ *l = '\0';
+ else
+ buf[size - 1] = '\0';
+}
+
+#define MAX_SERVERSPERPACKET 256
+
+/*
+===================
+CL_ServersResponsePacket
+===================
+*/
+static void CL_ServersResponsePacket(const netadr_t *from, msg_t *msg, bool extended)
+{
+ int i, count, total;
+ netadr_t addresses[MAX_SERVERSPERPACKET];
+ int numservers;
+ byte *buffptr;
+ byte *buffend;
+ char label[MAX_FEATLABEL_CHARS] = "";
+
+ Com_DPrintf("CL_ServersResponsePacket from %s %s\n",
+ NET_AdrToStringwPort(*from),
+ extended ? " (extended)" : "");
+
+ if (cls.numglobalservers == -1)
+ {
+ // state to detect lack of servers or lack of response
+ cls.numglobalservers = 0;
+ cls.numGlobalServerAddresses = 0;
+ for (i = 0; i < 3; ++i)
+ {
+ cls.numAlternateMasterPackets[i] = 0;
+ cls.receivedAlternateMasterPackets[i] = 0;
+ }
+ }
+
+ // parse through server response string
+ numservers = 0;
+ buffptr = msg->data;
+ buffend = buffptr + msg->cursize;
+
+ // skip header
+ buffptr += 4;
+
+ // advance to initial token
+ // I considered using strchr for this but I don't feel like relying
+ // on its behaviour with '\0'
+ while (*buffptr && *buffptr != '\\' && *buffptr != '/')
+ {
+ buffptr++;
+
+ if (buffptr >= buffend) break;
+ }
+
+ if (*buffptr == '\0')
+ {
+ int ind = CL_GSRSequenceInformation(from->alternateProtocol, &buffptr);
+ if (ind >= 0)
+ {
+ // this denotes the start of new-syntax stuff
+ // have we already received this packet?
+ if (cls.receivedAlternateMasterPackets[from->alternateProtocol] & (1 << (ind - 1)))
+ {
+ Com_DPrintf(
+ "CL_ServersResponsePacket: "
+ "received packet %d again, ignoring\n",
+ ind);
+ return;
+ }
+ // TODO: detect dropped packets and make another
+ // request
+ Com_DPrintf(
+ "CL_ServersResponsePacket:%s packet "
+ "%d of %d\n",
+ (from->alternateProtocol == 0 ? "" : from->alternateProtocol == 1 ? " alternate-1" : " alternate-2"),
+ ind, cls.numAlternateMasterPackets[from->alternateProtocol]);
+ cls.receivedAlternateMasterPackets[from->alternateProtocol] |= (1 << (ind - 1));
+
+ CL_GSRFeaturedLabel(&buffptr, label, sizeof(label));
+ }
+ // now skip to the server list
+ for (; buffptr < buffend && *buffptr != '\\' && *buffptr != '/'; buffptr++)
+ ;
+ }
+
+ while (buffptr + 1 < buffend)
+ {
+ // IPv4 address
+ if (*buffptr == '\\')
+ {
+ buffptr++;
+
+ if (buffend - buffptr < sizeof(addresses[numservers].ip) + sizeof(addresses[numservers].port) + 1) break;
+
+ for (i = 0; i < sizeof(addresses[numservers].ip); i++) addresses[numservers].ip[i] = *buffptr++;
+
+ addresses[numservers].type = NA_IP;
+ }
+ // IPv6 address, if it's an extended response
+ else if (extended && *buffptr == '/')
+ {
+ buffptr++;
+
+ if (buffend - buffptr < sizeof(addresses[numservers].ip6) + sizeof(addresses[numservers].port) + 1) break;
+
+ for (i = 0; i < sizeof(addresses[numservers].ip6); i++) addresses[numservers].ip6[i] = *buffptr++;
+
+ addresses[numservers].type = NA_IP6;
+ addresses[numservers].scope_id = from->scope_id;
+ }
+ else
+ // syntax error!
+ break;
+
+ // parse out port
+ addresses[numservers].port = (*buffptr++) << 8;
+ addresses[numservers].port += *buffptr++;
+ addresses[numservers].port = BigShort(addresses[numservers].port);
+
+ // syntax check
+ if (*buffptr != '\\' && *buffptr != '/') break;
+
+ addresses[numservers].alternateProtocol = from->alternateProtocol;
+
+ numservers++;
+ if (numservers >= MAX_SERVERSPERPACKET) break;
+ }
+
+ count = cls.numglobalservers;
+
+ for (i = 0; i < numservers && count < MAX_GLOBAL_SERVERS; i++)
+ {
+ // build net address
+ serverInfo_t *server = &cls.globalServers[count];
+
+ CL_InitServerInfo(server, &addresses[i]);
+ Q_strncpyz(server->label, label, sizeof(server->label));
+ // advance to next slot
+ count++;
+ }
+
+ // if getting the global list
+ if (count >= MAX_GLOBAL_SERVERS && cls.numGlobalServerAddresses < MAX_GLOBAL_SERVERS)
+ {
+ // if we couldn't store the servers in the main list anymore
+ for (; i < numservers && cls.numGlobalServerAddresses < MAX_GLOBAL_SERVERS; i++)
+ {
+ // just store the addresses in an additional list
+ cls.globalServerAddresses[cls.numGlobalServerAddresses++] = addresses[i];
+ }
+ }
+
+ cls.numglobalservers = count;
+ total = count + cls.numGlobalServerAddresses;
+
+ Com_Printf("%d servers parsed (total %d)\n", numservers, total);
+}
+/*
+==================
+CL_CheckTimeout
+
+==================
+*/
+static void CL_CheckTimeout(void)
+{
+ //
+ // check timeout
+ //
+ if ((!CL_CheckPaused() || !sv_paused->integer) && clc.state >= CA_CONNECTED && clc.state != CA_CINEMATIC &&
+ cls.realtime - clc.lastPacketTime > cl_timeout->value * 1000)
+ {
+ if (++cl.timeoutcount > 5)
+ { // timeoutcount saves debugger
+ Com_Printf("\nServer connection timed out.\n");
+ CL_Disconnect(true);
+ return;
+ }
+ }
+ else
+ {
+ cl.timeoutcount = 0;
+ }
+}
+
+/*
+==================
+CL_CheckPaused
+Check whether client has been paused.
+==================
+*/
+bool CL_CheckPaused(void)
+{ // if cl_paused->modified is set, the cvar has only been changed in
+ // this frame. Keep paused in this frame to ensure the server doesn't
+ // lag behind.
+ if (cl_paused->integer || cl_paused->modified) return true;
+
+ return false;
+}
+
+//============================================================================
+
+/*
+==================
+CL_CheckUserinfo
+
+==================
+*/
+static void CL_CheckUserinfo(void)
+{
+ // don't add reliable commands when not yet connected
+ if (clc.state < CA_CONNECTED) return;
+
+ // don't overflow the reliable command buffer when paused
+ if (CL_CheckPaused()) return;
+
+ // send a reliable userinfo update if needed
+ if (cvar_modifiedFlags & CVAR_USERINFO)
+ {
+ cvar_modifiedFlags &= ~CVAR_USERINFO;
+ CL_AddReliableCommand(va("userinfo \"%s\"", Cvar_InfoString(CVAR_USERINFO)), false);
+ }
+}
+
+/*
+==================
+CL_Frame
+
+==================
+*/
+void CL_Frame(int msec)
+{
+ if (!com_cl_running->integer) return;
+
+ // We may have a download prompt ready
+ if ((com_downloadPrompt->integer & DLP_TYPE_MASK) && !(com_downloadPrompt->integer & DLP_PROMPTED))
+ {
+ Com_Printf("Download prompt returned %d\n", com_downloadPrompt->integer);
+ CL_NextDownload();
+ }
+ else if (com_downloadPrompt->integer & DLP_SHOW)
+ {
+ // If the UI VM does not support the download prompt, we need to catch
+ // the prompt here and replicate regular behavior.
+ // One frame will always run between requesting and showing the prompt.
+
+ if (com_downloadPrompt->integer & DLP_STALE)
+ {
+ Com_Printf("WARNING: UI VM does not support download prompt\n");
+ Cvar_Set("com_downloadPrompt", va("%d", DLP_IGNORE));
+ CL_NextDownload();
+ }
+ else
+ {
+ Cvar_Set("com_downloadPrompt", va("%d", com_downloadPrompt->integer | DLP_STALE));
+ }
+ }
+
+ if (clc.downloadCURLM)
+ {
+ CL_cURL_PerformDownload();
+ // we can't process frames normally when in disconnected download mode
+ // since the ui vm expects clc.state to be CA_CONNECTED
+ if (clc.cURLDisconnected)
+ {
+ cls.realFrametime = msec;
+ cls.frametime = msec;
+ cls.realtime += cls.frametime;
+
+ SCR_UpdateScreen();
+ S_Update();
+ Con_RunConsole();
+
+ cls.framecount++;
+ return;
+ }
+ }
+
+ if (clc.state == CA_DISCONNECTED && !(Key_GetCatcher() & KEYCATCH_UI) && !com_sv_running->integer && cls.ui)
+ {
+ // if disconnected, bring up the menu
+ S_StopAllSounds();
+ VM_Call(cls.ui, UI_SET_ACTIVE_MENU - (cls.uiInterface == 2 ? 2 : 0), UIMENU_MAIN);
+ }
+
+ // if recording an avi, lock to a fixed fps
+ if (CL_VideoRecording() && cl_aviFrameRate->integer && msec)
+ {
+ // save the current screen
+ if (clc.state == CA_ACTIVE || cl_forceavidemo->integer)
+ {
+ float fps = MIN(cl_aviFrameRate->value * com_timescale->value, 1000.0f);
+ float frameDuration = MAX(1000.0f / fps, 1.0f) + clc.aviVideoFrameRemainder;
+
+ CL_TakeVideoFrame();
+
+ msec = (int)frameDuration;
+ clc.aviVideoFrameRemainder = frameDuration - msec;
+ }
+ }
+
+ if (cl_autoRecordDemo->integer)
+ {
+ if (clc.state == CA_ACTIVE && !clc.demorecording && !clc.demoplaying)
+ {
+ // If not recording a demo, and we should be, start one
+ qtime_t now;
+ Com_RealTime(&now);
+
+ const char *nowString = va("%04d%02d%02d%02d%02d%02d", 1900 + now.tm_year, 1 + now.tm_mon, now.tm_mday,
+ now.tm_hour, now.tm_min, now.tm_sec);
+
+ char serverName[MAX_OSPATH];
+ Q_strncpyz(serverName, clc.servername, MAX_OSPATH);
+
+ // Replace the ":" in the address as it is not a valid
+ // file name character
+ char *p = strstr(serverName, ":");
+ if (p) *p = '.';
+
+ char mapName[MAX_QPATH];
+ Q_strncpyz(mapName, COM_SkipPath(cl.mapname), sizeof(cl.mapname));
+ COM_StripExtension(mapName, mapName, sizeof(mapName));
+ Cbuf_ExecuteText(EXEC_NOW, va("record \"%s-%s-%s\"\n", nowString, serverName, mapName));
+ }
+ else if (clc.state != CA_ACTIVE && clc.demorecording)
+ {
+ // Recording, but not CA_ACTIVE, so stop recording
+ CL_StopRecord_f();
+ }
+ }
+
+ // save the msec before checking pause
+ cls.realFrametime = msec;
+
+ // decide the simulation time
+ cls.frametime = msec;
+
+ cls.realtime += cls.frametime;
+
+ if (cl_timegraph->integer)
+ {
+ SCR_DebugGraph(cls.realFrametime * 0.25);
+ }
+
+ // see if we need to update any userinfo
+ CL_CheckUserinfo();
+
+ // if we haven't gotten a packet in a long time, drop the connection
+ CL_CheckTimeout();
+
+ // send intentions now
+ CL_SendCmd();
+
+ // resend a connection request if necessary
+ CL_CheckForResend();
+
+ // decide on the serverTime to render
+ CL_SetCGameTime();
+
+ // update the screen
+ SCR_UpdateScreen();
+
+ // update audio
+ S_Update();
+
+#ifdef USE_VOIP
+ CL_CaptureVoip();
+#endif
+
+#ifdef USE_MUMBLE
+ CL_UpdateMumble();
+#endif
+
+ // advance local effects for next frame
+ SCR_RunCinematic();
+
+ Con_RunConsole();
+
+ cls.framecount++;
+}
+
+//============================================================================
+
+/*
+================
+CL_RefPrintf
+
+DLL glue
+================
+*/
+static __attribute__((format(printf, 2, 3))) void QDECL CL_RefPrintf(int print_level, const char *fmt, ...)
+{
+ va_list argptr;
+ char msg[MAXPRINTMSG];
+
+ va_start(argptr, fmt);
+ Q_vsnprintf(msg, sizeof(msg), fmt, argptr);
+ va_end(argptr);
+
+ switch (print_level)
+ {
+ case PRINT_ALL:
+ Com_Printf("%s", msg);
+ break;
+
+ case PRINT_WARNING:
+ Com_Printf(S_COLOR_YELLOW "%s", msg);
+ break;
+
+ case PRINT_DEVELOPER:
+ Com_DPrintf(S_COLOR_RED "%s", msg);
+ break;
+ }
+}
+
+/*
+============
+CL_ShutdownRef
+============
+*/
+static void CL_ShutdownRef(void)
+{
+ if (re.Shutdown) re.Shutdown(true);
+
+ ::memset(&re, 0, sizeof(re));
+
+#ifdef USE_RENDERER_DLOPEN
+ if (rendererLib)
+ {
+ Sys_UnloadLibrary(rendererLib);
+ rendererLib = NULL;
+ }
+#endif
+}
+
+/*
+=====================
+CL_ShutdownAll
+=====================
+*/
+void CL_ShutdownAll(bool shutdownRef)
+{
+ if (CL_VideoRecording()) CL_CloseAVI();
+
+ if (clc.demorecording) CL_StopRecord_f();
+
+ CL_cURL_Shutdown();
+
+ // clear sounds
+ S_DisableSounds();
+ // shutdown CGame
+ CL_ShutdownCGame();
+ // shutdown UI
+ CL_ShutdownUI();
+
+ // shutdown the renderer
+ if (shutdownRef)
+ CL_ShutdownRef();
+ else if (re.Shutdown)
+ re.Shutdown(false); // don't destroy window or context
+
+ cls.uiStarted = false;
+ cls.cgameStarted = false;
+ cls.rendererStarted = false;
+ cls.soundRegistered = false;
+}
+
+/*
+=================
+CL_ClearMemory
+
+Called by Com_GameRestart
+=================
+*/
+static void CL_ClearMemory(bool shutdownRef)
+{
+ // shutdown all the client stuff
+ CL_ShutdownAll(shutdownRef);
+
+ // if not running a server clear the whole hunk
+ if (!com_sv_running->integer)
+ {
+ // clear the whole hunk
+ Hunk_Clear();
+ // clear collision map data
+ CM_ClearMap();
+ }
+ else
+ {
+ // clear all the client data on the hunk
+ Hunk_ClearToMark();
+ }
+}
+
+/*
+=================
+CL_FlushMemory
+
+Called by CL_MapLoading, CL_Connect_f, CL_PlayDemo_f, and CL_ParseGamestate the only
+ways a client gets into a game
+Also called by Com_Error
+=================
+*/
+void CL_FlushMemory(void)
+{
+ CL_ClearMemory(false);
+ CL_StartHunkUsers(false);
+}
+
+/*
+=================
+CL_Vid_Restart_f
+
+Restart the video subsystem
+
+we also have to reload the UI and CGame because the renderer
+doesn't know what graphics to reload
+=================
+*/
+static void CL_Vid_Restart_f(void)
+{
+ // Settings may have changed so stop recording now
+ if (CL_VideoRecording())
+ {
+ CL_CloseAVI();
+ }
+
+ if (clc.demorecording) CL_StopRecord_f();
+
+ // don't let them loop during the restart
+ S_StopAllSounds();
+
+ if (!FS_ConditionalRestart(clc.checksumFeed, true))
+ {
+ // if not running a server clear the whole hunk
+ if (com_sv_running->integer)
+ {
+ // clear all the client data on the hunk
+ Hunk_ClearToMark();
+ }
+ else
+ {
+ // clear the whole hunk
+ Hunk_Clear();
+ }
+
+ // shutdown the UI
+ CL_ShutdownUI();
+ // shutdown the CGame
+ CL_ShutdownCGame();
+ // shutdown the renderer and clear the renderer interface
+ CL_ShutdownRef();
+ // client is no longer pure untill new checksums are sent
+ CL_ResetPureClientAtServer();
+ // clear pak references
+ FS_ClearPakReferences(FS_UI_REF | FS_CGAME_REF);
+ // reinitialize the filesystem if the game directory or checksum has changed
+
+ cls.rendererStarted = false;
+ cls.uiStarted = false;
+ cls.cgameStarted = false;
+ cls.soundRegistered = false;
+
+ // unpause so the cgame definately gets a snapshot and renders a frame
+ Cvar_Set("cl_paused", "0");
+
+ // initialize the renderer interface
+ CL_InitRef();
+
+ // startup all the client stuff
+ CL_StartHunkUsers(false);
+
+ // start the cgame if connected
+ if (clc.state > CA_CONNECTED && clc.state != CA_CINEMATIC)
+ {
+ cls.cgameStarted = true;
+ CL_InitCGame();
+ // send pure checksums
+ CL_SendPureChecksums();
+ }
+ }
+}
+
+/*
+=================
+CL_Snd_Restart_f
+
+Restart the sound subsystem
+The cgame and game must also be forced to restart because
+handles will be invalid
+=================
+*/
+static void CL_Snd_Restart_f(void)
+{
+ CL_Snd_Shutdown();
+ // sound will be reinitialized by vid_restart
+ CL_Vid_Restart_f();
+}
+
+
+/*
+============
+CL_InitRenderer
+============
+*/
+static void CL_InitRenderer(void)
+{
+ // this sets up the renderer and calls R_Init
+ re.BeginRegistration(&cls.glconfig);
+
+ // load character sets
+ cls.charSetShader = re.RegisterShader("gfx/2d/bigchars");
+ cls.whiteShader = re.RegisterShader("white");
+ cls.consoleShader = re.RegisterShader("console");
+ g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2;
+ g_consoleField.widthInChars = g_console_field_width;
+}
+
+/*
+============================
+CL_StartHunkUsers
+
+After the server has cleared the hunk, these will need to be restarted
+This is the only place that any of these functions are called from
+============================
+*/
+void CL_StartHunkUsers(bool rendererOnly)
+{
+ if (!com_cl_running)
+ {
+ return;
+ }
+
+ if (!com_cl_running->integer)
+ {
+ return;
+ }
+
+ if (!cls.rendererStarted)
+ {
+ cls.rendererStarted = true;
+ CL_InitRenderer();
+ }
+
+ if (rendererOnly)
+ {
+ return;
+ }
+
+ if (!cls.soundStarted)
+ {
+ cls.soundStarted = true;
+ S_Init();
+ }
+
+ if (!cls.soundRegistered)
+ {
+ cls.soundRegistered = true;
+ S_BeginRegistration();
+ }
+
+ if (com_dedicated->integer)
+ {
+ return;
+ }
+
+ if (!cls.uiStarted)
+ {
+ cls.uiStarted = true;
+ CL_InitUI();
+ }
+}
+
+/*
+============
+CL_RefMalloc
+============
+*/
+static void *CL_RefMalloc(int size) { return Z_TagMalloc(size, TAG_RENDERER); }
+
+/*
+============
+CL_ScaledMilliseconds
+============
+*/
+int CL_ScaledMilliseconds(void) { return Sys_Milliseconds() * com_timescale->value; }
+
+//===========================================================================================
+
+static void CL_SetModel_f(void)
+{
+ char name[256];
+
+ const char *arg = Cmd_Argv(1);
+ if (arg[0])
+ {
+ Cvar_Set("model", arg);
+ Cvar_Set("headmodel", arg);
+ }
+ else
+ {
+ Cvar_VariableStringBuffer("model", name, sizeof(name));
+ Com_Printf("model is set to %s\n", name);
+ }
+}
+
+//===========================================================================================
+
+/*
+===============
+CL_Video_f
+
+video
+video [filename]
+===============
+*/
+static void CL_Video_f(void)
+{
+ char filename[MAX_OSPATH];
+
+ if (!clc.demoplaying)
+ {
+ Com_Printf("The video command can only be used when playing back demos\n");
+ return;
+ }
+
+ if (Cmd_Argc() == 2)
+ {
+ // explicit filename
+ Com_sprintf(filename, MAX_OSPATH, "videos/%s.avi", Cmd_Argv(1));
+ }
+ else
+ {
+ int i, last;
+
+ // scan for a free filename
+ for (i = 0; i <= 9999; i++)
+ {
+ int a, b, c, d;
+
+ last = i;
+
+ a = last / 1000;
+ last -= a * 1000;
+ b = last / 100;
+ last -= b * 100;
+ c = last / 10;
+ last -= c * 10;
+ d = last;
+
+ Com_sprintf(filename, MAX_OSPATH, "videos/video%d%d%d%d.avi", a, b, c, d);
+
+ if (!FS_FileExists(filename)) break; // file doesn't exist
+ }
+
+ if (i > 9999)
+ {
+ Com_Printf(S_COLOR_RED "ERROR: no free file names to create video\n");
+ return;
+ }
+ }
+
+ CL_OpenAVIForWriting(filename);
+}
+
+/*
+===============
+CL_StopVideo_f
+===============
+*/
+static void CL_StopVideo_f(void) { CL_CloseAVI(); }
+/*
+===============
+CL_GenerateQKey
+
+test to see if a valid QKEY_FILE exists. If one does not, try to generate
+it by filling it with 2048 bytes of random data.
+===============
+*/
+static void CL_GenerateQKey(void)
+{
+ int len = 0;
+ unsigned char buff[QKEY_SIZE];
+ fileHandle_t f;
+
+ len = FS_SV_FOpenFileRead(QKEY_FILE, &f);
+ FS_FCloseFile(f);
+ if (len == QKEY_SIZE)
+ {
+ Com_Printf("QKEY found.\n");
+ return;
+ }
+ else
+ {
+ if (len > 0)
+ {
+ Com_Printf("QKEY file size != %d, regenerating\n", QKEY_SIZE);
+ }
+
+ Com_Printf("QKEY building random string\n");
+ Com_RandomBytes(buff, sizeof(buff));
+
+ f = FS_SV_FOpenFileWrite(QKEY_FILE);
+ if (!f)
+ {
+ Com_Printf("QKEY could not open %s for write\n", QKEY_FILE);
+ return;
+ }
+ FS_Write(buff, sizeof(buff), f);
+ FS_FCloseFile(f);
+ Com_Printf("QKEY generated\n");
+ }
+}
+
+static void CL_SetServerInfo(serverInfo_t *server, const char *info, int ping)
+{
+ if (server)
+ {
+ if (info)
+ {
+ server->clients = atoi(Info_ValueForKey(info, "clients"));
+ Q_strncpyz(server->hostName, Info_ValueForKey(info, "hostname"), MAX_HOSTNAME_LENGTH);
+ Q_strncpyz(server->mapName, Info_ValueForKey(info, "mapname"), MAX_NAME_LENGTH);
+ server->maxClients = atoi(Info_ValueForKey(info, "sv_maxclients"));
+ server->gameType = atoi(Info_ValueForKey(info, "gametype"));
+ server->netType = atoi(Info_ValueForKey(info, "nettype"));
+ server->minPing = atoi(Info_ValueForKey(info, "minping"));
+ server->maxPing = atoi(Info_ValueForKey(info, "maxping"));
+ const char *game = Info_ValueForKey(info, "game");
+ Q_strncpyz(server->game, (game[0]) ? game : BASEGAME, MAX_NAME_LENGTH);
+ }
+ server->ping = ping;
+ }
+}
+
+static void CL_SetServerInfoByAddress(netadr_t from, const char *info, int ping)
+{
+ int i;
+
+ for (i = 0; i < MAX_OTHER_SERVERS; i++)
+ {
+ if (NET_CompareAdr(from, cls.localServers[i].adr))
+ {
+ CL_SetServerInfo(&cls.localServers[i], info, ping);
+ }
+ }
+
+ for (i = 0; i < MAX_GLOBAL_SERVERS; i++)
+ {
+ if (NET_CompareAdr(from, cls.globalServers[i].adr))
+ {
+ CL_SetServerInfo(&cls.globalServers[i], info, ping);
+ }
+ }
+
+ for (i = 0; i < MAX_OTHER_SERVERS; i++)
+ {
+ if (NET_CompareAdr(from, cls.favoriteServers[i].adr))
+ {
+ CL_SetServerInfo(&cls.favoriteServers[i], info, ping);
+ }
+ }
+}
+
+/*
+===================
+CL_ServerInfoPacket
+===================
+*/
+static void CL_ServerInfoPacket(netadr_t from, msg_t *msg)
+{
+ int i, type;
+ char info[MAX_INFO_STRING];
+ char *infoString;
+ int prot;
+ char *gamename;
+ bool gameMismatch;
+
+ infoString = MSG_ReadString(msg);
+
+ if (from.alternateProtocol == 0)
+ {
+ // if this isn't the correct gamename, ignore it
+ gamename = Info_ValueForKey(infoString, "gamename");
+
+ gameMismatch = !*gamename || strcmp(gamename, com_gamename->string) != 0;
+
+ if (gameMismatch)
+ {
+ Com_DPrintf("Game mismatch in info packet: %s\n", infoString);
+ return;
+ }
+ }
+
+ // if this isn't the correct protocol version, ignore it
+ prot = atoi(Info_ValueForKey(infoString, "protocol"));
+ if (prot != (from.alternateProtocol == 0 ? PROTOCOL_VERSION : from.alternateProtocol == 1 ? 70 : 69))
+ {
+ Com_DPrintf("Different protocol info packet: %s\n", infoString);
+ return;
+ }
+
+ // iterate servers waiting for ping response
+ for (i = 0; i < MAX_PINGREQUESTS; i++)
+ {
+ if (cl_pinglist[i].adr.port && !cl_pinglist[i].time && NET_CompareAdr(from, cl_pinglist[i].adr))
+ {
+ // calc ping time
+ cl_pinglist[i].time = Sys_Milliseconds() - cl_pinglist[i].start;
+ Com_DPrintf("ping time %dms from %s\n", cl_pinglist[i].time, NET_AdrToString(from));
+
+ // save of info
+ Q_strncpyz(cl_pinglist[i].info, infoString, sizeof(cl_pinglist[i].info));
+
+ // tack on the net type
+ // NOTE: make sure these types are in sync with the netnames strings in the UI
+ switch (from.type)
+ {
+ case NA_BROADCAST:
+ case NA_IP:
+ type = 1;
+ break;
+ case NA_IP6:
+ type = 2;
+ break;
+ default:
+ type = 0;
+ break;
+ }
+ Info_SetValueForKey(cl_pinglist[i].info, "nettype", va("%d", type));
+ CL_SetServerInfoByAddress(from, infoString, cl_pinglist[i].time);
+
+ return;
+ }
+ }
+
+ // if not just sent a local broadcast or pinging local servers
+ if (cls.pingUpdateSource != AS_LOCAL)
+ {
+ return;
+ }
+
+ for (i = 0; i < MAX_OTHER_SERVERS; i++)
+ {
+ // empty slot
+ if (cls.localServers[i].adr.port == 0)
+ {
+ break;
+ }
+
+ // avoid duplicate
+ if (NET_CompareAdr(from, cls.localServers[i].adr))
+ {
+ return;
+ }
+ }
+
+ if (i == MAX_OTHER_SERVERS)
+ {
+ Com_DPrintf("MAX_OTHER_SERVERS hit, dropping infoResponse\n");
+ return;
+ }
+
+ // add this to the list
+ cls.numlocalservers = i + 1;
+ CL_InitServerInfo(&cls.localServers[i], &from);
+
+ Q_strncpyz(info, MSG_ReadString(msg), MAX_INFO_STRING);
+ if (strlen(info))
+ {
+ if (info[strlen(info) - 1] != '\n')
+ {
+ Q_strcat(info, sizeof(info), "\n");
+ }
+ Com_Printf("%s: %s", NET_AdrToStringwPort(from), info);
+ }
+}
+
+/*
+===================
+CL_ServerStatusResponse
+===================
+*/
+static void CL_ServerStatusResponse(netadr_t from, msg_t *msg)
+{
+ char info[MAX_INFO_STRING];
+ int i, l, score, ping;
+ int len;
+ serverStatus_t *serverStatus;
+
+ serverStatus = NULL;
+ for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++)
+ {
+ if (NET_CompareAdr(from, cl_serverStatusList[i].address))
+ {
+ serverStatus = &cl_serverStatusList[i];
+ break;
+ }
+ }
+ // if we didn't request this server status
+ if (!serverStatus)
+ {
+ return;
+ }
+
+ const char *s = MSG_ReadStringLine(msg);
+
+ len = 0;
+ Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string) - len, "%s", s);
+
+ if (serverStatus->print)
+ {
+ Com_Printf("Server settings:\n");
+ // print cvars
+ while (*s)
+ {
+ for (i = 0; i < 2 && *s; i++)
+ {
+ if (*s == '\\') s++;
+ l = 0;
+ while (*s)
+ {
+ info[l++] = *s;
+ if (l >= MAX_INFO_STRING - 1) break;
+ s++;
+ if (*s == '\\')
+ {
+ break;
+ }
+ }
+ info[l] = '\0';
+ if (i)
+ {
+ Com_Printf("%s\n", info);
+ }
+ else
+ {
+ Com_Printf("%-24s", info);
+ }
+ }
+ }
+ }
+
+ len = strlen(serverStatus->string);
+ Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string) - len, "\\");
+
+ if (serverStatus->print)
+ {
+ Com_Printf("\nPlayers:\n");
+ Com_Printf("num: score: ping: name:\n");
+ }
+ for (i = 0, s = MSG_ReadStringLine(msg); *s; s = MSG_ReadStringLine(msg), i++)
+ {
+ len = strlen(serverStatus->string);
+ Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string) - len, "\\%s", s);
+
+ if (serverStatus->print)
+ {
+ score = ping = 0;
+ sscanf(s, "%d %d", &score, &ping);
+ s = strchr(s, ' ');
+ if (s) s = strchr(s + 1, ' ');
+ if (s)
+ s++;
+ else
+ s = "unknown";
+ Com_Printf("%-2d %-3d %-3d %s\n", i, score, ping, s);
+ }
+ }
+ len = strlen(serverStatus->string);
+ Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string) - len, "\\");
+
+ serverStatus->time = Com_Milliseconds();
+ serverStatus->address = from;
+ serverStatus->pending = false;
+ if (serverStatus->print)
+ {
+ serverStatus->retrieved = true;
+ }
+}
+
+/*
+=================
+CL_ConnectionlessPacket
+
+Responses to broadcasts, etc
+=================
+*/
+static void CL_ConnectionlessPacket(netadr_t from, msg_t *msg)
+{
+ int challenge = 0;
+
+ MSG_BeginReadingOOB(msg);
+ MSG_ReadLong(msg); // skip the -1
+
+ const char *s = MSG_ReadStringLine(msg);
+
+ Cmd_TokenizeString(s);
+
+ const char *c = Cmd_Argv(0);
+
+ Com_DPrintf("CL packet %s: %s\n", NET_AdrToStringwPort(from), c);
+
+ // challenge from the server we are connecting to
+ if (!Q_stricmp(c, "challengeResponse"))
+ {
+ int ver;
+
+ if (clc.state != CA_CONNECTING)
+ {
+ Com_DPrintf("Unwanted challenge response received. Ignored.\n");
+ return;
+ }
+
+ const char *strver = Cmd_Argv(3);
+ if (*strver)
+ {
+ ver = atoi(strver);
+
+ if (ver != PROTOCOL_VERSION)
+ {
+ Com_Printf(S_COLOR_YELLOW
+ "Warning: Server reports protocol version %d, we have %d. "
+ "Trying anyways.\n",
+ ver, PROTOCOL_VERSION);
+ }
+ }
+ if (clc.serverAddress.alternateProtocol == 0)
+ {
+ c = Cmd_Argv(2);
+ if (*c) challenge = atoi(c);
+
+ if (!*c || challenge != clc.challenge)
+ {
+ Com_Printf("Bad challenge for challengeResponse. Ignored.\n");
+ return;
+ }
+ }
+
+ // start sending challenge response instead of challenge request packets
+ clc.challenge = atoi(Cmd_Argv(1));
+ clc.state = CA_CHALLENGING;
+ clc.connectPacketCount = 0;
+ clc.connectTime = -99999;
+
+ if (cl_rsaAuth->integer)
+ {
+ s = Cmd_Argv(4);
+ if (*s)
+ {
+ Q_strncpyz(clc.challenge2, s, sizeof(clc.challenge2));
+ clc.sendSignature = true;
+ }
+ }
+
+ // take this address as the new server address. This allows
+ // a server proxy to hand off connections to multiple servers
+ clc.serverAddress = from;
+ Com_DPrintf("challengeResponse: %d\n", clc.challenge);
+ return;
+ }
+
+ // server connection
+ if (!Q_stricmp(c, "connectResponse"))
+ {
+ if (clc.state >= CA_CONNECTED)
+ {
+ Com_Printf("Dup connect received. Ignored.\n");
+ return;
+ }
+ if (clc.state != CA_CHALLENGING)
+ {
+ Com_Printf("connectResponse packet while not connecting. Ignored.\n");
+ return;
+ }
+ if (!NET_CompareAdr(from, clc.serverAddress))
+ {
+ Com_Printf("connectResponse from wrong address. Ignored.\n");
+ return;
+ }
+
+ if (clc.serverAddress.alternateProtocol == 0)
+ {
+ c = Cmd_Argv(1);
+
+ if (*c)
+ challenge = atoi(c);
+ else
+ {
+ Com_Printf("Bad connectResponse received. Ignored.\n");
+ return;
+ }
+
+ if (challenge != clc.challenge)
+ {
+ Com_Printf("ConnectResponse with bad challenge received. Ignored.\n");
+ return;
+ }
+ }
+
+ Netchan_Setup(clc.serverAddress.alternateProtocol, NS_CLIENT, &clc.netchan, from,
+ Cvar_VariableValue("net_qport"), clc.challenge);
+
+ clc.state = CA_CONNECTED;
+ clc.lastPacketSentTime = -9999; // send first packet immediately
+ return;
+ }
+
+ // server responding to an info broadcast
+ if (!Q_stricmp(c, "infoResponse"))
+ {
+ CL_ServerInfoPacket(from, msg);
+ return;
+ }
+
+ // server responding to a get playerlist
+ if (!Q_stricmp(c, "statusResponse"))
+ {
+ CL_ServerStatusResponse(from, msg);
+ return;
+ }
+
+ // echo request from server
+ if (!Q_stricmp(c, "echo"))
+ {
+ NET_OutOfBandPrint(NS_CLIENT, from, "%s", Cmd_Argv(1));
+ return;
+ }
+
+ // global MOTD from trem master
+ if (!Q_stricmp(c, "motd"))
+ {
+ CL_MotdPacket(from, s);
+ return;
+ }
+
+ // echo request from server
+ if (!Q_stricmp(c, "print"))
+ {
+ s = MSG_ReadString(msg);
+
+ Q_strncpyz(clc.serverMessage, s, sizeof(clc.serverMessage));
+
+ while (clc.serverMessage[strlen(clc.serverMessage) - 1] == '\n')
+ clc.serverMessage[strlen(clc.serverMessage) - 1] = '\0';
+
+ Com_Printf("%s", s);
+
+ return;
+ }
+
+ // list of servers sent back by a master server (classic)
+ if (!Q_strncmp(c, "getserversResponse", 18))
+ {
+ CL_ServersResponsePacket(&from, msg, false);
+
+ return;
+ }
+
+ // list of servers sent back by a master server (extended)
+ if (!Q_strncmp(c, "getserversExtResponse", 21))
+ {
+ CL_ServersResponsePacket(&from, msg, true);
+ return;
+ }
+
+ Com_DPrintf("Unknown connectionless packet command.\n");
+}
+
+/*
+=================
+CL_PacketEvent
+
+A packet has arrived from the main event loop
+=================
+*/
+void CL_PacketEvent(netadr_t from, msg_t *msg)
+{
+ int headerBytes;
+
+ clc.lastPacketTime = cls.realtime;
+
+ if (msg->cursize >= 4 && *(int *)msg->data == -1)
+ {
+ CL_ConnectionlessPacket(from, msg);
+ return;
+ }
+
+ if (clc.state < CA_CONNECTED)
+ {
+ return; // can't be a valid sequenced packet
+ }
+
+ if (msg->cursize < 4)
+ {
+ Com_Printf("%s: Runt packet\n", NET_AdrToStringwPort(from));
+ return;
+ }
+
+ //
+ // packet from server
+ //
+ if (!NET_CompareAdr(from, clc.netchan.remoteAddress))
+ {
+ Com_DPrintf("%s:sequenced packet without connection\n", NET_AdrToStringwPort(from));
+ // FIXME: send a client disconnect?
+ return;
+ }
+
+ if (!CL_Netchan_Process(&clc.netchan, msg))
+ {
+ return; // out of order, duplicated, etc
+ }
+
+ // the header is different lengths for reliable and unreliable messages
+ headerBytes = msg->readcount;
+
+ // track the last message received so it can be returned in
+ // client messages, allowing the server to detect a dropped
+ // gamestate
+ clc.serverMessageSequence = LittleLong(*(int *)msg->data);
+
+ clc.lastPacketTime = cls.realtime;
+ CL_ParseServerMessage(msg);
+
+ //
+ // we don't know if it is ok to save a demo message until
+ // after we have parsed the frame
+ //
+ if (clc.demorecording && !clc.demowaiting)
+ {
+ CL_WriteDemoMessage(msg, headerBytes);
+ }
+}
+
+/*
+===================
+CL_GetServerStatus
+===================
+*/
+static serverStatus_t *CL_GetServerStatus(netadr_t from)
+{
+ int i, oldest, oldestTime;
+
+ for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++)
+ {
+ if (NET_CompareAdr(from, cl_serverStatusList[i].address))
+ {
+ return &cl_serverStatusList[i];
+ }
+ }
+ for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++)
+ {
+ if (cl_serverStatusList[i].retrieved)
+ {
+ return &cl_serverStatusList[i];
+ }
+ }
+ oldest = -1;
+ oldestTime = 0;
+ for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++)
+ {
+ if (oldest == -1 || cl_serverStatusList[i].startTime < oldestTime)
+ {
+ oldest = i;
+ oldestTime = cl_serverStatusList[i].startTime;
+ }
+ }
+ return &cl_serverStatusList[oldest];
+}
+
+/*
+===================
+CL_ServerStatus
+===================
+*/
+bool CL_ServerStatus(char *serverAddress, char *serverStatusString, int maxLen)
+{
+ int i;
+ netadr_t to;
+ serverStatus_t *serverStatus;
+
+ // if no server address then reset all server status requests
+ if (!serverAddress)
+ {
+ for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++)
+ {
+ cl_serverStatusList[i].address.port = 0;
+ cl_serverStatusList[i].retrieved = true;
+ }
+ return false;
+ }
+ // get the address
+ if (!NET_StringToAdr(serverAddress, &to, NA_UNSPEC))
+ {
+ return false;
+ }
+ serverStatus = CL_GetServerStatus(to);
+ // if no server status string then reset the server status request for this address
+ if (!serverStatusString)
+ {
+ serverStatus->retrieved = true;
+ return false;
+ }
+
+ // if this server status request has the same address
+ if (NET_CompareAdr(to, serverStatus->address))
+ {
+ // if we received a response for this server status request
+ if (!serverStatus->pending)
+ {
+ Q_strncpyz(serverStatusString, serverStatus->string, maxLen);
+ serverStatus->retrieved = true;
+ serverStatus->startTime = 0;
+ return true;
+ }
+ // resend the request regularly
+ else if (serverStatus->startTime < Com_Milliseconds() - cl_serverStatusResendTime->integer)
+ {
+ serverStatus->print = false;
+ serverStatus->pending = true;
+ serverStatus->retrieved = false;
+ serverStatus->time = 0;
+ serverStatus->startTime = Com_Milliseconds();
+ NET_OutOfBandPrint(NS_CLIENT, to, "getstatus");
+ return false;
+ }
+ }
+ // if retrieved
+ else if (serverStatus->retrieved)
+ {
+ serverStatus->address = to;
+ serverStatus->print = false;
+ serverStatus->pending = true;
+ serverStatus->retrieved = false;
+ serverStatus->startTime = Com_Milliseconds();
+ serverStatus->time = 0;
+ NET_OutOfBandPrint(NS_CLIENT, to, "getstatus");
+ return false;
+ }
+ return false;
+}
+
+/*
+==================
+CL_LocalServers_f
+==================
+*/
+static void CL_LocalServers_f(void)
+{
+ const char *message;
+ int i, j;
+ netadr_t to;
+
+ Com_Printf("Scanning for servers on the local network...\n");
+
+ // reset the list, waiting for response
+ cls.numlocalservers = 0;
+ cls.pingUpdateSource = AS_LOCAL;
+
+ for (i = 0; i < MAX_OTHER_SERVERS; i++)
+ {
+ bool b = cls.localServers[i].visible;
+ ::memset(&cls.localServers[i], 0, sizeof(cls.localServers[i]));
+ cls.localServers[i].visible = b;
+ }
+ ::memset(&to, 0, sizeof(to));
+
+ // The 'xxx' in the message is a challenge that will be echoed back
+ // by the server. We don't care about that here, but master servers
+ // can use that to prevent spoofed server responses from invalid ip
+ message = "\377\377\377\377getinfo xxx";
+
+ // send each message twice in case one is dropped
+ for (i = 0; i < 2; i++)
+ {
+ // send a broadcast packet on each server port
+ // we support multiple server ports so a single machine
+ // can nicely run multiple servers
+ for (j = 0; j < NUM_SERVER_PORTS; j++)
+ {
+ to.port = BigShort((short)(PORT_SERVER + j));
+
+ to.type = NA_BROADCAST;
+ NET_SendPacket(NS_CLIENT, strlen(message), message, to);
+ to.type = NA_MULTICAST6;
+ NET_SendPacket(NS_CLIENT, strlen(message), message, to);
+ }
+ }
+}
+
+/*
+==================
+CL_GlobalServers_f
+==================
+*/
+static void CL_GlobalServers_f(void)
+{
+ int netAlternateProtocols, a;
+ int i;
+ char command[1024];
+ const char *masteraddress;
+
+ int masterNum;
+ int count = Cmd_Argc();
+ if ( count < 2 || (masterNum = atoi(Cmd_Argv(1))) < 0 || masterNum > MAX_MASTER_SERVERS )
+ {
+ Com_Printf("usage: globalservers <master# 0-%d> [keywords]\n", MAX_MASTER_SERVERS);
+ return;
+ }
+
+ netAlternateProtocols = Cvar_VariableIntegerValue("net_alternateProtocols");
+
+ for (a = 0; a < 3; ++a)
+ {
+ // indent
+ if (a == 0 && (netAlternateProtocols & NET_DISABLEPRIMPROTO)) continue;
+ if (a == 1 && !(netAlternateProtocols & NET_ENABLEALT1PROTO)) continue;
+ if (a == 2 && !(netAlternateProtocols & NET_ENABLEALT2PROTO)) continue;
+
+ // request from all master servers
+ if ( masterNum == 0 )
+ {
+ int numAddress = 0;
+
+ for ( int i = 1; i <= MAX_MASTER_SERVERS; i++ )
+ {
+ sprintf(command, "sv_master%d", i);
+ masteraddress = Cvar_VariableString(command);
+
+ if(!*masteraddress)
+ continue;
+
+ numAddress++;
+
+ Com_sprintf(command, sizeof(command), "globalservers %d %s %s\n", i, Cmd_Argv(2), Cmd_ArgsFrom(3));
+ Cbuf_AddText(command);
+ }
+
+ if ( !numAddress )
+ Com_Printf("CL_GlobalServers_f: Error: No master server addresses.\n");
+
+ return;
+ }
+
+ sprintf(command, "sv_%smaster%d", (a == 0 ? "" : a == 1 ? "alt1" : "alt2"), masterNum);
+ masteraddress = Cvar_VariableString(command);
+
+ if (!*masteraddress)
+ {
+ Com_Printf("CL_GlobalServers_f: Error: No%s master server address given.\n",
+ (a == 0 ? "" : a == 1 ? " alternate-1" : " alternate-2"));
+ continue;
+ }
+
+ // reset the list, waiting for response
+ // -1 is used to distinguish a "no response"
+ netadr_t to;
+ int i = NET_StringToAdr(masteraddress, &to, NA_UNSPEC);
+
+ if ( i == 0 )
+ {
+ Com_Printf("CL_GlobalServers_f: Error: could not resolve address of%s master %s\n",
+ (a == 0 ? "" : a == 1 ? " alternate-1" : " alternate-2"), masteraddress);
+ continue;
+ }
+ else if ( i == 2 )
+ {
+ to.port = BigShort(a == 0 ? PORT_MASTER : a == 1 ? ALT1PORT_MASTER : ALT2PORT_MASTER);
+ }
+ to.alternateProtocol = a;
+
+ Com_Printf("Requesting servers from%s master %s...\n",
+ a == 0 ? "" : a == 1 ? " alternate-1" : " alternate-2",
+ masteraddress);
+
+ cls.numglobalservers = -1;
+ cls.pingUpdateSource = AS_GLOBAL;
+
+ Com_sprintf(command, sizeof(command), "getserversExt %s %i%s",
+ com_gamename->string,
+ a == 0 ? PROTOCOL_VERSION : a == 1 ? 70 : 69,
+ Cvar_VariableIntegerValue("net_enabled") & NET_ENABLEV4 ? "" : " ipv6");
+
+ for (i = 3; i < count; i++)
+ {
+ Q_strcat(command, sizeof(command), " ");
+ Q_strcat(command, sizeof(command), Cmd_Argv(i));
+ }
+
+ NET_OutOfBandPrint(NS_SERVER, to, "%s", command);
+ // outdent
+ }
+ CL_RequestMotd();
+}
+
+/*
+==================
+CL_GetPing
+==================
+*/
+void CL_GetPing(int n, char *buf, int buflen, int *pingtime)
+{
+ const char *str;
+ int time;
+ int maxPing;
+
+ if (n < 0 || n >= MAX_PINGREQUESTS || !cl_pinglist[n].adr.port)
+ {
+ // empty or invalid slot
+ buf[0] = '\0';
+ *pingtime = 0;
+ return;
+ }
+
+ str = NET_AdrToStringwPort(cl_pinglist[n].adr);
+ Q_strncpyz(buf, str, buflen);
+
+ time = cl_pinglist[n].time;
+ if (!time)
+ {
+ // check for timeout
+ time = Sys_Milliseconds() - cl_pinglist[n].start;
+ maxPing = Cvar_VariableIntegerValue("cl_maxPing");
+ if (maxPing < 100)
+ {
+ maxPing = 100;
+ }
+ if (time < maxPing)
+ {
+ // not timed out yet
+ time = 0;
+ }
+ }
+
+ CL_SetServerInfoByAddress(cl_pinglist[n].adr, cl_pinglist[n].info, cl_pinglist[n].time);
+
+ *pingtime = time;
+}
+
+/*
+==================
+CL_GetPingInfo
+==================
+*/
+void CL_GetPingInfo(int n, char *buf, int buflen)
+{
+ if (n < 0 || n >= MAX_PINGREQUESTS || !cl_pinglist[n].adr.port)
+ {
+ // empty or invalid slot
+ if (buflen) buf[0] = '\0';
+ return;
+ }
+
+ Q_strncpyz(buf, cl_pinglist[n].info, buflen);
+}
+
+/*
+==================
+CL_ClearPing
+==================
+*/
+void CL_ClearPing(int n)
+{
+ if (n < 0 || n >= MAX_PINGREQUESTS) return;
+
+ cl_pinglist[n].adr.port = 0;
+}
+
+/*
+==================
+CL_GetPingQueueCount
+==================
+*/
+int CL_GetPingQueueCount(void)
+{
+ int i;
+ int count;
+ ping_t *pingptr;
+
+ count = 0;
+ pingptr = cl_pinglist;
+
+ for (i = 0; i < MAX_PINGREQUESTS; i++, pingptr++)
+ {
+ if (pingptr->adr.port)
+ {
+ count++;
+ }
+ }
+
+ return (count);
+}
+
+/*
+==================
+CL_GetFreePing
+==================
+*/
+static ping_t *CL_GetFreePing(void)
+{
+ ping_t *pingptr;
+ ping_t *best;
+ int oldest;
+ int i;
+ int time;
+
+ pingptr = cl_pinglist;
+ for (i = 0; i < MAX_PINGREQUESTS; i++, pingptr++)
+ {
+ // find free ping slot
+ if (pingptr->adr.port)
+ {
+ if (!pingptr->time)
+ {
+ if (Sys_Milliseconds() - pingptr->start < 500)
+ {
+ // still waiting for response
+ continue;
+ }
+ }
+ else if (pingptr->time < 500)
+ {
+ // results have not been queried
+ continue;
+ }
+ }
+
+ // clear it
+ pingptr->adr.port = 0;
+ return (pingptr);
+ }
+
+ // use oldest entry
+ pingptr = cl_pinglist;
+ best = cl_pinglist;
+ oldest = INT_MIN;
+ for (i = 0; i < MAX_PINGREQUESTS; i++, pingptr++)
+ {
+ // scan for oldest
+ time = Sys_Milliseconds() - pingptr->start;
+ if (time > oldest)
+ {
+ oldest = time;
+ best = pingptr;
+ }
+ }
+
+ return (best);
+}
+
+/*
+==================
+CL_Ping_f
+==================
+*/
+static void CL_Ping_f(void)
+{
+ netadr_t to;
+ ping_t *pingptr;
+ const char *server;
+ int argc;
+ netadrtype_t family = NA_UNSPEC;
+
+ argc = Cmd_Argc();
+
+ if (argc != 2 && argc != 3)
+ {
+ Com_Printf("usage: ping [-4|-6] server\n");
+ return;
+ }
+
+ if (argc == 2)
+ server = Cmd_Argv(1);
+ else
+ {
+ if (!strcmp(Cmd_Argv(1), "-4"))
+ family = NA_IP;
+ else if (!strcmp(Cmd_Argv(1), "-6"))
+ family = NA_IP6;
+ else
+ Com_Printf("warning: only -4 or -6 as address type understood.\n");
+
+ server = Cmd_Argv(2);
+ }
+
+ ::memset(&to, 0, sizeof(netadr_t));
+
+ if (!NET_StringToAdr(server, &to, family))
+ {
+ return;
+ }
+
+ pingptr = CL_GetFreePing();
+
+ memcpy(&pingptr->adr, &to, sizeof(netadr_t));
+ pingptr->start = Sys_Milliseconds();
+ pingptr->time = 0;
+
+ CL_SetServerInfoByAddress(pingptr->adr, NULL, 0);
+
+ NET_OutOfBandPrint(NS_CLIENT, to, "getinfo xxx");
+}
+
+/*
+==================
+CL_UpdateVisiblePings_f
+==================
+*/
+bool CL_UpdateVisiblePings_f(int source)
+{
+ int slots, i;
+ char buff[MAX_STRING_CHARS];
+ int pingTime;
+ int max;
+ bool status = false;
+
+ if (source < 0 || source > AS_FAVORITES)
+ {
+ return false;
+ }
+
+ cls.pingUpdateSource = source;
+
+ slots = CL_GetPingQueueCount();
+ if (slots < MAX_PINGREQUESTS)
+ {
+ serverInfo_t *server = NULL;
+
+ switch (source)
+ {
+ case AS_LOCAL:
+ server = &cls.localServers[0];
+ max = cls.numlocalservers;
+ break;
+ case AS_GLOBAL:
+ server = &cls.globalServers[0];
+ max = cls.numglobalservers;
+ break;
+ case AS_FAVORITES:
+ server = &cls.favoriteServers[0];
+ max = cls.numfavoriteservers;
+ break;
+ default:
+ return false;
+ }
+ for (i = 0; i < max; i++)
+ {
+ if (server[i].visible)
+ {
+ if (server[i].ping == -1)
+ {
+ int j;
+
+ if (slots >= MAX_PINGREQUESTS)
+ {
+ break;
+ }
+ for (j = 0; j < MAX_PINGREQUESTS; j++)
+ {
+ if (!cl_pinglist[j].adr.port)
+ {
+ continue;
+ }
+ if (NET_CompareAdr(cl_pinglist[j].adr, server[i].adr))
+ {
+ // already on the list
+ break;
+ }
+ }
+ if (j >= MAX_PINGREQUESTS)
+ {
+ status = true;
+ for (j = 0; j < MAX_PINGREQUESTS; j++)
+ {
+ if (!cl_pinglist[j].adr.port)
+ {
+ break;
+ }
+ }
+ memcpy(&cl_pinglist[j].adr, &server[i].adr, sizeof(netadr_t));
+ cl_pinglist[j].start = Sys_Milliseconds();
+ cl_pinglist[j].time = 0;
+ NET_OutOfBandPrint(NS_CLIENT, cl_pinglist[j].adr, "getinfo xxx");
+ slots++;
+ }
+ }
+ // if the server has a ping higher than cl_maxPing or
+ // the ping packet got lost
+ else if (server[i].ping == 0)
+ {
+ // if we are updating global servers
+ if (source == AS_GLOBAL)
+ {
+ //
+ if (cls.numGlobalServerAddresses > 0)
+ {
+ // overwrite this server with one from the additional global servers
+ cls.numGlobalServerAddresses--;
+ CL_InitServerInfo(&server[i], &cls.globalServerAddresses[cls.numGlobalServerAddresses]);
+ // NOTE: the server[i].visible flag stays untouched
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (slots)
+ {
+ status = true;
+ }
+ for (i = 0; i < MAX_PINGREQUESTS; i++)
+ {
+ if (!cl_pinglist[i].adr.port)
+ {
+ continue;
+ }
+ CL_GetPing(i, buff, MAX_STRING_CHARS, &pingTime);
+ if (pingTime != 0)
+ {
+ CL_ClearPing(i);
+ status = true;
+ }
+ }
+
+ return status;
+}
+
+/*
+==================
+CL_ServerStatus_f
+==================
+*/
+static void CL_ServerStatus_f(void)
+{
+ netadr_t to, *toptr = NULL;
+ const char *server;
+ serverStatus_t *serverStatus;
+ int argc;
+ netadrtype_t family = NA_UNSPEC;
+
+ argc = Cmd_Argc();
+
+ if (argc != 2 && argc != 3)
+ {
+ if (clc.state != CA_ACTIVE || clc.demoplaying)
+ {
+ Com_Printf("Not connected to a server.\n");
+ Com_Printf("usage: serverstatus [-4|-6] server\n");
+ return;
+ }
+
+ toptr = &clc.serverAddress;
+ }
+
+ if (!toptr)
+ {
+ ::memset(&to, 0, sizeof(netadr_t));
+
+ if (argc == 2)
+ server = Cmd_Argv(1);
+ else
+ {
+ if (!strcmp(Cmd_Argv(1), "-4"))
+ family = NA_IP;
+ else if (!strcmp(Cmd_Argv(1), "-6"))
+ family = NA_IP6;
+ else
+ Com_Printf("warning: only -4 or -6 as address type understood.\n");
+
+ server = Cmd_Argv(2);
+ }
+
+ toptr = &to;
+ if (!NET_StringToAdr(server, toptr, family)) return;
+ }
+
+ NET_OutOfBandPrint(NS_CLIENT, *toptr, "getstatus");
+
+ serverStatus = CL_GetServerStatus(*toptr);
+ serverStatus->address = *toptr;
+ serverStatus->print = true;
+ serverStatus->pending = true;
+}
+
+/*
+============
+CL_InitRef
+============
+*/
+static void CL_InitRef(void)
+{
+ refimport_t ri;
+ refexport_t *ret;
+#ifdef USE_RENDERER_DLOPEN
+ GetRefAPI_t GetRefAPI;
+ char dllName[MAX_OSPATH];
+#endif
+
+ Com_Printf("----- Initializing Renderer ----\n");
+
+#ifdef USE_RENDERER_DLOPEN
+ cl_renderer = Cvar_Get("cl_renderer", "opengl2", CVAR_ARCHIVE | CVAR_LATCH);
+
+ Com_sprintf(dllName, sizeof(dllName), "renderer_%s" DLL_EXT, cl_renderer->string);
+
+ if (!(rendererLib = Sys_LoadDll(dllName, false)) && strcmp(cl_renderer->string, cl_renderer->resetString))
+ {
+ Com_Printf("failed:\n\"%s\"\n", Sys_LibraryError());
+ Cvar_ForceReset("cl_renderer");
+
+ Com_sprintf(dllName, sizeof(dllName), "renderer_opengl1" DLL_EXT);
+ rendererLib = Sys_LoadDll(dllName, false);
+ }
+
+ if (!rendererLib)
+ {
+ Com_Printf("failed:\n\"%s\"\n", Sys_LibraryError());
+ Com_Error(ERR_FATAL, "Failed to load renderer");
+ }
+
+ GetRefAPI = (GetRefAPI_t)Sys_LoadFunction(rendererLib, "GetRefAPI");
+ if (!GetRefAPI)
+ {
+ Com_Error(ERR_FATAL, "Can't load symbol GetRefAPI: '%s'", Sys_LibraryError());
+ }
+#endif
+
+ ri.Cmd_AddCommand = Cmd_AddCommand;
+ ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
+ ri.Cmd_Argc = Cmd_Argc;
+ ri.Cmd_Argv = Cmd_Argv;
+ ri.Cmd_ExecuteText = Cbuf_ExecuteText;
+ ri.Printf = CL_RefPrintf;
+ ri.Error = Com_Error;
+ ri.Milliseconds = CL_ScaledMilliseconds;
+ ri.Malloc = CL_RefMalloc;
+ ri.Free = Z_Free;
+#ifdef HUNK_DEBUG
+ ri.Hunk_AllocDebug = Hunk_AllocDebug;
+#else
+ ri.Hunk_Alloc = Hunk_Alloc;
+#endif
+ ri.Hunk_AllocateTempMemory = Hunk_AllocateTempMemory;
+ ri.Hunk_FreeTempMemory = Hunk_FreeTempMemory;
+
+ ri.CM_ClusterPVS = CM_ClusterPVS;
+ ri.CM_DrawDebugSurface = CM_DrawDebugSurface;
+
+ ri.FS_ReadFile = FS_ReadFile;
+ ri.FS_FreeFile = FS_FreeFile;
+ ri.FS_WriteFile = FS_WriteFile;
+ ri.FS_FreeFileList = FS_FreeFileList;
+ ri.FS_ListFiles = FS_ListFiles;
+ ri.FS_FileIsInPAK = FS_FileIsInPAK;
+ ri.FS_FileExists = FS_FileExists;
+ ri.Cvar_Get = Cvar_Get;
+ ri.Cvar_Set = Cvar_Set;
+ ri.Cvar_SetValue = Cvar_SetValue;
+ ri.Cvar_CheckRange = Cvar_CheckRange;
+ ri.Cvar_SetDescription = Cvar_SetDescription;
+ ri.Cvar_VariableIntegerValue = Cvar_VariableIntegerValue;
+
+ // cinematic stuff
+
+ ri.CIN_UploadCinematic = CIN_UploadCinematic;
+ ri.CIN_PlayCinematic = CIN_PlayCinematic;
+ ri.CIN_RunCinematic = CIN_RunCinematic;
+
+ ri.CL_WriteAVIVideoFrame = CL_WriteAVIVideoFrame;
+
+ ri.IN_Init = IN_Init;
+ ri.IN_Shutdown = IN_Shutdown;
+ ri.IN_Restart = IN_Restart;
+
+ ri.Sys_GLimpSafeInit = Sys_GLimpSafeInit;
+ ri.Sys_GLimpInit = Sys_GLimpInit;
+ ri.Sys_LowPhysicalMemory = Sys_LowPhysicalMemory;
+
+ ret = GetRefAPI(REF_API_VERSION, &ri);
+
+#if defined __USEA3D && defined __A3D_GEOM
+ hA3Dg_ExportRenderGeom(ret);
+#endif
+
+ Com_Printf("-------------------------------\n");
+
+ if (!ret)
+ {
+ Com_Error(ERR_FATAL, "Couldn't initialize refresh");
+ }
+
+ re = *ret;
+
+ // unpause so the cgame definately gets a snapshot and renders a frame
+ Cvar_Set("cl_paused", "0");
+}
+
+/*
+====================
+CL_ProtocolSpecificCommandsInit
+
+For adding/remove commands that depend on a/some
+specific protocols, whenever the protcol may change
+====================
+*/
+void CL_ProtocolSpecificCommandsInit(void)
+{
+ Con_MessageModesInit();
+}
+
+/*
+====================
+CL_Init
+====================
+*/
+void CL_Init(void)
+{
+ Com_Printf("----- Client Initialization -----\n");
+
+ Con_Init();
+
+ if (!com_fullyInitialized)
+ {
+ CL_ClearState();
+ clc.state = CA_DISCONNECTED; // no longer CA_UNINITIALIZED
+ cl_oldGameSet = false;
+ }
+
+ CL_InitInput();
+
+ //
+ // register our variables
+ //
+ cl_noprint = Cvar_Get("cl_noprint", "0", 0);
+ cl_motd = Cvar_Get("cl_motd", "1", 0);
+
+ cl_timeout = Cvar_Get("cl_timeout", "200", 0);
+
+ cl_timeNudge = Cvar_Get("cl_timeNudge", "0", CVAR_TEMP);
+ cl_shownet = Cvar_Get("cl_shownet", "0", CVAR_TEMP);
+ cl_showSend = Cvar_Get("cl_showSend", "0", CVAR_TEMP);
+ cl_showTimeDelta = Cvar_Get("cl_showTimeDelta", "0", CVAR_TEMP);
+ cl_freezeDemo = Cvar_Get("cl_freezeDemo", "0", CVAR_TEMP);
+ rcon_client_password = Cvar_Get("rconPassword", "", CVAR_TEMP);
+ cl_activeAction = Cvar_Get("activeAction", "", CVAR_TEMP);
+
+ cl_timedemo = Cvar_Get("timedemo", "0", 0);
+ cl_timedemoLog = Cvar_Get("cl_timedemoLog", "", CVAR_ARCHIVE);
+ cl_autoRecordDemo = Cvar_Get("cl_autoRecordDemo", "0", CVAR_ARCHIVE);
+ cl_aviFrameRate = Cvar_Get("cl_aviFrameRate", "25", CVAR_ARCHIVE);
+ cl_aviMotionJpeg = Cvar_Get("cl_aviMotionJpeg", "1", CVAR_ARCHIVE);
+ cl_forceavidemo = Cvar_Get("cl_forceavidemo", "0", 0);
+
+ rconAddress = Cvar_Get("rconAddress", "", 0);
+
+ cl_yawspeed = Cvar_Get("cl_yawspeed", "140", CVAR_ARCHIVE);
+ cl_pitchspeed = Cvar_Get("cl_pitchspeed", "140", CVAR_ARCHIVE);
+ cl_anglespeedkey = Cvar_Get("cl_anglespeedkey", "1.5", 0);
+
+ cl_maxpackets = Cvar_Get("cl_maxpackets", "30", CVAR_ARCHIVE);
+ cl_packetdup = Cvar_Get("cl_packetdup", "1", CVAR_ARCHIVE);
+
+ cl_run = Cvar_Get("cl_run", "1", CVAR_ARCHIVE);
+ cl_sensitivity = Cvar_Get("sensitivity", "5", CVAR_ARCHIVE);
+ cl_mouseAccel = Cvar_Get("cl_mouseAccel", "0", CVAR_ARCHIVE);
+ cl_freelook = Cvar_Get("cl_freelook", "1", CVAR_ARCHIVE);
+
+ // 0: legacy mouse acceleration
+ // 1: new implementation
+ cl_mouseAccelStyle = Cvar_Get("cl_mouseAccelStyle", "0", CVAR_ARCHIVE);
+ // offset for the power function (for style 1, ignored otherwise)
+ // this should be set to the max rate value
+ cl_mouseAccelOffset = Cvar_Get("cl_mouseAccelOffset", "5", CVAR_ARCHIVE);
+ Cvar_CheckRange(cl_mouseAccelOffset, 0.001f, 50000.0f, false);
+
+ cl_showMouseRate = Cvar_Get("cl_showmouserate", "0", 0);
+
+ cl_allowDownload = Cvar_Get("cl_allowDownload", "1", CVAR_ARCHIVE);
+
+ if (cl_allowDownload->integer != -1) cl_allowDownload->integer = DLF_ENABLE;
+
+ com_downloadPrompt = Cvar_Get("com_downloadPrompt", "0", CVAR_ROM);
+ Cvar_Get("com_downloadPromptText", "", CVAR_TEMP);
+
+ cl_conXOffset = Cvar_Get("cl_conXOffset", "0", 0);
+#ifdef __APPLE__
+ // In game video is REALLY slow in Mac OS X right now due to driver slowness
+ cl_inGameVideo = Cvar_Get("r_inGameVideo", "0", CVAR_ARCHIVE);
+#else
+ cl_inGameVideo = Cvar_Get("r_inGameVideo", "1", CVAR_ARCHIVE);
+#endif
+
+ cl_serverStatusResendTime = Cvar_Get("cl_serverStatusResendTime", "750", 0);
+
+ m_pitch = Cvar_Get("m_pitch", "0.022", CVAR_ARCHIVE);
+ m_yaw = Cvar_Get("m_yaw", "0.022", CVAR_ARCHIVE);
+ m_forward = Cvar_Get("m_forward", "0.25", CVAR_ARCHIVE);
+ m_side = Cvar_Get("m_side", "0.25", CVAR_ARCHIVE);
+#ifdef __APPLE__
+ // Input is jittery on OS X w/o this
+ m_filter = Cvar_Get("m_filter", "1", CVAR_ARCHIVE);
+#else
+ m_filter = Cvar_Get("m_filter", "0", CVAR_ARCHIVE);
+#endif
+
+ j_pitch = Cvar_Get("j_pitch", "0.022", CVAR_ARCHIVE);
+ j_yaw = Cvar_Get("j_yaw", "-0.022", CVAR_ARCHIVE);
+ j_forward = Cvar_Get("j_forward", "-0.25", CVAR_ARCHIVE);
+ j_side = Cvar_Get("j_side", "0.25", CVAR_ARCHIVE);
+ j_up = Cvar_Get("j_up", "0", CVAR_ARCHIVE);
+
+ j_pitch_axis = Cvar_Get("j_pitch_axis", "3", CVAR_ARCHIVE);
+ j_yaw_axis = Cvar_Get("j_yaw_axis", "2", CVAR_ARCHIVE);
+ j_forward_axis = Cvar_Get("j_forward_axis", "1", CVAR_ARCHIVE);
+ j_side_axis = Cvar_Get("j_side_axis", "0", CVAR_ARCHIVE);
+ j_up_axis = Cvar_Get("j_up_axis", "4", CVAR_ARCHIVE);
+
+ Cvar_CheckRange(j_pitch_axis, 0, MAX_JOYSTICK_AXIS - 1, true);
+ Cvar_CheckRange(j_yaw_axis, 0, MAX_JOYSTICK_AXIS - 1, true);
+ Cvar_CheckRange(j_forward_axis, 0, MAX_JOYSTICK_AXIS - 1, true);
+ Cvar_CheckRange(j_side_axis, 0, MAX_JOYSTICK_AXIS - 1, true);
+ Cvar_CheckRange(j_up_axis, 0, MAX_JOYSTICK_AXIS - 1, true);
+
+ cl_motdString = Cvar_Get("cl_motdString", "", CVAR_ROM);
+
+ Cvar_Get("cl_maxPing", "800", CVAR_ARCHIVE);
+
+ cl_lanForcePackets = Cvar_Get("cl_lanForcePackets", "1", CVAR_ARCHIVE);
+
+ cl_guidServerUniq = Cvar_Get("cl_guidServerUniq", "1", CVAR_ARCHIVE);
+
+ cl_rsaAuth = Cvar_Get("cl_rsaAuth", "0", CVAR_INIT | CVAR_PROTECTED);
+
+ // ~ and `, as keys and characters
+ cl_consoleKeys = Cvar_Get("cl_consoleKeys", "~ ` 0x7e 0x60", CVAR_ARCHIVE);
+
+ cl_clantag = Cvar_Get ("cl_clantag", "", CVAR_ARCHIVE);
+
+ // userinfo
+ Cvar_Get("name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE);
+ cl_rate = Cvar_Get("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE);
+ Cvar_Get("snaps", "40", CVAR_USERINFO | CVAR_ARCHIVE);
+ Cvar_Get("color1", "4", CVAR_USERINFO | CVAR_ARCHIVE);
+ Cvar_Get("color2", "5", CVAR_USERINFO | CVAR_ARCHIVE);
+ Cvar_Get("handicap", "100", CVAR_USERINFO | CVAR_ARCHIVE);
+ Cvar_Get("sex", "male", CVAR_USERINFO | CVAR_ARCHIVE);
+
+ Cvar_Get("password", "", CVAR_USERINFO);
+
+#ifdef USE_MUMBLE
+ cl_useMumble = Cvar_Get("cl_useMumble", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ cl_mumbleScale = Cvar_Get("cl_mumbleScale", "0.0254", CVAR_ARCHIVE);
+#endif
+
+#ifdef USE_VOIP
+ cl_voipSend = Cvar_Get("cl_voipSend", "0", 0);
+ cl_voipSendTarget = Cvar_Get("cl_voipSendTarget", "spatial", 0);
+ cl_voipGainDuringCapture = Cvar_Get("cl_voipGainDuringCapture", "0.2", CVAR_ARCHIVE);
+ cl_voipCaptureMult = Cvar_Get("cl_voipCaptureMult", "2.0", CVAR_ARCHIVE);
+ cl_voipUseVAD = Cvar_Get("cl_voipUseVAD", "0", CVAR_ARCHIVE);
+ cl_voipVADThreshold = Cvar_Get("cl_voipVADThreshold", "0.25", CVAR_ARCHIVE);
+ cl_voipShowMeter = Cvar_Get("cl_voipShowMeter", "1", CVAR_ARCHIVE);
+
+ cl_voip = Cvar_Get("cl_voip", "1", CVAR_ARCHIVE);
+ Cvar_CheckRange(cl_voip, 0, 1, true);
+ cl_voipProtocol = Cvar_Get("cl_voipProtocol", cl_voip->integer ? "opus" : "", CVAR_USERINFO | CVAR_ROM);
+#endif
+
+ // cgame might not be initialized before menu is used
+ Cvar_Get("cg_viewsize", "100", CVAR_ARCHIVE);
+ // Make sure cg_stereoSeparation is zero as that variable is deprecated and should not be used anymore.
+ Cvar_Get("cg_stereoSeparation", "0", CVAR_ROM);
+
+ //
+ // register our commands
+ //
+ Cmd_AddCommand("cmd", CL_ForwardToServer_f);
+ Cmd_AddCommand("configstrings", CL_Configstrings_f);
+ Cmd_AddCommand("clientinfo", CL_Clientinfo_f);
+ Cmd_AddCommand("snd_restart", CL_Snd_Restart_f);
+ Cmd_AddCommand("vid_restart", CL_Vid_Restart_f);
+ Cmd_AddCommand("disconnect", CL_Disconnect_f);
+ Cmd_AddCommand("record", CL_Record_f);
+ Cmd_AddCommand("demo", CL_PlayDemo_f);
+ Cmd_SetCommandCompletionFunc("demo", CL_CompleteDemoName);
+ Cmd_AddCommand("cinematic", CL_PlayCinematic_f);
+ Cmd_AddCommand("stoprecord", CL_StopRecord_f);
+ Cmd_AddCommand("connect", CL_Connect_f);
+ Cmd_AddCommand("reconnect", CL_Reconnect_f);
+ Cmd_AddCommand("localservers", CL_LocalServers_f);
+ Cmd_AddCommand("globalservers", CL_GlobalServers_f);
+ Cmd_AddCommand("rcon", CL_Rcon_f);
+ Cmd_SetCommandCompletionFunc("rcon", CL_CompleteRcon);
+ Cmd_AddCommand("ping", CL_Ping_f);
+ Cmd_AddCommand("serverstatus", CL_ServerStatus_f);
+ Cmd_AddCommand("showip", CL_ShowIP_f);
+ Cmd_AddCommand("fs_openedList", CL_OpenedPK3List_f);
+ Cmd_AddCommand("fs_referencedList", CL_ReferencedPK3List_f);
+ Cmd_AddCommand("model", CL_SetModel_f);
+ Cmd_AddCommand("video", CL_Video_f);
+ Cmd_AddCommand("stopvideo", CL_StopVideo_f);
+ Cmd_AddCommand("downloadUpdate", CL_DownloadUpdate_f);
+ Cmd_AddCommand("installUpdate", CL_InstallUpdate_f);
+ Cmd_AddCommand("checkForUpdate", CL_CheckForUpdate_f);
+ Cmd_AddCommand("browseHomepath", CL_BrowseHomepath_f);
+ Cmd_AddCommand("browseDemos", CL_BrowseDemos_f);
+ Cmd_AddCommand("browseScreenShots", CL_BrowseScreenShots_f);
+
+ CL_InitRef();
+
+ SCR_Init();
+
+ // Cbuf_Execute ();
+
+ Cvar_Set("cl_running", "1");
+
+ if (cl_rsaAuth->integer) CL_LoadRSAKeypair();
+
+ CL_GenerateQKey();
+ Cvar_Get("cl_guid", "", CVAR_USERINFO | CVAR_ROM);
+ if (clc.state == CA_DISCONNECTED) CL_UpdateGUID(NULL, 0);
+
+ Com_Printf("----- Client Initialization Complete -----\n");
+}
+
+/*
+===============
+CL_Shutdown
+
+===============
+*/
+void CL_Shutdown(const char *finalmsg, bool disconnect, bool quit)
+{
+ static bool recursive = false;
+ int realtime;
+
+ // check whether the client is running at all.
+ if (!(com_cl_running && com_cl_running->integer)) return;
+
+ Com_Printf("----- Client Shutdown (%s) -----\n", finalmsg);
+
+ if (recursive)
+ {
+ Com_Printf("WARNING: Recursive shutdown\n");
+ return;
+ }
+ recursive = true;
+
+ noGameRestart = quit;
+
+ if (disconnect) CL_Disconnect(true);
+
+ CL_ClearMemory(true);
+ CL_Snd_Shutdown();
+
+ Cmd_RemoveCommand("cmd");
+ Cmd_RemoveCommand("configstrings");
+ Cmd_RemoveCommand("clientinfo");
+ Cmd_RemoveCommand("snd_restart");
+ Cmd_RemoveCommand("vid_restart");
+ Cmd_RemoveCommand("disconnect");
+ Cmd_RemoveCommand("record");
+ Cmd_RemoveCommand("demo");
+ Cmd_RemoveCommand("cinematic");
+ Cmd_RemoveCommand("stoprecord");
+ Cmd_RemoveCommand("connect");
+ Cmd_RemoveCommand("reconnect");
+ Cmd_RemoveCommand("localservers");
+ Cmd_RemoveCommand("globalservers");
+ Cmd_RemoveCommand("rcon");
+ Cmd_RemoveCommand("ping");
+ Cmd_RemoveCommand("serverstatus");
+ Cmd_RemoveCommand("showip");
+ Cmd_RemoveCommand("fs_openedList");
+ Cmd_RemoveCommand("fs_referencedList");
+ Cmd_RemoveCommand("model");
+ Cmd_RemoveCommand("video");
+ Cmd_RemoveCommand("stopvideo");
+
+ CL_ShutdownInput();
+ Con_Shutdown();
+
+ Cvar_Set("cl_running", "0");
+
+ recursive = false;
+
+ if (cl_rsaAuth->integer) CL_UnloadRSAKeypair();
+
+ realtime = cls.realtime;
+ ::memset(&cls, 0, sizeof(cls));
+ cls.realtime = realtime;
+ Key_SetCatcher(0);
+
+ Com_Printf("-----------------------\n");
+}
diff --git a/src/client/cl_net_chan.cpp b/src/client/cl_net_chan.cpp
new file mode 100644
index 0000000..80ac25d
--- /dev/null
+++ b/src/client/cl_net_chan.cpp
@@ -0,0 +1,190 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "client.h"
+
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+/*
+==============
+CL_Netchan_Encode
+
+ // first 12 bytes of the data are always:
+ long serverId;
+ long messageAcknowledge;
+ long reliableAcknowledge;
+
+==============
+*/
+static void CL_Netchan_Encode(msg_t *msg)
+{
+ int serverId, messageAcknowledge, reliableAcknowledge;
+ int i, idx, srdc, sbit;
+ bool soob;
+ byte key, *string;
+
+ if (msg->cursize <= CL_ENCODE_START)
+ {
+ return;
+ }
+
+ srdc = msg->readcount;
+ sbit = msg->bit;
+ soob = msg->oob;
+
+ msg->bit = 0;
+ msg->readcount = 0;
+ msg->oob = false;
+
+ serverId = MSG_ReadLong(msg);
+ messageAcknowledge = MSG_ReadLong(msg);
+ reliableAcknowledge = MSG_ReadLong(msg);
+
+ msg->oob = soob;
+ msg->bit = sbit;
+ msg->readcount = srdc;
+
+ string = (byte *)clc.serverCommands[reliableAcknowledge & (MAX_RELIABLE_COMMANDS - 1)];
+ idx = 0;
+ //
+ key = clc.challenge ^ serverId ^ messageAcknowledge;
+ for (i = CL_ENCODE_START; i < msg->cursize; i++)
+ {
+ // modify the key with the last received now acknowledged server command
+ if (!string[idx]) idx = 0;
+ if (string[idx] > 127 || (string[idx] == '%' && clc.netchan.alternateProtocol == 2))
+ {
+ key ^= '.' << (i & 1);
+ }
+ else
+ {
+ key ^= string[idx] << (i & 1);
+ }
+ idx++;
+ // encode the data with this key
+ *(msg->data + i) = (*(msg->data + i)) ^ key;
+ }
+}
+
+/*
+==============
+CL_Netchan_Decode
+
+ // first four bytes of the data are always:
+ long reliableAcknowledge;
+
+==============
+*/
+static void CL_Netchan_Decode(msg_t *msg)
+{
+ long reliableAcknowledge, i, idx;
+ byte key, *string;
+ int srdc, sbit;
+ bool soob;
+
+ srdc = msg->readcount;
+ sbit = msg->bit;
+ soob = msg->oob;
+
+ msg->oob = false;
+
+ reliableAcknowledge = MSG_ReadLong(msg);
+
+ msg->oob = soob;
+ msg->bit = sbit;
+ msg->readcount = srdc;
+
+ string = (byte *)clc.reliableCommands[reliableAcknowledge & (MAX_RELIABLE_COMMANDS - 1)];
+ idx = 0;
+ // xor the client challenge with the netchan sequence number (need something that changes every message)
+ key = clc.challenge ^ LittleLong(*(unsigned *)msg->data);
+ for (i = msg->readcount + CL_DECODE_START; i < msg->cursize; i++)
+ {
+ // modify the key with the last sent and with this message acknowledged client command
+ if (!string[idx]) idx = 0;
+ if (string[idx] > 127 || (string[idx] == '%' && clc.netchan.alternateProtocol == 2))
+ {
+ key ^= '.' << (i & 1);
+ }
+ else
+ {
+ key ^= string[idx] << (i & 1);
+ }
+ idx++;
+ // decode the data with this key
+ *(msg->data + i) = *(msg->data + i) ^ key;
+ }
+}
+
+/*
+=================
+CL_Netchan_TransmitNextFragment
+=================
+*/
+static bool CL_Netchan_TransmitNextFragment(netchan_t *chan)
+{
+ if (chan->unsentFragments)
+ {
+ Netchan_TransmitNextFragment(chan);
+ return true;
+ }
+
+ return false;
+}
+
+/*
+===============
+CL_Netchan_Transmit
+================
+*/
+void CL_Netchan_Transmit(netchan_t *chan, msg_t *msg)
+{
+ MSG_WriteByte(msg, clc_EOF);
+
+ if (chan->alternateProtocol != 0) CL_Netchan_Encode(msg);
+ Netchan_Transmit(chan, msg->cursize, msg->data);
+
+ // Transmit all fragments without delay
+ while (CL_Netchan_TransmitNextFragment(chan))
+ {
+ Com_DPrintf("WARNING: #462 unsent fragments (not supposed to happen!)\n");
+ }
+}
+
+/*
+=================
+CL_Netchan_Process
+=================
+*/
+bool CL_Netchan_Process(netchan_t *chan, msg_t *msg)
+{
+ int ret;
+
+ ret = Netchan_Process(chan, msg);
+ if (!ret) return false;
+ if (chan->alternateProtocol != 0) CL_Netchan_Decode(msg);
+
+ return true;
+}
diff --git a/src/client/cl_parse.cpp b/src/client/cl_parse.cpp
new file mode 100644
index 0000000..111211a
--- /dev/null
+++ b/src/client/cl_parse.cpp
@@ -0,0 +1,961 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// cl_parse.c -- parse a message received from the server
+
+#include "client.h"
+
+const char *svc_strings[256] = {
+ "svc_bad",
+ "svc_nop",
+ "svc_gamestate",
+ "svc_configstring",
+ "svc_baseline",
+ "svc_serverCommand",
+ "svc_download",
+ "svc_snapshot",
+ "svc_EOF",
+ "svc_voipSpeex",
+ "svc_voipOpus",
+};
+
+void SHOWNET( msg_t *msg, const char *s) {
+ if ( cl_shownet->integer >= 2) {
+ Com_Printf ("%3i:%s\n", msg->readcount-1, s);
+ }
+}
+
+
+/*
+=========================================================================
+
+MESSAGE PARSING
+
+=========================================================================
+*/
+
+/*
+==================
+CL_DeltaEntity
+
+Parses deltas from the given base and adds the resulting entity
+to the current frame
+==================
+*/
+static void CL_DeltaEntity(msg_t *msg, clSnapshot_t *frame, int newnum, entityState_t *old, bool unchanged)
+{
+ entityState_t *state;
+
+ // save the parsed entity state into the big circular buffer so it can be
+ // used as the source for a later delta
+ state = &cl.parseEntities[cl.parseEntitiesNum & (MAX_PARSE_ENTITIES-1)];
+
+ if ( unchanged )
+ {
+ *state = *old;
+ }
+ else
+ {
+ MSG_ReadDeltaEntity( clc.netchan.alternateProtocol, msg, old, state, newnum );
+ }
+
+ if ( state->number == (MAX_GENTITIES-1) )
+ {
+ return; // entity was delta removed
+ }
+
+ cl.parseEntitiesNum++;
+ frame->numEntities++;
+}
+
+/*
+==================
+CL_ParsePacketEntities
+
+==================
+*/
+static void CL_ParsePacketEntities( msg_t *msg, clSnapshot_t *oldframe, clSnapshot_t *newframe)
+{
+ int newnum;
+ entityState_t *oldstate;
+ int oldindex, oldnum;
+
+ newframe->parseEntitiesNum = cl.parseEntitiesNum;
+ newframe->numEntities = 0;
+
+ // delta from the entities present in oldframe
+ oldindex = 0;
+ oldstate = NULL;
+ if (!oldframe) {
+ oldnum = 99999;
+ } else {
+ if ( oldindex >= oldframe->numEntities ) {
+ oldnum = 99999;
+ } else {
+ oldstate = &cl.parseEntities[
+ (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+
+ while ( 1 ) {
+ // read the entity index number
+ newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
+
+ if ( newnum == (MAX_GENTITIES-1) ) {
+ break;
+ }
+
+ if ( msg->readcount > msg->cursize ) {
+ Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
+ }
+
+ while ( oldnum < newnum ) {
+ // one or more entities from the old packet are unchanged
+ if ( cl_shownet->integer == 3 ) {
+ Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
+ }
+ CL_DeltaEntity( msg, newframe, oldnum, oldstate, true );
+
+ oldindex++;
+
+ if ( oldindex >= oldframe->numEntities ) {
+ oldnum = 99999;
+ } else {
+ oldstate = &cl.parseEntities[
+ (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+ if (oldnum == newnum) {
+ // delta from previous state
+ if ( cl_shownet->integer == 3 ) {
+ Com_Printf ("%3i: delta: %i\n", msg->readcount, newnum);
+ }
+ CL_DeltaEntity( msg, newframe, newnum, oldstate, false );
+
+ oldindex++;
+
+ if ( oldindex >= oldframe->numEntities ) {
+ oldnum = 99999;
+ } else {
+ oldstate = &cl.parseEntities[
+ (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ continue;
+ }
+
+ if ( oldnum > newnum ) {
+ // delta from baseline
+ if ( cl_shownet->integer == 3 ) {
+ Com_Printf ("%3i: baseline: %i\n", msg->readcount, newnum);
+ }
+ CL_DeltaEntity( msg, newframe, newnum, &cl.entityBaselines[newnum], false );
+ continue;
+ }
+
+ }
+
+ // any remaining entities in the old frame are copied over
+ while ( oldnum != 99999 ) {
+ // one or more entities from the old packet are unchanged
+ if ( cl_shownet->integer == 3 ) {
+ Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
+ }
+ CL_DeltaEntity( msg, newframe, oldnum, oldstate, true );
+
+ oldindex++;
+
+ if ( oldindex >= oldframe->numEntities ) {
+ oldnum = 99999;
+ } else {
+ oldstate = &cl.parseEntities[
+ (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+}
+
+
+/*
+================
+CL_ParseSnapshot
+
+If the snapshot is parsed properly, it will be copied to
+cl.snap and saved in cl.snapshots[]. If the snapshot is invalid
+for any reason, no changes to the state will be made at all.
+================
+*/
+void CL_ParseSnapshot( msg_t *msg ) {
+ int len;
+ clSnapshot_t *old;
+ clSnapshot_t newSnap;
+ int deltaNum;
+ int oldMessageNum;
+ int i, packetNum;
+
+ // get the reliable sequence acknowledge number
+ // NOTE: now sent with all server to client messages
+ //clc.reliableAcknowledge = MSG_ReadLong( msg );
+
+ // read in the new snapshot to a temporary buffer
+ // we will only copy to cl.snap if it is valid
+ ::memset(&newSnap, 0, sizeof(newSnap));
+
+ // we will have read any new server commands in this
+ // message before we got to svc_snapshot
+ newSnap.serverCommandNum = clc.serverCommandSequence;
+
+ newSnap.serverTime = MSG_ReadLong( msg );
+
+ // if we were just unpaused, we can only *now* really let the
+ // change come into effect or the client hangs.
+ cl_paused->modified = false;
+
+ newSnap.messageNum = clc.serverMessageSequence;
+
+ deltaNum = MSG_ReadByte( msg );
+ if ( !deltaNum ) {
+ newSnap.deltaNum = -1;
+ } else {
+ newSnap.deltaNum = newSnap.messageNum - deltaNum;
+ }
+ newSnap.snapFlags = MSG_ReadByte( msg );
+
+ // If the frame is delta compressed from data that we
+ // no longer have available, we must suck up the rest of
+ // the frame, but not use it, then ask for a non-compressed
+ // message
+ if ( newSnap.deltaNum <= 0 ) {
+ newSnap.valid = true; // uncompressed frame
+ old = NULL;
+ clc.demowaiting = false; // we can start recording now
+ } else {
+ old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK];
+ if ( !old->valid ) {
+ // should never happen
+ Com_DPrintf ("Delta from invalid frame (not supposed to happen!).\n");
+ } else if ( old->messageNum != newSnap.deltaNum ) {
+ // The frame that the server did the delta from
+ // is too old, so we can't reconstruct it properly.
+ Com_DPrintf ("Delta frame too old.\n");
+ } else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES - MAX_SNAPSHOT_ENTITIES ) {
+ Com_DPrintf ("Delta parseEntitiesNum too old.\n");
+ } else {
+ newSnap.valid = true; // valid delta parse
+ }
+ }
+
+ // read areamask
+ len = MSG_ReadByte( msg );
+
+ if(len > sizeof(newSnap.areamask))
+ {
+ Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask", len);
+ return;
+ }
+
+ MSG_ReadData( msg, &newSnap.areamask, len);
+
+ // read playerinfo
+ SHOWNET( msg, "playerstate" );
+ if ( clc.netchan.alternateProtocol == 2 ) {
+ if ( old ) {
+ MSG_ReadDeltaAlternatePlayerstate( msg, &old->alternatePs, &newSnap.alternatePs );
+ } else {
+ MSG_ReadDeltaAlternatePlayerstate( msg, NULL, &newSnap.alternatePs );
+ }
+ } else {
+ if ( old ) {
+ MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
+ } else {
+ MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
+ }
+ }
+
+ // read packet entities
+ SHOWNET( msg, "packet entities" );
+ CL_ParsePacketEntities( msg, old, &newSnap );
+
+ // if not valid, dump the entire thing now that it has
+ // been properly read
+ if ( !newSnap.valid ) {
+ return;
+ }
+
+ // clear the valid flags of any snapshots between the last
+ // received and this one, so if there was a dropped packet
+ // it won't look like something valid to delta from next
+ // time we wrap around in the buffer
+ oldMessageNum = cl.snap.messageNum + 1;
+
+ if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) {
+ oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );
+ }
+ for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
+ cl.snapshots[oldMessageNum & PACKET_MASK].valid = false;
+ }
+
+ // copy to the current good spot
+ cl.snap = newSnap;
+ cl.snap.ping = 999;
+ // calculate ping time
+ for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
+ packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
+ if ( ( clc.netchan.alternateProtocol == 2 ? cl.snap.alternatePs.commandTime : cl.snap.ps.commandTime ) >= cl.outPackets[ packetNum ].p_serverTime ) {
+ cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;
+ break;
+ }
+ }
+ // save the frame off in the backup array for later delta comparisons
+ cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap;
+
+ if (cl_shownet->integer == 3) {
+ Com_Printf( " snapshot:%i delta:%i ping:%i\n", cl.snap.messageNum,
+ cl.snap.deltaNum, cl.snap.ping );
+ }
+
+ cl.newSnapshots = true;
+}
+
+
+//=====================================================================
+
+bool cl_connectedToPureServer;
+bool cl_connectedToCheatServer;
+
+/*
+==================
+CL_SystemInfoChanged
+
+The systeminfo configstring has been changed, so parse
+new information out of it. This will happen at every
+gamestate, and possibly during gameplay.
+==================
+*/
+void CL_SystemInfoChanged( void ) {
+ char *systemInfo;
+ const char *s, *t;
+ char key[BIG_INFO_KEY];
+ char value[BIG_INFO_VALUE];
+ bool gameSet;
+
+ systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ];
+ // NOTE TTimo:
+ // when the serverId changes, any further messages we send to the server will use this new serverId
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
+ // in some cases, outdated cp commands might get sent with this news serverId
+ cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) );
+
+#ifdef USE_VOIP
+ s = Info_ValueForKey( systemInfo, "sv_voipProtocol" );
+ clc.voipEnabled = !Q_stricmp(s, "opus");
+#endif
+
+ // only set the paks, fs_game, and sv_pure when playing a demo
+ if ( !clc.demoplaying ) {
+ s = Info_ValueForKey( systemInfo, "sv_cheats" );
+ cl_connectedToCheatServer = (bool)atoi( s );
+ if ( !cl_connectedToCheatServer ) {
+ Cvar_SetCheatState();
+ }
+ }
+
+ // check pure server string
+ s = Info_ValueForKey( systemInfo, "sv_paks" );
+ t = Info_ValueForKey( systemInfo, "sv_pakNames" );
+ FS_PureServerSetLoadedPaks( s, t );
+
+ s = Info_ValueForKey( systemInfo, "sv_referencedPaks" );
+ t = Info_ValueForKey( systemInfo, "sv_referencedPakNames" );
+ FS_PureServerSetReferencedPaks( s, t );
+
+ gameSet = false;
+ // scan through all the variables in the systeminfo and locally set cvars to match
+ s = systemInfo;
+ while ( s ) {
+ int cvar_flags;
+
+ Info_NextPair( &s, key, value );
+ if ( !key[0] ) {
+ break;
+ }
+
+ // ehw!
+ if (!Q_stricmp(key, "fs_game"))
+ {
+ if(FS_CheckDirTraversal(value))
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value);
+ continue;
+ }
+
+ gameSet = true;
+ } else if ( clc.demoplaying && Q_stricmp(key, "sv_pure" ) ) {
+ continue;
+ }
+
+ if((cvar_flags = Cvar_Flags(key)) == CVAR_NONEXISTENT)
+ Cvar_Get(key, value, CVAR_SERVER_CREATED | CVAR_ROM);
+ else
+ {
+ // If this cvar may not be modified by a server discard the value.
+ if(!(cvar_flags & (CVAR_SYSTEMINFO | CVAR_SERVER_CREATED | CVAR_USER_CREATED)))
+ {
+ if(Q_stricmp(key, "g_synchronousClients") && Q_stricmp(key, "pmove_fixed") &&
+ Q_stricmp(key, "pmove_msec"))
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: server is not allowed to set %s=%s\n", key, value);
+ continue;
+ }
+ }
+
+ Cvar_SetSafe(key, value);
+ }
+ }
+ // if game folder should not be set and it is set at the client side
+ if ( !gameSet && *Cvar_VariableString("fs_game") ) {
+ Cvar_Set( "fs_game", "" );
+ }
+ cl_connectedToPureServer = (bool)Cvar_VariableValue( "sv_pure" );
+}
+
+/*
+==================
+CL_ParseServerInfo
+==================
+*/
+static void CL_ParseServerInfo(void)
+{
+ const char *serverInfo;
+
+ serverInfo = cl.gameState.stringData
+ + cl.gameState.stringOffsets[ CS_SERVERINFO ];
+
+ clc.sv_allowDownload = atoi(Info_ValueForKey(serverInfo,
+ "sv_allowDownload"));
+ Q_strncpyz(clc.sv_dlURL,
+ Info_ValueForKey(serverInfo, "sv_dlURL"),
+ sizeof(clc.sv_dlURL));
+}
+
+/*
+==================
+CL_ParseGamestate
+==================
+*/
+void CL_ParseGamestate( msg_t *msg ) {
+ int i;
+ entityState_t *es;
+ int newnum;
+ entityState_t nullstate;
+ int cmd;
+ char *s;
+ char oldGame[MAX_QPATH];
+
+ clc.connectPacketCount = 0;
+
+ // wipe local client state
+ CL_ClearState();
+
+ // a gamestate always marks a server command sequence
+ clc.serverCommandSequence = MSG_ReadLong( msg );
+
+ // parse all the configstrings and baselines
+ cl.gameState.dataCount = 1; // leave a 0 at the beginning for uninitialized configstrings
+ while ( 1 ) {
+ cmd = MSG_ReadByte( msg );
+
+ if ( cmd == svc_EOF ) {
+ break;
+ }
+
+ if ( cmd == svc_configstring ) {
+ int len;
+
+ i = MSG_ReadShort( msg );
+ if ( i < 0 || i >= MAX_CONFIGSTRINGS ) {
+ Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
+ }
+ s = MSG_ReadBigString( msg );
+ len = strlen( s );
+
+ if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
+ Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" );
+ }
+
+ // append it to the gameState string buffer
+ cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
+ ::memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 );
+ cl.gameState.dataCount += len + 1;
+ } else if ( cmd == svc_baseline ) {
+ newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
+ if ( newnum < 0 || newnum >= MAX_GENTITIES ) {
+ Com_Error( ERR_DROP, "Baseline number out of range: %i", newnum );
+ }
+ ::memset(&nullstate, 0, sizeof(nullstate));
+ es = &cl.entityBaselines[ newnum ];
+ MSG_ReadDeltaEntity( clc.netchan.alternateProtocol, msg, &nullstate, es, newnum );
+ } else {
+ Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte" );
+ }
+ }
+
+ clc.clientNum = MSG_ReadLong(msg);
+ // read the checksum feed
+ clc.checksumFeed = MSG_ReadLong( msg );
+
+ // save old gamedir
+ Cvar_VariableStringBuffer("fs_game", oldGame, sizeof(oldGame));
+
+ // parse useful values out of CS_SERVERINFO
+ CL_ParseServerInfo();
+
+ // parse serverId and other cvars
+ CL_SystemInfoChanged();
+
+ // stop recording now so the demo won't have an unnecessary level load at the end.
+ if(cl_autoRecordDemo->integer && clc.demorecording)
+ CL_StopRecord_f();
+
+ // reinitialize the filesystem if the game directory has changed
+ if(!cl_oldGameSet && (Cvar_Flags("fs_game") & CVAR_MODIFIED))
+ {
+ cl_oldGameSet = true;
+ Q_strncpyz(cl_oldGame, oldGame, sizeof(cl_oldGame));
+ }
+
+ FS_ConditionalRestart(clc.checksumFeed, false);
+
+ // This used to call CL_StartHunkUsers, but now we enter the download state before loading the
+ // cgame
+ CL_InitDownloads();
+
+ // make sure the game starts
+ Cvar_Set( "cl_paused", "0" );
+}
+
+
+//=====================================================================
+
+/*
+=====================
+CL_ParseDownload
+
+A download message has been received from the server
+=====================
+*/
+void CL_ParseDownload ( msg_t *msg ) {
+ int size;
+ unsigned char data[MAX_MSGLEN];
+ uint16_t block;
+
+ if (!*clc.downloadTempName) {
+ Com_Printf("Server sending download, but no download was requested\n");
+ CL_AddReliableCommand("stopdl", false);
+ return;
+ }
+
+ // read the data
+ block = MSG_ReadShort ( msg );
+
+ if(!block && !clc.downloadBlock)
+ {
+ // block zero is special, contains file size
+ clc.downloadSize = MSG_ReadLong ( msg );
+
+ Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
+
+ if (clc.downloadSize < 0)
+ {
+ Com_Error( ERR_DROP, "%s", MSG_ReadString( msg ) );
+ return;
+ }
+ }
+
+ size = MSG_ReadShort ( msg );
+ if (size < 0 || size > sizeof(data))
+ {
+ Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk", size);
+ return;
+ }
+
+ MSG_ReadData(msg, data, size);
+
+ if((clc.downloadBlock & 0xFFFF) != block)
+ {
+ Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", (clc.downloadBlock & 0xFFFF), block);
+ return;
+ }
+
+ // open the file if not opened yet
+ if (!clc.download)
+ {
+ clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );
+
+ if (!clc.download) {
+ Com_Printf( "Could not create %s\n", clc.downloadTempName );
+ CL_AddReliableCommand("stopdl", false);
+ CL_NextDownload();
+ return;
+ }
+ }
+
+ if (size)
+ FS_Write( data, size, clc.download );
+
+ CL_AddReliableCommand(va("nextdl %d", clc.downloadBlock), false);
+ clc.downloadBlock++;
+
+ clc.downloadCount += size;
+
+ // So UI gets access to it
+ Cvar_SetValue( "cl_downloadCount", clc.downloadCount );
+
+ if (!size) { // A zero length block means EOF
+ if (clc.download) {
+ FS_FCloseFile( clc.download );
+ clc.download = 0;
+
+ // rename the file
+ FS_SV_Rename( clc.downloadTempName, clc.downloadName, false );
+ }
+
+ // send intentions now
+ // We need this because without it, we would hold the last nextdl and then start
+ // loading right away. If we take a while to load, the server is happily trying
+ // to send us that last block over and over.
+ // Write it twice to help make sure we acknowledge the download
+ CL_WritePacket();
+ CL_WritePacket();
+
+ // get another file if needed
+ CL_NextDownload ();
+ }
+}
+
+#ifdef USE_VOIP
+static bool CL_ShouldIgnoreVoipSender(int sender)
+{
+ if (!cl_voip->integer)
+ return true; // VoIP is disabled.
+ else if ((sender == clc.clientNum) && (!clc.demoplaying))
+ return true; // ignore own voice (unless playing back a demo).
+ else if (clc.voipMuteAll)
+ return true; // all channels are muted with extreme prejudice.
+ else if (clc.voipIgnore[sender])
+ return true; // just ignoring this guy.
+ else if (clc.voipGain[sender] == 0.0f)
+ return true; // too quiet to play.
+
+ return false;
+}
+
+/*
+=====================
+CL_PlayVoip
+
+Play raw data
+=====================
+*/
+
+static void CL_PlayVoip(int sender, int samplecnt, const byte *data, int flags)
+{
+ if(flags & VOIP_DIRECT)
+ {
+ S_RawSamples(sender + 1, samplecnt, 48000, 2, 1, data, clc.voipGain[sender], -1);
+ }
+
+ if(flags & VOIP_SPATIAL)
+ {
+ S_RawSamples(sender + MAX_CLIENTS + 1, samplecnt, 48000, 2, 1, data, 1.0f, sender);
+ }
+}
+
+/*
+=====================
+CL_ParseVoip
+
+A VoIP message has been received from the server
+=====================
+*/
+static void CL_ParseVoip( msg_t *msg, bool ignoreData )
+{
+ static short decoded[VOIP_MAX_PACKET_SAMPLES*4]; // !!! FIXME: don't hard code
+
+ const int sender = MSG_ReadShort(msg);
+ const int generation = MSG_ReadByte(msg);
+ const int sequence = MSG_ReadLong(msg);
+ const int frames = MSG_ReadByte(msg);
+ const int packetsize = MSG_ReadShort(msg);
+ int flags = VOIP_DIRECT;
+ if (clc.netchan.alternateProtocol == 0)
+ flags = MSG_ReadBits(msg, VOIP_FLAGCNT);
+ char encoded[4000];
+ int numSamples;
+ int seqdiff;
+ int written = 0;
+ int i;
+
+ Com_DPrintf("VoIP: %d-byte packet from client %d\n", packetsize, sender);
+
+ if (sender < 0)
+ return; // short/invalid packet, bail.
+ else if (generation < 0)
+ return; // short/invalid packet, bail.
+ else if (sequence < 0)
+ return; // short/invalid packet, bail.
+ else if (frames < 0)
+ return; // short/invalid packet, bail.
+ else if (packetsize < 0)
+ return; // short/invalid packet, bail.
+
+ if (packetsize > sizeof (encoded)) { // overlarge packet?
+ int bytesleft = packetsize;
+ while (bytesleft) {
+ int br = bytesleft;
+ if (br > sizeof (encoded))
+ br = sizeof (encoded);
+ MSG_ReadData(msg, encoded, br);
+ bytesleft -= br;
+ }
+ return; // overlarge packet, bail.
+ }
+
+ MSG_ReadData(msg, encoded, packetsize);
+
+ if (ignoreData) {
+ return; // just ignore legacy speex voip data
+ } else if (!clc.voipCodecInitialized) {
+ return; // can't handle VoIP without libopus!
+ } else if (sender >= MAX_CLIENTS) {
+ return; // bogus sender.
+ } else if (CL_ShouldIgnoreVoipSender(sender)) {
+ return; // Channel is muted, bail.
+ }
+
+ // !!! FIXME: make sure data is narrowband? Does decoder handle this?
+
+ Com_DPrintf("VoIP: packet accepted!\n");
+
+ seqdiff = sequence - clc.voipIncomingSequence[sender];
+
+ // This is a new "generation" ... a new recording started, reset the bits.
+ if (generation != clc.voipIncomingGeneration[sender]) {
+ Com_DPrintf("VoIP: new generation %d!\n", generation);
+ opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
+ clc.voipIncomingGeneration[sender] = generation;
+ seqdiff = 0;
+ } else if (seqdiff < 0) { // we're ahead of the sequence?!
+ // This shouldn't happen unless the packet is corrupted or something.
+ Com_DPrintf("VoIP: misordered sequence! %d < %d!\n",
+ sequence, clc.voipIncomingSequence[sender]);
+ // reset the decoder just in case.
+ opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
+ seqdiff = 0;
+ } else if (seqdiff * VOIP_MAX_PACKET_SAMPLES*2 >= sizeof (decoded)) { // dropped more than we can handle?
+ // just start over.
+ Com_DPrintf("VoIP: Dropped way too many (%d) frames from client #%d\n",
+ seqdiff, sender);
+ opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
+ seqdiff = 0;
+ }
+
+ if (seqdiff != 0) {
+ Com_DPrintf("VoIP: Dropped %d frames from client #%d\n",
+ seqdiff, sender);
+ // tell opus that we're missing frames...
+ for (i = 0; i < seqdiff; i++) {
+ assert((written + VOIP_MAX_PACKET_SAMPLES) * 2 < sizeof (decoded));
+ numSamples = opus_decode(clc.opusDecoder[sender], NULL, 0, decoded + written, VOIP_MAX_PACKET_SAMPLES, 0);
+ if ( numSamples <= 0 ) {
+ Com_DPrintf("VoIP: Error decoding frame %d from client #%d\n", i, sender);
+ continue;
+ }
+ written += numSamples;
+ }
+ }
+
+ numSamples = opus_decode(clc.opusDecoder[sender],
+ (const unsigned char*)encoded,
+ packetsize,
+ decoded + written,
+ ARRAY_LEN(decoded) - written,
+ 0);
+
+ if ( numSamples <= 0 ) {
+ Com_DPrintf("VoIP: Error decoding voip data from client #%d\n", sender);
+ numSamples = 0;
+ }
+
+ #if 0
+ static FILE *encio = NULL;
+ if (encio == NULL) encio = fopen("voip-incoming-encoded.bin", "wb");
+ if (encio != NULL) { fwrite(encoded, len, 1, encio); fflush(encio); }
+ static FILE *decio = NULL;
+ if (decio == NULL) decio = fopen("voip-incoming-decoded.bin", "wb");
+ if (decio != NULL) { fwrite(decoded+written, clc.speexFrameSize*2, 1, decio); fflush(decio); }
+ #endif
+
+ written += numSamples;
+
+ Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
+ written * 2, written, frames);
+
+ if(written > 0)
+ CL_PlayVoip(sender, written, (const byte *) decoded, flags);
+
+ clc.voipIncomingSequence[sender] = sequence + frames;
+}
+#endif
+
+
+/*
+=====================
+CL_ParseCommandString
+
+Command strings are just saved off until cgame asks for them
+when it transitions a snapshot
+=====================
+*/
+void CL_ParseCommandString( msg_t *msg ) {
+ char *s;
+ int seq;
+ int index;
+
+ seq = MSG_ReadLong( msg );
+ s = MSG_ReadString( msg );
+
+ // see if we have already executed stored it off
+ if ( clc.serverCommandSequence >= seq ) {
+ return;
+ }
+ clc.serverCommandSequence = seq;
+
+ index = seq & (MAX_RELIABLE_COMMANDS-1);
+ Q_strncpyz( clc.serverCommands[ index ], s, sizeof( clc.serverCommands[ index ] ) );
+}
+
+
+/*
+=====================
+CL_ParseServerMessage
+=====================
+*/
+void CL_ParseServerMessage( msg_t *msg ) {
+ int cmd;
+
+ if ( cl_shownet->integer == 1 ) {
+ Com_Printf ("%i ",msg->cursize);
+ } else if ( cl_shownet->integer >= 2 ) {
+ Com_Printf ("------------------\n");
+ }
+
+ MSG_Bitstream(msg);
+
+ // get the reliable sequence acknowledge number
+ clc.reliableAcknowledge = MSG_ReadLong( msg );
+ //
+ if ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) {
+ clc.reliableAcknowledge = clc.reliableSequence;
+ }
+
+ //
+ // parse the message
+ //
+ while ( 1 ) {
+ if ( msg->readcount > msg->cursize ) {
+ Com_Error (ERR_DROP,"CL_ParseServerMessage: read past end of server message");
+ break;
+ }
+
+ cmd = MSG_ReadByte( msg );
+
+ if ( clc.netchan.alternateProtocol != 0 )
+ {
+ // See if this is an extension command after the EOF, which means we
+ // got data that a legacy client should ignore.
+ if ( cmd == svc_EOF && MSG_LookaheadByte( msg ) == svc_voipSpeex ) {
+ SHOWNET( msg, "EXTENSION" );
+ MSG_ReadByte( msg ); // throw the svc_extension byte away.
+ cmd = MSG_ReadByte( msg ); // something legacy clients can't do!
+ // sometimes you get a svc_extension at end of stream...dangling
+ // bits in the huffman decoder giving a bogus value?
+ if ( cmd == -1 ) {
+ cmd = svc_EOF;
+ }
+ }
+
+ if ( cmd == svc_voipSpeex ) {
+ cmd = svc_voipSpeex + 1;
+ } else if ( cmd == svc_voipSpeex + 1 ) {
+ cmd = svc_voipSpeex;
+ }
+ }
+
+ if (cmd == svc_EOF) {
+ SHOWNET( msg, "END OF MESSAGE" );
+ break;
+ }
+
+ if ( cl_shownet->integer >= 2 ) {
+ if ( (cmd < 0) || (!svc_strings[cmd]) ) {
+ Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd );
+ } else {
+ SHOWNET( msg, svc_strings[cmd] );
+ }
+ }
+
+ // other commands
+ switch ( cmd ) {
+ default:
+ Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message");
+ break;
+ case svc_nop:
+ break;
+ case svc_serverCommand:
+ CL_ParseCommandString( msg );
+ break;
+ case svc_gamestate:
+ CL_ParseGamestate( msg );
+ break;
+ case svc_snapshot:
+ CL_ParseSnapshot( msg );
+ break;
+ case svc_download:
+ CL_ParseDownload( msg );
+ break;
+ case svc_voipSpeex:
+#ifdef USE_VOIP
+ CL_ParseVoip( msg, true );
+#endif
+ break;
+ case svc_voipOpus:
+#ifdef USE_VOIP
+ CL_ParseVoip( msg, !clc.voipEnabled );
+#endif
+ break;
+ }
+ }
+}
diff --git a/src/client/cl_rest.cpp b/src/client/cl_rest.cpp
new file mode 100644
index 0000000..c1ff2fc
--- /dev/null
+++ b/src/client/cl_rest.cpp
@@ -0,0 +1,117 @@
+//
+// Restclient wrapper abusively modified to be a one-off donwloader.
+// -wtfbbqhax
+//
+// TODO Verify sha256 of file if exists
+
+#include "cl_rest.h"
+
+#include <unistd.h>
+
+#include <cerrno>
+#include <cstring>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include "qcommon/files.h"
+#include "restclient/restclient.h"
+
+bool is_good(std::string filename, int permissions = (R_OK|W_OK))
+{
+ int ret = access(filename.c_str(), permissions);
+ if (ret)
+ std::cerr << filename << ": " << strerror(errno) << std::endl;
+
+ return !ret;
+}
+
+bool MakeDir(std::string destdir, std::string basegame)
+{
+ std::string destpath(destdir);
+
+ if ( basegame != "" )
+ {
+ destpath += '/';
+ destpath += basegame;
+ }
+
+ if ( *destpath.rbegin() != '/' )
+ destpath += '/'; // XXX FS_CreatePath requires a trailing slash.
+ // Maybe the assumption is that a file listing might be included?
+
+ FS_CreatePath(destpath.c_str());
+ return true;
+}
+
+#include "sys/dialog.h"
+static bool PromptDownloadPk3s(std::string basegame, const std::vector<std::string>& missing)
+{
+ std::string msg;
+
+ msg = "The following files must be downloaded to complete the installation.\n\n";
+ for ( auto f : missing )
+ msg += "\t" + basegame + "/" + f + "\n";
+
+ msg += "\n";
+ msg += "Yes to continue, No to quit the game.";
+
+ if( Sys_Dialog( DT_YES_NO, msg.c_str(), "You're almost ready!" ) == DR_YES )
+ return true;
+
+ return false;
+}
+
+bool GetTremulousPk3s(const char* destdir, const char* basegame)
+{
+ std::string baseuri = "https://github.com/wtfbbqhax/tremulous-data/raw/master/";
+ std::vector<std::string> files = {
+ "data-gpp1.pk3",
+ "data-1.1.0.pk3",
+ "map-arachnid2-1.1.0.pk3",
+ "map-atcs-1.1.0.pk3",
+ "map-karith-1.1.0.pk3",
+ "map-nexus6-1.1.0.pk3",
+ "map-niveus-1.1.0.pk3",
+ "map-transit-1.1.0.pk3",
+ "map-tremor-1.1.0.pk3",
+ "map-uncreation-1.1.0.pk3"
+ };
+
+ RestClient::init();
+
+ MakeDir(destdir, basegame);
+
+ if (!PromptDownloadPk3s(basegame, files))
+ return false;
+
+ for (auto f : files )
+ {
+ std::string destpath(destdir);
+ destpath += "/";
+ destpath += basegame;
+ destpath += "/";
+ destpath += f;
+
+ if ( is_good(destpath) )
+ {
+ return false;
+ }
+
+ std::cout << "Downloading " << baseuri << f << std::endl;
+ std::ofstream dl(destpath);
+ //dl.open(destpath);
+ if ( dl.fail() )
+ {
+ std::cerr << "Error " << strerror(errno) << "\n";
+ continue;
+ }
+
+ RestClient::Response resp = RestClient::get(baseuri + f);
+
+ dl << resp.body;
+ dl.close();
+ }
+
+ return true;
+}
diff --git a/src/client/cl_rest.h b/src/client/cl_rest.h
new file mode 100644
index 0000000..afde7d2
--- /dev/null
+++ b/src/client/cl_rest.h
@@ -0,0 +1,18 @@
+#ifndef _CL_REST_H_
+#define _CL_REST_H_
+
+bool GetPermissions(const char*execpath);
+
+// Download a fresh copy of the "required" base game files to the top-most fs_basegame.
+//
+// Returns true(1) on success
+// Return false(0) on error
+//
+bool GetTremulousPk3s(const char* destdir, const char* basegame);
+
+#include <string>
+
+//bool is_good(std::string filename, int permissions = (R_OK|W_OK));
+bool MakeDir(std::string destdir, std::string basegame);
+
+#endif
diff --git a/src/client/cl_scrn.cpp b/src/client/cl_scrn.cpp
new file mode 100644
index 0000000..7d0c7e2
--- /dev/null
+++ b/src/client/cl_scrn.cpp
@@ -0,0 +1,588 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
+
+#include "client.h"
+
+bool scr_initialized; // ready to draw
+
+cvar_t *cl_timegraph;
+cvar_t *cl_debuggraph;
+cvar_t *cl_graphheight;
+cvar_t *cl_graphscale;
+cvar_t *cl_graphshift;
+
+/*
+================
+SCR_DrawNamedPic
+
+Coordinates are 640*480 virtual values
+=================
+*/
+void SCR_DrawNamedPic(float x, float y, float width, float height, const char *picname)
+{
+ qhandle_t hShader;
+
+ assert(width != 0);
+
+ hShader = re.RegisterShader(picname);
+ SCR_AdjustFrom640(&x, &y, &width, &height);
+ re.DrawStretchPic(x, y, width, height, 0, 0, 1, 1, hShader);
+}
+
+/*
+================
+SCR_AdjustFrom640
+
+Adjusted for resolution and screen aspect ratio
+================
+*/
+void SCR_AdjustFrom640(float *x, float *y, float *w, float *h)
+{
+ float xscale;
+ float yscale;
+
+#if 0
+ // adjust for wide screens
+ if ( cls.glconfig.vidWidth * 480 > cls.glconfig.vidHeight * 640 ) {
+ *x += 0.5 * ( cls.glconfig.vidWidth - ( cls.glconfig.vidHeight * 640 / 480 ) );
+ }
+#endif
+
+ // scale for screen sizes
+ xscale = cls.glconfig.vidWidth / 640.0;
+ yscale = cls.glconfig.vidHeight / 480.0;
+ if (x)
+ {
+ *x *= xscale;
+ }
+ if (y)
+ {
+ *y *= yscale;
+ }
+ if (w)
+ {
+ *w *= xscale;
+ }
+ if (h)
+ {
+ *h *= yscale;
+ }
+}
+
+/*
+================
+SCR_FillRect
+
+Coordinates are 640*480 virtual values
+=================
+*/
+void SCR_FillRect(float x, float y, float width, float height, const float *color)
+{
+ re.SetColor(color);
+
+ SCR_AdjustFrom640(&x, &y, &width, &height);
+ re.DrawStretchPic(x, y, width, height, 0, 0, 0, 0, cls.whiteShader);
+
+ re.SetColor(NULL);
+}
+
+/*
+================
+SCR_DrawPic
+
+Coordinates are 640*480 virtual values
+=================
+*/
+void SCR_DrawPic(float x, float y, float width, float height, qhandle_t hShader)
+{
+ SCR_AdjustFrom640(&x, &y, &width, &height);
+ re.DrawStretchPic(x, y, width, height, 0, 0, 1, 1, hShader);
+}
+
+/*
+** SCR_DrawChar
+** chars are drawn at 640*480 virtual screen size
+*/
+static void SCR_DrawChar(int x, int y, float size, int ch)
+{
+ int row, col;
+ float frow, fcol;
+ float ax, ay, aw, ah;
+
+ ch &= 255;
+
+ if (ch == ' ')
+ {
+ return;
+ }
+
+ if (y < -size)
+ {
+ return;
+ }
+
+ ax = x;
+ ay = y;
+ aw = size;
+ ah = size;
+ SCR_AdjustFrom640(&ax, &ay, &aw, &ah);
+
+ row = ch >> 4;
+ col = ch & 15;
+
+ frow = row * 0.0625;
+ fcol = col * 0.0625;
+ size = 0.0625;
+
+ re.DrawStretchPic(ax, ay, aw, ah, fcol, frow, fcol + size, frow + size, cls.charSetShader);
+}
+
+/*
+** SCR_DrawSmallChar
+** small chars are drawn at native screen resolution
+*/
+void SCR_DrawSmallChar(int x, int y, int ch)
+{
+ int row, col;
+ float frow, fcol;
+ float size;
+
+ ch &= 255;
+
+ if (ch == ' ')
+ {
+ return;
+ }
+
+ if (y < -SMALLCHAR_HEIGHT)
+ {
+ return;
+ }
+
+ row = ch >> 4;
+ col = ch & 15;
+
+ frow = row * 0.0625;
+ fcol = col * 0.0625;
+ size = 0.0625;
+
+ re.DrawStretchPic(x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, fcol, frow, fcol + size, frow + size, cls.charSetShader);
+}
+
+/*
+==================
+SCR_DrawBigString[Color]
+
+Draws a multi-colored string with a drop shadow, optionally forcing
+to a fixed color.
+
+Coordinates are at 640 by 480 virtual resolution
+==================
+*/
+static void SCR_DrawStringExt(
+ int x, int y, float size, const char *string, float *setColor, bool forceColor, bool noColorEscape)
+{
+ vec4_t color;
+ const char *s;
+ int xx;
+
+ // draw the drop shadow
+ color[0] = color[1] = color[2] = 0;
+ color[3] = setColor[3];
+ re.SetColor(color);
+ s = string;
+ xx = x;
+ while (*s)
+ {
+ if (!noColorEscape && Q_IsColorString(s))
+ {
+ s += 2;
+ continue;
+ }
+ SCR_DrawChar(xx + 2, y + 2, size, *s);
+ xx += size;
+ s++;
+ }
+
+ // draw the colored text
+ s = string;
+ xx = x;
+ re.SetColor(setColor);
+ while (*s)
+ {
+ if (Q_IsColorString(s))
+ {
+ if (!forceColor)
+ {
+ ::memcpy(color, g_color_table[ColorIndex(*(s + 1))], sizeof(color));
+ color[3] = setColor[3];
+ re.SetColor(color);
+ }
+ if (!noColorEscape)
+ {
+ s += 2;
+ continue;
+ }
+ }
+ SCR_DrawChar(xx, y, size, *s);
+ xx += size;
+ s++;
+ }
+ re.SetColor(NULL);
+}
+
+void SCR_DrawBigString(int x, int y, const char *s, float alpha, bool noColorEscape)
+{
+ float color[4];
+
+ color[0] = color[1] = color[2] = 1.0;
+ color[3] = alpha;
+ SCR_DrawStringExt(x, y, BIGCHAR_WIDTH, s, color, false, noColorEscape);
+}
+
+void SCR_DrawBigStringColor(int x, int y, const char *s, vec4_t color, bool noColorEscape)
+{
+ SCR_DrawStringExt(x, y, BIGCHAR_WIDTH, s, color, true, noColorEscape);
+}
+
+/*
+==================
+SCR_DrawSmallString[Color]
+
+Draws a multi-colored string with a drop shadow, optionally forcing
+to a fixed color.
+==================
+*/
+void SCR_DrawSmallStringExt(int x, int y, const char *string, float *setColor, bool forceColor, bool noColorEscape)
+{
+ vec4_t color;
+ const char *s;
+ int xx;
+
+ // draw the colored text
+ s = string;
+ xx = x;
+ re.SetColor(setColor);
+ while (*s)
+ {
+ if (Q_IsColorString(s))
+ {
+ if (!forceColor)
+ {
+ ::memcpy(color, g_color_table[ColorIndex(*(s + 1))], sizeof(color));
+ color[3] = setColor[3];
+ re.SetColor(color);
+ }
+ if (!noColorEscape)
+ {
+ s += 2;
+ continue;
+ }
+ }
+ SCR_DrawSmallChar(xx, y, *s);
+ xx += SMALLCHAR_WIDTH;
+ s++;
+ }
+ re.SetColor(NULL);
+}
+
+/*
+** SCR_Strlen -- skips color escape codes
+*/
+static int SCR_Strlen(const char *str)
+{
+ const char *s = str;
+ int count = 0;
+
+ while (*s)
+ {
+ if (Q_IsColorString(s))
+ {
+ s += 2;
+ }
+ else
+ {
+ count++;
+ s++;
+ }
+ }
+
+ return count;
+}
+
+/*
+** SCR_GetBigStringWidth
+*/
+int SCR_GetBigStringWidth(const char *str) { return SCR_Strlen(str) * BIGCHAR_WIDTH; }
+//===============================================================================
+
+#ifdef USE_VOIP
+/*
+=================
+SCR_DrawVoipMeter
+
+FIXME: inherited from ioq3, move to cgame/ui
+=================
+*/
+void SCR_DrawVoipMeter(void)
+{
+ char buffer[16];
+ char string[256];
+ int limit, i;
+
+ if (!cl_voipShowMeter->integer)
+ return; // player doesn't want to show meter at all.
+ else if (!cl_voipSend->integer)
+ return; // not recording at the moment.
+ else if (clc.state != CA_ACTIVE)
+ return; // not connected to a server.
+ else if (!clc.voipEnabled)
+ return; // server doesn't support VoIP.
+ else if (clc.demoplaying)
+ return; // playing back a demo.
+ else if (!cl_voip->integer)
+ return; // client has VoIP support disabled.
+
+ limit = (int)(clc.voipPower * 10.0f);
+ if (limit > 10) limit = 10;
+
+ for (i = 0; i < limit; i++) buffer[i] = '*';
+ while (i < 10) buffer[i++] = ' ';
+ buffer[i] = '\0';
+
+ sprintf(string, "VoIP: [%s]", buffer);
+ SCR_DrawStringExt(320 - strlen(string) * 4, 10, 8, string, g_color_table[7], true, false);
+}
+#endif
+
+/*
+===============================================================================
+
+DEBUG GRAPH
+
+===============================================================================
+*/
+
+static int current;
+static float values[1024];
+
+/*
+==============
+SCR_DebugGraph
+==============
+*/
+void SCR_DebugGraph(float value)
+{
+ values[current] = value;
+ current = (current + 1) % ARRAY_LEN(values);
+}
+
+/*
+==============
+SCR_DrawDebugGraph
+==============
+*/
+void SCR_DrawDebugGraph(void)
+{
+ int a, x, y, w, i, h;
+ float v;
+
+ //
+ // draw the graph
+ //
+ w = cls.glconfig.vidWidth;
+ x = 0;
+ y = cls.glconfig.vidHeight;
+ re.SetColor(g_color_table[0]);
+ re.DrawStretchPic(x, y - cl_graphheight->integer, w, cl_graphheight->integer, 0, 0, 0, 0, cls.whiteShader);
+ re.SetColor(NULL);
+
+ for (a = 0; a < w; a++)
+ {
+ i = (ARRAY_LEN(values) + current - 1 - (a % ARRAY_LEN(values))) % ARRAY_LEN(values);
+ v = values[i];
+ v = v * cl_graphscale->integer + cl_graphshift->integer;
+
+ if (v < 0) v += cl_graphheight->integer * (1 + (int)(-v / cl_graphheight->integer));
+ h = (int)v % cl_graphheight->integer;
+ re.DrawStretchPic(x + w - 1 - a, y - h, 1, h, 0, 0, 0, 0, cls.whiteShader);
+ }
+}
+
+//=============================================================================
+
+/*
+==================
+SCR_Init
+==================
+*/
+void SCR_Init(void)
+{
+ cl_timegraph = Cvar_Get("timegraph", "0", CVAR_CHEAT);
+ cl_debuggraph = Cvar_Get("debuggraph", "0", CVAR_CHEAT);
+ cl_graphheight = Cvar_Get("graphheight", "32", CVAR_CHEAT);
+ cl_graphscale = Cvar_Get("graphscale", "1", CVAR_CHEAT);
+ cl_graphshift = Cvar_Get("graphshift", "0", CVAR_CHEAT);
+
+ scr_initialized = true;
+}
+
+//=======================================================
+
+/*
+==================
+SCR_DrawScreenField
+
+This will be called twice if rendering in stereo mode
+==================
+*/
+void SCR_DrawScreenField(stereoFrame_t stereoFrame)
+{
+ bool uiFullscreen;
+
+ re.BeginFrame(stereoFrame);
+
+ uiFullscreen = (cls.ui && VM_Call(cls.ui, UI_IS_FULLSCREEN - (cls.uiInterface == 2 ? 2 : 0)));
+
+ // wide aspect ratio screens need to have the sides cleared
+ // unless they are displaying game renderings
+ if (uiFullscreen || clc.state < CA_LOADING)
+ {
+ if (cls.glconfig.vidWidth * 480 > cls.glconfig.vidHeight * 640)
+ {
+ re.SetColor(g_color_table[0]);
+ re.DrawStretchPic(0, 0, cls.glconfig.vidWidth, cls.glconfig.vidHeight, 0, 0, 0, 0, cls.whiteShader);
+ re.SetColor(NULL);
+ }
+ }
+
+ // if the menu is going to cover the entire screen, we
+ // don't need to render anything under it
+ if (cls.ui && !uiFullscreen)
+ {
+ switch (clc.state)
+ {
+ default:
+ Com_Error(ERR_FATAL, "SCR_DrawScreenField: bad clc.state");
+ break;
+ case CA_CINEMATIC:
+ SCR_DrawCinematic();
+ break;
+ case CA_DISCONNECTED:
+ // force menu up
+ S_StopAllSounds();
+ VM_Call(cls.ui, UI_SET_ACTIVE_MENU - (cls.uiInterface == 2 ? 2 : 0), UIMENU_MAIN);
+ break;
+ case CA_CONNECTING:
+ case CA_CHALLENGING:
+ case CA_CONNECTED:
+ // connecting clients will only show the connection dialog
+ // refresh to update the time
+ VM_Call(cls.ui, UI_REFRESH - (cls.uiInterface == 2 ? 2 : 0), cls.realtime);
+ VM_Call(cls.ui, UI_DRAW_CONNECT_SCREEN - (cls.uiInterface == 2 ? 2 : 0), false);
+ break;
+ case CA_LOADING:
+ case CA_PRIMED:
+ // draw the game information screen and loading progress
+ CL_CGameRendering(stereoFrame);
+ break;
+ case CA_ACTIVE:
+ // always supply STEREO_CENTER as vieworg offset is now done by the engine.
+ CL_CGameRendering(stereoFrame);
+#ifdef USE_VOIP
+ SCR_DrawVoipMeter();
+#endif
+ break;
+ }
+ }
+
+ // the menu draws next
+ if (Key_GetCatcher() & KEYCATCH_UI && cls.ui)
+ {
+ VM_Call(cls.ui, UI_REFRESH - (cls.uiInterface == 2 ? 2 : 0), cls.realtime);
+ }
+
+ // console draws next
+ Con_DrawConsole();
+
+ // debug graph can be drawn on top of anything
+ if (cl_debuggraph->integer || cl_timegraph->integer || cl_debugMove->integer)
+ {
+ SCR_DrawDebugGraph();
+ }
+}
+
+/*
+==================
+SCR_UpdateScreen
+
+This is called every frame, and can also be called explicitly to flush
+text to the screen.
+==================
+*/
+void SCR_UpdateScreen(void)
+{
+ static int recursive;
+
+ if (!scr_initialized)
+ {
+ return; // not initialized yet
+ }
+
+ if (++recursive > 2)
+ {
+ Com_Error(ERR_FATAL, "SCR_UpdateScreen: recursively called");
+ }
+ recursive = 1;
+
+ // If there is no VM, there are also no rendering commands issued. Stop the renderer in
+ // that case.
+ if (cls.ui || com_dedicated->integer)
+ {
+ // XXX
+ int in_anaglyphMode = Cvar_VariableIntegerValue("r_anaglyphMode");
+ // if running in stereo, we need to draw the frame twice
+ if (cls.glconfig.stereoEnabled || in_anaglyphMode)
+ {
+ SCR_DrawScreenField(STEREO_LEFT);
+ SCR_DrawScreenField(STEREO_RIGHT);
+ }
+ else
+ {
+ SCR_DrawScreenField(STEREO_CENTER);
+ }
+
+ if (com_speeds->integer)
+ {
+ re.EndFrame(&time_frontend, &time_backend);
+ }
+ else
+ {
+ re.EndFrame(NULL, NULL);
+ }
+ }
+
+ recursive = 0;
+}
diff --git a/src/client/cl_ui.cpp b/src/client/cl_ui.cpp
new file mode 100644
index 0000000..4052fe6
--- /dev/null
+++ b/src/client/cl_ui.cpp
@@ -0,0 +1,1269 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "client.h"
+
+#include "cl_updates.h"
+
+/*
+====================
+GetClientState
+====================
+*/
+static void GetClientState(uiClientState_t *state)
+{
+ state->connectPacketCount = clc.connectPacketCount;
+ state->connState = clc.state;
+ Q_strncpyz(state->servername, clc.servername, sizeof(state->servername));
+ Q_strncpyz(state->updateInfoString, cls.updateInfoString, sizeof(state->updateInfoString));
+ Q_strncpyz(state->messageString, clc.serverMessage, sizeof(state->messageString));
+ state->clientNum = (clc.netchan.alternateProtocol == 2 ? cl.snap.alternatePs.clientNum : cl.snap.ps.clientNum);
+}
+
+/*
+====================
+LAN_LoadCachedServers
+====================
+*/
+void LAN_LoadCachedServers(void)
+{
+ int size;
+ fileHandle_t fileIn;
+ cls.numglobalservers = cls.numfavoriteservers = 0;
+ cls.numGlobalServerAddresses = 0;
+ if (FS_SV_FOpenFileRead("servercache.dat", &fileIn))
+ {
+ FS_Read(&cls.numglobalservers, sizeof(int), fileIn);
+ FS_Read(&cls.numfavoriteservers, sizeof(int), fileIn);
+ FS_Read(&size, sizeof(int), fileIn);
+ if (size == sizeof(cls.globalServers) + sizeof(cls.favoriteServers))
+ {
+ FS_Read(&cls.globalServers, sizeof(cls.globalServers), fileIn);
+ FS_Read(&cls.favoriteServers, sizeof(cls.favoriteServers), fileIn);
+ }
+ else
+ {
+ cls.numglobalservers = cls.numfavoriteservers = 0;
+ cls.numGlobalServerAddresses = 0;
+ }
+ FS_FCloseFile(fileIn);
+ }
+}
+
+/*
+====================
+LAN_SaveServersToCache
+====================
+*/
+void LAN_SaveServersToCache(void)
+{
+ fileHandle_t fileOut = FS_SV_FOpenFileWrite("servercache.dat");
+ FS_Write(&cls.numglobalservers, sizeof(int), fileOut);
+ FS_Write(&cls.numfavoriteservers, sizeof(int), fileOut);
+
+ int size = sizeof(cls.globalServers) + sizeof(cls.favoriteServers);
+ FS_Write(&size, sizeof(int), fileOut);
+ FS_Write(&cls.globalServers, sizeof(cls.globalServers), fileOut);
+ FS_Write(&cls.favoriteServers, sizeof(cls.favoriteServers), fileOut);
+ FS_FCloseFile(fileOut);
+}
+
+/*
+====================
+GetNews
+====================
+*/
+static bool GetNews(bool begin)
+{
+ bool finished = false;
+ fileHandle_t fileIn;
+ int readSize;
+
+ if (begin)
+ { // if not already using curl, start the download
+ if (!clc.downloadCURLM)
+ {
+ if (!CL_cURL_Init())
+ {
+ Cvar_Set("cl_newsString", "^1Error: Could not load cURL library");
+ return true;
+ }
+ clc.activeCURLNotGameRelated = true;
+ CL_cURL_BeginDownload("news.dat", "http://grangerhub.com/wp-content/uploads/clientnews.txt");
+ return false;
+ }
+ }
+
+ if (!clc.downloadCURLM && FS_SV_FOpenFileRead("news.dat", &fileIn))
+ {
+ readSize = FS_Read(clc.newsString, sizeof(clc.newsString), fileIn);
+ FS_FCloseFile(fileIn);
+ clc.newsString[readSize] = '\0';
+ if (readSize > 0)
+ {
+ finished = true;
+ clc.cURLUsed = false;
+ CL_cURL_Shutdown();
+ clc.activeCURLNotGameRelated = false;
+ }
+ }
+ if (!finished) strcpy(clc.newsString, "Retrieving...");
+ Cvar_Set("cl_newsString", clc.newsString);
+ return finished;
+ Cvar_Set("cl_newsString", "^1You must compile your client with CURL support to use this feature");
+ return true;
+}
+
+/*
+====================
+LAN_ResetPings
+====================
+*/
+static void LAN_ResetPings(int source)
+{
+ int count, i;
+ serverInfo_t *servers = NULL;
+ count = 0;
+
+ switch (source)
+ {
+ case AS_LOCAL:
+ servers = &cls.localServers[0];
+ count = MAX_OTHER_SERVERS;
+ break;
+ case AS_MPLAYER:
+ case AS_GLOBAL:
+ servers = &cls.globalServers[0];
+ count = MAX_GLOBAL_SERVERS;
+ break;
+ case AS_FAVORITES:
+ servers = &cls.favoriteServers[0];
+ count = MAX_OTHER_SERVERS;
+ break;
+ }
+ if (servers)
+ {
+ for (i = 0; i < count; i++)
+ {
+ servers[i].ping = -1;
+ }
+ }
+}
+
+/*
+====================
+LAN_AddServer
+====================
+*/
+static int LAN_AddServer(int source, const char *name, const char *address)
+{
+ int max, *count, i;
+ netadr_t adr;
+ serverInfo_t *servers = NULL;
+ max = MAX_OTHER_SERVERS;
+ count = NULL;
+
+ switch (source)
+ {
+ case AS_LOCAL:
+ count = &cls.numlocalservers;
+ servers = &cls.localServers[0];
+ break;
+ case AS_MPLAYER:
+ case AS_GLOBAL:
+ max = MAX_GLOBAL_SERVERS;
+ count = &cls.numglobalservers;
+ servers = &cls.globalServers[0];
+ break;
+ case AS_FAVORITES:
+ count = &cls.numfavoriteservers;
+ servers = &cls.favoriteServers[0];
+ break;
+ }
+ if (servers && *count < max)
+ {
+ NET_StringToAdr(address, &adr, NA_UNSPEC);
+ for (i = 0; i < *count; i++)
+ {
+ if (NET_CompareAdr(servers[i].adr, adr))
+ {
+ break;
+ }
+ }
+ if (i >= *count)
+ {
+ servers[*count].adr = adr;
+ Q_strncpyz(servers[*count].hostName, name, sizeof(servers[*count].hostName));
+ servers[*count].visible = true;
+ (*count)++;
+ return 1;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+/*
+====================
+LAN_RemoveServer
+====================
+*/
+static void LAN_RemoveServer(int source, const char *addr)
+{
+ int *count, i;
+ serverInfo_t *servers = NULL;
+ count = NULL;
+ switch (source)
+ {
+ case AS_LOCAL:
+ count = &cls.numlocalservers;
+ servers = &cls.localServers[0];
+ break;
+ case AS_MPLAYER:
+ case AS_GLOBAL:
+ count = &cls.numglobalservers;
+ servers = &cls.globalServers[0];
+ break;
+ case AS_FAVORITES:
+ count = &cls.numfavoriteservers;
+ servers = &cls.favoriteServers[0];
+ break;
+ }
+ if (servers)
+ {
+ netadr_t comp;
+ NET_StringToAdr(addr, &comp, NA_UNSPEC);
+ for (i = 0; i < *count; i++)
+ {
+ if (NET_CompareAdr(comp, servers[i].adr))
+ {
+ int j = i;
+ while (j < *count - 1)
+ {
+ ::memcpy(&servers[j], &servers[j + 1], sizeof(servers[j]));
+ j++;
+ }
+ (*count)--;
+ break;
+ }
+ }
+ }
+}
+
+/*
+====================
+LAN_GetServerCount
+====================
+*/
+static int LAN_GetServerCount(int source)
+{
+ switch (source)
+ {
+ case AS_LOCAL:
+ return cls.numlocalservers;
+ break;
+ case AS_MPLAYER:
+ case AS_GLOBAL:
+ return cls.numglobalservers;
+ break;
+ case AS_FAVORITES:
+ return cls.numfavoriteservers;
+ break;
+ }
+ return 0;
+}
+
+/*
+====================
+LAN_GetLocalServerAddressString
+====================
+*/
+static void LAN_GetServerAddressString(int source, int n, char *buf, int buflen)
+{
+ switch (source)
+ {
+ case AS_LOCAL:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ Q_strncpyz(buf, NET_AdrToStringwPort(cls.localServers[n].adr), buflen);
+ if (cls.localServers[n].adr.alternateProtocol != 0)
+ Q_strncpyz(buf + (int)strlen(buf), (cls.localServers[n].adr.alternateProtocol == 1 ? " -g" : " -1"),
+ buflen - (int)strlen(buf));
+ return;
+ }
+ break;
+ case AS_MPLAYER:
+ case AS_GLOBAL:
+ if (n >= 0 && n < MAX_GLOBAL_SERVERS)
+ {
+ Q_strncpyz(buf, NET_AdrToStringwPort(cls.globalServers[n].adr), buflen);
+ if (cls.globalServers[n].adr.alternateProtocol != 0)
+ Q_strncpyz(buf + (int)strlen(buf),
+ (cls.globalServers[n].adr.alternateProtocol == 1 ? " -g" : " -1"), buflen - (int)strlen(buf));
+ return;
+ }
+ break;
+ case AS_FAVORITES:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ Q_strncpyz(buf, NET_AdrToStringwPort(cls.favoriteServers[n].adr), buflen);
+ if (cls.favoriteServers[n].adr.alternateProtocol != 0)
+ Q_strncpyz(buf + (int)strlen(buf),
+ (cls.favoriteServers[n].adr.alternateProtocol == 1 ? " -g" : " -1"), buflen - (int)strlen(buf));
+ return;
+ }
+ break;
+ }
+ buf[0] = '\0';
+}
+
+/*
+====================
+LAN_GetServerInfo
+====================
+*/
+static void LAN_GetServerInfo(int source, int n, char *buf, int buflen)
+{
+ char info[MAX_STRING_CHARS];
+ serverInfo_t *server = NULL;
+ info[0] = '\0';
+ switch (source)
+ {
+ case AS_LOCAL:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ server = &cls.localServers[n];
+ }
+ break;
+ case AS_MPLAYER:
+ case AS_GLOBAL:
+ if (n >= 0 && n < MAX_GLOBAL_SERVERS)
+ {
+ server = &cls.globalServers[n];
+ }
+ break;
+ case AS_FAVORITES:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ server = &cls.favoriteServers[n];
+ }
+ break;
+ }
+ if (server && buf)
+ {
+ buf[0] = '\0';
+ if (server->adr.alternateProtocol != 0)
+ {
+ char hn[MAX_HOSTNAME_LENGTH];
+ Q_strncpyz(hn, server->hostName, sizeof(hn));
+ Q_strcat(
+ hn, sizeof(hn), (server->adr.alternateProtocol == 1 ? S_COLOR_WHITE " [GPP]" : S_COLOR_WHITE " [1.1]"));
+ Info_SetValueForKey(info, "hostname", hn);
+ }
+ else
+ {
+ Info_SetValueForKey(info, "hostname", server->hostName);
+ }
+ Info_SetValueForKey(info, "mapname", server->mapName);
+ Info_SetValueForKey(info, "label", server->label);
+ Info_SetValueForKey(info, "clients", va("%i", server->clients));
+ Info_SetValueForKey(info, "sv_maxclients", va("%i", server->maxClients));
+ Info_SetValueForKey(info, "ping", va("%i", server->ping));
+ Info_SetValueForKey(info, "minping", va("%i", server->minPing));
+ Info_SetValueForKey(info, "maxping", va("%i", server->maxPing));
+ Info_SetValueForKey(info, "game", server->game);
+ Info_SetValueForKey(info, "gametype", va("%i", server->gameType));
+ Info_SetValueForKey(info, "nettype", va("%i", server->netType));
+ Info_SetValueForKey(info, "addr", NET_AdrToStringwPort(server->adr));
+ Q_strncpyz(buf, info, buflen);
+ }
+ else
+ {
+ if (buf)
+ {
+ buf[0] = '\0';
+ }
+ }
+}
+
+/*
+====================
+LAN_GetServerPing
+====================
+*/
+static int LAN_GetServerPing(int source, int n)
+{
+ serverInfo_t *server = NULL;
+ switch (source)
+ {
+ case AS_LOCAL:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ server = &cls.localServers[n];
+ }
+ break;
+ case AS_MPLAYER:
+ case AS_GLOBAL:
+ if (n >= 0 && n < MAX_GLOBAL_SERVERS)
+ {
+ server = &cls.globalServers[n];
+ }
+ break;
+ case AS_FAVORITES:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ server = &cls.favoriteServers[n];
+ }
+ break;
+ }
+ if (server)
+ {
+ return server->ping;
+ }
+ return -1;
+}
+
+/*
+====================
+LAN_GetServerPtr
+====================
+*/
+static serverInfo_t *LAN_GetServerPtr(int source, int n)
+{
+ switch (source)
+ {
+ case AS_LOCAL:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ return &cls.localServers[n];
+ }
+ break;
+ case AS_MPLAYER:
+ case AS_GLOBAL:
+ if (n >= 0 && n < MAX_GLOBAL_SERVERS)
+ {
+ return &cls.globalServers[n];
+ }
+ break;
+ case AS_FAVORITES:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ return &cls.favoriteServers[n];
+ }
+ break;
+ }
+ return NULL;
+}
+
+#define FEATURED_MAXPING 200
+/*
+====================
+LAN_CompareServers
+====================
+*/
+static int LAN_CompareServers(int source, int sortKey, int sortDir, int s1, int s2)
+{
+ int res;
+ serverInfo_t *server1, *server2;
+
+ server1 = LAN_GetServerPtr(source, s1);
+ server2 = LAN_GetServerPtr(source, s2);
+ if (!server1 || !server2)
+ {
+ return 0;
+ }
+
+ // featured servers on top
+ if ((server1->label[0] && server1->ping <= FEATURED_MAXPING) ||
+ (server2->label[0] && server2->ping <= FEATURED_MAXPING))
+ {
+ res = Q_stricmpn(server1->label, server2->label, MAX_FEATLABEL_CHARS);
+ if (res) return -res;
+ }
+
+ res = 0;
+ switch (sortKey)
+ {
+ case SORT_HOST:
+ {
+ char hostName1[MAX_HOSTNAME_LENGTH];
+ char hostName2[MAX_HOSTNAME_LENGTH];
+ char *p;
+ int i;
+
+ for (p = server1->hostName, i = 0; *p != '\0'; p++)
+ {
+ if (Q_isalpha(*p)) hostName1[i++] = *p;
+ }
+ hostName1[i] = '\0';
+
+ for (p = server2->hostName, i = 0; *p != '\0'; p++)
+ {
+ if (Q_isalpha(*p)) hostName2[i++] = *p;
+ }
+ hostName2[i] = '\0';
+
+ res = Q_stricmp(hostName1, hostName2);
+ }
+ break;
+
+ case SORT_GAME:
+ res = Q_stricmp(server1->game, server2->game);
+ break;
+ case SORT_MAP:
+ res = Q_stricmp(server1->mapName, server2->mapName);
+ break;
+ case SORT_CLIENTS:
+ if (server1->clients < server2->clients)
+ {
+ res = -1;
+ }
+ else if (server1->clients > server2->clients)
+ {
+ res = 1;
+ }
+ else
+ {
+ res = 0;
+ }
+ break;
+ case SORT_PING:
+ if (server1->ping < server2->ping)
+ {
+ res = -1;
+ }
+ else if (server1->ping > server2->ping)
+ {
+ res = 1;
+ }
+ else
+ {
+ res = 0;
+ }
+ break;
+ }
+
+ if (sortDir)
+ {
+ if (res < 0) return 1;
+ if (res > 0) return -1;
+ return 0;
+ }
+ return res;
+}
+
+/*
+====================
+LAN_GetPingQueueCount
+====================
+*/
+static int LAN_GetPingQueueCount(void) { return (CL_GetPingQueueCount()); }
+/*
+====================
+LAN_ClearPing
+====================
+*/
+static void LAN_ClearPing(int n) { CL_ClearPing(n); }
+/*
+====================
+LAN_GetPing
+====================
+*/
+static void LAN_GetPing(int n, char *buf, int buflen, int *pingtime) { CL_GetPing(n, buf, buflen, pingtime); }
+/*
+====================
+LAN_GetPingInfo
+====================
+*/
+static void LAN_GetPingInfo(int n, char *buf, int buflen) { CL_GetPingInfo(n, buf, buflen); }
+/*
+====================
+LAN_MarkServerVisible
+====================
+*/
+static void LAN_MarkServerVisible(int source, int n, bool visible)
+{
+ if (n == -1)
+ {
+ int count = MAX_OTHER_SERVERS;
+ serverInfo_t *server = NULL;
+ switch (source)
+ {
+ case AS_LOCAL:
+ server = &cls.localServers[0];
+ break;
+ case AS_MPLAYER:
+ case AS_GLOBAL:
+ server = &cls.globalServers[0];
+ count = MAX_GLOBAL_SERVERS;
+ break;
+ case AS_FAVORITES:
+ server = &cls.favoriteServers[0];
+ break;
+ }
+ if (server)
+ {
+ for (n = 0; n < count; n++)
+ {
+ server[n].visible = visible;
+ }
+ }
+ }
+ else
+ {
+ switch (source)
+ {
+ case AS_LOCAL:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ cls.localServers[n].visible = visible;
+ }
+ break;
+ case AS_MPLAYER:
+ case AS_GLOBAL:
+ if (n >= 0 && n < MAX_GLOBAL_SERVERS)
+ {
+ cls.globalServers[n].visible = visible;
+ }
+ break;
+ case AS_FAVORITES:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ cls.favoriteServers[n].visible = visible;
+ }
+ break;
+ }
+ }
+}
+
+/*
+=======================
+LAN_ServerIsVisible
+=======================
+*/
+static bool LAN_ServerIsVisible(int source, int n)
+{
+ switch (source)
+ {
+ case AS_LOCAL:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ return cls.localServers[n].visible;
+ }
+ break;
+ case AS_MPLAYER:
+ case AS_GLOBAL:
+ if (n >= 0 && n < MAX_GLOBAL_SERVERS)
+ {
+ return cls.globalServers[n].visible;
+ }
+ break;
+ case AS_FAVORITES:
+ if (n >= 0 && n < MAX_OTHER_SERVERS)
+ {
+ return cls.favoriteServers[n].visible;
+ }
+ break;
+ }
+ return false;
+}
+
+/*
+=======================
+LAN_UpdateVisiblePings
+=======================
+*/
+static bool LAN_UpdateVisiblePings(int source) { return CL_UpdateVisiblePings_f(source); }
+/*
+====================
+LAN_GetServerStatus
+====================
+*/
+static bool LAN_GetServerStatus(char *serverAddress, char *serverStatus, int maxLen)
+{
+ return CL_ServerStatus(serverAddress, serverStatus, maxLen);
+}
+
+/*
+====================
+CL_GetGlConfig
+====================
+*/
+static void CL_GetGlconfig(glconfig_t *config) { *config = cls.glconfig; }
+/*
+====================
+GetConfigString
+====================
+*/
+static bool GetConfigString(int i, char *buf, int size)
+{
+ int offset;
+
+ if (i < 0 || i >= MAX_CONFIGSTRINGS) return false;
+
+ offset = cl.gameState.stringOffsets[i];
+ if (!offset)
+ {
+ if (size) buf[0] = '\0';
+ return false;
+ }
+
+ Q_strncpyz(buf, cl.gameState.stringData + offset, size);
+
+ return true;
+}
+
+/*
+====================
+FloatAsInt
+====================
+*/
+static int FloatAsInt(float f)
+{
+ floatint_t fi;
+ fi.f = f;
+ return fi.i;
+}
+
+static bool probingUI = false;
+
+/*
+====================
+CL_UISystemCalls
+
+The ui module is making a system call
+====================
+*/
+intptr_t CL_UISystemCalls(intptr_t *args)
+{
+ if (cls.uiInterface == 2)
+ {
+ if (args[0] >= UI_R_SETCLIPREGION && args[0] < UI_MEMSET)
+ {
+ if (args[0] < UI_S_STOPBACKGROUNDTRACK - 1)
+ {
+ args[0] += 1;
+ }
+ else if (args[0] < UI_S_STOPBACKGROUNDTRACK + 4)
+ {
+ args[0] += UI_PARSE_ADD_GLOBAL_DEFINE - UI_S_STOPBACKGROUNDTRACK + 1;
+ }
+ else if (args[0] >= UI_PARSE_ADD_GLOBAL_DEFINE + 4)
+ {
+ args[0] += UI_GETNEWS - UI_PARSE_ADD_GLOBAL_DEFINE - 5;
+ if (args[0] == UI_PARSE_SOURCE_FILE_AND_LINE || args[0] == UI_GETNEWS)
+ args[0] = UI_PARSE_SOURCE_FILE_AND_LINE - 1337 - args[0];
+ }
+ else
+ {
+ args[0] -= 4;
+ }
+ }
+
+ switch (args[0])
+ {
+ case UI_LAN_GETSERVERCOUNT:
+ case UI_LAN_GETSERVERADDRESSSTRING:
+ case UI_LAN_GETSERVERINFO:
+ case UI_LAN_MARKSERVERVISIBLE:
+ case UI_LAN_UPDATEVISIBLEPINGS:
+ case UI_LAN_RESETPINGS:
+ case UI_LAN_ADDSERVER:
+ case UI_LAN_REMOVESERVER:
+ case UI_LAN_GETSERVERPING:
+ case UI_LAN_SERVERISVISIBLE:
+ case UI_LAN_COMPARESERVERS:
+ if (args[1] == AS_GLOBAL)
+ {
+ args[1] = AS_LOCAL;
+ }
+ else if (args[1] == AS_LOCAL)
+ {
+ args[1] = AS_GLOBAL;
+ }
+ }
+ }
+
+ switch (args[0])
+ {
+ case UI_ERROR:
+ if (probingUI)
+ {
+ cls.uiInterface = 2;
+ return 0;
+ }
+ Com_Error(ERR_DROP, "%s", (const char *)VMA(1));
+ return 0;
+
+ case UI_PRINT:
+ Com_Printf("%s", (const char *)VMA(1));
+ return 0;
+
+ case UI_MILLISECONDS:
+ return Sys_Milliseconds();
+
+ case UI_CVAR_REGISTER:
+ Cvar_Register((vmCvar_t *)VMA(1), (const char *)VMA(2), (const char *)VMA(3), args[4]);
+ return 0;
+
+ case UI_CVAR_UPDATE:
+ Cvar_Update((vmCvar_t *)VMA(1));
+ return 0;
+
+ case UI_CVAR_SET:
+ Cvar_SetSafe((const char *)VMA(1), (const char *)VMA(2));
+ return 0;
+
+ case UI_CVAR_VARIABLEVALUE:
+ return FloatAsInt(Cvar_VariableValue((const char *)VMA(1)));
+
+ case UI_CVAR_VARIABLESTRINGBUFFER:
+ Cvar_VariableStringBuffer((const char *)VMA(1), (char *)VMA(2), args[3]);
+ return 0;
+
+ case UI_CVAR_SETVALUE:
+ Cvar_SetValueSafe((const char *)VMA(1), VMF(2));
+ return 0;
+
+ case UI_CVAR_RESET:
+ Cvar_Reset((const char *)VMA(1));
+ return 0;
+
+ case UI_CVAR_CREATE:
+ Cvar_Register(NULL, (const char *)VMA(1), (const char *)VMA(2), args[3]);
+ return 0;
+
+ case UI_CVAR_INFOSTRINGBUFFER:
+ Cvar_InfoStringBuffer(args[1], (char *)VMA(2), args[3]);
+ return 0;
+
+ case UI_ARGC:
+ return Cmd_Argc();
+
+ case UI_ARGV:
+ Cmd_ArgvBuffer(args[1], (char *)VMA(2), args[3]);
+ return 0;
+
+ case UI_CMD_EXECUTETEXT:
+ if (args[1] == EXEC_NOW)
+ {
+ if (!strncmp((const char *)VMA(2), "snd_restart", 11)
+ || !strncmp((const char *)VMA(2), "vid_restart", 11)
+ || !strncmp((const char *)VMA(2), "quit", 5))
+ {
+ Com_Printf(S_COLOR_YELLOW "turning EXEC_NOW '%.11s' into EXEC_INSERT\n", (const char *)VMA(2));
+ args[1] = EXEC_INSERT;
+ }
+ }
+
+ // TODO: Do this better
+ if (!strncmp((const char *)VMA(2), "checkForUpdate", 14))
+ {
+ CL_GetLatestRelease();
+ return 0;
+ }
+
+ Cbuf_ExecuteText(args[1], (const char *)VMA(2));
+ return 0;
+
+ case UI_FS_FOPENFILE:
+ return FS_FOpenFileByMode((const char *)VMA(1), (fileHandle_t *)VMA(2), (FS_Mode)args[3]);
+
+ case UI_FS_READ:
+ FS_Read(VMA(1), args[2], args[3]);
+ return 0;
+
+ case UI_FS_WRITE:
+ FS_Write(VMA(1), args[2], args[3]);
+ return 0;
+
+ case UI_FS_FCLOSEFILE:
+ FS_FCloseFile(args[1]);
+ return 0;
+
+ case UI_FS_GETFILELIST:
+ return FS_GetFileList((const char *)VMA(1), (const char *)VMA(2), (char *)VMA(3), args[4]);
+
+ case UI_FS_SEEK:
+ return FS_Seek((fileHandle_t)args[1], args[2], (FS_Origin)args[3]);
+
+ case UI_R_REGISTERMODEL:
+ return re.RegisterModel((const char *)VMA(1));
+
+ case UI_R_REGISTERSKIN:
+ return re.RegisterSkin((const char *)VMA(1));
+
+ case UI_R_REGISTERSHADERNOMIP:
+ return re.RegisterShaderNoMip((const char *)VMA(1));
+
+ case UI_R_CLEARSCENE:
+ re.ClearScene();
+ return 0;
+
+ case UI_R_ADDREFENTITYTOSCENE:
+ re.AddRefEntityToScene((const refEntity_t *)VMA(1));
+ return 0;
+
+ case UI_R_ADDPOLYTOSCENE:
+ re.AddPolyToScene(args[1], args[2], (const polyVert_t *)VMA(3), 1);
+ return 0;
+
+ case UI_R_ADDLIGHTTOSCENE:
+ re.AddLightToScene((const float *)VMA(1), VMF(2), VMF(3), VMF(4), VMF(5));
+ return 0;
+
+ case UI_R_RENDERSCENE:
+ re.RenderScene((const refdef_t *)VMA(1));
+ return 0;
+
+ case UI_R_SETCOLOR:
+ re.SetColor((const float *)VMA(1));
+ return 0;
+
+ case UI_R_SETCLIPREGION:
+ re.SetClipRegion((const float *)VMA(1));
+ return 0;
+
+ case UI_R_DRAWSTRETCHPIC:
+ re.DrawStretchPic(VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9]);
+ return 0;
+
+ case UI_R_MODELBOUNDS:
+ re.ModelBounds(args[1], (float *)VMA(2), (float *)VMA(3));
+ return 0;
+
+ case UI_UPDATESCREEN:
+ SCR_UpdateScreen();
+ return 0;
+
+ case UI_CM_LERPTAG:
+ re.LerpTag((orientation_t *)VMA(1), args[2], args[3], args[4], VMF(5), (const char *)VMA(6));
+ return 0;
+
+ case UI_S_REGISTERSOUND:
+ return S_RegisterSound((const char *)VMA(1), (bool)args[2]);
+
+ case UI_S_STARTLOCALSOUND:
+ S_StartLocalSound(args[1], args[2]);
+ return 0;
+
+ case UI_KEY_KEYNUMTOSTRINGBUF:
+ Key_KeynumToStringBuf(args[1], (char *)VMA(2), args[3]);
+ return 0;
+
+ case UI_KEY_GETBINDINGBUF:
+ Key_GetBindingBuf(args[1], (char *)VMA(2), args[3]);
+ return 0;
+
+ case UI_KEY_SETBINDING:
+ Key_SetBinding(args[1], (const char *)VMA(2));
+ return 0;
+
+ case UI_KEY_ISDOWN:
+ return Key_IsDown(args[1]);
+
+ case UI_KEY_GETOVERSTRIKEMODE:
+ return Key_GetOverstrikeMode();
+
+ case UI_KEY_SETOVERSTRIKEMODE:
+ Key_SetOverstrikeMode((bool)args[1]);
+ return 0;
+
+ case UI_KEY_CLEARSTATES:
+ Key_ClearStates();
+ return 0;
+
+ case UI_KEY_GETCATCHER:
+ return Key_GetCatcher();
+
+ case UI_KEY_SETCATCHER:
+ // don't allow the ui module to toggle the console
+ Key_SetCatcher((args[1] & ~KEYCATCH_CONSOLE) | (Key_GetCatcher() & KEYCATCH_CONSOLE));
+ return 0;
+
+ case UI_GETCLIPBOARDDATA:
+ ((char *)VMA(1))[0] = '\0';
+ return 0;
+
+ case UI_GETCLIENTSTATE:
+ GetClientState((uiClientState_t *)VMA(1));
+ return 0;
+
+ case UI_GETGLCONFIG:
+ CL_GetGlconfig((glconfig_t *)VMA(1));
+ return 0;
+
+ case UI_GETCONFIGSTRING:
+ return GetConfigString(args[1], (char *)VMA(2), args[3]);
+
+ case UI_LAN_LOADCACHEDSERVERS:
+ LAN_LoadCachedServers();
+ return 0;
+
+ case UI_LAN_SAVECACHEDSERVERS:
+ LAN_SaveServersToCache();
+ return 0;
+
+ case UI_LAN_ADDSERVER:
+ return LAN_AddServer(args[1], (const char *)VMA(2), (const char *)VMA(3));
+
+ case UI_LAN_REMOVESERVER:
+ LAN_RemoveServer(args[1], (const char *)VMA(2));
+ return 0;
+
+ case UI_LAN_GETPINGQUEUECOUNT:
+ return LAN_GetPingQueueCount();
+
+ case UI_LAN_CLEARPING:
+ LAN_ClearPing(args[1]);
+ return 0;
+
+ case UI_LAN_GETPING:
+ LAN_GetPing(args[1], (char *)VMA(2), args[3], (int *)VMA(4));
+ return 0;
+
+ case UI_LAN_GETPINGINFO:
+ LAN_GetPingInfo(args[1], (char *)VMA(2), args[3]);
+ return 0;
+
+ case UI_LAN_GETSERVERCOUNT:
+ return LAN_GetServerCount(args[1]);
+
+ case UI_LAN_GETSERVERADDRESSSTRING:
+ LAN_GetServerAddressString(args[1], args[2], (char *)VMA(3), args[4]);
+ return 0;
+
+ case UI_LAN_GETSERVERINFO:
+ LAN_GetServerInfo(args[1], args[2], (char *)VMA(3), args[4]);
+ return 0;
+
+ case UI_LAN_GETSERVERPING:
+ return LAN_GetServerPing(args[1], args[2]);
+
+ case UI_LAN_MARKSERVERVISIBLE:
+ LAN_MarkServerVisible(args[1], args[2], (bool)args[3]);
+ return 0;
+
+ case UI_LAN_SERVERISVISIBLE:
+ return LAN_ServerIsVisible(args[1], args[2]);
+
+ case UI_LAN_UPDATEVISIBLEPINGS:
+ return LAN_UpdateVisiblePings(args[1]);
+
+ case UI_LAN_RESETPINGS:
+ LAN_ResetPings(args[1]);
+ return 0;
+
+ case UI_LAN_SERVERSTATUS:
+ return LAN_GetServerStatus((char *)VMA(1), (char *)VMA(2), args[3]);
+
+ case UI_GETNEWS:
+ return GetNews((bool)args[1]);
+
+ case UI_LAN_COMPARESERVERS:
+ return LAN_CompareServers(args[1], args[2], args[3], args[4], args[5]);
+
+ case UI_MEMORY_REMAINING:
+ return Hunk_MemoryRemaining();
+
+ case UI_SET_PBCLSTATUS:
+ return 0;
+
+ case UI_R_REGISTERFONT:
+ re.RegisterFont((const char *)VMA(1), args[2], (fontInfo_t *)VMA(3));
+ return 0;
+
+ case UI_MEMSET:
+ ::memset(VMA(1), args[2], args[3]);
+ return 0;
+
+ case UI_MEMCPY:
+ ::memcpy(VMA(1), VMA(2), args[3]);
+ return 0;
+
+ case UI_STRNCPY:
+ strncpy((char *)VMA(1), (const char *)VMA(2), args[3]);
+ return args[1];
+
+ case UI_SIN:
+ return FloatAsInt(sin(VMF(1)));
+
+ case UI_COS:
+ return FloatAsInt(cos(VMF(1)));
+
+ case UI_ATAN2:
+ return FloatAsInt(atan2(VMF(1), VMF(2)));
+
+ case UI_SQRT:
+ return FloatAsInt(sqrt(VMF(1)));
+
+ case UI_FLOOR:
+ return FloatAsInt(floor(VMF(1)));
+
+ case UI_CEIL:
+ return FloatAsInt(ceil(VMF(1)));
+
+ case UI_PARSE_ADD_GLOBAL_DEFINE:
+ return Parse_AddGlobalDefine((char *)VMA(1));
+ case UI_PARSE_LOAD_SOURCE:
+ return Parse_LoadSourceHandle((char *)VMA(1));
+ case UI_PARSE_FREE_SOURCE:
+ return Parse_FreeSourceHandle(args[1]);
+ case UI_PARSE_READ_TOKEN:
+ return Parse_ReadTokenHandle(args[1], (pc_token_t *)VMA(2));
+ case UI_PARSE_SOURCE_FILE_AND_LINE:
+ return Parse_SourceFileAndLine(args[1], (char *)VMA(2), (int *)VMA(3));
+
+ case UI_S_STOPBACKGROUNDTRACK:
+ S_StopBackgroundTrack();
+ return 0;
+ case UI_S_STARTBACKGROUNDTRACK:
+ S_StartBackgroundTrack((const char *)VMA(1), (const char *)VMA(2));
+ return 0;
+
+ case UI_REAL_TIME:
+ return Com_RealTime((qtime_t *)VMA(1));
+
+ case UI_CIN_PLAYCINEMATIC:
+ return CIN_PlayCinematic((const char *)VMA(1), args[2], args[3], args[4], args[5], args[6]);
+
+ case UI_CIN_STOPCINEMATIC:
+ return CIN_StopCinematic(args[1]);
+
+ case UI_CIN_RUNCINEMATIC:
+ return CIN_RunCinematic(args[1]);
+
+ case UI_CIN_DRAWCINEMATIC:
+ CIN_DrawCinematic(args[1]);
+ return 0;
+
+ case UI_CIN_SETEXTENTS:
+ CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]);
+ return 0;
+
+ case UI_R_REMAP_SHADER:
+ re.RemapShader((const char *)VMA(1), (const char *)VMA(2), (const char *)VMA(3));
+ return 0;
+
+ default:
+ Com_Error(ERR_DROP, "Bad UI system trap: %ld", (long int)args[0]);
+ }
+
+ return 0;
+}
+
+/*
+====================
+CL_ShutdownUI
+====================
+*/
+void CL_ShutdownUI(void)
+{
+ Key_SetCatcher(Key_GetCatcher() & ~KEYCATCH_UI);
+ cls.uiStarted = false;
+ if (!cls.ui)
+ {
+ return;
+ }
+ VM_Call(cls.ui, UI_SHUTDOWN);
+ VM_Free(cls.ui);
+ cls.ui = NULL;
+}
+
+/*
+====================
+CL_InitUI
+====================
+*/
+void CL_InitUI(void)
+{
+ // load the dll or bytecode
+ vmInterpret_t interpret = (vmInterpret_t)Cvar_VariableValue("vm_ui");
+ if (cl_connectedToPureServer)
+ {
+ // if sv_pure is set we only allow qvms to be loaded
+ if (interpret != VMI_COMPILED && interpret != VMI_BYTECODE) interpret = VMI_COMPILED;
+ }
+
+ cls.ui = VM_Create("ui", CL_UISystemCalls, interpret);
+ if (!cls.ui)
+ {
+ Com_Printf("Failed to find a valid UI vm. The following paths were searched:\n");
+ Cmd_ExecuteString("path /\n");
+ Com_Error(ERR_RECONNECT, "VM_Create on UI failed");
+ }
+
+ // sanity check
+ int v = VM_Call(cls.ui, UI_GETAPIVERSION);
+ if (v != UI_API_VERSION)
+ {
+ // Free cls.ui now, so UI_SHUTDOWN doesn't get called later.
+ VM_Free(cls.ui);
+ cls.ui = NULL;
+
+ cls.uiStarted = false;
+ Com_Error(ERR_DROP, "User Interface is version %d, expected %d", v, UI_API_VERSION);
+ }
+
+ // Probe UI interface
+ // Calls the GPP UI_CONSOLE_COMMAND (10), if GPP will return false 0. If a 1.1.0 qvm, will hit the error handler.
+ Cmd_TokenizeString("");
+ cls.uiInterface = 0;
+ probingUI = true;
+ if ( VM_Call(cls.ui, UI_CONSOLE_COMMAND, 0) < 0 )
+ cls.uiInterface = 2;
+
+ probingUI = false;
+
+ if (clc.state >= CA_CONNECTED && clc.state <= CA_ACTIVE &&
+ (clc.netchan.alternateProtocol == 2) != (cls.uiInterface == 2))
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: %s protocol %i, but a ui module using the %s interface was found\n",
+ (clc.demoplaying ? "Demo was recorded using" : "Server uses"),
+ (clc.netchan.alternateProtocol == 0 ? PROTOCOL_VERSION : clc.netchan.alternateProtocol == 1 ? 70 : 69),
+ (cls.uiInterface == 2 ? "1.1" : "non-1.1"));
+ }
+
+ // init for this gamestate
+ VM_Call(cls.ui, UI_INIT, (clc.state >= CA_AUTHORIZING && clc.state < CA_ACTIVE));
+
+ // show where the ui folder was loaded from
+ Cmd_ExecuteString("which ui/\n");
+
+ clc.newsString[0] = '\0';
+}
+
+/*
+====================
+UI_GameCommand
+
+See if the current console command is claimed by the ui
+====================
+*/
+bool UI_GameCommand(void)
+{
+ if (!cls.ui) return false;
+
+ return (bool)VM_Call(cls.ui, UI_CONSOLE_COMMAND - (cls.uiInterface == 2 ? 2 : 0), cls.realtime);
+}
diff --git a/src/client/cl_updates.cpp b/src/client/cl_updates.cpp
new file mode 100644
index 0000000..0e6a237
--- /dev/null
+++ b/src/client/cl_updates.cpp
@@ -0,0 +1,476 @@
+#include "cl_updates.h"
+
+#include <libgen.h>
+#include <unistd.h>
+
+#include "nettle/rsa.h"
+#include "nettle/sha2.h"
+#include "rapidjson.h"
+#include "restclient/connection.h"
+#include "restclient/restclient.h"
+#include "semantic_version.h"
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <array>
+
+#include "qcommon/cvar.h"
+#include "qcommon/q_platform.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+#include "qcommon/unzip.h"
+#include "sys/sys_shared.h"
+
+#include "cl_rest.h"
+
+using namespace std;
+
+std::vector<std::string> release_package;
+static std::string granger_exe;
+static std::string granger_main_lua;
+static int nextCheckTime = 0;
+
+static const uint8_t release_key_pub[] = {
+ 0x28, 0x31, 0x30, 0x3a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b,
+ 0x65, 0x79, 0x28, 0x39, 0x3a, 0x72, 0x73, 0x61, 0x2d, 0x70, 0x6b, 0x63,
+ 0x73, 0x31, 0x28, 0x31, 0x3a, 0x6e, 0x35, 0x31, 0x33, 0x3a, 0x00, 0xaa,
+ 0x4a, 0xe1, 0xdc, 0x08, 0xed, 0x90, 0x92, 0x66, 0x4a, 0xc2, 0x00, 0x43,
+ 0x3e, 0x89, 0x40, 0x4d, 0x11, 0xaa, 0x98, 0x2d, 0x55, 0x08, 0xec, 0x43,
+ 0x9f, 0x73, 0xfe, 0xc9, 0x67, 0xcb, 0xb0, 0x4a, 0x52, 0x89, 0x1d, 0x1a,
+ 0xc1, 0x86, 0x29, 0x26, 0x32, 0xb2, 0x34, 0xb6, 0xa5, 0x42, 0x16, 0x08,
+ 0x60, 0x8d, 0xf1, 0xe4, 0x45, 0xd4, 0x90, 0x2b, 0xfb, 0x98, 0xb2, 0x2e,
+ 0xa7, 0xa9, 0x79, 0xff, 0x5e, 0xaa, 0xb5, 0xd6, 0xf9, 0xf9, 0x2e, 0x67,
+ 0x5c, 0xb6, 0x6c, 0x36, 0x70, 0xf3, 0xea, 0x3f, 0xd8, 0xc8, 0xd0, 0xda,
+ 0xd8, 0xfb, 0x1b, 0x55, 0xe9, 0x69, 0x9d, 0x4a, 0xea, 0xf2, 0xb1, 0xdd,
+ 0x6b, 0xea, 0xb4, 0x99, 0xd7, 0x5e, 0xca, 0x5f, 0x34, 0xcf, 0xee, 0xbb,
+ 0xc6, 0x07, 0xa8, 0x3b, 0x59, 0xc3, 0xc1, 0x53, 0x15, 0x2b, 0xe4, 0x2f,
+ 0x17, 0x2d, 0x0c, 0x0f, 0x4e, 0xee, 0x2e, 0xef, 0x97, 0x9c, 0xff, 0x58,
+ 0xec, 0x6a, 0xf1, 0x12, 0x21, 0x5a, 0xc5, 0xbb, 0x6a, 0xef, 0xb0, 0xc8,
+ 0x4b, 0x7d, 0x33, 0xca, 0x53, 0x03, 0x31, 0x4a, 0xbd, 0x82, 0x01, 0x56,
+ 0x8f, 0x4e, 0x1d, 0x21, 0x7d, 0x2e, 0x8d, 0xaa, 0x0d, 0xcd, 0xe6, 0x19,
+ 0x09, 0x79, 0x76, 0x11, 0x16, 0xb5, 0xd2, 0xc1, 0x03, 0xdb, 0xaa, 0x11,
+ 0xd5, 0x89, 0x70, 0xc8, 0x71, 0xbf, 0x1a, 0xea, 0x9d, 0xd6, 0xaa, 0x77,
+ 0x97, 0xa4, 0xcc, 0x1d, 0xd6, 0x1c, 0x1a, 0x14, 0x6f, 0x35, 0x34, 0x6a,
+ 0x10, 0x32, 0x13, 0x33, 0x41, 0x27, 0xad, 0x1b, 0x59, 0x41, 0xff, 0xb0,
+ 0x1b, 0x64, 0x14, 0xea, 0x29, 0x44, 0x2b, 0x62, 0xdc, 0x63, 0xbc, 0xc7,
+ 0xf8, 0xac, 0xf7, 0x5c, 0x9d, 0x3c, 0xbd, 0x17, 0x84, 0xd9, 0x56, 0x09,
+ 0x44, 0x1b, 0xdd, 0x72, 0x16, 0xf6, 0x67, 0xc4, 0x49, 0xd3, 0x56, 0x74,
+ 0x42, 0x2d, 0x08, 0xe2, 0x0b, 0x0c, 0x40, 0x97, 0x62, 0x97, 0xb3, 0xd6,
+ 0x0c, 0x69, 0x04, 0x6a, 0xd7, 0x7b, 0xf0, 0xe1, 0x37, 0x0b, 0xe0, 0xee,
+ 0x6b, 0x2d, 0x79, 0xa0, 0x72, 0xa5, 0x75, 0x97, 0xb1, 0x6b, 0x01, 0xa2,
+ 0xb8, 0xe3, 0xc7, 0x3c, 0x10, 0x50, 0x59, 0xe4, 0xda, 0x9e, 0x8d, 0xe6,
+ 0x1b, 0xef, 0xa6, 0xae, 0xc4, 0xd7, 0xd8, 0x9b, 0x57, 0x4c, 0xa3, 0xd7,
+ 0x9f, 0x37, 0x17, 0x72, 0x7f, 0x60, 0xd6, 0x4c, 0x42, 0x14, 0x54, 0x66,
+ 0x88, 0xc6, 0xa2, 0x1e, 0xdf, 0x55, 0xfc, 0xef, 0xb9, 0x05, 0x63, 0x8a,
+ 0xc4, 0x5b, 0xe7, 0x45, 0x28, 0x0e, 0x55, 0x8e, 0xcc, 0x74, 0x25, 0xf2,
+ 0xea, 0x2a, 0x66, 0x51, 0xf2, 0x8f, 0x72, 0x1d, 0x97, 0x5a, 0xfb, 0x1c,
+ 0x95, 0x01, 0x93, 0x6b, 0x2b, 0xa5, 0x87, 0x5d, 0xd8, 0xea, 0xb2, 0x24,
+ 0x78, 0xb1, 0x58, 0x63, 0x47, 0x86, 0xed, 0xd9, 0xbc, 0xe9, 0xd2, 0xea,
+ 0xa8, 0x90, 0x5b, 0xe8, 0x82, 0x89, 0xa2, 0xe2, 0x52, 0x1f, 0x78, 0x00,
+ 0x93, 0x64, 0x54, 0xdb, 0x9b, 0x93, 0xc3, 0xee, 0xa2, 0x37, 0xab, 0x2e,
+ 0x7e, 0x8f, 0xec, 0xb1, 0x0b, 0x69, 0xad, 0x21, 0xda, 0xa9, 0xaf, 0xd2,
+ 0x22, 0x52, 0x2f, 0x1a, 0x6b, 0xb9, 0x21, 0x5e, 0xe9, 0x1a, 0xe1, 0x4c,
+ 0x33, 0x26, 0x46, 0xa1, 0xde, 0x52, 0xf3, 0x87, 0xf4, 0x8c, 0x99, 0xe4,
+ 0x5d, 0xe7, 0x5b, 0x76, 0x6c, 0xf5, 0xe1, 0xae, 0x5b, 0xaa, 0xbb, 0x3a,
+ 0xf4, 0x90, 0xa7, 0x5c, 0x5c, 0x72, 0xab, 0xb8, 0x71, 0xdc, 0x47, 0xb1,
+ 0x75, 0x0d, 0xc8, 0xcc, 0xfd, 0xce, 0x62, 0xbe, 0xe5, 0x9f, 0x85, 0x00,
+ 0x53, 0x35, 0x91, 0x44, 0x29, 0x5f, 0x64, 0x8d, 0x7c, 0x37, 0x32, 0x28,
+ 0x45, 0x9d, 0xa3, 0x49, 0xbb, 0xe3, 0xd3, 0x1e, 0x0a, 0xae, 0x53, 0xbd,
+ 0x66, 0x86, 0x8c, 0x4d, 0xa6, 0xd3, 0x85, 0x29, 0x28, 0x31, 0x3a, 0x65,
+ 0x33, 0x3a, 0x01, 0x00, 0x01, 0x29, 0x29, 0x29
+};
+static const size_t release_key_pub_len = 560;
+
+struct UpdateManager {
+
+ static void refresh();
+ static void download();
+ static void validate_signature(std::string path, std::string signature_path);
+ static void extract(std::string extract_path, std::string path);
+ static void execute();
+
+private:
+ static constexpr auto url = "https://api.github.com/repos/GrangerHub/tremulous/releases";
+ static constexpr auto package_name = RELEASE_PACKAGE_NAME;
+ static constexpr auto signature_name = RELEASE_SIGNATURE_NAME;
+ static constexpr auto granger_binary_name = GRANGER_EXE;
+};
+
+#define AU_ACT_NIL 0
+#define AU_ACT_GET 1
+#define AU_ACT_RUN 2
+
+void UpdateManager::refresh()
+{
+ auto currentTime = Sys_Milliseconds();
+
+ if ( nextCheckTime > currentTime )
+ return;
+
+ nextCheckTime = currentTime + 10000;
+
+ Cvar_SetValue("ui_autoupdate_action", 0);
+ Cvar_Set("cl_latestDownload", "");
+ Cvar_Set("cl_latestRelease", "");
+ Cvar_Set("cl_latestSignature", "");
+
+ RestClient::Response r = RestClient::get(url);
+ if ( r.code != 200 )
+ {
+ std::string msg { va("Server did not return OK status code: %d", r.code) };
+
+ Cvar_Set("cl_latestRelease",
+ S_COLOR_RED "ERROR:\n"
+ S_COLOR_WHITE "Server did not return OK status code");
+
+ return;
+ }
+
+ rapidjson::Document d;
+ d.Parse( r.body.c_str() );
+
+ rapidjson::Value &release = d[0];
+ std::string txt;
+
+ semver::v2::Version current { PRODUCT_VERSION + 1 };
+ semver::v2::Version latest { release["tag_name"].GetString() + 1 };
+
+ if ( current == latest )
+ {
+ txt += "You are up to date\n\n";
+ }
+ else if ( current < latest )
+ {
+ txt += "A new release is available!\n\n";
+ }
+ else if ( current > latest )
+ {
+ txt += "Wow! You are ahead of the release.\n\n";
+ }
+
+ txt += release["tag_name"].GetString();
+ if (release["prerelease"].IsTrue())
+ txt += S_COLOR_YELLOW " (Prerelease)";
+
+ txt += '\n';
+ txt += S_COLOR_CYAN "Released:" S_COLOR_WHITE;
+ txt += release["published_at"].GetString();
+
+ txt += '\n';
+ txt += S_COLOR_RED "Release Notes:\n" S_COLOR_WHITE;
+
+ if (!release["body"].IsNull())
+ {
+ txt += '\n';
+ txt += release["body"].GetString();
+ }
+
+ rapidjson::Value &assets = release["assets"];
+ for ( rapidjson::SizeType i = 0; i < assets.Size(); ++i )
+ {
+ auto &a = assets[i];
+ std::string name = a["name"].GetString();
+
+ if ( name == package_name )
+ {
+ std::string dl = a["browser_download_url"].GetString();
+ Cvar_Set("cl_latestDownload", dl.c_str());
+ Cvar_Set("cl_latestPackage", package_name);
+ Cvar_Set("cl_latestRelease", txt.c_str());
+ Cvar_SetValue("ui_autoupdate_action", AU_ACT_GET);
+ }
+ else if ( name == signature_name )
+ {
+ std::string dl = a["browser_download_url"].GetString();
+ Cvar_Set("cl_latestSignature", dl.c_str());
+ }
+ }
+}
+
+void UpdateManager::extract(std::string extract_path, std::string path)
+{
+ // Extract the release package
+ auto z = unzOpen(path.c_str());
+ assert( z != nullptr );
+
+ unz_global_info zi;
+ unzGetGlobalInfo(z, &zi);
+
+ // Iterate through all files in the package
+ unzGoToFirstFile(z);
+ for (int i = 0; i < zi.number_entry; ++i)
+ {
+ unz_file_info fi;
+ char filename[256] = ""; // 256 == MAX_ZPATH
+ int err;
+
+ err = unzGetCurrentFileInfo(z, &fi, filename, sizeof(filename),
+ nullptr, 0, nullptr, 0);
+ assert( err == UNZ_OK ); // != OK means corrupt archive
+
+ std::string fn = { filename };
+
+ // FIXME stop doing dumb string stuff
+ std::string fullpath = extract_path;
+ fullpath += PATH_SEP;
+ fullpath += fn;
+ release_package.emplace_back(fn);
+
+ // Bad assumption of a directory?
+ if ( !fi.compressed_size && !fi.uncompressed_size )
+ {
+ Com_DPrintf(S_COLOR_CYAN"ARCHIVED DIR: "
+ S_COLOR_WHITE"%s\n",
+ fn.c_str());
+
+ MakeDir(extract_path, fn);
+
+ unzGoToNextFile(z);
+ continue;
+ }
+
+ // Must be a file
+ Com_DPrintf(S_COLOR_CYAN"ARCHIVED FILE: "
+ S_COLOR_WHITE"%s (%lu/%lu)\n",
+ filename,
+ fi.compressed_size,
+ fi.uncompressed_size);
+
+ if ( fn.rfind(granger_binary_name) != std::string::npos )
+ granger_exe = fn;
+
+ else if ( fn.rfind("main.lua") != std::string::npos )
+ granger_main_lua = fn;
+
+ err = unzOpenCurrentFile(z);
+ assert( err == UNZ_OK );
+
+ // FIXME cleanup all this shit string stuff
+ std::string path = extract_path;
+ path += PATH_SEP;
+ path += fn;
+
+ Com_DPrintf(S_COLOR_YELLOW"Extracted FILE: "
+ S_COLOR_WHITE"%s\n",
+ path.c_str());
+
+ std::fstream dl;
+ dl.open(path, fstream::out|ios::binary);
+
+ // Extract the release package
+ size_t numwrote;
+ do {
+ // Extract 16k at a time
+ unsigned blocksiz = 16384;
+
+ if ( blocksiz > fi.uncompressed_size - numwrote )
+ blocksiz = fi.uncompressed_size - numwrote;
+
+ uint8_t block[blocksiz];
+ unzReadCurrentFile(z, static_cast<void*>(&block), blocksiz);
+
+ dl.write((const char*)block, blocksiz);
+ numwrote += blocksiz;
+
+ } while ( fi.uncompressed_size > numwrote );
+ dl.close();
+
+ unzCloseCurrentFile(z);
+ unzGoToNextFile(z);
+ }
+
+ unzClose(z);
+}
+
+void UpdateManager::download()
+{
+ cvar_t *cl_enableSignatureCheck = Cvar_Get("cl_enableSignatureCheck", "0", CVAR_ARCHIVE | CVAR_PROTECTED);
+
+ // Check for and download signature
+ std::string signature_url = Cvar_VariableString("cl_latestSignature");
+ if ( signature_url.empty() && cl_enableSignatureCheck->integer)
+ throw exception();
+
+ // Download the latest release
+ auto url = Cvar_VariableString("cl_latestDownload");
+ auto r = RestClient::get(url);
+ if ( r.code != 200 )
+ throw exception();
+
+ Com_DPrintf(S_COLOR_CYAN "URL: " S_COLOR_WHITE "%s\n", url);
+
+ // FIXME Cleanup this string bullshit
+ std::string extract_path, signature_path, path { Cvar_VariableString("fs_homepath") };
+ path += PATH_SEP;
+ extract_path = path;
+ signature_path = path + signature_name;
+ path += package_name;
+
+ MakeDir(extract_path, "extract");
+ extract_path += "extract";
+
+ Com_DPrintf(S_COLOR_CYAN"PATH: " S_COLOR_WHITE "%s\n",
+ path.c_str());
+
+ // Write the release package to disk
+ {
+ std::fstream dl;
+ dl.open( path, fstream::out|ios::binary );
+ dl.write( r.body.c_str(), r.body.length() );
+ dl.close();
+ }
+
+ if (cl_enableSignatureCheck->integer)
+ {
+ auto r = RestClient::get(signature_url);
+ if ( r.code != 200 )
+ throw exception();
+
+ std::fstream dl;
+ dl.open( signature_path, fstream::out|ios::binary );
+ dl.write( r.body.c_str(), r.body.length() );
+ dl.close();
+
+ // Validate the signature of the package if enabled
+ UpdateManager::validate_signature(path, signature_path);
+ }
+
+ // Extract the contents of the release package
+ UpdateManager::extract(extract_path, path);
+
+ // Delete the release package
+ unlink(path.c_str());
+
+ Cvar_SetValue("au_autoupdate_action", AU_ACT_RUN);
+}
+
+void UpdateManager::validate_signature(std::string path, std::string signature_path)
+{
+ // Load public key
+ rsa_public_key public_key;
+ rsa_public_key_init(&public_key);
+ rsa_keypair_from_sexp(&public_key, NULL, 0, release_key_pub_len, release_key_pub);
+
+ auto min = [](auto a, auto b) { return a < b ? a : b; };
+
+ // Read in signature
+ mpz_t signature;
+ {
+ std::ifstream f(signature_path, ios::binary);
+ f.seekg (0, f.end);
+ size_t length = f.tellg();
+ f.seekg (0, f.beg);
+
+ std::vector<char> buffer(512, 0);
+ f.read(buffer.data(), min(length, buffer.size()));
+ nettle_mpz_init_set_str_256_u(signature, f.gcount(), (uint8_t *)buffer.data());
+ }
+
+ // Hash file
+ sha256_ctx ctx;
+ sha256_init(&ctx);
+ {
+ std::ifstream f(path, ios::binary);
+ f.seekg (0, f.end);
+ size_t length = f.tellg();
+ f.seekg (0, f.beg);
+
+ std::vector<unsigned char> buffer(16384, 0);
+ while (f.read((char *)buffer.data(), min(length, buffer.size()))) {
+ auto nbytes = f.gcount();
+ sha256_update(&ctx, nbytes, buffer.data());
+ length -= nbytes;
+ if (length <= 0) {
+ break;
+ }
+ }
+ }
+
+ // Verify signature
+ if (!rsa_sha256_verify(&public_key, &ctx, signature)) {
+ rsa_public_key_clear(&public_key);
+ mpz_clear(signature);
+ Com_Error( ERR_DROP, "Update signature was not verified\n" );
+ return;
+ }
+
+ unlink(signature_path.c_str());
+ rsa_public_key_clear(&public_key);
+ mpz_clear(signature);
+}
+
+extern char** environ;
+
+class FailInstaller : public std::exception {
+ std::string msg;
+public:
+ FailInstaller(int e)
+ { msg = strerror(e); }
+
+ virtual const char* what() throw()
+ { return msg.c_str(); }
+};
+
+void UpdateManager::execute()
+{
+ granger_exe = "";
+ granger_main_lua = "";
+
+ if ( granger_exe == "" || granger_main_lua == "" )
+ {
+ for ( auto const& i : release_package )
+ {
+ Com_Printf(S_COLOR_RED " Unlink %s\n", i.c_str());
+ unlink(i.c_str());
+ }
+
+ Com_Error( ERR_DROP, "Missing Granger or GrangerScript\n" );
+ return;
+ }
+
+ std::array<const char*, 4> argv{};
+
+ char* tmp = strdup(granger_exe.c_str());
+ const char* dir = dirname(tmp);
+
+ argv[0] = granger_exe.c_str();
+ argv[1] = va(" -C %s", dir);
+ argv[2] = granger_main_lua.c_str();
+
+ // Dump the details
+ Com_Printf(S_COLOR_YELLOW"Launching "
+ S_COLOR_WHITE"%s %s %s\n",
+ argv[0], argv[1], argv[2]);
+
+#ifndef _WIN32
+ // Fork solely to try cleanup SDL2/GL states
+ auto pid = fork();
+ if (pid == -1)
+ throw FailInstaller(errno);
+
+ if (pid == 0)
+ {
+ execve(argv[0],
+ const_cast<char **>(argv.data()),
+ environ);
+
+ throw FailInstaller(errno);
+ }
+ else
+ {
+ Engine_Exit("");
+ }
+#else
+ // FIXME Dirty exit on Windows...
+ execve(argv[0],
+ const_cast<char **>(argv.data()),
+ environ);
+
+ throw FailInstaller(errno);
+#endif
+}
+
+void CL_GetLatestRelease() { UpdateManager::refresh(); }
+void CL_DownloadRelease() { UpdateManager::download(); }
+void CL_ExecuteInstaller() { UpdateManager::execute(); }
diff --git a/src/client/cl_updates.h b/src/client/cl_updates.h
new file mode 100644
index 0000000..f85c64a
--- /dev/null
+++ b/src/client/cl_updates.h
@@ -0,0 +1,8 @@
+#ifndef CL_UPDATES
+#define CL_UPDATES
+
+void CL_GetLatestRelease();
+void CL_DownloadRelease();
+void CL_ExecuteInstaller();
+
+#endif
diff --git a/src/client/client.h b/src/client/client.h
new file mode 100644
index 0000000..2474a3d
--- /dev/null
+++ b/src/client/client.h
@@ -0,0 +1,716 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// client.h -- primary header for client
+
+#ifndef _CLIENT_H_
+#define _CLIENT_H_
+
+#ifdef USE_VOIP
+#include <opus.h>
+#endif
+
+#include "cgame/cg_public.h"
+#include "qcommon/alternatePlayerstate.h"
+#include "qcommon/cmd.h"
+#include "qcommon/crypto.h"
+#include "qcommon/cvar.h"
+#include "qcommon/files.h"
+#include "qcommon/huffman.h"
+#include "qcommon/msg.h"
+#include "qcommon/net.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+#include "qcommon/vm.h"
+#include "renderercommon/tr_public.h"
+#include "sys/sys_shared.h"
+#include "ui/ui_public.h"
+
+#include "cl_curl.h"
+#include "keys.h"
+#include "snd_public.h"
+
+struct alternateEntityState_t {
+ int number; // entity index
+ int eType; // entityType_t
+ int eFlags;
+
+ trajectory_t pos; // for calculating position
+ trajectory_t apos; // for calculating angles
+
+ int time;
+ int time2;
+
+ vec3_t origin;
+ vec3_t origin2;
+
+ vec3_t angles;
+ vec3_t angles2;
+
+ int otherEntityNum; // shotgun sources, etc
+ int otherEntityNum2;
+
+ int groundEntityNum; // ENTITYNUM_NONE = in air
+
+ int constantLight; // r + (g<<8) + (b<<16) + (intensity<<24)
+ int loopSound; // constantly loop this sound
+
+ int modelindex;
+ int modelindex2;
+ int clientNum; // 0 to (MAX_CLIENTS - 1), for players and corpses
+ int frame;
+
+ int solid; // for client side prediction, trap_linkentity sets this properly
+
+ int event; // impulse events -- muzzle flashes, footsteps, etc
+ int eventParm;
+
+ // for players
+ int misc; // bit flags
+ int weapon; // determines weapon and flash model, etc
+ int legsAnim; // mask off ANIM_TOGGLEBIT
+ int torsoAnim; // mask off ANIM_TOGGLEBIT
+
+ int generic1;
+};
+
+struct alternateSnapshot_t {
+ int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
+ int ping;
+
+ int serverTime; // server time the message is valid for (in msec)
+
+ byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
+
+ alternatePlayerState_t ps; // complete information about the current player at this time
+
+ int numEntities; // all of the entities that need to be presented
+ alternateEntityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot
+
+ int numServerCommands; // text based server commands to execute when this
+ int serverCommandSequence; // snapshot becomes current
+};
+
+// file full of random crap that gets used to create cl_guid
+#define QKEY_FILE "qkey"
+#define QKEY_SIZE 2048
+
+#define RETRANSMIT_TIMEOUT 3000 // time between connection packet retransmits
+
+// snapshots are a view of the server at a given time
+struct clSnapshot_t {
+ bool valid; // cleared if delta parsing was invalid
+ int snapFlags; // rate delayed and dropped commands
+
+ int serverTime; // server time the message is valid for (in msec)
+
+ int messageNum; // copied from netchan->incoming_sequence
+ int deltaNum; // messageNum the delta is from
+ int ping; // time from when cmdNum-1 was sent to time packet was reeceived
+ byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
+
+ int cmdNum; // the next cmdNum the server is expecting
+ playerState_t ps; // complete information about the current player at this time
+ alternatePlayerState_t alternatePs; // complete information about the current player at this time
+
+ int numEntities; // all of the entities that need to be presented
+ int parseEntitiesNum; // at the time of this snapshot
+
+ int serverCommandNum; // execute all commands up to this before
+ // making the snapshot current
+};
+
+/*
+=============================================================================
+
+the clientActive_t structure is wiped completely at every
+new gamestate_t, potentially several times during an established connection
+
+=============================================================================
+*/
+
+struct outPacket_t {
+ int p_cmdNumber; // cl.cmdNumber when packet was sent
+ int p_serverTime; // usercmd->serverTime when packet was sent
+ int p_realtime; // cls.realtime when packet was sent
+};
+
+// the parseEntities array must be large enough to hold PACKET_BACKUP frames of
+// entities, so that when a delta compressed message arives from the server
+// it can be un-deltad from the original
+#define MAX_PARSE_ENTITIES (PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES)
+
+extern int g_console_field_width;
+
+struct clientActive_t {
+ int timeoutcount; // it requres several frames in a timeout condition
+ // to disconnect, preventing debugging breaks from
+ // causing immediate disconnects on continue
+ clSnapshot_t snap; // latest received from server
+
+ int serverTime; // may be paused during play
+ int oldServerTime; // to prevent time from flowing bakcwards
+ int oldFrameServerTime; // to check tournament restarts
+ int serverTimeDelta; // cl.serverTime = cls.realtime + cl.serverTimeDelta
+ // this value changes as net lag varies
+ bool extrapolatedSnapshot; // set if any cgame frame has been forced to extrapolate
+ // cleared when CL_AdjustTimeDelta looks at it
+ bool newSnapshots; // set on parse of any valid packet
+
+ gameState_t gameState; // configstrings
+ char mapname[MAX_QPATH]; // extracted from CS_SERVERINFO
+
+ int parseEntitiesNum; // index (not anded off) into cl_parse_entities[]
+
+ int mouseDx[2], mouseDy[2]; // added to by mouse events
+ int mouseIndex;
+ int joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
+
+ // cgame communicates a few values to the client system
+ int cgameUserCmdValue; // current weapon to add to usercmd_t
+ float cgameSensitivity;
+
+ // cmds[cmdNumber] is the predicted command, [cmdNumber-1] is the last
+ // properly generated command
+ usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds
+ int cmdNumber; // incremented each frame, because multiple
+ // frames may need to be packed into a single packet
+
+ outPacket_t outPackets[PACKET_BACKUP]; // information about each packet we have sent out
+
+ // the client maintains its own idea of view angles, which are
+ // sent to the server each frame. It is cleared to 0 upon entering each level.
+ // the server sends a delta each frame which is added to the locally
+ // tracked view angles to account for standing on rotating objects,
+ // and teleport direction changes
+ vec3_t viewangles;
+
+ int serverId; // included in each client message so the server
+ // can tell if it is for a prior map_restart
+ // big stuff at end of structure so most offsets are 15 bits or less
+ clSnapshot_t snapshots[PACKET_BACKUP];
+
+ entityState_t entityBaselines[MAX_GENTITIES]; // for delta compression when not in previous frame
+
+ entityState_t parseEntities[MAX_PARSE_ENTITIES];
+};
+
+extern clientActive_t cl;
+
+/*
+=============================================================================
+
+the clientConnection_t structure is wiped when disconnecting from a server,
+either to go to a full screen console, play a demo, or connect to a different server
+
+A connection can be to either a server through the network layer or a
+demo through a file.
+
+=============================================================================
+*/
+
+#define MAX_TIMEDEMO_DURATIONS 4096
+
+struct clientConnection_t {
+ connstate_t state; // connection status
+
+ int clientNum;
+ int lastPacketSentTime; // for retransmits during connection
+ int lastPacketTime; // for timeouts
+
+ char servername[MAX_OSPATH]; // name of server from original connect (used by reconnect)
+ netadr_t serverAddress;
+ int connectTime; // for connection retransmits
+ int connectPacketCount; // for display on connection dialog
+ char serverMessage[MAX_STRING_TOKENS]; // for display on connection dialog
+
+ int challenge; // from the server to use for connecting
+ char challenge2[33];
+ bool sendSignature;
+ int checksumFeed; // from the server for checksum calculations
+
+ // these are our reliable messages that go to the server
+ int reliableSequence;
+ int reliableAcknowledge; // the last one the server has executed
+ char reliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];
+
+ // server message (unreliable) and command (reliable) sequence
+ // numbers are NOT cleared at level changes, but continue to
+ // increase as long as the connection is valid
+
+ // message sequence is used by both the network layer and the
+ // delta compression layer
+ int serverMessageSequence;
+
+ // reliable messages received from server
+ int serverCommandSequence;
+ int lastExecutedServerCommand; // last server command grabbed or executed with CL_GetServerCommand
+ char serverCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];
+
+ // file transfer from server
+ fileHandle_t download;
+ char downloadTempName[MAX_OSPATH];
+ char downloadName[MAX_OSPATH];
+
+ // XXX Refactor this -vjr
+ bool cURLEnabled;
+ bool cURLUsed;
+ bool cURLDisconnected;
+
+ char downloadURL[MAX_OSPATH];
+ CURL *downloadCURL;
+ CURLM *downloadCURLM;
+ bool activeCURLNotGameRelated;
+
+ int sv_allowDownload;
+ char sv_dlURL[MAX_CVAR_VALUE_STRING];
+ int downloadNumber;
+ int downloadBlock; // block we are waiting for
+ int downloadCount; // how many bytes we got
+ int downloadSize; // how many bytes we got
+ char downloadList[MAX_INFO_STRING]; // list of paks we need to download
+ bool downloadRestart; // if true, we need to do another FS_Restart because we downloaded a pak
+ char newsString[MAX_NEWS_STRING];
+
+ // demo information
+ char demoName[MAX_QPATH];
+ bool spDemoRecording;
+ bool demorecording;
+ bool demoplaying;
+ bool demowaiting; // don't record until a non-delta message is received
+ bool firstDemoFrameSkipped;
+ fileHandle_t demofile;
+
+ int timeDemoFrames; // counter of rendered frames
+ int timeDemoStart; // cls.realtime before first frame
+ int timeDemoBaseTime; // each frame will be at this time + frameNum * 50
+ int timeDemoLastFrame; // time the last frame was rendered
+ int timeDemoMinDuration; // minimum frame duration
+ int timeDemoMaxDuration; // maximum frame duration
+ unsigned char timeDemoDurations[MAX_TIMEDEMO_DURATIONS]; // log of frame durations
+
+ float aviVideoFrameRemainder;
+ float aviSoundFrameRemainder;
+
+#ifdef USE_VOIP
+ bool voipEnabled;
+ bool voipCodecInitialized;
+
+ // incoming data...
+ // !!! FIXME: convert from parallel arrays to array of a struct.
+ OpusDecoder *opusDecoder[MAX_CLIENTS];
+ byte voipIncomingGeneration[MAX_CLIENTS];
+ int voipIncomingSequence[MAX_CLIENTS];
+ float voipGain[MAX_CLIENTS];
+ bool voipIgnore[MAX_CLIENTS];
+ bool voipMuteAll;
+
+ // outgoing data...
+ // if voipTargets[i / 8] & (1 << (i % 8)),
+ // then we are sending to clientnum i.
+ uint8_t voipTargets[(MAX_CLIENTS + 7) / 8];
+ uint8_t voipFlags;
+ OpusEncoder *opusEncoder;
+ int voipOutgoingDataSize;
+ int voipOutgoingDataFrames;
+ int voipOutgoingSequence;
+ byte voipOutgoingGeneration;
+ byte voipOutgoingData[1024];
+ float voipPower;
+#endif
+
+ // big stuff at end of structure so most offsets are 15 bits or less
+ netchan_t netchan;
+};
+
+extern clientConnection_t clc;
+
+/*
+==================================================================
+
+the clientStatic_t structure is never wiped, and is used even when
+no client connection is active at all
+(except when CL_Shutdown is called)
+
+==================================================================
+*/
+
+struct ping_t {
+ netadr_t adr;
+ int start;
+ int time;
+ char info[MAX_INFO_STRING];
+};
+
+#define MAX_FEATLABEL_CHARS 32
+struct serverInfo_t {
+ netadr_t adr;
+ char hostName[MAX_HOSTNAME_LENGTH];
+ char mapName[MAX_NAME_LENGTH];
+ char game[MAX_NAME_LENGTH];
+ char label[MAX_FEATLABEL_CHARS]; // for featured servers, NULL otherwise
+ int netType;
+ int gameType;
+ int clients;
+ int maxClients;
+ int minPing;
+ int maxPing;
+ int ping;
+ bool visible;
+};
+
+struct clientStatic_t {
+ // when the server clears the hunk, all of these must be restarted
+ bool rendererStarted;
+ bool soundStarted;
+ bool soundRegistered;
+ bool uiStarted;
+ bool cgameStarted;
+
+ int framecount;
+ int frametime; // msec since last frame
+
+ int realtime; // ignores pause
+ int realFrametime; // ignoring pause, so console always works
+
+ // master server sequence information
+ int numAlternateMasterPackets[3];
+ unsigned int receivedAlternateMasterPackets[3]; // bitfield
+
+ int numlocalservers;
+ serverInfo_t localServers[MAX_OTHER_SERVERS];
+
+ int numglobalservers;
+ serverInfo_t globalServers[MAX_GLOBAL_SERVERS];
+ // additional global servers
+ int numGlobalServerAddresses;
+ netadr_t globalServerAddresses[MAX_GLOBAL_SERVERS];
+
+ int numfavoriteservers;
+ serverInfo_t favoriteServers[MAX_OTHER_SERVERS];
+
+ int pingUpdateSource; // source currently pinging or updating
+
+ // update server info
+ netadr_t updateServer;
+ char updateChallenge[MAX_TOKEN_CHARS];
+ char updateInfoString[MAX_INFO_STRING];
+
+ netadr_t authorizeServer;
+
+ // rendering info
+ glconfig_t glconfig;
+ qhandle_t charSetShader;
+ qhandle_t whiteShader;
+ qhandle_t consoleShader;
+
+ vm_t *cgame;
+ int cgInterface; // 0 == gpp, 2 == 1.1.0
+
+ vm_t *ui;
+ int uiInterface;
+
+ struct {
+ struct rsa_public_key public_key;
+ struct rsa_private_key private_key;
+ } rsa;
+};
+
+extern clientStatic_t cls;
+
+extern char cl_oldGame[MAX_QPATH];
+extern bool cl_oldGameSet;
+
+//=============================================================================
+
+extern refexport_t re; // interface to refresh .dll
+
+//
+// cvars
+//
+extern cvar_t *cl_nodelta;
+extern cvar_t *cl_debugMove;
+extern cvar_t *cl_noprint;
+extern cvar_t *cl_timegraph;
+extern cvar_t *cl_maxpackets;
+extern cvar_t *cl_packetdup;
+extern cvar_t *cl_shownet;
+extern cvar_t *cl_showSend;
+extern cvar_t *cl_timeNudge;
+extern cvar_t *cl_showTimeDelta;
+extern cvar_t *cl_freezeDemo;
+
+extern cvar_t *cl_yawspeed;
+extern cvar_t *cl_pitchspeed;
+extern cvar_t *cl_run;
+extern cvar_t *cl_anglespeedkey;
+
+extern cvar_t *cl_sensitivity;
+extern cvar_t *cl_freelook;
+
+extern cvar_t *cl_mouseAccel;
+extern cvar_t *cl_mouseAccelOffset;
+extern cvar_t *cl_mouseAccelStyle;
+extern cvar_t *cl_showMouseRate;
+
+extern cvar_t *m_pitch;
+extern cvar_t *m_yaw;
+extern cvar_t *m_forward;
+extern cvar_t *m_side;
+extern cvar_t *m_filter;
+
+extern cvar_t *j_pitch;
+extern cvar_t *j_yaw;
+extern cvar_t *j_forward;
+extern cvar_t *j_side;
+extern cvar_t *j_up;
+extern cvar_t *j_pitch_axis;
+extern cvar_t *j_yaw_axis;
+extern cvar_t *j_forward_axis;
+extern cvar_t *j_side_axis;
+extern cvar_t *j_up_axis;
+
+extern cvar_t *cl_timedemo;
+extern cvar_t *cl_aviFrameRate;
+extern cvar_t *cl_aviMotionJpeg;
+
+extern cvar_t *cl_activeAction;
+
+extern cvar_t *cl_allowDownload;
+extern cvar_t *cl_downloadMethod;
+extern cvar_t *cl_conXOffset;
+extern cvar_t *cl_inGameVideo;
+
+extern cvar_t *cl_lanForcePackets;
+extern cvar_t *cl_autoRecordDemo;
+
+extern cvar_t *cl_clantag;
+
+extern cvar_t *cl_consoleKeys;
+
+#ifdef USE_MUMBLE
+extern cvar_t *cl_useMumble;
+extern cvar_t *cl_mumbleScale;
+#endif
+
+#ifdef USE_VOIP
+// cl_voipSendTarget is a string: "all" to broadcast to everyone, "none" to
+// send to no one, or a comma-separated list of client numbers:
+// "0,7,2,23" ... an empty string is treated like "all".
+extern cvar_t *cl_voipUseVAD;
+extern cvar_t *cl_voipVADThreshold;
+extern cvar_t *cl_voipSend;
+extern cvar_t *cl_voipSendTarget;
+extern cvar_t *cl_voipGainDuringCapture;
+extern cvar_t *cl_voipCaptureMult;
+extern cvar_t *cl_voipShowMeter;
+extern cvar_t *cl_voip;
+
+// 20ms at 48k
+#define VOIP_MAX_FRAME_SAMPLES (20 * 48)
+
+// 3 frame is 60ms of audio, the max opus will encode at once
+#define VOIP_MAX_PACKET_FRAMES 3
+#define VOIP_MAX_PACKET_SAMPLES (VOIP_MAX_FRAME_SAMPLES * VOIP_MAX_PACKET_FRAMES)
+#endif
+
+extern cvar_t *cl_rsaAuth;
+
+//=================================================
+
+//
+// cl_main
+//
+
+void CL_Init(void);
+void CL_AddReliableCommand(const char *cmd, bool isDisconnectCmd);
+
+void CL_StartHunkUsers(bool rendererOnly);
+
+void CL_Disconnect_f(void);
+void CL_NextDemo(void);
+void CL_ReadDemoMessage(void);
+demoState_t CL_DemoState(void);
+int CL_DemoPos(void);
+void CL_DemoName(char *buffer, int size);
+void CL_StopRecord_f(void);
+
+void CL_InitDownloads(void);
+void CL_NextDownload(void);
+
+void CL_GetPing(int n, char *buf, int buflen, int *pingtime);
+void CL_GetPingInfo(int n, char *buf, int buflen);
+void CL_ClearPing(int n);
+int CL_GetPingQueueCount(void);
+
+bool CL_ServerStatus(char *serverAddress, char *serverStatusString, int maxLen);
+
+bool CL_CheckPaused(void);
+
+//
+// cl_input
+//
+typedef struct {
+ int down[2]; // key nums holding it down
+ unsigned downtime; // msec timestamp
+ unsigned msec; // msec down this frame if both a down and up happened
+ bool active; // current state
+ bool wasPressed; // set when down, not cleared when up
+} kbutton_t;
+
+void CL_InitInput(void);
+void CL_ShutdownInput(void);
+void CL_SendCmd(void);
+void CL_ClearState(void);
+void CL_ReadPackets(void);
+
+void CL_WritePacket(void);
+//void IN_CenterView(void);
+
+int Key_StringToKeynum(const char *str);
+const char *Key_KeynumToString(int keynum);
+
+//
+// cl_parse.c
+//
+extern bool cl_connectedToPureServer;
+extern bool cl_connectedToCheatServer;
+
+#ifdef USE_VOIP
+void CL_Voip_f(void);
+#endif
+
+void CL_SystemInfoChanged(void);
+void CL_ParseServerMessage(msg_t *msg);
+
+//====================================================================
+
+bool CL_UpdateVisiblePings_f(int source);
+
+//
+// console
+//
+void Con_DrawCharacter(int cx, int line, int num);
+
+void Con_CheckResize(void);
+void Con_MessageModesInit(void);
+void CL_ProtocolSpecificCommandsInit(void);
+void Con_Init(void);
+void Con_Shutdown(void);
+void Con_Clear_f(void);
+void Con_ToggleConsole_f(void);
+void Con_ClearNotify(void);
+void Con_RunConsole(void);
+void Con_DrawConsole(void);
+void Con_PageUp(void);
+void Con_PageDown(void);
+void Con_Top(void);
+void Con_Bottom(void);
+void Con_Close(void);
+
+void CL_LoadConsoleHistory(void);
+void CL_SaveConsoleHistory(void);
+
+//
+// cl_scrn.c
+//
+void SCR_Init(void);
+void SCR_UpdateScreen(void);
+
+void SCR_DebugGraph(float value);
+
+int SCR_GetBigStringWidth(const char *str); // returns in virtual 640x480 coordinates
+
+void SCR_AdjustFrom640(float *x, float *y, float *w, float *h);
+void SCR_FillRect(float x, float y, float width, float height, const float *color);
+void SCR_DrawPic(float x, float y, float width, float height, qhandle_t hShader);
+void SCR_DrawNamedPic(float x, float y, float width, float height, const char *picname);
+
+void SCR_DrawBigString(int x, int y, const char *s, float alpha,
+ bool noColorEscape); // draws a string with embedded color control characters with fade
+void SCR_DrawBigStringColor(
+ int x, int y, const char *s, vec4_t color, bool noColorEscape); // ignores embedded color control characters
+void SCR_DrawSmallStringExt(int x, int y, const char *string, float *setColor, bool forceColor, bool noColorEscape);
+void SCR_DrawSmallChar(int x, int y, int ch);
+
+//
+// cl_cin.c
+//
+
+void CL_PlayCinematic_f(void);
+void SCR_DrawCinematic(void);
+void SCR_RunCinematic(void);
+void SCR_StopCinematic(void);
+int CIN_PlayCinematic(const char *arg0, int xpos, int ypos, int width, int height, int bits);
+e_status CIN_StopCinematic(int handle);
+e_status CIN_RunCinematic(int handle);
+void CIN_DrawCinematic(int handle);
+void CIN_SetExtents(int handle, int x, int y, int w, int h);
+void CIN_UploadCinematic(int handle);
+void CIN_CloseAllVideos(void);
+
+//
+// cl_cgame.c
+//
+void CL_InitCGame(void);
+void CL_ShutdownCGame(void);
+bool CL_GameCommand(void);
+void CL_GameConsoleText(void);
+void CL_CGameRendering(stereoFrame_t stereo);
+void CL_SetCGameTime(void);
+void CL_FirstSnapshot(void);
+void CL_ShaderStateChanged(void);
+
+//
+// cl_ui.c
+//
+void CL_InitUI(void);
+void CL_ShutdownUI(void);
+int Key_GetCatcher(void);
+void Key_SetCatcher(int catcher);
+void LAN_LoadCachedServers(void);
+void LAN_SaveServersToCache(void);
+
+//
+// cl_net_chan.c
+//
+void CL_Netchan_Transmit(netchan_t *chan, msg_t *msg); // int length, const byte *data );
+bool CL_Netchan_Process(netchan_t *chan, msg_t *msg);
+
+//
+// cl_avi.c
+//
+bool CL_OpenAVIForWriting(const char *filename);
+void CL_TakeVideoFrame(void);
+void CL_WriteAVIVideoFrame(const byte *imageBuffer, int size);
+void CL_WriteAVIAudioFrame(const byte *pcmBuffer, int size);
+bool CL_CloseAVI(void);
+bool CL_VideoRecording(void);
+
+//
+// cl_main.c
+//
+void CL_WriteDemoMessage(msg_t *msg, int headerBytes);
+int CL_ScaledMilliseconds(void);
+
+#endif
diff --git a/src/client/keycodes.h b/src/client/keycodes.h
index ae6f189..3b2958d 100644
--- a/src/client/keycodes.h
+++ b/src/client/keycodes.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
//
@@ -262,6 +263,39 @@ typedef enum {
K_EURO,
K_UNDO,
+ // Gamepad controls
+ // Ordered to match SDL2 game controller buttons and axes
+ // Do not change this order without also changing IN_GamepadMove() in SDL_input.c
+ K_PAD0_A,
+ K_PAD0_B,
+ K_PAD0_X,
+ K_PAD0_Y,
+ K_PAD0_BACK,
+ K_PAD0_GUIDE,
+ K_PAD0_START,
+ K_PAD0_LEFTSTICK_CLICK,
+ K_PAD0_RIGHTSTICK_CLICK,
+ K_PAD0_LEFTSHOULDER,
+ K_PAD0_RIGHTSHOULDER,
+ K_PAD0_DPAD_UP,
+ K_PAD0_DPAD_DOWN,
+ K_PAD0_DPAD_LEFT,
+ K_PAD0_DPAD_RIGHT,
+
+ K_PAD0_LEFTSTICK_LEFT,
+ K_PAD0_LEFTSTICK_RIGHT,
+ K_PAD0_LEFTSTICK_UP,
+ K_PAD0_LEFTSTICK_DOWN,
+ K_PAD0_RIGHTSTICK_LEFT,
+ K_PAD0_RIGHTSTICK_RIGHT,
+ K_PAD0_RIGHTSTICK_UP,
+ K_PAD0_RIGHTSTICK_DOWN,
+ K_PAD0_LEFTTRIGGER,
+ K_PAD0_RIGHTTRIGGER,
+
+ // Pseudo-key that brings the console down
+ K_CONSOLE,
+
MAX_KEYS
} keyNum_t;
diff --git a/src/client/keys.h b/src/client/keys.h
new file mode 100644
index 0000000..5c8877f
--- /dev/null
+++ b/src/client/keys.h
@@ -0,0 +1,66 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#ifndef _KEYS_H_
+#define _KEYS_H_
+
+#include "keycodes.h"
+
+typedef struct {
+ bool down;
+ int repeats; // if > 1, it is autorepeating
+ char *binding;
+} qkey_t;
+
+extern bool key_overstrikeMode;
+extern qkey_t keys[MAX_KEYS];
+
+// NOTE TTimo the declaration of field_t and Field_Clear is now in qcommon/qcommon.h
+void Field_KeyDownEvent(field_t *edit, int key);
+void Field_CharEvent(field_t *edit, int ch);
+void Field_Draw(field_t *edit, int x, int y, int width, bool showCursor, bool noColorEscape);
+void Field_BigDraw(field_t *edit, int x, int y, int width, bool showCursor, bool noColorEscape);
+
+#define COMMAND_HISTORY 32
+extern field_t historyEditLines[COMMAND_HISTORY];
+
+extern field_t g_consoleField;
+extern field_t chatField;
+extern int anykeydown;
+extern bool chat_team;
+extern bool chat_admins;
+extern bool chat_clans;
+extern int chat_playerNum;
+
+void Key_WriteBindings(fileHandle_t f);
+void Key_SetBinding(int keynum, const char *binding);
+const char *Key_GetBinding(int keynum);
+bool Key_IsDown(int keynum);
+bool Key_GetOverstrikeMode(void);
+void Key_SetOverstrikeMode(bool state);
+void Key_ClearStates(void);
+int Key_GetKey(const char *binding);
+void Key_KeynumToStringBuf(int keynum, char *buf, int buflen);
+void Key_GetBindingBuf(int keynum, char *buf, int buflen);
+
+#endif
diff --git a/src/client/libmumblelink.cpp b/src/client/libmumblelink.cpp
new file mode 100644
index 0000000..59d59d3
--- /dev/null
+++ b/src/client/libmumblelink.cpp
@@ -0,0 +1,190 @@
+/* libmumblelink.c -- mumble link interface
+
+ Copyright (C) 2008 Ludwig Nussel <ludwig.nussel@suse.de>
+ Copyright (C) 2000-2013 Darklegion Development
+ Copyright (C) 2015-2019 GrangerHub
+
+ 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.
+
+*/
+
+#include "libmumblelink.h"
+
+#include <fcntl.h>
+#ifdef _WIN32
+#include <windows.h>
+#define uint32_t UINT32
+#else
+#include <unistd.h>
+#ifdef __sun
+#define _POSIX_C_SOURCE 199309L
+#endif
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#endif
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#ifndef MIN
+#define MIN(a, b) ((a)<(b)?(a):(b))
+#endif
+
+typedef struct
+{
+ uint32_t uiVersion;
+ uint32_t uiTick;
+ float fAvatarPosition[3];
+ float fAvatarFront[3];
+ float fAvatarTop[3];
+ wchar_t name[256];
+ /* new in mumble 1.2 */
+ float fCameraPosition[3];
+ float fCameraFront[3];
+ float fCameraTop[3];
+ wchar_t identity[256];
+ uint32_t context_len;
+ unsigned char context[256];
+ wchar_t description[2048];
+} LinkedMem;
+
+static LinkedMem *lm = NULL;
+
+#ifdef WIN32
+static HANDLE hMapObject = NULL;
+#else
+static int32_t GetTickCount(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+
+ return tv.tv_usec / 1000 + tv.tv_sec * 1000;
+}
+#endif
+
+int mumble_link(const char* name)
+{
+#ifdef WIN32
+ if(lm)
+ return 0;
+
+ hMapObject = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink");
+ if (hMapObject == NULL)
+ return -1;
+
+ lm = (LinkedMem *) MapViewOfFile(hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(LinkedMem));
+ if (lm == NULL) {
+ CloseHandle(hMapObject);
+ hMapObject = NULL;
+ return -1;
+ }
+#else
+ char file[256];
+ int shmfd;
+ if(lm)
+ return 0;
+
+ snprintf(file, sizeof (file), "/MumbleLink.%d", getuid());
+ shmfd = shm_open(file, O_RDWR, S_IRUSR | S_IWUSR);
+ if(shmfd < 0) {
+ return -1;
+ }
+
+ lm = (LinkedMem *) (mmap(NULL, sizeof(LinkedMem), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd,0));
+ if (lm == (void *) (-1)) {
+ lm = NULL;
+ close(shmfd);
+ return -1;
+ }
+ close(shmfd);
+#endif
+ memset(lm, 0, sizeof(LinkedMem));
+ mbstowcs(lm->name, name, sizeof(lm->name) / sizeof(wchar_t));
+
+ return 0;
+}
+
+void mumble_update_coordinates(float fPosition[3], float fFront[3], float fTop[3])
+{
+ mumble_update_coordinates2(fPosition, fFront, fTop, fPosition, fFront, fTop);
+}
+
+void mumble_update_coordinates2(float fAvatarPosition[3], float fAvatarFront[3], float fAvatarTop[3],
+ float fCameraPosition[3], float fCameraFront[3], float fCameraTop[3])
+{
+ if (!lm)
+ return;
+
+ memcpy(lm->fAvatarPosition, fAvatarPosition, sizeof(lm->fAvatarPosition));
+ memcpy(lm->fAvatarFront, fAvatarFront, sizeof(lm->fAvatarFront));
+ memcpy(lm->fAvatarTop, fAvatarTop, sizeof(lm->fAvatarTop));
+ memcpy(lm->fCameraPosition, fCameraPosition, sizeof(lm->fCameraPosition));
+ memcpy(lm->fCameraFront, fCameraFront, sizeof(lm->fCameraFront));
+ memcpy(lm->fCameraTop, fCameraTop, sizeof(lm->fCameraTop));
+ lm->uiVersion = 2;
+ lm->uiTick = GetTickCount();
+}
+
+void mumble_set_identity(const char* identity)
+{
+ size_t len;
+ if (!lm)
+ return;
+ len = MIN(sizeof(lm->identity)/sizeof(wchar_t), strlen(identity)+1);
+ mbstowcs(lm->identity, identity, len);
+}
+
+void mumble_set_context(const unsigned char* context, size_t len)
+{
+ if (!lm)
+ return;
+ len = MIN(sizeof(lm->context), len);
+ lm->context_len = len;
+ memcpy(lm->context, context, len);
+}
+
+void mumble_set_description(const char* description)
+{
+ size_t len;
+ if (!lm)
+ return;
+ len = MIN(sizeof(lm->description)/sizeof(wchar_t), strlen(description)+1);
+ mbstowcs(lm->description, description, len);
+}
+
+void mumble_unlink()
+{
+ if(!lm)
+ return;
+#ifdef WIN32
+ UnmapViewOfFile(lm);
+ CloseHandle(hMapObject);
+ hMapObject = NULL;
+#else
+ munmap(lm, sizeof(LinkedMem));
+#endif
+ lm = NULL;
+}
+
+int mumble_islinked(void)
+{
+ return lm != NULL;
+}
diff --git a/src/client/libmumblelink.h b/src/client/libmumblelink.h
new file mode 100644
index 0000000..aa8e2ce
--- /dev/null
+++ b/src/client/libmumblelink.h
@@ -0,0 +1,41 @@
+/* libmumblelink.h -- mumble link interface
+
+ Copyright (C) 2008 Ludwig Nussel <ludwig.nussel@suse.de>
+ Copyright (C) 2000-2013 Darklegion Development
+ Copyright (C) 2015-2019 GrangerHub
+
+ 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.
+
+*/
+#ifndef _LIBMUMBLELINK_H_
+#define _LIBMUMBLELINK_H_
+
+int mumble_link(const char* name);
+int mumble_islinked(void);
+void mumble_update_coordinates(float fPosition[3], float fFront[3], float fTop[3]);
+
+/* new for mumble 1.2: also set camera position */
+void mumble_update_coordinates2(float fAvatarPosition[3], float fAvatarFront[3], float fAvatarTop[3],
+ float fCameraPosition[3], float fCameraFront[3], float fCameraTop[3]);
+
+void mumble_set_description(const char* description);
+void mumble_set_context(const unsigned char* context, size_t len);
+void mumble_set_identity(const char* identity);
+
+void mumble_unlink(void);
+
+#endif // _LIBMUMBLELINK_H_
diff --git a/src/client/qal.cpp b/src/client/qal.cpp
new file mode 100644
index 0000000..466a45e
--- /dev/null
+++ b/src/client/qal.cpp
@@ -0,0 +1,337 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// Dynamically loads OpenAL
+
+#ifdef USE_OPENAL
+
+#include "qal.h"
+
+#ifdef USE_OPENAL_DLOPEN
+#include "sys/sys_loadlib.h"
+
+LPALENABLE qalEnable;
+LPALDISABLE qalDisable;
+LPALISENABLED qalIsEnabled;
+LPALGETSTRING qalGetString;
+LPALGETBOOLEANV qalGetBooleanv;
+LPALGETINTEGERV qalGetIntegerv;
+LPALGETFLOATV qalGetFloatv;
+LPALGETDOUBLEV qalGetDoublev;
+LPALGETBOOLEAN qalGetBoolean;
+LPALGETINTEGER qalGetInteger;
+LPALGETFLOAT qalGetFloat;
+LPALGETDOUBLE qalGetDouble;
+LPALGETERROR qalGetError;
+LPALISEXTENSIONPRESENT qalIsExtensionPresent;
+LPALGETPROCADDRESS qalGetProcAddress;
+LPALGETENUMVALUE qalGetEnumValue;
+LPALLISTENERF qalListenerf;
+LPALLISTENER3F qalListener3f;
+LPALLISTENERFV qalListenerfv;
+LPALLISTENERI qalListeneri;
+LPALGETLISTENERF qalGetListenerf;
+LPALGETLISTENER3F qalGetListener3f;
+LPALGETLISTENERFV qalGetListenerfv;
+LPALGETLISTENERI qalGetListeneri;
+LPALGENSOURCES qalGenSources;
+LPALDELETESOURCES qalDeleteSources;
+LPALISSOURCE qalIsSource;
+LPALSOURCEF qalSourcef;
+LPALSOURCE3F qalSource3f;
+LPALSOURCEFV qalSourcefv;
+LPALSOURCEI qalSourcei;
+LPALGETSOURCEF qalGetSourcef;
+LPALGETSOURCE3F qalGetSource3f;
+LPALGETSOURCEFV qalGetSourcefv;
+LPALGETSOURCEI qalGetSourcei;
+LPALSOURCEPLAYV qalSourcePlayv;
+LPALSOURCESTOPV qalSourceStopv;
+LPALSOURCEREWINDV qalSourceRewindv;
+LPALSOURCEPAUSEV qalSourcePausev;
+LPALSOURCEPLAY qalSourcePlay;
+LPALSOURCESTOP qalSourceStop;
+LPALSOURCEREWIND qalSourceRewind;
+LPALSOURCEPAUSE qalSourcePause;
+LPALSOURCEQUEUEBUFFERS qalSourceQueueBuffers;
+LPALSOURCEUNQUEUEBUFFERS qalSourceUnqueueBuffers;
+LPALGENBUFFERS qalGenBuffers;
+LPALDELETEBUFFERS qalDeleteBuffers;
+LPALISBUFFER qalIsBuffer;
+LPALBUFFERDATA qalBufferData;
+LPALGETBUFFERF qalGetBufferf;
+LPALGETBUFFERI qalGetBufferi;
+LPALDOPPLERFACTOR qalDopplerFactor;
+LPALSPEEDOFSOUND qalSpeedOfSound;
+LPALDISTANCEMODEL qalDistanceModel;
+
+LPALCCREATECONTEXT qalcCreateContext;
+LPALCMAKECONTEXTCURRENT qalcMakeContextCurrent;
+LPALCPROCESSCONTEXT qalcProcessContext;
+LPALCSUSPENDCONTEXT qalcSuspendContext;
+LPALCDESTROYCONTEXT qalcDestroyContext;
+LPALCGETCURRENTCONTEXT qalcGetCurrentContext;
+LPALCGETCONTEXTSDEVICE qalcGetContextsDevice;
+LPALCOPENDEVICE qalcOpenDevice;
+LPALCCLOSEDEVICE qalcCloseDevice;
+LPALCGETERROR qalcGetError;
+LPALCISEXTENSIONPRESENT qalcIsExtensionPresent;
+LPALCGETPROCADDRESS qalcGetProcAddress;
+LPALCGETENUMVALUE qalcGetEnumValue;
+LPALCGETSTRING qalcGetString;
+LPALCGETINTEGERV qalcGetIntegerv;
+LPALCCAPTUREOPENDEVICE qalcCaptureOpenDevice;
+LPALCCAPTURECLOSEDEVICE qalcCaptureCloseDevice;
+LPALCCAPTURESTART qalcCaptureStart;
+LPALCCAPTURESTOP qalcCaptureStop;
+LPALCCAPTURESAMPLES qalcCaptureSamples;
+
+static void *OpenALLib = NULL;
+
+static bool alinit_fail = false;
+
+/*
+=================
+GPA
+=================
+*/
+static void *GPA(const char *str)
+{
+ void *rv;
+
+ rv = Sys_LoadFunction(OpenALLib, str);
+ if(!rv)
+ {
+ Com_Printf( " Can't load symbol %s\n", str);
+ alinit_fail = true;
+ return NULL;
+ }
+ else
+ {
+ Com_DPrintf( " Loaded symbol %s (%p)\n", str, rv);
+ return rv;
+ }
+}
+
+/*
+=================
+QAL_Init
+=================
+*/
+bool QAL_Init(const char *libname)
+{
+ if(OpenALLib)
+ return true;
+
+ if(!(OpenALLib = Sys_LoadDll(libname, true)))
+ return false;
+
+ alinit_fail = false;
+
+ qalEnable = (LPALENABLE)GPA("alEnable");
+ qalDisable = (LPALDISABLE)GPA("alDisable");
+ qalIsEnabled = (LPALISENABLED)GPA("alIsEnabled");
+ qalGetString = (LPALGETSTRING)GPA("alGetString");
+ qalGetBooleanv = (LPALGETBOOLEANV)GPA("alGetBooleanv");
+ qalGetIntegerv = (LPALGETINTEGERV)GPA("alGetIntegerv");
+ qalGetFloatv = (LPALGETFLOATV)GPA("alGetFloatv");
+ qalGetDoublev = (LPALGETDOUBLEV)GPA("alGetDoublev");
+ qalGetBoolean = (LPALGETBOOLEAN)GPA("alGetBoolean");
+ qalGetInteger = (LPALGETINTEGER)GPA("alGetInteger");
+ qalGetFloat = (LPALGETFLOAT)GPA("alGetFloat");
+ qalGetDouble = (LPALGETDOUBLE)GPA("alGetDouble");
+ qalGetError = (LPALGETERROR)GPA("alGetError");
+ qalIsExtensionPresent = (LPALISEXTENSIONPRESENT)GPA("alIsExtensionPresent");
+ qalGetProcAddress = (LPALGETPROCADDRESS)GPA("alGetProcAddress");
+ qalGetEnumValue = (LPALGETENUMVALUE)GPA("alGetEnumValue");
+ qalListenerf = (LPALLISTENERF)GPA("alListenerf");
+ qalListener3f = (LPALLISTENER3F)GPA("alListener3f");
+ qalListenerfv = (LPALLISTENERFV)GPA("alListenerfv");
+ qalListeneri = (LPALLISTENERI)GPA("alListeneri");
+ qalGetListenerf = (LPALGETLISTENERF)GPA("alGetListenerf");
+ qalGetListener3f = (LPALGETLISTENER3F)GPA("alGetListener3f");
+ qalGetListenerfv = (LPALGETLISTENERFV)GPA("alGetListenerfv");
+ qalGetListeneri = (LPALGETLISTENERI)GPA("alGetListeneri");
+ qalGenSources = (LPALGENSOURCES)GPA("alGenSources");
+ qalDeleteSources = (LPALDELETESOURCES)GPA("alDeleteSources");
+ qalIsSource = (LPALISSOURCE)GPA("alIsSource");
+ qalSourcef = (LPALSOURCEF)GPA("alSourcef");
+ qalSource3f = (LPALSOURCE3F)GPA("alSource3f");
+ qalSourcefv = (LPALSOURCEFV)GPA("alSourcefv");
+ qalSourcei = (LPALSOURCEI)GPA("alSourcei");
+ qalGetSourcef = (LPALGETSOURCEF)GPA("alGetSourcef");
+ qalGetSource3f = (LPALGETSOURCE3F)GPA("alGetSource3f");
+ qalGetSourcefv = (LPALGETSOURCEFV)GPA("alGetSourcefv");
+ qalGetSourcei = (LPALGETSOURCEI)GPA("alGetSourcei");
+ qalSourcePlayv = (LPALSOURCEPLAYV)GPA("alSourcePlayv");
+ qalSourceStopv = (LPALSOURCESTOPV)GPA("alSourceStopv");
+ qalSourceRewindv = (LPALSOURCEREWINDV)GPA("alSourceRewindv");
+ qalSourcePausev = (LPALSOURCEPAUSEV)GPA("alSourcePausev");
+ qalSourcePlay = (LPALSOURCEPLAY)GPA("alSourcePlay");
+ qalSourceStop = (LPALSOURCESTOP)GPA("alSourceStop");
+ qalSourceRewind = (LPALSOURCEREWIND)GPA("alSourceRewind");
+ qalSourcePause = (LPALSOURCEPAUSE)GPA("alSourcePause");
+ qalSourceQueueBuffers = (LPALSOURCEQUEUEBUFFERS)GPA("alSourceQueueBuffers");
+ qalSourceUnqueueBuffers = (LPALSOURCEUNQUEUEBUFFERS)GPA("alSourceUnqueueBuffers");
+ qalGenBuffers = (LPALGENBUFFERS)GPA("alGenBuffers");
+ qalDeleteBuffers = (LPALDELETEBUFFERS)GPA("alDeleteBuffers");
+ qalIsBuffer = (LPALISBUFFER)GPA("alIsBuffer");
+ qalBufferData = (LPALBUFFERDATA)GPA("alBufferData");
+ qalGetBufferf = (LPALGETBUFFERF)GPA("alGetBufferf");
+ qalGetBufferi = (LPALGETBUFFERI)GPA("alGetBufferi");
+ qalDopplerFactor = (LPALDOPPLERFACTOR)GPA("alDopplerFactor");
+ qalSpeedOfSound = (LPALSPEEDOFSOUND)GPA("alSpeedOfSound");
+ qalDistanceModel = (LPALDISTANCEMODEL)GPA("alDistanceModel");
+
+ qalcCreateContext = (LPALCCREATECONTEXT)GPA("alcCreateContext");
+ qalcMakeContextCurrent = (LPALCMAKECONTEXTCURRENT)GPA("alcMakeContextCurrent");
+ qalcProcessContext = (LPALCPROCESSCONTEXT)GPA("alcProcessContext");
+ qalcSuspendContext = (LPALCSUSPENDCONTEXT)GPA("alcSuspendContext");
+ qalcDestroyContext = (LPALCDESTROYCONTEXT)GPA("alcDestroyContext");
+ qalcGetCurrentContext = (LPALCGETCURRENTCONTEXT)GPA("alcGetCurrentContext");
+ qalcGetContextsDevice = (LPALCGETCONTEXTSDEVICE)GPA("alcGetContextsDevice");
+ qalcOpenDevice = (LPALCOPENDEVICE)GPA("alcOpenDevice");
+ qalcCloseDevice = (LPALCCLOSEDEVICE)GPA("alcCloseDevice");
+ qalcGetError = (LPALCGETERROR)GPA("alcGetError");
+ qalcIsExtensionPresent = (LPALCISEXTENSIONPRESENT)GPA("alcIsExtensionPresent");
+ qalcGetProcAddress = (LPALCGETPROCADDRESS)GPA("alcGetProcAddress");
+ qalcGetEnumValue = (LPALCGETENUMVALUE)GPA("alcGetEnumValue");
+ qalcGetString = (LPALCGETSTRING)GPA("alcGetString");
+ qalcGetIntegerv = (LPALCGETINTEGERV)GPA("alcGetIntegerv");
+ qalcCaptureOpenDevice = (LPALCCAPTUREOPENDEVICE)GPA("alcCaptureOpenDevice");
+ qalcCaptureCloseDevice = (LPALCCAPTURECLOSEDEVICE)GPA("alcCaptureCloseDevice");
+ qalcCaptureStart = (LPALCCAPTURESTART)GPA("alcCaptureStart");
+ qalcCaptureStop = (LPALCCAPTURESTOP)GPA("alcCaptureStop");
+ qalcCaptureSamples = (LPALCCAPTURESAMPLES)GPA("alcCaptureSamples");
+
+ if(alinit_fail)
+ {
+ QAL_Shutdown();
+ Com_Printf( " One or more symbols not found\n");
+ return false;
+ }
+
+ return true;
+}
+
+/*
+=================
+QAL_Shutdown
+=================
+*/
+void QAL_Shutdown( void )
+{
+ if(OpenALLib)
+ {
+ Sys_UnloadLibrary(OpenALLib);
+ OpenALLib = NULL;
+ }
+
+ qalEnable = NULL;
+ qalDisable = NULL;
+ qalIsEnabled = NULL;
+ qalGetString = NULL;
+ qalGetBooleanv = NULL;
+ qalGetIntegerv = NULL;
+ qalGetFloatv = NULL;
+ qalGetDoublev = NULL;
+ qalGetBoolean = NULL;
+ qalGetInteger = NULL;
+ qalGetFloat = NULL;
+ qalGetDouble = NULL;
+ qalGetError = NULL;
+ qalIsExtensionPresent = NULL;
+ qalGetProcAddress = NULL;
+ qalGetEnumValue = NULL;
+ qalListenerf = NULL;
+ qalListener3f = NULL;
+ qalListenerfv = NULL;
+ qalListeneri = NULL;
+ qalGetListenerf = NULL;
+ qalGetListener3f = NULL;
+ qalGetListenerfv = NULL;
+ qalGetListeneri = NULL;
+ qalGenSources = NULL;
+ qalDeleteSources = NULL;
+ qalIsSource = NULL;
+ qalSourcef = NULL;
+ qalSource3f = NULL;
+ qalSourcefv = NULL;
+ qalSourcei = NULL;
+ qalGetSourcef = NULL;
+ qalGetSource3f = NULL;
+ qalGetSourcefv = NULL;
+ qalGetSourcei = NULL;
+ qalSourcePlayv = NULL;
+ qalSourceStopv = NULL;
+ qalSourceRewindv = NULL;
+ qalSourcePausev = NULL;
+ qalSourcePlay = NULL;
+ qalSourceStop = NULL;
+ qalSourceRewind = NULL;
+ qalSourcePause = NULL;
+ qalSourceQueueBuffers = NULL;
+ qalSourceUnqueueBuffers = NULL;
+ qalGenBuffers = NULL;
+ qalDeleteBuffers = NULL;
+ qalIsBuffer = NULL;
+ qalBufferData = NULL;
+ qalGetBufferf = NULL;
+ qalGetBufferi = NULL;
+ qalDopplerFactor = NULL;
+ qalSpeedOfSound = NULL;
+ qalDistanceModel = NULL;
+
+ qalcCreateContext = NULL;
+ qalcMakeContextCurrent = NULL;
+ qalcProcessContext = NULL;
+ qalcSuspendContext = NULL;
+ qalcDestroyContext = NULL;
+ qalcGetCurrentContext = NULL;
+ qalcGetContextsDevice = NULL;
+ qalcOpenDevice = NULL;
+ qalcCloseDevice = NULL;
+ qalcGetError = NULL;
+ qalcIsExtensionPresent = NULL;
+ qalcGetProcAddress = NULL;
+ qalcGetEnumValue = NULL;
+ qalcGetString = NULL;
+ qalcGetIntegerv = NULL;
+ qalcCaptureOpenDevice = NULL;
+ qalcCaptureCloseDevice = NULL;
+ qalcCaptureStart = NULL;
+ qalcCaptureStop = NULL;
+ qalcCaptureSamples = NULL;
+}
+#else
+bool QAL_Init(const char *libname)
+{
+ return true;
+}
+void QAL_Shutdown( void )
+{
+}
+#endif
+#endif
diff --git a/src/client/qal.h b/src/client/qal.h
new file mode 100644
index 0000000..41d6244
--- /dev/null
+++ b/src/client/qal.h
@@ -0,0 +1,252 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifndef __QAL_H__
+#define __QAL_H__
+
+#ifdef USE_LOCAL_HEADERS
+# include "AL/al.h"
+# include "AL/alc.h"
+#else
+# if defined(_MSC_VER) || defined(__APPLE__)
+// MSVC users must install the OpenAL SDK which doesn't use the AL/*.h scheme.
+// OSX framework also needs this
+# include <al.h>
+# include <alc.h>
+# else
+# include <AL/al.h>
+# include <AL/alc.h>
+# endif
+#endif
+
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+#ifdef USE_OPENAL_DLOPEN
+#define AL_NO_PROTOTYPES
+#define ALC_NO_PROTOTYPES
+#endif
+
+/* Hack to enable compiling both on OpenAL SDK and OpenAL-soft. */
+#ifndef ALC_ENUMERATE_ALL_EXT
+# define ALC_ENUMERATE_ALL_EXT 1
+# define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
+# define ALC_ALL_DEVICES_SPECIFIER 0x1013
+#endif
+
+#ifdef USE_OPENAL_DLOPEN
+extern LPALENABLE qalEnable;
+extern LPALDISABLE qalDisable;
+extern LPALISENABLED qalIsEnabled;
+extern LPALGETSTRING qalGetString;
+extern LPALGETBOOLEANV qalGetBooleanv;
+extern LPALGETINTEGERV qalGetIntegerv;
+extern LPALGETFLOATV qalGetFloatv;
+extern LPALGETDOUBLEV qalGetDoublev;
+extern LPALGETBOOLEAN qalGetBoolean;
+extern LPALGETINTEGER qalGetInteger;
+extern LPALGETFLOAT qalGetFloat;
+extern LPALGETDOUBLE qalGetDouble;
+extern LPALGETERROR qalGetError;
+extern LPALISEXTENSIONPRESENT qalIsExtensionPresent;
+extern LPALGETPROCADDRESS qalGetProcAddress;
+extern LPALGETENUMVALUE qalGetEnumValue;
+extern LPALLISTENERF qalListenerf;
+extern LPALLISTENER3F qalListener3f;
+extern LPALLISTENERFV qalListenerfv;
+extern LPALLISTENERI qalListeneri;
+extern LPALLISTENER3I qalListener3i;
+extern LPALLISTENERIV qalListeneriv;
+extern LPALGETLISTENERF qalGetListenerf;
+extern LPALGETLISTENER3F qalGetListener3f;
+extern LPALGETLISTENERFV qalGetListenerfv;
+extern LPALGETLISTENERI qalGetListeneri;
+extern LPALGETLISTENER3I qalGetListener3i;
+extern LPALGETLISTENERIV qalGetListeneriv;
+extern LPALGENSOURCES qalGenSources;
+extern LPALDELETESOURCES qalDeleteSources;
+extern LPALISSOURCE qalIsSource;
+extern LPALSOURCEF qalSourcef;
+extern LPALSOURCE3F qalSource3f;
+extern LPALSOURCEFV qalSourcefv;
+extern LPALSOURCEI qalSourcei;
+extern LPALSOURCE3I qalSource3i;
+extern LPALSOURCEIV qalSourceiv;
+extern LPALGETSOURCEF qalGetSourcef;
+extern LPALGETSOURCE3F qalGetSource3f;
+extern LPALGETSOURCEFV qalGetSourcefv;
+extern LPALGETSOURCEI qalGetSourcei;
+extern LPALGETSOURCE3I qalGetSource3i;
+extern LPALGETSOURCEIV qalGetSourceiv;
+extern LPALSOURCEPLAYV qalSourcePlayv;
+extern LPALSOURCESTOPV qalSourceStopv;
+extern LPALSOURCEREWINDV qalSourceRewindv;
+extern LPALSOURCEPAUSEV qalSourcePausev;
+extern LPALSOURCEPLAY qalSourcePlay;
+extern LPALSOURCESTOP qalSourceStop;
+extern LPALSOURCEREWIND qalSourceRewind;
+extern LPALSOURCEPAUSE qalSourcePause;
+extern LPALSOURCEQUEUEBUFFERS qalSourceQueueBuffers;
+extern LPALSOURCEUNQUEUEBUFFERS qalSourceUnqueueBuffers;
+extern LPALGENBUFFERS qalGenBuffers;
+extern LPALDELETEBUFFERS qalDeleteBuffers;
+extern LPALISBUFFER qalIsBuffer;
+extern LPALBUFFERDATA qalBufferData;
+extern LPALBUFFERF qalBufferf;
+extern LPALBUFFER3F qalBuffer3f;
+extern LPALBUFFERFV qalBufferfv;
+extern LPALBUFFERF qalBufferi;
+extern LPALBUFFER3F qalBuffer3i;
+extern LPALBUFFERFV qalBufferiv;
+extern LPALGETBUFFERF qalGetBufferf;
+extern LPALGETBUFFER3F qalGetBuffer3f;
+extern LPALGETBUFFERFV qalGetBufferfv;
+extern LPALGETBUFFERI qalGetBufferi;
+extern LPALGETBUFFER3I qalGetBuffer3i;
+extern LPALGETBUFFERIV qalGetBufferiv;
+extern LPALDOPPLERFACTOR qalDopplerFactor;
+extern LPALSPEEDOFSOUND qalSpeedOfSound;
+extern LPALDISTANCEMODEL qalDistanceModel;
+
+extern LPALCCREATECONTEXT qalcCreateContext;
+extern LPALCMAKECONTEXTCURRENT qalcMakeContextCurrent;
+extern LPALCPROCESSCONTEXT qalcProcessContext;
+extern LPALCSUSPENDCONTEXT qalcSuspendContext;
+extern LPALCDESTROYCONTEXT qalcDestroyContext;
+extern LPALCGETCURRENTCONTEXT qalcGetCurrentContext;
+extern LPALCGETCONTEXTSDEVICE qalcGetContextsDevice;
+extern LPALCOPENDEVICE qalcOpenDevice;
+extern LPALCCLOSEDEVICE qalcCloseDevice;
+extern LPALCGETERROR qalcGetError;
+extern LPALCISEXTENSIONPRESENT qalcIsExtensionPresent;
+extern LPALCGETPROCADDRESS qalcGetProcAddress;
+extern LPALCGETENUMVALUE qalcGetEnumValue;
+extern LPALCGETSTRING qalcGetString;
+extern LPALCGETINTEGERV qalcGetIntegerv;
+extern LPALCCAPTUREOPENDEVICE qalcCaptureOpenDevice;
+extern LPALCCAPTURECLOSEDEVICE qalcCaptureCloseDevice;
+extern LPALCCAPTURESTART qalcCaptureStart;
+extern LPALCCAPTURESTOP qalcCaptureStop;
+extern LPALCCAPTURESAMPLES qalcCaptureSamples;
+#else
+#define qalEnable alEnable
+#define qalDisable alDisable
+#define qalIsEnabled alIsEnabled
+#define qalGetString alGetString
+#define qalGetBooleanv alGetBooleanv
+#define qalGetIntegerv alGetIntegerv
+#define qalGetFloatv alGetFloatv
+#define qalGetDoublev alGetDoublev
+#define qalGetBoolean alGetBoolean
+#define qalGetInteger alGetInteger
+#define qalGetFloat alGetFloat
+#define qalGetDouble alGetDouble
+#define qalGetError alGetError
+#define qalIsExtensionPresent alIsExtensionPresent
+#define qalGetProcAddress alGetProcAddress
+#define qalGetEnumValue alGetEnumValue
+#define qalListenerf alListenerf
+#define qalListener3f alListener3f
+#define qalListenerfv alListenerfv
+#define qalListeneri alListeneri
+#define qalListener3i alListener3i
+#define qalListeneriv alListeneriv
+#define qalGetListenerf alGetListenerf
+#define qalGetListener3f alGetListener3f
+#define qalGetListenerfv alGetListenerfv
+#define qalGetListeneri alGetListeneri
+#define qalGetListener3i alGetListener3i
+#define qalGetListeneriv alGetListeneriv
+#define qalGenSources alGenSources
+#define qalDeleteSources alDeleteSources
+#define qalIsSource alIsSource
+#define qalSourcef alSourcef
+#define qalSource3f alSource3f
+#define qalSourcefv alSourcefv
+#define qalSourcei alSourcei
+#define qalSource3i alSource3i
+#define qalSourceiv alSourceiv
+#define qalGetSourcef alGetSourcef
+#define qalGetSource3f alGetSource3f
+#define qalGetSourcefv alGetSourcefv
+#define qalGetSourcei alGetSourcei
+#define qalGetSource3i alGetSource3i
+#define qalGetSourceiv alGetSourceiv
+#define qalSourcePlayv alSourcePlayv
+#define qalSourceStopv alSourceStopv
+#define qalSourceRewindv alSourceRewindv
+#define qalSourcePausev alSourcePausev
+#define qalSourcePlay alSourcePlay
+#define qalSourceStop alSourceStop
+#define qalSourceRewind alSourceRewind
+#define qalSourcePause alSourcePause
+#define qalSourceQueueBuffers alSourceQueueBuffers
+#define qalSourceUnqueueBuffers alSourceUnqueueBuffers
+#define qalGenBuffers alGenBuffers
+#define qalDeleteBuffers alDeleteBuffers
+#define qalIsBuffer alIsBuffer
+#define qalBufferData alBufferData
+#define qalBufferf alBufferf
+#define qalBuffer3f alBuffer3f
+#define qalBufferfv alBufferfv
+#define qalBufferi alBufferi
+#define qalBuffer3i alBuffer3i
+#define qalBufferiv alBufferiv
+#define qalGetBufferf alGetBufferf
+#define qalGetBuffer3f alGetBuffer3f
+#define qalGetBufferfv alGetBufferfv
+#define qalGetBufferi alGetBufferi
+#define qalGetBuffer3i alGetBuffer3i
+#define qalGetBufferiv alGetBufferiv
+#define qalDopplerFactor alDopplerFactor
+#define qalSpeedOfSound alSpeedOfSound
+#define qalDistanceModel alDistanceModel
+
+#define qalcCreateContext alcCreateContext
+#define qalcMakeContextCurrent alcMakeContextCurrent
+#define qalcProcessContext alcProcessContext
+#define qalcSuspendContext alcSuspendContext
+#define qalcDestroyContext alcDestroyContext
+#define qalcGetCurrentContext alcGetCurrentContext
+#define qalcGetContextsDevice alcGetContextsDevice
+#define qalcOpenDevice alcOpenDevice
+#define qalcCloseDevice alcCloseDevice
+#define qalcGetError alcGetError
+#define qalcIsExtensionPresent alcIsExtensionPresent
+#define qalcGetProcAddress alcGetProcAddress
+#define qalcGetEnumValue alcGetEnumValue
+#define qalcGetString alcGetString
+#define qalcGetIntegerv alcGetIntegerv
+#define qalcCaptureOpenDevice alcCaptureOpenDevice
+#define qalcCaptureCloseDevice alcCaptureCloseDevice
+#define qalcCaptureStart alcCaptureStart
+#define qalcCaptureStop alcCaptureStop
+#define qalcCaptureSamples alcCaptureSamples
+#endif
+
+bool QAL_Init(const char *libname);
+void QAL_Shutdown( void );
+
+#endif // __QAL_H__
diff --git a/src/client/snd_adpcm.cpp b/src/client/snd_adpcm.cpp
new file mode 100644
index 0000000..d5d9930
--- /dev/null
+++ b/src/client/snd_adpcm.cpp
@@ -0,0 +1,329 @@
+/***********************************************************
+Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/*
+** Intel/DVI ADPCM coder/decoder.
+**
+** The algorithm for this coder was taken from the IMA Compatability Project
+** proceedings, Vol 2, Number 2; May 1992.
+**
+** Version 1.2, 18-Dec-92.
+*/
+
+#include "snd_local.h"
+
+/* Intel ADPCM step variation table */
+static int indexTable[16] = {
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8,
+};
+
+static int stepsizeTable[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+
+void S_AdpcmEncode( short indata[], char outdata[], int len, struct adpcm_state *state ) {
+ short *inp; /* Input buffer pointer */
+ signed char *outp; /* output buffer pointer */
+ int val; /* Current input sample value */
+ int sign; /* Current adpcm sign bit */
+ int delta; /* Current adpcm output value */
+ int diff; /* Difference between val and sample */
+ int step; /* Stepsize */
+ int valpred; /* Predicted output value */
+ int vpdiff; /* Current change to valpred */
+ int index; /* Current step change index */
+ int outputbuffer; /* place to keep previous 4-bit value */
+ int bufferstep; /* toggle between outputbuffer/output */
+
+ outp = (signed char *)outdata;
+ inp = indata;
+
+ valpred = state->sample;
+ index = state->index;
+ step = stepsizeTable[index];
+
+ outputbuffer = 0; // quiet a compiler warning
+ bufferstep = 1;
+
+ for ( ; len > 0 ; len-- ) {
+ val = *inp++;
+
+ /* Step 1 - compute difference with previous value */
+ diff = val - valpred;
+ sign = (diff < 0) ? 8 : 0;
+ if ( sign ) diff = (-diff);
+
+ /* Step 2 - Divide and clamp */
+ /* Note:
+ ** This code *approximately* computes:
+ ** delta = diff*4/step;
+ ** vpdiff = (delta+0.5)*step/4;
+ ** but in shift step bits are dropped. The net result of this is
+ ** that even if you have fast mul/div hardware you cannot put it to
+ ** good use since the fixup would be too expensive.
+ */
+ delta = 0;
+ vpdiff = (step >> 3);
+
+ if ( diff >= step ) {
+ delta = 4;
+ diff -= step;
+ vpdiff += step;
+ }
+ step >>= 1;
+ if ( diff >= step ) {
+ delta |= 2;
+ diff -= step;
+ vpdiff += step;
+ }
+ step >>= 1;
+ if ( diff >= step ) {
+ delta |= 1;
+ vpdiff += step;
+ }
+
+ /* Step 3 - Update previous value */
+ if ( sign )
+ valpred -= vpdiff;
+ else
+ valpred += vpdiff;
+
+ /* Step 4 - Clamp previous value to 16 bits */
+ if ( valpred > 32767 )
+ valpred = 32767;
+ else if ( valpred < -32768 )
+ valpred = -32768;
+
+ /* Step 5 - Assemble value, update index and step values */
+ delta |= sign;
+
+ index += indexTable[delta];
+ if ( index < 0 ) index = 0;
+ if ( index > 88 ) index = 88;
+ step = stepsizeTable[index];
+
+ /* Step 6 - Output value */
+ if ( bufferstep ) {
+ outputbuffer = (delta << 4) & 0xf0;
+ } else {
+ *outp++ = (delta & 0x0f) | outputbuffer;
+ }
+ bufferstep = !bufferstep;
+ }
+
+ /* Output last step, if needed */
+ if ( !bufferstep )
+ *outp++ = outputbuffer;
+
+ state->sample = valpred;
+ state->index = index;
+}
+
+
+/* static */ void S_AdpcmDecode( const char indata[], short *outdata, int len, struct adpcm_state *state ) {
+ signed char *inp; /* Input buffer pointer */
+ int outp; /* output buffer pointer */
+ int sign; /* Current adpcm sign bit */
+ int delta; /* Current adpcm output value */
+ int step; /* Stepsize */
+ int valpred; /* Predicted value */
+ int vpdiff; /* Current change to valpred */
+ int index; /* Current step change index */
+ int inputbuffer; /* place to keep next 4-bit value */
+ int bufferstep; /* toggle between inputbuffer/input */
+
+ outp = 0;
+ inp = (signed char *)indata;
+
+ valpred = state->sample;
+ index = state->index;
+ step = stepsizeTable[index];
+
+ bufferstep = 0;
+ inputbuffer = 0; // quiet a compiler warning
+ for ( ; len > 0 ; len-- ) {
+
+ /* Step 1 - get the delta value */
+ if ( bufferstep ) {
+ delta = inputbuffer & 0xf;
+ } else {
+ inputbuffer = *inp++;
+ delta = (inputbuffer >> 4) & 0xf;
+ }
+ bufferstep = !bufferstep;
+
+ /* Step 2 - Find new index value (for later) */
+ index += indexTable[delta];
+ if ( index < 0 ) index = 0;
+ if ( index > 88 ) index = 88;
+
+ /* Step 3 - Separate sign and magnitude */
+ sign = delta & 8;
+ delta = delta & 7;
+
+ /* Step 4 - Compute difference and new predicted value */
+ /*
+ ** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
+ ** in adpcm_coder.
+ */
+ vpdiff = step >> 3;
+ if ( delta & 4 ) vpdiff += step;
+ if ( delta & 2 ) vpdiff += step>>1;
+ if ( delta & 1 ) vpdiff += step>>2;
+
+ if ( sign )
+ valpred -= vpdiff;
+ else
+ valpred += vpdiff;
+
+ /* Step 5 - clamp output value */
+ if ( valpred > 32767 )
+ valpred = 32767;
+ else if ( valpred < -32768 )
+ valpred = -32768;
+
+ /* Step 6 - Update step value */
+ step = stepsizeTable[index];
+
+ /* Step 7 - Output value */
+ outdata[outp] = valpred;
+ outp++;
+ }
+
+ state->sample = valpred;
+ state->index = index;
+}
+
+
+/*
+====================
+S_AdpcmMemoryNeeded
+
+Returns the amount of memory (in bytes) needed to store the samples in out internal adpcm format
+====================
+*/
+int S_AdpcmMemoryNeeded( const wavinfo_t *info ) {
+ float scale;
+ int scaledSampleCount;
+ int sampleMemory;
+ int blockCount;
+ int headerMemory;
+
+ // determine scale to convert from input sampling rate to desired sampling rate
+ scale = (float)info->rate / dma.speed;
+
+ // calc number of samples at playback sampling rate
+ scaledSampleCount = info->samples / scale;
+
+ // calc memory need to store those samples using ADPCM at 4 bits per sample
+ sampleMemory = scaledSampleCount / 2;
+
+ // calc number of sample blocks needed of PAINTBUFFER_SIZE
+ blockCount = scaledSampleCount / PAINTBUFFER_SIZE;
+ if( scaledSampleCount % PAINTBUFFER_SIZE ) {
+ blockCount++;
+ }
+
+ // calc memory needed to store the block headers
+ headerMemory = blockCount * sizeof(adpcm_state_t);
+
+ return sampleMemory + headerMemory;
+}
+
+
+/*
+====================
+S_AdpcmGetSamples
+====================
+*/
+void S_AdpcmGetSamples(sndBuffer *chunk, short *to) {
+ adpcm_state_t state;
+ byte *out;
+
+ // get the starting state from the block header
+ state.index = chunk->adpcm.index;
+ state.sample = chunk->adpcm.sample;
+
+ out = (byte *)chunk->sndChunk;
+ // get samples
+ S_AdpcmDecode((char *) out, to, SND_CHUNK_SIZE_BYTE*2, &state );
+}
+
+
+/*
+====================
+S_AdpcmEncodeSound
+====================
+*/
+void S_AdpcmEncodeSound( sfx_t *sfx, short *samples ) {
+ adpcm_state_t state;
+ int inOffset;
+ int count;
+ int n;
+ sndBuffer *newchunk, *chunk;
+ byte *out;
+
+ inOffset = 0;
+ count = sfx->soundLength;
+ state.index = 0;
+ state.sample = samples[0];
+
+ chunk = NULL;
+ while( count ) {
+ n = count;
+ if( n > SND_CHUNK_SIZE_BYTE*2 ) {
+ n = SND_CHUNK_SIZE_BYTE*2;
+ }
+
+ newchunk = SND_malloc();
+ if (sfx->soundData == NULL) {
+ sfx->soundData = newchunk;
+ } else if (chunk != NULL) {
+ chunk->next = newchunk;
+ }
+ chunk = newchunk;
+
+ // output the header
+ chunk->adpcm.index = state.index;
+ chunk->adpcm.sample = state.sample;
+
+ out = (byte *)chunk->sndChunk;
+
+ // encode the samples
+ S_AdpcmEncode( samples + inOffset, (char *) out, n, &state );
+
+ inOffset += n;
+ count -= n;
+ }
+}
diff --git a/src/client/snd_codec.cpp b/src/client/snd_codec.cpp
new file mode 100644
index 0000000..a794b90
--- /dev/null
+++ b/src/client/snd_codec.cpp
@@ -0,0 +1,239 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "client.h"
+#include "snd_codec.h"
+
+static snd_codec_t *codecs;
+
+/*
+=================
+S_CodecGetSound
+
+Opens/loads a sound, tries codec based on the sound's file extension
+then tries all supported codecs.
+=================
+*/
+static void *S_CodecGetSound(const char *filename, snd_info_t *info)
+{
+ snd_codec_t *codec;
+ snd_codec_t *orgCodec = NULL;
+ bool orgNameFailed = false;
+ char localName[ MAX_QPATH ];
+ const char *ext;
+ char altName[ MAX_QPATH ];
+ void *rtn = NULL;
+
+ Q_strncpyz(localName, filename, MAX_QPATH);
+
+ ext = COM_GetExtension(localName);
+
+ if( *ext )
+ {
+ // Look for the correct loader and use it
+ for( codec = codecs; codec; codec = codec->next )
+ {
+ if( !Q_stricmp( ext, codec->ext ) )
+ {
+ // Load
+ if( info )
+ rtn = codec->load(localName, info);
+ else
+ rtn = codec->open(localName);
+ break;
+ }
+ }
+
+ // A loader was found
+ if( codec )
+ {
+ if( !rtn )
+ {
+ // Loader failed, most likely because the file isn't there;
+ // try again without the extension
+ orgNameFailed = true;
+ orgCodec = codec;
+ COM_StripExtension( filename, localName, MAX_QPATH );
+ }
+ else
+ {
+ // Something loaded
+ return rtn;
+ }
+ }
+ }
+
+ // Try and find a suitable match using all
+ // the sound codecs supported
+ for( codec = codecs; codec; codec = codec->next )
+ {
+ if( codec == orgCodec )
+ continue;
+
+ Com_sprintf( altName, sizeof (altName), "%s.%s", localName, codec->ext );
+
+ // Load
+ if( info )
+ rtn = codec->load(altName, info);
+ else
+ rtn = codec->open(altName);
+
+ if( rtn )
+ {
+ if( orgNameFailed )
+ {
+ Com_DPrintf(S_COLOR_YELLOW "WARNING: %s not present, using %s instead\n",
+ filename, altName );
+ }
+
+ return rtn;
+ }
+ }
+
+ Com_Printf(S_COLOR_YELLOW "WARNING: Failed to %s sound %s!\n", info ? "load" : "open", filename);
+
+ return NULL;
+}
+
+/*
+=================
+S_CodecInit
+=================
+*/
+void S_CodecInit()
+{
+ codecs = NULL;
+
+#ifdef USE_CODEC_OPUS
+ S_CodecRegister(&opus_codec);
+#endif
+
+#ifdef USE_CODEC_VORBIS
+ S_CodecRegister(&ogg_codec);
+#endif
+
+// Register wav codec last so that it is always tried first when a file extension was not found
+ S_CodecRegister(&wav_codec);
+}
+
+/*
+=================
+S_CodecShutdown
+=================
+*/
+void S_CodecShutdown()
+{
+ codecs = NULL;
+}
+
+/*
+=================
+S_CodecRegister
+=================
+*/
+void S_CodecRegister(snd_codec_t *codec)
+{
+ codec->next = codecs;
+ codecs = codec;
+}
+
+/*
+=================
+S_CodecLoad
+=================
+*/
+void *S_CodecLoad(const char *filename, snd_info_t *info)
+{
+ return S_CodecGetSound(filename, info);
+}
+
+/*
+=================
+S_CodecOpenStream
+=================
+*/
+snd_stream_t *S_CodecOpenStream(const char *filename)
+{
+ return (snd_stream_t*)S_CodecGetSound(filename, NULL);
+}
+
+void S_CodecCloseStream(snd_stream_t *stream)
+{
+ stream->codec->close(stream);
+}
+
+int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
+{
+ return stream->codec->read(stream, bytes, buffer);
+}
+
+//=======================================================================
+// Util functions (used by codecs)
+
+/*
+=================
+S_CodecUtilOpen
+=================
+*/
+snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec)
+{
+ snd_stream_t *stream;
+ fileHandle_t hnd;
+ int length;
+
+ // Try to open the file
+ length = FS_FOpenFileRead(filename, &hnd, true);
+ if(!hnd)
+ {
+ Com_DPrintf("Can't read sound file %s\n", filename);
+ return NULL;
+ }
+
+ // Allocate a stream
+ stream = (snd_stream_t*)Z_Malloc(sizeof(snd_stream_t));
+ if(!stream)
+ {
+ FS_FCloseFile(hnd);
+ return NULL;
+ }
+
+ // Copy over, return
+ stream->codec = codec;
+ stream->file = hnd;
+ stream->length = length;
+ return stream;
+}
+
+/*
+=================
+S_CodecUtilClose
+=================
+*/
+void S_CodecUtilClose(snd_stream_t **stream)
+{
+ FS_FCloseFile((*stream)->file);
+ Z_Free(*stream);
+ *stream = NULL;
+}
diff --git a/src/client/snd_codec.h b/src/client/snd_codec.h
new file mode 100644
index 0000000..a5f4358
--- /dev/null
+++ b/src/client/snd_codec.h
@@ -0,0 +1,109 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifndef _SND_CODEC_H_
+#define _SND_CODEC_H_
+
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+typedef struct snd_info_s
+{
+ int rate;
+ int width;
+ int channels;
+ int samples;
+ int size;
+ int dataofs;
+} snd_info_t;
+
+typedef struct snd_codec_s snd_codec_t;
+
+typedef struct snd_stream_s
+{
+ snd_codec_t *codec;
+ fileHandle_t file;
+ snd_info_t info;
+ int length;
+ int pos;
+ void *ptr;
+} snd_stream_t;
+
+// Codec functions
+typedef void *(*CODEC_LOAD)(const char *filename, snd_info_t *info);
+typedef snd_stream_t *(*CODEC_OPEN)(const char *filename);
+typedef int (*CODEC_READ)(snd_stream_t *stream, int bytes, void *buffer);
+typedef void (*CODEC_CLOSE)(snd_stream_t *stream);
+
+// Codec data structure
+struct snd_codec_s
+{
+ const char *ext;
+ CODEC_LOAD load;
+ CODEC_OPEN open;
+ CODEC_READ read;
+ CODEC_CLOSE close;
+ snd_codec_t *next;
+};
+
+// Codec management
+void S_CodecInit( void );
+void S_CodecShutdown( void );
+void S_CodecRegister(snd_codec_t *codec);
+void *S_CodecLoad(const char *filename, snd_info_t *info);
+snd_stream_t *S_CodecOpenStream(const char *filename);
+void S_CodecCloseStream(snd_stream_t *stream);
+int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
+
+// Util functions (used by codecs)
+snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec);
+void S_CodecUtilClose(snd_stream_t **stream);
+
+// WAV Codec
+extern snd_codec_t wav_codec;
+void *S_WAV_CodecLoad(const char *filename, snd_info_t *info);
+snd_stream_t *S_WAV_CodecOpenStream(const char *filename);
+void S_WAV_CodecCloseStream(snd_stream_t *stream);
+int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
+
+// Ogg Vorbis codec
+#ifdef USE_CODEC_VORBIS
+extern snd_codec_t ogg_codec;
+void *S_OGG_CodecLoad(const char *filename, snd_info_t *info);
+snd_stream_t *S_OGG_CodecOpenStream(const char *filename);
+void S_OGG_CodecCloseStream(snd_stream_t *stream);
+int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
+#endif // USE_CODEC_VORBIS
+
+// Ogg Opus codec
+#ifdef USE_CODEC_OPUS
+extern snd_codec_t opus_codec;
+void *S_OggOpus_CodecLoad(const char *filename, snd_info_t *info);
+snd_stream_t *S_OggOpus_CodecOpenStream(const char *filename);
+void S_OggOpus_CodecCloseStream(snd_stream_t *stream);
+int S_OggOpus_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
+#endif // USE_CODEC_OPUS
+
+#endif // !_SND_CODEC_H_
diff --git a/src/client/snd_codec_ogg.cpp b/src/client/snd_codec_ogg.cpp
new file mode 100644
index 0000000..15fcd37
--- /dev/null
+++ b/src/client/snd_codec_ogg.cpp
@@ -0,0 +1,479 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
+Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// OGG support is enabled by this define
+#ifdef USE_CODEC_VORBIS
+
+// includes for the Q3 sound system
+#include "client.h"
+
+// includes for the OGG codec
+#define OV_EXCLUDE_STATIC_CALLBACKS
+#include <vorbis/vorbisfile.h>
+
+#include <cerrno>
+
+#include "snd_codec.h"
+
+// The OGG codec can return the samples in a number of different formats,
+// we use the standard signed short format.
+#define OGG_SAMPLEWIDTH 2
+
+// Q3 OGG codec
+snd_codec_t ogg_codec =
+{
+ "ogg",
+ S_OGG_CodecLoad,
+ S_OGG_CodecOpenStream,
+ S_OGG_CodecReadStream,
+ S_OGG_CodecCloseStream,
+ NULL
+};
+
+// callbacks for vobisfile
+
+// fread() replacement
+size_t S_OGG_Callback_read(void *ptr, size_t size, size_t nmemb, void *datasource)
+{
+ snd_stream_t *stream;
+ int byteSize = 0;
+ int bytesRead = 0;
+ size_t nMembRead = 0;
+
+ // check if input is valid
+ if(!ptr)
+ {
+ errno = EFAULT;
+ return 0;
+ }
+
+ if(!(size && nmemb))
+ {
+ // It's not an error, caller just wants zero bytes!
+ errno = 0;
+ return 0;
+ }
+
+ if(!datasource)
+ {
+ errno = EBADF;
+ return 0;
+ }
+
+ // we use a snd_stream_t in the generic pointer to pass around
+ stream = (snd_stream_t *) datasource;
+
+ // FS_Read does not support multi-byte elements
+ byteSize = nmemb * size;
+
+ // read it with the Q3 function FS_Read()
+ bytesRead = FS_Read(ptr, byteSize, stream->file);
+
+ // update the file position
+ stream->pos += bytesRead;
+
+ // this function returns the number of elements read not the number of bytes
+ nMembRead = bytesRead / size;
+
+ // even if the last member is only read partially
+ // it is counted as a whole in the return value
+ if(bytesRead % size)
+ {
+ nMembRead++;
+ }
+
+ return nMembRead;
+}
+
+// fseek() replacement
+int S_OGG_Callback_seek(void *datasource, ogg_int64_t offset, int whence)
+{
+ snd_stream_t *stream;
+ int retVal = 0;
+
+ // check if input is valid
+ if(!datasource)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ // snd_stream_t in the generic pointer
+ stream = (snd_stream_t *) datasource;
+
+ // we must map the whence to its Q3 counterpart
+ switch(whence)
+ {
+ case SEEK_SET :
+ {
+ // set the file position in the actual file with the Q3 function
+ retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET);
+
+ // something has gone wrong, so we return here
+ if(retVal < 0)
+ {
+ return retVal;
+ }
+
+ // keep track of file position
+ stream->pos = (int) offset;
+ break;
+ }
+
+ case SEEK_CUR :
+ {
+ // set the file position in the actual file with the Q3 function
+ retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR);
+
+ // something has gone wrong, so we return here
+ if(retVal < 0)
+ {
+ return retVal;
+ }
+
+ // keep track of file position
+ stream->pos += (int) offset;
+ break;
+ }
+
+ case SEEK_END :
+ {
+ // set the file position in the actual file with the Q3 function
+ retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_END);
+
+ // something has gone wrong, so we return here
+ if(retVal < 0)
+ {
+ return retVal;
+ }
+
+ // keep track of file position
+ stream->pos = stream->length + (int) offset;
+ break;
+ }
+
+ default :
+ {
+ // unknown whence, so we return an error
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ // stream->pos shouldn't be smaller than zero or bigger than the filesize
+ stream->pos = (stream->pos < 0) ? 0 : stream->pos;
+ stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos;
+
+ return 0;
+}
+
+// fclose() replacement
+int S_OGG_Callback_close(void *datasource)
+{
+ // we do nothing here and close all things manually in S_OGG_CodecCloseStream()
+ return 0;
+}
+
+// ftell() replacement
+long S_OGG_Callback_tell(void *datasource)
+{
+ snd_stream_t *stream;
+
+ // check if input is valid
+ if(!datasource)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ // snd_stream_t in the generic pointer
+ stream = (snd_stream_t *) datasource;
+
+ return (long) FS_FTell(stream->file);
+}
+
+// the callback structure
+const ov_callbacks S_OGG_Callbacks =
+{
+ &S_OGG_Callback_read,
+ &S_OGG_Callback_seek,
+ &S_OGG_Callback_close,
+ &S_OGG_Callback_tell
+};
+
+/*
+=================
+S_OGG_CodecOpenStream
+=================
+*/
+snd_stream_t *S_OGG_CodecOpenStream(const char *filename)
+{
+ snd_stream_t *stream;
+
+ // OGG codec control structure
+ OggVorbis_File *vf;
+
+ // some variables used to get informations about the OGG
+ vorbis_info *OGGInfo;
+ ogg_int64_t numSamples;
+
+ // check if input is valid
+ if(!filename)
+ {
+ return NULL;
+ }
+
+ // Open the stream
+ stream = S_CodecUtilOpen(filename, &ogg_codec);
+ if(!stream)
+ {
+ return NULL;
+ }
+
+ // alloctate the OggVorbis_File
+ vf = (OggVorbis_File*)Z_Malloc(sizeof(OggVorbis_File));
+ if(!vf)
+ {
+ S_CodecUtilClose(&stream);
+
+ return NULL;
+ }
+
+ // open the codec with our callbacks and stream as the generic pointer
+ if(ov_open_callbacks(stream, vf, NULL, 0, S_OGG_Callbacks) != 0)
+ {
+ Z_Free(vf);
+
+ S_CodecUtilClose(&stream);
+
+ return NULL;
+ }
+
+ // the stream must be seekable
+ if(!ov_seekable(vf))
+ {
+ ov_clear(vf);
+
+ Z_Free(vf);
+
+ S_CodecUtilClose(&stream);
+
+ return NULL;
+ }
+
+ // we only support OGGs with one substream
+ if(ov_streams(vf) != 1)
+ {
+ ov_clear(vf);
+
+ Z_Free(vf);
+
+ S_CodecUtilClose(&stream);
+
+ return NULL;
+ }
+
+ // get the info about channels and rate
+ OGGInfo = ov_info(vf, 0);
+ if(!OGGInfo)
+ {
+ ov_clear(vf);
+
+ Z_Free(vf);
+
+ S_CodecUtilClose(&stream);
+
+ return NULL;
+ }
+
+ // get the number of sample-frames in the OGG
+ numSamples = ov_pcm_total(vf, 0);
+
+ // fill in the info-structure in the stream
+ stream->info.rate = OGGInfo->rate;
+ stream->info.width = OGG_SAMPLEWIDTH;
+ stream->info.channels = OGGInfo->channels;
+ stream->info.samples = numSamples;
+ stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
+ stream->info.dataofs = 0;
+
+ // We use stream->pos for the file pointer in the compressed ogg file
+ stream->pos = 0;
+
+ // We use the generic pointer in stream for the OGG codec control structure
+ stream->ptr = vf;
+
+ return stream;
+}
+
+/*
+=================
+S_OGG_CodecCloseStream
+=================
+*/
+void S_OGG_CodecCloseStream(snd_stream_t *stream)
+{
+ // check if input is valid
+ if(!stream)
+ {
+ return;
+ }
+
+ // let the OGG codec cleanup its stuff
+ ov_clear((OggVorbis_File *) stream->ptr);
+
+ // free the OGG codec control struct
+ Z_Free(stream->ptr);
+
+ // close the stream
+ S_CodecUtilClose(&stream);
+}
+
+/*
+=================
+S_OGG_CodecReadStream
+=================
+*/
+int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
+{
+ // buffer handling
+ int bytesRead, bytesLeft, c;
+ char *bufPtr;
+
+ // Bitstream for the decoder
+ int BS = 0;
+
+ // big endian machines want their samples in big endian order
+ int IsBigEndian = 0;
+
+# ifdef Q3_BIG_ENDIAN
+ IsBigEndian = 1;
+# endif // Q3_BIG_ENDIAN
+
+ // check if input is valid
+ if(!(stream && buffer))
+ {
+ return 0;
+ }
+
+ if(bytes <= 0)
+ {
+ return 0;
+ }
+
+ bytesRead = 0;
+ bytesLeft = bytes;
+ bufPtr = (char*)buffer;
+
+ // cycle until we have the requested or all available bytes read
+ while(-1)
+ {
+ // read some bytes from the OGG codec
+ c = ov_read((OggVorbis_File *) stream->ptr, bufPtr, bytesLeft, IsBigEndian, OGG_SAMPLEWIDTH, 1, &BS);
+
+ // no more bytes are left
+ if(c <= 0)
+ {
+ break;
+ }
+
+ bytesRead += c;
+ bytesLeft -= c;
+ bufPtr += c;
+
+ // we have enough bytes
+ if(bytesLeft <= 0)
+ {
+ break;
+ }
+ }
+
+ return bytesRead;
+}
+
+/*
+=====================================================================
+S_OGG_CodecLoad
+
+We handle S_OGG_CodecLoad as a special case of the streaming functions
+where we read the whole stream at once.
+======================================================================
+*/
+void *S_OGG_CodecLoad(const char *filename, snd_info_t *info)
+{
+ snd_stream_t *stream;
+ byte *buffer;
+ int bytesRead;
+
+ // check if input is valid
+ if(!(filename && info))
+ {
+ return NULL;
+ }
+
+ // open the file as a stream
+ stream = S_OGG_CodecOpenStream(filename);
+ if(!stream)
+ {
+ return NULL;
+ }
+
+ // copy over the info
+ info->rate = stream->info.rate;
+ info->width = stream->info.width;
+ info->channels = stream->info.channels;
+ info->samples = stream->info.samples;
+ info->size = stream->info.size;
+ info->dataofs = stream->info.dataofs;
+
+ // allocate a buffer
+ // this buffer must be free-ed by the caller of this function
+ buffer = (byte*)Hunk_AllocateTempMemory(info->size);
+ if(!buffer)
+ {
+ S_OGG_CodecCloseStream(stream);
+
+ return NULL;
+ }
+
+ // fill the buffer
+ bytesRead = S_OGG_CodecReadStream(stream, info->size, buffer);
+
+ // we don't even have read a single byte
+ if(bytesRead <= 0)
+ {
+ Hunk_FreeTempMemory(buffer);
+ S_OGG_CodecCloseStream(stream);
+
+ return NULL;
+ }
+
+ S_OGG_CodecCloseStream(stream);
+
+ return buffer;
+}
+
+#endif // USE_CODEC_VORBIS
diff --git a/src/client/snd_codec_opus.cpp b/src/client/snd_codec_opus.cpp
new file mode 100644
index 0000000..a8ffba5
--- /dev/null
+++ b/src/client/snd_codec_opus.cpp
@@ -0,0 +1,452 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
+Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// Ogg Opus support is enabled by this define
+#ifdef USE_CODEC_OPUS
+
+// includes for the Q3 sound system
+#include "client.h"
+
+// includes for the Ogg Opus codec
+#include <opusfile.h>
+
+#include <cerrno>
+
+#include "snd_codec.h"
+
+// samples are 16 bit
+#define OPUS_SAMPLEWIDTH 2
+
+// Q3 Ogg Opus codec
+snd_codec_t opus_codec =
+{
+ "opus",
+ S_OggOpus_CodecLoad,
+ S_OggOpus_CodecOpenStream,
+ S_OggOpus_CodecReadStream,
+ S_OggOpus_CodecCloseStream,
+ NULL
+};
+
+// callbacks for opusfile
+
+// fread() replacement
+int S_OggOpus_Callback_read(void *datasource, unsigned char *ptr, int size )
+{
+ snd_stream_t *stream;
+ int bytesRead = 0;
+
+ // check if input is valid
+ if(!ptr)
+ {
+ errno = EFAULT;
+ return -1;
+ }
+
+ if(!size)
+ {
+ // It's not an error, caller just wants zero bytes!
+ errno = 0;
+ return 0;
+ }
+
+ if (size < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(!datasource)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ // we use a snd_stream_t in the generic pointer to pass around
+ stream = (snd_stream_t *) datasource;
+
+ // read it with the Q3 function FS_Read()
+ bytesRead = FS_Read(ptr, size, stream->file);
+
+ // update the file position
+ stream->pos += bytesRead;
+
+ return bytesRead;
+}
+
+// fseek() replacement
+int S_OggOpus_Callback_seek(void *datasource, opus_int64 offset, int whence)
+{
+ snd_stream_t *stream;
+ int retVal = 0;
+
+ // check if input is valid
+ if(!datasource)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ // snd_stream_t in the generic pointer
+ stream = (snd_stream_t *) datasource;
+
+ // we must map the whence to its Q3 counterpart
+ switch(whence)
+ {
+ case SEEK_SET :
+ {
+ // set the file position in the actual file with the Q3 function
+ retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET);
+
+ // something has gone wrong, so we return here
+ if(retVal < 0)
+ {
+ return retVal;
+ }
+
+ // keep track of file position
+ stream->pos = (int) offset;
+ break;
+ }
+
+ case SEEK_CUR :
+ {
+ // set the file position in the actual file with the Q3 function
+ retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR);
+
+ // something has gone wrong, so we return here
+ if(retVal < 0)
+ {
+ return retVal;
+ }
+
+ // keep track of file position
+ stream->pos += (int) offset;
+ break;
+ }
+
+ case SEEK_END :
+ {
+ // set the file position in the actual file with the Q3 function
+ retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_END);
+
+ // something has gone wrong, so we return here
+ if(retVal < 0)
+ {
+ return retVal;
+ }
+
+ // keep track of file position
+ stream->pos = stream->length + (int) offset;
+ break;
+ }
+
+ default :
+ {
+ // unknown whence, so we return an error
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ // stream->pos shouldn't be smaller than zero or bigger than the filesize
+ stream->pos = (stream->pos < 0) ? 0 : stream->pos;
+ stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos;
+
+ return 0;
+}
+
+// fclose() replacement
+int S_OggOpus_Callback_close(void *datasource)
+{
+ // we do nothing here and close all things manually in S_OggOpus_CodecCloseStream()
+ return 0;
+}
+
+// ftell() replacement
+opus_int64 S_OggOpus_Callback_tell(void *datasource)
+{
+ snd_stream_t *stream;
+
+ // check if input is valid
+ if(!datasource)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ // snd_stream_t in the generic pointer
+ stream = (snd_stream_t *) datasource;
+
+ return (opus_int64) FS_FTell(stream->file);
+}
+
+// the callback structure
+const OpusFileCallbacks S_OggOpus_Callbacks =
+{
+ &S_OggOpus_Callback_read,
+ &S_OggOpus_Callback_seek,
+ &S_OggOpus_Callback_tell,
+ &S_OggOpus_Callback_close
+};
+
+/*
+=================
+S_OggOpus_CodecOpenStream
+=================
+*/
+snd_stream_t *S_OggOpus_CodecOpenStream(const char *filename)
+{
+ snd_stream_t *stream;
+
+ // Opus codec control structure
+ OggOpusFile *of;
+
+ // some variables used to get informations about the file
+ const OpusHead *opusInfo;
+ ogg_int64_t numSamples;
+
+ // check if input is valid
+ if(!filename)
+ {
+ return NULL;
+ }
+
+ // Open the stream
+ stream = S_CodecUtilOpen(filename, &opus_codec);
+ if(!stream)
+ {
+ return NULL;
+ }
+
+ // open the codec with our callbacks and stream as the generic pointer
+ of = op_open_callbacks(stream, &S_OggOpus_Callbacks, NULL, 0, NULL );
+ if (!of)
+ {
+ S_CodecUtilClose(&stream);
+
+ return NULL;
+ }
+
+ // the stream must be seekable
+ if(!op_seekable(of))
+ {
+ op_free(of);
+
+ S_CodecUtilClose(&stream);
+
+ return NULL;
+ }
+
+ // get the info about channels and rate
+ opusInfo = op_head(of, -1);
+ if(!opusInfo)
+ {
+ op_free(of);
+
+ S_CodecUtilClose(&stream);
+
+ return NULL;
+ }
+
+ if(opusInfo->stream_count != 1)
+ {
+ op_free(of);
+
+ S_CodecUtilClose(&stream);
+
+ Com_Printf("Only Ogg Opus files with one stream are support\n");
+ return NULL;
+ }
+
+ if(opusInfo->channel_count != 1 && opusInfo->channel_count != 2)
+ {
+ op_free(of);
+
+ S_CodecUtilClose(&stream);
+
+ Com_Printf("Only mono and stereo Ogg Opus files are supported\n");
+ return NULL;
+ }
+
+ // get the number of sample-frames in the file
+ numSamples = op_pcm_total(of, -1);
+
+ // fill in the info-structure in the stream
+ stream->info.rate = 48000;
+ stream->info.width = OPUS_SAMPLEWIDTH;
+ stream->info.channels = opusInfo->channel_count;
+ stream->info.samples = numSamples;
+ stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
+ stream->info.dataofs = 0;
+
+ // We use stream->pos for the file pointer in the compressed ogg file
+ stream->pos = 0;
+
+ // We use the generic pointer in stream for the opus codec control structure
+ stream->ptr = of;
+
+ return stream;
+}
+
+/*
+=================
+S_OggOpus_CodecCloseStream
+=================
+*/
+void S_OggOpus_CodecCloseStream(snd_stream_t *stream)
+{
+ // check if input is valid
+ if(!stream)
+ {
+ return;
+ }
+
+ // let the opus codec cleanup its stuff
+ op_free((OggOpusFile *) stream->ptr);
+
+ // close the stream
+ S_CodecUtilClose(&stream);
+}
+
+/*
+=================
+S_OggOpus_CodecReadStream
+=================
+*/
+int S_OggOpus_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
+{
+ // buffer handling
+ int samplesRead, samplesLeft, c;
+ opus_int16 *bufPtr;
+
+ // check if input is valid
+ if(!(stream && buffer))
+ {
+ return 0;
+ }
+
+ if(bytes <= 0)
+ {
+ return 0;
+ }
+
+ samplesRead = 0;
+ samplesLeft = bytes / stream->info.channels / stream->info.width;
+ bufPtr = (opus_int16*)buffer;
+
+ if(samplesLeft <= 0)
+ {
+ return 0;
+ }
+
+ // cycle until we have the requested or all available bytes read
+ while(-1)
+ {
+ // read some samples from the opus codec
+ c = op_read((OggOpusFile *) stream->ptr, bufPtr + samplesRead * stream->info.channels, samplesLeft * stream->info.channels, NULL);
+
+ // no more samples are left
+ if(c <= 0)
+ {
+ break;
+ }
+
+ samplesRead += c;
+ samplesLeft -= c;
+
+ // we have enough samples
+ if(samplesLeft <= 0)
+ {
+ break;
+ }
+ }
+
+ return samplesRead * stream->info.channels * stream->info.width;
+}
+
+/*
+=====================================================================
+S_OggOpus_CodecLoad
+
+We handle S_OggOpus_CodecLoad as a special case of the streaming functions
+where we read the whole stream at once.
+======================================================================
+*/
+void *S_OggOpus_CodecLoad(const char *filename, snd_info_t *info)
+{
+ snd_stream_t *stream;
+ byte *buffer;
+ int bytesRead;
+
+ // check if input is valid
+ if(!(filename && info))
+ {
+ return NULL;
+ }
+
+ // open the file as a stream
+ stream = S_OggOpus_CodecOpenStream(filename);
+ if(!stream)
+ {
+ return NULL;
+ }
+
+ // copy over the info
+ info->rate = stream->info.rate;
+ info->width = stream->info.width;
+ info->channels = stream->info.channels;
+ info->samples = stream->info.samples;
+ info->size = stream->info.size;
+ info->dataofs = stream->info.dataofs;
+
+ // allocate a buffer
+ // this buffer must be free-ed by the caller of this function
+ buffer = (byte*)Hunk_AllocateTempMemory(info->size);
+ if(!buffer)
+ {
+ S_OggOpus_CodecCloseStream(stream);
+
+ return NULL;
+ }
+
+ // fill the buffer
+ bytesRead = S_OggOpus_CodecReadStream(stream, info->size, buffer);
+
+ // we don't even have read a single byte
+ if(bytesRead <= 0)
+ {
+ Hunk_FreeTempMemory(buffer);
+ S_OggOpus_CodecCloseStream(stream);
+
+ return NULL;
+ }
+
+ S_OggOpus_CodecCloseStream(stream);
+
+ return buffer;
+}
+
+#endif // USE_CODEC_OPUS
diff --git a/src/client/snd_codec_wav.cpp b/src/client/snd_codec_wav.cpp
new file mode 100644
index 0000000..a4016e2
--- /dev/null
+++ b/src/client/snd_codec_wav.cpp
@@ -0,0 +1,293 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "client.h"
+#include "snd_codec.h"
+
+/*
+=================
+FGetLittleLong
+=================
+*/
+static int FGetLittleLong( fileHandle_t f ) {
+ int v;
+
+ FS_Read( &v, sizeof(v), f );
+
+ return LittleLong( v);
+}
+
+/*
+=================
+FGetLittleShort
+=================
+*/
+static short FGetLittleShort( fileHandle_t f ) {
+ short v;
+
+ FS_Read( &v, sizeof(v), f );
+
+ return LittleShort( v);
+}
+
+/*
+=================
+S_ReadChunkInfo
+=================
+*/
+static int S_ReadChunkInfo(fileHandle_t f, char *name)
+{
+ int len, r;
+
+ name[4] = 0;
+
+ r = FS_Read(name, 4, f);
+ if(r != 4)
+ return -1;
+
+ len = FGetLittleLong(f);
+ if( len < 0 ) {
+ Com_Printf( S_COLOR_YELLOW "WARNING: Negative chunk length\n" );
+ return -1;
+ }
+
+ return len;
+}
+
+/*
+=================
+S_FindRIFFChunk
+
+Returns the length of the data in the chunk, or -1 if not found
+=================
+*/
+static int S_FindRIFFChunk( fileHandle_t f, const char *chunk ) {
+ char name[5];
+ int len;
+
+ while( ( len = S_ReadChunkInfo(f, name) ) >= 0 )
+ {
+ // If this is the right chunk, return
+ if( !Q_strncmp( name, chunk, 4 ) )
+ return len;
+
+ len = PAD( len, 2 );
+
+ // Not the right chunk - skip it
+ FS_Seek( f, len, FS_SEEK_CUR );
+ }
+
+ return -1;
+}
+
+/*
+=================
+S_ByteSwapRawSamples
+=================
+*/
+static void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data ) {
+ int i;
+
+ if ( width != 2 ) {
+ return;
+ }
+ if ( LittleShort( 256 ) == 256 ) {
+ return;
+ }
+
+ if ( s_channels == 2 ) {
+ samples <<= 1;
+ }
+ for ( i = 0 ; i < samples ; i++ ) {
+ ((short *)data)[i] = LittleShort( ((short *)data)[i] );
+ }
+}
+
+/*
+=================
+S_ReadRIFFHeader
+=================
+*/
+static bool S_ReadRIFFHeader(fileHandle_t file, snd_info_t *info)
+{
+ char dump[16];
+ int bits;
+ int fmtlen = 0;
+
+ // skip the riff wav header
+ FS_Read(dump, 12, file);
+
+ // Scan for the format chunk
+ if((fmtlen = S_FindRIFFChunk(file, "fmt ")) < 0)
+ {
+ Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"fmt\" chunk\n");
+ return false;
+ }
+
+ // Save the parameters
+ FGetLittleShort(file); // wav_format
+ info->channels = FGetLittleShort(file);
+ info->rate = FGetLittleLong(file);
+ FGetLittleLong(file);
+ FGetLittleShort(file);
+ bits = FGetLittleShort(file);
+
+ if( bits < 8 )
+ {
+ Com_Printf( S_COLOR_RED "ERROR: Less than 8 bit sound is not supported\n");
+ return false;
+ }
+
+ info->width = bits / 8;
+ info->dataofs = 0;
+
+ // Skip the rest of the format chunk if required
+ if(fmtlen > 16)
+ {
+ fmtlen -= 16;
+ FS_Seek( file, fmtlen, FS_SEEK_CUR );
+ }
+
+ // Scan for the data chunk
+ if( (info->size = S_FindRIFFChunk(file, "data")) < 0)
+ {
+ Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"data\" chunk\n");
+ return false;
+ }
+ info->samples = (info->size / info->width) / info->channels;
+
+ return true;
+}
+
+// WAV codec
+snd_codec_t wav_codec =
+{
+ "wav",
+ S_WAV_CodecLoad,
+ S_WAV_CodecOpenStream,
+ S_WAV_CodecReadStream,
+ S_WAV_CodecCloseStream,
+ NULL
+};
+
+/*
+=================
+S_WAV_CodecLoad
+=================
+*/
+void *S_WAV_CodecLoad(const char *filename, snd_info_t *info)
+{
+ fileHandle_t file;
+ void *buffer;
+
+ // Try to open the file
+ FS_FOpenFileRead(filename, &file, true);
+ if(!file)
+ {
+ return NULL;
+ }
+
+ // Read the RIFF header
+ if(!S_ReadRIFFHeader(file, info))
+ {
+ FS_FCloseFile(file);
+ Com_Printf( S_COLOR_RED "ERROR: Incorrect/unsupported format in \"%s\"\n",
+ filename);
+ return NULL;
+ }
+
+ // Allocate some memory
+ buffer = Hunk_AllocateTempMemory(info->size);
+ if(!buffer)
+ {
+ FS_FCloseFile(file);
+ Com_Printf( S_COLOR_RED "ERROR: Out of memory reading \"%s\"\n",
+ filename);
+ return NULL;
+ }
+
+ // Read, byteswap
+ FS_Read(buffer, info->size, file);
+ S_ByteSwapRawSamples(info->samples, info->width, info->channels, (byte *)buffer);
+
+ // Close and return
+ FS_FCloseFile(file);
+ return buffer;
+}
+
+/*
+=================
+S_WAV_CodecOpenStream
+=================
+*/
+snd_stream_t *S_WAV_CodecOpenStream(const char *filename)
+{
+ snd_stream_t *rv;
+
+ // Open
+ rv = S_CodecUtilOpen(filename, &wav_codec);
+ if(!rv)
+ return NULL;
+
+ // Read the RIFF header
+ if(!S_ReadRIFFHeader(rv->file, &rv->info))
+ {
+ S_CodecUtilClose(&rv);
+ return NULL;
+ }
+
+ return rv;
+}
+
+/*
+=================
+S_WAV_CodecCloseStream
+=================
+*/
+void S_WAV_CodecCloseStream(snd_stream_t *stream)
+{
+ S_CodecUtilClose(&stream);
+}
+
+/*
+=================
+S_WAV_CodecReadStream
+=================
+*/
+int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
+{
+ int remaining = stream->info.size - stream->pos;
+ int samples;
+
+ if(remaining <= 0)
+ return 0;
+ if(bytes > remaining)
+ bytes = remaining;
+ stream->pos += bytes;
+ samples = (bytes / stream->info.width) / stream->info.channels;
+ FS_Read(buffer, bytes, stream->file);
+ S_ByteSwapRawSamples(samples, stream->info.width, stream->info.channels, (byte*)buffer);
+ return bytes;
+}
diff --git a/src/client/snd_dma.cpp b/src/client/snd_dma.cpp
new file mode 100644
index 0000000..bef2b69
--- /dev/null
+++ b/src/client/snd_dma.cpp
@@ -0,0 +1,1644 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+/*****************************************************************************
+ * name: snd_dma.c
+ *
+ * desc: main control for any streaming sound output device
+ *
+ * $Archive: /MissionPack/code/client/snd_dma.c $
+ *
+ *****************************************************************************/
+
+#include "snd_local.h"
+#include "snd_codec.h"
+#include "client.h"
+
+void S_Update_( void );
+void S_Base_StopAllSounds(void);
+void S_Base_StopBackgroundTrack( void );
+
+snd_stream_t *s_backgroundStream = NULL;
+static char s_backgroundLoop[MAX_QPATH];
+//static char s_backgroundMusic[MAX_QPATH]; //TTimo: unused
+
+
+// =======================================================================
+// Internal sound data & structures
+// =======================================================================
+
+// only begin attenuating sound volumes when outside the FULLVOLUME range
+#define SOUND_FULLVOLUME 80
+
+#define SOUND_ATTENUATE 0.0008f
+
+channel_t s_channels[MAX_CHANNELS];
+channel_t loop_channels[MAX_CHANNELS];
+int numLoopChannels;
+
+static bool s_soundStarted;
+static bool s_soundMuted;
+
+dma_t dma;
+
+static int listener_number;
+static vec3_t listener_origin;
+static vec3_t listener_axis[3];
+
+int s_soundtime; // sample PAIRS
+int s_paintedtime; // sample PAIRS
+
+// MAX_SFX may be larger than MAX_SOUNDS because
+// of custom player sounds
+#define MAX_SFX 4096
+sfx_t s_knownSfx[MAX_SFX];
+int s_numSfx = 0;
+
+#define LOOP_HASH 128
+static sfx_t *sfxHash[LOOP_HASH];
+
+cvar_t *s_testsound;
+cvar_t *s_show;
+cvar_t *s_mixahead;
+cvar_t *s_mixPreStep;
+
+static loopSound_t loopSounds[MAX_GENTITIES];
+static channel_t *freelist = NULL;
+
+int s_rawend[MAX_RAW_STREAMS];
+portable_samplepair_t s_rawsamples[MAX_RAW_STREAMS][MAX_RAW_SAMPLES];
+
+
+// ====================================================================
+// User-setable variables
+// ====================================================================
+
+
+void S_Base_SoundInfo(void) {
+ Com_Printf("----- Sound Info -----\n" );
+ if (!s_soundStarted) {
+ Com_Printf ("sound system not started\n");
+ } else {
+ Com_Printf("%5d stereo\n", dma.channels - 1);
+ Com_Printf("%5d samples\n", dma.samples);
+ Com_Printf("%5d samplebits\n", dma.samplebits);
+ Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
+ Com_Printf("%5d speed\n", dma.speed);
+ Com_Printf("%p dma buffer\n", dma.buffer);
+ if ( s_backgroundStream ) {
+ Com_Printf("Background file: %s\n", s_backgroundLoop );
+ } else {
+ Com_Printf("No background file.\n" );
+ }
+
+ }
+ Com_Printf("----------------------\n" );
+}
+
+
+#ifdef USE_VOIP
+static
+void S_Base_StartCapture( void )
+{
+ // !!! FIXME: write me.
+}
+
+static
+int S_Base_AvailableCaptureSamples( void )
+{
+ // !!! FIXME: write me.
+ return 0;
+}
+
+static
+void S_Base_Capture( int samples, byte *data )
+{
+ // !!! FIXME: write me.
+}
+
+static
+void S_Base_StopCapture( void )
+{
+ // !!! FIXME: write me.
+}
+
+static
+void S_Base_MasterGain( float val )
+{
+ // !!! FIXME: write me.
+}
+#endif
+
+
+
+/*
+=================
+S_Base_SoundList
+=================
+*/
+void S_Base_SoundList( void ) {
+ int i;
+ sfx_t *sfx;
+ int size, total;
+ char type[4][16];
+ char mem[2][16];
+
+ strcpy(type[0], "16bit");
+ strcpy(type[1], "adpcm");
+ strcpy(type[2], "daub4");
+ strcpy(type[3], "mulaw");
+ strcpy(mem[0], "paged out");
+ strcpy(mem[1], "resident ");
+ total = 0;
+ for (sfx=s_knownSfx, i=0 ; i<s_numSfx ; i++, sfx++) {
+ size = sfx->soundLength;
+ total += size;
+ Com_Printf("%6i[%s] : %s[%s]\n", size, type[sfx->soundCompressionMethod],
+ sfx->soundName, mem[sfx->inMemory] );
+ }
+ Com_Printf ("Total resident: %i\n", total);
+ S_DisplayFreeMemory();
+}
+
+
+
+void S_ChannelFree(channel_t *v) {
+ v->thesfx = NULL;
+ *(channel_t **)v = freelist;
+ freelist = (channel_t*)v;
+}
+
+channel_t* S_ChannelMalloc( void ) {
+ channel_t *v;
+ if (freelist == NULL) {
+ return NULL;
+ }
+ v = freelist;
+ freelist = *(channel_t **)freelist;
+ v->allocTime = Com_Milliseconds();
+ return v;
+}
+
+void S_ChannelSetup( void ) {
+ channel_t *p, *q;
+
+ // clear all the sounds so they don't
+ ::memset( s_channels, 0, sizeof( s_channels ) );
+
+ p = s_channels;;
+ q = p + MAX_CHANNELS;
+ while (--q > p) {
+ *(channel_t **)q = q-1;
+ }
+
+ *(channel_t **)q = NULL;
+ freelist = p + MAX_CHANNELS - 1;
+ Com_DPrintf("Channel memory manager started\n");
+}
+
+
+
+// =======================================================================
+// Load a sound
+// =======================================================================
+
+/*
+================
+return a hash value for the sfx name
+================
+*/
+static long S_HashSFXName(const char *name) {
+ int i;
+ long hash;
+ char letter;
+
+ hash = 0;
+ i = 0;
+ while (name[i] != '\0') {
+ letter = tolower(name[i]);
+ if (letter =='.') break; // don't include extension
+ if (letter =='\\') letter = '/'; // damn path names
+ hash+=(long)(letter)*(i+119);
+ i++;
+ }
+ hash &= (LOOP_HASH-1);
+ return hash;
+}
+
+/*
+==================
+S_FindName
+
+Will allocate a new sfx if it isn't found
+==================
+*/
+static sfx_t *S_FindName( const char *name ) {
+ int i;
+ int hash;
+
+ sfx_t *sfx;
+
+ if (!name) {
+ Com_Error(ERR_FATAL, "Sound name is NULL");
+ }
+
+ if (!name[0]) {
+ Com_Printf( S_COLOR_YELLOW "WARNING: Sound name is empty\n" );
+ return NULL;
+ }
+
+ if (strlen(name) >= MAX_QPATH) {
+ Com_Printf( S_COLOR_YELLOW "WARNING: Sound name is too long: %s\n", name );
+ return NULL;
+ }
+
+ if (name[0] == '*') {
+ Com_Printf( S_COLOR_YELLOW "WARNING: Tried to load player sound directly: %s\n", name );
+ return NULL;
+ }
+
+ hash = S_HashSFXName(name);
+
+ sfx = sfxHash[hash];
+ // see if already loaded
+ while (sfx) {
+ if (!Q_stricmp(sfx->soundName, name) ) {
+ return sfx;
+ }
+ sfx = sfx->next;
+ }
+
+ // find a free sfx
+ for (i=0 ; i < s_numSfx ; i++) {
+ if (!s_knownSfx[i].soundName[0]) {
+ break;
+ }
+ }
+
+ if (i == s_numSfx) {
+ if (s_numSfx == MAX_SFX) {
+ Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
+ }
+ s_numSfx++;
+ }
+
+ sfx = &s_knownSfx[i];
+ ::memset (sfx, 0, sizeof(*sfx));
+ strcpy (sfx->soundName, name);
+
+ sfx->next = sfxHash[hash];
+ sfxHash[hash] = sfx;
+
+ return sfx;
+}
+
+/*
+=================
+S_DefaultSound
+=================
+*/
+void S_DefaultSound( sfx_t *sfx ) {
+
+ int i;
+
+ sfx->soundLength = 512;
+ sfx->soundData = SND_malloc();
+ sfx->soundData->next = NULL;
+
+
+ for ( i = 0 ; i < sfx->soundLength ; i++ ) {
+ sfx->soundData->sndChunk[i] = i;
+ }
+}
+
+/*
+===================
+S_DisableSounds
+
+Disables sounds until the next S_BeginRegistration.
+This is called when the hunk is cleared and the sounds
+are no longer valid.
+===================
+*/
+void S_Base_DisableSounds( void ) {
+ S_Base_StopAllSounds();
+ s_soundMuted = true;
+}
+
+/*
+==================
+S_RegisterSound
+
+Creates a default buzz sound if the file can't be loaded
+==================
+*/
+sfxHandle_t S_Base_RegisterSound( const char *name, bool compressed ) {
+ sfx_t *sfx;
+
+ compressed = false;
+ if (!s_soundStarted) {
+ return 0;
+ }
+
+ sfx = S_FindName( name );
+ if ( !sfx ) {
+ return 0;
+ }
+
+ if ( sfx->soundData ) {
+ if ( sfx->defaultSound ) {
+ Com_Printf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName );
+ return 0;
+ }
+ return sfx - s_knownSfx;
+ }
+
+ sfx->inMemory = false;
+ sfx->soundCompressed = compressed;
+
+ S_memoryLoad(sfx);
+
+ if ( sfx->defaultSound ) {
+ Com_Printf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName );
+ return 0;
+ }
+
+ return sfx - s_knownSfx;
+}
+
+/*
+==================
+S_Base_SoundDuration
+==================
+*/
+static int S_Base_SoundDuration( sfxHandle_t handle ) {
+ if ( handle < 0 || handle >= s_numSfx ) {
+ Com_Printf( S_COLOR_YELLOW "S_Base_SoundDuration: handle %i out of range\n", handle );
+ return 0;
+ }
+ return s_knownSfx[ handle ].duration;
+}
+
+
+
+/*
+=====================
+S_BeginRegistration
+
+=====================
+*/
+void S_Base_BeginRegistration( void ) {
+ s_soundMuted = false; // we can play again
+
+ if (s_numSfx == 0) {
+ SND_setup();
+
+ ::memset(s_knownSfx, '\0', sizeof(s_knownSfx));
+ ::memset(sfxHash, '\0', sizeof(sfx_t *) * LOOP_HASH);
+
+ S_Base_RegisterSound("sound/feedback/hit.wav", false); // changed to a sound in baseq3
+ }
+}
+
+void S_memoryLoad(sfx_t *sfx) {
+ // load the sound file
+ if ( !S_LoadSound ( sfx ) ) {
+// Com_Printf( S_COLOR_YELLOW "WARNING: couldn't load sound: %s\n", sfx->soundName );
+ sfx->defaultSound = true;
+ }
+ sfx->inMemory = true;
+}
+
+//=============================================================================
+
+/*
+=================
+S_SpatializeOrigin
+
+Used for spatializing s_channels
+=================
+*/
+void S_SpatializeOrigin (vec3_t origin, int master_vol, int *left_vol, int *right_vol)
+{
+ vec_t dot;
+ vec_t dist;
+ vec_t lscale, rscale, scale;
+ vec3_t source_vec;
+ vec3_t vec;
+
+ const float dist_mult = SOUND_ATTENUATE;
+
+ // calculate stereo seperation and distance attenuation
+ VectorSubtract(origin, listener_origin, source_vec);
+
+ dist = VectorNormalize(source_vec);
+ dist -= SOUND_FULLVOLUME;
+ if (dist < 0)
+ dist = 0; // close enough to be at full volume
+ dist *= dist_mult; // different attenuation levels
+
+ VectorRotate( source_vec, listener_axis, vec );
+
+ dot = -vec[1];
+
+ if (dma.channels == 1)
+ { // no attenuation = no spatialization
+ rscale = 1.0;
+ lscale = 1.0;
+ }
+ else
+ {
+ rscale = 0.5 * (1.0 + dot);
+ lscale = 0.5 * (1.0 - dot);
+ if ( rscale < 0 ) {
+ rscale = 0;
+ }
+ if ( lscale < 0 ) {
+ lscale = 0;
+ }
+ }
+
+ // add in distance effect
+ scale = (1.0 - dist) * rscale;
+ *right_vol = (master_vol * scale);
+ if (*right_vol < 0)
+ *right_vol = 0;
+
+ scale = (1.0 - dist) * lscale;
+ *left_vol = (master_vol * scale);
+ if (*left_vol < 0)
+ *left_vol = 0;
+}
+
+// =======================================================================
+// Start a sound effect
+// =======================================================================
+
+/*
+=================
+S_Base_HearingThroughEntity
+
+Also see S_AL_HearingThroughEntity
+=================
+*/
+static bool S_Base_HearingThroughEntity( int entityNum, vec3_t origin )
+{
+ float distanceSq;
+ vec3_t sorigin;
+
+ if (origin)
+ VectorCopy(origin, sorigin);
+ else
+ VectorCopy(loopSounds[entityNum].origin, sorigin);
+
+ if( listener_number == entityNum )
+ {
+ // This is an outrageous hack to detect
+ // whether or not the player is rendering in third person or not. We can't
+ // ask the renderer because the renderer has no notion of entities and we
+ // can't ask cgame since that would involve changing the API and hence mod
+ // compatibility. I don't think there is any way around this, but I'll leave
+ // the FIXME just in case anyone has a bright idea.
+ distanceSq = DistanceSquared(
+ sorigin,
+ listener_origin );
+
+ if( distanceSq > THIRD_PERSON_THRESHOLD_SQ )
+ return false; //we're the player, but third person
+ else
+ return true; //we're the player
+ }
+ else
+ return false; //not the player
+}
+
+/*
+====================
+S_Base_StartSoundEx
+
+Validates the parms and ques the sound up
+if origin is NULL, the sound will be dynamically sourced from the entity
+Entchannel 0 will never override a playing sound
+====================
+*/
+static void S_Base_StartSoundEx( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxHandle, bool localSound ) {
+ channel_t *ch;
+ sfx_t *sfx;
+ int i, oldest, chosen, time;
+ int inplay, allowed;
+ bool fullVolume;
+
+ if ( !s_soundStarted || s_soundMuted ) {
+ return;
+ }
+
+ if ( !origin && ( entityNum < 0 || entityNum >= MAX_GENTITIES ) ) {
+ Com_Error( ERR_DROP, "S_StartSound: bad entitynum %i", entityNum );
+ }
+
+ if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
+ Com_Printf( S_COLOR_YELLOW "S_StartSound: handle %i out of range\n", sfxHandle );
+ return;
+ }
+
+ sfx = &s_knownSfx[ sfxHandle ];
+
+ if (sfx->inMemory == false) {
+ S_memoryLoad(sfx);
+ }
+
+ if ( s_show->integer == 1 ) {
+ Com_Printf( "%i : %s\n", s_paintedtime, sfx->soundName );
+ }
+
+ time = Com_Milliseconds();
+
+// Com_Printf("playing %s\n", sfx->soundName);
+ // pick a channel to play on
+
+ allowed = 4;
+ if (entityNum == listener_number) {
+ allowed = 8;
+ }
+
+ fullVolume = false;
+ if (localSound || S_Base_HearingThroughEntity(entityNum, origin)) {
+ fullVolume = true;
+ }
+
+ ch = s_channels;
+ inplay = 0;
+ for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {
+ if (ch->entnum == entityNum && ch->thesfx == sfx) {
+ if (time - ch->allocTime < 50) {
+// if (Cvar_VariableValue( "cg_showmiss" )) {
+// Com_Printf("double sound start\n");
+// }
+ return;
+ }
+ inplay++;
+ }
+ }
+
+ if (inplay>allowed) {
+ return;
+ }
+
+ sfx->lastTimeUsed = time;
+
+ ch = S_ChannelMalloc(); // entityNum, entchannel);
+ if (!ch) {
+ ch = s_channels;
+
+ oldest = sfx->lastTimeUsed;
+ chosen = -1;
+ for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
+ if (ch->entnum != listener_number && ch->entnum == entityNum && ch->allocTime<oldest && ch->entchannel != CHAN_ANNOUNCER) {
+ oldest = ch->allocTime;
+ chosen = i;
+ }
+ }
+ if (chosen == -1) {
+ ch = s_channels;
+ for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
+ if (ch->entnum != listener_number && ch->allocTime<oldest && ch->entchannel != CHAN_ANNOUNCER) {
+ oldest = ch->allocTime;
+ chosen = i;
+ }
+ }
+ if (chosen == -1) {
+ ch = s_channels;
+ if (ch->entnum == listener_number) {
+ for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
+ if (ch->allocTime<oldest) {
+ oldest = ch->allocTime;
+ chosen = i;
+ }
+ }
+ }
+ if (chosen == -1) {
+ Com_DPrintf("dropping sound\n");
+ return;
+ }
+ }
+ }
+ ch = &s_channels[chosen];
+ ch->allocTime = sfx->lastTimeUsed;
+ }
+
+ if (origin) {
+ VectorCopy (origin, ch->origin);
+ ch->fixed_origin = true;
+ } else {
+ ch->fixed_origin = false;
+ }
+
+ ch->master_vol = 127;
+ ch->entnum = entityNum;
+ ch->thesfx = sfx;
+ ch->startSample = START_SAMPLE_IMMEDIATE;
+ ch->entchannel = entchannel;
+ ch->leftvol = ch->master_vol; // these will get calced at next spatialize
+ ch->rightvol = ch->master_vol; // unless the game isn't running
+ ch->doppler = false;
+ ch->fullVolume = fullVolume;
+}
+
+/*
+====================
+S_StartSound
+
+if origin is NULL, the sound will be dynamically sourced from the entity
+====================
+*/
+void S_Base_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxHandle ) {
+ S_Base_StartSoundEx( origin, entityNum, entchannel, sfxHandle, false );
+}
+
+/*
+==================
+S_StartLocalSound
+==================
+*/
+void S_Base_StartLocalSound( sfxHandle_t sfxHandle, int channelNum ) {
+ if ( !s_soundStarted || s_soundMuted ) {
+ return;
+ }
+
+ if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
+ Com_Printf( S_COLOR_YELLOW "S_StartLocalSound: handle %i out of range\n", sfxHandle );
+ return;
+ }
+
+ S_Base_StartSoundEx( NULL, listener_number, channelNum, sfxHandle, true );
+}
+
+
+/*
+==================
+S_ClearSoundBuffer
+
+If we are about to perform file access, clear the buffer
+so sound doesn't stutter.
+==================
+*/
+void S_Base_ClearSoundBuffer( void ) {
+ int clear;
+
+ if (!s_soundStarted)
+ return;
+
+ // stop looping sounds
+ ::memset(loopSounds, 0, MAX_GENTITIES*sizeof(loopSound_t));
+ ::memset(loop_channels, 0, MAX_CHANNELS*sizeof(channel_t));
+ numLoopChannels = 0;
+
+ S_ChannelSetup();
+
+ ::memset(s_rawend, '\0', sizeof (s_rawend));
+
+ if (dma.samplebits == 8)
+ clear = 0x80;
+ else
+ clear = 0;
+
+ SNDDMA_BeginPainting ();
+ if (dma.buffer)
+ ::memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
+ SNDDMA_Submit ();
+}
+
+/*
+==================
+S_StopAllSounds
+==================
+*/
+void S_Base_StopAllSounds(void) {
+ if ( !s_soundStarted ) {
+ return;
+ }
+
+ // stop the background music
+ S_Base_StopBackgroundTrack();
+
+ S_Base_ClearSoundBuffer ();
+}
+
+/*
+==============================================================
+
+continuous looping sounds are added each frame
+
+==============================================================
+*/
+
+void S_Base_StopLoopingSound(int entityNum) {
+ loopSounds[entityNum].active = false;
+// loopSounds[entityNum].sfx = 0;
+ loopSounds[entityNum].kill = false;
+}
+
+/*
+==================
+S_ClearLoopingSounds
+
+==================
+*/
+void S_Base_ClearLoopingSounds( bool killall )
+{
+ int i;
+ for ( i = 0 ; i < MAX_GENTITIES ; i++) {
+ if (killall || loopSounds[i].kill == true || (loopSounds[i].sfx && loopSounds[i].sfx->soundLength == 0)) {
+ S_Base_StopLoopingSound(i);
+ }
+ }
+ numLoopChannels = 0;
+}
+
+/*
+==================
+S_AddLoopingSound
+
+Called during entity generation for a frame
+Include velocity in case I get around to doing doppler...
+==================
+*/
+void S_Base_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {
+ sfx_t *sfx;
+
+ if ( !s_soundStarted || s_soundMuted ) {
+ return;
+ }
+
+ if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
+ Com_Printf( S_COLOR_YELLOW "S_AddLoopingSound: handle %i out of range\n", sfxHandle );
+ return;
+ }
+
+ sfx = &s_knownSfx[ sfxHandle ];
+
+ if (sfx->inMemory == false) {
+ S_memoryLoad(sfx);
+ }
+
+ if ( !sfx->soundLength ) {
+ Com_Error( ERR_DROP, "%s has length 0", sfx->soundName );
+ }
+
+ VectorCopy( origin, loopSounds[entityNum].origin );
+ VectorCopy( velocity, loopSounds[entityNum].velocity );
+ loopSounds[entityNum].active = true;
+ loopSounds[entityNum].kill = true;
+ loopSounds[entityNum].doppler = false;
+ loopSounds[entityNum].oldDopplerScale = 1.0;
+ loopSounds[entityNum].dopplerScale = 1.0;
+ loopSounds[entityNum].sfx = sfx;
+
+ if (s_doppler->integer && VectorLengthSquared(velocity)>0.0) {
+ vec3_t out;
+ float lena, lenb;
+
+ loopSounds[entityNum].doppler = true;
+ lena = DistanceSquared(loopSounds[listener_number].origin, loopSounds[entityNum].origin);
+ VectorAdd(loopSounds[entityNum].origin, loopSounds[entityNum].velocity, out);
+ lenb = DistanceSquared(loopSounds[listener_number].origin, out);
+ if ((loopSounds[entityNum].framenum+1) != cls.framecount) {
+ loopSounds[entityNum].oldDopplerScale = 1.0;
+ } else {
+ loopSounds[entityNum].oldDopplerScale = loopSounds[entityNum].dopplerScale;
+ }
+ loopSounds[entityNum].dopplerScale = lenb/(lena*100);
+ if (loopSounds[entityNum].dopplerScale<=1.0) {
+ loopSounds[entityNum].doppler = false; // don't bother doing the math
+ } else if (loopSounds[entityNum].dopplerScale>MAX_DOPPLER_SCALE) {
+ loopSounds[entityNum].dopplerScale = MAX_DOPPLER_SCALE;
+ }
+ }
+
+ loopSounds[entityNum].framenum = cls.framecount;
+}
+
+/*
+==================
+S_AddLoopingSound
+
+Called during entity generation for a frame
+Include velocity in case I get around to doing doppler...
+==================
+*/
+void S_Base_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {
+ sfx_t *sfx;
+
+ if ( !s_soundStarted || s_soundMuted ) {
+ return;
+ }
+
+ if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
+ Com_Printf( S_COLOR_YELLOW "S_AddRealLoopingSound: handle %i out of range\n", sfxHandle );
+ return;
+ }
+
+ sfx = &s_knownSfx[ sfxHandle ];
+
+ if (sfx->inMemory == false) {
+ S_memoryLoad(sfx);
+ }
+
+ if ( !sfx->soundLength ) {
+ Com_Error( ERR_DROP, "%s has length 0", sfx->soundName );
+ }
+ VectorCopy( origin, loopSounds[entityNum].origin );
+ VectorCopy( velocity, loopSounds[entityNum].velocity );
+ loopSounds[entityNum].sfx = sfx;
+ loopSounds[entityNum].active = true;
+ loopSounds[entityNum].kill = false;
+ loopSounds[entityNum].doppler = false;
+}
+
+
+
+/*
+==================
+S_AddLoopSounds
+
+Spatialize all of the looping sounds.
+All sounds are on the same cycle, so any duplicates can just
+sum up the channel multipliers.
+==================
+*/
+void S_AddLoopSounds (void) {
+ int i, j, time;
+ int left_total, right_total, left, right;
+ channel_t *ch;
+ loopSound_t *loop, *loop2;
+ static int loopFrame;
+
+
+ numLoopChannels = 0;
+
+ time = Com_Milliseconds();
+
+ loopFrame++;
+ for ( i = 0 ; i < MAX_GENTITIES ; i++) {
+ loop = &loopSounds[i];
+ if ( !loop->active || loop->mergeFrame == loopFrame ) {
+ continue; // already merged into an earlier sound
+ }
+
+ if (loop->kill) {
+ S_SpatializeOrigin( loop->origin, 127, &left_total, &right_total); // 3d
+ } else {
+ S_SpatializeOrigin( loop->origin, 90, &left_total, &right_total); // sphere
+ }
+
+ loop->sfx->lastTimeUsed = time;
+
+ for (j=(i+1); j< MAX_GENTITIES ; j++) {
+ loop2 = &loopSounds[j];
+ if ( !loop2->active || loop2->doppler || loop2->sfx != loop->sfx) {
+ continue;
+ }
+ loop2->mergeFrame = loopFrame;
+
+ if (loop2->kill) {
+ S_SpatializeOrigin( loop2->origin, 127, &left, &right); // 3d
+ } else {
+ S_SpatializeOrigin( loop2->origin, 90, &left, &right); // sphere
+ }
+
+ loop2->sfx->lastTimeUsed = time;
+ left_total += left;
+ right_total += right;
+ }
+ if (left_total == 0 && right_total == 0) {
+ continue; // not audible
+ }
+
+ // allocate a channel
+ ch = &loop_channels[numLoopChannels];
+
+ if (left_total > 255) {
+ left_total = 255;
+ }
+ if (right_total > 255) {
+ right_total = 255;
+ }
+
+ ch->master_vol = 127;
+ ch->leftvol = left_total;
+ ch->rightvol = right_total;
+ ch->thesfx = loop->sfx;
+ ch->doppler = loop->doppler;
+ ch->dopplerScale = loop->dopplerScale;
+ ch->oldDopplerScale = loop->oldDopplerScale;
+ ch->fullVolume = false;
+ numLoopChannels++;
+ if (numLoopChannels == MAX_CHANNELS) {
+ return;
+ }
+ }
+}
+
+//=============================================================================
+
+/*
+=================
+S_ByteSwapRawSamples
+
+If raw data has been loaded in little endien binary form, this must be done.
+If raw data was calculated, as with ADPCM, this should not be called.
+=================
+*/
+void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data ) {
+ int i;
+
+ if ( width != 2 ) {
+ return;
+ }
+ if ( LittleShort( 256 ) == 256 ) {
+ return;
+ }
+
+ if ( s_channels == 2 ) {
+ samples <<= 1;
+ }
+ for ( i = 0 ; i < samples ; i++ ) {
+ ((short *)data)[i] = LittleShort( ((short *)data)[i] );
+ }
+}
+
+/*
+============
+S_Base_RawSamples
+
+Music streaming
+============
+*/
+void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_channels, const byte *data, float volume, int entityNum)
+{
+ int i;
+ int src, dst;
+ float scale;
+ int intVolumeLeft, intVolumeRight;
+ portable_samplepair_t *rawsamples;
+
+ if ( !s_soundStarted || s_soundMuted ) {
+ return;
+ }
+
+ if ( (stream < 0) || (stream >= MAX_RAW_STREAMS) ) {
+ return;
+ }
+
+ rawsamples = s_rawsamples[stream];
+
+ if ( s_muted->integer ) {
+ intVolumeLeft = intVolumeRight = 0;
+ } else {
+ int leftvol, rightvol;
+
+ if ( entityNum >= 0 && entityNum < MAX_GENTITIES ) {
+ // support spatialized raw streams, e.g. for VoIP
+ S_SpatializeOrigin( loopSounds[ entityNum ].origin, 256, &leftvol, &rightvol );
+ } else {
+ leftvol = rightvol = 256;
+ }
+
+ intVolumeLeft = leftvol * volume * s_volume->value;
+ intVolumeRight = rightvol * volume * s_volume->value;
+ }
+
+ if ( s_rawend[stream] < s_soundtime ) {
+ Com_DPrintf( "S_Base_RawSamples: resetting minimum: %i < %i\n", s_rawend[stream], s_soundtime );
+ s_rawend[stream] = s_soundtime;
+ }
+
+ scale = (float)rate / dma.speed;
+
+//Com_Printf ("%i < %i < %i\n", s_soundtime, s_paintedtime, s_rawend[stream]);
+ if (s_channels == 2 && width == 2)
+ {
+ if (scale == 1.0)
+ { // optimized case
+ for (i=0 ; i<samples ; i++)
+ {
+ dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1);
+ s_rawend[stream]++;
+ rawsamples[dst].left = ((short *)data)[i*2] * intVolumeLeft;
+ rawsamples[dst].right = ((short *)data)[i*2+1] * intVolumeRight;
+ }
+ }
+ else
+ {
+ for (i=0 ; ; i++)
+ {
+ src = i*scale;
+ if (src >= samples)
+ break;
+ dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1);
+ s_rawend[stream]++;
+ rawsamples[dst].left = ((short *)data)[src*2] * intVolumeLeft;
+ rawsamples[dst].right = ((short *)data)[src*2+1] * intVolumeRight;
+ }
+ }
+ }
+ else if (s_channels == 1 && width == 2)
+ {
+ for (i=0 ; ; i++)
+ {
+ src = i*scale;
+ if (src >= samples)
+ break;
+ dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1);
+ s_rawend[stream]++;
+ rawsamples[dst].left = ((short *)data)[src] * intVolumeLeft;
+ rawsamples[dst].right = ((short *)data)[src] * intVolumeRight;
+ }
+ }
+ else if (s_channels == 2 && width == 1)
+ {
+ intVolumeLeft *= 256;
+ intVolumeRight *= 256;
+
+ for (i=0 ; ; i++)
+ {
+ src = i*scale;
+ if (src >= samples)
+ break;
+ dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1);
+ s_rawend[stream]++;
+ rawsamples[dst].left = ((char *)data)[src*2] * intVolumeLeft;
+ rawsamples[dst].right = ((char *)data)[src*2+1] * intVolumeRight;
+ }
+ }
+ else if (s_channels == 1 && width == 1)
+ {
+ intVolumeLeft *= 256;
+ intVolumeRight *= 256;
+
+ for (i=0 ; ; i++)
+ {
+ src = i*scale;
+ if (src >= samples)
+ break;
+ dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1);
+ s_rawend[stream]++;
+ rawsamples[dst].left = (((byte *)data)[src]-128) * intVolumeLeft;
+ rawsamples[dst].right = (((byte *)data)[src]-128) * intVolumeRight;
+ }
+ }
+
+ if ( s_rawend[stream] > s_soundtime + MAX_RAW_SAMPLES ) {
+ Com_DPrintf( "S_Base_RawSamples: overflowed %i > %i\n", s_rawend[stream], s_soundtime );
+ }
+}
+
+//=============================================================================
+
+/*
+=====================
+S_UpdateEntityPosition
+
+let the sound system know where an entity currently is
+======================
+*/
+void S_Base_UpdateEntityPosition( int entityNum, const vec3_t origin ) {
+ if ( entityNum < 0 || entityNum >= MAX_GENTITIES ) {
+ Com_Error( ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum );
+ }
+ VectorCopy( origin, loopSounds[entityNum].origin );
+}
+
+
+/*
+============
+S_Respatialize
+
+Change the volumes of all the playing sounds for changes in their positions
+============
+*/
+void S_Base_Respatialize( int entityNum, const vec3_t head, vec3_t axis[3], int inwater ) {
+ int i;
+ channel_t *ch;
+ vec3_t origin;
+
+ if ( !s_soundStarted || s_soundMuted ) {
+ return;
+ }
+
+ listener_number = entityNum;
+ VectorCopy(head, listener_origin);
+ VectorCopy(axis[0], listener_axis[0]);
+ VectorCopy(axis[1], listener_axis[1]);
+ VectorCopy(axis[2], listener_axis[2]);
+
+ // update spatialization for dynamic sounds
+ ch = s_channels;
+ for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
+ if ( !ch->thesfx ) {
+ continue;
+ }
+ // local and first person sounds will always be full volume
+ if (ch->fullVolume) {
+ ch->leftvol = ch->master_vol;
+ ch->rightvol = ch->master_vol;
+ } else {
+ if (ch->fixed_origin) {
+ VectorCopy( ch->origin, origin );
+ } else {
+ VectorCopy( loopSounds[ ch->entnum ].origin, origin );
+ }
+
+ S_SpatializeOrigin (origin, ch->master_vol, &ch->leftvol, &ch->rightvol);
+ }
+ }
+
+ // add loopsounds
+ S_AddLoopSounds ();
+}
+
+
+/*
+========================
+S_ScanChannelStarts
+
+Returns true if any new sounds were started since the last mix
+========================
+*/
+bool S_ScanChannelStarts( void ) {
+ channel_t *ch;
+ int i;
+ bool newSamples;
+
+ newSamples = false;
+ ch = s_channels;
+
+ for (i=0; i<MAX_CHANNELS ; i++, ch++) {
+ if ( !ch->thesfx ) {
+ continue;
+ }
+ // if this channel was just started this frame,
+ // set the sample count to it begins mixing
+ // into the very first sample
+ if ( ch->startSample == START_SAMPLE_IMMEDIATE ) {
+ ch->startSample = s_paintedtime;
+ newSamples = true;
+ continue;
+ }
+
+ // if it is completely finished by now, clear it
+ if ( ch->startSample + (ch->thesfx->soundLength) <= s_paintedtime ) {
+ S_ChannelFree(ch);
+ }
+ }
+
+ return newSamples;
+}
+
+/*
+============
+S_Update
+
+Called once each time through the main loop
+============
+*/
+void S_Base_Update( void ) {
+ int i;
+ int total;
+ channel_t *ch;
+
+ if ( !s_soundStarted || s_soundMuted ) {
+// Com_DPrintf ("not started or muted\n");
+ return;
+ }
+
+ //
+ // debugging output
+ //
+ if ( s_show->integer == 2 ) {
+ total = 0;
+ ch = s_channels;
+ for (i=0 ; i<MAX_CHANNELS; i++, ch++) {
+ if (ch->thesfx && (ch->leftvol || ch->rightvol) ) {
+ Com_Printf ("%d %d %s\n", ch->leftvol, ch->rightvol, ch->thesfx->soundName);
+ total++;
+ }
+ }
+
+ Com_Printf ("----(%i)---- painted: %i\n", total, s_paintedtime);
+ }
+
+ // add raw data from streamed samples
+ S_UpdateBackgroundTrack();
+
+ // mix some sound
+ S_Update_();
+}
+
+void S_GetSoundtime(void)
+{
+ int samplepos;
+ static int buffers;
+ static int oldsamplepos;
+ int fullsamples;
+
+ fullsamples = dma.samples / dma.channels;
+
+ if( CL_VideoRecording( ) )
+ {
+ float fps = MIN(cl_aviFrameRate->value, 1000.0f);
+ float frameDuration = MAX(dma.speed / fps, 1.0f) + clc.aviSoundFrameRemainder;
+
+ int msec = (int)frameDuration;
+ s_soundtime += msec;
+ clc.aviSoundFrameRemainder = frameDuration - msec;
+
+ return;
+ }
+
+ // it is possible to miscount buffers if it has wrapped twice between
+ // calls to S_Update. Oh well.
+ samplepos = SNDDMA_GetDMAPos();
+ if (samplepos < oldsamplepos)
+ {
+ buffers++; // buffer wrapped
+
+ if (s_paintedtime > 0x40000000)
+ { // time to chop things off to avoid 32 bit limits
+ buffers = 0;
+ s_paintedtime = fullsamples;
+ S_Base_StopAllSounds ();
+ }
+ }
+ oldsamplepos = samplepos;
+
+ s_soundtime = buffers*fullsamples + samplepos/dma.channels;
+
+#if 0
+// check to make sure that we haven't overshot
+ if (s_paintedtime < s_soundtime)
+ {
+ Com_DPrintf ("S_Update_ : overflow\n");
+ s_paintedtime = s_soundtime;
+ }
+#endif
+
+ if ( dma.submission_chunk < 256 ) {
+ s_paintedtime = s_soundtime + s_mixPreStep->value * dma.speed;
+ } else {
+ s_paintedtime = s_soundtime + dma.submission_chunk;
+ }
+}
+
+
+void S_Update_(void) {
+ unsigned endtime;
+ int samps;
+ static float lastTime = 0.0f;
+ float ma, op;
+ float thisTime, sane;
+ static int ot = -1;
+
+ if ( !s_soundStarted || s_soundMuted ) {
+ return;
+ }
+
+ thisTime = Com_Milliseconds();
+
+ // Updates s_soundtime
+ S_GetSoundtime();
+
+ if (s_soundtime == ot) {
+ return;
+ }
+ ot = s_soundtime;
+
+ // clear any sound effects that end before the current time,
+ // and start any new sounds
+ S_ScanChannelStarts();
+
+ sane = thisTime - lastTime;
+ if (sane<11) {
+ sane = 11; // 85hz
+ }
+
+ ma = s_mixahead->value * dma.speed;
+ op = s_mixPreStep->value + sane*dma.speed*0.01;
+
+ if (op < ma) {
+ ma = op;
+ }
+
+ // mix ahead of current position
+ endtime = s_soundtime + ma;
+
+ // mix to an even submission block size
+ endtime = (endtime + dma.submission_chunk-1)
+ & ~(dma.submission_chunk-1);
+
+ // never mix more than the complete buffer
+ samps = dma.samples >> (dma.channels-1);
+ if (endtime - s_soundtime > samps)
+ endtime = s_soundtime + samps;
+
+
+
+ SNDDMA_BeginPainting ();
+
+ S_PaintChannels (endtime);
+
+ SNDDMA_Submit ();
+
+ lastTime = thisTime;
+}
+
+
+
+/*
+===============================================================================
+
+background music functions
+
+===============================================================================
+*/
+
+/*
+======================
+S_StopBackgroundTrack
+======================
+*/
+void S_Base_StopBackgroundTrack( void ) {
+ if(!s_backgroundStream)
+ return;
+ S_CodecCloseStream(s_backgroundStream);
+ s_backgroundStream = NULL;
+ s_rawend[0] = 0;
+}
+
+/*
+======================
+S_OpenBackgroundStream
+======================
+*/
+static void S_OpenBackgroundStream( const char *filename ) {
+ // close the background track, but DON'T reset s_rawend
+ // if restarting the same back ground track
+ if(s_backgroundStream)
+ {
+ S_CodecCloseStream(s_backgroundStream);
+ s_backgroundStream = NULL;
+ }
+
+ // Open stream
+ s_backgroundStream = S_CodecOpenStream(filename);
+ if(!s_backgroundStream) {
+ Com_Printf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", filename );
+ return;
+ }
+
+ if(s_backgroundStream->info.channels != 2 || s_backgroundStream->info.rate != 22050) {
+ Com_Printf(S_COLOR_YELLOW "WARNING: music file %s is not 22k stereo\n", filename );
+ }
+}
+
+/*
+======================
+S_StartBackgroundTrack
+======================
+*/
+void S_Base_StartBackgroundTrack( const char *intro, const char *loop ){
+ if ( !intro ) {
+ intro = "";
+ }
+ if ( !loop || !loop[0] ) {
+ loop = intro;
+ }
+ Com_DPrintf( "S_StartBackgroundTrack( %s, %s )\n", intro, loop );
+
+ if(!*intro)
+ {
+ S_Base_StopBackgroundTrack();
+ return;
+ }
+
+ Q_strncpyz( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );
+
+ S_OpenBackgroundStream( intro );
+}
+
+/*
+======================
+S_UpdateBackgroundTrack
+======================
+*/
+void S_UpdateBackgroundTrack( void ) {
+ int bufferSamples;
+ int fileSamples;
+ byte raw[30000]; // just enough to fit in a mac stack frame
+ int fileBytes;
+ int r;
+
+ if(!s_backgroundStream) {
+ return;
+ }
+
+ // don't bother playing anything if musicvolume is 0
+ if ( s_musicVolume->value <= 0 ) {
+ return;
+ }
+
+ // see how many samples should be copied into the raw buffer
+ if ( s_rawend[0] < s_soundtime ) {
+ s_rawend[0] = s_soundtime;
+ }
+
+ while ( s_rawend[0] < s_soundtime + MAX_RAW_SAMPLES ) {
+ bufferSamples = MAX_RAW_SAMPLES - (s_rawend[0] - s_soundtime);
+
+ // decide how much data needs to be read from the file
+ fileSamples = bufferSamples * s_backgroundStream->info.rate / dma.speed;
+
+ if (!fileSamples)
+ return;
+
+ // our max buffer size
+ fileBytes = fileSamples * (s_backgroundStream->info.width * s_backgroundStream->info.channels);
+ if ( fileBytes > sizeof(raw) ) {
+ fileBytes = sizeof(raw);
+ fileSamples = fileBytes / (s_backgroundStream->info.width * s_backgroundStream->info.channels);
+ }
+
+ // Read
+ r = S_CodecReadStream(s_backgroundStream, fileBytes, raw);
+ if(r < fileBytes)
+ {
+ fileSamples = r / (s_backgroundStream->info.width * s_backgroundStream->info.channels);
+ }
+
+ if(r > 0)
+ {
+ // add to raw buffer
+ S_Base_RawSamples(0, fileSamples, s_backgroundStream->info.rate,
+ s_backgroundStream->info.width, s_backgroundStream->info.channels, raw, s_musicVolume->value, -1);
+ }
+ else
+ {
+ // loop
+ if(s_backgroundLoop[0])
+ {
+ S_OpenBackgroundStream( s_backgroundLoop );
+ if(!s_backgroundStream)
+ return;
+ }
+ else
+ {
+ S_Base_StopBackgroundTrack();
+ return;
+ }
+ }
+
+ }
+}
+
+
+/*
+======================
+S_FreeOldestSound
+======================
+*/
+
+void S_FreeOldestSound( void ) {
+ int i, oldest, used;
+ sfx_t *sfx;
+ sndBuffer *buffer, *nbuffer;
+
+ oldest = Com_Milliseconds();
+ used = 0;
+
+ for (i=1 ; i < s_numSfx ; i++) {
+ sfx = &s_knownSfx[i];
+ if (sfx->inMemory && sfx->lastTimeUsed<oldest) {
+ used = i;
+ oldest = sfx->lastTimeUsed;
+ }
+ }
+
+ sfx = &s_knownSfx[used];
+
+ Com_DPrintf("S_FreeOldestSound: freeing sound %s\n", sfx->soundName);
+
+ buffer = sfx->soundData;
+ while(buffer != NULL) {
+ nbuffer = buffer->next;
+ SND_free(buffer);
+ buffer = nbuffer;
+ }
+ sfx->inMemory = false;
+ sfx->soundData = NULL;
+}
+
+// =======================================================================
+// Shutdown sound engine
+// =======================================================================
+
+void S_Base_Shutdown( void ) {
+ if ( !s_soundStarted ) {
+ return;
+ }
+
+ SNDDMA_Shutdown();
+ SND_shutdown();
+
+ s_soundStarted = false;
+ s_numSfx = 0;
+
+ Cmd_RemoveCommand("s_info");
+}
+
+/*
+================
+S_Init
+================
+*/
+bool S_Base_Init( soundInterface_t *si )
+{
+
+ if( !si ) {
+ return false;
+ }
+
+ s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
+ s_mixPreStep = Cvar_Get ("s_mixPreStep", "0.05", CVAR_ARCHIVE);
+ s_show = Cvar_Get ("s_show", "0", CVAR_CHEAT);
+ s_testsound = Cvar_Get ("s_testsound", "0", CVAR_CHEAT);
+
+ bool r = SNDDMA_Init();
+ if ( r )
+ {
+ s_soundStarted = true;
+ s_soundMuted = true;
+// s_numSfx = 0;
+
+ ::memset(sfxHash, 0, sizeof(sfx_t *)*LOOP_HASH);
+
+ s_soundtime = 0;
+ s_paintedtime = 0;
+
+ S_Base_StopAllSounds( );
+ } else {
+ return false;
+ }
+
+ si->Shutdown = S_Base_Shutdown;
+ si->StartSound = S_Base_StartSound;
+ si->StartLocalSound = S_Base_StartLocalSound;
+ si->StartBackgroundTrack = S_Base_StartBackgroundTrack;
+ si->StopBackgroundTrack = S_Base_StopBackgroundTrack;
+ si->RawSamples = S_Base_RawSamples;
+ si->StopAllSounds = S_Base_StopAllSounds;
+ si->ClearLoopingSounds = S_Base_ClearLoopingSounds;
+ si->AddLoopingSound = S_Base_AddLoopingSound;
+ si->AddRealLoopingSound = S_Base_AddRealLoopingSound;
+ si->StopLoopingSound = S_Base_StopLoopingSound;
+ si->Respatialize = S_Base_Respatialize;
+ si->UpdateEntityPosition = S_Base_UpdateEntityPosition;
+ si->Update = S_Base_Update;
+ si->DisableSounds = S_Base_DisableSounds;
+ si->BeginRegistration = S_Base_BeginRegistration;
+ si->RegisterSound = S_Base_RegisterSound;
+ si->SoundDuration = S_Base_SoundDuration;
+ si->ClearSoundBuffer = S_Base_ClearSoundBuffer;
+ si->SoundInfo = S_Base_SoundInfo;
+ si->SoundList = S_Base_SoundList;
+
+#ifdef USE_VOIP
+ si->StartCapture = S_Base_StartCapture;
+ si->AvailableCaptureSamples = S_Base_AvailableCaptureSamples;
+ si->Capture = S_Base_Capture;
+ si->StopCapture = S_Base_StopCapture;
+ si->MasterGain = S_Base_MasterGain;
+#endif
+
+ return true;
+}
diff --git a/src/client/snd_local.h b/src/client/snd_local.h
new file mode 100644
index 0000000..38f26c4
--- /dev/null
+++ b/src/client/snd_local.h
@@ -0,0 +1,267 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// snd_local.h -- private sound definations
+
+#ifndef _SND_LOCAL_H
+#define _SND_LOCAL_H
+
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+#include "snd_public.h"
+
+typedef struct cvar_s cvar_t;
+
+#define PAINTBUFFER_SIZE 4096 // this is in samples
+
+#define SND_CHUNK_SIZE 1024 // samples
+#define SND_CHUNK_SIZE_FLOAT (SND_CHUNK_SIZE/2) // floats
+#define SND_CHUNK_SIZE_BYTE (SND_CHUNK_SIZE*2) // floats
+
+typedef struct {
+ int left; // the final values will be clamped to +/- 0x00ffff00 and shifted down
+ int right;
+} portable_samplepair_t;
+
+typedef struct adpcm_state {
+ short sample; /* Previous output value */
+ char index; /* Index into stepsize table */
+} adpcm_state_t;
+
+typedef struct sndBuffer_s {
+ short sndChunk[SND_CHUNK_SIZE];
+ struct sndBuffer_s *next;
+ int size;
+ adpcm_state_t adpcm;
+} sndBuffer;
+
+typedef struct sfx_s {
+ sndBuffer *soundData;
+ bool defaultSound; // couldn't be loaded, so use buzz
+ bool inMemory; // not in Memory
+ bool soundCompressed; // not in Memory
+ int soundCompressionMethod;
+ int soundLength;
+ int soundChannels;
+ char soundName[MAX_QPATH];
+ int lastTimeUsed;
+ int duration;
+ struct sfx_s *next;
+} sfx_t;
+
+typedef struct {
+ int channels;
+ int samples; // mono samples in buffer
+ int submission_chunk; // don't mix less than this #
+ int samplebits;
+ int speed;
+ byte *buffer;
+} dma_t;
+
+#define START_SAMPLE_IMMEDIATE 0x7fffffff
+
+#define MAX_DOPPLER_SCALE 50.0f //arbitrary
+
+#define THIRD_PERSON_THRESHOLD_SQ (48.0f*48.0f)
+
+typedef struct loopSound_s {
+ vec3_t origin;
+ vec3_t velocity;
+ sfx_t *sfx;
+ int mergeFrame;
+ bool active;
+ bool kill;
+ bool doppler;
+ float dopplerScale;
+ float oldDopplerScale;
+ int framenum;
+} loopSound_t;
+
+typedef struct
+{
+ sfx_t *thesfx; // sfx structure
+ int allocTime;
+ int startSample; // START_SAMPLE_IMMEDIATE = set immediately on next mix
+ int entnum; // to allow overriding a specific sound
+ int entchannel; // to allow overriding a specific sound
+ int leftvol; // 0-255 volume after spatialization
+ int rightvol; // 0-255 volume after spatialization
+ int master_vol; // 0-255 volume before spatialization
+ float dopplerScale;
+ float oldDopplerScale;
+ vec3_t origin; // only use if fixed_origin is set
+ bool fixed_origin; // use origin instead of fetching entnum's origin
+ bool doppler;
+ bool fullVolume;
+} channel_t;
+
+
+#define WAV_FORMAT_PCM 1
+
+
+typedef struct {
+ int format;
+ int rate;
+ int width;
+ int channels;
+ int samples;
+ int dataofs; // chunk starts this many bytes from file start
+} wavinfo_t;
+
+// Interface between Q3 sound "api" and the sound backend
+typedef struct
+{
+ void (*Shutdown)(void);
+ void (*StartSound)( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx );
+ void (*StartLocalSound)( sfxHandle_t sfx, int channelNum );
+ void (*StartBackgroundTrack)( const char *intro, const char *loop );
+ void (*StopBackgroundTrack)( void );
+ void (*RawSamples)(int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum);
+ void (*StopAllSounds)( void );
+ void (*ClearLoopingSounds)( bool killall );
+ void (*AddLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
+ void (*AddRealLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
+ void (*StopLoopingSound)(int entityNum );
+ void (*Respatialize)( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
+ void (*UpdateEntityPosition)( int entityNum, const vec3_t origin );
+ void (*Update)( void );
+ void (*DisableSounds)( void );
+ void (*BeginRegistration)( void );
+ sfxHandle_t (*RegisterSound)( const char *sample, bool compressed );
+ int (*SoundDuration)( sfxHandle_t handle );
+ void (*ClearSoundBuffer)( void );
+ void (*SoundInfo)( void );
+ void (*SoundList)( void );
+#ifdef USE_VOIP
+ void (*StartCapture)( void );
+ int (*AvailableCaptureSamples)( void );
+ void (*Capture)( int samples, byte *data );
+ void (*StopCapture)( void );
+ void (*MasterGain)( float gain );
+#endif
+} soundInterface_t;
+
+
+/*
+====================================================================
+
+ SYSTEM SPECIFIC FUNCTIONS
+
+====================================================================
+*/
+
+// initializes cycling through a DMA buffer and returns information on it
+bool SNDDMA_Init(void);
+
+// gets the current DMA position
+int SNDDMA_GetDMAPos(void);
+
+// shutdown the DMA xfer.
+void SNDDMA_Shutdown(void);
+
+void SNDDMA_BeginPainting (void);
+
+void SNDDMA_Submit(void);
+
+//====================================================================
+
+#define MAX_CHANNELS 96
+
+extern channel_t s_channels[MAX_CHANNELS];
+extern channel_t loop_channels[MAX_CHANNELS];
+extern int numLoopChannels;
+
+extern int s_paintedtime;
+extern vec3_t listener_forward;
+extern vec3_t listener_right;
+extern vec3_t listener_up;
+extern dma_t dma;
+
+#define MAX_RAW_SAMPLES 16384
+#define MAX_RAW_STREAMS (MAX_CLIENTS * 2 + 1)
+extern portable_samplepair_t s_rawsamples[MAX_RAW_STREAMS][MAX_RAW_SAMPLES];
+extern int s_rawend[MAX_RAW_STREAMS];
+
+extern cvar_t *s_volume;
+extern cvar_t *s_musicVolume;
+extern cvar_t *s_muted;
+extern cvar_t *s_doppler;
+
+extern cvar_t *s_testsound;
+
+bool S_LoadSound( sfx_t *sfx );
+
+void SND_free(sndBuffer *v);
+sndBuffer* SND_malloc( void );
+void SND_setup( void );
+void SND_shutdown(void);
+
+void S_PaintChannels(int endtime);
+
+void S_memoryLoad(sfx_t *sfx);
+
+// spatializes a channel
+void S_Spatialize(channel_t *ch);
+
+// adpcm functions
+int S_AdpcmMemoryNeeded( const wavinfo_t *info );
+void S_AdpcmEncodeSound( sfx_t *sfx, short *samples );
+void S_AdpcmGetSamples(sndBuffer *chunk, short *to);
+
+// wavelet function
+
+#define SENTINEL_MULAW_ZERO_RUN 127
+#define SENTINEL_MULAW_FOUR_BIT_RUN 126
+
+void S_FreeOldestSound( void );
+
+#define NXStream byte
+
+void encodeWavelet(sfx_t *sfx, short *packets);
+void decodeWavelet( sndBuffer *stream, short *packets);
+
+void encodeMuLaw( sfx_t *sfx, short *packets);
+extern short mulawToShort[256];
+
+extern short *sfxScratchBuffer;
+extern sfx_t *sfxScratchPointer;
+extern int sfxScratchIndex;
+
+bool S_Base_Init( soundInterface_t *si );
+
+// OpenAL stuff
+typedef enum
+{
+ SRCPRI_AMBIENT = 0, // Ambient sound effects
+ SRCPRI_ENTITY, // Entity sound effects
+ SRCPRI_ONESHOT, // One-shot sounds
+ SRCPRI_LOCAL, // Local sounds
+ SRCPRI_STREAM // Streams (music, cutscenes)
+} alSrcPriority_t;
+
+typedef int srcHandle_t;
+
+bool S_AL_Init( soundInterface_t *si );
+
+#endif
diff --git a/src/client/snd_main.cpp b/src/client/snd_main.cpp
new file mode 100644
index 0000000..a6873f1
--- /dev/null
+++ b/src/client/snd_main.cpp
@@ -0,0 +1,566 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "client.h"
+#include "snd_codec.h"
+#include "snd_local.h"
+#include "snd_public.h"
+
+cvar_t *s_volume;
+cvar_t *s_muted;
+cvar_t *s_musicVolume;
+cvar_t *s_doppler;
+cvar_t *s_backend;
+cvar_t *s_muteWhenMinimized;
+cvar_t *s_muteWhenUnfocused;
+
+static soundInterface_t si;
+
+/*
+=================
+S_ValidateInterface
+=================
+*/
+static bool S_ValidSoundInterface( soundInterface_t *si )
+{
+ if( !si->Shutdown ) return false;
+ if( !si->StartSound ) return false;
+ if( !si->StartLocalSound ) return false;
+ if( !si->StartBackgroundTrack ) return false;
+ if( !si->StopBackgroundTrack ) return false;
+ if( !si->RawSamples ) return false;
+ if( !si->StopAllSounds ) return false;
+ if( !si->ClearLoopingSounds ) return false;
+ if( !si->AddLoopingSound ) return false;
+ if( !si->AddRealLoopingSound ) return false;
+ if( !si->StopLoopingSound ) return false;
+ if( !si->Respatialize ) return false;
+ if( !si->UpdateEntityPosition ) return false;
+ if( !si->Update ) return false;
+ if( !si->DisableSounds ) return false;
+ if( !si->BeginRegistration ) return false;
+ if( !si->RegisterSound ) return false;
+ if( !si->SoundDuration ) return false;
+ if( !si->ClearSoundBuffer ) return false;
+ if( !si->SoundInfo ) return false;
+ if( !si->SoundList ) return false;
+
+#ifdef USE_VOIP
+ if( !si->StartCapture ) return false;
+ if( !si->AvailableCaptureSamples ) return false;
+ if( !si->Capture ) return false;
+ if( !si->StopCapture ) return false;
+ if( !si->MasterGain ) return false;
+#endif
+
+ return true;
+}
+
+/*
+=================
+S_StartSound
+=================
+*/
+void S_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx )
+{
+ if( si.StartSound ) {
+ si.StartSound( origin, entnum, entchannel, sfx );
+ }
+}
+
+/*
+=================
+S_StartLocalSound
+=================
+*/
+void S_StartLocalSound( sfxHandle_t sfx, int channelNum )
+{
+ if( si.StartLocalSound ) {
+ si.StartLocalSound( sfx, channelNum );
+ }
+}
+
+/*
+=================
+S_StartBackgroundTrack
+=================
+*/
+void S_StartBackgroundTrack( const char *intro, const char *loop )
+{
+ if( si.StartBackgroundTrack ) {
+ si.StartBackgroundTrack( intro, loop );
+ }
+}
+
+/*
+=================
+S_StopBackgroundTrack
+=================
+*/
+void S_StopBackgroundTrack( void )
+{
+ if( si.StopBackgroundTrack ) {
+ si.StopBackgroundTrack( );
+ }
+}
+
+/*
+=================
+S_RawSamples
+=================
+*/
+void S_RawSamples (int stream, int samples, int rate, int width, int channels,
+ const byte *data, float volume, int entityNum)
+{
+ if(si.RawSamples)
+ si.RawSamples(stream, samples, rate, width, channels, data, volume, entityNum);
+}
+
+/*
+=================
+S_StopAllSounds
+=================
+*/
+void S_StopAllSounds( void )
+{
+ if( si.StopAllSounds ) {
+ si.StopAllSounds( );
+ }
+}
+
+/*
+=================
+S_ClearLoopingSounds
+=================
+*/
+void S_ClearLoopingSounds( bool killall )
+{
+ if( si.ClearLoopingSounds ) {
+ si.ClearLoopingSounds( killall );
+ }
+}
+
+/*
+=================
+S_AddLoopingSound
+=================
+*/
+void S_AddLoopingSound( int entityNum, const vec3_t origin,
+ const vec3_t velocity, sfxHandle_t sfx )
+{
+ if( si.AddLoopingSound ) {
+ si.AddLoopingSound( entityNum, origin, velocity, sfx );
+ }
+}
+
+/*
+=================
+S_AddRealLoopingSound
+=================
+*/
+void S_AddRealLoopingSound( int entityNum, const vec3_t origin,
+ const vec3_t velocity, sfxHandle_t sfx )
+{
+ if( si.AddRealLoopingSound ) {
+ si.AddRealLoopingSound( entityNum, origin, velocity, sfx );
+ }
+}
+
+/*
+=================
+S_StopLoopingSound
+=================
+*/
+void S_StopLoopingSound( int entityNum )
+{
+ if( si.StopLoopingSound ) {
+ si.StopLoopingSound( entityNum );
+ }
+}
+
+/*
+=================
+S_Respatialize
+=================
+*/
+void S_Respatialize( int entityNum, const vec3_t origin,
+ vec3_t axis[3], int inwater )
+{
+ if( si.Respatialize ) {
+ si.Respatialize( entityNum, origin, axis, inwater );
+ }
+}
+
+/*
+=================
+S_UpdateEntityPosition
+=================
+*/
+void S_UpdateEntityPosition( int entityNum, const vec3_t origin )
+{
+ if( si.UpdateEntityPosition ) {
+ si.UpdateEntityPosition( entityNum, origin );
+ }
+}
+
+/*
+=================
+S_Update
+=================
+*/
+void S_Update( void )
+{
+ if(s_muted->integer)
+ {
+ if(!(s_muteWhenMinimized->integer && com_minimized->integer) &&
+ !(s_muteWhenUnfocused->integer && com_unfocused->integer))
+ {
+ s_muted->integer = false;
+ s_muted->modified = true;
+ }
+ }
+ else
+ {
+ if((s_muteWhenMinimized->integer && com_minimized->integer) ||
+ (s_muteWhenUnfocused->integer && com_unfocused->integer))
+ {
+ s_muted->integer = true;
+ s_muted->modified = true;
+ }
+ }
+
+ if( si.Update ) {
+ si.Update( );
+ }
+}
+
+/*
+=================
+S_DisableSounds
+=================
+*/
+void S_DisableSounds( void )
+{
+ if( si.DisableSounds ) {
+ si.DisableSounds( );
+ }
+}
+
+/*
+=================
+S_BeginRegistration
+=================
+*/
+void S_BeginRegistration( void )
+{
+ if( si.BeginRegistration ) {
+ si.BeginRegistration( );
+ }
+}
+
+/*
+=================
+S_RegisterSound
+=================
+*/
+sfxHandle_t S_RegisterSound( const char *sample, bool compressed )
+{
+ if( si.RegisterSound ) {
+ return si.RegisterSound( sample, compressed );
+ } else {
+ return 0;
+ }
+}
+
+/*
+=================
+S_SoundDuration
+=================
+*/
+int S_SoundDuration( sfxHandle_t handle )
+{
+ if( si.SoundDuration )
+ return si.SoundDuration( handle );
+ else
+ return 0;
+}
+
+/*
+=================
+S_ClearSoundBuffer
+=================
+*/
+void S_ClearSoundBuffer( void )
+{
+ if( si.ClearSoundBuffer ) {
+ si.ClearSoundBuffer( );
+ }
+}
+
+/*
+=================
+S_SoundInfo
+=================
+*/
+void S_SoundInfo( void )
+{
+ if( si.SoundInfo ) {
+ si.SoundInfo( );
+ }
+}
+
+/*
+=================
+S_SoundList
+=================
+*/
+void S_SoundList( void )
+{
+ if( si.SoundList ) {
+ si.SoundList( );
+ }
+}
+
+
+#ifdef USE_VOIP
+/*
+=================
+S_StartCapture
+=================
+*/
+void S_StartCapture( void )
+{
+ if( si.StartCapture ) {
+ si.StartCapture( );
+ }
+}
+
+/*
+=================
+S_AvailableCaptureSamples
+=================
+*/
+int S_AvailableCaptureSamples( void )
+{
+ if( si.AvailableCaptureSamples ) {
+ return si.AvailableCaptureSamples( );
+ }
+ return 0;
+}
+
+/*
+=================
+S_Capture
+=================
+*/
+void S_Capture( int samples, byte *data )
+{
+ if( si.Capture ) {
+ si.Capture( samples, data );
+ }
+}
+
+/*
+=================
+S_StopCapture
+=================
+*/
+void S_StopCapture( void )
+{
+ if( si.StopCapture ) {
+ si.StopCapture( );
+ }
+}
+
+/*
+=================
+S_MasterGain
+=================
+*/
+void S_MasterGain( float gain )
+{
+ if( si.MasterGain ) {
+ si.MasterGain( gain );
+ }
+}
+#endif
+
+//=============================================================================
+
+/*
+=================
+S_Play_f
+=================
+*/
+void S_Play_f( void ) {
+ int i;
+ int c;
+ sfxHandle_t h;
+
+ if( !si.RegisterSound || !si.StartLocalSound ) {
+ return;
+ }
+
+ c = Cmd_Argc();
+
+ if( c < 2 ) {
+ Com_Printf ("Usage: play <sound filename> [sound filename] [sound filename] ...\n");
+ return;
+ }
+
+ for( i = 1; i < c; i++ ) {
+ h = si.RegisterSound( Cmd_Argv(i), false );
+
+ if( h ) {
+ si.StartLocalSound( h, CHAN_LOCAL_SOUND );
+ }
+ }
+}
+
+/*
+=================
+S_Music_f
+=================
+*/
+void S_Music_f( void ) {
+ int c;
+
+ if( !si.StartBackgroundTrack ) {
+ return;
+ }
+
+ c = Cmd_Argc();
+
+ if ( c == 2 ) {
+ si.StartBackgroundTrack( Cmd_Argv(1), NULL );
+ } else if ( c == 3 ) {
+ si.StartBackgroundTrack( Cmd_Argv(1), Cmd_Argv(2) );
+ } else {
+ Com_Printf ("Usage: music <musicfile> [loopfile]\n");
+ return;
+ }
+
+}
+
+/*
+=================
+S_Music_f
+=================
+*/
+void S_StopMusic_f( void )
+{
+ if(!si.StopBackgroundTrack)
+ return;
+
+ si.StopBackgroundTrack();
+}
+
+
+//=============================================================================
+
+/*
+=================
+S_Init
+=================
+*/
+void S_Init( void )
+{
+ cvar_t *cv;
+ bool started = false;
+
+ Com_Printf( "------ Initializing Sound ------\n" );
+
+ s_volume = Cvar_Get( "s_volume", "0.8", CVAR_ARCHIVE );
+ s_musicVolume = Cvar_Get( "s_musicvolume", "0.25", CVAR_ARCHIVE );
+ s_muted = Cvar_Get("s_muted", "0", CVAR_ROM);
+ s_doppler = Cvar_Get( "s_doppler", "1", CVAR_ARCHIVE );
+ s_backend = Cvar_Get( "s_backend", "", CVAR_ROM );
+ s_muteWhenMinimized = Cvar_Get( "s_muteWhenMinimized", "0", CVAR_ARCHIVE );
+ s_muteWhenUnfocused = Cvar_Get( "s_muteWhenUnfocused", "0", CVAR_ARCHIVE );
+
+ cv = Cvar_Get( "s_initsound", "1", 0 );
+ if( !cv->integer ) {
+ Com_Printf( "Sound disabled.\n" );
+ } else {
+
+ S_CodecInit( );
+
+ Cmd_AddCommand( "play", S_Play_f );
+ Cmd_AddCommand( "music", S_Music_f );
+ Cmd_AddCommand( "stopmusic", S_StopMusic_f );
+ Cmd_AddCommand( "s_list", S_SoundList );
+ Cmd_AddCommand( "s_stop", S_StopAllSounds );
+ Cmd_AddCommand( "s_info", S_SoundInfo );
+
+ cv = Cvar_Get( "s_useOpenAL", "0", CVAR_ARCHIVE );
+ if( cv->integer ) {
+ //OpenAL
+ started = S_AL_Init( &si );
+ Cvar_Set( "s_backend", "OpenAL" );
+ }
+
+ if( !started ) {
+ started = S_Base_Init( &si );
+ Cvar_Set( "s_backend", "base" );
+ }
+
+ if( started ) {
+ if( !S_ValidSoundInterface( &si ) ) {
+ Com_Error( ERR_FATAL, "Sound interface invalid" );
+ }
+
+ S_SoundInfo( );
+ Com_Printf( "Sound initialization successful.\n" );
+ } else {
+ Com_Printf( "Sound initialization failed.\n" );
+ }
+ }
+
+ Com_Printf( "--------------------------------\n");
+}
+
+/*
+=================
+S_Shutdown
+=================
+*/
+void S_Shutdown( void )
+{
+ if( si.Shutdown )
+ {
+ si.Shutdown( );
+ }
+
+ ::memset( &si, 0, sizeof( soundInterface_t ) );
+
+ Cmd_RemoveCommand( "play" );
+ Cmd_RemoveCommand( "music");
+ Cmd_RemoveCommand( "stopmusic");
+ Cmd_RemoveCommand( "s_list" );
+ Cmd_RemoveCommand( "s_stop" );
+ Cmd_RemoveCommand( "s_info" );
+
+ S_CodecShutdown( );
+}
diff --git a/src/client/snd_mem.cpp b/src/client/snd_mem.cpp
new file mode 100644
index 0000000..128a471
--- /dev/null
+++ b/src/client/snd_mem.cpp
@@ -0,0 +1,297 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+/*****************************************************************************
+ * name: snd_mem.c
+ *
+ * desc: sound caching
+ *****************************************************************************/
+
+#include "snd_codec.h"
+#include "snd_local.h"
+
+#include "qcommon/cvar.h"
+
+#define DEF_COMSOUNDMEGS "8"
+
+/*
+===============================================================================
+
+memory management
+
+===============================================================================
+*/
+
+static sndBuffer *buffer = NULL;
+static sndBuffer *freelist = NULL;
+static int inUse = 0;
+static int totalInUse = 0;
+
+short *sfxScratchBuffer = NULL;
+sfx_t *sfxScratchPointer = NULL;
+int sfxScratchIndex = 0;
+
+void SND_free(sndBuffer *v)
+{
+ *(sndBuffer **)v = freelist;
+ freelist = (sndBuffer *)v;
+ inUse += sizeof(sndBuffer);
+}
+
+sndBuffer *SND_malloc(void)
+{
+ sndBuffer *v;
+redo:
+ if (freelist == NULL)
+ {
+ S_FreeOldestSound();
+ goto redo;
+ }
+
+ inUse -= sizeof(sndBuffer);
+ totalInUse += sizeof(sndBuffer);
+
+ v = freelist;
+ freelist = *(sndBuffer **)freelist;
+ v->next = NULL;
+
+ return v;
+}
+
+void SND_setup(void)
+{
+ cvar_t* cv = Cvar_Get("com_soundMegs",
+ DEF_COMSOUNDMEGS, CVAR_LATCH | CVAR_ARCHIVE);
+ int scs = cv->integer * 1536;
+
+ buffer = (sndBuffer*)malloc(scs * sizeof(sndBuffer));
+
+ // allocate the stack based hunk allocator
+ sfxScratchBuffer = (short*)malloc(SND_CHUNK_SIZE * sizeof(short) * 4);
+ sfxScratchPointer = NULL;
+
+ inUse = scs * sizeof(sndBuffer);
+ sndBuffer* p = buffer;
+ sndBuffer* q = p + scs;
+ while (--q > p)
+ {
+ *(sndBuffer **)q = q - 1;
+ }
+
+ *(sndBuffer **)q = NULL;
+ freelist = p + scs - 1;
+
+ Com_Printf("Sound memory manager started\n");
+}
+
+void SND_shutdown(void)
+{
+ free(sfxScratchBuffer);
+ free(buffer);
+}
+
+/*
+================
+ResampleSfx
+
+resample / decimate to the current source rate
+================
+*/
+static int ResampleSfx(sfx_t *sfx, int channels, int inrate, int inwidth, int samples, byte *data, bool compressed)
+{
+ float stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
+ int outcount = samples / stepscale;
+ int fracstep = stepscale * 256 * channels;
+ sndBuffer* chunk = sfx->soundData;
+
+ int samplefrac = 0;
+ int srcsample = 0;
+
+ for (int i = 0; i < outcount; i++)
+ {
+ srcsample += samplefrac >> 8;
+ samplefrac &= 255;
+ samplefrac += fracstep;
+
+ for (int j = 0; j < channels; j++)
+ {
+ int sample;
+
+ if (inwidth == 2)
+ {
+ sample = ((short *)data)[srcsample + j];
+ }
+ else
+ {
+ sample = (int)((unsigned char)(data[srcsample + j]) - 128) << 8;
+ }
+
+ int part = (i * channels + j) & (SND_CHUNK_SIZE - 1);
+ if (part == 0)
+ {
+ sndBuffer *newchunk = SND_malloc();
+
+ if (chunk == NULL)
+ {
+ sfx->soundData = newchunk;
+ }
+ else
+ {
+ chunk->next = newchunk;
+ }
+ chunk = newchunk;
+ }
+
+ chunk->sndChunk[part] = sample;
+ }
+ }
+
+ return outcount;
+}
+
+/*
+================
+ResampleSfxRaw
+
+resample / decimate to the current source rate
+================
+*/
+static int ResampleSfxRaw(short *sfx, int channels, int inrate, int inwidth, int samples, byte *data)
+{
+ float stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
+ int outcount = samples / stepscale;
+ int fracstep = stepscale * 256 * channels;
+
+ int samplefrac = 0;
+ int srcsample = 0;
+
+ for (int i = 0; i < outcount; i++)
+ {
+ srcsample += samplefrac >> 8;
+ srcsample &= 255;
+ samplefrac += fracstep;
+
+ for (int j = 0; j < channels; j++)
+ {
+ int sample;
+ if (inwidth == 2)
+ {
+ sample = LittleShort(((short *)data)[srcsample + j]);
+ }
+ else
+ {
+ sample = (int)((unsigned char)(data[srcsample + j]) - 128) << 8;
+ }
+ sfx[i * channels + j] = sample;
+ }
+ }
+ return outcount;
+}
+
+//=============================================================================
+
+/*
+==============
+S_LoadSound
+
+The filename may be different than sfx->name in the case
+of a forced fallback of a player specific sound
+==============
+*/
+bool S_LoadSound(sfx_t *sfx)
+{
+ snd_info_t info;
+ byte *data = (byte*)S_CodecLoad(sfx->soundName, &info);
+ if (!data)
+ {
+ return false;
+ }
+
+ int size_per_sec = info.rate * info.channels * info.width;
+ if (size_per_sec > 0)
+ {
+ sfx->duration = (int)(1000.0f * ((double)info.size / size_per_sec));
+ }
+
+ if (info.width == 1)
+ {
+ Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n",
+ sfx->soundName);
+ }
+
+ if (info.rate != 22050)
+ {
+ Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n",
+ sfx->soundName);
+ }
+
+ short* samples = (short*)Hunk_AllocateTempMemory(info.channels * info.samples * sizeof(short) * 2);
+
+ sfx->lastTimeUsed = Com_Milliseconds() + 1;
+
+ // each of these compression schemes works just fine
+ // but the 16bit quality is much nicer and with a local
+ // install assured we can rely upon the sound memory
+ // manager to do the right thing for us and page
+ // sound in as needed
+
+ if (info.channels == 1 && sfx->soundCompressed == true)
+ {
+ sfx->soundCompressionMethod = 1;
+ sfx->soundData = NULL;
+ sfx->soundLength = ResampleSfxRaw(
+ samples,
+ info.channels,
+ info.rate,
+ info.width,
+ info.samples,
+ data + info.dataofs);
+ S_AdpcmEncodeSound(sfx, samples);
+ }
+ else
+ {
+ sfx->soundCompressionMethod = 0;
+ sfx->soundData = NULL;
+ sfx->soundLength = ResampleSfx(
+ sfx,
+ info.channels,
+ info.rate,
+ info.width,
+ info.samples,
+ data + info.dataofs,
+ false);
+ }
+
+ sfx->soundChannels = info.channels;
+
+ Hunk_FreeTempMemory(samples);
+ Hunk_FreeTempMemory(data);
+
+ return true;
+}
+
+void S_DisplayFreeMemory(void)
+{
+ Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
+}
diff --git a/src/client/snd_mix.cpp b/src/client/snd_mix.cpp
new file mode 100644
index 0000000..4030bc6
--- /dev/null
+++ b/src/client/snd_mix.cpp
@@ -0,0 +1,792 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// snd_mix.c -- portable code to mix sounds for snd_dma.c
+
+#include "snd_local.h"
+#if idppc_altivec && !defined(__APPLE__)
+#include <altivec.h>
+#endif
+#include "client.h"
+
+static portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
+static int snd_vol;
+
+int* snd_p;
+int snd_linear_count;
+short* snd_out;
+
+#undef id386
+
+#if !id386 // if configured not to use asm
+
+void S_WriteLinearBlastStereo16 (void)
+{
+ int i;
+ int val;
+
+ for (i=0 ; i<snd_linear_count ; i+=2)
+ {
+ val = snd_p[i]>>8;
+ if (val > 0x7fff)
+ snd_out[i] = 0x7fff;
+ else if (val < -32768)
+ snd_out[i] = -32768;
+ else
+ snd_out[i] = val;
+
+ val = snd_p[i+1]>>8;
+ if (val > 0x7fff)
+ snd_out[i+1] = 0x7fff;
+ else if (val < -32768)
+ snd_out[i+1] = -32768;
+ else
+ snd_out[i+1] = val;
+ }
+}
+#elif defined(__GNUC__)
+// uses snd_mixa.s
+void S_WriteLinearBlastStereo16 (void);
+#else
+
+__declspec( naked ) void S_WriteLinearBlastStereo16 (void)
+{
+ __asm {
+
+ push edi
+ push ebx
+ mov ecx,ds:dword ptr[snd_linear_count]
+ mov ebx,ds:dword ptr[snd_p]
+ mov edi,ds:dword ptr[snd_out]
+LWLBLoopTop:
+ mov eax,ds:dword ptr[-8+ebx+ecx*4]
+ sar eax,8
+ cmp eax,07FFFh
+ jg LClampHigh
+ cmp eax,0FFFF8000h
+ jnl LClampDone
+ mov eax,0FFFF8000h
+ jmp LClampDone
+LClampHigh:
+ mov eax,07FFFh
+LClampDone:
+ mov edx,ds:dword ptr[-4+ebx+ecx*4]
+ sar edx,8
+ cmp edx,07FFFh
+ jg LClampHigh2
+ cmp edx,0FFFF8000h
+ jnl LClampDone2
+ mov edx,0FFFF8000h
+ jmp LClampDone2
+LClampHigh2:
+ mov edx,07FFFh
+LClampDone2:
+ shl edx,16
+ and eax,0FFFFh
+ or edx,eax
+ mov ds:dword ptr[-4+edi+ecx*2],edx
+ sub ecx,2
+ jnz LWLBLoopTop
+ pop ebx
+ pop edi
+ ret
+ }
+}
+
+#endif
+
+void S_TransferStereo16 (unsigned long *pbuf, int endtime)
+{
+ int lpos;
+ int ls_paintedtime;
+
+ snd_p = (int *) paintbuffer;
+ ls_paintedtime = s_paintedtime;
+
+ while (ls_paintedtime < endtime)
+ {
+ // handle recirculating buffer issues
+ lpos = ls_paintedtime & ((dma.samples>>1)-1);
+
+ snd_out = (short *) pbuf + (lpos<<1);
+
+ snd_linear_count = (dma.samples>>1) - lpos;
+ if (ls_paintedtime + snd_linear_count > endtime)
+ snd_linear_count = endtime - ls_paintedtime;
+
+ snd_linear_count <<= 1;
+
+ // write a linear blast of samples
+ S_WriteLinearBlastStereo16 ();
+
+ snd_p += snd_linear_count;
+ ls_paintedtime += (snd_linear_count>>1);
+
+ if( CL_VideoRecording( ) )
+ CL_WriteAVIAudioFrame( (byte *)snd_out, snd_linear_count << 1 );
+ }
+}
+
+/*
+===================
+S_TransferPaintBuffer
+
+===================
+*/
+void S_TransferPaintBuffer(int endtime)
+{
+ int out_idx;
+ int count;
+ int out_mask;
+ int *p;
+ int step;
+ int val;
+ unsigned long *pbuf;
+
+ pbuf = (unsigned long *)dma.buffer;
+
+
+ if ( s_testsound->integer ) {
+ int i;
+
+ // write a fixed sine wave
+ count = (endtime - s_paintedtime);
+ for (i=0 ; i<count ; i++)
+ paintbuffer[i].left = paintbuffer[i].right = sin((s_paintedtime+i)*0.1)*20000*256;
+ }
+
+
+ if (dma.samplebits == 16 && dma.channels == 2)
+ { // optimized case
+ S_TransferStereo16 (pbuf, endtime);
+ }
+ else
+ { // general case
+ p = (int *) paintbuffer;
+ count = (endtime - s_paintedtime) * dma.channels;
+ out_mask = dma.samples - 1;
+ out_idx = s_paintedtime * dma.channels & out_mask;
+ step = 3 - dma.channels;
+
+ if (dma.samplebits == 16)
+ {
+ short *out = (short *) pbuf;
+ while (count--)
+ {
+ val = *p >> 8;
+ p+= step;
+ if (val > 0x7fff)
+ val = 0x7fff;
+ else if (val < -32768)
+ val = -32768;
+ out[out_idx] = val;
+ out_idx = (out_idx + 1) & out_mask;
+ }
+ }
+ else if (dma.samplebits == 8)
+ {
+ unsigned char *out = (unsigned char *) pbuf;
+ while (count--)
+ {
+ val = *p >> 8;
+ p+= step;
+ if (val > 0x7fff)
+ val = 0x7fff;
+ else if (val < -32768)
+ val = -32768;
+ out[out_idx] = (val>>8) + 128;
+ out_idx = (out_idx + 1) & out_mask;
+ }
+ }
+ }
+}
+
+
+/*
+===============================================================================
+
+CHANNEL MIXING
+
+===============================================================================
+*/
+
+#if idppc_altivec
+static void S_PaintChannelFrom16_altivec( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
+ int data, aoff, boff;
+ int leftvol, rightvol;
+ int i, j;
+ portable_samplepair_t *samp;
+ sndBuffer *chunk;
+ short *samples;
+ float ooff, fdata[2], fdiv, fleftvol, frightvol;
+
+ if (sc->soundChannels <= 0) {
+ return;
+ }
+
+ samp = &paintbuffer[ bufferOffset ];
+
+ if (ch->doppler) {
+ sampleOffset = sampleOffset*ch->oldDopplerScale;
+ }
+
+ if ( sc->soundChannels == 2 ) {
+ sampleOffset *= sc->soundChannels;
+
+ if ( sampleOffset & 1 ) {
+ sampleOffset &= ~1;
+ }
+ }
+
+ chunk = sc->soundData;
+ while (sampleOffset>=SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ sampleOffset -= SND_CHUNK_SIZE;
+ if (!chunk) {
+ chunk = sc->soundData;
+ }
+ }
+
+ if (!ch->doppler || ch->dopplerScale==1.0f) {
+ vector signed short volume_vec;
+ vector unsigned int volume_shift;
+ int vectorCount, samplesLeft, chunkSamplesLeft;
+ leftvol = ch->leftvol*snd_vol;
+ rightvol = ch->rightvol*snd_vol;
+ samples = chunk->sndChunk;
+ ((short *)&volume_vec)[0] = leftvol;
+ ((short *)&volume_vec)[1] = leftvol;
+ ((short *)&volume_vec)[4] = leftvol;
+ ((short *)&volume_vec)[5] = leftvol;
+ ((short *)&volume_vec)[2] = rightvol;
+ ((short *)&volume_vec)[3] = rightvol;
+ ((short *)&volume_vec)[6] = rightvol;
+ ((short *)&volume_vec)[7] = rightvol;
+ volume_shift = vec_splat_u32(8);
+ i = 0;
+
+ while(i < count) {
+ /* Try to align destination to 16-byte boundary */
+ while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) {
+ data = samples[sampleOffset++];
+ samp[i].left += (data * leftvol)>>8;
+
+ if ( sc->soundChannels == 2 ) {
+ data = samples[sampleOffset++];
+ }
+ samp[i].right += (data * rightvol)>>8;
+
+ if (sampleOffset == SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ samples = chunk->sndChunk;
+ sampleOffset = 0;
+ }
+ i++;
+ }
+ /* Destination is now aligned. Process as many 8-sample
+ chunks as we can before we run out of room from the current
+ sound chunk. We do 8 per loop to avoid extra source data reads. */
+ samplesLeft = count - i;
+ chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset;
+ if(samplesLeft > chunkSamplesLeft)
+ samplesLeft = chunkSamplesLeft;
+
+ vectorCount = samplesLeft / 8;
+
+ if(vectorCount)
+ {
+ vector unsigned char tmp;
+ vector short s0, s1, sampleData0, sampleData1;
+ vector signed int merge0, merge1;
+ vector signed int d0, d1, d2, d3;
+ vector unsigned char samplePermute0 =
+ VECCONST_UINT8(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7);
+ vector unsigned char samplePermute1 =
+ VECCONST_UINT8(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15);
+ vector unsigned char loadPermute0, loadPermute1;
+
+ // Rather than permute the vectors after we load them to do the sample
+ // replication and rearrangement, we permute the alignment vector so
+ // we do everything in one step below and avoid data shuffling.
+ tmp = vec_lvsl(0,&samples[sampleOffset]);
+ loadPermute0 = vec_perm(tmp,tmp,samplePermute0);
+ loadPermute1 = vec_perm(tmp,tmp,samplePermute1);
+
+ s0 = *(vector short *)&samples[sampleOffset];
+ while(vectorCount)
+ {
+ /* Load up source (16-bit) sample data */
+ s1 = *(vector short *)&samples[sampleOffset+7];
+
+ /* Load up destination sample data */
+ d0 = *(vector signed int *)&samp[i];
+ d1 = *(vector signed int *)&samp[i+2];
+ d2 = *(vector signed int *)&samp[i+4];
+ d3 = *(vector signed int *)&samp[i+6];
+
+ sampleData0 = vec_perm(s0,s1,loadPermute0);
+ sampleData1 = vec_perm(s0,s1,loadPermute1);
+
+ merge0 = vec_mule(sampleData0,volume_vec);
+ merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
+
+ merge1 = vec_mulo(sampleData0,volume_vec);
+ merge1 = vec_sra(merge1,volume_shift);
+
+ d0 = vec_add(merge0,d0);
+ d1 = vec_add(merge1,d1);
+
+ merge0 = vec_mule(sampleData1,volume_vec);
+ merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
+
+ merge1 = vec_mulo(sampleData1,volume_vec);
+ merge1 = vec_sra(merge1,volume_shift);
+
+ d2 = vec_add(merge0,d2);
+ d3 = vec_add(merge1,d3);
+
+ /* Store destination sample data */
+ *(vector signed int *)&samp[i] = d0;
+ *(vector signed int *)&samp[i+2] = d1;
+ *(vector signed int *)&samp[i+4] = d2;
+ *(vector signed int *)&samp[i+6] = d3;
+
+ i += 8;
+ vectorCount--;
+ s0 = s1;
+ sampleOffset += 8;
+ }
+ if (sampleOffset == SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ samples = chunk->sndChunk;
+ sampleOffset = 0;
+ }
+ }
+ }
+ } else {
+ fleftvol = ch->leftvol*snd_vol;
+ frightvol = ch->rightvol*snd_vol;
+
+ ooff = sampleOffset;
+ samples = chunk->sndChunk;
+
+ for ( i=0 ; i<count ; i++ ) {
+
+ aoff = ooff;
+ ooff = ooff + ch->dopplerScale * sc->soundChannels;
+ boff = ooff;
+ fdata[0] = fdata[1] = 0;
+ for (j=aoff; j<boff; j += sc->soundChannels) {
+ if (j == SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ if (!chunk) {
+ chunk = sc->soundData;
+ }
+ samples = chunk->sndChunk;
+ ooff -= SND_CHUNK_SIZE;
+ }
+ if ( sc->soundChannels == 2 ) {
+ fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
+ fdata[1] += samples[(j+1)&(SND_CHUNK_SIZE-1)];
+ } else {
+ fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
+ fdata[1] += samples[j&(SND_CHUNK_SIZE-1)];
+ }
+ }
+ fdiv = 256 * (boff-aoff) / sc->soundChannels;
+ samp[i].left += (fdata[0] * fleftvol)/fdiv;
+ samp[i].right += (fdata[1] * frightvol)/fdiv;
+ }
+ }
+}
+#endif
+
+static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
+ int data, aoff, boff;
+ int leftvol, rightvol;
+ int i, j;
+ portable_samplepair_t *samp;
+ sndBuffer *chunk;
+ short *samples;
+ float ooff, fdata[2], fdiv, fleftvol, frightvol;
+
+ if (sc->soundChannels <= 0) {
+ return;
+ }
+
+ samp = &paintbuffer[ bufferOffset ];
+
+ if (ch->doppler) {
+ sampleOffset = sampleOffset*ch->oldDopplerScale;
+ }
+
+ if ( sc->soundChannels == 2 ) {
+ sampleOffset *= sc->soundChannels;
+
+ if ( sampleOffset & 1 ) {
+ sampleOffset &= ~1;
+ }
+ }
+
+ chunk = sc->soundData;
+ while (sampleOffset>=SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ sampleOffset -= SND_CHUNK_SIZE;
+ if (!chunk) {
+ chunk = sc->soundData;
+ }
+ }
+
+ if (!ch->doppler || ch->dopplerScale==1.0f) {
+ leftvol = ch->leftvol*snd_vol;
+ rightvol = ch->rightvol*snd_vol;
+ samples = chunk->sndChunk;
+ for ( i=0 ; i<count ; i++ ) {
+ data = samples[sampleOffset++];
+ samp[i].left += (data * leftvol)>>8;
+
+ if ( sc->soundChannels == 2 ) {
+ data = samples[sampleOffset++];
+ }
+ samp[i].right += (data * rightvol)>>8;
+
+ if (sampleOffset == SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ samples = chunk->sndChunk;
+ sampleOffset = 0;
+ }
+ }
+ } else {
+ fleftvol = ch->leftvol*snd_vol;
+ frightvol = ch->rightvol*snd_vol;
+
+ ooff = sampleOffset;
+ samples = chunk->sndChunk;
+
+
+
+
+ for ( i=0 ; i<count ; i++ ) {
+
+ aoff = ooff;
+ ooff = ooff + ch->dopplerScale * sc->soundChannels;
+ boff = ooff;
+ fdata[0] = fdata[1] = 0;
+ for (j=aoff; j<boff; j += sc->soundChannels) {
+ if (j == SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ if (!chunk) {
+ chunk = sc->soundData;
+ }
+ samples = chunk->sndChunk;
+ ooff -= SND_CHUNK_SIZE;
+ }
+ if ( sc->soundChannels == 2 ) {
+ fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
+ fdata[1] += samples[(j+1)&(SND_CHUNK_SIZE-1)];
+ } else {
+ fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
+ fdata[1] += samples[j&(SND_CHUNK_SIZE-1)];
+ }
+ }
+ fdiv = 256 * (boff-aoff) / sc->soundChannels;
+ samp[i].left += (fdata[0] * fleftvol)/fdiv;
+ samp[i].right += (fdata[1] * frightvol)/fdiv;
+ }
+ }
+}
+
+static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
+#if idppc_altivec
+ if (com_altivec->integer) {
+ // must be in a seperate function or G3 systems will crash.
+ S_PaintChannelFrom16_altivec( ch, sc, count, sampleOffset, bufferOffset );
+ return;
+ }
+#endif
+ S_PaintChannelFrom16_scalar( ch, sc, count, sampleOffset, bufferOffset );
+}
+
+void S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
+ int data;
+ int leftvol, rightvol;
+ int i;
+ portable_samplepair_t *samp;
+ sndBuffer *chunk;
+ short *samples;
+
+ leftvol = ch->leftvol*snd_vol;
+ rightvol = ch->rightvol*snd_vol;
+
+ i = 0;
+ samp = &paintbuffer[ bufferOffset ];
+ chunk = sc->soundData;
+ while (sampleOffset>=(SND_CHUNK_SIZE_FLOAT*4)) {
+ chunk = chunk->next;
+ sampleOffset -= (SND_CHUNK_SIZE_FLOAT*4);
+ i++;
+ }
+
+ if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
+ S_AdpcmGetSamples( chunk, sfxScratchBuffer );
+ sfxScratchIndex = i;
+ sfxScratchPointer = sc;
+ }
+
+ samples = sfxScratchBuffer;
+
+ for ( i=0 ; i<count ; i++ ) {
+ data = samples[sampleOffset++];
+ samp[i].left += (data * leftvol)>>8;
+ samp[i].right += (data * rightvol)>>8;
+
+ if (sampleOffset == SND_CHUNK_SIZE*2) {
+ chunk = chunk->next;
+ decodeWavelet(chunk, sfxScratchBuffer);
+ sfxScratchIndex++;
+ sampleOffset = 0;
+ }
+ }
+}
+
+void S_PaintChannelFromADPCM( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
+ int data;
+ int leftvol, rightvol;
+ int i;
+ portable_samplepair_t *samp;
+ sndBuffer *chunk;
+ short *samples;
+
+ leftvol = ch->leftvol*snd_vol;
+ rightvol = ch->rightvol*snd_vol;
+
+ i = 0;
+ samp = &paintbuffer[ bufferOffset ];
+ chunk = sc->soundData;
+
+ if (ch->doppler) {
+ sampleOffset = sampleOffset*ch->oldDopplerScale;
+ }
+
+ while (sampleOffset>=(SND_CHUNK_SIZE*4)) {
+ chunk = chunk->next;
+ sampleOffset -= (SND_CHUNK_SIZE*4);
+ i++;
+ }
+
+ if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
+ S_AdpcmGetSamples( chunk, sfxScratchBuffer );
+ sfxScratchIndex = i;
+ sfxScratchPointer = sc;
+ }
+
+ samples = sfxScratchBuffer;
+
+ for ( i=0 ; i<count ; i++ ) {
+ data = samples[sampleOffset++];
+ samp[i].left += (data * leftvol)>>8;
+ samp[i].right += (data * rightvol)>>8;
+
+ if (sampleOffset == SND_CHUNK_SIZE*4) {
+ chunk = chunk->next;
+ S_AdpcmGetSamples( chunk, sfxScratchBuffer);
+ sampleOffset = 0;
+ sfxScratchIndex++;
+ }
+ }
+}
+
+void S_PaintChannelFromMuLaw( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
+ int data;
+ int leftvol, rightvol;
+ int i;
+ portable_samplepair_t *samp;
+ sndBuffer *chunk;
+ byte *samples;
+ float ooff;
+
+ leftvol = ch->leftvol*snd_vol;
+ rightvol = ch->rightvol*snd_vol;
+
+ samp = &paintbuffer[ bufferOffset ];
+ chunk = sc->soundData;
+ while (sampleOffset>=(SND_CHUNK_SIZE*2)) {
+ chunk = chunk->next;
+ sampleOffset -= (SND_CHUNK_SIZE*2);
+ if (!chunk) {
+ chunk = sc->soundData;
+ }
+ }
+
+ if (!ch->doppler) {
+ samples = (byte *)chunk->sndChunk + sampleOffset;
+ for ( i=0 ; i<count ; i++ ) {
+ data = mulawToShort[*samples];
+ samp[i].left += (data * leftvol)>>8;
+ samp[i].right += (data * rightvol)>>8;
+ samples++;
+ if (chunk != NULL && samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {
+ chunk = chunk->next;
+ samples = (byte *)chunk->sndChunk;
+ }
+ }
+ } else {
+ ooff = sampleOffset;
+ samples = (byte *)chunk->sndChunk;
+ for ( i=0 ; i<count ; i++ ) {
+ data = mulawToShort[samples[(int)(ooff)]];
+ ooff = ooff + ch->dopplerScale;
+ samp[i].left += (data * leftvol)>>8;
+ samp[i].right += (data * rightvol)>>8;
+ if (ooff >= SND_CHUNK_SIZE*2) {
+ chunk = chunk->next;
+ if (!chunk) {
+ chunk = sc->soundData;
+ }
+ samples = (byte *)chunk->sndChunk;
+ ooff = 0.0;
+ }
+ }
+ }
+}
+
+/*
+===================
+S_PaintChannels
+===================
+*/
+void S_PaintChannels( int endtime ) {
+ int i;
+ int end;
+ int stream;
+ channel_t *ch;
+ sfx_t *sc;
+ int ltime, count;
+ int sampleOffset;
+
+ if(s_muted->integer)
+ snd_vol = 0;
+ else
+ snd_vol = s_volume->value*255;
+
+//Com_Printf ("%i to %i\n", s_paintedtime, endtime);
+ while ( s_paintedtime < endtime ) {
+ // if paintbuffer is smaller than DMA buffer
+ // we may need to fill it multiple times
+ end = endtime;
+ if ( endtime - s_paintedtime > PAINTBUFFER_SIZE ) {
+ end = s_paintedtime + PAINTBUFFER_SIZE;
+ }
+
+ // clear the paint buffer and mix any raw samples...
+ ::memset(paintbuffer, 0, sizeof (paintbuffer));
+ for (stream = 0; stream < MAX_RAW_STREAMS; stream++) {
+ if ( s_rawend[stream] >= s_paintedtime ) {
+ // copy from the streaming sound source
+ const portable_samplepair_t *rawsamples = s_rawsamples[stream];
+ const int stop = (end < s_rawend[stream]) ? end : s_rawend[stream];
+ for ( i = s_paintedtime ; i < stop ; i++ ) {
+ const int s = i&(MAX_RAW_SAMPLES-1);
+ paintbuffer[i-s_paintedtime].left += rawsamples[s].left;
+ paintbuffer[i-s_paintedtime].right += rawsamples[s].right;
+ }
+ }
+ }
+
+ // paint in the channels.
+ ch = s_channels;
+ for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {
+ if ( !ch->thesfx || (ch->leftvol<0.25 && ch->rightvol<0.25 )) {
+ continue;
+ }
+
+ ltime = s_paintedtime;
+ sc = ch->thesfx;
+
+ if (sc->soundData==NULL || sc->soundLength==0) {
+ continue;
+ }
+
+ sampleOffset = ltime - ch->startSample;
+ count = end - ltime;
+ if ( sampleOffset + count > sc->soundLength ) {
+ count = sc->soundLength - sampleOffset;
+ }
+
+ if ( count > 0 ) {
+ if( sc->soundCompressionMethod == 1) {
+ S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else if( sc->soundCompressionMethod == 2) {
+ S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else if( sc->soundCompressionMethod == 3) {
+ S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else {
+ S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ }
+ }
+ }
+
+ // paint in the looped channels.
+ ch = loop_channels;
+ for ( i = 0; i < numLoopChannels ; i++, ch++ ) {
+ if ( !ch->thesfx || (!ch->leftvol && !ch->rightvol )) {
+ continue;
+ }
+
+ ltime = s_paintedtime;
+ sc = ch->thesfx;
+
+ if (sc->soundData==NULL || sc->soundLength==0) {
+ continue;
+ }
+ // we might have to make two passes if it
+ // is a looping sound effect and the end of
+ // the sample is hit
+ do {
+ sampleOffset = (ltime % sc->soundLength);
+
+ count = end - ltime;
+ if ( sampleOffset + count > sc->soundLength ) {
+ count = sc->soundLength - sampleOffset;
+ }
+
+ if ( count > 0 ) {
+ if( sc->soundCompressionMethod == 1) {
+ S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else if( sc->soundCompressionMethod == 2) {
+ S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else if( sc->soundCompressionMethod == 3) {
+ S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else {
+ S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ }
+ ltime += count;
+ }
+ } while ( ltime < end);
+ }
+
+ // transfer out according to DMA format
+ S_TransferPaintBuffer( end );
+ s_paintedtime = end;
+ }
+}
diff --git a/src/client/snd_openal.cpp b/src/client/snd_openal.cpp
new file mode 100644
index 0000000..7ee53e2
--- /dev/null
+++ b/src/client/snd_openal.cpp
@@ -0,0 +1,2737 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "snd_local.h"
+#include "snd_codec.h"
+#include "client.h"
+
+#ifdef USE_OPENAL
+
+#include "qal.h"
+
+// Console variables specific to OpenAL
+cvar_t *s_alPrecache;
+cvar_t *s_alGain;
+cvar_t *s_alSources;
+cvar_t *s_alDopplerFactor;
+cvar_t *s_alDopplerSpeed;
+cvar_t *s_alMinDistance;
+cvar_t *s_alMaxDistance;
+cvar_t *s_alRolloff;
+cvar_t *s_alGraceDistance;
+cvar_t *s_alDriver;
+cvar_t *s_alDevice;
+cvar_t *s_alInputDevice;
+cvar_t *s_alAvailableDevices;
+cvar_t *s_alAvailableInputDevices;
+
+static bool enumeration_ext = false;
+static bool enumeration_all_ext = false;
+#ifdef USE_VOIP
+static bool capture_ext = false;
+#endif
+
+/*
+=================
+S_AL_Format
+=================
+*/
+static
+ALuint S_AL_Format(int width, int channels)
+{
+ ALuint format = AL_FORMAT_MONO16;
+
+ // Work out format
+ if(width == 1)
+ {
+ if(channels == 1)
+ format = AL_FORMAT_MONO8;
+ else if(channels == 2)
+ format = AL_FORMAT_STEREO8;
+ }
+ else if(width == 2)
+ {
+ if(channels == 1)
+ format = AL_FORMAT_MONO16;
+ else if(channels == 2)
+ format = AL_FORMAT_STEREO16;
+ }
+
+ return format;
+}
+
+/*
+=================
+S_AL_ErrorMsg
+=================
+*/
+static const char *S_AL_ErrorMsg(ALenum error)
+{
+ switch(error)
+ {
+ case AL_NO_ERROR:
+ return "No error";
+ case AL_INVALID_NAME:
+ return "Invalid name";
+ case AL_INVALID_ENUM:
+ return "Invalid enumerator";
+ case AL_INVALID_VALUE:
+ return "Invalid value";
+ case AL_INVALID_OPERATION:
+ return "Invalid operation";
+ case AL_OUT_OF_MEMORY:
+ return "Out of memory";
+ default:
+ return "Unknown error";
+ }
+}
+
+/*
+=================
+S_AL_ClearError
+=================
+*/
+static void S_AL_ClearError( bool quiet )
+{
+ int error = qalGetError();
+
+ if( quiet )
+ return;
+ if(error != AL_NO_ERROR)
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: unhandled AL error: %s\n",
+ S_AL_ErrorMsg(error));
+ }
+}
+
+
+//===========================================================================
+
+
+typedef struct alSfx_s
+{
+ char filename[MAX_QPATH];
+ ALuint buffer; // OpenAL buffer
+ snd_info_t info; // information for this sound like rate, sample count..
+
+ bool isDefault; // Couldn't be loaded - use default FX
+ bool isDefaultChecked; // Sound has been check if it isDefault
+ bool inMemory; // Sound is stored in memory
+ bool isLocked; // Sound is locked (can not be unloaded)
+ int lastUsedTime; // Time last used
+
+ int duration; // Milliseconds
+
+ int loopCnt; // number of loops using this sfx
+ int loopActiveCnt; // number of playing loops using this sfx
+ int masterLoopSrc; // All other sources looping this buffer are synced to this master src
+} alSfx_t;
+
+static bool alBuffersInitialised = false;
+
+// Sound effect storage, data structures
+#define MAX_SFX 4096
+static alSfx_t knownSfx[MAX_SFX];
+static sfxHandle_t numSfx = 0;
+
+static sfxHandle_t default_sfx;
+
+/*
+=================
+S_AL_BufferFindFree
+
+Find a free handle
+=================
+*/
+static sfxHandle_t S_AL_BufferFindFree( void )
+{
+ int i;
+
+ for(i = 0; i < MAX_SFX; i++)
+ {
+ // Got one
+ if(knownSfx[i].filename[0] == '\0')
+ {
+ if(i >= numSfx)
+ numSfx = i + 1;
+ return i;
+ }
+ }
+
+ // Shit...
+ Com_Error(ERR_FATAL, "S_AL_BufferFindFree: No free sound handles");
+ return -1;
+}
+
+/*
+=================
+S_AL_BufferFind
+
+Find a sound effect if loaded, set up a handle otherwise
+=================
+*/
+static sfxHandle_t S_AL_BufferFind(const char *filename)
+{
+ // Look it up in the table
+ sfxHandle_t sfx = -1;
+ int i;
+
+ if ( !filename ) {
+ Com_Error( ERR_FATAL, "Sound name is NULL" );
+ }
+
+ if ( !filename[0] ) {
+ Com_Printf( S_COLOR_YELLOW "WARNING: Sound name is empty\n" );
+ return 0;
+ }
+
+ if ( strlen( filename ) >= MAX_QPATH ) {
+ Com_Printf( S_COLOR_YELLOW "WARNING: Sound name is too long: %s\n", filename );
+ return 0;
+ }
+
+ if ( filename[0] == '*' ) {
+ Com_Printf( S_COLOR_YELLOW "WARNING: Tried to load player sound directly: %s\n", filename );
+ return 0;
+ }
+
+ for(i = 0; i < numSfx; i++)
+ {
+ if(!Q_stricmp(knownSfx[i].filename, filename))
+ {
+ sfx = i;
+ break;
+ }
+ }
+
+ // Not found in table?
+ if(sfx == -1)
+ {
+ alSfx_t *ptr;
+
+ sfx = S_AL_BufferFindFree();
+
+ // Clear and copy the filename over
+ ptr = &knownSfx[sfx];
+ memset(ptr, 0, sizeof(*ptr));
+ ptr->masterLoopSrc = -1;
+ strcpy(ptr->filename, filename);
+ }
+
+ // Return the handle
+ return sfx;
+}
+
+/*
+=================
+S_AL_BufferUseDefault
+=================
+*/
+static void S_AL_BufferUseDefault(sfxHandle_t sfx)
+{
+ if(sfx == default_sfx)
+ Com_Error(ERR_FATAL, "Can't load default sound effect %s", knownSfx[sfx].filename);
+
+ Com_Printf( S_COLOR_YELLOW "WARNING: Using default sound for %s\n", knownSfx[sfx].filename);
+ knownSfx[sfx].isDefault = true;
+ knownSfx[sfx].buffer = knownSfx[default_sfx].buffer;
+}
+
+/*
+=================
+S_AL_BufferUnload
+=================
+*/
+static void S_AL_BufferUnload(sfxHandle_t sfx)
+{
+ if(knownSfx[sfx].filename[0] == '\0')
+ return;
+
+ if(!knownSfx[sfx].inMemory)
+ return;
+
+ // Delete it
+ S_AL_ClearError( false );
+ qalDeleteBuffers(1, &knownSfx[sfx].buffer);
+ if(qalGetError() != AL_NO_ERROR)
+ Com_Printf( S_COLOR_RED "ERROR: Can't delete sound buffer for %s\n",
+ knownSfx[sfx].filename);
+
+ knownSfx[sfx].inMemory = false;
+}
+
+/*
+=================
+S_AL_BufferEvict
+=================
+*/
+static bool S_AL_BufferEvict( void )
+{
+ int i, oldestBuffer = -1;
+ int oldestTime = Sys_Milliseconds( );
+
+ for( i = 0; i < numSfx; i++ )
+ {
+ if( !knownSfx[ i ].filename[ 0 ] )
+ continue;
+
+ if( !knownSfx[ i ].inMemory )
+ continue;
+
+ if( knownSfx[ i ].lastUsedTime < oldestTime )
+ {
+ oldestTime = knownSfx[ i ].lastUsedTime;
+ oldestBuffer = i;
+ }
+ }
+
+ if( oldestBuffer >= 0 )
+ {
+ S_AL_BufferUnload( oldestBuffer );
+ return true;
+ }
+ else
+ return false;
+}
+
+/*
+=================
+S_AL_GenBuffers
+=================
+*/
+static bool S_AL_GenBuffers(ALsizei numBuffers, ALuint *buffers, const char *name)
+{
+ S_AL_ClearError( false );
+ qalGenBuffers( numBuffers, buffers );
+ ALenum error = qalGetError();
+
+ // If we ran out of buffers, start evicting the least recently used sounds
+ while( error == AL_INVALID_VALUE )
+ {
+ if( !S_AL_BufferEvict( ) )
+ {
+ Com_Printf( S_COLOR_RED "ERROR: Out of audio buffers\n");
+ return false;
+ }
+
+ // Try again
+ S_AL_ClearError( false );
+ qalGenBuffers( numBuffers, buffers );
+ error = qalGetError();
+ }
+
+ if( error != AL_NO_ERROR )
+ {
+ Com_Printf( S_COLOR_RED "ERROR: Can't create a sound buffer for %s - %s\n",
+ name, S_AL_ErrorMsg(error));
+ return false;
+ }
+
+ return true;
+}
+
+/*
+=================
+S_AL_BufferLoad
+=================
+*/
+static void S_AL_BufferLoad(sfxHandle_t sfx, bool cache)
+{
+ ALenum error;
+ ALuint format;
+
+ void *data;
+ snd_info_t info;
+ alSfx_t *curSfx = &knownSfx[sfx];
+
+ // Nothing?
+ if(curSfx->filename[0] == '\0')
+ return;
+
+ // Already done?
+ if((curSfx->inMemory) || (curSfx->isDefault) || (!cache && curSfx->isDefaultChecked))
+ return;
+
+ // Try to load
+ data = S_CodecLoad(curSfx->filename, &info);
+ if(!data)
+ {
+ S_AL_BufferUseDefault(sfx);
+ return;
+ }
+
+ curSfx->isDefaultChecked = true;
+
+ if (!cache)
+ {
+ // Don't create AL cache
+ Hunk_FreeTempMemory(data);
+ return;
+ }
+
+ format = S_AL_Format(info.width, info.channels);
+
+ // Create a buffer
+ if (!S_AL_GenBuffers(1, &curSfx->buffer, curSfx->filename))
+ {
+ S_AL_BufferUseDefault(sfx);
+ Hunk_FreeTempMemory(data);
+ return;
+ }
+
+ // Fill the buffer
+ if( info.size == 0 )
+ {
+ // We have no data to buffer, so buffer silence
+ byte dummyData[ 2 ] = { 0 };
+
+ qalBufferData(curSfx->buffer, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050);
+ }
+ else
+ qalBufferData(curSfx->buffer, format, data, info.size, info.rate);
+
+ error = qalGetError();
+
+ // If we ran out of memory, start evicting the least recently used sounds
+ while(error == AL_OUT_OF_MEMORY)
+ {
+ if( !S_AL_BufferEvict( ) )
+ {
+ qalDeleteBuffers(1, &curSfx->buffer);
+ S_AL_BufferUseDefault(sfx);
+ Hunk_FreeTempMemory(data);
+ Com_Printf( S_COLOR_RED "ERROR: Out of memory loading %s\n", curSfx->filename);
+ return;
+ }
+
+ // Try load it again
+ qalBufferData(curSfx->buffer, format, data, info.size, info.rate);
+ error = qalGetError();
+ }
+
+ // Some other error condition
+ if(error != AL_NO_ERROR)
+ {
+ qalDeleteBuffers(1, &curSfx->buffer);
+ S_AL_BufferUseDefault(sfx);
+ Hunk_FreeTempMemory(data);
+ Com_Printf( S_COLOR_RED "ERROR: Can't fill sound buffer for %s - %s\n",
+ curSfx->filename, S_AL_ErrorMsg(error));
+ return;
+ }
+
+ curSfx->info = info;
+
+ // Free the memory
+ Hunk_FreeTempMemory(data);
+
+ // Woo!
+ curSfx->inMemory = true;
+}
+
+/*
+=================
+S_AL_BufferUse
+=================
+*/
+static void S_AL_BufferUse(sfxHandle_t sfx)
+{
+ if(knownSfx[sfx].filename[0] == '\0')
+ return;
+
+ if((!knownSfx[sfx].inMemory) && (!knownSfx[sfx].isDefault))
+ S_AL_BufferLoad(sfx, true);
+ knownSfx[sfx].lastUsedTime = Sys_Milliseconds();
+}
+
+/*
+=================
+S_AL_BufferInit
+=================
+*/
+static bool S_AL_BufferInit( void )
+{
+ if(alBuffersInitialised)
+ return true;
+
+ // Clear the hash table, and SFX table
+ memset(knownSfx, 0, sizeof(knownSfx));
+ numSfx = 0;
+
+ // Load the default sound, and lock it
+ default_sfx = S_AL_BufferFind("sound/feedback/hit.wav");
+ S_AL_BufferUse(default_sfx);
+ knownSfx[default_sfx].isLocked = true;
+
+ // All done
+ alBuffersInitialised = true;
+ return true;
+}
+
+/*
+=================
+S_AL_BufferShutdown
+=================
+*/
+static void S_AL_BufferShutdown( void )
+{
+ if(!alBuffersInitialised)
+ return;
+
+ // Unlock the default sound effect
+ knownSfx[default_sfx].isLocked = false;
+
+ // Free all used effects
+ for(int i = 0; i < numSfx; i++)
+ S_AL_BufferUnload(i);
+
+ // Clear the tables
+ numSfx = 0;
+
+ // All undone
+ alBuffersInitialised = false;
+}
+
+/*
+=================
+S_AL_RegisterSound
+=================
+*/
+static sfxHandle_t S_AL_RegisterSound( const char *sample, bool compressed )
+{
+ sfxHandle_t sfx = S_AL_BufferFind(sample);
+
+ if((!knownSfx[sfx].inMemory) && (!knownSfx[sfx].isDefault))
+ S_AL_BufferLoad(sfx, s_alPrecache->integer ? true : false);
+ knownSfx[sfx].lastUsedTime = Com_Milliseconds();
+
+ if (knownSfx[sfx].isDefault) {
+ return 0;
+ }
+
+ return sfx;
+}
+
+/*
+=================
+S_AL_SoundDuration
+=================
+*/
+static int S_AL_SoundDuration( sfxHandle_t sfx )
+{
+ if (sfx < 0 || sfx >= numSfx)
+ {
+ Com_Printf(S_COLOR_RED "ERROR: S_AL_SoundDuration: handle %i out of range\n", sfx);
+ return 0;
+ }
+ return knownSfx[sfx].duration;
+}
+
+/*
+=================
+S_AL_BufferGet
+
+Return's a sfx's buffer
+=================
+*/
+static
+ALuint S_AL_BufferGet(sfxHandle_t sfx)
+{
+ return knownSfx[sfx].buffer;
+}
+
+
+//===========================================================================
+
+
+typedef struct src_s
+{
+ ALuint alSource; // OpenAL source object
+ sfxHandle_t sfx; // Sound effect in use
+
+ int lastUsedTime; // Last time used
+ alSrcPriority_t priority; // Priority
+ int entity; // Owning entity (-1 if none)
+ int channel; // Associated channel (-1 if none)
+
+ bool isActive; // Is this source currently in use?
+ bool isPlaying; // Is this source currently playing, or stopped?
+ bool isLocked; // This is locked (un-allocatable)
+ bool isLooping; // Is this a looping effect (attached to an entity)
+ bool isTracking; // Is this object tracking its owner
+ bool isStream; // Is this source a stream
+
+ float curGain; // gain employed if source is within maxdistance.
+ float scaleGain; // Last gain value for this source. 0 if muted.
+
+ float lastTimePos; // On stopped loops, the last position in the buffer
+ int lastSampleTime; // Time when this was stopped
+ vec3_t loopSpeakerPos; // Origin of the loop speaker
+
+ bool local; // Is this local (relative to the cam)
+} src_t;
+
+#ifdef __APPLE__
+ #define MAX_SRC 64
+#else
+ #define MAX_SRC 128
+#endif
+static src_t srcList[MAX_SRC];
+static int srcCount = 0;
+static int srcActiveCnt = 0;
+static bool alSourcesInitialised = false;
+static int lastListenerNumber = -1;
+static vec3_t lastListenerOrigin = { 0.0f, 0.0f, 0.0f };
+
+typedef struct sentity_s
+{
+ vec3_t origin;
+
+ bool srcAllocated; // If a src_t has been allocated to this entity
+ int srcIndex;
+
+ bool loopAddedThisFrame;
+ alSrcPriority_t loopPriority;
+ sfxHandle_t loopSfx;
+ bool startLoopingSound;
+} sentity_t;
+
+static sentity_t entityList[MAX_GENTITIES];
+
+/*
+=================
+S_AL_SanitiseVector
+=================
+*/
+#define S_AL_SanitiseVector(v) _S_AL_SanitiseVector(v,__LINE__)
+static void _S_AL_SanitiseVector( vec3_t v, int line )
+{
+ if( Q_isnan( v[ 0 ] ) || Q_isnan( v[ 1 ] ) || Q_isnan( v[ 2 ] ) )
+ {
+ Com_DPrintf( S_COLOR_YELLOW "WARNING: vector with one or more NaN components "
+ "being passed to OpenAL at %s:%d -- zeroing\n", __FILE__, line );
+ VectorClear( v );
+ }
+}
+
+/*
+=================
+S_AL_Gain
+Set gain to 0 if muted, otherwise set it to given value.
+=================
+*/
+
+static void S_AL_Gain(ALuint source, float gainval)
+{
+ if(s_muted->integer)
+ qalSourcef(source, AL_GAIN, 0.0f);
+ else
+ qalSourcef(source, AL_GAIN, gainval);
+}
+
+/*
+=================
+S_AL_ScaleGain
+Adapt the gain if necessary to get a quicker fadeout when the source is too far away.
+=================
+*/
+
+static void S_AL_ScaleGain(src_t *chksrc, vec3_t origin)
+{
+ float distance;
+
+ if(!chksrc->local)
+ distance = Distance(origin, lastListenerOrigin);
+
+ // If we exceed a certain distance, scale the gain linearly until the sound
+ // vanishes into nothingness.
+ if(!chksrc->local && (distance -= s_alMaxDistance->value) > 0)
+ {
+ float scaleFactor;
+
+ if(distance >= s_alGraceDistance->value)
+ scaleFactor = 0.0f;
+ else
+ scaleFactor = 1.0f - distance / s_alGraceDistance->value;
+
+ scaleFactor *= chksrc->curGain;
+
+ if(chksrc->scaleGain != scaleFactor)
+ {
+ chksrc->scaleGain = scaleFactor;
+ S_AL_Gain(chksrc->alSource, chksrc->scaleGain);
+ }
+ }
+ else if(chksrc->scaleGain != chksrc->curGain)
+ {
+ chksrc->scaleGain = chksrc->curGain;
+ S_AL_Gain(chksrc->alSource, chksrc->scaleGain);
+ }
+}
+
+/*
+=================
+S_AL_HearingThroughEntity
+
+Also see S_Base_HearingThroughEntity
+=================
+*/
+static bool S_AL_HearingThroughEntity( int entityNum )
+{
+
+ if( lastListenerNumber == entityNum )
+ {
+ // This is an outrageous hack to detect
+ // whether or not the player is rendering in third person or not. We can't
+ // ask the renderer because the renderer has no notion of entities and we
+ // can't ask cgame since that would involve changing the API and hence mod
+ // compatibility. I don't think there is any way around this, but I'll leave
+ // the FIXME just in case anyone has a bright idea.
+ float distanceSq = DistanceSquared( entityList[ entityNum ].origin, lastListenerOrigin );
+ if( distanceSq > THIRD_PERSON_THRESHOLD_SQ )
+ return false; //we're the player, but third person
+
+ //we're the player
+ return true;
+ }
+
+ //not the player
+ return false;
+}
+
+/*
+=================
+S_AL_SrcInit
+=================
+*/
+static bool S_AL_SrcInit( void )
+{
+ int i;
+ int limit;
+
+ // Clear the sources data structure
+ memset(srcList, 0, sizeof(srcList));
+ srcCount = 0;
+ srcActiveCnt = 0;
+
+ // Cap s_alSources to MAX_SRC
+ limit = s_alSources->integer;
+ if(limit > MAX_SRC)
+ limit = MAX_SRC;
+ else if(limit < 16)
+ limit = 16;
+
+ S_AL_ClearError( false );
+ // Allocate as many sources as possible
+ for(i = 0; i < limit; i++)
+ {
+ qalGenSources(1, &srcList[i].alSource);
+ if(qalGetError() != AL_NO_ERROR)
+ break;
+ srcCount++;
+ }
+
+ // All done. Print this for informational purposes
+ Com_Printf( "Allocated %d sources.\n", srcCount);
+ alSourcesInitialised = true;
+ return true;
+}
+
+/*
+=================
+S_AL_SrcShutdown
+=================
+*/
+static
+void S_AL_SrcShutdown( void )
+{
+ int i;
+ src_t *curSource;
+
+ if(!alSourcesInitialised)
+ return;
+
+ // Destroy all the sources
+ for(i = 0; i < srcCount; i++)
+ {
+ curSource = &srcList[i];
+
+ if(curSource->isLocked)
+ Com_DPrintf( S_COLOR_YELLOW "WARNING: Source %d is locked\n", i);
+
+ if(curSource->entity > 0)
+ entityList[curSource->entity].srcAllocated = false;
+
+ qalSourceStop(srcList[i].alSource);
+ qalDeleteSources(1, &srcList[i].alSource);
+ }
+
+ memset(srcList, 0, sizeof(srcList));
+
+ alSourcesInitialised = false;
+}
+
+/*
+=================
+S_AL_SrcSetup
+=================
+*/
+static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t priority, int entity, int channel, bool local)
+{
+ src_t *curSource;
+
+ // Set up src struct
+ curSource = &srcList[src];
+
+ curSource->lastUsedTime = Sys_Milliseconds();
+ curSource->sfx = sfx;
+ curSource->priority = priority;
+ curSource->entity = entity;
+ curSource->channel = channel;
+ curSource->isPlaying = false;
+ curSource->isLocked = false;
+ curSource->isLooping = false;
+ curSource->isTracking = false;
+ curSource->isStream = false;
+ curSource->curGain = s_alGain->value * s_volume->value;
+ curSource->scaleGain = curSource->curGain;
+ curSource->local = local;
+
+ // Set up OpenAL source
+ if(sfx >= 0)
+ {
+ // Mark the SFX as used, and grab the raw AL buffer
+ S_AL_BufferUse(sfx);
+ qalSourcei(curSource->alSource, AL_BUFFER, S_AL_BufferGet(sfx));
+ }
+
+ qalSourcef(curSource->alSource, AL_PITCH, 1.0f);
+ S_AL_Gain(curSource->alSource, curSource->curGain);
+ qalSourcefv(curSource->alSource, AL_POSITION, vec3_origin);
+ qalSourcefv(curSource->alSource, AL_VELOCITY, vec3_origin);
+ qalSourcei(curSource->alSource, AL_LOOPING, AL_FALSE);
+ qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
+
+ if(local)
+ {
+ qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE);
+ qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f);
+ }
+ else
+ {
+ qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE);
+ qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
+ }
+}
+
+/*
+=================
+S_AL_SaveLoopPos
+Remove given source as loop master if it is the master and hand off master status to another source in this case.
+=================
+*/
+
+static void S_AL_SaveLoopPos(src_t *dest, ALuint alSource)
+{
+ int error;
+
+ S_AL_ClearError(false);
+
+ qalGetSourcef(alSource, AL_SEC_OFFSET, &dest->lastTimePos);
+ if((error = qalGetError()) != AL_NO_ERROR)
+ {
+ // Old OpenAL implementations don't support AL_SEC_OFFSET
+
+ if(error != AL_INVALID_ENUM)
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: Could not get time offset for alSource %d: %s\n",
+ alSource, S_AL_ErrorMsg(error));
+ }
+
+ dest->lastTimePos = -1;
+ }
+ else
+ dest->lastSampleTime = Sys_Milliseconds();
+}
+
+/*
+=================
+S_AL_NewLoopMaster
+Remove given source as loop master if it is the master and hand off master status to another source in this case.
+=================
+*/
+
+static void S_AL_NewLoopMaster(src_t *rmSource, bool iskilled)
+{
+ int index;
+ src_t *curSource = NULL;
+ alSfx_t *curSfx;
+
+ curSfx = &knownSfx[rmSource->sfx];
+
+ if(rmSource->isPlaying)
+ curSfx->loopActiveCnt--;
+ if(iskilled)
+ curSfx->loopCnt--;
+
+ if(curSfx->loopCnt)
+ {
+ if(rmSource->priority == SRCPRI_ENTITY)
+ {
+ if(!iskilled && rmSource->isPlaying)
+ {
+ // only sync ambient loops...
+ // It makes more sense to have sounds for weapons/projectiles unsynced
+ S_AL_SaveLoopPos(rmSource, rmSource->alSource);
+ }
+ }
+ else if(rmSource == &srcList[curSfx->masterLoopSrc])
+ {
+ int firstInactive = -1;
+
+ // Only if rmSource was the master and if there are still playing loops for
+ // this sound will we need to find a new master.
+
+ if(iskilled || curSfx->loopActiveCnt)
+ {
+ for(index = 0; index < srcCount; index++)
+ {
+ curSource = &srcList[index];
+
+ if(curSource->sfx == rmSource->sfx && curSource != rmSource &&
+ curSource->isActive && curSource->isLooping && curSource->priority == SRCPRI_AMBIENT)
+ {
+ if(curSource->isPlaying)
+ {
+ curSfx->masterLoopSrc = index;
+ break;
+ }
+ else if(firstInactive < 0)
+ firstInactive = index;
+ }
+ }
+ }
+
+ if(!curSfx->loopActiveCnt)
+ {
+ if(firstInactive < 0)
+ {
+ if(iskilled)
+ {
+ curSfx->masterLoopSrc = -1;
+ return;
+ }
+ else
+ curSource = rmSource;
+ }
+ else
+ curSource = &srcList[firstInactive];
+
+ if(rmSource->isPlaying)
+ {
+ // this was the last not stopped source, save last sample position + time
+ S_AL_SaveLoopPos(curSource, rmSource->alSource);
+ }
+ else
+ {
+ // second case: all loops using this sound have stopped due to listener being of of range,
+ // and now the inactive master gets deleted. Just move over the soundpos settings to the
+ // new master.
+ curSource->lastTimePos = rmSource->lastTimePos;
+ curSource->lastSampleTime = rmSource->lastSampleTime;
+ }
+ }
+ }
+ }
+ else
+ curSfx->masterLoopSrc = -1;
+}
+
+/*
+=================
+S_AL_SrcKill
+=================
+*/
+static void S_AL_SrcKill(srcHandle_t src)
+{
+ src_t *curSource = &srcList[src];
+
+ // I'm not touching it. Unlock it first.
+ if(curSource->isLocked)
+ return;
+
+ // Remove the entity association and loop master status
+ if(curSource->isLooping)
+ {
+ curSource->isLooping = false;
+
+ if(curSource->entity != -1)
+ {
+ sentity_t *curEnt = &entityList[curSource->entity];
+
+ curEnt->srcAllocated = false;
+ curEnt->srcIndex = -1;
+ curEnt->loopAddedThisFrame = false;
+ curEnt->startLoopingSound = false;
+ }
+
+ S_AL_NewLoopMaster(curSource, true);
+ }
+
+ // Stop it if it's playing
+ if(curSource->isPlaying)
+ {
+ qalSourceStop(curSource->alSource);
+ curSource->isPlaying = false;
+ }
+
+ // Detach any buffers
+ qalSourcei(curSource->alSource, AL_BUFFER, 0);
+
+ curSource->sfx = 0;
+ curSource->lastUsedTime = 0;
+ curSource->priority = SRCPRI_AMBIENT;
+ curSource->entity = -1;
+ curSource->channel = -1;
+ if(curSource->isActive)
+ {
+ curSource->isActive = false;
+ srcActiveCnt--;
+ }
+ curSource->isLocked = false;
+ curSource->isTracking = false;
+ curSource->local = false;
+}
+
+/*
+=================
+S_AL_SrcAlloc
+=================
+*/
+static
+srcHandle_t S_AL_SrcAlloc( alSrcPriority_t priority, int entnum, int channel )
+{
+ int i;
+ int empty = -1;
+ int weakest = -1;
+ int weakest_time = Sys_Milliseconds();
+ int weakest_pri = 999;
+ float weakest_gain = 1000.0;
+ bool weakest_isplaying = true;
+ int weakest_numloops = 0;
+ src_t *curSource;
+
+ for(i = 0; i < srcCount; i++)
+ {
+ curSource = &srcList[i];
+
+ // If it's locked, we aren't even going to look at it
+ if(curSource->isLocked)
+ continue;
+
+ // Is it empty or not?
+ if(!curSource->isActive)
+ {
+ empty = i;
+ break;
+ }
+
+ if(curSource->isPlaying)
+ {
+ if(weakest_isplaying && curSource->priority < priority &&
+ (curSource->priority < weakest_pri ||
+ (!curSource->isLooping && (curSource->scaleGain < weakest_gain || curSource->lastUsedTime < weakest_time))))
+ {
+ // If it has lower priority, is fainter or older, flag it as weak
+ // the last two values are only compared if it's not a looping sound, because we want to prevent two
+ // loops (loops are added EVERY frame) fighting for a slot
+ weakest_pri = curSource->priority;
+ weakest_time = curSource->lastUsedTime;
+ weakest_gain = curSource->scaleGain;
+ weakest = i;
+ }
+ }
+ else
+ {
+ weakest_isplaying = false;
+
+ if(weakest < 0 ||
+ knownSfx[curSource->sfx].loopCnt > weakest_numloops ||
+ curSource->priority < weakest_pri ||
+ curSource->lastUsedTime < weakest_time)
+ {
+ // Sources currently not playing of course have lowest priority
+ // also try to always keep at least one loop master for every loop sound
+ weakest_pri = curSource->priority;
+ weakest_time = curSource->lastUsedTime;
+ weakest_numloops = knownSfx[curSource->sfx].loopCnt;
+ weakest = i;
+ }
+ }
+
+ // The channel system is not actually adhered to by baseq3, and not
+ // implemented in snd_dma.c, so while the following is strictly correct, it
+ // causes incorrect behaviour versus defacto baseq3
+#if 0
+ // Is it an exact match, and not on channel 0?
+ if((curSource->entity == entnum) && (curSource->channel == channel) && (channel != 0))
+ {
+ S_AL_SrcKill(i);
+ return i;
+ }
+#endif
+ }
+
+ if(empty == -1)
+ empty = weakest;
+
+ if(empty >= 0)
+ {
+ S_AL_SrcKill(empty);
+ srcList[empty].isActive = true;
+ srcActiveCnt++;
+ }
+
+ return empty;
+}
+
+/*
+=================
+S_AL_SrcFind
+
+Finds an active source with matching entity and channel numbers
+Returns -1 if there isn't one
+=================
+*/
+#if 0
+static
+srcHandle_t S_AL_SrcFind(int entnum, int channel)
+{
+ int i;
+ for(i = 0; i < srcCount; i++)
+ {
+ if(!srcList[i].isActive)
+ continue;
+ if((srcList[i].entity == entnum) && (srcList[i].channel == channel))
+ return i;
+ }
+ return -1;
+}
+#endif
+
+/*
+=================
+S_AL_SrcLock
+
+Locked sources will not be automatically reallocated or managed
+=================
+*/
+static
+void S_AL_SrcLock(srcHandle_t src)
+{
+ srcList[src].isLocked = true;
+}
+
+/*
+=================
+S_AL_SrcUnlock
+
+Once unlocked, the source may be reallocated again
+=================
+*/
+static
+void S_AL_SrcUnlock(srcHandle_t src)
+{
+ srcList[src].isLocked = false;
+}
+
+/*
+=================
+S_AL_UpdateEntityPosition
+=================
+*/
+static
+void S_AL_UpdateEntityPosition( int entityNum, const vec3_t origin )
+{
+ vec3_t sanOrigin;
+
+ VectorCopy( origin, sanOrigin );
+ S_AL_SanitiseVector( sanOrigin );
+ if ( entityNum < 0 || entityNum >= MAX_GENTITIES )
+ Com_Error( ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum );
+ VectorCopy( sanOrigin, entityList[entityNum].origin );
+}
+
+/*
+=================
+S_AL_CheckInput
+Check whether input values from mods are out of range.
+Necessary for i.g. Western Quake3 mod which is buggy.
+=================
+*/
+static bool S_AL_CheckInput(int entityNum, sfxHandle_t sfx)
+{
+ if (entityNum < 0 || entityNum >= MAX_GENTITIES)
+ Com_Error(ERR_DROP, "ERROR: S_AL_CheckInput: bad entitynum %i", entityNum);
+
+ if (sfx < 0 || sfx >= numSfx)
+ {
+ Com_Printf(S_COLOR_RED "ERROR: S_AL_CheckInput: handle %i out of range\n", sfx);
+ return true;
+ }
+
+ return false;
+}
+
+/*
+=================
+S_AL_StartLocalSound
+
+Play a local (non-spatialized) sound effect
+=================
+*/
+static
+void S_AL_StartLocalSound(sfxHandle_t sfx, int channel)
+{
+ srcHandle_t src;
+
+ if(S_AL_CheckInput(0, sfx))
+ return;
+
+ // Try to grab a source
+ src = S_AL_SrcAlloc(SRCPRI_LOCAL, -1, channel);
+
+ if(src == -1)
+ return;
+
+ // Set up the effect
+ S_AL_SrcSetup(src, sfx, SRCPRI_LOCAL, -1, channel, true);
+
+ // Start it playing
+ srcList[src].isPlaying = true;
+ qalSourcePlay(srcList[src].alSource);
+}
+
+/*
+=================
+S_AL_StartSound
+
+Play a one-shot sound effect
+=================
+*/
+static void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx )
+{
+ vec3_t sorigin;
+ srcHandle_t src;
+ src_t *curSource;
+
+ if(origin)
+ {
+ if(S_AL_CheckInput(0, sfx))
+ return;
+
+ VectorCopy(origin, sorigin);
+ }
+ else
+ {
+ if(S_AL_CheckInput(entnum, sfx))
+ return;
+
+ if(S_AL_HearingThroughEntity(entnum))
+ {
+ S_AL_StartLocalSound(sfx, entchannel);
+ return;
+ }
+
+ VectorCopy(entityList[entnum].origin, sorigin);
+ }
+
+ S_AL_SanitiseVector(sorigin);
+
+ if((srcActiveCnt > 5 * srcCount / 3) &&
+ (DistanceSquared(sorigin, lastListenerOrigin) >=
+ (s_alMaxDistance->value + s_alGraceDistance->value) * (s_alMaxDistance->value + s_alGraceDistance->value)))
+ {
+ // We're getting tight on sources and source is not within hearing distance so don't add it
+ return;
+ }
+
+ // Try to grab a source
+ src = S_AL_SrcAlloc(SRCPRI_ONESHOT, entnum, entchannel);
+ if(src == -1)
+ return;
+
+ S_AL_SrcSetup(src, sfx, SRCPRI_ONESHOT, entnum, entchannel, false);
+
+ curSource = &srcList[src];
+
+ if(!origin)
+ curSource->isTracking = true;
+
+ qalSourcefv(curSource->alSource, AL_POSITION, sorigin );
+ S_AL_ScaleGain(curSource, sorigin);
+
+ // Start it playing
+ curSource->isPlaying = true;
+ qalSourcePlay(curSource->alSource);
+}
+
+/*
+=================
+S_AL_ClearLoopingSounds
+=================
+*/
+static void S_AL_ClearLoopingSounds( bool killall )
+{
+ int i;
+ for(i = 0; i < srcCount; i++)
+ {
+ if((srcList[i].isLooping) && (srcList[i].entity != -1))
+ entityList[srcList[i].entity].loopAddedThisFrame = false;
+ }
+}
+
+/*
+=================
+S_AL_SrcLoop
+=================
+*/
+static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx,
+ const vec3_t origin, const vec3_t velocity, int entityNum )
+{
+ int src;
+ sentity_t *sent = &entityList[ entityNum ];
+ src_t *curSource;
+ vec3_t sorigin, svelocity;
+
+ if(S_AL_CheckInput(entityNum, sfx))
+ return;
+
+ // Do we need to allocate a new source for this entity
+ if( !sent->srcAllocated )
+ {
+ // Try to get a channel
+ src = S_AL_SrcAlloc( priority, entityNum, -1 );
+ if( src == -1 )
+ {
+ Com_DPrintf( S_COLOR_YELLOW "WARNING: Failed to allocate source "
+ "for loop sfx %d on entity %d\n", sfx, entityNum );
+ return;
+ }
+
+ curSource = &srcList[src];
+
+ sent->startLoopingSound = true;
+
+ curSource->lastTimePos = -1.0;
+ curSource->lastSampleTime = Sys_Milliseconds();
+ }
+ else
+ {
+ src = sent->srcIndex;
+ curSource = &srcList[src];
+ }
+
+ sent->srcAllocated = true;
+ sent->srcIndex = src;
+
+ sent->loopPriority = priority;
+ sent->loopSfx = sfx;
+
+ // If this is not set then the looping sound is stopped.
+ sent->loopAddedThisFrame = true;
+
+ // UGH
+ // These lines should be called via S_AL_SrcSetup, but we
+ // can't call that yet as it buffers sfxes that may change
+ // with subsequent calls to S_AL_SrcLoop
+ curSource->entity = entityNum;
+ curSource->isLooping = true;
+
+ if( S_AL_HearingThroughEntity( entityNum ) )
+ {
+ curSource->local = true;
+
+ VectorClear(sorigin);
+
+ qalSourcefv(curSource->alSource, AL_POSITION, sorigin);
+ qalSourcefv(curSource->alSource, AL_VELOCITY, vec3_origin);
+ }
+ else
+ {
+ curSource->local = false;
+
+ if(origin)
+ VectorCopy(origin, sorigin);
+ else
+ VectorCopy(sent->origin, sorigin);
+
+ S_AL_SanitiseVector(sorigin);
+
+ VectorCopy(sorigin, curSource->loopSpeakerPos);
+
+ if(velocity)
+ {
+ VectorCopy(velocity, svelocity);
+ S_AL_SanitiseVector(svelocity);
+ }
+ else
+ VectorClear(svelocity);
+
+ qalSourcefv(curSource->alSource, AL_POSITION, (ALfloat *) sorigin);
+ qalSourcefv(curSource->alSource, AL_VELOCITY, (ALfloat *) svelocity);
+ }
+}
+
+/*
+=================
+S_AL_AddLoopingSound
+=================
+*/
+static void S_AL_AddLoopingSound(int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx)
+{
+ S_AL_SrcLoop(SRCPRI_ENTITY, sfx, origin, velocity, entityNum);
+}
+
+/*
+=================
+S_AL_AddRealLoopingSound
+=================
+*/
+static void S_AL_AddRealLoopingSound(int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx)
+{
+ S_AL_SrcLoop(SRCPRI_AMBIENT, sfx, origin, velocity, entityNum);
+}
+
+/*
+=================
+S_AL_StopLoopingSound
+=================
+*/
+static
+void S_AL_StopLoopingSound(int entityNum )
+{
+ if(entityList[entityNum].srcAllocated)
+ S_AL_SrcKill(entityList[entityNum].srcIndex);
+}
+
+/*
+=================
+S_AL_SrcUpdate
+
+Update state (move things around, manage sources, and so on)
+=================
+*/
+static
+void S_AL_SrcUpdate( void )
+{
+ int i;
+ int entityNum;
+ ALint state;
+ src_t *curSource;
+
+ for(i = 0; i < srcCount; i++)
+ {
+ entityNum = srcList[i].entity;
+ curSource = &srcList[i];
+
+ if(curSource->isLocked)
+ continue;
+
+ if(!curSource->isActive)
+ continue;
+
+ // Update source parameters
+ if((s_alGain->modified) || (s_volume->modified))
+ curSource->curGain = s_alGain->value * s_volume->value;
+ if((s_alRolloff->modified) && (!curSource->local))
+ qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
+ if(s_alMinDistance->modified)
+ qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
+
+ if(curSource->isLooping)
+ {
+ sentity_t *sent = &entityList[ entityNum ];
+
+ // If a looping effect hasn't been touched this frame, pause or kill it
+ if(sent->loopAddedThisFrame)
+ {
+ alSfx_t *curSfx;
+
+ // The sound has changed without an intervening removal
+ if(curSource->isActive && !sent->startLoopingSound &&
+ curSource->sfx != sent->loopSfx)
+ {
+ S_AL_NewLoopMaster(curSource, true);
+
+ curSource->isPlaying = false;
+ qalSourceStop(curSource->alSource);
+ qalSourcei(curSource->alSource, AL_BUFFER, 0);
+ sent->startLoopingSound = true;
+ }
+
+ // The sound hasn't been started yet
+ if(sent->startLoopingSound)
+ {
+ S_AL_SrcSetup(i, sent->loopSfx, sent->loopPriority,
+ entityNum, -1, curSource->local);
+ curSource->isLooping = true;
+
+ knownSfx[curSource->sfx].loopCnt++;
+ sent->startLoopingSound = false;
+ }
+
+ curSfx = &knownSfx[curSource->sfx];
+
+ S_AL_ScaleGain(curSource, curSource->loopSpeakerPos);
+ if(!curSource->scaleGain)
+ {
+ if(curSource->isPlaying)
+ {
+ // Sound is mute, stop playback until we are in range again
+ S_AL_NewLoopMaster(curSource, false);
+ qalSourceStop(curSource->alSource);
+ curSource->isPlaying = false;
+ }
+ else if(!curSfx->loopActiveCnt && curSfx->masterLoopSrc < 0)
+ curSfx->masterLoopSrc = i;
+
+ continue;
+ }
+
+ if(!curSource->isPlaying)
+ {
+ qalSourcei(curSource->alSource, AL_LOOPING, AL_TRUE);
+ curSource->isPlaying = true;
+ qalSourcePlay(curSource->alSource);
+
+ if(curSource->priority == SRCPRI_AMBIENT)
+ {
+ // If there are other ambient looping sources with the same sound,
+ // make sure the sound of these sources are in sync.
+
+ if(curSfx->loopActiveCnt)
+ {
+ int offset, error;
+
+ // we already have a master loop playing, get buffer position.
+ S_AL_ClearError(false);
+ qalGetSourcei(srcList[curSfx->masterLoopSrc].alSource, AL_SAMPLE_OFFSET, &offset);
+ if((error = qalGetError()) != AL_NO_ERROR)
+ {
+ if(error != AL_INVALID_ENUM)
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: Cannot get sample offset from source %d: "
+ "%s\n", i, S_AL_ErrorMsg(error));
+ }
+ }
+ else
+ qalSourcei(curSource->alSource, AL_SAMPLE_OFFSET, offset);
+ }
+ else if(curSfx->loopCnt && curSfx->masterLoopSrc >= 0)
+ {
+ float secofs;
+
+ src_t *master = &srcList[curSfx->masterLoopSrc];
+ // This loop sound used to be played, but all sources are stopped. Use last sample position/time
+ // to calculate offset so the player thinks the sources continued playing while they were inaudible.
+
+ if(master->lastTimePos >= 0)
+ {
+ secofs = master->lastTimePos + (Sys_Milliseconds() - master->lastSampleTime) / 1000.0f;
+ secofs = fmodf(secofs, (float) curSfx->info.samples / curSfx->info.rate);
+
+ qalSourcef(curSource->alSource, AL_SEC_OFFSET, secofs);
+ }
+
+ // I be the master now
+ curSfx->masterLoopSrc = i;
+ }
+ else
+ curSfx->masterLoopSrc = i;
+ }
+ else if(curSource->lastTimePos >= 0)
+ {
+ float secofs;
+
+ // For unsynced loops (SRCPRI_ENTITY) just carry on playing as if the sound was never stopped
+
+ secofs = curSource->lastTimePos + (Sys_Milliseconds() - curSource->lastSampleTime) / 1000.0f;
+ secofs = fmodf(secofs, (float) curSfx->info.samples / curSfx->info.rate);
+ qalSourcef(curSource->alSource, AL_SEC_OFFSET, secofs);
+ }
+
+ curSfx->loopActiveCnt++;
+ }
+
+ // Update locality
+ if(curSource->local)
+ {
+ qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE);
+ qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f);
+ }
+ else
+ {
+ qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE);
+ qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
+ }
+
+ }
+ else if(curSource->priority == SRCPRI_AMBIENT)
+ {
+ if(curSource->isPlaying)
+ {
+ S_AL_NewLoopMaster(curSource, false);
+ qalSourceStop(curSource->alSource);
+ curSource->isPlaying = false;
+ }
+ }
+ else
+ S_AL_SrcKill(i);
+
+ continue;
+ }
+
+ if(!curSource->isStream)
+ {
+ // Check if it's done, and flag it
+ qalGetSourcei(curSource->alSource, AL_SOURCE_STATE, &state);
+ if(state == AL_STOPPED)
+ {
+ curSource->isPlaying = false;
+ S_AL_SrcKill(i);
+ continue;
+ }
+ }
+
+ // Query relativity of source, don't move if it's true
+ qalGetSourcei(curSource->alSource, AL_SOURCE_RELATIVE, &state);
+
+ // See if it needs to be moved
+ if(curSource->isTracking && !state)
+ {
+ qalSourcefv(curSource->alSource, AL_POSITION, entityList[entityNum].origin);
+ S_AL_ScaleGain(curSource, entityList[entityNum].origin);
+ }
+ }
+}
+
+/*
+=================
+S_AL_SrcShutup
+=================
+*/
+static
+void S_AL_SrcShutup( void )
+{
+ int i;
+ for(i = 0; i < srcCount; i++)
+ S_AL_SrcKill(i);
+}
+
+/*
+=================
+S_AL_SrcGet
+=================
+*/
+static
+ALuint S_AL_SrcGet(srcHandle_t src)
+{
+ return srcList[src].alSource;
+}
+
+
+//===========================================================================
+
+// Q3A cinematics use up to 12 buffers at once
+#define MAX_STREAM_BUFFERS 20
+
+static srcHandle_t streamSourceHandles[MAX_RAW_STREAMS];
+static bool streamPlaying[MAX_RAW_STREAMS];
+static ALuint streamSources[MAX_RAW_STREAMS];
+static ALuint streamBuffers[MAX_RAW_STREAMS][MAX_STREAM_BUFFERS];
+static int streamNumBuffers[MAX_RAW_STREAMS];
+static int streamBufIndex[MAX_RAW_STREAMS];
+
+/*
+=================
+S_AL_AllocateStreamChannel
+=================
+*/
+static void S_AL_AllocateStreamChannel(int stream, int entityNum)
+{
+ srcHandle_t cursrc;
+ ALuint alsrc;
+
+ if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
+ return;
+
+ if(entityNum >= 0)
+ {
+ // This is a stream that tracks an entity
+ // Allocate a streamSource at normal priority
+ cursrc = S_AL_SrcAlloc(SRCPRI_ENTITY, entityNum, 0);
+ if(cursrc < 0)
+ return;
+
+ S_AL_SrcSetup(cursrc, -1, SRCPRI_ENTITY, entityNum, 0, false);
+ alsrc = S_AL_SrcGet(cursrc);
+ srcList[cursrc].isTracking = true;
+ srcList[cursrc].isStream = true;
+ }
+ else
+ {
+ // Unspatialized stream source
+
+ // Allocate a streamSource at high priority
+ cursrc = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
+ if(cursrc < 0)
+ return;
+
+ alsrc = S_AL_SrcGet(cursrc);
+
+ // Lock the streamSource so nobody else can use it, and get the raw streamSource
+ S_AL_SrcLock(cursrc);
+
+ // make sure that after unmuting the S_AL_Gain in S_Update() does not turn
+ // volume up prematurely for this source
+ srcList[cursrc].scaleGain = 0.0f;
+
+ // Set some streamSource parameters
+ qalSourcei (alsrc, AL_BUFFER, 0 );
+ qalSourcei (alsrc, AL_LOOPING, AL_FALSE );
+ qalSource3f(alsrc, AL_POSITION, 0.0, 0.0, 0.0);
+ qalSource3f(alsrc, AL_VELOCITY, 0.0, 0.0, 0.0);
+ qalSource3f(alsrc, AL_DIRECTION, 0.0, 0.0, 0.0);
+ qalSourcef (alsrc, AL_ROLLOFF_FACTOR, 0.0 );
+ qalSourcei (alsrc, AL_SOURCE_RELATIVE, AL_TRUE );
+ }
+
+ streamSourceHandles[stream] = cursrc;
+ streamSources[stream] = alsrc;
+
+ streamNumBuffers[stream] = 0;
+ streamBufIndex[stream] = 0;
+}
+
+/*
+=================
+S_AL_FreeStreamChannel
+=================
+*/
+static void S_AL_FreeStreamChannel( int stream )
+{
+ if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
+ return;
+
+ // Detach any buffers
+ qalSourcei(streamSources[stream], AL_BUFFER, 0);
+
+ // Delete the buffers
+ if (streamNumBuffers[stream] > 0) {
+ qalDeleteBuffers(streamNumBuffers[stream], streamBuffers[stream]);
+ streamNumBuffers[stream] = 0;
+ }
+
+ // Release the output streamSource
+ S_AL_SrcUnlock(streamSourceHandles[stream]);
+ S_AL_SrcKill(streamSourceHandles[stream]);
+ streamSources[stream] = 0;
+ streamSourceHandles[stream] = -1;
+}
+
+/*
+=================
+S_AL_RawSamples
+=================
+*/
+static
+void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum)
+{
+ int numBuffers;
+ ALuint buffer;
+ ALuint format;
+
+ if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
+ return;
+
+ format = S_AL_Format( width, channels );
+
+ // Create the streamSource if necessary
+ if(streamSourceHandles[stream] == -1)
+ {
+ S_AL_AllocateStreamChannel(stream, entityNum);
+
+ // Failed?
+ if(streamSourceHandles[stream] == -1)
+ {
+ Com_Printf( S_COLOR_RED "ERROR: Can't allocate streaming streamSource\n");
+ return;
+ }
+ }
+
+ qalGetSourcei(streamSources[stream], AL_BUFFERS_QUEUED, &numBuffers);
+
+ if (numBuffers == MAX_STREAM_BUFFERS)
+ {
+ Com_DPrintf(S_COLOR_RED"WARNING: Steam dropping raw samples, reached MAX_STREAM_BUFFERS\n");
+ return;
+ }
+
+ // Allocate a new AL buffer if needed
+ if (numBuffers == streamNumBuffers[stream])
+ {
+ ALuint oldBuffers[MAX_STREAM_BUFFERS];
+ int i;
+
+ if (!S_AL_GenBuffers(1, &buffer, "stream"))
+ return;
+
+ ::memcpy(oldBuffers, &streamBuffers[stream], sizeof (oldBuffers));
+
+ // Reorder buffer array in order of oldest to newest
+ for ( i = 0; i < streamNumBuffers[stream]; ++i )
+ streamBuffers[stream][i] = oldBuffers[(streamBufIndex[stream] + i) % streamNumBuffers[stream]];
+
+ // Add the new buffer to end
+ streamBuffers[stream][streamNumBuffers[stream]] = buffer;
+ streamBufIndex[stream] = streamNumBuffers[stream];
+ streamNumBuffers[stream]++;
+ }
+
+ // Select next buffer in loop
+ buffer = streamBuffers[stream][ streamBufIndex[stream] ];
+ streamBufIndex[stream] = (streamBufIndex[stream] + 1) % streamNumBuffers[stream];
+
+ // Fill buffer
+ qalBufferData(buffer, format, (ALvoid *)data, (samples * width * channels), rate);
+
+ // Shove the data onto the streamSource
+ qalSourceQueueBuffers(streamSources[stream], 1, &buffer);
+
+ if(entityNum < 0)
+ {
+ // Volume
+ S_AL_Gain (streamSources[stream], volume * s_volume->value * s_alGain->value);
+ }
+
+ // Start stream
+ if(!streamPlaying[stream])
+ {
+ qalSourcePlay( streamSources[stream] );
+ streamPlaying[stream] = true;
+ }
+}
+
+/*
+=================
+S_AL_StreamUpdate
+=================
+*/
+static
+void S_AL_StreamUpdate( int stream )
+{
+ int numBuffers;
+ ALint state;
+
+ if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
+ return;
+
+ if(streamSourceHandles[stream] == -1)
+ return;
+
+ // Un-queue any buffers
+ qalGetSourcei( streamSources[stream], AL_BUFFERS_PROCESSED, &numBuffers );
+ while( numBuffers-- )
+ {
+ ALuint buffer;
+ qalSourceUnqueueBuffers(streamSources[stream], 1, &buffer);
+ }
+
+ // Start the streamSource playing if necessary
+ qalGetSourcei( streamSources[stream], AL_BUFFERS_QUEUED, &numBuffers );
+
+ qalGetSourcei(streamSources[stream], AL_SOURCE_STATE, &state);
+ if(state == AL_STOPPED)
+ {
+ streamPlaying[stream] = false;
+
+ // If there are no buffers queued up, release the streamSource
+ if( !numBuffers )
+ S_AL_FreeStreamChannel( stream );
+ }
+
+ if( !streamPlaying[stream] && numBuffers )
+ {
+ qalSourcePlay( streamSources[stream] );
+ streamPlaying[stream] = true;
+ }
+}
+
+/*
+=================
+S_AL_StreamDie
+=================
+*/
+static
+void S_AL_StreamDie( int stream )
+{
+ if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
+ return;
+
+ if(streamSourceHandles[stream] == -1)
+ return;
+
+ streamPlaying[stream] = false;
+ qalSourceStop(streamSources[stream]);
+
+ S_AL_FreeStreamChannel(stream);
+}
+
+
+//===========================================================================
+
+
+#define NUM_MUSIC_BUFFERS 4
+#define MUSIC_BUFFER_SIZE 4096
+
+static bool musicPlaying = false;
+static srcHandle_t musicSourceHandle = -1;
+static ALuint musicSource;
+static ALuint musicBuffers[NUM_MUSIC_BUFFERS];
+
+static snd_stream_t *mus_stream;
+static snd_stream_t *intro_stream;
+static char s_backgroundLoop[MAX_QPATH];
+
+static byte decode_buffer[MUSIC_BUFFER_SIZE];
+
+/*
+=================
+S_AL_MusicSourceGet
+=================
+*/
+static void S_AL_MusicSourceGet( void )
+{
+ // Allocate a musicSource at high priority
+ musicSourceHandle = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
+ if(musicSourceHandle == -1)
+ return;
+
+ // Lock the musicSource so nobody else can use it, and get the raw musicSource
+ S_AL_SrcLock(musicSourceHandle);
+ musicSource = S_AL_SrcGet(musicSourceHandle);
+
+ // make sure that after unmuting the S_AL_Gain in S_Update() does not turn
+ // volume up prematurely for this source
+ srcList[musicSourceHandle].scaleGain = 0.0f;
+
+ // Set some musicSource parameters
+ qalSource3f(musicSource, AL_POSITION, 0.0, 0.0, 0.0);
+ qalSource3f(musicSource, AL_VELOCITY, 0.0, 0.0, 0.0);
+ qalSource3f(musicSource, AL_DIRECTION, 0.0, 0.0, 0.0);
+ qalSourcef (musicSource, AL_ROLLOFF_FACTOR, 0.0 );
+ qalSourcei (musicSource, AL_SOURCE_RELATIVE, AL_TRUE );
+}
+
+/*
+=================
+S_AL_MusicSourceFree
+=================
+*/
+static void S_AL_MusicSourceFree( void )
+{
+ // Release the output musicSource
+ S_AL_SrcUnlock(musicSourceHandle);
+ S_AL_SrcKill(musicSourceHandle);
+ musicSource = 0;
+ musicSourceHandle = -1;
+}
+
+/*
+=================
+S_AL_CloseMusicFiles
+=================
+*/
+static void S_AL_CloseMusicFiles(void)
+{
+ if(intro_stream)
+ {
+ S_CodecCloseStream(intro_stream);
+ intro_stream = NULL;
+ }
+
+ if(mus_stream)
+ {
+ S_CodecCloseStream(mus_stream);
+ mus_stream = NULL;
+ }
+}
+
+/*
+=================
+S_AL_StopBackgroundTrack
+=================
+*/
+static
+void S_AL_StopBackgroundTrack( void )
+{
+ if(!musicPlaying)
+ return;
+
+ // Stop playing
+ qalSourceStop(musicSource);
+
+ // Detach any buffers
+ qalSourcei(musicSource, AL_BUFFER, 0);
+
+ // Delete the buffers
+ qalDeleteBuffers(NUM_MUSIC_BUFFERS, musicBuffers);
+
+ // Free the musicSource
+ S_AL_MusicSourceFree();
+
+ // Unload the stream
+ S_AL_CloseMusicFiles();
+
+ musicPlaying = false;
+}
+
+/*
+=================
+S_AL_MusicProcess
+=================
+*/
+static
+void S_AL_MusicProcess(ALuint b)
+{
+ ALenum error;
+ int l;
+ ALuint format;
+ snd_stream_t *curstream;
+
+ S_AL_ClearError( false );
+
+ if(intro_stream)
+ curstream = intro_stream;
+ else
+ curstream = mus_stream;
+
+ if(!curstream)
+ return;
+
+ l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer);
+
+ // Run out data to read, start at the beginning again
+ if(l == 0)
+ {
+ S_CodecCloseStream(curstream);
+
+ // the intro stream just finished playing so we don't need to reopen
+ // the music stream.
+ if(intro_stream)
+ intro_stream = NULL;
+ else
+ mus_stream = S_CodecOpenStream(s_backgroundLoop);
+
+ curstream = mus_stream;
+
+ if(!curstream)
+ {
+ S_AL_StopBackgroundTrack();
+ return;
+ }
+
+ l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer);
+ }
+
+ format = S_AL_Format(curstream->info.width, curstream->info.channels);
+
+ if( l == 0 )
+ {
+ // We have no data to buffer, so buffer silence
+ byte dummyData[ 2 ] = { 0 };
+
+ qalBufferData( b, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050 );
+ }
+ else
+ qalBufferData(b, format, decode_buffer, l, curstream->info.rate);
+
+ if( ( error = qalGetError( ) ) != AL_NO_ERROR )
+ {
+ S_AL_StopBackgroundTrack( );
+ Com_Printf( S_COLOR_RED "ERROR: while buffering data for music stream - %s\n",
+ S_AL_ErrorMsg( error ) );
+ return;
+ }
+}
+
+/*
+=================
+S_AL_StartBackgroundTrack
+=================
+*/
+static
+void S_AL_StartBackgroundTrack( const char *intro, const char *loop )
+{
+ int i;
+ bool issame;
+
+ // Stop any existing music that might be playing
+ S_AL_StopBackgroundTrack();
+
+ if((!intro || !*intro) && (!loop || !*loop))
+ return;
+
+ // Allocate a musicSource
+ S_AL_MusicSourceGet();
+ if(musicSourceHandle == -1)
+ return;
+
+ if (!loop || !*loop)
+ {
+ loop = intro;
+ issame = true;
+ }
+ else if(intro && *intro && !strcmp(intro, loop))
+ issame = true;
+ else
+ issame = false;
+
+ // Copy the loop over
+ Q_strncpyz( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );
+
+ if(!issame)
+ {
+ // Open the intro and don't mind whether it succeeds.
+ // The important part is the loop.
+ intro_stream = S_CodecOpenStream(intro);
+ }
+ else
+ intro_stream = NULL;
+
+ mus_stream = S_CodecOpenStream(s_backgroundLoop);
+ if(!mus_stream)
+ {
+ S_AL_CloseMusicFiles();
+ S_AL_MusicSourceFree();
+ return;
+ }
+
+ // Generate the musicBuffers
+ if (!S_AL_GenBuffers(NUM_MUSIC_BUFFERS, musicBuffers, "music"))
+ return;
+
+ // Queue the musicBuffers up
+ for(i = 0; i < NUM_MUSIC_BUFFERS; i++)
+ {
+ S_AL_MusicProcess(musicBuffers[i]);
+ }
+
+ qalSourceQueueBuffers(musicSource, NUM_MUSIC_BUFFERS, musicBuffers);
+
+ // Set the initial gain property
+ S_AL_Gain(musicSource, s_alGain->value * s_musicVolume->value);
+
+ // Start playing
+ qalSourcePlay(musicSource);
+
+ musicPlaying = true;
+}
+
+/*
+=================
+S_AL_MusicUpdate
+=================
+*/
+static
+void S_AL_MusicUpdate( void )
+{
+ int numBuffers;
+ ALint state;
+
+ if(!musicPlaying)
+ return;
+
+ qalGetSourcei( musicSource, AL_BUFFERS_PROCESSED, &numBuffers );
+ while( numBuffers-- )
+ {
+ ALuint b;
+ qalSourceUnqueueBuffers(musicSource, 1, &b);
+ S_AL_MusicProcess(b);
+ qalSourceQueueBuffers(musicSource, 1, &b);
+ }
+
+ // Hitches can cause OpenAL to be starved of buffers when streaming.
+ // If this happens, it will stop playback. This restarts the source if
+ // it is no longer playing, and if there are buffers available
+ qalGetSourcei( musicSource, AL_SOURCE_STATE, &state );
+ qalGetSourcei( musicSource, AL_BUFFERS_QUEUED, &numBuffers );
+ if( state == AL_STOPPED && numBuffers )
+ {
+ Com_DPrintf( S_COLOR_YELLOW "Restarted OpenAL music\n" );
+ qalSourcePlay(musicSource);
+ }
+
+ // Set the gain property
+ S_AL_Gain(musicSource, s_alGain->value * s_musicVolume->value);
+}
+
+
+//===========================================================================
+
+
+// Local state variables
+static ALCdevice *alDevice;
+static ALCcontext *alContext;
+
+#ifdef USE_VOIP
+static ALCdevice *alCaptureDevice;
+static cvar_t *s_alCapture;
+#endif
+
+#ifdef _WIN32
+#define ALDRIVER_DEFAULT "OpenAL32.dll"
+#elif defined(__APPLE__)
+#define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL"
+#elif defined(__OpenBSD__)
+#define ALDRIVER_DEFAULT "libopenal.so"
+#else
+#define ALDRIVER_DEFAULT "libopenal.so.1"
+#endif
+
+/*
+=================
+S_AL_StopAllSounds
+=================
+*/
+static
+void S_AL_StopAllSounds( void )
+{
+ int i;
+ S_AL_SrcShutup();
+ S_AL_StopBackgroundTrack();
+ for (i = 0; i < MAX_RAW_STREAMS; i++)
+ S_AL_StreamDie(i);
+}
+
+/*
+=================
+S_AL_Respatialize
+=================
+*/
+static
+void S_AL_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater )
+{
+ float orientation[6];
+ vec3_t sorigin;
+
+ VectorCopy( origin, sorigin );
+ S_AL_SanitiseVector( sorigin );
+
+ S_AL_SanitiseVector( axis[ 0 ] );
+ S_AL_SanitiseVector( axis[ 1 ] );
+ S_AL_SanitiseVector( axis[ 2 ] );
+
+ orientation[0] = axis[0][0]; orientation[1] = axis[0][1]; orientation[2] = axis[0][2];
+ orientation[3] = axis[2][0]; orientation[4] = axis[2][1]; orientation[5] = axis[2][2];
+
+ lastListenerNumber = entityNum;
+ VectorCopy( sorigin, lastListenerOrigin );
+
+ // Set OpenAL listener paramaters
+ qalListenerfv(AL_POSITION, (ALfloat *)sorigin);
+ qalListenerfv(AL_VELOCITY, vec3_origin);
+ qalListenerfv(AL_ORIENTATION, orientation);
+}
+
+/*
+=================
+S_AL_Update
+=================
+*/
+static
+void S_AL_Update( void )
+{
+ int i;
+
+ if(s_muted->modified)
+ {
+ // muted state changed. Let S_AL_Gain turn up all sources again.
+ for(i = 0; i < srcCount; i++)
+ {
+ if(srcList[i].isActive)
+ S_AL_Gain(srcList[i].alSource, srcList[i].scaleGain);
+ }
+
+ s_muted->modified = false;
+ }
+
+ // Update SFX channels
+ S_AL_SrcUpdate();
+
+ // Update streams
+ for (i = 0; i < MAX_RAW_STREAMS; i++)
+ S_AL_StreamUpdate(i);
+ S_AL_MusicUpdate();
+
+ // Doppler
+ if(s_doppler->modified)
+ {
+ s_alDopplerFactor->modified = true;
+ s_doppler->modified = false;
+ }
+
+ // Doppler parameters
+ if(s_alDopplerFactor->modified)
+ {
+ if(s_doppler->integer)
+ qalDopplerFactor(s_alDopplerFactor->value);
+ else
+ qalDopplerFactor(0.0f);
+ s_alDopplerFactor->modified = false;
+ }
+ if(s_alDopplerSpeed->modified)
+ {
+ qalSpeedOfSound(s_alDopplerSpeed->value);
+ s_alDopplerSpeed->modified = false;
+ }
+
+ // Clear the modified flags on the other cvars
+ s_alGain->modified = false;
+ s_volume->modified = false;
+ s_musicVolume->modified = false;
+ s_alMinDistance->modified = false;
+ s_alRolloff->modified = false;
+}
+
+/*
+=================
+S_AL_DisableSounds
+=================
+*/
+static
+void S_AL_DisableSounds( void )
+{
+ S_AL_StopAllSounds();
+}
+
+/*
+=================
+S_AL_BeginRegistration
+=================
+*/
+static
+void S_AL_BeginRegistration( void )
+{
+ if(!numSfx)
+ S_AL_BufferInit();
+}
+
+/*
+=================
+S_AL_ClearSoundBuffer
+=================
+*/
+static
+void S_AL_ClearSoundBuffer( void )
+{
+}
+
+/*
+=================
+S_AL_SoundList
+=================
+*/
+static
+void S_AL_SoundList( void )
+{
+}
+
+#ifdef USE_VOIP
+static
+void S_AL_StartCapture( void )
+{
+ if (alCaptureDevice != NULL)
+ qalcCaptureStart(alCaptureDevice);
+}
+
+static
+int S_AL_AvailableCaptureSamples( void )
+{
+ int retval = 0;
+ if (alCaptureDevice != NULL)
+ {
+ ALint samples = 0;
+ qalcGetIntegerv(alCaptureDevice, ALC_CAPTURE_SAMPLES, sizeof (samples), &samples);
+ retval = (int) samples;
+ }
+ return retval;
+}
+
+static
+void S_AL_Capture( int samples, byte *data )
+{
+ if (alCaptureDevice != NULL)
+ qalcCaptureSamples(alCaptureDevice, data, samples);
+}
+
+void S_AL_StopCapture( void )
+{
+ if (alCaptureDevice != NULL)
+ qalcCaptureStop(alCaptureDevice);
+}
+
+void S_AL_MasterGain( float gain )
+{
+ qalListenerf(AL_GAIN, gain);
+}
+#endif
+
+
+/*
+=================
+S_AL_SoundInfo
+=================
+*/
+static void S_AL_SoundInfo(void)
+{
+ Com_Printf( "OpenAL info:\n" );
+ Com_Printf( " Vendor: %s\n", qalGetString( AL_VENDOR ) );
+ Com_Printf( " Version: %s\n", qalGetString( AL_VERSION ) );
+ Com_Printf( " Renderer: %s\n", qalGetString( AL_RENDERER ) );
+ Com_Printf( " AL Extensions: %s\n", qalGetString( AL_EXTENSIONS ) );
+ Com_Printf( " ALC Extensions: %s\n", qalcGetString( alDevice, ALC_EXTENSIONS ) );
+
+ if(enumeration_all_ext)
+ Com_Printf(" Device: %s\n", qalcGetString(alDevice, ALC_ALL_DEVICES_SPECIFIER));
+ else if(enumeration_ext)
+ Com_Printf(" Device: %s\n", qalcGetString(alDevice, ALC_DEVICE_SPECIFIER));
+
+ if(enumeration_all_ext || enumeration_ext)
+ Com_Printf(" Available Devices:\n%s", s_alAvailableDevices->string);
+
+#ifdef USE_VOIP
+ if(capture_ext)
+ {
+ Com_Printf(" Input Device: %s\n", qalcGetString(alCaptureDevice, ALC_CAPTURE_DEVICE_SPECIFIER));
+ Com_Printf(" Available Input Devices:\n%s", s_alAvailableInputDevices->string);
+ }
+#endif
+}
+
+
+
+/*
+=================
+S_AL_Shutdown
+=================
+*/
+static
+void S_AL_Shutdown( void )
+{
+ // Shut down everything
+ int i;
+ for (i = 0; i < MAX_RAW_STREAMS; i++)
+ S_AL_StreamDie(i);
+ S_AL_StopBackgroundTrack( );
+ S_AL_SrcShutdown( );
+ S_AL_BufferShutdown( );
+
+ qalcDestroyContext(alContext);
+ qalcCloseDevice(alDevice);
+
+#ifdef USE_VOIP
+ if (alCaptureDevice != NULL) {
+ qalcCaptureStop(alCaptureDevice);
+ qalcCaptureCloseDevice(alCaptureDevice);
+ alCaptureDevice = NULL;
+ Com_Printf( "OpenAL capture device closed.\n" );
+ }
+#endif
+
+ for (i = 0; i < MAX_RAW_STREAMS; i++) {
+ streamSourceHandles[i] = -1;
+ streamPlaying[i] = false;
+ streamSources[i] = 0;
+ }
+
+ QAL_Shutdown();
+}
+
+#endif
+
+/*
+=================
+S_AL_Init
+=================
+*/
+bool S_AL_Init( soundInterface_t *si )
+{
+#ifdef USE_OPENAL
+ const char* device = NULL;
+ const char* inputdevice = NULL;
+ int i;
+
+ if( !si ) {
+ return false;
+ }
+
+ for (i = 0; i < MAX_RAW_STREAMS; i++) {
+ streamSourceHandles[i] = -1;
+ streamPlaying[i] = false;
+ streamSources[i] = 0;
+ streamNumBuffers[i] = 0;
+ streamBufIndex[i] = 0;
+ }
+
+ // New console variables
+ s_alPrecache = Cvar_Get( "s_alPrecache", "1", CVAR_ARCHIVE );
+ s_alGain = Cvar_Get( "s_alGain", "1.0", CVAR_ARCHIVE );
+ s_alSources = Cvar_Get( "s_alSources", "96", CVAR_ARCHIVE );
+ s_alDopplerFactor = Cvar_Get( "s_alDopplerFactor", "1.0", CVAR_ARCHIVE );
+ s_alDopplerSpeed = Cvar_Get( "s_alDopplerSpeed", "9000", CVAR_ARCHIVE );
+ s_alMinDistance = Cvar_Get( "s_alMinDistance", "120", CVAR_CHEAT );
+ s_alMaxDistance = Cvar_Get("s_alMaxDistance", "1024", CVAR_CHEAT);
+ s_alRolloff = Cvar_Get( "s_alRolloff", "2", CVAR_CHEAT);
+ s_alGraceDistance = Cvar_Get("s_alGraceDistance", "512", CVAR_CHEAT);
+
+
+ s_alInputDevice = Cvar_Get( "s_alInputDevice", "", CVAR_ARCHIVE | CVAR_LATCH );
+ s_alDevice = Cvar_Get("s_alDevice", "", CVAR_ARCHIVE | CVAR_LATCH);
+ s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH | CVAR_PROTECTED);
+
+ // Load QAL
+ if( !QAL_Init( s_alDriver->string ) )
+ {
+ Com_Printf( "Failed to load library: \"%s\".\n", s_alDriver->string );
+ if( !Q_stricmp( s_alDriver->string, ALDRIVER_DEFAULT ) || !QAL_Init( ALDRIVER_DEFAULT ) ) {
+ return false;
+ }
+ }
+
+ device = s_alDevice->string;
+ if(device && !*device)
+ device = NULL;
+
+ inputdevice = s_alInputDevice->string;
+ if(inputdevice && !*inputdevice)
+ inputdevice = NULL;
+
+
+ // Device enumeration support
+ enumeration_all_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT");
+ enumeration_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT");
+
+ if(enumeration_ext || enumeration_all_ext)
+ {
+ char devicenames[16384] = "";
+ const char *devicelist;
+#ifdef _WIN32
+ const char *defaultdevice;
+#endif
+ int curlen;
+
+ // get all available devices + the default device name.
+ if(enumeration_all_ext)
+ {
+ devicelist = qalcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
+#ifdef _WIN32
+ defaultdevice = qalcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
+#endif
+ }
+ else
+ {
+ // We don't have ALC_ENUMERATE_ALL_EXT but normal enumeration.
+ devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER);
+#ifdef _WIN32
+ defaultdevice = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
+#endif
+ enumeration_ext = true;
+ }
+
+#ifdef _WIN32
+ // check whether the default device is generic hardware. If it is, change to
+ // Generic Software as that one works more reliably with various sound systems.
+ // If it's not, use OpenAL's default selection as we don't want to ignore
+ // native hardware acceleration.
+ if(!device && defaultdevice && !strcmp(defaultdevice, "Generic Hardware"))
+ device = "Generic Software";
+#endif
+
+ // dump a list of available devices to a cvar for the user to see.
+
+ if(devicelist)
+ {
+ while((curlen = strlen(devicelist)))
+ {
+ Q_strcat(devicenames, sizeof(devicenames), devicelist);
+ Q_strcat(devicenames, sizeof(devicenames), "\n");
+
+ devicelist += curlen + 1;
+ }
+ }
+
+ s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART);
+ }
+
+ alDevice = qalcOpenDevice(device);
+ if( !alDevice && device )
+ {
+ Com_Printf( "Failed to open OpenAL device '%s', trying default.\n", device );
+ alDevice = qalcOpenDevice(NULL);
+ }
+
+ if( !alDevice )
+ {
+ QAL_Shutdown( );
+ Com_Printf( "Failed to open OpenAL device.\n" );
+ return false;
+ }
+
+ // Create OpenAL context
+ alContext = qalcCreateContext( alDevice, NULL );
+ if( !alContext )
+ {
+ QAL_Shutdown( );
+ qalcCloseDevice( alDevice );
+ Com_Printf( "Failed to create OpenAL context.\n" );
+ return false;
+ }
+ qalcMakeContextCurrent( alContext );
+
+ // Initialize sources, buffers, music
+ S_AL_BufferInit( );
+ S_AL_SrcInit( );
+
+ // Set up OpenAL parameters (doppler, etc)
+ qalDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
+ qalDopplerFactor( s_alDopplerFactor->value );
+ qalSpeedOfSound( s_alDopplerSpeed->value );
+
+#ifdef USE_VOIP
+ // !!! FIXME: some of these alcCaptureOpenDevice() values should be cvars.
+ // !!! FIXME: add support for capture device enumeration.
+ // !!! FIXME: add some better error reporting.
+ s_alCapture = Cvar_Get( "s_alCapture", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ if (!s_alCapture->integer)
+ {
+ Com_Printf("OpenAL capture support disabled by user ('+set s_alCapture 1' to enable)\n");
+ }
+#if USE_MUMBLE
+ else if (cl_useMumble->integer)
+ {
+ Com_Printf("OpenAL capture support disabled for Mumble support\n");
+ }
+#endif
+ else
+ {
+#ifdef __APPLE__
+ // !!! FIXME: Apple has a 1.1-compliant OpenAL, which includes
+ // !!! FIXME: capture support, but they don't list it in the
+ // !!! FIXME: extension string. We need to check the version string,
+ // !!! FIXME: then the extension string, but that's too much trouble,
+ // !!! FIXME: so we'll just check the function pointer for now.
+ if (qalcCaptureOpenDevice == NULL)
+#else
+ if (!qalcIsExtensionPresent(NULL, "ALC_EXT_capture"))
+#endif
+ {
+ Com_Printf("No ALC_EXT_capture support, can't record audio.\n");
+ }
+ else
+ {
+ char inputdevicenames[16384] = "";
+ const char *inputdevicelist;
+ const char *defaultinputdevice;
+ int curlen;
+
+ capture_ext = true;
+
+ // get all available input devices + the default input device name.
+ inputdevicelist = qalcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
+ defaultinputdevice = qalcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
+
+ // dump a list of available devices to a cvar for the user to see.
+ if (inputdevicelist)
+ {
+ while((curlen = strlen(inputdevicelist)))
+ {
+ Q_strcat(inputdevicenames, sizeof(inputdevicenames), inputdevicelist);
+ Q_strcat(inputdevicenames, sizeof(inputdevicenames), "\n");
+ inputdevicelist += curlen + 1;
+ }
+ }
+
+ s_alAvailableInputDevices = Cvar_Get("s_alAvailableInputDevices", inputdevicenames, CVAR_ROM | CVAR_NORESTART);
+
+ Com_Printf("OpenAL default capture device is '%s'\n", defaultinputdevice ? defaultinputdevice : "none");
+ alCaptureDevice = qalcCaptureOpenDevice(inputdevice, 48000, AL_FORMAT_MONO16, VOIP_MAX_PACKET_SAMPLES*4);
+ if( !alCaptureDevice && inputdevice )
+ {
+ Com_Printf( "Failed to open OpenAL Input device '%s', trying default.\n", inputdevice );
+ alCaptureDevice = qalcCaptureOpenDevice(NULL, 48000, AL_FORMAT_MONO16, VOIP_MAX_PACKET_SAMPLES*4);
+ }
+ Com_Printf( "OpenAL capture device %s.\n",
+ (alCaptureDevice == NULL) ? "failed to open" : "opened");
+ }
+ }
+#endif
+
+ si->Shutdown = S_AL_Shutdown;
+ si->StartSound = S_AL_StartSound;
+ si->StartLocalSound = S_AL_StartLocalSound;
+ si->StartBackgroundTrack = S_AL_StartBackgroundTrack;
+ si->StopBackgroundTrack = S_AL_StopBackgroundTrack;
+ si->RawSamples = S_AL_RawSamples;
+ si->StopAllSounds = S_AL_StopAllSounds;
+ si->ClearLoopingSounds = S_AL_ClearLoopingSounds;
+ si->AddLoopingSound = S_AL_AddLoopingSound;
+ si->AddRealLoopingSound = S_AL_AddRealLoopingSound;
+ si->StopLoopingSound = S_AL_StopLoopingSound;
+ si->Respatialize = S_AL_Respatialize;
+ si->UpdateEntityPosition = S_AL_UpdateEntityPosition;
+ si->Update = S_AL_Update;
+ si->DisableSounds = S_AL_DisableSounds;
+ si->BeginRegistration = S_AL_BeginRegistration;
+ si->RegisterSound = S_AL_RegisterSound;
+ si->SoundDuration = S_AL_SoundDuration;
+ si->ClearSoundBuffer = S_AL_ClearSoundBuffer;
+ si->SoundInfo = S_AL_SoundInfo;
+ si->SoundList = S_AL_SoundList;
+
+#ifdef USE_VOIP
+ si->StartCapture = S_AL_StartCapture;
+ si->AvailableCaptureSamples = S_AL_AvailableCaptureSamples;
+ si->Capture = S_AL_Capture;
+ si->StopCapture = S_AL_StopCapture;
+ si->MasterGain = S_AL_MasterGain;
+#endif
+
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/src/client/snd_public.h b/src/client/snd_public.h
new file mode 100644
index 0000000..b8e97b9
--- /dev/null
+++ b/src/client/snd_public.h
@@ -0,0 +1,88 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifndef _SND_PUBLIC_H_
+#define _SND_PUBLIC_H_
+
+void S_Init( void );
+void S_Shutdown( void );
+
+// if origin is NULL, the sound will be dynamically sourced from the entity
+void S_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx );
+void S_StartLocalSound( sfxHandle_t sfx, int channelNum );
+
+void S_StartBackgroundTrack( const char *intro, const char *loop );
+void S_StopBackgroundTrack( void );
+
+// cinematics and voice-over-network will send raw samples
+// 1.0 volume will be direct output of source samples
+void S_RawSamples(int stream, int samples, int rate, int width, int channels,
+ const byte *data, float volume, int entityNum);
+
+// stop all sounds and the background track
+void S_StopAllSounds( void );
+
+// all continuous looping sounds must be added before calling S_Update
+void S_ClearLoopingSounds( bool killall );
+void S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
+void S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
+void S_StopLoopingSound(int entityNum );
+
+// recompute the relative volumes for all running sounds
+// relative to the given entityNum / orientation
+void S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
+
+// let the sound system know where an entity currently is
+void S_UpdateEntityPosition( int entityNum, const vec3_t origin );
+
+void S_Update( void );
+
+void S_DisableSounds( void );
+
+void S_BeginRegistration( void );
+
+// RegisterSound will allways return a valid sample, even if it
+// has to create a placeholder. This prevents continuous filesystem
+// checks for missing files
+sfxHandle_t S_RegisterSound( const char *sample, bool compressed );
+
+int S_SoundDuration( sfxHandle_t handle );
+
+void S_DisplayFreeMemory(void);
+
+void S_ClearSoundBuffer( void );
+
+void SNDDMA_Activate( void );
+
+void S_UpdateBackgroundTrack( void );
+
+
+#ifdef USE_VOIP
+void S_StartCapture( void );
+int S_AvailableCaptureSamples( void );
+void S_Capture( int samples, byte *data );
+void S_StopCapture( void );
+void S_MasterGain( float gain );
+#endif
+#endif
diff --git a/src/client/snd_wavelet.cpp b/src/client/snd_wavelet.cpp
new file mode 100644
index 0000000..e06e3ef
--- /dev/null
+++ b/src/client/snd_wavelet.cpp
@@ -0,0 +1,252 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "snd_local.h"
+
+#define C0 0.4829629131445341
+#define C1 0.8365163037378079
+#define C2 0.2241438680420134
+#define C3 -0.1294095225512604
+
+void daub4(float b[], unsigned long n, int isign)
+{
+ float wksp[4097] = { 0.0f };
+#define a(x) b[(x)-1] // numerical recipies so a[1] = b[0]
+
+
+ unsigned long nh,nh1,i,j;
+
+ if (n < 4) return;
+
+ nh1=(nh=n >> 1)+1;
+ if (isign >= 0) {
+ for (i=1,j=1;j<=n-3;j+=2,i++) {
+ wksp[i] = C0*a(j)+C1*a(j+1)+C2*a(j+2)+C3*a(j+3);
+ wksp[i+nh] = C3*a(j)-C2*a(j+1)+C1*a(j+2)-C0*a(j+3);
+ }
+ wksp[i ] = C0*a(n-1)+C1*a(n)+C2*a(1)+C3*a(2);
+ wksp[i+nh] = C3*a(n-1)-C2*a(n)+C1*a(1)-C0*a(2);
+ } else {
+ wksp[1] = C2*a(nh)+C1*a(n)+C0*a(1)+C3*a(nh1);
+ wksp[2] = C3*a(nh)-C0*a(n)+C1*a(1)-C2*a(nh1);
+ for (i=1,j=3;i<nh;i++) {
+ wksp[j++] = C2*a(i)+C1*a(i+nh)+C0*a(i+1)+C3*a(i+nh1);
+ wksp[j++] = C3*a(i)-C0*a(i+nh)+C1*a(i+1)-C2*a(i+nh1);
+ }
+ }
+ for (i=1;i<=n;i++) {
+ a(i) = wksp[i];
+ }
+}
+
+void wt1(float a[], unsigned long n, int isign)
+{
+ unsigned long nn;
+ int inverseStartLength = n/4;
+ if (n < inverseStartLength) return;
+ if (isign >= 0) {
+ for (nn=n;nn>=inverseStartLength;nn>>=1) daub4(a,nn,isign);
+ } else {
+ for (nn=inverseStartLength;nn<=n;nn<<=1) daub4(a,nn,isign);
+ }
+}
+
+/* The number of bits required by each value */
+static unsigned char numBits[] = {
+ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+};
+
+byte MuLawEncode(short s) {
+ unsigned long adjusted;
+ byte sign, exponent, mantissa;
+
+ sign = (s<0)?0:0x80;
+
+ if (s<0) s=-s;
+ adjusted = (long)s << (16-sizeof(short)*8);
+ adjusted += 128L + 4L;
+ if (adjusted > 32767) adjusted = 32767;
+ exponent = numBits[(adjusted>>7)&0xff] - 1;
+ mantissa = (adjusted>>(exponent+3))&0xf;
+ return ~(sign | (exponent<<4) | mantissa);
+}
+
+short MuLawDecode(byte uLaw) {
+ signed long adjusted;
+ byte exponent, mantissa;
+
+ uLaw = ~uLaw;
+ exponent = (uLaw>>4) & 0x7;
+ mantissa = (uLaw&0xf) + 16;
+ adjusted = (mantissa << (exponent +3)) - 128 - 4;
+
+ return (uLaw & 0x80)? adjusted : -adjusted;
+}
+
+short mulawToShort[256];
+static bool madeTable = false;
+
+static int NXStreamCount;
+
+void NXPutc(NXStream *stream, char out) {
+ stream[NXStreamCount++] = out;
+}
+
+
+void encodeWavelet( sfx_t *sfx, short *packets) {
+ float wksp[4097] = {0}, temp;
+ int i, samples, size;
+ sndBuffer *newchunk, *chunk;
+ byte *out;
+
+ if (!madeTable) {
+ for (i=0;i<256;i++) {
+ mulawToShort[i] = (float)MuLawDecode((byte)i);
+ }
+ madeTable = true;
+ }
+ chunk = NULL;
+
+ samples = sfx->soundLength;
+ while(samples>0) {
+ size = samples;
+ if (size>(SND_CHUNK_SIZE*2)) {
+ size = (SND_CHUNK_SIZE*2);
+ }
+
+ if (size<4) {
+ size = 4;
+ }
+
+ newchunk = SND_malloc();
+ if (sfx->soundData == NULL) {
+ sfx->soundData = newchunk;
+ } else if (chunk != NULL) {
+ chunk->next = newchunk;
+ }
+ chunk = newchunk;
+ for(i=0; i<size; i++) {
+ wksp[i] = *packets;
+ packets++;
+ }
+ wt1(wksp, size, 1);
+ out = (byte *)chunk->sndChunk;
+
+ for(i=0;i<size;i++) {
+ temp = wksp[i];
+ if (temp > 32767) temp = 32767; else if (temp<-32768) temp = -32768;
+ out[i] = MuLawEncode((short)temp);
+ }
+
+ chunk->size = size;
+ samples -= size;
+ }
+}
+
+void decodeWavelet(sndBuffer *chunk, short *to) {
+ float wksp[4097] = {0};
+ int i;
+ byte *out;
+
+ int size = chunk->size;
+
+ out = (byte *)chunk->sndChunk;
+ for(i=0;i<size;i++) {
+ wksp[i] = mulawToShort[out[i]];
+ }
+
+ wt1(wksp, size, -1);
+
+ if (!to) return;
+
+ for(i=0; i<size; i++) {
+ to[i] = wksp[i];
+ }
+}
+
+
+void encodeMuLaw( sfx_t *sfx, short *packets) {
+ int i, samples, size, grade, poop;
+ sndBuffer *newchunk, *chunk;
+ byte *out;
+
+ if (!madeTable) {
+ for (i=0;i<256;i++) {
+ mulawToShort[i] = (float)MuLawDecode((byte)i);
+ }
+ madeTable = true;
+ }
+
+ chunk = NULL;
+ samples = sfx->soundLength;
+ grade = 0;
+
+ while(samples>0) {
+ size = samples;
+ if (size>(SND_CHUNK_SIZE*2)) {
+ size = (SND_CHUNK_SIZE*2);
+ }
+
+ newchunk = SND_malloc();
+ if (sfx->soundData == NULL) {
+ sfx->soundData = newchunk;
+ } else if (chunk != NULL) {
+ chunk->next = newchunk;
+ }
+ chunk = newchunk;
+ out = (byte *)chunk->sndChunk;
+ for(i=0; i<size; i++) {
+ poop = packets[0]+grade;
+ if (poop>32767) {
+ poop = 32767;
+ } else if (poop<-32768) {
+ poop = -32768;
+ }
+ out[i] = MuLawEncode((short)poop);
+ grade = poop - mulawToShort[out[i]];
+ packets++;
+ }
+ chunk->size = size;
+ samples -= size;
+ }
+}
+
+void decodeMuLaw(sndBuffer *chunk, short *to) {
+ int i;
+ byte *out;
+
+ int size = chunk->size;
+
+ out = (byte *)chunk->sndChunk;
+ for(i=0;i<size;i++) {
+ to[i] = mulawToShort[out[i]];
+ }
+}
diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt
new file mode 100644
index 0000000..cec287d
--- /dev/null
+++ b/src/game/CMakeLists.txt
@@ -0,0 +1,70 @@
+#
+## ____ _
+## / ___| __ _ _ __ ___ ___ ___ ___ __| | ___
+## | | _ / _` | '_ ` _ \ / _ \ / __/ _ \ / _` |/ _ \
+## | |_| | (_| | | | | | | __/ | (_| (_) | (_| | __/
+## \____|\__,_|_| |_| |_|\___| \___\___/ \__,_|\___|
+##
+#
+
+set(CMAKE_INSTALL_NAME_DIR ${PROJECT_BINARY_DIR}/gpp)
+
+set(QC_SOURCE_DIR ../qcommon)
+#set(RC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../renderercommon)
+#set(CLIENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../client)
+
+add_definitions( -DGAME )
+
+set( GAME_SOURCES
+ g_main.c # Must be listed first!
+ bg_alloc.c
+ bg_lib.c
+ bg_lib.h
+ bg_local.h
+ bg_misc.c
+ bg_pmove.c
+ bg_public.h
+ bg_slidemove.c
+ bg_voice.c
+ g_active.c
+ g_admin.c
+ g_admin.h
+ g_buildable.c
+ g_client.c
+ g_cmds.c
+ g_combat.c
+ g_local.h
+ g_maprotation.c
+ g_misc.c
+ g_missile.c
+ g_mover.c
+ g_namelog.c
+ g_physics.c
+ g_playermodel.c
+ g_public.h
+ g_session.c
+ g_spawn.c
+ g_svcmds.c
+ g_target.c
+ g_team.c
+ g_trigger.c
+ g_utils.c
+ g_weapon.c
+ g_weapondrop.c
+ tremulous.h
+ ${QC_SOURCE_DIR}/q_shared.h
+ ${QC_SOURCE_DIR}/q_shared.c
+ ${QC_SOURCE_DIR}/q_math.c
+ )
+
+add_library( game SHARED ${GAME_SOURCES} g_syscalls.c )
+
+include( ${CMAKE_SOURCE_DIR}/cmake/AddQVM.cmake )
+add_qvm( game ${GAME_SOURCES} g_syscalls.asm )
+
+add_custom_command(
+ TARGET game POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${CMAKE_CURRENT_BINARY_DIR}/libgame${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpp/game${CMAKE_SHARED_LIBRARY_SUFFIX}
+ )
+
diff --git a/src/game/g_mem.c b/src/game/bg_alloc.c
index 6935194..d08c29f 100644
--- a/src/game/g_mem.c
+++ b/src/game/bg_alloc.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,47 +17,53 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
-#include "g_local.h"
+#include "qcommon/q_shared.h"
+#include "bg_public.h"
+
+#ifdef GAME
+# define POOLSIZE ( 1024 * 1024 )
+#else
+# define POOLSIZE ( 256 * 1024 )
+#endif
-#define POOLSIZE ( 1024 * 1024 )
#define FREEMEMCOOKIE ((int)0xDEADBE3F) // Any unlikely to be used value
#define ROUNDBITS 31 // Round to 32 bytes
-struct freememnode
+typedef struct freeMemNode_s
{
// Size of ROUNDBITS
int cookie, size; // Size includes node (obviously)
- struct freememnode *prev, *next;
-};
+ struct freeMemNode_s *prev, *next;
+} freeMemNode_t;
-static char memoryPool[POOLSIZE];
-static struct freememnode *freehead;
-static int freemem;
+static char memoryPool[POOLSIZE];
+static freeMemNode_t *freeHead;
+static int freeMem;
-void *G_Alloc( int size )
+void *BG_Alloc( int size )
{
// Find a free block and allocate.
// Does two passes, attempts to fill same-sized free slot first.
- struct freememnode *fmn, *prev, *next, *smallest;
+ freeMemNode_t *fmn, *prev, *next, *smallest;
int allocsize, smallestsize;
char *endptr;
int *ptr;
- allocsize = ( size + sizeof(int) + ROUNDBITS ) & ~ROUNDBITS; // Round to 32-byte boundary
+ allocsize = ( size + (int)sizeof(int) + ROUNDBITS ) & ~ROUNDBITS; // Round to 32-byte boundary
ptr = NULL;
smallest = NULL;
smallestsize = POOLSIZE + 1; // Guaranteed not to miss any slots :)
- for( fmn = freehead; fmn; fmn = fmn->next )
+ for( fmn = freeHead; fmn; fmn = fmn->next )
{
if( fmn->cookie != FREEMEMCOOKIE )
- G_Error( "G_Alloc: Memory corruption detected!\n" );
+ Com_Error( ERR_DROP, "BG_Alloc: Memory corruption detected!" );
if( fmn->size >= allocsize )
{
@@ -71,8 +78,8 @@ void *G_Alloc( int size )
prev->next = next; // Point previous node to next
if( next )
next->prev = prev; // Point next node to previous
- if( fmn == freehead )
- freehead = next; // Set head pointer to next
+ if( fmn == freeHead )
+ freeHead = next; // Set head pointer to next
ptr = (int *) fmn;
break; // Stop the loop, this is fine
}
@@ -98,34 +105,30 @@ void *G_Alloc( int size )
if( ptr )
{
- freemem -= allocsize;
- if( g_debugAlloc.integer )
- G_Printf( "G_Alloc of %i bytes (%i left)\n", allocsize, freemem );
+ freeMem -= allocsize;
memset( ptr, 0, allocsize );
*ptr++ = allocsize; // Store a copy of size for deallocation
return( (void *) ptr );
}
- G_Error( "G_Alloc: failed on allocation of %i bytes\n", size );
+ Com_Error( ERR_DROP, "BG_Alloc: failed on allocation of %i bytes", size );
return( NULL );
}
-void G_Free( void *ptr )
+void BG_Free( void *ptr )
{
// Release allocated memory, add it to the free list.
- struct freememnode *fmn;
+ freeMemNode_t *fmn;
char *freeend;
int *freeptr;
freeptr = ptr;
freeptr--;
- freemem += *freeptr;
- if( g_debugAlloc.integer )
- G_Printf( "G_Free of %i bytes (%i left)\n", *freeptr, freemem );
+ freeMem += *freeptr;
- for( fmn = freehead; fmn; fmn = fmn->next )
+ for( fmn = freeHead; fmn; fmn = fmn->next )
{
freeend = ((char *) fmn) + fmn->size;
if( freeend == (char *) freeptr )
@@ -138,42 +141,42 @@ void G_Free( void *ptr )
}
// No merging, add to head of list
- fmn = (struct freememnode *) freeptr;
+ fmn = (freeMemNode_t *) freeptr;
fmn->size = *freeptr; // Set this first to avoid corrupting *freeptr
fmn->cookie = FREEMEMCOOKIE;
fmn->prev = NULL;
- fmn->next = freehead;
- freehead->prev = fmn;
- freehead = fmn;
+ fmn->next = freeHead;
+ freeHead->prev = fmn;
+ freeHead = fmn;
}
-void G_InitMemory( void )
+void BG_InitMemory( void )
{
// Set up the initial node
- freehead = (struct freememnode *)memoryPool;
- freehead->cookie = FREEMEMCOOKIE;
- freehead->size = POOLSIZE;
- freehead->next = NULL;
- freehead->prev = NULL;
- freemem = sizeof( memoryPool );
+ freeHead = (freeMemNode_t *)memoryPool;
+ freeHead->cookie = FREEMEMCOOKIE;
+ freeHead->size = POOLSIZE;
+ freeHead->next = NULL;
+ freeHead->prev = NULL;
+ freeMem = sizeof( memoryPool );
}
-void G_DefragmentMemory( void )
+void BG_DefragmentMemory( void )
{
// If there's a frenzy of deallocation and we want to
// allocate something big, this is useful. Otherwise...
// not much use.
- struct freememnode *startfmn, *endfmn, *fmn;
+ freeMemNode_t *startfmn, *endfmn, *fmn;
- for( startfmn = freehead; startfmn; )
+ for( startfmn = freeHead; startfmn; )
{
- endfmn = (struct freememnode *)(((char *) startfmn) + startfmn->size);
- for( fmn = freehead; fmn; )
+ endfmn = (freeMemNode_t *)(((char *) startfmn) + startfmn->size);
+ for( fmn = freeHead; fmn; )
{
if( fmn->cookie != FREEMEMCOOKIE )
- G_Error( "G_DefragmentMemory: Memory corruption detected!\n" );
+ Com_Error( ERR_DROP, "BG_DefragmentMemory: Memory corruption detected!" );
if( fmn == endfmn )
{
@@ -184,12 +187,12 @@ void G_DefragmentMemory( void )
if( fmn->next )
{
if( !(fmn->next->prev = fmn->prev) )
- freehead = fmn->next; // We're removing the head node
+ freeHead = fmn->next; // We're removing the head node
}
startfmn->size += fmn->size;
- memset( fmn, 0, sizeof(struct freememnode) ); // A redundant call, really.
+ memset( fmn, 0, sizeof(freeMemNode_t) ); // A redundant call, really.
- startfmn = freehead;
+ startfmn = freeHead;
endfmn = fmn = NULL; // Break out of current loop
}
else
@@ -201,16 +204,39 @@ void G_DefragmentMemory( void )
}
}
-void Svcmd_GameMem_f( void )
+void BG_MemoryInfo( void )
{
// Give a breakdown of memory
- struct freememnode *fmn;
+ freeMemNode_t *fmn = (freeMemNode_t *)memoryPool;
+ int size, chunks;
+ freeMemNode_t *end = (freeMemNode_t *)( memoryPool + POOLSIZE );
+ void *p;
- G_Printf( "Game memory status: %i out of %i bytes allocated\n", POOLSIZE - freemem, POOLSIZE );
+ Com_Printf( "%p-%p: %d out of %d bytes allocated\n",
+ fmn, end, POOLSIZE - freeMem, POOLSIZE );
- for( fmn = freehead; fmn; fmn = fmn->next )
- G_Printf( " %dd: %d bytes free.\n", fmn, fmn->size );
- G_Printf( "Status complete.\n" );
+ while( fmn < end )
+ {
+ size = chunks = 0;
+ p = fmn;
+ while( fmn < end && fmn->cookie == FREEMEMCOOKIE )
+ {
+ size += fmn->size;
+ chunks++;
+ fmn = (freeMemNode_t *)( (char *)fmn + fmn->size );
+ }
+ if( size )
+ Com_Printf( " %p: %d bytes free (%d chunks)\n", p, size, chunks );
+ size = chunks = 0;
+ p = fmn;
+ while( fmn < end && fmn->cookie != FREEMEMCOOKIE )
+ {
+ size += *(int *)fmn;
+ chunks++;
+ fmn = (freeMemNode_t *)( (size_t)fmn + *(int *)fmn );
+ }
+ if( size )
+ Com_Printf( " %p: %d bytes allocated (%d chunks)\n", p, size, chunks );
+ }
}
-
diff --git a/src/game/bg_lib.c b/src/game/bg_lib.c
index 69bca48..73b9a5d 100644
--- a/src/game/bg_lib.c
+++ b/src/game/bg_lib.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -25,7 +26,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// compiled for the virtual machine
-#include "../qcommon/q_shared.h"
+#ifdef Q3_VM
+
+#include "qcommon/q_shared.h"
/*-
* Copyright (c) 1992, 1993
@@ -67,21 +70,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
#endif
static const char rcsid[] =
- "$Id: bg_lib.c 965 2007-08-09 13:54:12Z msk $";
+ "$Id$";
#endif /* LIBC_SCCS and not lint */
-// bk001127 - needed for DLL's
-#if !defined( Q3_VM )
-typedef int cmp_t(const void *, const void *);
-#endif
-
static char* med3(char *, char *, char *, cmp_t *);
static void swapfunc(char *, char *, int, int);
-#ifndef min
-#define min(a, b) (a) < (b) ? a : b
-#endif
-
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*/
@@ -197,9 +191,9 @@ loop: SWAPINIT(a, es);
}
pn = (char *)a + n * es;
- r = min(pa - (char *)a, pb - pa);
+ r = MIN(pa - (char *)a, pb - pa);
vecswap(a, pb - r, r);
- r = min(pd - pc, pn - pd - es);
+ r = MIN(pd - pc, pn - pd - es);
vecswap(pb, pn - r, r);
if ((r = pb - pa) > es)
qsort(a, r / es, es, cmp);
@@ -215,11 +209,6 @@ loop: SWAPINIT(a, es);
//==================================================================================
-// this file is excluded from release builds because of intrinsics
-
-// bk001211 - gcc errors on compiling strcpy: parse error before `__extension__'
-#if defined ( Q3_VM )
-
size_t strlen( const char *string )
{
const char *s;
@@ -272,13 +261,12 @@ int strcmp( const char *string1, const char *string2 )
return *string1 - *string2;
}
-//TA:
char *strrchr( const char *string, int c )
{
int i, length = strlen( string );
char *p;
- for( i = length - 1; i >= 0; i-- )
+ for( i = length /*sic*/; i >= 0; i-- )
{
p = (char *)&string[ i ];
@@ -298,7 +286,7 @@ char *strchr( const char *string, int c )
string++;
}
- return (char *)0;
+ return c == '\0' ? (char *)string : (char *)0;
}
char *strstr( const char *string, const char *strCharSet )
@@ -321,10 +309,6 @@ char *strstr( const char *string, const char *strCharSet )
return (char *)0;
}
-#endif // bk001211
-
-#if defined ( Q3_VM )
-
int tolower( int c )
{
if( c >= 'A' && c <= 'Z' )
@@ -342,21 +326,23 @@ int toupper( int c )
return c;
}
-#endif
-
void *memmove( void *dest, const void *src, size_t count )
{
- int i;
+ size_t i;
if( dest > src )
{
- for( i = count - 1; i >= 0; i-- )
- ( (char *)dest )[ i ] = ( (char *)src )[ i ];
+ i = count;
+ while( i > 0 )
+ {
+ i--;
+ ((char *)dest)[ i ] = ((char *)src)[ i ];
+ }
}
else
{
for( i = 0; i < count; i++ )
- ( (char *)dest )[ i ] = ( (char *)src )[ i ];
+ ((char *) dest)[ i ] = ((char *)src)[ i ];
}
return dest;
@@ -816,7 +802,6 @@ double atan2( double y, double x ) {
#endif
-#ifdef Q3_VM
/*
===============
rint
@@ -830,8 +815,43 @@ double rint( double v )
return floor( v );
}
-// bk001127 - guarded this tan replacement
-// ld: undefined versioned symbol name tan@@GLIBC_2.0
+/*
+===============
+powN
+
+Raise a double to a integer power
+===============
+*/
+static double powN( double base, int exp )
+{
+ if( exp >= 0 )
+ {
+ double result = 1.0;
+
+ // calculate x, x^2, x^4, ... by repeated squaring
+ // and multiply together the ones corresponding to the
+ // binary digits of the exponent
+ // e.g. x^73 = x^(1 + 8 + 64) = x * x^8 * x^64
+ while( exp > 0 )
+ {
+ if( exp % 2 == 1 )
+ result *= base;
+
+ base *= base;
+ exp /= 2;
+ }
+
+ return result;
+ }
+ // if exp is INT_MIN, the next clause will be upset,
+ // because -exp isn't representable
+ else if( exp == INT_MIN )
+ return powN( base, exp + 1 ) / base;
+ // x < 0
+ else
+ return 1.0 / powN( base, -exp );
+}
+
double tan( double x )
{
return sin( x ) / cos( x );
@@ -1316,8 +1336,6 @@ float pow( float x, float y )
return s * z;
}
-#endif
-
static int randSeed = 0;
@@ -1409,12 +1427,210 @@ double atof( const char *string )
return value * sign;
}
+/*
+==============
+strtod
+
+Without an errno variable, this is a fair bit less useful than it is in libc
+but it's still a fair bit more capable than atof or _atof
+Handles inf[inity], nan (ignoring case), hexadecimals, and decimals
+Handles decimal exponents like 10e10 and hex exponents like 0x7f8p20
+10e10 == 10000000000 (power of ten)
+0x7f8p20 == 0x7f800000 (decimal power of two)
+The variable pointed to by endptr will hold the location of the first character
+in the nptr string that was not used in the conversion
+==============
+*/
+double strtod( const char *nptr, char **endptr )
+{
+ double res;
+ qboolean neg = qfalse;
+
+ // skip whitespace
+ while( isspace( *nptr ) )
+ nptr++;
+
+ // special string parsing
+ if( Q_stricmpn( nptr, "nan", 3 ) == 0 )
+ {
+ floatint_t nan;
+
+ if( endptr )
+ *endptr = (char *)&nptr[3];
+
+ // nan can be followed by a bracketed number (in hex, octal,
+ // or decimal) which is then put in the mantissa
+ // this can be used to generate signalling or quiet NaNs, for
+ // example (though I doubt it'll ever be used)
+ // note that nan(0) is infinity!
+ if( nptr[3] == '(' )
+ {
+ char *end;
+ int mantissa = strtol( &nptr[4], &end, 0 );
+
+ if( *end == ')' )
+ {
+ nan.ui = 0x7f800000 | ( mantissa & 0x7fffff );
+
+ if( endptr )
+ *endptr = &end[1];
+ return nan.f;
+ }
+ }
+
+ nan.ui = 0x7fffffff;
+ return nan.f;
+ }
+
+ if( Q_stricmpn( nptr, "inf", 3 ) == 0 )
+ {
+ floatint_t inf;
+ inf.ui = 0x7f800000;
+
+ if( endptr == NULL )
+ return inf.f;
+
+ if( Q_stricmpn( &nptr[3], "inity", 5 ) == 0 )
+ *endptr = (char *)&nptr[8];
+ else
+ *endptr = (char *)&nptr[3];
+
+ return inf.f;
+ }
+
+ // normal numeric parsing
+ // sign
+ if( *nptr == '-' )
+ {
+ nptr++;
+ neg = qtrue;
+ }
+ else if( *nptr == '+' )
+ nptr++;
+
+ // hex
+ if( Q_stricmpn( nptr, "0x", 2 ) == 0 )
+ {
+ // track if we use any digits
+ const char *s = &nptr[1], *end = s;
+ nptr += 2;
+
+ for( res = 0;; )
+ {
+ if( isdigit( *nptr ) )
+ res = 16 * res + ( *nptr++ - '0' );
+ else if( *nptr >= 'A' && *nptr <= 'F' )
+ res = 16 * res + 10 + *nptr++ - 'A';
+ else if( *nptr >= 'a' && *nptr <= 'f' )
+ res = 16 * res + 10 + *nptr++ - 'a';
+ else
+ break;
+ }
+
+ // if nptr moved, save it
+ if( end + 1 < nptr )
+ end = nptr;
+
+ if( *nptr == '.' )
+ {
+ float place;
+ nptr++;
+
+ // 1.0 / 16.0 == 0.0625
+ // I don't expect the float accuracy to hold out for
+ // very long but since we need to know the length of
+ // the string anyway we keep on going regardless
+ for( place = 0.0625;; place /= 16.0 )
+ {
+ if( isdigit( *nptr ) )
+ res += place * ( *nptr++ - '0' );
+ else if( *nptr >= 'A' && *nptr <= 'F' )
+ res += place * ( 10 + *nptr++ - 'A' );
+ else if( *nptr >= 'a' && *nptr <= 'f' )
+ res += place * ( 10 + *nptr++ - 'a' );
+ else
+ break;
+ }
+
+ if( end < nptr )
+ end = nptr;
+ }
+
+ // parse an optional exponent, representing multiplication
+ // by a power of two
+ // exponents are only valid if we encountered at least one
+ // digit already (and have therefore set end to something)
+ if( end != s && tolower( *nptr ) == 'p' )
+ {
+ int exp;
+ // apparently (confusingly) the exponent should be
+ // decimal
+ exp = strtol( &nptr[1], (char **)&end, 10 );
+ if( &nptr[1] == end )
+ {
+ // no exponent
+ if( endptr )
+ *endptr = (char *)nptr;
+ return res;
+ }
+
+ res *= powN( 2, exp );
+ }
+ if( endptr )
+ *endptr = (char *)end;
+ return res;
+ }
+ // decimal
+ else
+ {
+ // track if we find any digits
+ const char *end = nptr, *p = nptr;
+ // this is most of the work
+ for( res = 0; isdigit( *nptr );
+ res = 10 * res + *nptr++ - '0' );
+ // if nptr moved, we read something
+ if( end < nptr )
+ end = nptr;
+ if( *nptr == '.' )
+ {
+ // fractional part
+ float place;
+ nptr++;
+ for( place = 0.1; isdigit( *nptr ); place /= 10.0 )
+ res += ( *nptr++ - '0' ) * place;
+ // if nptr moved, we read something
+ if( end + 1 < nptr )
+ end = nptr;
+ }
+ // exponent
+ // meaningless without having already read digits, so check
+ // we've set end to something
+ if( p != end && tolower( *nptr ) == 'e' )
+ {
+ int exp;
+ exp = strtol( &nptr[1], (char **)&end, 10 );
+ if( &nptr[1] == end )
+ {
+ // no exponent
+ if( endptr )
+ *endptr = (char *)nptr;
+ return res;
+ }
+
+ res *= powN( 10, exp );
+ }
+ if( endptr )
+ *endptr = (char *)end;
+ return res;
+ }
+}
+
double _atof( const char **stringPtr )
{
const char *string;
float sign;
float value;
- int c = '0'; // bk001211 - uninitialized use possible
+ int c = '0';
string = *stringPtr;
@@ -1488,8 +1704,108 @@ double _atof( const char **stringPtr )
return value * sign;
}
+/*
+==============
+strtol
+
+Handles any base from 2 to 36. If base is 0 then it guesses
+decimal, hex, or octal based on the format of the number (leading 0 or 0x)
+Will not overflow - returns LONG_MIN or LONG_MAX as appropriate
+*endptr is set to the location of the first character not used
+==============
+*/
+long strtol( const char *nptr, char **endptr, int base )
+{
+ long res;
+ qboolean pos = qtrue;
+
+ if( endptr )
+ *endptr = (char *)nptr;
+
+ // bases other than 0, 2, 8, 16 are very rarely used, but they're
+ // not much extra effort to support
+ if( base < 0 || base == 1 || base > 36 )
+ return 0;
+
+ // skip leading whitespace
+ while( isspace( *nptr ) )
+ nptr++;
+
+ // sign
+ if( *nptr == '-' )
+ {
+ nptr++;
+ pos = qfalse;
+ }
+ else if( *nptr == '+' )
+ nptr++;
-#if defined ( Q3_VM )
+ // look for base-identifying sequences e.g. 0x for hex, 0 for octal
+ if( nptr[0] == '0' )
+ {
+ nptr++;
+
+ // 0 is always a valid digit
+ if( endptr )
+ *endptr = (char *)nptr;
+
+ if( *nptr == 'x' || *nptr == 'X' )
+ {
+ if( base != 0 && base != 16 )
+ {
+ // can't be hex, reject x (accept 0)
+ if( endptr )
+ *endptr = (char *)nptr;
+ return 0;
+ }
+
+ nptr++;
+ base = 16;
+ }
+ else if( base == 0 )
+ base = 8;
+ }
+ else if( base == 0 )
+ base = 10;
+
+ for( res = 0;; )
+ {
+ int val;
+
+ if( isdigit( *nptr ) )
+ val = *nptr - '0';
+ else if( islower( *nptr ) )
+ val = 10 + *nptr - 'a';
+ else if( isupper( *nptr ) )
+ val = 10 + *nptr - 'A';
+ else
+ break;
+
+ if( val >= base )
+ break;
+
+ // we go negative because LONG_MIN is further from 0 than
+ // LONG_MAX
+ if( res < ( LONG_MIN + val ) / base )
+ res = LONG_MIN; // overflow
+ else
+ res = res * base - val;
+
+ nptr++;
+
+ if( endptr )
+ *endptr = (char *)nptr;
+ }
+ if( pos )
+ {
+ // can't represent LONG_MIN positive
+ if( res == LONG_MIN )
+ res = LONG_MAX;
+ else
+ res = -res;
+ }
+ return res;
+}
int atoi( const char *string )
{
@@ -1613,9 +1929,9 @@ unsigned int _hextoi( const char **stringPtr )
int c;
int i;
const char *string;
-
+
string = *stringPtr;
-
+
// skip whitespace
while( *string <= ' ' )
{
@@ -1653,356 +1969,751 @@ unsigned int _hextoi( const char **stringPtr )
//=========================================================
+/*
+ * New implementation by Patrick Powell and others for vsnprintf.
+ * Supports length checking in strings.
+ */
-#define ALT 0x00000001 /* alternate form */
-#define HEX 0x00000002 /* hexadecimal */
-#define LADJUST 0x00000004 /* left adjustment */
-#define LONGDBL 0x00000008 /* long double */
-#define LONGINT 0x00000010 /* long integer */
-#define QUADINT 0x00000020 /* quad integer */
-#define SHORTINT 0x00000040 /* short integer */
-#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */
-#define FPT 0x00000100 /* floating point number */
-#define UNSIGNED 0x00000200 /* unsigned integer */
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell@astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
-#define to_digit(c) ((c) - '0')
-#define is_digit(c) ((unsigned)to_digit(c) <= 9)
-#define to_char(n) ((n) + '0')
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh. This sort of thing is always nasty do deal with. Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length. This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
+ * This was ugly. It is still ugly. I opted out of floating point
+ * numbers, but the formatter understands just about everything
+ * from the normal C string format, at least as far as I can tell from
+ * the Solaris 2.5 printf(3S) man page.
+ *
+ * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
+ * Ok, added some minimal floating point support, which means this
+ * probably requires libm on most operating systems. Don't yet
+ * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
+ * was pretty badly broken, it just wasn't being exercised in ways
+ * which showed it, so that's been fixed. Also, formated the code
+ * to mutt conventions, and removed dead code left over from the
+ * original. Also, there is now a builtin-test, just compile with:
+ * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ * and run snprintf for results.
+ *
+ * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
+ * The PGP code was using unsigned hexadecimal formats.
+ * Unfortunately, unsigned formats simply didn't work.
+ *
+ * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ * The original code assumed that both snprintf() and vsnprintf() were
+ * missing. Some systems only have snprintf() but not vsnprintf(), so
+ * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ * Andrew Tridgell (tridge@samba.org) Oct 1998
+ * fixed handling of %.0f
+ * added test for HAVE_LONG_DOUBLE
+ *
+ * Russ Allbery <rra@stanford.edu> 2000-08-26
+ * fixed return value to comply with C99
+ * fixed handling of snprintf(NULL, ...)
+ *
+ * Hrvoje Niksic <hniksic@arsdigita.com> 2000-11-04
+ * include <config.h> instead of "config.h".
+ * moved TEST_SNPRINTF stuff out of HAVE_SNPRINTF ifdef.
+ * include <stdio.h> for NULL.
+ * added support and test cases for long long.
+ * don't declare argument types to (v)snprintf if stdarg is not used.
+ * use int instead of short int as 2nd arg to va_arg.
+ *
+ **************************************************************/
-void AddInt( char **buf_p, int val, int width, int flags )
-{
- char text[ 32 ];
- int digits;
- char *buf;
+/* BDR 2002-01-13 %e and %g were being ignored. Now do something,
+ if not necessarily correctly */
+
+#if (SIZEOF_LONG_DOUBLE > 0)
+/* #ifdef HAVE_LONG_DOUBLE */
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif
- digits = 0;
+#if (SIZEOF_LONG_LONG > 0)
+/* #ifdef HAVE_LONG_LONG */
+# define LLONG long long
+#else
+# define LLONG long
+#endif
- if( flags & UNSIGNED )
- val = (unsigned) val;
+static int dopr (char *buffer, size_t maxlen, const char *format,
+ va_list args);
+static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max);
+static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
+ LLONG value, int base, int min, int max, int flags);
+static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags);
+static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
- if( flags & HEX )
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS 1
+#define DP_S_MIN 2
+#define DP_S_DOT 3
+#define DP_S_MAX 4
+#define DP_S_MOD 5
+#define DP_S_MOD_L 6
+#define DP_S_CONV 7
+#define DP_S_DONE 8
+
+/* format flags - Bits */
+#define DP_F_MINUS (1 << 0)
+#define DP_F_PLUS (1 << 1)
+#define DP_F_SPACE (1 << 2)
+#define DP_F_NUM (1 << 3)
+#define DP_F_ZERO (1 << 4)
+#define DP_F_UP (1 << 5)
+#define DP_F_UNSIGNED (1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT 1
+#define DP_C_LONG 2
+#define DP_C_LLONG 3
+#define DP_C_LDOUBLE 4
+
+#define char_to_int(p) (p - '0')
+
+static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
+{
+ char ch;
+ LLONG value;
+ LDOUBLE fvalue;
+ char *strvalue;
+ int min;
+ int max;
+ int state;
+ int flags;
+ int cflags;
+ int total;
+ size_t currlen;
+
+ state = DP_S_DEFAULT;
+ currlen = flags = cflags = min = 0;
+ max = -1;
+ ch = *format++;
+ total = 0;
+
+ while (state != DP_S_DONE)
{
- char c;
- int n = 0;
+ if (ch == '\0')
+ state = DP_S_DONE;
- while( n < 32 )
+ switch(state)
{
- c = "0123456789abcdef"[ ( val >> n ) & 0xF ];
- n += 4;
- if( c == '0' && !digits )
- continue;
- text[ digits++ ] = c;
+ case DP_S_DEFAULT:
+ if (ch == '%')
+ state = DP_S_FLAGS;
+ else
+ total += dopr_outch (buffer, &currlen, maxlen, ch);
+ ch = *format++;
+ break;
+ case DP_S_FLAGS:
+ switch (ch)
+ {
+ case '-':
+ flags |= DP_F_MINUS;
+ ch = *format++;
+ break;
+ case '+':
+ flags |= DP_F_PLUS;
+ ch = *format++;
+ break;
+ case ' ':
+ flags |= DP_F_SPACE;
+ ch = *format++;
+ break;
+ case '#':
+ flags |= DP_F_NUM;
+ ch = *format++;
+ break;
+ case '0':
+ flags |= DP_F_ZERO;
+ ch = *format++;
+ break;
+ default:
+ state = DP_S_MIN;
+ break;
+ }
+ break;
+ case DP_S_MIN:
+ if ('0' <= ch && ch <= '9')
+ {
+ min = 10*min + char_to_int (ch);
+ ch = *format++;
+ }
+ else if (ch == '*')
+ {
+ min = va_arg (args, int);
+ ch = *format++;
+ state = DP_S_DOT;
+ }
+ else
+ state = DP_S_DOT;
+ break;
+ case DP_S_DOT:
+ if (ch == '.')
+ {
+ state = DP_S_MAX;
+ ch = *format++;
+ }
+ else
+ state = DP_S_MOD;
+ break;
+ case DP_S_MAX:
+ if ('0' <= ch && ch <= '9')
+ {
+ if (max < 0)
+ max = 0;
+ max = 10*max + char_to_int (ch);
+ ch = *format++;
+ }
+ else if (ch == '*')
+ {
+ max = va_arg (args, int);
+ ch = *format++;
+ state = DP_S_MOD;
+ }
+ else
+ state = DP_S_MOD;
+ break;
+ case DP_S_MOD:
+ switch (ch)
+ {
+ case 'h':
+ cflags = DP_C_SHORT;
+ ch = *format++;
+ break;
+ case 'l':
+ cflags = DP_C_LONG;
+ ch = *format++;
+ break;
+ case 'L':
+ cflags = DP_C_LDOUBLE;
+ ch = *format++;
+ break;
+ default:
+ break;
+ }
+ if (cflags != DP_C_LONG)
+ state = DP_S_CONV;
+ else
+ state = DP_S_MOD_L;
+ break;
+ case DP_S_MOD_L:
+ switch (ch)
+ {
+ case 'l':
+ cflags = DP_C_LLONG;
+ ch = *format++;
+ break;
+ default:
+ break;
+ }
+ state = DP_S_CONV;
+ break;
+ case DP_S_CONV:
+ switch (ch)
+ {
+ case 'd':
+ case 'i':
+ if (cflags == DP_C_SHORT)
+ value = (short int)va_arg (args, int);
+ else if (cflags == DP_C_LONG)
+ value = va_arg (args, long int);
+ else if (cflags == DP_C_LLONG)
+ value = va_arg (args, LLONG);
+ else
+ value = va_arg (args, int);
+ total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+ break;
+ case 'o':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ // value = (unsigned short int) va_arg (args, unsigned short int); // Thilo: This does not work because the rcc compiler cannot do that cast correctly.
+ value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1); // Using this workaround instead.
+ else if (cflags == DP_C_LONG)
+ value = va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = va_arg (args, unsigned LLONG);
+ else
+ value = va_arg (args, unsigned int);
+ total += fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
+ break;
+ case 'u':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1);
+ else if (cflags == DP_C_LONG)
+ value = va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = va_arg (args, unsigned LLONG);
+ else
+ value = va_arg (args, unsigned int);
+ total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+ break;
+ case 'X':
+ flags |= DP_F_UP;
+ case 'x':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1);
+ else if (cflags == DP_C_LONG)
+ value = va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = va_arg (args, unsigned LLONG);
+ else
+ value = va_arg (args, unsigned int);
+ total += fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
+ break;
+ case 'f':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ /* um, floating point? */
+ total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+ break;
+ case 'E':
+ flags |= DP_F_UP;
+ case 'e':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ /* um, floating point? */
+ total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+ break;
+ case 'G':
+ flags |= DP_F_UP;
+ case 'g':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ /* um, floating point? */
+ total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+ break;
+ case 'c':
+ total += dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
+ break;
+ case 's':
+ strvalue = va_arg (args, char *);
+ total += fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
+ break;
+ case 'p':
+ strvalue = va_arg (args, void *);
+ total += fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min,
+ max, flags);
+ break;
+ case 'n':
+ if (cflags == DP_C_SHORT)
+ {
+ short int *num;
+ num = va_arg (args, short int *);
+ *num = currlen;
+ }
+ else if (cflags == DP_C_LONG)
+ {
+ long int *num;
+ num = va_arg (args, long int *);
+ *num = currlen;
+ }
+ else if (cflags == DP_C_LLONG)
+ {
+ LLONG *num;
+ num = va_arg (args, LLONG *);
+ *num = currlen;
+ }
+ else
+ {
+ int *num;
+ num = va_arg (args, int *);
+ *num = currlen;
+ }
+ break;
+ case '%':
+ total += dopr_outch (buffer, &currlen, maxlen, ch);
+ break;
+ case 'w':
+ /* not supported yet, treat as next char */
+ ch = *format++;
+ break;
+ default:
+ /* Unknown, skip */
+ break;
+ }
+ ch = *format++;
+ state = DP_S_DEFAULT;
+ flags = cflags = min = 0;
+ max = -1;
+ break;
+ case DP_S_DONE:
+ break;
+ default:
+ /* hmm? */
+ break; /* some picky compilers need this */
}
- text[ digits ] = '\0';
}
- else
- {
- int signedVal = val;
+ if (maxlen > 0)
+ buffer[currlen] = '\0';
+ return total;
+}
- if( val < 0 )
- val = -val;
- do
- {
- text[ digits++ ] = '0' + val % 10;
- val /= 10;
- } while( val );
+static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max)
+{
+ int padlen, strln; /* amount to pad */
+ int cnt = 0;
+ int total = 0;
- if( signedVal < 0 )
- text[ digits++ ] = '-';
+ if (value == 0)
+ {
+ value = "<NULL>";
}
- buf = *buf_p;
+ for (strln = 0; value[strln]; ++strln); /* strlen */
+ if (max >= 0 && max < strln)
+ strln = max;
+ padlen = min - strln;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justify */
- if( !( flags & LADJUST ) )
+ while (padlen > 0)
{
- while( digits < width )
- {
- *buf++ = ( flags & ZEROPAD ) ? '0' : ' ';
- width--;
- }
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
}
-
- while( digits-- )
+ while (*value && ((max < 0) || (cnt < max)))
{
- *buf++ = text[ digits ];
- width--;
+ total += dopr_outch (buffer, currlen, maxlen, *value++);
+ ++cnt;
}
-
- if( flags & LADJUST )
+ while (padlen < 0)
{
- while( width-- > 0 )
- *buf++ = ( flags & ZEROPAD ) ? '0' : ' ';
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
}
-
- *buf_p = buf;
+ return total;
}
-void AddFloat( char **buf_p, float fval, int width, int prec )
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
+ LLONG value, int base, int min, int max, int flags)
{
- char text[ 32 ];
- int digits;
- float signedVal;
- char *buf;
- int val;
+ int signvalue = 0;
+ unsigned LLONG uvalue;
+ char convert[24];
+ int place = 0;
+ int spadlen = 0; /* amount to space pad */
+ int zpadlen = 0; /* amount to zero pad */
+ const char *digits;
+ int total = 0;
- // get the sign
- signedVal = fval;
- if( fval < 0 )
- fval = -fval;
+ if (max < 0)
+ max = 0;
- // write the float number
- digits = 0;
- val = (int)fval;
+ uvalue = value;
- do
+ if(!(flags & DP_F_UNSIGNED))
{
- text[ digits++ ] = '0' + val % 10;
- val /= 10;
- } while( val );
-
- if( signedVal < 0 )
- text[digits++] = '-';
+ if( value < 0 ) {
+ signvalue = '-';
+ uvalue = -value;
+ }
+ else
+ if (flags & DP_F_PLUS) /* Do a sign (+/i) */
+ signvalue = '+';
+ else
+ if (flags & DP_F_SPACE)
+ signvalue = ' ';
+ }
- buf = *buf_p;
+ if (flags & DP_F_UP)
+ /* Should characters be upper case? */
+ digits = "0123456789ABCDEF";
+ else
+ digits = "0123456789abcdef";
- while( digits < width )
+ do {
+ convert[place++] = digits[uvalue % (unsigned)base];
+ uvalue = (uvalue / (unsigned)base );
+ } while(uvalue && (place < sizeof (convert)));
+ if (place == sizeof (convert)) place--;
+ convert[place] = 0;
+
+ zpadlen = max - place;
+ spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+ if (zpadlen < 0) zpadlen = 0;
+ if (spadlen < 0) spadlen = 0;
+ if (flags & DP_F_ZERO)
{
- *buf++ = ' ';
- width--;
+ zpadlen = MAX(zpadlen, spadlen);
+ spadlen = 0;
}
+ if (flags & DP_F_MINUS)
+ spadlen = -spadlen; /* Left Justifty */
- while( digits-- )
- *buf++ = text[ digits ];
-
- *buf_p = buf;
+#ifdef DEBUG_SNPRINTF
+ dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+ zpadlen, spadlen, min, max, place));
+#endif
- if( prec < 0 )
- prec = 6;
+ /* Spaces */
+ while (spadlen > 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ --spadlen;
+ }
- // write the fraction
- digits = 0;
+ /* Sign */
+ if (signvalue)
+ total += dopr_outch (buffer, currlen, maxlen, signvalue);
- while( digits < prec )
+ /* Zeros */
+ if (zpadlen > 0)
{
- fval -= (int)fval;
- fval *= 10.0;
- val = (int)fval;
- text[ digits++ ] = '0' + val % 10;
+ while (zpadlen > 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
}
- if( digits > 0 )
- {
- buf = *buf_p;
- *buf++ = '.';
- for( prec = 0; prec < digits; prec++ )
- *buf++ = text[ prec ];
+ /* Digits */
+ while (place > 0)
+ total += dopr_outch (buffer, currlen, maxlen, convert[--place]);
- *buf_p = buf;
+ /* Left Justified spaces */
+ while (spadlen < 0) {
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ ++spadlen;
}
+
+ return total;
}
-void AddVec3_t( char **buf_p, vec3_t v, int width, int prec )
+static LDOUBLE abs_val (LDOUBLE value)
{
- char *buf;
+ LDOUBLE result = value;
- buf = *buf_p;
+ if (value < 0)
+ result = -value;
- *buf++ = '[';
-
- AddFloat( &buf, v[ 0 ], width, prec );
- buf += width;
- *buf++ = ' ';
+ return result;
+}
- AddFloat( &buf, v[ 1 ], width, prec );
- buf += width;
- *buf++ = ' ';
+static long round (LDOUBLE value)
+{
+ long intpart;
- AddFloat( &buf, v[ 2 ], width, prec );
- buf += width;
- *buf++ = ']';
+ intpart = value;
+ value = value - intpart;
+ if (value >= 0.5)
+ intpart++;
- *buf_p = buf;
+ return intpart;
}
-void AddString( char **buf_p, char *string, int width, int prec )
+static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags)
{
- int size;
- char *buf;
+ int signvalue = 0;
+ LDOUBLE ufvalue;
+ char iconvert[20];
+ char fconvert[20];
+ int iplace = 0;
+ int fplace = 0;
+ int padlen = 0; /* amount to pad */
+ int zpadlen = 0;
+ int caps = 0;
+ int total = 0;
+ long intpart;
+ long fracpart;
- buf = *buf_p;
+ /*
+ * AIX manpage says the default is 0, but Solaris says the default
+ * is 6, and sprintf on AIX defaults to 6
+ */
+ if (max < 0)
+ max = 6;
- if( string == NULL )
- {
- string = "(null)";
- prec = -1;
- }
+ ufvalue = abs_val (fvalue);
- if( prec >= 0 )
- {
- for( size = 0; size < prec; size++ )
- {
- if( string[ size ] == '\0' )
- break;
- }
- }
+ if (fvalue < 0)
+ signvalue = '-';
else
- size = strlen( string );
-
- width -= size;
+ if (flags & DP_F_PLUS) /* Do a sign (+/i) */
+ signvalue = '+';
+ else
+ if (flags & DP_F_SPACE)
+ signvalue = ' ';
- while( size-- )
- *buf++ = *string++;
+#if 0
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
- while( width-- > 0 )
- *buf++ = ' ';
+ intpart = ufvalue;
- *buf_p = buf;
-}
+ /*
+ * Sorry, we only support 9 digits past the decimal because of our
+ * conversion method
+ */
+ if (max > 9)
+ max = 9;
-/*
-vsprintf
+ /* We "cheat" by converting the fractional part to integer by
+ * multiplying by a factor of 10
+ */
+ fracpart = round ((powN (10, max)) * (ufvalue - intpart));
-I'm not going to support a bunch of the more arcane stuff in here
-just to keep it simpler. For example, the '*' and '$' are not
-currently supported. I've tried to make it so that it will just
-parse and ignore formats we don't support.
-*/
-int vsprintf( char *buffer, const char *fmt, va_list argptr )
-{
- int *arg;
- char *buf_p;
- char ch;
- int flags;
- int width;
- int prec;
- int n;
- char sign;
-
- buf_p = buffer;
- arg = (int *)argptr;
-
- while( qtrue )
+ if (fracpart >= powN (10, max))
{
- // run through the format string until we hit a '%' or '\0'
- for( ch = *fmt; ( ch = *fmt ) != '\0' && ch != '%'; fmt++ )
- *buf_p++ = ch;
+ intpart++;
+ fracpart -= powN (10, max);
+ }
- if( ch == '\0' )
- goto done;
+#ifdef DEBUG_SNPRINTF
+ dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
+#endif
- // skip over the '%'
- fmt++;
+ /* Convert integer part */
+ do {
+ iconvert[iplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
+ intpart = (intpart / 10);
+ } while(intpart && (iplace < 20));
+ if (iplace == 20) iplace--;
+ iconvert[iplace] = 0;
+
+ /* Convert fractional part */
+ do {
+ fconvert[fplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
+ fracpart = (fracpart / 10);
+ } while(fracpart && (fplace < 20));
+ if (fplace == 20) fplace--;
+ fconvert[fplace] = 0;
+
+ /* -1 for decimal point, another -1 if we are printing a sign */
+ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+ zpadlen = max - fplace;
+ if (zpadlen < 0)
+ zpadlen = 0;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justifty */
+
+ if ((flags & DP_F_ZERO) && (padlen > 0))
+ {
+ if (signvalue)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, signvalue);
+ --padlen;
+ signvalue = 0;
+ }
+ while (padlen > 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, '0');
+ --padlen;
+ }
+ }
+ while (padlen > 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
+ }
+ if (signvalue)
+ total += dopr_outch (buffer, currlen, maxlen, signvalue);
- // reset formatting state
- flags = 0;
- width = 0;
- prec = -1;
- sign = '\0';
+ while (iplace > 0)
+ total += dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
-rflag:
- ch = *fmt++;
-reswitch:
- switch( ch )
- {
- case '-':
- flags |= LADJUST;
- goto rflag;
-
- case '.':
- n = 0;
- while( is_digit( ( ch = *fmt++ ) ) )
- n = 10 * n + ( ch - '0' );
-
- prec = n < 0 ? -1 : n;
- goto reswitch;
-
- case '0':
- flags |= ZEROPAD;
- goto rflag;
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- n = 0;
- do
- {
- n = 10 * n + ( ch - '0' );
- ch = *fmt++;
- } while( is_digit( ch ) );
+ /*
+ * Decimal point. This should probably use locale to find the correct
+ * char to print out.
+ */
+ if (max > 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, '.');
- width = n;
- goto reswitch;
+ while (zpadlen-- > 0)
+ total += dopr_outch (buffer, currlen, maxlen, '0');
- case 'c':
- *buf_p++ = (char)*arg;
- arg++;
- break;
+ while (fplace > 0)
+ total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
+ }
- case 'u':
- flags |= UNSIGNED;
- case 'd':
- case 'i':
- AddInt( &buf_p, *arg, width, flags );
- arg++;
- break;
+ while (padlen < 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
+ }
- case 'f':
- AddFloat( &buf_p, *(double *)arg, width, prec );
-#ifdef Q3_VM
- arg += 1; // everything is 32 bit in my compiler
-#else
- arg += 2;
-#endif
- break;
+ return total;
+}
- case 's':
- AddString( &buf_p, (char *)*arg, width, prec );
- arg++;
- break;
+static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+ if (*currlen + 1 < maxlen)
+ buffer[(*currlen)++] = c;
+ return 1;
+}
- case 'v':
- AddVec3_t( &buf_p, (vec_t *)*arg, width, prec );
- arg++;
- break;
-
- case 'x':
- flags |= HEX;
- AddInt( &buf_p, *arg, width, prec );
- arg++;
- break;
+int Q_vsnprintf(char *str, size_t length, const char *fmt, va_list args)
+{
+ return dopr(str, length, fmt, args);
+}
- case '%':
- *buf_p++ = ch;
- break;
+int Q_snprintf(char *str, size_t length, const char *fmt, ...)
+{
+ va_list ap;
+ int retval;
- default:
- *buf_p++ = (char)*arg;
- arg++;
- break;
- }
- }
+ va_start(ap, fmt);
+ retval = Q_vsnprintf(str, length, fmt, ap);
+ va_end(ap);
-done:
- *buf_p = 0;
- return buf_p - buffer;
+ return retval;
}
-
/* this is really crappy */
-// FIXME: count is still inaccurate in some cases.
int sscanf( const char *buffer, const char *fmt, ... )
{
int cmd;
- int **arg;
+ va_list ap;
int count;
+ size_t len;
- arg = (int **)&fmt + 1;
+ va_start( ap, fmt );
count = 0;
while( *fmt )
@@ -2013,33 +2724,70 @@ int sscanf( const char *buffer, const char *fmt, ... )
continue;
}
- if( !buffer[ 0 ] ) break;
+ fmt++;
+ cmd = *fmt;
- cmd = fmt[ 1 ];
- fmt += 2;
+ if( isdigit( cmd ) )
+ {
+ len = (size_t)_atoi( &fmt );
+ cmd = *( fmt - 1 );
+ }
+ else
+ {
+ len = MAX_STRING_CHARS - 1;
+ fmt++;
+ }
switch( cmd )
{
case 'i':
case 'd':
case 'u':
- **arg = _atoi( &buffer );
- ++count;
+ *( va_arg( ap, int * ) ) = _atoi( &buffer );
break;
case 'f':
- *(float *)*arg = _atof( &buffer );
- ++count;
+ *( va_arg( ap, float * ) ) = _atof( &buffer );
break;
case 'x':
- **arg = _hextoi( &buffer );
- ++count;
+ *( va_arg( ap, unsigned int * ) ) = _hextoi( &buffer );
+ break;
+ case 's':
+ {
+ char *s = va_arg( ap, char * );
+ while( isspace( *buffer ) )
+ buffer++;
+ while( *buffer && !isspace( *buffer) && len-- > 0 )
+ *s++ = *buffer++;
+ *s++ = '\0';
break;
+ }
}
-
- arg++;
}
+ va_end( ap );
return count;
}
+void *bsearch( const void *key, const void *base, size_t nmemb, size_t size,
+ cmp_t *compar )
+{
+ size_t low = 0, high = nmemb, mid;
+ int comp;
+ void *ptr;
+
+ while( low < high )
+ {
+ mid = low + (high - low) / 2;
+ ptr = (void *)((char *)base + ( mid * size ));
+ comp = compar (key, ptr);
+ if( comp < 0 )
+ high = mid;
+ else if( comp > 0 )
+ low = mid + 1;
+ else
+ return ptr;
+ }
+ return NULL;
+}
+
#endif
diff --git a/src/game/bg_lib.h b/src/game/bg_lib.h
index 962a625..a853654 100644
--- a/src/game/bg_lib.h
+++ b/src/game/bg_lib.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -25,14 +26,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// compiled for the virtual machine
// This file is NOT included on native builds
-#ifndef BG_LIB_H
+#if !defined( BG_LIB_H ) && defined( Q3_VM )
#define BG_LIB_H
#ifndef NULL
#define NULL ((void *)0)
#endif
-typedef int size_t;
+typedef unsigned int size_t;
typedef char * va_list;
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
@@ -40,21 +41,28 @@ typedef char * va_list;
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
-#define CHAR_BIT 8 /* number of bits in a char */
-#define SCHAR_MIN (-128) /* minimum signed char value */
-#define SCHAR_MAX 127 /* maximum signed char value */
-#define UCHAR_MAX 0xff /* maximum unsigned char value */
+#define CHAR_BIT 8 /* number of bits in a char */
+#define SCHAR_MAX 0x7f /* maximum signed char value */
+#define SCHAR_MIN (-SCHAR_MAX - 1)/* minimum signed char value */
+#define UCHAR_MAX 0xff /* maximum unsigned char value */
-#define SHRT_MIN (-32768) /* minimum (signed) short value */
-#define SHRT_MAX 32767 /* maximum (signed) short value */
+#define SHRT_MAX 0x7fff /* maximum (signed) short value */
+#define SHRT_MIN (-SHRT_MAX - 1) /* minimum (signed) short value */
#define USHRT_MAX 0xffff /* maximum unsigned short value */
-#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */
-#define INT_MAX 2147483647 /* maximum (signed) int value */
+#define INT_MAX 0x7fffffff /* maximum (signed) int value */
+#define INT_MIN (-INT_MAX - 1) /* minimum (signed) int value */
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
-#define LONG_MIN (-2147483647L - 1) /* minimum (signed) long value */
-#define LONG_MAX 2147483647L /* maximum (signed) long value */
+#define LONG_MAX 0x7fffffffL /* maximum (signed) long value */
+#define LONG_MIN (-LONG_MAX - 1) /* minimum (signed) long value */
#define ULONG_MAX 0xffffffffUL /* maximum unsigned long value */
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed long int32_t;
+typedef unsigned long uint32_t;
+
#define isalnum(c) (isalpha(c) || isdigit(c))
#define isalpha(c) (isupper(c) || islower(c))
#define isascii(c) ((c) > 0 && (c) <= 0x7f)
@@ -72,10 +80,17 @@ typedef char * va_list;
#define isxupper(c) (isdigit(c) || (c >= 'A' && c <= 'F'))
// Misc functions
+#define assert( expr )\
+ if( !( expr ) )\
+ Com_Error( ERR_DROP, "%s:%d: Assertion `%s' failed",\
+ __FILE__, __LINE__, #expr )
typedef int cmp_t( const void *, const void * );
void qsort( void *a, size_t n, size_t es, cmp_t *cmp );
+#define RAND_MAX 0x7fff
void srand( unsigned seed );
int rand( void );
+void *bsearch( const void *key, const void *base, size_t nmemb,
+ size_t size, cmp_t *compar );
// String functions
size_t strlen( const char *string );
@@ -91,11 +106,14 @@ int toupper( int c );
double atof( const char *string );
double _atof( const char **stringPtr );
+double strtod( const char *nptr, char **endptr );
int atoi( const char *string );
int _atoi( const char **stringPtr );
+long strtol( const char *nptr, char **endptr, int base );
+int Q_vsnprintf( char *buffer, size_t length, const char *fmt, va_list argptr );
+int Q_snprintf( char *buffer, size_t length, const char *fmt, ... ) __attribute__ ((format (printf, 3, 4)));
-int vsprintf( char *buffer, const char *fmt, va_list argptr );
int sscanf( const char *buffer, const char *fmt, ... );
// Memory functions
diff --git a/src/game/bg_local.h b/src/game/bg_local.h
index 354214c..1a67c49 100644
--- a/src/game/bg_local.h
+++ b/src/game/bg_local.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -31,8 +32,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define TIMER_GESTURE (34*66+50)
#define TIMER_ATTACK 500 //nonsegmented models
-#define OVERCLIP 1.001f
-
#define FALLING_THRESHOLD -900.0f //what vertical speed to start falling sound at
@@ -65,20 +64,19 @@ extern pml_t pml;
extern float pm_stopspeed;
extern float pm_duckScale;
extern float pm_swimScale;
-extern float pm_wadeScale;
extern float pm_accelerate;
-extern float pm_airaccelerate;
extern float pm_wateraccelerate;
extern float pm_flyaccelerate;
extern float pm_friction;
extern float pm_waterfriction;
extern float pm_flightfriction;
+extern float pm_spectatorfriction;
extern int c_pmove;
-void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce );
+void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out );
void PM_AddTouchEnt( int entityNum );
void PM_AddEvent( int newEvent );
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index fd50509..e30a754 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,45 +17,44 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// bg_misc.c -- both games misc functions, all completely stateless
-#include "../qcommon/q_shared.h"
+#include "qcommon/q_shared.h"
#include "bg_public.h"
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, enum FS_Mode mode );
void trap_FS_Read( void *buffer, int len, fileHandle_t f );
void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
void trap_FS_FCloseFile( fileHandle_t f );
-void trap_FS_Seek( fileHandle_t f, long offset, fsOrigin_t origin ); // fsOrigin_t
+void trap_FS_Seek( fileHandle_t f, long offset, enum FS_Origin origin ); // fsOrigin_t
+int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
-buildableAttributes_t bg_buildableList[ ] =
+static const buildableAttributes_t bg_buildableList[ ] =
{
{
- BA_A_SPAWN, //int buildNum;
- "eggpod", //char *buildName;
+ BA_A_SPAWN, //int number;
+ "eggpod", //char *name;
"Egg", //char *humanName;
+ "The most basic alien structure. It allows aliens to spawn "
+ "and protect the Overmind. Without any of these, the Overmind "
+ "is left nearly defenseless and defeat is imminent.",
"team_alien_spawn", //char *entityName;
- { "models/buildables/eggpod/eggpod.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -15, -15, -15 }, //vec3_t mins;
- { 15, 15, 15 }, //vec3_t maxs;
- 0.0f, //float zOffset;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
ASPAWN_BP, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
ASPAWN_HEALTH, //int health;
ASPAWN_REGEN, //int regenRate;
ASPAWN_SPLASHDAMAGE, //int splashDamage;
ASPAWN_SPLASHRADIUS, //int splashRadius;
MOD_ASPAWN, //int meansOfDeath;
- BIT_ALIENS, //int team;
- ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
+ TEAM_ALIENS, //int team;
+ ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
ASPAWN_BT, //int buildTime;
@@ -68,70 +68,66 @@ buildableAttributes_t bg_buildableList[ ] =
ASPAWN_CREEPSIZE, //int creepSize;
qfalse, //qboolean dccTest;
qfalse, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qfalse, //qboolean replacable;
+ qfalse, //qboolean uniqueTest;
+ ASPAWN_VALUE, //int value;
},
{
- BA_A_BARRICADE, //int buildNum;
- "barricade", //char *buildName;
- "Barricade", //char *humanName;
- "team_alien_barricade",//char *entityName;
- { "models/buildables/barricade/barricade.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -35, -35, -15 }, //vec3_t mins;
- { 35, 35, 60 }, //vec3_t maxs;
- 0.0f, //float zOffset;
+ BA_A_OVERMIND, //int number;
+ "overmind", //char *name;
+ "Overmind", //char *humanName;
+ "A collective consciousness that controls all the alien structures "
+ "in its vicinity. It must be protected at all costs, since its "
+ "death will render alien structures defenseless.",
+ "team_alien_overmind", //char *entityName;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
- BARRICADE_BP, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- BARRICADE_HEALTH, //int health;
- BARRICADE_REGEN, //int regenRate;
- BARRICADE_SPLASHDAMAGE,//int splashDamage;
- BARRICADE_SPLASHRADIUS,//int splashRadius;
+ OVERMIND_BP, //int buildPoints;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
+ OVERMIND_HEALTH, //int health;
+ OVERMIND_REGEN, //int regenRate;
+ OVERMIND_SPLASHDAMAGE, //int splashDamage;
+ OVERMIND_SPLASHRADIUS, //int splashRadius;
MOD_ASPAWN, //int meansOfDeath;
- BIT_ALIENS, //int team;
- ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
+ TEAM_ALIENS, //int team;
+ ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
- 100, //int nextthink;
- BARRICADE_BT, //int buildTime;
+ OVERMIND_ATTACK_REPEAT, //int nextthink;
+ OVERMIND_BT, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
WP_NONE, //weapon_t turretProjType;
- 0.707f, //float minNormal;
+ 0.95f, //float minNormal;
qfalse, //qboolean invertNormal;
- qtrue, //qboolean creepTest;
- BARRICADE_CREEPSIZE, //int creepSize;
+ qfalse, //qboolean creepTest;
+ OVERMIND_CREEPSIZE, //int creepSize;
qfalse, //qboolean dccTest;
qfalse, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qfalse, //qboolean replaceable;
+ qtrue, //qboolean uniqueTest;
+ OVERMIND_VALUE, //int value;
},
{
- BA_A_BOOSTER, //int buildNum;
- "booster", //char *buildName;
- "Booster", //char *humanName;
- "team_alien_booster", //char *entityName;
- { "models/buildables/booster/booster.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -26, -26, -9 }, //vec3_t mins;
- { 26, 26, 9 }, //vec3_t maxs;
- 0.0f, //float zOffset;
+ BA_A_BARRICADE, //int number;
+ "barricade", //char *name;
+ "Barricade", //char *humanName;
+ "Used to obstruct corridors and doorways, hindering humans from "
+ "threatening the spawns and Overmind. Barricades will shrink "
+ "to allow aliens to pass over them, however.",
+ "team_alien_barricade", //char *entityName;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
- BOOSTER_BP, //int buildPoints;
- ( 1 << S2 )|( 1 << S3 ), //int stages
- BOOSTER_HEALTH, //int health;
- BOOSTER_REGEN, //int regenRate;
- BOOSTER_SPLASHDAMAGE, //int splashDamage;
- BOOSTER_SPLASHRADIUS, //int splashRadius;
+ BARRICADE_BP, //int buildPoints;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
+ BARRICADE_HEALTH, //int health;
+ BARRICADE_REGEN, //int regenRate;
+ BARRICADE_SPLASHDAMAGE, //int splashDamage;
+ BARRICADE_SPLASHRADIUS, //int splashRadius;
MOD_ASPAWN, //int meansOfDeath;
- BIT_ALIENS, //int team;
- ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
+ TEAM_ALIENS, //int team;
+ ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
- BOOSTER_BT, //int buildTime;
+ BARRICADE_BT, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -139,33 +135,31 @@ buildableAttributes_t bg_buildableList[ ] =
0.707f, //float minNormal;
qfalse, //qboolean invertNormal;
qtrue, //qboolean creepTest;
- BOOSTER_CREEPSIZE, //int creepSize;
+ BARRICADE_CREEPSIZE, //int creepSize;
qfalse, //qboolean dccTest;
- qtrue, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qtrue, //qboolean replacable;
+ qfalse, //qboolean transparentTest;
+ qfalse, //qboolean uniqueTest;
+ BARRICADE_VALUE, //int value;
},
{
- BA_A_ACIDTUBE, //int buildNum;
- "acid_tube", //char *buildName;
+ BA_A_ACIDTUBE, //int number;
+ "acid_tube", //char *name;
"Acid Tube", //char *humanName;
- "team_alien_acid_tube",//char *entityName;
- { "models/buildables/acid_tube/acid_tube.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -25, -25, -25 }, //vec3_t mins;
- { 25, 25, 25 }, //vec3_t maxs;
- -15.0f, //float zOffset;
+ "Ejects lethal poisonous acid at an approaching human. These "
+ "are highly effective when used in conjunction with a trapper "
+ "to hold the victim in place.",
+ "team_alien_acid_tube", //char *entityName;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
ACIDTUBE_BP, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
ACIDTUBE_HEALTH, //int health;
ACIDTUBE_REGEN, //int regenRate;
ACIDTUBE_SPLASHDAMAGE, //int splashDamage;
ACIDTUBE_SPLASHRADIUS, //int splashRadius;
- MOD_ATUBE, //int meansOfDeath;
- BIT_ALIENS, //int team;
- ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
+ MOD_ASPAWN, //int meansOfDeath;
+ TEAM_ALIENS, //int team;
+ ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
200, //int nextthink;
ACIDTUBE_BT, //int buildTime;
@@ -179,67 +173,28 @@ buildableAttributes_t bg_buildableList[ ] =
ACIDTUBE_CREEPSIZE, //int creepSize;
qfalse, //qboolean dccTest;
qfalse, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qfalse, //qboolean replacable;
+ qfalse, //qboolean uniqueTest;
+ ACIDTUBE_VALUE, //int value;
},
{
- BA_A_HIVE, //int buildNum;
- "hive", //char *buildName;
- "Hive", //char *humanName;
- "team_alien_hive", //char *entityName;
- { "models/buildables/acid_tube/acid_tube.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -35, -35, -25 }, //vec3_t mins;
- { 35, 35, 25 }, //vec3_t maxs;
- -15.0f, //float zOffset;
- TR_GRAVITY, //trType_t traj;
- 0.0, //float bounce;
- HIVE_BP, //int buildPoints;
- ( 1 << S3 ), //int stages
- HIVE_HEALTH, //int health;
- HIVE_REGEN, //int regenRate;
- HIVE_SPLASHDAMAGE, //int splashDamage;
- HIVE_SPLASHRADIUS, //int splashRadius;
- MOD_ASPAWN, //int meansOfDeath;
- BIT_ALIENS, //int team;
- ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
- BANIM_IDLE1, //int idleAnim;
- 500, //int nextthink;
- HIVE_BT, //int buildTime;
- qfalse, //qboolean usable;
- 0, //int turretRange;
- 0, //int turretFireSpeed;
- WP_HIVE, //weapon_t turretProjType;
- 0.0f, //float minNormal;
- qtrue, //qboolean invertNormal;
- qtrue, //qboolean creepTest;
- HIVE_CREEPSIZE, //int creepSize;
- qfalse, //qboolean dccTest;
- qfalse, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qfalse, //qboolean replacable;
- },
- {
- BA_A_TRAPPER, //int buildNum;
- "trapper", //char *buildName;
+ BA_A_TRAPPER, //int number;
+ "trapper", //char *name;
"Trapper", //char *humanName;
+ "Fires a blob of adhesive spit at any non-alien in its line of "
+ "sight. This hinders their movement, making them an easy target "
+ "for other defensive structures or aliens.",
"team_alien_trapper", //char *entityName;
- { "models/buildables/trapper/trapper.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -15, -15, -15 }, //vec3_t mins;
- { 15, 15, 15 }, //vec3_t maxs;
- 0.0f, //float zOffset;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
TRAPPER_BP, //int buildPoints;
- ( 1 << S2 )|( 1 << S3 ), //int stages //NEEDS ADV BUILDER SO S2 AND UP
+ ( 1 << S2 )|( 1 << S3 ), //int stages; //NEEDS ADV BUILDER SO S2 AND UP
TRAPPER_HEALTH, //int health;
TRAPPER_REGEN, //int regenRate;
TRAPPER_SPLASHDAMAGE, //int splashDamage;
TRAPPER_SPLASHRADIUS, //int splashRadius;
MOD_ASPAWN, //int meansOfDeath;
- BIT_ALIENS, //int team;
- ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
+ TEAM_ALIENS, //int team;
+ ( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
TRAPPER_BT, //int buildTime;
@@ -253,104 +208,98 @@ buildableAttributes_t bg_buildableList[ ] =
TRAPPER_CREEPSIZE, //int creepSize;
qfalse, //qboolean dccTest;
qtrue, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qfalse, //qboolean replacable;
+ qfalse, //qboolean uniqueTest;
+ TRAPPER_VALUE, //int value;
},
{
- BA_A_OVERMIND, //int buildNum;
- "overmind", //char *buildName;
- "Overmind", //char *humanName;
- "team_alien_overmind", //char *entityName;
- { "models/buildables/overmind/overmind.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -45, -45, -15 }, //vec3_t mins;
- { 45, 45, 95 }, //vec3_t maxs;
- 0.0f, //float zOffset;
+ BA_A_BOOSTER, //int number;
+ "booster", //char *name;
+ "Booster", //char *humanName;
+ "Laces the attacks of any alien that touches it with a poison "
+ "that will gradually deal damage to any humans exposed to it. "
+ "The booster also increases the rate of health regeneration for "
+ "any nearby aliens.",
+ "team_alien_booster", //char *entityName;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
- OVERMIND_BP, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- OVERMIND_HEALTH, //int health;
- OVERMIND_REGEN, //int regenRate;
- OVERMIND_SPLASHDAMAGE, //int splashDamage;
- OVERMIND_SPLASHRADIUS, //int splashRadius;
+ BOOSTER_BP, //int buildPoints;
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
+ BOOSTER_HEALTH, //int health;
+ BOOSTER_REGEN, //int regenRate;
+ BOOSTER_SPLASHDAMAGE, //int splashDamage;
+ BOOSTER_SPLASHRADIUS, //int splashRadius;
MOD_ASPAWN, //int meansOfDeath;
- BIT_ALIENS, //int team;
- ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
+ TEAM_ALIENS, //int team;
+ ( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
- OVERMIND_ATTACK_REPEAT,//int nextthink;
- OVERMIND_BT, //int buildTime;
+ 100, //int nextthink;
+ BOOSTER_BT, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
WP_NONE, //weapon_t turretProjType;
- 0.95f, //float minNormal;
+ 0.707f, //float minNormal;
qfalse, //qboolean invertNormal;
- qfalse, //qboolean creepTest;
- OVERMIND_CREEPSIZE, //int creepSize;
+ qtrue, //qboolean creepTest;
+ BOOSTER_CREEPSIZE, //int creepSize;
qfalse, //qboolean dccTest;
- qfalse, //qboolean transparentTest;
- qtrue, //qboolean reactorTest;
- qtrue, //qboolean replacable;
+ qtrue, //qboolean transparentTest;
+ qfalse, //qboolean uniqueTest;
+ BOOSTER_VALUE, //int value;
},
{
- BA_A_HOVEL, //int buildNum;
- "hovel", //char *buildName;
- "Hovel", //char *humanName;
- "team_alien_hovel", //char *entityName;
- { "models/buildables/hovel/hovel.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -50, -50, -20 }, //vec3_t mins;
- { 50, 50, 20 }, //vec3_t maxs;
- 0.0f, //float zOffset;
+ BA_A_HIVE, //int number;
+ "hive", //char *name;
+ "Hive", //char *humanName;
+ "Houses millions of tiny insectoid aliens. When a human "
+ "approaches this structure, the insectoids attack.",
+ "team_alien_hive", //char *entityName;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
- HOVEL_BP, //int buildPoints;
- ( 1 << S3 ), //int stages
- HOVEL_HEALTH, //int health;
- HOVEL_REGEN, //int regenRate;
- HOVEL_SPLASHDAMAGE, //int splashDamage;
- HOVEL_SPLASHRADIUS, //int splashRadius;
+ HIVE_BP, //int buildPoints;
+ ( 1 << S3 ), //int stages;
+ HIVE_HEALTH, //int health;
+ HIVE_REGEN, //int regenRate;
+ HIVE_SPLASHDAMAGE, //int splashDamage;
+ HIVE_SPLASHRADIUS, //int splashRadius;
MOD_ASPAWN, //int meansOfDeath;
- BIT_ALIENS, //int team;
- ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
+ TEAM_ALIENS, //int team;
+ ( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
- 150, //int nextthink;
- HOVEL_BT, //int buildTime;
- qtrue, //qboolean usable;
+ 500, //int nextthink;
+ HIVE_BT, //int buildTime;
+ qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
- WP_NONE, //weapon_t turretProjType;
- 0.95f, //float minNormal;
- qfalse, //qboolean invertNormal;
+ WP_HIVE, //weapon_t turretProjType;
+ 0.0f, //float minNormal;
+ qtrue, //qboolean invertNormal;
qtrue, //qboolean creepTest;
- HOVEL_CREEPSIZE, //int creepSize;
+ HIVE_CREEPSIZE, //int creepSize;
qfalse, //qboolean dccTest;
qfalse, //qboolean transparentTest;
- qtrue, //qboolean reactorTest;
- qfalse, //qboolean replacable;
+ qfalse, //qboolean uniqueTest;
+ HIVE_VALUE, //int value;
},
{
- BA_H_SPAWN, //int buildNum;
- "telenode", //char *buildName;
+ BA_H_SPAWN, //int number;
+ "telenode", //char *name;
"Telenode", //char *humanName;
+ "The most basic human structure. It provides a means for humans "
+ "to enter the battle arena. Without any of these the humans "
+ "cannot spawn and defeat is imminent.",
"team_human_spawn", //char *entityName;
- { "models/buildables/telenode/telenode.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -40, -40, -4 }, //vec3_t mins;
- { 40, 40, 4 }, //vec3_t maxs;
- 0.0f, //float zOffset;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
HSPAWN_BP, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
HSPAWN_HEALTH, //int health;
0, //int regenRate;
HSPAWN_SPLASHDAMAGE, //int splashDamage;
HSPAWN_SPLASHRADIUS, //int splashRadius;
MOD_HSPAWN, //int meansOfDeath;
- BIT_HUMANS, //int team;
- ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
+ TEAM_HUMANS, //int team;
+ ( 1 << WP_HBUILD ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
HSPAWN_BT, //int buildTime;
@@ -364,69 +313,28 @@ buildableAttributes_t bg_buildableList[ ] =
0, //int creepSize;
qfalse, //qboolean dccTest;
qtrue, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qfalse, //qboolean replacable;
- },
- {
- BA_H_MEDISTAT, //int buildNum;
- "medistat", //char *buildName;
- "Medistation", //char *humanName;
- "team_human_medistat", //char *entityName;
- { "models/buildables/medistat/medistat.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -35, -35, -7 }, //vec3_t mins;
- { 35, 35, 7 }, //vec3_t maxs;
- 0.0f, //float zOffset;
- TR_GRAVITY, //trType_t traj;
- 0.0, //float bounce;
- MEDISTAT_BP, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- MEDISTAT_HEALTH, //int health;
- 0, //int regenRate;
- MEDISTAT_SPLASHDAMAGE, //int splashDamage;
- MEDISTAT_SPLASHRADIUS, //int splashRadius;
- MOD_HSPAWN, //int meansOfDeath;
- BIT_HUMANS, //int team;
- ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
- BANIM_IDLE1, //int idleAnim;
- 100, //int nextthink;
- MEDISTAT_BT, //int buildTime;
- qfalse, //qboolean usable;
- 0, //int turretRange;
- 0, //int turretFireSpeed;
- WP_NONE, //weapon_t turretProjType;
- 0.95f, //float minNormal;
- qfalse, //qboolean invertNormal;
- qfalse, //qboolean creepTest;
- 0, //int creepSize;
- qfalse, //qboolean dccTest;
- qtrue, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qtrue, //qboolean replacable;
+ qfalse, //qboolean uniqueTest;
+ HSPAWN_VALUE, //int value;
},
{
- BA_H_MGTURRET, //int buildNum;
- "mgturret", //char *buildName;
+ BA_H_MGTURRET, //int number;
+ "mgturret", //char *name;
"Machinegun Turret", //char *humanName;
+ "Automated base defense that is effective against large targets "
+ "but slow to begin firing. Should always be "
+ "backed up by physical support.",
"team_human_mgturret", //char *entityName;
- { "models/buildables/mgturret/turret_base.md3",
- "models/buildables/mgturret/turret_barrel.md3",
- "models/buildables/mgturret/turret_top.md3", 0 },
- 1.0f, //float modelScale;
- { -25, -25, -20 }, //vec3_t mins;
- { 25, 25, 20 }, //vec3_t maxs;
- 0.0f, //float zOffset;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
MGTURRET_BP, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
MGTURRET_HEALTH, //int health;
0, //int regenRate;
MGTURRET_SPLASHDAMAGE, //int splashDamage;
MGTURRET_SPLASHRADIUS, //int splashRadius;
MOD_HSPAWN, //int meansOfDeath;
- BIT_HUMANS, //int team;
- ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
+ TEAM_HUMANS, //int team;
+ ( 1 << WP_HBUILD ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
50, //int nextthink;
MGTURRET_BT, //int buildTime;
@@ -440,30 +348,28 @@ buildableAttributes_t bg_buildableList[ ] =
0, //int creepSize;
qfalse, //qboolean dccTest;
qtrue, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qfalse, //qboolean replacable;
+ qfalse, //qboolean uniqueTest;
+ MGTURRET_VALUE, //int value;
},
{
- BA_H_TESLAGEN, //int buildNum;
- "tesla", //char *buildName;
+ BA_H_TESLAGEN, //int number;
+ "tesla", //char *name;
"Tesla Generator", //char *humanName;
+ "A structure equipped with a strong electrical attack that fires "
+ "instantly and always hits its target. It is effective against smaller "
+ "aliens and for consolidating basic defense.",
"team_human_tesla", //char *entityName;
- { "models/buildables/tesla/tesla.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -22, -22, -40 }, //vec3_t mins;
- { 22, 22, 40 }, //vec3_t maxs;
- 0.0f, //float zOffset;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
TESLAGEN_BP, //int buildPoints;
- ( 1 << S3 ), //int stages
+ ( 1 << S3 ), //int stages;
TESLAGEN_HEALTH, //int health;
0, //int regenRate;
TESLAGEN_SPLASHDAMAGE, //int splashDamage;
TESLAGEN_SPLASHRADIUS, //int splashRadius;
MOD_HSPAWN, //int meansOfDeath;
- BIT_HUMANS, //int team;
- ( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
+ TEAM_HUMANS, //int team;
+ ( 1 << WP_HBUILD ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
150, //int nextthink;
TESLAGEN_BT, //int buildTime;
@@ -475,32 +381,65 @@ buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean invertNormal;
qfalse, //qboolean creepTest;
0, //int creepSize;
- qtrue, //qboolean dccTest;
+ qfalse, //qboolean dccTest;
qtrue, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qfalse, //qboolean replacable;
+ qfalse, //qboolean uniqueTest;
+ TESLAGEN_VALUE, //int value;
},
{
- BA_H_DCC, //int buildNum;
- "dcc", //char *buildName;
+ BA_H_ARMOURY, //int number;
+ "arm", //char *name;
+ "Armoury", //char *humanName;
+ "An essential part of the human base, providing a means "
+ "to upgrade the basic human equipment. A range of upgrades "
+ "and weapons are available for sale from the armoury.",
+ "team_human_armoury", //char *entityName;
+ TR_GRAVITY, //trType_t traj;
+ 0.0, //float bounce;
+ ARMOURY_BP, //int buildPoints;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
+ ARMOURY_HEALTH, //int health;
+ 0, //int regenRate;
+ ARMOURY_SPLASHDAMAGE, //int splashDamage;
+ ARMOURY_SPLASHRADIUS, //int splashRadius;
+ MOD_HSPAWN, //int meansOfDeath;
+ TEAM_HUMANS, //int team;
+ ( 1 << WP_HBUILD ), //weapon_t buildWeapon;
+ BANIM_IDLE1, //int idleAnim;
+ 100, //int nextthink;
+ ARMOURY_BT, //int buildTime;
+ qtrue, //qboolean usable;
+ 0, //int turretRange;
+ 0, //int turretFireSpeed;
+ WP_NONE, //weapon_t turretProjType;
+ 0.95f, //float minNormal;
+ qfalse, //qboolean invertNormal;
+ qfalse, //qboolean creepTest;
+ 0, //int creepSize;
+ qfalse, //qboolean dccTest;
+ qfalse, //qboolean transparentTest;
+ qfalse, //qboolean uniqueTest;
+ ARMOURY_VALUE, //int value;
+ },
+ {
+ BA_H_DCC, //int number;
+ "dcc", //char *name;
"Defence Computer", //char *humanName;
+ "A structure that enables self-repair functionality in "
+ "human structures. Each Defence Computer built increases "
+ "repair rate slightly.",
"team_human_dcc", //char *entityName;
- { "models/buildables/dcc/dcc.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -35, -35, -13 }, //vec3_t mins;
- { 35, 35, 47 }, //vec3_t maxs;
- 0.0f, //float zOffset;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
DC_BP, //int buildPoints;
- ( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
DC_HEALTH, //int health;
0, //int regenRate;
DC_SPLASHDAMAGE, //int splashDamage;
DC_SPLASHRADIUS, //int splashRadius;
MOD_HSPAWN, //int meansOfDeath;
- BIT_HUMANS, //int team;
- ( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
+ TEAM_HUMANS, //int team;
+ ( 1 << WP_HBUILD ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
DC_BT, //int buildTime;
@@ -514,34 +453,33 @@ buildableAttributes_t bg_buildableList[ ] =
0, //int creepSize;
qfalse, //qboolean dccTest;
qfalse, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qtrue, //qboolean replacable;
+ qfalse, //qboolean uniqueTest;
+ DC_VALUE, //int value;
},
{
- BA_H_ARMOURY, //int buildNum;
- "arm", //char *buildName;
- "Armoury", //char *humanName;
- "team_human_armoury", //char *entityName;
- { "models/buildables/arm/arm.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -40, -40, -13 }, //vec3_t mins;
- { 40, 40, 50 }, //vec3_t maxs;
- 0.0f, //float zOffset;
+ BA_H_MEDISTAT, //int number;
+ "medistat", //char *name;
+ "Medistation", //char *humanName;
+ "A structure that automatically restores "
+ "the health and stamina of any human that stands on it. "
+ "It may only be used by one person at a time. This structure "
+ "also issues medkits.",
+ "team_human_medistat", //char *entityName;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
- ARMOURY_BP, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- ARMOURY_HEALTH, //int health;
+ MEDISTAT_BP, //int buildPoints;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
+ MEDISTAT_HEALTH, //int health;
0, //int regenRate;
- ARMOURY_SPLASHDAMAGE, //int splashDamage;
- ARMOURY_SPLASHRADIUS, //int splashRadius;
+ MEDISTAT_SPLASHDAMAGE, //int splashDamage;
+ MEDISTAT_SPLASHRADIUS, //int splashRadius;
MOD_HSPAWN, //int meansOfDeath;
- BIT_HUMANS, //int team;
- ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
+ TEAM_HUMANS, //int team;
+ ( 1 << WP_HBUILD ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
- ARMOURY_BT, //int buildTime;
- qtrue, //qboolean usable;
+ MEDISTAT_BT, //int buildTime;
+ qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
WP_NONE, //weapon_t turretProjType;
@@ -550,33 +488,31 @@ buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean creepTest;
0, //int creepSize;
qfalse, //qboolean dccTest;
- qfalse, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qtrue, //qboolean replacable;
+ qtrue, //qboolean transparentTest;
+ qfalse, //qboolean uniqueTest;
+ MEDISTAT_VALUE, //int value;
},
{
- BA_H_REACTOR, //int buildNum;
- "reactor", //char *buildName;
+ BA_H_REACTOR, //int number;
+ "reactor", //char *name;
"Reactor", //char *humanName;
+ "All structures except the telenode rely on a reactor to operate. "
+ "The reactor provides power for all the human structures either "
+ "directly or via repeaters. Only one reactor can be built at a time.",
"team_human_reactor", //char *entityName;
- { "models/buildables/reactor/reactor.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -50, -50, -15 }, //vec3_t mins;
- { 50, 50, 95 }, //vec3_t maxs;
- 0.0f, //float zOffset;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
REACTOR_BP, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
REACTOR_HEALTH, //int health;
0, //int regenRate;
REACTOR_SPLASHDAMAGE, //int splashDamage;
REACTOR_SPLASHRADIUS, //int splashRadius;
MOD_HSPAWN, //int meansOfDeath;
- BIT_HUMANS, //int team;
- ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
+ TEAM_HUMANS, //int team;
+ ( 1 << WP_HBUILD ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
- REACTOR_ATTACK_REPEAT, //int nextthink;
+ REACTOR_ATTACK_DCC_REPEAT, //int nextthink;
REACTOR_BT, //int buildTime;
qtrue, //qboolean usable;
0, //int turretRange;
@@ -588,30 +524,28 @@ buildableAttributes_t bg_buildableList[ ] =
0, //int creepSize;
qfalse, //qboolean dccTest;
qfalse, //qboolean transparentTest;
- qtrue, //qboolean reactorTest;
- qtrue, //qboolean replacable;
+ qtrue, //qboolean uniqueTest;
+ REACTOR_VALUE, //int value;
},
{
- BA_H_REPEATER, //int buildNum;
- "repeater", //char *buildName;
+ BA_H_REPEATER, //int number;
+ "repeater", //char *name;
"Repeater", //char *humanName;
+ "A power distributor that transmits power from the reactor "
+ "to remote locations, so that bases may be built far "
+ "from the reactor.",
"team_human_repeater", //char *entityName;
- { "models/buildables/repeater/repeater.md3", 0, 0, 0 },
- 1.0f, //float modelScale;
- { -15, -15, -15 }, //vec3_t mins;
- { 15, 15, 25 }, //vec3_t maxs;
- 0.0f, //float zOffset;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
REPEATER_BP, //int buildPoints;
- ( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
REPEATER_HEALTH, //int health;
0, //int regenRate;
REPEATER_SPLASHDAMAGE, //int splashDamage;
REPEATER_SPLASHRADIUS, //int splashRadius;
MOD_HSPAWN, //int meansOfDeath;
- BIT_HUMANS, //int team;
- ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
+ TEAM_HUMANS, //int team;
+ ( 1 << WP_HBUILD ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
REPEATER_BT, //int buildTime;
@@ -625,757 +559,115 @@ buildableAttributes_t bg_buildableList[ ] =
0, //int creepSize;
qfalse, //qboolean dccTest;
qfalse, //qboolean transparentTest;
- qfalse, //qboolean reactorTest;
- qtrue, //qboolean replacable;
+ qfalse, //qboolean uniqueTest;
+ REPEATER_VALUE, //int value;
}
};
-int bg_numBuildables = sizeof( bg_buildableList ) / sizeof( bg_buildableList[ 0 ] );
+size_t bg_numBuildables = ARRAY_LEN( bg_buildableList );
-//separate from bg_buildableList to work around char struct init bug
-buildableAttributeOverrides_t bg_buildableOverrideList[ BA_NUM_BUILDABLES ];
+static const buildableAttributes_t nullBuildable = { 0 };
/*
==============
-BG_FindBuildNumForName
+BG_BuildableByName
==============
*/
-int BG_FindBuildNumForName( char *name )
+const buildableAttributes_t *BG_BuildableByName( const char *name )
{
int i;
for( i = 0; i < bg_numBuildables; i++ )
{
- if( !Q_stricmp( bg_buildableList[ i ].buildName, name ) )
- return bg_buildableList[ i ].buildNum;
+ if( !Q_stricmp( bg_buildableList[ i ].name, name ) )
+ return &bg_buildableList[ i ];
}
- //wimp out
- return BA_NONE;
+ return &nullBuildable;
}
/*
==============
-BG_FindBuildNumForEntityName
+BG_BuildableByEntityName
==============
*/
-int BG_FindBuildNumForEntityName( char *name )
+const buildableAttributes_t *BG_BuildableByEntityName( const char *name )
{
int i;
for( i = 0; i < bg_numBuildables; i++ )
{
if( !Q_stricmp( bg_buildableList[ i ].entityName, name ) )
- return bg_buildableList[ i ].buildNum;
+ return &bg_buildableList[ i ];
}
- //wimp out
- return BA_NONE;
+ return &nullBuildable;
}
/*
==============
-BG_FindNameForBuildNum
+BG_Buildable
==============
*/
-char *BG_FindNameForBuildable( int bclass )
+const buildableAttributes_t *BG_Buildable( buildable_t buildable )
{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- return bg_buildableList[ i ].buildName;
- }
-
- //wimp out
- return 0;
-}
-
-/*
-==============
-BG_FindHumanNameForBuildNum
-==============
-*/
-char *BG_FindHumanNameForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- return bg_buildableList[ i ].humanName;
- }
-
- //wimp out
- return 0;
+ return ( buildable > BA_NONE && buildable < BA_NUM_BUILDABLES ) ?
+ &bg_buildableList[ buildable - 1 ] : &nullBuildable;
}
/*
==============
-BG_FindEntityNameForBuildNum
+BG_BuildableAllowedInStage
==============
*/
-char *BG_FindEntityNameForBuildable( int bclass )
+qboolean BG_BuildableAllowedInStage( buildable_t buildable,
+ stage_t stage )
{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- return bg_buildableList[ i ].entityName;
- }
+ int stages = BG_Buildable( buildable )->stages;
- //wimp out
- return 0;
+ if( stages & ( 1 << stage ) )
+ return qtrue;
+ else
+ return qfalse;
}
-/*
-==============
-BG_FindModelsForBuildNum
-==============
-*/
-char *BG_FindModelsForBuildable( int bclass, int modelNum )
-{
- int i;
-
- if( bg_buildableOverrideList[ bclass ].models[ modelNum ][ 0 ] != 0 )
- return bg_buildableOverrideList[ bclass ].models[ modelNum ];
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- return bg_buildableList[ i ].models[ modelNum ];
- }
-
- //wimp out
- return 0;
-}
+static buildableConfig_t bg_buildableConfigList[ BA_NUM_BUILDABLES ];
/*
==============
-BG_FindModelScaleForBuildable
+BG_BuildableConfig
==============
*/
-float BG_FindModelScaleForBuildable( int bclass )
+buildableConfig_t *BG_BuildableConfig( buildable_t buildable )
{
- int i;
-
- if( bg_buildableOverrideList[ bclass ].modelScale != 0.0f )
- return bg_buildableOverrideList[ bclass ].modelScale;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- return bg_buildableList[ i ].modelScale;
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindModelScaleForBuildable( %d )\n", bclass );
- return 1.0f;
+ return &bg_buildableConfigList[ buildable ];
}
/*
==============
-BG_FindBBoxForBuildable
+BG_BuildableBoundingBox
==============
*/
-void BG_FindBBoxForBuildable( int bclass, vec3_t mins, vec3_t maxs )
+void BG_BuildableBoundingBox( buildable_t buildable,
+ vec3_t mins, vec3_t maxs )
{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- if( mins != NULL )
- {
- VectorCopy( bg_buildableList[ i ].mins, mins );
-
- if( VectorLength( bg_buildableOverrideList[ bclass ].mins ) )
- VectorCopy( bg_buildableOverrideList[ bclass ].mins, mins );
- }
-
- if( maxs != NULL )
- {
- VectorCopy( bg_buildableList[ i ].maxs, maxs );
-
- if( VectorLength( bg_buildableOverrideList[ bclass ].maxs ) )
- VectorCopy( bg_buildableOverrideList[ bclass ].maxs, maxs );
- }
-
- return;
- }
- }
+ buildableConfig_t *buildableConfig = BG_BuildableConfig( buildable );
if( mins != NULL )
- VectorCopy( bg_buildableList[ 0 ].mins, mins );
+ VectorCopy( buildableConfig->mins, mins );
if( maxs != NULL )
- VectorCopy( bg_buildableList[ 0 ].maxs, maxs );
-}
-
-/*
-==============
-BG_FindZOffsetForBuildable
-==============
-*/
-float BG_FindZOffsetForBuildable( int bclass )
-{
- int i;
-
- if( bg_buildableOverrideList[ bclass ].zOffset != 0.0f )
- return bg_buildableOverrideList[ bclass ].zOffset;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].zOffset;
- }
- }
-
- return 0.0f;
-}
-
-/*
-==============
-BG_FindTrajectoryForBuildable
-==============
-*/
-trType_t BG_FindTrajectoryForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].traj;
- }
- }
-
- return TR_GRAVITY;
-}
-
-/*
-==============
-BG_FindBounceForBuildable
-==============
-*/
-float BG_FindBounceForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].bounce;
- }
- }
-
- return 0.0;
-}
-
-/*
-==============
-BG_FindBuildPointsForBuildable
-==============
-*/
-int BG_FindBuildPointsForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].buildPoints;
- }
- }
-
- return 1000;
-}
-
-/*
-==============
-BG_FindStagesForBuildable
-==============
-*/
-qboolean BG_FindStagesForBuildable( int bclass, stage_t stage )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- if( bg_buildableList[ i ].stages & ( 1 << stage ) )
- return qtrue;
- else
- return qfalse;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindHealthForBuildable
-==============
-*/
-int BG_FindHealthForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].health;
- }
- }
-
- return 1000;
-}
-
-/*
-==============
-BG_FindRegenRateForBuildable
-==============
-*/
-int BG_FindRegenRateForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].regenRate;
- }
- }
-
- return 0;
-}
-
-/*
-==============
-BG_FindSplashDamageForBuildable
-==============
-*/
-int BG_FindSplashDamageForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].splashDamage;
- }
- }
-
- return 50;
-}
-
-/*
-==============
-BG_FindSplashRadiusForBuildable
-==============
-*/
-int BG_FindSplashRadiusForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].splashRadius;
- }
- }
-
- return 200;
-}
-
-/*
-==============
-BG_FindMODForBuildable
-==============
-*/
-int BG_FindMODForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].meansOfDeath;
- }
- }
-
- return MOD_UNKNOWN;
-}
-
-/*
-==============
-BG_FindTeamForBuildable
-==============
-*/
-int BG_FindTeamForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].team;
- }
- }
-
- return BIT_NONE;
-}
-
-/*
-==============
-BG_FindBuildWeaponForBuildable
-==============
-*/
-weapon_t BG_FindBuildWeaponForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].buildWeapon;
- }
- }
-
- return WP_NONE;
-}
-
-/*
-==============
-BG_FindAnimForBuildable
-==============
-*/
-int BG_FindAnimForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].idleAnim;
- }
- }
-
- return BANIM_IDLE1;
-}
-
-/*
-==============
-BG_FindNextThinkForBuildable
-==============
-*/
-int BG_FindNextThinkForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].nextthink;
- }
- }
-
- return 100;
-}
-
-/*
-==============
-BG_FindBuildTimeForBuildable
-==============
-*/
-int BG_FindBuildTimeForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].buildTime;
- }
- }
-
- return 10000;
-}
-
-/*
-==============
-BG_FindUsableForBuildable
-==============
-*/
-qboolean BG_FindUsableForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].usable;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindFireSpeedForBuildable
-==============
-*/
-int BG_FindFireSpeedForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].turretFireSpeed;
- }
- }
-
- return 1000;
-}
-
-/*
-==============
-BG_FindRangeForBuildable
-==============
-*/
-int BG_FindRangeForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].turretRange;
- }
- }
-
- return 1000;
-}
-
-/*
-==============
-BG_FindProjTypeForBuildable
-==============
-*/
-weapon_t BG_FindProjTypeForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].turretProjType;
- }
- }
-
- return WP_NONE;
-}
-
-/*
-==============
-BG_FindMinNormalForBuildable
-==============
-*/
-float BG_FindMinNormalForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].minNormal;
- }
- }
-
- return 0.707f;
-}
-
-/*
-==============
-BG_FindInvertNormalForBuildable
-==============
-*/
-qboolean BG_FindInvertNormalForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].invertNormal;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindCreepTestForBuildable
-==============
-*/
-int BG_FindCreepTestForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].creepTest;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindCreepSizeForBuildable
-==============
-*/
-int BG_FindCreepSizeForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].creepSize;
- }
- }
-
- return CREEP_BASESIZE;
-}
-
-/*
-==============
-BG_FindDCCTestForBuildable
-==============
-*/
-int BG_FindDCCTestForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].dccTest;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindUniqueTestForBuildable
-==============
-*/
-int BG_FindUniqueTestForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].reactorTest;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindReplaceableTestForBuildable
-==============
-*/
-qboolean BG_FindReplaceableTestForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].replaceable;
- }
- }
- return qfalse;
-}
-
-/*
-==============
-BG_FindOverrideForBuildable
-==============
-*/
-static buildableAttributeOverrides_t *BG_FindOverrideForBuildable( int bclass )
-{
- return &bg_buildableOverrideList[ bclass ];
-}
-
-/*
-==============
-BG_FindTransparentTestForBuildable
-==============
-*/
-qboolean BG_FindTransparentTestForBuildable( int bclass )
-{
- int i;
-
- for( i = 0; i < bg_numBuildables; i++ )
- {
- if( bg_buildableList[ i ].buildNum == bclass )
- {
- return bg_buildableList[ i ].transparentTest;
- }
- }
- return qfalse;
+ VectorCopy( buildableConfig->maxs, maxs );
}
/*
======================
BG_ParseBuildableFile
-Parses a configuration file describing a builable
+Parses a configuration file describing a buildable
======================
*/
-static qboolean BG_ParseBuildableFile( const char *filename, buildableAttributeOverrides_t *bao )
+static qboolean BG_ParseBuildableFile( const char *filename, buildableConfig_t *bc )
{
char *text_p;
int i;
@@ -1384,12 +676,24 @@ static qboolean BG_ParseBuildableFile( const char *filename, buildableAttributeO
char text[ 20000 ];
fileHandle_t f;
float scale;
+ int defined = 0;
+ enum
+ {
+ MODEL = 1 << 0,
+ MODELSCALE = 1 << 1,
+ MINS = 1 << 2,
+ MAXS = 1 << 3,
+ ZOFFSET = 1 << 4
+ };
// load the file
len = trap_FS_FOpenFile( filename, &f, FS_READ );
if( len < 0 )
+ {
+ Com_Printf( S_COLOR_RED "ERROR: Buildable file %s doesn't exist\n", filename );
return qfalse;
+ }
if( len == 0 || len >= sizeof( text ) - 1 )
{
@@ -1436,8 +740,9 @@ static qboolean BG_ParseBuildableFile( const char *filename, buildableAttributeO
if( !token )
break;
- Q_strncpyz( bao->models[ index ], token, sizeof( bao->models[ 0 ] ) );
+ Q_strncpyz( bc->models[ index ], token, sizeof( bc->models[ 0 ] ) );
+ defined |= MODEL;
continue;
}
else if( !Q_stricmp( token, "modelScale" ) )
@@ -1451,8 +756,9 @@ static qboolean BG_ParseBuildableFile( const char *filename, buildableAttributeO
if( scale < 0.0f )
scale = 0.0f;
- bao->modelScale = scale;
+ bc->modelScale = scale;
+ defined |= MODELSCALE;
continue;
}
else if( !Q_stricmp( token, "mins" ) )
@@ -1463,9 +769,10 @@ static qboolean BG_ParseBuildableFile( const char *filename, buildableAttributeO
if( !token )
break;
- bao->mins[ i ] = atof( token );
+ bc->mins[ i ] = atof( token );
}
+ defined |= MINS;
continue;
}
else if( !Q_stricmp( token, "maxs" ) )
@@ -1476,9 +783,10 @@ static qboolean BG_ParseBuildableFile( const char *filename, buildableAttributeO
if( !token )
break;
- bao->maxs[ i ] = atof( token );
+ bc->maxs[ i ] = atof( token );
}
+ defined |= MAXS;
continue;
}
else if( !Q_stricmp( token, "zOffset" ) )
@@ -1491,8 +799,9 @@ static qboolean BG_ParseBuildableFile( const char *filename, buildableAttributeO
offset = atof( token );
- bao->zOffset = offset;
+ bc->zOffset = offset;
+ defined |= ZOFFSET;
continue;
}
@@ -1501,59 +810,62 @@ static qboolean BG_ParseBuildableFile( const char *filename, buildableAttributeO
return qfalse;
}
+ if( !( defined & MODEL ) ) token = "model";
+ else if( !( defined & MODELSCALE ) ) token = "modelScale";
+ else if( !( defined & MINS ) ) token = "mins";
+ else if( !( defined & MAXS ) ) token = "maxs";
+ else if( !( defined & ZOFFSET ) ) token = "zOffset";
+ else token = "";
+
+ if( strlen( token ) > 0 )
+ {
+ Com_Printf( S_COLOR_RED "ERROR: %s not defined in %s\n",
+ token, filename );
+ return qfalse;
+ }
+
return qtrue;
}
/*
===============
-BG_InitBuildableOverrides
-
-Set any overrides specfied by file
+BG_InitBuildableConfigs
===============
*/
-void BG_InitBuildableOverrides( void )
+void BG_InitBuildableConfigs( void )
{
- int i;
- buildableAttributeOverrides_t *bao;
+ int i;
+ buildableConfig_t *bc;
for( i = BA_NONE + 1; i < BA_NUM_BUILDABLES; i++ )
{
- bao = BG_FindOverrideForBuildable( i );
+ bc = BG_BuildableConfig( i );
+ Com_Memset( bc, 0, sizeof( buildableConfig_t ) );
- BG_ParseBuildableFile( va( "overrides/buildables/%s.cfg", BG_FindNameForBuildable( i ) ), bao );
+ BG_ParseBuildableFile( va( "configs/buildables/%s.cfg",
+ BG_Buildable( i )->name ), bc );
}
}
////////////////////////////////////////////////////////////////////////////////
-classAttributes_t bg_classList[ ] =
+static const classAttributes_t bg_classList[ ] =
{
{
- PCL_NONE, //int classnum;
- "spectator", //char *className;
- "Spectator", //char *humanName;
- "", //char *modelname;
- 1.0f, //float modelScale;
- "", //char *skinname;
- 1.0f, //float shadowScale;
- "", //char *hudname;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- { -15, -15, -15 }, //vec3_t mins;
- { 15, 15, 15 }, //vec3_t maxs;
- { 15, 15, 15 }, //vec3_t crouchmaxs;
- { -15, -15, -15 }, //vec3_t deadmins;
- { 15, 15, 15 }, //vec3_t deadmaxs;
- 0.0f, //float zOffset
- 0, 0, //int viewheight, crouchviewheight;
+ PCL_NONE, //int number;
+ "spectator", //char *name;
+ "",
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
0, //int health;
0.0f, //float fallDamage;
- 0, //int regenRate;
+ 0.0f, //float regenRate;
0, //int abilities;
- WP_NONE, //weapon_t startWeapon
+ WP_NONE, //weapon_t startWeapon;
0.0f, //float buildDist;
90, //int fov;
0.000f, //float bob;
1.0f, //float bobCycle;
+ 0.0f, //float landBob;
0, //int steptime;
600, //float speed;
10.0f, //float acceleration;
@@ -1567,31 +879,21 @@ classAttributes_t bg_classList[ ] =
0 //int value;
},
{
- PCL_ALIEN_BUILDER0, //int classnum;
- "builder", //char *className;
- "Builder", //char *humanName;
- "builder", //char *modelname;
- 1.0f, //float modelScale;
- "default", //char *skinname;
- 1.0f, //float shadowScale;
- "alien_builder_hud", //char *hudname;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- { -15, -15, -20 }, //vec3_t mins;
- { 15, 15, 20 }, //vec3_t maxs;
- { 15, 15, 20 }, //vec3_t crouchmaxs;
- { -15, -15, -4 }, //vec3_t deadmins;
- { 15, 15, 4 }, //vec3_t deadmaxs;
- 0.0f, //float zOffset
- 0, 0, //int viewheight, crouchviewheight;
+ PCL_ALIEN_BUILDER0, //int number;
+ "builder", //char *name;
+ "Responsible for building and maintaining all the alien structures. "
+ "Has a weak melee slash attack.",
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
ABUILDER_HEALTH, //int health;
0.2f, //float fallDamage;
- ABUILDER_REGEN, //int regenRate;
- SCA_TAKESFALLDAMAGE|SCA_FOVWARPS|SCA_ALIENSENSE,//int abilities;
- WP_ABUILD, //weapon_t startWeapon
+ ABUILDER_REGEN, //float regenRate;
+ SCA_TAKESFALLDAMAGE|SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
+ WP_ABUILD, //weapon_t startWeapon;
95.0f, //float buildDist;
- 80, //int fov;
+ 110, //int fov;
0.001f, //float bob;
2.0f, //float bobCycle;
+ 4.5f, //float landBob;
150, //int steptime;
ABUILDER_SPEED, //float speed;
10.0f, //float acceleration;
@@ -1600,36 +902,27 @@ classAttributes_t bg_classList[ ] =
100.0f, //float stopSpeed;
195.0f, //float jumpMagnitude;
1.0f, //float knockbackScale;
- { PCL_ALIEN_BUILDER0_UPG, PCL_ALIEN_LEVEL0, PCL_NONE }, //int children[ 3 ];
+ { PCL_ALIEN_BUILDER0_UPG, PCL_ALIEN_LEVEL0, PCL_NONE }, //int children[ 3 ];
ABUILDER_COST, //int cost;
ABUILDER_VALUE //int value;
},
{
- PCL_ALIEN_BUILDER0_UPG, //int classnum;
- "builderupg", //char *classname;
- "Advanced Builder", //char *humanname;
- "builder", //char *modelname;
- 1.0f, //float modelScale;
- "advanced", //char *skinname;
- 1.0f, //float shadowScale;
- "alien_builder_hud", //char *hudname;
- ( 1 << S2 )|( 1 << S3 ), //int stages
- { -20, -20, -20 }, //vec3_t mins;
- { 20, 20, 20 }, //vec3_t maxs;
- { 20, 20, 20 }, //vec3_t crouchmaxs;
- { -20, -20, -4 }, //vec3_t deadmins;
- { 20, 20, 4 }, //vec3_t deadmaxs;
- 0.0f, //float zOffset
- 0, 0, //int viewheight, crouchviewheight;
+ PCL_ALIEN_BUILDER0_UPG, //int number;
+ "builderupg", //char *name;
+ "Similar to the base Granger, except that in addition to "
+ "being able to build structures it has a spit attack "
+ "that slows victims and the ability to crawl on walls.",
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
ABUILDER_UPG_HEALTH, //int health;
- 0.0f, //float fallDamage;
- ABUILDER_UPG_REGEN, //int regenRate;
- SCA_FOVWARPS|SCA_WALLCLIMBER|SCA_ALIENSENSE, //int abilities;
- WP_ABUILD2, //weapon_t startWeapon
+ 0.2f, //float fallDamage;
+ ABUILDER_UPG_REGEN, //float regenRate;
+ SCA_TAKESFALLDAMAGE|SCA_FOVWARPS|SCA_WALLCLIMBER|SCA_ALIENSENSE, //int abilities;
+ WP_ABUILD2, //weapon_t startWeapon;
105.0f, //float buildDist;
110, //int fov;
0.001f, //float bob;
2.0f, //float bobCycle;
+ 4.5f, //float landBob;
100, //int steptime;
ABUILDER_UPG_SPEED, //float speed;
10.0f, //float acceleration;
@@ -1643,32 +936,21 @@ classAttributes_t bg_classList[ ] =
ABUILDER_UPG_VALUE //int value;
},
{
- PCL_ALIEN_LEVEL0, //int classnum;
- "level0", //char *classname;
- "Soldier", //char *humanname;
- "jumper", //char *modelname;
- 0.2f, //float modelScale;
- "default", //char *skinname;
- 0.3f, //float shadowScale;
- "alien_general_hud", //char *hudname;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- { -15, -15, -15 }, //vec3_t mins;
- { 15, 15, 15 }, //vec3_t maxs;
- { 15, 15, 15 }, //vec3_t crouchmaxs;
- { -15, -15, -4 }, //vec3_t deadmins;
- { 15, 15, 4 }, //vec3_t deadmaxs;
- -8.0f, //float zOffset
- 0, 0, //int viewheight, crouchviewheight;
+ PCL_ALIEN_LEVEL0, //int number;
+ "level0", //char *name;
+ "Has a lethal reflexive bite and the ability to crawl on "
+ "walls and ceilings.",
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
LEVEL0_HEALTH, //int health;
0.0f, //float fallDamage;
- LEVEL0_REGEN, //int regenRate;
- SCA_WALLCLIMBER|SCA_NOWEAPONDRIFT|
- SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
- WP_ALEVEL0, //weapon_t startWeapon
+ LEVEL0_REGEN, //float regenRate;
+ SCA_WALLCLIMBER|SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
+ WP_ALEVEL0, //weapon_t startWeapon;
0.0f, //float buildDist;
140, //int fov;
0.0f, //float bob;
2.5f, //float bobCycle;
+ 0.0f, //float landBob;
25, //int steptime;
LEVEL0_SPEED, //float speed;
10.0f, //float acceleration;
@@ -1682,188 +964,138 @@ classAttributes_t bg_classList[ ] =
LEVEL0_VALUE //int value;
},
{
- PCL_ALIEN_LEVEL1, //int classnum;
- "level1", //char *classname;
- "Hydra", //char *humanname;
- "spitter", //char *modelname;
- 0.6f, //float modelScale;
- "default", //char *skinname;
- 1.0f, //float shadowScale;
- "alien_general_hud", //char *hudname;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- { -18, -18, -18 }, //vec3_t mins;
- { 18, 18, 18 }, //vec3_t maxs;
- { 18, 18, 18 }, //vec3_t crouchmaxs;
- { -18, -18, -4 }, //vec3_t deadmins;
- { 18, 18, 4 }, //vec3_t deadmaxs;
- 0.0f, //float zOffset
- 0, 0, //int viewheight, crouchviewheight;
+ PCL_ALIEN_LEVEL1, //int number;
+ "level1", //char *name;
+ "A support class able to crawl on walls and ceilings. Its melee "
+ "attack is most effective when combined with the ability to grab "
+ "and hold its victims in place. Provides a weak healing aura "
+ "that accelerates the healing rate of nearby aliens.",
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
LEVEL1_HEALTH, //int health;
0.0f, //float fallDamage;
- LEVEL1_REGEN, //int regenRate;
- SCA_NOWEAPONDRIFT|
- SCA_FOVWARPS|SCA_WALLCLIMBER|SCA_ALIENSENSE, //int abilities;
- WP_ALEVEL1, //weapon_t startWeapon
+ LEVEL1_REGEN, //float regenRate;
+ SCA_FOVWARPS|SCA_WALLCLIMBER|SCA_ALIENSENSE, //int abilities;
+ WP_ALEVEL1, //weapon_t startWeapon;
0.0f, //float buildDist;
120, //int fov;
0.001f, //float bob;
1.8f, //float bobCycle;
+ 0.0f, //float landBob;
60, //int steptime;
LEVEL1_SPEED, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
6.0f, //float friction;
300.0f, //float stopSpeed;
- 270.0f, //float jumpMagnitude;
+ 310.0f, //float jumpMagnitude;
1.2f, //float knockbackScale;
- { PCL_ALIEN_LEVEL2, PCL_ALIEN_LEVEL1_UPG, PCL_NONE }, //int children[ 3 ];
- LEVEL1_COST, //int cost;
- LEVEL1_VALUE //int value;
+ { PCL_ALIEN_LEVEL2, PCL_ALIEN_LEVEL1_UPG, PCL_NONE }, //int children[ 3 ];
+ LEVEL1_COST, //int cost;
+ LEVEL1_VALUE //int value;
},
{
- PCL_ALIEN_LEVEL1_UPG, //int classnum;
- "level1upg", //char *classname;
- "Hydra Upgrade", //char *humanname;
- "spitter", //char *modelname;
- 0.7f, //float modelScale;
- "blue", //char *skinname;
- 1.0f, //float shadowScale;
- "alien_general_hud", //char *hudname;
- ( 1 << S2 )|( 1 << S3 ), //int stages
- { -20, -20, -20 }, //vec3_t mins;
- { 20, 20, 20 }, //vec3_t maxs;
- { 20, 20, 20 }, //vec3_t crouchmaxs;
- { -20, -20, -4 }, //vec3_t deadmins;
- { 20, 20, 4 }, //vec3_t deadmaxs;
- 0.0f, //float zOffset
- 0, 0, //int viewheight, crouchviewheight;
+ PCL_ALIEN_LEVEL1_UPG, //int number;
+ "level1upg", //char *name;
+ "In addition to the basic Basilisk abilities, the Advanced "
+ "Basilisk sprays a poisonous gas which disorients any "
+ "nearby humans. Has a strong healing aura that "
+ "that accelerates the healing rate of nearby aliens.",
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
LEVEL1_UPG_HEALTH, //int health;
0.0f, //float fallDamage;
- LEVEL1_UPG_REGEN, //int regenRate;
- SCA_NOWEAPONDRIFT|SCA_FOVWARPS|
- SCA_WALLCLIMBER|SCA_ALIENSENSE, //int abilities;
- WP_ALEVEL1_UPG, //weapon_t startWeapon
+ LEVEL1_UPG_REGEN, //float regenRate;
+ SCA_FOVWARPS|SCA_WALLCLIMBER|SCA_ALIENSENSE, //int abilities;
+ WP_ALEVEL1_UPG, //weapon_t startWeapon;
0.0f, //float buildDist;
120, //int fov;
0.001f, //float bob;
1.8f, //float bobCycle;
+ 0.0f, //float landBob;
60, //int steptime;
LEVEL1_UPG_SPEED, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
6.0f, //float friction;
300.0f, //float stopSpeed;
- 270.0f, //float jumpMagnitude;
+ 310.0f, //float jumpMagnitude;
1.1f, //float knockbackScale;
{ PCL_ALIEN_LEVEL2, PCL_NONE, PCL_NONE }, //int children[ 3 ];
LEVEL1_UPG_COST, //int cost;
LEVEL1_UPG_VALUE //int value;
},
{
- PCL_ALIEN_LEVEL2, //int classnum;
- "level2", //char *classname;
- "Chimera", //char *humanname;
- "tarantula", //char *modelname;
- 0.75f, //float modelScale;
- "default", //char *skinname;
- 1.0f, //float shadowScale;
- "alien_general_hud", //char *hudname;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- { -22, -22, -22 }, //vec3_t mins;
- { 22, 22, 22 }, //vec3_t maxs;
- { 22, 22, 22 }, //vec3_t crouchmaxs;
- { -22, -22, -4 }, //vec3_t deadmins;
- { 22, 22, 4 }, //vec3_t deadmaxs;
- 0.0f, //float zOffset
- 10, 10, //int viewheight, crouchviewheight;
+ PCL_ALIEN_LEVEL2, //int number;
+ "level2", //char *name;
+ "Has a melee attack and the ability to jump off walls. This "
+ "allows the Marauder to gather great speed in enclosed areas.",
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
LEVEL2_HEALTH, //int health;
0.0f, //float fallDamage;
- LEVEL2_REGEN, //int regenRate;
- SCA_NOWEAPONDRIFT|SCA_WALLJUMPER|
- SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
- WP_ALEVEL2, //weapon_t startWeapon
+ LEVEL2_REGEN, //float regenRate;
+ SCA_WALLJUMPER|SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
+ WP_ALEVEL2, //weapon_t startWeapon;
0.0f, //float buildDist;
90, //int fov;
0.001f, //float bob;
1.5f, //float bobCycle;
+ 0.0f, //float landBob;
80, //int steptime;
LEVEL2_SPEED, //float speed;
10.0f, //float acceleration;
- 2.0f, //float airAcceleration;
+ 3.0f, //float airAcceleration;
6.0f, //float friction;
100.0f, //float stopSpeed;
- 400.0f, //float jumpMagnitude;
+ 380.0f, //float jumpMagnitude;
0.8f, //float knockbackScale;
- { PCL_ALIEN_LEVEL3, PCL_ALIEN_LEVEL2_UPG, PCL_NONE }, //int children[ 3 ];
+ { PCL_ALIEN_LEVEL3, PCL_ALIEN_LEVEL2_UPG, PCL_NONE }, //int children[ 3 ];
LEVEL2_COST, //int cost;
LEVEL2_VALUE //int value;
},
{
- PCL_ALIEN_LEVEL2_UPG, //int classnum;
- "level2upg", //char *classname;
- "Chimera Upgrade", //char *humanname;
- "tarantula", //char *modelname;
- 0.9f, //float modelScale;
- "red", //char *skinname;
- 1.0f, //float shadowScale;
- "alien_general_hud", //char *hudname;
- ( 1 << S2 )|( 1 << S3 ), //int stages
- { -24, -24, -24 }, //vec3_t mins;
- { 24, 24, 24 }, //vec3_t maxs;
- { 24, 24, 24 }, //vec3_t crouchmaxs;
- { -24, -24, -4 }, //vec3_t deadmins;
- { 24, 24, 4 }, //vec3_t deadmaxs;
- 0.0f, //float zOffset
- 12, 12, //int viewheight, crouchviewheight;
+ PCL_ALIEN_LEVEL2_UPG, //int number;
+ "level2upg", //char *name;
+ "The Advanced Marauder has all the abilities of the basic Marauder "
+ "with the addition of an area effect electric shock attack.",
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
LEVEL2_UPG_HEALTH, //int health;
0.0f, //float fallDamage;
- LEVEL2_UPG_REGEN, //int regenRate;
- SCA_NOWEAPONDRIFT|SCA_WALLJUMPER|
- SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
- WP_ALEVEL2_UPG, //weapon_t startWeapon
+ LEVEL2_UPG_REGEN, //float regenRate;
+ SCA_WALLJUMPER|SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
+ WP_ALEVEL2_UPG, //weapon_t startWeapon;
0.0f, //float buildDist;
90, //int fov;
0.001f, //float bob;
1.5f, //float bobCycle;
+ 0.0f, //float landBob;
80, //int steptime;
LEVEL2_UPG_SPEED, //float speed;
10.0f, //float acceleration;
- 2.0f, //float airAcceleration;
+ 3.0f, //float airAcceleration;
6.0f, //float friction;
100.0f, //float stopSpeed;
- 400.0f, //float jumpMagnitude;
+ 380.0f, //float jumpMagnitude;
0.7f, //float knockbackScale;
{ PCL_ALIEN_LEVEL3, PCL_NONE, PCL_NONE }, //int children[ 3 ];
LEVEL2_UPG_COST, //int cost;
LEVEL2_UPG_VALUE //int value;
},
{
- PCL_ALIEN_LEVEL3, //int classnum;
- "level3", //char *classname;
- "Dragoon", //char *humanname;
- "prowl", //char *modelname;
- 1.0f, //float modelScale;
- "default", //char *skinname;
- 1.0f, //float shadowScale;
- "alien_general_hud", //char *hudname;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- { -32, -32, -21 }, //vec3_t mins;
- { 32, 32, 21 }, //vec3_t maxs;
- { 32, 32, 21 }, //vec3_t crouchmaxs;
- { -32, -32, -4 }, //vec3_t deadmins;
- { 32, 32, 4 }, //vec3_t deadmaxs;
- 0.0f, //float zOffset
- 24, 24, //int viewheight, crouchviewheight;
+ PCL_ALIEN_LEVEL3, //int number;
+ "level3", //char *name;
+ "Possesses a melee attack and the pounce ability, which may "
+ "be used as both an attack and a means to reach remote "
+ "locations inaccessible from the ground.",
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
LEVEL3_HEALTH, //int health;
0.0f, //float fallDamage;
- LEVEL3_REGEN, //int regenRate;
- SCA_NOWEAPONDRIFT|
- SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
- WP_ALEVEL3, //weapon_t startWeapon
+ LEVEL3_REGEN, //float regenRate;
+ SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
+ WP_ALEVEL3, //weapon_t startWeapon;
0.0f, //float buildDist;
110, //int fov;
0.0005f, //float bob;
1.3f, //float bobCycle;
+ 0.0f, //float landBob;
90, //int steptime;
LEVEL3_SPEED, //float speed;
10.0f, //float acceleration;
@@ -1872,37 +1104,27 @@ classAttributes_t bg_classList[ ] =
200.0f, //float stopSpeed;
270.0f, //float jumpMagnitude;
0.5f, //float knockbackScale;
- { PCL_ALIEN_LEVEL4, PCL_ALIEN_LEVEL3_UPG, PCL_NONE }, //int children[ 3 ];
+ { PCL_ALIEN_LEVEL4, PCL_ALIEN_LEVEL3_UPG, PCL_NONE }, //int children[ 3 ];
LEVEL3_COST, //int cost;
LEVEL3_VALUE //int value;
},
{
- PCL_ALIEN_LEVEL3_UPG, //int classnum;
- "level3upg", //char *classname;
- "Dragoon Upgrade", //char *humanname;
- "prowl", //char *modelname;
- 1.0f, //float modelScale;
- "default", //char *skinname;
- 1.0f, //float shadowScale;
- "alien_general_hud", //char *hudname;
- ( 1 << S3 ), //int stages
- { -32, -32, -21 }, //vec3_t mins;
- { 32, 32, 21 }, //vec3_t maxs;
- { 32, 32, 21 }, //vec3_t crouchmaxs;
- { -32, -32, -4 }, //vec3_t deadmins;
- { 32, 32, 4 }, //vec3_t deadmaxs;
- 0.0f, //float zOffset
- 27, 27, //int viewheight, crouchviewheight;
+ PCL_ALIEN_LEVEL3_UPG, //int number;
+ "level3upg", //char *name;
+ "In addition to the basic Dragoon abilities, the Advanced "
+ "Dragoon has 3 barbs which may be used to attack humans "
+ "from a distance.",
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
LEVEL3_UPG_HEALTH, //int health;
0.0f, //float fallDamage;
- LEVEL3_UPG_REGEN, //int regenRate;
- SCA_NOWEAPONDRIFT|
- SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
- WP_ALEVEL3_UPG, //weapon_t startWeapon
+ LEVEL3_UPG_REGEN, //float regenRate;
+ SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
+ WP_ALEVEL3_UPG, //weapon_t startWeapon;
0.0f, //float buildDist;
110, //int fov;
0.0005f, //float bob;
1.3f, //float bobCycle;
+ 0.0f, //float landBob;
90, //int steptime;
LEVEL3_UPG_SPEED, //float speed;
10.0f, //float acceleration;
@@ -1916,32 +1138,23 @@ classAttributes_t bg_classList[ ] =
LEVEL3_UPG_VALUE //int value;
},
{
- PCL_ALIEN_LEVEL4, //int classnum;
- "level4", //char *classname;
- "Big Mofo", //char *humanname;
- "mofo", //char *modelname;
- 1.0f, //float modelScale;
- "default", //char *skinname;
- 2.0f, //float shadowScale;
- "alien_general_hud", //char *hudname;
- ( 1 << S3 ), //int stages
- { -30, -30, -20 }, //vec3_t mins;
- { 30, 30, 20 }, //vec3_t maxs;
- { 30, 30, 20 }, //vec3_t crouchmaxs;
- { -15, -15, -4 }, //vec3_t deadmins;
- { 15, 15, 4 }, //vec3_t deadmaxs;
- 0.0f, //float zOffset
- 35, 35, //int viewheight, crouchviewheight;
+ PCL_ALIEN_LEVEL4, //int number;
+ "level4", //char *name;
+ "A large alien with a strong melee attack, this class can "
+ "also charge at enemy humans and structures, inflicting "
+ "great damage. Any humans or their structures caught under "
+ "a falling Tyrant will be crushed by its weight.",
+ ( 1 << S3 ), //int stages;
LEVEL4_HEALTH, //int health;
0.0f, //float fallDamage;
- LEVEL4_REGEN, //int regenRate;
- SCA_NOWEAPONDRIFT|
- SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
- WP_ALEVEL4, //weapon_t startWeapon
+ LEVEL4_REGEN, //float regenRate;
+ SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities;
+ WP_ALEVEL4, //weapon_t startWeapon;
0.0f, //float buildDist;
90, //int fov;
0.001f, //float bob;
1.1f, //float bobCycle;
+ 0.0f, //float landBob;
100, //int steptime;
LEVEL4_SPEED, //float speed;
10.0f, //float acceleration;
@@ -1955,32 +1168,20 @@ classAttributes_t bg_classList[ ] =
LEVEL4_VALUE //int value;
},
{
- PCL_HUMAN, //int classnum;
- "human_base", //char *classname;
- "Human", //char *humanname;
- "sarge", //char *modelname;
- 1.0f, //float modelScale;
- "default", //char *skinname;
- 1.0f, //float shadowScale;
- "human_hud", //char *hudname;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- { -15, -15, -24 }, //vec3_t mins;
- { 15, 15, 32 }, //vec3_t maxs;
- { 15, 15, 16 }, //vec3_t crouchmaxs;
- { -15, -15, -4 }, //vec3_t deadmins;
- { 15, 15, 4 }, //vec3_t deadmaxs;
- 0.0f, //float zOffset
- 26, 12, //int viewheight, crouchviewheight;
+ PCL_HUMAN, //int number;
+ "human_base", //char *name;
+ "",
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
100, //int health;
1.0f, //float fallDamage;
- 0, //int regenRate;
- SCA_TAKESFALLDAMAGE|
- SCA_CANUSELADDERS, //int abilities;
- WP_NONE, //special-cased in g_client.c //weapon_t startWeapon
+ 0.0f, //float regenRate;
+ SCA_TAKESFALLDAMAGE|SCA_CANUSELADDERS, //int abilities;
+ WP_NONE, //special-cased in g_client.c //weapon_t startWeapon;
110.0f, //float buildDist;
90, //int fov;
0.002f, //float bob;
1.0f, //float bobCycle;
+ 8.0f, //float landBob;
100, //int steptime;
1.0f, //float speed;
10.0f, //float acceleration;
@@ -1991,684 +1192,120 @@ classAttributes_t bg_classList[ ] =
1.0f, //float knockbackScale;
{ PCL_NONE, PCL_NONE, PCL_NONE }, //int children[ 3 ];
0, //int cost;
- 0 //int value;
+ ALIEN_CREDITS_PER_KILL //int value;
},
{
- PCL_HUMAN_BSUIT, //int classnum;
- "human_bsuit", //char *classname;
- "bsuit", //char *humanname;
- "keel", //char *modelname;
- 1.0f, //float modelScale;
- "default", //char *skinname;
- 1.0f, //float shadowScale;
- "human_hud", //char *hudname;
- ( 1 << S3 ), //int stages
- { -15, -15, -38 }, //vec3_t mins;
- { 15, 15, 38 }, //vec3_t maxs;
- { 15, 15, 38 }, //vec3_t crouchmaxs;
- { -15, -15, -4 }, //vec3_t deadmins;
- { 15, 15, 4 }, //vec3_t deadmaxs;
- -16.0f, //float zOffset
- 35, 35, //int viewheight, crouchviewheight;
+ PCL_HUMAN_BSUIT, //int number;
+ "human_bsuit", //char *name;
+ "",
+ ( 1 << S3 ), //int stages;
100, //int health;
1.0f, //float fallDamage;
- 0, //int regenRate;
- SCA_TAKESFALLDAMAGE|
- SCA_CANUSELADDERS, //int abilities;
- WP_NONE, //special-cased in g_client.c //weapon_t startWeapon
+ 0.0f, //float regenRate;
+ SCA_TAKESFALLDAMAGE|SCA_CANUSELADDERS, //int abilities;
+ WP_NONE, //special-cased in g_client.c //weapon_t startWeapon;
110.0f, //float buildDist;
90, //int fov;
0.002f, //float bob;
1.0f, //float bobCycle;
+ 5.0f, //float landBob;
100, //int steptime;
1.0f, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
6.0f, //float friction;
100.0f, //float stopSpeed;
- 270.0f, //float jumpMagnitude;
+ 220.0f, //float jumpMagnitude;
1.0f, //float knockbackScale;
{ PCL_NONE, PCL_NONE, PCL_NONE }, //int children[ 3 ];
0, //int cost;
- 0 //int value;
- },
-};
-
-int bg_numPclasses = sizeof( bg_classList ) / sizeof( bg_classList[ 0 ] );
-
-//separate from bg_classList to work around char struct init bug
-classAttributeOverrides_t bg_classOverrideList[ PCL_NUM_CLASSES ];
-
-/*
-==============
-BG_FindClassNumForName
-==============
-*/
-int BG_FindClassNumForName( char *name )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( !Q_stricmp( bg_classList[ i ].className, name ) )
- return bg_classList[ i ].classNum;
- }
-
- //wimp out
- return PCL_NONE;
-}
-
-/*
-==============
-BG_FindNameForClassNum
-==============
-*/
-char *BG_FindNameForClassNum( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- return bg_classList[ i ].className;
+ ALIEN_CREDITS_PER_KILL //int value;
}
+};
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindNameForClassNum\n" );
- //wimp out
- return 0;
-}
-
-/*
-==============
-BG_FindHumanNameForClassNum
-==============
-*/
-char *BG_FindHumanNameForClassNum( int pclass )
-{
- int i;
-
- if( bg_classOverrideList[ pclass ].humanName[ 0 ] != 0 )
- return bg_classOverrideList[ pclass ].humanName;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- return bg_classList[ i ].humanName;
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindHumanNameForClassNum\n" );
- //wimp out
- return 0;
-}
-
-/*
-==============
-BG_FindModelNameForClass
-==============
-*/
-char *BG_FindModelNameForClass( int pclass )
-{
- int i;
-
- if( bg_classOverrideList[ pclass ].modelName[ 0 ] != 0 )
- return bg_classOverrideList[ pclass ].modelName;
+size_t bg_numClasses = ARRAY_LEN( bg_classList );
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- return bg_classList[ i ].modelName;
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindModelNameForClass\n" );
- //note: must return a valid modelName!
- return bg_classList[ 0 ].modelName;
-}
+static const classAttributes_t nullClass = { 0 };
/*
==============
-BG_FindModelScaleForClass
+BG_ClassByName
==============
*/
-float BG_FindModelScaleForClass( int pclass )
+const classAttributes_t *BG_ClassByName( const char *name )
{
int i;
- if( bg_classOverrideList[ pclass ].modelScale != 0.0f )
- return bg_classOverrideList[ pclass ].modelScale;
-
- for( i = 0; i < bg_numPclasses; i++ )
+ for( i = 0; i < bg_numClasses; i++ )
{
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].modelScale;
- }
+ if( !Q_stricmp( bg_classList[ i ].name, name ) )
+ return &bg_classList[ i ];
}
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindModelScaleForClass( %d )\n", pclass );
- return 1.0f;
+ return &nullClass;
}
/*
==============
-BG_FindSkinNameForClass
+BG_Class
==============
*/
-char *BG_FindSkinNameForClass( int pclass )
+const classAttributes_t *BG_Class( class_t class )
{
- int i;
-
- if( bg_classOverrideList[ pclass ].skinName[ 0 ] != 0 )
- return bg_classOverrideList[ pclass ].skinName;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- return bg_classList[ i ].skinName;
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindSkinNameForClass\n" );
- //note: must return a valid modelName!
- return bg_classList[ 0 ].skinName;
+ return ( class >= PCL_NONE && class < PCL_NUM_CLASSES ) ?
+ &bg_classList[ class ] : &nullClass;
}
/*
==============
-BG_FindShadowScaleForClass
+BG_ClassAllowedInStage
==============
*/
-float BG_FindShadowScaleForClass( int pclass )
+qboolean BG_ClassAllowedInStage( class_t class,
+ stage_t stage )
{
- int i;
+ int stages = BG_Class( class )->stages;
- if( bg_classOverrideList[ pclass ].shadowScale != 0.0f )
- return bg_classOverrideList[ pclass ].shadowScale;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].shadowScale;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindShadowScaleForClass( %d )\n", pclass );
- return 1.0f;
+ return stages & ( 1 << stage );
}
-/*
-==============
-BG_FindHudNameForClass
-==============
-*/
-char *BG_FindHudNameForClass( int pclass )
-{
- int i;
-
- if( bg_classOverrideList[ pclass ].hudName[ 0 ] != 0 )
- return bg_classOverrideList[ pclass ].hudName;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- return bg_classList[ i ].hudName;
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindHudNameForClass\n" );
- //note: must return a valid hudName!
- return bg_classList[ 0 ].hudName;
-}
+static classConfig_t bg_classConfigList[ PCL_NUM_CLASSES ];
/*
==============
-BG_FindStagesForClass
+BG_ClassConfig
==============
*/
-qboolean BG_FindStagesForClass( int pclass, stage_t stage )
+classConfig_t *BG_ClassConfig( class_t class )
{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- if( bg_classList[ i ].stages & ( 1 << stage ) )
- return qtrue;
- else
- return qfalse;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindStagesForClass\n" );
- return qfalse;
+ return &bg_classConfigList[ class ];
}
/*
==============
-BG_FindBBoxForClass
+BG_ClassBoundingBox
==============
*/
-void BG_FindBBoxForClass( int pclass, vec3_t mins, vec3_t maxs, vec3_t cmaxs, vec3_t dmins, vec3_t dmaxs )
+void BG_ClassBoundingBox( class_t class,
+ vec3_t mins, vec3_t maxs,
+ vec3_t cmaxs, vec3_t dmins, vec3_t dmaxs )
{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- if( mins != NULL )
- {
- VectorCopy( bg_classList[ i ].mins, mins );
-
- if( VectorLength( bg_classOverrideList[ pclass ].mins ) )
- VectorCopy( bg_classOverrideList[ pclass ].mins, mins );
- }
-
- if( maxs != NULL )
- {
- VectorCopy( bg_classList[ i ].maxs, maxs );
-
- if( VectorLength( bg_classOverrideList[ pclass ].maxs ) )
- VectorCopy( bg_classOverrideList[ pclass ].maxs, maxs );
- }
-
- if( cmaxs != NULL )
- {
- VectorCopy( bg_classList[ i ].crouchMaxs, cmaxs );
-
- if( VectorLength( bg_classOverrideList[ pclass ].crouchMaxs ) )
- VectorCopy( bg_classOverrideList[ pclass ].crouchMaxs, cmaxs );
- }
-
- if( dmins != NULL )
- {
- VectorCopy( bg_classList[ i ].deadMins, dmins );
-
- if( VectorLength( bg_classOverrideList[ pclass ].deadMins ) )
- VectorCopy( bg_classOverrideList[ pclass ].deadMins, dmins );
- }
-
- if( dmaxs != NULL )
- {
- VectorCopy( bg_classList[ i ].deadMaxs, dmaxs );
-
- if( VectorLength( bg_classOverrideList[ pclass ].deadMaxs ) )
- VectorCopy( bg_classOverrideList[ pclass ].deadMaxs, dmaxs );
- }
-
- return;
- }
- }
+ classConfig_t *classConfig = BG_ClassConfig( class );
if( mins != NULL )
- VectorCopy( bg_classList[ 0 ].mins, mins );
+ VectorCopy( classConfig->mins, mins );
if( maxs != NULL )
- VectorCopy( bg_classList[ 0 ].maxs, maxs );
+ VectorCopy( classConfig->maxs, maxs );
if( cmaxs != NULL )
- VectorCopy( bg_classList[ 0 ].crouchMaxs, cmaxs );
+ VectorCopy( classConfig->crouchMaxs, cmaxs );
if( dmins != NULL )
- VectorCopy( bg_classList[ 0 ].deadMins, dmins );
+ VectorCopy( classConfig->deadMins, dmins );
if( dmaxs != NULL )
- VectorCopy( bg_classList[ 0 ].deadMaxs, dmaxs );
-}
-
-/*
-==============
-BG_FindZOffsetForClass
-==============
-*/
-float BG_FindZOffsetForClass( int pclass )
-{
- int i;
-
- if( bg_classOverrideList[ pclass ].zOffset != 0.0f )
- return bg_classOverrideList[ pclass ].zOffset;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].zOffset;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindZOffsetForClass\n" );
- return 0.0f;
-}
-
-/*
-==============
-BG_FindViewheightForClass
-==============
-*/
-void BG_FindViewheightForClass( int pclass, int *viewheight, int *cViewheight )
-{
- int i;
- int vh = 0;
- int cvh = 0;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- vh = bg_classList[ i ].viewheight;
- cvh = bg_classList[ i ].crouchViewheight;
- break;
- }
- }
-
- if( bg_classOverrideList[ pclass ].viewheight != 0 )
- vh = bg_classOverrideList[ pclass ].viewheight;
- if( bg_classOverrideList[ pclass ].crouchViewheight != 0 )
- cvh = bg_classOverrideList[ pclass ].crouchViewheight;
-
-
- if( vh == 0 )
- vh = bg_classList[ 0 ].viewheight;
- if( cvh == 0 )
- cvh = bg_classList[ 0 ].crouchViewheight;
-
- if( viewheight != NULL )
- *viewheight = vh;
- if( cViewheight != NULL )
- *cViewheight = cvh;
-}
-
-/*
-==============
-BG_FindHealthForClass
-==============
-*/
-int BG_FindHealthForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].health;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindHealthForClass\n" );
- return 100;
-}
-
-/*
-==============
-BG_FindFallDamageForClass
-==============
-*/
-float BG_FindFallDamageForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].fallDamage;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindFallDamageForClass\n" );
- return 100;
-}
-
-/*
-==============
-BG_FindRegenRateForClass
-==============
-*/
-int BG_FindRegenRateForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].regenRate;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindRegenRateForClass\n" );
- return 0;
-}
-
-/*
-==============
-BG_FindFovForClass
-==============
-*/
-int BG_FindFovForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].fov;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindFovForClass\n" );
- return 90;
-}
-
-/*
-==============
-BG_FindBobForClass
-==============
-*/
-float BG_FindBobForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].bob;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindBobForClass\n" );
- return 0.002;
-}
-
-/*
-==============
-BG_FindBobCycleForClass
-==============
-*/
-float BG_FindBobCycleForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].bobCycle;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindBobCycleForClass\n" );
- return 1.0f;
-}
-
-/*
-==============
-BG_FindSpeedForClass
-==============
-*/
-float BG_FindSpeedForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].speed;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindSpeedForClass\n" );
- return 1.0f;
-}
-
-/*
-==============
-BG_FindAccelerationForClass
-==============
-*/
-float BG_FindAccelerationForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].acceleration;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindAccelerationForClass\n" );
- return 10.0f;
-}
-
-/*
-==============
-BG_FindAirAccelerationForClass
-==============
-*/
-float BG_FindAirAccelerationForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].airAcceleration;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindAirAccelerationForClass\n" );
- return 1.0f;
-}
-
-/*
-==============
-BG_FindFrictionForClass
-==============
-*/
-float BG_FindFrictionForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].friction;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindFrictionForClass\n" );
- return 6.0f;
-}
-
-/*
-==============
-BG_FindStopSpeedForClass
-==============
-*/
-float BG_FindStopSpeedForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].stopSpeed;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindStopSpeedForClass\n" );
- return 100.0f;
-}
-
-/*
-==============
-BG_FindJumpMagnitudeForClass
-==============
-*/
-float BG_FindJumpMagnitudeForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].jumpMagnitude;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindJumpMagnitudeForClass\n" );
- return 270.0f;
-}
-
-/*
-==============
-BG_FindKnockbackScaleForClass
-==============
-*/
-float BG_FindKnockbackScaleForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].knockbackScale;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindKnockbackScaleForClass\n" );
- return 1.0f;
-}
-
-/*
-==============
-BG_FindSteptimeForClass
-==============
-*/
-int BG_FindSteptimeForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].steptime;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindSteptimeForClass\n" );
- return 200;
+ VectorCopy( classConfig->deadMaxs, dmaxs );
}
/*
@@ -2676,61 +1313,11 @@ int BG_FindSteptimeForClass( int pclass )
BG_ClassHasAbility
==============
*/
-qboolean BG_ClassHasAbility( int pclass, int ability )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return ( bg_classList[ i ].abilities & ability );
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindStartWeaponForClass
-==============
-*/
-weapon_t BG_FindStartWeaponForClass( int pclass )
+qboolean BG_ClassHasAbility( class_t class, int ability )
{
- int i;
+ int abilities = BG_Class( class )->abilities;
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].startWeapon;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindStartWeaponForClass\n" );
- return WP_NONE;
-}
-
-/*
-==============
-BG_FindBuildDistForClass
-==============
-*/
-float BG_FindBuildDistForClass( int pclass )
-{
- int i;
-
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].buildDist;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindBuildDistForClass\n" );
- return 0.0f;
+ return abilities & ability;
}
/*
@@ -2738,95 +1325,78 @@ float BG_FindBuildDistForClass( int pclass )
BG_ClassCanEvolveFromTo
==============
*/
-int BG_ClassCanEvolveFromTo( int fclass, int tclass, int credits, int num )
+int BG_ClassCanEvolveFromTo( class_t fclass,
+ class_t tclass,
+ int credits, int stage,
+ int cost )
{
- int i, j, cost;
-
- cost = BG_FindCostOfClass( tclass );
+ int i, j, best, value;
- //base case
- if( credits < cost )
+ if( credits < cost || fclass == PCL_NONE || tclass == PCL_NONE ||
+ fclass == tclass )
return -1;
- if( fclass == PCL_NONE || tclass == PCL_NONE )
- return -1;
-
- for( i = 0; i < bg_numPclasses; i++ )
+ for( i = 0; i < bg_numClasses; i++ )
{
- if( bg_classList[ i ].classNum == fclass )
- {
- for( j = 0; j < 3; j++ )
- if( bg_classList[ i ].children[ j ] == tclass )
- return num + cost;
+ if( bg_classList[ i ].number != fclass )
+ continue;
- for( j = 0; j < 3; j++ )
- {
- int sub;
+ best = credits + 1;
+ for( j = 0; j < 3; j++ )
+ {
+ int thruClass, evolveCost;
+
+ thruClass = bg_classList[ i ].children[ j ];
+ if( thruClass == PCL_NONE || !BG_ClassAllowedInStage( thruClass, stage ) ||
+ !BG_ClassIsAllowed( thruClass ) )
+ continue;
- cost = BG_FindCostOfClass( bg_classList[ i ].children[ j ] );
- sub = BG_ClassCanEvolveFromTo( bg_classList[ i ].children[ j ],
- tclass, credits - cost, num + cost );
- if( sub >= 0 )
- return sub;
- }
+ evolveCost = BG_Class( thruClass )->cost * ALIEN_CREDITS_PER_KILL;
+ if( thruClass == tclass )
+ value = cost + evolveCost;
+ else
+ value = BG_ClassCanEvolveFromTo( thruClass, tclass, credits, stage,
+ cost + evolveCost );
- return -1; //may as well return by this point
+ if( value >= 0 && value < best )
+ best = value;
}
+
+ return best <= credits ? best : -1;
}
+ Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_ClassCanEvolveFromTo\n" );
return -1;
}
/*
==============
-BG_FindValueOfClass
+BG_AlienCanEvolve
==============
*/
-int BG_FindValueOfClass( int pclass )
+qboolean BG_AlienCanEvolve( class_t class, int credits, int stage )
{
- int i;
+ int i, j, tclass;
- for( i = 0; i < bg_numPclasses; i++ )
+ for( i = 0; i < bg_numClasses; i++ )
{
- if( bg_classList[ i ].classNum == pclass )
- {
- return bg_classList[ i ].value;
- }
- }
-
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindValueOfClass\n" );
- return 0;
-}
-
-/*
-==============
-BG_FindCostOfClass
-==============
-*/
-int BG_FindCostOfClass( int pclass )
-{
- int i;
+ if( bg_classList[ i ].number != class )
+ continue;
- for( i = 0; i < bg_numPclasses; i++ )
- {
- if( bg_classList[ i ].classNum == pclass )
+ for( j = 0; j < 3; j++ )
{
- return bg_classList[ i ].cost;
+ tclass = bg_classList[ i ].children[ j ];
+ if( tclass != PCL_NONE && BG_ClassAllowedInStage( tclass, stage ) &&
+ BG_ClassIsAllowed( tclass ) &&
+ credits >= BG_Class( tclass )->cost * ALIEN_CREDITS_PER_KILL )
+ return qtrue;
}
- }
- Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindCostOfClass\n" );
- return 0;
-}
+ return qfalse;
+ }
-/*
-==============
-BG_FindOverrideForClass
-==============
-*/
-static classAttributeOverrides_t *BG_FindOverrideForClass( int pclass )
-{
- return &bg_classOverrideList[ pclass ];
+ Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_AlienCanEvolve\n" );
+ return qfalse;
}
/*
@@ -2836,7 +1406,7 @@ BG_ParseClassFile
Parses a configuration file describing a class
======================
*/
-static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides_t *cao )
+static qboolean BG_ParseClassFile( const char *filename, classConfig_t *cc )
{
char *text_p;
int i;
@@ -2845,7 +1415,25 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
char text[ 20000 ];
fileHandle_t f;
float scale = 0.0f;
-
+ int defined = 0;
+ enum
+ {
+ MODEL = 1 << 0,
+ SKIN = 1 << 1,
+ HUD = 1 << 2,
+ MODELSCALE = 1 << 3,
+ SHADOWSCALE = 1 << 4,
+ MINS = 1 << 5,
+ MAXS = 1 << 6,
+ DEADMINS = 1 << 7,
+ DEADMAXS = 1 << 8,
+ CROUCHMAXS = 1 << 9,
+ VIEWHEIGHT = 1 << 10,
+ CVIEWHEIGHT = 1 << 11,
+ ZOFFSET = 1 << 12,
+ NAME = 1 << 13,
+ SHOULDEROFFSETS = 1 << 14
+ };
// load the file
len = trap_FS_FOpenFile( filename, &f, FS_READ );
@@ -2884,8 +1472,9 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
if( !token )
break;
- Q_strncpyz( cao->modelName, token, sizeof( cao->modelName ) );
+ Q_strncpyz( cc->modelName, token, sizeof( cc->modelName ) );
+ defined |= MODEL;
continue;
}
else if( !Q_stricmp( token, "skin" ) )
@@ -2894,8 +1483,9 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
if( !token )
break;
- Q_strncpyz( cao->skinName, token, sizeof( cao->skinName ) );
+ Q_strncpyz( cc->skinName, token, sizeof( cc->skinName ) );
+ defined |= SKIN;
continue;
}
else if( !Q_stricmp( token, "hud" ) )
@@ -2904,8 +1494,9 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
if( !token )
break;
- Q_strncpyz( cao->hudName, token, sizeof( cao->hudName ) );
+ Q_strncpyz( cc->hudName, token, sizeof( cc->hudName ) );
+ defined |= HUD;
continue;
}
else if( !Q_stricmp( token, "modelScale" ) )
@@ -2919,8 +1510,9 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
if( scale < 0.0f )
scale = 0.0f;
- cao->modelScale = scale;
+ cc->modelScale = scale;
+ defined |= MODELSCALE;
continue;
}
else if( !Q_stricmp( token, "shadowScale" ) )
@@ -2934,8 +1526,9 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
if( scale < 0.0f )
scale = 0.0f;
- cao->shadowScale = scale;
+ cc->shadowScale = scale;
+ defined |= SHADOWSCALE;
continue;
}
else if( !Q_stricmp( token, "mins" ) )
@@ -2946,9 +1539,10 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
if( !token )
break;
- cao->mins[ i ] = atof( token );
+ cc->mins[ i ] = atof( token );
}
+ defined |= MINS;
continue;
}
else if( !Q_stricmp( token, "maxs" ) )
@@ -2959,9 +1553,10 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
if( !token )
break;
- cao->maxs[ i ] = atof( token );
+ cc->maxs[ i ] = atof( token );
}
+ defined |= MAXS;
continue;
}
else if( !Q_stricmp( token, "deadMins" ) )
@@ -2972,9 +1567,10 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
if( !token )
break;
- cao->deadMins[ i ] = atof( token );
+ cc->deadMins[ i ] = atof( token );
}
+ defined |= DEADMINS;
continue;
}
else if( !Q_stricmp( token, "deadMaxs" ) )
@@ -2985,9 +1581,10 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
if( !token )
break;
- cao->deadMaxs[ i ] = atof( token );
+ cc->deadMaxs[ i ] = atof( token );
}
+ defined |= DEADMAXS;
continue;
}
else if( !Q_stricmp( token, "crouchMaxs" ) )
@@ -2998,21 +1595,24 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
if( !token )
break;
- cao->crouchMaxs[ i ] = atof( token );
+ cc->crouchMaxs[ i ] = atof( token );
}
+ defined |= CROUCHMAXS;
continue;
}
else if( !Q_stricmp( token, "viewheight" ) )
{
token = COM_Parse( &text_p );
- cao->viewheight = atoi( token );
+ cc->viewheight = atoi( token );
+ defined |= VIEWHEIGHT;
continue;
}
else if( !Q_stricmp( token, "crouchViewheight" ) )
{
token = COM_Parse( &text_p );
- cao->crouchViewheight = atoi( token );
+ cc->crouchViewheight = atoi( token );
+ defined |= CVIEWHEIGHT;
continue;
}
else if( !Q_stricmp( token, "zOffset" ) )
@@ -3025,8 +1625,9 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
offset = atof( token );
- cao->zOffset = offset;
+ cc->zOffset = offset;
+ defined |= ZOFFSET;
continue;
}
else if( !Q_stricmp( token, "name" ) )
@@ -3035,275 +1636,341 @@ static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides
if( !token )
break;
- Q_strncpyz( cao->humanName, token, sizeof( cao->humanName ) );
+ Q_strncpyz( cc->humanName, token, sizeof( cc->humanName ) );
+ defined |= NAME;
continue;
}
+ else if( !Q_stricmp( token, "shoulderOffsets" ) )
+ {
+ for( i = 0; i <= 2; i++ )
+ {
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+ cc->shoulderOffsets[ i ] = atof( token );
+ }
+
+ defined |= SHOULDEROFFSETS;
+ continue;
+ }
Com_Printf( S_COLOR_RED "ERROR: unknown token '%s'\n", token );
return qfalse;
}
+ if( !( defined & MODEL ) ) token = "model";
+ else if( !( defined & SKIN ) ) token = "skin";
+ else if( !( defined & HUD ) ) token = "hud";
+ else if( !( defined & MODELSCALE ) ) token = "modelScale";
+ else if( !( defined & SHADOWSCALE ) ) token = "shadowScale";
+ else if( !( defined & MINS ) ) token = "mins";
+ else if( !( defined & MAXS ) ) token = "maxs";
+ else if( !( defined & DEADMINS ) ) token = "deadMins";
+ else if( !( defined & DEADMAXS ) ) token = "deadMaxs";
+ else if( !( defined & CROUCHMAXS ) ) token = "crouchMaxs";
+ else if( !( defined & VIEWHEIGHT ) ) token = "viewheight";
+ else if( !( defined & CVIEWHEIGHT ) ) token = "crouchViewheight";
+ else if( !( defined & ZOFFSET ) ) token = "zOffset";
+ else if( !( defined & NAME ) ) token = "name";
+ else if( !( defined & SHOULDEROFFSETS ) ) token = "shoulderOffsets";
+ else token = "";
+
+ if( strlen( token ) > 0 )
+ {
+ Com_Printf( S_COLOR_RED "ERROR: %s not defined in %s\n",
+ token, filename );
+ return qfalse;
+ }
+
return qtrue;
}
/*
===============
-BG_InitClassOverrides
-
-Set any overrides specfied by file
+BG_InitClassConfigs
===============
*/
-void BG_InitClassOverrides( void )
+void BG_InitClassConfigs( void )
{
- int i;
- classAttributeOverrides_t *cao;
+ int i;
+ classConfig_t *cc;
- for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ )
+ for( i = PCL_NONE; i < PCL_NUM_CLASSES; i++ )
{
- cao = BG_FindOverrideForClass( i );
+ cc = BG_ClassConfig( i );
- BG_ParseClassFile( va( "overrides/classes/%s.cfg", BG_FindNameForClassNum( i ) ), cao );
+ BG_ParseClassFile( va( "configs/classes/%s.cfg",
+ BG_Class( i )->name ), cc );
}
}
////////////////////////////////////////////////////////////////////////////////
-weaponAttributes_t bg_weapons[ ] =
+static const weaponAttributes_t bg_weapons[ ] =
{
{
- WP_BLASTER, //int weaponNum;
+ WP_ALEVEL0, //int number;
0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- 0, //int slots;
- "blaster", //char *weaponName;
- "Blaster", //char *weaponHumanName;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
+ SLOT_WEAPON, //int slots;
+ "level0", //char *name;
+ "Bite", //char *humanName;
+ "",
0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
- BLASTER_REPEAT, //int repeatRate1;
+ LEVEL0_BITE_REPEAT, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
0, //int reloadTime;
- BLASTER_K_SCALE, //float knockbackScale;
+ LEVEL0_BITE_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
qfalse, //qboolean purchasable;
- qtrue, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ qfalse, //qboolean longRanged;
+ TEAM_ALIENS //team_t team;
},
{
- WP_MACHINEGUN, //int weaponNum;
- RIFLE_PRICE, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_ALEVEL1, //int number;
+ 0, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "rifle", //char *weaponName;
- "Rifle", //char *weaponHumanName;
- RIFLE_CLIPSIZE, //int maxAmmo;
- RIFLE_MAXCLIPS, //int maxClips;
- qfalse, //int infiniteAmmo;
+ "level1", //char *name;
+ "Claws", //char *humanName;
+ "",
+ 0, //int maxAmmo;
+ 0, //int maxClips;
+ qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
- RIFLE_REPEAT, //int repeatRate1;
+ LEVEL1_CLAW_REPEAT, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
- RIFLE_RELOAD, //int reloadTime;
- RIFLE_K_SCALE, //float knockbackScale;
+ 0, //int reloadTime;
+ LEVEL1_CLAW_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qtrue, //qboolean purchasable;
- qtrue, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ qfalse, //qboolean purchasable;
+ qfalse, //qboolean longRanged;
+ TEAM_ALIENS //team_t team;
},
{
- WP_SHOTGUN, //int weaponNum;
- SHOTGUN_PRICE, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_ALEVEL1_UPG, //int number;
+ 0, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "shotgun", //char *weaponName;
- "Shotgun", //char *weaponHumanName;
- SHOTGUN_SHELLS, //int maxAmmo;
- SHOTGUN_MAXCLIPS, //int maxClips;
- qfalse, //int infiniteAmmo;
+ "level1upg", //char *name;
+ "Claws Upgrade", //char *humanName;
+ "",
+ 0, //int maxAmmo;
+ 0, //int maxClips;
+ qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
- SHOTGUN_REPEAT, //int repeatRate1;
- 0, //int repeatRate2;
+ LEVEL1_CLAW_U_REPEAT, //int repeatRate1;
+ LEVEL1_PCLOUD_REPEAT, //int repeatRate2;
0, //int repeatRate3;
- SHOTGUN_RELOAD, //int reloadTime;
- SHOTGUN_K_SCALE, //float knockbackScale;
- qfalse, //qboolean hasAltMode;
+ 0, //int reloadTime;
+ LEVEL1_CLAW_U_K_SCALE, //float knockbackScale;
+ qtrue, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qtrue, //qboolean purchasable;
+ qfalse, //qboolean purchasable;
qtrue, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ TEAM_ALIENS //team_t team;
},
{
- WP_FLAMER, //int weaponNum;
- FLAMER_PRICE, //int price;
- ( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_ALEVEL2, //int number;
+ 0, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "flamer", //char *weaponName;
- "Flame Thrower", //char *weaponHumanName;
- FLAMER_GAS, //int maxAmmo;
+ "level2", //char *name;
+ "Bite", //char *humanName;
+ "",
+ 0, //int maxAmmo;
0, //int maxClips;
- qfalse, //int infiniteAmmo;
+ qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
- FLAMER_REPEAT, //int repeatRate1;
+ LEVEL2_CLAW_REPEAT, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
0, //int reloadTime;
- FLAMER_K_SCALE, //float knockbackScale;
+ LEVEL2_CLAW_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qtrue, //qboolean purchasable;
- qtrue, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ qfalse, //qboolean purchasable;
+ qfalse, //qboolean longRanged;
+ TEAM_ALIENS //team_t team;
},
{
- WP_CHAINGUN, //int weaponNum;
- CHAINGUN_PRICE, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_ALEVEL2_UPG, //int number;
+ 0, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "chaingun", //char *weaponName;
- "Chaingun", //char *weaponHumanName;
- CHAINGUN_BULLETS, //int maxAmmo;
+ "level2upg", //char *name;
+ "Zap", //char *humanName;
+ "",
+ 0, //int maxAmmo;
0, //int maxClips;
- qfalse, //int infiniteAmmo;
+ qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
- CHAINGUN_REPEAT, //int repeatRate1;
- 0, //int repeatRate2;
+ LEVEL2_CLAW_U_REPEAT, //int repeatRate1;
+ LEVEL2_AREAZAP_REPEAT, //int repeatRate2;
0, //int repeatRate3;
0, //int reloadTime;
- CHAINGUN_K_SCALE, //float knockbackScale;
- qfalse, //qboolean hasAltMode;
+ LEVEL2_CLAW_U_K_SCALE, //float knockbackScale;
+ qtrue, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qtrue, //qboolean purchasable;
- qtrue, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ qfalse, //qboolean purchasable;
+ qfalse, //qboolean longRanged;
+ TEAM_ALIENS //team_t team;
},
{
- WP_MASS_DRIVER, //int weaponNum;
- MDRIVER_PRICE, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_ALEVEL3, //int number;
+ 0, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "mdriver", //char *weaponName;
- "Mass Driver", //char *weaponHumanName;
- MDRIVER_CLIPSIZE, //int maxAmmo;
- MDRIVER_MAXCLIPS, //int maxClips;
- qfalse, //int infiniteAmmo;
- qtrue, //int usesEnergy;
- MDRIVER_REPEAT, //int repeatRate1;
+ "level3", //char *name;
+ "Pounce", //char *humanName;
+ "",
+ 0, //int maxAmmo;
+ 0, //int maxClips;
+ qtrue, //int infiniteAmmo;
+ qfalse, //int usesEnergy;
+ LEVEL3_CLAW_REPEAT, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
- MDRIVER_RELOAD, //int reloadTime;
- MDRIVER_K_SCALE, //float knockbackScale;
+ 0, //int reloadTime;
+ LEVEL3_CLAW_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
- qtrue, //qboolean canZoom;
- 20.0f, //float zoomFov;
- qtrue, //qboolean purchasable;
+ qfalse, //qboolean canZoom;
+ 90.0f, //float zoomFov;
+ qfalse, //qboolean purchasable;
+ qfalse, //qboolean longRanged;
+ TEAM_ALIENS //team_t team;
+ },
+ {
+ WP_ALEVEL3_UPG, //int number;
+ 0, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
+ SLOT_WEAPON, //int slots;
+ "level3upg", //char *name;
+ "Pounce (upgrade)", //char *humanName;
+ "",
+ 3, //int maxAmmo;
+ 0, //int maxClips;
+ qtrue, //int infiniteAmmo;
+ qfalse, //int usesEnergy;
+ LEVEL3_CLAW_U_REPEAT, //int repeatRate1;
+ 0, //int repeatRate2;
+ LEVEL3_BOUNCEBALL_REPEAT, //int repeatRate3;
+ 0, //int reloadTime;
+ LEVEL3_CLAW_U_K_SCALE, //float knockbackScale;
+ qfalse, //qboolean hasAltMode;
+ qtrue, //qboolean hasThirdMode;
+ qfalse, //qboolean canZoom;
+ 90.0f, //float zoomFov;
+ qfalse, //qboolean purchasable;
qtrue, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ TEAM_ALIENS //team_t team;
},
{
- WP_PULSE_RIFLE, //int weaponNum;
- PRIFLE_PRICE, //int price;
- ( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_ALEVEL4, //int number;
+ 0, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "prifle", //char *weaponName;
- "Pulse Rifle", //char *weaponHumanName;
- PRIFLE_CLIPS, //int maxAmmo;
- PRIFLE_MAXCLIPS, //int maxClips;
- qfalse, //int infiniteAmmo;
- qtrue, //int usesEnergy;
- PRIFLE_REPEAT, //int repeatRate1;
+ "level4", //char *name;
+ "Charge", //char *humanName;
+ "",
+ 0, //int maxAmmo;
+ 0, //int maxClips;
+ qtrue, //int infiniteAmmo;
+ qfalse, //int usesEnergy;
+ LEVEL4_CLAW_REPEAT, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
- PRIFLE_RELOAD, //int reloadTime;
- PRIFLE_K_SCALE, //float knockbackScale;
+ 0, //int reloadTime;
+ LEVEL4_CLAW_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qtrue, //qboolean purchasable;
- qtrue, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ qfalse, //qboolean purchasable;
+ qfalse, //qboolean longRanged;
+ TEAM_ALIENS //team_t team;
},
{
- WP_LUCIFER_CANNON, //int weaponNum;
- LCANNON_PRICE, //int price;
- ( 1 << S3 ), //int stages
- SLOT_WEAPON, //int slots;
- "lcannon", //char *weaponName;
- "Lucifer Cannon", //char *weaponHumanName;
- LCANNON_AMMO, //int maxAmmo;
+ WP_BLASTER, //int number;
+ 0, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
+ 0, //int slots;
+ "blaster", //char *name;
+ "Blaster", //char *humanName;
+ "",
+ 0, //int maxAmmo;
0, //int maxClips;
- qfalse, //int infiniteAmmo;
- qtrue, //int usesEnergy;
- LCANNON_REPEAT, //int repeatRate1;
- LCANNON_CHARGEREPEAT, //int repeatRate2;
+ qtrue, //int infiniteAmmo;
+ qfalse, //int usesEnergy;
+ BLASTER_REPEAT, //int repeatRate1;
+ 0, //int repeatRate2;
0, //int repeatRate3;
- LCANNON_RELOAD, //int reloadTime;
- LCANNON_K_SCALE, //float knockbackScale;
- qtrue, //qboolean hasAltMode;
+ 0, //int reloadTime;
+ BLASTER_K_SCALE, //float knockbackScale;
+ qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qtrue, //qboolean purchasable;
+ qfalse, //qboolean purchasable;
qtrue, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ TEAM_HUMANS //team_t team;
},
{
- WP_LAS_GUN, //int weaponNum;
- LASGUN_PRICE, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_MACHINEGUN, //int number;
+ RIFLE_PRICE, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "lgun", //char *weaponName;
- "Las Gun", //char *weaponHumanName;
- LASGUN_AMMO, //int maxAmmo;
- 0, //int maxClips;
+ "rifle", //char *name;
+ "Rifle", //char *humanName;
+ "Basic weapon. Cased projectile weapon, with a slow clip based "
+ "reload system.",
+ RIFLE_CLIPSIZE, //int maxAmmo;
+ RIFLE_MAXCLIPS, //int maxClips;
qfalse, //int infiniteAmmo;
- qtrue, //int usesEnergy;
- LASGUN_REPEAT, //int repeatRate1;
+ qfalse, //int usesEnergy;
+ RIFLE_REPEAT, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
- LASGUN_RELOAD, //int reloadTime;
- LASGUN_K_SCALE, //float knockbackScale;
+ RIFLE_RELOAD, //int reloadTime;
+ RIFLE_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
qtrue, //qboolean purchasable;
qtrue, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ TEAM_HUMANS //team_t team;
},
{
- WP_PAIN_SAW, //int weaponNum;
+ WP_PAIN_SAW, //int number;
PAINSAW_PRICE, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "psaw", //char *weaponName;
- "Pain Saw", //char *weaponHumanName;
+ "psaw", //char *name;
+ "Pain Saw", //char *humanName;
+ "Similar to a chainsaw, but instead of a chain it has an "
+ "electric arc capable of dealing a great deal of damage at "
+ "close range.",
0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
@@ -3319,1173 +1986,609 @@ weaponAttributes_t bg_weapons[ ] =
90.0f, //float zoomFov;
qtrue, //qboolean purchasable;
qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ TEAM_HUMANS //team_t team;
},
{
- WP_GRENADE, //int weaponNum;
- GRENADE_PRICE, //int price;
- ( 1 << S2 )|( 1 << S3 ), //int stages
- SLOT_NONE, //int slots;
- "grenade", //char *weaponName;
- "Grenade", //char *weaponHumanName;
- 1, //int maxAmmo;
- 0, //int maxClips;
+ WP_SHOTGUN, //int number;
+ SHOTGUN_PRICE, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
+ SLOT_WEAPON, //int slots;
+ "shotgun", //char *name;
+ "Shotgun", //char *humanName;
+ "Close range weapon that is useful against larger foes. "
+ "It has a slow repeat rate, but can be devastatingly "
+ "effective.",
+ SHOTGUN_SHELLS, //int maxAmmo;
+ SHOTGUN_MAXCLIPS, //int maxClips;
qfalse, //int infiniteAmmo;
qfalse, //int usesEnergy;
- GRENADE_REPEAT, //int repeatRate1;
+ SHOTGUN_REPEAT, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
- 0, //int reloadTime;
- GRENADE_K_SCALE, //float knockbackScale;
+ SHOTGUN_RELOAD, //int reloadTime;
+ SHOTGUN_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qfalse, //qboolean purchasable;
- qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ qtrue, //qboolean purchasable;
+ qtrue, //qboolean longRanged;
+ TEAM_HUMANS //team_t team;
},
{
- WP_HBUILD, //int weaponNum;
- HBUILD_PRICE, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_LAS_GUN, //int number;
+ LASGUN_PRICE, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "ckit", //char *weaponName;
- "Construction Kit", //char *weaponHumanName;
- 0, //int maxAmmo;
+ "lgun", //char *name;
+ "Las Gun", //char *humanName;
+ "Slightly more powerful than the basic rifle, rapidly fires "
+ "small packets of energy.",
+ LASGUN_AMMO, //int maxAmmo;
0, //int maxClips;
- qtrue, //int infiniteAmmo;
- qfalse, //int usesEnergy;
- HBUILD_REPEAT, //int repeatRate1;
- HBUILD_REPEAT, //int repeatRate2;
+ qfalse, //int infiniteAmmo;
+ qtrue, //int usesEnergy;
+ LASGUN_REPEAT, //int repeatRate1;
+ 0, //int repeatRate2;
0, //int repeatRate3;
- 0, //int reloadTime;
- 0.0f, //float knockbackScale;
- qtrue, //qboolean hasAltMode;
+ LASGUN_RELOAD, //int reloadTime;
+ LASGUN_K_SCALE, //float knockbackScale;
+ qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
qtrue, //qboolean purchasable;
- qfalse, //qboolean longRanged;
- HBUILD_DELAY, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ qtrue, //qboolean longRanged;
+ TEAM_HUMANS //team_t team;
},
{
- WP_HBUILD2, //int weaponNum;
- HBUILD2_PRICE, //int price;
- ( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_MASS_DRIVER, //int number;
+ MDRIVER_PRICE, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "ackit", //char *weaponName;
- "Adv Construction Kit",//char *weaponHumanName;
- 0, //int maxAmmo;
- 0, //int maxClips;
- qtrue, //int infiniteAmmo;
- qfalse, //int usesEnergy;
- HBUILD2_REPEAT, //int repeatRate1;
- HBUILD2_REPEAT, //int repeatRate2;
+ "mdriver", //char *name;
+ "Mass Driver", //char *humanName;
+ "A portable particle accelerator which causes minor nuclear "
+ "reactions at the point of impact. It has a very large "
+ "payload, but fires slowly.",
+ MDRIVER_CLIPSIZE, //int maxAmmo;
+ MDRIVER_MAXCLIPS, //int maxClips;
+ qfalse, //int infiniteAmmo;
+ qtrue, //int usesEnergy;
+ MDRIVER_REPEAT, //int repeatRate1;
+ 0, //int repeatRate2;
0, //int repeatRate3;
- 0, //int reloadTime;
- 0.0f, //float knockbackScale;
- qtrue, //qboolean hasAltMode;
+ MDRIVER_RELOAD, //int reloadTime;
+ MDRIVER_K_SCALE, //float knockbackScale;
+ qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
- qfalse, //qboolean canZoom;
- 90.0f, //float zoomFov;
+ qtrue, //qboolean canZoom;
+ 20.0f, //float zoomFov;
qtrue, //qboolean purchasable;
- qfalse, //qboolean longRanged;
- HBUILD2_DELAY, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ qtrue, //qboolean longRanged;
+ TEAM_HUMANS //team_t team;
},
{
- WP_ABUILD, //int weaponNum;
- 0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_CHAINGUN, //int number;
+ CHAINGUN_PRICE, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "abuild", //char *weaponName;
- "Alien build weapon", //char *weaponHumanName;
- 0, //int maxAmmo;
+ "chaingun", //char *name;
+ "Chaingun", //char *humanName;
+ "Belt drive, cased projectile weapon. It has a high repeat "
+ "rate but a wide firing angle and is therefore relatively "
+ "inaccurate.",
+ CHAINGUN_BULLETS, //int maxAmmo;
0, //int maxClips;
- qtrue, //int infiniteAmmo;
+ qfalse, //int infiniteAmmo;
qfalse, //int usesEnergy;
- ABUILDER_BUILD_REPEAT,//int repeatRate1;
- ABUILDER_BUILD_REPEAT,//int repeatRate2;
+ CHAINGUN_REPEAT, //int repeatRate1;
+ 0, //int repeatRate2;
0, //int repeatRate3;
0, //int reloadTime;
- 0.0f, //float knockbackScale;
- qtrue, //qboolean hasAltMode;
+ CHAINGUN_K_SCALE, //float knockbackScale;
+ qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
qtrue, //qboolean purchasable;
- qfalse, //qboolean longRanged;
- ABUILDER_BASE_DELAY, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
- },
- {
- WP_ABUILD2, //int weaponNum;
- 0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- SLOT_WEAPON, //int slots;
- "abuildupg", //char *weaponName;
- "Alien build weapon2",//char *weaponHumanName;
- 0, //int maxAmmo;
- 0, //int maxClips;
- qtrue, //int infiniteAmmo;
- qfalse, //int usesEnergy;
- ABUILDER_BUILD_REPEAT,//int repeatRate1;
- ABUILDER_CLAW_REPEAT, //int repeatRate2;
- ABUILDER_BLOB_REPEAT, //int repeatRate3;
- 0, //int reloadTime;
- ABUILDER_CLAW_K_SCALE,//float knockbackScale;
- qtrue, //qboolean hasAltMode;
- qtrue, //qboolean hasThirdMode;
- qfalse, //qboolean canZoom;
- 90.0f, //float zoomFov;
- qtrue, //qboolean purchasable;
- qfalse, //qboolean longRanged;
- ABUILDER_ADV_DELAY, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
+ qtrue, //qboolean longRanged;
+ TEAM_HUMANS //team_t team;
},
{
- WP_ALEVEL0, //int weaponNum;
- 0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_FLAMER, //int number;
+ FLAMER_PRICE, //int price;
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "level0", //char *weaponName;
- "Bite", //char *weaponHumanName;
- 0, //int maxAmmo;
+ "flamer", //char *name;
+ "Flame Thrower", //char *humanName;
+ "Sprays fire at its target. It is powered by compressed "
+ "gas. The relatively low rate of fire means this weapon is most "
+ "effective against static targets.",
+ FLAMER_GAS, //int maxAmmo;
0, //int maxClips;
- qtrue, //int infiniteAmmo;
+ qfalse, //int infiniteAmmo;
qfalse, //int usesEnergy;
- LEVEL0_BITE_REPEAT, //int repeatRate1;
+ FLAMER_REPEAT, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
0, //int reloadTime;
- LEVEL0_BITE_K_SCALE, //float knockbackScale;
+ FLAMER_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qfalse, //qboolean purchasable;
- qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
+ qtrue, //qboolean purchasable;
+ qtrue, //qboolean longRanged;
+ TEAM_HUMANS //team_t team;
},
{
- WP_ALEVEL1, //int weaponNum;
- 0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_PULSE_RIFLE, //int number;
+ PRIFLE_PRICE, //int price;
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "level1", //char *weaponName;
- "Claws", //char *weaponHumanName;
- 0, //int maxAmmo;
- 0, //int maxClips;
- qtrue, //int infiniteAmmo;
- qfalse, //int usesEnergy;
- LEVEL1_CLAW_REPEAT, //int repeatRate1;
+ "prifle", //char *name;
+ "Pulse Rifle", //char *humanName;
+ "An energy weapon that fires rapid pulses of concentrated energy.",
+ PRIFLE_CLIPS, //int maxAmmo;
+ PRIFLE_MAXCLIPS, //int maxClips;
+ qfalse, //int infiniteAmmo;
+ qtrue, //int usesEnergy;
+ PRIFLE_REPEAT, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
- 0, //int reloadTime;
- LEVEL1_CLAW_K_SCALE, //float knockbackScale;
+ PRIFLE_RELOAD, //int reloadTime;
+ PRIFLE_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qfalse, //qboolean purchasable;
- qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
+ qtrue, //qboolean purchasable;
+ qtrue, //qboolean longRanged;
+ TEAM_HUMANS //team_t team;
},
{
- WP_ALEVEL1_UPG, //int weaponNum;
- 0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_LUCIFER_CANNON, //int number;
+ LCANNON_PRICE, //int price;
+ ( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "level1upg", //char *weaponName;
- "Claws Upgrade", //char *weaponHumanName;
- 0, //int maxAmmo;
+ "lcannon", //char *name;
+ "Lucifer Cannon", //char *humanName;
+ "Blaster technology scaled up to deliver devastating power. "
+ "Primary fire must be charged before firing. It has a quick "
+ "secondary attack that does not require charging.",
+ LCANNON_AMMO, //int maxAmmo;
0, //int maxClips;
- qtrue, //int infiniteAmmo;
- qfalse, //int usesEnergy;
- LEVEL1_CLAW_U_REPEAT, //int repeatRate1;
- LEVEL1_PCLOUD_REPEAT, //int repeatRate2;
+ qfalse, //int infiniteAmmo;
+ qtrue, //int usesEnergy;
+ LCANNON_REPEAT, //int repeatRate1;
+ LCANNON_SECONDARY_REPEAT, //int repeatRate2;
0, //int repeatRate3;
- 0, //int reloadTime;
- LEVEL1_CLAW_U_K_SCALE,//float knockbackScale;
+ LCANNON_RELOAD, //int reloadTime;
+ LCANNON_K_SCALE, //float knockbackScale;
qtrue, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qfalse, //qboolean purchasable;
+ qtrue, //qboolean purchasable;
qtrue, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
+ TEAM_HUMANS //team_t team;
},
{
- WP_ALEVEL2, //int weaponNum;
- 0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- SLOT_WEAPON, //int slots;
- "level2", //char *weaponName;
- "Bite", //char *weaponHumanName;
- 0, //int maxAmmo;
+ WP_GRENADE, //int number;
+ GRENADE_PRICE, //int price;
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
+ SLOT_NONE, //int slots;
+ "grenade", //char *name;
+ "Grenade", //char *humanName;
+ "",
+ 1, //int maxAmmo;
0, //int maxClips;
- qtrue, //int infiniteAmmo;
+ qfalse, //int infiniteAmmo;
qfalse, //int usesEnergy;
- LEVEL2_CLAW_REPEAT, //int repeatRate1;
+ GRENADE_REPEAT, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
0, //int reloadTime;
- LEVEL2_CLAW_K_SCALE, //float knockbackScale;
+ GRENADE_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
qfalse, //qboolean purchasable;
qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
+ TEAM_HUMANS //team_t team;
},
{
- WP_ALEVEL2_UPG, //int weaponNum;
+ WP_LOCKBLOB_LAUNCHER, //int number;
0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "level2upg", //char *weaponName;
- "Zap", //char *weaponHumanName;
+ "lockblob", //char *name;
+ "Lock Blob", //char *humanName;
+ "",
0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
- LEVEL2_CLAW_U_REPEAT, //int repeatRate1;
- LEVEL2_AREAZAP_REPEAT,//int repeatRate2;
- 0, //int repeatRate3;
+ 500, //int repeatRate1;
+ 500, //int repeatRate2;
+ 500, //int repeatRate3;
0, //int reloadTime;
- LEVEL2_CLAW_U_K_SCALE,//float knockbackScale;
- qtrue, //qboolean hasAltMode;
+ LOCKBLOB_K_SCALE, //float knockbackScale;
+ qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
qfalse, //qboolean purchasable;
qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
+ TEAM_ALIENS //team_t team;
},
{
- WP_ALEVEL3, //int weaponNum;
+ WP_HIVE, //int number;
0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "level3", //char *weaponName;
- "Pounce", //char *weaponHumanName;
+ "hive", //char *name;
+ "Hive", //char *humanName;
+ "",
0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
- LEVEL3_CLAW_REPEAT, //int repeatRate1;
- 0, //int repeatRate2;
- 0, //int repeatRate3;
+ 500, //int repeatRate1;
+ 500, //int repeatRate2;
+ 500, //int repeatRate3;
0, //int reloadTime;
- LEVEL3_CLAW_K_SCALE, //float knockbackScale;
+ HIVE_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
qfalse, //qboolean purchasable;
qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
+ TEAM_ALIENS //team_t team;
},
{
- WP_ALEVEL3_UPG, //int weaponNum;
+ WP_TESLAGEN, //int number;
0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "level3upg", //char *weaponName;
- "Pounce (upgrade)", //char *weaponHumanName;
- 3, //int maxAmmo;
+ "teslagen", //char *name;
+ "Tesla Generator", //char *humanName;
+ "",
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
- qfalse, //int usesEnergy;
- LEVEL3_CLAW_U_REPEAT, //int repeatRate1;
- 0, //int repeatRate2;
- LEVEL3_BOUNCEBALL_REPEAT,//int repeatRate3;
+ qtrue, //int usesEnergy;
+ 500, //int repeatRate1;
+ 500, //int repeatRate2;
+ 500, //int repeatRate3;
0, //int reloadTime;
- LEVEL3_CLAW_U_K_SCALE,//float knockbackScale;
+ TESLAGEN_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
- qtrue, //qboolean hasThirdMode;
+ qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
qfalse, //qboolean purchasable;
- qtrue, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
+ qfalse, //qboolean longRanged;
+ TEAM_HUMANS //team_t team;
},
{
- WP_ALEVEL4, //int weaponNum;
+ WP_MGTURRET, //int number;
0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "level4", //char *weaponName;
- "Charge", //char *weaponHumanName;
+ "mgturret", //char *name;
+ "Machinegun Turret", //char *humanName;
+ "",
0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
- LEVEL4_CLAW_REPEAT, //int repeatRate1;
+ 0, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
0, //int reloadTime;
- LEVEL4_CLAW_K_SCALE, //float knockbackScale;
+ MGTURRET_K_SCALE, //float knockbackScale;
qfalse, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
qfalse, //qboolean purchasable;
qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
+ TEAM_HUMANS //team_t team;
},
{
- WP_LOCKBLOB_LAUNCHER, //int weaponNum;
+ WP_ABUILD, //int number;
0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "lockblob", //char *weaponName;
- "Lock Blob", //char *weaponHumanName;
+ "abuild", //char *name;
+ "Alien build weapon", //char *humanName;
+ "",
0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
- 500, //int repeatRate1;
- 500, //int repeatRate2;
- 500, //int repeatRate3;
+ ABUILDER_BUILD_REPEAT, //int repeatRate1;
+ ABUILDER_CLAW_REPEAT, //int repeatRate2;
+ 0, //int repeatRate3;
0, //int reloadTime;
- LOCKBLOB_K_SCALE, //float knockbackScale;
- qfalse, //qboolean hasAltMode;
+ ABUILDER_CLAW_K_SCALE, //float knockbackScale;
+ qtrue, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qfalse, //qboolean purchasable;
+ qtrue, //qboolean purchasable;
qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
+ TEAM_ALIENS //team_t team;
},
{
- WP_HIVE, //int weaponNum;
+ WP_ABUILD2, //int number;
0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "hive", //char *weaponName;
- "Hive", //char *weaponHumanName;
+ "abuildupg", //char *name;
+ "Alien build weapon2", //char *humanName;
+ "",
0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
- 500, //int repeatRate1;
- 500, //int repeatRate2;
- 500, //int repeatRate3;
+ ABUILDER_BUILD_REPEAT, //int repeatRate1;
+ ABUILDER_CLAW_REPEAT, //int repeatRate2;
+ ABUILDER_BLOB_REPEAT, //int repeatRate3;
0, //int reloadTime;
- HIVE_K_SCALE, //float knockbackScale;
- qfalse, //qboolean hasAltMode;
- qfalse, //qboolean hasThirdMode;
+ ABUILDER_CLAW_K_SCALE, //float knockbackScale;
+ qtrue, //qboolean hasAltMode;
+ qtrue, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qfalse, //qboolean purchasable;
+ qtrue, //qboolean purchasable;
qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_ALIENS //WUTeam_t team;
+ TEAM_ALIENS //team_t team;
},
{
- WP_MGTURRET, //int weaponNum;
- 0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ WP_HBUILD, //int number;
+ HBUILD_PRICE, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_WEAPON, //int slots;
- "mgturret", //char *weaponName;
- "Machinegun Turret", //char *weaponHumanName;
+ "ckit", //char *name;
+ "Construction Kit", //char *humanName;
+ "Used for building structures. This includes "
+ "spawns, power and basic defense. More structures become "
+ "available with new stages.",
0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
- 0, //int repeatRate1;
+ HBUILD_REPEAT, //int repeatRate1;
0, //int repeatRate2;
0, //int repeatRate3;
0, //int reloadTime;
- MGTURRET_K_SCALE, //float knockbackScale;
- qfalse, //qboolean hasAltMode;
- qfalse, //qboolean hasThirdMode;
- qfalse, //qboolean canZoom;
- 90.0f, //float zoomFov;
- qfalse, //qboolean purchasable;
- qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
- },
- {
- WP_TESLAGEN, //int weaponNum;
- 0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
- SLOT_WEAPON, //int slots;
- "teslagen", //char *weaponName;
- "Tesla Generator", //char *weaponHumanName;
- 0, //int maxAmmo;
- 0, //int maxClips;
- qtrue, //int infiniteAmmo;
- qtrue, //int usesEnergy;
- 500, //int repeatRate1;
- 500, //int repeatRate2;
- 500, //int repeatRate3;
- 0, //int reloadTime;
- TESLAGEN_K_SCALE, //float knockbackScale;
- qfalse, //qboolean hasAltMode;
+ 0.0f, //float knockbackScale;
+ qtrue, //qboolean hasAltMode;
qfalse, //qboolean hasThirdMode;
qfalse, //qboolean canZoom;
90.0f, //float zoomFov;
- qfalse, //qboolean purchasable;
+ qtrue, //qboolean purchasable;
qfalse, //qboolean longRanged;
- 0, //int buildDelay;
- WUT_HUMANS //WUTeam_t team;
+ TEAM_HUMANS //team_t team;
}
};
-int bg_numWeapons = sizeof( bg_weapons ) / sizeof( bg_weapons[ 0 ] );
-
-/*
-==============
-BG_FindPriceForWeapon
-==============
-*/
-int BG_FindPriceForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].price;
- }
- }
+size_t bg_numWeapons = ARRAY_LEN( bg_weapons );
- return 100;
-}
+static const weaponAttributes_t nullWeapon = { 0 };
/*
==============
-BG_FindStagesForWeapon
+BG_WeaponByName
==============
*/
-qboolean BG_FindStagesForWeapon( int weapon, stage_t stage )
+const weaponAttributes_t *BG_WeaponByName( const char *name )
{
int i;
for( i = 0; i < bg_numWeapons; i++ )
{
- if( bg_weapons[ i ].weaponNum == weapon )
+ if( !Q_stricmp( bg_weapons[ i ].name, name ) )
{
- if( bg_weapons[ i ].stages & ( 1 << stage ) )
- return qtrue;
- else
- return qfalse;
+ return &bg_weapons[ i ];
}
}
- return qfalse;
-}
-
-/*
-==============
-BG_FindSlotsForWeapon
-==============
-*/
-int BG_FindSlotsForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].slots;
- }
- }
-
- return SLOT_WEAPON;
-}
-
-/*
-==============
-BG_FindNameForWeapon
-==============
-*/
-char *BG_FindNameForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- return bg_weapons[ i ].weaponName;
- }
-
- //wimp out
- return 0;
+ return &nullWeapon;
}
/*
==============
-BG_FindWeaponNumForName
+BG_Weapon
==============
*/
-int BG_FindWeaponNumForName( char *name )
+const weaponAttributes_t *BG_Weapon( weapon_t weapon )
{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( !Q_stricmp( bg_weapons[ i ].weaponName, name ) )
- return bg_weapons[ i ].weaponNum;
- }
-
- //wimp out
- return WP_NONE;
+ return ( weapon > WP_NONE && weapon < WP_NUM_WEAPONS ) ?
+ &bg_weapons[ weapon - 1 ] : &nullWeapon;
}
/*
==============
-BG_FindHumanNameForWeapon
+BG_WeaponAllowedInStage
==============
*/
-char *BG_FindHumanNameForWeapon( int weapon )
+qboolean BG_WeaponAllowedInStage( weapon_t weapon, stage_t stage )
{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- return bg_weapons[ i ].weaponHumanName;
- }
+ int stages = BG_Weapon( weapon )->stages;
- //wimp out
- return 0;
-}
-
-/*
-==============
-BG_FindAmmoForWeapon
-==============
-*/
-void BG_FindAmmoForWeapon( int weapon, int *maxAmmo, int *maxClips )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- if( maxAmmo != NULL )
- *maxAmmo = bg_weapons[ i ].maxAmmo;
- if( maxClips != NULL )
- *maxClips = bg_weapons[ i ].maxClips;
-
- //no need to keep going
- break;
- }
- }
-}
-
-/*
-==============
-BG_FindInfinteAmmoForWeapon
-==============
-*/
-qboolean BG_FindInfinteAmmoForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].infiniteAmmo;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindUsesEnergyForWeapon
-==============
-*/
-qboolean BG_FindUsesEnergyForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].usesEnergy;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindRepeatRate1ForWeapon
-==============
-*/
-int BG_FindRepeatRate1ForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- return bg_weapons[ i ].repeatRate1;
- }
-
- return 1000;
-}
-
-/*
-==============
-BG_FindRepeatRate2ForWeapon
-==============
-*/
-int BG_FindRepeatRate2ForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- return bg_weapons[ i ].repeatRate2;
- }
-
- return 1000;
-}
-
-/*
-==============
-BG_FindRepeatRate3ForWeapon
-==============
-*/
-int BG_FindRepeatRate3ForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- return bg_weapons[ i ].repeatRate3;
- }
-
- return 1000;
-}
-
-/*
-==============
-BG_FindReloadTimeForWeapon
-==============
-*/
-int BG_FindReloadTimeForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].reloadTime;
- }
- }
-
- return 1000;
-}
-
-/*
-==============
-BG_FindKnockbackScaleForWeapon
-==============
-*/
-float BG_FindKnockbackScaleForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].knockbackScale;
- }
- }
-
- return 1.0f;
-}
-
-/*
-==============
-BG_WeaponHasAltMode
-==============
-*/
-qboolean BG_WeaponHasAltMode( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].hasAltMode;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_WeaponHasThirdMode
-==============
-*/
-qboolean BG_WeaponHasThirdMode( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].hasThirdMode;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_WeaponCanZoom
-==============
-*/
-qboolean BG_WeaponCanZoom( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].canZoom;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindZoomFovForWeapon
-==============
-*/
-float BG_FindZoomFovForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].zoomFov;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindPurchasableForWeapon
-==============
-*/
-qboolean BG_FindPurchasableForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].purchasable;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindLongRangeForWeapon
-==============
-*/
-qboolean BG_FindLongRangedForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].longRanged;
- }
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindBuildDelayForWeapon
-==============
-*/
-int BG_FindBuildDelayForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].buildDelay;
- }
- }
-
- return 0;
-}
-
-/*
-==============
-BG_FindTeamForWeapon
-==============
-*/
-WUTeam_t BG_FindTeamForWeapon( int weapon )
-{
- int i;
-
- for( i = 0; i < bg_numWeapons; i++ )
- {
- if( bg_weapons[ i ].weaponNum == weapon )
- {
- return bg_weapons[ i ].team;
- }
- }
-
- return WUT_NONE;
+ return stages & ( 1 << stage );
}
////////////////////////////////////////////////////////////////////////////////
-upgradeAttributes_t bg_upgrades[ ] =
+static const upgradeAttributes_t bg_upgrades[ ] =
{
{
- UP_LIGHTARMOUR, //int upgradeNum;
+ UP_LIGHTARMOUR, //int number;
LIGHTARMOUR_PRICE, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_TORSO|SLOT_ARMS|SLOT_LEGS, //int slots;
- "larmour", //char *upgradeName;
- "Light Armour", //char *upgradeHumanName;
+ "larmour", //char *name;
+ "Light Armour", //char *humanName;
+ "Protective armour that helps to defend against light alien melee "
+ "attacks.",
"icons/iconu_larmour",
- qtrue, //qboolean purchasable
- qfalse, //qboolean usable
- WUT_HUMANS //WUTeam_t team;
+ qtrue, //qboolean purchasable;
+ qfalse, //qboolean usable;
+ TEAM_HUMANS //team_t team;
},
{
- UP_HELMET, //int upgradeNum;
+ UP_HELMET, //int number;
HELMET_PRICE, //int price;
- ( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_HEAD, //int slots;
- "helmet", //char *upgradeName;
- "Helmet", //char *upgradeHumanName;
+ "helmet", //char *name;
+ "Helmet", //char *humanName;
+ "In addition to protecting your head, the helmet provides a "
+ "scanner indicating the presence of any friendly or hostile "
+ "lifeforms and structures in your immediate vicinity.",
"icons/iconu_helmet",
- qtrue, //qboolean purchasable
- qfalse, //qboolean usable
- WUT_HUMANS //WUTeam_t team;
+ qtrue, //qboolean purchasable;
+ qfalse, //qboolean usable;
+ TEAM_HUMANS //team_t team;
},
{
- UP_MEDKIT, //int upgradeNum;
+ UP_MEDKIT, //int number;
MEDKIT_PRICE, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_NONE, //int slots;
- "medkit", //char *upgradeName;
- "Medkit", //char *upgradeHumanName;
+ "medkit", //char *name;
+ "Medkit", //char *humanName;
+ "",
"icons/iconu_atoxin",
- qfalse, //qboolean purchasable
- qtrue, //qboolean usable
- WUT_HUMANS //WUTeam_t team;
+ qfalse, //qboolean purchasable;
+ qtrue, //qboolean usable;
+ TEAM_HUMANS //team_t team;
},
{
- UP_BATTPACK, //int upgradeNum;
+ UP_BATTPACK, //int number;
BATTPACK_PRICE, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_BACKPACK, //int slots;
- "battpack", //char *upgradeName;
- "Battery Pack", //char *upgradeHumanName;
+ "battpack", //char *name;
+ "Battery Pack", //char *humanName;
+ "Back-mounted battery pack that permits storage of one and a half "
+ "times the normal energy capacity for energy weapons.",
"icons/iconu_battpack",
- qtrue, //qboolean purchasable
- qfalse, //qboolean usable
- WUT_HUMANS //WUTeam_t team;
+ qtrue, //qboolean purchasable;
+ qfalse, //qboolean usable;
+ TEAM_HUMANS //team_t team;
},
{
- UP_JETPACK, //int upgradeNum;
+ UP_JETPACK, //int number;
JETPACK_PRICE, //int price;
- ( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_BACKPACK, //int slots;
- "jetpack", //char *upgradeName;
- "Jet Pack", //char *upgradeHumanName;
+ "jetpack", //char *name;
+ "Jet Pack", //char *humanName;
+ "Back-mounted jet pack that enables the user to fly to remote "
+ "locations. It is very useful against alien spawns in hard "
+ "to reach spots.",
"icons/iconu_jetpack",
- qtrue, //qboolean purchasable
- qtrue, //qboolean usable
- WUT_HUMANS //WUTeam_t team;
+ qtrue, //qboolean purchasable;
+ qtrue, //qboolean usable;
+ TEAM_HUMANS //team_t team;
},
{
- UP_BATTLESUIT, //int upgradeNum;
+ UP_BATTLESUIT, //int number;
BSUIT_PRICE, //int price;
- ( 1 << S3 ), //int stages
- SLOT_HEAD|SLOT_TORSO|SLOT_ARMS|SLOT_LEGS|SLOT_BACKPACK, //int slots;
- "bsuit", //char *upgradeName;
- "Battlesuit", //char *upgradeHumanName;
+ ( 1 << S3 ), //int stages;
+ SLOT_HEAD|SLOT_TORSO|SLOT_ARMS|SLOT_LEGS|SLOT_BACKPACK, //int slots;
+ "bsuit", //char *name;
+ "Battlesuit", //char *humanName;
+ "A full body armour that is highly effective at repelling alien attacks. "
+ "It allows the user to enter hostile situations with a greater degree "
+ "of confidence.",
"icons/iconu_bsuit",
- qtrue, //qboolean purchasable
- qfalse, //qboolean usable
- WUT_HUMANS //WUTeam_t team;
+ qtrue, //qboolean purchasable;
+ qfalse, //qboolean usable;
+ TEAM_HUMANS //team_t team;
},
{
- UP_GRENADE, //int upgradeNum;
+ UP_GRENADE, //int number;
GRENADE_PRICE, //int price;
- ( 1 << S2 )|( 1 << S3 ),//int stages
+ ( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_NONE, //int slots;
- "gren", //char *upgradeName;
- "Grenade", //char *upgradeHumanName;
+ "gren", //char *name;
+ "Grenade", //char *humanName;
+ "A small incendinary device ideal for damaging tightly packed "
+ "alien structures. Has a five second timer.",
0,
- qtrue, //qboolean purchasable
- qtrue, //qboolean usable
- WUT_HUMANS //WUTeam_t team;
+ qtrue, //qboolean purchasable;
+ qtrue, //qboolean usable;
+ TEAM_HUMANS //team_t team;
},
{
- UP_AMMO, //int upgradeNum;
+ UP_AMMO, //int number;
0, //int price;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages;
SLOT_NONE, //int slots;
- "ammo", //char *upgradeName;
- "Ammunition", //char *upgradeHumanName;
+ "ammo", //char *name;
+ "Ammunition", //char *humanName;
+ "Ammunition for the currently held weapon.",
0,
- qtrue, //qboolean purchasable
- qfalse, //qboolean usable
- WUT_HUMANS //WUTeam_t team;
+ qtrue, //qboolean purchasable;
+ qfalse, //qboolean usable;
+ TEAM_HUMANS //team_t team;
}
};
-int bg_numUpgrades = sizeof( bg_upgrades ) / sizeof( bg_upgrades[ 0 ] );
-
-/*
-==============
-BG_FindPriceForUpgrade
-==============
-*/
-int BG_FindPriceForUpgrade( int upgrade )
-{
- int i;
-
- for( i = 0; i < bg_numUpgrades; i++ )
- {
- if( bg_upgrades[ i ].upgradeNum == upgrade )
- {
- return bg_upgrades[ i ].price;
- }
- }
+size_t bg_numUpgrades = ARRAY_LEN( bg_upgrades );
- return 100;
-}
+static const upgradeAttributes_t nullUpgrade = { 0 };
/*
==============
-BG_FindStagesForUpgrade
+BG_UpgradeByName
==============
*/
-qboolean BG_FindStagesForUpgrade( int upgrade, stage_t stage )
+const upgradeAttributes_t *BG_UpgradeByName( const char *name )
{
int i;
for( i = 0; i < bg_numUpgrades; i++ )
{
- if( bg_upgrades[ i ].upgradeNum == upgrade )
+ if( !Q_stricmp( bg_upgrades[ i ].name, name ) )
{
- if( bg_upgrades[ i ].stages & ( 1 << stage ) )
- return qtrue;
- else
- return qfalse;
+ return &bg_upgrades[ i ];
}
}
- return qfalse;
+ return &nullUpgrade;
}
/*
==============
-BG_FindSlotsForUpgrade
+BG_Upgrade
==============
*/
-int BG_FindSlotsForUpgrade( int upgrade )
+const upgradeAttributes_t *BG_Upgrade( upgrade_t upgrade )
{
- int i;
-
- for( i = 0; i < bg_numUpgrades; i++ )
- {
- if( bg_upgrades[ i ].upgradeNum == upgrade )
- {
- return bg_upgrades[ i ].slots;
- }
- }
-
- return SLOT_NONE;
+ return ( upgrade > UP_NONE && upgrade < UP_NUM_UPGRADES ) ?
+ &bg_upgrades[ upgrade - 1 ] : &nullUpgrade;
}
/*
==============
-BG_FindNameForUpgrade
+BG_UpgradeAllowedInStage
==============
*/
-char *BG_FindNameForUpgrade( int upgrade )
+qboolean BG_UpgradeAllowedInStage( upgrade_t upgrade, stage_t stage )
{
- int i;
-
- for( i = 0; i < bg_numUpgrades; i++ )
- {
- if( bg_upgrades[ i ].upgradeNum == upgrade )
- return bg_upgrades[ i ].upgradeName;
- }
+ int stages = BG_Upgrade( upgrade )->stages;
- //wimp out
- return 0;
-}
-
-/*
-==============
-BG_FindUpgradeNumForName
-==============
-*/
-int BG_FindUpgradeNumForName( char *name )
-{
- int i;
-
- for( i = 0; i < bg_numUpgrades; i++ )
- {
- if( !Q_stricmp( bg_upgrades[ i ].upgradeName, name ) )
- return bg_upgrades[ i ].upgradeNum;
- }
-
- //wimp out
- return UP_NONE;
-}
-
-/*
-==============
-BG_FindHumanNameForUpgrade
-==============
-*/
-char *BG_FindHumanNameForUpgrade( int upgrade )
-{
- int i;
-
- for( i = 0; i < bg_numUpgrades; i++ )
- {
- if( bg_upgrades[ i ].upgradeNum == upgrade )
- return bg_upgrades[ i ].upgradeHumanName;
- }
-
- //wimp out
- return 0;
-}
-
-/*
-==============
-BG_FindIconForUpgrade
-==============
-*/
-char *BG_FindIconForUpgrade( int upgrade )
-{
- int i;
-
- for( i = 0; i < bg_numUpgrades; i++ )
- {
- if( bg_upgrades[ i ].upgradeNum == upgrade )
- return bg_upgrades[ i ].icon;
- }
-
- //wimp out
- return 0;
-}
-
-/*
-==============
-BG_FindPurchasableForUpgrade
-==============
-*/
-qboolean BG_FindPurchasableForUpgrade( int upgrade )
-{
- int i;
-
- for( i = 0; i < bg_numUpgrades; i++ )
- {
- if( bg_upgrades[ i ].upgradeNum == upgrade )
- return bg_upgrades[ i ].purchasable;
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindUsableForUpgrade
-==============
-*/
-qboolean BG_FindUsableForUpgrade( int upgrade )
-{
- int i;
-
- for( i = 0; i < bg_numUpgrades; i++ )
- {
- if( bg_upgrades[ i ].upgradeNum == upgrade )
- return bg_upgrades[ i ].usable;
- }
-
- return qfalse;
-}
-
-/*
-==============
-BG_FindTeamForUpgrade
-==============
-*/
-WUTeam_t BG_FindTeamForUpgrade( int upgrade )
-{
- int i;
-
- for( i = 0; i < bg_numUpgrades; i++ )
- {
- if( bg_upgrades[ i ].upgradeNum == upgrade )
- {
- return bg_upgrades[ i ].team;
- }
- }
-
- return WUT_NONE;
+ return stages & ( 1 << stage );
}
////////////////////////////////////////////////////////////////////////////////
@@ -4574,12 +2677,12 @@ void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t resu
case TR_SINE:
deltaTime = ( atTime - tr->trTime ) / (float)tr->trDuration;
phase = cos( deltaTime * M_PI * 2 ); // derivative of sin = cos
- phase *= 0.5;
+ phase *= 2 * M_PI * 1000 / (float)tr->trDuration;
VectorScale( tr->trDelta, phase, result );
break;
case TR_LINEAR_STOP:
- if( atTime > tr->trTime + tr->trDuration )
+ if( atTime > tr->trTime + tr->trDuration || atTime < tr->trTime )
{
VectorClear( result );
return;
@@ -4643,7 +2746,7 @@ char *eventnames[ ] =
"EV_FIRE_WEAPON2",
"EV_FIRE_WEAPON3",
- "EV_PLAYER_RESPAWN", //TA: for fovwarp effects
+ "EV_PLAYER_RESPAWN", // for fovwarp effects
"EV_PLAYER_TELEPORT_IN",
"EV_PLAYER_TELEPORT_OUT",
@@ -4656,6 +2759,7 @@ char *eventnames[ ] =
"EV_BULLET_HIT_WALL",
"EV_SHOTGUN",
+ "EV_MASS_DRIVER",
"EV_MISSILE_HIT",
"EV_MISSILE_MISS",
@@ -4664,8 +2768,8 @@ char *eventnames[ ] =
"EV_BULLET", // otherEntity is the shooter
"EV_LEV1_GRAB",
- "EV_LEV4_CHARGE_PREPARE",
- "EV_LEV4_CHARGE_START",
+ "EV_LEV4_TRAMPLE_PREPARE",
+ "EV_LEV4_TRAMPLE_START",
"EV_PAIN",
"EV_DEATH1",
@@ -4673,13 +2777,13 @@ char *eventnames[ ] =
"EV_DEATH3",
"EV_OBITUARY",
- "EV_GIB_PLAYER", // gib a previously living player
+ "EV_GIB_PLAYER",
- "EV_BUILD_CONSTRUCT", //TA
- "EV_BUILD_DESTROY", //TA
- "EV_BUILD_DELAY", //TA: can't build yet
- "EV_BUILD_REPAIR", //TA: repairing buildable
- "EV_BUILD_REPAIRED", //TA: buildable has full health
+ "EV_BUILD_CONSTRUCT",
+ "EV_BUILD_DESTROY",
+ "EV_BUILD_DELAY", // can't build yet
+ "EV_BUILD_REPAIR", // repairing buildable
+ "EV_BUILD_REPAIRED", // buildable has full health
"EV_HUMAN_BUILDABLE_EXPLOSION",
"EV_ALIEN_BUILDABLE_EXPLOSION",
"EV_ALIEN_ACIDTUBE",
@@ -4693,17 +2797,33 @@ char *eventnames[ ] =
"EV_STOPLOOPINGSOUND",
"EV_TAUNT",
- "EV_OVERMIND_ATTACK", //TA: overmind under attack
- "EV_OVERMIND_DYING", //TA: overmind close to death
- "EV_OVERMIND_SPAWNS", //TA: overmind needs spawns
+ "EV_OVERMIND_ATTACK", // overmind under attack
+ "EV_OVERMIND_DYING", // overmind close to death
+ "EV_OVERMIND_SPAWNS", // overmind needs spawns
+
+ "EV_DCC_ATTACK", // dcc under attack
- "EV_DCC_ATTACK", //TA: dcc under attack
+ "EV_MGTURRET_SPINUP", // trigger a sound
- "EV_RPTUSE_SOUND" //TA: trigger a sound
+ "EV_RPTUSE_SOUND", // trigger a sound
+ "EV_LEV2_ZAP"
};
/*
===============
+BG_EventName
+===============
+*/
+const char *BG_EventName( int num )
+{
+ if( num < 0 || num >= ARRAY_LEN( eventnames ) )
+ return "UNKNOWN";
+
+ return eventnames[ num ];
+}
+
+/*
+===============
BG_AddPredictableEventToPlayerstate
Handles the sequence numbers
@@ -4714,19 +2834,21 @@ void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bu
void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps )
{
-#ifdef _DEBUG
+#ifdef DEBUG_EVENTS
{
char buf[ 256 ];
trap_Cvar_VariableStringBuffer( "showevents", buf, sizeof( buf ) );
if( atof( buf ) != 0 )
{
-#ifdef QAGAME
+#ifdef GAME
Com_Printf( " game event svt %5d -> %5d: num = %20s parm %d\n",
- ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[ newEvent ], eventParm);
+ ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence,
+ BG_EventName( newEvent ), eventParm );
#else
Com_Printf( "Cgame event svt %5d -> %5d: num = %20s parm %d\n",
- ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[ newEvent ], eventParm);
+ ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence,
+ BG_EventName( newEvent ), eventParm );
#endif
}
}
@@ -4751,7 +2873,7 @@ void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean
if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR || ps->pm_type == PM_FREEZE )
s->eType = ET_INVISIBLE;
- else if( ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
+ else if( ps->persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
s->eType = ET_INVISIBLE;
else
s->eType = ET_PLAYER;
@@ -4773,11 +2895,10 @@ void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean
if( snap )
SnapVector( s->apos.trBase );
- //TA: i need for other things :)
- //s->angles2[YAW] = ps->movementDir;
s->time2 = ps->movementDir;
s->legsAnim = ps->legsAnim;
s->torsoAnim = ps->torsoAnim;
+ s->weaponAnim = ps->weaponAnim;
s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number
// so corpses can also reference the proper config
s->eFlags = ps->eFlags;
@@ -4827,12 +2948,10 @@ void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean
}
// use misc field to store team/class info:
- s->misc = ps->stats[ STAT_PTEAM ] | ( ps->stats[ STAT_PCLASS ] << 8 );
+ s->misc = ps->stats[ STAT_TEAM ] | ( ps->stats[ STAT_CLASS ] << 8 );
- //TA: have to get the surfNormal thru somehow...
+ // have to get the surfNormal through somehow...
VectorCopy( ps->grapplePoint, s->angles2 );
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- s->eFlags |= EF_WALLCLIMBCEILING;
s->loopSound = ps->loopSound;
s->generic1 = ps->generic1;
@@ -4840,7 +2959,7 @@ void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean
if( s->generic1 <= WPM_NONE || s->generic1 >= WPM_NUM_WEAPONMODES )
s->generic1 = WPM_PRIMARY;
- s->otherEntityNum = ps->otherEntityNum;
+ s->otherEntityNum = ps->otherEntityNum;
}
@@ -4858,7 +2977,7 @@ void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s
if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR || ps->pm_type == PM_FREEZE )
s->eType = ET_INVISIBLE;
- else if( ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
+ else if( ps->persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
s->eType = ET_INVISIBLE;
else
s->eType = ET_PLAYER;
@@ -4883,11 +3002,10 @@ void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s
if( snap )
SnapVector( s->apos.trBase );
- //TA: i need for other things :)
- //s->angles2[YAW] = ps->movementDir;
s->time2 = ps->movementDir;
s->legsAnim = ps->legsAnim;
s->torsoAnim = ps->torsoAnim;
+ s->weaponAnim = ps->weaponAnim;
s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number
// so corpses can also reference the proper config
s->eFlags = ps->eFlags;
@@ -4939,12 +3057,10 @@ void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s
}
// use misc field to store team/class info:
- s->misc = ps->stats[ STAT_PTEAM ] | ( ps->stats[ STAT_PCLASS ] << 8 );
+ s->misc = ps->stats[ STAT_TEAM ] | ( ps->stats[ STAT_CLASS ] << 8 );
- //TA: have to get the surfNormal thru somehow...
+ // have to get the surfNormal through somehow...
VectorCopy( ps->grapplePoint, s->angles2 );
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- s->eFlags |= EF_WALLCLIMBCEILING;
s->loopSound = ps->loopSound;
s->generic1 = ps->generic1;
@@ -4966,7 +3082,8 @@ qboolean BG_WeaponIsFull( weapon_t weapon, int stats[ ], int ammo, int clips )
{
int maxAmmo, maxClips;
- BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips );
+ maxAmmo = BG_Weapon( weapon )->maxAmmo;
+ maxClips = BG_Weapon( weapon )->maxClips;
if( BG_InventoryContainsUpgrade( UP_BATTPACK, stats ) )
maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
@@ -4976,63 +3093,53 @@ qboolean BG_WeaponIsFull( weapon_t weapon, int stats[ ], int ammo, int clips )
/*
========================
-BG_AddWeaponToInventory
+BG_InventoryContainsWeapon
-Give a player a weapon
+Does the player hold a weapon?
========================
*/
-void BG_AddWeaponToInventory( int weapon, int stats[ ] )
+qboolean BG_InventoryContainsWeapon( int weapon, int stats[ ] )
{
- int weaponList;
-
- weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 );
-
- weaponList |= ( 1 << weapon );
-
- stats[ STAT_WEAPONS ] = weaponList & 0x0000FFFF;
- stats[ STAT_WEAPONS2 ] = ( weaponList & 0xFFFF0000 ) >> 16;
-
- if( stats[ STAT_SLOTS ] & BG_FindSlotsForWeapon( weapon ) )
- Com_Printf( S_COLOR_YELLOW "WARNING: Held items conflict with weapon %d\n", weapon );
+ // humans always have a blaster
+ if( stats[ STAT_TEAM ] == TEAM_HUMANS && weapon == WP_BLASTER )
+ return qtrue;
- stats[ STAT_SLOTS ] |= BG_FindSlotsForWeapon( weapon );
+ return ( stats[ STAT_WEAPON ] == weapon );
}
/*
========================
-BG_RemoveWeaponToInventory
+BG_SlotsForInventory
-Take a weapon from a player
+Calculate the slots used by an inventory and warn of conflicts
========================
*/
-void BG_RemoveWeaponFromInventory( int weapon, int stats[ ] )
+int BG_SlotsForInventory( int stats[ ] )
{
- int weaponList;
+ int i, slot, slots;
- weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 );
+ slots = BG_Weapon( stats[ STAT_WEAPON ] )->slots;
+ if( stats[ STAT_TEAM ] == TEAM_HUMANS )
+ slots |= BG_Weapon( WP_BLASTER )->slots;
- weaponList &= ~( 1 << weapon );
-
- stats[ STAT_WEAPONS ] = weaponList & 0x0000FFFF;
- stats[ STAT_WEAPONS2 ] = ( weaponList & 0xFFFF0000 ) >> 16;
-
- stats[ STAT_SLOTS ] &= ~BG_FindSlotsForWeapon( weapon );
-}
-
-/*
-========================
-BG_InventoryContainsWeapon
+ for( i = UP_NONE; i < UP_NUM_UPGRADES; i++ )
+ {
+ if( BG_InventoryContainsUpgrade( i, stats ) )
+ {
+ slot = BG_Upgrade( i )->slots;
-Does the player hold a weapon?
-========================
-*/
-qboolean BG_InventoryContainsWeapon( int weapon, int stats[ ] )
-{
- int weaponList;
+ // this check should never be true
+ if( slots & slot )
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: held item %d conflicts with "
+ "inventory slot %d\n", i, slot );
+ }
- weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 );
+ slots |= slot;
+ }
+ }
- return( weaponList & ( 1 << weapon ) );
+ return slots;
}
/*
@@ -5045,11 +3152,6 @@ Give the player an upgrade
void BG_AddUpgradeToInventory( int item, int stats[ ] )
{
stats[ STAT_ITEMS ] |= ( 1 << item );
-
- if( stats[ STAT_SLOTS ] & BG_FindSlotsForUpgrade( item ) )
- Com_Printf( S_COLOR_YELLOW "WARNING: Held items conflict with upgrade %d\n", item );
-
- stats[ STAT_SLOTS ] |= BG_FindSlotsForUpgrade( item );
}
/*
@@ -5062,8 +3164,6 @@ Take an upgrade from the player
void BG_RemoveUpgradeFromInventory( int item, int stats[ ] )
{
stats[ STAT_ITEMS ] &= ~( 1 << item );
-
- stats[ STAT_SLOTS ] &= ~BG_FindSlotsForUpgrade( item );
}
/*
@@ -5166,6 +3266,40 @@ qboolean BG_RotateAxis( vec3_t surfNormal, vec3_t inAxis[ 3 ],
/*
===============
+BG_GetClientNormal
+
+Get the normal for the surface the client is walking on
+===============
+*/
+void BG_GetClientNormal( const playerState_t *ps, vec3_t normal )
+{
+ if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
+ {
+ if( ps->eFlags & EF_WALLCLIMBCEILING )
+ VectorSet( normal, 0.0f, 0.0f, -1.0f );
+ else
+ VectorCopy( ps->grapplePoint, normal );
+ }
+ else
+ VectorSet( normal, 0.0f, 0.0f, 1.0f );
+}
+
+/*
+===============
+BG_GetClientViewOrigin
+
+Get the position of the client's eye, based on the client's position, the surface's normal, and client's view height
+===============
+*/
+void BG_GetClientViewOrigin( const playerState_t *ps, vec3_t viewOrigin )
+{
+ vec3_t normal;
+ BG_GetClientNormal( ps, normal );
+ VectorMA( ps->origin, ps->viewheight, normal, viewOrigin );
+}
+
+/*
+===============
BG_PositionBuildableRelativeToPlayer
Find a place to build a buildable
@@ -5181,19 +3315,11 @@ void BG_PositionBuildableRelativeToPlayer( const playerState_t *ps,
vec3_t angles, playerOrigin, playerNormal;
float buildDist;
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- {
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- VectorSet( playerNormal, 0.0f, 0.0f, -1.0f );
- else
- VectorCopy( ps->grapplePoint, playerNormal );
- }
- else
- VectorSet( playerNormal, 0.0f, 0.0f, 1.0f );
+ BG_GetClientNormal( ps, playerNormal );
VectorCopy( ps->viewangles, angles );
VectorCopy( ps->origin, playerOrigin );
- buildDist = BG_FindBuildDistForClass( ps->stats[ STAT_PCLASS ] );
+ buildDist = BG_Class( ps->stats[ STAT_CLASS ] )->buildDist;
AngleVectors( angles, forward, NULL, NULL );
ProjectPointOnPlane( forward, forward, playerNormal );
@@ -5209,54 +3335,90 @@ void BG_PositionBuildableRelativeToPlayer( const playerState_t *ps,
//so buildings drop to floor
VectorMA( targetOrigin, -128, playerNormal, targetOrigin );
- (*trace)( tr, entityOrigin, mins, maxs, targetOrigin, ps->clientNum, MASK_PLAYERSOLID );
- VectorCopy( tr->endpos, entityOrigin );
- VectorMA( entityOrigin, 0.1f, playerNormal, outOrigin );
+ // The mask is MASK_DEADSOLID on purpose to avoid collisions with other entities
+ (*trace)( tr, entityOrigin, mins, maxs, targetOrigin, ps->clientNum, MASK_DEADSOLID );
+ VectorCopy( tr->endpos, outOrigin );
vectoangles( forward, outAngles );
}
/*
===============
-BG_GetValueOfEquipment
+BG_GetValueOfPlayer
-Returns the equipment value of some human player's gear
+Returns the credit value of a player
===============
*/
- int BG_GetValueOfEquipment( playerState_t *ps ) {
- int i, worth = 0;
+int BG_GetValueOfPlayer( playerState_t *ps )
+{
+ int worth = 0;
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- {
- if( BG_InventoryContainsUpgrade( i, ps->stats ) )
- worth += BG_FindPriceForUpgrade( i );
- }
+ worth = BG_Class( ps->stats[ STAT_CLASS ] )->value;
- for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
+ // Humans have worth from their equipment as well
+ if( ps->stats[ STAT_TEAM ] == TEAM_HUMANS )
{
- if( BG_InventoryContainsWeapon( i, ps->stats ) )
- worth += BG_FindPriceForWeapon( i );
- }
+ upgrade_t i;
+ for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
+ {
+ if( BG_InventoryContainsUpgrade( i, ps->stats ) )
+ worth += BG_Upgrade( i )->price;
+ }
- return worth;
+ if( ps->stats[ STAT_WEAPON ] != WP_NONE )
+ worth += BG_Weapon( ps->stats[ STAT_WEAPON ] )->price;
}
+
+ return worth;
+}
+
/*
-===============
-BG_GetValueOfHuman
+=================
+BG_PlayerCanChangeWeapon
+=================
+*/
+qboolean BG_PlayerCanChangeWeapon( playerState_t *ps )
+{
+ // Do not allow Lucifer Cannon "canceling" via weapon switch
+ if( ps->weapon == WP_LUCIFER_CANNON &&
+ ps->stats[ STAT_MISC ] > LCANNON_CHARGE_TIME_MIN )
+ return qfalse;
-Returns the kills value of some human player
-===============
+ return ps->weaponTime <= 0 || ps->weaponstate != WEAPON_FIRING;
+}
+
+/*
+=================
+BG_PlayerPoisonCloudTime
+=================
*/
-int BG_GetValueOfHuman( playerState_t *ps )
+int BG_PlayerPoisonCloudTime( playerState_t *ps )
{
- float portion = BG_GetValueOfEquipment( ps ) / (float)HUMAN_MAXED;
+ int time = LEVEL1_PCLOUD_TIME;
+ if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, ps->stats ) )
+ time -= BSUIT_PCLOUD_PROTECTION;
+ if( BG_InventoryContainsUpgrade( UP_HELMET, ps->stats ) )
+ time -= HELMET_PCLOUD_PROTECTION;
+ if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, ps->stats ) )
+ time -= LIGHTARMOUR_PCLOUD_PROTECTION;
+
+ return time;
+}
+
+/*
+=================
+BG_GetPlayerWeapon
- if( portion < 0.01f )
- portion = 0.01f;
- else if( portion > 1.0f )
- portion = 1.0f;
+Returns the players current weapon or the weapon they are switching to.
+Only needs to be used for human weapons.
+=================
+*/
+weapon_t BG_GetPlayerWeapon( playerState_t *ps )
+{
+ if( ps->persistant[ PERS_NEWWEAPON ] )
+ return ps->persistant[ PERS_NEWWEAPON ];
- return ceil( ALIEN_MAX_SINGLE_KILLS * portion );
+ return ps->weapon;
}
/*
@@ -5297,6 +3459,103 @@ int atoi_neg( char *token, qboolean allowNegative )
return value;
}
+#define MAX_NUM_PACKED_ENTITY_NUMS 10
+
+/*
+===============
+BG_PackEntityNumbers
+
+Pack entity numbers into an entityState_t
+===============
+*/
+void BG_PackEntityNumbers( entityState_t *es, const int *entityNums, int count )
+{
+ int i;
+
+ if( count > MAX_NUM_PACKED_ENTITY_NUMS )
+ {
+ count = MAX_NUM_PACKED_ENTITY_NUMS;
+ Com_Printf( S_COLOR_YELLOW "WARNING: A maximum of %d entity numbers can be "
+ "packed, but BG_PackEntityNumbers was passed %d entities",
+ MAX_NUM_PACKED_ENTITY_NUMS, count );
+ }
+
+ es->misc = es->time = es->time2 = es->constantLight = 0;
+
+ for( i = 0; i < MAX_NUM_PACKED_ENTITY_NUMS; i++ )
+ {
+ int entityNum;
+
+ if( i < count )
+ entityNum = entityNums[ i ];
+ else
+ entityNum = ENTITYNUM_NONE;
+
+ if( entityNum & ~GENTITYNUM_MASK )
+ {
+ Com_Error( ERR_FATAL, "BG_PackEntityNumbers passed an entity number (%d) which "
+ "exceeds %d bits", entityNum, GENTITYNUM_BITS );
+ }
+
+ switch( i )
+ {
+ case 0: es->misc |= entityNum; break;
+ case 1: es->time |= entityNum; break;
+ case 2: es->time |= entityNum << GENTITYNUM_BITS; break;
+ case 3: es->time |= entityNum << (GENTITYNUM_BITS * 2); break;
+ case 4: es->time2 |= entityNum; break;
+ case 5: es->time2 |= entityNum << GENTITYNUM_BITS; break;
+ case 6: es->time2 |= entityNum << (GENTITYNUM_BITS * 2); break;
+ case 7: es->constantLight |= entityNum; break;
+ case 8: es->constantLight |= entityNum << GENTITYNUM_BITS; break;
+ case 9: es->constantLight |= entityNum << (GENTITYNUM_BITS * 2); break;
+ default: Com_Error( ERR_FATAL, "Entity index %d not handled", i ); break;
+ }
+ }
+}
+
+/*
+===============
+BG_UnpackEntityNumbers
+
+Unpack entity numbers from an entityState_t
+===============
+*/
+int BG_UnpackEntityNumbers( entityState_t *es, int *entityNums, int count )
+{
+ int i;
+
+ if( count > MAX_NUM_PACKED_ENTITY_NUMS )
+ count = MAX_NUM_PACKED_ENTITY_NUMS;
+
+ for( i = 0; i < count; i++ )
+ {
+ int *entityNum = &entityNums[ i ];
+
+ switch( i )
+ {
+ case 0: *entityNum = es->misc; break;
+ case 1: *entityNum = es->time; break;
+ case 2: *entityNum = (es->time >> GENTITYNUM_BITS); break;
+ case 3: *entityNum = (es->time >> (GENTITYNUM_BITS * 2)); break;
+ case 4: *entityNum = es->time2; break;
+ case 5: *entityNum = (es->time2 >> GENTITYNUM_BITS); break;
+ case 6: *entityNum = (es->time2 >> (GENTITYNUM_BITS * 2)); break;
+ case 7: *entityNum = es->constantLight; break;
+ case 8: *entityNum = (es->constantLight >> GENTITYNUM_BITS); break;
+ case 9: *entityNum = (es->constantLight >> (GENTITYNUM_BITS * 2)); break;
+ default: Com_Error( ERR_FATAL, "Entity index %d not handled", i ); break;
+ }
+
+ *entityNum &= GENTITYNUM_MASK;
+
+ if( *entityNum == ENTITYNUM_NONE )
+ break;
+ }
+
+ return i;
+}
+
/*
===============
BG_ParseCSVEquipmentList
@@ -5330,10 +3589,10 @@ void BG_ParseCSVEquipmentList( const char *string, weapon_t *weapons, int weapon
q++;
if( weaponsSize )
- weapons[ i ] = BG_FindWeaponNumForName( q );
+ weapons[ i ] = BG_WeaponByName( q )->number;
if( upgradesSize )
- upgrades[ j ] = BG_FindUpgradeNumForName( q );
+ upgrades[ j ] = BG_UpgradeByName( q )->number;
if( weaponsSize && weapons[ i ] == WP_NONE &&
upgradesSize && upgrades[ j ] == UP_NONE )
@@ -5367,7 +3626,7 @@ void BG_ParseCSVEquipmentList( const char *string, weapon_t *weapons, int weapon
BG_ParseCSVClassList
===============
*/
-void BG_ParseCSVClassList( const char *string, pClass_t *classes, int classesSize )
+void BG_ParseCSVClassList( const char *string, class_t *classes, int classesSize )
{
char buffer[ MAX_STRING_CHARS ];
int i = 0;
@@ -5378,7 +3637,7 @@ void BG_ParseCSVClassList( const char *string, pClass_t *classes, int classesSiz
p = q = buffer;
- while( *p != '\0' )
+ while( *p != '\0' && i < classesSize - 1 )
{
//skip to first , or EOS
while( *p != ',' && *p != '\0' )
@@ -5393,7 +3652,7 @@ void BG_ParseCSVClassList( const char *string, pClass_t *classes, int classesSiz
while( *q == ' ' )
q++;
- classes[ i ] = BG_FindClassNumForName( q );
+ classes[ i ] = BG_ClassByName( q )->number;
if( classes[ i ] == PCL_NONE )
Com_Printf( S_COLOR_YELLOW "WARNING: unknown class %s\n", q );
@@ -5428,7 +3687,7 @@ void BG_ParseCSVBuildableList( const char *string, buildable_t *buildables, int
p = q = buffer;
- while( *p != '\0' )
+ while( *p != '\0' && i < buildablesSize - 1 )
{
//skip to first , or EOS
while( *p != ',' && *p != '\0' )
@@ -5443,7 +3702,7 @@ void BG_ParseCSVBuildableList( const char *string, buildable_t *buildables, int
while( *q == ' ' )
q++;
- buildables[ i ] = BG_FindBuildNumForName( q );
+ buildables[ i ] = BG_BuildableByName( q )->number;
if( buildables[ i ] == BA_NONE )
Com_Printf( S_COLOR_YELLOW "WARNING: unknown buildable %s\n", q );
@@ -5462,38 +3721,10 @@ void BG_ParseCSVBuildableList( const char *string, buildable_t *buildables, int
buildables[ i ] = BA_NONE;
}
-/*
-============
-BG_UpgradeClassAvailable
-============
-*/
-qboolean BG_UpgradeClassAvailable( playerState_t *ps )
-{
- int i;
- char buffer[ MAX_STRING_CHARS ];
- stage_t currentStage;
-
- trap_Cvar_VariableStringBuffer( "g_alienStage", buffer, MAX_STRING_CHARS );
- currentStage = atoi( buffer );
-
- for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ )
- {
- if( BG_ClassCanEvolveFromTo( ps->stats[ STAT_PCLASS ], i,
- ps->persistant[ PERS_CREDIT ], 0 ) >= 0 &&
- BG_FindStagesForClass( i, currentStage ) &&
- BG_ClassIsAllowed( i ) )
- {
- return qtrue;
- }
- }
-
- return qfalse;
-}
-
typedef struct gameElements_s
{
buildable_t buildables[ BA_NUM_BUILDABLES ];
- pClass_t classes[ PCL_NUM_CLASSES ];
+ class_t classes[ PCL_NUM_CLASSES ];
weapon_t weapons[ WP_NUM_WEAPONS ];
upgrade_t upgrades[ UP_NUM_UPGRADES ];
} gameElements_t;
@@ -5572,7 +3803,7 @@ qboolean BG_UpgradeIsAllowed( upgrade_t upgrade )
BG_ClassIsAllowed
============
*/
-qboolean BG_ClassIsAllowed( pClass_t class )
+qboolean BG_ClassIsAllowed( class_t class )
{
int i;
@@ -5607,81 +3838,86 @@ qboolean BG_BuildableIsAllowed( buildable_t buildable )
/*
============
-BG_ClientListTest
+BG_LoadEmoticons
============
*/
-qboolean BG_ClientListTest( clientList_t *list, int clientNum )
+int BG_LoadEmoticons( emoticon_t *emoticons, int num )
{
- if( clientNum < 0 || clientNum >= MAX_CLIENTS || !list )
- return qfalse;
- if( clientNum < 32 )
- return ( ( list->lo & ( 1 << clientNum ) ) != 0 );
- else
- return ( ( list->hi & ( 1 << ( clientNum - 32 ) ) ) != 0 );
-}
+ int numFiles;
+ char fileList[ MAX_EMOTICONS * ( MAX_EMOTICON_NAME_LEN + 9 ) ] = {""};
+ int i;
+ char *filePtr;
+ int fileLen;
+ int count;
-/*
-============
-BG_ClientListAdd
-============
-*/
-void BG_ClientListAdd( clientList_t *list, int clientNum )
-{
- if( clientNum < 0 || clientNum >= MAX_CLIENTS || !list )
- return;
- if( clientNum < 32 )
- list->lo |= ( 1 << clientNum );
- else
- list->hi |= ( 1 << ( clientNum - 32 ) );
+ numFiles = trap_FS_GetFileList( "emoticons", "x1.tga", fileList,
+ sizeof( fileList ) );
+
+ if( numFiles < 1 )
+ return 0;
+
+ filePtr = fileList;
+ fileLen = 0;
+ count = 0;
+ for( i = 0; i < numFiles && count < num; i++, filePtr += fileLen + 1 )
+ {
+ fileLen = strlen( filePtr );
+ if( fileLen < 9 || filePtr[ fileLen - 8 ] != '_' ||
+ filePtr[ fileLen - 7 ] < '1' || filePtr[ fileLen - 7 ] > '9' )
+ {
+ Com_Printf( S_COLOR_YELLOW "skipping invalidly named emoticon \"%s\"\n",
+ filePtr );
+ continue;
+ }
+ if( fileLen - 8 > MAX_EMOTICON_NAME_LEN )
+ {
+ Com_Printf( S_COLOR_YELLOW "emoticon file name \"%s\" too long (>%d)\n",
+ filePtr, MAX_EMOTICON_NAME_LEN + 8 );
+ continue;
+ }
+ if( !trap_FS_FOpenFile( va( "emoticons/%s", filePtr ), NULL, FS_READ ) )
+ {
+ Com_Printf( S_COLOR_YELLOW "could not open \"emoticons/%s\"\n", filePtr );
+ continue;
+ }
+
+ Q_strncpyz( emoticons[ count ].name, filePtr, fileLen - 8 + 1 );
+#ifndef GAME
+ emoticons[ count ].width = filePtr[ fileLen - 7 ] - '0';
+#endif
+ count++;
+ }
+
+ Com_Printf( "Loaded %d of %d emoticons (MAX_EMOTICONS is %d)\n",
+ count, numFiles, MAX_EMOTICONS );
+ return count;
}
/*
============
-BG_ClientListRemove
+BG_TeamName
============
*/
-void BG_ClientListRemove( clientList_t *list, int clientNum )
+char *BG_TeamName( team_t team )
{
- if( clientNum < 0 || clientNum >= MAX_CLIENTS || !list )
- return;
- if( clientNum < 32 )
- list->lo &= ~( 1 << clientNum );
- else
- list->hi &= ~( 1 << ( clientNum - 32 ) );
+ if( team == TEAM_NONE )
+ return "spectator";
+ if( team == TEAM_ALIENS )
+ return "alien";
+ if( team == TEAM_HUMANS )
+ return "human";
+ return "<team>";
}
-/*
-============
-BG_ClientListString
-============
-*/
-char *BG_ClientListString( clientList_t *list )
+int cmdcmp( const void *a, const void *b )
{
- static char s[ 17 ];
-
- s[ 0 ] = '\0';
- if( !list )
- return s;
- Com_sprintf( s, sizeof( s ), "%08x%08x", list->hi, list->lo );
- return s;
+ return Q_stricmp( (const char *)a, ((dummyCmd_t *)b)->name );
}
-/*
-============
-BG_ClientListParse
-============
-*/
-void BG_ClientListParse( clientList_t *list, const char *s )
+char *G_CopyString( const char *str )
{
- if( !list )
- return;
- list->lo = 0;
- list->hi = 0;
- if( !s )
- return;
- if( strlen( s ) != 16 )
- return;
- sscanf( s, "%x%x", &list->hi, &list->lo );
+ size_t size = strlen( str ) + 1;
+ char *cp = BG_Alloc( size );
+ memcpy( cp, str, size );
+ return cp;
}
-
-
diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c
index 542b585..c5f2293 100644
--- a/src/game/bg_pmove.c
+++ b/src/game/bg_pmove.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,15 +17,15 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// bg_pmove.c -- both games player movement code
// takes a playerstate and a usercmd as input and returns a modifed playerstate
-#include "../qcommon/q_shared.h"
+#include "qcommon/q_shared.h"
#include "bg_public.h"
#include "bg_local.h"
@@ -35,10 +36,8 @@ pml_t pml;
float pm_stopspeed = 100.0f;
float pm_duckScale = 0.25f;
float pm_swimScale = 0.50f;
-float pm_wadeScale = 0.70f;
float pm_accelerate = 10.0f;
-float pm_airaccelerate = 1.0f;
float pm_wateraccelerate = 4.0f;
float pm_flyaccelerate = 4.0f;
@@ -92,9 +91,9 @@ void PM_AddTouchEnt( int entityNum )
PM_StartTorsoAnim
===================
*/
-static void PM_StartTorsoAnim( int anim )
+void PM_StartTorsoAnim( int anim )
{
- if( pm->ps->pm_type >= PM_DEAD )
+ if( PM_Paralyzed( pm->ps->pm_type ) )
return;
pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
@@ -103,12 +102,26 @@ static void PM_StartTorsoAnim( int anim )
/*
===================
+PM_StartWeaponAnim
+===================
+*/
+static void PM_StartWeaponAnim( int anim )
+{
+ if( PM_Paralyzed( pm->ps->pm_type ) )
+ return;
+
+ pm->ps->weaponAnim = ( ( pm->ps->weaponAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
+ | anim;
+}
+
+/*
+===================
PM_StartLegsAnim
===================
*/
static void PM_StartLegsAnim( int anim )
{
- if( pm->ps->pm_type >= PM_DEAD )
+ if( PM_Paralyzed( pm->ps->pm_type ) )
return;
//legsTimer is clamped too tightly for nonsegmented models
@@ -170,6 +183,19 @@ static void PM_ContinueTorsoAnim( int anim )
/*
===================
+PM_ContinueWeaponAnim
+===================
+*/
+static void PM_ContinueWeaponAnim( int anim )
+{
+ if( ( pm->ps->weaponAnim & ~ANIM_TOGGLEBIT ) == anim )
+ return;
+
+ PM_StartWeaponAnim( anim );
+}
+
+/*
+===================
PM_ForceLegsAnim
===================
*/
@@ -192,29 +218,10 @@ PM_ClipVelocity
Slide off of the impacting surface
==================
*/
-void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce )
+void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out )
{
- float backoff;
- float change;
- int i;
-
- backoff = DotProduct( in, normal );
-
- //Com_Printf( "%1.0f ", backoff );
-
- if( backoff < 0 )
- backoff *= overbounce;
- else
- backoff /= overbounce;
-
- for( i = 0; i < 3; i++ )
- {
- change = normal[ i ] * backoff;
- //Com_Printf( "%1.0f ", change );
- out[ i ] = in[ i ] - change;
- }
-
- //Com_Printf( " " );
+ float t = -DotProduct( in, normal );
+ VectorMA( in, t, normal, out );
}
@@ -234,20 +241,15 @@ static void PM_Friction( void )
vel = pm->ps->velocity;
- //TA: make sure vertical velocity is NOT set to zero when wall climbing
+ // make sure vertical velocity is NOT set to zero when wall climbing
VectorCopy( vel, vec );
if( pml.walking && !( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) )
vec[ 2 ] = 0; // ignore slope movement
speed = VectorLength( vec );
- if( speed < 1 )
- {
- vel[ 0 ] = 0;
- vel[ 1 ] = 0; // allow sinking underwater
- // FIXME: still have z friction underwater?
+ if( speed < 0.1 )
return;
- }
drop = 0;
@@ -259,10 +261,11 @@ static void PM_Friction( void )
// if getting knocked back, no friction
if( !( pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) )
{
- float stopSpeed = BG_FindStopSpeedForClass( pm->ps->stats[ STAT_PCLASS ] );
+ float stopSpeed = BG_Class( pm->ps->stats[ STAT_CLASS ] )->stopSpeed;
+ float friction = BG_Class( pm->ps->stats[ STAT_CLASS ] )->friction;
control = speed < stopSpeed ? stopSpeed : speed;
- drop += control * BG_FindFrictionForClass( pm->ps->stats[ STAT_PCLASS ] ) * pml.frametime;
+ drop += control * friction * pml.frametime;
}
}
}
@@ -346,16 +349,43 @@ This allows the clients to use axial -127 to 127 values for all directions
without getting a sqrt(2) distortion in speed.
============
*/
-static float PM_CmdScale( usercmd_t *cmd )
+static float PM_CmdScale( usercmd_t *cmd, qboolean zFlight )
{
int max;
float total;
float scale;
float modifier = 1.0f;
-
- if( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS && pm->ps->pm_type == PM_NORMAL )
+
+ if( pm->ps->stats[ STAT_TEAM ] == TEAM_HUMANS && pm->ps->pm_type == PM_NORMAL )
{
- if( pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST )
+ qboolean wasSprinting;
+ qboolean sprint;
+ wasSprinting = sprint = pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST;
+
+ if( pm->ps->persistant[ PERS_STATE ] & PS_SPRINTTOGGLE )
+ {
+ if( cmd->buttons & BUTTON_SPRINT &&
+ !( pm->ps->pm_flags & PMF_SPRINTHELD ) )
+ {
+ sprint = !sprint;
+ pm->ps->pm_flags |= PMF_SPRINTHELD;
+ }
+ else if( pm->ps->pm_flags & PMF_SPRINTHELD &&
+ !( cmd->buttons & BUTTON_SPRINT ) )
+ pm->ps->pm_flags &= ~PMF_SPRINTHELD;
+ }
+ else
+ sprint = cmd->buttons & BUTTON_SPRINT;
+
+ if( sprint )
+ pm->ps->stats[ STAT_STATE ] |= SS_SPEEDBOOST;
+ else if( wasSprinting && !sprint )
+ pm->ps->stats[ STAT_STATE ] &= ~SS_SPEEDBOOST;
+
+ // Walk overrides sprint. We keep the state that we want to be sprinting
+ // (above), but don't apply the modifier, and in g_active we skip taking
+ // the stamina too.
+ if( sprint && !( cmd->buttons & BUTTON_WALKING ) )
modifier *= HUMAN_SPRINT_MODIFIER;
else
modifier *= HUMAN_JOG_MODIFIER;
@@ -371,13 +401,16 @@ static float PM_CmdScale( usercmd_t *cmd )
modifier *= HUMAN_SIDE_MODIFIER;
}
- //must have +ve stamina to jump
- if( pm->ps->stats[ STAT_STAMINA ] < 0 )
- cmd->upmove = 0;
+ if( !zFlight )
+ {
+ //must have have stamina to jump
+ if( pm->ps->stats[ STAT_STAMINA ] < STAMINA_SLOW_LEVEL + STAMINA_JUMP_TAKE )
+ cmd->upmove = 0;
+ }
//slow down once stamina depletes
- if( pm->ps->stats[ STAT_STAMINA ] <= -500 )
- modifier *= (float)( pm->ps->stats[ STAT_STAMINA ] + 1000 ) / 500.0f;
+ if( pm->ps->stats[ STAT_STAMINA ] <= STAMINA_SLOW_LEVEL )
+ modifier *= (float)( pm->ps->stats[ STAT_STAMINA ] + STAMINA_MAX ) / (float)(STAMINA_SLOW_LEVEL + STAMINA_MAX);
if( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED )
{
@@ -387,11 +420,20 @@ static float PM_CmdScale( usercmd_t *cmd )
else
modifier *= CREEP_MODIFIER;
}
+ if( pm->ps->eFlags & EF_POISONCLOUDED )
+ {
+ if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, pm->ps->stats ) ||
+ BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) )
+ modifier *= PCLOUD_ARMOUR_MODIFIER;
+ else
+ modifier *= PCLOUD_MODIFIER;
+ }
}
if( pm->ps->weapon == WP_ALEVEL4 && pm->ps->pm_flags & PMF_CHARGE )
- modifier *= ( 1.0f + ( pm->ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME ) *
- ( LEVEL4_CHARGE_SPEED - 1.0f ) );
+ modifier *= 1.0f + ( pm->ps->stats[ STAT_MISC ] *
+ ( LEVEL4_TRAMPLE_SPEED - 1.0f ) /
+ LEVEL4_TRAMPLE_DURATION );
//slow player if charging up for a pounce
if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG ) &&
@@ -405,28 +447,22 @@ static float PM_CmdScale( usercmd_t *cmd )
if( pm->ps->pm_type == PM_GRABBED )
modifier = 0.0f;
- if( pm->ps->pm_type != PM_SPECTATOR && pm->ps->pm_type != PM_NOCLIP )
- {
- if( BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ) == 0.0f )
- cmd->upmove = 0;
-
- //prevent speed distortions for non ducking classes
- if( !( pm->ps->pm_flags & PMF_DUCKED ) && pm->ps->pm_type != PM_JETPACK && cmd->upmove < 0 )
- cmd->upmove = 0;
- }
-
max = abs( cmd->forwardmove );
if( abs( cmd->rightmove ) > max )
max = abs( cmd->rightmove );
+ total = cmd->forwardmove * cmd->forwardmove + cmd->rightmove * cmd->rightmove;
- if( abs( cmd->upmove ) > max )
- max = abs( cmd->upmove );
+ if( zFlight )
+ {
+ if( abs( cmd->upmove ) > max )
+ max = abs( cmd->upmove );
+ total += cmd->upmove * cmd->upmove;
+ }
if( !max )
return 0;
- total = sqrt( cmd->forwardmove * cmd->forwardmove
- + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove );
+ total = sqrt( total );
scale = (float)pm->ps->speed * max / ( 127.0 * total ) * modifier;
@@ -438,7 +474,7 @@ static float PM_CmdScale( usercmd_t *cmd )
================
PM_SetMovementDir
-Determine the rotation of the legs reletive
+Determine the rotation of the legs relative
to the facing dir
================
*/
@@ -506,40 +542,49 @@ PM_CheckPounce
*/
static qboolean PM_CheckPounce( void )
{
+ int jumpMagnitude;
+
if( pm->ps->weapon != WP_ALEVEL3 &&
pm->ps->weapon != WP_ALEVEL3_UPG )
return qfalse;
- // we were pouncing, but we've landed
- if( pm->ps->groundEntityNum != ENTITYNUM_NONE
- && ( pm->ps->pm_flags & PMF_CHARGE ) )
+ // We were pouncing, but we've landed
+ if( pm->ps->groundEntityNum != ENTITYNUM_NONE &&
+ ( pm->ps->pm_flags & PMF_CHARGE ) )
{
- pm->ps->weaponTime += LEVEL3_POUNCE_TIME;
pm->ps->pm_flags &= ~PMF_CHARGE;
+ pm->ps->weaponTime += LEVEL3_POUNCE_REPEAT;
+ return qfalse;
}
- // we're building up for a pounce
+ // We're building up for a pounce
if( pm->cmd.buttons & BUTTON_ATTACK2 )
+ {
+ pm->ps->pm_flags &= ~PMF_CHARGE;
return qfalse;
+ }
- // already a pounce in progress
- if( pm->ps->pm_flags & PMF_CHARGE )
- return qfalse;
-
- if( pm->ps->stats[ STAT_MISC ] == 0 )
+ // Can't start a pounce
+ if( ( pm->ps->pm_flags & PMF_CHARGE ) ||
+ pm->ps->stats[ STAT_MISC ] < LEVEL3_POUNCE_TIME_MIN ||
+ pm->ps->groundEntityNum == ENTITYNUM_NONE )
return qfalse;
- pml.groundPlane = qfalse; // jumping away
+ // Give the player forward velocity and simulate a jump
+ pml.groundPlane = qfalse;
pml.walking = qfalse;
-
pm->ps->pm_flags |= PMF_CHARGE;
-
pm->ps->groundEntityNum = ENTITYNUM_NONE;
-
- VectorMA( pm->ps->velocity, pm->ps->stats[ STAT_MISC ], pml.forward, pm->ps->velocity );
-
+ if( pm->ps->weapon == WP_ALEVEL3 )
+ jumpMagnitude = pm->ps->stats[ STAT_MISC ] *
+ LEVEL3_POUNCE_JUMP_MAG / LEVEL3_POUNCE_TIME;
+ else
+ jumpMagnitude = pm->ps->stats[ STAT_MISC ] *
+ LEVEL3_POUNCE_JUMP_MAG_UPG / LEVEL3_POUNCE_TIME_UPG;
+ VectorMA( pm->ps->velocity, jumpMagnitude, pml.forward, pm->ps->velocity );
PM_AddEvent( EV_JUMP );
+ // Play jumping animation
if( pm->cmd.forwardmove >= 0 )
{
if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
@@ -572,15 +617,47 @@ PM_CheckWallJump
*/
static qboolean PM_CheckWallJump( void )
{
- vec3_t dir, forward, right;
+ vec3_t dir, forward, right, movedir, point;
vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
float normalFraction = 1.5f;
float cmdFraction = 1.0f;
float upFraction = 1.5f;
+ trace_t trace;
+
+ if( !( BG_Class( pm->ps->stats[ STAT_CLASS ] )->abilities & SCA_WALLJUMPER ) )
+ return qfalse;
+ ProjectPointOnPlane( movedir, pml.forward, refNormal );
+ VectorNormalize( movedir );
+
+ if( pm->cmd.forwardmove < 0 )
+ VectorNegate( movedir, movedir );
+
+ //allow strafe transitions
+ if( pm->cmd.rightmove )
+ {
+ VectorCopy( pml.right, movedir );
+
+ if( pm->cmd.rightmove < 0 )
+ VectorNegate( movedir, movedir );
+ }
+
+ //trace into direction we are moving
+ VectorMA( pm->ps->origin, 0.25f, movedir, point );
+ pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
+
+ if( trace.fraction < 1.0f &&
+ !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) &&
+ trace.plane.normal[ 2 ] < MIN_WALK_NORMAL )
+ {
+ VectorCopy( trace.plane.normal, pm->ps->grapplePoint );
+ }
+ else
+ return qfalse;
+
if( pm->ps->pm_flags & PMF_RESPAWNED )
return qfalse; // don't allow jump until all buttons are up
-
+
if( pm->cmd.upmove < 10 )
// not holding jump
return qfalse;
@@ -592,8 +669,6 @@ static qboolean PM_CheckWallJump( void )
if( pm->ps->pm_flags & PMF_JUMP_HELD &&
pm->ps->grapplePoint[ 2 ] == 1.0f )
{
- // clear upmove so cmdscale doesn't lower running speed
- pm->cmd.upmove = 0;
return qfalse;
}
@@ -624,7 +699,7 @@ static qboolean PM_CheckWallJump( void )
VectorMA( dir, upFraction, refNormal, dir );
VectorNormalize( dir );
- VectorMA( pm->ps->velocity, BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ),
+ VectorMA( pm->ps->velocity, BG_Class( pm->ps->stats[ STAT_CLASS ] )->jumpMagnitude,
dir, pm->ps->velocity );
//for a long run of wall jumps the velocity can get pretty large, this caps it
@@ -665,11 +740,13 @@ PM_CheckJump
*/
static qboolean PM_CheckJump( void )
{
- if( BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ) == 0.0f )
+ vec3_t normal;
+
+ if( pm->ps->groundEntityNum == ENTITYNUM_NONE )
return qfalse;
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
- return PM_CheckWallJump( );
+ if( BG_Class( pm->ps->stats[ STAT_CLASS ] )->jumpMagnitude == 0.0f )
+ return qfalse;
//can't jump and pounce at the same time
if( ( pm->ps->weapon == WP_ALEVEL3 ||
@@ -682,8 +759,13 @@ static qboolean PM_CheckJump( void )
pm->ps->stats[ STAT_MISC ] > 0 )
return qfalse;
- if( ( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) &&
- ( pm->ps->stats[ STAT_STAMINA ] < 0 ) )
+ if( ( pm->ps->stats[ STAT_TEAM ] == TEAM_HUMANS ) &&
+ ( pm->ps->stats[ STAT_STAMINA ] < STAMINA_SLOW_LEVEL + STAMINA_JUMP_TAKE ) )
+ return qfalse;
+
+ //no bunny hopping off a dodge
+ if( pm->ps->stats[ STAT_TEAM ] == TEAM_HUMANS &&
+ pm->ps->pm_time )
return qfalse;
if( pm->ps->pm_flags & PMF_RESPAWNED )
@@ -695,42 +777,37 @@ static qboolean PM_CheckJump( void )
//can't jump whilst grabbed
if( pm->ps->pm_type == PM_GRABBED )
- {
- pm->cmd.upmove = 0;
return qfalse;
- }
// must wait for jump to be released
if( pm->ps->pm_flags & PMF_JUMP_HELD )
- {
- // clear upmove so cmdscale doesn't lower running speed
- pm->cmd.upmove = 0;
return qfalse;
+
+ //don't allow walljump for a short while after jumping from the ground
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) )
+ {
+ pm->ps->pm_flags |= PMF_TIME_WALLJUMP;
+ pm->ps->pm_time = 200;
}
pml.groundPlane = qfalse; // jumping away
pml.walking = qfalse;
pm->ps->pm_flags |= PMF_JUMP_HELD;
- //TA: take some stamina off
- if( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS )
- pm->ps->stats[ STAT_STAMINA ] -= 500;
+ // take some stamina off
+ if( pm->ps->stats[ STAT_TEAM ] == TEAM_HUMANS )
+ pm->ps->stats[ STAT_STAMINA ] -= STAMINA_JUMP_TAKE;
pm->ps->groundEntityNum = ENTITYNUM_NONE;
- //TA: jump away from wall
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- {
- vec3_t normal = { 0, 0, -1 };
+ // jump away from wall
+ BG_GetClientNormal( pm->ps, normal );
+
+ if( pm->ps->velocity[ 2 ] < 0 )
+ pm->ps->velocity[ 2 ] = 0;
- if( !( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) )
- VectorCopy( pm->ps->grapplePoint, normal );
-
- VectorMA( pm->ps->velocity, BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ),
- normal, pm->ps->velocity );
- }
- else
- pm->ps->velocity[ 2 ] = BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] );
+ VectorMA( pm->ps->velocity, BG_Class( pm->ps->stats[ STAT_CLASS ] )->jumpMagnitude,
+ normal, pm->ps->velocity );
PM_AddEvent( EV_JUMP );
@@ -802,6 +879,108 @@ static qboolean PM_CheckWaterJump( void )
return qtrue;
}
+
+/*
+==================
+PM_CheckDodge
+
+Checks the dodge key and starts a human dodge or sprint
+==================
+*/
+static qboolean PM_CheckDodge( void )
+{
+ vec3_t right, forward, velocity = { 0.0f, 0.0f, 0.0f };
+ float jump, sideModifier;
+ int i;
+
+ if( pm->ps->stats[ STAT_TEAM ] != TEAM_HUMANS )
+ return qfalse;
+
+ // Landed a dodge
+ if( ( pm->ps->pm_flags & PMF_CHARGE ) &&
+ pm->ps->groundEntityNum != ENTITYNUM_NONE )
+ {
+ pm->ps->pm_flags = ( pm->ps->pm_flags & ~PMF_CHARGE ) | PMF_TIME_LAND;
+ pm->ps->pm_time = HUMAN_DODGE_TIMEOUT;
+ }
+
+ // Reasons why we can't start a dodge or sprint
+ if( pm->ps->pm_type != PM_NORMAL || pm->ps->stats[ STAT_STAMINA ] < STAMINA_SLOW_LEVEL + STAMINA_DODGE_TAKE ||
+ ( pm->ps->pm_flags & PMF_DUCKED ) )
+ return qfalse;
+
+ // Can't dodge forward
+ if( pm->cmd.forwardmove > 0 )
+ return qfalse;
+
+ // Reasons why we can't start a dodge only
+ if( pm->ps->pm_flags & ( PMF_TIME_LAND | PMF_CHARGE ) ||
+ pm->ps->groundEntityNum == ENTITYNUM_NONE ||
+ !( pm->cmd.buttons & BUTTON_DODGE ) )
+ return qfalse;
+
+ // Dodge direction specified with movement keys
+ if( ( !pm->cmd.rightmove && !pm->cmd.forwardmove ) || pm->cmd.upmove )
+ return qfalse;
+
+ AngleVectors( pm->ps->viewangles, NULL, right, NULL );
+ forward[ 0 ] = -right[ 1 ];
+ forward[ 1 ] = right[ 0 ];
+ forward[ 2 ] = 0.0f;
+
+ // Dodge magnitude is based on the jump magnitude scaled by the modifiers
+ jump = BG_Class( pm->ps->stats[ STAT_CLASS ] )->jumpMagnitude;
+ if( pm->cmd.rightmove && pm->cmd.forwardmove )
+ jump *= ( 0.5f * M_SQRT2 );
+
+ // Weaken dodge if slowed
+ if( ( pm->ps->stats[ STAT_STATE ] & SS_SLOWLOCKED ) ||
+ ( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED ) ||
+ ( pm->ps->eFlags & EF_POISONCLOUDED ) )
+ sideModifier = HUMAN_DODGE_SLOWED_MODIFIER;
+ else
+ sideModifier = HUMAN_DODGE_SIDE_MODIFIER;
+
+ // The dodge sets minimum velocity
+ if( pm->cmd.rightmove )
+ {
+ if( pm->cmd.rightmove < 0 )
+ VectorNegate( right, right );
+ VectorMA( velocity, jump * sideModifier, right, velocity );
+ }
+
+ if( pm->cmd.forwardmove )
+ {
+ if( pm->cmd.forwardmove < 0 )
+ VectorNegate( forward, forward );
+ VectorMA( velocity, jump * sideModifier, forward, velocity );
+ }
+
+ velocity[ 2 ] = jump * HUMAN_DODGE_UP_MODIFIER;
+
+ // Make sure client has minimum velocity
+ for( i = 0; i < 3; i++ )
+ {
+ if( ( velocity[ i ] < 0.0f &&
+ pm->ps->velocity[ i ] > velocity[ i ] ) ||
+ ( velocity[ i ] > 0.0f &&
+ pm->ps->velocity[ i ] < velocity[ i ] ) )
+ pm->ps->velocity[ i ] = velocity[ i ];
+ }
+
+ // Jumped away
+ pml.groundPlane = qfalse;
+ pml.walking = qfalse;
+ pm->ps->groundEntityNum = ENTITYNUM_NONE;
+ pm->ps->pm_flags |= PMF_CHARGE;
+ pm->ps->stats[ STAT_STAMINA ] -= STAMINA_DODGE_TAKE;
+ pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^
+ ANIM_TOGGLEBIT ) | LEGS_JUMP;
+ PM_AddEvent( EV_JUMP );
+
+ return qtrue;
+}
+
//============================================================================
@@ -863,23 +1042,15 @@ static void PM_WaterMove( void )
#endif
PM_Friction( );
- scale = PM_CmdScale( &pm->cmd );
+ scale = PM_CmdScale( &pm->cmd, qtrue );
//
// user intentions
//
- if( !scale )
- {
- wishvel[ 0 ] = 0;
- wishvel[ 1 ] = 0;
- wishvel[ 2 ] = -60; // sink towards bottom
- }
- else
- {
- for( i = 0; i < 3; i++ )
- wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove;
- wishvel[ 2 ] += scale * pm->cmd.upmove;
- }
+ for( i = 0; i < 3; i++ )
+ wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove;
+
+ wishvel[ 2 ] += scale * pm->cmd.upmove;
VectorCopy( wishvel, wishdir );
wishspeed = VectorNormalize( wishdir );
@@ -894,8 +1065,7 @@ static void PM_WaterMove( void )
{
vel = VectorLength( pm->ps->velocity );
// slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
VectorNormalize( pm->ps->velocity );
VectorScale( pm->ps->velocity, vel, pm->ps->velocity );
@@ -922,7 +1092,7 @@ static void PM_JetPackMove( void )
//normal slowdown
PM_Friction( );
- scale = PM_CmdScale( &pm->cmd );
+ scale = PM_CmdScale( &pm->cmd, qfalse );
// user intentions
for( i = 0; i < 2; i++ )
@@ -969,7 +1139,7 @@ static void PM_FlyMove( void )
// normal slowdown
PM_Friction( );
- scale = PM_CmdScale( &pm->cmd );
+ scale = PM_CmdScale( &pm->cmd, qtrue );
//
// user intentions
//
@@ -1012,13 +1182,14 @@ static void PM_AirMove( void )
float scale;
usercmd_t cmd;
+ PM_CheckWallJump( );
PM_Friction( );
fmove = pm->cmd.forwardmove;
smove = pm->cmd.rightmove;
cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
+ scale = PM_CmdScale( &cmd, qfalse );
// set the movementDir so clients can rotate the legs for strafing
PM_SetMovementDir( );
@@ -1040,14 +1211,13 @@ static void PM_AirMove( void )
// not on ground, so little effect on velocity
PM_Accelerate( wishdir, wishspeed,
- BG_FindAirAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] ) );
+ BG_Class( pm->ps->stats[ STAT_CLASS ] )->airAcceleration );
// we may have a ground plane that is very steep, even
// though we don't have a groundentity
// slide along the steep plane
if( pml.groundPlane )
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
PM_StepSlideMove( qtrue, qfalse );
}
@@ -1095,14 +1265,14 @@ static void PM_ClimbMove( void )
smove = pm->cmd.rightmove;
cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
+ scale = PM_CmdScale( &cmd, qfalse );
// set the movementDir so clients can rotate the legs for strafing
PM_SetMovementDir( );
// project the forward and right directions onto the ground plane
- PM_ClipVelocity( pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );
- PM_ClipVelocity( pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );
+ PM_ClipVelocity( pml.forward, pml.groundTrace.plane.normal, pml.forward );
+ PM_ClipVelocity( pml.right, pml.groundTrace.plane.normal, pml.right );
//
VectorNormalize( pml.forward );
VectorNormalize( pml.right );
@@ -1138,9 +1308,9 @@ static void PM_ClimbMove( void )
// when a player gets hit, they temporarily lose
// full control, which allows them to be moved a bit
if( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK )
- accelerate = BG_FindAirAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] );
+ accelerate = BG_Class( pm->ps->stats[ STAT_CLASS ] )->airAcceleration;
else
- accelerate = BG_FindAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] );
+ accelerate = BG_Class( pm->ps->stats[ STAT_CLASS ] )->acceleration;
PM_Accelerate( wishdir, wishspeed, accelerate );
@@ -1150,8 +1320,7 @@ static void PM_ClimbMove( void )
vel = VectorLength( pm->ps->velocity );
// slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
// don't decrease velocity when going up or down a slope
VectorNormalize( pm->ps->velocity );
@@ -1189,7 +1358,6 @@ static void PM_WalkMove( void )
return;
}
-
if( PM_CheckJump( ) || PM_CheckPounce( ) )
{
// jumped away
@@ -1210,7 +1378,7 @@ static void PM_WalkMove( void )
smove = pm->cmd.rightmove;
cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
+ scale = PM_CmdScale( &cmd, qfalse );
// set the movementDir so clients can rotate the legs for strafing
PM_SetMovementDir( );
@@ -1220,8 +1388,8 @@ static void PM_WalkMove( void )
pml.right[ 2 ] = 0;
// project the forward and right directions onto the ground plane
- PM_ClipVelocity( pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );
- PM_ClipVelocity( pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );
+ PM_ClipVelocity( pml.forward, pml.groundTrace.plane.normal, pml.forward );
+ PM_ClipVelocity( pml.right, pml.groundTrace.plane.normal, pml.right );
//
VectorNormalize( pml.forward );
VectorNormalize( pml.right );
@@ -1257,9 +1425,9 @@ static void PM_WalkMove( void )
// when a player gets hit, they temporarily lose
// full control, which allows them to be moved a bit
if( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK )
- accelerate = BG_FindAirAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] );
+ accelerate = BG_Class( pm->ps->stats[ STAT_CLASS ] )->airAcceleration;
else
- accelerate = BG_FindAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] );
+ accelerate = BG_Class( pm->ps->stats[ STAT_CLASS ] )->acceleration;
PM_Accelerate( wishdir, wishspeed, accelerate );
@@ -1275,8 +1443,7 @@ static void PM_WalkMove( void )
}
// slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
// don't do anything if standing still
if( !pm->ps->velocity[ 0 ] && !pm->ps->velocity[ 1 ] )
@@ -1307,7 +1474,7 @@ static void PM_LadderMove( void )
PM_Friction( );
- scale = PM_CmdScale( &pm->cmd );
+ scale = PM_CmdScale( &pm->cmd, qtrue );
for( i = 0; i < 3; i++ )
wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove;
@@ -1328,8 +1495,7 @@ static void PM_LadderMove( void )
vel = VectorLength( pm->ps->velocity );
// slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
VectorNormalize( pm->ps->velocity );
VectorScale( pm->ps->velocity, vel, pm->ps->velocity );
@@ -1352,7 +1518,7 @@ static void PM_CheckLadder( void )
trace_t trace;
//test if class can use ladders
- if( !BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_CANUSELADDERS ) )
+ if( !BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_CANUSELADDERS ) )
{
pml.ladder = qfalse;
return;
@@ -1414,8 +1580,6 @@ static void PM_NoclipMove( void )
float wishspeed;
float scale;
- pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
-
// friction
speed = VectorLength( pm->ps->velocity );
@@ -1444,7 +1608,7 @@ static void PM_NoclipMove( void )
}
// accelerate
- scale = PM_CmdScale( &pm->cmd );
+ scale = PM_CmdScale( &pm->cmd, qtrue );
fmove = pm->cmd.forwardmove;
smove = pm->cmd.rightmove;
@@ -1475,7 +1639,6 @@ Returns an event number apropriate for the groundsurface
*/
static int PM_FootstepForSurface( void )
{
- //TA:
if( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED )
return EV_FOOTSTEP_SQUELCH;
@@ -1543,10 +1706,6 @@ static void PM_CrashLand( void )
delta = vel + t * acc;
delta = delta*delta * 0.0001;
- // ducking while falling doubles damage
- if( pm->ps->pm_flags & PMF_DUCKED )
- delta *= 2;
-
// never take falling damage if completely underwater
if( pm->waterlevel == 3 )
return;
@@ -1571,12 +1730,12 @@ static void PM_CrashLand( void )
if( delta > AVG_FALL_DISTANCE )
{
- PM_AddEvent( EV_FALL_FAR );
+ if( PM_Alive( pm->ps->pm_type ) )
+ PM_AddEvent( EV_FALL_FAR );
}
else if( delta > MIN_FALL_DISTANCE )
{
- // this is a pain grunt, so don't play it if dead
- if( pm->ps->stats[STAT_HEALTH] > 0 )
+ if( PM_Alive( pm->ps->pm_type ) )
PM_AddEvent( EV_FALL_MEDIUM );
}
else
@@ -1688,7 +1847,7 @@ static void PM_GroundTraceMissed( void )
}
}
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_TAKESFALLDAMAGE ) )
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_TAKESFALLDAMAGE ) )
{
if( pm->ps->velocity[ 2 ] < FALLING_THRESHOLD && pml.previous_velocity[ 2 ] >= FALLING_THRESHOLD )
PM_AddEvent( EV_FALLING );
@@ -1699,7 +1858,6 @@ static void PM_GroundTraceMissed( void )
pml.walking = qfalse;
}
-
/*
=============
PM_GroundClimbTrace
@@ -1707,12 +1865,13 @@ PM_GroundClimbTrace
*/
static void PM_GroundClimbTrace( void )
{
- vec3_t surfNormal, movedir, lookdir, point;
- vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
- vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f };
- vec3_t toAngles, surfAngles;
- trace_t trace;
- int i;
+ vec3_t surfNormal, movedir, lookdir, point;
+ vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
+ vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f };
+ vec3_t toAngles, surfAngles;
+ trace_t trace;
+ int i;
+ const float eps = 0.000001f;
//used for delta correction
vec3_t traceCROSSsurf, traceCROSSref, surfCROSSref;
@@ -1724,12 +1883,7 @@ static void PM_GroundClimbTrace( void )
float ldDOTtCs, d;
vec3_t abc;
- //TA: If we're on the ceiling then grapplePoint is a rotation normal.. otherwise its a surface normal.
- // would have been nice if Carmack had left a few random variables in the ps struct for mod makers
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- VectorCopy( ceilingNormal, surfNormal );
- else
- VectorCopy( pm->ps->grapplePoint, surfNormal );
+ BG_GetClientNormal( pm->ps, surfNormal );
//construct a vector which reflects the direction the player is looking wrt the surface normal
ProjectPointOnPlane( movedir, pml.forward, surfNormal );
@@ -1765,8 +1919,10 @@ static void PM_GroundClimbTrace( void )
case 1:
//trace straight down anto "ground" surface
+ //mask out CONTENTS_BODY to not hit other players and avoid the camera flipping out when
+ // wallwalkers touch
VectorMA( pm->ps->origin, -0.25f, surfNormal, point );
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
+ pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask & ~CONTENTS_BODY );
break;
case 2:
@@ -1801,7 +1957,7 @@ static void PM_GroundClimbTrace( void )
}
//if we hit something
- if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) &&
+ if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) &&
!( trace.entityNum != ENTITYNUM_WORLD && i != 4 ) )
{
if( i == 2 || i == 3 )
@@ -1811,7 +1967,7 @@ static void PM_GroundClimbTrace( void )
VectorCopy( trace.endpos, pm->ps->origin );
}
-
+
//calculate a bunch of stuff...
CrossProduct( trace.plane.normal, surfNormal, traceCROSSsurf );
VectorNormalize( traceCROSSsurf );
@@ -1845,11 +2001,11 @@ static void PM_GroundClimbTrace( void )
//if the trace result and old surface normal are different then we must have transided to a new
//surface... do some stuff...
- if( !VectorCompare( trace.plane.normal, surfNormal ) )
+ if( !VectorCompareEpsilon( trace.plane.normal, surfNormal, eps ) )
{
//if the trace result or the old vector is not the floor or ceiling correct the YAW angle
- if( !VectorCompare( trace.plane.normal, refNormal ) && !VectorCompare( surfNormal, refNormal ) &&
- !VectorCompare( trace.plane.normal, ceilingNormal ) && !VectorCompare( surfNormal, ceilingNormal ) )
+ if( !VectorCompareEpsilon( trace.plane.normal, refNormal, eps ) && !VectorCompareEpsilon( surfNormal, refNormal, eps ) &&
+ !VectorCompareEpsilon( trace.plane.normal, ceilingNormal, eps ) && !VectorCompareEpsilon( surfNormal, ceilingNormal, eps ) )
{
//behold the evil mindfuck from hell
//it has fucked mind like nothing has fucked mind before
@@ -1907,16 +2063,16 @@ static void PM_GroundClimbTrace( void )
//transition from wall to ceiling
//normal for subsequent viewangle rotations
- if( VectorCompare( trace.plane.normal, ceilingNormal ) )
+ if( VectorCompareEpsilon( trace.plane.normal, ceilingNormal, eps ) )
{
CrossProduct( surfNormal, trace.plane.normal, pm->ps->grapplePoint );
VectorNormalize( pm->ps->grapplePoint );
- pm->ps->stats[ STAT_STATE ] |= SS_WALLCLIMBINGCEILING;
+ pm->ps->eFlags |= EF_WALLCLIMBCEILING;
}
//transition from ceiling to wall
//we need to do some different angle correction here cos GPISROTVEC
- if( VectorCompare( surfNormal, ceilingNormal ) )
+ if( VectorCompareEpsilon( surfNormal, ceilingNormal, eps ) )
{
vectoangles( trace.plane.normal, toAngles );
vectoangles( pm->ps->grapplePoint, surfAngles );
@@ -1931,11 +2087,11 @@ static void PM_GroundClimbTrace( void )
pm->ps->eFlags |= EF_WALLCLIMB;
//if we're not stuck to the ceiling then set grapplePoint to be a surface normal
- if( !VectorCompare( trace.plane.normal, ceilingNormal ) )
+ if( !VectorCompareEpsilon( trace.plane.normal, ceilingNormal, eps ) )
{
//so we know what surface we're stuck to
VectorCopy( trace.plane.normal, pm->ps->grapplePoint );
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING;
+ pm->ps->eFlags &= ~EF_WALLCLIMBCEILING;
}
//IMPORTANT: break out of the for loop if we've hit something
@@ -1958,7 +2114,7 @@ static void PM_GroundClimbTrace( void )
pm->ps->eFlags &= ~EF_WALLCLIMB;
//just transided from ceiling to floor... apply delta correction
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
+ if( pm->ps->eFlags & EF_WALLCLIMBCEILING )
{
vec3_t forward, rotated, angles;
@@ -1970,7 +2126,7 @@ static void PM_GroundClimbTrace( void )
pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( angles[ YAW ] - pm->ps->viewangles[ YAW ] );
}
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING;
+ pm->ps->eFlags &= ~EF_WALLCLIMBCEILING;
//we get very bizarre effects if we don't do this :0
VectorCopy( refNormal, pm->ps->grapplePoint );
@@ -1983,7 +2139,7 @@ static void PM_GroundClimbTrace( void )
// hitting solid ground will end a waterjump
if( pm->ps->pm_flags & PMF_TIME_WATERJUMP )
{
- pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND);
+ pm->ps->pm_flags &= ~PMF_TIME_WATERJUMP;
pm->ps->pm_time = 0;
}
@@ -1995,7 +2151,6 @@ static void PM_GroundClimbTrace( void )
PM_AddTouchEnt( trace.entityNum );
}
-
/*
=============
PM_GroundTrace
@@ -2004,11 +2159,10 @@ PM_GroundTrace
static void PM_GroundTrace( void )
{
vec3_t point;
- vec3_t movedir;
vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
trace_t trace;
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) )
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_WALLCLIMBER ) )
{
if( pm->ps->persistant[ PERS_STATE ] & PS_WALLCLIMBINGTOGGLE )
{
@@ -2043,7 +2197,7 @@ static void PM_GroundTrace( void )
}
//just transided from ceiling to floor... apply delta correction
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
+ if( pm->ps->eFlags & EF_WALLCLIMBCEILING )
{
vec3_t forward, rotated, angles;
@@ -2057,8 +2211,7 @@ static void PM_GroundTrace( void )
}
pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING;
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING;
- pm->ps->eFlags &= ~EF_WALLCLIMB;
+ pm->ps->eFlags &= ~( EF_WALLCLIMB | EF_WALLCLIMBCEILING );
point[ 0 ] = pm->ps->origin[ 0 ];
point[ 1 ] = pm->ps->origin[ 1 ];
@@ -2105,38 +2258,6 @@ static void PM_GroundTrace( void )
pml.groundPlane = qfalse;
pml.walking = qfalse;
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
- {
- ProjectPointOnPlane( movedir, pml.forward, refNormal );
- VectorNormalize( movedir );
-
- if( pm->cmd.forwardmove < 0 )
- VectorNegate( movedir, movedir );
-
- //allow strafe transitions
- if( pm->cmd.rightmove )
- {
- VectorCopy( pml.right, movedir );
-
- if( pm->cmd.rightmove < 0 )
- VectorNegate( movedir, movedir );
- }
-
- //trace into direction we are moving
- VectorMA( pm->ps->origin, 0.25f, movedir, point );
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
-
- if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) &&
- ( trace.entityNum == ENTITYNUM_WORLD ) )
- {
- if( !VectorCompare( trace.plane.normal, pm->ps->grapplePoint ) )
- {
- VectorCopy( trace.plane.normal, pm->ps->grapplePoint );
- PM_CheckWallJump( );
- }
- }
- }
-
return;
}
}
@@ -2193,7 +2314,7 @@ static void PM_GroundTrace( void )
// hitting solid ground will end a waterjump
if( pm->ps->pm_flags & PMF_TIME_WATERJUMP )
{
- pm->ps->pm_flags &= ~( PMF_TIME_WATERJUMP | PMF_TIME_LAND );
+ pm->ps->pm_flags &= ~PMF_TIME_WATERJUMP;
pm->ps->pm_time = 0;
}
@@ -2203,16 +2324,11 @@ static void PM_GroundTrace( void )
if( pm->debugLevel )
Com_Printf( "%i:Land\n", c_pmove );
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_TAKESFALLDAMAGE ) )
- PM_CrashLand( );
+ // communicate the fall velocity to the server
+ pm->pmext->fallVelocity = pml.previous_velocity[ 2 ];
- // don't do landing time if we were just going down a slope
- if( pml.previous_velocity[ 2 ] < -200 )
- {
- // don't allow another jump for a little while
- pm->ps->pm_flags |= PMF_TIME_LAND;
- pm->ps->pm_time = 250;
- }
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_TAKESFALLDAMAGE ) )
+ PM_CrashLand( );
}
pm->ps->groundEntityNum = trace.entityNum;
@@ -2273,23 +2389,29 @@ static void PM_SetWaterLevel( void )
/*
==============
+PM_SetViewheight
+==============
+*/
+static void PM_SetViewheight( void )
+{
+ pm->ps->viewheight = ( pm->ps->pm_flags & PMF_DUCKED )
+ ? BG_ClassConfig( pm->ps->stats[ STAT_CLASS ] )->crouchViewheight
+ : BG_ClassConfig( pm->ps->stats[ STAT_CLASS ] )->viewheight;
+}
+
+/*
+==============
PM_CheckDuck
-Sets mins, maxs, and pm->ps->viewheight
+Sets mins and maxs, and calls PM_SetViewheight
==============
*/
static void PM_CheckDuck (void)
{
trace_t trace;
vec3_t PCmins, PCmaxs, PCcmaxs;
- int PCvh, PCcvh;
- BG_FindBBoxForClass( pm->ps->stats[ STAT_PCLASS ], PCmins, PCmaxs, PCcmaxs, NULL, NULL );
- BG_FindViewheightForClass( pm->ps->stats[ STAT_PCLASS ], &PCvh, &PCcvh );
-
- //TA: iD bug? you can still crouch when you're a spectator
- if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
- PCcvh = PCvh;
+ BG_ClassBoundingBox( pm->ps->stats[ STAT_CLASS ], PCmins, PCmaxs, PCcmaxs, NULL, NULL );
pm->mins[ 0 ] = PCmins[ 0 ];
pm->mins[ 1 ] = PCmins[ 1 ];
@@ -2302,14 +2424,13 @@ static void PM_CheckDuck (void)
if( pm->ps->pm_type == PM_DEAD )
{
pm->maxs[ 2 ] = -8;
- pm->ps->viewheight = DEAD_VIEWHEIGHT;
+ pm->ps->viewheight = PCmins[ 2 ] + DEAD_VIEWHEIGHT;
return;
}
- //TA: If the standing and crouching viewheights are the same the class can't crouch
- if( ( pm->cmd.upmove < 0 ) && ( PCvh != PCcvh ) &&
- pm->ps->pm_type != PM_JETPACK &&
- !BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) )
+ // If the standing and crouching bboxes are the same the class can't crouch
+ if( ( pm->cmd.upmove < 0 ) && !VectorCompare( PCmaxs, PCcmaxs ) &&
+ pm->ps->pm_type != PM_JETPACK )
{
// duck
pm->ps->pm_flags |= PMF_DUCKED;
@@ -2328,15 +2449,11 @@ static void PM_CheckDuck (void)
}
if( pm->ps->pm_flags & PMF_DUCKED )
- {
pm->maxs[ 2 ] = PCcmaxs[ 2 ];
- pm->ps->viewheight = PCcvh;
- }
else
- {
pm->maxs[ 2 ] = PCmaxs[ 2 ];
- pm->ps->viewheight = PCvh;
- }
+
+ PM_SetViewheight( );
}
@@ -2359,9 +2476,9 @@ static void PM_Footsteps( void )
// calculate speed and cycle to be used for
// all cyclic walking effects
//
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) && ( pml.groundPlane ) )
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_WALLCLIMBER ) && ( pml.groundPlane ) )
{
- //TA: FIXME: yes yes i know this is wrong
+ // FIXME: yes yes i know this is wrong
pm->xyspeed = sqrt( pm->ps->velocity[ 0 ] * pm->ps->velocity[ 0 ]
+ pm->ps->velocity[ 1 ] * pm->ps->velocity[ 1 ]
+ pm->ps->velocity[ 2 ] * pm->ps->velocity[ 2 ] );
@@ -2519,7 +2636,7 @@ static void PM_Footsteps( void )
}
}
- bobmove *= BG_FindBobCycleForClass( pm->ps->stats[ STAT_PCLASS ] );
+ bobmove *= BG_Class( pm->ps->stats[ STAT_CLASS ] )->bobCycle;
if( pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST )
bobmove *= HUMAN_SPRINT_MODIFIER;
@@ -2606,19 +2723,15 @@ static void PM_BeginWeaponChange( int weapon )
if( pm->ps->weaponstate == WEAPON_DROPPING )
return;
- //special case to prevent storing a charged up lcannon
- if( pm->ps->weapon == WP_LUCIFER_CANNON )
- pm->ps->stats[ STAT_MISC ] = 0;
-
// cancel a reload
pm->ps->pm_flags &= ~PMF_WEAPON_RELOAD;
if( pm->ps->weaponstate == WEAPON_RELOADING )
pm->ps->weaponTime = 0;
- // force this here to prevent flamer effect from continuing, among other issues
- pm->ps->generic1 = WPM_NOTFIRING;
+ //special case to prevent storing a charged up lcannon
+ if( pm->ps->weapon == WP_LUCIFER_CANNON )
+ pm->ps->stats[ STAT_MISC ] = 0;
- PM_AddEvent( EV_CHANGE_WEAPON );
pm->ps->weaponstate = WEAPON_DROPPING;
pm->ps->weaponTime += 200;
pm->ps->persistant[ PERS_NEWWEAPON ] = weapon;
@@ -2627,7 +2740,10 @@ static void PM_BeginWeaponChange( int weapon )
pm->ps->stats[ STAT_BUILDABLE ] = BA_NONE;
if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
+ {
PM_StartTorsoAnim( TORSO_DROP );
+ PM_StartWeaponAnim( WANIM_DROP );
+ }
}
@@ -2640,6 +2756,7 @@ static void PM_FinishWeaponChange( void )
{
int weapon;
+ PM_AddEvent( EV_CHANGE_WEAPON );
weapon = pm->ps->persistant[ PERS_NEWWEAPON ];
if( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS )
weapon = WP_NONE;
@@ -2652,7 +2769,10 @@ static void PM_FinishWeaponChange( void )
pm->ps->weaponTime += 250;
if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
+ {
PM_StartTorsoAnim( TORSO_RAISE );
+ PM_StartWeaponAnim( WANIM_RAISE );
+ }
}
@@ -2664,15 +2784,17 @@ PM_TorsoAnimation
*/
static void PM_TorsoAnimation( void )
{
- if( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL )
- return;
-
if( pm->ps->weaponstate == WEAPON_READY )
{
- if( pm->ps->weapon == WP_BLASTER )
- PM_ContinueTorsoAnim( TORSO_STAND2 );
- else
- PM_ContinueTorsoAnim( TORSO_STAND );
+ if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
+ {
+ if( pm->ps->weapon == WP_BLASTER )
+ PM_ContinueTorsoAnim( TORSO_STAND2 );
+ else
+ PM_ContinueTorsoAnim( TORSO_STAND );
+ }
+
+ PM_ContinueWeaponAnim( WANIM_IDLE );
}
}
@@ -2687,61 +2809,169 @@ Generates weapon events and modifes the weapon counter
static void PM_Weapon( void )
{
int addTime = 200; //default addTime - should never be used
- int ammo, clips, maxClips;
- qboolean attack1 = qfalse;
- qboolean attack2 = qfalse;
- qboolean attack3 = qfalse;
+ qboolean attack1 = pm->cmd.buttons & BUTTON_ATTACK;
+ qboolean attack2 = pm->cmd.buttons & BUTTON_ATTACK2;
+ qboolean attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE;
- // don't allow attack until all buttons are up
- if( pm->ps->pm_flags & PMF_RESPAWNED )
+ // Ignore weapons in some cases
+ if( pm->ps->persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
return;
- // ignore if spectator
- if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
+ // Check for dead player
+ if( pm->ps->stats[ STAT_HEALTH ] <= 0 )
+ {
+ pm->ps->weapon = WP_NONE;
return;
+ }
- if( pm->ps->stats[ STAT_STATE ] & SS_INFESTING )
- return;
+ // Charging for a pounce or canceling a pounce
+ if( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG )
+ {
+ int max;
+
+ max = pm->ps->weapon == WP_ALEVEL3 ? LEVEL3_POUNCE_TIME :
+ LEVEL3_POUNCE_TIME_UPG;
+ if( pm->cmd.buttons & BUTTON_ATTACK2 )
+ pm->ps->stats[ STAT_MISC ] += pml.msec;
+ else
+ pm->ps->stats[ STAT_MISC ] -= pml.msec;
- if( pm->ps->stats[ STAT_STATE ] & SS_HOVELING )
- return;
+ if( pm->ps->stats[ STAT_MISC ] > max )
+ pm->ps->stats[ STAT_MISC ] = max;
+ else if( pm->ps->stats[ STAT_MISC ] < 0 )
+ pm->ps->stats[ STAT_MISC ] = 0;
+ }
- // check for dead player
- if( pm->ps->stats[ STAT_HEALTH ] <= 0 )
+ // Trample charge mechanics
+ if( pm->ps->weapon == WP_ALEVEL4 )
{
- pm->ps->weapon = WP_NONE;
+ // Charging up
+ if( !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) )
+ {
+ // Charge button held
+ if( pm->ps->stats[ STAT_MISC ] < LEVEL4_TRAMPLE_CHARGE_TRIGGER &&
+ ( pm->cmd.buttons & BUTTON_ATTACK2 ) )
+ {
+ pm->ps->stats[ STAT_STATE ] &= ~SS_CHARGING;
+ if( pm->cmd.forwardmove > 0 )
+ {
+ int charge = pml.msec;
+ vec3_t dir,vel;
+
+ AngleVectors( pm->ps->viewangles, dir, NULL, NULL );
+ VectorCopy( pm->ps->velocity, vel );
+ vel[2] = 0;
+ dir[2] = 0;
+ VectorNormalize( vel );
+ VectorNormalize( dir );
+
+ charge *= DotProduct( dir, vel );
+
+ pm->ps->stats[ STAT_MISC ] += charge;
+ }
+ else
+ pm->ps->stats[ STAT_MISC ] = 0;
+ }
+
+ // Charge button released
+ else if( !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) )
+ {
+ if( pm->ps->stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MIN )
+ {
+ if( pm->ps->stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MAX )
+ pm->ps->stats[ STAT_MISC ] = LEVEL4_TRAMPLE_CHARGE_MAX;
+ pm->ps->stats[ STAT_MISC ] = pm->ps->stats[ STAT_MISC ] *
+ LEVEL4_TRAMPLE_DURATION /
+ LEVEL4_TRAMPLE_CHARGE_MAX;
+ pm->ps->stats[ STAT_STATE ] |= SS_CHARGING;
+ PM_AddEvent( EV_LEV4_TRAMPLE_START );
+ }
+ else
+ pm->ps->stats[ STAT_MISC ] -= pml.msec;
+ }
+ }
+
+ // Discharging
+ else
+ {
+ if( pm->ps->stats[ STAT_MISC ] < LEVEL4_TRAMPLE_CHARGE_MIN )
+ pm->ps->stats[ STAT_MISC ] = 0;
+ else
+ pm->ps->stats[ STAT_MISC ] -= pml.msec;
+
+ // If the charger has stopped moving take a chunk of charge away
+ if( VectorLength( pm->ps->velocity ) < 64.0f || pm->cmd.rightmove )
+ pm->ps->stats[ STAT_MISC ] -= LEVEL4_TRAMPLE_STOP_PENALTY * pml.msec;
+ }
+
+ // Charge is over
+ if( pm->ps->stats[ STAT_MISC ] <= 0 || pm->cmd.forwardmove <= 0 )
+ {
+ pm->ps->stats[ STAT_MISC ] = 0;
+ pm->ps->stats[ STAT_STATE ] &= ~SS_CHARGING;
+ }
+ }
+
+ // Charging up a Lucifer Cannon
+ pm->ps->eFlags &= ~EF_WARN_CHARGE;
+
+ // don't allow attack until all buttons are up
+ if( pm->ps->pm_flags & PMF_RESPAWNED )
return;
+
+ if( pm->ps->weapon == WP_LUCIFER_CANNON )
+ {
+ // Charging up
+ if( !pm->ps->weaponTime &&
+ ( pm->cmd.buttons & BUTTON_ATTACK ) )
+ {
+ pm->ps->stats[ STAT_MISC ] += pml.msec;
+ if( pm->ps->stats[ STAT_MISC ] >= LCANNON_CHARGE_TIME_MAX )
+ pm->ps->stats[ STAT_MISC ] = LCANNON_CHARGE_TIME_MAX;
+ if( pm->ps->stats[ STAT_MISC ] > pm->ps->ammo * LCANNON_CHARGE_TIME_MAX /
+ LCANNON_CHARGE_AMMO )
+ pm->ps->stats[ STAT_MISC ] = pm->ps->ammo * LCANNON_CHARGE_TIME_MAX /
+ LCANNON_CHARGE_AMMO;
+ }
+
+ // Set overcharging flag so other players can hear the warning beep
+ if( pm->ps->stats[ STAT_MISC ] > LCANNON_CHARGE_TIME_WARN )
+ pm->ps->eFlags |= EF_WARN_CHARGE;
}
-
// no bite during pounce
- if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG )
- && ( pm->cmd.buttons & BUTTON_ATTACK )
- && ( pm->ps->pm_flags & PMF_CHARGE ) )
- {
+ if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG )
+ && ( pm->cmd.buttons & BUTTON_ATTACK )
+ && ( pm->ps->pm_flags & PMF_CHARGE ) )
return;
- }
+ // pump weapon delays (repeat times etc)
if( pm->ps->weaponTime > 0 )
pm->ps->weaponTime -= pml.msec;
+ if( pm->ps->weaponTime < 0 )
+ pm->ps->weaponTime = 0;
+
+ // no slash during charge
+ if( pm->ps->stats[ STAT_STATE ] & SS_CHARGING )
+ return;
// check for weapon change
// can't change if weapon is firing, but can change
// again if lowering or raising
- if( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING )
+ if( BG_PlayerCanChangeWeapon( pm->ps ) )
{
- //TA: must press use to switch weapons
+ // must press use to switch weapons
if( pm->cmd.buttons & BUTTON_USE_HOLDABLE )
{
if( !( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) )
{
- if( pm->cmd.weapon <= 32 )
+ if( pm->cmd.weapon < 32 )
{
//if trying to select a weapon, select it
if( pm->ps->weapon != pm->cmd.weapon )
PM_BeginWeaponChange( pm->cmd.weapon );
}
- else if( pm->cmd.weapon > 32 )
+ else
{
//if trying to toggle an upgrade, toggle it
if( BG_InventoryContainsUpgrade( pm->cmd.weapon - 32, pm->ps->stats ) ) //sanity check
@@ -2762,7 +2992,16 @@ static void PM_Weapon( void )
if( pm->ps->pm_flags & PMF_WEAPON_SWITCH )
{
pm->ps->pm_flags &= ~PMF_WEAPON_SWITCH;
- PM_BeginWeaponChange( pm->ps->persistant[ PERS_NEWWEAPON ] );
+ if( pm->ps->weapon != WP_NONE )
+ {
+ // drop the current weapon
+ PM_BeginWeaponChange( pm->ps->persistant[ PERS_NEWWEAPON ] );
+ }
+ else
+ {
+ // no current weapon, so just raise the new one
+ PM_FinishWeaponChange( );
+ }
}
}
@@ -2776,10 +3015,10 @@ static void PM_Weapon( void )
return;
}
+ // Set proper animation
if( pm->ps->weaponstate == WEAPON_RAISING )
{
pm->ps->weaponstate = WEAPON_READY;
-
if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
{
if( pm->ps->weapon == WP_BLASTER )
@@ -2788,19 +3027,21 @@ static void PM_Weapon( void )
PM_ContinueTorsoAnim( TORSO_STAND );
}
+ PM_ContinueWeaponAnim( WANIM_IDLE );
+
return;
}
- // start the animation even if out of ammo
- ammo = pm->ps->ammo;
- clips = pm->ps->clips;
- BG_FindAmmoForWeapon( pm->ps->weapon, NULL, &maxClips );
-
// check for out of ammo
- if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
+ if( !pm->ps->ammo && !pm->ps->clips && !BG_Weapon( pm->ps->weapon )->infiniteAmmo )
{
- PM_AddEvent( EV_NOAMMO );
- pm->ps->weaponTime += 200;
+ if( attack1 ||
+ ( BG_Weapon( pm->ps->weapon )->hasAltMode && attack2 ) ||
+ ( BG_Weapon( pm->ps->weapon )->hasThirdMode && attack3 ) )
+ {
+ PM_AddEvent( EV_NOAMMO );
+ pm->ps->weaponTime += 500;
+ }
if( pm->ps->weaponstate == WEAPON_FIRING )
pm->ps->weaponstate = WEAPON_READY;
@@ -2811,18 +3052,12 @@ static void PM_Weapon( void )
//done reloading so give em some ammo
if( pm->ps->weaponstate == WEAPON_RELOADING )
{
- if( maxClips > 0 )
- {
- clips--;
- BG_FindAmmoForWeapon( pm->ps->weapon, &ammo, NULL );
- }
+ pm->ps->clips--;
+ pm->ps->ammo = BG_Weapon( pm->ps->weapon )->maxAmmo;
- if( BG_FindUsesEnergyForWeapon( pm->ps->weapon ) &&
+ if( BG_Weapon( pm->ps->weapon )->usesEnergy &&
BG_InventoryContainsUpgrade( UP_BATTPACK, pm->ps->stats ) )
- ammo = (int)( (float)ammo * BATTPACK_MODIFIER );
-
- pm->ps->ammo = ammo;
- pm->ps->clips = clips;
+ pm->ps->ammo *= BATTPACK_MODIFIER;
//allow some time for the weapon to be raised
pm->ps->weaponstate = WEAPON_RAISING;
@@ -2832,19 +3067,18 @@ static void PM_Weapon( void )
}
// check for end of clip
- if( !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) &&
- ( !ammo || pm->ps->pm_flags & PMF_WEAPON_RELOAD ) && clips )
+ if( !BG_Weapon( pm->ps->weapon )->infiniteAmmo &&
+ ( pm->ps->ammo <= 0 || ( pm->ps->pm_flags & PMF_WEAPON_RELOAD ) ) &&
+ pm->ps->clips > 0 )
{
pm->ps->pm_flags &= ~PMF_WEAPON_RELOAD;
-
pm->ps->weaponstate = WEAPON_RELOADING;
//drop the weapon
PM_StartTorsoAnim( TORSO_DROP );
+ PM_StartWeaponAnim( WANIM_RELOAD );
- addTime = BG_FindReloadTimeForWeapon( pm->ps->weapon );
-
- pm->ps->weaponTime += addTime;
+ pm->ps->weaponTime += BG_Weapon( pm->ps->weapon )->reloadTime;
return;
}
@@ -2853,62 +3087,60 @@ static void PM_Weapon( void )
{
case WP_ALEVEL0:
//venom is only autohit
- attack1 = attack2 = attack3 = qfalse;
-
- if( !pm->autoWeaponHit[ pm->ps->weapon ] )
- {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
- return;
- }
- break;
+ return;
case WP_ALEVEL3:
case WP_ALEVEL3_UPG:
//pouncing has primary secondary AND autohit procedures
- attack1 = pm->cmd.buttons & BUTTON_ATTACK;
- attack2 = pm->cmd.buttons & BUTTON_ATTACK2;
- attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE;
-
- if( !pm->autoWeaponHit[ pm->ps->weapon ] && !attack1 && !attack2 && !attack3 )
- {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
+ // pounce is autohit
+ if( !attack1 && !attack2 && !attack3 )
return;
- }
break;
case WP_LUCIFER_CANNON:
- attack1 = pm->cmd.buttons & BUTTON_ATTACK;
- attack2 = pm->cmd.buttons & BUTTON_ATTACK2;
- attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE;
+ attack3 = qfalse;
- if( ( attack1 || pm->ps->stats[ STAT_MISC ] == 0 ) && !attack2 && !attack3 )
+ // Can't fire secondary while primary is charging
+ if( attack1 || pm->ps->stats[ STAT_MISC ] > 0 )
+ attack2 = qfalse;
+
+ if( ( attack1 || pm->ps->stats[ STAT_MISC ] == 0 ) && !attack2 )
{
- if( pm->ps->stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE )
+ pm->ps->weaponTime = 0;
+
+ // Charging
+ if( pm->ps->stats[ STAT_MISC ] < LCANNON_CHARGE_TIME_MAX )
{
- pm->ps->weaponTime = 0;
pm->ps->weaponstate = WEAPON_READY;
return;
}
- else
- attack1 = !attack1;
}
- //erp this looks confusing
- if( pm->ps->stats[ STAT_MISC ] > LCANNON_MIN_CHARGE )
- attack1 = !attack1;
+ if( pm->ps->stats[ STAT_MISC ] > LCANNON_CHARGE_TIME_MIN )
+ {
+ // Fire primary attack
+ attack1 = qtrue;
+ attack2 = qfalse;
+ }
else if( pm->ps->stats[ STAT_MISC ] > 0 )
{
+ // Not enough charge
pm->ps->stats[ STAT_MISC ] = 0;
pm->ps->weaponTime = 0;
pm->ps->weaponstate = WEAPON_READY;
return;
}
+ else if( !attack2 )
+ {
+ // Idle
+ pm->ps->weaponTime = 0;
+ pm->ps->weaponstate = WEAPON_READY;
+ return;
+ }
break;
case WP_MASS_DRIVER:
- attack1 = pm->cmd.buttons & BUTTON_ATTACK;
+ attack2 = attack3 = qfalse;
// attack2 is handled on the client for zooming (cg_view.c)
if( !attack1 )
@@ -2920,11 +3152,6 @@ static void PM_Weapon( void )
break;
default:
- //by default primary and secondary attacks are allowed
- attack1 = pm->cmd.buttons & BUTTON_ATTACK;
- attack2 = pm->cmd.buttons & BUTTON_ATTACK2;
- attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE;
-
if( !attack1 && !attack2 && !attack3 )
{
pm->ps->weaponTime = 0;
@@ -2933,29 +3160,22 @@ static void PM_Weapon( void )
}
break;
}
-
- if ( pm->ps->weapon == WP_LUCIFER_CANNON && pm->ps->stats[ STAT_MISC ] > 0 && attack3 )
- {
- attack1 = qtrue;
- attack3 = qfalse;
- }
-
- //TA: fire events for non auto weapons
+
+ // fire events for non auto weapons
if( attack3 )
{
- if( BG_WeaponHasThirdMode( pm->ps->weapon ) )
+ if( BG_Weapon( pm->ps->weapon )->hasThirdMode )
{
//hacky special case for slowblob
- if( pm->ps->weapon == WP_ALEVEL3_UPG && !ammo )
+ if( pm->ps->weapon == WP_ALEVEL3_UPG && !pm->ps->ammo )
{
- PM_AddEvent( EV_NOAMMO );
pm->ps->weaponTime += 200;
return;
}
pm->ps->generic1 = WPM_TERTIARY;
PM_AddEvent( EV_FIRE_WEAPON3 );
- addTime = BG_FindRepeatRate3ForWeapon( pm->ps->weapon );
+ addTime = BG_Weapon( pm->ps->weapon )->repeatRate3;
}
else
{
@@ -2967,11 +3187,11 @@ static void PM_Weapon( void )
}
else if( attack2 )
{
- if( BG_WeaponHasAltMode( pm->ps->weapon ) )
+ if( BG_Weapon( pm->ps->weapon )->hasAltMode )
{
pm->ps->generic1 = WPM_SECONDARY;
PM_AddEvent( EV_FIRE_WEAPON2 );
- addTime = BG_FindRepeatRate2ForWeapon( pm->ps->weapon );
+ addTime = BG_Weapon( pm->ps->weapon )->repeatRate2;
}
else
{
@@ -2985,10 +3205,10 @@ static void PM_Weapon( void )
{
pm->ps->generic1 = WPM_PRIMARY;
PM_AddEvent( EV_FIRE_WEAPON );
- addTime = BG_FindRepeatRate1ForWeapon( pm->ps->weapon );
+ addTime = BG_Weapon( pm->ps->weapon )->repeatRate1;
}
- //TA: fire events for autohit weapons
+ // fire events for autohit weapons
if( pm->autoWeaponHit[ pm->ps->weapon ] )
{
switch( pm->ps->weapon )
@@ -2996,14 +3216,14 @@ static void PM_Weapon( void )
case WP_ALEVEL0:
pm->ps->generic1 = WPM_PRIMARY;
PM_AddEvent( EV_FIRE_WEAPON );
- addTime = BG_FindRepeatRate1ForWeapon( pm->ps->weapon );
+ addTime = BG_Weapon( pm->ps->weapon )->repeatRate1;
break;
case WP_ALEVEL3:
case WP_ALEVEL3_UPG:
pm->ps->generic1 = WPM_SECONDARY;
PM_AddEvent( EV_FIRE_WEAPON2 );
- addTime = BG_FindRepeatRate2ForWeapon( pm->ps->weapon );
+ addTime = BG_Weapon( pm->ps->weapon )->repeatRate2;
break;
default:
@@ -3020,41 +3240,77 @@ static void PM_Weapon( void )
if( pm->ps->weaponstate == WEAPON_READY )
{
PM_StartTorsoAnim( TORSO_ATTACK );
+ PM_StartWeaponAnim( WANIM_ATTACK1 );
}
break;
case WP_BLASTER:
PM_StartTorsoAnim( TORSO_ATTACK2 );
+ PM_StartWeaponAnim( WANIM_ATTACK1 );
break;
default:
PM_StartTorsoAnim( TORSO_ATTACK );
+ PM_StartWeaponAnim( WANIM_ATTACK1 );
break;
}
}
else
{
- if( pm->ps->weapon == WP_ALEVEL4 )
- {
- //hack to get random attack animations
- //FIXME: does pm->ps->weaponTime cycle enough?
- int num = abs( pm->ps->weaponTime ) % 3;
+ int num = rand( );
- if( num == 0 )
- PM_ForceLegsAnim( NSPA_ATTACK1 );
- else if( num == 1 )
- PM_ForceLegsAnim( NSPA_ATTACK2 );
- else if( num == 2 )
- PM_ForceLegsAnim( NSPA_ATTACK3 );
- }
- else
+ //FIXME: it would be nice to have these hard coded policies in
+ // weapon.cfg
+ switch( pm->ps->weapon )
{
- if( attack1 )
- PM_ForceLegsAnim( NSPA_ATTACK1 );
- else if( attack2 )
- PM_ForceLegsAnim( NSPA_ATTACK2 );
- else if( attack3 )
- PM_ForceLegsAnim( NSPA_ATTACK3 );
+ case WP_ALEVEL1_UPG:
+ case WP_ALEVEL1:
+ if( attack1 )
+ {
+ num /= RAND_MAX / 6 + 1;
+ PM_ForceLegsAnim( NSPA_ATTACK1 );
+ PM_StartWeaponAnim( WANIM_ATTACK1 + num );
+ }
+ break;
+
+ case WP_ALEVEL2_UPG:
+ if( attack2 )
+ {
+ PM_ForceLegsAnim( NSPA_ATTACK2 );
+ PM_StartWeaponAnim( WANIM_ATTACK7 );
+ }
+ case WP_ALEVEL2:
+ if( attack1 )
+ {
+ num /= RAND_MAX / 6 + 1;
+ PM_ForceLegsAnim( NSPA_ATTACK1 );
+ PM_StartWeaponAnim( WANIM_ATTACK1 + num );
+ }
+ break;
+
+ case WP_ALEVEL4:
+ num /= RAND_MAX / 3 + 1;
+ PM_ForceLegsAnim( NSPA_ATTACK1 + num );
+ PM_StartWeaponAnim( WANIM_ATTACK1 + num );
+ break;
+
+ default:
+ if( attack1 )
+ {
+ PM_ForceLegsAnim( NSPA_ATTACK1 );
+ PM_StartWeaponAnim( WANIM_ATTACK1 );
+ }
+ else if( attack2 )
+ {
+ PM_ForceLegsAnim( NSPA_ATTACK2 );
+ PM_StartWeaponAnim( WANIM_ATTACK2 );
+ }
+ else if( attack3 )
+ {
+ PM_ForceLegsAnim( NSPA_ATTACK3 );
+ PM_StartWeaponAnim( WANIM_ATTACK3 );
+ }
+ break;
}
pm->ps->torsoTimer = TIMER_ATTACK;
@@ -3063,29 +3319,19 @@ static void PM_Weapon( void )
pm->ps->weaponstate = WEAPON_FIRING;
// take an ammo away if not infinite
- if( !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
+ if( !BG_Weapon( pm->ps->weapon )->infiniteAmmo ||
+ ( pm->ps->weapon == WP_ALEVEL3_UPG && attack3 ) )
{
- //special case for lCanon
+ // Special case for lcannon
if( pm->ps->weapon == WP_LUCIFER_CANNON && attack1 && !attack2 )
- {
- ammo -= (int)( ceil( ( (float)pm->ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE ) * 10.0f ) );
-
- //stay on the safe side
- if( ammo < 0 )
- ammo = 0;
- }
+ pm->ps->ammo -= ( pm->ps->stats[ STAT_MISC ] * LCANNON_CHARGE_AMMO +
+ LCANNON_CHARGE_TIME_MAX - 1 ) / LCANNON_CHARGE_TIME_MAX;
else
- ammo--;
+ pm->ps->ammo--;
- pm->ps->ammo = ammo;
- pm->ps->clips = clips;
- }
- else if( pm->ps->weapon == WP_ALEVEL3_UPG && attack3 )
- {
- //special case for slowblob
- ammo--;
- pm->ps->ammo = ammo;
- pm->ps->clips = clips;
+ // Stay on the safe side
+ if( pm->ps->ammo < 0 )
+ pm->ps->ammo = 0;
}
//FIXME: predicted angles miss a problem??
@@ -3114,14 +3360,21 @@ PM_Animate
*/
static void PM_Animate( void )
{
+ if( PM_Paralyzed( pm->ps->pm_type ) )
+ return;
+
if( pm->cmd.buttons & BUTTON_GESTURE )
{
+ if( pm->ps->tauntTimer > 0 )
+ return;
+
if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
{
if( pm->ps->torsoTimer == 0 )
{
PM_StartTorsoAnim( TORSO_GESTURE );
pm->ps->torsoTimer = TIMER_GESTURE;
+ pm->ps->tauntTimer = TIMER_GESTURE;
PM_AddEvent( EV_TAUNT );
}
@@ -3132,6 +3385,7 @@ static void PM_Animate( void )
{
PM_ForceLegsAnim( NSPA_GESTURE );
pm->ps->torsoTimer = TIMER_GESTURE;
+ pm->ps->tauntTimer = TIMER_GESTURE;
PM_AddEvent( EV_TAUNT );
}
@@ -3175,6 +3429,16 @@ static void PM_DropTimers( void )
if( pm->ps->torsoTimer < 0 )
pm->ps->torsoTimer = 0;
}
+
+ if( pm->ps->tauntTimer > 0 )
+ {
+ pm->ps->tauntTimer -= pml.msec;
+
+ if( pm->ps->tauntTimer < 0 )
+ {
+ pm->ps->tauntTimer = 0;
+ }
+ }
}
@@ -3193,7 +3457,7 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd )
vec3_t axis[ 3 ], rotaxis[ 3 ];
vec3_t tempang;
- if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION )
+ if( ps->pm_type == PM_INTERMISSION )
return; // no view changes at all
if( ps->pm_type != PM_SPECTATOR && ps->stats[ STAT_HEALTH ] <= 0 )
@@ -3202,7 +3466,21 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd )
// circularly clamp the angles with deltas
for( i = 0; i < 3; i++ )
{
- temp[ i ] = cmd->angles[ i ] + ps->delta_angles[ i ];
+ if( i == ROLL )
+ {
+ // Guard against speed hack
+ temp[ i ] = ps->delta_angles[ i ];
+
+#ifdef CGAME
+ // Assert here so that if cmd->angles[ i ] becomes non-zero
+ // for a legitimate reason we can tell where and why it's
+ // being ignored
+ assert( cmd->angles[ i ] == 0 );
+#endif
+
+ }
+ else
+ temp[ i ] = cmd->angles[ i ] + ps->delta_angles[ i ];
if( i == PITCH )
{
@@ -3226,7 +3504,7 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd )
if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ||
!BG_RotateAxis( ps->grapplePoint, axis, rotaxis, qfalse,
- ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) )
+ ps->eFlags & EF_WALLCLIMBCEILING ) )
AxisCopy( axis, rotaxis );
//convert the new axis back to angles
@@ -3238,7 +3516,7 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd )
while( tempang[ i ] > 180.0f )
tempang[ i ] -= 360.0f;
- while( tempang[ i ] < 180.0f )
+ while( tempang[ i ] < -180.0f )
tempang[ i ] += 360.0f;
}
@@ -3287,15 +3565,10 @@ void trap_SnapVector( float *v );
void PmoveSingle( pmove_t *pmove )
{
- int ammo, clips;
-
pm = pmove;
- ammo = pm->ps->ammo;
- clips = pm->ps->clips;
-
// this counter lets us debug movement problems with a journal
- // by setting a conditional breakpoint fot the previous frame
+ // by setting a conditional breakpoint for the previous frame
c_pmove++;
// clear results
@@ -3311,16 +3584,10 @@ void PmoveSingle( pmove_t *pmove )
if( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 )
pm->cmd.buttons &= ~BUTTON_WALKING;
- // set the talk balloon flag
- if( pm->cmd.buttons & BUTTON_TALK )
- pm->ps->eFlags |= EF_TALK;
- else
- pm->ps->eFlags &= ~EF_TALK;
-
// set the firing flag for continuous beam weapons
if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION &&
( pm->cmd.buttons & BUTTON_ATTACK ) &&
- ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
+ ( ( pm->ps->ammo > 0 || pm->ps->clips > 0 ) || BG_Weapon( pm->ps->weapon )->infiniteAmmo ) )
pm->ps->eFlags |= EF_FIRING;
else
pm->ps->eFlags &= ~EF_FIRING;
@@ -3328,7 +3595,7 @@ void PmoveSingle( pmove_t *pmove )
// set the firing flag for continuous beam weapons
if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION &&
( pm->cmd.buttons & BUTTON_ATTACK2 ) &&
- ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
+ ( ( pm->ps->ammo > 0 || pm->ps->clips > 0 ) || BG_Weapon( pm->ps->weapon )->infiniteAmmo ) )
pm->ps->eFlags |= EF_FIRING2;
else
pm->ps->eFlags &= ~EF_FIRING2;
@@ -3336,7 +3603,7 @@ void PmoveSingle( pmove_t *pmove )
// set the firing flag for continuous beam weapons
if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION &&
( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) &&
- ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
+ ( ( pm->ps->ammo > 0 || pm->ps->clips > 0 ) || BG_Weapon( pm->ps->weapon )->infiniteAmmo ) )
pm->ps->eFlags |= EF_FIRING3;
else
pm->ps->eFlags &= ~EF_FIRING3;
@@ -3355,7 +3622,9 @@ void PmoveSingle( pmove_t *pmove )
pmove->cmd.buttons = BUTTON_TALK;
pmove->cmd.forwardmove = 0;
pmove->cmd.rightmove = 0;
- pmove->cmd.upmove = 0;
+
+ if( pmove->cmd.upmove > 0 )
+ pmove->cmd.upmove = 0;
}
// clear all pmove local vars
@@ -3393,7 +3662,7 @@ void PmoveSingle( pmove_t *pmove )
else if( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) )
pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;
- if( pm->ps->pm_type >= PM_DEAD )
+ if( PM_Paralyzed( pm->ps->pm_type ) )
{
pm->cmd.forwardmove = 0;
pm->cmd.rightmove = 0;
@@ -3414,6 +3683,8 @@ void PmoveSingle( pmove_t *pmove )
{
PM_UpdateViewAngles( pm->ps, &pm->cmd );
PM_NoclipMove( );
+ PM_SetViewheight( );
+ PM_Weapon( );
PM_DropTimers( );
return;
}
@@ -3421,7 +3692,7 @@ void PmoveSingle( pmove_t *pmove )
if( pm->ps->pm_type == PM_FREEZE)
return; // no movement at all
- if( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION )
+ if( pm->ps->pm_type == PM_INTERMISSION )
return; // no movement at all
// set watertype, and waterlevel
@@ -3443,6 +3714,7 @@ void PmoveSingle( pmove_t *pmove )
PM_DeadMove( );
PM_DropTimers( );
+ PM_CheckDodge( );
if( pm->ps->pm_type == PM_JETPACK )
PM_JetPackMove( );
@@ -3454,9 +3726,9 @@ void PmoveSingle( pmove_t *pmove )
PM_LadderMove( );
else if( pml.walking )
{
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) &&
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_WALLCLIMBER ) &&
( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) )
- PM_ClimbMove( ); //TA: walking on any surface
+ PM_ClimbMove( ); // walking on any surface
else
PM_WalkMove( ); // walking on ground
}
@@ -3467,7 +3739,7 @@ void PmoveSingle( pmove_t *pmove )
// set groundentity, watertype, and waterlevel
PM_GroundTrace( );
- //TA: must update after every GroundTrace() - yet more clock cycles down the drain :( (14 vec rotations/frame)
+
// update the viewangles
PM_UpdateViewAngles( pm->ps, &pm->cmd );
@@ -3530,11 +3802,7 @@ void Pmove( pmove_t *pmove )
msec = 66;
}
-
pmove->cmd.serverTime = pmove->ps->commandTime + msec;
PmoveSingle( pmove );
-
- if( pmove->ps->pm_flags & PMF_JUMP_HELD )
- pmove->cmd.upmove = 20;
}
}
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 462bf95..f850a5d 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,15 +17,19 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
+#ifndef _BG_PUBLIC_H_
+#define _BG_PUBLIC_H_
+
// bg_public.h -- definitions shared by both the server game and client game modules
//tremulous balance header
-#include "tremulous.h"
+#include "qcommon/q_shared.h"
+#include "game/tremulous.h"
// because games can change separately from the main system version, we need a
// second version that must match between game and cgame
@@ -37,7 +42,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define MINS_Z -24
#define DEFAULT_VIEWHEIGHT 26
#define CROUCH_VIEWHEIGHT 12
-#define DEAD_VIEWHEIGHT -14 //TA: watch for mins[ 2 ] less than this causing
+#define DEAD_VIEWHEIGHT 4 // height from ground
+
+// player teams
+typedef enum
+{
+ TEAM_NONE,
+ TEAM_ALIENS,
+ TEAM_HUMANS,
+
+ NUM_TEAMS
+} team_t;
//
// config strings are a general means of communicating variable length strings
@@ -45,47 +60,42 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// CS_SERVERINFO and CS_SYSTEMINFO are defined in q_shared.h
-#define CS_MUSIC 2
-#define CS_MESSAGE 3 // from the map worldspawn's message field
-#define CS_MOTD 4 // g_motd string for server message of the day
-#define CS_WARMUP 5 // server time when the match will be restarted
-// 6 UNUSED
-// 7 UNUSED
-#define CS_VOTE_TIME 8
-#define CS_VOTE_STRING 9
-#define CS_VOTE_YES 10
-#define CS_VOTE_NO 11
-
-#define CS_TEAMVOTE_TIME 12
-#define CS_TEAMVOTE_STRING 14
-#define CS_TEAMVOTE_YES 16
-#define CS_TEAMVOTE_NO 18
-
-#define CS_GAME_VERSION 20
-#define CS_LEVEL_START_TIME 21 // so the timer only shows the current level
-#define CS_INTERMISSION 22 // when 1, fraglimit/timelimit has been hit and intermission will start in a second or two
-#define CS_WINNER 23 // string indicating round winner
-#define CS_SHADERSTATE 24
-#define CS_BOTINFO 25
-#define CS_CLIENTS_READY 26 //TA: following suggestion in STAT_ enum STAT_CLIENTS_READY becomes a configstring
-
-//TA: extra stuff:
-#define CS_BUILDPOINTS 28
-#define CS_STAGES 29
-#define CS_SPAWNS 30
-
-#define CS_MODELS 33
-#define CS_SOUNDS (CS_MODELS+MAX_MODELS)
-#define CS_SHADERS (CS_SOUNDS+MAX_SOUNDS)
-#define CS_PARTICLE_SYSTEMS (CS_SHADERS+MAX_GAME_SHADERS)
-#define CS_PLAYERS (CS_PARTICLE_SYSTEMS+MAX_GAME_PARTICLE_SYSTEMS)
-#define CS_PRECACHES (CS_PLAYERS+MAX_CLIENTS)
-#define CS_LOCATIONS (CS_PRECACHES+MAX_CLIENTS)
-
-#define CS_MAX (CS_LOCATIONS+MAX_LOCATIONS)
-
-#if (CS_MAX) > MAX_CONFIGSTRINGS
-#error overflow: (CS_MAX) > MAX_CONFIGSTRINGS
+enum
+{
+ CS_MUSIC = 2,
+ CS_MESSAGE, // from the map worldspawn's message field
+ CS_MOTD, // g_motd string for server message of the day
+ CS_WARMUP = 5, // server time when the match will be restarted !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!!
+
+ CS_VOTE_TIME, // Vote stuff each needs NUM_TEAMS slots
+ CS_VOTE_STRING = CS_VOTE_TIME + NUM_TEAMS,
+ CS_VOTE_YES = CS_VOTE_STRING + NUM_TEAMS,
+ CS_VOTE_NO = CS_VOTE_YES + NUM_TEAMS,
+ CS_VOTE_CALLER = CS_VOTE_NO + NUM_TEAMS,
+
+ CS_GAME_VERSION = CS_VOTE_CALLER + NUM_TEAMS,
+ CS_LEVEL_START_TIME, // so the timer only shows the current level
+ CS_INTERMISSION, // when 1, fraglimit/timelimit has been hit and intermission will start in a second or two
+ CS_WINNER , // string indicating round winner
+ CS_SHADERSTATE,
+ CS_BOTINFO,
+ CS_CLIENTS_READY,
+
+ CS_ALIEN_STAGES,
+ CS_HUMAN_STAGES,
+
+ CS_MODELS,
+ CS_SOUNDS = CS_MODELS + MAX_MODELS,
+ CS_SHADERS = CS_SOUNDS + MAX_SOUNDS,
+ CS_PARTICLE_SYSTEMS = CS_SHADERS + MAX_GAME_SHADERS,
+ CS_PLAYERS = CS_PARTICLE_SYSTEMS + MAX_GAME_PARTICLE_SYSTEMS,
+ CS_LOCATIONS = CS_PLAYERS + MAX_CLIENTS,
+
+ CS_MAX = CS_LOCATIONS + MAX_LOCATIONS
+};
+
+#if CS_MAX > MAX_CONFIGSTRINGS
+#error overflow: CS_MAX > MAX_CONFIGSTRINGS
#endif
typedef enum
@@ -112,39 +122,45 @@ typedef enum
PM_NOCLIP, // noclip movement
PM_SPECTATOR, // still run into walls
PM_JETPACK, // jetpack physics
- PM_GRABBED, // like dead, but for when the player is still live
+ PM_GRABBED, // like dead, but for when the player is still alive
PM_DEAD, // no acceleration or turning, but free falling
PM_FREEZE, // stuck in place with no control
- PM_INTERMISSION, // no movement or status bar
- PM_SPINTERMISSION // no movement or status bar
+ PM_INTERMISSION // no movement or status bar
} pmtype_t;
+// pmtype_t categories
+#define PM_Paralyzed( x ) ( (x) == PM_DEAD || (x) == PM_FREEZE ||\
+ (x) == PM_INTERMISSION )
+#define PM_Alive( x ) ( (x) == PM_NORMAL || (x) == PM_JETPACK ||\
+ (x) == PM_GRABBED )
+
typedef enum
{
WEAPON_READY,
WEAPON_RAISING,
WEAPON_DROPPING,
WEAPON_FIRING,
- WEAPON_RELOADING
+ WEAPON_RELOADING,
} weaponstate_t;
// pmove->pm_flags
-#define PMF_DUCKED 1
-#define PMF_JUMP_HELD 2
-#define PMF_CROUCH_HELD 4
-#define PMF_BACKWARDS_JUMP 8 // go into backwards land
-#define PMF_BACKWARDS_RUN 16 // coast down to backwards run
-#define PMF_TIME_LAND 32 // pm_time is time before rejump
-#define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time
-#define PMF_TIME_WATERJUMP 256 // pm_time is waterjump
-#define PMF_RESPAWNED 512 // clear after attack and jump buttons come up
-#define PMF_USE_ITEM_HELD 1024
-#define PMF_WEAPON_RELOAD 2048 //TA: force a weapon switch
-#define PMF_FOLLOW 4096 // spectate following another player
-#define PMF_QUEUED 8192 //TA: player is queued
-#define PMF_TIME_WALLJUMP 16384 //TA: for limiting wall jumping
-#define PMF_CHARGE 32768 //TA: keep track of pouncing
-#define PMF_WEAPON_SWITCH 65536 //TA: force a weapon switch
+#define PMF_DUCKED 0x000001
+#define PMF_JUMP_HELD 0x000002
+#define PMF_CROUCH_HELD 0x000004
+#define PMF_BACKWARDS_JUMP 0x000008 // go into backwards land
+#define PMF_BACKWARDS_RUN 0x000010 // coast down to backwards run
+#define PMF_TIME_LAND 0x000020 // pm_time is time before rejump
+#define PMF_TIME_KNOCKBACK 0x000040 // pm_time is an air-accelerate only time
+#define PMF_TIME_WATERJUMP 0x000080 // pm_time is waterjump
+#define PMF_RESPAWNED 0x000100 // clear after attack and jump buttons come up
+#define PMF_USE_ITEM_HELD 0x000200
+#define PMF_WEAPON_RELOAD 0x000400 // force a weapon switch
+#define PMF_FOLLOW 0x000800 // spectate following another player
+#define PMF_QUEUED 0x001000 // player is queued
+#define PMF_TIME_WALLJUMP 0x002000 // for limiting wall jumping
+#define PMF_CHARGE 0x004000 // keep track of pouncing
+#define PMF_WEAPON_SWITCH 0x008000 // force a weapon switch
+#define PMF_SPRINTHELD 0x010000
#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK|PMF_TIME_WALLJUMP)
@@ -152,10 +168,11 @@ typedef enum
typedef struct
{
int pouncePayload;
+ float fallVelocity;
} pmoveExt_t;
#define MAXTOUCH 32
-typedef struct
+typedef struct pmove_s
{
// state (in / out)
playerState_t *ps;
@@ -165,7 +182,7 @@ typedef struct
int tracemask; // collide against these types of surfaces
int debugLevel; // if set, diagnostic output will be printed
qboolean noFootsteps; // if the game is setup for no footsteps by the server
- qboolean autoWeaponHit[ 32 ]; //FIXME: TA: remind myself later this might be a problem
+ qboolean autoWeaponHit[ 32 ];
int framecount;
@@ -206,49 +223,43 @@ typedef enum
{
STAT_HEALTH,
STAT_ITEMS,
- STAT_SLOTS, //TA: tracks the amount of stuff human players are carrying
STAT_ACTIVEITEMS,
- STAT_WEAPONS, // 16 bit fields
- STAT_WEAPONS2, //TA: another 16 bits to push the max weapon count up
- STAT_MAX_HEALTH, // health / armor limit, changable by handicap
- STAT_PCLASS, //TA: player class (for aliens AND humans)
- STAT_PTEAM, //TA: player team
- STAT_STAMINA, //TA: stamina (human only)
- STAT_STATE, //TA: client states e.g. wall climbing
- STAT_MISC, //TA: for uh...misc stuff
- STAT_BUILDABLE, //TA: which ghost model to display for building
- STAT_BOOSTTIME, //TA: time left for boost (alien only)
- STAT_FALLDIST, //TA: the distance the player fell
- STAT_VIEWLOCK //TA: direction to lock the view in
+ STAT_WEAPON, // current primary weapon
+ STAT_MAX_HEALTH,// health / armor limit, changable by handicap
+ STAT_CLASS, // player class (for aliens AND humans)
+ STAT_TEAM, // player team
+ STAT_STAMINA, // stamina (human only)
+ STAT_STATE, // client states e.g. wall climbing
+ STAT_MISC, // for uh...misc stuff (pounce, trample, lcannon)
+ STAT_BUILDABLE, // which ghost model to display for building
+ STAT_FALLDIST, // the distance the player fell
+ STAT_VIEWLOCK // direction to lock the view in
+ // netcode has space for 3 more
} statIndex_t;
#define SCA_WALLCLIMBER 0x00000001
#define SCA_TAKESFALLDAMAGE 0x00000002
#define SCA_CANZOOM 0x00000004
-#define SCA_NOWEAPONDRIFT 0x00000008
-#define SCA_FOVWARPS 0x00000010
-#define SCA_ALIENSENSE 0x00000020
-#define SCA_CANUSELADDERS 0x00000040
-#define SCA_WALLJUMPER 0x00000080
+#define SCA_FOVWARPS 0x00000008
+#define SCA_ALIENSENSE 0x00000010
+#define SCA_CANUSELADDERS 0x00000020
+#define SCA_WALLJUMPER 0x00000040
#define SS_WALLCLIMBING 0x00000001
-#define SS_WALLCLIMBINGCEILING 0x00000002
-#define SS_CREEPSLOWED 0x00000004
-#define SS_SPEEDBOOST 0x00000008
-#define SS_INFESTING 0x00000010
-#define SS_GRABBED 0x00000020
-#define SS_BLOBLOCKED 0x00000040
-#define SS_POISONED 0x00000080
-#define SS_HOVELING 0x00000100
-#define SS_BOOSTED 0x00000200
-#define SS_SLOWLOCKED 0x00000400
-#define SS_POISONCLOUDED 0x00000800
-#define SS_MEDKIT_ACTIVE 0x00001000
-#define SS_CHARGING 0x00002000
-
-#define SB_VALID_TOGGLEBIT 0x00004000
-
-#define MAX_STAMINA 1000
+#define SS_CREEPSLOWED 0x00000002
+#define SS_SPEEDBOOST 0x00000004
+#define SS_GRABBED 0x00000008
+#define SS_BLOBLOCKED 0x00000010
+#define SS_POISONED 0x00000020
+#define SS_BOOSTED 0x00000040
+#define SS_BOOSTEDWARNING 0x00000080 // booster poison is running out
+#define SS_SLOWLOCKED 0x00000100
+#define SS_CHARGING 0x00000200
+#define SS_HEALING_ACTIVE 0x00000400 // medistat for humans, creep for aliens
+#define SS_HEALING_2X 0x00000800 // medkit or double healing rate
+#define SS_HEALING_3X 0x00001000 // triple healing rate
+
+#define SB_VALID_TOGGLEBIT 0x00002000
// player_state->persistant[] indexes
// these fields are the only part of player_state that isn't
@@ -257,63 +268,53 @@ typedef enum
{
PERS_SCORE, // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!!
PERS_HITS, // total points damage inflicted so damage beeps can sound on change
- PERS_UNUSED, // used to be PERS_RANK, no longer used
- PERS_TEAM,
+ PERS_SPAWNS, // how many spawns your team has
+ PERS_SPECSTATE,
PERS_SPAWN_COUNT, // incremented every respawn
PERS_ATTACKER, // clientnum of last damage inflicter
PERS_KILLED, // count of the number of times you died
- //TA:
PERS_STATE,
PERS_CREDIT, // human credit
- PERS_BANK, // human credit in the bank
PERS_QUEUEPOS, // position in the spawn queue
- PERS_NEWWEAPON // weapon to switch to
+ PERS_NEWWEAPON, // weapon to switch to
+ PERS_BP,
+ PERS_MARKEDBP
+ // netcode has space for 3 more
} persEnum_t;
#define PS_WALLCLIMBINGFOLLOW 0x00000001
#define PS_WALLCLIMBINGTOGGLE 0x00000002
#define PS_NONSEGMODEL 0x00000004
+#define PS_SPRINTTOGGLE 0x00000008
// entityState_t->eFlags
-#define EF_DEAD 0x00000001 // don't draw a foe marker over players with EF_DEAD
-#define EF_TELEPORT_BIT 0x00000002 // toggled every time the origin abruptly changes
-#define EF_PLAYER_EVENT 0x00000004
-#define EF_BOUNCE 0x00000008 // for missiles
-#define EF_BOUNCE_HALF 0x00000010 // for missiles
-#define EF_NO_BOUNCE_SOUND 0x00000020 // for missiles
-#define EF_WALLCLIMB 0x00000040 // TA: wall walking
-#define EF_WALLCLIMBCEILING 0x00000080 // TA: wall walking ceiling hack
-#define EF_NODRAW 0x00000100 // may have an event, but no model (unspawned items)
-#define EF_FIRING 0x00000200 // for lightning gun
-#define EF_FIRING2 0x00000400 // alt fire
-#define EF_FIRING3 0x00000800 // third fire
-#define EF_MOVER_STOP 0x00001000 // will push otherwise
-#define EF_TALK 0x00002000 // draw a talk balloon
-#define EF_CONNECTION 0x00004000 // draw a connection trouble sprite
-#define EF_VOTED 0x00008000 // already cast a vote
-#define EF_TEAMVOTED 0x00010000 // already cast a vote
-#define EF_BLOBLOCKED 0x00020000 // TA: caught by a trapper
-#define EF_REAL_LIGHT 0x00040000 // TA: light sprites according to ambient light
-#define EF_DBUILDER 0x00080000 // designated builder protection
-
-typedef enum
-{
- PW_NONE,
-
- PW_QUAD,
- PW_BATTLESUIT,
- PW_HASTE,
- PW_INVIS,
- PW_REGEN,
- PW_FLIGHT,
-
- PW_REDFLAG,
- PW_BLUEFLAG,
- PW_BALL,
-
- PW_NUM_POWERUPS
-} powerup_t;
+// notice that some flags are overlapped, so their meaning depends on context
+#define EF_DEAD 0x0001 // don't draw a foe marker over players with EF_DEAD
+#define EF_TELEPORT_BIT 0x0002 // toggled every time the origin abruptly changes
+#define EF_PLAYER_EVENT 0x0004 // only used for eType > ET_EVENTS
+
+// for missiles:
+#define EF_BOUNCE 0x0008 // for missiles
+#define EF_BOUNCE_HALF 0x0010 // for missiles
+#define EF_NO_BOUNCE_SOUND 0x0020 // for missiles
+
+// buildable flags:
+#define EF_B_SPAWNED 0x0008
+#define EF_B_POWERED 0x0010
+#define EF_B_MARKED 0x0020
+
+#define EF_WARN_CHARGE 0x0020 // Lucifer Cannon is about to overcharge
+#define EF_WALLCLIMB 0x0040 // wall walking
+#define EF_WALLCLIMBCEILING 0x0080 // wall walking ceiling hack
+#define EF_NODRAW 0x0100 // may have an event, but no model (unspawned items)
+#define EF_FIRING 0x0200 // for lightning gun
+#define EF_FIRING2 0x0400 // alt fire
+#define EF_FIRING3 0x0800 // third fire
+#define EF_MOVER_STOP 0x1000 // will push otherwise
+#define EF_POISONCLOUDED 0x2000 // player hit with basilisk gas
+#define EF_CONNECTION 0x4000 // draw a connection trouble sprite
+#define EF_BLOBLOCKED 0x8000 // caught by a trapper
typedef enum
{
@@ -358,8 +359,8 @@ typedef enum
WP_LAS_GUN,
WP_MASS_DRIVER,
WP_CHAINGUN,
- WP_PULSE_RIFLE,
WP_FLAMER,
+ WP_PULSE_RIFLE,
WP_LUCIFER_CANNON,
WP_GRENADE,
@@ -371,7 +372,6 @@ typedef enum
//build weapons must remain in a block
WP_ABUILD,
WP_ABUILD2,
- WP_HBUILD2,
WP_HBUILD,
//ok?
@@ -395,17 +395,7 @@ typedef enum
UP_NUM_UPGRADES
} upgrade_t;
-typedef enum
-{
- WUT_NONE,
-
- WUT_ALIENS,
- WUT_HUMANS,
-
- WUT_NUM_TEAMS
-} WUTeam_t;
-
-//TA: bitmasks for upgrade slots
+// bitmasks for upgrade slots
#define SLOT_NONE 0x00000000
#define SLOT_HEAD 0x00000001
#define SLOT_TORSO 0x00000002
@@ -428,8 +418,6 @@ typedef enum
BA_A_BOOSTER,
BA_A_HIVE,
- BA_A_HOVEL,
-
BA_H_SPAWN,
BA_H_MGTURRET,
@@ -447,30 +435,13 @@ typedef enum
typedef enum
{
- BIT_NONE,
-
- BIT_ALIENS,
- BIT_HUMANS,
-
- BIT_NUM_TEAMS
-} buildableTeam_t;
-
-#define B_HEALTH_BITS 5
-#define B_HEALTH_MASK ((1<<B_HEALTH_BITS)-1)
-
-#define B_DCCED_TOGGLEBIT 0x00000000
-#define B_SPAWNED_TOGGLEBIT 0x00000020
-#define B_POWERED_TOGGLEBIT 0x00000040
-#define B_MARKED_TOGGLEBIT 0x00000080
-
-
-// reward sounds (stored in ps->persistant[PERS_PLAYEREVENTS])
-#define PLAYEREVENT_DENIEDREWARD 0x0001
-#define PLAYEREVENT_GAUNTLETREWARD 0x0002
-#define PLAYEREVENT_HOLYSHIT 0x0004
+ RMT_SPHERE,
+ RMT_SPHERICAL_CONE_64,
+ RMT_SPHERICAL_CONE_240
+} rangeMarkerType_t;
// entityState_t->event values
-// entity events are for effects that take place reletive
+// entity events are for effects that take place relative
// to an existing entities origin. Very network efficient.
// two bits at the top of the entityState->event field
@@ -484,6 +455,8 @@ typedef enum
#define EVENT_VALID_MSEC 300
+const char *BG_EventName( int num );
+
typedef enum
{
EV_NONE,
@@ -522,7 +495,7 @@ typedef enum
EV_FIRE_WEAPON2,
EV_FIRE_WEAPON3,
- EV_PLAYER_RESPAWN, //TA: for fovwarp effects
+ EV_PLAYER_RESPAWN, // for fovwarp effects
EV_PLAYER_TELEPORT_IN,
EV_PLAYER_TELEPORT_OUT,
@@ -535,6 +508,7 @@ typedef enum
EV_BULLET_HIT_WALL,
EV_SHOTGUN,
+ EV_MASS_DRIVER,
EV_MISSILE_HIT,
EV_MISSILE_MISS,
@@ -543,8 +517,8 @@ typedef enum
EV_BULLET, // otherEntity is the shooter
EV_LEV1_GRAB,
- EV_LEV4_CHARGE_PREPARE,
- EV_LEV4_CHARGE_START,
+ EV_LEV4_TRAMPLE_PREPARE,
+ EV_LEV4_TRAMPLE_START,
EV_PAIN,
EV_DEATH1,
@@ -552,13 +526,13 @@ typedef enum
EV_DEATH3,
EV_OBITUARY,
- EV_GIB_PLAYER, // gib a previously living player
+ EV_GIB_PLAYER,
- EV_BUILD_CONSTRUCT, //TA
- EV_BUILD_DESTROY, //TA
- EV_BUILD_DELAY, //TA: can't build yet
- EV_BUILD_REPAIR, //TA: repairing buildable
- EV_BUILD_REPAIRED, //TA: buildable has full health
+ EV_BUILD_CONSTRUCT,
+ EV_BUILD_DESTROY,
+ EV_BUILD_DELAY, // can't build yet
+ EV_BUILD_REPAIR, // repairing buildable
+ EV_BUILD_REPAIRED, // buildable has full health
EV_HUMAN_BUILDABLE_EXPLOSION,
EV_ALIEN_BUILDABLE_EXPLOSION,
EV_ALIEN_ACIDTUBE,
@@ -572,73 +546,91 @@ typedef enum
EV_STOPLOOPINGSOUND,
EV_TAUNT,
- EV_OVERMIND_ATTACK, //TA: overmind under attack
- EV_OVERMIND_DYING, //TA: overmind close to death
- EV_OVERMIND_SPAWNS, //TA: overmind needs spawns
+ EV_OVERMIND_ATTACK, // overmind under attack
+ EV_OVERMIND_DYING, // overmind close to death
+ EV_OVERMIND_SPAWNS, // overmind needs spawns
+
+ EV_DCC_ATTACK, // dcc under attack
- EV_DCC_ATTACK, //TA: dcc under attack
+ EV_MGTURRET_SPINUP, // turret spinup sound should play
- EV_RPTUSE_SOUND //TA: trigger a sound
+ EV_RPTUSE_SOUND, // trigger a sound
+ EV_LEV2_ZAP
} entity_event_t;
typedef enum
{
+ MN_NONE,
+
MN_TEAM,
MN_A_TEAMFULL,
MN_H_TEAMFULL,
+ MN_A_TEAMLOCKED,
+ MN_H_TEAMLOCKED,
+ MN_PLAYERLIMIT,
+
+ // cmd stuff
+ MN_CMD_CHEAT,
+ MN_CMD_CHEAT_TEAM,
+ MN_CMD_TEAM,
+ MN_CMD_SPEC,
+ MN_CMD_ALIEN,
+ MN_CMD_HUMAN,
+ MN_CMD_ALIVE,
//alien stuff
MN_A_CLASS,
MN_A_BUILD,
MN_A_INFEST,
- MN_A_HOVEL_OCCUPIED,
- MN_A_HOVEL_BLOCKED,
MN_A_NOEROOM,
MN_A_TOOCLOSE,
MN_A_NOOVMND_EVOLVE,
+ MN_A_EVOLVEBUILDTIMER,
+ MN_A_CANTEVOLVE,
+ MN_A_EVOLVEWALLWALK,
+ MN_A_UNKNOWNCLASS,
+ MN_A_CLASSNOTSPAWN,
+ MN_A_CLASSNOTALLOWED,
+ MN_A_CLASSNOTATSTAGE,
+
+ //shared build
+ MN_B_NOROOM,
+ MN_B_NORMAL,
+ MN_B_CANNOT,
+ MN_B_LASTSPAWN,
+ MN_B_SUDDENDEATH,
+ MN_B_REVOKED,
+ MN_B_SURRENDER,
//alien build
- MN_A_SPWNWARN,
- MN_A_OVERMIND,
- MN_A_NOASSERT,
+ MN_A_ONEOVERMIND,
+ MN_A_NOBP,
MN_A_NOCREEP,
MN_A_NOOVMND,
- MN_A_NOROOM,
- MN_A_NORMAL,
- MN_A_HOVEL,
- MN_A_HOVEL_EXIT,
//human stuff
MN_H_SPAWN,
MN_H_BUILD,
MN_H_ARMOURY,
+ MN_H_UNKNOWNITEM,
MN_H_NOSLOTS,
MN_H_NOFUNDS,
MN_H_ITEMHELD,
+ MN_H_NOARMOURYHERE,
+ MN_H_NOENERGYAMMOHERE,
+ MN_H_NOROOMBSUITON,
+ MN_H_NOROOMBSUITOFF,
+ MN_H_ARMOURYBUILDTIMER,
+ MN_H_DEADTOCLASS,
+ MN_H_UNKNOWNSPAWNITEM,
//human build
- MN_H_REPEATER,
- MN_H_NOPOWER,
+ MN_H_NOPOWERHERE,
+ MN_H_NOBP,
MN_H_NOTPOWERED,
MN_H_NODCC,
- MN_H_REACTOR,
- MN_H_NOROOM,
- MN_H_NORMAL,
- MN_H_TNODEWARN,
- MN_H_RPTWARN,
- MN_H_RPTWARN2,
-
- //not used
- MN_A_TEAMCHANGEBUILDTIMER,
- MN_H_TEAMCHANGEBUILDTIMER,
-
- MN_A_EVOLVEBUILDTIMER,
-
- MN_H_NOENERGYAMMOHERE,
- MN_H_NOARMOURYHERE,
- MN_H_NOROOMBSUITON,
- MN_H_NOROOMBSUITOFF,
- MN_H_ARMOURYBUILDTIMER
+ MN_H_ONEREACTOR,
+ MN_H_RPTPOWERHERE,
} dynMenu_t;
// animations
@@ -744,7 +736,7 @@ typedef enum
MAX_NONSEG_PLAYER_TOTALANIMATIONS
} nonSegPlayerAnimNumber_t;
-//TA: for buildable animations
+// for buildable animations
typedef enum
{
BANIM_NONE,
@@ -772,6 +764,28 @@ typedef enum
MAX_BUILDABLE_ANIMATIONS
} buildableAnimNumber_t;
+typedef enum
+{
+ WANIM_NONE,
+
+ WANIM_IDLE,
+
+ WANIM_DROP,
+ WANIM_RELOAD,
+ WANIM_RAISE,
+
+ WANIM_ATTACK1,
+ WANIM_ATTACK2,
+ WANIM_ATTACK3,
+ WANIM_ATTACK4,
+ WANIM_ATTACK5,
+ WANIM_ATTACK6,
+ WANIM_ATTACK7,
+ WANIM_ATTACK8,
+
+ MAX_WEAPON_ANIMATIONS
+} weaponAnimNumber_t;
+
typedef struct animation_s
{
int firstFrame;
@@ -789,22 +803,10 @@ typedef struct animation_s
#define ANIM_TOGGLEBIT 0x80
#define ANIM_FORCEBIT 0x40
-
-typedef enum
-{
- TEAM_FREE,
- TEAM_SPECTATOR,
-
- TEAM_NUM_TEAMS
-} team_t;
-
// Time between location updates
-#define TEAM_LOCATION_UPDATE_TIME 1000
+#define TEAM_LOCATION_UPDATE_TIME 500
-// How many players on the overlay
-#define TEAM_MAXOVERLAY 32
-
-//TA: player classes
+// player classes
typedef enum
{
PCL_NONE,
@@ -828,19 +830,30 @@ typedef enum
PCL_HUMAN_BSUIT,
PCL_NUM_CLASSES
-} pClass_t;
-
+} class_t;
-//TA: player teams
+// spectator state
typedef enum
{
- PTE_NONE,
- PTE_ALIENS,
- PTE_HUMANS,
-
- PTE_NUM_TEAMS
-} pTeam_t;
-
+ SPECTATOR_NOT,
+ SPECTATOR_FREE,
+ SPECTATOR_LOCKED,
+ SPECTATOR_FOLLOW,
+ SPECTATOR_SCOREBOARD
+} spectatorState_t;
+
+// modes of text communication
+typedef enum
+{
+ SAY_ALL,
+ SAY_TEAM,
+ SAY_PRIVMSG,
+ SAY_TPRIVMSG,
+ SAY_AREA,
+ SAY_ADMINS,
+ SAY_ADMINS_PUBLIC,
+ SAY_RAW
+} saymode_t;
// means of death
typedef enum
@@ -879,7 +892,8 @@ typedef enum
MOD_LEVEL2_CLAW,
MOD_LEVEL2_ZAP,
MOD_LEVEL4_CLAW,
- MOD_LEVEL4_CHARGE,
+ MOD_LEVEL4_TRAMPLE,
+ MOD_LEVEL4_CRUSH,
MOD_SLOWBLOB,
MOD_POISON,
@@ -893,42 +907,27 @@ typedef enum
MOD_ASPAWN,
MOD_ATUBE,
MOD_OVERMIND,
- MOD_SLAP
+ MOD_DECONSTRUCT,
+ MOD_REPLACE,
+ MOD_NOCREEP
} meansOfDeath_t;
//---------------------------------------------------------
-//TA: player class record
+// player class record
typedef struct
{
- int classNum;
+ class_t number;
- char *className;
- char *humanName;
-
- char *modelName;
- float modelScale;
- char *skinName;
- float shadowScale;
-
- char *hudName;
+ char *name;
+ char *info;
int stages;
- vec3_t mins;
- vec3_t maxs;
- vec3_t crouchMaxs;
- vec3_t deadMins;
- vec3_t deadMaxs;
- float zOffset;
-
- int viewheight;
- int crouchViewheight;
-
int health;
float fallDamage;
- int regenRate;
+ float regenRate;
int abilities;
@@ -939,6 +938,7 @@ typedef struct
int fov;
float bob;
float bobCycle;
+ float landBob;
int steptime;
float speed;
@@ -971,7 +971,8 @@ typedef struct
int viewheight;
int crouchViewheight;
float zOffset;
-} classAttributeOverrides_t;
+ vec3_t shoulderOffsets;
+} classConfig_t;
//stages
typedef enum
@@ -983,59 +984,54 @@ typedef enum
#define MAX_BUILDABLE_MODELS 4
-//TA: buildable item record
+// buildable item record
typedef struct
{
- int buildNum;
+ buildable_t number;
- char *buildName;
- char *humanName;
- char *entityName;
+ char *name;
+ char *humanName;
+ char *info;
+ char *entityName;
- char *models[ MAX_BUILDABLE_MODELS ];
- float modelScale;
+ trType_t traj;
+ float bounce;
- vec3_t mins;
- vec3_t maxs;
- float zOffset;
+ int buildPoints;
+ int stages;
- trType_t traj;
- float bounce;
+ int health;
+ int regenRate;
- int buildPoints;
- int stages;
+ int splashDamage;
+ int splashRadius;
- int health;
- int regenRate;
-
- int splashDamage;
- int splashRadius;
+ int meansOfDeath;
- int meansOfDeath;
+ team_t team;
+ weapon_t buildWeapon;
- int team;
- weapon_t buildWeapon;
+ int idleAnim;
- int idleAnim;
+ int nextthink;
+ int buildTime;
+ qboolean usable;
- int nextthink;
- int buildTime;
- qboolean usable;
+ int turretRange;
+ int turretFireSpeed;
+ weapon_t turretProjType;
- int turretRange;
- int turretFireSpeed;
- weapon_t turretProjType;
+ float minNormal;
+ qboolean invertNormal;
- float minNormal;
- qboolean invertNormal;
+ qboolean creepTest;
+ int creepSize;
- qboolean creepTest;
- int creepSize;
-
- qboolean dccTest;
- qboolean transparentTest;
- qboolean reactorTest;
- qboolean replaceable;
+ qboolean dccTest;
+ qboolean transparentTest;
+ qboolean uniqueTest;
+
+ int value;
} buildableAttributes_t;
typedef struct
@@ -1046,20 +1042,21 @@ typedef struct
vec3_t mins;
vec3_t maxs;
float zOffset;
-} buildableAttributeOverrides_t;
+} buildableConfig_t;
-//TA: weapon record
+// weapon record
typedef struct
{
- int weaponNum;
+ weapon_t number;
int price;
int stages;
int slots;
- char *weaponName;
- char *weaponHumanName;
+ char *name;
+ char *humanName;
+ char *info;
int maxAmmo;
int maxClips;
@@ -1081,38 +1078,34 @@ typedef struct
qboolean purchasable;
qboolean longRanged;
- int buildDelay;
-
- WUTeam_t team;
+ team_t team;
} weaponAttributes_t;
-//TA: upgrade record
+// upgrade record
typedef struct
{
- int upgradeNum;
+ upgrade_t number;
int price;
int stages;
int slots;
- char *upgradeName;
- char *upgradeHumanName;
+ char *name;
+ char *humanName;
+ char *info;
char *icon;
qboolean purchasable;
qboolean usable;
- WUTeam_t team;
+ team_t team;
} upgradeAttributes_t;
-
-//TA:
qboolean BG_WeaponIsFull( weapon_t weapon, int stats[ ], int ammo, int clips );
-void BG_AddWeaponToInventory( int weapon, int stats[ ] );
-void BG_RemoveWeaponFromInventory( int weapon, int stats[ ] );
qboolean BG_InventoryContainsWeapon( int weapon, int stats[ ] );
+int BG_SlotsForInventory( int stats[ ] );
void BG_AddUpgradeToInventory( int item, int stats[ ] );
void BG_RemoveUpgradeFromInventory( int item, int stats[ ] );
qboolean BG_InventoryContainsUpgrade( int item, int stats[ ] );
@@ -1121,122 +1114,60 @@ void BG_DeactivateUpgrade( int item, int stats[ ] );
qboolean BG_UpgradeIsActive( int item, int stats[ ] );
qboolean BG_RotateAxis( vec3_t surfNormal, vec3_t inAxis[ 3 ],
vec3_t outAxis[ 3 ], qboolean inverse, qboolean ceiling );
+void BG_GetClientNormal( const playerState_t *ps, vec3_t normal );
+void BG_GetClientViewOrigin( const playerState_t *ps, vec3_t viewOrigin );
void BG_PositionBuildableRelativeToPlayer( const playerState_t *ps,
const vec3_t mins, const vec3_t maxs,
void (*trace)( trace_t *, const vec3_t, const vec3_t,
const vec3_t, const vec3_t, int, int ),
vec3_t outOrigin, vec3_t outAngles, trace_t *tr );
-int BG_GetValueOfHuman( playerState_t *ps );
-int BG_GetValueOfEquipment( playerState_t *ps );
-
-int BG_FindBuildNumForName( char *name );
-int BG_FindBuildNumForEntityName( char *name );
-char *BG_FindNameForBuildable( int bclass );
-char *BG_FindHumanNameForBuildable( int bclass );
-char *BG_FindEntityNameForBuildable( int bclass );
-char *BG_FindModelsForBuildable( int bclass, int modelNum );
-float BG_FindModelScaleForBuildable( int bclass );
-void BG_FindBBoxForBuildable( int bclass, vec3_t mins, vec3_t maxs );
-float BG_FindZOffsetForBuildable( int pclass );
-int BG_FindHealthForBuildable( int bclass );
-int BG_FindRegenRateForBuildable( int bclass );
-trType_t BG_FindTrajectoryForBuildable( int bclass );
-float BG_FindBounceForBuildable( int bclass );
-int BG_FindBuildPointsForBuildable( int bclass );
-qboolean BG_FindStagesForBuildable( int bclass, stage_t stage );
-int BG_FindSplashDamageForBuildable( int bclass );
-int BG_FindSplashRadiusForBuildable( int bclass );
-int BG_FindMODForBuildable( int bclass );
-int BG_FindTeamForBuildable( int bclass );
-weapon_t BG_FindBuildWeaponForBuildable( int bclass );
-int BG_FindAnimForBuildable( int bclass );
-int BG_FindNextThinkForBuildable( int bclass );
-int BG_FindBuildTimeForBuildable( int bclass );
-qboolean BG_FindUsableForBuildable( int bclass );
-int BG_FindRangeForBuildable( int bclass );
-int BG_FindFireSpeedForBuildable( int bclass );
-weapon_t BG_FindProjTypeForBuildable( int bclass );
-float BG_FindMinNormalForBuildable( int bclass );
-qboolean BG_FindInvertNormalForBuildable( int bclass );
-int BG_FindCreepTestForBuildable( int bclass );
-int BG_FindCreepSizeForBuildable( int bclass );
-int BG_FindDCCTestForBuildable( int bclass );
-int BG_FindUniqueTestForBuildable( int bclass );
-qboolean BG_FindReplaceableTestForBuildable( int bclass );
-qboolean BG_FindTransparentTestForBuildable( int bclass );
-void BG_InitBuildableOverrides( void );
-
-int BG_FindClassNumForName( char *name );
-char *BG_FindNameForClassNum( int pclass );
-char *BG_FindHumanNameForClassNum( int pclass );
-char *BG_FindModelNameForClass( int pclass );
-float BG_FindModelScaleForClass( int pclass );
-char *BG_FindSkinNameForClass( int pclass );
-float BG_FindShadowScaleForClass( int pclass );
-char *BG_FindHudNameForClass( int pclass );
-qboolean BG_FindStagesForClass( int pclass, stage_t stage );
-void BG_FindBBoxForClass( int pclass, vec3_t mins, vec3_t maxs, vec3_t cmaxs, vec3_t dmins, vec3_t dmaxs );
-float BG_FindZOffsetForClass( int pclass );
-void BG_FindViewheightForClass( int pclass, int *viewheight, int *cViewheight );
-int BG_FindHealthForClass( int pclass );
-float BG_FindFallDamageForClass( int pclass );
-int BG_FindRegenRateForClass( int pclass );
-int BG_FindFovForClass( int pclass );
-float BG_FindBobForClass( int pclass );
-float BG_FindBobCycleForClass( int pclass );
-float BG_FindSpeedForClass( int pclass );
-float BG_FindAccelerationForClass( int pclass );
-float BG_FindAirAccelerationForClass( int pclass );
-float BG_FindFrictionForClass( int pclass );
-float BG_FindStopSpeedForClass( int pclass );
-float BG_FindJumpMagnitudeForClass( int pclass );
-float BG_FindKnockbackScaleForClass( int pclass );
-int BG_FindSteptimeForClass( int pclass );
-qboolean BG_ClassHasAbility( int pclass, int ability );
-weapon_t BG_FindStartWeaponForClass( int pclass );
-float BG_FindBuildDistForClass( int pclass );
-int BG_ClassCanEvolveFromTo( int fclass, int tclass, int credits, int num );
-int BG_FindCostOfClass( int pclass );
-int BG_FindValueOfClass( int pclass );
-void BG_InitClassOverrides( void );
-
-int BG_FindPriceForWeapon( int weapon );
-qboolean BG_FindStagesForWeapon( int weapon, stage_t stage );
-int BG_FindSlotsForWeapon( int weapon );
-char *BG_FindNameForWeapon( int weapon );
-int BG_FindWeaponNumForName( char *name );
-char *BG_FindHumanNameForWeapon( int weapon );
-char *BG_FindModelsForWeapon( int weapon, int modelNum );
-char *BG_FindIconForWeapon( int weapon );
-char *BG_FindCrosshairForWeapon( int weapon );
-int BG_FindCrosshairSizeForWeapon( int weapon );
-void BG_FindAmmoForWeapon( int weapon, int *maxAmmo, int *maxClips );
-qboolean BG_FindInfinteAmmoForWeapon( int weapon );
-qboolean BG_FindUsesEnergyForWeapon( int weapon );
-int BG_FindRepeatRate1ForWeapon( int weapon );
-int BG_FindRepeatRate2ForWeapon( int weapon );
-int BG_FindRepeatRate3ForWeapon( int weapon );
-int BG_FindReloadTimeForWeapon( int weapon );
-float BG_FindKnockbackScaleForWeapon( int weapon );
-qboolean BG_WeaponHasAltMode( int weapon );
-qboolean BG_WeaponHasThirdMode( int weapon );
-qboolean BG_WeaponCanZoom( int weapon );
-float BG_FindZoomFovForWeapon( int weapon );
-qboolean BG_FindPurchasableForWeapon( int weapon );
-qboolean BG_FindLongRangedForWeapon( int weapon );
-int BG_FindBuildDelayForWeapon( int weapon );
-WUTeam_t BG_FindTeamForWeapon( int weapon );
-
-int BG_FindPriceForUpgrade( int upgrade );
-qboolean BG_FindStagesForUpgrade( int upgrade, stage_t stage );
-int BG_FindSlotsForUpgrade( int upgrade );
-char *BG_FindNameForUpgrade( int upgrade );
-int BG_FindUpgradeNumForName( char *name );
-char *BG_FindHumanNameForUpgrade( int upgrade );
-char *BG_FindIconForUpgrade( int upgrade );
-qboolean BG_FindPurchasableForUpgrade( int upgrade );
-qboolean BG_FindUsableForUpgrade( int upgrade );
-WUTeam_t BG_FindTeamForUpgrade( int upgrade );
+int BG_GetValueOfPlayer( playerState_t *ps );
+qboolean BG_PlayerCanChangeWeapon( playerState_t *ps );
+int BG_PlayerPoisonCloudTime( playerState_t *ps );
+weapon_t BG_GetPlayerWeapon( playerState_t *ps );
+qboolean BG_HasEnergyWeapon( playerState_t *ps );
+
+void BG_PackEntityNumbers( entityState_t *es, const int *entityNums, int count );
+int BG_UnpackEntityNumbers( entityState_t *es, int *entityNums, int count );
+
+const buildableAttributes_t *BG_BuildableByName( const char *name );
+const buildableAttributes_t *BG_BuildableByEntityName( const char *name );
+const buildableAttributes_t *BG_Buildable( buildable_t buildable );
+qboolean BG_BuildableAllowedInStage( buildable_t buildable,
+ stage_t stage );
+
+buildableConfig_t *BG_BuildableConfig( buildable_t buildable );
+void BG_BuildableBoundingBox( buildable_t buildable,
+ vec3_t mins, vec3_t maxs );
+void BG_InitBuildableConfigs( void );
+
+const classAttributes_t *BG_ClassByName( const char *name );
+const classAttributes_t *BG_Class( class_t klass );
+qboolean BG_ClassAllowedInStage( class_t klass,
+ stage_t stage );
+
+classConfig_t *BG_ClassConfig( class_t klass );
+
+void BG_ClassBoundingBox( class_t klass, vec3_t mins,
+ vec3_t maxs, vec3_t cmaxs,
+ vec3_t dmins, vec3_t dmaxs );
+qboolean BG_ClassHasAbility( class_t klass, int ability );
+int BG_ClassCanEvolveFromTo( class_t fclass,
+ class_t tclass,
+ int credits, int alienStage, int num );
+qboolean BG_AlienCanEvolve( class_t klass, int credits, int alienStage );
+
+void BG_InitClassConfigs( void );
+
+const weaponAttributes_t *BG_WeaponByName( const char *name );
+const weaponAttributes_t *BG_Weapon( weapon_t weapon );
+qboolean BG_WeaponAllowedInStage( weapon_t weapon,
+ stage_t stage );
+
+const upgradeAttributes_t *BG_UpgradeByName( const char *name );
+const upgradeAttributes_t *BG_Upgrade( upgrade_t upgrade );
+qboolean BG_UpgradeAllowedInStage( upgrade_t upgrade,
+ stage_t stage );
// content masks
#define MASK_ALL (-1)
@@ -1257,7 +1188,10 @@ typedef enum
ET_PLAYER,
ET_ITEM,
- ET_BUILDABLE, //TA: buildable type
+ ET_BUILDABLE,
+ ET_RANGE_MARKER,
+
+ ET_LOCATION,
ET_MISSILE,
ET_MOVER,
@@ -1275,12 +1209,19 @@ typedef enum
ET_MODELDOOR,
ET_LIGHTFLARE,
ET_LEV2_ZAP_CHAIN,
+ ET_WEAPON_DROP,
ET_EVENTS // any of the EV_* events can be added freestanding
// by setting eType to ET_EVENTS + eventNum
// this avoids having to set eFlags and eventNum
} entityType_t;
+void *BG_Alloc( int size );
+void BG_InitMemory( void );
+void BG_Free( void *ptr );
+void BG_DefragmentMemory( void );
+void BG_MemoryInfo( void );
+
void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result );
void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result );
@@ -1303,28 +1244,83 @@ int atoi_neg( char *token, qboolean allowNegative );
void BG_ParseCSVEquipmentList( const char *string, weapon_t *weapons, int weaponsSize,
upgrade_t *upgrades, int upgradesSize );
-void BG_ParseCSVClassList( const char *string, pClass_t *classes, int classesSize );
+void BG_ParseCSVClassList( const char *string, class_t *classes, int classesSize );
void BG_ParseCSVBuildableList( const char *string, buildable_t *buildables, int buildablesSize );
void BG_InitAllowedGameElements( void );
qboolean BG_WeaponIsAllowed( weapon_t weapon );
qboolean BG_UpgradeIsAllowed( upgrade_t upgrade );
-qboolean BG_ClassIsAllowed( pClass_t class );
+qboolean BG_ClassIsAllowed( class_t klass );
qboolean BG_BuildableIsAllowed( buildable_t buildable );
-qboolean BG_UpgradeClassAvailable( playerState_t *ps );
-
-typedef struct
-{
- unsigned int hi;
- unsigned int lo;
-} clientList_t;
-qboolean BG_ClientListTest( clientList_t *list, int clientNum );
-void BG_ClientListAdd( clientList_t *list, int clientNum );
-void BG_ClientListRemove( clientList_t *list, int clientNum );
-char *BG_ClientListString( clientList_t *list );
-void BG_ClientListParse( clientList_t *list, const char *s );
// Friendly Fire Flags
#define FFF_HUMANS 1
#define FFF_ALIENS 2
#define FFF_BUILDABLES 4
+// bg_voice.c
+#define MAX_VOICES 8
+#define MAX_VOICE_NAME_LEN 16
+#define MAX_VOICE_CMD_LEN 16
+#define VOICE_ENTHUSIASM_DECAY 0.5f // enthusiasm lost per second
+
+typedef enum
+{
+ VOICE_CHAN_ALL,
+ VOICE_CHAN_TEAM ,
+ VOICE_CHAN_LOCAL,
+
+ VOICE_CHAN_NUM_CHANS
+} voiceChannel_t;
+
+typedef struct voiceTrack_s
+{
+//#ifdef CGAME
+ sfxHandle_t track;
+ int duration;
+//#endif
+ char *text;
+ int enthusiasm;
+ int team;
+ int klass;
+ int weapon;
+ struct voiceTrack_s *next;
+} voiceTrack_t;
+
+typedef struct voiceCmd_s
+{
+ char cmd[ MAX_VOICE_CMD_LEN ];
+ voiceTrack_t *tracks;
+ struct voiceCmd_s *next;
+} voiceCmd_t;
+
+typedef struct voice_s
+{
+ char name[ MAX_VOICE_NAME_LEN ];
+ voiceCmd_t *cmds;
+ struct voice_s *next;
+} voice_t;
+
+voice_t *BG_VoiceInit( void );
+void BG_PrintVoices( voice_t *voices, int debugLevel );
+
+voice_t *BG_VoiceByName( voice_t *head, char *name );
+voiceCmd_t *BG_VoiceCmdFind( voiceCmd_t *head, char *name, int *cmdNum );
+voiceCmd_t *BG_VoiceCmdByNum( voiceCmd_t *head, int num);
+voiceTrack_t *BG_VoiceTrackByNum( voiceTrack_t *head, int num );
+voiceTrack_t *BG_VoiceTrackFind( voiceTrack_t *head, team_t team,
+ class_t klass, weapon_t weapon,
+ int enthusiasm, int *trackNum );
+
+int BG_LoadEmoticons( emoticon_t *emoticons, int num );
+
+char *BG_TeamName( team_t team );
+
+typedef struct
+{
+ const char *name;
+} dummyCmd_t;
+int cmdcmp( const void *a, const void *b );
+
+char *G_CopyString( const char *str );
+
+#endif
diff --git a/src/game/bg_shared.h b/src/game/bg_shared.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/game/bg_shared.h
diff --git a/src/game/bg_slidemove.c b/src/game/bg_slidemove.c
index aa32a6a..3d6a521 100644
--- a/src/game/bg_slidemove.c
+++ b/src/game/bg_slidemove.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,14 +17,14 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// bg_slidemove.c -- part of bg_pmove functionality
-#include "../qcommon/q_shared.h"
+#include "qcommon/q_shared.h"
#include "bg_public.h"
#include "bg_local.h"
@@ -74,8 +75,7 @@ qboolean PM_SlideMove( qboolean gravity )
if( pml.groundPlane )
{
// slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
}
}
@@ -166,10 +166,10 @@ qboolean PM_SlideMove( qboolean gravity )
pml.impactSpeed = -into;
// slide along the plane
- PM_ClipVelocity( pm->ps->velocity, planes[ i ], clipVelocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, planes[ i ], clipVelocity );
// slide along the plane
- PM_ClipVelocity( endVelocity, planes[ i ], endClipVelocity, OVERCLIP );
+ PM_ClipVelocity( endVelocity, planes[ i ], endClipVelocity );
// see if there is a second plane that the new move enters
for( j = 0; j < numplanes; j++ )
@@ -181,8 +181,8 @@ qboolean PM_SlideMove( qboolean gravity )
continue; // move doesn't interact with the plane
// try clipping the move to the plane
- PM_ClipVelocity( clipVelocity, planes[ j ], clipVelocity, OVERCLIP );
- PM_ClipVelocity( endClipVelocity, planes[ j ], endClipVelocity, OVERCLIP );
+ PM_ClipVelocity( clipVelocity, planes[ j ], clipVelocity );
+ PM_ClipVelocity( endClipVelocity, planes[ j ], endClipVelocity );
// see if it goes back into the first clip plane
if( DotProduct( clipVelocity, planes[ i ] ) >= 0 )
@@ -290,7 +290,6 @@ PM_StepSlideMove
qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive )
{
vec3_t start_o, start_v;
- vec3_t down_o, down_v;
trace_t trace;
vec3_t normal;
vec3_t step_v, step_vNormal;
@@ -298,15 +297,7 @@ qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive )
float stepSize;
qboolean stepped = qfalse;
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- {
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- VectorSet( normal, 0.0f, 0.0f, -1.0f );
- else
- VectorCopy( pm->ps->grapplePoint, normal );
- }
- else
- VectorSet( normal, 0.0f, 0.0f, 1.0f );
+ BG_GetClientNormal( pm->ps, normal );
VectorCopy( pm->ps->origin, start_o );
VectorCopy( pm->ps->velocity, start_v );
@@ -339,9 +330,6 @@ qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive )
return stepped;
}
- VectorCopy( pm->ps->origin, down_o );
- VectorCopy( pm->ps->velocity, down_v );
-
VectorCopy( start_o, up );
VectorMA( up, STEPSIZE, normal, up );
@@ -381,7 +369,7 @@ qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive )
VectorCopy( trace.endpos, pm->ps->origin );
if( trace.fraction < 1.0f )
- PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity );
}
if( !predictive && stepped )
diff --git a/src/game/bg_voice.c b/src/game/bg_voice.c
new file mode 100644
index 0000000..06ce939
--- /dev/null
+++ b/src/game/bg_voice.c
@@ -0,0 +1,653 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2008 Tony J. White
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// bg_voice.c -- both games voice functions
+#include "qcommon/q_shared.h"
+#include "bg_public.h"
+#include "bg_local.h"
+
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, enum FS_Mode mode );
+int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
+int trap_Parse_LoadSource( const char *filename );
+int trap_Parse_FreeSource( int handle );
+int trap_Parse_ReadToken( int handle, pc_token_t *pc_token );
+int trap_Parse_SourceFileAndLine( int handle, char *filename, int *line );
+
+#ifdef CGAME
+sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed );
+int trap_S_SoundDuration( sfxHandle_t handle );
+#endif
+
+
+/*
+============
+BG_VoiceParseError
+============
+*/
+static void BG_VoiceParseError( fileHandle_t handle, const char *err )
+{
+ int line;
+ char filename[ MAX_QPATH ];
+
+ trap_Parse_SourceFileAndLine( handle, filename, &line );
+ trap_Parse_FreeSource( handle );
+ Com_Error( ERR_FATAL, "%s on line %d of %s", err, line, filename );
+}
+
+/*
+============
+BG_VoiceList
+============
+*/
+static voice_t *BG_VoiceList( void )
+{
+ char fileList[ MAX_VOICES * ( MAX_VOICE_NAME_LEN + 8 ) ] = {""};
+ int numFiles, i, fileLen = 0;
+ int count = 0;
+ char *filePtr;
+ voice_t *voices = NULL;
+ voice_t *top = NULL;
+
+ numFiles = trap_FS_GetFileList( "voice", ".voice", fileList,
+ sizeof( fileList ) );
+
+ if( numFiles < 1 )
+ return NULL;
+
+ // special case for default.voice. this file is REQUIRED and will
+ // always be loaded first in the event of overflow of voice definitions
+ if( !trap_FS_FOpenFile( "voice/default.voice", NULL, FS_READ ) )
+ {
+ Com_Printf( "voice/default.voice missing, voice system disabled." );
+ return NULL;
+ }
+
+ voices = (voice_t*)BG_Alloc( sizeof( voice_t ) );
+ Q_strncpyz( voices->name, "default", sizeof( voices->name ) );
+ voices->cmds = NULL;
+ voices->next = NULL;
+ count = 1;
+
+ top = voices;
+
+ filePtr = fileList;
+ for( i = 0; i < numFiles; i++, filePtr += fileLen + 1 )
+ {
+ fileLen = strlen( filePtr );
+
+ // accounted for above
+ if( !Q_stricmp( filePtr, "default.voice" ) )
+ continue;
+
+ if( fileLen > MAX_VOICE_NAME_LEN + 8 ) {
+ Com_Printf( S_COLOR_YELLOW "WARNING: MAX_VOICE_NAME_LEN is %d. "
+ "skipping \"%s\", filename too long", MAX_VOICE_NAME_LEN, filePtr );
+ continue;
+ }
+
+ // trap_FS_GetFileList() buffer has overflowed
+ if( !trap_FS_FOpenFile( va( "voice/%s", filePtr ), NULL, FS_READ ) )
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: BG_VoiceList(): detected "
+ "an invalid .voice file \"%s\" in directory listing. You have "
+ "probably named one or more .voice files with outrageously long "
+ "names. gjbs", filePtr );
+ break;
+ }
+
+ if( count >= MAX_VOICES )
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: .voice file overflow. "
+ "%d of %d .voice files loaded. MAX_VOICES is %d",
+ count, numFiles, MAX_VOICES );
+ break;
+ }
+
+ voices->next = (voice_t*)BG_Alloc( sizeof( voice_t ) );
+ voices = voices->next;
+
+ Q_strncpyz( voices->name, filePtr, sizeof( voices->name ) );
+ // strip extension
+ voices->name[ fileLen - 6 ] = '\0';
+ voices->cmds = NULL;
+ voices->next = NULL;
+ count++;
+ }
+ return top;
+}
+
+/*
+============
+BG_VoiceParseTrack
+============
+*/
+static qboolean BG_VoiceParseTrack( int handle, voiceTrack_t *voiceTrack )
+{
+ pc_token_t token;
+ qboolean found = qfalse;
+ qboolean foundText = qfalse;
+ qboolean foundToken = qfalse;
+
+ foundToken = trap_Parse_ReadToken( handle, &token );
+ while( foundToken )
+ {
+ if( token.string[ 0 ] == '}' )
+ {
+ if( foundText )
+ return qtrue;
+ else
+ {
+ BG_VoiceParseError( handle, "BG_VoiceParseTrack(): "
+ "missing text attribute for track" );
+ }
+ }
+ else if( !Q_stricmp( token.string, "team" ) )
+ {
+ foundToken = trap_Parse_ReadToken( handle, &token );
+ found = qfalse;
+ while( foundToken && token.type == TT_NUMBER )
+ {
+ found = qtrue;
+ if( voiceTrack->team < 0 )
+ voiceTrack->team = 0;
+ voiceTrack->team |= ( 1 << token.intvalue );
+ foundToken = trap_Parse_ReadToken( handle, &token );
+ }
+ if( !found )
+ {
+ BG_VoiceParseError( handle,
+ "BG_VoiceParseTrack(): missing \"team\" value" );
+ }
+ continue;
+ }
+ else if( !Q_stricmp( token.string, "class" ) )
+ {
+ foundToken = trap_Parse_ReadToken( handle, &token );
+ found = qfalse;
+ while( foundToken && token.type == TT_NUMBER )
+ {
+ found = qtrue;
+ if( voiceTrack->klass < 0 )
+ voiceTrack->klass = 0;
+ voiceTrack->klass |= ( 1 << token.intvalue );
+ foundToken = trap_Parse_ReadToken( handle, &token );
+ }
+ if( !found )
+ {
+ BG_VoiceParseError( handle,
+ "BG_VoiceParseTrack(): missing \"class\" value" );
+ }
+ continue;
+ }
+ else if( !Q_stricmp( token.string, "weapon" ) )
+ {
+ foundToken = trap_Parse_ReadToken( handle, &token );
+ found = qfalse;
+ while( foundToken && token.type == TT_NUMBER )
+ {
+ found = qtrue;
+ if( voiceTrack->weapon < 0 )
+ voiceTrack->weapon = 0;
+ voiceTrack->weapon |= ( 1 << token.intvalue );
+ foundToken = trap_Parse_ReadToken( handle, &token );
+ }
+ if( !found )
+ {
+ BG_VoiceParseError( handle,
+ "BG_VoiceParseTrack(): missing \"weapon\" value");
+ }
+ continue;
+ }
+ else if( !Q_stricmp( token.string, "text" ) )
+ {
+ if( foundText )
+ {
+ BG_VoiceParseError( handle, "BG_VoiceParseTrack(): "
+ "duplicate \"text\" definition for track" );
+ }
+ foundToken = trap_Parse_ReadToken( handle, &token );
+ if( !foundToken )
+ {
+ BG_VoiceParseError( handle, "BG_VoiceParseTrack(): "
+ "missing \"text\" value" );
+ }
+ foundText = qtrue;
+ if( strlen( token.string ) >= MAX_SAY_TEXT )
+ {
+ BG_VoiceParseError( handle, va( "BG_VoiceParseTrack(): "
+ "\"text\" value " "\"%s\" exceeds MAX_SAY_TEXT length",
+ token.string ) );
+ }
+
+ voiceTrack->text = (char *)BG_Alloc( strlen( token.string ) + 1 );
+ Q_strncpyz( voiceTrack->text, token.string, strlen( token.string ) + 1 );
+ foundToken = trap_Parse_ReadToken( handle, &token );
+ continue;
+ }
+ else if( !Q_stricmp( token.string, "enthusiasm" ) )
+ {
+ foundToken = trap_Parse_ReadToken( handle, &token );
+ if( token.type == TT_NUMBER )
+ {
+ voiceTrack->enthusiasm = token.intvalue;
+ }
+ else
+ {
+ BG_VoiceParseError( handle, "BG_VoiceParseTrack(): "
+ "missing \"enthusiasm\" value" );
+ }
+ foundToken = trap_Parse_ReadToken( handle, &token );
+ continue;
+ }
+ else
+ {
+ BG_VoiceParseError( handle, va( "BG_VoiceParseTrack():"
+ " unknown token \"%s\"", token.string ) );
+ }
+ }
+ return qfalse;
+}
+
+/*
+============
+BG_VoiceParseCommand
+============
+*/
+static voiceTrack_t *BG_VoiceParseCommand( int handle )
+{
+ pc_token_t token;
+ qboolean parsingTrack = qfalse;
+ voiceTrack_t *voiceTracks = NULL;
+ voiceTrack_t *top = NULL;
+
+ while( trap_Parse_ReadToken( handle, &token ) )
+ {
+ if( !parsingTrack && token.string[ 0 ] == '}' )
+ return top;
+
+ if( parsingTrack )
+ {
+ if( token.string[ 0 ] == '{' )
+ {
+ BG_VoiceParseTrack( handle, voiceTracks );
+ parsingTrack = qfalse;
+ continue;
+
+ }
+ else
+ {
+ BG_VoiceParseError( handle, va( "BG_VoiceParseCommand(): "
+ "parse error at \"%s\"", token.string ) );
+ }
+ }
+
+
+ if( top == NULL )
+ {
+ voiceTracks = BG_Alloc( sizeof( voiceTrack_t ) );
+ top = voiceTracks;
+ }
+ else
+ {
+ voiceTracks->next = BG_Alloc( sizeof( voiceCmd_t ) );
+ voiceTracks = voiceTracks->next;
+ }
+
+ if( !trap_FS_FOpenFile( token.string, NULL, FS_READ ) )
+ {
+ int line;
+ char filename[ MAX_QPATH ];
+
+ trap_Parse_SourceFileAndLine( handle, filename, &line );
+ Com_Printf( S_COLOR_YELLOW "WARNING: BG_VoiceParseCommand(): "
+ "track \"%s\" referenced on line %d of %s does not exist\n",
+ token.string, line, filename );
+ }
+ else
+ {
+#ifdef CGAME
+ voiceTracks->track = trap_S_RegisterSound( token.string, qfalse );
+ voiceTracks->duration = trap_S_SoundDuration( voiceTracks->track );
+#endif
+ }
+
+ voiceTracks->team = -1;
+ voiceTracks->klass = -1;
+ voiceTracks->weapon = -1;
+ voiceTracks->enthusiasm = 0;
+ voiceTracks->text = NULL;
+ voiceTracks->next = NULL;
+ parsingTrack = qtrue;
+
+ }
+ return NULL;
+}
+
+/*
+============
+BG_VoiceParse
+============
+*/
+static voiceCmd_t *BG_VoiceParse( char *name )
+{
+ voiceCmd_t *voiceCmds = NULL;
+ voiceCmd_t *top = NULL;
+ pc_token_t token;
+ qboolean parsingCmd = qfalse;
+ int handle;
+
+ handle = trap_Parse_LoadSource( va( "voice/%s.voice", name ) );
+ if( !handle )
+ return NULL;
+
+ while( trap_Parse_ReadToken( handle, &token ) )
+ {
+ if( parsingCmd )
+ {
+ if( token.string[ 0 ] == '{' )
+ {
+ voiceCmds->tracks = BG_VoiceParseCommand( handle );
+ parsingCmd = qfalse;
+ continue;
+ }
+ else
+ {
+ int line;
+ char filename[ MAX_QPATH ];
+
+ trap_Parse_SourceFileAndLine( handle, filename, &line );
+ Com_Error( ERR_FATAL, "BG_VoiceParse(): "
+ "parse error on line %d of %s", line, filename );
+ }
+ }
+
+ if( strlen( token.string ) >= MAX_VOICE_CMD_LEN )
+ {
+ int line;
+ char filename[ MAX_QPATH ];
+
+ trap_Parse_SourceFileAndLine( handle, filename, &line );
+ Com_Error( ERR_FATAL, "BG_VoiceParse(): "
+ "command \"%s\" exceeds MAX_VOICE_CMD_LEN (%d) on line %d of %s",
+ token.string, MAX_VOICE_CMD_LEN, line, filename );
+ }
+
+ if( top == NULL )
+ {
+ voiceCmds = BG_Alloc( sizeof( voiceCmd_t ) );
+ top = voiceCmds;
+ }
+ else
+ {
+ voiceCmds->next = BG_Alloc( sizeof( voiceCmd_t ) );
+ voiceCmds = voiceCmds->next;
+ }
+
+ Q_strncpyz( voiceCmds->cmd, token.string, sizeof( voiceCmds->cmd ) );
+ voiceCmds->next = NULL;
+ parsingCmd = qtrue;
+
+ }
+
+ trap_Parse_FreeSource( handle );
+
+ return top;
+}
+
+/*
+============
+BG_VoiceInit
+============
+*/
+voice_t *BG_VoiceInit( void )
+{
+ voice_t *voices;
+ voice_t *voice;
+
+ voices = BG_VoiceList();
+
+ voice = voices;
+ while( voice )
+ {
+ voice->cmds = BG_VoiceParse( voice->name );
+ voice = voice->next;
+ }
+
+ return voices;
+}
+
+
+/*
+============
+BG_PrintVoices
+============
+*/
+void BG_PrintVoices( voice_t *voices, int debugLevel )
+{
+ voice_t *voice = voices;
+ voiceCmd_t *voiceCmd;
+ voiceTrack_t *voiceTrack;
+
+ int cmdCount;
+ int trackCount;
+
+ if( voice == NULL )
+ {
+ Com_Printf( "voice list is empty\n" );
+ return;
+ }
+
+ while( voice != NULL )
+ {
+ if( debugLevel > 0 )
+ Com_Printf( "voice \"%s\"\n", voice->name );
+ voiceCmd = voice->cmds;
+ cmdCount = 0;
+ trackCount = 0;
+ while( voiceCmd != NULL )
+ {
+ if( debugLevel > 0 )
+ Com_Printf( " %s\n", voiceCmd->cmd );
+ voiceTrack = voiceCmd->tracks;
+ cmdCount++;
+ while ( voiceTrack != NULL )
+ {
+ if( debugLevel > 1 )
+ Com_Printf( " text -> %s\n", voiceTrack->text );
+ if( debugLevel > 2 )
+ {
+ Com_Printf( " team -> %d\n", voiceTrack->team );
+ Com_Printf( " class -> %d\n", voiceTrack->klass );
+ Com_Printf( " weapon -> %d\n", voiceTrack->weapon );
+ Com_Printf( " enthusiasm -> %d\n", voiceTrack->enthusiasm );
+#ifdef CGAME
+ Com_Printf( " duration -> %d\n", voiceTrack->duration );
+#endif
+ }
+ if( debugLevel > 1 )
+ Com_Printf( "\n" );
+ trackCount++;
+ voiceTrack = voiceTrack->next;
+ }
+ voiceCmd = voiceCmd->next;
+ }
+
+ if( !debugLevel )
+ {
+ Com_Printf( "voice \"%s\": %d commands, %d tracks\n",
+ voice->name, cmdCount, trackCount );
+ }
+ voice = voice->next;
+ }
+}
+
+/*
+============
+BG_VoiceByName
+============
+*/
+voice_t *BG_VoiceByName( voice_t *head, char *name )
+{
+ voice_t *v = head;
+
+ while( v )
+ {
+ if( !Q_stricmp( v->name, name ) )
+ return v;
+ v = v->next;
+ }
+ return NULL;
+}
+
+/*
+============
+BG_VoiceCmdFind
+============
+*/
+voiceCmd_t *BG_VoiceCmdFind( voiceCmd_t *head, char *name, int *cmdNum )
+{
+ voiceCmd_t *vc = head;
+ int i = 0;
+
+ while( vc )
+ {
+ i++;
+ if( !Q_stricmp( vc->cmd, name ) )
+ {
+ *cmdNum = i;
+ return vc;
+ }
+ vc = vc->next;
+ }
+ return NULL;
+}
+
+/*
+============
+BG_VoiceCmdByNum
+============
+*/
+voiceCmd_t *BG_VoiceCmdByNum( voiceCmd_t *head, int num )
+{
+ voiceCmd_t *vc = head;
+ int i = 0;
+
+ while( vc )
+ {
+ i++;
+ if( i == num )
+ return vc;
+ vc = vc->next;
+ }
+ return NULL;
+}
+
+/*
+============
+BG_VoiceTrackByNum
+============
+*/
+voiceTrack_t *BG_VoiceTrackByNum( voiceTrack_t *head, int num )
+{
+ voiceTrack_t *vt = head;
+ int i = 0;
+
+ while( vt )
+ {
+ i++;
+ if( i == num )
+ return vt;
+ vt = vt->next;
+ }
+ return NULL;
+}
+
+/*
+============
+BG_VoiceTrackFind
+============
+*/
+voiceTrack_t *BG_VoiceTrackFind( voiceTrack_t *head, team_t team,
+ class_t class, weapon_t weapon,
+ int enthusiasm, int *trackNum )
+{
+ voiceTrack_t *vt = head;
+ int highestMatch = 0;
+ int matchCount = 0;
+ int selectedMatch = 0;
+ int i = 0;
+ int j = 0;
+
+ // find highest enthusiasm without going over
+ while( vt )
+ {
+ if( ( vt->team >= 0 && !( vt->team & ( 1 << team ) ) ) ||
+ ( vt->klass >= 0 && !( vt->klass & ( 1 << class ) ) ) ||
+ ( vt->weapon >= 0 && !( vt->weapon & ( 1 << weapon ) ) ) ||
+ vt->enthusiasm > enthusiasm )
+ {
+ vt = vt->next;
+ continue;
+ }
+
+ if( vt->enthusiasm > highestMatch )
+ {
+ matchCount = 0;
+ highestMatch = vt->enthusiasm;
+ }
+ if( vt->enthusiasm == highestMatch )
+ matchCount++;
+ vt = vt->next;
+ }
+
+ if( !matchCount )
+ return NULL;
+
+ // return randomly selected match
+ selectedMatch = rand() / ( RAND_MAX / matchCount + 1 );
+ vt = head;
+ i = 0;
+ j = 0;
+ while( vt )
+ {
+ j++;
+ if( ( vt->team >= 0 && !( vt->team & ( 1 << team ) ) ) ||
+ ( vt->klass >= 0 && !( vt->klass & ( 1 << class ) ) ) ||
+ ( vt->weapon >= 0 && !( vt->weapon & ( 1 << weapon ) ) ) ||
+ vt->enthusiasm != highestMatch )
+ {
+ vt = vt->next;
+ continue;
+ }
+ if( i == selectedMatch )
+ {
+ *trackNum = j;
+ return vt;
+ }
+ i++;
+ vt = vt->next;
+ }
+ return NULL;
+}
diff --git a/src/game/g_active.c b/src/game/g_active.c
index b5df273..d978a4a 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -40,7 +41,7 @@ void P_DamageFeedback( gentity_t *player )
vec3_t angles;
client = player->client;
- if( client->ps.pm_type == PM_DEAD )
+ if( !PM_Alive( client->ps.pm_type ) )
return;
// total points of damage shot at the player this frame
@@ -129,7 +130,7 @@ void P_WorldEffects( gentity_t *ent )
// play a gurp sound instead of a normal pain sound
if( ent->health <= ent->damage )
G_Sound( ent, CHAN_VOICE, G_SoundIndex( "*drown.wav" ) );
- else if( rand( ) & 1 )
+ else if( rand( ) < RAND_MAX / 2 + 1 )
G_Sound( ent, CHAN_VOICE, G_SoundIndex( "sound/player/gurp1.wav" ) );
else
G_Sound( ent, CHAN_VOICE, G_SoundIndex( "sound/player/gurp2.wav" ) );
@@ -191,59 +192,74 @@ void G_SetClientSound( gentity_t *ent )
//==============================================================
-static void G_ClientShove( gentity_t *ent, gentity_t *victim )
+/*
+==============
+ClientShove
+==============
+*/
+static int GetClientMass( gentity_t *ent )
{
- vec3_t dir, push;
- int entMass = 200, vicMass = 200;
-
- // shoving enemies changes gameplay too much
- if( !OnSameTeam( ent, victim ) )
- return;
+ int entMass = 100;
- if ( ( victim->client->ps.weapon >= WP_ABUILD ) &&
- ( victim->client->ps.weapon <= WP_HBUILD ) &&
- ( victim->client->ps.stats[ STAT_BUILDABLE ] != BA_NONE ) )
- return;
-
- // alien mass is directly related to their health points
- // human mass is 200, double for bsuit
- if( ent->client->pers.teamSelection == PTE_ALIENS )
- {
- entMass = BG_FindHealthForClass( ent->client->pers.classSelection );
- }
- else if( ent->client->pers.teamSelection == PTE_HUMANS )
+ if( ent->client->pers.teamSelection == TEAM_ALIENS )
+ entMass = BG_Class( ent->client->pers.classSelection )->health;
+ else if( ent->client->pers.teamSelection == TEAM_HUMANS )
{
if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, ent->client->ps.stats ) )
entMass *= 2;
}
else
+ return 0;
+ return entMass;
+}
+
+static void ClientShove( gentity_t *ent, gentity_t *victim )
+{
+ vec3_t dir, push;
+ float force;
+ int entMass, vicMass;
+
+ // Don't push if the entity is not trying to move
+ if( !ent->client->pers.cmd.rightmove && !ent->client->pers.cmd.forwardmove &&
+ !ent->client->pers.cmd.upmove )
return;
- if( victim->client->pers.teamSelection == PTE_ALIENS )
- {
- vicMass = BG_FindHealthForClass( victim->client->pers.classSelection );
- }
- else if( BG_InventoryContainsUpgrade( UP_BATTLESUIT,
- victim->client->ps.stats ) )
- {
- vicMass *= 2;
- }
+ // Cannot push enemy players unless they are walking on the player
+ if( !OnSameTeam( ent, victim ) &&
+ victim->client->ps.groundEntityNum != ent - g_entities )
+ return;
+ // Shove force is scaled by relative mass
+ entMass = GetClientMass( ent );
+ vicMass = GetClientMass( victim );
if( vicMass <= 0 || entMass <= 0 )
return;
+ force = g_shove.value * entMass / vicMass;
+ if( force < 0 )
+ force = 0;
+ if( force > 150 )
+ force = 150;
+ // Give the victim some shove velocity
VectorSubtract( victim->r.currentOrigin, ent->r.currentOrigin, dir );
VectorNormalizeFast( dir );
-
- // don't break the dretch elevator
- if( fabs( dir[ 2 ] ) > fabs( dir[ 0 ] ) && fabs( dir[ 2 ] ) > fabs( dir[ 1 ] ) )
- return;
-
- VectorScale( dir,
- ( g_shove.value * ( ( float )entMass / ( float )vicMass ) ), push );
- VectorAdd( victim->client->ps.velocity, push,
- victim->client->ps.velocity );
-
+ VectorScale( dir, force, push );
+ VectorAdd( victim->client->ps.velocity, push, victim->client->ps.velocity );
+
+ // Set the pmove timer so that the other client can't cancel
+ // out the movement immediately
+ if( !victim->client->ps.pm_time )
+ {
+ int time;
+
+ time = force * 2 + 0.5f;
+ if( time < 50 )
+ time = 50;
+ if( time > 200 )
+ time = 200;
+ victim->client->ps.pm_time = time;
+ victim->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
+ }
}
/*
@@ -253,45 +269,38 @@ ClientImpacts
*/
void ClientImpacts( gentity_t *ent, pmove_t *pm )
{
- int i, j;
+ int i;
trace_t trace;
gentity_t *other;
+ // clear a fake trace struct for touch function
memset( &trace, 0, sizeof( trace ) );
for( i = 0; i < pm->numtouch; i++ )
{
- for( j = 0; j < i; j++ )
- {
- if( pm->touchents[ j ] == pm->touchents[ i ] )
- break;
- }
-
- if( j != i )
- continue; // duplicated
-
other = &g_entities[ pm->touchents[ i ] ];
// see G_UnlaggedDetectCollisions(), this is the inverse of that.
// if our movement is blocked by another player's real position,
- // don't use the unlagged position for them because they are
+ // don't use the unlagged position for them because they are
// blocking or server-side Pmove() from reaching it
if( other->client && other->client->unlaggedCalc.used )
other->client->unlaggedCalc.used = qfalse;
- //charge attack
- if( ent->client->ps.weapon == WP_ALEVEL4 &&
- ent->client->ps.stats[ STAT_MISC ] > 0 &&
- ent->client->charging )
- ChargeAttack( ent, other );
+ // tyrant impact attacks
+ if( ent->client->ps.weapon == WP_ALEVEL4 )
+ {
+ G_ChargeAttack( ent, other );
+ G_CrushAttack( ent, other );
+ }
+ // shove players
if( ent->client && other->client )
- G_ClientShove( ent, other );
-
- if( !other->touch )
- continue;
+ ClientShove( ent, other );
- other->touch( other, ent, &trace );
+ // touch triggers
+ if( other->touch )
+ other->touch( other, ent, &trace );
}
}
@@ -316,11 +325,15 @@ void G_TouchTriggers( gentity_t *ent )
if( !ent->client )
return;
+ // noclipping clients don't activate triggers!
+ if( ent->client->noclip )
+ return;
+
// dead clients don't activate triggers!
if( ent->client->ps.stats[ STAT_HEALTH ] <= 0 )
return;
- BG_FindBBoxForClass( ent->client->ps.stats[ STAT_PCLASS ],
+ BG_ClassBoundingBox( ent->client->ps.stats[ STAT_CLASS ],
pmins, pmaxs, NULL, NULL, NULL );
VectorAdd( ent->client->ps.origin, pmins, mins );
@@ -346,9 +359,7 @@ void G_TouchTriggers( gentity_t *ent )
continue;
// ignore most entities if a spectator
- if( ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) ||
- ( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) ||
- ( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) )
+ if( ent->client->sess.spectatorState != SPECTATOR_NOT )
{
if( hit->s.eType != ET_TELEPORT_TRIGGER &&
// this is ugly but adding a new ET_? type will
@@ -380,136 +391,123 @@ void SpectatorThink( gentity_t *ent, usercmd_t *ucmd )
{
pmove_t pm;
gclient_t *client;
- qboolean attack1, attack3;
- qboolean doPmove = qtrue;
+ int clientNum;
+ qboolean attack1, following, queued;
client = ent->client;
client->oldbuttons = client->buttons;
client->buttons = ucmd->buttons;
- attack1 = ( ( client->buttons & BUTTON_ATTACK ) &&
- !( client->oldbuttons & BUTTON_ATTACK ) );
- attack3 = ( ( client->buttons & BUTTON_USE_HOLDABLE ) &&
- !( client->oldbuttons & BUTTON_USE_HOLDABLE ) );
-
- if( level.mapRotationVoteTime )
+ attack1 = ( client->buttons & BUTTON_ATTACK ) &&
+ !( client->oldbuttons & BUTTON_ATTACK );
+
+ // We are in following mode only if we are following a non-spectating client
+ following = client->sess.spectatorState == SPECTATOR_FOLLOW;
+ if( following )
{
- if( attack1 )
- {
- G_IntermissionMapVoteCommand( ent, qtrue, qfalse );
- attack1 = qfalse;
- }
- if( ( client->buttons & BUTTON_ATTACK2 ) && !( client->oldbuttons & BUTTON_ATTACK2 ) )
- G_IntermissionMapVoteCommand( ent, qfalse, qfalse );
+ clientNum = client->sess.spectatorClient;
+ if( clientNum < 0 || clientNum > level.maxclients ||
+ !g_entities[ clientNum ].client ||
+ g_entities[ clientNum ].client->sess.spectatorState != SPECTATOR_NOT )
+ following = qfalse;
}
-
- if( client->sess.spectatorState == SPECTATOR_LOCKED || client->sess.spectatorState == SPECTATOR_FOLLOW )
- client->ps.pm_type = PM_FREEZE;
+
+ // Check to see if we are in the spawn queue
+ if( client->pers.teamSelection == TEAM_ALIENS )
+ queued = G_SearchSpawnQueue( &level.alienSpawnQueue, ent - g_entities );
+ else if( client->pers.teamSelection == TEAM_HUMANS )
+ queued = G_SearchSpawnQueue( &level.humanSpawnQueue, ent - g_entities );
else
- client->ps.pm_type = PM_SPECTATOR;
+ queued = qfalse;
- if ( client->sess.spectatorState == SPECTATOR_FOLLOW )
+ // Wants to get out of spawn queue
+ if( attack1 && queued )
{
- gclient_t *cl;
- if ( client->sess.spectatorClient >= 0 )
- {
- cl = &level.clients[ client->sess.spectatorClient ];
- if ( cl->sess.sessionTeam != TEAM_SPECTATOR )
- doPmove = qfalse;
- }
+ if( client->sess.spectatorState == SPECTATOR_FOLLOW )
+ G_StopFollowing( ent );
+ if( client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ G_RemoveFromSpawnQueue( &level.alienSpawnQueue, client->ps.clientNum );
+ else if( client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ G_RemoveFromSpawnQueue( &level.humanSpawnQueue, client->ps.clientNum );
+ client->pers.classSelection = PCL_NONE;
+ client->pers.humanItemSelection = WP_NONE;
+ client->ps.stats[ STAT_CLASS ] = PCL_NONE;
+ client->ps.pm_flags &= ~PMF_QUEUED;
+ queued = qfalse;
+ }
+ else if( attack1 )
+ {
+ // Wants to get into spawn queue
+ if( client->sess.spectatorState == SPECTATOR_FOLLOW )
+ G_StopFollowing( ent );
+ if( client->pers.teamSelection == TEAM_NONE )
+ G_TriggerMenu( client->ps.clientNum, MN_TEAM );
+ else if( client->pers.teamSelection == TEAM_ALIENS )
+ G_TriggerMenu( client->ps.clientNum, MN_A_CLASS );
+ else if( client->pers.teamSelection == TEAM_HUMANS )
+ G_TriggerMenu( client->ps.clientNum, MN_H_SPAWN );
}
- if (doPmove)
+ // We are either not following anyone or following a spectator
+ if( !following )
{
- client->ps.speed = BG_FindSpeedForClass( client->ps.stats[ STAT_PCLASS ] );
-
- // in case the client entered the queue while following a teammate
- if( ( client->pers.teamSelection == PTE_ALIENS &&
- G_SearchSpawnQueue( &level.alienSpawnQueue, ent-g_entities ) ) ||
- ( client->pers.teamSelection == PTE_HUMANS &&
- G_SearchSpawnQueue( &level.humanSpawnQueue, ent-g_entities ) ) )
- {
- client->ps.pm_flags |= PMF_QUEUED;
- }
-
+ if( client->sess.spectatorState == SPECTATOR_LOCKED ||
+ client->sess.spectatorState == SPECTATOR_FOLLOW )
+ client->ps.pm_type = PM_FREEZE;
+ else if( client->noclip )
+ client->ps.pm_type = PM_NOCLIP;
+ else
+ client->ps.pm_type = PM_SPECTATOR;
+
+ if( queued )
+ client->ps.pm_flags |= PMF_QUEUED;
+ client->ps.speed = client->pers.flySpeed;
client->ps.stats[ STAT_STAMINA ] = 0;
client->ps.stats[ STAT_MISC ] = 0;
- client->ps.stats[ STAT_BUILDABLE ] = 0;
- client->ps.stats[ STAT_PCLASS ] = PCL_NONE;
+ client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
+ client->ps.stats[ STAT_CLASS ] = PCL_NONE;
client->ps.weapon = WP_NONE;
- // set up for pmove
+ // Set up for pmove
memset( &pm, 0, sizeof( pm ) );
pm.ps = &client->ps;
+ pm.pmext = &client->pmext;
pm.cmd = *ucmd;
- pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; // spectators can fly through bodies
+ pm.tracemask = ent->clipmask;
pm.trace = trap_Trace;
pm.pointcontents = trap_PointContents;
- // perform a pmove
+ // Perform a pmove
Pmove( &pm );
- // save results of pmove
- VectorCopy( client->ps.origin, ent->s.origin );
+ // Save results of pmove
+ VectorCopy( client->ps.origin, ent->s.pos.trBase );
+ VectorCopy( client->ps.origin, ent->r.currentOrigin );
+ VectorCopy( client->ps.viewangles, ent->r.currentAngles );
+ VectorCopy( client->ps.viewangles, ent->s.pos.trBase );
G_TouchTriggers( ent );
trap_UnlinkEntity( ent );
- if( ( attack1 ) && ( client->ps.pm_flags & PMF_QUEUED ) )
- {
- if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- G_RemoveFromSpawnQueue( &level.alienSpawnQueue, client->ps.clientNum );
- else if( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- G_RemoveFromSpawnQueue( &level.humanSpawnQueue, client->ps.clientNum );
-
- client->pers.classSelection = PCL_NONE;
- client->ps.stats[ STAT_PCLASS ] = PCL_NONE;
- }
-
- if( attack1 && client->pers.classSelection == PCL_NONE )
- {
- if( client->pers.teamSelection == PTE_NONE )
- G_TriggerMenu( client->ps.clientNum, MN_TEAM );
- else if( client->pers.teamSelection == PTE_ALIENS )
- G_TriggerMenu( client->ps.clientNum, MN_A_CLASS );
- else if( client->pers.teamSelection == PTE_HUMANS )
- G_TriggerMenu( client->ps.clientNum, MN_H_SPAWN );
- }
-
- //set the queue position for the client side
+ // Set the queue position and spawn count for the client side
if( client->ps.pm_flags & PMF_QUEUED )
{
- if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
client->ps.persistant[ PERS_QUEUEPOS ] =
G_GetPosInSpawnQueue( &level.alienSpawnQueue, client->ps.clientNum );
+ client->ps.persistant[ PERS_SPAWNS ] = level.numAlienSpawns;
}
- else if( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ else if( client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
client->ps.persistant[ PERS_QUEUEPOS ] =
G_GetPosInSpawnQueue( &level.humanSpawnQueue, client->ps.clientNum );
+ client->ps.persistant[ PERS_SPAWNS ] = level.numHumanSpawns;
}
}
}
-
- else if( attack1 && ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
- {
- G_StopFollowing( ent );
- client->pers.classSelection = PCL_NONE;
- if( client->pers.teamSelection == PTE_NONE )
- G_TriggerMenu( ent-g_entities, MN_TEAM );
- else if( client->pers.teamSelection == PTE_ALIENS )
- G_TriggerMenu( ent-g_entities, MN_A_CLASS );
- else if( client->pers.teamSelection == PTE_HUMANS )
- G_TriggerMenu( ent-g_entities, MN_H_SPAWN );
- }
-
- if( attack3 )
- {
- G_ToggleFollow( ent );
- }
}
@@ -521,8 +519,10 @@ ClientInactivityTimer
Returns qfalse if the client is dropped
=================
*/
-qboolean ClientInactivityTimer( gclient_t *client )
+qboolean ClientInactivityTimer( gentity_t *ent )
{
+ gclient_t *client = ent->client;
+
if( ! g_inactivity.integer )
{
// give everyone some time, so if the operator sets g_inactivity during
@@ -540,13 +540,16 @@ qboolean ClientInactivityTimer( gclient_t *client )
}
else if( !client->pers.localClient )
{
- if( level.time > client->inactivityTime )
+ if( level.time > client->inactivityTime &&
+ !G_admin_permission( ent, ADMF_ACTIVITY ) )
{
trap_DropClient( client - level.clients, "Dropped due to inactivity" );
return qfalse;
}
- if( level.time > client->inactivityTime - 10000 && !client->inactivityWarning )
+ if( level.time > client->inactivityTime - 10000 &&
+ !client->inactivityWarning &&
+ !G_admin_permission( ent, ADMF_ACTIVITY ) )
{
client->inactivityWarning = qtrue;
trap_SendServerCommand( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" );
@@ -569,203 +572,100 @@ void ClientTimerActions( gentity_t *ent, int msec )
usercmd_t *ucmd;
int aForward, aRight;
qboolean walking = qfalse, stopped = qfalse,
- crouched = qfalse, jumping = qfalse,
- strafing = qfalse;
+ crouched = qfalse;
+ int i;
ucmd = &ent->client->pers.cmd;
aForward = abs( ucmd->forwardmove );
aRight = abs( ucmd->rightmove );
- client = ent->client;
- client->time100 += msec;
- client->time1000 += msec;
- client->time10000 += msec;
-
if( aForward == 0 && aRight == 0 )
stopped = qtrue;
else if( aForward <= 64 && aRight <= 64 )
walking = qtrue;
- if( aRight > 0 )
- strafing = qtrue;
-
- if( ucmd->upmove > 0 )
- jumping = qtrue;
- else if( ent->client->ps.pm_flags & PMF_DUCKED )
+ if( ucmd->upmove <= 0 && ent->client->ps.pm_flags & PMF_DUCKED )
crouched = qtrue;
+ client = ent->client;
+ client->time100 += msec;
+ client->time1000 += msec;
+ client->time10000 += msec;
+
while ( client->time100 >= 100 )
{
+ weapon_t weapon = BG_GetPlayerWeapon( &client->ps );
+
client->time100 -= 100;
- //if not trying to run then not trying to sprint
- if( walking || stopped )
- client->ps.stats[ STAT_STATE ] &= ~SS_SPEEDBOOST;
-
- if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) && BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) )
- client->ps.stats[ STAT_STATE ] &= ~SS_SPEEDBOOST;
-
- if( ( client->ps.stats[ STAT_STATE ] & SS_SPEEDBOOST ) && !crouched )
- {
- //subtract stamina
- if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, client->ps.stats ) )
- client->ps.stats[ STAT_STAMINA ] -= STAMINA_LARMOUR_TAKE;
- else
- client->ps.stats[ STAT_STAMINA ] -= STAMINA_SPRINT_TAKE;
-
- if( client->ps.stats[ STAT_STAMINA ] < -MAX_STAMINA )
- client->ps.stats[ STAT_STAMINA ] = -MAX_STAMINA;
- }
-
- if( walking || crouched )
- {
- //restore stamina
- client->ps.stats[ STAT_STAMINA ] += STAMINA_WALK_RESTORE;
-
- if( client->ps.stats[ STAT_STAMINA ] > MAX_STAMINA )
- client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA;
- }
- else if( stopped )
- {
- //restore stamina faster
+ // Restore or subtract stamina
+ if( stopped || client->ps.pm_type == PM_JETPACK )
client->ps.stats[ STAT_STAMINA ] += STAMINA_STOP_RESTORE;
-
- if( client->ps.stats[ STAT_STAMINA ] > MAX_STAMINA )
- client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA;
- }
-
- //client is charging up for a pounce
- if( client->ps.weapon == WP_ALEVEL3 || client->ps.weapon == WP_ALEVEL3_UPG )
- {
- int pounceSpeed = 0;
-
- if( client->ps.weapon == WP_ALEVEL3 )
- pounceSpeed = LEVEL3_POUNCE_SPEED;
- else if( client->ps.weapon == WP_ALEVEL3_UPG )
- pounceSpeed = LEVEL3_POUNCE_UPG_SPEED;
-
- if( client->ps.stats[ STAT_MISC ] < pounceSpeed && ucmd->buttons & BUTTON_ATTACK2 )
- client->ps.stats[ STAT_MISC ] += ( 100.0f / (float)LEVEL3_POUNCE_CHARGE_TIME ) * pounceSpeed;
-
- if( !( ucmd->buttons & BUTTON_ATTACK2 ) )
- {
- if( client->pmext.pouncePayload > 0 )
- client->allowedToPounce = qtrue;
- }
-
- if( client->ps.stats[ STAT_MISC ] > pounceSpeed )
- client->ps.stats[ STAT_MISC ] = pounceSpeed;
- }
-
- //client is charging up for a... charge
- if( client->ps.weapon == WP_ALEVEL4 )
+ else if( ( client->ps.stats[ STAT_STATE ] & SS_SPEEDBOOST ) &&
+ !( client->buttons & BUTTON_WALKING ) ) // walk overrides sprint
+ client->ps.stats[ STAT_STAMINA ] -= STAMINA_SPRINT_TAKE;
+ else if( walking || crouched )
+ client->ps.stats[ STAT_STAMINA ] += STAMINA_WALK_RESTORE;
+
+ // Check stamina limits
+ if( client->ps.stats[ STAT_STAMINA ] > STAMINA_MAX )
+ client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
+ else if( client->ps.stats[ STAT_STAMINA ] < -STAMINA_MAX )
+ client->ps.stats[ STAT_STAMINA ] = -STAMINA_MAX;
+
+ if( weapon == WP_ABUILD || weapon == WP_ABUILD2 ||
+ client->ps.stats[ STAT_WEAPON ] == WP_HBUILD )
{
- if( client->ps.stats[ STAT_MISC ] < LEVEL4_CHARGE_TIME && ucmd->buttons & BUTTON_ATTACK2 &&
- !client->charging )
- {
- client->charging = qfalse; //should already be off, just making sure
- client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING;
-
- if( ucmd->forwardmove > 0 )
- {
- //trigger charge sound...is quite annoying
- //if( client->ps.stats[ STAT_MISC ] <= 0 )
- // G_AddEvent( ent, EV_LEV4_CHARGE_PREPARE, 0 );
-
- client->ps.stats[ STAT_MISC ] += (int)( 100 * (float)LEVEL4_CHARGE_CHARGE_RATIO );
-
- if( client->ps.stats[ STAT_MISC ] > LEVEL4_CHARGE_TIME )
- client->ps.stats[ STAT_MISC ] = LEVEL4_CHARGE_TIME;
- }
- else
- client->ps.stats[ STAT_MISC ] = 0;
- }
-
- if( !( ucmd->buttons & BUTTON_ATTACK2 ) || client->charging ||
- client->ps.stats[ STAT_MISC ] == LEVEL4_CHARGE_TIME )
- {
- if( client->ps.stats[ STAT_MISC ] > LEVEL4_MIN_CHARGE_TIME )
- {
+ // Update build timer
+ if( client->ps.stats[ STAT_MISC ] > 0 )
client->ps.stats[ STAT_MISC ] -= 100;
- if( client->charging == qfalse )
- G_AddEvent( ent, EV_LEV4_CHARGE_START, 0 );
-
- client->charging = qtrue;
- client->ps.stats[ STAT_STATE ] |= SS_CHARGING;
-
- //if the charger has stopped moving take a chunk of charge away
- if( VectorLength( client->ps.velocity ) < 64.0f || aRight )
- client->ps.stats[ STAT_MISC ] = client->ps.stats[ STAT_MISC ] / 2;
-
- //can't charge backwards
- if( ucmd->forwardmove < 0 )
- client->ps.stats[ STAT_MISC ] = 0;
- }
- else
- client->ps.stats[ STAT_MISC ] = 0;
-
-
- if( client->ps.stats[ STAT_MISC ] <= 0 )
- {
+ if( client->ps.stats[ STAT_MISC ] < 0 )
client->ps.stats[ STAT_MISC ] = 0;
- client->charging = qfalse;
- client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING;
- }
- }
- }
-
- //client is charging up an lcannon
- if( client->ps.weapon == WP_LUCIFER_CANNON )
- {
- int ammo;
-
- ammo = client->ps.ammo;
-
- if( client->ps.stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE && ucmd->buttons & BUTTON_ATTACK )
- client->ps.stats[ STAT_MISC ] += ( 100.0f / LCANNON_CHARGE_TIME ) * LCANNON_TOTAL_CHARGE;
-
- if( client->ps.stats[ STAT_MISC ] > LCANNON_TOTAL_CHARGE )
- client->ps.stats[ STAT_MISC ] = LCANNON_TOTAL_CHARGE;
-
- if( client->ps.stats[ STAT_MISC ] > ( ammo * LCANNON_TOTAL_CHARGE ) / 10 )
- client->ps.stats[ STAT_MISC ] = ammo * LCANNON_TOTAL_CHARGE / 10;
}
- switch( client->ps.weapon )
+ switch( weapon )
{
case WP_ABUILD:
case WP_ABUILD2:
case WP_HBUILD:
- case WP_HBUILD2:
- //set validity bit on buildable
+
+ // Set validity bit on buildable
if( ( client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) > BA_NONE )
{
- int dist = BG_FindBuildDistForClass( ent->client->ps.stats[ STAT_PCLASS ] );
- vec3_t dummy;
+ int dist = BG_Class( ent->client->ps.stats[ STAT_CLASS ] )->buildDist;
+ vec3_t dummy, dummy2;
+ int dummy3;
if( G_CanBuild( ent, client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT,
- dist, dummy ) == IBE_NONE )
+ dist, dummy, dummy2, &dummy3 ) == IBE_NONE )
client->ps.stats[ STAT_BUILDABLE ] |= SB_VALID_TOGGLEBIT;
else
client->ps.stats[ STAT_BUILDABLE ] &= ~SB_VALID_TOGGLEBIT;
- }
- case WP_BLASTER:
- //update build timer
- if( client->ps.stats[ STAT_MISC ] > 0 )
- client->ps.stats[ STAT_MISC ] -= 100;
-
- if( client->ps.stats[ STAT_MISC ] < 0 )
- client->ps.stats[ STAT_MISC ] = 0;
+ // Let the client know which buildables will be removed by building
+ for( i = 0; i < MAX_MISC; i++ )
+ {
+ if( i < level.numBuildablesForRemoval )
+ client->ps.misc[ i ] = level.markedBuildables[ i ]->s.number;
+ else
+ client->ps.misc[ i ] = 0;
+ }
+ }
+ else
+ {
+ for( i = 0; i < MAX_MISC; i++ )
+ client->ps.misc[ i ] = 0;
+ }
break;
default:
break;
}
- if( client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE )
+ if( ent->client->pers.teamSelection == TEAM_HUMANS &&
+ ( client->ps.stats[ STAT_STATE ] & SS_HEALING_2X ) )
{
int remainingStartupTime = MEDKIT_STARTUP_TIME - ( level.time - client->lastMedKitTime );
@@ -777,9 +677,10 @@ void ClientTimerActions( gentity_t *ent, int msec )
{
ent->client->medKitHealthToRestore--;
ent->health++;
+ ent->client->ps.stats[ STAT_HEALTH ] = ent->health;
}
else
- ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE;
+ ent->client->ps.stats[ STAT_STATE ] &= ~SS_HEALING_2X;
}
else
{
@@ -792,13 +693,14 @@ void ClientTimerActions( gentity_t *ent, int msec )
{
ent->client->medKitHealthToRestore--;
ent->health++;
+ ent->client->ps.stats[ STAT_HEALTH ] = ent->health;
client->medKitIncrementTime = level.time +
( remainingStartupTime / MEDKIT_STARTUP_SPEED );
}
}
else
- ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE;
+ ent->client->ps.stats[ STAT_STATE ] &= ~SS_HEALING_2X;
}
}
}
@@ -807,20 +709,17 @@ void ClientTimerActions( gentity_t *ent, int msec )
{
client->time1000 -= 1000;
- //client is poison clouded
- if( client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED )
- G_Damage( ent, client->lastPoisonCloudedClient, client->lastPoisonCloudedClient, NULL, NULL,
- LEVEL1_PCLOUD_DMG, 0, MOD_LEVEL1_PCLOUD );
-
//client is poisoned
if( client->ps.stats[ STAT_STATE ] & SS_POISONED )
{
- int damage = ALIEN_POISON_DMG;
-
+ int damage = ALIEN_POISON_DMG;
+
if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, client->ps.stats ) )
damage -= BSUIT_POISON_PROTECTION;
+
if( BG_InventoryContainsUpgrade( UP_HELMET, client->ps.stats ) )
damage -= HELMET_POISON_PROTECTION;
+
if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, client->ps.stats ) )
damage -= LIGHTARMOUR_POISON_PROTECTION;
@@ -828,135 +727,37 @@ void ClientTimerActions( gentity_t *ent, int msec )
0, damage, 0, MOD_POISON );
}
- //replenish alien health
- if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS &&
- level.surrenderTeam != PTE_ALIENS )
- {
- int entityList[ MAX_GENTITIES ];
- vec3_t range = { LEVEL1_REGEN_RANGE, LEVEL1_REGEN_RANGE, LEVEL1_REGEN_RANGE };
- vec3_t mins, maxs;
- int i, num;
- gentity_t *boostEntity;
- float modifier = 1.0f;
-
- VectorAdd( client->ps.origin, range, maxs );
- VectorSubtract( client->ps.origin, range, mins );
-
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
- {
- boostEntity = &g_entities[ entityList[ i ] ];
-
- if( boostEntity->client && boostEntity->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS &&
- boostEntity->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL1_UPG )
- {
- modifier = LEVEL1_REGEN_MOD;
- break;
- }
- else if( boostEntity->s.eType == ET_BUILDABLE &&
- boostEntity->s.modelindex == BA_A_BOOSTER &&
- boostEntity->spawned && boostEntity->health > 0 )
- {
- modifier = BOOSTER_REGEN_MOD;
- break;
- }
- }
-
- if( ent->health > 0 && ent->health < client->ps.stats[ STAT_MAX_HEALTH ] &&
- !level.paused &&
- ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time )
- {
- ent->health += BG_FindRegenRateForClass( client->ps.stats[ STAT_PCLASS ] ) * modifier;
-
- // if completely healed, cancel retribution
- if( ent->health >= client->ps.stats[ STAT_MAX_HEALTH ] )
- {
- for( i = 0; i < MAX_CLIENTS; i++ )
- ent->client->tkcredits[ i ] = 0;
- }
- }
-
- if( ent->health > client->ps.stats[ STAT_MAX_HEALTH ] )
- ent->health = client->ps.stats[ STAT_MAX_HEALTH ];
- }
-
-
- if( ent->client->ps.stats[ STAT_HEALTH ] > 0 && ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- ent->client->pers.statscounters.timealive++;
- level.alienStatsCounters.timealive++;
- if( G_BuildableRange( ent->client->ps.origin, 900, BA_A_OVERMIND ) )
- {
- ent->client->pers.statscounters.timeinbase++;
- level.alienStatsCounters.timeinbase++;
- }
- if( BG_ClassHasAbility( ent->client->ps.stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) )
- {
- ent->client->pers.statscounters.dretchbasytime++;
- level.alienStatsCounters.dretchbasytime++;
- if( ent->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING || ent->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING)
- {
- ent->client->pers.statscounters.jetpackusewallwalkusetime++;
- level.alienStatsCounters.jetpackusewallwalkusetime++;
- }
- }
- }
- else if( ent->client->ps.stats[ STAT_HEALTH ] > 0 && ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- ent->client->pers.statscounters.timealive++;
- level.humanStatsCounters.timealive++;
- if( G_BuildableRange( ent->client->ps.origin, 900, BA_H_REACTOR ) )
- {
- ent->client->pers.statscounters.timeinbase++;
- level.humanStatsCounters.timeinbase++;
- }
- if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) )
- {
- if( client->ps.pm_type == PM_JETPACK )
- {
- ent->client->pers.statscounters.jetpackusewallwalkusetime++;
- level.humanStatsCounters.jetpackusewallwalkusetime++;
- }
- }
- }
-
- // turn off life support when a team admits defeat
- if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS &&
- level.surrenderTeam == PTE_ALIENS )
+ // turn off life support when a team admits defeat
+ if( client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS &&
+ level.surrenderTeam == TEAM_ALIENS )
{
G_Damage( ent, NULL, NULL, NULL, NULL,
- BG_FindRegenRateForClass( client->ps.stats[ STAT_PCLASS ] ),
+ BG_Class( client->ps.stats[ STAT_CLASS ] )->regenRate,
DAMAGE_NO_ARMOR, MOD_SUICIDE );
}
- else if( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS &&
- level.surrenderTeam == PTE_HUMANS )
+ else if( client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS &&
+ level.surrenderTeam == TEAM_HUMANS )
{
G_Damage( ent, NULL, NULL, NULL, NULL, 5, DAMAGE_NO_ARMOR, MOD_SUICIDE );
}
- //my new jetpack code
- if( mod_jetpackFuel.value >= 10.0f ) {
- //if we have jetpack and its on
- if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) && BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) ) {
- //check if fuels 0 if so deactivate it if not give a 10 second fuel low warning and take JETPACK_USE_RATE from fuel
- if( client->jetpackfuel <= 0.0f ) {
- BG_DeactivateUpgrade( UP_JETPACK, client->ps.stats );
- } else if( client->jetpackfuel < 10.0f && client->jetpackfuel > 0.0f) {
- client->jetpackfuel = client->jetpackfuel - mod_jetpackConsume.value;
- trap_SendServerCommand( client - level.clients, "cp \"^3Fuel ^1Low!!!!!^7\nLand now.\"" );
- } else {
- client->jetpackfuel = client->jetpackfuel - mod_jetpackConsume.value;
- }
+ // lose some voice enthusiasm
+ if( client->voiceEnthusiasm > 0.0f )
+ client->voiceEnthusiasm -= VOICE_ENTHUSIASM_DECAY;
+ else
+ client->voiceEnthusiasm = 0.0f;
- //if jetpack isnt active regenerate fuel and give a message when its full
- } else if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) && !BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) ) {
- if( client->jetpackfuel > ( mod_jetpackFuel.value - 10.0f ) && client->jetpackfuel <= mod_jetpackFuel.value ) {
- client->jetpackfuel = client->jetpackfuel + mod_jetpackRegen.value;
- trap_SendServerCommand( client - level.clients, "cp \"^3Fuel Status: ^2Full!^7\n\"" );
- } else if( client->jetpackfuel < mod_jetpackFuel.value ) {
- //regenerate some fuel
- client->jetpackfuel = client->jetpackfuel + mod_jetpackRegen.value;
- }
+ client->pers.secondsAlive++;
+ if( g_freeFundPeriod.integer > 0 &&
+ client->pers.secondsAlive % g_freeFundPeriod.integer == 0 )
+ {
+ // Give clients some credit periodically
+ if( G_TimeTilSuddenDeath( ) > 0 )
+ {
+ if( client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ G_AddCreditToClient( client, FREEKILL_ALIEN, qtrue );
+ else if( client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ G_AddCreditToClient( client, FREEKILL_HUMAN, qtrue );
}
}
}
@@ -965,21 +766,42 @@ void ClientTimerActions( gentity_t *ent, int msec )
{
client->time10000 -= 10000;
- if( client->ps.weapon == WP_ALEVEL3_UPG )
+ if( ent->client->ps.weapon == WP_ABUILD ||
+ ent->client->ps.weapon == WP_ABUILD2 )
{
- int ammo, maxAmmo;
+ AddScore( ent, ALIEN_BUILDER_SCOREINC );
+ }
+ else if( ent->client->ps.weapon == WP_HBUILD )
+ {
+ AddScore( ent, HUMAN_BUILDER_SCOREINC );
+ }
- BG_FindAmmoForWeapon( WP_ALEVEL3_UPG, &maxAmmo, NULL );
- ammo = client->ps.ammo;
+ // Give score to basis that healed other aliens
+ if( ent->client->pers.hasHealed )
+ {
+ if( client->ps.weapon == WP_ALEVEL1 )
+ AddScore( ent, LEVEL1_REGEN_SCOREINC );
+ else if( client->ps.weapon == WP_ALEVEL1_UPG )
+ AddScore( ent, LEVEL1_UPG_REGEN_SCOREINC );
+
+ ent->client->pers.hasHealed = qfalse;
+ }
+ }
- if( ammo < maxAmmo )
+ // Regenerate Adv. Dragoon barbs
+ if( client->ps.weapon == WP_ALEVEL3_UPG )
+ {
+ if( client->ps.ammo < BG_Weapon( WP_ALEVEL3_UPG )->maxAmmo )
+ {
+ if( ent->timestamp + LEVEL3_BOUNCEBALL_REGEN < level.time )
{
- ammo++;
- client->ps.ammo = ammo;
- client->ps.clips = 0;
+ client->ps.ammo++;
+ ent->timestamp = level.time;
}
}
- }
+ else
+ ent->timestamp = level.time;
+ }
}
/*
@@ -989,7 +811,6 @@ ClientIntermissionThink
*/
void ClientIntermissionThink( gclient_t *client )
{
- client->ps.eFlags &= ~EF_TALK;
client->ps.eFlags &= ~EF_FIRING;
client->ps.eFlags &= ~EF_FIRING2;
@@ -1020,10 +841,10 @@ void ClientEvents( gentity_t *ent, int oldEventSequence )
vec3_t dir;
vec3_t point, mins;
float fallDistance;
- pClass_t class;
+ class_t class;
client = ent->client;
- class = client->ps.stats[ STAT_PCLASS ];
+ class = client->ps.stats[ STAT_CLASS ];
if( oldEventSequence < client->ps.eventSequence - MAX_PS_EVENTS )
oldEventSequence = client->ps.eventSequence - MAX_PS_EVENTS;
@@ -1047,11 +868,11 @@ void ClientEvents( gentity_t *ent, int oldEventSequence )
else if( fallDistance > 1.0f )
fallDistance = 1.0f;
- damage = (int)( (float)BG_FindHealthForClass( class ) *
- BG_FindFallDamageForClass( class ) * fallDistance );
+ damage = (int)( (float)BG_Class( class )->health *
+ BG_Class( class )->fallDamage * fallDistance );
VectorSet( dir, 0, 0, 1 );
- BG_FindBBoxForClass( class, mins, NULL, NULL, NULL, NULL );
+ BG_ClassBoundingBox( class, mins, NULL, NULL, NULL, NULL );
mins[ 0 ] = mins[ 1 ] = 0.0f;
VectorAdd( client->ps.origin, mins, point );
@@ -1122,8 +943,8 @@ void SendPendingPredictableEvents( playerState_t *ps )
==============
G_UnlaggedStore
- Called on every server frame. Stores position data for the client at that
- into client->unlaggedHist[] and the time into level.unlaggedTimes[].
+ Called on every server frame. Stores position data for the client at that
+ into client->unlaggedHist[] and the time into level.unlaggedTimes[].
This data is used by G_UnlaggedCalc()
==============
*/
@@ -1132,24 +953,24 @@ void G_UnlaggedStore( void )
int i = 0;
gentity_t *ent;
unlagged_t *save;
-
+
if( !g_unlagged.integer )
return;
- level.unlaggedIndex++;
+ level.unlaggedIndex++;
if( level.unlaggedIndex >= MAX_UNLAGGED_MARKERS )
level.unlaggedIndex = 0;
level.unlaggedTimes[ level.unlaggedIndex ] = level.time;
-
+
for( i = 0; i < level.maxclients; i++ )
{
ent = &g_entities[ i ];
save = &ent->client->unlaggedHist[ level.unlaggedIndex ];
- save->used = qfalse;
+ save->used = qfalse;
if( !ent->r.linked || !( ent->r.contents & CONTENTS_BODY ) )
continue;
if( ent->client->pers.connected != CON_CONNECTED )
- continue;
+ continue;
VectorCopy( ent->r.mins, save->mins );
VectorCopy( ent->r.maxs, save->maxs );
VectorCopy( ent->s.pos.trBase, save->origin );
@@ -1160,7 +981,7 @@ void G_UnlaggedStore( void )
/*
==============
G_UnlaggedClear
-
+
Mark all unlaggedHist[] markers for this client invalid. Useful for
preventing teleporting and death.
==============
@@ -1185,14 +1006,14 @@ void G_UnlaggedCalc( int time, gentity_t *rewindEnt )
{
int i = 0;
gentity_t *ent;
- int startIndex = level.unlaggedIndex;
- int stopIndex = -1;
- int frameMsec = 0;
- float lerp = 0.5f;
+ int startIndex;
+ int stopIndex;
+ int frameMsec;
+ float lerp;
if( !g_unlagged.integer )
return;
-
+
// clear any calculated values from a previous run
for( i = 0; i < level.maxclients; i++ )
{
@@ -1200,13 +1021,18 @@ void G_UnlaggedCalc( int time, gentity_t *rewindEnt )
ent->client->unlaggedCalc.used = qfalse;
}
- for( i = 0; i < MAX_UNLAGGED_MARKERS; i++ )
+ // client is on the current frame, no need for unlagged
+ if( level.unlaggedTimes[ level.unlaggedIndex ] <= time )
+ return;
+
+ startIndex = level.unlaggedIndex;
+ for( i = 1; i < MAX_UNLAGGED_MARKERS; i++ )
{
- if( level.unlaggedTimes[ startIndex ] <= time )
- break;
stopIndex = startIndex;
if( --startIndex < 0 )
startIndex = MAX_UNLAGGED_MARKERS - 1;
+ if( level.unlaggedTimes[ startIndex ] <= time )
+ break;
}
if( i == MAX_UNLAGGED_MARKERS )
{
@@ -1214,20 +1040,13 @@ void G_UnlaggedCalc( int time, gentity_t *rewindEnt )
// just use the oldest marker with no lerping
lerp = 0.0f;
}
-
- // client is on the current frame, no need for unlagged
- if( stopIndex == -1 )
- return;
-
- // lerp between two markers
- frameMsec = level.unlaggedTimes[ stopIndex ] -
- level.unlaggedTimes[ startIndex ];
- if( frameMsec > 0 )
+ else
{
- lerp = ( float )( time - level.unlaggedTimes[ startIndex ] )
- / ( float )frameMsec;
+ // lerp between two markers
+ frameMsec = level.unlaggedTimes[ stopIndex ] - level.unlaggedTimes[ startIndex ];
+ lerp = ( float )( time - level.unlaggedTimes[ startIndex ] ) / ( float )frameMsec;
}
-
+
for( i = 0; i < level.maxclients; i++ )
{
ent = &g_entities[ i ];
@@ -1243,13 +1062,13 @@ void G_UnlaggedCalc( int time, gentity_t *rewindEnt )
continue;
// between two unlagged markers
- VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].mins,
+ VectorLerp2( lerp, ent->client->unlaggedHist[ startIndex ].mins,
ent->client->unlaggedHist[ stopIndex ].mins,
ent->client->unlaggedCalc.mins );
- VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].maxs,
+ VectorLerp2( lerp, ent->client->unlaggedHist[ startIndex ].maxs,
ent->client->unlaggedHist[ stopIndex ].maxs,
ent->client->unlaggedCalc.maxs );
- VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].origin,
+ VectorLerp2( lerp, ent->client->unlaggedHist[ startIndex ].origin,
ent->client->unlaggedHist[ stopIndex ].origin,
ent->client->unlaggedCalc.origin );
@@ -1268,10 +1087,10 @@ void G_UnlaggedOff( void )
{
int i = 0;
gentity_t *ent;
-
+
if( !g_unlagged.integer )
return;
-
+
for( i = 0; i < level.maxclients; i++ )
{
ent = &g_entities[ i ];
@@ -1304,13 +1123,13 @@ void G_UnlaggedOn( gentity_t *attacker, vec3_t muzzle, float range )
int i = 0;
gentity_t *ent;
unlagged_t *calc;
-
+
if( !g_unlagged.integer )
return;
if( !attacker->client->pers.useUnlagged )
return;
-
+
for( i = 0; i < level.maxclients; i++ )
{
ent = &g_entities[ i ];
@@ -1331,7 +1150,7 @@ void G_UnlaggedOn( gentity_t *attacker, vec3_t muzzle, float range )
float maxRadius = ( r1 > r2 ) ? r1 : r2;
if( Distance( muzzle, calc->origin ) > range + maxRadius )
- continue;
+ continue;
}
// create a backup of the real positions
@@ -1355,7 +1174,7 @@ void G_UnlaggedOn( gentity_t *attacker, vec3_t muzzle, float range )
the current time, but only updates other player's positions up to the
postition sent in the most recent snapshot.
- This allows player X to essentially "move through" the position of player Y
+ This allows player X to essentially "move through" the position of player Y
when player X's cmd is processed with Pmove() on the server. This is because
player Y was clipping player X's Pmove() on his client, but when the same
cmd is processed with Pmove on the server it is not clipped.
@@ -1378,6 +1197,7 @@ static void G_UnlaggedDetectCollisions( gentity_t *ent )
if( !g_unlagged.integer )
return;
+
if( !ent->client->pers.useUnlagged )
return;
@@ -1400,49 +1220,13 @@ static void G_UnlaggedDetectCollisions( gentity_t *ent )
trap_Trace(&tr, ent->client->oldOrigin, ent->r.mins, ent->r.maxs,
ent->client->ps.origin, ent->s.number, MASK_PLAYERSOLID );
if( tr.entityNum >= 0 && tr.entityNum < MAX_CLIENTS )
- g_entities[ tr.entityNum ].client->unlaggedCalc.used = qfalse;
+ g_entities[ tr.entityNum ].client->unlaggedCalc.used = qfalse;
G_UnlaggedOff( );
}
/*
==============
-ClientGradualFunds
-
-g_gradualFreeFunds values:
-0 - disabled
-1 - vanilla behavior
-2 - 1 and counters don't reset on death or evolution
-3 - 2 and funds are given even during SD
-==============
-*/
-static void ClientGradualFunds( gentity_t *ent )
-{
- if( !g_gradualFreeFunds.integer )
- return;
-
- if( ent->client->pers.lastFreekillTime + FREEKILL_PERIOD >= level.time )
- return;
-
- if( g_suddenDeath.integer && g_gradualFreeFunds.integer < 3 )
- return;
-
- switch ( ent->client->ps.stats[ STAT_PTEAM ] )
- {
- case PTE_ALIENS:
- G_AddCreditToClient( ent->client, FREEKILL_ALIEN, qtrue );
- break;
-
- case PTE_HUMANS:
- G_AddCreditToClient( ent->client, FREEKILL_HUMAN, qtrue );
- break;
- }
-
- ent->client->pers.lastFreekillTime += FREEKILL_PERIOD;
-}
-
-/*
-==============
ClientThink
This will be called once for each client frame, which will
@@ -1459,7 +1243,6 @@ void ClientThink_real( gentity_t *ent )
int oldEventSequence;
int msec;
usercmd_t *ucmd;
- int real_pm_type;
client = ent->client;
@@ -1470,34 +1253,12 @@ void ClientThink_real( gentity_t *ent )
// mark the time, so the connection sprite can be removed
ucmd = &ent->client->pers.cmd;
- if( client->pers.paused )
- ucmd->forwardmove = ucmd->rightmove = ucmd->upmove = ucmd->buttons = 0;
-
// sanity check the command time to prevent speedup cheating
if( ucmd->serverTime > level.time + 200 )
- {
ucmd->serverTime = level.time + 200;
-// G_Printf("serverTime <<<<<\n" );
- }
if( ucmd->serverTime < level.time - 1000 )
- {
ucmd->serverTime = level.time - 1000;
-// G_Printf("serverTime >>>>>\n" );
- }
-
- // ucmd->serverTime is a client predicted value, but it works for making a
- // replacement for client->ps.ping when in SPECTATOR_FOLLOW
- client->pers.ping = level.time - ucmd->serverTime;
-
- // account for the one frame of delay on client side
- client->pers.ping -= level.time - level.previousTime;
-
- // account for the time that's elapsed since the last ClientEndFrame()
- client->pers.ping += trap_Milliseconds( ) - level.frameMsec;
-
- if( client->pers.ping < 0 )
- client->pers.ping = 0;
msec = ucmd->serverTime - client->ps.commandTime;
// following others may result in bad times, but we still want
@@ -1511,9 +1272,15 @@ void ClientThink_real( gentity_t *ent )
client->unlaggedTime = ucmd->serverTime;
if( pmove_msec.integer < 8 )
+ {
trap_Cvar_Set( "pmove_msec", "8" );
+ trap_Cvar_Update(&pmove_msec);
+ }
else if( pmove_msec.integer > 33 )
+ {
trap_Cvar_Set( "pmove_msec", "33" );
+ trap_Cvar_Update(&pmove_msec);
+ }
if( pmove_fixed.integer || client->pers.pmoveFixed )
{
@@ -1527,21 +1294,12 @@ void ClientThink_real( gentity_t *ent )
//
if( level.intermissiontime )
{
- if( level.mapRotationVoteTime )
- {
- SpectatorThink( ent, ucmd );
- return;
- }
-
ClientIntermissionThink( client );
return;
}
- if( client->pers.teamSelection != PTE_NONE && client->pers.joinedATeam )
- G_UpdatePTRConnection( client );
-
// spectators don't do much
- if( client->sess.sessionTeam == TEAM_SPECTATOR )
+ if( client->sess.spectatorState != SPECTATOR_NOT )
{
if( client->sess.spectatorState == SPECTATOR_SCOREBOARD )
return;
@@ -1550,20 +1308,19 @@ void ClientThink_real( gentity_t *ent )
return;
}
+ G_namelog_update_score( client );
+
// check for inactivity timer, but never drop the local client of a non-dedicated server
- if( !ClientInactivityTimer( client ) )
+ if( !ClientInactivityTimer( ent ) )
return;
- // calculate where ent is currently seeing all the other active clients
+ // calculate where ent is currently seeing all the other active clients
G_UnlaggedCalc( ent->client->unlaggedTime, ent );
if( client->noclip )
client->ps.pm_type = PM_NOCLIP;
else if( client->ps.stats[ STAT_HEALTH ] <= 0 )
client->ps.pm_type = PM_DEAD;
- else if( client->ps.stats[ STAT_STATE ] & SS_INFESTING ||
- client->ps.stats[ STAT_STATE ] & SS_HOVELING )
- client->ps.pm_type = PM_FREEZE;
else if( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED ||
client->ps.stats[ STAT_STATE ] & SS_GRABBED )
client->ps.pm_type = PM_GRABBED;
@@ -1572,31 +1329,33 @@ void ClientThink_real( gentity_t *ent )
else
client->ps.pm_type = PM_NORMAL;
- // paused
- real_pm_type = client->ps.pm_type;
- if ( level.paused ) client->ps.pm_type = PM_SPECTATOR;
-
- if( client->ps.stats[ STAT_STATE ] & SS_GRABBED &&
+ if( ( client->ps.stats[ STAT_STATE ] & SS_GRABBED ) &&
client->grabExpiryTime < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_GRABBED;
- if( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED &&
+ if( ( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED ) &&
client->lastLockTime + LOCKBLOB_LOCKTIME < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_BLOBLOCKED;
- if( client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED &&
+ if( ( client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED ) &&
client->lastSlowTime + ABUILDER_BLOB_TIME < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_SLOWLOCKED;
- client->ps.stats[ STAT_BOOSTTIME ] = level.time - client->lastBoostedTime;
-
- if( client->ps.stats[ STAT_STATE ] & SS_BOOSTED &&
- client->lastBoostedTime + BOOST_TIME < level.time )
- client->ps.stats[ STAT_STATE ] &= ~SS_BOOSTED;
+ // Update boosted state flags
+ client->ps.stats[ STAT_STATE ] &= ~SS_BOOSTEDWARNING;
+ if( client->ps.stats[ STAT_STATE ] & SS_BOOSTED )
+ {
+ if( level.time - client->boostedTime >= BOOST_TIME )
+ client->ps.stats[ STAT_STATE ] &= ~SS_BOOSTED;
+ else if( level.time - client->boostedTime >= BOOST_WARN_TIME )
+ client->ps.stats[ STAT_STATE ] |= SS_BOOSTEDWARNING;
+ }
- if( client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED &&
- client->lastPoisonCloudedTime + LEVEL1_PCLOUD_TIME < level.time )
- client->ps.stats[ STAT_STATE ] &= ~SS_POISONCLOUDED;
+ // Check if poison cloud has worn off
+ if( ( client->ps.eFlags & EF_POISONCLOUDED ) &&
+ BG_PlayerPoisonCloudTime( &client->ps ) - level.time +
+ client->lastPoisonCloudedTime <= 0 )
+ client->ps.eFlags &= ~EF_POISONCLOUDED;
if( client->ps.stats[ STAT_STATE ] & SS_POISONED &&
client->lastPoisonTime + ALIEN_POISON_TIME < level.time )
@@ -1608,13 +1367,13 @@ void ClientThink_real( gentity_t *ent )
BG_UpgradeIsActive( UP_MEDKIT, client->ps.stats ) )
{
//if currently using a medkit or have no need for a medkit now
- if( client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE ||
+ if( client->ps.stats[ STAT_STATE ] & SS_HEALING_2X ||
( client->ps.stats[ STAT_HEALTH ] == client->ps.stats[ STAT_MAX_HEALTH ] &&
!( client->ps.stats[ STAT_STATE ] & SS_POISONED ) ) )
{
BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats );
}
- else if( client->ps.stats[ STAT_HEALTH ] > 0 && !level.paused )
+ else if( client->ps.stats[ STAT_HEALTH ] > 0 )
{
//remove anti toxin
BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats );
@@ -1623,7 +1382,7 @@ void ClientThink_real( gentity_t *ent )
client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
client->poisonImmunityTime = level.time + MEDKIT_POISON_IMMUNITY_TIME;
- client->ps.stats[ STAT_STATE ] |= SS_MEDKIT_ACTIVE;
+ client->ps.stats[ STAT_STATE ] |= SS_HEALING_2X;
client->lastMedKitTime = level.time;
client->medKitHealthToRestore =
client->ps.stats[ STAT_MAX_HEALTH ] - client->ps.stats[ STAT_HEALTH ];
@@ -1634,6 +1393,102 @@ void ClientThink_real( gentity_t *ent )
}
}
+ // Replenish alien health
+ if( level.surrenderTeam != client->pers.teamSelection &&
+ ent->nextRegenTime >= 0 && ent->nextRegenTime < level.time )
+ {
+ float regenRate =
+ BG_Class( ent->client->ps.stats[ STAT_CLASS ] )->regenRate;
+
+ if( ent->health <= 0 || ent->nextRegenTime < 0 || regenRate == 0 )
+ ent->nextRegenTime = -1; // no regen
+ else
+ {
+ int entityList[ MAX_GENTITIES ];
+ int i, num;
+ int count, interval;
+ vec3_t range, mins, maxs;
+ float modifier = 1.0f;
+
+ VectorSet( range, REGEN_BOOST_RANGE, REGEN_BOOST_RANGE,
+ REGEN_BOOST_RANGE );
+ VectorAdd( client->ps.origin, range, maxs );
+ VectorSubtract( client->ps.origin, range, mins );
+
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
+ {
+ gentity_t *boost = &g_entities[ entityList[ i ] ];
+
+ if( Distance( client->ps.origin, boost->r.currentOrigin ) > REGEN_BOOST_RANGE )
+ continue;
+
+ if( modifier < BOOSTER_REGEN_MOD && boost->s.eType == ET_BUILDABLE &&
+ boost->s.modelindex == BA_A_BOOSTER && boost->spawned &&
+ boost->health > 0 && boost->powered )
+ {
+ modifier = BOOSTER_REGEN_MOD;
+ continue;
+ }
+
+ if( boost->s.eType == ET_PLAYER && boost->client &&
+ boost->client->pers.teamSelection ==
+ ent->client->pers.teamSelection && boost->health > 0 )
+ {
+ class_t class = boost->client->ps.stats[ STAT_CLASS ];
+ qboolean didBoost = qfalse;
+
+ if( class == PCL_ALIEN_LEVEL1 && modifier < LEVEL1_REGEN_MOD )
+ {
+ modifier = LEVEL1_REGEN_MOD;
+ didBoost = qtrue;
+ }
+ else if( class == PCL_ALIEN_LEVEL1_UPG &&
+ modifier < LEVEL1_UPG_REGEN_MOD )
+ {
+ modifier = LEVEL1_UPG_REGEN_MOD;
+ didBoost = qtrue;
+ }
+
+ if( didBoost && ent->health < client->ps.stats[ STAT_MAX_HEALTH ] )
+ boost->client->pers.hasHealed = qtrue;
+ }
+ }
+
+ // Transmit heal rate to the client so it can be displayed on the HUD
+ client->ps.stats[ STAT_STATE ] |= SS_HEALING_ACTIVE;
+ client->ps.stats[ STAT_STATE ] &= ~( SS_HEALING_2X | SS_HEALING_3X );
+ if( modifier == 1.0f && !G_FindCreep( ent ) )
+ {
+ client->ps.stats[ STAT_STATE ] &= ~SS_HEALING_ACTIVE;
+ modifier *= ALIEN_REGEN_NOCREEP_MOD;
+ }
+ else if( modifier >= 3.0f )
+ client->ps.stats[ STAT_STATE ] |= SS_HEALING_3X;
+ else if( modifier >= 2.0f )
+ client->ps.stats[ STAT_STATE ] |= SS_HEALING_2X;
+
+ interval = 1000 / ( regenRate * modifier );
+ // if recovery interval is less than frametime, compensate
+ count = 1 + ( level.time - ent->nextRegenTime ) / interval;
+ ent->nextRegenTime += count * interval;
+
+ if( ent->health < client->ps.stats[ STAT_MAX_HEALTH ] )
+ {
+ ent->health += count;
+ client->ps.stats[ STAT_HEALTH ] = ent->health;
+
+ // if at max health, clear damage counters
+ if( ent->health >= client->ps.stats[ STAT_MAX_HEALTH ] )
+ {
+ ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ];
+ for( i = 0; i < MAX_CLIENTS; i++ )
+ ent->credits[ i ] = 0;
+ }
+ }
+ }
+ }
+
if( BG_InventoryContainsUpgrade( UP_GRENADE, client->ps.stats ) &&
BG_UpgradeIsActive( UP_GRENADE, client->ps.stats ) )
{
@@ -1650,10 +1505,11 @@ void ClientThink_real( gentity_t *ent )
}
// set speed
- client->ps.speed = g_speed.value * BG_FindSpeedForClass( client->ps.stats[ STAT_PCLASS ] );
-
- if( client->pers.paused )
- client->ps.speed = 0;
+ if( client->ps.pm_type == PM_NOCLIP )
+ client->ps.speed = client->pers.flySpeed;
+ else
+ client->ps.speed = g_speed.value *
+ BG_Class( client->ps.stats[ STAT_CLASS ] )->speed;
if( client->lastCreepSlowTime + CREEP_TIMEOUT < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_CREEPSLOWED;
@@ -1669,7 +1525,7 @@ void ClientThink_real( gentity_t *ent )
}
//switch jetpack off if no reactor
- if( !level.reactorPresent )
+ if( !G_Reactor( ) )
BG_DeactivateUpgrade( UP_JETPACK, client->ps.stats );
}
@@ -1678,50 +1534,19 @@ void ClientThink_real( gentity_t *ent )
memset( &pm, 0, sizeof( pm ) );
- if( !( ucmd->buttons & BUTTON_TALK ) && !( client->ps.pm_flags & PMF_RESPAWNED ) )
- {
- switch( client->ps.weapon )
- {
- case WP_ALEVEL0:
- if( client->ps.weaponTime <= 0 )
- pm.autoWeaponHit[ client->ps.weapon ] = CheckVenomAttack( ent );
- break;
-
- case WP_ALEVEL1:
- case WP_ALEVEL1_UPG:
- CheckGrabAttack( ent );
- break;
-
- case WP_ALEVEL3:
- case WP_ALEVEL3_UPG:
- if( client->ps.weaponTime <= 0 )
- pm.autoWeaponHit[ client->ps.weapon ] = CheckPounceAttack( ent );
- break;
-
- default:
- break;
- }
- }
-
if( ent->flags & FL_FORCE_GESTURE )
{
ent->flags &= ~FL_FORCE_GESTURE;
ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
}
+
+ // clear fall velocity before every pmove
+ client->pmext.fallVelocity = 0.0f;
pm.ps = &client->ps;
pm.pmext = &client->pmext;
pm.cmd = *ucmd;
-
- if( pm.ps->pm_type == PM_DEAD )
- pm.tracemask = MASK_PLAYERSOLID; // & ~CONTENTS_BODY;
-
- if( pm.ps->stats[ STAT_STATE ] & SS_INFESTING ||
- pm.ps->stats[ STAT_STATE ] & SS_HOVELING )
- pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
- else
- pm.tracemask = MASK_PLAYERSOLID;
-
+ pm.tracemask = ent->clipmask;
pm.trace = trap_Trace;
pm.pointcontents = trap_PointContents;
pm.debugLevel = g_debugMove.integer;
@@ -1734,8 +1559,7 @@ void ClientThink_real( gentity_t *ent )
// moved from after Pmove -- potentially the cause of
// future triggering bugs
- if( !ent->client->noclip )
- G_TouchTriggers( ent );
+ G_TouchTriggers( ent );
Pmove( &pm );
@@ -1745,13 +1569,61 @@ void ClientThink_real( gentity_t *ent )
if( ent->client->ps.eventSequence != oldEventSequence )
ent->eventTime = level.time;
- if ( level.paused ) client->ps.pm_type = real_pm_type;
-
+ VectorCopy( ent->client->ps.viewangles, ent->r.currentAngles );
if( g_smoothClients.integer )
BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
else
BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
+ switch( client->ps.weapon )
+ {
+ case WP_ALEVEL0:
+ if( !CheckVenomAttack( ent ) )
+ {
+ client->ps.weaponstate = WEAPON_READY;
+ }
+ else
+ {
+ client->ps.generic1 = WPM_PRIMARY;
+ G_AddEvent( ent, EV_FIRE_WEAPON, 0 );
+ }
+ break;
+
+ case WP_ALEVEL1:
+ case WP_ALEVEL1_UPG:
+ CheckGrabAttack( ent );
+ break;
+
+ case WP_ALEVEL3:
+ case WP_ALEVEL3_UPG:
+ if( !CheckPounceAttack( ent ) )
+ {
+ client->ps.weaponstate = WEAPON_READY;
+ }
+ else
+ {
+ client->ps.generic1 = WPM_SECONDARY;
+ G_AddEvent( ent, EV_FIRE_WEAPON2, 0 );
+ }
+ break;
+
+ case WP_ALEVEL4:
+ // If not currently in a trample, reset the trample bookkeeping data
+ if( !( client->ps.pm_flags & PMF_CHARGE ) && client->trampleBuildablesHitPos )
+ {
+ ent->client->trampleBuildablesHitPos = 0;
+ memset( ent->client->trampleBuildablesHit, 0, sizeof( ent->client->trampleBuildablesHit ) );
+ }
+ break;
+
+ case WP_HBUILD:
+ CheckCkitRepair( ent );
+ break;
+
+ default:
+ break;
+ }
+
SendPendingPredictableEvents( &ent->client->ps );
if( !( ent->client->ps.eFlags & EF_FIRING ) )
@@ -1770,7 +1642,7 @@ void ClientThink_real( gentity_t *ent )
// touch other objects
ClientImpacts( ent, &pm );
-
+
// execute client events
ClientEvents( ent, oldEventSequence );
@@ -1779,12 +1651,12 @@ void ClientThink_real( gentity_t *ent )
// NOTE: now copy the exact origin over otherwise clients can be snapped into solid
VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
- VectorCopy( ent->client->ps.origin, ent->s.origin );
+ VectorCopy( ent->client->ps.origin, ent->s.pos.trBase );
// save results of triggers and client events
if( ent->client->ps.eventSequence != oldEventSequence )
ent->eventTime = level.time;
-
+
// Don't think anymore if dead
if( client->ps.stats[ STAT_HEALTH ] <= 0 )
return;
@@ -1794,121 +1666,84 @@ void ClientThink_real( gentity_t *ent )
client->buttons = ucmd->buttons;
client->latched_buttons |= client->buttons & ~client->oldbuttons;
- if( ( client->buttons & BUTTON_GETFLAG ) && !( client->oldbuttons & BUTTON_GETFLAG ) &&
+ if( ( client->buttons & BUTTON_USE_EVOLVE ) && !( client->oldbuttons & BUTTON_USE_EVOLVE ) &&
client->ps.stats[ STAT_HEALTH ] > 0 )
{
trace_t trace;
vec3_t view, point;
gentity_t *traceEnt;
- if( client->ps.stats[ STAT_STATE ] & SS_HOVELING )
- {
- gentity_t *hovel = client->hovel;
+#define USE_OBJECT_RANGE 64
- //only let the player out if there is room
- if( !AHovel_Blocked( hovel, ent, qtrue ) )
- {
- //prevent lerping
- client->ps.eFlags ^= EF_TELEPORT_BIT;
- client->ps.eFlags &= ~EF_NODRAW;
- G_UnlaggedClear( ent );
+ int entityList[ MAX_GENTITIES ];
+ vec3_t range = { USE_OBJECT_RANGE, USE_OBJECT_RANGE, USE_OBJECT_RANGE };
+ vec3_t mins, maxs;
+ int i, num;
- //client leaves hovel
- client->ps.stats[ STAT_STATE ] &= ~SS_HOVELING;
+ // look for object infront of player
+ AngleVectors( client->ps.viewangles, view, NULL, NULL );
+ VectorMA( client->ps.origin, USE_OBJECT_RANGE, view, point );
+ trap_Trace( &trace, client->ps.origin, NULL, NULL, point, ent->s.number, MASK_SHOT );
- //hovel is empty
- G_SetBuildableAnim( hovel, BANIM_ATTACK2, qfalse );
- hovel->active = qfalse;
- }
- else
- {
- //exit is blocked
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_HOVEL_BLOCKED );
- }
- }
+ traceEnt = &g_entities[ trace.entityNum ];
+
+ if( traceEnt && traceEnt->buildableTeam == client->ps.stats[ STAT_TEAM ] && traceEnt->use )
+ traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context
else
{
-#define USE_OBJECT_RANGE 64
-
- int entityList[ MAX_GENTITIES ];
- vec3_t range = { USE_OBJECT_RANGE, USE_OBJECT_RANGE, USE_OBJECT_RANGE };
- vec3_t mins, maxs;
- int i, num;
+ //no entity in front of player - do a small area search
- //TA: look for object infront of player
- AngleVectors( client->ps.viewangles, view, NULL, NULL );
- VectorMA( client->ps.origin, USE_OBJECT_RANGE, view, point );
- trap_Trace( &trace, client->ps.origin, NULL, NULL, point, ent->s.number, MASK_SHOT );
-
- traceEnt = &g_entities[ trace.entityNum ];
+ VectorAdd( client->ps.origin, range, maxs );
+ VectorSubtract( client->ps.origin, range, mins );
- if( traceEnt && traceEnt->biteam == client->ps.stats[ STAT_PTEAM ] && traceEnt->use )
- traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context
- else
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
{
- //no entity in front of player - do a small area search
-
- VectorAdd( client->ps.origin, range, maxs );
- VectorSubtract( client->ps.origin, range, mins );
+ traceEnt = &g_entities[ entityList[ i ] ];
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
+ if( traceEnt && traceEnt->buildableTeam == client->ps.stats[ STAT_TEAM ] && traceEnt->use )
{
- traceEnt = &g_entities[ entityList[ i ] ];
-
- if( traceEnt && traceEnt->biteam == client->ps.stats[ STAT_PTEAM ] && traceEnt->use )
- {
- traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context
- break;
- }
+ traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context
+ break;
}
+ }
- if( i == num && client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( i == num && client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ {
+ if( BG_AlienCanEvolve( client->ps.stats[ STAT_CLASS ],
+ client->pers.credit,
+ g_alienStage.integer ) )
{
- if( BG_UpgradeClassAvailable( &client->ps ) )
- {
- //no nearby objects and alien - show class menu
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_INFEST );
- }
- else
- {
- //flash frags
- G_AddEvent( ent, EV_ALIEN_EVOLVE_FAILED, 0 );
- }
+ //no nearby objects and alien - show class menu
+ G_TriggerMenu( ent->client->ps.clientNum, MN_A_INFEST );
+ }
+ else
+ {
+ //flash frags
+ G_AddEvent( ent, EV_ALIEN_EVOLVE_FAILED, 0 );
}
}
}
}
- if( level.framenum > client->retriggerArmouryMenu && client->retriggerArmouryMenu )
- {
- G_TriggerMenu( client->ps.clientNum, MN_H_ARMOURY );
-
- client->retriggerArmouryMenu = 0;
- }
+ client->ps.persistant[ PERS_BP ] = G_GetBuildPoints( client->ps.origin,
+ client->ps.stats[ STAT_TEAM ] );
+ client->ps.persistant[ PERS_MARKEDBP ] = G_GetMarkedBuildPoints( client->ps.origin,
+ client->ps.stats[ STAT_TEAM ] );
- // Give clients some credit periodically
- ClientGradualFunds( ent );
+ if( client->ps.persistant[ PERS_BP ] < 0 )
+ client->ps.persistant[ PERS_BP ] = 0;
// perform once-a-second actions
ClientTimerActions( ent, msec );
-
+
if( ent->suicideTime > 0 && ent->suicideTime < level.time )
{
- ent->flags &= ~FL_GODMODE;
ent->client->ps.stats[ STAT_HEALTH ] = ent->health = 0;
player_die( ent, ent, ent, 100000, MOD_SUICIDE );
ent->suicideTime = 0;
}
- if( client->pers.bubbleTime && client->pers.bubbleTime < level.time )
- {
- gentity_t *bubble;
-
- client->pers.bubbleTime = level.time + 500;
- bubble = G_TempEntity( client->ps.origin, EV_PLAYER_TELEPORT_OUT );
- bubble->s.clientNum = ent->s.clientNum;
- }
}
/*
@@ -1953,52 +1788,30 @@ SpectatorClientEndFrame
void SpectatorClientEndFrame( gentity_t *ent )
{
gclient_t *cl;
- int clientNum, flags;
+ int clientNum;
int score, ping;
- vec3_t spawn_origin, spawn_angles;
// if we are doing a chase cam or a remote view, grab the latest info
if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
{
clientNum = ent->client->sess.spectatorClient;
-
- if( clientNum >= 0 )
+ if( clientNum >= 0 && clientNum < level.maxclients )
{
cl = &level.clients[ clientNum ];
-
if( cl->pers.connected == CON_CONNECTED )
{
-
- if( cl -> sess.spectatorState != SPECTATOR_FOLLOW )
- {
- flags = ( cl->ps.eFlags & ~( EF_VOTED | EF_TEAMVOTED ) ) |
- ( ent->client->ps.eFlags & ( EF_VOTED | EF_TEAMVOTED ) );
- score = ent->client->ps.persistant[ PERS_SCORE ];
- ping = ent->client->ps.ping;
- ent->client->ps = cl->ps;
- ent->client->ps.persistant[ PERS_SCORE ] = score;
- ent->client->ps.ping = ping;
- ent->client->ps.eFlags = flags;
- ent->client->ps.pm_flags |= PMF_FOLLOW;
- ent->client->ps.pm_flags &= ~PMF_QUEUED;
- }
- else //we are stickyspec-spectating someone who is spectating someone else
- {
- ent->client->ps.clientNum = (g_entities + clientNum)->s.number;
- ent->client->ps.commandTime = cl->ps.commandTime;
- ent->client->ps.weapon = 0;
- ent->client->ps.pm_flags |= PMF_FOLLOW;
- ent->client->ps.stats[ STAT_PCLASS ] = PCL_NONE;
-
- if( cl->pers.teamSelection == PTE_ALIENS )
- G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles );
- else if( cl->pers.teamSelection == PTE_HUMANS )
- G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles );
-
- G_SetOrigin( ent, spawn_origin );
- VectorCopy( spawn_origin, ent->client->ps.origin );
- G_SetClientViewAngle( ent, spawn_angles );
- }
+ score = ent->client->ps.persistant[ PERS_SCORE ];
+ ping = ent->client->ps.ping;
+
+ // Copy
+ ent->client->ps = cl->ps;
+
+ // Restore
+ ent->client->ps.persistant[ PERS_SCORE ] = score;
+ ent->client->ps.ping = ping;
+
+ ent->client->ps.pm_flags |= PMF_FOLLOW;
+ ent->client->ps.pm_flags &= ~PMF_QUEUED;
}
}
}
@@ -2015,20 +1828,12 @@ while a slow client may have multiple ClientEndFrame between ClientThink.
*/
void ClientEndFrame( gentity_t *ent )
{
- clientPersistant_t *pers;
-
- if( ent->client->sess.sessionTeam == TEAM_SPECTATOR )
+ if( ent->client->sess.spectatorState != SPECTATOR_NOT )
{
SpectatorClientEndFrame( ent );
return;
}
- pers = &ent->client->pers;
-
- // save a copy of certain playerState values in case of SPECTATOR_FOLLOW
- pers->score = ent->client->ps.persistant[ PERS_SCORE ];
- pers->credit = ent->client->ps.persistant[ PERS_CREDIT ];
-
//
// If the end of unit layout is displayed, don't give
// the player any normal movement attributes
@@ -2048,8 +1853,6 @@ void ClientEndFrame( gentity_t *ent )
else
ent->s.eFlags &= ~EF_CONNECTION;
- ent->client->ps.stats[ STAT_HEALTH ] = ent->health; // FIXME: get rid of ent->health...
-
// respawn if dead
if( ent->client->ps.stats[ STAT_HEALTH ] <= 0 && level.time >= ent->client->respawnTime )
respawn( ent );
@@ -2064,5 +1867,3 @@ void ClientEndFrame( gentity_t *ent )
SendPendingPredictableEvents( &ent->client->ps );
}
-
-
diff --git a/src/game/g_admin.c b/src/game/g_admin.c
index dc19530..afc40cb 100644
--- a/src/game/g_admin.c
+++ b/src/game/g_admin.c
@@ -1,6 +1,7 @@
/*
===========================================================================
-Copyright (C) 2004-2006 Tony J. White
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
@@ -11,12 +12,12 @@ and Travis Maurer.
The functionality of this code mimics the behaviour of the currently
inactive project shrubet (http://www.etstats.com/shrubet/index.php?ver=2)
-by Ryan Mannion. However, shrubet was a closed-source project and
-none of it's code has been copied, only it's functionality.
+by Ryan Mannion. However, shrubet was a closed-source project and
+none of its code has been copied, only its functionality.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -25,8 +26,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -36,420 +37,270 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
static char g_bfb[ 32000 ];
// note: list ordered alphabetically
-g_admin_cmd_t g_admin_cmds[ ] =
- {
- {"adjustban", G_admin_adjustban, "ban",
- "change the duration or reason of a ban. time is specified as numbers "
- "followed by units 'w' (weeks), 'd' (days), 'h' (hours) or 'm' (minutes),"
- " or seconds if no units are specified. if the duration is"
- " preceded by a + or -, the ban duration will be extended or shortened by"
- " the specified amount",
- "[^3ban#^7] (^5duration^7) (^5reason^7)"
+g_admin_cmd_t g_admin_cmds[ ] =
+ {
+ {"addlayout", G_admin_addlayout, qfalse, "addlayout",
+ "place layout elements into the game. the elements are specified by a "
+ "union of filtered layouts. the syntax is demonstrated by an example: "
+ "^5reactor,telenode|westside+alien|sewers^7 will place only the "
+ "reactor and telenodes from the westside layout, and also all alien "
+ "layout elements from the sewers layout",
+ "[^3layoutelements^7]"
+ },
+
+ {"adjustban", G_admin_adjustban, qfalse, "ban",
+ "change the IP address mask, duration or reason of a ban. mask is "
+ "prefixed with '/'. duration is specified as numbers followed by units "
+ " 'w' (weeks), 'd' (days), 'h' (hours) or 'm' (minutes), or seconds if "
+ " no unit is specified. if the duration is preceded by a + or -, the "
+ "ban duration will be extended or shortened by the specified amount",
+ "[^3ban#^7] (^5/mask^7) (^5duration^7) (^5reason^7)"
},
-
- {"adminlog", G_admin_adminlog, "adminlog",
- "list recent admin activity",
- "(^5start id#|name|!command|-skip#^7) (^5search skip#^7)"
+
+ {"adminhelp", G_admin_adminhelp, qtrue, "adminhelp",
+ "display admin commands available to you or help on a specific command",
+ "(^5command^7)"
},
- {"admintest", G_admin_admintest, "admintest",
+ {"admintest", G_admin_admintest, qfalse, "admintest",
"display your current admin level",
""
},
- {"allowbuild", G_admin_denybuild, "denybuild",
+ {"allowbuild", G_admin_denybuild, qfalse, "denybuild",
"restore a player's ability to build",
"[^3name|slot#^7]"
},
- {"allowweapon", G_admin_denyweapon, "denyweapon",
- "restore a player's ability to use a weapon or class",
- "[^3name|slot#^7] [^3class|weapon|all^7]"
- },
-
- {"allready", G_admin_allready, "allready",
+ {"allready", G_admin_allready, qfalse, "allready",
"makes everyone ready in intermission",
""
},
- {"ban", G_admin_ban, "ban",
+ {"ban", G_admin_ban, qfalse, "ban",
"ban a player by IP and GUID with an optional expiration time and reason."
- " time is specified as numbers followed by units 'w' (weeks), 'd' "
+ " duration is specified as numbers followed by units 'w' (weeks), 'd' "
"(days), 'h' (hours) or 'm' (minutes), or seconds if no units are "
"specified",
- "[^3name|slot#|IP^7] (^5time^7) (^5reason^7)"
- },
-
- {"buildlog", G_admin_buildlog, "buildlog",
- "display a list of recent builds and deconstructs, optionally specifying"
- " a team",
- "(^5xnum^7) (^5#skip^7) (^5-name|num^7) (^5a|h^7)"
- "\n ^3Example:^7 '!buildlog #10 h' skips 10 events, then shows the previous 10 events affecting human buildables"
+ "[^3name|slot#|IP(/mask)^7] (^5duration^7) (^5reason^7)"
},
- {"cancelvote", G_admin_cancelvote, "cancelvote",
- "cancel a vote taking place",
+ {"builder", G_admin_builder, qtrue, "builder",
+ "show who built a structure",
""
},
-
- {"cp", G_admin_cp, "cp",
- "display a CP message to users, optionally specifying team(s) to send to",
- "(-AHS) [^3message^7]"
- },
- {"decon", G_admin_decon, "decon",
- "Reverts a decon previously made and ban the user for the time specified in g_deconBanTime",
- "[^3name|slot#^7]"
- },
-
- {"demo", G_admin_demo, "demo",
- "turn admin chat off for the caller so it does not appear in demos. "
- "this is a toggle use !demo again to turn warnings back on",
- ""
- },
-
- {"denybuild", G_admin_denybuild, "denybuild",
- "take away a player's ability to build",
- "[^3name|slot#^7]"
+ {"buildlog", G_admin_buildlog, qfalse, "buildlog",
+ "show buildable log",
+ "(^5name|slot#^7) (^5id^7)"
},
- {"designate", G_admin_designate, "designate",
- "give the player designated builder privileges",
- "[^3name|slot#^7]"
+ {"cancelvote", G_admin_endvote, qfalse, "cancelvote",
+ "cancel a vote taking place",
+ "(^5a|h^7)"
},
- {"devmap", G_admin_devmap, "devmap",
- "load a map with cheats (and optionally force layout)",
+ {"changemap", G_admin_changemap, qfalse, "changemap",
+ "load a map (and optionally force layout)",
"[^3mapname^7] (^5layout^7)"
},
- {"denyweapon", G_admin_denyweapon, "denyweapon",
- "take away a player's ability to use a weapon or class",
- "[^3name|slot#^7] [^3class|weapon^7]"
- },
-
- {"drop", G_admin_drop, "drop",
- "kick a client from the server without log",
- "[^3name|slot#^7] [^3message^7]"
- },
-
- {"flag", G_admin_flag, "flag",
- "add an admin flag to a player, prefix flag with '-' to disallow the flag. "
- "console can use this command on admin levels by prefacing a '*' to the admin level value.",
- "[^3name|slot#|admin#|*adminlevel^7] (^5+^7|^5-^7)[^3flag^7]"
- },
-
- {"flaglist", G_admin_flaglist, "flag",
- "list all flags understood by this server",
- ""
- },
-
- {"help", G_admin_help, "help",
- "display commands available to you or help on a specific command",
- "(^5command^7)"
+ {"denybuild", G_admin_denybuild, qfalse, "denybuild",
+ "take away a player's ability to build",
+ "[^3name|slot#^7]"
},
- {"info", G_admin_info, "info",
- "display the contents of server info files",
- "(^5subject^7)"
- },
-
- {"invisible", G_admin_invisible, "invisible",
- "hides a player so they cannot be seen in playerlists",
- ""
- },
-
- {"kick", G_admin_kick, "kick",
+ {"kick", G_admin_kick, qfalse, "kick",
"kick a player with an optional reason",
"[^3name|slot#^7] (^5reason^7)"
},
-
- {"L0", G_admin_L0, "l0",
- "Sets a level 1 to level 0",
- "[^3name|slot#^7]"
- },
-
- {"L1", G_admin_L1, "l1",
- "Sets a level 0 to level 1",
- "[^3name|slot#^7]"
- },
-
- {"layoutsave", G_admin_layoutsave, "layoutsave",
- "save a map layout",
- "[^3mapname^7]"
- },
-
- {"listadmins", G_admin_listadmins, "listadmins",
+
+ {"listadmins", G_admin_listadmins, qtrue, "listadmins",
"display a list of all server admins and their levels",
- "(^5name|start admin#^7) (^5minimum level to display^7)"
+ "(^5name^7) (^5start admin#^7)"
},
-
- {"listlayouts", G_admin_listlayouts, "listlayouts",
+
+ {"listlayouts", G_admin_listlayouts, qtrue, "listlayouts",
"display a list of all available layouts for a map",
"(^5mapname^7)"
},
- {"listplayers", G_admin_listplayers, "listplayers",
+ {"listplayers", G_admin_listplayers, qtrue, "listplayers",
"display a list of players, their client numbers and their levels",
""
},
-
- {"listmaps", G_admin_listmaps, "listmaps",
- "display a list of available maps on the server",
- "(^5map name^7)"
- },
-
- {"lock", G_admin_lock, "lock",
+
+ {"lock", G_admin_lock, qfalse, "lock",
"lock a team to prevent anyone from joining it",
"[^3a|h^7]"
},
-
- {"map", G_admin_map, "map",
- "load a map (and optionally force layout)",
- "[^3mapname^7] (^5layout^7)"
- },
- {"maplog", G_admin_maplog, "maplog",
- "show recently played maps",
- ""
- },
-
- {"mute", G_admin_mute, "mute",
+ {"mute", G_admin_mute, qfalse, "mute",
"mute a player",
- "[^3name|slot#^7] (Duration)"
+ "[^3name|slot#^7]"
},
-
- {"namelog", G_admin_namelog, "namelog",
+
+ {"namelog", G_admin_namelog, qtrue, "namelog",
"display a list of names used by recently connected players",
- "(^5name^7)"
+ "(^5name|IP(/mask)^7) (start namelog#)"
},
- {"nextmap", G_admin_nextmap, "nextmap",
+ {"nextmap", G_admin_nextmap, qfalse, "nextmap",
"go to the next map in the cycle",
""
},
- {"nobuild", G_admin_nobuild, "nobuild",
- "set nobuild markers to prevent players from building in an area",
- "(^5area^7) (^5height^7)"
+ {"passvote", G_admin_endvote, qfalse, "passvote",
+ "pass a vote currently taking place",
+ "(^5a|h^7)"
},
- {"passvote", G_admin_passvote, "passvote",
- "pass a vote currently taking place",
+ {"pause", G_admin_pause, qfalse, "pause",
+ "Pause (or unpause) the game.",
""
},
-
- {"pause", G_admin_pause, "pause",
- "prevent a player from interacting with the game."
- " * will pause all players, using no argument will pause game clock",
- "(^5name|slot|*^7)"
- },
-
- {"putteam", G_admin_putteam, "putteam",
+ {"putteam", G_admin_putteam, qfalse, "putteam",
"move a player to a specified team",
- "[^3name|slot#^7] [^3h|a|s^7] (^3duration^7)"
+ "[^3name|slot#^7] [^3h|a|s^7]"
},
- {"readconfig", G_admin_readconfig, "readconfig",
+ {"readconfig", G_admin_readconfig, qfalse, "readconfig",
"reloads the admin config file and refreshes permission flags",
""
},
-
- {"register", G_admin_register, "register",
- "Registers your name to protect it from being used by others or updates your admin name to your current name.",
- ""
- },
- {"rename", G_admin_rename, "rename",
+ {"rename", G_admin_rename, qfalse, "rename",
"rename a player",
"[^3name|slot#^7] [^3new name^7]"
},
- {"restart", G_admin_restart, "restart",
+ {"restart", G_admin_restart, qfalse, "restart",
"restart the current map (optionally using named layout or keeping/switching teams)",
"(^5layout^7) (^5keepteams|switchteams|keepteamslock|switchteamslock^7)"
},
- {"revert", G_admin_revert, "revert",
- "revert one or more buildlog events, optionally of only one team",
- "(^5xnum^7) (^5#ID^7) (^5-name|num^7) (^5a|h^7)"
- "\n ^3Example:^7 '!revert x5 h' reverts the last 5 events affecting human buildables"
+ {"revert", G_admin_revert, qfalse, "revert",
+ "revert buildables to a given time",
+ "[^3id^7]"
},
- {"rotation", G_admin_listrotation, "rotation",
- "display a list of maps that are in the active map rotation",
- ""
+ {"setdevmode", G_admin_setdevmode, qfalse, "setdevmode",
+ "switch developer mode on or off",
+ "[^3on|off^7]"
},
- {"seen", G_admin_seen, "seen",
- "find the last time a player was on the server",
- "[^3name|admin#^7]"
+ {"setivo", G_admin_setivo, qfalse, "setivo",
+ "set an intermission view override",
+ "[^3s|a|h^7]"
},
- {"setlevel", G_admin_setlevel, "setlevel",
+ {"setlevel", G_admin_setlevel, qfalse, "setlevel",
"sets the admin level of a player",
"[^3name|slot#|admin#^7] [^3level^7]"
},
- {"showbans", G_admin_showbans, "showbans",
- "display a (partial) list of active bans",
- "(^5start at ban#^7) (^5name|IP|'-subnet'^7)"
+ {"setnextmap", G_admin_setnextmap, qfalse, "setnextmap",
+ "set the next map (and, optionally, a forced layout)",
+ "[^3mapname^7] (^5layout^7)"
},
- {"slap", G_admin_slap, "slap",
- "Do damage to a player, and send them flying",
- "[^3name|slot^7] (damage)"
+ {"showbans", G_admin_showbans, qtrue, "showbans",
+ "display a (partial) list of active bans",
+ "(^5name|IP(/mask)^7) (^5start at ban#^7)"
},
- {"spec999", G_admin_spec999, "spec999",
+ {"spec999", G_admin_spec999, qfalse, "spec999",
"move 999 pingers to the spectator team",
- ""
- },
-
- {"specme", G_admin_putmespec, "specme",
- "moves you to the spectators",
- ""
- },
-
- {"subnetban", G_admin_subnetban, "subnetban",
- "Add or change a subnet mask on a ban",
- "[^3ban#^7] [^5CIDR mask^7]"
- "\n ^3Example:^7 '!subnetban 10 16' changes ban #10 to be a ban on XXX.XXX.*.*"
- "\n ^3Example:^7 '!subnetban 10 24' changes ban #10 to be a ban on XXX.XXX.XXX.*"
- "\n ^3Example:^7 '!subnetban 10 32' changes ban #10 to be a regular (non-subnet) ban"
- "\n ^1WARNING:^7 Use of this command may make your admin.dat incompatible with other game.qvms"
- },
-
- {"suspendban", G_admin_suspendban, "ban",
- "suspend a ban for a length of time. time is specified as numbers "
- "followed by units 'w' (weeks), 'd' (days), 'h' (hours) or 'm' (minutes),"
- " or seconds if no units are specified",
- "[^5ban #^7] [^5length^7]"
- },
+ ""},
- {"time", G_admin_time, "time",
+ {"time", G_admin_time, qtrue, "time",
"show the current local server time",
- ""
+ ""},
+ {"transform", G_admin_transform, qfalse, "magic",
+ "change a human player to a different player model",
+ "[^3name|slot#^7] [^3player model^7]"
},
- {"unban", G_admin_unban, "ban",
+ {"unban", G_admin_unban, qfalse, "ban",
"unbans a player specified by the slot as seen in showbans",
"[^3ban#^7]"
},
-
- {"undesignate", G_admin_designate, "designate",
- "revoke designated builder privileges",
- "[^3name|slot#^7]"
- },
-
- {"unflag", G_admin_flag, "flag",
- "clears an admin flag from a player. "
- "console can use this command on admin levels by prefacing a '*' to the admin level value.",
- "[^3name|slot#|admin#|*adminlevel^7] (^5+^7|^5-^7)[^3flag^7]"
- },
- {"unlock", G_admin_unlock, "lock",
+ {"unlock", G_admin_lock, qfalse, "lock",
"unlock a locked team",
"[^3a|h^7]"
},
-
- {"unmute", G_admin_mute, "mute",
+
+ {"unmute", G_admin_mute, qfalse, "mute",
"unmute a muted player",
"[^3name|slot#^7]"
},
- {"unpause", G_admin_pause, "pause",
- "allow a player to interact with the game."
- " * will unpause all players, using no argument will unpause game clock",
- "(^5name|slot|*^7)"
- },
-
- {
- "warn", G_admin_warn, "warn",
- "Warn a player to cease or face admin intervention",
- "[^3name|slot#^7] [reason]"
- },
-
- {"setdevmode", G_admin_setdevmode, "setdevmode",
- "switch developer mode on or off",
- "[^3on|off^7]"
- },
+ {"sm", G_admin_sm, qfalse, "schachtmeister",
+ "Schachtmeister",
+ "..."
+ }
+ };
- {"hstage", G_admin_hstage, "stage",
- "change the stage for humans",
- "[^3#^7]"
- },
+static size_t adminNumCmds = ARRAY_LEN( g_admin_cmds );
- {"astage", G_admin_astage, "stage",
- "change the stage for aliens",
- "[^3#^7]"
- },
+static int admin_level_maxname = 0;
+g_admin_level_t *g_admin_levels = NULL;
+g_admin_admin_t *g_admin_admins = NULL;
+g_admin_ban_t *g_admin_bans = NULL;
+g_admin_command_t *g_admin_commands = NULL;
- {"bubble", G_admin_bubble, "bubble",
- "continuously spawn bubbles around a player",
- "[^3name|slot#^7]"
- },
+void G_admin_register_cmds( void )
+{
+ int i;
- {"scrim", G_admin_scrim, "scrim",
- "toggles scrim mode",
- "[on|off]",
- },
+ for( i = 0; i < adminNumCmds; i++ )
+ trap_AddCommand( g_admin_cmds[ i ].keyword );
+}
- {"give", G_admin_give, "give",
- "give funds to a player",
- "[^3name|slot#^7] [^3amount^7]"
- },
+void G_admin_unregister_cmds( void )
+{
+ int i;
- {"setrotation", G_admin_setrotation, "setrotation",
- "sets the map rotation",
- "[^3rotation^7]"
- },
+ for( i = 0; i < adminNumCmds; i++ )
+ trap_RemoveCommand( g_admin_cmds[ i ].keyword );
+}
- {"versions", G_admin_versions, "namelog",
- "Check what versions of Tremulous players are running.",
- ""
- },
+void G_admin_cmdlist( gentity_t *ent )
+{
+ int i;
+ char out[ MAX_STRING_CHARS ] = "";
+ int len, outlen;
- {"showff", G_admin_showff, "showff",
- "shows how much friendly damage a player has done this game"
- "\nno arguments will list all connected players",
- "(^3name|slot^7)"
- "\n ^3Example:^7 ^120% ^7means 1/5th of the damage dealt this game was dealt to the team"
- },
+ outlen = 0;
- {"tklog", G_admin_tklog, "tklog",
- "list recent teamkill activity",
- "(^5start id#|name|-skip#^7) (^5search skip#^7)"
- },
+ for( i = 0; i < adminNumCmds; i++ )
+ {
+ if( !G_admin_permission( ent, g_admin_cmds[ i ].flag ) )
+ continue;
- {"sm", G_admin_sm, "schachtmeister",
- "Schachtmeister",
- "..."
+ len = strlen( g_admin_cmds[ i ].keyword ) + 1;
+ if( len + outlen >= sizeof( out ) - 1 )
+ {
+ trap_SendServerCommand( ent - g_entities, va( "cmds%s\n", out ) );
+ outlen = 0;
}
- };
-
-static int adminNumCmds = sizeof( g_admin_cmds ) / sizeof( g_admin_cmds[ 0 ] );
-
-static int admin_level_maxname = 0;
-g_admin_level_t *g_admin_levels[ MAX_ADMIN_LEVELS ];
-g_admin_admin_t *g_admin_admins[ MAX_ADMIN_ADMINS ];
-g_admin_ban_t *g_admin_bans[ MAX_ADMIN_BANS ];
-g_admin_command_t *g_admin_commands[ MAX_ADMIN_COMMANDS ];
-g_admin_namelog_t *g_admin_namelog[ MAX_ADMIN_NAMELOGS ];
+ strcpy( out + outlen, va( " %s", g_admin_cmds[ i ].keyword ) );
+ outlen += len;
+ }
-int G_admin_parse_time( const char *time );
+ trap_SendServerCommand( ent - g_entities, va( "cmds%s\n", out ) );
+}
// match a certain flag within these flags
-// return state of whether flag was found or not,
-// set *perm to indicate whether found flag was + or -
static qboolean admin_permission( char *flags, const char *flag, qboolean *perm )
{
char *token, *token_p = flags;
- qboolean all_found = qfalse;
- qboolean base_perm = qfalse;
-
+ qboolean allflags = qfalse;
+ qboolean p = qfalse;
+ *perm = qfalse;
while( *( token = COM_Parse( &token_p ) ) )
{
*perm = qtrue;
@@ -459,63 +310,84 @@ static qboolean admin_permission( char *flags, const char *flag, qboolean *perm
return qtrue;
if( !strcmp( token, ADMF_ALLFLAGS ) )
{
- all_found = qtrue;
- base_perm = *perm;
+ allflags = qtrue;
+ p = *perm;
}
}
+ if( allflags )
+ *perm = p;
+ return allflags;
+}
+
+g_admin_cmd_t *G_admin_cmd( const char *cmd )
+{
+ return bsearch( cmd, g_admin_cmds, adminNumCmds, sizeof( g_admin_cmd_t ),
+ cmdcmp );
+}
+
+g_admin_level_t *G_admin_level( const int l )
+{
+ g_admin_level_t *level;
- if( all_found && flag[ 0 ] != '.' )
+ for( level = g_admin_levels; level; level = level->next )
{
- *perm = base_perm;
- return qtrue;
+ if( level->level == l )
+ return level;
}
- return qfalse;
+ return NULL;
}
-static int admin_adminlog_index = 0;
-g_admin_adminlog_t *g_admin_adminlog[ MAX_ADMIN_ADMINLOGS ];
-
-static int admin_tklog_index = 0;
-g_admin_tklog_t *g_admin_tklog[ MAX_ADMIN_TKLOGS ];
-
-// This function should only be used directly when the client is connecting and thus has no GUID.
-// Else, use G_admin_permission()
-qboolean G_admin_permission_guid( char *guid, const char* flag )
+g_admin_admin_t *G_admin_admin( const char *guid )
{
- int i;
- int l = 0;
- qboolean perm = qfalse;
+ g_admin_admin_t *admin;
- // Does the admin specifically have this flag granted/denied to them,
- // irrespective of their admin level?
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ for( admin = g_admin_admins; admin; admin = admin->next )
{
- if( !Q_stricmp( guid, g_admin_admins[ i ]->guid ) )
- {
- if( admin_permission( g_admin_admins[ i ]->flags, flag, &perm ) )
- return perm;
- l = g_admin_admins[ i ]->level;
- break;
- }
+ if( !Q_stricmp( admin->guid, guid ) )
+ return admin;
}
- // If not, is this flag granted/denied for their admin level?
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ return NULL;
+}
+
+g_admin_command_t *G_admin_command( const char *cmd )
+{
+ g_admin_command_t *c;
+
+ for( c = g_admin_commands; c; c = c->next )
{
- if( g_admin_levels[ i ]->level == l )
- return admin_permission( g_admin_levels[ i ]->flags, flag, &perm ) &&
- perm;
+ if( !Q_stricmp( c->command, cmd ) )
+ return c;
}
- return qfalse;
-}
+ return NULL;
+}
qboolean G_admin_permission( gentity_t *ent, const char *flag )
{
- if(!ent) return qtrue; //console always wins
+ qboolean perm;
+ g_admin_admin_t *a;
+ g_admin_level_t *l;
+
+ // console always wins
+ if( !ent )
+ return qtrue;
+
+ if( ( a = ent->client->pers.admin ) )
+ {
+ if( admin_permission( a->flags, flag, &perm ) )
+ return perm;
+
+ l = G_admin_level( a->level );
+ }
+ else
+ l = G_admin_level( 0 );
+
+ if( l )
+ return admin_permission( l->flags, flag, &perm ) && perm;
- return G_admin_permission_guid(ent->client->pers.guid, flag);
+ return qfalse;
}
qboolean G_admin_name_check( gentity_t *ent, char *name, char *err, int len )
@@ -524,125 +396,94 @@ qboolean G_admin_name_check( gentity_t *ent, char *name, char *err, int len )
gclient_t *client;
char testName[ MAX_NAME_LENGTH ] = {""};
char name2[ MAX_NAME_LENGTH ] = {""};
+ g_admin_admin_t *admin;
int alphaCount = 0;
- G_SanitiseString( name, name2, sizeof( name2) );
+ G_SanitiseString( name, name2, sizeof( name2 ) );
- if( !Q_stricmp( name2, "UnnamedPlayer" ) )
+ if( !strcmp( name2, "unnamedplayer" ) )
return qtrue;
- if( !Q_stricmp( name2, "console" ) )
+ if( !strcmp( name2, "console" ) )
+ {
+ if( err && len > 0 )
+ Q_strncpyz( err, "The name 'console' is not allowed.", len );
+ return qfalse;
+ }
+
+ G_DecolorString( name, testName, sizeof( testName ) );
+ if( isdigit( testName[ 0 ] ) )
{
- Q_strncpyz( err, va( "The name '%s^7' is invalid here", name2 ),
- len );
+ if( err && len > 0 )
+ Q_strncpyz( err, "Names cannot begin with numbers", len );
+ return qfalse;
+ }
+
+ for( i = 0; testName[ i ]; i++)
+ {
+ if( isalpha( testName[ i ] ) )
+ alphaCount++;
+ }
+
+ if( alphaCount == 0 )
+ {
+ if( err && len > 0 )
+ Q_strncpyz( err, "Names must contain letters", len );
return qfalse;
}
for( i = 0; i < level.maxclients; i++ )
{
client = &level.clients[ i ];
- if( client->pers.connected != CON_CONNECTING
- && client->pers.connected != CON_CONNECTED )
- {
+ if( client->pers.connected == CON_DISCONNECTED )
continue;
- }
// can rename ones self to the same name using different colors
if( i == ( ent - g_entities ) )
continue;
- G_SanitiseString( client->pers.netname, testName, sizeof( testName) );
- if( !Q_stricmp( name2, testName ) )
+ G_SanitiseString( client->pers.netname, testName, sizeof( testName ) );
+ if( !strcmp( name2, testName ) )
{
- Q_strncpyz( err, va( "The name '%s^7' is already in use", name ),
- len );
+ if( err && len > 0 )
+ Com_sprintf( err, len, "The name '%s^7' is already in use", name );
return qfalse;
}
}
-
- if( Q_isdigit( name2[ 0 ] ) || name2[ 0 ] == '-' )
- {
- Q_strncpyz( err, "Names cannot begin with a number or with a dash. Please choose another.", len );
- return qfalse;
- }
-
- for( i = 0; name2[ i ] !='\0'; i++)
- {
- if( Q_isalpha( name2[ i ] ) )
- alphaCount++;
- if( name2[ i ] == ' ' )
- {
- if( name2[ i + 1 ] == '-' )
- {
- Q_strncpyz( err, "Names cannot contain a - preceded by a space. Please choose another.", len );
- return qfalse;
- }
- }
- }
-
- if( alphaCount == 0 )
+ for( admin = g_admin_admins; admin; admin = admin->next )
{
- Q_strncpyz( err, va( "The name '%s^7' does not include at least one letter. Please choose another.", name ), len );
- return qfalse;
- }
-
- if( !g_adminNameProtect.string[ 0 ] )
- return qtrue;
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( g_admin_admins[ i ]->level < 1 )
+ if( admin->level < 1 )
continue;
- G_SanitiseString( g_admin_admins[ i ]->name, testName, sizeof( testName) );
- if( !Q_stricmp( name2, testName ) &&
- Q_stricmp( ent->client->pers.guid, g_admin_admins[ i ]->guid ) )
+ G_SanitiseString( admin->name, testName, sizeof( testName ) );
+ if( !strcmp( name2, testName ) && ent->client->pers.admin != admin )
{
- Q_strncpyz( err, va( "The name '%s^7' belongs to an admin. "
- "Please choose another.", name ), len );
+ if( err && len > 0 )
+ Com_sprintf( err, len, "The name '%s^7' belongs to an admin, "
+ "please use another name", name );
return qfalse;
}
}
return qtrue;
}
-static qboolean admin_higher_guid( char *admin_guid, char *victim_guid )
+static qboolean admin_higher_admin( g_admin_admin_t *a, g_admin_admin_t *b )
{
- int i;
- int alevel = 0;
- int alevel2 = 0;
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( admin_guid, g_admin_admins[ i ]->guid ) )
- {
- alevel = g_admin_admins[ i ]->level;
-
- // Novelty Levels should be equivelant to level 1
- if( alevel > 9 )
- alevel = 1;
+ qboolean perm;
- break;
- }
- }
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( victim_guid, g_admin_admins[ i ]->guid ) )
- {
- alevel2 = g_admin_admins[ i ]->level;
+ if( !b )
+ return qtrue;
- // Novelty Levels should be equivelant to level 1
- if( alevel2 > 9 )
- alevel2 = 1;
+ if( admin_permission( b->flags, ADMF_IMMUTABLE, &perm ) )
+ return !perm;
- if( alevel < alevel2 )
- return qfalse;
+ return b->level <= ( a ? a->level : 0 );
+}
- if( strstr( g_admin_admins[ i ]->flags, va( "%s", ADMF_IMMUTABLE ) ) )
- return qfalse;
- }
- }
- return qtrue;
+static qboolean admin_higher_guid( char *admin_guid, char *victim_guid )
+{
+ return admin_higher_admin( G_admin_admin( admin_guid ),
+ G_admin_admin( victim_guid ) );
}
static qboolean admin_higher( gentity_t *admin, gentity_t *victim )
@@ -651,25 +492,15 @@ static qboolean admin_higher( gentity_t *admin, gentity_t *victim )
// console always wins
if( !admin )
return qtrue;
- // just in case
- if( !victim )
- return qtrue;
- return admin_higher_guid( admin->client->pers.guid,
- victim->client->pers.guid );
+ return admin_higher_admin( admin->client->pers.admin,
+ victim->client->pers.admin );
}
static void admin_writeconfig_string( char *s, fileHandle_t f )
{
- char buf[ MAX_STRING_CHARS ];
-
- buf[ 0 ] = '\0';
if( s[ 0 ] )
- {
- //Q_strcat(buf, sizeof(buf), s);
- Q_strncpyz( buf, s, sizeof( buf ) );
- trap_FS_Write( buf, strlen( buf ), f );
- }
+ trap_FS_Write( s, strlen( s ), f );
trap_FS_Write( "\n", 1, f );
}
@@ -677,18 +508,18 @@ static void admin_writeconfig_int( int v, fileHandle_t f )
{
char buf[ 32 ];
- Com_sprintf( buf, sizeof(buf), "%d", v );
- if( buf[ 0 ] )
- trap_FS_Write( buf, strlen( buf ), f );
- trap_FS_Write( "\n", 1, f );
+ Com_sprintf( buf, sizeof( buf ), "%d\n", v );
+ trap_FS_Write( buf, strlen( buf ), f );
}
-void admin_writeconfig( void )
+static void admin_writeconfig( void )
{
fileHandle_t f;
- int len, i;
- int t, expiretime;
- char levels[ MAX_STRING_CHARS ] = {""};
+ int t;
+ g_admin_admin_t *a;
+ g_admin_level_t *l;
+ g_admin_ban_t *b;
+ g_admin_command_t *c;
if( !g_admin.string[ 0 ] )
{
@@ -697,96 +528,75 @@ void admin_writeconfig( void )
return;
}
t = trap_RealTime( NULL );
- len = trap_FS_FOpenFile( g_admin.string, &f, FS_WRITE );
- if( len < 0 )
+ if( trap_FS_FOpenFile( g_admin.string, &f, FS_WRITE ) < 0 )
{
G_Printf( "admin_writeconfig: could not open g_admin file \"%s\"\n",
g_admin.string );
return;
}
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ for( l = g_admin_levels; l; l = l->next )
{
trap_FS_Write( "[level]\n", 8, f );
trap_FS_Write( "level = ", 10, f );
- admin_writeconfig_int( g_admin_levels[ i ]->level, f );
+ admin_writeconfig_int( l->level, f );
trap_FS_Write( "name = ", 10, f );
- admin_writeconfig_string( g_admin_levels[ i ]->name, f );
+ admin_writeconfig_string( l->name, f );
trap_FS_Write( "flags = ", 10, f );
- admin_writeconfig_string( g_admin_levels[ i ]->flags, f );
+ admin_writeconfig_string( l->flags, f );
trap_FS_Write( "\n", 1, f );
}
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ for( a = g_admin_admins; a; a = a->next )
{
// don't write level 0 users
- if( g_admin_admins[ i ]->level < 1 )
+ if( a->level == 0 )
continue;
- //if set dont write admins that havent been seen in a while
- expiretime = G_admin_parse_time( g_adminExpireTime.string );
- if( expiretime > 0 ) {
- //only expire level 1 people
- if( t - expiretime > g_admin_admins[ i ]->seen && g_admin_admins[ i ]->level == 1 ) {
- G_Printf("Admin %s has been expired.\n", g_admin_admins[ i ]->name );
- continue;
- }
- }
-
trap_FS_Write( "[admin]\n", 8, f );
trap_FS_Write( "name = ", 10, f );
- admin_writeconfig_string( g_admin_admins[ i ]->name, f );
+ admin_writeconfig_string( a->name, f );
trap_FS_Write( "guid = ", 10, f );
- admin_writeconfig_string( g_admin_admins[ i ]->guid, f );
+ admin_writeconfig_string( a->guid, f );
trap_FS_Write( "level = ", 10, f );
- admin_writeconfig_int( g_admin_admins[ i ]->level, f );
+ admin_writeconfig_int( a->level, f );
trap_FS_Write( "flags = ", 10, f );
- admin_writeconfig_string( g_admin_admins[ i ]->flags, f );
- trap_FS_Write( "seen = ", 10, f );
- admin_writeconfig_int( g_admin_admins[ i ]->seen, f );
+ admin_writeconfig_string( a->flags, f );
trap_FS_Write( "\n", 1, f );
}
- for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
+ for( b = g_admin_bans; b; b = b->next )
{
// don't write expired bans
// if expires is 0, then it's a perm ban
- if( g_admin_bans[ i ]->expires != 0 &&
- ( g_admin_bans[ i ]->expires - t ) < 1 )
+ if( b->expires != 0 && b->expires <= t )
continue;
trap_FS_Write( "[ban]\n", 6, f );
trap_FS_Write( "name = ", 10, f );
- admin_writeconfig_string( g_admin_bans[ i ]->name, f );
+ admin_writeconfig_string( b->name, f );
trap_FS_Write( "guid = ", 10, f );
- admin_writeconfig_string( g_admin_bans[ i ]->guid, f );
+ admin_writeconfig_string( b->guid, f );
trap_FS_Write( "ip = ", 10, f );
- admin_writeconfig_string( g_admin_bans[ i ]->ip, f );
+ admin_writeconfig_string( b->ip.str, f );
trap_FS_Write( "reason = ", 10, f );
- admin_writeconfig_string( g_admin_bans[ i ]->reason, f );
+ admin_writeconfig_string( b->reason, f );
trap_FS_Write( "made = ", 10, f );
- admin_writeconfig_string( g_admin_bans[ i ]->made, f );
+ admin_writeconfig_string( b->made, f );
trap_FS_Write( "expires = ", 10, f );
- admin_writeconfig_int( g_admin_bans[ i ]->expires, f );
- if( g_admin_bans[ i ]->suspend > t ) {
- trap_FS_Write( "suspend = ", 10, f );
- admin_writeconfig_int( g_admin_bans[ i ]->suspend, f );
- }
+ admin_writeconfig_int( b->expires, f );
trap_FS_Write( "banner = ", 10, f );
- admin_writeconfig_string( g_admin_bans[ i ]->banner, f );
- trap_FS_Write( "blevel = ", 10, f );
- admin_writeconfig_int( g_admin_bans[ i ]->bannerlevel, f );
+ admin_writeconfig_string( b->banner, f );
trap_FS_Write( "\n", 1, f );
}
- for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
+ for( c = g_admin_commands; c; c = c->next )
{
- levels[ 0 ] = '\0';
trap_FS_Write( "[command]\n", 10, f );
trap_FS_Write( "command = ", 10, f );
- admin_writeconfig_string( g_admin_commands[ i ]->command, f );
+ admin_writeconfig_string( c->command, f );
trap_FS_Write( "exec = ", 10, f );
- admin_writeconfig_string( g_admin_commands[ i ]->exec, f );
+ admin_writeconfig_string( c->exec, f );
trap_FS_Write( "desc = ", 10, f );
- admin_writeconfig_string( g_admin_commands[ i ]->desc, f );
+ admin_writeconfig_string( c->desc, f );
trap_FS_Write( "flag = ", 10, f );
- admin_writeconfig_string( g_admin_commands[ i ]->flag, f );
+ admin_writeconfig_string( c->flag, f );
trap_FS_Write( "\n", 1, f );
}
trap_FS_FCloseFile( f );
@@ -794,41 +604,32 @@ void admin_writeconfig( void )
static void admin_readconfig_string( char **cnf, char *s, int size )
{
- char * t;
+ char *t;
//COM_MatchToken(cnf, "=");
+ s[ 0 ] = '\0';
t = COM_ParseExt( cnf, qfalse );
- if( !strcmp( t, "=" ) )
- {
- t = COM_ParseExt( cnf, qfalse );
- }
- else
+ if( strcmp( t, "=" ) )
{
- G_Printf( "readconfig: warning missing = before "
- "\"%s\" on line %d\n",
- t,
- COM_GetCurrentParseLine() );
+ COM_ParseWarning( "expected '=' before \"%s\"", t );
+ Q_strncpyz( s, t, size );
}
- s[ 0 ] = '\0';
- while( t[ 0 ] )
+ while( 1 )
{
- if( ( s[ 0 ] == '\0' && strlen( t ) <= size )
- || ( strlen( t ) + strlen( s ) < size ) )
- {
-
- Q_strcat( s, size, t );
- Q_strcat( s, size, " " );
- }
t = COM_ParseExt( cnf, qfalse );
+ if( !*t )
+ break;
+ if( strlen( t ) + strlen( s ) >= size )
+ break;
+ if( *s )
+ Q_strcat( s, size, " " );
+ Q_strcat( s, size, t );
}
- // trim the trailing space
- if( strlen( s ) > 0 && s[ strlen( s ) - 1 ] == ' ' )
- s[ strlen( s ) - 1 ] = '\0';
}
static void admin_readconfig_int( char **cnf, int *v )
{
- char * t;
+ char *t;
//COM_MatchToken(cnf, "=");
t = COM_ParseExt( cnf, qfalse );
@@ -838,10 +639,7 @@ static void admin_readconfig_int( char **cnf, int *v )
}
else
{
- G_Printf( "readconfig: warning missing = before "
- "\"%s\" on line %d\n",
- t,
- COM_GetCurrentParseLine() );
+ COM_ParseWarning( "expected '=' before \"%s\"", t );
}
*v = atoi( t );
}
@@ -850,413 +648,217 @@ static void admin_readconfig_int( char **cnf, int *v )
// ones to make new installs easier for admins
static void admin_default_levels( void )
{
- g_admin_level_t * l;
- int i;
-
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- G_Free( g_admin_levels[ i ] );
- g_admin_levels[ i ] = NULL;
- }
- for( i = 0; i <= 5; i++ )
- {
- l = G_Alloc( sizeof( g_admin_level_t ) );
- l->level = i;
- *l->name = '\0';
- *l->flags = '\0';
- g_admin_levels[ i ] = l;
- }
+ g_admin_level_t *l;
+ int level = 0;
- Q_strncpyz( g_admin_levels[ 0 ]->name, "^4Unknown Player",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 0 ]->flags,
- "listplayers admintest help specme time",
+ l = g_admin_levels = BG_Alloc( sizeof( g_admin_level_t ) );
+ l->level = level++;
+ Q_strncpyz( l->name, "^4Unknown Player", sizeof( l->name ) );
+ Q_strncpyz( l->flags,
+ "listplayers admintest adminhelp time",
sizeof( l->flags ) );
- Q_strncpyz( g_admin_levels[ 1 ]->name, "^5Server Regular",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 1 ]->flags,
- "listplayers admintest help specme time",
+ l = l->next = BG_Alloc( sizeof( g_admin_level_t ) );
+ l->level = level++;
+ Q_strncpyz( l->name, "^5Server Regular", sizeof( l->name ) );
+ Q_strncpyz( l->flags,
+ "listplayers admintest adminhelp time",
sizeof( l->flags ) );
- Q_strncpyz( g_admin_levels[ 2 ]->name, "^6Team Manager",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 2 ]->flags,
- "listplayers admintest help specme time putteam spec999 warn denybuild",
+ l = l->next = BG_Alloc( sizeof( g_admin_level_t ) );
+ l->level = level++;
+ Q_strncpyz( l->name, "^6Team Manager", sizeof( l->name ) );
+ Q_strncpyz( l->flags,
+ "listplayers admintest adminhelp time putteam spec999",
sizeof( l->flags ) );
- Q_strncpyz( g_admin_levels[ 3 ]->name, "^2Junior Admin",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 3 ]->flags,
- "listplayers admintest help specme time putteam spec999 kick mute warn "
- "denybuild ADMINCHAT SEESFULLLISTPLAYERS",
+ l = l->next = BG_Alloc( sizeof( g_admin_level_t ) );
+ l->level = level++;
+ Q_strncpyz( l->name, "^2Junior Admin", sizeof( l->name ) );
+ Q_strncpyz( l->flags,
+ "listplayers admintest adminhelp time putteam spec999 kick mute ADMINCHAT",
sizeof( l->flags ) );
- Q_strncpyz( g_admin_levels[ 4 ]->name, "^3Senior Admin",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 4 ]->flags,
- "listplayers admintest help specme time putteam spec999 kick mute showbans "
- "ban namelog warn denybuild decon ADMINCHAT SEESFULLLISTPLAYERS",
+ l = l->next = BG_Alloc( sizeof( g_admin_level_t ) );
+ l->level = level++;
+ Q_strncpyz( l->name, "^3Senior Admin", sizeof( l->name ) );
+ Q_strncpyz( l->flags,
+ "listplayers admintest adminhelp time putteam spec999 kick mute showbans ban "
+ "namelog ADMINCHAT",
sizeof( l->flags ) );
- Q_strncpyz( g_admin_levels[ 5 ]->name, "^1Server Operator",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 5 ]->flags,
- "ALLFLAGS -INCOGNITO -IMMUTABLE -DBUILDER -BANIMMUNITY",
+ l = l->next = BG_Alloc( sizeof( g_admin_level_t ) );
+ l->level = level++;
+ Q_strncpyz( l->name, "^1Server Operator", sizeof( l->name ) );
+ Q_strncpyz( l->flags,
+ "ALLFLAGS -IMMUTABLE -INCOGNITO",
sizeof( l->flags ) );
+ admin_level_maxname = 15;
}
-// return a level for a player entity.
-int G_admin_level( gentity_t *ent )
+void G_admin_authlog( gentity_t *ent )
{
- int i;
- qboolean found = qfalse;
+ char aflags[ MAX_ADMIN_FLAGS * 2 ];
+ g_admin_level_t *level;
+ int levelNum = 0;
if( !ent )
- {
- return MAX_ADMIN_LEVELS;
- }
+ return;
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( g_admin_admins[ i ]->guid, ent->client->pers.guid ) )
- {
+ if( ent->client->pers.admin )
+ levelNum = ent->client->pers.admin->level;
- found = qtrue;
- break;
- }
- }
+ level = G_admin_level( levelNum );
- if( found )
- {
- return g_admin_admins[ i ]->level;
- }
+ Com_sprintf( aflags, sizeof( aflags ), "%s %s",
+ ent->client->pers.admin->flags,
+ ( level ) ? level->flags : "" );
- return 0;
+ G_LogPrintf( "AdminAuth: %i \"%s" S_COLOR_WHITE "\" \"%s" S_COLOR_WHITE
+ "\" [%d] (%s): %s\n",
+ (int)( ent - g_entities ), ent->client->pers.netname,
+ ent->client->pers.admin->name, ent->client->pers.admin->level,
+ ent->client->pers.guid, aflags );
}
-// set a player's adminname
-void G_admin_set_adminname( gentity_t *ent )
+static char adminLog[ MAX_STRING_CHARS ];
+static int adminLogLen;
+static void admin_log_start( gentity_t *admin, const char *cmd )
{
- int i;
- qboolean found = qfalse;
+ const char *name = admin ? admin->client->pers.netname : "console";
- if( !ent )
- {
- return;
- }
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( g_admin_admins[ i ]->guid, ent->client->pers.guid ) )
- {
- found = qtrue;
- break;
- }
- }
-
- if( found )
- {
- Q_strncpyz( ent->client->pers.adminName, g_admin_admins[ i ]->name, sizeof( ent->client->pers.adminName ) );
- }
- else
- {
- Q_strncpyz( ent->client->pers.adminName, "", sizeof( ent->client->pers.adminName ) );
- }
+ adminLogLen = Q_snprintf( adminLog, sizeof( adminLog ),
+ "%d \"%s" S_COLOR_WHITE "\" \"%s" S_COLOR_WHITE "\" [%d] (%s): %s",
+ admin ? admin->s.clientNum : -1,
+ name,
+ admin && admin->client->pers.admin ? admin->client->pers.admin->name : name,
+ admin && admin->client->pers.admin ? admin->client->pers.admin->level : 0,
+ admin ? admin->client->pers.guid : "",
+ cmd );
}
-// Get an admin's registered name
-const char *G_admin_get_adminname( gentity_t *ent )
+static void admin_log( const char *str )
{
- int i;
-
- if( !ent )
- return "console";
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( g_admin_admins[ i ]->guid, ent->client->pers.guid ) )
- return g_admin_admins[ i ]->name;
- }
-
- return ent->client->pers.netname;
+ if( adminLog[ 0 ] )
+ adminLogLen += Q_snprintf( adminLog + adminLogLen,
+ sizeof( adminLog ) - adminLogLen, ": %s", str );
}
-// Get an admin's name to print as the user of various commands,
-// obeying admin stealth settings when necessary
-char* G_admin_adminPrintName( gentity_t *ent )
+static void admin_log_abort( void )
{
- char *out;
-
- if( !ent->client->pers.adminLevel )
- {
- out = "";
- return out;
- }
-
- if( G_admin_permission( ent, ADMF_ADMINSTEALTH ) )
- {
- out = ent->client->pers.adminName;
- }
- else
- {
- out = ent->client->pers.netname;
- }
-
-
- return out;
+ adminLog[ 0 ] = '\0';
+ adminLogLen = 0;
}
-static void admin_log( gentity_t *admin, char *cmd, int skiparg )
+static void admin_log_end( const qboolean ok )
{
- fileHandle_t f;
- int len, i, j;
- char string[ MAX_STRING_CHARS ], decoloured[ MAX_STRING_CHARS ];
- int min, tens, sec;
- g_admin_admin_t *a;
- g_admin_level_t *l;
- char flags[ MAX_ADMIN_FLAGS * 2 ];
- gentity_t *victim = NULL;
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ];
-
- if( !g_adminLog.string[ 0 ] )
- return ;
-
-
- len = trap_FS_FOpenFile( g_adminLog.string, &f, FS_APPEND );
- if( len < 0 )
- {
- G_Printf( "admin_log: error could not open %s\n", g_adminLog.string );
- return ;
- }
+ if( adminLog[ 0 ] )
+ G_LogPrintf( "AdminExec: %s: %s\n", ok ? "ok" : "fail", adminLog );
+ admin_log_abort( );
+}
- sec = (level.time - level.startTime) / 1000;
- min = sec / 60;
- sec -= min * 60;
- tens = sec / 10;
- sec -= tens * 10;
+struct llist
+{
+ struct llist *next;
+};
+static int admin_search( gentity_t *ent,
+ const char *cmd,
+ const char *noun,
+ qboolean ( *match )( void *, const void * ),
+ void ( *out )( void *, char * ),
+ const void *list,
+ const void *arg, /* this will be used as char* later */
+ int start,
+ const int offset,
+ const int limit )
+{
+ int i;
+ int count = 0;
+ int found = 0;
+ int total;
+ int next = 0, end = 0;
+ char str[ MAX_STRING_CHARS ];
+ struct llist *l = (struct llist *)list;
+
+ for( total = 0; l; total++, l = l->next ) ;
+ if( start < 0 )
+ start += total;
+ else
+ start -= offset;
+ if( start < 0 || start > total )
+ start = 0;
- *flags = '\0';
- if( admin )
+ ADMBP_begin();
+ for( i = 0, l = (struct llist *)list; l; i++, l = l->next )
{
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ if( match( l, arg ) )
{
- if( !Q_stricmp( g_admin_admins[ i ]->guid , admin->client->pers.guid ) )
+ if( i >= start && ( limit < 1 || count < limit ) )
{
-
- a = g_admin_admins[ i ];
- Q_strncpyz( flags, a->flags, sizeof( flags ) );
- for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
- {
- if( g_admin_levels[ j ]->level == a->level )
- {
- l = g_admin_levels[ j ];
- Q_strcat( flags, sizeof( flags ), l->flags );
- break;
- }
- }
- break;
+ out( l, str );
+ ADMBP( va( "%-3d %s\n", i + offset, str ) );
+ count++;
+ end = i;
+ }
+ else if( count == limit )
+ {
+ if( next == 0 )
+ next = i;
}
- }
- }
- if( G_SayArgc() > 1 + skiparg )
- {
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( G_ClientNumbersFromString( name, pids ) == 1 )
- {
- victim = &g_entities[ pids[ 0 ] ];
+ found++;
}
}
- if( victim && Q_stricmp( cmd, "attempted" ) )
- {
- Com_sprintf( string, sizeof( string ),
- "%3i:%i%i: %i: %s: %s (%s): %s: %s: %s: %s: \"%s\"\n",
- min,
- tens,
- sec,
- ( admin ) ? admin->s.clientNum : -1,
- ( admin ) ? admin->client->pers.guid
- : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
- ( admin ) ? admin->client->pers.netname : "console",
- ( admin ) ? admin->client->pers.adminName : "console",
- flags,
- cmd,
- victim->client->pers.guid,
- victim->client->pers.netname,
- G_SayConcatArgs( 2 + skiparg ) );
- }
- else
+ if( limit > 0 )
{
- Com_sprintf( string, sizeof( string ),
- "%3i:%i%i: %i: %s: %s (%s): %s: %s: \"%s\"\n",
- min,
- tens,
- sec,
- ( admin ) ? admin->s.clientNum : -1,
- ( admin ) ? admin->client->pers.guid
- : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
- ( admin ) ? admin->client->pers.netname : "console",
- ( admin ) ? admin->client->pers.adminName : "console",
- flags,
- cmd,
- G_SayConcatArgs( 1 + skiparg ) );
+ ADMBP( va( "^3%s: ^7showing %d of %d %s %d-%d%s%s.",
+ cmd, count, found, noun, start + offset, end + offset,
+ *(char *)arg ? " matching " : "", (char *)arg ) );
+ if( next )
+ ADMBP( va( " use '%s%s%s %d' to see more", cmd,
+ *(char *)arg ? " " : "",
+ (char *)arg,
+ next + offset ) );
}
+ ADMBP( "\n" );
+ ADMBP_end();
+ return next + offset;
+}
- if( g_decolourLogfiles.integer )
- {
- G_DecolorString( string, decoloured );
- trap_FS_Write( decoloured, strlen( decoloured ), f );
- }
- else
+static qboolean admin_match( void *admin, const void *match )
+{
+ char n1[ MAX_NAME_LENGTH ], n2[ MAX_NAME_LENGTH ];
+ G_SanitiseString( (char *)match, n2, sizeof( n2 ) );
+ if( !n2[ 0 ] )
+ return qtrue;
+ G_SanitiseString( ( (g_admin_admin_t *)admin )->name, n1, sizeof( n1 ) );
+ return strstr( n1, n2 ) ? qtrue : qfalse;
+}
+static void admin_out( void *admin, char *str )
+{
+ g_admin_admin_t *a = (g_admin_admin_t *)admin;
+ g_admin_level_t *l = G_admin_level( a->level );
+ int lncol = 0, i;
+ for( i = 0; l && l->name[ i ]; i++ )
{
- trap_FS_Write( string, strlen( string ), f );
+ if( Q_IsColorString( l->name + i ) )
+ lncol += 2;
}
- trap_FS_FCloseFile( f );
-
- if ( !Q_stricmp( cmd, "attempted" ) )
- {
- Com_sprintf( string, sizeof( string ),
- "%s^7 (%i) %s: %s",
- ( admin ) ? admin->client->pers.netname : "console",
- ( admin ) ? admin->s.clientNum : -1,
- cmd,
- G_SayConcatArgs( 1 + skiparg ) );
- G_AdminsPrintf("%s\n",string);
- }
-
- G_LogPrintf("Admin Command: %s^7 (%s): %s %s\n",( admin ) ? admin->client->pers.netname : "console", ( admin ) ? admin->client->pers.adminName : "console", cmd, G_SayConcatArgs( 1 + skiparg ));
+ Com_sprintf( str, MAX_STRING_CHARS, "%-6d %*s^7 %s",
+ a->level, admin_level_maxname + lncol - 1, l ? l->name : "(null)",
+ a->name );
}
-
-static int admin_listadmins( gentity_t *ent, int start, char *search, int minlevel )
+static int admin_listadmins( gentity_t *ent, int start, char *search )
{
- int drawn = 0;
- char guid_stub[9];
- char name[ MAX_NAME_LENGTH ] = {""};
- char name2[ MAX_NAME_LENGTH ] = {""};
- char lname[ MAX_NAME_LENGTH ] = {""};
- char lname_fmt[ 5 ];
- int i,j;
- gentity_t *vic;
- int l = 0;
- qboolean dup = qfalse;
-
- ADMBP_begin();
-
- // print out all connected players regardless of level if name searching
- for( i = 0; i < level.maxclients && search[ 0 ]; i++ )
- {
- vic = &g_entities[ i ];
-
- if( vic->client && vic->client->pers.connected != CON_CONNECTED )
- continue;
-
- l = vic->client->pers.adminLevel;
-
- G_SanitiseString( vic->client->pers.netname, name, sizeof( name ) );
- if( !strstr( name, search ) )
- continue;
-
- for( j = 0; j < 8; j++ )
- guid_stub[ j ] = vic->client->pers.guid[ j + 24 ];
- guid_stub[ j ] = '\0';
-
- lname[ 0 ] = '\0';
- Q_strncpyz( lname_fmt, "%s", sizeof( lname_fmt ) );
- for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
- {
- if( g_admin_levels[ j ]->level == l )
- {
- G_DecolorString( g_admin_levels[ j ]->name, lname );
- Com_sprintf( lname_fmt, sizeof( lname_fmt ), "%%%is",
- ( admin_level_maxname + strlen( g_admin_levels[ j ]->name )
- - strlen( lname ) ) );
- Com_sprintf( lname, sizeof( lname ), lname_fmt,
- g_admin_levels[ j ]->name );
- break;
- }
- }
- ADMBP( va( "%4i %4i %s^7 (*%s) %s^7\n",
- i,
- l,
- lname,
- guid_stub,
- vic->client->pers.netname ) );
- drawn++;
- }
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]
- && drawn < MAX_ADMIN_LISTITEMS; i++ )
- if( g_admin_admins[ i ]->level >= minlevel )
- {
-
- if( start )
- {
- start--;
- continue;
- }
-
- if( search[ 0 ] )
- {
- G_SanitiseString( g_admin_admins[ i ]->name, name, sizeof( name ) );
- if( !strstr( name, search ) )
- continue;
-
- // verify we don't have the same guid/name pair in connected players
- // since we don't want to draw the same player twice
- dup = qfalse;
- for( j = 0; j < level.maxclients; j++ )
- {
- vic = &g_entities[ j ];
- if( !vic->client || vic->client->pers.connected != CON_CONNECTED )
- continue;
- G_SanitiseString( vic->client->pers.netname, name2, sizeof( name2) );
- if( !Q_stricmp( vic->client->pers.guid, g_admin_admins[ i ]->guid )
- && strstr( name2, search ) )
- {
- dup = qtrue;
- break;
- }
- }
- if( dup )
- continue;
- }
- for( j = 0; j < 8; j++ )
- guid_stub[ j ] = g_admin_admins[ i ]->guid[ j + 24 ];
- guid_stub[ j ] = '\0';
-
- lname[ 0 ] = '\0';
- Q_strncpyz( lname_fmt, "%s", sizeof( lname_fmt ) );
- for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
- {
- if( g_admin_levels[ j ]->level == g_admin_admins[ i ]->level )
- {
- G_DecolorString( g_admin_levels[ j ]->name, lname );
- Com_sprintf( lname_fmt, sizeof( lname_fmt ), "%%%is",
- ( admin_level_maxname + strlen( g_admin_levels[ j ]->name )
- - strlen( lname ) ) );
- Com_sprintf( lname, sizeof( lname ), lname_fmt,
- g_admin_levels[ j ]->name );
- break;
- }
- }
- ADMBP( va( "%4i %4i %s^7 (*%s) %s^7\n",
- ( i + MAX_CLIENTS ),
- g_admin_admins[ i ]->level,
- lname,
- guid_stub,
- g_admin_admins[ i ]->name ) );
- drawn++;
- }
- ADMBP_end();
- return drawn;
+ return admin_search( ent, "listadmins", "admins", admin_match, admin_out,
+ g_admin_admins, search, start, MAX_CLIENTS, MAX_ADMIN_LISTITEMS );
}
+#define MAX_DURATION_LENGTH 13
void G_admin_duration( int secs, char *duration, int dursize )
{
-
+ // sizeof("12.5 minutes") == 13
if( secs > ( 60 * 60 * 24 * 365 * 50 ) || secs < 0 )
Q_strncpyz( duration, "PERMANENT", dursize );
else if( secs >= ( 60 * 60 * 24 * 365 ) )
@@ -1278,440 +880,200 @@ void G_admin_duration( int secs, char *duration, int dursize )
Com_sprintf( duration, dursize, "%i seconds", secs );
}
-qboolean G_admin_ban_check( char *userinfo, char *reason, int rlen )
+static void G_admin_ban_message(
+ gentity_t *ent,
+ g_admin_ban_t *ban,
+ char *creason,
+ int clen,
+ char *areason,
+ int alen )
+{
+ if( creason )
+ {
+ char duration[ MAX_DURATION_LENGTH ];
+ G_admin_duration( ban->expires - trap_RealTime( NULL ), duration,
+ sizeof( duration ) );
+ // part of this might get cut off on the connect screen
+ Com_sprintf( creason, clen,
+ "You have been banned by %s" S_COLOR_WHITE " duration: %s"
+ " reason: %s",
+ ban->banner,
+ duration,
+ ban->reason );
+ }
+
+ if( areason && ent )
+ {
+ // we just want the ban number
+ int n = 1;
+ g_admin_ban_t *b = g_admin_bans;
+ for( ; b && b != ban; b = b->next, n++ )
+ ;
+ Com_sprintf( areason, alen,
+ S_COLOR_YELLOW "Banned player %s" S_COLOR_YELLOW
+ " tried to connect from %s (ban #%d)",
+ ent->client->pers.netname[ 0 ] ? ent->client->pers.netname : ban->name,
+ ent->client->pers.ip.str,
+ n );
+ }
+}
+
+static qboolean G_admin_ban_matches( g_admin_ban_t *ban, gentity_t *ent )
+{
+ return !Q_stricmp( ban->guid, ent->client->pers.guid ) ||
+ ( !G_admin_permission( ent, ADMF_IMMUNITY ) &&
+ G_AddressCompare( &ban->ip, &ent->client->pers.ip ) );
+}
+
+static g_admin_ban_t *G_admin_match_ban( gentity_t *ent )
{
- static char lastConnectIP[ 16 ] = {""};
- static int lastConnectTime = 0;
- char guid[ 33 ];
- char ip[ 16 ];
- char *value;
- int i;
- unsigned int userIP = 0, intIP = 0, tempIP;
- int IP[5], k, mask, ipscanfcount;
int t;
- char notice[51];
- qboolean ignoreIP = qfalse;
-
- trap_Cvar_VariableStringBuffer( "g_banNotice", notice, sizeof( notice ) );
-
- *reason = '\0';
-
- if( !*userinfo )
- return qfalse;
-
- value = Info_ValueForKey( userinfo, "ip" );
- Q_strncpyz( ip, value, sizeof( ip ) );
- // strip port
- value = strchr( ip, ':' );
- if ( value )
- *value = '\0';
-
- if( !*ip )
- return qfalse;
-
- value = Info_ValueForKey( userinfo, "cl_guid" );
- Q_strncpyz( guid, value, sizeof( guid ) );
-
+ g_admin_ban_t *ban;
+
t = trap_RealTime( NULL );
- memset( IP, 0, sizeof( IP ));
- sscanf(ip, "%i.%i.%i.%i", &IP[4], &IP[3], &IP[2], &IP[1]);
- for(k = 4; k >= 1; k--)
- {
- if(!IP[k]) continue;
- userIP |= IP[k] << 8*(k-1);
- }
- ignoreIP = G_admin_permission_guid( guid , ADMF_BAN_IMMUNITY );
- for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
+ if( ent->client->pers.localClient )
+ return NULL;
+
+ for( ban = g_admin_bans; ban; ban = ban->next )
{
// 0 is for perm ban
- if( g_admin_bans[ i ]->expires != 0 &&
- ( g_admin_bans[ i ]->expires - t ) < 1 )
- continue;
- //if suspend time is over continue
- if( g_admin_bans[ i ]->suspend >= t )
+ if( ban->expires != 0 && ban->expires <= t )
continue;
- if( !ignoreIP )
- {
- tempIP = userIP;
- intIP = 0;
- mask = -1;
-
- memset( IP, 0, sizeof( IP ));
- ipscanfcount = sscanf(g_admin_bans[ i ]->ip, "%d.%d.%d.%d/%d", &IP[4], &IP[3], &IP[2], &IP[1], &IP[0]);
-
- if( ipscanfcount == 4 )
- mask = -1;
- else if( ipscanfcount == 5 )
- mask = IP[0];
- else if( ipscanfcount > 0 && ipscanfcount < 4 )
- mask = 8 * ipscanfcount;
- else
- continue;
+ if( G_admin_ban_matches( ban, ent ) )
+ return ban;
+ }
- for(k = 4; k >= 1; k--)
- {
- if(!IP[k]) continue;
- intIP |= IP[k] << 8*(k-1);
- }
+ return NULL;
+}
- if(mask > 0 && mask <= 32)
- {
- tempIP &= ~((1 << (32-mask)) - 1);
- intIP &= ~((1 << (32-mask)) - 1);
- }
+qboolean G_admin_ban_check( gentity_t *ent, char *reason, int rlen )
+{
+ g_admin_ban_t *ban;
+ char warningMessage[ MAX_STRING_CHARS ];
- if( intIP == tempIP || mask == 0 )
- {
- char duration[ 32 ];
- G_admin_duration( ( g_admin_bans[ i ]->expires - t ),
- duration, sizeof( duration ) );
-
- // flood protected
- if( t - lastConnectTime >= 300 ||
- Q_stricmp( lastConnectIP, ip ) )
- {
- lastConnectTime = t;
- Q_strncpyz( lastConnectIP, ip, sizeof( lastConnectIP ) );
-
- G_WarningsPrintf(
- "ban",
- "Banned player %s^7 (%s^7) tried to connect (ban #%i on %s by %s^7 expires %s reason: %s^7 )\n",
- Info_ValueForKey( userinfo, "name" ),
- g_admin_bans[ i ]->name,
- i+1,
- ip,
- g_admin_bans[ i ]->banner,
- duration,
- g_admin_bans[ i ]->reason );
- }
-
- Com_sprintf(
- reason,
- rlen,
- "You have been banned by %s^7 reason: %s^7 expires: %s %s",
- g_admin_bans[ i ]->banner,
- g_admin_bans[ i ]->reason,
- duration,
- notice
- );
- G_LogPrintf("Banned player tried to connect from IP %s\n", ip);
- return qtrue;
- }
- }
- if( *guid && !Q_stricmp( g_admin_bans[ i ]->guid, guid ) )
- {
- char duration[ 32 ];
- G_admin_duration( ( g_admin_bans[ i ]->expires - t ),
- duration, sizeof( duration ) );
- Com_sprintf(
- reason,
- rlen,
- "You have been banned by %s^7 reason: %s^7 expires: %s",
- g_admin_bans[ i ]->banner,
- g_admin_bans[ i ]->reason,
- duration
- );
- G_Printf("Banned player tried to connect with GUID %s\n", guid);
- return qtrue;
- }
- }
- if ( *guid )
+ if( ent->client->pers.localClient )
+ return qfalse;
+
+ if( ( ban = G_admin_match_ban( ent ) ) )
{
- int count = 0;
- qboolean valid = qtrue;
+ G_admin_ban_message( ent, ban, reason, rlen,
+ warningMessage, sizeof( warningMessage ) );
- while( guid[ count ] != '\0' && valid )
- {
- if( (guid[ count ] < '0' || guid[ count ] > '9') &&
- (guid[ count ] < 'A' || guid[ count ] > 'F') )
- {
- valid = qfalse;
- }
- count++;
- }
- if( !valid || count != 32 )
- {
- Com_sprintf( reason, rlen, "Invalid client data" );
- G_Printf("Player with invalid GUID [%s] connect from IP %s\n", guid, ip);
- return qtrue;
- }
+ // don't spam admins
+ if( ban->warnCount++ < 5 )
+ G_AdminMessage( NULL, warningMessage );
+ // and don't fill the console
+ else if( ban->warnCount < 10 )
+ trap_Print( va( "%s%s\n", warningMessage,
+ ban->warnCount + 1 == 10 ?
+ S_COLOR_WHITE " - future messages for this ban will be suppressed" :
+ "" ) );
+ return qtrue;
}
+
return qfalse;
}
-qboolean G_admin_cmd_check( gentity_t *ent, qboolean say )
+qboolean G_admin_cmd_check( gentity_t *ent )
{
- int i;
char command[ MAX_ADMIN_CMD_LEN ];
- char *cmd;
- int skip = 0;
+ g_admin_cmd_t *admincmd;
+ g_admin_command_t *c;
+ qboolean success;
command[ 0 ] = '\0';
- G_SayArgv( 0, command, sizeof( command ) );
- if( !Q_stricmp( command, "say" ) ||
- ( G_admin_permission( ent, ADMF_TEAMCHAT_CMD ) &&
- ( !Q_stricmp( command, "say_team" ) ) ) )
- {
- skip = 1;
- G_SayArgv( 1, command, sizeof( command ) );
- }
+ trap_Argv( 0, command, sizeof( command ) );
if( !command[ 0 ] )
return qfalse;
- if( command[ 0 ] == '!' )
- {
- cmd = &command[ 1 ];
- }
- else
- {
- return qfalse;
- }
-
- // Flood limit. If they're talking too fast, determine that and return.
- if( g_floodMinTime.integer )
- if ( G_Flood_Limited( ent ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Your chat is flood-limited; wait before chatting again\n\"" );
- return qtrue;
- }
+ Q_strlwr( command );
+ admin_log_start( ent, command );
- if( G_admin_is_restricted( ent, qtrue ) )
- return qtrue;
-
- for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
+ if( ( c = G_admin_command( command ) ) )
{
- if( Q_stricmp( cmd, g_admin_commands[ i ]->command ) )
- continue;
-
- if( G_admin_permission( ent, g_admin_commands[ i ]->flag ) )
+ admin_log( ConcatArgsPrintable( 1 ) );
+ if( ( success = G_admin_permission( ent, c->flag ) ) )
{
- trap_SendConsoleCommand( EXEC_APPEND, g_admin_commands[ i ]->exec );
- admin_log( ent, cmd, skip );
- G_admin_adminlog_log( ent, cmd, NULL, skip, qtrue );
+ if( G_FloodLimited( ent ) )
+ return qtrue;
+ trap_SendConsoleCommand( EXEC_APPEND, c->exec );
}
else
{
- ADMP( va( "^3!%s: ^7permission denied\n", g_admin_commands[ i ]->command ) );
- admin_log( ent, "attempted", skip - 1 );
- G_admin_adminlog_log( ent, cmd, NULL, skip, qfalse );
+ ADMP( va( "^3%s: ^7permission denied\n", c->command ) );
}
+ admin_log_end( success );
return qtrue;
}
- for( i = 0; i < adminNumCmds; i++ )
+ if( ( admincmd = G_admin_cmd( command ) ) )
{
- if( Q_stricmp( cmd, g_admin_cmds[ i ].keyword ) )
- continue;
-
- if( G_admin_permission( ent, g_admin_cmds[ i ].flag ) )
+ if( ( success = G_admin_permission( ent, admincmd->flag ) ) )
{
- g_admin_cmds[ i ].handler( ent, skip );
- admin_log( ent, cmd, skip );
- G_admin_adminlog_log( ent, cmd, NULL, skip, qtrue );
+ if( G_FloodLimited( ent ) )
+ return qtrue;
+ if( admincmd->silent )
+ admin_log_abort( );
+ if( !( success = admincmd->handler( ent ) ) )
+ admin_log( ConcatArgsPrintable( 1 ) );
}
else
{
- ADMP( va( "^3!%s: ^7permission denied\n", g_admin_cmds[ i ].keyword ) );
- admin_log( ent, "attempted", skip - 1 );
- G_admin_adminlog_log( ent, cmd, NULL, skip, qfalse );
+ ADMP( va( "^3%s: ^7permission denied\n", admincmd->keyword ) );
+ admin_log( ConcatArgsPrintable( 1 ) );
}
+ admin_log_end( success );
return qtrue;
}
return qfalse;
}
-void G_admin_namelog_cleanup( )
+static void llsort( struct llist **head, int compar( const void *, const void * ) )
{
- int i;
+ struct llist *a, *b, *t, *l;
+ int i, c = 1, ns, as, bs;
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- {
- if( g_admin_namelog[ i ]->smj.comment )
- G_Free( g_admin_namelog[ i ]->smj.comment );
- G_Free( g_admin_namelog[ i ] );
- g_admin_namelog[ i ] = NULL;
- }
-}
-
-static void dispatchSchachtmeisterIPAQuery( const char *ipa )
-{
- trap_SendConsoleCommand( EXEC_APPEND, va( "smq ipa \"%s\"\n", ipa ) );
-}
-
-static void schachtmeisterProcess( g_admin_namelog_t *namelog )
-{
- schachtmeisterJudgement_t *j = &namelog->smj;
-
- if( !j->ratingTime || level.time - j->ratingTime >= 600000 )
- {
- if( j->queryTime )
- return;
-
- j->queryTime = level.time;
- goto dispatch;
- }
-
- if( !j->queryTime || level.time - j->queryTime >= 60000 )
- return;
-
- if( j->dispatchTime && level.time - j->dispatchTime < 5000 )
+ if( !*head )
return;
- dispatch:
- j->dispatchTime = level.time;
- dispatchSchachtmeisterIPAQuery( namelog->ip );
-}
-
-void G_admin_schachtmeisterFrame( void )
-{
- int i;
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- schachtmeisterProcess( g_admin_namelog[ i ] );
-}
-
-void G_admin_namelog_update( gclient_t *client, qboolean disconnect )
-{
- int i, j;
- g_admin_namelog_t *namelog;
- char n1[ MAX_NAME_LENGTH ];
- char n2[ MAX_NAME_LENGTH ];
- int clientNum = ( client - level.clients );
-
- if ( client->sess.invisible == qfalse )
- {
- G_admin_seen_update( client->pers.guid );
- }
-
- G_SanitiseString( client->pers.netname, n1, sizeof( n1 ) );
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
+ do
{
- if( disconnect && g_admin_namelog[ i ]->slot != clientNum )
- continue;
-
- if( !disconnect && !( g_admin_namelog[ i ]->slot == clientNum ||
- g_admin_namelog[ i ]->slot == -1 ) )
+ a = *head, l = *head = NULL;
+ for( ns = 0; a; ns++, a = b )
{
- continue;
- }
-
- if( !Q_stricmp( client->pers.ip, g_admin_namelog[ i ]->ip )
- && !Q_stricmp( client->pers.guid, g_admin_namelog[ i ]->guid ) )
- {
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES
- && g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
+ b = a;
+ for( i = as = 0; i < c; i++ )
{
- G_SanitiseString( g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
- if( !Q_stricmp( n1, n2 ) )
+ as++;
+ if( !( b = b->next ) )
break;
}
- if( j == MAX_ADMIN_NAMELOG_NAMES )
- j = MAX_ADMIN_NAMELOG_NAMES - 1;
- Q_strncpyz( g_admin_namelog[ i ]->name[ j ], client->pers.netname,
- sizeof( g_admin_namelog[ i ]->name[ j ] ) );
- g_admin_namelog[ i ]->slot = ( disconnect ) ? -1 : clientNum;
-
- // if this player is connecting, they are no longer banned
- if( !disconnect )
- g_admin_namelog[ i ]->banned = qfalse;
-
- //check other things like if user was denybuild or muted or denyweapon and restore them
- if( !disconnect )
- {
- if( g_admin_namelog[ i ]->muted )
- {
- client->pers.muted = qtrue;
- client->pers.muteExpires = g_admin_namelog[ i ]->muteExpires;
- G_AdminsPrintf( "^7%s^7's mute has been restored\n", client->pers.netname );
- g_admin_namelog[ i ]->muted = qfalse;
- }
- if( g_admin_namelog[ i ]->denyBuild )
- {
- client->pers.denyBuild = qtrue;
- G_AdminsPrintf( "^7%s^7's Denybuild has been restored\n", client->pers.netname );
- g_admin_namelog[ i ]->denyBuild = qfalse;
- }
- if( g_admin_namelog[ i ]->denyHumanWeapons > 0 || g_admin_namelog[ i ]->denyAlienClasses > 0 )
- {
- if( g_admin_namelog[ i ]->denyHumanWeapons > 0 )
- client->pers.denyHumanWeapons = g_admin_namelog[ i ]->denyHumanWeapons;
- if( g_admin_namelog[ i ]->denyAlienClasses > 0 )
- client->pers.denyAlienClasses = g_admin_namelog[ i ]->denyAlienClasses;
-
- G_AdminsPrintf( "^7%s^7's Denyweapon has been restored\n", client->pers.netname );
- g_admin_namelog[ i ]->denyHumanWeapons = 0;
- g_admin_namelog[ i ]->denyAlienClasses = 0;
- }
- if( g_admin_namelog[ i ]->specExpires > 0 )
- {
- client->pers.specExpires = g_admin_namelog[ i ]->specExpires;
- G_AdminsPrintf( "^7%s^7's Putteam spectator has been restored\n", client->pers.netname );
- g_admin_namelog[ i ]->specExpires = 0;
- }
- if( g_admin_namelog[ i ]->voteCount > 0 )
- {
- client->pers.voteCount = g_admin_namelog[ i ]->voteCount;
- g_admin_namelog[ i ]->voteCount = 0;
- }
- }
- else
+ for( bs = c; ( b && bs ) || as; l = t )
{
- //for mute
- if( G_IsMuted( client ) )
- {
- g_admin_namelog[ i ]->muted = qtrue;
- g_admin_namelog[ i ]->muteExpires = client->pers.muteExpires;
- }
- //denybuild
- if( client->pers.denyBuild )
- {
- g_admin_namelog[ i ]->denyBuild = qtrue;
- }
- //denyweapon humans
- if( client->pers.denyHumanWeapons > 0 )
- {
- g_admin_namelog[ i ]->denyHumanWeapons = client->pers.denyHumanWeapons;
- }
- //denyweapon aliens
- if( client->pers.denyAlienClasses > 0 )
- {
- g_admin_namelog[ i ]->denyAlienClasses = client->pers.denyAlienClasses;
- }
- //putteam spec
- if( client->pers.specExpires > 0 )
- {
- g_admin_namelog[ i ]->specExpires = client->pers.specExpires;
- }
- if( client->pers.voteCount > 0 )
- {
- g_admin_namelog[ i ]->voteCount = client->pers.voteCount;
- }
+ if( as && ( !bs || !b || compar( a, b ) <= 0 ) )
+ t = a, a = a->next, as--;
+ else
+ t = b, b = b->next, bs--;
+ if( l )
+ l->next = t;
+ else
+ *head = t;
}
-
- return;
}
- }
- if( i >= MAX_ADMIN_NAMELOGS )
- {
- G_Printf( "G_admin_namelog_update: warning, g_admin_namelogs overflow\n" );
- return;
- }
- namelog = G_Alloc( sizeof( g_admin_namelog_t ) );
- memset( namelog, 0, sizeof( *namelog ) );
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES ; j++ )
- namelog->name[ j ][ 0 ] = '\0';
- Q_strncpyz( namelog->ip, client->pers.ip, sizeof( namelog->ip ) );
- Q_strncpyz( namelog->guid, client->pers.guid, sizeof( namelog->guid ) );
- Q_strncpyz( namelog->name[ 0 ], client->pers.netname,
- sizeof( namelog->name[ 0 ] ) );
- namelog->slot = ( disconnect ) ? -1 : clientNum;
- schachtmeisterProcess( namelog );
- g_admin_namelog[ i ] = namelog;
+ l->next = NULL;
+ c *= 2;
+ } while( ns > 1 );
+}
+
+static int cmplevel( const void *a, const void *b )
+{
+ return ((g_admin_level_t *)b)->level - ((g_admin_level_t *)a)->level;
}
-qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
+qboolean G_admin_readconfig( gentity_t *ent )
{
- g_admin_level_t * l = NULL;
+ g_admin_level_t *l = NULL;
g_admin_admin_t *a = NULL;
g_admin_ban_t *b = NULL;
g_admin_command_t *c = NULL;
@@ -1722,54 +1084,82 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
char *t;
qboolean level_open, admin_open, ban_open, command_open;
int i;
+ char ip[ 44 ];
G_admin_cleanup();
if( !g_admin.string[ 0 ] )
{
- ADMP( "^3!readconfig: g_admin is not set, not loading configuration "
+ ADMP( "^3readconfig: g_admin is not set, not loading configuration "
"from a file\n" );
- admin_default_levels();
return qfalse;
}
- len = trap_FS_FOpenFile( g_admin.string, &f, FS_READ ) ;
+ len = trap_FS_FOpenFile( g_admin.string, &f, FS_READ );
if( len < 0 )
{
- ADMP( va( "^3!readconfig: ^7could not open admin config file %s\n",
- g_admin.string ) );
+ G_Printf( "^3readconfig: ^7could not open admin config file %s\n",
+ g_admin.string );
admin_default_levels();
return qfalse;
}
- cnf = G_Alloc( len + 1 );
+ cnf = BG_Alloc( len + 1 );
cnf2 = cnf;
trap_FS_Read( cnf, len, f );
*( cnf + len ) = '\0';
trap_FS_FCloseFile( f );
- t = COM_Parse( &cnf );
+ admin_level_maxname = 0;
+
level_open = admin_open = ban_open = command_open = qfalse;
- while( *t )
+ COM_BeginParseSession( g_admin.string );
+ while( 1 )
{
- if( !Q_stricmp( t, "[level]" ) ||
- !Q_stricmp( t, "[admin]" ) ||
- !Q_stricmp( t, "[ban]" ) ||
- !Q_stricmp( t, "[command]" ) )
- {
+ t = COM_Parse( &cnf );
+ if( !*t )
+ break;
- if( level_open )
- g_admin_levels[ lc++ ] = l;
- else if( admin_open )
- g_admin_admins[ ac++ ] = a;
- else if( ban_open )
- g_admin_bans[ bc++ ] = b;
- else if( command_open )
- g_admin_commands[ cc++ ] = c;
- level_open = admin_open =
- ban_open = command_open = qfalse;
+ if( !Q_stricmp( t, "[level]" ) )
+ {
+ if( l )
+ l = l->next = BG_Alloc( sizeof( g_admin_level_t ) );
+ else
+ l = g_admin_levels = BG_Alloc( sizeof( g_admin_level_t ) );
+ level_open = qtrue;
+ admin_open = ban_open = command_open = qfalse;
+ lc++;
}
-
- if( level_open )
+ else if( !Q_stricmp( t, "[admin]" ) )
+ {
+ if( a )
+ a = a->next = BG_Alloc( sizeof( g_admin_admin_t ) );
+ else
+ a = g_admin_admins = BG_Alloc( sizeof( g_admin_admin_t ) );
+ admin_open = qtrue;
+ level_open = ban_open = command_open = qfalse;
+ ac++;
+ }
+ else if( !Q_stricmp( t, "[ban]" ) )
+ {
+ if( b )
+ b = b->next = BG_Alloc( sizeof( g_admin_ban_t ) );
+ else
+ b = g_admin_bans = BG_Alloc( sizeof( g_admin_ban_t ) );
+ ban_open = qtrue;
+ level_open = admin_open = command_open = qfalse;
+ bc++;
+ }
+ else if( !Q_stricmp( t, "[command]" ) )
+ {
+ if( c )
+ c = c->next = BG_Alloc( sizeof( g_admin_command_t ) );
+ else
+ c = g_admin_commands = BG_Alloc( sizeof( g_admin_command_t ) );
+ command_open = qtrue;
+ level_open = admin_open = ban_open = qfalse;
+ cc++;
+ }
+ else if( level_open )
{
if( !Q_stricmp( t, "level" ) )
{
@@ -1778,6 +1168,10 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
else if( !Q_stricmp( t, "name" ) )
{
admin_readconfig_string( &cnf, l->name, sizeof( l->name ) );
+ // max printable name length for formatting
+ len = Q_PrintStrlen( l->name );
+ if( len > admin_level_maxname )
+ admin_level_maxname = len;
}
else if( !Q_stricmp( t, "flags" ) )
{
@@ -1785,9 +1179,7 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
}
else
{
- ADMP( va( "^3!readconfig: ^7[level] parse error near %s on line %d\n",
- t,
- COM_GetCurrentParseLine() ) );
+ COM_ParseError( "[level] unrecognized token \"%s\"", t );
}
}
else if( admin_open )
@@ -1808,15 +1200,9 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
{
admin_readconfig_string( &cnf, a->flags, sizeof( a->flags ) );
}
- else if( !Q_stricmp( t, "seen" ) )
- {
- admin_readconfig_int( &cnf, &a->seen );
- }
else
{
- ADMP( va( "^3!readconfig: ^7[admin] parse error near %s on line %d\n",
- t,
- COM_GetCurrentParseLine() ) );
+ COM_ParseError( "[admin] unrecognized token \"%s\"", t );
}
}
@@ -1832,7 +1218,8 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
}
else if( !Q_stricmp( t, "ip" ) )
{
- admin_readconfig_string( &cnf, b->ip, sizeof( b->ip ) );
+ admin_readconfig_string( &cnf, ip, sizeof( ip ) );
+ G_AddressParse( ip, &b->ip );
}
else if( !Q_stricmp( t, "reason" ) )
{
@@ -1846,23 +1233,13 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
{
admin_readconfig_int( &cnf, &b->expires );
}
- else if( !Q_stricmp( t, "suspend" ) )
- {
- admin_readconfig_int( &cnf, &b->suspend );
- }
else if( !Q_stricmp( t, "banner" ) )
{
admin_readconfig_string( &cnf, b->banner, sizeof( b->banner ) );
}
- else if( !Q_stricmp( t, "blevel" ) )
- {
- admin_readconfig_int( &cnf, &b->bannerlevel );
- }
else
{
- ADMP( va( "^3!readconfig: ^7[ban] parse error near %s on line %d\n",
- t,
- COM_GetCurrentParseLine() ) );
+ COM_ParseError( "[ban] unrecognized token \"%s\"", t );
}
}
else if( command_open )
@@ -1885,761 +1262,305 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
}
else
{
- ADMP( va( "^3!readconfig: ^7[command] parse error near %s on line %d\n",
- t,
- COM_GetCurrentParseLine() ) );
+ COM_ParseError( "[command] unrecognized token \"%s\"", t );
}
}
-
- if( !Q_stricmp( t, "[level]" ) )
- {
- if( lc >= MAX_ADMIN_LEVELS )
- return qfalse;
- l = G_Alloc( sizeof( g_admin_level_t ) );
- l->level = 0;
- *l->name = '\0';
- *l->flags = '\0';
- level_open = qtrue;
- }
- else if( !Q_stricmp( t, "[admin]" ) )
- {
- if( ac >= MAX_ADMIN_ADMINS )
- return qfalse;
- a = G_Alloc( sizeof( g_admin_admin_t ) );
- *a->name = '\0';
- *a->guid = '\0';
- a->level = 0;
- *a->flags = '\0';
- a->seen = 0;
- admin_open = qtrue;
- }
- else if( !Q_stricmp( t, "[ban]" ) )
- {
- if( bc >= MAX_ADMIN_BANS )
- return qfalse;
- b = G_Alloc( sizeof( g_admin_ban_t ) );
- *b->name = '\0';
- *b->guid = '\0';
- *b->ip = '\0';
- *b->made = '\0';
- b->expires = 0;
- b->suspend = 0;
- *b->reason = '\0';
- b->bannerlevel = 0;
- ban_open = qtrue;
- }
- else if( !Q_stricmp( t, "[command]" ) )
+ else
{
- if( cc >= MAX_ADMIN_COMMANDS )
- return qfalse;
- c = G_Alloc( sizeof( g_admin_command_t ) );
- *c->command = '\0';
- *c->exec = '\0';
- *c->desc = '\0';
- *c->flag = '\0';
- command_open = qtrue;
+ COM_ParseError( "unexpected token \"%s\"", t );
}
- t = COM_Parse( &cnf );
- }
- if( level_open )
- {
-
- g_admin_levels[ lc++ ] = l;
}
- if( admin_open )
- g_admin_admins[ ac++ ] = a;
- if( ban_open )
- g_admin_bans[ bc++ ] = b;
- if( command_open )
- g_admin_commands[ cc++ ] = c;
- G_Free( cnf2 );
- ADMP( va( "^3!readconfig: ^7loaded %d levels, %d admins, %d bans, %d commands\n",
+ BG_Free( cnf2 );
+ ADMP( va( "^3readconfig: ^7loaded %d levels, %d admins, %d bans, %d commands\n",
lc, ac, bc, cc ) );
if( lc == 0 )
admin_default_levels();
else
{
- char n[ MAX_NAME_LENGTH ] = {""};
-
- // max printable name length for formatting
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- G_DecolorString( l->name, n );
- if( strlen( n ) > admin_level_maxname )
- admin_level_maxname = strlen( n );
- }
+ llsort( (struct llist **)&g_admin_levels, cmplevel );
+ llsort( (struct llist **)&g_admin_admins, cmplevel );
}
- // reset adminLevel
+
+ // restore admin mapping
for( i = 0; i < level.maxclients; i++ )
+ {
if( level.clients[ i ].pers.connected != CON_DISCONNECTED )
- level.clients[ i ].pers.adminLevel = G_admin_level( &g_entities[ i ] );
+ {
+ level.clients[ i ].pers.admin =
+ G_admin_admin( level.clients[ i ].pers.guid );
+ if( level.clients[ i ].pers.admin )
+ G_admin_authlog( &g_entities[ i ] );
+ G_admin_cmdlist( &g_entities[ i ] );
+ }
+ }
+
return qtrue;
}
-qboolean G_admin_time( gentity_t *ent, int skiparg )
+qboolean G_admin_time( gentity_t *ent )
{
qtime_t qt;
- int t;
- t = trap_RealTime( &qt );
- ADMP( va( "^3!time: ^7local time is %02i:%02i:%02i\n",
+ trap_RealTime( &qt );
+ ADMP( va( "^3time: ^7local time is %02i:%02i:%02i\n",
qt.tm_hour, qt.tm_min, qt.tm_sec ) );
-
return qtrue;
}
-static int G_admin_find_slot( gentity_t *ent, char *namearg, const char *command )
-{
- char name[ MAX_NAME_LENGTH ];
- char testname[ MAX_NAME_LENGTH ];
- char *guid = NULL;
- int matches = 0;
- int id = -1;
- int i;
- qboolean numeric = qtrue;
-
- G_SanitiseString( namearg, name, sizeof( name ) );
- for( i = 0; i < sizeof( name ) && name[ i ] ; i++ )
- {
- if( !isdigit( name[ i ] ) )
- {
- numeric = qfalse;
- break;
- }
- }
- if( numeric )
- {
- id = atoi( name );
-
- if( id >= 0 && id < level.maxclients )
- {
- gentity_t *vic;
-
- vic = &g_entities[ id ];
- if( vic && vic->client && vic->client->pers.connected != CON_DISCONNECTED )
- return id;
-
- ADMP( va( "^3!%s:^7 no one connected by that slot number\n", command ) );
- return -1;
- }
- if( id >= MAX_CLIENTS && id < MAX_CLIENTS + MAX_ADMIN_ADMINS &&
- g_admin_admins[ id - MAX_CLIENTS ] )
- {
- return id;
- }
-
- ADMP( va( "^3!%s:^7 no match for slot or admin number %d\n", command, id ) );
- return -1;
- }
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] && matches < 2; i++ )
- {
- G_SanitiseString( g_admin_admins[ i ]->name, testname, sizeof( testname ) );
- if( strstr( testname, name ) )
- {
- id = i + MAX_CLIENTS;
- guid = g_admin_admins[ i ]->guid;
- matches++;
- }
- }
- for( i = 0; i < level.maxclients && matches < 2; i++ )
- {
- if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
- continue;
-
- if( matches && guid && !Q_stricmp( level.clients[ i ].pers.guid, guid ) )
- continue;
-
- G_SanitiseString( level.clients[ i ].pers.netname, testname, sizeof( testname ) );
- if( strstr( testname, name ) )
- {
- id = i;
- matches++;
- }
- }
-
- if( matches == 0 )
- {
- ADMP( va( "^3!%s:^7 no match, use !listplayers or !listadmins to "
- "find an appropriate number to use instead of name.\n", command ) );
- return -1;
- }
-
- if( matches == 1 )
- return id;
-
- ADMP( va( "^3!%s:^7 multiple matches, use the admin number instead:\n", command ) );
- admin_listadmins( ent, 0, name, 0 );
+// this should be in one of the headers, but it is only used here for now
+namelog_t *G_NamelogFromString( gentity_t *ent, char *s );
- return -1;
-}
-
-static int G_admin_find_admin_slot( gentity_t *ent, char *namearg, char *command, char *nick, int nick_len )
+/*
+for consistency, we should be able to target a disconnected player with setlevel
+but we can't use namelog and remain consistent, so the solution would be to make
+everyone a real level 0 admin so they can be targeted until the next level
+but that seems kind of stupid
+*/
+qboolean G_admin_setlevel( gentity_t *ent )
{
- gentity_t *vic;
- char *guid;
- int id;
+ char name[ MAX_NAME_LENGTH ] = {""};
+ char lstr[ 12 ]; // 11 is max strlen() for 32-bit (signed) int
+ char testname[ MAX_NAME_LENGTH ] = {""};
int i;
+ gentity_t *vic = NULL;
+ g_admin_admin_t *a = NULL;
+ g_admin_level_t *l = NULL;
+ int na;
- if ( nick )
- nick[ 0 ] = '\0';
-
- id = G_admin_find_slot( ent, namearg, command );
- if( id < 0 )
- return -1;
-
- if( id < MAX_CLIENTS )
+ if( trap_Argc() < 3 )
{
- vic = &g_entities[ id ];
- guid = vic->client->pers.guid;
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( guid, g_admin_admins[ i ]->guid ) )
- {
- id = i + MAX_CLIENTS;
- if( nick )
- Q_strncpyz( nick, vic->client->pers.netname, nick_len );
- break;
- }
- }
- if( id < MAX_CLIENTS )
- {
- ADMP( va( "^3!%s:^7 player is not !registered\n", command ) );
- return -1;
- }
+ ADMP( "^3setlevel: ^7usage: setlevel [name|slot#] [level]\n" );
+ return qfalse;
}
- id -= MAX_CLIENTS;
- if( nick && !nick[ 0 ] )
- Q_strncpyz( nick, g_admin_admins[ id ]->name, nick_len );
-
- return id;
-}
-
-qboolean G_admin_setlevel( gentity_t *ent, int skiparg )
-{
- char lstr[ 11 ]; // 10 is max strlen() for 32-bit int
- char adminname[ MAX_NAME_LENGTH ] = {""};
- char testname[ MAX_NAME_LENGTH ] = {""};
- char guid[ 33 ];
- int l, i;
- gentity_t *vic = NULL;
- qboolean updated = qfalse;
- g_admin_admin_t *a;
- qboolean found = qfalse;
- int id = -1;
+ trap_Argv( 1, testname, sizeof( testname ) );
+ trap_Argv( 2, lstr, sizeof( lstr ) );
- if( G_SayArgc() < 3 + skiparg )
+ if( !( l = G_admin_level( atoi( lstr ) ) ) )
{
- ADMP( "^3!setlevel: ^7usage: !setlevel [name|slot#] [level]\n" );
+ ADMP( "^3setlevel: ^7level is not defined\n" );
return qfalse;
}
- G_SayArgv( 1 + skiparg, testname, sizeof( testname ) );
- G_SayArgv( 2 + skiparg, lstr, sizeof( lstr ) );
- l = atoi( lstr );
- if( ent && l > ent->client->pers.adminLevel )
+ if( ent && l->level >
+ ( ent->client->pers.admin ? ent->client->pers.admin->level : 0 ) )
{
- ADMP( "^3!setlevel: ^7you may not use !setlevel to set a level higher "
+ ADMP( "^3setlevel: ^7you may not use setlevel to set a level higher "
"than your current level\n" );
return qfalse;
}
- // if admin is activated for the first time on a running server, we need
- // to ensure at least the default levels get created
- if( !ent && !g_admin_levels[ 0 ] )
- G_admin_readconfig(NULL, 0);
+ for( na = 0, a = g_admin_admins; a; na++, a = a->next );
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ for( i = 0; testname[ i ] && isdigit( testname[ i ] ); i++ );
+ if( !testname[ i ] )
{
- if( g_admin_levels[ i ]->level == l )
- {
- found = qtrue;
- break;
- }
- }
- if( !found )
- {
- ADMP( "^3!setlevel: ^7level is not defined\n" );
- return qfalse;
- }
-
- id = G_admin_find_slot( ent, testname, "setlevel" );
- if( id >=0 && id < MAX_CLIENTS )
- {
- vic = &g_entities[ id ];
- Q_strncpyz( adminname, vic->client->pers.netname, sizeof( adminname ) );
- Q_strncpyz( guid, vic->client->pers.guid, sizeof( guid ) );
- }
- else if( id >= MAX_CLIENTS && id < MAX_CLIENTS + MAX_ADMIN_ADMINS &&
- g_admin_admins[ id - MAX_CLIENTS ] )
- {
- Q_strncpyz( adminname, g_admin_admins[ id - MAX_CLIENTS ]->name,
- sizeof( adminname ) );
- Q_strncpyz( guid, g_admin_admins[ id - MAX_CLIENTS ]->guid,
- sizeof( guid ) );
- for( i = 0; i < level.maxclients; i++ )
+ int id = atoi( testname );
+ if( id < MAX_CLIENTS )
{
- if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
- continue;
- if( !Q_stricmp( level.clients[ i ].pers.guid, guid ) )
+ vic = &g_entities[ id ];
+ if( !vic || !vic->client || vic->client->pers.connected == CON_DISCONNECTED )
{
- vic = &g_entities[ i ];
- Q_strncpyz( adminname, vic->client->pers.netname, sizeof( adminname ) );
+ ADMP( va( "^3setlevel: ^7no player connected in slot %d\n", id ) );
+ return qfalse;
}
}
- }
- else
- {
- return qfalse;
- }
-
- if( !Q_stricmp( guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ) )
- {
- ADMP( va( "^3!setlevel: ^7%s does not have a valid GUID\n", adminname ) );
- return qfalse;
- }
- if( ent && !admin_higher_guid( ent->client->pers.guid, guid ) )
- {
- ADMP( "^3!setlevel: ^7sorry, but your intended victim has a higher"
- " admin level than you\n" );
- return qfalse;
- }
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ];i++ )
- {
- if( !Q_stricmp( g_admin_admins[ i ]->guid, guid ) )
- {
- g_admin_admins[ i ]->level = l;
- Q_strncpyz( g_admin_admins[ i ]->name, adminname,
- sizeof( g_admin_admins[ i ]->name ) );
- updated = qtrue;
- }
- }
- if( !updated )
- {
- if( i == MAX_ADMIN_ADMINS )
+ else if( id < na + MAX_CLIENTS )
+ for( i = 0, a = g_admin_admins; i < id - MAX_CLIENTS; i++, a = a->next );
+ else
{
- ADMP( "^3!setlevel: ^7too many admins\n" );
+ ADMP( va( "^3setlevel: ^7%s not in range 1-%d\n",
+ testname, na + MAX_CLIENTS - 1 ) );
return qfalse;
}
- a = G_Alloc( sizeof( g_admin_admin_t ) );
- a->level = l;
- Q_strncpyz( a->name, adminname, sizeof( a->name ) );
- Q_strncpyz( a->guid, guid, sizeof( a->guid ) );
- *a->flags = '\0';
- g_admin_admins[ i ] = a;
}
-
- AP( va(
- "print \"^3!setlevel: ^7%s^7 was given level %d admin rights by %s\n\"",
- adminname, l, ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- if( vic )
- {
- vic->client->pers.adminLevel = l;
- G_admin_set_adminname( vic );
- }
-
- if( !g_admin.string[ 0 ] )
- ADMP( "^3!setlevel: ^7WARNING g_admin not set, not saving admin record "
- "to a file\n" );
else
- admin_writeconfig();
- return qtrue;
-}
-
-static int SortFlags( const void *pa, const void *pb )
-{
- char *a = (char *)pa;
- char *b = (char *)pb;
-
- if( *a == '-' || *a == '+' )
- a++;
- if( *b == '-' || *b == '+' )
- b++;
- return strcmp(a, b);
-}
-
-#define MAX_USER_FLAGS 200
-const char *G_admin_user_flag( char *oldflags, char *flag, qboolean add, qboolean clear,
- char *newflags, int size )
-{
- char *token, *token_p;
- char *key;
- char head_flags[ MAX_USER_FLAGS ][ MAX_ADMIN_FLAG_LEN ];
- char tail_flags[ MAX_USER_FLAGS ][ MAX_ADMIN_FLAG_LEN ];
- char allflag[ MAX_ADMIN_FLAG_LEN ];
- char newflag[ MAX_ADMIN_FLAG_LEN ];
- int head_count = 0;
- int tail_count = 0;
- qboolean flagset = qfalse;
- int i;
+ G_SanitiseString( testname, name, sizeof( name ) );
- if( !flag[ 0 ] )
- {
- return "invalid admin flag";
- }
-
- allflag[ 0 ] = '\0';
- token_p = oldflags;
- while( *( token = COM_Parse( &token_p ) ) )
+ if( vic )
+ a = vic->client->pers.admin;
+ else if( !a )
{
- key = token;
- if( *key == '-' || *key == '+' )
- key++;
+ g_admin_admin_t *wa;
+ int matches = 0;
- if( !strcmp( key, flag ) )
+ for( wa = g_admin_admins; wa && matches < 2; wa = wa->next )
{
- if( flagset )
- continue;
- flagset = qtrue;
- if( clear )
+ G_SanitiseString( wa->name, testname, sizeof( testname ) );
+ if( strstr( testname, name ) )
{
- // clearing ALLFLAGS will result in clearing any following flags
- if( !strcmp( key, ADMF_ALLFLAGS ) )
- break;
- else
- continue;
+ a = wa;
+ matches++;
}
- Com_sprintf( newflag, sizeof( newflag ), "%s%s",
- ( add ) ? "+" : "-", key );
- }
- else
- {
- Q_strncpyz( newflag, token, sizeof( newflag ) );
}
- if( !strcmp( key, ADMF_ALLFLAGS ) )
+ for( i = 0; i < level.maxclients && matches < 2; i++ )
{
- if( !allflag[ 0 ] )
- Q_strncpyz( allflag, newflag, sizeof( allflag ) );
- continue;
- }
+ if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
+ continue;
- if( !allflag[ 0 ] )
- {
- if( head_count < MAX_USER_FLAGS )
+ if( matches && level.clients[ i ].pers.admin &&
+ level.clients[ i ].pers.admin == a )
{
- Q_strncpyz( head_flags[ head_count ], newflag,
- sizeof( head_flags[ head_count ] ) );
- head_count++;
+ vic = &g_entities[ i ];
+ continue;
}
- }
- else
- {
- if( tail_count < MAX_USER_FLAGS )
+
+ G_SanitiseString( level.clients[ i ].pers.netname, testname,
+ sizeof( testname ) );
+ if( strstr( testname, name ) )
{
- Q_strncpyz( tail_flags[ tail_count ], newflag,
- sizeof( tail_flags[ tail_count ] ) );
- tail_count++;
+ vic = &g_entities[ i ];
+ a = vic->client->pers.admin;
+ matches++;
}
}
- }
- if( !flagset && !clear )
- {
- if( !strcmp( flag, ADMF_ALLFLAGS ) )
+ if( matches == 0 )
{
- Com_sprintf( allflag, sizeof( allflag ), "%s%s",
- ( add ) ? "" : "-", ADMF_ALLFLAGS );
+ ADMP( "^3setlevel:^7 no match. use listplayers or listadmins to "
+ "find an appropriate number to use instead of name.\n" );
+ return qfalse;
}
- else if( !allflag[ 0 ] )
+ if( matches > 1 )
{
- if( head_count < MAX_USER_FLAGS )
- {
- Com_sprintf( head_flags[ head_count ], sizeof( head_flags[ head_count ] ),
- "%s%s", ( add ) ? "" : "-", flag );
- head_count++;
- }
- }
- else
- {
- if( tail_count < MAX_USER_FLAGS )
- {
- Com_sprintf( tail_flags[ tail_count ], sizeof( tail_flags[ tail_count ] ),
- "%s%s", ( add ) ? "+" : "-", flag );
- tail_count++;
- }
+ ADMP( "^3setlevel:^7 more than one match. Use the admin number "
+ "instead:\n" );
+ admin_listadmins( ent, 0, name );
+ return qfalse;
}
}
- qsort( head_flags, head_count, sizeof( head_flags[ 0 ] ), SortFlags );
- qsort( tail_flags, tail_count, sizeof( tail_flags[ 0 ] ), SortFlags );
-
- // rebuild flags
- newflags[ 0 ] = '\0';
- for( i = 0; i < head_count; i++ )
+ if( ent && !admin_higher_admin( ent->client->pers.admin, a ) )
{
- Q_strcat( newflags, size,
- va( "%s%s", ( i ) ? " ": "", head_flags[ i ] ) );
- }
- if( allflag[ 0 ] )
- {
- Q_strcat( newflags, size,
- va( "%s%s", ( newflags[ 0 ] ) ? " ": "", allflag ) );
-
- for( i = 0; i < tail_count; i++ )
- {
- Q_strcat( newflags, size,
- va( " %s", tail_flags[ i ] ) );
- }
+ ADMP( "^3setlevel: ^7sorry, but your intended victim has a higher"
+ " admin level than you\n" );
+ return qfalse;
}
- return NULL;
-}
-
-typedef struct {
- char *flag;
- char *description;
-} AdminFlagListEntry_t;
-static AdminFlagListEntry_t adminFlagList[] =
-{
- { ADMF_ACTIVITY, "inactivity rules do not apply" },
- { ADMF_ADMINCHAT, "can see and use admin chat" },
- { ADMF_HIGHADMINCHAT, "can see and use high admin chat" },
- { ADMF_ALLFLAGS, "has all flags and can use any command" },
- { ADMF_BAN_IMMUNITY, "immune from IP bans" },
- { ADMF_CAN_PERM_BAN, "can permanently ban players" },
- { ADMF_DBUILDER, "permanent designated builder" },
- { ADMF_FORCETEAMCHANGE, "team balance rules do not apply" },
- { ADMF_INCOGNITO, "does not show as admin in !listplayers" },
- { ADMF_SEESINCOGNITO, "sees registered name of players flagged with INCOGNITO" },
- { ADMF_IMMUNITY, "cannot be vote kicked or muted" },
- { ADMF_IMMUTABLE, "admin commands cannot be used on them" },
- { ADMF_NOCENSORFLOOD, "no flood protection" },
- { ADMF_NO_VOTE_LIMIT, "vote limitations do not apply" },
- { ADMF_SEESFULLLISTPLAYERS, "sees all info in !listplayers" },
- { ADMF_SPEC_ALLCHAT, "can see team chat as spectator" },
- { ADMF_ADMINSTEALTH, "uses admin stealth" },
- { ADMF_TEAMCHANGEFREE, "keeps credits on team switch" },
- { ADMF_TEAMCHAT_CMD, "can run commands from team chat" },
- { ADMF_UNACCOUNTABLE, "does not need to specify reason for kick/ban" },
- { ADMF_NOSCRIMRESTRICTION, "team joining, vote and chat restrictions during scrims do not apply" },
- { ADMF_NO_BUILD, "can not build" },
- { ADMF_NO_CHAT, "can not talk" },
- { ADMF_NO_VOTE, "can not call votes" },
- { ADMF_NOAUTOBAHN, "ignored by the Autobahn system" }
-};
-static int adminNumFlags= sizeof( adminFlagList ) / sizeof( adminFlagList[ 0 ] );
-
-#define MAX_LISTCOMMANDS 128
-qboolean G_admin_flaglist( gentity_t *ent, int skiparg )
-{
- qboolean shown[ MAX_LISTCOMMANDS ];
- int i, j;
- int count = 0;
-
- ADMBP_begin();
-
- ADMBP( "^3Ability flags:\n" );
-
- for( i = 0; i < adminNumFlags; i++ )
+ if( vic && vic->client->pers.guidless )
{
- ADMBP( va( " %s%-20s ^7%s\n",
- ( adminFlagList[ i ].flag[ 0 ] != '.' ) ? "^5" : "^1",
- adminFlagList[ i ].flag,
- adminFlagList[ i ].description ) );
+ ADMP( va( "^3setlevel: ^7%s^7 has no GUID\n", vic->client->pers.netname ) );
+ return qfalse;
}
- ADMBP( "^3Command flags:\n" );
-
- memset( shown, 0, sizeof( shown ) );
- for( i = 0; i < adminNumCmds; i++ )
+ if( !a && vic )
{
- if( i < MAX_LISTCOMMANDS && shown[ i ] )
- continue;
- ADMBP( va( " ^5%-20s^7", g_admin_cmds[ i ].flag ) );
- for( j = i; j < adminNumCmds; j++ )
- {
- if( !strcmp( g_admin_cmds[ j ].flag, g_admin_cmds[ i ].flag ) )
- {
- ADMBP( va( " %s", g_admin_cmds[ j ].keyword ) );
- if( j < MAX_LISTCOMMANDS )
- shown[ j ] = qtrue;
- }
- }
- ADMBP( "\n" );
- count++;
+ for( a = g_admin_admins; a && a->next; a = a->next );
+ if( a )
+ a = a->next = BG_Alloc( sizeof( g_admin_admin_t ) );
+ else
+ a = g_admin_admins = BG_Alloc( sizeof( g_admin_admin_t ) );
+ vic->client->pers.admin = a;
+ Q_strncpyz( a->guid, vic->client->pers.guid, sizeof( a->guid ) );
}
- ADMBP( va( "^3!flaglist: ^7listed %d abilities and %d command flags\n",
- adminNumFlags, count ) );
+ a->level = l->level;
+ if( vic )
+ Q_strncpyz( a->name, vic->client->pers.netname, sizeof( a->name ) );
- ADMBP_end();
+ admin_log( va( "%d (%s) \"%s" S_COLOR_WHITE "\"", a->level, a->guid,
+ a->name ) );
+
+ AP( va(
+ "print \"^3setlevel: ^7%s^7 was given level %d admin rights by %s\n\"",
+ a->name, a->level, ( ent ) ? ent->client->pers.netname : "console" ) );
+ admin_writeconfig();
+ if( vic )
+ {
+ G_admin_authlog( vic );
+ G_admin_cmdlist( vic );
+ }
return qtrue;
}
-qboolean G_admin_flag( gentity_t *ent, int skiparg )
+static void admin_create_ban( gentity_t *ent,
+ char *netname,
+ char *guid,
+ addr_t *ip,
+ int seconds,
+ char *reason )
{
- char command[ MAX_ADMIN_CMD_LEN ], *cmd;
- char name[ MAX_NAME_LENGTH ];
- char flagbuf[ MAX_ADMIN_FLAG_LEN ];
- char *flag;
- int id;
- char adminname[ MAX_NAME_LENGTH ] = {""};
- const char *result;
- qboolean add = qtrue;
- qboolean clear = qfalse;
- int admin_level = -1;
- int i, level;
-
- G_SayArgv( skiparg, command, sizeof( command ) );
- cmd = command;
- if( *cmd == '!' )
- cmd++;
-
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( va( "^3!%s: ^7usage: !%s slot# flag\n", cmd, cmd ) );
- return qfalse;
- }
-
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( name[ 0 ] == '*' )
- {
- if( ent )
- {
- ADMP( va( "^3!%s: only console can change admin level flags\n", cmd ) );
- return qfalse;
- }
- id = atoi( name + 1 );
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- if( g_admin_levels[ i ]->level == id )
- {
- admin_level = i;
- break;
- }
- }
- if( admin_level < 0 )
- {
- ADMP( va( "^3!%s: admin level %d does not exist\n", cmd, id ) );
- return qfalse;
- }
- Com_sprintf( adminname, sizeof( adminname ), "admin level %d", id );
- }
- else
- {
- id = G_admin_find_admin_slot( ent, name, cmd, adminname, sizeof( adminname ) );
- if( id < 0 )
- return qfalse;
+ g_admin_ban_t *b = NULL;
+ qtime_t qt;
+ int t;
+ int i;
+ char *name;
+ char disconnect[ MAX_STRING_CHARS ];
- if( ent && !admin_higher_guid( ent->client->pers.guid, g_admin_admins[ id ]->guid ) )
- {
- ADMP( va( "^3%s:^7 your intended victim has a higher admin level than you\n", cmd ) );
- return qfalse;
- }
- }
+ t = trap_RealTime( &qt );
- if( G_SayArgc() < 3 + skiparg )
+ for( b = g_admin_bans; b; b = b->next )
{
- flag = "";
- level = 0;
- if( admin_level < 0 )
- {
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- if( g_admin_admins[ id ]->level == g_admin_levels[ i ]->level )
- {
- flag = g_admin_levels[ i ]->flags;
- level = g_admin_admins[ id ]->level;
- break;
- }
- }
- ADMP( va( "^3%s:^7 flags for %s^7 are '^3%s^7'\n",
- cmd, adminname, g_admin_admins[ id ]->flags) );
- }
- else
- {
- flag = g_admin_levels[ admin_level ]->flags;
- level = g_admin_levels[ admin_level ]->level;
- }
- ADMP( va( "^3%s:^7 level %d flags are '%s'\n",
- cmd, level, flag ) );
-
- return qtrue;
+ if( !b->next )
+ break;
}
- G_SayArgv( 2 + skiparg, flagbuf, sizeof( flagbuf ) );
- flag = flagbuf;
- if( flag[ 0 ] == '-' || flag[ 0 ] == '+' )
- {
- add = ( flag[ 0 ] == '+' );
- flag++;
- }
- if( ent && !Q_stricmp( ent->client->pers.guid, g_admin_admins[ id ]->guid ) )
+ if( b )
{
- ADMP( va( "^3%s:^7 you may not change your own flags (use rcon)\n", cmd ) );
- return qfalse;
- }
- if( flag[ 0 ] != '.' && !G_admin_permission( ent, flag ) )
- {
- ADMP( va( "^3%s:^7 you can only change flags that you also have\n", cmd ) );
- return qfalse;
+ if( !b->next )
+ b = b->next = BG_Alloc( sizeof( g_admin_ban_t ) );
}
+ else
+ b = g_admin_bans = BG_Alloc( sizeof( g_admin_ban_t ) );
- if( !Q_stricmp( cmd, "unflag" ) )
- {
- clear = qtrue;
- }
+ Q_strncpyz( b->name, netname, sizeof( b->name ) );
+ Q_strncpyz( b->guid, guid, sizeof( b->guid ) );
+ memcpy( &b->ip, ip, sizeof( b->ip ) );
- if( admin_level < 0 )
- {
- result = G_admin_user_flag( g_admin_admins[ id ]->flags, flag, add, clear,
- g_admin_admins[ id ]->flags, sizeof( g_admin_admins[ id ]->flags ) );
- }
- else
- {
- result = G_admin_user_flag( g_admin_levels[ admin_level ]->flags, flag, add, clear,
- g_admin_levels[ admin_level ]->flags,
- sizeof( g_admin_levels[ admin_level ]->flags ) );
- }
- if( result )
- {
- ADMP( va( "^3!flag: ^7an error occured setting flag '^3%s^7', %s\n",
- flag, result ) );
- return qfalse;
- }
+ Com_sprintf( b->made, sizeof( b->made ), "%04i-%02i-%02i %02i:%02i:%02i",
+ qt.tm_year+1900, qt.tm_mon+1, qt.tm_mday,
+ qt.tm_hour, qt.tm_min, qt.tm_sec );
- if( !Q_stricmp( cmd, "flag" ) )
- {
- G_AdminsPrintf( "^3!%s: ^7%s^7 was %s admin flag '%s' by %s\n",
- cmd, adminname,
- ( add ) ? "given" : "denied",
- flag,
- ( ent ) ? ent->client->pers.netname : "console" );
- }
+ if( ent && ent->client->pers.admin )
+ name = ent->client->pers.admin->name;
+ else if( ent )
+ name = ent->client->pers.netname;
else
- {
- G_AdminsPrintf( "^3!%s: ^7admin flag '%s' for %s^7 cleared by %s\n",
- cmd, flag, adminname,
- ( ent ) ? ent->client->pers.netname : "console" );
- }
+ name = "console";
- if( !g_admin.string[ 0 ] )
- ADMP( va( "^3!%s: ^7WARNING g_admin not set, not saving admin record "
- "to a file\n", cmd ) );
+ Q_strncpyz( b->banner, name, sizeof( b->banner ) );
+ if( !seconds )
+ b->expires = 0;
else
- admin_writeconfig();
+ b->expires = t + seconds;
+ if( !*reason )
+ Q_strncpyz( b->reason, "banned by admin", sizeof( b->reason ) );
+ else
+ Q_strncpyz( b->reason, reason, sizeof( b->reason ) );
- return qtrue;
+ G_admin_ban_message( NULL, b, disconnect, sizeof( disconnect ), NULL, 0 );
+
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
+ continue;
+ if( G_admin_ban_matches( b, &g_entities[ i ] ) )
+ {
+ trap_SendServerCommand( i, va( "disconnect \"%s\"", disconnect ) );
+
+ trap_DropClient( i, va( "has been kicked by %s^7. reason: %s",
+ b->banner, b->reason ) );
+ }
+ }
}
int G_admin_parse_time( const char *time )
{
int seconds = 0, num = 0;
- int i;
- for( i = 0; time[ i ]; i++ )
+ if( !*time )
+ return -1;
+ while( *time )
{
- if( isdigit( time[ i ] ) )
- {
- num = num * 10 + time[ i ] - '0';
- continue;
- }
- if( i == 0 || !isdigit( time[ i - 1 ] ) )
+ if( !isdigit( *time ) )
return -1;
- switch( time[ i ] )
+ while( isdigit( *time ) )
+ num = num * 10 + *time++ - '0';
+
+ if( !*time )
+ break;
+ switch( *time++ )
{
case 'w': num *= 7;
case 'd': num *= 24;
@@ -2653,2093 +1574,776 @@ int G_admin_parse_time( const char *time )
}
if( num )
seconds += num;
- // overflow
- if( seconds < 0 )
- seconds = 0;
return seconds;
}
-static qboolean admin_create_ban( gentity_t *ent,
- char *netname,
- char *guid,
- char *ip,
- int seconds,
- char *reason )
+qboolean G_admin_setdevmode( gentity_t *ent )
{
- g_admin_ban_t *b = NULL;
- qtime_t qt;
- int t;
- int i;
-
- t = trap_RealTime( &qt );
- b = G_Alloc( sizeof( g_admin_ban_t ) );
-
- if( !b )
+ char str[ 5 ];
+ if( trap_Argc() != 2 )
+ {
+ ADMP( "^3setdevmode: ^7usage: setdevmode [on|off]\n" );
return qfalse;
-
- Q_strncpyz( b->name, netname, sizeof( b->name ) );
- Q_strncpyz( b->guid, guid, sizeof( b->guid ) );
- Q_strncpyz( b->ip, ip, sizeof( b->ip ) );
- b->suspend = 0;
-
- //strftime( b->made, sizeof( b->made ), "%m/%d/%y %H:%M:%S", lt );
- Q_strncpyz( b->made, va( "%02i/%02i/%02i %02i:%02i:%02i",
- (qt.tm_mon + 1), qt.tm_mday, (qt.tm_year - 100),
- qt.tm_hour, qt.tm_min, qt.tm_sec ),
- sizeof( b->made ) );
-
- Q_strncpyz( b->banner, G_admin_get_adminname( ent ), sizeof( b->banner ) );
-
- if( ent )
- b->bannerlevel = G_admin_level( ent );
- else
- b->bannerlevel = 0;
-
- if( !seconds )
- b->expires = 0;
- else
- b->expires = t + seconds;
- if( !*reason )
- Q_strncpyz( b->reason, "banned by admin", sizeof( b->reason ) );
+ }
+ trap_Argv( 1, str, sizeof( str ) );
+ if( !Q_stricmp( str, "on" ) )
+ {
+ if( g_cheats.integer )
+ {
+ ADMP( "^3setdevmode: ^7developer mode is already on\n" );
+ return qfalse;
+ }
+ trap_Cvar_Set( "sv_cheats", "1" );
+ trap_Cvar_Update( &g_cheats );
+ AP( va( "print \"^3setdevmode: ^7%s ^7has switched developer mode on\n\"",
+ ent ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+ }
+ else if( !Q_stricmp( str, "off" ) )
+ {
+ if( !g_cheats.integer )
+ {
+ ADMP( "^3setdevmode: ^7developer mode is already off\n" );
+ return qfalse;
+ }
+ trap_Cvar_Set( "sv_cheats", "0" );
+ trap_Cvar_Update( &g_cheats );
+ AP( va( "print \"^3setdevmode: ^7%s ^7has switched developer mode off\n\"",
+ ent ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+ }
else
- Q_strncpyz( b->reason, reason, sizeof( b->reason ) );
- for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
- ;
- if( i == MAX_ADMIN_BANS )
{
- ADMP( "^3!ban: ^7too many bans\n" );
- G_Free( b );
+ ADMP( "^3setdevmode: ^7usage: setdevmode [on|off]\n" );
return qfalse;
}
- g_admin_bans[ i ] = b;
- return qtrue;
}
-qboolean G_admin_kick( gentity_t *ent, int skiparg )
+qboolean G_admin_kick( gentity_t *ent )
{
- int pids[ MAX_CLIENTS ];
+ int pid;
char name[ MAX_NAME_LENGTH ], *reason, err[ MAX_STRING_CHARS ];
int minargc;
gentity_t *vic;
- char notice[51];
-
- trap_Cvar_VariableStringBuffer( "g_banNotice", notice, sizeof( notice ) );
- minargc = 3 + skiparg;
+ minargc = 3;
if( G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
- minargc = 2 + skiparg;
+ minargc = 2;
- if( G_SayArgc() < minargc )
+ if( trap_Argc() < minargc )
{
- ADMP( "^3!kick: ^7usage: !kick [name] [reason]\n" );
+ ADMP( "^3kick: ^7usage: kick [name] [reason]\n" );
return qfalse;
}
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- reason = G_SayConcatArgs( 2 + skiparg );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
+ trap_Argv( 1, name, sizeof( name ) );
+ reason = ConcatArgs( 2 );
+ if( ( pid = G_ClientNumberFromString( name, err, sizeof( err ) ) ) == -1 )
{
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!kick: ^7%s\n", err ) );
+ ADMP( va( "^3kick: ^7%s", err ) );
return qfalse;
}
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
+ vic = &g_entities[ pid ];
+ if( !admin_higher( ent, vic ) )
{
- ADMP( "^3!kick: ^7sorry, but your intended victim has a higher admin"
+ ADMP( "^3kick: ^7sorry, but your intended victim has a higher admin"
" level than you\n" );
return qfalse;
}
- vic = &g_entities[ pids[ 0 ] ];
+ if( vic->client->pers.localClient )
+ {
+ ADMP( "^3kick: ^7disconnecting the host would end the game\n" );
+ return qfalse;
+ }
+ admin_log( va( "%d (%s) \"%s" S_COLOR_WHITE "\": \"%s" S_COLOR_WHITE "\"",
+ pid,
+ vic->client->pers.guid,
+ vic->client->pers.netname,
+ reason ) );
admin_create_ban( ent,
vic->client->pers.netname,
- vic->client->pers.guid,
- vic->client->pers.ip, G_admin_parse_time( g_adminTempBan.string ),
+ vic->client->pers.guidless ? "" : vic->client->pers.guid,
+ &vic->client->pers.ip,
+ MAX( 1, G_admin_parse_time( g_adminTempBan.string ) ),
( *reason ) ? reason : "kicked by admin" );
- if( g_admin.string[ 0 ] )
- admin_writeconfig();
-
- trap_SendServerCommand( pids[ 0 ],
- va( "disconnect \"You have been kicked.\n%s^7\nreason:\n%s\n%s\"",
- ( ent ) ? va( "admin:\n%s", G_admin_adminPrintName( ent ) ) : "admin\nconsole",
- ( *reason ) ? reason : "kicked by admin", notice ) );
-
- trap_DropClient( pids[ 0 ], va( "kicked%s^7, reason: %s",
- ( ent ) ? va( " by %s", G_admin_adminPrintName( ent ) ) : " by console",
- ( *reason ) ? reason : "kicked by admin" ) );
+ admin_writeconfig();
return qtrue;
}
-qboolean G_admin_ban( gentity_t *ent, int skiparg )
+qboolean G_admin_setivo( gentity_t* ent )
{
- int seconds;
- char search[ MAX_NAME_LENGTH ];
- char secs[ 7 ];
- char *reason;
- int minargc;
- char duration[ 32 ];
- int logmatch = -1, logmatches = 0;
- int i, j;
- qboolean exactmatch = qfalse;
- char n2[ MAX_NAME_LENGTH ];
- char s2[ MAX_NAME_LENGTH ];
- char guid_stub[ 9 ];
- char notice[51];
-
- trap_Cvar_VariableStringBuffer( "g_banNotice", notice, sizeof( notice ) );
-
- if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
- G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
- {
- minargc = 2 + skiparg;
- }
- else if( ( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) || g_adminMaxBan.integer ) ||
- G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
- {
- minargc = 3 + skiparg;
- }
- else
- {
- minargc = 4 + skiparg;
- }
- if( G_SayArgc() < minargc )
+ char arg[ 3 ];
+ const char *cn;
+ gentity_t *spot;
+
+ if( !ent )
{
- ADMP( "^3!ban: ^7usage: !ban [name|slot|ip] [time] [reason]\n" );
+ ADMP( "^3setivo: ^7the console can't position intermission view overrides\n" );
return qfalse;
}
- G_SayArgv( 1 + skiparg, search, sizeof( search ) );
- G_SanitiseString( search, s2, sizeof( s2 ) );
- G_SayArgv( 2 + skiparg, secs, sizeof( secs ) );
- seconds = G_admin_parse_time( secs );
- if( seconds <= 0 )
+ if( trap_Argc() != 2 )
{
- if( g_adminMaxBan.integer && !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
- {
- ADMP( va( "^3!ban: ^7using your admin level's maximum ban length of %s\n",
- g_adminMaxBan.string ) );
- seconds = G_admin_parse_time( g_adminMaxBan.string );
- }
- else if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
- {
- seconds = 0;
- }
- else
- {
- ADMP( "^3!ban: ^7ban time must be positive\n" );
- return qfalse;
- }
- reason = G_SayConcatArgs( 2 + skiparg );
+ ADMP( "^3setivo: ^7usage: setivo {s|a|h}\n" );
+ return qfalse;
}
+ trap_Argv( 1, arg, sizeof( arg ) );
+ if( !Q_stricmp( arg, "s" ) )
+ cn = "info_player_intermission";
+ else if( !Q_stricmp( arg, "a" ) )
+ cn = "info_alien_intermission";
+ else if( !Q_stricmp( arg, "h" ) )
+ cn = "info_human_intermission";
else
{
- reason = G_SayConcatArgs( 3 + skiparg );
-
- if( g_adminMaxBan.integer &&
- seconds > G_admin_parse_time( g_adminMaxBan.string ) &&
- !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
- {
- seconds = G_admin_parse_time( g_adminMaxBan.string );
- ADMP( va( "^3!ban: ^7ban length limited to %s for your admin level\n",
- g_adminMaxBan.string ) );
- }
- }
-
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- {
- // skip players in the namelog who have already been banned
- if( g_admin_namelog[ i ]->banned )
- continue;
-
- // skip disconnected players when banning on slot number
- if( g_admin_namelog[ i ]->slot == -1 )
- continue;
-
- if( !Q_stricmp( va( "%d", g_admin_namelog[ i ]->slot ), s2 ) )
- {
- logmatches = 1;
- logmatch = i;
- exactmatch = qtrue;
- break;
- }
- }
-
- for( i = 0;
- !exactmatch && i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ];
- i++ )
- {
- // skip players in the namelog who have already been banned
- if( g_admin_namelog[ i ]->banned )
- continue;
-
- if( !Q_stricmp( g_admin_namelog[ i ]->ip, s2 ) )
- {
- logmatches = 1;
- logmatch = i;
- exactmatch = qtrue;
- break;
- }
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES
- && g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
- {
- G_SanitiseString(g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
- if( strstr( n2, s2 ) )
- {
- if( logmatch != i )
- logmatches++;
- logmatch = i;
- }
- }
- }
-
- if( !logmatches )
- {
- ADMP( "^3!ban: ^7no player found by that name, IP, or slot number\n" );
- return qfalse;
- }
- else if( logmatches > 1 )
- {
- ADMBP_begin();
- ADMBP( "^3!ban: ^7multiple recent clients match name, use IP or slot#:\n" );
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- {
- for( j = 0; j < 8; j++ )
- guid_stub[ j ] = g_admin_namelog[ i ]->guid[ j + 24 ];
- guid_stub[ j ] = '\0';
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES
- && g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
- {
- G_SanitiseString(g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
- if( strstr( n2, s2 ) )
- {
- if( g_admin_namelog[ i ]->slot > -1 )
- ADMBP( "^3" );
- ADMBP( va( "%-2s (*%s) %15s ^7'%s^7'\n",
- (g_admin_namelog[ i ]->slot > -1) ?
- va( "%d", g_admin_namelog[ i ]->slot ) : "-",
- guid_stub,
- g_admin_namelog[ i ]->ip,
- g_admin_namelog[ i ]->name[ j ] ) );
- }
- }
- }
- ADMBP_end();
+ ADMP( "^3setivo: ^7the argument must be either s, a or h\n" );
return qfalse;
}
-
- G_admin_duration( ( seconds ) ? seconds : -1,
- duration, sizeof( duration ) );
- if( ent && !admin_higher_guid( ent->client->pers.guid,
- g_admin_namelog[ logmatch ]->guid ) )
+ spot = G_Find( NULL, FOFS( classname ), cn );
+ if( !spot )
{
-
- ADMP( "^3!ban: ^7sorry, but your intended victim has a higher admin"
- " level than you\n" );
- return qfalse;
+ spot = G_Spawn();
+ spot->classname = (char *)cn;
}
+ spot->count = 1;
- admin_create_ban( ent,
- g_admin_namelog[ logmatch ]->name[ 0 ],
- g_admin_namelog[ logmatch ]->guid,
- g_admin_namelog[ logmatch ]->ip,
- seconds, reason );
-
- g_admin_namelog[ logmatch ]->banned = qtrue;
+ BG_GetClientViewOrigin( &ent->client->ps, spot->r.currentOrigin );
+ VectorCopy( ent->client->ps.viewangles, spot->r.currentAngles );
- if( !g_admin.string[ 0 ] )
- ADMP( "^3!ban: ^7WARNING g_admin not set, not saving ban to a file\n" );
- else
- admin_writeconfig();
-
- if( g_admin_namelog[ logmatch ]->slot == -1 )
- {
- // client is already disconnected so stop here
- AP( va( "print \"^3!ban:^7 %s^7 has been banned by %s^7 "
- "duration: %s, reason: %s\n\"",
- g_admin_namelog[ logmatch ]->name[ 0 ],
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
- duration,
- ( *reason ) ? reason : "banned by admin" ) );
- return qtrue;
- }
-
- trap_SendServerCommand( g_admin_namelog[ logmatch ]->slot,
- va( "disconnect \"You have been banned.\n"
- "admin:\n%s^7\nduration:\n%s\nreason:\n%s\n%s\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
- duration,
- ( *reason ) ? reason : "banned by admin", notice ) );
-
- trap_DropClient( g_admin_namelog[ logmatch ]->slot,
- va( "banned by %s^7, duration: %s, reason: %s",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
- duration,
- ( *reason ) ? reason : "banned by admin" ) );
+ ADMP( "^3setivo: ^7intermission view override positioned\n" );
return qtrue;
}
-// If true then don't let the player join a team, use the chat or run commands.
-qboolean G_admin_is_restricted(gentity_t *ent, qboolean sendMessage)
+qboolean G_admin_ban( gentity_t *ent )
{
- schachtmeisterJudgement_t *j = NULL;
- int i;
-
- // Never restrict admins or whitelisted players.
- if (G_admin_permission(ent, ADMF_NOAUTOBAHN) ||
- G_admin_permission(ent, ADMF_IMMUNITY))
- return qfalse;
-
- // Find the relevant namelog.
- // FIXME: this shouldn't require looping over *all* namelogs.
- for (i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[i]; i++) {
- if (g_admin_namelog[i]->slot == ent - g_entities) {
- j = &g_admin_namelog[i]->smj;
- break;
- }
- }
-
- // A missing namelog shouldn't happen.
- if (!j)
- return qfalse;
-
- // Restrictions concern only unrated players.
- if (j->ratingTime)
- return qfalse;
-
- // Don't wait forever, allow up to 15 seconds.
- if (level.time - j->queryTime >= 15000)
- return qfalse;
-
- if (sendMessage)
- trap_SendServerCommand(ent - g_entities, "print \"Please wait a moment before doing anything.\n\"");
-
- return qtrue;
-}
-
-static void admin_autobahn(gentity_t *ent, int rating)
-{
- // Allow per-GUID exceptions and never autoban admins.
- if (G_admin_permission(ent, ADMF_NOAUTOBAHN) ||
- G_admin_permission(ent, ADMF_IMMUNITY))
- return;
-
- // Don't do anything if the rating is clear.
- if (rating >= g_schachtmeisterClearThreshold.integer)
- return;
-
- // Ban only if the rating is low enough.
- if (rating > g_schachtmeisterAutobahnThreshold.integer) {
- G_AdminsPrintf("%s^7 (#%d) has rating %d\n",
- ent->client->pers.netname, ent - g_entities,
- rating);
- return;
- }
-
- G_LogAutobahn(ent, NULL, rating, qfalse);
-
- trap_SendServerCommand(ent - g_entities, va("disconnect \"%s\"\n",
- g_schachtmeisterAutobahnMessage.string));
- trap_DropClient(ent - g_entities, "dropped by the Autobahn");
-}
-
-void G_admin_IPA_judgement( const char *ipa, int rating, const char *comment )
-{
- int i;
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- {
- if( !strcmp( g_admin_namelog[ i ]->ip, ipa ) )
- {
- schachtmeisterJudgement_t *j = &g_admin_namelog[ i ]->smj;
-
- j->ratingTime = level.time;
- j->queryTime = 0;
- j->dispatchTime = 0;
-
- j->rating = rating;
-
- if( j->comment )
- G_Free( j->comment );
-
- if( comment )
- {
- j->comment = G_Alloc( strlen( comment ) + 1 );
- strcpy( j->comment, comment );
- }
- else
- j->comment = NULL;
-
- if( g_admin_namelog[ i ]->slot != -1 )
- admin_autobahn( g_entities + g_admin_namelog[ i ]->slot, j->rating );
- }
- }
-}
-
-qboolean G_admin_adjustban( gentity_t *ent, int skiparg )
-{
- int bnum;
- int length;
- int expires;
- int time = trap_RealTime( NULL );
- char duration[ 32 ] = {""};
- char *reason;
- char bs[ 5 ];
+ int seconds;
+ char search[ MAX_NAME_LENGTH ];
char secs[ MAX_TOKEN_CHARS ];
- char mode = '\0';
+ char *reason;
+ char duration[ MAX_DURATION_LENGTH ];
+ int i;
+ addr_t ip;
+ qboolean ipmatch = qfalse;
+ namelog_t *match = NULL;
+ qboolean cidr = qfalse;
- if( G_SayArgc() < 3 + skiparg )
+ if( trap_Argc() < 2 )
{
- ADMP( "^3!adjustban: ^7usage: !adjustban [ban#] [time] [reason]\n" );
+ ADMP( "^3ban: ^7usage: ban [name|slot|IP(/mask)] [duration] [reason]\n" );
return qfalse;
}
- G_SayArgv( 1 + skiparg, bs, sizeof( bs ) );
- bnum = atoi( bs );
- if( bnum < 1 || bnum > MAX_ADMIN_BANS || !g_admin_bans[ bnum - 1] )
+ trap_Argv( 1, search, sizeof( search ) );
+ trap_Argv( 2, secs, sizeof( secs ) );
+
+ seconds = G_admin_parse_time( secs );
+ if( seconds <= 0 )
{
- ADMP( "^3!adjustban: ^7invalid ban#\n" );
- return qfalse;
+ seconds = 0;
+ reason = ConcatArgs( 2 );
}
- if( g_admin_bans[ bnum - 1 ]->expires == 0 &&
- !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
+ else
{
- ADMP( "^3!adjustban: ^7you cannot modify permanent bans\n" );
- return qfalse;
+ reason = ConcatArgs( 3 );
}
- if( g_admin_bans[ bnum - 1 ]->bannerlevel > G_admin_level( ent ) )
+ if( !*reason && !G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
{
- ADMP( "^3!adjustban: ^7you cannot modify Bans made by admins higher than you\n" );
+ ADMP( "^3ban: ^7you must specify a reason\n" );
return qfalse;
}
- if( g_adminMaxBan.integer &&
- !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
- g_admin_bans[ bnum - 1 ]->expires - time > G_admin_parse_time( g_adminMaxBan.string ) )
+ if( !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
{
- ADMP( va( "^3!adjustban: ^7your admin level cannot modify bans longer than %s\n",
- g_adminMaxBan.string ) );
- return qfalse;
- }
- G_SayArgv( 2 + skiparg, secs, sizeof( secs ) );
- if( secs[ 0 ] == '+' || secs[ 0 ] == '-' )
- mode = secs[ 0 ];
- length = G_admin_parse_time( &secs[ mode ? 1 : 0 ] );
- if( length < 0 )
- skiparg--;
- else
- {
- if( length )
+ int maximum = MAX( 1, G_admin_parse_time( g_adminMaxBan.string ) );
+ if( seconds == 0 || seconds > maximum )
{
- if( g_admin_bans[ bnum - 1 ]->expires == 0 && mode )
- {
- ADMP( "^3!adjustban: ^7new duration must be explicit\n" );
- return qfalse;
- }
- if( mode == '+' )
- expires = g_admin_bans[ bnum - 1 ]->expires + length;
- else if( mode == '-' )
- expires = g_admin_bans[ bnum - 1 ]->expires - length;
- else
- expires = time + length;
- if( expires <= time )
- {
- ADMP( "^3!adjustban: ^7ban time must be positive\n" );
- return qfalse;
- }
- if( g_adminMaxBan.integer &&
- !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
- expires - time > G_admin_parse_time( g_adminMaxBan.string ) )
- {
- ADMP( va( "^3!adjustban: ^7ban length is limited to %s for your admin level\n",
- g_adminMaxBan.string ) );
- length = G_admin_parse_time( g_adminMaxBan.string );
- expires = time + length;
- }
+ ADMP( "^3ban: ^7you may not issue permanent bans\n" );
+ seconds = maximum;
}
- else if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
- expires = 0;
+ }
+
+ if( G_AddressParse( search, &ip ) )
+ {
+ int max = ip.type == IPv4 ? 32 : 128;
+ int min;
+
+ cidr = G_admin_permission( ent, ADMF_CAN_IP_BAN );
+ if( cidr )
+ min = ent ? max / 2 : 1;
else
+ min = max;
+
+ if( ip.mask < min || ip.mask > max )
{
- ADMP( "^3!adjustban: ^7ban time must be positive\n" );
+ ADMP( va( "^3ban: ^7invalid netmask (%d is not in the range %d-%d)\n",
+ ip.mask, min, max ) );
return qfalse;
}
+ ipmatch = qtrue;
- g_admin_bans[ bnum - 1 ]->expires = expires;
- G_admin_duration( ( expires ) ? expires - time : -1,
- duration, sizeof( duration ) );
- }
- reason = G_SayConcatArgs( 3 + skiparg );
- if( *reason )
- Q_strncpyz( g_admin_bans[ bnum - 1 ]->reason, reason,
- sizeof( g_admin_bans[ bnum - 1 ]->reason ) );
- AP( va( "print \"^3!adjustban: ^7ban #%d for %s^7 has been updated by %s^7 "
- "%s%s%s%s%s\n\"",
- bnum,
- g_admin_bans[ bnum - 1 ]->name,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
- ( length >= 0 ) ? "duration: " : "",
- duration,
- ( length >= 0 && *reason ) ? ", " : "",
- ( *reason ) ? "reason: " : "",
- reason ) );
- if( ent ) {
- Q_strncpyz( g_admin_bans[ bnum - 1 ]->banner, G_admin_get_adminname( ent ),
- sizeof( g_admin_bans[ bnum - 1 ]->banner ) );
- g_admin_bans[ bnum - 1 ]->bannerlevel = G_admin_level( ent );
- }
-
- if( g_admin.string[ 0 ] )
- admin_writeconfig();
- return qtrue;
-}
-
+ for( match = level.namelogs; match; match = match->next )
+ {
+ // skip players in the namelog who have already been banned
+ if( match->banned )
+ continue;
-qboolean G_admin_subnetban( gentity_t *ent, int skiparg )
-{
- int bnum;
- int mask;
- unsigned int IPRlow = 0, IPRhigh = 0;
- char cIPRlow[ 32 ], cIPRhigh[ 32 ];
- char bs[ 5 ];
- char strmask[ 5 ];
- char exl[2];
- int k, IP[5];
-
- if( G_SayArgc() < 3 + skiparg )
- {
- ADMP( "^3!subnetban: ^7usage: !subnetban [ban#] [mask]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, bs, sizeof( bs ) );
- bnum = atoi( bs );
- if( bnum < 1 || bnum > MAX_ADMIN_BANS || !g_admin_bans[ bnum - 1] )
- {
- ADMP( "^3!subnetban: ^7invalid ban#\n" );
- return qfalse;
- }
- if( g_admin_bans[ bnum - 1 ]->bannerlevel > G_admin_level( ent ) )
- {
- ADMP( "^3!subnetban: ^7you cannot subnetban Bans on bans made by admins higher than you\n" );
- return qfalse;
- }
+ for( i = 0; i < MAX_NAMELOG_ADDRS && match->ip[ i ].str[ 0 ]; i++ )
+ {
+ if( G_AddressCompare( &ip, &match->ip[ i ] ) )
+ break;
+ }
+ if( i < MAX_NAMELOG_ADDRS && match->ip[ i ].str[ 0 ] )
+ break;
+ }
- G_SayArgv( 2 + skiparg, strmask, sizeof( strmask ) );
- mask = atoi( strmask );
-
- if( mask >= 0 && mask <= 32)
- {
- G_SayArgv( 3 + skiparg, exl, sizeof( exl ) );
- if( mask >= 0 && mask < 16 )
+ if( !match )
{
- if( ent )
+ if( cidr )
{
- ADMP( "^3!subnetban: ^7Only console may ban such a large network. Regular admins may only ban >=16.\n" );
- return qfalse;
+ ADMP( "^3ban: ^7no player found by that IP address; banning anyway\n" );
}
- if( strcmp(exl, "!") )
+ else
{
- ADMP( "^3!subnetban: ^1WARNING:^7 you are about to ban a large network, use !subnetban [ban] [mask] ! to force^7\n" );
+ ADMP( "^3ban: ^7no player found by that IP address\n" );
return qfalse;
}
}
-
- memset( IP, 0, sizeof( IP ) );
- sscanf(g_admin_bans[ bnum - 1 ]->ip, "%d.%d.%d.%d/%d", &IP[4], &IP[3], &IP[2], &IP[1], &IP[0]);
- for(k = 4; k >= 1; k--)
- {
- if( IP[k] )
- IPRlow |= IP[k] << 8*(k-1);
- }
- IPRhigh = IPRlow;
- if( mask == 32 )
- {
- Q_strncpyz(
- g_admin_bans[ bnum - 1 ]->ip,
- va("%i.%i.%i.%i", IP[4], IP[3], IP[2], IP[1]),
- sizeof( g_admin_bans[ bnum - 1 ]->ip )
- );
- }
- else
- {
- Q_strncpyz(
- g_admin_bans[ bnum - 1 ]->ip,
- va("%i.%i.%i.%i/%i", IP[4], IP[3], IP[2], IP[1], mask ),
- sizeof( g_admin_bans[ bnum - 1 ]->ip )
- );
- IPRlow &= ~((1 << (32-mask)) - 1);
- IPRhigh |= ((1 << (32-mask)) - 1);
- }
}
- else
+ else if( !( match = G_NamelogFromString( ent, search ) ) || match->banned )
{
- ADMP( "^3!subnetban: ^7mask is out of range, please use 0-32 inclusive\n" );
+ ADMP( "^3ban: ^7no match\n" );
return qfalse;
}
- if( mask > 0 )
- {
- Q_strncpyz(
- cIPRlow,
- va("%u.%u.%u.%u", (IPRlow & (255 << 24)) >> 24, (IPRlow & (255 << 16)) >> 16, (IPRlow & (255 << 8)) >> 8, IPRlow & 255),
- sizeof( cIPRlow )
- );
- Q_strncpyz(
- cIPRhigh,
- va("%u.%u.%u.%u", (IPRhigh & (255 << 24)) >> 24, (IPRhigh & (255 << 16)) >> 16, (IPRhigh & (255 << 8)) >> 8, IPRhigh & 255),
- sizeof( cIPRhigh )
- );
- }
- else
- {
- Q_strncpyz( cIPRlow, "0.0.0.0", sizeof( cIPRlow ) );
- Q_strncpyz( cIPRhigh, "255.255.255.255", sizeof( cIPRhigh ) );
-
- }
-
- AP( va( "print \"^3!subnetban: ^7ban #%d for %s^7 has been updated by %s^7 "
- "%s (%s - %s)\n\"",
- bnum,
- g_admin_bans[ bnum - 1 ]->name,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
- g_admin_bans[ bnum - 1 ]->ip,
- cIPRlow,
- cIPRhigh) );
- if( ent )
- Q_strncpyz( g_admin_bans[ bnum - 1 ]->banner, G_admin_get_adminname( ent ),
- sizeof( g_admin_bans[ bnum - 1 ]->banner ) );
- if( g_admin.string[ 0 ] )
- admin_writeconfig();
- return qtrue;
-}
-
-qboolean G_admin_suspendban( gentity_t *ent, int skiparg )
-{
- int bnum;
- int length;
- int timenow = 0;
- int expires = 0;
- char *arg;
- char bs[ 5 ];
- char duration[ 32 ];
- qtime_t qt;
- if( G_SayArgc() < 3 + skiparg )
- {
- ADMP( "^3!suspendban: ^7usage: !suspendban [ban #] [length]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, bs, sizeof( bs ) );
- bnum = atoi( bs );
- if( bnum < 1 || !g_admin_bans[ bnum - 1] )
+ if( ent && match && !admin_higher_guid( ent->client->pers.guid, match->guid ) )
{
- ADMP( "^3!suspendban: ^7invalid ban #\n" );
+
+ ADMP( "^3ban: ^7sorry, but your intended victim has a higher admin"
+ " level than you\n" );
return qfalse;
}
- if( g_admin_bans[ bnum - 1 ]->bannerlevel > G_admin_level( ent ) )
+ if( match && match->slot > -1 && level.clients[ match->slot ].pers.localClient )
{
- ADMP( "^3!suspendban: ^7you cannot suspend Bans made by admins higher than you\n" );
+ ADMP( "^3ban: ^7disconnecting the host would end the game\n" );
return qfalse;
}
- arg = G_SayConcatArgs( 2 + skiparg );
- timenow = trap_RealTime( &qt );
- length = G_admin_parse_time( arg );
-
- if( length < 0 )
- {
- ADMP( "^3!suspendban: ^7invalid length\n" );
- return qfalse;
- }
- if( length > MAX_ADMIN_BANSUSPEND_DAYS * 24 * 60 * 60 )
- {
- length = MAX_ADMIN_BANSUSPEND_DAYS * 24 * 60 * 60;
- ADMP( va( "^3!suspendban: ^7maximum ban suspension is %d days\n",
- MAX_ADMIN_BANSUSPEND_DAYS ) );
- } else if( g_admin_bans[ bnum - 1 ]->expires > 0 && length + timenow > g_admin_bans[ bnum - 1 ]->expires ) {
- length = g_admin_bans[ bnum - 1 ]->expires - timenow;
- G_admin_duration( length , duration, sizeof( duration ) );
- ADMP( va( "^3!suspendban: ^7Suspension Duration trimmed to Ban duration: %s\n",
- duration ) );
- }
+ G_admin_duration( ( seconds ) ? seconds : -1,
+ duration, sizeof( duration ) );
- if ( length > 0 )
- {
- expires = timenow + length;
- }
- if( g_admin_bans[ bnum - 1 ]->suspend == expires )
- {
- ADMP( "^3!suspendban: ^7no change\n" );
- return qfalse;
- }
+ AP( va( "print \"^3ban:^7 %s^7 has been banned by %s^7 "
+ "duration: %s, reason: %s\n\"",
+ match ? match->name[ match->nameOffset ] : "an IP address",
+ ( ent ) ? ent->client->pers.netname : "console",
+ duration,
+ ( *reason ) ? reason : "banned by admin" ) );
- g_admin_bans[ bnum - 1 ]->suspend = expires;
- if ( length > 0 )
+ admin_log( va( "%d (%s) \"%s" S_COLOR_WHITE "\": \"%s" S_COLOR_WHITE "\"",
+ seconds,
+ match ? match->guid : "",
+ match ? match->name[ match->nameOffset ] : "IP ban",
+ reason ) );
+ if( ipmatch )
{
- G_admin_duration( length , duration, sizeof( duration ) );
- AP( va( "print \"^3!suspendban: ^7ban #%d suspended for %s\n\"",
- bnum, duration ) );
+ if( match )
+ {
+ admin_create_ban( ent,
+ match->slot == -1 ?
+ match->name[ match->nameOffset ] :
+ level.clients[ match->slot ].pers.netname,
+ match->guidless ? "" : match->guid,
+ &ip,
+ seconds, reason );
+ }
+ else
+ {
+ admin_create_ban( ent, "IP ban", "", &ip, seconds, reason );
+ }
+ admin_log( va( "[%s]", ip.str ) );
}
else
{
- AP( va( "print \"^3!suspendban: ^7ban #%d suspension removed\n\"",
- bnum ) );
+ // ban all IP addresses used by this player
+ for( i = 0; i < MAX_NAMELOG_ADDRS && match->ip[ i ].str[ 0 ]; i++ )
+ {
+ admin_create_ban( ent,
+ match->slot == -1 ?
+ match->name[ match->nameOffset ] :
+ level.clients[ match->slot ].pers.netname,
+ match->guidless ? "" : match->guid,
+ &match->ip[ i ],
+ seconds, reason );
+ admin_log( va( "[%s]", match->ip[ i ].str ) );
+ }
}
+ if( match )
+ match->banned = qtrue;
+
if( !g_admin.string[ 0 ] )
- ADMP( "^3!adjustban: ^7WARNING g_admin not set, not saving ban to a file\n" );
+ ADMP( "^3ban: ^7WARNING g_admin not set, not saving ban to a file\n" );
else
admin_writeconfig();
+
return qtrue;
}
-qboolean G_admin_unban( gentity_t *ent, int skiparg )
+qboolean G_admin_unban( gentity_t *ent )
{
int bnum;
+ int time = trap_RealTime( NULL );
char bs[ 5 ];
- int t;
+ int i;
+ g_admin_ban_t *ban;
- t = trap_RealTime( NULL );
- if( G_SayArgc() < 2 + skiparg )
+ if( trap_Argc() < 2 )
{
- ADMP( "^3!unban: ^7usage: !unban [ban#]\n" );
+ ADMP( "^3unban: ^7usage: unban [ban#]\n" );
return qfalse;
}
- G_SayArgv( 1 + skiparg, bs, sizeof( bs ) );
+ trap_Argv( 1, bs, sizeof( bs ) );
bnum = atoi( bs );
- if( bnum < 1 || bnum > MAX_ADMIN_BANS || !g_admin_bans[ bnum - 1 ] )
- {
- ADMP( "^3!unban: ^7invalid ban#\n" );
- return qfalse;
- }
- if( g_admin_bans[ bnum - 1 ]->expires == 0 &&
- !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
+ for( ban = g_admin_bans, i = 1; ban && i < bnum; ban = ban->next, i++ )
+ ;
+ if( i != bnum || !ban )
{
- ADMP( "^3!unban: ^7you cannot remove permanent bans\n" );
+ ADMP( "^3unban: ^7invalid ban#\n" );
return qfalse;
}
- if( g_admin_bans[ bnum - 1 ]->bannerlevel > G_admin_level( ent ) )
+ if( ban->expires > 0 && ban->expires - time <= 0 )
{
- ADMP( "^3!unban: ^7you cannot Remove Bans made by admins higher than you\n" );
+ ADMP( "^3unban: ^7ban already expired\n" );
return qfalse;
}
- if( g_adminMaxBan.integer &&
- !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
- g_admin_bans[ bnum - 1 ]->expires - t > G_admin_parse_time( g_adminMaxBan.string ) )
+ if( !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
+ ( ban->expires == 0 || ( ban->expires - time > MAX( 1,
+ G_admin_parse_time( g_adminMaxBan.string ) ) ) ) )
{
- ADMP( va( "^3!unban: ^7your admin level cannot remove bans longer than %s\n",
- g_adminMaxBan.string ) );
+ ADMP( "^3unban: ^7you cannot remove permanent bans\n" );
return qfalse;
}
- g_admin_bans[ bnum -1 ]->expires = t;
- AP( va( "print \"^3!unban: ^7ban #%d for %s^7 has been removed by %s\n\"",
+ admin_log( va( "%d (%s) \"%s" S_COLOR_WHITE "\": \"%s" S_COLOR_WHITE "\": [%s]",
+ ban->expires ? ban->expires - time : 0, ban->guid, ban->name, ban->reason,
+ ban->ip.str ) );
+ AP( va( "print \"^3unban: ^7ban #%d for %s^7 has been removed by %s\n\"",
bnum,
- g_admin_bans[ bnum - 1 ]->name,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- if( g_admin.string[ 0 ] )
- admin_writeconfig();
+ ban->name,
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ ban->expires = time;
+ admin_writeconfig();
return qtrue;
}
-qboolean G_admin_putteam( gentity_t *ent, int skiparg )
+qboolean G_admin_addlayout( gentity_t *ent )
{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], team[ 7 ], err[ MAX_STRING_CHARS ];
- gentity_t *vic;
- pTeam_t teamnum = PTE_NONE;
- char teamdesc[ 32 ] = {"spectators"};
- char secs[ 7 ];
- int seconds = 0;
- qboolean useDuration = qfalse;
-
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- G_SayArgv( 2 + skiparg, team, sizeof( team ) );
- if( G_SayArgc() < 3 + skiparg )
- {
- ADMP( "^3!putteam: ^7usage: !putteam [name] [h|a|s] (duration)\n" );
- return qfalse;
- }
-
- if( G_ClientNumbersFromString( name, pids ) != 1 )
- {
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!putteam: ^7%s\n", err ) );
- return qfalse;
- }
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
- {
- ADMP( "^3!putteam: ^7sorry, but your intended victim has a higher "
- " admin level than you\n" );
- return qfalse;
- }
- vic = &g_entities[ pids[ 0 ] ];
+ char layout[ MAX_QPATH ];
- if ( vic->client->sess.invisible == qtrue )
+ if( trap_Argc( ) != 2 )
{
- ADMP( "^3!putteam: ^7invisible players cannot join a team\n" );
+ ADMP( "^3addlayout: ^7usage: addlayout <layoutelements>\n" );
return qfalse;
}
- switch( team[ 0 ] )
- {
- case 'a':
- teamnum = PTE_ALIENS;
- Q_strncpyz( teamdesc, "aliens", sizeof( teamdesc ) );
- break;
- case 'h':
- teamnum = PTE_HUMANS;
- Q_strncpyz( teamdesc, "humans", sizeof( teamdesc ) );
- break;
- case 's':
- teamnum = PTE_NONE;
- break;
- default:
- ADMP( va( "^3!putteam: ^7unknown team %c\n", team[ 0 ] ) );
- return qfalse;
- }
- //duration code
- if( G_SayArgc() > 3 + skiparg ) {
- //can only lock players in spectator
- if ( teamnum != PTE_NONE )
- {
- ADMP( "^3!putteam: ^7You can only lock a player into the spectators team\n" );
- return qfalse;
- }
- G_SayArgv( 3 + skiparg, secs, sizeof( secs ) );
- seconds = G_admin_parse_time( secs );
- useDuration = qtrue;
- }
+ trap_Argv( 1, layout, sizeof( layout ) );
- if( vic->client->pers.teamSelection == teamnum && teamnum != PTE_NONE )
- {
- ADMP( va( "^3!putteam: ^7%s ^7is already on the %s team\n", vic->client->pers.netname, teamdesc ) );
- return qfalse;
- }
+ G_LayoutLoad( layout );
- if( useDuration == qtrue && seconds > 0 ) {
- vic->client->pers.specExpires = level.time + ( seconds * 1000 );
- }
- G_ChangeTeam( vic, teamnum );
-
- AP( va( "print \"^3!putteam: ^7%s^7 put %s^7 on to the %s team%s\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
- vic->client->pers.netname, teamdesc,
- ( seconds ) ? va( " for %i seconds", seconds ) : "" ) );
+ AP( va( "print \"^3addlayout: ^7some layout elements have been placed by %s\n\"",
+ ent ? ent->client->pers.netname : "console" ) );
return qtrue;
}
-qboolean G_admin_seen(gentity_t *ent, int skiparg )
+qboolean G_admin_adjustban( gentity_t *ent )
{
- char name[ MAX_NAME_LENGTH ];
- char search[ MAX_NAME_LENGTH ];
- char sduration[ 32 ];
- qboolean numeric = qtrue;
- int i, j;
- int id = -1;
- int count = 0;
- int t;
- qtime_t qt;
- gentity_t *vic;
- qboolean ison;
+ int bnum;
+ int length, maximum;
+ int expires;
+ int time = trap_RealTime( NULL );
+ char duration[ MAX_DURATION_LENGTH ] = {""};
+ char *reason;
+ char bs[ 5 ];
+ char secs[ MAX_TOKEN_CHARS ];
+ char mode = '\0';
+ g_admin_ban_t *ban;
+ int mask = 0;
+ int i;
+ int skiparg = 0;
- if( G_SayArgc() < 2 + skiparg )
+ if( trap_Argc() < 3 )
{
- ADMP( "^3!seen: ^7usage: !seen [name|admin#]\n" );
+ ADMP( "^3adjustban: ^7usage: adjustban [ban#] [/mask] [duration] [reason]"
+ "\n" );
return qfalse;
}
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- G_SanitiseString( name, search, sizeof( search ) );
- for( i = 0; i < sizeof( search ) && search[ i ] ; i++ )
+ trap_Argv( 1, bs, sizeof( bs ) );
+ bnum = atoi( bs );
+ for( ban = g_admin_bans, i = 1; ban && i < bnum; ban = ban->next, i++ );
+ if( i != bnum || !ban )
{
- if( search[ i ] < '0' || search[ i ] > '9' )
- {
- numeric = qfalse;
- break;
- }
+ ADMP( "^3adjustban: ^7invalid ban#\n" );
+ return qfalse;
}
-
- if( numeric )
+ maximum = MAX( 1, G_admin_parse_time( g_adminMaxBan.string ) );
+ if( !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
+ ( ban->expires == 0 || ban->expires - time > maximum ) )
{
- id = atoi( name );
- search[ 0 ] = '\0';
+ ADMP( "^3adjustban: ^7you cannot modify permanent bans\n" );
+ return qfalse;
}
-
- ADMBP_begin();
- t = trap_RealTime( &qt );
-
- for( i = 0; i < level.maxclients && count < 10; i ++ )
+ trap_Argv( 2, secs, sizeof( secs ) );
+ if( secs[ 0 ] == '/' )
{
- vic = &g_entities[ i ];
+ int max = ban->ip.type == IPv6 ? 128 : 32;
+ int min;
- if( !vic->client || vic->client->pers.connected != CON_CONNECTED )
- continue;
-
- G_SanitiseString( vic->client->pers.netname, name, sizeof( name ) );
+ if( G_admin_permission( ent, ADMF_CAN_IP_BAN ) )
+ min = ent ? max / 2 : 1;
+ else
+ min = max;
- if( i == id || (search[ 0 ] && strstr( name, search ) ) )
+ mask = atoi( secs + 1 );
+ if( mask < min || mask > max )
{
- if ( vic->client->sess.invisible == qfalse )
- {
- ADMBP( va( "^3%4d ^7%s^7 is currently playing\n", i, vic->client->pers.netname ) );
- count++;
- }
+ ADMP( va( "^3adjustban: ^7invalid netmask (%d is not in range %d-%d)\n",
+ mask, min, max ) );
+ return qfalse;
}
+ trap_Argv( 3 + skiparg++, secs, sizeof( secs ) );
}
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] && count < 10; i++ )
+ if( secs[ 0 ] == '+' || secs[ 0 ] == '-' )
+ mode = secs[ 0 ];
+ length = G_admin_parse_time( &secs[ mode ? 1 : 0 ] );
+ if( length < 0 )
+ skiparg--;
+ else
{
- G_SanitiseString( g_admin_admins[ i ]->name, name, sizeof( name ) );
- if( i + MAX_CLIENTS == id || (search[ 0 ] && strstr( name, search ) ) )
+ if( length )
{
- ison = qfalse;
- for( j = 0; j < level.maxclients; j++ )
+ if( ban->expires == 0 && mode )
{
- vic = &g_entities[ j ];
- if( !vic->client || vic->client->pers.connected != CON_CONNECTED )
- continue;
- G_SanitiseString( vic->client->pers.netname, name, sizeof( name ) );
- if( !Q_stricmp( vic->client->pers.guid, g_admin_admins[ i ]->guid )
- && strstr( name, search ) )
- {
- if ( vic->client->sess.invisible == qfalse )
- {
- ison = qtrue;
- break;
- }
- }
- }
-
- if( ison )
- {
- if( id == -1 )
- continue;
- ADMBP( va( "^3%4d ^7%s^7 is currently playing\n",
- i + MAX_CLIENTS, g_admin_admins[ i ]->name ) );
+ ADMP( "^3adjustban: ^7new duration must be explicit\n" );
+ return qfalse;
}
+ if( mode == '+' )
+ expires = ban->expires + length;
+ else if( mode == '-' )
+ expires = ban->expires - length;
else
+ expires = time + length;
+ if( expires <= time )
{
- G_admin_duration( t - g_admin_admins[ i ]->seen,
- sduration, sizeof( sduration ) );
- ADMBP( va( "%4d %s^7 last seen %s%s\n",
- i + MAX_CLIENTS, g_admin_admins[ i ]->name ,
- ( g_admin_admins[ i ]->seen ) ? sduration : "",
- ( g_admin_admins[ i ]->seen ) ? " ago" : "time is unknown" ) );
+ ADMP( "^3adjustban: ^7ban duration must be positive\n" );
+ return qfalse;
}
- count++;
- }
- }
-
- if( search[ 0 ] )
- ADMBP( va( "^3!seen:^7 found %d player%s matching '%s'\n",
- count, (count == 1) ? "" : "s", search ) );
- else if ( !count )
- ADMBP( "^3!seen:^7 no one connectd by that slot number\n" );
-
- ADMBP_end();
- return qtrue;
-}
-
-void G_admin_seen_update( char *guid )
-{
- int i;
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] ; i++ )
- {
- if( !Q_stricmp( g_admin_admins[ i ]->guid, guid ) )
- {
- qtime_t qt;
-
- g_admin_admins[ i ]->seen = trap_RealTime( &qt );
- return;
}
- }
-}
-
-void G_admin_adminlog_cleanup( void )
-{
- int i;
-
- for( i = 0; i < MAX_ADMIN_ADMINLOGS && g_admin_adminlog[ i ]; i++ )
- {
- G_Free( g_admin_adminlog[ i ] );
- g_admin_adminlog[ i ] = NULL;
- }
-
- admin_adminlog_index = 0;
-}
-
-void G_admin_adminlog_log( gentity_t *ent, char *command, char *args, int skiparg, qboolean success )
-{
- g_admin_adminlog_t *adminlog;
- int previous;
- int count = 1;
- int i;
-
- if( !command )
- return;
-
- if( !Q_stricmp( command, "adminlog" ) ||
- !Q_stricmp( command, "admintest" ) ||
- !Q_stricmp( command, "help" ) ||
- !Q_stricmp( command, "info" ) ||
- !Q_stricmp( command, "listadmins" ) ||
- !Q_stricmp( command, "listplayers" ) ||
- !Q_stricmp( command, "namelog" ) ||
- !Q_stricmp( command, "showbans" ) ||
- !Q_stricmp( command, "seen" ) ||
- !Q_stricmp( command, "time" ) )
- return;
-
- previous = admin_adminlog_index - 1;
- if( previous < 0 )
- previous = MAX_ADMIN_ADMINLOGS - 1;
-
- if( g_admin_adminlog[ previous ] )
- count = g_admin_adminlog[ previous ]->id + 1;
-
- if( g_admin_adminlog[ admin_adminlog_index ] )
- adminlog = g_admin_adminlog[ admin_adminlog_index ];
- else
- adminlog = G_Alloc( sizeof( g_admin_adminlog_t ) );
-
- memset( adminlog, 0, sizeof( *adminlog ) );
- adminlog->id = count;
- adminlog->time = level.time - level.startTime;
- adminlog->success = success;
- Q_strncpyz( adminlog->command, command, sizeof( adminlog->command ) );
-
- if ( args )
- Q_strncpyz( adminlog->args, args, sizeof( adminlog->args ) );
- else
- Q_strncpyz( adminlog->args, G_SayConcatArgs( 1 + skiparg ), sizeof( adminlog->args ) );
-
- if( ent )
- {
- qboolean found = qfalse;
- // real admin name
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ else
+ length = expires = 0;
+ if( !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
+ ( length == 0 || length > maximum ) )
{
- if( !Q_stricmp( g_admin_admins[ i ]->guid, ent->client->pers.guid ) )
- {
- Q_strncpyz( adminlog->name, g_admin_admins[ i ]->name, sizeof( adminlog->name ) );
- found = qtrue;
- break;
- }
+ ADMP( "^3adjustban: ^7you may not issue permanent bans\n" );
+ expires = time + maximum;
}
- if( !found )
- Q_strncpyz( adminlog->name, ent->client->pers.netname, sizeof( adminlog->name ) );
- adminlog->level = ent->client->pers.adminLevel;
+ ban->expires = expires;
+ G_admin_duration( ( expires ) ? expires - time : -1, duration,
+ sizeof( duration ) );
}
- else
+ if( mask )
{
- Q_strncpyz( adminlog->name, "console", sizeof( adminlog->name ) );
- adminlog->level = 10000;
+ char *p = strchr( ban->ip.str, '/' );
+ if( !p )
+ p = ban->ip.str + strlen( ban->ip.str );
+ if( mask == ( ban->ip.type == IPv6 ? 128 : 32 ) )
+ *p = '\0';
+ else
+ Com_sprintf( p, sizeof( ban->ip.str ) - ( p - ban->ip.str ), "/%d", mask );
+ ban->ip.mask = mask;
}
-
- g_admin_adminlog[ admin_adminlog_index ] = adminlog;
- admin_adminlog_index++;
- if( admin_adminlog_index >= MAX_ADMIN_ADMINLOGS )
- admin_adminlog_index = 0;
+ reason = ConcatArgs( 3 + skiparg );
+ if( *reason )
+ Q_strncpyz( ban->reason, reason, sizeof( ban->reason ) );
+ admin_log( va( "%d (%s) \"%s" S_COLOR_WHITE "\": \"%s" S_COLOR_WHITE "\": [%s]",
+ ban->expires ? ban->expires - time : 0, ban->guid, ban->name, ban->reason,
+ ban->ip.str ) );
+ AP( va( "print \"^3adjustban: ^7ban #%d for %s^7 has been updated by %s^7 "
+ "%s%s%s%s%s%s\n\"",
+ bnum,
+ ban->name,
+ ( ent ) ? ent->client->pers.netname : "console",
+ ( mask ) ?
+ va( "netmask: /%d%s", mask,
+ ( length >= 0 || *reason ) ? ", " : "" ) : "",
+ ( length >= 0 ) ? "duration: " : "",
+ duration,
+ ( length >= 0 && *reason ) ? ", " : "",
+ ( *reason ) ? "reason: " : "",
+ reason ) );
+ if( ent )
+ Q_strncpyz( ban->banner, ent->client->pers.netname, sizeof( ban->banner ) );
+ admin_writeconfig();
+ return qtrue;
}
-qboolean G_admin_adminlog( gentity_t *ent, int skiparg )
+qboolean G_admin_putteam( gentity_t *ent )
{
- g_admin_adminlog_t *results[ 10 ];
- int result_index = 0;
- char *search_cmd = NULL;
- char *search_name = NULL;
- int index;
- int skip = 0;
- int skipped = 0;
- int checked = 0;
- char n1[ MAX_NAME_LENGTH ];
- char fmt_name[ 16 ];
- char argbuf[ 32 ];
- int name_length = 12;
- int max_id = 0;
- int i;
- qboolean match;
-
- memset( results, 0, sizeof( results ) );
-
- index = admin_adminlog_index;
- for( i = 0; i < 10; i++ )
- {
- int prev;
-
- prev = index - 1;
- if( prev < 0 )
- prev = MAX_ADMIN_ADMINLOGS - 1;
- if( !g_admin_adminlog[ prev ] )
- break;
- if( g_admin_adminlog[ prev ]->id > max_id )
- max_id = g_admin_adminlog[ prev ]->id;
- index = prev;
- }
-
- if( G_SayArgc() > 1 + skiparg )
- {
- G_SayArgv( 1 + skiparg, argbuf, sizeof( argbuf ) );
- if( ( *argbuf >= '0' && *argbuf <= '9' ) || *argbuf == '-' )
- {
- int id;
-
- id = atoi( argbuf );
- if( id < 0 )
- id += ( max_id - 9 );
- else if( id <= max_id - MAX_ADMIN_ADMINLOGS )
- id = max_id - MAX_ADMIN_ADMINLOGS + 1;
-
- if( id + 9 >= max_id )
- id = max_id - 9;
- if( id < 1 )
- id = 1;
- for( i = 0; i < MAX_ADMIN_ADMINLOGS; i++ )
- {
- if( g_admin_adminlog[i] && g_admin_adminlog[ i ]->id == id )
- {
- index = i;
- break;
- }
- }
- }
- else if ( *argbuf == '!' )
- {
- search_cmd = argbuf + 1;
- }
- else
- {
- search_name = argbuf;
- }
-
- if( G_SayArgc() > 2 + skiparg && ( search_cmd || search_name ) )
- {
- char skipbuf[ 4 ];
- G_SayArgv( 2 + skiparg, skipbuf, sizeof( skipbuf ) );
- skip = atoi( skipbuf );
- }
- }
-
- if( search_cmd || search_name )
- {
- g_admin_adminlog_t *result_swap[ 10 ];
-
- memset( result_swap, 0, sizeof( result_swap ) );
-
- index = admin_adminlog_index - 1;
- if( index < 0 )
- index = MAX_ADMIN_ADMINLOGS - 1;
-
- while( g_admin_adminlog[ index ] &&
- checked < MAX_ADMIN_ADMINLOGS &&
- result_index < 10 )
- {
- match = qfalse;
- if( search_cmd )
- {
- if( !Q_stricmp( search_cmd, g_admin_adminlog[ index ]->command ) )
- match = qtrue;
- }
- if( search_name )
- {
- G_SanitiseString( g_admin_adminlog[ index ]->name, n1, sizeof( n1 ) );
- if( strstr( n1, search_name ) )
- match = qtrue;
- }
-
- if( match && skip > 0 )
- {
- match = qfalse;
- skip--;
- skipped++;
- }
- if( match )
- {
- result_swap[ result_index ] = g_admin_adminlog[ index ];
- result_index++;
- }
-
- checked++;
- index--;
- if( index < 0 )
- index = MAX_ADMIN_ADMINLOGS - 1;
- }
- // search runs backwards, turn it around
- for( i = 0; i < result_index; i++ )
- results[ i ] = result_swap[ result_index - i - 1 ];
- }
- else
- {
- while( g_admin_adminlog[ index ] && result_index < 10 )
- {
- results[ result_index ] = g_admin_adminlog[ index ];
- result_index++;
- index++;
- if( index >= MAX_ADMIN_ADMINLOGS )
- index = 0;
- }
- }
+ int pid;
+ char name[ MAX_NAME_LENGTH ], team[ sizeof( "spectators" ) ],
+ err[ MAX_STRING_CHARS ];
+ gentity_t *vic;
+ team_t teamnum = TEAM_NONE;
- for( i = 0; results[ i ] && i < 10; i++ )
+ trap_Argv( 1, name, sizeof( name ) );
+ trap_Argv( 2, team, sizeof( team ) );
+ if( trap_Argc() < 3 )
{
- int l;
-
- G_DecolorString( results[ i ]->name, n1 );
- l = strlen( n1 );
- if( l > name_length )
- name_length = l;
- }
- ADMBP_begin( );
- for( i = 0; results[ i ] && i < 10; i++ )
- {
- char levelbuf[ 8 ];
- int t;
-
- t = results[ i ]->time / 1000;
- G_DecolorString( results[ i ]->name, n1 );
- Com_sprintf( fmt_name, sizeof( fmt_name ), "%%%ds",
- ( name_length + strlen( results[ i ]->name ) - strlen( n1 ) ) );
- Com_sprintf( n1, sizeof( n1 ), fmt_name, results[ i ]->name );
- Com_sprintf( levelbuf, sizeof( levelbuf ), "%2d", results[ i ]->level );
- ADMBP( va( "%s%3d %3d:%02d %2s ^7%s^7 %s!%s ^7%s^7\n",
- ( results[ i ]->success ) ? "^7" : "^1",
- results[ i ]->id,
- t / 60, t % 60,
- ( results[ i ]->level ) < 10000 ? levelbuf : " -",
- n1,
- ( results[ i ]->success ) ? "^3" : "^1",
- results[ i ]->command,
- results[ i ]->args ) );
- }
- if( search_cmd || search_name )
- {
- ADMBP( va( "^3!adminlog:^7 Showing %d matches for '%s^7'.",
- result_index,
- argbuf ) );
- if( checked < MAX_ADMIN_ADMINLOGS && g_admin_adminlog[ checked ] )
- ADMBP( va( " run '!adminlog %s^7 %d' to see more",
- argbuf,
- skipped + result_index ) );
- ADMBP( "\n" );
- }
- else if ( results[ 0 ] )
- {
- ADMBP( va( "^3!adminlog:^7 Showing %d - %d of %d.\n",
- results[ 0 ]->id,
- results[ result_index - 1 ]->id,
- max_id ) );
- }
- else
- {
- ADMBP( "^3!adminlog:^7 log is empty.\n" );
+ ADMP( "^3putteam: ^7usage: putteam [name] [h|a|s]\n" );
+ return qfalse;
}
- ADMBP_end( );
- return qtrue;
-}
-
-qboolean G_admin_map( gentity_t *ent, int skiparg )
-{
- char map[ MAX_QPATH ];
- char layout[ MAX_QPATH ] = { "" };
-
- if( G_SayArgc( ) < 2 + skiparg )
+ if( ( pid = G_ClientNumberFromString( name, err, sizeof( err ) ) ) == -1 )
{
- ADMP( "^3!map: ^7usage: !map [map] (layout)\n" );
+ ADMP( va( "^3putteam: ^7%s", err ) );
return qfalse;
}
-
- G_SayArgv( skiparg + 1, map, sizeof( map ) );
-
- if( !trap_FS_FOpenFile( va( "maps/%s.bsp", map ), NULL, FS_READ ) )
+ vic = &g_entities[ pid ];
+ if( !admin_higher( ent, vic ) )
{
- ADMP( va( "^3!map: ^7invalid map name '%s'\n", map ) );
+ ADMP( "^3putteam: ^7sorry, but your intended victim has a higher "
+ " admin level than you\n" );
return qfalse;
}
-
- if( G_SayArgc( ) > 2 + skiparg )
+ teamnum = G_TeamFromString( team );
+ if( teamnum == NUM_TEAMS )
{
- G_SayArgv( skiparg + 2, layout, sizeof( layout ) );
- if( !Q_stricmp( layout, "*BUILTIN*" ) ||
- trap_FS_FOpenFile( va( "layouts/%s/%s.dat", map, layout ),
- NULL, FS_READ ) > 0 )
- {
- trap_Cvar_Set( "g_layouts", layout );
- }
- else
- {
- ADMP( va( "^3!map: ^7invalid layout name '%s'\n", layout ) );
- return qfalse;
- }
+ ADMP( va( "^3putteam: ^7unknown team %s\n", team ) );
+ return qfalse;
}
+ if( vic->client->pers.teamSelection == teamnum )
+ return qfalse;
+ admin_log( va( "%d (%s) \"%s" S_COLOR_WHITE "\"", pid, vic->client->pers.guid,
+ vic->client->pers.netname ) );
+ G_ChangeTeam( vic, teamnum );
- trap_SendConsoleCommand( EXEC_APPEND, va( "map %s", map ) );
- level.restarted = qtrue;
- AP( va( "print \"^3!map: ^7map '%s' started by %s^7 %s\n\"", map,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
- ( layout[ 0 ] ) ? va( "(forcing layout '%s')", layout ) : "" ) );
- G_admin_maplog_result( "M" );
+ AP( va( "print \"^3putteam: ^7%s^7 put %s^7 on to the %s team\n\"",
+ ( ent ) ? ent->client->pers.netname : "console",
+ vic->client->pers.netname, BG_TeamName( teamnum ) ) );
return qtrue;
}
-qboolean G_admin_devmap( gentity_t *ent, int skiparg )
+qboolean G_admin_changemap( gentity_t *ent )
{
char map[ MAX_QPATH ];
char layout[ MAX_QPATH ] = { "" };
- if( G_SayArgc( ) < 2 + skiparg )
+ if( trap_Argc( ) < 2 )
{
- ADMP( "^3!devmap: ^7usage: !devmap [map] (layout)\n" );
+ ADMP( "^3changemap: ^7usage: changemap [map] (layout)\n" );
return qfalse;
}
- G_SayArgv( skiparg + 1, map, sizeof( map ) );
+ trap_Argv( 1, map, sizeof( map ) );
- if( !trap_FS_FOpenFile( va( "maps/%s.bsp", map ), NULL, FS_READ ) )
+ if( !G_MapExists( map ) )
{
- ADMP( va( "^3!devmap: ^7invalid map name '%s'\n", map ) );
+ ADMP( va( "^3changemap: ^7invalid map name '%s'\n", map ) );
return qfalse;
}
- if( G_SayArgc( ) > 2 + skiparg )
+ if( trap_Argc( ) > 2 )
{
- G_SayArgv( skiparg + 2, layout, sizeof( layout ) );
- if( !Q_stricmp( layout, "*BUILTIN*" ) ||
- trap_FS_FOpenFile( va( "layouts/%s/%s.dat", map, layout ),
- NULL, FS_READ ) > 0 )
+ trap_Argv( 2, layout, sizeof( layout ) );
+ if( G_LayoutExists( map, layout ) )
{
- trap_Cvar_Set( "g_layouts", layout );
+ trap_Cvar_Set( "g_nextLayout", layout );
}
else
{
- ADMP( va( "^3!devmap: ^7invalid layout name '%s'\n", layout ) );
+ ADMP( va( "^3changemap: ^7invalid layout name '%s'\n", layout ) );
return qfalse;
}
}
+ admin_log( map );
+ admin_log( layout );
- trap_SendConsoleCommand( EXEC_APPEND, va( "devmap %s", map ) );
+ G_MapConfigs( map );
+ trap_SendConsoleCommand( EXEC_APPEND, va( "%smap \"%s\"\n",
+ ( g_cheats.integer ? "dev" : "" ), map ) );
level.restarted = qtrue;
- AP( va( "print \"^3!devmap: ^7map '%s' started by %s^7 with cheats %s\n\"", map,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
+ AP( va( "print \"^3changemap: ^7map '%s' started by %s^7 %s\n\"", map,
+ ( ent ) ? ent->client->pers.netname : "console",
( layout[ 0 ] ) ? va( "(forcing layout '%s')", layout ) : "" ) );
- G_admin_maplog_result( "D" );
return qtrue;
}
-void G_admin_maplog_update( void )
+qboolean G_admin_mute( gentity_t *ent )
{
- char map[ 64 ];
- char maplog[ MAX_CVAR_VALUE_STRING ];
- char *ptr;
- int count = 0;
-
- trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
-
- Q_strncpyz( maplog, g_adminMapLog.string, sizeof( maplog ) );
- ptr = maplog;
- while( *ptr && count < MAX_ADMIN_MAPLOG_LENGTH )
- {
- while( *ptr != ' ' && *ptr != '\0' ) ptr++;
-
- count++;
- if( count >= MAX_ADMIN_MAPLOG_LENGTH )
- {
- *ptr = '\0';
- }
-
- if( *ptr == ' ' ) ptr++;
- }
-
- trap_Cvar_Set( "g_adminMapLog", va( "%s%s%s",
- map,
- ( maplog[0] != '\0' ) ? " " : "",
- maplog ) );
-}
-
-void G_admin_maplog_result( char *flag )
-{
- static int lastTime = 0;
- char maplog[ MAX_CVAR_VALUE_STRING ];
- int t;
-
- if( !flag )
- return;
-
- // avoid race when called in same frame
- if( level.time == lastTime )
- return;
-
- lastTime = level.time;
-
- if( g_adminMapLog.string[ 0 ] &&
- g_adminMapLog.string[ 1 ] == ';' )
- {
- // only one result allowed
- return;
- }
-
- if ( level.surrenderTeam != PTE_NONE )
- {
- if( flag[ 0 ] == 'a' )
- {
- if( level.surrenderTeam == PTE_HUMANS )
- flag = "A";
- }
- else if( flag[ 0 ] == 'h' )
- {
- if( level.surrenderTeam == PTE_ALIENS )
- flag = "H";
- }
- }
-
- t = ( level.time - level.startTime ) / 1000;
- Q_strncpyz( maplog, g_adminMapLog.string, sizeof( maplog ) );
- trap_Cvar_Set( "g_adminMapLog", va( "%1s;%03d:%02d;%s",
- flag,
- t / 60, t % 60,
- maplog ) );
-}
-
-
-qboolean G_admin_maplog( gentity_t *ent, int skiparg )
-{
- char maplog[ MAX_CVAR_VALUE_STRING ];
- char *ptr;
- int count = 0;
-
- Q_strncpyz( maplog, g_adminMapLog.string, sizeof( maplog ) );
-
- ADMBP_begin( );
- ptr = maplog;
- while( *ptr != '\0' && count < MAX_ADMIN_MAPLOG_LENGTH + 1 )
- {
- char *end;
- const char *result = NULL;
- char *clock = NULL;
- char *colon;
-
- end = ptr;
- while( *end != ' ' && *end != '\0' ) end++;
- if( *end == ' ' )
- {
- *end = '\0';
- end++;
- }
-
- if( ptr[ 0 ] && ptr[ 1 ] == ';' )
- {
- switch( ptr[ 0 ] )
- {
- case 't':
- result = "^7tie";
- break;
- case 'a':
- result = "^1Alien win";
- break;
- case 'A':
- result = "^1Alien win ^7/ Humans admitted defeat";
- break;
- case 'h':
- result = "^4Human win";
- break;
- case 'H':
- result = "^4Human win ^7/ Aliens admitted defeat";
- break;
- case 'd':
- result = "^5draw vote";
- break;
- case 'N':
- result = "^6admin loaded next map";
- break;
- case 'r':
- result = "^2restart vote";
- break;
- case 'R':
- result = "^6admin restarted map";
- break;
- case 'm':
- result = "^2map vote";
- break;
- case 'M':
- result = "^6admin changed map";
- break;
- case 'D':
- result = "^6admin loaded devmap";
- break;
- default:
- result = "";
- break;
- }
- ptr += 2;
- colon = strchr( ptr, ';' );
- if ( colon )
- {
- clock = ptr;
- ptr = colon + 1;
- *colon = '\0';
-
- // right justification with -6%s doesnt work..
- if( clock[ 0 ] == '0' && clock[ 1 ] != ':' )
- {
- if( clock[ 1 ] == '0' && clock[ 2 ] != ':' )
- clock[ 1 ] = ' ';
- clock[ 0 ] = ' ';
- }
- }
- }
- else if( count == 0 )
- {
- result = "^3current map";
- clock = " -:--";
- }
-
- ADMBP( va( "%s%20s %-6s %s^7\n",
- ( count == 0 ) ? "^3" : "^7",
- ptr,
- ( clock ) ? clock : "",
- ( result ) ? result : "" ) );
-
- ptr = end;
- count++;
- }
- ADMBP_end( );
-
- return qtrue;
-}
-
-qboolean G_admin_layoutsave( gentity_t *ent, int skiparg )
-{
- char layout[ MAX_QPATH ];
-
- if( G_SayArgc( ) < 2 + skiparg )
- {
- ADMP( "^3!layoutsave: ^7usage: !layoutsave [layout]\n" );
- return qfalse;
- }
-
- G_SayArgv( skiparg + 1, layout, sizeof( layout ) );
-
- trap_SendConsoleCommand( EXEC_APPEND, va( "layoutsave %s", layout ) );
- AP( va( "print \"^3!layoutsave: ^7layout saved as '%s' by %s\n\"", layout,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- return qtrue;
-}
-
-qboolean G_admin_demo( gentity_t *ent, int skiparg )
-{
- if( !ent )
- {
- ADMP( "!demo: console can not use demo.\n" );
- return qfalse;
- }
-
- ent->client->pers.ignoreAdminWarnings = !( ent->client->pers.ignoreAdminWarnings );
-
- ADMP( va( "^3!demo: ^7your visibility of admin chat is now %s\n",
- ( ent->client->pers.ignoreAdminWarnings ) ? "^1disabled" : "^2enabled" ) );
-
- return qtrue;
-}
-
-qboolean G_admin_mute( gentity_t *ent, int skiparg )
-{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
- char command[ MAX_ADMIN_CMD_LEN ], *cmd;
- gentity_t *vic;
- char secs[ 7 ];
- int seconds = 0;
-
- G_SayArgv( skiparg, command, sizeof( command ) );
- cmd = command;
-
- if( cmd && *cmd == '!' )
- cmd++;
-
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( va( "^3!%s: ^7usage: !%s [name|slot#] (duration)\n", cmd, cmd ) );
- return qfalse;
- }
-
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
-
- if( G_ClientNumbersFromString( name, pids ) != 1 )
- {
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!%s: ^7%s\n", cmd, err ) );
- return qfalse;
- }
-
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
- {
- ADMP( va( "^3!%s: ^7sorry, but your intended victim has a higher admin"
- " level than you\n", cmd ) );
- return qfalse;
- }
-
- vic = &g_entities[ pids[ 0 ] ];
- if( !Q_stricmp( cmd, "unmute" ) )
- {
- if( vic->client->pers.muted == qfalse )
- {
- ADMP( "^3!unmute: ^7player is not currently muted\n" );
- return qtrue;
- }
-
- vic->client->pers.muteExpires = 0;
- vic->client->pers.muted = qfalse;
-
- CPx( pids[ 0 ], "cp \"^1You have been unmuted\"" );
- AP( va( "print \"^3!unmute: ^7%s^7 has been unmuted by %s\n\"",
- vic->client->pers.netname,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- } else {
- // Duration
- if( G_SayArgc() > 2 + skiparg )
- {
- G_SayArgv( 2 + skiparg, secs, sizeof( secs ) );
- seconds = G_admin_parse_time( secs );
- vic->client->pers.muteExpires = level.time + ( seconds * 1000 );
- }
-
- vic->client->pers.muted = qtrue;
-
- CPx( pids[ 0 ], "cp \"^1You've been muted\"" );
- AP( va( "print \"^3!mute: ^7%s^7 has been muted by ^7%s%s\n\"",
- vic->client->pers.netname,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
- ( seconds ) ? va( " ^7for %i seconds", seconds ) : "" ) );
- }
-
- return qtrue;
-}
-
-qboolean G_admin_cp( gentity_t *ent, int skiparg )
-{
- int minargc;
- char *s;
-
- minargc = 2 + skiparg;
-
- if( G_SayArgc() < minargc )
- {
- ADMP( "^3!cp: ^7usage: !cp [message]\n" );
- return qfalse;
- }
-
- s = G_SayConcatArgs( 1 + skiparg );
- G_CP(ent);
- return qtrue;
-}
-
-qboolean G_admin_denybuild( gentity_t *ent, int skiparg )
-{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
- char command[ MAX_ADMIN_CMD_LEN ], *cmd;
- gentity_t *vic;
+ char name[ MAX_NAME_LENGTH ];
+ char command[ MAX_ADMIN_CMD_LEN ];
+ namelog_t *vic;
- G_SayArgv( skiparg, command, sizeof( command ) );
- cmd = command;
- if( cmd && *cmd == '!' )
- cmd++;
- if( G_SayArgc() < 2 + skiparg )
+ trap_Argv( 0, command, sizeof( command ) );
+ if( trap_Argc() < 2 )
{
- ADMP( va( "^3!%s: ^7usage: !%s [name|slot#]\n", cmd, cmd ) );
+ ADMP( va( "^3%s: ^7usage: %s [name|slot#]\n", command, command ) );
return qfalse;
}
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
+ trap_Argv( 1, name, sizeof( name ) );
+ if( !( vic = G_NamelogFromString( ent, name ) ) )
{
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!%s: ^7%s\n", cmd, err ) );
+ ADMP( va( "^3%s: ^7no match\n", command ) );
return qfalse;
}
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
+ if( ent && !admin_higher_admin( ent->client->pers.admin,
+ G_admin_admin( vic->guid ) ) )
{
- ADMP( va( "^3!%s: ^7sorry, but your intended victim has a higher admin"
- " level than you\n", cmd ) );
+ ADMP( va( "^3%s: ^7sorry, but your intended victim has a higher admin"
+ " level than you\n", command ) );
return qfalse;
}
- vic = &g_entities[ pids[ 0 ] ];
- if( vic->client->pers.denyBuild )
+ if( vic->muted )
{
- if( !Q_stricmp( cmd, "denybuild" ) )
+ if( !Q_stricmp( command, "mute" ) )
{
- ADMP( "^3!denybuild: ^7player already has no building rights\n" );
- return qtrue;
+ ADMP( "^3mute: ^7player is already muted\n" );
+ return qfalse;
}
- vic->client->pers.denyBuild = qfalse;
- CPx( pids[ 0 ], "cp \"^1You've regained your building rights\"" );
- AP( va(
- "print \"^3!allowbuild: ^7building rights for ^7%s^7 restored by %s\n\"",
- vic->client->pers.netname,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
+ vic->muted = qfalse;
+ if( vic->slot > -1 )
+ CPx( vic->slot, "cp \"^1You have been unmuted\"" );
+ AP( va( "print \"^3unmute: ^7%s^7 has been unmuted by %s\n\"",
+ vic->name[ vic->nameOffset ],
+ ( ent ) ? ent->client->pers.netname : "console" ) );
}
else
{
- if( !Q_stricmp( cmd, "allowbuild" ) )
- {
- ADMP( "^3!allowbuild: ^7player already has building rights\n" );
- return qtrue;
- }
- vic->client->pers.denyBuild = qtrue;
- vic->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
- if( vic->client->ps.stats[ STAT_PCLASS ]== PCL_ALIEN_BUILDER0 || vic->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0_UPG )
+ if( !Q_stricmp( command, "unmute" ) )
{
- vic->suicideTime = level.time + 1000;
+ ADMP( "^3unmute: ^7player is not currently muted\n" );
+ return qfalse;
}
- CPx( pids[ 0 ], "cp \"^1You've lost your building rights\"" );
- AP( va(
- "print \"^3!denybuild: ^7building rights for ^7%s^7 revoked by ^7%s\n\"",
- vic->client->pers.netname,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
+ vic->muted = qtrue;
+ if( vic->slot > -1 )
+ CPx( vic->slot, "cp \"^1You've been muted\"" );
+ AP( va( "print \"^3mute: ^7%s^7 has been muted by ^7%s\n\"",
+ vic->name[ vic->nameOffset ],
+ ( ent ) ? ent->client->pers.netname : "console" ) );
}
+ admin_log( va( "%d (%s) \"%s" S_COLOR_WHITE "\"", vic->slot, vic->guid,
+ vic->name[ vic->nameOffset ] ) );
return qtrue;
}
-qboolean G_admin_denyweapon( gentity_t *ent, int skiparg )
+qboolean G_admin_denybuild( gentity_t *ent )
{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
- char command[ MAX_ADMIN_CMD_LEN ], *cmd;
- char buffer[ 32 ];
- int weapon = WP_NONE;
- int class = PCL_NONE;
- char *realname;
- gentity_t *vic;
- int flag;
- qboolean all = qfalse;
+ char name[ MAX_NAME_LENGTH ];
+ char command[ MAX_ADMIN_CMD_LEN ];
+ namelog_t *vic;
- G_SayArgv( skiparg, command, sizeof( command ) );
- cmd = command;
- if( cmd && *cmd == '!' )
- cmd++;
- if( G_SayArgc() < 3 + skiparg )
+ trap_Argv( 0, command, sizeof( command ) );
+ if( trap_Argc() < 2 )
{
- ADMP( va( "^3!%s: ^7usage: !%s [name|slot#] [class|weapon]\n", cmd, cmd ) );
+ ADMP( va( "^3%s: ^7usage: %s [name|slot#]\n", command, command ) );
return qfalse;
}
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
+ trap_Argv( 1, name, sizeof( name ) );
+ if( !( vic = G_NamelogFromString( ent, name ) ) )
{
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!%s: ^7%s\n", cmd, err ) );
+ ADMP( va( "^3%s: ^7no match\n", command ) );
return qfalse;
}
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
+ if( ent && !admin_higher_admin( ent->client->pers.admin,
+ G_admin_admin( vic->guid ) ) )
{
- ADMP( va( "^3!%s: ^7sorry, but your intended victim has a higher admin"
- " level than you\n", cmd ) );
+ ADMP( va( "^3%s: ^7sorry, but your intended victim has a higher admin"
+ " level than you\n", command ) );
return qfalse;
}
- vic = &g_entities[ pids[ 0 ] ];
-
- if( vic == ent &&
- !Q_stricmp( cmd, "denyweapon" ) )
- {
- ADMP( va( "^3!%s: ^7sorry, you cannot %s yourself\n", cmd, cmd ) );
- return qfalse;
- }
-
- G_SayArgv( 2 + skiparg, buffer, sizeof( buffer ) );
-
- if( !Q_stricmp( buffer, "all" ) &&
- !Q_stricmp( cmd, "allowweapon" ) )
- {
- if( vic->client->pers.denyHumanWeapons ||
- vic->client->pers.denyAlienClasses )
- {
- vic->client->pers.denyHumanWeapons = 0;
- vic->client->pers.denyAlienClasses = 0;
-
- CPx( pids[ 0 ], "cp \"^1You've regained all weapon and class rights\"" );
- AP( va( "print \"^3!%s: ^7all weapon and class rights for ^7%s^7 restored by %s\n\"",
- cmd,
- vic->client->pers.netname,
- ( ent ) ? ent->client->pers.netname : "console" ) );
- }
- else
- {
- ADMP( va( "^3!%s: ^7player already has all rights\n", cmd ) );
- }
- return qtrue;
- }
-
- if( !Q_stricmp( buffer, "all" ) &&
- !Q_stricmp( cmd, "denyweapon" ) )
- {
- all = qtrue;
- weapon = WP_NONE;
- class = PCL_NONE;
-
- if( vic->client->pers.denyHumanWeapons == 0xFFFFFF &&
- vic->client->pers.denyAlienClasses == 0xFFFFFF )
- {
- ADMP( va( "^3!%s: ^7player already has no weapon or class rights\n", cmd ) );
- return qtrue;
- }
-
- if( vic->client->pers.teamSelection == PTE_HUMANS )
- {
- weapon = vic->client->ps.weapon;
- if( weapon < WP_PAIN_SAW || weapon > WP_GRENADE )
- weapon = WP_NONE;
- }
- if( vic->client->pers.teamSelection == PTE_ALIENS )
- {
- class = vic->client->pers.classSelection;
- if( class < PCL_ALIEN_LEVEL1 || class > PCL_ALIEN_LEVEL4 )
- class = PCL_NONE;
- }
-
- vic->client->pers.denyHumanWeapons = 0xFFFFFF;
- vic->client->pers.denyAlienClasses = 0xFFFFFF;
- }
- else
- {
- weapon = BG_FindWeaponNumForName( buffer );
- if( weapon < WP_PAIN_SAW || weapon > WP_GRENADE )
- class = BG_FindClassNumForName( buffer );
- if( ( weapon < WP_PAIN_SAW || weapon > WP_GRENADE ) &&
- ( class < PCL_ALIEN_LEVEL1 || class > PCL_ALIEN_LEVEL4 ) )
- {
- {
- ADMP( va( "^3!%s: ^7unknown weapon or class\n", cmd ) );
- return qfalse;
- }
- }
- }
-
- if( class == PCL_NONE )
+ if( vic->denyBuild )
{
- realname = BG_FindHumanNameForWeapon( weapon );
- flag = 1 << (weapon - WP_BLASTER);
- if( !Q_stricmp( cmd, "denyweapon" ) )
+ if( !Q_stricmp( command, "denybuild" ) )
{
- if( ( vic->client->pers.denyHumanWeapons & flag ) && !all )
- {
- ADMP( va( "^3!%s: ^7player already has no %s rights\n", cmd, realname ) );
- return qtrue;
- }
- vic->client->pers.denyHumanWeapons |= flag;
- if( vic->client->pers.teamSelection == PTE_HUMANS )
- {
- if( ( weapon == WP_GRENADE || all ) &&
- BG_InventoryContainsUpgrade( UP_GRENADE, vic->client->ps.stats ) )
- {
- BG_RemoveUpgradeFromInventory( UP_GRENADE, vic->client->ps.stats );
- G_AddCreditToClient( vic->client, (short)BG_FindPriceForUpgrade( UP_GRENADE ), qfalse );
- }
- if( BG_InventoryContainsWeapon( weapon, vic->client->ps.stats ) )
- {
- int maxAmmo, maxClips;
-
- BG_RemoveWeaponFromInventory( weapon, vic->client->ps.stats );
- G_AddCreditToClient( vic->client, (short)BG_FindPriceForWeapon( weapon ), qfalse );
-
- BG_AddWeaponToInventory( WP_MACHINEGUN, vic->client->ps.stats );
- BG_FindAmmoForWeapon( WP_MACHINEGUN, &maxAmmo, &maxClips );
- vic->client->ps.ammo = maxAmmo;
- vic->client->ps.clips = maxClips;
- G_ForceWeaponChange( vic, WP_MACHINEGUN );
- vic->client->ps.stats[ STAT_MISC ] = 0;
- ClientUserinfoChanged( pids[ 0 ], qfalse );
- }
- }
- }
- else
- {
- if( !( vic->client->pers.denyHumanWeapons & flag ) )
- {
- ADMP( va( "^3!%s: ^7player already has %s rights\n", cmd, realname ) );
- return qtrue;
- }
- vic->client->pers.denyHumanWeapons &= ~flag;
+ ADMP( "^3denybuild: ^7player already has no building rights\n" );
+ return qfalse;
}
+ vic->denyBuild = qfalse;
+ if( vic->slot > -1 )
+ CPx( vic->slot, "cp \"^1You've regained your building rights\"" );
+ AP( va(
+ "print \"^3allowbuild: ^7building rights for ^7%s^7 restored by %s\n\"",
+ vic->name[ vic->nameOffset ],
+ ( ent ) ? ent->client->pers.netname : "console" ) );
}
else
{
- realname = BG_FindHumanNameForClassNum( class );
- flag = 1 << class;
- if( !Q_stricmp( cmd, "denyweapon" ) )
+ if( !Q_stricmp( command, "allowbuild" ) )
{
- if( ( vic->client->pers.denyAlienClasses & flag ) && !all )
- {
- ADMP( va( "^3!%s: ^7player already has no %s rights\n", cmd, realname ) );
- return qtrue;
- }
- vic->client->pers.denyAlienClasses |= flag;
- if( vic->client->pers.teamSelection == PTE_ALIENS &&
- vic->client->pers.classSelection == class )
- {
- vec3_t infestOrigin;
- short cost;
-
- G_RoomForClassChange( vic, PCL_ALIEN_LEVEL0, infestOrigin );
-
- vic->client->pers.evolveHealthFraction = (float)vic->client->ps.stats[ STAT_HEALTH ] /
- (float)BG_FindHealthForClass( class );
- if( vic->client->pers.evolveHealthFraction < 0.0f )
- vic->client->pers.evolveHealthFraction = 0.0f;
- else if( vic->client->pers.evolveHealthFraction > 1.0f )
- vic->client->pers.evolveHealthFraction = 1.0f;
-
- vic->client->pers.classSelection = PCL_ALIEN_LEVEL0;
- cost = BG_ClassCanEvolveFromTo( PCL_ALIEN_LEVEL0, class, 9, 0 );
- if( cost < 0 ) cost = 0;
- G_AddCreditToClient( vic->client, cost, qfalse );
- ClientUserinfoChanged( pids[ 0 ], qfalse );
- VectorCopy( infestOrigin, vic->s.pos.trBase );
- ClientSpawn( vic, vic, vic->s.pos.trBase, vic->s.apos.trBase );
- }
+ ADMP( "^3allowbuild: ^7player already has building rights\n" );
+ return qfalse;
}
- else
+ vic->denyBuild = qtrue;
+ if( vic->slot > -1 )
{
- if( !( vic->client->pers.denyAlienClasses & flag ) )
- {
- ADMP( va( "^3!%s: ^7player already has %s rights\n", cmd, realname ) );
- return qtrue;
- }
- vic->client->pers.denyAlienClasses &= ~flag;
+ level.clients[ vic->slot ].ps.stats[ STAT_BUILDABLE ] = BA_NONE;
+ CPx( vic->slot, "cp \"^1You've lost your building rights\"" );
}
+ AP( va(
+ "print \"^3denybuild: ^7building rights for ^7%s^7 revoked by ^7%s\n\"",
+ vic->name[ vic->nameOffset ],
+ ( ent ) ? ent->client->pers.netname : "console" ) );
}
-
- if( all )
- realname = "weapon and class";
-
- CPx( pids[ 0 ], va( "cp \"^1You've %s your %s rights\"",
- ( !Q_stricmp( cmd, "denyweapon" ) ) ? "lost" : "regained",
- realname ) );
- AP( va(
- "print \"^3!%s: ^7%s rights for ^7%s^7 %s by %s\n\"",
- cmd, realname,
- vic->client->pers.netname,
- ( !Q_stricmp( cmd, "denyweapon" ) ) ? "revoked" : "restored",
- ( ent ) ? ent->client->pers.netname : "console" ) );
-
+ admin_log( va( "%d (%s) \"%s" S_COLOR_WHITE "\"", vic->slot, vic->guid,
+ vic->name[ vic->nameOffset ] ) );
return qtrue;
}
-qboolean G_admin_listadmins( gentity_t *ent, int skiparg )
+qboolean G_admin_listadmins( gentity_t *ent )
{
- int i, found = 0;
+ int i;
char search[ MAX_NAME_LENGTH ] = {""};
char s[ MAX_NAME_LENGTH ] = {""};
- int start = 0;
- qboolean numeric = qtrue;
- int drawn = 0;
- int minlevel = 1;
+ int start = MAX_CLIENTS;
- if( G_SayArgc() == 3 + skiparg )
+ if( trap_Argc() == 3 )
{
- G_SayArgv( 2 + skiparg, s, sizeof( s ) );
- if( s[ 0 ] >= '0' && s[ 0] <= '9' )
- {
- minlevel = atoi( s );
- if( minlevel < 1 )
- minlevel = 1;
- }
- }
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( g_admin_admins[ i ]->level >= minlevel )
- found++;
- }
- if( !found )
- {
- if( minlevel > 1 )
- {
- ADMP( va( "^3!listadmins: ^7no admins level %i or greater found\n", minlevel ) );
- }
- else
- {
- ADMP( "^3!listadmins: ^7no admins defined\n" );
- }
- return qfalse;
+ trap_Argv( 2, s, sizeof( s ) );
+ start = atoi( s );
}
-
- if( G_SayArgc() >= 2 + skiparg )
+ if( trap_Argc() > 1 )
{
- G_SayArgv( 1 + skiparg, s, sizeof( s ) );
- for( i = 0; i < sizeof( s ) && s[ i ]; i++ )
+ trap_Argv( 1, s, sizeof( s ) );
+ i = 0;
+ if( trap_Argc() == 2 )
{
- if( s[ i ] >= '0' && s[ i ] <= '9' )
- continue;
- numeric = qfalse;
+ i = s[ 0 ] == '-';
+ for( ; isdigit( s[ i ] ); i++ );
}
- if( numeric )
- {
+ if( i && !s[ i ] )
start = atoi( s );
- if( start > 0 )
- start -= 1;
- else if( start < 0 )
- start = found + start;
- }
else
G_SanitiseString( s, search, sizeof( search ) );
}
- if( start >= found || start < 0 )
- start = 0;
-
- drawn = admin_listadmins( ent, start, search, minlevel );
-
- if( search[ 0 ] )
- {
- if( drawn <= 20 )
- {
- ADMP( va( "^3!listadmins:^7 found %d admins level %i or greater matching '%s^7'\n",
- drawn, minlevel, search ) );
- }
- else
- {
- ADMP( va( "^3!listadmins:^7 found >20 admins level %i or greater matching '%s^7. Try a more narrow search.'\n",
- minlevel, search ) );
- }
- }
- else
- {
- ADMBP_begin();
- ADMBP( va( "^3!listadmins:^7 showing admins level %i or greater %d - %d of %d. ",
- minlevel,
- ( found ) ? ( start + 1 ) : 0,
- ( ( start + MAX_ADMIN_LISTITEMS ) > found ) ?
- found : ( start + MAX_ADMIN_LISTITEMS ),
- found ) );
- if( ( start + MAX_ADMIN_LISTITEMS ) < found )
- {
- if( minlevel > 1)
- {
- ADMBP( va( "run '!listadmins %d %d' to see more",
- ( start + MAX_ADMIN_LISTITEMS + 1 ), minlevel ) );
- }
- else
- {
- ADMBP( va( "run '!listadmins %d' to see more",
- ( start + MAX_ADMIN_LISTITEMS + 1 ) ) );
- }
- }
- ADMBP( "\n" );
- ADMBP_end();
- }
+ admin_listadmins( ent, start, search );
return qtrue;
}
-qboolean G_admin_listlayouts( gentity_t *ent, int skiparg )
+qboolean G_admin_listlayouts( gentity_t *ent )
{
char list[ MAX_CVAR_VALUE_STRING ];
char map[ MAX_QPATH ];
int count = 0;
char *s;
char layout[ MAX_QPATH ] = { "" };
- int i = 0;
-
- if( G_SayArgc( ) == 2 + skiparg )
- G_SayArgv( 1 +skiparg, map, sizeof( map ) );
+ size_t i = 0;
+
+ if( trap_Argc( ) == 2 )
+ trap_Argv( 1, map, sizeof( map ) );
else
trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
-
+
count = G_LayoutList( map, list, sizeof( list ) );
ADMBP_begin( );
- ADMBP( va( "^3!listlayouts:^7 %d layouts found for '%s':\n", count, map ) );
+ ADMBP( va( "^3listlayouts:^7 %d layouts found for '%s':\n", count, map ) );
s = &list[ 0 ];
while( *s )
{
@@ -4762,690 +2366,193 @@ qboolean G_admin_listlayouts( gentity_t *ent, int skiparg )
return qtrue;
}
-qboolean G_admin_listplayers( gentity_t *ent, int skiparg )
+qboolean G_admin_listplayers( gentity_t *ent )
{
- int i, j;
- int invisiblePlayers = 0;
- gclient_t *p;
- char c[ 3 ], t[ 2 ]; // color and team letter
- char n[ MAX_NAME_LENGTH ] = {""};
- char n2[ MAX_NAME_LENGTH ] = {""};
- char n3[ MAX_NAME_LENGTH ] = {""};
- char lname[ MAX_NAME_LENGTH ];
- char lname2[ MAX_NAME_LENGTH ];
- char muted[ 2 ], denied[ 2 ], dbuilder[ 2 ], immune[ 2 ], guidless[ 2 ];
- int l;
- char lname_fmt[ 5 ];
-
- //get amount of invisible players
- for( i = 0; i < level.maxclients; i++ ) {
- p = &level.clients[ i ];
- if ( p->sess.invisible == qtrue )
- invisiblePlayers++;
- }
+ int i, j;
+ gclient_t *p;
+ char c, t; // color and team letter
+ char *registeredname;
+ char lname[ MAX_NAME_LENGTH ];
+ char muted, denied;
+ int colorlen;
+ char namecleaned[ MAX_NAME_LENGTH ];
+ char name2cleaned[ MAX_NAME_LENGTH ];
+ g_admin_level_t *l;
+ g_admin_level_t *d = G_admin_level( 0 );
+ qboolean hint;
+ qboolean canset = G_admin_permission( ent, "setlevel" );
ADMBP_begin();
- ADMBP( va( "^3!listplayers^7: %d players connected:\n",
- level.numConnectedClients - invisiblePlayers ) );
+ ADMBP( va( "^3listplayers: ^7%d players connected:\n",
+ level.numConnectedClients ) );
for( i = 0; i < level.maxclients; i++ )
{
p = &level.clients[ i ];
-
- // Ignore invisible players
- if ( p->sess.invisible == qtrue )
+ if( p->pers.connected == CON_DISCONNECTED )
continue;
-
- Q_strncpyz( t, "S", sizeof( t ) );
- Q_strncpyz( c, S_COLOR_YELLOW, sizeof( c ) );
- if( p->pers.teamSelection == PTE_HUMANS )
- {
- Q_strncpyz( t, "H", sizeof( t ) );
- Q_strncpyz( c, S_COLOR_BLUE, sizeof( c ) );
- }
- else if( p->pers.teamSelection == PTE_ALIENS )
- {
- Q_strncpyz( t, "A", sizeof( t ) );
- Q_strncpyz( c, S_COLOR_RED, sizeof( c ) );
- }
-
if( p->pers.connected == CON_CONNECTING )
{
- Q_strncpyz( t, "C", sizeof( t ) );
- Q_strncpyz( c, S_COLOR_CYAN, sizeof( c ) );
+ t = 'C';
+ c = COLOR_YELLOW;
}
- else if( p->pers.connected != CON_CONNECTED )
+ else
{
- continue;
+ t = toupper( *( BG_TeamName( p->pers.teamSelection ) ) );
+ if( p->pers.teamSelection == TEAM_HUMANS )
+ c = COLOR_CYAN;
+ else if( p->pers.teamSelection == TEAM_ALIENS )
+ c = COLOR_RED;
+ else
+ c = COLOR_WHITE;
}
- guidless[ 0 ] = '\0';
- if( !Q_stricmp( p->pers.guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ) )
- {
- Q_strncpyz( guidless, "G", sizeof( guidless ) );
- }
- muted[ 0 ] = '\0';
- if( G_admin_permission( &g_entities[ i ], ADMF_NO_VOTE ) || G_admin_permission( &g_entities[ i ], ADMF_FAKE_NO_VOTE ) )
- {
- Q_strncpyz( muted, "V", sizeof( muted ) );
- }
- if( p->pers.muted )
- {
- Q_strncpyz( muted, "M", sizeof( muted ) );
- }
- denied[ 0 ] = '\0';
- if( p->pers.denyBuild )
- {
- Q_strncpyz( denied, "B", sizeof( denied ) );
- }
- if( p->pers.denyHumanWeapons || p->pers.denyAlienClasses )
- {
- Q_strncpyz( denied, "W", sizeof( denied ) );
- }
+ muted = p->pers.namelog->muted ? 'M' : ' ';
+ denied = p->pers.namelog->denyBuild ? 'B' : ' ';
- dbuilder[ 0 ] = '\0';
- if( p->pers.designatedBuilder )
+ l = d;
+ registeredname = NULL;
+ hint = canset;
+ if( p->pers.admin )
{
- if( !G_admin_permission( &g_entities[ i ], ADMF_INCOGNITO ) &&
- G_admin_permission( &g_entities[ i ], ADMF_DBUILDER ) &&
- G_admin_permission(ent, ADMF_SEESFULLLISTPLAYERS ) )
- {
- Q_strncpyz( dbuilder, "P", sizeof( dbuilder ) );
- }
- else
+ if( hint )
+ hint = admin_higher( ent, &g_entities[ i ] );
+ if( hint || !G_admin_permission( &g_entities[ i ], ADMF_INCOGNITO ) )
{
- Q_strncpyz( dbuilder, "D", sizeof( dbuilder ) );
+ l = G_admin_level( p->pers.admin->level );
+ G_SanitiseString( p->pers.netname, namecleaned,
+ sizeof( namecleaned ) );
+ G_SanitiseString( p->pers.admin->name,
+ name2cleaned, sizeof( name2cleaned ) );
+ if( Q_stricmp( namecleaned, name2cleaned ) )
+ registeredname = p->pers.admin->name;
}
}
- immune[ 0 ] = '\0';
- if( G_admin_permission( &g_entities[ i ], ADMF_BAN_IMMUNITY ) &&
- G_admin_permission(ent, ADMF_SEESFULLLISTPLAYERS ) )
- {
- Q_strncpyz( immune, "I", sizeof( immune ) );
- }
- if( p->pers.paused )
- {
- // use immunity slot for paused player status
- Q_strncpyz( immune, "L", sizeof( immune ) );
- }
+ if( l )
+ Q_strncpyz( lname, l->name, sizeof( lname ) );
- l = 0;
- G_SanitiseString( p->pers.netname, n2, sizeof( n2 ) );
- n[ 0 ] = '\0';
- for( j = 0; j < MAX_ADMIN_ADMINS && g_admin_admins[ j ]; j++ )
+ for( colorlen = j = 0; lname[ j ]; j++ )
{
- if( !Q_stricmp( g_admin_admins[ j ]->guid, p->pers.guid ) )
- {
-
- // don't gather aka or level info if the admin is incognito
- if( ent && G_admin_permission( &g_entities[ i ], ADMF_INCOGNITO ) && !G_admin_permission(ent, ADMF_SEESINCOGNITO) )
- {
- break;
- }
- l = g_admin_admins[ j ]->level;
- G_SanitiseString( g_admin_admins[ j ]->name, n3, sizeof( n3 ) );
- if( Q_stricmp( n2, n3 ) )
- {
- Q_strncpyz( n, g_admin_admins[ j ]->name, sizeof( n ) );
- }
- break;
- }
+ if( Q_IsColorString( &lname[ j ] ) )
+ colorlen += 2;
}
- lname[ 0 ] = '\0';
- Q_strncpyz( lname_fmt, "%s", sizeof( lname_fmt ) );
- for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
- {
- if( g_admin_levels[ j ]->level == l )
- {
- Q_strncpyz( lname, g_admin_levels[ j ]->name, sizeof( lname ) );
- if( *lname )
- {
- G_DecolorString( lname, lname2 );
- Com_sprintf( lname_fmt, sizeof( lname_fmt ), "%%%is",
- ( admin_level_maxname + (int)( strlen( lname ) - strlen( lname2 ) ) ) );
- Com_sprintf( lname2, sizeof( lname2 ), lname_fmt, lname );
- }
- break;
- }
- }
+ ADMBP( va( "%2i ^%c%c %s %s^7 %*s^7 ^1%c%c^7 %s^7 %s%s%s\n",
+ i,
+ c,
+ t,
+ p->pers.guidless ? "^1---" : va( "^7%-2i^2%c", l ? l->level : 0, hint ? '*' : ' ' ),
+ p->pers.alternateProtocol == 2 ? "^11" : p->pers.alternateProtocol == 1 ? "^3G" : " ",
+ admin_level_maxname + colorlen,
+ lname,
+ muted,
+ denied,
+ p->pers.netname,
+ ( registeredname ) ? "(a.k.a. " : "",
+ ( registeredname ) ? registeredname : "",
+ ( registeredname ) ? S_COLOR_WHITE ")" : "" ) );
- if ( G_admin_permission(ent, ADMF_SEESFULLLISTPLAYERS ) ) {
- ADMBP( va( "%2i %s%s^7 %-2i %s^7 ^1%1s%1s%1s%1s%1s^7 %s^7 %s%s^7%s\n",
- i,
- c,
- t,
- l,
- ( *lname ) ? lname2 : "",
- immune,
- muted,
- dbuilder,
- denied,
- guidless,
- p->pers.netname,
- ( *n ) ? "(a.k.a. " : "",
- n,
- ( *n ) ? ")" : ""
- ) );
- } else {
- ADMBP( va( "%2i %s%s^7 %-2i %s^7 ^1%1s%1s%1s%1s^7 %s^7 %s%s^7%s\n",
- i,
- c,
- t,
- l,
- ( *lname ) ? lname2 : "",
- immune,
- muted,
- dbuilder,
- denied,
- p->pers.netname,
- ( *n ) ? "(a.k.a. " : "",
- n,
- ( *n ) ? ")" : ""
- ) );
- }
}
ADMBP_end();
return qtrue;
}
-#define MAX_LISTMAPS_MAPS 256
-
-static int SortMaps(const void *a, const void *b)
+static qboolean ban_matchip( void *ban, const void *ip )
{
- return strcmp(*(char **)a, *(char **)b);
+ return G_AddressCompare( &((g_admin_ban_t *)ban)->ip, (addr_t *)ip ) ||
+ G_AddressCompare( (addr_t *)ip, &((g_admin_ban_t *)ban)->ip );
}
-
-qboolean G_admin_listmaps( gentity_t *ent, int skiparg )
+static qboolean ban_matchname( void *ban, const void *name )
{
- char fileList[ 4096 ] = {""};
- char *fileSort[ MAX_LISTMAPS_MAPS ];
- char search[ 16 ] = {""};
- int numFiles;
- int i;
- int fileLen = 0;
- int count = 0;
- char *filePtr;
- int rows;
+ char match[ MAX_NAME_LENGTH ];
- if( G_SayArgc( ) > 1 + skiparg )
- {
- G_SayArgv( skiparg + 1, search, sizeof( search ) );
- }
-
- numFiles = trap_FS_GetFileList( "maps/", ".bsp",
- fileList, sizeof( fileList ) );
- filePtr = fileList;
- for( i = 0; i < numFiles && count < MAX_LISTMAPS_MAPS; i++, filePtr += fileLen + 1 )
- {
- fileLen = strlen( filePtr );
- if (fileLen < 5)
- continue;
-
- filePtr[ fileLen - 4 ] = '\0';
-
- if( search[ 0 ] && !strstr( filePtr, search ) )
- continue;
-
- fileSort[ count ] = filePtr;
- count++;
- }
-
- qsort(fileSort, count, sizeof(fileSort[ 0 ]), SortMaps);
-
- rows = count / 3;
- if ( rows * 3 < count ) rows++;
-
- ADMBP_begin();
- for( i = 0; i < rows; i++ )
- {
- ADMBP( va( "^7%20s %20s %20s\n",
- fileSort[ i ],
- ( rows + i < count ) ? fileSort[ rows + i ] : "",
- ( rows * 2 + i < count ) ? fileSort[ rows * 2 + i ] : "" ) );
- }
- if ( search[ 0 ] )
- ADMBP( va( "^3!listmaps: ^7found %d maps matching '%s^7'.\n", count, search ) );
- else
- ADMBP( va( "^3!listmaps: ^7listing %d maps.\n", count ) );
-
- ADMBP_end();
-
- return qtrue;
+ G_SanitiseString( ( (g_admin_ban_t *)ban )->name, match, sizeof( match ) );
+ return strstr( match, (const char *)name ) != NULL;
}
-
-qboolean G_admin_listrotation( gentity_t *ent, int skiparg )
+static void ban_out( void *ban, char *str )
{
- int i, j, statusColor;
- char mapnames[ MAX_STRING_CHARS ];
- char *status = NULL;
-
- extern mapRotations_t mapRotations;
+ size_t i;
+ int colorlen1 = 0;
+ char duration[ MAX_DURATION_LENGTH ];
+ char *d_color = S_COLOR_WHITE;
+ char date[ 11 ];
+ g_admin_ban_t *b = ( g_admin_ban_t * )ban;
+ int t = trap_RealTime( NULL );
+ char *made = b->made;
- // Check for an active map rotation
- if ( !G_MapRotationActive() ||
- g_currentMapRotation.integer == NOT_ROTATING )
+ for( i = 0; b->name[ i ]; i++ )
{
- trap_SendServerCommand( ent-g_entities, "print \"^3!rotation: ^7There is no active map rotation on this server\n\"" );
- return qfalse;
+ if( Q_IsColorString( &b->name[ i ] ) )
+ colorlen1 += 2;
}
- // Locate the active map rotation and output its contents
- for( i = 0; i < mapRotations.numRotations; i++ )
- {
- if ( i == g_currentMapRotation.integer )
- {
- int currentMap = G_GetCurrentMap( i );
-
- ADMBP_begin();
- ADMBP( va( "^3!rotation: ^7%s\n", mapRotations.rotations[ i ].name ) );
-
- for( j = 0; j < mapRotations.rotations[ i ].numMaps; j++ )
- {
- Q_strncpyz( mapnames, mapRotations.rotations[ i ].maps[ j ].name, sizeof( mapnames ) );
-
- if( !Q_stricmp( mapRotations.rotations[ i ].maps[ j ].name, "*VOTE*" ) )
- {
- char slotMap[ 64 ];
- int lineLen = 0;
- int k;
-
- trap_Cvar_VariableStringBuffer( "mapname", slotMap, sizeof( slotMap ) );
- mapnames[ 0 ] = '\0';
- for( k = 0; k < mapRotations.rotations[ i ].maps[ j ].numConditions; k++ )
- {
- char *thisMap;
- int mc = 7;
-
- if( mapRotations.rotations[ i ].maps[ j ].conditions[ k ].lhs != MCV_VOTE )
- continue;
-
- thisMap = mapRotations.rotations[ i ].maps[ j ].conditions[ k ].dest;
- lineLen += strlen( thisMap ) + 1;
-
- if( currentMap == j && !Q_stricmp( thisMap, slotMap ) )
- mc = 3;
- Q_strcat( mapnames, sizeof( mapnames ), va( "^7%s%s^%i%s",
- ( k ) ? ", " : "",
- ( lineLen > 50 ) ? "\n " : "",
- mc, thisMap ) );
- if( lineLen > 50 )
- lineLen = strlen( thisMap ) + 2;
- else
- lineLen++;
- }
-
- if( currentMap == j )
- {
- statusColor = 3;
- status = "current slot";
- }
- else if( !k )
- {
- statusColor = 1;
- status = "empty vote";
- }
- else
- {
- statusColor = 7;
- status = "vote";
- }
- } else if( !Q_stricmp( mapRotations.rotations[ i ].maps[ j ].name, "*RANDOM*" ) )
- {
- char slotMap[ 64 ];
- int lineLen = 0;
- int k;
-
- trap_Cvar_VariableStringBuffer( "mapname", slotMap, sizeof( slotMap ) );
- mapnames[ 0 ] = '\0';
- for( k = 0; k < mapRotations.rotations[ i ].maps[ j ].numConditions; k++ )
- {
- char *thisMap;
- int mc = 7;
-
- if( mapRotations.rotations[ i ].maps[ j ].conditions[ k ].lhs != MCV_SELECTEDRANDOM )
- continue;
-
- thisMap = mapRotations.rotations[ i ].maps[ j ].conditions[ k ].dest;
- lineLen += strlen( thisMap ) + 1;
-
- if( currentMap == j && !Q_stricmp( thisMap, slotMap ) )
- mc = 3;
- Q_strcat( mapnames, sizeof( mapnames ), va( "^7%s%s^%i%s",
- ( k ) ? ", " : "",
- ( lineLen > 50 ) ? "\n " : "",
- mc, thisMap ) );
- if( lineLen > 50 )
- lineLen = strlen( thisMap ) + 2;
- else
- lineLen++;
- }
-
- if( currentMap == j )
- {
- statusColor = 3;
- status = "current slot";
- }
- else if( !k )
- {
- statusColor = 1;
- status = "empty Random";
- }
- else
- {
- statusColor = 7;
- status = "Random";
- }
- }
- else if ( currentMap == j )
- {
- statusColor = 3;
- status = "current slot";
- }
- else if ( !G_MapExists( mapRotations.rotations[ i ].maps[ j ].name ) )
- {
- statusColor = 1;
- status = "missing";
- }
- else
- {
- statusColor = 7;
- status = "";
- }
- ADMBP( va( " ^%i%-12s %3i %s\n", statusColor, status, j + 1, mapnames ) );
- }
-
- ADMBP_end();
-
- // No maps were found in the active map rotation
- if ( mapRotations.rotations[ i ].numMaps < 1 )
- {
- trap_SendServerCommand( ent-g_entities, "print \" - ^7Empty!\n\"" );
- return qfalse;
- }
- }
- }
+ // only print out the the date part of made
+ date[ 0 ] = '\0';
+ for( i = 0; *made && *made != ' ' && i < sizeof( date ) - 1; i++ )
+ date[ i ] = *made++;
+ date[ i ] = 0;
- if( g_nextMap.string[0] )
+ if( !b->expires || b->expires - t > 0 )
+ G_admin_duration( b->expires ? b->expires - t : - 1,
+ duration, sizeof( duration ) );
+ else
{
- ADMP( va ("^5 Next map overriden by g_nextMap to: %s\n", g_nextMap.string ) );
+ Q_strncpyz( duration, "expired", sizeof( duration ) );
+ d_color = S_COLOR_CYAN;
}
-
- return qtrue;
-}
-
-qboolean G_admin_showbans( gentity_t *ent, int skiparg )
+ Com_sprintf( str, MAX_STRING_CHARS, "%-*s %s%-15s " S_COLOR_WHITE "%-8s %s"
+ "\n \\__ %s%-*s " S_COLOR_WHITE "%s",
+ MAX_NAME_LENGTH + colorlen1 - 1, b->name,
+ ( strchr( b->ip.str, '/' ) ) ? S_COLOR_RED : S_COLOR_WHITE,
+ b->ip.str,
+ date,
+ b->banner,
+ d_color,
+ MAX_DURATION_LENGTH - 1,
+ duration,
+ b->reason );
+}
+qboolean G_admin_showbans( gentity_t *ent )
{
- int i, found = 0;
- int t;
- char duration[ 32 ];
- char sduration[ 32 ];
- char suspended[ 64 ] = { "" };
- char name_fmt[ 32 ] = { "%s" };
- char banner_fmt[ 32 ] = { "%s" };
- int max_name = 1, max_banner = 1;
- int secs;
- int start = 0;
+ int i;
+ int start = 1;
char filter[ MAX_NAME_LENGTH ] = {""};
- char date[ 11 ];
- char *made;
- int j;
- char n1[ MAX_NAME_LENGTH * 2 ] = {""};
- char n2[ MAX_NAME_LENGTH * 2 ] = {""};
- int bannerslevel = 0;
- qboolean numeric = qtrue;
- char *ip_match = NULL;
- int ip_match_len = 0;
char name_match[ MAX_NAME_LENGTH ] = {""};
- int show_count = 0;
- qboolean subnetfilter = qfalse;
+ qboolean ipmatch = qfalse;
+ addr_t ip;
- t = trap_RealTime( NULL );
-
- for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
+ if( trap_Argc() == 3 )
{
- if( g_admin_bans[ i ]->expires != 0
- && ( g_admin_bans[ i ]->expires - t ) < 1 )
- {
- continue;
- }
- found++;
+ trap_Argv( 2, filter, sizeof( filter ) );
+ start = atoi( filter );
}
-
- if( G_SayArgc() >= 2 + skiparg )
+ if( trap_Argc() > 1 )
{
- G_SayArgv( 1 + skiparg, filter, sizeof( filter ) );
- if( G_SayArgc() >= 3 + skiparg )
- {
+ trap_Argv( 1, filter, sizeof( filter ) );
+ i = 0;
+ if( trap_Argc() == 2 )
+ for( i = filter[ 0 ] == '-'; isdigit( filter[ i ] ); i++ );
+ if( !filter[ i ] )
start = atoi( filter );
- G_SayArgv( 2 + skiparg, filter, sizeof( filter ) );
- }
- for( i = 0; i < sizeof( filter ) && filter[ i ] ; i++ )
- {
- if( ( filter[ i ] < '0' || filter[ i ] > '9' )
- && filter[ i ] != '.' && filter[ i ] != '-' )
- {
- numeric = qfalse;
- break;
- }
- }
-
- if (!numeric)
- {
- if( filter[ 0 ] != '-' )
- {
- G_SanitiseString( filter, name_match, sizeof( name_match) );
-
- }
- else
- {
- if( !Q_strncmp( filter, "-sub", 4 ) )
- {
- subnetfilter = qtrue;
- }
- else
- {
- ADMP( va( "^3!showbans: ^7invalid argument %s\n", filter ) );
- return qfalse;
- }
- }
- }
- else if( strchr( filter, '.' ) != NULL )
- {
- ip_match = filter;
- ip_match_len = strlen(ip_match);
- }
- else
- {
- start = atoi( filter );
- filter[0] = '\0';
- }
- // showbans 1 means start with ban 0
- if( start > 0 )
- start -= 1;
- else if( start < 0 )
- start = found + start;
- }
-
- if( start >= MAX_ADMIN_BANS || start < 0 )
- start = 0;
-
- for( i = start; i < MAX_ADMIN_BANS && g_admin_bans[ i ]
- && show_count < MAX_ADMIN_SHOWBANS; i++ )
- {
- qboolean match = qfalse;
-
- if (!numeric)
- {
- if( !subnetfilter )
- {
- G_SanitiseString( g_admin_bans[ i ]->name, n1, sizeof( n1 ) );
- if (strstr( n1, name_match) )
- match = qtrue;
- }
- else
- {
- int mask = -1;
- int dummy;
- int scanflen = 0;
- scanflen = sscanf( g_admin_bans[ i ]->ip, "%d.%d.%d.%d/%d", &dummy, &dummy, &dummy, &dummy, &mask );
- if( scanflen == 5 && mask < 32 )
- {
- match = qtrue;
- }
- }
- }
-
- if ( ( match ) || !ip_match
- || Q_strncmp( ip_match, g_admin_bans[ i ]->ip, ip_match_len) == 0 )
- {
- G_DecolorString( g_admin_bans[ i ]->name, n1 );
- G_DecolorString( g_admin_bans[ i ]->banner, n2 );
- if( strlen( n1 ) > max_name )
- {
- max_name = strlen( n1 );
- }
- if( strlen( n2 ) > max_banner )
- max_banner = strlen( n2 );
-
- show_count++;
- }
+ else if( !( ipmatch = G_AddressParse( filter, &ip ) ) )
+ G_SanitiseString( filter, name_match, sizeof( name_match ) );
}
- if( start >= found )
- {
- ADMP( va( "^3!showbans: ^7there are %d active bans\n", found ) );
- return qfalse;
- }
- ADMBP_begin();
- show_count = 0;
- for( i = start; i < MAX_ADMIN_BANS && g_admin_bans[ i ]
- && show_count < MAX_ADMIN_SHOWBANS; i++ )
- {
- if (!numeric)
- {
- if( !subnetfilter )
- {
- G_SanitiseString( g_admin_bans[ i ]->name, n1, sizeof( n1 ) );
- if ( strstr ( n1, name_match ) == NULL )
- continue;
- }
- else
- {
- int mask = -1;
- int dummy;
- int scanflen = 0;
- scanflen = sscanf( g_admin_bans[ i ]->ip, "%d.%d.%d.%d/%d", &dummy, &dummy, &dummy, &dummy, &mask );
- if( scanflen != 5 || mask >= 32 )
- {
- continue;
- }
- }
- }
- else if( ip_match != NULL
- && Q_strncmp( ip_match, g_admin_bans[ i ]->ip, ip_match_len ) != 0)
- continue;
-
- // only print out the the date part of made
- date[ 0 ] = '\0';
- made = g_admin_bans[ i ]->made;
- for( j = 0; made && *made; j++ )
- {
- if( ( j + 1 ) >= sizeof( date ) )
- break;
- if( *made == ' ' )
- break;
- date[ j ] = *made;
- date[ j + 1 ] = '\0';
- made++;
- }
-
- if( g_admin_bans[ i ]->expires != 0
- && ( g_admin_bans[ i ]->expires - t ) < 1 )
- {
- Com_sprintf( duration, sizeof( duration ), "^1*EXPIRED*^7" );
- } else {
- secs = ( g_admin_bans[ i ]->expires - t );
- G_admin_duration( secs, duration, sizeof( duration ) );
- }
-
- suspended[ 0 ] = '\0';
- if( g_admin_bans[ i ]->suspend > t )
- {
- G_admin_duration( g_admin_bans[ i ]->suspend - t, sduration, sizeof( sduration ) );
- Com_sprintf( suspended, sizeof( suspended ), "^3*SUSPENDED*^7 for %s^7",
- sduration );
- }
-
- G_DecolorString( g_admin_bans[ i ]->name, n1 );
- Com_sprintf( name_fmt, sizeof( name_fmt ), "%%%is",
- ( max_name + strlen( g_admin_bans[ i ]->name ) - strlen( n1 ) ) );
- Com_sprintf( n1, sizeof( n1 ), name_fmt, g_admin_bans[ i ]->name );
-
- G_DecolorString( g_admin_bans[ i ]->banner, n2 );
- Com_sprintf( banner_fmt, sizeof( banner_fmt ), "%%%is",
- ( max_banner + strlen( g_admin_bans[ i ]->banner ) - strlen( n2 ) ) );
- Com_sprintf( n2, sizeof( n2 ), banner_fmt, g_admin_bans[ i ]->banner );
- bannerslevel = g_admin_bans[ i ]->bannerlevel;
-
- ADMBP( va( "%4i %s^7 %-15s %-8s %-10s\n | %-15s^7 Level:%2i\n | %s\n \\__ %s\n",
- ( i + 1 ),
- n1,
- g_admin_bans[ i ]->ip,
- date,
- duration,
- n2,
- bannerslevel,
- suspended,
- g_admin_bans[ i ]->reason ) );
-
- show_count++;
- }
-
- if (!numeric || ip_match)
- {
- char matchmethod[50];
- if( numeric )
- Com_sprintf( matchmethod, sizeof(matchmethod), "IP" );
- else if( !subnetfilter )
- Com_sprintf( matchmethod, sizeof(matchmethod), "name" );
- else
- Com_sprintf( matchmethod, sizeof(matchmethod), "ip range size" );
-
-
- ADMBP( va( "^3!showbans:^7 found %d matching bans by %s. ",
- show_count,
- matchmethod ) );
- }
- else
- {
- ADMBP( va( "^3!showbans:^7 showing bans %d - %d of %d. ",
- ( found ) ? ( start + 1 ) : 0,
- ( ( start + MAX_ADMIN_SHOWBANS ) > found ) ?
- found : ( start + MAX_ADMIN_SHOWBANS ),
- found ) );
- }
-
- if( ( start + MAX_ADMIN_SHOWBANS ) < found )
- {
- ADMBP( va( "run !showbans %d %s to see more",
- ( start + MAX_ADMIN_SHOWBANS + 1 ),
- (filter[0]) ? filter : "" ) );
- }
- ADMBP( "\n" );
- ADMBP_end();
+ admin_search( ent, "showbans", "bans",
+ ipmatch ? ban_matchip : ban_matchname,
+ ban_out, g_admin_bans,
+ ipmatch ? (void * )&ip : (void *)name_match,
+ start, 1, MAX_ADMIN_SHOWBANS );
return qtrue;
}
-qboolean G_admin_help( gentity_t *ent, int skiparg )
+qboolean G_admin_adminhelp( gentity_t *ent )
{
- int i;
- int commandsPerLine = 6;
-
- if( G_SayArgc() < 2 + skiparg )
+ g_admin_command_t *c;
+ if( trap_Argc() < 2 )
{
- int j = 0;
+ size_t i;
int count = 0;
ADMBP_begin();
@@ -5453,235 +2560,104 @@ qboolean G_admin_help( gentity_t *ent, int skiparg )
{
if( G_admin_permission( ent, g_admin_cmds[ i ].flag ) )
{
- ADMBP( va( "^3!%-12s", g_admin_cmds[ i ].keyword ) );
- j++;
+ ADMBP( va( "^3%-12s", g_admin_cmds[ i ].keyword ) );
count++;
- }
- // show 6 commands per line
- if( j == 6 )
- {
- ADMBP( "\n" );
- j = 0;
+ // show 6 commands per line
+ if( count % 6 == 0 )
+ ADMBP( "\n" );
}
}
- for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
+ for( c = g_admin_commands; c; c = c->next )
{
- if( !G_admin_permission( ent, g_admin_commands[ i ]->flag ) )
+ if( !G_admin_permission( ent, c->flag ) )
continue;
- ADMBP( va( "^3!%-12s", g_admin_commands[ i ]->command ) );
- j++;
+ ADMBP( va( "^3%-12s", c->command ) );
count++;
// show 6 commands per line
- if( j == 6 )
- {
+ if( count % 6 == 0 )
ADMBP( "\n" );
- j = 0;
- }
}
-
- if( count )
+ if( count % 6 )
ADMBP( "\n" );
- ADMBP( va( "^3!help: ^7%i available commands\n", count ) );
- ADMBP( "run !help [^3command^7] for help with a specific command.\n" );
- ADMBP( "The following non-standard /commands may also be available to you: \n" );
- count = 1;
-
- if( ent && g_AllStats.integer ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "allstats" ) );
- count++;
- }
- if ( ent ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "builder" ) );
- count++;
- }
- if( ent && g_allowVote.integer && G_admin_permission( ent, ADMF_NO_VOTE ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "callvote" ) );
- count++;
- }
- if( ent && g_allowVote.integer && G_admin_permission( ent, ADMF_NO_VOTE ) && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "callteamvote" ) );
- count++;
- }
- if( ent && g_allowShare.integer && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "donate" ) );
- count++;
- }
- if( g_privateMessages.integer ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "m" ) );
- count++;
- }
- if( ent && g_markDeconstruct.integer == 2 && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "mark" ) );
- count++;
- }
- if( ent && g_actionPrefix.string[0] ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "me" ) );
- count++;
- }
- if( ent && g_actionPrefix.string[0] ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "me_team" ) );
- count++;
- }
- if( ent && g_actionPrefix.string[0] && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "mt" ) );
- count++;
- }
- if( ent && g_myStats.integer && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "mystats" ) );
- count++;
- }
- if( ent && ent->client->pers.designatedBuilder && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "protect" ) );
- count++;
- }
- if( ent && ent->client->pers.designatedBuilder && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "resign" ) );
- count++;
- }
- if( g_publicSayadmins.integer || G_admin_permission( ent, ADMF_ADMINCHAT ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "say_admins" ) );
- count++;
- }
- if( ent && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "say_area" ) );
- count++;
- }
- if( ent && g_allowShare.integer && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "share" ) );
- count++;
- }
- if( ent && g_teamStatus.integer && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "teamstatus" ) );
- count++;
- }
- ADMBP( "\n" );
+ ADMBP( va( "^3adminhelp: ^7%i available commands\n", count ) );
+ ADMBP( "run adminhelp [^3command^7] for adminhelp with a specific command.\n" );
ADMBP_end();
return qtrue;
}
else
{
- //!help param
+ // adminhelp param
char param[ MAX_ADMIN_CMD_LEN ];
- char *cmd;
+ g_admin_cmd_t *admincmd;
+ qboolean denied = qfalse;
- G_SayArgv( 1 + skiparg, param, sizeof( param ) );
- cmd = ( param[0] == '!' ) ? &param[1] : &param[0];
+ trap_Argv( 1, param, sizeof( param ) );
ADMBP_begin();
- for( i = 0; i < adminNumCmds; i++ )
+ if( ( c = G_admin_command( param ) ) )
{
- if( !Q_stricmp( cmd, g_admin_cmds[ i ].keyword ) )
+ if( G_admin_permission( ent, c->flag ) )
{
- if( !G_admin_permission( ent, g_admin_cmds[ i ].flag ) )
- {
- ADMBP( va( "^3!help: ^7you have no permission to use '%s'\n",
- g_admin_cmds[ i ].keyword ) );
- ADMBP_end();
- return qfalse;
- }
- ADMBP( va( "^3!help: ^7help for '!%s':\n",
- g_admin_cmds[ i ].keyword ) );
- ADMBP( va( " ^3Function: ^7%s\n", g_admin_cmds[ i ].function ) );
- ADMBP( va( " ^3Syntax: ^7!%s %s\n", g_admin_cmds[ i ].keyword,
- g_admin_cmds[ i ].syntax ) );
- ADMBP( va( " ^3Flag: ^7'%s'\n", g_admin_cmds[ i ].flag ) );
- ADMBP_end();
+ ADMBP( va( "^3adminhelp: ^7help for '%s':\n", c->command ) );
+ ADMBP( va( " ^3Description: ^7%s\n", c->desc ) );
+ ADMBP( va( " ^3Syntax: ^7%s\n", c->command ) );
+ ADMBP( va( " ^3Flag: ^7'%s'\n", c->flag ) );
+ ADMBP_end( );
return qtrue;
}
+ denied = qtrue;
}
- for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
+ if( ( admincmd = G_admin_cmd( param ) ) )
{
- if( !Q_stricmp( cmd, g_admin_commands[ i ]->command ) )
+ if( G_admin_permission( ent, admincmd->flag ) )
{
- if( !G_admin_permission( ent, g_admin_commands[ i ]->flag ) )
- {
- ADMBP( va( "^3!help: ^7you have no permission to use '%s'\n",
- g_admin_commands[ i ]->command ) );
- ADMBP_end();
- return qfalse;
- }
- ADMBP( va( "^3!help: ^7help for '%s':\n",
- g_admin_commands[ i ]->command ) );
- ADMBP( va( " ^3Description: ^7%s\n", g_admin_commands[ i ]->desc ) );
- ADMBP( va( " ^3Syntax: ^7!%s\n", g_admin_commands[ i ]->command ) );
+ ADMBP( va( "^3adminhelp: ^7help for '%s':\n", admincmd->keyword ) );
+ ADMBP( va( " ^3Description: ^7%s\n", admincmd->function ) );
+ ADMBP( va( " ^3Syntax: ^7%s %s\n", admincmd->keyword,
+ admincmd->syntax ) );
+ ADMBP( va( " ^3Flag: ^7'%s'\n", admincmd->flag ) );
ADMBP_end();
return qtrue;
}
+ denied = qtrue;
}
- ADMBP( va( "^3!help: ^7no help found for '%s'\n", cmd ) );
- ADMBP_end();
+ ADMBP( va( "^3adminhelp: ^7%s '%s'\n",
+ denied ? "you do not have permission to use" : "no help found for",
+ param ) );
+ ADMBP_end( );
return qfalse;
}
}
-qboolean G_admin_admintest( gentity_t *ent, int skiparg )
+qboolean G_admin_admintest( gentity_t *ent )
{
- int i, l = 0;
- qboolean found = qfalse;
- qboolean lname = qfalse;
+ g_admin_level_t *l;
if( !ent )
{
- ADMP( "^3!admintest: ^7you are on the console.\n" );
+ ADMP( "^3admintest: ^7you are on the console.\n" );
return qtrue;
}
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( g_admin_admins[ i ]->guid, ent->client->pers.guid ) )
- {
- found = qtrue;
- break;
- }
- }
- if( found )
- {
- l = g_admin_admins[ i ]->level;
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- if( g_admin_levels[ i ]->level != l )
- continue;
- if( *g_admin_levels[ i ]->name )
- {
- lname = qtrue;
- break;
- }
- }
- }
- AP( va( "print \"^3!admintest: ^7%s^7 is a level %d admin %s%s^7%s\n\"",
+ l = G_admin_level( ent->client->pers.admin ? ent->client->pers.admin->level : 0 );
+
+ AP( va( "print \"^3admintest: ^7%s^7 is a level %d admin %s%s^7%s\n\"",
ent->client->pers.netname,
- l,
- ( lname ) ? "(" : "",
- ( lname ) ? g_admin_levels[ i ]->name : "",
- ( lname ) ? ")" : "" ) );
+ l ? l->level : 0,
+ l ? "(" : "",
+ l ? l->name : "",
+ l ? ")" : "" ) );
return qtrue;
}
-qboolean G_admin_allready( gentity_t *ent, int skiparg )
+qboolean G_admin_allready( gentity_t *ent )
{
int i = 0;
gclient_t *cl;
if( !level.intermissiontime )
{
- ADMP( "^3!allready: ^7this command is only valid during intermission\n" );
+ ADMP( "^3allready: ^7this command is only valid during intermission\n" );
return qfalse;
}
@@ -5691,233 +2667,54 @@ qboolean G_admin_allready( gentity_t *ent, int skiparg )
if( cl->pers.connected != CON_CONNECTED )
continue;
- if( cl->pers.teamSelection == PTE_NONE )
+ if( cl->pers.teamSelection == TEAM_NONE )
continue;
- cl->readyToExit = 1;
- }
- AP( va( "print \"^3!allready:^7 %s^7 says everyone is READY now\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- return qtrue;
-}
-
-qboolean G_admin_cancelvote( gentity_t *ent, int skiparg )
-{
-
- if(!level.voteTime && !level.teamVoteTime[ 0 ] && !level.teamVoteTime[ 1 ] )
- {
- ADMP( "^3!cancelvote^7: no vote in progress\n" );
- return qfalse;
- }
- level.voteNo = level.numConnectedClients;
- level.voteYes = 0;
- CheckVote( );
- level.teamVoteNo[ 0 ] = level.numConnectedClients;
- level.teamVoteYes[ 0 ] = 0;
- CheckTeamVote( PTE_HUMANS );
- level.teamVoteNo[ 1 ] = level.numConnectedClients;
- level.teamVoteYes[ 1 ] = 0;
- CheckTeamVote( PTE_ALIENS );
- AP( va( "print \"^3!cancelvote: ^7%s^7 decided that everyone voted No\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- return qtrue;
-}
-
-qboolean G_admin_passvote( gentity_t *ent, int skiparg )
-{
- if(!level.voteTime && !level.teamVoteTime[ 0 ] && !level.teamVoteTime[ 1 ] )
- {
- ADMP( "^3!passvote^7: no vote in progress\n" );
- return qfalse;
+ cl->readyToExit = qtrue;
}
- level.voteYes = level.numConnectedClients;
- level.voteNo = 0;
- CheckVote( );
- level.teamVoteYes[ 0 ] = level.numConnectedClients;
- level.teamVoteNo[ 0 ] = 0;
- CheckTeamVote( PTE_HUMANS );
- level.teamVoteYes[ 1 ] = level.numConnectedClients;
- level.teamVoteNo[ 1 ] = 0;
- CheckTeamVote( PTE_ALIENS );
- AP( va( "print \"^3!passvote: ^7%s^7 decided that everyone voted Yes\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
+ AP( va( "print \"^3allready:^7 %s^7 says everyone is READY now\n\"",
+ ( ent ) ? ent->client->pers.netname : "console" ) );
return qtrue;
}
-static qboolean G_admin_global_pause( gentity_t *ent, int skiparg )
+qboolean G_admin_endvote( gentity_t *ent )
{
- if( level.paused )
- {
- level.pauseTime = level.time;
- ADMP( "^3!pause: ^7Game is already paused, unpause timer reset\n" );
- return qfalse;
- }
-
- level.paused = qtrue;
- level.pauseTime = level.time;
-
- level.pause_speed = g_speed.value;
- level.pause_gravity = g_gravity.value;
- level.pause_knockback = g_knockback.value;
- level.pause_ff = g_friendlyFire.integer;
- level.pause_ffb = g_friendlyBuildableFire.integer;
-
- g_speed.value = 0;
- g_gravity.value = 0;
- g_knockback.value = 0;
- g_friendlyFire.integer = 0;
- g_friendlyBuildableFire.integer = 0;
-
- CP( "cp \"^1Game is PAUSED\"" );
- AP( va( "print \"^3!pause: ^7The game has been paused by %s\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
-
- return qtrue;
-}
+ char teamName[ sizeof( "spectators" ) ] = {"s"};
+ char command[ MAX_ADMIN_CMD_LEN ];
+ team_t team;
+ qboolean cancel;
+ const char *msg;
-static qboolean G_admin_global_unpause( gentity_t *ent, int skiparg )
-{
- if( !level.paused )
+ trap_Argv( 0, command, sizeof( command ) );
+ cancel = !Q_stricmp( command, "cancelvote" );
+ if( trap_Argc() == 2 )
+ trap_Argv( 1, teamName, sizeof( teamName ) );
+ team = G_TeamFromString( teamName );
+ if( team == NUM_TEAMS )
{
- ADMP( "^3!unpause: ^7Game is not paused\n" );
+ ADMP( va( "^3%s: ^7invalid team '%s'\n", command, teamName ) );
return qfalse;
}
-
- level.paused = qfalse;
-
- g_speed.value = level.pause_speed;
- g_gravity.value = level.pause_gravity;
- g_knockback.value = level.pause_knockback;
- g_friendlyFire.integer = level.pause_ff;
- g_friendlyBuildableFire.integer = level.pause_ffb;
-
- CP( "cp \"^2Game is RESUMED\"" );
- AP( va( "print \"^3!unpause: ^7The game has been resumed by %s\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
-
- return qtrue;
-}
-
-static qboolean is_numeric(const char *str)
-{
- const char *p;
-
- if (!*str)
- return qfalse;
-
- for (p = str; *p; p++)
- if (*p < '0' || *p > '9')
- return qfalse;
-
- return qtrue;
-}
-
-qboolean G_admin_pause( gentity_t *ent, int skiparg )
-{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
- char command[ MAX_ADMIN_CMD_LEN ], *cmd;
- int i;
- int count = 0;
- gentity_t *vic;
-
- G_SayArgv( skiparg, command, sizeof( command ) );
- cmd = command;
- if( cmd && *cmd == '!' )
- cmd++;
-
- if( G_SayArgc() < 2 + skiparg )
- {
- // global pause
- if( !Q_stricmp( cmd, "pause" ) )
- return G_admin_global_pause( ent, skiparg );
- else
- return G_admin_global_unpause( ent, skiparg );
- }
- if( G_SayArgc() != 2 + skiparg )
+ msg = va( "print \"^3%s: ^7%s^7 decided that everyone voted %s\n\"",
+ command, ( ent ) ? ent->client->pers.netname : "console",
+ cancel ? "No" : "Yes" );
+ if( !level.voteTime[ team ] )
{
- ADMP( va( "^3!%s: ^7usage: !%s (^5name|slot|*^7)\n", cmd, cmd ) );
+ ADMP( va( "^3%s: ^7no vote in progress\n", command ) );
return qfalse;
}
-
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( !Q_stricmp( name, "*" ) )
- {
- for( i = 0; i < MAX_CLIENTS; i++ )
- {
- vic = &g_entities[ i ];
- if( vic && vic->client &&
- vic->client->pers.connected == CON_CONNECTED )
- {
- pids[ count ] = i;
- count++;
- }
- }
- }
+ admin_log( BG_TeamName( team ) );
+ level.voteNo[ team ] = cancel ? level.numVotingClients[ team ] : 0;
+ level.voteYes[ team ] = cancel ? 0 : level.numVotingClients[ team ];
+ G_CheckVote( team );
+ if( team == TEAM_NONE )
+ AP( msg );
else
- {
- if( G_ClientNumbersFromString( name, pids ) != 1 )
- {
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!%s: ^7%s\n", cmd, err ) );
- return qfalse;
- }
- count = 1;
- }
-
- for( i = 0; i < count; i++ )
- {
- vic = &g_entities[ pids[ i ] ];
- if ( !vic || !vic->client ) continue;
- if( !admin_higher( ent, vic ) )
- {
- if( count == 1 )
- ADMP( va( "^3!%s: ^7sorry, but your intended victim has a higher admin"
- " level than you\n", cmd ) );
- continue;
- }
- if( vic->client->pers.paused )
- {
- if( !Q_stricmp( cmd, "pause" ) )
- {
- if( count == 1 )
- ADMP( "^3!pause: ^7player is already paused\n" );
- continue;
- }
- vic->client->pers.paused = qfalse;
- CPx( pids[ i ], "cp \"^2You've been unpaused\"" );
- if( count == 1 )
- AP( va( "print \"^3!unpause: ^7%s^7 unpaused by %s\n\"",
- vic->client->pers.netname,
- ( ent ) ? ent->client->pers.netname : "console" ) );
- }
- else
- {
- if( !Q_stricmp( cmd, "unpause" ) )
- {
- if( count == 1 )
- ADMP( "^3!unpause: ^7player is already unpaused\n" );
- continue;
- }
- if( count == 1 && ent == vic)
- {
- ADMP( "^3!pause: ^7you can not pause yourself\n" );
- continue;
- }
- vic->client->pers.paused = qtrue;
- CPx( pids[ i ], va( "cp \"^1You've been paused by ^7%s\"",
- ( ent ) ? ent->client->pers.netname : "console" ) );
- if( count == 1 )
- AP( va( "print \"^3!pause: ^7%s^7 paused by %s\n\"",
- vic->client->pers.netname,
- ( ent ) ? ent->client->pers.netname : "console" ) );
- }
- ClientUserinfoChanged( pids[ i ], qfalse );
- }
+ G_TeamCommand( team, msg );
return qtrue;
}
-qboolean G_admin_spec999( gentity_t *ent, int skiparg )
+qboolean G_admin_spec999( gentity_t *ent )
{
int i;
gentity_t *vic;
@@ -5929,146 +2726,186 @@ qboolean G_admin_spec999( gentity_t *ent, int skiparg )
continue;
if( vic->client->pers.connected != CON_CONNECTED )
continue;
- if( vic->client->pers.teamSelection == PTE_NONE )
+ if( vic->client->pers.teamSelection == TEAM_NONE )
continue;
if( vic->client->ps.ping == 999 )
{
- G_ChangeTeam( vic, PTE_NONE );
- AP( va( "print \"^3!spec999: ^7%s^7 moved ^7%s^7 to spectators\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
+ G_ChangeTeam( vic, TEAM_NONE );
+ AP( va( "print \"^3spec999: ^7%s^7 moved %s^7 to spectators\n\"",
+ ( ent ) ? ent->client->pers.netname : "console",
vic->client->pers.netname ) );
}
}
return qtrue;
}
+
+qboolean G_admin_transform( gentity_t *ent )
+{
+ int pid;
+ char name[ MAX_NAME_LENGTH ];
+ char modelname[ MAX_NAME_LENGTH ];
+ char skin[ MAX_NAME_LENGTH ];
+ char err[ MAX_STRING_CHARS ];
+ char userinfo[ MAX_INFO_STRING ];
+ gentity_t *victim = NULL;
+ int i;
+ qboolean found = qfalse;
+
+ if (trap_Argc() < 3)
+ {
+ ADMP("^3transform: ^7usage: transform [name|slot#] [model] <skin>\n");
+ return qfalse;
+ }
-qboolean G_admin_register(gentity_t *ent, int skiparg ){
- int level = 0;
+ trap_Argv(1, name, sizeof(name));
+ trap_Argv(2, modelname, sizeof(modelname));
- if( !ent ) return qtrue;
+ strcpy(skin, "default");
+ if (trap_Argc() >= 4)
+ {
+ trap_Argv(1, skin, sizeof(skin));
+ }
- level = G_admin_level(ent);
+ pid = G_ClientNumberFromString(name, err, sizeof(err));
+ if (pid == -1)
+ {
+ ADMP(va("^3transform: ^7%s", err));
+ return qfalse;
+ }
- if( level == 0 )
- level = 1;
-
- if( !Q_stricmp( ent->client->pers.guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ) )
+ victim = &g_entities[ pid ];
+ if (victim->client->pers.connected != CON_CONNECTED)
{
- ADMP( va( "^3!register: ^7 You cannot register for name protection until you update your client. Please replace your client executable with the one at http://trem.tjw.org/backport/ and reconnect. Updating your client will also allow you to have faster map downloads.\n" ) );
+ ADMP("^3transform: ^7sorry, but your intended victim is still connecting\n");
return qfalse;
}
- if( g_newbieNumbering.integer
- && g_newbieNamePrefix.string[ 0 ]
- && !Q_stricmpn ( ent->client->pers.netname, g_newbieNamePrefix.string, strlen(g_newbieNamePrefix.string ) ) )
+ for ( i = 0; i < level.playerModelCount; i++ )
{
- ADMP( va( "^3!register: ^7 You cannot register names that begin with '%s^7'.\n",
- g_newbieNamePrefix.string ) );
+ if ( !strcmp(modelname, level.playerModel[i]) )
+ {
+ found = qtrue;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ ADMP(va("^3transform: ^7no matching model %s\n", modelname));
return qfalse;
}
- trap_SendConsoleCommand( EXEC_APPEND,va( "!setlevel %d %d;",ent - g_entities, level) );
-
- AP( va( "print \"^3!register: ^7%s^7 is now a protected nickname.\n\"", ent->client->pers.netname) );
-
+ trap_GetUserinfo(pid, userinfo, sizeof(userinfo));
+ AP( va("print \"^3transform: ^7%s^7 has been changed into %s^7 by %s\n\"",
+ victim->client->pers.netname, modelname,
+ (ent ? ent->client->pers.netname : "console")) );
+
+ Info_SetValueForKey( userinfo, "model", modelname );
+ Info_SetValueForKey( userinfo, "skin", GetSkin(modelname, skin));
+ Info_SetValueForKey( userinfo, "voice", modelname );
+ trap_SetUserinfo( pid, userinfo );
+ ClientUserinfoChanged( pid, qtrue );
+
return qtrue;
}
-qboolean G_admin_rename( gentity_t *ent, int skiparg )
+qboolean G_admin_rename( gentity_t *ent )
{
- int pids[ MAX_CLIENTS ];
+ int pid;
char name[ MAX_NAME_LENGTH ];
char newname[ MAX_NAME_LENGTH ];
- char oldname[ MAX_NAME_LENGTH ];
char err[ MAX_STRING_CHARS ];
char userinfo[ MAX_INFO_STRING ];
- char *s;
gentity_t *victim = NULL;
- if( G_SayArgc() < 3 + skiparg )
+ if( trap_Argc() < 3 )
{
- ADMP( "^3!rename: ^7usage: !rename [name] [newname]\n" );
+ ADMP( "^3rename: ^7usage: rename [name] [newname]\n" );
return qfalse;
}
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- s = G_SayConcatArgs( 2 + skiparg );
- Q_strncpyz( newname, s, sizeof( newname ) );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
+ trap_Argv( 1, name, sizeof( name ) );
+ Q_strncpyz( newname, ConcatArgs( 2 ), sizeof( newname ) );
+ if( ( pid = G_ClientNumberFromString( name, err, sizeof( err ) ) ) == -1 )
{
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!rename: ^7%s\n", err ) );
+ ADMP( va( "^3rename: ^7%s", err ) );
return qfalse;
}
- victim = &g_entities[ pids[ 0 ] ] ;
+ victim = &g_entities[ pid ];
if( !admin_higher( ent, victim ) )
{
- ADMP( "^3!rename: ^7sorry, but your intended victim has a higher admin"
+ ADMP( "^3rename: ^7sorry, but your intended victim has a higher admin"
" level than you\n" );
return qfalse;
}
if( !G_admin_name_check( victim, newname, err, sizeof( err ) ) )
{
- G_admin_print( ent, va( "^3!rename: Invalid name: ^7%s\n", err ) );
+ ADMP( va( "^3rename: ^7%s\n", err ) );
+ return qfalse;
+ }
+ if( victim->client->pers.connected != CON_CONNECTED )
+ {
+ ADMP( "^3rename: ^7sorry, but your intended victim is still connecting\n" );
return qfalse;
}
- level.clients[ pids[ 0 ] ].pers.nameChanges--;
- level.clients[ pids[ 0 ] ].pers.nameChangeTime = 0;
- trap_GetUserinfo( pids[ 0 ], userinfo, sizeof( userinfo ) );
- s = Info_ValueForKey( userinfo, "name" );
- Q_strncpyz( oldname, s, sizeof( oldname ) );
+ admin_log( va( "%d (%s) \"%s" S_COLOR_WHITE "\"", pid,
+ victim->client->pers.guid, victim->client->pers.netname ) );
+ admin_log( newname );
+ trap_GetUserinfo( pid, userinfo, sizeof( userinfo ) );
+ AP( va( "print \"^3rename: ^7%s^7 has been renamed to %s^7 by %s\n\"",
+ victim->client->pers.netname,
+ newname,
+ ( ent ) ? ent->client->pers.netname : "console" ) );
Info_SetValueForKey( userinfo, "name", newname );
- trap_SetUserinfo( pids[ 0 ], userinfo );
- ClientUserinfoChanged( pids[ 0 ], qtrue );
- if( strcmp( oldname, level.clients[ pids[ 0 ] ].pers.netname ) )
- AP( va( "print \"^3!rename: ^7%s^7 has been renamed to %s^7 by %s\n\"",
- oldname,
- level.clients[ pids[ 0 ] ].pers.netname,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
+ trap_SetUserinfo( pid, userinfo );
+ ClientUserinfoChanged( pid, qtrue );
return qtrue;
}
-qboolean G_admin_restart( gentity_t *ent, int skiparg )
+qboolean G_admin_restart( gentity_t *ent )
{
- char layout[ MAX_CVAR_VALUE_STRING ] = { "" };
- char teampref[ MAX_CVAR_VALUE_STRING ] = { "" };
- int i;
+ char layout[ MAX_CVAR_VALUE_STRING ] = { "" };
+ char teampref[ MAX_STRING_CHARS ] = { "" };
+ char map[ MAX_CVAR_VALUE_STRING ];
+ int i;
gclient_t *cl;
- if( G_SayArgc( ) > 1 + skiparg )
+ if( trap_Argc( ) > 1 )
{
char map[ MAX_QPATH ];
trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
- G_SayArgv( skiparg + 1, layout, sizeof( layout ) );
+ trap_Argv( 1, layout, sizeof( layout ) );
- if( Q_stricmp( layout, "keepteams" ) && Q_stricmp( layout, "keepteamslock" ) && Q_stricmp( layout, "switchteams" ) && Q_stricmp( layout, "switchteamslock" ) )
+ // Figure out which argument is which
+ if( Q_stricmp( layout, "keepteams" ) &&
+ Q_stricmp( layout, "keepteamslock" ) &&
+ Q_stricmp( layout, "switchteams" ) &&
+ Q_stricmp( layout, "switchteamslock" ) )
{
- if( !Q_stricmp( layout, "*BUILTIN*" ) ||
- trap_FS_FOpenFile( va( "layouts/%s/%s.dat", map, layout ),
- NULL, FS_READ ) > 0 )
+ if( G_LayoutExists( map, layout ) )
{
- trap_Cvar_Set( "g_layouts", layout );
+ trap_Cvar_Set( "g_nextLayout", layout );
}
else
{
- ADMP( va( "^3!restart: ^7layout '%s' does not exist\n", layout ) );
+ ADMP( va( "^3restart: ^7layout '%s' does not exist\n", layout ) );
return qfalse;
}
}
- else
+ else
{
- strcpy(layout,"");
- G_SayArgv( skiparg + 1, teampref, sizeof( teampref ) );
+ layout[ 0 ] = '\0';
+ trap_Argv( 1, teampref, sizeof( teampref ) );
}
}
-
- if( G_SayArgc( ) > 2 + skiparg )
- {
- G_SayArgv( skiparg + 2, teampref, sizeof( teampref ) );
- }
-
-
- if( !Q_stricmp( teampref, "keepteams" ) || !Q_stricmp( teampref, "keepteamslock" ) )
+
+ if( trap_Argc( ) > 2 )
+ trap_Argv( 2, teampref, sizeof( teampref ) );
+
+ admin_log( layout );
+ admin_log( teampref );
+
+ if( !Q_stricmpn( teampref, "keepteams", 9 ) )
{
for( i = 0; i < g_maxclients.integer; i++ )
{
@@ -6076,2349 +2913,716 @@ qboolean G_admin_restart( gentity_t *ent, int skiparg )
if( cl->pers.connected != CON_CONNECTED )
continue;
- if( cl->pers.teamSelection == PTE_NONE )
+ if( cl->pers.teamSelection == TEAM_NONE )
continue;
cl->sess.restartTeam = cl->pers.teamSelection;
}
- }
- else if(!Q_stricmp( teampref, "switchteams" ) || !Q_stricmp( teampref, "switchteamslock" ))
+ }
+ else if( !Q_stricmpn( teampref, "switchteams", 11 ) )
{
for( i = 0; i < g_maxclients.integer; i++ )
{
cl = level.clients + i;
- if( cl->pers.connected != CON_CONNECTED )
- continue;
- if( cl->pers.teamSelection == PTE_NONE )
+ if( cl->pers.connected != CON_CONNECTED )
continue;
- if( cl->pers.teamSelection == PTE_ALIENS )
- cl->sess.restartTeam = PTE_HUMANS;
- else if(cl->pers.teamSelection == PTE_HUMANS )
- cl->sess.restartTeam = PTE_ALIENS;
- }
+ if( cl->pers.teamSelection == TEAM_HUMANS )
+ cl->sess.restartTeam = TEAM_ALIENS;
+ else if(cl->pers.teamSelection == TEAM_ALIENS )
+ cl->sess.restartTeam = TEAM_HUMANS;
+ }
}
-
- if( !Q_stricmp( teampref, "switchteamslock" ) || !Q_stricmp( teampref, "keepteamslock" ) )
- {
+
+ if( !Q_stricmp( teampref, "switchteamslock" ) ||
+ !Q_stricmp( teampref, "keepteamslock" ) )
trap_Cvar_Set( "g_lockTeamsAtStart", "1" );
- }
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart" );
-
- if(teampref[ 0 ])
- strcpy(teampref,va( "^7(with teams option: '%s^7')", teampref ));
-
- G_admin_maplog_result( "R" );
-
- AP( va( "print \"^3!restart: ^7map restarted by %s %s %s\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
+ trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
+ G_MapConfigs( map );
+ trap_SendConsoleCommand( EXEC_APPEND, "map_restart\n" );
+
+ AP( va( "print \"^3restart: ^7map restarted by %s %s %s\n\"",
+ ( ent ) ? ent->client->pers.netname : "console",
( layout[ 0 ] ) ? va( "^7(forcing layout '%s^7')", layout ) : "",
- teampref ) );
+ ( teampref[ 0 ] ) ? va( "^7(with teams option: '%s^7')", teampref ) : "" ) );
return qtrue;
}
-qboolean G_admin_nobuild( gentity_t *ent, int skiparg )
+qboolean G_admin_nextmap( gentity_t *ent )
{
- char buffer[ MAX_STRING_CHARS ];
- int i, tmp;
-
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( "^3!nobuild: ^7usage: !nobuild (^5enable / disable / log / remove / save^7)\n" );
+ if( level.exited )
return qfalse;
- }
-
- G_SayArgv( 1 + skiparg, buffer, sizeof( buffer ) );
-
- if( !Q_stricmp( buffer, "enable" ) || !Q_stricmp( buffer, "Enable" ) )
- {
- if( G_SayArgc() < 4 + skiparg )
- {
- ADMP( "^3!nobuild: ^7usage: !nobuild enable (^5area^7) (^5height^7)\n" );
- return qfalse;
- }
-
- if( !level.noBuilding )
- {
-
- level.noBuilding = qtrue;
-
- // Grab and set the area
- G_SayArgv( 2 + skiparg, buffer, sizeof( buffer ) );
- tmp = atoi( buffer );
- level.nbArea = tmp;
-
- // Grab and set the height
- G_SayArgv( 3 + skiparg, buffer, sizeof( buffer ) );
- tmp = atoi( buffer );
- level.nbHeight = tmp;
-
- ADMP( "^3!nobuild: ^7nobuild is now enabled, please place a buildable to spawn a marker\n" );
- return qtrue;
- }
- else
- {
- ADMP( "^3!nobuild: ^7nobuild is already enabled. type !nobuild disable to disable nobuild mode.\n" );
- return qfalse;
- }
- }
-
- if( !Q_stricmp( buffer, "disable" ) || !Q_stricmp( buffer, "Disable" ) )
- {
- if( level.noBuilding )
- {
- level.noBuilding = qfalse;
- level.nbArea = 0.0f;
- level.nbHeight = 0.0f;
- ADMP( "^3!nobuild: ^7nobuild is now disabled\n" );
- return qtrue;
- }
- else
- {
- ADMP( "^3!nobuild: ^7nobuild is disabled. type !nobuild enable (^5area^7) (^5height^7) to enable nobuild mode.\n" );
- return qfalse;
- }
- }
-
- if( !Q_stricmp( buffer, "log" ) || !Q_stricmp( buffer, "Log" ) )
- {
- ADMBP_begin();
-
- tmp = 0;
- for( i = 0; i < MAX_GENTITIES; i++ )
- {
- if( level.nbMarkers[ i ].Marker == NULL )
- continue;
-
- // This will display a start at 1, and not 0. This is to stop confusion by server ops
- ADMBP( va( "^7#%i at origin (^5%f %f %f^7)^7\n", i + 1, level.nbMarkers[ i ].Origin[0], level.nbMarkers[ i ].Origin[1], level.nbMarkers[ i ].Origin[2] ) );
- tmp++;
- }
- ADMBP( va( "^3!nobuild:^7 displaying %i marker(s)\n", tmp ) );
-
- ADMBP_end();
- return qtrue;
- }
-
- if( !Q_stricmp( buffer, "remove" ) || !Q_stricmp( buffer, "Remove" ) )
- {
- if( G_SayArgc() < 3 + skiparg )
- {
- ADMP( "^3!nobuild: ^7usage: !nobuild remove (^5marker #^7)\n" );
- return qfalse;
- }
-
- G_SayArgv( 2 + skiparg, buffer, sizeof( buffer ) );
- tmp = atoi( buffer ) - 1;
- // ^ that was to work with the display number...
-
- if( level.nbMarkers[ tmp ].Marker == NULL )
- {
- ADMP( "^3!nobuild: ^7that is not a valid marker number\n" );
- return qfalse;
- }
- // Donno why im doing this, but lets clear this...
- level.nbMarkers[ tmp ].Marker->noBuild.isNB = qfalse;
- level.nbMarkers[ tmp ].Marker->noBuild.Area = 0.0f;
- level.nbMarkers[ tmp ].Marker->noBuild.Height = 0.0f;
-
- // Free the entitiy and null it out...
- G_FreeEntity( level.nbMarkers[ tmp ].Marker );
- level.nbMarkers[ tmp ].Marker = NULL;
-
- // That is to work with the display number...
- ADMP( va( "^3!nobuild:^7 marker %i has been removed\n", tmp + 1 ) );
- return qtrue;
- }
-
- if( !Q_stricmp( buffer, "save" ) || !Q_stricmp( buffer, "Save" ) )
- {
- int i, tmp;
-
- G_NobuildSave( );
-
- tmp = 0;
- for( i = 0; i < MAX_GENTITIES; i++ )
- {
- if( level.nbMarkers[ i ].Marker == NULL )
- continue;
-
- tmp++;
- }
- ADMP( va( "^3!nobuild:^7 %i nobuild markers have been saved\n", tmp ) );
- return qtrue;
- }
- return qfalse;
-}
-
-qboolean G_admin_nextmap( gentity_t *ent, int skiparg )
-{
- AP( va( "print \"^3!nextmap: ^7%s^7 decided to load the next map\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- level.lastWin = PTE_NONE;
+ AP( va( "print \"^3nextmap: ^7%s^7 decided to load the next map\n\"",
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ level.lastWin = TEAM_NONE;
trap_SetConfigstring( CS_WINNER, "Evacuation" );
LogExit( va( "nextmap was run by %s",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- G_admin_maplog_result( "N" );
+ ( ent ) ? ent->client->pers.netname : "console" ) );
return qtrue;
}
-static const char *displaySchachtmeisterJudgement(const schachtmeisterJudgement_t *j,
- g_admin_namelog_t *namelog)
-{
- static char buffer[20];
-
- if (G_admin_permission_guid(namelog->guid, ADMF_INCOGNITO)) {
- Com_sprintf(buffer, sizeof(buffer), "^2 +0");
- } else if (strcmp(namelog->guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") &&
- (G_admin_permission_guid(namelog->guid, ADMF_NOAUTOBAHN) ||
- G_admin_permission_guid(namelog->guid, ADMF_IMMUNITY))) {
- Com_sprintf(buffer, sizeof(buffer), "^7 N/A ");
- } else if (!j->ratingTime) {
- Com_sprintf(buffer, sizeof(buffer), "^5 wait");
- } else {
- int color;
-
- if (j->rating >= g_schachtmeisterClearThreshold.integer)
- color = 2;
- else if (j->rating <= g_schachtmeisterAutobahnThreshold.integer)
- color = 1;
- else
- color = 3;
-
- Com_sprintf(buffer, sizeof(buffer), "^%i%+5i", color, j->rating);
- }
-
- return buffer;
-}
-
-qboolean G_admin_namelog( gentity_t *ent, int skiparg )
+qboolean G_admin_setnextmap( gentity_t *ent )
{
- int i, j;
- char search[ MAX_NAME_LENGTH ] = {""};
- char s2[ MAX_NAME_LENGTH ] = {""};
- char n2[ MAX_NAME_LENGTH ] = {""};
- char guid_stub[ 9 ];
- qboolean found = qfalse;
- int printed = 0;
+ int argc = trap_Argc();
+ char map[ MAX_QPATH ];
+ char layout[ MAX_QPATH ];
- if( G_SayArgc() > 1 + skiparg )
+ if( argc < 2 || argc > 3 )
{
- G_SayArgv( 1 + skiparg, search, sizeof( search ) );
- G_SanitiseString( search, s2, sizeof( s2 ) );
+ ADMP( "^3setnextmap: ^7usage: setnextmap [map] (layout)\n" );
+ return qfalse;
}
- ADMBP_begin();
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- {
- if( search[0] )
- {
- found = qfalse;
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
- g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
- {
- G_SanitiseString( g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
- if( strstr( n2, s2 ) )
- {
- found = qtrue;
- break;
- }
- }
- if( !found )
- continue;
- }
- printed++;
- for( j = 0; j < 8; j++ )
- guid_stub[ j ] = g_admin_namelog[ i ]->guid[ j + 24 ];
- guid_stub[ j ] = '\0';
- if( g_admin_namelog[ i ]->slot > -1 )
- ADMBP( "^3" );
- ADMBP( va( "%-2s (*%s) %15s %s^7",
- (g_admin_namelog[ i ]->slot > -1 ) ?
- va( "%d", g_admin_namelog[ i ]->slot ) : "-",
- guid_stub, g_admin_namelog[ i ]->ip,
- displaySchachtmeisterJudgement( &g_admin_namelog[ i ]->smj, g_admin_namelog[ i ] ) ) );
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
- g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
- {
- ADMBP( va( " '%s^7'", g_admin_namelog[ i ]->name[ j ] ) );
- }
- ADMBP( "\n" );
- }
- ADMBP( va( "^3!namelog:^7 %d recent clients found\n", printed ) );
- ADMBP_end();
- return qtrue;
-}
-qboolean G_admin_lock( gentity_t *ent, int skiparg )
-{
- char teamName[2] = {""};
- pTeam_t team;
+ trap_Argv( 1, map, sizeof( map ) );
- if( G_SayArgc() < 2 + skiparg )
+ if( !G_MapExists( map ) )
{
- ADMP( "^3!lock: ^7usage: !lock [a|h]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, teamName, sizeof( teamName ) );
- if( teamName[ 0 ] == 'a' || teamName[ 0 ] == 'A' )
- team = PTE_ALIENS;
- else if( teamName[ 0 ] == 'h' || teamName[ 0 ] == 'H' )
- team = PTE_HUMANS;
- else
- {
- ADMP( va( "^3!lock: ^7invalid team\"%c\"\n", teamName[0] ) );
+ ADMP( va( "^3setnextmap: ^7map '%s' does not exist\n", map ) );
return qfalse;
}
- if( team == PTE_ALIENS )
+ if( argc > 2 )
{
- if( level.alienTeamLocked )
- {
- ADMP( "^3!lock: ^7Alien team is already locked\n" );
- return qfalse;
- }
- else
- level.alienTeamLocked = qtrue;
- }
- else if( team == PTE_HUMANS ) {
- if( level.humanTeamLocked )
+ trap_Argv( 2, layout, sizeof( layout ) );
+
+ if( !G_LayoutExists( map, layout ) )
{
- ADMP( "^3!lock: ^7Human team is already locked\n" );
+ ADMP( va( "^3setnextmap: ^7layout '%s' does not exist for map '%s'\n", layout, map ) );
return qfalse;
}
- else
- level.humanTeamLocked = qtrue;
- }
- AP( va( "print \"^3!lock: ^7%s team has been locked by %s\n\"",
- ( team == PTE_ALIENS ) ? "Alien" : "Human",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- return qtrue;
-}
-
-qboolean G_admin_unlock( gentity_t *ent, int skiparg )
-{
- char teamName[2] = {""};
- pTeam_t team;
-
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( "^3!unlock: ^7usage: !unlock [a|h]\n" );
- return qfalse;
+ trap_Cvar_Set( "g_nextLayout", layout );
}
- G_SayArgv( 1 + skiparg, teamName, sizeof( teamName ) );
- if( teamName[ 0 ] == 'a' || teamName[ 0 ] == 'A' )
- team = PTE_ALIENS;
- else if( teamName[ 0 ] == 'h' || teamName[ 0 ] == 'H' )
- team = PTE_HUMANS;
else
- {
- ADMP( va( "^3!unlock: ^7invalid team\"%c\"\n", teamName[0] ) );
- return qfalse;
- }
-
- if( team == PTE_ALIENS )
- {
- if( !level.alienTeamLocked )
- {
- ADMP( "^3!unlock: ^7Alien team is not currently locked\n" );
- return qfalse;
- }
- else
- level.alienTeamLocked = qfalse;
- }
- else if( team == PTE_HUMANS ) {
- if( !level.humanTeamLocked )
- {
- ADMP( "^3!unlock: ^7Human team is not currently locked\n" );
- return qfalse;
- }
- else
- level.humanTeamLocked = qfalse;
- }
+ trap_Cvar_Set( "g_nextLayout", "" );
+
+ trap_Cvar_Set( "g_nextMap", map );
- AP( va( "print \"^3!unlock: ^7%s team has been unlocked by %s\n\"",
- ( team == PTE_ALIENS ) ? "Alien" : "Human",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
+ AP( va( "print \"^3setnextmap: ^7%s^7 has set the next map to '%s'%s\n\"",
+ ( ent ) ? ent->client->pers.netname : "console", map,
+ argc > 2 ? va( " with layout '%s'", layout ) : "" ) );
return qtrue;
-}
+}
-qboolean G_admin_designate( gentity_t *ent, int skiparg )
+static qboolean namelog_matchip( void *namelog, const void *ip )
{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
- char command[ MAX_ADMIN_CMD_LEN ], *cmd;
- gentity_t *vic;
-
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( "^3!designate: ^7usage: designate [name|slot#]\n" );
- return qfalse;
- }
- G_SayArgv( skiparg, command, sizeof( command ) );
- cmd = command;
- if( cmd && *cmd == '!' )
- cmd++;
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
- {
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!designate: ^7%s\n", err ) );
- return qfalse;
- }
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) &&
- !Q_stricmp( cmd, "undesignate" ) )
- {
- ADMP( "^3!designate: ^7sorry, but your intended victim has a higher admin"
- " level than you\n" );
- return qfalse;
- }
- vic = &g_entities[ pids[ 0 ] ];
- if( vic->client->pers.designatedBuilder == qtrue )
+ int i;
+ namelog_t *n = (namelog_t *)namelog;
+ for( i = 0; i < MAX_NAMELOG_ADDRS && n->ip[ i ].str[ 0 ]; i++ )
{
- if( !Q_stricmp( cmd, "designate" ) )
- {
- ADMP( "^3!designate: ^7player is already designated builder\n" );
+ if( G_AddressCompare( &n->ip[ i ], (addr_t *)ip ) ||
+ G_AddressCompare( (addr_t *)ip, &n->ip[ i ] ) )
return qtrue;
- }
- vic->client->pers.designatedBuilder = qfalse;
- CPx( pids[ 0 ], "cp \"^1Your designation has been revoked\"" );
- AP( va(
- "print \"^3!designate: ^7%s^7's designation has been revoked by %s\n\"",
- vic->client->pers.netname,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- G_CheckDBProtection( );
}
- else
+ return qfalse;
+}
+static qboolean namelog_matchname( void *namelog, const void *name )
+{
+ char match[ MAX_NAME_LENGTH ];
+ int i;
+ namelog_t *n = (namelog_t *)namelog;
+ for( i = 0; i < MAX_NAMELOG_NAMES && n->name[ i ][ 0 ]; i++ )
{
- if( !Q_stricmp( cmd, "undesignate" ) )
- {
- ADMP( "^3!undesignate: ^7player is not currently designated builder\n" );
+ G_SanitiseString( n->name[ i ], match, sizeof( match ) );
+ if( strstr( match, (const char *)name ) )
return qtrue;
- }
- vic->client->pers.designatedBuilder = qtrue;
- CPx( pids[ 0 ], "cp \"^1You've been designated\"" );
- AP( va( "print \"^3!designate: ^7%s^7 has been designated by ^7%s\n\"",
- vic->client->pers.netname,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
}
- return qtrue;
+ return qfalse;
}
+static void namelog_out( void *namelog, char *str )
+{
+ namelog_t *n = (namelog_t *)namelog;
+ char *p = str;
+ int l, l2 = MAX_STRING_CHARS, i;
+ const char *scolor;
- //!Warn by Gate (Daniel Evans)
-qboolean G_admin_warn( gentity_t *ent, int skiparg )
-{//mostly copy and paste with the proper lines altered from !mute and !kick
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], *reason, err[ MAX_STRING_CHARS ];
- int minargc;
- gentity_t *vic;
-
- minargc = 3 + skiparg;
- if( G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
- minargc = 2 + skiparg;
-
- if( G_SayArgc() < minargc )
+ if( n->slot > -1 )
{
- ADMP( "^3!warn: ^7usage: warn [name] [reason]\n" );
- return qfalse;
+ scolor = S_COLOR_YELLOW;
+ l = Q_snprintf( p, l2, "%s%-2d", scolor, n->slot );
+ p += l;
+ l2 -= l;
}
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- reason = G_SayConcatArgs( 2 + skiparg );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
- {
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!warn: ^7%s\n", err ) );
- return qfalse;
- }
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
+ else
{
- ADMP( "^3!warn: ^7sorry, but your intended victim has a higher admin"
- " level than you.\n" );
- return qfalse;
+ *p++ = '-';
+ *p++ = ' ';
+ *p = '\0';
+ l2 -= 2;
+ scolor = S_COLOR_WHITE;
}
-
- vic = &g_entities[ pids[ 0 ] ];
- //next line is the onscreen warning
- CPx( pids[ 0 ],va("cp \"^1You have been warned by an administrator.\n ^3Cease immediately or face admin action!\n^1 %s%s\"",(*reason)? "REASON: " : "" ,(*reason)? reason : "") );
- AP( va( "print \"^3!warn: ^7%s^7 has been warned to cease and desist: %s by %s \n\"",
- vic->client->pers.netname, (*reason) ? reason : "his current activity",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );//console announcement
- return qtrue;
-}
-
-qboolean G_admin_putmespec( gentity_t *ent, int skiparg )
-{
- if( !ent )
+
+ for( i = 0; i < MAX_NAMELOG_ADDRS && n->ip[ i ].str[ 0 ]; i++ )
{
- ADMP( "!specme: sorry, but console isn't allowed on the spectators team\n");
- return qfalse;
+ l = Q_snprintf( p, l2, " %s", n->ip[ i ].str );
+ p += l;
+ l2 -= l;
}
- if( level.paused )
+ for( i = 0; i < MAX_NAMELOG_NAMES && n->name[ i ][ 0 ]; i++ )
{
- ADMP("!specme: disabled when game is paused\n");
- return qfalse;
- }
-
- if(ent->client->pers.teamSelection == PTE_NONE)
- return qfalse;
-
- //guard against build timer exploit
- if( ent->client->pers.teamSelection != PTE_NONE && ent->client->sess.sessionTeam != TEAM_SPECTATOR &&
- ( ent->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0 ||
- ent->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0_UPG ||
- BG_InventoryContainsWeapon( WP_HBUILD, ent->client->ps.stats ) ||
- BG_InventoryContainsWeapon( WP_HBUILD2, ent->client->ps.stats ) ) &&
- ent->client->ps.stats[ STAT_MISC ] > 0 )
- {
- ADMP("!specme: You cannot leave your team until the build timer expires");
- return qfalse;
+ l = Q_snprintf( p, l2, " '" S_COLOR_WHITE "%s%s'%s", n->name[ i ], scolor,
+ i == n->nameOffset ? "*" : "" );
+ p += l;
+ l2 -= l;
}
-
- G_ChangeTeam( ent, PTE_NONE );
- AP( va("print \"^3!specme: ^7%s^7 decided to join the spectators\n\"", ent->client->pers.netname ) );
- return qtrue;
}
-
-qboolean G_admin_slap( gentity_t *ent, int skiparg )
+qboolean G_admin_namelog( gentity_t *ent )
{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
- gentity_t *vic;
- vec3_t dir;
-
- if( level.intermissiontime ) return qfalse;
+ char search[ MAX_NAME_LENGTH ] = {""};
+ char s2[ MAX_NAME_LENGTH ] = {""};
+ addr_t ip;
+ qboolean ipmatch = qfalse;
+ int start = MAX_CLIENTS, i;
- if( G_SayArgc() < 2 + skiparg )
+ if( trap_Argc() == 3 )
{
- ADMP( "^3!slap: ^7usage: !slap [name|slot#]\n" );
- return qfalse;
+ trap_Argv( 2, search, sizeof( search ) );
+ start = atoi( search );
}
-
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
+ if( trap_Argc() > 1 )
{
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!slap: ^7%s\n", err ) );
- return qfalse;
+ trap_Argv( 1, search, sizeof( search ) );
+ i = 0;
+ if( trap_Argc() == 2 )
+ for( i = search[ 0 ] == '-'; isdigit( search[ i ] ); i++ );
+ if( !search[ i ] )
+ start = atoi( search );
+ else if( !( ipmatch = G_AddressParse( search, &ip ) ) )
+ G_SanitiseString( search, s2, sizeof( s2 ) );
}
- vic = &g_entities[ pids[ 0 ] ];
- if( !vic )
- {
- ADMP( "^3!slap: ^7bad target\n" );
- return qfalse;
- }
- if( vic == ent )
- {
- ADMP( "^3!slap: ^7sorry, you cannot slap yourself\n" );
- return qfalse;
- }
- if( !admin_higher( ent, vic ) )
- {
- ADMP( "^3!slap: ^7sorry, but your intended victim has a higher admin"
- " level than you\n" );
- return qfalse;
- }
- if( vic->client->pers.teamSelection == PTE_NONE ||
- vic->client->pers.classSelection == PCL_NONE )
- {
- ADMP( "^3!slap: ^7can't slap spectators\n" );
- return qfalse;
- }
+ admin_search( ent, "namelog", "recent players",
+ ipmatch ? namelog_matchip : namelog_matchname, namelog_out, level.namelogs,
+ ipmatch ? (void *)&ip : s2, start, MAX_CLIENTS, MAX_ADMIN_LISTITEMS );
+ return qtrue;
+}
- // knockback in a random direction
- dir[0] = crandom();
- dir[1] = crandom();
- dir[2] = random();
- G_Knockback( vic, dir, g_slapKnockback.integer );
+/*
+==================
+G_NamelogFromString
- trap_SendServerCommand( vic-g_entities,
- va( "cp \"%s^7 is not amused\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
+This is similar to G_ClientNumberFromString but for namelog instead
+Returns NULL if not exactly 1 match
+==================
+*/
+namelog_t *G_NamelogFromString( gentity_t *ent, char *s )
+{
+ namelog_t *p, *m = NULL;
+ int i, found = 0;
+ char n2[ MAX_NAME_LENGTH ] = {""};
+ char s2[ MAX_NAME_LENGTH ] = {""};
- if( g_slapDamage.integer > 0 )
+ if( !s[ 0 ] )
+ return NULL;
+
+ // if a number is provided, it is a clientnum or namelog id
+ for( i = 0; s[ i ] && isdigit( s[ i ] ); i++ );
+ if( !s[ i ] )
{
- int damage;
+ i = atoi( s );
- if( G_SayArgc() > 2 + skiparg )
+ if( i >= 0 && i < level.maxclients )
{
- char dmg_str[ MAX_STRING_CHARS ];
- G_SayArgv( 2 + skiparg, dmg_str, sizeof( dmg_str ) );
- damage = atoi(dmg_str);
- if( damage < 0 ) damage = 0;
+ if( level.clients[ i ].pers.connected != CON_DISCONNECTED )
+ return level.clients[ i ].pers.namelog;
}
- else
+ else if( i >= MAX_CLIENTS )
{
- if( g_slapDamage.integer > 100 ) g_slapDamage.integer = 100;
- damage = BG_FindHealthForClass( vic->client->ps.stats[ STAT_PCLASS ] ) *
- g_slapDamage.integer / 100;
- if( damage < 1 ) damage = 1;
+ for( p = level.namelogs; p; p = p->next )
+ {
+ if( p->id == i )
+ break;
+ }
+ if( p )
+ return p;
}
- vic->health -= damage;
- vic->client->ps.stats[ STAT_HEALTH ] = vic->health;
- vic->lastDamageTime = level.time;
- if( vic->health <= 0 )
- {
- vic->flags |= FL_NO_KNOCKBACK;
- vic->enemy = &g_entities[ pids[ 0 ] ];
- vic->die( vic, ent, ent, damage, MOD_SLAP );
- }
- else if( vic->pain )
- {
- vic->pain( vic, &g_entities[ pids[ 0 ] ], damage );
- }
+ return NULL;
}
- return qtrue;
-}
-qboolean G_admin_drop( gentity_t *ent, int skiparg )
-{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
+ // check for a name match
+ G_SanitiseString( s, s2, sizeof( s2 ) );
- if( G_SayArgc() < 2 + skiparg )
+ for( p = level.namelogs; p; p = p->next )
{
- ADMP( "^3!drop: ^7usage: !drop [name|slot#] [message]\n" );
- return qfalse;
- }
+ for( i = 0; i < MAX_NAMELOG_NAMES && p->name[ i ][ 0 ]; i++ )
+ {
+ G_SanitiseString( p->name[ i ], n2, sizeof( n2 ) );
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
- {
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!drop: ^7%s\n", err ) );
- return qfalse;
- }
+ // if this is an exact match to a current player
+ if( i == p->nameOffset && p->slot > -1 && !strcmp( s2, n2 ) )
+ return p;
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
- {
- ADMP( "^3!drop: ^7sorry, but your intended victim has a higher admin"
- " level than you\n" );
- return qfalse;
+ if( strstr( n2, s2 ) )
+ m = p;
+ }
+
+ if( m == p )
+ found++;
}
- // victim's message
- if( G_SayArgc() > 2 + skiparg )
- trap_SendServerCommand( pids[ 0 ],
- va( "disconnect \"You have been dropped.\n%s^7\n\"",
- G_SayConcatArgs( 2 + skiparg ) ) );
- else
- trap_SendServerCommand( pids[ 0 ], va( "disconnect" ) );
+ if( found == 1 )
+ return m;
- // server message
- trap_DropClient( pids[ 0 ], va( "disconnected" ) );
+ if( found > 1 )
+ admin_search( ent, "namelog", "recent players", namelog_matchname,
+ namelog_out, level.namelogs, s2, 0, MAX_CLIENTS, -1 );
- return qtrue;
+ return NULL;
}
-qboolean G_admin_buildlog( gentity_t *ent, int skiparg )
+qboolean G_admin_lock( gentity_t *ent )
{
-#define LOG_DISPLAY_LENGTH 10
- buildHistory_t *ptr;
- gentity_t *builder = NULL;
- int skip = 0, start = 0, lastID = -1, firstID = -1, i, len, matchlen = 0;
- pTeam_t team = PTE_NONE;
- char message[ MAX_STRING_CHARS ], *teamchar;
- char *name, *action, *buildablename, markstring[ MAX_STRING_CHARS ];
- if( !g_buildLogMaxLength.integer )
- {
- ADMP( "^3!buildlog: ^7build logging is disabled" );
- return qfalse;
- }
- if( G_SayArgc( ) >= 2 + skiparg )
- {
- for( i = 1; i + skiparg < G_SayArgc( ); i++ )
- {
- char argbuf[ 64 ], err[ MAX_STRING_CHARS ];
- int x = 0, pids[ MAX_CLIENTS ];
- G_SayArgv( i + skiparg, argbuf, sizeof argbuf );
- switch( argbuf[ 0 ])
- {
- case 'x':
- x = 1;
- default:
- skip = atoi( argbuf + x );
- start = 0;
- break;
- case '#':
- start = atoi( argbuf + 1 );
- skip = 0;
- break;
- case '-':
- if(G_ClientNumbersFromString(argbuf + 1, pids) != 1)
- {
- G_MatchOnePlayer(pids, err, sizeof(err));
- ADMP(va("^3!revert: ^7%s\n", err));
- return qfalse;
- }
- builder = g_entities + *pids;
- break;
- case 'A':
- case 'a':
- team = PTE_ALIENS;
- break;
- case 'H':
- case 'h':
- team = PTE_HUMANS;
- break;
- }
- }
- }
- // !buildlog can be abused, so let everyone know when it is used
- AP( va( "print \"^3!buildlog: ^7%s^7 requested a log of recent building"
- " activity\n\"", ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- len = G_CountBuildLog( ); // also clips the log if too long
- if( !len )
- {
- ADMP( "^3!buildlog: ^7no build log found\n" );
- return qfalse;
- }
- if( start )
- {
- // set skip based on start
- for( ptr = level.buildHistory; ptr && ptr->ID != start;
- ptr = ptr->next, skip++ );
- if( !ptr )
- {
- ADMP( "^3!buildlog: ^7log ID not found\n" );
- skip = 0;
- }
- }
- // ensure skip is a useful value
- if( skip > len - LOG_DISPLAY_LENGTH )
- skip = len - LOG_DISPLAY_LENGTH;
- *message = '\0';
- // skip to start entry
- for( ptr = level.buildHistory, i = len; ptr && i > len - skip;
- ptr = ptr->next )
- {
- // these checks could perhaps be done more efficiently but they are cheap
- // in processor time so I'm not worrying
- if( team != PTE_NONE && team != BG_FindTeamForBuildable( ptr->buildable ) )
- continue;
- if( builder && builder != ptr->ent )
- continue;
- matchlen++;
- i--;
- }
- for( ; i + LOG_DISPLAY_LENGTH > len - skip && i > 0; i--, ptr = ptr->next )
- {
- if( !ptr )
- break; // run out of log
- *markstring = '\0'; // reinit markstring
- // check team
- if( ( team != PTE_NONE && team != BG_FindTeamForBuildable( ptr->buildable ) )
- || ( builder && builder != ptr->ent ) )
- {
- skip++; // loop an extra time because we skipped one
- continue;
- }
- if( lastID < 0 )
- lastID = ptr->ID;
- firstID = ptr->ID;
- matchlen++;
- // set name to the ent's current name or last recorded name
- if( ptr->ent )
- {
- if( ptr->ent->client )
- name = ptr->ent->client->pers.netname;
- else
- name = "<world>"; // any non-client action
- }
- else
- name = ptr->name;
- switch( ptr->fate )
- {
- case BF_BUILT:
- action = "^2built^7 a";
- break;
- case BF_DECONNED:
- action = "^3DECONSTRUCTED^7 a";
- break;
- case BF_DESTROYED:
- action = "destroyed a";
- break;
- case BF_TEAMKILLED:
- action = "^1TEAMKILLED^7 a";
- break;
- default:
- action = "\0"; // erm
- break;
- }
- // handle buildables removed by markdecon
- if( ptr->marked )
- {
- buildHistory_t *mark;
- int j, markdecon[ BA_NUM_BUILDABLES ], and = 2;
- char bnames[ 32 ], *article;
- mark = ptr;
- // count the number of buildables
- memset( markdecon, 0, sizeof( markdecon ) );
- while( ( mark = mark->marked ) )
- markdecon[ mark->buildable ]++;
- // reverse order makes grammar easier
- for( j = BA_NUM_BUILDABLES; j >= 0; j-- )
- {
- buildablename = BG_FindHumanNameForBuildable( j );
- // plural is easy
- if( markdecon[ j ] > 1 )
- Com_sprintf( bnames, 32, "%d %ss", markdecon[ j ], buildablename );
- // use an appropriate article
- else if( markdecon[ j ] == 1 )
- {
- if( BG_FindUniqueTestForBuildable( j ) )
- article = "the"; // if only one
- else if( strchr( "aeiouAEIOU", *buildablename ) )
- article = "an"; // if first char is vowel
- else
- article = "a";
- Com_sprintf( bnames, 32, "%s %s", article, buildablename );
- }
- else
- continue; // none of this buildable
- // C grammar: x, y, and z
- // the integer and is 2 initially, the test means it is used on the
- // second sprintf only, the reverse order makes this second to last
- // the comma is only printed if there is already some markstring i.e.
- // not the first time ( which would put it on the end of the string )
- Com_sprintf( markstring, sizeof( markstring ), "%s%s %s%s", bnames,
- ( *markstring ) ? "," : "", ( and-- == 1 ) ? "and " : "", markstring );
- }
- }
- buildablename = BG_FindHumanNameForBuildable( ptr->buildable );
- switch( BG_FindTeamForBuildable( ptr->buildable ) )
- {
- case PTE_ALIENS:
- teamchar = "^1A";
- break;
- case PTE_HUMANS:
- teamchar = "^4H";
- break;
- default:
- teamchar = " "; // space so it lines up neatly
- break;
- }
- // prepend the information to the string as we go back in buildhistory
- // so the earliest events are at the top
- Com_sprintf( message, MAX_STRING_CHARS, "%3d %s^7 %s^7 %s%s %s%s%s\n%s",
- ptr->ID, teamchar, name, action,
- ( strchr( "aeiouAEIOU", buildablename[ 0 ] ) ) ? "n" : "",
- buildablename, ( markstring[ 0 ] ) ? ", removing " : "",
- markstring, message );
- }
- for( ; ptr; ptr = ptr->next )
- {
- if( builder && builder != ptr->ent )
- continue;
- if( team != PTE_NONE && team != BG_FindTeamForBuildable( ptr->buildable ) )
- continue;
- matchlen++;
- }
- if( matchlen )
- ADMP( va( "%s^3!buildlog: showing log entries %d - %d of %d\n", message,
- firstID, lastID, matchlen ) );
- else
- ADMP( "^3!buildlog: ^7no log entries match those criteria\n" );
- return qtrue;
-}
+ char command[ MAX_ADMIN_CMD_LEN ];
+ char teamName[ sizeof( "aliens" ) ];
+ team_t team;
+ qboolean lock, fail = qfalse;
-qboolean G_admin_revert( gentity_t *ent, int skiparg )
-{
- int i = 0, j = 0, repeat = 1, ID = 0, len, matchlen=0;
- pTeam_t team = PTE_NONE;
- qboolean force = qfalse, reached = qfalse;
- gentity_t *builder = NULL, *targ;
- buildHistory_t *ptr, *tmp, *mark, *prev;
- vec3_t dist;
- char argbuf[ 64 ], *name, *bname, *action, *article;
- len = G_CountBuildLog( );
- if( !len )
- {
- ADMP( "^3!revert: ^7no build log found\n" );
- return qfalse;
- }
- if( G_SayArgc( ) < 2 + skiparg )
+ trap_Argv( 0, command, sizeof( command ) );
+ if( trap_Argc() < 2 )
{
- ADMP( "^3!revert: ^7usage: !revert (^5xnum^7) (^5#ID^7) (^5-name|num^7) (^5a|h^7)\n" );
+ ADMP( va( "^3%s: ^7usage: %s [a|h]\n", command, command ) );
return qfalse;
}
- for( i = 1; i + skiparg < G_SayArgc( ); i++ )
- {
- char arg[ 64 ], err[ MAX_STRING_CHARS ];
- int pids[ MAX_CLIENTS ];
- G_SayArgv( i + skiparg, arg, sizeof arg );
- switch( arg[ 0 ])
- {
- case 'x':
- repeat = atoi( arg + 1 );
- break;
- case '#':
- ID = atoi( arg + 1 );
- break;
- case '-':
- if(G_ClientNumbersFromString(arg + 1, pids) != 1)
- {
- G_MatchOnePlayer(pids, err, sizeof err);
- ADMP(va("^3!revert: ^7%s\n", err));
- return qfalse;
- }
- builder = g_entities + *pids;
- break;
- case 'A':
- case 'a':
- team = PTE_ALIENS;
- break;
- case 'H':
- case 'h':
- team = PTE_HUMANS;
- break;
- case '!':
- force = qtrue;
- break;
- default:
- ADMP( "^3!revert: ^7usage: !revert (^5xnum^7) (^5#ID^7) (^5-name|num^7) (^5a|h^7)\n" );
- return qfalse;
- }
- }
- if( repeat > 25 )
- {
- ADMP( "^3!revert: ^7to avoid flooding, can only revert 25 builds at a time\n" );
- repeat = 25;
- }
- for( i = 0, ptr = prev = level.buildHistory; repeat > 0; repeat--, j = 0 )
+ lock = !Q_stricmp( command, "lock" );
+ trap_Argv( 1, teamName, sizeof( teamName ) );
+ team = G_TeamFromString( teamName );
+
+ if( team == TEAM_ALIENS )
{
- if( !ptr )
- break; // run out of bhist
- if( !reached && ID )
- {
- if( ptr->ID == ID )
- reached = qtrue;
- else
- {
- prev = ptr;
- ptr = ptr->next;
- repeat++;
- continue;
- }
- }
- if( ( team != PTE_NONE &&
- team != BG_FindTeamForBuildable( ptr->buildable ) ) ||
- ( builder && builder != ptr->ent ))
- {
- // team doesn't match, so skip this ptr and reset prev
- prev = ptr;
- ptr = ptr->next;
- // we don't want to count this one so counteract the decrement by the for
- repeat++;
- continue;
- }
- // get the ent's current or last recorded name
- if( ptr->ent )
- {
- if( ptr->ent->client )
- name = ptr->ent->client->pers.netname;
- else
- name = "<world>"; // non-client actions
- }
+ if( level.alienTeamLocked == lock )
+ fail = qtrue;
else
- name = ptr->name;
- bname = BG_FindHumanNameForBuildable( ptr->buildable );
- action = "";
- switch( ptr->fate )
- {
- case BF_BUILT:
- action = "^2build^7";
- for( j = MAX_CLIENTS, targ = g_entities + j;
- j < level.num_entities; j++, targ++ )
- {
- // easy checks first to save time
- if( targ->s.eType != ET_BUILDABLE )
- continue;
- if( targ->s.modelindex != ptr->buildable )
- continue;
- VectorSubtract( targ->s.pos.trBase, ptr->origin, dist );
-#define FIND_BUILDABLE_TOLERANCE 5
- if( VectorLength( dist ) > FIND_BUILDABLE_TOLERANCE )
- continue; // number is somewhat arbitrary, watch for false pos/neg
- // if we didn't continue then it's this one, unlink it but we can't
- // free it yet, because the markdecon buildables might not place
- trap_UnlinkEntity( targ );
- break;
- }
- // if there are marked buildables to replace, and we aren't overriding
- // space check, check they can fit before acting
- if( ptr->marked && !force )
- {
- for( mark = ptr->marked; mark; mark = mark->marked )
- if( !G_RevertCanFit( mark ) )
- {
- trap_LinkEntity( targ ); // put it back, we failed
- // scariest sprintf ever:
- Com_sprintf( argbuf, sizeof argbuf, "%s%s%s%s%s%s%s!",
- ( repeat > 1 ) ? "x" : "", ( repeat > 1 ) ? va( "%d ", repeat ) : "",
- ( ID ) ? "#" : "", ( ID ) ? va( "%d ", ptr->ID ) : "",
- ( builder ) ? "-" : "", ( builder ) ? va( "%d ", builder - g_entities ) : "",
- ( team == PTE_ALIENS ) ? "a " : ( team == PTE_HUMANS ) ? "h " : "" );
- ADMP( va( "^3!revert: ^7revert aborted: reverting this %s would conflict with "
- "another buildable, use ^3!revert %s ^7to override\n", action, argbuf ) );
- return qfalse;
- }
- }
- // Prevent teleport glitch when reverting an occupied hovel
- if( targ->s.modelindex == BA_A_HOVEL &&
- targ->active )
- {
- gentity_t *builder = targ->builder;
- vec3_t newOrigin;
- vec3_t newAngles;
-
- VectorCopy( targ->s.angles, newAngles );
- newAngles[ ROLL ] = 0;
-
- VectorCopy( targ->s.origin, newOrigin );
- VectorMA( newOrigin, 1.0f, targ->s.origin2, newOrigin );
-
- //prevent lerping
- builder->client->ps.eFlags ^= EF_TELEPORT_BIT;
- builder->client->ps.eFlags &= ~EF_NODRAW;
- G_UnlaggedClear( builder );
-
- G_SetOrigin( builder, newOrigin );
- VectorCopy( newOrigin, builder->client->ps.origin );
- G_SetClientViewAngle( builder, newAngles );
-
- //client leaves hovel
- builder->client->ps.stats[ STAT_STATE ] &= ~SS_HOVELING;
- }
-
- // if we haven't returned yet then we're good to go, free it
- G_FreeEntity( targ );
- // put the marked buildables back and mark them again
- if( ptr->marked ) // there may be a more efficient way of doing this
- {
- for( mark = ptr->marked; mark; mark = mark->marked )
- G_SpawnRevertedBuildable( mark, qtrue );
- }
- break;
- case BF_DECONNED:
- if( !action[ 0 ] ) action = "^3deconstruction^7";
- case BF_TEAMKILLED:
- if( !action[ 0 ] ) action ="^1TEAMKILL^7";
- case BF_DESTROYED:
- if( !action[ 0 ] ) action = "destruction";
- // if we're not overriding and the replacement can't fit, as before
- if( !force && !G_RevertCanFit( ptr ) )
- {
- Com_sprintf( argbuf, sizeof argbuf, "%s%s%s%s%s%s%s!",
- ( repeat > 1 ) ? "x" : "", ( repeat > 1 ) ? va( "%d ", repeat ) : "",
- ( ID ) ? "#" : "", ( ID ) ? va( "%d ", ptr->ID ) : "",
- ( builder ) ? "-" : "", ( builder ) ? va( "%d ", builder - g_entities ) : "",
- ( team == PTE_ALIENS ) ? "a " : ( team == PTE_HUMANS ) ? "h " : "" );
- ADMP( va( "^3!revert: ^7revert aborted: reverting this %s would "
- "conflict with another buildable, use ^3!revert %s ^7to override\n",
- action, argbuf ) );
- return qfalse;
- }
- // else replace it but don't mark it ( it might have been marked before
- // but it isn't that important )
- G_SpawnRevertedBuildable( ptr, qfalse );
- break;
- default:
- // if this happens something has gone wrong
- ADMP( "^3!revert: ^7incomplete or corrupted build log entry\n" );
- /* quarantine and dispose of the log, it's dangerous
- trap_Cvar_Set( "g_buildLogMaxLength", "0" );
- G_CountBuildLog( );
- */
- return qfalse;
- }
- if( j == level.num_entities )
- {
- ADMP( va( "^3!revert: ^7could not find logged buildable #%d\n", ptr->ID ));
- prev = ptr;
- ptr = ptr->next;
- continue;
- }
- // this is similar to the buildlog stuff
- if( BG_FindUniqueTestForBuildable( ptr->buildable ) )
- article = "the";
- else if( strchr( "aeiouAEIOU", *bname ) )
- article = "an";
- else
- article = "a";
- AP( va( "print \"%s^7 reverted %s^7'%s %s of %s %s\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
- name, strchr( "Ss", name[ strlen( name ) - 1 ] ) ? "" : "s",
- action, article, bname ) );
- matchlen++;
- // remove the reverted entry
- // ptr moves on, prev just readjusts ->next unless it is about to be
- // freed, in which case it is forced to move on too
- tmp = ptr;
- if( ptr == level.buildHistory )
- prev = level.buildHistory = ptr = ptr->next;
- else
- prev->next = ptr = ptr->next;
- G_Free( tmp );
- }
- if( ID && !reached )
- {
- ADMP( "^3!revert: ^7no buildlog entry with that ID\n" );
- return qfalse;
+ level.alienTeamLocked = lock;
}
-
- if( !matchlen )
+ else if( team == TEAM_HUMANS )
{
- ADMP( "^3!revert: ^7no log entries match those criteria\n" );
- return qfalse;
+ if( level.humanTeamLocked == lock )
+ fail = qtrue;
+ else
+ level.humanTeamLocked = lock;
}
else
{
- ADMP( va( "^3!revert: ^7reverted %d buildlog events\n", matchlen ) );
- }
-
- return qtrue;
-}
-
-void G_Unescape( char *input, char *output, int len );
-qboolean G_StringReplaceCvars( char *input, char *output, int len );
-
-qboolean G_admin_info( gentity_t *ent, int skiparg )
-{
- fileHandle_t infoFile;
- int length;
- char filename[ MAX_OSPATH ], message[ MAX_STRING_CHARS ];
- if( G_SayArgc() == 2 + skiparg )
- G_SayArgv( 1 + skiparg, filename, sizeof( filename ) );
- else if( G_SayArgc() == 1 + skiparg )
- Q_strncpyz( filename, "default", sizeof( filename ) );
- else
- {
- ADMP( "^3!info: ^7usage: ^3!info ^7(^5subject^7)\n" );
+ ADMP( va( "^3%s: ^7invalid team: '%s'\n", command, teamName ) );
return qfalse;
}
- Com_sprintf( filename, sizeof( filename ), "info/info-%s.txt", filename );
- length = trap_FS_FOpenFile( filename, &infoFile, FS_READ );
- if( length <= 0 || !infoFile )
- {
- trap_FS_FCloseFile( infoFile );
- ADMP( "^3!info: ^7no relevant information is available\n" );
- return qfalse;
- }
- else
- {
- int i;
- char *cr;
- trap_FS_Read( message, sizeof( message ), infoFile );
- if( length < sizeof( message ) )
- message[ length ] = '\0';
- else
- message[ sizeof( message ) - 1 ] = '\0';
- trap_FS_FCloseFile( infoFile );
- // strip carriage returns for windows platforms
- while( ( cr = strchr( message, '\r' ) ) )
- memmove( cr, cr + 1, strlen( cr + 1 ) + 1 );
-#define MAX_INFO_PARSE_LOOPS 100
- for( i = 0; i < MAX_INFO_PARSE_LOOPS &&
- G_StringReplaceCvars( message, message, sizeof( message ) ); i++ );
- G_Unescape( message, message, sizeof( message ) );
- if( i == MAX_INFO_PARSE_LOOPS )
- G_Printf( S_COLOR_YELLOW "WARNING: %s exceeds MAX_INFO_PARSE_LOOPS\n", filename );
- ADMP( va( "%s\n", message ) );
- return qtrue;
- }
-}
-
-void G_Unescape( char *input, char *output, int len )
-{
- // \n -> newline, \%c -> %c
- // output is terminated at output[len - 1]
- // it's OK for input to equal output, because our position in input is always
- // equal or greater than our position in output
- // however, if output is later in the same string as input, a crash is pretty
- // much inevitable
- int i, j;
- for( i = j = 0; input[i] && j + 1 < len; i++, j++ )
- {
- if( input[i] == '\\' )
- {
- if( !input[++i] )
- {
- output[j] = '\0';
- return;
- }
- else if( input[i] == 'n' )
- output[j] = '\n';
- else
- output[j] = input[i];
- }
- else
- output[j] = input[i];
- }
- output[j] = '\0';
-}
-qboolean G_StringReplaceCvars( char *input, char *output, int len )
-{
- int i, outNum = 0;
- char cvarName[ 64 ], cvarValue[ MAX_CVAR_VALUE_STRING ];
- char *outputBuffer;
- qboolean doneAnything = qfalse;
- if( len <= 0 )
- return qfalse;
- // use our own internal buffer in case output == input
- outputBuffer = G_Alloc( len );
- len -= 1; // fit in a terminator
- while( *input && outNum < len )
+ if( fail )
{
- if( *input == '\\' && input[1] && outNum < len - 1 )
- {
- outputBuffer[ outNum++ ] = *input++;
- outputBuffer[ outNum++ ] = *input++;
- }
- else if( *input == '$' )
- {
- doneAnything = qtrue;
- input++;
- if( *input == '{' )
- input++;
- for( i = 0; *input && ( isalnum( *input ) || *input == '_' ) &&
- i < 63; i++ )
- cvarName[ i ] = *input++;
- cvarName[ i ] = '\0';
- if( *input == '}' )
- input++;
- trap_Cvar_VariableStringBuffer( cvarName, cvarValue, sizeof( cvarValue ) );
- if( cvarValue[ 0 ] )
- {
- for( i = 0; cvarValue[ i ] && outNum < len; i++ )
- outputBuffer[ outNum++ ] = cvarValue[ i ];
- }
- }
- else
- outputBuffer[ outNum++ ] = *input++;
- }
- outputBuffer[ outNum ] = '\0';
- Q_strncpyz( output, outputBuffer, len );
- G_Free( outputBuffer );
- return doneAnything;
-}
-
-/*
-================
- G_admin_print
+ ADMP( va( "^3%s: ^7the %s team is %s locked\n",
+ command, BG_TeamName( team ), lock ? "already" : "not currently" ) );
- This function facilitates the ADMP define. ADMP() is similar to CP except
- that it prints the message to the server console if ent is not defined.
-================
-*/
-void G_admin_print( gentity_t *ent, char *m )
-{
- if( ent )
- trap_SendServerCommand( ent - level.gentities, va( "print \"%s\"", m ) );
- else
- {
- char m2[ MAX_STRING_CHARS ];
- if( !trap_Cvar_VariableIntegerValue( "com_ansiColor" ) )
- {
- G_DecolorString( m, m2 );
- G_Printf( m2 );
- }
- else
- G_Printf( m );
+ return qfalse;
}
-}
-void G_admin_buffer_begin()
-{
- g_bfb[ 0 ] = '\0';
-}
+ admin_log( BG_TeamName( team ) );
+ AP( va( "print \"^3%s: ^7the %s team has been %slocked by %s\n\"",
+ command, BG_TeamName( team ), lock ? "" : "un",
+ ent ? ent->client->pers.netname : "console" ) );
-void G_admin_buffer_end( gentity_t *ent )
-{
- ADMP( g_bfb );
+ return qtrue;
}
-void G_admin_buffer_print( gentity_t *ent, char *m )
+qboolean G_admin_builder( gentity_t *ent )
{
- // 1022 - strlen("print 64 \"\"") - 1
- if( strlen( m ) + strlen( g_bfb ) >= 1009 )
- {
- ADMP( g_bfb );
- g_bfb[ 0 ] = '\0';
- }
- Q_strcat( g_bfb, sizeof( g_bfb ), m );
-}
+ vec3_t forward, right, up;
+ vec3_t start, end, dist;
+ trace_t tr;
+ gentity_t *traceEnt;
+ buildLog_t *log;
+ int i;
+ qboolean buildlog;
+ char logid[ 20 ] = {""};
-
-void G_admin_cleanup()
-{
- int i = 0;
-
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- G_Free( g_admin_levels[ i ] );
- g_admin_levels[ i ] = NULL;
- }
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- G_Free( g_admin_admins[ i ] );
- g_admin_admins[ i ] = NULL;
- }
- for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
- {
- G_Free( g_admin_bans[ i ] );
- g_admin_bans[ i ] = NULL;
- }
- for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
- {
- G_Free( g_admin_commands[ i ] );
- g_admin_commands[ i ] = NULL;
- }
-}
-
-qboolean G_admin_L0(gentity_t *ent, int skiparg ){
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ] = {""};
- char testname[ MAX_NAME_LENGTH ] = {""};
- char err[ MAX_STRING_CHARS ];
- qboolean numeric = qtrue;
- int i;
- int id = -1;
- gentity_t *vic;
-
- if( G_SayArgc() < 2 + skiparg )
+ if( !ent )
{
- ADMP( "^3!L0: ^7usage: !L0 [name|slot#|admin#]\n" );
+ ADMP( "^3builder: ^7console can't aim.\n" );
return qfalse;
}
- G_SayArgv( 1 + skiparg, testname, sizeof( testname ) );
- G_SanitiseString( testname, name, sizeof( name ) );
- for( i = 0; i < sizeof( name ) && name[ i ] ; i++ )
- {
- if( name[ i ] < '0' || name[ i ] > '9' )
- {
- numeric = qfalse;
- break;
- }
- }
- if( numeric )
- {
- id = atoi( name );
- }
+ buildlog = G_admin_permission( ent, "buildlog" );
+
+ AngleVectors( ent->client->ps.viewangles, forward, right, up );
+ if( ent->client->pers.teamSelection != TEAM_NONE &&
+ ent->client->sess.spectatorState == SPECTATOR_NOT )
+ CalcMuzzlePoint( ent, forward, right, up, start );
else
- {
- if( G_ClientNumbersFromString( name, pids ) != 1 )
- {
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!L0: ^7%s\n", err ) );
- return qfalse;
- }
- id = pids[ 0 ];
- }
+ VectorCopy( ent->client->ps.origin, start );
+ VectorMA( start, 1000, forward, end );
- if (id >= 0 && id < level.maxclients)
+ trap_Trace( &tr, start, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
+ traceEnt = &g_entities[ tr.entityNum ];
+ if( tr.fraction < 1.0f && ( traceEnt->s.eType == ET_BUILDABLE ) )
{
- vic = &g_entities[ id ];
- if( !vic || !(vic->client) || vic->client->pers.connected != CON_CONNECTED )
+ if( !buildlog &&
+ ent->client->pers.teamSelection != TEAM_NONE &&
+ ent->client->pers.teamSelection != traceEnt->buildableTeam )
{
- ADMP( "^3!L0:^7 no one connected by that slot number\n" );
+ ADMP( "^3builder: ^7structure not owned by your team\n" );
return qfalse;
}
- if( G_admin_level( vic ) != 1 )
+ if( buildlog )
{
- ADMP( "^3!L0:^7 intended victim is not level 1\n" );
- return qfalse;
- }
- }
- else if (id >= MAX_CLIENTS && id < MAX_CLIENTS + MAX_ADMIN_ADMINS
- && g_admin_admins[ id - MAX_CLIENTS ] )
- {
- if( g_admin_admins[ id - MAX_CLIENTS ]->level != 1 )
- {
- ADMP( "^3!L0:^7 intended victim is not level 1\n" );
- return qfalse;
+ for( i = 0 ; buildlog && i < level.numBuildLogs; i++ )
+ {
+ log = &level.buildLog[ ( level.buildId - i - 1 ) % MAX_BUILDLOG ];
+ if( log->fate != BF_CONSTRUCT || traceEnt->s.modelindex != log->modelindex )
+ continue;
+
+ VectorSubtract( traceEnt->s.pos.trBase, log->origin, dist );
+ if( VectorLengthSquared( dist ) < 2.0f )
+ Com_sprintf( logid, sizeof( logid ), ", buildlog #%d",
+ MAX_CLIENTS + level.buildId - i - 1 );
+ }
}
+
+ ADMP( va( "^3builder: ^7%s%s%s^7%s\n",
+ BG_Buildable( traceEnt->s.modelindex )->humanName,
+ traceEnt->builtBy ? " built by " : "",
+ traceEnt->builtBy ?
+ traceEnt->builtBy->name[ traceEnt->builtBy->nameOffset ] :
+ "",
+ buildlog ? ( logid[ 0 ] ? logid : ", not in buildlog" ) : "" ) );
}
else
- {
- ADMP( "^3!L0:^7 no match. use !listplayers or !listadmins to "
- "find an appropriate number to use instead of name.\n" );
- return qfalse;
- }
-
- trap_SendConsoleCommand( EXEC_APPEND, va( "!setlevel %d 0;", id ) );
+ ADMP( "^3builder: ^7no structure found under crosshair\n" );
return qtrue;
}
-qboolean G_admin_L1(gentity_t *ent, int skiparg ){
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], *reason, err[ MAX_STRING_CHARS ];
- int minargc;
-
- minargc = 2 + skiparg;
-
- if( G_SayArgc() < minargc )
- {
- ADMP( "^3!L1: ^7usage: !L1 [name]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- reason = G_SayConcatArgs( 2 + skiparg );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
- {
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!L1: ^7%s\n", err ) );
- return qfalse;
- }
- if( G_admin_level(&g_entities[ pids[ 0 ] ] )>0 )
- {
- ADMP( "^3!L1: ^7Sorry, but that person is already higher than level 0.\n" );
- return qfalse;
- }
-
- trap_SendConsoleCommand( EXEC_APPEND,va( "!setlevel %d 1;", pids[ 0 ] ) );
- return qtrue;
-}
-
-qboolean G_admin_invisible( gentity_t *ent, int skiparg )
+qboolean G_admin_pause( gentity_t *ent )
{
- if( !ent )
- {
- ADMP( "!invisible: console can not become invisible.\n" );
- return qfalse;
- }
-
- if ( ent->client->sess.invisible != qtrue )
+ if( !level.pausedTime )
{
- // Make the player invisible
- G_ChangeTeam( ent, PTE_NONE );
- ent->client->sess.invisible = qtrue;
- ClientUserinfoChanged( ent->client->pers.connection->clientNum, qfalse );
- G_admin_namelog_update( ent->client, qtrue );
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " disconnected\n\"", ent->client->pers.netname ) );
+ AP( va( "print \"^3pause: ^7%s^7 paused the game.\n\"",
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ level.pausedTime = 1;
+ trap_SendServerCommand( -1, "cp \"The game has been paused. Please wait.\"" );
}
else
{
- // Make the player visible
- ent->client->sess.invisible = qfalse;
- ClientUserinfoChanged( ent->client->pers.connection->clientNum, qfalse );
- G_admin_namelog_update( ent->client, qfalse );
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"", ent->client->pers.netname ) );
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", ent->client->pers.netname ) );
- }
- return qtrue;
-}
+ // Prevent accidental pause->unpause race conditions by two admins
+ if( level.pausedTime < 1000 )
+ {
+ ADMP( "^3pause: ^7Unpausing so soon assumed accidental and ignored.\n" );
+ return qfalse;
+ }
-qboolean G_admin_decon( gentity_t *ent, int skiparg )
-{
- int i = 0, j = 0, repeat = 24, pids[ MAX_CLIENTS ], len, matchlen = 0;
- pTeam_t team = PTE_NONE;
- qboolean force = qfalse, reached = qfalse;
- gentity_t *builder = NULL, *targ;
- buildHistory_t *ptr, *tmp, *mark, *prev;
- vec3_t dist;
- char arg[ 64 ], err[ MAX_STRING_CHARS ], *name, *bname, *action, *article, *reason;
- len = G_CountBuildLog( );
-
- if( !len )
- {
- ADMP( "^3!decon: ^7no build log found, aborting...\n" );
- return qfalse;
- }
+ AP( va( "print \"^3pause: ^7%s^7 unpaused the game (Paused for %d sec) \n\"",
+ ( ent ) ? ent->client->pers.netname : "console",
+ (int) ( (float) level.pausedTime / 1000.0f ) ) );
+ trap_SendServerCommand( -1, "cp \"The game has been unpaused!\"" );
- if( G_SayArgc( ) < 2 + skiparg )
- {
- ADMP( "^3!decon: ^7usage: !decon (^5name|num^7)\n" );
- return qfalse;
+ level.pausedTime = 0;
}
- G_SayArgv( 1 + skiparg, arg, sizeof( arg ) );
- if( G_ClientNumbersFromString( arg, pids ) != 1 )
- {
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!decon: ^7%s\n", err ) );
- return qfalse;
- }
+ return qtrue;
+}
- builder = g_entities + *pids;
- if( builder->client->sess.invisible == qtrue )
- {
- ADMP( va( "^3!decon: ^7no connected player by the name or slot #\n" ) );
- return qfalse;
+static char *fates[] =
+{
+ "^2built^7",
+ "^3deconstructed^7",
+ "^7replaced^7",
+ "^3destroyed^7",
+ "^1TEAMKILLED^7",
+ "^7unpowered^7",
+ "removed"
+};
+qboolean G_admin_buildlog( gentity_t *ent )
+{
+ char search[ MAX_NAME_LENGTH ] = {""};
+ char s[ MAX_NAME_LENGTH ] = {""};
+ char n[ MAX_NAME_LENGTH ];
+ char stamp[ 8 ];
+ int id = -1;
+ int printed = 0;
+ int time;
+ int start = MAX_CLIENTS + level.buildId - level.numBuildLogs;
+ int i = 0, j;
+ buildLog_t *log;
+
+ if( !level.buildId )
+ {
+ ADMP( "^3buildlog: ^7log is empty\n" );
+ return qtrue;
}
- if( !admin_higher( ent, builder ) )
+ if( trap_Argc() == 3 )
{
- ADMP( "^3!decon: ^7sorry, but your intended victim has a higher admin"
- "level than you\n");
- return qfalse;
+ trap_Argv( 2, search, sizeof( search ) );
+ start = atoi( search );
}
-
- for( i = 0, ptr = prev = level.buildHistory; repeat > 0; repeat--, j = 0 )
+ if( trap_Argc() > 1 )
{
- if( !ptr )
- break;
- if( builder && builder != ptr->ent )
- {
- // team doesn't match, so skip this ptr and reset prev
- prev = ptr;
- ptr = ptr->next;
- // we don't want to count this one so counteract the decrement by the for
- repeat++;
- continue;
- }
- // get the ent's current or last recorded name
- if( ptr->ent )
- {
- if( ptr->ent->client )
- name = ptr->ent->client->pers.netname;
- else
- name = "<world>"; // non-client actions
- }
- else
- name = ptr->name;
- bname = BG_FindHumanNameForBuildable( ptr->buildable );
- action = "";
- switch( ptr->fate )
+ trap_Argv( 1, search, sizeof( search ) );
+ for( i = search[ 0 ] == '-'; isdigit( search[ i ] ); i++ );
+ if( i && !search[ i ] )
{
- case BF_BUILT:
- prev = ptr;
- ptr = ptr->next;
- repeat++;
- continue;
- case BF_DESTROYED:
- prev = ptr;
- ptr = ptr->next;
- repeat++;
- case BF_DECONNED:
- if( !action[0] ) action = "^3deconstruction^7";
- case BF_TEAMKILLED:
- if( !action[0] ) action = "^1TEAMKILL^7";
- // if we're not overriding and the replacement can't fit, as before
- if( !G_RevertCanFit( ptr ) )
- {
- prev = ptr;
- ptr = ptr->next;
- repeat++;
- continue;
- }
- // else replace it but don't mark it ( it might have been marked before
- // but it isn't that important )
- G_SpawnRevertedBuildable( ptr, qfalse );
- break;
- default:
- // if this happens something has gone wrong
- ADMP( "^3!decon: ^7incomplete or corrupted build log entry\n" );
- /* quarantine and dispose of the log, it's dangerous
- trap_Cvar_Set( "g_buildLogMaxLength", "0" );
- G_CountBuildLog( );
- */
+ id = atoi( search );
+ if( trap_Argc() == 2 && ( id < 0 || id >= MAX_CLIENTS ) )
+ {
+ start = id;
+ id = -1;
+ }
+ else if( id < 0 || id >= MAX_CLIENTS ||
+ level.clients[ id ].pers.connected != CON_CONNECTED )
+ {
+ ADMP( "^3buildlog: ^7invalid client id\n" );
return qfalse;
+ }
}
- // this is similar to the buildlog stuff
- if( BG_FindUniqueTestForBuildable( ptr->buildable ) )
- article = "the";
- else if( strchr( "aeiouAEIOU", *bname ) )
- article = "an";
else
- article = "a";
- AP( va( "print \"%s^7 reverted %s^7'%s %s of %s %s\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
- name, strchr( "Ss", name[ strlen( name ) - 1 ] ) ? "" : "s",
- action, article, bname ) );
- matchlen++;
- // remove the reverted entry
- // ptr moves on, prev just readjusts ->next unles it is about to be
- // freed, in which case it is forced to move on too
- tmp = ptr;
- if( ptr == level.buildHistory )
- prev = level.buildHistory = ptr = ptr->next;
- else
- prev->next = ptr = ptr->next;
- G_Free( tmp );
+ G_SanitiseString( search, s, sizeof( s ) );
}
+ else
+ start = MAX( -MAX_ADMIN_LISTITEMS, -level.buildId );
- if( !matchlen )
+ if( start < 0 )
+ start = MAX( level.buildId - level.numBuildLogs, start + level.buildId );
+ else
+ start -= MAX_CLIENTS;
+ if( start < level.buildId - level.numBuildLogs || start >= level.buildId )
{
- ADMP( "^3!decopn: ^7This user doesn't seem to have deconned anything...\n" );
+ ADMP( "^3buildlog: ^7invalid build ID\n" );
return qfalse;
}
- ADMP( va( "^3!decon: ^7reverted %d buildlog events\n", matchlen ) );
- admin_create_ban( ent,
- builder->client->pers.netname,
- builder->client->pers.guid,
- builder->client->pers.ip, G_admin_parse_time( g_deconBanTime.string ),
- ( *reason ) ? reason : "^1Decon" );
- if( g_admin.string[ 0 ] )
- admin_writeconfig();
-
- trap_SendServerCommand( pids[ 0 ],
- va( "disconnect \"You have been kicked.\n%s^7\nreason:\n%s\n%s\"",
- ( ent ) ? va( "admin:\n%s", G_admin_adminPrintName( ent ) ) : "admin\nconsole",
- ( *reason ) ? reason : "^1Decon" ) );
-
- trap_DropClient( pids[ 0 ], va( "kicked%s^7, reason: %s",
- ( ent ) ? va( " by %s", G_admin_adminPrintName( ent ) ) : " by console",
- ( *reason ) ? reason : "^1Decon" ) );
-
- return qtrue;
-}
+ if( ent && ent->client->pers.teamSelection != TEAM_NONE )
+ trap_SendServerCommand( -1,
+ va( "print \"^3buildlog: ^7%s^7 requested a log of recent building activity\n\"",
+ ent->client->pers.netname ) );
-qboolean G_admin_setdevmode( gentity_t *ent, int skiparg )
-{
- char str[ 5 ];
-
- if( G_SayArgc() != 2 + skiparg )
- {
- ADMP( "^3!setdevmode: ^7usage: !setdevmode [on|off]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, str, sizeof( str ) );
-
- if( !Q_stricmp( str, "on" ) )
+ ADMBP_begin();
+ for( i = start; i < level.buildId && printed < MAX_ADMIN_LISTITEMS; i++ )
{
- if( g_cheats.integer )
+ log = &level.buildLog[ i % MAX_BUILDLOG ];
+ if( id >= 0 && id < MAX_CLIENTS )
{
- ADMP( "^3!setdevmode: ^7developer mode is already on\n" );
- return qfalse;
+ if( log->actor != level.clients[ id ].pers.namelog )
+ continue;
}
- trap_Cvar_Set( "sv_cheats", "1" );
- trap_Cvar_Update( &g_cheats );
- AP( va( "print \"^3!setdevmode: ^7%s ^7has switched developer mode on\n\"",
- ent ? G_admin_adminPrintName( ent ) : "console" ) );
- }
- else if( !Q_stricmp( str, "off" ) )
- {
- if( !g_cheats.integer )
+ else if( s[ 0 ] )
{
- ADMP( "^3!setdevmode: ^7developer mode is already off\n" );
- return qfalse;
+ if( !log->actor )
+ continue;
+ for( j = 0; j < MAX_NAMELOG_NAMES && log->actor->name[ j ][ 0 ]; j++ )
+ {
+ G_SanitiseString( log->actor->name[ j ], n, sizeof( n ) );
+ if( strstr( n, s ) )
+ break;
+ }
+ if( j >= MAX_NAMELOG_NAMES || !log->actor->name[ j ][ 0 ] )
+ continue;
}
- trap_Cvar_Set( "sv_cheats", "0" );
- trap_Cvar_Update( &g_cheats );
- AP( va( "print \"^3!setdevmode: ^7%s ^7has switched developer mode off\n\"",
- ent ? G_admin_adminPrintName( ent ) : "console" ) );
- }
- else
- {
- ADMP( "^3!setdevmode: ^7usage: !setdevmode [on|off]\n" );
- return qfalse;
- }
-
+ printed++;
+ time = ( log->time - level.startTime ) / 1000;
+ Com_sprintf( stamp, sizeof( stamp ), "%3d:%02d", time / 60, time % 60 );
+ ADMBP( va( "^2%c^7%-3d %s %s^7%s%s%s %s%s%s\n",
+ log->actor && log->fate != BF_REPLACE && log->fate != BF_UNPOWER ?
+ '*' : ' ',
+ i + MAX_CLIENTS,
+ log->actor && ( log->fate == BF_REPLACE || log->fate == BF_UNPOWER ) ?
+ " \\_" : stamp,
+ BG_Buildable( log->modelindex )->humanName,
+ log->builtBy && log->fate != BF_CONSTRUCT ?
+ " (built by " :
+ "",
+ log->builtBy && log->fate != BF_CONSTRUCT ?
+ log->builtBy->name[ log->builtBy->nameOffset ] :
+ "",
+ log->builtBy && log->fate != BF_CONSTRUCT ?
+ "^7)" :
+ "",
+ fates[ log->fate ],
+ log->actor ? " by " : "",
+ log->actor ?
+ log->actor->name[ log->actor->nameOffset ] :
+ "" ) );
+ }
+ ADMBP( va( "^3buildlog: ^7showing %d build logs %d - %d of %d - %d. %s\n",
+ printed, start + MAX_CLIENTS, i + MAX_CLIENTS - 1,
+ level.buildId + MAX_CLIENTS - level.numBuildLogs,
+ level.buildId + MAX_CLIENTS - 1,
+ i < level.buildId ? va( "run 'buildlog %s%s%d' to see more",
+ search, search[ 0 ] ? " " : "", i + MAX_CLIENTS ) : "" ) );
+ ADMBP_end();
return qtrue;
}
-qboolean G_admin_hstage( gentity_t *ent, int skiparg )
+qboolean G_admin_revert( gentity_t *ent )
{
+ char arg[ MAX_TOKEN_CHARS ];
+ char time[ MAX_DURATION_LENGTH ];
+ int id;
+ buildLog_t *log;
- char lvl_chr[ MAX_STRING_CHARS ];
- int minargc;
- int lvl;
-
-
- minargc = 2 + skiparg;
-
- if( G_SayArgc() < minargc )
+ if( trap_Argc() != 2 )
{
- ADMP( "^3!hstage: ^7hstage: !hstage [#]\n" );
+ ADMP( "^3revert: ^7usage: revert [id]\n" );
return qfalse;
}
- G_SayArgv( 1 + skiparg, lvl_chr, sizeof( lvl_chr ) );
-
- lvl = atoi(lvl_chr);
-
- lvl -= 1;
- trap_SendConsoleCommand( EXEC_APPEND, va( "g_humanStage %i", lvl ) );
-
- return qtrue;
-
-}
-
-qboolean G_admin_astage( gentity_t *ent, int skiparg )
-{
-
- char lvl_chr[ MAX_STRING_CHARS ];
- int minargc;
- int lvl;
-
-
- minargc = 2 + skiparg;
-
- if( G_SayArgc() < minargc )
+ trap_Argv( 1, arg, sizeof( arg ) );
+ id = atoi( arg ) - MAX_CLIENTS;
+ if( id < level.buildId - level.numBuildLogs || id >= level.buildId )
{
- ADMP( "^3!astage: ^7astage: !astage [#]\n" );
+ ADMP( "^3revert: ^7invalid id\n" );
return qfalse;
}
- G_SayArgv( 1 + skiparg, lvl_chr, sizeof( lvl_chr ) );
-
- lvl = atoi(lvl_chr);
-
- lvl -= 1;
- trap_SendConsoleCommand( EXEC_APPEND, va( "g_alienStage %i", lvl ) );
-
- return qtrue;
-
-}
-
-qboolean G_admin_bubble( gentity_t *ent, int skiparg )
-{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
- gentity_t *vic;
-
- if(g_Bubbles.integer)
- {
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( "^3!bubble: ^7usage: !bubble [name|slot#]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
- {
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!bubble: ^7%s\n", err ) );
- return qfalse;
- }
- vic = &g_entities[ pids[ 0 ] ];
- if(vic->client->sess.invisible == qtrue)
- {
- ADMP( va( "^3!bubble: ^7no connected player by that name or slot #\n" ) );
- return qfalse;
- }
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
- {
- ADMP( "^3!bubble: ^7sorry, but your intended victim has a higher admin"
- " level than you\n" );
- return qfalse;
- }
-
-
- if( vic->client->pers.bubbleTime )
- vic->client->pers.bubbleTime = 0;
- else
- vic->client->pers.bubbleTime = level.time + 500;
-
- AP( va( "print \"^3!bubble: ^7bubbles %s for %s^7 by %s\n\"",
- ( vic->client->pers.bubbleTime ) ? "enabled" : "disabled",
- vic->client->pers.netname,
- ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- }
- else
+ log = &level.buildLog[ id % MAX_BUILDLOG ];
+ if( !log->actor || log->fate == BF_REPLACE || log->fate == BF_UNPOWER )
{
- ADMP( "^3!bubble: ^7sorry, but bubbles have been disabled on this server.\n" );
- return qfalse;
+ // fixme: then why list them with an id # in build log ? - rez
+ ADMP( "^3revert: ^7you can only revert direct player actions, "
+ "indicated by ^2* ^7in buildlog\n" );
+ return qfalse;
}
- return qtrue;
-}
-
-qboolean G_admin_scrim(gentity_t *ent, int skiparg )
-{
- char state[5];
-
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( "^3!scrim: ^7usage: !scrim [on|off]\n" );
- return qfalse;
- }
-
- G_SayArgv( 1 + skiparg, state, sizeof( state ) );
-
- if( !Q_stricmp(state, "on") )
- {
- if( g_scrimMode.integer != 0 )
- {
- ADMP( "^3!scrim: ^7scrim mode is already enabled.\n" );
- return qfalse;
- }
- AP( va( "print \"^3!scrim: ^7%s ^7turned scrim mode ^2on^7\n\"", ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- trap_Cvar_Set( "g_scrimMode", "1" );
- }
- else if( !Q_stricmp(state, "off") )
- {
- if( g_scrimMode.integer == 0 )
- {
- ADMP( "^3!scrim: ^7scrim mode is already disabled.\n" );
- return qfalse;
- }
- AP( va( "print \"^3!scrim: ^7%s ^7turned scrim mode ^1off^7\n\"", ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
- trap_Cvar_Set( "g_scrimMode", "0" );
-
- } else {
- ADMP( "^3!scrim: ^7usage: !scrim [on|off]\n" );
- return qfalse;
- }
-
+ G_admin_duration( ( level.time - log->time ) / 1000, time,
+ sizeof( time ) );
+ admin_log( arg );
+ AP( va( "print \"^3revert: ^7%s^7 reverted %d %s over the past %s\n\"",
+ ent ? ent->client->pers.netname : "console",
+ level.buildId - id,
+ ( level.buildId - id ) > 1 ? "changes" : "change",
+ time ) );
+ G_BuildLogRevert( id );
return qtrue;
}
-qboolean G_admin_give(gentity_t *ent, int skiparg)
-{
- char arg_name_raw[MAX_NAME_LENGTH];
- char arg_name[MAX_NAME_LENGTH];
- char arg_amount[30];
- int target_id, amount;
- gentity_t *target;
- const char *currency;
-
- if (G_SayArgc() < 3 + skiparg) {
- ADMP("^3!give: ^7usage: !give [player] [amount]\n");
- return qfalse;
- }
-
- G_SayArgv(1 + skiparg, arg_name_raw, sizeof(arg_name_raw));
- G_SanitiseString(arg_name_raw, arg_name, sizeof(arg_name));
-
- if (is_numeric(arg_name)) {
- target_id = atoi(arg_name);
-
- if (target_id < 0 || target_id >= MAX_CLIENTS) {
- ADMP(va("^3!give: ^7invalid client number\n"));
- return qfalse;
- }
- } else {
- int pids[ MAX_CLIENTS ];
-
- if (G_ClientNumbersFromString(arg_name, pids) != 1) {
- char error[MAX_STRING_CHARS];
-
- G_MatchOnePlayer(pids, error, sizeof(error));
- ADMP(va("^3!give: ^7%s\n", error));
- return qfalse;
- }
-
- target_id = pids[0];
- }
-
-
- target = g_entities + target_id;
-
- if (!target->client ||
- target->client->pers.connected != CON_CONNECTED) {
- invalid_target:
- ADMP("^3!give: ^7invalid target\n");
- return qfalse;
- }
-
- G_SayArgv(2 + skiparg, arg_amount, sizeof(arg_amount));
- amount = atoi(arg_amount);
-
- switch (target->client->pers.teamSelection) {
- case PTE_ALIENS:
- if (amount < -9 || amount > 9) {
- too_big:
- ADMP("^3!give: ^7amount is too big\n");
- return qfalse;
- }
-
- currency = "evo";
- break;
-
- case PTE_HUMANS:
- if (amount < -2000 || amount > 2000)
- goto too_big;
-
- currency = "credit";
- break;
-
- default:
- goto invalid_target;
- }
-
- G_AddCreditToClient(target->client, amount, qtrue);
- AP(va("print \"^3!give: ^7%s^7 was given %i %s%s by ^7%s^7\n\"",
- target->client->pers.netname, amount, currency,
- (abs(amount) != 1 ? "s" : ""),
- ent ? G_admin_adminPrintName(ent) : "console"));
-
- return qtrue;
-}
-
-extern mapRotations_t mapRotations;
+/*
+================
+ G_admin_print
-qboolean G_admin_setrotation(gentity_t *ent, int skiparg)
+ This function facilitates the ADMP define. ADMP() is similar to CP except
+ that it prints the message to the server console if ent is not defined.
+================
+*/
+void G_admin_print( gentity_t *ent, const char *m )
{
- char new_rotation[MAX_NAME_LENGTH];
- int i;
-
- if (G_SayArgc() < 2 + skiparg)
- {
- ADMP("^3!setrotation: ^7usage: !setrotation [rotation]\n");
- ADMP("Available rotations:\n");
- goto rotationlist;
- }
-
- G_SayArgv(1 + skiparg, new_rotation, sizeof(new_rotation));
-
- for( i = 0; i < mapRotations.numRotations; i++ )
- {
- if( Q_stricmp( mapRotations.rotations[ i ].name, new_rotation ) == 0 )
- {
- G_StartMapRotation(new_rotation, qfalse);
- trap_SendServerCommand( -1, va("print \"^3!setrotation: ^7rotation ^3%s ^7was started by %s",
- new_rotation, ent ? G_admin_adminPrintName(ent) : "console"));
- return qtrue;
- }
- }
- ADMP("^3!setrotation: ^7rotation not found. Available rotations:\n");
- goto rotationlist;
- rotationlist:
+ if( ent )
+ trap_SendServerCommand( ent - level.gentities, va( "print \"%s\"", m ) );
+ else
{
- for( i = 0; i < mapRotations.numRotations; i++ )
+ char m2[ MAX_STRING_CHARS ];
+ if( !trap_Cvar_VariableIntegerValue( "com_ansiColor" ) )
{
- ADMP(va(" %s\n", mapRotations.rotations[ i ].name));
+ G_DecolorString( m, m2, sizeof( m2 ) );
+ trap_Print( m2 );
}
- ADMP(va("Number of available rotations: ^3%d\n", mapRotations.numRotations));
+ else
+ trap_Print( m );
}
- return qfalse;
}
-qboolean G_admin_versions(gentity_t *ent, int skiparg)
+void G_admin_buffer_begin( void )
{
- int i;
-
- ADMBP_begin();
-
- for (i = 0; i < level.maxclients; i++) {
- gclient_t *client = level.clients + i;
- char userinfo[ MAX_INFO_STRING ], *p;
-
- if (client->pers.connected == CON_DISCONNECTED)
- continue;
-
- ADMBP(va("%02i ", i));
-
- trap_GetUserinfo(i, userinfo, sizeof(userinfo));
- p = Info_ValueForKey(userinfo, "version");
-
- if (p[0])
- ADMBP(va("'%s'\n", p));
- else {
- p = Info_ValueForKey(userinfo, "cl_voip");
-
- if (p[0])
- ADMBP("probably GPP or newer\n");
- else
- ADMBP("probably stock 1.1\n");
- }
- }
-
- ADMBP_end();
- return qtrue;
-}
-
-static int calc_ff_pct(statsCounters_t *sc) {
- if (sc->dmgdone + sc->structdmgdone <= 0) {
- if (sc->ffdmgdone <= 0)
- return 0;
- else
- return 100;
- } // else {
- // return round((float)sc->ffdmgdone / (sc->ffdmgdone + sc->dmgdone + sc->structdmgdone) * 100);
- // }
+ g_bfb[ 0 ] = '\0';
}
-qboolean G_admin_showff(gentity_t *ent, int skiparg)
+void G_admin_buffer_end( gentity_t *ent )
{
- char arg_name_raw[MAX_NAME_LENGTH];
- char arg_name[MAX_NAME_LENGTH];
- int target_id, ffpct;
- gentity_t *target;
- statsCounters_t *sc;
-
- if (G_SayArgc() == 1 + skiparg) {
- int i;
- char team[4];
- gclient_t *client;
-
- ADMBP_begin();
- ADMBP("^3!showff:^7 friendly fire damage percentage for all connected players\n");
-
- for (i = 0; i < level.maxclients; i++) {
- client = &level.clients[i];
-
- if (client->pers.connected != CON_CONNECTED)
- continue;
-
- if (client->pers.teamSelection == PTE_HUMANS)
- Com_sprintf( team, sizeof( team ), "^4H", team);
- else if (client->pers.teamSelection == PTE_ALIENS)
- Com_sprintf( team, sizeof( team ), "^1A", team);
- else
- Com_sprintf( team, sizeof( team ), "^3S", team);
-
- ffpct = calc_ff_pct(&client->pers.statscounters);
- ADMBP(va("%2d %s ^1%3d%% ^7%s^7\n", i, team, ffpct, client->pers.netname));
- }
-
- ADMBP("^7for detailed information, use ^3!showff player|slot^7\n");
- ADMBP_end();
- return qtrue;
- }
-
- G_SayArgv(1 + skiparg, arg_name_raw, sizeof(arg_name_raw));
- G_SanitiseString(arg_name_raw, arg_name, sizeof(arg_name));
-
- if (is_numeric(arg_name)) {
- target_id = atoi(arg_name);
-
- if (target_id < 0 || target_id >= MAX_CLIENTS) {
- ADMP(va("^3!showff: ^7invalid client number\n"));
- return qfalse;
- }
- } else {
- int pids[MAX_CLIENTS];
-
- if (G_ClientNumbersFromString(arg_name, pids) != 1) {
- char error[MAX_STRING_CHARS];
-
- G_MatchOnePlayer(pids, error, sizeof(error));
- ADMP(va("^3!showff: ^7%s\n", error));
- return qfalse;
- }
-
- target_id = pids[0];
- }
-
- target = g_entities + target_id;
- sc = &target->client->pers.statscounters;
- ffpct = calc_ff_pct(sc);
-
- ADMP(va("^3!showff: ^7detailed FF information for %s^7:\n",
- target->client->pers.netname));
- ADMP(va("^7damage to: Enemies: ^1%d^7, structures: ^1%d^7, friendlies: ^1%d\n",
- sc->dmgdone, sc->structdmgdone, sc->ffdmgdone));
- ADMP(va("dealt ^1%d%%^7 of their total damage to the team\n", ffpct));
-
- return qtrue;
+ ADMP( g_bfb );
}
-void G_admin_tklog_cleanup( void )
+void G_admin_buffer_print( gentity_t *ent, const char *m )
{
- int i;
-
- for( i = 0; i < MAX_ADMIN_TKLOGS && g_admin_tklog[ i ]; i++ )
+ // 1022 - strlen("print 64 \"\"") - 1
+ if( strlen( m ) + strlen( g_bfb ) >= 1009 )
{
- G_Free( g_admin_tklog[ i ] );
- g_admin_tklog[ i ] = NULL;
+ ADMP( g_bfb );
+ g_bfb[ 0 ] = '\0';
}
-
- admin_tklog_index = 0;
+ Q_strcat( g_bfb, sizeof( g_bfb ), m );
}
-void G_admin_tklog_log( gentity_t *attacker, gentity_t *victim, int meansOfDeath )
-{
- g_admin_tklog_t *tklog;
- int previous;
- int count = 1;
-
- if( !attacker )
- return;
-
- previous = admin_tklog_index - 1;
- if( previous < 0 )
- previous = MAX_ADMIN_TKLOGS - 1;
-
- if( g_admin_tklog[ previous ] )
- count = g_admin_tklog[ previous ]->id + 1;
- if( g_admin_tklog[ admin_tklog_index ] )
- tklog = g_admin_tklog[ admin_tklog_index ];
- else
- tklog = G_Alloc( sizeof( g_admin_tklog_t ) );
-
- memset( tklog, 0, sizeof( g_admin_tklog_t ) );
- tklog->id = count;
- tklog->time = level.time - level.startTime;
- Q_strncpyz( tklog->name, attacker->client->pers.netname, sizeof( tklog->name ) );
-
- if( victim )
- {
- Q_strncpyz( tklog->victim, victim->client->pers.netname, sizeof( tklog->victim ) );
- tklog->damage = victim->client->tkcredits[ attacker->s.number ];
- tklog->value = victim->client->ps.stats[ STAT_MAX_HEALTH ];
- }
- else
- {
- Q_strncpyz( tklog->victim, "^3BLEEDING", sizeof( tklog->victim ) );
- tklog->damage = attacker->client->pers.statscounters.spreebleeds;
- tklog->value = g_bleedingSpree.integer * 100;
- }
-
- tklog->team = attacker->client->ps.stats[ STAT_PTEAM ];
- if( meansOfDeath == MOD_GRENADE )
- tklog->weapon = WP_GRENADE;
- else if( tklog->team == PTE_HUMANS )
- tklog->weapon = attacker->s.weapon;
- else
- tklog->weapon = attacker->client->ps.stats[ STAT_PCLASS ];
-
- g_admin_tklog[ admin_tklog_index ] = tklog;
- admin_tklog_index++;
- if( admin_tklog_index >= MAX_ADMIN_TKLOGS )
- admin_tklog_index = 0;
-}
-
-qboolean G_admin_tklog( gentity_t *ent, int skiparg )
+void G_admin_cleanup( void )
{
- g_admin_tklog_t *results[ 10 ];
- int result_index = 0;
- char *search_name = NULL;
- int index;
- int skip = 0;
- int skipped = 0;
- int checked = 0;
- char n1[ MAX_NAME_LENGTH ];
- char fmt_name[ 16 ];
- char argbuf[ 32 ];
- char *weaponName;
- int name_length = 10;
- int max_id = 0;
- int i;
- qboolean match;
-
- memset( results, 0, sizeof( results ) );
-
- index = admin_tklog_index;
- for( i = 0; i < 10; i++ )
- {
- int prev;
-
- prev = index - 1;
- if( prev < 0 )
- prev = MAX_ADMIN_TKLOGS - 1;
- if( !g_admin_tklog[ prev ] )
- break;
- if( g_admin_tklog[ prev ]->id > max_id )
- max_id = g_admin_tklog[ prev ]->id;
- index = prev;
- }
-
- if( G_SayArgc() > 1 + skiparg )
- {
- G_SayArgv( 1 + skiparg, argbuf, sizeof( argbuf ) );
- if( ( *argbuf >= '0' && *argbuf <= '9' ) || *argbuf == '-' )
- {
- int id;
-
- id = atoi( argbuf );
- if( id < 0 )
- id += ( max_id - 9 );
- else if( id <= max_id - MAX_ADMIN_TKLOGS )
- id = max_id - MAX_ADMIN_TKLOGS + 1;
-
- if( id + 9 >= max_id )
- id = max_id - 9;
- if( id < 1 )
- id = 1;
- for( i = 0; i < MAX_ADMIN_TKLOGS; i++ )
- {
- if( g_admin_tklog[ i ]->id == id )
- {
- index = i;
- break;
- }
- }
- }
- else
- {
- search_name = argbuf;
- }
-
- if( G_SayArgc() > 2 + skiparg && ( search_name ) )
- {
- char skipbuf[ 4 ];
- G_SayArgv( 2 + skiparg, skipbuf, sizeof( skipbuf ) );
- skip = atoi( skipbuf );
- }
- }
+ g_admin_level_t *l;
+ g_admin_admin_t *a;
+ g_admin_ban_t *b;
+ g_admin_command_t *c;
+ void *n;
- if( search_name )
+ for( l = g_admin_levels; l; l = n )
{
- g_admin_tklog_t *result_swap[ 10 ];
-
- memset( &result_swap, 0, sizeof( result_swap ) );
-
- index = admin_tklog_index - 1;
- if( index < 0 )
- index = MAX_ADMIN_TKLOGS - 1;
-
- while( g_admin_tklog[ index ] &&
- checked < MAX_ADMIN_TKLOGS &&
- result_index < 10 )
- {
- match = qfalse;
-
- G_SanitiseString( g_admin_tklog[ index ]->name, n1, sizeof( n1 ) );
- if( strstr( n1, search_name ) )
- match = qtrue;
-
- if( match && skip > 0 )
- {
- match = qfalse;
- skip--;
- skipped++;
- }
- if( match )
- {
- result_swap[ result_index ] = g_admin_tklog[ index ];
- result_index++;
- }
-
- checked++;
- index--;
- if( index < 0 )
- index = MAX_ADMIN_TKLOGS - 1;
- }
- // search runs backwards, turn it around
- for( i = 0; i < result_index; i++ )
- results[ i ] = result_swap[ result_index - i - 1 ];
+ n = l->next;
+ BG_Free( l );
}
- else
+ g_admin_levels = NULL;
+ for( a = g_admin_admins; a; a = n )
{
- while( g_admin_tklog[ index ] && result_index < 10 )
- {
- results[ result_index ] = g_admin_tklog[ index ];
- result_index++;
- index++;
- if( index >= MAX_ADMIN_TKLOGS )
- index = 0;
- }
+ n = a->next;
+ BG_Free( a );
}
-
- for( i = 0; results[ i ] && i < 10; i++ )
- {
- int l;
-
- G_DecolorString( results[ i ]->name, n1 );
- l = strlen( n1 );
- if( l > name_length )
- name_length = l;
- }
- ADMBP_begin( );
- for( i = 0; results[ i ] && i < 10; i++ )
+ g_admin_admins = NULL;
+ for( b = g_admin_bans; b; b = n )
{
- int t;
-
- t = results[ i ]->time / 1000;
-
- G_DecolorString( results[ i ]->name, n1 );
- Com_sprintf( fmt_name, sizeof( fmt_name ), "%%%ds",
- ( name_length + (int)( strlen( results[ i ]->name ) - strlen( n1 ) ) ) );
- Com_sprintf( n1, sizeof( n1 ), fmt_name, results[ i ]->name );
-
- if( results[ i ]->team == PTE_HUMANS )
- weaponName = BG_FindNameForWeapon( results[ i ]->weapon );
- else
- weaponName = BG_FindNameForClassNum( results[ i ]->weapon );
-
- ADMBP( va( "^7%3d %3d:%02d %s^7 %3d / %3d %10s %s^7\n",
- results[ i ]->id,
- t / 60, t % 60,
- n1,
- results[ i ]->damage,
- results[ i ]->value,
- weaponName,
- results[ i ]->victim ) );
- }
- if( search_name )
- {
- ADMBP( va( "^3!tklog:^7 Showing %d matches for '%s^7'.",
- result_index,
- argbuf ) );
- if( checked < MAX_ADMIN_TKLOGS && g_admin_tklog[ checked ] )
- ADMBP( va( " run '!tklog %s^7 %d' to see more",
- argbuf,
- skipped + result_index ) );
- ADMBP( "\n" );
- }
- else if ( results[ 0 ] )
- {
- ADMBP( va( "^3!tklog:^7 Showing %d - %d of %d.\n",
- results[ 0 ]->id,
- results[ result_index - 1 ]->id,
- max_id ) );
+ n = b->next;
+ BG_Free( b );
}
- else
+ g_admin_bans = NULL;
+ for( c = g_admin_commands; c; c = n )
{
- ADMBP( "^3!tklog:^7 log is empty.\n" );
+ n = c->next;
+ BG_Free( c );
}
- ADMBP_end( );
-
- return qtrue;
+ g_admin_commands = NULL;
+ BG_DefragmentMemory( );
}
-qboolean G_admin_sm( gentity_t *ent, int skiparg )
+qboolean G_admin_sm( gentity_t *ent )
{
const char *s;
char feature[ 16 ];
- if( G_SayArgc() < 2 + skiparg )
+ if( trap_Argc() < 2 )
{
usage:
- ADMP( "^3!sm: ^7usage: !sm ipa <IPA>\n" );
+ ADMP( "^3sm: ^7usage: sm ipa <IPA>\n" );
return qfalse;
}
- s = G_SayConcatArgs( 1 + skiparg );
+ s = ConcatArgs( 1 );
if( strchr( s, '\n' ) || strchr( s, '\r' ) )
{
- ADMP( "^3!sm: ^7invalid character\n" );
+ ADMP( "^3sm: ^7invalid character\n" );
return qfalse;
}
- G_SayArgv( 1 + skiparg, feature, sizeof( feature ) );
+ trap_Argv( 1, feature, sizeof( feature ) );
if( !Q_stricmp( feature, "ipa" ) )
{
char ipa[ 32 ];
- int parts[ 4 ];
- if( G_SayArgc() > 3 + skiparg )
+ if( trap_Argc() > 3 )
{
- ADMP( "^3!sm: ^7excessive arguments\n" );
+ ADMP( "^3sm: ^7excessive arguments\n" );
goto usage;
}
- G_SayArgv( 2 + skiparg, ipa, sizeof( ipa ) );
-
- // have a well-formed IPv4 address, because Schachtmeister silently drops all invalid requests
-
- if( sscanf( ipa, "%i.%i.%i.%i", &parts[0], &parts[1], &parts[2], &parts[3] ) != 4
- || parts[0] < 0 || parts[0] > 255
- || parts[1] < 0 || parts[1] > 255
- || parts[2] < 0 || parts[2] > 255
- || parts[3] < 0 || parts[3] > 255 )
- {
- ADMP( "^3!sm: ^7invalid IP address\n" );
- return qfalse;
- }
-
- Com_sprintf( ipa, sizeof( ipa ), "%i.%i.%i.%i", parts[0], parts[1], parts[2], parts[3] );
+ trap_Argv( 2, ipa, sizeof( ipa ) );
if( rand() % 2 /* FIXME cache hit */ )
{
const char *answer = "interesting";
- ADMP( va( "^3!sm: ^7IP address %s is: %s\n", ipa, answer ) );
+ ADMP( va( "^3sm: ^7IP address '%s^7' is: %s\n", ipa, answer ) );
return qtrue;
}
- ADMP( "^3!sm: ^7hmm...\n" );
+ ADMP( "^3sm: ^7hmm...\n" );
trap_SendConsoleCommand( EXEC_APPEND, va( "smq ipa \"%s\"\n", ipa ) );
}
else
goto usage;
return qtrue;
-}
+} \ No newline at end of file
diff --git a/src/game/g_admin.h b/src/game/g_admin.h
index 25cf2a7..3ab445e 100644
--- a/src/game/g_admin.h
+++ b/src/game/g_admin.h
@@ -1,12 +1,13 @@
/*
===========================================================================
-Copyright (C) 2004-2006 Tony J. White
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -15,8 +16,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -31,100 +32,59 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define ADMBP_begin() G_admin_buffer_begin()
#define ADMBP_end() G_admin_buffer_end(ent)
-#define MAX_ADMIN_LEVELS 32
-#define MAX_ADMIN_ADMINS 1024
-#define MAX_ADMIN_BANS 1024
-#define MAX_ADMIN_NAMELOGS 128
-#define MAX_ADMIN_NAMELOG_NAMES 5
-#define MAX_ADMIN_ADMINLOGS 128
-#define MAX_ADMIN_ADMINLOG_ARGS 50
#define MAX_ADMIN_FLAG_LEN 20
#define MAX_ADMIN_FLAGS 1024
-#define MAX_ADMIN_COMMANDS 64
#define MAX_ADMIN_CMD_LEN 20
#define MAX_ADMIN_BAN_REASON 50
-#define MAX_ADMIN_BANSUSPEND_DAYS 14
-#define MAX_ADMIN_TKLOGS 64
/*
* IMMUNITY - cannot be vote kicked, vote muted
* NOCENSORFLOOD - cannot be censored or flood protected
- * TEAMCHANGEFREE - never loses credits for changing teams
* SPECALLCHAT - can see team chat as a spectator
* FORCETEAMCHANGE - can switch teams any time, regardless of balance
* UNACCOUNTABLE - does not need to specify a reason for a kick/ban
* NOVOTELIMIT - can call a vote at any time (regardless of a vote being
* disabled or voting limitations)
* CANPERMBAN - does not need to specify a duration for a ban
- * TEAMCHATCMD - can run commands from team chat
+ * CANIPBAN - allows banning not-necessarily-connected players with CIDR notation
* ACTIVITY - inactivity rules do not apply to them
* IMMUTABLE - admin commands cannot be used on them
- * INCOGNITO - does not show up as an admin in !listplayers
- * SEESINCOGNITO - sees registered name of players flagged with INCOGNITO
- * ADMINCHAT - receives and can send /a admin messages
- * SEESFULLLISTPLAYERS - sees all information in !listplayers
- * DBUILDER - permanent designated builder
- * STEALTH - uses admin stealth
- * SPECIAL - allows some special permissions (unlimited votes etc)
- * SPECIALNAME - allows black text in name
- * .NOCHAT - mutes a player on connect
- * .NOVOTE - disallows voting by a player
+ * INCOGNITO - does not show up as an admin in /listplayers
* ALLFLAGS - all flags (including command flags) apply to this player
+ * ADMINCHAT - receives and can send /a admin messages
*/
-
-
-#define ADMF_IMMUNITY "IMMUNITY"
-#define ADMF_NOCENSORFLOOD "NOCENSORFLOOD"
-#define ADMF_TEAMCHANGEFREE "TEAMCHANGEFREE"
-#define ADMF_SPEC_ALLCHAT "SPECALLCHAT"
-#define ADMF_FORCETEAMCHANGE "FORCETEAMCHANGE"
-#define ADMF_UNACCOUNTABLE "UNACCOUNTABLE"
-#define ADMF_NO_VOTE_LIMIT "NOVOTELIMIT"
-#define ADMF_CAN_PERM_BAN "CANPERMBAN"
-#define ADMF_TEAMCHAT_CMD "TEAMCHATCMD"
-#define ADMF_ACTIVITY "ACTIVITY"
-
-#define ADMF_IMMUTABLE "IMMUTABLE"
-#define ADMF_INCOGNITO "INCOGNITO"
-#define ADMF_SEESINCOGNITO "SEESINCOGNITO"
-#define ADMF_ADMINCHAT "ADMINCHAT"
-#define ADMF_HIGHADMINCHAT "HIGHADMINCHAT"
-#define ADMF_SEESFULLLISTPLAYERS "SEESFULLLISTPLAYERS"
-#define ADMF_DBUILDER "DBUILDER"
-#define ADMF_ADMINSTEALTH "STEALTH"
-#define ADMF_ALLFLAGS "ALLFLAGS"
-
-#define ADMF_BAN_IMMUNITY "BANIMMUNITY"
-
-#define ADMF_SPECIAL "SPECIAL"
-#define ADMF_SPECIALNAME "SPECIALNAME"
-
-#define ADMF_NOSCRIMRESTRICTION "NOSCRIMRESTRICTION"
-#define ADMF_NOAUTOBAHN "NOAUTOBAHN"
-
-#define ADMF_NO_BUILD ".NOBUILD"
-#define ADMF_NO_CHAT ".NOCHAT"
-#define ADMF_NO_VOTE ".NOVOTE"
-#define ADMF_FAKE_NO_VOTE ".FAKENOVOTE"
+#define ADMF_IMMUNITY "IMMUNITY"
+#define ADMF_NOCENSORFLOOD "NOCENSORFLOOD"
+#define ADMF_SPEC_ALLCHAT "SPECALLCHAT"
+#define ADMF_FORCETEAMCHANGE "FORCETEAMCHANGE"
+#define ADMF_UNACCOUNTABLE "UNACCOUNTABLE"
+#define ADMF_NO_VOTE_LIMIT "NOVOTELIMIT"
+#define ADMF_CAN_PERM_BAN "CANPERMBAN"
+#define ADMF_CAN_IP_BAN "CANIPBAN"
+#define ADMF_ACTIVITY "ACTIVITY"
+
+#define ADMF_IMMUTABLE "IMMUTABLE"
+#define ADMF_INCOGNITO "INCOGNITO"
+#define ADMF_ALLFLAGS "ALLFLAGS"
+#define ADMF_ADMINCHAT "ADMINCHAT"
#define MAX_ADMIN_LISTITEMS 20
#define MAX_ADMIN_SHOWBANS 10
-#define MAX_ADMIN_MAPLOG_LENGTH 5
-// important note: QVM does not seem to allow a single char to be a
-// member of a struct at init time. flag has been converted to char*
typedef struct
{
char *keyword;
- qboolean ( * handler ) ( gentity_t *ent, int skiparg );
+ qboolean ( * handler ) ( gentity_t *ent );
+ qboolean silent;
char *flag;
- char *function; // used for !help
- char *syntax; // used for !help
+ char *function; // used in /adminhelp
+ char *syntax; // used in /adminhelp
}
g_admin_cmd_t;
typedef struct g_admin_level
{
+ struct g_admin_level *next;
int level;
char name[ MAX_NAME_LENGTH ];
char flags[ MAX_ADMIN_FLAGS ];
@@ -133,30 +93,48 @@ g_admin_level_t;
typedef struct g_admin_admin
{
+ struct g_admin_admin *next;
+ int level;
char guid[ 33 ];
char name[ MAX_NAME_LENGTH ];
- int level;
char flags[ MAX_ADMIN_FLAGS ];
- int seen;
}
g_admin_admin_t;
+#define ADDRLEN 16
+/*
+addr_ts are passed as "arg" to admin_search for IP address matching
+admin_search prints (char *)arg, so the stringified address needs to be first
+*/
+typedef struct
+{
+ char str[ 44 ];
+ enum
+ {
+ IPv4,
+ IPv6
+ } type;
+ byte addr[ ADDRLEN ];
+ int mask;
+} addr_t;
+
typedef struct g_admin_ban
{
+ struct g_admin_ban *next;
char name[ MAX_NAME_LENGTH ];
char guid[ 33 ];
- char ip[ 20 ];
+ addr_t ip;
char reason[ MAX_ADMIN_BAN_REASON ];
- char made[ 18 ]; // big enough for strftime() %c
+ char made[ 20 ]; // "YYYY-MM-DD hh:mm:ss"
int expires;
- int suspend;
char banner[ MAX_NAME_LENGTH ];
- int bannerlevel;
+ int warnCount;
}
g_admin_ban_t;
typedef struct g_admin_command
{
+ struct g_admin_command *next;
char command[ MAX_ADMIN_CMD_LEN ];
char exec[ MAX_QPATH ];
char desc[ 50 ];
@@ -164,156 +142,60 @@ typedef struct g_admin_command
}
g_admin_command_t;
-typedef struct
-{
- int ratingTime;
- int queryTime;
- int dispatchTime;
- int rating;
- char *comment;
-} schachtmeisterJudgement_t;
-
-typedef struct g_admin_namelog
-{
- char name[ MAX_ADMIN_NAMELOG_NAMES ][MAX_NAME_LENGTH ];
- char ip[ 16 ];
- char guid[ 33 ];
- int slot;
- qboolean banned;
- qboolean muted;
- int muteExpires;
- qboolean denyBuild;
- int denyHumanWeapons;
- int denyAlienClasses;
- int specExpires;
- int voteCount;
- schachtmeisterJudgement_t smj;
-}
-g_admin_namelog_t;
-
-typedef struct g_admin_adminlog
-{
- char name[ MAX_NAME_LENGTH ];
- char command[ MAX_ADMIN_CMD_LEN ];
- char args[ MAX_ADMIN_ADMINLOG_ARGS ];
- int id;
- int time;
- int level;
- qboolean success;
-}
-g_admin_adminlog_t;
-
-typedef struct g_admin_tklog
-{
- char name[ MAX_NAME_LENGTH ];
- char victim[ MAX_NAME_LENGTH ];
- int id;
- int time;
- int damage;
- int value;
- int team;
- int weapon;
-}
-g_admin_tklog_t;
+void G_admin_register_cmds( void );
+void G_admin_unregister_cmds( void );
+void G_admin_cmdlist( gentity_t *ent );
-qboolean G_admin_ban_check( char *userinfo, char *reason, int rlen );
-qboolean G_admin_cmd_check( gentity_t *ent, qboolean say );
-qboolean G_admin_readconfig( gentity_t *ent, int skiparg );
+qboolean G_admin_ban_check( gentity_t *ent, char *reason, int rlen );
+qboolean G_admin_cmd_check( gentity_t *ent );
+qboolean G_admin_readconfig( gentity_t *ent );
qboolean G_admin_permission( gentity_t *ent, const char *flag );
qboolean G_admin_name_check( gentity_t *ent, char *name, char *err, int len );
-void G_admin_namelog_update( gclient_t *ent, qboolean disconnect );
-void G_admin_maplog_result( char *flag );
-int G_admin_level( gentity_t *ent );
-void G_admin_set_adminname( gentity_t *ent );
-char* G_admin_adminPrintName( gentity_t *ent );
-
-qboolean G_admin_seen(gentity_t *ent, int skiparg );
-void G_admin_seen_update( char *guid );
-
-// ! command functions
-qboolean G_admin_time( gentity_t *ent, int skiparg );
-qboolean G_admin_setlevel( gentity_t *ent, int skiparg );
-qboolean G_admin_flaglist( gentity_t *ent, int skiparg );
-qboolean G_admin_flag( gentity_t *ent, int skiparg );
-qboolean G_admin_kick( gentity_t *ent, int skiparg );
-qboolean G_admin_adjustban( gentity_t *ent, int skiparg );
-qboolean G_admin_subnetban( gentity_t *ent, int skiparg );
-qboolean G_admin_suspendban( gentity_t *ent, int skiparg );
-qboolean G_admin_ban( gentity_t *ent, int skiparg );
-qboolean G_admin_unban( gentity_t *ent, int skiparg );
-qboolean G_admin_putteam( gentity_t *ent, int skiparg );
-qboolean G_admin_adminlog( gentity_t *ent, int skiparg );
-void G_admin_adminlog_cleanup( void );
-void G_admin_adminlog_log( gentity_t *ent, char *command, char *args, int skiparg, qboolean success );
-qboolean G_admin_listadmins( gentity_t *ent, int skiparg );
-qboolean G_admin_listlayouts( gentity_t *ent, int skiparg );
-qboolean G_admin_listplayers( gentity_t *ent, int skiparg );
-qboolean G_admin_listmaps( gentity_t *ent, int skiparg );
-qboolean G_admin_listrotation( gentity_t *ent, int skiparg );
-qboolean G_admin_map( gentity_t *ent, int skiparg );
-qboolean G_admin_devmap( gentity_t *ent, int skiparg );
-void G_admin_maplog_update( void );
-qboolean G_admin_maplog( gentity_t *ent, int skiparg );
-qboolean G_admin_layoutsave( gentity_t *ent, int skiparg );
-qboolean G_admin_demo( gentity_t *ent, int skiparg );
-qboolean G_admin_mute( gentity_t *ent, int skiparg );
-qboolean G_admin_denybuild( gentity_t *ent, int skiparg );
-qboolean G_admin_denyweapon( gentity_t *ent, int skiparg );
-qboolean G_admin_showbans( gentity_t *ent, int skiparg );
-qboolean G_admin_help( gentity_t *ent, int skiparg );
-qboolean G_admin_admintest( gentity_t *ent, int skiparg );
-qboolean G_admin_allready( gentity_t *ent, int skiparg );
-qboolean G_admin_cancelvote( gentity_t *ent, int skiparg );
-qboolean G_admin_passvote( gentity_t *ent, int skiparg );
-qboolean G_admin_spec999( gentity_t *ent, int skiparg );
-qboolean G_admin_register( gentity_t *ent, int skiparg );
-qboolean G_admin_rename( gentity_t *ent, int skiparg );
-qboolean G_admin_restart( gentity_t *ent, int skiparg );
-qboolean G_admin_nobuild( gentity_t *ent, int skiparg );
-qboolean G_admin_nextmap( gentity_t *ent, int skiparg );
-qboolean G_admin_namelog( gentity_t *ent, int skiparg );
-qboolean G_admin_lock( gentity_t *ent, int skiparg );
-qboolean G_admin_unlock( gentity_t *ent, int skiparg );
-qboolean G_admin_info( gentity_t *ent, int skiparg );
-qboolean G_admin_buildlog( gentity_t *ent, int skiparg );
-qboolean G_admin_revert( gentity_t *ent, int skiparg );
-qboolean G_admin_decon( gentity_t *ent, int skiparg );
-qboolean G_admin_pause( gentity_t *ent, int skiparg );
-qboolean G_admin_L0( gentity_t *ent, int skiparg );
-qboolean G_admin_L1( gentity_t *ent, int skiparg );
-qboolean G_admin_putmespec( gentity_t *ent, int skiparg );
-qboolean G_admin_warn( gentity_t *ent, int skiparg );
-qboolean G_admin_designate( gentity_t *ent, int skiparg );
-qboolean G_admin_cp( gentity_t *ent, int skiparg );
-
-qboolean G_admin_slap( gentity_t *ent, int skiparg );
-qboolean G_admin_drop( gentity_t *ent, int skiparg );
-qboolean G_admin_invisible( gentity_t *ent, int skiparg );
-qboolean G_admin_setdevmode( gentity_t *ent, int skiparg );
-qboolean G_admin_hstage( gentity_t *ent, int skiparg );
-qboolean G_admin_astage( gentity_t *ent, int skiparg );
-qboolean G_admin_bubble( gentity_t *ent, int skiparg );
-qboolean G_admin_scrim( gentity_t *ent, int skiparg );
-qboolean G_admin_give( gentity_t *ent, int skiparg );
-qboolean G_admin_setrotation( gentity_t *ent, int skiparg );
-qboolean G_admin_versions( gentity_t *ent, int skiparg );
-qboolean G_admin_showff(gentity_t *ent, int skiparg);
-qboolean G_admin_tklog( gentity_t *ent, int skiparg );
-void G_admin_tklog_cleanup( void );
-void G_admin_tklog_log( gentity_t *attacker, gentity_t *victim, int meansOfDeath );
-void G_admin_IPA_judgement( const char *ipa, int rating, const char *comment );
-qboolean G_admin_sm( gentity_t *ent, int skiparg );
-void G_admin_schachtmeisterFrame( void );
-qboolean G_admin_is_restricted(gentity_t *ent, qboolean sendMessage);
-
-void G_admin_print( gentity_t *ent, char *m );
-void G_admin_buffer_print( gentity_t *ent, char *m );
+g_admin_admin_t *G_admin_admin( const char *guid );
+void G_admin_authlog( gentity_t *ent );
+
+// admin command functions
+qboolean G_admin_time( gentity_t *ent );
+qboolean G_admin_setlevel( gentity_t *ent );
+qboolean G_admin_kick( gentity_t *ent );
+qboolean G_admin_addlayout( gentity_t *ent );
+qboolean G_admin_setivo( gentity_t *ent );
+qboolean G_admin_adjustban( gentity_t *ent );
+qboolean G_admin_ban( gentity_t *ent );
+qboolean G_admin_unban( gentity_t *ent );
+qboolean G_admin_putteam( gentity_t *ent );
+qboolean G_admin_listadmins( gentity_t *ent );
+qboolean G_admin_listlayouts( gentity_t *ent );
+qboolean G_admin_listplayers( gentity_t *ent );
+qboolean G_admin_changemap( gentity_t *ent );
+qboolean G_admin_mute( gentity_t *ent );
+qboolean G_admin_denybuild( gentity_t *ent );
+qboolean G_admin_showbans( gentity_t *ent );
+qboolean G_admin_adminhelp( gentity_t *ent );
+qboolean G_admin_admintest( gentity_t *ent );
+qboolean G_admin_allready( gentity_t *ent );
+qboolean G_admin_endvote( gentity_t *ent );
+qboolean G_admin_spec999( gentity_t *ent );
+qboolean G_admin_transform( gentity_t *ent );
+qboolean G_admin_rename( gentity_t *ent );
+qboolean G_admin_restart( gentity_t *ent );
+qboolean G_admin_nextmap( gentity_t *ent );
+qboolean G_admin_setnextmap( gentity_t *ent );
+qboolean G_admin_namelog( gentity_t *ent );
+qboolean G_admin_lock( gentity_t *ent );
+qboolean G_admin_pause( gentity_t *ent );
+qboolean G_admin_builder( gentity_t *ent );
+qboolean G_admin_buildlog( gentity_t *ent );
+qboolean G_admin_revert( gentity_t *ent );
+qboolean G_admin_setdevmode( gentity_t *ent );
+qboolean G_admin_sm( gentity_t *ent );
+
+void G_admin_print( gentity_t *ent, const char *m );
+void G_admin_buffer_print( gentity_t *ent, const char *m );
void G_admin_buffer_begin( void );
void G_admin_buffer_end( gentity_t *ent );
void G_admin_duration( int secs, char *duration, int dursize );
void G_admin_cleanup( void );
-void G_admin_namelog_cleanup( void );
-void admin_writeconfig( void );
#endif /* ifndef _G_ADMIN_H */
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 461c2d0..05135c4 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,16 +17,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
#include "g_local.h"
-// from g_combat.c
-extern char *modNames[ ];
-
/*
================
G_SetBuildableAnim
@@ -35,19 +33,17 @@ Triggers an animation client side
*/
void G_SetBuildableAnim( gentity_t *ent, buildableAnimNumber_t anim, qboolean force )
{
- int localAnim = anim;
+ int localAnim = anim | ( ent->s.legsAnim & ANIM_TOGGLEBIT );
if( force )
localAnim |= ANIM_FORCEBIT;
- // don't toggle the togglebit more than once per frame
+ // don't flip the togglebit more than once per frame
if( ent->animTime != level.time )
{
- localAnim |= ( ( ent->s.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT );
ent->animTime = level.time;
+ localAnim ^= ANIM_TOGGLEBIT;
}
- else
- localAnim |= ent->s.legsAnim & ANIM_TOGGLEBIT;
ent->s.legsAnim = localAnim;
}
@@ -71,8 +67,8 @@ G_CheckSpawnPoint
Check if a spawn at a specified point is valid
===============
*/
-gentity_t *G_CheckSpawnPoint( int spawnNum, vec3_t origin, vec3_t normal,
- buildable_t spawn, vec3_t spawnOrigin )
+gentity_t *G_CheckSpawnPoint( int spawnNum, const vec3_t origin,
+ const vec3_t normal, buildable_t spawn, vec3_t spawnOrigin )
{
float displacement;
vec3_t mins, maxs;
@@ -80,83 +76,40 @@ gentity_t *G_CheckSpawnPoint( int spawnNum, vec3_t origin, vec3_t normal,
vec3_t localOrigin;
trace_t tr;
- BG_FindBBoxForBuildable( spawn, mins, maxs );
+ BG_BuildableBoundingBox( spawn, mins, maxs );
if( spawn == BA_A_SPAWN )
{
VectorSet( cmins, -MAX_ALIEN_BBOX, -MAX_ALIEN_BBOX, -MAX_ALIEN_BBOX );
VectorSet( cmaxs, MAX_ALIEN_BBOX, MAX_ALIEN_BBOX, MAX_ALIEN_BBOX );
- displacement = ( maxs[ 2 ] + MAX_ALIEN_BBOX ) * M_ROOT3;
+ displacement = ( maxs[ 2 ] + MAX_ALIEN_BBOX ) * M_ROOT3 + 1.0f;
VectorMA( origin, displacement, normal, localOrigin );
-
- trap_Trace( &tr, origin, NULL, NULL, localOrigin, spawnNum, MASK_SHOT );
-
- if( tr.entityNum != ENTITYNUM_NONE )
- return &g_entities[ tr.entityNum ];
-
- trap_Trace( &tr, localOrigin, cmins, cmaxs, localOrigin, -1, MASK_PLAYERSOLID );
-
- if( tr.entityNum == ENTITYNUM_NONE )
- {
- if( spawnOrigin != NULL )
- VectorCopy( localOrigin, spawnOrigin );
-
- return NULL;
- }
- else
- return &g_entities[ tr.entityNum ];
}
else if( spawn == BA_H_SPAWN )
{
- BG_FindBBoxForClass( PCL_HUMAN, cmins, cmaxs, NULL, NULL, NULL );
+ BG_ClassBoundingBox( PCL_HUMAN, cmins, cmaxs, NULL, NULL, NULL );
VectorCopy( origin, localOrigin );
localOrigin[ 2 ] += maxs[ 2 ] + fabs( cmins[ 2 ] ) + 1.0f;
-
- trap_Trace( &tr, origin, NULL, NULL, localOrigin, spawnNum, MASK_SHOT );
-
- if( tr.entityNum != ENTITYNUM_NONE )
- return &g_entities[ tr.entityNum ];
-
- trap_Trace( &tr, localOrigin, cmins, cmaxs, localOrigin, -1, MASK_PLAYERSOLID );
-
- if( tr.entityNum == ENTITYNUM_NONE )
- {
- if( spawnOrigin != NULL )
- VectorCopy( localOrigin, spawnOrigin );
-
- return NULL;
- }
- else
- return &g_entities[ tr.entityNum ];
}
+ else
+ return NULL;
- return NULL;
-}
+ trap_Trace( &tr, origin, NULL, NULL, localOrigin, spawnNum, MASK_SHOT );
-/*
-================
-G_NumberOfDependants
+ if( tr.entityNum != ENTITYNUM_NONE )
+ return &g_entities[ tr.entityNum ];
-Return number of entities that depend on this one
-================
-*/
-static int G_NumberOfDependants( gentity_t *self )
-{
- int i, n = 0;
- gentity_t *ent;
+ trap_Trace( &tr, localOrigin, cmins, cmaxs, localOrigin, ENTITYNUM_NONE, MASK_PLAYERSOLID );
- for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
- {
- if( ent->s.eType != ET_BUILDABLE )
- continue;
+ if( tr.entityNum != ENTITYNUM_NONE )
+ return &g_entities[ tr.entityNum ];
- if( ent->parentNode == self )
- n++;
- }
+ if( spawnOrigin != NULL )
+ VectorCopy( localOrigin, spawnOrigin );
- return n;
+ return NULL;
}
#define POWER_REFRESH_TIME 2000
@@ -168,191 +121,403 @@ G_FindPower
attempt to find power for self, return qtrue if successful
================
*/
-static qboolean G_FindPower( gentity_t *self )
+qboolean G_FindPower( gentity_t *self, qboolean searchUnspawned )
{
- int i;
- gentity_t *ent;
+ int i, j;
+ gentity_t *ent, *ent2;
gentity_t *closestPower = NULL;
int distance = 0;
- int minDistance = 10000;
+ int minDistance = REPEATER_BASESIZE + 1;
vec3_t temp_v;
- if( self->biteam != BIT_HUMANS )
+ if( self->buildableTeam != TEAM_HUMANS )
return qfalse;
- //reactor is always powered
+ // Reactor is always powered
if( self->s.modelindex == BA_H_REACTOR )
- return qtrue;
+ {
+ self->parentNode = self;
- //if this already has power then stop now
- if( self->parentNode && self->parentNode->powered )
return qtrue;
+ }
- //reset parent
- self->parentNode = NULL;
+ // Handle repeaters
+ if( self->s.modelindex == BA_H_REPEATER )
+ {
+ self->parentNode = G_Reactor( );
- //iterate through entities
- for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ return self->parentNode != NULL;
+ }
+
+ // Iterate through entities
+ for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
{
if( ent->s.eType != ET_BUILDABLE )
continue;
- //if entity is a power item calculate the distance to it
+ // If entity is a power item calculate the distance to it
if( ( ent->s.modelindex == BA_H_REACTOR || ent->s.modelindex == BA_H_REPEATER ) &&
- ent->spawned )
+ ( searchUnspawned || ent->spawned ) && ent->powered && ent->health > 0 )
{
- VectorSubtract( self->s.origin, ent->s.origin, temp_v );
+ VectorSubtract( self->r.currentOrigin, ent->r.currentOrigin, temp_v );
distance = VectorLength( temp_v );
- if( distance < minDistance && ent->powered &&
- ( ( ent->s.modelindex == BA_H_REACTOR &&
- distance <= REACTOR_BASESIZE ) ||
- ( ent->s.modelindex == BA_H_REPEATER &&
- distance <= REPEATER_BASESIZE ) ) ) {
+ // Always prefer a reactor if there is one in range
+ if( ent->s.modelindex == BA_H_REACTOR && distance <= REACTOR_BASESIZE )
+ {
+ // Only power as much BP as the reactor can hold
+ if( self->s.modelindex != BA_NONE )
+ {
+ int buildPoints = g_humanBuildPoints.integer;
+
+ // Scan the buildables in the reactor zone
+ for( j = MAX_CLIENTS, ent2 = g_entities + j; j < level.num_entities; j++, ent2++ )
+ {
+ if( ent2->s.eType != ET_BUILDABLE )
+ continue;
+
+ if( ent2 == self )
+ continue;
+
+ if( ent2->parentNode == ent )
+ {
+ buildPoints -= BG_Buildable( ent2->s.modelindex )->buildPoints;
+ }
+ }
+
+ buildPoints -= level.humanBuildPointQueue;
+
+ buildPoints -= BG_Buildable( self->s.modelindex )->buildPoints;
+ if( buildPoints >= 0 )
+ {
+ self->parentNode = ent;
+ return qtrue;
+ }
+ else
+ {
+ // a buildable can still be built if it shares BP from two zones
+
+ // TODO: handle combined power zones here
+ }
+ }
+
+ // Dummy buildables don't need to look for zones
+ else
+ {
+ self->parentNode = ent;
+ return qtrue;
+ }
+ }
+ else if( distance < minDistance )
+ {
+ // It's a repeater, so check that enough BP will be available to power
+ // the buildable but only if self is a real buildable
+
+ if( self->s.modelindex != BA_NONE )
+ {
+ int buildPoints = g_humanRepeaterBuildPoints.integer;
+
+ // Scan the buildables in the repeater zone
+ for( j = MAX_CLIENTS, ent2 = g_entities + j; j < level.num_entities; j++, ent2++ )
+ {
+ if( ent2->s.eType != ET_BUILDABLE )
+ continue;
+
+ if( ent2 == self )
+ continue;
+
+ if( ent2->parentNode == ent )
+ buildPoints -= BG_Buildable( ent2->s.modelindex )->buildPoints;
+ }
+
+ if( ent->usesBuildPointZone && level.buildPointZones[ ent->buildPointZone ].active )
+ buildPoints -= level.buildPointZones[ ent->buildPointZone ].queuedBuildPoints;
+
+ buildPoints -= BG_Buildable( self->s.modelindex )->buildPoints;
+
+ if( buildPoints >= 0 )
+ {
+ closestPower = ent;
+ minDistance = distance;
+ }
+ else
+ {
+ // a buildable can still be built if it shares BP from two zones
+
+ // TODO: handle combined power zones here
+ }
+ }
+ else
+ {
+ // Dummy buildables don't need to look for zones
closestPower = ent;
minDistance = distance;
+ }
}
}
}
- //if there were no power items nearby give up
- if( closestPower ) {
- self->parentNode = closestPower;
- return qtrue;
- }
- else
- return qfalse;
+ self->parentNode = closestPower;
+ return self->parentNode != NULL;
}
/*
================
-G_IsPowered
+G_PowerEntityForPoint
-Simple wrapper to G_FindPower to check if a location has power
+Simple wrapper to G_FindPower to find the entity providing
+power for the specified point
================
*/
-qboolean G_IsPowered( vec3_t origin )
+gentity_t *G_PowerEntityForPoint( const vec3_t origin )
{
gentity_t dummy;
dummy.parentNode = NULL;
- dummy.biteam = BIT_HUMANS;
+ dummy.buildableTeam = TEAM_HUMANS;
dummy.s.modelindex = BA_NONE;
- VectorCopy( origin, dummy.s.origin );
+ VectorCopy( origin, dummy.r.currentOrigin );
- return G_FindPower( &dummy );
+ if( G_FindPower( &dummy, qfalse ) )
+ return dummy.parentNode;
+ else
+ return NULL;
}
/*
================
-G_FindDCC
+G_PowerEntityForEntity
-attempt to find a controlling DCC for self, return qtrue if successful
+Simple wrapper to G_FindPower to find the entity providing
+power for the specified entity
================
*/
-static qboolean G_FindDCC( gentity_t *self )
+gentity_t *G_PowerEntityForEntity( gentity_t *ent )
+{
+ if( G_FindPower( ent, qfalse ) )
+ return ent->parentNode;
+ return NULL;
+}
+
+/*
+================
+G_IsPowered
+
+Check if a location has power, returning the entity type
+that is providing it
+================
+*/
+buildable_t G_IsPowered( vec3_t origin )
+{
+ gentity_t *ent = G_PowerEntityForPoint( origin );
+
+ if( ent )
+ return ent->s.modelindex;
+ else
+ return BA_NONE;
+}
+
+
+/*
+==================
+G_GetBuildPoints
+
+Get the number of build points from a position
+==================
+*/
+int G_GetBuildPoints( const vec3_t pos, team_t team )
+{
+ if( G_TimeTilSuddenDeath( ) <= 0 )
+ {
+ return 0;
+ }
+ else if( team == TEAM_ALIENS )
+ {
+ return level.alienBuildPoints;
+ }
+ else if( team == TEAM_HUMANS )
+ {
+ gentity_t *powerPoint = G_PowerEntityForPoint( pos );
+
+ if( powerPoint && powerPoint->s.modelindex == BA_H_REACTOR )
+ return level.humanBuildPoints;
+
+ if( powerPoint && powerPoint->s.modelindex == BA_H_REPEATER &&
+ powerPoint->usesBuildPointZone && level.buildPointZones[ powerPoint->buildPointZone ].active )
+ {
+ return level.buildPointZones[ powerPoint->buildPointZone ].totalBuildPoints -
+ level.buildPointZones[ powerPoint->buildPointZone ].queuedBuildPoints;
+ }
+
+ // Return the BP of the main zone by default
+ return level.humanBuildPoints;
+ }
+
+ return 0;
+}
+
+/*
+==================
+G_GetMarkedBuildPoints
+
+Get the number of marked build points from a position
+==================
+*/
+int G_GetMarkedBuildPoints( const vec3_t pos, team_t team )
{
- int i;
gentity_t *ent;
- gentity_t *closestDCC = NULL;
- int distance = 0;
- int minDistance = 10000;
- vec3_t temp_v;
- qboolean foundDCC = qfalse;
+ int i;
+ int sum = 0;
- if( self->biteam != BIT_HUMANS )
- return qfalse;
+ if( G_TimeTilSuddenDeath( ) <= 0 )
+ return 0;
- //if this already has dcc then stop now
- if( self->dccNode && self->dccNode->powered )
- return qtrue;
+ if( !g_markDeconstruct.integer )
+ return 0;
- //reset parent
- self->dccNode = NULL;
+ for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ {
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
- //iterate through entities
- for( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ if( team == TEAM_HUMANS &&
+ ent->s.modelindex != BA_H_REACTOR &&
+ ent->s.modelindex != BA_H_REPEATER &&
+ ent->parentNode != G_PowerEntityForPoint( pos ) )
+ continue;
+
+ if( !ent->inuse )
+ continue;
+
+ if( ent->health <= 0 )
+ continue;
+
+ if( ent->buildableTeam != team )
+ continue;
+
+ if( ent->deconstruct )
+ sum += BG_Buildable( ent->s.modelindex )->buildPoints;
+ }
+
+ return sum;
+}
+
+/*
+==================
+G_InPowerZone
+
+See if a buildable is inside of another power zone.
+Return pointer to provider if so.
+It's different from G_FindPower because FindPower for
+providers will find themselves.
+(This doesn't check if power zones overlap)
+==================
+*/
+gentity_t *G_InPowerZone( gentity_t *self )
+{
+ int i;
+ gentity_t *ent;
+ int distance;
+ vec3_t temp_v;
+
+ for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
{
if( ent->s.eType != ET_BUILDABLE )
continue;
- //if entity is a dcc calculate the distance to it
- if( ent->s.modelindex == BA_H_DCC && ent->spawned )
+ if( ent == self )
+ continue;
+
+ if( !ent->spawned )
+ continue;
+
+ if( ent->health <= 0 )
+ continue;
+
+ // if entity is a power item calculate the distance to it
+ if( ( ent->s.modelindex == BA_H_REACTOR || ent->s.modelindex == BA_H_REPEATER ) &&
+ ent->spawned && ent->powered )
{
- VectorSubtract( self->s.origin, ent->s.origin, temp_v );
+ VectorSubtract( self->r.currentOrigin, ent->r.currentOrigin, temp_v );
distance = VectorLength( temp_v );
- if( ( !foundDCC || distance < minDistance ) && ent->powered )
- {
- closestDCC = ent;
- minDistance = distance;
- foundDCC = qtrue;
- }
+
+ if( ent->s.modelindex == BA_H_REACTOR && distance <= REACTOR_BASESIZE )
+ return ent;
+ else if( ent->s.modelindex == BA_H_REPEATER && distance <= REPEATER_BASESIZE )
+ return ent;
}
}
- //if there was no nearby DCC give up
- if( !foundDCC )
- return qfalse;
-
- self->dccNode = closestDCC;
-
- return qtrue;
+ return NULL;
}
/*
================
-G_IsDCCBuilt
+G_FindDCC
-simple wrapper to G_FindDCC to check for a dcc
+attempt to find a controlling DCC for self, return number found
================
*/
-qboolean G_IsDCCBuilt( void )
+int G_FindDCC( gentity_t *self )
{
- gentity_t dummy;
+ int i;
+ gentity_t *ent;
+ int distance = 0;
+ vec3_t temp_v;
+ int foundDCC = 0;
- memset( &dummy, 0, sizeof( gentity_t ) );
+ if( self->buildableTeam != TEAM_HUMANS )
+ return 0;
- dummy.dccNode = NULL;
- dummy.biteam = BIT_HUMANS;
+ //iterate through entities
+ for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ {
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
- return G_FindDCC( &dummy );
+ //if entity is a dcc calculate the distance to it
+ if( ent->s.modelindex == BA_H_DCC && ent->spawned )
+ {
+ VectorSubtract( self->r.currentOrigin, ent->r.currentOrigin, temp_v );
+ distance = VectorLength( temp_v );
+ if( distance < DC_RANGE && ent->powered )
+ {
+ foundDCC++;
+ }
+ }
+ }
+
+ return foundDCC;
}
/*
================
-G_FindOvermind
+G_IsDCCBuilt
-Attempt to find an overmind for self
+See if any powered DCC exists
================
*/
-static qboolean G_FindOvermind( gentity_t *self )
+qboolean G_IsDCCBuilt( void )
{
int i;
gentity_t *ent;
- if( self->biteam != BIT_ALIENS )
- return qfalse;
+ for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ {
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
- //if this already has overmind then stop now
- if( self->overmindNode && self->overmindNode->health > 0 )
- return qtrue;
+ if( ent->s.modelindex != BA_H_DCC )
+ continue;
- //reset parent
- self->overmindNode = NULL;
+ if( !ent->spawned )
+ continue;
- //iterate through entities
- for( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
- {
- if( ent->s.eType != ET_BUILDABLE )
+ if( ent->health <= 0 )
continue;
- //if entity is an overmind calculate the distance to it
- if( ent->s.modelindex == BA_A_OVERMIND && ent->spawned && ent->health > 0 )
- {
- self->overmindNode = ent;
- return qtrue;
- }
+ return qtrue;
}
return qfalse;
@@ -360,21 +525,46 @@ static qboolean G_FindOvermind( gentity_t *self )
/*
================
-G_IsOvermindBuilt
+G_Reactor
+G_Overmind
+
+Since there's only one of these and we quite often want to find them, cache the
+results, but check them for validity each time
-Simple wrapper to G_FindOvermind to check if a location has an overmind
+The code here will break if more than one reactor or overmind is allowed, even
+if one of them is dead/unspawned
================
*/
-qboolean G_IsOvermindBuilt( void )
+static gentity_t *G_FindBuildable( buildable_t buildable );
+
+gentity_t *G_Reactor( void )
{
- gentity_t dummy;
+ static gentity_t *rc;
- memset( &dummy, 0, sizeof( gentity_t ) );
+ // If cache becomes invalid renew it
+ if( !rc || rc->s.eType != ET_BUILDABLE || rc->s.modelindex != BA_H_REACTOR )
+ rc = G_FindBuildable( BA_H_REACTOR );
- dummy.overmindNode = NULL;
- dummy.biteam = BIT_ALIENS;
+ // If we found it and it's alive, return it
+ if( rc && rc->spawned && rc->health > 0 )
+ return rc;
- return G_FindOvermind( &dummy );
+ return NULL;
+}
+
+gentity_t *G_Overmind( void )
+{
+ static gentity_t *om;
+
+ // If cache becomes invalid renew it
+ if( !om || om->s.eType != ET_BUILDABLE || om->s.modelindex != BA_A_OVERMIND )
+ om = G_FindBuildable( BA_A_OVERMIND );
+
+ // If we found it and it's alive, return it
+ if( om && om->spawned && om->health > 0 )
+ return om;
+
+ return NULL;
}
/*
@@ -384,7 +574,7 @@ G_FindCreep
attempt to find creep for self, return qtrue if successful
================
*/
-static qboolean G_FindCreep( gentity_t *self )
+qboolean G_FindCreep( gentity_t *self )
{
int i;
gentity_t *ent;
@@ -394,21 +584,23 @@ static qboolean G_FindCreep( gentity_t *self )
vec3_t temp_v;
//don't check for creep if flying through the air
- if( self->s.groundEntityNum == -1 )
+ if( !self->client && self->s.groundEntityNum == ENTITYNUM_NONE )
return qtrue;
- //if self does not have a parentNode or it's parentNode is invalid find a new one
- if( ( self->parentNode == NULL ) || !self->parentNode->inuse )
+ //if self does not have a parentNode or its parentNode is invalid, then find a new one
+ if( self->client || self->parentNode == NULL || !self->parentNode->inuse ||
+ self->parentNode->health <= 0 )
{
- for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
{
if( ent->s.eType != ET_BUILDABLE )
continue;
- if( ( ent->s.modelindex == BA_A_SPAWN || ent->s.modelindex == BA_A_OVERMIND ) &&
- ent->spawned )
+ if( ( ent->s.modelindex == BA_A_SPAWN ||
+ ent->s.modelindex == BA_A_OVERMIND ) &&
+ ent->spawned && ent->health > 0 )
{
- VectorSubtract( self->s.origin, ent->s.origin, temp_v );
+ VectorSubtract( self->r.currentOrigin, ent->r.currentOrigin, temp_v );
distance = VectorLength( temp_v );
if( distance < minDistance )
{
@@ -420,13 +612,17 @@ static qboolean G_FindCreep( gentity_t *self )
if( minDistance <= CREEP_BASESIZE )
{
- self->parentNode = closestSpawn;
+ if( !self->client )
+ self->parentNode = closestSpawn;
return qtrue;
}
else
return qfalse;
}
+ if( self->client )
+ return qfalse;
+
//if we haven't returned by now then we must already have a valid parent
return qtrue;
}
@@ -446,7 +642,7 @@ static qboolean G_IsCreepHere( vec3_t origin )
dummy.parentNode = NULL;
dummy.s.modelindex = BA_NONE;
- VectorCopy( origin, dummy.s.origin );
+ VectorCopy( origin, dummy.r.currentOrigin );
return G_FindCreep( &dummy );
}
@@ -466,12 +662,12 @@ static void G_CreepSlow( gentity_t *self )
int i, num;
gentity_t *enemy;
buildable_t buildable = self->s.modelindex;
- float creepSize = (float)BG_FindCreepSizeForBuildable( buildable );
+ float creepSize = (float)BG_Buildable( buildable )->creepSize;
VectorSet( range, creepSize, creepSize, creepSize );
- VectorAdd( self->s.origin, range, maxs );
- VectorSubtract( self->s.origin, range, mins );
+ VectorAdd( self->r.currentOrigin, range, maxs );
+ VectorSubtract( self->r.currentOrigin, range, mins );
//find humans
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
@@ -479,12 +675,11 @@ static void G_CreepSlow( gentity_t *self )
{
enemy = &g_entities[ entityList[ i ] ];
- if( enemy->flags & FL_NOTARGET )
- continue;
+ if( enemy->flags & FL_NOTARGET )
+ continue;
- if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS &&
- enemy->client->ps.groundEntityNum != ENTITYNUM_NONE &&
- G_Visible( self, enemy ) )
+ if( enemy->client && enemy->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS &&
+ enemy->client->ps.groundEntityNum != ENTITYNUM_NONE )
{
enemy->client->ps.stats[ STAT_STATE ] |= SS_CREEPSLOWED;
enemy->client->lastCreepSlowTime = level.time;
@@ -503,41 +698,27 @@ static void nullDieFunction( gentity_t *self, gentity_t *inflictor, gentity_t *a
{
}
-static void G_BuildableDeathSound( gentity_t *self )
-{
- gentity_t *snd = G_TempEntity( self->r.currentOrigin, EV_GENERAL_SOUND );
- snd->s.eventParm = G_SoundIndex( BG_FindTeamForBuildable( self->s.modelindex ) == PTE_HUMANS ?
- "sound/buildables/human/destroyed" : "sound/buildables/alien/construct2" );
-}
-
-/*
-================
-freeBuildable
-================
-*/
-static void freeBuildable( gentity_t *self )
-{
- G_FreeEntity( self );
-}
-
-
//==================================================================================
/*
================
-A_CreepRecede
+AGeneric_CreepRecede
-Called when an alien spawn dies
+Called when an alien buildable dies
================
*/
-void A_CreepRecede( gentity_t *self )
+void AGeneric_CreepRecede( gentity_t *self )
{
//if the creep just died begin the recession
if( !( self->s.eFlags & EF_DEAD ) )
{
self->s.eFlags |= EF_DEAD;
+ G_QueueBuildPoints( self );
+
+ G_RewardAttackers( self );
+
G_AddEvent( self, EV_BUILD_DESTROY, 0 );
if( self->spawned )
@@ -546,7 +727,7 @@ void A_CreepRecede( gentity_t *self )
self->s.time = -( level.time -
(int)( (float)CREEP_SCALEDOWN_TIME *
( 1.0f - ( (float)( level.time - self->buildTime ) /
- (float)BG_FindBuildTimeForBuildable( self->s.modelindex ) ) ) ) );
+ (float)BG_Buildable( self->s.modelindex )->buildTime ) ) ) );
}
//creep is still receeding
@@ -556,71 +737,30 @@ void A_CreepRecede( gentity_t *self )
G_FreeEntity( self );
}
-
-
-
-//==================================================================================
-
-
-
-
/*
================
-ASpawn_Melt
+AGeneric_Blast
-Called when an alien spawn dies
+Called when an Alien buildable explodes after dead state
================
*/
-void ASpawn_Melt( gentity_t *self )
+void AGeneric_Blast( gentity_t *self )
{
- G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage,
- self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS );
-
- //start creep recession
- if( !( self->s.eFlags & EF_DEAD ) )
- {
- self->s.eFlags |= EF_DEAD;
- G_AddEvent( self, EV_BUILD_DESTROY, 0 );
-
- if( self->spawned )
- self->s.time = -level.time;
- else
- self->s.time = -( level.time -
- (int)( (float)CREEP_SCALEDOWN_TIME *
- ( 1.0f - ( (float)( level.time - self->buildTime ) /
- (float)BG_FindBuildTimeForBuildable( self->s.modelindex ) ) ) ) );
- }
-
- //not dead yet
- if( ( self->timestamp + 10000 ) > level.time )
- self->nextthink = level.time + 500;
- else //dead now
- G_FreeEntity( self );
-}
-
-/*
-================
-ASpawn_Blast
-
-Called when an alien spawn dies
-================
-*/
-void ASpawn_Blast( gentity_t *self )
-{
- vec3_t dir;
+ vec3_t dir;
VectorCopy( self->s.origin2, dir );
//do a bit of radius damage
- G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage,
- self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS );
+ G_SelectiveRadiusDamage( self->s.pos.trBase, g_entities + self->killedBy, self->splashDamage,
+ self->splashRadius, self, self->splashMethodOfDeath,
+ TEAM_ALIENS );
//pretty events and item cleanup
self->s.eFlags |= EF_NODRAW; //don't draw the model once it's destroyed
G_AddEvent( self, EV_ALIEN_BUILDABLE_EXPLOSION, DirToByte( dir ) );
self->timestamp = level.time;
- self->think = ASpawn_Melt;
- self->nextthink = level.time + 500; //wait .5 seconds before damaging others
+ self->think = AGeneric_CreepRecede;
+ self->nextthink = level.time + 500;
self->r.contents = 0; //stop collisions...
trap_LinkEntity( self ); //...requires a relink
@@ -628,74 +768,93 @@ void ASpawn_Blast( gentity_t *self )
/*
================
-ASpawn_Die
+AGeneric_Die
-Called when an alien spawn dies
+Called when an Alien buildable is killed and enters a brief dead state prior to
+exploding.
================
*/
-void ASpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod )
+void AGeneric_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod )
{
- buildHistory_t *new;
- new = G_Alloc( sizeof( buildHistory_t ) );
- new->ID = ( ++level.lastBuildID > 1000 ) ? ( level.lastBuildID = 1 ) : level.lastBuildID;
- new->ent = ( attacker && attacker->client ) ? attacker : NULL;
- if( new->ent )
- new->name[ 0 ] = 0;
- else
- Q_strncpyz( new->name, "<world>", 8 );
- new->buildable = self->s.modelindex;
- VectorCopy( self->s.pos.trBase, new->origin );
- VectorCopy( self->s.angles, new->angles );
- VectorCopy( self->s.origin2, new->origin2 );
- VectorCopy( self->s.angles2, new->angles2 );
- new->fate = ( attacker && attacker->client && attacker->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) ? BF_TEAMKILLED : BF_DESTROYED;
- new->next = NULL;
- G_LogBuild( new );
-
- G_BuildableDeathSound( self );
-
G_SetBuildableAnim( self, BANIM_DESTROY1, qtrue );
G_SetIdleBuildableAnim( self, BANIM_DESTROYED );
self->die = nullDieFunction;
- self->think = ASpawn_Blast;
+ self->killedBy = attacker - g_entities;
+ self->think = AGeneric_Blast;
+ self->s.eFlags &= ~EF_FIRING; //prevent any firing effects
+ self->powered = qfalse;
if( self->spawned )
self->nextthink = level.time + 5000;
else
self->nextthink = level.time; //blast immediately
- self->s.eFlags &= ~EF_FIRING; //prevent any firing effects
+ G_RemoveRangeMarkerFrom( self );
+ G_LogDestruction( self, attacker, mod );
+}
- if( attacker && attacker->client )
+/*
+================
+AGeneric_CreepCheck
+
+Tests for creep and kills the buildable if there is none
+================
+*/
+void AGeneric_CreepCheck( gentity_t *self )
+{
+ gentity_t *spawn;
+
+ spawn = self->parentNode;
+ if( !G_FindCreep( self ) )
{
- if( attacker->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- if( self->s.modelindex == BA_A_OVERMIND )
- G_AddCreditToClient( attacker->client, OVERMIND_VALUE, qtrue );
- else if( self->s.modelindex == BA_A_SPAWN )
- G_AddCreditToClient( attacker->client, ASPAWN_VALUE, qtrue );
- }
+ if( spawn )
+ G_Damage( self, NULL, g_entities + spawn->killedBy, NULL, NULL,
+ self->health, 0, MOD_NOCREEP );
else
- {
- G_TeamCommand( PTE_ALIENS,
- va( "print \"%s ^3DESTROYED^7 by teammate %s^7\n\"",
- BG_FindHumanNameForBuildable( self->s.modelindex ),
- attacker->client->pers.netname ) );
- G_LogOnlyPrintf("%s ^3DESTROYED^7 by teammate %s^7\n",
- BG_FindHumanNameForBuildable( self->s.modelindex ),
- attacker->client->pers.netname );
- }
- G_LogPrintf( "Decon: %i %i %i: %s^7 destroyed %s by %s\n",
- attacker->client->ps.clientNum, self->s.modelindex, mod,
- attacker->client->pers.netname,
- BG_FindNameForBuildable( self->s.modelindex ),
- modNames[ mod ] );
+ G_Damage( self, NULL, NULL, NULL, NULL, self->health, 0, MOD_NOCREEP );
+ return;
}
+ G_CreepSlow( self );
+}
+
+/*
+================
+AGeneric_Think
+
+A generic think function for Alien buildables
+================
+*/
+void AGeneric_Think( gentity_t *self )
+{
+ self->powered = G_Overmind( ) != NULL;
+ self->nextthink = level.time + BG_Buildable( self->s.modelindex )->nextthink;
+ AGeneric_CreepCheck( self );
}
/*
================
+AGeneric_Pain
+
+A generic pain function for Alien buildables
+================
+*/
+void AGeneric_Pain( gentity_t *self, gentity_t *attacker, int damage )
+{
+ if( self->health <= 0 )
+ return;
+
+ // Alien buildables only have the first pain animation defined
+ G_SetBuildableAnim( self, BANIM_PAIN1, qfalse );
+}
+
+
+
+
+//==================================================================================
+
+/*
+================
ASpawn_Think
think function for Alien Spawn
@@ -708,16 +867,21 @@ void ASpawn_Think( gentity_t *self )
if( self->spawned )
{
//only suicide if at rest
- if( self->s.groundEntityNum )
+ if( self->s.groundEntityNum != ENTITYNUM_NONE )
{
- if( ( ent = G_CheckSpawnPoint( self->s.number, self->s.origin,
+ if( ( ent = G_CheckSpawnPoint( self->s.number, self->r.currentOrigin,
self->s.origin2, BA_A_SPAWN, NULL ) ) != NULL )
{
// If the thing blocking the spawn is a buildable, kill it.
// If it's part of the map, kill self.
if( ent->s.eType == ET_BUILDABLE )
{
- G_Damage( ent, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
+ // don't queue the bp from this
+ if( ent->builtBy && ent->builtBy->slot >= 0 )
+ G_Damage( ent, NULL, g_entities + ent->builtBy->slot, NULL, NULL, 10000, 0, MOD_SUICIDE );
+ else
+ G_Damage( ent, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
+
G_SetBuildableAnim( self, BANIM_SPAWN1, qtrue );
}
else if( ent->s.number == ENTITYNUM_WORLD || ent->s.eType == ET_MOVER )
@@ -725,61 +889,16 @@ void ASpawn_Think( gentity_t *self )
G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
return;
}
- else if( g_antiSpawnBlock.integer && ent->client &&
- ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- //spawnblock protection
- if( self->spawnBlockTime && level.time - self->spawnBlockTime > 10000 )
- {
- //five seconds of countermeasures and we're still blocked
- //time for something more drastic
- G_Damage( ent, NULL, NULL, NULL, NULL, 10000, 0, MOD_TRIGGER_HURT );
- self->spawnBlockTime += 2000;
- //inappropriate MOD but prints an apt obituary
- }
- else if( self->spawnBlockTime && level.time - self->spawnBlockTime > 5000 )
- //five seconds of blocked by client and...
- {
- //random direction
- vec3_t velocity;
- velocity[0] = crandom() * g_antiSpawnBlock.integer;
- velocity[1] = crandom() * g_antiSpawnBlock.integer;
- velocity[2] = g_antiSpawnBlock.integer;
-
- VectorAdd( ent->client->ps.velocity, velocity, ent->client->ps.velocity );
- trap_SendServerCommand( ent-g_entities, "cp \"Don't spawn block!\"" );
- }
- else if( !self->spawnBlockTime )
- self->spawnBlockTime = level.time;
- }
- if( ent->s.eType == ET_CORPSE )
- G_FreeEntity( ent ); //quietly remove
+
+ if( ent->s.eType == ET_CORPSE )
+ G_FreeEntity( ent ); //quietly remove
}
- else
- self->spawnBlockTime = 0;
}
}
G_CreepSlow( self );
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
-}
-
-/*
-================
-ASpawn_Pain
-
-pain function for Alien Spawn
-================
-*/
-void ASpawn_Pain( gentity_t *self, gentity_t *attacker, int damage )
-{
- G_SetBuildableAnim( self, BANIM_PAIN1, qfalse );
-
- if ( self->s.modelindex == BA_A_OVERMIND && self->health > 0 &&
- attacker && attacker->client && attacker->client->pers.teamSelection == PTE_ALIENS )
- G_TeamCommand( PTE_ALIENS, va( "print \"Overmind ^3DAMAGED^7 by ^1TEAMMATE^7 %s^7\n\"",
- attacker->client->pers.netname ));
+ self->nextthink = level.time + BG_Buildable( self->s.modelindex )->nextthink;
}
@@ -805,39 +924,26 @@ Think function for Alien Overmind
*/
void AOvermind_Think( gentity_t *self )
{
- int entityList[ MAX_GENTITIES ];
- vec3_t range = { OVERMIND_ATTACK_RANGE, OVERMIND_ATTACK_RANGE, OVERMIND_ATTACK_RANGE };
- vec3_t mins, maxs;
- int i, num;
- gentity_t *enemy;
-
- VectorAdd( self->s.origin, range, maxs );
- VectorSubtract( self->s.origin, range, mins );
+ int i;
if( self->spawned && ( self->health > 0 ) )
{
//do some damage
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
+ if( G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage,
+ self->splashRadius, self, MOD_OVERMIND, TEAM_ALIENS ) )
{
- enemy = &g_entities[ entityList[ i ] ];
-
- if( enemy->flags & FL_NOTARGET )
- continue;
-
- if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- self->timestamp = level.time;
- G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage,
- self->splashRadius, self, MOD_OVERMIND, PTE_ALIENS );
- G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
- }
+ self->timestamp = level.time;
+ G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
}
// just in case an egg finishes building after we tell overmind to stfu
if( level.numAlienSpawns > 0 )
level.overmindMuted = qfalse;
+ // shut up during intermission
+ if( level.intermissiontime )
+ level.overmindMuted = qtrue;
+
//low on spawns
if( !level.overmindMuted && level.numAlienSpawns <= 0 &&
level.time > self->overmindSpawnsTimer )
@@ -885,14 +991,13 @@ void AOvermind_Think( gentity_t *self )
G_CreepSlow( self );
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
+ self->nextthink = level.time + BG_Buildable( self->s.modelindex )->nextthink;
}
-
//==================================================================================
@@ -903,12 +1008,15 @@ void AOvermind_Think( gentity_t *self )
================
ABarricade_Pain
-pain function for Alien Spawn
+Barricade pain animation depends on shrunk state
================
*/
void ABarricade_Pain( gentity_t *self, gentity_t *attacker, int damage )
{
- if( rand( ) % 2 )
+ if( self->health <= 0 )
+ return;
+
+ if( !self->shrunkTime )
G_SetBuildableAnim( self, BANIM_PAIN1, qfalse );
else
G_SetBuildableAnim( self, BANIM_PAIN2, qfalse );
@@ -916,223 +1024,134 @@ void ABarricade_Pain( gentity_t *self, gentity_t *attacker, int damage )
/*
================
-ABarricade_Blast
+ABarricade_Shrink
-Called when an alien spawn dies
+Set shrink state for a barricade. When unshrinking, checks to make sure there
+is enough room.
================
*/
-void ABarricade_Blast( gentity_t *self )
+void ABarricade_Shrink( gentity_t *self, qboolean shrink )
{
- vec3_t dir;
-
- VectorCopy( self->s.origin2, dir );
+ if ( !self->spawned || self->health <= 0 )
+ shrink = qtrue;
+ if ( shrink && self->shrunkTime )
+ {
+ int anim;
- //do a bit of radius damage
- G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage,
- self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS );
+ // We need to make sure that the animation has been set to shrunk mode
+ // because we start out shrunk but with the construct animation when built
+ self->shrunkTime = level.time;
+ anim = self->s.torsoAnim & ~( ANIM_FORCEBIT | ANIM_TOGGLEBIT );
+ if ( self->spawned && self->health > 0 && anim != BANIM_DESTROYED )
+ {
+ G_SetIdleBuildableAnim( self, BANIM_DESTROYED );
+ G_SetBuildableAnim( self, BANIM_ATTACK1, qtrue );
+ }
+ return;
+ }
- //pretty events and item cleanup
- self->s.eFlags |= EF_NODRAW; //don't draw the model once its destroyed
- G_AddEvent( self, EV_ALIEN_BUILDABLE_EXPLOSION, DirToByte( dir ) );
- self->timestamp = level.time;
- self->think = A_CreepRecede;
- self->nextthink = level.time + 500; //wait .5 seconds before damaging others
+ if ( !shrink && ( !self->shrunkTime ||
+ level.time < self->shrunkTime + BARRICADE_SHRINKTIMEOUT ) )
+ return;
- self->r.contents = 0; //stop collisions...
- trap_LinkEntity( self ); //...requires a relink
-}
+ BG_BuildableBoundingBox( BA_A_BARRICADE, self->r.mins, self->r.maxs );
-/*
-================
-ABarricade_Die
+ if ( shrink )
+ {
+ self->r.maxs[ 2 ] = (int)( self->r.maxs[ 2 ] * BARRICADE_SHRINKPROP );
+ self->shrunkTime = level.time;
-Called when an alien spawn dies
-================
-*/
-void ABarricade_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod )
-{
- buildHistory_t *new;
- new = G_Alloc( sizeof( buildHistory_t ) );
- new->ID = ( ++level.lastBuildID > 1000 ) ? ( level.lastBuildID = 1 ) : level.lastBuildID;
- new->ent = ( attacker && attacker->client ) ? attacker : NULL;
- if( new->ent )
- new->name[ 0 ] = 0;
+ // shrink animation, the destroy animation is used
+ if ( self->spawned && self->health > 0 )
+ {
+ G_SetBuildableAnim( self, BANIM_ATTACK1, qtrue );
+ G_SetIdleBuildableAnim( self, BANIM_DESTROYED );
+ }
+ }
else
- Q_strncpyz( new->name, "<world>", 8 );
- new->buildable = self->s.modelindex;
- VectorCopy( self->s.pos.trBase, new->origin );
- VectorCopy( self->s.angles, new->angles );
- VectorCopy( self->s.origin2, new->origin2 );
- VectorCopy( self->s.angles2, new->angles2 );
- new->fate = ( attacker && attacker->client && attacker->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) ? BF_TEAMKILLED : BF_DESTROYED;
- new->next = NULL;
- G_LogBuild( new );
-
- G_BuildableDeathSound( self );
-
- G_SetBuildableAnim( self, BANIM_DESTROY1, qtrue );
- G_SetIdleBuildableAnim( self, BANIM_DESTROYED );
-
- self->die = nullDieFunction;
- self->think = ABarricade_Blast;
- self->s.eFlags &= ~EF_FIRING; //prevent any firing effects
+ {
+ trace_t tr;
+ int anim;
- if( self->spawned )
- self->nextthink = level.time + 5000;
- else
- self->nextthink = level.time; //blast immediately
+ trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
+ self->r.currentOrigin, self->s.number, MASK_PLAYERSOLID );
+ if ( tr.startsolid || tr.fraction < 1.0f )
+ {
+ self->r.maxs[ 2 ] = (int)( self->r.maxs[ 2 ] * BARRICADE_SHRINKPROP );
+ return;
+ }
+ self->shrunkTime = 0;
- if( attacker && attacker->client )
- {
- if( attacker->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ // unshrink animation, IDLE2 has been hijacked for this
+ anim = self->s.legsAnim & ~( ANIM_FORCEBIT | ANIM_TOGGLEBIT );
+ if ( self->spawned && self->health > 0 &&
+ anim != BANIM_CONSTRUCT1 && anim != BANIM_CONSTRUCT2 )
{
- G_TeamCommand( PTE_ALIENS,
- va( "print \"%s ^3DESTROYED^7 by teammate %s^7\n\"",
- BG_FindHumanNameForBuildable( self->s.modelindex ),
- attacker->client->pers.netname ) );
- G_LogOnlyPrintf("%s ^3DESTROYED^7 by teammate %s^7\n",
- BG_FindHumanNameForBuildable( self->s.modelindex ),
- attacker->client->pers.netname );
+ G_SetIdleBuildableAnim( self, BG_Buildable( BA_A_BARRICADE )->idleAnim );
+ G_SetBuildableAnim( self, BANIM_ATTACK2, qtrue );
}
- G_LogPrintf( "Decon: %i %i %i: %s^7 destroyed %s by %s\n",
- attacker->client->ps.clientNum, self->s.modelindex, mod,
- attacker->client->pers.netname,
- BG_FindNameForBuildable( self->s.modelindex ),
- modNames[ mod ] );
}
+
+ // a change in size requires a relink
+ if ( self->spawned )
+ trap_LinkEntity( self );
}
/*
================
-ABarricade_Think
+ABarricade_Die
-Think function for Alien Barricade
+Called when an alien barricade dies
================
*/
-void ABarricade_Think( gentity_t *self )
+void ABarricade_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod )
{
-
- self->powered = G_IsOvermindBuilt( );
-
- //if there is no creep nearby die
- if( !G_FindCreep( self ) )
- {
- G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
- return;
- }
-
- G_CreepSlow( self );
-
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
+ AGeneric_Die( self, inflictor, attacker, damage, mod );
+ ABarricade_Shrink( self, qtrue );
}
-
-
-
-//==================================================================================
-
-
-
-
-void AAcidTube_Think( gentity_t *self );
-
/*
================
-AAcidTube_Damage
+ABarricade_Think
-Damage function for Alien Acid Tube
+Think function for Alien Barricade
================
*/
-void AAcidTube_Damage( gentity_t *self )
+void ABarricade_Think( gentity_t *self )
{
- if( self->spawned )
- {
- if( !( self->s.eFlags & EF_FIRING ) )
- {
- self->s.eFlags |= EF_FIRING;
- G_AddEvent( self, EV_ALIEN_ACIDTUBE, DirToByte( self->s.origin2 ) );
- }
-
- if( ( self->timestamp + ACIDTUBE_REPEAT ) > level.time )
- self->think = AAcidTube_Damage;
- else
- {
- self->think = AAcidTube_Think;
- self->s.eFlags &= ~EF_FIRING;
- }
-
- //do some damage
- G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage,
- self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS );
- }
-
- G_CreepSlow( self );
+ AGeneric_Think( self );
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
+ // Shrink if unpowered
+ ABarricade_Shrink( self, !self->powered );
}
/*
================
-AAcidTube_Think
+ABarricade_Touch
-Think function for Alien Acid Tube
+Barricades shrink when they are come into contact with an Alien that can
+pass through
================
*/
-void AAcidTube_Think( gentity_t *self )
-{
- int entityList[ MAX_GENTITIES ];
- vec3_t range = { ACIDTUBE_RANGE, ACIDTUBE_RANGE, ACIDTUBE_RANGE };
- vec3_t mins, maxs;
- int i, num;
- gentity_t *enemy;
-
- self->powered = G_IsOvermindBuilt( );
- VectorAdd( self->s.origin, range, maxs );
- VectorSubtract( self->s.origin, range, mins );
+void ABarricade_Touch( gentity_t *self, gentity_t *other, trace_t *trace )
+{
+ gclient_t *client = other->client;
+ int client_z, min_z;
- //if there is no creep nearby die
- if( !G_FindCreep( self ) )
- {
- G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
+ if( !client || client->pers.teamSelection != TEAM_ALIENS )
return;
- }
-
- if( self->spawned && G_FindOvermind( self ) )
- {
- //do some damage
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
- {
- enemy = &g_entities[ entityList[ i ] ];
-
- if( enemy->flags & FL_NOTARGET )
- continue;
-
- if( !G_Visible( self, enemy ) )
- continue;
-
- if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- if( level.paused || enemy->client->pers.paused )
- continue;
- self->timestamp = level.time;
- self->think = AAcidTube_Damage;
- self->nextthink = level.time + 100;
- G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
- return;
- }
- }
- }
-
- G_CreepSlow( self );
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
+ // Client must be high enough to pass over. Note that STEPSIZE (18) is
+ // hardcoded here because we don't include bg_local.h!
+ client_z = other->r.currentOrigin[ 2 ] + other->r.mins[ 2 ];
+ min_z = self->r.currentOrigin[ 2 ] - 18 +
+ (int)( self->r.maxs[ 2 ] * BARRICADE_SHRINKPROP );
+ if( client_z < min_z )
+ return;
+ ABarricade_Shrink( self, qtrue );
}
-
-
-
//==================================================================================
@@ -1140,40 +1159,27 @@ void AAcidTube_Think( gentity_t *self )
/*
================
-AHive_Think
+AAcidTube_Think
-Think function for Alien Hive
+Think function for Alien Acid Tube
================
*/
-void AHive_Think( gentity_t *self )
+void AAcidTube_Think( gentity_t *self )
{
int entityList[ MAX_GENTITIES ];
vec3_t range = { ACIDTUBE_RANGE, ACIDTUBE_RANGE, ACIDTUBE_RANGE };
vec3_t mins, maxs;
int i, num;
gentity_t *enemy;
- vec3_t dirToTarget;
-
- self->powered = G_IsOvermindBuilt( );
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
+ AGeneric_Think( self );
- VectorAdd( self->s.origin, range, maxs );
- VectorSubtract( self->s.origin, range, mins );
+ VectorAdd( self->r.currentOrigin, range, maxs );
+ VectorSubtract( self->r.currentOrigin, range, mins );
- //if there is no creep nearby die
- if( !G_FindCreep( self ) )
+ // attack nearby humans
+ if( self->spawned && self->health > 0 && self->powered )
{
- G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
- return;
- }
-
- if( self->timestamp < level.time )
- self->active = qfalse; //nothing has returned in HIVE_REPEAT seconds, forget about it
-
- if( self->spawned && !self->active && G_FindOvermind( self ) )
- {
- //do some damage
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for( i = 0; i < num; i++ )
{
@@ -1182,33 +1188,26 @@ void AHive_Think( gentity_t *self )
if( enemy->flags & FL_NOTARGET )
continue;
- if( enemy->health <= 0 )
- continue;
-
- if( !G_Visible( self, enemy ) )
+ if( !G_Visible( self, enemy, CONTENTS_SOLID ) )
continue;
- if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( enemy->client && enemy->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
- if( level.paused || enemy->client->pers.paused )
- continue;
- self->active = qtrue;
- self->target_ent = enemy;
- self->timestamp = level.time + HIVE_REPEAT;
-
- VectorSubtract( enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget );
- VectorNormalize( dirToTarget );
- vectoangles( dirToTarget, self->turretAim );
-
- //fire at target
- FireWeapon( self );
- G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
+ // start the attack animation
+ if( level.time >= self->timestamp + ACIDTUBE_REPEAT_ANIM )
+ {
+ self->timestamp = level.time;
+ G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
+ G_AddEvent( self, EV_ALIEN_ACIDTUBE, DirToByte( self->s.origin2 ) );
+ }
+
+ G_SelectiveRadiusDamage( self->s.pos.trBase, self, ACIDTUBE_DAMAGE,
+ ACIDTUBE_RANGE, self, MOD_ATUBE, TEAM_ALIENS );
+ self->nextthink = level.time + ACIDTUBE_REPEAT;
return;
}
}
}
-
- G_CreepSlow( self );
}
@@ -1216,284 +1215,111 @@ void AHive_Think( gentity_t *self )
//==================================================================================
-
-
-
-#define HOVEL_TRACE_DEPTH 128.0f
-
/*
================
-AHovel_Blocked
+AHive_CheckTarget
-Is this hovel entrance blocked?
+Returns true and fires the hive missile if the target is valid
================
*/
-qboolean AHovel_Blocked( gentity_t *hovel, gentity_t *player, qboolean provideExit )
+static qboolean AHive_CheckTarget( gentity_t *self, gentity_t *enemy )
{
- vec3_t forward, normal, origin, start, end, angles, hovelMaxs;
- vec3_t mins, maxs;
- float displacement;
- trace_t tr;
-
- BG_FindBBoxForBuildable( BA_A_HOVEL, NULL, hovelMaxs );
- BG_FindBBoxForClass( player->client->ps.stats[ STAT_PCLASS ],
- mins, maxs, NULL, NULL, NULL );
-
- VectorCopy( hovel->s.origin2, normal );
- AngleVectors( hovel->s.angles, forward, NULL, NULL );
- VectorInverse( forward );
-
- displacement = VectorMaxComponent( maxs ) +
- VectorMaxComponent( hovelMaxs ) + 1.0f;
-
- VectorMA( hovel->s.origin, displacement, forward, origin );
-
- VectorCopy( hovel->s.origin, start );
- VectorCopy( origin, end );
-
- // see if there's something between the hovel and its exit
- // (eg built right up against a wall)
- trap_Trace( &tr, start, NULL, NULL, end, player->s.number, MASK_PLAYERSOLID );
- if( tr.fraction < 1.0f )
- return qtrue;
-
- vectoangles( forward, angles );
-
- VectorMA( origin, HOVEL_TRACE_DEPTH, normal, start );
+ trace_t trace;
+ vec3_t tip_origin, dirToTarget;
- //compute a place up in the air to start the real trace
- trap_Trace( &tr, origin, mins, maxs, start, player->s.number, MASK_PLAYERSOLID );
-
- VectorMA( origin, ( HOVEL_TRACE_DEPTH * tr.fraction ) - 1.0f, normal, start );
- VectorMA( origin, -HOVEL_TRACE_DEPTH, normal, end );
-
- trap_Trace( &tr, start, mins, maxs, end, player->s.number, MASK_PLAYERSOLID );
-
- VectorCopy( tr.endpos, origin );
-
- trap_Trace( &tr, origin, mins, maxs, origin, player->s.number, MASK_PLAYERSOLID );
+ // Check if this is a valid target
+ if( enemy->health <= 0 || !enemy->client ||
+ enemy->client->ps.stats[ STAT_TEAM ] != TEAM_HUMANS )
+ return qfalse;
- if( provideExit )
- {
- G_SetOrigin( player, origin );
- VectorCopy( origin, player->client->ps.origin );
- // nudge
- VectorMA( normal, 200.0f, forward, player->client->ps.velocity );
- G_SetClientViewAngle( player, angles );
- }
+ if( enemy->flags & FL_NOTARGET )
+ return qfalse;
- if( tr.fraction < 1.0f )
- return qtrue;
- else
+ // Check if the tip of the hive can see the target
+ VectorMA( self->s.pos.trBase, self->r.maxs[ 2 ], self->s.origin2,
+ tip_origin );
+ if( Distance( tip_origin, enemy->r.currentOrigin ) > HIVE_SENSE_RANGE )
return qfalse;
-}
-/*
-================
-APropHovel_Blocked
+ trap_Trace( &trace, tip_origin, NULL, NULL, enemy->s.pos.trBase,
+ self->s.number, MASK_SHOT );
+ if( trace.fraction < 1.0f && trace.entityNum != enemy->s.number )
+ return qfalse;
-Wrapper to test a hovel placement for validity
-================
-*/
-static qboolean APropHovel_Blocked( vec3_t origin, vec3_t angles, vec3_t normal,
- gentity_t *player )
-{
- gentity_t hovel;
+ self->active = qtrue;
+ self->target_ent = enemy;
+ self->timestamp = level.time + HIVE_REPEAT;
- VectorCopy( origin, hovel.s.origin );
- VectorCopy( angles, hovel.s.angles );
- VectorCopy( normal, hovel.s.origin2 );
+ VectorSubtract( enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget );
+ VectorNormalize( dirToTarget );
+ vectoangles( dirToTarget, self->turretAim );
- return AHovel_Blocked( &hovel, player, qfalse );
+ // Fire at target
+ FireWeapon( self );
+ G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
+ return qtrue;
}
/*
================
-AHovel_Use
+AHive_Think
-Called when an alien uses a hovel
+Think function for Alien Hive
================
*/
-void AHovel_Use( gentity_t *self, gentity_t *other, gentity_t *activator )
+void AHive_Think( gentity_t *self )
{
- vec3_t hovelOrigin, hovelAngles, inverseNormal;
+ int start;
- if( self->spawned && G_FindOvermind( self ) )
- {
- if( self->active )
- {
- //this hovel is in use
- G_TriggerMenu( activator->client->ps.clientNum, MN_A_HOVEL_OCCUPIED );
- }
- else if( ( ( activator->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0 ) ||
- ( activator->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0_UPG ) ) &&
- activator->health > 0 && self->health > 0 )
- {
- if( AHovel_Blocked( self, activator, qfalse ) )
- {
- //you can get in, but you can't get out
- G_TriggerMenu( activator->client->ps.clientNum, MN_A_HOVEL_BLOCKED );
- return;
- }
+ AGeneric_Think( self );
- self->active = qtrue;
- G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
-
- //prevent lerping
- activator->client->ps.eFlags ^= EF_TELEPORT_BIT;
- activator->client->ps.eFlags |= EF_NODRAW;
- G_UnlaggedClear( activator );
+ // Hive missile hasn't returned in HIVE_REPEAT seconds, forget about it
+ if( self->timestamp < level.time )
+ self->active = qfalse;
- activator->client->ps.stats[ STAT_STATE ] |= SS_HOVELING;
- activator->client->hovel = self;
- self->builder = activator;
-
- // Cancel pending suicides
- activator->suicideTime = 0;
+ // Find a target to attack
+ if( self->spawned && !self->active && self->powered )
+ {
+ int i, num, entityList[ MAX_GENTITIES ];
+ vec3_t mins, maxs,
+ range = { HIVE_SENSE_RANGE, HIVE_SENSE_RANGE, HIVE_SENSE_RANGE };
- VectorCopy( self->s.pos.trBase, hovelOrigin );
- VectorMA( hovelOrigin, 128.0f, self->s.origin2, hovelOrigin );
+ VectorAdd( self->r.currentOrigin, range, maxs );
+ VectorSubtract( self->r.currentOrigin, range, mins );
- VectorCopy( self->s.origin2, inverseNormal );
- VectorInverse( inverseNormal );
- vectoangles( inverseNormal, hovelAngles );
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- VectorCopy( activator->s.pos.trBase, activator->client->hovelOrigin );
+ if( num == 0 )
+ return;
- G_SetOrigin( activator, hovelOrigin );
- VectorCopy( hovelOrigin, activator->client->ps.origin );
- G_SetClientViewAngle( activator, hovelAngles );
+ start = rand( ) / ( RAND_MAX / num + 1 );
+ for( i = start; i < num + start; i++ )
+ {
+ if( AHive_CheckTarget( self, g_entities + entityList[ i % num ] ) )
+ return;
}
}
}
-
/*
================
-AHovel_Think
+AHive_Pain
-Think for alien hovel
+pain function for Alien Hive
================
*/
-void AHovel_Think( gentity_t *self )
+void AHive_Pain( gentity_t *self, gentity_t *attacker, int damage )
{
- self->powered = G_IsOvermindBuilt( );
- if( self->spawned )
- {
- if( self->active )
- G_SetIdleBuildableAnim( self, BANIM_IDLE2 );
- else
- G_SetIdleBuildableAnim( self, BANIM_IDLE1 );
- }
-
- G_CreepSlow( self );
-
- self->nextthink = level.time + 200;
-}
-
-/*
-================
-AHovel_Die
-
-Die for alien hovel
-================
-*/
-void AHovel_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod )
-{
- vec3_t dir;
-
- buildHistory_t *new;
- new = G_Alloc( sizeof( buildHistory_t ) );
- new->ID = ( ++level.lastBuildID > 1000 ) ? ( level.lastBuildID = 1 ) : level.lastBuildID;
- new->ent = ( attacker && attacker->client ) ? attacker : NULL;
- if( new->ent )
- new->name[ 0 ] = 0;
- else
- Q_strncpyz( new->name, "<world>", 8 );
- new->buildable = self->s.modelindex;
- VectorCopy( self->s.pos.trBase, new->origin );
- VectorCopy( self->s.angles, new->angles );
- VectorCopy( self->s.origin2, new->origin2 );
- VectorCopy( self->s.angles2, new->angles2 );
- new->fate = ( attacker && attacker->client && attacker->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) ? BF_TEAMKILLED : BF_DESTROYED;
- new->next = NULL;
- G_LogBuild( new );
-
- G_BuildableDeathSound( self );
-
- VectorCopy( self->s.origin2, dir );
-
- //do a bit of radius damage
- G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage,
- self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS );
-
- //pretty events and item cleanup
- self->s.eFlags |= EF_NODRAW; //don't draw the model once its destroyed
- G_AddEvent( self, EV_ALIEN_BUILDABLE_EXPLOSION, DirToByte( dir ) );
- self->s.eFlags &= ~EF_FIRING; //prevent any firing effects
- self->timestamp = level.time;
- self->think = ASpawn_Melt;
- self->nextthink = level.time + 500; //wait .5 seconds before damaging others
- self->die = nullDieFunction;
-
- //if the hovel is occupied free the occupant
- if( self->active )
- {
- gentity_t *builder = self->builder;
- vec3_t newOrigin;
- vec3_t newAngles;
-
- VectorCopy( self->s.angles, newAngles );
- newAngles[ ROLL ] = 0;
-
- VectorCopy( self->s.origin, newOrigin );
- VectorMA( newOrigin, 1.0f, self->s.origin2, newOrigin );
-
- //prevent lerping
- builder->client->ps.eFlags ^= EF_TELEPORT_BIT;
- builder->client->ps.eFlags &= ~EF_NODRAW;
- G_UnlaggedClear( builder );
-
- G_SetOrigin( builder, newOrigin );
- VectorCopy( newOrigin, builder->client->ps.origin );
- G_SetClientViewAngle( builder, newAngles );
+ if( self->spawned && self->powered && !self->active )
+ AHive_CheckTarget( self, attacker );
- //client leaves hovel
- builder->client->ps.stats[ STAT_STATE ] &= ~SS_HOVELING;
- }
-
- self->r.contents = 0; //stop collisions...
- trap_LinkEntity( self ); //...requires a relink
-
- if( attacker && attacker->client )
- {
- if( attacker->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- G_TeamCommand( PTE_ALIENS,
- va( "print \"%s ^3DESTROYED^7 by teammate %s^7\n\"",
- BG_FindHumanNameForBuildable( self->s.modelindex ),
- attacker->client->pers.netname ) );
- G_LogOnlyPrintf("%s ^3DESTROYED^7 by teammate %s^7\n",
- BG_FindHumanNameForBuildable( self->s.modelindex ),
- attacker->client->pers.netname );
- }
- G_LogPrintf( "Decon: %i %i %i: %s^7 destroyed %s by %s\n",
- attacker->client->ps.clientNum, self->s.modelindex, mod,
- attacker->client->pers.netname,
- BG_FindNameForBuildable( self->s.modelindex ),
- modNames[ mod ] );
- }
+ G_SetBuildableAnim( self, BANIM_PAIN1, qfalse );
}
-
-
-
//==================================================================================
-
-
/*
================
ABooster_Touch
@@ -1505,20 +1331,20 @@ void ABooster_Touch( gentity_t *self, gentity_t *other, trace_t *trace )
{
gclient_t *client = other->client;
- if( !self->spawned || self->health <= 0 )
- return;
-
- if( !G_FindOvermind( self ) )
+ if( !self->spawned || !self->powered || self->health <= 0 )
return;
if( !client )
return;
- if( client && client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
return;
+ if( other->flags & FL_NOTARGET )
+ return; // notarget cancels even beneficial effects?
+
client->ps.stats[ STAT_STATE ] |= SS_BOOSTED;
- client->lastBoostedTime = level.time;
+ client->boostedTime = level.time;
}
@@ -1540,11 +1366,11 @@ void ATrapper_FireOnEnemy( gentity_t *self, int firespeed, float range )
gentity_t *enemy = self->enemy;
vec3_t dirToTarget;
vec3_t halfAcceleration, thirdJerk;
- float distanceToTarget = BG_FindRangeForBuildable( self->s.modelindex );
+ float distanceToTarget = BG_Buildable( self->s.modelindex )->turretRange;
int lowMsec = 0;
int highMsec = (int)( (
( ( distanceToTarget * LOCKBLOB_SPEED ) +
- ( distanceToTarget * BG_FindSpeedForClass( enemy->client->ps.stats[ STAT_PCLASS ] ) ) ) /
+ ( distanceToTarget * BG_Class( enemy->client->ps.stats[ STAT_CLASS ] )->speed ) ) /
( LOCKBLOB_SPEED * LOCKBLOB_SPEED ) ) * 1000.0f );
VectorScale( enemy->acceleration, 1.0f / 2.0f, halfAcceleration );
@@ -1603,9 +1429,9 @@ qboolean ATrapper_CheckTarget( gentity_t *self, gentity_t *target, int range )
return qfalse;
if( target->flags & FL_NOTARGET ) // is the target cheating?
return qfalse;
- if( target->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) // one of us?
+ if( target->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) // one of us?
return qfalse;
- if( target->client->sess.sessionTeam == TEAM_SPECTATOR ) // is the target alive?
+ if( target->client->sess.spectatorState != SPECTATOR_NOT ) // is the target alive?
return qfalse;
if( target->health <= 0 ) // is the target still alive?
return qfalse;
@@ -1638,10 +1464,14 @@ Used by ATrapper_Think to locate enemy gentities
void ATrapper_FindEnemy( gentity_t *ent, int range )
{
gentity_t *target;
+ int i;
+ int start;
- //iterate through entities
- for( target = g_entities; target < &g_entities[ level.num_entities ]; target++ )
+ // iterate through entities
+ start = rand( ) / ( RAND_MAX / level.num_entities + 1 );
+ for( i = start; i < level.num_entities + start; i++ )
{
+ target = g_entities + ( i % level.num_entities );
//if target is not valid keep searching
if( !ATrapper_CheckTarget( ent, target, range ) )
continue;
@@ -1664,23 +1494,12 @@ think function for Alien Defense
*/
void ATrapper_Think( gentity_t *self )
{
- int range = BG_FindRangeForBuildable( self->s.modelindex );
- int firespeed = BG_FindFireSpeedForBuildable( self->s.modelindex );
+ int range = BG_Buildable( self->s.modelindex )->turretRange;
+ int firespeed = BG_Buildable( self->s.modelindex )->turretFireSpeed;
- self->powered = G_IsOvermindBuilt( );
+ AGeneric_Think( self );
- G_CreepSlow( self );
-
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
-
- //if there is no creep nearby die
- if( !G_FindCreep( self ) )
- {
- G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
- return;
- }
-
- if( self->spawned && G_FindOvermind( self ) )
+ if( self->spawned && self->powered )
{
//if the current target is not valid find a new one
if( !ATrapper_CheckTarget( self, self->enemy, range ) )
@@ -1698,48 +1517,304 @@ void ATrapper_Think( gentity_t *self )
+
//==================================================================================
+
/*
================
-HRepeater_Think
+G_SuicideIfNoPower
-Think for human power repeater
+Destroy human structures that have been unpowered too long
================
*/
-void HRepeater_Think( gentity_t *self )
+static qboolean G_SuicideIfNoPower( gentity_t *self )
+{
+ if( self->buildableTeam != TEAM_HUMANS )
+ return qfalse;
+
+ if( !self->powered )
+ {
+ // if the power hasn't reached this buildable for some time, then destroy the buildable
+ if( self->count == 0 )
+ self->count = level.time;
+ else if( ( level.time - self->count ) >= HUMAN_BUILDABLE_INACTIVE_TIME )
+ {
+ if( self->parentNode )
+ G_Damage( self, NULL, g_entities + self->parentNode->killedBy,
+ NULL, NULL, self->health, 0, MOD_NOCREEP );
+ else
+ G_Damage( self, NULL, NULL, NULL, NULL, self->health, 0, MOD_NOCREEP );
+ return qtrue;
+ }
+ }
+ else
+ self->count = 0;
+
+ return qfalse;
+}
+
+/*
+================
+G_IdlePowerState
+
+Set buildable idle animation to match power state
+================
+*/
+static void G_IdlePowerState( gentity_t *self )
+{
+ if( self->powered )
+ {
+ if( self->s.torsoAnim == BANIM_IDLE3 )
+ G_SetIdleBuildableAnim( self, BG_Buildable( self->s.modelindex )->idleAnim );
+ }
+ else
+ {
+ if( self->s.torsoAnim != BANIM_IDLE3 )
+ G_SetIdleBuildableAnim( self, BANIM_IDLE3 );
+ }
+}
+
+
+
+
+//==================================================================================
+
+
+
+
+/*
+================
+HSpawn_Disappear
+
+Called when a human spawn is destroyed before it is spawned
+think function
+================
+*/
+void HSpawn_Disappear( gentity_t *self )
+{
+ self->timestamp = level.time;
+ G_QueueBuildPoints( self );
+ G_RewardAttackers( self );
+
+ G_FreeEntity( self );
+}
+
+
+/*
+================
+HSpawn_blast
+
+Called when a human spawn explodes
+think function
+================
+*/
+void HSpawn_Blast( gentity_t *self )
+{
+ vec3_t dir;
+
+ // we don't have a valid direction, so just point straight up
+ dir[ 0 ] = dir[ 1 ] = 0;
+ dir[ 2 ] = 1;
+
+ self->timestamp = level.time;
+
+ //do some radius damage
+ G_RadiusDamage( self->s.pos.trBase, g_entities + self->killedBy, self->splashDamage,
+ self->splashRadius, self, self->splashMethodOfDeath );
+
+ // begin freeing build points
+ G_QueueBuildPoints( self );
+ G_RewardAttackers( self );
+ // turn into an explosion
+ self->s.eType = ET_EVENTS + EV_HUMAN_BUILDABLE_EXPLOSION;
+ self->freeAfterEvent = qtrue;
+ G_AddEvent( self, EV_HUMAN_BUILDABLE_EXPLOSION, DirToByte( dir ) );
+}
+
+
+/*
+================
+HSpawn_die
+
+Called when a human spawn dies
+================
+*/
+void HSpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod )
+{
+ G_SetBuildableAnim( self, BANIM_DESTROY1, qtrue );
+ G_SetIdleBuildableAnim( self, BANIM_DESTROYED );
+
+ self->die = nullDieFunction;
+ self->killedBy = attacker - g_entities;
+ self->powered = qfalse; //free up power
+ self->s.eFlags &= ~EF_FIRING; //prevent any firing effects
+
+ if( self->spawned )
+ {
+ self->think = HSpawn_Blast;
+ self->nextthink = level.time + HUMAN_DETONATION_DELAY;
+ }
+ else
+ {
+ self->think = HSpawn_Disappear;
+ self->nextthink = level.time; //blast immediately
+ }
+
+ G_RemoveRangeMarkerFrom( self );
+ G_LogDestruction( self, attacker, mod );
+}
+
+/*
+================
+HSpawn_Think
+
+Think for human spawn
+================
+*/
+void HSpawn_Think( gentity_t *self )
{
- int i;
- qboolean reactor = qfalse;
gentity_t *ent;
+ // set parentNode
+ self->powered = G_FindPower( self, qfalse );
+
+ if( G_SuicideIfNoPower( self ) )
+ return;
+
if( self->spawned )
{
- //iterate through entities
- for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ //only suicide if at rest
+ if( self->s.groundEntityNum != ENTITYNUM_NONE )
{
- if( ent->s.eType != ET_BUILDABLE )
- continue;
+ if( ( ent = G_CheckSpawnPoint( self->s.number, self->r.currentOrigin,
+ self->s.origin2, BA_H_SPAWN, NULL ) ) != NULL )
+ {
+ // If the thing blocking the spawn is a buildable, kill it.
+ // If it's part of the map, kill self.
+ if( ent->s.eType == ET_BUILDABLE )
+ {
+ G_Damage( ent, NULL, NULL, NULL, NULL, self->health, 0, MOD_SUICIDE );
+ G_SetBuildableAnim( self, BANIM_SPAWN1, qtrue );
+ }
+ else if( ent->s.number == ENTITYNUM_WORLD || ent->s.eType == ET_MOVER )
+ {
+ G_Damage( self, NULL, NULL, NULL, NULL, self->health, 0, MOD_SUICIDE );
+ return;
+ }
- if( ent->s.modelindex == BA_H_REACTOR && ent->spawned )
- reactor = qtrue;
+ if( ent->s.eType == ET_CORPSE )
+ G_FreeEntity( ent ); //quietly remove
+ }
}
}
- if( G_NumberOfDependants( self ) == 0 )
+ self->nextthink = level.time + BG_Buildable( self->s.modelindex )->nextthink;
+}
+
+
+
+
+//==================================================================================
+
+
+
+
+/*
+================
+HRepeater_Die
+
+Called when a repeater dies
+================
+*/
+static void HRepeater_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod )
+{
+ G_SetBuildableAnim( self, BANIM_DESTROY1, qtrue );
+ G_SetIdleBuildableAnim( self, BANIM_DESTROYED );
+
+ self->die = nullDieFunction;
+ self->killedBy = attacker - g_entities;
+ self->powered = qfalse; //free up power
+ self->s.eFlags &= ~EF_FIRING; //prevent any firing effects
+
+ if( self->spawned )
{
- //if no dependants for x seconds then disappear
- if( self->count < 0 )
- self->count = level.time;
- else if( self->count > 0 && ( ( level.time - self->count ) > REPEATER_INACTIVE_TIME ) )
- G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
+ self->think = HSpawn_Blast;
+ self->nextthink = level.time + HUMAN_DETONATION_DELAY;
}
else
- self->count = -1;
+ {
+ self->think = HSpawn_Disappear;
+ self->nextthink = level.time; //blast immediately
+ }
+
+ G_RemoveRangeMarkerFrom( self );
+ G_LogDestruction( self, attacker, mod );
+
+ if( self->usesBuildPointZone )
+ {
+ buildPointZone_t *zone = &level.buildPointZones[self->buildPointZone];
+
+ zone->active = qfalse;
+ self->usesBuildPointZone = qfalse;
+ }
+}
+
+/*
+================
+HRepeater_Think
+
+Think for human power repeater
+================
+*/
+void HRepeater_Think( gentity_t *self )
+{
+ int i;
+ gentity_t *powerEnt;
+ buildPointZone_t *zone;
+
+ self->powered = G_FindPower( self, qfalse );
+
+ powerEnt = G_InPowerZone( self );
+ if( powerEnt != NULL )
+ {
+ // If the repeater is inside of another power zone then suicide
+ // Attribute death to whoever built the reactor if that's a human,
+ // which will ensure that it does not queue the BP
+ if( powerEnt->builtBy && powerEnt->builtBy->slot >= 0 )
+ G_Damage( self, NULL, g_entities + powerEnt->builtBy->slot, NULL, NULL, self->health, 0, MOD_SUICIDE );
+ else
+ G_Damage( self, NULL, NULL, NULL, NULL, self->health, 0, MOD_SUICIDE );
+ return;
+ }
+
+ G_IdlePowerState( self );
- self->powered = reactor;
+ // Initialise the zone once the repeater has spawned
+ if( self->spawned && ( !self->usesBuildPointZone || !level.buildPointZones[ self->buildPointZone ].active ) )
+ {
+ // See if a free zone exists
+ for( i = 0; i < g_humanRepeaterMaxZones.integer; i++ )
+ {
+ zone = &level.buildPointZones[ i ];
+
+ if( !zone->active )
+ {
+ // Initialise the BP queue with no BP queued
+ zone->queuedBuildPoints = 0;
+ zone->totalBuildPoints = g_humanRepeaterBuildPoints.integer;
+ zone->nextQueueTime = level.time;
+ zone->active = qtrue;
+
+ self->buildPointZone = zone - level.buildPointZones;
+ self->usesBuildPointZone = qtrue;
+
+ break;
+ }
+ }
+ }
self->nextthink = level.time + POWER_REFRESH_TIME;
}
@@ -1753,19 +1828,13 @@ Use for human power repeater
*/
void HRepeater_Use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
- if( self->health <= 0 )
+ if( self->health <= 0 || !self->spawned )
return;
- if( !self->spawned )
- return;
-
- if( other )
+ if( other && other->client )
G_GiveClientMaxAmmo( other, qtrue );
}
-
-#define DCC_ATTACK_PERIOD 10000
-
/*
================
HReactor_Think
@@ -1776,75 +1845,70 @@ Think function for Human Reactor
void HReactor_Think( gentity_t *self )
{
int entityList[ MAX_GENTITIES ];
- vec3_t range = { REACTOR_ATTACK_RANGE, REACTOR_ATTACK_RANGE, REACTOR_ATTACK_RANGE };
+ vec3_t range = { REACTOR_ATTACK_RANGE,
+ REACTOR_ATTACK_RANGE,
+ REACTOR_ATTACK_RANGE };
+ vec3_t dccrange = { REACTOR_ATTACK_DCC_RANGE,
+ REACTOR_ATTACK_DCC_RANGE,
+ REACTOR_ATTACK_DCC_RANGE };
vec3_t mins, maxs;
int i, num;
gentity_t *enemy, *tent;
- VectorAdd( self->s.origin, range, maxs );
- VectorSubtract( self->s.origin, range, mins );
+ if( self->dcc )
+ {
+ VectorAdd( self->r.currentOrigin, dccrange, maxs );
+ VectorSubtract( self->r.currentOrigin, dccrange, mins );
+ }
+ else
+ {
+ VectorAdd( self->r.currentOrigin, range, maxs );
+ VectorSubtract( self->r.currentOrigin, range, mins );
+ }
if( self->spawned && ( self->health > 0 ) )
{
- //do some damage
+ qboolean fired = qfalse;
+
+ // Creates a tesla trail for every target
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for( i = 0; i < num; i++ )
{
enemy = &g_entities[ entityList[ i ] ];
-
+ if( !enemy->client ||
+ enemy->client->ps.stats[ STAT_TEAM ] != TEAM_ALIENS )
+ continue;
if( enemy->flags & FL_NOTARGET )
continue;
- if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- if( level.paused || enemy->client->pers.paused )
- continue;
- self->timestamp = level.time;
- G_SelectiveRadiusDamage( self->s.pos.trBase, self, REACTOR_ATTACK_DAMAGE,
- REACTOR_ATTACK_RANGE, self, MOD_REACTOR, PTE_HUMANS );
-
- tent = G_TempEntity( enemy->s.pos.trBase, EV_TESLATRAIL );
-
- VectorCopy( self->s.pos.trBase, tent->s.origin2 );
-
- tent->s.generic1 = self->s.number; //src
- tent->s.clientNum = enemy->s.number; //dest
- }
+ tent = G_TempEntity( enemy->s.pos.trBase, EV_TESLATRAIL );
+ tent->s.misc = self->s.number; //src
+ tent->s.clientNum = enemy->s.number; //dest
+ VectorCopy( self->s.pos.trBase, tent->s.origin2 );
+ fired = qtrue;
}
- //reactor under attack
- if( self->health < self->lastHealth &&
- level.time > level.humanBaseAttackTimer && G_IsDCCBuilt( ) )
+ // Actual damage is done by radius
+ if( fired )
{
- level.humanBaseAttackTimer = level.time + DCC_ATTACK_PERIOD;
- G_BroadcastEvent( EV_DCC_ATTACK, 0 );
+ self->timestamp = level.time;
+ if( self->dcc )
+ G_SelectiveRadiusDamage( self->s.pos.trBase, self,
+ REACTOR_ATTACK_DCC_DAMAGE,
+ REACTOR_ATTACK_DCC_RANGE, self,
+ MOD_REACTOR, TEAM_HUMANS );
+ else
+ G_SelectiveRadiusDamage( self->s.pos.trBase, self,
+ REACTOR_ATTACK_DAMAGE,
+ REACTOR_ATTACK_RANGE, self,
+ MOD_REACTOR, TEAM_HUMANS );
}
-
- self->lastHealth = self->health;
}
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
-}
-
-/*
-================
-HReactor_Pain
-================
-*/
-
-void HReactor_Pain( gentity_t *self, gentity_t *attacker, int damage)
-{
- if (self->health <= 0)
- return;
-
- if (!attacker || !attacker->client)
- return;
-
- if (attacker->client->pers.teamSelection != PTE_HUMANS)
- return;
-
- G_TeamCommand(PTE_HUMANS, va( "print \"Reactor ^3DAMAGED^7 by ^1TEAMMATE^7 %s^7\n\"",
- attacker->client->pers.netname));
+ if( self->dcc )
+ self->nextthink = level.time + REACTOR_ATTACK_DCC_REPEAT;
+ else
+ self->nextthink = level.time + REACTOR_ATTACK_REPEAT;
}
//==================================================================================
@@ -1863,7 +1927,7 @@ void HArmoury_Activate( gentity_t *self, gentity_t *other, gentity_t *activator
if( self->spawned )
{
//only humans can activate this
- if( activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
+ if( activator->client->ps.stats[ STAT_TEAM ] != TEAM_HUMANS )
return;
//if this is powered then call the armoury menu
@@ -1886,7 +1950,9 @@ void HArmoury_Think( gentity_t *self )
//make sure we have power
self->nextthink = level.time + POWER_REFRESH_TIME;
- self->powered = G_FindPower( self );
+ self->powered = G_FindPower( self, qfalse );
+
+ G_SuicideIfNoPower( self );
}
@@ -1910,7 +1976,9 @@ void HDCC_Think( gentity_t *self )
//make sure we have power
self->nextthink = level.time + POWER_REFRESH_TIME;
- self->powered = G_FindPower( self );
+ self->powered = G_FindPower( self, qfalse );
+
+ G_SuicideIfNoPower( self );
}
@@ -1918,6 +1986,26 @@ void HDCC_Think( gentity_t *self )
//==================================================================================
+
+
+
+/*
+================
+HMedistat_Die
+
+Die function for Human Medistation
+================
+*/
+void HMedistat_Die( gentity_t *self, gentity_t *inflictor,
+ gentity_t *attacker, int damage, int mod )
+{
+ //clear target's healing flag
+ if( self->enemy && self->enemy->client )
+ self->enemy->client->ps.stats[ STAT_STATE ] &= ~SS_HEALING_ACTIVE;
+
+ HSpawn_Die( self, inflictor, attacker, damage, mod );
+}
+
/*
================
HMedistat_Think
@@ -1933,15 +2021,22 @@ void HMedistat_Think( gentity_t *self )
gentity_t *player;
qboolean occupied = qfalse;
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
+ self->nextthink = level.time + BG_Buildable( self->s.modelindex )->nextthink;
+
+ self->powered = G_FindPower( self, qfalse );
+ if( G_SuicideIfNoPower( self ) )
+ return;
+ G_IdlePowerState( self );
+
+ //clear target's healing flag
+ if( self->enemy && self->enemy->client )
+ self->enemy->client->ps.stats[ STAT_STATE ] &= ~SS_HEALING_ACTIVE;
//make sure we have power
- if( !( self->powered = G_FindPower( self ) ) )
+ if( !self->powered )
{
if( self->active )
{
- G_SetBuildableAnim( self, BANIM_CONSTRUCT2, qtrue );
- G_SetIdleBuildableAnim( self, BANIM_IDLE1 );
self->active = qfalse;
self->enemy = NULL;
}
@@ -1952,8 +2047,8 @@ void HMedistat_Think( gentity_t *self )
if( self->spawned )
{
- VectorAdd( self->s.origin, self->r.maxs, maxs );
- VectorAdd( self->s.origin, self->r.mins, mins );
+ VectorAdd( self->r.currentOrigin, self->r.maxs, maxs );
+ VectorAdd( self->r.currentOrigin, self->r.mins, mins );
mins[ 2 ] += fabs( self->r.mins[ 2 ] ) + self->r.maxs[ 2 ];
maxs[ 2 ] += 60; //player height
@@ -1961,19 +2056,27 @@ void HMedistat_Think( gentity_t *self )
//if active use the healing idle
if( self->active )
G_SetIdleBuildableAnim( self, BANIM_IDLE2 );
-
+
//check if a previous occupier is still here
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for( i = 0; i < num; i++ )
{
player = &g_entities[ entityList[ i ] ];
- if( player->client && player->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( player->flags & FL_NOTARGET )
+ continue; // notarget cancels even beneficial effects?
+
+ //remove poison from everyone, not just the healed player
+ if( player->client && player->client->ps.stats[ STAT_STATE ] & SS_POISONED )
+ player->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
+
+ if( self->enemy == player && player->client &&
+ player->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS &&
+ player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] &&
+ PM_Alive( player->client->ps.pm_type ) )
{
- if( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] &&
- player->client->ps.pm_type != PM_DEAD &&
- self->enemy == player )
- occupied = qtrue;
+ occupied = qtrue;
+ player->client->ps.stats[ STAT_STATE ] |= SS_HEALING_ACTIVE;
}
}
@@ -1986,13 +2089,14 @@ void HMedistat_Think( gentity_t *self )
{
player = &g_entities[ entityList[ i ] ];
- if( player->flags & FL_NOTARGET )
- continue; // notarget cancels even beneficial effects?
+ if( player->flags & FL_NOTARGET )
+ continue; // notarget cancels even beneficial effects?
- if( player->client && player->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( player->client && player->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
- if( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] &&
- player->client->ps.pm_type != PM_DEAD )
+ if( ( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] ||
+ player->client->ps.stats[ STAT_STAMINA ] < STAMINA_MAX ) &&
+ PM_Alive( player->client->ps.pm_type ) )
{
self->enemy = player;
@@ -2001,6 +2105,7 @@ void HMedistat_Think( gentity_t *self )
{
G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
self->active = qtrue;
+ player->client->ps.stats[ STAT_STATE ] |= SS_HEALING_ACTIVE;
}
}
else if( !BG_InventoryContainsUpgrade( UP_MEDKIT, player->client->ps.stats ) )
@@ -2017,26 +2122,25 @@ void HMedistat_Think( gentity_t *self )
self->active = qfalse;
}
- else if( self->enemy ) //heal!
+ else if( self->enemy && self->enemy->client ) //heal!
{
- if( self->enemy->client && self->enemy->client->ps.stats[ STAT_STATE ] & SS_POISONED )
- self->enemy->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
+ if( self->enemy->client->ps.stats[ STAT_STAMINA ] < STAMINA_MAX )
+ self->enemy->client->ps.stats[ STAT_STAMINA ] += STAMINA_MEDISTAT_RESTORE;
- if( self->enemy->client && self->enemy->client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE )
- self->enemy->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE;
+ if( self->enemy->client->ps.stats[ STAT_STAMINA ] > STAMINA_MAX )
+ self->enemy->client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
- self->enemy->health++;
+ if( self->enemy->health < self->enemy->client->ps.stats[ STAT_MAX_HEALTH ] )
+ {
+ self->enemy->health++;
+ self->enemy->client->ps.stats[ STAT_HEALTH ] = self->enemy->health;
+ }
//if they're completely healed, give them a medkit
- if( self->enemy->health >= self->enemy->client->ps.stats[ STAT_MAX_HEALTH ] &&
- !BG_InventoryContainsUpgrade( UP_MEDKIT, self->enemy->client->ps.stats ) )
- BG_AddUpgradeToInventory( UP_MEDKIT, self->enemy->client->ps.stats );
-
- // if completely healed, cancel retribution
if( self->enemy->health >= self->enemy->client->ps.stats[ STAT_MAX_HEALTH ] )
{
- for( i = 0; i < MAX_CLIENTS; i++ )
- self->enemy->client->tkcredits[ i ] = 0;
+ if( !BG_InventoryContainsUpgrade( UP_MEDKIT, self->enemy->client->ps.stats ) )
+ BG_AddUpgradeToInventory( UP_MEDKIT, self->enemy->client->ps.stats );
}
}
}
@@ -2052,6 +2156,39 @@ void HMedistat_Think( gentity_t *self )
/*
================
+HMGTurret_CheckTarget
+
+Used by HMGTurret_Think to check enemies for validity
+================
+*/
+qboolean HMGTurret_CheckTarget( gentity_t *self, gentity_t *target,
+ qboolean los_check )
+{
+ trace_t tr;
+ vec3_t dir, end;
+
+ if( !target || target->health <= 0 || !target->client ||
+ target->client->pers.teamSelection != TEAM_ALIENS )
+ return qfalse;
+
+ if( target->flags & FL_NOTARGET )
+ return qfalse;
+
+ if( !los_check )
+ return qtrue;
+
+ // Accept target if we can line-trace to it
+ VectorSubtract( target->s.pos.trBase, self->s.pos.trBase, dir );
+ VectorNormalize( dir );
+ VectorMA( self->s.pos.trBase, MGTURRET_RANGE, dir, end );
+ trap_Trace( &tr, self->s.pos.trBase, NULL, NULL, end,
+ self->s.number, MASK_SHOT );
+ return tr.entityNum == target - g_entities;
+}
+
+
+/*
+================
HMGTurret_TrackEnemy
Used by HMGTurret_Think to track enemy location
@@ -2062,27 +2199,8 @@ qboolean HMGTurret_TrackEnemy( gentity_t *self )
vec3_t dirToTarget, dttAdjusted, angleToTarget, angularDiff, xNormal;
vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
float temp, rotAngle;
- float accuracyTolerance, angularSpeed;
-
- if( self->lev1Grabbed )
- {
- //can't turn fast if grabbed
- accuracyTolerance = MGTURRET_GRAB_ACCURACYTOLERANCE;
- angularSpeed = MGTURRET_GRAB_ANGULARSPEED;
- }
- else if( self->dcced )
- {
- accuracyTolerance = MGTURRET_DCC_ACCURACYTOLERANCE;
- angularSpeed = MGTURRET_DCC_ANGULARSPEED;
- }
- else
- {
- accuracyTolerance = MGTURRET_ACCURACYTOLERANCE;
- angularSpeed = MGTURRET_ANGULARSPEED;
- }
VectorSubtract( self->enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget );
-
VectorNormalize( dirToTarget );
CrossProduct( self->s.origin2, refNormal, xNormal );
@@ -2096,10 +2214,10 @@ qboolean HMGTurret_TrackEnemy( gentity_t *self )
angularDiff[ YAW ] = AngleSubtract( self->s.angles2[ YAW ], angleToTarget[ YAW ] );
//if not pointing at our target then move accordingly
- if( angularDiff[ PITCH ] < (-accuracyTolerance) )
- self->s.angles2[ PITCH ] += angularSpeed;
- else if( angularDiff[ PITCH ] > accuracyTolerance )
- self->s.angles2[ PITCH ] -= angularSpeed;
+ if( angularDiff[ PITCH ] < 0 && angularDiff[ PITCH ] < (-MGTURRET_ANGULARSPEED) )
+ self->s.angles2[ PITCH ] += MGTURRET_ANGULARSPEED;
+ else if( angularDiff[ PITCH ] > 0 && angularDiff[ PITCH ] > MGTURRET_ANGULARSPEED )
+ self->s.angles2[ PITCH ] -= MGTURRET_ANGULARSPEED;
else
self->s.angles2[ PITCH ] = angleToTarget[ PITCH ];
@@ -2112,10 +2230,10 @@ qboolean HMGTurret_TrackEnemy( gentity_t *self )
self->s.angles2[ PITCH ] = (-360) + MGTURRET_VERTICALCAP;
//if not pointing at our target then move accordingly
- if( angularDiff[ YAW ] < (-accuracyTolerance) )
- self->s.angles2[ YAW ] += angularSpeed;
- else if( angularDiff[ YAW ] > accuracyTolerance )
- self->s.angles2[ YAW ] -= angularSpeed;
+ if( angularDiff[ YAW ] < 0 && angularDiff[ YAW ] < ( -MGTURRET_ANGULARSPEED ) )
+ self->s.angles2[ YAW ] += MGTURRET_ANGULARSPEED;
+ else if( angularDiff[ YAW ] > 0 && angularDiff[ YAW ] > MGTURRET_ANGULARSPEED )
+ self->s.angles2[ YAW ] -= MGTURRET_ANGULARSPEED;
else
self->s.angles2[ YAW ] = angleToTarget[ YAW ];
@@ -2123,132 +2241,110 @@ qboolean HMGTurret_TrackEnemy( gentity_t *self )
RotatePointAroundVector( dirToTarget, xNormal, dttAdjusted, -rotAngle );
vectoangles( dirToTarget, self->turretAim );
- //if pointing at our target return true
- if( fabs( angleToTarget[ YAW ] - self->s.angles2[ YAW ] ) <= accuracyTolerance &&
- fabs( angleToTarget[ PITCH ] - self->s.angles2[ PITCH ] ) <= accuracyTolerance )
- return qtrue;
-
- return qfalse;
+ //fire if target is within accuracy
+ return ( fabs( angularDiff[ YAW ] ) - MGTURRET_ANGULARSPEED <=
+ MGTURRET_ACCURACY_TO_FIRE ) &&
+ ( fabs( angularDiff[ PITCH ] ) - MGTURRET_ANGULARSPEED <=
+ MGTURRET_ACCURACY_TO_FIRE );
}
/*
================
-HMGTurret_CheckTarget
+HMGTurret_FindEnemy
-Used by HMGTurret_Think to check enemies for validity
+Used by HMGTurret_Think to locate enemy gentities
================
*/
-qboolean HMGTurret_CheckTarget( gentity_t *self, gentity_t *target, qboolean ignorePainted )
+void HMGTurret_FindEnemy( gentity_t *self )
{
- trace_t trace;
- gentity_t *traceEnt;
-
- if( !target )
- return qfalse;
-
- if( target->flags & FL_NOTARGET )
- return qfalse;
-
- if( !target->client )
- return qfalse;
-
- if( level.paused || target->client->pers.paused )
- return qfalse;
-
- if( target->client->ps.stats[ STAT_STATE ] & SS_HOVELING )
- return qfalse;
-
- if( target->health <= 0 )
- return qfalse;
-
- if( Distance( self->s.origin, target->s.pos.trBase ) > MGTURRET_RANGE )
- return qfalse;
-
- //some turret has already selected this target
- if( self->dcced && target->targeted && target->targeted->powered && !ignorePainted )
- return qfalse;
-
- trap_Trace( &trace, self->s.pos.trBase, NULL, NULL, target->s.pos.trBase, self->s.number, MASK_SHOT );
+ int entityList[ MAX_GENTITIES ];
+ vec3_t range;
+ vec3_t mins, maxs;
+ int i, num;
+ gentity_t *target;
+ int start;
- traceEnt = &g_entities[ trace.entityNum ];
+ self->enemy = NULL;
+
+ // Look for targets in a box around the turret
+ VectorSet( range, MGTURRET_RANGE, MGTURRET_RANGE, MGTURRET_RANGE );
+ VectorAdd( self->r.currentOrigin, range, maxs );
+ VectorSubtract( self->r.currentOrigin, range, mins );
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- if( !traceEnt->client )
- return qfalse;
+ if( num == 0 )
+ return;
- if( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS )
- return qfalse;
+ start = rand( ) / ( RAND_MAX / num + 1 );
+ for( i = start; i < num + start ; i++ )
+ {
+ target = &g_entities[ entityList[ i % num ] ];
+ if( !HMGTurret_CheckTarget( self, target, qtrue ) )
+ continue;
- return qtrue;
+ self->enemy = target;
+ return;
+ }
}
-
/*
================
-HMGTurret_FindEnemy
+HMGTurret_State
-Used by HMGTurret_Think to locate enemy gentities
+Raise or lower MG turret towards desired state
================
*/
-void HMGTurret_FindEnemy( gentity_t *self )
+enum {
+ MGT_STATE_INACTIVE,
+ MGT_STATE_DROP,
+ MGT_STATE_RISE,
+ MGT_STATE_ACTIVE
+};
+
+static qboolean HMGTurret_State( gentity_t *self, int state )
{
- int entityList[ MAX_GENTITIES ];
- vec3_t range;
- vec3_t mins, maxs;
- int i, num;
- gentity_t *target;
+ float angle;
- VectorSet( range, MGTURRET_RANGE, MGTURRET_RANGE, MGTURRET_RANGE );
- VectorAdd( self->s.origin, range, maxs );
- VectorSubtract( self->s.origin, range, mins );
+ if( self->waterlevel == state )
+ return qfalse;
- //find aliens
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
- {
- target = &g_entities[ entityList[ i ] ];
+ angle = AngleNormalize180( self->s.angles2[ PITCH ] );
- if( target->client && target->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( state == MGT_STATE_INACTIVE )
+ {
+ if( angle < MGTURRET_VERTICALCAP )
{
- //if target is not valid keep searching
- if( !HMGTurret_CheckTarget( self, target, qfalse ) )
- continue;
+ if( self->waterlevel != MGT_STATE_DROP )
+ {
+ self->speed = 0.25f;
+ self->waterlevel = MGT_STATE_DROP;
+ }
+ else
+ self->speed *= 1.25f;
- //we found a target
- self->enemy = target;
- return;
+ self->s.angles2[ PITCH ] =
+ MIN( MGTURRET_VERTICALCAP, angle + self->speed );
+ return qtrue;
}
+ else
+ self->waterlevel = MGT_STATE_INACTIVE;
}
-
- if( self->dcced )
+ else if( state == MGT_STATE_ACTIVE )
{
- //check again, this time ignoring painted targets
- for( i = 0; i < num; i++ )
+ if( !self->enemy && angle > 0.0f )
{
- target = &g_entities[ entityList[ i ] ];
-
- if( target->client && target->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- //if target is not valid keep searching
- if( !HMGTurret_CheckTarget( self, target, qtrue ) )
- continue;
-
- //we found a target
- self->enemy = target;
- return;
- }
+ self->waterlevel = MGT_STATE_RISE;
+ self->s.angles2[ PITCH ] =
+ MAX( 0.0f, angle - MGTURRET_ANGULARSPEED * 0.5f );
}
+ else
+ self->waterlevel = MGT_STATE_ACTIVE;
}
- //couldn't find a target
- self->enemy = NULL;
+ return qfalse;
}
-#define MGTURRET_DROOPSCALE 0.5f
-#define TURRET_REST_TIME 5000
-#define TURRET_REST_SPEED 3.0f
-#define TURRET_REST_TOLERANCE 4.0f
-
/*
================
HMGTurret_Think
@@ -2258,69 +2354,73 @@ Think function for MG turret
*/
void HMGTurret_Think( gentity_t *self )
{
- int firespeed = BG_FindFireSpeedForBuildable( self->s.modelindex );
+ self->nextthink = level.time +
+ BG_Buildable( self->s.modelindex )->nextthink;
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
-
- //used for client side muzzle flashes
+ // Turn off client side muzzle flashes
self->s.eFlags &= ~EF_FIRING;
- //if not powered don't do anything and check again for power next think
- if( !( self->powered = G_FindPower( self ) ) )
- {
- if( self->spawned )
- {
- // unpowered turret barrel falls to bottom of range
- float droop;
+ self->powered = G_FindPower( self, qfalse );
+ if( G_SuicideIfNoPower( self ) )
+ return;
+ G_IdlePowerState( self );
- droop = AngleNormalize180( self->s.angles2[ PITCH ] );
- if( droop < MGTURRET_VERTICALCAP )
- {
- droop += MGTURRET_DROOPSCALE;
- if( droop > MGTURRET_VERTICALCAP )
- droop = MGTURRET_VERTICALCAP;
- self->s.angles2[ PITCH ] = droop;
- return;
- }
- }
+ // If not powered or spawned don't do anything
+ if( !self->powered )
+ {
+ // if power loss drop turret
+ if( self->spawned &&
+ HMGTurret_State( self, MGT_STATE_INACTIVE ) )
+ return;
self->nextthink = level.time + POWER_REFRESH_TIME;
return;
}
-
- if( self->spawned )
+ if( !self->spawned )
+ return;
+
+ // If the current target is not valid find a new enemy
+ if( !HMGTurret_CheckTarget( self, self->enemy, qtrue ) )
{
- //find a dcc for self
- self->dcced = G_FindDCC( self );
-
- //if the current target is not valid find a new one
- if( !HMGTurret_CheckTarget( self, self->enemy, qfalse ) )
- {
- if( self->enemy )
- self->enemy->targeted = NULL;
-
- HMGTurret_FindEnemy( self );
- }
+ self->active = qfalse;
+ self->turretSpinupTime = -1;
+ HMGTurret_FindEnemy( self );
+ }
+ // if newly powered raise turret
+ HMGTurret_State( self, MGT_STATE_ACTIVE );
+ if( !self->enemy )
+ return;
- //if a new target cannot be found don't do anything
- if( !self->enemy )
- return;
+ // Track until we can hit the target
+ if( !HMGTurret_TrackEnemy( self ) )
+ {
+ self->active = qfalse;
+ self->turretSpinupTime = -1;
+ return;
+ }
- self->enemy->targeted = self;
+ // Update spin state
+ if( !self->active && self->timestamp < level.time )
+ {
+ self->active = qtrue;
- //if we are pointing at our target and we can fire shoot it
- if( HMGTurret_TrackEnemy( self ) && ( self->count < level.time ) )
- {
- //fire at target
- FireWeapon( self );
+ self->turretSpinupTime = level.time + MGTURRET_SPINUP_TIME;
+ G_AddEvent( self, EV_MGTURRET_SPINUP, 0 );
+ }
- self->s.eFlags |= EF_FIRING;
- G_AddEvent( self, EV_FIRE_WEAPON, 0 );
- G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
+ // Not firing or haven't spun up yet
+ if( !self->active || self->turretSpinupTime > level.time )
+ return;
+
+ // Fire repeat delay
+ if( self->timestamp > level.time )
+ return;
- self->count = level.time + firespeed;
- }
- }
+ FireWeapon( self );
+ self->s.eFlags |= EF_FIRING;
+ self->timestamp = level.time + BG_Buildable( self->s.modelindex )->turretFireSpeed;
+ G_AddEvent( self, EV_FIRE_WEAPON, 0 );
+ G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
}
@@ -2340,54 +2440,51 @@ Think function for Tesla Generator
*/
void HTeslaGen_Think( gentity_t *self )
{
- int entityList[ MAX_GENTITIES ];
- vec3_t range;
- vec3_t mins, maxs;
- vec3_t dir;
- int i, num;
- gentity_t *enemy;
+ self->nextthink = level.time + BG_Buildable( self->s.modelindex )->nextthink;
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
+ self->powered = G_FindPower( self, qfalse );
+ if( G_SuicideIfNoPower( self ) )
+ return;
+ G_IdlePowerState( self );
//if not powered don't do anything and check again for power next think
- if( !( self->powered = G_FindPower( self ) ) || !( self->dcced = G_FindDCC( self ) ) )
+ if( !self->powered )
{
self->s.eFlags &= ~EF_FIRING;
self->nextthink = level.time + POWER_REFRESH_TIME;
return;
}
- if( self->spawned && self->count < level.time )
+ if( self->spawned && self->timestamp < level.time )
{
- //used to mark client side effects
+ vec3_t origin, range, mins, maxs;
+ int entityList[ MAX_GENTITIES ], i, num;
+
+ // Communicates firing state to client
self->s.eFlags &= ~EF_FIRING;
+ // Move the muzzle from the entity origin up a bit to fire over turrets
+ VectorMA( self->r.currentOrigin, self->r.maxs[ 2 ], self->s.origin2, origin );
+
VectorSet( range, TESLAGEN_RANGE, TESLAGEN_RANGE, TESLAGEN_RANGE );
- VectorAdd( self->s.origin, range, maxs );
- VectorSubtract( self->s.origin, range, mins );
+ VectorAdd( origin, range, maxs );
+ VectorSubtract( origin, range, mins );
- //find aliens
+ // Attack nearby Aliens
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for( i = 0; i < num; i++ )
{
- enemy = &g_entities[ entityList[ i ] ];
+ self->enemy = &g_entities[ entityList[ i ] ];
- if( enemy->flags & FL_NOTARGET )
+ if( self->enemy->flags & FL_NOTARGET )
continue;
- if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS &&
- enemy->health > 0 &&
- !level.paused && !enemy->client->pers.paused &&
- Distance( enemy->s.pos.trBase, self->s.pos.trBase ) <= TESLAGEN_RANGE )
- {
- VectorSubtract( enemy->s.pos.trBase, self->s.pos.trBase, dir );
- VectorNormalize( dir );
- vectoangles( dir, self->turretAim );
-
- //fire at target
+ if( self->enemy->client && self->enemy->health > 0 &&
+ self->enemy->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS &&
+ Distance( origin, self->enemy->s.pos.trBase ) <= TESLAGEN_RANGE )
FireWeapon( self );
- }
}
+ self->enemy = NULL;
if( self->s.eFlags & EF_FIRING )
{
@@ -2396,7 +2493,7 @@ void HTeslaGen_Think( gentity_t *self )
//doesn't really need an anim
//G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
- self->count = level.time + TESLAGEN_REPEAT;
+ self->timestamp = level.time + TESLAGEN_REPEAT;
}
}
}
@@ -2410,228 +2507,125 @@ void HTeslaGen_Think( gentity_t *self )
/*
-================
-HSpawn_Disappear
-
-Called when a human spawn is destroyed before it is spawned
-think function
-================
+============
+G_QueueValue
+============
*/
-void HSpawn_Disappear( gentity_t *self )
+
+static int G_QueueValue( gentity_t *self )
{
- vec3_t dir;
+ int i;
+ int damageTotal = 0;
+ int queuePoints;
+ double queueFraction = 0;
- // we don't have a valid direction, so just point straight up
- dir[ 0 ] = dir[ 1 ] = 0;
- dir[ 2 ] = 1;
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ gentity_t *player = g_entities + i;
- self->s.eFlags |= EF_NODRAW; //don't draw the model once its destroyed
- self->timestamp = level.time;
+ damageTotal += self->credits[ i ];
+
+ if( self->buildableTeam != player->client->pers.teamSelection )
+ queueFraction += (double) self->credits[ i ];
+ }
- self->think = freeBuildable;
- self->nextthink = level.time + 100;
+ if( damageTotal > 0 )
+ queueFraction = queueFraction / (double) damageTotal;
+ else // all damage was done by nonclients, so queue everything
+ queueFraction = 1.0;
- self->r.contents = 0; //stop collisions...
- trap_LinkEntity( self ); //...requires a relink
+ queuePoints = (int) ( queueFraction * (double) BG_Buildable( self->s.modelindex )->buildPoints );
+ return queuePoints;
}
-
/*
-================
-HSpawn_blast
-
-Called when a human spawn explodes
-think function
-================
+============
+G_QueueBuildPoints
+============
*/
-void HSpawn_Blast( gentity_t *self )
+void G_QueueBuildPoints( gentity_t *self )
{
- vec3_t dir;
+ gentity_t *powerEntity;
+ int queuePoints;
- // we don't have a valid direction, so just point straight up
- dir[ 0 ] = dir[ 1 ] = 0;
- dir[ 2 ] = 1;
+ queuePoints = G_QueueValue( self );
- self->s.eFlags |= EF_NODRAW; //don't draw the model once its destroyed
- G_AddEvent( self, EV_HUMAN_BUILDABLE_EXPLOSION, DirToByte( dir ) );
- self->timestamp = level.time;
+ if( !queuePoints )
+ return;
+
+ switch( self->buildableTeam )
+ {
+ default:
+ case TEAM_NONE:
+ return;
- //do some radius damage
- G_RadiusDamage( self->s.pos.trBase, self, self->splashDamage,
- self->splashRadius, self, 0, self->splashMethodOfDeath );
+ case TEAM_ALIENS:
+ if( !level.alienBuildPointQueue )
+ level.alienNextQueueTime = level.time + g_alienBuildQueueTime.integer;
- self->think = freeBuildable;
- self->nextthink = level.time + 100;
+ level.alienBuildPointQueue += queuePoints;
+ break;
- self->r.contents = 0; //stop collisions...
- trap_LinkEntity( self ); //...requires a relink
-}
+ case TEAM_HUMANS:
+ powerEntity = G_PowerEntityForEntity( self );
+ if( powerEntity )
+ {
+ int nqt;
+ switch( powerEntity->s.modelindex )
+ {
+ case BA_H_REACTOR:
+ nqt = G_NextQueueTime( level.humanBuildPointQueue,
+ g_humanBuildPoints.integer,
+ g_humanBuildQueueTime.integer );
+ if( !level.humanBuildPointQueue ||
+ level.time + nqt < level.humanNextQueueTime )
+ level.humanNextQueueTime = level.time + nqt;
+
+ level.humanBuildPointQueue += queuePoints;
+ break;
-/*
-================
-HSpawn_die
+ case BA_H_REPEATER:
+ if( powerEntity->usesBuildPointZone &&
+ level.buildPointZones[ powerEntity->buildPointZone ].active )
+ {
+ buildPointZone_t *zone = &level.buildPointZones[ powerEntity->buildPointZone ];
-Called when a human spawn dies
-================
-*/
-void HSpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod )
-{
- buildHistory_t *new;
- new = G_Alloc( sizeof( buildHistory_t ) );
- new->ID = ( ++level.lastBuildID > 1000 ) ? ( level.lastBuildID = 1 ) : level.lastBuildID;
- new->ent = ( attacker && attacker->client ) ? attacker : NULL;
- if( new->ent )
- new->name[ 0 ] = 0;
- else
- Q_strncpyz( new->name, "<world>", 8 );
- new->buildable = self->s.modelindex;
- VectorCopy( self->s.pos.trBase, new->origin );
- VectorCopy( self->s.angles, new->angles );
- VectorCopy( self->s.origin2, new->origin2 );
- VectorCopy( self->s.angles2, new->angles2 );
- new->fate = ( attacker && attacker->client && attacker->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ? BF_TEAMKILLED : BF_DESTROYED;
- new->next = NULL;
- G_LogBuild( new );
-
- G_BuildableDeathSound( self );
-
- //pretty events and cleanup
- G_SetBuildableAnim( self, BANIM_DESTROY1, qtrue );
- G_SetIdleBuildableAnim( self, BANIM_DESTROYED );
+ nqt = G_NextQueueTime( zone->queuedBuildPoints,
+ zone->totalBuildPoints,
+ g_humanRepeaterBuildQueueTime.integer );
- self->die = nullDieFunction;
- self->powered = qfalse; //free up power
- //prevent any firing effects and cancel structure protection
- self->s.eFlags &= ~( EF_FIRING | EF_DBUILDER );
+ if( !zone->queuedBuildPoints ||
+ level.time + nqt < zone->nextQueueTime )
+ zone->nextQueueTime = level.time + nqt;
- if( self->spawned )
- {
- self->think = HSpawn_Blast;
- self->nextthink = level.time + HUMAN_DETONATION_DELAY;
- }
- else
- {
- self->think = HSpawn_Disappear;
- self->nextthink = level.time; //blast immediately
- }
+ zone->queuedBuildPoints += queuePoints;
+ }
+ break;
- if( attacker && attacker->client )
- {
- if( attacker->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- if( self->s.modelindex == BA_H_REACTOR )
- G_AddCreditToClient( attacker->client, REACTOR_VALUE, qtrue );
- else if( self->s.modelindex == BA_H_SPAWN )
- G_AddCreditToClient( attacker->client, HSPAWN_VALUE, qtrue );
- }
- else
- {
- G_TeamCommand( PTE_HUMANS,
- va( "print \"%s ^3DESTROYED^7 by teammate %s^7\n\"",
- BG_FindHumanNameForBuildable( self->s.modelindex ),
- attacker->client->pers.netname ) );
- G_LogOnlyPrintf("%s ^3DESTROYED^7 by teammate %s^7\n",
- BG_FindHumanNameForBuildable( self->s.modelindex ),
- attacker->client->pers.netname );
- }
- G_LogPrintf( "Decon: %i %i %i: %s^7 destroyed %s by %s\n",
- attacker->client->ps.clientNum, self->s.modelindex, mod,
- attacker->client->pers.netname,
- BG_FindNameForBuildable( self->s.modelindex ),
- modNames[ mod ] );
+ default:
+ break;
+ }
+ }
}
}
/*
-================
-HSpawn_Think
-
-Think for human spawn
-================
+============
+G_NextQueueTime
+============
*/
-void HSpawn_Think( gentity_t *self )
+int G_NextQueueTime( int queuedBP, int totalBP, int queueBaseRate )
{
- gentity_t *ent;
-
- // spawns work without power
- self->powered = qtrue;
-
- if( self->spawned )
- {
- //only suicide if at rest
- if( self->s.groundEntityNum )
- {
- if( ( ent = G_CheckSpawnPoint( self->s.number, self->s.origin,
- self->s.origin2, BA_H_SPAWN, NULL ) ) != NULL )
- {
- // If the thing blocking the spawn is a buildable, kill it.
- // If it's part of the map, kill self.
- if( ent->s.eType == ET_BUILDABLE )
- {
- G_Damage( ent, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
- G_SetBuildableAnim( self, BANIM_SPAWN1, qtrue );
- }
- else if( ent->s.number == ENTITYNUM_WORLD || ent->s.eType == ET_MOVER )
- {
- G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
- return;
- }
- else if( g_antiSpawnBlock.integer && ent->client &&
- ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- //spawnblock protection
- if( self->spawnBlockTime && level.time - self->spawnBlockTime > 10000 )
- {
- //five seconds of countermeasures and we're still blocked
- //time for something more drastic
- G_Damage( ent, NULL, NULL, NULL, NULL, 10000, 0, MOD_TRIGGER_HURT );
- self->spawnBlockTime += 2000;
- //inappropriate MOD but prints an apt obituary
- }
- else if( self->spawnBlockTime && level.time - self->spawnBlockTime > 5000 )
- //five seconds of blocked by client and...
- {
- //random direction
- vec3_t velocity;
- velocity[0] = crandom() * g_antiSpawnBlock.integer;
- velocity[1] = crandom() * g_antiSpawnBlock.integer;
- velocity[2] = g_antiSpawnBlock.integer;
-
- VectorAdd( ent->client->ps.velocity, velocity, ent->client->ps.velocity );
- trap_SendServerCommand( ent-g_entities, "cp \"Don't spawn block!\"" );
- }
- else if( !self->spawnBlockTime )
- self->spawnBlockTime = level.time;
- }
+ float fractionQueued;
- if( ent->s.eType == ET_CORPSE )
- G_FreeEntity( ent ); //quietly remove
- }
- else
- self->spawnBlockTime = 0;
- }
+ if( totalBP == 0 )
+ return 0;
- //spawn under attack
- if( self->health < self->lastHealth &&
- level.time > level.humanBaseAttackTimer && G_IsDCCBuilt( ) )
- {
- level.humanBaseAttackTimer = level.time + DCC_ATTACK_PERIOD;
- G_BroadcastEvent( EV_DCC_ATTACK, 0 );
- }
-
- self->lastHealth = self->health;
- }
-
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
+ fractionQueued = queuedBP / (float)totalBP;
+ return ( 1.0f - fractionQueued ) * queueBaseRate;
}
-
-
-
-//==================================================================================
-
-
/*
============
G_BuildableTouchTriggers
@@ -2653,18 +2647,18 @@ void G_BuildableTouchTriggers( gentity_t *ent )
if( ent->health <= 0 )
return;
- BG_FindBBoxForBuildable( ent->s.modelindex, bmins, bmaxs );
+ BG_BuildableBoundingBox( ent->s.modelindex, bmins, bmaxs );
- VectorAdd( ent->s.origin, bmins, mins );
- VectorAdd( ent->s.origin, bmaxs, maxs );
+ VectorAdd( ent->r.currentOrigin, bmins, mins );
+ VectorAdd( ent->r.currentOrigin, bmaxs, maxs );
VectorSubtract( mins, range, mins );
VectorAdd( maxs, range, maxs );
num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
- VectorAdd( ent->s.origin, bmins, mins );
- VectorAdd( ent->s.origin, bmaxs, maxs );
+ VectorAdd( ent->r.currentOrigin, bmins, mins );
+ VectorAdd( ent->r.currentOrigin, bmaxs, maxs );
for( i = 0; i < num; i++ )
{
@@ -2700,66 +2694,85 @@ General think function for buildables
*/
void G_BuildableThink( gentity_t *ent, int msec )
{
- int bHealth = BG_FindHealthForBuildable( ent->s.modelindex );
- int bRegen = BG_FindRegenRateForBuildable( ent->s.modelindex );
- int bTime = BG_FindBuildTimeForBuildable( ent->s.modelindex );
-
- //pack health, power and dcc
+ int maxHealth = BG_Buildable( ent->s.modelindex )->health;
+ int regenRate = BG_Buildable( ent->s.modelindex )->regenRate;
+ int buildTime = BG_Buildable( ent->s.modelindex )->buildTime;
//toggle spawned flag for buildables
- if( !ent->spawned && ent->health > 0 )
+ if( !ent->spawned && ent->health > 0 && !level.pausedTime )
{
- if( ent->buildTime + bTime < level.time )
+ if( ent->buildTime + buildTime < level.time )
+ {
ent->spawned = qtrue;
+ if( ent->s.modelindex == BA_A_OVERMIND )
+ {
+ G_TeamCommand( TEAM_ALIENS, "cp \"The Overmind has awakened!\"" );
+ }
+ }
}
- ent->s.generic1 = (int)( ( (float)ent->health / (float)bHealth ) * B_HEALTH_MASK );
-
- if( ent->s.generic1 < 0 )
- ent->s.generic1 = 0;
-
- if( ent->powered )
- ent->s.generic1 |= B_POWERED_TOGGLEBIT;
-
- if( ent->dcced )
- ent->s.generic1 |= B_DCCED_TOGGLEBIT;
-
- if( ent->spawned )
- ent->s.generic1 |= B_SPAWNED_TOGGLEBIT;
-
- if( ent->deconstruct )
- ent->s.generic1 |= B_MARKED_TOGGLEBIT;
-
+ // Timer actions
ent->time1000 += msec;
-
if( ent->time1000 >= 1000 )
{
ent->time1000 -= 1000;
- if( !ent->spawned && ent->health > 0 )
- ent->health += (int)( ceil( (float)bHealth / (float)( bTime * 0.001 ) ) );
- else if( ent->biteam == BIT_ALIENS && ent->health > 0 && ent->health < bHealth &&
- bRegen && ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time )
- ent->health += bRegen;
+ if( ent->health > 0 && ent->health < maxHealth )
+ {
+ if( !ent->spawned )
+ ent->health += (int)( ceil( (float)maxHealth / (float)( buildTime * 0.001f ) ) );
+ else
+ {
+ if( ent->buildableTeam == TEAM_ALIENS && regenRate &&
+ ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time )
+ {
+ ent->health += regenRate;
+ }
+ else if( ent->buildableTeam == TEAM_HUMANS && ent->dcc &&
+ ( ent->lastDamageTime + HUMAN_REGEN_DAMAGE_TIME ) < level.time )
+ {
+ ent->health += DC_HEALRATE * ent->dcc;
+ }
+ }
- if( ent->health > bHealth )
- ent->health = bHealth;
+ if( ent->health >= maxHealth )
+ {
+ int i;
+ ent->health = maxHealth;
+ for( i = 0; i < MAX_CLIENTS; i++ )
+ ent->credits[ i ] = 0;
+ }
+ }
}
- if( ent->lev1Grabbed && ent->lev1GrabTime + LEVEL1_GRAB_TIME < level.time )
- ent->lev1Grabbed = qfalse;
-
if( ent->clientSpawnTime > 0 )
ent->clientSpawnTime -= msec;
if( ent->clientSpawnTime < 0 )
ent->clientSpawnTime = 0;
- //check if this buildable is touching any triggers
+ ent->dcc = ( ent->buildableTeam != TEAM_HUMANS ) ? 0 : G_FindDCC( ent );
+
+ // Set health
+ ent->s.misc = MAX( ent->health, 0 );
+
+ // Set flags
+ ent->s.eFlags &= ~( EF_B_POWERED | EF_B_SPAWNED | EF_B_MARKED );
+ if( ent->powered )
+ ent->s.eFlags |= EF_B_POWERED;
+
+ if( ent->spawned )
+ ent->s.eFlags |= EF_B_SPAWNED;
+
+ if( ent->deconstruct )
+ ent->s.eFlags |= EF_B_MARKED;
+
+ // Check if this buildable is touching any triggers
G_BuildableTouchTriggers( ent );
- //fall back on normal physics routines
- G_Physics( ent, msec );
+ // Fall back on normal physics routines
+ if( msec != 0 )
+ G_Physics( ent, msec );
}
@@ -2790,7 +2803,7 @@ qboolean G_BuildableRange( vec3_t origin, float r, buildable_t buildable )
if( ent->s.eType != ET_BUILDABLE )
continue;
- if( ent->biteam == BIT_HUMANS && !ent->powered )
+ if( ent->buildableTeam == TEAM_HUMANS && !ent->powered )
continue;
if( ent->s.modelindex == buildable && ent->spawned )
@@ -2800,20 +2813,29 @@ qboolean G_BuildableRange( vec3_t origin, float r, buildable_t buildable )
return qfalse;
}
-static qboolean G_BoundsIntersect(const vec3_t mins, const vec3_t maxs,
- const vec3_t mins2, const vec3_t maxs2)
+/*
+================
+G_FindBuildable
+
+Finds a buildable of the specified type
+================
+*/
+static gentity_t *G_FindBuildable( buildable_t buildable )
{
- if ( maxs[0] < mins2[0] ||
- maxs[1] < mins2[1] ||
- maxs[2] < mins2[2] ||
- mins[0] > maxs2[0] ||
- mins[1] > maxs2[1] ||
- mins[2] > maxs2[2])
+ int i;
+ gentity_t *ent;
+
+ for( i = MAX_CLIENTS, ent = g_entities + i;
+ i < level.num_entities; i++, ent++ )
{
- return qfalse;
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
+
+ if( ent->s.modelindex == buildable && !( ent->s.eFlags & EF_DEAD ) )
+ return ent;
}
- return qtrue;
+ return NULL;
}
/*
@@ -2829,15 +2851,15 @@ static qboolean G_BuildablesIntersect( buildable_t a, vec3_t originA,
vec3_t minsA, maxsA;
vec3_t minsB, maxsB;
- BG_FindBBoxForBuildable( a, minsA, maxsA );
+ BG_BuildableBoundingBox( a, minsA, maxsA );
VectorAdd( minsA, originA, minsA );
VectorAdd( maxsA, originA, maxsA );
- BG_FindBBoxForBuildable( b, minsB, maxsB );
+ BG_BuildableBoundingBox( b, minsB, maxsB );
VectorAdd( minsB, originB, minsB );
VectorAdd( maxsB, originB, maxsB );
- return G_BoundsIntersect( minsA, maxsA, minsB, maxsB );
+ return BoundsIntersect( minsA, maxsA, minsB, maxsB );
}
/*
@@ -2860,7 +2882,6 @@ static int G_CompareBuildablesForRemoval( const void *a, const void *b )
BA_A_TRAPPER,
BA_A_HIVE,
BA_A_BOOSTER,
- BA_A_HOVEL,
BA_A_SPAWN,
BA_A_OVERMIND,
@@ -2882,30 +2903,55 @@ static int G_CompareBuildablesForRemoval( const void *a, const void *b )
buildableA = *(gentity_t **)a;
buildableB = *(gentity_t **)b;
-
// Prefer the one that collides with the thing we're building
aMatches = G_BuildablesIntersect( cmpBuildable, cmpOrigin,
- buildableA->s.modelindex, buildableA->s.origin );
+ buildableA->s.modelindex, buildableA->r.currentOrigin );
bMatches = G_BuildablesIntersect( cmpBuildable, cmpOrigin,
- buildableB->s.modelindex, buildableB->s.origin );
+ buildableB->s.modelindex, buildableB->r.currentOrigin );
if( aMatches && !bMatches )
return -1;
- if( !aMatches && bMatches )
+ else if( !aMatches && bMatches )
return 1;
+ // If the only spawn is marked, prefer it last
+ if( cmpBuildable == BA_A_SPAWN || cmpBuildable == BA_H_SPAWN )
+ {
+ if( ( buildableA->s.modelindex == BA_A_SPAWN && level.numAlienSpawns == 1 ) ||
+ ( buildableA->s.modelindex == BA_H_SPAWN && level.numHumanSpawns == 1 ) )
+ return 1;
+
+ if( ( buildableB->s.modelindex == BA_A_SPAWN && level.numAlienSpawns == 1 ) ||
+ ( buildableB->s.modelindex == BA_H_SPAWN && level.numHumanSpawns == 1 ) )
+ return -1;
+ }
+
// If one matches the thing we're building, prefer it
aMatches = ( buildableA->s.modelindex == cmpBuildable );
bMatches = ( buildableB->s.modelindex == cmpBuildable );
if( aMatches && !bMatches )
return -1;
- if( !aMatches && bMatches )
+ else if( !aMatches && bMatches )
return 1;
- // If they're the same type then pick the one marked earliest
+ // They're the same type
if( buildableA->s.modelindex == buildableB->s.modelindex )
+ {
+ gentity_t *powerEntity = G_PowerEntityForPoint( cmpOrigin );
+
+ // Prefer the entity that is providing power for this point
+ aMatches = ( powerEntity == buildableA );
+ bMatches = ( powerEntity == buildableB );
+ if( aMatches && !bMatches )
+ return -1;
+ else if( !aMatches && bMatches )
+ return 1;
+
+ // Pick the one marked earliest
return buildableA->deconstructTime - buildableB->deconstructTime;
+ }
- for( i = 0; i < sizeof( precedence ) / sizeof( precedence[ 0 ] ); i++ )
+ // Resort to preference list
+ for( i = 0; i < ARRAY_LEN( precedence ); i++ )
{
if( buildableA->s.modelindex == precedence[ i ] )
aPrecedence = i;
@@ -2919,17 +2965,49 @@ static int G_CompareBuildablesForRemoval( const void *a, const void *b )
/*
===============
+G_ClearDeconMarks
+
+Remove decon mark from all buildables
+===============
+*/
+void G_ClearDeconMarks( void )
+{
+ int i;
+ gentity_t *ent;
+
+ for( i = MAX_CLIENTS, ent = g_entities + i ; i < level.num_entities ; i++, ent++ )
+ {
+ if( !ent->inuse )
+ continue;
+
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
+
+ ent->deconstruct = qfalse;
+ }
+}
+
+/*
+===============
G_FreeMarkedBuildables
Free up build points for a team by deconstructing marked buildables
===============
*/
-void G_FreeMarkedBuildables( void )
+void G_FreeMarkedBuildables( gentity_t *deconner, char *readable, int rsize,
+ char *nums, int nsize )
{
int i;
+ int bNum;
+ int listItems = 0;
+ int totalListItems = 0;
gentity_t *ent;
- buildHistory_t *new, *last;
- last = level.buildHistory;
+ int removalCounts[ BA_NUM_BUILDABLES ] = {0};
+
+ if( readable && rsize )
+ readable[ 0 ] = '\0';
+ if( nums && nsize )
+ nums[ 0 ] = '\0';
if( !g_markDeconstruct.integer )
return; // Not enabled, can't deconstruct anything
@@ -2937,24 +3015,43 @@ void G_FreeMarkedBuildables( void )
for( i = 0; i < level.numBuildablesForRemoval; i++ )
{
ent = level.markedBuildables[ i ];
+ bNum = BG_Buildable( ent->s.modelindex )->number;
+
+ if( removalCounts[ bNum ] == 0 )
+ totalListItems++;
- new = G_Alloc( sizeof( buildHistory_t ) );
- new->ID = -1;
- new->ent = NULL;
- Q_strncpyz( new->name, "<markdecon>", 12 );
- new->buildable = ent->s.modelindex;
- VectorCopy( ent->s.pos.trBase, new->origin );
- VectorCopy( ent->s.angles, new->angles );
- VectorCopy( ent->s.origin2, new->origin2 );
- VectorCopy( ent->s.angles2, new->angles2 );
- new->fate = BF_DECONNED;
- new->next = NULL;
- new->marked = NULL;
-
- last = last->marked = new;
+ G_Damage( ent, NULL, deconner, NULL, NULL, ent->health, 0, MOD_REPLACE );
+ removalCounts[ bNum ]++;
+
+ if( nums )
+ Q_strcat( nums, nsize, va( " %d", (int)( ent - g_entities ) ) );
+
+ G_RemoveRangeMarkerFrom( ent );
G_FreeEntity( ent );
}
+
+ if( !readable )
+ return;
+
+ for( i = 0; i < BA_NUM_BUILDABLES; i++ )
+ {
+ if( removalCounts[ i ] )
+ {
+ if( listItems )
+ {
+ if( listItems == ( totalListItems - 1 ) )
+ Q_strcat( readable, rsize, va( "%s and ",
+ ( totalListItems > 2 ) ? "," : "" ) );
+ else
+ Q_strcat( readable, rsize, ", " );
+ }
+ Q_strcat( readable, rsize, va( "%s", BG_Buildable( i )->humanName ) );
+ if( removalCounts[ i ] > 1 )
+ Q_strcat( readable, rsize, va( " (%dx)", removalCounts[ i ] ) );
+ listItems++;
+ }
+ }
}
/*
@@ -2962,20 +3059,20 @@ void G_FreeMarkedBuildables( void )
G_SufficientBPAvailable
Determine if enough build points can be released for the buildable
-and list the buildables that much be destroyed if this is the case
+and list the buildables that must be destroyed if this is the case
===============
*/
static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
vec3_t origin )
{
- int i;
- int numBuildables = 0;
- int pointsYielded = 0;
- gentity_t *ent;
- qboolean unique = BG_FindUniqueTestForBuildable( buildable );
- int remainingBP, remainingSpawns;
- int team;
- int buildPoints, buildpointsneeded;
+ int i;
+ int numBuildables = 0;
+ int numRequired = 0;
+ int pointsYielded = 0;
+ gentity_t *ent;
+ team_t team = BG_Buildable( buildable )->team;
+ int buildPoints = BG_Buildable( buildable )->buildPoints;
+ int remainingBP, remainingSpawns;
qboolean collision = qfalse;
int collisionCount = 0;
qboolean repeaterInRange = qfalse;
@@ -2984,29 +3081,35 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
buildable_t spawn;
buildable_t core;
int spawnCount = 0;
+ qboolean changed = qtrue;
level.numBuildablesForRemoval = 0;
- buildPoints = buildpointsneeded = BG_FindBuildPointsForBuildable( buildable );
- team = BG_FindTeamForBuildable( buildable );
- if( team == BIT_ALIENS )
+ if( team == TEAM_ALIENS )
{
- remainingBP = level.alienBuildPoints;
+ remainingBP = G_GetBuildPoints( origin, team );
remainingSpawns = level.numAlienSpawns;
- bpError = IBE_NOASSERT;
+ bpError = IBE_NOALIENBP;
spawn = BA_A_SPAWN;
core = BA_A_OVERMIND;
}
- else if( team == BIT_HUMANS )
+ else if( team == TEAM_HUMANS )
{
- remainingBP = level.humanBuildPoints;
+ if( buildable == BA_H_REACTOR || buildable == BA_H_REPEATER )
+ remainingBP = level.humanBuildPoints;
+ else
+ remainingBP = G_GetBuildPoints( origin, team );
+
remainingSpawns = level.numHumanSpawns;
- bpError = IBE_NOPOWER;
+ bpError = IBE_NOHUMANBP;
spawn = BA_H_SPAWN;
core = BA_H_REACTOR;
}
else
+ {
+ Com_Error( ERR_FATAL, "team is %d", team );
return IBE_NONE;
+ }
// Simple non-marking case
if( !g_markDeconstruct.integer )
@@ -3020,18 +3123,15 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
if( ent->s.eType != ET_BUILDABLE )
continue;
- if( G_BuildablesIntersect( buildable, origin, ent->s.modelindex, ent->s.origin ) )
+ if( G_BuildablesIntersect( buildable, origin, ent->s.modelindex, ent->r.currentOrigin ) )
return IBE_NOROOM;
}
return IBE_NONE;
}
- buildpointsneeded -= remainingBP;
-
// Set buildPoints to the number extra that are required
- if( !g_markDeconstructMode.integer )
- buildPoints -= remainingBP;
+ buildPoints -= remainingBP;
// Build a list of buildable entities
for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
@@ -3039,15 +3139,27 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
if( ent->s.eType != ET_BUILDABLE )
continue;
- collision = G_BuildablesIntersect( buildable, origin, ent->s.modelindex, ent->s.origin );
+ collision = G_BuildablesIntersect( buildable, origin, ent->s.modelindex, ent->r.currentOrigin );
if( collision )
+ {
+ // Don't allow replacements at all
+ if( g_markDeconstruct.integer == 1 )
+ return IBE_NOROOM;
+
+ // Only allow replacements of the same type
+ if( g_markDeconstruct.integer == 2 && ent->s.modelindex != buildable )
+ return IBE_NOROOM;
+
+ // Any other setting means anything goes
+
collisionCount++;
+ }
// Check if this is a repeater and it's in range
if( buildable == BA_H_REPEATER &&
buildable == ent->s.modelindex &&
- Distance( ent->s.origin, origin ) < REPEATER_BASESIZE )
+ Distance( ent->r.currentOrigin, origin ) < REPEATER_BASESIZE )
{
repeaterInRange = qtrue;
repeaterInRangeCount++;
@@ -3055,55 +3167,76 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
else
repeaterInRange = qfalse;
+ // Don't allow marked buildables to be replaced in another zone,
+ // unless the marked buildable isn't in a zone (and thus unpowered)
+ if( team == TEAM_HUMANS &&
+ buildable != BA_H_REACTOR &&
+ buildable != BA_H_REPEATER &&
+ ent->parentNode != G_PowerEntityForPoint( origin ) )
+ continue;
+
if( !ent->inuse )
continue;
if( ent->health <= 0 )
continue;
- if( ent->biteam != team )
+ if( ent->buildableTeam != team )
continue;
- // Don't allow destruction of hovel with granger inside
- if( ent->s.modelindex == BA_A_HOVEL && ent->active )
- {
- if( buildable == BA_A_HOVEL )
- return IBE_HOVEL;
- else
- continue;
- }
-
// Explicitly disallow replacement of the core buildable with anything
// other than the core buildable
if( ent->s.modelindex == core && buildable != core )
continue;
+ // Don't allow a power source to be replaced by a dependant
+ if( team == TEAM_HUMANS &&
+ G_PowerEntityForPoint( origin ) == ent &&
+ buildable != BA_H_REPEATER &&
+ buildable != core )
+ continue;
+
+ // Don't include unpowered buildables
+ if( !collision && !ent->powered )
+ continue;
+
if( ent->deconstruct )
{
level.markedBuildables[ numBuildables++ ] = ent;
+ // Buildables that are marked here will always end up at the front of the
+ // removal list, so just incrementing numBuildablesForRemoval is sufficient
if( collision || repeaterInRange )
{
+ // Collided with something, so we definitely have to remove it or
+ // it's a repeater that intersects the new repeater's power area,
+ // so it must be removed
+
if( collision )
collisionCount--;
if( repeaterInRange )
repeaterInRangeCount--;
- pointsYielded += BG_FindBuildPointsForBuildable( ent->s.modelindex );
+ if( ent->powered )
+ pointsYielded += BG_Buildable( ent->s.modelindex )->buildPoints;
level.numBuildablesForRemoval++;
}
- else if( unique && ent->s.modelindex == buildable )
+ else if( BG_Buildable( ent->s.modelindex )->uniqueTest &&
+ ent->s.modelindex == buildable )
{
// If it's a unique buildable, it must be replaced by the same type
- pointsYielded += BG_FindBuildPointsForBuildable( ent->s.modelindex );
+ if( ent->powered )
+ pointsYielded += BG_Buildable( ent->s.modelindex )->buildPoints;
level.numBuildablesForRemoval++;
}
}
}
+ numRequired = level.numBuildablesForRemoval;
+
// We still need build points, but have no candidates for removal
- if( buildpointsneeded > 0 && numBuildables == 0 )
+ if( buildPoints > 0 && numBuildables == 0 )
return bpError;
// Collided with something we can't remove
@@ -3112,7 +3245,7 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
// There are one or more repeaters we can't remove
if( repeaterInRangeCount > 0 )
- return IBE_RPTWARN2;
+ return IBE_RPTPOWERHERE;
// Sort the list
cmpBuildable = buildable;
@@ -3125,23 +3258,50 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
level.numBuildablesForRemoval++ )
{
ent = level.markedBuildables[ level.numBuildablesForRemoval ];
- pointsYielded += BG_FindBuildPointsForBuildable( ent->s.modelindex );
+ if( ent->powered )
+ pointsYielded += BG_Buildable( ent->s.modelindex )->buildPoints;
+ }
+
+ // Do another pass to see if we can meet quota with fewer buildables
+ // than we have now due to mismatches between priority and BP amounts
+ // by repeatedly testing if we can chop off the first thing that isn't
+ // required by rules of collision/uniqueness, which are always at the head
+ while( changed && level.numBuildablesForRemoval > 1 &&
+ level.numBuildablesForRemoval > numRequired )
+ {
+ int pointsUnYielded = 0;
+ changed = qfalse;
+ ent = level.markedBuildables[ numRequired ];
+ if( ent->powered )
+ pointsUnYielded = BG_Buildable( ent->s.modelindex )->buildPoints;
+
+ if( pointsYielded - pointsUnYielded >= buildPoints )
+ {
+ pointsYielded -= pointsUnYielded;
+ memmove( &level.markedBuildables[ numRequired ],
+ &level.markedBuildables[ numRequired + 1 ],
+ ( level.numBuildablesForRemoval - numRequired )
+ * sizeof( gentity_t * ) );
+ level.numBuildablesForRemoval--;
+ changed = qtrue;
+ }
}
- // Make sure we're not removing the last spawn
for( i = 0; i < level.numBuildablesForRemoval; i++ )
{
if( level.markedBuildables[ i ]->s.modelindex == spawn )
spawnCount++;
}
+
+ // Make sure we're not removing the last spawn
if( !g_cheats.integer && remainingSpawns > 0 && ( remainingSpawns - spawnCount ) < 1 )
- return IBE_NORMAL;
+ return IBE_LASTSPAWN;
// Not enough points yielded
- if( pointsYielded < buildpointsneeded )
+ if( pointsYielded < buildPoints )
return bpError;
-
- return IBE_NONE;
+ else
+ return IBE_NONE;
}
/*
@@ -3190,39 +3350,34 @@ G_CanBuild
Checks to see if a buildable can be built
================
*/
-itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance, vec3_t origin )
+itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance,
+ vec3_t origin, vec3_t normal, int *groundEntNum )
{
vec3_t angles;
- vec3_t entity_origin, normal;
- vec3_t mins, maxs, nbmins, nbmaxs;
- vec3_t nbVect;
+ vec3_t entity_origin;
+ vec3_t mins, maxs;
trace_t tr1, tr2, tr3;
- int i;
- itemBuildError_t reason = IBE_NONE;
+ itemBuildError_t reason = IBE_NONE, tempReason;
gentity_t *tempent;
float minNormal;
qboolean invert;
int contents;
playerState_t *ps = &ent->client->ps;
- int buildPoints;
- gentity_t *tmp;
- itemBuildError_t tempReason;
// Stop all buildables from interacting with traces
G_SetBuildableLinkState( qfalse );
- BG_FindBBoxForBuildable( buildable, mins, maxs );
+ BG_BuildableBoundingBox( buildable, mins, maxs );
BG_PositionBuildableRelativeToPlayer( ps, mins, maxs, trap_Trace, entity_origin, angles, &tr1 );
-
trap_Trace( &tr2, entity_origin, mins, maxs, entity_origin, ent->s.number, MASK_PLAYERSOLID );
trap_Trace( &tr3, ps->origin, NULL, NULL, entity_origin, ent->s.number, MASK_PLAYERSOLID );
VectorCopy( entity_origin, origin );
-
+ *groundEntNum = tr1.entityNum;
VectorCopy( tr1.plane.normal, normal );
- minNormal = BG_FindMinNormalForBuildable( buildable );
- invert = BG_FindInvertNormalForBuildable( buildable );
+ minNormal = BG_Buildable( buildable )->minNormal;
+ invert = BG_Buildable( buildable )->invertNormal;
//can we build at this angle?
if( !( normal[ 2 ] >= minNormal || ( invert && normal[ 2 ] <= -minNormal ) ) )
@@ -3232,174 +3387,93 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
reason = IBE_NORMAL;
contents = trap_PointContents( entity_origin, -1 );
- buildPoints = BG_FindBuildPointsForBuildable( buildable );
-
- //check if we are near a nobuild marker, if so, can't build here...
- for( i = 0; i < MAX_GENTITIES; i++ )
- {
- tmp = &g_entities[ i ];
-
- if( !tmp->noBuild.isNB )
- continue;
-
- nbVect[0] = tmp->noBuild.Area;
- nbVect[1] = tmp->noBuild.Area;
- nbVect[2] = tmp->noBuild.Height;
-
- VectorSubtract( origin, nbVect, nbmins );
- VectorAdd( origin, nbVect, nbmaxs );
-
- if( trap_EntityContact( nbmins, nbmaxs, tmp ) )
- reason = IBE_PERMISSION;
-
- }
- if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+
+ if( ( tempReason = G_SufficientBPAvailable( buildable, origin ) ) != IBE_NONE )
+ reason = tempReason;
+
+ if( ent->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
//alien criteria
- if( buildable == BA_A_HOVEL )
+ // Check there is an Overmind
+ if( buildable != BA_A_OVERMIND )
{
- vec3_t builderMins, builderMaxs;
-
- //this assumes the adv builder is the biggest thing that'll use the hovel
- BG_FindBBoxForClass( PCL_ALIEN_BUILDER0_UPG, builderMins, builderMaxs, NULL, NULL, NULL );
-
- if( APropHovel_Blocked( origin, angles, normal, ent ) )
- reason = IBE_HOVELEXIT;
+ if( !G_Overmind( ) )
+ reason = IBE_NOOVERMIND;
}
//check there is creep near by for building on
- if( BG_FindCreepTestForBuildable( buildable ) )
+ if( BG_Buildable( buildable )->creepTest )
{
if( !G_IsCreepHere( entity_origin ) )
reason = IBE_NOCREEP;
}
- //check permission to build here
- if( tr1.surfaceFlags & SURF_NOALIENBUILD || tr1.surfaceFlags & SURF_NOBUILD ||
- contents & CONTENTS_NOALIENBUILD || contents & CONTENTS_NOBUILD )
+ // Check permission to build here
+ if( tr1.surfaceFlags & SURF_NOALIENBUILD || contents & CONTENTS_NOALIENBUILD )
reason = IBE_PERMISSION;
-
- //look for an Overmind
- for ( i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ )
- {
- if( tempent->s.eType != ET_BUILDABLE )
- continue;
- if( tempent->s.modelindex == BA_A_OVERMIND && tempent->spawned &&
- tempent->health > 0 )
- break;
- }
-
- //if none found...
- if( i >= level.num_entities && buildable != BA_A_OVERMIND )
- reason = IBE_NOOVERMIND;
-
- //can we only have one of these?
- if( BG_FindUniqueTestForBuildable( buildable ) )
- {
- for ( i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ )
- {
- if( tempent->s.eType != ET_BUILDABLE )
- continue;
-
- if( tempent->s.modelindex == buildable && !tempent->deconstruct )
- {
- switch( buildable )
- {
- case BA_A_OVERMIND:
- reason = IBE_OVERMIND;
- break;
-
- case BA_A_HOVEL:
- reason = IBE_HOVEL;
- break;
-
- default:
- Com_Error( ERR_FATAL, "No reason for denying build of %d\n", buildable );
- break;
- }
-
- break;
- }
- }
- }
}
- else if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ else if( ent->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
//human criteria
- if( !G_IsPowered( entity_origin ) )
+
+ // Check for power
+ if( G_IsPowered( entity_origin ) == BA_NONE )
{
//tell player to build a repeater to provide power
if( buildable != BA_H_REACTOR && buildable != BA_H_REPEATER )
- reason = IBE_REPEATER;
+ reason = IBE_NOPOWERHERE;
}
//this buildable requires a DCC
- if( BG_FindDCCTestForBuildable( buildable ) && !G_IsDCCBuilt( ) )
+ if( BG_Buildable( buildable )->dccTest && !G_IsDCCBuilt( ) )
reason = IBE_NODCC;
//check that there is a parent reactor when building a repeater
if( buildable == BA_H_REPEATER )
{
- for ( i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ )
- {
- if( tempent->s.eType != ET_BUILDABLE )
- continue;
-
- if( tempent->s.modelindex == BA_H_REACTOR )
- break;
- }
-
- if( i >= level.num_entities )
- {
- //no reactor present
-
- //check for other nearby repeaters
- for ( i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ )
- {
- if( tempent->s.eType != ET_BUILDABLE )
- continue;
-
- if( tempent->s.modelindex == BA_H_REPEATER &&
- Distance( tempent->s.origin, entity_origin ) < REPEATER_BASESIZE )
- {
- reason = IBE_RPTWARN2;
- break;
- }
- }
-
- if( reason == IBE_NONE )
- reason = IBE_RPTWARN;
- }
- else if( G_IsPowered( entity_origin ) )
- reason = IBE_RPTWARN2;
+ tempent = G_Reactor( );
+
+ if( tempent == NULL ) // No reactor
+ reason = IBE_RPTNOREAC;
+ else if( g_markDeconstruct.integer && G_IsPowered( entity_origin ) == BA_H_REACTOR )
+ reason = IBE_RPTPOWERHERE;
+ else if( !g_markDeconstruct.integer && G_IsPowered( entity_origin ) )
+ reason = IBE_RPTPOWERHERE;
}
- //check permission to build here
- if( tr1.surfaceFlags & SURF_NOHUMANBUILD || tr1.surfaceFlags & SURF_NOBUILD ||
- contents & CONTENTS_NOHUMANBUILD || contents & CONTENTS_NOBUILD )
+ // Check permission to build here
+ if( tr1.surfaceFlags & SURF_NOHUMANBUILD || contents & CONTENTS_NOHUMANBUILD )
reason = IBE_PERMISSION;
+ }
+
+ // Check permission to build here
+ if( tr1.surfaceFlags & SURF_NOBUILD || contents & CONTENTS_NOBUILD )
+ reason = IBE_PERMISSION;
- //can we only build one of these?
- if( BG_FindUniqueTestForBuildable( buildable ) )
+ // Can we only have one of these?
+ if( BG_Buildable( buildable )->uniqueTest )
+ {
+ tempent = G_FindBuildable( buildable );
+ if( tempent && !tempent->deconstruct )
{
- for ( i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ )
+ switch( buildable )
{
- if( tempent->s.eType != ET_BUILDABLE )
- continue;
+ case BA_A_OVERMIND:
+ reason = IBE_ONEOVERMIND;
+ break;
- if( tempent->s.modelindex == BA_H_REACTOR && !tempent->deconstruct )
- {
- reason = IBE_REACTOR;
+ case BA_H_REACTOR:
+ reason = IBE_ONEREACTOR;
+ break;
+
+ default:
+ Com_Error( ERR_FATAL, "No reason for denying build of %d", buildable );
break;
- }
}
}
}
- if( ( tempReason = G_SufficientBPAvailable( buildable, origin ) ) != IBE_NONE )
- reason = tempReason;
-
// Relink buildables
G_SetBuildableLinkState( qtrue );
@@ -3413,8 +3487,8 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
}
//this item does not fit here
- if( reason == IBE_NONE && ( tr2.fraction < 1.0 || tr3.fraction < 1.0 ) )
- return IBE_NOROOM;
+ if( reason == IBE_NONE && ( tr2.fraction < 1.0f || tr3.fraction < 1.0f ) )
+ reason = IBE_NOROOM;
if( reason != IBE_NONE )
level.numBuildablesForRemoval = 0;
@@ -3422,28 +3496,55 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
return reason;
}
+
/*
-==============
-G_BuildingExists
-==============
+================
+G_AddRangeMarkerForBuildable
+================
*/
-qboolean G_BuildingExists( int bclass )
+static void G_AddRangeMarkerForBuildable( gentity_t *self )
{
- int i;
- gentity_t *tempent;
- //look for an Armoury
- for (i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ )
+ gentity_t *rm;
+
+ switch( self->s.modelindex )
{
- if( tempent->s.eType != ET_BUILDABLE )
- continue;
- if( tempent->s.modelindex == bclass && tempent->health > 0 )
- {
- return qtrue;
- }
+ case BA_A_SPAWN:
+ case BA_A_OVERMIND:
+ case BA_A_ACIDTUBE:
+ case BA_A_TRAPPER:
+ case BA_A_HIVE:
+ case BA_H_MGTURRET:
+ case BA_H_TESLAGEN:
+ case BA_H_DCC:
+ case BA_H_REACTOR:
+ case BA_H_REPEATER:
+ break;
+ default:
+ return;
}
- return qfalse;
+
+ rm = G_Spawn();
+ rm->classname = "buildablerangemarker";
+ rm->r.svFlags = SVF_BROADCAST | SVF_CLIENTMASK;
+ rm->s.eType = ET_RANGE_MARKER;
+ rm->s.modelindex = self->s.modelindex;
+
+ self->rangeMarker = rm;
}
+/*
+================
+G_RemoveRangeMarkerFrom
+================
+*/
+void G_RemoveRangeMarkerFrom( gentity_t *self )
+{
+ if( self->rangeMarker )
+ {
+ G_FreeEntity( self->rangeMarker );
+ self->rangeMarker = NULL;
+ }
+}
/*
================
@@ -3452,142 +3553,105 @@ G_Build
Spawns a buildable
================
*/
-static gentity_t *G_Build( gentity_t *builder, buildable_t buildable, vec3_t origin, vec3_t angles )
+static gentity_t *G_Build( gentity_t *builder, buildable_t buildable,
+ const vec3_t origin, const vec3_t normal, const vec3_t angles, int groundEntNum )
{
gentity_t *built;
- buildHistory_t *new;
- vec3_t normal;
-
- // initialise the buildhistory so other functions can use it
- if( builder && builder->client )
- {
- new = G_Alloc( sizeof( buildHistory_t ) );
- G_LogBuild( new );
- }
-
- // Free existing buildables
- G_FreeMarkedBuildables( );
-
- //spawn the buildable
- built = G_Spawn();
-
- built->s.eType = ET_BUILDABLE;
-
- built->classname = BG_FindEntityNameForBuildable( buildable );
+ char readable[ MAX_STRING_CHARS ];
+ char buildnums[ MAX_STRING_CHARS ];
+ buildLog_t *log;
- built->s.modelindex = buildable; //so we can tell what this is on the client side
- built->biteam = built->s.modelindex2 = BG_FindTeamForBuildable( buildable );
-
- BG_FindBBoxForBuildable( buildable, built->r.mins, built->r.maxs );
+ if( builder->client )
+ log = G_BuildLogNew( builder, BF_CONSTRUCT );
+ else
+ log = NULL;
- // detect the buildable's normal vector
- if( !builder->client )
- {
- // initial base layout created by server
+ // Free existing buildables
+ G_FreeMarkedBuildables( builder, readable, sizeof( readable ),
+ buildnums, sizeof( buildnums ) );
- if( builder->s.origin2[ 0 ]
- || builder->s.origin2[ 1 ]
- || builder->s.origin2[ 2 ] )
- {
- VectorCopy( builder->s.origin2, normal );
- }
- else if( BG_FindTrajectoryForBuildable( buildable ) == TR_BUOYANCY )
- VectorSet( normal, 0.0f, 0.0f, -1.0f );
- else
- VectorSet( normal, 0.0f, 0.0f, 1.0f );
- }
- else
+ if( builder->client )
{
- // in-game building by a player
-
- if( builder->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING )
- {
- if( builder->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- VectorSet( normal, 0.0f, 0.0f, -1.0f );
- else
- VectorCopy( builder->client->ps.grapplePoint, normal );
- }
- else
- VectorSet( normal, 0.0f, 0.0f, 1.0f );
+ // Spawn the buildable
+ built = G_Spawn();
}
+ else
+ built = builder;
- // when building the initial layout, spawn the entity slightly off its
- // target surface so that it can be "dropped" onto it
- if( !builder->client )
- VectorMA( origin, 1.0f, normal, origin );
+ built->s.eType = ET_BUILDABLE;
+ built->killedBy = ENTITYNUM_NONE;
+ built->classname = BG_Buildable( buildable )->entityName;
+ built->s.modelindex = buildable;
+ built->buildableTeam = built->s.modelindex2 = BG_Buildable( buildable )->team;
+ BG_BuildableBoundingBox( buildable, built->r.mins, built->r.maxs );
built->health = 1;
- built->splashDamage = BG_FindSplashDamageForBuildable( buildable );
- built->splashRadius = BG_FindSplashRadiusForBuildable( buildable );
- built->splashMethodOfDeath = BG_FindMODForBuildable( buildable );
+ built->splashDamage = BG_Buildable( buildable )->splashDamage;
+ built->splashRadius = BG_Buildable( buildable )->splashRadius;
+ built->splashMethodOfDeath = BG_Buildable( buildable )->meansOfDeath;
- built->nextthink = BG_FindNextThinkForBuildable( buildable );
+ built->nextthink = BG_Buildable( buildable )->nextthink;
built->takedamage = qtrue;
built->spawned = qfalse;
built->buildTime = built->s.time = level.time;
- built->spawnBlockTime = 0;
// build instantly in cheat mode
if( builder->client && g_cheats.integer )
{
- built->health = BG_FindHealthForBuildable( buildable );
+ built->health = BG_Buildable( buildable )->health;
built->buildTime = built->s.time =
- level.time - BG_FindBuildTimeForBuildable( buildable );
+ level.time - BG_Buildable( buildable )->buildTime;
}
//things that vary for each buildable that aren't in the dbase
switch( buildable )
{
case BA_A_SPAWN:
- built->die = ASpawn_Die;
+ built->die = AGeneric_Die;
built->think = ASpawn_Think;
- built->pain = ASpawn_Pain;
+ built->pain = AGeneric_Pain;
break;
case BA_A_BARRICADE:
built->die = ABarricade_Die;
built->think = ABarricade_Think;
built->pain = ABarricade_Pain;
+ built->touch = ABarricade_Touch;
+ built->shrunkTime = 0;
+ ABarricade_Shrink( built, qtrue );
break;
case BA_A_BOOSTER:
- built->die = ABarricade_Die;
- built->think = ABarricade_Think;
- built->pain = ABarricade_Pain;
+ built->die = AGeneric_Die;
+ built->think = AGeneric_Think;
+ built->pain = AGeneric_Pain;
built->touch = ABooster_Touch;
break;
case BA_A_ACIDTUBE:
- built->die = ABarricade_Die;
+ built->die = AGeneric_Die;
built->think = AAcidTube_Think;
- built->pain = ASpawn_Pain;
+ built->pain = AGeneric_Pain;
break;
case BA_A_HIVE:
- built->die = ABarricade_Die;
+ built->die = AGeneric_Die;
built->think = AHive_Think;
- built->pain = ASpawn_Pain;
+ built->pain = AHive_Pain;
break;
case BA_A_TRAPPER:
- built->die = ABarricade_Die;
+ built->die = AGeneric_Die;
built->think = ATrapper_Think;
- built->pain = ASpawn_Pain;
+ built->pain = AGeneric_Pain;
break;
case BA_A_OVERMIND:
- built->die = ASpawn_Die;
+ built->die = AGeneric_Die;
built->think = AOvermind_Think;
- built->pain = ASpawn_Pain;
- break;
-
- case BA_A_HOVEL:
- built->die = AHovel_Die;
- built->use = AHovel_Use;
- built->think = AHovel_Think;
- built->pain = ASpawn_Pain;
+ built->pain = AGeneric_Pain;
break;
case BA_H_SPAWN:
@@ -3618,7 +3682,7 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable, vec3_t ori
case BA_H_MEDISTAT:
built->think = HMedistat_Think;
- built->die = HSpawn_Die;
+ built->die = HMedistat_Die;
break;
case BA_H_REACTOR:
@@ -3626,12 +3690,11 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable, vec3_t ori
built->die = HSpawn_Die;
built->use = HRepeater_Use;
built->powered = built->active = qtrue;
- built->pain = HReactor_Pain;
break;
case BA_H_REPEATER:
built->think = HRepeater_Think;
- built->die = HSpawn_Die;
+ built->die = HRepeater_Die;
built->use = HRepeater_Use;
built->count = -1;
break;
@@ -3641,152 +3704,91 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable, vec3_t ori
break;
}
- built->s.number = built - g_entities;
built->r.contents = CONTENTS_BODY;
built->clipmask = MASK_PLAYERSOLID;
built->enemy = NULL;
- built->s.weapon = BG_FindProjTypeForBuildable( buildable );
+ built->s.weapon = BG_Buildable( buildable )->turretProjType;
if( builder->client )
- {
- built->builtBy = builder->client->ps.clientNum;
-
- if( builder->client->pers.designatedBuilder )
- {
- built->s.eFlags |= EF_DBUILDER; // designated builder protection
- }
- }
+ built->builtBy = builder->client->pers.namelog;
+ else if( builder->builtBy )
+ built->builtBy = builder->builtBy;
else
- built->builtBy = -1;
+ built->builtBy = NULL;
G_SetOrigin( built, origin );
-
- // gently nudge the buildable onto the surface :)
- VectorScale( normal, -50.0f, built->s.pos.trDelta );
// set turret angles
VectorCopy( builder->s.angles2, built->s.angles2 );
- VectorCopy( angles, built->s.angles );
- built->s.angles[ PITCH ] = 0.0f;
+ VectorCopy( angles, built->s.apos.trBase );
+ VectorCopy( angles, built->r.currentAngles );
+ built->s.apos.trBase[ PITCH ] = 0.0f;
+ built->r.currentAngles[ PITCH ] = 0.0f;
built->s.angles2[ YAW ] = angles[ YAW ];
- built->s.pos.trType = BG_FindTrajectoryForBuildable( buildable );
- built->s.pos.trTime = level.time;
- built->physicsBounce = BG_FindBounceForBuildable( buildable );
- built->s.groundEntityNum = -1;
+ built->s.angles2[ PITCH ] = MGTURRET_VERTICALCAP;
+ built->physicsBounce = BG_Buildable( buildable )->bounce;
- built->s.generic1 = (int)( ( (float)built->health /
- (float)BG_FindHealthForBuildable( buildable ) ) * B_HEALTH_MASK );
+ built->s.groundEntityNum = groundEntNum;
+ if( groundEntNum == ENTITYNUM_NONE )
+ {
+ built->s.pos.trType = BG_Buildable( buildable )->traj;
+ built->s.pos.trTime = level.time;
+ // gently nudge the buildable onto the surface :)
+ VectorScale( normal, -50.0f, built->s.pos.trDelta );
+ }
- if( built->s.generic1 < 0 )
- built->s.generic1 = 0;
+ built->s.misc = MAX( built->health, 0 );
- if( BG_FindTeamForBuildable( built->s.modelindex ) == PTE_ALIENS )
+ if( BG_Buildable( buildable )->team == TEAM_ALIENS )
{
built->powered = qtrue;
- built->s.generic1 |= B_POWERED_TOGGLEBIT;
+ built->s.eFlags |= EF_B_POWERED;
}
- else if( ( built->powered = G_FindPower( built ) ) )
- built->s.generic1 |= B_POWERED_TOGGLEBIT;
+ else if( ( built->powered = G_FindPower( built, qfalse ) ) )
+ built->s.eFlags |= EF_B_POWERED;
- if( ( built->dcced = G_FindDCC( built ) ) )
- built->s.generic1 |= B_DCCED_TOGGLEBIT;
-
- built->s.generic1 &= ~B_SPAWNED_TOGGLEBIT;
+ built->s.eFlags &= ~EF_B_SPAWNED;
VectorCopy( normal, built->s.origin2 );
G_AddEvent( built, EV_BUILD_CONSTRUCT, 0 );
- G_SetIdleBuildableAnim( built, BG_FindAnimForBuildable( buildable ) );
+ G_SetIdleBuildableAnim( built, BG_Buildable( buildable )->idleAnim );
- if( built->builtBy >= 0 )
+ if( built->builtBy )
G_SetBuildableAnim( built, BANIM_CONSTRUCT1, qtrue );
trap_LinkEntity( built );
-
-
- if( builder->client )
+
+ if( builder && builder->client )
{
- builder->client->pers.statscounters.structsbuilt++;
- if( builder->client->pers.teamSelection == PTE_ALIENS )
- {
- level.alienStatsCounters.structsbuilt++;
- }
- else if( builder->client->pers.teamSelection == PTE_HUMANS )
- {
- level.humanStatsCounters.structsbuilt++;
- }
+ G_TeamCommand( builder->client->ps.stats[ STAT_TEAM ],
+ va( "print \"%s ^2built^7 by %s%s%s\n\"",
+ BG_Buildable( built->s.modelindex )->humanName,
+ builder->client->pers.netname,
+ ( readable[ 0 ] ) ? "^7, ^3replacing^7 " : "",
+ readable ) );
+ G_LogPrintf( "Construct: %d %d %s%s: %s" S_COLOR_WHITE " is building "
+ "%s%s%s\n",
+ (int)( builder - g_entities ),
+ (int)( built - g_entities ),
+ BG_Buildable( built->s.modelindex )->name,
+ buildnums,
+ builder->client->pers.netname,
+ BG_Buildable( built->s.modelindex )->humanName,
+ readable[ 0 ] ? ", replacing " : "",
+ readable );
}
- if( builder->client ) {
- G_TeamCommand( builder->client->pers.teamSelection,
- va( "print \"%s is ^2being built^7 by %s^7\n\"",
- BG_FindHumanNameForBuildable( built->s.modelindex ),
- builder->client->pers.netname ) );
- G_LogPrintf("Build: %i %i 0: %s^7 is ^2building^7 %s\n",
- builder->client->ps.clientNum,
- built->s.modelindex,
- builder->client->pers.netname,
- BG_FindNameForBuildable( built->s.modelindex ) );
- }
+ if( log )
+ G_BuildLogSet( log, built );
- // ok we're all done building, so what we log here should be the final values
- if( builder && builder->client ) // log ingame building only
- {
- new = level.buildHistory;
- new->ID = ( ++level.lastBuildID > 1000 ) ? ( level.lastBuildID = 1 ) : level.lastBuildID;
- new->ent = builder;
- new->name[ 0 ] = 0;
- new->buildable = buildable;
- VectorCopy( built->s.pos.trBase, new->origin );
- VectorCopy( built->s.angles, new->angles );
- VectorCopy( built->s.origin2, new->origin2 );
- VectorCopy( built->s.angles2, new->angles2 );
- new->fate = BF_BUILT;
- }
-
- if( builder && builder->client )
- built->bdnumb = new->ID;
- else
- built->bdnumb = -1;
+ G_AddRangeMarkerForBuildable( built );
return built;
}
-static void G_SpawnMarker( vec3_t origin )
-{
- gentity_t *nb;
- int i;
-
- // Make the marker...
- nb = G_Spawn( );
- nb->s.modelindex = 0; //Coder humor is win
- VectorCopy( origin, nb->s.pos.trBase );
- VectorCopy( origin, nb->r.currentOrigin );
- nb->noBuild.isNB = qtrue;
- nb->noBuild.Area = level.nbArea;
- nb->noBuild.Height = level.nbHeight;
- trap_LinkEntity( nb );
-
- // Log markers made...
- for( i = 0; i < MAX_GENTITIES; i++ )
- {
- if( level.nbMarkers[ i ].Marker != NULL )
- continue;
-
- level.nbMarkers[ i ].Marker = nb;
- VectorCopy( origin, level.nbMarkers[ i ].Origin );
- SnapVector( level.nbMarkers[ i ].Origin );
- break;
- }
-
- // End nobuild mode...
- level.noBuilding = qfalse;
- level.nbArea = 0.0f;
- level.nbHeight = 0.0f;
-}
-
/*
=================
G_BuildIfValid
@@ -3795,27 +3797,19 @@ G_BuildIfValid
qboolean G_BuildIfValid( gentity_t *ent, buildable_t buildable )
{
float dist;
- vec3_t origin;
+ vec3_t origin, normal;
+ int groundEntNum;
- dist = BG_FindBuildDistForClass( ent->client->ps.stats[ STAT_PCLASS ] );
+ dist = BG_Class( ent->client->ps.stats[ STAT_CLASS ] )->buildDist;
- switch( G_CanBuild( ent, buildable, dist, origin ) )
+ switch( G_CanBuild( ent, buildable, dist, origin, normal, &groundEntNum ) )
{
case IBE_NONE:
- if( level.noBuilding )
- {
- vec3_t mins;
- BG_FindBBoxForBuildable( buildable, mins, NULL );
- origin[2] += mins[2];
-
- G_SpawnMarker( origin );
- return qtrue;
- }
- G_Build( ent, buildable, origin, ent->s.apos.trBase );
+ G_Build( ent, buildable, origin, normal, ent->s.apos.trBase, groundEntNum );
return qtrue;
- case IBE_NOASSERT:
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_NOASSERT );
+ case IBE_NOALIENBP:
+ G_TriggerMenu( ent->client->ps.clientNum, MN_A_NOBP );
return qfalse;
case IBE_NOOVERMIND:
@@ -3826,96 +3820,44 @@ qboolean G_BuildIfValid( gentity_t *ent, buildable_t buildable )
G_TriggerMenu( ent->client->ps.clientNum, MN_A_NOCREEP );
return qfalse;
- case IBE_OVERMIND:
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_OVERMIND );
- return qfalse;
-
- case IBE_HOVEL:
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_HOVEL );
- return qfalse;
-
- case IBE_HOVELEXIT:
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_HOVEL_EXIT );
+ case IBE_ONEOVERMIND:
+ G_TriggerMenu( ent->client->ps.clientNum, MN_A_ONEOVERMIND );
return qfalse;
case IBE_NORMAL:
- if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NORMAL );
- else
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_NORMAL );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_NORMAL );
return qfalse;
case IBE_PERMISSION:
- if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NORMAL );
- else
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_NORMAL );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_NORMAL );
return qfalse;
- case IBE_REACTOR:
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_REACTOR );
+ case IBE_ONEREACTOR:
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_ONEREACTOR );
return qfalse;
- case IBE_REPEATER:
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_REPEATER );
+ case IBE_NOPOWERHERE:
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOPOWERHERE );
return qfalse;
case IBE_NOROOM:
- if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOM );
- else
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_NOROOM );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_NOROOM );
return qfalse;
- case IBE_NOPOWER:
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOPOWER );
+ case IBE_NOHUMANBP:
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOBP);
return qfalse;
case IBE_NODCC:
G_TriggerMenu( ent->client->ps.clientNum, MN_H_NODCC );
return qfalse;
- case IBE_SPWNWARN:
- if( level.noBuilding )
- {
- vec3_t mins;
- BG_FindBBoxForBuildable( buildable, mins, NULL );
- origin[2] += mins[2];
- G_SpawnMarker( origin );
- return qtrue;
- }
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_SPWNWARN );
- G_Build( ent, buildable, origin, ent->s.apos.trBase );
- return qtrue;
-
- case IBE_TNODEWARN:
- if( level.noBuilding )
- {
- vec3_t mins;
- BG_FindBBoxForBuildable( buildable, mins, NULL );
- origin[2] += mins[2];
- G_SpawnMarker( origin );
- return qtrue;
- }
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_TNODEWARN );
- G_Build( ent, buildable, origin, ent->s.apos.trBase );
- return qtrue;
-
- case IBE_RPTWARN:
- if( level.noBuilding )
- {
- vec3_t mins;
- BG_FindBBoxForBuildable( buildable, mins, NULL );
- origin[2] += mins[2];
- G_SpawnMarker( origin );
- return qtrue;
- }
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_RPTWARN );
- G_Build( ent, buildable, origin, ent->s.apos.trBase );
- return qtrue;
+ case IBE_RPTPOWERHERE:
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_RPTPOWERHERE );
+ return qfalse;
- case IBE_RPTWARN2:
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_RPTWARN2 );
+ case IBE_LASTSPAWN:
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_LASTSPAWN );
return qfalse;
default:
@@ -3933,33 +3875,41 @@ Traces down to find where an item should rest, instead of letting them
free fall from their spawn points
================
*/
-static void G_FinishSpawningBuildable( gentity_t *ent )
+static gentity_t *G_FinishSpawningBuildable( gentity_t *ent, qboolean force )
{
trace_t tr;
- vec3_t dest;
+ vec3_t normal, dest;
gentity_t *built;
buildable_t buildable = ent->s.modelindex;
- built = G_Build( ent, buildable, ent->s.pos.trBase, ent->s.angles );
- G_FreeEntity( ent );
+ if( ent->s.origin2[ 0 ] || ent->s.origin2[ 1 ] || ent->s.origin2[ 2 ] )
+ VectorCopy( ent->s.origin2, normal );
+ else if( BG_Buildable( buildable )->traj == TR_BUOYANCY )
+ VectorSet( normal, 0.0f, 0.0f, -1.0f );
+ else
+ VectorSet( normal, 0.0f, 0.0f, 1.0f );
+
+ built = G_Build( ent, buildable, ent->r.currentOrigin,
+ normal, ent->r.currentAngles, ENTITYNUM_NONE );
built->takedamage = qtrue;
built->spawned = qtrue; //map entities are already spawned
- built->health = BG_FindHealthForBuildable( buildable );
- built->s.generic1 |= B_SPAWNED_TOGGLEBIT;
+ built->health = BG_Buildable( buildable )->health;
+ built->s.eFlags |= EF_B_SPAWNED;
// drop towards normal surface
VectorScale( built->s.origin2, -4096.0f, dest );
- VectorAdd( dest, built->s.origin, dest );
+ VectorAdd( dest, built->r.currentOrigin, dest );
- trap_Trace( &tr, built->s.origin, built->r.mins, built->r.maxs, dest, built->s.number, built->clipmask );
+ trap_Trace( &tr, built->r.currentOrigin, built->r.mins, built->r.maxs, dest, built->s.number, built->clipmask );
- if( tr.startsolid )
+ if( tr.startsolid && !force )
{
G_Printf( S_COLOR_YELLOW "G_FinishSpawningBuildable: %s startsolid at %s\n",
- built->classname, vtos( built->s.origin ) );
+ built->classname, vtos( built->r.currentOrigin ) );
+ G_RemoveRangeMarkerFrom( built );
G_FreeEntity( built );
- return;
+ return NULL;
}
//point items in the correct direction
@@ -3971,6 +3921,20 @@ static void G_FinishSpawningBuildable( gentity_t *ent )
G_SetOrigin( built, tr.endpos );
trap_LinkEntity( built );
+ return built;
+}
+
+/*
+============
+G_SpawnBuildableThink
+
+Complete spawning a buildable using its placeholder
+============
+*/
+static void G_SpawnBuildableThink( gentity_t *ent )
+{
+ G_FinishSpawningBuildable( ent, qfalse );
+ G_BuildableThink( ent, 0 );
}
/*
@@ -3990,76 +3954,96 @@ void G_SpawnBuildable( gentity_t *ent, buildable_t buildable )
// some movers spawn on the second frame, so delay item
// spawns until the third frame so they can ride trains
ent->nextthink = level.time + FRAMETIME * 2;
- ent->think = G_FinishSpawningBuildable;
+ ent->think = G_SpawnBuildableThink;
+}
+
+void G_ParseCSVBuildablePlusList( const char *string, int *buildables, int buildablesSize )
+{
+ char buffer[ MAX_STRING_CHARS ];
+ int i = 0;
+ char *p, *q;
+ qboolean EOS = qfalse;
+
+ Q_strncpyz( buffer, string, MAX_STRING_CHARS );
+
+ p = q = buffer;
+
+ while( *p != '\0' && i < buildablesSize - 1 )
+ {
+ //skip to first , or EOS
+ while( *p != ',' && *p != '\0' )
+ p++;
+
+ if( *p == '\0' )
+ EOS = qtrue;
+
+ *p = '\0';
+
+ //strip leading whitespace
+ while( *q == ' ' )
+ q++;
+
+ if( !Q_stricmp( q, "alien" ) )
+ {
+ buildable_t b;
+ for( b = BA_A_SPAWN; b <= BA_A_HIVE && i < buildablesSize - 1; ++b )
+ buildables[ i++ ] = b;
+
+ if( i < buildablesSize - 1 )
+ buildables[ i++ ] = BA_NUM_BUILDABLES + TEAM_ALIENS;
+ }
+ else if( !Q_stricmp( q, "human" ) )
+ {
+ buildable_t b;
+ for( b = BA_H_SPAWN; b <= BA_H_REPEATER && i < buildablesSize - 1; ++b )
+ buildables[ i++ ] = b;
+
+ if( i < buildablesSize - 1 )
+ buildables[ i++ ] = BA_NUM_BUILDABLES + TEAM_HUMANS;
+ }
+ else if( !Q_stricmp( q, "ivo_spectator" ) )
+ buildables[ i++ ] = BA_NUM_BUILDABLES + TEAM_NONE;
+ else if( !Q_stricmp( q, "ivo_alien" ) )
+ buildables[ i++ ] = BA_NUM_BUILDABLES + TEAM_ALIENS;
+ else if( !Q_stricmp( q, "ivo_human" ) )
+ buildables[ i++ ] = BA_NUM_BUILDABLES + TEAM_HUMANS;
+ else
+ {
+ buildables[ i ] = BG_BuildableByName( q )->number;
+ if( buildables[ i ] == BA_NONE )
+ Com_Printf( S_COLOR_YELLOW "WARNING: unknown buildable or special identifier %s\n", q );
+ else
+ i++;
+ }
+
+ if( !EOS )
+ {
+ p++;
+ q = p;
+ }
+ else
+ break;
+ }
+
+ buildables[ i ] = BA_NONE;
}
- /*
- ============
- G_CheckDBProtection
-
- Count how many designated builders are in both teams and
- if none found in some team, cancel protection for all
- structures of that team
- ============
- */
-
- void G_CheckDBProtection( void )
- {
- int alienDBs = 0, humanDBs = 0, i;
- gentity_t *ent;
-
- // count designated builders
- for( i = 0, ent = g_entities + i; i < level.maxclients; i++, ent++)
- {
- if( !ent->client || ( ent->client->pers.connected != CON_CONNECTED ) )
- continue;
-
- if( ent->client->pers.designatedBuilder)
- {
- if( ent->client->pers.teamSelection == PTE_HUMANS )
- {
- humanDBs++;
- }
- else if( ent->client->pers.teamSelection == PTE_ALIENS )
- {
- alienDBs++;
- }
- }
- }
-
- // both teams have designate builders, we're done
- if( alienDBs > 0 && humanDBs > 0 )
- return;
-
- // cancel protection if needed
- for( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++)
- {
- if( ent->s.eType != ET_BUILDABLE)
- continue;
-
- if( ( !alienDBs && ent->biteam == BIT_ALIENS ) ||
- ( !humanDBs && ent->biteam == BIT_HUMANS ) )
- {
- ent->s.eFlags &= ~EF_DBUILDER;
- }
- }
- }
-
/*
============
G_LayoutSave
-
============
*/
-void G_LayoutSave( char *name )
+void G_LayoutSave( char *lstr )
{
+ char *lstrPipePtr;
+ qboolean bAllowed[ BA_NUM_BUILDABLES + NUM_TEAMS ];
char map[ MAX_QPATH ];
char fileName[ MAX_OSPATH ];
fileHandle_t f;
int len;
int i;
gentity_t *ent;
- char *s;
+ const char *s;
trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
if( !map[ 0 ] )
@@ -4067,7 +4051,22 @@ void G_LayoutSave( char *name )
G_Printf( "LayoutSave( ): no map is loaded\n" );
return;
}
- Com_sprintf( fileName, sizeof( fileName ), "layouts/%s/%s.dat", map, name );
+
+ if( ( lstrPipePtr = strchr( lstr, '|' ) ) )
+ {
+ int bList[ BA_NUM_BUILDABLES + NUM_TEAMS ];
+ *lstrPipePtr = '\0';
+ G_ParseCSVBuildablePlusList( lstr, &bList[ 0 ], sizeof( bList ) / sizeof( bList[ 0 ] ) );
+ memset( bAllowed, 0, sizeof( bAllowed ) );
+ for( i = 0; bList[ i ] != BA_NONE; i++ )
+ bAllowed[ bList[ i ] ] = qtrue;
+ *lstrPipePtr = '|';
+ lstr = lstrPipePtr + 1;
+ }
+ else
+ bAllowed[ BA_NONE ] = qtrue; // allow all
+
+ Com_sprintf( fileName, sizeof( fileName ), "layouts/%s/%s.dat", map, lstr );
len = trap_FS_FOpenFile( fileName, &f, FS_WRITE );
if( len < 0 )
@@ -4076,22 +4075,48 @@ void G_LayoutSave( char *name )
return;
}
- G_Printf("layoutsave: saving layout to %s\n", fileName );
+ G_Printf( "layoutsave: saving layout to %s\n", fileName );
for( i = MAX_CLIENTS; i < level.num_entities; i++ )
{
+ const char *name;
+
ent = &level.gentities[ i ];
- if( ent->s.eType != ET_BUILDABLE )
+ if( ent->s.eType == ET_BUILDABLE )
+ {
+ if( !bAllowed[ BA_NONE ] && !bAllowed[ ent->s.modelindex ] )
+ continue;
+ name = BG_Buildable( ent->s.modelindex )->name;
+ }
+ else if( ent->count == 1 && !strcmp( ent->classname, "info_player_intermission" ) )
+ {
+ if( !bAllowed[ BA_NONE ] && !bAllowed[ BA_NUM_BUILDABLES + TEAM_NONE ] )
+ continue;
+ name = "ivo_spectator";
+ }
+ else if( ent->count == 1 && !strcmp( ent->classname, "info_alien_intermission" ) )
+ {
+ if( !bAllowed[ BA_NONE ] && !bAllowed[ BA_NUM_BUILDABLES + TEAM_ALIENS ] )
+ continue;
+ name = "ivo_alien";
+ }
+ else if( ent->count == 1 && !strcmp( ent->classname, "info_human_intermission" ) )
+ {
+ if( !bAllowed[ BA_NONE ] && !bAllowed[ BA_NUM_BUILDABLES + TEAM_HUMANS ] )
+ continue;
+ name = "ivo_human";
+ }
+ else
continue;
- s = va( "%i %f %f %f %f %f %f %f %f %f %f %f %f\n",
- ent->s.modelindex,
- ent->s.pos.trBase[ 0 ],
- ent->s.pos.trBase[ 1 ],
- ent->s.pos.trBase[ 2 ],
- ent->s.angles[ 0 ],
- ent->s.angles[ 1 ],
- ent->s.angles[ 2 ],
+ s = va( "%s %f %f %f %f %f %f %f %f %f %f %f %f\n",
+ name,
+ ent->r.currentOrigin[ 0 ],
+ ent->r.currentOrigin[ 1 ],
+ ent->r.currentOrigin[ 2 ],
+ ent->r.currentAngles[ 0 ],
+ ent->r.currentAngles[ 1 ],
+ ent->r.currentAngles[ 2 ],
ent->s.origin2[ 0 ],
ent->s.origin2[ 1 ],
ent->s.origin2[ 2 ],
@@ -4103,6 +4128,11 @@ void G_LayoutSave( char *name )
trap_FS_FCloseFile( f );
}
+/*
+============
+G_LayoutList
+============
+*/
int G_LayoutList( const char *map, char *list, int len )
{
// up to 128 single character layout names could fit in layouts
@@ -4112,7 +4142,7 @@ int G_LayoutList( const char *map, char *list, int len )
int count = 0;
char *filePtr;
- Q_strcat( layouts, sizeof( layouts ), "*BUILTIN* " );
+ Q_strcat( layouts, sizeof( layouts ), "*BUILTIN* " );
numFiles = trap_FS_GetFileList( va( "layouts/%s", map ), ".dat",
fileList, sizeof( fileList ) );
filePtr = fileList;
@@ -4121,7 +4151,7 @@ int G_LayoutList( const char *map, char *list, int len )
fileLen = strlen( filePtr );
listLen = strlen( layouts );
if( fileLen < 5 )
- continue;
+ continue;
// list is full, stop trying to add to it
if( ( listLen + fileLen ) >= sizeof( layouts ) )
@@ -4149,27 +4179,31 @@ int G_LayoutList( const char *map, char *list, int len )
============
G_LayoutSelect
-set level.layout based on g_layouts or g_layoutAuto
+set level.layout based on g_nextLayout, g_layouts or g_layoutAuto
============
*/
void G_LayoutSelect( void )
{
- char fileName[ MAX_OSPATH ];
- char layouts[ MAX_CVAR_VALUE_STRING ];
- char layouts2[ MAX_CVAR_VALUE_STRING ];
- char *l;
+ char layouts[ ( MAX_CVAR_VALUE_STRING - 1 ) * 9 + 1 ];
+ char layouts2[ ( MAX_CVAR_VALUE_STRING - 1 ) * 9 + 1 ];
+ char *l;
char map[ MAX_QPATH ];
char *s;
int cnt = 0;
int layoutNum;
- Q_strncpyz( layouts, g_layouts.string, sizeof( layouts ) );
+ Q_strncpyz( layouts, g_nextLayout.string, sizeof( layouts ) );
+ if( !layouts[ 0 ] )
+ {
+ for( layoutNum = 0; layoutNum < 9; ++layoutNum )
+ Q_strcat( layouts, sizeof( layouts ), g_layouts[ layoutNum ].string );
+ }
trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
- // one time use cvar
- trap_Cvar_Set( "g_layouts", "" );
-
- // pick an included layout at random if no list has been provided
+ // one time use cvar
+ trap_Cvar_Set( "g_nextLayout", "" );
+
+ // pick an included layout at random if no list has been provided
if( !layouts[ 0 ] && g_layoutAuto.integer )
{
G_LayoutList( map, layouts, sizeof( layouts ) );
@@ -4181,20 +4215,13 @@ void G_LayoutSelect( void )
Q_strncpyz( layouts2, layouts, sizeof( layouts2 ) );
l = &layouts2[ 0 ];
layouts[ 0 ] = '\0';
- s = COM_ParseExt( &l, qfalse );
- while( *s )
+ while( 1 )
{
- if( !Q_stricmp( s, "*BUILTIN*" ) )
- {
- Q_strcat( layouts, sizeof( layouts ), s );
- Q_strcat( layouts, sizeof( layouts ), " " );
- cnt++;
- s = COM_ParseExt( &l, qfalse );
- continue;
- }
-
- Com_sprintf( fileName, sizeof( fileName ), "layouts/%s/%s.dat", map, s );
- if( trap_FS_FOpenFile( fileName, NULL, FS_READ ) > 0 )
+ s = COM_ParseExt( &l, qfalse );
+ if( !*s )
+ break;
+
+ if( strchr( s, '+' ) || strchr( s, '|' ) || G_LayoutExists( map, s ) )
{
Q_strcat( layouts, sizeof( layouts ), s );
Q_strcat( layouts, sizeof( layouts ), " " );
@@ -4202,7 +4229,6 @@ void G_LayoutSelect( void )
}
else
G_Printf( S_COLOR_YELLOW "WARNING: layout \"%s\" does not exist\n", s );
- s = COM_ParseExt( &l, qfalse );
}
if( !cnt )
{
@@ -4210,335 +4236,178 @@ void G_LayoutSelect( void )
"found, using map default\n" );
return;
}
- layoutNum = ( rand( ) % cnt ) + 1;
+ layoutNum = rand( ) / ( RAND_MAX / cnt + 1 ) + 1;
cnt = 0;
Q_strncpyz( layouts2, layouts, sizeof( layouts2 ) );
l = &layouts2[ 0 ];
- s = COM_ParseExt( &l, qfalse );
- while( *s )
+ while( 1 )
{
+ s = COM_ParseExt( &l, qfalse );
+ if( !*s )
+ break;
+
Q_strncpyz( level.layout, s, sizeof( level.layout ) );
cnt++;
if( cnt >= layoutNum )
break;
- s = COM_ParseExt( &l, qfalse );
}
- G_Printf("using layout \"%s\" from list ( %s)\n", level.layout, layouts );
-}
-
-static void G_LayoutBuildItem( buildable_t buildable, vec3_t origin,
- vec3_t angles, vec3_t origin2, vec3_t angles2 )
-{
- gentity_t *builder;
-
- builder = G_Spawn( );
- builder->client = 0;
- VectorCopy( origin, builder->s.pos.trBase );
- VectorCopy( angles, builder->s.angles );
- VectorCopy( origin2, builder->s.origin2 );
- VectorCopy( angles2, builder->s.angles2 );
- G_SpawnBuildable( builder, buildable );
+ G_Printf( "using layout \"%s\" from list (%s)\n", level.layout, layouts );
}
/*
============
-G_InstantBuild
-
-This function is extremely similar to the few functions that place a
-buildable on map load. It exists because G_LayoutBuildItem takes a couple
-of frames to finish spawning it, so it's not truly instant
-Do not call this function immediately after the map loads - that's what
-G_LayoutBuildItem is for.
+G_LayoutBuildItem
============
*/
-gentity_t *G_InstantBuild( buildable_t buildable, vec3_t origin, vec3_t angles, vec3_t origin2, vec3_t angles2 )
+static void G_LayoutBuildItem( buildable_t buildable, vec3_t origin,
+ vec3_t angles, vec3_t origin2, vec3_t angles2 )
{
- gentity_t *builder, *built;
- trace_t tr;
- vec3_t dest;
-
+ gentity_t *builder;
+
builder = G_Spawn( );
- builder->client = 0;
- VectorCopy( origin, builder->s.pos.trBase );
- VectorCopy( angles, builder->s.angles );
+ builder->classname = "builder";
+ VectorCopy( origin, builder->r.currentOrigin );
+ VectorCopy( angles, builder->r.currentAngles );
VectorCopy( origin2, builder->s.origin2 );
VectorCopy( angles2, builder->s.angles2 );
-//old method didn't quite work out
-//builder->s.modelindex = buildable;
-//G_FinishSpawningBuildable( builder );
-
- built = G_Build( builder, buildable, builder->s.pos.trBase, builder->s.angles );
- G_FreeEntity( builder );
-
- built->takedamage = qtrue;
- built->spawned = qtrue; //map entities are already spawned
- built->health = BG_FindHealthForBuildable( buildable );
- built->s.generic1 |= B_SPAWNED_TOGGLEBIT;
-
- // drop towards normal surface
- VectorScale( built->s.origin2, -4096.0f, dest );
- VectorAdd( dest, built->s.origin, dest );
-
- trap_Trace( &tr, built->s.origin, built->r.mins, built->r.maxs, dest, built->s.number, built->clipmask );
- if( tr.startsolid )
- {
- G_Printf( S_COLOR_YELLOW "G_FinishSpawningBuildable: %s startsolid at %s\n",
- built->classname, vtos( built->s.origin ) );
- G_FreeEntity( built );
- return NULL;
- }
-
- //point items in the correct direction
- VectorCopy( tr.plane.normal, built->s.origin2 );
-
- // allow to ride movers
- built->s.groundEntityNum = tr.entityNum;
-
- G_SetOrigin( built, tr.endpos );
-
- trap_LinkEntity( built );
- return built;
+ G_SpawnBuildable( builder, buildable );
}
-/*
-============
-G_SpawnRevertedBuildable
-
-Given a buildhistory, try to replace the lost buildable
-============
-*/
-void G_SpawnRevertedBuildable( buildHistory_t *bh, qboolean mark )
+static void G_SpawnIntermissionViewOverride( char *cn, vec3_t origin, vec3_t angles )
{
- vec3_t mins, maxs;
- int i, j, blockCount, blockers[ MAX_GENTITIES ];
- gentity_t *targ, *built, *toRecontent[ MAX_GENTITIES ];
-
- BG_FindBBoxForBuildable( bh->buildable, mins, maxs );
- VectorAdd( bh->origin, mins, mins );
- VectorAdd( bh->origin, maxs, maxs );
- blockCount = trap_EntitiesInBox( mins, maxs, blockers, MAX_GENTITIES );
- for( i = j = 0; i < blockCount; i++ )
- {
- targ = g_entities + blockers[ i ];
- if( targ->s.eType == ET_BUILDABLE )
- G_FreeEntity( targ );
- else if( targ->s.eType == ET_PLAYER )
- {
- targ->r.contents = 0; // make it intangible
- toRecontent[ j++ ] = targ; // and remember it
- }
- }
- level.numBuildablesForRemoval = 0;
- built = G_InstantBuild( bh->buildable, bh->origin, bh->angles, bh->origin2, bh->angles2 );
- if( built )
+ gentity_t *spot = G_Find( NULL, FOFS( classname ), cn );
+ if( !spot )
{
- built->r.contents = 0;
- built->think = G_CommitRevertedBuildable;
- built->nextthink = level.time;
- built->deconstruct = mark;
+ spot = G_Spawn();
+ spot->classname = cn;
}
- for( i = 0; i < j; i++ )
- toRecontent[ i ]->r.contents = CONTENTS_BODY;
-}
-
-/*
-============
-G_CommitRevertedBuildable
+ spot->count = 1;
-Check if there's anyone occupying me, and if not, become solid and operate as
-normal. Else, try to get rid of them.
-============
-*/
-void G_CommitRevertedBuildable( gentity_t *ent )
-{
- gentity_t *targ;
- int i, n, occupants[ MAX_GENTITIES ];
- vec3_t mins, maxs;
- int victims = 0;
-
- VectorAdd( ent->s.origin, ent->r.mins, mins );
- VectorAdd( ent->s.origin, ent->r.maxs, maxs );
- trap_UnlinkEntity( ent );
- n = trap_EntitiesInBox( mins, maxs, occupants, MAX_GENTITIES );
- trap_LinkEntity( ent );
-
- for( i = 0; i < n; i++ )
- {
- vec3_t gtfo;
- targ = g_entities + occupants[ i ];
- if( targ->client )
- {
- VectorSet( gtfo, crandom() * 150, crandom() * 150, random() * 150 );
- VectorAdd( targ->client->ps.velocity, gtfo, targ->client->ps.velocity );
- victims++;
- }
- }
- if( !victims )
- { // we're in the clear!
- ent->r.contents = MASK_PLAYERSOLID;
- trap_LinkEntity( ent ); // relink
- // oh dear, manual think set
- switch( ent->s.modelindex )
- {
- case BA_A_SPAWN:
- ent->think = ASpawn_Think;
- break;
- case BA_A_BARRICADE:
- case BA_A_BOOSTER:
- ent->think = ABarricade_Think;
- break;
- case BA_A_ACIDTUBE:
- ent->think = AAcidTube_Think;
- break;
- case BA_A_HIVE:
- ent->think = AHive_Think;
- break;
- case BA_A_TRAPPER:
- ent->think = ATrapper_Think;
- break;
- case BA_A_OVERMIND:
- ent->think = AOvermind_Think;
- break;
- case BA_A_HOVEL:
- ent->think = AHovel_Think;
- break;
- case BA_H_SPAWN:
- ent->think = HSpawn_Think;
- break;
- case BA_H_MGTURRET:
- ent->think = HMGTurret_Think;
- break;
- case BA_H_TESLAGEN:
- ent->think = HTeslaGen_Think;
- break;
- case BA_H_ARMOURY:
- ent->think = HArmoury_Think;
- break;
- case BA_H_DCC:
- ent->think = HDCC_Think;
- break;
- case BA_H_MEDISTAT:
- ent->think = HMedistat_Think;
- break;
- case BA_H_REACTOR:
- ent->think = HReactor_Think;
- break;
- case BA_H_REPEATER:
- ent->think = HRepeater_Think;
- break;
- }
- ent->nextthink = level.time + BG_FindNextThinkForBuildable( ent->s.modelindex );
- // oh if only everything was that simple
- return;
- }
-#define REVERT_THINK_INTERVAL 50
- ent->nextthink = level.time + REVERT_THINK_INTERVAL;
-}
-
-/*
-============
-G_RevertCanFit
-
-take a bhist and make sure you're not overwriting anything by placing it
-============
-*/
-qboolean G_RevertCanFit( buildHistory_t *bh )
-{
- int i, num, blockers[ MAX_GENTITIES ];
- vec3_t mins, maxs;
- gentity_t *targ;
- vec3_t dist;
-
- BG_FindBBoxForBuildable( bh->buildable, mins, maxs );
- VectorAdd( bh->origin, mins, mins );
- VectorAdd( bh->origin, maxs, maxs );
- num = trap_EntitiesInBox( mins, maxs, blockers, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
- {
- targ = g_entities + blockers[ i ];
- if( targ->s.eType == ET_BUILDABLE )
- {
- VectorSubtract( bh->origin, targ->s.pos.trBase, dist );
- if( targ->s.modelindex == bh->buildable && VectorLength( dist ) < 10 && targ->health <= 0 )
- continue; // it's the same buildable, hasn't blown up yet
- else
- return qfalse; // can't get rid of this one
- }
- else
- continue;
- }
- return qtrue;
+ VectorCopy( origin, spot->r.currentOrigin );
+ VectorCopy( angles, spot->r.currentAngles );
}
/*
============
G_LayoutLoad
-
-load the layout .dat file indicated by level.layout and spawn buildables
-as if a builder was creating them
============
*/
-void G_LayoutLoad( void )
+void G_LayoutLoad( char *lstr )
{
+ char *lstrPlusPtr, *lstrPipePtr;
+ qboolean bAllowed[ BA_NUM_BUILDABLES + NUM_TEAMS ];
fileHandle_t f;
int len;
- char *layout;
+ char *layout, *layoutHead;
char map[ MAX_QPATH ];
- int buildable = BA_NONE;
+ char buildName[ MAX_TOKEN_CHARS ];
+ int buildable;
vec3_t origin = { 0.0f, 0.0f, 0.0f };
vec3_t angles = { 0.0f, 0.0f, 0.0f };
vec3_t origin2 = { 0.0f, 0.0f, 0.0f };
vec3_t angles2 = { 0.0f, 0.0f, 0.0f };
char line[ MAX_STRING_CHARS ];
- int i = 0;
+ int i;
- if( !level.layout[ 0 ] || !Q_stricmp( level.layout, "*BUILTIN*" ) )
+ if( !lstr[ 0 ] || !Q_stricmp( lstr, "*BUILTIN*" ) )
return;
-
+
+ loadAnotherLayout:
+ lstrPlusPtr = strchr( lstr, '+' );
+ if( lstrPlusPtr )
+ *lstrPlusPtr = '\0';
+
+ if( ( lstrPipePtr = strchr( lstr, '|' ) ) )
+ {
+ int bList[ BA_NUM_BUILDABLES + NUM_TEAMS ];
+ *lstrPipePtr = '\0';
+ G_ParseCSVBuildablePlusList( lstr, &bList[ 0 ], sizeof( bList ) / sizeof( bList[ 0 ] ) );
+ memset( bAllowed, 0, sizeof( bAllowed ) );
+ for( i = 0; bList[ i ] != BA_NONE; i++ )
+ bAllowed[ bList[ i ] ] = qtrue;
+ *lstrPipePtr = '|';
+ lstr = lstrPipePtr + 1;
+ }
+ else
+ bAllowed[ BA_NONE ] = qtrue; // allow all
+
trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
- len = trap_FS_FOpenFile( va( "layouts/%s/%s.dat", map, level.layout ),
+ len = trap_FS_FOpenFile( va( "layouts/%s/%s.dat", map, lstr ),
&f, FS_READ );
if( len < 0 )
{
- G_Printf( "ERROR: layout %s could not be opened\n", level.layout );
+ G_Printf( "ERROR: layout %s could not be opened\n", lstr );
return;
}
- layout = G_Alloc( len + 1 );
+ layoutHead = layout = BG_Alloc( len + 1 );
trap_FS_Read( layout, len, f );
- *( layout + len ) = '\0';
+ layout[ len ] = '\0';
trap_FS_FCloseFile( f );
+ i = 0;
while( *layout )
{
if( i >= sizeof( line ) - 1 )
{
G_Printf( S_COLOR_RED "ERROR: line overflow in %s before \"%s\"\n",
- va( "layouts/%s/%s.dat", map, level.layout ), line );
- return;
+ va( "layouts/%s/%s.dat", map, lstr ), line );
+ break;
}
line[ i++ ] = *layout;
line[ i ] = '\0';
if( *layout == '\n' )
{
- i = 0;
- sscanf( line, "%d %f %f %f %f %f %f %f %f %f %f %f %f\n",
- &buildable,
+ i = 0;
+ sscanf( line, "%s %f %f %f %f %f %f %f %f %f %f %f %f\n",
+ buildName,
&origin[ 0 ], &origin[ 1 ], &origin[ 2 ],
&angles[ 0 ], &angles[ 1 ], &angles[ 2 ],
&origin2[ 0 ], &origin2[ 1 ], &origin2[ 2 ],
&angles2[ 0 ], &angles2[ 1 ], &angles2[ 2 ] );
- if( buildable > BA_NONE && buildable < BA_NUM_BUILDABLES )
- G_LayoutBuildItem( buildable, origin, angles, origin2, angles2 );
+ buildable = BG_BuildableByName( buildName )->number;
+ if( !Q_stricmp( buildName, "ivo_spectator" ) )
+ {
+ if( bAllowed[ BA_NONE ] || bAllowed[ BA_NUM_BUILDABLES + TEAM_NONE ] )
+ G_SpawnIntermissionViewOverride( "info_player_intermission", origin, angles );
+ }
+ else if( !Q_stricmp( buildName, "ivo_alien" ) )
+ {
+ if( bAllowed[ BA_NONE ] || bAllowed[ BA_NUM_BUILDABLES + TEAM_ALIENS ] )
+ G_SpawnIntermissionViewOverride( "info_alien_intermission", origin, angles );
+ }
+ else if( !Q_stricmp( buildName, "ivo_human" ) )
+ {
+ if( bAllowed[ BA_NONE ] || bAllowed[ BA_NUM_BUILDABLES + TEAM_HUMANS ] )
+ G_SpawnIntermissionViewOverride( "info_human_intermission", origin, angles );
+ }
+ else if( buildable <= BA_NONE || buildable >= BA_NUM_BUILDABLES )
+ G_Printf( S_COLOR_YELLOW "WARNING: bad buildable name (%s) in layout."
+ " skipping\n", buildName );
else
- G_Printf( S_COLOR_YELLOW "WARNING: bad buildable number (%d) in "
- " layout. skipping\n", buildable );
+ {
+ if( bAllowed[ BA_NONE ] || bAllowed[ buildable ] )
+ G_LayoutBuildItem( buildable, origin, angles, origin2, angles2 );
+ }
}
layout++;
}
+ BG_Free( layoutHead );
+
+ if( lstrPlusPtr )
+ {
+ *lstrPlusPtr = '+';
+ lstr = lstrPlusPtr + 1;
+ goto loadAnotherLayout;
+ }
}
-void G_BaseSelfDestruct( pTeam_t team )
+/*
+============
+G_BaseSelfDestruct
+============
+*/
+void G_BaseSelfDestruct( team_t team )
{
int i;
gentity_t *ent;
@@ -4550,192 +4419,274 @@ void G_BaseSelfDestruct( pTeam_t team )
continue;
if( ent->s.eType != ET_BUILDABLE )
continue;
- if( team == PTE_HUMANS && ent->biteam != BIT_HUMANS )
- continue;
- if( team == PTE_ALIENS && ent->biteam != BIT_ALIENS )
+ if( ent->buildableTeam != team )
continue;
G_Damage( ent, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
}
}
- int G_LogBuild( buildHistory_t *new )
- {
- new->next = level.buildHistory;
- level.buildHistory = new;
- return G_CountBuildLog();
- }
-
- int G_CountBuildLog( void )
- {
- buildHistory_t *ptr, *mark;
- int i = 0, overflow;
- for( ptr = level.buildHistory; ptr; ptr = ptr->next, i++ );
- if( i > g_buildLogMaxLength.integer )
- {
- for( overflow = i - g_buildLogMaxLength.integer; overflow > 0; overflow-- )
- {
- ptr = level.buildHistory;
- while( ptr->next )
- {
- if( ptr->next->next )
- ptr = ptr->next;
- else
- {
- while( ( mark = ptr->next ) )
- {
- ptr->next = ptr->next->marked;
- G_Free( mark );
- }
- }
- }
- }
- return g_buildLogMaxLength.integer;
- }
- return i;
- }
-
- char *G_FindBuildLogName( int id )
- {
- buildHistory_t *ptr;
-
- for( ptr = level.buildHistory; ptr && ptr->ID != id; ptr = ptr->next );
- if( ptr )
- {
- if( ptr->ent )
- {
- if( ptr->ent->client )
- return ptr->ent->client->pers.netname;
- }
- else if( ptr->name[ 0 ] )
- {
- return ptr->name;
- }
- }
-
- return "<buildlog entry expired>";
- }
-
/*
============
-G_NobuildLoad
-
-load the nobuild markers that were previously saved (if there are any).
+build log
============
*/
-void G_NobuildLoad( void )
+buildLog_t *G_BuildLogNew( gentity_t *actor, buildFate_t fate )
{
- fileHandle_t f;
- int len;
- char *nobuild;
- char map[ MAX_QPATH ];
- vec3_t origin = { 0.0f, 0.0f, 0.0f };
- char line[ MAX_STRING_CHARS ];
- int i = 0;
- gentity_t *nb;
- float area;
- float height;
+ buildLog_t *log = &level.buildLog[ level.buildId++ % MAX_BUILDLOG ];
+
+ if( level.numBuildLogs < MAX_BUILDLOG )
+ level.numBuildLogs++;
+ log->time = level.time;
+ log->fate = fate;
+ log->actor = actor && actor->client ? actor->client->pers.namelog : NULL;
+ return log;
+}
- trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
- len = trap_FS_FOpenFile( va( "nobuild/%s.dat", map ),
- &f, FS_READ );
- if( len < 0 )
+void G_BuildLogSet( buildLog_t *log, gentity_t *ent )
+{
+ log->modelindex = ent->s.modelindex;
+ log->deconstruct = ent->deconstruct;
+ log->deconstructTime = ent->deconstructTime;
+ log->builtBy = ent->builtBy;
+ VectorCopy( ent->r.currentOrigin, log->origin );
+ VectorCopy( ent->r.currentAngles, log->angles );
+ VectorCopy( ent->s.origin2, log->origin2 );
+ VectorCopy( ent->s.angles2, log->angles2 );
+ log->powerSource = ent->parentNode ? ent->parentNode->s.modelindex : BA_NONE;
+ log->powerValue = G_QueueValue( ent );
+}
+
+void G_BuildLogAuto( gentity_t *actor, gentity_t *buildable, buildFate_t fate )
+{
+ G_BuildLogSet( G_BuildLogNew( actor, fate ), buildable );
+}
+
+void G_BuildLogRevertThink( gentity_t *ent )
+{
+ gentity_t *built;
+ vec3_t mins, maxs;
+ int blockers[ MAX_GENTITIES ];
+ int num;
+ int victims = 0;
+ int i;
+
+ if( ent->suicideTime > 0 )
{
- // This isn't needed since nobuild is pretty much optional...
- //G_Printf( "ERROR: nobuild for %s could not be opened\n", map );
- return;
+ BG_BuildableBoundingBox( ent->s.modelindex, mins, maxs );
+ VectorAdd( ent->s.pos.trBase, mins, mins );
+ VectorAdd( ent->s.pos.trBase, maxs, maxs );
+ num = trap_EntitiesInBox( mins, maxs, blockers, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
+ {
+ gentity_t *targ;
+ vec3_t push;
+
+ targ = g_entities + blockers[ i ];
+ if( targ->client )
+ {
+ float val = ( targ->client->ps.eFlags & EF_WALLCLIMB) ? 300.0 : 150.0;
+
+ VectorSet( push, crandom() * val, crandom() * val, random() * val );
+ VectorAdd( targ->client->ps.velocity, push, targ->client->ps.velocity );
+ victims++;
+ }
+ }
+
+ ent->suicideTime--;
+
+ if( victims )
+ {
+ // still a blocker
+ ent->nextthink = level.time + FRAMETIME;
+ return;
+ }
}
- nobuild = G_Alloc( len + 1 );
- trap_FS_Read( nobuild, len, f );
- *( nobuild + len ) = '\0';
- trap_FS_FCloseFile( f );
- while( *nobuild )
+
+ built = G_FinishSpawningBuildable( ent, qtrue );
+ built->buildTime = built->s.time = 0;
+ G_KillBox( built );
+
+ G_LogPrintf( "revert: restore %d %s\n",
+ (int)( built - g_entities ), BG_Buildable( built->s.modelindex )->name );
+
+ G_BuildableThink( built, 0 );
+}
+
+void G_BuildLogRevert( int id )
+{
+ buildLog_t *log;
+ gentity_t *ent;
+ int i;
+ vec3_t dist;
+
+ level.numBuildablesForRemoval = 0;
+
+ level.numBuildLogs -= level.buildId - id;
+ while( level.buildId > id )
{
- if( i >= sizeof( line ) - 1 )
+ log = &level.buildLog[ --level.buildId % MAX_BUILDLOG ];
+ if( log->fate == BF_CONSTRUCT )
{
- return;
+ for( i = MAX_CLIENTS; i < level.num_entities; i++ )
+ {
+ ent = &g_entities[ i ];
+ if( ( ( ent->s.eType == ET_BUILDABLE &&
+ ent->health > 0 ) ||
+ ( ent->s.eType == ET_GENERAL &&
+ ent->think == G_BuildLogRevertThink ) ) &&
+ ent->s.modelindex == log->modelindex )
+ {
+ VectorSubtract( ent->s.pos.trBase, log->origin, dist );
+ if( VectorLengthSquared( dist ) <= 2.0f )
+ {
+ if( ent->s.eType == ET_BUILDABLE )
+ G_LogPrintf( "revert: remove %d %s\n",
+ (int)( ent - g_entities ), BG_Buildable( ent->s.modelindex )->name );
+ G_RemoveRangeMarkerFrom( ent );
+ G_FreeEntity( ent );
+ break;
+ }
+ }
+ }
}
-
- line[ i++ ] = *nobuild;
- line[ i ] = '\0';
- if( *nobuild == '\n' )
+ else
{
- i = 0;
- sscanf( line, "%f %f %f %f %f\n",
- &origin[ 0 ], &origin[ 1 ], &origin[ 2 ], &area, &height );
-
- // Make the marker...
- nb = G_Spawn( );
- nb->s.modelindex = 0;
- VectorCopy( origin, nb->s.pos.trBase );
- VectorCopy( origin, nb->r.currentOrigin );
- nb->noBuild.isNB = qtrue;
- nb->noBuild.Area = area;
- nb->noBuild.Height = height;
- trap_LinkEntity( nb );
-
- // Log markers made...
- for( i = 0; i < MAX_GENTITIES; i++ )
- {
- if( level.nbMarkers[ i ].Marker != NULL )
- continue;
-
- level.nbMarkers[ i ].Marker = nb;
- VectorCopy( origin, level.nbMarkers[ i ].Origin );
- SnapVector( level.nbMarkers[ i ].Origin );
- break;
- }
-
+ gentity_t *builder = G_Spawn();
+ builder->classname = "builder";
+
+ VectorCopy( log->origin, builder->r.currentOrigin );
+ VectorCopy( log->angles, builder->r.currentAngles );
+ VectorCopy( log->origin2, builder->s.origin2 );
+ VectorCopy( log->angles2, builder->s.angles2 );
+ builder->s.modelindex = log->modelindex;
+ builder->deconstruct = log->deconstruct;
+ builder->deconstructTime = log->deconstructTime;
+ builder->builtBy = log->builtBy;
+
+ builder->think = G_BuildLogRevertThink;
+ builder->nextthink = level.time + FRAMETIME;
+
+ // Number of thinks before giving up and killing players in the way
+ builder->suicideTime = 30;
+
+ if( log->fate == BF_DESTROY || log->fate == BF_TEAMKILL )
+ {
+ int value = log->powerValue;
+
+ if( BG_Buildable( log->modelindex )->team == TEAM_ALIENS )
+ {
+ level.alienBuildPointQueue =
+ MAX( 0, level.alienBuildPointQueue - value );
+ }
+ else
+ {
+ if( log->powerSource == BA_H_REACTOR )
+ {
+ level.humanBuildPointQueue =
+ MAX( 0, level.humanBuildPointQueue - value );
+ }
+ else if( log->powerSource == BA_H_REPEATER )
+ {
+ gentity_t *source;
+ buildPointZone_t *zone;
+
+ source = G_PowerEntityForPoint( log->origin );
+ if( source && source->usesBuildPointZone )
+ {
+ zone = &level.buildPointZones[ source->buildPointZone ];
+ zone->queuedBuildPoints =
+ MAX( 0, zone->queuedBuildPoints - value );
+ }
+ }
+ }
+ }
}
- nobuild++;
}
}
/*
-============
-G_NobuildSave
-Save all currently placed nobuild markers into the "nobuild" folder
-============
+================
+G_UpdateBuildableRangeMarkers
+================
*/
-void G_NobuildSave( void )
+void G_UpdateBuildableRangeMarkers( void )
{
- char map[ MAX_QPATH ];
- char fileName[ MAX_OSPATH ];
- fileHandle_t f;
- int len;
- int i;
- gentity_t *ent;
- char *s;
+ // is the entity 64-bit client-masking extension available?
+ qboolean maskingExtension = ( trap_Cvar_VariableIntegerValue( "sv_gppExtension" ) >= 1 );
- trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
- if( !map[ 0 ] )
+ gentity_t *e;
+ for( e = &g_entities[ MAX_CLIENTS ]; e < &g_entities[ level.num_entities ]; ++e )
{
- G_Printf( "NobuildSave( ): no map is loaded\n" );
- return;
- }
- Com_sprintf( fileName, sizeof( fileName ), "nobuild/%s.dat", map );
+ buildable_t bType;
+ team_t bTeam;
+ int i;
- len = trap_FS_FOpenFile( fileName, &f, FS_WRITE );
- if( len < 0 )
- {
- G_Printf( "nobuildsave: could not open %s\n", fileName );
- return;
- }
+ if( e->s.eType != ET_BUILDABLE || !e->rangeMarker )
+ continue;
- G_Printf("nobuildsave: saving nobuild to %s\n", fileName );
+ bType = e->s.modelindex;
+ bTeam = BG_Buildable( bType )->team;
- for( i = 0; i < MAX_GENTITIES; i++ )
- {
- ent = &level.gentities[ i ];
- if( ent->noBuild.isNB != qtrue )
- continue;
+ e->rangeMarker->s.pos = e->s.pos;
+ if( bType == BA_A_HIVE || bType == BA_H_TESLAGEN )
+ VectorMA( e->s.pos.trBase, e->r.maxs[ 2 ], e->s.origin2, e->rangeMarker->s.pos.trBase );
+ else if( bType == BA_A_TRAPPER || bType == BA_H_MGTURRET )
+ vectoangles( e->s.origin2, e->rangeMarker->s.apos.trBase );
- s = va( "%f %f %f %f %f\n",
- ent->r.currentOrigin[ 0 ],
- ent->r.currentOrigin[ 1 ],
- ent->r.currentOrigin[ 2 ],
- ent->noBuild.Area,
- ent->noBuild.Height );
- trap_FS_Write( s, strlen( s ), f );
+ e->rangeMarker->r.singleClient = 0;
+ e->rangeMarker->r.hack.generic1 = 0;
+
+ // remove any previously added NOCLIENT flags from the hack below
+ e->rangeMarker->r.svFlags &= ~SVF_NOCLIENT;
+
+ for( i = 0; i < level.maxclients; ++i )
+ {
+ gclient_t *client;
+ team_t team;
+ qboolean weaponDisplays, wantsToSee;
+
+ client = &level.clients[ i ];
+ if( client->pers.connected != CON_CONNECTED )
+ continue;
+
+ if( i >= 32 && !maskingExtension )
+ {
+ // resort to not sending range markers at all
+ if( !trap_Cvar_VariableIntegerValue( "g_rangeMarkerWarningGiven" ) )
+ {
+ trap_SendServerCommand( -1, "print \"" S_COLOR_YELLOW "WARNING: There is no "
+ "support for entity 64-bit client-masking on this server. Please update "
+ "your server executable. Until then, range markers will not be displayed "
+ "while there are clients with client numbers above 31 in the game.\n\"" );
+ trap_Cvar_Set( "g_rangeMarkerWarningGiven", "1" );
+ }
+
+ for( e = &g_entities[ MAX_CLIENTS ]; e < &g_entities[ level.num_entities ]; ++e )
+ {
+ if( e->s.eType == ET_BUILDABLE && e->rangeMarker )
+ e->rangeMarker->r.svFlags |= SVF_NOCLIENT;
+ }
+
+ return;
+ }
+
+ team = client->pers.teamSelection;
+ if( team != TEAM_NONE )
+ {
+ weaponDisplays = ( BG_InventoryContainsWeapon( WP_HBUILD, client->ps.stats ) ||
+ client->ps.weapon == WP_ABUILD || client->ps.weapon == WP_ABUILD2 );
+ }
+ wantsToSee = !!( client->pers.buildableRangeMarkerMask & ( 1 << bType ) );
+
+ if( ( team == TEAM_NONE || ( team == bTeam && weaponDisplays ) ) && wantsToSee )
+ {
+ if( i >= 32 )
+ e->rangeMarker->r.hack.generic1 |= 1 << ( i - 32 );
+ else
+ e->rangeMarker->r.singleClient |= 1 << i;
+ }
+ }
+
+ trap_LinkEntity( e->rangeMarker );
}
- trap_FS_FCloseFile( f );
}
diff --git a/src/game/g_client.c b/src/game/g_client.c
index c77d4f7..3481af9 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -81,156 +82,35 @@ void SP_info_human_intermission( gentity_t *ent )
/*
===============
-G_OverflowCredits
-===============
-*/
-void G_OverflowCredits( gclient_t *doner, int credits )
-{
- int i;
- int maxCredits;
- int clientNum;
-
- if( !g_creditOverflow.integer )
- return;
-
- if( doner->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- maxCredits = ALIEN_MAX_KILLS;
- clientNum = level.lastCreditedAlien;
- }
- else if( doner->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- maxCredits = HUMAN_MAX_CREDITS;
- clientNum = level.lastCreditedHuman;
- }
- else
- {
- return;
- }
-
- if( g_creditOverflow.integer == 1 )
- {
- // distribute to everyone on team
- gentity_t *vic;
-
- i = 0;
- while( credits > 0 && i < level.maxclients )
- {
- i++;
- clientNum++;
- if( clientNum >= level.maxclients )
- clientNum = 0;
-
- vic = &g_entities[ clientNum ];
- if( vic->client->ps.stats[ STAT_PTEAM ] != doner->ps.stats[ STAT_PTEAM ] ||
- vic->client->ps.persistant[ PERS_CREDIT ] >= maxCredits )
- continue;
-
- if( vic->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- level.lastCreditedAlien = clientNum;
- else
- level.lastCreditedHuman = clientNum;
-
- if( vic->client->ps.persistant[ PERS_CREDIT ] + credits > maxCredits )
- {
- credits -= maxCredits - vic->client->ps.persistant[ PERS_CREDIT ];
- vic->client->ps.persistant[ PERS_CREDIT ] = maxCredits;
- }
- else
- {
- vic->client->ps.persistant[ PERS_CREDIT ] += credits;
- return;
- }
- }
- }
- else if( g_creditOverflow.integer == 2 )
- {
- // distribute by team rank
- gclient_t *cl;
-
- for( i = 0; i < level.numPlayingClients && credits > 0; i++ )
- {
- // get the client list sorted by rank
- cl = &level.clients[ level.sortedClients[ i ] ];
- if( cl->ps.stats[ STAT_PTEAM ] != doner->ps.stats[ STAT_PTEAM ] ||
- cl->ps.persistant[ PERS_CREDIT ] >= maxCredits )
- continue;
-
- if( cl->ps.persistant[ PERS_CREDIT ] + credits > maxCredits )
- {
- credits -= maxCredits - cl->ps.persistant[ PERS_CREDIT ];
- cl->ps.persistant[ PERS_CREDIT ] = maxCredits;
- }
- else
- {
- cl->ps.persistant[ PERS_CREDIT ] += credits;
- return;
- }
- }
- }
-}
-
-/*
-===============
G_AddCreditToClient
===============
*/
void G_AddCreditToClient( gclient_t *client, short credit, qboolean cap )
{
+ int capAmount;
+
if( !client )
return;
- //if we're already at the max and trying to add credit then stop
- if( cap )
- {
- if( client->pers.teamSelection == PTE_ALIENS )
- {
- if( client->pers.credit >= ALIEN_MAX_KILLS &&
- credit > 0 )
- {
- G_OverflowCredits( client, credit );
- return;
- }
- }
- else if( client->pers.teamSelection == PTE_HUMANS )
- {
- if( client->pers.credit >= HUMAN_MAX_CREDITS &&
- credit > 0 )
- {
- G_OverflowCredits( client, credit );
- return;
- }
- }
- }
-
- client->pers.credit += credit;
-
- if( cap )
+ if( cap && credit > 0 )
{
- if( client->pers.teamSelection == PTE_ALIENS )
+ capAmount = client->pers.teamSelection == TEAM_ALIENS ?
+ ALIEN_MAX_CREDITS : HUMAN_MAX_CREDITS;
+ if( client->pers.credit < capAmount )
{
- if( client->pers.credit > ALIEN_MAX_KILLS )
- {
- G_OverflowCredits( client, client->ps.persistant[ PERS_CREDIT ] - ALIEN_MAX_KILLS );
- client->pers.credit = ALIEN_MAX_KILLS;
- }
- }
- else if( client->pers.teamSelection == PTE_HUMANS )
- {
- if( client->pers.credit > HUMAN_MAX_CREDITS )
- {
- G_OverflowCredits( client, client->ps.persistant[ PERS_CREDIT ] - HUMAN_MAX_CREDITS );
- client->pers.credit = HUMAN_MAX_CREDITS;
- }
+ client->pers.credit += credit;
+ if( client->pers.credit > capAmount )
+ client->pers.credit = capAmount;
}
}
+ else
+ client->pers.credit += credit;
if( client->pers.credit < 0 )
client->pers.credit = 0;
- // keep PERS_CREDIT in sync if not following
- if( client->sess.spectatorState != SPECTATOR_FOLLOW )
- client->ps.persistant[ PERS_CREDIT ] = client->pers.credit;
+ // Copy to ps so the client can access it
+ client->ps.persistant[ PERS_CREDIT ] = client->pers.credit;
}
@@ -255,8 +135,8 @@ qboolean SpotWouldTelefrag( gentity_t *spot )
gentity_t *hit;
vec3_t mins, maxs;
- VectorAdd( spot->s.origin, playerMins, mins );
- VectorAdd( spot->s.origin, playerMaxs, maxs );
+ VectorAdd( spot->r.currentOrigin, playerMins, mins );
+ VectorAdd( spot->r.currentOrigin, playerMaxs, maxs );
num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
for( i = 0; i < num; i++ )
@@ -270,75 +150,6 @@ qboolean SpotWouldTelefrag( gentity_t *spot )
return qfalse;
}
-/*
-================
-G_SelectNearestDeathmatchSpawnPoint
-
-Find the spot that we DON'T want to use
-================
-*/
-#define MAX_SPAWN_POINTS 128
-gentity_t *G_SelectNearestDeathmatchSpawnPoint( vec3_t from )
-{
- gentity_t *spot;
- vec3_t delta;
- float dist, nearestDist;
- gentity_t *nearestSpot;
-
- nearestDist = 999999;
- nearestSpot = NULL;
- spot = NULL;
-
- while( (spot = G_Find( spot, FOFS( classname ), "info_player_deathmatch" ) ) != NULL )
- {
- VectorSubtract( spot->s.origin, from, delta );
- dist = VectorLength( delta );
-
- if( dist < nearestDist )
- {
- nearestDist = dist;
- nearestSpot = spot;
- }
- }
-
- return nearestSpot;
-}
-
-
-/*
-================
-G_SelectRandomDeathmatchSpawnPoint
-
-go to a random point that doesn't telefrag
-================
-*/
-#define MAX_SPAWN_POINTS 128
-gentity_t *G_SelectRandomDeathmatchSpawnPoint( void )
-{
- gentity_t *spot;
- int count;
- int selection;
- gentity_t *spots[ MAX_SPAWN_POINTS ];
-
- count = 0;
- spot = NULL;
-
- while( ( spot = G_Find( spot, FOFS( classname ), "info_player_deathmatch" ) ) != NULL )
- {
- if( SpotWouldTelefrag( spot ) )
- continue;
-
- spots[ count ] = spot;
- count++;
- }
-
- if( !count ) // no spots that won't telefrag
- return G_Find( NULL, FOFS( classname ), "info_player_deathmatch" );
-
- selection = rand( ) % count;
- return spots[ selection ];
-}
-
/*
===========
@@ -347,7 +158,7 @@ G_SelectRandomFurthestSpawnPoint
Chooses a player start, deathmatch start, etc
============
*/
-gentity_t *G_SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles )
+static gentity_t *G_SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles )
{
gentity_t *spot;
vec3_t delta;
@@ -364,7 +175,7 @@ gentity_t *G_SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin,
if( SpotWouldTelefrag( spot ) )
continue;
- VectorSubtract( spot->s.origin, avoidPoint, delta );
+ VectorSubtract( spot->r.currentOrigin, avoidPoint, delta );
dist = VectorLength( delta );
for( i = 0; i < numSpots; i++ )
@@ -406,18 +217,18 @@ gentity_t *G_SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin,
if( !spot )
G_Error( "Couldn't find a spawn point" );
- VectorCopy( spot->s.origin, origin );
+ VectorCopy( spot->r.currentOrigin, origin );
origin[ 2 ] += 9;
- VectorCopy( spot->s.angles, angles );
+ VectorCopy( spot->r.currentAngles, angles );
return spot;
}
// select a random spot from the spawn points furthest away
rnd = random( ) * ( numSpots / 2 );
- VectorCopy( list_spot[ rnd ]->s.origin, origin );
+ VectorCopy( list_spot[ rnd ]->r.currentOrigin, origin );
origin[ 2 ] += 9;
- VectorCopy( list_spot[ rnd ]->s.angles, angles );
+ VectorCopy( list_spot[ rnd ]->r.currentAngles, angles );
return list_spot[ rnd ];
}
@@ -425,102 +236,45 @@ gentity_t *G_SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin,
/*
================
-G_SelectAlienSpawnPoint
-
-go to a random point that doesn't telefrag
-================
-*/
-gentity_t *G_SelectAlienSpawnPoint( vec3_t preference )
-{
- gentity_t *spot;
- int count;
- gentity_t *spots[ MAX_SPAWN_POINTS ];
-
- if( level.numAlienSpawns <= 0 )
- return NULL;
-
- count = 0;
- spot = NULL;
-
- while( ( spot = G_Find( spot, FOFS( classname ),
- BG_FindEntityNameForBuildable( BA_A_SPAWN ) ) ) != NULL )
- {
- if( !spot->spawned )
- continue;
-
- if( spot->health <= 0 )
- continue;
-
- if( !spot->s.groundEntityNum )
- continue;
-
- if( spot->clientSpawnTime > 0 )
- continue;
-
- if( G_CheckSpawnPoint( spot->s.number, spot->s.origin,
- spot->s.origin2, BA_A_SPAWN, NULL ) != NULL )
- continue;
-
- spots[ count ] = spot;
- count++;
- }
-
- if( !count )
- return NULL;
-
- return G_ClosestEnt( preference, spots, count );
-}
-
-
-/*
-================
-G_SelectHumanSpawnPoint
+G_SelectSpawnBuildable
-go to a random point that doesn't telefrag
+find the nearest buildable of the right type that is
+spawned/healthy/unblocked etc.
================
*/
-gentity_t *G_SelectHumanSpawnPoint( vec3_t preference )
+static gentity_t *G_SelectSpawnBuildable( vec3_t preference, buildable_t buildable )
{
- gentity_t *spot;
- int count;
- gentity_t *spots[ MAX_SPAWN_POINTS ];
-
- if( level.numHumanSpawns <= 0 )
- return NULL;
+ gentity_t *search, *spot;
- count = 0;
- spot = NULL;
+ search = spot = NULL;
- while( ( spot = G_Find( spot, FOFS( classname ),
- BG_FindEntityNameForBuildable( BA_H_SPAWN ) ) ) != NULL )
+ while( ( search = G_Find( search, FOFS( classname ),
+ BG_Buildable( buildable )->entityName ) ) != NULL )
{
- if( !spot->spawned )
+ if( !search->spawned )
continue;
- if( spot->health <= 0 )
+ if( search->health <= 0 )
continue;
- if( !spot->s.groundEntityNum )
+ if( search->s.groundEntityNum == ENTITYNUM_NONE )
continue;
- if( spot->clientSpawnTime > 0 )
+ if( search->clientSpawnTime > 0 )
continue;
- if( G_CheckSpawnPoint( spot->s.number, spot->s.origin,
- spot->s.origin2, BA_H_SPAWN, NULL ) != NULL )
+ if( G_CheckSpawnPoint( search->s.number, search->r.currentOrigin,
+ search->s.origin2, buildable, NULL ) != NULL )
continue;
- spots[ count ] = spot;
- count++;
+ if( !spot || DistanceSquared( preference, search->r.currentOrigin ) <
+ DistanceSquared( preference, spot->r.currentOrigin ) )
+ spot = search;
}
- if( !count )
- return NULL;
-
- return G_ClosestEnt( preference, spots, count );
+ return spot;
}
-
/*
===========
G_SelectSpawnPoint
@@ -541,25 +295,35 @@ G_SelectTremulousSpawnPoint
Chooses a player start, deathmatch start, etc
============
*/
-gentity_t *G_SelectTremulousSpawnPoint( pTeam_t team, vec3_t preference, vec3_t origin, vec3_t angles )
+gentity_t *G_SelectTremulousSpawnPoint( team_t team, vec3_t preference, vec3_t origin, vec3_t angles )
{
gentity_t *spot = NULL;
- if( team == PTE_ALIENS )
- spot = G_SelectAlienSpawnPoint( preference );
- else if( team == PTE_HUMANS )
- spot = G_SelectHumanSpawnPoint( preference );
+ if( team == TEAM_ALIENS )
+ {
+ if( level.numAlienSpawns <= 0 )
+ return NULL;
+
+ spot = G_SelectSpawnBuildable( preference, BA_A_SPAWN );
+ }
+ else if( team == TEAM_HUMANS )
+ {
+ if( level.numHumanSpawns <= 0 )
+ return NULL;
+
+ spot = G_SelectSpawnBuildable( preference, BA_H_SPAWN );
+ }
//no available spots
if( !spot )
return NULL;
- if( team == PTE_ALIENS )
- G_CheckSpawnPoint( spot->s.number, spot->s.origin, spot->s.origin2, BA_A_SPAWN, origin );
- else if( team == PTE_HUMANS )
- G_CheckSpawnPoint( spot->s.number, spot->s.origin, spot->s.origin2, BA_H_SPAWN, origin );
+ if( team == TEAM_ALIENS )
+ G_CheckSpawnPoint( spot->s.number, spot->r.currentOrigin, spot->s.origin2, BA_A_SPAWN, origin );
+ else if( team == TEAM_HUMANS )
+ G_CheckSpawnPoint( spot->s.number, spot->r.currentOrigin, spot->s.origin2, BA_H_SPAWN, origin );
- VectorCopy( spot->s.angles, angles );
+ VectorCopy( spot->r.currentAngles, angles );
angles[ ROLL ] = 0;
return spot;
@@ -569,42 +333,11 @@ gentity_t *G_SelectTremulousSpawnPoint( pTeam_t team, vec3_t preference, vec3_t
/*
===========
-G_SelectInitialSpawnPoint
-
-Try to find a spawn point marked 'initial', otherwise
-use normal spawn selection.
-============
-*/
-gentity_t *G_SelectInitialSpawnPoint( vec3_t origin, vec3_t angles )
-{
- gentity_t *spot;
-
- spot = NULL;
- while( ( spot = G_Find( spot, FOFS( classname ), "info_player_deathmatch" ) ) != NULL )
- {
- if( spot->spawnflags & 1 )
- break;
- }
-
- if( !spot || SpotWouldTelefrag( spot ) )
- {
- return G_SelectSpawnPoint( vec3_origin, origin, angles );
- }
-
- VectorCopy( spot->s.origin, origin );
- origin[ 2 ] += 9;
- VectorCopy( spot->s.angles, angles );
-
- return spot;
-}
-
-/*
-===========
G_SelectSpectatorSpawnPoint
============
*/
-gentity_t *G_SelectSpectatorSpawnPoint( vec3_t origin, vec3_t angles )
+static gentity_t *G_SelectSpectatorSpawnPoint( vec3_t origin, vec3_t angles )
{
FindIntermissionPoint( );
@@ -633,8 +366,8 @@ gentity_t *G_SelectAlienLockSpawnPoint( vec3_t origin, vec3_t angles )
if( !spot )
return G_SelectSpectatorSpawnPoint( origin, angles );
- VectorCopy( spot->s.origin, origin );
- VectorCopy( spot->s.angles, angles );
+ VectorCopy( spot->r.currentOrigin, origin );
+ VectorCopy( spot->r.currentAngles, angles );
return spot;
}
@@ -658,8 +391,8 @@ gentity_t *G_SelectHumanLockSpawnPoint( vec3_t origin, vec3_t angles )
if( !spot )
return G_SelectSpectatorSpawnPoint( origin, angles );
- VectorCopy( spot->s.origin, origin );
- VectorCopy( spot->s.angles, angles );
+ VectorCopy( spot->r.currentOrigin, origin );
+ VectorCopy( spot->r.currentAngles, angles );
return spot;
}
@@ -681,7 +414,7 @@ BodySink
After sitting around for five seconds, fall into the ground and dissapear
=============
*/
-void BodySink( gentity_t *ent )
+static void BodySink( gentity_t *ent )
{
//run on first BodySink call
if( !ent->active )
@@ -706,40 +439,17 @@ void BodySink( gentity_t *ent )
/*
=============
-BodyFree
-
-After sitting around for a while the body becomes a freebie
-=============
-*/
-void BodyFree( gentity_t *ent )
-{
- ent->killedBy = -1;
-
- //if not claimed in the next minute destroy
- ent->think = BodySink;
- ent->nextthink = level.time + 60000;
-}
-
-
-/*
-=============
SpawnCorpse
A player is respawning, so make an entity that looks
just like the existing corpse to leave behind.
=============
*/
-void SpawnCorpse( gentity_t *ent )
+static void SpawnCorpse( gentity_t *ent )
{
gentity_t *body;
int contents;
- vec3_t origin, dest;
- trace_t tr;
- float vDiff;
-
- // prevent crashing everyone with bad corpsenum bug
- if( ent->client->pers.connected != CON_CONNECTED )
- return;
+ vec3_t origin, mins;
VectorCopy( ent->r.currentOrigin, origin );
@@ -752,17 +462,18 @@ void SpawnCorpse( gentity_t *ent )
body = G_Spawn( );
- VectorCopy( ent->s.apos.trBase, body->s.angles );
+ VectorCopy( ent->s.apos.trBase, body->s.apos.trBase );
+ VectorCopy( ent->s.apos.trBase, body->r.currentAngles );
body->s.eFlags = EF_DEAD;
body->s.eType = ET_CORPSE;
- body->s.number = body - g_entities;
body->timestamp = level.time;
body->s.event = 0;
body->r.contents = CONTENTS_CORPSE;
- body->s.clientNum = ent->client->ps.stats[ STAT_PCLASS ];
+ body->clipmask = MASK_DEADSOLID;
+ body->s.clientNum = ent->client->ps.stats[ STAT_CLASS ];
body->nonSegModel = ent->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL;
- if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( ent->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
body->classname = "humanCorpse";
else
body->classname = "alienCorpse";
@@ -815,25 +526,19 @@ void SpawnCorpse( gentity_t *ent )
body->takedamage = qfalse;
- body->health = ent->health = ent->client->ps.stats[ STAT_HEALTH ];
- ent->health = 0;
+ body->health = ent->health;
//change body dimensions
- BG_FindBBoxForClass( ent->client->ps.stats[ STAT_PCLASS ], NULL, NULL, NULL, body->r.mins, body->r.maxs );
- vDiff = body->r.mins[ 2 ] - ent->r.mins[ 2 ];
+ BG_ClassBoundingBox( ent->client->ps.stats[ STAT_CLASS ], mins, NULL, NULL, body->r.mins, body->r.maxs );
//drop down to match the *model* origins of ent and body
- VectorSet( dest, origin[ 0 ], origin[ 1 ], origin[ 2 ] - vDiff );
- trap_Trace( &tr, origin, body->r.mins, body->r.maxs, dest, body->s.number, body->clipmask );
- VectorCopy( tr.endpos, origin );
+ origin[2] += mins[ 2 ] - body->r.mins[ 2 ];
G_SetOrigin( body, origin );
- VectorCopy( origin, body->s.origin );
body->s.pos.trType = TR_GRAVITY;
body->s.pos.trTime = level.time;
VectorCopy( ent->client->ps.velocity, body->s.pos.trDelta );
- VectorCopy ( body->s.pos.trBase, body->r.currentOrigin );
trap_LinkEntity( body );
}
@@ -846,7 +551,7 @@ G_SetClientViewAngle
==================
*/
-void G_SetClientViewAngle( gentity_t *ent, vec3_t angle )
+void G_SetClientViewAngle( gentity_t *ent, const vec3_t angle )
{
int i;
@@ -859,8 +564,9 @@ void G_SetClientViewAngle( gentity_t *ent, vec3_t angle )
ent->client->ps.delta_angles[ i ] = cmdAngle - ent->client->pers.cmd.angles[ i ];
}
- VectorCopy( angle, ent->s.angles );
- VectorCopy( ent->s.angles, ent->client->ps.viewangles );
+ VectorCopy( angle, ent->s.apos.trBase );
+ VectorCopy( angle, ent->r.currentAngles );
+ VectorCopy( angle, ent->client->ps.viewangles );
}
/*
@@ -870,52 +576,79 @@ respawn
*/
void respawn( gentity_t *ent )
{
+ int i;
+
SpawnCorpse( ent );
- //TA: Clients can't respawn - they must go thru the class cmd
+ // Clients can't respawn - they must go through the class cmd
ent->client->pers.classSelection = PCL_NONE;
ClientSpawn( ent, NULL, NULL, NULL );
-}
-/*
-================
-TeamCount
+ // stop any following clients that don't have sticky spec on
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ if( level.clients[ i ].sess.spectatorState == SPECTATOR_FOLLOW &&
+ level.clients[ i ].sess.spectatorClient == ent - g_entities )
+ {
+ if( !( level.clients[ i ].pers.stickySpec ) )
+ {
+ if( !G_FollowNewClient( &g_entities[ i ], 1 ) )
+ G_StopFollowing( &g_entities[ i ] );
+ }
+ else
+ G_FollowLockView( &g_entities[ i ] );
+ }
+ }
+}
-Returns number of players on a team
-================
-*/
-team_t TeamCount( int ignoreClientNum, int team )
+static qboolean G_IsEmoticon( const char *s, qboolean *escaped )
{
- int i;
- int count = 0;
+ int i, j;
+ const char *p = s;
+ char emoticon[ MAX_EMOTICON_NAME_LEN ] = {""};
+ qboolean escape = qfalse;
- for( i = 0 ; i < level.maxclients ; i++ )
+ if( *p != '[' )
+ return qfalse;
+ p++;
+ if( *p == '[' )
{
- if( i == ignoreClientNum )
- continue;
-
- if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
- continue;
-
- if( level.clients[ i ].sess.sessionTeam == team )
- count++;
+ escape = qtrue;
+ p++;
}
-
- return count;
+ i = 0;
+ while( *p && i < ( MAX_EMOTICON_NAME_LEN - 1 ) )
+ {
+ if( *p == ']' )
+ {
+ for( j = 0; j < level.emoticonCount; j++ )
+ {
+ if( !Q_stricmp( emoticon, level.emoticons[ j ].name ) )
+ {
+ *escaped = escape;
+ return qtrue;
+ }
+ }
+ return qfalse;
+ }
+ emoticon[ i++ ] = *p;
+ emoticon[ i ] = '\0';
+ p++;
+ }
+ return qfalse;
}
-
/*
===========
-ClientCleanName
+G_ClientCleanName
============
*/
-static void ClientCleanName( const char *in, char *out, int outSize, qboolean special )
+static void G_ClientCleanName( const char *in, char *out, int outSize )
{
int len, colorlessLen;
- char ch;
char *p;
int spaces;
+ qboolean escaped;
qboolean invalid = qfalse;
//save room for trailing null byte
@@ -927,44 +660,48 @@ static void ClientCleanName( const char *in, char *out, int outSize, qboolean sp
*p = 0;
spaces = 0;
- while( 1 )
+ for( ; *in; in++ )
{
- ch = *in++;
- if( !ch )
- break;
-
// don't allow leading spaces
- if( !*p && ch == ' ' )
+ if( colorlessLen == 0 && *in == ' ' )
continue;
// don't allow nonprinting characters or (dead) console keys
- if( ch < ' ' || ch > '}' || ch == '`' || ch == '%' )
+ if( *in < ' ' || *in > '}' || *in == '`' )
continue;
// check colors
- if( Q_IsColorString( in - 1 ) )
+ if( Q_IsColorString( in ) )
{
+ in++;
+
// make sure room in dest for both chars
if( len > outSize - 2 )
break;
- *out++ = ch;
- len += 2;
+ *out++ = Q_COLOR_ESCAPE;
- // solo trailing carat is not a color prefix
- if( !*in ) {
- *out++ = COLOR_WHITE;
- break;
- }
+ *out++ = *in;
- *out++ = *in;
+ len += 2;
+ continue;
+ }
+ else if( !g_emoticonsAllowedInNames.integer && G_IsEmoticon( in, &escaped ) )
+ {
+ // make sure room in dest for both chars
+ if( len > outSize - 2 )
+ break;
- in++;
+ *out++ = '[';
+ *out++ = '[';
+ len += 2;
+ if( escaped )
+ in++;
continue;
}
// don't allow too many consecutive spaces
- if( ch == ' ' )
+ if( *in == ' ' )
{
spaces++;
if( spaces > 3 )
@@ -976,7 +713,7 @@ static void ClientCleanName( const char *in, char *out, int outSize, qboolean sp
if( len > outSize - 1 )
break;
- *out++ = ch;
+ *out++ = *in;
colorlessLen++;
len++;
}
@@ -984,7 +721,7 @@ static void ClientCleanName( const char *in, char *out, int outSize, qboolean sp
*out = 0;
// don't allow names beginning with "[skipnotify]" because it messes up /ignore-related code
- if( !Q_strncmp( p, "[skipnotify]", 12 ) )
+ if( !Q_stricmpn( p, "[skipnotify]", 12 ) )
invalid = qtrue;
// don't allow comment-beginning strings because it messes up various parsers
@@ -1002,37 +739,6 @@ static void ClientCleanName( const char *in, char *out, int outSize, qboolean sp
/*
-===================
-G_NextNewbieName
-
-Generate a unique, known-good name for an UnnamedPlayer
-===================
-*/
-char *G_NextNewbieName( gentity_t *ent )
-{
- char newname[ MAX_NAME_LENGTH ];
- char namePrefix[ MAX_NAME_LENGTH - 4 ];
- char err[ MAX_STRING_CHARS ];
-
- if( g_newbieNamePrefix.string[ 0 ] )
- Q_strncpyz( namePrefix, g_newbieNamePrefix.string , sizeof( namePrefix ) );
- else
- strcpy( namePrefix, "Newbie#" );
-
- while( level.numNewbies < 10000 )
- {
- strcpy( newname, va( "%s%i", namePrefix, level.numNewbies ) );
- if ( G_admin_name_check( ent, newname, err, sizeof( err ) ) )
- {
- return va( "%s", newname );
- }
- level.numNewbies++; // Only increments if the last requested name was used.
- }
- return "UnnamedPlayer";
-}
-
-
-/*
======================
G_NonSegModel
@@ -1099,24 +805,19 @@ The game can override any of the settings and call trap_SetUserinfo
if desired.
============
*/
-void ClientUserinfoChanged( int clientNum, qboolean forceName )
+char *ClientUserinfoChanged( int clientNum, qboolean forceName )
{
gentity_t *ent;
- int teamTask, teamLeader, health;
- char *s;
- char model[ MAX_QPATH ];
- char buffer[ MAX_QPATH ];
+ char *s, *s2;
+ char model[ MAX_QPATH] = { '\0' };
+ char buffer[ MAX_QPATH ] = { '\0' };
char filename[ MAX_QPATH ];
char oldname[ MAX_NAME_LENGTH ];
char newname[ MAX_NAME_LENGTH ];
char err[ MAX_STRING_CHARS ];
qboolean revertName = qfalse;
- qboolean showRenameMsg = qtrue;
gclient_t *client;
- char c1[ MAX_INFO_STRING ];
- char c2[ MAX_INFO_STRING ];
char userinfo[ MAX_INFO_STRING ];
- pTeam_t team;
ent = g_entities + clientNum;
client = ent->client;
@@ -1130,81 +831,49 @@ void ClientUserinfoChanged( int clientNum, qboolean forceName )
"disconnect \"illegal or malformed userinfo\n\"" );
trap_DropClient( ent - g_entities,
"dropped: illegal or malformed userinfo");
+ return "Illegal or malformed userinfo";
}
+ // If their userinfo overflowed, tremded is in the process of disconnecting them.
+ // If we send our own disconnect, it won't work, so just return to prevent crashes later
+ // in this function. This check must come after the Info_Validate call.
+ else if( !userinfo[ 0 ] )
+ return "Empty (overflowed) userinfo";
-
- // check for local client
- s = Info_ValueForKey( userinfo, "ip" );
-
- if( !strcmp( s, "localhost" ) )
- client->pers.localClient = qtrue;
-
- // check the item prediction
- s = Info_ValueForKey( userinfo, "cg_predictItems" );
-
- if( !atoi( s ) )
- client->pers.predictItemPickup = qfalse;
- else
- client->pers.predictItemPickup = qtrue;
+ // stickyspec toggle
+ s = Info_ValueForKey( userinfo, "cg_stickySpec" );
+ client->pers.stickySpec = atoi( s ) != 0;
// set name
Q_strncpyz( oldname, client->pers.netname, sizeof( oldname ) );
s = Info_ValueForKey( userinfo, "name" );
-
- if ( !G_admin_permission( ent, ADMF_SPECIALNAME ) )
- ClientCleanName( s, newname, sizeof( newname ), qfalse );
- else
- ClientCleanName( s, newname, sizeof( newname ), qtrue );
+ G_ClientCleanName( s, newname, sizeof( newname ) );
if( strcmp( oldname, newname ) )
{
- if( !strlen( oldname ) && client->pers.connected != CON_CONNECTED )
- showRenameMsg = qfalse;
-
- // in case we need to revert and there's no oldname
- if ( !G_admin_permission( ent, ADMF_SPECIALNAME ) )
- ClientCleanName( va( "%s", client->pers.netname ), oldname, sizeof( oldname ), qfalse );
- else
- ClientCleanName( va( "%s", client->pers.netname ), oldname, sizeof( oldname ), qtrue );
-
- if( g_newbieNumbering.integer )
+ if( !forceName && client->pers.namelog->nameChangeTime &&
+ level.time - client->pers.namelog->nameChangeTime <=
+ g_minNameChangePeriod.value * 1000 )
{
- if( !strcmp( newname, "UnnamedPlayer" ) )
- Q_strncpyz( newname, G_NextNewbieName( ent ), sizeof( newname ) );
- if( !strcmp( oldname, "UnnamedPlayer" ) )
- Q_strncpyz( oldname, G_NextNewbieName( ent ), sizeof( oldname ) );
+ trap_SendServerCommand( ent - g_entities, va(
+ "print \"Name change spam protection (g_minNameChangePeriod = %d)\n\"",
+ g_minNameChangePeriod.integer ) );
+ revertName = qtrue;
}
-
-
- if( !forceName )
+ else if( !forceName && g_maxNameChanges.integer > 0 &&
+ client->pers.namelog->nameChanges >= g_maxNameChanges.integer )
{
- if( G_IsMuted( client ) )
- {
- trap_SendServerCommand( ent - g_entities,
- "print \"You cannot change your name while you are muted\n\"" );
- revertName = qtrue;
- }
- else if( client->pers.nameChangeTime &&
- ( level.time - client->pers.nameChangeTime )
- <= ( g_minNameChangePeriod.value * 1000 ) )
- {
- trap_SendServerCommand( ent - g_entities, va(
- "print \"Name change spam protection (g_minNameChangePeriod = %d)\n\"",
- g_minNameChangePeriod.integer ) );
- revertName = qtrue;
- }
- else if( g_maxNameChanges.integer > 0
- && client->pers.nameChanges >= g_maxNameChanges.integer
- && !G_admin_permission( ent, ADMF_SPECIAL ) )
- {
- trap_SendServerCommand( ent - g_entities, va(
- "print \"Maximum name changes reached (g_maxNameChanges = %d)\n\"",
- g_maxNameChanges.integer ) );
- revertName = qtrue;
- }
+ trap_SendServerCommand( ent - g_entities, va(
+ "print \"Maximum name changes reached (g_maxNameChanges = %d)\n\"",
+ g_maxNameChanges.integer ) );
+ revertName = qtrue;
}
-
- if( !G_admin_name_check( ent, newname, err, sizeof( err ) ) )
+ else if( !forceName && client->pers.namelog->muted )
+ {
+ trap_SendServerCommand( ent - g_entities,
+ "print \"You cannot change your name while you are muted\n\"" );
+ revertName = qtrue;
+ }
+ else if( !G_admin_name_check( ent, newname, err, sizeof( err ) ) )
{
trap_SendServerCommand( ent - g_entities, va( "print \"%s\n\"", err ) );
revertName = qtrue;
@@ -1212,110 +881,96 @@ void ClientUserinfoChanged( int clientNum, qboolean forceName )
if( revertName )
{
- Q_strncpyz( client->pers.netname, oldname,
+ Q_strncpyz( client->pers.netname, *oldname ? oldname : "UnnamedPlayer",
sizeof( client->pers.netname ) );
Info_SetValueForKey( userinfo, "name", oldname );
trap_SetUserinfo( clientNum, userinfo );
}
else
{
- Q_strncpyz( client->pers.netname, newname,
- sizeof( client->pers.netname ) );
- Info_SetValueForKey( userinfo, "name", newname );
- trap_SetUserinfo( clientNum, userinfo );
- if( client->pers.connected == CON_CONNECTED )
+ G_CensorString( client->pers.netname, newname,
+ sizeof( client->pers.netname ), ent );
+ if( !forceName && client->pers.connected == CON_CONNECTED )
+ {
+ client->pers.namelog->nameChangeTime = level.time;
+ client->pers.namelog->nameChanges++;
+ }
+ if( *oldname )
{
- client->pers.nameChangeTime = level.time;
- client->pers.nameChanges++;
+ G_LogPrintf( "ClientRename: %i [%s] (%s) \"%s^7\" -> \"%s^7\" \"%c%s%c^7\"\n",
+ clientNum, client->pers.ip.str, client->pers.guid,
+ oldname, client->pers.netname,
+ DECOLOR_OFF, client->pers.netname, DECOLOR_ON );
}
}
+ G_namelog_update_name( client );
}
- if( client->sess.sessionTeam == TEAM_SPECTATOR )
+ if ( client->pers.teamSelection == TEAM_HUMANS )
{
- if( client->sess.spectatorState == SPECTATOR_SCOREBOARD )
- Q_strncpyz( client->pers.netname, "scoreboard", sizeof( client->pers.netname ) );
- }
+ int i;
+ qboolean found = qfalse;
- if( client->pers.connected >= CON_CONNECTING && showRenameMsg )
- {
- if( strcmp( oldname, client->pers.netname ) )
- {
- //dont show if players invisible
- if( client->sess.invisible != qtrue )
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE
- " renamed to %s^7\n\"", oldname, client->pers.netname ) );
- if( g_decolourLogfiles.integer)
- {
- char decoloured[ MAX_STRING_CHARS ] = "";
- if( g_decolourLogfiles.integer == 1 )
- {
- Com_sprintf( decoloured, sizeof(decoloured), " (\"%s^7\" -> \"%s^7\")", oldname, client->pers.netname );
- G_DecolorString( decoloured, decoloured );
- G_LogPrintfColoured( "ClientRename: %i [%s] (%s) \"%s^7\" -> \"%s^7\"%s\n", clientNum,
- client->pers.ip, client->pers.guid, oldname, client->pers.netname, decoloured );
- }
- else
- {
- G_LogPrintf( "ClientRename: %i [%s] (%s) \"%s^7\" -> \"%s^7\"%s\n", clientNum,
- client->pers.ip, client->pers.guid, oldname, client->pers.netname, decoloured );
- }
+ s = Info_ValueForKey(userinfo, "model");
- }
- else
+ for ( i = 0; i < level.playerModelCount; i++ )
+ {
+ if ( !strcmp(s, level.playerModel[i]) )
{
- G_LogPrintf( "ClientRename: %i [%s] (%s) \"%s^7\" -> \"%s^7\"\n", clientNum,
- client->pers.ip, client->pers.guid, oldname, client->pers.netname );
+ found = qtrue;
+ break;
}
- G_admin_namelog_update( client, qfalse );
}
- }
- // set max health
- health = atoi( Info_ValueForKey( userinfo, "handicap" ) );
- client->pers.maxHealth = health;
+ if ( !found )
+ s = NULL;
+ else if ( !g_cheats.integer
+ && !forceName
+ && !G_admin_permission( ent, va("MODEL%s", s) ) )
+ s = NULL;
- if( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 )
- client->pers.maxHealth = 100;
-
- //hack to force a client update if the config string does not change between spawning
- if( client->pers.classSelection == PCL_NONE )
- client->pers.maxHealth = 0;
-
- // set model
- if( client->ps.stats[ STAT_PCLASS ] == PCL_HUMAN && BG_InventoryContainsUpgrade( UP_BATTLESUIT, client->ps.stats ) )
+ if (s)
+ {
+ s2 = Info_ValueForKey(userinfo, "skin");
+ s2 = GetSkin(s, s2);
+ }
+ }
+ else
{
- Com_sprintf( buffer, MAX_QPATH, "%s/%s", BG_FindModelNameForClass( PCL_HUMAN_BSUIT ),
- BG_FindSkinNameForClass( PCL_HUMAN_BSUIT ) );
+ s = NULL;
}
- else if( client->pers.classSelection == PCL_NONE )
+
+ if( client->pers.classSelection == PCL_NONE )
{
//This looks hacky and frankly it is. The clientInfo string needs to hold different
//model details to that of the spawning class or the info change will not be
//registered and an axis appears instead of the player model. There is zero chance
//the player can spawn with the battlesuit, hence this choice.
- Com_sprintf( buffer, MAX_QPATH, "%s/%s", BG_FindModelNameForClass( PCL_HUMAN_BSUIT ),
- BG_FindSkinNameForClass( PCL_HUMAN_BSUIT ) );
+ Com_sprintf( buffer, MAX_QPATH, "%s/%s", BG_ClassConfig( PCL_HUMAN_BSUIT )->modelName,
+ BG_ClassConfig( PCL_HUMAN_BSUIT )->skinName );
}
else
{
- Com_sprintf( buffer, MAX_QPATH, "%s/%s", BG_FindModelNameForClass( client->pers.classSelection ),
- BG_FindSkinNameForClass( client->pers.classSelection ) );
- }
- Q_strncpyz( model, buffer, sizeof( model ) );
+ if ( !(client->pers.classSelection == PCL_HUMAN_BSUIT) && s )
+ {
+ Com_sprintf( buffer, MAX_QPATH, "%s/%s", s, s2 );
+ }
+ else
+ {
+ Com_sprintf( buffer, MAX_QPATH, "%s/%s", BG_ClassConfig( client->pers.classSelection )->modelName,
+ BG_ClassConfig( client->pers.classSelection )->skinName );
+ }
- //don't bother setting model type if spectating
- if( client->pers.classSelection != PCL_NONE )
- {
//model segmentation
Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg",
- BG_FindModelNameForClass( client->pers.classSelection ) );
+ BG_ClassConfig( client->pers.classSelection )->modelName );
if( G_NonSegModel( filename ) )
client->ps.persistant[ PERS_STATE ] |= PS_NONSEGMODEL;
else
client->ps.persistant[ PERS_STATE ] &= ~PS_NONSEGMODEL;
}
+ Q_strncpyz( model, buffer, sizeof( model ) );
// wallwalk follow
s = Info_ValueForKey( userinfo, "cg_wwFollow" );
@@ -1333,13 +988,44 @@ void ClientUserinfoChanged( int clientNum, qboolean forceName )
else
client->ps.persistant[ PERS_STATE ] &= ~PS_WALLCLIMBINGTOGGLE;
+ // always sprint
+ s = Info_ValueForKey( userinfo, "cg_sprintToggle" );
+
+ if( atoi( s ) )
+ client->ps.persistant[ PERS_STATE ] |= PS_SPRINTTOGGLE;
+ else
+ client->ps.persistant[ PERS_STATE ] &= ~PS_SPRINTTOGGLE;
+
+ // fly speed
+ s = Info_ValueForKey( userinfo, "cg_flySpeed" );
+
+ if( *s )
+ client->pers.flySpeed = atoi( s );
+ else
+ client->pers.flySpeed = BG_Class( PCL_NONE )->speed;
+
+ // disable blueprint errors
+ s = Info_ValueForKey( userinfo, "cg_disableBlueprintErrors" );
+
+ if( atoi( s ) )
+ client->pers.disableBlueprintErrors = qtrue;
+ else
+ client->pers.disableBlueprintErrors = qfalse;
+
+ client->pers.buildableRangeMarkerMask =
+ atoi( Info_ValueForKey( userinfo, "cg_buildableRangeMarkerMask" ) );
+
// teamInfo
s = Info_ValueForKey( userinfo, "teamoverlay" );
- if( ! *s || atoi( s ) != 0 )
- client->pers.teamInfo = qtrue;
+ if( atoi( s ) != 0 )
+ {
+ // teamoverlay was enabled so we need an update
+ if( client->pers.teamInfo == 0 )
+ client->pers.teamInfo = 1;
+ }
else
- client->pers.teamInfo = qfalse;
+ client->pers.teamInfo = 0;
s = Info_ValueForKey( userinfo, "cg_unlagged" );
if( !s[0] || atoi( s ) != 0 )
@@ -1347,67 +1033,26 @@ void ClientUserinfoChanged( int clientNum, qboolean forceName )
else
client->pers.useUnlagged = qfalse;
- // team task (0 = none, 1 = offence, 2 = defence)
- teamTask = atoi( Info_ValueForKey( userinfo, "teamtask" ) );
- // team Leader (1 = leader, 0 is normal player)
- teamLeader = client->sess.teamLeader;
-
- // colors
- strcpy( c1, Info_ValueForKey( userinfo, "color1" ) );
- strcpy( c2, Info_ValueForKey( userinfo, "color2" ) );
-
- team = client->pers.teamSelection;
+ Q_strncpyz( client->pers.voice, Info_ValueForKey( userinfo, "voice" ),
+ sizeof( client->pers.voice ) );
// send over a subset of the userinfo keys so other clients can
// print scoreboards, display models, and play custom sounds
- if ( client->sess.invisible != qtrue )
- {
- Com_sprintf( userinfo, sizeof( userinfo ),
- "n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\"
- "hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\"
- "tl\\%d\\ig\\%16s",
- client->pers.netname, team, model, model, c1, c2,
- client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask,
- teamLeader, BG_ClientListString( &client->sess.ignoreList ) );
-
- trap_SetConfigstring( CS_PLAYERS + clientNum, userinfo );
- } else {
- trap_SetConfigstring( CS_PLAYERS + clientNum, "" );
- }
+
+ Com_sprintf( userinfo, sizeof( userinfo ),
+ "n\\%s\\t\\%i\\model\\%s\\ig\\%16s\\v\\%s",
+ client->pers.netname, client->pers.teamSelection, model,
+ Com_ClientListString( &client->sess.ignoreList ),
+ client->pers.voice );
+
+ trap_SetConfigstring( CS_PLAYERS + clientNum, userinfo );
+
/*G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, userinfo );*/
-}
-/*
-===========
-LogAutobahn
-===========
-*/
-void G_LogAutobahn(gentity_t *ent, const char *userinfo, int rating,
- qboolean onConnect)
-{
- char ip_buffer[20];
- const char *ip, *name, *verb;
-
- verb = (onConnect ? "refused" : "dropped");
-
- if (userinfo) {
- Q_strncpyz(ip_buffer, Info_ValueForKey(userinfo, "ip"),
- sizeof(ip_buffer));
- ip = ip_buffer;
- name = Info_ValueForKey(userinfo, "name");
- } else {
- ip = ent->client->pers.ip;
- name = ent->client->pers.netname;
- }
-
- G_LogPrintf("Autobahn: %s %i %s %+i \"%s^7\"\n", verb, ent - g_entities,
- ip, rating, name);
-
- if (g_adminAutobahnNotify.integer)
- G_AdminsPrintf("Autobahn %s '%s^7' with rating %+i, connecting from %s.\n",
- verb, name, rating, ip);
+ return NULL;
}
+
/*
===========
ClientConnect
@@ -1428,52 +1073,59 @@ to the server machine, but qfalse on map changes and tournement
restarts.
============
*/
-char *ClientConnect( int clientNum, qboolean firstTime )
+const char *ClientConnect( int clientNum, qboolean firstTime )
{
char *value;
+ char *userInfoError;
gclient_t *client;
char userinfo[ MAX_INFO_STRING ];
gentity_t *ent;
- char guid[ 33 ];
- char ip[ 16 ] = {""};
char reason[ MAX_STRING_CHARS ] = {""};
int i;
ent = &g_entities[ clientNum ];
+ client = &level.clients[ clientNum ];
+
+ // ignore if client already connected
+ if( client->pers.connected != CON_DISCONNECTED )
+ return NULL;
+
+ ent->client = client;
+ memset( client, 0, sizeof( *client ) );
trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
value = Info_ValueForKey( userinfo, "cl_guid" );
- Q_strncpyz( guid, value, sizeof( guid ) );
-
- // check for admin ban
- if( G_admin_ban_check( userinfo, reason, sizeof( reason ) ) )
- {
- return va( "%s", reason );
- }
+ Q_strncpyz( client->pers.guid, value, sizeof( client->pers.guid ) );
- // IP filtering
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=500
- // recommanding PB based IP / GUID banning, the builtin system is pretty limited
- // check to see if they are on the banned IP list
value = Info_ValueForKey( userinfo, "ip" );
- i = 0;
- while( *value && i < sizeof( ip ) - 2 )
+ // check for local client
+ if( !strcmp( value, "localhost" ) )
+ client->pers.localClient = qtrue;
+ G_AddressParse( value, &client->pers.ip );
+
+ client->pers.admin = G_admin_admin( client->pers.guid );
+
+ client->pers.alternateProtocol = trap_Cvar_VariableIntegerValue( va( "sv_clAltProto%i", clientNum ) );
+
+ if( client->pers.alternateProtocol == 2 && client->pers.guid[ 0 ] == '\0' )
{
- if( *value != '.' && ( *value < '0' || *value > '9' ) )
- break;
- ip[ i++ ] = *value;
- value++;
+ size_t len = strlen( client->pers.ip.str );
+ if( len == 0 )
+ len = 1;
+ for( i = 0; i < sizeof( client->pers.guid ) - 1; ++i )
+ {
+ int j = client->pers.ip.str[ i % len ] + rand() / ( RAND_MAX / 16 + 1 );
+ client->pers.guid[ i ] = "0123456789ABCDEF"[ j % 16 ];
+ }
+ client->pers.guid[ sizeof( client->pers.guid ) - 1 ] = '\0';
+ client->pers.guidless = qtrue;
}
- ip[ i ] = '\0';
- if( G_FilterPacket( value ) )
- return "You are banned from this server.";
- if( strlen( ip ) < 7 && strcmp( Info_ValueForKey( userinfo, "ip" ), "localhost" ) )
+ // check for admin ban
+ if( G_admin_ban_check( ent, reason, sizeof( reason ) ) )
{
- G_AdminsPrintf( "Connect from client with invalid IP: '%s' NAME: '%s^7'\n",
- ip, Info_ValueForKey( userinfo, "name" ) );
- return "Invalid client data";
+ return va( "%s", reason );
}
// check for a password
@@ -1483,66 +1135,12 @@ char *ClientConnect( int clientNum, qboolean firstTime )
strcmp( g_password.string, value ) != 0 )
return "Invalid password";
- schachtmeisterJudgement_t *smj = NULL;
-
- if (!(G_admin_permission_guid(guid, ADMF_NOAUTOBAHN)
- || G_admin_permission_guid(guid, ADMF_IMMUNITY)))
- {
- extern g_admin_namelog_t *g_admin_namelog[128];
- for (i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[i]; ++i)
- {
- if (!Q_stricmp(g_admin_namelog[i]->ip, ip)
- || !Q_stricmp(g_admin_namelog[i]->guid, guid))
- {
- schachtmeisterJudgement_t *j = &g_admin_namelog[i]->smj;
- if (j->ratingTime)
- {
- if (j->rating >= g_schachtmeisterClearThreshold.integer)
- break;
- else if (j->rating <= g_schachtmeisterAutobahnThreshold.integer)
- {
- G_LogAutobahn( ent, userinfo, j->rating, qtrue );
- return g_schachtmeisterAutobahnMessage.string;
- }
- smj = j;
- }
- break;
- }
- }
- }
-
- // they can connect
- ent->client = level.clients + clientNum;
- client = ent->client;
-
- memset( client, 0, sizeof(*client) );
-
// add guid to session so we don't have to keep parsing userinfo everywhere
- if( !guid[ 0 ] )
- {
- Q_strncpyz( client->pers.guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
- sizeof( client->pers.guid ) );
- }
- else
- {
- Q_strncpyz( client->pers.guid, guid, sizeof( client->pers.guid ) );
- }
+ for( i = 0; i < sizeof( client->pers.guid ) - 1 &&
+ isxdigit( client->pers.guid[ i ] ); i++ );
- Q_strncpyz( client->pers.ip, ip, sizeof( client->pers.ip ) );
- client->pers.adminLevel = G_admin_level( ent );
-
- // do autoghost now so that there won't be any name conflicts later on
- if ( g_autoGhost.integer && client->pers.guid[ 0 ] != 'X' )
- {
- for ( i = 0; i < MAX_CLIENTS; i++ )
- {
- if ( i != ent - g_entities && g_entities[i].client && g_entities[i].client->pers.connected != CON_DISCONNECTED && !Q_stricmp( g_entities[i].client->pers.guid, client->pers.guid ) )
- {
- trap_SendServerCommand( i, "disconnect \"You may not be connected to this server multiple times\"" );
- trap_DropClient( i, "disconnected" );
- }
- }
- }
+ if( i < sizeof( client->pers.guid ) - 1 )
+ return "Invalid GUID";
client->pers.connected = CON_CONNECTING;
@@ -1552,81 +1150,36 @@ char *ClientConnect( int clientNum, qboolean firstTime )
G_ReadSessionData( client );
- if( firstTime )
- client->pers.firstConnect = qtrue;
- else
- client->pers.firstConnect = qfalse;
-
// get and distribute relevent paramters
- ClientUserinfoChanged( clientNum, qfalse );
-
- G_admin_set_adminname( ent );
-
- if( g_decolourLogfiles.integer )
- {
- char decoloured[ MAX_STRING_CHARS ] = "";
- if( g_decolourLogfiles.integer == 1 )
- {
- Com_sprintf( decoloured, sizeof(decoloured), " (\"%s^7\")", client->pers.netname );
- G_DecolorString( decoloured, decoloured );
- G_LogPrintfColoured( "ClientConnect: %i [%s] (%s) \"%s^7\"%s\n", clientNum,
- client->pers.ip, client->pers.guid, client->pers.netname, decoloured );
- }
- else
- {
- G_LogPrintf( "ClientConnect: %i [%s] (%s) \"%s^7\"%s\n", clientNum,
- client->pers.ip, client->pers.guid, client->pers.netname, decoloured );
- }
- }
- else
- {
- G_LogPrintf( "ClientConnect: %i [%s] (%s) \"%s^7\"\n", clientNum,
- client->pers.ip, client->pers.guid, client->pers.netname );
- }
-
- if( client->pers.adminLevel )
- {
- G_LogPrintf( "ClientAuth: %i [%s] \"%s^7\" authenticated to admin level %i using GUID %s (^7%s)\n", clientNum, client->pers.ip, client->pers.netname, client->pers.adminLevel, client->pers.guid, client->pers.adminName );
- }
+ G_namelog_connect( client );
+ userInfoError = ClientUserinfoChanged( clientNum, qfalse );
+ if( userInfoError != NULL )
+ return userInfoError;
+
+ G_LogPrintf( "ClientConnect: %i [%s] (%s) \"%s^7\" \"%c%s%c^7\"\n",
+ clientNum, client->pers.ip.str, client->pers.guid,
+ client->pers.netname,
+ DECOLOR_OFF, client->pers.netname, DECOLOR_ON );
// don't do the "xxx connected" messages if they were caried over from previous level
- if( client->sess.invisible != qtrue )
- {
- if( firstTime )
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname ) );
+ if( firstTime )
+ trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"",
+ client->pers.netname ) );
- // count current clients and rank for scoreboard
- CalculateRanks( );
- G_admin_namelog_update( client, qfalse );
- }
+ if( client->pers.admin )
+ G_admin_authlog( ent );
+
+ // count current clients and rank for scoreboard
+ CalculateRanks( );
+
// if this is after !restart keepteams or !restart switchteams, apply said selection
- if ( client->sess.restartTeam != PTE_NONE ) {
+ if ( client->sess.restartTeam != TEAM_NONE )
+ {
G_ChangeTeam( ent, client->sess.restartTeam );
- client->sess.restartTeam = PTE_NONE;
+ client->sess.restartTeam = TEAM_NONE;
}
- if( !( G_admin_permission( ent, ADMF_NOAUTOBAHN ) ||
- G_admin_permission( ent, ADMF_IMMUNITY ) ) )
- {
- extern g_admin_namelog_t *g_admin_namelog[ 128 ];
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- {
- if( !Q_stricmp( ip, g_admin_namelog[ i ]->ip ) || !Q_stricmp( guid, g_admin_namelog[ i ]->guid ) )
- {
- schachtmeisterJudgement_t *j = &g_admin_namelog[i]->smj;
- if( j->ratingTime )
- {
- if( j->rating >= g_schachtmeisterClearThreshold.integer )
- break;
- else if( j->rating <= g_schachtmeisterAutobahnThreshold.integer )
- return g_schachtmeisterAutobahnMessage.string;
- G_AdminsPrintf( "%s^7 (#%d) has rating %d\n", ent->client->pers.netname, ent - g_entities, j->rating );
- }
- break;
- }
- }
- }
return NULL;
}
@@ -1635,9 +1188,9 @@ char *ClientConnect( int clientNum, qboolean firstTime )
===========
ClientBegin
-called when a client has finished connecting, and is ready
-to be placed into the level. This will happen every level load,
-and on transition between teams, but doesn't happen on respawns
+Called when a client has finished connecting, and is ready
+to be placed into the level. This will happen on every
+level load and level restart, but doesn't happen on respawns.
============
*/
void ClientBegin( int clientNum )
@@ -1650,6 +1203,10 @@ void ClientBegin( int clientNum )
client = level.clients + clientNum;
+ // ignore if client already entered the game
+ if( client->pers.connected != CON_CONNECTING )
+ return;
+
if( ent->r.linked )
trap_UnlinkEntity( ent );
@@ -1660,8 +1217,6 @@ void ClientBegin( int clientNum )
client->pers.connected = CON_CONNECTED;
client->pers.enterTime = level.time;
- client->pers.teamState.state = TEAM_BEGIN;
- client->pers.classSelection = PCL_NONE;
// save eflags around this, because changing teams will
// cause this to happen with a valid entity, and we
@@ -1674,44 +1229,19 @@ void ClientBegin( int clientNum )
client->ps.eFlags = flags;
// locate ent at a spawn point
-
ClientSpawn( ent, NULL, NULL, NULL );
- // Ignore invisible players for this section:
- if ( client->sess.invisible != qtrue )
- {
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname ) );
-
- // auto denybuild
- if( G_admin_permission( ent, ADMF_NO_BUILD ) )
- client->pers.denyBuild = qtrue;
-
- // auto mute flag
- if( G_admin_permission( ent, ADMF_NO_CHAT ) )
- client->pers.muted = qtrue;
+ trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname ) );
- // name can change between ClientConnect() and ClientBegin()
- G_admin_namelog_update( client, qfalse );
+ G_namelog_restore( client );
- if( g_scrimMode.integer == 1 )
- {
- ADMP( "^5Scrim mode is enabled. Teams are locked and you can only use spectator chat.\n" );
- }
-
- // request the clients PTR code
- trap_SendServerCommand( ent - g_entities, "ptrcrequest" );
- }
G_LogPrintf( "ClientBegin: %i\n", clientNum );
- if( !Q_stricmp( ent->client->pers.guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ) &&
- g_outdatedClientMessage.string[0] )
- {
- trap_SendServerCommand( client->ps.clientNum, va(
- "print \"%s\n\"", g_outdatedClientMessage.string ) );
- }
-
// count current clients and rank for scoreboard
CalculateRanks( );
+
+ // send the client a list of commands that can be used
+ G_ListCommands( ent );
}
/*
@@ -1723,7 +1253,7 @@ after the first ClientBegin, and after each respawn
Initializes all non-persistant parts of playerState
============
*/
-void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles )
+void ClientSpawn( gentity_t *ent, gentity_t *spawn, const vec3_t origin, const vec3_t angles )
{
int index;
vec3_t spawn_origin, spawn_angles;
@@ -1731,8 +1261,8 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
int i;
clientPersistant_t saved;
clientSession_t savedSess;
+ qboolean savedNoclip, savedCliprcontents;
int persistant[ MAX_PERSISTANT ];
- gentity_t *spawnPoint = NULL;
int flags;
int savedPing;
int teamLocal;
@@ -1742,75 +1272,65 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
int maxAmmo, maxClips;
weapon_t weapon;
-
index = ent - g_entities;
client = ent->client;
teamLocal = client->pers.teamSelection;
- //TA: only start client if chosen a class and joined a team
- if( client->pers.classSelection == PCL_NONE && teamLocal == PTE_NONE )
+ //if client is dead and following teammate, stop following before spawning
+ if( client->sess.spectatorClient != -1 )
{
- client->sess.sessionTeam = TEAM_SPECTATOR;
+ client->sess.spectatorClient = -1;
client->sess.spectatorState = SPECTATOR_FREE;
}
+
+ // only start client if chosen a class and joined a team
+ if( client->pers.classSelection == PCL_NONE && teamLocal == TEAM_NONE )
+ client->sess.spectatorState = SPECTATOR_FREE;
else if( client->pers.classSelection == PCL_NONE )
- {
- client->sess.sessionTeam = TEAM_SPECTATOR;
client->sess.spectatorState = SPECTATOR_LOCKED;
- }
-
- //if client is dead and following teammate, stop following before spawning
- if(ent->client->sess.spectatorClient!=-1)
- {
- ent->client->sess.spectatorClient = -1;
- ent->client->sess.spectatorState = SPECTATOR_FREE;
- }
-
- if( origin != NULL )
- VectorCopy( origin, spawn_origin );
- if( angles != NULL )
- VectorCopy( angles, spawn_angles );
+ // if client is dead and following teammate, stop following before spawning
+ if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
+ G_StopFollowing( ent );
// find a spawn point
// do it before setting health back up, so farthest
// ranging doesn't count this client
- if( client->sess.sessionTeam == TEAM_SPECTATOR )
+ if( client->sess.spectatorState != SPECTATOR_NOT )
{
- if( teamLocal == PTE_NONE )
- spawnPoint = G_SelectSpectatorSpawnPoint( spawn_origin, spawn_angles );
- else if( teamLocal == PTE_ALIENS )
- spawnPoint = G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles );
- else if( teamLocal == PTE_HUMANS )
- spawnPoint = G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles );
+ if( teamLocal == TEAM_ALIENS )
+ spawn = G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles );
+ else if( teamLocal == TEAM_HUMANS )
+ spawn = G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles );
+ else
+ spawn = G_SelectSpectatorSpawnPoint( spawn_origin, spawn_angles );
}
else
{
- if( spawn == NULL )
+ if( origin == NULL || angles == NULL )
{
- G_Error( "ClientSpawn: spawn is NULL\n" );
+ G_Error( "ClientSpawn: origin or angles is NULL" );
return;
}
- spawnPoint = spawn;
+ VectorCopy( origin, spawn_origin );
+ VectorCopy( angles, spawn_angles );
- if( ent != spawn )
+ if( spawn != NULL && spawn != ent )
{
//start spawn animation on spawnPoint
- G_SetBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue );
+ G_SetBuildableAnim( spawn, BANIM_SPAWN1, qtrue );
- if( spawnPoint->biteam == PTE_ALIENS )
- spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME;
- else if( spawnPoint->biteam == PTE_HUMANS )
- spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME;
+ if( spawn->buildableTeam == TEAM_ALIENS )
+ spawn->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME;
+ else if( spawn->buildableTeam == TEAM_HUMANS )
+ spawn->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME;
}
}
- client->pers.teamState.state = TEAM_ACTIVE;
// toggle the teleport bit so the client knows to not lerp
- flags = ent->client->ps.eFlags & ( EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED );
- flags ^= EF_TELEPORT_BIT;
+ flags = ( ent->client->ps.eFlags & EF_TELEPORT_BIT ) ^ EF_TELEPORT_BIT;
G_UnlaggedClear( ent );
// clear everything but the persistant data
@@ -1818,6 +1338,8 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
saved = client->pers;
savedSess = client->sess;
savedPing = client->ps.ping;
+ savedNoclip = client->noclip;
+ savedCliprcontents = client->cliprcontents;
for( i = 0; i < MAX_PERSISTANT; i++ )
persistant[ i ] = client->ps.persistant[ i ];
@@ -1828,6 +1350,8 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
client->pers = saved;
client->sess = savedSess;
client->ps.ping = savedPing;
+ client->noclip = savedNoclip;
+ client->cliprcontents = savedCliprcontents;
client->lastkilled_client = -1;
for( i = 0; i < MAX_PERSISTANT; i++ )
@@ -1837,11 +1361,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
// increment the spawncount so the client will detect the respawn
client->ps.persistant[ PERS_SPAWN_COUNT ]++;
- client->ps.persistant[ PERS_TEAM ] = client->sess.sessionTeam;
-
- // restore really persistant things
- client->ps.persistant[ PERS_SCORE ] = client->pers.score;
- client->ps.persistant[ PERS_CREDIT ] = client->pers.credit;
+ client->ps.persistant[ PERS_SPECSTATE ] = client->sess.spectatorState;
client->airOutTime = level.time + 12000;
@@ -1853,52 +1373,58 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
ent->s.groundEntityNum = ENTITYNUM_NONE;
ent->client = &level.clients[ index ];
ent->takedamage = qtrue;
- ent->inuse = qtrue;
ent->classname = "player";
- ent->r.contents = CONTENTS_BODY;
- ent->clipmask = MASK_PLAYERSOLID;
+ if( client->noclip )
+ client->cliprcontents = CONTENTS_BODY;
+ else
+ ent->r.contents = CONTENTS_BODY;
+ if( client->pers.teamSelection == TEAM_NONE )
+ ent->clipmask = MASK_DEADSOLID;
+ else
+ ent->clipmask = MASK_PLAYERSOLID;
ent->die = player_die;
ent->waterlevel = 0;
ent->watertype = 0;
- ent->flags = 0;
+ ent->flags &= FL_GODMODE | FL_NOTARGET;
- //TA: calculate each client's acceleration
+ // calculate each client's acceleration
ent->evaluateAcceleration = qtrue;
- client->ps.stats[ STAT_WEAPONS ] = 0;
- client->ps.stats[ STAT_WEAPONS2 ] = 0;
- client->ps.stats[ STAT_SLOTS ] = 0;
+ client->ps.stats[ STAT_MISC ] = 0;
client->ps.eFlags = flags;
client->ps.clientNum = index;
- BG_FindBBoxForClass( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, NULL, NULL, NULL );
+ BG_ClassBoundingBox( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, NULL, NULL, NULL );
- if( client->sess.sessionTeam != TEAM_SPECTATOR )
- client->pers.maxHealth = client->ps.stats[ STAT_MAX_HEALTH ] =
- BG_FindHealthForClass( ent->client->pers.classSelection );
+ if( client->sess.spectatorState == SPECTATOR_NOT )
+ client->ps.stats[ STAT_MAX_HEALTH ] =
+ BG_Class( ent->client->pers.classSelection )->health;
else
- client->pers.maxHealth = client->ps.stats[ STAT_MAX_HEALTH ] = 100;
+ client->ps.stats[ STAT_MAX_HEALTH ] = 100;
// clear entity values
if( ent->client->pers.classSelection == PCL_HUMAN )
{
- BG_AddWeaponToInventory( WP_BLASTER, client->ps.stats );
BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats );
weapon = client->pers.humanItemSelection;
}
- else if( client->sess.sessionTeam != TEAM_SPECTATOR )
- weapon = BG_FindStartWeaponForClass( ent->client->pers.classSelection );
+ else if( client->sess.spectatorState == SPECTATOR_NOT )
+ weapon = BG_Class( ent->client->pers.classSelection )->startWeapon;
else
weapon = WP_NONE;
- BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips );
- BG_AddWeaponToInventory( weapon, client->ps.stats );
+ maxAmmo = BG_Weapon( weapon )->maxAmmo;
+ maxClips = BG_Weapon( weapon )->maxClips;
+ client->ps.stats[ STAT_WEAPON ] = weapon;
client->ps.ammo = maxAmmo;
client->ps.clips = maxClips;
- ent->client->ps.stats[ STAT_PCLASS ] = ent->client->pers.classSelection;
- ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.teamSelection;
+ // We just spawned, not changing weapons
+ client->ps.persistant[ PERS_NEWWEAPON ] = 0;
+
+ ent->client->ps.stats[ STAT_CLASS ] = ent->client->pers.classSelection;
+ ent->client->ps.stats[ STAT_TEAM ] = ent->client->pers.teamSelection;
ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
ent->client->ps.stats[ STAT_STATE ] = 0;
@@ -1911,18 +1437,14 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
if( ent == spawn )
{
ent->health *= ent->client->pers.evolveHealthFraction;
- client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction;
+ client->ps.stats[ STAT_HEALTH ] = ent->health;
}
//clear the credits array
for( i = 0; i < MAX_CLIENTS; i++ )
ent->credits[ i ] = 0;
- client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA;
-
- if( mod_jetpackFuel.value >= 10.0f ) {
- client->jetpackfuel = mod_jetpackFuel.value;
- }
+ client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
G_SetOrigin( ent, spawn_origin );
VectorCopy( spawn_origin, client->ps.origin );
@@ -1931,10 +1453,14 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
#define F_VEL 50.0f
//give aliens some spawn velocity
- if( client->sess.sessionTeam != TEAM_SPECTATOR &&
- client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( client->sess.spectatorState == SPECTATOR_NOT &&
+ client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
- if( ent == spawn )
+ if( spawn == NULL )
+ {
+ G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 );
+ }
+ else if( ent == spawn )
{
//evolution particle system
G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) );
@@ -1944,13 +1470,13 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
spawn_angles[ YAW ] += 180.0f;
AngleNormalize360( spawn_angles[ YAW ] );
- if( spawnPoint->s.origin2[ 2 ] > 0.0f )
+ if( spawn->s.origin2[ 2 ] > 0.0f )
{
vec3_t forward, dir;
AngleVectors( spawn_angles, forward, NULL, NULL );
VectorScale( forward, F_VEL, forward );
- VectorAdd( spawnPoint->s.origin2, forward, dir );
+ VectorAdd( spawn->s.origin2, forward, dir );
VectorNormalize( dir );
VectorScale( dir, UP_VEL, client->ps.velocity );
@@ -1959,11 +1485,14 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 );
}
}
- else if( client->sess.sessionTeam != TEAM_SPECTATOR &&
- client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ else if( client->sess.spectatorState == SPECTATOR_NOT &&
+ client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
- spawn_angles[ YAW ] += 180.0f;
- AngleNormalize360( spawn_angles[ YAW ] );
+ if( spawn != NULL )
+ {
+ spawn_angles[ YAW ] += 180.0f;
+ AngleNormalize360( spawn_angles[ YAW ] );
+ }
}
// the respawned flag will be cleared after the attack and jump keys come up
@@ -1972,13 +1501,14 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd );
G_SetClientViewAngle( ent, spawn_angles );
- if( !( client->sess.sessionTeam == TEAM_SPECTATOR ) )
+ if( client->sess.spectatorState == SPECTATOR_NOT )
{
- /*G_KillBox( ent );*/ //blame this if a newly spawned client gets stuck in another
trap_LinkEntity( ent );
// force the base weapon up
- client->ps.weapon = WP_NONE;
+ if( client->pers.teamSelection == TEAM_HUMANS )
+ G_ForceWeaponChange( ent, weapon );
+
client->ps.weaponstate = WEAPON_READY;
}
@@ -1987,8 +1517,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
client->ps.pm_time = 100;
client->respawnTime = level.time;
- if( g_gradualFreeFunds.integer < 2 )
- client->pers.lastFreekillTime = level.time;
+ ent->nextRegenTime = level.time;
client->inactivityTime = level.time + g_inactivity.integer * 1000;
client->latched_buttons = 0;
@@ -2002,21 +1531,10 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
else
{
// fire the targets of the spawn point
- if( !spawn )
- G_UseTargets( spawnPoint, ent );
+ if( spawn != NULL && spawn != ent )
+ G_UseTargets( spawn, ent );
- // select the highest weapon number available, after any
- // spawn given items have fired
- client->ps.weapon = 1;
-
- for( i = WP_NUM_WEAPONS - 1; i > 0 ; i-- )
- {
- if( BG_InventoryContainsWeapon( i, client->ps.stats ) )
- {
- client->ps.weapon = i;
- break;
- }
- }
+ client->ps.weapon = client->ps.stats[ STAT_WEAPON ];
}
// run a client frame to drop exactly to the floor,
@@ -2025,15 +1543,16 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
ent->client->pers.cmd.serverTime = level.time;
ClientThink( ent-g_entities );
+ VectorCopy( ent->client->ps.viewangles, ent->r.currentAngles );
+ VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
// positively link the client, even if the command times are weird
- if( client->sess.sessionTeam != TEAM_SPECTATOR )
+ if( client->sess.spectatorState == SPECTATOR_NOT )
{
BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
- VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
trap_LinkEntity( ent );
}
- //TA: must do this here so the number of active clients is calculated
+ // must do this here so the number of active clients is calculated
CalculateRanks( );
// run the presend to set anything else
@@ -2041,6 +1560,8 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
// clear entity state values
BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
+
+ client->pers.infoChangeTime = level.time;
}
@@ -2061,55 +1582,40 @@ void ClientDisconnect( int clientNum )
gentity_t *ent;
gentity_t *tent;
int i;
- buildHistory_t *ptr;
ent = g_entities + clientNum;
- if( !ent->client )
+ if( !ent->client || ent->client->pers.connected == CON_DISCONNECTED )
return;
- // look through the bhist and readjust it if the referenced ent has left
- for( ptr = level.buildHistory; ptr; ptr = ptr->next )
- {
- if( ptr->ent == ent )
- {
- ptr->ent = NULL;
- Q_strncpyz( ptr->name, ent->client->pers.netname, MAX_NETNAME );
- }
- }
-
- if ( ent->client->sess.invisible != qtrue )
- G_admin_namelog_update( ent->client, qtrue );
G_LeaveTeam( ent );
+ G_namelog_disconnect( ent->client );
+ G_Vote( ent, TEAM_NONE, qfalse );
// stop any following clients
for( i = 0; i < level.maxclients; i++ )
{
// remove any /ignore settings for this clientNum
- BG_ClientListRemove( &level.clients[ i ].sess.ignoreList, clientNum );
+ Com_ClientListRemove( &level.clients[ i ].sess.ignoreList, clientNum );
}
// send effect if they were completely connected
if( ent->client->pers.connected == CON_CONNECTED &&
- ent->client->sess.sessionTeam != TEAM_SPECTATOR )
+ ent->client->sess.spectatorState == SPECTATOR_NOT )
{
tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
tent->s.clientNum = ent->s.clientNum;
}
- if( ent->client->pers.connection )
- ent->client->pers.connection->clientNum = -1;
-
- G_LogPrintf( "ClientDisconnect: %i [%s] (%s) \"%s\"\n", clientNum,
- ent->client->pers.ip, ent->client->pers.guid, ent->client->pers.netname );
+ G_LogPrintf( "ClientDisconnect: %i [%s] (%s) \"%s^7\"\n", clientNum,
+ ent->client->pers.ip.str, ent->client->pers.guid, ent->client->pers.netname );
trap_UnlinkEntity( ent );
- ent->s.modelindex = 0;
ent->inuse = qfalse;
ent->classname = "disconnected";
ent->client->pers.connected = CON_DISCONNECTED;
- ent->client->ps.persistant[ PERS_TEAM ] = TEAM_FREE;
- ent->client->sess.sessionTeam = TEAM_FREE;
+ ent->client->sess.spectatorState =
+ ent->client->ps.persistant[ PERS_SPECSTATE ] = SPECTATOR_NOT;
trap_SetConfigstring( CS_PLAYERS + clientNum, "");
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index c380b45..4dccf6a 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,59 +17,41 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
#include "g_local.h"
+static qboolean G_RoomForClassChange( gentity_t*, class_t, vec3_t );
+
/*
==================
G_SanitiseString
-Remove case and control characters from a player name
+Remove color codes and non-alphanumeric characters from a string
==================
*/
void G_SanitiseString( char *in, char *out, int len )
{
- qboolean skip = qtrue;
- int spaces = 0;
+ len--;
while( *in && len > 0 )
{
- // strip leading white space
- if( *in == ' ' )
- {
- if( skip )
- {
- in++;
- continue;
- }
- spaces++;
- }
- else
- {
- spaces = 0;
- skip = qfalse;
- }
-
if( Q_IsColorString( in ) )
{
in += 2; // skip color code
continue;
}
- if( *in < 32 )
+ if( isalnum( *in ) )
{
- in++;
- continue;
+ *out++ = tolower( *in );
+ len--;
}
-
- *out++ = tolower( *in++ );
- len--;
+ in++;
}
- out -= spaces;
*out = 0;
}
@@ -77,36 +60,69 @@ void G_SanitiseString( char *in, char *out, int len )
G_ClientNumberFromString
Returns a player number for either a number or name string
-Returns -1 if invalid
+Returns -1 and optionally sets err if invalid or not exactly 1 match
+err will have a trailing \n if set
==================
*/
-int G_ClientNumberFromString( gentity_t *to, char *s )
+int G_ClientNumberFromString( char *s, char *err, int len )
{
gclient_t *cl;
- int idnum;
- char s2[ MAX_STRING_CHARS ];
- char n2[ MAX_STRING_CHARS ];
+ int i, found = 0, m = -1;
+ char s2[ MAX_NAME_LENGTH ];
+ char n2[ MAX_NAME_LENGTH ];
+ char *p = err;
+ int l, l2 = len;
+
+ if( !s[ 0 ] )
+ {
+ if( p )
+ Q_strncpyz( p, "no player name or slot # provided\n", len );
+
+ return -1;
+ }
// numeric values are just slot numbers
- if( s[ 0 ] >= '0' && s[ 0 ] <= '9' )
+ for( i = 0; s[ i ] && isdigit( s[ i ] ); i++ );
+ if( !s[ i ] )
{
- idnum = atoi( s );
+ i = atoi( s );
- if( idnum < 0 || idnum >= level.maxclients )
+ if( i < 0 || i >= level.maxclients )
return -1;
- cl = &level.clients[ idnum ];
+ cl = &level.clients[ i ];
if( cl->pers.connected == CON_DISCONNECTED )
+ {
+ if( p )
+ Q_strncpyz( p, "no player connected in that slot #\n", len );
+
return -1;
+ }
- return idnum;
+ return i;
}
- // check for a name match
G_SanitiseString( s, s2, sizeof( s2 ) );
+ if( !s2[ 0 ] )
+ {
+ if( p )
+ Q_strncpyz( p, "no player name provided\n", len );
- for( idnum = 0, cl = level.clients; idnum < level.maxclients; idnum++, cl++ )
+ return -1;
+ }
+
+ if( p )
+ {
+ Q_strncpyz( p, "more than one player name matches. "
+ "be more specific or use the slot #:\n", l2 );
+ l = strlen( p );
+ p += l;
+ l2 -= l;
+ }
+
+ // check for a name match
+ for( i = 0, cl = level.clients; i < level.maxclients; i++, cl++ )
{
if( cl->pers.connected == CON_DISCONNECTED )
continue;
@@ -114,54 +130,29 @@ int G_ClientNumberFromString( gentity_t *to, char *s )
G_SanitiseString( cl->pers.netname, n2, sizeof( n2 ) );
if( !strcmp( n2, s2 ) )
- return idnum;
- }
-
- return -1;
-}
-
-
-/*
-==================
-G_MatchOnePlayer
-
-This is a companion function to G_ClientNumbersFromString()
-
-returns qtrue if the int array plist only has one client id, false otherwise
-In the case of false, err will be populated with an error message.
-==================
-*/
-qboolean G_MatchOnePlayer( int *plist, char *err, int len )
-{
- gclient_t *cl;
- int *p;
- char line[ MAX_NAME_LENGTH + 10 ] = {""};
+ return i;
- err[ 0 ] = '\0';
- if( plist[ 0 ] == -1 )
- {
- Q_strcat( err, len, "no connected player by that name or slot #" );
- return qfalse;
- }
- if( plist[ 1 ] != -1 )
- {
- Q_strcat( err, len, "more than one player name matches. "
- "be more specific or use the slot #:\n" );
- for( p = plist; *p != -1; p++ )
+ if( strstr( n2, s2 ) )
{
- cl = &level.clients[ *p ];
- if( cl->pers.connected == CON_CONNECTED )
+ if( p )
{
- Com_sprintf( line, sizeof( line ), "%2i - %s^7\n",
- *p, cl->pers.netname );
- if( strlen( err ) + strlen( line ) > len )
- break;
- Q_strcat( err, len, line );
+ l = Q_snprintf( p, l2, "%-2d - %s^7\n", i, cl->pers.netname );
+ p += l;
+ l2 -= l;
}
+
+ found++;
+ m = i;
}
- return qfalse;
}
- return qtrue;
+
+ if( found == 1 )
+ return m;
+
+ if( found == 0 && err )
+ Q_strncpyz( err, "no connected player by that name or slot #\n", len );
+
+ return -1;
}
/*
@@ -171,22 +162,27 @@ G_ClientNumbersFromString
Sets plist to an array of integers that represent client numbers that have
names that are a partial match for s.
-Returns number of matching clientids up to MAX_CLIENTS.
+Returns number of matching clientids up to max.
==================
*/
-int G_ClientNumbersFromString( char *s, int *plist)
+int G_ClientNumbersFromString( char *s, int *plist, int max )
{
gclient_t *p;
int i, found = 0;
+ char *endptr;
char n2[ MAX_NAME_LENGTH ] = {""};
char s2[ MAX_NAME_LENGTH ] = {""};
- int max = MAX_CLIENTS;
- // if a number is provided, it might be a slot #
- for( i = 0; s[ i ] && isdigit( s[ i ] ); i++ );
- if( !s[ i ] )
+ if( max == 0 )
+ return 0;
+
+ if( !s[ 0 ] )
+ return 0;
+
+ // if a number is provided, it is a clientnum
+ i = strtol( s, &endptr, 10 );
+ if( *endptr == '\0' )
{
- i = atoi( s );
if( i >= 0 && i < level.maxclients )
{
p = &level.clients[ i ];
@@ -197,15 +193,14 @@ int G_ClientNumbersFromString( char *s, int *plist)
}
}
// we must assume that if only a number is provided, it is a clientNum
- *plist = -1;
return 0;
}
// now look for name matches
G_SanitiseString( s, s2, sizeof( s2 ) );
- if( strlen( s2 ) < 1 )
+ if( !s2[ 0 ] )
return 0;
- for( i = 0; i < level.maxclients && found <= max; i++ )
+ for( i = 0; i < level.maxclients && found < max; i++ )
{
p = &level.clients[ i ];
if( p->pers.connected == CON_DISCONNECTED )
@@ -219,7 +214,6 @@ int G_ClientNumbersFromString( char *s, int *plist)
found++;
}
}
- *plist = -1;
return found;
}
@@ -254,15 +248,12 @@ void ScoreboardMessage( gentity_t *ent )
if( cl->pers.connected == CON_CONNECTING )
ping = -1;
- else if( cl->sess.spectatorState == SPECTATOR_FOLLOW )
- ping = cl->pers.ping < 999 ? cl->pers.ping : 999;
else
ping = cl->ps.ping < 999 ? cl->ps.ping : 999;
- //If (loop) client is a spectator, they have nothing, so indicate such.
- //Only send the client requesting the scoreboard the weapon/upgrades information for members of their team. If they are not on a team, send it all.
- if( cl->sess.sessionTeam != TEAM_SPECTATOR &&
- (ent->client->pers.teamSelection == PTE_NONE || cl->pers.teamSelection == ent->client->pers.teamSelection ) )
+ if( cl->sess.spectatorState == SPECTATOR_NOT &&
+ ( ent->client->pers.teamSelection == TEAM_NONE ||
+ cl->pers.teamSelection == ent->client->pers.teamSelection ) )
{
weapon = cl->ps.weapon;
@@ -286,19 +277,19 @@ void ScoreboardMessage( gentity_t *ent )
}
Com_sprintf( entry, sizeof( entry ),
- " %d %d %d %d %d %d", level.sortedClients[ i ], cl->pers.score, ping,
- ( level.time - cl->pers.enterTime ) / 60000, weapon, upgrade );
+ " %d %d %d %d %d %d", level.sortedClients[ i ], cl->ps.persistant[ PERS_SCORE ],
+ ping, ( level.time - cl->pers.enterTime ) / 60000, weapon, upgrade );
j = strlen( entry );
- if( stringlength + j > 1024 )
+ if( stringlength + j >= sizeof( string ) )
break;
strcpy( string + stringlength, entry );
stringlength += j;
}
- trap_SendServerCommand( ent-g_entities, va( "scores %i %i %i%s", i,
+ trap_SendServerCommand( ent-g_entities, va( "scores %i %i%s",
level.alienKills, level.humanKills, string ) );
}
@@ -346,50 +337,120 @@ char *ConcatArgs( int start )
/*
==================
-G_Flood_Limited
-
-Determine whether a user is flood limited, and adjust their flood demerits
+ConcatArgsPrintable
+Duplicate of concatargs but enquotes things that need to be
+Used to log command arguments in a way that preserves user intended tokenizing
==================
*/
+char *ConcatArgsPrintable( int start )
+{
+ int i, c, tlen;
+ static char line[ MAX_STRING_CHARS ];
+ int len;
+ char arg[ MAX_STRING_CHARS + 2 ];
+ const char* printArg;
-qboolean G_Flood_Limited( gentity_t *ent )
+ len = 0;
+ c = trap_Argc( );
+
+ for( i = start; i < c; i++ )
+ {
+ printArg = arg;
+ trap_Argv( i, arg, sizeof( arg ) );
+ if( strchr( arg, ' ' ) )
+ printArg = va( "\"%s\"", arg );
+ tlen = strlen( printArg );
+
+ if( len + tlen >= MAX_STRING_CHARS - 1 )
+ break;
+
+ memcpy( line + len, printArg, tlen );
+ len += tlen;
+
+ if( len == MAX_STRING_CHARS - 1 )
+ break;
+
+ if( i != c - 1 )
+ {
+ line[ len ] = ' ';
+ len++;
+ }
+ }
+
+ line[ len ] = 0;
+
+ return line;
+}
+
+static void Give_Class( gentity_t *ent, char *s )
{
- int millisSinceLastCommand;
- int maximumDemerits;
+ class_t currentClass = ent->client->pers.classSelection;
+ int clientNum = ent->client - level.clients;
+ vec3_t infestOrigin;
+ vec3_t oldVel;
+ int oldBoostTime = -1;
+ int newClass = BG_ClassByName( s )->number;
- // This shouldn't be called if g_floodMinTime isn't set, but handle it anyway.
- if( !g_floodMinTime.integer )
- return qfalse;
-
- // Do not limit admins with no censor/flood flag
- if( G_admin_permission( ent, ADMF_NOCENSORFLOOD ) )
- return qfalse;
-
- millisSinceLastCommand = level.time - ent->client->pers.lastFloodTime;
- if( millisSinceLastCommand < g_floodMinTime.integer )
- ent->client->pers.floodDemerits += ( g_floodMinTime.integer - millisSinceLastCommand );
- else
+ if( newClass == PCL_NONE )
+ return;
+
+ if( !G_RoomForClassChange( ent, newClass, infestOrigin ) )
{
- ent->client->pers.floodDemerits -= ( millisSinceLastCommand - g_floodMinTime.integer );
- if( ent->client->pers.floodDemerits < 0 )
- ent->client->pers.floodDemerits = 0;
+ ADMP("give: not enough room to evolve\n");
+ return;
}
- ent->client->pers.lastFloodTime = level.time;
+ ent->client->pers.evolveHealthFraction
+ = (float)ent->client->ps.stats[ STAT_HEALTH ]
+ / (float)BG_Class( currentClass )->health;
- // If g_floodMaxDemerits == 0, then we go against g_floodMinTime^2.
-
- if( !g_floodMaxDemerits.integer )
- maximumDemerits = g_floodMinTime.integer * g_floodMinTime.integer / 1000;
- else
- maximumDemerits = g_floodMaxDemerits.integer;
+ if( ent->client->pers.evolveHealthFraction < 0.0f )
+ ent->client->pers.evolveHealthFraction = 0.0f;
+ else if( ent->client->pers.evolveHealthFraction > 1.0f )
+ ent->client->pers.evolveHealthFraction = 1.0f;
- if( ent->client->pers.floodDemerits > maximumDemerits )
- return qtrue;
+ //remove credit
+ //G_AddCreditToClient( ent->client, -cost, qtrue );
+ ent->client->pers.classSelection = newClass;
+ ClientUserinfoChanged( clientNum, qfalse );
+ VectorCopy( infestOrigin, ent->s.pos.trBase );
+ VectorCopy( ent->client->ps.velocity, oldVel );
- return qfalse;
+ if( ent->client->ps.stats[ STAT_STATE ] & SS_BOOSTED )
+ oldBoostTime = ent->client->boostedTime;
+
+ ClientSpawn( ent, ent, ent->s.pos.trBase, ent->s.apos.trBase );
+
+ VectorCopy( oldVel, ent->client->ps.velocity );
+ if( oldBoostTime > 0 )
+ {
+ ent->client->boostedTime = oldBoostTime;
+ ent->client->ps.stats[ STAT_STATE ] |= SS_BOOSTED;
+ }
+}
+
+static void Give_Gun( gentity_t *ent, char *s )
+{
+ int w = BG_WeaponByName( s )->number;
+
+ if ( w == WP_NONE )
+ return;
+
+ //if( !BG_Weapon( w )->purchasable )
+ // return;
+
+ ent->client->ps.stats[ STAT_WEAPON ] = w;
+ ent->client->ps.ammo = BG_Weapon( w )->maxAmmo;
+ ent->client->ps.clips = BG_Weapon( w )->maxClips;
+ G_ForceWeaponChange( ent, w );
+}
+
+static void Give_Upgrade( gentity_t *ent, char *s )
+{
+ int u = BG_UpgradeByName( s )->number;
+ BG_AddUpgradeToInventory( u, ent->client->ps.stats );
}
-
+
/*
==================
Cmd_Give_f
@@ -402,52 +463,157 @@ void Cmd_Give_f( gentity_t *ent )
char *name;
qboolean give_all = qfalse;
+ if( trap_Argc( ) < 2 )
+ {
+ ADMP( "^3give: ^7usage: give [what]\n"
+ "health, funds <amount>, stamina, poison, gas, ammo, "
+ "^3level0, level1, level1upg, level2, level2upg, level3, level3upg, level4, builder, builderupg, "
+ "human_base, human_bsuit, "
+ "^5blaster, rifle, psaw, shotgun, lgun, mdriver, chaingun, flamer, prifle, grenade, lockblob, "
+ "hive, teslagen, mgturret, abuild, abuildupg, portalgun, proximity, smokecan, "
+ "^2larmour, helmet, medkit, battpak, jetpack, bsuit, gren \n" );
+ return;
+ }
+
name = ConcatArgs( 1 );
if( Q_stricmp( name, "all" ) == 0 )
give_all = qtrue;
if( give_all || Q_stricmp( name, "health" ) == 0 )
{
- if(!g_devmapNoGod.integer)
+ ent->health = ent->client->ps.stats[ STAT_MAX_HEALTH ];
+ BG_AddUpgradeToInventory( UP_MEDKIT, ent->client->ps.stats );
+ }
+
+ if( give_all || Q_stricmpn( name, "funds", 5 ) == 0 )
+ {
+ float credits;
+
+ if( give_all || trap_Argc( ) < 3 )
+ credits = 30000.0f;
+ else
{
- ent->health = ent->client->ps.stats[ STAT_MAX_HEALTH ];
- BG_AddUpgradeToInventory( UP_MEDKIT, ent->client->ps.stats );
+ credits = atof( name + 6 ) *
+ ( ent->client->pers.teamSelection ==
+ TEAM_ALIENS ? ALIEN_CREDITS_PER_KILL : 1.0f );
+
+ // clamp credits manually, as G_AddCreditToClient() expects a short int
+ if( credits > SHRT_MAX )
+ credits = 30000.0f;
+ else if( credits < SHRT_MIN )
+ credits = -30000.0f;
}
+
+ G_AddCreditToClient( ent->client, (short)credits, qtrue );
}
- if( give_all || Q_stricmpn( name, "funds", 5 ) == 0 )
+ if( ent->client->ps.stats[ STAT_HEALTH ] <= 0 ||
+ ent->client->sess.spectatorState != SPECTATOR_NOT )
{
- int credits = give_all ? HUMAN_MAX_CREDITS : atoi( name + 6 );
- G_AddCreditToClient( ent->client, credits, qtrue );
+ if( !( give_all || Q_stricmpn( name, "funds", 5 ) == 0 ) )
+ G_TriggerMenu( ent-g_entities, MN_CMD_ALIVE );
+ return;
+ }
+
+ if( give_all || Q_stricmp( name, "health" ) == 0 )
+ {
+ if( ent->health < ent->client->ps.stats[ STAT_MAX_HEALTH ] )
+ {
+ ent->health = ent->client->ps.stats[ STAT_MAX_HEALTH ];
+ ent->client->ps.stats[ STAT_HEALTH ] = ent->health;
+ }
+ BG_AddUpgradeToInventory( UP_MEDKIT, ent->client->ps.stats );
}
if( give_all || Q_stricmp( name, "stamina" ) == 0 )
- ent->client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA;
+ ent->client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
+
+ // Adding guns
+ Give_Gun(ent, name);
+
+ // Adding upgrades
+ Give_Upgrade( ent, name);
+
+ // Change class- this allows you to be any alien class on TEAM_HUMAN and the
+ // otherway round.
+ Give_Class(ent, name);
if( Q_stricmp( name, "poison" ) == 0 )
{
- ent->client->ps.stats[ STAT_STATE ] |= SS_BOOSTED;
- ent->client->lastBoostedTime = level.time;
+ if( ent->client->pers.teamSelection == TEAM_HUMANS )
+ {
+ ent->client->ps.stats[ STAT_STATE ] |= SS_POISONED;
+ ent->client->lastPoisonTime = level.time;
+ ent->client->lastPoisonClient = ent;
+ }
+ else
+ {
+ ent->client->ps.stats[ STAT_STATE ] |= SS_BOOSTED;
+ ent->client->boostedTime = level.time;
+ }
+ }
+
+ if( Q_stricmp( name, "gas" ) == 0 )
+ {
+ ent->client->ps.eFlags |= EF_POISONCLOUDED;
+ ent->client->lastPoisonCloudedTime = level.time;
+ trap_SendServerCommand( ent->client->ps.clientNum, "poisoncloud" );
}
if( give_all || Q_stricmp( name, "ammo" ) == 0 )
{
- int maxAmmo, maxClips;
gclient_t *client = ent->client;
if( client->ps.weapon != WP_ALEVEL3_UPG &&
- BG_FindInfinteAmmoForWeapon( client->ps.weapon ) )
+ BG_Weapon( client->ps.weapon )->infiniteAmmo )
return;
- BG_FindAmmoForWeapon( client->ps.weapon, &maxAmmo, &maxClips );
+ client->ps.ammo = BG_Weapon( client->ps.weapon )->maxAmmo;
+ client->ps.clips = BG_Weapon( client->ps.weapon )->maxClips;
- if( BG_FindUsesEnergyForWeapon( client->ps.weapon ) &&
+ if( BG_Weapon( client->ps.weapon )->usesEnergy &&
BG_InventoryContainsUpgrade( UP_BATTPACK, client->ps.stats ) )
- maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
+ client->ps.ammo = (int)( (float)client->ps.ammo * BATTPACK_MODIFIER );
+ }
+}
+
+/*
+Cmd_Drop_f
+Drop a weapon onto the ground
+*/
+void Cmd_Drop_f( gentity_t *ent )
+{
+ char t[ MAX_TOKEN_CHARS ];
+ char angle[ MAX_TOKEN_CHARS ];
+ float ang = 0.0f;
+ int i;
+
+ if( trap_Argc( ) < 2 )
+ {
+ ADMP("^3drop: ^7usage: drop <weapon> [angle]\n");
+ return;
+ }
- client->ps.ammo = maxAmmo;
- client->ps.clips = maxClips;
+ trap_Argv( 1, t, sizeof(t) );
+
+ if ( trap_Argc() > 2 )
+ {
+ trap_Argv( 2, angle, sizeof(angle) );
+ ang = atof( angle );
}
+
+ switch ((i = BG_WeaponByName( t )->number))
+ {
+ case WP_NONE:
+ ADMP("^3drop: ^7usage: drop <weapon> [angle]\n");
+ break;
+
+ default:
+ G_DropWeapon( ent, i, ang );
+ break;
+ };
+
+
}
@@ -464,19 +630,12 @@ void Cmd_God_f( gentity_t *ent )
{
char *msg;
- if( !g_devmapNoGod.integer )
- {
ent->flags ^= FL_GODMODE;
if( !( ent->flags & FL_GODMODE ) )
msg = "godmode OFF\n";
else
msg = "godmode ON\n";
- }
- else
- {
- msg = "Godmode has been disabled.\n";
- }
trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) );
}
@@ -495,19 +654,12 @@ void Cmd_Notarget_f( gentity_t *ent )
{
char *msg;
- if( !g_devmapNoGod.integer )
- {
ent->flags ^= FL_NOTARGET;
if( !( ent->flags & FL_NOTARGET ) )
msg = "notarget OFF\n";
else
msg = "notarget ON\n";
- }
- else
- {
- msg = "Godmode has been disabled.\n";
- }
trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) );
}
@@ -524,19 +676,22 @@ void Cmd_Noclip_f( gentity_t *ent )
{
char *msg;
- if( !g_devmapNoGod.integer )
- {
if( ent->client->noclip )
+ {
msg = "noclip OFF\n";
+ ent->r.contents = ent->client->cliprcontents;
+ }
else
+ {
msg = "noclip ON\n";
+ ent->client->cliprcontents = ent->r.contents;
+ ent->r.contents = 0;
+ }
ent->client->noclip = !ent->client->noclip;
- }
- else
- {
- msg = "Godmode has been disabled.\n";
- }
+
+ if( ent->r.linked )
+ trap_LinkEntity( ent );
trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) );
}
@@ -565,15 +720,6 @@ Cmd_Kill_f
*/
void Cmd_Kill_f( gentity_t *ent )
{
- if( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING )
- return;
-
- if( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Leave the hovel first (use your destroy key)\n\"" );
- return;
- }
-
if( g_cheats.integer )
{
ent->flags &= ~FL_GODMODE;
@@ -589,730 +735,409 @@ void Cmd_Kill_f( gentity_t *ent )
}
else if( ent->suicideTime > level.time )
{
- trap_SendServerCommand( ent-g_entities, "print \"Suicide canceled\n\"" );
+ trap_SendServerCommand( ent-g_entities, "print \"Suicide cancelled\n\"" );
ent->suicideTime = 0;
}
}
}
/*
-==================
-G_LeaveTeam
-==================
+=================
+Cmd_Team_f
+=================
*/
-void G_LeaveTeam( gentity_t *self )
+void Cmd_Team_f( gentity_t *ent )
{
- pTeam_t team = self->client->pers.teamSelection;
- gentity_t *ent;
- int i;
+ team_t team;
+ team_t oldteam = ent->client->pers.teamSelection;
+ char s[ MAX_TOKEN_CHARS ];
+ qboolean force = G_admin_permission( ent, ADMF_FORCETEAMCHANGE );
+ int aliens = level.numAlienClients;
+ int humans = level.numHumanClients;
- if( team == PTE_ALIENS )
- G_RemoveFromSpawnQueue( &level.alienSpawnQueue, self->client->ps.clientNum );
- else if( team == PTE_HUMANS )
- G_RemoveFromSpawnQueue( &level.humanSpawnQueue, self->client->ps.clientNum );
- else
+ if( oldteam == TEAM_ALIENS )
+ aliens--;
+ else if( oldteam == TEAM_HUMANS )
+ humans--;
+
+ // stop team join spam
+ if( ent->client->pers.teamChangeTime &&
+ level.time - ent->client->pers.teamChangeTime < 1000 )
+ return;
+
+ // stop switching teams for gameplay exploit reasons by enforcing a long
+ // wait before they can come back
+ if( !force && !g_cheats.integer && ent->client->pers.secondsAlive &&
+ level.time - ent->client->pers.teamChangeTime < 30000 )
{
- if( self->client->sess.spectatorState == SPECTATOR_FOLLOW )
- {
- G_StopFollowing( self );
- }
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"You must wait another %d seconds before changing teams again\n\"",
+ (int) ( ( 30000 - ( level.time - ent->client->pers.teamChangeTime ) ) / 1000.f ) ) );
return;
}
-
- // Cancel pending suicides
- self->suicideTime = 0;
- // stop any following clients
- G_StopFromFollowing( self );
+ trap_Argv( 1, s, sizeof( s ) );
- for( i = 0; i < level.num_entities; i++ )
+ if( !s[ 0 ] )
{
- ent = &g_entities[ i ];
- if( !ent->inuse )
- continue;
+ trap_SendServerCommand( ent-g_entities, va( "print \"team: %s\n\"",
+ BG_TeamName( oldteam ) ) );
+ return;
+ }
- // clean up projectiles
- if( ent->s.eType == ET_MISSILE && ent->r.ownerNum == self->s.number )
- G_FreeEntity( ent );
- if( ent->client && ent->client->pers.connected == CON_CONNECTED )
- {
- // cure poison
- if( ent->client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED &&
- ent->client->lastPoisonCloudedClient == self )
- ent->client->ps.stats[ STAT_STATE ] &= ~SS_POISONCLOUDED;
- if( ent->client->ps.stats[ STAT_STATE ] & SS_POISONED &&
- ent->client->lastPoisonClient == self )
- ent->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
- }
+ if( !Q_stricmp( s, "auto" ) )
+ {
+ if( level.humanTeamLocked && level.alienTeamLocked )
+ team = TEAM_NONE;
+ else if( level.humanTeamLocked || humans > aliens )
+ team = TEAM_ALIENS;
+
+ else if( level.alienTeamLocked || aliens > humans )
+ team = TEAM_HUMANS;
+ else
+ team = TEAM_ALIENS + rand( ) / ( RAND_MAX / 2 + 1 );
}
-}
+ else switch( G_TeamFromString( s ) )
+ {
+ case TEAM_NONE:
+ team = TEAM_NONE;
+ break;
-/*
-=================
-G_ChangeTeam
-=================
-*/
-void G_ChangeTeam( gentity_t *ent, pTeam_t newTeam )
-{
- pTeam_t oldTeam = ent->client->pers.teamSelection;
- qboolean isFixingImbalance=qfalse;
+ case TEAM_ALIENS:
+ if( level.alienTeamLocked )
+ {
+ G_TriggerMenu( ent - g_entities, MN_A_TEAMLOCKED );
+ return;
+ }
+ else if( level.humanTeamLocked )
+ force = qtrue;
- if( oldTeam == newTeam )
- return;
+ if( !force && g_teamForceBalance.integer && aliens > humans )
+ {
+ G_TriggerMenu( ent - g_entities, MN_A_TEAMFULL );
+ return;
+ }
- G_LeaveTeam( ent );
- ent->client->pers.teamSelection = newTeam;
+ team = TEAM_ALIENS;
+ break;
- ent->client->pers.lastFreekillTime = level.time;
+ case TEAM_HUMANS:
+ if( level.humanTeamLocked )
+ {
+ G_TriggerMenu( ent - g_entities, MN_H_TEAMLOCKED );
+ return;
+ }
+ else if( level.alienTeamLocked )
+ force = qtrue;
- // G_LeaveTeam() calls G_StopFollowing() which sets spec mode to free.
- // Undo that in this case, or else people can freespec while in the spawn queue on their new team
- if( newTeam != PTE_NONE )
- {
- ent->client->sess.spectatorState = SPECTATOR_LOCKED;
- }
-
-
- if ( ( level.numAlienClients - level.numHumanClients > 2 && oldTeam==PTE_ALIENS && newTeam == PTE_HUMANS && level.numHumanSpawns>0 ) ||
- ( level.numHumanClients - level.numAlienClients > 2 && oldTeam==PTE_HUMANS && newTeam == PTE_ALIENS && level.numAlienSpawns>0 ) )
- {
- isFixingImbalance=qtrue;
- }
+ if( !force && g_teamForceBalance.integer && humans > aliens )
+ {
+ G_TriggerMenu( ent - g_entities, MN_H_TEAMFULL );
+ return;
+ }
- // under certain circumstances, clients can keep their kills and credits
- // when switching teams
- if( G_admin_permission( ent, ADMF_TEAMCHANGEFREE ) ||
- ( g_teamImbalanceWarnings.integer && isFixingImbalance ) ||
- ( ( oldTeam == PTE_HUMANS || oldTeam == PTE_ALIENS )
- && ( level.time - ent->client->pers.teamChangeTime ) > 60000 ) )
- {
- if( oldTeam == PTE_ALIENS )
- ent->client->pers.credit *= (float)FREEKILL_HUMAN / FREEKILL_ALIEN;
- else if( newTeam == PTE_ALIENS )
- ent->client->pers.credit *= (float)FREEKILL_ALIEN / FREEKILL_HUMAN;
- }
- else
- {
- ent->client->pers.credit = 0;
- ent->client->pers.score = 0;
- }
-
- ent->client->ps.persistant[ PERS_KILLED ] = 0;
- ent->client->pers.statscounters.kills = 0;
- ent->client->pers.statscounters.structskilled = 0;
- ent->client->pers.statscounters.assists = 0;
- ent->client->pers.statscounters.repairspoisons = 0;
- ent->client->pers.statscounters.headshots = 0;
- ent->client->pers.statscounters.hits = 0;
- ent->client->pers.statscounters.hitslocational = 0;
- ent->client->pers.statscounters.deaths = 0;
- ent->client->pers.statscounters.feeds = 0;
- ent->client->pers.statscounters.suicides = 0;
- ent->client->pers.statscounters.teamkills = 0;
- ent->client->pers.statscounters.dmgdone = 0;
- ent->client->pers.statscounters.structdmgdone = 0;
- ent->client->pers.statscounters.ffdmgdone = 0;
- ent->client->pers.statscounters.structsbuilt = 0;
- ent->client->pers.statscounters.timealive = 0;
- ent->client->pers.statscounters.timeinbase = 0;
- ent->client->pers.statscounters.dretchbasytime = 0;
- ent->client->pers.statscounters.jetpackusewallwalkusetime = 0;
-
- if( G_admin_permission( ent, ADMF_DBUILDER ) )
- {
- if( !ent->client->pers.designatedBuilder )
- {
- ent->client->pers.designatedBuilder = qtrue;
- trap_SendServerCommand( ent-g_entities,
- "print \"Your designation has been restored\n\"" );
- }
- }
- else if( ent->client->pers.designatedBuilder )
- {
- ent->client->pers.designatedBuilder = qfalse;
- trap_SendServerCommand( ent-g_entities,
- "print \"You have lost designation due to teamchange\n\"" );
+ team = TEAM_HUMANS;
+ break;
+
+ default:
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"Unknown team: %s\n\"", s ) );
+ return;
}
- ent->client->pers.classSelection = PCL_NONE;
- ClientSpawn( ent, NULL, NULL, NULL );
+ // stop team join spam
+ if( oldteam == team )
+ return;
- ent->client->pers.joinedATeam = qtrue;
- ent->client->pers.teamChangeTime = level.time;
+ if( team != TEAM_NONE && g_maxGameClients.integer &&
+ level.numPlayingClients >= g_maxGameClients.integer )
+ {
+ G_TriggerMenu( ent - g_entities, MN_PLAYERLIMIT );
+ return;
+ }
- //update ClientInfo
- ClientUserinfoChanged( ent->client->ps.clientNum, qfalse );
- G_CheckDBProtection( );
+ // Apply the change
+ G_ChangeTeam( ent, team );
}
/*
-=================
-Cmd_Team_f
-=================
+==================
+G_CensorString
+==================
*/
-void Cmd_Team_f( gentity_t *ent )
+static char censors[ 20000 ];
+static int numcensors;
+
+void G_LoadCensors( void )
{
- pTeam_t team;
- pTeam_t oldteam = ent->client->pers.teamSelection;
- char s[ MAX_TOKEN_CHARS ];
- char buf[ MAX_STRING_CHARS ];
- qboolean force = G_admin_permission(ent, ADMF_FORCETEAMCHANGE);
- int aliens = level.numAlienClients;
- int humans = level.numHumanClients;
+ char *text_p, *token;
+ char text[ 20000 ];
+ char *term;
+ int len;
+ fileHandle_t f;
- // stop team join spam
- if( level.time - ent->client->pers.teamChangeTime < 1000 )
- return;
- // Prevent invisible players from joining a team
- if ( ent->client->sess.invisible == qtrue )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"You cannot join a team while invisible\n\"" ) );
+ numcensors = 0;
+
+ if( !g_censorship.string[ 0 ] )
return;
- }
- if( g_scrimMode.integer != 0 && !G_admin_permission( ent, ADMF_NOSCRIMRESTRICTION ) )
+ len = trap_FS_FOpenFile( g_censorship.string, &f, FS_READ );
+ if( len < 0 )
{
- trap_SendServerCommand( ent-g_entities,
- va( "print \"You can't join a team when scrim mode is enabled\n\"" ) );
+ Com_Printf( S_COLOR_RED "ERROR: Censors file %s doesn't exist\n",
+ g_censorship.string );
return;
}
-
- if( oldteam == PTE_ALIENS )
- aliens--;
- else if( oldteam == PTE_HUMANS )
- humans--;
-
- // do warm up
- if( g_doWarmup.integer && g_warmupMode.integer == 1 &&
- level.time - level.startTime < g_warmup.integer * 1000 )
+ if( len == 0 || len >= sizeof( text ) - 1 )
{
- trap_SendServerCommand( ent - g_entities, va( "print \"team: you can't join"
- " a team during warm up (%d seconds remaining)\n\"",
- g_warmup.integer - ( level.time - level.startTime ) / 1000 ) );
+ trap_FS_FCloseFile( f );
+ Com_Printf( S_COLOR_RED "ERROR: Censors file %s is %s\n",
+ g_censorship.string, len == 0 ? "empty" : "too long" );
return;
}
+ trap_FS_Read( text, len, f );
+ trap_FS_FCloseFile( f );
+ text[ len ] = 0;
- trap_Argv( 1, s, sizeof( s ) );
+ term = censors;
- if( !strlen( s ) )
+ text_p = text;
+ while( 1 )
{
- trap_SendServerCommand( ent-g_entities, va("print \"team: %i\n\"",
- oldteam ) );
- return;
+ token = COM_Parse( &text_p );
+ if( !*token || sizeof( censors ) - ( term - censors ) < 4 )
+ break;
+ Q_strncpyz( term, token, sizeof( censors ) - ( term - censors ) );
+ Q_strlwr( term );
+ term += strlen( term ) + 1;
+ if( sizeof( censors ) - ( term - censors ) == 0 )
+ break;
+ token = COM_ParseExt( &text_p, qfalse );
+ Q_strncpyz( term, token, sizeof( censors ) - ( term - censors ) );
+ term += strlen( term ) + 1;
+ numcensors++;
}
+ G_Printf( "Parsed %d string replacements\n", numcensors );
+}
- if( Q_stricmpn( s, "spec", 4 ) ){
- if(G_admin_level(ent)<g_minLevelToJoinTeam.integer){
- trap_SendServerCommand( ent-g_entities,"print \"Sorry, but your admin level is only permitted to spectate.\n\"" );
- return;
- }
- }
-
- if( !Q_stricmpn( s, "spec", 4 ) )
- team = PTE_NONE;
- else if( !force && ent->client->pers.teamSelection == PTE_NONE &&
- g_maxGameClients.integer && level.numPlayingClients >=
- g_maxGameClients.integer )
+void G_CensorString( char *out, const char *in, int len, gentity_t *ent )
+{
+ const char *s, *m;
+ int i;
+
+ if( !numcensors || G_admin_permission( ent, ADMF_NOCENSORFLOOD) )
{
- trap_SendServerCommand( ent - g_entities, va( "print \"The maximum number "
- "of playing clients has been reached (g_maxGameClients = %i)\n\"",
- g_maxGameClients.integer ) );
+ Q_strncpyz( out, in, len );
return;
}
- else if ( ent->client->pers.specExpires > level.time )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't join a team yet. Expires in %d seconds.\n\"",
- ( ent->client->pers.specExpires - level.time ) / 1000 ) );
- return;
- }
- else if( !Q_stricmpn( s, "alien", 5 ) )
- {
- if( g_forceAutoSelect.integer && !G_admin_permission(ent, ADMF_FORCETEAMCHANGE) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You can only join teams using autoselect\n\"" );
- return;
- }
-
- if( level.alienTeamLocked && !force )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"Alien team has been ^1LOCKED\n\"" ) );
- return;
- }
- else if( level.humanTeamLocked )
- {
- // if only one team has been locked, let people join the other
- // regardless of balance
- force = qtrue;
- }
- if( !force && g_teamForceBalance.integer && aliens > humans )
- {
- G_TriggerMenu( ent - g_entities, MN_A_TEAMFULL );
- return;
- }
-
-
- team = PTE_ALIENS;
- }
- else if( !Q_stricmpn( s, "human", 5 ) )
+ len--;
+ while( *in )
{
- if( g_forceAutoSelect.integer && !G_admin_permission(ent, ADMF_FORCETEAMCHANGE) )
+ if( Q_IsColorString( in ) )
{
- trap_SendServerCommand( ent-g_entities, "print \"You can only join teams using autoselect\n\"" );
- return;
+ if( len < 2 )
+ break;
+ *out++ = *in++;
+ *out++ = *in++;
+ len -= 2;
+ continue;
}
-
- if( level.humanTeamLocked && !force )
+ if( !isalnum( *in ) )
{
- trap_SendServerCommand( ent-g_entities,
- va( "print \"Human team has been ^1LOCKED\n\"" ) );
- return;
+ if( len < 1 )
+ break;
+ *out++ = *in++;
+ len--;
+ continue;
}
- else if( level.alienTeamLocked )
+ m = censors;
+ for( i = 0; i < numcensors; i++, m++ )
{
- // if only one team has been locked, let people join the other
- // regardless of balance
- force = qtrue;
+ s = in;
+ while( *s && *m )
+ {
+ if( Q_IsColorString( s ) )
+ {
+ s += 2;
+ continue;
+ }
+ if( !isalnum( *s ) )
+ {
+ s++;
+ continue;
+ }
+ if( tolower( *s ) != *m )
+ break;
+ s++;
+ m++;
+ }
+ // match
+ if( !*m )
+ {
+ in = s;
+ m++;
+ while( *m )
+ {
+ if( len < 1 )
+ break;
+ *out++ = *m++;
+ len--;
+ }
+ break;
+ }
+ else
+ {
+ while( *m )
+ m++;
+ m++;
+ while( *m )
+ m++;
+ }
}
-
- if( !force && g_teamForceBalance.integer && humans > aliens )
+ if( len < 1 )
+ break;
+ // no match
+ if( i == numcensors )
{
- G_TriggerMenu( ent - g_entities, MN_H_TEAMFULL );
- return;
+ *out++ = *in++;
+ len--;
}
-
- team = PTE_HUMANS;
}
- else if( !Q_stricmp( s, "auto" ) )
- {
- if( level.humanTeamLocked && level.alienTeamLocked )
- team = PTE_NONE;
- else if( humans > aliens )
- team = PTE_ALIENS;
- else if( humans < aliens )
- team = PTE_HUMANS;
- else
- team = PTE_ALIENS + ( rand( ) % 2 );
-
- if( team == PTE_ALIENS && level.alienTeamLocked )
- team = PTE_HUMANS;
- else if( team == PTE_HUMANS && level.humanTeamLocked )
- team = PTE_ALIENS;
- }
- else
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"Unknown team: %s\n\"", s ) );
- return;
- }
-
- // stop team join spam
- if( oldteam == team )
- return;
-
- //guard against build timer exploit
- if( oldteam != PTE_NONE && ent->client->sess.sessionTeam != TEAM_SPECTATOR &&
- ( ent->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0 ||
- ent->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0_UPG ||
- BG_InventoryContainsWeapon( WP_HBUILD, ent->client->ps.stats ) ||
- BG_InventoryContainsWeapon( WP_HBUILD2, ent->client->ps.stats ) ) &&
- ent->client->ps.stats[ STAT_MISC ] > 0 )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"You cannot change teams until build timer expires\n\"" ) );
- return;
- }
-
- if (team != PTE_NONE)
- {
- char namebuff[32];
-
- Q_strncpyz (namebuff, ent->client->pers.netname, sizeof(namebuff));
- Q_CleanStr (namebuff);
-
- if (!namebuff[0] || !Q_stricmp (namebuff, "UnnamedPlayer"))
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"Please set your player name before joining a team. Press ESC and use the Options / Game menu or use /name in the console\n\"") );
- return;
- }
- }
-
-
- G_ChangeTeam( ent, team );
-
-
-
- if( team == PTE_ALIENS ) {
- if ( oldteam == PTE_HUMANS )
- Com_sprintf( buf, sizeof( buf ), "%s^7 abandoned humans and joined the aliens.", ent->client->pers.netname );
- else
- Com_sprintf( buf, sizeof( buf ), "%s^7 joined the aliens.", ent->client->pers.netname );
- }
- else if( team == PTE_HUMANS ) {
- if ( oldteam == PTE_ALIENS )
- Com_sprintf( buf, sizeof( buf ), "%s^7 abandoned the aliens and joined the humans.", ent->client->pers.netname );
- else
- Com_sprintf( buf, sizeof( buf ), "%s^7 joined the humans.", ent->client->pers.netname );
- }
- else if( team == PTE_NONE ) {
- if ( oldteam == PTE_HUMANS )
- Com_sprintf( buf, sizeof( buf ), "%s^7 left the humans.", ent->client->pers.netname );
- else
- Com_sprintf( buf, sizeof( buf ), "%s^7 left the aliens.", ent->client->pers.netname );
- }
- trap_SendServerCommand( -1, va( "print \"%s\n\"", buf ) );
- G_LogOnlyPrintf("ClientTeam: %s\n",buf);
+ *out = 0;
}
-
/*
==================
G_Say
==================
*/
-static void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, const char *name, const char *message, const char *prefix )
+static qboolean G_SayTo( gentity_t *ent, gentity_t *other, saymode_t mode, const char *message )
{
- qboolean ignore = qfalse;
- qboolean specAllChat = qfalse;
-
if( !other )
- return;
+ return qfalse;
if( !other->inuse )
- return;
+ return qfalse;
if( !other->client )
- return;
+ return qfalse;
if( other->client->pers.connected != CON_CONNECTED )
- return;
+ return qfalse;
- if( ( mode == SAY_TEAM || mode == SAY_ACTION_T ) && !OnSameTeam( ent, other ) )
- {
- if( other->client->pers.teamSelection != PTE_NONE )
- return;
+ if( Com_ClientListContains( &other->client->sess.ignoreList, (int)( ent - g_entities ) ) )
+ return qfalse;
- specAllChat = G_admin_permission( other, ADMF_SPEC_ALLCHAT );
- if( !specAllChat )
- return;
+ if( ( ent && !OnSameTeam( ent, other ) ) &&
+ ( mode == SAY_TEAM || mode == SAY_AREA || mode == SAY_TPRIVMSG ) )
+ {
+ if( other->client->pers.teamSelection != TEAM_NONE )
+ return qfalse;
// specs with ADMF_SPEC_ALLCHAT flag can see team chat
+ if( !G_admin_permission( other, ADMF_SPEC_ALLCHAT ) && mode != SAY_TPRIVMSG )
+ return qfalse;
}
- if( mode == SAY_ADMINS &&
- (!G_admin_permission( other, ADMF_ADMINCHAT ) || other->client->pers.ignoreAdminWarnings ||
- ( g_scrimMode.integer != 0 && !G_admin_permission( ent, ADMF_NOSCRIMRESTRICTION ) ) ) )
- return;
-
- if( mode == SAY_HADMINS &&
- (!G_admin_permission( other, ADMF_HIGHADMINCHAT ) || other->client->pers.ignoreAdminWarnings ) )
- return;
-
- if( BG_ClientListTest( &other->client->sess.ignoreList, ent-g_entities ) )
- ignore = qtrue;
-
- if ( ignore && g_fullIgnore.integer )
- return;
+ trap_SendServerCommand( other-g_entities, va( "chat %d %d \"%s\"",
+ (int)( ent ? ent-g_entities : -1 ),
+ mode,
+ message ) );
- trap_SendServerCommand( other-g_entities, va( "%s \"%s%s%s%c%c%s\"",
- ( mode == SAY_TEAM || mode == SAY_ACTION_T ) ? "tchat" : "chat",
- ( ignore ) ? "[skipnotify]" : "",
- ( specAllChat ) ? prefix : "",
- name, Q_COLOR_ESCAPE, color, message ) );
+ return qtrue;
}
-#define EC "\x19"
-
-void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText )
+void G_Say( gentity_t *ent, saymode_t mode, const char *chatText )
{
int j;
gentity_t *other;
- int color;
- const char *prefix;
- char name[ 64 ];
// don't let text be too long for malicious reasons
char text[ MAX_SAY_TEXT ];
- char location[ 64 ];
-
- // Bail if the text is blank.
- if( ! chatText[0] )
- return;
-
- // Invisible players cannot use chat
- if( ent->client->sess.invisible == qtrue )
- {
- if( !G_admin_cmd_check( ent, qtrue ) )
- trap_SendServerCommand( ent-g_entities, "print \"You cannot chat while invisible\n\"" );
- return;
- }
- if( ent && ent->client->pers.teamSelection == PTE_NONE && g_scrimMode.integer != 0 && !G_admin_permission( ent, ADMF_NOSCRIMRESTRICTION ) && mode != SAY_TEAM )
+ // check if blocked by g_specChat 0
+ if( ( !g_specChat.integer ) && ( mode != SAY_TEAM ) &&
+ ( ent ) && ( ent->client->pers.teamSelection == TEAM_NONE ) &&
+ ( !G_admin_permission( ent, ADMF_NOCENSORFLOOD ) ) )
{
- trap_SendServerCommand( ent-g_entities, "print \"You can't chat when scrim mode is enabled.\n\"" );
- return;
- }
-
- // Spam limit: If they said this message recently, ignore it.
- if( g_spamTime.integer )
- {
- if ( ( level.time - ent->client->pers.lastMessageTime ) < ( g_spamTime.integer * 1000 ) &&
- !Q_stricmp( ent->client->pers.lastMessage, chatText) &&
- !G_admin_permission( ent, ADMF_NOCENSORFLOOD ) &&
- ent->client->pers.floodDemerits <= g_floodMaxDemerits.integer )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Your message has been ignored to prevent spam\n\"" );
- return;
- }
- else
- {
- ent->client->pers.lastMessageTime = level.time;
-
- Q_strncpyz( ent->client->pers.lastMessage, chatText,
- sizeof( ent->client->pers.lastMessage ) );
- }
- }
-
- // Flood limit. If they're talking too fast, determine that and return.
- if( g_floodMinTime.integer )
- if ( G_Flood_Limited( ent ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Your chat is flood-limited; wait before chatting again\n\"" );
- return;
- }
-
- if (g_chatTeamPrefix.integer && ent && ent->client )
- {
- switch( ent->client->pers.teamSelection)
- {
- default:
- case PTE_NONE:
- prefix = "[^3S^7] ";
- break;
-
- case PTE_ALIENS:
- prefix = "[^1A^7] ";
- break;
-
- case PTE_HUMANS:
- prefix = "[^4H^7] ";
- }
+ trap_SendServerCommand( ent-g_entities, "print \"say: Global chatting for "
+ "spectators has been disabled. You may only use team chat.\n\"" );
+ mode = SAY_TEAM;
}
- else
- prefix = "";
switch( mode )
{
- default:
case SAY_ALL:
- G_LogPrintf( "say: %s^7: %s^7\n", ent->client->pers.netname, chatText );
- Com_sprintf( name, sizeof( name ), "%s%s%c%c"EC": ", prefix,
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_GREEN;
+ G_LogPrintf( "Say: %d \"%s" S_COLOR_WHITE "\": " S_COLOR_GREEN "%s\n",
+ (int)( ( ent ) ? ent - g_entities : -1 ),
+ ( ent ) ? ent->client->pers.netname : "console", chatText );
break;
-
case SAY_TEAM:
- G_LogPrintf( "sayteam: %s%s^7: %s^7\n", prefix, ent->client->pers.netname, chatText );
- if( Team_GetLocationMsg( ent, location, sizeof( location ) ) )
- Com_sprintf( name, sizeof( name ), EC"(%s%c%c"EC") (%s)"EC": ",
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location );
- else
- Com_sprintf( name, sizeof( name ), EC"(%s%c%c"EC")"EC": ",
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
-
- if( ent->client->pers.teamSelection == PTE_NONE )
- color = COLOR_YELLOW;
- else
- color = COLOR_CYAN;
- break;
-
- case SAY_TELL:
- if( target && OnSameTeam( target, ent ) &&
- Team_GetLocationMsg( ent, location, sizeof( location ) ) )
- Com_sprintf( name, sizeof( name ), EC"[%s%c%c"EC"] (%s)"EC": ",
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location );
- else
- Com_sprintf( name, sizeof( name ), EC"[%s%c%c"EC"]"EC": ",
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_MAGENTA;
- break;
-
- case SAY_ACTION:
- G_LogPrintf( "action: %s^7: %s^7\n", ent->client->pers.netname, chatText );
- Com_sprintf( name, sizeof( name ), "^2%s^7%s%s%c%c"EC" ", g_actionPrefix.string, prefix,
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_WHITE;
+ // console say_team is handled in g_svscmds, not here
+ if( !ent || !ent->client )
+ Com_Error( ERR_FATAL, "SAY_TEAM by non-client entity" );
+ G_LogPrintf( "SayTeam: %d \"%s" S_COLOR_WHITE "\": " S_COLOR_CYAN "%s\n",
+ (int)( ent - g_entities ), ent->client->pers.netname, chatText );
break;
-
- case SAY_ACTION_T:
- G_LogPrintf( "actionteam: %s%s^7: %s^7\n", prefix, ent->client->pers.netname, chatText );
- if( Team_GetLocationMsg( ent, location, sizeof( location ) ) )
- Com_sprintf( name, sizeof( name ), EC"^5%s^7%s%c%c"EC"(%s)"EC" ", g_actionPrefix.string,
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location );
- else
- Com_sprintf( name, sizeof( name ), EC"^5%s^7%s%c%c"EC""EC" ", g_actionPrefix.string,
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_WHITE;
+ case SAY_RAW:
+ if( ent )
+ Com_Error( ERR_FATAL, "SAY_RAW by client entity" );
+ G_LogPrintf( "Chat: -1 \"console\": %s\n", chatText );
+ default:
break;
-
- case SAY_ADMINS:
- if( G_admin_permission( ent, ADMF_ADMINCHAT ) ) //Differentiate between inter-admin chatter and user-admin alerts
- {
- G_LogPrintf( "say_admins: [ADMIN]%s^7: %s^7\n", ( ent ) ? ent->client->pers.netname : "console", chatText );
- Com_sprintf( name, sizeof( name ), "%s[ADMIN]%s%c%c"EC": ", prefix,
- ( ent ) ? ent->client->pers.netname : "console", Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_MAGENTA;
- }
- else
- {
- G_LogPrintf( "say_admins: [PLAYER]%s^7: %s^7\n", ent->client->pers.netname, chatText );
- Com_sprintf( name, sizeof( name ), "%s[PLAYER]%s%c%c"EC": ", prefix,
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_MAGENTA;
- }
- break;
-
- case SAY_HADMINS:
- if( G_admin_permission( ent, ADMF_HIGHADMINCHAT ) ) //Differentiate between inter-high-admin chatter and lower-admin-high-admin-admin alerts and user-admin alerts
- {
- G_LogPrintf( "say_hadmins: ^5[^1HIGH ADMIN^5]^7%s^7: %s^7\n", ( ent ) ? ent->client->pers.netname : "console", chatText );
- Com_sprintf( name, sizeof( name ), "%s^5[^1HIGH ADMIN^5]^7%s%c%c"EC": ", prefix,
- ( ent ) ? ent->client->pers.netname : "console", Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_RED;
- }
- else if( G_admin_permission( ent, ADMF_ADMINCHAT ) )
- {
- G_LogPrintf( "say_haadmins: ^1[^6LOWER ADMIN^1]^7%s^7: %s^7\n", ( ent ) ? ent->client->pers.netname : "console", chatText );
- Com_sprintf( name, sizeof( name ), "%s[^6LOWER ADMIN^7]%s%c%c"EC": ", prefix,
- ( ent ) ? ent->client->pers.netname : "console", Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_RED;
- }
- else
- {
- G_LogPrintf( "say_hadmins: [PLAYER]%s^7: %s^7\n", ent->client->pers.netname, chatText );
- Com_sprintf( name, sizeof( name ), "%s[PLAYER]%s%c%c"EC": ", prefix,
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_RED;
- }
- break;
-}
-
-
- if( mode!=SAY_TEAM && ent && ent->client && ent->client->pers.teamSelection == PTE_NONE && G_admin_level(ent)<g_minLevelToSpecMM1.integer )
- {
- trap_SendServerCommand( ent-g_entities,va( "print \"Sorry, but your admin level may only use teamchat while spectating.\n\"") );
- return;
}
- Com_sprintf( text, sizeof( text ), "%s^7", chatText );
+ G_CensorString( text, chatText, sizeof( text ), ent );
- if( ent && ent->client && g_aimbotAdvertBan.integer && ( Q_stricmp( text, "^1N^7ullify for ^1T^7remulous [beta] | Get it at CheatersUtopia.com^7" ) == 0 ) )
+ // send it to all the apropriate clients
+ for( j = 0; j < level.maxclients; j++ )
{
- trap_SendConsoleCommand( 0,
- va( "!ban %s %s %s\n",
- ent->client->pers.ip,
- ( Q_stricmp( g_aimbotAdvertBanTime.string, "0" ) == 1 ) ? g_aimbotAdvertBanTime.string : "" ,
- g_aimbotAdvertBanReason.string ) );
- Q_strncpyz( text, "^7has been caught hacking and will be dealt with.", sizeof( text ) );
+ other = &g_entities[ j ];
+ G_SayTo( ent, other, mode, text );
}
-
- if( target )
- {
- G_SayTo( ent, target, mode, color, name, text, prefix );
- return;
- }
-
-
-
- // Ugly hax: if adminsayfilter is off, do the SAY first to prevent text from going out of order
- if( !g_adminSayFilter.integer )
- {
- // send it to all the apropriate clients
- for( j = 0; j < level.maxclients; j++ )
- {
- other = &g_entities[ j ];
- G_SayTo( ent, other, mode, color, name, text, prefix );
- }
- }
-
- if( g_adminParseSay.integer && ( mode== SAY_ALL || mode == SAY_TEAM ) )
- {
- if( G_admin_cmd_check ( ent, qtrue ) && g_adminSayFilter.integer )
- {
- return;
- }
- }
-
- // if it's on, do it here, where it won't happen if it was an admin command
- if( g_adminSayFilter.integer )
- {
- // send it to all the apropriate clients
- for( j = 0; j < level.maxclients; j++ )
- {
- other = &g_entities[ j ];
- G_SayTo( ent, other, mode, color, name, text, prefix );
- }
- }
-
-
}
+/*
+==================
+Cmd_SayArea_f
+==================
+*/
static void Cmd_SayArea_f( gentity_t *ent )
{
int entityList[ MAX_GENTITIES ];
int num, i;
- int color = COLOR_BLUE;
- const char *prefix;
- vec3_t range = { HELMET_RANGE, HELMET_RANGE, HELMET_RANGE };
+ vec3_t range = { 1000.0f, 1000.0f, 1000.0f };
vec3_t mins, maxs;
- char *msg = ConcatArgs( 1 );
- char name[ 64 ];
-
- if( g_floodMinTime.integer )
- if ( G_Flood_Limited( ent ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Your chat is flood-limited; wait before chatting again\n\"" );
- return;
- }
-
- if (g_chatTeamPrefix.integer)
+ char *msg;
+
+ if( trap_Argc( ) < 2 )
{
- switch( ent->client->pers.teamSelection)
- {
- default:
- case PTE_NONE:
- prefix = "[^3S^7] ";
- break;
+ ADMP( "usage: say_area [message]\n" );
+ return;
+ }
- case PTE_ALIENS:
- prefix = "[^1A^7] ";
- break;
+ msg = ConcatArgs( 1 );
- case PTE_HUMANS:
- prefix = "[^4H^7] ";
- }
- }
- else
- prefix = "";
+ for(i = 0; i < 3; i++ )
+ range[ i ] = g_sayAreaRange.value;
- G_LogPrintf( "sayarea: %s%s^7: %s\n", prefix, ent->client->pers.netname, msg );
- Com_sprintf( name, sizeof( name ), EC"<%s%c%c"EC"> ",
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
+ G_LogPrintf( "SayArea: %d \"%s" S_COLOR_WHITE "\": " S_COLOR_BLUE "%s\n",
+ (int)( ent - g_entities ), ent->client->pers.netname, msg );
- VectorAdd( ent->s.origin, range, maxs );
- VectorSubtract( ent->s.origin, range, mins );
+ VectorAdd( ent->r.currentOrigin, range, maxs );
+ VectorSubtract( ent->r.currentOrigin, range, mins );
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for( i = 0; i < num; i++ )
- G_SayTo( ent, &g_entities[ entityList[ i ] ], SAY_TEAM, color, name, msg, prefix );
-
+ G_SayTo( ent, &g_entities[ entityList[ i ] ], SAY_AREA, msg );
+
//Send to ADMF_SPEC_ALLCHAT candidates
for( i = 0; i < level.maxclients; i++ )
{
- if( (&g_entities[ i ])->client->pers.teamSelection == PTE_NONE &&
+ if( g_entities[ i ].client->pers.teamSelection == TEAM_NONE &&
G_admin_permission( &g_entities[ i ], ADMF_SPEC_ALLCHAT ) )
{
- G_SayTo( ent, &g_entities[ i ], SAY_TEAM, color, name, msg, prefix );
+ G_SayTo( ent, &g_entities[ i ], SAY_AREA, msg );
}
}
}
@@ -1326,160 +1151,141 @@ Cmd_Say_f
static void Cmd_Say_f( gentity_t *ent )
{
char *p;
- char *args;
- int mode = SAY_ALL;
- int skipargs = 0;
+ char cmd[ MAX_TOKEN_CHARS ];
+ saymode_t mode = SAY_ALL;
- args = G_SayConcatArgs( 0 );
- if( Q_stricmpn( args, "say_team ", 9 ) == 0 )
+ if( trap_Argc( ) < 2 )
+ return;
+
+ trap_Argv( 0, cmd, sizeof( cmd ) );
+ if( Q_stricmp( cmd, "say_team" ) == 0 )
mode = SAY_TEAM;
- if( Q_stricmpn( args, "say_admins ", 11 ) == 0 || Q_stricmpn( args, "a ", 2 ) == 0)
- mode = SAY_ADMINS;
- if( Q_stricmpn( args, "say_hadmins ", 12 ) == 0 || Q_stricmpn( args, "ha ", 3 ) == 0)
- mode = SAY_HADMINS;
-
- // support parsing /m out of say text since some people have a hard
- // time figuring out what the console is.
- if( !Q_stricmpn( args, "say /m ", 7 ) ||
- !Q_stricmpn( args, "say_team /m ", 12 ) ||
- !Q_stricmpn( args, "say /mt ", 8 ) ||
- !Q_stricmpn( args, "say_team /mt ", 13 ) )
+
+ p = ConcatArgs( 1 );
+
+ G_Say( ent, mode, p );
+}
+
+/*
+==================
+Cmd_VSay_f
+==================
+*/
+void Cmd_VSay_f( gentity_t *ent )
+{
+ char arg[MAX_TOKEN_CHARS];
+ char text[ MAX_TOKEN_CHARS ];
+ voiceChannel_t vchan;
+ voice_t *voice;
+ voiceCmd_t *cmd;
+ voiceTrack_t *track;
+ int cmdNum = 0;
+ int trackNum = 0;
+ char voiceName[ MAX_VOICE_NAME_LEN ] = {"default"};
+ char voiceCmd[ MAX_VOICE_CMD_LEN ] = {""};
+ char vsay[ 12 ] = {""};
+ weapon_t weapon;
+
+ if( !ent || !ent->client )
+ Com_Error( ERR_FATAL, "Cmd_VSay_f() called by non-client entity" );
+
+ trap_Argv( 0, arg, sizeof( arg ) );
+ if( trap_Argc( ) < 2 )
{
- G_PrivateMessage( ent );
+ trap_SendServerCommand( ent-g_entities, va(
+ "print \"usage: %s command [text] \n\"", arg ) );
return;
}
-
- if( !Q_stricmpn( args, "say /a ", 7) ||
- !Q_stricmpn( args, "say_team /a ", 12) ||
- !Q_stricmpn( args, "say /say_admins ", 16) ||
- !Q_stricmpn( args, "say_team /say_admins ", 21) )
- {
- mode = SAY_ADMINS;
- skipargs=1;
- }
-
- if( !Q_stricmpn( args, "say /ha ", 8) ||
- !Q_stricmpn( args, "say_team /ha ", 13) ||
- !Q_stricmpn( args, "say /say_hadmins ", 17) ||
- !Q_stricmpn( args, "say_team /say_hadmins ", 22) )
- {
- mode = SAY_HADMINS;
- skipargs=1;
- }
-
- if( mode == SAY_ADMINS)
- if(!G_admin_permission( ent, ADMF_ADMINCHAT ) )
- {
- if( !g_publicSayadmins.integer )
- {
- ADMP( "Sorry, but public use of say_admins has been disabled.\n" );
- return;
- }
- else
- {
- ADMP( "Your message has been sent to any available admins and to the server logs.\n" );
- }
- }
-
- if( mode == SAY_HADMINS)
- if(!G_admin_permission( ent, ADMF_HIGHADMINCHAT ) )
- {
- {
- ADMP( "You don't have permissions to see/use this channel.\n" );
- }
- }
-
- if(!Q_stricmpn( args, "say /me ", 8 ) )
+ if( !level.voices )
{
- if( g_actionPrefix.string[0] )
- {
- mode = SAY_ACTION;
- skipargs=1;
- } else return;
+ trap_SendServerCommand( ent-g_entities, va(
+ "print \"%s: voice system is not installed on this server\n\"", arg ) );
+ return;
}
- else if(!Q_stricmpn( args, "say_team /me ", 13 ) )
+ if( !g_voiceChats.integer )
{
- if( g_actionPrefix.string[0] )
- {
- mode = SAY_ACTION_T;
- skipargs=1;
- } else return;
+ trap_SendServerCommand( ent-g_entities, va(
+ "print \"%s: voice system administratively disabled on this server\n\"",
+ arg ) );
+ return;
}
- else if( !Q_stricmpn( args, "me ", 3 ) )
+ if( !Q_stricmp( arg, "vsay" ) )
+ vchan = VOICE_CHAN_ALL;
+ else if( !Q_stricmp( arg, "vsay_team" ) )
+ vchan = VOICE_CHAN_TEAM;
+ else if( !Q_stricmp( arg, "vsay_local" ) )
+ vchan = VOICE_CHAN_LOCAL;
+ else
+ return;
+ Q_strncpyz( vsay, arg, sizeof( vsay ) );
+
+ if( ent->client->pers.voice[ 0 ] )
+ Q_strncpyz( voiceName, ent->client->pers.voice, sizeof( voiceName ) );
+ voice = BG_VoiceByName( level.voices, voiceName );
+ if( !voice )
{
- if( g_actionPrefix.string[0] )
- {
- mode = SAY_ACTION;
- } else return;
+ trap_SendServerCommand( ent-g_entities, va(
+ "print \"%s: voice '%s' not found\n\"", vsay, voiceName ) );
+ return;
}
- else if( !Q_stricmpn( args, "me_team ", 8 ) )
+
+ trap_Argv( 1, voiceCmd, sizeof( voiceCmd ) ) ;
+ cmd = BG_VoiceCmdFind( voice->cmds, voiceCmd, &cmdNum );
+ if( !cmd )
{
- if( g_actionPrefix.string[0] )
- {
- mode = SAY_ACTION_T;
- } else return;
+ trap_SendServerCommand( ent-g_entities, va(
+ "print \"%s: command '%s' not found in voice '%s'\n\"",
+ vsay, voiceCmd, voiceName ) );
+ return;
}
-
- if( g_allowShare.integer )
+ // filter non-spec humans by their primary weapon as well
+ weapon = WP_NONE;
+ if( ent->client->sess.spectatorState == SPECTATOR_NOT )
{
- args = G_SayConcatArgs(0);
- if( !Q_stricmpn( args, "say /share", 10 ) ||
- !Q_stricmpn( args, "say_team /share", 15 ) )
- {
- Cmd_Share_f( ent );
- return;
- }
- if( !Q_stricmpn( args, "say /donate", 11 ) ||
- !Q_stricmpn( args, "say_team /donate", 16 ) )
- {
- Cmd_Donate_f( ent );
- return;
- }
+ weapon = ent->client->ps.stats[ STAT_WEAPON ];
}
-
- if( trap_Argc( ) < 2 )
- return;
-
- p = G_SayConcatArgs( 1 + skipargs );
-
- G_Say( ent, NULL, mode, p );
-}
-
-/*
-==================
-Cmd_Tell_f
-==================
-*/
-static void Cmd_Tell_f( gentity_t *ent )
-{
- int targetNum;
- gentity_t *target;
- char *p;
- char arg[MAX_TOKEN_CHARS];
-
- if( trap_Argc( ) < 2 )
+ track = BG_VoiceTrackFind( cmd->tracks, ent->client->pers.teamSelection,
+ ent->client->pers.classSelection, weapon, (int)ent->client->voiceEnthusiasm,
+ &trackNum );
+ if( !track )
+ {
+ trap_SendServerCommand( ent-g_entities, va(
+ "print \"%s: no available track for command '%s', team %d, "
+ "class %d, weapon %d, and enthusiasm %d in voice '%s'\n\"",
+ vsay, voiceCmd, ent->client->pers.teamSelection,
+ ent->client->pers.classSelection, weapon,
+ (int)ent->client->voiceEnthusiasm, voiceName ) );
return;
+ }
- trap_Argv( 1, arg, sizeof( arg ) );
- targetNum = atoi( arg );
-
- if( targetNum < 0 || targetNum >= level.maxclients )
- return;
+ if( !Q_stricmp( ent->client->lastVoiceCmd, cmd->cmd ) )
+ ent->client->voiceEnthusiasm++;
- target = &g_entities[ targetNum ];
- if( !target || !target->inuse || !target->client )
- return;
+ Q_strncpyz( ent->client->lastVoiceCmd, cmd->cmd,
+ sizeof( ent->client->lastVoiceCmd ) );
- p = ConcatArgs( 2 );
+ // optional user supplied text
+ trap_Argv( 2, arg, sizeof( arg ) );
+ G_CensorString( text, arg, sizeof( text ), ent );
- G_LogPrintf( "tell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, p );
- G_Say( ent, target, SAY_TELL, p );
- // don't tell to the player self if it was already directed to this player
- // also don't send the chat back to a bot
- if( ent != target )
- G_Say( ent, ent, SAY_TELL, p );
+ switch( vchan )
+ {
+ case VOICE_CHAN_ALL:
+ case VOICE_CHAN_LOCAL:
+ trap_SendServerCommand( -1, va(
+ "voice %d %d %d %d \"%s\"\n",
+ (int)( ent-g_entities ), vchan, cmdNum, trackNum, text ) );
+ break;
+ case VOICE_CHAN_TEAM:
+ G_TeamCommand( ent->client->pers.teamSelection, va(
+ "voice %d %d %d %d \"%s\"\n",
+ (int)( ent-g_entities ), vchan, cmdNum, trackNum, text ) );
+ break;
+ default:
+ break;
+ }
}
/*
@@ -1489,27 +1295,12 @@ Cmd_Where_f
*/
void Cmd_Where_f( gentity_t *ent )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"%s\n\"", vtos( ent->s.origin ) ) );
-}
-
-
-static qboolean map_is_votable( const char *map )
-{
- char maps[ MAX_CVAR_VALUE_STRING ];
- char *token, *token_p;
-
- if( !g_votableMaps.string[ 0 ] )
- return qtrue;
-
- Q_strncpyz( maps, g_votableMaps.string, sizeof( maps ) );
- token_p = maps;
- while( *( token = COM_Parse( &token_p ) ) )
- {
- if( !Q_stricmp( token, map ) )
- return qtrue;
- }
-
- return qfalse;
+ if( !ent->client )
+ return;
+ trap_SendServerCommand( ent - g_entities,
+ va( "print \"origin: %f %f %f\n\"",
+ ent->r.currentOrigin[ 0 ], ent->r.currentOrigin[ 1 ],
+ ent->r.currentOrigin[ 2 ] ) );
}
/*
@@ -1519,1099 +1310,449 @@ Cmd_CallVote_f
*/
void Cmd_CallVote_f( gentity_t *ent )
{
- int i;
- char arg1[ MAX_STRING_TOKENS ];
- char arg2[ MAX_STRING_TOKENS ];
- int clientNum = -1;
- char name[ MAX_NETNAME ];
- char *arg1plus;
- char *arg2plus;
- char message[ MAX_STRING_CHARS ];
- char targetname[ MAX_NAME_LENGTH] = "";
- char reason[ MAX_STRING_CHARS ] = "";
- char *ptr = NULL;
-
- arg1plus = G_SayConcatArgs( 1 );
- arg2plus = G_SayConcatArgs( 2 );
-
- // Invisible players cannot call votes
- if( ent->client->sess.invisible == qtrue )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You cannot call votes while invisible\n\"" );
- return;
- }
-
- if( !g_allowVote.integer )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here\n\"" );
- return;
- }
+ char cmd[ MAX_TOKEN_CHARS ],
+ vote[ MAX_TOKEN_CHARS ],
+ arg[ MAX_TOKEN_CHARS ],
+ extra[ MAX_TOKEN_CHARS ];
+ char name[ MAX_NAME_LENGTH ] = "";
+ char caller[ MAX_NAME_LENGTH ] = "";
+ char reason[ MAX_TOKEN_CHARS ];
+ char *creason;
+ int clientNum = -1;
+ int id = -1;
+ team_t team;
- // Flood limit. If they're talking too fast, determine that and return.
- if( g_floodMinTime.integer )
- if ( G_Flood_Limited( ent ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Your /callvote attempt is flood-limited; wait before chatting again\n\"" );
- return;
- }
+ trap_Argv( 0, cmd, sizeof( cmd ) );
+ trap_Argv( 1, vote, sizeof( vote ) );
+ trap_Argv( 2, arg, sizeof( arg ) );
+ trap_Argv( 3, extra, sizeof( extra ) );
+ creason = ConcatArgs( 3 );
+ G_DecolorString( creason, reason, sizeof( reason ) );
+
+ if( !Q_stricmp( cmd, "callteamvote" ) )
+ team = ent->client->pers.teamSelection;
+ else
+ team = TEAM_NONE;
- //see if they can vote
- if( G_admin_permission( ent, ADMF_NO_VOTE ) )
+ if( !g_allowVote.integer )
{
- trap_SendServerCommand( ent-g_entities, "print \"You have no voting rights\n\"" );
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: voting not allowed here\n\"", cmd ) );
return;
}
- if( g_voteMinTime.integer
- && ent->client->pers.firstConnect
- && level.time - ent->client->pers.enterTime < g_voteMinTime.integer * 1000
- && !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT )
- && (level.numPlayingClients > 0 && level.numConnectedClients>1) )
+ if( level.voteTime[ team ] )
{
- trap_SendServerCommand( ent-g_entities, va(
- "print \"You must wait %d seconds after connecting before calling a vote\n\"",
- g_voteMinTime.integer ) );
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: a vote is already in progress\n\"", cmd ) );
return;
}
- if( level.voteTime )
+ // protect against the dreaded exploit of '\n'-interpretation inside quotes
+ if( strchr( arg, '\n' ) || strchr( arg, '\r' ) ||
+ strchr( extra, '\n' ) || strchr( extra, '\r' ) ||
+ strchr( creason, '\n' ) || strchr( creason, '\r' ) )
{
- trap_SendServerCommand( ent-g_entities, "print \"A vote is already in progress\n\"" );
+ trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" );
return;
}
- if( g_voteLimit.integer > 0
- && ent->client->pers.voteCount >= g_voteLimit.integer
- && !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT ) )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"You have already called the maximum number of votes (%d)\n\"",
- g_voteLimit.integer ) );
- return;
- }
-
- if( G_IsMuted( ent->client ) )
- {
- trap_SendServerCommand( ent - g_entities,
- "print \"You are muted and cannot call votes\n\"" );
- return;
- }
+ if( level.voteExecuteTime[ team ] )
+ G_ExecuteVote( team );
- if( !G_admin_permission( ent, ADMF_NOSCRIMRESTRICTION ) && g_scrimMode.integer != 0 &&
- ent->client->pers.teamSelection == PTE_NONE )
- {
- trap_SendServerCommand( ent - g_entities,
- "print \"You can't call votes when scrim mode is enabled\n\"" );
- return;
- }
-
- // make sure it is a valid command to vote on
- trap_Argv( 1, arg1, sizeof( arg1 ) );
- trap_Argv( 2, arg2, sizeof( arg2 ) );
+ level.voteDelay[ team ] = 0;
+ level.voteThreshold[ team ] = 50;
- if( strchr( arg1plus, ';' ) )
+ if( g_voteLimit.integer > 0 &&
+ ent->client->pers.namelog->voteCount >= g_voteLimit.integer &&
+ !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT ) )
{
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" );
+ trap_SendServerCommand( ent-g_entities, va(
+ "print \"%s: you have already called the maximum number of votes (%d)\n\"",
+ cmd, g_voteLimit.integer ) );
return;
}
- // if there is still a vote to be executed
- if( level.voteExecuteTime )
- {
- if( !Q_stricmp( level.voteString, "map_restart" ) )
- {
- G_admin_maplog_result( "r" );
- }
- else if( !Q_stricmpn( level.voteString, "map", 3 ) )
- {
- G_admin_maplog_result( "m" );
- }
-
- level.voteExecuteTime = 0;
- trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.voteString ) );
- }
-
- level.votePassThreshold=50;
-
- ptr = strstr(arg1plus, " -");
- if( ptr )
+ // kick, mute, unmute, denybuild, allowbuild
+ if( !Q_stricmp( vote, "kick" ) ||
+ !Q_stricmp( vote, "mute" ) || !Q_stricmp( vote, "unmute" ) ||
+ !Q_stricmp( vote, "denybuild" ) || !Q_stricmp( vote, "allowbuild" ) )
{
- *ptr = '\0';
- ptr+=2;
-
- if( *ptr == 'r' || *ptr=='R' )
- {
- ptr++;
- while( *ptr == ' ' )
- ptr++;
- strcpy(reason, ptr);
- }
- else
- {
- trap_SendServerCommand( ent-g_entities, "print \"callvote: Warning: invalid argument specified \n\"" );
- }
- }
+ char err[ MAX_STRING_CHARS ];
- // detect clientNum for partial name match votes
- if( !Q_stricmp( arg1, "kick" ) ||
- !Q_stricmp( arg1, "spec" ) ||
- !Q_stricmp( arg1, "mute" ) ||
- !Q_stricmp( arg1, "unmute" ) )
- {
- int clientNums[ MAX_CLIENTS ] = { -1 };
- int numMatches=0;
- char err[ MAX_STRING_CHARS ] = "";
-
- Q_strncpyz(targetname, arg2plus, sizeof(targetname));
- ptr = strstr(targetname, " -");
- if( ptr )
- *ptr = '\0';
-
- if( g_requireVoteReasons.integer && !G_admin_permission( ent, ADMF_UNACCOUNTABLE ) && !Q_stricmp( arg1, "kick" ) && reason[ 0 ]=='\0' )
- {
- trap_SendServerCommand( ent-g_entities, "print \"callvote: You must specify a reason. Use /callvote kick [player] -r [reason] \n\"" );
- return;
- }
-
- if( !targetname[ 0 ] )
+ if( !arg[ 0 ] )
{
trap_SendServerCommand( ent-g_entities,
- "print \"callvote: no target\n\"" );
+ va( "print \"%s: no target\n\"", cmd ) );
return;
}
- numMatches = G_ClientNumbersFromString( targetname, clientNums );
- if( numMatches == 1 )
- {
- // there was only one partial name match
- clientNum = clientNums[ 0 ];
- }
- else
- {
- // look for an exact name match (sets clientNum to -1 if it fails)
- clientNum = G_ClientNumberFromString( ent, targetname );
- }
-
- if( clientNum==-1 && numMatches > 1 )
+ // with a little extra work only players from the right team are considered
+ clientNum = G_ClientNumberFromString( arg, err, sizeof( err ) );
+
+ if( clientNum == -1 )
{
- G_MatchOnePlayer( clientNums, err, sizeof( err ) );
- ADMP( va( "^3callvote: ^7%s\n", err ) );
+ ADMP( va( "%s: %s", cmd, err ) );
return;
}
-
- if( clientNum != -1 &&
- level.clients[ clientNum ].pers.connected != CON_CONNECTED )
- {
- clientNum = -1;
- }
- if( clientNum != -1 )
+ G_DecolorString( level.clients[ clientNum ].pers.netname, name, sizeof( name ) );
+ id = level.clients[ clientNum ].pers.namelog->id;
+
+ if( !Q_stricmp( vote, "kick" ) || !Q_stricmp( vote, "mute" ) ||
+ !Q_stricmp( vote, "denybuild" ) )
{
- Q_strncpyz( name, level.clients[ clientNum ].pers.netname,
- sizeof( name ) );
- Q_CleanStr( name );
- if ( G_admin_permission ( &g_entities[ clientNum ], ADMF_IMMUNITY ) )
+ if( G_admin_permission( g_entities + clientNum, ADMF_IMMUNITY ) )
{
- char reasonprint[ MAX_STRING_CHARS ] = "";
-
- if( reason[ 0 ] != '\0' )
- Com_sprintf(reasonprint, sizeof(reasonprint), "With reason: %s", reason);
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: admin is immune\n\"", cmd ) );
+
+ G_AdminMessage( NULL, va( S_COLOR_WHITE "%s" S_COLOR_YELLOW " attempted %s %s"
+ " on immune admin " S_COLOR_WHITE "%s" S_COLOR_YELLOW
+ " for: %s",
+ ent->client->pers.netname, cmd, vote,
+ g_entities[ clientNum ].client->pers.netname,
+ reason[ 0 ] ? reason : "no reason" ) );
+ return;
+ }
- Com_sprintf( message, sizeof( message ), "%s^7 attempted /callvote %s %s on immune admin %s^7 %s^7",
- ent->client->pers.netname, arg1, targetname, g_entities[ clientNum ].client->pers.netname, reasonprint );
+ if( team != TEAM_NONE &&
+ ( ent->client->pers.teamSelection !=
+ level.clients[ clientNum ].pers.teamSelection ) )
+ {
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: player is not on your team\n\"", cmd ) );
+ return;
}
- }
- else
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callvote: invalid player\n\"" );
- return;
- }
- }
-
- if( !Q_stricmp( arg1, "kick" ) )
- {
- if( G_admin_permission( &g_entities[ clientNum ], ADMF_IMMUNITY ) )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callvote: admin is immune from vote kick\n\"" );
- G_AdminsPrintf("%s\n",message);
- G_admin_adminlog_log( ent, "vote", NULL, 0, qfalse );
- return;
- }
- // use ip in case this player disconnects before the vote ends
- Com_sprintf( level.voteString, sizeof( level.voteString ),
- "!ban %s \"%s\" vote kick", level.clients[ clientNum ].pers.ip,
- g_adminTempBan.string );
- if ( reason[0]!='\0' )
- Q_strcat( level.voteString, sizeof( level.voteDisplayString ), va( "(%s^7)", reason ) );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ),
- "Kick player \'%s\'", name );
- }
- else if( !Q_stricmp( arg1, "spec" ) )
- {
- if( G_admin_permission( &g_entities[ clientNum ], ADMF_IMMUNITY ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"callvote: admin is immune from vote spec\n\"" );
- return;
+ if( !reason[ 0 ] && !G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
+ {
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: You must provide a reason\n\"", cmd ) );
+ return;
+ }
}
- Com_sprintf( level.voteString, sizeof( level.voteString ), "!putteam %i s %s", clientNum, g_adminTempSpec.string );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Spec player \'%s\'", name );
-
}
- else if( !Q_stricmp( arg1, "mute" ) )
- {
- if( G_IsMuted( &level.clients[ clientNum ] ) )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callvote: player is already muted\n\"" );
- return;
- }
- if( G_admin_permission( &g_entities[ clientNum ], ADMF_IMMUNITY ) )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callvote: admin is immune from vote mute\n\"" );
- G_AdminsPrintf("%s\n",message);
- G_admin_adminlog_log( ent, "vote", NULL, 0, qfalse );
- return;
- }
- Com_sprintf( level.voteString, sizeof( level.voteString ),
- "!mute %i %s", clientNum, g_adminTempMute.string );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ),
- "Mute player \'%s\'", name );
- }
- else if( !Q_stricmp( arg1, "unmute" ) )
+ if( !Q_stricmp( vote, "kick" ) )
{
- if( !G_IsMuted( &level.clients[ clientNum ] ) )
+ if( level.clients[ clientNum ].pers.localClient )
{
trap_SendServerCommand( ent-g_entities,
- "print \"callvote: player is not currently muted\n\"" );
- return;
- }
- Com_sprintf( level.voteString, sizeof( level.voteString ),
- "!unmute %i", clientNum );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ),
- "Un-Mute player \'%s\'", name );
- }
- else if( !Q_stricmp( arg1, "map_restart" ) )
- {
- if( g_mapvoteMaxTime.integer
- && (( level.time - level.startTime ) >= g_mapvoteMaxTime.integer * 1000 )
- && !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT )
- && (level.numPlayingClients > 0 && level.numConnectedClients>1) )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"You cannot call for a restart after %d seconds\n\"",
- g_mapvoteMaxTime.integer ) );
- G_admin_adminlog_log( ent, "vote", NULL, 0, qfalse );
- return;
- }
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s", arg1 );
- Com_sprintf( level.voteDisplayString,
- sizeof( level.voteDisplayString ), "Restart current map" );
- level.votePassThreshold = g_mapVotesPercent.integer;
- }
- else if( !Q_stricmp( arg1, "map" ) )
- {
- if( g_mapvoteMaxTime.integer
- && (( level.time - level.startTime ) >= g_mapvoteMaxTime.integer * 1000 )
- && !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT )
- && (level.numPlayingClients > 0 && level.numConnectedClients>1) )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"You cannot call for a mapchange after %d seconds\n\"",
- g_mapvoteMaxTime.integer ) );
- G_admin_adminlog_log( ent, "vote", NULL, 0, qfalse );
- return;
- }
-
- if( !G_MapExists( arg2 ) )
- {
- trap_SendServerCommand( ent - g_entities, va( "print \"callvote: "
- "'maps/%s.bsp' could not be found on the server\n\"", arg2 ) );
+ va( "print \"%s: admin is immune\n\"", cmd ) );
return;
}
- if( !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT ) && !map_is_votable( arg2 ) )
+ Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
+ "ban %s \"1s%s\" vote kick (%s)", level.clients[ clientNum ].pers.ip.str,
+ g_adminTempBan.string, reason );
+ Com_sprintf( level.voteDisplayString[ team ],
+ sizeof( level.voteDisplayString[ team ] ), "Kick player '%s'", name );
+ if( reason[ 0 ] )
{
- trap_SendServerCommand( ent - g_entities, va( "print \"callvote: "
- "Only admins may call a vote for map: %s\n\"", arg2 ) );
- return;
+ Q_strcat( level.voteDisplayString[ team ],
+ sizeof( level.voteDisplayString[ team ] ), va( " for '%s'", reason ) );
}
-
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %s", arg1, arg2 );
- Com_sprintf( level.voteDisplayString,
- sizeof( level.voteDisplayString ), "Change to map '%s'", arg2 );
- level.votePassThreshold = g_mapVotesPercent.integer;
}
- else if( !Q_stricmp( arg1, "nextmap" ) )
+ else if( team == TEAM_NONE )
{
- if( G_MapExists( g_nextMap.string ) )
- {
- trap_SendServerCommand( ent - g_entities, va( "print \"callvote: "
- "the next map is already set to '%s^7'\n\"", g_nextMap.string ) );
- return;
- }
-
- if( !arg2[ 0 ] )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callvote: you must specify a map\n\"" );
- return;
- }
-
- if( !G_MapExists( arg2 ) )
+ if( !Q_stricmp( vote, "mute" ) )
{
- trap_SendServerCommand( ent - g_entities, va( "print \"callvote: "
- "'maps/%s^7.bsp' could not be found on the server\n\"", arg2 ) );
- return;
- }
+ if( level.clients[ clientNum ].pers.namelog->muted )
+ {
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: player is already muted\n\"", cmd ) );
+ return;
+ }
- if( !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT ) && !map_is_votable( arg2 ) )
- {
- trap_SendServerCommand( ent - g_entities, va( "print \"callvote: "
- "Only admins may call a vote for map: %s\n\"", arg2 ) );
- return;
+ Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
+ "mute %d", id );
+ Com_sprintf( level.voteDisplayString[ team ],
+ sizeof( level.voteDisplayString[ team ] ),
+ "Mute player '%s'", name );
+ if( reason[ 0 ] )
+ {
+ Q_strcat( level.voteDisplayString[ team ],
+ sizeof( level.voteDisplayString[ team ] ), va( " for '%s'", reason ) );
+ }
}
-
- Com_sprintf( level.voteString, sizeof( level.voteString ),
- "set g_nextMap %s", arg2 );
- Com_sprintf( level.voteDisplayString,
- sizeof( level.voteDisplayString ), "Set the next map to '%s^7'", arg2 );
- level.votePassThreshold = g_mapVotesPercent.integer;
- }
- else if( !Q_stricmp( arg1, "draw" ) )
- {
- Com_sprintf( level.voteString, sizeof( level.voteString ), "evacuation" );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ),
- "End match in a draw" );
- level.votePassThreshold = g_mapVotesPercent.integer;
- }
- else if( !Q_stricmp( arg1, "poll" ) )
+ else if( !Q_stricmp( vote, "unmute" ) )
{
- if( arg2plus[ 0 ] == '\0' )
+ if( !level.clients[ clientNum ].pers.namelog->muted )
{
- trap_SendServerCommand( ent-g_entities, "print \"callvote: You forgot to specify what people should vote on.\n\"" );
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: player is not currently muted\n\"", cmd ) );
return;
}
- level.voteString[ 0 ] = '\0';
- Com_sprintf( level.voteDisplayString,
- sizeof( level.voteDisplayString ), "[Poll] \'%s\'", arg2plus );
- }
- else if( !Q_stricmp( arg1, "sudden_death" ) ||
- !Q_stricmp( arg1, "suddendeath" ) )
- {
- if(!g_suddenDeathVotePercent.integer)
- {
- trap_SendServerCommand( ent-g_entities, "print \"Sudden Death votes have been disabled\n\"" );
- return;
- }
- else if( g_suddenDeath.integer )
- {
- trap_SendServerCommand( ent - g_entities, va( "print \"callvote: Sudden Death has already begun\n\"") );
- return;
- }
- else if( G_TimeTilSuddenDeath() <= g_suddenDeathVoteDelay.integer * 1000 )
- {
- trap_SendServerCommand( ent - g_entities, va( "print \"callvote: Sudden Death is already immenent\n\"") );
- return;
- }
- else
- {
- level.votePassThreshold = g_suddenDeathVotePercent.integer;
- Com_sprintf( level.voteString, sizeof( level.voteString ), "suddendeath" );
- Com_sprintf( level.voteDisplayString,
- sizeof( level.voteDisplayString ), "Begin sudden death" );
-
- if( g_suddenDeathVoteDelay.integer )
- Q_strcat( level.voteDisplayString, sizeof( level.voteDisplayString ), va( " in %d seconds", g_suddenDeathVoteDelay.integer ) );
-
- }
- }
- else if( !Q_stricmp( arg1, "extend" ) )
- {
- if( !g_extendVotesPercent.integer )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Extend votes have been disabled\n\"" );
- return;
- }
- if( g_extendVotesCount.integer
- && level.extend_vote_count >= g_extendVotesCount.integer )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"callvote: Maximum number of %d extend votes has been reached\n\"",
- g_extendVotesCount.integer ) );
- return;
- }
- if( !g_timelimit.integer ) {
- trap_SendServerCommand( ent-g_entities,
- "print \"This match has no timelimit so extend votes wont work\n\"" );
- return;
- }
- if( level.time - level.startTime <
- ( g_timelimit.integer - g_extendVotesTime.integer / 2 ) * 60000 )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"callvote: Extend votes only allowed with less than %d minutes remaining\n\"",
- g_extendVotesTime.integer / 2 ) );
- return;
- }
- level.extend_vote_count++;
- level.votePassThreshold = g_extendVotesPercent.integer;
- Com_sprintf( level.voteString, sizeof( level.voteString ),
- "timelimit %i", g_timelimit.integer + g_extendVotesTime.integer );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ),
- "Extend the timelimit by %d minutes", g_extendVotesTime.integer );
- }
- else
- {
- qboolean match = qfalse;
- char customVoteKeys[ MAX_STRING_CHARS ];
- customVoteKeys[ 0 ] = '\0';
- if( g_customVotePercent.integer )
+ Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
+ "unmute %d", id );
+ Com_sprintf( level.voteDisplayString[ team ],
+ sizeof( level.voteDisplayString[ team ] ),
+ "Unmute player '%s'", name );
+ }
+ else if( !Q_stricmp( vote, "map_restart" ) )
{
- char text[ MAX_STRING_CHARS ];
- char *votekey, *votemsg, *votecmd, *voteperc;
- int votePValue;
-
- text[ 0 ] = '\0';
- for( i = 0; i < CUSTOM_VOTE_COUNT; i++ )
+ if( arg[ 0 ] )
{
- switch( i )
- {
- case 0:
- Q_strncpyz( text, g_customVote1.string, sizeof( text ) );
- break;
- case 1:
- Q_strncpyz( text, g_customVote2.string, sizeof( text ) );
- break;
- case 2:
- Q_strncpyz( text, g_customVote3.string, sizeof( text ) );
- break;
- case 3:
- Q_strncpyz( text, g_customVote4.string, sizeof( text ) );
- break;
- case 4:
- Q_strncpyz( text, g_customVote5.string, sizeof( text ) );
- break;
- case 5:
- Q_strncpyz( text, g_customVote6.string, sizeof( text ) );
- break;
- case 6:
- Q_strncpyz( text, g_customVote7.string, sizeof( text ) );
- break;
- case 7:
- Q_strncpyz( text, g_customVote8.string, sizeof( text ) );
- break;
- }
- if ( text[ 0 ] == '\0' )
- continue;
+ char map[ MAX_QPATH ];
+ trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
- // custom vote cvar format: "callvote_name,Vote message string,vote success command[,percent]"
- votekey = text;
- votemsg = strchr( votekey, ',' );
- if( !votemsg || *votemsg != ',' )
- continue;
- *votemsg = '\0';
- votemsg++;
- Q_strcat( customVoteKeys, sizeof( customVoteKeys ),
- va( "%s%s", ( customVoteKeys[ 0 ] == '\0' ) ? "" : ", ", votekey ) );
- votecmd = strchr( votemsg, ',' );
- if( !votecmd || *votecmd != ',' )
- continue;
- *votecmd = '\0';
- votecmd++;
-
- voteperc = strchr( votecmd, ',' );
- if( !voteperc || *voteperc != ',' )
- votePValue = g_customVotePercent.integer;
- else
+ if( !G_LayoutExists( map, arg ) )
{
- *voteperc = '\0';
- voteperc++;
- votePValue = atoi( voteperc );
- if( !votePValue )
- votePValue = g_customVotePercent.integer;
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: layout '%s' does not exist for map '%s'\n\"",
+ cmd, arg, map ) );
+ return;
}
-
- if( Q_stricmp( arg1, votekey ) != 0 )
- continue;
- if( votemsg[ 0 ] == '\0' || votecmd[ 0 ] == '\0' )
- continue;
-
- level.votePassThreshold = votePValue;
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s", votecmd );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", votemsg );
- match = qtrue;
- break;
}
- }
-
- if( !match )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" );
- trap_SendServerCommand( ent-g_entities, "print \"Valid vote commands are: "
- "map, map_restart, draw, extend, nextmap, kick, spec, mute, unmute, poll, and sudden_death\n" );
- if( customVoteKeys[ 0 ] != '\0' )
- trap_SendServerCommand( ent-g_entities,
- va( "print \"Additional custom vote commands: %s\n\"", customVoteKeys ) );
- return;
- }
- }
-
- if( level.votePassThreshold!=50 )
- {
- Q_strcat( level.voteDisplayString, sizeof( level.voteDisplayString ), va( "^7 (Needs > %d percent)", level.votePassThreshold ) );
- }
-
- if ( reason[0]!='\0' )
- Q_strcat( level.voteDisplayString, sizeof( level.voteDisplayString ), va( " Reason: '%s^7'", reason ) );
-
- G_admin_adminlog_log( ent, "vote", NULL, 0, qtrue );
-
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE
- " called a vote: %s" S_COLOR_WHITE "\n\"", ent->client->pers.netname, level.voteDisplayString ) );
-
- G_LogPrintf("Vote: %s^7 called a vote: %s^7\n", ent->client->pers.netname, level.voteDisplayString );
-
- Q_strcat( level.voteDisplayString, sizeof( level.voteDisplayString ), va( " Called by: '%s^7'", ent->client->pers.netname ) );
-
- ent->client->pers.voteCount++;
-
- // start the voting, the caller autoamtically votes yes
- level.voteTime = level.time;
- level.voteNo = 0;
-
- for( i = 0 ; i < level.maxclients ; i++ )
- level.clients[i].ps.eFlags &= ~EF_VOTED;
-
- if( !Q_stricmp( arg1, "poll" ) )
- {
- level.voteYes = 0;
- }
- else
- {
- level.voteYes = 1;
- ent->client->ps.eFlags |= EF_VOTED;
- }
-
- trap_SetConfigstring( CS_VOTE_TIME, va( "%i", level.voteTime ) );
- trap_SetConfigstring( CS_VOTE_STRING, level.voteDisplayString );
- trap_SetConfigstring( CS_VOTE_YES, va( "%i", level.voteYes ) );
- trap_SetConfigstring( CS_VOTE_NO, va( "%i", level.voteNo ) );
-}
-
-/*
-==================
-Cmd_Vote_f
-==================
-*/
-void Cmd_Vote_f( gentity_t *ent )
-{
- char msg[ 64 ];
-
- if ( level.intermissiontime || level.paused )
- {
- if( level.mapRotationVoteTime )
- {
- trap_Argv( 1, msg, sizeof( msg ) );
- if( msg[ 0 ] == 'y' || msg[ 1 ] == 'Y' || msg[ 1 ] == '1' )
- G_IntermissionMapVoteCommand( ent, qfalse, qtrue );
+ Com_sprintf( level.voteDisplayString[ team ], sizeof( level.voteDisplayString[ team ] ),
+ "Restart the current map%s", arg[ 0 ] ? va( " with layout '%s'", arg ) : "" );
+ Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
+ "set g_nextMap \"\" ; set g_nextLayout \"%s\" ; %s", arg, vote );
+ // map_restart comes with a default delay
}
-
- return;
- }
-
- if( !level.voteTime )
- {
- if( ent->client->pers.teamSelection != PTE_NONE )
+ else if( !Q_stricmp( vote, "map" ) )
{
- // If there is a teamvote going on but no global vote, forward this vote on as a teamvote
- // (ugly hack for 1.1 cgames + noobs who can't figure out how to use any command that isn't bound by default)
- int cs_offset = 0;
- if( ent->client->pers.teamSelection == PTE_ALIENS )
- cs_offset = 1;
-
- if( level.teamVoteTime[ cs_offset ] )
+ if( !G_MapExists( arg ) )
{
- if( !(ent->client->ps.eFlags & EF_TEAMVOTED ) )
- {
- Cmd_TeamVote_f(ent);
- return;
- }
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: 'maps/%s.bsp' could not be found on the server\n\"",
+ cmd, arg ) );
+ return;
}
- }
- trap_SendServerCommand( ent-g_entities, "print \"No vote in progress\n\"" );
- return;
- }
-
- if( ent->client->ps.eFlags & EF_VOTED )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Vote already cast\n\"" );
- return;
- }
-
- trap_SendServerCommand( ent-g_entities, "print \"Vote cast\n\"" );
- ent->client->ps.eFlags |= EF_VOTED;
-
- trap_Argv( 1, msg, sizeof( msg ) );
-
- if( msg[ 0 ] == 'y' || msg[ 1 ] == 'Y' || msg[ 1 ] == '1' )
- {
- level.voteYes++;
- trap_SetConfigstring( CS_VOTE_YES, va( "%i", level.voteYes ) );
- }
- else
- {
- level.voteNo++;
- trap_SetConfigstring( CS_VOTE_NO, va( "%i", level.voteNo ) );
- }
-
- // a majority will be determined in G_CheckVote, which will also account
- // for players entering or leaving
-}
-
-/*
-==================
-Cmd_CallTeamVote_f
-==================
-*/
-void Cmd_CallTeamVote_f( gentity_t *ent )
-{
- int i, team, cs_offset = 0;
- char arg1[ MAX_STRING_TOKENS ];
- char arg2[ MAX_STRING_TOKENS ];
- int clientNum = -1;
- char name[ MAX_NETNAME ];
- char message[ MAX_STRING_CHARS ];
- char targetname[ MAX_NAME_LENGTH] = "";
- char reason[ MAX_STRING_CHARS ] = "";
- char *arg1plus;
- char *arg2plus;
- char *ptr = NULL;
- int numVoters = 0;
-
- arg1plus = G_SayConcatArgs( 1 );
- arg2plus = G_SayConcatArgs( 2 );
-
- team = ent->client->pers.teamSelection;
-
- if( team == PTE_ALIENS )
- cs_offset = 1;
-
- if(team==PTE_ALIENS)
- numVoters = level.numAlienClients;
- else if(team==PTE_HUMANS)
- numVoters = level.numHumanClients;
-
- if( !g_allowVote.integer )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here\n\"" );
- return;
- }
-
- if( level.teamVoteTime[ cs_offset ] )
- {
- trap_SendServerCommand( ent-g_entities, "print \"A team vote is already in progress\n\"" );
- return;
- }
-
- //see if they can vote
- if( G_admin_permission( ent, ADMF_NO_VOTE ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You have no voting rights\n\"" );
- return;
- }
-
- if( g_voteLimit.integer > 0
- && ent->client->pers.voteCount >= g_voteLimit.integer
- && !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT ) )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"You have already called the maximum number of votes (%d)\n\"",
- g_voteLimit.integer ) );
- return;
- }
-
- if( G_IsMuted( ent->client ) )
- {
- trap_SendServerCommand( ent - g_entities,
- "print \"You are muted and cannot call teamvotes\n\"" );
- return;
- }
-
- if( g_voteMinTime.integer
- && ent->client->pers.firstConnect
- && level.time - ent->client->pers.enterTime < g_voteMinTime.integer * 1000
- && !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT )
- && (level.numPlayingClients > 0 && level.numConnectedClients>1) )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"You must wait %d seconds after connecting before calling a vote\n\"",
- g_voteMinTime.integer ) );
- return;
- }
-
- // make sure it is a valid command to vote on
- trap_Argv( 1, arg1, sizeof( arg1 ) );
- trap_Argv( 2, arg2, sizeof( arg2 ) );
-
- if( strchr( arg1plus, ';' ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid team vote string\n\"" );
- return;
- }
-
- ptr = strstr(arg1plus, " -");
- if( ptr )
- {
- *ptr = '\0';
- ptr+=2;
+ if( extra[ 0 ] && !G_LayoutExists( arg, extra ) )
+ {
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: layout '%s' does not exist for map '%s'\n\"",
+ cmd, extra, arg ) );
+ return;
+ }
- if( *ptr == 'r' || *ptr=='R' )
- {
- ptr++;
- while( *ptr == ' ' )
- ptr++;
- strcpy(reason, ptr);
+ Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
+ "set g_nextMap \"\" ; set g_nextLayout \"%s\" ; %s \"%s\"", extra, vote, arg );
+ Com_sprintf( level.voteDisplayString[ team ], sizeof( level.voteDisplayString[ team ] ),
+ "Change to map '%s'%s", arg, extra[ 0 ] ? va( " with layout '%s'", extra ) : "" );
+ level.voteDelay[ team ] = 3000;
}
- else
+ else if( !Q_stricmp( vote, "nextmap" ) )
{
- trap_SendServerCommand( ent-g_entities, "print \"callteamvote: Warning: invalid argument specified \n\"" );
- }
- }
-
- // detect clientNum for partial name match votes
- if( !Q_stricmp( arg1, "kick" ) ||
- !Q_stricmp( arg1, "denybuild" ) ||
- !Q_stricmp( arg1, "allowbuild" ) ||
- !Q_stricmp( arg1, "designate" ) ||
- !Q_stricmp( arg1, "undesignate" ) )
- {
- int clientNums[ MAX_CLIENTS ] = { -1 };
- int numMatches=0;
- char err[ MAX_STRING_CHARS ];
-
- Q_strncpyz(targetname, arg2plus, sizeof(targetname));
- ptr = strstr(targetname, " -");
- if( ptr )
- *ptr = '\0';
-
- if( g_requireVoteReasons.integer && !G_admin_permission( ent, ADMF_UNACCOUNTABLE ) && !Q_stricmp( arg1, "kick" ) && reason[ 0 ]=='\0' )
- {
- trap_SendServerCommand( ent-g_entities, "print \"callvote: You must specify a reason. Use /callteamvote kick [player] -r [reason] \n\"" );
- return;
- }
-
+ if( G_MapExists( g_nextMap.string ) &&
+ ( !g_nextLayout.string[ 0 ] || G_LayoutExists( g_nextMap.string, g_nextLayout.string ) ) )
+ {
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: the next map is already set to '%s'%s\n\"",
+ cmd, g_nextMap.string,
+ g_nextLayout.string[ 0 ] ? va( " with layout '%s'", g_nextLayout.string ) : "" ) );
+ return;
+ }
- if( !arg2[ 0 ] )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callteamvote: no target\n\"" );
- return;
- }
+ if( !G_MapExists( arg ) )
+ {
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: 'maps/%s.bsp' could not be found on the server\n\"",
+ cmd, arg ) );
+ return;
+ }
- numMatches = G_ClientNumbersFromString( targetname, clientNums );
- if( numMatches == 1 )
- {
- // there was only one partial name match
- clientNum = clientNums[ 0 ];
- }
- else
- {
- // look for an exact name match (sets clientNum to -1 if it fails)
- clientNum = G_ClientNumberFromString( ent, targetname );
- }
-
- if( clientNum==-1 && numMatches > 1 )
- {
- G_MatchOnePlayer( clientNums, err, sizeof( err ) );
- ADMP( va( "^3callteamvote: ^7%s\n", err ) );
- return;
- }
+ if( extra[ 0 ] && !G_LayoutExists( arg, extra ) )
+ {
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: layout '%s' does not exist for map '%s'\n\"",
+ cmd, extra, arg ) );
+ return;
+ }
- // make sure this player is on the same team
- if( clientNum != -1 && level.clients[ clientNum ].pers.teamSelection !=
- team )
- {
- clientNum = -1;
+ Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
+ "set g_nextMap \"%s\" ; set g_nextLayout \"%s\"", arg, extra );
+ Com_sprintf( level.voteDisplayString[ team ], sizeof( level.voteDisplayString[ team ] ),
+ "Set the next map to '%s'%s", arg, extra[ 0 ] ? va( " with layout '%s'", extra ) : "" );
}
-
- if( clientNum != -1 &&
- level.clients[ clientNum ].pers.connected == CON_DISCONNECTED )
+ else if( !Q_stricmp( vote, "draw" ) )
{
- clientNum = -1;
+ strcpy( level.voteString[ team ], "evacuation" );
+ strcpy( level.voteDisplayString[ team ], "End match in a draw" );
+ level.voteDelay[ team ] = 3000;
}
-
- if( clientNum != -1 )
+ else if( !Q_stricmp( vote, "sudden_death" ) )
{
- Q_strncpyz( name, level.clients[ clientNum ].pers.netname,
- sizeof( name ) );
- Q_CleanStr( name );
- if( G_admin_permission( &g_entities[ clientNum ], ADMF_IMMUNITY ) )
+ if(!g_suddenDeathVotePercent.integer)
{
- char reasonprint[ MAX_STRING_CHARS ] = "";
- if( reason[ 0 ] != '\0' )
- Com_sprintf(reasonprint, sizeof(reasonprint), "With reason: %s", reason);
-
- Com_sprintf( message, sizeof( message ), "%s^7 attempted /callteamvote %s %s on immune admin %s^7 %s^7",
- ent->client->pers.netname, arg1, arg2, g_entities[ clientNum ].client->pers.netname, reasonprint );
+ trap_SendServerCommand( ent-g_entities,
+ "print \"Sudden Death votes have been disabled\n\"" );
+ return;
+ }
+ if( G_TimeTilSuddenDeath( ) <= 0 )
+ {
+ trap_SendServerCommand( ent - g_entities,
+ va( "print \"callvote: Sudden Death has already begun\n\"") );
+ return;
}
+ if( level.suddenDeathBeginTime > 0 &&
+ G_TimeTilSuddenDeath() <= g_suddenDeathVoteDelay.integer * 1000 )
+ {
+ trap_SendServerCommand( ent - g_entities,
+ va( "print \"callvote: Sudden Death is imminent\n\"") );
+ return;
+ }
+ level.voteThreshold[ team ] = g_suddenDeathVotePercent.integer;
+ Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
+ "suddendeath %d", g_suddenDeathVoteDelay.integer );
+ Com_sprintf( level.voteDisplayString[ team ],
+ sizeof( level.voteDisplayString[ team ] ),
+ "Begin sudden death in %d seconds",
+ g_suddenDeathVoteDelay.integer );
}
else
{
- trap_SendServerCommand( ent-g_entities,
- "print \"callteamvote: invalid player\n\"" );
- return;
- }
- }
-
- if( !Q_stricmp( arg1, "kick" ) )
- {
- if( G_admin_permission( &g_entities[ clientNum ], ADMF_IMMUNITY ) )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callteamvote: admin is immune from vote kick\n\"" );
- G_AdminsPrintf("%s\n",message);
- G_admin_adminlog_log( ent, "teamvote", NULL, 0, qfalse );
+ trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" );
+ trap_SendServerCommand( ent-g_entities, "print \"Valid vote commands are: "
+ "map, nextmap, map_restart, draw, sudden_death, kick, mute and unmute\n" );
return;
}
-
-
- // use ip in case this player disconnects before the vote ends
- Com_sprintf( level.teamVoteString[ cs_offset ],
- sizeof( level.teamVoteString[ cs_offset ] ),
- "!ban %s \"%s\" team vote kick", level.clients[ clientNum ].pers.ip,
- g_adminTempBan.string );
- Com_sprintf( level.teamVoteDisplayString[ cs_offset ],
- sizeof( level.teamVoteDisplayString[ cs_offset ] ),
- "Kick player '%s'", name );
}
- else if( !Q_stricmp( arg1, "denybuild" ) )
+ else if( !Q_stricmp( vote, "denybuild" ) )
{
- if( level.clients[ clientNum ].pers.denyBuild )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callteamvote: player already lost building rights\n\"" );
- return;
- }
-
- if( G_admin_permission( &g_entities[ clientNum ], ADMF_IMMUNITY ) )
+ if( level.clients[ clientNum ].pers.namelog->denyBuild )
{
trap_SendServerCommand( ent-g_entities,
- "print \"callteamvote: admin is immune from denybuild\n\"" );
- G_AdminsPrintf("%s\n",message);
- G_admin_adminlog_log( ent, "teamvote", NULL, 0, qfalse );
+ va( "print \"%s: player already lost building rights\n\"", cmd ) );
return;
}
- Com_sprintf( level.teamVoteString[ cs_offset ],
- sizeof( level.teamVoteString[ cs_offset ] ), "!denybuild %i", clientNum );
- Com_sprintf( level.teamVoteDisplayString[ cs_offset ],
- sizeof( level.teamVoteDisplayString[ cs_offset ] ),
- "Take away building rights from '%s'", name );
- }
- else if( !Q_stricmp( arg1, "allowbuild" ) )
- {
- if( !level.clients[ clientNum ].pers.denyBuild )
+ Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
+ "denybuild %d", id );
+ Com_sprintf( level.voteDisplayString[ team ],
+ sizeof( level.voteDisplayString[ team ] ),
+ "Take away building rights from '%s'", name );
+ if( reason[ 0 ] )
{
- trap_SendServerCommand( ent-g_entities,
- "print \"callteamvote: player already has building rights\n\"" );
- return;
+ Q_strcat( level.voteDisplayString[ team ],
+ sizeof( level.voteDisplayString[ team ] ), va( " for '%s'", reason ) );
}
-
- Com_sprintf( level.teamVoteString[ cs_offset ],
- sizeof( level.teamVoteString[ cs_offset ] ), "!allowbuild %i", clientNum );
- Com_sprintf( level.teamVoteDisplayString[ cs_offset ],
- sizeof( level.teamVoteDisplayString[ cs_offset ] ),
- "Allow '%s' to build", name );
}
- else if( !Q_stricmp( arg1, "designate" ) )
+ else if( !Q_stricmp( vote, "allowbuild" ) )
{
- if( !g_designateVotes.integer )
+ if( !level.clients[ clientNum ].pers.namelog->denyBuild )
{
trap_SendServerCommand( ent-g_entities,
- "print \"callteamvote: Designate votes have been disabled.\n\"" );
+ va( "print \"%s: player already has building rights\n\"", cmd ) );
return;
}
- if( level.clients[ clientNum ].pers.designatedBuilder )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callteamvote: player is already a designated builder\n\"" );
- return;
- }
- Com_sprintf( level.teamVoteString[ cs_offset ],
- sizeof( level.teamVoteString[ cs_offset ] ), "!designate %i", clientNum );
- Com_sprintf( level.teamVoteDisplayString[ cs_offset ],
- sizeof( level.teamVoteDisplayString[ cs_offset ] ),
- "Make '%s' a designated builder", name );
+ Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
+ "allowbuild %d", id );
+ Com_sprintf( level.voteDisplayString[ team ],
+ sizeof( level.voteDisplayString[ team ] ),
+ "Allow '%s' to build", name );
}
- else if( !Q_stricmp( arg1, "undesignate" ) )
+ else if( !Q_stricmp( vote, "admitdefeat" ) )
{
-
- if( !g_designateVotes.integer )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callteamvote: Designate votes have been disabled.\n\"" );
- return;
- }
-
- if( !level.clients[ clientNum ].pers.designatedBuilder )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callteamvote: player is not currently a designated builder\n\"" );
- return;
- }
- Com_sprintf( level.teamVoteString[ cs_offset ],
- sizeof( level.teamVoteString[ cs_offset ] ), "!undesignate %i", clientNum );
- Com_sprintf( level.teamVoteDisplayString[ cs_offset ],
- sizeof( level.teamVoteDisplayString[ cs_offset ] ),
- "Remove designated builder status from '%s'", name );
+ Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
+ "admitdefeat %d", team );
+ strcpy( level.voteDisplayString[ team ], "Admit Defeat" );
+ level.voteDelay[ team ] = 3000;
}
- else if( !Q_stricmp( arg1, "admitdefeat" ) )
- {
- if( numVoters <=1 )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"callteamvote: You cannot admitdefeat by yourself. Use /callvote draw.\n\"" );
- return;
- }
-
- Com_sprintf( level.teamVoteString[ cs_offset ],
- sizeof( level.teamVoteString[ cs_offset ] ), "admitdefeat %i", team );
- Com_sprintf( level.teamVoteDisplayString[ cs_offset ],
- sizeof( level.teamVoteDisplayString[ cs_offset ] ),
- "Admit Defeat" );
- }
- else if( !Q_stricmp( arg1, "poll" ) )
- {
- if( arg2plus[ 0 ] == '\0' )
- {
- trap_SendServerCommand( ent-g_entities, "print \"callteamvote: You forgot to specify what people should vote on.\n\"" );
- return;
- }
- level.teamVoteString[ cs_offset ][ 0 ] = '\0';
- Com_sprintf( level.teamVoteDisplayString[ cs_offset ],
- sizeof( level.voteDisplayString ), "[Poll] \'%s\'", arg2plus );
- }
else
{
trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" );
trap_SendServerCommand( ent-g_entities,
"print \"Valid team vote commands are: "
- "kick, denybuild, allowbuild, poll, designate, undesignate, and admitdefeat\n\"" );
+ "kick, denybuild, allowbuild and admitdefeat\n\"" );
return;
}
- ent->client->pers.voteCount++;
- G_admin_adminlog_log( ent, "teamvote", arg1, 0, qtrue );
-
- if ( reason[0]!='\0' )
- Q_strcat( level.teamVoteDisplayString[ cs_offset ], sizeof( level.teamVoteDisplayString[ cs_offset ] ), va( " Reason: '%s'^7", reason ) );
+ G_LogPrintf( "%s: %d \"%s" S_COLOR_WHITE "\": %s\n",
+ team == TEAM_NONE ? "CallVote" : "CallTeamVote",
+ (int)( ent - g_entities ), ent->client->pers.netname, level.voteString[ team ] );
- for( i = 0 ; i < level.maxclients ; i++ )
+ if( team == TEAM_NONE )
{
- if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
- continue;
+ trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE
+ " called a vote: %s\n\"", ent->client->pers.netname,
+ level.voteDisplayString[ team ] ) );
+ }
+ else
+ {
+ int i;
- if( level.clients[ i ].ps.stats[ STAT_PTEAM ] == team )
- {
- trap_SendServerCommand( i, va("print \"%s " S_COLOR_WHITE
- "called a team vote: %s^7 \n\"", ent->client->pers.netname, level.teamVoteDisplayString[ cs_offset ] ) );
- }
- else if( G_admin_permission( &g_entities[ i ], ADMF_ADMINCHAT ) &&
- ( ( !Q_stricmp( arg1, "kick" ) || !Q_stricmp( arg1, "denybuild" ) ) ||
- level.clients[ i ].pers.teamSelection == PTE_NONE ) )
+ for( i = 0 ; i < level.maxclients ; i++ )
{
- trap_SendServerCommand( i, va("print \"^6[Admins]^7 %s " S_COLOR_WHITE
- "called a team vote: %s^7 \n\"", ent->client->pers.netname, level.teamVoteDisplayString[ cs_offset ] ) );
+ if( level.clients[ i ].pers.connected == CON_CONNECTED )
+ {
+ if( level.clients[ i ].pers.teamSelection == team ||
+ ( level.clients[ i ].pers.teamSelection == TEAM_NONE &&
+ G_admin_permission( &g_entities[ i ], ADMF_SPEC_ALLCHAT ) ) )
+ {
+ trap_SendServerCommand( i, va( "print \"%s" S_COLOR_WHITE
+ " called a team vote: %s\n\"", ent->client->pers.netname,
+ level.voteDisplayString[ team ] ) );
+ }
+ else if( G_admin_permission( &g_entities[ i ], ADMF_ADMINCHAT ) )
+ {
+ trap_SendServerCommand( i, va( "chat -1 %d \"" S_COLOR_YELLOW "%s"
+ S_COLOR_YELLOW " called a team vote (%ss): %s\"", SAY_ADMINS,
+ ent->client->pers.netname, BG_TeamName( team ),
+ level.voteDisplayString[ team ] ) );
+ }
+ }
}
}
-
- if(team==PTE_ALIENS)
- G_LogPrintf("Teamvote: %s^7 called a teamvote (aliens): %s^7\n", ent->client->pers.netname, level.teamVoteDisplayString[ cs_offset ] );
- else if(team==PTE_HUMANS)
- G_LogPrintf("Teamvote: %s^7 called a teamvote (humans): %s^7\n", ent->client->pers.netname, level.teamVoteDisplayString[ cs_offset ] );
-
- Q_strcat( level.teamVoteDisplayString[ cs_offset ], sizeof( level.teamVoteDisplayString[ cs_offset ] ), va( " Called by: '%s^7'", ent->client->pers.netname ) );
- // start the voting, the caller autoamtically votes yes
- level.teamVoteTime[ cs_offset ] = level.time;
- level.teamVoteNo[ cs_offset ] = 0;
+ G_DecolorString( ent->client->pers.netname, caller, sizeof( caller ) );
- for( i = 0 ; i < level.maxclients ; i++ )
- {
- if( level.clients[ i ].ps.stats[ STAT_PTEAM ] == team )
- level.clients[ i ].ps.eFlags &= ~EF_TEAMVOTED;
- }
+ level.voteTime[ team ] = level.time;
+ trap_SetConfigstring( CS_VOTE_TIME + team,
+ va( "%d", level.voteTime[ team ] ) );
+ trap_SetConfigstring( CS_VOTE_STRING + team,
+ level.voteDisplayString[ team ] );
+ trap_SetConfigstring( CS_VOTE_CALLER + team,
+ caller );
- if( !Q_stricmp( arg1, "poll" ) )
- {
- level.teamVoteYes[ cs_offset ] = 0;
- }
- else
- {
- level.teamVoteYes[ cs_offset ] = 1;
- ent->client->ps.eFlags |= EF_TEAMVOTED;
- }
-
- trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, va( "%i", level.teamVoteTime[ cs_offset ] ) );
- trap_SetConfigstring( CS_TEAMVOTE_STRING + cs_offset, level.teamVoteDisplayString[ cs_offset ] );
- trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va( "%i", level.teamVoteYes[ cs_offset ] ) );
- trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va( "%i", level.teamVoteNo[ cs_offset ] ) );
+ ent->client->pers.namelog->voteCount++;
+ ent->client->pers.vote |= 1 << team;
+ G_Vote( ent, team, qtrue );
}
-
/*
==================
-Cmd_TeamVote_f
+Cmd_Vote_f
==================
*/
-void Cmd_TeamVote_f( gentity_t *ent )
+void Cmd_Vote_f( gentity_t *ent )
{
- int cs_offset = 0;
- char msg[ 64 ];
+ char cmd[ MAX_TOKEN_CHARS ], vote[ MAX_TOKEN_CHARS ];
+ team_t team = ent->client->pers.teamSelection;
- if( ent->client->pers.teamSelection == PTE_ALIENS )
- cs_offset = 1;
+ trap_Argv( 0, cmd, sizeof( cmd ) );
+ if( Q_stricmp( cmd, "teamvote" ) )
+ team = TEAM_NONE;
- if( !level.teamVoteTime[ cs_offset ] )
+ if( !level.voteTime[ team ] )
{
- trap_SendServerCommand( ent-g_entities, "print \"No team vote in progress\n\"" );
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: no vote in progress\n\"", cmd ) );
return;
}
- if( ent->client->ps.eFlags & EF_TEAMVOTED )
+ if( ent->client->pers.voted & ( 1 << team ) )
{
- trap_SendServerCommand( ent-g_entities, "print \"Team vote already cast\n\"" );
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: vote already cast\n\"", cmd ) );
return;
}
- trap_SendServerCommand( ent-g_entities, "print \"Team vote cast\n\"" );
-
- ent->client->ps.eFlags |= EF_TEAMVOTED;
-
- trap_Argv( 1, msg, sizeof( msg ) );
+ trap_SendServerCommand( ent-g_entities,
+ va( "print \"%s: vote cast\n\"", cmd ) );
- if( msg[ 0 ] == 'y' || msg[ 1 ] == 'Y' || msg[ 1 ] == '1' )
- {
- level.teamVoteYes[ cs_offset ]++;
- trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va( "%i", level.teamVoteYes[ cs_offset ] ) );
- }
+ trap_Argv( 1, vote, sizeof( vote ) );
+ if( vote[ 0 ] == 'y' )
+ ent->client->pers.vote |= 1 << team;
else
- {
- level.teamVoteNo[ cs_offset ]++;
- trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va( "%i", level.teamVoteNo[ cs_offset ] ) );
- }
-
- // a majority will be determined in TeamCheckVote, which will also account
- // for players entering or leaving
+ ent->client->pers.vote &= ~( 1 << team );
+ G_Vote( ent, team, qtrue );
}
@@ -2626,29 +1767,38 @@ void Cmd_SetViewpos_f( gentity_t *ent )
char buffer[ MAX_TOKEN_CHARS ];
int i;
- if( trap_Argc( ) != 5 )
+ if( trap_Argc( ) < 4 )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"usage: setviewpos x y z yaw\n\"" ) );
+ trap_SendServerCommand( ent-g_entities, "print \"usage: setviewpos <x> <y> <z> [<yaw> [<pitch>]]\n\"" );
return;
}
- VectorClear( angles );
-
- for( i = 0 ; i < 3 ; i++ )
+ for( i = 0; i < 3; i++ )
{
trap_Argv( i + 1, buffer, sizeof( buffer ) );
origin[ i ] = atof( buffer );
}
+ origin[ 2 ] -= ent->client->ps.viewheight;
- trap_Argv( 4, buffer, sizeof( buffer ) );
- angles[ YAW ] = atof( buffer );
+ VectorCopy( ent->client->ps.viewangles, angles );
+ angles[ ROLL ] = 0;
- TeleportPlayer( ent, origin, angles );
+ if( trap_Argc() >= 5 ) {
+ trap_Argv( 4, buffer, sizeof( buffer ) );
+ angles[ YAW ] = atof( buffer );
+ if( trap_Argc() >= 6 ) {
+ trap_Argv( 5, buffer, sizeof( buffer ) );
+ angles[ PITCH ] = atof( buffer );
+ }
+ }
+
+ TeleportPlayer( ent, origin, angles, 0.0f );
}
#define AS_OVER_RT3 ((ALIENSENSE_RANGE*0.5f)/M_ROOT3)
-qboolean G_RoomForClassChange( gentity_t *ent, pClass_t class, vec3_t newOrigin )
+static qboolean G_RoomForClassChange( gentity_t *ent, class_t class,
+ vec3_t newOrigin )
{
vec3_t fromMins, fromMaxs;
vec3_t toMins, toMaxs;
@@ -2656,12 +1806,12 @@ qboolean G_RoomForClassChange( gentity_t *ent, pClass_t class, vec3_t newOrigin
trace_t tr;
float nudgeHeight;
float maxHorizGrowth;
- pClass_t oldClass = ent->client->ps.stats[ STAT_PCLASS ];
+ class_t oldClass = ent->client->ps.stats[ STAT_CLASS ];
- BG_FindBBoxForClass( oldClass, fromMins, fromMaxs, NULL, NULL, NULL );
- BG_FindBBoxForClass( class, toMins, toMaxs, NULL, NULL, NULL );
+ BG_ClassBoundingBox( oldClass, fromMins, fromMaxs, NULL, NULL, NULL );
+ BG_ClassBoundingBox( class, toMins, toMaxs, NULL, NULL, NULL );
- VectorCopy( ent->s.origin, newOrigin );
+ VectorCopy( ent->client->ps.origin, newOrigin );
// find max x/y diff
maxHorizGrowth = toMaxs[ 0 ] - fromMaxs[ 0 ];
@@ -2684,7 +1834,10 @@ qboolean G_RoomForClassChange( gentity_t *ent, pClass_t class, vec3_t newOrigin
}
// find what the new origin would be on a level surface
- newOrigin[ 2 ] += fabs( toMins[ 2 ] ) - fabs( fromMins[ 2 ] );
+ newOrigin[ 2 ] -= toMins[ 2 ] - fromMins[ 2 ];
+
+ if( ent->client->noclip )
+ return qtrue;
//compute a place up in the air to start the real trace
VectorCopy( newOrigin, temp );
@@ -2702,10 +1855,7 @@ qboolean G_RoomForClassChange( gentity_t *ent, pClass_t class, vec3_t newOrigin
ent->s.number, MASK_PLAYERSOLID );
//check there is room to evolve
- if( !tr.startsolid && tr.fraction == 1.0f )
- return qtrue;
- else
- return qfalse;
+ return ( !tr.startsolid && tr.fraction == 1.0f );
}
/*
@@ -2719,56 +1869,43 @@ void Cmd_Class_f( gentity_t *ent )
int clientNum;
int i;
vec3_t infestOrigin;
- pClass_t currentClass = ent->client->pers.classSelection;
- pClass_t newClass;
- int numLevels;
+ class_t currentClass = ent->client->pers.classSelection;
+ class_t newClass;
int entityList[ MAX_GENTITIES ];
vec3_t range = { AS_OVER_RT3, AS_OVER_RT3, AS_OVER_RT3 };
vec3_t mins, maxs;
int num;
gentity_t *other;
- qboolean humanNear = qfalse;
- vec3_t oldVel;
int oldBoostTime = -1;
+ vec3_t oldVel;
clientNum = ent->client - level.clients;
trap_Argv( 1, s, sizeof( s ) );
- newClass = BG_FindClassNumForName( s );
+ newClass = BG_ClassByName( s )->number;
- if( ent->client->sess.sessionTeam == TEAM_SPECTATOR )
+ if( ent->client->sess.spectatorState != SPECTATOR_NOT )
{
if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
G_StopFollowing( ent );
-
- if( ent->client->pers.teamSelection == PTE_ALIENS )
+ if( ent->client->pers.teamSelection == TEAM_ALIENS )
{
if( newClass != PCL_ALIEN_BUILDER0 &&
newClass != PCL_ALIEN_BUILDER0_UPG &&
newClass != PCL_ALIEN_LEVEL0 )
{
- trap_SendServerCommand( ent-g_entities,
- va( "print \"You cannot spawn with class %s\n\"", s ) );
- return;
- }
-
- if( !BG_ClassIsAllowed( newClass ) )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"Class %s is not allowed\n\"", s ) );
+ G_TriggerMenuArgs( ent->client->ps.clientNum, MN_A_CLASSNOTSPAWN, newClass );
return;
}
-
- if( !BG_FindStagesForClass( newClass, g_alienStage.integer ) )
+
+ if( !BG_ClassIsAllowed( newClass ) )
{
- trap_SendServerCommand( ent-g_entities,
- va( "print \"Class %s not allowed at stage %d\n\"",
- s, g_alienStage.integer ) );
+ G_TriggerMenuArgs( ent->client->ps.clientNum, MN_A_CLASSNOTALLOWED, newClass );
return;
}
-
- if( ent->client->pers.denyBuild && ( newClass==PCL_ALIEN_BUILDER0 || newClass==PCL_ALIEN_BUILDER0_UPG ) )
+
+ if( !BG_ClassAllowedInStage( newClass, g_alienStage.integer ) )
{
- trap_SendServerCommand( ent-g_entities, "print \"Your building rights have been revoked\n\"" );
+ G_TriggerMenuArgs( ent->client->ps.clientNum, MN_A_CLASSNOTATSTAGE, newClass );
return;
}
@@ -2776,40 +1913,32 @@ void Cmd_Class_f( gentity_t *ent )
if( G_PushSpawnQueue( &level.alienSpawnQueue, clientNum ) )
{
ent->client->pers.classSelection = newClass;
- ent->client->ps.stats[ STAT_PCLASS ] = newClass;
+ ent->client->ps.stats[ STAT_CLASS ] = newClass;
}
}
- else if( ent->client->pers.teamSelection == PTE_HUMANS )
+ else if( ent->client->pers.teamSelection == TEAM_HUMANS )
{
//set the item to spawn with
- if( !Q_stricmp( s, BG_FindNameForWeapon( WP_MACHINEGUN ) ) &&
+ if( !Q_stricmp( s, BG_Weapon( WP_MACHINEGUN )->name ) &&
BG_WeaponIsAllowed( WP_MACHINEGUN ) )
{
ent->client->pers.humanItemSelection = WP_MACHINEGUN;
}
- else if( !Q_stricmp( s, BG_FindNameForWeapon( WP_HBUILD ) ) &&
+ else if( !Q_stricmp( s, BG_Weapon( WP_HBUILD )->name ) &&
BG_WeaponIsAllowed( WP_HBUILD ) )
{
ent->client->pers.humanItemSelection = WP_HBUILD;
}
- else if( !Q_stricmp( s, BG_FindNameForWeapon( WP_HBUILD2 ) ) &&
- BG_WeaponIsAllowed( WP_HBUILD2 ) &&
- BG_FindStagesForWeapon( WP_HBUILD2, g_humanStage.integer ) )
- {
- ent->client->pers.humanItemSelection = WP_HBUILD2;
- }
else
{
- trap_SendServerCommand( ent-g_entities,
- "print \"Unknown starting item\n\"" );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_UNKNOWNSPAWNITEM );
return;
}
// spawn from a telenode
- G_LogOnlyPrintf("ClientTeamClass: %i human %s\n", clientNum, s);
if( G_PushSpawnQueue( &level.humanSpawnQueue, clientNum ) )
{
ent->client->pers.classSelection = PCL_HUMAN;
- ent->client->ps.stats[ STAT_PCLASS ] = PCL_HUMAN;
+ ent->client->ps.stats[ STAT_CLASS ] = PCL_HUMAN;
}
}
return;
@@ -2818,24 +1947,23 @@ void Cmd_Class_f( gentity_t *ent )
if( ent->health <= 0 )
return;
- if( ent->client->pers.teamSelection == PTE_ALIENS &&
- !( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) &&
- !( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) )
+ if( ent->client->pers.teamSelection == TEAM_ALIENS )
{
if( newClass == PCL_NONE )
{
- trap_SendServerCommand( ent-g_entities, "print \"Unknown class\n\"" );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_A_UNKNOWNCLASS );
return;
}
//if we are not currently spectating, we are attempting evolution
if( ent->client->pers.classSelection != PCL_NONE )
{
- if( ( ent->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) ||
- ( ent->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) )
+ int cost;
+
+ //check that we have an overmind
+ if( !G_Overmind( ) )
{
- trap_SendServerCommand( ent-g_entities,
- "print \"You cannot evolve while wallwalking\n\"" );
+ G_TriggerMenu( clientNum, MN_A_NOOVMND_EVOLVE );
return;
}
@@ -2848,64 +1976,42 @@ void Cmd_Class_f( gentity_t *ent )
{
other = &g_entities[ entityList[ i ] ];
- if( ( other->client && other->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ||
- ( other->s.eType == ET_BUILDABLE && other->biteam == BIT_HUMANS ) )
- {
- humanNear = qtrue;
- }
- //If its the OM, then ignore all humans.
- if(other->s.eType == ET_BUILDABLE && other->s.modelindex == BA_A_OVERMIND)
+ if( ( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) ||
+ ( other->s.eType == ET_BUILDABLE && other->buildableTeam == TEAM_HUMANS &&
+ other->powered ) )
{
- humanNear = qfalse;
- break;
+ G_TriggerMenu( clientNum, MN_A_TOOCLOSE );
+ return;
}
}
- if(humanNear == qtrue) {
- G_TriggerMenu( clientNum, MN_A_TOOCLOSE );
- return;
- }
-
- if( !level.overmindPresent )
+ //check that we are not wallwalking
+ if( ent->client->ps.eFlags & EF_WALLCLIMB )
{
- G_TriggerMenu( clientNum, MN_A_NOOVMND_EVOLVE );
+ G_TriggerMenu( clientNum, MN_A_EVOLVEWALLWALK );
return;
}
- // denyweapons
- if( newClass >= PCL_ALIEN_LEVEL1 && newClass <= PCL_ALIEN_LEVEL4 &&
- ent->client->pers.denyAlienClasses & ( 1 << newClass ) )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"You are denied from using this class\n\"" ) );
- return;
- }
-
- //guard against selling the HBUILD weapons exploit
- if( ent->client->sess.sessionTeam != TEAM_SPECTATOR &&
- ( currentClass == PCL_ALIEN_BUILDER0 ||
+ if( ent->client->sess.spectatorState == SPECTATOR_NOT &&
+ ( currentClass == PCL_ALIEN_BUILDER0 ||
currentClass == PCL_ALIEN_BUILDER0_UPG ) &&
ent->client->ps.stats[ STAT_MISC ] > 0 )
{
- trap_SendServerCommand( ent-g_entities,
- va( "print \"You cannot evolve until build timer expires\n\"" ) );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_A_EVOLVEBUILDTIMER );
return;
}
- numLevels = BG_ClassCanEvolveFromTo( currentClass,
- newClass,
- (short)ent->client->ps.persistant[ PERS_CREDIT ], 0 );
+ cost = BG_ClassCanEvolveFromTo( currentClass, newClass,
+ ent->client->pers.credit,
+ g_alienStage.integer, 0 );
if( G_RoomForClassChange( ent, newClass, infestOrigin ) )
{
- //...check we can evolve to that class
- if( numLevels >= 0 &&
- BG_FindStagesForClass( newClass, g_alienStage.integer ) &&
- BG_ClassIsAllowed( newClass ) )
+ if( cost >= 0 )
{
- G_LogOnlyPrintf("ClientTeamClass: %i alien %s\n", clientNum, s);
ent->client->pers.evolveHealthFraction = (float)ent->client->ps.stats[ STAT_HEALTH ] /
- (float)BG_FindHealthForClass( currentClass );
+ (float)BG_Class( currentClass )->health;
if( ent->client->pers.evolveHealthFraction < 0.0f )
ent->client->pers.evolveHealthFraction = 0.0f;
@@ -2913,91 +2019,35 @@ void Cmd_Class_f( gentity_t *ent )
ent->client->pers.evolveHealthFraction = 1.0f;
//remove credit
- G_AddCreditToClient( ent->client, -(short)numLevels, qtrue );
+ G_AddCreditToClient( ent->client, -cost, qtrue );
ent->client->pers.classSelection = newClass;
ClientUserinfoChanged( clientNum, qfalse );
VectorCopy( infestOrigin, ent->s.pos.trBase );
VectorCopy( ent->client->ps.velocity, oldVel );
+
if( ent->client->ps.stats[ STAT_STATE ] & SS_BOOSTED )
- oldBoostTime = ent->client->lastBoostedTime;
+ oldBoostTime = ent->client->boostedTime;
+
ClientSpawn( ent, ent, ent->s.pos.trBase, ent->s.apos.trBase );
+
VectorCopy( oldVel, ent->client->ps.velocity );
if( oldBoostTime > 0 )
{
- ent->client->lastBoostedTime = oldBoostTime;
+ ent->client->boostedTime = oldBoostTime;
ent->client->ps.stats[ STAT_STATE ] |= SS_BOOSTED;
}
- return;
}
else
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"You cannot evolve from your current class\n\"" );
- return;
- }
+ G_TriggerMenuArgs( clientNum, MN_A_CANTEVOLVE, newClass );
}
else
- {
G_TriggerMenu( clientNum, MN_A_NOEROOM );
- return;
- }
}
- else if( ent->client->pers.teamSelection == PTE_HUMANS )
- {
- //humans cannot use this command whilst alive
- if( ent->client->pers.classSelection != PCL_NONE )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"You must be dead to use the class command\n\"" ) );
- return;
- }
-
- ent->client->pers.classSelection =
- ent->client->ps.stats[ STAT_PCLASS ] = PCL_HUMAN;
-
- //set the item to spawn with
- if( !Q_stricmp( s, BG_FindNameForWeapon( WP_MACHINEGUN ) ) && BG_WeaponIsAllowed( WP_MACHINEGUN ) )
- ent->client->pers.humanItemSelection = WP_MACHINEGUN;
- else if( !Q_stricmp( s, BG_FindNameForWeapon( WP_HBUILD ) ) && BG_WeaponIsAllowed( WP_HBUILD ) )
- ent->client->pers.humanItemSelection = WP_HBUILD;
- else if( !Q_stricmp( s, BG_FindNameForWeapon( WP_HBUILD2 ) ) && BG_WeaponIsAllowed( WP_HBUILD2 ) &&
- BG_FindStagesForWeapon( WP_HBUILD2, g_humanStage.integer ) )
- ent->client->pers.humanItemSelection = WP_HBUILD2;
- else
- {
- ent->client->pers.classSelection = PCL_NONE;
- trap_SendServerCommand( ent-g_entities, va( "print \"Unknown starting item\n\"" ) );
- return;
- }
-
- G_LogOnlyPrintf("ClientTeamClass: %i human %s\n", clientNum, s);
-
- G_PushSpawnQueue( &level.humanSpawnQueue, clientNum );
}
- }
+ else if( ent->client->pers.teamSelection == TEAM_HUMANS )
+ G_TriggerMenu( clientNum, MN_H_DEADTOCLASS );
}
-/*
-=================
-DBCommand
-
-Send command to all designated builders of selected team
-=================
-*/
-void DBCommand( pTeam_t team, const char *text )
-{
- int i;
- gentity_t *ent;
-
- for( i = 0, ent = g_entities + i; i < level.maxclients; i++, ent++ )
- {
- if( !ent->client || ( ent->client->pers.connected != CON_CONNECTED ) ||
- ( ent->client->pers.teamSelection != team ) ||
- !ent->client->pers.designatedBuilder )
- continue;
-
- trap_SendServerCommand( i, text );
- }
-}
/*
=================
@@ -3006,16 +2056,16 @@ Cmd_Destroy_f
*/
void Cmd_Destroy_f( gentity_t *ent )
{
- vec3_t forward, end;
+ vec3_t viewOrigin, forward, end;
trace_t tr;
gentity_t *traceEnt;
char cmd[ 12 ];
qboolean deconstruct = qtrue;
+ qboolean lastSpawn = qfalse;
- if( ent->client->pers.denyBuild )
+ if( ent->client->pers.namelog->denyBuild )
{
- trap_SendServerCommand( ent-g_entities,
- "print \"Your building rights have been revoked\n\"" );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_REVOKED );
return;
}
@@ -3023,251 +2073,104 @@ void Cmd_Destroy_f( gentity_t *ent )
if( Q_stricmp( cmd, "destroy" ) == 0 )
deconstruct = qfalse;
- if( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING )
+ BG_GetClientViewOrigin( &ent->client->ps, viewOrigin );
+ AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL );
+ VectorMA( viewOrigin, 100, forward, end );
+
+ trap_Trace( &tr, viewOrigin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
+ traceEnt = &g_entities[ tr.entityNum ];
+
+ if( tr.fraction < 1.0f &&
+ ( traceEnt->s.eType == ET_BUILDABLE ) &&
+ ( traceEnt->buildableTeam == ent->client->pers.teamSelection ) &&
+ ( ( ent->client->ps.weapon >= WP_ABUILD ) &&
+ ( ent->client->ps.weapon <= WP_HBUILD ) ) )
{
- if( ( ent->client->hovel->s.eFlags & EF_DBUILDER ) &&
- !ent->client->pers.designatedBuilder )
+ // Always let the builder prevent the explosion
+ if( traceEnt->health <= 0 )
{
- trap_SendServerCommand( ent-g_entities,
- "print \"This structure is protected by designated builder\n\"" );
- DBCommand( ent->client->pers.teamSelection,
- va( "print \"%s^3 has attempted to decon a protected structure!\n\"",
- ent->client->pers.netname ) );
+ G_QueueBuildPoints( traceEnt );
+ G_RewardAttackers( traceEnt );
+ G_FreeEntity( traceEnt );
return;
}
- G_Damage( ent->client->hovel, ent, ent, forward, ent->s.origin,
- 10000, 0, MOD_SUICIDE );
- }
- if( !( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) )
- {
- AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL );
- VectorMA( ent->client->ps.origin, 100, forward, end );
-
- trap_Trace( &tr, ent->client->ps.origin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
- traceEnt = &g_entities[ tr.entityNum ];
-
- if( tr.fraction < 1.0f &&
- ( traceEnt->s.eType == ET_BUILDABLE ) &&
- ( traceEnt->biteam == ent->client->pers.teamSelection ) &&
- ( ( ent->client->ps.weapon >= WP_ABUILD ) &&
- ( ent->client->ps.weapon <= WP_HBUILD ) ) )
+ // Cancel deconstruction (unmark)
+ if( deconstruct && g_markDeconstruct.integer && traceEnt->deconstruct )
{
- // Cancel deconstruction
- if( g_markDeconstruct.integer == 1 && traceEnt->deconstruct )
- {
- traceEnt->deconstruct = qfalse;
- return;
- }
- if( ( traceEnt->s.eFlags & EF_DBUILDER ) &&
- !ent->client->pers.designatedBuilder )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"This structure is protected by designated builder\n\"" );
- DBCommand( ent->client->pers.teamSelection,
- va( "print \"%s^3 has attempted to decon a protected structure!\n\"",
- ent->client->pers.netname ) );
- return;
- }
-
- // Check the minimum level to deconstruct
- if ( G_admin_level( ent ) < g_minDeconLevel.integer && !ent->client->pers.designatedBuilder )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"You do not have deconstructuction rights.\n\"" );
- return;
- }
+ traceEnt->deconstruct = qfalse;
+ return;
+ }
- // Prevent destruction of the last spawn
- if( g_markDeconstruct.integer != 1 && !g_cheats.integer )
- {
- if( ent->client->pers.teamSelection == PTE_ALIENS &&
- traceEnt->s.modelindex == BA_A_SPAWN )
- {
- if( level.numAlienSpawns <= 1 )
- return;
- }
- else if( ent->client->pers.teamSelection == PTE_HUMANS &&
- traceEnt->s.modelindex == BA_H_SPAWN )
- {
- if( level.numHumanSpawns <= 1 )
- return;
- }
- }
+ // Prevent destruction of the last spawn
+ if( ent->client->pers.teamSelection == TEAM_ALIENS &&
+ traceEnt->s.modelindex == BA_A_SPAWN )
+ {
+ if( level.numAlienSpawns <= 1 )
+ lastSpawn = qtrue;
+ }
+ else if( ent->client->pers.teamSelection == TEAM_HUMANS &&
+ traceEnt->s.modelindex == BA_H_SPAWN )
+ {
+ if( level.numHumanSpawns <= 1 )
+ lastSpawn = qtrue;
+ }
- // Don't allow destruction of hovel with granger inside
- if( traceEnt->s.modelindex == BA_A_HOVEL && traceEnt->active )
- return;
+ if( lastSpawn && !g_cheats.integer &&
+ !g_markDeconstruct.integer )
+ {
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_LASTSPAWN );
+ return;
+ }
- // Don't allow destruction of buildables that cannot be rebuilt
- if(g_suddenDeath.integer && traceEnt->health > 0 &&
- ( ( g_suddenDeathMode.integer == SDMODE_SELECTIVE &&
- !BG_FindReplaceableTestForBuildable( traceEnt->s.modelindex ) ) ||
- ( g_suddenDeathMode.integer == SDMODE_BP &&
- BG_FindBuildPointsForBuildable( traceEnt->s.modelindex ) ) ||
- g_suddenDeathMode.integer == SDMODE_NO_BUILD ||
- g_suddenDeathMode.integer == SDMODE_NO_DECON ) )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"During Sudden Death you can only decon buildings that "
- "can be rebuilt\n\"" );
- return;
- }
+ // Don't allow destruction of buildables that cannot be rebuilt
+ if( G_TimeTilSuddenDeath( ) <= 0 )
+ {
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_SUDDENDEATH );
+ return;
+ }
+ if( !g_markDeconstruct.integer ||
+ ( ent->client->pers.teamSelection == TEAM_HUMANS &&
+ !G_FindPower( traceEnt, qtrue ) ) )
+ {
if( ent->client->ps.stats[ STAT_MISC ] > 0 )
{
G_AddEvent( ent, EV_BUILD_DELAY, ent->client->ps.clientNum );
return;
}
-
- if( traceEnt->health > 0 || g_deconDead.integer )
- {
- if( g_markDeconstruct.integer == 1 )
- {
- traceEnt->deconstruct = qtrue; // Mark buildable for deconstruction
- traceEnt->deconstructTime = level.time;
- }
- else
- {
- if( traceEnt->health > 0 )
- {
- buildHistory_t *new;
-
- new = G_Alloc( sizeof( buildHistory_t ) );
- new->ID = ( ++level.lastBuildID > 1000 )
- ? ( level.lastBuildID = 1 ) : level.lastBuildID;
- new->ent = ent;
- new->name[ 0 ] = 0;
- new->buildable = traceEnt->s.modelindex;
- VectorCopy( traceEnt->s.pos.trBase, new->origin );
- VectorCopy( traceEnt->s.angles, new->angles );
- VectorCopy( traceEnt->s.origin2, new->origin2 );
- VectorCopy( traceEnt->s.angles2, new->angles2 );
- new->fate = BF_DECONNED;
- new->next = NULL;
- new->marked = NULL;
- G_LogBuild( new );
-
- G_TeamCommand( ent->client->pers.teamSelection,
- va( "print \"%s ^3DECONSTRUCTED^7 by %s^7\n\"",
- BG_FindHumanNameForBuildable( traceEnt->s.modelindex ),
- ent->client->pers.netname ) );
-
- G_LogPrintf( "Decon: %i %i 0: %s^7 deconstructed %s\n",
- ent->client->ps.clientNum,
- traceEnt->s.modelindex,
- ent->client->pers.netname,
- BG_FindNameForBuildable( traceEnt->s.modelindex ) );
- }
-
- if( !deconstruct )
- G_Damage( traceEnt, ent, ent, forward, tr.endpos, 10000, 0, MOD_SUICIDE );
- else
- G_FreeEntity( traceEnt );
-
- if( !g_cheats.integer )
- ent->client->ps.stats[ STAT_MISC ] +=
- BG_FindBuildDelayForWeapon( ent->s.weapon ) >> 2;
- }
- }
}
- }
-}
-
-void Cmd_Mark_f( gentity_t *ent )
-{
- vec3_t forward, end;
- trace_t tr;
- gentity_t *traceEnt;
- if( g_markDeconstruct.integer != 2 )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"Mark is disabled\n\"" );
- return;
- }
-
- if( ent->client->pers.denyBuild )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"Your building rights have been revoked\n\"" );
- return;
- }
-
- // Check the minimum level to deconstruct
- if ( G_admin_level( ent ) < g_minDeconLevel.integer && !ent->client->pers.designatedBuilder && g_minDeconAffectsMark.integer > 0 )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"You do not have deconstructuction rights.\n\"" );
- return;
- }
-
- // can't mark when in hovel
- if( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING )
- return;
-
- if( !( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) )
- {
- AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL );
- VectorMA( ent->client->ps.origin, 100, forward, end );
-
- trap_Trace( &tr, ent->client->ps.origin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
- traceEnt = &g_entities[ tr.entityNum ];
-
- if( tr.fraction < 1.0f &&
- ( traceEnt->s.eType == ET_BUILDABLE ) &&
- ( traceEnt->biteam == ent->client->pers.teamSelection ) &&
- ( ( ent->client->ps.weapon >= WP_ABUILD ) &&
- ( ent->client->ps.weapon <= WP_HBUILD ) ) )
+ if( traceEnt->health > 0 )
{
- if( ( traceEnt->s.eFlags & EF_DBUILDER ) &&
- !ent->client->pers.designatedBuilder )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"this structure is protected by a designated builder\n\"" );
- return;
- }
-
- // Cancel deconstruction
- if( traceEnt->deconstruct )
- {
- traceEnt->deconstruct = qfalse;
-
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s no longer marked for deconstruction\n\"",
- BG_FindHumanNameForBuildable( traceEnt->s.modelindex ) ) );
- return;
- }
-
- // Don't allow marking of buildables that cannot be rebuilt
- if(g_suddenDeath.integer && traceEnt->health > 0 &&
- ( ( g_suddenDeathMode.integer == SDMODE_SELECTIVE &&
- !BG_FindReplaceableTestForBuildable( traceEnt->s.modelindex ) ) ||
- ( g_suddenDeathMode.integer == SDMODE_BP &&
- BG_FindBuildPointsForBuildable( traceEnt->s.modelindex ) ) ||
- g_suddenDeathMode.integer == SDMODE_NO_BUILD ||
- g_suddenDeathMode.integer == SDMODE_NO_DECON ) )
+ if( !deconstruct )
{
- trap_SendServerCommand( ent-g_entities,
- "print \"During Sudden Death you can only mark buildings that "
- "can be rebuilt\n\"" );
- return;
+ G_Damage( traceEnt, ent, ent, forward, tr.endpos,
+ traceEnt->health, 0, MOD_SUICIDE );
}
-
- if( traceEnt->health > 0 )
+ else if( g_markDeconstruct.integer &&
+ ( ent->client->pers.teamSelection != TEAM_HUMANS ||
+ G_FindPower( traceEnt , qtrue ) || lastSpawn ) )
{
traceEnt->deconstruct = qtrue; // Mark buildable for deconstruction
traceEnt->deconstructTime = level.time;
-
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s marked for deconstruction\n\"",
- BG_FindHumanNameForBuildable( traceEnt->s.modelindex ) ) );
+ }
+ else
+ {
+ if( !g_cheats.integer ) // add a bit to the build timer
+ {
+ ent->client->ps.stats[ STAT_MISC ] +=
+ BG_Buildable( traceEnt->s.modelindex )->buildTime / 4;
+ }
+ G_Damage( traceEnt, ent, ent, forward, tr.endpos,
+ traceEnt->health, 0, MOD_DECONSTRUCT );
+ G_RemoveRangeMarkerFrom( traceEnt );
+ G_FreeEntity( traceEnt );
}
}
}
}
-
/*
=================
Cmd_ActivateItem_f
@@ -3281,13 +2184,28 @@ void Cmd_ActivateItem_f( gentity_t *ent )
int upgrade, weapon;
trap_Argv( 1, s, sizeof( s ) );
- upgrade = BG_FindUpgradeNumForName( s );
- weapon = BG_FindWeaponNumForName( s );
+
+ // "weapon" aliased to whatever weapon you have
+ if( !Q_stricmp( "weapon", s ) )
+ {
+ if( ent->client->ps.weapon == WP_BLASTER &&
+ BG_PlayerCanChangeWeapon( &ent->client->ps ) )
+ G_ForceWeaponChange( ent, WP_NONE );
+ return;
+ }
+
+ upgrade = BG_UpgradeByName( s )->number;
+ weapon = BG_WeaponByName( s )->number;
if( upgrade != UP_NONE && BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
BG_ActivateUpgrade( upgrade, ent->client->ps.stats );
- else if( weapon != WP_NONE && BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ) )
- G_ForceWeaponChange( ent, weapon );
+ else if( weapon != WP_NONE &&
+ BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ) )
+ {
+ if( ent->client->ps.weapon != weapon &&
+ BG_PlayerCanChangeWeapon( &ent->client->ps ) )
+ G_ForceWeaponChange( ent, weapon );
+ }
else
trap_SendServerCommand( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) );
}
@@ -3302,11 +2220,11 @@ Deactivate an item
*/
void Cmd_DeActivateItem_f( gentity_t *ent )
{
- char s[ MAX_TOKEN_CHARS ];
- int upgrade;
+ char s[ MAX_TOKEN_CHARS ];
+ upgrade_t upgrade;
trap_Argv( 1, s, sizeof( s ) );
- upgrade = BG_FindUpgradeNumForName( s );
+ upgrade = BG_UpgradeByName( s )->number;
if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
BG_DeactivateUpgrade( upgrade, ent->client->ps.stats );
@@ -3322,38 +2240,25 @@ Cmd_ToggleItem_f
*/
void Cmd_ToggleItem_f( gentity_t *ent )
{
- char s[ MAX_TOKEN_CHARS ];
- int upgrade, weapon, i;
+ char s[ MAX_TOKEN_CHARS ];
+ weapon_t weapon;
+ upgrade_t upgrade;
trap_Argv( 1, s, sizeof( s ) );
- upgrade = BG_FindUpgradeNumForName( s );
- weapon = BG_FindWeaponNumForName( s );
+ upgrade = BG_UpgradeByName( s )->number;
+ weapon = BG_WeaponByName( s )->number;
if( weapon != WP_NONE )
{
+ if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) )
+ return;
+
//special case to allow switching between
//the blaster and the primary weapon
-
if( ent->client->ps.weapon != WP_BLASTER )
weapon = WP_BLASTER;
else
- {
- //find a held weapon which isn't the blaster
- for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
- {
- if( i == WP_BLASTER )
- continue;
-
- if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) )
- {
- weapon = i;
- break;
- }
- }
-
- if( i == WP_NUM_WEAPONS )
- weapon = WP_BLASTER;
- }
+ weapon = WP_NONE;
G_ForceWeaponChange( ent, weapon );
}
@@ -3375,60 +2280,32 @@ Cmd_Buy_f
*/
void Cmd_Buy_f( gentity_t *ent )
{
- char s[ MAX_TOKEN_CHARS ];
- int i;
- int weapon, upgrade, numItems = 0;
- int maxAmmo, maxClips;
- qboolean buyingEnergyAmmo = qfalse;
- qboolean hasEnergyWeapon = qfalse;
-
- for( i = UP_NONE; i < UP_NUM_UPGRADES; i++ )
- {
- if( BG_InventoryContainsUpgrade( i, ent->client->ps.stats ) )
- numItems++;
- }
-
- for( i = WP_NONE; i < WP_NUM_WEAPONS; i++ )
- {
- if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) )
- {
- if( BG_FindUsesEnergyForWeapon( i ) )
- hasEnergyWeapon = qtrue;
- numItems++;
- }
- }
+ char s[ MAX_TOKEN_CHARS ];
+ weapon_t weapon;
+ upgrade_t upgrade;
+ qboolean energyOnly;
trap_Argv( 1, s, sizeof( s ) );
- weapon = BG_FindWeaponNumForName( s );
- upgrade = BG_FindUpgradeNumForName( s );
-
- //special case to keep norf happy
- if( weapon == WP_NONE && upgrade == UP_AMMO )
- {
- buyingEnergyAmmo = hasEnergyWeapon;
- }
-
- if( buyingEnergyAmmo )
- {
- //no armoury nearby
- if( !G_BuildableRange( ent->client->ps.origin, 100, BA_H_REACTOR ) &&
- !G_BuildableRange( ent->client->ps.origin, 100, BA_H_REPEATER ) &&
- !G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"You must be near a reactor, repeater or armoury\n\"" ) );
- return;
- }
- }
+ weapon = BG_WeaponByName( s )->number;
+ upgrade = BG_UpgradeByName( s )->number;
+
+ // Only give energy from reactors or repeaters
+ if( G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) )
+ energyOnly = qfalse;
+ else if( upgrade == UP_AMMO &&
+ BG_Weapon( ent->client->ps.stats[ STAT_WEAPON ] )->usesEnergy &&
+ ( G_BuildableRange( ent->client->ps.origin, 100, BA_H_REACTOR ) ||
+ G_BuildableRange( ent->client->ps.origin, 100, BA_H_REPEATER ) ) )
+ energyOnly = qtrue;
else
{
- //no armoury nearby
- if( !G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) );
- return;
- }
+ if( upgrade == UP_AMMO &&
+ BG_Weapon( ent->client->ps.weapon )->usesEnergy )
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOENERGYAMMOHERE );
+ else
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOARMOURYHERE );
+ return;
}
if( weapon != WP_NONE )
@@ -3440,59 +2317,52 @@ void Cmd_Buy_f( gentity_t *ent )
return;
}
- // denyweapons
- if( weapon >= WP_PAIN_SAW && weapon <= WP_GRENADE &&
- ent->client->pers.denyHumanWeapons & ( 1 << (weapon - WP_BLASTER) ) )
+ // Only humans can buy stuff
+ if( BG_Weapon( weapon )->team != TEAM_HUMANS )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You are denied from buying this weapon\n\"" ) );
+ trap_SendServerCommand( ent-g_entities, "print \"You can't buy alien items\n\"" );
return;
}
- //can afford this?
- if( BG_FindPriceForWeapon( weapon ) > (short)ent->client->ps.persistant[ PERS_CREDIT ] )
+ //are we /allowed/ to buy this?
+ if( !BG_Weapon( weapon )->purchasable )
{
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOFUNDS );
+ trap_SendServerCommand( ent-g_entities, "print \"You can't buy this item\n\"" );
return;
}
- //have space to carry this?
- if( BG_FindSlotsForWeapon( weapon ) & ent->client->ps.stats[ STAT_SLOTS ] )
+ //are we /allowed/ to buy this?
+ if( !BG_WeaponAllowedInStage( weapon, g_humanStage.integer ) || !BG_WeaponIsAllowed( weapon ) )
{
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOSLOTS );
+ trap_SendServerCommand( ent-g_entities, "print \"You can't buy this item\n\"" );
return;
}
- if( BG_FindTeamForWeapon( weapon ) != WUT_HUMANS )
+ //can afford this?
+ if( BG_Weapon( weapon )->price > (short)ent->client->pers.credit )
{
- //shouldn't need a fancy dialog
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy alien items\n\"" ) );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOFUNDS );
return;
}
- //are we /allowed/ to buy this?
- if( !BG_FindPurchasableForWeapon( weapon ) )
+ //have space to carry this?
+ if( BG_Weapon( weapon )->slots & BG_SlotsForInventory( ent->client->ps.stats ) )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOSLOTS );
return;
}
- //are we /allowed/ to buy this?
- if( !BG_FindStagesForWeapon( weapon, g_humanStage.integer ) || !BG_WeaponIsAllowed( weapon ) )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
+ // In some instances, weapons can't be changed
+ if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) )
return;
- }
- //add to inventory
- BG_AddWeaponToInventory( weapon, ent->client->ps.stats );
- BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips );
+ ent->client->ps.stats[ STAT_WEAPON ] = weapon;
+ ent->client->ps.ammo = BG_Weapon( weapon )->maxAmmo;
+ ent->client->ps.clips = BG_Weapon( weapon )->maxClips;
- if( BG_FindUsesEnergyForWeapon( weapon ) &&
+ if( BG_Weapon( weapon )->usesEnergy &&
BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) )
- maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
-
- ent->client->ps.ammo = maxAmmo;
- ent->client->ps.clips = maxClips;
+ ent->client->ps.ammo *= BATTPACK_MODIFIER;
G_ForceWeaponChange( ent, weapon );
@@ -3500,7 +2370,7 @@ void Cmd_Buy_f( gentity_t *ent )
ent->client->ps.stats[ STAT_MISC ] = 0;
//subtract from funds
- G_AddCreditToClient( ent->client, -(short)BG_FindPriceForWeapon( weapon ), qfalse );
+ G_AddCreditToClient( ent->client, -(short)BG_Weapon( weapon )->price, qfalse );
}
else if( upgrade != UP_NONE )
{
@@ -3511,60 +2381,60 @@ void Cmd_Buy_f( gentity_t *ent )
return;
}
- // denyweapons
- if( upgrade == UP_GRENADE &&
- ent->client->pers.denyHumanWeapons & ( 1 << (WP_GRENADE - WP_BLASTER) ) )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"You are denied from buying this upgrade\n\"" ) );
- return;
- }
-
//can afford this?
- if( BG_FindPriceForUpgrade( upgrade ) > (short)ent->client->ps.persistant[ PERS_CREDIT ] )
+ if( BG_Upgrade( upgrade )->price > (short)ent->client->pers.credit )
{
G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOFUNDS );
return;
}
//have space to carry this?
- if( BG_FindSlotsForUpgrade( upgrade ) & ent->client->ps.stats[ STAT_SLOTS ] )
+ if( BG_Upgrade( upgrade )->slots & BG_SlotsForInventory( ent->client->ps.stats ) )
{
G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOSLOTS );
return;
}
- if( BG_FindTeamForUpgrade( upgrade ) != WUT_HUMANS )
+ // Only humans can buy stuff
+ if( BG_Upgrade( upgrade )->team != TEAM_HUMANS )
{
- //shouldn't need a fancy dialog
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy alien items\n\"" ) );
+ trap_SendServerCommand( ent-g_entities, "print \"You can't buy alien items\n\"" );
return;
}
//are we /allowed/ to buy this?
- if( !BG_FindPurchasableForUpgrade( upgrade ) )
+ if( !BG_Upgrade( upgrade )->purchasable )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
+ trap_SendServerCommand( ent-g_entities, "print \"You can't buy this item\n\"" );
return;
}
//are we /allowed/ to buy this?
- if( !BG_FindStagesForUpgrade( upgrade, g_humanStage.integer ) || !BG_UpgradeIsAllowed( upgrade ) )
+ if( !BG_UpgradeAllowedInStage( upgrade, g_humanStage.integer ) || !BG_UpgradeIsAllowed( upgrade ) )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
- return;
- }
-
- if( upgrade == UP_BATTLESUIT && ent->client->ps.pm_flags & PMF_DUCKED )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"You can't buy this item while crouching\n\"" ) );
+ trap_SendServerCommand( ent-g_entities, "print \"You can't buy this item\n\"" );
return;
}
if( upgrade == UP_AMMO )
- G_GiveClientMaxAmmo( ent, buyingEnergyAmmo );
+ G_GiveClientMaxAmmo( ent, energyOnly );
else
{
+ if( upgrade == UP_BATTLESUIT )
+ {
+ vec3_t newOrigin;
+
+ if( !G_RoomForClassChange( ent, PCL_HUMAN_BSUIT, newOrigin ) )
+ {
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOMBSUITON );
+ return;
+ }
+ VectorCopy( newOrigin, ent->client->ps.origin );
+ ent->client->ps.stats[ STAT_CLASS ] = PCL_HUMAN_BSUIT;
+ ent->client->pers.classSelection = PCL_HUMAN_BSUIT;
+ ent->client->ps.eFlags ^= EF_TELEPORT_BIT;
+ }
+
//add to inventory
BG_AddUpgradeToInventory( upgrade, ent->client->ps.stats );
}
@@ -3573,30 +2443,17 @@ void Cmd_Buy_f( gentity_t *ent )
G_GiveClientMaxAmmo( ent, qtrue );
//subtract from funds
- G_AddCreditToClient( ent->client, -(short)BG_FindPriceForUpgrade( upgrade ), qfalse );
+ G_AddCreditToClient( ent->client, -(short)BG_Upgrade( upgrade )->price, qfalse );
}
else
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Unknown item\n\"" ) );
- }
-
- if( trap_Argc( ) >= 2 )
- {
- trap_Argv( 2, s, sizeof( s ) );
-
- //retrigger the armoury menu
- if( !Q_stricmp( s, "retrigger" ) )
- ent->client->retriggerArmouryMenu = level.framenum + RAM_FRAMES;
- }
- if( ent->client->pers.paused )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"You may not deconstruct while paused\n\"" );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_UNKNOWNITEM );
return;
}
//update ClientInfo
ClientUserinfoChanged( ent->client->ps.clientNum, qfalse );
+ ent->client->pers.infoChangeTime = level.time;
}
@@ -3609,26 +2466,36 @@ void Cmd_Sell_f( gentity_t *ent )
{
char s[ MAX_TOKEN_CHARS ];
int i;
- int weapon, upgrade;
+ weapon_t weapon;
+ upgrade_t upgrade;
trap_Argv( 1, s, sizeof( s ) );
//no armoury nearby
if( !G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOARMOURYHERE );
return;
}
- weapon = BG_FindWeaponNumForName( s );
- upgrade = BG_FindUpgradeNumForName( s );
+ if( !Q_stricmpn( s, "weapon", 6 ) )
+ weapon = ent->client->ps.stats[ STAT_WEAPON ];
+ else
+ weapon = BG_WeaponByName( s )->number;
+
+ upgrade = BG_UpgradeByName( s )->number;
if( weapon != WP_NONE )
{
+ weapon_t selected = BG_GetPlayerWeapon( &ent->client->ps );
+
+ if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) )
+ return;
+
//are we /allowed/ to sell this?
- if( !BG_FindPurchasableForWeapon( weapon ) )
+ if( !BG_Weapon( weapon )->purchasable )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't sell this weapon\n\"" ) );
+ trap_SendServerCommand( ent-g_entities, "print \"You can't sell this weapon\n\"" );
return;
}
@@ -3636,67 +2503,59 @@ void Cmd_Sell_f( gentity_t *ent )
if( BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ) )
{
//guard against selling the HBUILD weapons exploit
- if( ( weapon == WP_HBUILD || weapon == WP_HBUILD2 ) &&
- ent->client->ps.stats[ STAT_MISC ] > 0 )
+ if( weapon == WP_HBUILD && ent->client->ps.stats[ STAT_MISC ] > 0 )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_ARMOURYBUILDTIMER );
return;
}
- BG_RemoveWeaponFromInventory( weapon, ent->client->ps.stats );
+ ent->client->ps.stats[ STAT_WEAPON ] = WP_NONE;
+ // Cancel ghost buildables
+ ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
//add to funds
- G_AddCreditToClient( ent->client, (short)BG_FindPriceForWeapon( weapon ), qfalse );
+ G_AddCreditToClient( ent->client, (short)BG_Weapon( weapon )->price, qfalse );
}
//if we have this weapon selected, force a new selection
- if( weapon == ent->client->ps.weapon )
- G_ForceWeaponChange( ent, WP_NONE );
+ if( weapon == selected )
+ G_ForceWeaponChange( ent, WP_BLASTER );
}
else if( upgrade != UP_NONE )
{
//are we /allowed/ to sell this?
- if( !BG_FindPurchasableForUpgrade( upgrade ) )
+ if( !BG_Upgrade( upgrade )->purchasable )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't sell this item\n\"" ) );
+ trap_SendServerCommand( ent-g_entities, "print \"You can't sell this item\n\"" );
return;
}
//remove upgrade if carried
if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
{
+ // shouldn't really need to test for this, but just to be safe
+ if( upgrade == UP_BATTLESUIT )
+ {
+ vec3_t newOrigin;
+
+ if( !G_RoomForClassChange( ent, PCL_HUMAN, newOrigin ) )
+ {
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOMBSUITOFF );
+ return;
+ }
+ VectorCopy( newOrigin, ent->client->ps.origin );
+ ent->client->ps.stats[ STAT_CLASS ] = PCL_HUMAN;
+ ent->client->pers.classSelection = PCL_HUMAN;
+ ent->client->ps.eFlags ^= EF_TELEPORT_BIT;
+ }
+
+ //add to inventory
BG_RemoveUpgradeFromInventory( upgrade, ent->client->ps.stats );
if( upgrade == UP_BATTPACK )
G_GiveClientMaxAmmo( ent, qtrue );
//add to funds
- G_AddCreditToClient( ent->client, (short)BG_FindPriceForUpgrade( upgrade ), qfalse );
- }
- }
- else if( !Q_stricmp( s, "weapons" ) )
- {
- for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
- {
- //guard against selling the HBUILD weapons exploit
- if( ( i == WP_HBUILD || i == WP_HBUILD2 ) &&
- ent->client->ps.stats[ STAT_MISC ] > 0 )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) );
- continue;
- }
-
- if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) &&
- BG_FindPurchasableForWeapon( i ) )
- {
- BG_RemoveWeaponFromInventory( i, ent->client->ps.stats );
-
- //add to funds
- G_AddCreditToClient( ent->client, (short)BG_FindPriceForWeapon( i ), qfalse );
- }
-
- //if we have this weapon selected, force a new selection
- if( i == ent->client->ps.weapon )
- G_ForceWeaponChange( ent, WP_NONE );
+ G_AddCreditToClient( ent->client, (short)BG_Upgrade( upgrade )->price, qfalse );
}
}
else if( !Q_stricmp( s, "upgrades" ) )
@@ -3705,47 +2564,44 @@ void Cmd_Sell_f( gentity_t *ent )
{
//remove upgrade if carried
if( BG_InventoryContainsUpgrade( i, ent->client->ps.stats ) &&
- BG_FindPurchasableForUpgrade( i ) )
+ BG_Upgrade( i )->purchasable )
{
- BG_RemoveUpgradeFromInventory( i, ent->client->ps.stats );
- if( i == UP_BATTPACK )
+ // shouldn't really need to test for this, but just to be safe
+ if( i == UP_BATTLESUIT )
{
- int j;
+ vec3_t newOrigin;
- //remove energy
- for( j = WP_NONE; j < WP_NUM_WEAPONS; j++ )
+ if( !G_RoomForClassChange( ent, PCL_HUMAN, newOrigin ) )
{
- if( BG_InventoryContainsWeapon( j, ent->client->ps.stats ) &&
- BG_FindUsesEnergyForWeapon( j ) &&
- !BG_FindInfinteAmmoForWeapon( j ) )
- {
- // GH FIXME
- ent->client->ps.ammo = 0;
- ent->client->ps.clips = 0;
- }
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOMBSUITOFF );
+ continue;
}
+ VectorCopy( newOrigin, ent->client->ps.origin );
+ ent->client->ps.stats[ STAT_CLASS ] = PCL_HUMAN;
+ ent->client->pers.classSelection = PCL_HUMAN;
+ ent->client->ps.eFlags ^= EF_TELEPORT_BIT;
}
+ BG_RemoveUpgradeFromInventory( i, ent->client->ps.stats );
+
+ if( i == UP_BATTPACK )
+ G_GiveClientMaxAmmo( ent, qtrue );
+
//add to funds
- G_AddCreditToClient( ent->client, (short)BG_FindPriceForUpgrade( i ), qfalse );
+ G_AddCreditToClient( ent->client, (short)BG_Upgrade( i )->price, qfalse );
}
}
}
else
- trap_SendServerCommand( ent-g_entities, va( "print \"Unknown item\n\"" ) );
-
- if( trap_Argc( ) >= 2 )
{
- trap_Argv( 2, s, sizeof( s ) );
-
- //retrigger the armoury menu
- if( !Q_stricmp( s, "retrigger" ) )
- ent->client->retriggerArmouryMenu = level.framenum + RAM_FRAMES;
+ G_TriggerMenu( ent->client->ps.clientNum, MN_H_UNKNOWNITEM );
+ return;
}
//update ClientInfo
ClientUserinfoChanged( ent->client->ps.clientNum, qfalse );
+ ent->client->pers.infoChangeTime = level.time;
}
@@ -3759,207 +2615,126 @@ void Cmd_Build_f( gentity_t *ent )
char s[ MAX_TOKEN_CHARS ];
buildable_t buildable;
float dist;
- vec3_t origin;
- pTeam_t team;
+ vec3_t origin, normal;
+ int groundEntNum;
+ team_t team;
- if( ent->client->pers.denyBuild )
+ if( ent->client->pers.namelog->denyBuild )
{
- trap_SendServerCommand( ent-g_entities,
- "print \"Your building rights have been revoked\n\"" );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_REVOKED );
return;
}
- if( ent->client->pers.paused )
+
+ if( ent->client->pers.teamSelection == level.surrenderTeam )
{
- trap_SendServerCommand( ent-g_entities,
- "print \"You may not mark while paused\n\"" );
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_SURRENDER );
return;
}
trap_Argv( 1, s, sizeof( s ) );
- buildable = BG_FindBuildNumForName( s );
+ buildable = BG_BuildableByName( s )->number;
+ team = ent->client->ps.stats[ STAT_TEAM ];
+ if( buildable == BA_NONE || !BG_BuildableIsAllowed( buildable ) ||
+ !( ( 1 << ent->client->ps.weapon ) & BG_Buildable( buildable )->buildWeapon ) ||
+ ( team == TEAM_ALIENS && !BG_BuildableAllowedInStage( buildable, g_alienStage.integer ) ) ||
+ ( team == TEAM_HUMANS && !BG_BuildableAllowedInStage( buildable, g_humanStage.integer ) ) )
+ {
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_CANNOT );
+ return;
+ }
- if( g_suddenDeath.integer)
+ if( G_TimeTilSuddenDeath( ) <= 0 )
{
- if( g_suddenDeathMode.integer == SDMODE_SELECTIVE )
- {
- if( !BG_FindReplaceableTestForBuildable( buildable ) )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"This building type cannot be rebuilt during Sudden Death\n\"" );
- return;
- }
- if( G_BuildingExists( buildable ) )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"You can only rebuild one of each type of rebuildable building during Sudden Death.\n\"" );
- return;
- }
- }
- else if( g_suddenDeathMode.integer == SDMODE_NO_BUILD )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"Building is not allowed during Sudden Death\n\"" );
- return;
- }
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_SUDDENDEATH );
+ return;
}
- team = ent->client->ps.stats[ STAT_PTEAM ];
+ ent->client->ps.stats[ STAT_BUILDABLE ] = buildable;
- if( buildable != BA_NONE &&
- ( ( 1 << ent->client->ps.weapon ) & BG_FindBuildWeaponForBuildable( buildable ) ) &&
- !( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) &&
- !( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) &&
- BG_BuildableIsAllowed( buildable ) &&
- ( ( team == PTE_ALIENS && BG_FindStagesForBuildable( buildable, g_alienStage.integer ) ) ||
- ( team == PTE_HUMANS && BG_FindStagesForBuildable( buildable, g_humanStage.integer ) ) ) )
+ if( 1 )
{
- dist = BG_FindBuildDistForClass( ent->client->ps.stats[ STAT_PCLASS ] );
+ dynMenu_t err;
+ dist = BG_Class( ent->client->ps.stats[ STAT_CLASS ] )->buildDist;
//these are the errors displayed when the builder first selects something to use
- switch( G_CanBuild( ent, buildable, dist, origin ) )
+ switch( G_CanBuild( ent, buildable, dist, origin, normal, &groundEntNum ) )
{
+ // can place right away, set the blueprint and the valid togglebit
case IBE_NONE:
case IBE_TNODEWARN:
- case IBE_RPTWARN:
- case IBE_RPTWARN2:
+ case IBE_RPTNOREAC:
+ case IBE_RPTPOWERHERE:
case IBE_SPWNWARN:
- case IBE_NOROOM:
+ err = MN_NONE;
+ ent->client->ps.stats[ STAT_BUILDABLE ] |= SB_VALID_TOGGLEBIT;
+ break;
+
+ // can't place yet but maybe soon: start with valid togglebit off
case IBE_NORMAL:
- case IBE_HOVELEXIT:
- ent->client->ps.stats[ STAT_BUILDABLE ] = ( buildable | SB_VALID_TOGGLEBIT );
+ err = MN_B_NORMAL;
break;
- case IBE_NOASSERT:
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_NOASSERT );
+ case IBE_NOCREEP:
+ err = MN_A_NOCREEP;
+ break;
+
+ case IBE_NOROOM:
+ err = MN_B_NOROOM;
break;
case IBE_NOOVERMIND:
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_NOOVMND );
+ err = MN_A_NOOVMND;
break;
- case IBE_OVERMIND:
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_OVERMIND );
+ case IBE_NOPOWERHERE:
+ err = MN_NONE;
break;
- case IBE_REACTOR:
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_REACTOR );
+ // more serious errors just pop a menu
+ case IBE_NOALIENBP:
+ err = MN_A_NOBP;
break;
- case IBE_REPEATER:
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_REPEATER );
+ case IBE_ONEOVERMIND:
+ err = MN_A_ONEOVERMIND;
break;
- case IBE_NOPOWER:
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOPOWER );
+ case IBE_ONEREACTOR:
+ err = MN_H_ONEREACTOR;
break;
- case IBE_NOCREEP:
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_NOCREEP );
+ case IBE_NOHUMANBP:
+ err = MN_H_NOBP;
break;
case IBE_NODCC:
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NODCC );
+ err = MN_H_NODCC;
break;
- default:
+ case IBE_PERMISSION:
+ err = MN_B_NORMAL;
break;
- }
- }
- else
- trap_SendServerCommand( ent-g_entities, va( "print \"Cannot build this item\n\"" ) );
-}
-
-
-/*
-=================
-Cmd_Boost_f
-=================
-*/
-void Cmd_Boost_f( gentity_t *ent )
-{
- if( BG_InventoryContainsUpgrade( UP_JETPACK, ent->client->ps.stats ) &&
- BG_UpgradeIsActive( UP_JETPACK, ent->client->ps.stats ) )
- return;
-
- if( ent->client->pers.cmd.buttons & BUTTON_WALKING )
- return;
-
- if( ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) &&
- ( ent->client->ps.stats[ STAT_STAMINA ] > 0 ) )
- ent->client->ps.stats[ STAT_STATE ] |= SS_SPEEDBOOST;
-}
-
-/*
-=================
-Cmd_Protect_f
-=================
-*/
-void Cmd_Protect_f( gentity_t *ent )
-{
- vec3_t forward, end;
- trace_t tr;
- gentity_t *traceEnt;
- if( !ent->client->pers.designatedBuilder )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Only designated"
- " builders can toggle structure protection.\n\"" );
- return;
- }
-
- AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL );
- VectorMA( ent->client->ps.origin, 100, forward, end );
-
- trap_Trace( &tr, ent->client->ps.origin, NULL, NULL, end, ent->s.number,
- MASK_PLAYERSOLID );
- traceEnt = &g_entities[ tr.entityNum ];
+ case IBE_LASTSPAWN:
+ err = MN_B_LASTSPAWN;
+ break;
- if( tr.fraction < 1.0f && ( traceEnt->s.eType == ET_BUILDABLE ) &&
- ( traceEnt->biteam == ent->client->pers.teamSelection ) )
- {
- if( traceEnt->s.eFlags & EF_DBUILDER )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"Structure protection removed\n\"" );
- traceEnt->s.eFlags &= ~EF_DBUILDER;
+ default:
+ err = -1; // stop uninitialised warning
+ break;
}
- else
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"Structure protection applied\n\"" );
- traceEnt->s.eFlags |= EF_DBUILDER;
- // adding protection turns off deconstruction mark
- traceEnt->deconstruct = qfalse;
- }
+ if( err == MN_NONE || ent->client->pers.disableBlueprintErrors )
+ ent->client->ps.stats[ STAT_BUILDABLE ] |= buildable;
+ else
+ G_TriggerMenu( ent->client->ps.clientNum, err );
}
+ else
+ G_TriggerMenu( ent->client->ps.clientNum, MN_B_CANNOT );
}
- /*
- =================
- Cmd_Resign_f
- =================
- */
- void Cmd_Resign_f( gentity_t *ent )
- {
- if( !ent->client->pers.designatedBuilder )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"You are not a designated builder\n\"" );
- return;
- }
-
- ent->client->pers.designatedBuilder = qfalse;
- trap_SendServerCommand( -1, va(
- "print \"%s" S_COLOR_WHITE " has resigned\n\"",
- ent->client->pers.netname ) );
- G_CheckDBProtection( );
- }
-
-
-
/*
=================
Cmd_Reload_f
@@ -3967,347 +2742,29 @@ Cmd_Reload_f
*/
void Cmd_Reload_f( gentity_t *ent )
{
- if( ( ent->client->ps.weapon >= WP_ABUILD ) &&
- ( ent->client->ps.weapon <= WP_HBUILD ) )
- {
- if( ent->client->pers.designatedBuilder )
- Cmd_Protect_f( ent );
- else
- Cmd_Mark_f( ent );
- }
- else if( ent->client->ps.weaponstate != WEAPON_RELOADING )
- ent->client->ps.pm_flags |= PMF_WEAPON_RELOAD;
-}
-
-
-/*
-=================
-Cmd_MyStats_f
-=================
-*/
-void Cmd_MyStats_f( gentity_t *ent )
-{
-
- if(!ent) return;
-
-
- if( !level.intermissiontime && ent->client->pers.statscounters.timeLastViewed && (level.time - ent->client->pers.statscounters.timeLastViewed) <60000 )
- {
- ADMP( "You may only check your stats once per minute and during intermission.\n");
- return;
- }
-
- if( !g_myStats.integer )
- {
- ADMP( "myStats has been disabled\n");
- return;
- }
-
- ADMP( G_statsString( &ent->client->pers.statscounters, &ent->client->pers.teamSelection ) );
- ent->client->pers.statscounters.timeLastViewed = level.time;
-
- return;
-}
-
-char *G_statsString( statsCounters_t *sc, pTeam_t *pt )
-{
- char *s;
-
- int percentNearBase=0;
- int percentJetpackWallwalk=0;
- int percentHeadshots=0;
- double avgTimeAlive=0;
- int avgTimeAliveMins = 0;
- int avgTimeAliveSecs = 0;
-
- if( sc->timealive )
- percentNearBase = (int)(100 * (float) sc->timeinbase / ((float) (sc->timealive ) ) );
-
- if( sc->timealive && sc->deaths )
- {
- avgTimeAlive = sc->timealive / sc->deaths;
- }
-
- avgTimeAliveMins = (int) (avgTimeAlive / 60.0f);
- avgTimeAliveSecs = (int) (avgTimeAlive - (60.0f * avgTimeAliveMins));
-
- if( *pt == PTE_ALIENS )
- {
- if( sc->dretchbasytime > 0 )
- percentJetpackWallwalk = (int)(100 * (float) sc->jetpackusewallwalkusetime / ((float) ( sc->dretchbasytime) ) );
-
- if( sc->hitslocational )
- percentHeadshots = (int)(100 * (float) sc->headshots / ((float) (sc->hitslocational) ) );
-
- s = va( "^3Kills:^7 %3i ^3StructKills:^7 %3i ^3Assists:^7 %3i^7 ^3Poisons:^7 %3i ^3Headshots:^7 %3i (%3i)\n^3Deaths:^7 %3i ^3Feeds:^7 %3i ^3Suicides:^7 %3i ^3TKs:^7 %3i ^3Avg Lifespan:^7 %4d:%02d\n^3Damage to:^7 ^3Enemies:^7 %5i ^3Structs:^7 %5i ^3Friendlies:^7 %3i \n^3Structs Built:^7 %3i ^3Time Near Base:^7 %3i ^3Time wallwalking:^7 %3i\n",
- sc->kills,
- sc->structskilled,
- sc->assists,
- sc->repairspoisons,
- sc->headshots,
- percentHeadshots,
- sc->deaths,
- sc->feeds,
- sc->suicides,
- sc->teamkills,
- avgTimeAliveMins,
- avgTimeAliveSecs,
- sc->dmgdone,
- sc->structdmgdone,
- sc->ffdmgdone,
- sc->structsbuilt,
- percentNearBase,
- percentJetpackWallwalk
- );
- }
- else if( *pt == PTE_HUMANS )
- {
- if( sc->timealive )
- percentJetpackWallwalk = (int)(100 * (float) sc->jetpackusewallwalkusetime / ((float) ( sc->timealive ) ) );
- s = va( "^3Kills:^7 %3i ^3StructKills:^7 %3i ^3Assists:^7 %3i \n^3Deaths:^7 %3i ^3Feeds:^7 %3i ^3Suicides:^7 %3i ^3TKs:^7 %3i ^3Avg Lifespan:^7 %4d:%02d\n^3Damage to:^7 ^3Enemies:^7 %5i ^3Structs:^7 %5i ^3Friendlies:^7 %3i \n^3Structs Built:^7 %3i ^3Repairs:^7 %4i ^3Time Near Base:^7 %3i ^3Time Jetpacking:^7 %3i\n",
- sc->kills,
- sc->structskilled,
- sc->assists,
- sc->deaths,
- sc->feeds,
- sc->suicides,
- sc->teamkills,
- avgTimeAliveMins,
- avgTimeAliveSecs,
- sc->dmgdone,
- sc->structdmgdone,
- sc->ffdmgdone,
- sc->structsbuilt,
- sc->repairspoisons,
- percentNearBase,
- percentJetpackWallwalk
- );
- }
- else s="No stats available\n";
-
- return s;
-}
-
- /*
- =================
- Cmd_AllStats_f
- =================
- */
- void Cmd_AllStats_f( gentity_t *ent )
- {
- int i;
- int NextViewTime;
- int NumResults = 0;
- int Teamcolor = 3;
- gentity_t *tmpent;
-
- //check if ent exists
- if(!ent) return;
-
- NextViewTime = ent->client->pers.statscounters.AllstatstimeLastViewed + g_AllStatsTime.integer * 1000;
- //check if you can use the cmd at this time
- if( !level.intermissiontime && level.time < NextViewTime)
- {
- ADMP( va("You may only check your stats every %i Seconds and during intermission. Next valid time is %d:%02d\n",( g_AllStatsTime.integer ) ? ( g_AllStatsTime.integer ) : 60, ( NextViewTime / 60000 ), ( NextViewTime / 1000 ) % 60 ) );
- return;
- }
- //see if allstats is enabled
- if( !g_AllStats.integer )
- {
- ADMP( "AllStats has been disabled\n");
- return;
- }
- ADMP("^3K^2=^7Kills ^3A^2=^7Assists ^3SK^2=^7StructKills\n^3D^2=^7Deaths ^3F^2=^7Feeds ^3S^2=^7Suicides ^3TK^2=^7Teamkills\n^3DD^2=^7Damage done ^3TDD^2=^7Team Damage done\n^3SB^2=^7Structs Built\n\n" );
- //display a header describing the data
- ADMP( "^3 #| K A SK| D F S TK| DD TDD| SB| Name\n" );
+ playerState_t *ps = &ent->client->ps;
+ int ammo;
- //loop through the clients that are connected
- for( i = 0; i < level.numConnectedClients; i++ )
- {
- //assign a tempent 4 the hell of it
- tmpent = &g_entities[ level.sortedClients[ i ] ];
-
- //check for what mode we are working in and display relevent data
- if( g_AllStats.integer == 1 )
- {
- //check if client is connected and on same team
- if( tmpent->client && tmpent->client->pers.connected == CON_CONNECTED && tmpent->client->pers.teamSelection == ent->client->pers.teamSelection && tmpent->client->pers.teamSelection != PTE_NONE )
- {
- NumResults++;
- if( tmpent->client->pers.teamSelection == PTE_ALIENS ) Teamcolor = 1;
- if( tmpent->client->pers.teamSelection == PTE_HUMANS ) Teamcolor = 5;
- ADMP( va( "^%i%2i^3|^%i%3i %3i %3i^3|^%i%3i %3i %3i %3i^3|^%i%5i %5i^3|^%i%3i^3|^7 %s\n",
- Teamcolor,
- NumResults,
- Teamcolor,
- ( tmpent->client->pers.statscounters.kills ) ? tmpent->client->pers.statscounters.kills : 0,
- ( tmpent->client->pers.statscounters.assists ) ? tmpent->client->pers.statscounters.assists : 0,
- ( tmpent->client->pers.statscounters.structskilled ) ? tmpent->client->pers.statscounters.structskilled : 0,
- Teamcolor,
- ( tmpent->client->pers.statscounters.deaths ) ? tmpent->client->pers.statscounters.deaths : 0,
- ( tmpent->client->pers.statscounters.feeds ) ? tmpent->client->pers.statscounters.feeds : 0,
- ( tmpent->client->pers.statscounters.suicides ) ? tmpent->client->pers.statscounters.suicides : 0,
- ( tmpent->client->pers.statscounters.teamkills ) ? tmpent->client->pers.statscounters.teamkills : 0,
- Teamcolor,
- ( tmpent->client->pers.statscounters.dmgdone ) ? tmpent->client->pers.statscounters.dmgdone : 0,
- ( tmpent->client->pers.statscounters.ffdmgdone ) ? tmpent->client->pers.statscounters.ffdmgdone : 0,
- Teamcolor,
- ( tmpent->client->pers.statscounters.structsbuilt ) ? tmpent->client->pers.statscounters.structsbuilt : 0,
- ( tmpent->client->pers.netname ) ? tmpent->client->pers.netname : "Unknown" ) );
- }
- }
- else if( g_AllStats.integer == 2 )
- {
- //check if client is connected and has some stats or atleast is on a team
- if( tmpent->client && tmpent->client->pers.connected == CON_CONNECTED && ( tmpent->client->pers.teamSelection != PTE_NONE ) )
- {
- NumResults++;
- if( tmpent->client->pers.teamSelection == PTE_ALIENS ) Teamcolor = 1;
- if( tmpent->client->pers.teamSelection == PTE_HUMANS ) Teamcolor = 5;
- ADMP( va( "^%i%2i^3|^%i%3i %3i %3i^3|^%i%3i %3i %3i %3i^3|^%i%5i %5i^3|^%i%3i^3|^7 %s\n",
- Teamcolor,
- NumResults,
- Teamcolor,
- ( tmpent->client->pers.statscounters.kills ) ? tmpent->client->pers.statscounters.kills : 0,
- ( tmpent->client->pers.statscounters.assists ) ? tmpent->client->pers.statscounters.assists : 0,
- ( tmpent->client->pers.statscounters.structskilled ) ? tmpent->client->pers.statscounters.structskilled : 0,
- Teamcolor,
- ( tmpent->client->pers.statscounters.deaths ) ? tmpent->client->pers.statscounters.deaths : 0,
- ( tmpent->client->pers.statscounters.feeds ) ? tmpent->client->pers.statscounters.feeds : 0,
- ( tmpent->client->pers.statscounters.suicides ) ? tmpent->client->pers.statscounters.suicides : 0,
- ( tmpent->client->pers.statscounters.teamkills ) ? tmpent->client->pers.statscounters.teamkills : 0,
- Teamcolor,
- ( tmpent->client->pers.statscounters.dmgdone ) ? tmpent->client->pers.statscounters.dmgdone : 0,
- ( tmpent->client->pers.statscounters.ffdmgdone ) ? tmpent->client->pers.statscounters.ffdmgdone : 0,
- Teamcolor,
- ( tmpent->client->pers.statscounters.structsbuilt ) ? tmpent->client->pers.statscounters.structsbuilt : 0,
- ( tmpent->client->pers.netname ) ? tmpent->client->pers.netname : "Unknown" ) );
- }
- }
- }
- if( NumResults == 0 ) {
- ADMP( " ^3EMPTY!\n" );
- } else {
- ADMP( va( "^7 %i Players found!\n", NumResults ) );
- }
- //update time last viewed
-
- ent->client->pers.statscounters.AllstatstimeLastViewed = level.time;
+ // weapon doesn't ever need reloading
+ if( BG_Weapon( ps->weapon )->infiniteAmmo )
return;
-}
-/*
-=================
-Cmd_TeamStatus_f
-=================
-*/
-void Cmd_TeamStatus_f( gentity_t *ent )
-{
- char multiple[ 12 ];
- int builders = 0;
- int arm = 0, mediboost = 0;
- int omrccount = 0, omrchealth = 0;
- qboolean omrcbuild = qfalse;
- gentity_t *tmp;
- int i;
-
- if( !g_teamStatus.integer )
- {
- trap_SendServerCommand( ent - g_entities,
- "print \"teamstatus is disabled.\n\"" );
+ if( ps->clips <= 0 )
return;
- }
- if( G_IsMuted( ent->client ) )
- {
- trap_SendServerCommand( ent - g_entities,
- "print \"You are muted and cannot use message commands.\n\"" );
- return;
- }
+ if( BG_Weapon( ps->weapon )->usesEnergy &&
+ BG_InventoryContainsUpgrade( UP_BATTPACK, ps->stats ) )
+ ammo = BG_Weapon( ps->weapon )->maxAmmo * BATTPACK_MODIFIER;
+ else
+ ammo = BG_Weapon( ps->weapon )->maxAmmo;
- if( ent->client->pers.lastTeamStatus &&
- ( level.time - ent->client->pers.lastTeamStatus) < g_teamStatus.integer * 1000 )
- {
- ADMP( va("You may only check your team's status once every %i seconds.\n",
- g_teamStatus.integer ));
+ // don't reload when full
+ if( ps->ammo >= ammo )
return;
- }
- ent->client->pers.lastTeamStatus = level.time;
-
- tmp = &g_entities[ 0 ];
- for ( i = 0; i < level.num_entities; i++, tmp++ )
- {
- if( i < MAX_CLIENTS )
- {
- if( tmp->client &&
- tmp->client->pers.connected == CON_CONNECTED &&
- tmp->client->pers.teamSelection == ent->client->pers.teamSelection &&
- tmp->health > 0 &&
- ( tmp->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0 ||
- tmp->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0_UPG ||
- BG_InventoryContainsWeapon( WP_HBUILD, tmp->client->ps.stats ) ||
- BG_InventoryContainsWeapon( WP_HBUILD2, tmp->client->ps.stats ) ) )
- builders++;
- continue;
- }
-
- if( tmp->s.eType == ET_BUILDABLE )
- {
- if( tmp->biteam != ent->client->pers.teamSelection ||
- tmp->health <= 0 )
- continue;
-
- switch( tmp->s.modelindex )
- {
- case BA_H_REACTOR:
- case BA_A_OVERMIND:
- omrccount++;
- if( tmp->health > omrchealth )
- omrchealth = tmp->health;
- if( !omrcbuild )
- omrcbuild = tmp->spawned;
- break;
- case BA_H_ARMOURY:
- arm++;
- break;
- case BA_H_MEDISTAT:
- case BA_A_BOOSTER:
- mediboost++;
- break;
- default:
- break;
- }
- }
- }
-
- if( omrccount > 1 )
- Com_sprintf( multiple, sizeof( multiple ), "^7[x%d]", omrccount );
- else
- multiple[ 0 ] = '\0';
-
- if( ent->client->pers.teamSelection == PTE_ALIENS )
- {
- G_Say( ent, NULL, SAY_TEAM,
- va( "^3OM: %s(%d)%s ^3Spawns: ^5%d ^3Builders: ^5%d ^3Boosters: ^5%d^7" ,
- ( !omrccount ) ? "^1Down" : ( omrcbuild ) ? "^2Up" : "^5Building",
- omrchealth * 100 / OVERMIND_HEALTH,
- multiple,
- level.numAlienSpawns,
- builders,
- mediboost ) );
- }
- else
- {
- G_Say( ent, NULL, SAY_TEAM,
- va( "^3RC: %s(%d)%s ^3Spawns: ^5%d ^3Builders: ^5%d ^3Armouries: ^5%d ^3Medistations: ^5%d^7" ,
- ( !omrccount ) ? "^1Down" : ( omrcbuild ) ? "^2Up" : "^5Building",
- omrchealth * 100 / REACTOR_HEALTH,
- multiple,
- level.numHumanSpawns,
- builders,
- arm, mediboost ) );
- }
+ // the animation, ammo refilling etc. is handled by PM_Weapon
+ if( ent->client->ps.weaponstate != WEAPON_RELOADING )
+ ent->client->ps.pm_flags |= PMF_WEAPON_RELOAD;
}
/*
@@ -4325,7 +2782,7 @@ void G_StopFromFollowing( gentity_t *ent )
for( i = 0; i < level.maxclients; i++ )
{
if( level.clients[ i ].sess.spectatorState == SPECTATOR_FOLLOW &&
- level.clients[ i ].sess.spectatorClient == ent-g_entities )
+ level.clients[ i ].sess.spectatorClient == ent->client->ps.clientNum )
{
if( !G_FollowNewClient( &g_entities[ i ], 1 ) )
G_StopFollowing( &g_entities[ i ] );
@@ -4343,44 +2800,86 @@ to free floating spectator mode
*/
void G_StopFollowing( gentity_t *ent )
{
- ent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR;
- ent->client->sess.sessionTeam = TEAM_SPECTATOR;
- ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.teamSelection;
+ ent->client->ps.stats[ STAT_TEAM ] = ent->client->pers.teamSelection;
- if( ent->client->pers.teamSelection == PTE_NONE )
+ if( ent->client->pers.teamSelection == TEAM_NONE )
{
- ent->client->sess.spectatorState = SPECTATOR_FREE;
- ent->client->ps.pm_type = PM_SPECTATOR;
- ent->client->ps.stats[ STAT_HEALTH ] = 100; // hacky server-side fix to prevent cgame from viewlocking a freespec
+ ent->client->sess.spectatorState =
+ ent->client->ps.persistant[ PERS_SPECSTATE ] = SPECTATOR_FREE;
}
else
{
- vec3_t spawn_origin, spawn_angles;
+ vec3_t spawn_origin, spawn_angles;
- ent->client->sess.spectatorState = SPECTATOR_LOCKED;
- if( ent->client->pers.teamSelection == PTE_ALIENS )
+ ent->client->sess.spectatorState =
+ ent->client->ps.persistant[ PERS_SPECSTATE ] = SPECTATOR_LOCKED;
+
+ if( ent->client->pers.teamSelection == TEAM_ALIENS )
G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles );
- else if( ent->client->pers.teamSelection == PTE_HUMANS )
+ else if( ent->client->pers.teamSelection == TEAM_HUMANS )
G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles );
+
G_SetOrigin( ent, spawn_origin );
VectorCopy( spawn_origin, ent->client->ps.origin );
G_SetClientViewAngle( ent, spawn_angles );
}
ent->client->sess.spectatorClient = -1;
ent->client->ps.pm_flags &= ~PMF_FOLLOW;
+ ent->client->ps.groundEntityNum = ENTITYNUM_NONE;
+ ent->client->ps.stats[ STAT_STATE ] = 0;
+ ent->client->ps.stats[ STAT_VIEWLOCK ] = 0;
+ ent->client->ps.eFlags &= ~( EF_WALLCLIMB | EF_WALLCLIMBCEILING );
+ ent->client->ps.viewangles[ PITCH ] = 0.0f;
+ ent->client->ps.clientNum = ent - g_entities;
+ ent->client->ps.persistant[ PERS_CREDIT ] = ent->client->pers.credit;
+
+ if( ent->client->pers.teamSelection == TEAM_NONE )
+ {
+ vec3_t viewOrigin, angles;
+
+ BG_GetClientViewOrigin( &ent->client->ps, viewOrigin );
+ VectorCopy( ent->client->ps.viewangles, angles );
+ angles[ ROLL ] = 0;
+ TeleportPlayer( ent, viewOrigin, angles, qfalse );
+ }
+
+ CalculateRanks( );
+}
+
+/*
+=================
+G_FollowLockView
- // Prevent spawning with bsuit in rare case
- if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, ent->client->ps.stats ) )
- BG_RemoveUpgradeFromInventory( UP_BATTLESUIT, ent->client->ps.stats );
+Client is still following a player, but that player has gone to spectator
+mode and cannot be followed for the moment
+=================
+*/
+void G_FollowLockView( gentity_t *ent )
+{
+ vec3_t spawn_origin, spawn_angles;
+ int clientNum;
+ clientNum = ent->client->sess.spectatorClient;
+ ent->client->sess.spectatorState =
+ ent->client->ps.persistant[ PERS_SPECSTATE ] = SPECTATOR_FOLLOW;
+ ent->client->ps.clientNum = clientNum;
+ ent->client->ps.pm_flags &= ~PMF_FOLLOW;
+ ent->client->ps.stats[ STAT_TEAM ] = ent->client->pers.teamSelection;
ent->client->ps.stats[ STAT_STATE ] &= ~SS_WALLCLIMBING;
- ent->client->ps.stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING;
- ent->client->ps.eFlags &= ~EF_WALLCLIMB;
+ ent->client->ps.stats[ STAT_VIEWLOCK ] = 0;
+ ent->client->ps.eFlags &= ~( EF_WALLCLIMB | EF_WALLCLIMBCEILING );
+ ent->client->ps.eFlags ^= EF_TELEPORT_BIT;
ent->client->ps.viewangles[ PITCH ] = 0.0f;
- ent->client->ps.clientNum = ent - g_entities;
+ // Put the view at the team spectator lock position
+ if( level.clients[ clientNum ].pers.teamSelection == TEAM_ALIENS )
+ G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles );
+ else if( level.clients[ clientNum ].pers.teamSelection == TEAM_HUMANS )
+ G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles );
- CalculateRanks( );
+ G_SetOrigin( ent, spawn_origin );
+ VectorCopy( spawn_origin, ent->client->ps.origin );
+ G_SetClientViewAngle( ent, spawn_angles );
}
/*
@@ -4403,7 +2902,7 @@ qboolean G_FollowNewClient( gentity_t *ent, int dir )
else if( dir == 0 )
return qtrue;
- if( ent->client->sess.sessionTeam != TEAM_SPECTATOR )
+ if( ent->client->sess.spectatorState == SPECTATOR_NOT )
return qfalse;
// select any if no target exists
@@ -4423,36 +2922,41 @@ qboolean G_FollowNewClient( gentity_t *ent, int dir )
if( clientnum < 0 )
clientnum = level.maxclients - 1;
+ // can't follow self
+ if( &g_entities[ clientnum ] == ent )
+ continue;
+
// avoid selecting existing follow target
if( clientnum == original && !selectAny )
continue; //effectively break;
- // can't follow self
- if( &level.clients[ clientnum ] == ent->client )
- continue;
-
// can only follow connected clients
if( level.clients[ clientnum ].pers.connected != CON_CONNECTED )
continue;
- // can't follow another spectator
- if( level.clients[ clientnum ].pers.teamSelection == PTE_NONE )
- continue;
-
- // can only follow teammates when dead and on a team
- if( ent->client->pers.teamSelection != PTE_NONE &&
- ( level.clients[ clientnum ].pers.teamSelection !=
- ent->client->pers.teamSelection ) )
- continue;
-
- // cannot follow a teammate who is following you
- if( level.clients[ clientnum ].sess.spectatorState == SPECTATOR_FOLLOW &&
- ( level.clients[ clientnum ].sess.spectatorClient == ent->s.number ) )
- continue;
+ // can't follow a spectator
+ if( level.clients[ clientnum ].pers.teamSelection == TEAM_NONE )
+ continue;
+
+ // if stickyspec is disabled, can't follow someone in queue either
+ if( !ent->client->pers.stickySpec &&
+ level.clients[ clientnum ].sess.spectatorState != SPECTATOR_NOT )
+ continue;
+
+ // can only follow teammates when dead and on a team
+ if( ent->client->pers.teamSelection != TEAM_NONE &&
+ ( level.clients[ clientnum ].pers.teamSelection !=
+ ent->client->pers.teamSelection ) )
+ continue;
// this is good, we can use it
ent->client->sess.spectatorClient = clientnum;
ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
+
+ // if this client is in the spawn queue, we need to do something special
+ if( level.clients[ clientnum ].sess.spectatorState != SPECTATOR_NOT )
+ G_FollowLockView( ent );
+
return qtrue;
} while( clientnum != original );
@@ -4467,12 +2971,6 @@ G_ToggleFollow
*/
void G_ToggleFollow( gentity_t *ent )
{
- if( level.mapRotationVoteTime )
- {
- G_IntermissionMapVoteCommand( ent, qfalse, qtrue );
- return;
- }
-
if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
G_StopFollowing( ent );
else
@@ -4487,20 +2985,11 @@ Cmd_Follow_f
void Cmd_Follow_f( gentity_t *ent )
{
int i;
- int pids[ MAX_CLIENTS ];
- char arg[ MAX_TOKEN_CHARS ];
+ char arg[ MAX_NAME_LENGTH ];
- if( ent->client->sess.sessionTeam != TEAM_SPECTATOR )
- {
- trap_SendServerCommand( ent - g_entities, "print \"follow: You cannot follow unless you are dead or on the spectators.\n\"" );
- return;
- }
- if( ent->client->pers.paused )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"You may not build while paused\n\"" );
+ // won't work unless spectating
+ if( ent->client->sess.spectatorState == SPECTATOR_NOT )
return;
- }
if( trap_Argc( ) != 2 )
{
@@ -4508,45 +2997,32 @@ void Cmd_Follow_f( gentity_t *ent )
}
else
{
+ char err[ MAX_STRING_CHARS ];
trap_Argv( 1, arg, sizeof( arg ) );
- if( G_ClientNumbersFromString( arg, pids ) == 1 )
- {
- i = pids[ 0 ];
- }
- else
- {
- i = G_ClientNumberFromString( ent, arg );
- if( i == -1 )
- {
- trap_SendServerCommand( ent - g_entities,
- "print \"follow: invalid player\n\"" );
- return;
- }
+ i = G_ClientNumberFromString( arg, err, sizeof( err ) );
+
+ if( i == -1 )
+ {
+ trap_SendServerCommand( ent - g_entities,
+ va( "print \"follow: %s\"", err ) );
+ return;
}
// can't follow self
if( &level.clients[ i ] == ent->client )
- {
- trap_SendServerCommand( ent - g_entities, "print \"follow: You cannot follow yourself.\n\"" );
return;
- }
- // can't follow another spectator
- if( level.clients[ i ].pers.teamSelection == PTE_NONE)
- {
- trap_SendServerCommand( ent - g_entities, "print \"follow: You cannot follow another spectator.\n\"" );
+ // can't follow another spectator if sticky spec is off
+ if( !ent->client->pers.stickySpec &&
+ level.clients[ i ].sess.spectatorState != SPECTATOR_NOT )
return;
- }
- // can only follow teammates when dead and on a team
- if( ent->client->pers.teamSelection != PTE_NONE &&
- ( level.clients[ i ].pers.teamSelection !=
+ // if not on team spectator, you can only follow teammates
+ if( ent->client->pers.teamSelection != TEAM_NONE &&
+ ( level.clients[ i ].pers.teamSelection !=
ent->client->pers.teamSelection ) )
- {
- trap_SendServerCommand( ent - g_entities, "print \"follow: You can only follow teammates, and only when you are dead.\n\"" );
return;
- }
ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
ent->client->sess.spectatorClient = i;
@@ -4568,126 +3044,10 @@ void Cmd_FollowCycle_f( gentity_t *ent )
dir = -1;
// won't work unless spectating
- if( ent->client->sess.sessionTeam != TEAM_SPECTATOR )
- return;
- if( ent->client->sess.spectatorState == SPECTATOR_NOT )
- return;
- G_FollowNewClient( ent, dir );
-}
-
-/*
-=================
-Cmd_PTRCVerify_f
-
-Check a PTR code is valid
-=================
-*/
-void Cmd_PTRCVerify_f( gentity_t *ent )
-{
- connectionRecord_t *connection;
- char s[ MAX_TOKEN_CHARS ] = { 0 };
- int code;
-
- if( ent->client->pers.connection )
- return;
-
- trap_Argv( 1, s, sizeof( s ) );
-
- if( !strlen( s ) )
+ if( ent->client->sess.spectatorState == SPECTATOR_NOT )
return;
- code = atoi( s );
-
- connection = G_FindConnectionForCode( code );
- if( connection && connection->clientNum == -1 )
- {
- // valid code
- if( connection->clientTeam != PTE_NONE )
- trap_SendServerCommand( ent->client->ps.clientNum, "ptrcconfirm" );
-
- // restore mapping
- ent->client->pers.connection = connection;
- connection->clientNum = ent->client->ps.clientNum;
- }
- else
- {
- // invalid code -- generate a new one
- connection = G_GenerateNewConnection( ent->client );
-
- if( connection )
- {
- trap_SendServerCommand( ent->client->ps.clientNum,
- va( "ptrcissue %d", connection->ptrCode ) );
- }
- }
-}
-
-/*
-=================
-Cmd_PTRCRestore_f
-
-Restore against a PTR code
-=================
-*/
-void Cmd_PTRCRestore_f( gentity_t *ent )
-{
- char s[ MAX_TOKEN_CHARS ] = { 0 };
- int code;
- connectionRecord_t *connection;
-
- if( ent->client->pers.joinedATeam )
- {
- trap_SendServerCommand( ent - g_entities,
- "print \"You cannot use a PTR code after joining a team\n\"" );
- return;
- }
-
- trap_Argv( 1, s, sizeof( s ) );
-
- if( !strlen( s ) )
- return;
-
- code = atoi( s );
-
- connection = ent->client->pers.connection;
- if( connection && connection->ptrCode == code )
- {
- // Set the correct team
- if( !( ent->client->pers.specExpires > level.time ) )
- {
- // Check if the alien team is full
- if( connection->clientTeam == PTE_ALIENS &&
- !G_admin_permission(ent, ADMF_FORCETEAMCHANGE) &&
- g_teamForceBalance.integer &&
- level.numAlienClients > level.numHumanClients )
- {
- G_TriggerMenu( ent - g_entities, MN_A_TEAMFULL );
- }
- // Check if the human team is full
- else if( connection->clientTeam == PTE_HUMANS &&
- !G_admin_permission(ent, ADMF_FORCETEAMCHANGE) &&
- g_teamForceBalance.integer &&
- level.numHumanClients > level.numAlienClients )
- {
- G_TriggerMenu( ent - g_entities, MN_H_TEAMFULL );
- }
- else
- {
- G_ChangeTeam( ent, connection->clientTeam );
- }
- }
-
- // set the correct credit etc.
- ent->client->ps.persistant[ PERS_CREDIT ] = 0;
- G_AddCreditToClient( ent->client, connection->clientCredit, qtrue );
- ent->client->pers.score = connection->clientScore;
- ent->client->pers.enterTime = connection->clientEnterTime;
- }
- else
- {
- trap_SendServerCommand( ent - g_entities,
- va( "print \"\"%d\" is not a valid PTR code\n\"", code ) );
- }
+ G_FollowNewClient( ent, dir );
}
static void Cmd_Ignore_f( gentity_t *ent )
@@ -4706,12 +3066,12 @@ static void Cmd_Ignore_f( gentity_t *ent )
if( trap_Argc() < 2 )
{
trap_SendServerCommand( ent-g_entities, va( "print \"[skipnotify]"
- "%s: usage \\%s [clientNum | partial name match]\n\"", cmd, cmd ) );
+ "usage: %s [clientNum | partial name match]\n\"", cmd ) );
return;
}
Q_strncpyz( name, ConcatArgs( 1 ), sizeof( name ) );
- matches = G_ClientNumbersFromString( name, pids );
+ matches = G_ClientNumbersFromString( name, pids, MAX_CLIENTS );
if( matches < 1 )
{
trap_SendServerCommand( ent-g_entities, va( "print \"[skipnotify]"
@@ -4723,9 +3083,9 @@ static void Cmd_Ignore_f( gentity_t *ent )
{
if( ignore )
{
- if( !BG_ClientListTest( &ent->client->sess.ignoreList, pids[ i ] ) )
+ if( !Com_ClientListContains( &ent->client->sess.ignoreList, pids[ i ] ) )
{
- BG_ClientListAdd( &ent->client->sess.ignoreList, pids[ i ] );
+ Com_ClientListAdd( &ent->client->sess.ignoreList, pids[ i ] );
ClientUserinfoChanged( ent->client->ps.clientNum, qfalse );
trap_SendServerCommand( ent-g_entities, va( "print \"[skipnotify]"
"ignore: added %s^7 to your ignore list\n\"",
@@ -4740,9 +3100,9 @@ static void Cmd_Ignore_f( gentity_t *ent )
}
else
{
- if( BG_ClientListTest( &ent->client->sess.ignoreList, pids[ i ] ) )
+ if( Com_ClientListContains( &ent->client->sess.ignoreList, pids[ i ] ) )
{
- BG_ClientListRemove( &ent->client->sess.ignoreList, pids[ i ] );
+ Com_ClientListRemove( &ent->client->sess.ignoreList, pids[ i ] );
ClientUserinfoChanged( ent->client->ps.clientNum, qfalse );
trap_SendServerCommand( ent-g_entities, va( "print \"[skipnotify]"
"unignore: removed %s^7 from your ignore list\n\"",
@@ -4758,396 +3118,356 @@ static void Cmd_Ignore_f( gentity_t *ent )
}
}
- /*
- =================
- Cmd_Share_f
- =================
- */
- void Cmd_Share_f( gentity_t *ent )
- {
- int i, clientNum = 0, creds = 0, skipargs = 0;
- int clientNums[ MAX_CLIENTS ] = { -1 };
- char cmd[ 12 ];
- char arg1[ MAX_STRING_TOKENS ];
- char arg2[ MAX_STRING_TOKENS ];
- pTeam_t team;
-
- if( !ent || !ent->client || ( ent->client->pers.teamSelection == PTE_NONE ) )
- {
- return;
- }
-
- if( !g_allowShare.integer )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Share has been disabled.\n\"" );
- return;
- }
-
- if( g_floodMinTime.integer )
- if ( G_Flood_Limited( ent ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Your chat is flood-limited; wait before chatting again\n\"" );
+/*
+=================
+Cmd_ListMaps_f
+
+List all maps on the server
+=================
+*/
+
+static int SortMaps( const void *a, const void *b )
+{
+ return strcmp( *(char **)a, *(char **)b );
+}
+
+#define MAX_MAPLIST_MAPS 256
+#define MAX_MAPLIST_ROWS 9
+void Cmd_ListMaps_f( gentity_t *ent )
+{
+ char search[ 16 ] = {""};
+ char fileList[ 4096 ] = {""};
+ char *fileSort[ MAX_MAPLIST_MAPS ];
+ char *filePtr, *p;
+ int numFiles;
+ int fileLen = 0;
+ int shown = 0;
+ int count = 0;
+ int page = 0;
+ int pages;
+ int row, rows;
+ int start, i, j;
+
+ if( trap_Argc( ) > 1 )
+ {
+ trap_Argv( 1, search, sizeof( search ) );
+ for( p = search; ( *p ) && isdigit( *p ); p++ );
+ if( !( *p ) )
+ {
+ page = atoi( search );
+ search[ 0 ] = '\0';
+ }
+ else if( trap_Argc( ) > 2 )
+ {
+ char lp[ 8 ];
+ trap_Argv( 2, lp, sizeof( lp ) );
+ page = atoi( lp );
+ }
+
+ if( page > 0 )
+ page--;
+ else if( page < 0 )
+ page = 0;
+ }
+
+ numFiles = trap_FS_GetFileList( "maps/", ".bsp",
+ fileList, sizeof( fileList ) );
+ filePtr = fileList;
+ for( i = 0; i < numFiles && count < MAX_MAPLIST_MAPS; i++, filePtr += fileLen + 1 )
+ {
+ fileLen = strlen( filePtr );
+ if ( fileLen < 5 )
+ continue;
+
+ filePtr[ fileLen - 4 ] = '\0';
+
+ if( search[ 0 ] && !strstr( filePtr, search ) )
+ continue;
+
+ fileSort[ count ] = filePtr;
+ count++;
+ }
+ qsort( fileSort, count, sizeof( fileSort[ 0 ] ), SortMaps );
+
+ rows = ( count + 2 ) / 3;
+ pages = MAX( 1, ( rows + MAX_MAPLIST_ROWS - 1 ) / MAX_MAPLIST_ROWS );
+ if( page >= pages )
+ page = pages - 1;
+
+ start = page * MAX_MAPLIST_ROWS * 3;
+ if( count < start + ( 3 * MAX_MAPLIST_ROWS ) )
+ rows = ( count - start + 2 ) / 3;
+ else
+ rows = MAX_MAPLIST_ROWS;
+
+ ADMBP_begin( );
+ for( row = 0; row < rows; row++ )
+ {
+ for( i = start + row, j = 0; i < count && j < 3; i += rows, j++ )
+ {
+ ADMBP( va( "^7 %-20s", fileSort[ i ] ) );
+ shown++;
+ }
+ ADMBP( "\n" );
+ }
+ if ( search[ 0 ] )
+ ADMBP( va( "^3listmaps: ^7found %d maps matching '%s^7'", count, search ) );
+ else
+ ADMBP( va( "^3listmaps: ^7listing %d of %d maps", shown, count ) );
+ if( pages > 1 )
+ ADMBP( va( ", page %d of %d", page + 1, pages ) );
+ if( page + 1 < pages )
+ ADMBP( va( ", use 'listmaps %s%s%d' to see more",
+ search, ( search[ 0 ] ) ? " ": "", page + 2 ) );
+ ADMBP( ".\n" );
+ ADMBP_end( );
+}
+
+/*
+=================
+Cmd_ListVoices_f
+=================
+*/
+void Cmd_ListVoices_f( gentity_t *ent )
+{
+ if ( !level.voices ) {
+ ADMP( "^3listvoices: ^7voice system is not installed on this server\n" );
return;
- }
-
- team = ent->client->pers.teamSelection;
-
- G_SayArgv( 0, cmd, sizeof( cmd ) );
- if( !Q_stricmp( cmd, "say" ) || !Q_stricmp( cmd, "say_team" ) )
- {
- skipargs = 1;
- G_SayArgv( 1, cmd, sizeof( cmd ) );
- }
-
- // target player name is in arg1
- G_SayArgv( 1+skipargs, arg1, sizeof( arg1 ) );
- // amount to be shared is in arg2
- G_SayArgv( 2+skipargs, arg2, sizeof( arg2 ) );
-
- if( arg1[0] && !strchr( arg1, ';' ) && Q_stricmp( arg1, "target_in_aim" ) )
- {
- //check arg1 is a number
- for( i = 0; arg1[ i ]; i++ )
- {
- if( arg1[ i ] < '0' || arg1[ i ] > '9' )
- {
- clientNum = -1;
- break;
- }
- }
-
- if( clientNum >= 0 )
- {
- clientNum = atoi( arg1 );
- }
- else if( G_ClientNumbersFromString( arg1, clientNums ) == 1 )
- {
- // there was one partial name match
- clientNum = clientNums[ 0 ];
- }
- else
- {
- // look for an exact name match before bailing out
- clientNum = G_ClientNumberFromString( ent, arg1 );
- if( clientNum == -1 )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"share: invalid player name specified.\n\"" );
- return;
- }
- }
- }
- else // arg1 not set
- {
- vec3_t forward, end;
- trace_t tr;
- gentity_t *traceEnt;
-
- // trace a teammate
- AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL );
- VectorMA( ent->client->ps.origin, 8192 * 16, forward, end );
-
- trap_Trace( &tr, ent->client->ps.origin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
- traceEnt = &g_entities[ tr.entityNum ];
-
- if( tr.fraction < 1.0f && traceEnt->client &&
- ( traceEnt->client->pers.teamSelection == team ) )
- {
- clientNum = traceEnt - g_entities;
- }
- else
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"share: aim at a teammate to share %s.\n\"",
- ( team == PTE_HUMANS ) ? "credits" : "evolvepoints" ) );
- return;
- }
- }
-
- // verify target player team
- if( ( clientNum < 0 ) || ( clientNum >= level.maxclients ) ||
- ( level.clients[ clientNum ].pers.teamSelection != team ) )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"share: not a valid player of your team.\n\"" );
- return;
- }
-
- if( !arg2[0] || strchr( arg2, ';' ) )
- {
- // default credit count
- if( team == PTE_HUMANS )
- {
- creds = FREEKILL_HUMAN;
- }
- else if( team == PTE_ALIENS )
- {
- creds = FREEKILL_ALIEN;
- }
- }
- else
- {
- //check arg2 is a number
- for( i = 0; arg2[ i ]; i++ )
- {
- if( arg2[ i ] < '0' || arg2[ i ] > '9' )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"usage: share [name|slot#] [amount]\n\"" );
- return;
- }
- }
-
- // credit count from parameter
- creds = atoi( arg2 );
- }
-
- // player specified "0" to transfer
- if( creds <= 0 )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"Ooh, you are a generous one, indeed!\n\"" );
- return;
- }
-
- // transfer only credits the player really has
- if( creds > ent->client->pers.credit )
- {
- creds = ent->client->pers.credit;
- }
-
- // player has no credits
- if( creds <= 0 )
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"Earn some first, lazy gal!\n\"" );
- return;
- }
-
- // allow transfers only up to the credit/evo limit
- if( ( team == PTE_HUMANS ) &&
- ( creds > HUMAN_MAX_CREDITS - level.clients[ clientNum ].pers.credit ) )
- {
- creds = HUMAN_MAX_CREDITS - level.clients[ clientNum ].pers.credit;
- }
- else if( ( team == PTE_ALIENS ) &&
- ( creds > ALIEN_MAX_KILLS - level.clients[ clientNum ].pers.credit ) )
- {
- creds = ALIEN_MAX_KILLS - level.clients[ clientNum ].pers.credit;
- }
-
- // target cannot take any more credits
- if( creds <= 0 )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"share: player cannot receive any more %s.\n\"",
- ( team == PTE_HUMANS ) ? "credits" : "evolvepoints" ) );
- return;
- }
-
- // transfer credits
- G_AddCreditToClient( ent->client, -creds, qfalse );
- trap_SendServerCommand( ent-g_entities,
- va( "print \"share: transferred %d %s to %s^7.\n\"", creds,
- ( team == PTE_HUMANS ) ? "credits" : "evolvepoints",
- level.clients[ clientNum ].pers.netname ) );
- G_AddCreditToClient( &(level.clients[ clientNum ]), creds, qtrue );
- trap_SendServerCommand( clientNum,
- va( "print \"You have received %d %s from %s^7.\n\"", creds,
- ( team == PTE_HUMANS ) ? "credits" : "evolvepoints",
- ent->client->pers.netname ) );
-
- G_LogPrintf( "Share: %i %i %i %d: %s^7 transferred %d%s to %s^7\n",
- ent->client->ps.clientNum,
- clientNum,
- team,
- creds,
- ent->client->pers.netname,
- creds,
- ( team == PTE_HUMANS ) ? "c" : "e",
- level.clients[ clientNum ].pers.netname );
- }
-
- /*
- =================
- Cmd_Donate_f
-
- Alms for the poor
- =================
- */
- void Cmd_Donate_f( gentity_t *ent ) {
- char s[ MAX_TOKEN_CHARS ] = "", *type = "evo(s)";
- int i, value, divisor, portion, new_credits, total=0,
- max = ALIEN_MAX_KILLS, *amounts, *totals;
- qboolean donated = qtrue;
-
- if( !ent->client ) return;
-
- if( !g_allowShare.integer )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Donate has been disabled.\n\"" );
- return;
- }
-
- if( g_floodMinTime.integer )
- if ( G_Flood_Limited( ent ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Your chat is flood-limited; wait before chatting again\n\"" );
+ }
+
+ if ( !g_voiceChats.integer ) {
+ ADMP( "^3listvoices: ^7voice system administratively disabled on this server\n" );
return;
- }
-
- if( ent->client->pers.teamSelection == PTE_ALIENS )
- divisor = level.numAlienClients-1;
- else if( ent->client->pers.teamSelection == PTE_HUMANS ) {
- divisor = level.numHumanClients-1;
- max = HUMAN_MAX_CREDITS;
- type = "credit(s)";
- } else {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"donate: spectators cannot be so gracious\n\"" ) );
- return;
- }
-
- if( divisor < 1 ) {
- trap_SendServerCommand( ent-g_entities,
- "print \"donate: get yourself some teammates first\n\"" );
- return;
- }
-
- trap_Argv( 1, s, sizeof( s ) );
- value = atoi(s);
- if( value <= 0 ) {
- trap_SendServerCommand( ent-g_entities,
- "print \"donate: very funny\n\"" );
- return;
- }
- if( value > ent->client->pers.credit)
- value = ent->client->pers.credit;
-
- // allocate memory for distribution amounts
- amounts = G_Alloc( level.maxclients * sizeof( int ) );
- totals = G_Alloc( level.maxclients * sizeof( int ) );
- for( i = 0; i < level.maxclients; i++ ) {
- amounts[ i ] = 0;
- totals[ i ] = 0;
- }
-
- // determine donation amounts for each client
- total = value;
- while( donated && value ) {
- donated = qfalse;
- portion = value / divisor;
- if( portion < 1 ) portion = 1;
- for( i = 0; i < level.maxclients; i++ )
- if( level.clients[ i ].pers.connected == CON_CONNECTED &&
- ent->client != level.clients + i &&
- level.clients[ i ].pers.teamSelection ==
- ent->client->pers.teamSelection &&
- level.clients[ i ].pers.credit < max ) {
- new_credits = level.clients[ i ].pers.credit + portion;
- amounts[ i ] = portion;
- totals[ i ] += portion;
- if( new_credits > max ) {
- amounts[ i ] -= new_credits - max;
- totals[ i ] -= new_credits - max;
- new_credits = max;
- }
- if( amounts[ i ] ) {
- G_AddCreditToClient( &(level.clients[ i ]), amounts[ i ], qtrue );
- donated = qtrue;
- value -= amounts[ i ];
- if( value < portion ) break;
- }
- }
- }
-
- // transfer funds
- G_AddCreditToClient( ent->client, value - total, qtrue );
- for( i = 0; i < level.maxclients; i++ )
- if( totals[ i ] ) {
- trap_SendServerCommand( i,
- va( "print \"%s^7 donated %d %s to you, don't forget to say 'thank you'!\n\"",
- ent->client->pers.netname, totals[ i ], type ) );
- }
-
- G_Free( amounts );
- G_Free( totals );
-
- trap_SendServerCommand( ent-g_entities,
- va( "print \"Donated %d %s to the cause.\n\"",
- total-value, type ) );
- }
+ }
-commands_t cmds[ ] = {
- // normal commands
- { "team", 0, Cmd_Team_f },
- { "vote", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Vote_f },
- { "ignore", 0, Cmd_Ignore_f },
- { "unignore", 0, Cmd_Ignore_f },
+ if ( trap_Argc() < 2 )
+ {
+ voice_t *v;
+ int i = 0;
+
+ ADMBP_begin();
+ for( v = level.voices; v; v = v->next )
+ {
+ ADMBP(va("%d - %s\n", i+1, v->name));
+ i++;
+ }
+ ADMBP(va("^3listvoices: ^7showing %d voices\n", i));
+ ADMBP("^3listvoices: ^7run 'listvoices <voice>' to see available commands.\n");
+ ADMBP_end();
+ return;
+ }
+ else if ( trap_Argc() >= 2 )
+ {
+ voice_t *v;
+ voiceCmd_t *c;
+ int i = 0;
+
+ char name[ MAX_VOICE_NAME_LEN ];
+ trap_Argv(1, name, sizeof(name));
+
+ v = BG_VoiceByName(level.voices, name);
+ if ( !v )
+ {
+ ADMP(va("^3listvoices: ^7no matching voice \"%s\"\n", name));
+ return;
+ }
+
+ ADMBP_begin();
+ for ( c = v->cmds; c; c = c->next )
+ {
+ ADMBP(va("%d - %s\n", i+1, c->cmd));
+ i++;
+ }
+ ADMBP(va("^3listvoices: ^7showing %d voice commands for %s\n", i, v->name));
+ ADMBP_end();
+ }
+}
+
+/*
+=================
+Cmd_ListModels_f
+
+List all the available player models installed on the server.
+=================
+*/
+void Cmd_ListModels_f( gentity_t *ent )
+{
+ int i;
+
+ ADMBP_begin();
+ for (i = 0; i < level.playerModelCount; i++)
+ {
+ ADMBP(va("%d - %s\n", i+1, level.playerModel[i]));
+ }
+ ADMBP(va("^3listmodels: ^7showing %d player models\n", level.playerModelCount));
+ ADMBP_end();
+
+}
+
+/*
+=================
+Cmd_ListSkins_f
+=================
+*/
+void Cmd_ListSkins_f( gentity_t *ent )
+{
+ char modelname[ 64 ];
+ char skins[ MAX_PLAYER_MODEL ][ 64 ];
+ int numskins;
+ int i;
+
+ if ( trap_Argc() < 2 )
+ {
+ ADMP("^3listskins: ^7usage: listskins <model>\n");
+ return;
+ }
+
+ trap_Argv(1, modelname, sizeof(modelname));
+
+ G_GetPlayerModelSkins(modelname, skins, MAX_PLAYER_MODEL, &numskins);
+
+ ADMBP_begin();
+ for (i = 0; i < numskins; i++)
+ {
+ ADMBP(va("%d - %s\n", i+1, skins[i]));
+ }
+ ADMBP(va("^3listskins: ^7default skin ^2%s\n", GetSkin(modelname, "default")));
+ ADMBP(va("^3listskins: ^7showing %d skins for %s\n", numskins, modelname));
+ ADMBP_end();
+}
+
+
+/*
+=================
+Cmd_Test_f
+=================
+*/
+void Cmd_Test_f( gentity_t *humanPlayer )
+{
+}
+
+/*
+=================
+Cmd_Damage_f
+
+Deals damage to you (for testing), arguments: [damage] [dx] [dy] [dz]
+The dx/dy arguments describe the damage point's offset from the entity origin
+=================
+*/
+void Cmd_Damage_f( gentity_t *ent )
+{
+ vec3_t point;
+ char arg[ 16 ];
+ float dx = 0.0f, dy = 0.0f, dz = 100.0f;
+ int damage = 100;
+ qboolean nonloc = qtrue;
+
+ if( trap_Argc() > 1 )
+ {
+ trap_Argv( 1, arg, sizeof( arg ) );
+ damage = atoi( arg );
+ }
+ if( trap_Argc() > 4 )
+ {
+ trap_Argv( 2, arg, sizeof( arg ) );
+ dx = atof( arg );
+ trap_Argv( 3, arg, sizeof( arg ) );
+ dy = atof( arg );
+ trap_Argv( 4, arg, sizeof( arg ) );
+ dz = atof( arg );
+ nonloc = qfalse;
+ }
+ VectorCopy( ent->r.currentOrigin, point );
+ point[ 0 ] += dx;
+ point[ 1 ] += dy;
+ point[ 2 ] += dz;
+ G_Damage( ent, NULL, NULL, NULL, point, damage,
+ ( nonloc ? DAMAGE_NO_LOCDAMAGE : 0 ), MOD_TARGET_LASER );
+}
+
+/*
+==================
+G_FloodLimited
+
+Determine whether a user is flood limited, and adjust their flood demerits
+Print them a warning message if they are over the limit
+Return is time in msec until the user can speak again
+==================
+*/
+int G_FloodLimited( gentity_t *ent )
+{
+ int deltatime, ms;
- // communication commands
- { "tell", CMD_MESSAGE, Cmd_Tell_f },
+ if( g_floodMinTime.integer <= 0 )
+ return 0;
+
+ // handles !ent
+ if( G_admin_permission( ent, ADMF_NOCENSORFLOOD ) )
+ return 0;
+
+ deltatime = level.time - ent->client->pers.floodTime;
+
+ ent->client->pers.floodDemerits += g_floodMinTime.integer - deltatime;
+ if( ent->client->pers.floodDemerits < 0 )
+ ent->client->pers.floodDemerits = 0;
+ ent->client->pers.floodTime = level.time;
+
+ ms = ent->client->pers.floodDemerits - g_floodMaxDemerits.integer;
+ if( ms <= 0 )
+ return 0;
+ trap_SendServerCommand( ent - g_entities, va( "print \"You are flooding: "
+ "please wait %d second%s before trying again\n",
+ ( ms + 999 ) / 1000, ( ms > 1000 ) ? "s" : "" ) );
+ return ms;
+}
+
+commands_t cmds[ ] = {
+ { "a", CMD_MESSAGE|CMD_INTERMISSION, Cmd_AdminMessage_f },
+ { "build", CMD_TEAM|CMD_ALIVE, Cmd_Build_f },
+ { "buy", CMD_HUMAN|CMD_ALIVE, Cmd_Buy_f },
+ { "callteamvote", CMD_MESSAGE|CMD_TEAM, Cmd_CallVote_f },
{ "callvote", CMD_MESSAGE, Cmd_CallVote_f },
- { "callteamvote", CMD_MESSAGE|CMD_TEAM, Cmd_CallTeamVote_f },
- { "say_area", CMD_MESSAGE|CMD_TEAM, Cmd_SayArea_f },
- // can be used even during intermission
+ { "class", CMD_TEAM, Cmd_Class_f },
+ { "damage", CMD_CHEAT|CMD_ALIVE, Cmd_Damage_f },
+ { "deconstruct", CMD_TEAM|CMD_ALIVE, Cmd_Destroy_f },
+ { "destroy", CMD_CHEAT|CMD_TEAM|CMD_ALIVE, Cmd_Destroy_f },
+ { "drop", CMD_HUMAN|CMD_CHEAT, Cmd_Drop_f },
+ { "follow", CMD_SPEC, Cmd_Follow_f },
+ { "follownext", CMD_SPEC, Cmd_FollowCycle_f },
+ { "followprev", CMD_SPEC, Cmd_FollowCycle_f },
+ { "give", CMD_CHEAT|CMD_TEAM, Cmd_Give_f },
+ { "god", CMD_CHEAT, Cmd_God_f },
+ { "ignore", 0, Cmd_Ignore_f },
+ { "itemact", CMD_HUMAN|CMD_ALIVE, Cmd_ActivateItem_f },
+ { "itemdeact", CMD_HUMAN|CMD_ALIVE, Cmd_DeActivateItem_f },
+ { "itemtoggle", CMD_HUMAN|CMD_ALIVE, Cmd_ToggleItem_f },
+ { "kill", CMD_TEAM|CMD_ALIVE, Cmd_Kill_f },
+ { "listmaps", CMD_MESSAGE|CMD_INTERMISSION, Cmd_ListMaps_f },
+ { "listmodels", CMD_MESSAGE|CMD_INTERMISSION, Cmd_ListModels_f },
+ { "listskins", CMD_MESSAGE|CMD_INTERMISSION, Cmd_ListSkins_f },
+ { "listvoices", CMD_MESSAGE|CMD_INTERMISSION, Cmd_ListVoices_f },
+ { "m", CMD_MESSAGE|CMD_INTERMISSION, Cmd_PrivateMessage_f },
+ { "mt", CMD_MESSAGE|CMD_INTERMISSION, Cmd_PrivateMessage_f },
+ { "noclip", CMD_CHEAT_TEAM, Cmd_Noclip_f },
+ { "notarget", CMD_CHEAT|CMD_TEAM|CMD_ALIVE, Cmd_Notarget_f },
+ { "reload", CMD_HUMAN|CMD_ALIVE, Cmd_Reload_f },
{ "say", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
+ { "say_area", CMD_MESSAGE|CMD_TEAM|CMD_ALIVE, Cmd_SayArea_f },
{ "say_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
- { "say_admins", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
- { "say_hadmins", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
- { "a", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
- { "ha", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
- { "m", CMD_MESSAGE|CMD_INTERMISSION, G_PrivateMessage },
- { "mt", CMD_MESSAGE|CMD_INTERMISSION, G_PrivateMessage },
- { "me", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
- { "me_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
-
{ "score", CMD_INTERMISSION, ScoreboardMessage },
- { "mystats", CMD_TEAM|CMD_INTERMISSION, Cmd_MyStats_f },
- { "allstats", 0|CMD_INTERMISSION, Cmd_AllStats_f },
- { "teamstatus", CMD_TEAM, Cmd_TeamStatus_f },
-
- // cheats
- { "give", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_Give_f },
- { "god", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_God_f },
- { "notarget", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_Notarget_f },
- { "noclip", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_Noclip_f },
- { "levelshot", CMD_CHEAT, Cmd_LevelShot_f },
- { "setviewpos", CMD_CHEAT, Cmd_SetViewpos_f },
- { "destroy", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_Destroy_f },
-
- { "kill", CMD_TEAM|CMD_LIVING, Cmd_Kill_f },
-
- // game commands
- { "ptrcverify", CMD_NOTEAM, Cmd_PTRCVerify_f },
- { "ptrcrestore", CMD_NOTEAM, Cmd_PTRCRestore_f },
-
- { "follow", 0, Cmd_Follow_f },
- { "follownext", 0, Cmd_FollowCycle_f },
- { "followprev", 0, Cmd_FollowCycle_f },
-
- { "where", CMD_TEAM, Cmd_Where_f },
- { "teamvote", CMD_TEAM, Cmd_TeamVote_f },
- { "class", CMD_TEAM, Cmd_Class_f },
-
- { "build", CMD_TEAM|CMD_LIVING, Cmd_Build_f },
- { "deconstruct", CMD_TEAM|CMD_LIVING, Cmd_Destroy_f },
- { "mark", CMD_TEAM|CMD_LIVING, Cmd_Mark_f },
-
- { "buy", CMD_HUMAN|CMD_LIVING, Cmd_Buy_f },
- { "sell", CMD_HUMAN|CMD_LIVING, Cmd_Sell_f },
- { "itemact", CMD_HUMAN|CMD_LIVING, Cmd_ActivateItem_f },
- { "itemdeact", CMD_HUMAN|CMD_LIVING, Cmd_DeActivateItem_f },
- { "itemtoggle", CMD_HUMAN|CMD_LIVING, Cmd_ToggleItem_f },
- { "reload", CMD_TEAM|CMD_LIVING, Cmd_Reload_f },
- { "boost", 0, Cmd_Boost_f },
- { "share", CMD_TEAM, Cmd_Share_f },
- { "donate", CMD_TEAM, Cmd_Donate_f },
- { "protect", CMD_TEAM|CMD_LIVING, Cmd_Protect_f },
- { "resign", CMD_TEAM, Cmd_Resign_f },
- { "builder", 0, Cmd_Builder_f }
+ { "sell", CMD_HUMAN|CMD_ALIVE, Cmd_Sell_f },
+ { "setviewpos", CMD_CHEAT_TEAM, Cmd_SetViewpos_f },
+ { "team", 0, Cmd_Team_f },
+ { "teamvote", CMD_TEAM, Cmd_Vote_f },
+ { "test", CMD_CHEAT, Cmd_Test_f },
+ { "unignore", 0, Cmd_Ignore_f },
+ { "vote", 0, Cmd_Vote_f },
+ { "vsay", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VSay_f },
+ { "vsay_local", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VSay_f },
+ { "vsay_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VSay_f },
+ { "where", 0, Cmd_Where_f }
};
-static int numCmds = sizeof( cmds ) / sizeof( cmds[ 0 ] );
+static size_t numCmds = ARRAY_LEN( cmds );
/*
=================
@@ -5156,25 +3476,21 @@ ClientCommand
*/
void ClientCommand( int clientNum )
{
- gentity_t *ent;
- char cmd[ MAX_TOKEN_CHARS ];
- int i;
+ gentity_t *ent;
+ char cmd[ MAX_TOKEN_CHARS ];
+ commands_t *command;
ent = g_entities + clientNum;
- if( !ent->client )
+ if( !ent->client || ent->client->pers.connected != CON_CONNECTED )
return; // not fully in game yet
trap_Argv( 0, cmd, sizeof( cmd ) );
- for( i = 0; i < numCmds; i++ )
- {
- if( Q_stricmp( cmd, cmds[ i ].cmdName ) == 0 )
- break;
- }
+ command = bsearch( cmd, cmds, numCmds, sizeof( cmds[ 0 ] ), cmdcmp );
- if( i == numCmds )
+ if( !command )
{
- if( !G_admin_cmd_check( ent, qfalse ) )
+ if( !G_admin_cmd_check( ent ) )
trap_SendServerCommand( clientNum,
va( "print \"Unknown command %s\n\"", cmd ) );
return;
@@ -5182,622 +3498,232 @@ void ClientCommand( int clientNum )
// do tests here to reduce the amount of repeated code
- if( !( cmds[ i ].cmdFlags & CMD_INTERMISSION ) && ( level.intermissiontime || level.paused ) )
+ if( !( command->cmdFlags & CMD_INTERMISSION ) &&
+ ( level.intermissiontime || level.pausedTime ) )
return;
- if( cmds[ i ].cmdFlags & CMD_CHEAT && !g_cheats.integer )
+ if( command->cmdFlags & CMD_CHEAT && !g_cheats.integer )
{
- trap_SendServerCommand( clientNum,
- "print \"Cheats are not enabled on this server\n\"" );
+ G_TriggerMenu( clientNum, MN_CMD_CHEAT );
return;
}
- if( cmds[ i ].cmdFlags & CMD_MESSAGE && G_IsMuted( ent->client ) )
- {
- trap_SendServerCommand( clientNum,
- "print \"You are muted and cannot use message commands.\n\"" );
+ if( command->cmdFlags & CMD_MESSAGE && ( ent->client->pers.namelog->muted ||
+ G_FloodLimited( ent ) ) )
return;
- }
- if( cmds[ i ].cmdFlags & CMD_TEAM &&
- ent->client->pers.teamSelection == PTE_NONE )
+ if( command->cmdFlags & CMD_TEAM &&
+ ent->client->pers.teamSelection == TEAM_NONE )
{
- trap_SendServerCommand( clientNum, "print \"Join a team first\n\"" );
+ G_TriggerMenu( clientNum, MN_CMD_TEAM );
return;
}
- if( cmds[ i ].cmdFlags & CMD_NOTEAM &&
- ent->client->pers.teamSelection != PTE_NONE )
+ if( command->cmdFlags & CMD_CHEAT_TEAM && !g_cheats.integer &&
+ ent->client->pers.teamSelection != TEAM_NONE )
{
- trap_SendServerCommand( clientNum,
- "print \"Cannot use this command when on a team\n\"" );
+ G_TriggerMenu( clientNum, MN_CMD_CHEAT_TEAM );
return;
}
- if( cmds[ i ].cmdFlags & CMD_ALIEN &&
- ent->client->pers.teamSelection != PTE_ALIENS )
+ if( command->cmdFlags & CMD_SPEC &&
+ ent->client->sess.spectatorState == SPECTATOR_NOT )
{
- trap_SendServerCommand( clientNum,
- "print \"Must be alien to use this command\n\"" );
+ G_TriggerMenu( clientNum, MN_CMD_SPEC );
return;
}
- if( cmds[ i ].cmdFlags & CMD_HUMAN &&
- ent->client->pers.teamSelection != PTE_HUMANS )
+ if( command->cmdFlags & CMD_ALIEN &&
+ ent->client->pers.teamSelection != TEAM_ALIENS )
{
- trap_SendServerCommand( clientNum,
- "print \"Must be human to use this command\n\"" );
+ G_TriggerMenu( clientNum, MN_CMD_ALIEN );
return;
}
- if( cmds[ i ].cmdFlags & CMD_LIVING &&
- ( ent->client->ps.stats[ STAT_HEALTH ] <= 0 ||
- ent->client->sess.sessionTeam == TEAM_SPECTATOR ) )
+ if( command->cmdFlags & CMD_HUMAN &&
+ ent->client->pers.teamSelection != TEAM_HUMANS )
{
- trap_SendServerCommand( clientNum,
- "print \"Must be living to use this command\n\"" );
+ G_TriggerMenu( clientNum, MN_CMD_HUMAN );
return;
}
- // Disallow a large class of commands if a player is restricted.
- if( G_admin_is_restricted( ent, qtrue ) &&
- ( !Q_stricmp( cmd, "team" ) ||
- ( cmds[ i ].cmdFlags & ( CMD_MESSAGE | CMD_TEAM | CMD_NOTEAM ) ) ) )
+ if( command->cmdFlags & CMD_ALIVE &&
+ ( ent->client->ps.stats[ STAT_HEALTH ] <= 0 ||
+ ent->client->sess.spectatorState != SPECTATOR_NOT ) )
{
+ G_TriggerMenu( clientNum, MN_CMD_ALIVE );
return;
}
- cmds[ i ].cmdHandler( ent );
+ command->cmdHandler( ent );
}
-int G_SayArgc( void )
+void G_ListCommands( gentity_t *ent )
{
- int c = 0;
- char *s;
+ int i;
+ char out[ MAX_STRING_CHARS ] = "";
+ int len, outlen;
- s = ConcatArgs( 0 );
- while( 1 )
+ outlen = 0;
+
+ for( i = 0; i < numCmds; i++ )
{
- while( *s == ' ' )
- s++;
- if( !*s )
- break;
- c++;
- while( *s && *s != ' ' )
- s++;
- }
- return c;
-}
+ // never advertise cheats
+ if( cmds[ i ].cmdFlags & CMD_CHEAT )
+ continue;
-qboolean G_SayArgv( int n, char *buffer, int bufferLength )
-{
- int bc = 0;
- int c = 0;
- char *s;
+ len = strlen( cmds[ i ].cmdName ) + 1;
+ if( len + outlen >= sizeof( out ) - 1 )
+ {
+ trap_SendServerCommand( ent - g_entities, va( "cmds%s\n", out ) );
+ outlen = 0;
+ }
- if( bufferLength < 1 )
- return qfalse;
- if( n < 0 )
- return qfalse;
- s = ConcatArgs( 0 );
- while( c < n )
- {
- while( *s == ' ' )
- s++;
- if( !*s )
- break;
- c++;
- while( *s && *s != ' ' )
- s++;
+ strcpy( out + outlen, va( " %s", cmds[ i ].cmdName ) );
+ outlen += len;
}
- if( c < n )
- return qfalse;
- while( *s == ' ' )
- s++;
- if( !*s )
- return qfalse;
- //memccpy( buffer, s, ' ', bufferLength );
- while( bc < bufferLength - 1 && *s && *s != ' ' )
- buffer[ bc++ ] = *s++;
- buffer[ bc ] = 0;
- return qtrue;
+
+ trap_SendServerCommand( ent - g_entities, va( "cmds%s\n", out ) );
+ G_admin_cmdlist( ent );
}
-char *G_SayConcatArgs( int start )
+void G_DecolorString( const char *in, char *out, int len )
{
- char *s;
- int c = 0;
+ qboolean decolor = qtrue;
- s = ConcatArgs( 0 );
- while( c < start )
- {
- while( *s == ' ' )
- s++;
- if( !*s )
- break;
- c++;
- while( *s && *s != ' ' )
- s++;
- }
- while( *s == ' ' )
- s++;
- return s;
-}
+ len--;
-void G_DecolorString( char *in, char *out )
-{
- while( *in ) {
- if( *in == 27 || *in == '^' ) {
+ while( *in && len > 0 ) {
+ if( *in == DECOLOR_OFF || *in == DECOLOR_ON )
+ {
+ decolor = ( *in == DECOLOR_ON );
in++;
- if( *in )
- in++;
+ continue;
+ }
+ if( Q_IsColorString( in ) && decolor ) {
+ in += 2;
continue;
}
*out++ = *in++;
+ len--;
}
*out = '\0';
}
-void G_ParseEscapedString( char *buffer )
+void G_UnEscapeString( char *in, char *out, int len )
{
- int i = 0;
- int j = 0;
+ len--;
- while( buffer[i] )
+ while( *in && len > 0 )
{
- if(!buffer[i]) break;
-
- if(buffer[i] == '\\')
+ if( *in >= ' ' || *in == '\n' )
{
- if(buffer[i + 1] == '\\')
- buffer[j] = buffer[++i];
- else if(buffer[i + 1] == 'n')
- {
- buffer[j] = '\n';
- i++;
- }
- else
- buffer[j] = buffer[i];
+ *out++ = *in;
+ len--;
}
- else
- buffer[j] = buffer[i];
-
- i++;
- j++;
+ in++;
}
- buffer[j] = 0;
-}
-
-void G_WordWrap( char *buffer, int maxwidth )
-{
- char out[ MAX_STRING_CHARS ];
- int i = 0;
- int j = 0;
- int k;
- int linecount = 0;
- int currentcolor = 7;
-
- while ( buffer[ j ]!='\0' )
- {
- if( i == ( MAX_STRING_CHARS - 1 ) )
- break;
-
- //If it's the start of a new line, copy over the color code,
- //but not if we already did it, or if the text at the start of the next line is also a color code
- if( linecount == 0 && i>2 && out[ i-2 ] != Q_COLOR_ESCAPE && out[ i-1 ] != Q_COLOR_ESCAPE )
- {
- out[ i ] = Q_COLOR_ESCAPE;
- out[ i + 1 ] = '0' + currentcolor;
- i+=2;
- continue;
- }
-
- if( linecount < maxwidth )
- {
- out[ i ] = buffer[ j ];
- if( out[ i ] == '\n' )
- {
- linecount = 0;
- }
- else if( Q_IsColorString( &buffer[j] ) )
- {
- currentcolor = buffer[j+1] - '0';
- }
- else
- linecount++;
-
- //If we're at a space and getting close to a line break, look ahead and make sure that there isn't already a \n or a closer space coming. If not, break here.
- if( out[ i ] == ' ' && linecount >= (maxwidth - 10 ) )
- {
- qboolean foundbreak = qfalse;
- for( k = i+1; k < maxwidth; k++ )
- {
- if( !buffer[ k ] )
- continue;
- if( buffer[ k ] == '\n' || buffer[ k ] == ' ' )
- foundbreak = qtrue;
- }
- if( !foundbreak )
- {
- out [ i ] = '\n';
- linecount = 0;
- }
- }
-
- i++;
- j++;
- }
- else
- {
- out[ i ] = '\n';
- i++;
- linecount = 0;
- }
- }
- out[ i ] = '\0';
-
-
- strcpy( buffer, out );
+ *out = '\0';
}
-void G_PrivateMessage( gentity_t *ent )
+void Cmd_PrivateMessage_f( gentity_t *ent )
{
int pids[ MAX_CLIENTS ];
- int ignoreids[ MAX_CLIENTS ];
char name[ MAX_NAME_LENGTH ];
char cmd[ 12 ];
- char str[ MAX_STRING_CHARS ];
+ char text[ MAX_STRING_CHARS ];
char *msg;
char color;
- int pcount, matches, ignored = 0;
- int i;
- int skipargs = 0;
+ int i, pcount;
+ int count = 0;
qboolean teamonly = qfalse;
- gentity_t *tmpent;
+ char recipients[ MAX_STRING_CHARS ] = "";
if( !g_privateMessages.integer && ent )
{
ADMP( "Sorry, but private messages have been disabled\n" );
return;
}
-
- if( g_floodMinTime.integer )
- if ( G_Flood_Limited( ent ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Your chat is flood-limited; wait before chatting again\n\"" );
- return;
- }
- G_SayArgv( 0, cmd, sizeof( cmd ) );
- if( !Q_stricmp( cmd, "say" ) || !Q_stricmp( cmd, "say_team" ) )
- {
- skipargs = 1;
- G_SayArgv( 1, cmd, sizeof( cmd ) );
- }
- if( G_SayArgc( ) < 3+skipargs )
+ trap_Argv( 0, cmd, sizeof( cmd ) );
+ if( trap_Argc( ) < 3 )
{
ADMP( va( "usage: %s [name|slot#] [message]\n", cmd ) );
return;
}
- if( !Q_stricmp( cmd, "mt" ) || !Q_stricmp( cmd, "/mt" ) )
+ if( !Q_stricmp( cmd, "mt" ) )
teamonly = qtrue;
- G_SayArgv( 1+skipargs, name, sizeof( name ) );
- msg = G_SayConcatArgs( 2+skipargs );
- pcount = G_ClientNumbersFromString( name, pids );
+ trap_Argv( 1, name, sizeof( name ) );
+ msg = ConcatArgs( 2 );
+ pcount = G_ClientNumbersFromString( name, pids, MAX_CLIENTS );
- if( ent )
- {
- int count = 0;
+ G_CensorString( text, msg, sizeof( text ), ent );
- for( i=0; i < pcount; i++ )
+ // send the message
+ for( i = 0; i < pcount; i++ )
+ {
+ if( G_SayTo( ent, &g_entities[ pids[ i ] ],
+ teamonly ? SAY_TPRIVMSG : SAY_PRIVMSG, text ) )
{
- tmpent = &g_entities[ pids[ i ] ];
-
- if( teamonly && !OnSameTeam( ent, tmpent ) )
- continue;
-
- // Ignore sending to invisible players
- if( tmpent->client->sess.invisible == qtrue && !G_admin_permission( ent, "invisible" ) )
- continue;
-
- // Ignore sending to non-invisible-capable players while invisible
- if( ent->client->sess.invisible == qtrue && !G_admin_permission( tmpent, "invisible" ) )
- continue;
-
- if( BG_ClientListTest( &tmpent->client->sess.ignoreList,
- ent-g_entities ) )
- {
- ignoreids[ ignored++ ] = pids[ i ];
- continue;
- }
-
- pids[ count ] = pids[ i ];
count++;
+ Q_strcat( recipients, sizeof( recipients ), va( "%s" S_COLOR_WHITE ", ",
+ level.clients[ pids[ i ] ].pers.netname ) );
}
- matches = count;
- }
- else
- {
- matches = pcount;
}
+ // report the results
color = teamonly ? COLOR_CYAN : COLOR_YELLOW;
- if( !Q_stricmp( name, "console" ) )
- {
- ADMP( va( "^%cPrivate message: ^7%s\n", color, msg ) );
- ADMP( va( "^%csent to Console.\n", color ) );
-
- G_LogPrintf( "privmsg: %s^7: Console: ^6%s^7\n",
- ( ent ) ? ent->client->pers.netname : "Console", msg );
-
- return;
- }
-
- Q_strncpyz( str,
- va( "^%csent to %i player%s: ^7", color, matches,
- ( matches == 1 ) ? "" : "s" ),
- sizeof( str ) );
-
- for( i=0; i < matches; i++ )
- {
- tmpent = &g_entities[ pids[ i ] ];
-
- if( i > 0 )
- Q_strcat( str, sizeof( str ), "^7, " );
- Q_strcat( str, sizeof( str ), tmpent->client->pers.netname );
- trap_SendServerCommand( pids[ i ], va(
- "chat \"%s^%c -> ^7%s^7: (%d recipients): ^%c%s^7\" %i",
- ( ent ) ? ent->client->pers.netname : "console",
- color,
- name,
- matches,
- color,
- msg,
- ent ? ent-g_entities : -1 ) );
-
- trap_SendServerCommand( pids[ i ], va(
- "cp \"^%cprivate message from ^7%s^7\"", color,
- ( ent ) ? ent->client->pers.netname : "console" ) );
- }
-
- if( !matches )
+ if( !count )
ADMP( va( "^3No player matching ^7\'%s^7\' ^3to send message to.\n",
name ) );
else
{
- if( ent )
- ADMP( va( "^%cPrivate message: ^7%s\n", color, msg ) );
+ ADMP( va( "^%cPrivate message: ^7%s\n", color, text ) );
+ // remove trailing ", "
+ recipients[ strlen( recipients ) - 2 ] = '\0';
+ ADMP( va( "^%csent to %i player%s: " S_COLOR_WHITE "%s\n", color, count,
+ count == 1 ? "" : "s", recipients ) );
- ADMP( va( "%s\n", str ) );
-
- G_LogPrintf( "%s: %s^7: %s^7: %s\n",
- ( teamonly ) ? "tprivmsg" : "privmsg",
+ G_LogPrintf( "%s: %d \"%s" S_COLOR_WHITE "\" \"%s\": ^%c%s\n",
+ ( teamonly ) ? "TPrivMsg" : "PrivMsg",
+ (int)( ( ent ) ? ent - g_entities : -1 ),
( ent ) ? ent->client->pers.netname : "console",
- name, msg );
+ name, color, msg );
}
-
- if( ignored )
- {
- Q_strncpyz( str, va( "^%cignored by %i player%s: ^7", color, ignored,
- ( ignored == 1 ) ? "" : "s" ), sizeof( str ) );
- for( i=0; i < ignored; i++ )
- {
- tmpent = &g_entities[ ignoreids[ i ] ];
- if( i > 0 )
- Q_strcat( str, sizeof( str ), "^7, " );
- Q_strcat( str, sizeof( str ), tmpent->client->pers.netname );
- }
- ADMP( va( "%s\n", str ) );
- }
-}
-
- /*
- =================
- Cmd_Builder_f
- =================
- */
- void Cmd_Builder_f( gentity_t *ent )
- {
- vec3_t forward, right, up;
- vec3_t start, end;
- trace_t tr;
- gentity_t *traceEnt;
- char bdnumbchr[21];
-
- AngleVectors( ent->client->ps.viewangles, forward, right, up );
- if( ent->client->pers.teamSelection != PTE_NONE )
- CalcMuzzlePoint( ent, forward, right, up, start );
- else
- VectorCopy( ent->client->ps.origin, start );
- VectorMA( start, 1000, forward, end );
-
- trap_Trace( &tr, start, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
- traceEnt = &g_entities[ tr.entityNum ];
-
- Com_sprintf( bdnumbchr, sizeof(bdnumbchr), "%i", traceEnt->bdnumb );
-
- if( tr.fraction < 1.0f && ( traceEnt->s.eType == ET_BUILDABLE ) )
- {
- if( G_admin_permission( ent, "buildlog" ) ) {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"^5/builder:^7 ^3Building:^7 %s ^3Built By:^7 %s^7 ^3Buildlog Number:^7 %s^7\n\"",
- BG_FindHumanNameForBuildable( traceEnt->s.modelindex ),
- (traceEnt->bdnumb != -1) ? G_FindBuildLogName( traceEnt->bdnumb ) : "<world>",
- (traceEnt->bdnumb != -1) ? bdnumbchr : "none" ) );
- }
- else
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"^5/builder:^7 ^3Building:^7 %s ^3Built By:^7 %s^7\n\"",
- BG_FindHumanNameForBuildable( traceEnt->s.modelindex ),
- (traceEnt->bdnumb != -1) ? G_FindBuildLogName( traceEnt->bdnumb ) : "<world>" ) );
- }
- }
- else
- {
- trap_SendServerCommand( ent-g_entities, "print \"^5/builder:^7 No structure found in your crosshair. Please face a structure and try again.\n\"" );
- }
- }
-
-void G_CP( gentity_t *ent )
-{
- int i;
- char buffer[MAX_STRING_CHARS];
- char prefixes[MAX_STRING_CHARS] = "";
- char wrappedtext[ MAX_STRING_CHARS ] = "";
- char *ptr;
- char *text;
- qboolean sendAliens = qtrue;
- qboolean sendHumans = qtrue;
- qboolean sendSpecs = qtrue;
- Q_strncpyz( buffer, ConcatArgs( 1 ), sizeof( buffer ) );
- G_ParseEscapedString( buffer );
-
- if( strstr( buffer, "!cp" ) )
- {
- ptr = buffer;
- while( *ptr != '!' )
- ptr++;
- ptr+=4;
-
- Q_strncpyz( buffer, ptr, sizeof(buffer) );
- }
-
- text = buffer;
-
- ptr = buffer;
- while( *ptr == ' ' )
- ptr++;
- if( *ptr == '-' )
- {
- sendAliens = qfalse;
- sendHumans = qfalse;
- sendSpecs = qfalse;
- Q_strcat( prefixes, sizeof( prefixes ), " " );
- ptr++;
-
- while( *ptr && *ptr != ' ' )
- {
- if( !sendAliens && ( *ptr == 'a' || *ptr == 'A' ) )
- {
- sendAliens = qtrue;
- Q_strcat( prefixes, sizeof( prefixes ), "[^1A^7]" );
- }
- if( !sendHumans && ( *ptr == 'h' || *ptr == 'H' ) )
- {
- sendHumans = qtrue;
- Q_strcat( prefixes, sizeof( prefixes ), "[^4H^7]" );
- }
- if( !sendSpecs && ( *ptr == 's' || *ptr == 'S' ) )
- {
- sendSpecs = qtrue;
- Q_strcat( prefixes, sizeof( prefixes ), "[^3S^7]" );
- }
- ptr++;
- }
- if( *ptr ) text = ptr+1;
- else text = ptr;
- }
-
- strcpy( wrappedtext, text );
-
- if( strlen( text ) == 0 ) return;
-
- G_WordWrap( wrappedtext, 50 );
-
- for( i = 0; i < level.maxclients; i++ )
- {
- if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
- continue;
-
- if( ( !sendAliens && level.clients[ i ].pers.teamSelection == PTE_ALIENS ) ||
- ( !sendHumans && level.clients[ i ].pers.teamSelection == PTE_HUMANS ) ||
- ( !sendSpecs && level.clients[ i ].pers.teamSelection == PTE_NONE ) )
- {
- if( G_admin_permission( &g_entities[ i ], ADMF_ADMINCHAT ) )
- {
- trap_SendServerCommand( i, va("print \"^6[Admins]^7 CP to other team%s: %s \n\"", prefixes, text ) );
- }
- continue;
- }
-
- trap_SendServerCommand( i, va( "cp \"%s\"", wrappedtext ) );
- trap_SendServerCommand( i, va( "print \"%s^7 CP%s: %s\n\"", ( ent ? G_admin_adminPrintName( ent ) : "console" ), prefixes, text ) );
- }
-
- G_Printf( "cp: %s\n", ConcatArgs( 1 ) );
}
/*
=================
-G_IsMuted
+Cmd_AdminMessage_f
-Check if a player is muted
+Send a message to all active admins
=================
*/
-qboolean G_IsMuted( gclient_t *client )
+void Cmd_AdminMessage_f( gentity_t *ent )
{
- qboolean muteState = qfalse;
-
- //check if mute has expired
- if( client->pers.muteExpires ) {
- if( client->pers.muteExpires < level.time )
+ // Check permissions and add the appropriate user [prefix]
+ if( !G_admin_permission( ent, ADMF_ADMINCHAT ) )
+ {
+ if( !g_publicAdminMessages.integer )
+ {
+ ADMP( "Sorry, but use of /a by non-admins has been disabled.\n" );
+ return;
+ }
+ else
{
- client->pers.muted = qfalse;
- client->pers.muteExpires = 0;
+ ADMP( "Your message has been sent to any available admins "
+ "and to the server logs.\n" );
}
}
- if( client->pers.muted )
- muteState = qtrue;
-
- return muteState;
-}
-
-/*
-==================
-G_TeamKill_Repent
-
-Determine whether a players team kill activity is high
-==================
-*/
-
-qboolean G_TeamKill_Repent( gentity_t *ent )
-{
- int millisSinceLastTeamKill;
-
- // Doesn't work if g_teamKillThreshold isn't set
- if( !g_teamKillThreshold.integer ||
- g_teamKillThreshold.integer == 0 )
- return qfalse;
-
- // Doesn't work when game is paused
- if( level.paused )
- return qfalse;
-
- millisSinceLastTeamKill = level.time - ent->client->pers.lastTeamKillTime;
- if( millisSinceLastTeamKill < 30000 )
- ent->client->pers.teamKillDemerits++;
- else
+ if( trap_Argc( ) < 2 )
{
- ent->client->pers.teamKillDemerits--;
- if( ent->client->pers.teamKillDemerits < 0 )
- ent->client->pers.teamKillDemerits = 0;
+ ADMP( "usage: a [message]\n" );
+ return;
}
- ent->client->pers.lastTeamKillTime = level.time;
-
- if ( ent->client->pers.teamKillDemerits >= ( g_teamKillThreshold.integer + 2 ) )
- trap_SendConsoleCommand( 0, va( "!ban %s 30m team killing\n", ent->client->pers.ip ) );
- else if ( ent->client->pers.teamKillDemerits == ( g_teamKillThreshold.integer + 1 ) )
- trap_SendConsoleCommand( 0, va( "!warn %i team killing\n", ent->client->ps.clientNum ) );
- else if ( ent->client->pers.teamKillDemerits == g_teamKillThreshold.integer )
- G_AdminsPrintf( "Team killer %s^7 has team killed ^6%i^7 times.\n",
- ent->client->pers.netname,
- ent->client->pers.statscounters.teamkills );
-
- return qfalse;
+ G_AdminMessage( ent, ConcatArgs( 1 ) );
}
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index 5350895..cb15147 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,24 +17,24 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
#include "g_local.h"
-damageRegion_t g_damageRegions[ PCL_NUM_CLASSES ][ MAX_LOCDAMAGE_REGIONS ];
+damageRegion_t g_damageRegions[ PCL_NUM_CLASSES ][ MAX_DAMAGE_REGIONS ];
int g_numDamageRegions[ PCL_NUM_CLASSES ];
-armourRegion_t g_armourRegions[ UP_NUM_UPGRADES ][ MAX_ARMOUR_REGIONS ];
+damageRegion_t g_armourRegions[ UP_NUM_UPGRADES ][ MAX_DAMAGE_REGIONS ];
int g_numArmourRegions[ UP_NUM_UPGRADES ];
/*
============
AddScore
-Adds score to both the client and his team
+Adds score to the client
============
*/
void AddScore( gentity_t *ent, int score )
@@ -41,6 +42,15 @@ void AddScore( gentity_t *ent, int score )
if( !ent->client )
return;
+ // make alien and human scores equivalent
+ if ( ent->client->pers.teamSelection == TEAM_ALIENS )
+ {
+ score = rint( ((float)score) / 2.0f );
+ }
+
+ // scale values down to fit the scoreboard better
+ score = rint( ((float)score) / 50.0f );
+
ent->client->ps.persistant[ PERS_SCORE ] += score;
CalculateRanks( );
}
@@ -52,19 +62,13 @@ LookAtKiller
*/
void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker )
{
- vec3_t dir;
if ( attacker && attacker != self )
- VectorSubtract( attacker->s.pos.trBase, self->s.pos.trBase, dir );
+ self->client->ps.stats[ STAT_VIEWLOCK ] = attacker - g_entities;
else if( inflictor && inflictor != self )
- VectorSubtract( inflictor->s.pos.trBase, self->s.pos.trBase, dir );
+ self->client->ps.stats[ STAT_VIEWLOCK ] = inflictor - g_entities;
else
- {
- self->client->ps.stats[ STAT_VIEWLOCK ] = self->s.angles[ YAW ];
- return;
- }
-
- self->client->ps.stats[ STAT_VIEWLOCK ] = vectoyaw( dir );
+ self->client->ps.stats[ STAT_VIEWLOCK ] = self - g_entities;
}
// these are just for logging, the client prints its own messages
@@ -104,7 +108,8 @@ char *modNames[ ] =
"MOD_LEVEL2_CLAW",
"MOD_LEVEL2_ZAP",
"MOD_LEVEL4_CLAW",
- "MOD_LEVEL4_CHARGE",
+ "MOD_LEVEL4_TRAMPLE",
+ "MOD_LEVEL4_CRUSH",
"MOD_SLOWBLOB",
"MOD_POISON",
@@ -118,11 +123,112 @@ char *modNames[ ] =
"MOD_ASPAWN",
"MOD_ATUBE",
"MOD_OVERMIND",
- "MOD_SLAP"
+ "MOD_DECONSTRUCT",
+ "MOD_REPLACE",
+ "MOD_NOCREEP"
};
/*
==================
+G_RewardAttackers
+
+Function to distribute rewards to entities that killed this one.
+Returns the total damage dealt.
+==================
+*/
+float G_RewardAttackers( gentity_t *self )
+{
+ float value, totalDamage = 0;
+ int team, i, maxHealth = 0;
+ int alienCredits = 0, humanCredits = 0;
+ gentity_t *player;
+
+ // Total up all the damage done by non-teammates
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ player = g_entities + i;
+
+ if( !OnSameTeam( self, player ) ||
+ self->buildableTeam != player->client->ps.stats[ STAT_TEAM ] )
+ totalDamage += (float)self->credits[ i ];
+ }
+
+ if( totalDamage <= 0.0f )
+ return 0.0f;
+
+ // Only give credits for killing players and buildables
+ if( self->client )
+ {
+ value = BG_GetValueOfPlayer( &self->client->ps );
+ team = self->client->pers.teamSelection;
+ maxHealth = self->client->ps.stats[ STAT_MAX_HEALTH ];
+ }
+ else if( self->s.eType == ET_BUILDABLE )
+ {
+ value = BG_Buildable( self->s.modelindex )->value;
+
+ // only give partial credits for a buildable not yet completed
+ if( !self->spawned )
+ {
+ value *= (float)( level.time - self->buildTime ) /
+ BG_Buildable( self->s.modelindex )->buildTime;
+ }
+
+ team = self->buildableTeam;
+ maxHealth = BG_Buildable( self->s.modelindex )->health;
+ }
+ else
+ return totalDamage;
+
+ // Give credits and empty the array
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ int stageValue = value * self->credits[ i ] / totalDamage;
+ player = g_entities + i;
+
+ if( player->client->pers.teamSelection != team )
+ {
+ if( totalDamage < maxHealth )
+ stageValue *= totalDamage / maxHealth;
+
+ if( !self->credits[ i ] || player->client->ps.stats[ STAT_TEAM ] == team )
+ continue;
+
+ AddScore( player, stageValue );
+
+ // killing buildables earns score, but not credits
+ if( self->s.eType != ET_BUILDABLE )
+ {
+ G_AddCreditToClient( player->client, stageValue, qtrue );
+
+ // add to stage counters
+ if( player->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ alienCredits += stageValue;
+ else if( player->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ humanCredits += stageValue;
+ }
+ }
+ self->credits[ i ] = 0;
+ }
+
+ if( alienCredits )
+ {
+ trap_Cvar_Set( "g_alienCredits",
+ va( "%d", g_alienCredits.integer + alienCredits ) );
+ trap_Cvar_Update( &g_alienCredits );
+ }
+ if( humanCredits )
+ {
+ trap_Cvar_Set( "g_humanCredits",
+ va( "%d", g_humanCredits.integer + humanCredits ) );
+ trap_Cvar_Update( &g_humanCredits );
+ }
+
+ return totalDamage;
+}
+
+/*
+==================
player_die
==================
*/
@@ -131,18 +237,11 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
gentity_t *ent;
int anim;
int killer;
- int i, j;
- char *killerName, *obit;
- float totalTK = 0;
- float totalDamage = 0.0f;
- float percentDamage = 0.0f;
- gentity_t *player;
- qboolean tk = qfalse;
-
+ int i;
+ const char *killerName, *obit;
if( self->client->ps.pm_type == PM_DEAD )
return;
-
if( level.intermissiontime )
return;
@@ -155,27 +254,9 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
killer = attacker->s.number;
if( attacker->client )
- {
killerName = attacker->client->pers.netname;
- tk = ( attacker != self && attacker->client->ps.stats[ STAT_PTEAM ]
- == self->client->ps.stats[ STAT_PTEAM ] );
-
- if( attacker != self && attacker->client->ps.stats[ STAT_PTEAM ] == self->client->ps.stats[ STAT_PTEAM ] )
- {
- attacker->client->pers.statscounters.teamkills++;
- if( attacker->client->pers.teamSelection == PTE_ALIENS )
- {
- level.alienStatsCounters.teamkills++;
- }
- else if( attacker->client->pers.teamSelection == PTE_HUMANS )
- {
- level.humanStatsCounters.teamkills++;
- }
- }
-
- }
else
- killerName = "<non-client>";
+ killerName = "<world>";
}
else
{
@@ -183,395 +264,62 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
killerName = "<world>";
}
- if( killer < 0 || killer >= MAX_CLIENTS )
- {
- killer = ENTITYNUM_WORLD;
- killerName = "<world>";
- }
-
- if( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) )
- obit = "<bad obituary>";
+ if( meansOfDeath < 0 || meansOfDeath >= ARRAY_LEN( modNames ) )
+ // fall back on the number
+ obit = va( "%d", meansOfDeath );
else
obit = modNames[ meansOfDeath ];
- G_LogPrintf("Kill: %i %i %i: %s^7 killed %s^7 by %s\n",
- killer, self->s.number, meansOfDeath, killerName,
- self->client->pers.netname, obit );
+ G_LogPrintf( "Die: %d %d %s: %s" S_COLOR_WHITE " killed %s\n",
+ killer,
+ (int)( self - g_entities ),
+ obit,
+ killerName,
+ self->client->pers.netname );
- //TA: deactivate all upgrades
+ // deactivate all upgrades
for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
BG_DeactivateUpgrade( i, self->client->ps.stats );
- if( meansOfDeath == MOD_SLAP )
- {
- trap_SendServerCommand( -1,
- va( "print \"%s^7 felt %s^7's authority\n\"",
- self->client->pers.netname, killerName ) );
- goto finish_dying;
- }
-
// broadcast the death event to everyone
- if( !tk )
- {
- ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
- ent->s.eventParm = meansOfDeath;
- ent->s.otherEntityNum = self->s.number;
- ent->s.otherEntityNum2 = killer;
- ent->r.svFlags = SVF_BROADCAST; // send to everyone
- }
- else if( attacker && attacker->client )
- {
- // tjw: obviously this is a hack and belongs in the client, but
- // this works as a temporary fix.
- trap_SendServerCommand( -1,
- va( "print \"%s^7 was killed by ^1TEAMMATE^7 %s^7 (Did %d damage to %d max)\n\"",
- self->client->pers.netname, attacker->client->pers.netname, self->client->tkcredits[ attacker->s.number ], self->client->ps.stats[ STAT_MAX_HEALTH ] ) );
- trap_SendServerCommand( attacker - g_entities,
- va( "cp \"You killed ^1TEAMMATE^7 %s\"", self->client->pers.netname ) );
- G_LogOnlyPrintf("%s^7 was killed by ^1TEAMMATE^7 %s^7 (Did %d damage to %d max)\n",
- self->client->pers.netname, attacker->client->pers.netname, self->client->tkcredits[ attacker->s.number ], self->client->ps.stats[ STAT_MAX_HEALTH ] );
- G_TeamKill_Repent( attacker );
- }
+ ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
+ ent->s.eventParm = meansOfDeath;
+ ent->s.otherEntityNum = self->s.number;
+ ent->s.otherEntityNum2 = killer;
+ ent->r.svFlags = SVF_BROADCAST; // send to everyone
self->enemy = attacker;
-
self->client->ps.persistant[ PERS_KILLED ]++;
- self->client->pers.statscounters.deaths++;
- if( self->client->pers.teamSelection == PTE_ALIENS )
- {
- level.alienStatsCounters.deaths++;
- }
- else if( self->client->pers.teamSelection == PTE_HUMANS )
- {
- level.humanStatsCounters.deaths++;
- }
if( attacker && attacker->client )
{
attacker->client->lastkilled_client = self->s.number;
- if( g_killerHP.integer ||
- ( g_devmapKillerHP.integer && g_cheats.integer ) )
- {
- trap_SendServerCommand( self-g_entities,
- va( "print \"Your killer, %s^7, had %3i HP.\n\"",
- killerName, attacker->health ) );
- }
-
- if( attacker == self || OnSameTeam( self, attacker ) )
- {
- AddScore( attacker, -1 );
-
- // Normal teamkill penalty
- if( !g_retribution.integer )
- {
- if( attacker->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- G_AddCreditToClient( attacker->client, -FREEKILL_ALIEN, qtrue );
- else if( attacker->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- G_AddCreditToClient( attacker->client, -FREEKILL_HUMAN, qtrue );
- }
- }
- else
- {
- AddScore( attacker, 1 );
-
- if( g_gradualFreeFunds.integer < 2 )
- attacker->client->pers.lastFreekillTime = level.time;
- attacker->client->pers.statscounters.kills++;
- if( attacker->client->pers.teamSelection == PTE_ALIENS )
- {
- level.alienStatsCounters.kills++;
- }
- else if( attacker->client->pers.teamSelection == PTE_HUMANS )
- {
- level.humanStatsCounters.kills++;
- }
- }
-
- if( attacker == self )
+ if( ( attacker == self || OnSameTeam( self, attacker ) ) && meansOfDeath != MOD_HSPAWN )
{
- attacker->client->pers.statscounters.suicides++;
- if( attacker->client->pers.teamSelection == PTE_ALIENS )
+ //punish team kills and suicides
+ if( attacker->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
- level.alienStatsCounters.suicides++;
+ G_AddCreditToClient( attacker->client, -ALIEN_TK_SUICIDE_PENALTY, qtrue );
+ AddScore( attacker, -ALIEN_TK_SUICIDE_PENALTY );
}
- else if( attacker->client->pers.teamSelection == PTE_HUMANS )
+ else if( attacker->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
- level.humanStatsCounters.suicides++;
+ G_AddCreditToClient( attacker->client, -HUMAN_TK_SUICIDE_PENALTY, qtrue );
+ AddScore( attacker, -HUMAN_TK_SUICIDE_PENALTY );
}
}
}
else if( attacker->s.eType != ET_BUILDABLE )
- AddScore( self, -1 );
-
- //total up all the damage done by every client
- for( i = 0; i < MAX_CLIENTS; i++ )
{
- totalDamage += (float)self->credits[ i ];
- totalTK += (float)self->client->tkcredits[ i ];
+ if( self->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ AddScore( self, -ALIEN_TK_SUICIDE_PENALTY );
+ else if( self->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ AddScore( self, -HUMAN_TK_SUICIDE_PENALTY );
}
- // punish players for damaging teammates
- if ( g_retribution.integer && totalTK )
- {
- int totalPrice;
- int max = HUMAN_MAX_CREDITS;
-
- if ( self->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- totalPrice = BG_ClassCanEvolveFromTo( PCL_ALIEN_LEVEL0, self->client->ps.stats[ STAT_PCLASS ], ALIEN_MAX_KILLS, 0 );
- max = ALIEN_MAX_KILLS;
- }
- else
- {
- totalPrice = BG_GetValueOfEquipment( &self->client->ps );
- }
-
- if ( self->client->ps.persistant[ PERS_CREDIT ] + totalPrice > max )
- totalPrice = max - self->client->ps.persistant[ PERS_CREDIT ];
- if ( totalPrice > 0 )
- {
- totalTK += totalDamage;
- if( totalTK < self->client->ps.stats[ STAT_MAX_HEALTH ] )
- totalTK = self->client->ps.stats[ STAT_MAX_HEALTH ];
-
- if ( self->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- for ( i = 0; i < MAX_CLIENTS; i++ )
- {
- int price;
- // no retribution if self damage or enemy damage or building damage or no damage from this client
- if ( i == self - g_entities || !g_entities[ i ].client ||
- !OnSameTeam( &g_entities[ i ], self ) ||
- !self->client->tkcredits[ i ] )
- continue;
-
- // calculate retribution price (rounded up)
- price = ( totalPrice * self->client->tkcredits[ i ] ) / totalTK + 0.5f;
- self->client->tkcredits[ i ] = 0;
-
- // check for enough credits
- if ( g_entities[ i ].client->ps.persistant[ PERS_CREDIT ] < price )
- price = g_entities[ i ].client->ps.persistant[ PERS_CREDIT ];
- if ( price )
- {
- G_AddCreditToClient( self->client, price, qtrue );
- G_AddCreditToClient( g_entities[ i ].client, -price, qtrue );
-
- trap_SendServerCommand( self->client->ps.clientNum,
- va( "print \"Received ^3%d credits ^7from %s ^7in retribution.\n\"",
- price, g_entities[ i ].client->pers.netname ) );
- trap_SendServerCommand( g_entities[ i ].client->ps.clientNum,
- va( "print \"Transfered ^3%d credits ^7to %s ^7in retribution.\n\"",
- price, self->client->pers.netname ) );
- }
- }
- }
- else
- {
- int toPay[ MAX_CLIENTS ] = { 0 };
- int frags = totalPrice;
- int damageForEvo = totalTK / totalPrice;
- for ( i = 0; i < MAX_CLIENTS; i++ )
- {
- // no retribution if self damage or enemy damage or building damage or no damage from this client
- if ( i == self - g_entities || !g_entities[ i ].client ||
- !OnSameTeam( &g_entities[ i ], self ) ||
- !self->client->tkcredits[ i ] )
- continue;
-
- // find out how many full evos this client needs to pay
- toPay[ i ] = ( totalPrice * self->client->tkcredits[ i ] ) / totalTK;
- if ( toPay[ i ] > g_entities[ i ].client->ps.persistant[ PERS_CREDIT ] )
- toPay[ i ] = g_entities[ i ].client->ps.persistant[ PERS_CREDIT ];
- frags -= toPay[ i ];
- self->client->tkcredits[ i ] -= damageForEvo * toPay[ i ];
- }
-
- // if we have not met the evo count, continue stealing evos
- while ( 1 )
- {
- int maximum = 0;
- int topClient = 0;
- for ( i = 0; i < MAX_CLIENTS; i++ )
- {
- if ( self->client->tkcredits[ i ] > maximum && g_entities[ i ].client->ps.persistant[ PERS_CREDIT ] )
- {
- maximum = self->client->tkcredits[ i ];
- topClient = i;
- }
- }
- if ( !maximum )
- break;
- toPay[ topClient ]++;
- self->client->tkcredits[ topClient ] = 0;
- frags--;
- if ( !frags )
- break;
- }
-
- // now move the evos around
- for ( i = 0; i < MAX_CLIENTS; i++ )
- {
- if ( !toPay[ i ] )
- continue;
-
- G_AddCreditToClient( self->client, toPay[ i ], qtrue );
- G_AddCreditToClient( g_entities[ i ].client, -toPay[ i ], qtrue );
-
- trap_SendServerCommand( self->client->ps.clientNum,
- va( "print \"Received ^3%d ^7evos from %s ^7in retribution.\n\"",
- toPay[ i ], g_entities[ i ].client->pers.netname ) );
- trap_SendServerCommand( g_entities[ i ].client->ps.clientNum,
- va( "print \"Transfered ^3%d ^7evos to %s ^7in retribution.\n\"",
- toPay[ i ], self->client->pers.netname ) );
- }
- }
- }
- }
-
- // if players did more than DAMAGE_FRACTION_FOR_KILL increment the stage counters
- if( !OnSameTeam( self, attacker ) && totalDamage >= ( self->client->ps.stats[ STAT_MAX_HEALTH ] * DAMAGE_FRACTION_FOR_KILL ) )
- {
- if( self->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- trap_Cvar_Set( "g_alienKills", va( "%d", g_alienKills.integer + 1 ) );
- if( g_alienStage.integer < 2 )
- {
- self->client->pers.statscounters.feeds++;
- level.humanStatsCounters.feeds++;
- }
- }
- else if( self->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- trap_Cvar_Set( "g_humanKills", va( "%d", g_humanKills.integer + 1 ) );
- if( g_humanStage.integer < 2 )
- {
- self->client->pers.statscounters.feeds++;
- level.alienStatsCounters.feeds++;
- }
- }
- }
-
- if( totalDamage > 0.0f )
- {
- if( self->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- //nice simple happy bouncy human land
- float classValue = BG_FindValueOfClass( self->client->ps.stats[ STAT_PCLASS ] );
-
- for( i = 0; i < MAX_CLIENTS; i++ )
- {
- player = g_entities + i;
-
- if( !player->client )
- continue;
-
- if( player->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
- continue;
-
- if( !self->credits[ i ] )
- continue;
-
- percentDamage = (float)self->credits[ i ] / totalDamage;
- if( percentDamage > 0 && percentDamage < 1)
- {
- player->client->pers.statscounters.assists++;
- level.humanStatsCounters.assists++;
- }
-
- //add credit
- G_AddCreditToClient( player->client,
- (int)( classValue * percentDamage ), qtrue );
- }
- }
- else if( self->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- //horribly complex nasty alien land
- float humanValue = BG_GetValueOfHuman( &self->client->ps );
- int frags;
- int unclaimedFrags = (int)humanValue;
-
- for( i = 0; i < MAX_CLIENTS; i++ )
- {
- player = g_entities + i;
-
- if( !player->client )
- continue;
-
- if( player->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS )
- continue;
-
- //this client did no damage
- if( !self->credits[ i ] )
- continue;
-
- //nothing left to claim
- if( !unclaimedFrags )
- break;
-
- percentDamage = (float)self->credits[ i ] / totalDamage;
- if( percentDamage > 0 && percentDamage < 1)
- {
- player->client->pers.statscounters.assists++;
- level.alienStatsCounters.assists++;
- }
-
- frags = (int)floor( humanValue * percentDamage);
-
- if( frags > 0 )
- {
- //add kills
- G_AddCreditToClient( player->client, frags, qtrue );
-
- //can't revist this account later
- self->credits[ i ] = 0;
-
- //reduce frags left to be claimed
- unclaimedFrags -= frags;
- }
- }
-
- //there are frags still to be claimed
- if( unclaimedFrags )
- {
- //the clients remaining at this point do not
- //have enough credit to claim even one frag
- //so simply give the top <unclaimedFrags> clients
- //a frag each
-
- for( i = 0; i < unclaimedFrags; i++ )
- {
- int maximum = 0;
- int topClient = 0;
-
- for( j = 0; j < MAX_CLIENTS; j++ )
- {
- //this client did no damage
- if( !self->credits[ j ] )
- continue;
-
- if( self->credits[ j ] > maximum )
- {
- maximum = self->credits[ j ];
- topClient = j;
- }
- }
-
- if( maximum > 0 )
- {
- player = g_entities + topClient;
-
- //add kills
- G_AddCreditToClient( player->client, 1, qtrue );
-
- //can't revist this account again
- self->credits[ topClient ] = 0;
- }
- }
- }
- }
- }
+ // give credits for killing this player
+ G_RewardAttackers( self );
ScoreboardMessage( self ); // show scores
@@ -585,29 +333,28 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
if( client->pers.connected != CON_CONNECTED )
continue;
- if( client->sess.sessionTeam != TEAM_SPECTATOR )
+ if( client->sess.spectatorState == SPECTATOR_NOT )
continue;
if( client->sess.spectatorClient == self->s.number )
ScoreboardMessage( g_entities + i );
}
-finish_dying: // from MOD_SLAP
-
- VectorCopy( self->s.origin, self->client->pers.lastDeathLocation );
+ VectorCopy( self->r.currentOrigin, self->client->pers.lastDeathLocation );
self->takedamage = qfalse; // can still be gibbed
self->s.weapon = WP_NONE;
- self->r.contents = CONTENTS_CORPSE;
+ if( self->client->noclip )
+ self->client->cliprcontents = CONTENTS_CORPSE;
+ else
+ self->r.contents = CONTENTS_CORPSE;
- self->s.angles[ PITCH ] = 0;
- self->s.angles[ ROLL ] = 0;
- self->s.angles[ YAW ] = self->s.apos.trBase[ YAW ];
+ self->client->ps.viewangles[ PITCH ] = 0; // zomg
+ self->client->ps.viewangles[ YAW ] = self->s.apos.trBase[ YAW ];
+ self->client->ps.viewangles[ ROLL ] = 0;
LookAtKiller( self, inflictor, attacker );
- VectorCopy( self->s.angles, self->client->ps.viewangles );
-
self->s.loopSound = 0;
self->r.maxs[ 2 ] = -8;
@@ -674,57 +421,55 @@ finish_dying: // from MOD_SLAP
}
trap_LinkEntity( self );
-}
-
-////////TA: locdamage
+ self->client->pers.infoChangeTime = level.time;
+}
/*
===============
-G_ParseArmourScript
+G_ParseDmgScript
===============
*/
-void G_ParseArmourScript( char *buf, int upgrade )
+static int G_ParseDmgScript( damageRegion_t *regions, char *buf )
{
char *token;
+ float angleSpan, heightSpan;
int count;
- count = 0;
-
- while( 1 )
+ for( count = 0; ; count++ )
{
token = COM_Parse( &buf );
-
- if( !token[0] )
+ if( !token[ 0 ] )
break;
if( strcmp( token, "{" ) )
{
- G_Printf( "Missing { in armour file\n" );
+ COM_ParseError( "Missing {" );
break;
}
- if( count == MAX_ARMOUR_REGIONS )
+ if( count >= MAX_DAMAGE_REGIONS )
{
- G_Printf( "Max armour regions exceeded in locdamage file\n" );
+ COM_ParseError( "Max damage regions exceeded" );
break;
}
- //default
- g_armourRegions[ upgrade ][ count ].minHeight = 0.0;
- g_armourRegions[ upgrade ][ count ].maxHeight = 1.0;
- g_armourRegions[ upgrade ][ count ].minAngle = 0;
- g_armourRegions[ upgrade ][ count ].maxAngle = 360;
- g_armourRegions[ upgrade ][ count ].modifier = 1.0;
- g_armourRegions[ upgrade ][ count ].crouch = qfalse;
+ // defaults
+ regions[ count ].name[ 0 ] = '\0';
+ regions[ count ].minHeight = 0.0f;
+ regions[ count ].maxHeight = 1.0f;
+ regions[ count ].minAngle = 0.0f;
+ regions[ count ].maxAngle = 360.0f;
+ regions[ count ].modifier = 1.0f;
+ regions[ count ].crouch = qfalse;
while( 1 )
{
token = COM_ParseExt( &buf, qtrue );
- if( !token[0] )
+ if( !token[ 0 ] )
{
- G_Printf( "Unexpected end of armour file\n" );
+ COM_ParseError( "Unexpected end of file" );
break;
}
@@ -732,172 +477,260 @@ void G_ParseArmourScript( char *buf, int upgrade )
{
break;
}
+ else if( !strcmp( token, "name" ) )
+ {
+ token = COM_ParseExt( &buf, qfalse );
+ if( token[ 0 ] )
+ Q_strncpyz( regions[ count ].name, token,
+ sizeof( regions[ count ].name ) );
+ }
else if( !strcmp( token, "minHeight" ) )
{
token = COM_ParseExt( &buf, qfalse );
-
- if ( !token[0] )
+ if( !token[ 0 ] )
strcpy( token, "0" );
-
- g_armourRegions[ upgrade ][ count ].minHeight = atof( token );
+ regions[ count ].minHeight = atof( token );
}
else if( !strcmp( token, "maxHeight" ) )
{
token = COM_ParseExt( &buf, qfalse );
-
- if ( !token[0] )
+ if( !token[ 0 ] )
strcpy( token, "100" );
-
- g_armourRegions[ upgrade ][ count ].maxHeight = atof( token );
+ regions[ count ].maxHeight = atof( token );
}
else if( !strcmp( token, "minAngle" ) )
{
token = COM_ParseExt( &buf, qfalse );
-
- if ( !token[0] )
+ if( !token[ 0 ] )
strcpy( token, "0" );
-
- g_armourRegions[ upgrade ][ count ].minAngle = atoi( token );
+ regions[ count ].minAngle = atoi( token );
}
else if( !strcmp( token, "maxAngle" ) )
{
token = COM_ParseExt( &buf, qfalse );
-
- if ( !token[0] )
+ if( !token[ 0 ] )
strcpy( token, "360" );
-
- g_armourRegions[ upgrade ][ count ].maxAngle = atoi( token );
+ regions[ count ].maxAngle = atoi( token );
}
else if( !strcmp( token, "modifier" ) )
{
token = COM_ParseExt( &buf, qfalse );
-
- if ( !token[0] )
+ if( !token[ 0 ] )
strcpy( token, "1.0" );
-
- g_armourRegions[ upgrade ][ count ].modifier = atof( token );
+ regions[ count ].modifier = atof( token );
}
else if( !strcmp( token, "crouch" ) )
{
- g_armourRegions[ upgrade ][ count ].crouch = qtrue;
+ regions[ count ].crouch = qtrue;
+ }
+ else
+ {
+ COM_ParseWarning("Unknown token \"%s\"", token);
}
}
-
- g_numArmourRegions[ upgrade ]++;
- count++;
+
+ // Angle portion covered
+ angleSpan = regions[ count ].maxAngle - regions[ count ].minAngle;
+ if( angleSpan < 0.0f )
+ angleSpan += 360.0f;
+ angleSpan /= 360.0f;
+
+ // Height portion covered
+ heightSpan = regions[ count ].maxHeight - regions[ count ].minHeight;
+ if( heightSpan < 0.0f )
+ heightSpan = -heightSpan;
+ if( heightSpan > 1.0f )
+ heightSpan = 1.0f;
+
+ regions[ count ].area = angleSpan * heightSpan;
+ if( !regions[ count ].area )
+ regions[ count ].area = 0.00001f;
}
+
+ return count;
}
-
/*
-===============
-G_ParseDmgScript
-===============
+============
+GetRegionDamageModifier
+============
*/
-void G_ParseDmgScript( char *buf, int class )
+static float GetRegionDamageModifier( gentity_t *targ, int class, int piece )
{
- char *token;
- int count;
-
- count = 0;
-
- while( 1 )
+ damageRegion_t *regions, *overlap;
+ float modifier = 0.0f, areaSum = 0.0f;
+ int j, i;
+ qboolean crouch;
+
+ crouch = targ->client->ps.pm_flags & PMF_DUCKED;
+ overlap = &g_damageRegions[ class ][ piece ];
+
+ if( g_debugDamage.integer > 2 )
+ G_Printf( "GetRegionDamageModifier():\n"
+ ". bodyRegion = [%d %d %f %f] (%s)\n"
+ ". modifier = %f\n",
+ overlap->minAngle, overlap->maxAngle,
+ overlap->minHeight, overlap->maxHeight,
+ overlap->name, overlap->modifier );
+
+ // Find the armour layer modifier, assuming that none of the armour regions
+ // overlap and that any areas that are not covered have a modifier of 1.0
+ for( j = UP_NONE + 1; j < UP_NUM_UPGRADES; j++ )
{
- token = COM_Parse( &buf );
-
- if( !token[0] )
- break;
-
- if( strcmp( token, "{" ) )
- {
- G_Printf( "Missing { in locdamage file\n" );
- break;
- }
-
- if( count == MAX_LOCDAMAGE_REGIONS )
- {
- G_Printf( "Max damage regions exceeded in locdamage file\n" );
- break;
- }
-
- //default
- g_damageRegions[ class ][ count ].minHeight = 0.0;
- g_damageRegions[ class ][ count ].maxHeight = 1.0;
- g_damageRegions[ class ][ count ].minAngle = 0;
- g_damageRegions[ class ][ count ].maxAngle = 360;
- g_damageRegions[ class ][ count ].modifier = 1.0;
- g_damageRegions[ class ][ count ].crouch = qfalse;
-
- while( 1 )
+ if( !BG_InventoryContainsUpgrade( j, targ->client->ps.stats ) ||
+ !g_numArmourRegions[ j ] )
+ continue;
+ regions = g_armourRegions[ j ];
+
+ for( i = 0; i < g_numArmourRegions[ j ]; i++ )
{
- token = COM_ParseExt( &buf, qtrue );
-
- if( !token[0] )
+ float overlapMaxA, regionMinA, regionMaxA, angleSpan, heightSpan, area;
+
+ if( regions[ i ].crouch != crouch )
+ continue;
+
+ // Convert overlap angle to 0 to max
+ overlapMaxA = overlap->maxAngle - overlap->minAngle;
+ if( overlapMaxA < 0.0f )
+ overlapMaxA += 360.0f;
+
+ // Convert region angles to match overlap
+ regionMinA = regions[ i ].minAngle - overlap->minAngle;
+ if( regionMinA < 0.0f )
+ regionMinA += 360.0f;
+ regionMaxA = regions[ i ].maxAngle - overlap->minAngle;
+ if( regionMaxA < 0.0f )
+ regionMaxA += 360.0f;
+
+ // Overlapping Angle portion
+ if( regionMinA <= regionMaxA )
{
- G_Printf( "Unexpected end of locdamage file\n" );
- break;
+ angleSpan = 0.0f;
+ if( regionMinA < overlapMaxA )
+ {
+ if( regionMaxA > overlapMaxA )
+ regionMaxA = overlapMaxA;
+ angleSpan = regionMaxA - regionMinA;
+ }
}
-
- if( !Q_stricmp( token, "}" ) )
+ else
{
- break;
+ if( regionMaxA > overlapMaxA )
+ regionMaxA = overlapMaxA;
+ angleSpan = regionMaxA;
+ if( regionMinA < overlapMaxA )
+ angleSpan += overlapMaxA - regionMinA;
}
- else if( !strcmp( token, "minHeight" ) )
- {
- token = COM_ParseExt( &buf, qfalse );
+ angleSpan /= 360.0f;
+
+ // Overlapping height portion
+ heightSpan = MIN( overlap->maxHeight, regions[ i ].maxHeight ) -
+ MAX( overlap->minHeight, regions[ i ].minHeight );
+ if( heightSpan < 0.0f )
+ heightSpan = 0.0f;
+ if( heightSpan > 1.0f )
+ heightSpan = 1.0f;
+
+ if( g_debugDamage.integer > 2 )
+ G_Printf( ". armourRegion = [%d %d %f %f] (%s)\n"
+ ". . modifier = %f\n"
+ ". . angleSpan = %f\n"
+ ". . heightSpan = %f\n",
+ regions[ i ].minAngle, regions[ i ].maxAngle,
+ regions[ i ].minHeight, regions[ i ].maxHeight,
+ regions[ i ].name, regions[ i ].modifier,
+ angleSpan, heightSpan );
+
+ areaSum += area = angleSpan * heightSpan;
+ modifier += regions[ i ].modifier * area;
+ }
+ }
- if ( !token[0] )
- strcpy( token, "0" );
+ if( g_debugDamage.integer > 2 )
+ G_Printf( ". areaSum = %f\n"
+ ". armourModifier = %f\n", areaSum, modifier );
- g_damageRegions[ class ][ count ].minHeight = atof( token );
- }
- else if( !strcmp( token, "maxHeight" ) )
- {
- token = COM_ParseExt( &buf, qfalse );
+ return overlap->modifier * ( overlap->area + modifier - areaSum );
+}
- if ( !token[0] )
- strcpy( token, "100" );
+/*
+============
+GetNonLocDamageModifier
+============
+*/
+static float GetNonLocDamageModifier( gentity_t *targ, int class )
+{
+ float modifier = 0.0f, area = 0.0f, scale = 0.0f;
+ int i;
+ qboolean crouch;
+
+ // For every body region, use stretch-armor formula to apply armour modifier
+ // for any overlapping area that armour shares with the body region
+ crouch = targ->client->ps.pm_flags & PMF_DUCKED;
+ for( i = 0; i < g_numDamageRegions[ class ]; i++ )
+ {
+ damageRegion_t *region;
- g_damageRegions[ class ][ count ].maxHeight = atof( token );
- }
- else if( !strcmp( token, "minAngle" ) )
- {
- token = COM_ParseExt( &buf, qfalse );
+ region = &g_damageRegions[ class ][ i ];
- if ( !token[0] )
- strcpy( token, "0" );
+ if( region->crouch != crouch )
+ continue;
- g_damageRegions[ class ][ count ].minAngle = atoi( token );
- }
- else if( !strcmp( token, "maxAngle" ) )
- {
- token = COM_ParseExt( &buf, qfalse );
+ modifier += GetRegionDamageModifier( targ, class, i );
- if ( !token[0] )
- strcpy( token, "360" );
+ scale += region->modifier * region->area;
+ area += region->area;
- g_damageRegions[ class ][ count ].maxAngle = atoi( token );
- }
- else if( !strcmp( token, "modifier" ) )
- {
- token = COM_ParseExt( &buf, qfalse );
+ }
- if ( !token[0] )
- strcpy( token, "1.0" );
+ modifier = !scale ? 1.0f : 1.0f + ( modifier / scale - 1.0f ) * area;
+
+ if( g_debugDamage.integer > 1 )
+ G_Printf( "GetNonLocDamageModifier() modifier:%f, area:%f, scale:%f\n",
+ modifier, area, scale );
+
+ return modifier;
+}
- g_damageRegions[ class ][ count ].modifier = atof( token );
- }
- else if( !strcmp( token, "crouch" ) )
- {
- g_damageRegions[ class ][ count ].crouch = qtrue;
- }
- }
+/*
+============
+GetPointDamageModifier
+
+Returns the damage region given an angle and a height proportion
+============
+*/
+static float GetPointDamageModifier( gentity_t *targ, damageRegion_t *regions,
+ int len, float angle, float height )
+{
+ float modifier = 1.0f;
+ int i;
- g_numDamageRegions[ class ]++;
- count++;
+ for( i = 0; i < len; i++ )
+ {
+ if( regions[ i ].crouch != ( targ->client->ps.pm_flags & PMF_DUCKED ) )
+ continue;
+
+ // Angle must be within range
+ if( ( regions[ i ].minAngle <= regions[ i ].maxAngle &&
+ ( angle < regions[ i ].minAngle ||
+ angle > regions[ i ].maxAngle ) ) ||
+ ( regions[ i ].minAngle > regions[ i ].maxAngle &&
+ angle > regions[ i ].maxAngle && angle < regions[ i ].minAngle ) )
+ continue;
+
+ // Height must be within range
+ if( height < regions[ i ].minHeight || height > regions[ i ].maxHeight )
+ continue;
+
+ modifier *= regions[ i ].modifier;
}
-}
+ if( g_debugDamage.integer )
+ G_Printf( "GetDamageRegionModifier(angle = %f, height = %f): %f\n",
+ angle, height, modifier );
+
+ return modifier;
+}
/*
============
@@ -906,34 +739,33 @@ G_CalcDamageModifier
*/
static float G_CalcDamageModifier( vec3_t point, gentity_t *targ, gentity_t *attacker, int class, int dflags )
{
- vec3_t targOrigin;
- vec3_t bulletPath;
- vec3_t bulletAngle;
- vec3_t pMINUSfloor, floor, normal;
-
- float clientHeight, hitRelative, hitRatio;
- int bulletRotation, clientRotation, hitRotation;
- float modifier = 1.0f;
- int i, j;
+ vec3_t targOrigin, bulletPath, bulletAngle, pMINUSfloor, floor, normal;
+ float clientHeight, hitRelative, hitRatio, modifier;
+ int hitRotation, i;
if( point == NULL )
return 1.0f;
+ // Don't need to calculate angles and height for non-locational damage
+ if( dflags & DAMAGE_NO_LOCDAMAGE )
+ return GetNonLocDamageModifier( targ, class );
+
+ // Get the point location relative to the floor under the target
if( g_unlagged.integer && targ->client && targ->client->unlaggedCalc.used )
VectorCopy( targ->client->unlaggedCalc.origin, targOrigin );
else
VectorCopy( targ->r.currentOrigin, targOrigin );
- clientHeight = targ->r.maxs[ 2 ] - targ->r.mins[ 2 ];
-
- if( targ->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING )
- VectorCopy( targ->client->ps.grapplePoint, normal );
- else
- VectorSet( normal, 0, 0, 1 );
-
+ BG_GetClientNormal( &targ->client->ps, normal );
VectorMA( targOrigin, targ->r.mins[ 2 ], normal, floor );
VectorSubtract( point, floor, pMINUSfloor );
+ // Get the proportion of the target height where the hit landed
+ clientHeight = targ->r.maxs[ 2 ] - targ->r.mins[ 2 ];
+
+ if( !clientHeight )
+ clientHeight = 1.0f;
+
hitRelative = DotProduct( normal, pMINUSfloor ) / VectorLength( normal );
if( hitRelative < 0.0f )
@@ -944,105 +776,25 @@ static float G_CalcDamageModifier( vec3_t point, gentity_t *targ, gentity_t *att
hitRatio = hitRelative / clientHeight;
- VectorSubtract( targOrigin, point, bulletPath );
+ // Get the yaw of the attack relative to the target's view yaw
+ VectorSubtract( point, targOrigin, bulletPath );
vectoangles( bulletPath, bulletAngle );
- clientRotation = targ->client->ps.viewangles[ YAW ];
- bulletRotation = bulletAngle[ YAW ];
-
- hitRotation = abs( clientRotation - bulletRotation );
+ hitRotation = AngleNormalize360( targ->client->ps.viewangles[ YAW ] -
+ bulletAngle[ YAW ] );
- hitRotation = hitRotation % 360; // Keep it in the 0-359 range
+ // Get modifiers from the target's damage regions
+ modifier = GetPointDamageModifier( targ, g_damageRegions[ class ],
+ g_numDamageRegions[ class ],
+ hitRotation, hitRatio );
- if( dflags & DAMAGE_NO_LOCDAMAGE )
+ for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
{
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
+ if( BG_InventoryContainsUpgrade( i, targ->client->ps.stats ) )
{
- float totalModifier = 0.0f;
- float averageModifier = 1.0f;
-
- //average all of this upgrade's armour regions together
- if( BG_InventoryContainsUpgrade( i, targ->client->ps.stats ) )
- {
- for( j = 0; j < g_numArmourRegions[ i ]; j++ )
- totalModifier += g_armourRegions[ i ][ j ].modifier;
-
- if( g_numArmourRegions[ i ] )
- averageModifier = totalModifier / g_numArmourRegions[ i ];
- else
- averageModifier = 1.0f;
- }
-
- modifier *= averageModifier;
- }
- }
- else
- {
- if( attacker && attacker->client )
- {
- attacker->client->pers.statscounters.hitslocational++;
- level.alienStatsCounters.hitslocational++;
- }
- for( i = 0; i < g_numDamageRegions[ class ]; i++ )
- {
- qboolean rotationBound;
-
- if( g_damageRegions[ class ][ i ].minAngle >
- g_damageRegions[ class ][ i ].maxAngle )
- {
- rotationBound = ( hitRotation >= g_damageRegions[ class ][ i ].minAngle &&
- hitRotation <= 360 ) || ( hitRotation >= 0 &&
- hitRotation <= g_damageRegions[ class ][ i ].maxAngle );
- }
- else
- {
- rotationBound = ( hitRotation >= g_damageRegions[ class ][ i ].minAngle &&
- hitRotation <= g_damageRegions[ class ][ i ].maxAngle );
- }
-
- if( rotationBound &&
- hitRatio >= g_damageRegions[ class ][ i ].minHeight &&
- hitRatio <= g_damageRegions[ class ][ i ].maxHeight &&
- ( g_damageRegions[ class ][ i ].crouch ==
- ( targ->client->ps.pm_flags & PMF_DUCKED ) ) )
- modifier *= g_damageRegions[ class ][ i ].modifier;
- }
-
- if( attacker && attacker->client && modifier == 2 )
- {
- attacker->client->pers.statscounters.headshots++;
- level.alienStatsCounters.headshots++;
- }
-
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- {
- if( BG_InventoryContainsUpgrade( i, targ->client->ps.stats ) )
- {
- for( j = 0; j < g_numArmourRegions[ i ]; j++ )
- {
- qboolean rotationBound;
-
- if( g_armourRegions[ i ][ j ].minAngle >
- g_armourRegions[ i ][ j ].maxAngle )
- {
- rotationBound = ( hitRotation >= g_armourRegions[ i ][ j ].minAngle &&
- hitRotation <= 360 ) || ( hitRotation >= 0 &&
- hitRotation <= g_armourRegions[ i ][ j ].maxAngle );
- }
- else
- {
- rotationBound = ( hitRotation >= g_armourRegions[ i ][ j ].minAngle &&
- hitRotation <= g_armourRegions[ i ][ j ].maxAngle );
- }
-
- if( rotationBound &&
- hitRatio >= g_armourRegions[ i ][ j ].minHeight &&
- hitRatio <= g_armourRegions[ i ][ j ].maxHeight &&
- ( g_armourRegions[ i ][ j ].crouch ==
- ( targ->client->ps.pm_flags & PMF_DUCKED ) ) )
- modifier *= g_armourRegions[ i ][ j ].modifier;
- }
- }
+ modifier *= GetPointDamageModifier( targ, g_armourRegions[ i ],
+ g_numArmourRegions[ i ],
+ hitRotation, hitRatio );
}
}
@@ -1062,37 +814,41 @@ void G_InitDamageLocations( void )
int i;
int len;
fileHandle_t fileHandle;
- char buffer[ MAX_LOCDAMAGE_TEXT ];
+ char buffer[ MAX_DAMAGE_REGION_TEXT ];
for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ )
{
- modelName = BG_FindModelNameForClass( i );
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/locdamage.cfg", modelName );
+ modelName = BG_ClassConfig( i )->modelName;
+ Com_sprintf( filename, sizeof( filename ),
+ "models/players/%s/locdamage.cfg", modelName );
len = trap_FS_FOpenFile( filename, &fileHandle, FS_READ );
if ( !fileHandle )
{
- G_Printf( va( S_COLOR_RED "file not found: %s\n", filename ) );
+ G_Printf( S_COLOR_RED "file not found: %s\n", filename );
continue;
}
- if( len >= MAX_LOCDAMAGE_TEXT )
+ if( len >= MAX_DAMAGE_REGION_TEXT )
{
- G_Printf( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_LOCDAMAGE_TEXT ) );
+ G_Printf( S_COLOR_RED "file too large: %s is %i, max allowed is %i",
+ filename, len, MAX_DAMAGE_REGION_TEXT );
trap_FS_FCloseFile( fileHandle );
continue;
}
+ COM_BeginParseSession( filename );
+
trap_FS_Read( buffer, len, fileHandle );
buffer[len] = 0;
trap_FS_FCloseFile( fileHandle );
- G_ParseDmgScript( buffer, i );
+ g_numDamageRegions[ i ] = G_ParseDmgScript( g_damageRegions[ i ], buffer );
}
for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
{
- modelName = BG_FindNameForUpgrade( i );
+ modelName = BG_Upgrade( i )->name;
Com_sprintf( filename, sizeof( filename ), "armour/%s.armour", modelName );
len = trap_FS_FOpenFile( filename, &fileHandle, FS_READ );
@@ -1101,23 +857,24 @@ void G_InitDamageLocations( void )
if ( !fileHandle )
continue;
- if( len >= MAX_LOCDAMAGE_TEXT )
+ if( len >= MAX_DAMAGE_REGION_TEXT )
{
- G_Printf( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_LOCDAMAGE_TEXT ) );
+ G_Printf( S_COLOR_RED "file too large: %s is %i, max allowed is %i",
+ filename, len, MAX_DAMAGE_REGION_TEXT );
trap_FS_FCloseFile( fileHandle );
continue;
}
+ COM_BeginParseSession( filename );
+
trap_FS_Read( buffer, len, fileHandle );
buffer[len] = 0;
trap_FS_FCloseFile( fileHandle );
- G_ParseArmourScript( buffer, i );
+ g_numArmourRegions[ i ] = G_ParseDmgScript( g_armourRegions[ i ], buffer );
}
}
-////////TA: locdamage
-
/*
============
@@ -1138,16 +895,16 @@ inflictor, attacker, dir, and point can be NULL for environmental effects
dflags these flags are used to control how T_Damage works
DAMAGE_RADIUS damage was indirect (from a nearby explosion)
DAMAGE_NO_ARMOR armor does not protect from this damage
- DAMAGE_KNOCKBACK affect velocity, not just view angles
- DAMAGE_NO_PROTECTION kills godmode, armor, everything
+ DAMAGE_NO_KNOCKBACK do not affect velocity, just view angles
+ DAMAGE_NO_PROTECTION kills everything except godmode
============
*/
-//TA: team is the team that is immune to this damage
+// team is the team that is immune to this damage
void G_SelectiveDamage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
vec3_t dir, vec3_t point, int damage, int dflags, int mod, int team )
{
- if( targ->client && ( team != targ->client->ps.stats[ STAT_PTEAM ] ) )
+ if( targ->client && ( team != targ->client->ps.stats[ STAT_TEAM ] ) )
G_Damage( targ, inflictor, attacker, dir, point, damage, dflags, mod );
}
@@ -1156,18 +913,11 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
{
gclient_t *client;
int take;
- int save;
int asave = 0;
- int knockback = 0;
- float damagemodifier=0.0;
- int takeNoOverkill;
-
- if( !targ->takedamage )
- return;
+ int knockback;
- // the intermission has allready been qualified for, so don't
- // allow any extra scoring
- if( level.intermissionQueued )
+ // Can't deal damage sometimes
+ if( !targ->takedamage || targ->health <= 0 || level.intermissionQueued )
return;
if( !inflictor )
@@ -1176,9 +926,6 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
if( !attacker )
attacker = &g_entities[ ENTITYNUM_WORLD ];
- if( attacker->client && attacker->client->pers.paused )
- return;
-
// shootable doors / buttons don't actually have any health
if( targ->s.eType == ET_MOVER )
{
@@ -1190,42 +937,41 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
}
client = targ->client;
-
- if( client )
- {
- if( client->noclip && !g_devmapNoGod.integer)
- return;
- if( client->pers.paused )
- return;
- }
+ if( client && client->noclip )
+ return;
if( !dir )
- dflags &= ~DAMAGE_KNOCKBACK;
+ dflags |= DAMAGE_NO_KNOCKBACK;
else
VectorNormalize( dir );
- if( dflags & DAMAGE_KNOCKBACK )
+ knockback = damage;
+
+ if( inflictor->s.weapon != WP_NONE )
+ {
+ knockback = (int)( (float)knockback *
+ BG_Weapon( inflictor->s.weapon )->knockbackScale );
+ }
+
+ if( targ->client )
{
- knockback = damage;
+ knockback = (int)( (float)knockback *
+ BG_Class( targ->client->ps.stats[ STAT_CLASS ] )->knockbackScale );
+ }
- if( inflictor->s.weapon != WP_NONE )
- {
- knockback = (int)( (float)knockback *
- BG_FindKnockbackScaleForWeapon( inflictor->s.weapon ) );
- }
+ // Too much knockback from falling really far makes you "bounce" and
+ // looks silly. However, none at all also looks bad. Cap it.
+ if( mod == MOD_FALLING && knockback > 50 )
+ knockback = 50;
- if( targ->client )
- {
- knockback = (int)( (float)knockback *
- BG_FindKnockbackScaleForClass( targ->client->ps.stats[ STAT_PCLASS ] ) );
- }
+ if( knockback > 200 )
+ knockback = 200;
- if( knockback > 200 )
- knockback = 200;
+ if( targ->flags & FL_NO_KNOCKBACK )
+ knockback = 0;
- if( targ->flags & FL_NO_KNOCKBACK )
- knockback = 0;
- }
+ if( dflags & DAMAGE_NO_KNOCKBACK )
+ knockback = 0;
// figure momentum add, even if the damage won't be taken
if( knockback && targ->client )
@@ -1256,6 +1002,18 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
}
}
+ // check for godmode
+ if( targ->flags & FL_GODMODE )
+ return;
+
+ // don't do friendly fire on movement attacks
+ if( ( mod == MOD_LEVEL4_TRAMPLE || mod == MOD_LEVEL3_POUNCE ||
+ mod == MOD_LEVEL4_CRUSH ) &&
+ targ->s.eType == ET_BUILDABLE && targ->buildableTeam == TEAM_ALIENS )
+ {
+ return;
+ }
+
// check for completely getting out of the damage
if( !( dflags & DAMAGE_NO_PROTECTION ) )
{
@@ -1264,8 +1022,14 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
// if the attacker was on the same team
if( targ != attacker && OnSameTeam( targ, attacker ) )
{
+ // don't do friendly fire on movement attacks
+ if( mod == MOD_LEVEL4_TRAMPLE || mod == MOD_LEVEL3_POUNCE ||
+ mod == MOD_LEVEL4_CRUSH )
+ return;
+
+ // if dretchpunt is enabled and this is a dretch, do dretchpunt instead of damage
if( g_dretchPunt.integer &&
- targ->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL0 )
+ targ->client->ps.stats[ STAT_CLASS ] == PCL_ALIEN_LEVEL0 )
{
vec3_t dir, push;
@@ -1275,67 +1039,33 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
push[2] = 64.0f;
VectorAdd( targ->client->ps.velocity, push, targ->client->ps.velocity );
return;
- }
- else if(mod == MOD_LEVEL4_CHARGE || mod == MOD_LEVEL3_POUNCE )
- { // don't do friendly fire on movement attacks
- if( g_friendlyFireMovementAttacks.value <= 0 || ( g_friendlyFire.value<=0 && g_friendlyFireAliens.value<=0 ) )
- return;
- else if( g_friendlyFireMovementAttacks.value > 0 && g_friendlyFireMovementAttacks.value < 1 )
- damage =(int)(0.5 + g_friendlyFireMovementAttacks.value * (float) damage);
- }
- else if( g_friendlyFire.value <=0)
- {
- if( targ->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- if(g_friendlyFireHumans.value<=0)
- return;
- else if( g_friendlyFireHumans.value > 0 && g_friendlyFireHumans.value < 1 )
- damage =(int)(0.5 + g_friendlyFireHumans.value * (float) damage);
- }
- if( targ->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- if(g_friendlyFireAliens.value==0)
- return;
- else if( g_friendlyFireAliens.value > 0 && g_friendlyFireAliens.value < 1 )
- damage =(int)(0.5 + g_friendlyFireAliens.value * (float) damage);
- }
}
- else if( g_friendlyFire.value > 0 && g_friendlyFire.value < 1 )
+
+ // check if friendly fire has been disabled
+ if( !g_friendlyFire.integer )
{
- damage =(int)(0.5 + g_friendlyFire.value * (float) damage);
+ return;
}
}
- // If target is buildable on the same team as the attacking client
if( targ->s.eType == ET_BUILDABLE && attacker->client &&
- targ->biteam == attacker->client->pers.teamSelection )
+ mod != MOD_DECONSTRUCT && mod != MOD_SUICIDE &&
+ mod != MOD_REPLACE && mod != MOD_NOCREEP )
{
- if(mod == MOD_LEVEL4_CHARGE || mod == MOD_LEVEL3_POUNCE )
- {
- if(g_friendlyFireMovementAttacks.value <= 0)
- return;
- else if(g_friendlyFireMovementAttacks.value > 0 && g_friendlyFireMovementAttacks.value < 1)
- damage =(int)(0.5 + g_friendlyFireMovementAttacks.value * (float) damage);
- }
- if( g_friendlyBuildableFire.value <= 0 )
+ if( targ->buildableTeam == attacker->client->pers.teamSelection &&
+ !g_friendlyBuildableFire.integer )
{
return;
}
- else if( g_friendlyBuildableFire.value > 0 && g_friendlyBuildableFire.value < 1 )
+
+ // base is under attack warning if DCC'd
+ if( targ->buildableTeam == TEAM_HUMANS && G_FindDCC( targ ) &&
+ level.time > level.humanBaseAttackTimer )
{
- damage =(int)(0.5 + g_friendlyBuildableFire.value * (float) damage);
+ level.humanBaseAttackTimer = level.time + DC_ATTACK_PERIOD;
+ G_BroadcastEvent( EV_DCC_ATTACK, 0 );
}
}
-
- // check for godmode
- if ( targ->flags & FL_GODMODE && !g_devmapNoGod.integer)
- return;
-
- if( level.paused )
- return;
-
- if(targ->s.eType == ET_BUILDABLE && g_cheats.integer && g_devmapNoStructDmg.integer)
- return;
}
// add to the attacker's hit counter
@@ -1350,7 +1080,6 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
}
take = damage;
- save = 0;
// add to the damage inflicted on a player this frame
// the total will be turned into screen blends and view angle kicks
@@ -1380,23 +1109,21 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
// set the last client who damaged the target
targ->client->lasthurt_client = attacker->s.number;
targ->client->lasthurt_mod = mod;
-
- damagemodifier = G_CalcDamageModifier( point, targ, attacker, client->ps.stats[ STAT_PCLASS ], dflags );
- take = (int)( (float)take * damagemodifier );
+ take = (int)( take * G_CalcDamageModifier( point, targ, attacker,
+ client->ps.stats[ STAT_CLASS ],
+ dflags ) + 0.5f );
//if boosted poison every attack
if( attacker->client && attacker->client->ps.stats[ STAT_STATE ] & SS_BOOSTED )
{
- if( targ->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS &&
- !( targ->client->ps.stats[ STAT_STATE ] & SS_POISONED ) &&
- mod != MOD_LEVEL2_ZAP &&
- targ->client->poisonImmunityTime < level.time )
+ if( targ->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS &&
+ mod != MOD_LEVEL2_ZAP && mod != MOD_POISON &&
+ mod != MOD_LEVEL1_PCLOUD && mod != MOD_HSPAWN &&
+ mod != MOD_ASPAWN && targ->client->poisonImmunityTime < level.time )
{
targ->client->ps.stats[ STAT_STATE ] |= SS_POISONED;
targ->client->lastPoisonTime = level.time;
targ->client->lastPoisonClient = attacker;
- attacker->client->pers.statscounters.repairspoisons++;
- level.alienStatsCounters.repairspoisons++;
}
}
}
@@ -1410,90 +1137,23 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
targ->health, take, asave );
}
- takeNoOverkill = take;
- if( takeNoOverkill > targ->health )
- {
- if(targ->health > 0)
- takeNoOverkill = targ->health;
- else
- takeNoOverkill = 0;
- }
-
+ // do the damage
if( take )
{
- //Increment some stats counters
- if( attacker && attacker->client )
- {
- if( targ->biteam == attacker->client->pers.teamSelection || OnSameTeam( targ, attacker ) )
- {
- attacker->client->pers.statscounters.ffdmgdone += takeNoOverkill;
- if( attacker->client->pers.teamSelection == PTE_ALIENS )
- {
- level.alienStatsCounters.ffdmgdone+=takeNoOverkill;
- }
- else if( attacker->client->pers.teamSelection == PTE_HUMANS )
- {
- level.humanStatsCounters.ffdmgdone+=takeNoOverkill;
- }
- }
- else if( targ->s.eType == ET_BUILDABLE )
- {
- attacker->client->pers.statscounters.structdmgdone += takeNoOverkill;
-
- if( attacker->client->pers.teamSelection == PTE_ALIENS )
- {
- level.alienStatsCounters.structdmgdone+=takeNoOverkill;
- }
- else if( attacker->client->pers.teamSelection == PTE_HUMANS )
- {
- level.humanStatsCounters.structdmgdone+=takeNoOverkill;
- }
-
- if( targ->health > 0 && ( targ->health - take ) <=0 )
- {
- attacker->client->pers.statscounters.structskilled++;
- if( attacker->client->pers.teamSelection == PTE_ALIENS )
- {
- level.alienStatsCounters.structskilled++;
- }
- else if( attacker->client->pers.teamSelection == PTE_HUMANS )
- {
- level.humanStatsCounters.structskilled++;
- }
- }
- }
- else if( targ->client )
- {
- attacker->client->pers.statscounters.dmgdone +=takeNoOverkill;
- attacker->client->pers.statscounters.hits++;
- if( attacker->client->pers.teamSelection == PTE_ALIENS )
- {
- level.alienStatsCounters.dmgdone+=takeNoOverkill;
- }
- else if( attacker->client->pers.teamSelection == PTE_HUMANS )
- {
- level.humanStatsCounters.dmgdone+=takeNoOverkill;
- }
- }
- }
-
-
- //Do the damage
targ->health = targ->health - take;
if( targ->client )
+ {
targ->client->ps.stats[ STAT_HEALTH ] = targ->health;
+ targ->client->pers.infoChangeTime = level.time;
+ }
targ->lastDamageTime = level.time;
+ targ->nextRegenTime = level.time + ALIEN_REGEN_DAMAGE_TIME;
- //TA: add to the attackers "account" on the target
- if( targ->client && attacker->client )
- {
- if( attacker != targ && !OnSameTeam( targ, attacker ) )
- targ->credits[ attacker->client->ps.clientNum ] += take;
- else if( attacker != targ && OnSameTeam( targ, attacker ) )
- targ->client->tkcredits[ attacker->client->ps.clientNum ] += takeNoOverkill;
- }
+ // add to the attackers "account" on the target
+ if( attacker->client && attacker != targ )
+ targ->credits[ attacker->client->ps.clientNum ] += take;
if( targ->health <= 0 )
{
@@ -1501,7 +1161,11 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
targ->flags |= FL_NO_KNOCKBACK;
if( targ->health < -999 )
+ {
targ->health = -999;
+ if( targ->client )
+ targ->client->ps.stats[ STAT_HEALTH ] = -999;
+ }
targ->enemy = attacker;
targ->die( targ, inflictor, attacker, take, mod );
@@ -1570,8 +1234,6 @@ qboolean CanDamage( gentity_t *targ, vec3_t origin )
return qfalse;
}
-
-//TA:
/*
============
G_SelectiveRadiusDamage
@@ -1611,6 +1273,9 @@ qboolean G_SelectiveRadiusDamage( vec3_t origin, gentity_t *attacker, float dama
if( !ent->takedamage )
continue;
+ if( ent->flags & FL_NOTARGET )
+ continue;
+
// find the distance from the edge of the bounding box
for( i = 0 ; i < 3 ; i++ )
{
@@ -1628,14 +1293,16 @@ qboolean G_SelectiveRadiusDamage( vec3_t origin, gentity_t *attacker, float dama
points = damage * ( 1.0 - dist / radius );
- if( CanDamage( ent, origin ) )
+ if( CanDamage( ent, origin ) && ent->client &&
+ ent->client->ps.stats[ STAT_TEAM ] != team )
{
VectorSubtract( ent->r.currentOrigin, origin, dir );
// push the center of mass higher than the origin so players
// get knocked into the air more
dir[ 2 ] += 24;
- G_SelectiveDamage( ent, NULL, attacker, dir, origin,
- (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE, mod, team );
+ hitClient = qtrue;
+ G_Damage( ent, NULL, attacker, dir, origin,
+ (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE, mod );
}
}
@@ -1649,7 +1316,7 @@ G_RadiusDamage
============
*/
qboolean G_RadiusDamage( vec3_t origin, gentity_t *attacker, float damage,
- float radius, gentity_t *ignore, int dflags, int mod )
+ float radius, gentity_t *ignore, int mod )
{
float points, dist;
gentity_t *ent;
@@ -1705,8 +1372,9 @@ qboolean G_RadiusDamage( vec3_t origin, gentity_t *attacker, float damage,
// push the center of mass higher than the origin so players
// get knocked into the air more
dir[ 2 ] += 24;
+ hitClient = qtrue;
G_Damage( ent, NULL, attacker, dir, origin,
- (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE|dflags, mod );
+ (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE, mod );
}
}
@@ -1714,46 +1382,71 @@ qboolean G_RadiusDamage( vec3_t origin, gentity_t *attacker, float damage,
}
/*
-============
-G_Knockback
-============
+================
+G_LogDestruction
+
+Log deconstruct/destroy events
+================
*/
-void G_Knockback( gentity_t *targ, vec3_t dir, int knockback )
+void G_LogDestruction( gentity_t *self, gentity_t *actor, int mod )
{
- if( knockback && targ->client )
- {
- vec3_t kvel;
- float mass;
+ buildFate_t fate;
- mass = 200;
-
- // Halve knockback for bsuits
- if( targ->client &&
- targ->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS &&
- BG_InventoryContainsUpgrade( UP_BATTLESUIT, targ->client->ps.stats ) )
- mass += 400;
-
- // Halve knockback for crouching players
- if(targ->client->ps.pm_flags&PMF_DUCKED) knockback /= 2;
-
- VectorScale( dir, g_knockback.value * (float)knockback / mass, kvel );
- VectorAdd( targ->client->ps.velocity, kvel, targ->client->ps.velocity );
+ switch( mod )
+ {
+ case MOD_DECONSTRUCT:
+ fate = BF_DECONSTRUCT;
+ break;
+ case MOD_REPLACE:
+ fate = BF_REPLACE;
+ break;
+ case MOD_NOCREEP:
+ fate = ( actor->client ) ? BF_UNPOWER : BF_AUTO;
+ break;
+ default:
+ if( actor->client )
+ {
+ if( actor->client->pers.teamSelection ==
+ BG_Buildable( self->s.modelindex )->team )
+ {
+ fate = BF_TEAMKILL;
+ }
+ else
+ fate = BF_DESTROY;
+ }
+ else
+ fate = BF_AUTO;
+ break;
+ }
+ G_BuildLogAuto( actor, self, fate );
- // set the timer so that the other client can't cancel
- // out the movement immediately
- if( !targ->client->ps.pm_time )
- {
- int t;
+ // don't log when marked structures are removed
+ if( mod == MOD_REPLACE )
+ return;
- t = knockback * 2;
- if( t < 50 )
- t = 50;
+ G_LogPrintf( S_COLOR_YELLOW "Deconstruct: %d %d %s %s: %s %s by %s\n",
+ (int)( actor - g_entities ),
+ (int)( self - g_entities ),
+ BG_Buildable( self->s.modelindex )->name,
+ modNames[ mod ],
+ BG_Buildable( self->s.modelindex )->humanName,
+ mod == MOD_DECONSTRUCT ? "deconstructed" : "destroyed",
+ actor->client ? actor->client->pers.netname : "<world>" );
+
+ // No-power deaths for humans come after some minutes and it's confusing
+ // when the messages appear attributed to the deconner. Just don't print them.
+ if( mod == MOD_NOCREEP && actor->client &&
+ actor->client->pers.teamSelection == TEAM_HUMANS )
+ return;
- if( t > 200 )
- t = 200;
- targ->client->ps.pm_time = t;
- targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
- }
+ if( actor->client && actor->client->pers.teamSelection ==
+ BG_Buildable( self->s.modelindex )->team )
+ {
+ G_TeamCommand( actor->client->ps.stats[ STAT_TEAM ],
+ va( "print \"%s ^3%s^7 by %s\n\"",
+ BG_Buildable( self->s.modelindex )->humanName,
+ mod == MOD_DECONSTRUCT ? "DECONSTRUCTED" : "DESTROYED",
+ actor->client->pers.netname ) );
}
-}
+}
diff --git a/src/game/g_local.h b/src/game/g_local.h
index df16a84..f894ec2 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,14 +17,14 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// g_local.h -- local definitions for game module
-#include "../qcommon/q_shared.h"
+#include "qcommon/q_shared.h"
#include "bg_public.h"
#include "g_public.h"
@@ -37,11 +38,8 @@ typedef struct gclient_s gclient_t;
#define INFINITE 1000000
#define FRAMETIME 100 // msec
-#define CARNAGE_REWARD_TIME 3000
-#define REWARD_SPRITE_TIME 2000
#define INTERMISSION_DELAY_TIME 1000
-#define SP_INTERMISSION_DELAY_TIME 5000
// gentity->flags
#define FL_GODMODE 0x00000010
@@ -53,19 +51,6 @@ typedef struct gclient_s gclient_t;
#define FL_NO_HUMANS 0x00004000 // spawn point just for bots
#define FL_FORCE_GESTURE 0x00008000 // spawn point just for bots
-typedef struct
-{
- qboolean isNB;
- float Area;
- float Height;
-} noBuild_t;
-
-typedef struct
-{
- gentity_t *Marker;
- vec3_t Origin;
-} nbMarkers_t;
-
// movers are things like doors, plats, buttons, etc
typedef enum
{
@@ -87,6 +72,12 @@ typedef enum
#define SP_PODIUM_MODEL "models/mapobjects/podium/podium4.md3"
+typedef struct gitem_s
+{
+ int ammo; // ammo held
+ int clips; // clips held
+} gitem_t;
+
//============================================================================
struct gentity_s
@@ -99,6 +90,7 @@ struct gentity_s
//================================
struct gclient_s *client; // NULL if not a client
+ gitem_t item;
qboolean inuse;
@@ -134,7 +126,6 @@ struct gentity_s
int soundLoop;
gentity_t *parent;
gentity_t *nextTrain;
- gentity_t *prevTrain;
vec3_t pos1, pos2;
float rotatorAngle;
gentity_t *clipBrush; // clipping brush for model doors
@@ -143,7 +134,6 @@ struct gentity_s
int timestamp; // body queue sinking, etc
- float angle; // set in editor, -1 = up, -2 = down
char *target;
char *targetname;
char *team;
@@ -172,7 +162,6 @@ struct gentity_s
void (*die)( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod );
int pain_debounce_time;
- int fly_sound_debounce_time; // wind tunnel
int last_move_time;
int health;
@@ -181,12 +170,10 @@ struct gentity_s
qboolean takedamage;
int damage;
- int dflags;
int splashDamage; // quad will increase this without increasing radius
int splashRadius;
int methodOfDeath;
int splashMethodOfDeath;
- int chargeRepeat;
int count;
@@ -205,18 +192,18 @@ struct gentity_s
float wait;
float random;
- pTeam_t stageTeam;
+ team_t stageTeam;
stage_t stageStage;
- int biteam; // buildable item team
+ team_t buildableTeam; // buildable item team
gentity_t *parentNode; // for creep and defence/spawn dependencies
+ gentity_t *rangeMarker;
qboolean active; // for power repeater, but could be useful elsewhere
qboolean powered; // for human buildables
- int builtBy; // clientNum of person that built this
- gentity_t *dccNode; // controlling dcc
- gentity_t *overmindNode; // controlling overmind
- qboolean dcced; // controlled by a dcc or not?
+ struct namelog_s *builtBy; // person who built this
+ int dcc; // number of controlling dccs
qboolean spawned; // whether or not this buildable has finished spawning
+ int shrunkTime; // time when a barricade shrunk or zero
int buildTime; // when this buildable was built
int animTime; // last animation change
int time1000; // timer evaluated every second
@@ -228,25 +215,20 @@ struct gentity_s
int nextPhysicsTime; // buildables don't need to check what they're sitting on
// every single frame.. so only do it periodically
int clientSpawnTime; // the time until this spawn can spawn a client
- qboolean lev1Grabbed; // for turrets interacting with lev1s
- int lev1GrabTime; // for turrets interacting with lev1s
- int spawnBlockTime;
int credits[ MAX_CLIENTS ]; // human credits for each client
- qboolean creditsHash[ MAX_CLIENTS ]; // track who has claimed credit
int killedBy; // clientNum of killer
- gentity_t *targeted; // true if the player is currently a valid target of a turret
vec3_t turretAim; // aim vector for turrets
+ vec3_t turretAimRate; // track turn speed for norfenturrets
+ int turretSpinupTime; // spinup delay for norfenturrets
vec4_t animation; // animated map objects
- gentity_t *builder; // occupant of this hovel
-
qboolean nonSegModel; // this entity uses a nonsegmented player model
buildable_t bTriggers[ BA_NUM_BUILDABLES ]; // which buildables are triggers
- pClass_t cTriggers[ PCL_NUM_CLASSES ]; // which classes are triggers
+ class_t cTriggers[ PCL_NUM_CLASSES ]; // which classes are triggers
weapon_t wTriggers[ WP_NUM_WEAPONS ]; // which weapons are triggers
upgrade_t uTriggers[ UP_NUM_UPGRADES ]; // which upgrades are triggers
@@ -255,11 +237,12 @@ struct gentity_s
int suicideTime; // when the client will suicide
int lastDamageTime;
-
- int bdnumb; // buildlog entry ID
-
- // For nobuild!
- noBuild_t noBuild;
+ int nextRegenTime;
+
+ qboolean pointAgainstWorld; // don't use the bbox for map collisions
+
+ int buildPointZone; // index for zone
+ int usesBuildPointZone; // does it use a zone?
};
typedef enum
@@ -269,125 +252,46 @@ typedef enum
CON_CONNECTED
} clientConnected_t;
-typedef enum
-{
- SPECTATOR_NOT,
- SPECTATOR_FREE,
- SPECTATOR_LOCKED,
- SPECTATOR_FOLLOW,
- SPECTATOR_SCOREBOARD
-} spectatorState_t;
-
-typedef enum
-{
- TEAM_BEGIN, // Beginning a team game, spawn at base
- TEAM_ACTIVE // Now actively playing
-} playerTeamStateState_t;
-
-typedef struct
-{
- playerTeamStateState_t state;
-
- int location;
-
- int captures;
- int basedefense;
- int carrierdefense;
- int flagrecovery;
- int fragcarrier;
- int assists;
-
- float lasthurtcarrier;
- float lastreturnedflag;
- float flagsince;
- float lastfraggedcarrier;
-} playerTeamState_t;
-
-// the auto following clients don't follow a specific client
-// number, but instead follow the first two active players
-#define FOLLOW_ACTIVE1 -1
-#define FOLLOW_ACTIVE2 -2
-
// client data that stays across multiple levels or tournament restarts
// this is achieved by writing all the data to cvar strings at game shutdown
// time and reading them back at connection time. Anything added here
// MUST be dealt with in G_InitSessionData() / G_ReadSessionData() / G_WriteSessionData()
typedef struct
{
- team_t sessionTeam;
- pTeam_t restartTeam; //for !restart keepteams and !restart switchteams
int spectatorTime; // for determining next-in-line to play
spectatorState_t spectatorState;
int spectatorClient; // for chasecam and follow mode
- int wins, losses; // tournament stats
- qboolean invisible; // for being invisible on the server - ghosts!
- qboolean teamLeader; // true when this client is a team leader
+ team_t restartTeam; //for !restart keepteams and !restart switchteams
clientList_t ignoreList;
} clientSession_t;
-#define MAX_NETNAME 36
-
-// data to store details of clients that have abnormally disconnected
-typedef struct connectionRecord_s
+// namelog
+#define MAX_NAMELOG_NAMES 5
+#define MAX_NAMELOG_ADDRS 5
+typedef struct namelog_s
{
- int clientNum;
- pTeam_t clientTeam;
- int clientCredit;
- int clientScore;
- int clientEnterTime;
+ struct namelog_s *next;
+ char name[ MAX_NAMELOG_NAMES ][ MAX_NAME_LENGTH ];
+ addr_t ip[ MAX_NAMELOG_ADDRS ];
+ char guid[ 33 ];
+ qboolean guidless;
+ int slot;
+ qboolean banned;
- int ptrCode;
-} connectionRecord_t;
+ int nameOffset;
+ int nameChangeTime;
+ int nameChanges;
+ int voteCount;
-typedef struct
-{
- short kills;
- short deaths;
- short feeds;
- short suicides;
- short assists;
- int dmgdone;
- int ffdmgdone;
- int structdmgdone;
- short structsbuilt;
- short repairspoisons;
- short structskilled;
- int timealive;
- int timeinbase;
- short headshots;
- int hits;
- int hitslocational;
- short teamkills;
- int dretchbasytime;
- int jetpackusewallwalkusetime;
- int timeLastViewed;
- int AllstatstimeLastViewed;
- int spreebleeds;
-} statsCounters_t;
+ qboolean muted;
+ qboolean denyBuild;
-typedef struct
-{
- int kills;
- int deaths;
- int feeds;
- int suicides;
- int assists;
- long dmgdone;
- long ffdmgdone;
- long structdmgdone;
- int structsbuilt;
- int repairspoisons;
- int structskilled;
- long timealive;
- long timeinbase;
- int headshots;
- long hits;
- long hitslocational;
- int teamkills;
- long dretchbasytime;
- long jetpackusewallwalkusetime;
- long timeLastViewed;
-} statsCounters_level;
+ int score;
+ int credits;
+ team_t team;
+
+ int id;
+} namelog_t;
// client data that stays across multiple respawns, but is cleared
// on each level change or team change at ClientBegin()
@@ -396,66 +300,51 @@ typedef struct
clientConnected_t connected;
usercmd_t cmd; // we would lose angles if not persistant
qboolean localClient; // true if "ip" info key is "localhost"
- qboolean initialSpawn; // the first spawn should be at a cool location
- qboolean predictItemPickup; // based on cg_predictItems userinfo
+ qboolean stickySpec; // don't stop spectating a player after they get killed
qboolean pmoveFixed; //
- char netname[ MAX_NETNAME ];
- int maxHealth; // for handicapping
+ char netname[ MAX_NAME_LENGTH ];
int enterTime; // level.time the client entered the game
- playerTeamState_t teamState; // status in teamplay games
- int voteCount; // to prevent people from constantly calling votes
- qboolean teamInfo; // send team overlay updates?
+ int location; // player locations
+ int teamInfo; // level.time of team overlay update (disabled = 0)
+ float flySpeed; // for spectator/noclip moves
+ qboolean disableBlueprintErrors; // should the buildable blueprint never be hidden from the players?
+ int buildableRangeMarkerMask;
- pClass_t classSelection; // player class (copied to ent->client->ps.stats[ STAT_PCLASS ] once spawned)
+ class_t classSelection; // player class (copied to ent->client->ps.stats[ STAT_CLASS ] once spawned)
float evolveHealthFraction;
weapon_t humanItemSelection; // humans have a starting item
- pTeam_t teamSelection; // player team (copied to ps.stats[ STAT_PTEAM ])
+ team_t teamSelection; // player team (copied to ps.stats[ STAT_TEAM ])
int teamChangeTime; // level.time of last team change
- qboolean joinedATeam; // used to tell when a PTR code is valid
- connectionRecord_t *connection;
+ namelog_t *namelog;
+ g_admin_admin_t *admin;
- int nameChangeTime;
- int nameChanges;
+ int secondsAlive; // time player has been alive in seconds
+ qboolean hasHealed; // has healed a player (basi regen aura) in the last 10sec (for score use)
- // used to save playerState_t values while in SPECTATOR_FOLLOW mode
- int score;
+ // used to save persistant[] values while in SPECTATOR_FOLLOW mode
int credit;
- int ping;
-
- int lastTeamStatus;
- int lastFreekillTime;
- int lastFloodTime; // level.time of last flood-limited command
- int floodDemerits; // number of flood demerits accumulated
+ int voted;
+ int vote;
- char lastMessage[ MAX_SAY_TEXT ]; // last message said by this player
- int lastMessageTime; // level.time of last message said by this player
-
- int lastTeamKillTime; // level.time of last team kill
- int teamKillDemerits; // number of team kill demerits accumulated
+ // flood protection
+ int floodDemerits;
+ int floodTime;
vec3_t lastDeathLocation;
+ int alternateProtocol;
char guid[ 33 ];
- char ip[ 16 ];
- qboolean paused;
- qboolean muted;
- int muteExpires; // level.time at which a player is unmuted
- qboolean ignoreAdminWarnings;
- qboolean denyBuild;
- int specExpires; // level.time at which a player can join a team again after being forced into spectator
- int denyHumanWeapons;
- int denyAlienClasses;
- int adminLevel;
- char adminName[ MAX_NETNAME ];
- qboolean designatedBuilder;
- qboolean firstConnect; // This is the first map since connect
+ qboolean guidless;
+ addr_t ip;
+ char voice[ MAX_VOICE_NAME_LEN ];
qboolean useUnlagged;
- statsCounters_t statscounters;
- int bubbleTime;
+
+ // level.time when teamoverlay info changed so we know to tell other players
+ int infoChangeTime;
} clientPersistant_t;
-#define MAX_UNLAGGED_MARKERS 10
+#define MAX_UNLAGGED_MARKERS 256
typedef struct unlagged_s {
vec3_t origin;
vec3_t mins;
@@ -463,6 +352,7 @@ typedef struct unlagged_s {
qboolean used;
} unlagged_t;
+#define MAX_TRAMPLE_BUILDABLES_TRACKED 20
// this structure is cleared on each ClientSpawn(),
// except for 'client->pers' and 'client->sess'
struct gclient_s
@@ -480,6 +370,7 @@ struct gclient_s
qboolean readyToExit; // wishes to leave the intermission
qboolean noclip;
+ int cliprcontents; // the backup layer of ent->r.contents for when noclipping
int lastCmdTime; // level.time of last usercmd_t, for EF_CONNECTION
// we can't just use pers.lastCommand.time, because
@@ -508,6 +399,7 @@ struct gclient_s
int inactivityTime; // kick players when time > this
qboolean inactivityWarning;// qtrue if the five seoond warning has been given
int rewardTime; // clear the EF_AWARD_IMPRESSIVE, etc when time > this
+ int boostedTime; // last time we touched a booster
int airOutTime;
@@ -517,53 +409,43 @@ struct gclient_s
int switchTeamTime; // time the player switched teams
- // timeResidual is used to handle events that happen every second
- // like health / armor countdowns and regeneration
- // two timers, one every 100 msecs, another every sec
- int time100;
- int time1000;
- int time10000;
+ int time100; // timer for 100ms interval events
+ int time1000; // timer for one second interval events
+ int time10000; // timer for ten second interval events
char *areabits;
- gentity_t *hovel;
-
int lastPoisonTime;
int poisonImmunityTime;
gentity_t *lastPoisonClient;
int lastPoisonCloudedTime;
- gentity_t *lastPoisonCloudedClient;
int grabExpiryTime;
int lastLockTime;
int lastSlowTime;
- int lastBoostedTime;
int lastMedKitTime;
int medKitHealthToRestore;
int medKitIncrementTime;
int lastCreepSlowTime; // time until creep can be removed
- qboolean allowedToPounce;
-
qboolean charging;
- float jetpackfuel;
-
- vec3_t hovelOrigin; // player origin before entering hovel
-
int lastFlameBall; // s.number of the last flame ball fired
-#define RAM_FRAMES 1 // number of frames to wait before retriggering
- int retriggerArmouryMenu; // frame number to retrigger the armoury menu
-
unlagged_t unlaggedHist[ MAX_UNLAGGED_MARKERS ];
unlagged_t unlaggedBackup;
unlagged_t unlaggedCalc;
int unlaggedTime;
-
- int tkcredits[ MAX_CLIENTS ];
-};
+ float voiceEnthusiasm;
+ char lastVoiceCmd[ MAX_VOICE_CMD_LEN ];
+ int lcannonStartTime;
+ int trampleBuildablesHitPos;
+ int trampleBuildablesHit[ MAX_TRAMPLE_BUILDABLES_TRACKED ];
+
+ int lastCrushTime; // Tyrant crush
+ int lastDropTime; // Weapon drop with /drop
+};
typedef struct spawnQueue_s
{
@@ -583,35 +465,30 @@ qboolean G_SearchSpawnQueue( spawnQueue_t *sq, int clientNum );
qboolean G_PushSpawnQueue( spawnQueue_t *sq, int clientNum );
qboolean G_RemoveFromSpawnQueue( spawnQueue_t *sq, int clientNum );
int G_GetPosInSpawnQueue( spawnQueue_t *sq, int clientNum );
+void G_PrintSpawnQueue( spawnQueue_t *sq );
-#define MAX_LOCDAMAGE_TEXT 8192
-#define MAX_LOCDAMAGE_REGIONS 16
+#define MAX_DAMAGE_REGION_TEXT 8192
+#define MAX_DAMAGE_REGIONS 16
-// store locational damage regions
-typedef struct damageRegion_s
+// build point zone
+typedef struct
{
- float minHeight, maxHeight;
- int minAngle, maxAngle;
+ int active;
- float modifier;
+ int totalBuildPoints;
+ int queuedBuildPoints;
+ int nextQueueTime;
+} buildPointZone_t;
- qboolean crouch;
-} damageRegion_t;
-
-#define MAX_ARMOUR_TEXT 8192
-#define MAX_ARMOUR_REGIONS 16
-
-// store locational armour regions
-typedef struct armourRegion_s
+// store locational damage regions
+typedef struct damageRegion_s
{
- float minHeight, maxHeight;
+ char name[ 32 ];
+ float area, modifier, minHeight, maxHeight;
int minAngle, maxAngle;
-
- float modifier;
-
qboolean crouch;
-} armourRegion_t;
+} damageRegion_t;
//status of the warning of certain events
typedef enum
@@ -621,37 +498,43 @@ typedef enum
TW_PASSED
} timeWarning_t;
+// fate of a buildable
typedef enum
{
- BF_BUILT,
- BF_DECONNED,
- BF_DESTROYED,
- BF_TEAMKILLED
-} buildableFate_t;
-
-// record all changes to the buildable layout - build, decon, destroy - and
-// enough information to revert that change
-typedef struct buildHistory_s buildHistory_t;
-struct buildHistory_s
+ BF_CONSTRUCT,
+ BF_DECONSTRUCT,
+ BF_REPLACE,
+ BF_DESTROY,
+ BF_TEAMKILL,
+ BF_UNPOWER,
+ BF_AUTO
+} buildFate_t;
+
+// data needed to revert a change in layout
+typedef struct
{
- int ID; // persistent ID to aid in specific reverting
- gentity_t *ent; // who, NULL if they've disconnected (or aren't an ent)
- char name[ MAX_NETNAME ]; // who, saves name if ent is NULL
- int buildable; // what
- vec3_t origin; // where
- vec3_t angles; // which way round
- vec3_t origin2; // I don't know what the hell these are, but layoutsave saves
- vec3_t angles2; // them so I will do the same
- buildableFate_t fate; // was it built, destroyed or deconned
- buildHistory_t *next; // next oldest change
- buildHistory_t *marked; // linked list of markdecon buildings taken
-};
+ int time;
+ buildFate_t fate;
+ namelog_t *actor;
+ namelog_t *builtBy;
+ buildable_t modelindex;
+ qboolean deconstruct;
+ int deconstructTime;
+ vec3_t origin;
+ vec3_t angles;
+ vec3_t origin2;
+ vec3_t angles2;
+ buildable_t powerSource;
+ int powerValue;
+} buildLog_t;
//
// this structure is cleared as each map is entered
//
#define MAX_SPAWN_VARS 64
#define MAX_SPAWN_VARS_CHARS 4096
+#define MAX_BUILDLOG 128
+#define MAX_PLAYER_MODEL 256
typedef struct
{
@@ -659,7 +542,9 @@ typedef struct
struct gentity_s *gentities;
int gentitySize;
- int num_entities; // current number, <= MAX_GENTITIES
+ int num_entities; // MAX_CLIENTS <= num_entities <= ENTITYNUM_MAX_NORMAL
+
+ int warmupTime; // restart match at this time
fileHandle_t logFile;
@@ -673,7 +558,7 @@ typedef struct
int startTime; // level.time the map was started
- int teamScores[ TEAM_NUM_TEAMS ];
+ int teamScores[ NUM_TEAMS ];
int lastTeamLocationTime; // last time of client team location update
qboolean newSession; // don't use any old session data, because
@@ -686,27 +571,20 @@ typedef struct
int numPlayingClients; // connected, non-spectators
int sortedClients[MAX_CLIENTS]; // sorted by score
- int numNewbies; // number of UnnamedPlayers who have been renamed this round.
-
int snd_fry; // sound index for standing in lava
+ int warmupModificationCount; // for detecting if g_warmup is changed
+
// voting state
- char voteString[MAX_STRING_CHARS];
- char voteDisplayString[MAX_STRING_CHARS];
- int votePassThreshold;
- int voteTime; // level.time vote was called
- int voteExecuteTime; // time the vote is executed
- int voteYes;
- int voteNo;
- int numVotingClients; // set by CalculateRanks
-
- // team voting state
- char teamVoteString[ 2 ][ MAX_STRING_CHARS ];
- char teamVoteDisplayString[ 2 ][ MAX_STRING_CHARS ];
- int teamVoteTime[ 2 ]; // level.time vote was called
- int teamVoteYes[ 2 ];
- int teamVoteNo[ 2 ];
- int numteamVotingClients[ 2 ]; // set by CalculateRanks
+ int voteThreshold[ NUM_TEAMS ]; // need at least this percent to pass
+ char voteString[ NUM_TEAMS ][ MAX_STRING_CHARS ];
+ char voteDisplayString[ NUM_TEAMS ][ MAX_STRING_CHARS ];
+ int voteTime[ NUM_TEAMS ]; // level.time vote was called
+ int voteExecuteTime[ NUM_TEAMS ]; // time the vote is executed
+ int voteDelay[ NUM_TEAMS ]; // it doesn't make sense to always delay vote execution
+ int voteYes[ NUM_TEAMS ];
+ int voteNo[ NUM_TEAMS ];
+ int numVotingClients[ NUM_TEAMS ];// set by CalculateRanks
// spawn variables
qboolean spawning; // the G_Spawn*() functions are valid
@@ -716,6 +594,7 @@ typedef struct
char spawnVarChars[ MAX_SPAWN_VARS_CHARS ];
// intermission state
+ qboolean exited;
int intermissionQueued; // intermission was qualified, but
// wait INTERMISSION_DELAY_TIME before
// actually going there so the last
@@ -728,7 +607,6 @@ typedef struct
vec3_t intermission_origin; // also used for spectator spawns
vec3_t intermission_angle;
- qboolean locationLinked; // target_locations get linked
gentity_t *locationHead; // head of the location list
int numAlienSpawns;
@@ -742,12 +620,17 @@ typedef struct
float averageNumHumanClients;
int numHumanSamples;
- int numLiveAlienClients;
- int numLiveHumanClients;
+ int numAlienClientsAlive;
+ int numHumanClientsAlive;
int alienBuildPoints;
+ int alienBuildPointQueue;
+ int alienNextQueueTime;
int humanBuildPoints;
- int humanBuildPointsPowered;
+ int humanBuildPointQueue;
+ int humanNextQueueTime;
+
+ buildPointZone_t *buildPointZones;
gentity_t *markedBuildables[ MAX_GENTITIES ];
int numBuildablesForRemoval;
@@ -755,21 +638,15 @@ typedef struct
int alienKills;
int humanKills;
- qboolean reactorPresent;
- qboolean overmindPresent;
qboolean overmindMuted;
int humanBaseAttackTimer;
- pTeam_t lastWin;
+ team_t lastWin;
- int suddenDeathABuildPoints;
- int suddenDeathHBuildPoints;
- qboolean suddenDeath;
int suddenDeathBeginTime;
timeWarning_t suddenDeathWarning;
timeWarning_t timelimitWarning;
- int extend_vote_count;
spawnQueue_t alienSpawnQueue;
spawnQueue_t humanSpawnQueue;
@@ -783,48 +660,41 @@ typedef struct
qboolean uncondHumanWin;
qboolean alienTeamLocked;
qboolean humanTeamLocked;
- qboolean paused;
- int pauseTime;
- float pause_speed;
- float pause_gravity;
- float pause_knockback;
- int pause_ff;
- int pause_ffb;
-
- int lastCreditedAlien;
- int lastCreditedHuman;
+ int pausedTime;
int unlaggedIndex;
int unlaggedTimes[ MAX_UNLAGGED_MARKERS ];
char layout[ MAX_QPATH ];
- pTeam_t surrenderTeam;
- buildHistory_t *buildHistory;
- int lastBuildID;
- int lastTeamUnbalancedTime;
- int numTeamWarnings;
- int lastMsgTime;
- int mapRotationVoteTime;
-
- statsCounters_level alienStatsCounters;
- statsCounters_level humanStatsCounters;
-
- qboolean noBuilding;
- float nbArea;
- float nbHeight;
+ team_t surrenderTeam;
+ int lastTeamImbalancedTime;
+ int numTeamImbalanceWarnings;
+
+ voice_t *voices;
+
+ emoticon_t emoticons[ MAX_EMOTICONS ];
+ int emoticonCount;
- nbMarkers_t nbMarkers[ MAX_GENTITIES ];
+ char *playerModel[ MAX_PLAYER_MODEL ];
+ int playerModelCount;
+
+ namelog_t *namelogs;
+
+ buildLog_t buildLog[ MAX_BUILDLOG ];
+ int buildId;
+ int numBuildLogs;
} level_locals_t;
-#define CMD_CHEAT 0x01
-#define CMD_MESSAGE 0x02 // sends message to others (skip when muted)
-#define CMD_TEAM 0x04 // must be on a team
-#define CMD_NOTEAM 0x08 // must not be on a team
-#define CMD_ALIEN 0x10
-#define CMD_HUMAN 0x20
-#define CMD_LIVING 0x40
-#define CMD_INTERMISSION 0x80 // valid during intermission
+#define CMD_CHEAT 0x0001
+#define CMD_CHEAT_TEAM 0x0002 // is a cheat when used on a team
+#define CMD_MESSAGE 0x0004 // sends message to others (skip when muted)
+#define CMD_TEAM 0x0008 // must be on a team
+#define CMD_SPEC 0x0010 // must be a spectator
+#define CMD_ALIEN 0x0020
+#define CMD_HUMAN 0x0040
+#define CMD_ALIVE 0x0080
+#define CMD_INTERMISSION 0x0100 // valid during intermission
typedef struct
{
@@ -847,33 +717,31 @@ char *G_NewString( const char *string );
//
// g_cmds.c
//
-void Cmd_Score_f( gentity_t *ent );
-qboolean G_RoomForClassChange( gentity_t *ent, pClass_t class, vec3_t newOrigin );
-void G_StopFromFollowing( gentity_t *ent );
+
+#define DECOLOR_OFF '\16'
+#define DECOLOR_ON '\17'
+
void G_StopFollowing( gentity_t *ent );
+void G_StopFromFollowing( gentity_t *ent );
+void G_FollowLockView( gentity_t *ent );
qboolean G_FollowNewClient( gentity_t *ent, int dir );
void G_ToggleFollow( gentity_t *ent );
-qboolean G_MatchOnePlayer( int *plist, char *err, int len );
-int G_ClientNumbersFromString( char *s, int *plist );
-void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText );
-int G_SayArgc( void );
-qboolean G_SayArgv( int n, char *buffer, int bufferLength );
-char *G_SayConcatArgs( int start );
-void G_DecolorString( char *in, char *out );
-void G_ParseEscapedString( char *buffer );
-void G_LeaveTeam( gentity_t *self );
-void G_ChangeTeam( gentity_t *ent, pTeam_t newTeam );
+int G_ClientNumberFromString( char *s, char *err, int len );
+int G_ClientNumbersFromString( char *s, int *plist, int max );
+char *ConcatArgs( int start );
+char *ConcatArgsPrintable( int start );
+void G_Say( gentity_t *ent, saymode_t mode, const char *chatText );
+void G_DecolorString( const char *in, char *out, int len );
+void G_UnEscapeString( char *in, char *out, int len );
void G_SanitiseString( char *in, char *out, int len );
-void G_PrivateMessage( gentity_t *ent );
-char *G_statsString( statsCounters_t *sc, pTeam_t *pt );
-void Cmd_Share_f( gentity_t *ent );
-void Cmd_Donate_f( gentity_t *ent );
-void Cmd_TeamVote_f( gentity_t *ent );
-void Cmd_Builder_f( gentity_t *ent );
-void G_WordWrap( char *buffer, int maxwidth );
-void G_CP( gentity_t *ent );
-qboolean G_IsMuted( gclient_t *ent );
-qboolean G_TeamKill_Repent( gentity_t *ent );
+void Cmd_PrivateMessage_f( gentity_t *ent );
+void Cmd_ListMaps_f( gentity_t *ent );
+void Cmd_Test_f( gentity_t *ent );
+void Cmd_AdminMessage_f( gentity_t *ent );
+int G_FloodLimited( gentity_t *ent );
+void G_ListCommands( gentity_t *ent );
+void G_LoadCensors( void );
+void G_CensorString( char *out, const char *in, int len, gentity_t *ent );
//
// g_physics.c
@@ -891,69 +759,80 @@ typedef enum
IBE_NONE,
IBE_NOOVERMIND,
- IBE_OVERMIND,
- IBE_NOASSERT,
- IBE_SPWNWARN,
+ IBE_ONEOVERMIND,
+ IBE_NOALIENBP,
+ IBE_SPWNWARN, // not currently used
IBE_NOCREEP,
- IBE_HOVEL,
- IBE_HOVELEXIT,
-
- IBE_REACTOR,
- IBE_REPEATER,
- IBE_TNODEWARN,
- IBE_RPTWARN,
- IBE_RPTWARN2,
- IBE_NOPOWER,
+
+ IBE_ONEREACTOR,
+ IBE_NOPOWERHERE,
+ IBE_TNODEWARN, // not currently used
+ IBE_RPTNOREAC,
+ IBE_RPTPOWERHERE,
+ IBE_NOHUMANBP,
IBE_NODCC,
- IBE_NORMAL,
+ IBE_NORMAL, // too steep
IBE_NOROOM,
IBE_PERMISSION,
+ IBE_LASTSPAWN,
IBE_MAXERRORS
} itemBuildError_t;
-qboolean AHovel_Blocked( gentity_t *hovel, gentity_t *player, qboolean provideExit );
-gentity_t *G_CheckSpawnPoint( int spawnNum, vec3_t origin, vec3_t normal,
- buildable_t spawn, vec3_t spawnOrigin );
+gentity_t *G_CheckSpawnPoint( int spawnNum, const vec3_t origin,
+ const vec3_t normal, buildable_t spawn,
+ vec3_t spawnOrigin );
-qboolean G_IsPowered( vec3_t origin );
+buildable_t G_IsPowered( vec3_t origin );
qboolean G_IsDCCBuilt( void );
-qboolean G_IsOvermindBuilt( void );
+int G_FindDCC( gentity_t *self );
+gentity_t *G_Reactor( void );
+gentity_t *G_Overmind( void );
+qboolean G_FindCreep( gentity_t *self );
void G_BuildableThink( gentity_t *ent, int msec );
qboolean G_BuildableRange( vec3_t origin, float r, buildable_t buildable );
-itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance, vec3_t origin );
-qboolean G_BuildingExists( int bclass ) ;
+void G_ClearDeconMarks( void );
+itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance,
+ vec3_t origin, vec3_t normal, int *groundEntNum );
qboolean G_BuildIfValid( gentity_t *ent, buildable_t buildable );
void G_SetBuildableAnim( gentity_t *ent, buildableAnimNumber_t anim, qboolean force );
void G_SetIdleBuildableAnim( gentity_t *ent, buildableAnimNumber_t anim );
void G_SpawnBuildable(gentity_t *ent, buildable_t buildable);
void FinishSpawningBuildable( gentity_t *ent );
-void G_CheckDBProtection( void );
void G_LayoutSave( char *name );
int G_LayoutList( const char *map, char *list, int len );
void G_LayoutSelect( void );
-void G_LayoutLoad( void );
-void G_BaseSelfDestruct( pTeam_t team );
-gentity_t *G_InstantBuild( buildable_t buildable, vec3_t origin, vec3_t angles, vec3_t origin2, vec3_t angles2 );
-void G_SpawnRevertedBuildable( buildHistory_t *bh, qboolean mark );
-void G_CommitRevertedBuildable( gentity_t *ent );
-qboolean G_RevertCanFit( buildHistory_t *bh );
-int G_LogBuild( buildHistory_t *new );
-int G_CountBuildLog( void );
-char *G_FindBuildLogName( int id );
-void G_NobuildSave( void );
-void G_NobuildLoad( void );
+void G_LayoutLoad( char *lstr );
+void G_BaseSelfDestruct( team_t team );
+int G_NextQueueTime( int queuedBP, int totalBP, int queueBaseRate );
+void G_QueueBuildPoints( gentity_t *self );
+int G_GetBuildPoints( const vec3_t pos, team_t team );
+int G_GetMarkedBuildPoints( const vec3_t pos, team_t team );
+qboolean G_FindPower( gentity_t *self, qboolean searchUnspawned );
+gentity_t *G_PowerEntityForPoint( const vec3_t origin );
+gentity_t *G_PowerEntityForEntity( gentity_t *ent );
+gentity_t *G_RepeaterEntityForPoint( vec3_t origin );
+gentity_t *G_InPowerZone( gentity_t *self );
+buildLog_t *G_BuildLogNew( gentity_t *actor, buildFate_t fate );
+void G_BuildLogSet( buildLog_t *log, gentity_t *ent );
+void G_BuildLogAuto( gentity_t *actor, gentity_t *buildable, buildFate_t fate );
+void G_BuildLogRevert( int id );
+void G_RemoveRangeMarkerFrom( gentity_t *self );
+void G_UpdateBuildableRangeMarkers( void );
//
// g_utils.c
//
-int G_ParticleSystemIndex( char *name );
-int G_ShaderIndex( char *name );
-int G_ModelIndex( char *name );
-int G_SoundIndex( char *name );
-void G_TeamCommand( pTeam_t team, char *cmd );
+//addr_t in g_admin.h for g_admin_ban_t
+qboolean G_AddressParse( const char *str, addr_t *addr );
+qboolean G_AddressCompare( const addr_t *a, const addr_t *b );
+
+int G_ParticleSystemIndex( const char *name );
+int G_ShaderIndex( const char *name );
+int G_ModelIndex( const char *name );
+int G_SoundIndex( const char *name );
void G_KillBox (gentity_t *ent);
gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match);
gentity_t *G_PickTarget (char *targetname);
@@ -962,15 +841,14 @@ void G_SetMovedir ( vec3_t angles, vec3_t movedir);
void G_InitGentity( gentity_t *e );
gentity_t *G_Spawn( void );
-gentity_t *G_TempEntity( vec3_t origin, int event );
+gentity_t *G_TempEntity( const vec3_t origin, int event );
void G_Sound( gentity_t *ent, int channel, int soundIndex );
void G_FreeEntity( gentity_t *e );
+void G_RemoveEntity( gentity_t *ent );
qboolean G_EntitiesFree( void );
void G_TouchTriggers( gentity_t *ent );
-void G_TouchSolids( gentity_t *ent );
-float *tv( float x, float y, float z );
char *vtos( const vec3_t v );
float vectoyaw( const vec3_t vec );
@@ -978,7 +856,7 @@ float vectoyaw( const vec3_t vec );
void G_AddPredictableEvent( gentity_t *ent, int event, int eventParm );
void G_AddEvent( gentity_t *ent, int event, int eventParm );
void G_BroadcastEvent( int event, int eventParm );
-void G_SetOrigin( gentity_t *ent, vec3_t origin );
+void G_SetOrigin( gentity_t *ent, const vec3_t origin );
void AddRemap(const char *oldShader, const char *newShader, float timeOffset);
const char *BuildShaderStateConfig( void );
@@ -986,9 +864,10 @@ const char *BuildShaderStateConfig( void );
qboolean G_ClientIsLagging( gclient_t *client );
void G_TriggerMenu( int clientNum, dynMenu_t menu );
+void G_TriggerMenuArgs( int clientNum, dynMenu_t menu, int arg );
void G_CloseMenus( int clientNum );
-qboolean G_Visible( gentity_t *ent1, gentity_t *ent2 );
+qboolean G_Visible( gentity_t *ent1, gentity_t *ent2, int contents );
gentity_t *G_ClosestEnt( vec3_t origin, gentity_t **entities, int numEntities );
//
@@ -1000,31 +879,32 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
void G_SelectiveDamage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_t dir,
vec3_t point, int damage, int dflags, int mod, int team );
qboolean G_RadiusDamage( vec3_t origin, gentity_t *attacker, float damage, float radius,
- gentity_t *ignore, int dflags, int mod );
+ gentity_t *ignore, int mod );
qboolean G_SelectiveRadiusDamage( vec3_t origin, gentity_t *attacker, float damage, float radius,
gentity_t *ignore, int mod, int team );
-void G_Knockback( gentity_t *targ, vec3_t dir, int knockback );
-void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath );
+float G_RewardAttackers( gentity_t *self );
void AddScore( gentity_t *ent, int score );
+void G_LogDestruction( gentity_t *self, gentity_t *actor, int mod );
void G_InitDamageLocations( void );
// damage flags
#define DAMAGE_RADIUS 0x00000001 // damage was indirect
#define DAMAGE_NO_ARMOR 0x00000002 // armour does not protect from this damage
-#define DAMAGE_KNOCKBACK 0x00000004 // affect velocity, not just view angles
-#define DAMAGE_NO_PROTECTION 0x00000008 // armor, shields, invulnerability, and godmode have no effect
+#define DAMAGE_NO_KNOCKBACK 0x00000004 // do not affect velocity, just view angles
+#define DAMAGE_NO_PROTECTION 0x00000008 // kills everything except godmode
#define DAMAGE_NO_LOCDAMAGE 0x00000010 // do not apply locational damage
//
// g_missile.c
//
+void G_BounceMissile( gentity_t *ent, trace_t *trace );
void G_RunMissile( gentity_t *ent );
gentity_t *fire_flamer( gentity_t *self, vec3_t start, vec3_t aimdir );
gentity_t *fire_blaster( gentity_t *self, vec3_t start, vec3_t dir );
gentity_t *fire_pulseRifle( gentity_t *self, vec3_t start, vec3_t dir );
-gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir, int damage, int radius );
+gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir, int damage, int radius, int speed );
gentity_t *fire_lockblob( gentity_t *self, vec3_t start, vec3_t dir );
gentity_t *fire_paraLockBlob( gentity_t *self, vec3_t start, vec3_t dir );
gentity_t *fire_slowBlob( gentity_t *self, vec3_t start, vec3_t dir );
@@ -1044,35 +924,44 @@ void manualTriggerSpectator( gentity_t *trigger, gentity_t *player );
// g_trigger.c
//
void trigger_teleporter_touch( gentity_t *self, gentity_t *other, trace_t *trace );
-void G_Checktrigger_stages( pTeam_t team, stage_t stage );
+void G_Checktrigger_stages( team_t team, stage_t stage );
//
// g_misc.c
//
-void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles );
-void ShineTorch( gentity_t *self );
+void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles, float speed );
//
-// g_weapon.c
+// g_playermodel.c
//
+void G_InitPlayerModel(void);
+qboolean G_IsValidPlayerModel(const char *model);
+void G_FreePlayerModel(void);
+void G_GetPlayerModelSkins( const char *modelname, char skins[][ 64 ], int maxskins, int *numskins );
+char *GetSkin( char *modelname, char *wish );
-#define MAX_ZAP_TARGETS LEVEL2_AREAZAP_MAX_TARGETS
+//
+// g_weapon.c
+//
typedef struct zap_s
{
qboolean used;
gentity_t *creator;
- gentity_t *targets[ MAX_ZAP_TARGETS ];
+ gentity_t *targets[ LEVEL2_AREAZAP_MAX_TARGETS ];
int numTargets;
+ float distances[ LEVEL2_AREAZAP_MAX_TARGETS ];
int timeToLive;
- int damageUsed;
gentity_t *effectChannel;
} zap_t;
+#define MAX_ZAPS MAX_CLIENTS
+extern zap_t zaps[ MAX_ZAPS ];
+
void G_ForceWeaponChange( gentity_t *ent, weapon_t weapon );
void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo );
void CalcMuzzlePoint( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint );
@@ -1080,35 +969,34 @@ void SnapVectorTowards( vec3_t v, vec3_t to );
qboolean CheckVenomAttack( gentity_t *ent );
void CheckGrabAttack( gentity_t *ent );
qboolean CheckPounceAttack( gentity_t *ent );
-void ChargeAttack( gentity_t *ent, gentity_t *victim );
+void CheckCkitRepair( gentity_t *ent );
+void G_ChargeAttack( gentity_t *ent, gentity_t *victim );
+void G_CrushAttack( gentity_t *ent, gentity_t *victim );
void G_UpdateZaps( int msec );
+void G_ClearPlayerZapEffects( gentity_t *player );
//
// g_client.c
//
void G_AddCreditToClient( gclient_t *client, short credit, qboolean cap );
-team_t TeamCount( int ignoreClientNum, int team );
-void G_SetClientViewAngle( gentity_t *ent, vec3_t angle );
-gentity_t *G_SelectTremulousSpawnPoint( pTeam_t team, vec3_t preference, vec3_t origin, vec3_t angles );
+void G_SetClientViewAngle( gentity_t *ent, const vec3_t angle );
+gentity_t *G_SelectTremulousSpawnPoint( team_t team, vec3_t preference, vec3_t origin, vec3_t angles );
gentity_t *G_SelectSpawnPoint( vec3_t avoidPoint, vec3_t origin, vec3_t angles );
gentity_t *G_SelectAlienLockSpawnPoint( vec3_t origin, vec3_t angles );
gentity_t *G_SelectHumanLockSpawnPoint( vec3_t origin, vec3_t angles );
-void SpawnCorpse( gentity_t *ent );
void respawn( gentity_t *ent );
void BeginIntermission( void );
-void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles );
+void ClientSpawn( gentity_t *ent, gentity_t *spawn, const vec3_t origin, const vec3_t angles );
void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod );
qboolean SpotWouldTelefrag( gentity_t *spot );
-char *G_NextNewbieName( gentity_t *ent );
-void G_LogAutobahn( gentity_t *ent, const char *userinfo, int rating, qboolean onConnect );
//
// g_svcmds.c
//
qboolean ConsoleCommand( void );
-void G_ProcessIPBans( void );
-qboolean G_FilterPacket( char *from );
+void G_RegisterCommands( void );
+void G_UnregisterCommands( void );
//
// g_weapon.c
@@ -1118,8 +1006,11 @@ void FireWeapon2( gentity_t *ent );
void FireWeapon3( gentity_t *ent );
//
-// g_cmds.c
+// g_weapondrop.c
//
+gentity_t *LaunchWeapon( gentity_t *client, weapon_t weap, vec3_t origin, vec3_t velocity );
+gentity_t *G_DropWeapon( gentity_t *ent, weapon_t w, float angle );
+void G_RunWeaponDrop(gentity_t *ent);
//
// g_main.c
@@ -1130,27 +1021,22 @@ void G_MapConfigs( const char *mapname );
void CalculateRanks( void );
void FindIntermissionPoint( void );
void G_RunThink( gentity_t *ent );
-void QDECL G_LogPrintf( const char *fmt, ... );
-void QDECL G_LogPrintfColoured( const char *fmt, ... );
-void QDECL G_LogOnlyPrintf( const char *fmt, ... );
-void QDECL G_AdminsPrintf( const char *fmt, ... );
-void QDECL G_WarningsPrintf( char *flag, const char *fmt, ... );
-void QDECL G_LogOnlyPrintf( const char *fmt, ... );
+void G_AdminMessage( gentity_t *ent, const char *string );
+void QDECL G_LogPrintf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2)));
void SendScoreboardMessageToAllClients( void );
-void QDECL G_Printf( const char *fmt, ... );
-void QDECL G_Error( const char *fmt, ... );
-void CheckVote( void );
-void CheckTeamVote( int teamnum );
+void QDECL G_Printf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2)));
+void QDECL G_Error( const char *fmt, ... ) __attribute__ ((noreturn, format (printf, 1, 2)));
+void G_Vote( gentity_t *ent, team_t team, qboolean voting );
+void G_ExecuteVote( team_t team );
+void G_CheckVote( team_t team );
void LogExit( const char *string );
int G_TimeTilSuddenDeath( void );
-void CheckMsgTimer( void );
-qboolean G_Flood_Limited( gentity_t *ent );
//
// g_client.c
//
-char *ClientConnect( int clientNum, qboolean firstTime );
-void ClientUserinfoChanged( int clientNum, qboolean forceName );
+const char *ClientConnect( int clientNum, qboolean firstTime );
+char *ClientUserinfoChanged( int clientNum, qboolean forceName );
void ClientDisconnect( int clientNum );
void ClientBegin( int clientNum );
void ClientCommand( int clientNum );
@@ -1170,20 +1056,15 @@ void G_RunClient( gentity_t *ent );
//
// g_team.c
//
+team_t G_TeamFromString( char *str );
+void G_TeamCommand( team_t team, const char *cmd );
qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 );
+void G_LeaveTeam( gentity_t *self );
+void G_ChangeTeam( gentity_t *ent, team_t newTeam );
gentity_t *Team_GetLocation( gentity_t *ent );
-qboolean Team_GetLocationMsg( gentity_t *ent, char *loc, int loclen );
void TeamplayInfoMessage( gentity_t *ent );
void CheckTeamStatus( void );
-
-//
-// g_mem.c
-//
-void *G_Alloc( int size );
-void G_InitMemory( void );
-void G_Free( void *ptr );
-void G_DefragmentMemory( void );
-void Svcmd_GameMem_f( void );
+void G_UpdateTeamConfigStrings( void );
//
// g_session.c
@@ -1195,100 +1076,28 @@ void G_WriteSessionData( void );
//
// g_maprotation.c
//
-#define MAX_MAP_ROTATIONS 64
-#define MAX_MAP_ROTATION_MAPS 64
-#define MAX_MAP_COMMANDS 16
-#define MAX_MAP_ROTATION_CONDS 8
-
-#define NOT_ROTATING -1
-
-typedef enum
-{
- MCV_ERR,
- MCV_RANDOM,
- MCV_NUMCLIENTS,
- MCV_LASTWIN,
- MCV_VOTE,
- MCV_SELECTEDRANDOM
-} mapConditionVariable_t;
-
-typedef enum
-{
- MCO_LT,
- MCO_EQ,
- MCO_GT
-} mapConditionOperator_t;
-
-typedef enum
-{
- MCT_ERR,
- MCT_MAP,
- MCT_ROTATION
-} mapConditionType_t;
-
-typedef struct mapRotationCondition_s
-{
- char dest[ MAX_QPATH ];
-
- qboolean unconditional;
-
- mapConditionVariable_t lhs;
- mapConditionOperator_t op;
-
- int numClients;
- pTeam_t lastWin;
-} mapRotationCondition_t;
-
-typedef struct mapRotationEntry_s
-{
- char name[ MAX_QPATH ];
-
- char postCmds[ MAX_MAP_COMMANDS ][ MAX_STRING_CHARS ];
- char layouts[ MAX_CVAR_VALUE_STRING ];
- int numCmds;
-
- mapRotationCondition_t conditions[ MAX_MAP_ROTATION_CONDS ];
- int numConditions;
-} mapRotationEntry_t;
-
-typedef struct mapRotation_s
-{
- char name[ MAX_QPATH ];
-
- mapRotationEntry_t maps[ MAX_MAP_ROTATION_MAPS ];
- int numMaps;
- int currentMap;
-} mapRotation_t;
-
-typedef struct mapRotations_s
-{
- mapRotation_t rotations[ MAX_MAP_ROTATIONS ];
- int numRotations;
-} mapRotations_t;
-
void G_PrintRotations( void );
-qboolean G_AdvanceMapRotation( void );
-qboolean G_StartMapRotation( char *name, qboolean changeMap );
+void G_AdvanceMapRotation( int depth );
+qboolean G_StartMapRotation( char *name, qboolean advance,
+ qboolean putOnStack, qboolean reset_index, int depth );
void G_StopMapRotation( void );
qboolean G_MapRotationActive( void );
void G_InitMapRotations( void );
-qboolean G_MapExists( char *name );
-int G_GetCurrentMap( int rotation );
-
-qboolean G_CheckMapRotationVote( void );
-qboolean G_IntermissionMapVoteWinner( void );
-void G_IntermissionMapVoteMessage( gentity_t *ent );
-void G_IntermissionMapVoteMessageAll( void );
-void G_IntermissionMapVoteCommand( gentity_t *ent, qboolean next, qboolean choose );
+void G_ShutdownMapRotations( void );
+qboolean G_MapExists( const char *name );
+qboolean G_LayoutExists( const char *map, const char *layout );
+void G_ClearRotationStack( void );
//
-// g_ptr.c
+// g_namelog.c
//
-void G_UpdatePTRConnection( gclient_t *client );
-connectionRecord_t *G_GenerateNewConnection( gclient_t *client );
-void G_ResetPTRConnections( void );
-connectionRecord_t *G_FindConnectionForCode( int code );
+void G_namelog_connect( gclient_t *client );
+void G_namelog_disconnect( gclient_t *client );
+void G_namelog_restore( gclient_t *client );
+void G_namelog_update_score( gclient_t *client );
+void G_namelog_update_name( gclient_t *client );
+void G_namelog_cleanup( void );
//some maxs
#define MAX_FILEPATH 144
@@ -1296,7 +1105,7 @@ connectionRecord_t *G_FindConnectionForCode( int code );
extern level_locals_t level;
extern gentity_t g_entities[ MAX_GENTITIES ];
-#define FOFS(x) ((int)&(((gentity_t *)0)->x))
+#define FOFS(x) ((size_t)&(((gentity_t *)0)->x))
extern vmCvar_t g_dedicated;
extern vmCvar_t g_cheats;
@@ -1304,94 +1113,54 @@ extern vmCvar_t g_maxclients; // allow this many total, including spectato
extern vmCvar_t g_maxGameClients; // allow this many active
extern vmCvar_t g_restarted;
extern vmCvar_t g_lockTeamsAtStart;
-extern vmCvar_t g_minCommandPeriod;
extern vmCvar_t g_minNameChangePeriod;
extern vmCvar_t g_maxNameChanges;
-extern vmCvar_t g_newbieNumbering;
-extern vmCvar_t g_newbieNamePrefix;
extern vmCvar_t g_timelimit;
extern vmCvar_t g_suddenDeathTime;
-extern vmCvar_t g_suddenDeath;
-extern vmCvar_t g_suddenDeathMode;
extern vmCvar_t g_friendlyFire;
-extern vmCvar_t g_friendlyFireHumans;
-extern vmCvar_t g_friendlyFireAliens;
-extern vmCvar_t g_retribution;
-extern vmCvar_t g_friendlyFireMovementAttacks;
extern vmCvar_t g_friendlyBuildableFire;
+extern vmCvar_t g_dretchPunt;
extern vmCvar_t g_password;
extern vmCvar_t g_needpass;
extern vmCvar_t g_gravity;
extern vmCvar_t g_speed;
extern vmCvar_t g_knockback;
-extern vmCvar_t g_quadfactor;
extern vmCvar_t g_inactivity;
extern vmCvar_t g_debugMove;
-extern vmCvar_t g_debugAlloc;
extern vmCvar_t g_debugDamage;
-extern vmCvar_t g_weaponRespawn;
-extern vmCvar_t g_weaponTeamRespawn;
extern vmCvar_t g_synchronousClients;
extern vmCvar_t g_motd;
extern vmCvar_t g_warmup;
-extern vmCvar_t g_warmupMode;
extern vmCvar_t g_doWarmup;
-extern vmCvar_t g_blood;
extern vmCvar_t g_allowVote;
-extern vmCvar_t g_requireVoteReasons;
extern vmCvar_t g_voteLimit;
extern vmCvar_t g_suddenDeathVotePercent;
extern vmCvar_t g_suddenDeathVoteDelay;
-extern vmCvar_t g_extendVotesPercent;
-extern vmCvar_t g_extendVotesTime;
-extern vmCvar_t g_extendVotesCount;
-extern vmCvar_t g_kickVotesPercent;
-extern vmCvar_t g_customVote1;
-extern vmCvar_t g_customVote2;
-extern vmCvar_t g_customVote3;
-extern vmCvar_t g_customVote4;
-extern vmCvar_t g_customVote5;
-extern vmCvar_t g_customVote6;
-extern vmCvar_t g_customVote7;
-extern vmCvar_t g_customVote8;
-#define CUSTOM_VOTE_COUNT 8
-extern vmCvar_t g_customVotePercent;
-extern vmCvar_t g_mapVotesPercent;
-extern vmCvar_t g_mapRotationVote;
-extern vmCvar_t g_extendVotesPercent;
-extern vmCvar_t g_extendVotesTime;
-extern vmCvar_t g_extendVotesCount;
-extern vmCvar_t g_readyPercent;
-extern vmCvar_t g_designateVotes;
-extern vmCvar_t g_teamAutoJoin;
extern vmCvar_t g_teamForceBalance;
-extern vmCvar_t g_banIPs;
-extern vmCvar_t g_filterBan;
extern vmCvar_t g_smoothClients;
-extern vmCvar_t g_outdatedClientMessage;
extern vmCvar_t pmove_fixed;
extern vmCvar_t pmove_msec;
-extern vmCvar_t g_rankings;
-extern vmCvar_t g_allowShare;
-extern vmCvar_t g_creditOverflow;
-extern vmCvar_t g_enableDust;
-extern vmCvar_t g_enableBreath;
-extern vmCvar_t g_singlePlayer;
-extern vmCvar_t g_humanBuildPoints;
extern vmCvar_t g_alienBuildPoints;
+extern vmCvar_t g_alienBuildQueueTime;
+extern vmCvar_t g_humanBuildPoints;
+extern vmCvar_t g_humanBuildQueueTime;
+extern vmCvar_t g_humanRepeaterBuildPoints;
+extern vmCvar_t g_humanRepeaterBuildQueueTime;
+extern vmCvar_t g_humanRepeaterMaxZones;
extern vmCvar_t g_humanStage;
-extern vmCvar_t g_humanKills;
+extern vmCvar_t g_humanCredits;
extern vmCvar_t g_humanMaxStage;
extern vmCvar_t g_humanStage2Threshold;
extern vmCvar_t g_humanStage3Threshold;
extern vmCvar_t g_alienStage;
-extern vmCvar_t g_alienKills;
+extern vmCvar_t g_alienCredits;
extern vmCvar_t g_alienMaxStage;
extern vmCvar_t g_alienStage2Threshold;
extern vmCvar_t g_alienStage3Threshold;
extern vmCvar_t g_teamImbalanceWarnings;
+extern vmCvar_t g_freeFundPeriod;
extern vmCvar_t g_unlagged;
@@ -1400,120 +1169,60 @@ extern vmCvar_t g_disabledClasses;
extern vmCvar_t g_disabledBuildables;
extern vmCvar_t g_markDeconstruct;
-extern vmCvar_t g_markDeconstructMode;
-extern vmCvar_t g_deconDead;
extern vmCvar_t g_debugMapRotation;
extern vmCvar_t g_currentMapRotation;
-extern vmCvar_t g_currentMap;
+extern vmCvar_t g_mapRotationNodes;
+extern vmCvar_t g_mapRotationStack;
extern vmCvar_t g_nextMap;
extern vmCvar_t g_initialMapRotation;
-extern vmCvar_t g_chatTeamPrefix;
-extern vmCvar_t g_actionPrefix;
+extern vmCvar_t g_sayAreaRange;
+
+extern vmCvar_t g_debugVoices;
+extern vmCvar_t g_voiceChats;
+
extern vmCvar_t g_floodMaxDemerits;
extern vmCvar_t g_floodMinTime;
-extern vmCvar_t g_spamTime;
extern vmCvar_t g_shove;
extern vmCvar_t g_mapConfigs;
-extern vmCvar_t g_layouts;
+extern vmCvar_t g_nextLayout;
+extern vmCvar_t g_layouts[ 9 ];
extern vmCvar_t g_layoutAuto;
+extern vmCvar_t g_emoticonsAllowedInNames;
+
extern vmCvar_t g_admin;
-extern vmCvar_t g_adminLog;
-extern vmCvar_t g_adminParseSay;
-extern vmCvar_t g_adminSayFilter;
-extern vmCvar_t g_adminNameProtect;
-extern vmCvar_t g_adminTempMute;
extern vmCvar_t g_adminTempBan;
extern vmCvar_t g_adminMaxBan;
-extern vmCvar_t g_adminTempSpec;
-extern vmCvar_t g_adminMapLog;
-extern vmCvar_t g_minLevelToJoinTeam;
-extern vmCvar_t g_minDeconLevel;
-extern vmCvar_t g_minDeconAffectsMark;
-extern vmCvar_t g_forceAutoSelect;
-extern vmCvar_t g_minLevelToSpecMM1;
-extern vmCvar_t g_banNotice;
-
-extern vmCvar_t g_devmapKillerHP;
-extern vmCvar_t g_killerHP;
extern vmCvar_t g_privateMessages;
-extern vmCvar_t g_fullIgnore;
-extern vmCvar_t g_decolourLogfiles;
-extern vmCvar_t g_publicSayadmins;
-extern vmCvar_t g_myStats;
-extern vmCvar_t g_teamStatus;
-extern vmCvar_t g_antiSpawnBlock;
-
-extern vmCvar_t g_dretchPunt;
-
-extern vmCvar_t g_devmapNoGod;
-extern vmCvar_t g_devmapNoStructDmg;
-
-extern vmCvar_t g_slapKnockback;
-extern vmCvar_t g_slapDamage;
-
-extern vmCvar_t g_voteMinTime;
-extern vmCvar_t g_mapvoteMaxTime;
-extern vmCvar_t g_votableMaps;
-
-extern vmCvar_t g_msg;
-extern vmCvar_t g_msgTime;
-extern vmCvar_t g_welcomeMsg;
-extern vmCvar_t g_welcomeMsgTime;
-extern vmCvar_t g_deconBanTime;
+extern vmCvar_t g_specChat;
+extern vmCvar_t g_publicAdminMessages;
+extern vmCvar_t g_allowTeamOverlay;
-extern vmCvar_t g_buildLogMaxLength;
+extern vmCvar_t g_censorship;
-extern vmCvar_t g_AllStats;
-extern vmCvar_t g_AllStatsTime;
-
-extern vmCvar_t mod_jetpackFuel;
-extern vmCvar_t mod_jetpackConsume;
-extern vmCvar_t mod_jetpackRegen;
-
-extern vmCvar_t g_adminExpireTime;
-
-extern vmCvar_t g_autoGhost;
-
-extern vmCvar_t g_teamKillThreshold;
-
-extern vmCvar_t g_aimbotAdvertBan;
-extern vmCvar_t g_aimbotAdvertBanTime;
-extern vmCvar_t g_aimbotAdvertBanReason;
-
-extern vmCvar_t g_Bubbles;
-extern vmCvar_t g_scrimMode;
-extern vmCvar_t g_gradualFreeFunds;
-extern vmCvar_t g_bleedingSpree;
-extern vmCvar_t g_schachtmeisterClearThreshold;
-extern vmCvar_t g_schachtmeisterAutobahnThreshold;
-extern vmCvar_t g_schachtmeisterAutobahnMessage;
-extern vmCvar_t g_adminAutobahnNotify;
-
-void trap_Printf( const char *fmt );
-void trap_Error( const char *fmt );
+void trap_Print( const char *fmt );
+void trap_Error( const char *fmt ) __attribute__((noreturn));
int trap_Milliseconds( void );
int trap_RealTime( qtime_t *qtime );
int trap_Argc( void );
void trap_Argv( int n, char *buffer, int bufferLength );
void trap_Args( char *buffer, int bufferLength );
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, enum FS_Mode mode );
void trap_FS_Read( void *buffer, int len, fileHandle_t f );
void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
void trap_FS_FCloseFile( fileHandle_t f );
int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
+int trap_FS_Seek( fileHandle_t f, long offset, enum FS_Mode origin ); // fsOrigin_t
void trap_SendConsoleCommand( int exec_when, const char *text );
void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags );
void trap_Cvar_Update( vmCvar_t *cvar );
void trap_Cvar_Set( const char *var_name, const char *value );
int trap_Cvar_VariableIntegerValue( const char *var_name );
-float trap_Cvar_VariableValue( const char *var_name );
void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
void trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
playerState_t *gameClients, int sizeofGameClient );
@@ -1521,6 +1230,7 @@ void trap_DropClient( int clientNum, const char *reason );
void trap_SendServerCommand( int clientNum, const char *text );
void trap_SetConfigstring( int num, const char *string );
void trap_GetConfigstring( int num, char *buffer, int bufferSize );
+void trap_SetConfigstringRestrictions( int num, const clientList_t *clientList );
void trap_GetUserinfo( int num, char *buffer, int bufferSize );
void trap_SetUserinfo( int num, const char *buffer );
void trap_GetServerinfo( char *buffer, int bufferSize );
@@ -1536,10 +1246,11 @@ void trap_LinkEntity( gentity_t *ent );
void trap_UnlinkEntity( gentity_t *ent );
int trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount );
qboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
-int trap_BotAllocateClient( void );
-void trap_BotFreeClient( int clientNum );
void trap_GetUsercmd( int clientNum, usercmd_t *cmd );
qboolean trap_GetEntityToken( char *buffer, int bufferSize );
void trap_SnapVector( float *v );
-void trap_SendGameStat( const char *data );
+
+void trap_AddCommand( const char *cmdName );
+void trap_RemoveCommand( const char *cmdName );
+int trap_FS_GetFilteredFiles( const char *path, const char *extension, const char *filter, char *listbuf, int bufsize );
diff --git a/src/game/g_main.c b/src/game/g_main.c
index 6623959..f0f2158 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,44 +17,38 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
#include "g_local.h"
-#define QVM_NAME "AA-QVM"
-#define QVM_VERSIONNUM "MULTIPROTOCOL"
-
level_locals_t level;
typedef struct
{
vmCvar_t *vmCvar;
- char *cvarName;
- char *defaultString;
- int cvarFlags;
- int modificationCount; // for tracking changes
- qboolean trackChange; // track this variable, and announce if changed
- qboolean teamShader; // track and if changed, update shader state
+ char *cvarName;
+ char *defaultString;
+ int cvarFlags;
+ int modificationCount; // for tracking changes
+ qboolean trackChange; // track this variable, and announce if changed
+ /* certain cvars can be set in worldspawn, but we don't want those values to
+ persist, so keep track of non-worldspawn changes and restore that on map
+ end. unfortunately, if the server crashes, the value set in worldspawn may
+ persist */
+ char *explicit;
} cvarTable_t;
gentity_t g_entities[ MAX_GENTITIES ];
gclient_t g_clients[ MAX_CLIENTS ];
-vmCvar_t g_fraglimit;
vmCvar_t g_timelimit;
vmCvar_t g_suddenDeathTime;
-vmCvar_t g_suddenDeath;
-vmCvar_t g_suddenDeathMode;
-vmCvar_t g_capturelimit;
vmCvar_t g_friendlyFire;
-vmCvar_t g_friendlyFireAliens;
-vmCvar_t g_friendlyFireHumans;
-vmCvar_t g_friendlyFireMovementAttacks;
-vmCvar_t g_retribution;
vmCvar_t g_friendlyBuildableFire;
+vmCvar_t g_dretchPunt;
vmCvar_t g_password;
vmCvar_t g_needpass;
vmCvar_t g_maxclients;
@@ -63,79 +58,47 @@ vmCvar_t g_speed;
vmCvar_t g_gravity;
vmCvar_t g_cheats;
vmCvar_t g_knockback;
-vmCvar_t g_quadfactor;
vmCvar_t g_inactivity;
vmCvar_t g_debugMove;
vmCvar_t g_debugDamage;
-vmCvar_t g_debugAlloc;
-vmCvar_t g_weaponRespawn;
-vmCvar_t g_weaponTeamRespawn;
vmCvar_t g_motd;
vmCvar_t g_synchronousClients;
vmCvar_t g_warmup;
-vmCvar_t g_warmupMode;
vmCvar_t g_doWarmup;
vmCvar_t g_restarted;
vmCvar_t g_lockTeamsAtStart;
vmCvar_t g_logFile;
vmCvar_t g_logFileSync;
-vmCvar_t g_blood;
-vmCvar_t g_podiumDist;
-vmCvar_t g_podiumDrop;
vmCvar_t g_allowVote;
-vmCvar_t g_requireVoteReasons;
vmCvar_t g_voteLimit;
vmCvar_t g_suddenDeathVotePercent;
vmCvar_t g_suddenDeathVoteDelay;
-vmCvar_t g_extendVotesPercent;
-vmCvar_t g_extendVotesTime;
-vmCvar_t g_extendVotesCount;
-vmCvar_t g_kickVotesPercent;
-vmCvar_t g_customVote1;
-vmCvar_t g_customVote2;
-vmCvar_t g_customVote3;
-vmCvar_t g_customVote4;
-vmCvar_t g_customVote5;
-vmCvar_t g_customVote6;
-vmCvar_t g_customVote7;
-vmCvar_t g_customVote8;
-vmCvar_t g_customVotePercent;
-vmCvar_t g_mapVotesPercent;
-vmCvar_t g_extendVotesPercent;
-vmCvar_t g_extendVotesTime;
-vmCvar_t g_extendVotesCount;
-vmCvar_t g_mapRotationVote;
-vmCvar_t g_readyPercent;
-vmCvar_t g_designateVotes;
-vmCvar_t g_teamAutoJoin;
vmCvar_t g_teamForceBalance;
-vmCvar_t g_banIPs;
-vmCvar_t g_filterBan;
vmCvar_t g_smoothClients;
-vmCvar_t g_outdatedClientMessage;
vmCvar_t pmove_fixed;
vmCvar_t pmove_msec;
-vmCvar_t g_rankings;
-vmCvar_t g_listEntity;
-vmCvar_t g_minCommandPeriod;
vmCvar_t g_minNameChangePeriod;
vmCvar_t g_maxNameChanges;
-vmCvar_t g_newbieNumbering;
-vmCvar_t g_newbieNamePrefix;
-vmCvar_t g_humanBuildPoints;
vmCvar_t g_alienBuildPoints;
+vmCvar_t g_alienBuildQueueTime;
+vmCvar_t g_humanBuildPoints;
+vmCvar_t g_humanBuildQueueTime;
+vmCvar_t g_humanRepeaterBuildPoints;
+vmCvar_t g_humanRepeaterBuildQueueTime;
+vmCvar_t g_humanRepeaterMaxZones;
vmCvar_t g_humanStage;
-vmCvar_t g_humanKills;
+vmCvar_t g_humanCredits;
vmCvar_t g_humanMaxStage;
vmCvar_t g_humanStage2Threshold;
vmCvar_t g_humanStage3Threshold;
vmCvar_t g_alienStage;
-vmCvar_t g_alienKills;
+vmCvar_t g_alienCredits;
vmCvar_t g_alienMaxStage;
vmCvar_t g_alienStage2Threshold;
vmCvar_t g_alienStage3Threshold;
vmCvar_t g_teamImbalanceWarnings;
+vmCvar_t g_freeFundPeriod;
vmCvar_t g_unlagged;
@@ -144,105 +107,52 @@ vmCvar_t g_disabledClasses;
vmCvar_t g_disabledBuildables;
vmCvar_t g_markDeconstruct;
-vmCvar_t g_markDeconstructMode;
-vmCvar_t g_deconDead;
vmCvar_t g_debugMapRotation;
vmCvar_t g_currentMapRotation;
-vmCvar_t g_currentMap;
+vmCvar_t g_mapRotationNodes;
+vmCvar_t g_mapRotationStack;
vmCvar_t g_nextMap;
vmCvar_t g_initialMapRotation;
+vmCvar_t g_debugVoices;
+vmCvar_t g_voiceChats;
+
vmCvar_t g_shove;
vmCvar_t g_mapConfigs;
-vmCvar_t g_chatTeamPrefix;
-vmCvar_t g_actionPrefix;
+vmCvar_t g_sayAreaRange;
+
vmCvar_t g_floodMaxDemerits;
vmCvar_t g_floodMinTime;
-vmCvar_t g_spamTime;
-vmCvar_t g_layouts;
+vmCvar_t g_nextLayout;
+vmCvar_t g_layouts[ 9 ];
vmCvar_t g_layoutAuto;
+vmCvar_t g_emoticonsAllowedInNames;
+
vmCvar_t g_admin;
-vmCvar_t g_adminLog;
-vmCvar_t g_adminParseSay;
-vmCvar_t g_adminSayFilter;
-vmCvar_t g_adminNameProtect;
-vmCvar_t g_adminTempMute;
vmCvar_t g_adminTempBan;
vmCvar_t g_adminMaxBan;
-vmCvar_t g_adminTempSpec;
-vmCvar_t g_adminMapLog;
-vmCvar_t g_minLevelToJoinTeam;
-vmCvar_t g_minDeconLevel;
-vmCvar_t g_minDeconAffectsMark;
-vmCvar_t g_forceAutoSelect;
vmCvar_t g_privateMessages;
-vmCvar_t g_fullIgnore;
-vmCvar_t g_decolourLogfiles;
-vmCvar_t g_minLevelToSpecMM1;
-vmCvar_t g_publicSayadmins;
-vmCvar_t g_myStats;
-vmCvar_t g_AllStats;
-vmCvar_t g_AllStatsTime;
-vmCvar_t g_teamStatus;
-vmCvar_t g_antiSpawnBlock;
-vmCvar_t g_banNotice;
-
-vmCvar_t g_devmapKillerHP;
-vmCvar_t g_killerHP;
-
-vmCvar_t g_buildLogMaxLength;
-
-vmCvar_t g_tag;
-
-vmCvar_t g_dretchPunt;
-
-vmCvar_t g_allowShare;
-vmCvar_t g_creditOverflow;
-
-vmCvar_t g_devmapNoGod;
-vmCvar_t g_devmapNoStructDmg;
-
-vmCvar_t g_slapKnockback;
-vmCvar_t g_slapDamage;
-
-vmCvar_t g_voteMinTime;
-vmCvar_t g_mapvoteMaxTime;
-vmCvar_t g_votableMaps;
+vmCvar_t g_specChat;
+vmCvar_t g_publicAdminMessages;
+vmCvar_t g_allowTeamOverlay;
-vmCvar_t g_msg;
-vmCvar_t g_msgTime;
-vmCvar_t g_welcomeMsg;
-vmCvar_t g_welcomeMsgTime;
-vmCvar_t g_deconBanTime;
+vmCvar_t g_censorship;
+vmCvar_t g_tag;
-vmCvar_t mod_jetpackFuel;
-vmCvar_t mod_jetpackConsume;
-vmCvar_t mod_jetpackRegen;
-
-vmCvar_t g_adminExpireTime;
-
-vmCvar_t g_autoGhost;
-
-vmCvar_t g_teamKillThreshold;
-
-vmCvar_t g_aimbotAdvertBan;
-vmCvar_t g_aimbotAdvertBanTime;
-vmCvar_t g_aimbotAdvertBanReason;
-vmCvar_t g_Bubbles;
-vmCvar_t g_scrimMode;
-vmCvar_t g_gradualFreeFunds;
-vmCvar_t g_bleedingSpree;
-vmCvar_t g_schachtmeisterClearThreshold;
-vmCvar_t g_schachtmeisterAutobahnThreshold;
-vmCvar_t g_schachtmeisterAutobahnMessage;
-vmCvar_t g_adminAutobahnNotify;
+// copy cvars that can be set in worldspawn so they can be restored later
+static char cv_gravity[ MAX_CVAR_VALUE_STRING ];
+static char cv_humanMaxStage[ MAX_CVAR_VALUE_STRING ];
+static char cv_alienMaxStage[ MAX_CVAR_VALUE_STRING ];
+static char cv_humanRepeaterBuildPoints[ MAX_CVAR_VALUE_STRING ];
+static char cv_humanBuildPoints[ MAX_CVAR_VALUE_STRING ];
+static char cv_alienBuildPoints[ MAX_CVAR_VALUE_STRING ];
static cvarTable_t gameCvarTable[ ] =
{
@@ -251,223 +161,133 @@ static cvarTable_t gameCvarTable[ ] =
// noset vars
{ NULL, "gamename", GAME_VERSION , CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
- { NULL, "gamedate", __DATE__ , CVAR_ROM, 0, qfalse },
{ &g_restarted, "g_restarted", "0", CVAR_ROM, 0, qfalse },
{ &g_lockTeamsAtStart, "g_lockTeamsAtStart", "0", CVAR_ROM, 0, qfalse },
{ NULL, "sv_mapname", "", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
{ NULL, "P", "", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
- { NULL, "ff", "0", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
- { NULL, "qvm_version", QVM_NAME " " QVM_VERSIONNUM " (" __DATE__ ", " __TIME__ ")", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
// latched vars
{ &g_maxclients, "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
- { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
// change anytime vars
- { &g_timelimit, "timelimit", "45", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
- { &g_suddenDeathTime, "g_suddenDeathTime", "30", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
- { &g_suddenDeathMode, "g_suddenDeathMode", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
- { &g_suddenDeath, "g_suddenDeath", "0", CVAR_SERVERINFO | CVAR_NORESTART, 0, qtrue },
+ { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
- { &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0, qfalse },
+ { &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
+ { &g_suddenDeathTime, "g_suddenDeathTime", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
- { &g_friendlyFire, "g_friendlyFire", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qtrue },
- { &g_friendlyFireAliens, "g_friendlyFireAliens", "0", CVAR_ARCHIVE, 0, qtrue },
- { &g_friendlyFireHumans, "g_friendlyFireHumans", "0", CVAR_ARCHIVE, 0, qtrue },
- { &g_retribution, "g_retribution", "0", CVAR_ARCHIVE, 0, qtrue },
- { &g_friendlyBuildableFire, "g_friendlyBuildableFire", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qtrue },
- { &g_friendlyFireMovementAttacks, "g_friendlyFireMovementAttacks", "1", CVAR_ARCHIVE, 0, qtrue },
- { &g_devmapNoGod, "g_devmapNoGod", "0", CVAR_ARCHIVE, 0, qtrue },
- { &g_devmapNoStructDmg, "g_devmapNoStructDmg", "0", CVAR_ARCHIVE, 0, qtrue },
+ { &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0, qfalse },
- { &g_slapKnockback, "g_slapKnockback", "200", CVAR_ARCHIVE, 0, qfalse},
- { &g_slapDamage, "g_slapDamage", "0", CVAR_ARCHIVE, 0, qfalse},
+ { &g_friendlyFire, "g_friendlyFire", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
+ { &g_friendlyBuildableFire, "g_friendlyBuildableFire", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
+ { &g_dretchPunt, "g_dretchPunt", "1", CVAR_ARCHIVE, 0, qtrue },
- { &g_teamAutoJoin, "g_teamAutoJoin", "0", CVAR_ARCHIVE },
- { &g_teamForceBalance, "g_teamForceBalance", "1", CVAR_ARCHIVE },
+ { &g_teamForceBalance, "g_teamForceBalance", "0", CVAR_ARCHIVE, 0, qtrue },
{ &g_warmup, "g_warmup", "10", CVAR_ARCHIVE, 0, qtrue },
- { &g_warmupMode, "g_warmupMode", "1", CVAR_ARCHIVE, 0, qtrue },
- { &g_doWarmup, "g_doWarmup", "1", CVAR_ARCHIVE, 0, qtrue },
+ { &g_doWarmup, "g_doWarmup", "0", CVAR_ARCHIVE, 0, qtrue },
{ &g_logFile, "g_logFile", "games.log", CVAR_ARCHIVE, 0, qfalse },
{ &g_logFileSync, "g_logFileSync", "0", CVAR_ARCHIVE, 0, qfalse },
{ &g_password, "g_password", "", CVAR_USERINFO, 0, qfalse },
- { &g_banIPs, "g_banIPs", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_filterBan, "g_filterBan", "1", CVAR_ARCHIVE, 0, qfalse },
-
{ &g_needpass, "g_needpass", "0", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
-
- { &g_autoGhost, "g_autoGhost", "1", CVAR_SERVERINFO, 0, qfalse },
{ &g_dedicated, "dedicated", "0", 0, 0, qfalse },
- { &g_speed, "g_speed", "320", CVAR_SERVERINFO, 0, qtrue },
- { &g_gravity, "g_gravity", "800", CVAR_SERVERINFO, 0, qtrue },
- { &g_knockback, "g_knockback", "1000", CVAR_SERVERINFO, 0, qtrue },
- { &g_quadfactor, "g_quadfactor", "3", 0, 0, qtrue },
- { &g_weaponRespawn, "g_weaponrespawn", "5", 0, 0, qtrue },
- { &g_weaponTeamRespawn, "g_weaponTeamRespawn", "30", 0, 0, qtrue },
+ { &g_speed, "g_speed", "320", 0, 0, qtrue },
+ { &g_gravity, "g_gravity", "800", 0, 0, qtrue, cv_gravity },
+ { &g_knockback, "g_knockback", "1000", 0, 0, qtrue },
{ &g_inactivity, "g_inactivity", "0", 0, 0, qtrue },
{ &g_debugMove, "g_debugMove", "0", 0, 0, qfalse },
{ &g_debugDamage, "g_debugDamage", "0", 0, 0, qfalse },
- { &g_debugAlloc, "g_debugAlloc", "0", 0, 0, qfalse },
{ &g_motd, "g_motd", "", 0, 0, qfalse },
- { &g_blood, "com_blood", "1", 0, 0, qfalse },
-
- { &g_podiumDist, "g_podiumDist", "80", 0, 0, qfalse },
- { &g_podiumDrop, "g_podiumDrop", "70", 0, 0, qfalse },
{ &g_allowVote, "g_allowVote", "1", CVAR_ARCHIVE, 0, qfalse },
- { &g_requireVoteReasons, "g_requireVoteReasons", "0", CVAR_ARCHIVE, 0, qfalse },
{ &g_voteLimit, "g_voteLimit", "5", CVAR_ARCHIVE, 0, qfalse },
- { &g_voteMinTime, "g_voteMinTime", "120", CVAR_ARCHIVE, 0, qfalse },
- { &g_mapvoteMaxTime, "g_mapvoteMaxTime", "240", CVAR_ARCHIVE, 0, qfalse },
- { &g_votableMaps, "g_votableMaps", "", CVAR_ARCHIVE, 0, qtrue },
{ &g_suddenDeathVotePercent, "g_suddenDeathVotePercent", "74", CVAR_ARCHIVE, 0, qfalse },
{ &g_suddenDeathVoteDelay, "g_suddenDeathVoteDelay", "180", CVAR_ARCHIVE, 0, qfalse },
- { &g_customVote1, "g_customVote1", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_customVote2, "g_customVote2", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_customVote3, "g_customVote3", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_customVote4, "g_customVote4", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_customVote5, "g_customVote5", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_customVote6, "g_customVote6", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_customVote7, "g_customVote7", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_customVote8, "g_customVote8", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_customVotePercent, "g_customVotePercent", "50", CVAR_ARCHIVE, 0, qfalse },
- { &g_mapVotesPercent, "g_mapVotesPercent", "50", CVAR_ARCHIVE, 0, qfalse },
- { &g_extendVotesPercent, "g_extendVotesPercent", "74", CVAR_ARCHIVE, 0, qfalse },
- { &g_extendVotesTime, "g_extendVotesTime", "10", CVAR_ARCHIVE, 0, qfalse },
- { &g_extendVotesCount, "g_extendVotesCount", "2", CVAR_ARCHIVE, 0, qfalse },
- { &g_mapRotationVote, "g_mapRotationVote", "15", CVAR_ARCHIVE, 0, qfalse },
- { &g_readyPercent, "g_readyPercent", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_designateVotes, "g_designateVotes", "0", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_listEntity, "g_listEntity", "0", 0, 0, qfalse },
- { &g_minCommandPeriod, "g_minCommandPeriod", "500", 0, 0, qfalse},
{ &g_minNameChangePeriod, "g_minNameChangePeriod", "5", 0, 0, qfalse},
{ &g_maxNameChanges, "g_maxNameChanges", "5", 0, 0, qfalse},
- { &g_newbieNumbering, "g_newbieNumbering", "0", CVAR_ARCHIVE, 0, qfalse},
- { &g_newbieNamePrefix, "g_newbieNamePrefix", "Newbie#", CVAR_ARCHIVE, 0, qfalse},
{ &g_smoothClients, "g_smoothClients", "1", 0, 0, qfalse},
- { &g_outdatedClientMessage, "g_outdatedClientMessage", "", CVAR_ARCHIVE, 0, qfalse},
{ &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO, 0, qfalse},
{ &pmove_msec, "pmove_msec", "8", CVAR_SYSTEMINFO, 0, qfalse},
- { &g_humanBuildPoints, "g_humanBuildPoints", DEFAULT_HUMAN_BUILDPOINTS, CVAR_SERVERINFO, 0, qfalse },
- { &g_alienBuildPoints, "g_alienBuildPoints", DEFAULT_ALIEN_BUILDPOINTS, CVAR_SERVERINFO, 0, qfalse },
+ { &g_alienBuildPoints, "g_alienBuildPoints", DEFAULT_ALIEN_BUILDPOINTS, 0, 0, qfalse, cv_alienBuildPoints },
+ { &g_alienBuildQueueTime, "g_alienBuildQueueTime", DEFAULT_ALIEN_QUEUE_TIME, CVAR_ARCHIVE, 0, qfalse },
+ { &g_humanBuildPoints, "g_humanBuildPoints", DEFAULT_HUMAN_BUILDPOINTS, 0, 0, qfalse, cv_humanBuildPoints },
+ { &g_humanBuildQueueTime, "g_humanBuildQueueTime", DEFAULT_HUMAN_QUEUE_TIME, CVAR_ARCHIVE, 0, qfalse },
+ { &g_humanRepeaterBuildPoints, "g_humanRepeaterBuildPoints", DEFAULT_HUMAN_REPEATER_BUILDPOINTS, CVAR_ARCHIVE, 0, qfalse, cv_humanRepeaterBuildPoints },
+ { &g_humanRepeaterMaxZones, "g_humanRepeaterMaxZones", DEFAULT_HUMAN_REPEATER_MAX_ZONES, CVAR_ARCHIVE, 0, qfalse },
+ { &g_humanRepeaterBuildQueueTime, "g_humanRepeaterBuildQueueTime", DEFAULT_HUMAN_REPEATER_QUEUE_TIME, CVAR_ARCHIVE, 0, qfalse },
{ &g_humanStage, "g_humanStage", "0", 0, 0, qfalse },
- { &g_humanKills, "g_humanKills", "0", 0, 0, qfalse },
- { &g_humanMaxStage, "g_humanMaxStage", DEFAULT_HUMAN_MAX_STAGE, 0, 0, qfalse },
+ { &g_humanCredits, "g_humanCredits", "0", 0, 0, qfalse },
+ { &g_humanMaxStage, "g_humanMaxStage", DEFAULT_HUMAN_MAX_STAGE, 0, 0, qfalse, cv_humanMaxStage },
{ &g_humanStage2Threshold, "g_humanStage2Threshold", DEFAULT_HUMAN_STAGE2_THRESH, 0, 0, qfalse },
{ &g_humanStage3Threshold, "g_humanStage3Threshold", DEFAULT_HUMAN_STAGE3_THRESH, 0, 0, qfalse },
{ &g_alienStage, "g_alienStage", "0", 0, 0, qfalse },
- { &g_alienKills, "g_alienKills", "0", 0, 0, qfalse },
- { &g_alienMaxStage, "g_alienMaxStage", DEFAULT_ALIEN_MAX_STAGE, 0, 0, qfalse },
+ { &g_alienCredits, "g_alienCredits", "0", 0, 0, qfalse },
+ { &g_alienMaxStage, "g_alienMaxStage", DEFAULT_ALIEN_MAX_STAGE, 0, 0, qfalse, cv_alienMaxStage },
{ &g_alienStage2Threshold, "g_alienStage2Threshold", DEFAULT_ALIEN_STAGE2_THRESH, 0, 0, qfalse },
{ &g_alienStage3Threshold, "g_alienStage3Threshold", DEFAULT_ALIEN_STAGE3_THRESH, 0, 0, qfalse },
-
{ &g_teamImbalanceWarnings, "g_teamImbalanceWarnings", "30", CVAR_ARCHIVE, 0, qfalse },
-
+ { &g_freeFundPeriod, "g_freeFundPeriod", DEFAULT_FREEKILL_PERIOD, CVAR_ARCHIVE, 0, qtrue },
+
{ &g_unlagged, "g_unlagged", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
- { &g_disabledEquipment, "g_disabledEquipment", "", CVAR_ROM, 0, qfalse },
- { &g_disabledClasses, "g_disabledClasses", "", CVAR_ROM, 0, qfalse },
- { &g_disabledBuildables, "g_disabledBuildables", "", CVAR_ROM, 0, qfalse },
+ { &g_disabledEquipment, "g_disabledEquipment", "", CVAR_ROM | CVAR_SYSTEMINFO, 0, qfalse },
+ { &g_disabledClasses, "g_disabledClasses", "", CVAR_ROM | CVAR_SYSTEMINFO, 0, qfalse },
+ { &g_disabledBuildables, "g_disabledBuildables", "", CVAR_ROM | CVAR_SYSTEMINFO, 0, qfalse },
+
+ { &g_sayAreaRange, "g_sayAreaRange", "1000", CVAR_ARCHIVE, 0, qtrue },
- { &g_chatTeamPrefix, "g_chatTeamPrefix", "1", CVAR_ARCHIVE },
- { &g_actionPrefix, "g_actionPrefix", "* ", CVAR_ARCHIVE, 0, qfalse },
{ &g_floodMaxDemerits, "g_floodMaxDemerits", "5000", CVAR_ARCHIVE, 0, qfalse },
{ &g_floodMinTime, "g_floodMinTime", "2000", CVAR_ARCHIVE, 0, qfalse },
- { &g_spamTime, "g_spamTime", "2", CVAR_ARCHIVE, 0, qfalse },
- { &g_markDeconstruct, "g_markDeconstruct", "0", CVAR_ARCHIVE, 0, qtrue },
- { &g_markDeconstructMode, "g_markDeconstructMode", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_deconDead, "g_deconDead", "0", CVAR_ARCHIVE, 0, qtrue },
+ { &g_markDeconstruct, "g_markDeconstruct", "3", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
{ &g_debugMapRotation, "g_debugMapRotation", "0", 0, 0, qfalse },
{ &g_currentMapRotation, "g_currentMapRotation", "-1", 0, 0, qfalse }, // -1 = NOT_ROTATING
- { &g_currentMap, "g_currentMap", "0", 0, 0, qfalse },
+ { &g_mapRotationNodes, "g_mapRotationNodes", "", CVAR_ROM, 0, qfalse },
+ { &g_mapRotationStack, "g_mapRotationStack", "", CVAR_ROM, 0, qfalse },
{ &g_nextMap, "g_nextMap", "", 0 , 0, qtrue },
{ &g_initialMapRotation, "g_initialMapRotation", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_shove, "g_shove", "15", CVAR_ARCHIVE, 0, qfalse },
+ { &g_debugVoices, "g_debugVoices", "0", 0, 0, qfalse },
+ { &g_voiceChats, "g_voiceChats", "1", CVAR_ARCHIVE, 0, qfalse },
+ { &g_shove, "g_shove", "0.0", CVAR_ARCHIVE, 0, qfalse },
{ &g_mapConfigs, "g_mapConfigs", "", CVAR_ARCHIVE, 0, qfalse },
{ NULL, "g_mapConfigsLoaded", "0", CVAR_ROM, 0, qfalse },
- { &g_layouts, "g_layouts", "", CVAR_LATCH, 0, qfalse },
+ { &g_nextLayout, "g_nextLayout", "", 0, 0, qfalse },
+ { &g_layouts[ 0 ], "g_layouts", "", 0, 0, qfalse },
+ { &g_layouts[ 1 ], "g_layouts2", "", 0, 0, qfalse },
+ { &g_layouts[ 2 ], "g_layouts3", "", 0, 0, qfalse },
+ { &g_layouts[ 3 ], "g_layouts4", "", 0, 0, qfalse },
+ { &g_layouts[ 4 ], "g_layouts5", "", 0, 0, qfalse },
+ { &g_layouts[ 5 ], "g_layouts6", "", 0, 0, qfalse },
+ { &g_layouts[ 6 ], "g_layouts7", "", 0, 0, qfalse },
+ { &g_layouts[ 7 ], "g_layouts8", "", 0, 0, qfalse },
+ { &g_layouts[ 8 ], "g_layouts9", "", 0, 0, qfalse },
{ &g_layoutAuto, "g_layoutAuto", "1", CVAR_ARCHIVE, 0, qfalse },
+ { &g_emoticonsAllowedInNames, "g_emoticonsAllowedInNames", "1", CVAR_LATCH|CVAR_ARCHIVE, 0, qfalse },
+
{ &g_admin, "g_admin", "admin.dat", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminLog, "g_adminLog", "admin.log", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminParseSay, "g_adminParseSay", "1", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminSayFilter, "g_adminSayFilter", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminNameProtect, "g_adminNameProtect", "1", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminTempMute, "g_adminTempMute", "5m", CVAR_ARCHIVE, 0, qfalse },
{ &g_adminTempBan, "g_adminTempBan", "2m", CVAR_ARCHIVE, 0, qfalse },
{ &g_adminMaxBan, "g_adminMaxBan", "2w", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminTempSpec, "g_adminTempSpec", "2m", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminMapLog, "g_adminMapLog", "", CVAR_ROM, 0, qfalse },
- { &g_minLevelToJoinTeam, "g_minLevelToJoinTeam", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_minDeconLevel, "g_minDeconLevel", "0", CVAR_ARCHIVE, 0, qfalse},
- { &g_minDeconAffectsMark, "g_minDeconAffectsMark", "0", CVAR_ARCHIVE, 0, qfalse},
- { &g_forceAutoSelect, "g_forceAutoSelect", "0", CVAR_ARCHIVE, 0, qtrue },
- { &g_adminExpireTime, "g_adminExpireTime", "0", CVAR_ARCHIVE, 0, qfalse },
-
+
{ &g_privateMessages, "g_privateMessages", "1", CVAR_ARCHIVE, 0, qfalse },
- { &g_fullIgnore, "g_fullIgnore", "1", CVAR_ARCHIVE, 0, qtrue },
- { &g_decolourLogfiles, "g_decolourLogfiles", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_buildLogMaxLength, "g_buildLogMaxLength", "50", CVAR_ARCHIVE, 0, qfalse },
- { &g_myStats, "g_myStats", "1", CVAR_ARCHIVE, 0, qtrue },
- { &g_AllStats, "g_AllStats", "0", CVAR_ARCHIVE, 0, qtrue },
- { &g_AllStatsTime, "g_AllStatsTime", "60", CVAR_ARCHIVE, 0, qfalse },
- { &g_teamStatus, "g_teamStatus", "0", CVAR_ARCHIVE, 0, qtrue },
- { &g_publicSayadmins, "g_publicSayadmins", "1", CVAR_ARCHIVE, 0, qfalse },
- { &g_minLevelToSpecMM1, "g_minLevelToSpecMM1", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_antiSpawnBlock, "g_antiSpawnBlock", "0", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_devmapKillerHP, "g_devmapKillerHP", "0", CVAR_ARCHIVE, 0, qtrue },
- { &g_killerHP, "g_killerHP", "0", CVAR_ARCHIVE, 0, qtrue },
-
- { &g_tag, "g_tag", "main", CVAR_INIT, 0, qfalse },
-
- { &g_dretchPunt, "g_dretchPunt", "1", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_msg, "g_msg", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_msgTime, "g_msgTime", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_welcomeMsg, "g_welcomeMsg", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_welcomeMsgTime, "g_welcomeMsgTime", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_deconBanTime, "g_deconBanTime", "2h", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_rankings, "g_rankings", "0", 0, 0, qfalse },
- { &g_allowShare, "g_allowShare", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse},
- { &g_creditOverflow, "g_creditOverflow", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse},
- { &g_banNotice, "g_banNotice", "", CVAR_ARCHIVE, 0, qfalse },
-
- { &mod_jetpackFuel, "mod_jetpackFuel", "0", CVAR_ARCHIVE, 0, qtrue },
- { &mod_jetpackConsume, "mod_jetpackConsume", "2", CVAR_ARCHIVE, 0, qfalse },
- { &mod_jetpackRegen, "mod_jetpackRegen", "3", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_teamKillThreshold, "g_teamKillThreshold", "0", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_aimbotAdvertBan, "g_aimbotAdvertBan", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_aimbotAdvertBanTime, "g_aimbotAdvertBanTime", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_aimbotAdvertBanReason, "g_aimbotAdvertBanReason", "AUTOBAN: AIMBOT", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_Bubbles, "g_Bubbles", "1", CVAR_ARCHIVE, 0, qfalse },
- { &g_scrimMode, "g_scrimMode", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_gradualFreeFunds, "g_gradualFreeFunds", "2", CVAR_ARCHIVE, 0, qtrue },
- { &g_bleedingSpree, "g_bleedingSpree", "0", CVAR_ARCHIVE, 0, qfalse },
- { &g_gradualFreeFunds, "g_gradualFreeFunds", "2", CVAR_ARCHIVE, 0, qtrue },
- { &g_schachtmeisterClearThreshold, "g_schachtmeisterClearThreshold", "-10", CVAR_ARCHIVE, 0, qfalse },
- { &g_schachtmeisterAutobahnThreshold, "g_schachtmeisterAutobahnThreshold", "-30", CVAR_ARCHIVE, 0, qfalse },
- { &g_schachtmeisterAutobahnMessage, "g_schachtmeisterAutobahnMessage", "Your host is blacklisted.", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminAutobahnNotify, "g_adminAutobahnNotify", "1", CVAR_ARCHIVE, 0, qfalse }
+ { &g_specChat, "g_specChat", "1", CVAR_ARCHIVE, 0, qfalse },
+ { &g_publicAdminMessages, "g_publicAdminMessages", "1", CVAR_ARCHIVE, 0, qfalse },
+ { &g_allowTeamOverlay, "g_allowTeamOverlay", "1", CVAR_ARCHIVE, 0, qtrue },
+
+ { &g_censorship, "g_censorship", "", CVAR_ARCHIVE, 0, qfalse },
+
+ { &g_tag, "g_tag", "main", CVAR_INIT, 0, qfalse }
};
-static int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[ 0 ] );
+static size_t gameCvarTableSize = ARRAY_LEN( gameCvarTable );
void G_InitGame( int levelTime, int randomSeed, int restart );
@@ -486,9 +306,7 @@ This is the only way control passes into the module.
This must be the very first function compiled into the .q3vm file
================
*/
-Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4,
- int arg5, int arg6, int arg7, int arg8, int arg9,
- int arg10, int arg11 )
+Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2 )
{
switch( command )
{
@@ -541,10 +359,10 @@ void QDECL G_Printf( const char *fmt, ... )
char text[ 1024 ];
va_start( argptr, fmt );
- vsprintf( text, fmt, argptr );
+ Q_vsnprintf( text, sizeof( text ), fmt, argptr );
va_end( argptr );
- trap_Printf( text );
+ trap_Print( text );
}
void QDECL G_Error( const char *fmt, ... )
@@ -553,7 +371,7 @@ void QDECL G_Error( const char *fmt, ... )
char text[ 1024 ];
va_start( argptr, fmt );
- vsprintf( text, fmt, argptr );
+ Q_vsnprintf( text, sizeof( text ), fmt, argptr );
va_end( argptr );
trap_Error( text );
@@ -579,11 +397,8 @@ void G_FindTeams( void )
c = 0;
c2 = 0;
- for( i = 1, e = g_entities+i; i < level.num_entities; i++, e++ )
+ for( i = MAX_CLIENTS, e = g_entities + i; i < level.num_entities; i++, e++ )
{
- if( !e->inuse )
- continue;
-
if( !e->team )
continue;
@@ -596,9 +411,6 @@ void G_FindTeams( void )
for( j = i + 1, e2 = e + 1; j < level.num_entities; j++, e2++ )
{
- if( !e2->inuse )
- continue;
-
if( !e2->team )
continue;
@@ -626,10 +438,6 @@ void G_FindTeams( void )
G_Printf( "%i teams with %i entities\n", c, c2 );
}
-void G_RemapTeamShaders( void )
-{
-}
-
/*
=================
@@ -640,7 +448,6 @@ void G_RegisterCvars( void )
{
int i;
cvarTable_t *cv;
- qboolean remapped = qfalse;
for( i = 0, cv = gameCvarTable; i < gameCvarTableSize; i++, cv++ )
{
@@ -650,12 +457,9 @@ void G_RegisterCvars( void )
if( cv->vmCvar )
cv->modificationCount = cv->vmCvar->modificationCount;
- if( cv->teamShader )
- remapped = qtrue;
+ if( cv->explicit )
+ strcpy( cv->explicit, cv->vmCvar->string );
}
-
- if( remapped )
- G_RemapTeamShaders( );
}
/*
@@ -667,7 +471,6 @@ void G_UpdateCvars( void )
{
int i;
cvarTable_t *cv;
- qboolean remapped = qfalse;
for( i = 0, cv = gameCvarTable; i < gameCvarTableSize; i++, cv++ )
{
@@ -680,21 +483,31 @@ void G_UpdateCvars( void )
cv->modificationCount = cv->vmCvar->modificationCount;
if( cv->trackChange )
- {
trap_SendServerCommand( -1, va( "print \"Server: %s changed to %s\n\"",
cv->cvarName, cv->vmCvar->string ) );
- // update serverinfo in case this cvar is passed to clients indirectly
- CalculateRanks( );
- }
- if( cv->teamShader )
- remapped = qtrue;
+ if( !level.spawning && cv->explicit )
+ strcpy( cv->explicit, cv->vmCvar->string );
}
}
}
+}
+
+/*
+=================
+G_RestoreCvars
+=================
+*/
+void G_RestoreCvars( void )
+{
+ int i;
+ cvarTable_t *cv;
- if( remapped )
- G_RemapTeamShaders( );
+ for( i = 0, cv = gameCvarTable; i < gameCvarTableSize; i++, cv++ )
+ {
+ if( cv->vmCvar && cv->explicit )
+ trap_Cvar_Set( cv->cvarName, cv->explicit );
+ }
}
/*
@@ -713,7 +526,7 @@ void G_MapConfigs( const char *mapname )
trap_SendConsoleCommand( EXEC_APPEND,
va( "exec \"%s/default.cfg\"\n", g_mapConfigs.string ) );
-
+
trap_SendConsoleCommand( EXEC_APPEND,
va( "exec \"%s/%s.cfg\"\n", g_mapConfigs.string, mapname ) );
@@ -736,11 +549,8 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
G_Printf( "------- Game Initialization -------\n" );
G_Printf( "gamename: %s\n", GAME_VERSION );
- G_Printf( "gamedate: %s\n", __DATE__ );
- G_ProcessIPBans( );
-
- G_InitMemory( );
+ BG_InitMemory( );
// set some level globals
memset( &level, 0, sizeof( level ) );
@@ -751,9 +561,6 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
level.snd_fry = G_SoundIndex( "sound/misc/fry.wav" ); // FIXME standing in lava / slime
- trap_Cvar_Set( "qvm_version",
- QVM_NAME " " QVM_VERSIONNUM " (" __DATE__ ", " __TIME__ ")" );
-
if( g_logFile.string[ 0 ] )
{
if( g_logFileSync.integer )
@@ -767,17 +574,15 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
{
char serverinfo[ MAX_INFO_STRING ];
qtime_t qt;
- int t;
-
trap_GetServerinfo( serverinfo, sizeof( serverinfo ) );
G_LogPrintf( "------------------------------------------------------------\n" );
G_LogPrintf( "InitGame: %s\n", serverinfo );
- t = trap_RealTime( &qt );
- G_LogPrintf("RealTime: %04i/%02i/%02i %02i:%02i:%02i\n",
- qt.tm_year+1900, qt.tm_mon+1, qt.tm_mday,
+ trap_RealTime( &qt );
+ G_LogPrintf("RealTime: %04i-%02i-%02i %02i:%02i:%02i\n",
+ qt.tm_year+1900, qt.tm_mon+1, qt.tm_mday,
qt.tm_hour, qt.tm_min, qt.tm_sec );
}
@@ -785,19 +590,28 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
else
G_Printf( "Not logging to disk\n" );
+ if( g_mapConfigs.string[ 0 ] && !trap_Cvar_VariableIntegerValue( "g_mapConfigsLoaded" ) )
{
char map[ MAX_CVAR_VALUE_STRING ] = {""};
+ G_Printf( "InitGame: executing map configuration scripts and restarting\n" );
trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
G_MapConfigs( map );
+ trap_SendConsoleCommand( EXEC_APPEND, "wait\nmap_restart 0\n" );
+ }
+ else
+ {
+ // we're done with g_mapConfigs, so reset this for the next map
+ trap_Cvar_Set( "g_mapConfigsLoaded", "0" );
}
- // we're done with g_mapConfigs, so reset this for the next map
- trap_Cvar_Set( "g_mapConfigsLoaded", "0" );
+ // set this cvar to 0 if it exists, but otherwise avoid its creation
+ if( trap_Cvar_VariableIntegerValue( "g_rangeMarkerWarningGiven" ) )
+ trap_Cvar_Set( "g_rangeMarkerWarningGiven", "0" );
- if ( g_admin.string[ 0 ] ) {
- G_admin_readconfig( NULL, 0 );
- }
+ G_RegisterCommands( );
+ G_admin_readconfig( NULL );
+ G_LoadCensors( );
// initialize all entities for this game
memset( g_entities, 0, MAX_GENTITIES * sizeof( g_entities[ 0 ] ) );
@@ -817,26 +631,29 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
// range are NEVER anything but clients
level.num_entities = MAX_CLIENTS;
+ for( i = 0; i < MAX_CLIENTS; i++ )
+ g_entities[ i ].classname = "clientslot";
+
// let the server system know where the entites are
trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ),
&level.clients[ 0 ].ps, sizeof( level.clients[ 0 ] ) );
+ level.emoticonCount = BG_LoadEmoticons( level.emoticons, MAX_EMOTICONS );
+
trap_SetConfigstring( CS_INTERMISSION, "0" );
- // update maplog
- G_admin_maplog_update( );
+ G_InitPlayerModel();
// test to see if a custom buildable layout will be loaded
G_LayoutSelect( );
+ // this has to be flipped after the first UpdateCvars
+ level.spawning = qtrue;
// parse the key/value pairs and spawn gentities
G_SpawnEntitiesFromString( );
// load up a custom building layout if there is one
- G_LayoutLoad( );
-
- // load any nobuild markers that have been saved
- G_NobuildLoad( );
+ G_LayoutLoad( level.layout );
// the map might disable some things
BG_InitAllowedGameElements( );
@@ -844,9 +661,8 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
// general initialization
G_FindTeams( );
- //TA:
- BG_InitClassOverrides( );
- BG_InitBuildableOverrides( );
+ BG_InitClassConfigs( );
+ BG_InitBuildableConfigs( );
G_InitDamageLocations( );
G_InitMapRotations( );
G_InitSpawnQueue( &level.alienSpawnQueue );
@@ -855,27 +671,27 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
if( g_debugMapRotation.integer )
G_PrintRotations( );
+ level.voices = BG_VoiceInit( );
+ BG_PrintVoices( level.voices, g_debugVoices.integer );
+
//reset stages
trap_Cvar_Set( "g_alienStage", va( "%d", S1 ) );
trap_Cvar_Set( "g_humanStage", va( "%d", S1 ) );
- trap_Cvar_Set( "g_alienKills", 0 );
- trap_Cvar_Set( "g_humanKills", 0 );
- trap_Cvar_Set( "g_suddenDeath", 0 );
+ trap_Cvar_Set( "g_alienCredits", 0 );
+ trap_Cvar_Set( "g_humanCredits", 0 );
level.suddenDeathBeginTime = g_suddenDeathTime.integer * 60000;
G_Printf( "-----------------------------------\n" );
- G_RemapTeamShaders( );
-
- //TA: so the server counts the spawns without a client attached
+ // So the server counts the spawns without a client attached
G_CountSpawns( );
- G_ResetPTRConnections( );
-
- if(g_lockTeamsAtStart.integer)
+ G_UpdateTeamConfigStrings( );
+
+ if( g_lockTeamsAtStart.integer )
{
- level.alienTeamLocked=qtrue;
- level.humanTeamLocked=qtrue;
+ level.alienTeamLocked = qtrue;
+ level.humanTeamLocked = qtrue;
trap_Cvar_Set( "g_lockTeamsAtStart", "0" );
}
}
@@ -889,15 +705,13 @@ remove all currently active votes
*/
static void G_ClearVotes( void )
{
- level.voteTime = 0;
- trap_SetConfigstring( CS_VOTE_TIME, "" );
- trap_SetConfigstring( CS_VOTE_STRING, "" );
- level.teamVoteTime[ 0 ] = 0;
- trap_SetConfigstring( CS_TEAMVOTE_TIME, "" );
- trap_SetConfigstring( CS_TEAMVOTE_STRING, "" );
- level.teamVoteTime[ 1 ] = 0;
- trap_SetConfigstring( CS_TEAMVOTE_TIME + 1, "" );
- trap_SetConfigstring( CS_TEAMVOTE_STRING + 1, "" );
+ int i;
+ memset( level.voteTime, 0, sizeof( level.voteTime ) );
+ for( i = 0; i < NUM_TEAMS; i++ )
+ {
+ trap_SetConfigstring( CS_VOTE_TIME + i, "" );
+ trap_SetConfigstring( CS_VOTE_STRING + i, "" );
+ }
}
/*
@@ -910,6 +724,8 @@ void G_ShutdownGame( int restart )
// in case of a map_restart
G_ClearVotes( );
+ G_RestoreCvars( );
+
G_Printf( "==== ShutdownGame ====\n" );
if( level.logFile )
@@ -917,20 +733,21 @@ void G_ShutdownGame( int restart )
G_LogPrintf( "ShutdownGame:\n" );
G_LogPrintf( "------------------------------------------------------------\n" );
trap_FS_FCloseFile( level.logFile );
+ level.logFile = 0;
}
- // write admin.dat for !seen data
- admin_writeconfig();
-
// write all the client session data so we can get it back
G_WriteSessionData( );
G_admin_cleanup( );
- G_admin_namelog_cleanup( );
- G_admin_adminlog_cleanup( );
+ G_namelog_cleanup( );
+ G_UnregisterCommands( );
+
+ G_FreePlayerModel( );
+ G_ShutdownMapRotations( );
level.restarted = qfalse;
- level.surrenderTeam = PTE_NONE;
+ level.surrenderTeam = TEAM_NONE;
trap_SetConfigstring( CS_WINNER, "" );
}
@@ -944,7 +761,7 @@ void QDECL Com_Error( int level, const char *error, ... )
char text[ 1024 ];
va_start( argptr, error );
- vsprintf( text, error, argptr );
+ Q_vsnprintf( text, sizeof( text ), error, argptr );
va_end( argptr );
G_Error( "%s", text );
@@ -956,7 +773,7 @@ void QDECL Com_Printf( const char *msg, ... )
char text[ 1024 ];
va_start( argptr, msg );
- vsprintf( text, msg, argptr );
+ Q_vsnprintf( text, sizeof( text ), msg, argptr );
va_end( argptr );
G_Printf( "%s", text );
@@ -985,9 +802,9 @@ int QDECL SortRanks( const void *a, const void *b )
cb = &level.clients[ *(int *)b ];
// then sort by score
- if( ca->pers.score > cb->pers.score )
+ if( ca->ps.persistant[ PERS_SCORE ] > cb->ps.persistant[ PERS_SCORE ] )
return -1;
- else if( ca->pers.score < cb->pers.score )
+ if( ca->ps.persistant[ PERS_SCORE ] < cb->ps.persistant[ PERS_SCORE ] )
return 1;
else
return 0;
@@ -1016,7 +833,7 @@ void G_InitSpawnQueue( spawnQueue_t *sq )
============
G_GetSpawnQueueLength
-Return tha length of a spawn queue
+Return the length of a spawn queue
============
*/
int G_GetSpawnQueueLength( spawnQueue_t *sq )
@@ -1047,6 +864,7 @@ int G_PopSpawnQueue( spawnQueue_t *sq )
{
sq->clients[ sq->front ] = -1;
sq->front = QUEUE_PLUS1( sq->front );
+ G_StopFollowing( g_entities + clientNum );
g_entities[ clientNum ].client->ps.pm_flags &= ~PMF_QUEUED;
return clientNum;
@@ -1079,8 +897,11 @@ qboolean G_SearchSpawnQueue( spawnQueue_t *sq, int clientNum )
int i;
for( i = 0; i < MAX_CLIENTS; i++ )
+ {
if( sq->clients[ i ] == clientNum )
return qtrue;
+ }
+
return qfalse;
}
@@ -1211,24 +1032,20 @@ G_SpawnClients
Spawn queued clients
============
*/
-void G_SpawnClients( pTeam_t team )
+void G_SpawnClients( team_t team )
{
int clientNum;
gentity_t *ent, *spawn;
vec3_t spawn_origin, spawn_angles;
spawnQueue_t *sq = NULL;
int numSpawns = 0;
- if( g_doWarmup.integer && ( g_warmupMode.integer==1 || g_warmupMode.integer == 2 ) &&
- level.time - level.startTime < g_warmup.integer * 1000 )
- {
- return;
- }
- if( team == PTE_ALIENS )
+
+ if( team == TEAM_ALIENS )
{
sq = &level.alienSpawnQueue;
numSpawns = level.numAlienSpawns;
}
- else if( team == PTE_HUMANS )
+ else if( team == TEAM_HUMANS )
{
sq = &level.humanSpawnQueue;
numSpawns = level.numHumanSpawns;
@@ -1250,7 +1067,7 @@ void G_SpawnClients( pTeam_t team )
ent = &g_entities[ clientNum ];
- ent->client->sess.sessionTeam = TEAM_FREE;
+ ent->client->sess.spectatorState = SPECTATOR_NOT;
ClientUserinfoChanged( clientNum, qfalse );
ClientSpawn( ent, spawn, spawn_origin, spawn_angles );
}
@@ -1271,33 +1088,31 @@ void G_CountSpawns( void )
level.numAlienSpawns = 0;
level.numHumanSpawns = 0;
-
for( i = 1, ent = g_entities + i ; i < level.num_entities ; i++, ent++ )
{
- if( !ent->inuse )
+ if( !ent->inuse || ent->s.eType != ET_BUILDABLE || ent->health <= 0 )
continue;
- if( ent->s.modelindex == BA_A_SPAWN && ent->health > 0 )
+ if( ent->s.modelindex == BA_A_SPAWN )
level.numAlienSpawns++;
- if( ent->s.modelindex == BA_H_SPAWN && ent->health > 0 )
+ if( ent->s.modelindex == BA_H_SPAWN )
level.numHumanSpawns++;
}
-
- //let the client know how many spawns there are
- trap_SetConfigstring( CS_SPAWNS, va( "%d %d",
- level.numAlienSpawns, level.numHumanSpawns ) );
}
+
/*
============
G_TimeTilSuddenDeath
============
*/
+#define SUDDENDEATHWARNING 60000
int G_TimeTilSuddenDeath( void )
{
- if( (!g_suddenDeathTime.integer && level.suddenDeathBeginTime==0 ) || level.suddenDeathBeginTime<0 )
- return 999999999; // Always some time away
+ if( ( !g_suddenDeathTime.integer && level.suddenDeathBeginTime == 0 ) ||
+ ( level.suddenDeathBeginTime < 0 ) )
+ return SUDDENDEATHWARNING + 1; // Always some time away
return ( ( level.suddenDeathBeginTime ) - ( level.time - level.startTime ) );
}
@@ -1314,180 +1129,152 @@ Recalculate the quantity of building points available to the teams
*/
void G_CalculateBuildPoints( void )
{
- int i;
- buildable_t buildable;
- gentity_t *ent;
- int localHTP = g_humanBuildPoints.integer,
- localATP = g_alienBuildPoints.integer;
-
- // g_suddenDeath sets what state we want it to be.
- // level.suddenDeath says whether we've calculated BPs at the 'start' of SD or not
+ int i;
+ buildable_t buildable;
+ buildPointZone_t *zone;
- // reset if SD was on, but now it's off
- if(!g_suddenDeath.integer && level.suddenDeath)
+ // BP queue updates
+ while( level.alienBuildPointQueue > 0 &&
+ level.alienNextQueueTime < level.time )
{
- level.suddenDeath = qfalse;
- level.suddenDeathWarning = 0;
- level.suddenDeathBeginTime = -1;
- if((level.time - level.startTime) < (g_suddenDeathTime.integer * 60000 ) )
- level.suddenDeathBeginTime = g_suddenDeathTime.integer * 60000;
- else
- level.suddenDeathBeginTime = -1;
+ level.alienBuildPointQueue--;
+ level.alienNextQueueTime += G_NextQueueTime( level.alienBuildPointQueue,
+ g_alienBuildPoints.integer,
+ g_alienBuildQueueTime.integer );
}
- if(!level.suddenDeath)
+ while( level.humanBuildPointQueue > 0 &&
+ level.humanNextQueueTime < level.time )
{
- if(g_suddenDeath.integer || G_TimeTilSuddenDeath( ) <= 0 ) //Conditions to enter SD
- {
- //begin sudden death
- if( level.suddenDeathWarning < TW_PASSED )
- {
- trap_SendServerCommand( -1, "cp \"Sudden Death!\"" );
- G_LogPrintf("Beginning Sudden Death (Mode %d)\n",g_suddenDeathMode.integer);
- localHTP = 0;
- localATP = 0;
+ level.humanBuildPointQueue--;
+ level.humanNextQueueTime += G_NextQueueTime( level.humanBuildPointQueue,
+ g_humanBuildPoints.integer,
+ g_humanBuildQueueTime.integer );
+ }
- if( g_suddenDeathMode.integer == SDMODE_SELECTIVE )
- {
- for( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
- {
- if( ent->s.eType != ET_BUILDABLE )
- continue;
-
- if( BG_FindReplaceableTestForBuildable( ent->s.modelindex ) )
- {
- int t = BG_FindTeamForBuildable( ent->s.modelindex );
-
- if( t == BIT_HUMANS )
- localHTP += BG_FindBuildPointsForBuildable( ent->s.modelindex );
- else if( t == BIT_ALIENS )
- localATP += BG_FindBuildPointsForBuildable( ent->s.modelindex );
- }
- }
- }
- level.suddenDeathHBuildPoints = localHTP;
- level.suddenDeathABuildPoints = localATP;
- level.suddenDeathBeginTime = level.time;
- level.suddenDeath=qtrue;
- trap_Cvar_Set( "g_suddenDeath", "1" );
+ // Sudden Death checks
+ if( G_TimeTilSuddenDeath( ) <= 0 && level.suddenDeathWarning < TW_PASSED )
+ {
+ G_LogPrintf( "Beginning Sudden Death\n" );
+ trap_SendServerCommand( -1, "cp \"Sudden Death!\"" );
+ trap_SendServerCommand( -1, "print \"Beginning Sudden Death.\n\"" );
+ level.suddenDeathWarning = TW_PASSED;
+ G_ClearDeconMarks( );
- level.suddenDeathWarning = TW_PASSED;
- }
- }
- else
+ // Clear blueprints, or else structs that cost 0 BP can still be built after SD
+ for( i = 0; i < level.maxclients; i++ )
{
- //warn about sudden death
- if( ( G_TimeTilSuddenDeath( ) <= 60000 ) &&
- ( level.suddenDeathWarning < TW_IMMINENT ) )
- {
- trap_SendServerCommand( -1, va("cp \"Sudden Death in %d seconds!\"",
- (int)(G_TimeTilSuddenDeath() / 1000 ) ) );
- level.suddenDeathWarning = TW_IMMINENT;
- }
+ if( g_entities[ i ].client->ps.stats[ STAT_BUILDABLE ] != BA_NONE )
+ g_entities[ i ].client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
}
}
-
- //set BP at each cycle
- if( g_suddenDeath.integer )
+ else if( G_TimeTilSuddenDeath( ) <= SUDDENDEATHWARNING &&
+ level.suddenDeathWarning < TW_IMMINENT )
{
- localHTP = level.suddenDeathHBuildPoints;
- localATP = level.suddenDeathABuildPoints;
+ trap_SendServerCommand( -1, va( "cp \"Sudden Death in %d seconds!\"",
+ (int)( G_TimeTilSuddenDeath( ) / 1000 ) ) );
+ trap_SendServerCommand( -1, va( "print \"Sudden Death will begin in %d seconds.\n\"",
+ (int)( G_TimeTilSuddenDeath( ) / 1000 ) ) );
+ level.suddenDeathWarning = TW_IMMINENT;
}
- else
+
+ level.humanBuildPoints = g_humanBuildPoints.integer - level.humanBuildPointQueue;
+ level.alienBuildPoints = g_alienBuildPoints.integer - level.alienBuildPointQueue;
+
+ // Reset buildPointZones
+ for( i = 0; i < g_humanRepeaterMaxZones.integer; i++ )
{
- localHTP = g_humanBuildPoints.integer;
- localATP = g_alienBuildPoints.integer;
+ buildPointZone_t *zone = &level.buildPointZones[ i ];
+
+ zone->active = qfalse;
+ zone->totalBuildPoints = g_humanRepeaterBuildPoints.integer;
}
- level.humanBuildPoints = level.humanBuildPointsPowered = localHTP;
- level.alienBuildPoints = localATP;
+ // Iterate through entities
+ for( i = MAX_CLIENTS; i < level.num_entities; i++ )
+ {
+ gentity_t *ent = &g_entities[ i ];
+ buildPointZone_t *zone;
+ buildable_t buildable;
+ int cost;
- level.reactorPresent = qfalse;
- level.overmindPresent = qfalse;
+ if( ent->s.eType != ET_BUILDABLE || ent->s.eFlags & EF_DEAD )
+ continue;
- for( i = 1, ent = g_entities + i ; i < level.num_entities ; i++, ent++ )
+ // mark a zone as active
+ if( ent->usesBuildPointZone )
+ {
+ assert( ent->buildPointZone >= 0 && ent->buildPointZone < g_humanRepeaterMaxZones.integer );
+
+ zone = &level.buildPointZones[ ent->buildPointZone ];
+ zone->active = qtrue;
+ }
+
+ // Subtract the BP from the appropriate pool
+ buildable = ent->s.modelindex;
+ cost = BG_Buildable( buildable )->buildPoints;
+
+ if( ent->buildableTeam == TEAM_ALIENS )
+ level.alienBuildPoints -= cost;
+ if( buildable == BA_H_REPEATER )
+ level.humanBuildPoints -= cost;
+ else if( buildable != BA_H_REACTOR )
+ {
+ gentity_t *power = G_PowerEntityForEntity( ent );
+
+ if( power )
+ {
+ if( power->s.modelindex == BA_H_REACTOR )
+ level.humanBuildPoints -= cost;
+ else if( power->s.modelindex == BA_H_REPEATER && power->usesBuildPointZone )
+ level.buildPointZones[ power->buildPointZone ].totalBuildPoints -= cost;
+ }
+ }
+ }
+
+ // Finally, update repeater zones and their queues
+ // note that this has to be done after the used BP is calculated
+ for( i = MAX_CLIENTS; i < level.num_entities; i++ )
{
- if( !ent->inuse )
- continue;
+ gentity_t *ent = &g_entities[ i ];
- if( ent->s.eType != ET_BUILDABLE )
+ if( ent->s.eType != ET_BUILDABLE || ent->s.eFlags & EF_DEAD ||
+ ent->buildableTeam != TEAM_HUMANS )
continue;
buildable = ent->s.modelindex;
- if( buildable != BA_NONE )
- {
- if( buildable == BA_H_REACTOR && ent->spawned && ent->health > 0 )
- level.reactorPresent = qtrue;
+ if( buildable != BA_H_REPEATER )
+ continue;
- if( buildable == BA_A_OVERMIND && ent->spawned && ent->health > 0 )
- level.overmindPresent = qtrue;
+ if( ent->usesBuildPointZone && level.buildPointZones[ ent->buildPointZone ].active )
+ {
+ zone = &level.buildPointZones[ ent->buildPointZone ];
- if( !g_suddenDeath.integer || BG_FindReplaceableTestForBuildable( buildable ) )
+ if( G_TimeTilSuddenDeath( ) > 0 )
{
- if( BG_FindTeamForBuildable( buildable ) == BIT_HUMANS )
- {
- level.humanBuildPoints -= BG_FindBuildPointsForBuildable( buildable );
- if( ent->powered )
- level.humanBuildPointsPowered -= BG_FindBuildPointsForBuildable( buildable );
- }
- else
+ // BP queue updates
+ while( zone->queuedBuildPoints > 0 &&
+ zone->nextQueueTime < level.time )
{
- level.alienBuildPoints -= BG_FindBuildPointsForBuildable( buildable );
+ zone->queuedBuildPoints--;
+ zone->nextQueueTime += G_NextQueueTime( zone->queuedBuildPoints,
+ zone->totalBuildPoints,
+ g_humanRepeaterBuildQueueTime.integer );
}
}
+ else
+ {
+ zone->totalBuildPoints = zone->queuedBuildPoints = 0;
+ }
}
}
if( level.humanBuildPoints < 0 )
- {
- localHTP -= level.humanBuildPoints;
- level.humanBuildPointsPowered -= level.humanBuildPoints;
level.humanBuildPoints = 0;
- }
if( level.alienBuildPoints < 0 )
- {
- localATP -= level.alienBuildPoints;
level.alienBuildPoints = 0;
- }
-
- trap_SetConfigstring( CS_BUILDPOINTS, va( "%d %d %d %d %d",
- level.alienBuildPoints, localATP,
- level.humanBuildPoints, localHTP,
- level.humanBuildPointsPowered ) );
-
- //may as well pump the stages here too
- {
- float alienPlayerCountMod = level.averageNumAlienClients / PLAYER_COUNT_MOD;
- float humanPlayerCountMod = level.averageNumHumanClients / PLAYER_COUNT_MOD;
- int alienNextStageThreshold, humanNextStageThreshold;
-
- if( alienPlayerCountMod < 0.1f )
- alienPlayerCountMod = 0.1f;
-
- if( humanPlayerCountMod < 0.1f )
- humanPlayerCountMod = 0.1f;
-
- if( g_alienStage.integer == S1 && g_alienMaxStage.integer > S1 )
- alienNextStageThreshold = (int)( ceil( (float)g_alienStage2Threshold.integer * alienPlayerCountMod ) );
- else if( g_alienStage.integer == S2 && g_alienMaxStage.integer > S2 )
- alienNextStageThreshold = (int)( ceil( (float)g_alienStage3Threshold.integer * alienPlayerCountMod ) );
- else
- alienNextStageThreshold = -1;
-
- if( g_humanStage.integer == S1 && g_humanMaxStage.integer > S1 )
- humanNextStageThreshold = (int)( ceil( (float)g_humanStage2Threshold.integer * humanPlayerCountMod ) );
- else if( g_humanStage.integer == S2 && g_humanMaxStage.integer > S2 )
- humanNextStageThreshold = (int)( ceil( (float)g_humanStage3Threshold.integer * humanPlayerCountMod ) );
- else
- humanNextStageThreshold = -1;
-
- trap_SetConfigstring( CS_STAGES, va( "%d %d %d %d %d %d",
- g_alienStage.integer, g_humanStage.integer,
- g_alienKills.integer, g_humanKills.integer,
- alienNextStageThreshold, humanNextStageThreshold ) );
- }
}
/*
@@ -1499,8 +1286,11 @@ void G_CalculateStages( void )
{
float alienPlayerCountMod = level.averageNumAlienClients / PLAYER_COUNT_MOD;
float humanPlayerCountMod = level.averageNumHumanClients / PLAYER_COUNT_MOD;
+ int alienNextStageThreshold, humanNextStageThreshold;
static int lastAlienStageModCount = 1;
static int lastHumanStageModCount = 1;
+ static int alienTriggerStage = 0;
+ static int humanTriggerStage = 0;
if( alienPlayerCountMod < 0.1f )
alienPlayerCountMod = 0.1f;
@@ -1508,7 +1298,7 @@ void G_CalculateStages( void )
if( humanPlayerCountMod < 0.1f )
humanPlayerCountMod = 0.1f;
- if( g_alienKills.integer >=
+ if( g_alienCredits.integer >=
(int)( ceil( (float)g_alienStage2Threshold.integer * alienPlayerCountMod ) ) &&
g_alienStage.integer == S1 && g_alienMaxStage.integer > S1 )
{
@@ -1518,7 +1308,7 @@ void G_CalculateStages( void )
G_LogPrintf("Stage: A 2: Aliens reached Stage 2\n");
}
- if( g_alienKills.integer >=
+ if( g_alienCredits.integer >=
(int)( ceil( (float)g_alienStage3Threshold.integer * alienPlayerCountMod ) ) &&
g_alienStage.integer == S2 && g_alienMaxStage.integer > S2 )
{
@@ -1528,7 +1318,7 @@ void G_CalculateStages( void )
G_LogPrintf("Stage: A 3: Aliens reached Stage 3\n");
}
- if( g_humanKills.integer >=
+ if( g_humanCredits.integer >=
(int)( ceil( (float)g_humanStage2Threshold.integer * humanPlayerCountMod ) ) &&
g_humanStage.integer == S1 && g_humanMaxStage.integer > S1 )
{
@@ -1538,30 +1328,33 @@ void G_CalculateStages( void )
G_LogPrintf("Stage: H 2: Humans reached Stage 2\n");
}
- if( g_humanKills.integer >=
+ if( g_humanCredits.integer >=
(int)( ceil( (float)g_humanStage3Threshold.integer * humanPlayerCountMod ) ) &&
g_humanStage.integer == S2 && g_humanMaxStage.integer > S2 )
{
trap_Cvar_Set( "g_humanStage", va( "%d", S3 ) );
level.humanStage3Time = level.time;
- G_LogPrintf("Stage: H 3: Humans reached Stage 3\n");
lastHumanStageModCount = g_humanStage.modificationCount;
+ G_LogPrintf("Stage: H 3: Humans reached Stage 3\n");
}
-
+
if( g_alienStage.modificationCount > lastAlienStageModCount )
{
- G_Checktrigger_stages( PTE_ALIENS, g_alienStage.integer );
- if( g_alienStage.integer == S2 )
+ while( alienTriggerStage < MIN( g_alienStage.integer, S3 ) )
+ G_Checktrigger_stages( TEAM_ALIENS, ++alienTriggerStage );
+
+ if( g_alienStage.integer == S2 )
level.alienStage2Time = level.time;
else if( g_alienStage.integer == S3 )
level.alienStage3Time = level.time;
-
+
lastAlienStageModCount = g_alienStage.modificationCount;
}
-
+
if( g_humanStage.modificationCount > lastHumanStageModCount )
{
- G_Checktrigger_stages( PTE_HUMANS, g_humanStage.integer );
+ while( humanTriggerStage < MIN( g_humanStage.integer, S3 ) )
+ G_Checktrigger_stages( TEAM_HUMANS, ++humanTriggerStage );
if( g_humanStage.integer == S2 )
level.humanStage2Time = level.time;
@@ -1570,6 +1363,35 @@ void G_CalculateStages( void )
lastHumanStageModCount = g_humanStage.modificationCount;
}
+
+ if( g_alienStage.integer == S1 && g_alienMaxStage.integer > S1 )
+ alienNextStageThreshold = (int)( ceil( (float)g_alienStage2Threshold.integer * alienPlayerCountMod ) );
+ else if( g_alienStage.integer == S2 && g_alienMaxStage.integer > S2 )
+ alienNextStageThreshold = (int)( ceil( (float)g_alienStage3Threshold.integer * alienPlayerCountMod ) );
+ else
+ alienNextStageThreshold = -1;
+
+ if( g_humanStage.integer == S1 && g_humanMaxStage.integer > S1 )
+ humanNextStageThreshold = (int)( ceil( (float)g_humanStage2Threshold.integer * humanPlayerCountMod ) );
+ else if( g_humanStage.integer == S2 && g_humanMaxStage.integer > S2 )
+ humanNextStageThreshold = (int)( ceil( (float)g_humanStage3Threshold.integer * humanPlayerCountMod ) );
+ else
+ humanNextStageThreshold = -1;
+
+ // save a lot of bandwidth by rounding thresholds up to the nearest 100
+ if( alienNextStageThreshold > 0 )
+ alienNextStageThreshold = ceil( (float)alienNextStageThreshold / 100 ) * 100;
+
+ if( humanNextStageThreshold > 0 )
+ humanNextStageThreshold = ceil( (float)humanNextStageThreshold / 100 ) * 100;
+
+ trap_SetConfigstring( CS_ALIEN_STAGES, va( "%d %d %d",
+ g_alienStage.integer, g_alienCredits.integer,
+ alienNextStageThreshold ) );
+
+ trap_SetConfigstring( CS_HUMAN_STAGES, va( "%d %d %d",
+ g_humanStage.integer, g_humanCredits.integer,
+ humanNextStageThreshold ) );
}
/*
@@ -1587,13 +1409,13 @@ void G_CalculateAvgPlayers( void )
if( !level.numAlienClients )
{
level.numAlienSamples = 0;
- trap_Cvar_Set( "g_alienKills", "0" );
+ trap_Cvar_Set( "g_alienCredits", "0" );
}
if( !level.numHumanClients )
{
level.numHumanSamples = 0;
- trap_Cvar_Set( "g_humanKills", "0" );
+ trap_Cvar_Set( "g_humanCredits", "0" );
}
//calculate average number of clients for stats
@@ -1623,16 +1445,14 @@ void CalculateRanks( void )
{
int i;
char P[ MAX_CLIENTS + 1 ] = {""};
- int ff = 0;
level.numConnectedClients = 0;
- level.numNonSpectatorClients = 0;
level.numPlayingClients = 0;
- level.numVotingClients = 0; // don't count bots
+ memset( level.numVotingClients, 0, sizeof( level.numVotingClients ) );
level.numAlienClients = 0;
level.numHumanClients = 0;
- level.numLiveAlienClients = 0;
- level.numLiveHumanClients = 0;
+ level.numAlienClientsAlive = 0;
+ level.numHumanClientsAlive = 0;
for( i = 0; i < level.maxclients; i++ )
{
@@ -1643,46 +1463,36 @@ void CalculateRanks( void )
level.numConnectedClients++;
P[ i ] = (char)'0' + level.clients[ i ].pers.teamSelection;
+ level.numVotingClients[ TEAM_NONE ]++;
+
if( level.clients[ i ].pers.connected != CON_CONNECTED )
continue;
- level.numVotingClients++;
- if( level.clients[ i ].pers.teamSelection != PTE_NONE )
+ if( level.clients[ i ].pers.teamSelection != TEAM_NONE )
{
level.numPlayingClients++;
- if( level.clients[ i ].sess.sessionTeam != TEAM_SPECTATOR )
- level.numNonSpectatorClients++;
-
- if( level.clients[ i ].pers.teamSelection == PTE_ALIENS )
+ if( level.clients[ i ].pers.teamSelection == TEAM_ALIENS )
{
level.numAlienClients++;
- if( level.clients[ i ].sess.sessionTeam != TEAM_SPECTATOR )
- level.numLiveAlienClients++;
+ if( level.clients[ i ].sess.spectatorState == SPECTATOR_NOT )
+ level.numAlienClientsAlive++;
}
- else if( level.clients[ i ].pers.teamSelection == PTE_HUMANS )
+ else if( level.clients[ i ].pers.teamSelection == TEAM_HUMANS )
{
level.numHumanClients++;
- if( level.clients[ i ].sess.sessionTeam != TEAM_SPECTATOR )
- level.numLiveHumanClients++;
+ if( level.clients[ i ].sess.spectatorState == SPECTATOR_NOT )
+ level.numHumanClientsAlive++;
}
}
}
}
- level.numteamVotingClients[ 0 ] = level.numHumanClients;
- level.numteamVotingClients[ 1 ] = level.numAlienClients;
+ level.numNonSpectatorClients = level.numAlienClientsAlive +
+ level.numHumanClientsAlive;
+ level.numVotingClients[ TEAM_ALIENS ] = level.numAlienClients;
+ level.numVotingClients[ TEAM_HUMANS ] = level.numHumanClients;
P[ i ] = '\0';
trap_Cvar_Set( "P", P );
- if( g_friendlyFire.value>0 )
- ff |= ( FFF_HUMANS | FFF_ALIENS );
- if( g_friendlyFireHumans.value>0 )
- ff |= FFF_HUMANS;
- if( g_friendlyFireAliens.value>0 )
- ff |= FFF_ALIENS;
- if( g_friendlyBuildableFire.value>0 )
- ff |= FFF_BUILDABLES;
- trap_Cvar_Set( "ff", va( "%i", ff ) );
-
qsort( level.sortedClients, level.numConnectedClients,
sizeof( level.sortedClients[ 0 ] ), SortRanks );
@@ -1690,7 +1500,7 @@ void CalculateRanks( void )
CheckExitRules( );
// if we are at the intermission, send the new info to everyone
- if( level.intermissiontime && !level.mapRotationVoteTime )
+ if( level.intermissiontime )
SendScoreboardMessageToAllClients( );
}
@@ -1737,8 +1547,10 @@ void MoveClientToIntermission( gentity_t *ent )
G_StopFollowing( ent );
// move to the spot
- VectorCopy( level.intermission_origin, ent->s.origin );
+ VectorCopy( level.intermission_origin, ent->s.pos.trBase );
+ VectorCopy( level.intermission_origin, ent->r.currentOrigin );
VectorCopy( level.intermission_origin, ent->client->ps.origin );
+ VectorCopy( level.intermission_angle, ent->s.apos.trBase );
VectorCopy( level.intermission_angle, ent->client->ps.viewangles );
ent->client->ps.pm_type = PM_INTERMISSION;
@@ -1748,7 +1560,6 @@ void MoveClientToIntermission( gentity_t *ent )
ent->client->ps.eFlags = 0;
ent->s.eFlags = 0;
ent->s.eType = ET_GENERAL;
- ent->s.modelindex = 0;
ent->s.loopSound = 0;
ent->s.event = 0;
ent->r.contents = 0;
@@ -1775,8 +1586,8 @@ void FindIntermissionPoint( void )
}
else
{
- VectorCopy( ent->s.origin, level.intermission_origin );
- VectorCopy( ent->s.angles, level.intermission_angle );
+ VectorCopy( ent->r.currentOrigin, level.intermission_origin );
+ VectorCopy( ent->r.currentAngles, level.intermission_angle );
// if it has a target, look towards it
if( ent->target )
{
@@ -1784,7 +1595,7 @@ void FindIntermissionPoint( void )
if( target )
{
- VectorSubtract( target->s.origin, level.intermission_origin, dir );
+ VectorSubtract( target->r.currentOrigin, level.intermission_origin, dir );
vectoangles( dir, level.intermission_angle );
}
}
@@ -1805,12 +1616,12 @@ void BeginIntermission( void )
if( level.intermissiontime )
return; // already active
- level.numTeamWarnings = 99;
-
level.intermissiontime = level.time;
G_ClearVotes( );
+ G_UpdateTeamConfigStrings( );
+
FindIntermissionPoint( );
// move all clients to the intermission point
@@ -1830,42 +1641,8 @@ void BeginIntermission( void )
// send the current scoring to all clients
SendScoreboardMessageToAllClients( );
-
- if( g_nextMap.string[ 0 ] )
- {
- trap_SendServerCommand( -1,
- va( "print \"next map has been set to %s^7%s\n\"",
- g_nextMap.string,
- ( G_CheckMapRotationVote() ) ? ", voting will be skipped" : "" ) );
- }
}
-void BeginMapRotationVote( void )
-{
- gentity_t *ent;
- int length;
- int i;
-
- if( level.mapRotationVoteTime )
- return;
-
- length = g_mapRotationVote.integer;
- if( length > 60 )
- length = 60;
- level.mapRotationVoteTime = level.time + ( length * 1000 );
-
- for( i = 0; i < level.maxclients; i++ )
- {
- ent = g_entities + i;
-
- if( !ent->inuse )
- continue;
-
- ent->client->ps.pm_type = PM_SPECTATOR;
- ent->client->sess.sessionTeam = TEAM_SPECTATOR;
- ent->client->sess.spectatorState = SPECTATOR_LOCKED;
- }
-}
/*
=============
@@ -1879,44 +1656,22 @@ void ExitLevel( void )
{
int i;
gclient_t *cl;
- buildHistory_t *tmp, *mark;
-
- char currentmap[ MAX_CVAR_VALUE_STRING ];
-
- trap_Cvar_VariableStringBuffer( "mapname", currentmap, sizeof( currentmap ));
-
- if( level.mapRotationVoteTime )
- {
- if( level.time < level.mapRotationVoteTime &&
- !G_IntermissionMapVoteWinner( ) )
- return;
- }
- else if( g_mapRotationVote.integer > 0 &&
- G_CheckMapRotationVote() &&
- !g_nextMap.string[ 0 ] )
- {
- BeginMapRotationVote( );
- return;
- }
- while( ( tmp = level.buildHistory ) )
+ if ( G_MapExists( g_nextMap.string ) )
{
- level.buildHistory = level.buildHistory->next;
- while( ( mark = tmp ) )
- {
- tmp = tmp->marked;
- G_Free( mark );
- }
+ G_MapConfigs( g_nextMap.string );
+ trap_SendConsoleCommand( EXEC_APPEND, va( "%smap \"%s\"\n",
+ ( g_cheats.integer ? "dev" : "" ), g_nextMap.string ) );
}
-
- if( !Q_stricmp( currentmap, g_nextMap.string ) )
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart\n" );
- else if ( G_MapExists( g_nextMap.string ) )
- trap_SendConsoleCommand( EXEC_APPEND, va("!map %s\n", g_nextMap.string ) );
else if( G_MapRotationActive( ) )
- G_AdvanceMapRotation( );
+ G_AdvanceMapRotation( 0 );
else
+ {
+ char map[ MAX_CVAR_VALUE_STRING ];
+ trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
+ G_MapConfigs( map );
trap_SendConsoleCommand( EXEC_APPEND, "map_restart\n" );
+ }
trap_Cvar_Set( "g_nextMap", "" );
@@ -1934,7 +1689,7 @@ void ExitLevel( void )
cl->ps.persistant[ PERS_SCORE ] = 0;
}
- // we need to do this here before chaning to CON_CONNECTING
+ // we need to do this here before changing to CON_CONNECTING
G_WriteSessionData( );
// change all client states to connecting, so the early players into the
@@ -1946,79 +1701,48 @@ void ExitLevel( void )
}
}
+
/*
=================
-G_AdminsPrintf
+G_AdminMessage
-Print to all active admins, and the logfile with a time stamp if it is open, and to the console
+Print to all active server admins, and to the logfile, and to the server console
=================
*/
-void QDECL G_AdminsPrintf( const char *fmt, ... )
+void G_AdminMessage( gentity_t *ent, const char *msg )
{
- va_list argptr;
char string[ 1024 ];
- gentity_t *tempent;
- int j;
-
- va_start( argptr, fmt );
- vsprintf( string, fmt,argptr );
- va_end( argptr );
+ int i;
- for( j = 0; j < level.maxclients; j++ )
- {
- tempent = &g_entities[ j ];
- if( G_admin_permission( tempent, ADMF_ADMINCHAT ) &&
- !tempent->client->pers.ignoreAdminWarnings )
- {
- trap_SendServerCommand(tempent-g_entities,va( "print \"^6[Admins]^7 %s\"", string) );
- }
- }
-
- G_LogPrintf("%s",string);
+ Com_sprintf( string, sizeof( string ), "chat %d %d \"%s\"",
+ (int)( ent ? ent - g_entities : -1 ),
+ G_admin_permission( ent, ADMF_ADMINCHAT ) ? SAY_ADMINS : SAY_ADMINS_PUBLIC,
+ msg );
+ // Send to all appropriate clients
+ for( i = 0; i < level.maxclients; i++ )
+ if( G_admin_permission( &g_entities[ i ], ADMF_ADMINCHAT ) )
+ trap_SendServerCommand( i, string );
+
+ // Send to the logfile and server console
+ G_LogPrintf( "%s: %d \"%s" S_COLOR_WHITE "\": " S_COLOR_MAGENTA "%s\n",
+ G_admin_permission( ent, ADMF_ADMINCHAT ) ? "AdminMsg" : "AdminMsgPublic",
+ (int)( ent ? ent - g_entities : -1 ), ent ? ent->client->pers.netname : "console",
+ msg );
}
-/*
-=================
-G_WarningsPrintf
-
-Print to everyone with a certain flag, and the logfile with a time stamp if it is open, and to the console
-(just a copy of the G_AdminsPrintf with flag suport)
-=================
-*/
-void QDECL G_WarningsPrintf( char *flag, const char *fmt, ... )
-{
- va_list argptr;
- char string[ 1024 ];
- gentity_t *tempent;
- int j;
- va_start( argptr, fmt );
- vsprintf( string, fmt,argptr );
- va_end( argptr );
-
- for( j = 0; j < level.maxclients; j++ )
- {
- tempent = &g_entities[ j ];
- if( G_admin_permission( tempent, flag ) )
- {
- trap_SendServerCommand(tempent-g_entities,va( "print \"^6[Warnings]^7 %s\"", string) );
- }
- }
-
- G_LogPrintf("%s",string);
-}
/*
=================
G_LogPrintf
-Print to the logfile with a time stamp if it is open
+Print to the logfile with a time stamp if it is open, and to the server console
=================
*/
void QDECL G_LogPrintf( const char *fmt, ... )
{
va_list argptr;
- char string[ 1024 ], decoloured[ 1024 ];
+ char string[ 1024 ], decolored[ 1024 ];
int min, tens, sec;
sec = ( level.time - level.startTime ) / 1000;
@@ -2031,186 +1755,20 @@ void QDECL G_LogPrintf( const char *fmt, ... )
Com_sprintf( string, sizeof( string ), "%3i:%i%i ", min, tens, sec );
va_start( argptr, fmt );
- vsprintf( string +7 , fmt,argptr );
+ Q_vsnprintf( string + 7, sizeof( string ) - 7, fmt, argptr );
va_end( argptr );
if( g_dedicated.integer )
- G_Printf( "%s", string + 7 );
-
- if( !level.logFile )
- return;
-
- if( g_decolourLogfiles.integer )
- {
- G_DecolorString( string, decoloured );
- trap_FS_Write( decoloured, strlen( decoloured ), level.logFile );
- }
- else
{
- trap_FS_Write( string, strlen( string ), level.logFile );
+ G_UnEscapeString( string, decolored, sizeof( decolored ) );
+ G_Printf( "%s", decolored + 7 );
}
-}
-
-/*
-=================
-G_LogPrintfColoured
-
-Bypasses g_decolourLogfiles for events that need colors in the logs
-=================
-*/
-void QDECL G_LogPrintfColoured( const char *fmt, ... )
-{
- va_list argptr;
- char string[ 1024 ];
- int min, tens, sec;
-
- sec = (level.time - level.startTime) / 1000;
-
- min = sec / 60;
- sec -= min * 60;
- tens = sec / 10;
- sec -= tens * 10;
-
- Com_sprintf( string, sizeof( string ), "%3i:%i%i ", min, tens, sec );
-
- va_start( argptr, fmt );
- vsprintf( string +7 , fmt,argptr );
- va_end( argptr );
-
- if( g_dedicated.integer )
- G_Printf( "%s", string + 7 );
if( !level.logFile )
return;
- trap_FS_Write( string, strlen( string ), level.logFile );
-}
-
-/*
-=================
-G_LogOnlyPrintf
-
-Print to the logfile only (not console) with a time stamp if it is open
-=================
-*/
-void QDECL G_LogOnlyPrintf( const char *fmt, ... )
-{
- va_list argptr;
- char string[ 1024 ], decoloured[ 1024 ];
- int min, tens, sec;
-
- sec = (level.time - level.startTime) / 1000;
-
- min = sec / 60;
- sec -= min * 60;
- tens = sec / 10;
- sec -= tens * 10;
-
- Com_sprintf( string, sizeof( string ), "%3i:%i%i ", min, tens, sec );
-
- va_start( argptr, fmt );
- vsprintf( string +7 , fmt,argptr );
- va_end( argptr );
-
- if( !level.logFile )
- return;
-
- if( g_decolourLogfiles.integer )
- {
- G_DecolorString( string, decoloured );
- trap_FS_Write( decoloured, strlen( decoloured ), level.logFile );
- }
- else
- {
- trap_FS_Write( string, strlen( string ), level.logFile );
- }
-}
-
-/*
-=================
-G_SendGameStat
-=================
-*/
-void G_SendGameStat( pTeam_t team )
-{
- char map[ MAX_STRING_CHARS ];
- char teamChar;
- char data[ BIG_INFO_STRING ];
- char entry[ MAX_STRING_CHARS ];
- int i, dataLength, entryLength;
- gclient_t *cl;
-
- trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
-
- switch( team )
- {
- case PTE_ALIENS: teamChar = 'A'; break;
- case PTE_HUMANS: teamChar = 'H'; break;
- case PTE_NONE: teamChar = 'L'; break;
- default: return;
- }
-
- Com_sprintf( data, BIG_INFO_STRING,
- "%s %s T:%c A:%f H:%f M:%s D:%d SD:%d AS:%d AS2T:%d AS3T:%d HS:%d HS2T:%d HS3T:%d CL:%d",
- Q3_VERSION,
- g_tag.string,
- teamChar,
- level.averageNumAlienClients,
- level.averageNumHumanClients,
- map,
- level.time - level.startTime,
- G_TimeTilSuddenDeath( ),
- g_alienStage.integer,
- level.alienStage2Time - level.startTime,
- level.alienStage3Time - level.startTime,
- g_humanStage.integer,
- level.humanStage2Time - level.startTime,
- level.humanStage3Time - level.startTime,
- level.numConnectedClients );
-
- dataLength = strlen( data );
-
- for( i = 0; i < level.numConnectedClients; i++ )
- {
- int ping;
-
- cl = &level.clients[ level.sortedClients[ i ] ];
-
- // Ignore invisible players
- if ( cl->sess.invisible == qtrue )
- continue;
-
- if( cl->pers.connected == CON_CONNECTING )
- ping = -1;
- else
- ping = cl->ps.ping < 999 ? cl->ps.ping : 999;
-
- switch( cl->ps.stats[ STAT_PTEAM ] )
- {
- case PTE_ALIENS: teamChar = 'A'; break;
- case PTE_HUMANS: teamChar = 'H'; break;
- case PTE_NONE: teamChar = 'S'; break;
- default: return;
- }
-
- Com_sprintf( entry, MAX_STRING_CHARS,
- " \"%s\" %c %d %d %d",
- cl->pers.netname,
- teamChar,
- cl->ps.persistant[ PERS_SCORE ],
- ping,
- ( level.time - cl->pers.enterTime ) / 60000 );
-
- entryLength = strlen( entry );
-
- if( dataLength + entryLength >= BIG_INFO_STRING )
- break;
-
- strcpy( data + dataLength, entry );
- dataLength += entryLength;
- }
-
- trap_SendGameStat( data );
+ G_DecolorString( string, decolored, sizeof( decolored ) );
+ trap_FS_Write( decolored, strlen( decolored ), level.logFile );
}
/*
@@ -2226,6 +1784,8 @@ void LogExit( const char *string )
gclient_t *cl;
gentity_t *ent;
+ level.exited = qtrue;
+
G_LogPrintf( "Exit: %s\n", string );
level.intermissionQueued = level.time;
@@ -2245,7 +1805,7 @@ void LogExit( const char *string )
cl = &level.clients[ level.sortedClients[ i ] ];
- if( cl->ps.stats[ STAT_PTEAM ] == PTE_NONE )
+ if( cl->ps.stats[ STAT_TEAM ] == TEAM_NONE )
continue;
if( cl->pers.connected == CON_CONNECTING )
@@ -2270,8 +1830,6 @@ void LogExit( const char *string )
ent->use( ent, ent, ent );
}
}
-
- G_SendGameStat( level.lastWin );
}
@@ -2287,20 +1845,13 @@ wait 10 seconds before going on.
*/
void CheckIntermissionExit( void )
{
- int ready, notReady, numPlayers;
+ int ready, notReady;
int i;
gclient_t *cl;
- int readyMask;
+ clientList_t readyMasks;
//if no clients are connected, just exit
- if( !level.numConnectedClients )
- {
- ExitLevel( );
- return;
- }
-
- // map vote started
- if( level.mapRotationVoteTime )
+ if( level.numConnectedClients == 0 )
{
ExitLevel( );
return;
@@ -2309,30 +1860,28 @@ void CheckIntermissionExit( void )
// see which players are ready
ready = 0;
notReady = 0;
- readyMask = 0;
- numPlayers = 0;
+ Com_Memset( &readyMasks, 0, sizeof( readyMasks ) );
for( i = 0; i < g_maxclients.integer; i++ )
{
cl = level.clients + i;
+
if( cl->pers.connected != CON_CONNECTED )
continue;
- if( cl->ps.stats[ STAT_PTEAM ] == PTE_NONE )
+ if( cl->ps.stats[ STAT_TEAM ] == TEAM_NONE )
continue;
if( cl->readyToExit )
{
ready++;
- if( i < 16 )
- readyMask |= 1 << i;
+
+ Com_ClientListAdd( &readyMasks, i );
}
else
notReady++;
-
- numPlayers++;
}
- trap_SetConfigstring( CS_CLIENTS_READY, va( "%d", readyMask ) );
+ trap_SetConfigstring( CS_CLIENTS_READY, Com_ClientListString( &readyMasks ) );
// never exit in less than five seconds
if( level.time < level.intermissiontime + 5000 )
@@ -2346,22 +1895,14 @@ void CheckIntermissionExit( void )
}
// if nobody wants to go, clear timer
- if( !ready && numPlayers )
+ if( ready == 0 && notReady > 0 )
{
level.readyToExit = qfalse;
return;
}
// if everyone wants to go, go now
- if( !notReady )
- {
- ExitLevel( );
- return;
- }
-
- // if only a percent is needed to ready, check for it
- if( g_readyPercent.integer && numPlayers &&
- ready * 100 / numPlayers >= g_readyPercent.integer )
+ if( notReady == 0 )
{
ExitLevel( );
return;
@@ -2434,11 +1975,10 @@ void CheckExitRules( void )
{
if( level.time - level.startTime >= g_timelimit.integer * 60000 )
{
- level.lastWin = PTE_NONE;
+ level.lastWin = TEAM_NONE;
trap_SendServerCommand( -1, "print \"Timelimit hit\n\"" );
trap_SetConfigstring( CS_WINNER, "Stalemate" );
LogExit( "Timelimit hit." );
- G_admin_maplog_result( "t" );
return;
}
else if( level.time - level.startTime >= ( g_timelimit.integer - 5 ) * 60000 &&
@@ -2456,295 +1996,177 @@ void CheckExitRules( void )
}
if( level.uncondHumanWin ||
- ( ( level.time > level.startTime + 1000 ) &&
+ ( !level.uncondAlienWin &&
+ ( level.time > level.startTime + 1000 ) &&
( level.numAlienSpawns == 0 ) &&
- ( level.numLiveAlienClients == 0 ) ) )
+ ( level.numAlienClientsAlive == 0 ) ) )
{
//humans win
- level.lastWin = PTE_HUMANS;
+ level.lastWin = TEAM_HUMANS;
trap_SendServerCommand( -1, "print \"Humans win\n\"");
trap_SetConfigstring( CS_WINNER, "Humans Win" );
LogExit( "Humans win." );
- G_admin_maplog_result( "h" );
}
else if( level.uncondAlienWin ||
( ( level.time > level.startTime + 1000 ) &&
( level.numHumanSpawns == 0 ) &&
- ( level.numLiveHumanClients == 0 ) ) )
+ ( level.numHumanClientsAlive == 0 ) ) )
{
//aliens win
- level.lastWin = PTE_ALIENS;
+ level.lastWin = TEAM_ALIENS;
trap_SendServerCommand( -1, "print \"Aliens win\n\"");
trap_SetConfigstring( CS_WINNER, "Aliens Win" );
LogExit( "Aliens win." );
- G_admin_maplog_result( "a" );
}
}
-
-
-/*
-========================================================================
-
-FUNCTIONS CALLED EVERY FRAME
-
-========================================================================
-*/
-
-
/*
==================
-CheckVote
+G_Vote
==================
*/
-void CheckVote( void )
+void G_Vote( gentity_t *ent, team_t team, qboolean voting )
{
- int votePassThreshold=level.votePassThreshold;
- int voteYesPercent;
-
- if( level.voteExecuteTime && level.voteExecuteTime < level.time )
- {
- level.voteExecuteTime = 0;
-
- if( !Q_stricmp( level.voteString, "map_restart" ) )
- {
- G_admin_maplog_result( "r" );
- }
- else if( !Q_stricmpn( level.voteString, "map", 3 ) )
- {
- G_admin_maplog_result( "m" );
- }
-
-
- if( !Q_stricmp( level.voteString, "suddendeath" ) )
- {
- level.suddenDeathBeginTime = level.time + ( 1000 * g_suddenDeathVoteDelay.integer ) - level.startTime;
-
- level.voteString[0] = '\0';
-
- if( g_suddenDeathVoteDelay.integer )
- trap_SendServerCommand( -1, va("cp \"Sudden Death will begin in %d seconds\n\"", g_suddenDeathVoteDelay.integer ) );
- }
-
- if( level.voteString[0] )
- trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.voteString ) );
+ if( !level.voteTime[ team ] )
+ return;
- if( !Q_stricmp( level.voteString, "map_restart" ) ||
- !Q_stricmpn( level.voteString, "map", 3 ) )
- {
- level.restarted = qtrue;
- }
- }
+ if( voting && ent->client->pers.voted & ( 1 << team ) )
+ return;
- if( !level.voteTime )
+ if( !voting && !( ent->client->pers.voted & ( 1 << team ) ) )
return;
- if( level.voteYes + level.voteNo > 0 )
- voteYesPercent = (int)( 100 * ( level.voteYes ) / ( level.voteYes + level.voteNo ) );
- else
- voteYesPercent = 0;
-
- if( ( level.time - level.voteTime >= VOTE_TIME ) ||
- ( level.voteYes + level.voteNo == level.numConnectedClients ) )
+ ent->client->pers.voted |= 1 << team;
+
+ if( ent->client->pers.vote & ( 1 << team ) )
{
- if( voteYesPercent> votePassThreshold || level.voteNo == 0 )
- {
- // execute the command, then remove the vote
- trap_SendServerCommand( -1, va("print \"Vote passed (%d - %d)\n\"",
- level.voteYes, level.voteNo ) );
- G_LogPrintf( "Vote: Vote passed (%d-%d)\n", level.voteYes, level.voteNo );
- level.voteExecuteTime = level.time + 3000;
- }
+ if( voting )
+ level.voteYes[ team ]++;
else
- {
- // same behavior as a timeout
- trap_SendServerCommand( -1, va("print \"Vote failed (%d - %d)\n\"",
- level.voteYes, level.voteNo ) );
- G_LogPrintf( "Vote: Vote failed (%d - %d)\n", level.voteYes, level.voteNo );
- }
+ level.voteYes[ team ]--;
+
+ trap_SetConfigstring( CS_VOTE_YES + team,
+ va( "%d", level.voteYes[ team ] ) );
}
else
{
- if( level.voteYes > (int)( (double) level.numConnectedClients *
- ( (double) votePassThreshold/100.0 ) ) )
- {
- // execute the command, then remove the vote
- trap_SendServerCommand( -1, va("print \"Vote passed (%d - %d)\n\"",
- level.voteYes, level.voteNo ) );
- G_LogPrintf( "Vote: Vote passed (%d - %d)\n", level.voteYes, level.voteNo );
- level.voteExecuteTime = level.time + 3000;
- }
- else if( level.voteNo > (int)( (double) level.numConnectedClients *
- ( (double) ( 100.0-votePassThreshold )/ 100.0 ) ) )
- {
- // same behavior as a timeout
- trap_SendServerCommand( -1, va("print \"Vote failed (%d - %d)\n\"",
- level.voteYes, level.voteNo ) );
- G_LogPrintf("Vote failed\n");
- }
+ if( voting )
+ level.voteNo[ team ]++;
else
- {
- // still waiting for a majority
- return;
- }
- }
+ level.voteNo[ team ]--;
- level.voteTime = 0;
- trap_SetConfigstring( CS_VOTE_TIME, "" );
- trap_SetConfigstring( CS_VOTE_STRING, "" );
+ trap_SetConfigstring( CS_VOTE_NO + team,
+ va( "%d", level.voteNo[ team ] ) );
+ }
}
/*
-==================
-CheckTeamVote
-==================
+========================================================================
+
+FUNCTIONS CALLED EVERY FRAME
+
+========================================================================
*/
-void CheckTeamVote( int team )
-{
- int cs_offset;
- if ( team == PTE_HUMANS )
- cs_offset = 0;
- else if ( team == PTE_ALIENS )
- cs_offset = 1;
- else
- return;
- if( !level.teamVoteTime[ cs_offset ] )
- return;
+void G_ExecuteVote( team_t team )
+{
+ level.voteExecuteTime[ team ] = 0;
- if( level.time - level.teamVoteTime[ cs_offset ] >= VOTE_TIME )
+ if( !Q_stricmpn( level.voteString[ team ], "map_restart", 11 ) )
{
- if( level.teamVoteYes[ cs_offset ] > level.teamVoteNo[ cs_offset ] && level.teamVoteYes[ cs_offset ] >= 2 )
- {
- // execute the command, then remove the vote
- trap_SendServerCommand( -1, va("print \"Team vote passed (%d - %d)\n\"", level.teamVoteYes[ cs_offset ], level.teamVoteNo[ cs_offset ] ) );
- trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.teamVoteString[ cs_offset ] ) );
- }
- else
- {
- trap_SendServerCommand( -1, va("print \"Team vote failed (%d - %d)\n\"", level.teamVoteYes[ cs_offset ], level.teamVoteNo[ cs_offset ] ) );
- G_LogPrintf( "Teamvote: Team vote failed (%d - %d)\n", level.teamVoteYes[ cs_offset ], level.teamVoteNo[ cs_offset ] );
- }
+ char map[ MAX_QPATH ];
+ trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
+ G_MapConfigs( map );
}
- else
+ else if( !Q_stricmpn( level.voteString[ team ], "map", 3 ) )
{
- if( level.teamVoteYes[ cs_offset ] > level.numteamVotingClients[ cs_offset ] / 2 )
- {
- // execute the command, then remove the vote
- trap_SendServerCommand( -1, va("print \"Team vote passed (%d - %d)\n\"", level.teamVoteYes[ cs_offset ], level.teamVoteNo[ cs_offset ] ) );
- G_LogPrintf( "Teamvote: Team vote passed (%d - %d)\n", level.teamVoteYes[ cs_offset ], level.teamVoteNo[ cs_offset ] );
- //
- trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.teamVoteString[ cs_offset ] ) );
- }
- else if( level.teamVoteNo[ cs_offset ] >= level.numteamVotingClients[ cs_offset ] / 2 )
- {
- // same behavior as a timeout
- trap_SendServerCommand( -1, va("print \"Team vote failed (%d - %d)\n\"", level.teamVoteYes[ cs_offset ], level.teamVoteNo[ cs_offset ] ) );
- G_LogPrintf( "Teamvote: Team vote failed (%d - %d)\n", level.teamVoteYes[ cs_offset ], level.teamVoteNo[ cs_offset ] );
- }
- else
- {
- // still waiting for a majority
- return;
- }
+ char map[ MAX_QPATH ];
+ char *p;
+ Q_strncpyz( map, strchr( level.voteString[ team ], '"' ) + 1, sizeof( map ) );
+ if( ( p = strchr( map, '"' ) ) )
+ *p = '\0';
+ G_MapConfigs( map );
}
- level.teamVoteTime[ cs_offset ] = 0;
- trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, "" );
- trap_SetConfigstring( CS_TEAMVOTE_STRING + cs_offset, "" );
+ trap_SendConsoleCommand( EXEC_APPEND, va( "%s%s\n",
+ ( !Q_stricmp( level.voteString[ team ], "map" ) && g_cheats.integer ? "dev" : "" ),
+ level.voteString[ team ] ) );
+
+ if( !Q_stricmpn( level.voteString[ team ], "map", 3 ) )
+ level.restarted = qtrue;
}
/*
==================
-CheckMsgTimer
+G_CheckVote
==================
*/
-void CheckMsgTimer( void )
+void G_CheckVote( team_t team )
{
- static int LastTime = 0;
+ float votePassThreshold = (float)level.voteThreshold[ team ] / 100.0f;
+ qboolean pass = qfalse;
+ const char *msg;
+ int i;
- if( level.time - LastTime < 1000 )
- return;
+ if( level.voteExecuteTime[ team ] &&
+ level.voteExecuteTime[ team ] < level.time )
+ {
+ G_ExecuteVote( team );
+ }
- LastTime = level.time;
+ if( !level.voteTime[ team ] )
+ return;
- if( level.mapRotationVoteTime )
+ if( ( level.time - level.voteTime[ team ] >= VOTE_TIME ) ||
+ ( level.voteYes[ team ] + level.voteNo[ team ] == level.numVotingClients[ team ] ) )
{
- G_IntermissionMapVoteMessageAll( );
- return;
+ pass = ( level.voteYes[ team ] &&
+ (float)level.voteYes[ team ] / ( (float)level.voteYes[ team ] + (float)level.voteNo[ team ] ) > votePassThreshold );
}
-
- if( g_welcomeMsgTime.integer && g_welcomeMsg.string[ 0 ] )
+ else
{
- char buffer[ MAX_STRING_CHARS ];
- int wt;
- int i;
-
- buffer[ 0 ] = '\0';
- wt = g_welcomeMsgTime.integer * 1000;
- for( i = 0; i < level.maxclients; i++ )
+ if( (float)level.voteYes[ team ] >
+ (float)level.numVotingClients[ team ] * votePassThreshold )
{
- if( level.clients[ i ].pers.connected != CON_CONNECTED )
- continue;
-
- if( level.time - level.clients[ i ].pers.enterTime < wt )
- {
- if( buffer[ 0 ] == '\0' )
- {
- Q_strncpyz( buffer, g_welcomeMsg.string, sizeof( buffer ) );
- G_ParseEscapedString( buffer );
- }
- trap_SendServerCommand( i, va( "cp \"%s\"", buffer ) );
- }
+ pass = qtrue;
+ }
+ else if( (float)level.voteNo[ team ] <=
+ (float)level.numVotingClients[ team ] * ( 1.0f - votePassThreshold ) )
+ {
+ return;
}
}
- if( !g_msgTime.integer )
- return;
+ if( pass )
+ level.voteExecuteTime[ team ] = level.time + level.voteDelay[ team ];
- if( level.time - level.lastMsgTime < abs( g_msgTime.integer ) * 60000 )
- return;
+ G_LogPrintf( "EndVote: %s %s %d %d %d\n",
+ team == TEAM_NONE ? "global" : BG_TeamName( team ),
+ pass ? "pass" : "fail",
+ level.voteYes[ team ], level.voteNo[ team ], level.numVotingClients[ team ] );
- // negative settings only print once per map
- if( ( level.lastMsgTime ) && g_msgTime.integer < 0 )
- return;
+ msg = va( "print \"%sote %sed (%d - %d)\n\"",
+ team == TEAM_NONE ? "V" : "Team v", pass ? "pass" : "fail",
+ level.voteYes[ team ], level.voteNo[ team ] );
- level.lastMsgTime = level.time;
-
- if( g_msg.string[0] )
- {
- char buffer[ MAX_STRING_CHARS ];
-
- Q_strncpyz( buffer, g_msg.string, sizeof( buffer ) );
- G_ParseEscapedString( buffer );
- trap_SendServerCommand( -1, va( "cp \"%s\"", buffer ) );
- trap_SendServerCommand( -1, va( "print \"%s\n\"", buffer ) );
- }
-}
-
-/*
-==================
-CheckCountdown
-==================
-*/
-void CheckCountdown( void )
-{
- static int lastmsg = 0;
- int timeleft = g_warmup.integer - ( level.time - level.startTime ) / 1000;
+ if( team == TEAM_NONE )
+ trap_SendServerCommand( -1, msg );
+ else
+ G_TeamCommand( team, msg );
- if( !g_doWarmup.integer || timeleft < 0 )
- return;
+ level.voteTime[ team ] = 0;
+ level.voteYes[ team ] = 0;
+ level.voteNo[ team ] = 0;
- if( level.time - lastmsg < 1000 )
- return;
+ for( i = 0; i < level.maxclients; i++ )
+ level.clients[ i ].pers.voted &= ~( 1 << team );
- lastmsg = level.time;
- if( timeleft > 0 )
- trap_SendServerCommand( -1, va( "cp \"^1Warmup Time:^7\n^%i----- ^7%i ^%i-----\"", timeleft % 7, timeleft, timeleft % 7 ) );
- else if( timeleft == 0 )
- trap_SendServerCommand( -1, "cp \"^2----- GO! -----^7\"" );
+ trap_SetConfigstring( CS_VOTE_TIME + team, "" );
+ trap_SetConfigstring( CS_VOTE_STRING + team, "" );
+ trap_SetConfigstring( CS_VOTE_YES + team, "0" );
+ trap_SetConfigstring( CS_VOTE_NO + team, "0" );
}
@@ -2758,6 +2180,7 @@ void CheckCvars( void )
static int lastPasswordModCount = -1;
static int lastMarkDeconModCount = -1;
static int lastSDTimeModCount = -1;
+ static int lastNumZones = 0;
if( g_password.modificationCount != lastPasswordModCount )
{
@@ -2773,29 +2196,36 @@ void CheckCvars( void )
// the server setting is changed
if( g_markDeconstruct.modificationCount != lastMarkDeconModCount )
{
- int i;
- gentity_t *ent;
-
lastMarkDeconModCount = g_markDeconstruct.modificationCount;
-
- for( i = 1, ent = g_entities + i ; i < level.num_entities ; i++, ent++ )
- {
- if( !ent->inuse )
- continue;
-
- if( ent->s.eType != ET_BUILDABLE )
- continue;
-
- ent->deconstruct = qfalse;
- }
+ G_ClearDeconMarks( );
}
+ // If we change g_suddenDeathTime during a map, we need to update
+ // when sd will begin
if( g_suddenDeathTime.modificationCount != lastSDTimeModCount )
{
lastSDTimeModCount = g_suddenDeathTime.modificationCount;
level.suddenDeathBeginTime = g_suddenDeathTime.integer * 60000;
}
+ // If the number of zones changes, we need a new array
+ if( g_humanRepeaterMaxZones.integer != lastNumZones )
+ {
+ buildPointZone_t *newZones;
+ size_t newsize = g_humanRepeaterMaxZones.integer * sizeof( buildPointZone_t );
+ size_t oldsize = lastNumZones * sizeof( buildPointZone_t );
+
+ newZones = BG_Alloc( newsize );
+ if( level.buildPointZones )
+ {
+ Com_Memcpy( newZones, level.buildPointZones, MIN( oldsize, newsize ) );
+ BG_Free( level.buildPointZones );
+ }
+
+ level.buildPointZones = newZones;
+ lastNumZones = g_humanRepeaterMaxZones.integer;
+ }
+
level.frameMsec = trap_Milliseconds( );
}
@@ -2855,47 +2285,62 @@ Advances the non-player objects in the world
*/
void G_RunFrame( int levelTime )
{
- int i;
- gentity_t *ent;
- int msec;
- int start, end;
+ int i;
+ gentity_t *ent;
+ int msec;
+ static int ptime3000 = 0;
// if we are waiting for the level to restart, do nothing
if( level.restarted )
return;
-
- if( level.paused )
+
+ if( level.pausedTime )
{
- if( ( levelTime % 6000 ) == 0)
- trap_SendServerCommand( -1, "cp \"^3Game is paused.\"" );
+ msec = levelTime - level.time - level.pausedTime;
+ level.pausedTime = levelTime - level.time;
+
+ ptime3000 += msec;
+ while( ptime3000 > 3000 )
+ {
+ ptime3000 -= 3000;
+ trap_SendServerCommand( -1, "cp \"The game has been paused. Please wait.\"" );
- level.startTime += levelTime - level.time;
- trap_SetConfigstring( CS_LEVEL_START_TIME, va( "%i", level.startTime ) );
+ if( level.pausedTime >= 110000 && level.pausedTime <= 119000 )
+ trap_SendServerCommand( -1, va( "print \"Server: Game will auto-unpause in %d seconds\n\"",
+ (int) ( (float) ( 120000 - level.pausedTime ) / 1000.0f ) ) );
+ }
- if( levelTime - level.pauseTime > 3 * 60000 )
+ // Prevents clients from getting lagged-out messages
+ for( i = 0; i < level.maxclients; i++ )
{
- trap_SendConsoleCommand( EXEC_APPEND, "!unpause" );
+ if( level.clients[ i ].pers.connected == CON_CONNECTED )
+ level.clients[ i ].ps.commandTime = levelTime;
}
+
+ if( level.pausedTime > 120000 )
+ {
+ trap_SendServerCommand( -1, "print \"Server: The game has been unpaused automatically (2 minute max)\n\"" );
+ trap_SendServerCommand( -1, "cp \"The game has been unpaused!\"" );
+ level.pausedTime = 0;
+ }
+
+ return;
}
- CheckMsgTimer( );
- CheckCountdown( );
-
level.framenum++;
level.previousTime = level.time;
level.time = levelTime;
msec = level.time - level.previousTime;
- //TA: seed the rng
- srand( level.framenum );
-
// get any cvar changes
G_UpdateCvars( );
+ CheckCvars( );
+ // now we are done spawning
+ level.spawning = qfalse;
//
// go through all allocated objects
//
- start = trap_Milliseconds( );
ent = &g_entities[ 0 ];
for( i = 0; i < level.num_entities; i++, ent++ )
@@ -2935,7 +2380,7 @@ void G_RunFrame( int levelTime )
if( ent->freeAfterEvent )
continue;
- //TA: calculate the acceleration of this entity
+ // calculate the acceleration of this entity
if( ent->evaluateAcceleration )
G_EvaluateAcceleration( ent, msec );
@@ -2948,6 +2393,12 @@ void G_RunFrame( int levelTime )
continue;
}
+ if ( ent->s.eType == ET_WEAPON_DROP )
+ {
+ G_RunWeaponDrop( ent );
+ continue;
+ }
+
if( ent->s.eType == ET_BUILDABLE )
{
G_BuildableThink( ent, msec );
@@ -2974,9 +2425,6 @@ void G_RunFrame( int levelTime )
G_RunThink( ent );
}
- end = trap_Milliseconds();
-
- start = trap_Milliseconds();
// perform final fixups on the players
ent = &g_entities[ 0 ];
@@ -2987,19 +2435,20 @@ void G_RunFrame( int levelTime )
ClientEndFrame( ent );
}
- // save position information for all active clients
+ // save position information for all active clients
G_UnlaggedStore( );
- end = trap_Milliseconds();
-
- //TA:
G_CountSpawns( );
- G_CalculateBuildPoints( );
- G_CalculateStages( );
- G_SpawnClients( PTE_ALIENS );
- G_SpawnClients( PTE_HUMANS );
- G_CalculateAvgPlayers( );
- G_UpdateZaps( msec );
+ if( !g_doWarmup.integer || level.warmupTime <= level.time )
+ {
+ G_CalculateBuildPoints( );
+ G_CalculateStages( );
+ G_SpawnClients( TEAM_ALIENS );
+ G_SpawnClients( TEAM_HUMANS );
+ G_CalculateAvgPlayers( );
+ G_UpdateZaps( msec );
+ }
+ G_UpdateBuildableRangeMarkers( );
// see if it is time to end the level
CheckExitRules( );
@@ -3008,23 +2457,8 @@ void G_RunFrame( int levelTime )
CheckTeamStatus( );
// cancel vote if timed out
- CheckVote( );
-
- // check team votes
- CheckTeamVote( PTE_HUMANS );
- CheckTeamVote( PTE_ALIENS );
+ for( i = 0; i < NUM_TEAMS; i++ )
+ G_CheckVote( i );
- G_admin_schachtmeisterFrame();
-
- // for tracking changes
- CheckCvars( );
-
- if( g_listEntity.integer )
- {
- for( i = 0; i < MAX_GENTITIES; i++ )
- G_Printf( "%4i: %s\n", i, g_entities[ i ].classname );
-
- trap_Cvar_Set( "g_listEntity", "0" );
- }
+ level.frameMsec = trap_Milliseconds();
}
-
diff --git a/src/game/g_maprotation.c b/src/game/g_maprotation.c
index a846c79..90a51cf 100644
--- a/src/game/g_maprotation.c
+++ b/src/game/g_maprotation.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -25,10 +26,91 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "g_local.h"
-mapRotations_t mapRotations;
+#define MAX_MAP_ROTATIONS 64
+#define MAX_MAP_ROTATION_MAPS 256
+
+#define NOT_ROTATING -1
+
+typedef enum
+{
+ CV_ERR,
+ CV_RANDOM,
+ CV_NUMCLIENTS,
+ CV_LASTWIN
+} conditionVariable_t;
+
+typedef enum
+{
+ CO_LT,
+ CO_EQ,
+ CO_GT
+} conditionOp_t;
+
+typedef struct condition_s
+{
+ struct node_s *target;
+
+ conditionVariable_t lhs;
+ conditionOp_t op;
+
+ int numClients;
+ team_t lastWin;
+} condition_t;
+
+typedef struct map_s
+{
+ char name[ MAX_QPATH ];
+
+ char postCommand[ MAX_STRING_CHARS ];
+ char layouts[ MAX_CVAR_VALUE_STRING ];
+} map_t;
+
+typedef struct label_s
+{
+ char name[ MAX_QPATH ];
+} label_t;
+
+typedef enum
+{
+ NT_MAP,
+ NT_CONDITION,
+ NT_GOTO,
+ NT_RESUME,
+ NT_LABEL,
+ NT_RETURN
+} nodeType_t;
+
+typedef struct node_s
+{
+ nodeType_t type;
+
+ union
+ {
+ map_t map;
+ condition_t condition;
+ label_t label;
+ } u;
+} node_t;
-static qboolean G_GetVotedMap( char *name, int size, int rotation, int map );
+typedef struct mapRotation_s
+{
+ char name[ MAX_QPATH ];
+
+ node_t *nodes[ MAX_MAP_ROTATION_MAPS ];
+ int numNodes;
+ int currentNode;
+} mapRotation_t;
+
+typedef struct mapRotations_s
+{
+ mapRotation_t rotations[ MAX_MAP_ROTATIONS ];
+ int numRotations;
+} mapRotations_t;
+
+static mapRotations_t mapRotations;
+
+static int G_NodeIndexAfter( int currentNode, int rotation );
/*
===============
@@ -37,9 +119,21 @@ G_MapExists
Check if a map exists
===============
*/
-qboolean G_MapExists( char *name )
+qboolean G_MapExists( const char *name )
+{
+ return trap_FS_FOpenFile( va( "maps/%s.bsp", name ), NULL, FS_READ ) > 0;
+}
+
+/*
+===============
+G_LayoutExists
+
+Check if a layout exists for a map
+===============
+*/
+qboolean G_LayoutExists( const char *map, const char *layout )
{
- return trap_FS_FOpenFile( va( "maps/%s.bsp", name ), NULL, FS_READ );
+ return !Q_stricmp( layout, "*BUILTIN*" ) || trap_FS_FOpenFile( va( "layouts/%s/%s.dat", map, layout ), NULL, FS_READ ) > 0;
}
/*
@@ -64,62 +158,111 @@ static qboolean G_RotationExists( char *name )
/*
===============
-G_ParseCommandSection
+G_LabelExists
+
+Check if a label exists in a rotation
+===============
+*/
+static qboolean G_LabelExists( int rotation, char *name )
+{
+ mapRotation_t *mr = &mapRotations.rotations[ rotation ];
+ int i;
+
+ for( i = 0; i < mr->numNodes; i++ )
+ {
+ node_t *node = mr->nodes[ i ];
+
+ if( node->type == NT_LABEL &&
+ !Q_stricmp( name, node->u.label.name ) )
+ return qtrue;
+
+ if( node->type == NT_MAP &&
+ !Q_stricmp( name, node->u.map.name ) )
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+===============
+G_AllocateNode
+
+Allocate memory for a node_t
+===============
+*/
+static node_t *G_AllocateNode( void )
+{
+ node_t *node = BG_Alloc( sizeof( node_t ) );
+
+ return node;
+}
+
+/*
+===============
+G_ParseMapCommandSection
Parse a map rotation command section
===============
*/
-static qboolean G_ParseMapCommandSection( mapRotationEntry_t *mre, char **text_p )
+static qboolean G_ParseMapCommandSection( node_t *node, char **text_p )
{
- char *token;
+ char *token;
+ map_t *map = &node->u.map;
+ int commandLength = 0;
// read optional parameters
while( 1 )
{
token = COM_Parse( text_p );
- if( !token )
+ if( !*token )
break;
if( !Q_stricmp( token, "" ) )
return qfalse;
if( !Q_stricmp( token, "}" ) )
+ {
+ if( commandLength > 0 )
+ {
+ // Replace last ; with \n
+ map->postCommand[ commandLength - 1 ] = '\n';
+ }
+
return qtrue; //reached the end of this command section
+ }
if( !Q_stricmp( token, "layouts" ) )
{
token = COM_ParseExt( text_p, qfalse );
- mre->layouts[ 0 ] = '\0';
- while( token && token[ 0 ] != 0 )
+ map->layouts[ 0 ] = '\0';
+
+ while( token[ 0 ] != 0 )
{
- Q_strcat( mre->layouts, sizeof( mre->layouts ), token );
- Q_strcat( mre->layouts, sizeof( mre->layouts ), " " );
+ Q_strcat( map->layouts, sizeof( map->layouts ), token );
+ Q_strcat( map->layouts, sizeof( map->layouts ), " " );
token = COM_ParseExt( text_p, qfalse );
}
+
continue;
}
- Q_strncpyz( mre->postCmds[ mre->numCmds ], token, sizeof( mre->postCmds[ 0 ] ) );
- Q_strcat( mre->postCmds[ mre->numCmds ], sizeof( mre->postCmds[ 0 ] ), " " );
+ // Parse the rest of the line into map->postCommand
+ Q_strcat( map->postCommand, sizeof( map->postCommand ), token );
+ Q_strcat( map->postCommand, sizeof( map->postCommand ), " " );
token = COM_ParseExt( text_p, qfalse );
- while( token && token[ 0 ] != 0 )
+ while( token[ 0 ] != 0 )
{
- Q_strcat( mre->postCmds[ mre->numCmds ], sizeof( mre->postCmds[ 0 ] ), token );
- Q_strcat( mre->postCmds[ mre->numCmds ], sizeof( mre->postCmds[ 0 ] ), " " );
+ Q_strcat( map->postCommand, sizeof( map->postCommand ), token );
+ Q_strcat( map->postCommand, sizeof( map->postCommand ), " " );
token = COM_ParseExt( text_p, qfalse );
}
- if( mre->numCmds == MAX_MAP_COMMANDS )
- {
- G_Printf( S_COLOR_RED "ERROR: maximum number of map commands (%d) reached\n",
- MAX_MAP_COMMANDS );
- return qfalse;
- }
- else
- mre->numCmds++;
+ commandLength = strlen( map->postCommand );
+ map->postCommand[ commandLength - 1 ] = ';';
}
return qfalse;
@@ -127,291 +270,195 @@ static qboolean G_ParseMapCommandSection( mapRotationEntry_t *mre, char **text_p
/*
===============
-G_ParseMapRotation
+G_ParseNode
-Parse a map rotation section
+Parse a node
===============
*/
-static qboolean G_ParseMapRotation( mapRotation_t *mr, char **text_p )
+static qboolean G_ParseNode( node_t **node, char *token, char **text_p, qboolean conditional )
{
- char *token;
- qboolean mnSet = qfalse;
- mapRotationEntry_t *mre = NULL;
- mapRotationCondition_t *mrc;
-
- // read optional parameters
- while( 1 )
+ if( !Q_stricmp( token, "if" ) )
{
- token = COM_Parse( text_p );
+ condition_t *condition;
- if( !token )
- break;
+ (*node)->type = NT_CONDITION;
+ condition = &(*node)->u.condition;
- if( !Q_stricmp( token, "" ) )
+ token = COM_Parse( text_p );
+
+ if( !*token )
return qfalse;
- if( !Q_stricmp( token, "{" ) )
+ if( !Q_stricmp( token, "numClients" ) )
{
- if( !mnSet )
- {
- G_Printf( S_COLOR_RED "ERROR: map settings section with no name\n" );
+ condition->lhs = CV_NUMCLIENTS;
+
+ token = COM_Parse( text_p );
+
+ if( !*token )
return qfalse;
- }
- if( !G_ParseMapCommandSection( mre, text_p ) )
+ if( !Q_stricmp( token, "<" ) )
+ condition->op = CO_LT;
+ else if( !Q_stricmp( token, ">" ) )
+ condition->op = CO_GT;
+ else if( !Q_stricmp( token, "=" ) )
+ condition->op = CO_EQ;
+ else
{
- G_Printf( S_COLOR_RED "ERROR: failed to parse map command section\n" );
+ G_Printf( S_COLOR_RED "ERROR: invalid operator in expression: %s\n", token );
return qfalse;
}
- mnSet = qfalse;
- continue;
- }
- else if( !Q_stricmp( token, "goto" ) )
- {
token = COM_Parse( text_p );
- if( !token )
- break;
-
- mrc = &mre->conditions[ mre->numConditions ];
- mrc->unconditional = qtrue;
- Q_strncpyz( mrc->dest, token, sizeof( mrc->dest ) );
-
- if( mre->numConditions == MAX_MAP_ROTATION_CONDS )
- {
- G_Printf( S_COLOR_RED "ERROR: maximum number of conditions for one map (%d) reached\n",
- MAX_MAP_ROTATION_CONDS );
+ if( !*token )
return qfalse;
- }
- else
- mre->numConditions++;
- continue;
+ condition->numClients = atoi( token );
}
- else if( !Q_stricmp( token, "if" ) )
+ else if( !Q_stricmp( token, "lastWin" ) )
{
- token = COM_Parse( text_p );
+ condition->lhs = CV_LASTWIN;
- if( !token )
- break;
+ token = COM_Parse( text_p );
- mrc = &mre->conditions[ mre->numConditions ];
+ if( !*token )
+ return qfalse;
- if( !Q_stricmp( token, "numClients" ) )
+ if( !Q_stricmp( token, "aliens" ) )
+ condition->lastWin = TEAM_ALIENS;
+ else if( !Q_stricmp( token, "humans" ) )
+ condition->lastWin = TEAM_HUMANS;
+ else
{
- mrc->lhs = MCV_NUMCLIENTS;
+ G_Printf( S_COLOR_RED "ERROR: invalid right hand side in expression: %s\n", token );
+ return qfalse;
+ }
+ }
+ else if( !Q_stricmp( token, "random" ) )
+ condition->lhs = CV_RANDOM;
+ else
+ {
+ G_Printf( S_COLOR_RED "ERROR: invalid left hand side in expression: %s\n", token );
+ return qfalse;
+ }
- token = COM_Parse( text_p );
+ token = COM_Parse( text_p );
- if( !token )
- break;
+ if( !*token )
+ return qfalse;
- if( !Q_stricmp( token, "<" ) )
- mrc->op = MCO_LT;
- else if( !Q_stricmp( token, ">" ) )
- mrc->op = MCO_GT;
- else if( !Q_stricmp( token, "=" ) )
- mrc->op = MCO_EQ;
- else
- {
- G_Printf( S_COLOR_RED "ERROR: invalid operator in expression: %s\n", token );
- return qfalse;
- }
+ condition->target = G_AllocateNode( );
+ *node = condition->target;
- token = COM_Parse( text_p );
+ return G_ParseNode( node, token, text_p, qtrue );
+ }
+ else if( !Q_stricmp( token, "return" ) )
+ {
+ (*node)->type = NT_RETURN;
+ }
+ else if( !Q_stricmp( token, "goto" ) ||
+ !Q_stricmp( token, "resume" ) )
+ {
+ label_t *label;
- if( !token )
- break;
+ if( !Q_stricmp( token, "goto" ) )
+ (*node)->type = NT_GOTO;
+ else
+ (*node)->type = NT_RESUME;
+ label = &(*node)->u.label;
- mrc->numClients = atoi( token );
- }
- else if( !Q_stricmp( token, "lastWin" ) )
- {
- mrc->lhs = MCV_LASTWIN;
+ token = COM_Parse( text_p );
- token = COM_Parse( text_p );
+ if( !*token )
+ {
+ G_Printf( S_COLOR_RED "ERROR: goto or resume without label\n" );
+ return qfalse;
+ }
- if( !token )
- break;
+ Q_strncpyz( label->name, token, sizeof( label->name ) );
+ }
+ else if( *token == '#' || conditional )
+ {
+ label_t *label;
- if( !Q_stricmp( token, "aliens" ) )
- mrc->lastWin = PTE_ALIENS;
- else if( !Q_stricmp( token, "humans" ) )
- mrc->lastWin = PTE_HUMANS;
- else
- {
- G_Printf( S_COLOR_RED "ERROR: invalid right hand side in expression: %s\n", token );
- return qfalse;
- }
- }
- else if( !Q_stricmp( token, "random" ) )
- mrc->lhs = MCV_RANDOM;
- else
- {
- G_Printf( S_COLOR_RED "ERROR: invalid left hand side in expression: %s\n", token );
- return qfalse;
- }
+ (*node)->type = ( conditional ) ? NT_GOTO : NT_LABEL;
+ label = &(*node)->u.label;
- token = COM_Parse( text_p );
+ Q_strncpyz( label->name, token, sizeof( label->name ) );
+ }
+ else
+ {
+ map_t *map;
- if( !token )
- break;
+ (*node)->type = NT_MAP;
+ map = &(*node)->u.map;
- mrc->unconditional = qfalse;
- Q_strncpyz( mrc->dest, token, sizeof( mrc->dest ) );
+ Q_strncpyz( map->name, token, sizeof( map->name ) );
+ map->postCommand[ 0 ] = '\0';
+ }
- if( mre->numConditions == MAX_MAP_ROTATION_CONDS )
- {
- G_Printf( S_COLOR_RED "ERROR: maximum number of conditions for one map (%d) reached\n",
- MAX_MAP_ROTATION_CONDS );
- return qfalse;
- }
- else
- mre->numConditions++;
+ return qtrue;
+}
- continue;
- }
- else if( !Q_stricmp( token, "*VOTE*" ) )
- {
- if( mr->numMaps == MAX_MAP_ROTATION_MAPS )
- {
- G_Printf( S_COLOR_RED "ERROR: maximum number of maps in one rotation (%d) reached\n",
- MAX_MAP_ROTATION_MAPS );
- return qfalse;
- }
- mre = &mr->maps[ mr->numMaps ];
- Q_strncpyz( mre->name, token, sizeof( mre->name ) );
+/*
+===============
+G_ParseMapRotation
- token = COM_Parse( text_p );
+Parse a map rotation section
+===============
+*/
+static qboolean G_ParseMapRotation( mapRotation_t *mr, char **text_p )
+{
+ char *token;
+ node_t *node = NULL;
- if( !Q_stricmp( token, "{" ) )
- {
- while( 1 )
- {
- token = COM_Parse( text_p );
+ // read optional parameters
+ while( 1 )
+ {
+ token = COM_Parse( text_p );
- if( !token )
- break;
+ if( !*token )
+ break;
- if( !Q_stricmp( token, "}" ) )
- {
- break;
- }
- else
- {
- if( mre->numConditions < MAX_MAP_ROTATION_CONDS )
- {
- mrc = &mre->conditions[ mre->numConditions ];
- mrc->lhs = MCV_VOTE;
- mrc->unconditional = qfalse;
- Q_strncpyz( mrc->dest, token, sizeof( mrc->dest ) );
-
- mre->numConditions++;
- }
- else
- {
- G_Printf( S_COLOR_YELLOW "WARNING: maximum number of maps for one vote (%d) reached\n",
- MAX_MAP_ROTATION_CONDS );
- }
- }
- }
- if( !mre->numConditions )
- {
- G_Printf( S_COLOR_YELLOW "WARNING: no maps in *VOTE* section\n" );
- }
- else
- {
- mr->numMaps++;
- mnSet = qtrue;
- }
- }
- else
- {
- G_Printf( S_COLOR_RED "ERROR: *VOTE* with no section\n" );
- return qfalse;
- }
+ if( !Q_stricmp( token, "" ) )
+ return qfalse;
- continue;
- }
- else if( !Q_stricmp( token, "*RANDOM*" ) )
+ if( !Q_stricmp( token, "{" ) )
{
- if( mr->numMaps == MAX_MAP_ROTATION_MAPS )
+ if( node == NULL )
{
- G_Printf( S_COLOR_RED "ERROR: maximum number of maps in one rotation (%d) reached\n",
- MAX_MAP_ROTATION_MAPS );
+ G_Printf( S_COLOR_RED "ERROR: map command section with no associated map\n" );
return qfalse;
}
- mre = &mr->maps[ mr->numMaps ];
- Q_strncpyz( mre->name, token, sizeof( mre->name ) );
-
- token = COM_Parse( text_p );
-
- if( !Q_stricmp( token, "{" ) )
- {
- while( 1 )
- {
- token = COM_Parse( text_p );
-
- if( !token )
- break;
- if( !Q_stricmp( token, "}" ) )
- {
- break;
- }
- else
- {
- if( mre->numConditions < MAX_MAP_ROTATION_CONDS )
- {
- mrc = &mre->conditions[ mre->numConditions ];
- mrc->lhs = MCV_SELECTEDRANDOM;
- mrc->unconditional = qfalse;
- Q_strncpyz( mrc->dest, token, sizeof( mrc->dest ) );
-
- mre->numConditions++;
- }
- else
- {
- G_Printf( S_COLOR_YELLOW "WARNING: maximum number of maps for one Random Slot (%d) reached\n",
- MAX_MAP_ROTATION_CONDS );
- }
- }
- }
- if( !mre->numConditions )
- {
- G_Printf( S_COLOR_YELLOW "WARNING: no maps in *RANDOM* section\n" );
- }
- else
- {
- mr->numMaps++;
- mnSet = qtrue;
- }
- }
- else
+ if( !G_ParseMapCommandSection( node, text_p ) )
{
- G_Printf( S_COLOR_RED "ERROR: *RANDOM* with no section\n" );
+ G_Printf( S_COLOR_RED "ERROR: failed to parse map command section\n" );
return qfalse;
}
continue;
}
else if( !Q_stricmp( token, "}" ) )
- return qtrue; //reached the end of this map rotation
-
- mre = &mr->maps[ mr->numMaps ];
+ {
+ // Reached the end of this map rotation
+ return qtrue;
+ }
- if( mr->numMaps == MAX_MAP_ROTATION_MAPS )
+ if( mr->numNodes == MAX_MAP_ROTATION_MAPS )
{
G_Printf( S_COLOR_RED "ERROR: maximum number of maps in one rotation (%d) reached\n",
MAX_MAP_ROTATION_MAPS );
return qfalse;
}
- else
- mr->numMaps++;
- Q_strncpyz( mre->name, token, sizeof( mre->name ) );
- mnSet = qtrue;
+ node = G_AllocateNode( );
+ mr->nodes[ mr->numNodes++ ] = node;
+
+ if( !G_ParseNode( &node, token, text_p, qfalse ) )
+ return qfalse;
}
return qfalse;
@@ -427,7 +474,7 @@ Load the map rotations from a map rotation file
static qboolean G_ParseMapRotationFile( const char *fileName )
{
char *text_p;
- int i, j, k;
+ int i, j;
int len;
char *token;
char text[ 20000 ];
@@ -460,7 +507,7 @@ static qboolean G_ParseMapRotationFile( const char *fileName )
{
token = COM_Parse( &text_p );
- if( !token )
+ if( !*token )
break;
if( !Q_stricmp( token, "" ) )
@@ -471,13 +518,17 @@ static qboolean G_ParseMapRotationFile( const char *fileName )
if( mrNameSet )
{
//check for name space clashes
- for( i = 0; i < mapRotations.numRotations; i++ )
+ if( G_RotationExists( mrName ) )
{
- if( !Q_stricmp( mapRotations.rotations[ i ].name, mrName ) )
- {
- G_Printf( S_COLOR_RED "ERROR: a map rotation is already named %s\n", mrName );
- return qfalse;
- }
+ G_Printf( S_COLOR_RED "ERROR: a map rotation is already named %s\n", mrName );
+ return qfalse;
+ }
+
+ if( mapRotations.numRotations == MAX_MAP_ROTATIONS )
+ {
+ G_Printf( S_COLOR_RED "ERROR: maximum number of map rotations (%d) reached\n",
+ MAX_MAP_ROTATIONS );
+ return qfalse;
}
Q_strncpyz( mapRotations.rotations[ mapRotations.numRotations ].name, mrName, MAX_QPATH );
@@ -488,23 +539,16 @@ static qboolean G_ParseMapRotationFile( const char *fileName )
return qfalse;
}
+ mapRotations.numRotations++;
+
//start parsing map rotations again
mrNameSet = qfalse;
- if( mapRotations.numRotations == MAX_MAP_ROTATIONS )
- {
- G_Printf( S_COLOR_RED "ERROR: maximum number of map rotations (%d) reached\n",
- MAX_MAP_ROTATIONS );
- return qfalse;
- }
- else
- mapRotations.numRotations++;
-
continue;
}
else
{
- G_Printf( S_COLOR_RED "ERROR: unamed map rotation\n" );
+ G_Printf( S_COLOR_RED "ERROR: unnamed map rotation\n" );
return qfalse;
}
}
@@ -523,29 +567,46 @@ static qboolean G_ParseMapRotationFile( const char *fileName )
for( i = 0; i < mapRotations.numRotations; i++ )
{
- for( j = 0; j < mapRotations.rotations[ i ].numMaps; j++ )
+ mapRotation_t *mr = &mapRotations.rotations[ i ];
+ int mapCount = 0;
+
+ for( j = 0; j < mr->numNodes; j++ )
{
- if( Q_stricmp( mapRotations.rotations[ i ].maps[ j ].name, "*VOTE*") != 0 &&
- Q_stricmp( mapRotations.rotations[ i ].maps[ j ].name, "*RANDOM*") != 0 &&
- !G_MapExists( mapRotations.rotations[ i ].maps[ j ].name ) )
- {
- G_Printf( S_COLOR_RED "ERROR: map \"%s\" doesn't exist\n",
- mapRotations.rotations[ i ].maps[ j ].name );
- return qfalse;
- }
+ node_t *node = mr->nodes[ j ];
- for( k = 0; k < mapRotations.rotations[ i ].maps[ j ].numConditions; k++ )
+ if( node->type == NT_MAP )
{
- if( !G_MapExists( mapRotations.rotations[ i ].maps[ j ].conditions[ k ].dest ) &&
- !G_RotationExists( mapRotations.rotations[ i ].maps[ j ].conditions[ k ].dest ) )
+ mapCount++;
+ if( !G_MapExists( node->u.map.name ) )
{
- G_Printf( S_COLOR_RED "ERROR: conditional destination \"%s\" doesn't exist\n",
- mapRotations.rotations[ i ].maps[ j ].conditions[ k ].dest );
+ G_Printf( S_COLOR_RED "ERROR: rotation map \"%s\" doesn't exist\n",
+ node->u.map.name );
return qfalse;
}
+ continue;
+ }
+ else if( node->type == NT_RETURN )
+ continue;
+ else if( node->type == NT_LABEL )
+ continue;
+ else while( node->type == NT_CONDITION )
+ node = node->u.condition.target;
+ if( ( node->type == NT_GOTO || node->type == NT_RESUME ) &&
+ !G_LabelExists( i, node->u.label.name ) &&
+ !G_RotationExists( node->u.label.name ) )
+ {
+ G_Printf( S_COLOR_RED "ERROR: goto destination named \"%s\" doesn't exist\n",
+ node->u.label.name );
+ return qfalse;
}
+ }
+ if( mapCount == 0 )
+ {
+ G_Printf( S_COLOR_RED "ERROR: rotation \"%s\" needs at least one map entry\n",
+ mr->name );
+ return qfalse;
}
}
@@ -554,6 +615,19 @@ static qboolean G_ParseMapRotationFile( const char *fileName )
/*
===============
+G_PrintSpaces
+===============
+*/
+static void G_PrintSpaces( int spaces )
+{
+ int i;
+
+ for( i = 0; i < spaces; i++ )
+ G_Printf( " " );
+}
+
+/*
+===============
G_PrintRotations
Print the parsed map rotations
@@ -561,55 +635,167 @@ Print the parsed map rotations
*/
void G_PrintRotations( void )
{
- int i, j, k;
+ int i, j;
+ int size = sizeof( mapRotations );
G_Printf( "Map rotations as parsed:\n\n" );
for( i = 0; i < mapRotations.numRotations; i++ )
{
- G_Printf( "rotation: %s\n{\n", mapRotations.rotations[ i ].name );
+ mapRotation_t *mr = &mapRotations.rotations[ i ];
- for( j = 0; j < mapRotations.rotations[ i ].numMaps; j++ )
+ G_Printf( "rotation: %s\n{\n", mr->name );
+
+ size += mr->numNodes * sizeof( node_t );
+
+ for( j = 0; j < mr->numNodes; j++ )
{
- G_Printf( " map: %s\n {\n", mapRotations.rotations[ i ].maps[ j ].name );
+ node_t *node = mr->nodes[ j ];
+ int indentation = 0;
- for( k = 0; k < mapRotations.rotations[ i ].maps[ j ].numCmds; k++ )
+ while( node->type == NT_CONDITION )
{
- G_Printf( " command: %s\n",
- mapRotations.rotations[ i ].maps[ j ].postCmds[ k ] );
+ G_PrintSpaces( indentation );
+ G_Printf( " condition\n" );
+ node = node->u.condition.target;
+
+ size += sizeof( node_t );
+
+ indentation += 2;
}
- G_Printf( " }\n" );
+ G_PrintSpaces( indentation );
- for( k = 0; k < mapRotations.rotations[ i ].maps[ j ].numConditions; k++ )
+ switch( node->type )
{
- G_Printf( " conditional: %s\n",
- mapRotations.rotations[ i ].maps[ j ].conditions[ k ].dest );
- }
+ case NT_MAP:
+ G_Printf( " %s\n", node->u.map.name );
+ if( strlen( node->u.map.postCommand ) > 0 )
+ G_Printf( " command: %s", node->u.map.postCommand );
+
+ break;
+
+ case NT_RETURN:
+ G_Printf( " return\n" );
+ break;
+
+ case NT_LABEL:
+ G_Printf( " label: %s\n", node->u.label.name );
+ break;
+
+ case NT_GOTO:
+ G_Printf( " goto: %s\n", node->u.label.name );
+ break;
+
+ case NT_RESUME:
+ G_Printf( " resume: %s\n", node->u.label.name );
+ break;
+
+ default:
+ break;
+ }
}
G_Printf( "}\n" );
}
- G_Printf( "Total memory used: %d bytes\n", sizeof( mapRotations ) );
+ G_Printf( "Total memory used: %d bytes\n", size );
+}
+
+/*
+===============
+G_ClearRotationStack
+
+Clear the rotation stack
+===============
+*/
+void G_ClearRotationStack( void )
+{
+ trap_Cvar_Set( "g_mapRotationStack", "" );
+ trap_Cvar_Update( &g_mapRotationStack );
+}
+
+/*
+===============
+G_PushRotationStack
+
+Push the rotation stack
+===============
+*/
+static void G_PushRotationStack( int rotation )
+{
+ char text[ MAX_CVAR_VALUE_STRING ];
+
+ Com_sprintf( text, sizeof( text ), "%d %s",
+ rotation, g_mapRotationStack.string );
+ trap_Cvar_Set( "g_mapRotationStack", text );
+ trap_Cvar_Update( &g_mapRotationStack );
+}
+
+/*
+===============
+G_PopRotationStack
+
+Pop the rotation stack
+===============
+*/
+static int G_PopRotationStack( void )
+{
+ int value = -1;
+ char text[ MAX_CVAR_VALUE_STRING ];
+ char *text_p, *token;
+
+ Q_strncpyz( text, g_mapRotationStack.string, sizeof( text ) );
+
+ text_p = text;
+ token = COM_Parse( &text_p );
+
+ if( *token )
+ value = atoi( token );
+
+ if( text_p )
+ {
+ while ( *text_p == ' ' )
+ text_p++;
+ trap_Cvar_Set( "g_mapRotationStack", text_p );
+ trap_Cvar_Update( &g_mapRotationStack );
+ }
+ else
+ G_ClearRotationStack( );
+
+ return value;
}
/*
===============
-G_GetCurrentMapArray
+G_RotationNameByIndex
-Fill a static array with the current map of each rotation
+Returns the name of a rotation by its index
===============
*/
-static int *G_GetCurrentMapArray( void )
+static char *G_RotationNameByIndex( int index )
{
- static int currentMap[ MAX_MAP_ROTATIONS ];
+ if( index >= 0 && index < mapRotations.numRotations )
+ return mapRotations.rotations[ index ].name;
+ return NULL;
+}
+
+/*
+===============
+G_CurrentNodeIndexArray
+
+Fill a static array with the current node of each rotation
+===============
+*/
+static int *G_CurrentNodeIndexArray( void )
+{
+ static int currentNode[ MAX_MAP_ROTATIONS ];
int i = 0;
char text[ MAX_MAP_ROTATIONS * 2 ];
char *text_p, *token;
- Q_strncpyz( text, g_currentMap.string, sizeof( text ) );
+ Q_strncpyz( text, g_mapRotationNodes.string, sizeof( text ) );
text_p = text;
@@ -617,166 +803,138 @@ static int *G_GetCurrentMapArray( void )
{
token = COM_Parse( &text_p );
- if( !token )
- break;
-
- if( !Q_stricmp( token, "" ) )
+ if( !*token )
break;
- currentMap[ i++ ] = atoi( token );
+ currentNode[ i++ ] = atoi( token );
}
- return currentMap;
+ return currentNode;
}
/*
===============
-G_SetCurrentMap
+G_SetCurrentNodeByIndex
Set the current map in some rotation
===============
*/
-static void G_SetCurrentMap( int currentMap, int rotation )
+static void G_SetCurrentNodeByIndex( int currentNode, int rotation )
{
- char text[ MAX_MAP_ROTATIONS * 2 ] = { 0 };
- int *p = G_GetCurrentMapArray( );
+ char text[ MAX_MAP_ROTATIONS * 4 ] = { 0 };
+ int *p = G_CurrentNodeIndexArray( );
int i;
- p[ rotation ] = currentMap;
+ p[ rotation ] = currentNode;
for( i = 0; i < mapRotations.numRotations; i++ )
Q_strcat( text, sizeof( text ), va( "%d ", p[ i ] ) );
- trap_Cvar_Set( "g_currentMap", text );
- trap_Cvar_Update( &g_currentMap );
+ trap_Cvar_Set( "g_mapRotationNodes", text );
+ trap_Cvar_Update( &g_mapRotationNodes );
}
/*
===============
-G_GetCurrentMap
+G_CurrentNodeIndex
-Return the current map in some rotation
+Return the current node index in some rotation
===============
*/
-int G_GetCurrentMap( int rotation )
+static int G_CurrentNodeIndex( int rotation )
{
- int *p = G_GetCurrentMapArray( );
+ int *p = G_CurrentNodeIndexArray( );
return p[ rotation ];
}
-static qboolean G_GetRandomMap( char *name, int size, int rotation, int map );
-
/*
===============
-G_IssueMapChange
+G_NodeByIndex
-Send commands to the server to actually change the map
+Return a node in a rotation by its index
===============
*/
-static void G_IssueMapChange( int rotation )
+static node_t *G_NodeByIndex( int index, int rotation )
{
- int i;
- int map = G_GetCurrentMap( rotation );
- char cmd[ MAX_TOKEN_CHARS ];
- char newmap[ MAX_CVAR_VALUE_STRING ];
- char currentmap[ MAX_CVAR_VALUE_STRING ];
-
- Q_strncpyz( newmap, mapRotations.rotations[rotation].maps[map].name, sizeof( newmap ));
- trap_Cvar_VariableStringBuffer( "mapname", currentmap, sizeof( currentmap ));
+ if( rotation >= 0 && rotation < mapRotations.numRotations &&
+ index >= 0 && index < mapRotations.rotations[ rotation ].numNodes )
+ return mapRotations.rotations[ rotation ].nodes[ index ];
- if (!Q_stricmp( newmap, "*VOTE*") )
- {
- fileHandle_t f;
+ return NULL;
+}
- G_GetVotedMap( newmap, sizeof( newmap ), rotation, map );
- if( trap_FS_FOpenFile( va("maps/%s.bsp", newmap), &f, FS_READ ) > 0 )
- {
- trap_FS_FCloseFile( f );
- }
- else
- {
- G_AdvanceMapRotation();
- return;
- }
- }
- else if(!Q_stricmp( newmap, "*RANDOM*") )
- {
- fileHandle_t f;
+/*
+===============
+G_IssueMapChange
- G_GetRandomMap( newmap, sizeof( newmap ), rotation, map );
- if( trap_FS_FOpenFile( va("maps/%s.bsp", newmap), &f, FS_READ ) > 0 )
- {
- trap_FS_FCloseFile( f );
- }
- else
- {
- G_AdvanceMapRotation();
- return;
- }
- }
+Send commands to the server to actually change the map
+===============
+*/
+static void G_IssueMapChange( int index, int rotation )
+{
+ node_t *node = mapRotations.rotations[ rotation ].nodes[ index ];
+ map_t *map = &node->u.map;
- // allow a manually defined g_layouts setting to override the maprotation
- if( !g_layouts.string[ 0 ] &&
- mapRotations.rotations[ rotation ].maps[ map ].layouts[ 0 ] )
+ // allow a manually defined g_nextLayout setting to override the maprotation
+ if( !g_nextLayout.string[ 0 ] && map->layouts[ 0 ] )
{
- trap_Cvar_Set( "g_layouts",
- mapRotations.rotations[ rotation ].maps[ map ].layouts );
+ trap_Cvar_Set( "g_nextLayout", map->layouts );
}
- if( !Q_stricmp( currentmap, newmap ) )
- {
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart\n" );
- }
- else
- {
- trap_SendConsoleCommand( EXEC_APPEND, va( "map %s\n", newmap ) );
- }
+ G_MapConfigs( map->name );
- // load up map defaults if g_mapConfigs is set
- G_MapConfigs( newmap );
+ trap_SendConsoleCommand( EXEC_APPEND, va( "map \"%s\"\n", map->name ) );
- for( i = 0; i < mapRotations.rotations[ rotation ].maps[ map ].numCmds; i++ )
- {
- Q_strncpyz( cmd, mapRotations.rotations[ rotation ].maps[ map ].postCmds[ i ],
- sizeof( cmd ) );
- Q_strcat( cmd, sizeof( cmd ), "\n" );
- trap_SendConsoleCommand( EXEC_APPEND, cmd );
- }
+ if( strlen( map->postCommand ) > 0 )
+ trap_SendConsoleCommand( EXEC_APPEND, map->postCommand );
}
/*
===============
-G_ResolveConditionDestination
+G_GotoLabel
-Resolve the destination of some condition
+Resolve the label of some condition
===============
*/
-static mapConditionType_t G_ResolveConditionDestination( int *n, char *name )
+static qboolean G_GotoLabel( int rotation, int nodeIndex, char *name,
+ qboolean reset_index, int depth )
{
- int i;
+ node_t *node;
+ int i;
+
+ // Search the rotation names...
+ if( G_StartMapRotation( name, qtrue, qtrue, reset_index, depth ) )
+ return qtrue;
- //search the current rotation first...
- for( i = 0; i < mapRotations.rotations[ g_currentMapRotation.integer ].numMaps; i++ )
+ // ...then try labels in the rotation
+ for( i = 0; i < mapRotations.rotations[ rotation ].numNodes; i++ )
{
- if( !Q_stricmp( mapRotations.rotations[ g_currentMapRotation.integer ].maps[ i ].name, name ) )
+ node = mapRotations.rotations[ rotation ].nodes[ i ];
+
+ if( node->type == NT_LABEL && !Q_stricmp( node->u.label.name, name ) )
{
- *n = i;
- return MCT_MAP;
+ G_SetCurrentNodeByIndex( G_NodeIndexAfter( i, rotation ), rotation );
+ G_AdvanceMapRotation( depth );
+ return qtrue;
}
}
- //...then search the rotation names
- for( i = 0; i < mapRotations.numRotations; i++ )
+ // finally check for a map by name
+ for( i = 0; i < mapRotations.rotations[ rotation ].numNodes; i++ )
{
- if( !Q_stricmp( mapRotations.rotations[ i ].name, name ) )
+ nodeIndex = G_NodeIndexAfter( nodeIndex, rotation );
+ node = mapRotations.rotations[ rotation ].nodes[ nodeIndex ];
+
+ if( node->type == NT_MAP && !Q_stricmp( node->u.map.name, name ) )
{
- *n = i;
- return MCT_ROTATION;
+ G_SetCurrentNodeByIndex( nodeIndex, rotation );
+ G_AdvanceMapRotation( depth );
+ return qtrue;
}
}
- return MCT_ERR;
+ return qfalse;
}
/*
@@ -786,133 +944,231 @@ G_EvaluateMapCondition
Evaluate a map condition
===============
*/
-static qboolean G_EvaluateMapCondition( mapRotationCondition_t *mrc )
+static qboolean G_EvaluateMapCondition( condition_t **condition )
{
- switch( mrc->lhs )
+ qboolean result = qfalse;
+ condition_t *localCondition = *condition;
+
+ switch( localCondition->lhs )
{
- case MCV_RANDOM:
- return rand( ) & 1;
+ case CV_RANDOM:
+ result = rand( ) / ( RAND_MAX / 2 + 1 );
break;
- case MCV_NUMCLIENTS:
- switch( mrc->op )
+ case CV_NUMCLIENTS:
+ switch( localCondition->op )
{
- case MCO_LT:
- return level.numConnectedClients < mrc->numClients;
+ case CO_LT:
+ result = level.numConnectedClients < localCondition->numClients;
break;
- case MCO_GT:
- return level.numConnectedClients > mrc->numClients;
+ case CO_GT:
+ result = level.numConnectedClients > localCondition->numClients;
break;
- case MCO_EQ:
- return level.numConnectedClients == mrc->numClients;
+ case CO_EQ:
+ result = level.numConnectedClients == localCondition->numClients;
break;
}
break;
- case MCV_LASTWIN:
- return level.lastWin == mrc->lastWin;
- break;
-
- case MCV_VOTE:
- // ignore vote for conditions;
- break;
- case MCV_SELECTEDRANDOM:
- // ignore vote for conditions;
+ case CV_LASTWIN:
+ result = level.lastWin == localCondition->lastWin;
break;
default:
- case MCV_ERR:
- G_Printf( S_COLOR_RED "ERROR: malformed map switch condition\n" );
+ case CV_ERR:
+ G_Printf( S_COLOR_RED "ERROR: malformed map switch localCondition\n" );
break;
}
- return qfalse;
+ if( localCondition->target->type == NT_CONDITION )
+ {
+ *condition = &localCondition->target->u.condition;
+
+ return result && G_EvaluateMapCondition( condition );
+ }
+
+ return result;
}
/*
===============
-G_AdvanceMapRotation
-
-Increment the current map rotation
+G_NodeIndexAfter
===============
*/
-qboolean G_AdvanceMapRotation( void )
+static int G_NodeIndexAfter( int currentNode, int rotation )
{
- mapRotation_t *mr;
- mapRotationEntry_t *mre;
- mapRotationCondition_t *mrc;
- int currentRotation, currentMap, nextMap;
- int i, n;
- mapConditionType_t mct;
-
- if( ( currentRotation = g_currentMapRotation.integer ) == NOT_ROTATING )
- return qfalse;
+ mapRotation_t *mr = &mapRotations.rotations[ rotation ];
+
+ return ( currentNode + 1 ) % mr->numNodes;
+}
+
+/*
+===============
+G_StepMapRotation
- currentMap = G_GetCurrentMap( currentRotation );
+Run one node of a map rotation
+===============
+*/
+qboolean G_StepMapRotation( int rotation, int nodeIndex, int depth )
+{
+ node_t *node;
+ condition_t *condition;
+ int returnRotation;
+ qboolean step = qtrue;
- mr = &mapRotations.rotations[ currentRotation ];
- mre = &mr->maps[ currentMap ];
- nextMap = ( currentMap + 1 ) % mr->numMaps;
+ node = G_NodeByIndex( nodeIndex, rotation );
+ depth++;
- for( i = 0; i < mre->numConditions; i++ )
+ // guard against inifinite loop in conditional code
+ if( depth > 32 && node->type != NT_MAP )
{
- mrc = &mre->conditions[ i ];
+ if( depth > 64 )
+ {
+ G_Printf( S_COLOR_RED "ERROR: infinite loop protection stopped at map rotation %s\n",
+ G_RotationNameByIndex( rotation ) );
+ return qfalse;
+ }
- if( mrc->unconditional || G_EvaluateMapCondition( mrc ) )
+ G_Printf( S_COLOR_YELLOW "WARNING: possible infinite loop in map rotation %s\n",
+ G_RotationNameByIndex( rotation ) );
+ return qtrue;
+ }
+
+ while( step )
+ {
+ step = qfalse;
+ switch( node->type )
{
- mct = G_ResolveConditionDestination( &n, mrc->dest );
+ case NT_CONDITION:
+ condition = &node->u.condition;
- switch( mct )
- {
- case MCT_MAP:
- nextMap = n;
- break;
+ if( G_EvaluateMapCondition( &condition ) )
+ {
+ node = condition->target;
+ step = qtrue;
+ continue;
+ }
+ break;
- case MCT_ROTATION:
- //need to increment the current map before changing the rotation
- //or you get infinite loops with some conditionals
- G_SetCurrentMap( nextMap, currentRotation );
- G_StartMapRotation( mrc->dest, qtrue );
- return qtrue;
- break;
+ case NT_RETURN:
+ returnRotation = G_PopRotationStack( );
+ if( returnRotation >= 0 )
+ {
+ G_SetCurrentNodeByIndex(
+ G_NodeIndexAfter( nodeIndex, rotation ), rotation );
+ if( G_StartMapRotation( G_RotationNameByIndex( returnRotation ),
+ qtrue, qfalse, qfalse, depth ) )
+ {
+ return qfalse;
+ }
+ }
+ break;
- default:
- case MCT_ERR:
- G_Printf( S_COLOR_YELLOW "WARNING: map switch destination could not be resolved: %s\n",
- mrc->dest );
- break;
- }
+ case NT_MAP:
+ if( G_MapExists( node->u.map.name ) )
+ {
+ G_SetCurrentNodeByIndex(
+ G_NodeIndexAfter( nodeIndex, rotation ), rotation );
+ G_IssueMapChange( nodeIndex, rotation );
+ return qfalse;
+ }
+
+ G_Printf( S_COLOR_YELLOW "WARNING: skipped missing map %s in rotation %s\n",
+ node->u.map.name, G_RotationNameByIndex( rotation ) );
+ break;
+
+ case NT_LABEL:
+ break;
+
+ case NT_GOTO:
+ case NT_RESUME:
+ G_SetCurrentNodeByIndex(
+ G_NodeIndexAfter( nodeIndex, rotation ), rotation );
+ if ( G_GotoLabel( rotation, nodeIndex, node->u.label.name,
+ ( node->type == NT_GOTO ), depth ) )
+ return qfalse;
+
+ G_Printf( S_COLOR_YELLOW "WARNING: label, map, or rotation %s not found in %s\n",
+ node->u.label.name, G_RotationNameByIndex( rotation ) );
+ break;
}
}
- G_SetCurrentMap( nextMap, currentRotation );
- G_IssueMapChange( currentRotation );
-
return qtrue;
}
/*
===============
+G_AdvanceMapRotation
+
+Increment the current map rotation
+===============
+*/
+void G_AdvanceMapRotation( int depth )
+{
+ node_t *node;
+ int rotation;
+ int nodeIndex;
+
+ rotation = g_currentMapRotation.integer;
+ if( rotation < 0 || rotation >= MAX_MAP_ROTATIONS )
+ return;
+
+ nodeIndex = G_CurrentNodeIndex( rotation );
+ node = G_NodeByIndex( nodeIndex, rotation );
+ if( !node )
+ {
+ G_Printf( S_COLOR_YELLOW "WARNING: index incorrect for map rotation %s, trying 0\n",
+ G_RotationNameByIndex( rotation) );
+ nodeIndex = 0;
+ node = G_NodeByIndex( nodeIndex, rotation );
+ }
+
+ while( node && G_StepMapRotation( rotation, nodeIndex, depth ) )
+ {
+ nodeIndex = G_NodeIndexAfter( nodeIndex, rotation );
+ node = G_NodeByIndex( nodeIndex, rotation );
+ depth++;
+ }
+
+ if( !node )
+ G_Printf( S_COLOR_RED "ERROR: unexpected end of maprotation '%s'\n",
+ G_RotationNameByIndex( rotation) );
+}
+
+/*
+===============
G_StartMapRotation
Switch to a new map rotation
===============
*/
-qboolean G_StartMapRotation( char *name, qboolean changeMap )
+qboolean G_StartMapRotation( char *name, qboolean advance,
+ qboolean putOnStack, qboolean reset_index, int depth )
{
int i;
+ int currentRotation = g_currentMapRotation.integer;
for( i = 0; i < mapRotations.numRotations; i++ )
{
if( !Q_stricmp( mapRotations.rotations[ i ].name, name ) )
{
+ if( putOnStack && currentRotation >= 0 )
+ G_PushRotationStack( currentRotation );
+
trap_Cvar_Set( "g_currentMapRotation", va( "%d", i ) );
trap_Cvar_Update( &g_currentMapRotation );
- if( changeMap )
- G_IssueMapChange( i );
+ if( advance )
+ {
+ if( reset_index )
+ G_SetCurrentNodeByIndex( 0, i );
+
+ G_AdvanceMapRotation( depth );
+ }
+
break;
}
}
@@ -952,14 +1208,14 @@ qboolean G_MapRotationActive( void )
===============
G_InitMapRotations
-Load and intialise the map rotations
+Load and initialise the map rotations
===============
*/
void G_InitMapRotations( void )
{
- const char *fileName = "maprotation.cfg";
+ const char *fileName = "maprotation.cfg";
- //load the file if it exists
+ // Load the file if it exists
if( trap_FS_FOpenFile( fileName, NULL, FS_READ ) )
{
if( !G_ParseMapRotationFile( fileName ) )
@@ -972,7 +1228,7 @@ void G_InitMapRotations( void )
{
if( g_initialMapRotation.string[ 0 ] != 0 )
{
- G_StartMapRotation( g_initialMapRotation.string, qfalse );
+ G_StartMapRotation( g_initialMapRotation.string, qfalse, qtrue, qfalse, 0 );
trap_Cvar_Set( "g_initialMapRotation", "" );
trap_Cvar_Update( &g_initialMapRotation );
@@ -980,347 +1236,41 @@ void G_InitMapRotations( void )
}
}
-static char rotationVoteList[ MAX_MAP_ROTATION_CONDS ][ MAX_QPATH ];
-static int rotationVoteLen = 0;
-
-static int rotationVoteClientPosition[ MAX_CLIENTS ];
-static int rotationVoteClientSelection[ MAX_CLIENTS ];
-
/*
===============
-G_CheckMapRotationVote
+G_FreeNode
+
+Free up memory used by a node
===============
*/
-qboolean G_CheckMapRotationVote( void )
-{
- mapRotation_t *mr;
- mapRotationEntry_t *mre;
- mapRotationCondition_t *mrc;
- int currentRotation, currentMap, nextMap;
- int i;
-
- rotationVoteLen = 0;
-
- if( g_mapRotationVote.integer < 1 )
- return qfalse;
-
- if( ( currentRotation = g_currentMapRotation.integer ) == NOT_ROTATING )
- return qfalse;
-
- currentMap = G_GetCurrentMap( currentRotation );
-
- mr = &mapRotations.rotations[ currentRotation ];
- nextMap = ( currentMap + 1 ) % mr->numMaps;
- mre = &mr->maps[ nextMap ];
-
- for( i = 0; i < mre->numConditions; i++ )
- {
- mrc = &mre->conditions[ i ];
-
- if( mrc->lhs == MCV_VOTE )
- {
- Q_strncpyz( rotationVoteList[ rotationVoteLen ], mrc->dest,
- sizeof( rotationVoteList[ rotationVoteLen ] ) );
- rotationVoteLen++;
- if( rotationVoteLen >= MAX_MAP_ROTATION_CONDS )
- break;
- }
- }
-
- if( !rotationVoteLen )
- return qfalse;
-
- for( i = 0; i < MAX_CLIENTS; i++ )
- {
- rotationVoteClientPosition[ i ] = 0;
- rotationVoteClientSelection[ i ] = -1;
- }
-
- return qtrue;
-}
-
-typedef struct {
- int votes;
- int map;
-} MapVoteResultsSort_t;
-
-static int SortMapVoteResults( const void *av, const void *bv )
-{
- const MapVoteResultsSort_t *a = av;
- const MapVoteResultsSort_t *b = bv;
-
- if( a->votes > b->votes )
- return -1;
- if( a->votes < b->votes )
- return 1;
-
- if( a->map > b->map )
- return 1;
- if( a->map < b->map )
- return -1;
-
- return 0;
-}
-
-static int G_GetMapVoteWinner( int *winvotes, int *totalvotes, int *resultorder )
-{
- MapVoteResultsSort_t results[ MAX_MAP_ROTATION_CONDS ];
- int tv = 0;
- int i, n;
-
- for( i = 0; i < MAX_MAP_ROTATION_CONDS; i++ )
- {
- results[ i ].votes = 0;
- results[ i ].map = i;
- }
- for( i = 0; i < MAX_CLIENTS; i++ )
- {
- n = rotationVoteClientSelection[ i ];
- if( n >=0 && n < MAX_MAP_ROTATION_CONDS )
- {
- results[ n ].votes += 1;
- tv++;
- }
- }
-
- qsort ( results, MAX_MAP_ROTATION_CONDS, sizeof( results[ 0 ] ), SortMapVoteResults );
-
- if( winvotes != NULL )
- *winvotes = results[ 0 ].votes;
- if( totalvotes != NULL )
- *totalvotes = tv;
-
- if( resultorder != NULL )
- {
- for( i = 0; i < MAX_MAP_ROTATION_CONDS; i++ )
- resultorder[ results[ i ].map ] = i;
- }
-
- return results[ 0 ].map;
-}
-
-qboolean G_IntermissionMapVoteWinner( void )
+void G_FreeNode( node_t *node )
{
- int winner, winvotes, totalvotes;
- int nonvotes;
+ if( node->type == NT_CONDITION )
+ G_FreeNode( node->u.condition.target );
- winner = G_GetMapVoteWinner( &winvotes, &totalvotes, NULL );
- if( winvotes * 2 > level.numConnectedClients )
- return qtrue;
- nonvotes = level.numConnectedClients - totalvotes;
- if( nonvotes < 0 )
- nonvotes = 0;
- if( winvotes > nonvotes + ( totalvotes - winvotes ) )
- return qtrue;
-
- return qfalse;
+ BG_Free( node );
}
-static qboolean G_GetVotedMap( char *name, int size, int rotation, int map )
-{
- mapRotation_t *mr;
- mapRotationEntry_t *mre;
- mapRotationCondition_t *mrc;
- int i, n;
- int winner;
- qboolean found = qfalse;
-
- if( !rotationVoteLen )
- return qfalse;
-
- winner = G_GetMapVoteWinner( NULL, NULL, NULL );
-
- mr = &mapRotations.rotations[ rotation ];
- mre = &mr->maps[ map ];
-
- n = 0;
- for( i = 0; i < mre->numConditions && n < rotationVoteLen; i++ )
- {
- mrc = &mre->conditions[ i ];
-
- if( mrc->lhs == MCV_VOTE )
- {
- if( n == winner )
- {
- Q_strncpyz( name, mrc->dest, size );
- found = qtrue;
- break;
- }
- n++;
- }
- }
-
- rotationVoteLen = 0;
-
- return found;
-}
+/*
+===============
+G_ShutdownMapRotations
-static void G_IntermissionMapVoteMessageReal( gentity_t *ent, int winner, int winvotes, int totalvotes, int *ranklist )
+Free up memory used by map rotations
+===============
+*/
+void G_ShutdownMapRotations( void )
{
- int clientNum;
- char string[ MAX_STRING_CHARS ];
- char entry[ MAX_STRING_CHARS ];
- int ourlist[ MAX_MAP_ROTATION_CONDS ];
- int len = 0;
- int index, selection;
- int i;
- char *color;
- char *rank;
-
- clientNum = ent-g_entities;
-
- index = rotationVoteClientSelection[ clientNum ];
- selection = rotationVoteClientPosition[ clientNum ];
-
- if( winner < 0 || winner >= MAX_MAP_ROTATION_CONDS || ranklist == NULL )
- {
- ranklist = &ourlist[0];
- winner = G_GetMapVoteWinner( &winvotes, &totalvotes, ranklist );
- }
+ int i, j;
- Q_strncpyz( string, "^7Attack = down ^0/^7 Repair = up ^0/^7 F1 = vote\n\n"
- "^2Map Vote Menu\n"
- "^7+------------------+\n", sizeof( string ) );
- for( i = 0; i < rotationVoteLen; i++ )
+ for( i = 0; i < mapRotations.numRotations; i++ )
{
- if( !G_MapExists( rotationVoteList[ i ] ) )
- continue;
-
- if( i == selection )
- color = "^5";
- else if( i == index )
- color = "^1";
- else
- color = "^7";
+ mapRotation_t *mr = &mapRotations.rotations[ i ];
- switch( ranklist[ i ] )
+ for( j = 0; j < mr->numNodes; j++ )
{
- case 0:
- rank = "^7---";
- break;
- case 1:
- rank = "^7--";
- break;
- case 2:
- rank = "^7-";
- break;
- default:
- rank = "";
- break;
- }
-
- Com_sprintf( entry, sizeof( entry ), "^7%s%s%s%s %s %s%s^7%s\n",
- ( i == index ) ? "^1>>>" : "",
- ( i == selection ) ? "^7(" : " ",
- rank,
- color,
- rotationVoteList[ i ],
- rank,
- ( i == selection ) ? "^7)" : " ",
- ( i == index ) ? "^1<<<" : "" );
-
- Q_strcat( string, sizeof( string ), entry );
- len += strlen( entry );
- }
-
- Com_sprintf( entry, sizeof( entry ),
- "\n^7+----------------+\nleader: ^3%s^7 with %d vote%s\nvoters: %d\ntime left: %d",
- rotationVoteList[ winner ],
- winvotes,
- ( winvotes == 1 ) ? "" : "s",
- totalvotes,
- ( level.mapRotationVoteTime - level.time ) / 1000 );
- Q_strcat( string, sizeof( string ), entry );
+ node_t *node = mr->nodes[ j ];
- trap_SendServerCommand( ent-g_entities, va( "cp \"%s\"\n", string ) );
-}
-
-void G_IntermissionMapVoteMessageAll( void )
-{
- int ranklist[ MAX_MAP_ROTATION_CONDS ];
- int winner;
- int winvotes, totalvotes;
- int i;
-
- winner = G_GetMapVoteWinner( &winvotes, &totalvotes, &ranklist[ 0 ] );
- for( i = 0; i < level.maxclients; i++ )
- {
- if( level.clients[ i ].pers.connected == CON_CONNECTED )
- G_IntermissionMapVoteMessageReal( g_entities + i, winner, winvotes, totalvotes, ranklist );
- }
-}
-
-void G_IntermissionMapVoteMessage( gentity_t *ent )
-{
- G_IntermissionMapVoteMessageReal( ent, -1, 0, 0, NULL );
-}
-
-void G_IntermissionMapVoteCommand( gentity_t *ent, qboolean next, qboolean choose )
-{
- int clientNum;
- int n;
-
- clientNum = ent-g_entities;
-
- if( choose )
- {
- rotationVoteClientSelection[ clientNum ] = rotationVoteClientPosition[ clientNum ];
- }
- else
- {
- n = rotationVoteClientPosition[ clientNum ];
- if( next )
- n++;
- else
- n--;
-
- if( n >= rotationVoteLen )
- n = rotationVoteLen - 1;
- if( n < 0 )
- n = 0;
-
- rotationVoteClientPosition[ clientNum ] = n;
- }
-
- G_IntermissionMapVoteMessage( ent );
-}
-
-static qboolean G_GetRandomMap( char *name, int size, int rotation, int map )
-{
- mapRotation_t *mr;
- mapRotationEntry_t *mre;
- mapRotationCondition_t *mrc;
- int i, nummaps;
- int randompick = 0;
- int maplist[ 32 ];
-
- mr = &mapRotations.rotations[ rotation ];
- mre = &mr->maps[ map ];
-
- nummaps = 0;
- //count the number of map votes
- for( i = 0; i < mre->numConditions; i++ )
- {
- mrc = &mre->conditions[ i ];
-
- if( mrc->lhs == MCV_SELECTEDRANDOM )
- {
- //map doesnt exist
- if( !G_MapExists( mrc->dest ) ) {
- continue;
- }
- maplist[ nummaps ] = i;
- nummaps++;
+ G_FreeNode( node );
}
}
-
- if( nummaps == 0 ) {
- return qfalse;
- }
-
- randompick = (int)( random() * nummaps );
-
- Q_strncpyz( name, mre->conditions[ maplist[ randompick ] ].dest, size );
-
- return qtrue;
}
diff --git a/src/game/g_misc.c b/src/game/g_misc.c
index a68eeb8..66066ba 100644
--- a/src/game/g_misc.c
+++ b/src/game/g_misc.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -44,7 +45,7 @@ target_position does the same thing
*/
void SP_info_notnull( gentity_t *self )
{
- G_SetOrigin( self, self->s.origin );
+ G_SetOrigin( self, self->r.currentOrigin );
}
@@ -70,39 +71,47 @@ TELEPORTERS
=================================================================================
*/
-void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles )
+void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles, float speed )
{
// unlink to make sure it can't possibly interfere with G_KillBox
trap_UnlinkEntity( player );
VectorCopy( origin, player->client->ps.origin );
- player->client->ps.origin[ 2 ] += 1;
+ player->client->ps.groundEntityNum = ENTITYNUM_NONE;
+ player->client->ps.stats[ STAT_STATE ] &= ~SS_GRABBED;
- // spit the player out
AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
- VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
- player->client->ps.pm_time = 160; // hold time
- player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
+ VectorScale( player->client->ps.velocity, speed, player->client->ps.velocity );
+ player->client->ps.pm_time = 0.4f * fabs( speed ); // duration of loss of control
+ if( player->client->ps.pm_time > 160 )
+ player->client->ps.pm_time = 160;
+ if( player->client->ps.pm_time != 0 )
+ player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
// toggle the teleport bit so the client knows to not lerp
player->client->ps.eFlags ^= EF_TELEPORT_BIT;
G_UnlaggedClear( player );
+ // cut all relevant zap beams
+ G_ClearPlayerZapEffects( player );
+
// set angles
G_SetClientViewAngle( player, angles );
- // kill anything at the destination
- if( player->client->sess.sessionTeam != TEAM_SPECTATOR )
- G_KillBox( player );
-
// save results of pmove
BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
// use the precise origin for linking
VectorCopy( player->client->ps.origin, player->r.currentOrigin );
+ VectorCopy( player->client->ps.viewangles, player->r.currentAngles );
+
+ if( player->client->sess.spectatorState == SPECTATOR_NOT )
+ {
+ // kill anything at the destination
+ G_KillBox( player );
- if( player->client->sess.sessionTeam != TEAM_SPECTATOR )
trap_LinkEntity (player);
+ }
}
@@ -129,8 +138,7 @@ void SP_misc_model( gentity_t *ent )
VectorSet (ent->maxs, 16, 16, 16);
trap_LinkEntity (ent);
- G_SetOrigin( ent, ent->s.origin );
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
+ G_SetOrigin( ent, ent->r.currentOrigin );
#else
G_FreeEntity( ent );
#endif
@@ -171,19 +179,23 @@ void locateCamera( gentity_t *ent )
// clientNum holds the rotate offset
ent->s.clientNum = owner->s.clientNum;
- VectorCopy( owner->s.origin, ent->s.origin2 );
+ VectorCopy( owner->r.currentOrigin, ent->s.origin2 );
// see if the portal_camera has a target
target = G_PickTarget( owner->target );
if( target )
{
- VectorSubtract( target->s.origin, owner->s.origin, dir );
+ VectorSubtract( target->r.currentOrigin, owner->r.currentOrigin, dir );
VectorNormalize( dir );
}
else
- G_SetMovedir( owner->s.angles, dir );
+ G_SetMovedir( owner->r.currentAngles, dir );
ent->s.eventParm = DirToByte( dir );
+
+ ByteToDir( ent->s.eventParm, dir );
+ vectoangles( dir, ent->r.currentAngles );
+ ent->r.currentAngles[ 2 ] = ent->s.clientNum * 360.0f / 256;
}
/*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
@@ -201,7 +213,7 @@ void SP_misc_portal_surface( gentity_t *ent )
if( !ent->target )
{
- VectorCopy( ent->s.origin, ent->s.origin2 );
+ VectorCopy( ent->r.currentOrigin, ent->s.origin2 );
}
else
{
@@ -273,7 +285,7 @@ void SP_misc_particle_system( gentity_t *self )
{
char *s;
- G_SetOrigin( self, self->s.origin );
+ G_SetOrigin( self, self->r.currentOrigin );
G_SpawnString( "psName", "", &s );
G_SpawnFloat( "wait", "0", &self->wait );
@@ -420,7 +432,7 @@ void SP_misc_light_flare( gentity_t *self )
//try to find a spot near to the flare which is empty. This
//is used to facilitate visibility testing
- findEmptySpot( self->s.origin, 8.0f, self->s.angles2 );
+ findEmptySpot( self->r.currentOrigin, 8.0f, self->s.angles2 );
self->use = SP_use_light_flare;
diff --git a/src/game/g_missile.c b/src/game/g_missile.c
index 26cb97e..14494cd 100644
--- a/src/game/g_missile.c
+++ b/src/game/g_missile.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -82,7 +83,6 @@ void G_ExplodeMissile( gentity_t *ent )
ent->s.eType = ET_GENERAL;
- //TA: tired... can't be fucked... hack
if( ent->s.weapon != WP_LOCKBLOB_LAUNCHER &&
ent->s.weapon != WP_FLAMER )
G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
@@ -92,7 +92,7 @@ void G_ExplodeMissile( gentity_t *ent )
// splash damage
if( ent->splashDamage )
G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage,
- ent->splashRadius, ent, ent->dflags, ent->splashMethodOfDeath );
+ ent->splashRadius, ent, ent->splashMethodOfDeath );
trap_LinkEntity( ent );
}
@@ -140,7 +140,7 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace )
}
else if( !strcmp( ent->classname, "lockblob" ) )
{
- if( other->client && other->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
other->client->ps.stats[ STAT_STATE ] |= SS_BLOBLOCKED;
other->client->lastLockTime = level.time;
@@ -150,7 +150,7 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace )
}
else if( !strcmp( ent->classname, "slowblob" ) )
{
- if( other->client && other->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
other->client->ps.stats[ STAT_STATE ] |= SS_SLOWLOCKED;
other->client->lastSlowTime = level.time;
@@ -175,11 +175,11 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace )
//prevent collision with the client when returning
ent->r.ownerNum = other->s.number;
- ent->think = AHive_ReturnToHive;
+ ent->think = G_ExplodeMissile;
ent->nextthink = level.time + FRAMETIME;
//only damage humans
- if( other->client && other->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
returnAfterDamage = qtrue;
else
return;
@@ -198,8 +198,8 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace )
if( VectorLength( velocity ) == 0 )
velocity[ 2 ] = 1; // stepped on a grenade
- G_Damage( other, ent, attacker, velocity, ent->s.origin, ent->damage,
- ent->dflags, ent->methodOfDeath );
+ G_Damage( other, ent, attacker, velocity, ent->r.currentOrigin, ent->damage,
+ DAMAGE_NO_LOCDAMAGE, ent->methodOfDeath );
}
}
@@ -209,7 +209,8 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace )
// is it cheaper in bandwidth to just remove this ent and create a new
// one, rather than changing the missile into the explosion?
- if( other->takedamage && other->client )
+ if( other->takedamage &&
+ ( other->s.eType == ET_PLAYER || other->s.eType == ET_BUILDABLE ) )
{
G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
ent->s.otherEntityNum = other->s.number;
@@ -231,7 +232,7 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace )
// splash damage (doesn't apply to person directly hit)
if( ent->splashDamage )
G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
- other, ent->dflags, ent->splashMethodOfDeath );
+ other, ent->splashMethodOfDeath );
trap_LinkEntity( ent );
}
@@ -247,7 +248,8 @@ void G_RunMissile( gentity_t *ent )
{
vec3_t origin;
trace_t tr;
- int passent;
+ int passent;
+ qboolean impact = qfalse;
// get current position
BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
@@ -255,40 +257,73 @@ void G_RunMissile( gentity_t *ent )
// ignore interactions with the missile owner
passent = ent->r.ownerNum;
- // trace a line from the previous position to the current position
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
+ // general trace to see if we hit anything at all
+ trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs,
+ origin, passent, ent->clipmask );
if( tr.startsolid || tr.allsolid )
{
- // make sure the tr.entityNum is set to the entity we're stuck in
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
- tr.fraction = 0;
+ tr.fraction = 0.0f;
+ VectorCopy( ent->r.currentOrigin, tr.endpos );
}
- else
- VectorCopy( tr.endpos, ent->r.currentOrigin );
- ent->r.contents = CONTENTS_SOLID; //trick trap_LinkEntity into...
- trap_LinkEntity( ent );
- ent->r.contents = 0; //...encoding bbox information
+ if( tr.fraction < 1.0f )
+ {
+ if( !ent->pointAgainstWorld || tr.contents & CONTENTS_BODY )
+ {
+ // We hit an entity or we don't care
+ impact = qtrue;
+ }
+ else
+ {
+ trap_Trace( &tr, ent->r.currentOrigin, NULL, NULL, origin,
+ passent, ent->clipmask );
+
+ if( tr.fraction < 1.0f )
+ {
+ // Hit the world with point trace
+ impact = qtrue;
+ }
+ else
+ {
+ if( tr.contents & CONTENTS_BODY )
+ {
+ // Hit an entity
+ impact = qtrue;
+ }
+ else
+ {
+ trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs,
+ origin, passent, CONTENTS_BODY );
+
+ if( tr.fraction < 1.0f )
+ impact = qtrue;
+ }
+ }
+ }
+ }
- if( tr.fraction != 1 )
+ VectorCopy( tr.endpos, ent->r.currentOrigin );
+
+ if( impact )
{
- // never explode or bounce on sky
if( tr.surfaceFlags & SURF_NOIMPACT )
{
- // If grapple, reset owner
- if( ent->parent && ent->parent->client && ent->parent->client->hook == ent )
- ent->parent->client->hook = NULL;
-
+ // Never explode or bounce on sky
G_FreeEntity( ent );
return;
}
G_MissileImpact( ent, &tr );
+
if( ent->s.eType != ET_MISSILE )
return; // exploded
}
+ ent->r.contents = CONTENTS_SOLID; //trick trap_LinkEntity into...
+ trap_LinkEntity( ent );
+ ent->r.contents = 0; //...encoding bbox information
+
// check think function after bouncing
G_RunThink( ent );
}
@@ -311,23 +346,23 @@ gentity_t *fire_flamer( gentity_t *self, vec3_t start, vec3_t dir )
bolt = G_Spawn();
bolt->classname = "flame";
+ bolt->pointAgainstWorld = qfalse;
bolt->nextthink = level.time + FLAMER_LIFETIME;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_FLAMER;
bolt->s.generic1 = self->s.generic1; //weaponMode
bolt->r.ownerNum = self->s.number;
bolt->parent = self;
bolt->damage = FLAMER_DMG;
- bolt->splashDamage = FLAMER_DMG;
+ bolt->splashDamage = FLAMER_SPLASHDAMAGE;
bolt->splashRadius = FLAMER_RADIUS;
bolt->methodOfDeath = MOD_FLAMER;
bolt->splashMethodOfDeath = MOD_FLAMER_SPLASH;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
- bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -15.0f;
- bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = 15.0f;
+ bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -FLAMER_SIZE;
+ bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = FLAMER_SIZE;
bolt->s.pos.trType = TR_LINEAR;
bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
@@ -357,10 +392,10 @@ gentity_t *fire_blaster( gentity_t *self, vec3_t start, vec3_t dir )
bolt = G_Spawn();
bolt->classname = "blaster";
+ bolt->pointAgainstWorld = qtrue;
bolt->nextthink = level.time + 10000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_BLASTER;
bolt->s.generic1 = self->s.generic1; //weaponMode
bolt->r.ownerNum = self->s.number;
@@ -372,6 +407,8 @@ gentity_t *fire_blaster( gentity_t *self, vec3_t start, vec3_t dir )
bolt->splashMethodOfDeath = MOD_BLASTER;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
+ bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -BLASTER_SIZE;
+ bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = BLASTER_SIZE;
bolt->s.pos.trType = TR_LINEAR;
bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
@@ -400,10 +437,10 @@ gentity_t *fire_pulseRifle( gentity_t *self, vec3_t start, vec3_t dir )
bolt = G_Spawn();
bolt->classname = "pulse";
+ bolt->pointAgainstWorld = qtrue;
bolt->nextthink = level.time + 10000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_PULSE_RIFLE;
bolt->s.generic1 = self->s.generic1; //weaponMode
bolt->r.ownerNum = self->s.number;
@@ -415,6 +452,8 @@ gentity_t *fire_pulseRifle( gentity_t *self, vec3_t start, vec3_t dir )
bolt->splashMethodOfDeath = MOD_PRIFLE;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
+ bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -PRIFLE_SIZE;
+ bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = PRIFLE_SIZE;
bolt->s.pos.trType = TR_LINEAR;
bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
@@ -435,42 +474,53 @@ fire_luciferCannon
=================
*/
-gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir, int damage, int radius )
+gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir,
+ int damage, int radius, int speed )
{
gentity_t *bolt;
- int localDamage = (int)( ceil( ( (float)damage /
- (float)LCANNON_TOTAL_CHARGE ) * (float)LCANNON_DAMAGE ) );
+ float charge;
VectorNormalize( dir );
bolt = G_Spawn( );
bolt->classname = "lcannon";
+ bolt->pointAgainstWorld = qtrue;
- if( damage == LCANNON_TOTAL_CHARGE )
+ if( damage == LCANNON_DAMAGE )
bolt->nextthink = level.time;
else
bolt->nextthink = level.time + 10000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_LUCIFER_CANNON;
bolt->s.generic1 = self->s.generic1; //weaponMode
bolt->r.ownerNum = self->s.number;
bolt->parent = self;
- bolt->damage = localDamage;
- bolt->dflags = DAMAGE_KNOCKBACK;
- bolt->splashDamage = localDamage / 2;
+ bolt->damage = damage;
+ bolt->splashDamage = damage / 2;
bolt->splashRadius = radius;
bolt->methodOfDeath = MOD_LCANNON;
bolt->splashMethodOfDeath = MOD_LCANNON_SPLASH;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
+
+ // Give the missile a small bounding box
+ bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] =
+ -LCANNON_SIZE;
+ bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] =
+ -bolt->r.mins[ 0 ];
+
+ // Pass the missile charge through
+ charge = (float)( damage - LCANNON_SECONDARY_DAMAGE ) / LCANNON_DAMAGE;
+ bolt->s.torsoAnim = charge * 255;
+ if( bolt->s.torsoAnim < 0 )
+ bolt->s.torsoAnim = 0;
bolt->s.pos.trType = TR_LINEAR;
bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, LCANNON_SPEED, bolt->s.pos.trDelta );
+ VectorScale( dir, speed, bolt->s.pos.trDelta );
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
VectorCopy( start, bolt->r.currentOrigin );
@@ -492,17 +542,16 @@ gentity_t *launch_grenade( gentity_t *self, vec3_t start, vec3_t dir )
bolt = G_Spawn( );
bolt->classname = "grenade";
+ bolt->pointAgainstWorld = qfalse;
bolt->nextthink = level.time + 5000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_GRENADE;
bolt->s.eFlags = EF_BOUNCE_HALF;
bolt->s.generic1 = WPM_PRIMARY; //weaponMode
bolt->r.ownerNum = self->s.number;
bolt->parent = self;
bolt->damage = GRENADE_DAMAGE;
- bolt->dflags = DAMAGE_KNOCKBACK;
bolt->splashDamage = GRENADE_DAMAGE;
bolt->splashRadius = GRENADE_RANGE;
bolt->methodOfDeath = MOD_GRENADE;
@@ -525,85 +574,79 @@ gentity_t *launch_grenade( gentity_t *self, vec3_t start, vec3_t dir )
}
//=============================================================================
+
+
/*
================
-AHive_ReturnToHive
+AHive_SearchAndDestroy
-Adjust the trajectory to point towards the hive
+Adjust the trajectory to point towards the target
================
*/
-void AHive_ReturnToHive( gentity_t *self )
+void AHive_SearchAndDestroy( gentity_t *self )
{
- vec3_t dir;
- trace_t tr;
-
- if( !self->parent )
- {
- G_Printf( S_COLOR_YELLOW "WARNING: AHive_ReturnToHive called with no self->parent\n" );
- return;
- }
+ vec3_t dir;
+ trace_t tr;
+ gentity_t *ent;
+ int i;
+ float d, nearest;
- trap_UnlinkEntity( self->parent );
- trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
- self->parent->r.currentOrigin, self->r.ownerNum, self->clipmask );
- trap_LinkEntity( self->parent );
+ if( self->parent && !self->parent->inuse )
+ self->parent = NULL;
- if( tr.fraction < 1.0f )
+ if( level.time > self->timestamp )
{
- //if can't see hive then disperse
VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
self->s.pos.trType = TR_STATIONARY;
self->s.pos.trTime = level.time;
self->think = G_ExplodeMissile;
- self->nextthink = level.time + 2000;
- self->parent->active = qfalse; //allow the parent to start again
+ self->nextthink = level.time + 50;
+ if( self->parent )
+ self->parent->active = qfalse; //allow the parent to start again
+ return;
}
+
+ ent = self->target_ent;
+ if( ent && ent->health > 0 && ent->client && ent->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ nearest = DistanceSquared( self->r.currentOrigin, ent->r.currentOrigin );
else
{
- VectorSubtract( self->parent->r.currentOrigin, self->r.currentOrigin, dir );
- VectorNormalize( dir );
-
- //change direction towards the hive
- VectorScale( dir, HIVE_SPEED, self->s.pos.trDelta );
- SnapVector( self->s.pos.trDelta ); // save net bandwidth
- VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
- self->s.pos.trTime = level.time;
-
- self->think = G_ExplodeMissile;
- self->nextthink = level.time + 15000;
+ self->target_ent = NULL;
+ nearest = 0; // silence warning
}
-}
-
-/*
-================
-AHive_SearchAndDestroy
-Adjust the trajectory to point towards the target
-================
-*/
-void AHive_SearchAndDestroy( gentity_t *self )
-{
- vec3_t dir;
- trace_t tr;
-
- trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
- self->target_ent->r.currentOrigin, self->r.ownerNum, self->clipmask );
-
- //if there is no LOS or the parent hive is too far away or the target is dead or notargeting, return
- if( tr.entityNum == ENTITYNUM_WORLD ||
- Distance( self->r.currentOrigin, self->parent->r.currentOrigin ) > ( HIVE_RANGE * 5 ) ||
- self->target_ent->health <= 0 || self->target_ent->flags & FL_NOTARGET )
+ //find the closest human
+ for( i = 0; i < MAX_CLIENTS; i++ )
{
- self->r.ownerNum = ENTITYNUM_WORLD;
+ ent = &g_entities[ i ];
+
+ if( ent->flags & FL_NOTARGET )
+ continue;
- self->think = AHive_ReturnToHive;
- self->nextthink = level.time + FRAMETIME;
+ if( ent->client &&
+ ent->health > 0 &&
+ ent->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS &&
+ ( d = DistanceSquared( ent->r.currentOrigin, self->r.currentOrigin ),
+ ( self->target_ent == NULL || d < nearest ) ) )
+ {
+ trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
+ ent->r.currentOrigin, self->r.ownerNum, self->clipmask );
+ if( tr.entityNum != ENTITYNUM_WORLD )
+ {
+ nearest = d;
+ self->target_ent = ent;
+ }
+ }
}
+
+ if( self->target_ent == NULL )
+ VectorClear( dir );
else
{
VectorSubtract( self->target_ent->r.currentOrigin, self->r.currentOrigin, dir );
VectorNormalize( dir );
+ }
//change direction towards the player
VectorScale( dir, HIVE_SPEED, self->s.pos.trDelta );
@@ -612,7 +655,6 @@ void AHive_SearchAndDestroy( gentity_t *self )
self->s.pos.trTime = level.time;
self->nextthink = level.time + HIVE_DIR_CHANGE_PERIOD;
- }
}
/*
@@ -628,11 +670,11 @@ gentity_t *fire_hive( gentity_t *self, vec3_t start, vec3_t dir )
bolt = G_Spawn( );
bolt->classname = "hive";
+ bolt->pointAgainstWorld = qfalse;
bolt->nextthink = level.time + HIVE_DIR_CHANGE_PERIOD;
bolt->think = AHive_SearchAndDestroy;
bolt->s.eType = ET_MISSILE;
- bolt->s.eFlags |= EF_BOUNCE|EF_NO_BOUNCE_SOUND;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
+ bolt->s.eFlags |= EF_BOUNCE | EF_NO_BOUNCE_SOUND;
bolt->s.weapon = WP_HIVE;
bolt->s.generic1 = WPM_PRIMARY; //weaponMode
bolt->r.ownerNum = self->s.number;
@@ -643,6 +685,7 @@ gentity_t *fire_hive( gentity_t *self, vec3_t start, vec3_t dir )
bolt->methodOfDeath = MOD_SWARM;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = self->target_ent;
+ bolt->timestamp = level.time + HIVE_LIFETIME;
bolt->s.pos.trType = TR_LINEAR;
bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
@@ -669,10 +712,10 @@ gentity_t *fire_lockblob( gentity_t *self, vec3_t start, vec3_t dir )
bolt = G_Spawn( );
bolt->classname = "lockblob";
+ bolt->pointAgainstWorld = qtrue;
bolt->nextthink = level.time + 15000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_LOCKBLOB_LAUNCHER;
bolt->s.generic1 = WPM_PRIMARY; //weaponMode
bolt->r.ownerNum = self->s.number;
@@ -707,10 +750,10 @@ gentity_t *fire_slowBlob( gentity_t *self, vec3_t start, vec3_t dir )
bolt = G_Spawn( );
bolt->classname = "slowblob";
+ bolt->pointAgainstWorld = qtrue;
bolt->nextthink = level.time + 15000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_ABUILD2;
bolt->s.generic1 = self->s.generic1; //weaponMode
bolt->r.ownerNum = self->s.number;
@@ -746,10 +789,10 @@ gentity_t *fire_paraLockBlob( gentity_t *self, vec3_t start, vec3_t dir )
bolt = G_Spawn( );
bolt->classname = "lockblob";
+ bolt->pointAgainstWorld = qtrue;
bolt->nextthink = level.time + 15000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_LOCKBLOB_LAUNCHER;
bolt->s.generic1 = self->s.generic1; //weaponMode
bolt->r.ownerNum = self->s.number;
@@ -783,18 +826,17 @@ gentity_t *fire_bounceBall( gentity_t *self, vec3_t start, vec3_t dir )
bolt = G_Spawn( );
bolt->classname = "bounceball";
+ bolt->pointAgainstWorld = qtrue;
bolt->nextthink = level.time + 3000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_ALEVEL3_UPG;
bolt->s.generic1 = self->s.generic1; //weaponMode
bolt->r.ownerNum = self->s.number;
bolt->parent = self;
bolt->damage = LEVEL3_BOUNCEBALL_DMG;
- bolt->dflags = DAMAGE_KNOCKBACK;
- bolt->splashDamage = 0;
- bolt->splashRadius = 0;
+ bolt->splashDamage = LEVEL3_BOUNCEBALL_DMG;
+ bolt->splashRadius = LEVEL3_BOUNCEBALL_RADIUS;
bolt->methodOfDeath = MOD_LEVEL3_BOUNCEBALL;
bolt->splashMethodOfDeath = MOD_LEVEL3_BOUNCEBALL;
bolt->clipmask = MASK_SHOT;
@@ -806,8 +848,6 @@ gentity_t *fire_bounceBall( gentity_t *self, vec3_t start, vec3_t dir )
VectorScale( dir, LEVEL3_BOUNCEBALL_SPEED, bolt->s.pos.trDelta );
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
VectorCopy( start, bolt->r.currentOrigin );
- /*bolt->s.eFlags |= EF_BOUNCE;*/
return bolt;
}
-
diff --git a/src/game/g_mover.c b/src/game/g_mover.c
index 20b5c08..77c1e0c 100644
--- a/src/game/g_mover.c
+++ b/src/game/g_mover.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -33,8 +34,6 @@ PUSHMOVE
===============================================================================
*/
-void MatchTeam( gentity_t *teamLeader, int moverState, int time );
-
typedef struct
{
gentity_t *ent;
@@ -55,17 +54,11 @@ G_TestEntityPosition
gentity_t *G_TestEntityPosition( gentity_t *ent )
{
trace_t tr;
- int mask;
-
- if( ent->clipmask )
- mask = ent->clipmask;
- else
- mask = MASK_SOLID;
if( ent->client )
- trap_Trace( &tr, ent->client->ps.origin, ent->r.mins, ent->r.maxs, ent->client->ps.origin, ent->s.number, mask );
+ trap_Trace( &tr, ent->client->ps.origin, ent->r.mins, ent->r.maxs, ent->client->ps.origin, ent->s.number, ent->clipmask );
else
- trap_Trace( &tr, ent->s.pos.trBase, ent->r.mins, ent->r.maxs, ent->s.pos.trBase, ent->s.number, mask );
+ trap_Trace( &tr, ent->s.pos.trBase, ent->r.mins, ent->r.maxs, ent->s.pos.trBase, ent->s.number, ent->clipmask );
if( tr.startsolid )
return &g_entities[ tr.entityNum ];
@@ -183,7 +176,7 @@ qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, v
// may have pushed them off an edge
if( check->s.groundEntityNum != pusher->s.number )
- check->s.groundEntityNum = -1;
+ check->s.groundEntityNum = ENTITYNUM_NONE;
block = G_TestEntityPosition( check );
@@ -212,7 +205,7 @@ qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, v
if( !block )
{
- check->s.groundEntityNum = -1;
+ check->s.groundEntityNum = ENTITYNUM_NONE;
pushed_p--;
return qtrue;
}
@@ -285,7 +278,7 @@ qboolean G_MoverPush( gentity_t *pusher, vec3_t move, vec3_t amove, gentity_t **
listedEntities = trap_EntitiesInBox( totalMins, totalMaxs, entityList, MAX_GENTITIES );
- // move the pusher to it's final position
+ // move the pusher to its final position
VectorAdd( pusher->r.currentOrigin, move, pusher->r.currentOrigin );
VectorAdd( pusher->r.currentAngles, amove, pusher->r.currentAngles );
trap_LinkEntity( pusher );
@@ -379,6 +372,12 @@ void G_MoverTeam( gentity_t *ent )
pushed_p = pushed;
for( part = ent; part; part = part->teamchain )
{
+ if( part->s.pos.trType == TR_STATIONARY &&
+ part->s.apos.trType == TR_STATIONARY )
+ {
+ continue;
+ }
+
// get current position
BG_EvaluateTrajectory( &part->s.pos, level.time, origin );
BG_EvaluateTrajectory( &part->s.apos, level.time, angles );
@@ -393,6 +392,12 @@ void G_MoverTeam( gentity_t *ent )
// go back to the previous position
for( part = ent; part; part = part->teamchain )
{
+ if( part->s.pos.trType == TR_STATIONARY &&
+ part->s.apos.trType == TR_STATIONARY )
+ {
+ continue;
+ }
+
part->s.pos.trTime += level.time - level.previousTime;
part->s.apos.trTime += level.time - level.previousTime;
BG_EvaluateTrajectory( &part->s.pos, level.time, part->r.currentOrigin );
@@ -442,10 +447,7 @@ void G_RunMover( gentity_t *ent )
if( ent->flags & FL_TEAMSLAVE )
return;
- // if stationary at one of the positions, don't move anything
- if( ( ent->s.pos.trType != TR_STATIONARY || ent->s.apos.trType != TR_STATIONARY ) &&
- ent->moverState < MODEL_POS1 ) //yuck yuck hack
- G_MoverTeam( ent );
+ G_MoverTeam( ent );
// check think function
G_RunThink( ent );
@@ -554,7 +556,6 @@ void SetMoverState( gentity_t *ent, moverState_t moverState, int time )
MatchTeam
All entities in a mover team will move from pos1 to pos2
-in the same amount of time
================
*/
void MatchTeam( gentity_t *teamLeader, int moverState, int time )
@@ -566,40 +567,65 @@ void MatchTeam( gentity_t *teamLeader, int moverState, int time )
}
+/*
+================
+MasterOf
+================
+*/
+gentity_t *MasterOf( gentity_t *ent )
+{
+ if( ent->teammaster )
+ return ent->teammaster;
+ else
+ return ent;
+}
+
/*
================
-ReturnToPos1
+GetMoverTeamState
+
+Returns a MOVER_* value representing the phase (either one
+ of pos1, 1to2, pos2, or 2to1) of a mover team as a whole.
================
*/
-void ReturnToPos1( gentity_t *ent )
+moverState_t GetMoverTeamState( gentity_t *ent )
{
- MatchTeam( ent, MOVER_2TO1, level.time );
+ qboolean pos1 = qfalse;
- // looping sound
- ent->s.loopSound = ent->soundLoop;
+ for( ent = MasterOf( ent ); ent; ent = ent->teamchain )
+ {
+ if( ent->moverState == MOVER_POS1 || ent->moverState == ROTATOR_POS1 )
+ pos1 = qtrue;
+ else if( ent->moverState == MOVER_1TO2 || ent->moverState == ROTATOR_1TO2 )
+ return MOVER_1TO2;
+ else if( ent->moverState == MOVER_2TO1 || ent->moverState == ROTATOR_2TO1 )
+ return MOVER_2TO1;
+ }
- // starting sound
- if( ent->sound2to1 )
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
+ if( pos1 )
+ return MOVER_POS1;
+ else
+ return MOVER_POS2;
}
/*
================
-ReturnToApos1
+ReturnToPos1orApos1
+
+Used only by a master movers.
================
*/
-void ReturnToApos1( gentity_t *ent )
-{
- MatchTeam( ent, ROTATOR_2TO1, level.time );
- // looping sound
- ent->s.loopSound = ent->soundLoop;
+void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator );
- // starting sound
- if( ent->sound2to1 )
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
+void ReturnToPos1orApos1( gentity_t *ent )
+{
+ if( GetMoverTeamState( ent ) != MOVER_POS2 )
+ return; // not every mover in the team has reached its endpoint yet
+
+ Use_BinaryMover( ent, ent, ent->activator );
}
@@ -690,10 +716,10 @@ void Think_OpenModelDoor( gentity_t *ent )
//set brush non-solid
trap_UnlinkEntity( ent->clipBrush );
- // looping sound
- ent->s.loopSound = ent->soundLoop;
+ // stop the looping sound
+ ent->s.loopSound = 0;
- // starting sound
+ // play sound
if( ent->soundPos2 )
G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 );
@@ -718,8 +744,10 @@ Reached_BinaryMover
*/
void Reached_BinaryMover( gentity_t *ent )
{
+ gentity_t *master = MasterOf( ent );
+
// stop the looping sound
- ent->s.loopSound = ent->soundLoop;
+ ent->s.loopSound = 0;
if( ent->moverState == MOVER_1TO2 )
{
@@ -731,8 +759,8 @@ void Reached_BinaryMover( gentity_t *ent )
G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 );
// return to pos1 after a delay
- ent->think = ReturnToPos1;
- ent->nextthink = level.time + ent->wait;
+ master->think = ReturnToPos1orApos1;
+ master->nextthink = MAX( master->nextthink, level.time + ent->wait );
// fire targets
if( !ent->activator )
@@ -763,8 +791,8 @@ void Reached_BinaryMover( gentity_t *ent )
G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 );
// return to apos1 after a delay
- ent->think = ReturnToApos1;
- ent->nextthink = level.time + ent->wait;
+ master->think = ReturnToPos1orApos1;
+ master->nextthink = MAX( master->nextthink, level.time + ent->wait );
// fire targets
if( !ent->activator )
@@ -799,6 +827,8 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
{
int total;
int partial;
+ gentity_t *master;
+ moverState_t teamState;
// if this is a non-client-usable door return
if( ent->targetname && other && other->client )
@@ -813,11 +843,17 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
ent->activator = activator;
+ master = MasterOf( ent );
+ teamState = GetMoverTeamState( ent );
+
+ for( ent = master; ent; ent = ent->teamchain )
+ {
+ //ind
if( ent->moverState == MOVER_POS1 )
{
// start moving 50 msec later, becase if this was player
// triggered, level.time hasn't been advanced yet
- MatchTeam( ent, MOVER_1TO2, level.time + 50 );
+ SetMoverState( ent, MOVER_1TO2, level.time + 50 );
// starting sound
if( ent->sound1to2 )
@@ -830,10 +866,30 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
if( ent->teammaster == ent || !ent->teammaster )
trap_AdjustAreaPortalState( ent, qtrue );
}
- else if( ent->moverState == MOVER_POS2 )
+ else if( ent->moverState == MOVER_POS2 &&
+ !( teamState == MOVER_1TO2 || other == master ) )
{
// if all the way up, just delay before coming down
- ent->nextthink = level.time + ent->wait;
+ master->think = ReturnToPos1orApos1;
+ master->nextthink = MAX( master->nextthink, level.time + ent->wait );
+ }
+ else if( ent->moverState == MOVER_POS2 &&
+ ( teamState == MOVER_1TO2 || other == master ) )
+ {
+ // start moving 50 msec later, becase if this was player
+ // triggered, level.time hasn't been advanced yet
+ SetMoverState( ent, MOVER_2TO1, level.time + 50 );
+
+ // starting sound
+ if( ent->sound2to1 )
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
+
+ // looping sound
+ ent->s.loopSound = ent->soundLoop;
+
+ // open areaportal
+ if( ent->teammaster == ent || !ent->teammaster )
+ trap_AdjustAreaPortalState( ent, qtrue );
}
else if( ent->moverState == MOVER_2TO1 )
{
@@ -844,7 +900,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
if( partial > total )
partial = total;
- MatchTeam( ent, MOVER_1TO2, level.time - ( total - partial ) );
+ SetMoverState( ent, MOVER_1TO2, level.time - ( total - partial ) );
if( ent->sound1to2 )
G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
@@ -858,7 +914,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
if( partial > total )
partial = total;
- MatchTeam( ent, MOVER_2TO1, level.time - ( total - partial ) );
+ SetMoverState( ent, MOVER_2TO1, level.time - ( total - partial ) );
if( ent->sound2to1 )
G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
@@ -867,7 +923,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
{
// start moving 50 msec later, becase if this was player
// triggered, level.time hasn't been advanced yet
- MatchTeam( ent, ROTATOR_1TO2, level.time + 50 );
+ SetMoverState( ent, ROTATOR_1TO2, level.time + 50 );
// starting sound
if( ent->sound1to2 )
@@ -880,10 +936,30 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
if( ent->teammaster == ent || !ent->teammaster )
trap_AdjustAreaPortalState( ent, qtrue );
}
- else if( ent->moverState == ROTATOR_POS2 )
+ else if( ent->moverState == ROTATOR_POS2 &&
+ !( teamState == MOVER_1TO2 || other == master ) )
{
// if all the way up, just delay before coming down
- ent->nextthink = level.time + ent->wait;
+ master->think = ReturnToPos1orApos1;
+ master->nextthink = MAX( master->nextthink, level.time + ent->wait );
+ }
+ else if( ent->moverState == ROTATOR_POS2 &&
+ ( teamState == MOVER_1TO2 || other == master ) )
+ {
+ // start moving 50 msec later, becase if this was player
+ // triggered, level.time hasn't been advanced yet
+ SetMoverState( ent, ROTATOR_2TO1, level.time + 50 );
+
+ // starting sound
+ if( ent->sound2to1 )
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
+
+ // looping sound
+ ent->s.loopSound = ent->soundLoop;
+
+ // open areaportal
+ if( ent->teammaster == ent || !ent->teammaster )
+ trap_AdjustAreaPortalState( ent, qtrue );
}
else if( ent->moverState == ROTATOR_2TO1 )
{
@@ -894,7 +970,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
if( partial > total )
partial = total;
- MatchTeam( ent, ROTATOR_1TO2, level.time - ( total - partial ) );
+ SetMoverState( ent, ROTATOR_1TO2, level.time - ( total - partial ) );
if( ent->sound1to2 )
G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
@@ -908,7 +984,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
if( partial > total )
partial = total;
- MatchTeam( ent, ROTATOR_2TO1, level.time - ( total - partial ) );
+ SetMoverState( ent, ROTATOR_2TO1, level.time - ( total - partial ) );
if( ent->sound2to1 )
G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
@@ -939,6 +1015,8 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
// if all the way up, just delay before coming down
ent->nextthink = level.time + ent->wait;
}
+ //outd
+ }
}
@@ -959,15 +1037,16 @@ void InitMover( gentity_t *ent )
vec3_t color;
qboolean lightSet, colorSet;
char *sound;
+ char *team;
// if the "model2" key is set, use a seperate model
// for drawing, but clip against the brushes
if( ent->model2 )
ent->s.modelindex2 = G_ModelIndex( ent->model2 );
- // if the "loopsound" key is set, use a constant looping sound when moving
- if( G_SpawnString( "noise", "100", &sound ) )
- ent->s.loopSound = G_SoundIndex( sound );
+ // if the "noise" key is set, use a constant looping sound when moving
+ if( G_SpawnString( "noise", "", &sound ) )
+ ent->soundLoop = G_SoundIndex( sound );
// if the "color" or "light" keys are set, setup constantLight
lightSet = G_SpawnFloat( "light", "100", &light );
@@ -1000,8 +1079,10 @@ void InitMover( gentity_t *ent )
ent->use = Use_BinaryMover;
ent->reached = Reached_BinaryMover;
+ if( G_SpawnString( "team", "", &team ) )
+ ent->team = G_CopyString( team );
+
ent->moverState = MOVER_POS1;
- ent->r.svFlags = SVF_USE_CURRENT_ORIGIN;
ent->s.eType = ET_MOVER;
VectorCopy( ent->pos1, ent->r.currentOrigin );
trap_LinkEntity( ent );
@@ -1039,15 +1120,16 @@ void InitRotator( gentity_t *ent )
vec3_t color;
qboolean lightSet, colorSet;
char *sound;
+ char *team;
// if the "model2" key is set, use a seperate model
// for drawing, but clip against the brushes
if( ent->model2 )
ent->s.modelindex2 = G_ModelIndex( ent->model2 );
- // if the "loopsound" key is set, use a constant looping sound when moving
- if( G_SpawnString( "noise", "100", &sound ) )
- ent->s.loopSound = G_SoundIndex( sound );
+ // if the "noise" key is set, use a constant looping sound when moving
+ if( G_SpawnString( "noise", "", &sound ) )
+ ent->soundLoop = G_SoundIndex( sound );
// if the "color" or "light" keys are set, setup constantLight
lightSet = G_SpawnFloat( "light", "100", &light );
@@ -1084,8 +1166,10 @@ void InitRotator( gentity_t *ent )
ent->use = Use_BinaryMover;
ent->reached = Reached_BinaryMover;
+ if( G_SpawnString( "team", "", &team ) )
+ ent->team = G_CopyString( team );
+
ent->moverState = ROTATOR_POS1;
- ent->r.svFlags = SVF_USE_CURRENT_ORIGIN;
ent->s.eType = ET_MOVER;
VectorCopy( ent->pos1, ent->r.currentAngles );
trap_LinkEntity( ent );
@@ -1156,8 +1240,8 @@ static void Touch_DoorTriggerSpectator( gentity_t *ent, gentity_t *other, trace_
axis = ent->count;
VectorClear( dir );
- if( fabs( other->s.origin[ axis ] - ent->r.absmax[ axis ] ) <
- fabs( other->s.origin[ axis ] - ent->r.absmin[ axis ] ) )
+ if( fabs( other->r.currentOrigin[ axis ] - ent->r.absmax[ axis ] ) <
+ fabs( other->r.currentOrigin[ axis ] - ent->r.absmin[ axis ] ) )
{
origin[ axis ] = ent->r.absmin[ axis ] - 20;
dir[ axis ] = -1;
@@ -1177,7 +1261,7 @@ static void Touch_DoorTriggerSpectator( gentity_t *ent, gentity_t *other, trace_
}
vectoangles( dir, angles );
- TeleportPlayer( other, origin, angles );
+ TeleportPlayer( other, origin, angles, 400.0f );
}
@@ -1237,7 +1321,7 @@ static void manualDoorTriggerSpectator( gentity_t *door, gentity_t *player )
================
manualTriggerSpectator
-Trip to skip the closest door targetted by trigger
+Trip to skip the closest door targeted by trigger
================
*/
void manualTriggerSpectator( gentity_t *trigger, gentity_t *player )
@@ -1259,14 +1343,6 @@ void manualTriggerSpectator( gentity_t *trigger, gentity_t *player )
{
if( !strcmp( t->classname, "func_door" ) )
targets[ i++ ] = t;
- else if( t == trigger )
- G_Printf( "WARNING: Entity used itself.\n" );
-
- if( !trigger->inuse )
- {
- G_Printf( "triggerity was removed while using targets\n" );
- return;
- }
}
//if more than 0 targets
@@ -1299,25 +1375,30 @@ Touch_DoorTrigger
*/
void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace )
{
+ moverState_t teamState;
+
//buildables don't trigger movers
if( other->s.eType == ET_BUILDABLE )
return;
- if( other->client && other->client->sess.sessionTeam == TEAM_SPECTATOR )
+ teamState = GetMoverTeamState( ent->parent );
+
+ if( other->client && other->client->sess.spectatorState != SPECTATOR_NOT )
{
// if the door is not open and not opening
- if( ent->parent->moverState != MOVER_1TO2 &&
- ent->parent->moverState != MOVER_POS2 &&
- ent->parent->moverState != ROTATOR_1TO2 &&
- ent->parent->moverState != ROTATOR_POS2 )
+ if( teamState != MOVER_POS2 && teamState != MOVER_1TO2 )
Touch_DoorTriggerSpectator( ent, other, trace );
}
- else if( ent->parent->moverState != MOVER_1TO2 &&
- ent->parent->moverState != ROTATOR_1TO2 &&
- ent->parent->moverState != ROTATOR_2TO1 )
- {
+ else if( teamState != MOVER_1TO2 )
Use_BinaryMover( ent->parent, ent, other );
- }
+}
+
+
+void Think_MatchTeam( gentity_t *ent )
+{
+ if( ent->flags & FL_TEAMSLAVE )
+ return;
+ MatchTeam( ent, ent->moverState, level.time );
}
@@ -1335,11 +1416,6 @@ void Think_SpawnNewDoorTrigger( gentity_t *ent )
vec3_t mins, maxs;
int i, best;
- //TA: disable shootable doors
- // set all of the slaves as shootable
- //for( other = ent; other; other = other->teamchain )
- // other->takedamage = qtrue;
-
// find the bounds of everything on the team
VectorCopy( ent->r.absmin, mins );
VectorCopy( ent->r.absmax, maxs );
@@ -1374,12 +1450,7 @@ void Think_SpawnNewDoorTrigger( gentity_t *ent )
trap_LinkEntity( other );
if( ent->moverState < MODEL_POS1 )
- MatchTeam( ent, ent->moverState, level.time );
-}
-
-void Think_MatchTeam( gentity_t *ent )
-{
- MatchTeam( ent, ent->moverState, level.time );
+ Think_MatchTeam( ent );
}
@@ -1406,6 +1477,7 @@ void SP_func_door( gentity_t *ent )
vec3_t size;
float lip;
char *s;
+ int health;
G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s );
ent->sound2to1 = G_SoundIndex( s );
@@ -1436,11 +1508,13 @@ void SP_func_door( gentity_t *ent )
G_SpawnInt( "dmg", "2", &ent->damage );
// first position at start
- VectorCopy( ent->s.origin, ent->pos1 );
+ VectorCopy( ent->r.currentOrigin, ent->pos1 );
+ G_SetMovedir( ent->r.currentAngles, ent->movedir );
+ VectorClear( ent->s.apos.trBase );
+ VectorClear( ent->r.currentOrigin );
// calculate second position
trap_SetBrushModel( ent, ent->model );
- G_SetMovedir( ent->s.angles, ent->movedir );
abs_movedir[ 0 ] = fabs( ent->movedir[ 0 ] );
abs_movedir[ 1 ] = fabs( ent->movedir[ 1 ] );
abs_movedir[ 2 ] = fabs( ent->movedir[ 2 ] );
@@ -1454,7 +1528,7 @@ void SP_func_door( gentity_t *ent )
vec3_t temp;
VectorCopy( ent->pos2, temp );
- VectorCopy( ent->s.origin, ent->pos2 );
+ VectorCopy( ent->r.currentOrigin, ent->pos2 );
VectorCopy( temp, ent->pos1 );
}
@@ -1462,22 +1536,17 @@ void SP_func_door( gentity_t *ent )
ent->nextthink = level.time + FRAMETIME;
- if( !( ent->flags & FL_TEAMSLAVE ) )
- {
- int health;
-
- G_SpawnInt( "health", "0", &health );
- if( health )
- ent->takedamage = qtrue;
+ G_SpawnInt( "health", "0", &health );
+ if( health )
+ ent->takedamage = qtrue;
- if( ent->targetname || health )
- {
- // non touch/shoot doors
- ent->think = Think_MatchTeam;
- }
- else
- ent->think = Think_SpawnNewDoorTrigger;
+ if( ent->targetname || health )
+ {
+ // non touch/shoot doors
+ ent->think = Think_MatchTeam;
}
+ else
+ ent->think = Think_SpawnNewDoorTrigger;
}
/*QUAKED func_door_rotating (0 .5 .8) START_OPEN CRUSHER REVERSE TOGGLE X_AXIS Y_AXIS
@@ -1502,6 +1571,7 @@ void SP_func_door( gentity_t *ent )
void SP_func_door_rotating( gentity_t *ent )
{
char *s;
+ int health;
G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s );
ent->sound2to1 = G_SoundIndex( s );
@@ -1534,7 +1604,8 @@ void SP_func_door_rotating( gentity_t *ent )
// set the axis of rotation
VectorClear( ent->movedir );
- VectorClear( ent->s.angles );
+ VectorClear( ent->s.apos.trBase );
+ VectorClear( ent->r.currentAngles );
if( ent->spawnflags & 32 )
ent->movedir[ 2 ] = 1.0;
@@ -1552,12 +1623,12 @@ void SP_func_door_rotating( gentity_t *ent )
if( !ent->rotatorAngle )
{
G_Printf( "%s at %s with no rotatorAngle set.\n",
- ent->classname, vtos( ent->s.origin ) );
+ ent->classname, vtos( ent->r.currentOrigin ) );
ent->rotatorAngle = 90.0;
}
- VectorCopy( ent->s.angles, ent->pos1 );
+ VectorCopy( ent->r.currentAngles, ent->pos1 );
trap_SetBrushModel( ent, ent->model );
VectorMA( ent->pos1, ent->rotatorAngle, ent->movedir, ent->pos2 );
@@ -1567,36 +1638,26 @@ void SP_func_door_rotating( gentity_t *ent )
vec3_t temp;
VectorCopy( ent->pos2, temp );
- VectorCopy( ent->s.angles, ent->pos2 );
+ VectorCopy( ent->pos1, ent->pos2 );
VectorCopy( temp, ent->pos1 );
VectorNegate( ent->movedir, ent->movedir );
}
- // set origin
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );
-
InitRotator( ent );
ent->nextthink = level.time + FRAMETIME;
- if( !( ent->flags & FL_TEAMSLAVE ) )
- {
- int health;
-
- G_SpawnInt( "health", "0", &health );
-
- if( health )
- ent->takedamage = qtrue;
+ G_SpawnInt( "health", "0", &health );
+ if( health )
+ ent->takedamage = qtrue;
- if( ent->targetname || health )
- {
- // non touch/shoot doors
- ent->think = Think_MatchTeam;
- }
- else
- ent->think = Think_SpawnNewDoorTrigger;
+ if( ent->targetname || health )
+ {
+ // non touch/shoot doors
+ ent->think = Think_MatchTeam;
}
+ else
+ ent->think = Think_SpawnNewDoorTrigger;
}
/*QUAKED func_door_model (0 .5 .8) ? START_OPEN
@@ -1620,6 +1681,7 @@ void SP_func_door_model( gentity_t *ent )
qboolean lightSet, colorSet;
char *sound;
gentity_t *clipBrush;
+ int health;
G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s );
ent->sound2to1 = G_SoundIndex( s );
@@ -1643,6 +1705,8 @@ void SP_func_door_model( gentity_t *ent )
//brush model
clipBrush = ent->clipBrush = G_Spawn( );
+ clipBrush->classname = "func_door_model_clip_brush";
+ clipBrush->clipBrush = ent; // link back
clipBrush->model = ent->model;
trap_SetBrushModel( clipBrush, clipBrush->model );
clipBrush->s.eType = ET_INVISIBLE;
@@ -1655,7 +1719,7 @@ void SP_func_door_model( gentity_t *ent )
VectorCopy( clipBrush->r.mins, ent->r.mins );
VectorCopy( clipBrush->r.maxs, ent->r.maxs );
- G_SpawnVector( "modelOrigin", "0 0 0", ent->s.origin );
+ G_SpawnVector( "modelOrigin", "0 0 0", ent->r.currentOrigin );
G_SpawnVector( "scale", "1 1 1", ent->s.origin2 );
@@ -1666,9 +1730,9 @@ void SP_func_door_model( gentity_t *ent )
else
ent->s.modelindex = G_ModelIndex( ent->model2 );
- // if the "loopsound" key is set, use a constant looping sound when moving
- if( G_SpawnString( "noise", "100", &sound ) )
- ent->s.loopSound = G_SoundIndex( sound );
+ // if the "noise" key is set, use a constant looping sound when moving
+ if( G_SpawnString( "noise", "", &sound ) )
+ ent->soundLoop = G_SoundIndex( sound );
// if the "color" or "light" keys are set, setup constantLight
lightSet = G_SpawnFloat( "light", "100", &light );
@@ -1701,19 +1765,17 @@ void SP_func_door_model( gentity_t *ent )
ent->moverState = MODEL_POS1;
ent->s.eType = ET_MODELDOOR;
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
ent->s.pos.trType = TR_STATIONARY;
ent->s.pos.trTime = 0;
ent->s.pos.trDuration = 0;
VectorClear( ent->s.pos.trDelta );
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
ent->s.apos.trType = TR_STATIONARY;
ent->s.apos.trTime = 0;
ent->s.apos.trDuration = 0;
VectorClear( ent->s.apos.trDelta );
- ent->s.misc = (int)ent->animation[ 0 ]; //first frame
- ent->s.weapon = abs( (int)ent->animation[ 1 ] ); //number of frames
+ ent->s.misc = (int)ent->animation[ 0 ]; //first frame
+ ent->s.weapon = abs( (int)ent->animation[ 1 ] ); //number of frames
//must be at least one frame -- mapper has forgotten animation key
if( ent->s.weapon == 0 )
@@ -1723,19 +1785,14 @@ void SP_func_door_model( gentity_t *ent )
trap_LinkEntity( ent );
- if( !( ent->flags & FL_TEAMSLAVE ) )
- {
- int health;
-
- G_SpawnInt( "health", "0", &health );
- if( health )
- ent->takedamage = qtrue;
+ G_SpawnInt( "health", "0", &health );
+ if( health )
+ ent->takedamage = qtrue;
- if( !( ent->targetname || health ) )
- {
- ent->nextthink = level.time + FRAMETIME;
- ent->think = Think_SpawnNewDoorTrigger;
- }
+ if( !( ent->targetname || health ) )
+ {
+ ent->nextthink = level.time + FRAMETIME;
+ ent->think = Think_SpawnNewDoorTrigger;
}
}
@@ -1751,7 +1808,7 @@ PLAT
==============
Touch_Plat
-Don't allow decent if a living player is on it
+Don't allow to descend if a player is on it and is alive
===============
*/
void Touch_Plat( gentity_t *ent, gentity_t *other, trace_t *trace )
@@ -1860,7 +1917,8 @@ void SP_func_plat( gentity_t *ent )
G_SpawnString( "soundPos1", "sound/movers/plats/pt1_end.wav", &s );
ent->soundPos1 = G_SoundIndex( s );
- VectorClear( ent->s.angles );
+ VectorClear( ent->s.apos.trBase );
+ VectorClear( ent->r.currentAngles );
G_SpawnFloat( "speed", "200", &ent->speed );
G_SpawnInt( "dmg", "2", &ent->damage );
@@ -1876,7 +1934,7 @@ void SP_func_plat( gentity_t *ent )
height = ( ent->r.maxs[ 2 ] - ent->r.mins[ 2 ] ) - lip;
// pos1 is the rest (bottom) position, pos2 is the top
- VectorCopy( ent->s.origin, ent->pos2 );
+ VectorCopy( ent->r.currentOrigin, ent->pos2 );
VectorCopy( ent->pos2, ent->pos1 );
ent->pos1[ 2 ] -= height;
@@ -1921,7 +1979,7 @@ void Touch_Button( gentity_t *ent, gentity_t *other, trace_t *trace )
/*QUAKED func_button (0 .5 .8) ?
-When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
+When a button is touched, it moves some distance in the direction of its angle, triggers all of its targets, waits some time, then returns to its original position where it can be triggered again.
"model2" .md3 model to also draw
"angle" determines the opening direction
@@ -1953,14 +2011,16 @@ void SP_func_button( gentity_t *ent )
ent->wait *= 1000;
// first position
- VectorCopy( ent->s.origin, ent->pos1 );
+ VectorCopy( ent->r.currentOrigin, ent->pos1 );
+ G_SetMovedir( ent->r.currentAngles, ent->movedir );
+ VectorClear( ent->s.apos.trBase );
+ VectorClear( ent->r.currentAngles );
// calculate second position
trap_SetBrushModel( ent, ent->model );
G_SpawnFloat( "lip", "4", &lip );
- G_SetMovedir( ent->s.angles, ent->movedir );
abs_movedir[ 0 ] = fabs( ent->movedir[ 0 ] );
abs_movedir[ 1 ] = fabs( ent->movedir[ 1 ] );
abs_movedir[ 2 ] = fabs( ent->movedir[ 2 ] );
@@ -2031,8 +2091,8 @@ void Reached_Train( gentity_t *ent )
// set the new trajectory
ent->nextTrain = next->nextTrain;
- VectorCopy( next->s.origin, ent->pos1 );
- VectorCopy( next->nextTrain->s.origin, ent->pos2 );
+ VectorCopy( next->r.currentOrigin, ent->pos1 );
+ VectorCopy( next->nextTrain->r.currentOrigin, ent->pos2 );
// if the path_corner has a speed, use that
if( next->speed )
@@ -2056,6 +2116,19 @@ void Reached_Train( gentity_t *ent )
ent->s.pos.trDuration = length * 1000 / speed;
+ // Be sure to send to clients after any fast move case
+ ent->r.svFlags &= ~SVF_NOCLIENT;
+
+ // Fast move case
+ if( ent->s.pos.trDuration < 1 )
+ {
+ // As trDuration is used later in a division, we need to avoid that case now
+ ent->s.pos.trDuration = 1;
+
+ // Don't send entity to clients so it becomes really invisible
+ ent->r.svFlags |= SVF_NOCLIENT;
+ }
+
// looping sound
ent->s.loopSound = next->soundLoop;
@@ -2160,7 +2233,7 @@ void Think_SetupTrainTargets( gentity_t *ent )
if( !path->target )
{
G_Printf( "Train corner at %s without a target\n",
- vtos( path->s.origin ) );
+ vtos( path->r.currentOrigin ) );
return;
}
@@ -2175,7 +2248,7 @@ void Think_SetupTrainTargets( gentity_t *ent )
if( !next )
{
G_Printf( "Train corner at %s without a target path_corner\n",
- vtos( path->s.origin ) );
+ vtos( path->r.currentOrigin ) );
return;
}
} while( strcmp( next->classname, "path_corner" ) );
@@ -2199,7 +2272,7 @@ void SP_path_corner( gentity_t *self )
{
if( !self->targetname )
{
- G_Printf( "path_corner with no targetname at %s\n", vtos( self->s.origin ) );
+ G_Printf( "path_corner with no targetname at %s\n", vtos( self->r.currentOrigin ) );
G_FreeEntity( self );
return;
}
@@ -2231,16 +2304,16 @@ void Blocked_Train( gentity_t *self, gentity_t *other )
vec3_t dir;
gentity_t *tent;
- if( other->biteam == BIT_ALIENS )
+ if( other->buildableTeam == TEAM_ALIENS )
{
VectorCopy( other->s.origin2, dir );
- tent = G_TempEntity( other->s.origin, EV_ALIEN_BUILDABLE_EXPLOSION );
+ tent = G_TempEntity( other->r.currentOrigin, EV_ALIEN_BUILDABLE_EXPLOSION );
tent->s.eventParm = DirToByte( dir );
}
- else if( other->biteam == BIT_HUMANS )
+ else if( other->buildableTeam == TEAM_HUMANS )
{
VectorSet( dir, 0.0f, 0.0f, 1.0f );
- tent = G_TempEntity( other->s.origin, EV_HUMAN_BUILDABLE_EXPLOSION );
+ tent = G_TempEntity( other->r.currentOrigin, EV_HUMAN_BUILDABLE_EXPLOSION );
tent->s.eventParm = DirToByte( dir );
}
}
@@ -2271,7 +2344,8 @@ The train spawns at the first target it is pointing at.
*/
void SP_func_train( gentity_t *self )
{
- VectorClear( self->s.angles );
+ VectorClear( self->s.apos.trBase );
+ VectorClear( self->r.currentAngles );
if( self->spawnflags & TRAIN_BLOCK_STOPS )
self->damage = 0;
@@ -2318,10 +2392,12 @@ A bmodel that just sits there, doing nothing. Can be used for conditional walls
*/
void SP_func_static( gentity_t *ent )
{
+ vec3_t savedOrigin;
trap_SetBrushModel( ent, ent->model );
+ VectorCopy( ent->r.currentOrigin, savedOrigin );
InitMover( ent );
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
+ VectorCopy( savedOrigin, ent->r.currentOrigin );
+ VectorCopy( savedOrigin, ent->s.pos.trBase );
}
@@ -2347,6 +2423,8 @@ check either the X_AXIS or Y_AXIS box to change that.
*/
void SP_func_rotating( gentity_t *ent )
{
+ vec3_t savedOrigin;
+
if( !ent->speed )
ent->speed = 100;
@@ -2364,11 +2442,10 @@ void SP_func_rotating( gentity_t *ent )
ent->damage = 2;
trap_SetBrushModel( ent, ent->model );
+ VectorCopy( ent->r.currentOrigin, savedOrigin );
InitMover( ent );
-
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );
- VectorCopy( ent->s.apos.trBase, ent->r.currentAngles );
+ VectorCopy( savedOrigin, ent->r.currentOrigin );
+ VectorCopy( savedOrigin, ent->s.pos.trBase );
trap_LinkEntity( ent );
}
@@ -2397,6 +2474,7 @@ void SP_func_bobbing( gentity_t *ent )
{
float height;
float phase;
+ vec3_t savedOrigin;
G_SpawnFloat( "speed", "4", &ent->speed );
G_SpawnFloat( "height", "32", &height );
@@ -2404,10 +2482,10 @@ void SP_func_bobbing( gentity_t *ent )
G_SpawnFloat( "phase", "0", &phase );
trap_SetBrushModel( ent, ent->model );
+ VectorCopy( ent->r.currentOrigin, savedOrigin );
InitMover( ent );
-
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
+ VectorCopy( savedOrigin, ent->r.currentOrigin );
+ VectorCopy( savedOrigin, ent->s.pos.trBase );
ent->s.pos.trDuration = ent->speed * 1000;
ent->s.pos.trTime = ent->s.pos.trDuration * phase;
@@ -2448,6 +2526,7 @@ void SP_func_pendulum( gentity_t *ent )
float length;
float phase;
float speed;
+ vec3_t savedOrigin;
G_SpawnFloat( "speed", "30", &speed );
G_SpawnInt( "dmg", "2", &ent->damage );
@@ -2465,12 +2544,10 @@ void SP_func_pendulum( gentity_t *ent )
ent->s.pos.trDuration = ( 1000 / freq );
+ VectorCopy( ent->r.currentOrigin, savedOrigin );
InitMover( ent );
-
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
-
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
+ VectorCopy( savedOrigin, ent->r.currentOrigin );
+ VectorCopy( savedOrigin, ent->s.pos.trBase );
ent->s.apos.trDuration = 1000 / freq;
ent->s.apos.trTime = ent->s.apos.trDuration * phase;
diff --git a/src/game/g_namelog.c b/src/game/g_namelog.c
new file mode 100644
index 0000000..b789743
--- /dev/null
+++ b/src/game/g_namelog.c
@@ -0,0 +1,128 @@
+/*
+===========================================================================
+Copyright (C) 2010 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "g_local.h"
+
+void G_namelog_cleanup( void )
+{
+ namelog_t *namelog, *n;
+
+ for( namelog = level.namelogs; namelog; namelog = n )
+ {
+ n = namelog->next;
+ BG_Free( namelog );
+ }
+}
+
+void G_namelog_connect( gclient_t *client )
+{
+ namelog_t *n, *p = NULL;
+ int i;
+ char *newname;
+
+ for( n = level.namelogs; n; p = n, n = n->next )
+ {
+ if( n->slot != -1 )
+ continue;
+ if( !Q_stricmp( client->pers.guid, n->guid ) )
+ break;
+ }
+ if( !n )
+ {
+ n = BG_Alloc( sizeof( namelog_t ) );
+ strcpy( n->guid, client->pers.guid );
+ n->guidless = client->pers.guidless;
+ if( p )
+ {
+ p->next = n;
+ n->id = p->id + 1;
+ }
+ else
+ {
+ level.namelogs = n;
+ n->id = MAX_CLIENTS;
+ }
+ }
+ client->pers.namelog = n;
+ n->slot = client - level.clients;
+ n->banned = qfalse;
+
+ newname = n->name[ n->nameOffset ];
+ // If they're muted, copy in their last known name - this will stop people
+ // reconnecting to get around the name change protection.
+ if( n->muted && G_admin_name_check( &g_entities[ n->slot ],
+ newname, NULL, 0 ) )
+ Q_strncpyz( client->pers.netname, newname, MAX_NAME_LENGTH );
+
+ for( i = 0; i < MAX_NAMELOG_ADDRS && n->ip[ i ].str[ 0 ]; i++ )
+ if( !strcmp( n->ip[ i ].str, client->pers.ip.str ) )
+ return;
+ if( i == MAX_NAMELOG_ADDRS )
+ i--;
+ memcpy( &n->ip[ i ], &client->pers.ip, sizeof( n->ip[ i ] ) );
+}
+
+void G_namelog_disconnect( gclient_t *client )
+{
+ if( client->pers.namelog == NULL )
+ return;
+ client->pers.namelog->slot = -1;
+ client->pers.namelog = NULL;
+}
+
+void G_namelog_update_score( gclient_t *client )
+{
+ namelog_t *n = client->pers.namelog;
+ if( n == NULL )
+ return;
+
+ n->team = client->pers.teamSelection;
+ n->score = client->ps.persistant[ PERS_SCORE ];
+ n->credits = client->pers.credit;
+}
+
+void G_namelog_update_name( gclient_t *client )
+{
+ char n1[ MAX_NAME_LENGTH ], n2[ MAX_NAME_LENGTH ];
+ namelog_t *n = client->pers.namelog;
+
+ if( n->name[ n->nameOffset ][ 0 ] )
+ {
+ G_SanitiseString( client->pers.netname, n1, sizeof( n1 ) );
+ G_SanitiseString( n->name[ n->nameOffset ],
+ n2, sizeof( n2 ) );
+ if( strcmp( n1, n2 ) != 0 )
+ n->nameOffset = ( n->nameOffset + 1 ) % MAX_NAMELOG_NAMES;
+ }
+ strcpy( n->name[ n->nameOffset ], client->pers.netname );
+}
+
+void G_namelog_restore( gclient_t *client )
+{
+ namelog_t *n = client->pers.namelog;
+
+ G_ChangeTeam( g_entities + n->slot, n->team );
+ client->ps.persistant[ PERS_SCORE ] = n->score;
+ client->ps.persistant[ PERS_CREDIT ] = 0;
+ G_AddCreditToClient( client, n->credits, qfalse );
+}
diff --git a/src/game/g_physics.c b/src/game/g_physics.c
index 58c6487..9384c17 100644
--- a/src/game/g_physics.c
+++ b/src/game/g_physics.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -45,8 +46,8 @@ static void G_Bounce( gentity_t *ent, trace_t *trace )
if( ent->s.eType == ET_BUILDABLE )
{
- minNormal = BG_FindMinNormalForBuildable( ent->s.modelindex );
- invert = BG_FindInvertNormalForBuildable( ent->s.modelindex );
+ minNormal = BG_Buildable( ent->s.modelindex )->minNormal;
+ invert = BG_Buildable( ent->s.modelindex )->invertNormal;
}
else
minNormal = 0.707f;
@@ -61,7 +62,6 @@ static void G_Bounce( gentity_t *ent, trace_t *trace )
if( VectorLength( ent->s.pos.trDelta ) < 10 )
{
- VectorMA( trace->endpos, 0.5f, trace->plane.normal, trace->endpos ); // make sure it is off ground
G_SetOrigin( ent, trace->endpos );
ent->s.groundEntityNum = trace->entityNum;
VectorCopy( trace->plane.normal, ent->s.origin2 );
@@ -69,8 +69,8 @@ static void G_Bounce( gentity_t *ent, trace_t *trace )
return;
}
+ VectorMA( ent->r.currentOrigin, 0.15, trace->plane.normal, ent->r.currentOrigin );
VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
- VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
ent->s.pos.trTime = level.time;
}
@@ -87,16 +87,15 @@ void G_Physics( gentity_t *ent, int msec )
vec3_t origin;
trace_t tr;
int contents;
- int mask;
- // if groundentity has been set to -1, it may have been pushed off an edge
- if( ent->s.groundEntityNum == -1 )
+ // if groundentity has been set to ENTITYNUM_NONE, ent may have been pushed off an edge
+ if( ent->s.groundEntityNum == ENTITYNUM_NONE )
{
if( ent->s.eType == ET_BUILDABLE )
{
- if( ent->s.pos.trType != BG_FindTrajectoryForBuildable( ent->s.modelindex ) )
+ if( ent->s.pos.trType != BG_Buildable( ent->s.modelindex )->traj )
{
- ent->s.pos.trType = BG_FindTrajectoryForBuildable( ent->s.modelindex );
+ ent->s.pos.trType = BG_Buildable( ent->s.modelindex )->traj;
ent->s.pos.trTime = level.time;
}
}
@@ -107,12 +106,6 @@ void G_Physics( gentity_t *ent, int msec )
}
}
- // trace a line from the previous position to the current position
- if( ent->clipmask )
- mask = ent->clipmask;
- else
- mask = MASK_PLAYERSOLID & ~CONTENTS_BODY;//MASK_SOLID;
-
if( ent->s.pos.trType == TR_STATIONARY )
{
// check think function
@@ -125,10 +118,10 @@ void G_Physics( gentity_t *ent, int msec )
VectorMA( origin, -2.0f, ent->s.origin2, origin );
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, ent->s.number, mask );
+ trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, ent->s.number, ent->clipmask );
if( tr.fraction == 1.0f )
- ent->s.groundEntityNum = -1;
+ ent->s.groundEntityNum = ENTITYNUM_NONE;
ent->nextPhysicsTime = level.time + PHYSICS_TIME;
}
@@ -136,10 +129,12 @@ void G_Physics( gentity_t *ent, int msec )
return;
}
+ // trace a line from the previous position to the current position
+
// get current position
BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, ent->s.number, mask );
+ trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, ent->s.number, ent->clipmask );
VectorCopy( tr.endpos, ent->r.currentOrigin );
@@ -158,10 +153,11 @@ void G_Physics( gentity_t *ent, int msec )
contents = trap_PointContents( ent->r.currentOrigin, -1 );
if( contents & CONTENTS_NODROP )
{
+ if( ent->s.eType == ET_BUILDABLE )
+ G_RemoveRangeMarkerFrom( ent );
G_FreeEntity( ent );
return;
}
G_Bounce( ent, &tr );
}
-
diff --git a/src/game/g_playermodel.c b/src/game/g_playermodel.c
new file mode 100644
index 0000000..7f79b38
--- /dev/null
+++ b/src/game/g_playermodel.c
@@ -0,0 +1,193 @@
+//
+// Author: blowFish <blowfish@badsec.org>
+//
+
+#include "g_local.h"
+
+//-------------------------------------------------------------------------
+// Player models
+//-------------------------------------------------------------------------
+//
+static qboolean
+_is_playermodel_uniq(const char *model)
+{
+ int i;
+ for ( i = 0; i < level.playerModelCount; i++ )
+ {
+ if ( !strcmp( model, level.playerModel[i] ) )
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+static void
+G_AddPlayerModel(const char *model)
+{
+ if (!_is_playermodel_uniq(model))
+ return;
+
+ // HACK!
+ if (!strcmp(model, "human_bsuit"))
+ return;
+
+ level.playerModel[ level.playerModelCount ] = G_CopyString(model);
+ level.playerModelCount++;
+}
+
+void G_InitPlayerModel(void)
+{
+ char fileList[ 16*1024 ] = {""};
+ char *filePtr;
+ int numFiles;
+ int fileLen = 0;
+ int i;
+
+ // TODO: Add an FS trap which is does correct file globbing
+ numFiles = trap_FS_GetFilteredFiles( "/models/players", "",
+ "models*players*head_*.skin",
+ fileList, sizeof(fileList) );
+ filePtr = fileList;
+
+ for( i = 0; i < numFiles && level.playerModelCount < MAX_PLAYER_MODEL;
+ i++, filePtr += fileLen + 1 )
+ {
+ char *start, *c;
+
+ fileLen = strlen( filePtr );
+
+ // skip leading '/'
+ start = filePtr + 15;
+
+ // Only want directory names at the current depth.
+ for ( c = start; c != '\0'; c++ )
+ {
+ if ( *c == '/' || *c == '\\' )
+ {
+ *c = '\0';
+ break;
+ }
+ }
+
+ G_AddPlayerModel(start);
+ }
+}
+
+qboolean G_IsValidPlayerModel(const char *model)
+{
+ return !_is_playermodel_uniq(model);
+}
+
+void G_FreePlayerModel(void)
+{
+ int i;
+ for ( i = 0; i < level.playerModelCount; i++ )
+ BG_Free( level.playerModel[i] );
+}
+
+//-------------------------------------------------------------------------
+// Skins
+//-------------------------------------------------------------------------
+
+void G_GetPlayerModelSkins( const char *modelname, char skins[][ 64 ],
+ int maxskins, int *numskins )
+{
+ char fileList[ 16*1024 ] = {""};
+ int nFiles;
+ char *filePtr;
+ int fileLen = 0;
+ int i;
+
+ *numskins = 0;
+ nFiles = trap_FS_GetFilteredFiles("models/players", ".skin",
+ va("models*players*%s*skin", modelname),
+ fileList, sizeof(fileList));
+ filePtr = fileList;
+ for (i = 0; i < nFiles && i < maxskins; i++ )
+ {
+ char *start, *end;
+
+ fileLen = strlen( filePtr );
+
+ start = filePtr;
+ start += strlen(va("models/players/%s/", modelname));
+
+ end = filePtr + fileLen;
+ end -= 5;
+ *end = '\0';
+ filePtr += fileLen + 1;
+
+ // dumb way to filter out the unique skins of segmented and
+ // nonsegmented models.
+ // TODO: Stop writing code at 4am.
+ if ( start[0] == 'h'
+ && start[1] == 'e'
+ && start[2] == 'a'
+ && start[3] == 'd'
+ && start[4] == '_' )
+ start += 5;
+
+ else if ( start[0] == 'n'
+ && start[1] == 'o'
+ && start[2] == 'n'
+ && start[3] == 's'
+ && start[4] == 'e'
+ && start[5] == 'g'
+ && start[6] == '_' )
+ start += 7;
+
+ else
+ continue;
+
+ strncpy(skins[*numskins], start, 64 );
+ (*numskins)++;
+ }
+}
+
+/*
+======================
+GetSkin
+
+Probably should be called GetSkin[or]Default. Tries to recreate what
+appears to be an undocumented set of conventions that must be allowed
+in other q3 derives.
+
+This algorithm is not really good enough for Tremulous considering
+armour + upgrade/advanced in gameplay
+
+XXX Move this into bg_
+======================
+*/
+char *GetSkin( char *modelname, char *wish )
+{
+ char skins[ MAX_PLAYER_MODEL ][ 64 ];
+ int numskins;
+ int i;
+ qboolean foundDefault = qfalse;
+ qboolean foundSelfNamed = qfalse;
+ static char lastpick[ 64 ] = {""};
+ lastpick[0] = '\0'; // reset static buf
+
+ G_GetPlayerModelSkins(modelname, skins, MAX_PLAYER_MODEL, &numskins);
+
+ for (i = 0; i < numskins; i++)
+ {
+ if ( i == 0 )
+ strncpy(lastpick, skins[0], 64 );
+
+ if ( !strcmp(wish, skins[i]) )
+ return wish;
+ else if ( !strcmp("default", skins[i]))
+ foundDefault = qtrue;
+ else if ( !strcmp(modelname, skins[i]))
+ foundSelfNamed = qtrue;
+ }
+
+ if (foundDefault)
+ return "default";
+ else if (foundSelfNamed)
+ return modelname;
+
+ return lastpick;
+}
+
diff --git a/src/game/g_ptr.c b/src/game/g_ptr.c
deleted file mode 100644
index e102183..0000000
--- a/src/game/g_ptr.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
-
-This file is part of Tremulous.
-
-Tremulous is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Tremulous is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-// g_ptr.c -- post timeout restoration handling
-
-#include "g_local.h"
-
-static connectionRecord_t connections[ MAX_CLIENTS ];
-
-/*
-===============
-G_CheckForUniquePTRC
-
-Callback to detect ptrc clashes
-===============
-*/
-static qboolean G_CheckForUniquePTRC( int code )
-{
- int i;
-
- if( code == 0 )
- return qfalse;
-
- for( i = 0; i < MAX_CLIENTS; i++ )
- {
- if( connections[ i ].ptrCode == code )
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-===============
-G_UpdatePTRConnection
-
-Update the data in a connection record
-===============
-*/
-void G_UpdatePTRConnection( gclient_t *client )
-{
- if( client && client->pers.connection )
- {
- client->pers.connection->clientTeam = client->pers.teamSelection;
- client->pers.connection->clientCredit = client->pers.credit;
- client->pers.connection->clientScore = client->pers.score;
- }
-}
-
-/*
-===============
-G_GenerateNewConnection
-
-Generates a new connection
-===============
-*/
-connectionRecord_t *G_GenerateNewConnection( gclient_t *client )
-{
- int code = 0;
- int i;
-
- // this should be really random
- srand( trap_Milliseconds( ) );
-
- // there is a very very small possibility that this
- // will loop infinitely
- do
- {
- code = rand( );
- } while( !G_CheckForUniquePTRC( code ) );
-
- for( i = 0; i < MAX_CLIENTS; i++ )
- {
- //found an unused slot
- if( !connections[ i ].ptrCode )
- {
- connections[ i ].ptrCode = code;
- connections[ i ].clientNum = client->ps.clientNum;
- client->pers.connection = &connections[ i ];
- G_UpdatePTRConnection( client );
- client->pers.connection->clientEnterTime = client->pers.enterTime;
-
- return &connections[ i ];
- }
- }
-
- return NULL;
-}
-
-/*
-===============
-G_FindConnectionForCode
-
-Finds a connection for a given code
-===============
-*/
-connectionRecord_t *G_FindConnectionForCode( int code )
-{
- int i;
-
- if( code == 0 )
- return NULL;
-
- for( i = 0; i < MAX_CLIENTS; i++ )
- {
- if( connections[ i ].ptrCode == code )
- return &connections[ i ];
- }
-
- return NULL;
-}
-
-/*
-===============
-G_ResetPTRConnections
-
-Invalidate any existing codes
-===============
-*/
-void G_ResetPTRConnections( void )
-{
- memset( connections, 0, sizeof( connectionRecord_t ) * MAX_CLIENTS );
-}
diff --git a/src/game/g_public.h b/src/game/g_public.h
index e1e01d7..415ab96 100644
--- a/src/game/g_public.h
+++ b/src/game/g_public.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,252 +17,253 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// g_public.h -- game module information visible to server
+#ifndef GAME_PUBLIC_H
+#define GAME_PUBLIC_H
+
+#include "qcommon/q_shared.h"
-#define GAME_API_VERSION 8
+#define GAME_API_VERSION 9
// entity->svFlags
// the server does not know how to interpret most of the values
// in entityStates (level eType), so the game must explicitly flag
// special server behaviors
-#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects
-
-// TTimo
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=551
-#define SVF_CLIENTMASK 0x00000002
-
-#define SVF_BROADCAST 0x00000020 // send to all connected clients
-#define SVF_PORTAL 0x00000040 // merge a second pvs at origin2 into snapshots
-#define SVF_USE_CURRENT_ORIGIN 0x00000080 // entity->r.currentOrigin instead of entity->s.origin
- // for link position (missiles and movers)
-#define SVF_SINGLECLIENT 0x00000100 // only send to a single client (entityShared_t->singleClient)
-#define SVF_NOSERVERINFO 0x00000200 // don't send CS_SERVERINFO updates to this client
- // so that it can be updated for ping tools without
- // lagging clients
-#define SVF_CAPSULE 0x00000400 // use capsule for collision detection instead of bbox
-#define SVF_NOTSINGLECLIENT 0x00000800 // send entity to everyone but one client
- // (entityShared_t->singleClient)
+#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects
-//===============================================================
+#define SVF_CLIENTMASK 0x00000002 // send to clients specified by these bitmasks:
+// entityShared_t->singleClient: low-order bits (0..31)
+// entityShared_t->hack.generic1: high-order bits (32..63)
+#define SVF_BROADCAST 0x00000020 // send to all connected clients
+#define SVF_PORTAL 0x00000040 // merge a second pvs at origin2 into snapshots
-typedef struct {
- entityState_t s; // communicated by server to clients
-
- qboolean linked; // qfalse if not in any good cluster
- int linkcount;
-
- int svFlags; // SVF_NOCLIENT, SVF_BROADCAST, etc
- int singleClient; // only send to this client when SVF_SINGLECLIENT is set
-
- qboolean bmodel; // if false, assume an explicit mins / maxs bounding box
- // only set by trap_SetBrushModel
- vec3_t mins, maxs;
- int contents; // CONTENTS_TRIGGER, CONTENTS_SOLID, CONTENTS_BODY, etc
- // a non-solid entity should set to 0
-
- vec3_t absmin, absmax; // derived from mins/maxs and origin + rotation
-
- // currentOrigin will be used for all collision detection and world linking.
- // it will not necessarily be the same as the trajectory evaluation for the current
- // time, because each entity must be moved one at a time after time is advanced
- // to avoid simultanious collision issues
- vec3_t currentOrigin;
- vec3_t currentAngles;
-
- // when a trace call is made and passEntityNum != ENTITYNUM_NONE,
- // an ent will be excluded from testing if:
- // ent->s.number == passEntityNum (don't interact with self)
- // ent->s.ownerNum = passEntityNum (don't interact with your own missiles)
- // entity[ent->s.ownerNum].ownerNum = passEntityNum (don't interact with other missiles from owner)
- int ownerNum;
-} entityShared_t;
+#define SVF_SINGLECLIENT 0x00000100 // only send to a single client (entityShared_t->singleClient)
+#define SVF_NOSERVERINFO 0x00000200 // don't send CS_SERVERINFO updates to this client
+// so that it can be updated for ping tools without
+// lagging clients
+#define SVF_CAPSULE 0x00000400 // use capsule for collision detection instead of bbox
+#define SVF_NOTSINGLECLIENT 0x00000800 // send entity to everyone but one client
+// (entityShared_t->singleClient)
+//===============================================================
+typedef struct {
+ entityState_t hack; // exists (as padding) to retain ABI compatibility
+ // with GPP, but can be used for extension hacks
+
+ qboolean linked; // qfalse if not in any good cluster
+ int linkcount;
+
+ int svFlags; // SVF_NOCLIENT, SVF_BROADCAST, etc.
+ int singleClient; // only send to this client when SVF_SINGLECLIENT is set
+
+ qboolean bmodel; // if false, assume an explicit mins / maxs bounding box
+ // only set by trap_SetBrushModel
+ vec3_t mins, maxs;
+ int contents; // CONTENTS_TRIGGER, CONTENTS_SOLID, CONTENTS_BODY, etc
+ // a non-solid entity should set to 0
+
+ vec3_t absmin, absmax; // derived from mins/maxs and origin + rotation
+
+ // currentOrigin will be used for all collision detection and world linking.
+ // it will not necessarily be the same as the trajectory evaluation for the current
+ // time, because each entity must be moved one at a time after time is advanced
+ // to avoid simultanious collision issues
+ vec3_t currentOrigin;
+ vec3_t currentAngles;
+
+ // when a trace call is made and passEntityNum != ENTITYNUM_NONE,
+ // an ent will be excluded from testing if:
+ // ent->s.number == passEntityNum (don't interact with self)
+ // ent->r.ownerNum == passEntityNum (don't interact with your own missiles)
+ // entity[ent->r.ownerNum].r.ownerNum == passEntityNum (don't interact with other missiles from owner)
+ int ownerNum;
+} entityShared_t;
// the server looks at a sharedEntity, which is the start of the game's gentity_t structure
typedef struct {
- entityState_t s; // communicated by server to clients
- entityShared_t r; // shared by both the server system and game
+ entityState_t s; // communicated by server to clients
+ entityShared_t r; // shared by both the server system and game
} sharedEntity_t;
-
-
//===============================================================
//
// system traps provided by the main engine
//
typedef enum {
- //============== general Quake services ==================
-
- G_PRINT, // ( const char *string );
- // print message on the local console
+ //============== general Quake services ==================
- G_ERROR, // ( const char *string );
- // abort the game
+ G_PRINT, // ( const char *string );
+ // print message on the local console
- G_MILLISECONDS, // ( void );
- // get current time for profiling reasons
- // this should NOT be used for any game related tasks,
- // because it is not journaled
+ G_ERROR, // ( const char *string );
+ // abort the game
- // console variable interaction
- G_CVAR_REGISTER, // ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
- G_CVAR_UPDATE, // ( vmCvar_t *vmCvar );
- G_CVAR_SET, // ( const char *var_name, const char *value );
- G_CVAR_VARIABLE_INTEGER_VALUE, // ( const char *var_name );
+ G_MILLISECONDS, // ( void );
+ // get current time for profiling reasons
+ // this should NOT be used for any game related tasks,
+ // because it is not journaled
- G_CVAR_VARIABLE_STRING_BUFFER, // ( const char *var_name, char *buffer, int bufsize );
+ // console variable interaction
+ G_CVAR_REGISTER, // ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
+ G_CVAR_UPDATE, // ( vmCvar_t *vmCvar );
+ G_CVAR_SET, // ( const char *var_name, const char *value );
+ G_CVAR_VARIABLE_INTEGER_VALUE, // ( const char *var_name );
- G_ARGC, // ( void );
- // ClientCommand and ServerCommand parameter access
+ G_CVAR_VARIABLE_STRING_BUFFER, // ( const char *var_name, char *buffer, int bufsize );
- G_ARGV, // ( int n, char *buffer, int bufferLength );
+ G_ARGC, // ( void );
+ // ClientCommand and ServerCommand parameter access
- G_FS_FOPEN_FILE, // ( const char *qpath, fileHandle_t *file, fsMode_t mode );
- G_FS_READ, // ( void *buffer, int len, fileHandle_t f );
- G_FS_WRITE, // ( const void *buffer, int len, fileHandle_t f );
- G_FS_FCLOSE_FILE, // ( fileHandle_t f );
+ G_ARGV, // ( int n, char *buffer, int bufferLength );
- G_SEND_CONSOLE_COMMAND, // ( const char *text );
- // add commands to the console as if they were typed in
- // for map changing, etc
+ G_FS_FOPEN_FILE, // ( const char *qpath, fileHandle_t *file, enum FS_Mode mode );
+ G_FS_READ, // ( void *buffer, int len, fileHandle_t f );
+ G_FS_WRITE, // ( const void *buffer, int len, fileHandle_t f );
+ G_FS_FCLOSE_FILE, // ( fileHandle_t f );
+ G_SEND_CONSOLE_COMMAND, // ( const char *text );
+ // add commands to the console as if they were typed in
+ // for map changing, etc
- //=========== server specific functionality =============
+ //=========== server specific functionality =============
- G_LOCATE_GAME_DATA, // ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
- // playerState_t *clients, int sizeofGameClient );
- // the game needs to let the server system know where and how big the gentities
- // are, so it can look at them directly without going through an interface
+ G_LOCATE_GAME_DATA, // ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
+ // playerState_t *clients, int sizeofGameClient );
+ // the game needs to let the server system know where and how big the gentities
+ // are, so it can look at them directly without going through an interface
- G_DROP_CLIENT, // ( int clientNum, const char *reason );
- // kick a client off the server with a message
+ G_DROP_CLIENT, // ( int clientNum, const char *reason );
+ // kick a client off the server with a message
- G_SEND_SERVER_COMMAND, // ( int clientNum, const char *fmt, ... );
- // reliably sends a command string to be interpreted by the given
- // client. If clientNum is -1, it will be sent to all clients
+ G_SEND_SERVER_COMMAND, // ( int clientNum, const char *fmt, ... );
+ // reliably sends a command string to be interpreted by the given
+ // client. If clientNum is -1, it will be sent to all clients
- G_SET_CONFIGSTRING, // ( int num, const char *string );
- // config strings hold all the index strings, and various other information
- // that is reliably communicated to all clients
- // All of the current configstrings are sent to clients when
- // they connect, and changes are sent to all connected clients.
- // All confgstrings are cleared at each level start.
+ G_SET_CONFIGSTRING, // ( int num, const char *string );
+ // config strings hold all the index strings, and various other information
+ // that is reliably communicated to all clients
+ // All of the current configstrings are sent to clients when
+ // they connect, and changes are sent to all connected clients.
+ // All confgstrings are cleared at each level start.
- G_GET_CONFIGSTRING, // ( int num, char *buffer, int bufferSize );
+ G_GET_CONFIGSTRING, // ( int num, char *buffer, int bufferSize );
- G_SET_CONFIGSTRING_RESTRICTIONS, // ( int num, const clientList* clientList );
+ G_SET_CONFIGSTRING_RESTRICTIONS, // ( int num, const clientList* clientList );
- G_GET_USERINFO, // ( int num, char *buffer, int bufferSize );
- // userinfo strings are maintained by the server system, so they
- // are persistant across level loads, while all other game visible
- // data is completely reset
+ G_GET_USERINFO, // ( int num, char *buffer, int bufferSize );
+ // userinfo strings are maintained by the server system, so they
+ // are persistant across level loads, while all other game visible
+ // data is completely reset
- G_SET_USERINFO, // ( int num, const char *buffer );
+ G_SET_USERINFO, // ( int num, const char *buffer );
- G_GET_SERVERINFO, // ( char *buffer, int bufferSize );
- // the serverinfo info string has all the cvars visible to server browsers
+ G_GET_SERVERINFO, // ( char *buffer, int bufferSize );
+ // the serverinfo info string has all the cvars visible to server browsers
- G_SET_BRUSH_MODEL, // ( gentity_t *ent, const char *name );
- // sets mins and maxs based on the brushmodel name
+ G_SET_BRUSH_MODEL, // ( gentity_t *ent, const char *name );
+ // sets mins and maxs based on the brushmodel name
- G_TRACE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
- // collision detection against all linked entities
+ G_TRACE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int
+ // passEntityNum, int contentmask );
+ // collision detection against all linked entities
- G_POINT_CONTENTS, // ( const vec3_t point, int passEntityNum );
- // point contents against all linked entities
+ G_POINT_CONTENTS, // ( const vec3_t point, int passEntityNum );
+ // point contents against all linked entities
- G_IN_PVS, // ( const vec3_t p1, const vec3_t p2 );
+ G_IN_PVS, // ( const vec3_t p1, const vec3_t p2 );
- G_IN_PVS_IGNORE_PORTALS, // ( const vec3_t p1, const vec3_t p2 );
+ G_IN_PVS_IGNORE_PORTALS, // ( const vec3_t p1, const vec3_t p2 );
- G_ADJUST_AREA_PORTAL_STATE, // ( gentity_t *ent, qboolean open );
+ G_ADJUST_AREA_PORTAL_STATE, // ( gentity_t *ent, qboolean open );
- G_AREAS_CONNECTED, // ( int area1, int area2 );
+ G_AREAS_CONNECTED, // ( int area1, int area2 );
- G_LINKENTITY, // ( gentity_t *ent );
- // an entity will never be sent to a client or used for collision
- // if it is not passed to linkentity. If the size, position, or
- // solidity changes, it must be relinked.
+ G_LINKENTITY, // ( gentity_t *ent );
+ // an entity will never be sent to a client or used for collision
+ // if it is not passed to linkentity. If the size, position, or
+ // solidity changes, it must be relinked.
- G_UNLINKENTITY, // ( gentity_t *ent );
- // call before removing an interactive entity
+ G_UNLINKENTITY, // ( gentity_t *ent );
+ // call before removing an interactive entity
- G_ENTITIES_IN_BOX, // ( const vec3_t mins, const vec3_t maxs, gentity_t **list, int maxcount );
- // EntitiesInBox will return brush models based on their bounding box,
- // so exact determination must still be done with EntityContact
+ G_ENTITIES_IN_BOX, // ( const vec3_t mins, const vec3_t maxs, gentity_t **list, int maxcount );
+ // EntitiesInBox will return brush models based on their bounding box,
+ // so exact determination must still be done with EntityContact
- G_ENTITY_CONTACT, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
- // perform an exact check against inline brush models of non-square shape
+ G_ENTITY_CONTACT, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
+ // perform an exact check against inline brush models of non-square shape
- G_GET_USERCMD, // ( int clientNum, usercmd_t *cmd )
+ G_GET_USERCMD, // ( int clientNum, usercmd_t *cmd )
- G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize )
- // Retrieves the next string token from the entity spawn text, returning
- // false when all tokens have been parsed.
- // This should only be done at GAME_INIT time.
+ G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize )
+ // Retrieves the next string token from the entity spawn text, returning
+ // false when all tokens have been parsed.
+ // This should only be done at GAME_INIT time.
- G_FS_GETFILELIST,
- G_REAL_TIME,
- G_SNAPVECTOR,
+ G_FS_GETFILELIST,
+ G_REAL_TIME,
+ G_SNAPVECTOR,
- G_TRACECAPSULE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
- G_ENTITY_CONTACTCAPSULE, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
+ G_TRACECAPSULE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
+ // int passEntityNum, int contentmask );
+ G_ENTITY_CONTACTCAPSULE, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
- // 1.32
- G_FS_SEEK,
+ // 1.32
+ G_FS_SEEK,
- G_PARSE_ADD_GLOBAL_DEFINE,
- G_PARSE_LOAD_SOURCE,
- G_PARSE_FREE_SOURCE,
- G_PARSE_READ_TOKEN,
- G_PARSE_SOURCE_FILE_AND_LINE,
+ G_PARSE_ADD_GLOBAL_DEFINE,
+ G_PARSE_LOAD_SOURCE,
+ G_PARSE_FREE_SOURCE,
+ G_PARSE_READ_TOKEN,
+ G_PARSE_SOURCE_FILE_AND_LINE,
- G_SEND_GAMESTAT,
+ G_SEND_GAMESTAT,
- G_ADDCOMMAND,
- G_REMOVECOMMAND
+ G_ADDCOMMAND,
+ G_REMOVECOMMAND,
+ G_FS_GETFILTEREDFILES
} gameImport_t;
-
//
// functions exported by the game subsystem
//
typedef enum {
- GAME_INIT, // ( int levelTime, int randomSeed, int restart );
- // init and shutdown will be called every single level
- // The game should call G_GET_ENTITY_TOKEN to parse through all the
- // entity configuration text and spawn gentities.
+ GAME_INIT, // ( int levelTime, int randomSeed, int restart );
+ // init and shutdown will be called every single level
+ // The game should call G_GET_ENTITY_TOKEN to parse through all the
+ // entity configuration text and spawn gentities.
- GAME_SHUTDOWN, // (void);
+ GAME_SHUTDOWN, // (void);
- GAME_CLIENT_CONNECT, // ( int clientNum, qboolean firstTime );
- // return NULL if the client is allowed to connect, otherwise return
- // a text string with the reason for denial
+ GAME_CLIENT_CONNECT, // ( int clientNum, qboolean firstTime );
+ // return NULL if the client is allowed to connect, otherwise return
+ // a text string with the reason for denial
- GAME_CLIENT_BEGIN, // ( int clientNum );
+ GAME_CLIENT_BEGIN, // ( int clientNum );
- GAME_CLIENT_USERINFO_CHANGED, // ( int clientNum );
+ GAME_CLIENT_USERINFO_CHANGED, // ( int clientNum );
- GAME_CLIENT_DISCONNECT, // ( int clientNum );
+ GAME_CLIENT_DISCONNECT, // ( int clientNum );
- GAME_CLIENT_COMMAND, // ( int clientNum );
+ GAME_CLIENT_COMMAND, // ( int clientNum );
- GAME_CLIENT_THINK, // ( int clientNum );
+ GAME_CLIENT_THINK, // ( int clientNum );
- GAME_RUN_FRAME, // ( int levelTime );
+ GAME_RUN_FRAME, // ( int levelTime );
- GAME_CONSOLE_COMMAND // ( void );
- // ConsoleCommand will be called when a command has been issued
- // that is not recognized as a builtin function.
- // The game can issue trap_argc() / trap_argv() commands to get the command
- // and parameters. Return qfalse if the game doesn't recognize it as a command.
+ GAME_CONSOLE_COMMAND // ( void );
+ // ConsoleCommand will be called when a command has been issued
+ // that is not recognized as a builtin function.
+ // The game can issue trap_argc() / trap_argv() commands to get the command
+ // and parameters. Return qfalse if the game doesn't recognize it as a command.
} gameExport_t;
+#endif
diff --git a/src/game/g_session.c b/src/game/g_session.c
index ef78e8a..9063ce1 100644
--- a/src/game/g_session.c
+++ b/src/game/g_session.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -46,20 +47,15 @@ void G_WriteClientSessionData( gclient_t *client )
const char *s;
const char *var;
- s = va( "%i %i %i %i %i %i %i %i %i %s",
- client->sess.sessionTeam,
- client->sess.restartTeam,
+ s = va( "%i %i %i %i %s",
client->sess.spectatorTime,
client->sess.spectatorState,
client->sess.spectatorClient,
- client->sess.wins,
- client->sess.losses,
- client->sess.teamLeader,
- client->sess.invisible,
- BG_ClientListString( &client->sess.ignoreList )
+ client->sess.restartTeam,
+ Com_ClientListString( &client->sess.ignoreList )
);
- var = va( "session%i", client - level.clients );
+ var = va( "session%i", (int)( client - level.clients ) );
trap_Cvar_Set( var, s );
}
@@ -73,40 +69,26 @@ Called on a reconnect
*/
void G_ReadSessionData( gclient_t *client )
{
- char s[ MAX_STRING_CHARS ];
+ char s[ MAX_STRING_CHARS ];
const char *var;
+ int spectatorState;
+ int restartTeam;
+ char ignorelist[ 17 ];
- // bk001205 - format
- int teamLeader;
- int spectatorState;
- int sessionTeam;
- int restartTeam;
- int invisible;
-
- var = va( "session%i", client - level.clients );
+ var = va( "session%i", (int)( client - level.clients ) );
trap_Cvar_VariableStringBuffer( var, s, sizeof(s) );
- // FIXME: should be using BG_ClientListParse() for ignoreList, but
- // bg_lib.c's sscanf() currently lacks %s
- sscanf( s, "%i %i %i %i %i %i %i %i %i %x%x",
- &sessionTeam,
- &restartTeam,
+ sscanf( s, "%i %i %i %i %16s",
&client->sess.spectatorTime,
&spectatorState,
&client->sess.spectatorClient,
- &client->sess.wins,
- &client->sess.losses,
- &teamLeader,
- &invisible,
- &client->sess.ignoreList.hi,
- &client->sess.ignoreList.lo
+ &restartTeam,
+ ignorelist
);
- // bk001205 - format issues
- client->sess.sessionTeam = (team_t)sessionTeam;
- client->sess.restartTeam = (pTeam_t)restartTeam;
+
client->sess.spectatorState = (spectatorState_t)spectatorState;
- client->sess.teamLeader = (qboolean)teamLeader;
- client->sess.invisible = (qboolean)invisible;
+ client->sess.restartTeam = (team_t)restartTeam;
+ Com_ClientListParse( &client->sess.ignoreList, ignorelist );
}
@@ -129,18 +111,18 @@ void G_InitSessionData( gclient_t *client, char *userinfo )
if( value[ 0 ] == 's' )
{
// a willing spectator, not a waiting-in-line
- sess->sessionTeam = TEAM_SPECTATOR;
+ sess->spectatorState = SPECTATOR_FREE;
}
else
{
if( g_maxGameClients.integer > 0 &&
level.numNonSpectatorClients >= g_maxGameClients.integer )
- sess->sessionTeam = TEAM_SPECTATOR;
+ sess->spectatorState = SPECTATOR_FREE;
else
- sess->sessionTeam = TEAM_FREE;
+ sess->spectatorState = SPECTATOR_NOT;
}
- sess->restartTeam = PTE_NONE;
+ sess->restartTeam = TEAM_NONE;
sess->spectatorState = SPECTATOR_FREE;
sess->spectatorTime = level.time;
sess->spectatorClient = -1;
@@ -160,7 +142,7 @@ void G_WriteSessionData( void )
{
int i;
- //TA: ?
+ //FIXME: What's this for?
trap_Cvar_Set( "session", va( "%i", 0 ) );
for( i = 0 ; i < level.maxclients ; i++ )
diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c
index 028c39f..f7eea93 100644
--- a/src/game/g_spawn.c
+++ b/src/game/g_spawn.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -31,6 +32,7 @@ qboolean G_SpawnString( const char *key, const char *defaultString, char **out )
{
*out = (char *)defaultString;
// G_Error( "G_SpawnString() called while not spawning" );
+ return qfalse;
}
for( i = 0; i < level.numSpawnVars; i++ )
@@ -95,55 +97,45 @@ typedef enum
{
F_INT,
F_FLOAT,
- F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
- F_GSTRING, // string on disk, pointer in memory, TAG_GAME
+ F_STRING,
F_VECTOR,
- F_VECTOR4, //TA
- F_ANGLEHACK,
- F_ENTITY, // index on disk, pointer in memory
- F_ITEM, // index on disk, pointer in memory
- F_CLIENT, // index on disk, pointer in memory
- F_IGNORE
+ F_VECTOR4,
+ F_ANGLEHACK
} fieldtype_t;
typedef struct
{
char *name;
- int ofs;
+ size_t ofs;
fieldtype_t type;
- int flags;
} field_t;
field_t fields[ ] =
{
- {"classname", FOFS(classname), F_LSTRING},
- {"origin", FOFS(s.origin), F_VECTOR},
- {"model", FOFS(model), F_LSTRING},
- {"model2", FOFS(model2), F_LSTRING},
- {"spawnflags", FOFS(spawnflags), F_INT},
- {"speed", FOFS(speed), F_FLOAT},
- {"target", FOFS(target), F_LSTRING},
- {"targetname", FOFS(targetname), F_LSTRING},
- {"message", FOFS(message), F_LSTRING},
- {"team", FOFS(team), F_LSTRING},
- {"wait", FOFS(wait), F_FLOAT},
- {"random", FOFS(random), F_FLOAT},
+ {"acceleration", FOFS(acceleration), F_VECTOR},
+ {"alpha", FOFS(pos1), F_VECTOR},
+ {"angle", FOFS(s.apos.trBase), F_ANGLEHACK},
+ {"angles", FOFS(s.apos.trBase), F_VECTOR},
+ {"animation", FOFS(animation), F_VECTOR4},
+ {"bounce", FOFS(physicsBounce), F_FLOAT},
+ {"classname", FOFS(classname), F_STRING},
{"count", FOFS(count), F_INT},
- {"health", FOFS(health), F_INT},
- {"light", 0, F_IGNORE},
{"dmg", FOFS(damage), F_INT},
- {"angles", FOFS(s.angles), F_VECTOR},
- {"angle", FOFS(s.angles), F_ANGLEHACK},
- {"bounce", FOFS(physicsBounce), F_FLOAT},
- {"alpha", FOFS(pos1), F_VECTOR},
+ {"health", FOFS(health), F_INT},
+ {"message", FOFS(message), F_STRING},
+ {"model", FOFS(model), F_STRING},
+ {"model2", FOFS(model2), F_STRING},
+ {"origin", FOFS(s.pos.trBase), F_VECTOR},
{"radius", FOFS(pos2), F_VECTOR},
- {"acceleration", FOFS(acceleration), F_VECTOR},
- {"animation", FOFS(animation), F_VECTOR4},
+ {"random", FOFS(random), F_FLOAT},
{"rotatorAngle", FOFS(rotatorAngle), F_FLOAT},
- {"targetShaderName", FOFS(targetShaderName), F_LSTRING},
- {"targetShaderNewName", FOFS(targetShaderNewName), F_LSTRING},
-
- {NULL}
+ {"spawnflags", FOFS(spawnflags), F_INT},
+ {"speed", FOFS(speed), F_FLOAT},
+ {"target", FOFS(target), F_STRING},
+ {"targetname", FOFS(targetname), F_STRING},
+ {"targetShaderName", FOFS(targetShaderName), F_STRING},
+ {"targetShaderNewName", FOFS(targetShaderNewName), F_STRING},
+ {"wait", FOFS(wait), F_FLOAT}
};
@@ -160,11 +152,6 @@ void SP_info_player_intermission( gentity_t *ent );
void SP_info_alien_intermission( gentity_t *ent );
void SP_info_human_intermission( gentity_t *ent );
-void SP_info_firstplace( gentity_t *ent );
-void SP_info_secondplace( gentity_t *ent );
-void SP_info_thirdplace( gentity_t *ent );
-void SP_info_podium( gentity_t *ent );
-
void SP_func_plat( gentity_t *ent );
void SP_func_static( gentity_t *ent );
void SP_func_rotating( gentity_t *ent );
@@ -194,7 +181,6 @@ void SP_trigger_ammo( gentity_t *ent );
void SP_target_delay( gentity_t *ent );
void SP_target_speaker( gentity_t *ent );
void SP_target_print( gentity_t *ent );
-void SP_target_character( gentity_t *ent );
void SP_target_score( gentity_t *ent );
void SP_target_teleporter( gentity_t *ent );
void SP_target_relay( gentity_t *ent );
@@ -210,7 +196,6 @@ void SP_target_hurt( gentity_t *ent );
void SP_light( gentity_t *self );
void SP_info_null( gentity_t *self );
void SP_info_notnull( gentity_t *self );
-void SP_info_camp( gentity_t *self );
void SP_path_corner( gentity_t *self );
void SP_misc_teleporter_dest( gentity_t *self );
@@ -218,41 +203,60 @@ void SP_misc_model( gentity_t *ent );
void SP_misc_portal_camera( gentity_t *ent );
void SP_misc_portal_surface( gentity_t *ent );
-void SP_shooter_rocket( gentity_t *ent );
-void SP_shooter_plasma( gentity_t *ent );
-void SP_shooter_grenade( gentity_t *ent );
-
void SP_misc_particle_system( gentity_t *ent );
void SP_misc_anim_model( gentity_t *ent );
void SP_misc_light_flare( gentity_t *ent );
spawn_t spawns[ ] =
{
+ { "func_bobbing", SP_func_bobbing },
+ { "func_button", SP_func_button },
+ { "func_door", SP_func_door },
+ { "func_door_model", SP_func_door_model },
+ { "func_door_rotating", SP_func_door_rotating },
+ { "func_group", SP_info_null },
+ { "func_pendulum", SP_func_pendulum },
+ { "func_plat", SP_func_plat },
+ { "func_rotating", SP_func_rotating },
+ { "func_static", SP_func_static },
+ { "func_timer", SP_func_timer }, // rename trigger_timer?
+ { "func_train", SP_func_train },
+
// info entities don't do anything at all, but provide positional
// information for things controlled by other processes
- { "info_player_start", SP_info_player_start },
- { "info_player_deathmatch", SP_info_player_deathmatch },
- { "info_player_intermission", SP_info_player_intermission },
-
- //TA: extra bits
{ "info_alien_intermission", SP_info_alien_intermission },
{ "info_human_intermission", SP_info_human_intermission },
-
- { "info_null", SP_info_null },
{ "info_notnull", SP_info_notnull }, // use target_position instead
+ { "info_null", SP_info_null },
+ { "info_player_deathmatch", SP_info_player_deathmatch },
+ { "info_player_intermission", SP_info_player_intermission },
+ { "info_player_start", SP_info_player_start },
+ { "light", SP_light },
+ { "misc_anim_model", SP_misc_anim_model },
+ { "misc_light_flare", SP_misc_light_flare },
+ { "misc_model", SP_misc_model },
+ { "misc_particle_system", SP_misc_particle_system },
+ { "misc_portal_camera", SP_misc_portal_camera },
+ { "misc_portal_surface", SP_misc_portal_surface },
+ { "misc_teleporter_dest", SP_misc_teleporter_dest },
+ { "path_corner", SP_path_corner },
- { "func_plat", SP_func_plat },
- { "func_button", SP_func_button },
- { "func_door", SP_func_door },
- { "func_door_rotating", SP_func_door_rotating }, //TA
- { "func_door_model", SP_func_door_model }, //TA
- { "func_static", SP_func_static },
- { "func_rotating", SP_func_rotating },
- { "func_bobbing", SP_func_bobbing },
- { "func_pendulum", SP_func_pendulum },
- { "func_train", SP_func_train },
- { "func_group", SP_info_null },
- { "func_timer", SP_func_timer }, // rename trigger_timer?
+ // targets perform no action by themselves, but must be triggered
+ // by another entity
+ { "target_alien_win", SP_target_alien_win },
+ { "target_delay", SP_target_delay },
+ { "target_human_win", SP_target_human_win },
+ { "target_hurt", SP_target_hurt },
+ { "target_kill", SP_target_kill },
+ { "target_location", SP_target_location },
+ { "target_position", SP_target_position },
+ { "target_print", SP_target_print },
+ { "target_push", SP_target_push },
+ { "target_relay", SP_target_relay },
+ { "target_rumble", SP_target_rumble },
+ { "target_score", SP_target_score },
+ { "target_speaker", SP_target_speaker },
+ { "target_teleporter", SP_target_teleporter },
// Triggers are brush objects that cause an effect when contacted
// by a living player, usually involving firing targets.
@@ -260,49 +264,18 @@ spawn_t spawns[ ] =
// a single trigger class and different targets, triggered effects
// could not be client side predicted (push and teleport).
{ "trigger_always", SP_trigger_always },
- { "trigger_multiple", SP_trigger_multiple },
- { "trigger_push", SP_trigger_push },
- { "trigger_teleport", SP_trigger_teleport },
- { "trigger_hurt", SP_trigger_hurt },
- { "trigger_stage", SP_trigger_stage },
- { "trigger_win", SP_trigger_win },
+ { "trigger_ammo", SP_trigger_ammo },
{ "trigger_buildable", SP_trigger_buildable },
{ "trigger_class", SP_trigger_class },
{ "trigger_equipment", SP_trigger_equipment },
{ "trigger_gravity", SP_trigger_gravity },
{ "trigger_heal", SP_trigger_heal },
- { "trigger_ammo", SP_trigger_ammo },
-
- // targets perform no action by themselves, but must be triggered
- // by another entity
- { "target_delay", SP_target_delay },
- { "target_speaker", SP_target_speaker },
- { "target_print", SP_target_print },
- { "target_score", SP_target_score },
- { "target_teleporter", SP_target_teleporter },
- { "target_relay", SP_target_relay },
- { "target_kill", SP_target_kill },
- { "target_position", SP_target_position },
- { "target_location", SP_target_location },
- { "target_push", SP_target_push },
- { "target_rumble", SP_target_rumble },
- { "target_alien_win", SP_target_alien_win },
- { "target_human_win", SP_target_human_win },
- { "target_hurt", SP_target_hurt },
-
- { "light", SP_light },
- { "path_corner", SP_path_corner },
-
- { "misc_teleporter_dest", SP_misc_teleporter_dest },
- { "misc_model", SP_misc_model },
- { "misc_portal_surface", SP_misc_portal_surface },
- { "misc_portal_camera", SP_misc_portal_camera },
-
- { "misc_particle_system", SP_misc_particle_system },
- { "misc_anim_model", SP_misc_anim_model },
- { "misc_light_flare", SP_misc_light_flare },
-
- { NULL, 0 }
+ { "trigger_hurt", SP_trigger_hurt },
+ { "trigger_multiple", SP_trigger_multiple },
+ { "trigger_push", SP_trigger_push },
+ { "trigger_stage", SP_trigger_stage },
+ { "trigger_teleport", SP_trigger_teleport },
+ { "trigger_win", SP_trigger_win }
};
/*
@@ -325,16 +298,18 @@ qboolean G_CallSpawn( gentity_t *ent )
}
//check buildable spawn functions
- if( ( buildable = BG_FindBuildNumForEntityName( ent->classname ) ) != BA_NONE )
+ buildable = BG_BuildableByEntityName( ent->classname )->number;
+ if( buildable != BA_NONE )
{
// don't spawn built-in buildings if we are using a custom layout
if( level.layout[ 0 ] && Q_stricmp( level.layout, "*BUILTIN*" ) )
- return qtrue;
+ return qfalse;
if( buildable == BA_A_SPAWN || buildable == BA_H_SPAWN )
{
- ent->s.angles[ YAW ] += 180.0f;
- AngleNormalize360( ent->s.angles[ YAW ] );
+ ent->r.currentAngles[ YAW ] += 180.0f;
+ AngleNormalize360( ent->r.currentAngles[ YAW ] );
+ ent->s.apos.trBase[ YAW ] = ent->r.currentAngles[ YAW ];
}
G_SpawnBuildable( ent, buildable );
@@ -342,14 +317,13 @@ qboolean G_CallSpawn( gentity_t *ent )
}
// check normal spawn functions
- for( s = spawns; s->name; s++ )
+ s = bsearch( ent->classname, spawns, ARRAY_LEN( spawns ),
+ sizeof( spawn_t ), cmdcmp );
+ if( s )
{
- if( !strcmp( s->name, ent->classname ) )
- {
- // found it
- s->spawn( ent );
- return qtrue;
- }
+ // found it
+ s->spawn( ent );
+ return qtrue;
}
G_Printf( "%s doesn't have a spawn function\n", ent->classname );
@@ -371,7 +345,7 @@ char *G_NewString( const char *string )
l = strlen( string ) + 1;
- newb = G_Alloc( l );
+ newb = BG_Alloc( l );
new_p = newb;
@@ -412,58 +386,49 @@ void G_ParseField( const char *key, const char *value, gentity_t *ent )
vec3_t vec;
vec4_t vec4;
- for( f = fields; f->name; f++ )
+ f = bsearch( key, fields, ARRAY_LEN( fields ),
+ sizeof( field_t ), cmdcmp );
+ if( !f )
+ return;
+ b = (byte *)ent;
+
+ switch( f->type )
{
- if( !Q_stricmp( f->name, key ) )
- {
- // found it
- b = (byte *)ent;
-
- switch( f->type )
- {
- case F_LSTRING:
- *(char **)( b + f->ofs ) = G_NewString( value );
- break;
-
- case F_VECTOR:
- sscanf( value, "%f %f %f", &vec[ 0 ], &vec[ 1 ], &vec[ 2 ] );
-
- ( (float *)( b + f->ofs ) )[ 0 ] = vec[ 0 ];
- ( (float *)( b + f->ofs ) )[ 1 ] = vec[ 1 ];
- ( (float *)( b + f->ofs ) )[ 2 ] = vec[ 2 ];
- break;
-
- case F_VECTOR4:
- sscanf( value, "%f %f %f %f", &vec4[ 0 ], &vec4[ 1 ], &vec4[ 2 ], &vec4[ 3 ] );
-
- ( (float *)( b + f->ofs ) )[ 0 ] = vec4[ 0 ];
- ( (float *)( b + f->ofs ) )[ 1 ] = vec4[ 1 ];
- ( (float *)( b + f->ofs ) )[ 2 ] = vec4[ 2 ];
- ( (float *)( b + f->ofs ) )[ 3 ] = vec4[ 3 ];
- break;
-
- case F_INT:
- *(int *)( b + f->ofs ) = atoi( value );
- break;
-
- case F_FLOAT:
- *(float *)( b + f->ofs ) = atof( value );
- break;
-
- case F_ANGLEHACK:
- v = atof( value );
- ( (float *)( b + f->ofs ) )[ 0 ] = 0;
- ( (float *)( b + f->ofs ) )[ 1 ] = v;
- ( (float *)( b + f->ofs ) )[ 2 ] = 0;
- break;
-
- default:
- case F_IGNORE:
- break;
- }
-
- return;
- }
+ case F_STRING:
+ *(char **)( b + f->ofs ) = G_NewString( value );
+ break;
+
+ case F_VECTOR:
+ sscanf( value, "%f %f %f", &vec[ 0 ], &vec[ 1 ], &vec[ 2 ] );
+
+ ( (float *)( b + f->ofs ) )[ 0 ] = vec[ 0 ];
+ ( (float *)( b + f->ofs ) )[ 1 ] = vec[ 1 ];
+ ( (float *)( b + f->ofs ) )[ 2 ] = vec[ 2 ];
+ break;
+
+ case F_VECTOR4:
+ sscanf( value, "%f %f %f %f", &vec4[ 0 ], &vec4[ 1 ], &vec4[ 2 ], &vec4[ 3 ] );
+
+ ( (float *)( b + f->ofs ) )[ 0 ] = vec4[ 0 ];
+ ( (float *)( b + f->ofs ) )[ 1 ] = vec4[ 1 ];
+ ( (float *)( b + f->ofs ) )[ 2 ] = vec4[ 2 ];
+ ( (float *)( b + f->ofs ) )[ 3 ] = vec4[ 3 ];
+ break;
+
+ case F_INT:
+ *(int *)( b + f->ofs ) = atoi( value );
+ break;
+
+ case F_FLOAT:
+ *(float *)( b + f->ofs ) = atof( value );
+ break;
+
+ case F_ANGLEHACK:
+ v = atof( value );
+ ( (float *)( b + f->ofs ) )[ 0 ] = 0;
+ ( (float *)( b + f->ofs ) )[ 1 ] = v;
+ ( (float *)( b + f->ofs ) )[ 2 ] = 0;
+ break;
}
}
@@ -497,9 +462,8 @@ void G_SpawnGEntityFromSpawnVars( void )
return;
}
- // move editor origin to pos
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
+ VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );
+ VectorCopy( ent->s.apos.trBase, ent->r.currentAngles );
// if we didn't get a classname, don't bother spawning anything
if( !G_CallSpawn( ent ) )
@@ -617,38 +581,23 @@ void SP_worldspawn( void )
trap_SetConfigstring( CS_MOTD, g_motd.string ); // message of the day
- G_SpawnString( "gravity", "800", &s );
- trap_Cvar_Set( "g_gravity", s );
-
- G_SpawnString( "humanBuildPoints", DEFAULT_HUMAN_BUILDPOINTS, &s );
- trap_Cvar_Set( "g_humanBuildPoints", s );
-
- G_SpawnString( "humanMaxStage", DEFAULT_HUMAN_MAX_STAGE, &s );
- trap_Cvar_Set( "g_humanMaxStage", s );
+ if( G_SpawnString( "gravity", "", &s ) )
+ trap_Cvar_Set( "g_gravity", s );
- G_SpawnString( "humanStage2Threshold", DEFAULT_HUMAN_STAGE2_THRESH, &s );
- trap_Cvar_Set( "g_humanStage2Threshold", s );
+ if( G_SpawnString( "humanMaxStage", "", &s ) )
+ trap_Cvar_Set( "g_humanMaxStage", s );
- G_SpawnString( "humanStage3Threshold", DEFAULT_HUMAN_STAGE3_THRESH, &s );
- trap_Cvar_Set( "g_humanStage3Threshold", s );
+ if( G_SpawnString( "alienMaxStage", "", &s ) )
+ trap_Cvar_Set( "g_alienMaxStage", s );
- G_SpawnString( "alienBuildPoints", DEFAULT_ALIEN_BUILDPOINTS, &s );
- trap_Cvar_Set( "g_alienBuildPoints", s );
+ if( G_SpawnString( "humanRepeaterBuildPoints", "", &s ) )
+ trap_Cvar_Set( "g_humanRepeaterBuildPoints", s );
- G_SpawnString( "alienMaxStage", DEFAULT_ALIEN_MAX_STAGE, &s );
- trap_Cvar_Set( "g_alienMaxStage", s );
+ if( G_SpawnString( "humanBuildPoints", "", &s ) )
+ trap_Cvar_Set( "g_humanBuildPoints", s );
- G_SpawnString( "alienStage2Threshold", DEFAULT_ALIEN_STAGE2_THRESH, &s );
- trap_Cvar_Set( "g_alienStage2Threshold", s );
-
- G_SpawnString( "alienStage3Threshold", DEFAULT_ALIEN_STAGE3_THRESH, &s );
- trap_Cvar_Set( "g_alienStage3Threshold", s );
-
- G_SpawnString( "enableDust", "0", &s );
- trap_Cvar_Set( "g_enableDust", s );
-
- G_SpawnString( "enableBreath", "0", &s );
- trap_Cvar_Set( "g_enableBreath", s );
+ if( G_SpawnString( "alienBuildPoints", "", &s ) )
+ trap_Cvar_Set( "g_alienBuildPoints", s );
G_SpawnString( "disabledEquipment", "", &s );
trap_Cvar_Set( "g_disabledEquipment", s );
@@ -660,11 +609,25 @@ void SP_worldspawn( void )
trap_Cvar_Set( "g_disabledBuildables", s );
g_entities[ ENTITYNUM_WORLD ].s.number = ENTITYNUM_WORLD;
+ g_entities[ ENTITYNUM_WORLD ].r.ownerNum = ENTITYNUM_NONE;
g_entities[ ENTITYNUM_WORLD ].classname = "worldspawn";
+ g_entities[ ENTITYNUM_NONE ].s.number = ENTITYNUM_NONE;
+ g_entities[ ENTITYNUM_NONE ].r.ownerNum = ENTITYNUM_NONE;
+ g_entities[ ENTITYNUM_NONE ].classname = "nothing";
+
if( g_restarted.integer )
trap_Cvar_Set( "g_restarted", "0" );
+ // see if we want a warmup time
+ trap_SetConfigstring( CS_WARMUP, "-1" );
+ if( g_doWarmup.integer )
+ {
+ level.warmupTime = level.time - level.startTime + ( g_warmup.integer * 1000 );
+ trap_SetConfigstring( CS_WARMUP, va( "%i", level.warmupTime ) );
+ G_LogPrintf( "Warmup: %i\n", g_warmup.integer );
+ }
+
}
@@ -677,8 +640,6 @@ Parses textual entity definitions out of an entstring and spawns gentities.
*/
void G_SpawnEntitiesFromString( void )
{
- // allow calls to G_Spawn*()
- level.spawning = qtrue;
level.numSpawnVars = 0;
// the worldspawn is not an actual entity, but it still
@@ -692,7 +653,4 @@ void G_SpawnEntitiesFromString( void )
// parse ents
while( G_ParseSpawnVars( ) )
G_SpawnGEntityFromSpawnVars( );
-
- level.spawning = qfalse; // any future calls to G_Spawn*() will be errors
}
-
diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c
index f0d45b1..3760fdd 100644
--- a/src/game/g_svcmds.c
+++ b/src/game/g_svcmds.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -25,315 +26,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "g_local.h"
-
-/*
-==============================================================================
-
-PACKET FILTERING
-
-
-You can add or remove addresses from the filter list with:
-
-addip <ip>
-removeip <ip>
-
-The ip address is specified in dot format, and you can use '*' to match any value
-so you can specify an entire class C network with "addip 192.246.40.*"
-
-Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host.
-
-listip
-Prints the current list of filters.
-
-g_filterban <0 or 1>
-
-If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting.
-
-If 0, then only addresses matching the list will be allowed. This lets you easily set up a private game, or a game that only allows players from your local network.
-
-TTimo NOTE: for persistence, bans are stored in g_banIPs cvar MAX_CVAR_VALUE_STRING
-The size of the cvar string buffer is limiting the banning to around 20 masks
-this could be improved by putting some g_banIPs2 g_banIps3 etc. maybe
-still, you should rely on PB for banning instead
-
-==============================================================================
-*/
-
-// extern vmCvar_t g_banIPs;
-// extern vmCvar_t g_filterBan;
-
-
-typedef struct ipFilter_s
-{
- unsigned mask;
- unsigned compare;
-} ipFilter_t;
-
-#define MAX_IPFILTERS 1024
-
-static ipFilter_t ipFilters[ MAX_IPFILTERS ];
-static int numIPFilters;
-
-/*
-=================
-StringToFilter
-=================
-*/
-static qboolean StringToFilter( char *s, ipFilter_t *f )
-{
- char num[ 128 ];
- int i, j;
- byte b[ 4 ];
- byte m[ 4 ];
-
- for( i = 0; i < 4; i++ )
- {
- b[ i ] = 0;
- m[ i ] = 0;
- }
-
- for( i = 0; i < 4; i++ )
- {
- if( *s < '0' || *s > '9' )
- {
- if( *s == '*' ) // 'match any'
- {
- //b[ i ] and m[ i ] to 0
- s++;
- if ( !*s )
- break;
-
- s++;
- continue;
- }
-
- G_Printf( "Bad filter address: %s\n", s );
- return qfalse;
- }
-
- j = 0;
- while( *s >= '0' && *s <= '9' )
- num[ j++ ] = *s++;
-
- num[ j ] = 0;
- b[ i ] = atoi( num );
-
- m[ i ] = 255;
-
- if( !*s )
- break;
-
- s++;
- }
-
- f->mask = *(unsigned *)m;
- f->compare = *(unsigned *)b;
-
- return qtrue;
-}
-
-/*
-=================
-UpdateIPBans
-=================
-*/
-static void UpdateIPBans( void )
-{
- byte b[ 4 ];
- byte m[ 4 ];
- int i, j;
- char iplist_final[ MAX_CVAR_VALUE_STRING ];
- char ip[ 64 ];
-
- *iplist_final = 0;
-
- for( i = 0 ; i < numIPFilters ; i++ )
- {
- if( ipFilters[ i ].compare == 0xffffffff )
- continue;
-
- *(unsigned *)b = ipFilters[ i ].compare;
- *(unsigned *)m = ipFilters[ i ].mask;
- *ip = 0;
-
- for( j = 0 ; j < 4 ; j++ )
- {
- if( m[ j ] != 255 )
- Q_strcat( ip, sizeof( ip ), "*" );
- else
- Q_strcat( ip, sizeof( ip ), va( "%i", b[ j ] ) );
-
- Q_strcat( ip, sizeof( ip ), ( j < 3 ) ? "." : " " );
- }
-
- if( strlen( iplist_final ) + strlen( ip ) < MAX_CVAR_VALUE_STRING )
- Q_strcat( iplist_final, sizeof( iplist_final ), ip );
- else
- {
- Com_Printf( "g_banIPs overflowed at MAX_CVAR_VALUE_STRING\n" );
- break;
- }
- }
-
- trap_Cvar_Set( "g_banIPs", iplist_final );
-}
-
-/*
-=================
-G_FilterPacket
-=================
-*/
-qboolean G_FilterPacket( char *from )
-{
- int i;
- unsigned in;
- byte m[ 4 ];
- char *p;
-
- i = 0;
- p = from;
- while( *p && i < 4 )
- {
- m[ i ] = 0;
- while( *p >= '0' && *p <= '9' )
- {
- m[ i ] = m[ i ] * 10 + ( *p - '0' );
- p++;
- }
-
- if( !*p || *p == ':' )
- break;
-
- i++, p++;
- }
-
- in = *(unsigned *)m;
-
- for( i = 0; i < numIPFilters; i++ )
- if( ( in & ipFilters[ i ].mask ) == ipFilters[ i ].compare )
- return g_filterBan.integer != 0;
-
- return g_filterBan.integer == 0;
-}
-
-/*
-=================
-AddIP
-=================
-*/
-static void AddIP( char *str )
-{
- int i;
-
- for( i = 0 ; i < numIPFilters ; i++ )
- if( ipFilters[ i ].compare == 0xffffffff )
- break; // free spot
-
- if( i == numIPFilters )
- {
- if( numIPFilters == MAX_IPFILTERS )
- {
- G_Printf( "IP filter list is full\n" );
- return;
- }
-
- numIPFilters++;
- }
-
- if( !StringToFilter( str, &ipFilters[ i ] ) )
- ipFilters[ i ].compare = 0xffffffffu;
-
- UpdateIPBans( );
-}
-
-/*
-=================
-G_ProcessIPBans
-=================
-*/
-void G_ProcessIPBans( void )
-{
- char *s, *t;
- char str[ MAX_CVAR_VALUE_STRING ];
-
- Q_strncpyz( str, g_banIPs.string, sizeof( str ) );
-
- for( t = s = g_banIPs.string; *t; /* */ )
- {
- s = strchr( s, ' ' );
-
- if( !s )
- break;
-
- while( *s == ' ' )
- *s++ = 0;
-
- if( *t )
- AddIP( t );
-
- t = s;
- }
-}
-
-
-/*
-=================
-Svcmd_AddIP_f
-=================
-*/
-void Svcmd_AddIP_f( void )
-{
- char str[ MAX_TOKEN_CHARS ];
-
- if( trap_Argc( ) < 2 )
- {
- G_Printf( "Usage: addip <ip-mask>\n" );
- return;
- }
-
- trap_Argv( 1, str, sizeof( str ) );
-
- AddIP( str );
-}
-
-/*
-=================
-Svcmd_RemoveIP_f
-=================
-*/
-void Svcmd_RemoveIP_f( void )
-{
- ipFilter_t f;
- int i;
- char str[ MAX_TOKEN_CHARS ];
-
- if( trap_Argc( ) < 2 )
- {
- G_Printf( "Usage: sv removeip <ip-mask>\n" );
- return;
- }
-
- trap_Argv( 1, str, sizeof( str ) );
-
- if( !StringToFilter( str, &f ) )
- return;
-
- for( i = 0; i < numIPFilters; i++ )
- {
- if( ipFilters[ i ].mask == f.mask &&
- ipFilters[ i ].compare == f.compare)
- {
- ipFilters[ i ].compare = 0xffffffffu;
- G_Printf ( "Removed.\n" );
-
- UpdateIPBans( );
- return;
- }
- }
-
- G_Printf ( "Didn't find %s.\n", str );
-}
-
/*
===================
Svcmd_EntityList_f
@@ -367,6 +59,12 @@ void Svcmd_EntityList_f( void )
case ET_BUILDABLE:
G_Printf( "ET_BUILDABLE " );
break;
+ case ET_RANGE_MARKER:
+ G_Printf( "ET_RANGE_MARKER " );
+ break;
+ case ET_LOCATION:
+ G_Printf( "ET_LOCATION " );
+ break;
case ET_MISSILE:
G_Printf( "ET_MISSILE " );
break;
@@ -394,8 +92,26 @@ void Svcmd_EntityList_f( void )
case ET_GRAPPLE:
G_Printf( "ET_GRAPPLE " );
break;
+ case ET_CORPSE:
+ G_Printf( "ET_CORPSE " );
+ break;
+ case ET_PARTICLE_SYSTEM:
+ G_Printf( "ET_PARTICLE_SYSTEM " );
+ break;
+ case ET_ANIMMAPOBJ:
+ G_Printf( "ET_ANIMMAPOBJ " );
+ break;
+ case ET_MODELDOOR:
+ G_Printf( "ET_MODELDOOR " );
+ break;
+ case ET_LIGHTFLARE:
+ G_Printf( "ET_LIGHTFLARE " );
+ break;
+ case ET_LEV2_ZAP_CHAIN:
+ G_Printf( "ET_LEV2_ZAP_CHAIN " );
+ break;
default:
- G_Printf( "%3i ", check->s.eType );
+ G_Printf( "%-3i ", check->s.eType );
break;
}
@@ -406,48 +122,52 @@ void Svcmd_EntityList_f( void )
}
}
-gclient_t *ClientForString( const char *s )
+static gclient_t *ClientForString( char *s )
{
- gclient_t *cl;
- int i;
- int idnum;
+ int idnum;
+ char err[ MAX_STRING_CHARS ];
- // numeric values are just slot numbers
- if( s[ 0 ] >= '0' && s[ 0 ] <= '9' )
+ idnum = G_ClientNumberFromString( s, err, sizeof( err ) );
+ if( idnum == -1 )
{
- idnum = atoi( s );
-
- if( idnum < 0 || idnum >= level.maxclients )
- {
- Com_Printf( "Bad client slot: %i\n", idnum );
- return NULL;
- }
-
- cl = &level.clients[ idnum ];
+ G_Printf( "%s", err );
+ return NULL;
+ }
- if( cl->pers.connected == CON_DISCONNECTED )
- {
- G_Printf( "Client %i is not connected\n", idnum );
- return NULL;
- }
+ return &level.clients[ idnum ];
+}
- return cl;
- }
+static void Svcmd_Status_f( void )
+{
+ int i;
+ gclient_t *cl;
+ char userinfo[ MAX_INFO_STRING ];
- // check for a name match
- for( i = 0; i < level.maxclients; i++ )
+ G_Printf( "slot score ping address rate name\n" );
+ G_Printf( "---- ----- ---- ------- ---- ----\n" );
+ for( i = 0, cl = level.clients; i < level.maxclients; i++, cl++ )
{
- cl = &level.clients[ i ];
if( cl->pers.connected == CON_DISCONNECTED )
continue;
- if( !Q_stricmp( cl->pers.netname, s ) )
- return cl;
- }
+ G_Printf( "%-4d ", i );
+ G_Printf( "%-5d ", cl->ps.persistant[ PERS_SCORE ] );
- G_Printf( "User %s is not on the server\n", s );
+ if( cl->pers.connected == CON_CONNECTING )
+ G_Printf( "CNCT " );
+ else
+ G_Printf( "%-4d ", cl->ps.ping );
- return NULL;
+ trap_GetUserinfo( i, userinfo, sizeof( userinfo ) );
+ G_Printf( "%-21s ", Info_ValueForKey( userinfo, "ip" ) );
+ G_Printf( "%-8d ", atoi( Info_ValueForKey( userinfo, "rate" ) ) );
+ G_Printf( "%s\n", cl->pers.netname ); // Info_ValueForKey( userinfo, "name" )
+ }
+}
+
+static void Svcmd_SMR_f( void )
+{
+ G_Printf( "unrecognized Schachtmeister response: %s\n", ConcatArgs( 1 ) );
}
/*
@@ -457,22 +177,32 @@ Svcmd_ForceTeam_f
forceteam <player> <team>
===================
*/
-void Svcmd_ForceTeam_f( void )
+static void Svcmd_ForceTeam_f( void )
{
gclient_t *cl;
char str[ MAX_TOKEN_CHARS ];
+ team_t team;
+
+ if( trap_Argc( ) != 3 )
+ {
+ G_Printf( "usage: forceteam <player> <team>\n" );
+ return;
+ }
- // find the player
trap_Argv( 1, str, sizeof( str ) );
cl = ClientForString( str );
if( !cl )
return;
- // set the team
trap_Argv( 2, str, sizeof( str ) );
- /*SetTeam( &g_entities[cl - level.clients], str );*/
- //FIXME: tremulise this
+ team = G_TeamFromString( str );
+ if( team == NUM_TEAMS )
+ {
+ G_Printf( "forceteam: invalid team \"%s\"\n", str );
+ return;
+ }
+ G_ChangeTeam( &g_entities[ cl - level.clients ], team );
}
/*
@@ -482,37 +212,40 @@ Svcmd_LayoutSave_f
layoutsave <name>
===================
*/
-void Svcmd_LayoutSave_f( void )
+static void Svcmd_LayoutSave_f( void )
{
char str[ MAX_QPATH ];
char str2[ MAX_QPATH - 4 ];
char *s;
int i = 0;
+ qboolean pipeEncountered = qfalse;
if( trap_Argc( ) != 2 )
{
- G_Printf( "usage: layoutsave LAYOUTNAME\n" );
+ G_Printf( "usage: layoutsave <name>\n" );
return;
}
trap_Argv( 1, str, sizeof( str ) );
// sanitize name
+ str2[ 0 ] = '\0';
s = &str[ 0 ];
while( *s && i < sizeof( str2 ) - 1 )
{
- if( ( *s >= '0' && *s <= '9' ) ||
- ( *s >= 'a' && *s <= 'z' ) ||
- ( *s >= 'A' && *s <= 'Z' ) || *s == '-' || *s == '_' )
+ if( isalnum( *s ) || *s == '-' || *s == '_' ||
+ ( ( *s == '|' || *s == ',' ) && !pipeEncountered ) )
{
str2[ i++ ] = *s;
str2[ i ] = '\0';
+ if( *s == '|' )
+ pipeEncountered = qtrue;
}
s++;
}
if( !str2[ 0 ] )
{
- G_Printf("layoutsave: invalid name \"%s\"\n", str );
+ G_Printf( "layoutsave: invalid name \"%s\"\n", str );
return;
}
@@ -528,18 +261,27 @@ Svcmd_LayoutLoad_f
layoutload [<name> [<name2> [<name3 [...]]]]
This is just a silly alias for doing:
- set g_layouts "name name2 name3"
+ set g_nextLayout "name name2 name3"
map_restart
===================
*/
-void Svcmd_LayoutLoad_f( void )
+static void Svcmd_LayoutLoad_f( void )
{
char layouts[ MAX_CVAR_VALUE_STRING ];
+ char map[ MAX_CVAR_VALUE_STRING ];
char *s;
+ if( trap_Argc( ) < 2 )
+ {
+ G_Printf( "usage: layoutload <name> ...\n" );
+ return;
+ }
+
s = ConcatArgs( 1 );
Q_strncpyz( layouts, s, sizeof( layouts ) );
- trap_Cvar_Set( "g_layouts", layouts );
+ trap_Cvar_Set( "g_nextLayout", layouts );
+ trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
+ G_MapConfigs( map );
trap_SendConsoleCommand( EXEC_APPEND, "map_restart\n" );
level.restarted = qtrue;
}
@@ -555,225 +297,363 @@ static void Svcmd_AdmitDefeat_f( void )
return;
}
trap_Argv( 1, teamNum, sizeof( teamNum ) );
- team = atoi( teamNum );
- if( team == PTE_ALIENS || teamNum[ 0 ] == 'a' )
+ team = G_TeamFromString( teamNum );
+ if( team == TEAM_ALIENS )
{
- level.surrenderTeam = PTE_ALIENS;
- G_BaseSelfDestruct( PTE_ALIENS );
- G_TeamCommand( PTE_ALIENS, "cp \"Hivemind Link Broken\" 1");
+ G_TeamCommand( TEAM_ALIENS, "cp \"Hivemind Link Broken\" 1");
trap_SendServerCommand( -1, "print \"Alien team has admitted defeat\n\"" );
}
- else if( team == PTE_HUMANS || teamNum[ 0 ] == 'h' )
+ else if( team == TEAM_HUMANS )
{
- level.surrenderTeam = PTE_HUMANS;
- G_BaseSelfDestruct( PTE_HUMANS );
- G_TeamCommand( PTE_HUMANS, "cp \"Life Support Terminated\" 1");
+ G_TeamCommand( TEAM_HUMANS, "cp \"Life Support Terminated\" 1");
trap_SendServerCommand( -1, "print \"Human team has admitted defeat\n\"" );
}
else
{
G_Printf("admitdefeat: invalid team\n");
- }
+ return;
+ }
+ level.surrenderTeam = team;
+ G_BaseSelfDestruct( team );
}
-/*
-=================
-ConsoleCommand
-
-=================
-*/
-qboolean ConsoleCommand( void )
+static void Svcmd_TeamWin_f( void )
{
- char cmd[ MAX_TOKEN_CHARS ];
-
+ // this is largely made redundant by admitdefeat <team>
+ char cmd[ 6 ];
trap_Argv( 0, cmd, sizeof( cmd ) );
- if( Q_stricmp( cmd, "entitylist" ) == 0 )
+ switch( G_TeamFromString( cmd ) )
{
- Svcmd_EntityList_f( );
- return qtrue;
- }
+ case TEAM_ALIENS:
+ G_BaseSelfDestruct( TEAM_HUMANS );
+ break;
- if( Q_stricmp( cmd, "forceteam" ) == 0 )
- {
- Svcmd_ForceTeam_f( );
- return qtrue;
- }
+ case TEAM_HUMANS:
+ G_BaseSelfDestruct( TEAM_ALIENS );
+ break;
- if( Q_stricmp( cmd, "game_memory" ) == 0 )
- {
- Svcmd_GameMem_f( );
- return qtrue;
+ default:
+ return;
}
+}
- if( Q_stricmp( cmd, "addip" ) == 0 )
- {
- Svcmd_AddIP_f( );
- return qtrue;
- }
+static void Svcmd_Evacuation_f( void )
+{
+ if( level.exited )
+ return;
+ trap_SendServerCommand( -1, "print \"Evacuation ordered\n\"" );
+ level.lastWin = TEAM_NONE;
+ trap_SetConfigstring( CS_WINNER, "Evacuation" );
+ LogExit( "Evacuation." );
+}
+
+static void Svcmd_MapRotation_f( void )
+{
+ char rotationName[ MAX_QPATH ];
- if( Q_stricmp( cmd, "removeip" ) == 0 )
+ if( trap_Argc( ) != 2 )
{
- Svcmd_RemoveIP_f( );
- return qtrue;
+ G_Printf( "usage: maprotation <name>\n" );
+ return;
}
- if( Q_stricmp( cmd, "listip" ) == 0 )
+ G_ClearRotationStack( );
+
+ trap_Argv( 1, rotationName, sizeof( rotationName ) );
+ if( !G_StartMapRotation( rotationName, qfalse, qtrue, qfalse, 0 ) )
+ G_Printf( "maprotation: invalid map rotation \"%s\"\n", rotationName );
+}
+
+static void Svcmd_TeamMessage_f( void )
+{
+ char teamNum[ 2 ];
+ team_t team;
+
+ if( trap_Argc( ) < 3 )
{
- trap_SendConsoleCommand( EXEC_NOW, "g_banIPs\n" );
- return qtrue;
+ G_Printf( "usage: say_team <team> <message>\n" );
+ return;
}
- if( Q_stricmp( cmd, "mapRotation" ) == 0 )
+ trap_Argv( 1, teamNum, sizeof( teamNum ) );
+ team = G_TeamFromString( teamNum );
+
+ if( team == NUM_TEAMS )
{
- char *rotationName = ConcatArgs( 1 );
+ G_Printf( "say_team: invalid team \"%s\"\n", teamNum );
+ return;
+ }
- if( !G_StartMapRotation( rotationName, qfalse ) )
- G_Printf( "Can't find map rotation %s\n", rotationName );
+ G_TeamCommand( team, va( "chat -1 %d \"%s\"", SAY_TEAM, ConcatArgs( 2 ) ) );
+ G_LogPrintf( "SayTeam: -1 \"console\": %s\n", ConcatArgs( 2 ) );
+}
- return qtrue;
+static void Svcmd_CenterPrint_f( void )
+{
+ if( trap_Argc( ) < 2 )
+ {
+ G_Printf( "usage: cp <message>\n" );
+ return;
}
- if( Q_stricmp( cmd, "stopMapRotation" ) == 0 )
- {
- G_StopMapRotation( );
+ trap_SendServerCommand( -1, va( "cp \"%s\"", ConcatArgs( 1 ) ) );
+}
- return qtrue;
- }
+static void Svcmd_EjectClient_f( void )
+{
+ char *reason, name[ MAX_STRING_CHARS ];
- if( Q_stricmp( cmd, "advanceMapRotation" ) == 0 )
+ if( trap_Argc( ) < 2 )
{
- G_AdvanceMapRotation( );
-
- return qtrue;
+ G_Printf( "usage: eject <player|-1> <reason>\n" );
+ return;
}
- if( Q_stricmp( cmd, "alienWin" ) == 0 )
- {
- int i;
- gentity_t *e;
+ trap_Argv( 1, name, sizeof( name ) );
+ reason = ConcatArgs( 2 );
- for( i = 1, e = g_entities + i; i < level.num_entities; i++, e++ )
+ if( atoi( name ) == -1 )
+ {
+ int i;
+ for( i = 0; i < level.maxclients; i++ )
{
- if( e->s.modelindex == BA_H_SPAWN )
- G_Damage( e, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
+ if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
+ continue;
+ if( level.clients[ i ].pers.localClient )
+ continue;
+ trap_DropClient( i, reason );
}
-
- return qtrue;
}
-
- if( Q_stricmp( cmd, "humanWin" ) == 0 )
+ else
{
- int i;
- gentity_t *e;
-
- for( i = 1, e = g_entities + i; i < level.num_entities; i++, e++ )
+ gclient_t *cl = ClientForString( name );
+ if( !cl )
+ return;
+ if( cl->pers.localClient )
{
- if( e->s.modelindex == BA_A_SPAWN )
- G_Damage( e, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
+ G_Printf( "eject: cannot eject local clients\n" );
+ return;
}
+ trap_DropClient( cl-level.clients, reason );
+ }
+}
- return qtrue;
+static void Svcmd_DumpUser_f( void )
+{
+ char name[ MAX_STRING_CHARS ], userinfo[ MAX_INFO_STRING ];
+ char key[ BIG_INFO_KEY ], value[ BIG_INFO_VALUE ];
+ const char *info;
+ gclient_t *cl;
+
+ if( trap_Argc( ) != 2 )
+ {
+ G_Printf( "usage: dumpuser <player>\n" );
+ return;
}
- if( !Q_stricmp( cmd, "layoutsave" ) )
+ trap_Argv( 1, name, sizeof( name ) );
+ cl = ClientForString( name );
+ if( !cl )
+ return;
+
+ trap_GetUserinfo( cl-level.clients, userinfo, sizeof( userinfo ) );
+ info = &userinfo[ 0 ];
+ G_Printf( "userinfo\n--------\n" );
+ //Info_Print( userinfo );
+ while( 1 )
{
- Svcmd_LayoutSave_f( );
- return qtrue;
+ Info_NextPair( &info, key, value );
+ if( !*info )
+ return;
+
+ G_Printf( "%-20s%s\n", key, value );
}
-
- if( !Q_stricmp( cmd, "layoutload" ) )
+}
+
+static void Svcmd_Pr_f( void )
+{
+ char targ[ 4 ];
+ int cl;
+
+ if( trap_Argc( ) < 3 )
{
- Svcmd_LayoutLoad_f( );
- return qtrue;
+ G_Printf( "usage: <clientnum|-1> <message>\n" );
+ return;
}
-
- if( !Q_stricmp( cmd, "admitdefeat" ) )
+
+ trap_Argv( 1, targ, sizeof( targ ) );
+ cl = atoi( targ );
+
+ if( cl >= MAX_CLIENTS || cl < -1 )
{
- Svcmd_AdmitDefeat_f( );
- return qtrue;
+ G_Printf( "invalid clientnum %d\n", cl );
+ return;
}
- if( !Q_stricmp( cmd, "evacuation" ) )
+ trap_SendServerCommand( cl, va( "print \"%s\n\"", ConcatArgs( 2 ) ) );
+}
+
+static void Svcmd_PrintQueue_f( void )
+{
+ char team[ MAX_STRING_CHARS ];
+
+ if( trap_Argc() != 2 )
{
- trap_SendServerCommand( -1, "print \"Evacuation ordered\n\"" );
- level.lastWin = PTE_NONE;
- trap_SetConfigstring( CS_WINNER, "Evacuation" );
- LogExit( "Evacuation." );
- G_admin_maplog_result( "d" );
- return qtrue;
+ G_Printf( "usage: printqueue <team>\n" );
+ return;
}
- if( !Q_stricmp( cmd, "smr" ) )
+ trap_Argv( 1, team, sizeof( team ) );
+
+ switch( G_TeamFromString( team ) )
{
- if( trap_Argc() >= 2 )
- {
- char arg[ 32 ];
- trap_Argv( 1, arg, sizeof( arg ) );
+ case TEAM_ALIENS:
+ G_PrintSpawnQueue( &level.alienSpawnQueue );
+ break;
- if( !Q_stricmp( arg, "ipa" ) && trap_Argc() >= 4 )
- {
- int rating;
- const char *comment = NULL;
+ case TEAM_HUMANS:
+ G_PrintSpawnQueue( &level.humanSpawnQueue );
+ break;
- trap_Argv( 3, arg, sizeof( arg ) );
- rating = atoi( arg );
- if( trap_Argc() >= 5 )
- comment = ConcatArgs( 4 );
- trap_Argv( 2, arg, sizeof( arg ) );
+ default:
+ G_Printf( "unknown team\n" );
+ }
+}
- G_admin_IPA_judgement( arg, rating, comment );
+// dumb wrapper for "a", "m", "chat", and "say"
+static void Svcmd_MessageWrapper( void )
+{
+ char cmd[ 5 ];
+ trap_Argv( 0, cmd, sizeof( cmd ) );
- return qtrue;
- }
- }
+ if( !Q_stricmp( cmd, "a" ) )
+ Cmd_AdminMessage_f( NULL );
+ else if( !Q_stricmp( cmd, "m" ) )
+ Cmd_PrivateMessage_f( NULL );
+ else if( !Q_stricmp( cmd, "say" ) )
+ G_Say( NULL, SAY_ALL, ConcatArgs( 1 ) );
+ else if( !Q_stricmp( cmd, "chat" ) )
+ G_Say( NULL, SAY_RAW, ConcatArgs( 1 ) );
+}
- G_Printf( "unrecognized Schachtmeister response: %s\n", ConcatArgs( 1 ) );
- return qtrue;
- }
+static void Svcmd_ListMapsWrapper( void )
+{
+ Cmd_ListMaps_f( NULL );
+}
+
+static void Svcmd_SuddenDeath_f( void )
+{
+ char secs[ 5 ];
+ int offset;
+ trap_Argv( 1, secs, sizeof( secs ) );
+ offset = atoi( secs );
+
+ level.suddenDeathBeginTime = level.time - level.startTime + offset * 1000;
+ trap_SendServerCommand( -1,
+ va( "cp \"Sudden Death will begin in %d second%s\"",
+ offset, offset == 1 ? "" : "s" ) );
+}
- // see if this is a a admin command
- if( G_admin_cmd_check( NULL, qfalse ) )
- return qtrue;
+static void Svcmd_G_AdvanceMapRotation_f( void )
+{
+ G_AdvanceMapRotation( 0 );
+}
- if( g_dedicated.integer )
+struct svcmd
+{
+ char *cmd;
+ qboolean dedicated;
+ void ( *function )( void );
+} svcmds[ ] = {
+ { "a", qtrue, Svcmd_MessageWrapper },
+ { "admitDefeat", qfalse, Svcmd_AdmitDefeat_f },
+ { "advanceMapRotation", qfalse, Svcmd_G_AdvanceMapRotation_f },
+ { "alienWin", qfalse, Svcmd_TeamWin_f },
+ { "chat", qtrue, Svcmd_MessageWrapper },
+ { "cp", qtrue, Svcmd_CenterPrint_f },
+ { "dumpuser", qfalse, Svcmd_DumpUser_f },
+ { "eject", qfalse, Svcmd_EjectClient_f },
+ { "entityList", qfalse, Svcmd_EntityList_f },
+ { "evacuation", qfalse, Svcmd_Evacuation_f },
+ { "forceTeam", qfalse, Svcmd_ForceTeam_f },
+ { "game_memory", qfalse, BG_MemoryInfo },
+ { "humanWin", qfalse, Svcmd_TeamWin_f },
+ { "layoutLoad", qfalse, Svcmd_LayoutLoad_f },
+ { "layoutSave", qfalse, Svcmd_LayoutSave_f },
+ { "listmaps", qtrue, Svcmd_ListMapsWrapper },
+ { "loadcensors", qfalse, G_LoadCensors },
+ { "m", qtrue, Svcmd_MessageWrapper },
+ { "mapRotation", qfalse, Svcmd_MapRotation_f },
+ { "pr", qfalse, Svcmd_Pr_f },
+ { "printqueue", qfalse, Svcmd_PrintQueue_f },
+ { "say", qtrue, Svcmd_MessageWrapper },
+ { "say_team", qtrue, Svcmd_TeamMessage_f },
+ { "smr", qfalse, Svcmd_SMR_f },
+ { "status", qfalse, Svcmd_Status_f },
+ { "stopMapRotation", qfalse, G_StopMapRotation },
+ { "suddendeath", qfalse, Svcmd_SuddenDeath_f }
+};
+
+/*
+=================
+ConsoleCommand
+
+=================
+*/
+qboolean ConsoleCommand( void )
+{
+ char cmd[ MAX_TOKEN_CHARS ];
+ struct svcmd *command;
+
+ trap_Argv( 0, cmd, sizeof( cmd ) );
+
+ command = bsearch( cmd, svcmds, ARRAY_LEN( svcmds ),
+ sizeof( struct svcmd ), cmdcmp );
+
+ if( !command )
{
- if( Q_stricmp( cmd, "say" ) == 0 )
- {
- trap_SendServerCommand( -1, va( "print \"server: %s\n\"", ConcatArgs( 1 ) ) );
- return qtrue;
- }
- else if( !Q_stricmp( cmd, "chat" ) )
- {
- trap_SendServerCommand( -1, va( "chat \"%s\" -1 0", ConcatArgs( 1 ) ) );
- G_Printf( "chat: %s\n", ConcatArgs( 1 ) );
- return qtrue;
- }
- else if( !Q_stricmp( cmd, "cp" ) )
- {
- G_CP( NULL );
- return qtrue;
- }
- else if( !Q_stricmp( cmd, "m" ) )
- {
- G_PrivateMessage( NULL );
- return qtrue;
- }
- else if( !Q_stricmp( cmd, "a" ) || !Q_stricmp( cmd, "say_admins" ))
- {
- G_Say( NULL, NULL, SAY_ADMINS, ConcatArgs( 1 ) );
+ // see if this is an admin command
+ if( G_admin_cmd_check( NULL ) )
return qtrue;
- }
- else if( !Q_stricmp( cmd, "ha" ) || !Q_stricmp( cmd, "say_hadmins" ))
- {
- G_Say( NULL, NULL, SAY_HADMINS, ConcatArgs( 1 ) );
- return qtrue;
- }
- G_Printf( "unknown command: %s\n", cmd );
- return qtrue;
+ if( g_dedicated.integer )
+ G_Printf( "unknown command: %s\n", cmd );
+
+ return qfalse;
+ }
+
+ if( command->dedicated && !g_dedicated.integer )
+ return qfalse;
+
+ command->function( );
+ return qtrue;
+}
+
+void G_RegisterCommands( void )
+{
+ int i;
+
+ for( i = 0; i < ARRAY_LEN( svcmds ); i++ )
+ {
+ if( svcmds[ i ].dedicated && !g_dedicated.integer )
+ continue;
+ trap_AddCommand( svcmds[ i ].cmd );
}
- return qfalse;
+ G_admin_register_cmds( );
}
+void G_UnregisterCommands( void )
+{
+ int i;
+
+ for( i = 0; i < ARRAY_LEN( svcmds ); i++ )
+ {
+ if( svcmds[ i ].dedicated && !g_dedicated.integer )
+ continue;
+ trap_RemoveCommand( svcmds[ i ].cmd );
+ }
+
+ G_admin_unregister_cmds( );
+}
diff --git a/src/game/g_syscalls.asm b/src/game/g_syscalls.asm
index 242c2ad..4057923 100644
--- a/src/game/g_syscalls.asm
+++ b/src/game/g_syscalls.asm
@@ -1,6 +1,6 @@
code
-equ trap_Printf -1
+equ trap_Print -1
equ trap_Error -2
equ trap_Milliseconds -3
equ trap_Cvar_Register -4
@@ -54,6 +54,7 @@ equ trap_SendGameStat -49
equ trap_AddCommand -50
equ trap_RemoveCommand -51
+equ trap_FS_GetFilteredFiles -52
equ memset -101
equ memcpy -102
diff --git a/src/game/g_syscalls.c b/src/game/g_syscalls.c
index 6e3dc26..7c658be 100644
--- a/src/game/g_syscalls.c
+++ b/src/game/g_syscalls.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -36,12 +37,12 @@ Q_EXPORT void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) )
int PASSFLOAT( float x )
{
- float floatTemp;
- floatTemp = x;
- return *(int *)&floatTemp;
+ floatint_t fi;
+ fi.f = x;
+ return fi.i;
}
-void trap_Printf( const char *fmt )
+void trap_Print( const char *fmt )
{
syscall( G_PRINT, fmt );
}
@@ -49,6 +50,8 @@ void trap_Printf( const char *fmt )
void trap_Error( const char *fmt )
{
syscall( G_ERROR, fmt );
+ // shut up GCC warning about returning functions, because we know better
+ exit(1);
}
int trap_Milliseconds( void )
@@ -65,7 +68,7 @@ void trap_Argv( int n, char *buffer, int bufferLength )
syscall( G_ARGV, n, buffer, bufferLength );
}
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode )
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, enum FS_Mode mode )
{
return syscall( G_FS_FOPEN_FILE, qpath, f, mode );
}
@@ -147,6 +150,11 @@ void trap_GetConfigstring( int num, char *buffer, int bufferSize )
syscall( G_GET_CONFIGSTRING, num, buffer, bufferSize );
}
+void trap_SetConfigstringRestrictions( int num, const clientList_t *clientList )
+{
+ syscall( G_SET_CONFIGSTRING_RESTRICTIONS, num, clientList );
+}
+
void trap_GetUserinfo( int num, char *buffer, int bufferSize )
{
syscall( G_GET_USERINFO, num, buffer, bufferSize );
@@ -248,13 +256,6 @@ int trap_RealTime( qtime_t *qtime )
void trap_SnapVector( float *v )
{
syscall( G_SNAPVECTOR, v );
- return;
-}
-
-void trap_SendGameStat( const char *data )
-{
- syscall( G_SEND_GAMESTAT, data );
- return;
}
int trap_Parse_AddGlobalDefine( char *define )
@@ -282,3 +283,17 @@ int trap_Parse_SourceFileAndLine( int handle, char *filename, int *line )
return syscall( G_PARSE_SOURCE_FILE_AND_LINE, handle, filename, line );
}
+void trap_AddCommand( const char *cmdName )
+{
+ syscall( G_ADDCOMMAND, cmdName );
+}
+
+void trap_RemoveCommand( const char *cmdName )
+{
+ syscall( G_REMOVECOMMAND, cmdName );
+}
+
+int trap_FS_GetFilteredFiles( const char *path, const char *extension, const char *filter, char *listbuf, int bufsize )
+{
+ return syscall( G_FS_GETFILTEREDFILES, path, extension, filter, listbuf, bufsize );
+}
diff --git a/src/game/g_target.c b/src/game/g_target.c
index 467920a..f2a3f0f 100644
--- a/src/game/g_target.c
+++ b/src/game/g_target.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -31,6 +32,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
void Think_Target_Delay( gentity_t *ent )
{
+ if( ent->activator && !ent->activator->inuse )
+ ent->activator = NULL;
G_UseTargets( ent, ent->activator );
}
@@ -86,18 +89,19 @@ If "private", only the activator gets the message. If no checks, all clients ge
*/
void Use_Target_Print( gentity_t *ent, gentity_t *other, gentity_t *activator )
{
- if( activator && activator->client && ( ent->spawnflags & 4 ) )
+ if( ent->spawnflags & 4 )
{
- trap_SendServerCommand( activator-g_entities, va( "cp \"%s\"", ent->message ) );
+ if( activator && activator->client )
+ trap_SendServerCommand( activator-g_entities, va( "cp \"%s\"", ent->message ) );
return;
}
if( ent->spawnflags & 3 )
{
if( ent->spawnflags & 1 )
- G_TeamCommand( PTE_HUMANS, va( "cp \"%s\"", ent->message ) );
+ G_TeamCommand( TEAM_HUMANS, va( "cp \"%s\"", ent->message ) );
if( ent->spawnflags & 2 )
- G_TeamCommand( PTE_ALIENS, va( "cp \"%s\"", ent->message ) );
+ G_TeamCommand( TEAM_ALIENS, va( "cp \"%s\"", ent->message ) );
return;
}
@@ -156,9 +160,9 @@ void SP_target_speaker( gentity_t *ent )
G_SpawnFloat( "random", "0", &ent->random );
if( !G_SpawnString( "noise", "NOSOUND", &s ) )
- G_Error( "target_speaker without a noise key at %s", vtos( ent->s.origin ) );
+ G_Error( "target_speaker without a noise key at %s", vtos( ent->r.currentOrigin ) );
- // force all client reletive sounds to be "activator" speakers that
+ // force all client relative sounds to be "activator" speakers that
// play on the entity that activates it
if( s[ 0 ] == '*' )
ent->spawnflags |= 8;
@@ -186,8 +190,6 @@ void SP_target_speaker( gentity_t *ent )
if( ent->spawnflags & 4 )
ent->r.svFlags |= SVF_BROADCAST;
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
-
// must link the entity so we get areas and clusters so
// the server can determine who to send updates to
trap_LinkEntity( ent );
@@ -210,7 +212,7 @@ void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activa
return;
}
- TeleportPlayer( activator, dest->s.origin, dest->s.angles );
+ TeleportPlayer( activator, dest->r.currentOrigin, dest->r.currentAngles, self->speed );
}
/*QUAKED target_teleporter (1 0 0) (-8 -8 -8) (8 8 8)
@@ -219,7 +221,9 @@ The activator will be teleported away.
void SP_target_teleporter( gentity_t *self )
{
if( !self->targetname )
- G_Printf( "untargeted %s at %s\n", self->classname, vtos( self->s.origin ) );
+ G_Printf( "untargeted %s at %s\n", self->classname, vtos( self->r.currentOrigin ) );
+
+ G_SpawnFloat( "speed", "400", &self->speed );
self->use = target_teleporter_use;
}
@@ -235,11 +239,11 @@ if RANDOM is checked, only one of the targets will be fired, not all of them
void target_relay_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
if( ( self->spawnflags & 1 ) && activator && activator->client &&
- activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
+ activator->client->ps.stats[ STAT_TEAM ] != TEAM_HUMANS )
return;
if( ( self->spawnflags & 2 ) && activator && activator->client &&
- activator->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS )
+ activator->client->ps.stats[ STAT_TEAM ] != TEAM_ALIENS )
return;
if( self->spawnflags & 4 )
@@ -285,36 +289,7 @@ Used as a positional target for in-game calculation, like jumppad targets.
*/
void SP_target_position( gentity_t *self )
{
- G_SetOrigin( self, self->s.origin );
-}
-
-static void target_location_linkup( gentity_t *ent )
-{
- int i;
- int n;
-
- if( level.locationLinked )
- return;
-
- level.locationLinked = qtrue;
-
- level.locationHead = NULL;
-
- trap_SetConfigstring( CS_LOCATIONS, "unknown" );
-
- for( i = 0, ent = g_entities, n = 1; i < level.num_entities; i++, ent++)
- {
- if( ent->classname && !Q_stricmp( ent->classname, "target_location" ) )
- {
- // lets overload some variables!
- ent->health = n; // use for location marking
- trap_SetConfigstring( CS_LOCATIONS + n, ent->message );
- n++;
- ent->nextTrain = level.locationHead;
- level.locationHead = ent;
- }
- }
- // All linked together now
+ G_SetOrigin( self, self->r.currentOrigin );
}
/*QUAKED target_location (0 0.5 0) (-8 -8 -8) (8 8 8)
@@ -327,10 +302,36 @@ in site, closest in distance
*/
void SP_target_location( gentity_t *self )
{
- self->think = target_location_linkup;
- self->nextthink = level.time + 200; // Let them all spawn first
+ static int n = 0;
+ const char *message;
+ self->s.eType = ET_LOCATION;
+ self->r.svFlags = SVF_BROADCAST;
+ trap_LinkEntity( self ); // make the server send them to the clients
+ if( n == MAX_LOCATIONS )
+ {
+ G_Printf( S_COLOR_YELLOW "too many target_locations\n" );
+ return;
+ }
+ if( self->count )
+ {
+ if( self->count < 0 )
+ self->count = 0;
+
+ if( self->count > 7 )
+ self->count = 7;
- G_SetOrigin( self, self->s.origin );
+ message = va( "%c%c%s" S_COLOR_WHITE, Q_COLOR_ESCAPE, self->count + '0',
+ (const char*)self->message);
+ }
+ else
+ message = self->message;
+ trap_SetConfigstring( CS_LOCATIONS + n, message );
+ self->nextTrain = level.locationHead;
+ self->s.generic1 = n; // use for location marking
+ level.locationHead = self;
+ n++;
+
+ G_SetOrigin( self, self->r.currentOrigin );
}
@@ -391,7 +392,7 @@ void SP_target_rumble( gentity_t *self )
if( !self->targetname )
{
G_Printf( S_COLOR_YELLOW "WARNING: untargeted %s at %s\n", self->classname,
- vtos( self->s.origin ) );
+ vtos( self->r.currentOrigin ) );
}
if( !self->count )
@@ -411,7 +412,8 @@ target_alien_win_use
*/
void target_alien_win_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
- level.uncondAlienWin = qtrue;
+ if( !level.uncondHumanWin )
+ level.uncondAlienWin = qtrue;
}
/*
@@ -431,7 +433,8 @@ target_human_win_use
*/
void target_human_win_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
- level.uncondHumanWin = qtrue;
+ if( !level.uncondAlienWin )
+ level.uncondHumanWin = qtrue;
}
/*
@@ -468,7 +471,7 @@ void SP_target_hurt( gentity_t *self )
if( !self->targetname )
{
G_Printf( S_COLOR_YELLOW "WARNING: untargeted %s at %s\n", self->classname,
- vtos( self->s.origin ) );
+ vtos( self->r.currentOrigin ) );
}
if( !self->damage )
diff --git a/src/game/g_team.c b/src/game/g_team.c
index 1d8d102..4af6235 100644
--- a/src/game/g_team.c
+++ b/src/game/g_team.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,35 +17,54 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
#include "g_local.h"
-// NULL for everyone
-void QDECL PrintMsg( gentity_t *ent, const char *fmt, ... )
-{
- char msg[ 1024 ];
- va_list argptr;
- char *p;
-
- va_start( argptr,fmt );
+/*
+================
+G_TeamFromString
- if( vsprintf( msg, fmt, argptr ) > sizeof( msg ) )
- G_Error ( "PrintMsg overrun" );
+Return the team referenced by a string
+================
+*/
+team_t G_TeamFromString( char *str )
+{
+ switch( tolower( *str ) )
+ {
+ case '0': case 's': return TEAM_NONE;
+ case '1': case 'a': return TEAM_ALIENS;
+ case '2': case 'h': return TEAM_HUMANS;
+ default: return NUM_TEAMS;
+ }
+}
- va_end( argptr );
+/*
+================
+G_TeamCommand
- // double quotes are bad
- while( ( p = strchr( msg, '"' ) ) != NULL )
- *p = '\'';
+Broadcasts a command to only a specific team
+================
+*/
+void G_TeamCommand( team_t team, const char *cmd )
+{
+ int i;
- trap_SendServerCommand( ( ( ent == NULL ) ? -1 : ent-g_entities ), va( "print \"%s\"", msg ) );
+ for( i = 0 ; i < level.maxclients ; i++ )
+ {
+ if( level.clients[ i ].pers.connected == CON_CONNECTED )
+ {
+ if( level.clients[ i ].pers.teamSelection == team ||
+ ( level.clients[ i ].pers.teamSelection == TEAM_NONE &&
+ G_admin_permission( &g_entities[ i ], ADMF_SPEC_ALLCHAT ) ) )
+ trap_SendServerCommand( i, cmd );
+ }
+ }
}
-
/*
==============
OnSameTeam
@@ -62,156 +82,312 @@ qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 )
}
/*
-===========
-Team_GetLocation
+==================
+G_ClientListForTeam
+==================
+*/
+static clientList_t G_ClientListForTeam( team_t team )
+{
+ int i;
+ clientList_t clientList;
-Report a location for the player. Uses placed nearby target_location entities
-============
+ Com_Memset( &clientList, 0, sizeof( clientList_t ) );
+
+ for( i = 0; i < g_maxclients.integer; i++ )
+ {
+ gentity_t *ent = g_entities + i;
+ if( ent->client->pers.connected != CON_CONNECTED )
+ continue;
+
+ if( ent->inuse && ( ent->client->ps.stats[ STAT_TEAM ] == team ) )
+ Com_ClientListAdd( &clientList, ent->client->ps.clientNum );
+ }
+
+ return clientList;
+}
+
+/*
+==================
+G_UpdateTeamConfigStrings
+==================
*/
-gentity_t *Team_GetLocation( gentity_t *ent )
+void G_UpdateTeamConfigStrings( void )
{
- gentity_t *eloc, *best;
- float bestlen, len;
- vec3_t origin;
+ clientList_t alienTeam = G_ClientListForTeam( TEAM_ALIENS );
+ clientList_t humanTeam = G_ClientListForTeam( TEAM_HUMANS );
- best = NULL;
- bestlen = 3.0f * 8192.0f * 8192.0f;
+ if( level.intermissiontime )
+ {
+ // No restrictions once the game has ended
+ Com_Memset( &alienTeam, 0, sizeof( clientList_t ) );
+ Com_Memset( &humanTeam, 0, sizeof( clientList_t ) );
+ }
- VectorCopy( ent->r.currentOrigin, origin );
+ trap_SetConfigstringRestrictions( CS_VOTE_TIME + TEAM_ALIENS, &humanTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_STRING + TEAM_ALIENS, &humanTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_YES + TEAM_ALIENS, &humanTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_NO + TEAM_ALIENS, &humanTeam );
- for( eloc = level.locationHead; eloc; eloc = eloc->nextTrain )
+ trap_SetConfigstringRestrictions( CS_VOTE_TIME + TEAM_HUMANS, &alienTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_STRING + TEAM_HUMANS, &alienTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_YES + TEAM_HUMANS, &alienTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_NO + TEAM_HUMANS, &alienTeam );
+
+ trap_SetConfigstringRestrictions( CS_ALIEN_STAGES, &humanTeam );
+ trap_SetConfigstringRestrictions( CS_HUMAN_STAGES, &alienTeam );
+}
+
+/*
+==================
+G_LeaveTeam
+==================
+*/
+void G_LeaveTeam( gentity_t *self )
+{
+ team_t team = self->client->pers.teamSelection;
+ gentity_t *ent;
+ int i;
+
+ if( team == TEAM_ALIENS )
+ G_RemoveFromSpawnQueue( &level.alienSpawnQueue, self->client->ps.clientNum );
+ else if( team == TEAM_HUMANS )
+ G_RemoveFromSpawnQueue( &level.humanSpawnQueue, self->client->ps.clientNum );
+ else
{
- len = ( origin[ 0 ] - eloc->r.currentOrigin[ 0 ] ) * ( origin[ 0 ] - eloc->r.currentOrigin[ 0 ] )
- + ( origin[ 1 ] - eloc->r.currentOrigin[ 1 ] ) * ( origin[ 1 ] - eloc->r.currentOrigin[ 1 ] )
- + ( origin[ 2 ] - eloc->r.currentOrigin[ 2 ] ) * ( origin[ 2 ] - eloc->r.currentOrigin[ 2 ] );
+ if( self->client->sess.spectatorState == SPECTATOR_FOLLOW )
+ G_StopFollowing( self );
+ return;
+ }
- if( len > bestlen )
- continue;
+ // stop any following clients
+ G_StopFromFollowing( self );
- if( !trap_InPVS( origin, eloc->r.currentOrigin ) )
+ G_Vote( self, team, qfalse );
+ self->suicideTime = 0;
+
+ for( i = 0; i < level.num_entities; i++ )
+ {
+ ent = &g_entities[ i ];
+ if( !ent->inuse )
continue;
- bestlen = len;
- best = eloc;
+ if( ent->client && ent->client->pers.connected == CON_CONNECTED )
+ {
+ // cure poison
+ if( ent->client->ps.stats[ STAT_STATE ] & SS_POISONED &&
+ ent->client->lastPoisonClient == self )
+ ent->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
+ }
+ else if( ent->s.eType == ET_MISSILE && ent->r.ownerNum == self->s.number )
+ G_FreeEntity( ent );
}
- return best;
+ // cut all relevant zap beams
+ G_ClearPlayerZapEffects( self );
+
+ G_namelog_update_score( self->client );
}
+/*
+=================
+G_ChangeTeam
+=================
+*/
+void G_ChangeTeam( gentity_t *ent, team_t newTeam )
+{
+ team_t oldTeam = ent->client->pers.teamSelection;
+
+ if( oldTeam == newTeam )
+ return;
+
+ G_LeaveTeam( ent );
+ ent->client->pers.teamChangeTime = level.time;
+ ent->client->pers.teamSelection = newTeam;
+ ent->client->pers.classSelection = PCL_NONE;
+ ClientSpawn( ent, NULL, NULL, NULL );
+
+ if( oldTeam == TEAM_HUMANS && newTeam == TEAM_ALIENS )
+ {
+ // Convert from human to alien credits
+ ent->client->pers.credit =
+ (int)( ent->client->pers.credit *
+ ALIEN_MAX_CREDITS / HUMAN_MAX_CREDITS + 0.5f );
+ }
+ else if( oldTeam == TEAM_ALIENS && newTeam == TEAM_HUMANS )
+ {
+ // Convert from alien to human credits
+ ent->client->pers.credit =
+ (int)( ent->client->pers.credit *
+ HUMAN_MAX_CREDITS / ALIEN_MAX_CREDITS + 0.5f );
+ }
+
+ if( !g_cheats.integer )
+ {
+ if( ent->client->noclip )
+ {
+ ent->client->noclip = qfalse;
+ ent->r.contents = ent->client->cliprcontents;
+ }
+ ent->flags &= ~( FL_GODMODE | FL_NOTARGET );
+ }
+
+ // Copy credits to ps for the client
+ ent->client->ps.persistant[ PERS_CREDIT ] = ent->client->pers.credit;
+
+ ClientUserinfoChanged( ent->client->ps.clientNum, qfalse );
+
+ G_UpdateTeamConfigStrings( );
+
+ G_LogPrintf( "ChangeTeam: %d %s: %s" S_COLOR_WHITE " switched teams\n",
+ (int)( ent - g_entities ), BG_TeamName( newTeam ), ent->client->pers.netname );
+
+ G_namelog_update_score( ent->client );
+ TeamplayInfoMessage( ent );
+}
/*
===========
-Team_GetLocationMsg
+Team_GetLocation
-Report a location message for the player. Uses placed nearby target_location entities
+Report a location for the player. Uses placed nearby target_location entities
============
*/
-qboolean Team_GetLocationMsg( gentity_t *ent, char *loc, int loclen )
+gentity_t *Team_GetLocation( gentity_t *ent )
{
- gentity_t *best;
-
- best = Team_GetLocation( ent );
+ gentity_t *eloc, *best;
+ float bestlen, len;
- if( !best )
- return qfalse;
+ best = NULL;
+ bestlen = 3.0f * 8192.0f * 8192.0f;
- if( best->count )
+ for( eloc = level.locationHead; eloc; eloc = eloc->nextTrain )
{
- if( best->count < 0 )
- best->count = 0;
+ len = DistanceSquared( ent->r.currentOrigin, eloc->r.currentOrigin );
+
+ if( len > bestlen )
+ continue;
- if( best->count > 7 )
- best->count = 7;
+ if( !trap_InPVS( ent->r.currentOrigin, eloc->r.currentOrigin ) )
+ continue;
- Com_sprintf( loc, loclen, "%c%c%s" S_COLOR_WHITE, Q_COLOR_ESCAPE, best->count + '0', best->message );
+ bestlen = len;
+ best = eloc;
}
- else
- Com_sprintf( loc, loclen, "%s", best->message );
- return qtrue;
+ return best;
}
/*---------------------------------------------------------------------------*/
-static int QDECL SortClients( const void *a, const void *b )
-{
- return *(int *)a - *(int *)b;
-}
-
-
/*
==================
-TeamplayLocationsMessage
+TeamplayInfoMessage
Format:
- clientNum location health armor weapon powerups
+ clientNum location health weapon upgrade
==================
*/
void TeamplayInfoMessage( gentity_t *ent )
{
- char entry[ 1024 ];
- char string[ 8192 ];
- int stringlength;
- int i, j;
+ char entry[ 17 ],
+ string[ ( MAX_CLIENTS - 1 ) * ( sizeof( entry ) - 1 ) + 1 ];
+ int i, j;
+ int team, stringlength;
gentity_t *player;
- int cnt;
- int h, a = 0;
- int clients[ TEAM_MAXOVERLAY ];
+ gclient_t *cl;
+ upgrade_t upgrade = UP_NONE;
+ int curWeaponClass = WP_NONE ; // sends weapon for humans, class for aliens
+ char *format;
- if( ! ent->client->pers.teamInfo )
- return;
+ if( !g_allowTeamOverlay.integer )
+ return;
- // figure out what client should be on the display
- // we are limited to 8, but we want to use the top eight players
- // but in client order (so they don't keep changing position on the overlay)
- for( i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++ )
- {
- player = g_entities + level.sortedClients[ i ];
+ if( !ent->client->pers.teamInfo )
+ return;
- if( player->inuse && player->client->sess.sessionTeam ==
- ent->client->sess.sessionTeam )
- clients[ cnt++ ] = level.sortedClients[ i ];
+ if( ent->client->pers.teamSelection == TEAM_NONE )
+ {
+ if( ent->client->sess.spectatorState == SPECTATOR_FREE ||
+ ent->client->sess.spectatorClient < 0 )
+ return;
+ team = g_entities[ ent->client->sess.spectatorClient ].client->
+ pers.teamSelection;
}
+ else
+ team = ent->client->pers.teamSelection;
- // We have the top eight players, sort them by clientNum
- qsort( clients, cnt, sizeof( clients[ 0 ] ), SortClients );
+ if( team == TEAM_ALIENS )
+ format = " %i %i %i %i"; // aliens don't have upgrades
+ else
+ format = " %i %i %i %i %i";
- // send the latest information on all clients
- string[ 0 ] = 0;
+ string[ 0 ] = '\0';
stringlength = 0;
- for( i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++)
+ for( i = 0; i < level.maxclients; i++)
{
- player = g_entities + i;
+ player = g_entities + i ;
+ cl = player->client;
- if( player->inuse && player->client->sess.sessionTeam ==
- ent->client->sess.sessionTeam )
- {
- h = player->client->ps.stats[ STAT_HEALTH ];
+ if( ent == player || !cl || team != cl->pers.teamSelection ||
+ !player->inuse )
+ continue;
- if( h < 0 )
- h = 0;
+ // only update if changed since last time
+ if( cl->pers.infoChangeTime <= ent->client->pers.teamInfo )
+ continue;
- Com_sprintf( entry, sizeof( entry ),
- " %i %i %i %i %i %i",
-// level.sortedClients[i], player->client->pers.teamState.location, h, a,
- i, player->client->pers.teamState.location, h, a,
- player->client->ps.weapon, player->s.misc );
+ if( cl->sess.spectatorState != SPECTATOR_NOT )
+ {
+ curWeaponClass = WP_NONE;
+ upgrade = UP_NONE;
+ }
+ else if ( cl->pers.teamSelection == TEAM_HUMANS )
+ {
+ curWeaponClass = cl->ps.weapon;
+
+ if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, cl->ps.stats ) )
+ upgrade = UP_BATTLESUIT;
+ else if( BG_InventoryContainsUpgrade( UP_JETPACK, cl->ps.stats ) )
+ upgrade = UP_JETPACK;
+ else if( BG_InventoryContainsUpgrade( UP_BATTPACK, cl->ps.stats ) )
+ upgrade = UP_BATTPACK;
+ else if( BG_InventoryContainsUpgrade( UP_HELMET, cl->ps.stats ) )
+ upgrade = UP_HELMET;
+ else if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, cl->ps.stats ) )
+ upgrade = UP_LIGHTARMOUR;
+ else
+ upgrade = UP_NONE;
+ }
+ else if( cl->pers.teamSelection == TEAM_ALIENS )
+ {
+ curWeaponClass = cl->ps.stats[ STAT_CLASS ];
+ upgrade = UP_NONE;
+ }
- j = strlen( entry );
+ Com_sprintf( entry, sizeof( entry ), format, i,
+ cl->pers.location,
+ cl->ps.stats[ STAT_HEALTH ] < 1 ? 0 : cl->ps.stats[ STAT_HEALTH ],
+ curWeaponClass,
+ upgrade );
- if( stringlength + j > sizeof( string ) )
- break;
+ j = strlen( entry );
- strcpy( string + stringlength, entry );
- stringlength += j;
- cnt++;
- }
+ // this should not happen if entry and string sizes are correct
+ if( stringlength + j >= sizeof( string ) )
+ break;
+
+ strcpy( string + stringlength, entry );
+ stringlength += j;
}
- trap_SendServerCommand( ent - g_entities, va( "tinfo %i %s", cnt, string ) );
+ if( string[ 0 ] )
+ {
+ trap_SendServerCommand( ent - g_entities, va( "tinfo%s", string ) );
+ ent->client->pers.teamInfo = level.time;
+ }
}
void CheckTeamStatus( void )
@@ -229,16 +405,25 @@ void CheckTeamStatus( void )
if( ent->client->pers.connected != CON_CONNECTED )
continue;
- if( ent->inuse && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ||
- ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) )
+ if( ent->inuse && ( ent->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ||
+ ent->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) )
{
loc = Team_GetLocation( ent );
if( loc )
- ent->client->pers.teamState.location = loc->health;
- else
- ent->client->pers.teamState.location = 0;
+ {
+ if( ent->client->pers.location != loc->s.generic1 )
+ {
+ ent->client->pers.infoChangeTime = level.time;
+ ent->client->pers.location = loc->s.generic1;
+ }
+ }
+ else if( ent->client->pers.location != 0 )
+ {
+ ent->client->pers.infoChangeTime = level.time;
+ ent->client->pers.location = 0;
+ }
}
}
@@ -248,29 +433,35 @@ void CheckTeamStatus( void )
if( ent->client->pers.connected != CON_CONNECTED )
continue;
- if( ent->inuse && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ||
- ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) )
+ if( ent->inuse )
TeamplayInfoMessage( ent );
}
}
- //Warn on unbalanced teams
- if ( g_teamImbalanceWarnings.integer && !level.intermissiontime && level.time - level.lastTeamUnbalancedTime > ( g_teamImbalanceWarnings.integer * 1000 ) && level.numTeamWarnings<3 )
+ // Warn on imbalanced teams
+ if( g_teamImbalanceWarnings.integer && !level.intermissiontime &&
+ ( level.time - level.lastTeamImbalancedTime >
+ ( g_teamImbalanceWarnings.integer * 1000 ) ) &&
+ level.numTeamImbalanceWarnings < 3 && !level.restarted )
{
- level.lastTeamUnbalancedTime = level.time;
- if (level.numAlienSpawns > 0 && level.numHumanClients - level.numAlienClients > 2)
- {
- trap_SendServerCommand (-1, "print \"Teams are unbalanced. Humans have more players.\n Humans will keep their points when switching teams.\n\"");
- level.numTeamWarnings++;
- }
- else if (level.numHumanSpawns > 0 && level.numAlienClients - level.numHumanClients > 2)
- {
- trap_SendServerCommand (-1, "print \"Teams are unbalanced. Aliens have more players.\n Aliens will keep their points when switching teams.\n\"");
- level.numTeamWarnings++;
- }
- else
- {
- level.numTeamWarnings = 0;
- }
+ level.lastTeamImbalancedTime = level.time;
+ if( level.numAlienSpawns > 0 &&
+ level.numHumanClients - level.numAlienClients > 2 )
+ {
+ trap_SendServerCommand( -1, "print \"Teams are imbalanced. "
+ "Humans have more players.\n\"");
+ level.numTeamImbalanceWarnings++;
+ }
+ else if( level.numHumanSpawns > 0 &&
+ level.numAlienClients - level.numHumanClients > 2 )
+ {
+ trap_SendServerCommand ( -1, "print \"Teams are imbalanced. "
+ "Aliens have more players.\n\"");
+ level.numTeamImbalanceWarnings++;
+ }
+ else
+ {
+ level.numTeamImbalanceWarnings = 0;
+ }
}
}
diff --git a/src/game/g_trigger.c b/src/game/g_trigger.c
index 0ac34bb..8d7c518 100644
--- a/src/game/g_trigger.c
+++ b/src/game/g_trigger.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -26,8 +27,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
void InitTrigger( gentity_t *self )
{
- if( !VectorCompare( self->s.angles, vec3_origin ) )
- G_SetMovedir( self->s.angles, self->movedir );
+ if( !VectorCompare( self->r.currentAngles, vec3_origin ) )
+ G_SetMovedir( self->r.currentAngles, self->movedir );
trap_SetBrushModel( self, self->model );
self->r.contents = CONTENTS_TRIGGER; // replaces the -1 from trap_SetBrushModel
@@ -42,6 +43,24 @@ void multi_wait( gentity_t *ent )
}
+void trigger_check_wait( gentity_t *self )
+{
+ if( self->wait > 0 )
+ {
+ self->think = multi_wait;
+ self->nextthink = level.time + ( self->wait + self->random * crandom( ) ) * 1000;
+ }
+ else
+ {
+ // we can't just remove (self) here, because this is a touch function
+ // called while looping through area links...
+ self->touch = 0;
+ self->nextthink = level.time + FRAMETIME;
+ self->think = G_FreeEntity;
+ }
+}
+
+
// the trigger was just activated
// ent->activator should be set to the activator so it can be held through a delay
// so wait for the delay time before firing
@@ -51,32 +70,19 @@ void multi_trigger( gentity_t *ent, gentity_t *activator )
if( ent->nextthink )
return; // can't retrigger until the wait is over
- if( activator->client )
+ if( activator && activator->client )
{
if( ( ent->spawnflags & 1 ) &&
- activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
+ activator->client->ps.stats[ STAT_TEAM ] != TEAM_HUMANS )
return;
if( ( ent->spawnflags & 2 ) &&
- activator->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS )
+ activator->client->ps.stats[ STAT_TEAM ] != TEAM_ALIENS )
return;
}
G_UseTargets( ent, ent->activator );
-
- if( ent->wait > 0 )
- {
- ent->think = multi_wait;
- ent->nextthink = level.time + ( ent->wait + ent->random * crandom( ) ) * 1000;
- }
- else
- {
- // we can't just remove (self) here, because this is a touch function
- // called while looping through area links...
- ent->touch = 0;
- ent->nextthink = level.time + FRAMETIME;
- ent->think = G_FreeEntity;
- }
+ trigger_check_wait( ent );
}
void Use_Multi( gentity_t *ent, gentity_t *other, gentity_t *activator )
@@ -184,7 +190,7 @@ void AimAtTarget( gentity_t *self )
return;
}
- height = ent->s.origin[ 2 ] - origin[ 2 ];
+ height = ent->r.currentOrigin[ 2 ] - origin[ 2 ];
gravity = g_gravity.value;
time = sqrt( height / ( 0.5 * gravity ) );
@@ -195,7 +201,7 @@ void AimAtTarget( gentity_t *self )
}
// set s.origin2 to the push velocity
- VectorSubtract( ent->s.origin, origin, self->s.origin2 );
+ VectorSubtract( ent->r.currentOrigin, origin, self->s.origin2 );
self->s.origin2[ 2 ] = 0;
dist = VectorNormalize( self->s.origin2 );
@@ -227,7 +233,7 @@ void SP_trigger_push( gentity_t *self )
void Use_target_push( gentity_t *self, gentity_t *other, gentity_t *activator )
{
- if( !activator->client )
+ if( !activator || !activator->client )
return;
if( activator->client->ps.pm_type != PM_NORMAL )
@@ -246,13 +252,13 @@ void SP_target_push( gentity_t *self )
if( !self->speed )
self->speed = 1000;
- G_SetMovedir( self->s.angles, self->s.origin2 );
+ G_SetMovedir( self->r.currentAngles, self->s.origin2 );
VectorScale( self->s.origin2, self->speed, self->s.origin2 );
if( self->target )
{
- VectorCopy( self->s.origin, self->r.absmin );
- VectorCopy( self->s.origin, self->r.absmax );
+ VectorCopy( self->r.currentOrigin, self->r.absmin );
+ VectorCopy( self->r.currentOrigin, self->r.absmax );
self->think = AimAtTarget;
self->nextthink = level.time + FRAMETIME;
}
@@ -283,7 +289,7 @@ void trigger_teleporter_touch( gentity_t *self, gentity_t *other, trace_t *trace
// Spectators only?
if( ( self->spawnflags & 1 ) &&
- other->client->sess.sessionTeam != TEAM_SPECTATOR )
+ other->client->sess.spectatorState == SPECTATOR_NOT )
return;
@@ -295,7 +301,7 @@ void trigger_teleporter_touch( gentity_t *self, gentity_t *other, trace_t *trace
return;
}
- TeleportPlayer( other, dest->s.origin, dest->s.angles );
+ TeleportPlayer( other, dest->r.currentOrigin, dest->r.currentAngles, self->speed );
}
/*
@@ -321,6 +327,8 @@ void SP_trigger_teleport( gentity_t *self )
{
InitTrigger( self );
+ G_SpawnFloat( "speed", "400", &self->speed );
+
// unlike other triggers, we need to send this one to the client
// unless is a spectator trigger
if( self->spawnflags & 1 )
@@ -407,11 +415,12 @@ void SP_trigger_hurt( gentity_t *self )
self->r.contents = CONTENTS_TRIGGER;
- if( self->spawnflags & 2 )
- self->use = hurt_use;
+ self->use = hurt_use;
// link in to the world if starting active
- if( !( self->spawnflags & 1 ) )
+ if( self->spawnflags & 1 )
+ trap_UnlinkEntity( self );
+ else
trap_LinkEntity( self );
}
@@ -469,7 +478,7 @@ void SP_func_timer( gentity_t *self )
if( self->random >= self->wait )
{
self->random = self->wait - FRAMETIME;
- G_Printf( "func_timer at %s has random >= wait\n", vtos( self->s.origin ) );
+ G_Printf( "func_timer at %s has random >= wait\n", vtos( self->r.currentOrigin ) );
}
if( self->spawnflags & 1 )
@@ -489,7 +498,7 @@ G_Checktrigger_stages
Called when stages change
===============
*/
-void G_Checktrigger_stages( pTeam_t team, stage_t stage )
+void G_Checktrigger_stages( team_t team, stage_t stage )
{
int i;
gentity_t *ent;
@@ -558,6 +567,9 @@ qboolean trigger_buildable_match( gentity_t *self, gentity_t *activator )
{
int i = 0;
+ if( !activator )
+ return qfalse;
+
//if there is no buildable list every buildable triggers
if( self->bTriggers[ i ] == BA_NONE )
return qtrue;
@@ -592,26 +604,18 @@ void trigger_buildable_trigger( gentity_t *self, gentity_t *activator )
if( self->s.eFlags & EF_DEAD )
{
if( !trigger_buildable_match( self, activator ) )
+ {
G_UseTargets( self, activator );
+ trigger_check_wait( self );
+ }
}
else
{
if( trigger_buildable_match( self, activator ) )
+ {
G_UseTargets( self, activator );
- }
-
- if( self->wait > 0 )
- {
- self->think = multi_wait;
- self->nextthink = level.time + ( self->wait + self->random * crandom( ) ) * 1000;
- }
- else
- {
- // we can't just remove (self) here, because this is a touch function
- // called while looping through area links...
- self->touch = 0;
- self->nextthink = level.time + FRAMETIME;
- self->think = G_FreeEntity;
+ trigger_check_wait( self );
+ }
}
}
@@ -686,6 +690,9 @@ qboolean trigger_class_match( gentity_t *self, gentity_t *activator )
{
int i = 0;
+ if( !activator )
+ return qfalse;
+
//if there is no class list every class triggers (stupid case)
if( self->cTriggers[ i ] == PCL_NONE )
return qtrue;
@@ -694,7 +701,7 @@ qboolean trigger_class_match( gentity_t *self, gentity_t *activator )
//otherwise check against the list
for( i = 0; self->cTriggers[ i ] != PCL_NONE; i++ )
{
- if( activator->client->ps.stats[ STAT_PCLASS ] == self->cTriggers[ i ] )
+ if( activator->client->ps.stats[ STAT_CLASS ] == self->cTriggers[ i ] )
return qtrue;
}
}
@@ -710,10 +717,10 @@ trigger_class_trigger
void trigger_class_trigger( gentity_t *self, gentity_t *activator )
{
//sanity check
- if( !activator->client )
+ if( !activator || !activator->client )
return;
- if( activator->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS )
+ if( activator->client->ps.stats[ STAT_TEAM ] != TEAM_ALIENS )
return;
if( self->s.eFlags & EF_NODRAW )
@@ -726,27 +733,20 @@ void trigger_class_trigger( gentity_t *self, gentity_t *activator )
if( self->s.eFlags & EF_DEAD )
{
if( !trigger_class_match( self, activator ) )
+ {
G_UseTargets( self, activator );
+ trigger_check_wait( self );
+ }
}
else
{
if( trigger_class_match( self, activator ) )
+ {
G_UseTargets( self, activator );
+ trigger_check_wait( self );
+ }
}
- if( self->wait > 0 )
- {
- self->think = multi_wait;
- self->nextthink = level.time + ( self->wait + self->random * crandom( ) ) * 1000;
- }
- else
- {
- // we can't just remove (self) here, because this is a touch function
- // called while looping through area links...
- self->touch = 0;
- self->nextthink = level.time + FRAMETIME;
- self->think = G_FreeEntity;
- }
}
/*
@@ -820,6 +820,9 @@ qboolean trigger_equipment_match( gentity_t *self, gentity_t *activator )
{
int i = 0;
+ if( !activator )
+ return qfalse;
+
//if there is no equipment list all equipment triggers (stupid case)
if( self->wTriggers[ i ] == WP_NONE && self->uTriggers[ i ] == UP_NONE )
return qtrue;
@@ -850,10 +853,10 @@ trigger_equipment_trigger
void trigger_equipment_trigger( gentity_t *self, gentity_t *activator )
{
//sanity check
- if( !activator->client )
+ if( !activator || !activator->client )
return;
- if( activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
+ if( activator->client->ps.stats[ STAT_TEAM ] != TEAM_HUMANS )
return;
if( self->s.eFlags & EF_NODRAW )
@@ -866,26 +869,18 @@ void trigger_equipment_trigger( gentity_t *self, gentity_t *activator )
if( self->s.eFlags & EF_DEAD )
{
if( !trigger_equipment_match( self, activator ) )
+ {
G_UseTargets( self, activator );
+ trigger_check_wait( self );
+ }
}
else
{
if( trigger_equipment_match( self, activator ) )
+ {
G_UseTargets( self, activator );
- }
-
- if( self->wait > 0 )
- {
- self->think = multi_wait;
- self->nextthink = level.time + ( self->wait + self->random * crandom( ) ) * 1000;
- }
- else
- {
- // we can't just remove (self) here, because this is a touch function
- // called while looping through area links...
- self->touch = 0;
- self->nextthink = level.time + FRAMETIME;
- self->think = G_FreeEntity;
+ trigger_check_wait( self );
+ }
}
}
@@ -1061,7 +1056,9 @@ void SP_trigger_heal( gentity_t *self )
InitTrigger( self );
// link in to the world if starting active
- if( !( self->spawnflags & 1 ) )
+ if( self->spawnflags & 1 )
+ trap_UnlinkEntity( self );
+ else
trap_LinkEntity( self );
}
@@ -1073,12 +1070,13 @@ trigger_ammo_touch
*/
void trigger_ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace )
{
- int ammo, clips, maxClips, maxAmmo;
+ int maxClips, maxAmmo;
+ weapon_t weapon;
if( !other->client )
return;
- if( other->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
+ if( other->client->ps.stats[ STAT_TEAM ] != TEAM_HUMANS )
return;
if( self->timestamp > level.time )
@@ -1087,10 +1085,11 @@ void trigger_ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace )
if( other->client->ps.weaponstate != WEAPON_READY )
return;
- if( BG_FindUsesEnergyForWeapon( other->client->ps.weapon ) && self->spawnflags & 2 )
+ weapon = other->client->ps.stats[ STAT_WEAPON ];
+ if( BG_Weapon( weapon )->usesEnergy && self->spawnflags & 2 )
return;
- if( !BG_FindUsesEnergyForWeapon( other->client->ps.weapon ) && self->spawnflags & 4 )
+ if( !BG_Weapon( weapon )->usesEnergy && self->spawnflags & 4 )
return;
if( self->spawnflags & 1 )
@@ -1098,25 +1097,21 @@ void trigger_ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace )
else
self->timestamp = level.time + FRAMETIME;
- BG_FindAmmoForWeapon( other->client->ps.weapon, &maxAmmo, &maxClips );
- ammo = other->client->ps.ammo;
- clips = other->client->ps.clips;
+ maxAmmo = BG_Weapon( weapon )->maxAmmo;
+ maxClips = BG_Weapon( weapon )->maxClips;
- if( ( ammo + self->damage ) > maxAmmo )
+ if( ( other->client->ps.ammo + self->damage ) > maxAmmo )
{
- if( clips < maxClips )
+ if( other->client->ps.clips < maxClips )
{
- clips++;
- ammo = 1;
+ other->client->ps.clips++;
+ other->client->ps.ammo = 1;
}
else
- ammo = maxAmmo;
+ other->client->ps.ammo = maxAmmo;
}
else
- ammo += self->damage;
-
- other->client->ps.ammo = ammo;
- other->client->ps.clips = clips;
+ other->client->ps.ammo += self->damage;
}
/*
diff --git a/src/game/g_utils.c b/src/game/g_utils.c
index a74df3f..5c74188 100644
--- a/src/game/g_utils.c
+++ b/src/game/g_utils.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -93,7 +94,7 @@ G_FindConfigstringIndex
================
*/
-int G_FindConfigstringIndex( char *name, int start, int max, qboolean create )
+int G_FindConfigstringIndex( const char *name, int start, int max, qboolean create )
{
int i;
char s[ MAX_STRING_CHARS ];
@@ -122,55 +123,28 @@ int G_FindConfigstringIndex( char *name, int start, int max, qboolean create )
return i;
}
-//TA: added ParticleSystemIndex
-int G_ParticleSystemIndex( char *name )
+int G_ParticleSystemIndex( const char *name )
{
return G_FindConfigstringIndex( name, CS_PARTICLE_SYSTEMS, MAX_GAME_PARTICLE_SYSTEMS, qtrue );
}
-//TA: added ShaderIndex
-int G_ShaderIndex( char *name )
+int G_ShaderIndex( const char *name )
{
return G_FindConfigstringIndex( name, CS_SHADERS, MAX_GAME_SHADERS, qtrue );
}
-int G_ModelIndex( char *name )
+int G_ModelIndex( const char *name )
{
return G_FindConfigstringIndex( name, CS_MODELS, MAX_MODELS, qtrue );
}
-int G_SoundIndex( char *name )
+int G_SoundIndex( const char *name )
{
return G_FindConfigstringIndex( name, CS_SOUNDS, MAX_SOUNDS, qtrue );
}
//=====================================================================
-
-/*
-================
-G_TeamCommand
-
-Broadcasts a command to only a specific team
-================
-*/
-void G_TeamCommand( pTeam_t team, char *cmd )
-{
- int i;
-
- for( i = 0 ; i < level.maxclients ; i++ )
- {
- if( level.clients[ i ].pers.connected == CON_CONNECTED )
- {
- if( level.clients[ i ].pers.teamSelection == team ||
- ( level.clients[ i ].pers.teamSelection == PTE_NONE &&
- G_admin_permission( &g_entities[ i ], ADMF_SPEC_ALLCHAT ) ) )
- trap_SendServerCommand( i, cmd );
- }
- }
-}
-
-
/*
=============
G_Find
@@ -249,7 +223,7 @@ gentity_t *G_PickTarget( char *targetname )
return NULL;
}
- return choice[ rand( ) % num_choices ];
+ return choice[ rand( ) / ( RAND_MAX / num_choices + 1 ) ];
}
@@ -268,9 +242,6 @@ void G_UseTargets( gentity_t *ent, gentity_t *activator )
{
gentity_t *t;
- if( !ent )
- return;
-
if( ent->targetShaderName && ent->targetShaderNewName )
{
float f = level.time * 0.001;
@@ -505,7 +476,6 @@ qboolean G_EntitiesFree( void )
return qfalse;
}
-
/*
=================
G_FreeEntity
@@ -528,6 +498,181 @@ void G_FreeEntity( gentity_t *ent )
/*
=================
+G_RemoveEntity
+
+Safely remove an entity, perform reasonable cleanup logic
+=================
+*/
+void G_RemoveEntity( gentity_t *ent )
+{
+ gentity_t *e;
+
+ if( ent->client )
+ {
+ // removing a player causes the player to "unspawn"
+ class_t class = ent->client->pers.classSelection; // back up the spawn queue choice
+ weapon_t weapon = ent->client->pers.humanItemSelection; // back up
+ ent->client->pers.classSelection = PCL_NONE;
+ ent->client->pers.humanItemSelection = WP_NONE;
+ ent->suicideTime = 0; // cancel any timed suicides
+ ClientSpawn( ent, NULL, NULL, NULL );
+ ent->client->pers.classSelection = class; // restore the spawn queue choice
+ ent->client->pers.humanItemSelection = weapon; // restore
+ return;
+ }
+ else if( ent->s.eType == ET_RANGE_MARKER )
+ {
+ for( e = &g_entities[ MAX_CLIENTS ]; e < &g_entities[ level.num_entities ]; ++e )
+ {
+ if( e->rangeMarker == ent )
+ {
+ // clear the buildable's reference to this range marker
+ e->rangeMarker = NULL;
+ break;
+ }
+ }
+ }
+ else if( ent->s.eType == ET_BUILDABLE )
+ {
+ // the range marker (if any) goes away with the buildable
+ G_RemoveRangeMarkerFrom( ent );
+ }
+ else if( !strcmp( ent->classname, "lev2zapchain" ) )
+ {
+ zap_t *z;
+ for( z = &zaps[ 0 ]; z < &zaps[ MAX_ZAPS ]; ++z )
+ {
+ if( z->used && z->effectChannel == ent )
+ {
+ // free the zap slot occupied by this zap effect
+ z->used = qfalse;
+ break;
+ }
+ }
+ }
+ else if( ent->s.eType == ET_MOVER )
+ {
+ if( !strcmp( ent->classname, "func_door" ) ||
+ !strcmp( ent->classname, "func_door_rotating" ) ||
+ !strcmp( ent->classname, "func_door_model" ) ||
+ !strcmp( ent->classname, "func_door_model_clip_brush" ) ||
+ !strcmp( ent->classname, "func_plat" ) )
+ {
+ // each func_door_model entity is paired with a clip brush, remove the other
+ if( ent->clipBrush != NULL )
+ G_FreeEntity( ent->clipBrush );
+ for( e = &g_entities[ MAX_CLIENTS ]; e < &g_entities[ level.num_entities ]; ++e )
+ {
+ if( e->parent == ent )
+ {
+ // this mover has a trigger area brush
+ if( ent->teammaster != NULL && ent->teammaster->teamchain != NULL )
+ {
+ // the mover is part of a team of at least 2
+ e->parent = ent->teammaster->teamchain; // hand the brush over to the next mover in command
+ }
+ else
+ G_FreeEntity( e ); // remove the teamless or to-be-orphaned brush
+ break;
+ }
+ }
+ }
+ // removing a mover opens the relevant portal
+ trap_AdjustAreaPortalState( ent, qtrue );
+ }
+ else if( !strcmp( ent->classname, "path_corner" ) )
+ {
+ for( e = &g_entities[ MAX_CLIENTS ]; e < &g_entities[ level.num_entities ]; ++e )
+ {
+ if( e->nextTrain == ent )
+ e->nextTrain = ent->nextTrain; // redirect func_train and path_corner entities
+ }
+ }
+ else if( !strcmp( ent->classname, "info_player_intermission" ) ||
+ !strcmp( ent->classname, "info_player_deathmatch" ) )
+ {
+ for( e = &g_entities[ MAX_CLIENTS ]; e < &g_entities[ level.num_entities ]; ++e )
+ {
+ if( e->inuse && e != ent &&
+ ( !strcmp( e->classname, "info_player_intermission" ) ||
+ !strcmp( e->classname, "info_player_deathmatch" ) ) )
+ {
+ break;
+ }
+ }
+ // refuse to remove the last info_player_intermission/info_player_deathmatch entity
+ // (because it is required for initial camera placement)
+ if( e >= &g_entities[ level.num_entities ] )
+ return;
+ }
+ else if( !strcmp( ent->classname, "target_location" ) )
+ {
+ if( ent == level.locationHead )
+ level.locationHead = ent->nextTrain;
+ else
+ {
+ for( e = level.locationHead; e != NULL; e = e->nextTrain )
+ {
+ if( e->nextTrain == ent )
+ {
+ e->nextTrain = ent->nextTrain;
+ break;
+ }
+ }
+ }
+ }
+ else if( !Q_stricmp( ent->classname, "misc_portal_camera" ) )
+ {
+ for( e = &g_entities[ MAX_CLIENTS ]; e < &g_entities[ level.num_entities ]; ++e )
+ {
+ if( e->r.ownerNum == ent - g_entities )
+ {
+ // disown the surface
+ e->r.ownerNum = ENTITYNUM_NONE;
+ }
+ }
+ }
+
+ if( ent->teammaster != NULL )
+ {
+ // this entity is part of a mover team
+ if( ent == ent->teammaster )
+ {
+ // the entity is the master
+ gentity_t *snd = ent->teamchain;
+ for( e = snd; e != NULL; e = e->teamchain )
+ e->teammaster = snd; // put the 2nd entity (if any) in command
+ if( snd )
+ {
+ if( !strcmp( ent->classname, snd->classname ) )
+ {
+ // transfer certain activity properties
+ snd->think = ent->think;
+ snd->nextthink = ent->nextthink;
+ }
+ snd->flags &= ~FL_TEAMSLAVE; // put the 2nd entity (if any) in command
+ }
+ }
+ else
+ {
+ // the entity is a slave
+ for( e = ent->teammaster; e != NULL; e = e->teamchain )
+ {
+ if( e->teamchain == ent )
+ {
+ // unlink it from the chain
+ e->teamchain = ent->teamchain;
+ break;
+ }
+ }
+ }
+ }
+
+ G_FreeEntity( ent );
+}
+
+/*
+=================
G_TempEntity
Spawns an event entity that will be auto-removed
@@ -535,7 +680,7 @@ The origin will be snapped to save net bandwidth, so care
must be taken if the origin is right on a surface (snap towards start vector first)
=================
*/
-gentity_t *G_TempEntity( vec3_t origin, int event )
+gentity_t *G_TempEntity( const vec3_t origin, int event )
{
gentity_t *e;
vec3_t snapped;
@@ -582,18 +727,18 @@ void G_KillBox( gentity_t *ent )
gentity_t *hit;
vec3_t mins, maxs;
- VectorAdd( ent->client->ps.origin, ent->r.mins, mins );
- VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs );
+ VectorAdd( ent->r.currentOrigin, ent->r.mins, mins );
+ VectorAdd( ent->r.currentOrigin, ent->r.maxs, maxs );
num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
for( i = 0; i < num; i++ )
{
hit = &g_entities[ touch[ i ] ];
- if( !hit->client )
+ if( ent->client && !hit->client ) // players can telefrag only other players
continue;
- //TA: impossible to telefrag self
+ // impossible to telefrag self
if( ent == hit )
continue;
@@ -644,8 +789,8 @@ void G_AddEvent( gentity_t *ent, int event, int eventParm )
// eventParm is converted to uint8_t (0 - 255) in msg.c
if( eventParm & ~0xFF )
{
- G_Printf( S_COLOR_YELLOW "WARNING: G_AddEvent: event %d "
- " eventParm uint8_t overflow (given %d)\n", event, eventParm );
+ G_Printf( S_COLOR_YELLOW "WARNING: G_AddEvent( %s ) has eventParm %d, "
+ "which will overflow\n", BG_EventName( event ), eventParm );
}
// clients need to add the event in playerState_t instead of entityState_t
@@ -728,7 +873,7 @@ G_SetOrigin
Sets the pos trajectory for a fixed position
================
*/
-void G_SetOrigin( gentity_t *ent, vec3_t origin )
+void G_SetOrigin( gentity_t *ent, const vec3_t origin )
{
VectorCopy( origin, ent->s.pos.trBase );
ent->s.pos.trType = TR_STATIONARY;
@@ -737,10 +882,9 @@ void G_SetOrigin( gentity_t *ent, vec3_t origin )
VectorClear( ent->s.pos.trDelta );
VectorCopy( origin, ent->r.currentOrigin );
- VectorCopy( origin, ent->s.origin ); //TA: if shit breaks - blame this line
}
-//TA: from quakestyle.telefragged.com
+// from quakestyle.telefragged.com
// (NOBODY): Code helper function
//
gentity_t *G_FindRadius( gentity_t *from, vec3_t org, float rad )
@@ -777,16 +921,14 @@ G_Visible
Test for a LOS between two entities
===============
*/
-qboolean G_Visible( gentity_t *ent1, gentity_t *ent2 )
+qboolean G_Visible( gentity_t *ent1, gentity_t *ent2, int contents )
{
trace_t trace;
- trap_Trace( &trace, ent1->s.pos.trBase, NULL, NULL, ent2->s.pos.trBase, ent1->s.number, MASK_SHOT );
-
- if( trace.contents & CONTENTS_SOLID )
- return qfalse;
+ trap_Trace( &trace, ent1->s.pos.trBase, NULL, NULL, ent2->s.pos.trBase,
+ ent1->s.number, contents );
- return qtrue;
+ return trace.fraction >= 1.0f || trace.entityNum == ent2 - g_entities;
}
/*
@@ -799,15 +941,21 @@ Test a list of entities for the closest to a particular point
gentity_t *G_ClosestEnt( vec3_t origin, gentity_t **entities, int numEntities )
{
int i;
- float nd, d = 1000000.0f;
- gentity_t *closestEnt = NULL;
+ float nd, d;
+ gentity_t *closestEnt;
+
+ if( numEntities <= 0 )
+ return NULL;
+
+ closestEnt = entities[ 0 ];
+ d = DistanceSquared( origin, closestEnt->r.currentOrigin );
- for( i = 0; i < numEntities; i++ )
+ for( i = 1; i < numEntities; i++ )
{
gentity_t *ent = entities[ i ];
- nd = DistanceSquared( origin, ent->s.origin );
- if( i == 0 || nd < d )
+ nd = DistanceSquared( origin, ent->r.currentOrigin );
+ if( nd < d )
{
d = nd;
closestEnt = ent;
@@ -828,10 +976,24 @@ void G_TriggerMenu( int clientNum, dynMenu_t menu )
{
char buffer[ 32 ];
- Com_sprintf( buffer, 32, "servermenu %d", menu );
+ Com_sprintf( buffer, sizeof( buffer ), "servermenu %d", menu );
trap_SendServerCommand( clientNum, buffer );
}
+/*
+===============
+G_TriggerMenuArgs
+
+Trigger a menu on some client and passes an argument
+===============
+*/
+void G_TriggerMenuArgs( int clientNum, dynMenu_t menu, int arg )
+{
+ char buffer[ 64 ];
+
+ Com_sprintf( buffer, sizeof( buffer ), "servermenu %d %d", menu, arg );
+ trap_SendServerCommand( clientNum, buffer );
+}
/*
===============
@@ -847,3 +1009,179 @@ void G_CloseMenus( int clientNum )
Com_sprintf( buffer, 32, "serverclosemenus" );
trap_SendServerCommand( clientNum, buffer );
}
+
+
+/*
+===============
+G_AddressParse
+
+Make an IP address more usable
+===============
+*/
+static const char *addr4parse( const char *str, addr_t *addr )
+{
+ int i;
+ int octet = 0;
+ int num = 0;
+ memset( addr, 0, sizeof( addr_t ) );
+ addr->type = IPv4;
+ for( i = 0; octet < 4; i++ )
+ {
+ if( isdigit( str[ i ] ) )
+ num = num * 10 + str[ i ] - '0';
+ else
+ {
+ if( num < 0 || num > 255 )
+ return NULL;
+ addr->addr[ octet ] = (byte)num;
+ octet++;
+ if( str[ i ] != '.' || str[ i + 1 ] == '.' )
+ break;
+ num = 0;
+ }
+ }
+ if( octet < 1 )
+ return NULL;
+ return str + i;
+}
+
+static const char *addr6parse( const char *str, addr_t *addr )
+{
+ int i;
+ qboolean seen = qfalse;
+ /* keep track of the parts before and after the ::
+ it's either this or even uglier hacks */
+ byte a[ ADDRLEN ], b[ ADDRLEN ];
+ size_t before = 0, after = 0;
+ int num = 0;
+ /* 8 hexadectets unless :: is present */
+ for( i = 0; before + after <= 8; i++ )
+ {
+ //num = num << 4 | str[ i ] - '0';
+ if( isdigit( str[ i ] ) )
+ num = num * 16 + str[ i ] - '0';
+ else if( str[ i ] >= 'A' && str[ i ] <= 'F' )
+ num = num * 16 + 10 + str[ i ] - 'A';
+ else if( str[ i ] >= 'a' && str[ i ] <= 'f' )
+ num = num * 16 + 10 + str[ i ] - 'a';
+ else
+ {
+ if( num < 0 || num > 65535 )
+ return NULL;
+ if( i == 0 )
+ {
+ //
+ }
+ else if( seen ) // :: has been seen already
+ {
+ b[ after * 2 ] = num >> 8;
+ b[ after * 2 + 1 ] = num & 0xff;
+ after++;
+ }
+ else
+ {
+ a[ before * 2 ] = num >> 8;
+ a[ before * 2 + 1 ] = num & 0xff;
+ before++;
+ }
+ if( !str[ i ] )
+ break;
+ if( str[ i ] != ':' || before + after == 8 )
+ break;
+ if( str[ i + 1 ] == ':' )
+ {
+ // ::: or multiple ::
+ if( seen || str[ i + 2 ] == ':' )
+ break;
+ seen = qtrue;
+ i++;
+ }
+ else if( i == 0 ) // starts with : but not ::
+ return NULL;
+ num = 0;
+ }
+ }
+ if( seen )
+ {
+ // there have to be fewer than 8 hexadectets when :: is present
+ if( before + after == 8 )
+ return NULL;
+ }
+ else if( before + after < 8 ) // require exactly 8 hexadectets
+ return NULL;
+ memset( addr, 0, sizeof( addr_t ) );
+ addr->type = IPv6;
+ if( before )
+ memcpy( addr->addr, a, before * 2 );
+ if( after )
+ memcpy( addr->addr + ADDRLEN - 2 * after, b, after * 2 );
+ return str + i;
+}
+
+qboolean G_AddressParse( const char *str, addr_t *addr )
+{
+ const char *p;
+ int max;
+ if( strchr( str, ':' ) )
+ {
+ p = addr6parse( str, addr );
+ max = 128;
+ }
+ else if( strchr( str, '.' ) )
+ {
+ p = addr4parse( str, addr );
+ max = 32;
+ }
+ else
+ return qfalse;
+ Q_strncpyz( addr->str, str, sizeof( addr->str ) );
+ if( !p )
+ return qfalse;
+ if( *p == '/' )
+ {
+ addr->mask = atoi( p + 1 );
+ if( addr->mask < 1 || addr->mask > max )
+ addr->mask = max;
+ }
+ else
+ {
+ if( *p )
+ return qfalse;
+ addr->mask = max;
+ }
+ return qtrue;
+}
+
+/*
+===============
+G_AddressCompare
+
+Based largely on NET_CompareBaseAdrMask from ioq3 revision 1557
+===============
+*/
+qboolean G_AddressCompare( const addr_t *a, const addr_t *b )
+{
+ int i, netmask;
+ if( a->type != b->type )
+ return qfalse;
+ netmask = a->mask;
+ if( a->type == IPv4 )
+ {
+ if( netmask < 1 || netmask > 32 )
+ netmask = 32;
+ }
+ else if( a->type == IPv6 )
+ {
+ if( netmask < 1 || netmask > 128 )
+ netmask = 128;
+ }
+ for( i = 0; netmask > 7; i++, netmask -= 8 )
+ if( a->addr[ i ] != b->addr[ i ] )
+ return qfalse;
+ if( netmask )
+ {
+ netmask = ( ( 1 << netmask ) - 1 ) << ( 8 - netmask );
+ return ( a->addr[ i ] & netmask ) == ( b->addr[ i ] & netmask );
+ }
+ return qtrue;
+}
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index ddad4af..302c47e 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -36,51 +37,24 @@ G_ForceWeaponChange
*/
void G_ForceWeaponChange( gentity_t *ent, weapon_t weapon )
{
- int i;
-
- if( !ent )
- return;
-
- if( ent->client->ps.weaponstate == WEAPON_RELOADING )
- {
- ent->client->ps.torsoAnim = ( ( ent->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | TORSO_RAISE;
- ent->client->ps.weaponTime = 250;
- ent->client->ps.weaponstate = WEAPON_READY;
- }
-
- ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH;
+ playerState_t *ps = &ent->client->ps;
- if( weapon == WP_NONE
- || !BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ))
+ // stop a reload in progress
+ if( ps->weaponstate == WEAPON_RELOADING )
{
- //switch to the first non blaster weapon
- for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
- {
- if( i == WP_BLASTER )
- continue;
-
- if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) )
- {
- ent->client->ps.persistant[ PERS_NEWWEAPON ] = i;
- break;
- }
- }
-
- //only got the blaster to switch to
- if( i == WP_NUM_WEAPONS )
- ent->client->ps.persistant[ PERS_NEWWEAPON ] = WP_BLASTER;
+ ps->torsoAnim = ( ( ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | TORSO_RAISE;
+ ps->weaponTime = 250;
+ ps->weaponstate = WEAPON_READY;
}
- else
- ent->client->ps.persistant[ PERS_NEWWEAPON ] = weapon;
- // Lak: The following hack has been moved to PM_BeginWeaponChange, but I'm going to
- // redundantly leave it here as well just in case there's a case I'm forgetting
- // because I don't want to face the gameplay consequences such an error would have
+ ps->persistant[ PERS_NEWWEAPON ] = ( weapon == WP_BLASTER ) ?
+ WP_BLASTER : ps->stats[ STAT_WEAPON ];
// force this here to prevent flamer effect from continuing
- ent->client->ps.generic1 = WPM_NOTFIRING;
+ ps->generic1 = WPM_NOTFIRING;
- ent->client->ps.weapon = ent->client->ps.persistant[ PERS_NEWWEAPON ];
+ // The PMove will do an animated drop, raise, and set the new weapon
+ ps->pm_flags |= PMF_WEAPON_SWITCH;
}
/*
@@ -90,43 +64,35 @@ G_GiveClientMaxAmmo
*/
void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo )
{
- int i;
- int maxAmmo, maxClips;
- qboolean weaponType, restoredAmmo = qfalse;
+ int maxAmmo;
+ weapon_t weapon = ent->client->ps.stats[ STAT_WEAPON ];
- // GH FIXME
+ if( BG_Weapon( weapon )->infiniteAmmo )
+ return;
- for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
- {
- if( buyingEnergyAmmo )
- weaponType = BG_FindUsesEnergyForWeapon( i );
- else
- weaponType = !BG_FindUsesEnergyForWeapon( i );
+ if( buyingEnergyAmmo && !BG_Weapon( weapon )->usesEnergy )
+ return;
- if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) &&
- weaponType && !BG_FindInfinteAmmoForWeapon( i ) &&
- !BG_WeaponIsFull( i, ent->client->ps.stats,
- ent->client->ps.ammo, ent->client->ps.clips ) )
- {
- BG_FindAmmoForWeapon( i, &maxAmmo, &maxClips );
+ if( BG_WeaponIsFull( weapon, ent->client->ps.stats, ent->client->ps.ammo,
+ ent->client->ps.clips ) )
+ return;
- if( buyingEnergyAmmo )
- {
- G_AddEvent( ent, EV_RPTUSE_SOUND, 0 );
+ maxAmmo = BG_Weapon( weapon )->maxAmmo;
- if( BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) )
- maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
- }
+ // Apply battery pack modifier
+ if( BG_Weapon( weapon )->usesEnergy &&
+ BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) )
+ {
+ maxAmmo *= BATTPACK_MODIFIER;
+ }
- ent->client->ps.ammo = maxAmmo;
- ent->client->ps.clips = maxClips;
+ ent->client->ps.ammo = maxAmmo;
+ ent->client->ps.clips = BG_Weapon( weapon )->maxClips;
- restoredAmmo = qtrue;
- }
- }
+ G_ForceWeaponChange( ent, ent->client->ps.weapon );
- if( restoredAmmo )
- G_ForceWeaponChange( ent, ent->client->ps.weapon );
+ if( BG_Weapon( weapon )->usesEnergy )
+ G_AddEvent( ent, EV_RPTUSE_SOUND, 0 );
}
/*
@@ -155,50 +121,46 @@ Trace a bounding box against entities, but not the world
Also check there is a line of sight between the start and end point
================
*/
-static void G_WideTrace( trace_t *tr, gentity_t *ent, float range, float width, gentity_t **target )
+static void G_WideTrace( trace_t *tr, gentity_t *ent, float range,
+ float width, float height, gentity_t **target )
{
vec3_t mins, maxs;
vec3_t end;
- VectorSet( mins, -width, -width, -width );
- VectorSet( maxs, width, width, width );
+ VectorSet( mins, -width, -width, -height );
+ VectorSet( maxs, width, width, height );
*target = NULL;
if( !ent->client )
return;
- // Set aiming directions
- AngleVectors( ent->client->ps.viewangles, forward, right, up );
- CalcMuzzlePoint( ent, forward, right, up, muzzle );
- VectorMA( muzzle, range, forward, end );
+ G_UnlaggedOn( ent, muzzle, range + width );
- G_UnlaggedOn( ent, muzzle, range );
+ VectorMA( muzzle, range, forward, end );
// Trace against entities
trap_Trace( tr, muzzle, mins, maxs, end, ent->s.number, CONTENTS_BODY );
if( tr->entityNum != ENTITYNUM_NONE )
- {
*target = &g_entities[ tr->entityNum ];
- // Set range to the trace length plus the width, so that the end of the
- // LOS trace is close to the exterior of the target's bounding box
- range = Distance( muzzle, tr->endpos ) + width;
- VectorMA( muzzle, range, forward, end );
+ // Set range to the trace length plus the width, so that the end of the
+ // LOS trace is close to the exterior of the target's bounding box
+ range = Distance( muzzle, tr->endpos ) + width;
+ VectorMA( muzzle, range, forward, end );
- // Trace for line of sight against the world
- trap_Trace( tr, muzzle, NULL, NULL, end, 0, CONTENTS_SOLID );
- if( tr->fraction < 1.0f )
- *target = NULL;
- }
+ // Trace for line of sight against the world
+ trap_Trace( tr, muzzle, NULL, NULL, end, ent->s.number, CONTENTS_SOLID );
+ if( tr->entityNum != ENTITYNUM_NONE )
+ *target = &g_entities[ tr->entityNum ];
G_UnlaggedOff( );
}
-
/*
======================
SnapVectorTowards
+SnapVectorNormal
Round a vector to integers for more efficient network
transmission, but make sure that it rounds towards a given point
@@ -212,57 +174,120 @@ void SnapVectorTowards( vec3_t v, vec3_t to )
for( i = 0 ; i < 3 ; i++ )
{
- if( to[ i ] <= v[ i ] )
- v[ i ] = (int)v[ i ];
+ if( v[ i ] >= 0 )
+ v[ i ] = (int)( v[ i ] + ( to[ i ] <= v[ i ] ? 0 : 1 ) );
+ else
+ v[ i ] = (int)( v[ i ] + ( to[ i ] <= v[ i ] ? -1 : 0 ) );
+ }
+}
+
+void SnapVectorNormal( vec3_t v, vec3_t normal )
+{
+ int i;
+
+ for( i = 0 ; i < 3 ; i++ )
+ {
+ if( v[ i ] >= 0 )
+ v[ i ] = (int)( v[ i ] + ( normal[ i ] <= 0 ? 0 : 1 ) );
else
- v[ i ] = (int)v[ i ] + 1;
+ v[ i ] = (int)( v[ i ] + ( normal[ i ] <= 0 ? -1 : 0 ) );
}
}
/*
===============
-meleeAttack
+BloodSpurt
+
+Generates a blood spurt event for traces with accurate end points
===============
*/
-void meleeAttack( gentity_t *ent, float range, float width, int damage, meansOfDeath_t mod )
+static void BloodSpurt( gentity_t *attacker, gentity_t *victim, trace_t *tr )
{
- trace_t tr;
- vec3_t end;
gentity_t *tent;
- gentity_t *traceEnt;
- vec3_t mins, maxs;
- VectorSet( mins, -width, -width, -width );
- VectorSet( maxs, width, width, width );
+ if( !attacker->client )
+ return;
- // set aiming directions
- AngleVectors( ent->client->ps.viewangles, forward, right, up );
+ if( victim->health <= 0 )
+ return;
- CalcMuzzlePoint( ent, forward, right, up, muzzle );
+ tent = G_TempEntity( tr->endpos, EV_MISSILE_HIT );
+ tent->s.otherEntityNum = victim->s.number;
+ tent->s.eventParm = DirToByte( tr->plane.normal );
+ tent->s.weapon = attacker->s.weapon;
+ tent->s.generic1 = attacker->s.generic1; // weaponMode
+}
- VectorMA( muzzle, range, forward, end );
+/*
+===============
+WideBloodSpurt
- G_UnlaggedOn( ent, muzzle, range );
- trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT );
- G_UnlaggedOff( );
+Calculates the position of a blood spurt for wide traces and generates an event
+===============
+*/
+static void WideBloodSpurt( gentity_t *attacker, gentity_t *victim, trace_t *tr )
+{
+ gentity_t *tent;
+ vec3_t normal, origin;
+ float mag, radius;
- if( tr.surfaceFlags & SURF_NOIMPACT )
+ if( !attacker->client )
return;
- traceEnt = &g_entities[ tr.entityNum ];
+ if( victim->health <= 0 )
+ return;
- // send blood impact
- if( traceEnt->takedamage && traceEnt->client )
+ if( tr )
+ VectorSubtract( tr->endpos, victim->r.currentOrigin, normal );
+ else
+ VectorSubtract( attacker->client->ps.origin,
+ victim->r.currentOrigin, normal );
+
+ // Normalize the horizontal components of the vector difference to the
+ // "radius" of the bounding box
+ mag = sqrt( normal[ 0 ] * normal[ 0 ] + normal[ 1 ] * normal[ 1 ] );
+ radius = victim->r.maxs[ 0 ] * 1.21f;
+ if( mag > radius )
{
- tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
- tent->s.otherEntityNum = traceEnt->s.number;
- tent->s.eventParm = DirToByte( tr.plane.normal );
- tent->s.weapon = ent->s.weapon;
- tent->s.generic1 = ent->s.generic1; //weaponMode
+ normal[ 0 ] = normal[ 0 ] / mag * radius;
+ normal[ 1 ] = normal[ 1 ] / mag * radius;
}
- if( traceEnt->takedamage )
- G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, mod );
+ // Clamp origin to be within bounding box vertically
+ if( normal[ 2 ] > victim->r.maxs[ 2 ] )
+ normal[ 2 ] = victim->r.maxs[ 2 ];
+ if( normal[ 2 ] < victim->r.mins[ 2 ] )
+ normal[ 2 ] = victim->r.mins[ 2 ];
+
+ VectorAdd( victim->r.currentOrigin, normal, origin );
+ VectorNegate( normal, normal );
+ VectorNormalize( normal );
+
+ // Create the blood spurt effect entity
+ tent = G_TempEntity( origin, EV_MISSILE_HIT );
+ tent->s.eventParm = DirToByte( normal );
+ tent->s.otherEntityNum = victim->s.number;
+ tent->s.weapon = attacker->s.weapon;
+ tent->s.generic1 = attacker->s.generic1; // weaponMode
+}
+
+/*
+===============
+meleeAttack
+===============
+*/
+void meleeAttack( gentity_t *ent, float range, float width, float height,
+ int damage, meansOfDeath_t mod )
+{
+ trace_t tr;
+ gentity_t *traceEnt;
+
+ G_WideTrace( &tr, ent, range, width, height, &traceEnt );
+ if( traceEnt == NULL || !traceEnt->takedamage )
+ return;
+
+ WideBloodSpurt( ent, traceEnt, &tr );
+ G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, mod );
}
/*
@@ -308,7 +333,9 @@ void bulletFire( gentity_t *ent, float spread, int damage, int mod )
SnapVectorTowards( tr.endpos, muzzle );
// send bullet impact
- if( traceEnt->takedamage && traceEnt->client )
+ if( traceEnt->takedamage &&
+ (traceEnt->s.eType == ET_PLAYER ||
+ traceEnt->s.eType == ET_BUILDABLE ) )
{
tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
tent->s.eventParm = traceEnt->s.number;
@@ -356,7 +383,7 @@ void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent )
{
r = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16;
u = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16;
- VectorMA( origin, 8192 * 16, forward, end );
+ VectorMA( origin, SHOTGUN_RANGE, forward, end );
VectorMA( end, r, right, end );
VectorMA( end, u, up, end );
@@ -381,9 +408,9 @@ void shotgunFire( gentity_t *ent )
tent = G_TempEntity( muzzle, EV_SHOTGUN );
VectorScale( forward, 4096, tent->s.origin2 );
SnapVector( tent->s.origin2 );
- tent->s.eventParm = rand() & 255; // seed for spread pattern
+ tent->s.eventParm = rand() / ( RAND_MAX / 0x100 + 1 ); // seed for spread pattern
tent->s.otherEntityNum = ent->s.number;
- G_UnlaggedOn( ent, muzzle, 8192 * 16 );
+ G_UnlaggedOn( ent, muzzle, SHOTGUN_RANGE );
ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent );
G_UnlaggedOff();
}
@@ -403,9 +430,9 @@ void massDriverFire( gentity_t *ent )
gentity_t *tent;
gentity_t *traceEnt;
- VectorMA( muzzle, 8192 * 16, forward, end );
+ VectorMA( muzzle, 8192.0f * 16.0f, forward, end );
- G_UnlaggedOn( ent, muzzle, 8192 * 16 );
+ G_UnlaggedOn( ent, muzzle, 8192.0f * 16.0f );
trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
G_UnlaggedOff( );
@@ -418,13 +445,11 @@ void massDriverFire( gentity_t *ent )
SnapVectorTowards( tr.endpos, muzzle );
// send impact
- if( traceEnt->takedamage && traceEnt->client )
+ if( traceEnt->takedamage &&
+ (traceEnt->s.eType == ET_BUILDABLE ||
+ traceEnt->s.eType == ET_PLAYER ) )
{
- tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
- tent->s.otherEntityNum = traceEnt->s.number;
- tent->s.eventParm = DirToByte( tr.plane.normal );
- tent->s.weapon = ent->s.weapon;
- tent->s.generic1 = ent->s.generic1; //weaponMode
+ BloodSpurt( ent, traceEnt, &tr );
}
else
{
@@ -451,11 +476,7 @@ LOCKBLOB
void lockBlobLauncherFire( gentity_t *ent )
{
- gentity_t *m;
-
- m = fire_lockblob( ent, muzzle, forward );
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+ fire_lockblob( ent, muzzle, forward );
}
/*
@@ -468,11 +489,12 @@ HIVE
void hiveFire( gentity_t *ent )
{
- gentity_t *m;
-
- m = fire_hive( ent, muzzle, forward );
+ vec3_t origin;
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+ // Fire from the hive tip, not the center
+ VectorMA( muzzle, ent->r.maxs[ 2 ], ent->s.origin2, origin );
+
+ fire_hive( ent, origin, forward );
}
/*
@@ -485,11 +507,7 @@ BLASTER PISTOL
void blasterFire( gentity_t *ent )
{
- gentity_t *m;
-
- m = fire_blaster( ent, muzzle, forward );
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+ fire_blaster( ent, muzzle, forward );
}
/*
@@ -502,11 +520,7 @@ PULSE RIFLE
void pulseRifleFire( gentity_t *ent )
{
- gentity_t *m;
-
- m = fire_pulseRifle( ent, muzzle, forward );
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+ fire_pulseRifle( ent, muzzle, forward );
}
/*
@@ -519,9 +533,15 @@ FLAME THROWER
void flamerFire( gentity_t *ent )
{
- gentity_t *m;
+ vec3_t origin;
+
+ // Correct muzzle so that the missile does not start in the ceiling
+ VectorMA( muzzle, -7.0f, up, origin );
+
+ // Correct muzzle so that the missile fires from the player's hand
+ VectorMA( origin, 4.5f, right, origin );
- m = fire_flamer( ent, muzzle, forward );
+ fire_flamer( ent, origin, forward );
}
/*
@@ -534,9 +554,7 @@ GRENADE
void throwGrenade( gentity_t *ent )
{
- gentity_t *m;
-
- m = launch_grenade( ent, muzzle, forward );
+ launch_grenade( ent, muzzle, forward );
}
/*
@@ -574,13 +592,11 @@ void lasGunFire( gentity_t *ent )
SnapVectorTowards( tr.endpos, muzzle );
// send impact
- if( traceEnt->takedamage && traceEnt->client )
+ if( traceEnt->takedamage &&
+ (traceEnt->s.eType == ET_BUILDABLE ||
+ traceEnt->s.eType == ET_PLAYER ) )
{
- tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
- tent->s.otherEntityNum = traceEnt->s.number;
- tent->s.eventParm = DirToByte( tr.plane.normal );
- tent->s.weapon = ent->s.weapon;
- tent->s.generic1 = ent->s.generic1; //weaponMode
+ BloodSpurt( ent, traceEnt, &tr );
}
else
{
@@ -605,50 +621,32 @@ PAIN SAW
void painSawFire( gentity_t *ent )
{
trace_t tr;
- vec3_t end;
- gentity_t *tent;
- gentity_t *traceEnt;
-
- // set aiming directions
- AngleVectors( ent->client->ps.viewangles, forward, right, up );
-
- CalcMuzzlePoint( ent, forward, right, up, muzzle );
-
- VectorMA( muzzle, PAINSAW_RANGE, forward, end );
-
- G_UnlaggedOn( ent, muzzle, PAINSAW_RANGE );
- trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
- G_UnlaggedOff( );
+ vec3_t temp;
+ gentity_t *tent, *traceEnt;
- if( tr.surfaceFlags & SURF_NOIMPACT )
+ G_WideTrace( &tr, ent, PAINSAW_RANGE, PAINSAW_WIDTH, PAINSAW_HEIGHT,
+ &traceEnt );
+ if( !traceEnt || !traceEnt->takedamage )
return;
- traceEnt = &g_entities[ tr.entityNum ];
+ // hack to line up particle system with weapon model
+ tr.endpos[ 2 ] -= 5.0f;
// send blood impact
- if( traceEnt->takedamage )
+ if( traceEnt->s.eType == ET_PLAYER || traceEnt->s.eType == ET_BUILDABLE )
+ {
+ BloodSpurt( ent, traceEnt, &tr );
+ }
+ else
{
- vec3_t temp;
-
- //hack to get the particle system to line up with the weapon
VectorCopy( tr.endpos, temp );
- temp[ 2 ] -= 10.0f;
-
- if( traceEnt->client )
- {
- tent = G_TempEntity( temp, EV_MISSILE_HIT );
- tent->s.otherEntityNum = traceEnt->s.number;
- }
- else
- tent = G_TempEntity( temp, EV_MISSILE_MISS );
-
+ tent = G_TempEntity( temp, EV_MISSILE_MISS );
tent->s.eventParm = DirToByte( tr.plane.normal );
tent->s.weapon = ent->s.weapon;
tent->s.generic1 = ent->s.generic1; //weaponMode
}
- if( traceEnt->takedamage )
- G_Damage( traceEnt, ent, ent, forward, tr.endpos, PAINSAW_DAMAGE, 0, MOD_PAINSAW );
+ G_Damage( traceEnt, ent, ent, forward, tr.endpos, PAINSAW_DAMAGE, DAMAGE_NO_KNOCKBACK, MOD_PAINSAW );
}
/*
@@ -666,19 +664,14 @@ LCChargeFire
*/
void LCChargeFire( gentity_t *ent, qboolean secondary )
{
- gentity_t *m;
-
- if( secondary )
- {
- m = fire_luciferCannon( ent, muzzle, forward, LCANNON_SECONDARY_DAMAGE,
- LCANNON_SECONDARY_RADIUS );
- ent->client->ps.weaponTime = LCANNON_REPEAT;
- }
+ if( secondary && ent->client->ps.stats[ STAT_MISC ] <= 0 )
+ fire_luciferCannon( ent, muzzle, forward, LCANNON_SECONDARY_DAMAGE,
+ LCANNON_SECONDARY_RADIUS, LCANNON_SECONDARY_SPEED );
else
- {
- m = fire_luciferCannon( ent, muzzle, forward, ent->client->ps.stats[ STAT_MISC ], LCANNON_RADIUS );
- ent->client->ps.weaponTime = LCANNON_CHARGEREPEAT;
- }
+ fire_luciferCannon( ent, muzzle, forward,
+ ent->client->ps.stats[ STAT_MISC ] *
+ LCANNON_DAMAGE / LCANNON_CHARGE_TIME_MAX,
+ LCANNON_RADIUS, LCANNON_SPEED );
ent->client->ps.stats[ STAT_MISC ] = 0;
}
@@ -692,49 +685,44 @@ TESLA GENERATOR
*/
-void teslaFire( gentity_t *ent )
+void teslaFire( gentity_t *self )
{
- trace_t tr;
- vec3_t end;
- gentity_t *traceEnt, *tent;
-
- VectorMA( muzzle, TESLAGEN_RANGE, forward, end );
-
- trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
+ trace_t tr;
+ vec3_t origin, target;
+ gentity_t *tent;
- if( tr.entityNum == ENTITYNUM_NONE )
+ if( !self->enemy )
return;
- traceEnt = &g_entities[ tr.entityNum ];
+ // Move the muzzle from the entity origin up a bit to fire over turrets
+ VectorMA( muzzle, self->r.maxs[ 2 ], self->s.origin2, origin );
- if( !traceEnt->client )
- return;
+ // Don't aim for the center, aim at the top of the bounding box
+ VectorCopy( self->enemy->r.currentOrigin, target );
+ target[ 2 ] += self->enemy->r.maxs[ 2 ];
- if( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS )
+ // Trace to the target entity
+ trap_Trace( &tr, origin, NULL, NULL, target, self->s.number, MASK_SHOT );
+ if( tr.entityNum != self->enemy->s.number )
return;
- //so the client side knows
- ent->s.eFlags |= EF_FIRING;
+ // Client side firing effect
+ self->s.eFlags |= EF_FIRING;
- if( traceEnt->takedamage )
+ // Deal damage
+ if( self->enemy->takedamage )
{
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- TESLAGEN_DMG, 0, MOD_TESLAGEN );
- }
+ vec3_t dir;
- // snap the endpos to integers to save net bandwidth, but nudged towards the line
- SnapVectorTowards( tr.endpos, muzzle );
+ VectorSubtract( target, origin, dir );
+ G_Damage( self->enemy, self, self, dir, tr.endpos,
+ TESLAGEN_DMG, 0, MOD_TESLAGEN );
+ }
- // send railgun beam effect
+ // Send tesla zap trail
tent = G_TempEntity( tr.endpos, EV_TESLATRAIL );
-
- VectorCopy( muzzle, tent->s.origin2 );
-
- tent->s.generic1 = ent->s.number; //src
- tent->s.clientNum = traceEnt->s.number; //dest
-
- // move origin a bit to come closer to the drawn gun muzzle
- VectorMA( tent->s.origin2, 28, up, tent->s.origin2 );
+ tent->s.misc = self->s.number; // src
+ tent->s.clientNum = self->enemy->s.number; // dest
}
@@ -745,65 +733,62 @@ BUILD GUN
======================================================================
*/
-
-/*
-===============
-cancelBuildFire
-===============
-*/
-void cancelBuildFire( gentity_t *ent )
+void CheckCkitRepair( gentity_t *ent )
{
- vec3_t forward, end;
+ vec3_t viewOrigin, forward, end;
trace_t tr;
gentity_t *traceEnt;
int bHealth;
- if( ent->client->ps.stats[ STAT_BUILDABLE ] != BA_NONE )
- {
- ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
+ if( ent->client->ps.weaponTime > 0 ||
+ ent->client->ps.stats[ STAT_MISC ] > 0 )
return;
- }
- //repair buildable
- if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL );
- VectorMA( ent->client->ps.origin, 100, forward, end );
+ BG_GetClientViewOrigin( &ent->client->ps, viewOrigin );
+ AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL );
+ VectorMA( viewOrigin, 100, forward, end );
- trap_Trace( &tr, ent->client->ps.origin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
- traceEnt = &g_entities[ tr.entityNum ];
+ trap_Trace( &tr, viewOrigin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
+ traceEnt = &g_entities[ tr.entityNum ];
- if( tr.fraction < 1.0 &&
- ( traceEnt->s.eType == ET_BUILDABLE ) &&
- ( traceEnt->biteam == ent->client->ps.stats[ STAT_PTEAM ] ) &&
- ( ( ent->client->ps.weapon >= WP_HBUILD2 ) &&
- ( ent->client->ps.weapon <= WP_HBUILD ) ) &&
- traceEnt->spawned && traceEnt->health > 0 )
+ if( tr.fraction < 1.0f && traceEnt->spawned && traceEnt->health > 0 &&
+ traceEnt->s.eType == ET_BUILDABLE && traceEnt->buildableTeam == TEAM_HUMANS )
+ {
+ bHealth = BG_Buildable( traceEnt->s.modelindex )->health;
+ if( traceEnt->health < bHealth )
{
- if( ent->client->ps.stats[ STAT_MISC ] > 0 )
- {
- G_AddEvent( ent, EV_BUILD_DELAY, ent->client->ps.clientNum );
- return;
- }
-
- bHealth = BG_FindHealthForBuildable( traceEnt->s.modelindex );
-
traceEnt->health += HBUILD_HEALRATE;
- ent->client->pers.statscounters.repairspoisons++;
- level.humanStatsCounters.repairspoisons++;
-
- if( traceEnt->health > bHealth )
+ if( traceEnt->health >= bHealth )
+ {
traceEnt->health = bHealth;
-
- if( traceEnt->health == bHealth )
G_AddEvent( ent, EV_BUILD_REPAIRED, 0 );
+ }
else
G_AddEvent( ent, EV_BUILD_REPAIR, 0 );
+
+ ent->client->ps.weaponTime += BG_Weapon( ent->client->ps.weapon )->repeatRate1;
}
}
- else if( ent->client->ps.weapon == WP_ABUILD2 )
+}
+
+/*
+===============
+cancelBuildFire
+===============
+*/
+void cancelBuildFire( gentity_t *ent )
+{
+ // Cancel ghost buildable
+ if( ent->client->ps.stats[ STAT_BUILDABLE ] != BA_NONE )
+ {
+ ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
+ return;
+ }
+
+ if( ent->client->ps.weapon == WP_ABUILD ||
+ ent->client->ps.weapon == WP_ABUILD2 )
meleeAttack( ent, ABUILDER_CLAW_RANGE, ABUILDER_CLAW_WIDTH,
- ABUILDER_CLAW_DMG, MOD_ABUILDER_CLAW ); //melee attack for alien builder
+ ABUILDER_CLAW_WIDTH, ABUILDER_CLAW_DMG, MOD_ABUILDER_CLAW );
}
/*
@@ -813,7 +798,10 @@ buildFire
*/
void buildFire( gentity_t *ent, dynMenu_t menu )
{
- if( ( ent->client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) > BA_NONE )
+ buildable_t buildable = ( ent->client->ps.stats[ STAT_BUILDABLE ]
+ & ~SB_VALID_TOGGLEBIT );
+
+ if( buildable > BA_NONE )
{
if( ent->client->ps.stats[ STAT_MISC ] > 0 )
{
@@ -821,33 +809,17 @@ void buildFire( gentity_t *ent, dynMenu_t menu )
return;
}
- if( G_BuildIfValid( ent, ent->client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) )
+ if( G_BuildIfValid( ent, buildable ) )
{
- if( g_cheats.integer )
- {
- ent->client->ps.stats[ STAT_MISC ] = 0;
- }
- else if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS && !G_IsOvermindBuilt( ) )
- {
- ent->client->ps.stats[ STAT_MISC ] +=
- BG_FindBuildDelayForWeapon( ent->s.weapon ) * 2;
- }
- else if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS && !G_IsPowered( muzzle ) &&
- ( ent->client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) != BA_H_REPEATER ) //hack
+ if( !g_cheats.integer )
{
ent->client->ps.stats[ STAT_MISC ] +=
- BG_FindBuildDelayForWeapon( ent->s.weapon ) * 2;
+ BG_Buildable( buildable )->buildTime;
}
- else
- ent->client->ps.stats[ STAT_MISC ] +=
- BG_FindBuildDelayForWeapon( ent->s.weapon );
ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
-
- // don't want it bigger than 32k
- if( ent->client->ps.stats[ STAT_MISC ] > 30000 )
- ent->client->ps.stats[ STAT_MISC ] = 30000;
}
+
return;
}
@@ -856,11 +828,7 @@ void buildFire( gentity_t *ent, dynMenu_t menu )
void slowBlobFire( gentity_t *ent )
{
- gentity_t *m;
-
- m = fire_slowBlob( ent, muzzle, forward );
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+ fire_slowBlob( ent, muzzle, forward );
}
@@ -880,65 +848,51 @@ CheckVenomAttack
qboolean CheckVenomAttack( gentity_t *ent )
{
trace_t tr;
- vec3_t end;
- gentity_t *tent;
gentity_t *traceEnt;
- vec3_t mins, maxs;
int damage = LEVEL0_BITE_DMG;
- VectorSet( mins, -LEVEL0_BITE_WIDTH, -LEVEL0_BITE_WIDTH, -LEVEL0_BITE_WIDTH );
- VectorSet( maxs, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH );
+ if( ent->client->ps.weaponTime )
+ return qfalse;
- // set aiming directions
+ // Calculate muzzle point
AngleVectors( ent->client->ps.viewangles, forward, right, up );
-
CalcMuzzlePoint( ent, forward, right, up, muzzle );
- VectorMA( muzzle, LEVEL0_BITE_RANGE, forward, end );
-
- G_UnlaggedOn( ent, muzzle, LEVEL0_BITE_RANGE );
- trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT );
- G_UnlaggedOff( );
+ G_WideTrace( &tr, ent, LEVEL0_BITE_RANGE, LEVEL0_BITE_WIDTH,
+ LEVEL0_BITE_WIDTH, &traceEnt );
- if( tr.surfaceFlags & SURF_NOIMPACT )
+ if( traceEnt == NULL )
return qfalse;
- traceEnt = &g_entities[ tr.entityNum ];
-
if( !traceEnt->takedamage )
return qfalse;
- //allow bites to work against defensive buildables only
+ if( traceEnt->health <= 0 )
+ return qfalse;
+
+ // only allow bites to work against buildings as they are constructing
if( traceEnt->s.eType == ET_BUILDABLE )
{
- if( traceEnt->s.modelindex != BA_H_MGTURRET &&
- traceEnt->s.modelindex != BA_H_TESLAGEN )
+ if( traceEnt->spawned )
return qfalse;
- //hackery
- damage *= 0.5f;
+ if( traceEnt->buildableTeam == TEAM_ALIENS )
+ return qfalse;
}
if( traceEnt->client )
{
- if( traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( traceEnt->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
return qfalse;
if( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 )
return qfalse;
}
// send blood impact
- if( traceEnt->takedamage && traceEnt->client )
- {
- tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
- tent->s.otherEntityNum = traceEnt->s.number;
- tent->s.eventParm = DirToByte( tr.plane.normal );
- tent->s.weapon = ent->s.weapon;
- tent->s.generic1 = ent->s.generic1; //weaponMode
- }
-
- G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_LEVEL0_BITE );
+ WideBloodSpurt( ent, traceEnt, &tr );
+ G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_LEVEL0_BITE );
+ ent->client->ps.weaponTime += LEVEL0_BITE_REPEAT;
return qtrue;
}
@@ -966,7 +920,10 @@ void CheckGrabAttack( gentity_t *ent )
CalcMuzzlePoint( ent, forward, right, up, muzzle );
- VectorMA( muzzle, LEVEL1_GRAB_RANGE, forward, end );
+ if( ent->client->ps.weapon == WP_ALEVEL1 )
+ VectorMA( muzzle, LEVEL1_GRAB_RANGE, forward, end );
+ else if( ent->client->ps.weapon == WP_ALEVEL1_UPG )
+ VectorMA( muzzle, LEVEL1_GRAB_U_RANGE, forward, end );
trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
if( tr.surfaceFlags & SURF_NOIMPACT )
@@ -979,7 +936,7 @@ void CheckGrabAttack( gentity_t *ent )
if( traceEnt->client )
{
- if( traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( traceEnt->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
return;
if( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 )
@@ -1001,15 +958,6 @@ void CheckGrabAttack( gentity_t *ent )
else if( ent->client->ps.weapon == WP_ALEVEL1_UPG )
traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_U_TIME;
}
- else if( traceEnt->s.eType == ET_BUILDABLE &&
- traceEnt->s.modelindex == BA_H_MGTURRET )
- {
- if( !traceEnt->lev1Grabbed )
- G_AddPredictableEvent( ent, EV_LEV1_GRAB, 0 );
-
- traceEnt->lev1Grabbed = qtrue;
- traceEnt->lev1GrabTime = level.time;
- }
}
/*
@@ -1023,7 +971,7 @@ void poisonCloud( gentity_t *ent )
vec3_t range = { LEVEL1_PCLOUD_RANGE, LEVEL1_PCLOUD_RANGE, LEVEL1_PCLOUD_RANGE };
vec3_t mins, maxs;
int i, num;
- gentity_t *target;
+ gentity_t *humanPlayer;
trace_t tr;
VectorAdd( ent->client->ps.origin, range, maxs );
@@ -1033,39 +981,23 @@ void poisonCloud( gentity_t *ent )
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for( i = 0; i < num; i++ )
{
- target = &g_entities[ entityList[ i ] ];
+ humanPlayer = &g_entities[ entityList[ i ] ];
- if( target->client && target->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ if( humanPlayer->client &&
+ humanPlayer->client->pers.teamSelection == TEAM_HUMANS )
{
- if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, target->client->ps.stats ) )
- continue;
-
- if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, target->client->ps.stats ) )
- continue;
-
- trap_Trace( &tr, muzzle, NULL, NULL, target->s.origin, target->s.number, MASK_SHOT );
+ trap_Trace( &tr, muzzle, NULL, NULL, humanPlayer->r.currentOrigin,
+ humanPlayer->s.number, CONTENTS_SOLID );
//can't see target from here
if( tr.entityNum == ENTITYNUM_WORLD )
continue;
- if( !( target->client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED ) )
- {
- target->client->ps.stats[ STAT_STATE ] |= SS_POISONCLOUDED;
- target->client->lastPoisonCloudedTime = level.time;
- target->client->lastPoisonCloudedClient = ent;
- trap_SendServerCommand( target->client->ps.clientNum, "poisoncloud" );
- }
- }
- if( target->client && target->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- trap_Trace( &tr, muzzle, NULL, NULL, target->s.origin, target->s.number, MASK_SOLID );
-
- if( tr.entityNum == ENTITYNUM_WORLD )
- continue;
+ humanPlayer->client->ps.eFlags |= EF_POISONCLOUDED;
+ humanPlayer->client->lastPoisonCloudedTime = level.time;
- target->client->ps.stats[ STAT_STATE ] |= SS_BOOSTED;
- target->client->lastBoostedTime = MAX( target->client->lastBoostedTime, level.time - BOOST_TIME + LEVEL1_PCLOUD_BOOST_TIME );
+ trap_SendServerCommand( humanPlayer->client->ps.clientNum,
+ "poisoncloud" );
}
}
G_UnlaggedOff( );
@@ -1080,72 +1012,60 @@ LEVEL2
======================================================================
*/
-#define MAX_ZAPS 64
-
-static zap_t zaps[ MAX_CLIENTS ];
+zap_t zaps[ MAX_ZAPS ];
/*
===============
-G_FindNewZapTarget
+G_FindZapChainTargets
===============
*/
-static gentity_t *G_FindNewZapTarget( gentity_t *ent )
+static void G_FindZapChainTargets( zap_t *zap )
{
+ gentity_t *ent = zap->targets[ 0 ]; // the source
int entityList[ MAX_GENTITIES ];
- vec3_t range = { LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE };
+ vec3_t range = { LEVEL2_AREAZAP_CHAIN_RANGE,
+ LEVEL2_AREAZAP_CHAIN_RANGE,
+ LEVEL2_AREAZAP_CHAIN_RANGE };
vec3_t mins, maxs;
- int i, j, k, num;
+ int i, num;
gentity_t *enemy;
trace_t tr;
+ float distance;
- VectorScale( range, 1.0f / M_ROOT3, range );
- VectorAdd( ent->s.origin, range, maxs );
- VectorSubtract( ent->s.origin, range, mins );
+ VectorAdd( ent->r.currentOrigin, range, maxs );
+ VectorSubtract( ent->r.currentOrigin, range, mins );
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for( i = 0; i < num; i++ )
{
enemy = &g_entities[ entityList[ i ] ];
-
- if( ( ( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ||
- ( enemy->s.eType == ET_BUILDABLE &&
- BG_FindTeamForBuildable( enemy->s.modelindex ) == BIT_HUMANS ) ) && enemy->health > 0 )
+ // don't chain to self; noclippers can be listed, don't chain to them either
+ if( enemy == ent || ( enemy->client && enemy->client->noclip ) )
+ continue;
+
+ distance = Distance( ent->r.currentOrigin, enemy->r.currentOrigin );
+
+ if( ( ( enemy->client &&
+ enemy->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) ||
+ ( enemy->s.eType == ET_BUILDABLE &&
+ BG_Buildable( enemy->s.modelindex )->team == TEAM_HUMANS ) ) &&
+ enemy->health > 0 && // only chain to living targets
+ distance <= LEVEL2_AREAZAP_CHAIN_RANGE )
{
- qboolean foundOldTarget = qfalse;
-
- trap_Trace( &tr, muzzle, NULL, NULL, enemy->s.origin, ent->s.number, MASK_SHOT );
-
- //can't see target from here
- if( tr.entityNum == ENTITYNUM_WORLD )
- continue;
+ // world-LOS check: trace against the world, ignoring other BODY entities
+ trap_Trace( &tr, ent->r.currentOrigin, NULL, NULL,
+ enemy->r.currentOrigin, ent->s.number, CONTENTS_SOLID );
- for( j = 0; j < MAX_ZAPS; j++ )
+ if( tr.entityNum == ENTITYNUM_NONE )
{
- zap_t *zap = &zaps[ j ];
-
- for( k = 0; k < zap->numTargets; k++ )
- {
- if( zap->targets[ k ] == enemy )
- {
- foundOldTarget = qtrue;
- break;
- }
- }
-
- if( foundOldTarget )
- break;
+ zap->targets[ zap->numTargets ] = enemy;
+ zap->distances[ zap->numTargets ] = distance;
+ if( ++zap->numTargets >= LEVEL2_AREAZAP_MAX_TARGETS )
+ return;
}
-
- // enemy is already targetted
- if( foundOldTarget )
- continue;
-
- return enemy;
}
}
-
- return NULL;
}
/*
@@ -1155,30 +1075,19 @@ G_UpdateZapEffect
*/
static void G_UpdateZapEffect( zap_t *zap )
{
- int j;
- gentity_t *effect = zap->effectChannel;
-
- effect->s.eType = ET_LEV2_ZAP_CHAIN;
- effect->classname = "lev2zapchain";
- G_SetOrigin( effect, zap->creator->s.origin );
- effect->s.misc = zap->creator->s.number;
+ int i;
+ int entityNums[ LEVEL2_AREAZAP_MAX_TARGETS + 1 ];
- effect->s.time = effect->s.time2 = effect->s.constantLight = -1;
+ entityNums[ 0 ] = zap->creator->s.number;
- for( j = 0; j < zap->numTargets; j++ )
- {
- int number = zap->targets[ j ]->s.number;
+ for( i = 0; i < zap->numTargets; i++ )
+ entityNums[ i + 1 ] = zap->targets[ i ]->s.number;
- switch( j )
- {
- case 0: effect->s.time = number; break;
- case 1: effect->s.time2 = number; break;
- case 2: effect->s.constantLight = number; break;
- default: break;
- }
- }
+ BG_PackEntityNumbers( &zap->effectChannel->s,
+ entityNums, zap->numTargets + 1 );
- trap_LinkEntity( effect );
+ VectorCopy( zap->creator->r.currentOrigin, zap->effectChannel->r.currentOrigin );
+ trap_LinkEntity( zap->effectChannel );
}
/*
@@ -1188,38 +1097,48 @@ G_CreateNewZap
*/
static void G_CreateNewZap( gentity_t *creator, gentity_t *target )
{
- int i, j;
- zap_t *zap;
+ int i;
+ zap_t *zap;
for( i = 0; i < MAX_ZAPS; i++ )
{
zap = &zaps[ i ];
+ if( zap->used )
+ continue;
- if( !zap->used )
- {
- zap->used = qtrue;
+ zap->used = qtrue;
+ zap->timeToLive = LEVEL2_AREAZAP_TIME;
- zap->timeToLive = LEVEL2_AREAZAP_TIME;
- zap->damageUsed = 0;
+ zap->creator = creator;
+ zap->targets[ 0 ] = target;
+ zap->numTargets = 1;
- zap->creator = creator;
+ // the zap chains only through living entities
+ if( target->health > 0 )
+ {
+ G_Damage( target, creator, creator, forward,
+ target->r.currentOrigin, LEVEL2_AREAZAP_DMG,
+ DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE,
+ MOD_LEVEL2_ZAP );
- zap->targets[ 0 ] = target;
- zap->numTargets = 1;
+ G_FindZapChainTargets( zap );
- for( j = 1; j < MAX_ZAP_TARGETS && zap->targets[ j - 1 ]; j++ )
+ for( i = 1; i < zap->numTargets; i++ )
{
- zap->targets[ j ] = G_FindNewZapTarget( zap->targets[ j - 1 ] );
-
- if( zap->targets[ j ] )
- zap->numTargets++;
+ G_Damage( zap->targets[ i ], target, zap->creator, forward, target->r.currentOrigin,
+ LEVEL2_AREAZAP_DMG * ( 1 - pow( (zap->distances[ i ] /
+ LEVEL2_AREAZAP_CHAIN_RANGE ), LEVEL2_AREAZAP_CHAIN_FALLOFF ) ) + 1,
+ DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE,
+ MOD_LEVEL2_ZAP );
}
+ }
- zap->effectChannel = G_Spawn( );
- G_UpdateZapEffect( zap );
+ zap->effectChannel = G_Spawn( );
+ zap->effectChannel->s.eType = ET_LEV2_ZAP_CHAIN;
+ zap->effectChannel->classname = "lev2zapchain";
+ G_UpdateZapEffect( zap );
- return;
- }
+ return;
}
}
@@ -1233,80 +1152,67 @@ void G_UpdateZaps( int msec )
{
int i, j;
zap_t *zap;
- int damage;
for( i = 0; i < MAX_ZAPS; i++ )
{
zap = &zaps[ i ];
+ if( !zap->used )
+ continue;
- if( zap->used )
+ zap->timeToLive -= msec;
+
+ // first, the disappearance of players is handled immediately in G_ClearPlayerZapEffects()
+
+ // the deconstruction or gibbing of a directly targeted buildable destroys the whole zap effect
+ if( zap->timeToLive <= 0 || !zap->targets[ 0 ]->inuse )
{
- //check each target is valid
- for( j = 0; j < zap->numTargets; j++ )
- {
- gentity_t *source;
- gentity_t *target = zap->targets[ j ];
-
- if( j == 0 )
- source = zap->creator;
- else
- source = zap->targets[ j - 1 ];
-
- if( target->health <= 0 || !target->inuse || //early out
- Distance( source->s.origin, target->s.origin ) > LEVEL2_AREAZAP_RANGE )
- {
- target = zap->targets[ j ] = G_FindNewZapTarget( source );
-
- //couldn't find a target, so forget about the rest of the chain
- if( !target )
- zap->numTargets = j;
- }
- }
+ G_FreeEntity( zap->effectChannel );
+ zap->used = qfalse;
+ continue;
+ }
- if( zap->numTargets )
- {
- for( j = 0; j < zap->numTargets; j++ )
- {
- gentity_t *source;
- gentity_t *target = zap->targets[ j ];
- float r = 1.0f / zap->numTargets;
- float damageFraction = 2 * r - 2 * j * r * r - r * r;
- vec3_t forward;
-
- if( j == 0 )
- source = zap->creator;
- else
- source = zap->targets[ j - 1 ];
-
- damage = ceil( ( (float)msec / LEVEL2_AREAZAP_TIME ) *
- LEVEL2_AREAZAP_DMG * damageFraction );
-
- // don't let a high msec value inflate the total damage
- if( damage + zap->damageUsed > LEVEL2_AREAZAP_DMG )
- damage = LEVEL2_AREAZAP_DMG - zap->damageUsed;
-
- VectorSubtract( target->s.origin, source->s.origin, forward );
- VectorNormalize( forward );
-
- //do the damage
- if( damage )
- {
- G_Damage( target, source, zap->creator, forward, target->s.origin,
- damage, DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP );
- zap->damageUsed += damage;
- }
- }
- }
+ // the deconstruction or gibbing of chained buildables destroy the appropriate beams
+ for( j = 1; j < zap->numTargets; j++ )
+ {
+ if( !zap->targets[ j ]->inuse )
+ zap->targets[ j-- ] = zap->targets[ --zap->numTargets ];
+ }
- G_UpdateZapEffect( zap );
+ G_UpdateZapEffect( zap );
+ }
+}
- zap->timeToLive -= msec;
+/*
+===============
+G_ClearPlayerZapEffects
- if( zap->timeToLive <= 0 || zap->numTargets == 0 || zap->creator->health <= 0 )
- {
- zap->used = qfalse;
- G_FreeEntity( zap->effectChannel );
- }
+called from G_LeaveTeam() and TeleportPlayer()
+===============
+*/
+void G_ClearPlayerZapEffects( gentity_t *player )
+{
+ int i, j;
+ zap_t *zap;
+
+ for( i = 0; i < MAX_ZAPS; i++ )
+ {
+ zap = &zaps[ i ];
+ if( !zap->used )
+ continue;
+
+ // the disappearance of the creator or the first target destroys the whole zap effect
+ if( zap->creator == player || zap->targets[ 0 ] == player )
+ {
+ G_FreeEntity( zap->effectChannel );
+ zap->used = qfalse;
+ continue;
+ }
+
+ // the disappearance of chained players destroy the appropriate beams
+ for( j = 1; j < zap->numTargets; j++ )
+ {
+ if( zap->targets[ j ] == player )
+ zap->targets[ j-- ] = zap->targets[ --zap->numTargets ];
}
}
}
@@ -1319,32 +1225,16 @@ areaZapFire
void areaZapFire( gentity_t *ent )
{
trace_t tr;
- vec3_t end;
gentity_t *traceEnt;
- vec3_t mins, maxs;
-
- VectorSet( mins, -LEVEL2_AREAZAP_WIDTH, -LEVEL2_AREAZAP_WIDTH, -LEVEL2_AREAZAP_WIDTH );
- VectorSet( maxs, LEVEL2_AREAZAP_WIDTH, LEVEL2_AREAZAP_WIDTH, LEVEL2_AREAZAP_WIDTH );
-
- // set aiming directions
- AngleVectors( ent->client->ps.viewangles, forward, right, up );
-
- CalcMuzzlePoint( ent, forward, right, up, muzzle );
- VectorMA( muzzle, LEVEL2_AREAZAP_RANGE, forward, end );
+ G_WideTrace( &tr, ent, LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_WIDTH, LEVEL2_AREAZAP_WIDTH, &traceEnt );
- G_UnlaggedOn( ent, muzzle, LEVEL2_AREAZAP_RANGE );
- trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT );
- G_UnlaggedOff( );
-
- if( tr.surfaceFlags & SURF_NOIMPACT )
+ if( traceEnt == NULL )
return;
- traceEnt = &g_entities[ tr.entityNum ];
-
- if( ( ( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ||
+ if( ( traceEnt->client && traceEnt->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) ||
( traceEnt->s.eType == ET_BUILDABLE &&
- BG_FindTeamForBuildable( traceEnt->s.modelindex ) == BIT_HUMANS ) ) && traceEnt->health > 0 )
+ BG_Buildable( traceEnt->s.modelindex )->team == TEAM_HUMANS ) )
{
G_CreateNewZap( ent, traceEnt );
}
@@ -1366,61 +1256,51 @@ CheckPounceAttack
*/
qboolean CheckPounceAttack( gentity_t *ent )
{
- trace_t tr;
- gentity_t *tent;
+ trace_t tr;
gentity_t *traceEnt;
- int damage;
-
- if( ent->client->ps.groundEntityNum != ENTITYNUM_NONE )
- {
- ent->client->allowedToPounce = qfalse;
- ent->client->pmext.pouncePayload = 0;
- }
+ int damage, timeMax, pounceRange, payload;
- if( !ent->client->allowedToPounce )
+ if( ent->client->pmext.pouncePayload <= 0 )
return qfalse;
- if( ent->client->ps.weaponTime )
- return qfalse;
+ // In case the goon lands on his target, he gets one shot after landing
+ payload = ent->client->pmext.pouncePayload;
+ if( !( ent->client->ps.pm_flags & PMF_CHARGE ) )
+ ent->client->pmext.pouncePayload = 0;
- G_WideTrace( &tr, ent, LEVEL3_POUNCE_RANGE, LEVEL3_POUNCE_WIDTH, &traceEnt );
+ // Calculate muzzle point
+ AngleVectors( ent->client->ps.viewangles, forward, right, up );
+ CalcMuzzlePoint( ent, forward, right, up, muzzle );
+ // Trace from muzzle to see what we hit
+ pounceRange = ent->client->ps.weapon == WP_ALEVEL3 ? LEVEL3_POUNCE_RANGE :
+ LEVEL3_POUNCE_UPG_RANGE;
+ G_WideTrace( &tr, ent, pounceRange, LEVEL3_POUNCE_WIDTH,
+ LEVEL3_POUNCE_WIDTH, &traceEnt );
if( traceEnt == NULL )
return qfalse;
- // send blood impact
- if( traceEnt->takedamage && traceEnt->client )
- {
- tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
- tent->s.otherEntityNum = traceEnt->s.number;
- tent->s.eventParm = DirToByte( tr.plane.normal );
- tent->s.weapon = ent->s.weapon;
- tent->s.generic1 = ent->s.generic1; //weaponMode
- }
+ // Send blood impact
+ if( traceEnt->takedamage )
+ WideBloodSpurt( ent, traceEnt, &tr );
if( !traceEnt->takedamage )
return qfalse;
-
- damage = (int)( ( (float)ent->client->pmext.pouncePayload
- / (float)LEVEL3_POUNCE_SPEED ) * LEVEL3_POUNCE_DMG );
-
+
+ // Deal damage
+ timeMax = ent->client->ps.weapon == WP_ALEVEL3 ? LEVEL3_POUNCE_TIME :
+ LEVEL3_POUNCE_TIME_UPG;
+ damage = payload * LEVEL3_POUNCE_DMG / timeMax;
ent->client->pmext.pouncePayload = 0;
-
G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage,
- DAMAGE_NO_LOCDAMAGE, MOD_LEVEL3_POUNCE );
-
- ent->client->allowedToPounce = qfalse;
+ DAMAGE_NO_LOCDAMAGE, MOD_LEVEL3_POUNCE );
return qtrue;
}
void bounceBallFire( gentity_t *ent )
{
- gentity_t *m;
-
- m = fire_bounceBall( ent, muzzle, forward );
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+ fire_bounceBall( ent, muzzle, forward );
}
@@ -1434,39 +1314,96 @@ LEVEL4
/*
===============
-ChargeAttack
+G_ChargeAttack
===============
*/
-void ChargeAttack( gentity_t *ent, gentity_t *victim )
+void G_ChargeAttack( gentity_t *ent, gentity_t *victim )
{
- gentity_t *tent;
int damage;
- vec3_t forward, normal;
+ int i;
+ vec3_t forward;
- if( level.time < victim->chargeRepeat )
+ if( ent->client->ps.stats[ STAT_MISC ] <= 0 ||
+ !( ent->client->ps.stats[ STAT_STATE ] & SS_CHARGING ) ||
+ ent->client->ps.weaponTime )
return;
- victim->chargeRepeat = level.time + LEVEL4_CHARGE_REPEAT;
-
- VectorSubtract( victim->s.origin, ent->s.origin, forward );
+ VectorSubtract( victim->r.currentOrigin, ent->r.currentOrigin, forward );
VectorNormalize( forward );
- VectorNegate( forward, normal );
- if( victim->client )
+ if( !victim->takedamage )
+ return;
+
+ // For buildables, track the last MAX_TRAMPLE_BUILDABLES_TRACKED buildables
+ // hit, and do not do damage if the current buildable is in that list
+ // in order to prevent dancing over stuff to kill it very quickly
+ if( !victim->client )
{
- tent = G_TempEntity( victim->s.origin, EV_MISSILE_HIT );
- tent->s.otherEntityNum = victim->s.number;
- tent->s.eventParm = DirToByte( normal );
- tent->s.weapon = ent->s.weapon;
- tent->s.generic1 = ent->s.generic1; //weaponMode
+ for( i = 0; i < MAX_TRAMPLE_BUILDABLES_TRACKED; i++ )
+ {
+ if( ent->client->trampleBuildablesHit[ i ] == victim - g_entities )
+ return;
+ }
+
+ ent->client->trampleBuildablesHit[
+ ent->client->trampleBuildablesHitPos++ % MAX_TRAMPLE_BUILDABLES_TRACKED ] =
+ victim - g_entities;
}
- if( !victim->takedamage )
+ WideBloodSpurt( ent, victim, NULL );
+
+ damage = LEVEL4_TRAMPLE_DMG * ent->client->ps.stats[ STAT_MISC ] /
+ LEVEL4_TRAMPLE_DURATION;
+
+ G_Damage( victim, ent, ent, forward, victim->r.currentOrigin, damage,
+ DAMAGE_NO_LOCDAMAGE, MOD_LEVEL4_TRAMPLE );
+
+ ent->client->ps.weaponTime += LEVEL4_TRAMPLE_REPEAT;
+}
+
+/*
+===============
+G_CrushAttack
+
+Should only be called if there was an impact between a tyrant and another player
+===============
+*/
+void G_CrushAttack( gentity_t *ent, gentity_t *victim )
+{
+ vec3_t dir;
+ float jump;
+ int damage;
+
+ if( !victim->takedamage ||
+ ent->client->ps.origin[ 2 ] + ent->r.mins[ 2 ] <
+ victim->r.currentOrigin[ 2 ] + victim->r.maxs[ 2 ] ||
+ ( victim->client &&
+ victim->client->ps.groundEntityNum == ENTITYNUM_NONE ) )
return;
- damage = (int)( ( (float)ent->client->ps.stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME ) * LEVEL4_CHARGE_DMG );
+ // Deal velocity based damage to target
+ jump = BG_Class( ent->client->ps.stats[ STAT_CLASS ] )->jumpMagnitude;
+ damage = ( ent->client->pmext.fallVelocity + jump ) *
+ -LEVEL4_CRUSH_DAMAGE_PER_V;
+
+ if( damage < 0 )
+ damage = 0;
+
+ // Players also get damaged periodically
+ if( victim->client &&
+ ent->client->lastCrushTime + LEVEL4_CRUSH_REPEAT < level.time )
+ {
+ ent->client->lastCrushTime = level.time;
+ damage += LEVEL4_CRUSH_DAMAGE;
+ }
+
+ if( damage < 1 )
+ return;
- G_Damage( victim, ent, ent, forward, victim->s.origin, damage, 0, MOD_LEVEL4_CHARGE );
+ // Crush the victim over a period of time
+ VectorSubtract( victim->r.currentOrigin, ent->client->ps.origin, dir );
+ G_Damage( victim, ent, ent, dir, victim->r.currentOrigin, damage,
+ DAMAGE_NO_LOCDAMAGE, MOD_LEVEL4_CRUSH );
}
//======================================================================
@@ -1480,10 +1417,12 @@ set muzzle location relative to pivoting eye
*/
void CalcMuzzlePoint( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint )
{
- VectorCopy( ent->s.pos.trBase, muzzlePoint );
- muzzlePoint[ 2 ] += ent->client->ps.viewheight;
+ vec3_t normal;
+
+ VectorCopy( ent->client->ps.origin, muzzlePoint );
+ BG_GetClientNormal( &ent->client->ps, normal );
+ VectorMA( muzzlePoint, ent->client->ps.viewheight, normal, muzzlePoint );
VectorMA( muzzlePoint, 1, forward, muzzlePoint );
- VectorMA( muzzlePoint, 1, right, muzzlePoint );
// snap to integer coordinates for more efficient network bandwidth usage
SnapVector( muzzlePoint );
}
@@ -1548,18 +1487,18 @@ void FireWeapon2( gentity_t *ent )
case WP_ALEVEL1_UPG:
poisonCloud( ent );
break;
- case WP_ALEVEL2_UPG:
- areaZapFire( ent );
- break;
case WP_LUCIFER_CANNON:
LCChargeFire( ent, qtrue );
break;
+ case WP_ALEVEL2_UPG:
+ areaZapFire( ent );
+ break;
+
case WP_ABUILD:
case WP_ABUILD2:
case WP_HBUILD:
- case WP_HBUILD2:
cancelBuildFire( ent );
break;
default:
@@ -1574,13 +1513,11 @@ FireWeapon
*/
void FireWeapon( gentity_t *ent )
{
- if( level.paused ) return;
-
if( ent->client )
{
// set aiming directions
AngleVectors( ent->client->ps.viewangles, forward, right, up );
- CalcMuzzlePoint( ent, forward, right, up, muzzle );
+ CalcMuzzlePoint( ent, forward, right, up, muzzle );
}
else
{
@@ -1592,21 +1529,32 @@ void FireWeapon( gentity_t *ent )
switch( ent->s.weapon )
{
case WP_ALEVEL1:
+ meleeAttack( ent, LEVEL1_CLAW_RANGE, LEVEL1_CLAW_WIDTH, LEVEL1_CLAW_WIDTH,
+ LEVEL1_CLAW_DMG, MOD_LEVEL1_CLAW );
+ break;
case WP_ALEVEL1_UPG:
- meleeAttack( ent, LEVEL1_CLAW_RANGE, LEVEL1_CLAW_WIDTH, LEVEL1_CLAW_DMG, MOD_LEVEL1_CLAW );
+ meleeAttack( ent, LEVEL1_CLAW_U_RANGE, LEVEL1_CLAW_WIDTH, LEVEL1_CLAW_WIDTH,
+ LEVEL1_CLAW_DMG, MOD_LEVEL1_CLAW );
break;
case WP_ALEVEL3:
+ meleeAttack( ent, LEVEL3_CLAW_RANGE, LEVEL3_CLAW_WIDTH, LEVEL3_CLAW_WIDTH,
+ LEVEL3_CLAW_DMG, MOD_LEVEL3_CLAW );
+ break;
case WP_ALEVEL3_UPG:
- meleeAttack( ent, LEVEL3_CLAW_RANGE, LEVEL3_CLAW_WIDTH, LEVEL3_CLAW_DMG, MOD_LEVEL3_CLAW );
+ meleeAttack( ent, LEVEL3_CLAW_UPG_RANGE, LEVEL3_CLAW_WIDTH,
+ LEVEL3_CLAW_WIDTH, LEVEL3_CLAW_DMG, MOD_LEVEL3_CLAW );
break;
case WP_ALEVEL2:
- meleeAttack( ent, LEVEL2_CLAW_RANGE, LEVEL2_CLAW_WIDTH, LEVEL2_CLAW_DMG, MOD_LEVEL2_CLAW );
+ meleeAttack( ent, LEVEL2_CLAW_RANGE, LEVEL2_CLAW_WIDTH, LEVEL2_CLAW_WIDTH,
+ LEVEL2_CLAW_DMG, MOD_LEVEL2_CLAW );
break;
case WP_ALEVEL2_UPG:
- meleeAttack( ent, LEVEL2_CLAW_RANGE, LEVEL2_CLAW_WIDTH, LEVEL2_CLAW_DMG, MOD_LEVEL2_CLAW );
+ meleeAttack( ent, LEVEL2_CLAW_U_RANGE, LEVEL2_CLAW_WIDTH, LEVEL2_CLAW_WIDTH,
+ LEVEL2_CLAW_DMG, MOD_LEVEL2_CLAW );
break;
case WP_ALEVEL4:
- meleeAttack( ent, LEVEL4_CLAW_RANGE, LEVEL4_CLAW_WIDTH, LEVEL4_CLAW_DMG, MOD_LEVEL4_CLAW );
+ meleeAttack( ent, LEVEL4_CLAW_RANGE, LEVEL4_CLAW_WIDTH,
+ LEVEL4_CLAW_HEIGHT, LEVEL4_CLAW_DMG, MOD_LEVEL4_CLAW );
break;
case WP_BLASTER:
@@ -1661,11 +1609,9 @@ void FireWeapon( gentity_t *ent )
buildFire( ent, MN_A_BUILD );
break;
case WP_HBUILD:
- case WP_HBUILD2:
buildFire( ent, MN_H_BUILD );
break;
default:
break;
}
}
-
diff --git a/src/game/g_weapondrop.c b/src/game/g_weapondrop.c
new file mode 100644
index 0000000..11884ee
--- /dev/null
+++ b/src/game/g_weapondrop.c
@@ -0,0 +1,199 @@
+//
+// Ported + rewritten ioq3 item-drop.
+//
+// blowFish
+//
+#include "g_local.h"
+
+#define DISABLE_TOUCH_TIME 1000
+#define MISSILE_PRESTEP_TIME 50
+
+//
+// Pickup Weapon
+//
+// ent - The "weapon" being picked up
+// other - The client who picked it up
+//
+void Pickup_Weapon (gentity_t *ent, gentity_t *other)
+{
+ int w = ent->s.modelindex;
+
+ if ( w == WP_NONE )
+ return;
+
+ other->client->ps.stats[ STAT_WEAPON ] = w;
+ other->client->ps.ammo = ent->item.ammo;
+ other->client->ps.clips = ent->item.clips;
+ G_ForceWeaponChange( other, w );
+}
+
+//
+// Touch Weapon
+//
+// ent - The "weapon" being picked up
+// other - The client who picked it up
+//
+void Touch_Weapon (gentity_t *ent, gentity_t *other, trace_t *trace)
+{
+ if( !other->client
+ || other->client->pers.teamSelection == TEAM_NONE
+ || other->client->pers.teamSelection == TEAM_ALIENS )
+ return;
+
+ if( (other->client->lastDropTime + DISABLE_TOUCH_TIME) > level.time)
+ return;
+
+ if ( other->health < 1 )
+ return;
+
+ Pickup_Weapon(ent, other);
+
+ // dropped items will not respawn
+ if ( ent->flags & FL_DROPPED_ITEM )
+ {
+ ent->freeAfterEvent = qtrue;
+ }
+
+ ent->r.svFlags |= SVF_NOCLIENT;
+ ent->s.eFlags |= EF_NODRAW;
+ ent->r.contents = 0;
+
+ trap_LinkEntity( ent );
+}
+
+#define ITEM_RADIUS 15
+
+//
+// Launch Weapon
+//
+// Spawn a weapon and toss it into the world.
+//
+gentity_t *LaunchWeapon (gentity_t* client, weapon_t weap, vec3_t origin, vec3_t velocity)
+{
+ gentity_t *dropped;
+
+ dropped = G_Spawn();
+
+ dropped->s.eType = ET_WEAPON_DROP;
+ dropped->s.modelindex = weap; // store weapon number in modelindex
+ dropped->s.modelindex2 = 1; // This is non-zero is it's a dropped item
+
+ dropped->classname = BG_Weapon(weap)->name;
+ VectorSet (dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
+ VectorSet (dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
+ dropped->r.contents = CONTENTS_TRIGGER;
+
+ dropped->item.ammo = client->client->ps.ammo;
+ dropped->item.clips = client->client->ps.clips;
+
+ dropped->touch = Touch_Weapon;
+
+ G_SetOrigin( dropped, origin );
+ dropped->s.pos.trType = TR_GRAVITY;
+ dropped->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;
+ VectorCopy( velocity, dropped->s.pos.trDelta );
+
+ dropped->s.eFlags |= EF_BOUNCE_HALF;
+ dropped->think = G_FreeEntity;
+ dropped->nextthink = level.time + 30000;
+
+ dropped->flags = FL_DROPPED_ITEM;
+
+ trap_LinkEntity (dropped);
+
+ return dropped;
+}
+
+//
+// Drop Weapon
+//
+// Spawns an weapon and tosses it forward
+//
+gentity_t *G_DropWeapon (gentity_t *ent, weapon_t w, float angle)
+{
+ vec3_t velocity;
+ vec3_t angles;
+
+ // set aiming directions
+ VectorCopy( ent->s.apos.trBase, angles );
+ angles[YAW] += angle;
+ angles[PITCH] = 0; // always forward
+
+ AngleVectors( angles, velocity, NULL, NULL );
+ VectorScale( velocity, 150, velocity );
+ velocity[2] += 200 + crandom() * 50;
+
+ ent->client->lastDropTime = level.time;
+ return LaunchWeapon( ent, w, ent->s.pos.trBase, velocity );
+}
+
+//
+// Run Weapon Drops
+//
+void G_RunWeaponDrop (gentity_t *ent)
+{
+ vec3_t origin;
+ trace_t tr;
+ int contents;
+ int mask;
+
+ // if its groundentity has been set to none, it may have been pushed off an edge
+ if ( ent->s.groundEntityNum == ENTITYNUM_NONE )
+ {
+ if ( ent->s.pos.trType != TR_GRAVITY )
+ {
+ ent->s.pos.trType = TR_GRAVITY;
+ ent->s.pos.trTime = level.time;
+ }
+ }
+
+ if ( ent->s.pos.trType == TR_STATIONARY )
+ {
+ // check think function
+ G_RunThink( ent );
+ return;
+ }
+
+ // get current position
+ BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
+
+ // trace a line from the previous position to the current position
+ if ( ent->clipmask )
+ {
+ mask = ent->clipmask;
+ }
+ else
+ {
+ mask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
+ }
+
+ trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin,
+ ent->r.ownerNum, mask );
+
+ VectorCopy( tr.endpos, ent->r.currentOrigin );
+
+ if ( tr.startsolid )
+ {
+ tr.fraction = 0;
+ }
+
+ trap_LinkEntity( ent ); // FIXME: avoid this for stationary?
+
+ // check think function
+ G_RunThink( ent );
+
+ if ( tr.fraction == 1 )
+ {
+ return;
+ }
+
+ // if it is in a nodrop volume, remove it
+ contents = trap_PointContents( ent->r.currentOrigin, -1 );
+ if ( contents & CONTENTS_NODROP )
+ {
+ G_FreeEntity( ent );
+ return;
+ }
+
+ G_BounceMissile( ent, &tr );
+}
diff --git a/src/game/tremulous.h b/src/game/tremulous.h
index 423d465..f5f5e16 100644
--- a/src/game/tremulous.h
+++ b/src/game/tremulous.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,11 +17,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
+#ifndef _TREMULOUS_H_
+#define _TREMULOUS_H_
/*
* ALIEN weapons
@@ -41,86 +44,101 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define ABUILDER_CLAW_WIDTH 4.0f
#define ABUILDER_CLAW_REPEAT 1000
#define ABUILDER_CLAW_K_SCALE 1.0f
-#define ABUILDER_BASE_DELAY 17000
-#define ABUILDER_ADV_DELAY 12000
#define ABUILDER_BLOB_DMG ADM(4)
#define ABUILDER_BLOB_REPEAT 1000
#define ABUILDER_BLOB_SPEED 800.0f
#define ABUILDER_BLOB_SPEED_MOD 0.5f
-#define ABUILDER_BLOB_TIME 5000
+#define ABUILDER_BLOB_TIME 2000
-#define LEVEL0_BITE_DMG ADM(48)
+#define LEVEL0_BITE_DMG ADM(36)
#define LEVEL0_BITE_RANGE 64.0f
#define LEVEL0_BITE_WIDTH 6.0f
#define LEVEL0_BITE_REPEAT 500
#define LEVEL0_BITE_K_SCALE 1.0f
#define LEVEL1_CLAW_DMG ADM(32)
-#define LEVEL1_CLAW_RANGE 96.0f
+#define LEVEL1_CLAW_RANGE 64.0f
+#define LEVEL1_CLAW_U_RANGE LEVEL1_CLAW_RANGE + 3.0f
#define LEVEL1_CLAW_WIDTH 10.0f
#define LEVEL1_CLAW_REPEAT 600
#define LEVEL1_CLAW_U_REPEAT 500
#define LEVEL1_CLAW_K_SCALE 1.0f
#define LEVEL1_CLAW_U_K_SCALE 1.0f
-#define LEVEL1_GRAB_RANGE 64.0f
+#define LEVEL1_GRAB_RANGE 96.0f
+#define LEVEL1_GRAB_U_RANGE LEVEL1_GRAB_RANGE + 3.0f
#define LEVEL1_GRAB_TIME 300
-#define LEVEL1_GRAB_U_TIME 450
+#define LEVEL1_GRAB_U_TIME 300
#define LEVEL1_PCLOUD_DMG ADM(4)
-#define LEVEL1_PCLOUD_RANGE 200.0f
+#define LEVEL1_PCLOUD_RANGE 120.0f
#define LEVEL1_PCLOUD_REPEAT 2000
#define LEVEL1_PCLOUD_TIME 10000
-#define LEVEL1_PCLOUD_BOOST_TIME 5000
-#define LEVEL1_REGEN_RANGE 200.0f
#define LEVEL1_REGEN_MOD 2.0f
+#define LEVEL1_UPG_REGEN_MOD 3.0f
+#define LEVEL1_REGEN_SCOREINC AVM(100) // score added for healing per 10s
+#define LEVEL1_UPG_REGEN_SCOREINC AVM(200)
#define LEVEL2_CLAW_DMG ADM(40)
-#define LEVEL2_CLAW_RANGE 96.0f
-#define LEVEL2_CLAW_WIDTH 12.0f
+#define LEVEL2_CLAW_RANGE 80.0f
+#define LEVEL2_CLAW_U_RANGE LEVEL2_CLAW_RANGE + 2.0f
+#define LEVEL2_CLAW_WIDTH 14.0f
#define LEVEL2_CLAW_REPEAT 500
#define LEVEL2_CLAW_K_SCALE 1.0f
#define LEVEL2_CLAW_U_REPEAT 400
#define LEVEL2_CLAW_U_K_SCALE 1.0f
-#define LEVEL2_AREAZAP_DMG ADM(80)
+#define LEVEL2_AREAZAP_DMG ADM(60)
#define LEVEL2_AREAZAP_RANGE 200.0f
+#define LEVEL2_AREAZAP_CHAIN_RANGE 150.0f
+#define LEVEL2_AREAZAP_CHAIN_FALLOFF 8.0f
#define LEVEL2_AREAZAP_WIDTH 15.0f
#define LEVEL2_AREAZAP_REPEAT 1500
#define LEVEL2_AREAZAP_TIME 1000
-#define LEVEL2_AREAZAP_MAX_TARGETS 3
+#define LEVEL2_AREAZAP_MAX_TARGETS 5
#define LEVEL2_WALLJUMP_MAXSPEED 1000.0f
#define LEVEL3_CLAW_DMG ADM(80)
-#define LEVEL3_CLAW_RANGE 96.0f
-#define LEVEL3_CLAW_WIDTH 16.0f
-#define LEVEL3_CLAW_REPEAT 700
+#define LEVEL3_CLAW_RANGE 80.0f
+#define LEVEL3_CLAW_UPG_RANGE LEVEL3_CLAW_RANGE + 3.0f
+#define LEVEL3_CLAW_WIDTH 12.0f
+#define LEVEL3_CLAW_REPEAT 900
#define LEVEL3_CLAW_K_SCALE 1.0f
-#define LEVEL3_CLAW_U_REPEAT 600
+#define LEVEL3_CLAW_U_REPEAT 800
#define LEVEL3_CLAW_U_K_SCALE 1.0f
#define LEVEL3_POUNCE_DMG ADM(100)
-#define LEVEL3_POUNCE_RANGE 72.0f
-#define LEVEL3_POUNCE_WIDTH 16.0f
-#define LEVEL3_POUNCE_SPEED 700
-#define LEVEL3_POUNCE_UPG_SPEED 800
-#define LEVEL3_POUNCE_SPEED_MOD 0.75f
-#define LEVEL3_POUNCE_CHARGE_TIME 700
-#define LEVEL3_POUNCE_TIME 400
+#define LEVEL3_POUNCE_RANGE 48.0f
+#define LEVEL3_POUNCE_UPG_RANGE LEVEL3_POUNCE_RANGE + 3.0f
+#define LEVEL3_POUNCE_WIDTH 14.0f
+#define LEVEL3_POUNCE_TIME 800 // msec for full Dragoon pounce
+#define LEVEL3_POUNCE_TIME_UPG 800 // msec for full Adv. Dragoon pounce
+#define LEVEL3_POUNCE_TIME_MIN 200 // msec before which pounce cancels
+#define LEVEL3_POUNCE_REPEAT 400 // msec before a new pounce starts
+#define LEVEL3_POUNCE_SPEED_MOD 0.75f // walking speed modifier for pounce charging
+#define LEVEL3_POUNCE_JUMP_MAG 700 // Dragoon pounce jump power
+#define LEVEL3_POUNCE_JUMP_MAG_UPG 800 // Adv. Dragoon pounce jump power
#define LEVEL3_BOUNCEBALL_DMG ADM(110)
-#define LEVEL3_BOUNCEBALL_REPEAT 1000
+#define LEVEL3_BOUNCEBALL_REPEAT 1200
#define LEVEL3_BOUNCEBALL_SPEED 1000.0f
+#define LEVEL3_BOUNCEBALL_RADIUS 75
+#define LEVEL3_BOUNCEBALL_REGEN 15000 // msec until new barb
#define LEVEL4_CLAW_DMG ADM(100)
-#define LEVEL4_CLAW_RANGE 128.0f
-#define LEVEL4_CLAW_WIDTH 20.0f
-#define LEVEL4_CLAW_REPEAT 750
+#define LEVEL4_CLAW_RANGE 100.0f
+#define LEVEL4_CLAW_WIDTH 14.0f
+#define LEVEL4_CLAW_HEIGHT 20.0f
+#define LEVEL4_CLAW_REPEAT 800
#define LEVEL4_CLAW_K_SCALE 1.0f
-#define LEVEL4_CHARGE_SPEED 2.0f
-#define LEVEL4_CHARGE_TIME 3000
-#define LEVEL4_CHARGE_CHARGE_TIME 1500
-#define LEVEL4_MIN_CHARGE_TIME 750
-#define LEVEL4_CHARGE_CHARGE_RATIO (LEVEL4_CHARGE_TIME/LEVEL4_CHARGE_CHARGE_TIME)
-#define LEVEL4_CHARGE_REPEAT 1000
-#define LEVEL4_CHARGE_DMG ADM(110)
+#define LEVEL4_TRAMPLE_DMG ADM(111)
+#define LEVEL4_TRAMPLE_SPEED 2.0f
+#define LEVEL4_TRAMPLE_CHARGE_MIN 375 // minimum msec to start a charge
+#define LEVEL4_TRAMPLE_CHARGE_MAX 1000 // msec to maximum charge stored
+#define LEVEL4_TRAMPLE_CHARGE_TRIGGER 3000 // msec charge starts on its own
+#define LEVEL4_TRAMPLE_DURATION 3000 // msec trample lasts on full charge
+#define LEVEL4_TRAMPLE_STOP_PENALTY 1 // charge lost per msec when stopped
+#define LEVEL4_TRAMPLE_REPEAT 100 // msec before a trample will rehit a player
+#define LEVEL4_CRUSH_DAMAGE_PER_V 0.5f // damage per falling velocity
+#define LEVEL4_CRUSH_DAMAGE 120 // to players only
+#define LEVEL4_CRUSH_REPEAT 500 // player damage repeat
/*
* ALIEN classes
@@ -138,68 +156,66 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define ALIEN_VALUE_MODIFIER 1.0f
#define AVM(h) ((int)((float)h*ALIEN_VALUE_MODIFIER))
-#define ABUILDER_SPEED 0.8f
-#define ABUILDER_VALUE AVM(200)
+#define ABUILDER_SPEED 0.9f
+#define ABUILDER_VALUE AVM(240)
#define ABUILDER_HEALTH AHM(50)
-#define ABUILDER_REGEN 2
+#define ABUILDER_REGEN (0.04f * ABUILDER_HEALTH)
#define ABUILDER_COST 0
-#define ABUILDER_UPG_SPEED 1.0f
-#define ABUILDER_UPG_VALUE AVM(250)
+#define ABUILDER_UPG_SPEED 0.9f
+#define ABUILDER_UPG_VALUE AVM(300)
#define ABUILDER_UPG_HEALTH AHM(75)
-#define ABUILDER_UPG_REGEN 3
+#define ABUILDER_UPG_REGEN (0.04f * ABUILDER_UPG_HEALTH)
#define ABUILDER_UPG_COST 0
-#define LEVEL0_SPEED 1.3f
-#define LEVEL0_VALUE AVM(175)
+#define LEVEL0_SPEED 1.4f
+#define LEVEL0_VALUE AVM(180)
#define LEVEL0_HEALTH AHM(25)
-#define LEVEL0_REGEN 1
+#define LEVEL0_REGEN (0.05f * LEVEL0_HEALTH)
#define LEVEL0_COST 0
#define LEVEL1_SPEED 1.25f
-#define LEVEL1_VALUE AVM(225)
-#define LEVEL1_HEALTH AHM(75)
-#define LEVEL1_REGEN 2
+#define LEVEL1_VALUE AVM(270)
+#define LEVEL1_HEALTH AHM(60)
+#define LEVEL1_REGEN (0.03f * LEVEL1_HEALTH)
#define LEVEL1_COST 1
#define LEVEL1_UPG_SPEED 1.25f
-#define LEVEL1_UPG_VALUE AVM(275)
-#define LEVEL1_UPG_HEALTH AHM(100)
-#define LEVEL1_UPG_REGEN 3
+#define LEVEL1_UPG_VALUE AVM(330)
+#define LEVEL1_UPG_HEALTH AHM(80)
+#define LEVEL1_UPG_REGEN (0.03f * LEVEL1_UPG_HEALTH)
#define LEVEL1_UPG_COST 1
#define LEVEL2_SPEED 1.2f
-#define LEVEL2_VALUE AVM(350)
+#define LEVEL2_VALUE AVM(420)
#define LEVEL2_HEALTH AHM(150)
-#define LEVEL2_REGEN 4
+#define LEVEL2_REGEN (0.03f * LEVEL2_HEALTH)
#define LEVEL2_COST 1
#define LEVEL2_UPG_SPEED 1.2f
-#define LEVEL2_UPG_VALUE AVM(450)
+#define LEVEL2_UPG_VALUE AVM(540)
#define LEVEL2_UPG_HEALTH AHM(175)
-#define LEVEL2_UPG_REGEN 5
+#define LEVEL2_UPG_REGEN (0.03f * LEVEL2_UPG_HEALTH)
#define LEVEL2_UPG_COST 1
#define LEVEL3_SPEED 1.1f
-#define LEVEL3_VALUE AVM(500)
+#define LEVEL3_VALUE AVM(600)
#define LEVEL3_HEALTH AHM(200)
-#define LEVEL3_REGEN 6
+#define LEVEL3_REGEN (0.03f * LEVEL3_HEALTH)
#define LEVEL3_COST 1
#define LEVEL3_UPG_SPEED 1.1f
-#define LEVEL3_UPG_VALUE AVM(600)
+#define LEVEL3_UPG_VALUE AVM(720)
#define LEVEL3_UPG_HEALTH AHM(250)
-#define LEVEL3_UPG_REGEN 7
+#define LEVEL3_UPG_REGEN (0.03f * LEVEL3_UPG_HEALTH)
#define LEVEL3_UPG_COST 1
#define LEVEL4_SPEED 1.2f
-#define LEVEL4_VALUE AVM(800)
-#define LEVEL4_HEALTH AHM(400)
-#define LEVEL4_REGEN 7
+#define LEVEL4_VALUE AVM(960)
+#define LEVEL4_HEALTH AHM(350)
+#define LEVEL4_REGEN (0.025f * LEVEL4_HEALTH)
#define LEVEL4_COST 2
-
-
/*
* ALIEN buildables
*
@@ -216,6 +232,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define ALIEN_BHLTH_MODIFIER 1.0f
#define ABHM(h) ((int)((float)h*ALIEN_BHLTH_MODIFIER))
+#define ALIEN_BVALUE_MODIFIER 90.0f
+#define ABVM(h) ((int)((float)h*ALIEN_BVALUE_MODIFIER))
#define CREEP_BASESIZE 700
#define CREEP_TIMEOUT 1000
@@ -223,44 +241,53 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define CREEP_ARMOUR_MODIFIER 0.75f
#define CREEP_SCALEDOWN_TIME 3000
+#define PCLOUD_MODIFIER 0.5f
+#define PCLOUD_ARMOUR_MODIFIER 0.75f
+
#define ASPAWN_BP 10
#define ASPAWN_BT 15000
#define ASPAWN_HEALTH ABHM(250)
#define ASPAWN_REGEN 8
#define ASPAWN_SPLASHDAMAGE 50
-#define ASPAWN_SPLASHRADIUS 50
+#define ASPAWN_SPLASHRADIUS 100
#define ASPAWN_CREEPSIZE 120
-#define ASPAWN_VALUE 150
+#define ASPAWN_VALUE ABVM(ASPAWN_BP)
-#define BARRICADE_BP 10
+#define BARRICADE_BP 8
#define BARRICADE_BT 20000
-#define BARRICADE_HEALTH ABHM(200)
+#define BARRICADE_HEALTH ABHM(300)
#define BARRICADE_REGEN 14
#define BARRICADE_SPLASHDAMAGE 50
-#define BARRICADE_SPLASHRADIUS 50
+#define BARRICADE_SPLASHRADIUS 100
#define BARRICADE_CREEPSIZE 120
+#define BARRICADE_SHRINKPROP 0.25f
+#define BARRICADE_SHRINKTIMEOUT 500
+#define BARRICADE_VALUE ABVM(BARRICADE_BP)
#define BOOSTER_BP 12
#define BOOSTER_BT 15000
#define BOOSTER_HEALTH ABHM(150)
#define BOOSTER_REGEN 8
#define BOOSTER_SPLASHDAMAGE 50
-#define BOOSTER_SPLASHRADIUS 50
+#define BOOSTER_SPLASHRADIUS 100
#define BOOSTER_CREEPSIZE 120
-#define BOOSTER_INTERVAL 30000 //time in msec between uses (per player)
-#define BOOSTER_REGEN_MOD 2.0f
-#define BOOST_TIME 30000
+#define BOOSTER_REGEN_MOD 3.0f
+#define BOOSTER_VALUE ABVM(BOOSTER_BP)
+#define BOOST_TIME 20000
+#define BOOST_WARN_TIME 15000
#define ACIDTUBE_BP 8
#define ACIDTUBE_BT 15000
#define ACIDTUBE_HEALTH ABHM(125)
#define ACIDTUBE_REGEN 10
-#define ACIDTUBE_SPLASHDAMAGE 6
-#define ACIDTUBE_SPLASHRADIUS 300
+#define ACIDTUBE_SPLASHDAMAGE 50
+#define ACIDTUBE_SPLASHRADIUS 100
#define ACIDTUBE_CREEPSIZE 120
+#define ACIDTUBE_DAMAGE 8
#define ACIDTUBE_RANGE 300.0f
-#define ACIDTUBE_REPEAT 3000
-#define ACIDTUBE_K_SCALE 1.0f
+#define ACIDTUBE_REPEAT 300
+#define ACIDTUBE_REPEAT_ANIM 2000
+#define ACIDTUBE_VALUE ABVM(ACIDTUBE_BP)
#define HIVE_BP 12
#define HIVE_BT 20000
@@ -269,12 +296,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define HIVE_SPLASHDAMAGE 30
#define HIVE_SPLASHRADIUS 200
#define HIVE_CREEPSIZE 120
-#define HIVE_RANGE 400.0f
-#define HIVE_REPEAT 5000
+#define HIVE_SENSE_RANGE 500.0f
+#define HIVE_LIFETIME 3000
+#define HIVE_REPEAT 3000
#define HIVE_K_SCALE 1.0f
-#define HIVE_DMG 50
-#define HIVE_SPEED 240.0f
+#define HIVE_DMG 80
+#define HIVE_SPEED 320.0f
#define HIVE_DIR_CHANGE_PERIOD 500
+#define HIVE_VALUE ABVM(HIVE_BP)
#define TRAPPER_BP 8
#define TRAPPER_BT 12000
@@ -285,7 +314,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define TRAPPER_CREEPSIZE 30
#define TRAPPER_RANGE 400
#define TRAPPER_REPEAT 1000
-#define TRAPPER_K_SCALE 1.0f
+#define TRAPPER_VALUE ABVM(TRAPPER_BP)
#define LOCKBLOB_SPEED 650.0f
#define LOCKBLOB_LOCKTIME 5000
#define LOCKBLOB_DOT 0.85f // max angle = acos( LOCKBLOB_DOT )
@@ -300,17 +329,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define OVERMIND_CREEPSIZE 120
#define OVERMIND_ATTACK_RANGE 150.0f
#define OVERMIND_ATTACK_REPEAT 1000
-#define OVERMIND_VALUE 300
-
-#define HOVEL_BP 0
-#define HOVEL_BT 15000
-#define HOVEL_HEALTH ABHM(375)
-#define HOVEL_REGEN 20
-#define HOVEL_SPLASHDAMAGE 20
-#define HOVEL_SPLASHRADIUS 200
-#define HOVEL_CREEPSIZE 120
-
-
+#define OVERMIND_VALUE ABVM(30)
/*
* ALIEN misc
@@ -320,14 +339,21 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define ALIENSENSE_RANGE 1000.0f
+#define REGEN_BOOST_RANGE 200.0f
-#define ALIEN_POISON_TIME 5000
+#define ALIEN_POISON_TIME 10000
#define ALIEN_POISON_DMG 5
#define ALIEN_POISON_DIVIDER (1.0f/1.32f) //about 1.0/(time`th root of damage)
#define ALIEN_SPAWN_REPEAT_TIME 10000
#define ALIEN_REGEN_DAMAGE_TIME 2000 //msec since damage that regen starts again
+#define ALIEN_REGEN_NOCREEP_MOD (1.0f/3.0f) //regen off creep
+
+#define ALIEN_MAX_FRAGS 9
+#define ALIEN_MAX_CREDITS (ALIEN_MAX_FRAGS*ALIEN_CREDITS_PER_KILL)
+#define ALIEN_CREDITS_PER_KILL 400
+#define ALIEN_TK_SUICIDE_PENALTY 350
/*
* HUMAN weapons
@@ -347,7 +373,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define BLASTER_K_SCALE 1.0f
#define BLASTER_SPREAD 200
#define BLASTER_SPEED 1400
-#define BLASTER_DMG HDM(9)
+#define BLASTER_DMG HDM(10)
+#define BLASTER_SIZE 5
#define RIFLE_CLIPSIZE 30
#define RIFLE_MAXCLIPS 6
@@ -361,8 +388,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define PAINSAW_PRICE 100
#define PAINSAW_REPEAT 75
#define PAINSAW_K_SCALE 1.0f
-#define PAINSAW_DAMAGE HDM(15)
-#define PAINSAW_RANGE 40.0f
+#define PAINSAW_DAMAGE HDM(11)
+#define PAINSAW_RANGE 64.0f
+#define PAINSAW_WIDTH 0.0f
+#define PAINSAW_HEIGHT 8.0f
#define GRENADE_PRICE 200
#define GRENADE_REPEAT 0
@@ -373,13 +402,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define SHOTGUN_PRICE 150
#define SHOTGUN_SHELLS 8
-#define SHOTGUN_PELLETS 8 //used to sync server and client side
+#define SHOTGUN_PELLETS 11 //used to sync server and client side
#define SHOTGUN_MAXCLIPS 3
#define SHOTGUN_REPEAT 1000
#define SHOTGUN_K_SCALE 1.0f
#define SHOTGUN_RELOAD 2000
-#define SHOTGUN_SPREAD 900
-#define SHOTGUN_DMG HDM(7)
+#define SHOTGUN_SPREAD 700
+#define SHOTGUN_DMG HDM(5)
+#define SHOTGUN_RANGE (8192 * 12)
#define LASGUN_PRICE 250
#define LASGUN_AMMO 200
@@ -391,7 +421,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define MDRIVER_PRICE 350
#define MDRIVER_CLIPSIZE 5
#define MDRIVER_MAXCLIPS 4
-#define MDRIVER_DMG HDM(38)
+#define MDRIVER_DMG HDM(40)
#define MDRIVER_REPEAT 1000
#define MDRIVER_K_SCALE 1.0f
#define MDRIVER_RELOAD 2000
@@ -400,64 +430,66 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define CHAINGUN_BULLETS 300
#define CHAINGUN_REPEAT 80
#define CHAINGUN_K_SCALE 1.0f
-#define CHAINGUN_SPREAD 1000
+#define CHAINGUN_SPREAD 900
#define CHAINGUN_DMG HDM(6)
-#define PRIFLE_PRICE 400
-#define PRIFLE_CLIPS 50
-#define PRIFLE_MAXCLIPS 4
+#define FLAMER_PRICE 400
+#define FLAMER_GAS 200
+#define FLAMER_REPEAT 200
+#define FLAMER_K_SCALE 2.0f
+#define FLAMER_DMG HDM(20)
+#define FLAMER_SPLASHDAMAGE HDM(10)
+#define FLAMER_RADIUS 50 // splash radius
+#define FLAMER_SIZE 15 // missile bounding box
+#define FLAMER_LIFETIME 700.0f
+#define FLAMER_SPEED 500.0f
+#define FLAMER_LAG 0.65f // the amount of player velocity that is added to the fireball
+
+#define PRIFLE_PRICE 450
+#define PRIFLE_CLIPS 40
+#define PRIFLE_MAXCLIPS 5
#define PRIFLE_REPEAT 100
#define PRIFLE_K_SCALE 1.0f
#define PRIFLE_RELOAD 2000
#define PRIFLE_DMG HDM(9)
-#define PRIFLE_SPEED 1000
-
-#define FLAMER_PRICE 450
-#define FLAMER_GAS 150
-#define FLAMER_REPEAT 200
-#define FLAMER_K_SCALE 1.0f
-#define FLAMER_DMG HDM(20)
-#define FLAMER_RADIUS 50
-#define FLAMER_LIFETIME 800.0f
-#define FLAMER_SPEED 200.0f
-#define FLAMER_LAG 0.65f //the amount of player velocity that is added to the fireball
+#define PRIFLE_SPEED 1200
+#define PRIFLE_SIZE 5
#define LCANNON_PRICE 600
-#define LCANNON_AMMO 90
-#define LCANNON_REPEAT 500
+#define LCANNON_AMMO 80
#define LCANNON_K_SCALE 1.0f
-#define LCANNON_CHARGEREPEAT 1000
-#define LCANNON_RELOAD 2000
+#define LCANNON_REPEAT 500
+#define LCANNON_RELOAD 0
#define LCANNON_DAMAGE HDM(265)
-#define LCANNON_RADIUS 150
-#define LCANNON_SECONDARY_DAMAGE HDM(27)
-#define LCANNON_SECONDARY_RADIUS 75
-#define LCANNON_SPEED 350
-#define LCANNON_CHARGE_TIME 2000
-#define LCANNON_TOTAL_CHARGE 255
-#define LCANNON_MIN_CHARGE 50
+#define LCANNON_RADIUS 150 // primary splash damage radius
+#define LCANNON_SIZE 5 // missile bounding box radius
+#define LCANNON_SECONDARY_DAMAGE HDM(30)
+#define LCANNON_SECONDARY_RADIUS 75 // secondary splash damage radius
+#define LCANNON_SECONDARY_SPEED 1400
+#define LCANNON_SECONDARY_RELOAD 2000
+#define LCANNON_SECONDARY_REPEAT 1000
+#define LCANNON_SPEED 700
+#define LCANNON_CHARGE_TIME_MAX 3000
+#define LCANNON_CHARGE_TIME_MIN 100
+#define LCANNON_CHARGE_TIME_WARN 2000
+#define LCANNON_CHARGE_AMMO 10 // ammo cost of a full charge shot
#define HBUILD_PRICE 0
#define HBUILD_REPEAT 1000
-#define HBUILD_DELAY 17500
#define HBUILD_HEALRATE 18
-#define HBUILD2_PRICE 0
-#define HBUILD2_REPEAT 1000
-#define HBUILD2_DELAY 15000
-
-
-
/*
* HUMAN upgrades
*/
#define LIGHTARMOUR_PRICE 70
#define LIGHTARMOUR_POISON_PROTECTION 1
+#define LIGHTARMOUR_PCLOUD_PROTECTION 1000
#define HELMET_PRICE 90
#define HELMET_RANGE 1000.0f
-#define HELMET_POISON_PROTECTION 2
+#define HELMET_POISON_PROTECTION 1
+#define HELMET_PCLOUD_PROTECTION 1000
#define MEDKIT_PRICE 0
@@ -471,19 +503,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define JETPACK_DISABLE_CHANCE 0.3f
#define BSUIT_PRICE 400
-#define BSUIT_POISON_PROTECTION 4
-
-#define MGCLIP_PRICE 0
-
-#define CGAMMO_PRICE 0
-
-#define GAS_PRICE 0
+#define BSUIT_POISON_PROTECTION 3
+#define BSUIT_PCLOUD_PROTECTION 3000
#define MEDKIT_POISON_IMMUNITY_TIME 0
#define MEDKIT_STARTUP_TIME 4000
#define MEDKIT_STARTUP_SPEED 5
-
/*
* HUMAN buildables
*
@@ -492,7 +518,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* _SPLASHDAMGE - the amount of damage caused by this buildable when it blows up
* _SPLASHRADIUS - the radius around which it does this damage
*
- * REACTOR_BASESIZE - the maximum distance a buildable can be from an reactor
+ * REACTOR_BASESIZE - the maximum distance a buildable can be from a reactor
* REPEATER_BASESIZE - the maximum distance a buildable can be from a repeater
* HUMAN_BHLTH_MODIFIER - overall health modifier for coarse tuning
*
@@ -500,6 +526,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define HUMAN_BHLTH_MODIFIER 1.0f
#define HBHM(h) ((int)((float)h*HUMAN_BHLTH_MODIFIER))
+#define HUMAN_BVALUE_MODIFIER 240.0f
+#define HBVM(h) ((int)((float)h*(float)HUMAN_BVALUE_MODIFIER)) // remember these are measured in credits not frags (c.f. ALIEN_CREDITS_PER_KILL)
#define REACTOR_BASESIZE 1000
#define REPEATER_BASESIZE 500
@@ -510,31 +538,30 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define HSPAWN_HEALTH HBHM(310)
#define HSPAWN_SPLASHDAMAGE 50
#define HSPAWN_SPLASHRADIUS 100
-#define HSPAWN_VALUE 1
+#define HSPAWN_VALUE HBVM(HSPAWN_BP)
#define MEDISTAT_BP 8
#define MEDISTAT_BT 10000
#define MEDISTAT_HEALTH HBHM(190)
#define MEDISTAT_SPLASHDAMAGE 50
#define MEDISTAT_SPLASHRADIUS 100
+#define MEDISTAT_VALUE HBVM(MEDISTAT_BP)
#define MGTURRET_BP 8
#define MGTURRET_BT 10000
#define MGTURRET_HEALTH HBHM(190)
#define MGTURRET_SPLASHDAMAGE 100
#define MGTURRET_SPLASHRADIUS 100
-#define MGTURRET_ANGULARSPEED 8 //degrees/think ~= 200deg/sec
-#define MGTURRET_ACCURACYTOLERANCE MGTURRET_ANGULARSPEED / 1.5f //angular difference for turret to fire
+#define MGTURRET_ANGULARSPEED 12
+#define MGTURRET_ACCURACY_TO_FIRE 0
#define MGTURRET_VERTICALCAP 30 // +/- maximum pitch
-#define MGTURRET_REPEAT 100
+#define MGTURRET_REPEAT 150
#define MGTURRET_K_SCALE 1.0f
-#define MGTURRET_RANGE 300.0f
+#define MGTURRET_RANGE 400.0f
#define MGTURRET_SPREAD 200
-#define MGTURRET_DMG HDM(4)
-#define MGTURRET_DCC_ANGULARSPEED 10
-#define MGTURRET_DCC_ACCURACYTOLERANCE MGTURRET_DCC_ANGULARSPEED / 1.5f
-#define MGTURRET_GRAB_ANGULARSPEED 3
-#define MGTURRET_GRAB_ACCURACYTOLERANCE MGTURRET_GRAB_ANGULARSPEED / 1.5f
+#define MGTURRET_DMG HDM(8)
+#define MGTURRET_SPINUP_TIME 750 // time between target sighted and fire
+#define MGTURRET_VALUE HBVM(MGTURRET_BP)
#define TESLAGEN_BP 10
#define TESLAGEN_BT 15000
@@ -543,20 +570,26 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define TESLAGEN_SPLASHRADIUS 100
#define TESLAGEN_REPEAT 250
#define TESLAGEN_K_SCALE 4.0f
-#define TESLAGEN_RANGE 250
-#define TESLAGEN_DMG HDM(9)
+#define TESLAGEN_RANGE 200
+#define TESLAGEN_DMG HDM(10)
+#define TESLAGEN_VALUE HBVM(TESLAGEN_BP)
#define DC_BP 8
#define DC_BT 10000
#define DC_HEALTH HBHM(190)
#define DC_SPLASHDAMAGE 50
#define DC_SPLASHRADIUS 100
+#define DC_ATTACK_PERIOD 10000 // how often to spam "under attack"
+#define DC_HEALRATE 4
+#define DC_RANGE 1000
+#define DC_VALUE HBVM(DC_BP)
#define ARMOURY_BP 10
#define ARMOURY_BT 10000
-#define ARMOURY_HEALTH HBHM(280)
+#define ARMOURY_HEALTH HBHM(420)
#define ARMOURY_SPLASHDAMAGE 50
#define ARMOURY_SPLASHRADIUS 100
+#define ARMOURY_VALUE HBVM(ARMOURY_BP)
#define REACTOR_BP 0
#define REACTOR_BT 20000
@@ -566,14 +599,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define REACTOR_ATTACK_RANGE 100.0f
#define REACTOR_ATTACK_REPEAT 1000
#define REACTOR_ATTACK_DAMAGE 40
-#define REACTOR_VALUE 2
+#define REACTOR_ATTACK_DCC_REPEAT 1000
+#define REACTOR_ATTACK_DCC_RANGE 150.0f
+#define REACTOR_ATTACK_DCC_DAMAGE 40
+#define REACTOR_VALUE HBVM(30)
-#define REPEATER_BP 0
+#define REPEATER_BP 4
#define REPEATER_BT 10000
#define REPEATER_HEALTH HBHM(250)
#define REPEATER_SPLASHDAMAGE 50
#define REPEATER_SPLASHRADIUS 100
-#define REPEATER_INACTIVE_TIME 90000
+#define REPEATER_VALUE HBVM(REPEATER_BP)
/*
* HUMAN misc
@@ -583,13 +619,33 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define HUMAN_JOG_MODIFIER 1.0f
#define HUMAN_BACK_MODIFIER 0.8f
#define HUMAN_SIDE_MODIFIER 0.9f
+#define HUMAN_DODGE_SIDE_MODIFIER 2.9f
+#define HUMAN_DODGE_SLOWED_MODIFIER 0.9f
+#define HUMAN_DODGE_UP_MODIFIER 0.5f
+#define HUMAN_DODGE_TIMEOUT 500
+#define HUMAN_LAND_FRICTION 3.0f
-#define STAMINA_STOP_RESTORE 25
+#define STAMINA_STOP_RESTORE 30
#define STAMINA_WALK_RESTORE 15
-#define STAMINA_SPRINT_TAKE 8
-#define STAMINA_LARMOUR_TAKE 4
+#define STAMINA_MEDISTAT_RESTORE 30 // stacked on STOP or WALK
+#define STAMINA_SPRINT_TAKE 6
+#define STAMINA_JUMP_TAKE 250
+#define STAMINA_DODGE_TAKE 250
+#define STAMINA_MAX 1000
+#define STAMINA_BREATHING_LEVEL 0
+#define STAMINA_SLOW_LEVEL -500
+#define STAMINA_BLACKOUT_LEVEL -800
#define HUMAN_SPAWN_REPEAT_TIME 10000
+#define HUMAN_REGEN_DAMAGE_TIME 2000 //msec since damage before dcc repairs
+
+#define HUMAN_MAX_CREDITS 2000
+#define HUMAN_TK_SUICIDE_PENALTY 150
+
+#define HUMAN_BUILDER_SCOREINC 50 // builders receive this many points every 10 seconds
+#define ALIEN_BUILDER_SCOREINC AVM(100) // builders receive this many points every 10 seconds
+
+#define HUMAN_BUILDABLE_INACTIVE_TIME 90000
/*
* Misc
@@ -599,29 +655,27 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define MAX_FALL_DISTANCE 120.0f //the fall distance at which maximum damage is dealt
#define AVG_FALL_DISTANCE ((MIN_FALL_DISTANCE+MAX_FALL_DISTANCE)/2.0f)
-#define HUMAN_MAXED 900 //a human with a strong selection of weapons/upgrades
-#define HUMAN_MAX_CREDITS 2000
-#define ALIEN_MAX_KILLS 9
-#define ALIEN_MAX_SINGLE_KILLS 3
-
-#define FREEKILL_PERIOD 120000 //msec
-#define FREEKILL_ALIEN 1
+#define DEFAULT_FREEKILL_PERIOD "120" //seconds
+#define FREEKILL_ALIEN ALIEN_CREDITS_PER_KILL
#define FREEKILL_HUMAN LEVEL0_VALUE
-#define DEFAULT_ALIEN_BUILDPOINTS "130"
-#define DEFAULT_ALIEN_STAGE2_THRESH "20"
-#define DEFAULT_ALIEN_STAGE3_THRESH "40"
+#define DEFAULT_ALIEN_BUILDPOINTS "150"
+#define DEFAULT_ALIEN_QUEUE_TIME "12000"
+#define DEFAULT_ALIEN_STAGE2_THRESH "12000"
+#define DEFAULT_ALIEN_STAGE3_THRESH "24000"
#define DEFAULT_ALIEN_MAX_STAGE "2"
-#define DEFAULT_HUMAN_BUILDPOINTS "130"
-#define DEFAULT_HUMAN_STAGE2_THRESH "20"
-#define DEFAULT_HUMAN_STAGE3_THRESH "40"
+#define DEFAULT_HUMAN_BUILDPOINTS "100"
+#define DEFAULT_HUMAN_QUEUE_TIME "8000"
+#define DEFAULT_HUMAN_REPEATER_BUILDPOINTS "20"
+#define DEFAULT_HUMAN_REPEATER_QUEUE_TIME "2000"
+#define DEFAULT_HUMAN_REPEATER_MAX_ZONES "500"
+#define DEFAULT_HUMAN_STAGE2_THRESH "6000"
+#define DEFAULT_HUMAN_STAGE3_THRESH "12000"
#define DEFAULT_HUMAN_MAX_STAGE "2"
#define DAMAGE_FRACTION_FOR_KILL 0.5f //how much damage players (versus structures) need to
//do to increment the stage kill counters
+
+#define MAXIMUM_BUILD_TIME 20000 // used for pie timer
-// g_suddenDeathMode settings
-#define SDMODE_BP 0
-#define SDMODE_NO_BUILD 1
-#define SDMODE_SELECTIVE 2
-#define SDMODE_NO_DECON 3
+#endif
diff --git a/src/granger/COPYING b/src/granger/COPYING
new file mode 100644
index 0000000..f755e7e
--- /dev/null
+++ b/src/granger/COPYING
@@ -0,0 +1,622 @@
+GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+ Preamble
+
+The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+0. Definitions.
+
+"This License" refers to version 3 of the GNU General Public License.
+
+"Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+"The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+1. Source Code.
+
+The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+The Corresponding Source for a work in source code form is that
+same work.
+
+2. Basic Permissions.
+
+All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+a) The work must carry prominent notices stating that you modified
+it, and giving a relevant date.
+
+b) The work must carry prominent notices stating that it is
+released under this License and any conditions added under section
+7. This requirement modifies the requirement in section 4 to
+"keep intact all notices".
+
+c) You must license the entire work, as a whole, under this
+License to anyone who comes into possession of a copy. This
+License will therefore apply, along with any applicable section 7
+additional terms, to the whole of the work, and all its parts,
+regardless of how they are packaged. This License gives no
+permission to license the work in any other way, but it does not
+invalidate such permission if you have separately received it.
+
+d) If the work has interactive user interfaces, each must display
+Appropriate Legal Notices; however, if the Program has interactive
+interfaces that do not display Appropriate Legal Notices, your
+work need not make them do so.
+
+A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+a) Convey the object code in, or embodied in, a physical product
+(including a physical distribution medium), accompanied by the
+Corresponding Source fixed on a durable physical medium
+customarily used for software interchange.
+
+b) Convey the object code in, or embodied in, a physical product
+(including a physical distribution medium), accompanied by a
+written offer, valid for at least three years and valid for as
+long as you offer spare parts or customer support for that product
+model, to give anyone who possesses the object code either (1) a
+copy of the Corresponding Source for all the software in the
+product that is covered by this License, on a durable physical
+medium customarily used for software interchange, for a price no
+more than your reasonable cost of physically performing this
+conveying of source, or (2) access to copy the
+Corresponding Source from a network server at no charge.
+
+c) Convey individual copies of the object code with a copy of the
+written offer to provide the Corresponding Source. This
+alternative is allowed only occasionally and noncommercially, and
+only if you received the object code with such an offer, in accord
+with subsection 6b.
+
+d) Convey the object code by offering access from a designated
+place (gratis or for a charge), and offer equivalent access to the
+Corresponding Source in the same way through the same place at no
+further charge. You need not require recipients to copy the
+Corresponding Source along with the object code. If the place to
+copy the object code is a network server, the Corresponding Source
+may be on a different server (operated by you or a third party)
+that supports equivalent copying facilities, provided you maintain
+clear directions next to the object code saying where to find the
+Corresponding Source. Regardless of what server hosts the
+Corresponding Source, you remain obligated to ensure that it is
+available for as long as needed to satisfy these requirements.
+
+e) Convey the object code using peer-to-peer transmission, provided
+you inform other peers where the object code and Corresponding
+Source of the work are being offered to the general public at no
+charge under subsection 6d.
+
+A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+"Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+7. Additional Terms.
+
+"Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+a) Disclaiming warranty or limiting liability differently from the
+terms of sections 15 and 16 of this License; or
+
+b) Requiring preservation of specified reasonable legal notices or
+author attributions in that material or in the Appropriate Legal
+Notices displayed by works containing it; or
+
+c) Prohibiting misrepresentation of the origin of that material, or
+requiring that modified versions of such material be marked in
+reasonable ways as different from the original version; or
+
+d) Limiting the use for publicity purposes of names of licensors or
+authors of the material; or
+
+e) Declining to grant rights under trademark law for use of some
+trade names, trademarks, or service marks; or
+
+f) Requiring indemnification of licensors and authors of that
+material by anyone who conveys the material (or modified versions of
+it) with contractual assumptions of liability to the recipient, for
+any liability that these contractual assumptions directly impose on
+those licensors and authors.
+
+All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+8. Termination.
+
+You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+11. Patents.
+
+A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+12. No Surrender of Others' Freedom.
+
+If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+13. Use with the GNU Affero General Public License.
+
+Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/src/granger/Dockerfile b/src/granger/Dockerfile
new file mode 100644
index 0000000..11698c8
--- /dev/null
+++ b/src/granger/Dockerfile
@@ -0,0 +1,4 @@
+FROM ubuntu:yakkety
+WORKDIR /usr/src
+COPY . /usr/src/
+RUN apt update && apt install -y cmake libgl1-mesa-dev libsdl2-dev libfreetype6-dev mingw-w64 g++-mingw-w64 g++-multilib git zip vim-nox
diff --git a/src/granger/README.md b/src/granger/README.md
new file mode 100644
index 0000000..ef77989
--- /dev/null
+++ b/src/granger/README.md
@@ -0,0 +1,139 @@
+# Granger
+[![AppVeyor](https://img.shields.io/appveyor/ci/jkent/granger.svg?style=flat-square)](https://ci.appveyor.com/project/jkent/granger)
+[![Travis-CI](https://travis-ci.org/GrangerHub/granger.svg?branch=master "Travis-CI")](https://travis-ci.org/GrangerHub/granger)
+
+### Lua API documentation
+`os.access(p, mode)`<br>
+Checks that the file is executable/writable/readable. `mode` is a string of the characters "rwx".
+
+`os.chdir(p)`<br>
+Change the current working directory.
+
+`os.copyfile(src, dst)`<br>
+Copy a file from one location to another.
+
+`os.elevate()`<br>
+Attempts to re-run process under elevated privlidges, returning true if elevated or false if unsuccessful.
+
+`os.get()`<br>
+Retrieve the current operating system ID string.
+
+`os.getcwd()`<br>
+Retrieve the current working directory.
+
+`os.is(id)`<br>
+Check the current operating system.
+
+`os.is64bit()`<br>
+Determine if the current system is running a 64-bit architecture.
+
+`os.isdir(p)`<br>
+Returns true if the specified directory exists.
+
+`os.isfile(p)`<br>
+Returns true if the given file exists.
+
+`os.matchdirs(p)`<br>
+Performs a wildcard match to locate one or more directories.
+
+`os.matchfiles(p)`<br>
+Performs a wildcard match to locate one or more files.
+
+`os.mkdir(p)`<br>
+An overload of os.mkdir() function, which will create any missing subdirectories along the path.
+
+`os.outputof(cmd)`<br>
+Run a shell command and return the output.
+
+`os.pathsearch(p, path1, ...)`<br>
+Locates a file, given a set of search paths.
+
+`os.rmdir(p)`<br>
+Remove a directory, along with any contained files or subdirectories.
+
+`os.stat(p)`<br>
+Retrieve information about a file.
+
+`path.getbasename(p)`<br>
+Retrieve the filename portion of a path, without any extension.
+
+`path.getabsolute(p)`<br>
+Returns an absolute version of a relative path.
+
+`path.getdirectory(p)`<br>
+Retrieve the directory portion of a path, or an empty string if the path does not include a directory.
+
+`path.getdrive(p)`<br>
+Retrieve the drive letter, if a Windows path.
+
+`path.getextension(p)`<br>
+Retrieve the file extension.
+
+`path.getname(p)`<br>
+Retreive the filename portion of a path.
+
+`path.getrelative(p1, p2)`<br>
+Returns a path relative to another.
+
+`path.isabsolute(p)`<br>
+Determines if a path is absolute or relative.
+
+`path.join(...)`<br>
+Builds a path from two or more path parts.
+
+`path.normalize(p)`<br>
+Removes any wwirdness from a file system path string.
+
+`path.rebase(p, oldbase, newbase)`<br>
+Takes a path which is relative to one location and makes it relative to another location instead.
+
+`path.translate(p, sep)`<br>
+Convert the separators in a path from one form to another. If `sep` is nil, then a platform-specific separator is used.
+
+`path.wildcards(pattern)`<br>
+Converts from a simple wildcard syntax, where * is "match any" and ** is "match recursive", to the corresponding Lua pattern.
+
+`string.explode(s, pattern, plain)`<br>
+Returns an array of strings, each which is a substring of `s` formed by splitting on boundaries formed by `pattern`.
+
+`string.endswith(haystack, needle)`<br>
+Returns true if `haystack` ends with `needle`.
+
+`string.findlast(s, pattern, plain)`<br>
+Find the last instance of a pattern in a string.
+
+`string.startswith(haystack, needle)`<br>
+Returns true if `haystack` starts with `needle`.
+
+`table.contains(t, value)`<br>
+Returns true if the table contains the specified value.
+
+`table.extract(arr, fname)`<br>
+Enumerates an array of objects and returns a new table containing only the value of one particular field.
+
+`table.flatten(arr)`<br>
+Flattens a hierarchy of tables into a single array containing all of the values.
+
+`table.implode(arr, before, after, between)`<br>
+Merges an array of items into a string.
+
+`table.insertflat(tbl, values)`<br>
+Inserts a value of array of values into a table. If the value is itself a table, its contents are enumerated and added instead. So these inputs give these outputs:<br>
+"x" -> { "x" }<br>
+{ "x", "y" } -> { "x", "y" }<br>
+{ "x", { "y" }} -> { "x", "y" }<br>
+
+`table.isempty(t)`<br>
+Returns true of the table is empty, and contains no indexed or keyed values.
+
+`table.join(...)`<br>
+Adds the values from one array to the end of another and returns the result.
+
+`table.keys(tbl)`<br>
+Return a list of all the keys used in a table.
+
+`table.merge(...)`<br>
+Adds the key-value associations from one table into another and returns the resulting merged table.
+
+`table.translate(arr, translation)`<br>
+Translates the values contained in array, using specified translation table and returns the results in a new array.
diff --git a/src/granger/appveyor.yml b/src/granger/appveyor.yml
new file mode 100644
index 0000000..c283de6
--- /dev/null
+++ b/src/granger/appveyor.yml
@@ -0,0 +1,32 @@
+platform:
+ - x86
+ - x64
+
+configuration:
+ - Debug
+ - Release
+
+os: Visual Studio 2015
+
+clone_folder: c:\projects\granger
+
+build_script:
+ # show settings
+ - cmake -version
+ - echo %platform%
+ - echo %configuration%
+
+ # generate a solution file
+ - cd c:\projects\granger
+ - mkdir build
+ - cd build
+ - if "%platform%" == "x64" set cmake_platform=%platform%
+ - cmake -g "Visual Studio 14 2015" .. -DCMAKE_GENERATOR_PLATFORM=%cmake_platform%
+
+ # build it
+ - if "%platform%" == "x86" set msbuild_platform=Win32
+ - if "%platform%" == "x64" set msbuild_platform=%platform%
+ - msbuild granger.sln /p:Configuration=%configuration% /toolsversion:14.0 /p:PlatformToolset=v140 /p:Platform=%msbuild_platform%
+
+test_script:
+ - if "%configuration%" == "Debug" ctest -VV --schedule-random -C Debug
diff --git a/src/granger/misc/docker-build.sh b/src/granger/misc/docker-build.sh
new file mode 100644
index 0000000..fe3232a
--- /dev/null
+++ b/src/granger/misc/docker-build.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+[[ -d build ]] \
+ || mkdir build
+
+cd build
+cmake ..
+make
diff --git a/src/granger/src/CMakeLists.txt b/src/granger/src/CMakeLists.txt
new file mode 100644
index 0000000..f59ae9c
--- /dev/null
+++ b/src/granger/src/CMakeLists.txt
@@ -0,0 +1,60 @@
+add_subdirectory(lua)
+add_subdirectory(nettle)
+add_subdirectory(premake)
+
+add_executable(granger
+ getopt.h
+ lnettlelib.c
+ lnettlelib.h
+ main.c
+ strvec.c
+ strvec.h
+ )
+
+if(APPLE)
+ add_definitions(-DLUA_USE_MACOSX)
+endif(APPLE)
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ add_definitions(-DLUA_USE_LINUX)
+endif()
+
+add_definitions (
+ #-DLUA_COMPAT_5_2
+ -DNDEBUG
+ -mfpmath=sse
+ -ffast-math
+ -DGRANGER
+ )
+
+include_directories (
+ include
+ )
+target_link_libraries(granger granger_lua granger_nettle premake)
+
+if (NOT WIN32)
+ target_link_libraries(granger m dl)
+endif()
+
+if(WIN32)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+endif(WIN32)
+
+if (APPLE)
+ macro(ADD_FRAMEWORK fwname appname)
+ find_library(FRAMEWORK_${fwname}
+ NAMES ${fwname}
+ PATHS ${CMAKE_OSX_SYSROOT}/System/Library
+ PATH_SUFFIXES Frameworks
+ NO_DEFAULT_PATH)
+ if( ${FRAMEWORK_${fwname}} STREQUAL FRAMEWORK_${fwname}-NOTFOUND)
+ MESSAGE(ERROR ": Framework ${fwname} not found")
+ else()
+ TARGET_LINK_LIBRARIES(${appname} "${FRAMEWORK_${fwname}}/${fwname}")
+ MESSAGE(STATUS "Framework ${fwname} found at ${FRAMEWORK_${fwname}}")
+ endif()
+ endmacro(ADD_FRAMEWORK)
+
+ add_framework(CoreServices granger)
+ add_framework(Security granger)
+endif()
diff --git a/src/granger/src/getopt.h b/src/granger/src/getopt.h
new file mode 100644
index 0000000..c15cbd9
--- /dev/null
+++ b/src/granger/src/getopt.h
@@ -0,0 +1,653 @@
+#ifndef __GETOPT_H__
+/**
+ * DISCLAIMER
+ * This file is part of the mingw-w64 runtime package.
+ *
+ * The mingw-w64 runtime package and its code is distributed in the hope that it
+ * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
+ * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
+ * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+ /*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * 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. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#pragma warning(disable:4996);
+
+#define __GETOPT_H__
+
+/* All the headers include this file. */
+#include <crtdefs.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <windows.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
+
+#ifdef REPLACE_GETOPT
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+int optopt = '?'; /* character checked for validity */
+#undef optreset /* see getopt.h */
+#define optreset __mingw_optreset
+int optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+#endif
+
+//extern int optind; /* index of first non-option in argv */
+//extern int optopt; /* single option character, as parsed */
+//extern int opterr; /* flag to enable built-in diagnostics... */
+// /* (user may set to zero, to suppress) */
+//
+//extern char *optarg; /* pointer to argument of current option */
+
+#define PRINT_ERROR ((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
+#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#ifndef __CYGWIN__
+#define __progname __argv[0]
+#else
+extern char __declspec(dllimport) *__progname;
+#endif
+
+#ifdef __CYGWIN__
+static char EMSG[] = "";
+#else
+#define EMSG ""
+#endif
+
+struct option /* specification for a long form option... */
+{
+ const char *name; /* option name, without leading hyphens */
+ int has_arg; /* does it take an argument? */
+ int *flag; /* where to save its status, or NULL */
+ int val; /* its associated status value */
+};
+
+static int getopt_internal(int, char * const *, const char *,
+ const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+ const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+static void
+_vwarnx(const char *fmt,va_list ap)
+{
+ (void)fprintf(stderr,"%s: ",__progname);
+ if (fmt != NULL)
+ (void)vfprintf(stderr,fmt,ap);
+ (void)fprintf(stderr,"\n");
+}
+
+static void
+warnx(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap,fmt);
+ _vwarnx(fmt,ap);
+ va_end(ap);
+}
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+ char * const *nargv)
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end+i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ /* LINTED const cast */
+ ((char **) nargv)[pos] = nargv[cstart];
+ /* LINTED const cast */
+ ((char **)nargv)[cstart] = swap;
+ }
+ }
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+ /*
+ * We don't pass FLAG_PERMUTE to getopt_internal() since
+ * the BSD getopt(3) (unlike GNU) has never done this.
+ *
+ * Furthermore, since many privileged programs call getopt()
+ * before dropping privileges it makes sense to keep things
+ * as simple (and bug-free) as possible.
+ */
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+#endif /* REPLACE_GETOPT */
+
+//extern int getopt(int nargc, char * const *nargv, const char *options);
+
+#ifdef _BSD_SOURCE
+/*
+ * BSD adds the non-standard `optreset' feature, for reinitialisation
+ * of `getopt' parsing. We support this feature, for applications which
+ * proclaim their BSD heritage, before including this header; however,
+ * to maintain portability, developers are advised to avoid it.
+ */
+# define optreset __mingw_optreset
+extern int optreset;
+#endif
+#ifdef __cplusplus
+}
+#endif
+/*
+ * POSIX requires the `getopt' API to be specified in `unistd.h';
+ * thus, `unistd.h' includes this header. However, we do not want
+ * to expose the `getopt_long' or `getopt_long_only' APIs, when
+ * included in this manner. Thus, close the standard __GETOPT_H__
+ * declarations block, and open an additional __GETOPT_LONG_H__
+ * specific block, only when *not* __UNISTD_H_SOURCED__, in which
+ * to declare the extended API.
+ */
+#endif /* !defined(__GETOPT_H__) */
+
+#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
+#define __GETOPT_LONG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum /* permitted values for its `has_arg' field... */
+{
+ no_argument = 0, /* option never takes an argument */
+ required_argument, /* option always requires an argument */
+ optional_argument /* option may take an argument */
+};
+
+/*
+ * parse_long_options --
+ * Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int short_too)
+{
+ char *current_argv, *has_equal;
+ size_t current_argv_len;
+ int i, ambiguous, match;
+
+#define IDENTICAL_INTERPRETATION(_x, _y) \
+ (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
+ long_options[(_x)].flag == long_options[(_y)].flag && \
+ long_options[(_x)].val == long_options[(_y)].val)
+
+ current_argv = place;
+ match = -1;
+ ambiguous = 0;
+
+ optind++;
+
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == current_argv_len) {
+ /* exact match */
+ match = i;
+ ambiguous = 0;
+ break;
+ }
+ /*
+ * If this is a known short option, don't allow
+ * a partial match of a single character.
+ */
+ if (short_too && current_argv_len == 1)
+ continue;
+
+ if (match == -1) /* partial match */
+ match = i;
+ else if (!IDENTICAL_INTERPRETATION(i, match))
+ ambiguous = 1;
+ }
+ if (ambiguous) {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ warnx(ambig, (int)current_argv_len,
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ warnx(noarg, (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ return (BADARG);
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use next nargv
+ */
+ optarg = nargv[optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument; leading ':' indicates no error
+ * should be generated.
+ */
+ if (PRINT_ERROR)
+ warnx(recargstring,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ --optind;
+ return (BADARG);
+ }
+ } else { /* unknown option */
+ if (short_too) {
+ --optind;
+ return (-1);
+ }
+ if (PRINT_ERROR)
+ warnx(illoptstring, current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (idx)
+ *idx = match;
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ return (0);
+ } else
+ return (long_options[match].val);
+#undef IDENTICAL_INTERPRETATION
+}
+
+/*
+ * getopt_internal --
+ * Parse argc/argv argument vector. Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int flags)
+{
+ char *oli; /* option letter list index */
+ int optchar, short_too;
+ static int posixly_correct = -1;
+
+ if (options == NULL)
+ return (-1);
+
+ /*
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of
+ * XXX using optreset. Work around this braindamage.
+ */
+ if (optind == 0)
+ optind = optreset = 1;
+
+ /*
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
+ * string begins with a '+'.
+ *
+ * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
+ * optreset != 0 for GNU compatibility.
+ */
+ if (posixly_correct == -1 || optreset != 0)
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+ if (*options == '-')
+ flags |= FLAG_ALLARGS;
+ else if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+ if (*options == '+' || *options == '-')
+ options++;
+
+ optarg = NULL;
+ if (optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set optind
+ * to the first of them.
+ */
+ optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ if (*(place = nargv[optind]) != '-' ||
+ (place[1] == '\0' && strchr(options, '-') == NULL)) {
+ place = EMSG; /* found non-option */
+ if (flags & FLAG_ALLARGS) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ optarg = nargv[optind++];
+ return (INORDER);
+ }
+ if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If no permutation wanted, stop parsing
+ * at first non-option.
+ */
+ return (-1);
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ nonopt_start = optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = optind;
+
+ /*
+ * If we have "-" do nothing, if "--" we are done.
+ */
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ optind++;
+ place = EMSG;
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ }
+
+ /*
+ * Check long options if:
+ * 1) we were passed some
+ * 2) the arg is not just "-"
+ * 3) either the arg starts with -- we are getopt_long_only()
+ */
+ if (long_options != NULL && place != nargv[optind] &&
+ (*place == '-' || (flags & FLAG_LONGONLY))) {
+ short_too = 0;
+ if (*place == '-')
+ place++; /* --foo long option */
+ else if (*place != ':' && strchr(options, *place) != NULL)
+ short_too = 1; /* could be short option too */
+
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, short_too);
+ if (optchar != -1) {
+ place = EMSG;
+ return (optchar);
+ }
+ }
+
+ if ((optchar = (int)*place++) == (int)':' ||
+ (optchar == (int)'-' && *place != '\0') ||
+ (oli = (char*)strchr(options, optchar)) == NULL) {
+ /*
+ * If the user specified "-" and '-' isn't listed in
+ * options, return -1 (non-option) as per POSIX.
+ * Otherwise, it is an unknown option character (or ':').
+ */
+ if (optchar == (int)'-' && *place == '\0')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (PRINT_ERROR)
+ warnx(illoptchar, optchar);
+ optopt = optchar;
+ return (BADCH);
+ }
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+ /* -W long-option */
+ if (*place) /* no space */
+ /* NOTHING */;
+ else if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else /* white space */
+ place = nargv[optind];
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, 0);
+ place = EMSG;
+ return (optchar);
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++optind;
+ } else { /* takes (optional) argument */
+ optarg = NULL;
+ if (*place) /* no white space */
+ optarg = place;
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else
+ optarg = nargv[optind];
+ }
+ place = EMSG;
+ ++optind;
+ }
+ /* dump back option letter */
+ return (optchar);
+}
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE|FLAG_LONGONLY));
+}
+
+//extern int getopt_long(int nargc, char * const *nargv, const char *options,
+// const struct option *long_options, int *idx);
+//extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
+// const struct option *long_options, int *idx);
+/*
+ * Previous MinGW implementation had...
+ */
+#ifndef HAVE_DECL_GETOPT
+/*
+ * ...for the long form API only; keep this for compatibility.
+ */
+# define HAVE_DECL_GETOPT 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
diff --git a/src/granger/src/lnettlelib.c b/src/granger/src/lnettlelib.c
new file mode 100644
index 0000000..787c75f
--- /dev/null
+++ b/src/granger/src/lnettlelib.c
@@ -0,0 +1,181 @@
+/*
+ * This file is part of Granger.
+ * Copyright (c) 2016 Jeff Kent <jeff@jkent.net>
+ *
+ * Granger is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Granger is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Granger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "nettle/md5.h"
+#include "nettle/sha2.h"
+
+#define MD5_CTX "md5_ctx*"
+#define SHA256_CTX "sha256_ctx*"
+
+static int lmd5(lua_State *L)
+{
+ struct md5_ctx *ctx;
+
+ ctx = (struct md5_ctx *)lua_newuserdata(L, sizeof(struct md5_ctx));
+ luaL_setmetatable(L, MD5_CTX);
+ md5_init(ctx);
+ return 1;
+}
+
+static int lmd5_digest(lua_State *L)
+{
+ struct md5_ctx *ctx;
+ char digest[MD5_DIGEST_SIZE];
+
+ ctx = luaL_checkudata(L, 1, MD5_CTX);
+ md5_digest(ctx, sizeof(digest), digest);
+ lua_pushlstring(L, digest, sizeof(digest));
+ return 1;
+}
+
+static int lmd5_update(lua_State *L)
+{
+ struct md5_ctx *ctx;
+ const char *data;
+ size_t len;
+
+ ctx = luaL_checkudata(L, 1, MD5_CTX);
+ if (lua_isnil(L, 2)) {
+ return 0;
+ }
+ data = luaL_checklstring(L, 2, &len);
+ nettle_md5_update(ctx, len, data);
+ return 0;
+}
+
+static int lmd5_tostring(lua_State *L)
+{
+ struct md5_ctx *ctx, ctx2;
+ char digest[MD5_DIGEST_SIZE];
+ char hex[MD5_DIGEST_SIZE*2+1];
+ int i;
+
+ ctx = luaL_checkudata(L, 1, MD5_CTX);
+ memcpy(&ctx2, ctx, sizeof(struct md5_ctx));
+
+ md5_digest(&ctx2, sizeof(digest), digest);
+ for (i = 0; i < sizeof(digest); i++) {
+ sprintf(hex + 2 * i, "%02hhx", digest[i]);
+ }
+
+ lua_pushstring(L, hex);
+ return 1;
+}
+
+static int lsha256(lua_State *L)
+{
+ struct sha256_ctx *ctx;
+
+ ctx = (struct sha256_ctx *)lua_newuserdata(L, sizeof(struct sha256_ctx));
+ luaL_setmetatable(L, SHA256_CTX);
+ sha256_init(ctx);
+ return 1;
+}
+
+static int lsha256_digest(lua_State *L)
+{
+ struct sha256_ctx *ctx;
+ char digest[SHA256_DIGEST_SIZE];
+
+ ctx = luaL_checkudata(L, 1, SHA256_CTX);
+ sha256_digest(ctx, sizeof(digest), digest);
+ lua_pushlstring(L, digest, sizeof(digest));
+ return 1;
+}
+
+static int lsha256_update(lua_State *L)
+{
+ struct sha256_ctx *ctx;
+ const char *data;
+ size_t len;
+
+ ctx = luaL_checkudata(L, 1, SHA256_CTX);
+ if (lua_isnil(L, 2)) {
+ return 0;
+ }
+ data = luaL_checklstring(L, 2, &len);
+ nettle_sha256_update(ctx, len, data);
+ return 0;
+}
+
+static int lsha256_tostring(lua_State *L)
+{
+ struct sha256_ctx *ctx, ctx2;
+ char digest[SHA256_DIGEST_SIZE];
+ char hex[SHA256_DIGEST_SIZE*2+1];
+ int i;
+
+ ctx = luaL_checkudata(L, 1, SHA256_CTX);
+ memcpy(&ctx2, ctx, sizeof(struct sha256_ctx));
+
+ sha256_digest(&ctx2, sizeof(digest), digest);
+ for (i = 0; i < sizeof(digest); i++) {
+ sprintf(hex + 2 * i, "%02hhx", digest[i]);
+ }
+
+ lua_pushstring(L, hex);
+ return 1;
+}
+
+/* functions for 'nettle' library */
+static const luaL_Reg nettlelib[] = {
+ {"md5", lmd5},
+ {"sha256", lsha256},
+ {NULL, NULL}
+};
+
+static const luaL_Reg lmd5_methods[] = {
+ {"digest", lmd5_digest},
+ {"update", lmd5_update},
+ {"__tostring", lmd5_tostring},
+ {NULL, NULL}
+};
+
+/* functions for sha256 objects */
+static const luaL_Reg lsha256_methods[] = {
+ {"digest", lsha256_digest},
+ {"update", lsha256_update},
+ {"__tostring", lsha256_tostring},
+ {NULL, NULL}
+};
+
+static void createmeta (lua_State *L)
+{
+ luaL_newmetatable(L, MD5_CTX); /* create metatable for file handles */
+ lua_pushvalue(L, -1); /* push metatable */
+ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
+ luaL_setfuncs(L, lmd5_methods, 0); /* add file methods to new metatable */
+ lua_pop(L, 1); /* pop new metatable */
+
+ luaL_newmetatable(L, SHA256_CTX); /* create metatable for file handles */
+ lua_pushvalue(L, -1); /* push metatable */
+ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
+ luaL_setfuncs(L, lsha256_methods, 0); /* add file methods to new metatable */
+ lua_pop(L, 1); /* pop new metatable */
+}
+
+LUAMOD_API int luaopen_nettle (lua_State *L)
+{
+ luaL_newlib(L, nettlelib);
+ createmeta(L);
+ return 1;
+}
diff --git a/src/granger/src/lnettlelib.h b/src/granger/src/lnettlelib.h
new file mode 100644
index 0000000..0afd753
--- /dev/null
+++ b/src/granger/src/lnettlelib.h
@@ -0,0 +1,25 @@
+/*
+ * This file is part of Granger.
+ * Copyright (c) 2016 Jeff Kent <jeff@jkent.net>
+ *
+ * Granger is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Granger is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Granger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef lnettlelib_h
+#define lnettlelib_h
+
+#define LUA_NETTLELIBNAME "nettle"
+LUAMOD_API int (luaopen_nettle) (lua_State *L);
+
+#endif /* lnettlelib_h */
diff --git a/src/granger/src/lua/CMakeLists.txt b/src/granger/src/lua/CMakeLists.txt
new file mode 100644
index 0000000..1508ef2
--- /dev/null
+++ b/src/granger/src/lua/CMakeLists.txt
@@ -0,0 +1,57 @@
+set(PARENT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
+
+add_library( granger_lua STATIC
+ ${PARENT_DIR}/lua-5.3.3/src/lapi.c
+ ${PARENT_DIR}/lua-5.3.3/src/lcode.c
+ ${PARENT_DIR}/lua-5.3.3/src/lctype.c
+ ${PARENT_DIR}/lua-5.3.3/src/ldebug.c
+ ${PARENT_DIR}/lua-5.3.3/src/ldo.c
+ ${PARENT_DIR}/lua-5.3.3/src/ldump.c
+ ${PARENT_DIR}/lua-5.3.3/src/lfunc.c
+ ${PARENT_DIR}/lua-5.3.3/src/lgc.c
+ ${PARENT_DIR}/lua-5.3.3/src/llex.c
+ ${PARENT_DIR}/lua-5.3.3/src/lmem.c
+ ${PARENT_DIR}/lua-5.3.3/src/lobject.c
+ ${PARENT_DIR}/lua-5.3.3/src/lopcodes.c
+ ${PARENT_DIR}/lua-5.3.3/src/lparser.c
+ ${PARENT_DIR}/lua-5.3.3/src/lstate.c
+ ${PARENT_DIR}/lua-5.3.3/src/lstring.c
+ ${PARENT_DIR}/lua-5.3.3/src/ltable.c
+ ${PARENT_DIR}/lua-5.3.3/src/ltm.c
+ ${PARENT_DIR}/lua-5.3.3/src/lundump.c
+ ${PARENT_DIR}/lua-5.3.3/src/lvm.c
+ ${PARENT_DIR}/lua-5.3.3/src/lzio.c
+ ${PARENT_DIR}/lua-5.3.3/src/lauxlib.c
+ ${PARENT_DIR}/lua-5.3.3/src/lbaselib.c
+ ${PARENT_DIR}/lua-5.3.3/src/lbitlib.c
+ ${PARENT_DIR}/lua-5.3.3/src/lcorolib.c
+ ${PARENT_DIR}/lua-5.3.3/src/ldblib.c
+ ${PARENT_DIR}/lua-5.3.3/src/liolib.c
+ ${PARENT_DIR}/lua-5.3.3/src/lmathlib.c
+ ${PARENT_DIR}/lua-5.3.3/src/loslib.c
+ ${PARENT_DIR}/lua-5.3.3/src/lstrlib.c
+ ${PARENT_DIR}/lua-5.3.3/src/ltablib.c
+ ${PARENT_DIR}/lua-5.3.3/src/lutf8lib.c
+ ${PARENT_DIR}/lua-5.3.3/src/loadlib.c
+ ${PARENT_DIR}/lua-5.3.3/src/linit.c
+ )
+
+if(APPLE)
+ add_definitions(-DLUA_USE_MACOSX)
+endif(APPLE)
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ add_definitions(-DLUA_USE_LINUX)
+endif()
+
+add_definitions (
+ -DLUA_COMPAT_5_2
+ -DNDEBUG
+ -mfpmath=sse
+ -ffast-math
+ -DGRANGER
+ )
+
+include_directories (
+ include
+ )
diff --git a/src/granger/src/main.c b/src/granger/src/main.c
new file mode 100644
index 0000000..3d1b28f
--- /dev/null
+++ b/src/granger/src/main.c
@@ -0,0 +1,97 @@
+/*
+ * This file is part of Granger.
+ * Copyright (c) 2016 Jeff Kent <jeff@jkent.net>
+ *
+ * Granger is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Granger is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Granger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include "premake/premake.h"
+
+#if defined(PLATFORM_WINDOWS)
+#include "getopt.h"
+#endif
+
+#include "lnettlelib.h"
+
+extern const luaL_Reg extra_os_functions[];
+
+int main (int argc, char *argv[])
+{
+ char *script_path;
+ lua_State *L;
+ int c;
+
+ while ((c = getopt(argc, argv, "C:")) != -1) {
+ switch (c) {
+ case 'C':
+ if (chdir(optarg)) {
+ fprintf(stderr, "could not change working directory\n");
+ return EXIT_FAILURE;
+ }
+ break;
+ case '?':
+ default:
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (optind >= argc || argv[optind][0] == '-') {
+ fprintf(stderr, "lua script not provided\n");
+ return EXIT_FAILURE;
+ }
+ script_path = argv[optind];
+ optind++;
+
+ L = luaL_newstate();
+ if (L == NULL) {
+ fprintf(stderr, "cannot create lua state\n");
+ return EXIT_FAILURE;
+ }
+
+ luaL_openlibs(L);
+ luaL_requiref(L, "nettle", luaopen_nettle, 1);
+ lua_pop(L, 1);
+
+ premake_init(L);
+ premake_locate(L, argv[0]);
+ lua_setglobal(L, "_EXE_PATH");
+
+ lua_pushstring(L, script_path);
+ lua_setglobal(L, "_GRANGER_SCRIPT");
+
+ lua_newtable(L);
+ for (int i = 1; optind < argc; i++, optind++) {
+ lua_pushinteger(L, i);
+ lua_pushstring(L, argv[optind]);
+ lua_settable(L, 1);
+ }
+ lua_setglobal(L, "argv");
+
+ if (luaL_dofile(L, script_path)) {
+ fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
+ lua_close(L);
+ return EXIT_FAILURE;
+ }
+
+ lua_close(L);
+ return EXIT_SUCCESS;
+}
diff --git a/src/granger/src/nettle/CMakeLists.txt b/src/granger/src/nettle/CMakeLists.txt
new file mode 100644
index 0000000..c2ec77c
--- /dev/null
+++ b/src/granger/src/nettle/CMakeLists.txt
@@ -0,0 +1,23 @@
+if(NOT WIN32)
+ add_definitions(-Wall -Wextra)
+endif(NOT WIN32)
+
+if(WIN32)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+endif(WIN32)
+
+add_library(granger_nettle
+ macros.h
+ md5-compress.c
+ md5.c
+ md5.h
+ nettle-stdint.h
+ nettle-types.h
+ nettle-write.h
+ sha2.h
+ sha256-compress.c
+ sha256.c
+ version.h
+ write-be32.c
+ write-le32.c
+ )
diff --git a/src/granger/src/nettle/macros.h b/src/granger/src/nettle/macros.h
new file mode 100644
index 0000000..af84841
--- /dev/null
+++ b/src/granger/src/nettle/macros.h
@@ -0,0 +1,245 @@
+/* macros.h
+
+ Copyright (C) 2001, 2010 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_MACROS_H_INCLUDED
+#define NETTLE_MACROS_H_INCLUDED
+
+/* Reads a 64-bit integer, in network, big-endian, byte order */
+#define READ_UINT64(p) \
+( (((uint64_t) (p)[0]) << 56) \
+ | (((uint64_t) (p)[1]) << 48) \
+ | (((uint64_t) (p)[2]) << 40) \
+ | (((uint64_t) (p)[3]) << 32) \
+ | (((uint64_t) (p)[4]) << 24) \
+ | (((uint64_t) (p)[5]) << 16) \
+ | (((uint64_t) (p)[6]) << 8) \
+ | ((uint64_t) (p)[7]))
+
+#define WRITE_UINT64(p, i) \
+do { \
+ (p)[0] = ((i) >> 56) & 0xff; \
+ (p)[1] = ((i) >> 48) & 0xff; \
+ (p)[2] = ((i) >> 40) & 0xff; \
+ (p)[3] = ((i) >> 32) & 0xff; \
+ (p)[4] = ((i) >> 24) & 0xff; \
+ (p)[5] = ((i) >> 16) & 0xff; \
+ (p)[6] = ((i) >> 8) & 0xff; \
+ (p)[7] = (i) & 0xff; \
+} while(0)
+
+/* Reads a 32-bit integer, in network, big-endian, byte order */
+#define READ_UINT32(p) \
+( (((uint32_t) (p)[0]) << 24) \
+ | (((uint32_t) (p)[1]) << 16) \
+ | (((uint32_t) (p)[2]) << 8) \
+ | ((uint32_t) (p)[3]))
+
+#define WRITE_UINT32(p, i) \
+do { \
+ (p)[0] = ((i) >> 24) & 0xff; \
+ (p)[1] = ((i) >> 16) & 0xff; \
+ (p)[2] = ((i) >> 8) & 0xff; \
+ (p)[3] = (i) & 0xff; \
+} while(0)
+
+/* Analogous macros, for 24 and 16 bit numbers */
+#define READ_UINT24(p) \
+( (((uint32_t) (p)[0]) << 16) \
+ | (((uint32_t) (p)[1]) << 8) \
+ | ((uint32_t) (p)[2]))
+
+#define WRITE_UINT24(p, i) \
+do { \
+ (p)[0] = ((i) >> 16) & 0xff; \
+ (p)[1] = ((i) >> 8) & 0xff; \
+ (p)[2] = (i) & 0xff; \
+} while(0)
+
+#define READ_UINT16(p) \
+( (((uint32_t) (p)[0]) << 8) \
+ | ((uint32_t) (p)[1]))
+
+#define WRITE_UINT16(p, i) \
+do { \
+ (p)[0] = ((i) >> 8) & 0xff; \
+ (p)[1] = (i) & 0xff; \
+} while(0)
+
+/* And the other, little-endian, byteorder */
+#define LE_READ_UINT64(p) \
+( (((uint64_t) (p)[7]) << 56) \
+ | (((uint64_t) (p)[6]) << 48) \
+ | (((uint64_t) (p)[5]) << 40) \
+ | (((uint64_t) (p)[4]) << 32) \
+ | (((uint64_t) (p)[3]) << 24) \
+ | (((uint64_t) (p)[2]) << 16) \
+ | (((uint64_t) (p)[1]) << 8) \
+ | ((uint64_t) (p)[0]))
+
+#define LE_WRITE_UINT64(p, i) \
+do { \
+ (p)[7] = ((i) >> 56) & 0xff; \
+ (p)[6] = ((i) >> 48) & 0xff; \
+ (p)[5] = ((i) >> 40) & 0xff; \
+ (p)[4] = ((i) >> 32) & 0xff; \
+ (p)[3] = ((i) >> 24) & 0xff; \
+ (p)[2] = ((i) >> 16) & 0xff; \
+ (p)[1] = ((i) >> 8) & 0xff; \
+ (p)[0] = (i) & 0xff; \
+} while (0)
+
+#define LE_READ_UINT32(p) \
+( (((uint32_t) (p)[3]) << 24) \
+ | (((uint32_t) (p)[2]) << 16) \
+ | (((uint32_t) (p)[1]) << 8) \
+ | ((uint32_t) (p)[0]))
+
+#define LE_WRITE_UINT32(p, i) \
+do { \
+ (p)[3] = ((i) >> 24) & 0xff; \
+ (p)[2] = ((i) >> 16) & 0xff; \
+ (p)[1] = ((i) >> 8) & 0xff; \
+ (p)[0] = (i) & 0xff; \
+} while(0)
+
+/* Analogous macros, for 16 bit numbers */
+#define LE_READ_UINT16(p) \
+ ( (((uint32_t) (p)[1]) << 8) \
+ | ((uint32_t) (p)[0]))
+
+#define LE_WRITE_UINT16(p, i) \
+ do { \
+ (p)[1] = ((i) >> 8) & 0xff; \
+ (p)[0] = (i) & 0xff; \
+ } while(0)
+
+/* Macro to make it easier to loop over several blocks. */
+#define FOR_BLOCKS(length, dst, src, blocksize) \
+ assert( !((length) % (blocksize))); \
+ for (; (length); ((length) -= (blocksize), \
+ (dst) += (blocksize), \
+ (src) += (blocksize)) )
+
+/* The masking of the right shift is needed to allow n == 0 (using
+ just 32 - n and 64 - n results in undefined behaviour). Most uses
+ of these macros use a constant and non-zero rotation count. */
+#define ROTL32(n,x) (((x)<<(n)) | ((x)>>((-(n)&31))))
+
+#define ROTL64(n,x) (((x)<<(n)) | ((x)>>((-(n))&63)))
+
+/* Requires that size > 0 */
+#define INCREMENT(size, ctr) \
+ do { \
+ unsigned increment_i = (size) - 1; \
+ if (++(ctr)[increment_i] == 0) \
+ while (increment_i > 0 \
+ && ++(ctr)[--increment_i] == 0 ) \
+ ; \
+ } while (0)
+
+
+/* Helper macro for Merkle-Damgård hash functions. Assumes the context
+ structs includes the following fields:
+
+ uint8_t block[...]; // Buffer holding one block
+ unsigned int index; // Index into block
+*/
+
+/* Currently used by sha512 (and sha384) only. */
+#define MD_INCR(ctx) ((ctx)->count_high += !++(ctx)->count_low)
+
+/* Takes the compression function f as argument. NOTE: also clobbers
+ length and data. */
+#define MD_UPDATE(ctx, length, data, f, incr) \
+ do { \
+ if ((ctx)->index) \
+ { \
+ /* Try to fill partial block */ \
+ unsigned __md_left = sizeof((ctx)->block) - (ctx)->index; \
+ if ((length) < __md_left) \
+ { \
+ memcpy((ctx)->block + (ctx)->index, (data), (length)); \
+ (ctx)->index += (length); \
+ goto __md_done; /* Finished */ \
+ } \
+ else \
+ { \
+ memcpy((ctx)->block + (ctx)->index, (data), __md_left); \
+ \
+ f((ctx), (ctx)->block); \
+ (incr); \
+ \
+ (data) += __md_left; \
+ (length) -= __md_left; \
+ } \
+ } \
+ while ((length) >= sizeof((ctx)->block)) \
+ { \
+ f((ctx), (data)); \
+ (incr); \
+ \
+ (data) += sizeof((ctx)->block); \
+ (length) -= sizeof((ctx)->block); \
+ } \
+ memcpy ((ctx)->block, (data), (length)); \
+ (ctx)->index = (length); \
+ __md_done: \
+ ; \
+ } while (0)
+
+/* Pads the block to a block boundary with the bit pattern 1 0*,
+ leaving size octets for the length field at the end. If needed,
+ compresses the block and starts a new one. */
+#define MD_PAD(ctx, size, f) \
+ do { \
+ unsigned __md_i; \
+ __md_i = (ctx)->index; \
+ \
+ /* Set the first char of padding to 0x80. This is safe since there \
+ is always at least one byte free */ \
+ \
+ assert(__md_i < sizeof((ctx)->block)); \
+ (ctx)->block[__md_i++] = 0x80; \
+ \
+ if (__md_i > (sizeof((ctx)->block) - (size))) \
+ { /* No room for length in this block. Process it and \
+ pad with another one */ \
+ memset((ctx)->block + __md_i, 0, sizeof((ctx)->block) - __md_i); \
+ \
+ f((ctx), (ctx)->block); \
+ __md_i = 0; \
+ } \
+ memset((ctx)->block + __md_i, 0, \
+ sizeof((ctx)->block) - (size) - __md_i); \
+ \
+ } while (0)
+
+#endif /* NETTLE_MACROS_H_INCLUDED */
diff --git a/src/granger/src/nettle/md5-compress.c b/src/granger/src/nettle/md5-compress.c
new file mode 100644
index 0000000..b8dad3f
--- /dev/null
+++ b/src/granger/src/nettle/md5-compress.c
@@ -0,0 +1,174 @@
+/* md5-compress.c
+
+ The compression function for the md5 hash function.
+
+ Copyright (C) 2001, 2005 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+/* Based on public domain code hacked by Colin Plumb, Andrew Kuchling, and
+ * Niels Möller. */
+
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef MD5_DEBUG
+# define MD5_DEBUG 0
+#endif
+
+#if MD5_DEBUG
+# include <stdio.h>
+# define DEBUG(i) \
+ fprintf(stderr, "%2d: %8x %8x %8x %8x\n", i, a, b, c, d)
+#else
+# define DEBUG(i)
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "md5.h"
+
+#include "macros.h"
+
+/* A block, treated as a sequence of 32-bit words. */
+#define MD5_DATA_LENGTH 16
+
+/* MD5 functions */
+
+#define F1(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define F2(x, y, z) F1((z), (x), (y))
+#define F3(x, y, z) ((x) ^ (y) ^ (z))
+#define F4(x, y, z) ((y) ^ ((x) | ~(z)))
+
+#define ROUND(f, w, x, y, z, data, s) \
+( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/* Perform the MD5 transformation on one full block of 16 32-bit
+ * words.
+ *
+ * Compresses 20 (_MD5_DIGEST_LENGTH + MD5_DATA_LENGTH) words into 4
+ * (_MD5_DIGEST_LENGTH) words. */
+
+void
+_nettle_md5_compress(uint32_t *digest, const uint8_t *input)
+{
+ uint32_t data[MD5_DATA_LENGTH];
+ uint32_t a, b, c, d;
+ unsigned i;
+
+ for (i = 0; i < MD5_DATA_LENGTH; i++, input += 4)
+ data[i] = LE_READ_UINT32(input);
+
+ a = digest[0];
+ b = digest[1];
+ c = digest[2];
+ d = digest[3];
+
+ DEBUG(-1);
+ ROUND(F1, a, b, c, d, data[ 0] + 0xd76aa478, 7); DEBUG(0);
+ ROUND(F1, d, a, b, c, data[ 1] + 0xe8c7b756, 12); DEBUG(1);
+ ROUND(F1, c, d, a, b, data[ 2] + 0x242070db, 17);
+ ROUND(F1, b, c, d, a, data[ 3] + 0xc1bdceee, 22);
+ ROUND(F1, a, b, c, d, data[ 4] + 0xf57c0faf, 7);
+ ROUND(F1, d, a, b, c, data[ 5] + 0x4787c62a, 12);
+ ROUND(F1, c, d, a, b, data[ 6] + 0xa8304613, 17);
+ ROUND(F1, b, c, d, a, data[ 7] + 0xfd469501, 22);
+ ROUND(F1, a, b, c, d, data[ 8] + 0x698098d8, 7);
+ ROUND(F1, d, a, b, c, data[ 9] + 0x8b44f7af, 12);
+ ROUND(F1, c, d, a, b, data[10] + 0xffff5bb1, 17);
+ ROUND(F1, b, c, d, a, data[11] + 0x895cd7be, 22);
+ ROUND(F1, a, b, c, d, data[12] + 0x6b901122, 7);
+ ROUND(F1, d, a, b, c, data[13] + 0xfd987193, 12);
+ ROUND(F1, c, d, a, b, data[14] + 0xa679438e, 17);
+ ROUND(F1, b, c, d, a, data[15] + 0x49b40821, 22); DEBUG(15);
+
+ ROUND(F2, a, b, c, d, data[ 1] + 0xf61e2562, 5); DEBUG(16);
+ ROUND(F2, d, a, b, c, data[ 6] + 0xc040b340, 9); DEBUG(17);
+ ROUND(F2, c, d, a, b, data[11] + 0x265e5a51, 14);
+ ROUND(F2, b, c, d, a, data[ 0] + 0xe9b6c7aa, 20);
+ ROUND(F2, a, b, c, d, data[ 5] + 0xd62f105d, 5);
+ ROUND(F2, d, a, b, c, data[10] + 0x02441453, 9);
+ ROUND(F2, c, d, a, b, data[15] + 0xd8a1e681, 14);
+ ROUND(F2, b, c, d, a, data[ 4] + 0xe7d3fbc8, 20);
+ ROUND(F2, a, b, c, d, data[ 9] + 0x21e1cde6, 5);
+ ROUND(F2, d, a, b, c, data[14] + 0xc33707d6, 9);
+ ROUND(F2, c, d, a, b, data[ 3] + 0xf4d50d87, 14);
+ ROUND(F2, b, c, d, a, data[ 8] + 0x455a14ed, 20);
+ ROUND(F2, a, b, c, d, data[13] + 0xa9e3e905, 5);
+ ROUND(F2, d, a, b, c, data[ 2] + 0xfcefa3f8, 9);
+ ROUND(F2, c, d, a, b, data[ 7] + 0x676f02d9, 14);
+ ROUND(F2, b, c, d, a, data[12] + 0x8d2a4c8a, 20); DEBUG(31);
+
+ ROUND(F3, a, b, c, d, data[ 5] + 0xfffa3942, 4); DEBUG(32);
+ ROUND(F3, d, a, b, c, data[ 8] + 0x8771f681, 11); DEBUG(33);
+ ROUND(F3, c, d, a, b, data[11] + 0x6d9d6122, 16);
+ ROUND(F3, b, c, d, a, data[14] + 0xfde5380c, 23);
+ ROUND(F3, a, b, c, d, data[ 1] + 0xa4beea44, 4);
+ ROUND(F3, d, a, b, c, data[ 4] + 0x4bdecfa9, 11);
+ ROUND(F3, c, d, a, b, data[ 7] + 0xf6bb4b60, 16);
+ ROUND(F3, b, c, d, a, data[10] + 0xbebfbc70, 23);
+ ROUND(F3, a, b, c, d, data[13] + 0x289b7ec6, 4);
+ ROUND(F3, d, a, b, c, data[ 0] + 0xeaa127fa, 11);
+ ROUND(F3, c, d, a, b, data[ 3] + 0xd4ef3085, 16);
+ ROUND(F3, b, c, d, a, data[ 6] + 0x04881d05, 23);
+ ROUND(F3, a, b, c, d, data[ 9] + 0xd9d4d039, 4);
+ ROUND(F3, d, a, b, c, data[12] + 0xe6db99e5, 11);
+ ROUND(F3, c, d, a, b, data[15] + 0x1fa27cf8, 16);
+ ROUND(F3, b, c, d, a, data[ 2] + 0xc4ac5665, 23); DEBUG(47);
+
+ ROUND(F4, a, b, c, d, data[ 0] + 0xf4292244, 6); DEBUG(48);
+ ROUND(F4, d, a, b, c, data[ 7] + 0x432aff97, 10); DEBUG(49);
+ ROUND(F4, c, d, a, b, data[14] + 0xab9423a7, 15);
+ ROUND(F4, b, c, d, a, data[ 5] + 0xfc93a039, 21);
+ ROUND(F4, a, b, c, d, data[12] + 0x655b59c3, 6);
+ ROUND(F4, d, a, b, c, data[ 3] + 0x8f0ccc92, 10);
+ ROUND(F4, c, d, a, b, data[10] + 0xffeff47d, 15);
+ ROUND(F4, b, c, d, a, data[ 1] + 0x85845dd1, 21);
+ ROUND(F4, a, b, c, d, data[ 8] + 0x6fa87e4f, 6);
+ ROUND(F4, d, a, b, c, data[15] + 0xfe2ce6e0, 10);
+ ROUND(F4, c, d, a, b, data[ 6] + 0xa3014314, 15);
+ ROUND(F4, b, c, d, a, data[13] + 0x4e0811a1, 21);
+ ROUND(F4, a, b, c, d, data[ 4] + 0xf7537e82, 6);
+ ROUND(F4, d, a, b, c, data[11] + 0xbd3af235, 10);
+ ROUND(F4, c, d, a, b, data[ 2] + 0x2ad7d2bb, 15);
+ ROUND(F4, b, c, d, a, data[ 9] + 0xeb86d391, 21); DEBUG(63);
+
+ digest[0] += a;
+ digest[1] += b;
+ digest[2] += c;
+ digest[3] += d;
+#if MD5_DEBUG
+ fprintf(stderr, "99: %8x %8x %8x %8x\n",
+ digest[0], digest[1], digest[2], digest[3]);
+#endif
+
+}
diff --git a/src/granger/src/nettle/md5.c b/src/granger/src/nettle/md5.c
new file mode 100644
index 0000000..97a5245
--- /dev/null
+++ b/src/granger/src/nettle/md5.c
@@ -0,0 +1,93 @@
+/* md5.c
+
+ The MD5 hash function, described in RFC 1321.
+
+ Copyright (C) 2001 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+/* Based on public domain code hacked by Colin Plumb, Andrew Kuchling, and
+ * Niels Möller. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "md5.h"
+
+#include "macros.h"
+#include "nettle-write.h"
+
+void
+md5_init(struct md5_ctx *ctx)
+{
+ const uint32_t iv[_MD5_DIGEST_LENGTH] =
+ {
+ 0x67452301,
+ 0xefcdab89,
+ 0x98badcfe,
+ 0x10325476,
+ };
+ memcpy(ctx->state, iv, sizeof(ctx->state));
+ ctx->count = 0;
+ ctx->index = 0;
+}
+
+#define COMPRESS(ctx, data) (_nettle_md5_compress((ctx)->state, (data)))
+
+void
+md5_update(struct md5_ctx *ctx,
+ size_t length,
+ const uint8_t *data)
+{
+ MD_UPDATE(ctx, length, data, COMPRESS, ctx->count++);
+}
+
+void
+md5_digest(struct md5_ctx *ctx,
+ size_t length,
+ uint8_t *digest)
+{
+ uint64_t bit_count;
+
+ assert(length <= MD5_DIGEST_SIZE);
+
+ MD_PAD(ctx, 8, COMPRESS);
+
+ /* There are 512 = 2^9 bits in one block */
+ bit_count = (ctx->count << 9) | (ctx->index << 3);
+
+ LE_WRITE_UINT64(ctx->block + (MD5_BLOCK_SIZE - 8), bit_count);
+ _nettle_md5_compress(ctx->state, ctx->block);
+
+ _nettle_write_le32(length, digest, ctx->state);
+ md5_init(ctx);
+}
diff --git a/src/granger/src/nettle/md5.h b/src/granger/src/nettle/md5.h
new file mode 100644
index 0000000..79304bc
--- /dev/null
+++ b/src/granger/src/nettle/md5.h
@@ -0,0 +1,86 @@
+/* md5.h
+
+ The MD5 hash function, described in RFC 1321.
+
+ Copyright (C) 2001 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_MD5_H_INCLUDED
+#define NETTLE_MD5_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define md5_init nettle_md5_init
+#define md5_update nettle_md5_update
+#define md5_digest nettle_md5_digest
+
+#define MD5_DIGEST_SIZE 16
+#define MD5_BLOCK_SIZE 64
+/* For backwards compatibility */
+#define MD5_DATA_SIZE MD5_BLOCK_SIZE
+
+/* Digest is kept internally as 4 32-bit words. */
+#define _MD5_DIGEST_LENGTH 4
+
+struct md5_ctx
+{
+ uint32_t state[_MD5_DIGEST_LENGTH];
+ uint64_t count; /* Block count */
+ uint8_t block[MD5_BLOCK_SIZE]; /* Block buffer */
+ unsigned index; /* Into buffer */
+};
+
+void
+md5_init(struct md5_ctx *ctx);
+
+void
+md5_update(struct md5_ctx *ctx,
+ size_t length,
+ const uint8_t *data);
+
+void
+md5_digest(struct md5_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+/* Internal compression function. STATE points to 4 uint32_t words,
+ and DATA points to 64 bytes of input data, possibly unaligned. */
+void
+_nettle_md5_compress(uint32_t *state, const uint8_t *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_MD5_H_INCLUDED */
diff --git a/src/granger/src/nettle/nettle-stdint.h b/src/granger/src/nettle/nettle-stdint.h
new file mode 100644
index 0000000..3298fa6
--- /dev/null
+++ b/src/granger/src/nettle/nettle-stdint.h
@@ -0,0 +1,6 @@
+#ifndef __NETTLE_STDINT_H
+#define __NETTLE_STDINT_H
+
+#include <stdint.h>
+
+#endif /* __NETTLE_STDINT_H */
diff --git a/src/granger/src/nettle/nettle-types.h b/src/granger/src/nettle/nettle-types.h
new file mode 100644
index 0000000..8f77ea9
--- /dev/null
+++ b/src/granger/src/nettle/nettle-types.h
@@ -0,0 +1,110 @@
+/* nettle-types.h
+
+ Copyright (C) 2005, 2014 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_TYPES_H
+#define NETTLE_TYPES_H
+
+/* For size_t */
+#include <stddef.h>
+
+/* Pretend these types always exists. Nettle doesn't use them. */
+#define _STDINT_HAVE_INT_FAST32_T 1
+#include "nettle-stdint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* An aligned 16-byte block. */
+union nettle_block16
+{
+ uint8_t b[16];
+ unsigned long w[16 / sizeof(unsigned long)];
+};
+
+/* Randomness. Used by key generation and dsa signature creation. */
+typedef void nettle_random_func(void *ctx,
+ size_t length, uint8_t *dst);
+
+/* Progress report function, mainly for key generation. */
+typedef void nettle_progress_func(void *ctx, int c);
+
+/* Realloc function, used by struct nettle_buffer. */
+typedef void *nettle_realloc_func(void *ctx, void *p, size_t length);
+
+/* Ciphers */
+typedef void nettle_set_key_func(void *ctx, const uint8_t *key);
+
+/* For block ciphers, const context. */
+typedef void nettle_cipher_func(const void *ctx,
+ size_t length, uint8_t *dst,
+ const uint8_t *src);
+
+
+/* Uses a void * for cipher contexts. Used for crypt operations where
+ the internal state changes during the encryption. */
+typedef void nettle_crypt_func(void *ctx,
+ size_t length, uint8_t *dst,
+ const uint8_t *src);
+
+/* Hash algorithms */
+typedef void nettle_hash_init_func(void *ctx);
+typedef void nettle_hash_update_func(void *ctx,
+ size_t length,
+ const uint8_t *src);
+typedef void nettle_hash_digest_func(void *ctx,
+ size_t length, uint8_t *dst);
+
+/* ASCII armor codecs. NOTE: Experimental and subject to change. */
+
+typedef size_t nettle_armor_length_func(size_t length);
+typedef void nettle_armor_init_func(void *ctx);
+
+typedef size_t nettle_armor_encode_update_func(void *ctx,
+ uint8_t *dst,
+ size_t src_length,
+ const uint8_t *src);
+
+typedef size_t nettle_armor_encode_final_func(void *ctx, uint8_t *dst);
+
+typedef int nettle_armor_decode_update_func(void *ctx,
+ size_t *dst_length,
+ uint8_t *dst,
+ size_t src_length,
+ const uint8_t *src);
+
+typedef int nettle_armor_decode_final_func(void *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_TYPES_H */
diff --git a/src/granger/src/nettle/nettle-write.h b/src/granger/src/nettle/nettle-write.h
new file mode 100644
index 0000000..54152bd
--- /dev/null
+++ b/src/granger/src/nettle/nettle-write.h
@@ -0,0 +1,58 @@
+/* nettle-write.h
+
+ Internal functions to write out word-sized data to byte arrays.
+
+ Copyright (C) 2010 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_WRITE_H_INCLUDED
+#define NETTLE_WRITE_H_INCLUDED
+
+/* For size_t */
+#include <stddef.h>
+
+#include "nettle-stdint.h"
+
+/* Write the word array at SRC to the byte array at DST, using little
+ endian (le) or big endian (be) byte order, and truncating the
+ result to LENGTH bytes. */
+
+/* FIXME: Use a macro shortcut to memcpy for native endianness. */
+void
+_nettle_write_be32(size_t length, uint8_t *dst,
+ uint32_t *src);
+void
+_nettle_write_le32(size_t length, uint8_t *dst,
+ uint32_t *src);
+
+void
+_nettle_write_le64(size_t length, uint8_t *dst,
+ uint64_t *src);
+
+#endif /* NETTLE_WRITE_H_INCLUDED */
diff --git a/src/granger/src/nettle/sha2.h b/src/granger/src/nettle/sha2.h
new file mode 100644
index 0000000..d0426d7
--- /dev/null
+++ b/src/granger/src/nettle/sha2.h
@@ -0,0 +1,206 @@
+/* sha2.h
+
+ The sha2 family of hash functions.
+
+ Copyright (C) 2001, 2012 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_SHA2_H_INCLUDED
+#define NETTLE_SHA2_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define sha224_init nettle_sha224_init
+#define sha224_digest nettle_sha224_digest
+#define sha256_init nettle_sha256_init
+#define sha256_update nettle_sha256_update
+#define sha256_digest nettle_sha256_digest
+#define sha384_init nettle_sha384_init
+#define sha384_digest nettle_sha384_digest
+#define sha512_init nettle_sha512_init
+#define sha512_update nettle_sha512_update
+#define sha512_digest nettle_sha512_digest
+#define sha512_224_init nettle_sha512_224_init
+#define sha512_224_digest nettle_sha512_224_digest
+#define sha512_256_init nettle_sha512_256_init
+#define sha512_256_digest nettle_sha512_256_digest
+
+/* For backwards compatibility */
+#define SHA224_DATA_SIZE SHA256_BLOCK_SIZE
+#define SHA256_DATA_SIZE SHA256_BLOCK_SIZE
+#define SHA512_DATA_SIZE SHA512_BLOCK_SIZE
+#define SHA384_DATA_SIZE SHA512_BLOCK_SIZE
+
+/* SHA256 */
+
+#define SHA256_DIGEST_SIZE 32
+#define SHA256_BLOCK_SIZE 64
+
+/* Digest is kept internally as 8 32-bit words. */
+#define _SHA256_DIGEST_LENGTH 8
+
+struct sha256_ctx
+{
+ uint32_t state[_SHA256_DIGEST_LENGTH]; /* State variables */
+ uint64_t count; /* 64-bit block count */
+ uint8_t block[SHA256_BLOCK_SIZE]; /* SHA256 data buffer */
+ unsigned int index; /* index into buffer */
+};
+
+void
+sha256_init(struct sha256_ctx *ctx);
+
+void
+sha256_update(struct sha256_ctx *ctx,
+ size_t length,
+ const uint8_t *data);
+
+void
+sha256_digest(struct sha256_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+/* Internal compression function. STATE points to 8 uint32_t words,
+ DATA points to 64 bytes of input data, possibly unaligned, and K
+ points to the table of constants. */
+void
+_nettle_sha256_compress(uint32_t *state, const uint8_t *data, const uint32_t *k);
+
+
+/* SHA224, a truncated SHA256 with different initial state. */
+
+#define SHA224_DIGEST_SIZE 28
+#define SHA224_BLOCK_SIZE SHA256_BLOCK_SIZE
+#define sha224_ctx sha256_ctx
+
+void
+sha224_init(struct sha256_ctx *ctx);
+
+#define sha224_update nettle_sha256_update
+
+void
+sha224_digest(struct sha256_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+
+/* SHA512 */
+
+#define SHA512_DIGEST_SIZE 64
+#define SHA512_BLOCK_SIZE 128
+
+/* Digest is kept internally as 8 64-bit words. */
+#define _SHA512_DIGEST_LENGTH 8
+
+struct sha512_ctx
+{
+ uint64_t state[_SHA512_DIGEST_LENGTH]; /* State variables */
+ uint64_t count_low, count_high; /* 128-bit block count */
+ uint8_t block[SHA512_BLOCK_SIZE]; /* SHA512 data buffer */
+ unsigned int index; /* index into buffer */
+};
+
+void
+sha512_init(struct sha512_ctx *ctx);
+
+void
+sha512_update(struct sha512_ctx *ctx,
+ size_t length,
+ const uint8_t *data);
+
+void
+sha512_digest(struct sha512_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+/* Internal compression function. STATE points to 8 uint64_t words,
+ DATA points to 128 bytes of input data, possibly unaligned, and K
+ points to the table of constants. */
+void
+_nettle_sha512_compress(uint64_t *state, const uint8_t *data, const uint64_t *k);
+
+
+/* SHA384, a truncated SHA512 with different initial state. */
+
+#define SHA384_DIGEST_SIZE 48
+#define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE
+#define sha384_ctx sha512_ctx
+
+void
+sha384_init(struct sha512_ctx *ctx);
+
+#define sha384_update nettle_sha512_update
+
+void
+sha384_digest(struct sha512_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+
+/* SHA512_224 and SHA512_256, two truncated versions of SHA512
+ with different initial states. */
+
+#define SHA512_224_DIGEST_SIZE 28
+#define SHA512_224_BLOCK_SIZE SHA512_BLOCK_SIZE
+#define sha512_224_ctx sha512_ctx
+
+void
+sha512_224_init(struct sha512_224_ctx *ctx);
+
+#define sha512_224_update nettle_sha512_update
+
+void
+sha512_224_digest(struct sha512_224_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+#define SHA512_256_DIGEST_SIZE 32
+#define SHA512_256_BLOCK_SIZE SHA512_BLOCK_SIZE
+#define sha512_256_ctx sha512_ctx
+
+void
+sha512_256_init(struct sha512_256_ctx *ctx);
+
+#define sha512_256_update nettle_sha512_update
+
+void
+sha512_256_digest(struct sha512_256_ctx *ctx,
+ size_t length,
+ uint8_t *digest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_SHA2_H_INCLUDED */
diff --git a/src/granger/src/nettle/sha256-compress.c b/src/granger/src/nettle/sha256-compress.c
new file mode 100644
index 0000000..8b82d70
--- /dev/null
+++ b/src/granger/src/nettle/sha256-compress.c
@@ -0,0 +1,199 @@
+/* sha256-compress.c
+
+ The compression function of the sha256 hash function.
+
+ Copyright (C) 2001, 2010 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef SHA256_DEBUG
+# define SHA256_DEBUG 0
+#endif
+
+#if SHA256_DEBUG
+# include <stdio.h>
+# define DEBUG(i) \
+ fprintf(stderr, "%2d: %8x %8x %8x %8x %8x %8x %8x %8x\n", \
+ i, A, B, C, D ,E, F, G, H)
+#else
+# define DEBUG(i)
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sha2.h"
+
+#include "macros.h"
+
+/* A block, treated as a sequence of 32-bit words. */
+#define SHA256_DATA_LENGTH 16
+
+/* The SHA256 functions. The Choice function is the same as the SHA1
+ function f1, and the majority function is the same as the SHA1 f3
+ function. They can be optimized to save one boolean operation each
+ - thanks to Rich Schroeppel, rcs@cs.arizona.edu for discovering
+ this */
+
+/* #define Choice(x,y,z) ( ( (x) & (y) ) | ( ~(x) & (z) ) ) */
+#define Choice(x,y,z) ( (z) ^ ( (x) & ( (y) ^ (z) ) ) )
+/* #define Majority(x,y,z) ( ((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)) ) */
+#define Majority(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) )
+
+#define S0(x) (ROTL32(30,(x)) ^ ROTL32(19,(x)) ^ ROTL32(10,(x)))
+#define S1(x) (ROTL32(26,(x)) ^ ROTL32(21,(x)) ^ ROTL32(7,(x)))
+
+#define s0(x) (ROTL32(25,(x)) ^ ROTL32(14,(x)) ^ ((x) >> 3))
+#define s1(x) (ROTL32(15,(x)) ^ ROTL32(13,(x)) ^ ((x) >> 10))
+
+/* The initial expanding function. The hash function is defined over an
+ 64-word expanded input array W, where the first 16 are copies of the input
+ data, and the remaining 64 are defined by
+
+ W[ t ] = s1(W[t-2]) + W[t-7] + s0(W[i-15]) + W[i-16]
+
+ This implementation generates these values on the fly in a circular
+ buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this
+ optimization.
+*/
+
+#define EXPAND(W,i) \
+( W[(i) & 15 ] += (s1(W[((i)-2) & 15]) + W[((i)-7) & 15] + s0(W[((i)-15) & 15])) )
+
+/* The prototype SHA sub-round. The fundamental sub-round is:
+
+ T1 = h + S1(e) + Choice(e,f,g) + K[t] + W[t]
+ T2 = S0(a) + Majority(a,b,c)
+ a' = T1+T2
+ b' = a
+ c' = b
+ d' = c
+ e' = d + T1
+ f' = e
+ g' = f
+ h' = g
+
+ but this is implemented by unrolling the loop 8 times and renaming
+ the variables
+ ( h, a, b, c, d, e, f, g ) = ( a, b, c, d, e, f, g, h ) each
+ iteration. */
+
+/* It's crucial that DATA is only used once, as that argument will
+ * have side effects. */
+#define ROUND(a,b,c,d,e,f,g,h,k,data) do { \
+ h += S1(e) + Choice(e,f,g) + k + data; \
+ d += h; \
+ h += S0(a) + Majority(a,b,c); \
+ } while (0)
+
+/* For fat builds */
+#if HAVE_NATIVE_sha256_compress
+void
+_nettle_sha256_compress_c(uint32_t *state, const uint8_t *input, const uint32_t *k);
+#define _nettle_sha256_compress _nettle_sha256_compress_c
+#endif
+
+void
+_nettle_sha256_compress(uint32_t *state, const uint8_t *input, const uint32_t *k)
+{
+ uint32_t data[SHA256_DATA_LENGTH];
+ uint32_t A, B, C, D, E, F, G, H; /* Local vars */
+ unsigned i;
+ uint32_t *d;
+
+ for (i = 0; i < SHA256_DATA_LENGTH; i++, input+= 4)
+ {
+ data[i] = READ_UINT32(input);
+ }
+
+ /* Set up first buffer and local data buffer */
+ A = state[0];
+ B = state[1];
+ C = state[2];
+ D = state[3];
+ E = state[4];
+ F = state[5];
+ G = state[6];
+ H = state[7];
+
+ /* Heavy mangling */
+ /* First 16 subrounds that act on the original data */
+
+ DEBUG(-1);
+ for (i = 0, d = data; i<16; i+=8, k += 8, d+= 8)
+ {
+ ROUND(A, B, C, D, E, F, G, H, k[0], d[0]); DEBUG(i);
+ ROUND(H, A, B, C, D, E, F, G, k[1], d[1]); DEBUG(i+1);
+ ROUND(G, H, A, B, C, D, E, F, k[2], d[2]);
+ ROUND(F, G, H, A, B, C, D, E, k[3], d[3]);
+ ROUND(E, F, G, H, A, B, C, D, k[4], d[4]);
+ ROUND(D, E, F, G, H, A, B, C, k[5], d[5]);
+ ROUND(C, D, E, F, G, H, A, B, k[6], d[6]); DEBUG(i+6);
+ ROUND(B, C, D, E, F, G, H, A, k[7], d[7]); DEBUG(i+7);
+ }
+
+ for (; i<64; i += 16, k+= 16)
+ {
+ ROUND(A, B, C, D, E, F, G, H, k[ 0], EXPAND(data, 0)); DEBUG(i);
+ ROUND(H, A, B, C, D, E, F, G, k[ 1], EXPAND(data, 1)); DEBUG(i+1);
+ ROUND(G, H, A, B, C, D, E, F, k[ 2], EXPAND(data, 2)); DEBUG(i+2);
+ ROUND(F, G, H, A, B, C, D, E, k[ 3], EXPAND(data, 3)); DEBUG(i+3);
+ ROUND(E, F, G, H, A, B, C, D, k[ 4], EXPAND(data, 4)); DEBUG(i+4);
+ ROUND(D, E, F, G, H, A, B, C, k[ 5], EXPAND(data, 5)); DEBUG(i+5);
+ ROUND(C, D, E, F, G, H, A, B, k[ 6], EXPAND(data, 6)); DEBUG(i+6);
+ ROUND(B, C, D, E, F, G, H, A, k[ 7], EXPAND(data, 7)); DEBUG(i+7);
+ ROUND(A, B, C, D, E, F, G, H, k[ 8], EXPAND(data, 8)); DEBUG(i+8);
+ ROUND(H, A, B, C, D, E, F, G, k[ 9], EXPAND(data, 9)); DEBUG(i+9);
+ ROUND(G, H, A, B, C, D, E, F, k[10], EXPAND(data, 10)); DEBUG(i+10);
+ ROUND(F, G, H, A, B, C, D, E, k[11], EXPAND(data, 11)); DEBUG(i+11);
+ ROUND(E, F, G, H, A, B, C, D, k[12], EXPAND(data, 12)); DEBUG(i+12);
+ ROUND(D, E, F, G, H, A, B, C, k[13], EXPAND(data, 13)); DEBUG(i+13);
+ ROUND(C, D, E, F, G, H, A, B, k[14], EXPAND(data, 14)); DEBUG(i+14);
+ ROUND(B, C, D, E, F, G, H, A, k[15], EXPAND(data, 15)); DEBUG(i+15);
+ }
+
+ /* Update state */
+ state[0] += A;
+ state[1] += B;
+ state[2] += C;
+ state[3] += D;
+ state[4] += E;
+ state[5] += F;
+ state[6] += G;
+ state[7] += H;
+#if SHA256_DEBUG
+ fprintf(stderr, "99: %8x %8x %8x %8x %8x %8x %8x %8x\n",
+ state[0], state[1], state[2], state[3],
+ state[4], state[5], state[6], state[7]);
+#endif
+}
diff --git a/src/granger/src/nettle/sha256.c b/src/granger/src/nettle/sha256.c
new file mode 100644
index 0000000..0cb3559
--- /dev/null
+++ b/src/granger/src/nettle/sha256.c
@@ -0,0 +1,162 @@
+/* sha256.c
+
+ The sha256 hash function.
+ See http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+
+ Copyright (C) 2001 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+/* Modelled after the sha1.c code by Peter Gutmann. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sha2.h"
+
+#include "macros.h"
+#include "nettle-write.h"
+
+/* Generated by the shadata program. */
+static const uint32_t
+K[64] =
+{
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+ 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+ 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+ 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+ 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+ 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+ 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+ 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+ 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+ 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+ 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+ 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+ 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
+};
+
+#define COMPRESS(ctx, data) (_nettle_sha256_compress((ctx)->state, (data), K))
+
+/* Initialize the SHA values */
+
+void
+sha256_init(struct sha256_ctx *ctx)
+{
+ /* Initial values, also generated by the shadata program. */
+ static const uint32_t H0[_SHA256_DIGEST_LENGTH] =
+ {
+ 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL,
+ 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL,
+ };
+
+ memcpy(ctx->state, H0, sizeof(H0));
+
+ /* Initialize bit count */
+ ctx->count = 0;
+
+ /* Initialize buffer */
+ ctx->index = 0;
+}
+
+void
+sha256_update(struct sha256_ctx *ctx,
+ size_t length, const uint8_t *data)
+{
+ MD_UPDATE (ctx, length, data, COMPRESS, ctx->count++);
+}
+
+static void
+sha256_write_digest(struct sha256_ctx *ctx,
+ size_t length,
+ uint8_t *digest)
+{
+ uint64_t bit_count;
+
+ assert(length <= SHA256_DIGEST_SIZE);
+
+ MD_PAD(ctx, 8, COMPRESS);
+
+ /* There are 512 = 2^9 bits in one block */
+ bit_count = (ctx->count << 9) | (ctx->index << 3);
+
+ /* This is slightly inefficient, as the numbers are converted to
+ big-endian format, and will be converted back by the compression
+ function. It's probably not worth the effort to fix this. */
+ WRITE_UINT64(ctx->block + (SHA256_BLOCK_SIZE - 8), bit_count);
+ COMPRESS(ctx, ctx->block);
+
+ _nettle_write_be32(length, digest, ctx->state);
+}
+
+void
+sha256_digest(struct sha256_ctx *ctx,
+ size_t length,
+ uint8_t *digest)
+{
+ sha256_write_digest(ctx, length, digest);
+ sha256_init(ctx);
+}
+
+/* sha224 variant. */
+
+void
+sha224_init(struct sha256_ctx *ctx)
+{
+ /* Initial values. Low 32 bits of the initial values for sha384. */
+ static const uint32_t H0[_SHA256_DIGEST_LENGTH] =
+ {
+ 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+ 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,
+ };
+
+ memcpy(ctx->state, H0, sizeof(H0));
+
+ /* Initialize bit count */
+ ctx->count = 0;
+
+ /* Initialize buffer */
+ ctx->index = 0;
+}
+
+void
+sha224_digest(struct sha256_ctx *ctx,
+ size_t length,
+ uint8_t *digest)
+{
+ sha256_write_digest(ctx, length, digest);
+ sha224_init(ctx);
+}
diff --git a/src/granger/src/nettle/version.h b/src/granger/src/nettle/version.h
new file mode 100644
index 0000000..3a1d20c
--- /dev/null
+++ b/src/granger/src/nettle/version.h
@@ -0,0 +1,58 @@
+/* version.h
+
+ Information about library version.
+
+ Copyright (C) 2015 Red Hat, Inc.
+ Copyright (C) 2015 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_VERSION_H_INCLUDED
+#define NETTLE_VERSION_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Individual version numbers in decimal */
+#define NETTLE_VERSION_MAJOR 3
+#define NETTLE_VERSION_MINOR 3
+
+#define NETTLE_USE_MINI_GMP 1
+
+/* We need a preprocessor constant for GMP_NUMB_BITS, simply using
+ sizeof(mp_limb_t) * CHAR_BIT is not good enough. */
+#if NETTLE_USE_MINI_GMP
+# define GMP_NUMB_BITS (sizeof(unsigned long) * 8)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_VERSION_H_INCLUDED */
diff --git a/src/granger/src/nettle/write-be32.c b/src/granger/src/nettle/write-be32.c
new file mode 100644
index 0000000..7d68905
--- /dev/null
+++ b/src/granger/src/nettle/write-be32.c
@@ -0,0 +1,77 @@
+/* write-be32.c
+
+ Copyright (C) 2001 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "nettle-write.h"
+
+#include "macros.h"
+
+void
+_nettle_write_be32(size_t length, uint8_t *dst,
+ uint32_t *src)
+{
+ size_t i;
+ size_t words;
+ unsigned leftover;
+
+ words = length / 4;
+ leftover = length % 4;
+
+ for (i = 0; i < words; i++, dst += 4)
+ WRITE_UINT32(dst, src[i]);
+
+ if (leftover)
+ {
+ uint32_t word;
+ unsigned j = leftover;
+
+ word = src[i];
+
+ switch (leftover)
+ {
+ default:
+ abort();
+ case 3:
+ dst[--j] = (word >> 8) & 0xff;
+ /* Fall through */
+ case 2:
+ dst[--j] = (word >> 16) & 0xff;
+ /* Fall through */
+ case 1:
+ dst[--j] = (word >> 24) & 0xff;
+ }
+ }
+}
diff --git a/src/granger/src/nettle/write-le32.c b/src/granger/src/nettle/write-le32.c
new file mode 100644
index 0000000..d44eb24
--- /dev/null
+++ b/src/granger/src/nettle/write-le32.c
@@ -0,0 +1,69 @@
+/* write-le32.c
+
+ Copyright (C) 2001, 2011 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "nettle-write.h"
+
+#include "macros.h"
+
+void
+_nettle_write_le32(size_t length, uint8_t *dst,
+ uint32_t *src)
+{
+ size_t i;
+ size_t words;
+ unsigned leftover;
+
+ words = length / 4;
+ leftover = length % 4;
+
+ for (i = 0; i < words; i++, dst += 4)
+ LE_WRITE_UINT32(dst, src[i]);
+
+ if (leftover)
+ {
+ uint32_t word;
+
+ word = src[i];
+
+ do
+ {
+ *dst++ = word & 0xff;
+ word >>= 8;
+ }
+ while (--leftover);
+ }
+}
diff --git a/src/granger/src/premake/CMakeLists.txt b/src/granger/src/premake/CMakeLists.txt
new file mode 100644
index 0000000..455a9e2
--- /dev/null
+++ b/src/granger/src/premake/CMakeLists.txt
@@ -0,0 +1,32 @@
+if(NOT WIN32)
+ add_definitions(-Wall -Wextra)
+endif(NOT WIN32)
+
+if(WIN32)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+endif(WIN32)
+
+add_library(premake
+ os_access.c
+ os_chdir.c
+ os_copyfile.c
+ os_elevate.c
+ os_getcwd.c
+ os_is64bit.c
+ os_isdir.c
+ os_isfile.c
+ os_match.c
+ os_mkdir.c
+ os_pathsearch.c
+ os_rmdir.c
+ os_stat.c
+ path_getabsolute.c
+ path_getrelative.c
+ path_isabsolute.c
+ path_join.c
+ path_normalize.c
+ path_translate.c
+ premake.c
+ premake.h
+ string_endswith.c
+ )
diff --git a/src/granger/src/premake/os_access.c b/src/granger/src/premake/os_access.c
new file mode 100644
index 0000000..90ceb46
--- /dev/null
+++ b/src/granger/src/premake/os_access.c
@@ -0,0 +1,58 @@
+/*
+ * This file is part of Granger.
+ * Copyright (c) 2016 Jeff Kent <jeff@jkent.net>
+ *
+ * Granger is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Granger is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Granger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "premake.h"
+
+#if defined(PLATFORM_WINDOWS)
+#include <io.h>
+#define access _access
+#define X_OK 1
+#define W_OK 2
+#define R_OK 4
+#endif
+
+int os_access(lua_State *L)
+{
+ const char *filename = luaL_checkstring(L, 1);
+ const char *mode = luaL_optstring(L, 2, "r");
+ int nmode = 0;
+ int result;
+
+ while (*mode) {
+ switch (*mode) {
+ case 'x':
+ nmode |= X_OK;
+ break;
+ case 'w':
+ nmode |= W_OK;
+ break;
+ case 'r':
+ nmode |= R_OK;
+ break;
+ default:
+ lua_pushboolean(L, 0);
+ return 1;
+ }
+ mode++;
+ }
+
+ result = access(filename, nmode);
+
+ lua_pushboolean(L, result == 0);
+ return 1;
+}
diff --git a/src/granger/src/premake/os_chdir.c b/src/granger/src/premake/os_chdir.c
new file mode 100644
index 0000000..3acce68
--- /dev/null
+++ b/src/granger/src/premake/os_chdir.c
@@ -0,0 +1,32 @@
+/**
+ * \file os_chdir.c
+ * \brief Change the current working directory.
+ * \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
+ */
+
+#include "premake.h"
+
+
+int os_chdir(lua_State* L)
+{
+ int z;
+ const char* path = luaL_checkstring(L, 1);
+
+#if PLATFORM_WINDOWS
+ z = SetCurrentDirectory(path);
+#else
+ z = !chdir(path);
+#endif
+
+ if (!z)
+ {
+ lua_pushnil(L);
+ lua_pushfstring(L, "unable to switch to directory '%s'", path);
+ return 2;
+ }
+ else
+ {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+}
diff --git a/src/granger/src/premake/os_copyfile.c b/src/granger/src/premake/os_copyfile.c
new file mode 100644
index 0000000..b15d600
--- /dev/null
+++ b/src/granger/src/premake/os_copyfile.c
@@ -0,0 +1,34 @@
+/**
+ * \file os_copyfile.c
+ * \brief Copy a file from one location to another.
+ * \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
+ */
+
+#include <stdlib.h>
+#include "premake.h"
+
+int os_copyfile(lua_State* L)
+{
+ int z;
+ const char* src = luaL_checkstring(L, 1);
+ const char* dst = luaL_checkstring(L, 2);
+
+#if PLATFORM_WINDOWS
+ z = CopyFile(src, dst, FALSE);
+#else
+ lua_pushfstring(L, "cp %s %s", src, dst);
+ z = (system(lua_tostring(L, -1)) == 0);
+#endif
+
+ if (!z)
+ {
+ lua_pushnil(L);
+ lua_pushfstring(L, "unable to copy file to '%s'", dst);
+ return 2;
+ }
+ else
+ {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+}
diff --git a/src/granger/src/premake/os_elevate.c b/src/granger/src/premake/os_elevate.c
new file mode 100644
index 0000000..cab0906
--- /dev/null
+++ b/src/granger/src/premake/os_elevate.c
@@ -0,0 +1,240 @@
+/*
+ * This file is part of Granger.
+ * Copyright (c) 2016 Jeff Kent <jeff@jkent.net>
+ *
+ * Granger is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Granger is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ *
+ * along with Granger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "premake.h"
+#include "../strvec.h"
+
+#if defined(PLATFORM_WINDOWS)
+#include <shellapi.h>
+static int do_elevate(lua_State *L)
+{
+ BOOL is_elevated = FALSE;
+ HANDLE hToken = NULL;
+
+ if (OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken)) {
+ TOKEN_ELEVATION Elevation;
+ DWORD cbSize = sizeof(TOKEN_ELEVATION);
+ if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) {
+ is_elevated = Elevation.TokenIsElevated;
+ }
+ }
+ if (hToken) {
+ CloseHandle(hToken);
+ }
+ if (is_elevated) {
+ return 1;
+ }
+
+ char szPath[MAX_PATH];
+ if (!GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath))) {
+ return 0;
+ }
+
+ void *sv = StringVector_New();
+
+ lua_getglobal(L, "_GRANGER_SCRIPT");
+ StringVector_Add(sv, luaL_checkstring(L, 1));
+ lua_pop(L, 1);
+
+ lua_getglobal(L, "argv");
+ if (luaL_len(L, 1) > 0) {
+ StringVector_Add(sv, "--");
+ }
+
+ for (int i = 1; ; i++) {
+ lua_pushinteger(L, i);
+ lua_gettable(L, 1);
+ if (lua_isnil(L, -1)) {
+ break;
+ }
+ StringVector_Add(sv, luaL_checkstring(L, -1));
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+
+ SHELLEXECUTEINFO sei = { 0 };
+ sei.cbSize = sizeof(SHELLEXECUTEINFO);
+ sei.lpVerb = "runas";
+ sei.lpFile = szPath;
+ sei.lpParameters = StringVector_toString(sv);
+ sei.nShow = SW_NORMAL;
+
+ StringVector_Delete(sv);
+
+ if (ShellExecuteEx(&sei)) {
+ free((void*)sei.lpParameters);
+ exit(0);
+ }
+
+ free((void*)sei.lpParameters);
+ return 0;
+}
+#endif
+
+#if defined(PLATFORM_MACOSX)
+#include <Security/Authorization.h>
+#include <Security/AuthorizationTags.h>
+
+static int do_elevate(lua_State *L)
+{
+ const char *execpath;
+ int argc = 0;
+ char **argv;
+
+ if (geteuid() == 0) {
+ return 1;
+ }
+
+ lua_getglobal(L, "_EXE_PATH");
+ execpath = luaL_checkstring(L, 1);
+
+ OSStatus err;
+ AuthorizationRef ref;
+ AuthorizationFlags flags;
+
+ flags = kAuthorizationFlagDefaults;
+ err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, flags, &ref);
+
+ if (err != errAuthorizationSuccess) {
+ return 0;
+ }
+
+ AuthorizationItem _temp = {kAuthorizationRightExecute, 0, NULL, 0};
+ AuthorizationRights rights = {1, &_temp};
+
+ flags = kAuthorizationFlagDefaults |
+ kAuthorizationFlagInteractionAllowed |
+ kAuthorizationFlagPreAuthorize |
+ kAuthorizationFlagExtendRights;
+
+ err = AuthorizationCopyRights(ref, &rights, NULL, flags, NULL);
+ if (err != errAuthorizationSuccess) {
+ AuthorizationFree(ref, kAuthorizationFlagDefaults);
+ return 0;
+ }
+
+ void *sv = StringVector_New();
+
+ lua_getglobal(L, "_GRANGER_SCRIPT");
+ StringVector_Add(sv, luaL_checkstring(L, 1));
+ lua_pop(L, 1);
+
+ lua_getglobal(L, "argv");
+ if (luaL_len(L, 1) > 0) {
+ StringVector_Add(sv, "--");
+ }
+
+ for (int i = 1; ; i++) {
+ lua_pushinteger(L, i);
+ lua_gettable(L, 1);
+ if (lua_isnil(L, -1)) {
+ break;
+ }
+ StringVector_Add(sv, luaL_checkstring(L, -1));
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+
+ flags = kAuthorizationFlagDefaults;
+ err = AuthorizationExecuteWithPrivileges(ref, execpath, flags, StringVector_GetVector(sv), NULL);
+ AuthorizationFree(ref, kAuthorizationFlagDefaults);
+ if (err != errAuthorizationSuccess) {
+ StringVector_Delete(sv);
+ return 0;
+ }
+
+ StringVector_Delete(sv);
+ exit(0);
+}
+#endif
+
+#if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD)
+static int do_elevate(lua_State *L)
+{
+ char *pkexec, *display;
+ char cwd[PATH_MAX + 1];
+
+ if (geteuid() == 0) {
+ return 1;
+ }
+
+ display = getenv("DISPLAY");
+ if (!display) {
+ return 0;
+ }
+
+ if (access("/usr/bin/pkexec", X_OK) != -1) {
+ pkexec = "/usr/bin/pkexec";
+ } else if (access("/usr/local/bin/pkexec", X_OK) != -1) {
+ pkexec = "/usr/local/bin/pkexec";
+ } else {
+ return 0;
+ }
+
+ if (!getcwd(cwd, sizeof(cwd))) {
+ return 0;
+ }
+
+ void *sv = StringVector_New();
+ StringVector_Add(sv, "pkexec");
+ StringVector_Add(sv, "--user");
+ StringVector_Add(sv, "root");
+
+ lua_getglobal(L, "_EXE_PATH");
+ StringVector_Add(sv, luaL_checkstring(L, 1));
+ lua_pop(L, 1);
+
+ StringVector_Add(sv, "-C");
+ StringVector_Add(sv, cwd);
+
+ lua_getglobal(L, "_GRANGER_SCRIPT");
+ StringVector_Add(sv, luaL_checkstring(L, 1));
+ lua_pop(L, 1);
+
+ lua_getglobal(L, "argv");
+ if (luaL_len(L, 1) > 0) {
+ StringVector_Add(sv, "--");
+ }
+
+ for (int i = 1; ; i++) {
+ lua_pushinteger(L, i);
+ lua_gettable(L, 1);
+ if (lua_isnil(L, -1)) {
+ break;
+ }
+ StringVector_Add(sv, luaL_checkstring(L, -1));
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+
+ execv(pkexec, (char * const*)StringVector_GetVector(sv));
+
+ fprintf(stderr, "execv failed\n");
+ lua_pop(L, 1);
+ return 0;
+}
+#endif
+
+int os_elevate(lua_State* L)
+{
+ lua_pushboolean(L, do_elevate(L));
+ return 1;
+}
diff --git a/src/granger/src/premake/os_getcwd.c b/src/granger/src/premake/os_getcwd.c
new file mode 100644
index 0000000..de8bfbd
--- /dev/null
+++ b/src/granger/src/premake/os_getcwd.c
@@ -0,0 +1,36 @@
+/**
+ * \file os_getcwd.c
+ * \brief Retrieve the current working directory.
+ * \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
+ */
+
+#include "premake.h"
+
+int os_getcwd(lua_State* L)
+{
+ char buffer[0x4000];
+ if (do_getcwd(buffer, 0x4000)) {
+ lua_pushstring(L, buffer);
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+int do_getcwd(char* buffer, size_t size)
+{
+ int result;
+
+#if PLATFORM_WINDOWS
+ result = (GetCurrentDirectory(size, buffer) != 0);
+ if (result) {
+ do_translate(buffer, '/');
+ }
+#else
+ result = (getcwd(buffer, size) != 0);
+#endif
+
+ return result;
+}
diff --git a/src/granger/src/premake/os_is64bit.c b/src/granger/src/premake/os_is64bit.c
new file mode 100644
index 0000000..3134751
--- /dev/null
+++ b/src/granger/src/premake/os_is64bit.c
@@ -0,0 +1,30 @@
+/**
+ * \file os_is64bit.c
+ * \brief Native code-side checking for a 64-bit architecture.
+ * \author Copyright (c) 2011 Jason Perkins and the Premake project
+ */
+
+#include "premake.h"
+
+int os_is64bit(lua_State* L)
+{
+ // If this code returns true, then the platform is 64-bit. If it
+ // returns false, the platform might still be 64-bit, but more
+ // checking will need to be done on the Lua side of things.
+#if PLATFORM_WINDOWS
+ typedef BOOL (WINAPI* WowFuncSig)(HANDLE, PBOOL);
+ WowFuncSig func = (WowFuncSig)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
+ if (func)
+ {
+ BOOL isWow = FALSE;
+ if (func(GetCurrentProcess(), &isWow))
+ {
+ lua_pushboolean(L, isWow);
+ return 1;
+ }
+ }
+#endif
+
+ lua_pushboolean(L, 0);
+ return 1;
+}
diff --git a/src/granger/src/premake/os_isdir.c b/src/granger/src/premake/os_isdir.c
new file mode 100644
index 0000000..fb5e8bb
--- /dev/null
+++ b/src/granger/src/premake/os_isdir.c
@@ -0,0 +1,34 @@
+/**
+ * \file os_isdir.c
+ * \brief Returns true if the specified directory exists.
+ * \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
+ */
+
+#include <string.h>
+#include <sys/stat.h>
+#include "premake.h"
+
+
+int os_isdir(lua_State* L)
+{
+ struct stat buf;
+ const char* path = luaL_checkstring(L, 1);
+
+ /* empty path is equivalent to ".", must be true */
+ if (strlen(path) == 0)
+ {
+ lua_pushboolean(L, 1);
+ }
+ else if (stat(path, &buf) == 0)
+ {
+ lua_pushboolean(L, buf.st_mode & S_IFDIR);
+ }
+ else
+ {
+ lua_pushboolean(L, 0);
+ }
+
+ return 1;
+}
+
+
diff --git a/src/granger/src/premake/os_isfile.c b/src/granger/src/premake/os_isfile.c
new file mode 100644
index 0000000..61e0def
--- /dev/null
+++ b/src/granger/src/premake/os_isfile.c
@@ -0,0 +1,30 @@
+/**
+ * \file os_isfile.c
+ * \brief Returns true if the given file exists on the file system.
+ * \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
+ */
+
+#include <sys/stat.h>
+#include "premake.h"
+
+
+int os_isfile(lua_State* L)
+{
+ const char* filename = luaL_checkstring(L, 1);
+ lua_pushboolean(L, do_isfile(filename));
+ return 1;
+}
+
+
+int do_isfile(const char* filename)
+{
+ struct stat buf;
+ if (stat(filename, &buf) == 0)
+ {
+ return ((buf.st_mode & S_IFDIR) == 0);
+ }
+ else
+ {
+ return 0;
+ }
+}
diff --git a/src/granger/src/premake/os_match.c b/src/granger/src/premake/os_match.c
new file mode 100644
index 0000000..5ccc04d
--- /dev/null
+++ b/src/granger/src/premake/os_match.c
@@ -0,0 +1,181 @@
+/**
+ * \file os_match.c
+ * \brief Match files and directories.
+ * \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "premake.h"
+
+
+#if PLATFORM_WINDOWS
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct struct_MatchInfo
+{
+ HANDLE handle;
+ int is_first;
+ WIN32_FIND_DATA entry;
+} MatchInfo;
+
+int os_matchstart(lua_State* L)
+{
+ const char* mask = luaL_checkstring(L, 1);
+ MatchInfo* m = (MatchInfo*)malloc(sizeof(MatchInfo));
+ m->handle = FindFirstFile(mask, &m->entry);
+ m->is_first = 1;
+ lua_pushlightuserdata(L, m);
+ return 1;
+}
+
+int os_matchdone(lua_State* L)
+{
+ MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
+ if (m->handle != INVALID_HANDLE_VALUE)
+ FindClose(m->handle);
+ free(m);
+ return 0;
+}
+
+int os_matchname(lua_State* L)
+{
+ MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
+ lua_pushstring(L, m->entry.cFileName);
+ return 1;
+}
+
+int os_matchisfile(lua_State* L)
+{
+ MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
+ lua_pushboolean(L, (m->entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
+ return 1;
+}
+
+int os_matchnext(lua_State* L)
+{
+ MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
+ if (m->handle == INVALID_HANDLE_VALUE) {
+ return 0;
+ }
+
+ while (m) /* loop forever */
+ {
+ if (!m->is_first)
+ {
+ if (!FindNextFile(m->handle, &m->entry))
+ return 0;
+ }
+
+ m->is_first = 0;
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+#else
+
+#include <dirent.h>
+#include <fnmatch.h>
+#include <sys/stat.h>
+
+typedef struct struct_MatchInfo
+{
+ DIR* handle;
+ struct dirent* entry;
+ char* path;
+ char* mask;
+} MatchInfo;
+
+int os_matchstart(lua_State* L)
+{
+ const char* split;
+ const char* mask = luaL_checkstring(L, 1);
+ MatchInfo* m = (MatchInfo*)malloc(sizeof(MatchInfo));
+
+ /* split the mask into path and filename components */
+ split = strrchr(mask, '/');
+ if (split)
+ {
+ m->path = (char*)malloc(split - mask + 1);
+ strncpy(m->path, mask, split - mask);
+ m->path[split - mask] = '\0';
+ m->mask = (char*)malloc(mask + strlen(mask) - split);
+ strcpy(m->mask, split + 1);
+ }
+ else
+ {
+ m->path = (char*)malloc(2);
+ strcpy(m->path, ".");
+ m->mask = (char*)malloc(strlen(mask)+1);
+ strcpy(m->mask, mask);
+ }
+
+ m->handle = opendir(m->path);
+ lua_pushlightuserdata(L, m);
+ return 1;
+}
+
+int os_matchdone(lua_State* L)
+{
+ MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
+ if (m->handle != NULL)
+ closedir(m->handle);
+ free(m->path);
+ free(m->mask);
+ free(m);
+ return 0;
+}
+
+int os_matchname(lua_State* L)
+{
+ MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
+ lua_pushstring(L, m->entry->d_name);
+ return 1;
+}
+
+int os_matchisfile(lua_State* L)
+{
+ struct stat info;
+ const char* fname;
+
+ MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
+ lua_pushfstring(L, "%s/%s", m->path, m->entry->d_name);
+ fname = lua_tostring(L, -1);
+ lua_pop(L, 1);
+
+ if (stat(fname, &info) == 0)
+ {
+ lua_pushboolean(L, S_ISREG(info.st_mode));
+ return 1;
+ }
+
+ return 0;
+}
+
+int os_matchnext(lua_State* L)
+{
+ MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
+ if (m->handle == NULL)
+ return 0;
+
+ m->entry = readdir(m->handle);
+ while (m->entry != NULL)
+ {
+ const char* name = m->entry->d_name;
+ if (fnmatch(m->mask, name, 0) == 0)
+ {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ m->entry = readdir(m->handle);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/src/granger/src/premake/os_mkdir.c b/src/granger/src/premake/os_mkdir.c
new file mode 100644
index 0000000..a7a69db
--- /dev/null
+++ b/src/granger/src/premake/os_mkdir.c
@@ -0,0 +1,33 @@
+/**
+ * \file os_mkdir.c
+ * \brief Create a subdirectory.
+ * \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
+ */
+
+#include <sys/stat.h>
+#include "premake.h"
+
+
+int os_mkdir(lua_State* L)
+{
+ int z;
+ const char* path = luaL_checkstring(L, 1);
+
+#if PLATFORM_WINDOWS
+ z = CreateDirectory(path, NULL);
+#else
+ z = (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0);
+#endif
+
+ if (!z)
+ {
+ lua_pushnil(L);
+ lua_pushfstring(L, "unable to create directory '%s'", path);
+ return 2;
+ }
+ else
+ {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+}
diff --git a/src/granger/src/premake/os_pathsearch.c b/src/granger/src/premake/os_pathsearch.c
new file mode 100644
index 0000000..44f775d
--- /dev/null
+++ b/src/granger/src/premake/os_pathsearch.c
@@ -0,0 +1,84 @@
+/**
+ * \file os_pathsearch.c
+ * \brief Locates a file, given a set of search paths.
+ * \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
+ *
+ * \note This function is required by the bootstrapping code; it must be
+ * implemented here in the host and not scripted.
+ */
+
+#include <string.h>
+#include "premake.h"
+
+
+int os_pathsearch(lua_State* L)
+{
+ int i;
+ for (i = 2; i <= lua_gettop(L); ++i)
+ {
+ const char* path;
+
+ if (lua_isnil(L, i))
+ continue;
+
+ path = luaL_checkstring(L, i);
+ do
+ {
+ const char* split;
+
+ /* look for the closest path separator ; or : */
+ /* can't use : on windows because it breaks on C:\path */
+ const char* semi = strchr(path, ';');
+#if !defined(PLATFORM_WINDOWS)
+ const char* full = strchr(path, ':');
+#else
+ const char* full = NULL;
+#endif
+
+ if (!semi)
+ {
+ split = full;
+ }
+ else if (!full)
+ {
+ split = semi;
+ }
+ else
+ {
+ split = (semi < full) ? semi : full;
+ }
+
+ /* push this piece of the full search string onto the stack */
+ if (split)
+ {
+ lua_pushlstring(L, path, split - path);
+ }
+ else
+ {
+ lua_pushstring(L, path);
+ }
+
+ /* keep an extra copy around, so I can return it if I have a match */
+ lua_pushvalue(L, -1);
+
+ /* append the filename to make the full test path */
+ lua_pushstring(L, "/");
+ lua_pushvalue(L, 1);
+ lua_concat(L, 3);
+
+ /* test it - if it exists return the path */
+ if (do_isfile(lua_tostring(L, -1)))
+ {
+ lua_pop(L, 1);
+ return 1;
+ }
+
+ /* no match, set up the next try */
+ lua_pop(L, 2);
+ path = (split) ? split + 1 : NULL;
+ }
+ while (path);
+ }
+
+ return 0;
+}
diff --git a/src/granger/src/premake/os_rmdir.c b/src/granger/src/premake/os_rmdir.c
new file mode 100644
index 0000000..f2ffeee
--- /dev/null
+++ b/src/granger/src/premake/os_rmdir.c
@@ -0,0 +1,33 @@
+/**
+ * \file os_rmdir.c
+ * \brief Remove a subdirectory.
+ * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
+ */
+
+#include <stdlib.h>
+#include "premake.h"
+
+
+int os_rmdir(lua_State* L)
+{
+ int z;
+ const char* path = luaL_checkstring(L, 1);
+
+#if PLATFORM_WINDOWS
+ z = RemoveDirectory(path);
+#else
+ z = (0 == rmdir(path));
+#endif
+
+ if (!z)
+ {
+ lua_pushnil(L);
+ lua_pushfstring(L, "unable to remove directory '%s'", path);
+ return 2;
+ }
+ else
+ {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+}
diff --git a/src/granger/src/premake/os_stat.c b/src/granger/src/premake/os_stat.c
new file mode 100644
index 0000000..b3554dc
--- /dev/null
+++ b/src/granger/src/premake/os_stat.c
@@ -0,0 +1,46 @@
+/**
+ * \file os_stat.c
+ * \brief Retrieve information about a file.
+ * \author Copyright (c) 2011 Jason Perkins and the Premake project
+ */
+
+#include "premake.h"
+#include <sys/stat.h>
+#include <errno.h>
+
+int os_stat(lua_State* L)
+{
+ struct stat s;
+
+ const char* filename = luaL_checkstring(L, 1);
+ if (stat(filename, &s) != 0)
+ {
+ lua_pushnil(L);
+ switch (errno)
+ {
+ case EACCES:
+ lua_pushfstring(L, "'%s' could not be accessed", filename);
+ break;
+ case ENOENT:
+ lua_pushfstring(L, "'%s' was not found", filename);
+ break;
+ default:
+ lua_pushfstring(L, "An unknown error %d occured while accessing '%s'", errno, filename);
+ break;
+ }
+ return 2;
+ }
+
+
+ lua_newtable(L);
+
+ lua_pushstring(L, "mtime");
+ lua_pushinteger(L, (lua_Integer)s.st_mtime);
+ lua_settable(L, -3);
+
+ lua_pushstring(L, "size");
+ lua_pushnumber(L, s.st_size);
+ lua_settable(L, -3);
+
+ return 1;
+}
diff --git a/src/granger/src/premake/path_getabsolute.c b/src/granger/src/premake/path_getabsolute.c
new file mode 100644
index 0000000..36b1c3a
--- /dev/null
+++ b/src/granger/src/premake/path_getabsolute.c
@@ -0,0 +1,102 @@
+/**
+ * \file path_getabsolute.c
+ * \brief Returns an absolute version of a relative path.
+ * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
+ */
+
+#include "premake.h"
+#include <string.h>
+
+
+void do_getabsolute(char* result, const char* value, const char* relative_to)
+{
+ int i;
+ char* ch;
+ char* prev;
+ char buffer[0x4000] = { '\0' };
+
+ /* if the path is not already absolute, base it on working dir */
+ if (!do_isabsolute(value)) {
+ if (relative_to) {
+ strcpy(buffer, relative_to);
+ }
+ else {
+ do_getcwd(buffer, 0x4000);
+ }
+ strcat(buffer, "/");
+ }
+
+ /* normalize the path */
+ strcat(buffer, value);
+ do_translate(buffer, '/');
+
+ /* process it part by part */
+ result[0] = '\0';
+ if (buffer[0] == '/') {
+ strcat(result, "/");
+ }
+
+ prev = NULL;
+ ch = strtok(buffer, "/");
+ while (ch) {
+ /* remove ".." where I can */
+ if (strcmp(ch, "..") == 0 && (prev == NULL || (prev[0] != '$' && strcmp(prev, "..") != 0))) {
+ i = strlen(result) - 2;
+ while (i >= 0 && result[i] != '/') {
+ --i;
+ }
+ if (i >= 0) {
+ result[i + 1] = '\0';
+ }
+ ch = NULL;
+ }
+
+ /* allow everything except "." */
+ else if (strcmp(ch, ".") != 0) {
+ strcat(result, ch);
+ strcat(result, "/");
+ }
+
+ prev = ch;
+ ch = strtok(NULL, "/");
+ }
+
+ /* remove trailing slash */
+ i = strlen(result) - 1;
+ if (result[i] == '/') {
+ result[i] = '\0';
+ }
+}
+
+
+int path_getabsolute(lua_State* L)
+{
+ const char* relative_to;
+ char buffer[0x4000];
+
+ relative_to = NULL;
+ if (lua_gettop(L) > 1 && !lua_isnil(L,2)) {
+ relative_to = luaL_checkstring(L, 2);
+ }
+
+ if (lua_istable(L, 1)) {
+ int i = 0;
+ lua_newtable(L);
+ lua_pushnil(L);
+ while (lua_next(L, 1)) {
+ const char* value = luaL_checkstring(L, -1);
+ do_getabsolute(buffer, value, relative_to);
+ lua_pop(L, 1);
+
+ lua_pushstring(L, buffer);
+ lua_rawseti(L, -3, ++i);
+ }
+ return 1;
+ }
+ else {
+ const char* value = luaL_checkstring(L, 1);
+ do_getabsolute(buffer, value, relative_to);
+ lua_pushstring(L, buffer);
+ return 1;
+ }
+}
diff --git a/src/granger/src/premake/path_getrelative.c b/src/granger/src/premake/path_getrelative.c
new file mode 100644
index 0000000..dc6629b
--- /dev/null
+++ b/src/granger/src/premake/path_getrelative.c
@@ -0,0 +1,80 @@
+/**
+ * \file path_getrelative.c
+ * \brief Returns a path relative to another.
+ * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
+ */
+
+#include "premake.h"
+#include <string.h>
+
+
+int path_getrelative(lua_State* L)
+{
+ int i, last, count;
+ char src[0x4000];
+ char dst[0x4000];
+
+ const char* p1 = luaL_checkstring(L, 1);
+ const char* p2 = luaL_checkstring(L, 2);
+
+ /* normalize the paths */
+ do_getabsolute(src, p1, NULL);
+ do_getabsolute(dst, p2, NULL);
+
+ /* same directory? */
+ if (strcmp(src, dst) == 0) {
+ lua_pushstring(L, ".");
+ return 1;
+ }
+
+ /* dollar macro? Can't tell what the real path might be, so treat
+ * as absolute. This enables paths like $(SDK_ROOT)/include to
+ * work as expected. */
+ if (dst[0] == '$') {
+ lua_pushstring(L, dst);
+ return 1;
+ }
+
+ /* find the common leading directories */
+ strcat(src, "/");
+ strcat(dst, "/");
+
+ last = -1;
+ i = 0;
+ while (src[i] && dst[i] && src[i] == dst[i]) {
+ if (src[i] == '/') {
+ last = i;
+ }
+ ++i;
+ }
+
+ /* if I end up with just the root of the filesystem, either a single
+ * slash (/) or a drive letter (c:) then return the absolute path. */
+ if (last <= 0 || (last == 2 && src[1] == ':')) {
+ dst[strlen(dst) - 1] = '\0';
+ lua_pushstring(L, dst);
+ return 1;
+ }
+
+ /* count remaining levels in src */
+ count = 0;
+ for (i = last + 1; src[i] != '\0'; ++i) {
+ if (src[i] == '/') {
+ ++count;
+ }
+ }
+
+ /* start my result by backing out that many levels */
+ src[0] = '\0';
+ for (i = 0; i < count; ++i) {
+ strcat(src, "../");
+ }
+
+ /* append what's left */
+ strcat(src, dst + last + 1);
+
+ /* remove trailing slash and done */
+ src[strlen(src) - 1] = '\0';
+ lua_pushstring(L, src);
+ return 1;
+}
diff --git a/src/granger/src/premake/path_isabsolute.c b/src/granger/src/premake/path_isabsolute.c
new file mode 100644
index 0000000..7412935
--- /dev/null
+++ b/src/granger/src/premake/path_isabsolute.c
@@ -0,0 +1,27 @@
+/**
+ * \file path_isabsolute.c
+ * \brief Determines if a path is absolute or relative.
+ * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
+ */
+
+#include "premake.h"
+
+
+int path_isabsolute(lua_State* L)
+{
+ const char* path = luaL_checkstring(L, -1);
+ lua_pushboolean(L, do_isabsolute(path));
+ return 1;
+}
+
+
+int do_isabsolute(const char* path)
+{
+ return (
+ path[0] == '/' ||
+ path[0] == '\\' ||
+ path[0] == '$' ||
+ (path[0] == '"' && path[1] == '$') ||
+ (path[0] != '\0' && path[1] == ':')
+ );
+}
diff --git a/src/granger/src/premake/path_join.c b/src/granger/src/premake/path_join.c
new file mode 100644
index 0000000..7d80104
--- /dev/null
+++ b/src/granger/src/premake/path_join.c
@@ -0,0 +1,58 @@
+/**
+ * \file path_join.c
+ * \brief Join two or more pieces of a file system path.
+ * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
+ */
+
+#include "premake.h"
+#include <string.h>
+
+
+int path_join(lua_State* L)
+{
+ int i, len;
+ const char* part;
+ char buffer[0x4000];
+ char* ptr = buffer;
+
+ /* for each argument... */
+ int argc = lua_gettop(L);
+ for (i = 1; i <= argc; ++i) {
+ /* if next argument is nil, skip it */
+ if (lua_isnil(L, i)) {
+ continue;
+ }
+
+ /* grab the next argument */
+ part = luaL_checkstring(L, i);
+ len = strlen(part);
+
+ /* remove trailing slashes */
+ while (len > 1 && part[len - 1] == '/') {
+ --len;
+ }
+
+ /* ignore empty segments and "." */
+ if (len == 0 || (len == 1 && part[0] == '.')) {
+ continue;
+ }
+
+ /* if I encounter an absolute path, restart my result */
+ if (do_isabsolute(part)) {
+ ptr = buffer;
+ }
+
+ /* if the path is already started, split parts */
+ if (ptr != buffer && *(ptr - 1) != '/') {
+ *(ptr++) = '/';
+ }
+
+ /* append new part */
+ strcpy(ptr, part);
+ ptr += len;
+ }
+
+ *ptr = '\0';
+ lua_pushstring(L, buffer);
+ return 1;
+}
diff --git a/src/granger/src/premake/path_normalize.c b/src/granger/src/premake/path_normalize.c
new file mode 100644
index 0000000..64c5cf2
--- /dev/null
+++ b/src/granger/src/premake/path_normalize.c
@@ -0,0 +1,77 @@
+/**
+ * \file path_normalize.c
+ * \brief Removes any weirdness from a file system path string.
+ * \author Copyright (c) 2013 Jason Perkins and the Premake project
+ */
+
+#include "premake.h"
+#include <string.h>
+
+
+int path_normalize(lua_State* L)
+{
+ char buffer[0x4000];
+ char* src;
+ char* dst;
+ char last;
+
+ const char* path = luaL_checkstring(L, 1);
+ strcpy(buffer, path);
+
+ src = buffer;
+ dst = buffer;
+ last = '\0';
+
+ while (*src != '\0') {
+ char ch = (*src);
+
+ /* make sure we're using '/' for all separators */
+ if (ch == '\\') {
+ ch = '/';
+ }
+
+ /* add to the result, filtering out duplicate slashes */
+ if (ch != '/' || last != '/') {
+ *(dst++) = ch;
+ }
+
+ /* ...except at the start of a string, for UNC paths */
+ if (src != buffer) {
+ last = (*src);
+ }
+
+ ++src;
+ }
+
+ /* remove any trailing slashes */
+ for (--src; src > buffer && *src == '/'; --src) {
+ *src = '\0';
+ }
+
+ /* remove any leading "./" sequences */
+ src = buffer;
+ while (strncmp(src, "./", 2) == 0) {
+ src += 2;
+ }
+
+ *dst = '\0';
+ lua_pushstring(L, src);
+ return 1;
+}
+
+
+/* Call the scripted path.normalize(), to allow for overrides */
+void do_normalize(lua_State* L, char* buffer, const char* path)
+{
+ int top = lua_gettop(L);
+
+ lua_getglobal(L, "path");
+ lua_getfield(L, -1, "normalize");
+ lua_pushstring(L, path);
+ lua_call(L, 1, 1);
+
+ path = luaL_checkstring(L, -1);
+ strcpy(buffer, path);
+
+ lua_settop(L, top);
+}
diff --git a/src/granger/src/premake/path_translate.c b/src/granger/src/premake/path_translate.c
new file mode 100644
index 0000000..8996b37
--- /dev/null
+++ b/src/granger/src/premake/path_translate.c
@@ -0,0 +1,61 @@
+/**
+ * \file path_translate.c
+ * \brief Translates between path separators.
+ * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
+ */
+
+#include "premake.h"
+#include <string.h>
+
+
+void do_translate(char* value, const char sep)
+{
+ char* ch;
+ for (ch = value; *ch != '\0'; ++ch) {
+ if (*ch == '/' || *ch == '\\') {
+ *ch = sep;
+ }
+ }
+}
+
+
+static void translate(char* result, const char* value, const char sep)
+{
+ strcpy(result, value);
+ do_translate(result, sep);
+}
+
+
+int path_translate(lua_State* L)
+{
+ const char* sep;
+ char buffer[0x4000];
+
+ if (lua_gettop(L) == 1) {
+ sep = "\\";
+ }
+ else {
+ sep = luaL_checkstring(L, 2);
+ }
+
+ if (lua_istable(L, 1)) {
+ int i = 0;
+ lua_newtable(L);
+ lua_pushnil(L);
+ while (lua_next(L, 1)) {
+ const char* value = luaL_checkstring(L, 4);
+ translate(buffer, value, sep[0]);
+ lua_pop(L, 1);
+
+ lua_pushstring(L, buffer);
+ lua_rawseti(L, -3, ++i);
+ }
+ return 1;
+ }
+ else {
+ const char* value = luaL_checkstring(L, 1);
+ translate(buffer, value, sep[0]);
+ lua_pushstring(L, buffer);
+ return 1;
+ }
+}
diff --git a/src/granger/src/premake/premake.c b/src/granger/src/premake/premake.c
new file mode 100644
index 0000000..19a6168
--- /dev/null
+++ b/src/granger/src/premake/premake.c
@@ -0,0 +1,171 @@
+/**
+ * \file premake.c
+ * \brief Program entry point.
+ * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "premake.h"
+
+#if PLATFORM_MACOSX
+#include <CoreFoundation/CFBundle.h>
+#endif
+
+int premake_locate(lua_State* L, const char* argv0);
+
+/* Built-in functions */
+static const luaL_Reg path_functions[] = {
+ { "getabsolute", path_getabsolute },
+ { "getrelative", path_getrelative },
+ { "isabsolute", path_isabsolute },
+ { "join", path_join },
+ { "normalize", path_normalize },
+ { "translate", path_translate },
+ { NULL, NULL }
+};
+
+static const luaL_Reg os_functions[] = {
+ { "access", os_access },
+ { "chdir", os_chdir },
+ { "copyfile", os_copyfile },
+ { "elevate", os_elevate },
+ { "getcwd", os_getcwd },
+ { "_is64bit", os_is64bit },
+ { "isdir", os_isdir },
+ { "isfile", os_isfile },
+ { "matchdone", os_matchdone },
+ { "matchisfile", os_matchisfile },
+ { "matchname", os_matchname },
+ { "matchnext", os_matchnext },
+ { "matchstart", os_matchstart },
+ { "mkdir", os_mkdir },
+ { "pathsearch", os_pathsearch },
+ { "rmdir", os_rmdir },
+ { "stat", os_stat },
+ { NULL, NULL }
+};
+
+static const luaL_Reg string_functions[] = {
+ { "endswith", string_endswith },
+ { NULL, NULL }
+};
+
+
+/**
+ * Initialize the Premake Lua environment.
+ */
+int premake_init(lua_State* L)
+{
+ if (lua_getglobal(L, "path") != LUA_TTABLE) {
+ lua_pop(L, 1);
+ lua_newtable(L);
+ }
+ luaL_setfuncs(L, path_functions, 0);
+ lua_setglobal(L, "path");
+
+ if (lua_getglobal(L, "os") != LUA_TTABLE) {
+ lua_pop(L, 1);
+ lua_newtable(L);
+ }
+ luaL_setfuncs(L, os_functions, 0);
+ lua_setglobal(L, "os");
+
+ if (lua_getglobal(L, "string") != LUA_TTABLE) {
+ lua_pop(L, 1);
+ lua_newtable(L);
+ }
+ luaL_setfuncs(L, string_functions, 0);
+ lua_setglobal(L, "string");
+
+ lua_pushstring(L, PLATFORM_STRING);
+ lua_setglobal(L, "_OS");
+
+ return OKAY;
+}
+
+/**
+ * Locate the Premake executable, and push its full path to the Lua stack.
+ * Based on:
+ * http://sourceforge.net/tracker/index.php?func=detail&aid=3351583&group_id=71616&atid=531880
+ * http://stackoverflow.com/questions/933850/how-to-find-the-location-of-the-executable-in-c
+ * http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
+ */
+int premake_locate(lua_State* L, const char* argv0)
+{
+#if !defined(PATH_MAX)
+#define PATH_MAX (4096)
+#endif
+
+ char buffer[PATH_MAX];
+ const char* path = NULL;
+
+#if PLATFORM_WINDOWS
+ DWORD len = GetModuleFileName(NULL, buffer, PATH_MAX);
+ if (len > 0)
+ path = buffer;
+#endif
+
+#if PLATFORM_MACOSX
+ CFURLRef bundleURL = CFBundleCopyExecutableURL(CFBundleGetMainBundle());
+ CFStringRef pathRef = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
+ if (CFStringGetCString(pathRef, buffer, PATH_MAX - 1, kCFStringEncodingUTF8))
+ path = buffer;
+#endif
+
+#if PLATFORM_LINUX
+ int len = readlink("/proc/self/exe", buffer, PATH_MAX);
+ if (len > 0)
+ path = buffer;
+#endif
+
+#if PLATFORM_BSD
+ int len = readlink("/proc/curproc/file", buffer, PATH_MAX);
+ if (len < 0)
+ len = readlink("/proc/curproc/exe", buffer, PATH_MAX);
+ if (len > 0)
+ path = buffer;
+#endif
+
+#if PLATFORM_SOLARIS
+ int len = readlink("/proc/self/path/a.out", buffer, PATH_MAX);
+ if (len > 0)
+ path = buffer;
+#endif
+
+ /* As a fallback, search the PATH with argv[0] */
+ if (!path)
+ {
+ lua_pushcfunction(L, os_pathsearch);
+ lua_pushstring(L, argv0);
+ lua_pushstring(L, getenv("PATH"));
+ if (lua_pcall(L, 2, 1, 0) == OKAY && !lua_isnil(L, -1))
+ {
+ lua_pushstring(L, "/");
+ lua_pushstring(L, argv0);
+ lua_concat(L, 3);
+ path = lua_tostring(L, -1);
+ }
+ }
+
+ /* If all else fails, use argv[0] as-is and hope for the best */
+ if (!path)
+ {
+ /* make it absolute, if needed */
+ os_getcwd(L);
+ lua_pushstring(L, "/");
+ lua_pushstring(L, argv0);
+
+ if (!path_isabsolute(L)) {
+ lua_concat(L, 3);
+ }
+ else {
+ lua_pop(L, 1);
+ }
+
+ path = lua_tostring(L, -1);
+ }
+
+ lua_pushstring(L, path);
+ return 1;
+}
diff --git a/src/granger/src/premake/premake.h b/src/granger/src/premake/premake.h
new file mode 100644
index 0000000..c54f162
--- /dev/null
+++ b/src/granger/src/premake/premake.h
@@ -0,0 +1,90 @@
+/**
+ * \file premake.h
+ * \brief Program-wide constants and definitions.
+ * \author Copyright (c) 2002-2011 Jason Perkins and the Premake project
+ */
+
+#define lua_c
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/* Identify the current platform I'm not sure how to reliably detect
+ * Windows but since it is the most common I use it as the default */
+#if defined(__linux__)
+#define PLATFORM_LINUX (1)
+#define PLATFORM_STRING "linux"
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+#define PLATFORM_BSD (1)
+#define PLATFORM_STRING "bsd"
+#elif defined(__APPLE__) && defined(__MACH__)
+#define PLATFORM_MACOSX (1)
+#define PLATFORM_STRING "macosx"
+#elif defined(__sun__) && defined(__svr4__)
+#define PLATFORM_SOLARIS (1)
+#define PLATFORM_STRING "solaris"
+#elif defined(__HAIKU__)
+#define PLATFORM_HAIKU (1)
+#define PLATFORM_STRING "haiku"
+#else
+#define PLATFORM_WINDOWS (1)
+#define PLATFORM_STRING "windows"
+#endif
+
+
+/* Pull in platform-specific headers required by built-in functions */
+#if PLATFORM_WINDOWS
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <shellapi.h>
+#else
+#include <unistd.h>
+#endif
+
+
+/* A success return code */
+#define OKAY (0)
+
+
+/* Bootstrapping helper functions */
+void do_getabsolute(char* result, const char* value, const char* relative_to);
+int do_getcwd(char* buffer, size_t size);
+int do_isabsolute(const char* path);
+int do_isfile(const char* filename);
+void do_normalize(lua_State* L, char* buffer, const char* path);
+void do_translate(char* value, const char sep);
+
+
+/* Built-in functions */
+int path_getabsolute(lua_State* L);
+int path_getrelative(lua_State* L);
+int path_isabsolute(lua_State* L);
+int path_join(lua_State* L);
+int path_normalize(lua_State* L);
+int path_translate(lua_State* L);
+int os_access(lua_State* L);
+int os_chdir(lua_State* L);
+int os_copyfile(lua_State* L);
+int os_elevate(lua_State *L);
+int os_getcwd(lua_State* L);
+int os_getversion(lua_State* L);
+int os_is64bit(lua_State* L);
+int os_isdir(lua_State* L);
+int os_isfile(lua_State* L);
+int os_matchdone(lua_State* L);
+int os_matchisfile(lua_State* L);
+int os_matchname(lua_State* L);
+int os_matchnext(lua_State* L);
+int os_matchstart(lua_State* L);
+int os_mkdir(lua_State* L);
+int os_pathsearch(lua_State* L);
+int os_rmdir(lua_State* L);
+int os_stat(lua_State* L);
+int string_endswith(lua_State* L);
+
+
+/* Engine interface */
+int premake_init(lua_State* L);
+int premake_locate(lua_State* L, const char* argv0);
+
diff --git a/src/granger/src/premake/string_endswith.c b/src/granger/src/premake/string_endswith.c
new file mode 100644
index 0000000..f80cfc1
--- /dev/null
+++ b/src/granger/src/premake/string_endswith.c
@@ -0,0 +1,28 @@
+/**
+ * \file string_endswith.c
+ * \brief Determines if a string ends with the given sequence.
+ * \author Copyright (c) 2002-2009 Jason Perkins and the Premake project
+ */
+
+#include "premake.h"
+#include <string.h>
+
+
+int string_endswith(lua_State* L)
+{
+ const char* haystack = luaL_optstring(L, 1, NULL);
+ const char* needle = luaL_optstring(L, 2, NULL);
+
+ if (haystack && needle)
+ {
+ int hlen = strlen(haystack);
+ int nlen = strlen(needle);
+ if (hlen >= nlen)
+ {
+ lua_pushboolean(L, strcmp(haystack + hlen - nlen, needle) == 0);
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/granger/src/strvec.c b/src/granger/src/strvec.c
new file mode 100644
index 0000000..14681e8
--- /dev/null
+++ b/src/granger/src/strvec.c
@@ -0,0 +1,156 @@
+/****************************************************************************
+ *
+ * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
+ * Copyright (C) 2009-2013 Sourcefire, Inc.
+ * Copyright (C) 2015-2019 GrangerHub
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 3 as
+ * published by the Free Software Foundation. You may not use, modify or
+ * distribute this program under any other version of the GNU General
+ * Public License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "strvec.h"
+
+typedef struct {
+ char** v;
+ unsigned n;
+} StringVector;
+
+void* StringVector_New (void)
+{
+ StringVector* sv = malloc(sizeof(*sv));
+ if ( !sv )
+ return NULL;
+
+ sv->v = malloc(sizeof(*sv->v));
+ if ( !sv->v )
+ {
+ free(sv);
+ return NULL;
+ }
+
+ sv->n = 0;
+ return sv;
+}
+
+void StringVector_Delete (void* pv)
+{
+ unsigned i;
+ StringVector* sv = (StringVector*)pv;
+
+ if ( !sv )
+ return;
+
+ for ( i = 0; i < sv->n; i++ )
+ free(sv->v[i]);
+
+ free(sv->v);
+ free(sv);
+}
+
+int StringVector_Add (void* pv, const char* s)
+{
+ StringVector* sv = (StringVector*)pv;
+ char** v;
+ char* temp;
+
+ if ( !sv || !s )
+ return 0;
+
+ temp = strdup(s);
+ if ( !temp )
+ return 0;
+
+ v = realloc(sv->v, (sv->n+2) * sizeof(char*));
+ if ( !v )
+ return 0;
+
+ sv->v = v;
+ sv->v[sv->n++] = temp;
+ sv->v[sv->n] = NULL;
+
+ return 1;
+}
+
+char* StringVector_Get (void* pv, unsigned index)
+{
+ StringVector* sv = (StringVector*)pv;
+
+ if ( !sv || index >= sv->n )
+ return NULL;
+
+ return sv->v[index];
+}
+
+int StringVector_AddVector (void* pd, void* ps)
+{
+ unsigned i = 0;
+ const char* s = StringVector_Get(ps, i++);
+
+ while ( s )
+ {
+ if ( !StringVector_Add(pd, s) )
+ return 0;
+
+ s = StringVector_Get(ps, i++);
+ }
+ return 1;
+}
+
+const char** StringVector_GetVector (void* pv)
+{
+ StringVector* sv = (StringVector*)pv;
+
+ if ( !sv )
+ return NULL;
+
+ return (const char**)sv->v;
+}
+
+const char* StringVector_toString(void* pv)
+{
+ unsigned i = 0;
+ const char* s = StringVector_Get(pv, i++);
+
+ char* ret = NULL;
+ size_t siz = 0;
+
+ while ( s )
+ {
+ size_t n = siz + strlen(s) + 2;
+ size_t o = n - 1;
+
+ char* _tmp = realloc(ret, n);
+ if ( !_tmp )
+ {
+ free(ret);
+ return NULL;
+ }
+ ret = _tmp;
+
+ memcpy(ret + siz, s, strlen(s));
+ ret[o] = ' ';
+ siz = n;
+
+ s = StringVector_Get(pv, i++);
+ }
+
+ if ( ret && siz )
+ ret[siz-1] = '\0';
+
+ return ret;
+}
diff --git a/src/granger/src/strvec.h b/src/granger/src/strvec.h
new file mode 100644
index 0000000..69bab51
--- /dev/null
+++ b/src/granger/src/strvec.h
@@ -0,0 +1,36 @@
+/****************************************************************************
+ *
+ * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
+ * Copyright (C) 2009-2013 Sourcefire, Inc.
+ * Copyright (C) 2015-2019 GrangerHub
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 3 as
+ * published by the Free Software Foundation. You may not use, modify or
+ * distribute this program under any other version of the GNU General
+ * Public License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+#ifndef _STRVEC_H_
+#define _STRVEC_H_
+
+void* StringVector_New(void);
+void StringVector_Delete(void*);
+
+int StringVector_Add(void*, const char*);
+char* StringVector_Get(void*, unsigned index);
+
+int StringVector_AddVector(void* dst, void* src);
+const char** StringVector_GetVector(void*);
+const char* StringVector_toString(void*);
+
+#endif // _STRVEC_H_
diff --git a/src/granger/test/main.lua b/src/granger/test/main.lua
new file mode 100644
index 0000000..a5f9aee
--- /dev/null
+++ b/src/granger/test/main.lua
@@ -0,0 +1,11 @@
+--
+-- main.lua
+-- test runner
+-- Copyright (c) 2016 Jeff Kent <jeff@jkent.net>
+--
+
+package.path = package.path .. ";../lua/?.lua;../lua/?/init.lua"
+
+require "lib"
+require "test-os-access"
+require "test-nettle"
diff --git a/src/granger/test/test-nettle.lua b/src/granger/test/test-nettle.lua
new file mode 100644
index 0000000..e453a57
--- /dev/null
+++ b/src/granger/test/test-nettle.lua
@@ -0,0 +1,33 @@
+--
+-- test-nettle.lua
+-- test cases for nettle library
+-- Copyright (c) 2016 Jeff Kent <jeff@jkent.net>
+--
+
+print "nettle tests begin"
+
+empty_hash = tostring(nettle.sha256())
+
+ctx = nettle.sha256()
+ctx:update(nil)
+assert(empty_hash == tostring(ctx))
+
+ctx = nettle.sha256()
+ctx:update("Hello World!")
+ctx:update("Hello World!")
+hash = tostring(ctx)
+assert(hash == "95a5a79bf6218dd0938950acb61bca24d5809172fe6cfd7f1af4b059449e52f8")
+
+ctx = nettle.sha256()
+ctx:update("Hello World!Hello World!")
+hash = tostring(ctx)
+assert(hash == "95a5a79bf6218dd0938950acb61bca24d5809172fe6cfd7f1af4b059449e52f8")
+
+require "util"
+hash = md5_file("../COPYING")
+assert(hash == "b234ee4d69f5fce4486a80fdaf4a4263")
+
+hash = sha256_file("../COPYING")
+assert(hash == "8177f97513213526df2cf6184d8ff986c675afb514d4e68a404010521b880643")
+
+print "nettle tests completed"
diff --git a/src/granger/test/test-os-access.lua b/src/granger/test/test-os-access.lua
new file mode 100644
index 0000000..60740c4
--- /dev/null
+++ b/src/granger/test/test-os-access.lua
@@ -0,0 +1,17 @@
+--
+-- test-os-access.lua
+-- test case for os.access()
+-- Copyright (c) 2016 Jeff Kent <jeff@jkent.net>
+--
+
+print "os.access() test begin"
+
+if not os.is("windows") then
+ p = os.tmpname()
+ os.execute("touch " .. p .. "; chmod 400 " .. p)
+ assert(os.access(p, "r") == true)
+ assert(os.access(p, "w") == false)
+ os.execute("rm -f " .. p)
+end
+
+print "os.access() test end"
diff --git a/src/null/null_client.cpp b/src/null/null_client.cpp
new file mode 100644
index 0000000..697780e
--- /dev/null
+++ b/src/null/null_client.cpp
@@ -0,0 +1,95 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "qcommon/cvar.h"
+#include "qcommon/msg.h"
+#include "qcommon/net.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+cvar_t *cl_shownet;
+
+void CL_Shutdown(const char *finalmsg, bool disconnect, bool quit)
+{
+}
+
+void CL_Init( void ) {
+ cl_shownet = Cvar_Get ("cl_shownet", "0", CVAR_TEMP );
+}
+
+void CL_MouseEvent( int dx, int dy, int time ) {
+}
+
+void Key_WriteBindings( fileHandle_t f ) {
+}
+
+void CL_Frame ( int msec ) {
+}
+
+void CL_PacketEvent( struct netadr_t from, struct msg_t *msg ) {
+}
+
+void CL_CharEvent( int key ) {
+}
+
+void CL_Disconnect( bool showMainMenu ) {
+}
+
+void CL_MapLoading( void ) {
+}
+
+bool CL_GameCommand( void ) {
+ return false;
+}
+
+void CL_KeyEvent (int key, bool down, unsigned time) {
+}
+
+bool UI_GameCommand( void ) {
+ return false;
+}
+
+void CL_ForwardCommandToServer( const char *string ) {
+}
+
+void CL_ConsolePrint( const char *txt ) {
+}
+
+void CL_JoystickEvent( int axis, int value, int time ) {
+}
+
+void CL_InitKeyCommands( void ) {
+}
+
+void CL_FlushMemory(void)
+{
+}
+
+void CL_ShutdownAll(bool shutdownRef)
+{
+}
+
+void CL_StartHunkUsers( bool rendererOnly )
+{
+}
diff --git a/src/null/null_glimp.cpp b/src/null/null_glimp.cpp
new file mode 100644
index 0000000..3f9f602
--- /dev/null
+++ b/src/null/null_glimp.cpp
@@ -0,0 +1,63 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "renderercommon/tr_common.h"
+
+qboolean ( * qwglSwapIntervalEXT)( int interval );
+void ( * qglMultiTexCoord2fARB )( GLenum texture, float s, float t );
+void ( * qglActiveTextureARB )( GLenum texture );
+void ( * qglClientActiveTextureARB )( GLenum texture );
+
+
+void ( * qglLockArraysEXT)( int, int);
+void ( * qglUnlockArraysEXT) ( void );
+
+
+void GLimp_EndFrame( void ) {
+}
+
+void GLimp_Init( void ) {
+}
+
+void GLimp_Shutdown( void ) {
+}
+
+void GLimp_EnableLogging( qboolean enable ) {
+}
+
+void GLimp_LogComment( const char *comment ) {
+}
+
+qboolean QGL_Init( const char *dllname ) {
+ return qtrue;
+}
+
+void QGL_Shutdown( void ) {
+}
+
+void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] ) {
+}
+
+void GLimp_Minimize( void ) {
+}
diff --git a/src/null/null_input.cpp b/src/null/null_input.cpp
new file mode 100644
index 0000000..05bfff8
--- /dev/null
+++ b/src/null/null_input.cpp
@@ -0,0 +1,37 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "sys/sys_local.h"
+
+void IN_Init( void ) {
+}
+
+void IN_Frame (void) {
+}
+
+void IN_Shutdown( void ) {
+}
+
+void IN_Restart( void ) {
+}
diff --git a/src/null/null_main.cpp b/src/null/null_main.cpp
new file mode 100644
index 0000000..f30850a
--- /dev/null
+++ b/src/null/null_main.cpp
@@ -0,0 +1,83 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// null_main.c -- null system driver to aid porting efforts
+
+#include <cerrno>
+#include <cstdio>
+
+#include "qcommon/qcommon.h"
+
+int sys_curtime;
+
+
+//===================================================================
+
+
+void Sys_Error (char *error, ...) {
+ va_list argptr;
+
+ printf ("Sys_Error: ");
+ va_start (argptr,error);
+ vprintf (error,argptr);
+ va_end (argptr);
+ printf ("\n");
+
+ exit (1);
+}
+
+void Sys_Quit (void) {
+ exit (0);
+}
+
+char *Sys_GetClipboardData( void ) {
+ return NULL;
+}
+
+int Sys_Milliseconds (void) {
+ return 0;
+}
+
+FILE *Sys_FOpen(const char *ospath, const char *mode) {
+ return fopen( ospath, mode );
+}
+
+void Sys_Mkdir (char *path) {
+}
+
+bool Sys_OpenWithDefault( const char *path )
+{
+ return false;
+}
+
+void Sys_Init (void) {
+}
+
+
+void main (int argc, char **argv) {
+ Com_Init (argc, argv);
+
+ while (1) {
+ Com_Frame( );
+ }
+}
diff --git a/src/null/null_net.cpp b/src/null/null_net.cpp
new file mode 100644
index 0000000..97b2d9c
--- /dev/null
+++ b/src/null/null_net.cpp
@@ -0,0 +1,55 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "qcommon/qcommon.h"
+
+/*
+=============
+NET_StringToAdr
+
+localhost
+idnewt
+idnewt:28000
+192.246.40.70
+192.246.40.70:28000
+=============
+*/
+qboolean NET_StringToAdr (char *s, netadr_t *a)
+{
+ if (!strcmp (s, "localhost")) {
+ memset (a, 0, sizeof(*a));
+ a->type = NA_LOOPBACK;
+ return true;
+ }
+
+ return false;
+}
+
+/*
+==================
+Sys_SendPacket
+==================
+*/
+void Sys_SendPacket( int length, void *data, netadr_t to ) {
+}
diff --git a/src/null/null_snddma.cpp b/src/null/null_snddma.cpp
new file mode 100644
index 0000000..d77899b
--- /dev/null
+++ b/src/null/null_snddma.cpp
@@ -0,0 +1,62 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// snddma_null.c
+// all other sound mixing is portable
+
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+bool SNDDMA_Init(void)
+{
+ return false;
+}
+
+int SNDDMA_GetDMAPos(void)
+{
+ return 0;
+}
+
+void SNDDMA_Shutdown(void)
+{
+}
+
+void SNDDMA_BeginPainting (void)
+{
+}
+
+void SNDDMA_Submit(void)
+{
+}
+
+sfxHandle_t S_RegisterSound( const char *name, bool compressed )
+{
+ return 0;
+}
+
+void S_StartLocalSound( sfxHandle_t sfxHandle, int channelNum ) {
+}
+
+void S_ClearSoundBuffer( void ) {
+}
diff --git a/src/qcommon/CMakeLists.txt b/src/qcommon/CMakeLists.txt
new file mode 100644
index 0000000..493dfa4
--- /dev/null
+++ b/src/qcommon/CMakeLists.txt
@@ -0,0 +1,54 @@
+add_library (
+ common STATIC
+ cm_load.c
+ cm_local.h
+ cm_patch.c
+ cm_patch.h
+ cm_polylib.c
+ cm_polylib.h
+ cm_public.h
+ cm_test.c
+ cm_trace.c
+ cmd.cpp
+ common.c
+ cvar.cpp
+ dialog.h
+ files.c
+ huffman.c
+ ioapi.c
+ ioapi.h
+ json.h
+ md4.c
+ md5.c
+ msg.c
+ net_chan.c
+ net_ip.c
+ parse.c
+ puff.c
+ puff.h
+ q3_lauxlib.cpp
+ q3_lauxlib.h
+ q_math.c
+ q_platform.h
+ q_shared.c
+ q_shared.h
+ qcommon.h
+ qfiles.h
+ surfaceflags.h
+ unzip.c
+ unzip.h
+ vm.c
+ vm_interpreted.c
+ vm_local.h
+ vm_none.c
+ vm_powerpc.c
+ vm_powerpc_asm.c
+ vm_powerpc_asm.h
+ vm_sparc.c
+ vm_sparc.h
+ vm_x86.c
+)
+
+include_directories( ${RESTCLIENT_INCLUDES_DIR} )
+
+set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14" )
diff --git a/src/qcommon/alternatePlayerstate.h b/src/qcommon/alternatePlayerstate.h
new file mode 100644
index 0000000..a35778b
--- /dev/null
+++ b/src/qcommon/alternatePlayerstate.h
@@ -0,0 +1,75 @@
+#ifndef QCOMMON_ALTERNATEPLAYERSTATE_H
+#define QCOMMON_ALTERNATEPLAYERSTATE_H 1
+
+#include "q_shared.h"
+
+struct alternatePlayerState_t {
+ int commandTime; // cmd->serverTime of last executed command
+ int pm_type;
+ int bobCycle; // for view bobbing and footstep generation
+ int pm_flags; // ducked, jump_held, etc
+ int pm_time;
+
+ vec3_t origin;
+ vec3_t velocity;
+ int weaponTime;
+ int gravity;
+ int speed;
+ int delta_angles[3]; // add to command angles to get view direction
+ // changed by spawns, rotating objects, and teleporters
+
+ int groundEntityNum; // ENTITYNUM_NONE = in air
+
+ int legsTimer; // don't change low priority animations until this runs out
+ int legsAnim; // mask off ANIM_TOGGLEBIT
+
+ int torsoTimer; // don't change low priority animations until this runs out
+ int torsoAnim; // mask off ANIM_TOGGLEBIT
+
+ int movementDir; // a number 0 to 7 that represents the relative angle
+ // of movement to the view angle (axial and diagonals)
+ // when at rest, the value will remain unchanged
+ // used to twist the legs during strafing
+
+ vec3_t grapplePoint; // location of grapple to pull towards if PMF_GRAPPLE_PULL
+
+ int eFlags; // copied to entityState_t->eFlags
+
+ int eventSequence; // pmove generated events
+ int events[MAX_PS_EVENTS];
+ int eventParms[MAX_PS_EVENTS];
+
+ int externalEvent; // events set on player from another source
+ int externalEventParm;
+ int externalEventTime;
+
+ int clientNum; // ranges from 0 to MAX_CLIENTS-1
+ int weapon; // copied to entityState_t->weapon
+ int weaponstate;
+
+ vec3_t viewangles; // for fixed views
+ int viewheight;
+
+ // damage feedback
+ int damageEvent; // when it changes, latch the other parms
+ int damageYaw;
+ int damagePitch;
+ int damageCount;
+
+ int stats[MAX_STATS];
+ int persistant[MAX_PERSISTANT]; // stats that aren't cleared on death
+ int misc[MAX_MISC]; // misc data
+ int ammo[MAX_WEAPONS];
+
+ int generic1;
+ int loopSound;
+ int otherEntityNum;
+
+ // not communicated over the net at all
+ int ping; // server to game info for scoreboard
+ int pmove_framecount;
+ int jumppad_frame;
+ int entityEventSequence;
+};
+
+#endif
diff --git a/src/qcommon/cdefs.h b/src/qcommon/cdefs.h
new file mode 100644
index 0000000..327c244
--- /dev/null
+++ b/src/qcommon/cdefs.h
@@ -0,0 +1,79 @@
+/* Copyright (c) 2010-2012, Victor J. Roemer. 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. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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.
+ */
+#ifndef __CDEFS_H__
+#define __CDEFS_H__
+
+#define UNUSED __attribute__((unused))
+
+#define NORETURN __attribute__((noreturn))
+
+/* Support for flexible arrays, stolen from dnet */
+#undef __flexarr
+#if defined(__GNUC__) && ((__GNUC__ > 2) || \
+ (__GNUC__ == 2 && __GNUC_MINOR__ >= 97))
+
+/* GCC 2.97 supports C99 flexible array members. */
+# define __flexarr []
+#else
+# ifdef __GNUC__
+# define __flexarr [0]
+# else
+# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+# define __flexarr []
+# elif defined(_WIN32)
+/* MS VC++ */
+# define __flexarr []
+# else
+/* Some other non-C99 compiler. Approximate with [1]. */
+# define __flexarr [1]
+# endif
+# endif
+#endif
+
+#ifndef SO_PUBLIC
+#if defined _WIN32 || defined __CYGWIN__
+# ifdef __GNUC__
+# define SO_PUBLIC __attribute__((dllimport))
+# else
+# define SO_PUBLIC __declspec(dllimport)
+# endif
+# define DLL_LOCAL
+#else
+# ifdef HAVE_VISIBILITY
+# define SO_PUBLIC __attribute__ ((visibility("default")))
+# define SO_PRIVATE __attribute__ ((visibility("hidden")))
+# else
+# define SO_PUBLIC
+# define SO_PRIVATE
+# endif
+#endif
+#endif
+
+#endif
diff --git a/src/qcommon/cm_load.cpp b/src/qcommon/cm_load.cpp
new file mode 100644
index 0000000..0ce0606
--- /dev/null
+++ b/src/qcommon/cm_load.cpp
@@ -0,0 +1,1022 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// cmodel.c -- model loading
+
+#include "cm_local.h"
+#include "files.h"
+#include "md4.h"
+
+#ifdef BSPC
+
+#include "../bspc/l_qfiles.h"
+
+void SetPlaneSignbits (cplane_t *out) {
+ int bits, j;
+
+ // for fast box on planeside test
+ bits = 0;
+ for (j=0 ; j<3 ; j++) {
+ if (out->normal[j] < 0) {
+ bits |= 1<<j;
+ }
+ }
+ out->signbits = bits;
+}
+#endif //BSPC
+
+// to allow boxes to be treated as brush models, we allocate
+// some extra indexes along with those needed by the map
+#define BOX_BRUSHES 1
+#define BOX_SIDES 6
+#define BOX_LEAFS 2
+#define BOX_PLANES 12
+
+#define LL(x) x=LittleLong(x)
+
+
+clipMap_t cm;
+int c_pointcontents;
+int c_traces, c_brush_traces, c_patch_traces;
+
+
+byte *cmod_base;
+
+#ifndef BSPC
+cvar_t *cm_noAreas;
+cvar_t *cm_noCurves;
+cvar_t *cm_playerCurveClip;
+#endif
+
+cmodel_t box_model;
+cplane_t *box_planes;
+cbrush_t *box_brush;
+
+
+
+void CM_InitBoxHull (void);
+
+
+/*
+===============================================================================
+
+ MAP LOADING
+
+===============================================================================
+*/
+
+/*
+=================
+CMod_LoadShaders
+=================
+*/
+void CMod_LoadShaders( lump_t *l ) {
+ dshader_t *in, *out;
+ int i, count;
+
+ in = (dshader_t *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in)) {
+ Com_Error (ERR_DROP, "CMod_LoadShaders: funny lump size");
+ }
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1) {
+ Com_Error (ERR_DROP, "Map with no shaders");
+ }
+ cm.shaders = (dshader_t*)Hunk_Alloc( count * sizeof( *cm.shaders ), h_high );
+ cm.numShaders = count;
+
+ ::memcpy( cm.shaders, in, count * sizeof( *cm.shaders ) );
+
+ out = cm.shaders;
+ for ( i=0 ; i<count ; i++, in++, out++ ) {
+ out->contentFlags = LittleLong( out->contentFlags );
+ out->surfaceFlags = LittleLong( out->surfaceFlags );
+ }
+}
+
+
+/*
+=================
+CMod_LoadSubmodels
+=================
+*/
+void CMod_LoadSubmodels( lump_t *l ) {
+ dmodel_t *in;
+ cmodel_t *out;
+ int i, j, count;
+ int *indexes;
+
+ in = (dmodel_t *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "CMod_LoadSubmodels: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no models");
+ cm.cmodels = (cmodel_t*)Hunk_Alloc( count * sizeof( *cm.cmodels ), h_high );
+ cm.numSubModels = count;
+
+ if ( count > MAX_SUBMODELS ) {
+ Com_Error( ERR_DROP, "MAX_SUBMODELS exceeded" );
+ }
+
+ for ( i=0 ; i<count ; i++, in++)
+ {
+ out = &cm.cmodels[i];
+
+ for (j=0 ; j<3 ; j++)
+ { // spread the mins / maxs by a pixel
+ out->mins[j] = LittleFloat (in->mins[j]) - 1;
+ out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
+ }
+
+ if ( i == 0 ) {
+ continue; // world model doesn't need other info
+ }
+
+ // make a "leaf" just to hold the model's brushes and surfaces
+ out->leaf.numLeafBrushes = LittleLong( in->numBrushes );
+ indexes = (int*)Hunk_Alloc( out->leaf.numLeafBrushes * 4, h_high );
+ out->leaf.firstLeafBrush = indexes - cm.leafbrushes;
+ for ( j = 0 ; j < out->leaf.numLeafBrushes ; j++ ) {
+ indexes[j] = LittleLong( in->firstBrush ) + j;
+ }
+
+ out->leaf.numLeafSurfaces = LittleLong( in->numSurfaces );
+ indexes = (int*)Hunk_Alloc( out->leaf.numLeafSurfaces * 4, h_high );
+ out->leaf.firstLeafSurface = indexes - cm.leafsurfaces;
+ for ( j = 0 ; j < out->leaf.numLeafSurfaces ; j++ ) {
+ indexes[j] = LittleLong( in->firstSurface ) + j;
+ }
+ }
+}
+
+
+/*
+=================
+CMod_LoadNodes
+
+=================
+*/
+void CMod_LoadNodes( lump_t *l ) {
+ dnode_t *in;
+ int child;
+ cNode_t *out;
+ int count;
+
+ in = (dnode_t *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map has no nodes");
+
+ cm.nodes = (cNode_t*)Hunk_Alloc( count * sizeof( *cm.nodes ), h_high );
+ cm.numNodes = count;
+
+ out = cm.nodes;
+
+ for (int i=0 ; i<count ; i++, out++, in++)
+ {
+ out->plane = cm.planes + LittleLong( in->planeNum );
+ for (int j=0 ; j<2 ; j++)
+ {
+ child = LittleLong (in->children[j]);
+ out->children[j] = child;
+ }
+ }
+
+}
+
+/*
+=================
+CM_BoundBrush
+
+=================
+*/
+void CM_BoundBrush( cbrush_t *b ) {
+ b->bounds[0][0] = -b->sides[0].plane->dist;
+ b->bounds[1][0] = b->sides[1].plane->dist;
+
+ b->bounds[0][1] = -b->sides[2].plane->dist;
+ b->bounds[1][1] = b->sides[3].plane->dist;
+
+ b->bounds[0][2] = -b->sides[4].plane->dist;
+ b->bounds[1][2] = b->sides[5].plane->dist;
+}
+
+
+/*
+=================
+CMod_LoadBrushes
+
+=================
+*/
+void CMod_LoadBrushes( lump_t *l ) {
+ dbrush_t *in;
+ cbrush_t *out;
+ int count;
+
+ in = (dbrush_t *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in)) {
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ }
+ count = l->filelen / sizeof(*in);
+
+ cm.brushes = (cbrush_t*)Hunk_Alloc( ( BOX_BRUSHES + count ) * sizeof( *cm.brushes ), h_high );
+ cm.numBrushes = count;
+
+ out = cm.brushes;
+
+ for ( int i = 0 ; i<count ; i++, out++, in++ ) {
+ out->sides = cm.brushsides + LittleLong(in->firstSide);
+ out->numsides = LittleLong(in->numSides);
+
+ out->shaderNum = LittleLong( in->shaderNum );
+ if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {
+ Com_Error( ERR_DROP, "CMod_LoadBrushes: bad shaderNum: %i", out->shaderNum );
+ }
+ out->contents = cm.shaders[out->shaderNum].contentFlags;
+
+ CM_BoundBrush( out );
+ }
+
+}
+
+/*
+=================
+CMod_LoadLeafs
+=================
+*/
+void CMod_LoadLeafs (lump_t *l)
+{
+ cLeaf_t *out;
+ dleaf_t *in;
+ int count;
+
+ in = (dleaf_t *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no leafs");
+
+ cm.leafs = (cLeaf_t*)Hunk_Alloc( ( BOX_LEAFS + count ) * sizeof( *cm.leafs ), h_high );
+ cm.numLeafs = count;
+
+ out = cm.leafs;
+ for ( int i = 0 ; i<count ; i++, in++, out++)
+ {
+ out->cluster = LittleLong (in->cluster);
+ out->area = LittleLong (in->area);
+ out->firstLeafBrush = LittleLong (in->firstLeafBrush);
+ out->numLeafBrushes = LittleLong (in->numLeafBrushes);
+ out->firstLeafSurface = LittleLong (in->firstLeafSurface);
+ out->numLeafSurfaces = LittleLong (in->numLeafSurfaces);
+
+ if (out->cluster >= cm.numClusters)
+ cm.numClusters = out->cluster + 1;
+ if (out->area >= cm.numAreas)
+ cm.numAreas = out->area + 1;
+ }
+
+ cm.areas = (cArea_t*)Hunk_Alloc( cm.numAreas * sizeof( *cm.areas ), h_high );
+ cm.areaPortals = (int*)Hunk_Alloc( cm.numAreas * cm.numAreas * sizeof( *cm.areaPortals ), h_high );
+}
+
+/*
+=================
+CMod_LoadPlanes
+=================
+*/
+void CMod_LoadPlanes (lump_t *l)
+{
+ cplane_t *out;
+ dplane_t *in;
+ int count;
+ int bits;
+
+ in = (dplane_t*)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no planes");
+ cm.planes = (cplane_t*)Hunk_Alloc( ( BOX_PLANES + count ) * sizeof( *cm.planes ), h_high );
+ cm.numPlanes = count;
+
+ out = cm.planes;
+
+ for ( int i = 0 ; i<count ; i++, in++, out++)
+ {
+ bits = 0;
+ for (int j = 0 ; j<3 ; j++)
+ {
+ out->normal[j] = LittleFloat (in->normal[j]);
+ if (out->normal[j] < 0)
+ bits |= 1<<j;
+ }
+
+ out->dist = LittleFloat (in->dist);
+ out->type = PlaneTypeForNormal( out->normal );
+ out->signbits = bits;
+ }
+}
+
+/*
+=================
+CMod_LoadLeafBrushes
+=================
+*/
+void CMod_LoadLeafBrushes (lump_t *l)
+{
+ int *out;
+ int *in;
+ int count;
+
+ in = (int*)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ cm.leafbrushes = (int*)Hunk_Alloc( (count + BOX_BRUSHES) * sizeof( *cm.leafbrushes ), h_high );
+ cm.numLeafBrushes = count;
+
+ out = cm.leafbrushes;
+
+ for ( int i=0 ; i<count ; i++, in++, out++)
+ {
+ *out = LittleLong (*in);
+ }
+}
+
+/*
+=================
+CMod_LoadLeafSurfaces
+=================
+*/
+void CMod_LoadLeafSurfaces( lump_t *l )
+{
+ int *out;
+ int *in;
+ int count;
+
+ in = (int*)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ cm.leafsurfaces = (int*)Hunk_Alloc( count * sizeof( *cm.leafsurfaces ), h_high );
+ cm.numLeafSurfaces = count;
+
+ out = cm.leafsurfaces;
+
+ for ( int i = 0 ; i<count ; i++, in++, out++)
+ {
+ *out = LittleLong (*in);
+ }
+}
+
+/*
+=================
+CMod_LoadBrushSides
+=================
+*/
+void CMod_LoadBrushSides (lump_t *l)
+{
+ int i;
+ cbrushside_t *out;
+ dbrushside_t *in;
+ int count;
+ int num;
+
+ in = (dbrushside_t *)(cmod_base + l->fileofs);
+ if ( l->filelen % sizeof(*in) ) {
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ }
+ count = l->filelen / sizeof(*in);
+
+ cm.brushsides = (cbrushside_t*)Hunk_Alloc( ( BOX_SIDES + count ) * sizeof( *cm.brushsides ), h_high );
+ cm.numBrushSides = count;
+
+ out = cm.brushsides;
+
+ for ( i=0 ; i<count ; i++, in++, out++) {
+ num = LittleLong( in->planeNum );
+ out->planeNum = num;
+ out->plane = &cm.planes[num];
+ out->shaderNum = LittleLong( in->shaderNum );
+ if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {
+ Com_Error( ERR_DROP, "CMod_LoadBrushSides: bad shaderNum: %i", out->shaderNum );
+ }
+ out->surfaceFlags = cm.shaders[out->shaderNum].surfaceFlags;
+ }
+}
+
+#define CM_EDGE_VERTEX_EPSILON 0.1f
+
+/*
+=================
+CMod_BrushEdgesAreTheSame
+=================
+*/
+static bool CMod_BrushEdgesAreTheSame( const vec3_t p0, const vec3_t p1,
+ const vec3_t q0, const vec3_t q1 )
+{
+ if( VectorCompareEpsilon( p0, q0, CM_EDGE_VERTEX_EPSILON ) &&
+ VectorCompareEpsilon( p1, q1, CM_EDGE_VERTEX_EPSILON ) )
+ return true;
+
+ if( VectorCompareEpsilon( p1, q0, CM_EDGE_VERTEX_EPSILON ) &&
+ VectorCompareEpsilon( p0, q1, CM_EDGE_VERTEX_EPSILON ) )
+ return true;
+
+ return false;
+}
+
+/*
+=================
+CMod_AddEdgeToBrush
+=================
+*/
+static bool CMod_AddEdgeToBrush( const vec3_t p0, const vec3_t p1,
+ cbrushedge_t *edges, int *numEdges )
+{
+ int i;
+
+ if( !edges || !numEdges )
+ return false;
+
+ for( i = 0; i < *numEdges; i++ )
+ {
+ if( CMod_BrushEdgesAreTheSame( p0, p1,
+ edges[ i ].p0, edges[ i ].p1 ) )
+ return false;
+ }
+
+ VectorCopy( p0, edges[ *numEdges ].p0 );
+ VectorCopy( p1, edges[ *numEdges ].p1 );
+ (*numEdges)++;
+
+ return true;
+}
+
+/*
+=================
+CMod_CreateBrushSideWindings
+=================
+*/
+static void CMod_CreateBrushSideWindings( void )
+{
+ int i, j, k;
+ winding_t *w;
+ cbrushside_t *side, *chopSide;
+ cplane_t *plane;
+ cbrush_t *brush;
+ cbrushedge_t *tempEdges;
+ int numEdges;
+ int edgesAlloc;
+ int totalEdgesAlloc = 0;
+ int totalEdges = 0;
+
+ for( i = 0; i < cm.numBrushes; i++ )
+ {
+ brush = &cm.brushes[ i ];
+ numEdges = 0;
+
+ // walk the list of brush sides
+ for( j = 0; j < brush->numsides; j++ )
+ {
+ // get side and plane
+ side = &brush->sides[ j ];
+ plane = side->plane;
+
+ w = BaseWindingForPlane( plane->normal, plane->dist );
+
+ // walk the list of brush sides
+ for( k = 0; k < brush->numsides && w != NULL; k++ )
+ {
+ chopSide = &brush->sides[ k ];
+
+ if( chopSide == side )
+ continue;
+
+ if( chopSide->planeNum == ( side->planeNum ^ 1 ) )
+ continue; // back side clipaway
+
+ plane = &cm.planes[ chopSide->planeNum ^ 1 ];
+ ChopWindingInPlace( &w, plane->normal, plane->dist, 0 );
+ }
+
+ if( w )
+ numEdges += w->numpoints;
+
+ // set side winding
+ side->winding = w;
+ }
+
+ // Allocate a temporary buffer of the maximal size
+ tempEdges = (cbrushedge_t *)Z_Malloc( sizeof( cbrushedge_t ) * numEdges );
+ brush->numEdges = 0;
+
+ // compose the points into edges
+ for( j = 0; j < brush->numsides; j++ )
+ {
+ side = &brush->sides[ j ];
+
+ if( side->winding )
+ {
+ for( k = 0; k < side->winding->numpoints - 1; k++ )
+ {
+ if( brush->numEdges == numEdges )
+ Com_Error( ERR_FATAL,
+ "Insufficient memory allocated for collision map edges" );
+
+ CMod_AddEdgeToBrush( side->winding->p[ k ],
+ side->winding->p[ k + 1 ], tempEdges, &brush->numEdges );
+ }
+
+ FreeWinding( side->winding );
+ side->winding = NULL;
+ }
+ }
+
+ // Allocate a buffer of the actual size
+ edgesAlloc = sizeof( cbrushedge_t ) * brush->numEdges;
+ totalEdgesAlloc += edgesAlloc;
+ brush->edges = (cbrushedge_t *)Hunk_Alloc( edgesAlloc, h_low );
+
+ // Copy temporary buffer to permanent buffer
+ ::memcpy( brush->edges, tempEdges, edgesAlloc );
+
+ // Free temporary buffer
+ Z_Free( tempEdges );
+
+ totalEdges += brush->numEdges;
+ }
+
+ Com_DPrintf( "Allocated %d bytes for %d collision map edges...\n",
+ totalEdgesAlloc, totalEdges );
+}
+
+/*
+=================
+CMod_LoadEntityString
+=================
+*/
+void CMod_LoadEntityString( lump_t *l ) {
+ cm.entityString = (char*)Hunk_Alloc( l->filelen, h_high );
+ cm.numEntityChars = l->filelen;
+ ::memcpy (cm.entityString, cmod_base + l->fileofs, l->filelen);
+}
+
+/*
+=================
+CMod_LoadVisibility
+=================
+*/
+#define VIS_HEADER 8
+void CMod_LoadVisibility( lump_t *l ) {
+ int len;
+ byte *buf;
+
+ len = l->filelen;
+ if ( !len ) {
+ cm.clusterBytes = ( cm.numClusters + 31 ) & ~31;
+ cm.visibility = (byte*)Hunk_Alloc( cm.clusterBytes, h_high );
+ ::memset( cm.visibility, 255, cm.clusterBytes );
+ return;
+ }
+ buf = cmod_base + l->fileofs;
+
+ cm.vised = true;
+ cm.visibility = (byte*)Hunk_Alloc( len, h_high );
+ cm.numClusters = LittleLong( ((int *)buf)[0] );
+ cm.clusterBytes = LittleLong( ((int *)buf)[1] );
+ ::memcpy (cm.visibility, buf + VIS_HEADER, len - VIS_HEADER );
+}
+
+//==================================================================
+
+
+/*
+=================
+CMod_LoadPatches
+=================
+*/
+#define MAX_PATCH_VERTS 1024
+void CMod_LoadPatches( lump_t *surfs, lump_t *verts ) {
+ drawVert_t *dv, *dv_p;
+ dsurface_t *in;
+ int count;
+ int i, j;
+ int c;
+ cPatch_t *patch;
+ vec3_t points[MAX_PATCH_VERTS];
+ int width, height;
+ int shaderNum;
+
+ in = (dsurface_t *)(cmod_base + surfs->fileofs);
+ if (surfs->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ cm.numSurfaces = count = surfs->filelen / sizeof(*in);
+ cm.surfaces = (cPatch_t**)Hunk_Alloc( cm.numSurfaces * sizeof( cm.surfaces[0] ), h_high );
+
+ dv = (drawVert_t *)(cmod_base + verts->fileofs);
+ if (verts->filelen % sizeof(*dv))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+
+ // scan through all the surfaces, but only load patches,
+ // not planar faces
+ for ( i = 0 ; i < count ; i++, in++ ) {
+ if ( LittleLong( in->surfaceType ) != MST_PATCH ) {
+ continue; // ignore other surfaces
+ }
+ // FIXME: check for non-colliding patches
+
+ cm.surfaces[ i ] = patch = (cPatch_t*)Hunk_Alloc( sizeof( *patch ), h_high );
+
+ // load the full drawverts onto the stack
+ width = LittleLong( in->patchWidth );
+ height = LittleLong( in->patchHeight );
+ c = width * height;
+ if ( c > MAX_PATCH_VERTS ) {
+ Com_Error( ERR_DROP, "ParseMesh: MAX_PATCH_VERTS" );
+ }
+
+ dv_p = dv + LittleLong( in->firstVert );
+ for ( j = 0 ; j < c ; j++, dv_p++ ) {
+ points[j][0] = LittleFloat( dv_p->xyz[0] );
+ points[j][1] = LittleFloat( dv_p->xyz[1] );
+ points[j][2] = LittleFloat( dv_p->xyz[2] );
+ }
+
+ shaderNum = LittleLong( in->shaderNum );
+ patch->contents = cm.shaders[shaderNum].contentFlags;
+ patch->surfaceFlags = cm.shaders[shaderNum].surfaceFlags;
+
+ // create the internal facet structure
+ patch->pc = CM_GeneratePatchCollide( width, height, points );
+ }
+}
+
+//==================================================================
+
+unsigned CM_LumpChecksum(lump_t *lump) {
+ return LittleLong (Com_BlockChecksum (cmod_base + lump->fileofs, lump->filelen));
+}
+
+unsigned CM_Checksum(dheader_t *header) {
+ unsigned checksums[16];
+ checksums[0] = CM_LumpChecksum(&header->lumps[LUMP_SHADERS]);
+ checksums[1] = CM_LumpChecksum(&header->lumps[LUMP_LEAFS]);
+ checksums[2] = CM_LumpChecksum(&header->lumps[LUMP_LEAFBRUSHES]);
+ checksums[3] = CM_LumpChecksum(&header->lumps[LUMP_LEAFSURFACES]);
+ checksums[4] = CM_LumpChecksum(&header->lumps[LUMP_PLANES]);
+ checksums[5] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHSIDES]);
+ checksums[6] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHES]);
+ checksums[7] = CM_LumpChecksum(&header->lumps[LUMP_MODELS]);
+ checksums[8] = CM_LumpChecksum(&header->lumps[LUMP_NODES]);
+ checksums[9] = CM_LumpChecksum(&header->lumps[LUMP_SURFACES]);
+ checksums[10] = CM_LumpChecksum(&header->lumps[LUMP_DRAWVERTS]);
+
+ return LittleLong(Com_BlockChecksum(checksums, 11 * 4));
+}
+
+/*
+==================
+CM_LoadMap
+
+Loads in the map and all submodels
+==================
+*/
+void CM_LoadMap( const char *name, bool clientload, int *checksum ) {
+ union {
+ int *i;
+ void *v;
+ } buf;
+ dheader_t header;
+ int length;
+ static unsigned last_checksum;
+
+ if ( !name || !name[0] ) {
+ Com_Error( ERR_DROP, "CM_LoadMap: NULL name" );
+ }
+
+#ifndef BSPC
+ cm_noAreas = Cvar_Get ("cm_noAreas", "0", CVAR_CHEAT);
+ cm_noCurves = Cvar_Get ("cm_noCurves", "0", CVAR_CHEAT);
+ cm_playerCurveClip = Cvar_Get ("cm_playerCurveClip", "1", CVAR_ARCHIVE|CVAR_CHEAT );
+#endif
+ Com_DPrintf( "CM_LoadMap( %s, %i )\n", name, clientload );
+
+ if ( !strcmp( cm.name, name ) && clientload ) {
+ *checksum = last_checksum;
+ return;
+ }
+
+ // free old stuff
+ ::memset( &cm, 0, sizeof( cm ) );
+ CM_ClearLevelPatches();
+
+ if ( !name[0] ) {
+ cm.numLeafs = 1;
+ cm.numClusters = 1;
+ cm.numAreas = 1;
+ cm.cmodels = (cmodel_t*)Hunk_Alloc( sizeof( *cm.cmodels ), h_high );
+ *checksum = 0;
+ return;
+ }
+
+ //
+ // load the file
+ //
+#ifndef BSPC
+ length = FS_ReadFile( name, &buf.v );
+#else
+ length = LoadQuakeFile((quakefile_t *) name, &buf.v);
+#endif
+
+ if ( !buf.i ) {
+ Com_Error (ERR_DROP, "Couldn't load %s", name);
+ }
+
+ last_checksum = LittleLong (Com_BlockChecksum (buf.i, length));
+ *checksum = last_checksum;
+
+ header = *(dheader_t *)buf.i;
+ for (size_t i = 0 ; i<sizeof(dheader_t)/4 ; i++) {
+ ((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
+ }
+
+ if ( header.version != BSP_VERSION ) {
+ Com_Error (ERR_DROP, "CM_LoadMap: %s has wrong version number (%i should be %i)"
+ , name, header.version, BSP_VERSION );
+ }
+
+ cmod_base = (byte *)buf.i;
+
+ // load into heap
+ CMod_LoadShaders( &header.lumps[LUMP_SHADERS] );
+ CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
+ CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
+ CMod_LoadLeafSurfaces (&header.lumps[LUMP_LEAFSURFACES]);
+ CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
+ CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
+ CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
+ CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
+ CMod_LoadNodes (&header.lumps[LUMP_NODES]);
+ CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
+ CMod_LoadVisibility( &header.lumps[LUMP_VISIBILITY] );
+ CMod_LoadPatches( &header.lumps[LUMP_SURFACES], &header.lumps[LUMP_DRAWVERTS] );
+
+ CMod_CreateBrushSideWindings( );
+
+ // we are NOT freeing the file, because it is cached for the ref
+ FS_FreeFile (buf.v);
+
+ CM_InitBoxHull ();
+
+ CM_FloodAreaConnections ();
+
+ // allow this to be cached if it is loaded by the server
+ if ( !clientload ) {
+ Q_strncpyz( cm.name, name, sizeof( cm.name ) );
+ }
+}
+
+/*
+==================
+CM_ClearMap
+==================
+*/
+void CM_ClearMap( void ) {
+ ::memset( &cm, 0, sizeof( cm ) );
+ CM_ClearLevelPatches();
+}
+
+/*
+==================
+CM_ClipHandleToModel
+==================
+*/
+cmodel_t *CM_ClipHandleToModel( clipHandle_t handle ) {
+ if ( handle < 0 ) {
+ Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle );
+ }
+ if ( handle < cm.numSubModels ) {
+ return &cm.cmodels[handle];
+ }
+ if ( handle == BOX_MODEL_HANDLE ) {
+ return &box_model;
+ }
+ if ( handle < MAX_SUBMODELS ) {
+ Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i < %i < %i",
+ cm.numSubModels, handle, MAX_SUBMODELS );
+ }
+ Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle + MAX_SUBMODELS );
+
+ return NULL;
+
+}
+
+/*
+==================
+CM_InlineModel
+==================
+*/
+clipHandle_t CM_InlineModel( int index ) {
+ if ( index < 0 || index >= cm.numSubModels ) {
+ Com_Error (ERR_DROP, "CM_InlineModel: bad number");
+ }
+ return index;
+}
+
+int CM_NumClusters( void ) {
+ return cm.numClusters;
+}
+
+int CM_NumInlineModels( void ) {
+ return cm.numSubModels;
+}
+
+char *CM_EntityString( void ) {
+ return cm.entityString;
+}
+
+int CM_LeafCluster( int leafnum ) {
+ if (leafnum < 0 || leafnum >= cm.numLeafs) {
+ Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
+ }
+ return cm.leafs[leafnum].cluster;
+}
+
+int CM_LeafArea( int leafnum ) {
+ if ( leafnum < 0 || leafnum >= cm.numLeafs ) {
+ Com_Error (ERR_DROP, "CM_LeafArea: bad number");
+ }
+ return cm.leafs[leafnum].area;
+}
+
+//=======================================================================
+
+
+/*
+===================
+CM_InitBoxHull
+
+Set up the planes and nodes so that the six floats of a bounding box
+can just be stored out and get a proper clipping hull structure.
+===================
+*/
+void CM_InitBoxHull (void)
+{
+ int i;
+ int side;
+ cplane_t *p;
+ cbrushside_t *s;
+
+ box_planes = &cm.planes[cm.numPlanes];
+
+ box_brush = &cm.brushes[cm.numBrushes];
+ box_brush->numsides = 6;
+ box_brush->sides = cm.brushsides + cm.numBrushSides;
+ box_brush->contents = CONTENTS_BODY;
+ box_brush->edges = (cbrushedge_t *)Hunk_Alloc(
+ sizeof( cbrushedge_t ) * 12, h_low );
+ box_brush->numEdges = 12;
+
+ box_model.leaf.numLeafBrushes = 1;
+// box_model.leaf.firstLeafBrush = cm.numBrushes;
+ box_model.leaf.firstLeafBrush = cm.numLeafBrushes;
+ cm.leafbrushes[cm.numLeafBrushes] = cm.numBrushes;
+
+ for (i=0 ; i<6 ; i++)
+ {
+ side = i&1;
+
+ // brush sides
+ s = &cm.brushsides[cm.numBrushSides+i];
+ s->plane = cm.planes + (cm.numPlanes+i*2+side);
+ s->surfaceFlags = 0;
+
+ // planes
+ p = &box_planes[i*2];
+ p->type = i>>1;
+ p->signbits = 0;
+ VectorClear (p->normal);
+ p->normal[i>>1] = 1;
+
+ p = &box_planes[i*2+1];
+ p->type = 3 + (i>>1);
+ p->signbits = 0;
+ VectorClear (p->normal);
+ p->normal[i>>1] = -1;
+
+ SetPlaneSignbits( p );
+ }
+}
+
+/*
+===================
+CM_TempBoxModel
+
+To keep everything totally uniform, bounding boxes are turned into small
+BSP trees instead of being compared directly.
+Capsules are handled differently though.
+===================
+*/
+clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs, int capsule ) {
+
+ VectorCopy( mins, box_model.mins );
+ VectorCopy( maxs, box_model.maxs );
+
+ if ( capsule ) {
+ return CAPSULE_MODEL_HANDLE;
+ }
+
+ box_planes[0].dist = maxs[0];
+ box_planes[1].dist = -maxs[0];
+ box_planes[2].dist = mins[0];
+ box_planes[3].dist = -mins[0];
+ box_planes[4].dist = maxs[1];
+ box_planes[5].dist = -maxs[1];
+ box_planes[6].dist = mins[1];
+ box_planes[7].dist = -mins[1];
+ box_planes[8].dist = maxs[2];
+ box_planes[9].dist = -maxs[2];
+ box_planes[10].dist = mins[2];
+ box_planes[11].dist = -mins[2];
+
+ // First side
+ VectorSet( box_brush->edges[ 0 ].p0, mins[ 0 ], mins[ 1 ], mins[ 2 ] );
+ VectorSet( box_brush->edges[ 0 ].p1, mins[ 0 ], maxs[ 1 ], mins[ 2 ] );
+ VectorSet( box_brush->edges[ 1 ].p0, mins[ 0 ], maxs[ 1 ], mins[ 2 ] );
+ VectorSet( box_brush->edges[ 1 ].p1, mins[ 0 ], maxs[ 1 ], maxs[ 2 ] );
+ VectorSet( box_brush->edges[ 2 ].p0, mins[ 0 ], maxs[ 1 ], maxs[ 2 ] );
+ VectorSet( box_brush->edges[ 2 ].p1, mins[ 0 ], mins[ 1 ], maxs[ 2 ] );
+ VectorSet( box_brush->edges[ 3 ].p0, mins[ 0 ], mins[ 1 ], maxs[ 2 ] );
+ VectorSet( box_brush->edges[ 3 ].p1, mins[ 0 ], mins[ 1 ], mins[ 2 ] );
+
+ // Opposite side
+ VectorSet( box_brush->edges[ 4 ].p0, maxs[ 0 ], mins[ 1 ], mins[ 2 ] );
+ VectorSet( box_brush->edges[ 4 ].p1, maxs[ 0 ], maxs[ 1 ], mins[ 2 ] );
+ VectorSet( box_brush->edges[ 5 ].p0, maxs[ 0 ], maxs[ 1 ], mins[ 2 ] );
+ VectorSet( box_brush->edges[ 5 ].p1, maxs[ 0 ], maxs[ 1 ], maxs[ 2 ] );
+ VectorSet( box_brush->edges[ 6 ].p0, maxs[ 0 ], maxs[ 1 ], maxs[ 2 ] );
+ VectorSet( box_brush->edges[ 6 ].p1, maxs[ 0 ], mins[ 1 ], maxs[ 2 ] );
+ VectorSet( box_brush->edges[ 7 ].p0, maxs[ 0 ], mins[ 1 ], maxs[ 2 ] );
+ VectorSet( box_brush->edges[ 7 ].p1, maxs[ 0 ], mins[ 1 ], mins[ 2 ] );
+
+ // Connecting edges
+ VectorSet( box_brush->edges[ 8 ].p0, mins[ 0 ], mins[ 1 ], mins[ 2 ] );
+ VectorSet( box_brush->edges[ 8 ].p1, maxs[ 0 ], mins[ 1 ], mins[ 2 ] );
+ VectorSet( box_brush->edges[ 9 ].p0, mins[ 0 ], maxs[ 1 ], mins[ 2 ] );
+ VectorSet( box_brush->edges[ 9 ].p1, maxs[ 0 ], maxs[ 1 ], mins[ 2 ] );
+ VectorSet( box_brush->edges[ 10 ].p0, mins[ 0 ], maxs[ 1 ], maxs[ 2 ] );
+ VectorSet( box_brush->edges[ 10 ].p1, maxs[ 0 ], maxs[ 1 ], maxs[ 2 ] );
+ VectorSet( box_brush->edges[ 11 ].p0, mins[ 0 ], mins[ 1 ], maxs[ 2 ] );
+ VectorSet( box_brush->edges[ 11 ].p1, maxs[ 0 ], mins[ 1 ], maxs[ 2 ] );
+
+ VectorCopy( mins, box_brush->bounds[0] );
+ VectorCopy( maxs, box_brush->bounds[1] );
+
+ return BOX_MODEL_HANDLE;
+}
+
+/*
+===================
+CM_ModelBounds
+===================
+*/
+void CM_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {
+ cmodel_t *cmod;
+
+ cmod = CM_ClipHandleToModel( model );
+ VectorCopy( cmod->mins, mins );
+ VectorCopy( cmod->maxs, maxs );
+}
diff --git a/src/qcommon/cm_local.h b/src/qcommon/cm_local.h
new file mode 100644
index 0000000..54e62eb
--- /dev/null
+++ b/src/qcommon/cm_local.h
@@ -0,0 +1,225 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifndef CM_LOCAL_H
+#define CM_LOCAL_H 1
+
+#include "cvar.h"
+#include "q_shared.h"
+#include "qcommon.h"
+#include "cm_polylib.h"
+
+#define MAX_SUBMODELS 256
+#define BOX_MODEL_HANDLE 255
+#define CAPSULE_MODEL_HANDLE 254
+
+typedef struct {
+ cplane_t *plane;
+ int children[2]; // negative numbers are leafs
+} cNode_t;
+
+typedef struct {
+ int cluster;
+ int area;
+
+ int firstLeafBrush;
+ int numLeafBrushes;
+
+ int firstLeafSurface;
+ int numLeafSurfaces;
+} cLeaf_t;
+
+typedef struct cmodel_s {
+ vec3_t mins, maxs;
+ cLeaf_t leaf; // submodels don't reference the main tree
+} cmodel_t;
+
+typedef struct cbrushedge_s
+{
+ vec3_t p0;
+ vec3_t p1;
+} cbrushedge_t;
+
+typedef struct {
+ cplane_t *plane;
+ int planeNum;
+ int surfaceFlags;
+ int shaderNum;
+ winding_t *winding;
+} cbrushside_t;
+
+typedef struct {
+ int shaderNum; // the shader that determined the contents
+ int contents;
+ vec3_t bounds[2];
+ int numsides;
+ cbrushside_t *sides;
+ int checkcount; // to avoid repeated testings
+ bool collided; // marker for optimisation
+ cbrushedge_t *edges;
+ int numEdges;
+} cbrush_t;
+
+
+typedef struct {
+ int checkcount; // to avoid repeated testings
+ int surfaceFlags;
+ int contents;
+ struct patchCollide_s *pc;
+} cPatch_t;
+
+
+typedef struct {
+ int floodnum;
+ int floodvalid;
+} cArea_t;
+
+typedef struct {
+ char name[MAX_QPATH];
+
+ int numShaders;
+ dshader_t *shaders;
+
+ int numBrushSides;
+ cbrushside_t *brushsides;
+
+ int numPlanes;
+ cplane_t *planes;
+
+ int numNodes;
+ cNode_t *nodes;
+
+ int numLeafs;
+ cLeaf_t *leafs;
+
+ int numLeafBrushes;
+ int *leafbrushes;
+
+ int numLeafSurfaces;
+ int *leafsurfaces;
+
+ int numSubModels;
+ cmodel_t *cmodels;
+
+ int numBrushes;
+ cbrush_t *brushes;
+
+ int numClusters;
+ int clusterBytes;
+ byte *visibility;
+ bool vised; // if false, visibility is just a single cluster of ffs
+
+ int numEntityChars;
+ char *entityString;
+
+ int numAreas;
+ cArea_t *areas;
+ int *areaPortals; // [ numAreas*numAreas ] reference counts
+
+ int numSurfaces;
+ cPatch_t **surfaces; // non-patches will be NULL
+
+ int floodvalid;
+ int checkcount; // incremented on each trace
+} clipMap_t;
+
+
+// keep 1/8 unit away to keep the position valid before network snapping
+// and to avoid various numeric issues
+#define SURFACE_CLIP_EPSILON (0.125)
+
+extern clipMap_t cm;
+extern int c_pointcontents;
+extern int c_traces, c_brush_traces, c_patch_traces;
+extern cvar_t *cm_noAreas;
+extern cvar_t *cm_noCurves;
+extern cvar_t *cm_playerCurveClip;
+
+// cm_test.c
+
+typedef struct
+{
+ float startRadius;
+ float endRadius;
+} biSphere_t;
+
+// Used for oriented capsule collision detection
+typedef struct
+{
+ float radius;
+ float halfheight;
+ vec3_t offset;
+} sphere_t;
+
+typedef struct {
+ traceType_t type;
+ vec3_t start;
+ vec3_t end;
+ vec3_t size[2]; // size of the box being swept through the model
+ vec3_t offsets[8]; // [signbits][x] = either size[0][x] or size[1][x]
+ float maxOffset; // longest corner length from origin
+ vec3_t extents; // greatest of abs(size[0]) and abs(size[1])
+ vec3_t bounds[2]; // enclosing box of start and end surrounding by size
+ vec3_t modelOrigin;// origin of the model tracing through
+ int contents; // ored contents of the model tracing through
+ bool isPoint; // optimized case
+ trace_t trace; // returned from trace call
+ sphere_t sphere; // sphere for oriendted capsule collision
+ biSphere_t biSphere;
+ bool testLateralCollision; // whether or not to test for lateral collision
+} traceWork_t;
+
+typedef struct leafList_s {
+ int count;
+ int maxcount;
+ bool overflowed;
+ int *list;
+ vec3_t bounds[2];
+ int lastLeaf; // for overflows where each leaf can't be stored individually
+ void (*storeLeafs)( struct leafList_s *ll, int nodenum );
+} leafList_t;
+
+
+int CM_BoxBrushes( const vec3_t mins, const vec3_t maxs, cbrush_t **list, int listsize );
+
+void CM_StoreLeafs( leafList_t *ll, int nodenum );
+void CM_StoreBrushes( leafList_t *ll, int nodenum );
+
+void CM_BoxLeafnums_r( leafList_t *ll, int nodenum );
+
+cmodel_t *CM_ClipHandleToModel( clipHandle_t handle );
+bool CM_BoundsIntersect( const vec3_t mins, const vec3_t maxs, const vec3_t mins2, const vec3_t maxs2 );
+bool CM_BoundsIntersectPoint( const vec3_t mins, const vec3_t maxs, const vec3_t point );
+
+// cm_patch.c
+
+struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, vec3_t *points );
+void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
+bool CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
+void CM_ClearLevelPatches( void );
+
+// cm_test.c
+void CM_FloodAreaConnections (void);
+
+#endif
diff --git a/src/qcommon/cm_patch.cpp b/src/qcommon/cm_patch.cpp
new file mode 100644
index 0000000..274d7c6
--- /dev/null
+++ b/src/qcommon/cm_patch.cpp
@@ -0,0 +1,1801 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "cm_local.h"
+#include "cm_patch.h"
+
+/*
+
+This file does not reference any globals, and has these entry points:
+
+void CM_ClearLevelPatches( void );
+struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, const vec3_t *points );
+void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
+bool CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
+void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, flaot *points) );
+
+
+WARNING: this may misbehave with meshes that have rows or columns that only
+degenerate a few triangles. Completely degenerate rows and columns are handled
+properly.
+*/
+
+/*
+#define MAX_FACETS 1024
+#define MAX_PATCH_PLANES 2048
+
+typedef struct {
+ float plane[4];
+ int signbits; // signx + (signy<<1) + (signz<<2), used as lookup during collision
+} patchPlane_t;
+
+typedef struct {
+ int surfacePlane;
+ int numBorders; // 3 or four + 6 axial bevels + 4 or 3 * 4 edge bevels
+ int borderPlanes[4+6+16];
+ int borderInward[4+6+16];
+ bool borderNoAdjust[4+6+16];
+} facet_t;
+
+typedef struct patchCollide_s {
+ vec3_t bounds[2];
+ int numPlanes; // surface planes plus edge planes
+ patchPlane_t *planes;
+ int numFacets;
+ facet_t *facets;
+} patchCollide_t;
+
+
+#define MAX_GRID_SIZE 129
+
+typedef struct {
+ int width;
+ int height;
+ bool wrapWidth;
+ bool wrapHeight;
+ vec3_t points[MAX_GRID_SIZE][MAX_GRID_SIZE]; // [width][height]
+} cGrid_t;
+
+#define SUBDIVIDE_DISTANCE 16 //4 // never more than this units away from curve
+#define PLANE_TRI_EPSILON 0.1
+#define WRAP_POINT_EPSILON 0.1
+*/
+
+int c_totalPatchBlocks;
+int c_totalPatchSurfaces;
+int c_totalPatchEdges;
+
+static const patchCollide_t *debugPatchCollide;
+static const facet_t *debugFacet;
+static bool debugBlock;
+static vec3_t debugBlockPoints[4];
+
+/*
+=================
+CM_ClearLevelPatches
+=================
+*/
+void CM_ClearLevelPatches( void ) {
+ debugPatchCollide = NULL;
+ debugFacet = NULL;
+}
+
+/*
+=================
+CM_SignbitsForNormal
+=================
+*/
+static int CM_SignbitsForNormal( vec3_t normal ) {
+ int bits, j;
+
+ bits = 0;
+ for (j=0 ; j<3 ; j++) {
+ if ( normal[j] < 0 ) {
+ bits |= 1<<j;
+ }
+ }
+ return bits;
+}
+
+/*
+=====================
+CM_PlaneFromPoints
+
+Returns false if the triangle is degenrate.
+The normal will point out of the clock for clockwise ordered points
+=====================
+*/
+static bool CM_PlaneFromPoints( vec4_t plane, vec3_t a, vec3_t b, vec3_t c ) {
+ vec3_t d1, d2;
+
+ VectorSubtract( b, a, d1 );
+ VectorSubtract( c, a, d2 );
+ CrossProduct( d2, d1, plane );
+ if ( VectorNormalize( plane ) == 0 ) {
+ return false;
+ }
+
+ plane[3] = DotProduct( a, plane );
+ return true;
+}
+
+
+/*
+================================================================================
+
+GRID SUBDIVISION
+
+================================================================================
+*/
+
+/*
+=================
+CM_NeedsSubdivision
+
+Returns true if the given quadratic curve is not flat enough for our
+collision detection purposes
+=================
+*/
+static bool CM_NeedsSubdivision( vec3_t a, vec3_t b, vec3_t c ) {
+ vec3_t cmid;
+ vec3_t lmid;
+ vec3_t delta;
+ float dist;
+ int i;
+
+ // calculate the linear midpoint
+ for ( i = 0 ; i < 3 ; i++ ) {
+ lmid[i] = 0.5*(a[i] + c[i]);
+ }
+
+ // calculate the exact curve midpoint
+ for ( i = 0 ; i < 3 ; i++ ) {
+ cmid[i] = 0.5 * ( 0.5*(a[i] + b[i]) + 0.5*(b[i] + c[i]) );
+ }
+
+ // see if the curve is far enough away from the linear mid
+ VectorSubtract( cmid, lmid, delta );
+ dist = VectorLength( delta );
+
+ return (bool)(dist >= SUBDIVIDE_DISTANCE);
+}
+
+/*
+===============
+CM_Subdivide
+
+a, b, and c are control points.
+the subdivided sequence will be: a, out1, out2, out3, c
+===============
+*/
+static void CM_Subdivide( vec3_t a, vec3_t b, vec3_t c, vec3_t out1, vec3_t out2, vec3_t out3 ) {
+ int i;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ out1[i] = 0.5 * (a[i] + b[i]);
+ out3[i] = 0.5 * (b[i] + c[i]);
+ out2[i] = 0.5 * (out1[i] + out3[i]);
+ }
+}
+
+/*
+=================
+CM_TransposeGrid
+
+Swaps the rows and columns in place
+=================
+*/
+static void CM_TransposeGrid( cGrid_t *grid ) {
+ int i, j, l;
+ vec3_t temp;
+ bool tempWrap;
+
+ if ( grid->width > grid->height ) {
+ for ( i = 0 ; i < grid->height ; i++ ) {
+ for ( j = i + 1 ; j < grid->width ; j++ ) {
+ if ( j < grid->height ) {
+ // swap the value
+ VectorCopy( grid->points[i][j], temp );
+ VectorCopy( grid->points[j][i], grid->points[i][j] );
+ VectorCopy( temp, grid->points[j][i] );
+ } else {
+ // just copy
+ VectorCopy( grid->points[j][i], grid->points[i][j] );
+ }
+ }
+ }
+ } else {
+ for ( i = 0 ; i < grid->width ; i++ ) {
+ for ( j = i + 1 ; j < grid->height ; j++ ) {
+ if ( j < grid->width ) {
+ // swap the value
+ VectorCopy( grid->points[j][i], temp );
+ VectorCopy( grid->points[i][j], grid->points[j][i] );
+ VectorCopy( temp, grid->points[i][j] );
+ } else {
+ // just copy
+ VectorCopy( grid->points[i][j], grid->points[j][i] );
+ }
+ }
+ }
+ }
+
+ l = grid->width;
+ grid->width = grid->height;
+ grid->height = l;
+
+ tempWrap = grid->wrapWidth;
+ grid->wrapWidth = grid->wrapHeight;
+ grid->wrapHeight = tempWrap;
+}
+
+/*
+===================
+CM_SetGridWrapWidth
+
+If the left and right columns are exactly equal, set grid->wrapWidth true
+===================
+*/
+static void CM_SetGridWrapWidth( cGrid_t *grid ) {
+ int i, j;
+ float d;
+
+ for ( i = 0 ; i < grid->height ; i++ ) {
+ for ( j = 0 ; j < 3 ; j++ ) {
+ d = grid->points[0][i][j] - grid->points[grid->width-1][i][j];
+ if ( d < -WRAP_POINT_EPSILON || d > WRAP_POINT_EPSILON ) {
+ break;
+ }
+ }
+ if ( j != 3 ) {
+ break;
+ }
+ }
+ if ( i == grid->height ) {
+ grid->wrapWidth = true;
+ } else {
+ grid->wrapWidth = false;
+ }
+}
+
+/*
+=================
+CM_SubdivideGridColumns
+
+Adds columns as necessary to the grid until
+all the aproximating points are within SUBDIVIDE_DISTANCE
+from the true curve
+=================
+*/
+static void CM_SubdivideGridColumns( cGrid_t *grid ) {
+ int i, j, k;
+
+ for ( i = 0 ; i < grid->width - 2 ; ) {
+ // grid->points[i][x] is an interpolating control point
+ // grid->points[i+1][x] is an aproximating control point
+ // grid->points[i+2][x] is an interpolating control point
+
+ //
+ // first see if we can collapse the aproximating collumn away
+ //
+ for ( j = 0 ; j < grid->height ; j++ ) {
+ if ( CM_NeedsSubdivision( grid->points[i][j], grid->points[i+1][j], grid->points[i+2][j] ) ) {
+ break;
+ }
+ }
+ if ( j == grid->height ) {
+ // all of the points were close enough to the linear midpoints
+ // that we can collapse the entire column away
+ for ( j = 0 ; j < grid->height ; j++ ) {
+ // remove the column
+ for ( k = i + 2 ; k < grid->width ; k++ ) {
+ VectorCopy( grid->points[k][j], grid->points[k-1][j] );
+ }
+ }
+
+ grid->width--;
+
+ // go to the next curve segment
+ i++;
+ continue;
+ }
+
+ //
+ // we need to subdivide the curve
+ //
+ for ( j = 0 ; j < grid->height ; j++ ) {
+ vec3_t prev, mid, next;
+
+ // save the control points now
+ VectorCopy( grid->points[i][j], prev );
+ VectorCopy( grid->points[i+1][j], mid );
+ VectorCopy( grid->points[i+2][j], next );
+
+ // make room for two additional columns in the grid
+ // columns i+1 will be replaced, column i+2 will become i+4
+ // i+1, i+2, and i+3 will be generated
+ for ( k = grid->width - 1 ; k > i + 1 ; k-- ) {
+ VectorCopy( grid->points[k][j], grid->points[k+2][j] );
+ }
+
+ // generate the subdivided points
+ CM_Subdivide( prev, mid, next, grid->points[i+1][j], grid->points[i+2][j], grid->points[i+3][j] );
+ }
+
+ grid->width += 2;
+
+ // the new aproximating point at i+1 may need to be removed
+ // or subdivided farther, so don't advance i
+ }
+}
+
+/*
+======================
+CM_ComparePoints
+======================
+*/
+#define POINT_EPSILON 0.1
+static bool CM_ComparePoints( float *a, float *b ) {
+ float d;
+
+ d = a[0] - b[0];
+ if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
+ return false;
+ }
+ d = a[1] - b[1];
+ if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
+ return false;
+ }
+ d = a[2] - b[2];
+ if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
+ return false;
+ }
+ return true;
+}
+
+/*
+=================
+CM_RemoveDegenerateColumns
+
+If there are any identical columns, remove them
+=================
+*/
+static void CM_RemoveDegenerateColumns( cGrid_t *grid ) {
+ int i, j, k;
+
+ for ( i = 0 ; i < grid->width - 1 ; i++ ) {
+ for ( j = 0 ; j < grid->height ; j++ ) {
+ if ( !CM_ComparePoints( grid->points[i][j], grid->points[i+1][j] ) ) {
+ break;
+ }
+ }
+
+ if ( j != grid->height ) {
+ continue; // not degenerate
+ }
+
+ for ( j = 0 ; j < grid->height ; j++ ) {
+ // remove the column
+ for ( k = i + 2 ; k < grid->width ; k++ ) {
+ VectorCopy( grid->points[k][j], grid->points[k-1][j] );
+ }
+ }
+ grid->width--;
+
+ // check against the next column
+ i--;
+ }
+}
+
+/*
+================================================================================
+
+PATCH COLLIDE GENERATION
+
+================================================================================
+*/
+
+static int numPlanes;
+static patchPlane_t planes[MAX_PATCH_PLANES];
+
+static int numFacets;
+static facet_t facets[MAX_FACETS];
+
+#define NORMAL_EPSILON 0.0001
+#define DIST_EPSILON 0.02
+
+/*
+==================
+CM_PlaneEqual
+==================
+*/
+int CM_PlaneEqual(patchPlane_t *p, float plane[4], int *flipped) {
+ float invplane[4];
+
+ if (
+ fabs(p->plane[0] - plane[0]) < NORMAL_EPSILON
+ && fabs(p->plane[1] - plane[1]) < NORMAL_EPSILON
+ && fabs(p->plane[2] - plane[2]) < NORMAL_EPSILON
+ && fabs(p->plane[3] - plane[3]) < DIST_EPSILON )
+ {
+ *flipped = false;
+ return true;
+ }
+
+ VectorNegate(plane, invplane);
+ invplane[3] = -plane[3];
+
+ if (
+ fabs(p->plane[0] - invplane[0]) < NORMAL_EPSILON
+ && fabs(p->plane[1] - invplane[1]) < NORMAL_EPSILON
+ && fabs(p->plane[2] - invplane[2]) < NORMAL_EPSILON
+ && fabs(p->plane[3] - invplane[3]) < DIST_EPSILON )
+ {
+ *flipped = true;
+ return true;
+ }
+
+ return false;
+}
+
+/*
+==================
+CM_SnapVector
+==================
+*/
+void CM_SnapVector(vec3_t normal) {
+ int i;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
+ {
+ VectorClear (normal);
+ normal[i] = 1;
+ break;
+ }
+ if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
+ {
+ VectorClear (normal);
+ normal[i] = -1;
+ break;
+ }
+ }
+}
+
+/*
+==================
+CM_FindPlane2
+==================
+*/
+int CM_FindPlane2(float plane[4], int *flipped) {
+ int i;
+
+ // see if the points are close enough to an existing plane
+ for ( i = 0 ; i < numPlanes ; i++ ) {
+ if (CM_PlaneEqual(&planes[i], plane, flipped)) return i;
+ }
+
+ // add a new plane
+ if ( numPlanes == MAX_PATCH_PLANES ) {
+ Com_Error( ERR_DROP, "MAX_PATCH_PLANES" );
+ }
+
+ Vector4Copy( plane, planes[numPlanes].plane );
+ planes[numPlanes].signbits = CM_SignbitsForNormal( plane );
+
+ numPlanes++;
+
+ *flipped = false;
+
+ return numPlanes-1;
+}
+
+/*
+==================
+CM_FindPlane
+==================
+*/
+static int CM_FindPlane( float *p1, float *p2, float *p3 ) {
+ float plane[4];
+ int i;
+ float d;
+
+ if ( !CM_PlaneFromPoints( plane, p1, p2, p3 ) ) {
+ return -1;
+ }
+
+ // see if the points are close enough to an existing plane
+ for ( i = 0 ; i < numPlanes ; i++ ) {
+ if ( DotProduct( plane, planes[i].plane ) < 0 ) {
+ continue; // allow backwards planes?
+ }
+
+ d = DotProduct( p1, planes[i].plane ) - planes[i].plane[3];
+ if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
+ continue;
+ }
+
+ d = DotProduct( p2, planes[i].plane ) - planes[i].plane[3];
+ if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
+ continue;
+ }
+
+ d = DotProduct( p3, planes[i].plane ) - planes[i].plane[3];
+ if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
+ continue;
+ }
+
+ // found it
+ return i;
+ }
+
+ // add a new plane
+ if ( numPlanes == MAX_PATCH_PLANES ) {
+ Com_Error( ERR_DROP, "MAX_PATCH_PLANES" );
+ }
+
+ Vector4Copy( plane, planes[numPlanes].plane );
+ planes[numPlanes].signbits = CM_SignbitsForNormal( plane );
+
+ numPlanes++;
+
+ return numPlanes-1;
+}
+
+/*
+==================
+CM_PointOnPlaneSide
+==================
+*/
+static int CM_PointOnPlaneSide( float *p, int planeNum ) {
+ float *plane;
+ float d;
+
+ if ( planeNum == -1 ) {
+ return SIDE_ON;
+ }
+ plane = planes[ planeNum ].plane;
+
+ d = DotProduct( p, plane ) - plane[3];
+
+ if ( d > PLANE_TRI_EPSILON ) {
+ return SIDE_FRONT;
+ }
+
+ if ( d < -PLANE_TRI_EPSILON ) {
+ return SIDE_BACK;
+ }
+
+ return SIDE_ON;
+}
+
+/*
+==================
+CM_GridPlane
+==================
+*/
+static int CM_GridPlane( int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int tri ) {
+ int p;
+
+ p = gridPlanes[i][j][tri];
+ if ( p != -1 ) {
+ return p;
+ }
+ p = gridPlanes[i][j][!tri];
+ if ( p != -1 ) {
+ return p;
+ }
+
+ // should never happen
+ Com_Printf( "WARNING: CM_GridPlane unresolvable\n" );
+ return -1;
+}
+
+/*
+==================
+CM_EdgePlaneNum
+==================
+*/
+static int CM_EdgePlaneNum( cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int k ) {
+ float *p1, *p2;
+ vec3_t up;
+ int p;
+
+ switch ( k ) {
+ case 0: // top border
+ p1 = grid->points[i][j];
+ p2 = grid->points[i+1][j];
+ p = CM_GridPlane( gridPlanes, i, j, 0 );
+ if ( p == -1 ) {
+ return -1;
+ }
+ VectorMA( p1, 4, planes[ p ].plane, up );
+ return CM_FindPlane( p1, p2, up );
+
+ case 2: // bottom border
+ p1 = grid->points[i][j+1];
+ p2 = grid->points[i+1][j+1];
+ p = CM_GridPlane( gridPlanes, i, j, 1 );
+ if ( p == -1 ) {
+ return -1;
+ }
+ VectorMA( p1, 4, planes[ p ].plane, up );
+ return CM_FindPlane( p2, p1, up );
+
+ case 3: // left border
+ p1 = grid->points[i][j];
+ p2 = grid->points[i][j+1];
+ p = CM_GridPlane( gridPlanes, i, j, 1 );
+ if ( p == -1 ) {
+ return -1;
+ }
+ VectorMA( p1, 4, planes[ p ].plane, up );
+ return CM_FindPlane( p2, p1, up );
+
+ case 1: // right border
+ p1 = grid->points[i+1][j];
+ p2 = grid->points[i+1][j+1];
+ p = CM_GridPlane( gridPlanes, i, j, 0 );
+ if ( p == -1 ) {
+ return -1;
+ }
+ VectorMA( p1, 4, planes[ p ].plane, up );
+ return CM_FindPlane( p1, p2, up );
+
+ case 4: // diagonal out of triangle 0
+ p1 = grid->points[i+1][j+1];
+ p2 = grid->points[i][j];
+ p = CM_GridPlane( gridPlanes, i, j, 0 );
+ if ( p == -1 ) {
+ return -1;
+ }
+ VectorMA( p1, 4, planes[ p ].plane, up );
+ return CM_FindPlane( p1, p2, up );
+
+ case 5: // diagonal out of triangle 1
+ p1 = grid->points[i][j];
+ p2 = grid->points[i+1][j+1];
+ p = CM_GridPlane( gridPlanes, i, j, 1 );
+ if ( p == -1 ) {
+ return -1;
+ }
+ VectorMA( p1, 4, planes[ p ].plane, up );
+ return CM_FindPlane( p1, p2, up );
+
+ }
+
+ Com_Error( ERR_DROP, "CM_EdgePlaneNum: bad k" );
+ return -1;
+}
+
+/*
+===================
+CM_SetBorderInward
+===================
+*/
+static void CM_SetBorderInward( facet_t *facet, cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2],
+ int i, int j, int which ) {
+ int k, l;
+ float *points[4];
+ int numPoints;
+
+ switch ( which ) {
+ case -1:
+ points[0] = grid->points[i][j];
+ points[1] = grid->points[i+1][j];
+ points[2] = grid->points[i+1][j+1];
+ points[3] = grid->points[i][j+1];
+ numPoints = 4;
+ break;
+ case 0:
+ points[0] = grid->points[i][j];
+ points[1] = grid->points[i+1][j];
+ points[2] = grid->points[i+1][j+1];
+ numPoints = 3;
+ break;
+ case 1:
+ points[0] = grid->points[i+1][j+1];
+ points[1] = grid->points[i][j+1];
+ points[2] = grid->points[i][j];
+ numPoints = 3;
+ break;
+ default:
+ Com_Error( ERR_FATAL, "CM_SetBorderInward: bad parameter" );
+ numPoints = 0;
+ break;
+ }
+
+ for ( k = 0 ; k < facet->numBorders ; k++ ) {
+ int front, back;
+
+ front = 0;
+ back = 0;
+
+ for ( l = 0 ; l < numPoints ; l++ ) {
+ int side;
+
+ side = CM_PointOnPlaneSide( points[l], facet->borderPlanes[k] );
+ if ( side == SIDE_FRONT ) {
+ front++;
+ } if ( side == SIDE_BACK ) {
+ back++;
+ }
+ }
+
+ if ( front && !back ) {
+ facet->borderInward[k] = true;
+ } else if ( back && !front ) {
+ facet->borderInward[k] = false;
+ } else if ( !front && !back ) {
+ // flat side border
+ facet->borderPlanes[k] = -1;
+ } else {
+ // bisecting side border
+ Com_DPrintf( "WARNING: CM_SetBorderInward: mixed plane sides\n" );
+ facet->borderInward[k] = false;
+ if ( !debugBlock ) {
+ debugBlock = true;
+ VectorCopy( grid->points[i][j], debugBlockPoints[0] );
+ VectorCopy( grid->points[i+1][j], debugBlockPoints[1] );
+ VectorCopy( grid->points[i+1][j+1], debugBlockPoints[2] );
+ VectorCopy( grid->points[i][j+1], debugBlockPoints[3] );
+ }
+ }
+ }
+}
+
+/*
+==================
+CM_ValidateFacet
+
+If the facet isn't bounded by its borders, we screwed up.
+==================
+*/
+static bool CM_ValidateFacet( facet_t *facet ) {
+ float plane[4];
+ int j;
+ winding_t *w;
+ vec3_t bounds[2];
+
+ if ( facet->surfacePlane == -1 ) {
+ return false;
+ }
+
+ Vector4Copy( planes[ facet->surfacePlane ].plane, plane );
+ w = BaseWindingForPlane( plane, plane[3] );
+ for ( j = 0 ; j < facet->numBorders && w ; j++ ) {
+ if ( facet->borderPlanes[j] == -1 ) {
+ FreeWinding( w );
+ return false;
+ }
+ Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );
+ if ( !facet->borderInward[j] ) {
+ VectorSubtract( vec3_origin, plane, plane );
+ plane[3] = -plane[3];
+ }
+ ChopWindingInPlace( &w, plane, plane[3], 0.1f );
+ }
+
+ if ( !w ) {
+ return false; // winding was completely chopped away
+ }
+
+ // see if the facet is unreasonably large
+ WindingBounds( w, bounds[0], bounds[1] );
+ FreeWinding( w );
+
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( bounds[1][j] - bounds[0][j] > MAX_MAP_BOUNDS ) {
+ return false; // we must be missing a plane
+ }
+ if ( bounds[0][j] >= MAX_MAP_BOUNDS ) {
+ return false;
+ }
+ if ( bounds[1][j] <= -MAX_MAP_BOUNDS ) {
+ return false;
+ }
+ }
+ return true; // winding is fine
+}
+
+/*
+==================
+CM_AddFacetBevels
+==================
+*/
+void CM_AddFacetBevels( facet_t *facet ) {
+
+ int i, j, k, l;
+ int axis, dir, flipped;
+ float plane[4], d, newplane[4];
+ winding_t *w, *w2;
+ vec3_t mins, maxs, vec, vec2;
+
+ Vector4Copy( planes[ facet->surfacePlane ].plane, plane );
+
+ w = BaseWindingForPlane( plane, plane[3] );
+ for ( j = 0 ; j < facet->numBorders && w ; j++ ) {
+ if (facet->borderPlanes[j] == facet->surfacePlane) continue;
+ Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );
+
+ if ( !facet->borderInward[j] ) {
+ VectorSubtract( vec3_origin, plane, plane );
+ plane[3] = -plane[3];
+ }
+
+ ChopWindingInPlace( &w, plane, plane[3], 0.1f );
+ }
+ if ( !w ) {
+ return;
+ }
+
+ WindingBounds(w, mins, maxs);
+
+ // add the axial planes
+ for ( axis = 0 ; axis < 3 ; axis++ )
+ {
+ for ( dir = -1 ; dir <= 1 ; dir += 2 )
+ {
+ VectorClear(plane);
+ plane[axis] = dir;
+ if (dir == 1) {
+ plane[3] = maxs[axis];
+ }
+ else {
+ plane[3] = -mins[axis];
+ }
+ //if it's the surface plane
+ if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {
+ continue;
+ }
+ // see if the plane is allready present
+ for ( i = 0 ; i < facet->numBorders ; i++ ) {
+ if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped))
+ break;
+ }
+
+ if ( i == facet->numBorders ) {
+ if ( facet->numBorders >= 4 + 6 + 16 ) {
+ Com_Printf( "ERROR: too many bevels\n" );
+ continue;
+ }
+ facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
+ facet->borderNoAdjust[facet->numBorders] = false;
+ facet->borderInward[facet->numBorders] = flipped;
+ facet->numBorders++;
+ }
+ }
+ }
+ //
+ // add the edge bevels
+ //
+ // test the non-axial plane edges
+ for ( j = 0 ; j < w->numpoints ; j++ )
+ {
+ k = (j+1)%w->numpoints;
+ VectorSubtract (w->p[j], w->p[k], vec);
+ //if it's a degenerate edge
+ if (VectorNormalize (vec) < 0.5)
+ continue;
+ CM_SnapVector(vec);
+ for ( k = 0; k < 3 ; k++ )
+ if ( vec[k] == -1 || vec[k] == 1 )
+ break; // axial
+ if ( k < 3 )
+ continue; // only test non-axial edges
+
+ // try the six possible slanted axials from this edge
+ for ( axis = 0 ; axis < 3 ; axis++ )
+ {
+ for ( dir = -1 ; dir <= 1 ; dir += 2 )
+ {
+ // construct a plane
+ VectorClear (vec2);
+ vec2[axis] = dir;
+ CrossProduct (vec, vec2, plane);
+ if (VectorNormalize (plane) < 0.5)
+ continue;
+ plane[3] = DotProduct (w->p[j], plane);
+
+ // if all the points of the facet winding are
+ // behind this plane, it is a proper edge bevel
+ for ( l = 0 ; l < w->numpoints ; l++ )
+ {
+ d = DotProduct (w->p[l], plane) - plane[3];
+ if (d > 0.1)
+ break; // point in front
+ }
+ if ( l < w->numpoints )
+ continue;
+
+ //if it's the surface plane
+ if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {
+ continue;
+ }
+ // see if the plane is allready present
+ for ( i = 0 ; i < facet->numBorders ; i++ ) {
+ if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) {
+ break;
+ }
+ }
+
+ if ( i == facet->numBorders ) {
+ if ( facet->numBorders >= 4 + 6 + 16 ) {
+ Com_Printf( "ERROR: too many bevels\n" );
+ continue;
+ }
+ facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
+
+ for ( k = 0 ; k < facet->numBorders ; k++ ) {
+ if (facet->borderPlanes[facet->numBorders] ==
+ facet->borderPlanes[k]) Com_Printf("WARNING: bevel plane already used\n");
+ }
+
+ facet->borderNoAdjust[facet->numBorders] = false;
+ facet->borderInward[facet->numBorders] = flipped;
+ //
+ w2 = CopyWinding(w);
+ Vector4Copy(planes[facet->borderPlanes[facet->numBorders]].plane, newplane);
+ if (!facet->borderInward[facet->numBorders])
+ {
+ VectorNegate(newplane, newplane);
+ newplane[3] = -newplane[3];
+ } //end if
+ ChopWindingInPlace( &w2, newplane, newplane[3], 0.1f );
+ if (!w2) {
+ Com_DPrintf("WARNING: CM_AddFacetBevels... invalid bevel\n");
+ continue;
+ }
+ else {
+ FreeWinding(w2);
+ }
+ //
+ facet->numBorders++;
+ //already got a bevel
+// break;
+ }
+ }
+ }
+ }
+ FreeWinding( w );
+
+#ifndef BSPC
+ //add opposite plane
+ if ( facet->numBorders >= 4 + 6 + 16 ) {
+ Com_Printf( "ERROR: too many bevels\n" );
+ return;
+ }
+ facet->borderPlanes[facet->numBorders] = facet->surfacePlane;
+ facet->borderNoAdjust[facet->numBorders] = false;
+ facet->borderInward[facet->numBorders] = true;
+ facet->numBorders++;
+#endif //BSPC
+
+}
+
+typedef enum {
+ EN_TOP,
+ EN_RIGHT,
+ EN_BOTTOM,
+ EN_LEFT
+} edgeName_t;
+
+/*
+==================
+CM_PatchCollideFromGrid
+==================
+*/
+static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) {
+ int i, j;
+ float *p1, *p2, *p3;
+ int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2];
+ facet_t *facet;
+ int borders[4];
+ int noAdjust[4];
+
+ numPlanes = 0;
+ numFacets = 0;
+
+ // find the planes for each triangle of the grid
+ for ( i = 0 ; i < grid->width - 1 ; i++ ) {
+ for ( j = 0 ; j < grid->height - 1 ; j++ ) {
+ p1 = grid->points[i][j];
+ p2 = grid->points[i+1][j];
+ p3 = grid->points[i+1][j+1];
+ gridPlanes[i][j][0] = CM_FindPlane( p1, p2, p3 );
+
+ p1 = grid->points[i+1][j+1];
+ p2 = grid->points[i][j+1];
+ p3 = grid->points[i][j];
+ gridPlanes[i][j][1] = CM_FindPlane( p1, p2, p3 );
+ }
+ }
+
+ // create the borders for each facet
+ for ( i = 0 ; i < grid->width - 1 ; i++ ) {
+ for ( j = 0 ; j < grid->height - 1 ; j++ ) {
+
+ borders[EN_TOP] = -1;
+ if ( j > 0 ) {
+ borders[EN_TOP] = gridPlanes[i][j-1][1];
+ } else if ( grid->wrapHeight ) {
+ borders[EN_TOP] = gridPlanes[i][grid->height-2][1];
+ }
+ noAdjust[EN_TOP] = ( borders[EN_TOP] == gridPlanes[i][j][0] );
+ if ( borders[EN_TOP] == -1 || noAdjust[EN_TOP] ) {
+ borders[EN_TOP] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 0 );
+ }
+
+ borders[EN_BOTTOM] = -1;
+ if ( j < grid->height - 2 ) {
+ borders[EN_BOTTOM] = gridPlanes[i][j+1][0];
+ } else if ( grid->wrapHeight ) {
+ borders[EN_BOTTOM] = gridPlanes[i][0][0];
+ }
+ noAdjust[EN_BOTTOM] = ( borders[EN_BOTTOM] == gridPlanes[i][j][1] );
+ if ( borders[EN_BOTTOM] == -1 || noAdjust[EN_BOTTOM] ) {
+ borders[EN_BOTTOM] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 2 );
+ }
+
+ borders[EN_LEFT] = -1;
+ if ( i > 0 ) {
+ borders[EN_LEFT] = gridPlanes[i-1][j][0];
+ } else if ( grid->wrapWidth ) {
+ borders[EN_LEFT] = gridPlanes[grid->width-2][j][0];
+ }
+ noAdjust[EN_LEFT] = ( borders[EN_LEFT] == gridPlanes[i][j][1] );
+ if ( borders[EN_LEFT] == -1 || noAdjust[EN_LEFT] ) {
+ borders[EN_LEFT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 3 );
+ }
+
+ borders[EN_RIGHT] = -1;
+ if ( i < grid->width - 2 ) {
+ borders[EN_RIGHT] = gridPlanes[i+1][j][1];
+ } else if ( grid->wrapWidth ) {
+ borders[EN_RIGHT] = gridPlanes[0][j][1];
+ }
+ noAdjust[EN_RIGHT] = ( borders[EN_RIGHT] == gridPlanes[i][j][0] );
+ if ( borders[EN_RIGHT] == -1 || noAdjust[EN_RIGHT] ) {
+ borders[EN_RIGHT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 1 );
+ }
+
+ if ( numFacets == MAX_FACETS ) {
+ Com_Error( ERR_DROP, "MAX_FACETS" );
+ }
+ facet = &facets[numFacets];
+ ::memset( facet, 0, sizeof( *facet ) );
+
+ if ( gridPlanes[i][j][0] == gridPlanes[i][j][1] ) {
+ if ( gridPlanes[i][j][0] == -1 ) {
+ continue; // degenrate
+ }
+ facet->surfacePlane = gridPlanes[i][j][0];
+ facet->numBorders = 4;
+ facet->borderPlanes[0] = borders[EN_TOP];
+ facet->borderNoAdjust[0] = (bool)noAdjust[EN_TOP];
+ facet->borderPlanes[1] = borders[EN_RIGHT];
+ facet->borderNoAdjust[1] = (bool)noAdjust[EN_RIGHT];
+ facet->borderPlanes[2] = borders[EN_BOTTOM];
+ facet->borderNoAdjust[2] = (bool)noAdjust[EN_BOTTOM];
+ facet->borderPlanes[3] = borders[EN_LEFT];
+ facet->borderNoAdjust[3] = (bool)noAdjust[EN_LEFT];
+ CM_SetBorderInward( facet, grid, gridPlanes, i, j, -1 );
+ if ( CM_ValidateFacet( facet ) ) {
+ CM_AddFacetBevels( facet );
+ numFacets++;
+ }
+ } else {
+ // two seperate triangles
+ facet->surfacePlane = gridPlanes[i][j][0];
+ facet->numBorders = 3;
+ facet->borderPlanes[0] = borders[EN_TOP];
+ facet->borderNoAdjust[0] = (bool)noAdjust[EN_TOP];
+ facet->borderPlanes[1] = borders[EN_RIGHT];
+ facet->borderNoAdjust[1] = (bool)noAdjust[EN_RIGHT];
+ facet->borderPlanes[2] = gridPlanes[i][j][1];
+ if ( facet->borderPlanes[2] == -1 ) {
+ facet->borderPlanes[2] = borders[EN_BOTTOM];
+ if ( facet->borderPlanes[2] == -1 ) {
+ facet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 4 );
+ }
+ }
+ CM_SetBorderInward( facet, grid, gridPlanes, i, j, 0 );
+ if ( CM_ValidateFacet( facet ) ) {
+ CM_AddFacetBevels( facet );
+ numFacets++;
+ }
+
+ if ( numFacets == MAX_FACETS ) {
+ Com_Error( ERR_DROP, "MAX_FACETS" );
+ }
+ facet = &facets[numFacets];
+ ::memset( facet, 0, sizeof( *facet ) );
+
+ facet->surfacePlane = gridPlanes[i][j][1];
+ facet->numBorders = 3;
+ facet->borderPlanes[0] = borders[EN_BOTTOM];
+ facet->borderNoAdjust[0] = (bool)noAdjust[EN_BOTTOM];
+ facet->borderPlanes[1] = borders[EN_LEFT];
+ facet->borderNoAdjust[1] = (bool)noAdjust[EN_LEFT];
+ facet->borderPlanes[2] = gridPlanes[i][j][0];
+ if ( facet->borderPlanes[2] == -1 ) {
+ facet->borderPlanes[2] = borders[EN_TOP];
+ if ( facet->borderPlanes[2] == -1 ) {
+ facet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 5 );
+ }
+ }
+ CM_SetBorderInward( facet, grid, gridPlanes, i, j, 1 );
+ if ( CM_ValidateFacet( facet ) ) {
+ CM_AddFacetBevels( facet );
+ numFacets++;
+ }
+ }
+ }
+ }
+
+ // copy the results out
+ pf->numPlanes = numPlanes;
+ pf->numFacets = numFacets;
+ pf->facets = (facet_t*)Hunk_Alloc( numFacets * sizeof( *pf->facets ), h_high );
+ ::memcpy( pf->facets, facets, numFacets * sizeof( *pf->facets ) );
+ pf->planes = (patchPlane_t*)Hunk_Alloc( numPlanes * sizeof( *pf->planes ), h_high );
+ ::memcpy( pf->planes, planes, numPlanes * sizeof( *pf->planes ) );
+}
+
+
+/*
+===================
+CM_GeneratePatchCollide
+
+Creates an internal structure that will be used to perform
+collision detection with a patch mesh.
+
+Points is packed as concatenated rows.
+===================
+*/
+struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, vec3_t *points ) {
+ patchCollide_t *pf;
+ cGrid_t grid;
+ int i, j;
+
+ if ( width <= 2 || height <= 2 || !points ) {
+ Com_Error( ERR_DROP, "CM_GeneratePatchFacets: bad parameters: (%i, %i, %p)",
+ width, height, (void *)points );
+ }
+
+ if ( !(width & 1) || !(height & 1) ) {
+ Com_Error( ERR_DROP, "CM_GeneratePatchFacets: even sizes are invalid for quadratic meshes" );
+ }
+
+ if ( width > MAX_GRID_SIZE || height > MAX_GRID_SIZE ) {
+ Com_Error( ERR_DROP, "CM_GeneratePatchFacets: source is > MAX_GRID_SIZE" );
+ }
+
+ // build a grid
+ grid.width = width;
+ grid.height = height;
+ grid.wrapWidth = false;
+ grid.wrapHeight = false;
+ for ( i = 0 ; i < width ; i++ ) {
+ for ( j = 0 ; j < height ; j++ ) {
+ VectorCopy( points[j*width + i], grid.points[i][j] );
+ }
+ }
+
+ // subdivide the grid
+ CM_SetGridWrapWidth( &grid );
+ CM_SubdivideGridColumns( &grid );
+ CM_RemoveDegenerateColumns( &grid );
+
+ CM_TransposeGrid( &grid );
+
+ CM_SetGridWrapWidth( &grid );
+ CM_SubdivideGridColumns( &grid );
+ CM_RemoveDegenerateColumns( &grid );
+
+ // we now have a grid of points exactly on the curve
+ // the aproximate surface defined by these points will be
+ // collided against
+ pf = (patchCollide_t*)Hunk_Alloc( sizeof( *pf ), h_high );
+ ClearBounds( pf->bounds[0], pf->bounds[1] );
+ for ( i = 0 ; i < grid.width ; i++ ) {
+ for ( j = 0 ; j < grid.height ; j++ ) {
+ AddPointToBounds( grid.points[i][j], pf->bounds[0], pf->bounds[1] );
+ }
+ }
+
+ c_totalPatchBlocks += ( grid.width - 1 ) * ( grid.height - 1 );
+
+ // generate a bsp tree for the surface
+ CM_PatchCollideFromGrid( &grid, pf );
+
+ // expand by one unit for epsilon purposes
+ pf->bounds[0][0] -= 1;
+ pf->bounds[0][1] -= 1;
+ pf->bounds[0][2] -= 1;
+
+ pf->bounds[1][0] += 1;
+ pf->bounds[1][1] += 1;
+ pf->bounds[1][2] += 1;
+
+ return pf;
+}
+
+/*
+================================================================================
+
+TRACE TESTING
+
+================================================================================
+*/
+
+/*
+====================
+CM_TracePointThroughPatchCollide
+
+ special case for point traces because the patch collide "brushes" have no volume
+====================
+*/
+void CM_TracePointThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
+ bool frontFacing[MAX_PATCH_PLANES];
+ float intersection[MAX_PATCH_PLANES];
+ float intersect;
+ const patchPlane_t *planes;
+ const facet_t *facet;
+ int i, j, k;
+ float offset;
+ float d1, d2;
+#ifndef BSPC
+ static cvar_t *cv;
+#endif //BSPC
+
+#ifndef BSPC
+ if ( !cm_playerCurveClip->integer || !tw->isPoint ) {
+ return;
+ }
+#endif
+
+ // determine the trace's relationship to all planes
+ planes = pc->planes;
+ for ( i = 0 ; i < pc->numPlanes ; i++, planes++ ) {
+ offset = DotProduct( tw->offsets[ planes->signbits ], planes->plane );
+ d1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset;
+ d2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset;
+ if ( d1 <= 0 ) {
+ frontFacing[i] = false;
+ } else {
+ frontFacing[i] = true;
+ }
+ if ( d1 == d2 ) {
+ intersection[i] = 99999;
+ } else {
+ intersection[i] = d1 / ( d1 - d2 );
+ if ( intersection[i] <= 0 ) {
+ intersection[i] = 99999;
+ }
+ }
+ }
+
+
+ // see if any of the surface planes are intersected
+ facet = pc->facets;
+ for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
+ if ( !frontFacing[facet->surfacePlane] ) {
+ continue;
+ }
+ intersect = intersection[facet->surfacePlane];
+ if ( intersect < 0 ) {
+ continue; // surface is behind the starting point
+ }
+ if ( intersect > tw->trace.fraction ) {
+ continue; // already hit something closer
+ }
+ for ( j = 0 ; j < facet->numBorders ; j++ ) {
+ k = facet->borderPlanes[j];
+ if ( frontFacing[k] ^ facet->borderInward[j] ) {
+ if ( intersection[k] > intersect ) {
+ break;
+ }
+ } else {
+ if ( intersection[k] < intersect ) {
+ break;
+ }
+ }
+ }
+ if ( j == facet->numBorders ) {
+ // we hit this facet
+#ifndef BSPC
+ if (!cv) {
+ cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 );
+ }
+ if (cv->integer) {
+ debugPatchCollide = pc;
+ debugFacet = facet;
+ }
+#endif //BSPC
+ planes = &pc->planes[facet->surfacePlane];
+
+ // calculate intersection with a slight pushoff
+ offset = DotProduct( tw->offsets[ planes->signbits ], planes->plane );
+ d1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset;
+ d2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset;
+ tw->trace.fraction = ( d1 - SURFACE_CLIP_EPSILON ) / ( d1 - d2 );
+
+ if ( tw->trace.fraction < 0 ) {
+ tw->trace.fraction = 0;
+ }
+
+ VectorCopy( planes->plane, tw->trace.plane.normal );
+ tw->trace.plane.dist = planes->plane[3];
+ }
+ }
+}
+
+/*
+====================
+CM_CheckFacetPlane
+====================
+*/
+int CM_CheckFacetPlane(float *plane, vec3_t start, vec3_t end, float *enterFrac, float *leaveFrac, int *hit) {
+ float d1, d2, f;
+
+ *hit = false;
+
+ d1 = DotProduct( start, plane ) - plane[3];
+ d2 = DotProduct( end, plane ) - plane[3];
+
+ // if completely in front of face, no intersection with the entire facet
+ if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) ) {
+ return false;
+ }
+
+ // if it doesn't cross the plane, the plane isn't relevent
+ if (d1 <= 0 && d2 <= 0 ) {
+ return true;
+ }
+
+ // crosses face
+ if (d1 > d2) { // enter
+ f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);
+ if ( f < 0 ) {
+ f = 0;
+ }
+ //always favor previous plane hits and thus also the surface plane hit
+ if (f > *enterFrac) {
+ *enterFrac = f;
+ *hit = true;
+ }
+ } else { // leave
+ f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);
+ if ( f > 1 ) {
+ f = 1;
+ }
+ if (f < *leaveFrac) {
+ *leaveFrac = f;
+ }
+ }
+ return true;
+}
+
+/*
+====================
+CM_TraceThroughPatchCollide
+====================
+*/
+void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
+ int i, j, hit, hitnum;
+ float offset, enterFrac, leaveFrac, t;
+ patchPlane_t *planes;
+ facet_t *facet;
+ float plane[4] = {0, 0, 0, 0}, bestplane[4] = {0, 0, 0, 0};
+ vec3_t startp, endp;
+#ifndef BSPC
+ static cvar_t *cv;
+#endif //BSPC
+
+ if ( !CM_BoundsIntersect( tw->bounds[0], tw->bounds[1],
+ pc->bounds[0], pc->bounds[1] ) ) {
+ return;
+ }
+
+ if (tw->isPoint) {
+ CM_TracePointThroughPatchCollide( tw, pc );
+ return;
+ }
+
+ facet = pc->facets;
+ for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
+ enterFrac = -1.0;
+ leaveFrac = 1.0;
+ hitnum = -1;
+ //
+ planes = &pc->planes[ facet->surfacePlane ];
+ VectorCopy(planes->plane, plane);
+ plane[3] = planes->plane[3];
+ if ( tw->type == TT_CAPSULE ) {
+ // adjust the plane distance apropriately for radius
+ plane[3] += tw->sphere.radius;
+
+ // find the closest point on the capsule to the plane
+ t = DotProduct( plane, tw->sphere.offset );
+ if ( t > 0.0f ) {
+ VectorSubtract( tw->start, tw->sphere.offset, startp );
+ VectorSubtract( tw->end, tw->sphere.offset, endp );
+ }
+ else {
+ VectorAdd( tw->start, tw->sphere.offset, startp );
+ VectorAdd( tw->end, tw->sphere.offset, endp );
+ }
+ }
+ else {
+ offset = DotProduct( tw->offsets[ planes->signbits ], plane);
+ plane[3] -= offset;
+ VectorCopy( tw->start, startp );
+ VectorCopy( tw->end, endp );
+ }
+
+ if (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) {
+ continue;
+ }
+ if (hit) {
+ Vector4Copy(plane, bestplane);
+ }
+
+ for ( j = 0; j < facet->numBorders; j++ ) {
+ planes = &pc->planes[ facet->borderPlanes[j] ];
+ if (facet->borderInward[j]) {
+ VectorNegate(planes->plane, plane);
+ plane[3] = -planes->plane[3];
+ }
+ else {
+ VectorCopy(planes->plane, plane);
+ plane[3] = planes->plane[3];
+ }
+ if ( tw->type == TT_CAPSULE ) {
+ // adjust the plane distance apropriately for radius
+ plane[3] += tw->sphere.radius;
+
+ // find the closest point on the capsule to the plane
+ t = DotProduct( plane, tw->sphere.offset );
+ if ( t > 0.0f ) {
+ VectorSubtract( tw->start, tw->sphere.offset, startp );
+ VectorSubtract( tw->end, tw->sphere.offset, endp );
+ }
+ else {
+ VectorAdd( tw->start, tw->sphere.offset, startp );
+ VectorAdd( tw->end, tw->sphere.offset, endp );
+ }
+ }
+ else {
+ // NOTE: this works even though the plane might be flipped because the bbox is centered
+ offset = DotProduct( tw->offsets[ planes->signbits ], plane);
+ plane[3] += fabs(offset);
+ VectorCopy( tw->start, startp );
+ VectorCopy( tw->end, endp );
+ }
+
+ if (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) {
+ break;
+ }
+ if (hit) {
+ hitnum = j;
+ Vector4Copy(plane, bestplane);
+ }
+ }
+ if (j < facet->numBorders) continue;
+ //never clip against the back side
+ if (hitnum == facet->numBorders - 1) continue;
+
+ if (enterFrac < leaveFrac && enterFrac >= 0) {
+ if (enterFrac < tw->trace.fraction) {
+ if (enterFrac < 0) {
+ enterFrac = 0;
+ }
+#ifndef BSPC
+ if (!cv) {
+ cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 );
+ }
+ if (cv && cv->integer) {
+ debugPatchCollide = pc;
+ debugFacet = facet;
+ }
+#endif //BSPC
+
+ tw->trace.fraction = enterFrac;
+ VectorCopy( bestplane, tw->trace.plane.normal );
+ tw->trace.plane.dist = bestplane[3];
+ }
+ }
+ }
+}
+
+
+/*
+=======================================================================
+
+POSITION TEST
+
+=======================================================================
+*/
+
+/*
+====================
+CM_PositionTestInPatchCollide
+====================
+*/
+bool CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
+ int i, j;
+ float offset, t;
+ patchPlane_t *planes;
+ facet_t *facet;
+ float plane[4];
+ vec3_t startp;
+
+ if (tw->isPoint) {
+ return false;
+ }
+ //
+ facet = pc->facets;
+ for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
+ planes = &pc->planes[ facet->surfacePlane ];
+ VectorCopy(planes->plane, plane);
+ plane[3] = planes->plane[3];
+ if ( tw->type == TT_CAPSULE ) {
+ // adjust the plane distance apropriately for radius
+ plane[3] += tw->sphere.radius;
+
+ // find the closest point on the capsule to the plane
+ t = DotProduct( plane, tw->sphere.offset );
+ if ( t > 0 ) {
+ VectorSubtract( tw->start, tw->sphere.offset, startp );
+ }
+ else {
+ VectorAdd( tw->start, tw->sphere.offset, startp );
+ }
+ }
+ else {
+ offset = DotProduct( tw->offsets[ planes->signbits ], plane);
+ plane[3] -= offset;
+ VectorCopy( tw->start, startp );
+ }
+
+ if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) {
+ continue;
+ }
+
+ for ( j = 0; j < facet->numBorders; j++ ) {
+ planes = &pc->planes[ facet->borderPlanes[j] ];
+ if (facet->borderInward[j]) {
+ VectorNegate(planes->plane, plane);
+ plane[3] = -planes->plane[3];
+ }
+ else {
+ VectorCopy(planes->plane, plane);
+ plane[3] = planes->plane[3];
+ }
+ if ( tw->type == TT_CAPSULE ) {
+ // adjust the plane distance apropriately for radius
+ plane[3] += tw->sphere.radius;
+
+ // find the closest point on the capsule to the plane
+ t = DotProduct( plane, tw->sphere.offset );
+ if ( t > 0.0f ) {
+ VectorSubtract( tw->start, tw->sphere.offset, startp );
+ }
+ else {
+ VectorAdd( tw->start, tw->sphere.offset, startp );
+ }
+ }
+ else {
+ // NOTE: this works even though the plane might be flipped because the bbox is centered
+ offset = DotProduct( tw->offsets[ planes->signbits ], plane);
+ plane[3] += fabs(offset);
+ VectorCopy( tw->start, startp );
+ }
+
+ if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) {
+ break;
+ }
+ }
+ if (j < facet->numBorders) {
+ continue;
+ }
+ // inside this patch facet
+ return true;
+ }
+ return false;
+}
+
+/*
+=======================================================================
+
+DEBUGGING
+
+=======================================================================
+*/
+
+
+/*
+==================
+CM_DrawDebugSurface
+
+Called from the renderer
+==================
+*/
+void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *points) ) {
+ static cvar_t *cv;
+#ifndef BSPC
+ static cvar_t *cv2;
+#endif
+ const patchCollide_t *pc;
+ facet_t *facet;
+ winding_t *w;
+ int i, j, k, n;
+ int curplanenum, planenum, curinward, inward;
+ float plane[4];
+ vec3_t mins = {-15, -15, -28}, maxs = {15, 15, 28};
+ //vec3_t mins = {0, 0, 0}, maxs = {0, 0, 0};
+ vec3_t v1, v2;
+
+#ifndef BSPC
+ if ( !cv2 )
+ {
+ cv2 = Cvar_Get( "r_debugSurface", "0", 0 );
+ }
+
+ if (cv2->integer != 1)
+ {
+ return;
+ }
+#endif
+
+ if ( !debugPatchCollide ) {
+ return;
+ }
+
+#ifndef BSPC
+ if ( !cv ) {
+ cv = Cvar_Get( "cm_debugSize", "2", 0 );
+ }
+#endif
+ pc = debugPatchCollide;
+
+ for ( i = 0, facet = pc->facets ; i < pc->numFacets ; i++, facet++ ) {
+
+ for ( k = 0 ; k < facet->numBorders + 1; k++ ) {
+ //
+ if (k < facet->numBorders) {
+ planenum = facet->borderPlanes[k];
+ inward = facet->borderInward[k];
+ }
+ else {
+ planenum = facet->surfacePlane;
+ inward = false;
+ //continue;
+ }
+
+ Vector4Copy( pc->planes[ planenum ].plane, plane );
+
+ //planenum = facet->surfacePlane;
+ if ( inward ) {
+ VectorSubtract( vec3_origin, plane, plane );
+ plane[3] = -plane[3];
+ }
+
+ plane[3] += cv->value;
+ //*
+ for (n = 0; n < 3; n++)
+ {
+ if (plane[n] > 0) v1[n] = maxs[n];
+ else v1[n] = mins[n];
+ } //end for
+ VectorNegate(plane, v2);
+ plane[3] += fabs(DotProduct(v1, v2));
+ //*/
+
+ w = BaseWindingForPlane( plane, plane[3] );
+ for ( j = 0 ; j < facet->numBorders + 1 && w; j++ ) {
+ //
+ if (j < facet->numBorders) {
+ curplanenum = facet->borderPlanes[j];
+ curinward = facet->borderInward[j];
+ }
+ else {
+ curplanenum = facet->surfacePlane;
+ curinward = false;
+ //continue;
+ }
+ //
+ if (curplanenum == planenum) continue;
+
+ Vector4Copy( pc->planes[ curplanenum ].plane, plane );
+ if ( !curinward ) {
+ VectorSubtract( vec3_origin, plane, plane );
+ plane[3] = -plane[3];
+ }
+ // if ( !facet->borderNoAdjust[j] ) {
+ plane[3] -= cv->value;
+ // }
+ for (n = 0; n < 3; n++)
+ {
+ if (plane[n] > 0) v1[n] = maxs[n];
+ else v1[n] = mins[n];
+ } //end for
+ VectorNegate(plane, v2);
+ plane[3] -= fabs(DotProduct(v1, v2));
+
+ ChopWindingInPlace( &w, plane, plane[3], 0.1f );
+ }
+ if ( w ) {
+ if ( facet == debugFacet ) {
+ drawPoly( 4, w->numpoints, w->p[0] );
+ //Com_Printf("blue facet has %d border planes\n", facet->numBorders);
+ } else {
+ drawPoly( 1, w->numpoints, w->p[0] );
+ }
+ FreeWinding( w );
+ }
+ else
+ Com_Printf("winding chopped away by border planes\n");
+ }
+ }
+
+ // draw the debug block
+ {
+ vec3_t v[3];
+
+ VectorCopy( debugBlockPoints[0], v[0] );
+ VectorCopy( debugBlockPoints[1], v[1] );
+ VectorCopy( debugBlockPoints[2], v[2] );
+ drawPoly( 2, 3, v[0] );
+
+ VectorCopy( debugBlockPoints[2], v[0] );
+ VectorCopy( debugBlockPoints[3], v[1] );
+ VectorCopy( debugBlockPoints[0], v[2] );
+ drawPoly( 2, 3, v[0] );
+ }
+
+#if 0
+ vec3_t v[4];
+
+ v[0][0] = pc->bounds[1][0];
+ v[0][1] = pc->bounds[1][1];
+ v[0][2] = pc->bounds[1][2];
+
+ v[1][0] = pc->bounds[1][0];
+ v[1][1] = pc->bounds[0][1];
+ v[1][2] = pc->bounds[1][2];
+
+ v[2][0] = pc->bounds[0][0];
+ v[2][1] = pc->bounds[0][1];
+ v[2][2] = pc->bounds[1][2];
+
+ v[3][0] = pc->bounds[0][0];
+ v[3][1] = pc->bounds[1][1];
+ v[3][2] = pc->bounds[1][2];
+
+ drawPoly( 4, v[0] );
+#endif
+}
diff --git a/src/qcommon/cm_patch.h b/src/qcommon/cm_patch.h
new file mode 100644
index 0000000..50e10af
--- /dev/null
+++ b/src/qcommon/cm_patch.h
@@ -0,0 +1,105 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+//#define CULL_BBOX
+
+/*
+
+This file does not reference any globals, and has these entry points:
+
+void CM_ClearLevelPatches( void );
+struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, const vec3_t *points );
+void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
+bool CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
+void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, flaot *points) );
+
+
+Issues for collision against curved surfaces:
+
+Surface edges need to be handled differently than surface planes
+
+Plane expansion causes raw surfaces to expand past expanded bounding box
+
+Position test of a volume against a surface is tricky.
+
+Position test of a point against a surface is not well defined, because the surface has no volume.
+
+
+Tracing leading edge points instead of volumes?
+Position test by tracing corner to corner? (8*7 traces -- ouch)
+
+coplanar edges
+triangulated patches
+degenerate patches
+
+ endcaps
+ degenerate
+
+WARNING: this may misbehave with meshes that have rows or columns that only
+degenerate a few triangles. Completely degenerate rows and columns are handled
+properly.
+*/
+
+
+#define MAX_FACETS 1024
+#define MAX_PATCH_PLANES 2048
+
+typedef struct {
+ float plane[4];
+ int signbits; // signx + (signy<<1) + (signz<<2), used as lookup during collision
+} patchPlane_t;
+
+typedef struct {
+ int surfacePlane;
+ int numBorders; // 3 or four + 6 axial bevels + 4 or 3 * 4 edge bevels
+ int borderPlanes[4+6+16];
+ int borderInward[4+6+16];
+ bool borderNoAdjust[4+6+16];
+} facet_t;
+
+typedef struct patchCollide_s {
+ vec3_t bounds[2];
+ int numPlanes; // surface planes plus edge planes
+ patchPlane_t *planes;
+ int numFacets;
+ facet_t *facets;
+} patchCollide_t;
+
+
+#define MAX_GRID_SIZE 129
+
+typedef struct {
+ int width;
+ int height;
+ bool wrapWidth;
+ bool wrapHeight;
+ vec3_t points[MAX_GRID_SIZE][MAX_GRID_SIZE]; // [width][height]
+} cGrid_t;
+
+#define SUBDIVIDE_DISTANCE 16 //4 // never more than this units away from curve
+#define PLANE_TRI_EPSILON 0.1
+#define WRAP_POINT_EPSILON 0.1
+
+
+struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, vec3_t *points );
diff --git a/src/qcommon/cm_polylib.cpp b/src/qcommon/cm_polylib.cpp
new file mode 100644
index 0000000..ca1c94c
--- /dev/null
+++ b/src/qcommon/cm_polylib.cpp
@@ -0,0 +1,737 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// this is only used for visualization tools in cm_ debug functions
+
+
+#include "cm_local.h"
+
+
+// counters are only bumped when running single threaded,
+// because they are an awful coherence problem
+int c_active_windings;
+int c_peak_windings;
+int c_winding_allocs;
+int c_winding_points;
+
+void pw(winding_t *w)
+{
+ int i;
+ for (i=0 ; i<w->numpoints ; i++)
+ printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
+}
+
+
+/*
+=============
+AllocWinding
+=============
+*/
+winding_t *AllocWinding (int points)
+{
+ winding_t *w;
+ int s;
+
+ c_winding_allocs++;
+ c_winding_points += points;
+ c_active_windings++;
+ if (c_active_windings > c_peak_windings)
+ c_peak_windings = c_active_windings;
+
+ s = sizeof(vec_t)*3*points + sizeof(int);
+ w = (winding_t*)Z_Malloc (s);
+ ::memset (w, 0, s);
+ return w;
+}
+
+void FreeWinding (winding_t *w)
+{
+ if (*(unsigned *)w == 0xdeaddead)
+ Com_Error (ERR_FATAL, "FreeWinding: freed a freed winding");
+ *(unsigned *)w = 0xdeaddead;
+
+ c_active_windings--;
+ Z_Free (w);
+}
+
+/*
+============
+RemoveColinearPoints
+============
+*/
+int c_removed;
+
+void RemoveColinearPoints (winding_t *w)
+{
+ int i, j, k;
+ vec3_t v1, v2;
+ int nump;
+ vec3_t p[MAX_POINTS_ON_WINDING];
+
+ nump = 0;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ j = (i+1)%w->numpoints;
+ k = (i+w->numpoints-1)%w->numpoints;
+ VectorSubtract (w->p[j], w->p[i], v1);
+ VectorSubtract (w->p[i], w->p[k], v2);
+ VectorNormalize2(v1,v1);
+ VectorNormalize2(v2,v2);
+ if (DotProduct(v1, v2) < 0.999)
+ {
+ VectorCopy (w->p[i], p[nump]);
+ nump++;
+ }
+ }
+
+ if (nump == w->numpoints)
+ return;
+
+ c_removed += w->numpoints - nump;
+ w->numpoints = nump;
+ ::memcpy (w->p, p, nump*sizeof(p[0]));
+}
+
+/*
+============
+WindingPlane
+============
+*/
+void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)
+{
+ vec3_t v1, v2;
+
+ VectorSubtract (w->p[1], w->p[0], v1);
+ VectorSubtract (w->p[2], w->p[0], v2);
+ CrossProduct (v2, v1, normal);
+ VectorNormalize2(normal, normal);
+ *dist = DotProduct (w->p[0], normal);
+
+}
+
+/*
+=============
+WindingArea
+=============
+*/
+vec_t WindingArea (winding_t *w)
+{
+ int i;
+ vec3_t d1, d2, cross;
+ vec_t total;
+
+ total = 0;
+ for (i=2 ; i<w->numpoints ; i++)
+ {
+ VectorSubtract (w->p[i-1], w->p[0], d1);
+ VectorSubtract (w->p[i], w->p[0], d2);
+ CrossProduct (d1, d2, cross);
+ total += 0.5 * VectorLength ( cross );
+ }
+ return total;
+}
+
+/*
+=============
+WindingBounds
+=============
+*/
+void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs)
+{
+ vec_t v;
+ int i,j;
+
+ mins[0] = mins[1] = mins[2] = MAX_MAP_BOUNDS;
+ maxs[0] = maxs[1] = maxs[2] = -MAX_MAP_BOUNDS;
+
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ v = w->p[i][j];
+ if (v < mins[j])
+ mins[j] = v;
+ if (v > maxs[j])
+ maxs[j] = v;
+ }
+ }
+}
+
+/*
+=============
+WindingCenter
+=============
+*/
+void WindingCenter (winding_t *w, vec3_t center)
+{
+ int i;
+ float scale;
+
+ VectorCopy (vec3_origin, center);
+ for (i=0 ; i<w->numpoints ; i++)
+ VectorAdd (w->p[i], center, center);
+
+ scale = 1.0/w->numpoints;
+ VectorScale (center, scale, center);
+}
+
+/*
+=================
+BaseWindingForPlane
+=================
+*/
+winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
+{
+ int i, x;
+ vec_t max, v;
+ vec3_t org, vright, vup;
+ winding_t *w;
+
+// find the major axis
+
+ max = -MAX_MAP_BOUNDS;
+ x = -1;
+ for (i=0 ; i<3; i++)
+ {
+ v = fabs(normal[i]);
+ if (v > max)
+ {
+ x = i;
+ max = v;
+ }
+ }
+ if (x==-1)
+ Com_Error (ERR_DROP, "BaseWindingForPlane: no axis found");
+
+ VectorCopy (vec3_origin, vup);
+ switch (x)
+ {
+ case 0:
+ case 1:
+ vup[2] = 1;
+ break;
+ case 2:
+ vup[0] = 1;
+ break;
+ }
+
+ v = DotProduct (vup, normal);
+ VectorMA (vup, -v, normal, vup);
+ VectorNormalize2(vup, vup);
+
+ VectorScale (normal, dist, org);
+
+ CrossProduct (vup, normal, vright);
+
+ VectorScale (vup, MAX_MAP_BOUNDS, vup);
+ VectorScale (vright, MAX_MAP_BOUNDS, vright);
+
+// project a really big axis aligned box onto the plane
+ w = AllocWinding (4);
+
+ VectorSubtract (org, vright, w->p[0]);
+ VectorAdd (w->p[0], vup, w->p[0]);
+
+ VectorAdd (org, vright, w->p[1]);
+ VectorAdd (w->p[1], vup, w->p[1]);
+
+ VectorAdd (org, vright, w->p[2]);
+ VectorSubtract (w->p[2], vup, w->p[2]);
+
+ VectorSubtract (org, vright, w->p[3]);
+ VectorSubtract (w->p[3], vup, w->p[3]);
+
+ w->numpoints = 4;
+
+ return w;
+}
+
+/*
+==================
+CopyWinding
+==================
+*/
+winding_t *CopyWinding (winding_t *w)
+{
+ intptr_t size;
+ winding_t *c;
+
+ c = AllocWinding (w->numpoints);
+ size = (intptr_t) ((winding_t *)0)->p[w->numpoints];
+ ::memcpy (c, w, size);
+ return c;
+}
+
+/*
+==================
+ReverseWinding
+==================
+*/
+winding_t *ReverseWinding (winding_t *w)
+{
+ int i;
+ winding_t *c;
+
+ c = AllocWinding (w->numpoints);
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
+ }
+ c->numpoints = w->numpoints;
+ return c;
+}
+
+
+/*
+=============
+ClipWindingEpsilon
+=============
+*/
+void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
+ vec_t epsilon, winding_t **front, winding_t **back)
+{
+ vec_t dists[MAX_POINTS_ON_WINDING+4] = { 0 };
+ int sides[MAX_POINTS_ON_WINDING+4] = { 0 };
+ int counts[3];
+ static vec_t dot; // VC 4.2 optimizer bug if not static
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+ winding_t *f, *b;
+ int maxpts;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+// determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->p[i], normal);
+ dot -= dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ *front = *back = NULL;
+
+ if (!counts[0])
+ {
+ *back = CopyWinding (in);
+ return;
+ }
+ if (!counts[1])
+ {
+ *front = CopyWinding (in);
+ return;
+ }
+
+ maxpts = in->numpoints+4; // cant use counts[0]+2 because
+ // of fp grouping errors
+
+ *front = f = AllocWinding (maxpts);
+ *back = b = AllocWinding (maxpts);
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ p1 = in->p[i];
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ VectorCopy (p1, b->p[b->numpoints]);
+ b->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ }
+ if (sides[i] == SIDE_BACK)
+ {
+ VectorCopy (p1, b->p[b->numpoints]);
+ b->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ // generate a split point
+ p2 = in->p[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (normal[j] == 1)
+ mid[j] = dist;
+ else if (normal[j] == -1)
+ mid[j] = -dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, f->p[f->numpoints]);
+ f->numpoints++;
+ VectorCopy (mid, b->p[b->numpoints]);
+ b->numpoints++;
+ }
+
+ if (f->numpoints > maxpts || b->numpoints > maxpts)
+ Com_Error (ERR_DROP, "ClipWinding: points exceeded estimate");
+ if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
+ Com_Error (ERR_DROP, "ClipWinding: MAX_POINTS_ON_WINDING");
+}
+
+
+/*
+=============
+ChopWindingInPlace
+=============
+*/
+void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon)
+{
+ winding_t *in;
+ vec_t dists[MAX_POINTS_ON_WINDING+4] = { 0 };
+ int sides[MAX_POINTS_ON_WINDING+4] = { 0 };
+ int counts[3];
+ static vec_t dot; // VC 4.2 optimizer bug if not static
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+ winding_t *f;
+ int maxpts;
+
+ in = *inout;
+ counts[0] = counts[1] = counts[2] = 0;
+
+// determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->p[i], normal);
+ dot -= dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ if (!counts[0])
+ {
+ FreeWinding (in);
+ *inout = NULL;
+ return;
+ }
+ if (!counts[1])
+ return; // inout stays the same
+
+ maxpts = in->numpoints+4; // cant use counts[0]+2 because
+ // of fp grouping errors
+
+ f = AllocWinding (maxpts);
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ p1 = in->p[i];
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ // generate a split point
+ p2 = in->p[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (normal[j] == 1)
+ mid[j] = dist;
+ else if (normal[j] == -1)
+ mid[j] = -dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, f->p[f->numpoints]);
+ f->numpoints++;
+ }
+
+ if (f->numpoints > maxpts)
+ Com_Error (ERR_DROP, "ClipWinding: points exceeded estimate");
+ if (f->numpoints > MAX_POINTS_ON_WINDING)
+ Com_Error (ERR_DROP, "ClipWinding: MAX_POINTS_ON_WINDING");
+
+ FreeWinding (in);
+ *inout = f;
+}
+
+
+/*
+=================
+ChopWinding
+
+Returns the fragment of in that is on the front side
+of the cliping plane. The original is freed.
+=================
+*/
+winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
+{
+ winding_t *f, *b;
+
+ ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
+ FreeWinding (in);
+ if (b)
+ FreeWinding (b);
+ return f;
+}
+
+
+/*
+=================
+CheckWinding
+
+=================
+*/
+void CheckWinding (winding_t *w)
+{
+ int i, j;
+ vec_t *p1, *p2;
+ vec_t d, edgedist;
+ vec3_t dir, edgenormal, facenormal;
+ vec_t area;
+ vec_t facedist;
+
+ if (w->numpoints < 3)
+ Com_Error (ERR_DROP, "CheckWinding: %i points",w->numpoints);
+
+ area = WindingArea(w);
+ if (area < 1)
+ Com_Error (ERR_DROP, "CheckWinding: %f area", area);
+
+ WindingPlane (w, facenormal, &facedist);
+
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ p1 = w->p[i];
+
+ for (j=0 ; j<3 ; j++)
+ if (p1[j] > MAX_MAP_BOUNDS || p1[j] < -MAX_MAP_BOUNDS)
+ Com_Error (ERR_DROP, "CheckFace: BUGUS_RANGE: %f",p1[j]);
+
+ j = i+1 == w->numpoints ? 0 : i+1;
+
+ // check the point is on the face plane
+ d = DotProduct (p1, facenormal) - facedist;
+ if (d < -ON_EPSILON || d > ON_EPSILON)
+ Com_Error (ERR_DROP, "CheckWinding: point off plane");
+
+ // check the edge isnt degenerate
+ p2 = w->p[j];
+ VectorSubtract (p2, p1, dir);
+
+ if (VectorLength (dir) < ON_EPSILON)
+ Com_Error (ERR_DROP, "CheckWinding: degenerate edge");
+
+ CrossProduct (facenormal, dir, edgenormal);
+ VectorNormalize2 (edgenormal, edgenormal);
+ edgedist = DotProduct (p1, edgenormal);
+ edgedist += ON_EPSILON;
+
+ // all other points must be on front side
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ if (j == i)
+ continue;
+ d = DotProduct (w->p[j], edgenormal);
+ if (d > edgedist)
+ Com_Error (ERR_DROP, "CheckWinding: non-convex");
+ }
+ }
+}
+
+
+/*
+============
+WindingOnPlaneSide
+============
+*/
+int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)
+{
+ bool front, back;
+ int i;
+ vec_t d;
+
+ front = false;
+ back = false;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ d = DotProduct (w->p[i], normal) - dist;
+ if (d < -ON_EPSILON)
+ {
+ if (front)
+ return SIDE_CROSS;
+ back = true;
+ continue;
+ }
+ if (d > ON_EPSILON)
+ {
+ if (back)
+ return SIDE_CROSS;
+ front = true;
+ continue;
+ }
+ }
+
+ if (back)
+ return SIDE_BACK;
+ if (front)
+ return SIDE_FRONT;
+ return SIDE_ON;
+}
+
+
+/*
+=================
+AddWindingToConvexHull
+
+Both w and *hull are on the same plane
+=================
+*/
+#define MAX_HULL_POINTS 128
+void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) {
+ int i, j, k;
+ float *p, *copy;
+ vec3_t dir;
+ float d;
+ int numHullPoints, numNew;
+ vec3_t hullPoints[MAX_HULL_POINTS];
+ vec3_t newHullPoints[MAX_HULL_POINTS];
+ vec3_t hullDirs[MAX_HULL_POINTS];
+ bool hullSide[MAX_HULL_POINTS];
+ bool outside;
+
+ if ( !*hull ) {
+ *hull = CopyWinding( w );
+ return;
+ }
+
+ numHullPoints = (*hull)->numpoints;
+ ::memcpy( hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t) );
+
+ for ( i = 0 ; i < w->numpoints ; i++ ) {
+ p = w->p[i];
+
+ // calculate hull side vectors
+ for ( j = 0 ; j < numHullPoints ; j++ ) {
+ k = ( j + 1 ) % numHullPoints;
+
+ VectorSubtract( hullPoints[k], hullPoints[j], dir );
+ VectorNormalize2( dir, dir );
+ CrossProduct( normal, dir, hullDirs[j] );
+ }
+
+ outside = false;
+ for ( j = 0 ; j < numHullPoints ; j++ ) {
+ VectorSubtract( p, hullPoints[j], dir );
+ d = DotProduct( dir, hullDirs[j] );
+ if ( d >= ON_EPSILON ) {
+ outside = true;
+ }
+ if ( d >= -ON_EPSILON ) {
+ hullSide[j] = true;
+ } else {
+ hullSide[j] = false;
+ }
+ }
+
+ // if the point is effectively inside, do nothing
+ if ( !outside ) {
+ continue;
+ }
+
+ // find the back side to front side transition
+ for ( j = 0 ; j < numHullPoints ; j++ ) {
+ if ( !hullSide[ j % numHullPoints ] && hullSide[ (j + 1) % numHullPoints ] ) {
+ break;
+ }
+ }
+ if ( j == numHullPoints ) {
+ continue;
+ }
+
+ // insert the point here
+ VectorCopy( p, newHullPoints[0] );
+ numNew = 1;
+
+ // copy over all points that aren't double fronts
+ j = (j+1)%numHullPoints;
+ for ( k = 0 ; k < numHullPoints ; k++ ) {
+ if ( hullSide[ (j+k) % numHullPoints ] && hullSide[ (j+k+1) % numHullPoints ] ) {
+ continue;
+ }
+ copy = hullPoints[ (j+k+1) % numHullPoints ];
+ VectorCopy( copy, newHullPoints[numNew] );
+ numNew++;
+ }
+
+ numHullPoints = numNew;
+ ::memcpy( hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t) );
+ }
+
+ FreeWinding( *hull );
+ w = AllocWinding( numHullPoints );
+ w->numpoints = numHullPoints;
+ *hull = w;
+ ::memcpy( w->p, hullPoints, numHullPoints * sizeof(vec3_t) );
+}
diff --git a/src/qcommon/cm_polylib.h b/src/qcommon/cm_polylib.h
new file mode 100644
index 0000000..0a04bd6
--- /dev/null
+++ b/src/qcommon/cm_polylib.h
@@ -0,0 +1,74 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// this is only used for visualization tools in cm_ debug functions
+
+#ifndef CM_POLYLIB_H
+#define CM_POLYLIB_H 1
+
+typedef struct
+{
+ int numpoints;
+ vec3_t p[4]; // variable sized
+} winding_t;
+
+#define MAX_POINTS_ON_WINDING 64
+
+#define SIDE_FRONT 0
+#define SIDE_BACK 1
+#define SIDE_ON 2
+#define SIDE_CROSS 3
+
+#define CLIP_EPSILON 0.1f
+
+#define MAX_MAP_BOUNDS 65535
+
+// you can define on_epsilon in the makefile as tighter
+#ifndef ON_EPSILON
+#define ON_EPSILON 0.1f
+#endif
+
+winding_t *AllocWinding (int points);
+vec_t WindingArea (winding_t *w);
+void WindingCenter (winding_t *w, vec3_t center);
+void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, vec_t epsilon, winding_t **front, winding_t **back);
+winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist);
+winding_t *CopyWinding (winding_t *w);
+winding_t *ReverseWinding (winding_t *w);
+winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
+void CheckWinding (winding_t *w);
+void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist);
+void RemoveColinearPoints (winding_t *w);
+int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist);
+void FreeWinding (winding_t *w);
+void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);
+
+void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal );
+
+void ChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon);
+// frees the original if clipped
+
+void pw(winding_t *w);
+
+#endif
diff --git a/src/qcommon/cm_public.h b/src/qcommon/cm_public.h
new file mode 100644
index 0000000..5b3a46f
--- /dev/null
+++ b/src/qcommon/cm_public.h
@@ -0,0 +1,79 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#ifndef _CM_PUBLIC_H_
+#define _CM_PUBLIC_H_
+
+#include "qfiles.h"
+
+void CM_LoadMap( const char *name, bool clientload, int *checksum);
+void CM_ClearMap( void );
+clipHandle_t CM_InlineModel( int index ); // 0 = world, 1 + are bmodels
+clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs, int capsule );
+
+void CM_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
+
+int CM_NumClusters (void);
+int CM_NumInlineModels( void );
+char *CM_EntityString (void);
+
+// returns an ORed contents mask
+int CM_PointContents( const vec3_t p, clipHandle_t model );
+int CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles );
+
+void CM_BoxTrace ( trace_t *results, const vec3_t start, const vec3_t end,
+ vec3_t mins, vec3_t maxs,
+ clipHandle_t model, int brushmask, traceType_t type );
+void CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ vec3_t mins, vec3_t maxs,
+ clipHandle_t model, int brushmask,
+ const vec3_t origin, const vec3_t angles, traceType_t type );
+void CM_BiSphereTrace( trace_t *results, const vec3_t start,
+ const vec3_t end, float startRad, float endRad,
+ clipHandle_t model, int mask );
+void CM_TransformedBiSphereTrace( trace_t *results, const vec3_t start,
+ const vec3_t end, float startRad, float endRad,
+ clipHandle_t model, int mask,
+ const vec3_t origin );
+
+byte *CM_ClusterPVS (int cluster);
+
+int CM_PointLeafnum( const vec3_t p );
+
+// only returns non-solid leafs
+// overflow if return listsize and if *lastLeaf != list[listsize-1]
+int CM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, int *list,
+ int listsize, int *lastLeaf );
+
+int CM_LeafCluster (int leafnum);
+int CM_LeafArea (int leafnum);
+
+void CM_AdjustAreaPortalState( int area1, int area2, bool open );
+bool CM_AreasConnected( int area1, int area2 );
+
+int CM_WriteAreaBits( byte *buffer, int area );
+
+// cm_patch.c
+void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *points) );
+
+#endif
diff --git a/src/qcommon/cm_test.cpp b/src/qcommon/cm_test.cpp
new file mode 100644
index 0000000..b7f8b8f
--- /dev/null
+++ b/src/qcommon/cm_test.cpp
@@ -0,0 +1,526 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "cm_local.h"
+
+/*
+==================
+CM_PointLeafnum_r
+
+==================
+*/
+int CM_PointLeafnum_r( const vec3_t p, int num ) {
+ float d;
+ cNode_t *node;
+ cplane_t *plane;
+
+ while (num >= 0)
+ {
+ node = cm.nodes + num;
+ plane = node->plane;
+
+ if (plane->type < 3)
+ d = p[plane->type] - plane->dist;
+ else
+ d = DotProduct (plane->normal, p) - plane->dist;
+ if (d < 0)
+ num = node->children[1];
+ else
+ num = node->children[0];
+ }
+
+ c_pointcontents++; // optimize counter
+
+ return -1 - num;
+}
+
+int CM_PointLeafnum( const vec3_t p ) {
+ if ( !cm.numNodes ) { // map not loaded
+ return 0;
+ }
+ return CM_PointLeafnum_r (p, 0);
+}
+
+
+/*
+======================================================================
+
+LEAF LISTING
+
+======================================================================
+*/
+
+
+void CM_StoreLeafs( leafList_t *ll, int nodenum ) {
+ int leafNum;
+
+ leafNum = -1 - nodenum;
+
+ // store the lastLeaf even if the list is overflowed
+ if ( cm.leafs[ leafNum ].cluster != -1 ) {
+ ll->lastLeaf = leafNum;
+ }
+
+ if ( ll->count >= ll->maxcount) {
+ ll->overflowed = true;
+ return;
+ }
+ ll->list[ ll->count++ ] = leafNum;
+}
+
+void CM_StoreBrushes( leafList_t *ll, int nodenum ) {
+ int i, k;
+ int leafnum;
+ int brushnum;
+ cLeaf_t *leaf;
+ cbrush_t *b;
+
+ leafnum = -1 - nodenum;
+
+ leaf = &cm.leafs[leafnum];
+
+ for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
+ brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
+ b = &cm.brushes[brushnum];
+ if ( b->checkcount == cm.checkcount ) {
+ continue; // already checked this brush in another leaf
+ }
+ b->checkcount = cm.checkcount;
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( b->bounds[0][i] >= ll->bounds[1][i] || b->bounds[1][i] <= ll->bounds[0][i] ) {
+ break;
+ }
+ }
+ if ( i != 3 ) {
+ continue;
+ }
+ if ( ll->count >= ll->maxcount) {
+ ll->overflowed = true;
+ return;
+ }
+ ((cbrush_t **)ll->list)[ ll->count++ ] = b;
+ }
+#if 0
+ // store patches?
+ for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
+ patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstleafsurface + k ] ];
+ if ( !patch ) {
+ continue;
+ }
+ }
+#endif
+}
+
+/*
+=============
+CM_BoxLeafnums
+
+Fills in a list of all the leafs touched
+=============
+*/
+void CM_BoxLeafnums_r( leafList_t *ll, int nodenum ) {
+ cplane_t *plane;
+ cNode_t *node;
+ int s;
+
+ while (1) {
+ if (nodenum < 0) {
+ ll->storeLeafs( ll, nodenum );
+ return;
+ }
+
+ node = &cm.nodes[nodenum];
+ plane = node->plane;
+ s = BoxOnPlaneSide( ll->bounds[0], ll->bounds[1], plane );
+ if (s == 1) {
+ nodenum = node->children[0];
+ } else if (s == 2) {
+ nodenum = node->children[1];
+ } else {
+ // go down both
+ CM_BoxLeafnums_r( ll, node->children[0] );
+ nodenum = node->children[1];
+ }
+
+ }
+}
+
+/*
+==================
+CM_BoxLeafnums
+==================
+*/
+int CM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, int *list, int listsize, int *lastLeaf) {
+ leafList_t ll;
+
+ cm.checkcount++;
+
+ VectorCopy( mins, ll.bounds[0] );
+ VectorCopy( maxs, ll.bounds[1] );
+ ll.count = 0;
+ ll.maxcount = listsize;
+ ll.list = list;
+ ll.storeLeafs = CM_StoreLeafs;
+ ll.lastLeaf = 0;
+ ll.overflowed = false;
+
+ CM_BoxLeafnums_r( &ll, 0 );
+
+ *lastLeaf = ll.lastLeaf;
+ return ll.count;
+}
+
+/*
+==================
+CM_BoxBrushes
+==================
+*/
+int CM_BoxBrushes( const vec3_t mins, const vec3_t maxs, cbrush_t **list, int listsize ) {
+ leafList_t ll;
+
+ cm.checkcount++;
+
+ VectorCopy( mins, ll.bounds[0] );
+ VectorCopy( maxs, ll.bounds[1] );
+ ll.count = 0;
+ ll.maxcount = listsize;
+ ll.list = (int *)list;
+ ll.storeLeafs = CM_StoreBrushes;
+ ll.lastLeaf = 0;
+ ll.overflowed = false;
+
+ CM_BoxLeafnums_r( &ll, 0 );
+
+ return ll.count;
+}
+
+
+//====================================================================
+
+
+/*
+==================
+CM_PointContents
+
+==================
+*/
+int CM_PointContents( const vec3_t p, clipHandle_t model ) {
+ int leafnum;
+ int i, k;
+ int brushnum;
+ cLeaf_t *leaf;
+ cbrush_t *b;
+ int contents;
+ float d;
+ cmodel_t *clipm;
+
+ if (!cm.numNodes) { // map not loaded
+ return 0;
+ }
+
+ if ( model ) {
+ clipm = CM_ClipHandleToModel( model );
+ leaf = &clipm->leaf;
+ } else {
+ leafnum = CM_PointLeafnum_r (p, 0);
+ leaf = &cm.leafs[leafnum];
+ }
+
+ if(leaf->area == -1)
+ return CONTENTS_SOLID;
+
+ contents = 0;
+ for (k=0 ; k<leaf->numLeafBrushes ; k++) {
+ brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
+ b = &cm.brushes[brushnum];
+
+ if ( !CM_BoundsIntersectPoint( b->bounds[0], b->bounds[1], p ) ) {
+ continue;
+ }
+
+ // see if the point is in the brush
+ for ( i = 0 ; i < b->numsides ; i++ ) {
+ d = DotProduct( p, b->sides[i].plane->normal );
+// FIXME test for Cash
+// if ( d >= b->sides[i].plane->dist ) {
+ if ( d > b->sides[i].plane->dist ) {
+ break;
+ }
+ }
+
+ if ( i == b->numsides ) {
+ contents |= b->contents;
+ }
+ }
+
+ return contents;
+}
+
+/*
+==================
+CM_TransformedPointContents
+
+Handles offseting and rotation of the end points for moving and
+rotating entities
+==================
+*/
+int CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles) {
+ vec3_t p_l;
+ vec3_t temp;
+ vec3_t forward, right, up;
+
+ // subtract origin offset
+ VectorSubtract (p, origin, p_l);
+
+ // rotate start and end into the models frame of reference
+ if ( model != BOX_MODEL_HANDLE &&
+ (angles[0] || angles[1] || angles[2]) )
+ {
+ AngleVectors (angles, forward, right, up);
+
+ VectorCopy (p_l, temp);
+ p_l[0] = DotProduct (temp, forward);
+ p_l[1] = -DotProduct (temp, right);
+ p_l[2] = DotProduct (temp, up);
+ }
+
+ return CM_PointContents( p_l, model );
+}
+
+
+
+/*
+===============================================================================
+
+PVS
+
+===============================================================================
+*/
+
+byte *CM_ClusterPVS (int cluster) {
+ if (cluster < 0 || cluster >= cm.numClusters || !cm.vised ) {
+ return cm.visibility;
+ }
+
+ return cm.visibility + cluster * cm.clusterBytes;
+}
+
+
+
+/*
+===============================================================================
+
+AREAPORTALS
+
+===============================================================================
+*/
+
+void CM_FloodArea_r( int areaNum, int floodnum) {
+ int i;
+ cArea_t *area;
+ int *con;
+
+ area = &cm.areas[ areaNum ];
+
+ if ( area->floodvalid == cm.floodvalid ) {
+ if (area->floodnum == floodnum)
+ return;
+ Com_Error (ERR_DROP, "FloodArea_r: reflooded");
+ }
+
+ area->floodnum = floodnum;
+ area->floodvalid = cm.floodvalid;
+ con = cm.areaPortals + areaNum * cm.numAreas;
+ for ( i=0 ; i < cm.numAreas ; i++ ) {
+ if ( con[i] > 0 ) {
+ CM_FloodArea_r( i, floodnum );
+ }
+ }
+}
+
+/*
+====================
+CM_FloodAreaConnections
+
+====================
+*/
+void CM_FloodAreaConnections( void ) {
+ int i;
+ cArea_t *area;
+ int floodnum;
+
+ // all current floods are now invalid
+ cm.floodvalid++;
+ floodnum = 0;
+
+ for (i = 0 ; i < cm.numAreas ; i++) {
+ area = &cm.areas[i];
+ if (area->floodvalid == cm.floodvalid) {
+ continue; // already flooded into
+ }
+ floodnum++;
+ CM_FloodArea_r (i, floodnum);
+ }
+
+}
+
+/*
+====================
+CM_AdjustAreaPortalState
+
+====================
+*/
+void CM_AdjustAreaPortalState( int area1, int area2, bool open ) {
+ if ( area1 < 0 || area2 < 0 ) {
+ return;
+ }
+
+ if ( area1 >= cm.numAreas || area2 >= cm.numAreas ) {
+ Com_Error (ERR_DROP, "CM_ChangeAreaPortalState: bad area number");
+ }
+
+ if ( open ) {
+ cm.areaPortals[ area1 * cm.numAreas + area2 ]++;
+ cm.areaPortals[ area2 * cm.numAreas + area1 ]++;
+ } else {
+ cm.areaPortals[ area1 * cm.numAreas + area2 ]--;
+ cm.areaPortals[ area2 * cm.numAreas + area1 ]--;
+ if ( cm.areaPortals[ area2 * cm.numAreas + area1 ] < 0 ) {
+ Com_Error (ERR_DROP, "CM_AdjustAreaPortalState: negative reference count");
+ }
+ }
+
+ CM_FloodAreaConnections ();
+}
+
+/*
+====================
+CM_AreasConnected
+
+====================
+*/
+bool CM_AreasConnected( int area1, int area2 ) {
+#ifndef BSPC
+ if ( cm_noAreas->integer ) {
+ return true;
+ }
+#endif
+
+ if ( area1 < 0 || area2 < 0 ) {
+ return false;
+ }
+
+ if (area1 >= cm.numAreas || area2 >= cm.numAreas) {
+ Com_Error (ERR_DROP, "area >= cm.numAreas");
+ }
+
+ if (cm.areas[area1].floodnum == cm.areas[area2].floodnum) {
+ return true;
+ }
+ return false;
+}
+
+
+/*
+=================
+CM_WriteAreaBits
+
+Writes a bit vector of all the areas
+that are in the same flood as the area parameter
+Returns the number of bytes needed to hold all the bits.
+
+The bits are OR'd in, so you can CM_WriteAreaBits from multiple
+viewpoints and get the union of all visible areas.
+
+This is used to cull non-visible entities from snapshots
+=================
+*/
+int CM_WriteAreaBits (byte *buffer, int area)
+{
+ int i;
+ int floodnum;
+ int bytes;
+
+ bytes = (cm.numAreas+7)>>3;
+
+#ifndef BSPC
+ if (cm_noAreas->integer || area == -1)
+#else
+ if ( area == -1)
+#endif
+ { // for debugging, send everything
+ ::memset (buffer, 255, bytes);
+ }
+ else
+ {
+ floodnum = cm.areas[area].floodnum;
+ for (i=0 ; i<cm.numAreas ; i++)
+ {
+ if (cm.areas[i].floodnum == floodnum || area == -1)
+ buffer[i>>3] |= 1<<(i&7);
+ }
+ }
+
+ return bytes;
+}
+
+/*
+====================
+CM_BoundsIntersect
+====================
+*/
+bool CM_BoundsIntersect( const vec3_t mins, const vec3_t maxs, const vec3_t mins2, const vec3_t maxs2 )
+{
+ if (maxs[0] < mins2[0] - SURFACE_CLIP_EPSILON ||
+ maxs[1] < mins2[1] - SURFACE_CLIP_EPSILON ||
+ maxs[2] < mins2[2] - SURFACE_CLIP_EPSILON ||
+ mins[0] > maxs2[0] + SURFACE_CLIP_EPSILON ||
+ mins[1] > maxs2[1] + SURFACE_CLIP_EPSILON ||
+ mins[2] > maxs2[2] + SURFACE_CLIP_EPSILON)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+====================
+CM_BoundsIntersectPoint
+====================
+*/
+bool CM_BoundsIntersectPoint( const vec3_t mins, const vec3_t maxs, const vec3_t point )
+{
+ if (maxs[0] < point[0] - SURFACE_CLIP_EPSILON ||
+ maxs[1] < point[1] - SURFACE_CLIP_EPSILON ||
+ maxs[2] < point[2] - SURFACE_CLIP_EPSILON ||
+ mins[0] > point[0] + SURFACE_CLIP_EPSILON ||
+ mins[1] > point[1] + SURFACE_CLIP_EPSILON ||
+ mins[2] > point[2] + SURFACE_CLIP_EPSILON)
+ {
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/qcommon/cm_trace.cpp b/src/qcommon/cm_trace.cpp
new file mode 100644
index 0000000..b773f2a
--- /dev/null
+++ b/src/qcommon/cm_trace.cpp
@@ -0,0 +1,1801 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "cm_local.h"
+
+// always use bbox vs. bbox collision and never capsule vs. bbox or vice versa
+//#define ALWAYS_BBOX_VS_BBOX
+// always use capsule vs. capsule collision and never capsule vs. bbox or vice versa
+//#define ALWAYS_CAPSULE_VS_CAPSULE
+
+//#define CAPSULE_DEBUG
+
+/*
+===============================================================================
+
+BASIC MATH
+
+===============================================================================
+*/
+
+/*
+================
+RotatePoint
+================
+*/
+void RotatePoint(vec3_t point, /*const*/ vec3_t matrix[3]) { // FIXME
+ vec3_t tvec;
+
+ VectorCopy(point, tvec);
+ point[0] = DotProduct(matrix[0], tvec);
+ point[1] = DotProduct(matrix[1], tvec);
+ point[2] = DotProduct(matrix[2], tvec);
+}
+
+/*
+================
+TransposeMatrix
+================
+*/
+void TransposeMatrix(/*const*/ vec3_t matrix[3], vec3_t transpose[3]) { // FIXME
+ int i, j;
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ transpose[i][j] = matrix[j][i];
+ }
+ }
+}
+
+/*
+================
+CreateRotationMatrix
+================
+*/
+void CreateRotationMatrix(const vec3_t angles, vec3_t matrix[3]) {
+ AngleVectors(angles, matrix[0], matrix[1], matrix[2]);
+ VectorInverse(matrix[1]);
+}
+
+/*
+================
+CM_ProjectPointOntoVector
+================
+*/
+void CM_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vDir, vec3_t vProj )
+{
+ vec3_t pVec;
+
+ VectorSubtract( point, vStart, pVec );
+ // project onto the directional vector for this segment
+ VectorMA( vStart, DotProduct( pVec, vDir ), vDir, vProj );
+}
+
+/*
+================
+CM_DistanceFromLineSquared
+================
+*/
+float CM_DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2, vec3_t dir) {
+ vec3_t proj, t;
+ int j;
+
+ CM_ProjectPointOntoVector(p, lp1, dir, proj);
+ for (j = 0; j < 3; j++)
+ if ((proj[j] > lp1[j] && proj[j] > lp2[j]) ||
+ (proj[j] < lp1[j] && proj[j] < lp2[j]))
+ break;
+ if (j < 3) {
+ if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j]))
+ VectorSubtract(p, lp1, t);
+ else
+ VectorSubtract(p, lp2, t);
+ return VectorLengthSquared(t);
+ }
+ VectorSubtract(p, proj, t);
+ return VectorLengthSquared(t);
+}
+
+/*
+================
+CM_VectorDistanceSquared
+================
+*/
+float CM_VectorDistanceSquared(vec3_t p1, vec3_t p2) {
+ vec3_t dir;
+
+ VectorSubtract(p2, p1, dir);
+ return VectorLengthSquared(dir);
+}
+
+/*
+================
+SquareRootFloat
+================
+*/
+float SquareRootFloat(float number) {
+ floatint_t t;
+ float x, y;
+ const float f = 1.5F;
+
+ x = number * 0.5F;
+ t.f = number;
+ t.i = 0x5f3759df - ( t.i >> 1 );
+ y = t.f;
+ y = y * ( f - ( x * y * y ) );
+ y = y * ( f - ( x * y * y ) );
+ return number * y;
+}
+
+
+/*
+===============================================================================
+
+POSITION TESTING
+
+===============================================================================
+*/
+
+/*
+================
+CM_TestBoxInBrush
+================
+*/
+void CM_TestBoxInBrush( traceWork_t *tw, cbrush_t *brush ) {
+ int i;
+ cplane_t *plane;
+ float dist;
+ float d1;
+ cbrushside_t *side;
+ float t;
+ vec3_t startp;
+
+ if (!brush->numsides) {
+ return;
+ }
+
+ // special test for axial
+ if ( tw->bounds[0][0] > brush->bounds[1][0]
+ || tw->bounds[0][1] > brush->bounds[1][1]
+ || tw->bounds[0][2] > brush->bounds[1][2]
+ || tw->bounds[1][0] < brush->bounds[0][0]
+ || tw->bounds[1][1] < brush->bounds[0][1]
+ || tw->bounds[1][2] < brush->bounds[0][2]
+ ) {
+ return;
+ }
+
+ if ( tw->type == TT_CAPSULE ) {
+ // the first six planes are the axial planes, so we only
+ // need to test the remainder
+ for ( i = 6 ; i < brush->numsides ; i++ ) {
+ side = brush->sides + i;
+ plane = side->plane;
+
+ // adjust the plane distance apropriately for radius
+ dist = plane->dist + tw->sphere.radius;
+ // find the closest point on the capsule to the plane
+ t = DotProduct( plane->normal, tw->sphere.offset );
+ if ( t > 0 )
+ {
+ VectorSubtract( tw->start, tw->sphere.offset, startp );
+ }
+ else
+ {
+ VectorAdd( tw->start, tw->sphere.offset, startp );
+ }
+ d1 = DotProduct( startp, plane->normal ) - dist;
+ // if completely in front of face, no intersection
+ if ( d1 > 0 ) {
+ return;
+ }
+ }
+ } else {
+ // the first six planes are the axial planes, so we only
+ // need to test the remainder
+ for ( i = 6 ; i < brush->numsides ; i++ ) {
+ side = brush->sides + i;
+ plane = side->plane;
+
+ // adjust the plane distance apropriately for mins/maxs
+ dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );
+
+ d1 = DotProduct( tw->start, plane->normal ) - dist;
+
+ // if completely in front of face, no intersection
+ if ( d1 > 0 ) {
+ return;
+ }
+ }
+ }
+
+ // inside this brush
+ tw->trace.startsolid = tw->trace.allsolid = qtrue;
+ tw->trace.fraction = 0;
+ tw->trace.contents = brush->contents;
+}
+
+
+
+/*
+================
+CM_TestInLeaf
+================
+*/
+void CM_TestInLeaf( traceWork_t *tw, cLeaf_t *leaf ) {
+ int k;
+ int brushnum;
+ cbrush_t *b;
+ cPatch_t *patch;
+
+ // test box position against all brushes in the leaf
+ for (k=0 ; k<leaf->numLeafBrushes ; k++) {
+ brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
+ b = &cm.brushes[brushnum];
+ if (b->checkcount == cm.checkcount) {
+ continue; // already checked this brush in another leaf
+ }
+ b->checkcount = cm.checkcount;
+
+ if ( !(b->contents & tw->contents)) {
+ continue;
+ }
+
+ CM_TestBoxInBrush( tw, b );
+ if ( tw->trace.allsolid ) {
+ return;
+ }
+ }
+
+ // test against all patches
+#ifdef BSPC
+ if (1) {
+#else
+ if ( !cm_noCurves->integer ) {
+#endif //BSPC
+ for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
+ patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];
+ if ( !patch ) {
+ continue;
+ }
+ if ( patch->checkcount == cm.checkcount ) {
+ continue; // already checked this brush in another leaf
+ }
+ patch->checkcount = cm.checkcount;
+
+ if ( !(patch->contents & tw->contents)) {
+ continue;
+ }
+
+ if ( CM_PositionTestInPatchCollide( tw, patch->pc ) ) {
+ tw->trace.startsolid = tw->trace.allsolid = qtrue;
+ tw->trace.fraction = 0;
+ tw->trace.contents = patch->contents;
+ return;
+ }
+ }
+ }
+}
+
+/*
+==================
+CM_TestCapsuleInCapsule
+
+capsule inside capsule check
+==================
+*/
+void CM_TestCapsuleInCapsule( traceWork_t *tw, clipHandle_t model ) {
+ int i;
+ vec3_t mins, maxs;
+ vec3_t top, bottom;
+ vec3_t p1, p2, tmp;
+ vec3_t offset, symetricSize[2];
+ float radius, halfwidth, halfheight, offs, r;
+
+ CM_ModelBounds(model, mins, maxs);
+
+ VectorAdd(tw->start, tw->sphere.offset, top);
+ VectorSubtract(tw->start, tw->sphere.offset, bottom);
+ for ( i = 0 ; i < 3 ; i++ ) {
+ offset[i] = ( mins[i] + maxs[i] ) * 0.5;
+ symetricSize[0][i] = mins[i] - offset[i];
+ symetricSize[1][i] = maxs[i] - offset[i];
+ }
+ halfwidth = symetricSize[ 1 ][ 0 ];
+ halfheight = symetricSize[ 1 ][ 2 ];
+ radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
+ offs = halfheight - radius;
+
+ r = Square(tw->sphere.radius + radius);
+ // check if any of the spheres overlap
+ VectorCopy(offset, p1);
+ p1[2] += offs;
+ VectorSubtract(p1, top, tmp);
+ if ( VectorLengthSquared(tmp) < r ) {
+ tw->trace.startsolid = tw->trace.allsolid = qtrue;
+ tw->trace.fraction = 0;
+ }
+ VectorSubtract(p1, bottom, tmp);
+ if ( VectorLengthSquared(tmp) < r ) {
+ tw->trace.startsolid = tw->trace.allsolid = qtrue;
+ tw->trace.fraction = 0;
+ }
+ VectorCopy(offset, p2);
+ p2[2] -= offs;
+ VectorSubtract(p2, top, tmp);
+ if ( VectorLengthSquared(tmp) < r ) {
+ tw->trace.startsolid = tw->trace.allsolid = qtrue;
+ tw->trace.fraction = 0;
+ }
+ VectorSubtract(p2, bottom, tmp);
+ if ( VectorLengthSquared(tmp) < r ) {
+ tw->trace.startsolid = tw->trace.allsolid = qtrue;
+ tw->trace.fraction = 0;
+ }
+ // if between cylinder up and lower bounds
+ if ( (top[2] >= p1[2] && top[2] <= p2[2]) ||
+ (bottom[2] >= p1[2] && bottom[2] <= p2[2]) ) {
+ // 2d coordinates
+ top[2] = p1[2] = 0;
+ // if the cylinders overlap
+ VectorSubtract(top, p1, tmp);
+ if ( VectorLengthSquared(tmp) < r ) {
+ tw->trace.startsolid = tw->trace.allsolid = qtrue;
+ tw->trace.fraction = 0;
+ }
+ }
+}
+
+/*
+==================
+CM_TestBoundingBoxInCapsule
+
+bounding box inside capsule check
+==================
+*/
+void CM_TestBoundingBoxInCapsule( traceWork_t *tw, clipHandle_t model ) {
+ vec3_t mins, maxs, offset, size[2];
+ clipHandle_t h;
+ cmodel_t *cmod;
+ int i;
+
+ // mins maxs of the capsule
+ CM_ModelBounds(model, mins, maxs);
+
+ // offset for capsule center
+ for ( i = 0 ; i < 3 ; i++ ) {
+ offset[i] = ( mins[i] + maxs[i] ) * 0.5;
+ size[0][i] = mins[i] - offset[i];
+ size[1][i] = maxs[i] - offset[i];
+ tw->start[i] -= offset[i];
+ tw->end[i] -= offset[i];
+ }
+
+ // replace the bounding box with the capsule
+ tw->type = TT_CAPSULE;
+ tw->sphere.radius = ( size[1][0] > size[1][2] ) ? size[1][2]: size[1][0];
+ tw->sphere.halfheight = size[1][2];
+ VectorSet( tw->sphere.offset, 0, 0, size[1][2] - tw->sphere.radius );
+
+ // replace the capsule with the bounding box
+ h = CM_TempBoxModel(tw->size[0], tw->size[1], false);
+ // calculate collision
+ cmod = CM_ClipHandleToModel( h );
+ CM_TestInLeaf( tw, &cmod->leaf );
+}
+
+/*
+==================
+CM_PositionTest
+==================
+*/
+#define MAX_POSITION_LEAFS 1024
+void CM_PositionTest( traceWork_t *tw ) {
+ int leafs[MAX_POSITION_LEAFS];
+ int i;
+ leafList_t ll;
+
+ // identify the leafs we are touching
+ VectorAdd( tw->start, tw->size[0], ll.bounds[0] );
+ VectorAdd( tw->start, tw->size[1], ll.bounds[1] );
+
+ for (i=0 ; i<3 ; i++) {
+ ll.bounds[0][i] -= 1;
+ ll.bounds[1][i] += 1;
+ }
+
+ ll.count = 0;
+ ll.maxcount = MAX_POSITION_LEAFS;
+ ll.list = leafs;
+ ll.storeLeafs = CM_StoreLeafs;
+ ll.lastLeaf = 0;
+ ll.overflowed = false;
+
+ cm.checkcount++;
+
+ CM_BoxLeafnums_r( &ll, 0 );
+
+
+ cm.checkcount++;
+
+ // test the contents of the leafs
+ for (i=0 ; i < ll.count ; i++) {
+ CM_TestInLeaf( tw, &cm.leafs[leafs[i]] );
+ if ( tw->trace.allsolid ) {
+ break;
+ }
+ }
+}
+
+/*
+===============================================================================
+
+TRACING
+
+===============================================================================
+*/
+
+/*
+================
+CM_TraceThroughPatch
+================
+*/
+
+void CM_TraceThroughPatch( traceWork_t *tw, cPatch_t *patch ) {
+ float oldFrac;
+
+ c_patch_traces++;
+
+ oldFrac = tw->trace.fraction;
+
+ CM_TraceThroughPatchCollide( tw, patch->pc );
+
+ if ( tw->trace.fraction < oldFrac ) {
+ tw->trace.surfaceFlags = patch->surfaceFlags;
+ tw->trace.contents = patch->contents;
+ }
+}
+
+/*
+================
+CM_TraceThroughBrush
+================
+*/
+void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) {
+ int i;
+ cplane_t *plane, *clipplane;
+ float dist;
+ float enterFrac, leaveFrac;
+ float d1, d2;
+ bool getout, startout;
+ float f;
+ cbrushside_t *side, *leadside;
+ float t;
+ vec3_t startp;
+ vec3_t endp;
+
+ enterFrac = -1.0;
+ leaveFrac = 1.0;
+ clipplane = NULL;
+
+ if ( !brush->numsides ) {
+ return;
+ }
+
+ c_brush_traces++;
+
+ getout = false;
+ startout = false;
+
+ leadside = NULL;
+
+ if( tw->type == TT_BISPHERE )
+ {
+ //
+ // compare the trace against all planes of the brush
+ // find the latest time the trace crosses a plane towards the interior
+ // and the earliest time the trace crosses a plane towards the exterior
+ //
+ for( i = 0; i < brush->numsides; i++ )
+ {
+ side = brush->sides + i;
+ plane = side->plane;
+
+ // adjust the plane distance apropriately for radius
+ d1 = DotProduct( tw->start, plane->normal ) -
+ ( plane->dist + tw->biSphere.startRadius );
+ d2 = DotProduct( tw->end, plane->normal ) -
+ ( plane->dist + tw->biSphere.endRadius );
+
+ if( d2 > 0 )
+ getout = true; // endpoint is not in solid
+
+ if( d1 > 0 )
+ startout = true;
+
+ // if completely in front of face, no intersection with the entire brush
+ if( d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) )
+ return;
+
+ // if it doesn't cross the plane, the plane isn't relevent
+ if( d1 <= 0 && d2 <= 0 )
+ continue;
+
+ brush->collided = true;
+
+ // crosses face
+ if( d1 > d2 )
+ {
+ // enter
+ f = ( d1 - SURFACE_CLIP_EPSILON ) / ( d1 - d2 );
+
+ if( f < 0 )
+ f = 0;
+
+ if( f > enterFrac )
+ {
+ enterFrac = f;
+ clipplane = plane;
+ leadside = side;
+ }
+ }
+ else
+ {
+ // leave
+ f = ( d1 + SURFACE_CLIP_EPSILON ) / ( d1 - d2 );
+
+ if( f > 1 )
+ f = 1;
+
+ if( f < leaveFrac )
+ leaveFrac = f;
+ }
+ }
+ }
+ else if ( tw->type == TT_CAPSULE ) {
+ //
+ // compare the trace against all planes of the brush
+ // find the latest time the trace crosses a plane towards the interior
+ // and the earliest time the trace crosses a plane towards the exterior
+ //
+ for (i = 0; i < brush->numsides; i++) {
+ side = brush->sides + i;
+ plane = side->plane;
+
+ // adjust the plane distance apropriately for radius
+ dist = plane->dist + tw->sphere.radius;
+
+ // find the closest point on the capsule to the plane
+ t = DotProduct( plane->normal, tw->sphere.offset );
+ if ( t > 0 )
+ {
+ VectorSubtract( tw->start, tw->sphere.offset, startp );
+ VectorSubtract( tw->end, tw->sphere.offset, endp );
+ }
+ else
+ {
+ VectorAdd( tw->start, tw->sphere.offset, startp );
+ VectorAdd( tw->end, tw->sphere.offset, endp );
+ }
+
+ d1 = DotProduct( startp, plane->normal ) - dist;
+ d2 = DotProduct( endp, plane->normal ) - dist;
+
+ if (d2 > 0) {
+ getout = true; // endpoint is not in solid
+ }
+ if (d1 > 0) {
+ startout = true;
+ }
+
+ // if completely in front of face, no intersection with the entire brush
+ if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) ) {
+ return;
+ }
+
+ // if it doesn't cross the plane, the plane isn't relevent
+ if (d1 <= 0 && d2 <= 0 ) {
+ continue;
+ }
+
+ brush->collided = true;
+
+ // crosses face
+ if (d1 > d2) { // enter
+ f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);
+ if ( f < 0 ) {
+ f = 0;
+ }
+ if (f > enterFrac) {
+ enterFrac = f;
+ clipplane = plane;
+ leadside = side;
+ }
+ } else { // leave
+ f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);
+ if ( f > 1 ) {
+ f = 1;
+ }
+ if (f < leaveFrac) {
+ leaveFrac = f;
+ }
+ }
+ }
+ } else {
+ //
+ // compare the trace against all planes of the brush
+ // find the latest time the trace crosses a plane towards the interior
+ // and the earliest time the trace crosses a plane towards the exterior
+ //
+ for (i = 0; i < brush->numsides; i++) {
+ side = brush->sides + i;
+ plane = side->plane;
+
+ // adjust the plane distance apropriately for mins/maxs
+ dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );
+
+ d1 = DotProduct( tw->start, plane->normal ) - dist;
+ d2 = DotProduct( tw->end, plane->normal ) - dist;
+
+ if (d2 > 0) {
+ getout = true; // endpoint is not in solid
+ }
+ if (d1 > 0) {
+ startout = true;
+ }
+
+ // if completely in front of face, no intersection with the entire brush
+ if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) ) {
+ return;
+ }
+
+ // if it doesn't cross the plane, the plane isn't relevent
+ if (d1 <= 0 && d2 <= 0 ) {
+ continue;
+ }
+
+ brush->collided = true;
+
+ // crosses face
+ if (d1 > d2) { // enter
+ f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);
+ if ( f < 0 ) {
+ f = 0;
+ }
+ if (f > enterFrac) {
+ enterFrac = f;
+ clipplane = plane;
+ leadside = side;
+ }
+ } else { // leave
+ f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);
+ if ( f > 1 ) {
+ f = 1;
+ }
+ if (f < leaveFrac) {
+ leaveFrac = f;
+ }
+ }
+ }
+ }
+
+ //
+ // all planes have been checked, and the trace was not
+ // completely outside the brush
+ //
+ if (!startout) { // original point was inside brush
+ tw->trace.startsolid = qtrue;
+ if (!getout) {
+ tw->trace.allsolid = qtrue;
+ tw->trace.fraction = 0;
+ tw->trace.contents = brush->contents;
+ }
+ return;
+ }
+
+ if (enterFrac < leaveFrac) {
+ if (enterFrac > -1 && enterFrac < tw->trace.fraction) {
+ if (enterFrac < 0) {
+ enterFrac = 0;
+ }
+ tw->trace.fraction = enterFrac;
+ if (clipplane != NULL) {
+ tw->trace.plane = *clipplane;
+ }
+ if (leadside != NULL) {
+ tw->trace.surfaceFlags = leadside->surfaceFlags;
+ }
+ tw->trace.contents = brush->contents;
+ }
+ }
+}
+
+/*
+================
+CM_ProximityToBrush
+================
+*/
+static void CM_ProximityToBrush( traceWork_t *tw, cbrush_t *brush )
+{
+ int i;
+ cbrushedge_t *edge;
+ float dist, minDist = 1e+10f;
+ float s, t;
+ float sAtMin = 0.0f;
+ float radius = 0.0f, fraction;
+ traceWork_t tw2;
+
+ // cheapish purely linear trace to test for intersection
+ ::memset( &tw2, 0, sizeof( tw2 ) );
+ tw2.trace.fraction = 1.0f;
+ tw2.type = TT_CAPSULE;
+ tw2.sphere.radius = 0.0f;
+ VectorClear( tw2.sphere.offset );
+ VectorCopy( tw->start, tw2.start );
+ VectorCopy( tw->end, tw2.end );
+
+ CM_TraceThroughBrush( &tw2, brush );
+
+ if( tw2.trace.fraction == 1.0f && !tw2.trace.allsolid && !tw2.trace.startsolid )
+ {
+ for( i = 0; i < brush->numEdges; i++ )
+ {
+ edge = &brush->edges[ i ];
+
+ dist = DistanceBetweenLineSegmentsSquared( tw->start, tw->end,
+ edge->p0, edge->p1, &s, &t );
+
+ if( dist < minDist )
+ {
+ minDist = dist;
+ sAtMin = s;
+ }
+ }
+
+ if( tw->type == TT_BISPHERE )
+ {
+ radius = tw->biSphere.startRadius +
+ ( sAtMin * ( tw->biSphere.endRadius - tw->biSphere.startRadius ) );
+ }
+ else if( tw->type == TT_CAPSULE )
+ {
+ radius = tw->sphere.radius;
+ }
+ else if( tw->type == TT_AABB )
+ {
+ //FIXME
+ }
+
+ fraction = minDist / ( radius * radius );
+
+ if( fraction < tw->trace.lateralFraction )
+ tw->trace.lateralFraction = fraction;
+ }
+ else
+ tw->trace.lateralFraction = 0.0f;
+}
+
+/*
+================
+CM_ProximityToPatch
+================
+*/
+static void CM_ProximityToPatch( traceWork_t *tw, cPatch_t *patch )
+{
+ traceWork_t tw2;
+
+ // cheapish purely linear trace to test for intersection
+ ::memset( &tw2, 0, sizeof( tw2 ) );
+ tw2.trace.fraction = 1.0f;
+ tw2.type = TT_CAPSULE;
+ tw2.sphere.radius = 0.0f;
+ VectorClear( tw2.sphere.offset );
+ VectorCopy( tw->start, tw2.start );
+ VectorCopy( tw->end, tw2.end );
+
+ CM_TraceThroughPatch( &tw2, patch );
+
+ if( tw2.trace.fraction == 1.0f && !tw2.trace.allsolid && !tw2.trace.startsolid )
+ {
+ //FIXME: implement me
+ }
+ else
+ tw->trace.lateralFraction = 0.0f;
+}
+
+/*
+================
+CM_TraceThroughLeaf
+================
+*/
+void CM_TraceThroughLeaf( traceWork_t *tw, cLeaf_t *leaf ) {
+ int k;
+ int brushnum;
+ cbrush_t *b;
+ cPatch_t *patch;
+
+ // trace line against all brushes in the leaf
+ for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
+ brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
+
+ b = &cm.brushes[brushnum];
+ if ( b->checkcount == cm.checkcount ) {
+ continue; // already checked this brush in another leaf
+ }
+ b->checkcount = cm.checkcount;
+
+ if ( !(b->contents & tw->contents) ) {
+ continue;
+ }
+
+ b->collided = false;
+
+ if ( !CM_BoundsIntersect( tw->bounds[0], tw->bounds[1],
+ b->bounds[0], b->bounds[1] ) ) {
+ continue;
+ }
+
+ CM_TraceThroughBrush( tw, b );
+ if ( !tw->trace.fraction ) {
+ tw->trace.lateralFraction = 0.0f;
+ return;
+ }
+ }
+
+ // trace line against all patches in the leaf
+#ifdef BSPC
+ if (1) {
+#else
+ if ( !cm_noCurves->integer ) {
+#endif
+ for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
+ patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];
+ if ( !patch ) {
+ continue;
+ }
+ if ( patch->checkcount == cm.checkcount ) {
+ continue; // already checked this patch in another leaf
+ }
+ patch->checkcount = cm.checkcount;
+
+ if ( !(patch->contents & tw->contents) ) {
+ continue;
+ }
+
+ CM_TraceThroughPatch( tw, patch );
+
+ if ( !tw->trace.fraction ) {
+ tw->trace.lateralFraction = 0.0f;
+ return;
+ }
+ }
+ }
+
+ if( tw->testLateralCollision && tw->trace.fraction < 1.0f )
+ {
+ for( k = 0; k < leaf->numLeafBrushes; k++ )
+ {
+ brushnum = cm.leafbrushes[ leaf->firstLeafBrush + k ];
+
+ b = &cm.brushes[ brushnum ];
+
+ // This brush never collided, so don't bother
+ if( !b->collided )
+ continue;
+
+ if( !( b->contents & tw->contents ) )
+ continue;
+
+ CM_ProximityToBrush( tw, b );
+
+ if( !tw->trace.lateralFraction )
+ return;
+ }
+
+ for( k = 0; k < leaf->numLeafSurfaces; k++ )
+ {
+ patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];
+ if( !patch )
+ continue;
+
+ if( !( patch->contents & tw->contents ) )
+ continue;
+
+ CM_ProximityToPatch( tw, patch );
+
+ if( !tw->trace.lateralFraction )
+ return;
+ }
+ }
+}
+
+#define RADIUS_EPSILON 1.0f
+
+/*
+================
+CM_TraceThroughSphere
+
+get the first intersection of the ray with the sphere
+================
+*/
+void CM_TraceThroughSphere( traceWork_t *tw, vec3_t origin, float radius, vec3_t start, vec3_t end ) {
+ float l1, l2, length, scale, fraction;
+ //float a;
+ float b, c, d, sqrtd;
+ vec3_t v1, dir, intersection;
+
+ // if inside the sphere
+ VectorSubtract(start, origin, dir);
+ l1 = VectorLengthSquared(dir);
+ if (l1 < Square(radius)) {
+ tw->trace.fraction = 0;
+ tw->trace.startsolid = qtrue;
+ // test for allsolid
+ VectorSubtract(end, origin, dir);
+ l1 = VectorLengthSquared(dir);
+ if (l1 < Square(radius)) {
+ tw->trace.allsolid = qtrue;
+ }
+ return;
+ }
+ //
+ VectorSubtract(end, start, dir);
+ length = VectorNormalize(dir);
+ //
+ l1 = CM_DistanceFromLineSquared(origin, start, end, dir);
+ VectorSubtract(end, origin, v1);
+ l2 = VectorLengthSquared(v1);
+ // if no intersection with the sphere and the end point is at least an epsilon away
+ if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
+ return;
+ }
+ //
+ // | origin - (start + t * dir) | = radius
+ // a = dir[0]^2 + dir[1]^2 + dir[2]^2;
+ // b = 2 * (dir[0] * (start[0] - origin[0]) + dir[1] * (start[1] - origin[1]) + dir[2] * (start[2] - origin[2]));
+ // c = (start[0] - origin[0])^2 + (start[1] - origin[1])^2 + (start[2] - origin[2])^2 - radius^2;
+ //
+ VectorSubtract(start, origin, v1);
+ // dir is normalized so a = 1
+ //a = 1.0f;//dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
+ b = 2.0f * (dir[0] * v1[0] + dir[1] * v1[1] + dir[2] * v1[2]);
+ c = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);
+
+ d = b * b - 4.0f * c;// * a;
+ if (d > 0) {
+ sqrtd = SquareRootFloat(d);
+ // = (- b + sqrtd) * 0.5f; // / (2.0f * a);
+ fraction = (- b - sqrtd) * 0.5f; // / (2.0f * a);
+ //
+ if (fraction < 0) {
+ fraction = 0;
+ }
+ else {
+ fraction /= length;
+ }
+ if ( fraction < tw->trace.fraction ) {
+ tw->trace.fraction = fraction;
+ VectorSubtract(end, start, dir);
+ VectorMA(start, fraction, dir, intersection);
+ VectorSubtract(intersection, origin, dir);
+ #ifdef CAPSULE_DEBUG
+ l2 = VectorLength(dir);
+ if (l2 < radius) {
+ int bah = 1;
+ }
+ #endif
+ scale = 1 / (radius+RADIUS_EPSILON);
+ VectorScale(dir, scale, dir);
+ VectorCopy(dir, tw->trace.plane.normal);
+ VectorAdd( tw->modelOrigin, intersection, intersection);
+ tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);
+ tw->trace.contents = CONTENTS_BODY;
+ }
+ }
+ else if (d == 0) {
+ //t1 = (- b ) / 2;
+ // slide along the sphere
+ }
+ // no intersection at all
+}
+
+/*
+================
+CM_TraceThroughVerticalCylinder
+
+get the first intersection of the ray with the cylinder
+the cylinder extends halfheight above and below the origin
+================
+*/
+void CM_TraceThroughVerticalCylinder( traceWork_t *tw, vec3_t origin, float radius, float halfheight, vec3_t start, vec3_t end) {
+ float length, scale, fraction, l1, l2;
+ //float a;
+ float b, c, d, sqrtd;
+ vec3_t v1, dir, start2d, end2d, org2d, intersection;
+
+ // 2d coordinates
+ VectorSet(start2d, start[0], start[1], 0);
+ VectorSet(end2d, end[0], end[1], 0);
+ VectorSet(org2d, origin[0], origin[1], 0);
+ // if between lower and upper cylinder bounds
+ if (start[2] <= origin[2] + halfheight &&
+ start[2] >= origin[2] - halfheight) {
+ // if inside the cylinder
+ VectorSubtract(start2d, org2d, dir);
+ l1 = VectorLengthSquared(dir);
+ if (l1 < Square(radius)) {
+ tw->trace.fraction = 0;
+ tw->trace.startsolid = qtrue;
+ VectorSubtract(end2d, org2d, dir);
+ l1 = VectorLengthSquared(dir);
+ if (l1 < Square(radius)) {
+ tw->trace.allsolid = qtrue;
+ }
+ return;
+ }
+ }
+ //
+ VectorSubtract(end2d, start2d, dir);
+ length = VectorNormalize(dir);
+ //
+ l1 = CM_DistanceFromLineSquared(org2d, start2d, end2d, dir);
+ VectorSubtract(end2d, org2d, v1);
+ l2 = VectorLengthSquared(v1);
+ // if no intersection with the cylinder and the end point is at least an epsilon away
+ if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
+ return;
+ }
+ //
+ //
+ // (start[0] - origin[0] - t * dir[0]) ^ 2 + (start[1] - origin[1] - t * dir[1]) ^ 2 = radius ^ 2
+ // (v1[0] + t * dir[0]) ^ 2 + (v1[1] + t * dir[1]) ^ 2 = radius ^ 2;
+ // v1[0] ^ 2 + 2 * v1[0] * t * dir[0] + (t * dir[0]) ^ 2 +
+ // v1[1] ^ 2 + 2 * v1[1] * t * dir[1] + (t * dir[1]) ^ 2 = radius ^ 2
+ // t ^ 2 * (dir[0] ^ 2 + dir[1] ^ 2) + t * (2 * v1[0] * dir[0] + 2 * v1[1] * dir[1]) +
+ // v1[0] ^ 2 + v1[1] ^ 2 - radius ^ 2 = 0
+ //
+ VectorSubtract(start, origin, v1);
+ // dir is normalized so we can use a = 1
+ //a = 1.0f;// * (dir[0] * dir[0] + dir[1] * dir[1]);
+ b = 2.0f * (v1[0] * dir[0] + v1[1] * dir[1]);
+ c = v1[0] * v1[0] + v1[1] * v1[1] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);
+
+ d = b * b - 4.0f * c;// * a;
+ if (d > 0) {
+ sqrtd = SquareRootFloat(d);
+ // = (- b + sqrtd) * 0.5f;// / (2.0f * a);
+ fraction = (- b - sqrtd) * 0.5f;// / (2.0f * a);
+ //
+ if (fraction < 0) {
+ fraction = 0;
+ }
+ else {
+ fraction /= length;
+ }
+ if ( fraction < tw->trace.fraction ) {
+ VectorSubtract(end, start, dir);
+ VectorMA(start, fraction, dir, intersection);
+ // if the intersection is between the cylinder lower and upper bound
+ if (intersection[2] <= origin[2] + halfheight &&
+ intersection[2] >= origin[2] - halfheight) {
+ //
+ tw->trace.fraction = fraction;
+ VectorSubtract(intersection, origin, dir);
+ dir[2] = 0;
+ #ifdef CAPSULE_DEBUG
+ l2 = VectorLength(dir);
+ if (l2 <= radius) {
+ int bah = 1;
+ }
+ #endif
+ scale = 1 / (radius+RADIUS_EPSILON);
+ VectorScale(dir, scale, dir);
+ VectorCopy(dir, tw->trace.plane.normal);
+ VectorAdd( tw->modelOrigin, intersection, intersection);
+ tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);
+ tw->trace.contents = CONTENTS_BODY;
+ }
+ }
+ }
+ else if (d == 0) {
+ //t[0] = (- b ) / 2 * a;
+ // slide along the cylinder
+ }
+ // no intersection at all
+}
+
+/*
+================
+CM_TraceCapsuleThroughCapsule
+
+capsule vs. capsule collision (not rotated)
+================
+*/
+void CM_TraceCapsuleThroughCapsule( traceWork_t *tw, clipHandle_t model ) {
+ int i;
+ vec3_t mins, maxs;
+ vec3_t top, bottom, starttop, startbottom, endtop, endbottom;
+ vec3_t offset, symetricSize[2];
+ float radius, halfwidth, halfheight, offs, h;
+
+ CM_ModelBounds(model, mins, maxs);
+ // test trace bounds vs. capsule bounds
+ if ( tw->bounds[0][0] > maxs[0] + RADIUS_EPSILON
+ || tw->bounds[0][1] > maxs[1] + RADIUS_EPSILON
+ || tw->bounds[0][2] > maxs[2] + RADIUS_EPSILON
+ || tw->bounds[1][0] < mins[0] - RADIUS_EPSILON
+ || tw->bounds[1][1] < mins[1] - RADIUS_EPSILON
+ || tw->bounds[1][2] < mins[2] - RADIUS_EPSILON
+ ) {
+ return;
+ }
+ // top origin and bottom origin of each sphere at start and end of trace
+ VectorAdd(tw->start, tw->sphere.offset, starttop);
+ VectorSubtract(tw->start, tw->sphere.offset, startbottom);
+ VectorAdd(tw->end, tw->sphere.offset, endtop);
+ VectorSubtract(tw->end, tw->sphere.offset, endbottom);
+
+ // calculate top and bottom of the capsule spheres to collide with
+ for ( i = 0 ; i < 3 ; i++ ) {
+ offset[i] = ( mins[i] + maxs[i] ) * 0.5;
+ symetricSize[0][i] = mins[i] - offset[i];
+ symetricSize[1][i] = maxs[i] - offset[i];
+ }
+ halfwidth = symetricSize[ 1 ][ 0 ];
+ halfheight = symetricSize[ 1 ][ 2 ];
+ radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
+ offs = halfheight - radius;
+ VectorCopy(offset, top);
+ top[2] += offs;
+ VectorCopy(offset, bottom);
+ bottom[2] -= offs;
+ // expand radius of spheres
+ radius += tw->sphere.radius;
+ // if there is horizontal movement
+ if ( tw->start[0] != tw->end[0] || tw->start[1] != tw->end[1] ) {
+ // height of the expanded cylinder is the height of both cylinders minus the radius of both spheres
+ h = halfheight + tw->sphere.halfheight - radius;
+ // if the cylinder has a height
+ if ( h > 0 ) {
+ // test for collisions between the cylinders
+ CM_TraceThroughVerticalCylinder(tw, offset, radius, h, tw->start, tw->end);
+ }
+ }
+ // test for collision between the spheres
+ CM_TraceThroughSphere(tw, top, radius, startbottom, endbottom);
+ CM_TraceThroughSphere(tw, bottom, radius, starttop, endtop);
+}
+
+/*
+================
+CM_TraceBoundingBoxThroughCapsule
+
+bounding box vs. capsule collision
+================
+*/
+void CM_TraceBoundingBoxThroughCapsule( traceWork_t *tw, clipHandle_t model ) {
+ vec3_t mins, maxs, offset, size[2];
+ clipHandle_t h;
+ cmodel_t *cmod;
+ int i;
+
+ // mins maxs of the capsule
+ CM_ModelBounds(model, mins, maxs);
+
+ // offset for capsule center
+ for ( i = 0 ; i < 3 ; i++ ) {
+ offset[i] = ( mins[i] + maxs[i] ) * 0.5;
+ size[0][i] = mins[i] - offset[i];
+ size[1][i] = maxs[i] - offset[i];
+ tw->start[i] -= offset[i];
+ tw->end[i] -= offset[i];
+ }
+
+ // replace the bounding box with the capsule
+ tw->type = TT_CAPSULE;
+ tw->sphere.radius = ( size[1][0] > size[1][2] ) ? size[1][2]: size[1][0];
+ tw->sphere.halfheight = size[1][2];
+ VectorSet( tw->sphere.offset, 0, 0, size[1][2] - tw->sphere.radius );
+
+ // replace the capsule with the bounding box
+ h = CM_TempBoxModel(tw->size[0], tw->size[1], false);
+ // calculate collision
+ cmod = CM_ClipHandleToModel( h );
+ CM_TraceThroughLeaf( tw, &cmod->leaf );
+}
+
+//=========================================================================================
+
+/*
+==================
+CM_TraceThroughTree
+
+Traverse all the contacted leafs from the start to the end position.
+If the trace is a point, they will be exactly in order, but for larger
+trace volumes it is possible to hit something in a later leaf with
+a smaller intercept fraction.
+==================
+*/
+void CM_TraceThroughTree( traceWork_t *tw, int num, float p1f, float p2f, vec3_t p1, vec3_t p2) {
+ cNode_t *node;
+ cplane_t *plane;
+ float t1, t2, offset;
+ float frac, frac2;
+ float idist;
+ vec3_t mid;
+ int side;
+ float midf;
+
+ if (tw->trace.fraction <= p1f) {
+ return; // already hit something nearer
+ }
+
+ // if < 0, we are in a leaf node
+ if (num < 0) {
+ CM_TraceThroughLeaf( tw, &cm.leafs[-1-num] );
+ return;
+ }
+
+ //
+ // find the point distances to the seperating plane
+ // and the offset for the size of the box
+ //
+ node = cm.nodes + num;
+ plane = node->plane;
+
+ // adjust the plane distance apropriately for mins/maxs
+ if ( plane->type < 3 ) {
+ t1 = p1[plane->type] - plane->dist;
+ t2 = p2[plane->type] - plane->dist;
+ offset = tw->extents[plane->type];
+ } else {
+ t1 = DotProduct (plane->normal, p1) - plane->dist;
+ t2 = DotProduct (plane->normal, p2) - plane->dist;
+ if ( tw->isPoint ) {
+ offset = 0;
+ } else {
+ // this is silly
+ offset = 2048;
+ }
+ }
+
+ // see which sides we need to consider
+ if ( t1 >= offset + 1 && t2 >= offset + 1 ) {
+ CM_TraceThroughTree( tw, node->children[0], p1f, p2f, p1, p2 );
+ return;
+ }
+ if ( t1 < -offset - 1 && t2 < -offset - 1 ) {
+ CM_TraceThroughTree( tw, node->children[1], p1f, p2f, p1, p2 );
+ return;
+ }
+
+ // put the crosspoint SURFACE_CLIP_EPSILON pixels on the near side
+ if ( t1 < t2 ) {
+ idist = 1.0/(t1-t2);
+ side = 1;
+ frac2 = (t1 + offset + SURFACE_CLIP_EPSILON)*idist;
+ frac = (t1 - offset + SURFACE_CLIP_EPSILON)*idist;
+ } else if (t1 > t2) {
+ idist = 1.0/(t1-t2);
+ side = 0;
+ frac2 = (t1 - offset - SURFACE_CLIP_EPSILON)*idist;
+ frac = (t1 + offset + SURFACE_CLIP_EPSILON)*idist;
+ } else {
+ side = 0;
+ frac = 1;
+ frac2 = 0;
+ }
+
+ // move up to the node
+ if ( frac < 0 ) {
+ frac = 0;
+ }
+ if ( frac > 1 ) {
+ frac = 1;
+ }
+
+ midf = p1f + (p2f - p1f)*frac;
+
+ mid[0] = p1[0] + frac*(p2[0] - p1[0]);
+ mid[1] = p1[1] + frac*(p2[1] - p1[1]);
+ mid[2] = p1[2] + frac*(p2[2] - p1[2]);
+
+ CM_TraceThroughTree( tw, node->children[side], p1f, midf, p1, mid );
+
+
+ // go past the node
+ if ( frac2 < 0 ) {
+ frac2 = 0;
+ }
+ if ( frac2 > 1 ) {
+ frac2 = 1;
+ }
+
+ midf = p1f + (p2f - p1f)*frac2;
+
+ mid[0] = p1[0] + frac2*(p2[0] - p1[0]);
+ mid[1] = p1[1] + frac2*(p2[1] - p1[1]);
+ mid[2] = p1[2] + frac2*(p2[2] - p1[2]);
+
+ CM_TraceThroughTree( tw, node->children[side^1], midf, p2f, mid, p2 );
+}
+
+//======================================================================
+
+
+/*
+==================
+CM_Trace
+==================
+*/
+void CM_Trace( trace_t *results, const vec3_t start,
+ const vec3_t end, vec3_t mins, vec3_t maxs,
+ clipHandle_t model, const vec3_t origin, int brushmask,
+ traceType_t type, sphere_t *sphere ) {
+ int i;
+ traceWork_t tw;
+ vec3_t offset;
+ cmodel_t *cmod;
+
+ cmod = CM_ClipHandleToModel( model );
+
+ cm.checkcount++; // for multi-check avoidance
+
+ c_traces++; // for statistics, may be zeroed
+
+ // fill in a default trace
+ ::memset( &tw, 0, sizeof(tw) );
+ tw.trace.fraction = 1; // assume it goes the entire distance until shown otherwise
+ VectorCopy(origin, tw.modelOrigin);
+ tw.type = type;
+
+ if (!cm.numNodes) {
+ *results = tw.trace;
+
+ return; // map not loaded, shouldn't happen
+ }
+
+ // allow NULL to be passed in for 0,0,0
+ if ( !mins ) {
+ mins = vec3_origin;
+ }
+ if ( !maxs ) {
+ maxs = vec3_origin;
+ }
+
+ // set basic parms
+ tw.contents = brushmask;
+
+ // adjust so that mins and maxs are always symetric, which
+ // avoids some complications with plane expanding of rotated
+ // bmodels
+ for ( i = 0 ; i < 3 ; i++ ) {
+ offset[i] = ( mins[i] + maxs[i] ) * 0.5;
+ tw.size[0][i] = mins[i] - offset[i];
+ tw.size[1][i] = maxs[i] - offset[i];
+ tw.start[i] = start[i] + offset[i];
+ tw.end[i] = end[i] + offset[i];
+ }
+
+ // if a sphere is already specified
+ if ( sphere ) {
+ tw.sphere = *sphere;
+ }
+ else {
+ tw.sphere.radius = ( tw.size[1][0] > tw.size[1][2] ) ? tw.size[1][2]: tw.size[1][0];
+ tw.sphere.halfheight = tw.size[1][2];
+ VectorSet( tw.sphere.offset, 0, 0, tw.size[1][2] - tw.sphere.radius );
+ }
+
+ tw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2];
+
+ // tw.offsets[signbits] = vector to apropriate corner from origin
+ tw.offsets[0][0] = tw.size[0][0];
+ tw.offsets[0][1] = tw.size[0][1];
+ tw.offsets[0][2] = tw.size[0][2];
+
+ tw.offsets[1][0] = tw.size[1][0];
+ tw.offsets[1][1] = tw.size[0][1];
+ tw.offsets[1][2] = tw.size[0][2];
+
+ tw.offsets[2][0] = tw.size[0][0];
+ tw.offsets[2][1] = tw.size[1][1];
+ tw.offsets[2][2] = tw.size[0][2];
+
+ tw.offsets[3][0] = tw.size[1][0];
+ tw.offsets[3][1] = tw.size[1][1];
+ tw.offsets[3][2] = tw.size[0][2];
+
+ tw.offsets[4][0] = tw.size[0][0];
+ tw.offsets[4][1] = tw.size[0][1];
+ tw.offsets[4][2] = tw.size[1][2];
+
+ tw.offsets[5][0] = tw.size[1][0];
+ tw.offsets[5][1] = tw.size[0][1];
+ tw.offsets[5][2] = tw.size[1][2];
+
+ tw.offsets[6][0] = tw.size[0][0];
+ tw.offsets[6][1] = tw.size[1][1];
+ tw.offsets[6][2] = tw.size[1][2];
+
+ tw.offsets[7][0] = tw.size[1][0];
+ tw.offsets[7][1] = tw.size[1][1];
+ tw.offsets[7][2] = tw.size[1][2];
+
+ //
+ // calculate bounds
+ //
+ if ( tw.type == TT_CAPSULE ) {
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( tw.start[i] < tw.end[i] ) {
+ tw.bounds[0][i] = tw.start[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;
+ tw.bounds[1][i] = tw.end[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;
+ } else {
+ tw.bounds[0][i] = tw.end[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;
+ tw.bounds[1][i] = tw.start[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;
+ }
+ }
+ }
+ else {
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( tw.start[i] < tw.end[i] ) {
+ tw.bounds[0][i] = tw.start[i] + tw.size[0][i];
+ tw.bounds[1][i] = tw.end[i] + tw.size[1][i];
+ } else {
+ tw.bounds[0][i] = tw.end[i] + tw.size[0][i];
+ tw.bounds[1][i] = tw.start[i] + tw.size[1][i];
+ }
+ }
+ }
+
+ //
+ // check for position test special case
+ //
+ if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) {
+ if ( model ) {
+#ifdef ALWAYS_BBOX_VS_BBOX // FIXME - compile time flag?
+ if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
+ tw.type = TT_AABB;
+ CM_TestInLeaf( &tw, &cmod->leaf );
+ }
+ else
+#elif defined(ALWAYS_CAPSULE_VS_CAPSULE)
+ if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
+ CM_TestCapsuleInCapsule( &tw, model );
+ }
+ else
+#endif
+ if ( model == CAPSULE_MODEL_HANDLE ) {
+ if ( tw.type == TT_CAPSULE ) {
+ CM_TestCapsuleInCapsule( &tw, model );
+ }
+ else {
+ CM_TestBoundingBoxInCapsule( &tw, model );
+ }
+ }
+ else {
+ CM_TestInLeaf( &tw, &cmod->leaf );
+ }
+ } else {
+ CM_PositionTest( &tw );
+ }
+ } else {
+ //
+ // check for point special case
+ //
+ if ( tw.size[0][0] == 0 && tw.size[0][1] == 0 && tw.size[0][2] == 0 ) {
+ tw.isPoint = true;
+ VectorClear( tw.extents );
+ } else {
+ tw.isPoint = false;
+ tw.extents[0] = tw.size[1][0];
+ tw.extents[1] = tw.size[1][1];
+ tw.extents[2] = tw.size[1][2];
+ }
+
+ //
+ // general sweeping through world
+ //
+ if ( model ) {
+#ifdef ALWAYS_BBOX_VS_BBOX
+ if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
+ tw.type = TT_AABB;
+ CM_TraceThroughLeaf( &tw, &cmod->leaf );
+ }
+ else
+#elif defined(ALWAYS_CAPSULE_VS_CAPSULE)
+ if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
+ CM_TraceCapsuleThroughCapsule( &tw, model );
+ }
+ else
+#endif
+ if ( model == CAPSULE_MODEL_HANDLE ) {
+ if ( tw.type == TT_CAPSULE ) {
+ CM_TraceCapsuleThroughCapsule( &tw, model );
+ }
+ else {
+ CM_TraceBoundingBoxThroughCapsule( &tw, model );
+ }
+ }
+ else {
+ CM_TraceThroughLeaf( &tw, &cmod->leaf );
+ }
+ } else {
+ CM_TraceThroughTree( &tw, 0, 0, 1, tw.start, tw.end );
+ }
+ }
+
+ // generate endpos from the original, unmodified start/end
+ if ( tw.trace.fraction == 1 ) {
+ VectorCopy (end, tw.trace.endpos);
+ } else {
+ for ( i=0 ; i<3 ; i++ ) {
+ tw.trace.endpos[i] = start[i] + tw.trace.fraction * (end[i] - start[i]);
+ }
+ }
+
+ // If allsolid is set (was entirely inside something solid), the plane is not valid.
+ // If fraction == 1.0, we never hit anything, and thus the plane is not valid.
+ // Otherwise, the normal on the plane should have unit length
+ assert(tw.trace.allsolid ||
+ tw.trace.fraction == 1.0 ||
+ VectorLengthSquared(tw.trace.plane.normal) > 0.9999);
+ *results = tw.trace;
+}
+
+/*
+==================
+CM_BoxTrace
+==================
+*/
+void CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ vec3_t mins, vec3_t maxs,
+ clipHandle_t model, int brushmask, traceType_t type ) {
+ CM_Trace( results, start, end, mins, maxs, model, vec3_origin, brushmask, type, NULL );
+}
+
+/*
+==================
+CM_TransformedBoxTrace
+
+Handles offseting and rotation of the end points for moving and
+rotating entities
+==================
+*/
+void CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ vec3_t mins, vec3_t maxs,
+ clipHandle_t model, int brushmask,
+ const vec3_t origin, const vec3_t angles, traceType_t type ) {
+ trace_t trace;
+ vec3_t start_l, end_l;
+ bool rotated;
+ vec3_t offset;
+ vec3_t symetricSize[2];
+ vec3_t matrix[3], transpose[3];
+ int i;
+ float halfwidth;
+ float halfheight;
+ float t;
+ sphere_t sphere;
+
+ if ( !mins ) {
+ mins = vec3_origin;
+ }
+ if ( !maxs ) {
+ maxs = vec3_origin;
+ }
+
+ // adjust so that mins and maxs are always symetric, which
+ // avoids some complications with plane expanding of rotated
+ // bmodels
+ for ( i = 0 ; i < 3 ; i++ ) {
+ offset[i] = ( mins[i] + maxs[i] ) * 0.5;
+ symetricSize[0][i] = mins[i] - offset[i];
+ symetricSize[1][i] = maxs[i] - offset[i];
+ start_l[i] = start[i] + offset[i];
+ end_l[i] = end[i] + offset[i];
+ }
+
+ // subtract origin offset
+ VectorSubtract( start_l, origin, start_l );
+ VectorSubtract( end_l, origin, end_l );
+
+ // rotate start and end into the models frame of reference
+ if ( model != BOX_MODEL_HANDLE &&
+ (angles[0] || angles[1] || angles[2]) ) {
+ rotated = true;
+ } else {
+ rotated = false;
+ }
+
+ halfwidth = symetricSize[ 1 ][ 0 ];
+ halfheight = symetricSize[ 1 ][ 2 ];
+
+ sphere.radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
+ sphere.halfheight = halfheight;
+ t = halfheight - sphere.radius;
+
+ if (rotated) {
+ // rotation on trace line (start-end) instead of rotating the bmodel
+ // NOTE: This is still incorrect for bounding boxes because the actual bounding
+ // box that is swept through the model is not rotated. We cannot rotate
+ // the bounding box or the bmodel because that would make all the brush
+ // bevels invalid.
+ // However this is correct for capsules since a capsule itself is rotated too.
+ CreateRotationMatrix(angles, matrix);
+ RotatePoint(start_l, matrix);
+ RotatePoint(end_l, matrix);
+ // rotated sphere offset for capsule
+ sphere.offset[0] = matrix[0][ 2 ] * t;
+ sphere.offset[1] = -matrix[1][ 2 ] * t;
+ sphere.offset[2] = matrix[2][ 2 ] * t;
+ }
+ else {
+ VectorSet( sphere.offset, 0, 0, t );
+ }
+
+ // sweep the box through the model
+ CM_Trace( &trace, start_l, end_l, symetricSize[0], symetricSize[1],
+ model, origin, brushmask, type, &sphere );
+
+ // if the bmodel was rotated and there was a collision
+ if ( rotated && trace.fraction != 1.0 ) {
+ // rotation of bmodel collision plane
+ TransposeMatrix(matrix, transpose);
+ RotatePoint(trace.plane.normal, transpose);
+ }
+
+ // re-calculate the end position of the trace because the trace.endpos
+ // calculated by CM_Trace could be rotated and have an offset
+ trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
+ trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
+ trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
+
+ *results = trace;
+}
+
+/*
+==================
+CM_BiSphereTrace
+==================
+*/
+void CM_BiSphereTrace( trace_t *results, const vec3_t start,
+ const vec3_t end, float startRad, float endRad,
+ clipHandle_t model, int mask )
+{
+ int i;
+ traceWork_t tw;
+ float largestRadius = startRad > endRad ? startRad : endRad;
+ cmodel_t *cmod;
+
+ cmod = CM_ClipHandleToModel( model );
+
+ cm.checkcount++; // for multi-check avoidance
+
+ c_traces++; // for statistics, may be zeroed
+
+ // fill in a default trace
+ ::memset( &tw, 0, sizeof( tw ) );
+ tw.trace.fraction = 1.0f; // assume it goes the entire distance until shown otherwise
+ VectorCopy( vec3_origin, tw.modelOrigin );
+ tw.type = TT_BISPHERE;
+ tw.testLateralCollision = true;
+ tw.trace.lateralFraction = 1.0f;
+
+ if( !cm.numNodes )
+ {
+ *results = tw.trace;
+
+ return; // map not loaded, shouldn't happen
+ }
+
+ // set basic parms
+ tw.contents = mask;
+
+ VectorCopy( start, tw.start );
+ VectorCopy( end, tw.end );
+
+ tw.biSphere.startRadius = startRad;
+ tw.biSphere.endRadius = endRad;
+
+ //
+ // calculate bounds
+ //
+ for( i = 0 ; i < 3 ; i++ )
+ {
+ if( tw.start[ i ] < tw.end[ i ] )
+ {
+ tw.bounds[ 0 ][ i ] = tw.start[ i ] - tw.biSphere.startRadius;
+ tw.bounds[ 1 ][ i ] = tw.end[ i ] + tw.biSphere.endRadius;
+ }
+ else
+ {
+ tw.bounds[ 0 ][ i ] = tw.end[ i ] + tw.biSphere.endRadius;
+ tw.bounds[ 1 ][ i ] = tw.start[ i ] - tw.biSphere.startRadius;
+ }
+ }
+
+ tw.isPoint = false;
+ tw.extents[ 0 ] = largestRadius;
+ tw.extents[ 1 ] = largestRadius;
+ tw.extents[ 2 ] = largestRadius;
+
+ //
+ // general sweeping through world
+ //
+ if( model )
+ CM_TraceThroughLeaf( &tw, &cmod->leaf );
+ else
+ CM_TraceThroughTree( &tw, 0, 0.0f, 1.0f, tw.start, tw.end );
+
+ // generate endpos from the original, unmodified start/end
+ if( tw.trace.fraction == 1.0f )
+ {
+ VectorCopy( end, tw.trace.endpos );
+ }
+ else
+ {
+ for( i = 0; i < 3; i++ )
+ tw.trace.endpos[ i ] = start[ i ] + tw.trace.fraction * ( end[ i ] - start[ i ] );
+ }
+
+ // If allsolid is set (was entirely inside something solid), the plane is not valid.
+ // If fraction == 1.0, we never hit anything, and thus the plane is not valid.
+ // Otherwise, the normal on the plane should have unit length
+ assert( tw.trace.allsolid ||
+ tw.trace.fraction == 1.0 ||
+ VectorLengthSquared(tw.trace.plane.normal ) > 0.9999 );
+
+ *results = tw.trace;
+}
+
+/*
+==================
+CM_TransformedBiSphereTrace
+
+Handles offseting and rotation of the end points for moving and
+rotating entities
+==================
+*/
+void CM_TransformedBiSphereTrace( trace_t *results, const vec3_t start,
+ const vec3_t end, float startRad, float endRad,
+ clipHandle_t model, int mask,
+ const vec3_t origin )
+{
+ trace_t trace;
+ vec3_t start_l, end_l;
+
+ // subtract origin offset
+ VectorSubtract( start, origin, start_l );
+ VectorSubtract( end, origin, end_l );
+
+ CM_BiSphereTrace( &trace, start_l, end_l, startRad, endRad, model, mask );
+
+ // re-calculate the end position of the trace because the trace.endpos
+ // calculated by CM_BiSphereTrace could be rotated and have an offset
+ trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
+ trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
+ trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
+
+ *results = trace;
+}
diff --git a/src/qcommon/cmd.cpp b/src/qcommon/cmd.cpp
new file mode 100644
index 0000000..97b1226
--- /dev/null
+++ b/src/qcommon/cmd.cpp
@@ -0,0 +1,941 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// cmd.c -- Quake script command processing module
+
+#include "cmd.h"
+
+#include "cvar.h"
+#include "files.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+#ifndef DEDICATED
+#include "client/client.h"
+#endif
+
+#define MAX_CMD_BUFFER 128*1024
+#define MAX_CMD_LINE 1024
+
+typedef struct {
+ byte *data;
+ int maxsize;
+ int cursize;
+} cmd_t;
+
+int cmd_wait;
+cmd_t cmd_text;
+byte cmd_text_buf[MAX_CMD_BUFFER];
+
+
+//=============================================================================
+
+/*
+============
+Cmd_Wait_f
+
+Causes execution of the remainder of the command buffer to be delayed until
+next frame. This allows commands like:
+bind g "cmd use rocket ; +attack ; wait ; -attack ; cmd use blaster"
+============
+*/
+void Cmd_Wait_f( void ) {
+ if ( Cmd_Argc() == 2 ) {
+ cmd_wait = atoi( Cmd_Argv( 1 ) );
+ if ( cmd_wait < 0 )
+ cmd_wait = 1; // ignore the argument
+ } else {
+ cmd_wait = 1;
+ }
+}
+
+
+/*
+=============================================================================
+
+ COMMAND BUFFER
+
+=============================================================================
+*/
+
+/*
+============
+Cbuf_Init
+============
+*/
+void Cbuf_Init (void)
+{
+ cmd_text.data = cmd_text_buf;
+ cmd_text.maxsize = MAX_CMD_BUFFER;
+ cmd_text.cursize = 0;
+}
+
+/*
+============
+Cbuf_AddText
+
+Adds command text at the end of the buffer, does NOT add a final \n
+============
+*/
+void Cbuf_AddText( const char *text ) {
+ int l;
+
+ l = strlen (text);
+
+ if (cmd_text.cursize + l >= cmd_text.maxsize)
+ {
+ Com_Printf ("Cbuf_AddText: overflow\n");
+ return;
+ }
+ ::memcpy(&cmd_text.data[cmd_text.cursize], text, l);
+ cmd_text.cursize += l;
+}
+
+
+/*
+============
+Cbuf_InsertText
+
+Adds command text immediately after the current command
+Adds a \n to the text
+============
+*/
+void Cbuf_InsertFmtText( const char *fmt, ... ) {
+ int len;
+ int i;
+
+ char text[MAXPRINTMSG];
+
+ va_list args;
+ va_start(args, fmt);
+ Q_vsnprintf(text, sizeof(text), fmt, args);
+ va_end(args);
+
+ len = strlen( text ) + 1;
+ if ( len + cmd_text.cursize > cmd_text.maxsize ) {
+ Com_Printf( "Cbuf_InsertText overflowed\n" );
+ return;
+ }
+
+ // move the existing command text
+ for ( i = cmd_text.cursize - 1 ; i >= 0 ; i-- ) {
+ cmd_text.data[ i + len ] = cmd_text.data[ i ];
+ }
+
+ // copy the new text in
+ ::memcpy( cmd_text.data, text, len - 1 );
+
+ // add a \n
+ cmd_text.data[ len - 1 ] = '\n';
+
+ cmd_text.cursize += len;
+}
+
+void Cbuf_InsertText( const char *text ) {
+ int len;
+ int i;
+
+ len = strlen( text ) + 1;
+ if ( len + cmd_text.cursize > cmd_text.maxsize ) {
+ Com_Printf( "Cbuf_InsertText overflowed\n" );
+ return;
+ }
+
+ // move the existing command text
+ for ( i = cmd_text.cursize - 1 ; i >= 0 ; i-- ) {
+ cmd_text.data[ i + len ] = cmd_text.data[ i ];
+ }
+
+ // copy the new text in
+ ::memcpy( cmd_text.data, text, len - 1 );
+
+ // add a \n
+ cmd_text.data[ len - 1 ] = '\n';
+
+ cmd_text.cursize += len;
+}
+
+/*
+============
+Cbuf_ExecuteText
+============
+*/
+void Cbuf_ExecuteText (int exec_when, const char *text)
+{
+ switch (exec_when)
+ {
+ case EXEC_NOW:
+ if (text && strlen(text) > 0) {
+ Com_DPrintf(S_COLOR_YELLOW "EXEC_NOW %s\n", text);
+ Cmd_ExecuteString (text);
+ } else {
+ Cbuf_Execute();
+ Com_DPrintf(S_COLOR_YELLOW "EXEC_NOW %s\n", cmd_text.data);
+ }
+ break;
+ case EXEC_INSERT:
+ Cbuf_InsertText (text);
+ break;
+ case EXEC_APPEND:
+ Cbuf_AddText (text);
+ break;
+ default:
+ Com_Error (ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
+ }
+}
+
+/*
+============
+Cbuf_Execute
+============
+*/
+void Cbuf_Execute (void)
+{
+ int i;
+ char *text;
+ char line[MAX_CMD_LINE];
+ int quotes;
+
+ // This will keep // style comments all on one line by not breaking on
+ // a semicolon. It will keep /* ... */ style comments all on one line by not
+ // breaking it for semicolon or newline.
+ bool in_star_comment = false;
+ bool in_slash_comment = false;
+ while (cmd_text.cursize)
+ {
+ if ( cmd_wait > 0 ) {
+ // skip out while text still remains in buffer, leaving it
+ // for next frame
+ cmd_wait--;
+ break;
+ }
+
+ // find a \n or ; line break or comment: // or /* */
+ text = (char *)cmd_text.data;
+
+ quotes = 0;
+ for (i=0 ; i< cmd_text.cursize ; i++)
+ {
+ if (text[i] == '"')
+ quotes++;
+
+ if ( !(quotes&1)) {
+ if (i < cmd_text.cursize - 1) {
+ if (! in_star_comment && text[i] == '/' && text[i+1] == '/')
+ in_slash_comment = true;
+ else if (! in_slash_comment && text[i] == '/' && text[i+1] == '*')
+ in_star_comment = true;
+ else if (in_star_comment && text[i] == '*' && text[i+1] == '/') {
+ in_star_comment = false;
+ // If we are in a star comment, then the part after it is valid
+ // Note: This will cause it to NUL out the terminating '/'
+ // but ExecuteString doesn't require it anyway.
+ i++;
+ break;
+ }
+ }
+ if (! in_slash_comment && ! in_star_comment && text[i] == ';')
+ break;
+ }
+ if (! in_star_comment && (text[i] == '\n' || text[i] == '\r')) {
+ in_slash_comment = false;
+ break;
+ }
+ }
+
+ if( i >= (MAX_CMD_LINE - 1)) {
+ i = MAX_CMD_LINE - 1;
+ }
+
+ ::memcpy (line, text, i);
+ line[i] = 0;
+
+// delete the text from the command buffer and move remaining commands down
+// this is necessary because commands (exec) can insert data at the
+// beginning of the text buffer
+
+ if (i == cmd_text.cursize)
+ cmd_text.cursize = 0;
+ else
+ {
+ i++;
+ cmd_text.cursize -= i;
+ memmove (text, text+i, cmd_text.cursize);
+ }
+
+// execute the command line
+
+ Cmd_ExecuteString (line);
+ }
+}
+
+
+/*
+==============================================================================
+
+ SCRIPT COMMANDS
+
+==============================================================================
+*/
+
+
+/*
+===============
+Cmd_Exec_f
+===============
+*/
+void Cmd_Exec_f( void ) {
+ bool quiet;
+ union {
+ char *c;
+ void *v;
+ } f;
+ char filename[MAX_QPATH];
+
+ quiet = !Q_stricmp(Cmd_Argv(0), "execq");
+
+ if (Cmd_Argc () != 2) {
+ Com_Printf ("exec%s <filename> : execute a script file%s\n",
+ quiet ? "q" : "", quiet ? " without notification" : "");
+ return;
+ }
+
+ Q_strncpyz( filename, Cmd_Argv(1), sizeof( filename ) );
+ COM_DefaultExtension( filename, sizeof( filename ), ".cfg" );
+ FS_ReadFile( filename, &f.v);
+ if (!f.c) {
+ Com_Printf ("couldn't exec %s\n", filename);
+ return;
+ }
+ if (!quiet)
+ Com_Printf ("execing %s\n", filename);
+
+ Cbuf_InsertText (f.c);
+
+ FS_FreeFile (f.v);
+}
+
+
+/*
+===============
+Cmd_Vstr_f
+
+Inserts the current value of a variable as command text
+===============
+*/
+void Cmd_Vstr_f( void ) {
+ if (Cmd_Argc() != 2) {
+ Com_Printf ("vstr <variablename> : execute a variable command\n");
+ return;
+ }
+
+ const char* v = Cvar_VariableString( Cmd_Argv( 1 ) );
+ Cbuf_InsertFmtText( "%s\n", v );
+}
+
+
+/*
+===============
+Cmd_Echo_f
+
+Just prints the rest of the line to the console
+===============
+*/
+void Cmd_Echo_f (void)
+{
+ Com_Printf ("%s\n", Cmd_Args());
+}
+
+
+/*
+=============================================================================
+
+ COMMAND EXECUTION
+
+=============================================================================
+*/
+
+struct cmd_function_t
+{
+ cmd_function_t *next;
+ char *name;
+ xcommand_t function;
+ completionFunc_t complete;
+};
+
+
+typedef struct cmdContext_s
+{
+ int argc;
+ char *argv[ MAX_STRING_TOKENS ]; // points into cmd.tokenized
+ char tokenized[ BIG_INFO_STRING + MAX_STRING_TOKENS ]; // will have 0 bytes inserted
+ char cmd[ BIG_INFO_STRING ]; // the original command we received (no token processing)
+} cmdContext_t;
+
+static cmdContext_t cmd;
+static cmdContext_t savedCmd;
+static cmd_function_t *cmd_functions; // possible commands to execute
+
+/*
+============
+Cmd_SaveCmdContext
+============
+*/
+void Cmd_SaveCmdContext( void )
+{
+ ::memcpy( &savedCmd, &cmd, sizeof( cmdContext_t ) );
+}
+
+/*
+============
+Cmd_RestoreCmdContext
+============
+*/
+void Cmd_RestoreCmdContext( void )
+{
+ ::memcpy( &cmd, &savedCmd, sizeof( cmdContext_t ) );
+}
+
+/*
+============
+Cmd_Argc
+============
+*/
+int Cmd_Argc( void ) {
+ return cmd.argc;
+}
+
+/*
+============
+Cmd_Argv
+============
+*/
+char* Cmd_Argv( int arg ) {
+ if ( arg >= cmd.argc ) {
+ return (char*)"\0";
+ }
+ return cmd.argv[arg];
+}
+
+/*
+============
+Cmd_ArgvBuffer
+
+The interpreted versions use this because
+they can't have pointers returned to them
+============
+*/
+void Cmd_ArgvBuffer( int arg, char *buffer, int bufferLength ) {
+ Q_strncpyz( buffer, Cmd_Argv( arg ), bufferLength );
+}
+
+
+/*
+============
+Cmd_Args
+
+Returns a single string containing argv(1) to argv(argc()-1)
+============
+*/
+char *Cmd_Args( void ) {
+ static char cmd_args[MAX_STRING_CHARS];
+ int i;
+
+ cmd_args[0] = 0;
+ for ( i = 1 ; i < cmd.argc ; i++ ) {
+ strcat( cmd_args, cmd.argv[i] );
+ if ( i != cmd.argc-1 ) {
+ strcat( cmd_args, " " );
+ }
+ }
+
+ return cmd_args;
+}
+
+/*
+============
+Cmd_Args
+
+Returns a single string containing argv(arg) to argv(argc()-1)
+============
+*/
+char *Cmd_ArgsFrom( int arg ) {
+ static char cmd_args[BIG_INFO_STRING];
+ int i;
+
+ cmd_args[0] = 0;
+ if (arg < 0)
+ arg = 0;
+ for ( i = arg ; i < cmd.argc ; i++ ) {
+ strcat( cmd_args, cmd.argv[i] );
+ if ( i != cmd.argc-1 ) {
+ strcat( cmd_args, " " );
+ }
+ }
+
+ return cmd_args;
+}
+
+/*
+============
+Cmd_ArgsBuffer
+
+The interpreted versions use this because
+they can't have pointers returned to them
+============
+*/
+void Cmd_ArgsBuffer( char *buffer, int bufferLength ) {
+ Q_strncpyz( buffer, Cmd_Args(), bufferLength );
+}
+
+/*
+============
+Cmd_LiteralArgsBuffer
+
+The interpreted versions use this because
+they can't have pointers returned to them
+============
+*/
+void Cmd_LiteralArgsBuffer( char *buffer, int bufferLength ) {
+ Q_strncpyz( buffer, cmd.cmd, bufferLength );
+}
+
+/*
+============
+Cmd_Cmd
+
+Retrieve the unmodified command string
+For rcon use when you want to transmit without altering quoting
+https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543
+============
+*/
+char *Cmd_Cmd(void)
+{
+ return cmd.cmd;
+}
+
+/*
+============
+Cmd_TokenizeString
+
+Parses the given string into command line tokens.
+The text is copied to a seperate buffer and 0 characters
+are inserted in the apropriate place, The argv array
+will point into this temporary buffer.
+============
+*/
+// NOTE TTimo define that to track tokenization issues
+//#define TKN_DBG
+static void Cmd_TokenizeString2( const char *text_in, bool ignoreQuotes ) {
+ const char *text;
+ char *textOut;
+
+#ifdef TKN_DBG
+ // FIXME TTimo blunt hook to try to find the tokenization of userinfo
+ Com_DPrintf("Cmd_TokenizeString: %s\n", text_in);
+#endif
+
+ // clear previous args
+ cmd.argc = 0;
+ cmd.cmd[ 0 ] = '\0';
+
+ if ( !text_in ) {
+ return;
+ }
+
+ Q_strncpyz( cmd.cmd, text_in, sizeof(cmd.cmd) );
+
+ text = text_in;
+ textOut = cmd.tokenized;
+
+ while ( 1 ) {
+ if ( cmd.argc == MAX_STRING_TOKENS ) {
+ return; // this is usually something malicious
+ }
+
+ while ( 1 ) {
+ // skip whitespace
+ while ( *text && *text <= ' ' ) {
+ text++;
+ }
+ if ( !*text ) {
+ return; // all tokens parsed
+ }
+
+ // skip // comments
+ if ( text[0] == '/' && text[1] == '/' ) {
+ return; // all tokens parsed
+ }
+
+ // skip /* */ comments
+ if ( text[0] == '/' && text[1] =='*' ) {
+ while ( *text && ( text[0] != '*' || text[1] != '/' ) ) {
+ text++;
+ }
+ if ( !*text ) {
+ return; // all tokens parsed
+ }
+ text += 2;
+ } else {
+ break; // we are ready to parse a token
+ }
+ }
+
+ // handle quoted strings
+ // NOTE TTimo this doesn't handle \" escaping
+ if ( !ignoreQuotes && *text == '"' ) {
+ cmd.argv[cmd.argc] = textOut;
+ cmd.argc++;
+ text++;
+ while ( *text && *text != '"' ) {
+ *textOut++ = *text++;
+ }
+ *textOut++ = 0;
+ if ( !*text ) {
+ return; // all tokens parsed
+ }
+ text++;
+ continue;
+ }
+
+ // regular token
+ cmd.argv[cmd.argc] = textOut;
+ cmd.argc++;
+
+ // skip until whitespace, quote, or command
+ while ( *text > ' ' ) {
+ if ( !ignoreQuotes && text[0] == '"' ) {
+ break;
+ }
+
+ if ( text[0] == '/' && text[1] == '/' ) {
+ break;
+ }
+
+ // skip /* */ comments
+ if ( text[0] == '/' && text[1] =='*' ) {
+ break;
+ }
+
+ *textOut++ = *text++;
+ }
+
+ *textOut++ = 0;
+
+ if ( !*text ) {
+ return; // all tokens parsed
+ }
+ }
+
+}
+
+/*
+============
+Cmd_TokenizeString
+============
+*/
+void Cmd_TokenizeString( const char *text_in ) {
+ Cmd_TokenizeString2( text_in, false );
+}
+
+/*
+============
+Cmd_TokenizeStringIgnoreQuotes
+============
+*/
+void Cmd_TokenizeStringIgnoreQuotes( const char *text_in ) {
+ Cmd_TokenizeString2( text_in, true );
+}
+
+/*
+============
+Cmd_FindCommand
+============
+*/
+cmd_function_t *Cmd_FindCommand( const char *cmd_name )
+{
+ cmd_function_t *cmd;
+ for( cmd = cmd_functions; cmd; cmd = cmd->next )
+ if( !Q_stricmp( cmd_name, cmd->name ) )
+ return cmd;
+ return nullptr;
+}
+
+/*
+============
+Cmd_FindCommand
+============
+*/
+bool Cmd_CommadExists( const char *cmd_name )
+{
+ return Cmd_FindCommand( cmd_name ) ? true : false;
+}
+
+/*
+============
+Cmd_AddCommand
+============
+*/
+void Cmd_AddCommand( const char *cmd_name, xcommand_t function ) {
+ cmd_function_t *cmd;
+
+ // fail if the command already exists
+ if( Cmd_FindCommand( cmd_name ) )
+ {
+ // allow completion-only commands to be silently doubled
+ if( function != nullptr )
+ Com_Printf( "Cmd_AddCommand: %s already defined\n", cmd_name );
+ return;
+ }
+
+ // use a small malloc to avoid zone fragmentation
+ cmd = new cmd_function_t;
+ cmd->name = CopyString( cmd_name );
+ cmd->function = function;
+ cmd->complete = nullptr;
+ cmd->next = cmd_functions;
+ cmd_functions = cmd;
+}
+
+/*
+============
+Cmd_SetCommandCompletionFunc
+============
+*/
+void Cmd_SetCommandCompletionFunc( const char *command, completionFunc_t complete ) {
+ cmd_function_t *cmd;
+
+ for( cmd = cmd_functions; cmd; cmd = cmd->next ) {
+ if( !Q_stricmp( command, cmd->name ) ) {
+ cmd->complete = complete;
+ return;
+ }
+ }
+}
+
+/*
+============
+Cmd_RemoveCommand
+============
+*/
+void Cmd_RemoveCommand( const char *cmd_name )
+{
+ cmd_function_t *cmd, **back;
+
+ back = &cmd_functions;
+ for ( ;; )
+ {
+ cmd = *back;
+ if ( !cmd ) {
+ // command wasn't active
+ return;
+ }
+ if ( !strcmp( cmd_name, cmd->name ) ) {
+ *back = cmd->next;
+ if (cmd->name) {
+ Z_Free(cmd->name);
+ }
+ delete cmd;
+ return;
+ }
+ back = &cmd->next;
+ }
+}
+
+/*
+============
+Cmd_RemoveCommandSafe
+
+Only remove commands with no associated function
+============
+*/
+void Cmd_RemoveCommandSafe( const char *cmd_name )
+{
+ cmd_function_t *cmd = Cmd_FindCommand( cmd_name );
+
+ if( !cmd )
+ return;
+
+ if( cmd->function )
+ {
+ Com_Error( ERR_DROP, "Restricted source tried to remove system command \"%s\"",
+ cmd_name );
+ return;
+ }
+
+ Cmd_RemoveCommand( cmd_name );
+}
+
+/*
+============
+Cmd_CommandCompletion
+============
+*/
+void Cmd_CommandCompletion( void(*callback)(const char *s) ) {
+ cmd_function_t *cmd;
+
+ for (cmd=cmd_functions ; cmd ; cmd=cmd->next) {
+ callback( cmd->name );
+ }
+}
+
+/*
+============
+Cmd_CompleteArgument
+============
+*/
+void Cmd_CompleteArgument( const char *command, char *args, int argNum )
+{
+ cmd_function_t *cmd;
+
+ // FIXIT-H: There needs to be a way to toggle this functionality at runtime
+ // rather than just crashing when a cgame doesn't provide support. #45
+ // https://github.com/GrangerHub/tremulous/issues/45
+#if 0
+#ifndef DEDICATED
+ // Forward command argument completion to CGAME VM
+ if( cls.cgame && !VM_Call( cls.cgame, CG_CONSOLE_COMPLETARGUMENT, argNum ) )
+#endif
+#endif
+ // Call local completion if VM doesn't pick up
+ for( cmd = cmd_functions; cmd; cmd = cmd->next )
+ if( !Q_stricmp( command, cmd->name ) && cmd->complete )
+ cmd->complete( args, argNum );
+}
+
+
+/*
+============
+Cmd_ExecuteString
+
+A complete command line has been parsed, so try to execute it
+============
+*/
+void Cmd_ExecuteString( const char *text ) {
+ cmd_function_t *cmdFunc, **prev;
+
+ // execute the command line
+ Cmd_TokenizeString( text );
+ if ( !Cmd_Argc() ) {
+ return; // no tokens
+ }
+
+ // check registered command functions
+ for ( prev = &cmd_functions ; *prev ; prev = &cmdFunc->next ) {
+ cmdFunc = *prev;
+ if ( !Q_stricmp( cmd.argv[0], cmdFunc->name ) ) {
+ // rearrange the links so that the command will be
+ // near the head of the list next time it is used
+ *prev = cmdFunc->next;
+ cmdFunc->next = cmd_functions;
+ cmd_functions = cmdFunc;
+
+ // perform the action
+ if ( !cmdFunc->function ) {
+ // let the cgame or game handle it
+ break;
+ } else {
+ cmdFunc->function ();
+ }
+ return;
+ }
+ }
+
+ // check cvars
+ if ( Cvar_Command() ) {
+ return;
+ }
+
+ // check client game commands
+ if ( com_cl_running && com_cl_running->integer && CL_GameCommand() ) {
+ return;
+ }
+
+ // check server game commands
+ if ( com_sv_running && com_sv_running->integer && SV_GameCommand() ) {
+ return;
+ }
+
+ // check ui commands
+ if ( com_cl_running && com_cl_running->integer && UI_GameCommand() ) {
+ return;
+ }
+
+ // send it as a server command if we are connected
+ CL_ForwardCommandToServer ( text );
+}
+
+/*
+============
+Cmd_List_f
+============
+*/
+void Cmd_List_f (void)
+{
+ cmd_function_t* cmd;
+ int i;
+ const char* match;
+
+ if ( Cmd_Argc() > 1 ) {
+ match = Cmd_Argv( 1 );
+ } else {
+ match = nullptr;
+ }
+
+ i = 0;
+ for (cmd=cmd_functions ; cmd ; cmd=cmd->next) {
+ if (match && !Com_Filter(match, cmd->name, false)) continue;
+
+ Com_Printf ("%s\n", cmd->name);
+ i++;
+ }
+ Com_Printf ("%i commands\n", i);
+}
+
+/*
+==================
+Cmd_CompleteCfgName
+==================
+*/
+void Cmd_CompleteCfgName( char *args, int argNum ) {
+ if( argNum == 2 ) {
+ Field_CompleteFilename( "", "cfg", false, true );
+ }
+}
+
+/*
+============
+Cmd_Init
+============
+*/
+void Cmd_Init (void) {
+ Cmd_AddCommand ("cmdlist",Cmd_List_f);
+ Cmd_AddCommand ("exec",Cmd_Exec_f);
+ Cmd_AddCommand ("execq",Cmd_Exec_f);
+ Cmd_SetCommandCompletionFunc( "exec", Cmd_CompleteCfgName );
+ Cmd_SetCommandCompletionFunc( "execq", Cmd_CompleteCfgName );
+ Cmd_AddCommand ("vstr",Cmd_Vstr_f);
+ Cmd_SetCommandCompletionFunc( "vstr", Cvar_CompleteCvarName );
+ Cmd_AddCommand ("echo",Cmd_Echo_f);
+ Cmd_AddCommand ("wait", Cmd_Wait_f);
+}
diff --git a/src/qcommon/cmd.h b/src/qcommon/cmd.h
new file mode 100644
index 0000000..390fa85
--- /dev/null
+++ b/src/qcommon/cmd.h
@@ -0,0 +1,115 @@
+/*
+ * This file is part of Tremulous.
+ * Copyright © 2017 Victor Roemer (blowfish) <victor@badsec.org>
+ * Copyright (C) 2015-2019 GrangerHub
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CMD_H
+#define CMD_H
+
+/*
+==============================================================
+
+CMD
+
+Command text buffering and command execution
+
+==============================================================
+*/
+
+/*
+
+Any number of commands can be added in a frame, from several different sources.
+Most commands come from either keybindings or console line input, but entire text
+files can be execed.
+
+*/
+
+void Cbuf_Init(void);
+// allocates an initial text buffer that will grow as needed
+
+void Cbuf_AddText(const char *text);
+// Adds command text at the end of the buffer, does NOT add a final \n
+
+void Cbuf_ExecuteText(int exec_when, const char *text);
+// this can be used in place of either Cbuf_AddText or Cbuf_InsertText
+
+void Cbuf_Execute(void);
+// Pulls off \n terminated lines of text from the command buffer and sends
+// them through Cmd_ExecuteString. Stops when the buffer is empty.
+// Normally called once per frame, but may be explicitly invoked.
+// Do not call inside a command function, or current args will be destroyed.
+
+//===========================================================================
+
+/*
+
+Command execution takes a null terminated string, breaks it into tokens,
+then searches for a command or variable that matches the first token.
+
+*/
+
+using xcommand_t = void(*)();
+
+void Cmd_Init(void);
+
+bool Cmd_CommadExists( const char *cmd_name );
+
+void Cmd_AddCommand(const char *cmd_name, xcommand_t function);
+// called by the init functions of other parts of the program to
+// register commands and functions to call for them.
+// The cmd_name is referenced later, so it should not be in temp memory
+// if function is NULL, the command will be forwarded to the server
+// as a clc_clientCommand instead of executed locally
+
+void Cmd_RemoveCommand(const char *cmd_name);
+
+typedef void (*completionFunc_t)(char *args, int argNum);
+
+// don't allow VMs to remove system commands
+void Cmd_RemoveCommandSafe(const char *cmd_name);
+
+void Cmd_CommandCompletion(void (*callback)(const char *s));
+// callback with each valid string
+void Cmd_SetCommandCompletionFunc(const char *command, completionFunc_t complete);
+void Cmd_CompleteArgument(const char *command, char *args, int argNum);
+void Cmd_CompleteCfgName(char *args, int argNum);
+
+int Cmd_Argc(void);
+char *Cmd_Argv(int arg);
+void Cmd_ArgvBuffer(int arg, char *buffer, int bufferLength);
+char *Cmd_Args(void);
+char *Cmd_ArgsFrom(int arg);
+void Cmd_ArgsBuffer(char *buffer, int bufferLength);
+void Cmd_LiteralArgsBuffer(char *buffer, int bufferLength);
+char *Cmd_Cmd(void);
+// The functions that execute commands get their parameters with these
+// functions. Cmd_Argv () will return an empty string, not a NULL
+// if arg > argc, so string operations are allways safe.
+
+void Cmd_TokenizeString(const char *text);
+void Cmd_TokenizeStringIgnoreQuotes(const char *text_in);
+// Takes a null terminated string. Does not need to be /n terminated.
+// breaks the string up into arg tokens.
+
+void Cmd_ExecuteString(const char *text);
+// Parses a single line of text into arguments and tries to execute it
+// as if it was typed at the console
+
+void Cmd_SaveCmdContext(void);
+void Cmd_RestoreCmdContext(void);
+
+#endif
diff --git a/src/qcommon/common.cpp b/src/qcommon/common.cpp
new file mode 100644
index 0000000..051f475
--- /dev/null
+++ b/src/qcommon/common.cpp
@@ -0,0 +1,3662 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// common.c -- misc functions used in client and server
+
+#include "qcommon.h"
+
+#include <setjmp.h>
+#ifdef _WIN32
+#include <winsock.h>
+#else
+#include <netinet/in.h>
+//#include <sys/stat.h> // umask
+#endif
+
+#include "sys/sys_shared.h"
+
+#include "cmd.h"
+#include "crypto.h"
+#include "cvar.h"
+#include "files.h"
+#define JSON_IMPLEMENTATION
+#include "json.h"
+#include "msg.h"
+#include "q_shared.h"
+#include "vm.h"
+
+int demo_protocols[] = { PROTOCOL_VERSION, 70, 69, 0 };
+
+#define MAX_NUM_ARGVS 50
+
+#define MIN_DEDICATED_COMHUNKMEGS 16
+#define MIN_COMHUNKMEGS 256
+#define DEF_COMHUNKMEGS 256
+#define DEF_COMZONEMEGS 48
+#define DEF_COMHUNKMEGS_S XSTRING(DEF_COMHUNKMEGS)
+#define DEF_COMZONEMEGS_S XSTRING(DEF_COMZONEMEGS)
+
+int com_argc;
+char* com_argv[MAX_NUM_ARGVS+1];
+
+jmp_buf abortframe; // an ERR_DROP occured, exit the entire frame
+
+
+FILE *debuglogfile;
+static fileHandle_t pipefile;
+static fileHandle_t logfile;
+fileHandle_t com_journalFile; // events are written here
+fileHandle_t com_journalDataFile; // config files are written here
+
+cvar_t *com_speeds;
+cvar_t *com_developer;
+cvar_t *com_dedicated;
+cvar_t *com_timescale;
+cvar_t *com_fixedtime;
+cvar_t *com_journal;
+cvar_t *com_maxfps;
+cvar_t *com_altivec;
+cvar_t *com_timedemo;
+cvar_t *com_sv_running;
+cvar_t *com_cl_running;
+cvar_t *com_logfile; // 1 = buffer log, 2 = flush after each print
+cvar_t *com_pipefile;
+cvar_t *com_showtrace;
+cvar_t *com_version;
+cvar_t *com_buildScript; // for automated data building scripts
+#ifdef CINEMATICS_INTRO
+cvar_t *com_introPlayed;
+#endif
+cvar_t *cl_paused;
+cvar_t *sv_paused;
+cvar_t *cl_packetdelay;
+cvar_t *sv_packetdelay;
+cvar_t *com_cameraMode;
+cvar_t *com_ansiColor;
+cvar_t *com_unfocused;
+cvar_t *com_maxfpsUnfocused;
+cvar_t *com_minimized;
+cvar_t *com_maxfpsMinimized;
+cvar_t *com_standalone;
+cvar_t *com_gamename;
+cvar_t *com_protocol;
+#ifdef LEGACY_PROTOCOL
+cvar_t *com_legacyprotocol;
+#endif
+cvar_t *com_basegame;
+cvar_t *com_homepath;
+cvar_t *com_busyWait;
+
+#if id386
+void (QDECL *Q_SnapVector)(vec3_t vec);
+#endif
+
+// com_speeds times
+int time_game;
+int time_frontend; // renderer frontend time
+int time_backend; // renderer backend time
+
+int com_frameTime;
+int com_frameNumber;
+
+bool com_errorEntered = false;
+bool com_fullyInitialized = false;
+bool com_gameRestarting = false;
+
+char com_errorMessage[MAXPRINTMSG];
+
+void Com_WriteConfig_f( void );
+void CIN_CloseAllVideos( void );
+
+//============================================================================
+
+static char* rd_buffer;
+static unsigned int rd_buffersize;
+static void (*rd_flush)( char *buffer );
+
+void Com_BeginRedirect (char *buffer, int buffersize, void (*flush)( char *) )
+{
+ if (!buffer || !buffersize || !flush)
+ return;
+ rd_buffer = buffer;
+ rd_buffersize = buffersize;
+ rd_flush = flush;
+
+ *rd_buffer = 0;
+}
+
+void Com_EndRedirect(void)
+{
+ if ( rd_flush )
+ rd_flush(rd_buffer);
+
+ rd_buffer = NULL;
+ rd_buffersize = 0;
+ rd_flush = NULL;
+}
+
+/*
+=============
+Com_Printf
+
+Both client and server can use this, and it will output
+to the apropriate place.
+
+A raw string should NEVER be passed as fmt, because of "%f" type crashers.
+=============
+*/
+void QDECL Com_Printf( const char *fmt, ... )
+{
+ va_list argptr;
+ char msg[MAXPRINTMSG];
+ static bool opening_qconsole = false;
+
+
+ va_start (argptr,fmt);
+ Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
+ va_end (argptr);
+
+ if ( rd_buffer )
+ {
+ if ((strlen(msg) + strlen(rd_buffer)) > (rd_buffersize - 1))
+ {
+ rd_flush(rd_buffer);
+ *rd_buffer = 0;
+ }
+ Q_strcat(rd_buffer, rd_buffersize, msg);
+ // TTimo nooo .. that would defeat the purpose
+ //rd_flush(rd_buffer);
+ //*rd_buffer = 0;
+ return;
+ }
+
+#ifndef DEDICATED
+ CL_ConsolePrint( msg );
+#endif
+
+ Q_StripIndentMarker( msg );
+
+ // echo to dedicated console and early console
+ Sys_Print( msg );
+
+ // logfile
+ if ( com_logfile && com_logfile->integer ) {
+ // TTimo: only open the qconsole.log if the filesystem is in an initialized state
+ // also, avoid recursing in the qconsole.log opening (i.e. if fs_debug is on)
+ if ( !logfile && FS_Initialized() && !opening_qconsole) {
+ struct tm *newtime;
+ time_t aclock;
+
+ opening_qconsole = true;
+
+ time( &aclock );
+ newtime = localtime( &aclock );
+
+ logfile = FS_FOpenFileWrite( "qconsole.log" );
+
+ if(logfile)
+ {
+ Com_Printf( "logfile opened on %s\n", asctime( newtime ) );
+
+ if ( com_logfile->integer > 1 )
+ {
+ // force it to not buffer so we get valid
+ // data even if we are crashing
+ FS_ForceFlush(logfile);
+ }
+ }
+ else
+ {
+ Com_Printf("Opening qconsole.log failed!\n");
+ Cvar_SetValue("logfile", 0);
+ }
+
+ opening_qconsole = false;
+ }
+ if ( logfile && FS_Initialized()) {
+ FS_Write(msg, strlen(msg), logfile);
+ }
+ }
+}
+
+
+/*
+================
+Com_DPrintf
+
+A Com_Printf that only shows up if the "developer" cvar is set
+================
+*/
+void QDECL Com_DPrintf( const char *fmt, ...)
+{
+ va_list argptr;
+ char msg[MAXPRINTMSG];
+
+ if ( !com_developer || !com_developer->integer )
+ return;
+
+ va_start(argptr,fmt);
+ Q_vsnprintf(msg, sizeof(msg), fmt, argptr);
+ va_end(argptr);
+
+ Com_Printf("%s", msg);
+}
+
+/*
+=============
+Com_Error
+
+Both client and server can use this, and it will
+do the appropriate thing.
+=============
+*/
+void QDECL Com_Error( int code, const char *fmt, ... )
+{
+ va_list argptr;
+ static int lastErrorTime;
+ static int errorCount;
+ int currentTime;
+
+ if(com_errorEntered)
+ Sys_Error("recursive error after: %s", com_errorMessage);
+
+ com_errorEntered = true;
+
+ Cvar_Set("com_errorCode", va("%i", code));
+
+ // when we are running automated scripts, make sure we
+ // know if anything failed
+ if ( com_buildScript && com_buildScript->integer )
+ code = ERR_FATAL;
+
+ // if we are getting a solid stream of ERR_DROP, do an ERR_FATAL
+ currentTime = Sys_Milliseconds();
+ if ( currentTime - lastErrorTime < 100 )
+ {
+ if ( ++errorCount > 3 )
+ code = ERR_FATAL;
+ }
+ else
+ {
+ errorCount = 0;
+ }
+ lastErrorTime = currentTime;
+
+ va_start(argptr,fmt);
+ Q_vsnprintf(com_errorMessage, sizeof(com_errorMessage),fmt,argptr);
+ va_end(argptr);
+
+ if ( code != ERR_DISCONNECT )
+ Cvar_Set("com_errorMessage", com_errorMessage);
+
+ if (code == ERR_DISCONNECT || code == ERR_SERVERDISCONNECT)
+ {
+ VM_Forced_Unload_Start();
+ SV_Shutdown( "Server disconnected" );
+ CL_Disconnect( true );
+ CL_FlushMemory( );
+ VM_Forced_Unload_Done();
+ // make sure we can get at our local stuff
+ FS_PureServerSetLoadedPaks("", "");
+ com_errorEntered = false;
+ longjmp (abortframe, -1);
+ }
+ else if (code == ERR_DROP || code == ERR_RECONNECT)
+ {
+ Com_Printf ("********************\nERROR: %s\n********************\n", com_errorMessage);
+ VM_Forced_Unload_Start();
+ SV_Shutdown(va("Server crashed: %s", com_errorMessage));
+ CL_Disconnect( true );
+ CL_FlushMemory( );
+ VM_Forced_Unload_Done();
+ FS_PureServerSetLoadedPaks("", "");
+ com_errorEntered = false;
+
+ static int reconnectCount = 0;
+ if ( code == ERR_RECONNECT && reconnectCount <= 0 )
+ {
+ reconnectCount++;
+ Cbuf_AddText("reconnect\n");
+ }
+ else
+ {
+ reconnectCount = 0;
+ }
+
+ longjmp(abortframe, -1);
+ }
+ else
+ {
+ VM_Forced_Unload_Start();
+ CL_Shutdown(va("Client fatal crashed: %s", com_errorMessage), true, true);
+ SV_Shutdown(va("Server fatal crashed: %s", com_errorMessage));
+ VM_Forced_Unload_Done();
+ }
+
+ Com_Shutdown();
+
+ Sys_Error("%s", com_errorMessage);
+}
+
+/*
+=============
+Com_Quit_f
+
+Both client and server can use this, and it will
+do the apropriate things.
+=============
+*/
+void Engine_Exit(const char* p )
+{
+ // don't try to shutdown if we are in a recursive error
+ if ( !com_errorEntered )
+ {
+ // Some VMs might execute "quit" command directly,
+ // which would trigger an unload of active VM error.
+ // Sys_Quit will kill this process anyways, so
+ // a corrupt call stack makes no difference
+ VM_Forced_Unload_Start();
+ SV_Shutdown(p[0] ? p : "Server quit");
+ CL_Shutdown(p[0] ? p : "Client quit", true, true);
+ VM_Forced_Unload_Done();
+ Com_Shutdown();
+ FS_Shutdown(true);
+ }
+ Sys_Quit ();
+}
+
+void Com_Quit_f( void )
+{
+ char *p = Cmd_Args();
+ Engine_Exit(p);
+}
+
+
+
+/*
+============================================================================
+
+COMMAND LINE FUNCTIONS
+
++ characters seperate the commandLine string into multiple console
+command lines.
+
+All of these are valid:
+
+tremulous +set test blah +map test
+tremulous set test blah+map test
+tremulous set test blah + map test
+
+============================================================================
+*/
+
+#define MAX_CONSOLE_LINES 32
+int com_numConsoleLines;
+char* com_consoleLines[MAX_CONSOLE_LINES];
+
+/*
+==================
+Com_ParseCommandLine
+
+Break it up into multiple console lines
+==================
+*/
+void Com_ParseCommandLine( char *commandLine )
+{
+ int inq = 0;
+ com_consoleLines[0] = commandLine;
+ com_numConsoleLines = 1;
+
+ while ( *commandLine )
+ {
+ if ( *commandLine == '"' )
+ inq = !inq;
+
+ // look for a + seperating character
+ // if commandLine came from a file, we might have real line seperators
+ if ( (commandLine[0] == '+' && !inq) || commandLine[0] == '\n' || commandLine[0] == '\r' )
+ {
+ if ( com_numConsoleLines == MAX_CONSOLE_LINES )
+ return;
+
+ com_consoleLines[com_numConsoleLines] = commandLine + 1;
+ com_numConsoleLines++;
+ *commandLine = 0;
+ }
+ commandLine++;
+ }
+}
+
+/*
+===================
+Com_SafeMode
+
+Check for "safe" on the command line, which will
+skip loading of autogen.cfg
+===================
+*/
+bool Com_SafeMode( void )
+{
+ for ( int i = 0 ; i < com_numConsoleLines ; i++ )
+ {
+ Cmd_TokenizeString(com_consoleLines[i]);
+ if ( !Q_stricmp(Cmd_Argv(0), "safe")
+ || !Q_stricmp(Cmd_Argv(0), "cvar_restart") )
+ {
+ com_consoleLines[i][0] = 0;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*
+===============
+Com_StartupVariable
+
+Searches for command line parameters that are set commands.
+If match is not NULL, only that cvar will be looked for.
+That is necessary because cddir and basedir need to be set
+before the filesystem is started, but all other sets should
+be after execing the config and default.
+===============
+*/
+void Com_StartupVariable( const char *match )
+{
+ for (int i = 0 ; i < com_numConsoleLines ; i++)
+ {
+ Cmd_TokenizeString( com_consoleLines[i] );
+ if ( strcmp( Cmd_Argv(0), "set" ) ) {
+ continue;
+ }
+
+ const char* s = Cmd_Argv(1);
+ if(!match || !strcmp(s, match))
+ {
+ if(Cvar_Flags(s) == CVAR_NONEXISTENT)
+ Cvar_Get(s, Cmd_ArgsFrom(2), CVAR_USER_CREATED);
+ else
+ Cvar_Set2(s, Cmd_ArgsFrom(2), false);
+ }
+ }
+}
+
+/*
+=================
+Com_AddStartupCommands
+
+Adds command line parameters as script statements
+Commands are seperated by + signs
+
+Returns true if any late commands were added
+=================
+*/
+bool Com_AddStartupCommands( void )
+{
+ bool added = false;
+
+ // quote every token, so args with semicolons can work
+ for ( int i = 0 ; i < com_numConsoleLines ; i++)
+ {
+ if ( !com_consoleLines[i] || !com_consoleLines[i][0] )
+ continue;
+
+ // set commands already added with Com_StartupVariable
+ if ( !Q_stricmpn(com_consoleLines[i], "set ", 4) )
+ continue;
+
+ added = true;
+ Cbuf_AddText( com_consoleLines[i] );
+ Cbuf_AddText( "\n" );
+ }
+
+ return added;
+}
+
+//============================================================================
+
+void Info_Print( const char *s )
+{
+ char key[BIG_INFO_KEY];
+ char value[BIG_INFO_VALUE];
+ char* o;
+ int l;
+
+ if (*s == '\\')
+ s++;
+
+ while (*s)
+ {
+ o = key;
+ while (*s && *s != '\\')
+ *o++ = *s++;
+
+ l = o - key;
+ if (l < 20)
+ {
+ ::memset(o, ' ', 20-l);
+ key[20] = 0;
+ }
+ else
+ *o = 0;
+ Com_Printf("%s ", key);
+
+ if (!*s)
+ {
+ Com_Printf("MISSING VALUE\n");
+ return;
+ }
+
+ o = value;
+ s++;
+ while (*s && *s != '\\')
+ *o++ = *s++;
+ *o = 0;
+
+ if (*s)
+ s++;
+
+ Com_Printf("%s\n", value);
+ }
+}
+
+/*
+============
+Com_StringContains
+============
+*/
+char *Com_StringContains(char *str1, char *str2, int casesensitive)
+{
+ int len, i, j;
+
+ len = strlen(str1) - strlen(str2);
+ for (i = 0; i <= len; i++, str1++) {
+ for (j = 0; str2[j]; j++) {
+ if (casesensitive) {
+ if (str1[j] != str2[j]) {
+ break;
+ }
+ }
+ else {
+ if (toupper(str1[j]) != toupper(str2[j])) {
+ break;
+ }
+ }
+ }
+ if (!str2[j]) {
+ return str1;
+ }
+ }
+ return NULL;
+}
+
+/*
+============
+Com_Filter
+============
+*/
+int Com_Filter(const char* filter, char *name, int casesensitive)
+{
+ char buf[MAX_TOKEN_CHARS];
+ char *ptr;
+ int i, found;
+
+ while(*filter) {
+ if (*filter == '*') {
+ filter++;
+ for (i = 0; *filter; i++) {
+ if (*filter == '*' || *filter == '?') break;
+ buf[i] = *filter;
+ filter++;
+ }
+ buf[i] = '\0';
+ if (strlen(buf)) {
+ ptr = Com_StringContains(name, buf, casesensitive);
+ if (!ptr) return false;
+ name = ptr + strlen(buf);
+ }
+ }
+ else if (*filter == '?') {
+ filter++;
+ name++;
+ }
+ else if (*filter == '[' && *(filter+1) == '[') {
+ filter++;
+ }
+ else if (*filter == '[') {
+ filter++;
+ found = false;
+ while(*filter && !found) {
+ if (*filter == ']' && *(filter+1) != ']') break;
+ if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {
+ if (casesensitive) {
+ if (*name >= *filter && *name <= *(filter+2)) found = true;
+ }
+ else {
+ if (toupper(*name) >= toupper(*filter) &&
+ toupper(*name) <= toupper(*(filter+2))) found = true;
+ }
+ filter += 3;
+ }
+ else {
+ if (casesensitive) {
+ if (*filter == *name) found = true;
+ }
+ else {
+ if (toupper(*filter) == toupper(*name)) found = true;
+ }
+ filter++;
+ }
+ }
+ if (!found) return false;
+ while(*filter) {
+ if (*filter == ']' && *(filter+1) != ']') break;
+ filter++;
+ }
+ filter++;
+ name++;
+ }
+ else {
+ if (casesensitive) {
+ if (*filter != *name) return false;
+ }
+ else {
+ if (toupper(*filter) != toupper(*name)) return false;
+ }
+ filter++;
+ name++;
+ }
+ }
+ return true;
+}
+
+/*
+============
+Com_FilterPath
+============
+*/
+int Com_FilterPath(const char *filter, char *name, int casesensitive)
+{
+ int i;
+ char new_filter[MAX_QPATH];
+ char new_name[MAX_QPATH];
+
+ for (i = 0; i < MAX_QPATH-1 && filter[i]; i++) {
+ if ( filter[i] == '\\' || filter[i] == ':' ) {
+ new_filter[i] = '/';
+ }
+ else {
+ new_filter[i] = filter[i];
+ }
+ }
+ new_filter[i] = '\0';
+ for (i = 0; i < MAX_QPATH-1 && name[i]; i++) {
+ if ( name[i] == '\\' || name[i] == ':' ) {
+ new_name[i] = '/';
+ }
+ else {
+ new_name[i] = name[i];
+ }
+ }
+ new_name[i] = '\0';
+ return Com_Filter(new_filter, new_name, casesensitive);
+}
+
+/*
+================
+Com_RealTime
+================
+*/
+int Com_RealTime(qtime_t *qtime)
+{
+ time_t t;
+ struct tm *tms;
+
+ t = time(NULL);
+ if (!qtime)
+ return t;
+ tms = localtime(&t);
+ if (tms) {
+ qtime->tm_sec = tms->tm_sec;
+ qtime->tm_min = tms->tm_min;
+ qtime->tm_hour = tms->tm_hour;
+ qtime->tm_mday = tms->tm_mday;
+ qtime->tm_mon = tms->tm_mon;
+ qtime->tm_year = tms->tm_year;
+ qtime->tm_wday = tms->tm_wday;
+ qtime->tm_yday = tms->tm_yday;
+ qtime->tm_isdst = tms->tm_isdst;
+ }
+ return t;
+}
+
+/*
+==============================================================================
+
+ZONE MEMORY ALLOCATION
+
+There is never any space between memblocks, and there will never be two
+contiguous free memblocks.
+
+The rover can be left pointing at a non-empty block
+
+The zone calls are pretty much only used for small strings and structures,
+all big things are allocated on the hunk.
+==============================================================================
+*/
+
+#define ZONEID 0x1d4a11
+#define MINFRAGMENT 64
+
+typedef struct zonedebug_s {
+ const char *label;
+ const char *file;
+ int line;
+ int allocSize;
+} zonedebug_t;
+
+typedef struct memblock_s {
+ int size; // including the header and possibly tiny fragments
+ int tag; // a tag of 0 is a free block
+ struct memblock_s *next, *prev;
+ int id; // should be ZONEID
+#ifdef ZONE_DEBUG
+ zonedebug_t d;
+#endif
+} memblock_t;
+
+typedef struct {
+ int size; // total bytes malloced, including header
+ int used; // total bytes used
+ memblock_t blocklist; // start / end cap for linked list
+ memblock_t *rover;
+} memzone_t;
+
+// main zone for all "dynamic" memory allocation
+memzone_t *mainzone;
+// we also have a small zone for small allocations that would only
+// fragment the main zone (think of cvar and cmd strings)
+memzone_t *smallzone;
+
+void Z_CheckHeap( void );
+
+/*
+========================
+Z_ClearZone
+========================
+*/
+void Z_ClearZone( memzone_t *zone, int size )
+{
+ memblock_t *block;
+
+ // set the entire zone to one free block
+
+ zone->blocklist.next = zone->blocklist.prev = block =
+ (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
+ zone->blocklist.tag = 1; // in use block
+ zone->blocklist.id = 0;
+ zone->blocklist.size = 0;
+ zone->rover = block;
+ zone->size = size;
+ zone->used = 0;
+
+ block->prev = block->next = &zone->blocklist;
+ block->tag = 0; // free block
+ block->id = ZONEID;
+ block->size = size - sizeof(memzone_t);
+}
+
+/*
+========================
+Z_AvailableZoneMemory
+========================
+*/
+int Z_AvailableZoneMemory( memzone_t *zone )
+{
+ return zone->size - zone->used;
+}
+
+/*
+========================
+Z_AvailableMemory
+========================
+*/
+int Z_AvailableMemory( void )
+{
+ return Z_AvailableZoneMemory( mainzone );
+}
+
+/*
+========================
+Z_Free
+========================
+*/
+void Z_Free( void *ptr )
+{
+ memblock_t *block, *other;
+ memzone_t *zone;
+
+ if (!ptr) {
+ Com_Printf(S_COLOR_YELLOW "Z_Free: NULL pointer" );
+ return;
+ }
+
+ block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+ if (block->id != ZONEID) {
+ Com_Error( ERR_FATAL, "Z_Free: freed a pointer without ZONEID" );
+ }
+ if (block->tag == 0) {
+ Com_Error( ERR_FATAL, "Z_Free: freed a freed pointer" );
+ }
+ // if static memory
+ if (block->tag == TAG_STATIC) {
+ return;
+ }
+
+ // check the memory trash tester
+ if ( *(int *)((byte *)block + block->size - 4 ) != ZONEID ) {
+ Com_Error( ERR_FATAL, "Z_Free: memory block wrote past end" );
+ }
+
+ if (block->tag == TAG_SMALL) {
+ zone = smallzone;
+ }
+ else {
+ zone = mainzone;
+ }
+
+ zone->used -= block->size;
+ // set the block to something that should cause problems
+ // if it is referenced...
+ ::memset( ptr, 0xaa, block->size - sizeof( *block ) );
+
+ block->tag = 0; // mark as free
+
+ other = block->prev;
+ if (!other->tag) {
+ // merge with previous free block
+ other->size += block->size;
+ other->next = block->next;
+ other->next->prev = other;
+ if (block == zone->rover) {
+ zone->rover = other;
+ }
+ block = other;
+ }
+
+ zone->rover = block;
+
+ other = block->next;
+ if ( !other->tag ) {
+ // merge the next free block onto the end
+ block->size += other->size;
+ block->next = other->next;
+ block->next->prev = block;
+ }
+}
+
+
+/*
+================
+Z_FreeTags
+================
+*/
+void Z_FreeTags( int tag )
+{
+ memzone_t *zone;
+
+ if ( tag == TAG_SMALL )
+ {
+ zone = smallzone;
+ }
+ else
+ {
+ zone = mainzone;
+ }
+ // use the rover as our pointer, because
+ // Z_Free automatically adjusts it
+ zone->rover = zone->blocklist.next;
+ do {
+ if ( zone->rover->tag == tag ) {
+ Z_Free( (void *)(zone->rover + 1) );
+ continue;
+ }
+ zone->rover = zone->rover->next;
+ } while ( zone->rover != &zone->blocklist );
+}
+
+
+/*
+================
+Z_TagMalloc
+================
+*/
+#ifdef ZONE_DEBUG
+void *Z_TagMallocDebug( int size, int tag, const char *label, const char *file, int line )
+#else
+void *Z_TagMalloc( int size, int tag )
+#endif
+{
+ int extra;
+ memblock_t *start, *rover, *_new, *base;
+ memzone_t *zone;
+
+ if (!tag)
+ Com_Error( ERR_FATAL, "Z_TagMalloc: tried to use a 0 tag" );
+
+ if ( tag == TAG_SMALL )
+ zone = smallzone;
+ else
+ zone = mainzone;
+
+#ifdef ZONE_DEBUG
+ int allocSize = size;
+#endif
+ //
+ // scan through the block list looking for the first free block
+ // of sufficient size
+ //
+ size += sizeof(memblock_t); // account for size of block header
+ size += 4; // space for memory trash tester
+ size = PAD(size, sizeof(intptr_t)); // align to 32/64 bit boundary
+
+ base = rover = zone->rover;
+ start = base->prev;
+
+ do {
+ if (rover == start)
+ {
+ // scaned all the way around the list
+#ifdef ZONE_DEBUG
+ Z_LogHeap();
+
+ Com_Error(ERR_FATAL, "Z_Malloc: failed on allocation of %i bytes from the %s zone: %s, line: %d (%s)",
+ size, zone == smallzone ? "small" : "main", file, line, label);
+#else
+ Com_Error(ERR_FATAL, "Z_Malloc: failed on allocation of %i bytes from the %s zone",
+ size, zone == smallzone ? "small" : "main");
+#endif
+ return NULL;
+ }
+ if (rover->tag) {
+ base = rover = rover->next;
+ } else {
+ rover = rover->next;
+ }
+ } while (base->tag || base->size < size);
+
+ //
+ // found a block big enough
+ //
+ extra = base->size - size;
+ if (extra > MINFRAGMENT) {
+ // there will be a free fragment after the allocated block
+ _new = (memblock_t *) ((byte *)base + size );
+ _new->size = extra;
+ _new->tag = 0; // free block
+ _new->prev = base;
+ _new->id = ZONEID;
+ _new->next = base->next;
+ _new->next->prev = _new;
+ base->next = _new;
+ base->size = size;
+ }
+
+ base->tag = tag; // n_o longer a free block
+
+ zone->rover = base->next; // next allocation will start looking here
+ zone->used += base->size;
+
+ base->id = ZONEID;
+
+#ifdef ZONE_DEBUG
+ base->d.label = label;
+ base->d.file = file;
+ base->d.line = line;
+ base->d.allocSize = allocSize;
+#endif
+
+ // marker for memory trash testing
+ *(int *)((byte *)base + base->size - 4) = ZONEID;
+
+ return (void *) ((byte *)base + sizeof(memblock_t));
+}
+
+/*
+========================
+Z_Malloc
+========================
+*/
+#ifdef ZONE_DEBUG
+void *Z_MallocDebug( int size, const char *label, const char *file, int line )
+#else
+void *Z_Malloc( int size )
+#endif
+{
+ void *buf;
+
+ //Z_CheckHeap(); // XXX DEBUG
+
+#ifdef ZONE_DEBUG
+ buf = Z_TagMallocDebug( size, TAG_GENERAL, label, file, line );
+#else
+ buf = Z_TagMalloc( size, TAG_GENERAL );
+#endif
+ ::memset( buf, 0, size );
+
+ return buf;
+}
+
+#ifdef ZONE_DEBUG
+void *S_MallocDebug( int size, const char *label, const char *file, int line )
+{
+ return Z_TagMallocDebug( size, TAG_SMALL, label, file, line );
+}
+#else
+void *S_Malloc( int size )
+{
+ return Z_TagMalloc( size, TAG_SMALL );
+}
+#endif
+
+/*
+========================
+Z_CheckHeap
+========================
+*/
+void Z_CheckHeap( void )
+{
+ memblock_t *block;
+
+ for (block = mainzone->blocklist.next ; ; block = block->next)
+ {
+ if (block->next == &mainzone->blocklist)
+ break; // all blocks have been hit
+
+ if ( (byte *)block + block->size != (byte *)block->next)
+ Com_Error( ERR_FATAL, "Z_CheckHeap: block size does not touch the next block" );
+
+ if ( block->next->prev != block)
+ Com_Error( ERR_FATAL, "Z_CheckHeap: next block doesn't have proper back link" );
+
+ if ( !block->tag && !block->next->tag )
+ Com_Error( ERR_FATAL, "Z_CheckHeap: two consecutive free blocks" );
+ }
+}
+
+/*
+========================
+Z_LogZoneHeap
+========================
+*/
+void Z_LogZoneHeap( memzone_t *zone, const char *name )
+{
+#ifdef ZONE_DEBUG
+ char dump[32], *ptr;
+ int i, j;
+#endif
+ memblock_t *block;
+ char buf[4096];
+ int size, allocSize, numBlocks;
+
+ if (!logfile || !FS_Initialized())
+ return;
+
+ size = numBlocks = 0;
+#ifdef ZONE_DEBUG
+ allocSize = 0;
+#endif
+ Com_sprintf(buf, sizeof(buf), "\r\n================\r\n%s log\r\n================\r\n", name);
+ FS_Write(buf, strlen(buf), logfile);
+
+ for (block = zone->blocklist.next ; block->next != &zone->blocklist; block = block->next)
+ {
+ if (block->tag)
+ {
+#ifdef ZONE_DEBUG
+ ptr = ((char *) block) + sizeof(memblock_t);
+ j = 0;
+ for (i = 0; i < 20 && i < block->d.allocSize; i++)
+ {
+ if (ptr[i] >= 32 && ptr[i] < 127) {
+ dump[j++] = ptr[i];
+ }
+ else {
+ dump[j++] = '_';
+ }
+ }
+ dump[j] = '\0';
+ Com_sprintf(buf, sizeof(buf), "size = %8d: %s, line: %d (%s) [%s]\r\n", block->d.allocSize, block->d.file, block->d.line, block->d.label, dump);
+ FS_Write(buf, strlen(buf), logfile);
+ allocSize += block->d.allocSize;
+#endif
+ size += block->size;
+ numBlocks++;
+ }
+ }
+#ifdef ZONE_DEBUG
+ // subtract debug memory
+ size -= numBlocks * sizeof(zonedebug_t);
+#else
+ allocSize = numBlocks * sizeof(memblock_t); // + 32 bit alignment
+#endif
+ Com_sprintf(buf, sizeof(buf), "%d %s memory in %d blocks\r\n", size, name, numBlocks);
+ FS_Write(buf, strlen(buf), logfile);
+ Com_sprintf(buf, sizeof(buf), "%d %s memory overhead\r\n", size - allocSize, name);
+ FS_Write(buf, strlen(buf), logfile);
+}
+
+/*
+========================
+Z_LogHeap
+========================
+*/
+void Z_LogHeap( void )
+{
+ Z_LogZoneHeap( mainzone, "MAIN" );
+ Z_LogZoneHeap( smallzone, "SMALL" );
+}
+
+// static mem blocks to reduce a lot of small zone overhead
+typedef struct memstatic_s {
+ memblock_t b;
+ byte mem[2];
+} memstatic_t;
+
+memstatic_t emptystring = {
+ {(sizeof(memblock_t)+2 + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'\0', '\0'}
+};
+
+memstatic_t numberstring[] = {
+ { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'0', '\0'} },
+ { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'1', '\0'} },
+ { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'2', '\0'} },
+ { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'3', '\0'} },
+ { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'4', '\0'} },
+ { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'5', '\0'} },
+ { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'6', '\0'} },
+ { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'7', '\0'} },
+ { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'8', '\0'} },
+ { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'9', '\0'} }
+};
+
+/*
+========================
+CopyString
+
+NOTE: never write over the memory CopyString returns because
+memory from a memstatic_t might be returned
+========================
+*/
+char *CopyString( const char *in )
+{
+ char *out;
+
+ if (!in[0]) {
+ return ((char *)&emptystring) + sizeof(memblock_t);
+ }
+ else if (!in[1]) {
+ if (in[0] >= '0' && in[0] <= '9') {
+ return ((char *)&numberstring[in[0]-'0']) + sizeof(memblock_t);
+ }
+ }
+ out = (char*)S_Malloc(strlen(in)+1);
+ strcpy (out, in);
+ return out;
+}
+
+/*
+==============================================================================
+
+Goals:
+ reproducable without history effects -- no out of memory errors on weird map to map changes
+ allow restarting of the client without fragmentation
+ minimize total pages in use at run time
+ minimize total pages needed during load time
+
+ Single block of memory with stack allocators coming from both ends towards the middle.
+
+ One side is designated the temporary memory allocator.
+
+ Temporary memory can be allocated and freed in any order.
+
+ A highwater mark is kept of the most in use at any time.
+
+ When there is no temporary memory allocated, the permanent and temp sides
+ can be switched, allowing the already touched temp memory to be used for
+ permanent storage.
+
+ Temp memory must never be allocated on two ends at once, or fragmentation
+ could occur.
+
+ If we have any in-use temp memory, additional temp allocations must come from
+ that side.
+
+ If not, we can choose to make either side the new temp side and push future
+ permanent allocations to the other side. Permanent allocations should be
+ kept on the side that has the current greatest wasted highwater mark.
+
+==============================================================================
+*/
+
+
+#define HUNK_MAGIC 0x89537892
+#define HUNK_FREE_MAGIC 0x89537893
+
+typedef struct {
+ unsigned int magic;
+ unsigned int size;
+} hunkHeader_t;
+
+typedef struct {
+ int mark;
+ int permanent;
+ int temp;
+ int tempHighwater;
+} hunkUsed_t;
+
+typedef struct hunkblock_s {
+ int size;
+ byte printed;
+ struct hunkblock_s *next;
+ const char *label;
+ const char *file;
+ int line;
+} hunkblock_t;
+
+static hunkblock_t *hunkblocks;
+
+static hunkUsed_t hunk_low, hunk_high;
+static hunkUsed_t *hunk_permanent, *hunk_temp;
+
+static byte* s_hunkData = NULL;
+static int s_hunkTotal;
+
+static int s_zoneTotal;
+static int s_smallZoneTotal;
+
+/*
+=================
+Com_Meminfo_f
+=================
+*/
+void Com_Meminfo_f( void )
+{
+ memblock_t *block;
+ int zoneBytes, zoneBlocks;
+ int smallZoneBytes;
+ int botlibBytes, rendererBytes;
+ int unused;
+
+ zoneBytes = 0;
+ botlibBytes = 0;
+ rendererBytes = 0;
+ zoneBlocks = 0;
+ for (block = mainzone->blocklist.next ; ; block = block->next) {
+ if ( Cmd_Argc() != 1 ) {
+ Com_Printf ("block:%p size:%7i tag:%3i\n",
+ (void *)block, block->size, block->tag);
+ }
+ if ( block->tag ) {
+ zoneBytes += block->size;
+ zoneBlocks++;
+ if ( block->tag == TAG_BOTLIB ) {
+ botlibBytes += block->size;
+ } else if ( block->tag == TAG_RENDERER ) {
+ rendererBytes += block->size;
+ }
+ }
+
+ if (block->next == &mainzone->blocklist) {
+ break; // all blocks have been hit
+ }
+ if ( (byte *)block + block->size != (byte *)block->next) {
+ Com_Printf ("ERROR: block size does not touch the next block\n");
+ }
+ if ( block->next->prev != block) {
+ Com_Printf ("ERROR: next block doesn't have proper back link\n");
+ }
+ if ( !block->tag && !block->next->tag ) {
+ Com_Printf ("ERROR: two consecutive free blocks\n");
+ }
+ }
+
+ smallZoneBytes = 0;
+ for (block = smallzone->blocklist.next ; ; block = block->next)
+ {
+ if ( block->tag )
+ smallZoneBytes += block->size;
+
+ if (block->next == &smallzone->blocklist)
+ break; // all blocks have been hit
+ }
+
+ Com_Printf( "%8i bytes total hunk\n", s_hunkTotal );
+ Com_Printf( "%8i bytes total zone\n", s_zoneTotal );
+ Com_Printf( "\n" );
+ Com_Printf( "%8i low mark\n", hunk_low.mark );
+ Com_Printf( "%8i low permanent\n", hunk_low.permanent );
+ if ( hunk_low.temp != hunk_low.permanent ) {
+ Com_Printf( "%8i low temp\n", hunk_low.temp );
+ }
+ Com_Printf( "%8i low tempHighwater\n", hunk_low.tempHighwater );
+ Com_Printf( "\n" );
+ Com_Printf( "%8i high mark\n", hunk_high.mark );
+ Com_Printf( "%8i high permanent\n", hunk_high.permanent );
+ if ( hunk_high.temp != hunk_high.permanent ) {
+ Com_Printf( "%8i high temp\n", hunk_high.temp );
+ }
+ Com_Printf( "%8i high tempHighwater\n", hunk_high.tempHighwater );
+ Com_Printf( "\n" );
+ Com_Printf( "%8i total hunk in use\n", hunk_low.permanent + hunk_high.permanent );
+ unused = 0;
+ if ( hunk_low.tempHighwater > hunk_low.permanent ) {
+ unused += hunk_low.tempHighwater - hunk_low.permanent;
+ }
+ if ( hunk_high.tempHighwater > hunk_high.permanent ) {
+ unused += hunk_high.tempHighwater - hunk_high.permanent;
+ }
+ Com_Printf( "%8i unused highwater\n", unused );
+ Com_Printf( "\n" );
+ Com_Printf( "%8i bytes in %i zone blocks\n", zoneBytes, zoneBlocks );
+ Com_Printf( " %8i bytes in dynamic botlib\n", botlibBytes );
+ Com_Printf( " %8i bytes in dynamic renderer\n", rendererBytes );
+ Com_Printf( " %8i bytes in dynamic other\n", zoneBytes - ( botlibBytes + rendererBytes ) );
+ Com_Printf( " %8i bytes in small Zone memory\n", smallZoneBytes );
+}
+
+/*
+===============
+Com_TouchMemory
+
+Touch all known used data to make sure it is paged in
+===============
+*/
+void Com_TouchMemory( void )
+{
+ int start, end;
+ int i, j;
+ int sum;
+ memblock_t *block;
+
+ Z_CheckHeap();
+
+ start = Sys_Milliseconds();
+
+ sum = 0;
+
+ j = hunk_low.permanent >> 2;
+ for ( i = 0 ; i < j ; i+=64 ) { // only need to touch each page
+ sum += ((int *)s_hunkData)[i];
+ }
+
+ i = ( s_hunkTotal - hunk_high.permanent ) >> 2;
+ j = hunk_high.permanent >> 2;
+ for ( ; i < j ; i+=64 ) { // only need to touch each page
+ sum += ((int *)s_hunkData)[i];
+ }
+
+ for (block = mainzone->blocklist.next ; ; block = block->next) {
+ if ( block->tag ) {
+ j = block->size >> 2;
+ for ( i = 0 ; i < j ; i+=64 ) { // only need to touch each page
+ sum += ((int *)block)[i];
+ }
+ }
+ if ( block->next == &mainzone->blocklist ) {
+ break; // all blocks have been hit
+ }
+ }
+
+ end = Sys_Milliseconds();
+
+ Com_Printf( "Com_TouchMemory: %i msec\n", end - start );
+}
+
+
+
+/*
+=================
+Com_InitZoneMemory
+=================
+*/
+void Com_InitSmallZoneMemory( void )
+{
+ s_smallZoneTotal = (512 * 1024);
+ smallzone = (memzone_t*)calloc(s_smallZoneTotal, 1);
+ if ( !smallzone )
+ Com_Error(ERR_FATAL, "Small zone data failed to allocate %1.1f megs", (float)s_smallZoneTotal / (1024*1024));
+
+ Z_ClearZone( smallzone, s_smallZoneTotal );
+}
+
+void Com_InitZoneMemory( void )
+{
+ // Please note: com_zoneMegs can only be set on the command line, and not
+ // in q3config.cfg or Com_StartupVariable, as they haven't been executed by
+ // this point. It's a chicken and egg problem. We need the memory manager
+ // configured to handle those places where you would configure the memory
+ // manager.
+
+ // allocate the random block zone
+ cvar_t* cv = Cvar_Get( "com_zoneMegs", DEF_COMZONEMEGS_S, CVAR_LATCH | CVAR_ARCHIVE );
+
+ if ( cv->integer < DEF_COMZONEMEGS ) {
+ s_zoneTotal = 1024 * 1024 * DEF_COMZONEMEGS;
+ } else {
+ s_zoneTotal = cv->integer * 1024 * 1024;
+ }
+
+ mainzone = (memzone_t*)calloc( s_zoneTotal, 1 );
+ if ( !mainzone ) {
+ Com_Error( ERR_FATAL, "Zone data failed to allocate %i megs", s_zoneTotal / (1024*1024) );
+ }
+ Z_ClearZone( mainzone, s_zoneTotal );
+}
+
+/*
+=================
+Hunk_Log
+=================
+*/
+void Hunk_Log( void)
+{
+ char buf[4096];
+
+ if (!logfile || !FS_Initialized())
+ return;
+
+ int size = 0;
+ int numBlocks = 0;
+
+ Com_sprintf(buf, sizeof(buf), "\r\n================\r\nHunk log\r\n================\r\n");
+ FS_Write(buf, strlen(buf), logfile);
+
+ for ( hunkblock_t* block = hunkblocks; block; block = block->next )
+ {
+#ifdef HUNK_DEBUG
+ Com_sprintf(buf, sizeof(buf), "size = %8d: %s, line: %d (%s)\r\n", block->size, block->file, block->line, block->label);
+ FS_Write(buf, strlen(buf), logfile);
+#endif
+ size += block->size;
+ numBlocks++;
+ }
+
+ Com_sprintf(buf, sizeof(buf), "%d Hunk memory\r\n", size);
+ FS_Write(buf, strlen(buf), logfile);
+
+ Com_sprintf(buf, sizeof(buf), "%d hunk blocks\r\n", numBlocks);
+ FS_Write(buf, strlen(buf), logfile);
+}
+
+/*
+=================
+Hunk_SmallLog
+=================
+*/
+void Hunk_SmallLog(void)
+{
+ char buf[4096];
+
+ if (!logfile || !FS_Initialized())
+ return;
+
+ for ( hunkblock_t* block = hunkblocks ; block; block = block->next )
+ block->printed = false;
+
+ int size = 0;
+ int numBlocks = 0;
+
+ Com_sprintf(buf, sizeof(buf), "\r\n================\r\nHunk Small log\r\n================\r\n");
+ FS_Write(buf, strlen(buf), logfile);
+
+ for ( hunkblock_t* block = hunkblocks; block; block = block->next )
+ {
+ if (block->printed)
+ continue;
+
+ int locsize = block->size;
+ for ( hunkblock_t* block2 = block->next; block2; block2 = block2->next )
+ {
+ if (block->line != block2->line)
+ continue;
+
+ if (Q_stricmp(block->file, block2->file))
+ continue;
+
+ size += block2->size;
+ locsize += block2->size;
+ block2->printed = true;
+ }
+#ifdef HUNK_DEBUG
+ Com_sprintf(buf, sizeof(buf), "size = %8d: %s, line: %d (%s)\r\n", locsize, block->file, block->line, block->label);
+ FS_Write(buf, strlen(buf), logfile);
+#endif
+ size += block->size;
+ numBlocks++;
+ }
+ Com_sprintf(buf, sizeof(buf), "%d Hunk memory\r\n", size);
+ FS_Write(buf, strlen(buf), logfile);
+
+ Com_sprintf(buf, sizeof(buf), "%d hunk blocks\r\n", numBlocks);
+ FS_Write(buf, strlen(buf), logfile);
+}
+
+/*
+=================
+Com_InitHunkZoneMemory
+=================
+*/
+void Com_InitHunkMemory( void )
+{
+ cvar_t *cv;
+ int nMinAlloc;
+ const char *pMsg = NULL;
+
+ // make sure the file system has allocated and "not" freed any temp blocks
+ // this allows the config and product id files ( journal files too ) to be loaded
+ // by the file system without redunant routines in the file system utilizing different
+ // memory systems
+ if (FS_LoadStack() != 0)
+ Com_Error( ERR_FATAL, "Hunk initialization failed. File system load stack not zero");
+
+ // allocate the stack based hunk allocator
+ cv = Cvar_Get( "com_hunkMegs", DEF_COMHUNKMEGS_S, CVAR_LATCH | CVAR_ARCHIVE );
+ Cvar_SetDescription(cv, "The size of the hunk memory segment");
+
+ // if we are not dedicated min allocation is 56, otherwise min is 1
+ if (com_dedicated && com_dedicated->integer)
+ {
+ nMinAlloc = MIN_DEDICATED_COMHUNKMEGS;
+ pMsg = "Minimum com_hunkMegs for a dedicated server is %i, allocating %i megs.\n";
+ }
+ else
+ {
+ nMinAlloc = MIN_COMHUNKMEGS;
+ pMsg = "Minimum com_hunkMegs is %i, allocating %i megs.\n";
+ }
+
+ if ( cv->integer < nMinAlloc )
+ {
+ s_hunkTotal = 1024 * 1024 * nMinAlloc;
+ Com_Printf(pMsg, nMinAlloc, s_hunkTotal / (1024 * 1024));
+ }
+ else
+ {
+ s_hunkTotal = cv->integer * 1024 * 1024;
+ }
+
+ s_hunkData = (byte*)calloc( s_hunkTotal + 31, 1 );
+ if ( !s_hunkData )
+ {
+ Com_Error( ERR_FATAL, "Hunk data failed to allocate %i megs", s_hunkTotal / (1024*1024) );
+ }
+ // cacheline align
+ s_hunkData = (byte *) ( ( (intptr_t)s_hunkData + 31 ) & ~31 );
+ Hunk_Clear();
+
+ Cmd_AddCommand( "meminfo", Com_Meminfo_f );
+#ifdef ZONE_DEBUG
+ Cmd_AddCommand( "zonelog", Z_LogHeap );
+#endif
+#ifdef HUNK_DEBUG
+ Cmd_AddCommand( "hunklog", Hunk_Log );
+ Cmd_AddCommand( "hunksmalllog", Hunk_SmallLog );
+#endif
+}
+
+/*
+====================
+Hunk_MemoryRemaining
+====================
+*/
+int Hunk_MemoryRemaining( void )
+{
+ int low = hunk_low.permanent > hunk_low.temp ? hunk_low.permanent : hunk_low.temp;
+ int high = hunk_high.permanent > hunk_high.temp ? hunk_high.permanent : hunk_high.temp;
+ return s_hunkTotal - ( low + high );
+}
+
+/*
+===================
+Hunk_SetMark
+
+The server calls this after the level and game VM have been loaded
+===================
+*/
+void Hunk_SetMark( void )
+{
+ hunk_low.mark = hunk_low.permanent;
+ hunk_high.mark = hunk_high.permanent;
+}
+
+/*
+=================
+Hunk_ClearToMark
+
+The client calls this before starting a vid_restart or snd_restart
+=================
+*/
+void Hunk_ClearToMark( void )
+{
+ hunk_low.permanent = hunk_low.temp = hunk_low.mark;
+ hunk_high.permanent = hunk_high.temp = hunk_high.mark;
+}
+
+/*
+=================
+Hunk_CheckMark
+=================
+*/
+bool Hunk_CheckMark( void )
+{
+ if( hunk_low.mark || hunk_high.mark )
+ return true;
+ return false;
+}
+
+void CL_ShutdownCGame( void );
+void CL_ShutdownUI( void );
+void SV_ShutdownGameProgs( void );
+
+/*
+=================
+Hunk_Clear
+
+The server calls this before shutting down or loading a new map
+=================
+*/
+void Hunk_Clear( void )
+{
+#ifndef DEDICATED
+ CL_ShutdownCGame();
+ CL_ShutdownUI();
+#endif
+ SV_ShutdownGameProgs();
+#ifndef DEDICATED
+ CIN_CloseAllVideos();
+#endif
+ hunk_low.mark = 0;
+ hunk_low.permanent = 0;
+ hunk_low.temp = 0;
+ hunk_low.tempHighwater = 0;
+
+ hunk_high.mark = 0;
+ hunk_high.permanent = 0;
+ hunk_high.temp = 0;
+ hunk_high.tempHighwater = 0;
+
+ hunk_permanent = &hunk_low;
+ hunk_temp = &hunk_high;
+
+ Com_Printf( "Hunk_Clear: reset the hunk ok\n" );
+ VM_Clear();
+#ifdef HUNK_DEBUG
+ hunkblocks = NULL;
+#endif
+}
+
+static void Hunk_SwapBanks( void )
+{
+ hunkUsed_t *swap;
+
+ // can't swap banks if there is any temp already allocated
+ if ( hunk_temp->temp != hunk_temp->permanent )
+ return;
+
+ // if we have a larger highwater mark on this side, start making
+ // our permanent allocations here and use the other side for temp
+ if ( hunk_temp->tempHighwater - hunk_temp->permanent
+ > hunk_permanent->tempHighwater - hunk_permanent->permanent )
+ {
+ swap = hunk_temp;
+ hunk_temp = hunk_permanent;
+ hunk_permanent = swap;
+ }
+}
+
+/*
+=================
+Hunk_Alloc
+
+Allocate permanent (until the hunk is cleared) memory
+=================
+*/
+#ifdef HUNK_DEBUG
+void *Hunk_AllocDebug( int size, ha_pref preference, const char *label, const char *file, int line )
+#else
+void *Hunk_Alloc( int size, ha_pref preference )
+#endif
+{
+ void* buf;
+
+ if ( s_hunkData == NULL)
+ {
+ Com_Error( ERR_FATAL, "Hunk_Alloc: Hunk memory system not initialized" );
+ }
+
+ // can't do preference if there is any temp allocated
+ if (preference == h_dontcare || hunk_temp->temp != hunk_temp->permanent) {
+ Hunk_SwapBanks();
+ } else {
+ if (preference == h_low && hunk_permanent != &hunk_low) {
+ Hunk_SwapBanks();
+ } else if (preference == h_high && hunk_permanent != &hunk_high) {
+ Hunk_SwapBanks();
+ }
+ }
+
+#ifdef HUNK_DEBUG
+ size += sizeof(hunkblock_t);
+#endif
+
+ // round to cacheline
+ size = (size+31)&~31;
+
+ if ( hunk_low.temp + hunk_high.temp + size > s_hunkTotal ) {
+#ifdef HUNK_DEBUG
+ Hunk_Log();
+ Hunk_SmallLog();
+
+ Com_Error(ERR_DROP, "Hunk_Alloc failed on %i: %s, line: %d (%s)", size, file, line, label);
+#else
+ Com_Error(ERR_DROP, "Hunk_Alloc failed on %i", size);
+#endif
+ }
+
+ if ( hunk_permanent == &hunk_low ) {
+ buf = (void *)(s_hunkData + hunk_permanent->permanent);
+ hunk_permanent->permanent += size;
+ } else {
+ hunk_permanent->permanent += size;
+ buf = (void *)(s_hunkData + s_hunkTotal - hunk_permanent->permanent );
+ }
+
+ hunk_permanent->temp = hunk_permanent->permanent;
+
+ ::memset( buf, 0, size );
+
+#ifdef HUNK_DEBUG
+ {
+ hunkblock_t *block;
+
+ block = (hunkblock_t *) buf;
+ block->size = size - sizeof(hunkblock_t);
+ block->file = file;
+ block->label = label;
+ block->line = line;
+ block->next = hunkblocks;
+ hunkblocks = block;
+ buf = ((byte *) buf) + sizeof(hunkblock_t);
+ }
+#endif
+ return buf;
+}
+
+/*
+=================
+Hunk_AllocateTempMemory
+
+This is used by the file loading system.
+Multiple files can be loaded in temporary memory.
+When the files-in-use count reaches zero, all temp memory will be deleted
+=================
+*/
+void *Hunk_AllocateTempMemory( int size )
+{
+ void* buf;
+ hunkHeader_t* hdr;
+
+ // return a Z_Malloc'd block if the hunk has not been initialized
+ // this allows the config and product id files ( journal files too ) to be loaded
+ // by the file system without redunant routines in the file system utilizing different
+ // memory systems
+ if ( s_hunkData == NULL )
+ return Z_Malloc(size);
+
+ Hunk_SwapBanks();
+
+ size = PAD(size, sizeof(intptr_t)) + sizeof( hunkHeader_t );
+
+ if ( hunk_temp->temp + hunk_permanent->permanent + size > s_hunkTotal )
+ Com_Error( ERR_DROP, "Hunk_AllocateTempMemory: failed on %i", size );
+
+ if ( hunk_temp == &hunk_low )
+ {
+ buf = (void *)(s_hunkData + hunk_temp->temp);
+ hunk_temp->temp += size;
+ }
+ else
+ {
+ hunk_temp->temp += size;
+ buf = (void *)(s_hunkData + s_hunkTotal - hunk_temp->temp );
+ }
+
+ if ( hunk_temp->temp > hunk_temp->tempHighwater )
+ hunk_temp->tempHighwater = hunk_temp->temp;
+
+ hdr = (hunkHeader_t *)buf;
+ buf = (void *)(hdr+1);
+
+ hdr->magic = HUNK_MAGIC;
+ hdr->size = size;
+
+ // don't bother clearing, because we are going to load a file over it
+ return buf;
+}
+
+/*
+==================
+Hunk_FreeTempMemory
+==================
+*/
+void Hunk_FreeTempMemory( void *buf )
+{
+ // free with Z_Free if the hunk has not been initialized
+ // this allows the config and product id files ( journal files too ) to be
+ // loaded by the file system without redunant routines in the file system
+ // utilizing different memory systems
+ if ( s_hunkData == NULL )
+ {
+ Z_Free(buf);
+ return;
+ }
+
+ hunkHeader_t* hdr = ( (hunkHeader_t *)buf ) - 1;
+ if ( hdr->magic != HUNK_MAGIC )
+ Com_Error(ERR_FATAL, "Hunk_FreeTempMemory: bad magic");
+
+ hdr->magic = HUNK_FREE_MAGIC;
+
+ // this only works if the files are freed in stack order,
+ // otherwise the memory will stay around until Hunk_ClearTempMemory
+ if ( hunk_temp == &hunk_low )
+ {
+ if ( hdr == (void *)(s_hunkData + hunk_temp->temp - hdr->size ) )
+ hunk_temp->temp -= hdr->size;
+ else
+ Com_Printf( "Hunk_FreeTempMemory: not the final block\n" );
+ }
+ else
+ {
+ if ( hdr == (void *)(s_hunkData + s_hunkTotal - hunk_temp->temp ) )
+ hunk_temp->temp -= hdr->size;
+ else
+ Com_Printf( "Hunk_FreeTempMemory: not the final block\n" );
+ }
+}
+
+/*
+=================
+Hunk_ClearTempMemory
+
+The temp space is no longer needed. If we have left more
+touched but unused memory on this side, have future
+permanent allocs use this side.
+=================
+*/
+void Hunk_ClearTempMemory( void )
+{
+ if ( s_hunkData != NULL )
+ hunk_temp->temp = hunk_temp->permanent;
+}
+
+/*
+===================================================================
+
+EVENTS AND JOURNALING
+
+In addition to these events, .cfg files are also copied to the
+journaled file
+===================================================================
+*/
+
+#define MAX_PUSHED_EVENTS 1024
+static int com_pushedEventsHead = 0;
+static int com_pushedEventsTail = 0;
+static sysEvent_t com_pushedEvents[MAX_PUSHED_EVENTS];
+
+/*
+=================
+Com_InitJournaling
+=================
+*/
+void Com_InitJournaling( void )
+{
+ Com_StartupVariable( "journal" );
+ com_journal = Cvar_Get ("journal", "0", CVAR_INIT);
+ if ( !com_journal->integer ) {
+ return;
+ }
+
+ if ( com_journal->integer == 1 ) {
+ Com_Printf( "Journaling events\n");
+ com_journalFile = FS_FOpenFileWrite( "journal.dat" );
+ com_journalDataFile = FS_FOpenFileWrite( "journaldata.dat" );
+ } else if ( com_journal->integer == 2 ) {
+ Com_Printf( "Replaying journaled events\n");
+ FS_FOpenFileRead( "journal.dat", &com_journalFile, true );
+ FS_FOpenFileRead( "journaldata.dat", &com_journalDataFile, true );
+ }
+
+ if ( !com_journalFile || !com_journalDataFile ) {
+ Cvar_Set( "com_journal", "0" );
+ com_journalFile = 0;
+ com_journalDataFile = 0;
+ Com_Printf( "Couldn't open journal files\n" );
+ }
+}
+
+/*
+========================================================================
+
+EVENT LOOP
+
+========================================================================
+*/
+
+#define MAX_QUEUED_EVENTS 256
+#define MASK_QUEUED_EVENTS ( MAX_QUEUED_EVENTS - 1 )
+
+static sysEvent_t eventQueue[ MAX_QUEUED_EVENTS ];
+static int eventHead = 0;
+static int eventTail = 0;
+
+/*
+================
+Com_QueueEvent
+
+A time of 0 will get the current time
+Ptr should either be null, or point to a block of data that can
+be freed by the game later.
+================
+*/
+void Com_QueueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr )
+{
+ sysEvent_t *ev;
+
+ // combine mouse movement with previous mouse event
+ if ( type == SE_MOUSE && eventHead != eventTail )
+ {
+ ev = &eventQueue[ ( eventHead + MAX_QUEUED_EVENTS - 1 ) & MASK_QUEUED_EVENTS ];
+
+ if ( ev->evType == SE_MOUSE )
+ {
+ ev->evValue += value;
+ ev->evValue2 += value2;
+ return;
+ }
+ }
+
+ ev = &eventQueue[ eventHead & MASK_QUEUED_EVENTS ];
+
+ if ( eventHead - eventTail >= MAX_QUEUED_EVENTS )
+ {
+ Com_Printf("Com_QueueEvent: overflow\n");
+ // we are discarding an event, but don't leak memory
+ if ( ev->evPtr )
+ {
+ Z_Free( ev->evPtr );
+ }
+ eventTail++;
+ }
+
+ eventHead++;
+
+ if ( time == 0 )
+ {
+ time = Sys_Milliseconds();
+ }
+
+ ev->evTime = time;
+ ev->evType = type;
+ ev->evValue = value;
+ ev->evValue2 = value2;
+ ev->evPtrLength = ptrLength;
+ ev->evPtr = ptr;
+}
+
+/*
+================
+Com_GetSystemEvent
+
+================
+*/
+sysEvent_t Com_GetSystemEvent( void )
+{
+ sysEvent_t ev;
+ char *s;
+
+ // return if we have data
+ if ( eventHead > eventTail )
+ {
+ eventTail++;
+ return eventQueue[ ( eventTail - 1 ) & MASK_QUEUED_EVENTS ];
+ }
+
+ // check for console commands
+ s = Sys_ConsoleInput();
+ if ( s )
+ {
+ char *b;
+ int len;
+
+ len = strlen( s ) + 1;
+ b = (char*)Z_Malloc( len );
+ strcpy( b, s );
+ Com_QueueEvent( 0, SE_CONSOLE, 0, 0, len, b );
+ }
+
+ // return if we have data
+ if ( eventHead > eventTail )
+ {
+ eventTail++;
+ return eventQueue[ ( eventTail - 1 ) & MASK_QUEUED_EVENTS ];
+ }
+
+ // create an empty event to return
+ memset( &ev, 0, sizeof( ev ) );
+ ev.evTime = Sys_Milliseconds();
+
+ return ev;
+}
+
+/*
+=================
+Com_GetRealEvent
+=================
+*/
+sysEvent_t Com_GetRealEvent( void )
+{
+ sysEvent_t ev;
+
+ // either get an event from the system or the journal file
+ if ( com_journal->integer == 2 )
+ {
+ int r = FS_Read( &ev, sizeof(ev), com_journalFile );
+ if ( r != sizeof(ev) )
+ Com_Error( ERR_FATAL, "Error reading from journal file" );
+
+ if ( ev.evPtrLength )
+ {
+ ev.evPtr = Z_Malloc( ev.evPtrLength );
+ r = FS_Read( ev.evPtr, ev.evPtrLength, com_journalFile );
+ if ( r != ev.evPtrLength ) {
+ Com_Error( ERR_FATAL, "Error reading from journal file" );
+ }
+ }
+ }
+ else
+ {
+ ev = Com_GetSystemEvent();
+
+ // write the journal value out if needed
+ if ( com_journal->integer == 1 )
+ {
+ int r = FS_Write( &ev, sizeof(ev), com_journalFile );
+ if ( r != sizeof(ev) )
+ Com_Error( ERR_FATAL, "Error writing to journal file" );
+
+ if ( ev.evPtrLength )
+ {
+ r = FS_Write( ev.evPtr, ev.evPtrLength, com_journalFile );
+ if ( r != ev.evPtrLength )
+ Com_Error( ERR_FATAL, "Error writing to journal file" );
+ }
+ }
+ }
+
+ return ev;
+}
+
+
+/*
+=================
+Com_InitPushEvent
+=================
+*/
+void Com_InitPushEvent( void ) {
+ // clear the static buffer array
+ // this requires SE_NONE to be accepted as a valid but NOP event
+ memset( com_pushedEvents, 0, sizeof(com_pushedEvents) );
+ // reset counters while we are at it
+ // beware: GetEvent might still return an SE_NONE from the buffer
+ com_pushedEventsHead = 0;
+ com_pushedEventsTail = 0;
+}
+
+
+/*
+=================
+Com_PushEvent
+=================
+*/
+void Com_PushEvent( sysEvent_t *event )
+{
+ static int printedWarning = 0;
+ sysEvent_t *ev = &com_pushedEvents[ com_pushedEventsHead & (MAX_PUSHED_EVENTS-1) ];
+
+ if ( com_pushedEventsHead - com_pushedEventsTail >= MAX_PUSHED_EVENTS )
+ {
+ // don't print the warning constantly, or it can give time for more...
+ if ( !printedWarning )
+ {
+ printedWarning = true;
+ Com_Printf("WARNING: Com_PushEvent overflow\n");
+ }
+
+ if ( ev->evPtr )
+ Z_Free( ev->evPtr );
+
+ com_pushedEventsTail++;
+ }
+ else
+ {
+ printedWarning = false;
+ }
+
+ *ev = *event;
+ com_pushedEventsHead++;
+}
+
+/*
+=================
+Com_GetEvent
+=================
+*/
+sysEvent_t Com_GetEvent(void)
+{
+ if ( com_pushedEventsHead > com_pushedEventsTail )
+ {
+ com_pushedEventsTail++;
+ return com_pushedEvents[ (com_pushedEventsTail-1) & (MAX_PUSHED_EVENTS-1) ];
+ }
+ return Com_GetRealEvent();
+}
+
+/*
+=================
+Com_RunAndTimeServerPacket
+=================
+*/
+void Com_RunAndTimeServerPacket( netadr_t *evFrom, msg_t *buf )
+{
+ int t1 = 0;
+ if ( com_speeds->integer )
+ t1 = Sys_Milliseconds();
+
+ SV_PacketEvent(*evFrom, buf);
+
+ if ( com_speeds->integer )
+ {
+ int t2 = Sys_Milliseconds();
+ int msec = t2 - t1;
+ if ( com_speeds->integer == 3 )
+ Com_Printf("SV_PacketEvent time: %i\n", msec);
+ }
+}
+
+/*
+=================
+Com_EventLoop
+
+Returns last event time
+=================
+*/
+int Com_EventLoop(void)
+{
+ sysEvent_t ev;
+ netadr_t evFrom;
+ byte bufData[MAX_MSGLEN];
+ msg_t buf;
+
+ MSG_Init(&buf, bufData, sizeof(bufData));
+
+ for (;;)
+ {
+ ev = Com_GetEvent();
+
+ // if no more events are available
+ if ( ev.evType == SE_NONE )
+ {
+ // manually send packet events for the loopback channel
+ while ( NET_GetLoopPacket( NS_CLIENT, &evFrom, &buf ) )
+ CL_PacketEvent( evFrom, &buf );
+
+ // if the server just shut down, flush the events
+ while ( NET_GetLoopPacket( NS_SERVER, &evFrom, &buf ) )
+ if ( com_sv_running->integer )
+ Com_RunAndTimeServerPacket( &evFrom, &buf );
+
+ return ev.evTime;
+ }
+
+ switch(ev.evType)
+ {
+ case SE_KEY:
+ CL_KeyEvent( ev.evValue, (bool)ev.evValue2, ev.evTime );
+ break;
+ case SE_CHAR:
+ CL_CharEvent( ev.evValue );
+ break;
+ case SE_MOUSE:
+ CL_MouseEvent( ev.evValue, ev.evValue2, ev.evTime );
+ break;
+ case SE_JOYSTICK_AXIS:
+ CL_JoystickEvent( ev.evValue, ev.evValue2, ev.evTime );
+ break;
+ case SE_CONSOLE:
+ Cbuf_AddText( (char *)ev.evPtr );
+ Cbuf_AddText( "\n" );
+ break;
+ default:
+ Com_Error( ERR_FATAL, "Com_EventLoop: bad event type %i", ev.evType );
+ break;
+ }
+
+ // free any block data
+ if ( ev.evPtr )
+ Z_Free( ev.evPtr );
+ }
+
+ return 0; // never reached
+}
+
+/*
+================
+Com_Milliseconds
+
+Can be used for profiling, but will be journaled accurately
+================
+*/
+int Com_Milliseconds(void)
+{
+ sysEvent_t ev;
+ // get events and push them until we get a null event with the current time
+ do {
+ ev = Com_GetRealEvent();
+
+ if ( ev.evType != SE_NONE )
+ Com_PushEvent( &ev );
+
+ } while ( ev.evType != SE_NONE );
+
+ return ev.evTime;
+}
+
+//============================================================================
+
+/*
+=============
+Com_Error_f
+
+Just throw a fatal error to
+test error shutdown procedures
+=============
+*/
+static void __attribute__((__noreturn__)) Com_Error_f (void)
+{
+ if ( Cmd_Argc() > 1 )
+ Com_Error( ERR_DROP, "Testing drop error" );
+ else
+ Com_Error( ERR_FATAL, "Testing fatal error" );
+}
+
+/*
+=============
+Com_Freeze_f
+
+Just freeze in place for a given number of seconds to test
+error recovery
+=============
+*/
+static void Com_Freeze_f (void)
+{
+ float s;
+ int start, now;
+
+ if ( Cmd_Argc() != 2 )
+ {
+ Com_Printf( "freeze <seconds>\n" );
+ return;
+ }
+
+ s = atof(Cmd_Argv(1));
+ start = Com_Milliseconds();
+
+ for (;;)
+ {
+ now = Com_Milliseconds();
+ if ( (now - start) * 0.001 > s )
+ break;
+ }
+}
+
+/*
+=================
+Com_Crash_f
+
+A way to force a bus error for development reasons
+=================
+*/
+static void Com_Crash_f( void )
+{
+ *( volatile int * )0 = 0x12345678;
+}
+
+/*
+==================
+Com_ExecuteCfg
+
+For controlling environment variables
+==================
+*/
+
+void Com_ExecuteCfg(void)
+{
+ Cbuf_ExecuteText(EXEC_NOW, "exec default.cfg\n");
+ Cbuf_Execute(); // Always execute after exec to prevent text buffer overflowing
+
+ if(!Com_SafeMode())
+ {
+ // skip the q3config.cfg and autoexec.cfg if "safe" is on the command line
+ Cbuf_ExecuteText(EXEC_NOW, "exec " Q3CONFIG_CFG "\n");
+ Cbuf_Execute();
+ Cbuf_ExecuteText(EXEC_NOW, "exec autoexec.cfg\n");
+ Cbuf_Execute();
+ }
+}
+
+/*
+==================
+Com_GameRestart
+
+Change to a new mod properly with cleaning up cvars before switching.
+==================
+*/
+
+void Com_GameRestart(int checksumFeed, bool disconnect)
+{
+ // make sure no recursion can be triggered
+ if(!com_gameRestarting && com_fullyInitialized)
+ {
+ int clWasRunning;
+
+ com_gameRestarting = true;
+ clWasRunning = com_cl_running->integer;
+
+ // Kill server if we have one
+ if(com_sv_running->integer)
+ SV_Shutdown("Game directory changed");
+
+ if(clWasRunning)
+ {
+ if(disconnect)
+ CL_Disconnect(false);
+
+ CL_Shutdown("Game directory changed", disconnect, false);
+ }
+
+ FS_Restart(checksumFeed);
+
+ // Clean out any user and VM created cvars
+ Cvar_Restart(true);
+ Com_ExecuteCfg();
+
+ if(disconnect)
+ {
+ // We don't want to change any network settings if gamedir
+ // change was triggered by a connect to server because the
+ // new network settings might make the connection fail.
+ NET_Restart_f();
+ }
+
+ if(clWasRunning)
+ {
+ CL_Init();
+ CL_StartHunkUsers(false);
+ }
+
+ com_gameRestarting = false;
+ }
+}
+
+/*
+==================
+Com_GameRestart_f
+
+Expose possibility to change current running mod to the user
+==================
+*/
+
+void Com_GameRestart_f(void)
+{
+ if(!FS_FilenameCompare(Cmd_Argv(1), BASEGAME))
+ {
+ // This is the standard base game. Servers and clients should
+ // use "" and not the standard basegame name because this messes
+ // up pak file negotiation and lots of other stuff
+
+ Cvar_Set("fs_game", "");
+ }
+ else
+ Cvar_Set("fs_game", Cmd_Argv(1));
+
+ Com_GameRestart(0, true);
+}
+
+static void Com_DetectAltivec(void)
+{
+ // Only detect if user hasn't forcibly disabled it.
+ if ( com_altivec->integer )
+ {
+ static bool altivec = false;
+ static bool detected = false;
+
+ if (!detected)
+ {
+ altivec = ( Sys_GetProcessorFeatures( ) & CF_ALTIVEC ) == CF_ALTIVEC;
+ detected = true;
+ }
+
+ if (!altivec)
+ Cvar_Set( "com_altivec", "0" ); // we don't have it! Disable support!
+ }
+}
+
+/*
+=================
+Com_DetectSSE
+Find out whether we have SSE support
+=================
+*/
+
+#if id386 || idx64
+static void Com_DetectSSE(void)
+{
+#if !idx64
+ cpuFeatures_t feat = Sys_GetProcessorFeatures();
+ if(feat & CF_SSE)
+ {
+ if(feat & CF_SSE2)
+ Q_SnapVector = qsnapvectorsse;
+ else
+ Q_SnapVector = qsnapvectorx87;
+#endif
+ Com_Printf("Have SSE support\n");
+#if !idx64
+ }
+ else
+ {
+ Q_SnapVector = qsnapvectorx87;
+
+ Com_Printf("No SSE support on this machine\n");
+ }
+#endif
+}
+
+#else
+
+#define Com_DetectSSE()
+
+#endif
+
+/*
+=================
+Com_InitRand
+Seed the random number generator, if possible with an OS supplied random seed.
+=================
+*/
+static void Com_InitRand(void)
+{
+ unsigned int seed;
+
+ if(Sys_RandomBytes((byte *) &seed, sizeof(seed)))
+ srand(seed);
+ else
+ srand(time(NULL));
+}
+
+/*
+=================
+Com_Init
+=================
+*/
+void Com_Init( char *commandLine )
+{
+ int qport;
+
+ if ( setjmp (abortframe) ) {
+ Sys_Error ("Error during initialization");
+ }
+
+ // Clear queues
+ ::memset( &eventQueue[ 0 ], 0, MAX_QUEUED_EVENTS * sizeof( sysEvent_t ) );
+
+ // initialize the weak pseudo-random number generator for use later.
+ Com_InitRand();
+
+ // do this before anything else decides to push events
+ Com_InitPushEvent();
+
+ Com_InitSmallZoneMemory();
+ Cvar_Init();
+
+ // prepare enough of the subsystems to handle
+ // cvar and command buffer management
+ Com_ParseCommandLine( commandLine );
+
+ //Swap_Init ();
+ Cbuf_Init ();
+
+ Com_DetectSSE();
+
+ // override anything from the config files with command line args
+ Com_StartupVariable( NULL );
+
+ Com_InitZoneMemory();
+ Cmd_Init ();
+
+ // get the developer cvar set as early as possible
+ com_developer = Cvar_Get("developer", "0", CVAR_TEMP);
+
+ // done early so bind command exists
+ CL_InitKeyCommands();
+
+ com_homepath = Cvar_Get("com_homepath", "", CVAR_INIT);
+
+ FS_InitFilesystem ();
+
+ Com_InitJournaling();
+
+ // Add some commands here already so users can use them from config files
+ if (com_developer && com_developer->integer)
+ {
+ Cmd_AddCommand ("error", Com_Error_f);
+ Cmd_AddCommand ("crash", Com_Crash_f);
+ Cmd_AddCommand ("freeze", Com_Freeze_f);
+ }
+ Cmd_AddCommand ("quit", Com_Quit_f);
+ Cmd_AddCommand ("changeVectors", MSG_ReportChangeVectors_f );
+ Cmd_AddCommand ("writeconfig", Com_WriteConfig_f );
+ Cmd_SetCommandCompletionFunc( "writeconfig", Cmd_CompleteCfgName );
+ Cmd_AddCommand("game_restart", Com_GameRestart_f);
+
+ Com_ExecuteCfg();
+
+ // override anything from the config files with command line args
+ Com_StartupVariable( NULL );
+
+ // get dedicated here for proper hunk megs initialization
+#ifdef DEDICATED
+ com_dedicated = Cvar_Get ("dedicated", "1", CVAR_INIT);
+ Cvar_CheckRange( com_dedicated, 1, 2, true );
+#else
+ com_dedicated = Cvar_Get ("dedicated", "0", CVAR_LATCH);
+ Cvar_CheckRange( com_dedicated, 0, 2, true );
+#endif
+ // allocate the stack based hunk allocator
+ Com_InitHunkMemory();
+
+ // if any archived cvars are modified after this, we will trigger a writing
+ // of the config file
+ cvar_modifiedFlags &= ~CVAR_ARCHIVE;
+
+ //
+ // init commands and vars
+ //
+ com_altivec = Cvar_Get ("com_altivec", "1", CVAR_ARCHIVE);
+ com_maxfps = Cvar_Get ("com_maxfps", "85", CVAR_ARCHIVE);
+
+ com_logfile = Cvar_Get ("logfile", "0", CVAR_TEMP );
+
+ com_timescale = Cvar_Get ("timescale", "1", CVAR_CHEAT | CVAR_SYSTEMINFO );
+ com_fixedtime = Cvar_Get ("fixedtime", "0", CVAR_CHEAT);
+ com_showtrace = Cvar_Get ("com_showtrace", "0", CVAR_CHEAT);
+ com_speeds = Cvar_Get ("com_speeds", "0", 0);
+ com_timedemo = Cvar_Get ("timedemo", "0", CVAR_CHEAT);
+ com_cameraMode = Cvar_Get ("com_cameraMode", "0", CVAR_CHEAT);
+
+ cl_paused = Cvar_Get ("cl_paused", "0", CVAR_ROM);
+ sv_paused = Cvar_Get ("sv_paused", "0", CVAR_ROM);
+ cl_packetdelay = Cvar_Get ("cl_packetdelay", "0", CVAR_CHEAT);
+ sv_packetdelay = Cvar_Get ("sv_packetdelay", "0", CVAR_CHEAT);
+ com_sv_running = Cvar_Get ("sv_running", "0", CVAR_ROM);
+ com_cl_running = Cvar_Get ("cl_running", "0", CVAR_ROM);
+ com_buildScript = Cvar_Get( "com_buildScript", "0", 0 );
+ com_ansiColor = Cvar_Get( "com_ansiColor", "0", CVAR_ARCHIVE );
+
+ com_unfocused = Cvar_Get( "com_unfocused", "0", CVAR_ROM );
+ com_maxfpsUnfocused = Cvar_Get( "com_maxfpsUnfocused", "0", CVAR_ARCHIVE );
+ com_minimized = Cvar_Get( "com_minimized", "0", CVAR_ROM );
+ com_maxfpsMinimized = Cvar_Get( "com_maxfpsMinimized", "0", CVAR_ARCHIVE );
+ com_busyWait = Cvar_Get("com_busyWait", "0", CVAR_ARCHIVE);
+ Cvar_Get("com_errorMessage", "", CVAR_ROM | CVAR_NORESTART);
+ Cvar_Get("com_demoErrorMessage", "", CVAR_ROM | CVAR_NORESTART);
+
+ com_version = Cvar_Get ("version", PRODUCT_NAME, CVAR_ROM | CVAR_SERVERINFO );
+ Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_ROM);
+ com_gamename = Cvar_Get("com_gamename", GAMENAME_FOR_MASTER, CVAR_SERVERINFO | CVAR_INIT);
+
+ Sys_Init();
+
+ // Pick a random port value
+ Com_RandomBytes( (byte*)&qport, sizeof(int) );
+ Netchan_Init( qport & 0xffff );
+
+ VM_Init();
+ Crypto_Init();
+ SV_Init();
+
+ com_dedicated->modified = false;
+#ifndef DEDICATED
+ CL_Init();
+#endif
+
+ // set com_frameTime so that if a map is started on the
+ // command line it will still be able to count on com_frameTime
+ // being random enough for a serverid
+ com_frameTime = Com_Milliseconds();
+
+ // add + commands from command line
+ if ( !Com_AddStartupCommands() ) {
+#ifdef CINEMATICS_LOGO
+ // if the user didn't give any commands, run default action
+ if ( !com_dedicated->integer ) {
+ Cbuf_AddText ("cinematic splash.RoQ\n");
+ }
+#endif
+ }
+
+ // start in full screen ui mode
+ Cvar_Set("r_uiFullScreen", "1");
+
+ CL_StartHunkUsers( false );
+
+ com_fullyInitialized = true;
+
+ // always set the cvar, but only print the info if it makes sense.
+ Com_DetectAltivec();
+#if idppc
+ Com_Printf ("Altivec support is %s\n", com_altivec->integer ? "enabled" : "disabled");
+#endif
+
+ com_pipefile = Cvar_Get( "com_pipefile", "", CVAR_ARCHIVE|CVAR_LATCH );
+ if( com_pipefile->string[0] )
+ {
+ pipefile = FS_FCreateOpenPipeFile( com_pipefile->string );
+ }
+
+ Com_Printf ("--- Common Initialization Complete ---\n");
+}
+
+/*
+===============
+Com_ReadFromPipe
+
+Read whatever is in com_pipefile, if anything, and execute it
+===============
+*/
+void Com_ReadFromPipe( void )
+{
+ static char buf[MAX_STRING_CHARS];
+ static int accu = 0;
+ int read;
+
+ if( !pipefile )
+ return;
+
+ while( ( read = FS_Read( buf + accu, sizeof( buf ) - accu - 1, pipefile ) ) > 0 )
+ {
+ char *brk = NULL;
+
+ for( int i = accu; i < accu + read; ++i )
+ {
+ if( buf[ i ] == '\0' )
+ buf[ i ] = '\n';
+ if( buf[ i ] == '\n' || buf[ i ] == '\r' )
+ brk = &buf[ i + 1 ];
+ }
+ buf[ accu + read ] = '\0';
+
+ accu += read;
+
+ if( brk )
+ {
+ char tmp = *brk;
+ *brk = '\0';
+ Cbuf_ExecuteText( EXEC_APPEND, buf );
+ *brk = tmp;
+
+ accu -= brk - buf;
+ memmove( buf, brk, accu + 1 );
+ }
+ else if( accu >= sizeof( buf ) - 1 ) // full
+ {
+ Cbuf_ExecuteText( EXEC_APPEND, buf );
+ accu = 0;
+ }
+ }
+}
+
+
+//==================================================================
+
+void Com_WriteConfigToFile( const char *filename )
+{
+ fileHandle_t f;
+
+ f = FS_FOpenFileWrite( filename );
+ if ( !f )
+ {
+ Com_Printf("Couldn't write %s.\n", filename );
+ return;
+ }
+
+ FS_Printf(f, "// generated by tremulous, do not modify\n");
+
+ Key_WriteBindings(f);
+ Cvar_WriteVariables(f);
+ FS_FCloseFile(f);
+}
+
+
+/*
+===============
+Com_WriteConfiguration
+
+Writes key bindings and archived cvars to config file if modified
+===============
+*/
+void Com_WriteConfiguration( void )
+{
+ // if we are quiting without fully initializing, make sure
+ // we don't write out anything
+ if ( !com_fullyInitialized )
+ return;
+
+ if ( !(cvar_modifiedFlags & CVAR_ARCHIVE) )
+ return;
+
+ cvar_modifiedFlags &= ~CVAR_ARCHIVE;
+
+ Com_WriteConfigToFile(Q3CONFIG_CFG);
+}
+
+/*
+===============
+Com_WriteConfig_f
+
+Write the config file to a specific name
+===============
+*/
+void Com_WriteConfig_f( void )
+{
+ char filename[MAX_QPATH];
+
+ if ( Cmd_Argc() != 2 ) {
+ Com_Printf( "Usage: writeconfig <filename>\n" );
+ return;
+ }
+
+ Q_strncpyz( filename, Cmd_Argv(1), sizeof( filename ) );
+ COM_DefaultExtension( filename, sizeof( filename ), ".cfg" );
+
+ if ( !COM_CompareExtension(filename, ".cfg") )
+ {
+ Com_Printf("Com_WriteConfig_f: Only the \".cfg\" extension is supported by this command!\n");
+ return;
+ }
+
+ Com_Printf( "Writing %s.\n", filename );
+ Com_WriteConfigToFile( filename );
+}
+
+/*
+================
+Com_ModifyMsec
+================
+*/
+int Com_ModifyMsec( int msec )
+{
+ int clampTime;
+
+ //
+ // modify time for debugging values
+ //
+ if ( com_fixedtime->integer )
+ msec = com_fixedtime->integer;
+ else if ( com_timescale->value )
+ msec *= com_timescale->value;
+ else if (com_cameraMode->integer)
+ msec *= com_timescale->value;
+
+ // don't let it scale below 1 msec
+ if ( msec < 1 && com_timescale->value)
+ msec = 1;
+
+ if ( com_dedicated->integer )
+ {
+ // dedicated servers don't want to clamp for a much longer
+ // period, because it would mess up all the client's views
+ // of time.
+ if (com_sv_running->integer && msec > 500)
+ Com_Printf("Hitch warning: %i msec frame time\n", msec);
+
+ clampTime = 5000;
+ }
+ else
+ {
+ if ( !com_sv_running->integer )
+ {
+ // clients of remote servers do not want to clamp time, because
+ // it would skew their view of the server's time temporarily
+ clampTime = 5000;
+ }
+ else
+ {
+ // for local single player gaming
+ // we may want to clamp the time to prevent players from
+ // flying off edges when something hitches.
+ clampTime = 200;
+ }
+ }
+
+ if ( msec > clampTime )
+ msec = clampTime;
+
+ return msec;
+}
+
+/*
+=================
+Com_TimeVal
+=================
+*/
+
+int Com_TimeVal(int minMsec)
+{
+ int timeVal = Sys_Milliseconds() - com_frameTime;
+
+ if(timeVal >= minMsec)
+ timeVal = 0;
+ else
+ timeVal = minMsec - timeVal;
+
+ return timeVal;
+}
+
+/*
+=================
+Com_Frame
+=================
+*/
+void Com_Frame( void )
+{
+
+ int msec, minMsec;
+ int timeVal, timeValSV;
+ static int lastTime = 0, bias = 0;
+
+ int timeBeforeFirstEvents;
+ int timeBeforeServer;
+ int timeBeforeEvents;
+ int timeBeforeClient;
+ int timeAfter;
+
+ if ( setjmp(abortframe) )
+ return; // an ERR_DROP was thrown
+
+ timeBeforeFirstEvents =0;
+ timeBeforeServer =0;
+ timeBeforeEvents =0;
+ timeBeforeClient = 0;
+ timeAfter = 0;
+
+ // write config file if anything changed
+ Com_WriteConfiguration();
+
+ //
+ // main event loop
+ //
+ if ( com_speeds->integer )
+ timeBeforeFirstEvents = Sys_Milliseconds();
+
+ // Figure out how much time we have
+ if ( !com_timedemo->integer )
+ {
+ if(com_dedicated->integer)
+ {
+ minMsec = SV_FrameMsec();
+ }
+ else
+ {
+ if(com_minimized->integer && com_maxfpsMinimized->integer > 0)
+ minMsec = 1000 / com_maxfpsMinimized->integer;
+ else if(com_unfocused->integer && com_maxfpsUnfocused->integer > 0)
+ minMsec = 1000 / com_maxfpsUnfocused->integer;
+ else if(com_maxfps->integer > 0)
+ minMsec = 1000 / com_maxfps->integer;
+ else
+ minMsec = 1;
+
+ timeVal = com_frameTime - lastTime;
+ bias += timeVal - minMsec;
+
+ if(bias > minMsec)
+ bias = minMsec;
+
+ // Adjust minMsec if previous frame took too long to render so
+ // that framerate is stable at the requested value.
+ minMsec -= bias;
+ }
+ }
+ else
+ {
+ minMsec = 1;
+ }
+
+ do {
+ if ( com_sv_running->integer )
+ {
+ timeValSV = SV_SendQueuedPackets();
+ timeVal = Com_TimeVal(minMsec);
+
+ if ( timeValSV < timeVal )
+ timeVal = timeValSV;
+ }
+ else
+ {
+ timeVal = Com_TimeVal(minMsec);
+ }
+
+ if ( com_busyWait->integer || timeVal < 1 )
+ NET_Sleep(0);
+ else
+ NET_Sleep(timeVal - 1);
+ } while( Com_TimeVal(minMsec) );
+
+ IN_Frame();
+
+ lastTime = com_frameTime;
+ com_frameTime = Com_EventLoop();
+
+ msec = com_frameTime - lastTime;
+
+ Cbuf_Execute();
+
+ if ( com_altivec->modified )
+ {
+ Com_DetectAltivec();
+ com_altivec->modified = false;
+ }
+
+ // mess with msec if needed
+ msec = Com_ModifyMsec(msec);
+
+ //
+ // server side
+ //
+ if ( com_speeds->integer )
+ timeBeforeServer = Sys_Milliseconds();
+
+ SV_Frame(msec);
+
+ // if "dedicated" has been modified, start up
+ // or shut down the client system.
+ // Do this after the server may have started,
+ // but before the client tries to auto-connect
+ if ( com_dedicated->modified )
+ {
+ // get the latched value
+ Cvar_Get("dedicated", "0", 0);
+ com_dedicated->modified = false;
+
+ if ( !com_dedicated->integer )
+ {
+ SV_Shutdown("dedicated set to 0");
+ CL_FlushMemory();
+ }
+ }
+
+#ifndef DEDICATED
+ //
+ // client system
+ //
+ //
+ // run event loop a second time to get server to client packets
+ // without a frame of latency
+ //
+ if ( com_speeds->integer )
+ timeBeforeEvents = Sys_Milliseconds();
+
+ Com_EventLoop();
+ Cbuf_Execute();
+
+ //
+ // client side
+ //
+ if ( com_speeds->integer )
+ timeBeforeClient = Sys_Milliseconds();
+
+ CL_Frame(msec);
+
+ if ( com_speeds->integer )
+ timeAfter = Sys_Milliseconds();
+#else
+ if ( com_speeds->integer )
+ {
+ timeAfter = Sys_Milliseconds();
+ timeBeforeEvents = timeAfter;
+ timeBeforeClient = timeAfter;
+ }
+#endif
+
+ NET_FlushPacketQueue();
+
+ //
+ // report timing information
+ //
+ if ( com_speeds->integer )
+ {
+ int all = timeAfter - timeBeforeServer;
+ int sv = timeBeforeEvents - timeBeforeServer;
+ int ev = timeBeforeServer - timeBeforeFirstEvents + timeBeforeClient - timeBeforeEvents;
+ int cl = timeAfter - timeBeforeClient;
+
+ sv -= time_game;
+ cl -= time_frontend + time_backend;
+
+ Com_Printf("frame:%i all:%3i sv:%3i ev:%3i cl:%3i gm:%3i rf:%3i bk:%3i\n",
+ com_frameNumber, all, sv, ev, cl, time_game, time_frontend, time_backend );
+ }
+
+ //
+ // trace optimization tracking
+ //
+ if ( com_showtrace->integer )
+ {
+ extern int c_traces, c_brush_traces, c_patch_traces;
+ extern int c_pointcontents;
+
+ Com_Printf("%4i traces (%ib %ip) %4i points\n",
+ c_traces, c_brush_traces, c_patch_traces, c_pointcontents);
+
+ c_traces = 0;
+ c_brush_traces = 0;
+ c_patch_traces = 0;
+ c_pointcontents = 0;
+ }
+
+ Com_ReadFromPipe();
+
+ com_frameNumber++;
+}
+
+/*
+=================
+Com_Shutdown
+=================
+*/
+void Com_Shutdown(void)
+{
+ if (logfile)
+ {
+ FS_FCloseFile (logfile);
+ logfile = 0;
+ }
+
+ if ( com_journalFile )
+ {
+ FS_FCloseFile( com_journalFile );
+ com_journalFile = 0;
+ }
+
+ if( pipefile )
+ {
+ FS_FCloseFile( pipefile );
+ FS_HomeRemove( com_pipefile->string );
+ }
+}
+
+/*
+===========================================
+command line completion
+===========================================
+*/
+
+/*
+==================
+Field_Clear
+==================
+*/
+void Field_Clear( field_t *edit )
+{
+ memset(edit->buffer, 0, MAX_EDIT_LINE);
+ edit->cursor = 0;
+ edit->scroll = 0;
+}
+
+static const char *completionString;
+static char shortestMatch[MAX_TOKEN_CHARS];
+static int matchCount;
+// field we are working on, passed to Field_AutoComplete(&g_consoleCommand for instance)
+static field_t *completionField;
+
+/*
+===============
+FindMatches
+
+===============
+*/
+static void FindMatches( const char *s )
+{
+ if ( Q_stricmpn(s, completionString, strlen(completionString)) )
+ return;
+
+ matchCount++;
+ if ( matchCount == 1 )
+ {
+ Q_strncpyz( shortestMatch, s, sizeof( shortestMatch ) );
+ return;
+ }
+
+ // cut shortestMatch to the amount common with s
+ for ( int i = 0 ; shortestMatch[i] ; i++ )
+ {
+ if ( i >= strlen(s) )
+ {
+ shortestMatch[i] = 0;
+ break;
+ }
+
+ if ( tolower(shortestMatch[i]) != tolower(s[i]) )
+ shortestMatch[i] = 0;
+ }
+}
+
+/*
+===============
+PrintMatches
+
+===============
+*/
+static void PrintMatches( const char *s )
+{
+ if ( !Q_stricmpn(s, shortestMatch, strlen(shortestMatch)) )
+ Com_Printf(" %s\n", s);
+}
+
+/*
+===============
+PrintCvarMatches
+
+===============
+*/
+static void PrintCvarMatches( const char *s )
+{
+ char value[ TRUNCATE_LENGTH ];
+ if ( !Q_stricmpn(s, shortestMatch, strlen( shortestMatch)) )
+ {
+ Com_TruncateLongString( value, Cvar_VariableString( s ) );
+ Com_Printf( " %s = \"%s\"\n", s, value );
+ }
+}
+
+/*
+===============
+Field_FindFirstSeparator
+===============
+*/
+static char *Field_FindFirstSeparator( char *s )
+{
+ for( int i = 0; i < strlen( s ); i++ )
+ if( s[ i ] == ';' )
+ return &s[ i ];
+
+ return NULL;
+}
+
+/*
+===============
+Field_Complete
+===============
+*/
+static bool Field_Complete( void )
+{
+ if( matchCount == 0 )
+ return true;
+
+ int completionOffset = strlen( completionField->buffer ) - strlen( completionString );
+
+ Q_strncpyz( &completionField->buffer[ completionOffset ], shortestMatch,
+ sizeof( completionField->buffer ) - completionOffset );
+
+ completionField->cursor = strlen( completionField->buffer );
+
+ if( matchCount == 1 )
+ {
+ Q_strcat( completionField->buffer, sizeof( completionField->buffer ), " " );
+ completionField->cursor++;
+ return true;
+ }
+
+ Com_Printf( "]%s\n", completionField->buffer );
+
+ return false;
+}
+
+#ifndef DEDICATED
+/*
+===============
+Field_CompleteKeyname
+===============
+*/
+void Field_CompleteKeyname( void )
+{
+ matchCount = 0;
+ shortestMatch[ 0 ] = 0;
+
+ Key_KeynameCompletion( FindMatches );
+
+ if( !Field_Complete( ) )
+ Key_KeynameCompletion( PrintMatches );
+}
+#endif
+
+/*
+===============
+Field_CompleteFilename
+===============
+*/
+void Field_CompleteFilename( const char *dir, const char *ext,
+ bool stripExt, bool allowNonPureFilesOnDisk )
+{
+ matchCount = 0;
+ shortestMatch[ 0 ] = 0;
+
+ FS_FilenameCompletion( dir, ext, stripExt, FindMatches, allowNonPureFilesOnDisk );
+
+ if( !Field_Complete( ) )
+ FS_FilenameCompletion( dir, ext, stripExt, PrintMatches, allowNonPureFilesOnDisk );
+}
+
+/*
+============
+Field_ListCompletion
+============
+*/
+void Field_ListCompletion( char *listJson, void(*callback)(const char *s) )
+{
+ char item[ 256 ];
+ const char *arrayPtr;
+ const char *listEnd = listJson + strlen( listJson );
+
+ // JSON parse array
+ for ( arrayPtr = JSON_ArrayGetFirstValue( listJson, listEnd );
+ arrayPtr ;
+ arrayPtr = JSON_ArrayGetNextValue( arrayPtr, listEnd ) )
+ {
+ JSON_ValueGetString( arrayPtr, listEnd, item, 256 );
+ callback( item );
+ }
+}
+
+/*
+===============
+Field_CompleteList
+
+Completes an arbirary list of JSON encoded items passed from a VM
+===============
+*/
+void Field_CompleteList( char *listJson )
+{
+ matchCount = 0;
+ shortestMatch[ 0 ] = 0;
+
+ Field_ListCompletion( listJson, FindMatches );
+
+ if( !Field_Complete() )
+ Field_ListCompletion( listJson, PrintMatches );
+}
+
+/*
+===============
+Field_CompleteCommand
+===============
+*/
+void Field_CompleteCommand( char *cmd, bool doCommands, bool doCvars )
+{
+ // Skip leading whitespace and quotes
+ cmd = Com_SkipCharset( cmd, " \"" );
+
+ Cmd_TokenizeStringIgnoreQuotes( cmd );
+ int completionArgument = Cmd_Argc( );
+
+ // If there is trailing whitespace on the cmd
+ if( *( cmd + strlen( cmd ) - 1 ) == ' ' )
+ {
+ completionString = "";
+ completionArgument++;
+ }
+ else
+ completionString = Cmd_Argv( completionArgument - 1 );
+
+ if ( completionString == nullptr )
+ return;
+
+#ifndef DEDICATED
+ // Unconditionally add a '\' to the start of the buffer
+ if( completionField->buffer[ 0 ] &&
+ completionField->buffer[ 0 ] != '\\' )
+ {
+ if( completionField->buffer[ 0 ] != '/' )
+ {
+ // Buffer is full, refuse to complete
+ if( strlen( completionField->buffer ) + 1 >=
+ sizeof( completionField->buffer ) )
+ return;
+
+ memmove( &completionField->buffer[ 1 ],
+ &completionField->buffer[ 0 ],
+ strlen( completionField->buffer ) + 1 );
+ completionField->cursor++;
+ }
+
+ completionField->buffer[ 0 ] = '\\';
+ }
+#endif
+
+ if( completionArgument > 1 )
+ {
+ const char *baseCmd = Cmd_Argv( 0 );
+ char *p;
+
+#ifndef DEDICATED
+ // This should always be true
+ if( baseCmd[ 0 ] == '\\' || baseCmd[ 0 ] == '/' )
+ baseCmd++;
+#endif
+
+ if( ( p = Field_FindFirstSeparator( cmd ) ) )
+ Field_CompleteCommand( p + 1, true, true ); // Compound command
+ else
+ Cmd_CompleteArgument( baseCmd, cmd, completionArgument );
+ }
+ else
+ {
+ if( completionString[0] == '\\' || completionString[0] == '/' )
+ completionString++;
+
+ matchCount = 0;
+ shortestMatch[ 0 ] = 0;
+
+ if( strlen( completionString ) == 0 )
+ return;
+
+ if( doCommands )
+ Cmd_CommandCompletion( FindMatches );
+
+ if( doCvars )
+ Cvar_CommandCompletion( FindMatches );
+
+ if( !Field_Complete( ) )
+ {
+ // run through again, printing matches
+ if( doCommands )
+ Cmd_CommandCompletion( PrintMatches );
+
+ if( doCvars )
+ Cvar_CommandCompletion( PrintCvarMatches );
+ }
+ }
+}
+
+/*
+===============
+Field_AutoComplete
+
+Perform Tab expansion
+===============
+*/
+void Field_AutoComplete( field_t *field )
+{
+ completionField = field;
+ Field_CompleteCommand( completionField->buffer, true, true );
+}
+
+/*
+==================
+Com_RandomBytes
+
+fills string array with len random bytes, preferably from the OS randomizer
+==================
+*/
+void Com_RandomBytes( byte *string, int len )
+{
+ if( Sys_RandomBytes( string, len ) )
+ return;
+
+ Com_Printf( "Com_RandomBytes: using weak randomization\n" );
+ for( int i = 0; i < len; i++ )
+ string[i] = (unsigned char)( rand() % 256 );
+}
+
+
+/*
+==================
+Com_IsVoipTarget
+
+Returns non-zero if given clientNum is enabled in voipTargets, zero otherwise.
+If clientNum is negative return if any bit is set.
+==================
+*/
+bool Com_IsVoipTarget(uint8_t *voipTargets, int voipTargetsSize, int clientNum)
+{
+ int i = 0;
+
+ if ( clientNum < 0 )
+ {
+ for ( i = 0; i < voipTargetsSize; i++ )
+ {
+ if(voipTargets[i])
+ return true;
+ }
+
+ return false;
+ }
+
+ i = clientNum >> 3;
+
+ if( i < voipTargetsSize )
+ return (bool)(voipTargets[i] & (1 << (clientNum & 0x07)));
+
+ return false;
+}
+
+/*
+===============
+Field_CompletePlayerName
+===============
+*/
+static bool Field_CompletePlayerNameFinal( bool whitespace )
+{
+ if( matchCount == 0 )
+ return true;
+
+ int completionOffset = strlen( completionField->buffer ) - strlen( completionString );
+
+ Q_strncpyz( &completionField->buffer[ completionOffset ], shortestMatch,
+ sizeof( completionField->buffer ) - completionOffset );
+
+ completionField->cursor = strlen( completionField->buffer );
+
+ if( matchCount == 1 && whitespace )
+ {
+ Q_strcat( completionField->buffer, sizeof( completionField->buffer ), " " );
+ completionField->cursor++;
+ return true;
+ }
+
+ return false;
+}
+
+static void Name_PlayerNameCompletion( const char **names, int nameCount, void(*callback)(const char *s) )
+{
+ for( int i = 0; i < nameCount; i++ )
+ callback( names[ i ] );
+}
+
+bool Com_FieldStringToPlayerName( char *name, int length, const char *rawname )
+{
+ char hex[5];
+
+ if( name == NULL || rawname == NULL )
+ return false;
+
+ if( length <= 0 )
+ return true;
+
+ int i;
+ for( i = 0; *rawname && i + 1 <= length; rawname++, i++ )
+ {
+ if( *rawname == '\\' )
+ {
+ Q_strncpyz( hex, rawname + 1, sizeof(hex) );
+ int ch = Com_HexStrToInt( hex );
+ if( ch > -1 )
+ {
+ name[i] = ch;
+ rawname += 4; //hex string length, 0xXX
+ }
+ else
+ {
+ name[i] = *rawname;
+ }
+ } else {
+ name[i] = *rawname;
+ }
+ }
+ name[i] = '\0';
+
+ return true;
+}
+
+bool Com_PlayerNameToFieldString( char *str, int length, const char *name )
+{
+ const char *p;
+ int i;
+ int x1, x2;
+
+ if( str == NULL || name == NULL )
+ return false;
+
+ if( length <= 0 )
+ return true;
+
+ *str = '\0';
+ p = name;
+
+ for( i = 0; *p != '\0'; i++, p++ )
+ {
+ if( i + 1 >= length )
+ break;
+
+ if( *p <= ' ' )
+ {
+ if( i + 5 + 1 >= length )
+ break;
+
+ x1 = *p >> 4;
+ x2 = *p & 15;
+
+ str[i+0] = '\\';
+ str[i+1] = '0';
+ str[i+2] = 'x';
+ str[i+3] = x1 > 9 ? x1 - 10 + 'a' : x1 + '0';
+ str[i+4] = x2 > 9 ? x2 - 10 + 'a' : x2 + '0';
+
+ i += 4;
+ } else {
+ str[i] = *p;
+ }
+ }
+ str[i] = '\0';
+
+ return true;
+}
+
+void Field_CompletePlayerName( const char **names, int nameCount )
+{
+
+ matchCount = 0;
+ shortestMatch[ 0 ] = 0;
+
+ if( nameCount <= 0 )
+ return;
+
+ Name_PlayerNameCompletion( names, nameCount, FindMatches );
+
+ if( completionString[0] == '\0' )
+ Com_PlayerNameToFieldString( shortestMatch, sizeof( shortestMatch ), names[ 0 ] );
+
+ //allow to tab player names
+ //if full player name switch to next player name
+ if( completionString[0] != '\0'
+ && Q_stricmp( shortestMatch, completionString ) == 0
+ && nameCount > 1 )
+ {
+ for( int i = 0; i < nameCount; i++ )
+ {
+ if( Q_stricmp( names[ i ], completionString ) == 0 )
+ {
+ i++;
+
+ if( i >= nameCount )
+ i = 0;
+
+ Com_PlayerNameToFieldString( shortestMatch, sizeof( shortestMatch ), names[ i ] );
+ break;
+ }
+ }
+ }
+
+ if( matchCount > 1 )
+ {
+ Com_Printf( "]%s\n", completionField->buffer );
+
+ Name_PlayerNameCompletion( names, nameCount, PrintMatches );
+ }
+
+ bool whitespace = nameCount == 1 ? true : false;
+ Field_CompletePlayerNameFinal(whitespace);
+}
+
+int QDECL Com_strCompare( const void *a, const void *b )
+{
+ const char **pa = (const char **)a;
+ const char **pb = (const char **)b;
+ return strcmp( *pa, *pb );
+}
diff --git a/src/qcommon/crypto.cpp b/src/qcommon/crypto.cpp
new file mode 100644
index 0000000..dd71371
--- /dev/null
+++ b/src/qcommon/crypto.cpp
@@ -0,0 +1,92 @@
+/*
+===========================================================================
+Copyright (C) 2007-2008 Amanieu d'Antras (amanieu@gmail.com)
+Copyright (C) 2015-2016 Jeff Kent (jeff@jkent.net)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "crypto.h"
+
+#include "sys/sys_shared.h"
+
+#include "cvar.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+#define TO_REAL_PTR(x) ((uint8_t*)x - sizeof(size_t))
+#define TO_MOCK_PTR(x) ((uint8_t*)x + sizeof(size_t))
+#define REAL_PTR_SIZE(x) (*((size_t *)x))
+#define MOCK_PTR_SIZE(x) (REAL_PTR_SIZE(TO_REAL_PTR(x)))
+
+
+static void *crypto_alloc( size_t size )
+{
+ void *p;
+
+ assert( size > 0 );
+
+ p = malloc( sizeof(size_t) + size );
+ if ( !p )
+ Com_Error( ERR_FATAL, "crypto_alloc: Virtual memory exhausted." );
+
+ REAL_PTR_SIZE( p ) = size;
+ return TO_MOCK_PTR( p );
+}
+
+static void *crypto_realloc( void *old, size_t old_size, size_t new_size )
+{
+ void *p;
+
+ old_size = MOCK_PTR_SIZE( old );
+ if ( new_size == old_size ) {
+ return old;
+ }
+
+ p = malloc( sizeof(size_t) + new_size );
+ if ( !p )
+ Com_Error( ERR_FATAL, "crypto_realloc: Virtual memory exhausted." );
+ REAL_PTR_SIZE( p ) = new_size;
+
+ p = TO_MOCK_PTR( p );
+ memcpy( p, old, MIN( old_size, new_size ) );
+ old = TO_REAL_PTR( old );
+ memset( old, 0, sizeof(size_t) + old_size );
+ free( old );
+
+ return p;
+}
+
+static void crypto_free( void *p, size_t size )
+{
+ p = TO_REAL_PTR( p );
+ size = REAL_PTR_SIZE( p );
+ memset( p, 0, sizeof(size_t) + size );
+ free( p );
+}
+
+void Crypto_Init( void )
+{
+ mp_set_memory_functions( crypto_alloc, crypto_realloc, crypto_free );
+}
+
+void qnettle_random( void *ctx, size_t length, uint8_t *dst )
+{
+ Sys_CryptoRandomBytes( dst, length );
+}
diff --git a/src/qcommon/crypto.h b/src/qcommon/crypto.h
new file mode 100644
index 0000000..9b21943
--- /dev/null
+++ b/src/qcommon/crypto.h
@@ -0,0 +1,45 @@
+/*
+===========================================================================
+Copyright (C) 2007-2008 Amanieu d'Antras (amanieu@gmail.com)
+Copyright (C) 2015-2016 Jeff Kent (jeff@jkent.net)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifndef __CRYPTO_H__
+#define __CRYPTO_H__
+
+#include "nettle/bignum.h"
+#include "nettle/buffer.h"
+#include "nettle/rsa.h"
+#include "nettle/sha2.h"
+
+
+#define RSA_PRIVATE_KEY_FILE "rsa_private_key"
+#define RSA_PUBLIC_KEY_FILE "rsa_public_key"
+
+#define RSA_PUBLIC_EXPONENT 65537
+
+#define RSA_KEY_LENGTH 4096
+#define RSA_STRING_LENGTH (RSA_KEY_LENGTH / 4 + 1)
+
+void Crypto_Init( void );
+void qnettle_random( void *ctx, size_t length, uint8_t *dst );
+
+#endif /* __CRYPTO_H__ */
diff --git a/src/qcommon/cvar.cpp b/src/qcommon/cvar.cpp
new file mode 100644
index 0000000..560138a
--- /dev/null
+++ b/src/qcommon/cvar.cpp
@@ -0,0 +1,1498 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// cvar.c -- dynamic variable tracking
+
+#include "cvar.h"
+
+#include "cmd.h"
+#include "files.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+static cvar_t *cvar_vars = nullptr;
+cvar_t *cvar_cheats;
+int cvar_modifiedFlags = 0;
+
+#define MAX_CVARS 2048
+static cvar_t cvar_indexes[MAX_CVARS];
+static int cvar_numIndexes;
+
+#define FILE_HASH_SIZE 256
+static cvar_t *hashTable[FILE_HASH_SIZE];
+
+/*
+================
+return a hash value for the filename
+================
+*/
+static long generateHashValue(const char *fname)
+{
+ long hash = 0;
+ int i = 0;
+ while (fname[i] != '\0')
+ {
+ char letter = tolower(fname[i]);
+ hash += (long)(letter) * (i + 119);
+ i++;
+ }
+ hash &= (FILE_HASH_SIZE - 1);
+ return hash;
+}
+
+/*
+============
+Cvar_ValidateString
+============
+*/
+bool Cvar_ValidateString(const char *s)
+{
+ if (!s)
+ {
+ return false;
+ }
+ if (strchr(s, '\\'))
+ {
+ return false;
+ }
+ if (strchr(s, '\"'))
+ {
+ return false;
+ }
+ if (strchr(s, ';'))
+ {
+ return false;
+ }
+ return true;
+}
+
+/*
+============
+Cvar_FindVar
+============
+*/
+cvar_t *Cvar_FindVar(const char *var_name)
+{
+ long hash = generateHashValue(var_name);
+
+ for (cvar_t *var = hashTable[hash]; var; var = var->hashNext)
+ if (!Q_stricmp(var_name, var->name))
+ return var;
+
+ return nullptr;
+}
+
+/*
+============
+Cvar_VariableValue
+============
+*/
+float Cvar_VariableValue(const char *var_name)
+{
+ cvar_t *var = Cvar_FindVar(var_name);
+ if (!var)
+ return 0;
+ return var->value;
+}
+
+/*
+============
+Cvar_VariableIntegerValue
+============
+*/
+int Cvar_VariableIntegerValue(const char *var_name)
+{
+ cvar_t *var = Cvar_FindVar(var_name);
+ if (!var)
+ return 0;
+ return var->integer;
+}
+
+/*
+============
+Cvar_VariableString
+============
+*/
+const char *Cvar_VariableString(const char *var_name)
+{
+ cvar_t *var = Cvar_FindVar(var_name);
+ if (!var)
+ return "";
+ return var->string;
+}
+
+/*
+============
+Cvar_VariableStringBuffer
+============
+*/
+void Cvar_VariableStringBuffer(const char *var_name, char *buffer, int bufsize)
+{
+ cvar_t *var = Cvar_FindVar(var_name);
+ if (var)
+ Q_strncpyz(buffer, var->string, bufsize);
+ else
+ *buffer = 0;
+}
+
+/*
+============
+Cvar_Flags
+============
+*/
+unsigned int Cvar_Flags(const char *var_name)
+{
+ cvar_t *var;
+
+ if (!(var = Cvar_FindVar(var_name)))
+ return CVAR_NONEXISTENT;
+ else if (var->modified)
+ return var->flags | CVAR_MODIFIED;
+
+ return var->flags;
+}
+
+/*
+============
+Cvar_CommandCompletion
+============
+*/
+void Cvar_CommandCompletion(void (*callback)(const char *s))
+{
+ for (cvar_t *cvar = cvar_vars; cvar; cvar = cvar->next)
+ {
+ if (cvar->name)
+ callback(cvar->name);
+ }
+}
+
+/*
+============
+Cvar_Validate
+============
+*/
+const char *Cvar_Validate(cvar_t *var, const char *value, bool warn)
+{
+ static char s[MAX_CVAR_VALUE_STRING];
+ float valuef;
+ bool changed = false;
+
+ if (!var->validate)
+ return value;
+
+ if (!value)
+ return nullptr;
+
+ if (Q_isanumber(value))
+ {
+ valuef = atof(value);
+
+ if (var->integral)
+ {
+ if (!Q_isintegral(valuef))
+ {
+ if (warn)
+ Com_Printf("WARNING: cvar '%s' must be integral", var->name);
+
+ valuef = (int)valuef;
+ changed = true;
+ }
+ }
+ }
+ else
+ {
+ if (warn)
+ Com_Printf("WARNING: cvar '%s' must be numeric", var->name);
+
+ valuef = atof(var->resetString);
+ changed = true;
+ }
+
+ if (valuef < var->min)
+ {
+ if (warn)
+ {
+ if (changed)
+ Com_Printf(" and is");
+ else
+ Com_Printf("WARNING: cvar '%s'", var->name);
+
+ if (Q_isintegral(var->min))
+ Com_Printf(" out of range (min %d)", (int)var->min);
+ else
+ Com_Printf(" out of range (min %f)", var->min);
+ }
+
+ valuef = var->min;
+ changed = true;
+ }
+ else if (valuef > var->max)
+ {
+ if (warn)
+ {
+ if (changed)
+ Com_Printf(" and is");
+ else
+ Com_Printf("WARNING: cvar '%s'", var->name);
+
+ if (Q_isintegral(var->max))
+ Com_Printf(" out of range (max %d)", (int)var->max);
+ else
+ Com_Printf(" out of range (max %f)", var->max);
+ }
+
+ valuef = var->max;
+ changed = true;
+ }
+
+ if (changed)
+ {
+ if (Q_isintegral(valuef))
+ {
+ Com_sprintf(s, sizeof(s), "%d", (int)valuef);
+
+ if (warn)
+ Com_Printf(", setting to %d\n", (int)valuef);
+ }
+ else
+ {
+ Com_sprintf(s, sizeof(s), "%f", valuef);
+
+ if (warn)
+ Com_Printf(", setting to %f\n", valuef);
+ }
+
+ return s;
+ }
+
+ return value;
+}
+
+/*
+============
+Cvar_Get
+
+If the variable already exists, the value will not be set unless CVAR_ROM
+The flags will be or'ed in if the variable exists.
+============
+*/
+cvar_t *Cvar_Get(const char *var_name, const char *var_value, int flags)
+{
+ if (!var_name || !var_value)
+ {
+ Com_Error(ERR_FATAL, "Cvar_Get: nullptr parameter");
+ }
+
+ if (!Cvar_ValidateString(var_name))
+ {
+ Com_Printf("invalid cvar name string: %s\n", var_name);
+ var_name = "BADNAME";
+ }
+
+#if 0 // FIXME: values with backslash happen
+ if ( !Cvar_ValidateString( var_value ) ) {
+ Com_Printf("invalid cvar value string: %s\n", var_value );
+ var_value = "BADVALUE";
+ }
+#endif
+
+ cvar_t *var = Cvar_FindVar(var_name);
+ if (var)
+ {
+ var_value = Cvar_Validate(var, var_value, false);
+
+ // Make sure the game code cannot mark engine-added variables as gamecode vars
+ if (var->flags & CVAR_VM_CREATED)
+ {
+ if (!(flags & CVAR_VM_CREATED))
+ var->flags &= ~CVAR_VM_CREATED;
+ }
+ else if (!(var->flags & CVAR_USER_CREATED))
+ {
+ if (flags & CVAR_VM_CREATED)
+ flags &= ~CVAR_VM_CREATED;
+ }
+
+ // if the C code is now specifying a variable that the user already
+ // set a value for, take the new value as the reset value
+ if (var->flags & CVAR_USER_CREATED)
+ {
+ var->flags &= ~CVAR_USER_CREATED;
+ Z_Free(var->resetString);
+ var->resetString = CopyString(var_value);
+
+ if (flags & CVAR_ROM)
+ {
+ // this variable was set by the user,
+ // so force it to value given by the engine.
+
+ if (var->latchedString)
+ Z_Free(var->latchedString);
+
+ var->latchedString = CopyString(var_value);
+ }
+ }
+
+ // Make sure servers cannot mark engine-added variables as SERVER_CREATED
+ if (var->flags & CVAR_SERVER_CREATED)
+ {
+ if (!(flags & CVAR_SERVER_CREATED))
+ var->flags &= ~CVAR_SERVER_CREATED;
+ }
+ else
+ {
+ if (flags & CVAR_SERVER_CREATED)
+ flags &= ~CVAR_SERVER_CREATED;
+ }
+
+ var->flags |= flags;
+
+ // only allow one non-empty reset string without a warning
+ if (!var->resetString[0])
+ {
+ // we don't have a reset string yet
+ Z_Free(var->resetString);
+ var->resetString = CopyString(var_value);
+ }
+ else if (var_value[0] && strcmp(var->resetString, var_value))
+ {
+ Com_DPrintf("Warning: cvar \"%s\" given initial values: \"%s\" and \"%s\"\n",
+ var_name, var->resetString, var_value);
+ }
+ // if we have a latched string, take that value now
+ if (var->latchedString)
+ {
+ char *s = var->latchedString;
+ var->latchedString = nullptr; // otherwise cvar_set2 would free it
+ Cvar_Set2(var_name, s, true);
+ Z_Free(s);
+ }
+
+ // ZOID--needs to be set so that cvars the game sets as
+ // SERVERINFO get sent to clients
+ cvar_modifiedFlags |= flags;
+ if (flags & CVAR_ALTERNATE_SYSTEMINFO)
+ {
+ cvar_modifiedFlags |= CVAR_SYSTEMINFO;
+ }
+
+ return var;
+ }
+
+ //
+ // allocate a new cvar
+ //
+
+ // find a free cvar
+ int i;
+ for (i = 0; i < MAX_CVARS; i++)
+ if (!cvar_indexes[i].name)
+ break;
+
+ if (i >= MAX_CVARS)
+ {
+ if (!com_errorEntered)
+ Com_Error(ERR_FATAL, "Error: Too many cvars, cannot create a new one!");
+ return nullptr;
+ }
+
+ var = &cvar_indexes[i];
+
+ if (i >= cvar_numIndexes)
+ cvar_numIndexes = i + 1;
+
+ var->name = CopyString(var_name);
+ var->string = CopyString(var_value);
+ var->modified = true;
+ var->modificationCount = 1;
+ var->value = atof(var->string);
+ var->integer = atoi(var->string);
+ var->resetString = CopyString(var_value);
+ var->validate = false;
+ var->description = nullptr;
+
+ // link the variable in
+ var->next = cvar_vars;
+ if (cvar_vars)
+ cvar_vars->prev = var;
+
+ var->prev = nullptr;
+ cvar_vars = var;
+
+ var->flags = flags;
+ // note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
+ cvar_modifiedFlags |= var->flags;
+ if (var->flags & CVAR_ALTERNATE_SYSTEMINFO)
+ cvar_modifiedFlags |= CVAR_SYSTEMINFO;
+
+ long hash = generateHashValue(var_name);
+ var->hashIndex = hash;
+
+ var->hashNext = hashTable[hash];
+ if (hashTable[hash])
+ hashTable[hash]->hashPrev = var;
+
+ var->hashPrev = nullptr;
+ hashTable[hash] = var;
+
+ return var;
+}
+
+/*
+============
+Cvar_Print
+
+Prints the value, default, and latched string of the given variable
+============
+*/
+void Cvar_Print(cvar_t *v)
+{
+ Com_Printf("\"%s\" is:\"%s" S_COLOR_WHITE "\"", v->name, v->string);
+
+ if (!(v->flags & CVAR_ROM))
+ {
+ if (!Q_stricmp(v->string, v->resetString))
+ Com_Printf(", the default");
+ else
+ Com_Printf(" default:\"%s" S_COLOR_WHITE "\"", v->resetString);
+ }
+
+ Com_Printf("\n");
+
+ if (v->latchedString)
+ Com_Printf("latched: \"%s\"\n", v->latchedString);
+
+ if (v->description)
+ Com_Printf("%s\n", v->description);
+}
+
+/*
+============
+Cvar_Set2
+============
+*/
+cvar_t *Cvar_Set2(const char *var_name, const char *value, bool force)
+{
+ if (!Cvar_ValidateString(var_name))
+ {
+ Com_Printf("invalid cvar name string: %s\n", var_name);
+ var_name = "BADNAME";
+ }
+
+#if 0 // FIXME
+ if ( value && !Cvar_ValidateString( value ) ) {
+ Com_Printf("invalid cvar value string: %s\n", value );
+ var_value = "BADVALUE";
+ }
+#endif
+
+ cvar_t *var = Cvar_FindVar(var_name);
+ if (!var)
+ {
+ if (!value)
+ return nullptr;
+
+ if (!force)
+ return Cvar_Get(var_name, value, CVAR_USER_CREATED);
+
+ return Cvar_Get(var_name, value, 0);
+ }
+
+ if (!value)
+ value = var->resetString;
+
+ value = Cvar_Validate(var, value, true);
+
+ if ((var->flags & CVAR_LATCH) && var->latchedString)
+ {
+ if (!strcmp(value, var->string))
+ {
+ Z_Free(var->latchedString);
+ var->latchedString = nullptr;
+ return var;
+ }
+
+ if (!strcmp(value, var->latchedString))
+ return var;
+ }
+ else if (!strcmp(value, var->string))
+ return var;
+
+ // note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
+ cvar_modifiedFlags |= var->flags;
+ if (var->flags & CVAR_ALTERNATE_SYSTEMINFO)
+ {
+ cvar_modifiedFlags |= CVAR_SYSTEMINFO;
+ }
+
+ if (!force)
+ {
+ if (var->flags & CVAR_ROM)
+ {
+ Com_Printf("%s is read only.\n", var_name);
+ return var;
+ }
+
+ if (var->flags & CVAR_INIT)
+ {
+ Com_Printf("%s is write protected.\n", var_name);
+ return var;
+ }
+
+ if (var->flags & CVAR_LATCH)
+ {
+ if (var->latchedString)
+ {
+ if (strcmp(value, var->latchedString) == 0)
+ return var;
+ Z_Free(var->latchedString);
+ var->latchedString = nullptr;
+ }
+ else
+ {
+ if (strcmp(value, var->string) == 0)
+ return var;
+ }
+
+ Com_Printf("%s will be changed upon restarting.\n", var_name);
+ var->latchedString = CopyString(value);
+ var->modified = true;
+ var->modificationCount++;
+ return var;
+ }
+
+ if ((var->flags & CVAR_CHEAT) && !cvar_cheats->integer)
+ {
+ Com_Printf("%s is cheat protected.\n", var_name);
+ return var;
+ }
+ }
+ else
+ {
+ if (var->latchedString)
+ {
+ Z_Free(var->latchedString);
+ var->latchedString = nullptr;
+ }
+ }
+
+ if (!strcmp(value, var->string))
+ return var; // not changed
+
+ var->modified = true;
+ var->modificationCount++;
+
+ Z_Free(var->string); // free the old value string
+
+ var->string = CopyString(value);
+ var->value = atof(var->string);
+ var->integer = atoi(var->string);
+
+ return var;
+}
+
+/*
+============
+Cvar_Set
+============
+*/
+void Cvar_Set(const char *var_name, const char *value)
+{
+ Cvar_Set2(var_name, value, true);
+}
+/*
+============
+Cvar_SetSafe
+============
+*/
+void Cvar_SetSafe(const char *var_name, const char *value)
+{
+ unsigned flags = Cvar_Flags(var_name);
+
+ if ((flags != CVAR_NONEXISTENT) && (flags & CVAR_PROTECTED))
+ {
+ if (value)
+ Com_Error(ERR_DROP, "Restricted source tried to set \"%s\" to \"%s\"",
+ var_name, value);
+ else
+ Com_Error(ERR_DROP, "Restricted source tried to modify \"%s\"",
+ var_name);
+ return;
+ }
+ Cvar_Set(var_name, value);
+}
+
+/*
+============
+Cvar_SetLatched
+============
+*/
+void Cvar_SetLatched(const char *var_name, const char *value)
+{
+ Cvar_Set2(var_name, value, false);
+}
+/*
+============
+Cvar_SetValue
+============
+*/
+void Cvar_SetValue(const char *var_name, float value)
+{
+ char val[32];
+
+ if (value == (int)value)
+ {
+ Com_sprintf(val, sizeof(val), "%i", (int)value);
+ }
+ else
+ {
+ Com_sprintf(val, sizeof(val), "%f", value);
+ }
+ Cvar_Set(var_name, val);
+}
+
+/*
+============
+Cvar_SetValueSafe
+============
+*/
+void Cvar_SetValueSafe(const char *var_name, float value)
+{
+ char val[32];
+
+ if (Q_isintegral(value))
+ Com_sprintf(val, sizeof(val), "%i", (int)value);
+ else
+ Com_sprintf(val, sizeof(val), "%f", value);
+ Cvar_SetSafe(var_name, val);
+}
+
+/*
+============
+Cvar_Reset
+============
+*/
+void Cvar_Reset(const char *var_name)
+{
+ Cvar_Set2(var_name, nullptr, false);
+}
+/*
+============
+Cvar_ForceReset
+============
+*/
+void Cvar_ForceReset(const char *var_name)
+{
+ Cvar_Set2(var_name, nullptr, true);
+}
+/*
+============
+Cvar_SetCheatState
+
+Any testing variables will be reset to the safe values
+============
+*/
+void Cvar_SetCheatState(void)
+{
+ // set all default vars to the safe value
+ for (cvar_t *var = cvar_vars; var; var = var->next)
+ {
+ if (var->flags & CVAR_CHEAT)
+ {
+ // the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here
+ // because of a different var->latchedString
+ if (var->latchedString)
+ {
+ Z_Free(var->latchedString);
+ var->latchedString = nullptr;
+ }
+ if (strcmp(var->resetString, var->string))
+ Cvar_Set(var->name, var->resetString);
+ }
+ }
+}
+
+/*
+============
+Cvar_Command
+
+Handles variable inspection and changing from the console
+============
+*/
+bool Cvar_Command(void)
+{
+ cvar_t *v = Cvar_FindVar(Cmd_Argv(0));
+ if (!v)
+ {
+ return false;
+ }
+
+ // perform a variable print or set
+ if (Cmd_Argc() == 1)
+ {
+ Cvar_Print(v);
+ return true;
+ }
+
+ // set the value if forcing isn't required
+ Cvar_Set2(v->name, Cmd_Args(), false);
+ return true;
+}
+
+/*
+============
+Cvar_Print_f
+
+Prints the contents of a cvar
+(preferred over Cvar_Command where cvar names and commands conflict)
+============
+*/
+void Cvar_Print_f(void)
+{
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf("usage: print <variable>\n");
+ return;
+ }
+
+ const char *name = Cmd_Argv(1);
+ cvar_t *cv = Cvar_FindVar(name);
+
+ if (cv)
+ Cvar_Print(cv);
+ else
+ Com_Printf("Cvar %s does not exist.\n", name);
+}
+
+/*
+============
+Cvar_Toggle_f
+
+Toggles a cvar for easy single key binding, optionally through a list of
+given values
+============
+*/
+void Cvar_Toggle_f(void)
+{
+ int c = Cmd_Argc();
+ if (c < 2)
+ {
+ Com_Printf("usage: toggle <variable> [value1, value2, ...]\n");
+ return;
+ }
+ else if (c == 2)
+ {
+ Cvar_Set2(Cmd_Argv(1), va("%d", !Cvar_VariableValue(Cmd_Argv(1))), false);
+ return;
+ }
+ else if (c == 3)
+ {
+ Com_Printf("toggle: nothing to toggle to\n");
+ return;
+ }
+
+ const char *curval = Cvar_VariableString(Cmd_Argv(1));
+
+ // don't bother checking the last arg for a match since the desired
+ // behaviour is the same as no match (set to the first argument)
+ for (int i = 2; i + 1 < c; i++)
+ {
+ if (strcmp(curval, Cmd_Argv(i)) == 0)
+ {
+ Cvar_Set2(Cmd_Argv(1), Cmd_Argv(i + 1), false);
+ return;
+ }
+ }
+
+ // fallback
+ Cvar_Set2(Cmd_Argv(1), Cmd_Argv(2), false);
+}
+
+/*
+============
+Cvar_Set_f
+
+Allows setting and defining of arbitrary cvars from console, even if they
+weren't declared in C code.
+============
+*/
+void Cvar_Set_f(void)
+{
+ int c = Cmd_Argc();
+ const char *cmd = Cmd_Argv(0);
+
+ if (c < 2)
+ {
+ Com_Printf("usage: %s <variable> <value>\n", cmd);
+ return;
+ }
+ else if (c == 2)
+ {
+ Cvar_Print_f();
+ return;
+ }
+
+ cvar_t *v = Cvar_Set2(Cmd_Argv(1), Cmd_ArgsFrom(2), false);
+ if (!v)
+ {
+ return;
+ }
+
+ switch (cmd[3])
+ {
+ case 'a':
+ if (!(v->flags & CVAR_ARCHIVE))
+ {
+ v->flags |= CVAR_ARCHIVE;
+ cvar_modifiedFlags |= CVAR_ARCHIVE;
+ }
+ break;
+ case 'u':
+ if (!(v->flags & CVAR_USERINFO))
+ {
+ v->flags |= CVAR_USERINFO;
+ cvar_modifiedFlags |= CVAR_USERINFO;
+ }
+ break;
+ case 's':
+ if (!(v->flags & CVAR_SERVERINFO))
+ {
+ v->flags |= CVAR_SERVERINFO;
+ cvar_modifiedFlags |= CVAR_SERVERINFO;
+ }
+ break;
+ }
+}
+
+/*
+============
+Cvar_Reset_f
+============
+*/
+void Cvar_Reset_f(void)
+{
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf("usage: reset <variable>\n");
+ return;
+ }
+ Cvar_Reset(Cmd_Argv(1));
+}
+
+/*
+============
+Cvar_WriteVariables
+
+Appends lines containing "set variable value" for all variables
+with the archive flag set to true.
+============
+*/
+void Cvar_WriteVariables(fileHandle_t f)
+{
+ cvar_t *var;
+ char buffer[1024];
+
+ for (var = cvar_vars; var; var = var->next)
+ {
+ if (!var->name)
+ continue;
+
+ if (var->flags & CVAR_ARCHIVE)
+ {
+ // write the latched value, even if it hasn't taken effect yet
+ if (var->latchedString)
+ {
+ if (strlen(var->name) + strlen(var->latchedString) + 10 > sizeof(buffer))
+ {
+ Com_Printf(S_COLOR_YELLOW
+ "WARNING: value of variable "
+ "\"%s\" too long to write to file\n",
+ var->name);
+ continue;
+ }
+ Com_sprintf(buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->latchedString);
+ }
+ else
+ {
+ if (strlen(var->name) + strlen(var->string) + 10 > sizeof(buffer))
+ {
+ Com_Printf(S_COLOR_YELLOW
+ "WARNING: value of variable "
+ "\"%s\" too long to write to file\n",
+ var->name);
+ continue;
+ }
+ Com_sprintf(buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->string);
+ }
+ FS_Write(buffer, strlen(buffer), f);
+ }
+ }
+}
+
+/*
+============
+Cvar_List_f
+============
+*/
+void Cvar_List_f(void)
+{
+ cvar_t *var;
+ int i;
+ const char *match;
+
+ if (Cmd_Argc() > 1)
+ {
+ match = Cmd_Argv(1);
+ }
+ else
+ {
+ match = nullptr;
+ }
+
+ i = 0;
+ for (var = cvar_vars; var; var = var->next, i++)
+ {
+ if (!var->name || (match && !Com_Filter(match, var->name, false)))
+ continue;
+
+ if (var->flags & CVAR_SERVERINFO)
+ {
+ Com_Printf("S");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_SYSTEMINFO)
+ {
+ Com_Printf("s");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_USERINFO)
+ {
+ Com_Printf("U");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_ROM)
+ {
+ Com_Printf("R");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_INIT)
+ {
+ Com_Printf("I");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_ARCHIVE)
+ {
+ Com_Printf("A");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_LATCH)
+ {
+ Com_Printf("L");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_CHEAT)
+ {
+ Com_Printf("C");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_USER_CREATED)
+ {
+ Com_Printf("?");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+
+ Com_Printf(" %s \"%s\"\n", var->name, var->string);
+ }
+
+ Com_Printf("\n%i total cvars\n", i);
+ Com_Printf("%i cvar indexes\n", cvar_numIndexes);
+}
+
+/*
+============
+Cvar_ListModified_f
+============
+*/
+void Cvar_ListModified_f(void)
+{
+ cvar_t *var;
+ int totalModified;
+ char *value;
+ const char *match;
+
+ if (Cmd_Argc() > 1)
+ {
+ match = Cmd_Argv(1);
+ }
+ else
+ {
+ match = nullptr;
+ }
+
+ totalModified = 0;
+ for (var = cvar_vars; var; var = var->next)
+ {
+ if (!var->name || !var->modificationCount)
+ continue;
+
+ value = var->latchedString ? var->latchedString : var->string;
+ if (!strcmp(value, var->resetString))
+ continue;
+
+ totalModified++;
+
+ if (match && !Com_Filter(match, var->name, false))
+ continue;
+
+ if (var->flags & CVAR_SERVERINFO)
+ {
+ Com_Printf("S");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_SYSTEMINFO)
+ {
+ Com_Printf("s");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_USERINFO)
+ {
+ Com_Printf("U");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_ROM)
+ {
+ Com_Printf("R");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_INIT)
+ {
+ Com_Printf("I");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_ARCHIVE)
+ {
+ Com_Printf("A");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_LATCH)
+ {
+ Com_Printf("L");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_CHEAT)
+ {
+ Com_Printf("C");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+ if (var->flags & CVAR_USER_CREATED)
+ {
+ Com_Printf("?");
+ }
+ else
+ {
+ Com_Printf(" ");
+ }
+
+ Com_Printf(" %s \"%s\", default \"%s\"\n", var->name, value, var->resetString);
+ }
+
+ Com_Printf("\n%i total modified cvars\n", totalModified);
+}
+
+/*
+============
+Cvar_Unset
+
+Unsets a cvar
+============
+*/
+
+cvar_t *Cvar_Unset(cvar_t *cv)
+{
+ cvar_t *next = cv->next;
+
+ // note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
+ cvar_modifiedFlags |= cv->flags;
+
+ if (cv->name)
+ Z_Free(cv->name);
+ if (cv->string)
+ Z_Free(cv->string);
+ if (cv->latchedString)
+ Z_Free(cv->latchedString);
+ if (cv->resetString)
+ Z_Free(cv->resetString);
+ if (cv->description)
+ Z_Free(cv->description);
+
+ if (cv->prev)
+ cv->prev->next = cv->next;
+ else
+ cvar_vars = cv->next;
+ if (cv->next)
+ cv->next->prev = cv->prev;
+
+ if (cv->hashPrev)
+ cv->hashPrev->hashNext = cv->hashNext;
+ else
+ hashTable[cv->hashIndex] = cv->hashNext;
+ if (cv->hashNext)
+ cv->hashNext->hashPrev = cv->hashPrev;
+
+ ::memset(cv, '\0', sizeof(*cv));
+
+ return next;
+}
+
+/*
+============
+Cvar_Unset_f
+
+Unsets a userdefined cvar
+============
+*/
+
+void Cvar_Unset_f(void)
+{
+ cvar_t *cv;
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf("Usage: %s <varname>\n", Cmd_Argv(0));
+ return;
+ }
+
+ cv = Cvar_FindVar(Cmd_Argv(1));
+
+ if (!cv)
+ return;
+
+ if (cv->flags & CVAR_USER_CREATED)
+ Cvar_Unset(cv);
+ else
+ Com_Printf("Error: %s: Variable %s is not user created.\n", Cmd_Argv(0), cv->name);
+}
+
+/*
+============
+Cvar_Restart
+
+Resets all cvars to their hardcoded values and removes userdefined variables
+and variables added via the VMs if requested.
+============
+*/
+
+void Cvar_Restart(bool unsetVM)
+{
+ cvar_t *curvar;
+
+ curvar = cvar_vars;
+
+ while (curvar)
+ {
+ if ((curvar->flags & CVAR_USER_CREATED) || (unsetVM && (curvar->flags & CVAR_VM_CREATED)))
+ {
+ // throw out any variables the user/vm created
+ curvar = Cvar_Unset(curvar);
+ continue;
+ }
+
+ if (!(curvar->flags & (CVAR_ROM | CVAR_INIT | CVAR_NORESTART)))
+ {
+ // Just reset the rest to their default values.
+ Cvar_Set2(curvar->name, curvar->resetString, false);
+ }
+
+ curvar = curvar->next;
+ }
+}
+
+/*
+============
+Cvar_Restart_f
+
+Resets all cvars to their hardcoded values
+============
+*/
+void Cvar_Restart_f(void)
+{
+ Cvar_Restart(false);
+}
+/*
+=====================
+Cvar_InfoString
+=====================
+*/
+char *Cvar_InfoString(int bit)
+{
+ static char info[MAX_INFO_STRING];
+ cvar_t *var;
+
+ info[0] = 0;
+
+ for (var = cvar_vars; var; var = var->next)
+ {
+ if (var->name && (var->flags & bit))
+ Info_SetValueForKey(info, var->name, var->string);
+ }
+
+ return info;
+}
+
+/*
+=====================
+Cvar_InfoString_Big
+
+ handles large info strings ( CS_SYSTEMINFO )
+=====================
+*/
+char *Cvar_InfoString_Big(int bit)
+{
+ static char info[BIG_INFO_STRING];
+ cvar_t *var;
+
+ info[0] = 0;
+
+ for (var = cvar_vars; var; var = var->next)
+ {
+ if (var->name && (var->flags & bit))
+ Info_SetValueForKey_Big(info, var->name, var->string);
+ }
+ return info;
+}
+
+/*
+=====================
+Cvar_InfoStringBuffer
+=====================
+*/
+void Cvar_InfoStringBuffer(int bit, char *buff, int buffsize)
+{
+ Q_strncpyz(buff, Cvar_InfoString(bit), buffsize);
+}
+/*
+=====================
+Cvar_CheckRange
+=====================
+*/
+void Cvar_CheckRange(cvar_t *var, float min, float max, bool integral)
+{
+ var->validate = true;
+ var->min = min;
+ var->max = max;
+ var->integral = integral;
+
+ // Force an initial range check
+ Cvar_Set(var->name, var->string);
+}
+
+/*
+=====================
+Cvar_SetDescription
+=====================
+*/
+void Cvar_SetDescription(cvar_t *var, const char *var_description)
+{
+ if (var_description && var_description[0] != '\0')
+ {
+ if (var->description != nullptr)
+ {
+ Z_Free(var->description);
+ }
+ var->description = CopyString(var_description);
+ }
+}
+
+/*
+=====================
+Cvar_Register
+
+basically a slightly modified Cvar_Get for the interpreted modules
+=====================
+*/
+void Cvar_Register(vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags)
+{
+ cvar_t *cv;
+
+ // There is code in Cvar_Get to prevent CVAR_ROM cvars being changed by the
+ // user. In other words CVAR_ARCHIVE and CVAR_ROM are mutually exclusive
+ // flags. Unfortunately some historical game code (including single player
+ // baseq3) sets both flags. We unset CVAR_ROM for such cvars.
+ if ((flags & (CVAR_ARCHIVE | CVAR_ROM)) == (CVAR_ARCHIVE | CVAR_ROM))
+ {
+ Com_DPrintf(S_COLOR_YELLOW
+ "WARNING: Unsetting CVAR_ROM cvar '%s', "
+ "since it is also CVAR_ARCHIVE\n",
+ varName);
+ flags &= ~CVAR_ROM;
+ }
+
+ cv = Cvar_Get(varName, defaultValue, flags | CVAR_VM_CREATED);
+
+ if (!vmCvar)
+ return;
+
+ vmCvar->handle = cv - cvar_indexes;
+ vmCvar->modificationCount = -1;
+ Cvar_Update(vmCvar);
+}
+
+/*
+=====================
+Cvar_Update
+
+updates an interpreted modules' version of a cvar
+=====================
+*/
+void Cvar_Update(vmCvar_t *vmCvar)
+{
+ cvar_t *cv = nullptr;
+ assert(vmCvar);
+
+ if (vmCvar->handle >= cvar_numIndexes)
+ {
+ Com_Error(ERR_DROP, "Cvar_Update: handle out of range");
+ }
+
+ cv = cvar_indexes + vmCvar->handle;
+
+ if (cv->modificationCount == vmCvar->modificationCount)
+ {
+ return;
+ }
+ if (!cv->string)
+ {
+ return; // variable might have been cleared by a cvar_restart
+ }
+ vmCvar->modificationCount = cv->modificationCount;
+ if (strlen(cv->string) + 1 > MAX_CVAR_VALUE_STRING)
+ Com_Error(ERR_DROP, "Cvar_Update: src %s length %u exceeds MAX_CVAR_VALUE_STRING", cv->string,
+ (unsigned int)strlen(cv->string));
+ Q_strncpyz(vmCvar->string, cv->string, MAX_CVAR_VALUE_STRING);
+
+ vmCvar->value = cv->value;
+ vmCvar->integer = cv->integer;
+}
+
+/*
+==================
+Cvar_CompleteCvarName
+==================
+*/
+void Cvar_CompleteCvarName(char *args, int argNum)
+{
+ if (argNum == 2)
+ {
+ // Skip "<cmd> "
+ char *p = Com_SkipTokens(args, 1, " ");
+
+ if (p > args)
+ Field_CompleteCommand(p, false, true);
+ }
+}
+
+/*
+============
+Cvar_Init
+
+Reads in all archived cvars
+============
+*/
+void Cvar_Init(void)
+{
+ ::memset(cvar_indexes, '\0', sizeof(cvar_indexes));
+ ::memset(hashTable, '\0', sizeof(hashTable));
+
+ cvar_cheats = Cvar_Get("sv_cheats", "1", CVAR_ROM | CVAR_SYSTEMINFO);
+
+ Cmd_AddCommand("print", Cvar_Print_f);
+ Cmd_AddCommand("toggle", Cvar_Toggle_f);
+ Cmd_SetCommandCompletionFunc("toggle", Cvar_CompleteCvarName);
+ Cmd_AddCommand("set", Cvar_Set_f);
+ Cmd_SetCommandCompletionFunc("set", Cvar_CompleteCvarName);
+ Cmd_AddCommand("sets", Cvar_Set_f);
+ Cmd_SetCommandCompletionFunc("sets", Cvar_CompleteCvarName);
+ Cmd_AddCommand("setu", Cvar_Set_f);
+ Cmd_SetCommandCompletionFunc("setu", Cvar_CompleteCvarName);
+ Cmd_AddCommand("seta", Cvar_Set_f);
+ Cmd_SetCommandCompletionFunc("seta", Cvar_CompleteCvarName);
+ Cmd_AddCommand("reset", Cvar_Reset_f);
+ Cmd_SetCommandCompletionFunc("reset", Cvar_CompleteCvarName);
+ Cmd_AddCommand("unset", Cvar_Unset_f);
+ Cmd_SetCommandCompletionFunc("unset", Cvar_CompleteCvarName);
+
+ Cmd_AddCommand("cvarlist", Cvar_List_f);
+ Cmd_AddCommand("cvar_modified", Cvar_ListModified_f);
+ Cmd_AddCommand("cvar_restart", Cvar_Restart_f);
+}
diff --git a/src/qcommon/cvar.h b/src/qcommon/cvar.h
new file mode 100644
index 0000000..465a99d
--- /dev/null
+++ b/src/qcommon/cvar.h
@@ -0,0 +1,199 @@
+/*
+ * This file is part of Tremulous.
+ * Copyright © 2017 Victor Roemer (blowfish) <victor@badsec.org>
+ * Copyright (C) 2015-2019 GrangerHub
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CVAR_H
+#define CVAR_H
+
+#include "q_platform.h"
+#include "q_shared.h"
+
+/*
+==========================================================
+
+CVARS (console variables)
+
+Many variables can be used for cheating purposes, so when
+cheats is zero, force all unspecified variables to their
+default values.
+==========================================================
+*/
+
+#define CVAR_ARCHIVE 0x0001 // set to cause it to be saved to vars.rc
+// used for system variables, not for player
+// specific configurations
+#define CVAR_USERINFO 0x0002 // sent to server on connect or change
+#define CVAR_SERVERINFO 0x0004 // sent in response to front end requests
+#define CVAR_SYSTEMINFO 0x0008 // these cvars will be duplicated on all clients
+#define CVAR_INIT 0x0010 // don't allow change from console at all,
+// but can be set from the command line
+#define CVAR_LATCH 0x0020 // will only change when C code next does
+// a Cvar_Get(), so it can't be changed without proper initialization.
+// modified will be set, even though the value hasn't changed yet
+#define CVAR_ROM 0x0040 // display only, cannot be set by user at all
+#define CVAR_USER_CREATED 0x0080 // created by a set command
+#define CVAR_TEMP 0x0100 // can be set even when cheats are disabled, but is not archived
+#define CVAR_CHEAT 0x0200 // can not be changed if cheats are disabled
+#define CVAR_NORESTART 0x0400 // do not clear when a cvar_restart is issued
+
+#define CVAR_SERVER_CREATED 0x0800 // cvar was created by a server the client connected to.
+#define CVAR_VM_CREATED 0x1000 // cvar was created exclusively in one of the VMs.
+#define CVAR_PROTECTED 0x2000 // prevent modifying this var from VMs or the server
+#define CVAR_ALTERNATE_SYSTEMINFO 0x1000000
+// These flags are only returned by the Cvar_Flags() function
+#define CVAR_MODIFIED 0x40000000 // Cvar was modified
+#define CVAR_NONEXISTENT 0x80000000 // Cvar doesn't exist.
+
+// nothing outside the Cvar_*() functions should modify these fields!
+typedef struct cvar_s cvar_t;
+
+struct cvar_s {
+ char *name;
+ char *string;
+ char *resetString; // cvar_restart will reset to this value
+ char *latchedString; // for CVAR_LATCH vars
+ int flags;
+ bool modified; // set each time the cvar is changed
+ int modificationCount; // incremented each time the cvar is changed
+ float value; // atof( string )
+ int integer; // atoi( string )
+ bool validate;
+ bool integral;
+ float min;
+ float max;
+ char *description;
+
+ cvar_t *next;
+ cvar_t *prev;
+ cvar_t *hashNext;
+ cvar_t *hashPrev;
+ int hashIndex;
+};
+
+/*
+==============================================================
+
+CVAR
+
+==============================================================
+*/
+
+/*
+
+cvar_t variables are used to hold scalar or string variables that can be changed
+or displayed at the console or prog code as well as accessed directly
+in C code.
+
+The user can access cvars from the console in three ways:
+r_draworder prints the current value
+r_draworder 0 sets the current value to 0
+set r_draworder 0 as above, but creates the cvar if not present
+
+Cvars are restricted from having the same names as commands to keep this
+interface from being ambiguous.
+
+The are also occasionally used to communicated information between different
+modules of the program.
+
+*/
+
+cvar_t *Cvar_Get(const char *var_name, const char *value, int flags);
+// creates the variable if it doesn't exist, or returns the existing one
+// if it exists, the value will not be changed, but flags will be ORed in
+// that allows variables to be unarchived without needing bitflags
+// if value is "", the value will not override a previously set value.
+
+void Cvar_Register(vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags);
+// basically a slightly modified Cvar_Get for the interpreted modules
+
+void Cvar_Update(vmCvar_t *vmCvar);
+// updates an interpreted modules' version of a cvar
+
+void Cvar_Set(const char *var_name, const char *value);
+// will create the variable with no flags if it doesn't exist
+
+cvar_t *Cvar_Set2(const char *var_name, const char *value, bool force);
+// same as Cvar_Set, but allows more control over setting of cvar
+
+void Cvar_SetSafe(const char *var_name, const char *value);
+// sometimes we set variables from an untrusted source: fail if flags & CVAR_PROTECTED
+
+void Cvar_SetLatched(const char *var_name, const char *value);
+// don't set the cvar immediately
+
+void Cvar_SetValue(const char *var_name, float value);
+void Cvar_SetValueSafe(const char *var_name, float value);
+// expands value to a string and calls Cvar_Set/Cvar_SetSafe
+
+// Validate String used to validate cvar names
+bool Cvar_ValidateString(const char *s);
+cvar_t *Cvar_FindVar(const char *var_name);
+const char *Cvar_Validate(cvar_t *var, const char *value, bool warn);
+void Cvar_Print(cvar_t *v);
+
+float Cvar_VariableValue(const char *var_name);
+int Cvar_VariableIntegerValue(const char *var_name);
+// returns 0 if not defined or non numeric
+
+const char *Cvar_VariableString(const char *var_name);
+void Cvar_VariableStringBuffer(const char *var_name, char *buffer, int bufsize);
+// returns an empty string if not defined
+
+unsigned int Cvar_Flags(const char *var_name);
+// returns CVAR_NONEXISTENT if cvar doesn't exist or the flags of that particular CVAR.
+
+void Cvar_CommandCompletion(void (*callback)(const char *s));
+// callback with each valid string
+
+void Cvar_Reset(const char *var_name);
+void Cvar_ForceReset(const char *var_name);
+
+void Cvar_SetCheatState(void);
+// reset all testing vars to a safe value
+
+bool Cvar_Command(void);
+// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known
+// command. Returns true if the command was a variable reference that
+// was handled. (print or change)
+
+void Cvar_WriteVariables(fileHandle_t f);
+// writes lines containing "set variable value" for all variables
+// with the archive flag set to true.
+
+void Cvar_Init(void);
+
+char *Cvar_InfoString(int bit);
+char *Cvar_InfoString_Big(int bit);
+// returns an info string containing all the cvars that have the given bit set
+// in their flags ( CVAR_USERINFO, CVAR_SERVERINFO, CVAR_SYSTEMINFO, etc )
+void Cvar_InfoStringBuffer(int bit, char *buff, int buffsize);
+void Cvar_CheckRange(cvar_t *cv, float minVal, float maxVal, bool shouldBeIntegral);
+void Cvar_SetDescription(cvar_t *var, const char *var_description);
+
+void Cvar_Restart(bool unsetVM);
+void Cvar_Restart_f(void);
+
+void Cvar_CompleteCvarName(char *args, int argNum);
+
+extern int cvar_modifiedFlags;
+// whenever a cvar is modifed, its flags will be OR'd into this, so
+// a single check can determine if any CVAR_USERINFO, CVAR_SERVERINFO,
+// etc, variables have been modified since the last check. The bit
+// can then be cleared to allow another change detection.
+
+#endif
diff --git a/src/qcommon/files.cpp b/src/qcommon/files.cpp
new file mode 100644
index 0000000..68b72b3
--- /dev/null
+++ b/src/qcommon/files.cpp
@@ -0,0 +1,3986 @@
+/*
+ Copyright (C) 2016 Victor Roemer (wtfbbqhax), <victor@badsec.org>.
+ Copyright (C) 2000-2013 Darklegion Development
+ Copyright (C) 1999-2005 Id Software, Inc.
+ Copyright (C) 2015-2019 GrangerHub
+
+ This file is part of Tremulous.
+
+ Tremulous is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ Tremulous is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+*/
+
+#include "files.h"
+
+#ifdef _WIN32
+#include <io.h>
+#include <windows.h>
+#endif
+
+#include <cctype>
+#include <cstdarg>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include "cmd.h"
+#include "cvar.h"
+#include "md4.h"
+#include "q_platform.h"
+#include "q_shared.h"
+#include "qcommon.h"
+#include "unzip.h"
+#include "vm.h"
+
+#ifndef DEDICATED
+#include "client/cl_rest.h"
+#endif
+#include "sys/sys_shared.h"
+
+using namespace std;
+
+#define MAX_ZPATH 256
+#define MAX_SEARCH_PATHS 4096
+#define MAX_FILEHASH_SIZE 1024
+
+static bool FS_IsDemoExt(const char *filename);
+static bool FS_IsExt(const char *filename, const char *ext, int namelen);
+
+struct fileInPack_t {
+ char* name;
+ unsigned long pos; // file info position in zip
+ unsigned long len; // uncompressed file size
+ fileInPack_t* next;
+};
+
+struct pack_t {
+ char pakPathname[MAX_OSPATH]; // /tremulous/baseq3
+ char pakFilename[MAX_OSPATH]; // /tremulous/base/pak0.pk3
+ char pakBasename[MAX_OSPATH]; // pak0
+ char pakGamename[MAX_OSPATH]; // base
+ unzFile handle; // handle to zip file
+ int checksum; // regular checksum
+ int pure_checksum; // checksum for pure
+ int numfiles; // number of files in pk3
+ int referenced; // referenced file flags
+ int hashSize; // hash table size (power of 2)
+ fileInPack_t **hashTable; // hash table
+ fileInPack_t *buildBuffer; // buffer with the filenames etc.
+ // some multiprotocol stuff
+ bool onlyPrimary;
+ bool onlyAlternate;
+ pack_t *primaryVersion;
+
+ // member functions
+ inline fileInPack_t* find(string filename);
+ inline bool is_pure();
+};
+
+struct directory_t {
+ char path[MAX_OSPATH];
+ char fullpath[MAX_OSPATH]; // /tremulous/base
+ char gamedir[MAX_OSPATH]; // base
+};
+
+struct searchpath_t {
+ pack_t *pack; // only one of pack / dir will be non nullptr
+ directory_t *dir;
+ searchpath_t *next;
+};
+
+static char fs_gamedir[MAX_OSPATH]; // this will be a single file name with no separators
+static cvar_t *fs_debug;
+static cvar_t *fs_homepath;
+
+static cvar_t *fs_basepath;
+static cvar_t *fs_basegame;
+#ifdef __APPLE__
+static cvar_t *fs_apppath; // Also search the .app bundle for .pk3 files
+#endif
+static cvar_t *fs_gamedirvar;
+
+static searchpath_t *fs_searchpaths;
+static int fs_readCount; // total bytes read
+static int fs_loadCount; // total files read
+static int fs_loadStack; // total files in memory
+static int fs_packFiles = 0; // total number of files in packs
+
+static int fs_checksumFeed;
+
+union qfile_gut {
+ FILE *o;
+ unzFile z;
+};
+
+struct qfile_ut {
+ qfile_gut file;
+ bool unique;
+};
+
+struct fileHandleData_t {
+ qfile_ut handleFiles;
+ bool handleSync;
+ int fileSize;
+ int zipFilePos;
+ int zipFileLen;
+ bool zipFile;
+ char name[MAX_ZPATH];
+
+ void close();
+};
+
+static fileHandleData_t fsh[MAX_FILE_HANDLES];
+
+// TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=540
+// wether we did a reorder on the current search path when joining the server
+
+static bool fs_reordered;
+
+// never load anything from pk3 files that are not present at the server when pure
+
+static int fs_numServerPaks = 0;
+static int fs_serverPaks[MAX_SEARCH_PATHS]; // checksums
+static char *fs_serverPakNames[MAX_SEARCH_PATHS]; // pk3 names
+
+// only used for autodownload, to make sure the client has at least
+// all the pk3 files that are referenced at the server side
+
+static int fs_numServerReferencedPaks;
+static int fs_serverReferencedPaks[MAX_SEARCH_PATHS]; // checksums
+static char *fs_serverReferencedPakNames[MAX_SEARCH_PATHS]; // pk3 names
+
+// last valid game folder used
+char lastValidBase[MAX_OSPATH];
+char lastValidGame[MAX_OSPATH];
+
+#ifdef FS_MISSING
+FILE *missingFiles = nullptr;
+#endif
+
+/*
+==============
+FS_Initialized
+==============
+*/
+
+bool FS_Initialized(void) { return fs_searchpaths ? true : false; }
+
+/*
+=================
+pack_t::is_pure()
+
+FIXME: also use hashed file names
+=================
+*/
+inline bool pack_t::is_pure()
+{
+ if (fs_numServerPaks)
+ {
+ for (int i = 0; i < fs_numServerPaks; i++)
+ if (checksum == fs_serverPaks[i])
+ return true;
+
+ return false;
+ }
+ return true;
+}
+
+/*
+=================
+FS_LoadStack
+return load stack
+=================
+*/
+int FS_LoadStack(void) { return fs_loadStack; }
+
+inline fileInPack_t* pack_t::find(string filename)
+{
+ long hash = 0;
+ auto fn = filename.c_str();
+ for (long i = 0; fn[i]; i++)
+ {
+ long c = tolower(fn[i]);
+ if (c == '.')
+ break; // FIXME probably a bad idea
+
+ if (c == '\\')
+ c = '/';
+ hash += c * (i + 119);
+ }
+ hash = (hash ^ (hash >> 10) ^ (hash >> 20));
+ hash &= (hashSize - 1);
+
+ for (auto file = hashTable[hash]; file; file = file->next)
+ {
+ if (FS_FilenameCompare(file->name, fn) == false)
+ return file;
+ }
+ return nullptr;
+}
+/*
+================
+return a hash value for the filename
+================
+*/
+static long FS_HashFileName(const char *fname, int hashSize)
+{
+ int i;
+ long hash;
+ char letter;
+
+ hash = 0;
+ i = 0;
+ while (fname[i] != '\0')
+ {
+ letter = tolower(fname[i]);
+ if (letter == '.') break; // don't include extension
+ if (letter == '\\') letter = '/'; // damn path names
+ if (letter == PATH_SEP) letter = '/'; // damn path names
+ hash += (long)(letter) * (i + 119);
+ i++;
+ }
+ hash = (hash ^ (hash >> 10) ^ (hash >> 20));
+ hash &= (hashSize - 1);
+ return hash;
+}
+
+static fileHandle_t FS_HandleForFile(void)
+{
+ for (int i = 1; i < MAX_FILE_HANDLES; i++)
+ {
+ if (fsh[i].handleFiles.file.o == nullptr)
+ {
+ return i;
+ }
+ }
+ Com_Error(ERR_DROP, "FS_HandleForFile: none free");
+ return 0;
+}
+
+static FILE *FS_FileForHandle(fileHandle_t f)
+{
+ if (f < 1 || f >= MAX_FILE_HANDLES)
+ {
+ Com_Error(ERR_DROP, "FS_FileForHandle: out of range");
+ }
+
+ if (fsh[f].zipFile == true)
+ {
+ Com_Error(ERR_DROP, "FS_FileForHandle: can't get FILE on zip file");
+ }
+
+ if (!fsh[f].handleFiles.file.o)
+ {
+ Com_Error(ERR_DROP, "FS_FileForHandle: nullptr");
+ }
+
+ return fsh[f].handleFiles.file.o;
+}
+
+void FS_ForceFlush(fileHandle_t f)
+{
+ FILE *file = FS_FileForHandle(f);
+ setvbuf(file, nullptr, _IONBF, 0);
+}
+
+/*
+================
+FS_fplength
+================
+*/
+
+long FS_fplength(FILE *h)
+{
+ long pos = ftell(h);
+ fseek(h, 0, SEEK_END);
+
+ long end = ftell(h);
+ fseek(h, pos, SEEK_SET);
+
+ return end;
+}
+
+/*
+================
+FS_filelength
+
+If this is called on a non-unique FILE (from a pak file),
+it will return the size of the pak file, not the expected
+size of the file.
+================
+*/
+long FS_filelength(fileHandle_t f)
+{
+ FILE *h = FS_FileForHandle(f);
+ if (h == nullptr) return -1;
+
+ return FS_fplength(h);
+}
+
+/*
+====================
+FS_ReplaceSeparators
+
+Fix things up differently for win/unix/mac
+====================
+*/
+void FS_ReplaceSeparators(char *path)
+{
+ bool lastCharWasSep = false;
+
+ for (char *s = path; *s; s++)
+ {
+ if (*s == '/' || *s == '\\')
+ {
+ if (!lastCharWasSep)
+ {
+ *s = PATH_SEP;
+ lastCharWasSep = true;
+ }
+ else
+ {
+ memmove(s, s + 1, strlen(s));
+ }
+ }
+ else
+ {
+ lastCharWasSep = false;
+ }
+ }
+}
+
+/*
+===================
+FS_BuildOSPath
+
+Qpath may have either forward or backwards slashes
+===================
+*/
+char *FS_BuildOSPath(const char *base, const char *game, const char *qpath)
+{
+ char temp[MAX_OSPATH];
+ // "FIXME FS_BuildOSPath() returns static buffer with function scope"
+
+ // This code will alternate between 2 different buffers-
+ // XXX 3 or more calls to FS_BuildOSPath in a row are not safe.
+ static char ospath[2][MAX_OSPATH];
+ static bool toggle;
+
+ toggle = !toggle; // flip-flop to allow two returns without clash
+
+ if (!game || !game[0])
+ {
+ game = fs_gamedir;
+ }
+
+ Com_sprintf(temp, sizeof(temp), "/%s/%s", game, qpath);
+ FS_ReplaceSeparators(temp);
+ Com_sprintf(ospath[toggle], sizeof(ospath[0]), "%s%s", base, temp);
+
+ Com_DPrintf(S_COLOR_GREEN "%s: returning " S_COLOR_RED "%s\n",
+ __FUNCTION__, ospath[toggle]);
+
+ return ospath[toggle];
+}
+
+/*
+============
+FS_OpenWithDefault
+
+Wrapper for Sys_OpenWithDefault()
+============
+*/
+static bool FS_OpenWithDefault( const char *path )
+{
+ if( Sys_OpenWithDefault( path ) )
+ {
+ // minimize the client's window
+ Cmd_ExecuteString( "minimize" );
+ return true;
+ }
+
+ return false;
+}
+
+/*
+============
+FS_BrowseHomepath
+
+Opens the homepath in the default file manager
+============
+*/
+bool FS_BrowseHomepath( void )
+{
+ const char *homePath = Sys_DefaultHomePath( );
+
+ if (!homePath || !homePath[0])
+ {
+ homePath = fs_basepath->string;
+ }
+
+ if( FS_OpenWithDefault( homePath ) )
+ return true;
+
+ Com_Printf( S_COLOR_RED "FS_BrowseHomepath: failed to open the homepath with the default file manager.\n" S_COLOR_WHITE );
+ return false;
+}
+
+/*
+============
+FS_OpenBaseGamePath
+
+Opens the given path for the
+base game in the default file manager
+============
+*/
+bool FS_OpenBaseGamePath( const char *baseGamePath )
+{
+ const char *homePath = Sys_DefaultHomePath( );
+ const char *path;
+
+ if (!homePath || !homePath[0])
+ {
+ homePath = fs_basepath->string;
+ }
+
+ path = FS_BuildOSPath( homePath, fs_basegame->string, baseGamePath);
+
+ if( FS_OpenWithDefault( path ) )
+ return true;
+
+ Com_Printf( S_COLOR_RED "FS_BrowseHomepath: failed to open the homepath with the default file manager.\n" S_COLOR_WHITE );
+ return false;
+}
+
+/*
+============
+FS_CreatePath
+
+Creates any directories needed to store the given filename
+============
+*/
+bool FS_CreatePath(const char *OSPath)
+{
+ // make absolutely sure that it can't back up the path
+ // FIXME: is c: allowed???
+ if (strstr(OSPath, "..") || strstr(OSPath, "::"))
+ {
+ Com_Printf("WARNING: refusing to create relative path \"%s\"\n", OSPath);
+ return true;
+ }
+
+ char path[MAX_OSPATH];
+ Q_strncpyz(path, OSPath, sizeof(path));
+ FS_ReplaceSeparators(path);
+
+ // Skip creation of the root directory as it will always be there
+ char *ofs = strchr(path, PATH_SEP);
+ if (ofs != nullptr)
+ {
+ ofs++;
+ }
+
+ for (; ofs != nullptr && *ofs; ofs++)
+ {
+ if (*ofs == PATH_SEP)
+ {
+ // create the directory
+ *ofs = 0;
+ if (!Sys_Mkdir(path))
+ {
+ Com_Error(ERR_FATAL, "FS_CreatePath: failed to create path \"%s\"", path);
+ }
+ *ofs = PATH_SEP;
+ }
+ }
+
+ return false;
+}
+
+/*
+=================
+FS_CheckFilenameIsMutable
+
+ERR_FATAL if trying to maniuplate a file with the platform library, QVM, or pk3 extension
+=================
+ */
+static void FS_CheckFilenameIsMutable(const char *filename, const char *function)
+{
+ // Check if the filename ends with the library, QVM, or pk3 extension
+ if (Sys_DllExtension(filename) || COM_CompareExtension(filename, ".qvm") ||
+ COM_CompareExtension(filename, ".lua") || COM_CompareExtension(filename, ".pk3"))
+ {
+ Com_Error(ERR_FATAL, "%s: Not allowed to manipulate '%s' due to %s extension",
+ function, filename, COM_GetExtension(filename));
+ }
+}
+
+/*
+===========
+FS_Remove
+
+===========
+*/
+void FS_Remove(const char *osPath)
+{
+ FS_CheckFilenameIsMutable(osPath, __FUNCTION__);
+// RB begin
+#if defined(_WIN32)
+ ::DeleteFile(osPath);
+#else
+ remove(osPath);
+#endif
+}
+
+/*
+===========
+FS_HomeRemove
+
+===========
+*/
+void FS_HomeRemove(const char *homePath)
+{
+ FS_CheckFilenameIsMutable(homePath, __FUNCTION__);
+ FS_Remove(FS_BuildOSPath(fs_homepath->string, fs_gamedir, homePath));
+}
+
+#if 0
+bool FS_RemoveDir(const char* relativePath)
+{
+ bool success = true;
+ success = Sys_Rmdir(FS_BuildOSPath(fs_homepath->string, fs_gamedir, relativePath));
+ return success;
+}
+#endif
+
+/*
+================
+FS_FileInPathExists
+
+Tests if path and file exists
+================
+*/
+bool FS_FileInPathExists(const char *testpath)
+{
+ FILE *filep;
+
+ filep = Sys_FOpen(testpath, "rb");
+
+ if (filep)
+ {
+ fclose(filep);
+ return true;
+ }
+
+ return false;
+}
+
+/*
+================
+FS_FileExists
+
+Tests if the file exists in the current gamedir, this DOES NOT
+search the paths. This is to determine if opening a file to write
+(which always goes into the current gamedir) will cause any overwrites.
+NOTE TTimo: this goes with FS_FOpenFileWrite for opening the file afterwards
+================
+*/
+bool FS_FileExists(const char *file)
+{
+ return FS_FileInPathExists(FS_BuildOSPath(fs_homepath->string, fs_gamedir, file));
+}
+
+/*
+================
+FS_SV_FileExists
+
+Tests if the file exists
+================
+*/
+bool FS_SV_FileExists(const char *file)
+{
+ char *testpath = FS_BuildOSPath(fs_homepath->string, file, "");
+ testpath[strlen(testpath) - 1] = '\0';
+
+ return FS_FileInPathExists(testpath);
+}
+
+/*
+===========
+FS_SV_FOpenFileWrite
+
+===========
+*/
+fileHandle_t FS_SV_FOpenFileWrite(const char *filename)
+{
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ char *ospath = FS_BuildOSPath(fs_homepath->string, filename, "");
+ ospath[strlen(ospath) - 1] = '\0';
+
+ fileHandle_t f = FS_HandleForFile();
+ fsh[f].zipFile = false;
+
+ Com_DPrintf("FS_SV_FOpenFileWrite: %s\n", ospath);
+
+ FS_CheckFilenameIsMutable(ospath, __FUNCTION__);
+
+ if (FS_CreatePath(ospath))
+ {
+ return 0;
+ }
+
+ Com_DPrintf("writing to: %s\n", ospath);
+ fsh[f].handleFiles.file.o = Sys_FOpen(ospath, "wb");
+
+ Q_strncpyz(fsh[f].name, filename, sizeof(fsh[f].name));
+
+ fsh[f].handleSync = false;
+ if (!fsh[f].handleFiles.file.o)
+ {
+ f = 0;
+ }
+
+ return f;
+}
+
+/*
+===========
+FS_SV_FOpenFileRead
+
+Search for a file somewhere below the home path then base path
+in that order
+===========
+*/
+long FS_SV_FOpenFileRead(const char *filename, fileHandle_t *fp)
+{
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ fileHandle_t f = FS_HandleForFile();
+ fsh[f].zipFile = false;
+
+ Q_strncpyz(fsh[f].name, filename, sizeof(fsh[f].name));
+
+ // don't let sound stutter
+ S_ClearSoundBuffer();
+
+ // search homepath
+ char *ospath = FS_BuildOSPath(fs_homepath->string, filename, "");
+ // remove trailing slash
+ ospath[strlen(ospath) - 1] = '\0';
+
+ Com_DPrintf("FS_SV_FOpenFileRead (fs_homepath): %s\n", ospath);
+
+ fsh[f].handleFiles.file.o = Sys_FOpen(ospath, "rb");
+ fsh[f].handleSync = false;
+ if (!fsh[f].handleFiles.file.o)
+ {
+ // If fs_homepath == fs_basepath, don't bother
+ if (Q_stricmp(fs_homepath->string, fs_basepath->string))
+ {
+ // search basepath
+ ospath = FS_BuildOSPath(fs_basepath->string, filename, "");
+ ospath[strlen(ospath) - 1] = '\0';
+
+ Com_DPrintf("FS_SV_FOpenFileRead (fs_basepath): %s\n", ospath);
+
+ fsh[f].handleFiles.file.o = Sys_FOpen(ospath, "rb");
+ fsh[f].handleSync = false;
+ }
+
+ if (!fsh[f].handleFiles.file.o)
+ {
+ f = 0;
+ }
+ }
+
+ *fp = f;
+ if (f)
+ {
+ return FS_filelength(f);
+ }
+
+ return -1;
+}
+
+/*
+===========
+FS_SV_Rename
+
+===========
+*/
+void FS_SV_Rename(const char *from, const char *to, bool safe)
+{
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ // don't let sound stutter
+ S_ClearSoundBuffer();
+
+ char *from_ospath = FS_BuildOSPath(fs_homepath->string, from, "");
+ char *to_ospath = FS_BuildOSPath(fs_homepath->string, to, "");
+
+ from_ospath[strlen(from_ospath) - 1] = '\0';
+ to_ospath[strlen(to_ospath) - 1] = '\0';
+
+ Com_DPrintf("FS_SV_Rename: (%s) %s --> %s\n", safe ? "safe" : "unsafe", from_ospath, to_ospath);
+
+ if (safe)
+ {
+ FS_CheckFilenameIsMutable(to_ospath, __FUNCTION__);
+ }
+
+ rename(from_ospath, to_ospath);
+}
+
+/*
+===========
+FS_Rename
+
+===========
+*/
+void FS_Rename(const char *from, const char *to)
+{
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ // don't let sound stutter
+ S_ClearSoundBuffer();
+
+ char *from_ospath = FS_BuildOSPath(fs_homepath->string, fs_gamedir, from);
+ char *to_ospath = FS_BuildOSPath(fs_homepath->string, fs_gamedir, to);
+
+ Com_DPrintf("FS_Rename: %s --> %s\n", from_ospath, to_ospath);
+
+ FS_CheckFilenameIsMutable(to_ospath, __FUNCTION__);
+
+ rename(from_ospath, to_ospath);
+}
+
+/*
+==============
+FS_FCloseFile
+
+If the FILE pointer is an open pak file, leave it open.
+
+For some reason, other dll's can't just cal fclose()
+on files returned by FS_FOpenFile...
+==============
+*/
+void fileHandleData_t::close()
+{
+ if (zipFile == true)
+ {
+ unzCloseCurrentFile(handleFiles.file.z);
+
+ if (handleFiles.unique)
+ unzClose(handleFiles.file.z);
+ }
+ // we didn't find it as a pak, so close it as a unique file
+ else if (handleFiles.file.o)
+ {
+ ::fclose(handleFiles.file.o);
+ }
+
+ ::memset(this, 0, sizeof(*this));
+}
+
+void FS_FCloseFile(fileHandle_t f)
+{
+ if (!fs_searchpaths)
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+
+ fsh[f].close();
+
+ ::memset(&fsh[f], 0, sizeof(fsh[f]));
+}
+
+/*
+===========
+FS_FOpenFileWrite
+
+===========
+*/
+fileHandle_t FS_FOpenFileWrite(const char *filename)
+{
+
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ fileHandle_t f = FS_HandleForFile();
+ fsh[f].zipFile = false;
+
+ char *ospath = FS_BuildOSPath(fs_homepath->string, fs_gamedir, filename);
+
+ Com_DPrintf("FS_FOpenFileWrite: %s\n", ospath);
+
+ FS_CheckFilenameIsMutable(ospath, __FUNCTION__);
+
+ if (FS_CreatePath(ospath))
+ {
+ return 0;
+ }
+
+ // enabling the following line causes a recursive function call loop
+ // when running with +set logfile 1 +set developer 1
+ // Com_DPrintf( "writing to: %s\n", ospath );
+ fsh[f].handleFiles.file.o = Sys_FOpen(ospath, "wb");
+
+ Q_strncpyz(fsh[f].name, filename, sizeof(fsh[f].name));
+
+ fsh[f].handleSync = false;
+ if (!fsh[f].handleFiles.file.o)
+ {
+ f = 0;
+ }
+ return f;
+}
+
+/*
+===========
+FS_FOpenFileAppend
+
+===========
+*/
+fileHandle_t FS_FOpenFileAppend(const char *filename)
+{
+ char *ospath;
+ fileHandle_t f;
+
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ f = FS_HandleForFile();
+ fsh[f].zipFile = false;
+
+ Q_strncpyz(fsh[f].name, filename, sizeof(fsh[f].name));
+
+ // don't let sound stutter
+ S_ClearSoundBuffer();
+
+ ospath = FS_BuildOSPath(fs_homepath->string, fs_gamedir, filename);
+
+ Com_DPrintf("FS_FOpenFileAppend: %s\n", ospath);
+
+ FS_CheckFilenameIsMutable(ospath, __FUNCTION__);
+
+ if (FS_CreatePath(ospath))
+ {
+ return 0;
+ }
+
+ fsh[f].handleFiles.file.o = Sys_FOpen(ospath, "ab");
+ fsh[f].handleSync = false;
+ if (!fsh[f].handleFiles.file.o)
+ {
+ f = 0;
+ }
+ return f;
+}
+
+/*
+===========
+FS_FCreateOpenPipeFile
+
+===========
+*/
+fileHandle_t FS_FCreateOpenPipeFile(const char *filename)
+{
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ fileHandle_t f = FS_HandleForFile();
+ fsh[f].zipFile = false;
+
+ Q_strncpyz(fsh[f].name, filename, sizeof(fsh[f].name));
+
+ // don't let sound stutter
+ S_ClearSoundBuffer();
+
+ char *ospath = FS_BuildOSPath(fs_homepath->string, fs_gamedir, filename);
+
+ Com_DPrintf("FS_FCreateOpenPipeFile: %s\n", ospath);
+
+ FS_CheckFilenameIsMutable(ospath, __FUNCTION__);
+
+ FILE *fifo = Sys_Mkfifo(ospath);
+ if (fifo)
+ {
+ fsh[f].handleFiles.file.o = fifo;
+ fsh[f].handleSync = false;
+ }
+ else
+ {
+ Com_Printf(S_COLOR_YELLOW
+ "WARNING: Could not create new com_pipefile at %s. "
+ "com_pipefile will not be used.\n",
+ ospath);
+ f = 0;
+ }
+
+ return f;
+}
+
+/*
+===========
+FS_FilenameCompare
+
+Ignore case and seprator char distinctions
+===========
+*/
+bool FS_FilenameCompare(const char *s1, const char *s2)
+{
+ int c1, c2;
+
+ do
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (c1 >= 'a' && c1 <= 'z')
+ {
+ c1 -= ('a' - 'A');
+ }
+ if (c2 >= 'a' && c2 <= 'z')
+ {
+ c2 -= ('a' - 'A');
+ }
+
+ if (c1 == '\\' || c1 == ':')
+ {
+ c1 = '/';
+ }
+ if (c2 == '\\' || c2 == ':')
+ {
+ c2 = '/';
+ }
+
+ if (c1 != c2)
+ {
+ return true; // strings not equal
+ }
+ } while (c1);
+
+ return false; // strings are equal
+}
+
+/*
+===========
+FS_IsExt
+
+Return true if ext matches file extension filename
+===========
+*/
+static bool FS_IsExt(const char *filename, const char *ext, int namelen)
+{
+ int extlen = strlen(ext);
+
+ if (extlen > namelen) return false;
+
+ filename += namelen - extlen;
+
+ return !Q_stricmp(filename, ext);
+}
+
+/*
+===========
+FS_IsDemoExt
+
+Return true if filename has a demo extension
+===========
+*/
+
+static bool FS_IsDemoExt(const char *filename)
+{
+ const char *ext_test = strrchr(filename, '.');
+ if (ext_test && !Q_stricmpn(ext_test + 1, DEMOEXT, ARRAY_LEN(DEMOEXT) - 1))
+ {
+ int protocol = atoi(ext_test + ARRAY_LEN(DEMOEXT));
+ if (protocol == PROTOCOL_VERSION) return true;
+
+ for (int i = 0; demo_protocols[i]; i++)
+ if (demo_protocols[i] == protocol) return true;
+ }
+
+ return false;
+}
+
+/*
+===========
+FS_FOpenFileReadDir
+
+Tries opening file "filename" in searchpath "search"
+Returns filesize and an open FILE pointer.
+===========
+*/
+long FS_FOpenFileReadDir(
+ const char *filename, void *_search, fileHandle_t *file, bool uniqueFILE, bool unpure)
+{
+ pack_t *pak;
+ directory_t *dir;
+ char *netpath;
+ FILE *filep;
+ int len;
+
+ searchpath_t *search = static_cast<searchpath_t *>(_search);
+
+ if (filename == nullptr)
+ Com_Error(ERR_FATAL, "FS_FOpenFileRead: nullptr 'filename' parameter passed");
+
+ // qpaths are not supposed to have a leading slash
+ if (filename[0] == '/' || filename[0] == '\\') filename++;
+
+ // make absolutely sure that it can't back up the path.
+ // The searchpaths do guarantee that something will always
+ // be prepended, so we don't need to worry about "c:" or "//limbo"
+ if (strstr(filename, "..") || strstr(filename, "::"))
+ {
+ if (file == nullptr) return false;
+
+ *file = 0;
+ return -1;
+ }
+
+ if (file == nullptr)
+ {
+ // just wants to see if file is there
+
+ if ( fs_debug->integer )
+ {
+ Com_Printf(S_COLOR_GREEN "Searching for: " S_COLOR_RED "%s\n", filename);
+ }
+
+ // is the element a pak file?
+ if (search->pack)
+ {
+ auto pakfile = search->pack->find(filename);
+ if (pakfile)
+ {
+ // found it!
+ if (!pakfile->len)
+ {
+ // FIXME: It's not nice, but legacy code depends on
+ // positive value if file exists no matter what size
+ return 1;
+ }
+
+ return pakfile->len;
+ }
+ }
+ else if (search->dir)
+ {
+ dir = search->dir;
+
+ netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename);
+ filep = Sys_FOpen(netpath, "rb");
+
+ if (filep)
+ {
+ len = FS_fplength(filep);
+ fclose(filep);
+
+ if (len)
+ return len;
+ else
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+ *file = FS_HandleForFile();
+ fsh[*file].handleFiles.unique = uniqueFILE;
+
+ // is the element a pak file?
+ if (search->pack)
+ {
+ pak = search->pack;
+ auto pakfile = pak->find(filename);
+ if (pakfile )
+ {
+ if ( fs_debug->integer == 2 )
+ Com_Printf(S_COLOR_GREEN "#2 Searching for: " S_COLOR_RED "%s\n", filename);
+
+ // disregard if it doesn't match one of the allowed pure pak files
+ if (!unpure && !pak->is_pure())
+ {
+ if ( fs_debug->integer == 2 )
+ Com_Printf(S_COLOR_GREEN "Ugh-oh %s found in unpure pk3\n", filename);
+
+ *file = 0;
+ return -1;
+ }
+
+ len = strlen(filename);
+
+ if (!(pak->referenced & FS_GENERAL_REF))
+ {
+ if ( !FS_IsExt(filename, ".shader", len)
+ && !FS_IsExt(filename, ".mtr", len)
+ && !FS_IsExt(filename, ".txt", len)
+ && !FS_IsExt(filename, ".cfg", len)
+ && !FS_IsExt(filename, ".config", len)
+ && !FS_IsExt(filename, ".arena", len)
+ && !FS_IsExt(filename, ".menu", len)
+ && !strstr(filename, "levelshots") )
+ {
+ pak->referenced |= FS_GENERAL_REF;
+ }
+ }
+
+ if (strstr(filename, "cgame.qvm"))
+ pak->referenced |= FS_CGAME_REF;
+
+ if (strstr(filename, "ui.qvm"))
+ pak->referenced |= FS_UI_REF;
+
+ if (uniqueFILE)
+ {
+ fsh[*file].handleFiles.file.z = unzOpen(pak->pakFilename);
+ if ( !fsh[*file].handleFiles.file.z )
+ Com_Error(ERR_FATAL, "Couldn't open %s", pak->pakFilename);
+ }
+ else
+ {
+ fsh[*file].handleFiles.file.z = pak->handle;
+ }
+
+ Q_strncpyz(fsh[*file].name, filename, sizeof(fsh[*file].name));
+ fsh[*file].zipFile = true;
+
+ // set the file position in the zip file (also sets the current file info)
+ unzSetOffset(fsh[*file].handleFiles.file.z, pakfile->pos);
+
+ // open the file in the zip
+ unzOpenCurrentFile(fsh[*file].handleFiles.file.z);
+ fsh[*file].zipFilePos = pakfile->pos;
+ fsh[*file].zipFileLen = pakfile->len;
+
+ if ( fs_debug->integer )
+ {
+ Com_Printf( "FS_FOpenFileRead: %s (found in '%s')\n",
+ filename, pak->pakFilename);
+ }
+
+ return pakfile->len;
+ }
+ }
+ else if (search->dir)
+ {
+ // check a file in the directory tree
+
+ // if we are running restricted, the only files we
+ // will allow to come from the directory are .cfg files
+ len = strlen(filename);
+ // FIXME TTimo I'm not sure about the fs_numServerPaks test
+ // if you are using FS_ReadFile to find out if a file exists,
+ // this test can make the search fail although the file is in the directory
+ // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
+ // turned out I used FS_FileExists instead
+ if (!unpure && fs_numServerPaks)
+ {
+ if (!FS_IsExt(filename, ".cfg", len) && // for config files
+ !FS_IsExt(filename, ".lua", len) && // lua
+ !FS_IsExt(filename, ".menu", len) && // menu files
+ !FS_IsExt(filename, ".game", len) && // menu files
+ !FS_IsExt(filename, ".dat", len) && // for journal files
+ !FS_IsDemoExt(filename)) // demos
+ {
+ *file = 0;
+ return -1;
+ }
+ }
+
+ dir = search->dir;
+
+ netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename);
+ filep = Sys_FOpen(netpath, "rb");
+
+ if (filep == nullptr)
+ {
+ *file = 0;
+ return -1;
+ }
+
+ Q_strncpyz(fsh[*file].name, filename, sizeof(fsh[*file].name));
+ fsh[*file].zipFile = false;
+
+ if (fs_debug->integer)
+ {
+ Com_Printf("FS_FOpenFileRead: %s (found in '%s%c%s')\n",
+ filename, dir->path, PATH_SEP, dir->gamedir);
+ }
+
+ fsh[*file].handleFiles.file.o = filep;
+ return FS_fplength(filep);
+ }
+
+ *file = 0;
+ return -1;
+}
+
+/*
+===========
+FS_FOpenFileRead
+
+Finds the file in the search path.
+Returns filesize and an open FILE pointer.
+Used for streaming data out of either a
+separate file or a ZIP file.
+===========
+*/
+long FS_FOpenFileRead(const char *filename, fileHandle_t *file, bool uniqueFILE)
+{
+ searchpath_t *search;
+ long len;
+
+ if (!fs_searchpaths) Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+
+ bool isLocalConfig = !strcmp(filename, "autoexec.cfg") || !strcmp(filename, Q3CONFIG_CFG);
+ for (search = fs_searchpaths; search; search = search->next)
+ {
+ // autoexec.cfg and q3config.cfg can only be loaded outside of pk3 files.
+ if (isLocalConfig && search->pack) continue;
+
+ len = FS_FOpenFileReadDir(filename, search, file, uniqueFILE, false);
+
+ if (file == nullptr)
+ {
+ if (len > 0) return len;
+ }
+ else
+ {
+ if (len >= 0 && *file) return len;
+ }
+ }
+
+#ifdef FS_MISSING
+ if (missingFiles) fprintf(missingFiles, "%s\n", filename);
+#endif
+
+ if (file)
+ {
+ *file = 0;
+ return -1;
+ }
+ else
+ {
+ // When file is nullptr, we're querying the existance of the file
+ // If we've got here, it doesn't exist
+ return 0;
+ }
+}
+
+/*
+=================
+FS_FindVM
+
+Find a suitable VM file in search path order.
+
+In each searchpath try:
+ - open DLL file if DLL loading enabled
+ - open QVM file
+
+Enable search for DLL by setting enableDll to FSVM_ENABLEDLL
+
+write found DLL or QVM to "found" and return VMI_NATIVE if DLL, VMI_COMPILED if QVM
+Return the searchpath in "startSearch".
+=================
+*/
+
+int FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, int enableDll)
+{
+ searchpath_t *search, *lastSearch;
+ directory_t *dir;
+ pack_t *pack;
+ char dllName[MAX_OSPATH], qvmName[MAX_OSPATH];
+ char *netpath;
+
+ if (!fs_searchpaths) Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+
+ if (enableDll) Com_sprintf(dllName, sizeof(dllName), "%s" DLL_EXT, name);
+
+ Com_sprintf(qvmName, sizeof(qvmName), "vm/%s.qvm", name);
+
+ lastSearch = static_cast<searchpath_t *>(*startSearch);
+ if (*startSearch == nullptr)
+ search = fs_searchpaths;
+ else
+ search = lastSearch->next;
+
+ while (search)
+ {
+ if (search->dir && (!fs_numServerPaks || !strcmp(name, "game")))
+ {
+ dir = search->dir;
+
+ if (enableDll)
+ {
+ netpath = FS_BuildOSPath(dir->path, dir->gamedir, dllName);
+
+ if (FS_FileInPathExists(netpath))
+ {
+ Q_strncpyz(found, netpath, foundlen);
+ *startSearch = search;
+
+ return VMI_NATIVE;
+ }
+ }
+
+ if (FS_FOpenFileReadDir(qvmName, search, nullptr, false, false) > 0)
+ {
+ *startSearch = search;
+ return VMI_COMPILED;
+ }
+ }
+ else if (search->pack)
+ {
+ pack = search->pack;
+
+ if (lastSearch && lastSearch->pack)
+ {
+ // make sure we only try loading one VM file per game dir
+ // i.e. if VM from pak7.pk3 fails we won't try one from pak6.pk3
+
+ if (!FS_FilenameCompare(lastSearch->pack->pakPathname, pack->pakPathname))
+ {
+ search = search->next;
+ continue;
+ }
+ }
+
+ if (FS_FOpenFileReadDir(qvmName, search, nullptr, false, false) > 0)
+ {
+ *startSearch = search;
+
+ return VMI_COMPILED;
+ }
+ }
+
+ search = search->next;
+ }
+
+ return -1;
+}
+
+int FS_Read(void *buffer, int len, fileHandle_t f)
+{
+ int block, remaining;
+ int read;
+ byte *buf;
+ int tries;
+
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ if (!f)
+ {
+ return 0;
+ }
+
+ buf = (byte *)buffer;
+ fs_readCount += len;
+
+ if (fsh[f].zipFile == false)
+ {
+ remaining = len;
+ tries = 0;
+ while (remaining)
+ {
+ block = remaining;
+ read = fread(buf, 1, block, fsh[f].handleFiles.file.o);
+ if (read == 0)
+ {
+ // we might have been trying to read from a CD, which
+ // sometimes returns a 0 read on windows
+ if (!tries)
+ {
+ tries = 1;
+ }
+ else
+ {
+ return len - remaining; // Com_Error (ERR_FATAL, "FS_Read: 0 bytes read");
+ }
+ }
+
+ if (read == -1)
+ {
+ Com_Error(ERR_FATAL, "FS_Read: -1 bytes read");
+ }
+
+ remaining -= read;
+ buf += read;
+ }
+ return len;
+ }
+ else
+ {
+ return unzReadCurrentFile(fsh[f].handleFiles.file.z, buffer, len);
+ }
+}
+
+/*
+=================
+FS_Write
+
+Properly handles partial writes
+=================
+*/
+int FS_Write(const void *buffer, int len, fileHandle_t h)
+{
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ if (!h)
+ {
+ return 0;
+ }
+
+ FILE *f = FS_FileForHandle(h);
+ byte *buf = (byte *)buffer;
+
+ int remaining = len;
+ int tries = 0;
+ while (remaining)
+ {
+ int block = remaining;
+ int written = fwrite(buf, 1, block, f);
+ if (written == 0)
+ {
+ if (!tries)
+ {
+ tries = 1;
+ }
+ else
+ {
+ Com_Printf("FS_Write: 0 bytes written\n");
+ return 0;
+ }
+ }
+
+ if (written == -1)
+ {
+ Com_Printf("FS_Write: -1 bytes written\n");
+ return 0;
+ }
+
+ remaining -= written;
+ buf += written;
+ }
+
+ if (fsh[h].handleSync)
+ {
+ fflush(f);
+ }
+ return len;
+}
+
+void QDECL FS_Printf(fileHandle_t h, const char *fmt, ...)
+{
+ va_list argptr;
+ char msg[MAXPRINTMSG];
+
+ va_start(argptr, fmt);
+ Q_vsnprintf(msg, sizeof(msg), fmt, argptr);
+ va_end(argptr);
+
+ FS_Write(msg, strlen(msg), h);
+}
+
+#define PK3_SEEK_BUFFER_SIZE 65536
+
+/*
+=================
+FS_Seek
+
+=================
+*/
+int FS_Seek(fileHandle_t f, long offset, enum FS_Origin origin)
+{
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ return -1;
+ }
+
+ if (fsh[f].zipFile == true)
+ {
+ // FIXME: this is really, really crappy
+ //(but better than what was here before)
+ byte buffer[PK3_SEEK_BUFFER_SIZE];
+ int remainder;
+ int currentPosition = FS_FTell(f);
+
+ // change negative offsets into FS_SEEK_SET
+ if (offset < 0)
+ {
+ switch (origin)
+ {
+ case FS_SEEK_END:
+ remainder = fsh[f].zipFileLen + offset;
+ break;
+
+ case FS_SEEK_CUR:
+ remainder = currentPosition + offset;
+ break;
+
+ case FS_SEEK_SET:
+ default:
+ remainder = 0;
+ break;
+ }
+
+ if (remainder < 0)
+ {
+ remainder = 0;
+ }
+
+ origin = FS_SEEK_SET;
+ }
+ else
+ {
+ if (origin == FS_SEEK_END)
+ {
+ remainder = fsh[f].zipFileLen - currentPosition + offset;
+ }
+ else
+ {
+ remainder = offset;
+ }
+ }
+
+ switch (origin)
+ {
+ case FS_SEEK_SET:
+ if (remainder == currentPosition)
+ {
+ return offset;
+ }
+ unzSetOffset(fsh[f].handleFiles.file.z, fsh[f].zipFilePos);
+ unzOpenCurrentFile(fsh[f].handleFiles.file.z);
+ // fallthrough
+
+ case FS_SEEK_END: // fall through
+ case FS_SEEK_CUR:
+ while (remainder > PK3_SEEK_BUFFER_SIZE)
+ {
+ FS_Read(buffer, PK3_SEEK_BUFFER_SIZE, f);
+ remainder -= PK3_SEEK_BUFFER_SIZE;
+ }
+ FS_Read(buffer, remainder, f);
+ return offset;
+
+ default:
+ Com_Error(ERR_FATAL, "Bad origin in FS_Seek");
+ return -1;
+ }
+ }
+ else
+ {
+ FILE *file;
+ file = FS_FileForHandle(f);
+ int _origin;
+ switch (origin)
+ {
+ case FS_SEEK_CUR:
+ _origin = SEEK_CUR;
+ break;
+ case FS_SEEK_END:
+ _origin = SEEK_END;
+ break;
+ case FS_SEEK_SET:
+ _origin = SEEK_SET;
+ break;
+ default:
+ Com_Error(ERR_FATAL, "Bad origin in FS_Seek");
+ break;
+ }
+
+ return fseek(file, offset, _origin);
+ }
+}
+
+/*
+======================================================================================
+
+CONVENIENCE FUNCTIONS FOR ENTIRE FILES
+
+======================================================================================
+*/
+
+int FS_FileIsInPAK_A(bool alternate, const char *filename, int *pChecksum)
+{
+ if (!fs_searchpaths)
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+
+ if (!filename)
+ Com_Error(ERR_FATAL, "FS_FOpenFileRead: nullptr 'filename' parameter passed");
+
+ // qpaths are not supposed to have a leading slash
+ if (filename[0] == '/' || filename[0] == '\\')
+ filename++;
+
+ // make absolutely sure that it can't back up the path.
+ // The searchpaths do guarantee that something will always
+ // be prepended, so we don't need to worry about "c:" or "//limbo"
+ if (strstr(filename, "..") || strstr(filename, "::"))
+ return -1;
+
+ //
+ // search through the path, one element at a time
+ //
+ for (auto search = fs_searchpaths; search; search = search->next)
+ {
+ if (!search->pack)
+ continue;
+
+ // disregard if it doesn't match one of the allowed pure pak files
+ if (!search->pack->is_pure())
+ continue;
+
+ if ((alternate && search->pack->onlyPrimary) ||
+ (!alternate && search->pack->onlyAlternate))
+ continue;
+
+ auto found = search->pack->find(filename);
+ if (found)
+ {
+ if (pChecksum)
+ *pChecksum = search->pack->pure_checksum;
+
+ return 1;
+ }
+ }
+ return -1;
+}
+
+int FS_FileIsInPAK(const char *filename, int *pChecksum)
+{
+ return FS_FileIsInPAK_A(false, filename, pChecksum);
+}
+/*
+============
+FS_ReadFileDir
+
+Filename are relative to the quake search path
+a null buffer will just return the file length without loading
+If searchPath is non-nullptr search only in that specific search path
+============
+*/
+long FS_ReadFileDir(const char *qpath, void *searchPath, bool unpure, void **buffer)
+{
+ fileHandle_t h;
+ byte *buf;
+ bool isConfig;
+ long len;
+
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ if (!qpath || !qpath[0])
+ {
+ Com_Error(ERR_FATAL, "FS_ReadFile with empty name");
+ }
+
+ buf = nullptr; // quiet compiler warning
+
+ // if this is a .cfg file and we are playing back a journal, read
+ // it from the journal file
+ if (strstr(qpath, ".cfg"))
+ {
+ isConfig = true;
+ if (com_journal && com_journal->integer == 2)
+ {
+ Com_DPrintf("Loading %s from journal file.\n", qpath);
+
+ int r = FS_Read(&len, sizeof(len), com_journalDataFile);
+ if (r != sizeof(len))
+ {
+ if (buffer != nullptr) *buffer = nullptr;
+ return -1;
+ }
+
+ // if the file didn't exist when the journal was created
+ if (!len)
+ {
+ if (buffer == nullptr)
+ {
+ return 1; // hack for old journal files
+ }
+ *buffer = nullptr;
+ return -1;
+ }
+
+ if (buffer == nullptr)
+ {
+ return len;
+ }
+
+ buf = static_cast<byte *>(Hunk_AllocateTempMemory(len + 1));
+ *buffer = buf;
+
+ r = FS_Read(buf, len, com_journalDataFile);
+ if (r != len)
+ {
+ Com_Error(ERR_FATAL, "Read from journalDataFile failed");
+ }
+
+ fs_loadCount++;
+ fs_loadStack++;
+
+ // guarantee that it will have a trailing 0 for string operations
+ buf[len] = 0;
+
+ return len;
+ }
+ }
+ else
+ {
+ isConfig = false;
+ }
+
+ searchpath_t *search = static_cast<searchpath_t *>(searchPath);
+ if (search == nullptr)
+ {
+ // look for it in the filesystem or pack files
+ len = FS_FOpenFileRead(qpath, &h, false);
+ }
+ else
+ {
+ // look for it in a specific search path only
+ len = FS_FOpenFileReadDir(qpath, search, &h, false, unpure);
+ }
+
+ if (h == 0)
+ {
+ if (buffer)
+ {
+ *buffer = nullptr;
+ }
+ // if we are journalling and it is a config file, write a zero to the journal file
+ if (isConfig && com_journal && com_journal->integer == 1)
+ {
+ Com_DPrintf("Writing zero for %s to journal file.\n", qpath);
+ len = 0;
+ FS_Write(&len, sizeof(len), com_journalDataFile);
+ FS_Flush(com_journalDataFile);
+ }
+ return -1;
+ }
+
+ if (!buffer)
+ {
+ if (isConfig && com_journal && com_journal->integer == 1)
+ {
+ Com_DPrintf("Writing len for %s to journal file.\n", qpath);
+ FS_Write(&len, sizeof(len), com_journalDataFile);
+ FS_Flush(com_journalDataFile);
+ }
+ FS_FCloseFile(h);
+ return len;
+ }
+
+ fs_loadCount++;
+ fs_loadStack++;
+
+ buf = static_cast<byte *>(Hunk_AllocateTempMemory(len + 1));
+ *buffer = buf;
+
+ FS_Read(buf, len, h);
+
+ // guarantee that it will have a trailing 0 for string operations
+ buf[len] = 0;
+ FS_FCloseFile(h);
+
+ // if we are journalling and it is a config file, write it to the journal file
+ if (isConfig && com_journal && com_journal->integer == 1)
+ {
+ Com_DPrintf("Writing %s to journal file.\n", qpath);
+ FS_Write(&len, sizeof(len), com_journalDataFile);
+ FS_Write(buf, len, com_journalDataFile);
+ FS_Flush(com_journalDataFile);
+ }
+ return len;
+}
+
+/*
+============
+FS_ReadFile
+
+Filename are relative to the quake search path
+a null buffer will just return the file length without loading
+============
+*/
+long FS_ReadFile(const char *qpath, void **buffer)
+{
+ return FS_ReadFileDir(qpath, nullptr, false, buffer);
+}
+/*
+=============
+FS_FreeFile
+=============
+*/
+void FS_FreeFile(void *buffer)
+{
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+ if (!buffer)
+ {
+ Com_Error(ERR_FATAL, "FS_FreeFile( nullptr )");
+ }
+
+ fs_loadStack--;
+ Hunk_FreeTempMemory(buffer);
+
+ // if all of our temp files are free, clear all of our space
+ if (fs_loadStack == 0)
+ {
+ Hunk_ClearTempMemory();
+ }
+}
+
+/*
+============
+FS_WriteFile
+
+Filename are relative to the quake search path
+============
+*/
+void FS_WriteFile(const char *qpath, const void *buffer, int size)
+{
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ if (!qpath || !buffer)
+ {
+ Com_Error(ERR_FATAL, "FS_WriteFile: nullptr parameter");
+ }
+
+ fileHandle_t f = FS_FOpenFileWrite(qpath);
+ if (!f)
+ {
+ Com_Printf("Failed to open %s\n", qpath);
+ return;
+ }
+
+ FS_Write(buffer, size, f);
+ FS_FCloseFile(f);
+}
+
+/*
+==========================================================================
+
+ZIP FILE LOADING
+
+==========================================================================
+*/
+
+/*
+=================
+FS_LoadZipFile
+
+Creates a new pack_t in the search chain for the contents of a zip file.
+=================
+*/
+static pack_t *FS_LoadZipFile(const char *zipfile, const char *basename)
+{
+ int fs_numHeaderLongs = 0;
+ unsigned long len = 0;
+ char filename[MAX_ZPATH];
+
+ auto z = unzOpen(zipfile);
+
+ unz_global_info gi;
+ int err = unzGetGlobalInfo(z, &gi);
+ if (err) return nullptr;
+
+ err = unzGoToFirstFile(z);
+ if (err) return nullptr;
+
+ for (uLong i = 0; i < gi.number_entry; i++)
+ {
+ unz_file_info fi;
+ err = unzGetCurrentFileInfo(
+ z, &fi, filename, sizeof(filename), nullptr, 0, nullptr, 0);
+
+ if (err) break;
+
+ len += strlen(filename) + 1;
+ unzGoToNextFile(z);
+ }
+
+ fileInPack_t *buildBuffer =
+ static_cast<fileInPack_t *>(Z_Malloc((gi.number_entry * sizeof(fileInPack_t)) + len));
+
+ char *namePtr = ((char *)buildBuffer) + gi.number_entry * sizeof(fileInPack_t);
+
+ int *fs_headerLongs = static_cast<int *>(Z_Malloc((gi.number_entry + 1) * sizeof(int)));
+
+ fs_headerLongs[fs_numHeaderLongs] = LittleLong(fs_checksumFeed);
+ fs_numHeaderLongs++;
+
+ // get the hash table size from the number of files in the zip
+ // because lots of custom pk3 files have less than 32 or 64 files
+ uLong hashsiz;
+ for (hashsiz = 1; hashsiz <= MAX_FILEHASH_SIZE; hashsiz <<= 1)
+ {
+ if (hashsiz > gi.number_entry) break;
+ }
+
+ pack_t *pack = static_cast<pack_t *>(Z_Malloc(sizeof(pack_t) + hashsiz * sizeof(fileInPack_t *)));
+
+ pack->hashSize = hashsiz;
+ pack->hashTable = (fileInPack_t **)(((char *)pack) + sizeof(pack_t));
+
+ for (int i = 0; i < pack->hashSize; i++)
+ {
+ pack->hashTable[i] = nullptr;
+ }
+
+ Q_strncpyz(pack->pakFilename, zipfile, sizeof(pack->pakFilename));
+ Q_strncpyz(pack->pakBasename, basename, sizeof(pack->pakBasename));
+
+ // strip .pk3 if needed
+ if ( strlen(pack->pakBasename) > 4 &&
+ !Q_stricmp(pack->pakBasename + strlen(pack->pakBasename) - 4, ".pk3"))
+ {
+ pack->pakBasename[strlen(pack->pakBasename) - 4] = '\0';
+ }
+
+ pack->handle = z;
+ pack->numfiles = gi.number_entry;
+ unzGoToFirstFile(z);
+ for (uLong i = 0; i < gi.number_entry; i++)
+ {
+ unz_file_info fi;
+ err = unzGetCurrentFileInfo(
+ z, &fi, filename, sizeof(filename), nullptr, 0, nullptr, 0);
+
+ if (err) break;
+
+ if (fi.uncompressed_size)
+ {
+ fs_headerLongs[fs_numHeaderLongs] = LittleLong(fi.crc);
+ fs_numHeaderLongs++;
+ }
+
+ Q_strlwr(filename);
+ long hash = FS_HashFileName(filename, pack->hashSize);
+
+ buildBuffer[i].name = namePtr;
+ strcpy(buildBuffer[i].name, filename);
+ namePtr += strlen(filename) + 1;
+
+ // store the file position in the zip
+ buildBuffer[i].pos = unzGetOffset(z);
+ buildBuffer[i].len = fi.uncompressed_size;
+ buildBuffer[i].next = pack->hashTable[hash];
+
+ pack->hashTable[hash] = &buildBuffer[i];
+ unzGoToNextFile(z);
+ }
+
+ pack->checksum =
+ Com_BlockChecksum(&fs_headerLongs[1], sizeof(*fs_headerLongs) * (fs_numHeaderLongs - 1));
+ pack->pure_checksum =
+ Com_BlockChecksum(fs_headerLongs, sizeof(*fs_headerLongs) * fs_numHeaderLongs);
+ pack->checksum = LittleLong(pack->checksum);
+ pack->pure_checksum = LittleLong(pack->pure_checksum);
+
+ Z_Free(fs_headerLongs);
+
+ pack->buildBuffer = buildBuffer;
+ return pack;
+}
+
+/*
+=================
+FS_FreePak
+
+Frees a pak structure and releases all associated resources
+=================
+*/
+
+static void FS_FreePak(pack_t *thepak)
+{
+ unzClose(thepak->handle);
+ Z_Free(thepak->buildBuffer);
+ Z_Free(thepak);
+}
+
+/*
+=================
+FS_GetZipChecksum
+
+Compares whether the given pak file matches a referenced checksum
+=================
+*/
+bool FS_CompareZipChecksum(const char *zipfile)
+{
+ pack_t *thepak = FS_LoadZipFile(zipfile, "");
+
+ if (!thepak) return false;
+
+ int checksum = thepak->checksum;
+ FS_FreePak(thepak);
+
+ for (int i = 0; i < fs_numServerReferencedPaks; i++)
+ {
+ if (checksum == fs_serverReferencedPaks[i]) return true;
+ }
+
+ return false;
+}
+
+/*
+=================================================================================
+
+DIRECTORY SCANNING FUNCTIONS
+
+=================================================================================
+*/
+
+#define MAX_FOUND_FILES 0x1000
+
+static int FS_ReturnPath(const char *zname, char *zpath, int *depth)
+{
+ int newdep = 0;
+ int len = 0;
+ int at = 0;
+ zpath[0] = 0;
+
+ while (zname[at] != 0)
+ {
+ if (zname[at] == '/' || zname[at] == '\\')
+ {
+ len = at;
+ newdep++;
+ }
+ at++;
+ }
+ strcpy(zpath, zname);
+ zpath[len] = 0;
+ *depth = newdep;
+
+ return len;
+}
+
+/*
+==================
+FS_AddFileToList
+==================
+*/
+static int FS_AddFileToList(char *name, char *list[MAX_FOUND_FILES], int nfiles)
+{
+ if (nfiles == MAX_FOUND_FILES - 1)
+ {
+ return nfiles;
+ }
+
+ for (int i = 0; i < nfiles; i++)
+ {
+ if (!Q_stricmp(name, list[i]))
+ {
+ return nfiles; // allready in list
+ }
+ }
+ list[nfiles] = CopyString(name);
+ nfiles++;
+
+ return nfiles;
+}
+
+/*
+===============
+FS_ListFilteredFiles
+
+Returns a uniqued list of files that match the given criteria
+from all search paths
+===============
+*/
+char **FS_ListFilteredFiles(const char *path, const char *extension, const char *filter,
+ int *numfiles, bool allowNonPureFilesOnDisk)
+{
+ int nfiles;
+ char **listCopy;
+ char *list[MAX_FOUND_FILES];
+ searchpath_t *search;
+ int i;
+ int pathLength;
+ int extensionLength;
+ int length, pathDepth, temp;
+ pack_t *pak;
+ fileInPack_t *buildBuffer;
+ char zpath[MAX_ZPATH];
+
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ if (!path)
+ {
+ *numfiles = 0;
+ return nullptr;
+ }
+ if (!extension)
+ {
+ extension = "";
+ }
+
+ pathLength = strlen(path);
+ if (path[pathLength - 1] == '\\' || path[pathLength - 1] == '/')
+ {
+ pathLength--;
+ }
+ extensionLength = strlen(extension);
+ nfiles = 0;
+ FS_ReturnPath(path, zpath, &pathDepth);
+
+ //
+ // search through the path, one element at a time, adding to list
+ //
+ for (search = fs_searchpaths; search; search = search->next)
+ {
+ // is the element a pak file?
+ if (search->pack)
+ {
+ // ZOID: If we are pure, don't search for files on paks that
+ // aren't on the pure list
+ if (!search->pack->is_pure())
+ {
+ continue;
+ }
+
+ // look through all the pak file elements
+ pak = search->pack;
+ buildBuffer = pak->buildBuffer;
+ for (i = 0; i < pak->numfiles; i++)
+ {
+ char *name;
+ int zpathLen, depth;
+
+ // check for directory match
+ name = buildBuffer[i].name;
+ //
+ if (filter)
+ {
+ // case insensitive
+ if (!Com_FilterPath(filter, name, false)) continue;
+ // unique the match
+ nfiles = FS_AddFileToList(name, list, nfiles);
+ }
+ else
+ {
+ zpathLen = FS_ReturnPath(name, zpath, &depth);
+
+ if ((depth - pathDepth) > 2 || pathLength > zpathLen ||
+ Q_stricmpn(name, path, pathLength))
+ {
+ continue;
+ }
+
+ // check for extension match
+ length = strlen(name);
+ if (length < extensionLength)
+ {
+ continue;
+ }
+
+ if (Q_stricmp(name + length - extensionLength, extension))
+ {
+ continue;
+ }
+ // unique the match
+
+ temp = pathLength;
+ if (pathLength)
+ {
+ temp++; // include the '/'
+ }
+ nfiles = FS_AddFileToList(name + temp, list, nfiles);
+ }
+ }
+ }
+ else if (search->dir)
+ { // scan for files in the filesystem
+
+ // don't scan directories for files if we are pure or restricted
+ if (fs_numServerPaks && !allowNonPureFilesOnDisk)
+ {
+ continue;
+ }
+ else
+ {
+ int numSysFiles;
+ char *netpath = FS_BuildOSPath(search->dir->path, search->dir->gamedir, path);
+ char **sysFiles = Sys_ListFiles(netpath, extension, filter, &numSysFiles, false);
+ for (i = 0; i < numSysFiles; i++)
+ {
+ // unique the match
+ char *name = sysFiles[i];
+ nfiles = FS_AddFileToList(name, list, nfiles);
+ }
+ Sys_FreeFileList(sysFiles);
+ }
+ }
+ }
+
+ // return a copy of the list
+ *numfiles = nfiles;
+
+ if (!nfiles)
+ {
+ return nullptr;
+ }
+
+ listCopy = static_cast<char **>(Z_Malloc((nfiles + 1) * sizeof(*listCopy)));
+ for (i = 0; i < nfiles; i++)
+ {
+ listCopy[i] = list[i];
+ }
+ listCopy[i] = nullptr;
+
+ return listCopy;
+}
+
+/*
+=================
+FS_ListFiles
+=================
+*/
+char **FS_ListFiles(const char *path, const char *extension, int *numfiles)
+{
+ return FS_ListFilteredFiles(path, extension, nullptr, numfiles, false);
+}
+
+/*
+=================
+FS_FreeFileList
+=================
+*/
+void FS_FreeFileList(char **list)
+{
+ if (!fs_searchpaths)
+ {
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+ }
+
+ if (!list)
+ {
+ return;
+ }
+
+ for (int i = 0; list[i]; i++)
+ {
+ Z_Free(list[i]);
+ }
+
+ Z_Free(list);
+}
+
+/*
+================
+FS_GetFileList
+================
+*/
+int FS_GetFileList(const char *path, const char *extension, char *listbuf, int bufsize)
+{
+ int nFiles = 0;
+ int nTotal = 0;
+ *listbuf = 0;
+
+ if (Q_stricmp(path, "$modlist") == 0)
+ {
+ return FS_GetModList(listbuf, bufsize);
+ }
+
+ char **pFiles = FS_ListFiles(path, extension, &nFiles);
+
+ for (int i = 0; i < nFiles; i++)
+ {
+ int nLen = strlen(pFiles[i]) + 1;
+ if (nTotal + nLen + 1 < bufsize)
+ {
+ strcpy(listbuf, pFiles[i]);
+ listbuf += nLen;
+ nTotal += nLen;
+ }
+ else
+ {
+ nFiles = i;
+ break;
+ }
+ }
+
+ FS_FreeFileList(pFiles);
+
+ return nFiles;
+}
+
+/*
+================
+FS_GetFilteredFiles
+================
+*/
+int FS_GetFilteredFiles(
+ const char *path, const char *extension, const char *filter, char *listbuf, int bufsize)
+{
+ int nFiles = 0;
+ int nTotal = 0;
+ *listbuf = 0;
+
+ char **pFiles = FS_ListFilteredFiles(path, extension, filter, &nFiles, false);
+
+ for (int i = 0; i < nFiles; i++)
+ {
+ int nLen = strlen(pFiles[i]) + 1;
+ if (nTotal + nLen + 1 < bufsize)
+ {
+ strcpy(listbuf, pFiles[i]);
+ listbuf += nLen;
+ nTotal += nLen;
+ }
+ else
+ {
+ nFiles = i;
+ break;
+ }
+ }
+
+ FS_FreeFileList(pFiles);
+
+ return nFiles;
+}
+
+/*
+=======================
+Sys_ConcatenateFileLists
+
+mkv: Naive implementation. Concatenates three lists into a
+ new list, and frees the old lists from the heap.
+bk001129 - from cvs1.17 (mkv)
+
+FIXME TTimo those two should move to common.c next to Sys_ListFiles
+=======================
+ */
+static unsigned int Sys_CountFileList(char **list)
+{
+ unsigned int i = 0;
+ if (list)
+ {
+ while (*list)
+ {
+ list++;
+ i++;
+ }
+ }
+ return i;
+}
+
+static char **Sys_ConcatenateFileLists(char **list0, char **list1)
+{
+ char **cat, **dst;
+
+ int totalLength = 0;
+ totalLength += Sys_CountFileList(list0);
+ totalLength += Sys_CountFileList(list1);
+
+ /* Create new list. */
+ dst = cat = static_cast<char **>(Z_Malloc((totalLength + 1) * sizeof(char *)));
+
+ /* Copy over lists. */
+ if (list0)
+ {
+ for (char **src = list0; *src; src++, dst++) *dst = *src;
+ }
+
+ if (list1)
+ {
+ for (char **src = list1; *src; src++, dst++) *dst = *src;
+ }
+
+ // Terminate the list
+ *dst = nullptr;
+
+ // Free our old lists.
+ // NOTE: not freeing their content, it's been merged in dst and still being used
+ if (list0) Z_Free(list0);
+ if (list1) Z_Free(list1);
+
+ return cat;
+}
+
+/*
+================
+FS_GetModList
+
+Returns a list of mod directory names
+A mod directory is a peer to baseq3 with a pk3 or pk3dir in it
+================
+*/
+int FS_GetModList( char *listbuf, int bufsize )
+{
+ char * start = listbuf;
+ *listbuf = '\0';
+
+ // paths to search for mods
+ const char * const paths[] = {
+ fs_basepath->string,
+ fs_homepath->string
+ };
+
+ char **pFiles = nullptr;
+ for (int i = 0; i < ARRAY_LEN(paths); i++)
+ {
+ int dummy;
+ char **pFiles0 = Sys_ListFiles(paths[i], NULL, NULL, &dummy, true);
+ pFiles = Sys_ConcatenateFileLists(pFiles, pFiles0);
+ }
+
+ int nMods = 0;
+ int nTotal = 0;
+ for (int i = 0; i < Sys_CountFileList(pFiles); i++)
+ {
+ const char* name = pFiles[i];
+
+ if ( name[0] == '.' )
+ continue;
+
+ // In order to be a valid mod the directory must contain at least one
+ // .pk3 or .pk3dir we didn't keep the information when we merged the
+ // directory names, as to what OS Path it was found under so we will
+ // try each of them here.
+ int nPaks = 0;
+ int nPakDirs = 0;
+ for (int j = 0; j < ARRAY_LEN(paths); j++)
+ {
+ const char* path = FS_BuildOSPath(paths[j], name, "");
+ int nDirs = 0;
+
+ char **pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, false);
+ char **pDirs = Sys_ListFiles(path, "/", NULL, &nDirs, false);
+ for (int k = 0; k < nDirs; k++)
+ {
+ // we only want to count directories ending with ".pk3dir"
+ if (FS_IsExt(pDirs[k], ".pk3dir", strlen(pDirs[k])))
+ nPakDirs++;
+ }
+
+ // we only use Sys_ListFiles to check whether files are present
+ Sys_FreeFileList(pPaks);
+ Sys_FreeFileList(pDirs);
+
+ if (nPaks > 0 || nPakDirs > 0)
+ break;
+ }
+
+ if (nPaks > 0 || nPakDirs > 0)
+ {
+ size_t nLen = strlen(name) + 1;
+
+ if (nTotal + nLen + 1 < bufsize)
+ {
+ strcpy(listbuf, name);
+ listbuf += nLen;
+ nTotal += nLen;
+ nMods++;
+ }
+ else
+ {
+ Com_Printf(S_COLOR_RED "Warning: Too many mods!\n");
+ break;
+ }
+ }
+ }
+
+ Sys_FreeFileList( pFiles );
+ return nMods;
+}
+
+//============================================================================
+
+/*
+================
+FS_Dir_f
+================
+*/
+void FS_Dir_f(void)
+{
+ const char *path;
+ const char *extension;
+
+ if (Cmd_Argc() < 2 || Cmd_Argc() > 3)
+ {
+ Com_Printf("usage: dir <directory> [extension]\n");
+ return;
+ }
+
+ if (Cmd_Argc() == 2)
+ {
+ path = Cmd_Argv(1);
+ extension = "";
+ }
+ else
+ {
+ path = Cmd_Argv(1);
+ extension = Cmd_Argv(2);
+ }
+
+ Com_Printf("Directory of %s %s\n", path, extension);
+ Com_Printf("---------------\n");
+
+ int ndirs;
+ char **dirnames = FS_ListFiles(path, extension, &ndirs);
+
+ for (int i = 0; i < ndirs; i++)
+ {
+ Com_Printf("%s\n", dirnames[i]);
+ }
+ FS_FreeFileList(dirnames);
+}
+
+/*
+===========
+FS_ConvertPath
+===========
+*/
+void FS_ConvertPath(char *s)
+{
+ while (*s)
+ {
+ if (*s == '\\' || *s == ':')
+ {
+ *s = '/';
+ }
+ s++;
+ }
+}
+
+/*
+===========
+FS_PathCmp
+
+Ignore case and seprator char distinctions
+===========
+*/
+int FS_PathCmp(const char *s1, const char *s2)
+{
+ int c1, c2;
+
+ do
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (c1 >= 'a' && c1 <= 'z')
+ {
+ c1 -= ('a' - 'A');
+ }
+ if (c2 >= 'a' && c2 <= 'z')
+ {
+ c2 -= ('a' - 'A');
+ }
+
+ if (c1 == '\\' || c1 == ':')
+ {
+ c1 = '/';
+ }
+ if (c2 == '\\' || c2 == ':')
+ {
+ c2 = '/';
+ }
+
+ if (c1 < c2)
+ {
+ return -1; // strings not equal
+ }
+ else if (c1 > c2)
+ {
+ return 1;
+ }
+ } while (c1);
+
+ return 0; // strings are equal
+}
+
+/*
+================
+FS_SortFileList
+================
+*/
+void FS_SortFileList(char **filelist, int numfiles)
+{
+ char **sortedlist = static_cast<char **>(Z_Malloc((numfiles + 1) * sizeof(*sortedlist)));
+ sortedlist[0] = nullptr;
+
+ int numsortedfiles = 0;
+ for (int i = 0; i < numfiles; i++)
+ {
+ int j;
+ for (j = 0; j < numsortedfiles; j++)
+ {
+ if (FS_PathCmp(filelist[i], sortedlist[j]) < 0) break;
+ }
+
+ int k;
+ for (k = numsortedfiles; k > j; k--)
+ {
+ sortedlist[k] = sortedlist[k - 1];
+ }
+
+ sortedlist[j] = filelist[i];
+ numsortedfiles++;
+ }
+ ::memcpy(filelist, sortedlist, numfiles * sizeof(*filelist));
+ Z_Free(sortedlist);
+}
+
+/*
+================
+FS_NewDir_f
+================
+*/
+void FS_NewDir_f(void)
+{
+ if (Cmd_Argc() < 2)
+ {
+ Com_Printf("usage: fdir <filter>\n");
+ Com_Printf("example: fdir *q3dm*.bsp\n");
+ return;
+ }
+
+ Com_Printf("---------------\n");
+
+ const char *filter = Cmd_Argv(1);
+
+ int ndirs;
+ char **dirnames = FS_ListFilteredFiles("", "", filter, &ndirs, false);
+
+ FS_SortFileList(dirnames, ndirs);
+ for (int i = 0; i < ndirs; i++)
+ {
+ FS_ConvertPath(dirnames[i]);
+ Com_Printf("%s\n", dirnames[i]);
+ }
+ Com_Printf("%d files listed\n", ndirs);
+ FS_FreeFileList(dirnames);
+}
+
+/*
+============
+FS_Path_f
+
+============
+*/
+void FS_Path_f(void)
+{
+ Com_Printf("We are looking in the current search path:\n");
+
+ for (auto s = fs_searchpaths; s; s = s->next)
+ {
+ if (s->pack)
+ {
+ Com_Printf("%s (%i files%s)\n",
+ s->pack->pakFilename,
+ s->pack->numfiles,
+ s->pack->onlyPrimary ? ", not for 1.1"
+ : s->pack->onlyAlternate ? ", only for 1.1" : "");
+
+ if (s->pack->primaryVersion)
+ Com_Printf(" (the 1.1 version of %s)\n",
+ s->pack->primaryVersion->pakFilename);
+
+ if (fs_numServerPaks)
+ {
+ if (!s->pack->is_pure())
+ {
+ Com_Printf(" not on the pure list\n");
+ }
+ else
+ {
+ Com_Printf(" on the pure list\n");
+ }
+ }
+ }
+ else
+ {
+ Com_Printf("%s%c%s\n", s->dir->path, PATH_SEP, s->dir->gamedir);
+ }
+ }
+
+ Com_Printf("\n");
+ for (int i = 1; i < MAX_FILE_HANDLES; i++)
+ {
+ if (fsh[i].handleFiles.file.o)
+ {
+ Com_Printf("handle %i: %s\n", i, fsh[i].name);
+ }
+ }
+}
+
+/*
+============
+FS_TouchFile_f
+============
+*/
+void FS_TouchFile_f(void)
+{
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf("Usage: touchFile <file>\n");
+ return;
+ }
+
+ fileHandle_t f;
+ FS_FOpenFileRead(Cmd_Argv(1), &f, false);
+ if (f)
+ {
+ FS_FCloseFile(f);
+ }
+}
+
+/*
+============
+FS_Which
+============
+*/
+
+bool FS_Which(const char *filename, void *searchPath)
+{
+ searchpath_t *search = static_cast<searchpath_t *>(searchPath);
+
+ if (FS_FOpenFileReadDir(filename, search, nullptr, false, false) > 0)
+ {
+ if (search->pack)
+ {
+ Com_Printf("File \"%s\" found in \"%s\"\n", filename, search->pack->pakFilename);
+ return true;
+ }
+ else if (search->dir)
+ {
+ Com_Printf("File \"%s\" found at \"%s\"\n", filename, search->dir->fullpath);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*
+============
+FS_Which_f
+============
+*/
+void FS_Which_f(void)
+{
+ const char *filename = Cmd_Argv(1);
+
+ if (!filename[0])
+ {
+ Com_Printf("Usage: which <file>\n");
+ return;
+ }
+
+ // qpaths are not supposed to have a leading slash
+ if (filename[0] == '/' || filename[0] == '\\') filename++;
+
+ // just wants to see if file is there
+ for (searchpath_t *search = fs_searchpaths; search; search = search->next)
+ if (FS_Which(filename, search)) return;
+
+ Com_Printf("File not found: \"%s\"\n", filename);
+}
+
+//===========================================================================
+
+static int QDECL paksort(const void *a, const void *b)
+{
+ char *aa = *(char **)a;
+ char *bb = *(char **)b;
+
+ return FS_PathCmp(aa, bb);
+}
+
+/*
+================
+FS_AddGameDirectory
+
+Sets fs_gamedir, adds the directory to the head of the path,
+then loads the zip headers
+================
+*/
+void FS_AddGameDirectory(const char *path, const char *dir)
+{
+ pack_t *pak;
+ char curpath[MAX_OSPATH + 1];
+ int numfiles;
+ char **pakfiles;
+ int pakfilesi;
+ char **pakfilestmp;
+ int numdirs;
+ char **pakdirs;
+ int pakdirsi;
+ char **pakdirstmp;
+
+ int lengths[10][2];
+
+ // Unique
+ for (searchpath_t *sp = fs_searchpaths; sp; sp = sp->next)
+ {
+ if (sp->dir && !Q_stricmp(sp->dir->path, path) && !Q_stricmp(sp->dir->gamedir, dir))
+ return; // we've already got this one
+ }
+
+ Q_strncpyz(fs_gamedir, dir, sizeof(fs_gamedir));
+
+ // find all pak files in this directory
+ Q_strncpyz(curpath, FS_BuildOSPath(path, dir, ""), sizeof(curpath));
+ curpath[strlen(curpath) - 1] = '\0'; // strip the trailing slash
+
+ // Get .pk3 files
+ pakfiles = Sys_ListFiles(curpath, ".pk3", nullptr, &numfiles, false);
+
+ qsort(pakfiles, numfiles, sizeof(char *), paksort);
+
+ if (fs_numServerPaks)
+ {
+ numdirs = 0;
+ pakdirs = nullptr;
+ }
+ else
+ {
+ // Get top level directories (we'll filter them later since the Sys_ListFiles filtering is
+ // terrible)
+ pakdirs = Sys_ListFiles(curpath, "/", nullptr, &numdirs, false);
+ qsort(pakdirs, numdirs, sizeof(char *), paksort);
+ }
+
+ char prefixBuf[MAX_STRING_CHARS];
+ Q_strncpyz(prefixBuf, Cvar_VariableString("fs_pk3PrefixPairs"), sizeof(prefixBuf));
+ int numPairs = 0;
+
+ char *p = prefixBuf;
+ if (!p[0]) p = nullptr;
+
+ const char *prefixes[10][2];
+ while (p)
+ {
+ prefixes[numPairs][0] = p;
+ p = strchr(p, '&');
+ if (!p)
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: fs_pk3PrefixPairs ends with an incomplete pair\n");
+ break;
+ }
+ lengths[numPairs][0] = (int)(p - prefixes[numPairs][0]);
+ *p++ = '\0';
+ prefixes[numPairs][1] = p;
+ p = strchr(p, '|');
+ if (p)
+ {
+ lengths[numPairs][1] = (int)(p - prefixes[numPairs][1]);
+ *p++ = '\0';
+ }
+ else
+ {
+ lengths[numPairs][1] = (int)strlen(prefixes[numPairs][1]);
+ }
+ if (lengths[numPairs][0] == 0 && lengths[numPairs][1] == 0)
+ {
+ Com_Printf(S_COLOR_YELLOW
+ "WARNING: fs_pk3PrefixPairs contains a null-null pair, "
+ "skipping this pair\n");
+ continue;
+ }
+ if (lengths[numPairs][0] != 0 && lengths[numPairs][1] != 0 &&
+ !Q_stricmpn(prefixes[numPairs][0], prefixes[numPairs][1],
+ MIN(lengths[numPairs][0], lengths[numPairs][1])))
+ {
+ Com_Printf(S_COLOR_YELLOW
+ "WARNING: in fs_pk3PrefixPairs, one of '%s' and '%s' is a real prefix "
+ "of the other, skipping this pair\n",
+ prefixes[numPairs][0], prefixes[numPairs][1]);
+
+ continue;
+ }
+ ++numPairs;
+ }
+ searchpath_t *otherSearchpaths = fs_searchpaths;
+
+ pakfilesi = 0;
+ pakdirsi = 0;
+
+ while ((pakfilesi < numfiles) || (pakdirsi < numdirs))
+ {
+ bool pakwhich;
+ // Check if a pakfile or pakdir comes next
+ if (pakfilesi >= numfiles)
+ {
+ pakwhich = false; // We've used all the pak files, it must be a pak directory.
+ }
+ else if (pakdirsi >= numdirs)
+ {
+ pakwhich = true; // We've used all the pak directories, it must be a pak file.
+ }
+ else
+ {
+ // Could be either, compare to see which name comes first
+ // Need tmp variables for appropriate indirection for paksort()
+ pakfilestmp = &pakfiles[pakfilesi];
+ pakdirstmp = &pakdirs[pakdirsi];
+ pakwhich = (paksort(pakfilestmp, pakdirstmp) < 0);
+ }
+
+ if (pakwhich)
+ {
+ // The next .pk3 file is before the next .pk3dir
+ char *pakfile = FS_BuildOSPath(path, dir, pakfiles[pakfilesi]);
+ if ((pak = FS_LoadZipFile(pakfile, pakfiles[pakfilesi])) == 0)
+ {
+ // This isn't a .pk3! Next!
+ pakfilesi++;
+ continue;
+ }
+
+ Q_strncpyz(pak->pakPathname, curpath, sizeof(pak->pakPathname));
+ // store the game name for downloading
+ Q_strncpyz(pak->pakGamename, dir, sizeof(pak->pakGamename));
+
+ fs_packFiles += pak->numfiles;
+
+ searchpath_t *search = static_cast<searchpath_t *>(Z_Malloc(sizeof(searchpath_t)));
+ search->pack = pak;
+ search->next = fs_searchpaths;
+ fs_searchpaths = search;
+
+ pak->onlyPrimary = false;
+ pak->onlyAlternate = false;
+ for (int i = 0; i < numPairs; ++i)
+ {
+ if (lengths[i][0] && !Q_stricmpn(pak->pakBasename, prefixes[i][0], lengths[i][0]))
+ {
+ pak->onlyPrimary = true;
+ break;
+ }
+ else if (lengths[i][1] &&
+ !Q_stricmpn(pak->pakBasename, prefixes[i][1], lengths[i][1]))
+ {
+ pak->onlyAlternate = true;
+ break;
+ }
+ }
+
+ pak->primaryVersion = nullptr;
+ pakfilesi++;
+ }
+ else
+ {
+ // The next .pk3dir is before the next .pk3 file
+ // But wait, this could be any directory, we're filtering to only ending with ".pk3dir"
+ // here.
+ int len = strlen(pakdirs[pakdirsi]);
+ if (!FS_IsExt(pakdirs[pakdirsi], ".pk3dir", len))
+ {
+ // This isn't a .pk3dir! Next!
+ pakdirsi++;
+ continue;
+ }
+
+ char *pakfile = FS_BuildOSPath(path, dir, pakdirs[pakdirsi]);
+
+ // add the directory to the search path
+ searchpath_t *search = static_cast<searchpath_t *>(Z_Malloc(sizeof(searchpath_t)));
+ search->dir = static_cast<directory_t *>(Z_Malloc(sizeof(*search->dir)));
+
+ Q_strncpyz(search->dir->path, curpath, sizeof(search->dir->path)); // c:\quake3\baseq3
+ Q_strncpyz(search->dir->fullpath, pakfile,
+ sizeof(search->dir->fullpath)); // c:\quake3\baseq3\mypak.pk3dir
+ Q_strncpyz(search->dir->gamedir, pakdirs[pakdirsi],
+ sizeof(search->dir->gamedir)); // mypak.pk3dir
+
+ search->next = fs_searchpaths;
+ fs_searchpaths = search;
+
+ pakdirsi++;
+ }
+ }
+
+ // done
+ Sys_FreeFileList(pakfiles);
+ Sys_FreeFileList(pakdirs);
+
+ if (numPairs > 0)
+ {
+ int bnlengths[2];
+ for (searchpath_t *search = fs_searchpaths; search != otherSearchpaths;
+ search = search->next)
+ {
+ if (!(search->pack && search->pack->onlyPrimary))
+ {
+ continue;
+ }
+
+ bnlengths[0] = (int)strlen(search->pack->pakBasename);
+ for (searchpath_t *srch = fs_searchpaths; srch != otherSearchpaths; srch = srch->next)
+ {
+ if (!(srch->pack && srch->pack->onlyAlternate))
+ {
+ continue;
+ }
+
+ bnlengths[1] = (int)strlen(srch->pack->pakBasename);
+ for (int i = 0; i < numPairs; ++i)
+ {
+ if (lengths[i][0] && lengths[i][1] && bnlengths[0] >= lengths[i][0] &&
+ bnlengths[1] >= lengths[i][1] &&
+ !Q_stricmp(search->pack->pakBasename + lengths[i][0],
+ srch->pack->pakBasename + lengths[i][1]))
+ {
+ srch->pack->primaryVersion = search->pack;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // add the directory to the search path
+ //
+ searchpath_t *search = static_cast<searchpath_t *>(Z_Malloc(sizeof(searchpath_t)));
+ search->dir = static_cast<directory_t *>(Z_Malloc(sizeof(*search->dir)));
+
+ Q_strncpyz(search->dir->path, path, sizeof(search->dir->path));
+ Q_strncpyz(search->dir->fullpath, curpath, sizeof(search->dir->fullpath));
+ Q_strncpyz(search->dir->gamedir, dir, sizeof(search->dir->gamedir));
+
+ search->next = fs_searchpaths;
+ fs_searchpaths = search;
+}
+
+/*
+================
+FS_CheckDirTraversal
+
+Check whether the string contains stuff like "../" to prevent directory traversal bugs
+and return true if it does.
+================
+*/
+
+bool FS_CheckDirTraversal(const char *checkdir)
+{
+ if (strstr(checkdir, "../") || strstr(checkdir, "..\\")) return true;
+
+ return false;
+}
+
+/*
+================
+FS_ComparePaks
+
+----------------
+dlstring == true
+
+Returns a list of pak files that we should download from the server. They all get stored
+in the current gamedir and an FS_Restart will be fired up after we download them all.
+
+The string is the format:
+
+@remotename@localname [repeat]
+
+static int fs_numServerReferencedPaks;
+static int fs_serverReferencedPaks[MAX_SEARCH_PATHS];
+static char *fs_serverReferencedPakNames[MAX_SEARCH_PATHS];
+
+----------------
+dlstring == false
+
+we are not interested in a download string format, we want something human-readable
+(this is used for diagnostics while connecting to a pure server)
+
+================
+*/
+bool FS_ComparePaks(char *neededpaks, int len, bool dlstring)
+{
+ if (!fs_numServerReferencedPaks)
+ {
+ return false; // Server didn't send any pack information along
+ }
+
+ char *origpos = neededpaks;
+ *neededpaks = '\0';
+
+ bool havepak = false;
+ for (int i = 0; i < fs_numServerReferencedPaks; i++)
+ {
+ // Ok, see if we have this pak file
+ havepak = false;
+
+ // Make sure the server cannot make us write to non-quake3 directories.
+ if (FS_CheckDirTraversal(fs_serverReferencedPakNames[i]))
+ {
+ Com_Printf("WARNING: Invalid download name %s\n", fs_serverReferencedPakNames[i]);
+ continue;
+ }
+
+ for (searchpath_t *sp = fs_searchpaths; sp; sp = sp->next)
+ {
+ if (sp->pack && sp->pack->checksum == fs_serverReferencedPaks[i])
+ {
+ havepak = true; // This is it!
+ break;
+ }
+ }
+
+ if (!havepak && fs_serverReferencedPakNames[i] && *fs_serverReferencedPakNames[i])
+ {
+ // Don't got it
+ if (dlstring)
+ {
+ // We need this to make sure we won't hit the end of the buffer or the server could
+ // overwrite non-pk3 files on clients by writing so much crap into neededpaks that
+ // Q_strcat cuts off the .pk3 extension.
+
+ origpos += strlen(origpos);
+
+ // Remote name
+ Q_strcat(neededpaks, len, "@");
+ Q_strcat(neededpaks, len, fs_serverReferencedPakNames[i]);
+ Q_strcat(neededpaks, len, ".pk3");
+
+ // Local name
+ Q_strcat(neededpaks, len, "@");
+ // Do we have one with the same name?
+ if (FS_SV_FileExists(va("%s.pk3", fs_serverReferencedPakNames[i])))
+ {
+ char st[MAX_ZPATH];
+ // We already have one called this, we need to download it to another name
+ // Make something up with the checksum in it
+ Com_sprintf(st, sizeof(st), "%s.%08x.pk3", fs_serverReferencedPakNames[i],
+ fs_serverReferencedPaks[i]);
+ Q_strcat(neededpaks, len, st);
+ }
+ else
+ {
+ Q_strcat(neededpaks, len, fs_serverReferencedPakNames[i]);
+ Q_strcat(neededpaks, len, ".pk3");
+ }
+
+ // Find out whether it might have overflowed the buffer and don't add this file to
+ // the
+ // list if that is the case.
+ if (strlen(origpos) + (origpos - neededpaks) >= (len - 1))
+ {
+ *origpos = '\0';
+ break;
+ }
+ }
+ else
+ {
+ Q_strcat(neededpaks, len, fs_serverReferencedPakNames[i]);
+ Q_strcat(neededpaks, len, ".pk3");
+ // Do we have one with the same name?
+ if (FS_SV_FileExists(va("%s.pk3", fs_serverReferencedPakNames[i])))
+ {
+ Q_strcat(neededpaks, len, " (local file exists with wrong checksum)");
+ }
+ Q_strcat(neededpaks, len, "\n");
+ }
+ }
+ }
+
+ if (*neededpaks)
+ {
+ return true;
+ }
+
+ return false; // We have them all
+}
+
+/*
+================
+FS_Shutdown
+
+Frees all resources.
+================
+*/
+
+void FS_Shutdown(bool closemfp)
+{
+ for (int i = 0; i < MAX_FILE_HANDLES; i++)
+ {
+ if (fsh[i].fileSize) FS_FCloseFile(i);
+ }
+
+ searchpath_t *next;
+ // free everything
+ for (auto p = fs_searchpaths; p; p = next)
+ {
+ next = p->next;
+ if (p->pack) FS_FreePak(p->pack);
+ if (p->dir) Z_Free(p->dir);
+ Z_Free(p);
+ }
+
+ // Any FS_ calls will now be an error until reinitialized
+ fs_searchpaths = nullptr;
+
+ Cmd_RemoveCommand("path");
+ Cmd_RemoveCommand("dir");
+ Cmd_RemoveCommand("fdir");
+ Cmd_RemoveCommand("touchFile");
+ Cmd_RemoveCommand("which");
+
+#ifdef FS_MISSING
+ if (closemfp)
+ {
+ fclose(missingFiles);
+ }
+#endif
+}
+
+/*
+================
+FS_ReorderPurePaks
+NOTE TTimo: the reordering that happens here is not reflected in the cvars (\cvarlist *pak*)
+ this can lead to misleading situations, see
+https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=540
+================
+*/
+static void FS_ReorderPurePaks(void)
+{
+ // do this before fs_numServerPaks check?
+ fs_reordered = false;
+
+ // only relevant when connected to pure server
+ if (!fs_numServerPaks) return;
+
+ // we insert in order at the beginning of the list
+ auto p_insert_index = &fs_searchpaths;
+ for (int i = 0; i < fs_numServerPaks; i++)
+ {
+ // track the pointer-to-current-item
+ auto p_previous = p_insert_index;
+ for (auto s = *p_insert_index; s; s = s->next)
+ {
+ // the part of the list before p_insert_index has been sorted already
+ if (s->pack && fs_serverPaks[i] == s->pack->checksum)
+ {
+ fs_reordered = true;
+
+ // move this element to the insert list
+ *p_previous = s->next;
+ s->next = *p_insert_index;
+ *p_insert_index = s;
+
+ // increment insert list
+ p_insert_index = &s->next;
+
+ // iterate to next server pack
+ break;
+ }
+ p_previous = &s->next;
+ }
+ }
+}
+
+/*
+================
+FS_Startup
+================
+*/
+static void FS_Startup(const char *gameName)
+{
+ Com_Printf("----- FS_Startup -----\n");
+ fs_packFiles = 0;
+
+ fs_debug = Cvar_Get("fs_debug", "0", 0);
+ fs_basepath = Cvar_Get("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT | CVAR_PROTECTED);
+ fs_basegame = Cvar_Get("fs_basegame", BASEGAME, CVAR_INIT);
+
+ const char *homePath = Sys_DefaultHomePath();
+ if (!homePath || !homePath[0])
+ {
+ homePath = fs_basepath->string;
+ }
+
+ fs_homepath = Cvar_Get("fs_homepath", homePath, CVAR_INIT | CVAR_PROTECTED);
+ fs_gamedirvar = Cvar_Get("fs_game", BASEGAME, CVAR_INIT | CVAR_SYSTEMINFO);
+
+#ifdef DEDICATED
+ // add search path elements in reverse priority order
+ if (fs_basepath->string[0])
+ FS_AddGameDirectory(fs_basepath->string, gameName);
+
+ // NOTE: same filtering below for mods and basegame
+ if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string))
+ {
+ FS_CreatePath(fs_homepath->string);
+ FS_AddGameDirectory(fs_homepath->string, gameName);
+ }
+
+ // check for additional base game so mods can be based upon other mods
+ if ( fs_basegame->string[0] && Q_stricmp( fs_basegame->string, gameName ) )
+ {
+ if (fs_basepath->string[0])
+ FS_AddGameDirectory(fs_basepath->string, fs_basegame->string);
+ if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string))
+ FS_AddGameDirectory(fs_homepath->string, fs_basegame->string);
+ }
+
+ // check for additional game folder for mods
+ if ( fs_gamedirvar->string[0] && Q_stricmp( fs_gamedirvar->string, gameName ) )
+ {
+ if (fs_basepath->string[0])
+ FS_AddGameDirectory(fs_basepath->string, fs_gamedirvar->string);
+ if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string))
+ FS_AddGameDirectory(fs_homepath->string, fs_gamedirvar->string);
+ }
+
+#else
+
+ // add search path elements in reverse priority order
+ if (fs_basepath->string[0])
+ {
+ FS_AddGameDirectory(fs_basepath->string, "base");
+ }
+
+#ifdef __APPLE__
+ // Make MacOSX also include the base path included with the .app bundle
+ fs_apppath = Cvar_Get("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT | CVAR_PROTECTED);
+ if (fs_apppath->string[0])
+ {
+ FS_AddGameDirectory(fs_apppath->string, "base");
+ }
+#endif
+
+ // NOTE: same filtering below for mods and basegame
+ if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string, fs_basepath->string))
+ {
+ FS_CreatePath(fs_homepath->string);
+ FS_AddGameDirectory(fs_homepath->string, "base");
+ }
+
+ // check for additional base game so mods can be based upon other mods
+ if (fs_basegame->string[0] && Q_stricmp(fs_basegame->string, gameName))
+ {
+ if (fs_basepath->string[0])
+ FS_AddGameDirectory(fs_basepath->string, fs_basegame->string);
+ if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string, fs_basepath->string))
+ FS_AddGameDirectory(fs_homepath->string, fs_basegame->string);
+ }
+
+ // check for additional game folder for mods
+ if (fs_gamedirvar->string[0] && Q_stricmp(fs_gamedirvar->string, gameName))
+ {
+ if (fs_basepath->string[0])
+ FS_AddGameDirectory(fs_basepath->string, fs_gamedirvar->string);
+ if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string, fs_basepath->string))
+ FS_AddGameDirectory(fs_homepath->string, fs_gamedirvar->string);
+ }
+
+ // NOTE: same filtering below for mods and basegame
+ if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string, fs_basepath->string))
+ {
+ FS_CreatePath(fs_homepath->string);
+ FS_AddGameDirectory(fs_homepath->string, gameName);
+ }
+
+ // add search path elements in reverse priority order
+ if (fs_basepath->string[0])
+ {
+ FS_AddGameDirectory(fs_basepath->string, gameName);
+ }
+
+#ifdef __APPLE__
+ // Make MacOSX also include the base path included with the .app bundle
+ fs_apppath = Cvar_Get("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT | CVAR_PROTECTED);
+ if (fs_apppath->string[0])
+ {
+ FS_AddGameDirectory(fs_apppath->string, gameName);
+ }
+#endif
+#endif
+
+ // add our commands
+ Cmd_AddCommand("path", FS_Path_f);
+ Cmd_AddCommand("dir", FS_Dir_f);
+ Cmd_AddCommand("fdir", FS_NewDir_f);
+ Cmd_AddCommand("touchFile", FS_TouchFile_f);
+ Cmd_AddCommand("which", FS_Which_f);
+
+ // reorder the pure pk3 files according to server order
+ FS_ReorderPurePaks();
+
+ // print the current search paths
+ FS_Path_f();
+
+ // We just loaded, it's not modified
+ fs_gamedirvar->modified = false;
+
+ Com_Printf("----------------------\n");
+
+#ifdef FS_MISSING
+ if (missingFiles == nullptr)
+ {
+ missingFiles = Sys_FOpen("\\missing.txt", "ab");
+ }
+#endif
+
+ Com_Printf("%d files in pk3 files\n", fs_packFiles);
+}
+
+/*
+=====================
+FS_LoadedPakChecksums
+
+Returns a space separated string containing the checksums of all loaded pk3 files.
+Servers with sv_pure set will get this string and pass it to clients.
+=====================
+*/
+const char *FS_LoadedPakChecksums(bool alternate)
+{
+ static char info[BIG_INFO_STRING];
+ info[0] = 0;
+
+ for (auto search = fs_searchpaths; search; search = search->next)
+ {
+ // is the element a pak file?
+ if (!search->pack) continue;
+ if ((alternate && search->pack->onlyPrimary) || (!alternate && search->pack->onlyAlternate))
+ continue;
+ Q_strcat(info, sizeof(info), va("%i ", search->pack->checksum));
+ }
+
+ return info;
+}
+
+/*
+=====================
+FS_LoadedPakNames
+
+Returns a space separated string containing the names of all loaded pk3 files.
+Servers with sv_pure set will get this string and pass it to clients.
+=====================
+*/
+const char *FS_LoadedPakNames(bool alternate)
+{
+ static char info[BIG_INFO_STRING];
+ info[0] = 0;
+
+ for (auto search = fs_searchpaths; search; search = search->next)
+ {
+ // is the element a pak file?
+ if (!search->pack) continue;
+ if ((alternate && search->pack->onlyPrimary) || (!alternate && search->pack->onlyAlternate))
+ continue;
+ if (info[0]) Q_strcat(info, sizeof(info), " ");
+ Q_strcat(info, sizeof(info), search->pack->pakBasename);
+ }
+
+ return info;
+}
+
+/*
+=====================
+FS_LoadedPakPureChecksums
+
+Returns a space separated string containing the pure checksums of all loaded pk3 files.
+Servers with sv_pure use these checksums to compare with the checksums the clients send
+back to the server.
+=====================
+*/
+const char *FS_LoadedPakPureChecksums(bool alternate)
+{
+ static char info[BIG_INFO_STRING];
+ info[0] = 0;
+
+ for (auto search = fs_searchpaths; search; search = search->next)
+ {
+ // is the element a pak file?
+ if (!search->pack) continue;
+ if ((alternate && search->pack->onlyPrimary) || (!alternate && search->pack->onlyAlternate))
+ continue;
+ Q_strcat(info, sizeof(info), va("%i ", search->pack->pure_checksum));
+ }
+
+ return info;
+}
+
+/*
+=====================
+FS_ReferencedPakChecksums
+
+Returns a space separated string containing the checksums of all referenced pk3 files.
+The server will send this to the clients so they can check which files should be auto-downloaded.
+=====================
+*/
+const char *FS_ReferencedPakChecksums(bool alternate)
+{
+ static char info[BIG_INFO_STRING];
+ info[0] = 0;
+
+ for (auto search = fs_searchpaths; search; search = search->next)
+ {
+ // is the element a pak file?
+ if (search->pack)
+ {
+ if ((alternate and search->pack->onlyPrimary) or
+ (!alternate and search->pack->onlyAlternate))
+ continue;
+
+ if (search->pack->referenced or
+ (search->pack->primaryVersion and search->pack->primaryVersion->referenced) or
+ (*fs_gamedirvar->string and Q_stricmp(fs_gamedirvar->string, BASEGAME) and
+ Q_stricmp(search->pack->pakGamename, fs_gamedirvar->string) == 0))
+ {
+ Q_strcat(info, sizeof(info), va("%i ", search->pack->checksum));
+ }
+ }
+ }
+
+ return info;
+}
+
+/*
+=====================
+FS_ReferencedPakPureChecksums
+
+Returns a space separated string containing the pure checksums of all referenced pk3 files.
+Servers with sv_pure set will get this string back from clients for pure validation
+
+The string has a specific order, "cgame ui @ ref1 ref2 ref3 ..."
+=====================
+*/
+const char *FS_ReferencedPakPureChecksums(void)
+{
+ static char info[BIG_INFO_STRING];
+ info[0] = 0;
+
+ int checksum = fs_checksumFeed;
+ int numPaks = 0;
+ for (int nFlags = FS_CGAME_REF; nFlags; nFlags = nFlags >> 1)
+ {
+ if (nFlags & FS_GENERAL_REF)
+ {
+ // add a delimter between must haves and general refs
+ // Q_strcat(info, sizeof(info), "@ ");
+ info[strlen(info) + 1] = '\0';
+ info[strlen(info) + 2] = '\0';
+ info[strlen(info)] = '@';
+ info[strlen(info)] = ' ';
+ }
+ for (auto search = fs_searchpaths; search; search = search->next)
+ {
+ // is the element a pak file and has it been referenced based on flag?
+ if (search->pack && (search->pack->referenced & nFlags))
+ {
+ Q_strcat(info, sizeof(info), va("%i ", search->pack->pure_checksum));
+ if (nFlags & (FS_CGAME_REF | FS_UI_REF)) break;
+
+ checksum ^= search->pack->pure_checksum;
+ numPaks++;
+ }
+ }
+ }
+ // last checksum is the encoded number of referenced pk3s
+ checksum ^= numPaks;
+ Q_strcat(info, sizeof(info), va("%i ", checksum));
+
+ return info;
+}
+
+/*
+=====================
+FS_ReferencedPakNames
+
+Returns a space separated string containing the names of all referenced pk3 files.
+The server will send this to the clients so they can check which files should be auto-downloaded.
+=====================
+*/
+const char *FS_ReferencedPakNames(bool alternate)
+{
+ static char info[BIG_INFO_STRING];
+ info[0] = 0;
+
+ // we want to return ALL pk3's from the fs_game path
+ // and referenced one's from base
+ for (auto search = fs_searchpaths; search; search = search->next)
+ {
+ // is the element a pak file?
+ if (search->pack)
+ {
+ if ((alternate && search->pack->onlyPrimary) ||
+ (!alternate && search->pack->onlyAlternate))
+ continue;
+
+ if (search->pack->referenced ||
+ (search->pack->primaryVersion && search->pack->primaryVersion->referenced) ||
+ (fs_gamedirvar->string[0] && Q_stricmp(fs_gamedirvar->string, BASEGAME) &&
+ !Q_stricmp(search->pack->pakGamename, fs_gamedirvar->string)))
+ {
+ if (*info) Q_strcat(info, sizeof(info), " ");
+
+ Q_strcat(info, sizeof(info), search->pack->pakGamename);
+ Q_strcat(info, sizeof(info), "/");
+ Q_strcat(info, sizeof(info), search->pack->pakBasename);
+ }
+ }
+ }
+
+ return info;
+}
+
+/*
+=====================
+FS_ClearPakReferences
+=====================
+*/
+void FS_ClearPakReferences(int flags)
+{
+ if (!flags) flags = -1;
+
+ for (auto search = fs_searchpaths; search; search = search->next)
+ {
+ // is the element a pak file and has it been referenced?
+ if (search->pack) search->pack->referenced &= ~flags;
+ }
+}
+
+/*
+=====================
+FS_PureServerSetLoadedPaks
+
+If the string is empty, all data sources will be allowed.
+If not empty, only pk3 files that match one of the space
+separated checksums will be checked for files, with the
+exception of .cfg and .dat files.
+=====================
+*/
+void FS_PureServerSetLoadedPaks(const char *pakSums, const char *pakNames)
+{
+ Cmd_TokenizeString(pakSums);
+
+ int c = Cmd_Argc();
+ if (c > MAX_SEARCH_PATHS) c = MAX_SEARCH_PATHS;
+
+ fs_numServerPaks = c;
+
+ for (int i = 0; i < c; i++) fs_serverPaks[i] = atoi(Cmd_Argv(i));
+
+ if (fs_numServerPaks)
+ {
+ Com_DPrintf("Connected to a pure server.\n");
+ }
+ else if (fs_reordered)
+ {
+ // force a restart to make sure the search order will be correct
+ Com_DPrintf("FS search reorder is required\n");
+ FS_Restart(fs_checksumFeed);
+ return;
+ }
+
+ for (int i = 0; i < c; i++)
+ {
+ if (fs_serverPakNames[i]) Z_Free(fs_serverPakNames[i]);
+ fs_serverPakNames[i] = nullptr;
+ }
+
+ if (pakNames && pakNames[0])
+ {
+ Cmd_TokenizeString(pakNames);
+
+ int d = Cmd_Argc();
+ if (d > MAX_SEARCH_PATHS) d = MAX_SEARCH_PATHS;
+
+ for (int i = 0; i < d; i++) fs_serverPakNames[i] = CopyString(Cmd_Argv(i));
+ }
+}
+
+/*
+=====================
+FS_PureServerSetReferencedPaks
+
+The checksums and names of the pk3 files referenced at the server
+are sent to the client and stored here. The client will use these
+checksums to see if any pk3 files need to be auto-downloaded.
+=====================
+*/
+void FS_PureServerSetReferencedPaks(const char *pakSums, const char *pakNames)
+{
+ Cmd_TokenizeString(pakSums);
+
+ unsigned c = Cmd_Argc();
+ if (c > MAX_SEARCH_PATHS) c = MAX_SEARCH_PATHS;
+
+ for (unsigned i = 0; i < c; i++) fs_serverReferencedPaks[i] = atoi(Cmd_Argv(i));
+
+ for (unsigned i = 0; i < ARRAY_LEN(fs_serverReferencedPakNames); i++)
+ {
+ if (fs_serverReferencedPakNames[i]) Z_Free(fs_serverReferencedPakNames[i]);
+ fs_serverReferencedPakNames[i] = nullptr;
+ }
+
+ unsigned d = 0;
+ if (pakNames && *pakNames)
+ {
+ Cmd_TokenizeString(pakNames);
+
+ d = Cmd_Argc();
+ if (d > c) d = c;
+
+ for (unsigned i = 0; i < d; i++) fs_serverReferencedPakNames[i] = CopyString(Cmd_Argv(i));
+ }
+
+ // ensure that there are as many checksums as there are pak names.
+ if (d < c) c = d;
+
+ fs_numServerReferencedPaks = c;
+}
+
+/*
+================
+FS_InitFilesystem
+
+Called only at inital startup, not when the filesystem
+is resetting due to a game change
+================
+*/
+void FS_InitFilesystem(void)
+{
+ // allow command line parms to override our defaults
+ // we have to specially handle this, because normal command
+ // line variable sets don't happen until after the filesystem
+ // has already been initialized
+ Com_StartupVariable("fs_basepath");
+ Com_StartupVariable("fs_homepath");
+ Com_StartupVariable("fs_game");
+ Com_StartupVariable("fs_pk3PrefixPairs");
+
+ if (!FS_FilenameCompare(Cvar_VariableString("fs_game"), BASEGAME)) Cvar_Set("fs_game", "");
+
+ // try to start up normally
+ FS_Startup(BASEGAME);
+
+ // if we can't find default.cfg, assume that the paths are
+ // busted and error out now, rather than getting an unreadable
+ // graphics screen when the font fails to load
+ if (FS_ReadFile("default.cfg", nullptr) <= 0)
+ {
+ Com_Error(ERR_FATAL, "Couldn't load default.cfg");
+ }
+
+ Q_strncpyz(lastValidBase, fs_basegame->string, sizeof(lastValidBase));
+ Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame));
+}
+
+/*
+================
+FS_Restart
+================
+*/
+void FS_Restart(int checksumFeed)
+{
+ // free anything we currently have loaded
+ FS_Shutdown(false);
+
+ // set the checksum feed
+ fs_checksumFeed = checksumFeed;
+
+ // clear pak references
+ FS_ClearPakReferences(0);
+
+ // try to start up normally
+ FS_Startup(BASEGAME);
+
+ // if we can't find default.cfg, assume that the paths are
+ // busted and error out now, rather than getting an unreadable
+ // graphics screen when the font fails to load
+ if (FS_ReadFile("default.cfg", nullptr) <= 0)
+ {
+ // this might happen when connecting to a pure server not using BASEGAME/pak0.pk3
+ // (for instance a TA demo server)
+ if (lastValidBase[0])
+ {
+ FS_PureServerSetLoadedPaks("", "");
+ Cvar_Set("fs_basegame", lastValidBase);
+ Cvar_Set("fs_game", lastValidGame);
+ lastValidBase[0] = lastValidGame[0] = '\0';
+ FS_Restart(checksumFeed);
+ Com_Error(ERR_DROP, "Invalid game folder");
+ return;
+ }
+ Com_Error(ERR_FATAL, "Couldn't load default.cfg");
+ }
+
+ if (Q_stricmp(fs_gamedirvar->string, lastValidGame))
+ {
+ // skip the autogen.cfg if "safe" is on the command line
+ if (!Com_SafeMode())
+ {
+ Cbuf_AddText("exec " Q3CONFIG_CFG "\n");
+ }
+ }
+
+ Q_strncpyz(lastValidBase, fs_basegame->string, sizeof(lastValidBase));
+ Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame));
+}
+
+/*
+=================
+FS_ConditionalRestart
+
+Restart if necessary
+Return true if restarting due to game directory changed, false otherwise
+=================
+*/
+bool FS_ConditionalRestart(int checksumFeed, bool disconnect)
+{
+ if (fs_gamedirvar->modified)
+ {
+ if (FS_FilenameCompare(lastValidGame, fs_gamedirvar->string) &&
+ (*lastValidGame || FS_FilenameCompare(fs_gamedirvar->string, BASEGAME)) &&
+ (*fs_gamedirvar->string || FS_FilenameCompare(lastValidGame, BASEGAME)))
+ {
+ Com_GameRestart(checksumFeed, disconnect);
+ return true;
+ }
+ fs_gamedirvar->modified = false;
+ }
+
+ if (checksumFeed != fs_checksumFeed)
+ FS_Restart(checksumFeed);
+
+ else if (fs_numServerPaks && !fs_reordered)
+ FS_ReorderPurePaks();
+
+ return false;
+}
+
+/*
+========================================================================================
+
+Handle based file calls for virtual machines
+
+========================================================================================
+*/
+
+int FS_FOpenFileByMode(const char *qpath, fileHandle_t *f, enum FS_Mode mode)
+{
+ int r;
+ bool sync = false;
+
+ switch (mode)
+ {
+ case FS_READ:
+ r = FS_FOpenFileRead(qpath, f, true);
+ break;
+
+ case FS_WRITE:
+ *f = FS_FOpenFileWrite(qpath);
+ r = 0;
+ if (*f == 0) r = -1;
+ break;
+
+ case FS_APPEND_SYNC:
+ sync = true;
+ // fall through
+
+ case FS_APPEND:
+ *f = FS_FOpenFileAppend(qpath);
+ r = 0;
+ if (*f == 0) r = -1;
+ break;
+
+ default:
+ Com_Error(ERR_FATAL, "FS_FOpenFileByMode: bad mode");
+ return -1;
+ }
+
+ if (!f) return r;
+
+ if (*f)
+ {
+ fsh[*f].fileSize = r;
+ }
+ fsh[*f].handleSync = sync;
+
+ return r;
+}
+
+int FS_FTell(fileHandle_t f)
+{
+ if (fsh[f].zipFile == true) return unztell(fsh[f].handleFiles.file.z);
+ return ftell(fsh[f].handleFiles.file.o);
+}
+
+void FS_Flush(fileHandle_t f)
+{
+ fflush(fsh[f].handleFiles.file.o);
+}
+
+void FS_FilenameCompletion(const char *dir, const char *ext, bool stripExt,
+ void (*callback)(const char *s), bool allowNonPureFilesOnDisk)
+{
+ int nfiles;
+ char filename[MAX_STRING_CHARS];
+ char **filenames = FS_ListFilteredFiles(dir, ext, nullptr, &nfiles, allowNonPureFilesOnDisk);
+
+ FS_SortFileList(filenames, nfiles);
+
+ for (int i = 0; i < nfiles; i++)
+ {
+ FS_ConvertPath(filenames[i]);
+ Q_strncpyz(filename, filenames[i], MAX_STRING_CHARS);
+ if (stripExt) COM_StripExtension(filename, filename, sizeof(filename));
+ callback(filename);
+ }
+ FS_FreeFileList(filenames);
+}
+
+const char *FS_GetCurrentGameDir(void)
+{
+ if (fs_gamedirvar->string[0]) return fs_gamedirvar->string;
+ return BASEGAME;
+}
diff --git a/src/qcommon/files.h b/src/qcommon/files.h
new file mode 100644
index 0000000..d54bdf4
--- /dev/null
+++ b/src/qcommon/files.h
@@ -0,0 +1,286 @@
+/*
+ * This file is part of Tremulous.
+ * Copyright © 2016 Victor Roemer (blowfish) <victor@badsec.org>
+ * Copyright (C) 2015-2019 GrangerHub
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QC_FILES_H
+#define QC_FILES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "q_platform.h"
+#include "q_shared.h"
+
+// referenced flags
+// these are in loop specific order so don't change the order
+#define FS_GENERAL_REF 0x01
+#define FS_UI_REF 0x02
+#define FS_CGAME_REF 0x04
+
+#define MAX_FILE_HANDLES 64
+
+#define BASEGAME "gpp"
+
+#ifdef DEDICATED
+#define Q3CONFIG_CFG "autogen_server.cfg"
+#else
+#define Q3CONFIG_CFG "autogen.cfg"
+#endif
+
+/*
+ =============================================================
+
+ QUAKE3 FILESYSTEM
+
+ All of Quake's data access is through a hierarchical file system, but the contents of
+ the file system can be transparently merged from several sources.
+
+ A "qpath" is a reference to game file data. MAX_ZPATH is 256 characters, which must include
+ a terminating zero. "..", "\\", and ":" are explicitly illegal in qpaths to prevent any
+ references outside the quake directory system.
+
+ The "base path" is the path to the directory holding all the game directories and usually
+ the executable. It defaults to ".", but can be overridden with a "+set fs_basepath c:\quake3"
+ command line to allow code debugging in a different directory. Basepath cannot
+ be modified at all after startup. Any files that are created (demos, screenshots,
+ etc) will be created relative to the base path, so base path should usually be writable.
+
+ The "home path" is the path used for all write access. On win32 systems we have "base path"
+ == "home path", but on *nix systems the base installation is usually readonly, and
+ "home path" points to ~/.q3a or similar
+
+ The user can also install custom mods and content in "home path", so it should be searched
+ along with "home path" and "cd path" for game content.
+
+
+ The "base game" is the directory under the paths where data comes from by default, and
+ can be "base".
+
+ The "current game" may be the same as the base game, or it may be the name of another
+ directory under the paths that should be searched for files before looking in the base game.
+ This is the basis for addons.
+
+ Clients automatically set the game directory after receiving a gamestate from a server,
+ so only servers need to worry about +set fs_game.
+
+ No other directories outside of the base game and current game will ever be referenced by
+ filesystem functions.
+
+ To save disk space and speed loading, directory trees can be collapsed into zip files.
+ The files use a ".pk3" extension to prevent users from unzipping them accidentally, but
+ otherwise the are simply normal uncompressed zip files. A game directory can have multiple
+ zip files of the form "pak0.pk3", "pak1.pk3", etc. Zip files are searched in decending order
+ from the highest number to the lowest, and will always take precedence over the filesystem.
+ This allows a pk3 distributed as a patch to override all existing data.
+
+ Because we will have updated executables freely available online, there is no point to
+ trying to restrict demo / oem versions of the game with code changes. Demo / oem versions
+ should be exactly the same executables as release versions, but with different data that
+ automatically restricts where game media can come from to prevent add-ons from working.
+
+ File search order: when FS_FOpenFileRead gets called it will go through the fs_searchpaths
+ structure and stop on the first successful hit. fs_searchpaths is built with successive
+ calls to FS_AddGameDirectory
+
+ Additionaly, we search in several subdirectories:
+ current game is the current mode
+ base game is a variable to allow mods based on other mods
+ (such as base + missionpack content combination in a mod for instance)
+ BASEGAME is the hardcoded base game ("base")
+
+ e.g. the qpath "sound/newstuff/test.wav" would be searched for in the following places:
+
+ home path + current game's zip files
+ home path + current game's directory
+ base path + current game's zip files
+ base path + current game's directory
+ cd path + current game's zip files
+ cd path + current game's directory
+
+ home path + base game's zip file
+ home path + base game's directory
+ base path + base game's zip file
+ base path + base game's directory
+ cd path + base game's zip file
+ cd path + base game's directory
+
+ home path + BASEGAME's zip file
+ home path + BASEGAME's directory
+ base path + BASEGAME's zip file
+ base path + BASEGAME's directory
+ cd path + BASEGAME's zip file
+ cd path + BASEGAME's directory
+
+ server download, to be written to home path + current game's directory
+
+
+ The filesystem can be safely shutdown and reinitialized with different
+ basedir / cddir / game combinations, but all other subsystems that rely on it
+ (sound, video) must also be forced to restart.
+
+ Because the same files are loaded by both the clip model (CM_) and renderer (TR_)
+ subsystems, a simple single-file caching scheme is used. The CM_ subsystems will
+ load the file with a request to cache. Only one file will be kept cached at a time,
+ so any models that are going to be referenced by both subsystems should alternate
+ between the CM_ load function and the ref load function.
+
+ TODO: A qpath that starts with a leading slash will always refer to the base game, even if another
+ game is currently active. This allows character models, skins, and sounds to be downloaded
+ to a common directory no matter which game is active.
+
+ How to prevent downloading zip files?
+ Pass pk3 file names in systeminfo, and download before FS_Restart (void)?
+
+ Aborting a download disconnects the client from the server.
+
+ How to mark files as downloadable? Commercial add-ons won't be downloadable.
+
+ Non-commercial downloads will want to download the entire zip file.
+ the game would have to be reset to actually read the zip in
+
+ Auto-update information
+
+ Path separators
+
+ Casing
+
+ separate server gamedir and client gamedir, so if the user starts
+ a local game after having connected to a network game, it won't stick
+ with the network game.
+
+ allow menu options for game selection?
+
+ Read / write config to floppy option.
+
+ Different version coexistance?
+
+ When building a pak file, make sure a autogen.cfg isn't present in it,
+ or configs will never get loaded from disk!
+
+ todo:
+
+ downloading (outside fs?)
+ game directory passing and restarting
+
+ =============================================================================
+*/
+
+//enum FS_Mode {
+// FS_READ,
+// FS_WRITE,
+// FS_APPEND,
+// FS_APPEND_SYNC
+//};
+//
+//enum FS_Origin {
+// FS_SEEK_CUR,
+// FS_SEEK_END,
+// FS_SEEK_SET
+//};
+
+const char* FS_GetCurrentGameDir (void);
+void FS_FilenameCompletion (const char* dir, const char* ext, bool stripExt, void (* callback)(const char* s), bool allowNonPureFilesOnDisk);
+int FS_FOpenFileByMode (const char* qpath, fileHandle_t* f, enum FS_Mode mode);
+bool FS_ConditionalRestart (int checksumFeed, bool disconnect);
+void FS_InitFilesystem (void);
+void FS_PureServerSetReferencedPaks (const char* pakSums, const char* pakNames);
+void FS_Restart (int checksumFeed);
+void FS_PureServerSetLoadedPaks (const char* pakSums, const char* pakNames);
+void FS_ClearPakReferences (int flags);
+const char* FS_ReferencedPakNames (bool alternate);
+const char* FS_ReferencedPakPureChecksums (void);
+const char* FS_ReferencedPakChecksums (bool alternate);
+const char* FS_LoadedPakPureChecksums (bool alternate);
+const char* FS_LoadedPakNames (bool alternate);
+const char* FS_LoadedPakChecksums (bool alternate);
+void FS_Shutdown (bool closemfp);
+bool FS_ComparePaks (char* neededpaks, int len, bool dlstring);
+bool FS_CheckDirTraversal (const char* checkdir);
+void FS_AddGameDirectory (const char* path, const char* dir);
+bool FS_Which (const char* filename, void* searchPath);
+void FS_SortFileList (char** filelist, int numfiles);
+int FS_PathCmp (const char* s1, const char* s2);
+void FS_ConvertPath (char* s);
+int FS_GetModList (char* listbuf, int bufsize);
+int FS_GetFileList (const char* path, const char* extension, char* listbuf, int bufsize);
+void FS_FreeFileList (char** list);
+int FS_GetFilteredFiles (const char *path, const char *extension, const char *filter, char *listbuf, int bufsize);
+char** FS_ListFiles (const char* path, const char* extension, int* numfiles);
+char** FS_ListFilteredFiles (const char* path, const char* extension, const char* filter, int* numfiles, bool allowNonPureFilesOnDisk);
+bool FS_CompareZipChecksum (const char* zipfile);
+void FS_WriteFile (const char* qpath, const void* buffer, int size);
+void FS_FreeFile (void* buffer);
+long FS_ReadFile (const char* qpath, void** buffer);
+void FS_Flush (fileHandle_t f);
+long FS_ReadFileDir (const char* qpath, void* searchPath, bool unpure, void** buffer);
+int FS_FileIsInPAK_A(bool alternate, const char *filename, int *pChecksum);
+int FS_FileIsInPAK (const char* filename, int* pChecksum);
+int FS_FTell (fileHandle_t f);
+int FS_Seek (fileHandle_t f, long offset, enum FS_Origin origin);
+void QDECL FS_Printf (fileHandle_t h, const char* fmt, ...);
+int FS_Write (const void* buffer, int len, fileHandle_t h);
+int FS_Read (void* buffer, int len, fileHandle_t f);
+int FS_Read (void* buffer, int len, fileHandle_t f);
+int FS_FindVM (void** startSearch, char* found, int foundlen, const char* name, int enableDll);
+long FS_FOpenFileRead (const char* filename, fileHandle_t* file, bool uniqueFILE);
+long FS_FOpenFileReadDir (const char* filename, void* search, fileHandle_t* file, bool uniqueFILE, bool unpure);
+bool FS_FilenameCompare (const char* s1, const char* s2);
+fileHandle_t FS_FCreateOpenPipeFile (const char* filename);
+fileHandle_t FS_FOpenFileAppend (const char* filename);
+fileHandle_t FS_FOpenFileWrite (const char* filename);
+void FS_FCloseFile (fileHandle_t f);
+void FS_Rename (const char* from, const char* to);
+void FS_SV_Rename (const char* from, const char* to, bool safe);
+long FS_SV_FOpenFileRead (const char* filename, fileHandle_t* fp);
+fileHandle_t FS_SV_FOpenFileWrite (const char* filename);
+bool FS_SV_FileExists (const char* file);
+bool FS_FileExists (const char* file);
+bool FS_FileInPathExists (const char* testpath);
+void FS_HomeRemove (const char* homePath);
+void FS_Remove (const char* osPath);
+bool FS_BrowseHomepath ( void );
+bool FS_OpenBaseGamePath( const char *baseGamePath );
+bool FS_CreatePath (const char* OSPath);
+char* FS_BuildOSPath (const char* base, const char* game, const char* qpath);
+long FS_filelength (fileHandle_t f);
+void FS_ReplaceSeparators (char *path);
+void FS_ForceFlush (fileHandle_t f);
+int FS_LoadStack (void);
+bool FS_Initialized (void);
+
+void FS_Which_f (void);
+void FS_TouchFile_f (void);
+void FS_Path_f (void);
+void FS_NewDir_f (void);
+void FS_Dir_f (void);
+
+
+// XXX Delete me.
+#if defined (FS_MISSING)
+extern FILE *missingFiles;
+#endif
+
+extern char lastValidGame[MAX_OSPATH];
+extern char lastValidBase[MAX_OSPATH];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/qcommon/huffman.cpp b/src/qcommon/huffman.cpp
new file mode 100644
index 0000000..4cb0d8b
--- /dev/null
+++ b/src/qcommon/huffman.cpp
@@ -0,0 +1,558 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+/* This is based on the Adaptive Huffman algorithm described in Sayood's Data
+ * Compression book. The ranks are not actually stored, but implicitly defined
+ * by the location of a node within a doubly-linked list */
+
+#include "huffman.h"
+
+#include "alternatePlayerstate.h"
+#include "cvar.h"
+#include "msg.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+static int bloc = 0;
+
+void Huff_putBit(int bit, uint8_t *fout, int *offset)
+{
+ bloc = *offset;
+ if ((bloc & 7) == 0)
+ {
+ fout[(bloc >> 3)] = 0;
+ }
+ fout[(bloc >> 3)] |= bit << (bloc & 7);
+ bloc++;
+ *offset = bloc;
+}
+
+int Huff_getBloc(void) { return bloc; }
+void Huff_setBloc(int _bloc) { bloc = _bloc; }
+int Huff_getBit(uint8_t *fin, int *offset)
+{
+ int t;
+ bloc = *offset;
+ t = (fin[(bloc >> 3)] >> (bloc & 7)) & 0x1;
+ bloc++;
+ *offset = bloc;
+ return t;
+}
+
+/* Add a bit to the output file (buffered) */
+static void add_bit(char bit, uint8_t *fout)
+{
+ if ((bloc & 7) == 0)
+ {
+ fout[(bloc >> 3)] = 0;
+ }
+ fout[(bloc >> 3)] |= bit << (bloc & 7);
+ bloc++;
+}
+
+/* Receive one bit from the input file (buffered) */
+static int get_bit(uint8_t *fin)
+{
+ int t;
+ t = (fin[(bloc >> 3)] >> (bloc & 7)) & 0x1;
+ bloc++;
+ return t;
+}
+
+static node_t **get_ppnode(huff_t *huff)
+{
+ node_t **tppnode;
+ if (!huff->freelist)
+ {
+ return &(huff->nodePtrs[huff->blocPtrs++]);
+ }
+ else
+ {
+ tppnode = huff->freelist;
+ huff->freelist = (node_t **)*tppnode;
+ return tppnode;
+ }
+}
+
+static void free_ppnode(huff_t *huff, node_t **ppnode)
+{
+ *ppnode = (node_t *)huff->freelist;
+ huff->freelist = ppnode;
+}
+
+/* Swap the location of these two nodes in the tree */
+static void swap(huff_t *huff, node_t *node1, node_t *node2)
+{
+ node_t *par1, *par2;
+
+ par1 = node1->parent;
+ par2 = node2->parent;
+
+ if (par1)
+ {
+ if (par1->left == node1)
+ {
+ par1->left = node2;
+ }
+ else
+ {
+ par1->right = node2;
+ }
+ }
+ else
+ {
+ huff->tree = node2;
+ }
+
+ if (par2)
+ {
+ if (par2->left == node2)
+ {
+ par2->left = node1;
+ }
+ else
+ {
+ par2->right = node1;
+ }
+ }
+ else
+ {
+ huff->tree = node1;
+ }
+
+ node1->parent = par2;
+ node2->parent = par1;
+}
+
+/* Swap these two nodes in the linked list (update ranks) */
+static void swaplist(node_t *node1, node_t *node2)
+{
+ node_t *par1;
+
+ par1 = node1->next;
+ node1->next = node2->next;
+ node2->next = par1;
+
+ par1 = node1->prev;
+ node1->prev = node2->prev;
+ node2->prev = par1;
+
+ if (node1->next == node1)
+ {
+ node1->next = node2;
+ }
+ if (node2->next == node2)
+ {
+ node2->next = node1;
+ }
+ if (node1->next)
+ {
+ node1->next->prev = node1;
+ }
+ if (node2->next)
+ {
+ node2->next->prev = node2;
+ }
+ if (node1->prev)
+ {
+ node1->prev->next = node1;
+ }
+ if (node2->prev)
+ {
+ node2->prev->next = node2;
+ }
+}
+
+/* Do the increments */
+static void increment(huff_t *huff, node_t *node)
+{
+ node_t *lnode;
+
+ if (!node)
+ {
+ return;
+ }
+
+ if (node->next != NULL && node->next->weight == node->weight)
+ {
+ lnode = *node->head;
+ if (lnode != node->parent)
+ {
+ swap(huff, lnode, node);
+ }
+ swaplist(lnode, node);
+ }
+ if (node->prev && node->prev->weight == node->weight)
+ {
+ *node->head = node->prev;
+ }
+ else
+ {
+ *node->head = NULL;
+ free_ppnode(huff, node->head);
+ }
+ node->weight++;
+ if (node->next && node->next->weight == node->weight)
+ {
+ node->head = node->next->head;
+ }
+ else
+ {
+ node->head = get_ppnode(huff);
+ *node->head = node;
+ }
+ if (node->parent)
+ {
+ increment(huff, node->parent);
+ if (node->prev == node->parent)
+ {
+ swaplist(node, node->parent);
+ if (*node->head == node)
+ {
+ *node->head = node->parent;
+ }
+ }
+ }
+}
+
+void Huff_addRef(huff_t *huff, uint8_t ch)
+{
+ node_t *tnode, *tnode2;
+ if (huff->loc[ch] == NULL)
+ { /* if this is the first transmission of this node */
+ tnode = &(huff->nodeList[huff->blocNode++]);
+ tnode2 = &(huff->nodeList[huff->blocNode++]);
+
+ tnode2->symbol = INTERNAL_NODE;
+ tnode2->weight = 1;
+ tnode2->next = huff->lhead->next;
+ if (huff->lhead->next)
+ {
+ huff->lhead->next->prev = tnode2;
+ if (huff->lhead->next->weight == 1)
+ {
+ tnode2->head = huff->lhead->next->head;
+ }
+ else
+ {
+ tnode2->head = get_ppnode(huff);
+ *tnode2->head = tnode2;
+ }
+ }
+ else
+ {
+ tnode2->head = get_ppnode(huff);
+ *tnode2->head = tnode2;
+ }
+ huff->lhead->next = tnode2;
+ tnode2->prev = huff->lhead;
+
+ tnode->symbol = ch;
+ tnode->weight = 1;
+ tnode->next = huff->lhead->next;
+ if (huff->lhead->next)
+ {
+ huff->lhead->next->prev = tnode;
+ if (huff->lhead->next->weight == 1)
+ {
+ tnode->head = huff->lhead->next->head;
+ }
+ else
+ {
+ /* this should never happen */
+ tnode->head = get_ppnode(huff);
+ *tnode->head = tnode2;
+ }
+ }
+ else
+ {
+ /* this should never happen */
+ tnode->head = get_ppnode(huff);
+ *tnode->head = tnode;
+ }
+ huff->lhead->next = tnode;
+ tnode->prev = huff->lhead;
+ tnode->left = tnode->right = NULL;
+
+ if (huff->lhead->parent)
+ {
+ if (huff->lhead->parent->left == huff->lhead)
+ { /* lhead is guaranteed to by the NYT */
+ huff->lhead->parent->left = tnode2;
+ }
+ else
+ {
+ huff->lhead->parent->right = tnode2;
+ }
+ }
+ else
+ {
+ huff->tree = tnode2;
+ }
+
+ tnode2->right = tnode;
+ tnode2->left = huff->lhead;
+
+ tnode2->parent = huff->lhead->parent;
+ huff->lhead->parent = tnode->parent = tnode2;
+
+ huff->loc[ch] = tnode;
+
+ increment(huff, tnode2->parent);
+ }
+ else
+ {
+ increment(huff, huff->loc[ch]);
+ }
+}
+
+/* Get a symbol */
+int Huff_Receive(node_t *node, int *ch, uint8_t *fin)
+{
+ while (node && node->symbol == INTERNAL_NODE)
+ {
+ if (get_bit(fin))
+ {
+ node = node->right;
+ }
+ else
+ {
+ node = node->left;
+ }
+ }
+ if (!node)
+ {
+ return 0;
+ // Com_Error(ERR_DROP, "Illegal tree!");
+ }
+ return (*ch = node->symbol);
+}
+
+/* Get a symbol */
+void Huff_offsetReceive(node_t *node, int *ch, uint8_t *fin, int *offset, int maxoffset)
+{
+ bloc = *offset;
+ while (node && node->symbol == INTERNAL_NODE)
+ {
+ if ( bloc >= maxoffset )
+ {
+ *ch = 0;
+ *offset = maxoffset + 1;
+ return;
+ }
+
+ if (get_bit(fin))
+ {
+ node = node->right;
+ }
+ else
+ {
+ node = node->left;
+ }
+ }
+ if (!node)
+ {
+ *ch = 0;
+ return;
+ // Com_Error(ERR_DROP, "Illegal tree!");
+ }
+ *ch = node->symbol;
+ *offset = bloc;
+}
+
+/* Send the prefix code for this node */
+static void send(node_t *node, node_t *child, uint8_t *fout, int maxoffset)
+{
+ if (node->parent)
+ {
+ send(node->parent, node, fout, maxoffset);
+ }
+ if (child)
+ {
+ if (bloc >= maxoffset)
+ {
+ bloc = maxoffset + 1;
+ return;
+ }
+
+ if (node->right == child)
+ {
+ add_bit(1, fout);
+ }
+ else
+ {
+ add_bit(0, fout);
+ }
+ }
+}
+
+/* Send a symbol */
+void Huff_transmit(huff_t *huff, int ch, uint8_t *fout, int maxoffset)
+{
+ int i;
+ if (huff->loc[ch] == NULL)
+ {
+ /* node_t hasn't been transmitted, send a NYT, then the symbol */
+ Huff_transmit(huff, NYT, fout, maxoffset);
+ for (i = 7; i >= 0; i--)
+ {
+ add_bit((char)((ch >> i) & 0x1), fout);
+ }
+ }
+ else
+ {
+ send(huff->loc[ch], NULL, fout, maxoffset);
+ }
+}
+
+void Huff_offsetTransmit(huff_t *huff, int ch, uint8_t *fout, int *offset, int maxoffset)
+{
+ bloc = *offset;
+ send(huff->loc[ch], NULL, fout, maxoffset);
+ *offset = bloc;
+}
+
+void Huff_Decompress(struct msg_t *mbuf, int offset)
+{
+ int ch, cch, i, j, size;
+ uint8_t seq[65536];
+ uint8_t *buffer;
+ huff_t huff;
+
+ size = mbuf->cursize - offset;
+ buffer = mbuf->data + offset;
+
+ if (size <= 0)
+ {
+ return;
+ }
+
+ memset(&huff, 0, sizeof(huff_t));
+ // Initialize the tree & list with the NYT node
+ huff.tree = huff.lhead = huff.ltail = huff.loc[NYT] = &(huff.nodeList[huff.blocNode++]);
+ huff.tree->symbol = NYT;
+ huff.tree->weight = 0;
+ huff.lhead->next = huff.lhead->prev = NULL;
+ huff.tree->parent = huff.tree->left = huff.tree->right = NULL;
+
+ cch = buffer[0] * 256 + buffer[1];
+ // don't overflow with bad messages
+ if (cch > mbuf->maxsize - offset)
+ {
+ cch = mbuf->maxsize - offset;
+ }
+ bloc = 16;
+
+ for (j = 0; j < cch; j++)
+ {
+ ch = 0;
+ // don't overflow reading from the messages
+ // FIXME: would it be better to have an overflow check in get_bit ?
+ if ((bloc >> 3) > size)
+ {
+ seq[j] = 0;
+ break;
+ }
+ Huff_Receive(huff.tree, &ch, buffer); /* Get a character */
+ if (ch == NYT)
+ { /* We got a NYT, get the symbol associated with it */
+ ch = 0;
+ for (i = 0; i < 8; i++)
+ {
+ ch = (ch << 1) + get_bit(buffer);
+ }
+ }
+
+ seq[j] = ch; /* Write symbol */
+
+ Huff_addRef(&huff, (uint8_t)ch); /* Increment node */
+ }
+ mbuf->cursize = cch + offset;
+ memcpy(mbuf->data + offset, seq, cch);
+}
+
+extern int oldsize;
+
+void Huff_Compress(struct msg_t *mbuf, int offset)
+{
+ int i, ch, size;
+ uint8_t seq[65536];
+ uint8_t *buffer;
+ huff_t huff;
+
+ size = mbuf->cursize - offset;
+ buffer = mbuf->data + +offset;
+
+ if (size <= 0)
+ {
+ return;
+ }
+
+ memset(&huff, 0, sizeof(huff_t));
+ // Add the NYT (not yet transmitted) node into the tree/list */
+ huff.tree = huff.lhead = huff.loc[NYT] = &(huff.nodeList[huff.blocNode++]);
+ huff.tree->symbol = NYT;
+ huff.tree->weight = 0;
+ huff.lhead->next = huff.lhead->prev = NULL;
+ huff.tree->parent = huff.tree->left = huff.tree->right = NULL;
+
+ seq[0] = (size >> 8);
+ seq[1] = size & 0xff;
+
+ bloc = 16;
+
+ for (i = 0; i < size; i++)
+ {
+ ch = buffer[i];
+ Huff_transmit(&huff, ch, seq, size << 3); /* Transmit symbol */
+ Huff_addRef(&huff, (uint8_t)ch); /* Do update */
+ }
+
+ bloc += 8; // next uint8_t
+
+ mbuf->cursize = (bloc >> 3) + offset;
+ memcpy(mbuf->data + offset, seq, (bloc >> 3));
+}
+
+void Huff_Init(huffman_t *huff)
+{
+ memset(&huff->compressor, 0, sizeof(huff_t));
+ memset(&huff->decompressor, 0, sizeof(huff_t));
+
+ // Initialize the tree & list with the NYT node
+ huff->decompressor.tree = huff->decompressor.lhead = huff->decompressor.ltail = huff->decompressor.loc[NYT] =
+ &(huff->decompressor.nodeList[huff->decompressor.blocNode++]);
+ huff->decompressor.tree->symbol = NYT;
+ huff->decompressor.tree->weight = 0;
+ huff->decompressor.lhead->next = huff->decompressor.lhead->prev = NULL;
+ huff->decompressor.tree->parent = huff->decompressor.tree->left = huff->decompressor.tree->right = NULL;
+
+ // Add the NYT (not yet transmitted) node into the tree/list */
+ huff->compressor.tree = huff->compressor.lhead = huff->compressor.loc[NYT] =
+ &(huff->compressor.nodeList[huff->compressor.blocNode++]);
+ huff->compressor.tree->symbol = NYT;
+ huff->compressor.tree->weight = 0;
+ huff->compressor.lhead->next = huff->compressor.lhead->prev = NULL;
+ huff->compressor.tree->parent = huff->compressor.tree->left = huff->compressor.tree->right = NULL;
+}
diff --git a/src/qcommon/huffman.h b/src/qcommon/huffman.h
new file mode 100644
index 0000000..217fb9f
--- /dev/null
+++ b/src/qcommon/huffman.h
@@ -0,0 +1,59 @@
+#ifndef QCOMMON_HUFFMAN_H
+#define QCOMMON_HUFFMAN_H 1
+
+#include <stdint.h>
+
+/* This is based on the Adaptive Huffman algorithm described in Sayood's Data
+ * Compression book. The ranks are not actually stored, but implicitly defined
+ * by the location of a node within a doubly-linked list */
+
+#define NYT HMAX /* NYT = Not Yet Transmitted */
+#define INTERNAL_NODE (HMAX + 1)
+
+typedef struct nodetype {
+ struct nodetype *left, *right, *parent; /* tree structure */
+ struct nodetype *next, *prev; /* doubly-linked list */
+ struct nodetype **head; /* highest ranked node in block */
+ int weight;
+ int symbol;
+} node_t;
+
+#define HMAX 256 /* Maximum symbol */
+
+typedef struct {
+ int blocNode;
+ int blocPtrs;
+
+ node_t *tree;
+ node_t *lhead;
+ node_t *ltail;
+ node_t *loc[HMAX + 1];
+ node_t **freelist;
+
+ node_t nodeList[768];
+ node_t *nodePtrs[768];
+} huff_t;
+
+typedef struct {
+ huff_t compressor;
+ huff_t decompressor;
+} huffman_t;
+
+void Huff_Compress(struct msg_t *buf, int offset);
+void Huff_Decompress(struct msg_t *buf, int offset);
+void Huff_Init(huffman_t *huff);
+void Huff_addRef(huff_t *huff, uint8_t ch);
+int Huff_Receive(node_t *node, int *ch, uint8_t *fin);
+void Huff_transmit(huff_t *huff, int ch, uint8_t *fout, int maxoffset);
+void Huff_offsetReceive(node_t *node, int *ch, uint8_t *fin, int *offset, int maxoffset);
+void Huff_offsetTransmit(huff_t *huff, int ch, uint8_t *fout, int *offset, int maxoffset);
+void Huff_putBit(int bit, uint8_t *fout, int *offset);
+int Huff_getBit(uint8_t *fout, int *offset);
+
+// don't use if you don't know what you're doing.
+int Huff_getBloc(void);
+void Huff_setBloc(int _bloc);
+
+extern huffman_t clientHuffTables;
+
+#endif
diff --git a/src/qcommon/ioapi.cpp b/src/qcommon/ioapi.cpp
new file mode 100644
index 0000000..0d22f9f
--- /dev/null
+++ b/src/qcommon/ioapi.cpp
@@ -0,0 +1,373 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+ part of the MiniZip project
+
+ Copyright (C) 1998-2010 Gilles Vollant
+ http://www.winimage.com/zLibDll/minizip.html
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson
+ http://result42.com
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "ioapi.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "zconf.h"
+
+#if defined(_WIN32)
+# define snprintf _snprintf
+#endif
+
+#ifdef __APPLE__
+/* In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions */
+# define FOPEN_FUNC(filename, mode) fopen(filename, mode)
+# define FTELLO_FUNC(stream) ftello(stream)
+# define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
+#else
+# define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
+# define FTELLO_FUNC(stream) ftello64(stream)
+# define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
+#endif
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+#ifndef SEEK_CUR
+# define SEEK_CUR 1
+#endif
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
+{
+ if (pfilefunc->zfile_func64.zopen64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
+ return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
+}
+
+voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, unsigned long number_disk, int mode))
+{
+ if (pfilefunc->zfile_func64.zopendisk64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zopendisk64_file)) (pfilefunc->zfile_func64.opaque,filestream,number_disk,mode);
+ return (*(pfilefunc->zopendisk32_file))(pfilefunc->zfile_func64.opaque,filestream,number_disk,mode);
+}
+
+long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)
+{
+ uLong offsetTruncated;
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
+ offsetTruncated = (uLong)offset;
+ if (offsetTruncated != offset)
+ return -1;
+ return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
+}
+
+ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)
+{
+ uLong tell_uLong;
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
+ tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
+ if ((tell_uLong) == 0xffffffff)
+ return (ZPOS64_T)-1;
+ return tell_uLong;
+}
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)
+{
+ p_filefunc64_32->zfile_func64.zopen64_file = NULL;
+ p_filefunc64_32->zfile_func64.zopendisk64_file = NULL;
+ p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
+ p_filefunc64_32->zopendisk32_file = p_filefunc32->zopendisk_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
+ p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
+ p_filefunc64_32->zfile_func64.ztell64_file = NULL;
+ p_filefunc64_32->zfile_func64.zseek64_file = NULL;
+ p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
+ p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
+ p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
+}
+
+static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));
+static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));
+static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream));
+static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream));
+static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream));
+
+typedef struct
+{
+ FILE *file;
+ int filenameLength;
+ void *filename;
+} FILE_IOPOSIX;
+
+static voidpf file_build_ioposix(FILE *file, const char *filename)
+{
+ FILE_IOPOSIX *ioposix = NULL;
+ if (file == NULL)
+ return NULL;
+ ioposix = (FILE_IOPOSIX*)malloc(sizeof(FILE_IOPOSIX));
+ ioposix->file = file;
+ ioposix->filenameLength = (int)strlen(filename) + 1;
+ ioposix->filename = (char*)malloc(ioposix->filenameLength * sizeof(char));
+ strncpy((char*)ioposix->filename, filename, ioposix->filenameLength);
+ return (voidpf)ioposix;
+}
+
+static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode)
+{
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename != NULL) && (mode_fopen != NULL))
+ {
+ file = fopen(filename, mode_fopen);
+ return file_build_ioposix(file, filename);
+ }
+ return file;
+}
+
+static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode)
+{
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename != NULL) && (mode_fopen != NULL))
+ {
+ file = FOPEN_FUNC((const char*)filename, mode_fopen);
+ return file_build_ioposix(file, (const char*)filename);
+ }
+ return file;
+}
+
+static voidpf ZCALLBACK fopendisk64_file_func (voidpf opaque, voidpf stream, unsigned long number_disk, int mode)
+{
+ FILE_IOPOSIX *ioposix = NULL;
+ char *diskFilename = NULL;
+ voidpf ret = NULL;
+ int i = 0;
+
+ if (stream == NULL)
+ return NULL;
+ ioposix = (FILE_IOPOSIX*)stream;
+ diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char));
+ strncpy(diskFilename, (const char*)ioposix->filename, ioposix->filenameLength);
+ for (i = ioposix->filenameLength - 1; i >= 0; i -= 1)
+ {
+ if (diskFilename[i] != '.')
+ continue;
+ snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02lu", number_disk + 1);
+ break;
+ }
+ if (i >= 0)
+ ret = fopen64_file_func(opaque, diskFilename, mode);
+ free(diskFilename);
+ return ret;
+}
+
+static voidpf ZCALLBACK fopendisk_file_func (voidpf opaque, voidpf stream, unsigned long number_disk, int mode)
+{
+ FILE_IOPOSIX *ioposix = NULL;
+ char *diskFilename = NULL;
+ voidpf ret = NULL;
+ int i = 0;
+
+ if (stream == NULL)
+ return NULL;
+ ioposix = (FILE_IOPOSIX*)stream;
+ diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char));
+ strncpy(diskFilename, (const char*)ioposix->filename, ioposix->filenameLength);
+ for (i = ioposix->filenameLength - 1; i >= 0; i -= 1)
+ {
+ if (diskFilename[i] != '.')
+ continue;
+ snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02lu", number_disk + 1);
+ break;
+ }
+ if (i >= 0)
+ ret = fopen_file_func(opaque, diskFilename, mode);
+ free(diskFilename);
+ return ret;
+}
+
+static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size)
+{
+ FILE_IOPOSIX *ioposix = NULL;
+ uLong ret;
+ if (stream == NULL)
+ return -1;
+ ioposix = (FILE_IOPOSIX*)stream;
+ ret = (uLong)fread(buf, 1, (size_t)size, ioposix->file);
+ return ret;
+}
+
+static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size)
+{
+ FILE_IOPOSIX *ioposix = NULL;
+ uLong ret;
+ if (stream == NULL)
+ return -1;
+ ioposix = (FILE_IOPOSIX*)stream;
+ ret = (uLong)fwrite(buf, 1, (size_t)size, ioposix->file);
+ return ret;
+}
+
+static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream)
+{
+ FILE_IOPOSIX *ioposix = NULL;
+ long ret = -1;
+ if (stream == NULL)
+ return ret;
+ ioposix = (FILE_IOPOSIX*)stream;
+ ret = ftell(ioposix->file);
+ return ret;
+}
+
+static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)
+{
+ FILE_IOPOSIX *ioposix = NULL;
+ ZPOS64_T ret = -1;
+ if (stream == NULL)
+ return ret;
+ ioposix = (FILE_IOPOSIX*)stream;
+ ret = FTELLO_FUNC(ioposix->file);
+ return ret;
+}
+
+static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin)
+{
+ FILE_IOPOSIX *ioposix = NULL;
+ int fseek_origin = 0;
+ long ret = 0;
+
+ if (stream == NULL)
+ return -1;
+ ioposix = (FILE_IOPOSIX*)stream;
+
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR:
+ fseek_origin = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END:
+ fseek_origin = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET:
+ fseek_origin = SEEK_SET;
+ break;
+ default:
+ return -1;
+ }
+ if (fseek(ioposix->file, offset, fseek_origin) != 0)
+ ret = -1;
+ return ret;
+}
+
+static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)
+{
+ FILE_IOPOSIX *ioposix = NULL;
+ int fseek_origin = 0;
+ long ret = 0;
+
+ if (stream == NULL)
+ return -1;
+ ioposix = (FILE_IOPOSIX*)stream;
+
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR:
+ fseek_origin = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END:
+ fseek_origin = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET:
+ fseek_origin = SEEK_SET;
+ break;
+ default:
+ return -1;
+ }
+
+ if(FSEEKO_FUNC(ioposix->file, offset, fseek_origin) != 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream)
+{
+ FILE_IOPOSIX *ioposix = NULL;
+ int ret = -1;
+ if (stream == NULL)
+ return ret;
+ ioposix = (FILE_IOPOSIX*)stream;
+ if (ioposix->filename != NULL)
+ free(ioposix->filename);
+ ret = fclose(ioposix->file);
+ free(ioposix);
+ return ret;
+}
+
+static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream)
+{
+ FILE_IOPOSIX *ioposix = NULL;
+ int ret = -1;
+ if (stream == NULL)
+ return ret;
+ ioposix = (FILE_IOPOSIX*)stream;
+ ret = ferror(ioposix->file);
+ return ret;
+}
+
+void fill_fopen_filefunc (zlib_filefunc_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen_file = fopen_file_func;
+ pzlib_filefunc_def->zopendisk_file = fopendisk_file_func;
+ pzlib_filefunc_def->zread_file = fread_file_func;
+ pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+ pzlib_filefunc_def->ztell_file = ftell_file_func;
+ pzlib_filefunc_def->zseek_file = fseek_file_func;
+ pzlib_filefunc_def->zclose_file = fclose_file_func;
+ pzlib_filefunc_def->zerror_file = ferror_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+
+void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen64_file = fopen64_file_func;
+ pzlib_filefunc_def->zopendisk64_file = fopendisk64_file_func;
+ pzlib_filefunc_def->zread_file = fread_file_func;
+ pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+ pzlib_filefunc_def->ztell64_file = ftell64_file_func;
+ pzlib_filefunc_def->zseek64_file = fseek64_file_func;
+ pzlib_filefunc_def->zclose_file = fclose_file_func;
+ pzlib_filefunc_def->zerror_file = ferror_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
diff --git a/src/qcommon/ioapi.h b/src/qcommon/ioapi.h
new file mode 100644
index 0000000..4b3c297
--- /dev/null
+++ b/src/qcommon/ioapi.h
@@ -0,0 +1,173 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+ part of the MiniZip project
+
+ Copyright (C) 1998-2010 Gilles Vollant
+ http://www.winimage.com/zLibDll/minizip.html
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson
+ http://result42.com
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef _ZLIBIOAPI64_H
+#define _ZLIBIOAPI64_H
+
+#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
+# ifndef __USE_FILE_OFFSET64
+# define __USE_FILE_OFFSET64
+# endif
+# ifndef __USE_LARGEFILE64
+# define __USE_LARGEFILE64
+# endif
+# ifndef _LARGEFILE64_SOURCE
+# define _LARGEFILE64_SOURCE
+# endif
+# ifndef _FILE_OFFSET_BIT
+# define _FILE_OFFSET_BIT 64
+# endif
+#endif
+
+#include "zconf.h"
+
+#if defined(USE_FILE32API)
+# define fopen64 fopen
+# define ftello64 ftell
+# define fseeko64 fseek
+#else
+# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
+# define fopen64 fopen
+# define ftello64 ftello
+# define fseeko64 fseeko
+# endif
+# ifdef _MSC_VER
+# define fopen64 fopen
+# if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
+# define ftello64 _ftelli64
+# define fseeko64 _fseeki64
+# else /* old MSC */
+# define ftello64 ftell
+# define fseeko64 fseek
+# endif
+# endif
+#endif
+
+/* a type choosen by DEFINE */
+#ifdef HAVE_64BIT_INT_CUSTOM
+typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
+#else
+# ifdef HAVE_STDINT_H
+# include "stdint.h"
+ typedef uint64_t ZPOS64_T;
+# else
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+ typedef unsigned __int64 ZPOS64_T;
+# else
+ typedef unsigned long long int ZPOS64_T;
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+
+#define ZLIB_FILEFUNC_MODE_READ (1)
+#define ZLIB_FILEFUNC_MODE_WRITE (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
+#define ZLIB_FILEFUNC_MODE_EXISTING (4)
+#define ZLIB_FILEFUNC_MODE_CREATE (8)
+
+#ifndef ZCALLBACK
+# if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) \
+ && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+# define ZCALLBACK CALLBACK
+# else
+# define ZCALLBACK
+# endif
+#endif
+
+typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
+typedef voidpf (ZCALLBACK *opendisk_file_func) OF((voidpf opaque, voidpf stream, unsigned long number_disk, int mode));
+typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
+typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
+
+typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
+typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
+
+/* here is the "old" 32 bits structure structure */
+typedef struct zlib_filefunc_def_s
+{
+ open_file_func zopen_file;
+ opendisk_file_func zopendisk_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell_file_func ztell_file;
+ seek_file_func zseek_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc_def;
+
+typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode));
+typedef voidpf (ZCALLBACK *opendisk64_file_func) OF((voidpf opaque, voidpf stream, unsigned long number_disk, int mode));
+typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream));
+typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+
+typedef struct zlib_filefunc64_def_s
+{
+ open64_file_func zopen64_file;
+ opendisk64_file_func zopendisk64_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell64_file_func ztell64_file;
+ seek64_file_func zseek64_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc64_def;
+
+void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
+void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def));
+
+/* now internal definition, only for zip.c and unzip.h */
+typedef struct zlib_filefunc64_32_def_s
+{
+ zlib_filefunc64_def zfile_func64;
+ open_file_func zopen32_file;
+ opendisk_file_func zopendisk32_file;
+ tell_file_func ztell32_file;
+ seek_file_func zseek32_file;
+} zlib_filefunc64_32_def;
+
+#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+/*#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))*/
+/*#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))*/
+#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
+#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
+
+voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode));
+voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, unsigned long number_disk, int mode));
+long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
+ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream));
+
+void fill_zlib_filefunc64_32_def_from_filefunc32 OF((zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32));
+
+#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
+#define ZOPENDISK64(filefunc,filestream,diskn,mode) (call_zopendisk64((&(filefunc)),(filestream),(diskn),(mode)))
+#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
+#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/qcommon/json.h b/src/qcommon/json.h
new file mode 100644
index 0000000..956ae84
--- /dev/null
+++ b/src/qcommon/json.h
@@ -0,0 +1,353 @@
+/*
+===========================================================================
+Copyright (C) 2016 James Canete
+Copyright (C) 2015-2019 GrangerHub
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 3
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.
+===========================================================================
+*/
+
+#ifndef JSON_H
+#define JSON_H
+
+enum
+{
+ JSONTYPE_STRING, // string
+ JSONTYPE_OBJECT, // object
+ JSONTYPE_ARRAY, // array
+ JSONTYPE_VALUE, // number, true, false, or null
+ JSONTYPE_ERROR // out of data
+};
+
+// --------------------------------------------------------------------------
+// Array Functions
+// --------------------------------------------------------------------------
+
+// Get pointer to first value in array
+// When given pointer to an array, returns pointer to the first
+// returns NULL if array is empty or not an array.
+const char *JSON_ArrayGetFirstValue(const char *json, const char *jsonEnd);
+
+// Get pointer to next value in array
+// When given pointer to a value, returns pointer to the next value
+// returns NULL when no next value.
+const char *JSON_ArrayGetNextValue(const char *json, const char *jsonEnd);
+
+// Get pointers to values in an array
+// returns 0 if not an array, array is empty, or out of data
+// returns number of values in the array and copies into index if successful
+unsigned int JSON_ArrayGetIndex(const char *json, const char *jsonEnd, const char **indexes, unsigned int numIndexes);
+
+// Get pointer to indexed value from array
+// returns NULL if not an array, no index, or out of data
+const char *JSON_ArrayGetValue(const char *json, const char *jsonEnd, unsigned int index);
+
+// --------------------------------------------------------------------------
+// Object Functions
+// --------------------------------------------------------------------------
+
+// Get pointer to named value from object
+// returns NULL if not an object, name not found, or out of data
+const char *JSON_ObjectGetNamedValue(const char *json, const char *jsonEnd, const char *name);
+
+// --------------------------------------------------------------------------
+// Value Functions
+// --------------------------------------------------------------------------
+
+// Get type of value
+// returns JSONTYPE_ERROR if out of data
+unsigned int JSON_ValueGetType(const char *json, const char *jsonEnd);
+
+// Get value as string
+// returns 0 if out of data
+// returns length and copies into string if successful, including terminating nul.
+// string values are stripped of enclosing quotes but not escaped
+unsigned int JSON_ValueGetString(const char *json, const char *jsonEnd, char *outString, unsigned int stringLen);
+
+// Get value as appropriate type
+// returns 0 if value is false, value is null, or out of data
+// returns 1 if value is true
+// returns value otherwise
+double JSON_ValueGetDouble(const char *json, const char *jsonEnd);
+float JSON_ValueGetFloat(const char *json, const char *jsonEnd);
+int JSON_ValueGetInt(const char *json, const char *jsonEnd);
+
+#endif
+
+#ifdef JSON_IMPLEMENTATION
+#include <stdio.h>
+
+// --------------------------------------------------------------------------
+// Internal Functions
+// --------------------------------------------------------------------------
+
+static const char *JSON_SkipSeparators(const char *json, const char *jsonEnd);
+static const char *JSON_SkipString(const char *json, const char *jsonEnd);
+static const char *JSON_SkipStruct(const char *json, const char *jsonEnd);
+static const char *JSON_SkipValue(const char *json, const char *jsonEnd);
+static const char *JSON_SkipValueAndSeparators(const char *json, const char *jsonEnd);
+
+#define IS_SEPARATOR(x) ((x) == ' ' || (x) == '\t' || (x) == '\n' || (x) == '\r' || (x) == ',' || (x) == ':')
+#define IS_STRUCT_OPEN(x) ((x) == '{' || (x) == '[')
+#define IS_STRUCT_CLOSE(x) ((x) == '}' || (x) == ']')
+
+static const char *JSON_SkipSeparators(const char *json, const char *jsonEnd)
+{
+ while (json < jsonEnd && IS_SEPARATOR(*json))
+ json++;
+
+ return json;
+}
+
+static const char *JSON_SkipString(const char *json, const char *jsonEnd)
+{
+ for (json++; json < jsonEnd && *json != '"'; json++)
+ if (*json == '\\')
+ json++;
+
+ return (json + 1 > jsonEnd) ? jsonEnd : json + 1;
+}
+
+static const char *JSON_SkipStruct(const char *json, const char *jsonEnd)
+{
+ json = JSON_SkipSeparators(json + 1, jsonEnd);
+ while (json < jsonEnd && !IS_STRUCT_CLOSE(*json))
+ json = JSON_SkipValueAndSeparators(json, jsonEnd);
+
+ return (json + 1 > jsonEnd) ? jsonEnd : json + 1;
+}
+
+static const char *JSON_SkipValue(const char *json, const char *jsonEnd)
+{
+ if (json >= jsonEnd)
+ return jsonEnd;
+ else if (*json == '"')
+ json = JSON_SkipString(json, jsonEnd);
+ else if (IS_STRUCT_OPEN(*json))
+ json = JSON_SkipStruct(json, jsonEnd);
+ else
+ {
+ while (json < jsonEnd && !IS_SEPARATOR(*json) && !IS_STRUCT_CLOSE(*json))
+ json++;
+ }
+
+ return json;
+}
+
+static const char *JSON_SkipValueAndSeparators(const char *json, const char *jsonEnd)
+{
+ json = JSON_SkipValue(json, jsonEnd);
+ return JSON_SkipSeparators(json, jsonEnd);
+}
+
+// returns 0 if value requires more parsing, 1 if no more data/false/null, 2 if true
+static unsigned int JSON_NoParse(const char *json, const char *jsonEnd)
+{
+ if (!json || json >= jsonEnd || *json == 'f' || *json == 'n')
+ return 1;
+
+ if (*json == 't')
+ return 2;
+
+ return 0;
+}
+
+// --------------------------------------------------------------------------
+// Array Functions
+// --------------------------------------------------------------------------
+
+const char *JSON_ArrayGetFirstValue(const char *json, const char *jsonEnd)
+{
+ if (!json || json >= jsonEnd || !IS_STRUCT_OPEN(*json))
+ return NULL;
+
+ json = JSON_SkipSeparators(json + 1, jsonEnd);
+
+ return (json >= jsonEnd || IS_STRUCT_CLOSE(*json)) ? NULL : json;
+}
+
+const char *JSON_ArrayGetNextValue(const char *json, const char *jsonEnd)
+{
+ if (!json || json >= jsonEnd || IS_STRUCT_CLOSE(*json))
+ return NULL;
+
+ json = JSON_SkipValueAndSeparators(json, jsonEnd);
+
+ return (json >= jsonEnd || IS_STRUCT_CLOSE(*json)) ? NULL : json;
+}
+
+unsigned int JSON_ArrayGetIndex(const char *json, const char *jsonEnd, const char **indexes, unsigned int numIndexes)
+{
+ unsigned int length = 0;
+
+ for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json; json = JSON_ArrayGetNextValue(json, jsonEnd))
+ {
+ if (indexes && numIndexes)
+ {
+ *indexes++ = json;
+ numIndexes--;
+ }
+ length++;
+ }
+
+ return length;
+}
+
+const char *JSON_ArrayGetValue(const char *json, const char *jsonEnd, unsigned int index)
+{
+ for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json && index; json = JSON_ArrayGetNextValue(json, jsonEnd))
+ index--;
+
+ return json;
+}
+
+// --------------------------------------------------------------------------
+// Object Functions
+// --------------------------------------------------------------------------
+
+const char *JSON_ObjectGetNamedValue(const char *json, const char *jsonEnd, const char *name)
+{
+ unsigned int nameLen = strlen(name);
+
+ for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json; json = JSON_ArrayGetNextValue(json, jsonEnd))
+ {
+ if (*json == '"')
+ {
+ const char *thisNameStart, *thisNameEnd;
+
+ thisNameStart = json + 1;
+ json = JSON_SkipString(json, jsonEnd);
+ thisNameEnd = json - 1;
+ json = JSON_SkipSeparators(json, jsonEnd);
+
+ if ((unsigned int)(thisNameEnd - thisNameStart) == nameLen)
+ if (strncmp(thisNameStart, name, nameLen) == 0)
+ return json;
+ }
+ }
+
+ return NULL;
+}
+
+// --------------------------------------------------------------------------
+// Value Functions
+// --------------------------------------------------------------------------
+
+unsigned int JSON_ValueGetType(const char *json, const char *jsonEnd)
+{
+ if (!json || json >= jsonEnd)
+ return JSONTYPE_ERROR;
+ else if (*json == '"')
+ return JSONTYPE_STRING;
+ else if (*json == '{')
+ return JSONTYPE_OBJECT;
+ else if (*json == '[')
+ return JSONTYPE_ARRAY;
+
+ return JSONTYPE_VALUE;
+}
+
+unsigned int JSON_ValueGetString(const char *json, const char *jsonEnd, char *outString, unsigned int stringLen)
+{
+ const char *stringEnd, *stringStart;
+
+ if (!json)
+ {
+ *outString = '\0';
+ return 0;
+ }
+
+ stringStart = json;
+ stringEnd = JSON_SkipValue(stringStart, jsonEnd);
+ if (stringEnd >= jsonEnd)
+ {
+ *outString = '\0';
+ return 0;
+ }
+
+ // skip enclosing quotes if they exist
+ if (*stringStart == '"')
+ stringStart++;
+
+ if (*(stringEnd - 1) == '"')
+ stringEnd--;
+
+ stringLen--;
+ if (stringLen > stringEnd - stringStart)
+ stringLen = stringEnd - stringStart;
+
+ json = stringStart;
+ while (stringLen--)
+ *outString++ = *json++;
+ *outString = '\0';
+
+ return stringEnd - stringStart;
+}
+
+double JSON_ValueGetDouble(const char *json, const char *jsonEnd)
+{
+ char cValue[256];
+ double dValue = 0.0;
+ unsigned int np = JSON_NoParse(json, jsonEnd);
+
+ if (np)
+ return (double)(np - 1);
+
+ if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+ return 0.0;
+
+ sscanf(cValue, "%lf", &dValue);
+
+ return dValue;
+}
+
+float JSON_ValueGetFloat(const char *json, const char *jsonEnd)
+{
+ char cValue[256];
+ float fValue = 0.0f;
+ unsigned int np = JSON_NoParse(json, jsonEnd);
+
+ if (np)
+ return (float)(np - 1);
+
+ if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+ return 0.0f;
+
+ sscanf(cValue, "%f", &fValue);
+
+ return fValue;
+}
+
+int JSON_ValueGetInt(const char *json, const char *jsonEnd)
+{
+ char cValue[256];
+ int iValue = 0;
+ unsigned int np = JSON_NoParse(json, jsonEnd);
+
+ if (np)
+ return np - 1;
+
+ if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+ return 0;
+
+ sscanf(cValue, "%d", &iValue);
+
+ return iValue;
+}
+
+#undef IS_SEPARATOR
+#undef IS_STRUCT_OPEN
+#undef IS_STRUCT_CLOSE
+
+#endif
diff --git a/src/qcommon/md4.cpp b/src/qcommon/md4.cpp
new file mode 100644
index 0000000..1b212f3
--- /dev/null
+++ b/src/qcommon/md4.cpp
@@ -0,0 +1,202 @@
+/*
+ mdfour.c
+
+ An implementation of MD4 designed for use in the samba SMB
+ authentication protocol
+
+ Copyright (C) 1997-1998 Andrew Tridgell
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ $Id: mdfour.c,v 1.1 2002/08/23 22:03:27 abster Exp $
+*/
+
+#include "cvar.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+struct mdfour {
+ uint32_t A, B, C, D;
+ uint32_t totalN;
+};
+
+
+/* NOTE: This code makes no attempt to be fast!
+
+ It assumes that an int is at least 32 bits long
+ */
+
+static struct mdfour *m;
+
+#define F(X,Y,Z) (((X)&(Y)) | ((~(X))&(Z)))
+#define G(X,Y,Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)))
+#define H(X,Y,Z) ((X)^(Y)^(Z))
+#define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s))))
+
+#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999,s)
+#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s)
+
+/* this applies md4 to 64 byte chunks */
+static void mdfour64(uint32_t *M)
+{
+ int j;
+ uint32_t AA, BB, CC, DD;
+ uint32_t X[16];
+ uint32_t A,B,C,D;
+
+ for (j=0;j<16;j++)
+ X[j] = M[j];
+
+ A = m->A; B = m->B; C = m->C; D = m->D;
+ AA = A; BB = B; CC = C; DD = D;
+
+ ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
+ ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
+ ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
+ ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
+ ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
+ ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
+ ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
+ ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
+
+ ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
+ ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
+ ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
+ ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
+ ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
+ ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
+ ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
+ ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
+
+ ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
+ ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
+ ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
+ ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
+ ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
+ ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
+ ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
+ ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
+
+ A += AA; B += BB; C += CC; D += DD;
+
+ for (j=0;j<16;j++)
+ X[j] = 0;
+
+ m->A = A; m->B = B; m->C = C; m->D = D;
+}
+
+static void copy64(uint32_t *M, byte *in)
+{
+ int i;
+
+ for (i=0;i<16;i++)
+ M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) | (in[i*4+1]<<8) | (in[i*4+0]<<0);
+}
+
+static void copy4(byte *out,uint32_t x)
+{
+ out[0] = x&0xFF;
+ out[1] = (x>>8)&0xFF;
+ out[2] = (x>>16)&0xFF;
+ out[3] = (x>>24)&0xFF;
+}
+
+void mdfour_begin(struct mdfour *md)
+{
+ md->A = 0x67452301;
+ md->B = 0xefcdab89;
+ md->C = 0x98badcfe;
+ md->D = 0x10325476;
+ md->totalN = 0;
+}
+
+
+static void mdfour_tail(byte *in, int n)
+{
+ byte buf[128];
+ uint32_t M[16];
+ uint32_t b;
+
+ m->totalN += n;
+
+ b = m->totalN * 8;
+
+ memset(buf, 0, 128);
+ if (n) memcpy(buf, in, n);
+ buf[n] = 0x80;
+
+ if (n <= 55) {
+ copy4(buf+56, b);
+ copy64(M, buf);
+ mdfour64(M);
+ } else {
+ copy4(buf+120, b);
+ copy64(M, buf);
+ mdfour64(M);
+ copy64(M, buf+64);
+ mdfour64(M);
+ }
+}
+
+static void mdfour_update(struct mdfour *md, byte *in, int n)
+{
+ uint32_t M[16];
+
+ m = md;
+
+ if (n == 0) mdfour_tail(in, n);
+
+ while (n >= 64) {
+ copy64(M, in);
+ mdfour64(M);
+ in += 64;
+ n -= 64;
+ m->totalN += 64;
+ }
+
+ mdfour_tail(in, n);
+}
+
+
+static void mdfour_result(struct mdfour *md, byte *out)
+{
+ copy4(out, md->A);
+ copy4(out+4, md->B);
+ copy4(out+8, md->C);
+ copy4(out+12, md->D);
+}
+
+static void mdfour(byte *out, byte *in, int n)
+{
+ struct mdfour md;
+ mdfour_begin(&md);
+ mdfour_update(&md, in, n);
+ mdfour_result(&md, out);
+}
+
+//===================================================================
+
+unsigned Com_BlockChecksum (const void *buffer, int length)
+{
+ int digest[4];
+ unsigned val;
+
+ mdfour( (byte *)digest, (byte *)buffer, length );
+
+ val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
+
+ return val;
+}
diff --git a/src/qcommon/md4.h b/src/qcommon/md4.h
new file mode 100644
index 0000000..cbb8166
--- /dev/null
+++ b/src/qcommon/md4.h
@@ -0,0 +1,6 @@
+#ifndef QCOMMON_MD4_H
+#define QCOMMON_MD4_H
+
+unsigned Com_BlockChecksum( const void *buffer, int length );
+
+#endif
diff --git a/src/qcommon/md5.cpp b/src/qcommon/md5.cpp
new file mode 100644
index 0000000..a8e8c58
--- /dev/null
+++ b/src/qcommon/md5.cpp
@@ -0,0 +1,312 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include "files.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+typedef struct MD5Context {
+ uint32_t buf[4];
+ uint32_t bits[2];
+ unsigned char in[64];
+} MD5_CTX;
+
+#ifndef Q3_BIG_ENDIAN
+ #define byteReverse(buf, len) /* Nothing */
+#else
+ static void byteReverse(unsigned char *buf, unsigned longs);
+
+ /*
+ * Note: this code is harmless on little-endian machines.
+ */
+ static void byteReverse(unsigned char *buf, unsigned longs)
+ {
+ uint32_t t;
+ do {
+ t = (uint32_t)
+ ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32_t *) buf = t;
+ buf += 4;
+ } while (--longs);
+ }
+#endif // Q3_BIG_ENDIAN
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+static void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(uint32_t buf[4],
+ uint32_t const in[16])
+{
+ uint32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void MD5Update(struct MD5Context *ctx, unsigned char const *buf,
+ unsigned len)
+{
+ uint32_t t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+static void MD5Final(struct MD5Context *ctx, unsigned char *digest)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32_t *) ctx->in)[14] = ctx->bits[0];
+ ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+
+ if (digest!=NULL)
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+}
+
+
+char *Com_MD5File( const char *fn, int length, const char *prefix, int prefix_len )
+{
+ static char final[33] = {""};
+ unsigned char digest[16] = {""};
+ fileHandle_t f;
+ MD5_CTX md5;
+ byte buffer[2048];
+ int i;
+ int filelen = 0;
+ int r = 0;
+ int total = 0;
+
+ Q_strncpyz( final, "", sizeof( final ) );
+
+ filelen = FS_SV_FOpenFileRead( fn, &f );
+
+ if( !f ) {
+ return final;
+ }
+ if( filelen < 1 ) {
+ FS_FCloseFile( f );
+ return final;
+ }
+ if(filelen < length || !length) {
+ length = filelen;
+ }
+
+ MD5Init(&md5);
+
+ if( prefix_len && *prefix )
+ MD5Update(&md5 , (unsigned char *)prefix, prefix_len);
+
+ for(;;) {
+ r = FS_Read(buffer, sizeof(buffer), f);
+ if(r < 1)
+ break;
+ if(r + total > length)
+ r = length - total;
+ total += r;
+ MD5Update(&md5 , buffer, r);
+ if(r < sizeof(buffer) || total >= length)
+ break;
+ }
+ FS_FCloseFile(f);
+ MD5Final(&md5, digest);
+ final[0] = '\0';
+ for(i = 0; i < 16; i++) {
+ Q_strcat(final, sizeof(final), va("%02X", digest[i]));
+ }
+ return final;
+}
diff --git a/src/qcommon/msg.cpp b/src/qcommon/msg.cpp
new file mode 100644
index 0000000..fc4a62a
--- /dev/null
+++ b/src/qcommon/msg.cpp
@@ -0,0 +1,2248 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "msg.h"
+
+#include "alternatePlayerstate.h"
+#include "cvar.h"
+#include "huffman.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+static huffman_t msgHuff;
+
+static bool msgInit = false;
+
+int pcount[256];
+
+/*
+==============================================================================
+
+ MESSAGE IO FUNCTIONS
+
+Handles uint8_t ordering and avoids alignment errors
+==============================================================================
+*/
+
+int oldsize = 0;
+
+void MSG_initHuffman(void);
+
+void MSG_Init(msg_t *buf, uint8_t *data, int length)
+{
+ if (!msgInit)
+ {
+ MSG_initHuffman();
+ }
+ ::memset(buf, 0, sizeof(*buf));
+ buf->data = data;
+ buf->maxsize = length;
+}
+
+void MSG_InitOOB(msg_t *buf, uint8_t *data, int length)
+{
+ if (!msgInit)
+ {
+ MSG_initHuffman();
+ }
+ ::memset(buf, 0, sizeof(*buf));
+ buf->data = data;
+ buf->maxsize = length;
+ buf->oob = true;
+}
+
+void MSG_Clear(msg_t *buf)
+{
+ buf->cursize = 0;
+ buf->overflowed = false;
+ buf->bit = 0; //<- in bits
+}
+
+void MSG_Bitstream(msg_t *buf) { buf->oob = false; }
+void MSG_BeginReading(msg_t *msg)
+{
+ msg->readcount = 0;
+ msg->bit = 0;
+ msg->oob = false;
+}
+
+void MSG_BeginReadingOOB(msg_t *msg)
+{
+ msg->readcount = 0;
+ msg->bit = 0;
+ msg->oob = true;
+}
+
+void MSG_Copy(msg_t *buf, uint8_t *data, int length, msg_t *src)
+{
+ if (length < src->cursize)
+ {
+ Com_Error(ERR_DROP, "MSG_Copy: can't copy into a smaller msg_t buffer");
+ }
+ ::memcpy(buf, src, sizeof(msg_t));
+ buf->data = data;
+ ::memcpy(buf->data, src->data, src->cursize);
+}
+
+/*
+=============================================================================
+
+bit functions
+
+=============================================================================
+*/
+
+int overflows;
+
+// negative bit values include signs
+void MSG_WriteBits(msg_t *msg, int value, int bits)
+{
+ int i;
+ //FILE* fp;
+
+ oldsize += bits;
+
+ if ( msg->overflowed )
+ {
+ return;
+ }
+
+ if (bits == 0 || bits < -31 || bits > 32)
+ {
+ Com_Error(ERR_DROP, "MSG_WriteBits: bad bits %i", bits);
+ }
+
+ // check for overflows
+ if (bits != 32)
+ {
+ if (bits > 0)
+ {
+ if (value > ((1 << bits) - 1) || value < 0)
+ {
+ overflows++;
+ }
+ }
+ else
+ {
+ int r;
+
+ r = 1 << (bits - 1);
+
+ if (value > r - 1 || value < -r)
+ {
+ overflows++;
+ }
+ }
+ }
+ if (bits < 0)
+ {
+ bits = -bits;
+ }
+ if (msg->oob)
+ {
+ if (msg->cursize + (bits >> 3) > msg->maxsize)
+ {
+ msg->overflowed = true;
+ return;
+ }
+ if (bits == 8)
+ {
+ msg->data[msg->cursize] = value;
+ msg->cursize += 1;
+ msg->bit += 8;
+ }
+ else if (bits == 16)
+ {
+ short temp = value;
+
+ CopyLittleShort(&msg->data[msg->cursize], &temp);
+ msg->cursize += 2;
+ msg->bit += 16;
+ }
+ else if (bits == 32)
+ {
+ CopyLittleLong(&msg->data[msg->cursize], &value);
+ msg->cursize += 4;
+ msg->bit += 32;
+ }
+ else
+ Com_Error(ERR_DROP, "can't write %d bits", bits);
+ }
+ else
+ {
+ value &= (0xffffffff >> (32 - bits));
+ if (bits & 7)
+ {
+ int nbits;
+ nbits = bits & 7;
+
+ if ( msg->bit + nbits > msg->maxsize << 3 )
+ {
+ msg->overflowed = true;
+ return;
+ }
+
+ for (i = 0; i < nbits; i++)
+ {
+ Huff_putBit((value & 1), msg->data, &msg->bit);
+ value = (value >> 1);
+ }
+ bits = bits - nbits;
+ }
+ if (bits)
+ {
+ for (i = 0; i < bits; i += 8)
+ {
+ Huff_offsetTransmit(&msgHuff.compressor, (value & 0xff), msg->data, &msg->bit, msg->maxsize << 3);
+ value = (value >> 8);
+
+ if (msg->bit > msg->maxsize << 3)
+ {
+ msg->overflowed = true;
+ return;
+ }
+ }
+ }
+ msg->cursize = (msg->bit >> 3) + 1;
+ }
+}
+
+int MSG_ReadBits(msg_t *msg, int bits)
+{
+ int value;
+ int get;
+ bool sgn;
+
+
+ if (msg->readcount > msg->cursize)
+ {
+ return 0;
+ }
+
+ value = 0;
+
+ if (bits < 0)
+ {
+ bits = -bits;
+ sgn = true;
+ }
+ else
+ {
+ sgn = false;
+ }
+
+ if (msg->oob)
+ {
+ if (msg->readcount + (bits >> 3) > msg->cursize)
+ {
+ msg->readcount = msg->cursize + 1;
+ return 0;
+ }
+
+ if (bits == 8)
+ {
+ value = msg->data[msg->readcount];
+ msg->readcount += 1;
+ msg->bit += 8;
+ }
+ else if (bits == 16)
+ {
+ short temp;
+
+ CopyLittleShort(&temp, &msg->data[msg->readcount]);
+ value = temp;
+ msg->readcount += 2;
+ msg->bit += 16;
+ }
+ else if (bits == 32)
+ {
+ CopyLittleLong(&value, &msg->data[msg->readcount]);
+ msg->readcount += 4;
+ msg->bit += 32;
+ }
+ else
+ Com_Error(ERR_DROP, "can't read %d bits", bits);
+ }
+ else
+ {
+ int nbits = 0;
+ if (bits & 7)
+ {
+ nbits = bits & 7;
+ if (msg->bit + nbits > msg->cursize << 3)
+ {
+ msg->readcount = msg->cursize + 1;
+ return 0;
+ }
+ for (int i = 0; i < nbits; i++)
+ {
+ value |= (Huff_getBit(msg->data, &msg->bit) << i);
+ }
+ bits = bits - nbits;
+ }
+ if (bits)
+ {
+ for (int i = 0; i < bits; i += 8)
+ {
+ Huff_offsetReceive(msgHuff.decompressor.tree, &get, msg->data, &msg->bit, msg->cursize << 3);
+ value |= (get << (i + nbits));
+
+ if (msg->bit > msg->cursize << 3)
+ {
+ msg->readcount = msg->cursize + 1;
+ return 0;
+ }
+ }
+ }
+ msg->readcount = (msg->bit >> 3) + 1;
+ }
+ if (sgn && bits > 0 && bits < 32)
+ {
+ if (value & (1 << (bits - 1)))
+ {
+ value |= -1 ^ ((1 << bits) - 1);
+ }
+ }
+
+ return value;
+}
+
+//================================================================================
+
+//
+// writing functions
+//
+
+void MSG_WriteChar(msg_t *sb, int c)
+{
+#ifdef PARANOID
+ if (c < -128 || c > 127) Com_Error(ERR_FATAL, "MSG_WriteChar: range error");
+#endif
+
+ MSG_WriteBits(sb, c, 8);
+}
+
+void MSG_WriteByte(msg_t *sb, int c)
+{
+#ifdef PARANOID
+ if (c < 0 || c > 255) Com_Error(ERR_FATAL, "MSG_WriteByte: range error");
+#endif
+
+ MSG_WriteBits(sb, c, 8);
+}
+
+void MSG_WriteData(msg_t *buf, const void *data, int length)
+{
+ int i;
+ for (i = 0; i < length; i++)
+ {
+ MSG_WriteByte(buf, ((uint8_t *)data)[i]);
+ }
+}
+
+void MSG_WriteShort(msg_t *sb, int c)
+{
+#ifdef PARANOID
+ if (c < ((short)0x8000) || c > (short)0x7fff) Com_Error(ERR_FATAL, "MSG_WriteShort: range error");
+#endif
+
+ MSG_WriteBits(sb, c, 16);
+}
+
+void MSG_WriteLong(msg_t *sb, int c) { MSG_WriteBits(sb, c, 32); }
+void MSG_WriteFloat(msg_t *sb, float f)
+{
+ floatint_t dat;
+ dat.f = f;
+ MSG_WriteBits(sb, dat.i, 32);
+}
+
+static void MSG_WriteString2(msg_t *sb, const char *s, int maxsize)
+{
+ int size = strlen(s) + 1;
+
+ if (size > maxsize)
+ {
+ Com_Printf("MSG_WriteString2: %i > %i\n", size, maxsize);
+ MSG_WriteData(sb, "", 1);
+ return;
+ }
+
+ MSG_WriteData(sb, s, size);
+}
+
+void MSG_WriteString(msg_t *sb, const char *s) { MSG_WriteString2(sb, s, MAX_STRING_CHARS); }
+void MSG_WriteBigString(msg_t *sb, const char *s) { MSG_WriteString2(sb, s, BIG_INFO_STRING); }
+void MSG_WriteAngle(msg_t *sb, float f) { MSG_WriteByte(sb, (int)(f * 256 / 360) & 255); }
+void MSG_WriteAngle16(msg_t *sb, float f) { MSG_WriteShort(sb, ANGLE2SHORT(f)); }
+//============================================================
+
+//
+// reading functions
+//
+
+// returns -1 if no more characters are available
+int MSG_ReadChar(msg_t *msg)
+{
+ int c;
+
+ c = (signed char)MSG_ReadBits(msg, 8);
+ if (msg->readcount > msg->cursize)
+ {
+ c = -1;
+ }
+
+ return c;
+}
+
+int MSG_ReadByte(msg_t *msg)
+{
+ int c;
+
+ c = (unsigned char)MSG_ReadBits(msg, 8);
+ if (msg->readcount > msg->cursize)
+ {
+ c = -1;
+ }
+ return c;
+}
+
+int MSG_LookaheadByte(msg_t *msg)
+{
+ const int bloc = Huff_getBloc();
+ const int readcount = msg->readcount;
+ const int bit = msg->bit;
+ int c = MSG_ReadByte(msg);
+ Huff_setBloc(bloc);
+ msg->readcount = readcount;
+ msg->bit = bit;
+ return c;
+}
+
+int MSG_ReadShort(msg_t *msg)
+{
+ int c;
+
+ c = (short)MSG_ReadBits(msg, 16);
+ if (msg->readcount > msg->cursize)
+ {
+ c = -1;
+ }
+
+ return c;
+}
+
+int MSG_ReadLong(msg_t *msg)
+{
+ int c;
+
+ c = MSG_ReadBits(msg, 32);
+ if (msg->readcount > msg->cursize)
+ {
+ c = -1;
+ }
+
+ return c;
+}
+
+float MSG_ReadFloat(msg_t *msg)
+{
+ floatint_t dat;
+
+ dat.i = MSG_ReadBits(msg, 32);
+ if (msg->readcount > msg->cursize)
+ {
+ dat.f = -1;
+ }
+
+ return dat.f;
+}
+
+char *MSG_ReadString(msg_t *msg)
+{
+ static char string[MAX_STRING_CHARS];
+
+ size_t l = 0;
+ do
+ {
+ int c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
+ if (c == -1 || c == 0)
+ {
+ break;
+ }
+
+ string[l] = c;
+ l++;
+ } while (l < sizeof(string) - 1);
+
+ string[l] = 0;
+
+ return string;
+}
+
+char *MSG_ReadBigString(msg_t *msg)
+{
+ static char string[BIG_INFO_STRING];
+
+ size_t l = 0;
+ do
+ {
+ int c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
+ if (c == -1 || c == 0)
+ {
+ break;
+ }
+
+ string[l] = c;
+ l++;
+ } while (l < sizeof(string) - 1);
+
+ string[l] = 0;
+
+ return string;
+}
+
+char *MSG_ReadStringLine(msg_t *msg)
+{
+ static char string[MAX_STRING_CHARS];
+
+ size_t l = 0;
+ do
+ {
+ int c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
+ if (c == -1 || c == 0 || c == '\n')
+ {
+ break;
+ }
+
+ string[l] = c;
+ l++;
+ } while (l < sizeof(string) - 1);
+
+ string[l] = 0;
+
+ return string;
+}
+
+float MSG_ReadAngle16(msg_t *msg) { return SHORT2ANGLE(MSG_ReadShort(msg)); }
+void MSG_ReadData(msg_t *msg, void *data, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ ((uint8_t *)data)[i] = MSG_ReadByte(msg);
+ }
+}
+
+// a string hasher which gives the same hash value even if the
+// string is later modified via the legacy MSG read/write code
+int MSG_HashKey(int alternateProtocol, const char *string, int maxlen)
+{
+ int hash, i;
+
+ hash = 0;
+ for (i = 0; i < maxlen && string[i] != '\0'; i++)
+ {
+ if (string[i] & 0x80 || (alternateProtocol == 2 && string[i] == '%'))
+ hash += '.' * (119 + i);
+ else
+ hash += string[i] * (119 + i);
+ }
+ hash = (hash ^ (hash >> 10) ^ (hash >> 20));
+ return hash;
+}
+
+/*
+=============================================================================
+
+delta functions
+
+=============================================================================
+*/
+
+extern cvar_t *cl_shownet;
+
+#define LOG(x) \
+ if (cl_shownet && cl_shownet->integer == 4) \
+ { \
+ Com_Printf("%s ", x); \
+ };
+
+void MSG_WriteDelta(msg_t *msg, int oldV, int newV, int bits)
+{
+ if (oldV == newV)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ return;
+ }
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, newV, bits);
+}
+
+int MSG_ReadDelta(msg_t *msg, int oldV, int bits)
+{
+ if (MSG_ReadBits(msg, 1))
+ {
+ return MSG_ReadBits(msg, bits);
+ }
+ return oldV;
+}
+
+void MSG_WriteDeltaFloat(msg_t *msg, float oldV, float newV)
+{
+ floatint_t fi;
+ if (oldV == newV)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ return;
+ }
+ fi.f = newV;
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, fi.i, 32);
+}
+
+float MSG_ReadDeltaFloat(msg_t *msg, float oldV)
+{
+ if (MSG_ReadBits(msg, 1))
+ {
+ floatint_t fi;
+
+ fi.i = MSG_ReadBits(msg, 32);
+ return fi.f;
+ }
+ return oldV;
+}
+
+/*
+=============================================================================
+
+delta functions with keys
+
+=============================================================================
+*/
+
+unsigned int kbitmask[32] = {
+ 0x00000001, 0x00000003, 0x00000007, 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, 0x000001FF,
+ 0x000003FF, 0x000007FF, 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, 0x0001FFFF, 0x0003FFFF,
+ 0x0007FFFF, 0x000FFFFF, 0x001FFFFf, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
+ 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
+};
+
+void MSG_WriteDeltaKey(msg_t *msg, int key, int oldV, int newV, int bits)
+{
+ if (oldV == newV)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ return;
+ }
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, newV ^ key, bits);
+}
+
+int MSG_ReadDeltaKey(msg_t *msg, int key, int oldV, int bits)
+{
+ if (MSG_ReadBits(msg, 1))
+ {
+ return MSG_ReadBits(msg, bits) ^ (key & kbitmask[bits - 1]);
+ }
+ return oldV;
+}
+
+void MSG_WriteDeltaKeyFloat(msg_t *msg, int key, float oldV, float newV)
+{
+ floatint_t fi;
+ if (oldV == newV)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ return;
+ }
+ fi.f = newV;
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, fi.i ^ key, 32);
+}
+
+float MSG_ReadDeltaKeyFloat(msg_t *msg, int key, float oldV)
+{
+ if (MSG_ReadBits(msg, 1))
+ {
+ floatint_t fi;
+
+ fi.i = MSG_ReadBits(msg, 32) ^ key;
+ return fi.f;
+ }
+ return oldV;
+}
+
+/*
+============================================================================
+
+usercmd_t communication
+
+============================================================================
+*/
+
+/*
+=====================
+MSG_WriteDeltaUsercmdKey
+=====================
+*/
+void MSG_WriteDeltaUsercmdKey(msg_t *msg, int key, usercmd_t *from, usercmd_t *to)
+{
+ if (to->serverTime - from->serverTime < 256)
+ {
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, to->serverTime - from->serverTime, 8);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 0, 1);
+ MSG_WriteBits(msg, to->serverTime, 32);
+ }
+ if ( from->angles[0] == to->angles[0]
+ && from->angles[1] == to->angles[1]
+ && from->angles[2] == to->angles[2]
+ && from->forwardmove == to->forwardmove
+ && from->rightmove == to->rightmove
+ && from->upmove == to->upmove
+ && from->buttons == to->buttons
+ && from->weapon == to->weapon )
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ oldsize += 7;
+ return;
+ }
+ key ^= to->serverTime;
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteDeltaKey(msg, key, from->angles[0], to->angles[0], 16);
+ MSG_WriteDeltaKey(msg, key, from->angles[1], to->angles[1], 16);
+ MSG_WriteDeltaKey(msg, key, from->angles[2], to->angles[2], 16);
+ MSG_WriteDeltaKey(msg, key, from->forwardmove, to->forwardmove, 8);
+ MSG_WriteDeltaKey(msg, key, from->rightmove, to->rightmove, 8);
+ MSG_WriteDeltaKey(msg, key, from->upmove, to->upmove, 8);
+ MSG_WriteDeltaKey(msg, key, from->buttons, to->buttons, 16);
+ MSG_WriteDeltaKey(msg, key, from->weapon, to->weapon, 8);
+}
+
+/*
+=====================
+MSG_ReadDeltaUsercmdKey
+=====================
+*/
+void MSG_ReadDeltaUsercmdKey(msg_t *msg, int key, usercmd_t *from, usercmd_t *to)
+{
+ if (MSG_ReadBits(msg, 1))
+ {
+ to->serverTime = from->serverTime + MSG_ReadBits(msg, 8);
+ }
+ else
+ {
+ to->serverTime = MSG_ReadBits(msg, 32);
+ }
+ if (MSG_ReadBits(msg, 1))
+ {
+ key ^= to->serverTime;
+ to->angles[0] = MSG_ReadDeltaKey(msg, key, from->angles[0], 16);
+ to->angles[1] = MSG_ReadDeltaKey(msg, key, from->angles[1], 16);
+ to->angles[2] = MSG_ReadDeltaKey(msg, key, from->angles[2], 16);
+ to->forwardmove = MSG_ReadDeltaKey(msg, key, from->forwardmove, 8);
+ if (to->forwardmove == -128) to->forwardmove = -127;
+ to->rightmove = MSG_ReadDeltaKey(msg, key, from->rightmove, 8);
+ if (to->rightmove == -128) to->rightmove = -127;
+ to->upmove = MSG_ReadDeltaKey(msg, key, from->upmove, 8);
+ if (to->upmove == -128) to->upmove = -127;
+ to->buttons = MSG_ReadDeltaKey(msg, key, from->buttons, 16);
+ to->weapon = MSG_ReadDeltaKey(msg, key, from->weapon, 8);
+ }
+ else
+ {
+ to->angles[0] = from->angles[0];
+ to->angles[1] = from->angles[1];
+ to->angles[2] = from->angles[2];
+ to->forwardmove = from->forwardmove;
+ to->rightmove = from->rightmove;
+ to->upmove = from->upmove;
+ to->buttons = from->buttons;
+ to->weapon = from->weapon;
+ }
+}
+
+/*
+=============================================================================
+
+entityState_t communication
+
+=============================================================================
+*/
+
+/*
+=================
+MSG_ReportChangeVectors_f
+
+Prints out a table from the current statistics for copying to code
+=================
+*/
+void MSG_ReportChangeVectors_f(void)
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ {
+ if (pcount[i])
+ {
+ Com_Printf("%d used %d\n", i, pcount[i]);
+ }
+ }
+}
+
+typedef struct {
+ const char *name;
+ size_t offset;
+ int bits; // 0 = float
+} netField_t;
+
+// using the stringizing operator to save typing...
+#define NETF(x) #x, (size_t) & ((entityState_t *) 0)->x
+
+netField_t entityStateFields[] = {
+ {NETF(pos.trTime), 32},
+ {NETF(pos.trBase[0]), 0},
+ {NETF(pos.trBase[1]), 0},
+ {NETF(pos.trDelta[0]), 0},
+ {NETF(pos.trDelta[1]), 0},
+ {NETF(pos.trBase[2]), 0},
+ {NETF(apos.trBase[1]), 0},
+ {NETF(pos.trDelta[2]), 0},
+ {NETF(apos.trBase[0]), 0},
+ {NETF(event), 10},
+ {NETF(angles2[1]), 0},
+ {NETF(eType), 8},
+ {NETF(torsoAnim), 8},
+ {NETF(weaponAnim), 8},
+ {NETF(eventParm), 8},
+ {NETF(legsAnim), 8},
+ {NETF(groundEntityNum), GENTITYNUM_BITS},
+ {NETF(pos.trType), 8},
+ {NETF(eFlags), 19},
+ {NETF(otherEntityNum), GENTITYNUM_BITS},
+ {NETF(weapon), 8},
+ {NETF(clientNum), 8},
+ {NETF(angles[1]), 0},
+ {NETF(pos.trDuration), 32},
+ {NETF(apos.trType), 8},
+ {NETF(origin[0]), 0},
+ {NETF(origin[1]), 0},
+ {NETF(origin[2]), 0},
+ {NETF(solid), 24},
+ {NETF(misc), MAX_MISC},
+ {NETF(modelindex), 8},
+ {NETF(otherEntityNum2), GENTITYNUM_BITS},
+ {NETF(loopSound), 8},
+ {NETF(generic1), 10},
+ {NETF(origin2[2]), 0},
+ {NETF(origin2[0]), 0},
+ {NETF(origin2[1]), 0},
+ {NETF(modelindex2), 8},
+ {NETF(angles[0]), 0},
+ {NETF(time), 32},
+ {NETF(apos.trTime), 32},
+ {NETF(apos.trDuration), 32},
+ {NETF(apos.trBase[2]), 0},
+ {NETF(apos.trDelta[0]), 0},
+ {NETF(apos.trDelta[1]), 0},
+ {NETF(apos.trDelta[2]), 0},
+ {NETF(time2), 32},
+ {NETF(angles[2]), 0},
+ {NETF(angles2[0]), 0},
+ {NETF(angles2[2]), 0},
+ {NETF(constantLight), 32},
+ {NETF(frame), 16}
+};
+
+// if (int)f == f and (int)f + ( 1<<(FLOAT_INT_BITS-1) ) < ( 1 << FLOAT_INT_BITS )
+// the float will be sent with FLOAT_INT_BITS, otherwise all 32 bits will be sent
+#define FLOAT_INT_BITS 13
+#define FLOAT_INT_BIAS (1 << (FLOAT_INT_BITS - 1))
+
+/*
+==================
+MSG_WriteDeltaEntity
+
+Writes part of a packetentities message, including the entity number.
+Can delta from either a baseline or a previous packet_entity
+If to is NULL, a remove entity update will be sent
+If force is not set, then nothing at all will be generated if the entity is
+identical, under the assumption that the in-order delta code will catch it.
+==================
+*/
+void MSG_WriteDeltaEntity(int alternateProtocol, msg_t *msg, struct entityState_s *from, struct entityState_s *to, bool force)
+{
+ int i, lc;
+ int numFields;
+ netField_t *field;
+ int trunc;
+ float fullFloat;
+ int *fromF, *toF;
+
+ numFields = ARRAY_LEN(entityStateFields);
+
+ // all fields should be 32 bits to avoid any compiler packing issues
+ // the "number" field is not part of the field list
+ // if this assert fails, someone added a field to the entityState_t
+ // struct without updating the message fields
+ assert(numFields + 1 == sizeof(*from) / 4);
+
+ // a NULL to is a delta remove message
+ if (to == NULL)
+ {
+ if (from == NULL)
+ {
+ return;
+ }
+ MSG_WriteBits(msg, from->number, GENTITYNUM_BITS);
+ MSG_WriteBits(msg, 1, 1);
+ return;
+ }
+
+ if (to->number < 0 || to->number >= MAX_GENTITIES)
+ {
+ Com_Error(ERR_FATAL, "MSG_WriteDeltaEntity: Bad entity number: %i", to->number);
+ }
+
+ lc = 0;
+ // build the change vector as bytes so it is endien independent
+ for (i = 0, field = entityStateFields; i < numFields; i++, field++)
+ {
+ if (alternateProtocol == 2 && i == 13)
+ {
+ continue;
+ }
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ if (*fromF != *toF)
+ {
+ lc = i + 1;
+ }
+ }
+
+ if (lc == 0)
+ {
+ // nothing at all changed
+ if (!force)
+ {
+ return; // nothing at all
+ }
+ // write two bits for no change
+ MSG_WriteBits(msg, to->number, GENTITYNUM_BITS);
+ MSG_WriteBits(msg, 0, 1); // not removed
+ MSG_WriteBits(msg, 0, 1); // no delta
+ return;
+ }
+
+ MSG_WriteBits(msg, to->number, GENTITYNUM_BITS);
+ MSG_WriteBits(msg, 0, 1); // not removed
+ MSG_WriteBits(msg, 1, 1); // we have a delta
+
+ if (alternateProtocol == 2 && lc - 1 > 13)
+ {
+ MSG_WriteByte(msg, lc - 1); // # of changes
+ }
+ else
+ {
+ MSG_WriteByte(msg, lc); // # of changes
+ }
+
+ oldsize += numFields;
+
+ for (i = 0, field = entityStateFields; i < lc; i++, field++)
+ {
+ if (alternateProtocol == 2 && i == 13)
+ {
+ continue;
+ }
+
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+
+ if (*fromF == *toF)
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ continue;
+ }
+
+ MSG_WriteBits(msg, 1, 1); // changed
+
+ if (field->bits == 0)
+ {
+ // float
+ fullFloat = *(float *)toF;
+ trunc = (int)fullFloat;
+
+ if (fullFloat == 0.0f)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ oldsize += FLOAT_INT_BITS;
+ }
+ else
+ {
+ MSG_WriteBits(msg, 1, 1);
+ if (trunc == fullFloat && trunc + FLOAT_INT_BIAS >= 0 && trunc + FLOAT_INT_BIAS < (1 << FLOAT_INT_BITS))
+ {
+ // send as small integer
+ MSG_WriteBits(msg, 0, 1);
+ MSG_WriteBits(msg, trunc + FLOAT_INT_BIAS, FLOAT_INT_BITS);
+ }
+ else
+ {
+ // send as full floating point value
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, *toF, 32);
+ }
+ }
+ }
+ else
+ {
+ if (*toF == 0)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 1, 1);
+ // integer
+ if (alternateProtocol == 2 && i == 33)
+ {
+ MSG_WriteBits(msg, *toF, 8);
+ }
+ else
+ {
+ MSG_WriteBits(msg, *toF, field->bits);
+ }
+ }
+ }
+ }
+}
+
+/*
+==================
+MSG_ReadDeltaEntity
+
+The entity number has already been read from the message, which
+is how the from state is identified.
+
+If the delta removes the entity, entityState_t->number will be set to MAX_GENTITIES-1
+
+Can go from either a baseline or a previous packet_entity
+==================
+*/
+void MSG_ReadDeltaEntity(int alternateProtocol, msg_t *msg, entityState_t *from, entityState_t *to, int number)
+{
+ int i, lc;
+ int numFields;
+ netField_t *field;
+ int *fromF, *toF;
+ int print;
+ int trunc;
+ int startBit, endBit;
+
+ if (number < 0 || number >= MAX_GENTITIES)
+ {
+ Com_Error(ERR_DROP, "Bad delta entity number: %i", number);
+ }
+
+ if (msg->bit == 0)
+ {
+ startBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ startBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+
+ // check for a remove
+ if (MSG_ReadBits(msg, 1) == 1)
+ {
+ ::memset(to, 0, sizeof(*to));
+ to->number = MAX_GENTITIES - 1;
+ if (cl_shownet && (cl_shownet->integer >= 2 || cl_shownet->integer == -1))
+ {
+ Com_Printf("%3i: #%-3i remove\n", msg->readcount, number);
+ }
+ return;
+ }
+
+ // check for no delta
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ *to = *from;
+ to->number = number;
+ return;
+ }
+
+ numFields = ARRAY_LEN(entityStateFields);
+ lc = MSG_ReadByte(msg);
+ if (alternateProtocol == 2 && lc - 1 >= 13)
+ {
+ ++lc;
+ }
+
+ if (lc > numFields || lc < 0)
+ {
+ Com_Error(ERR_DROP, "invalid entityState field count");
+ }
+
+ // shownet 2/3 will interleave with other printed info, -1 will
+ // just print the delta records`
+ if (cl_shownet && (cl_shownet->integer >= 2 || cl_shownet->integer == -1))
+ {
+ print = 1;
+ Com_Printf("%3i: #%-3i ", msg->readcount, to->number);
+ }
+ else
+ {
+ print = 0;
+ }
+
+ to->number = number;
+
+ for (i = 0, field = entityStateFields; i < lc; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ if (alternateProtocol == 2 && i == 13)
+ {
+ *toF = 0;
+ continue;
+ }
+
+ if (!MSG_ReadBits(msg, 1))
+ {
+ // no change
+ *toF = *fromF;
+ }
+ else
+ {
+ if (field->bits == 0)
+ {
+ // float
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ *(float *)toF = 0.0f;
+ }
+ else
+ {
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ // integral float
+ trunc = MSG_ReadBits(msg, FLOAT_INT_BITS);
+ // bias to allow equal parts positive and negative
+ trunc -= FLOAT_INT_BIAS;
+ *(float *)toF = trunc;
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, trunc);
+ }
+ }
+ else
+ {
+ // full floating point value
+ *toF = MSG_ReadBits(msg, 32);
+ if (print)
+ {
+ Com_Printf("%s:%f ", field->name, *(float *)toF);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ *toF = 0;
+ }
+ else
+ {
+ // integer
+ if (alternateProtocol == 2 && i == 33)
+ {
+ *toF = MSG_ReadBits(msg, 8);
+ }
+ else
+ {
+ *toF = MSG_ReadBits(msg, field->bits);
+ }
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, *toF);
+ }
+ }
+ }
+ // pcount[i]++;
+ }
+ }
+ for (i = lc, field = &entityStateFields[lc]; i < numFields; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ // no change
+ *toF = *fromF;
+ }
+
+ if (print)
+ {
+ if (msg->bit == 0)
+ {
+ endBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ endBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+ Com_Printf(" (%i bits)\n", endBit - startBit);
+ }
+}
+
+/*
+============================================================================
+
+plyer_state_t communication
+
+============================================================================
+*/
+
+// using the stringizing operator to save typing...
+#define PSF(x) #x, (size_t) & ((playerState_t *) 0)->x
+
+netField_t playerStateFields[] = {
+ {PSF(commandTime), 32},
+ {PSF(origin[0]), 0},
+ {PSF(origin[1]), 0},
+ {PSF(bobCycle), 8},
+ {PSF(velocity[0]), 0},
+ {PSF(velocity[1]), 0},
+ {PSF(viewangles[1]), 0},
+ {PSF(viewangles[0]), 0},
+ {PSF(weaponTime), -16},
+ {PSF(origin[2]), 0},
+ {PSF(velocity[2]), 0},
+ {PSF(legsTimer), 8},
+ {PSF(pm_time), -16},
+ {PSF(eventSequence), 16},
+ {PSF(torsoAnim), 8},
+ {PSF(weaponAnim), 8},
+ {PSF(movementDir), 4},
+ {PSF(events[0]), 8},
+ {PSF(legsAnim), 8},
+ {PSF(events[1]), 8},
+ {PSF(pm_flags), 24},
+ {PSF(groundEntityNum), GENTITYNUM_BITS},
+ {PSF(weaponstate), 4},
+ {PSF(eFlags), 16},
+ {PSF(externalEvent), 10},
+ {PSF(gravity), -16},
+ {PSF(speed), -16},
+ {PSF(delta_angles[1]), 16},
+ {PSF(externalEventParm), 8},
+ {PSF(viewheight), -8},
+ {PSF(damageEvent), 8},
+ {PSF(damageYaw), 8},
+ {PSF(damagePitch), 8},
+ {PSF(damageCount), 8},
+ {PSF(ammo), 12},
+ {PSF(clips), 4},
+ {PSF(generic1), 10},
+ {PSF(pm_type), 8},
+ {PSF(delta_angles[0]), 16},
+ {PSF(delta_angles[2]), 16},
+ {PSF(torsoTimer), 12},
+ {PSF(tauntTimer), 12},
+ {PSF(eventParms[0]), 8},
+ {PSF(eventParms[1]), 8},
+ {PSF(clientNum), 8},
+ {PSF(weapon), 5},
+ {PSF(viewangles[2]), 0},
+ {PSF(grapplePoint[0]), 0},
+ {PSF(grapplePoint[1]), 0},
+ {PSF(grapplePoint[2]), 0},
+ {PSF(otherEntityNum), GENTITYNUM_BITS},
+ {PSF(loopSound), 16}
+};
+
+#define APSF(x) #x, (size_t) & ((alternatePlayerState_t *) 0)->x
+
+netField_t alternatePlayerStateFields[] = {
+ {APSF(commandTime), 32},
+ {APSF(origin[0]), 0},
+ {APSF(origin[1]), 0},
+ {APSF(bobCycle), 8},
+ {APSF(velocity[0]), 0},
+ {APSF(velocity[1]), 0},
+ {APSF(viewangles[1]), 0},
+ {APSF(viewangles[0]), 0},
+ {APSF(weaponTime), -16},
+ {APSF(origin[2]), 0},
+ {APSF(velocity[2]), 0},
+ {APSF(legsTimer), 8},
+ {APSF(pm_time), -16},
+ {APSF(eventSequence), 16},
+ {APSF(torsoAnim), 8},
+ {APSF(movementDir), 4},
+ {APSF(events[0]), 8},
+ {APSF(legsAnim), 8},
+ {APSF(events[1]), 8},
+ {APSF(pm_flags), 16},
+ {APSF(groundEntityNum), GENTITYNUM_BITS},
+ {APSF(weaponstate), 4},
+ {APSF(eFlags), 16},
+ {APSF(externalEvent), 10},
+ {APSF(gravity), -16},
+ {APSF(speed), -16},
+ {APSF(delta_angles[1]), 16},
+ {APSF(externalEventParm), 8},
+ {APSF(viewheight), -8},
+ {APSF(damageEvent), 8},
+ {APSF(damageYaw), 8},
+ {APSF(damagePitch), 8},
+ {APSF(damageCount), 8},
+ {APSF(generic1), 8},
+ {APSF(pm_type), 8},
+ {APSF(delta_angles[0]), 16},
+ {APSF(delta_angles[2]), 16},
+ {APSF(torsoTimer), 12},
+ {APSF(eventParms[0]), 8},
+ {APSF(eventParms[1]), 8},
+ {APSF(clientNum), 8},
+ {APSF(weapon), 5},
+ {APSF(viewangles[2]), 0},
+ {APSF(grapplePoint[0]), 0},
+ {APSF(grapplePoint[1]), 0},
+ {APSF(grapplePoint[2]), 0},
+ {APSF(otherEntityNum), GENTITYNUM_BITS},
+ {APSF(loopSound), 16}
+};
+
+/*
+=============
+MSG_WriteDeltaPlayerstate
+
+=============
+*/
+void MSG_WriteDeltaPlayerstate(int alternateProtocol, msg_t *msg, struct playerState_s *from, struct playerState_s *to)
+{
+ int i;
+ playerState_t dummy;
+ int statsbits;
+ int persistantbits;
+ int altFromAmmo[3];
+ int altToAmmo[3];
+ int ammobits;
+ int miscbits;
+ int numFields;
+ netField_t *field;
+ int *fromF, *toF;
+ float fullFloat;
+ int trunc, lc;
+
+ if (!from)
+ {
+ from = &dummy;
+ ::memset(&dummy, 0, sizeof(dummy));
+ }
+
+ numFields = ARRAY_LEN(playerStateFields);
+
+ lc = 0;
+ for (i = 0, field = playerStateFields; i < numFields; i++, field++)
+ {
+ if (alternateProtocol == 2 && (i == 15 || i == 34 || i == 35 || i == 41))
+ {
+ continue;
+ }
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ if (*fromF != *toF)
+ {
+ lc = i + 1;
+ }
+ }
+
+ if (alternateProtocol == 2)
+ {
+ if (lc - 1 > 41)
+ {
+ MSG_WriteByte(msg, lc - 4); // # of changes
+ }
+ else if (lc - 1 > 35)
+ {
+ MSG_WriteByte(msg, lc - 3); // # of changes
+ }
+ else if (lc - 1 > 34)
+ {
+ MSG_WriteByte(msg, lc - 2); // # of changes
+ }
+ else if (lc - 1 > 15)
+ {
+ MSG_WriteByte(msg, lc - 1); // # of changes
+ }
+ else
+ {
+ MSG_WriteByte(msg, lc); // # of changes
+ }
+ }
+ else
+ {
+ MSG_WriteByte(msg, lc); // # of changes
+ }
+
+ oldsize += numFields - lc;
+
+ for (i = 0, field = playerStateFields; i < lc; i++, field++)
+ {
+ if (alternateProtocol == 2 && (i == 15 || i == 34 || i == 35 || i == 41))
+ {
+ continue;
+ }
+
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+
+ if (*fromF == *toF)
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ continue;
+ }
+
+ MSG_WriteBits(msg, 1, 1); // changed
+ // pcount[i]++;
+
+ if (field->bits == 0)
+ {
+ // float
+ fullFloat = *(float *)toF;
+ trunc = (int)fullFloat;
+
+ if (trunc == fullFloat && trunc + FLOAT_INT_BIAS >= 0 && trunc + FLOAT_INT_BIAS < (1 << FLOAT_INT_BITS))
+ {
+ // send as small integer
+ MSG_WriteBits(msg, 0, 1);
+ MSG_WriteBits(msg, trunc + FLOAT_INT_BIAS, FLOAT_INT_BITS);
+ }
+ else
+ {
+ // send as full floating point value
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, *toF, 32);
+ }
+ }
+ else
+ {
+ // integer
+ if (alternateProtocol == 2)
+ {
+ if (i == 20)
+ {
+ MSG_WriteBits(msg, *toF, 16);
+ }
+ else if (i == 36)
+ {
+ MSG_WriteBits(msg, *toF, 8);
+ }
+ else
+ {
+ MSG_WriteBits(msg, *toF, field->bits);
+ }
+ }
+ else
+ {
+ MSG_WriteBits(msg, *toF, field->bits);
+ }
+ }
+ }
+
+ //
+ // send the arrays
+ //
+ statsbits = 0;
+ for (i = 0; i < MAX_STATS; i++)
+ {
+ if (to->stats[i] != from->stats[i])
+ {
+ statsbits |= 1 << i;
+ }
+ }
+ persistantbits = 0;
+ for (i = 0; i < MAX_PERSISTANT; i++)
+ {
+ if (to->persistant[i] != from->persistant[i])
+ {
+ persistantbits |= 1 << i;
+ }
+ }
+ if (alternateProtocol == 2)
+ {
+ altFromAmmo[0] = (from->weaponAnim & 0xFF) | ((from->pm_flags >> 8) & 0xFF00);
+ altFromAmmo[1] = (from->ammo & 0xFFF) | ((from->clips << 12) & 0xF000);
+ altFromAmmo[2] = (from->tauntTimer & 0xFFF) | ((from->generic1 << 4) & 0x3000);
+ altToAmmo[0] = (to->weaponAnim & 0xFF) | ((to->pm_flags >> 8) & 0xFF00);
+ altToAmmo[1] = (to->ammo & 0xFFF) | ((to->clips << 12) & 0xF000);
+ altToAmmo[2] = (to->tauntTimer & 0xFFF) | ((to->generic1 << 4) & 0x3000);
+ ammobits = 0;
+ for (i = 0; i < 3; i++)
+ {
+ if (altToAmmo[i] != altFromAmmo[i])
+ {
+ ammobits |= 1 << i;
+ }
+ }
+ }
+ else
+ {
+ ammobits = 0;
+ }
+ miscbits = 0;
+ for (i = 0; i < MAX_MISC; i++)
+ {
+ if (to->misc[i] != from->misc[i])
+ {
+ miscbits |= 1 << i;
+ }
+ }
+
+ if (!statsbits && !persistantbits && !ammobits && !miscbits)
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ oldsize += 4;
+ return;
+ }
+ MSG_WriteBits(msg, 1, 1); // changed
+
+ if (statsbits)
+ {
+ MSG_WriteBits(msg, 1, 1); // changed
+ MSG_WriteBits(msg, statsbits, MAX_STATS);
+ for (i = 0; i < MAX_STATS; i++)
+ if (statsbits & (1 << i)) MSG_WriteShort(msg, to->stats[i]);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ }
+
+ if (persistantbits)
+ {
+ MSG_WriteBits(msg, 1, 1); // changed
+ MSG_WriteBits(msg, persistantbits, MAX_PERSISTANT);
+ for (i = 0; i < MAX_PERSISTANT; i++)
+ if (persistantbits & (1 << i)) MSG_WriteShort(msg, to->persistant[i]);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ }
+
+ if (alternateProtocol == 2)
+ {
+ if (ammobits)
+ {
+ MSG_WriteBits(msg, 1, 1); // changed
+ MSG_WriteBits(msg, ammobits, 16);
+ for (i = 0; i < 3; i++)
+ if (ammobits & (1 << i)) MSG_WriteShort(msg, altToAmmo[i]);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ }
+ }
+
+ if (miscbits)
+ {
+ MSG_WriteBits(msg, 1, 1); // changed
+ MSG_WriteBits(msg, miscbits, MAX_MISC);
+ for (i = 0; i < MAX_MISC; i++)
+ if (miscbits & (1 << i)) MSG_WriteLong(msg, to->misc[i]);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ }
+}
+
+/*
+===================
+MSG_ReadDeltaPlayerstate
+===================
+*/
+void MSG_ReadDeltaPlayerstate(msg_t *msg, playerState_t *from, playerState_t *to)
+{
+ int i, lc;
+ int bits;
+ netField_t *field;
+ int numFields;
+ int startBit, endBit;
+ int print;
+ int *fromF, *toF;
+ int trunc;
+ playerState_t dummy;
+
+ if (!from)
+ {
+ from = &dummy;
+ ::memset(&dummy, 0, sizeof(dummy));
+ }
+ *to = *from;
+
+ if (msg->bit == 0)
+ {
+ startBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ startBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+
+ // shownet 2/3 will interleave with other printed info, -2 will
+ // just print the delta records
+ if (cl_shownet && (cl_shownet->integer >= 2 || cl_shownet->integer == -2))
+ {
+ print = 1;
+ Com_Printf("%3i: playerstate ", msg->readcount);
+ }
+ else
+ {
+ print = 0;
+ }
+
+ numFields = ARRAY_LEN(playerStateFields);
+ lc = MSG_ReadByte(msg);
+
+ if (lc > numFields || lc < 0)
+ {
+ Com_Error(ERR_DROP, "invalid playerState field count");
+ }
+
+ for (i = 0, field = playerStateFields; i < lc; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+
+ if (!MSG_ReadBits(msg, 1))
+ {
+ // no change
+ *toF = *fromF;
+ }
+ else
+ {
+ if (field->bits == 0)
+ {
+ // float
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ // integral float
+ trunc = MSG_ReadBits(msg, FLOAT_INT_BITS);
+ // bias to allow equal parts positive and negative
+ trunc -= FLOAT_INT_BIAS;
+ *(float *)toF = trunc;
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, trunc);
+ }
+ }
+ else
+ {
+ // full floating point value
+ *toF = MSG_ReadBits(msg, 32);
+ if (print)
+ {
+ Com_Printf("%s:%f ", field->name, *(float *)toF);
+ }
+ }
+ }
+ else
+ {
+ // integer
+ *toF = MSG_ReadBits(msg, field->bits);
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, *toF);
+ }
+ }
+ }
+ }
+ for (i = lc, field = &playerStateFields[lc]; i < numFields; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ // no change
+ *toF = *fromF;
+ }
+
+ // read the arrays
+ if (MSG_ReadBits(msg, 1))
+ {
+ // parse stats
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_STATS");
+ bits = MSG_ReadBits(msg, MAX_STATS);
+ for (i = 0; i < MAX_STATS; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->stats[i] = MSG_ReadShort(msg);
+ }
+ }
+ }
+
+ // parse persistant stats
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_PERSISTANT");
+ bits = MSG_ReadBits(msg, MAX_PERSISTANT);
+ for (i = 0; i < MAX_PERSISTANT; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->persistant[i] = MSG_ReadShort(msg);
+ }
+ }
+ }
+
+ // parse misc data
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_MISC");
+ bits = MSG_ReadBits(msg, MAX_MISC);
+ for (i = 0; i < MAX_MISC; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->misc[i] = MSG_ReadLong(msg);
+ }
+ }
+ }
+ }
+
+ if (print)
+ {
+ if (msg->bit == 0)
+ {
+ endBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ endBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+ Com_Printf(" (%i bits)\n", endBit - startBit);
+ }
+}
+
+void MSG_ReadDeltaAlternatePlayerstate(msg_t *msg, alternatePlayerState_t *from, alternatePlayerState_t *to)
+{
+ int i, lc;
+ int bits;
+ netField_t *field;
+ int numFields;
+ int startBit, endBit;
+ int print;
+ int *fromF, *toF;
+ int trunc;
+ alternatePlayerState_t dummy;
+
+ if (!from)
+ {
+ from = &dummy;
+ ::memset(&dummy, 0, sizeof(dummy));
+ }
+ *to = *from;
+
+ if (msg->bit == 0)
+ {
+ startBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ startBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+
+ // shownet 2/3 will interleave with other printed info, -2 will
+ // just print the delta records
+ if (cl_shownet && (cl_shownet->integer >= 2 || cl_shownet->integer == -2))
+ {
+ print = 1;
+ Com_Printf("%3i: playerstate ", msg->readcount);
+ }
+ else
+ {
+ print = 0;
+ }
+
+ numFields = ARRAY_LEN(alternatePlayerStateFields);
+ lc = MSG_ReadByte(msg);
+
+ if (lc > numFields || lc < 0)
+ {
+ Com_Error(ERR_DROP, "invalid playerState field count");
+ }
+
+ for (i = 0, field = alternatePlayerStateFields; i < lc; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+
+ if (!MSG_ReadBits(msg, 1))
+ {
+ // no change
+ *toF = *fromF;
+ }
+ else
+ {
+ if (field->bits == 0)
+ {
+ // float
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ // integral float
+ trunc = MSG_ReadBits(msg, FLOAT_INT_BITS);
+ // bias to allow equal parts positive and negative
+ trunc -= FLOAT_INT_BIAS;
+ *(float *)toF = trunc;
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, trunc);
+ }
+ }
+ else
+ {
+ // full floating point value
+ *toF = MSG_ReadBits(msg, 32);
+ if (print)
+ {
+ Com_Printf("%s:%f ", field->name, *(float *)toF);
+ }
+ }
+ }
+ else
+ {
+ // integer
+ *toF = MSG_ReadBits(msg, field->bits);
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, *toF);
+ }
+ }
+ }
+ }
+ for (i = lc, field = &alternatePlayerStateFields[lc]; i < numFields; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ // no change
+ *toF = *fromF;
+ }
+
+ // read the arrays
+ if (MSG_ReadBits(msg, 1))
+ {
+ // parse stats
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_STATS");
+ bits = MSG_ReadBits(msg, MAX_STATS);
+ for (i = 0; i < MAX_STATS; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->stats[i] = MSG_ReadShort(msg);
+ }
+ }
+ }
+
+ // parse persistant stats
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_PERSISTANT");
+ bits = MSG_ReadBits(msg, MAX_PERSISTANT);
+ for (i = 0; i < MAX_PERSISTANT; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->persistant[i] = MSG_ReadShort(msg);
+ }
+ }
+ }
+
+ // parse ammo
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_AMMO");
+ bits = MSG_ReadBits(msg, MAX_WEAPONS);
+ for (i = 0; i < MAX_WEAPONS; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->ammo[i] = MSG_ReadShort(msg);
+ }
+ }
+ }
+
+ // parse misc data
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_MISC");
+ bits = MSG_ReadBits(msg, MAX_MISC);
+ for (i = 0; i < MAX_MISC; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->misc[i] = MSG_ReadLong(msg);
+ }
+ }
+ }
+ }
+
+ if (print)
+ {
+ if (msg->bit == 0)
+ {
+ endBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ endBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+ Com_Printf(" (%i bits)\n", endBit - startBit);
+ }
+}
+
+int msg_hData[256] = {
+ 250315, // 0
+ 41193, // 1
+ 6292, // 2
+ 7106, // 3
+ 3730, // 4
+ 3750, // 5
+ 6110, // 6
+ 23283, // 7
+ 33317, // 8
+ 6950, // 9
+ 7838, // 10
+ 9714, // 11
+ 9257, // 12
+ 17259, // 13
+ 3949, // 14
+ 1778, // 15
+ 8288, // 16
+ 1604, // 17
+ 1590, // 18
+ 1663, // 19
+ 1100, // 20
+ 1213, // 21
+ 1238, // 22
+ 1134, // 23
+ 1749, // 24
+ 1059, // 25
+ 1246, // 26
+ 1149, // 27
+ 1273, // 28
+ 4486, // 29
+ 2805, // 30
+ 3472, // 31
+ 21819, // 32
+ 1159, // 33
+ 1670, // 34
+ 1066, // 35
+ 1043, // 36
+ 1012, // 37
+ 1053, // 38
+ 1070, // 39
+ 1726, // 40
+ 888, // 41
+ 1180, // 42
+ 850, // 43
+ 960, // 44
+ 780, // 45
+ 1752, // 46
+ 3296, // 47
+ 10630, // 48
+ 4514, // 49
+ 5881, // 50
+ 2685, // 51
+ 4650, // 52
+ 3837, // 53
+ 2093, // 54
+ 1867, // 55
+ 2584, // 56
+ 1949, // 57
+ 1972, // 58
+ 940, // 59
+ 1134, // 60
+ 1788, // 61
+ 1670, // 62
+ 1206, // 63
+ 5719, // 64
+ 6128, // 65
+ 7222, // 66
+ 6654, // 67
+ 3710, // 68
+ 3795, // 69
+ 1492, // 70
+ 1524, // 71
+ 2215, // 72
+ 1140, // 73
+ 1355, // 74
+ 971, // 75
+ 2180, // 76
+ 1248, // 77
+ 1328, // 78
+ 1195, // 79
+ 1770, // 80
+ 1078, // 81
+ 1264, // 82
+ 1266, // 83
+ 1168, // 84
+ 965, // 85
+ 1155, // 86
+ 1186, // 87
+ 1347, // 88
+ 1228, // 89
+ 1529, // 90
+ 1600, // 91
+ 2617, // 92
+ 2048, // 93
+ 2546, // 94
+ 3275, // 95
+ 2410, // 96
+ 3585, // 97
+ 2504, // 98
+ 2800, // 99
+ 2675, // 100
+ 6146, // 101
+ 3663, // 102
+ 2840, // 103
+ 14253, // 104
+ 3164, // 105
+ 2221, // 106
+ 1687, // 107
+ 3208, // 108
+ 2739, // 109
+ 3512, // 110
+ 4796, // 111
+ 4091, // 112
+ 3515, // 113
+ 5288, // 114
+ 4016, // 115
+ 7937, // 116
+ 6031, // 117
+ 5360, // 118
+ 3924, // 119
+ 4892, // 120
+ 3743, // 121
+ 4566, // 122
+ 4807, // 123
+ 5852, // 124
+ 6400, // 125
+ 6225, // 126
+ 8291, // 127
+ 23243, // 128
+ 7838, // 129
+ 7073, // 130
+ 8935, // 131
+ 5437, // 132
+ 4483, // 133
+ 3641, // 134
+ 5256, // 135
+ 5312, // 136
+ 5328, // 137
+ 5370, // 138
+ 3492, // 139
+ 2458, // 140
+ 1694, // 141
+ 1821, // 142
+ 2121, // 143
+ 1916, // 144
+ 1149, // 145
+ 1516, // 146
+ 1367, // 147
+ 1236, // 148
+ 1029, // 149
+ 1258, // 150
+ 1104, // 151
+ 1245, // 152
+ 1006, // 153
+ 1149, // 154
+ 1025, // 155
+ 1241, // 156
+ 952, // 157
+ 1287, // 158
+ 997, // 159
+ 1713, // 160
+ 1009, // 161
+ 1187, // 162
+ 879, // 163
+ 1099, // 164
+ 929, // 165
+ 1078, // 166
+ 951, // 167
+ 1656, // 168
+ 930, // 169
+ 1153, // 170
+ 1030, // 171
+ 1262, // 172
+ 1062, // 173
+ 1214, // 174
+ 1060, // 175
+ 1621, // 176
+ 930, // 177
+ 1106, // 178
+ 912, // 179
+ 1034, // 180
+ 892, // 181
+ 1158, // 182
+ 990, // 183
+ 1175, // 184
+ 850, // 185
+ 1121, // 186
+ 903, // 187
+ 1087, // 188
+ 920, // 189
+ 1144, // 190
+ 1056, // 191
+ 3462, // 192
+ 2240, // 193
+ 4397, // 194
+ 12136, // 195
+ 7758, // 196
+ 1345, // 197
+ 1307, // 198
+ 3278, // 199
+ 1950, // 200
+ 886, // 201
+ 1023, // 202
+ 1112, // 203
+ 1077, // 204
+ 1042, // 205
+ 1061, // 206
+ 1071, // 207
+ 1484, // 208
+ 1001, // 209
+ 1096, // 210
+ 915, // 211
+ 1052, // 212
+ 995, // 213
+ 1070, // 214
+ 876, // 215
+ 1111, // 216
+ 851, // 217
+ 1059, // 218
+ 805, // 219
+ 1112, // 220
+ 923, // 221
+ 1103, // 222
+ 817, // 223
+ 1899, // 224
+ 1872, // 225
+ 976, // 226
+ 841, // 227
+ 1127, // 228
+ 956, // 229
+ 1159, // 230
+ 950, // 231
+ 7791, // 232
+ 954, // 233
+ 1289, // 234
+ 933, // 235
+ 1127, // 236
+ 3207, // 237
+ 1020, // 238
+ 927, // 239
+ 1355, // 240
+ 768, // 241
+ 1040, // 242
+ 745, // 243
+ 952, // 244
+ 805, // 245
+ 1073, // 246
+ 740, // 247
+ 1013, // 248
+ 805, // 249
+ 1008, // 250
+ 796, // 251
+ 996, // 252
+ 1057, // 253
+ 11457, // 254
+ 13504, // 255
+};
+
+void MSG_initHuffman(void)
+{
+ int i, j;
+
+ msgInit = true;
+ Huff_Init(&msgHuff);
+ for (i = 0; i < 256; i++)
+ {
+ for (j = 0; j < msg_hData[i]; j++)
+ {
+ Huff_addRef(&msgHuff.compressor, (uint8_t)i); // Do update
+ Huff_addRef(&msgHuff.decompressor, (uint8_t)i); // Do update
+ }
+ }
+}
+
+/*
+void MSG_NUinitHuffman() {
+ uint8_t *data;
+ int size, i, ch;
+ int array[256];
+
+ msgInit = true;
+
+ Huff_Init(&msgHuff);
+ // load it in
+ size = FS_ReadFile( "netchan/netchan.bin", (void **)&data );
+
+ for(i=0;i<256;i++) {
+ array[i] = 0;
+ }
+ for(i=0;i<size;i++) {
+ ch = data[i];
+ Huff_addRef(&msgHuff.compressor, ch); // Do update
+ Huff_addRef(&msgHuff.decompressor, ch); // Do update
+ array[ch]++;
+ }
+ Com_Printf("msg_hData {\n");
+ for(i=0;i<256;i++) {
+ if (array[i] == 0) {
+ Huff_addRef(&msgHuff.compressor, i); // Do update
+ Huff_addRef(&msgHuff.decompressor, i); // Do update
+ }
+ Com_Printf("%d, // %d\n", array[i], i);
+ }
+ Com_Printf("};\n");
+ FS_FreeFile( data );
+ Cbuf_AddText( "condump dump.txt\n" );
+}
+*/
+
+//===========================================================================
diff --git a/src/qcommon/msg.h b/src/qcommon/msg.h
new file mode 100644
index 0000000..518f755
--- /dev/null
+++ b/src/qcommon/msg.h
@@ -0,0 +1,79 @@
+#ifndef QCOMMON_MSG_H
+#define QCOMMON_MSG_H 1
+
+#include <stdint.h>
+
+//
+// msg.c
+//
+struct msg_t {
+ bool allowoverflow; // if false, do a Com_Error
+ bool overflowed; // set to true if the buffer size failed (with allowoverflow set)
+ bool oob; // set to true if the buffer size failed (with allowoverflow set)
+ uint8_t *data;
+ int maxsize;
+ int cursize;
+ int readcount;
+ int bit; // for bitwise reads and writes
+};
+
+void MSG_Init(struct msg_t *buf, uint8_t *data, int length);
+void MSG_InitOOB(struct msg_t *buf, uint8_t *data, int length);
+void MSG_Clear(struct msg_t *buf);
+void MSG_WriteData(struct msg_t *buf, const void *data, int length);
+void MSG_Bitstream(struct msg_t *buf);
+
+// TTimo
+// copy a struct msg_t in case we need to store it as is for a bit
+// (as I needed this to keep an struct msg_t from a static var for later use)
+// sets data buffer as MSG_Init does prior to do the copy
+void MSG_Copy(struct msg_t *buf, uint8_t *data, int length, struct msg_t *src);
+
+typedef struct usercmd_s usercmd_t;
+typedef struct entityState_s entityState_t;
+typedef struct playerState_s playerState_t;
+
+void MSG_WriteBits(struct msg_t *msg, int value, int bits);
+
+void MSG_WriteChar(struct msg_t *sb, int c);
+void MSG_WriteByte(struct msg_t *sb, int c);
+void MSG_WriteShort(struct msg_t *sb, int c);
+void MSG_WriteLong(struct msg_t *sb, int c);
+void MSG_WriteFloat(struct msg_t *sb, float f);
+void MSG_WriteString(struct msg_t *sb, const char *s);
+void MSG_WriteBigString(struct msg_t *sb, const char *s);
+void MSG_WriteAngle16(struct msg_t *sb, float f);
+int MSG_HashKey(int alternateProtocol, const char *string, int maxlen);
+
+void MSG_BeginReading(struct msg_t *sb);
+void MSG_BeginReadingOOB(struct msg_t *sb);
+
+int MSG_ReadBits(struct msg_t *msg, int bits);
+
+int MSG_ReadChar(struct msg_t *sb);
+int MSG_ReadByte(struct msg_t *sb);
+int MSG_ReadShort(struct msg_t *sb);
+int MSG_ReadLong(struct msg_t *sb);
+float MSG_ReadFloat(struct msg_t *sb);
+char *MSG_ReadString(struct msg_t *sb);
+char *MSG_ReadBigString(struct msg_t *sb);
+char *MSG_ReadStringLine(struct msg_t *sb);
+float MSG_ReadAngle16(struct msg_t *sb);
+void MSG_ReadData(struct msg_t *sb, void *buffer, int size);
+int MSG_LookaheadByte(struct msg_t *msg);
+
+void MSG_WriteDeltaUsercmdKey(struct msg_t *msg, int key, usercmd_t *from, usercmd_t *to);
+void MSG_ReadDeltaUsercmdKey(struct msg_t *msg, int key, usercmd_t *from, usercmd_t *to);
+
+void MSG_WriteDeltaEntity(int alternateProtocol, struct msg_t *msg, struct entityState_s *from, struct entityState_s *to, bool force);
+void MSG_ReadDeltaEntity(int alternateProtocol, struct msg_t *msg, entityState_t *from, entityState_t *to, int number);
+
+void MSG_WriteDeltaPlayerstate(int alternateProtocol, struct msg_t *msg, struct playerState_s *from, struct playerState_s *to);
+void MSG_ReadDeltaPlayerstate(struct msg_t *msg, struct playerState_s *from, struct playerState_s *to);
+
+struct alternatePlayerState_t;
+void MSG_ReadDeltaAlternatePlayerstate(struct msg_t *msg, struct alternatePlayerState_t *from, struct alternatePlayerState_t *to);
+
+void MSG_ReportChangeVectors_f(void);
+
+#endif
diff --git a/src/qcommon/net.h b/src/qcommon/net.h
new file mode 100644
index 0000000..7766d23
--- /dev/null
+++ b/src/qcommon/net.h
@@ -0,0 +1,145 @@
+#ifndef QCOMMON_NET_H
+#define QCOMMON_NET_H 1
+
+#include <stdint.h>
+
+/*
+==============================================================
+
+NET
+
+==============================================================
+*/
+
+#define NET_ENABLEV4 0x01
+#define NET_ENABLEV6 0x02
+// if this flag is set, always attempt ipv6 connections instead of ipv4 if a v6 address is found.
+#define NET_PRIOV6 0x04
+// disables ipv6 multicast support if set.
+#define NET_DISABLEMCAST 0x08
+
+#define NET_ENABLEALT1PROTO 0x01
+#define NET_ENABLEALT2PROTO 0x02
+#define NET_DISABLEPRIMPROTO 0x04
+
+#define PACKET_BACKUP 32 // number of old messages that must be kept on client and
+ // server for delta compression and ping estimation
+#define PACKET_MASK (PACKET_BACKUP - 1)
+
+#define MAX_PACKET_USERCMDS 32 // max number of usercmd_t in a packet
+
+#define MAX_SNAPSHOT_ENTITIES 256
+
+#define PORT_ANY -1
+
+#define MAX_RELIABLE_COMMANDS 128 // max string commands buffered for retransmit
+
+enum netadrtype_t {
+ NA_BAD = 0, // an address lookup failed
+ NA_LOOPBACK,
+ NA_BROADCAST,
+ NA_IP,
+ NA_IP6,
+ NA_MULTICAST6,
+ NA_UNSPEC
+};
+
+typedef enum { NS_CLIENT, NS_SERVER } netsrc_t;
+
+#define NET_ADDRSTRMAXLEN 48 // maximum length of an IPv6 address string including trailing '\0'
+struct netadr_t {
+ enum netadrtype_t type;
+
+ uint8_t ip[4];
+ uint8_t ip6[16];
+
+ unsigned short port;
+ unsigned long scope_id; // Needed for IPv6 link-local addresses
+
+ int alternateProtocol;
+};
+
+void NET_Init(void);
+void NET_Shutdown(void);
+void NET_Restart_f(void);
+void NET_Config(bool enableNetworking);
+void NET_FlushPacketQueue(void);
+void NET_SendPacket(netsrc_t sock, int length, const void *data, struct netadr_t to);
+void NET_OutOfBandPrint(netsrc_t net_socket, struct netadr_t adr, const char *format, ...)
+ __attribute__((format(printf, 3, 4)));
+void NET_OutOfBandData(netsrc_t sock, struct netadr_t adr, uint8_t *format, int len);
+
+bool NET_CompareAdr(struct netadr_t a, struct netadr_t b);
+bool NET_CompareBaseAdrMask(struct netadr_t a, struct netadr_t b, int netmask);
+bool NET_CompareBaseAdr(struct netadr_t a, struct netadr_t b);
+bool NET_IsLocalAddress(struct netadr_t adr);
+const char *NET_AdrToString(struct netadr_t a);
+const char *NET_AdrToStringwPort(struct netadr_t a);
+int NET_StringToAdr(const char *s, struct netadr_t *a, enum netadrtype_t family);
+bool NET_GetLoopPacket(netsrc_t sock, struct netadr_t *net_from, struct msg_t *net_message);
+void NET_JoinMulticast6(void);
+void NET_LeaveMulticast6(void);
+void NET_Sleep(int msec);
+
+#define MAX_MSGLEN 16384 // max length of a message, which may be fragmented into multiple packets
+
+#define MAX_DOWNLOAD_WINDOW 48 // ACK window of 48 download chunks. Cannot set this higher, or clients
+ // will overflow the reliable commands buffer
+#define MAX_DOWNLOAD_BLKSIZE 1024 // 896 uint8_t block chunks
+
+#define NETCHAN_GENCHECKSUM(challenge, sequence) ((challenge) ^ ((sequence) * (challenge)))
+
+/*
+Netchan handles packet fragmentation and out of order / duplicate suppression
+*/
+
+typedef struct {
+ netsrc_t sock;
+
+ int dropped; // between last packet and previous
+
+ int alternateProtocol;
+ struct netadr_t remoteAddress;
+ int qport; // qport value to write when transmitting
+
+ // sequencing variables
+ int incomingSequence;
+ int outgoingSequence;
+
+ // incoming fragment assembly buffer
+ int fragmentSequence;
+ int fragmentLength;
+ uint8_t fragmentBuffer[MAX_MSGLEN];
+
+ // outgoing fragment buffer
+ // we need to space out the sending of large fragmented messages
+ bool unsentFragments;
+ int unsentFragmentStart;
+ int unsentLength;
+ uint8_t unsentBuffer[MAX_MSGLEN];
+
+ int challenge;
+ int lastSentTime;
+ int lastSentSize;
+} netchan_t;
+
+void Netchan_Init(int qport);
+void Netchan_Setup(
+ int alternateProtocol, netsrc_t sock, netchan_t *chan, struct netadr_t adr, int qport, int challenge);
+
+void Netchan_Transmit(netchan_t *chan, int length, const uint8_t *data);
+void Netchan_TransmitNextFragment(netchan_t *chan);
+
+bool Netchan_Process(netchan_t *chan, struct msg_t *msg);
+
+void Sys_SendPacket(int length, const void *data, struct netadr_t to);
+bool Sys_StringToAdr(const char *s, struct netadr_t *a, enum netadrtype_t family); // Does NOT parse port numbers, only base addresses.
+bool Sys_IsLANAddress(struct netadr_t adr);
+void Sys_ShowIP(void);
+
+#define SV_ENCODE_START 4
+#define SV_DECODE_START 12
+#define CL_ENCODE_START 12
+#define CL_DECODE_START 4
+
+#endif
diff --git a/src/qcommon/net_chan.cpp b/src/qcommon/net_chan.cpp
new file mode 100644
index 0000000..1dab821
--- /dev/null
+++ b/src/qcommon/net_chan.cpp
@@ -0,0 +1,697 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "net.h"
+
+#include "sys/sys_shared.h"
+
+#include "cvar.h"
+#include "huffman.h"
+#include "msg.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+/*
+
+packet header
+-------------
+4 outgoing sequence. high bit will be set if this is a fragmented message
+[2 qport (only for client to server)]
+[2 fragment start byte]
+[2 fragment length. if < FRAGMENT_SIZE, this is the last fragment]
+
+if the sequence number is -1, the packet should be handled as an out-of-band
+message instead of as part of a netcon.
+
+All fragments will have the same sequence numbers.
+
+The qport field is a workaround for bad address translating routers that
+sometimes remap the client's source port on a packet during game play.
+
+If the base part of the net address matches and the qport matches, then the
+channel matches even if the IP port differs. The IP port should be updated
+to the new value before sending out any replies.
+
+*/
+
+#define MAX_PACKETLEN 1400 // max size of a network packet
+
+#define FRAGMENT_SIZE (MAX_PACKETLEN - 100)
+#define PACKET_HEADER 10 // two ints and a short
+
+#define FRAGMENT_BIT (1 << 31)
+
+cvar_t *showpackets;
+cvar_t *showdrop;
+cvar_t *qport;
+
+static const char *netsrcString[2] = {"client", "server"};
+
+/*
+===============
+Netchan_Init
+
+===============
+*/
+void Netchan_Init(int port)
+{
+ port &= 0xffff;
+ showpackets = Cvar_Get("showpackets", "0", CVAR_TEMP);
+ showdrop = Cvar_Get("showdrop", "0", CVAR_TEMP);
+ qport = Cvar_Get("net_qport", va("%i", port), CVAR_INIT);
+}
+
+/*
+==============
+Netchan_Setup
+
+called to open a channel to a remote system
+==============
+*/
+void Netchan_Setup(int alternateProtocol, netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, int challenge)
+{
+ ::memset(chan, 0, sizeof(*chan));
+
+ chan->sock = sock;
+ chan->remoteAddress = adr;
+ chan->qport = qport;
+ chan->incomingSequence = 0;
+ chan->outgoingSequence = 1;
+ chan->challenge = challenge;
+ chan->alternateProtocol = alternateProtocol;
+}
+
+/*
+=================
+Netchan_TransmitNextFragment
+
+Send one fragment of the current message
+=================
+*/
+void Netchan_TransmitNextFragment(netchan_t *chan)
+{
+ msg_t send;
+ byte send_buf[MAX_PACKETLEN];
+ int fragmentLength;
+ int outgoingSequence;
+
+ // write the packet header
+ MSG_InitOOB(&send, send_buf, sizeof(send_buf)); // <-- only do the oob here
+
+ outgoingSequence = chan->outgoingSequence | FRAGMENT_BIT;
+ MSG_WriteLong(&send, outgoingSequence);
+
+ // send the qport if we are a client
+ if (chan->sock == NS_CLIENT)
+ {
+ MSG_WriteShort(&send, qport->integer);
+ }
+
+ if (chan->alternateProtocol == 0)
+ MSG_WriteLong(&send, NETCHAN_GENCHECKSUM(chan->challenge, chan->outgoingSequence));
+
+ // copy the reliable message to the packet first
+ fragmentLength = FRAGMENT_SIZE;
+ if (chan->unsentFragmentStart + fragmentLength > chan->unsentLength)
+ {
+ fragmentLength = chan->unsentLength - chan->unsentFragmentStart;
+ }
+
+ MSG_WriteShort(&send, chan->unsentFragmentStart);
+ MSG_WriteShort(&send, fragmentLength);
+ MSG_WriteData(&send, chan->unsentBuffer + chan->unsentFragmentStart, fragmentLength);
+
+ // send the datagram
+ NET_SendPacket(chan->sock, send.cursize, send.data, chan->remoteAddress);
+
+ // Store send time and size of this packet for rate control
+ chan->lastSentTime = Sys_Milliseconds();
+ chan->lastSentSize = send.cursize;
+
+ if (showpackets->integer)
+ {
+ Com_Printf("%s send %4i : s=%i fragment=%i,%i\n", netsrcString[chan->sock], send.cursize,
+ chan->outgoingSequence, chan->unsentFragmentStart, fragmentLength);
+ }
+
+ chan->unsentFragmentStart += fragmentLength;
+
+ // this exit condition is a little tricky, because a packet
+ // that is exactly the fragment length still needs to send
+ // a second packet of zero length so that the other side
+ // can tell there aren't more to follow
+ if (chan->unsentFragmentStart == chan->unsentLength && fragmentLength != FRAGMENT_SIZE)
+ {
+ chan->outgoingSequence++;
+ chan->unsentFragments = false;
+ }
+}
+
+/*
+===============
+Netchan_Transmit
+
+Sends a message to a connection, fragmenting if necessary
+A 0 length will still generate a packet.
+================
+*/
+void Netchan_Transmit(netchan_t *chan, int length, const byte *data)
+{
+ msg_t send;
+ byte send_buf[MAX_PACKETLEN];
+
+ if (length > MAX_MSGLEN)
+ {
+ Com_Error(ERR_DROP, "Netchan_Transmit: length = %i", length);
+ }
+ chan->unsentFragmentStart = 0;
+
+ // fragment large reliable messages
+ if (length >= FRAGMENT_SIZE)
+ {
+ chan->unsentFragments = true;
+ chan->unsentLength = length;
+ ::memcpy(chan->unsentBuffer, data, length);
+
+ // only send the first fragment now
+ Netchan_TransmitNextFragment(chan);
+
+ return;
+ }
+
+ // write the packet header
+ MSG_InitOOB(&send, send_buf, sizeof(send_buf));
+
+ MSG_WriteLong(&send, chan->outgoingSequence);
+
+ // send the qport if we are a client
+ if (chan->sock == NS_CLIENT) MSG_WriteShort(&send, qport->integer);
+
+ if (chan->alternateProtocol == 0)
+ MSG_WriteLong(&send, NETCHAN_GENCHECKSUM(chan->challenge, chan->outgoingSequence));
+
+ chan->outgoingSequence++;
+
+ MSG_WriteData(&send, data, length);
+
+ // send the datagram
+ NET_SendPacket(chan->sock, send.cursize, send.data, chan->remoteAddress);
+
+ // Store send time and size of this packet for rate control
+ chan->lastSentTime = Sys_Milliseconds();
+ chan->lastSentSize = send.cursize;
+
+ if (showpackets->integer)
+ {
+ Com_Printf("%s send %4i : s=%i ack=%i\n", netsrcString[chan->sock], send.cursize, chan->outgoingSequence - 1,
+ chan->incomingSequence);
+ }
+}
+
+/*
+=================
+Netchan_Process
+
+Returns false if the message should not be processed due to being
+out of order or a fragment.
+
+Msg must be large enough to hold MAX_MSGLEN, because if this is the
+final fragment of a multi-part message, the entire thing will be
+copied out.
+=================
+*/
+bool Netchan_Process(netchan_t *chan, msg_t *msg)
+{
+ int sequence;
+ int fragmentStart, fragmentLength;
+ int checksum;
+ bool fragmented;
+
+ // XOR unscramble all data in the packet after the header
+ // Netchan_UnScramblePacket( msg );
+
+ // get sequence numbers
+ MSG_BeginReadingOOB(msg);
+ sequence = MSG_ReadLong(msg);
+
+ // check for fragment information
+ if (sequence & FRAGMENT_BIT)
+ {
+ sequence &= ~FRAGMENT_BIT;
+ fragmented = true;
+ }
+ else
+ {
+ fragmented = false;
+ }
+
+ // read the qport if we are a server
+ if (chan->sock == NS_SERVER)
+ {
+ MSG_ReadShort(msg);
+ }
+
+ if (chan->alternateProtocol == 0)
+ {
+ checksum = MSG_ReadLong(msg);
+
+ // UDP spoofing protection
+ if (NETCHAN_GENCHECKSUM(chan->challenge, sequence) != checksum) return false;
+ }
+
+ // read the fragment information
+ if (fragmented)
+ {
+ fragmentStart = MSG_ReadShort(msg);
+ fragmentLength = MSG_ReadShort(msg);
+ }
+ else
+ {
+ fragmentStart = 0; // stop warning message
+ fragmentLength = 0;
+ }
+
+ if (showpackets->integer)
+ {
+ if (fragmented)
+ {
+ Com_Printf("%s recv %4i : s=%i fragment=%i,%i\n", netsrcString[chan->sock], msg->cursize, sequence,
+ fragmentStart, fragmentLength);
+ }
+ else
+ {
+ Com_Printf("%s recv %4i : s=%i\n", netsrcString[chan->sock], msg->cursize, sequence);
+ }
+ }
+
+ //
+ // discard out of order or duplicated packets
+ //
+ if (sequence <= chan->incomingSequence)
+ {
+ if (showdrop->integer || showpackets->integer)
+ {
+ Com_Printf("%s:Out of order packet %i at %i\n", NET_AdrToString(chan->remoteAddress), sequence,
+ chan->incomingSequence);
+ }
+ return false;
+ }
+
+ //
+ // dropped packets don't keep the message from being used
+ //
+ chan->dropped = sequence - (chan->incomingSequence + 1);
+ if (chan->dropped > 0)
+ {
+ if (showdrop->integer || showpackets->integer)
+ {
+ Com_Printf("%s:Dropped %i packets at %i\n", NET_AdrToString(chan->remoteAddress), chan->dropped, sequence);
+ }
+ }
+
+ //
+ // if this is the final fragment of a reliable message,
+ // bump incoming_reliable_sequence
+ //
+ if (fragmented)
+ {
+ // TTimo
+ // make sure we add the fragments in correct order
+ // either a packet was dropped, or we received this one too soon
+ // we don't reconstruct the fragments. We will wait till this fragment gets to us again
+ // (NOTE: we could probably try to rebuild by out of order chunks if needed)
+ if (sequence != chan->fragmentSequence)
+ {
+ chan->fragmentSequence = sequence;
+ chan->fragmentLength = 0;
+ }
+
+ // if we missed a fragment, dump the message
+ if (fragmentStart != chan->fragmentLength)
+ {
+ if (showdrop->integer || showpackets->integer)
+ {
+ Com_Printf("%s:Dropped a message fragment\n", NET_AdrToString(chan->remoteAddress));
+ }
+ // we can still keep the part that we have so far,
+ // so we don't need to clear chan->fragmentLength
+ return false;
+ }
+
+ // copy the fragment to the fragment buffer
+ if (fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize
+ || (size_t)(chan->fragmentLength + fragmentLength) > sizeof(chan->fragmentBuffer))
+ {
+ if (showdrop->integer || showpackets->integer)
+ {
+ Com_Printf("%s:illegal fragment length\n", NET_AdrToString(chan->remoteAddress));
+ }
+ return false;
+ }
+
+ ::memcpy(chan->fragmentBuffer + chan->fragmentLength, msg->data + msg->readcount, fragmentLength);
+
+ chan->fragmentLength += fragmentLength;
+
+ // if this wasn't the last fragment, don't process anything
+ if (fragmentLength == FRAGMENT_SIZE)
+ {
+ return false;
+ }
+
+ if (chan->fragmentLength > msg->maxsize)
+ {
+ Com_Printf(
+ "%s:fragmentLength %i > msg->maxsize\n", NET_AdrToString(chan->remoteAddress), chan->fragmentLength);
+ return false;
+ }
+
+ // copy the full message over the partial fragment
+
+ // make sure the sequence number is still there
+ *(int *)msg->data = LittleLong(sequence);
+
+ ::memcpy(msg->data + 4, chan->fragmentBuffer, chan->fragmentLength);
+ msg->cursize = chan->fragmentLength + 4;
+ chan->fragmentLength = 0;
+ msg->readcount = 4; // past the sequence number
+ msg->bit = 32; // past the sequence number
+
+ // TTimo
+ // clients were not acking fragmented messages
+ chan->incomingSequence = sequence;
+
+ return true;
+ }
+
+ //
+ // the message can now be read from the current message pointer
+ //
+ chan->incomingSequence = sequence;
+
+ return true;
+}
+
+//==============================================================================
+
+/*
+=============================================================================
+
+LOOPBACK BUFFERS FOR LOCAL PLAYER
+
+=============================================================================
+*/
+
+// there needs to be enough loopback messages to hold a complete
+// gamestate of maximum size
+#define MAX_LOOPBACK 16
+
+typedef struct {
+ byte data[MAX_PACKETLEN];
+ int datalen;
+} loopmsg_t;
+
+typedef struct {
+ loopmsg_t msgs[MAX_LOOPBACK];
+ int get, send;
+} loopback_t;
+
+loopback_t loopbacks[2];
+
+bool NET_GetLoopPacket(netsrc_t sock, netadr_t *net_from, msg_t *net_message)
+{
+ int i;
+ loopback_t *loop;
+
+ loop = &loopbacks[sock];
+
+ if (loop->send - loop->get > MAX_LOOPBACK) loop->get = loop->send - MAX_LOOPBACK;
+
+ if (loop->get >= loop->send) return false;
+
+ i = loop->get & (MAX_LOOPBACK - 1);
+ loop->get++;
+
+ ::memcpy(net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
+ net_message->cursize = loop->msgs[i].datalen;
+ ::memset(net_from, 0, sizeof(*net_from));
+ net_from->type = NA_LOOPBACK;
+ return true;
+}
+
+void NET_SendLoopPacket(netsrc_t sock, int length, const void *data, netadr_t to)
+{
+ int i;
+ loopback_t *loop;
+
+ loop = &loopbacks[sock ^ 1];
+
+ i = loop->send & (MAX_LOOPBACK - 1);
+ loop->send++;
+
+ ::memcpy(loop->msgs[i].data, data, length);
+ loop->msgs[i].datalen = length;
+}
+
+//=============================================================================
+
+typedef struct packetQueue_s {
+ struct packetQueue_s *next;
+ int length;
+ byte *data;
+ netadr_t to;
+ int release;
+} packetQueue_t;
+
+packetQueue_t *packetQueue = NULL;
+
+static void NET_QueuePacket(int length, const void *data, netadr_t to, int offset)
+{
+ packetQueue_t *_new, *next = packetQueue;
+
+ if (offset > 999) offset = 999;
+
+ _new = (packetQueue_t *)S_Malloc(sizeof(packetQueue_t));
+ _new->data = (byte *)S_Malloc(length);
+ ::memcpy(_new->data, data, length);
+ _new->length = length;
+ _new->to = to;
+ _new->release = Sys_Milliseconds() + (int)((float)offset / com_timescale->value);
+ _new->next = NULL;
+
+ if (!packetQueue)
+ {
+ packetQueue = _new;
+ return;
+ }
+ while (next)
+ {
+ if (!next->next)
+ {
+ next->next = _new;
+ return;
+ }
+ next = next->next;
+ }
+}
+
+void NET_FlushPacketQueue(void)
+{
+ packetQueue_t *last;
+ int now;
+
+ while (packetQueue)
+ {
+ now = Sys_Milliseconds();
+ if (packetQueue->release >= now) break;
+ Sys_SendPacket(packetQueue->length, packetQueue->data, packetQueue->to);
+ last = packetQueue;
+ packetQueue = packetQueue->next;
+ Z_Free(last->data);
+ Z_Free(last);
+ }
+}
+
+void NET_SendPacket(netsrc_t sock, int length, const void *data, netadr_t to)
+{
+ // sequenced packets are shown in netchan, so just show oob
+ if (showpackets->integer && *(int *)data == -1)
+ {
+ Com_Printf("send packet %4i\n", length);
+ }
+
+ if (to.type == NA_LOOPBACK)
+ {
+ NET_SendLoopPacket(sock, length, data, to);
+ return;
+ }
+ if (to.type == NA_BAD)
+ {
+ return;
+ }
+
+ if (sock == NS_CLIENT && cl_packetdelay->integer > 0)
+ {
+ NET_QueuePacket(length, data, to, cl_packetdelay->integer);
+ }
+ else if (sock == NS_SERVER && sv_packetdelay->integer > 0)
+ {
+ NET_QueuePacket(length, data, to, sv_packetdelay->integer);
+ }
+ else
+ {
+ Sys_SendPacket(length, data, to);
+ }
+}
+
+/*
+===============
+NET_OutOfBandPrint
+
+Sends a text message in an out-of-band datagram
+================
+*/
+void QDECL NET_OutOfBandPrint(netsrc_t sock, netadr_t adr, const char *format, ...)
+{
+ va_list argptr;
+ char string[MAX_MSGLEN];
+
+ // set the header
+ string[0] = -1;
+ string[1] = -1;
+ string[2] = -1;
+ string[3] = -1;
+
+ va_start(argptr, format);
+ Q_vsnprintf(string + 4, sizeof(string) - 4, format, argptr);
+ va_end(argptr);
+
+ // send the datagram
+ NET_SendPacket(sock, strlen(string), string, adr);
+}
+
+/*
+===============
+NET_OutOfBandPrint
+
+Sends a data message in an out-of-band datagram (only used for "connect")
+================
+*/
+void QDECL NET_OutOfBandData(netsrc_t sock, netadr_t adr, byte *format, int len)
+{
+ byte string[MAX_MSGLEN * 2];
+ int i;
+ msg_t mbuf;
+
+ // set the header
+ string[0] = 0xff;
+ string[1] = 0xff;
+ string[2] = 0xff;
+ string[3] = 0xff;
+
+ for (i = 0; i < len; i++)
+ {
+ string[i + 4] = format[i];
+ }
+
+ mbuf.data = string;
+ mbuf.cursize = len + 4;
+ Huff_Compress(&mbuf, 12);
+ // send the datagram
+ NET_SendPacket(sock, mbuf.cursize, mbuf.data, adr);
+}
+
+/*
+=============
+NET_StringToAdr
+
+Traps "localhost" for loopback, passes everything else to system
+return 0 on address not found, 1 on address found with port, 2 on address found without port.
+=============
+*/
+int NET_StringToAdr(const char *s, netadr_t *a, netadrtype_t family)
+{
+ char base[MAX_STRING_CHARS], *search;
+ char *port = NULL;
+
+ if (!strcmp(s, "localhost"))
+ {
+ ::memset(a, 0, sizeof(*a));
+ a->type = NA_LOOPBACK;
+ // as NA_LOOPBACK doesn't require ports report port was given.
+ return 1;
+ }
+
+ Q_strncpyz(base, s, sizeof(base));
+
+ if (*base == '[' || Q_CountChar(base, ':') > 1)
+ {
+ // This is an ipv6 address, handle it specially.
+ search = strchr(base, ']');
+ if (search)
+ {
+ *search = '\0';
+ search++;
+
+ if (*search == ':') port = search + 1;
+ }
+
+ if (*base == '[')
+ search = base + 1;
+ else
+ search = base;
+ }
+ else
+ {
+ // look for a port number
+ port = strchr(base, ':');
+
+ if (port)
+ {
+ *port = '\0';
+ port++;
+ }
+
+ search = base;
+ }
+
+ a->alternateProtocol = 0;
+
+ if (!Sys_StringToAdr(search, a, family))
+ {
+ a->type = NA_BAD;
+ return 0;
+ }
+
+ if (port)
+ {
+ a->port = BigShort((short)atoi(port));
+ return 1;
+ }
+ else
+ {
+ a->port = BigShort(PORT_SERVER);
+ return 2;
+ }
+}
diff --git a/src/qcommon/net_ip.cpp b/src/qcommon/net_ip.cpp
new file mode 100644
index 0000000..910301d
--- /dev/null
+++ b/src/qcommon/net_ip.cpp
@@ -0,0 +1,1842 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "net.h"
+
+#include "cmd.h"
+#include "cvar.h"
+#include "msg.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#if WINVER < 0x501
+#ifdef __MINGW32__
+// wspiapi.h isn't available on MinGW, so if it's
+// present it's because the end user has added it
+// and we should look for it in our tree
+#include "wspiapi.h"
+#else
+#include <wspiapi.h>
+#endif
+#else
+#include <ws2spi.h>
+#endif
+
+typedef int socklen_t;
+#ifdef ADDRESS_FAMILY
+#define sa_family_t ADDRESS_FAMILY
+#else
+typedef unsigned short sa_family_t;
+#endif
+
+#define EAGAIN WSAEWOULDBLOCK
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define ECONNRESET WSAECONNRESET
+typedef u_long ioctlarg_t;
+#define socketError WSAGetLastError()
+
+static WSADATA winsockdata;
+static bool winsockInitialized = false;
+
+#else
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
+// needed for socklen_t on OSX 10.2
+#define _BSD_SOCKLEN_T_
+#endif
+
+#include <sys/socket.h>
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#if !defined(__sun) && !defined(__sgi)
+#include <ifaddrs.h>
+#endif
+
+#ifdef __sun
+#include <sys/filio.h>
+#endif
+
+typedef int SOCKET;
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define closesocket close
+#define ioctlsocket ioctl
+typedef int ioctlarg_t;
+#define socketError errno
+
+#endif
+
+static bool usingSocks = false;
+static int networkingEnabled = 0;
+
+static cvar_t *net_enabled;
+static cvar_t *net_alternateProtocols;
+
+static cvar_t *net_socksEnabled;
+static cvar_t *net_socksServer;
+static cvar_t *net_socksPort;
+static cvar_t *net_socksUsername;
+static cvar_t *net_socksPassword;
+
+static cvar_t *net_ip;
+static cvar_t *net_ip6;
+static cvar_t *net_ports[3];
+static cvar_t *net_port6s[3];
+static cvar_t *net_mcast6addr;
+static cvar_t *net_mcast6iface;
+
+static cvar_t *net_dropsim;
+
+static struct sockaddr socksRelayAddr;
+
+static SOCKET ip_sockets[3] = {INVALID_SOCKET, INVALID_SOCKET, INVALID_SOCKET};
+static SOCKET ip6_sockets[3] = {INVALID_SOCKET, INVALID_SOCKET, INVALID_SOCKET};
+/*
+TODO: accommodate
+static SOCKET socks_socket = INVALID_SOCKET;
+static SOCKET multicast6_socket = INVALID_SOCKET;
+*/
+
+// Keep track of currently joined multicast group.
+static struct ipv6_mreq curgroup;
+// And the currently bound address.
+static struct sockaddr_in6 boundto;
+
+#ifndef IF_NAMESIZE
+#define IF_NAMESIZE 16
+#endif
+
+// use an admin local address per default so that network admins can decide on how to handle quake3 traffic.
+#define NET_MULTICAST_IP6 "ff04::696f:7175:616b:6533"
+
+#define MAX_IPS 32
+
+typedef struct {
+ char ifname[IF_NAMESIZE];
+
+ netadrtype_t type;
+ sa_family_t family;
+ struct sockaddr_storage addr;
+ struct sockaddr_storage netmask;
+} nip_localaddr_t;
+
+static nip_localaddr_t localIP[MAX_IPS];
+static int numIP;
+
+//=============================================================================
+
+/*
+====================
+NET_ErrorString
+====================
+*/
+const char *NET_ErrorString(void)
+{
+#ifdef _WIN32
+ // FIXME: replace with FormatMessage?
+ switch (socketError)
+ {
+ case WSAEINTR:
+ return "WSAEINTR";
+ case WSAEBADF:
+ return "WSAEBADF";
+ case WSAEACCES:
+ return "WSAEACCES";
+ case WSAEDISCON:
+ return "WSAEDISCON";
+ case WSAEFAULT:
+ return "WSAEFAULT";
+ case WSAEINVAL:
+ return "WSAEINVAL";
+ case WSAEMFILE:
+ return "WSAEMFILE";
+ case WSAEWOULDBLOCK:
+ return "WSAEWOULDBLOCK";
+ case WSAEINPROGRESS:
+ return "WSAEINPROGRESS";
+ case WSAEALREADY:
+ return "WSAEALREADY";
+ case WSAENOTSOCK:
+ return "WSAENOTSOCK";
+ case WSAEDESTADDRREQ:
+ return "WSAEDESTADDRREQ";
+ case WSAEMSGSIZE:
+ return "WSAEMSGSIZE";
+ case WSAEPROTOTYPE:
+ return "WSAEPROTOTYPE";
+ case WSAENOPROTOOPT:
+ return "WSAENOPROTOOPT";
+ case WSAEPROTONOSUPPORT:
+ return "WSAEPROTONOSUPPORT";
+ case WSAESOCKTNOSUPPORT:
+ return "WSAESOCKTNOSUPPORT";
+ case WSAEOPNOTSUPP:
+ return "WSAEOPNOTSUPP";
+ case WSAEPFNOSUPPORT:
+ return "WSAEPFNOSUPPORT";
+ case WSAEAFNOSUPPORT:
+ return "WSAEAFNOSUPPORT";
+ case WSAEADDRINUSE:
+ return "WSAEADDRINUSE";
+ case WSAEADDRNOTAVAIL:
+ return "WSAEADDRNOTAVAIL";
+ case WSAENETDOWN:
+ return "WSAENETDOWN";
+ case WSAENETUNREACH:
+ return "WSAENETUNREACH";
+ case WSAENETRESET:
+ return "WSAENETRESET";
+ case WSAECONNABORTED:
+ return "WSWSAECONNABORTEDAEINTR";
+ case WSAECONNRESET:
+ return "WSAECONNRESET";
+ case WSAENOBUFS:
+ return "WSAENOBUFS";
+ case WSAEISCONN:
+ return "WSAEISCONN";
+ case WSAENOTCONN:
+ return "WSAENOTCONN";
+ case WSAESHUTDOWN:
+ return "WSAESHUTDOWN";
+ case WSAETOOMANYREFS:
+ return "WSAETOOMANYREFS";
+ case WSAETIMEDOUT:
+ return "WSAETIMEDOUT";
+ case WSAECONNREFUSED:
+ return "WSAECONNREFUSED";
+ case WSAELOOP:
+ return "WSAELOOP";
+ case WSAENAMETOOLONG:
+ return "WSAENAMETOOLONG";
+ case WSAEHOSTDOWN:
+ return "WSAEHOSTDOWN";
+ case WSASYSNOTREADY:
+ return "WSASYSNOTREADY";
+ case WSAVERNOTSUPPORTED:
+ return "WSAVERNOTSUPPORTED";
+ case WSANOTINITIALISED:
+ return "WSANOTINITIALISED";
+ case WSAHOST_NOT_FOUND:
+ return "WSAHOST_NOT_FOUND";
+ case WSATRY_AGAIN:
+ return "WSATRY_AGAIN";
+ case WSANO_RECOVERY:
+ return "WSANO_RECOVERY";
+ case WSANO_DATA:
+ return "WSANO_DATA";
+ default:
+ return "NO ERROR";
+ }
+#else
+ return strerror(socketError);
+#endif
+}
+
+static void NetadrToSockadr(netadr_t *a, struct sockaddr *s)
+{
+ if (a->type == NA_BROADCAST)
+ {
+ ((struct sockaddr_in *)s)->sin_family = AF_INET;
+ ((struct sockaddr_in *)s)->sin_port = a->port;
+#ifdef __FreeBSD__
+ ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_ANY;
+#else
+ ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
+#endif
+ }
+ else if (a->type == NA_IP)
+ {
+ ((struct sockaddr_in *)s)->sin_family = AF_INET;
+ ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
+ ((struct sockaddr_in *)s)->sin_port = a->port;
+ }
+ else if (a->type == NA_IP6)
+ {
+ ((struct sockaddr_in6 *)s)->sin6_family = AF_INET6;
+ ((struct sockaddr_in6 *)s)->sin6_addr = *((struct in6_addr *)&a->ip6);
+ ((struct sockaddr_in6 *)s)->sin6_port = a->port;
+ ((struct sockaddr_in6 *)s)->sin6_scope_id = a->scope_id;
+ }
+ else if (a->type == NA_MULTICAST6)
+ {
+ ((struct sockaddr_in6 *)s)->sin6_family = AF_INET6;
+ ((struct sockaddr_in6 *)s)->sin6_addr = curgroup.ipv6mr_multiaddr;
+ ((struct sockaddr_in6 *)s)->sin6_port = a->port;
+ }
+}
+
+static void SockadrToNetadr(struct sockaddr *s, netadr_t *a)
+{
+ if (s->sa_family == AF_INET)
+ {
+ a->type = NA_IP;
+ *(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
+ a->port = ((struct sockaddr_in *)s)->sin_port;
+ }
+ else if (s->sa_family == AF_INET6)
+ {
+ a->type = NA_IP6;
+ memcpy(a->ip6, &((struct sockaddr_in6 *)s)->sin6_addr, sizeof(a->ip6));
+ a->port = ((struct sockaddr_in6 *)s)->sin6_port;
+ a->scope_id = ((struct sockaddr_in6 *)s)->sin6_scope_id;
+ }
+ a->alternateProtocol = 0;
+}
+
+static struct addrinfo *SearchAddrInfo(struct addrinfo *hints, sa_family_t family)
+{
+ while (hints)
+ {
+ if (hints->ai_family == family) return hints;
+
+ hints = hints->ai_next;
+ }
+
+ return NULL;
+}
+
+/*
+=============
+Sys_StringToSockaddr
+=============
+*/
+static bool Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, size_t sadr_len, sa_family_t family)
+{
+ struct addrinfo hints;
+ struct addrinfo *res = NULL;
+ struct addrinfo *search = NULL;
+ struct addrinfo *hintsp;
+ int retval;
+
+ memset(sadr, '\0', sizeof(*sadr));
+ memset(&hints, '\0', sizeof(hints));
+
+ hintsp = &hints;
+ hintsp->ai_family = family;
+ hintsp->ai_socktype = SOCK_DGRAM;
+
+ retval = getaddrinfo(s, NULL, hintsp, &res);
+
+ if (!retval)
+ {
+ if (family == AF_UNSPEC)
+ {
+ // Decide here and now which protocol family to use
+ if (net_enabled->integer & NET_PRIOV6)
+ {
+ if (net_enabled->integer & NET_ENABLEV6) search = SearchAddrInfo(res, AF_INET6);
+
+ if (!search && (net_enabled->integer & NET_ENABLEV4)) search = SearchAddrInfo(res, AF_INET);
+ }
+ else
+ {
+ if (net_enabled->integer & NET_ENABLEV4) search = SearchAddrInfo(res, AF_INET);
+
+ if (!search && (net_enabled->integer & NET_ENABLEV6)) search = SearchAddrInfo(res, AF_INET6);
+ }
+ }
+ else
+ search = SearchAddrInfo(res, family);
+
+ if (search)
+ {
+ if (search->ai_addrlen > sadr_len) search->ai_addrlen = sadr_len;
+
+ memcpy(sadr, search->ai_addr, search->ai_addrlen);
+ freeaddrinfo(res);
+
+ return true;
+ }
+ else
+ Com_Printf("Sys_StringToSockaddr: Error resolving %s: No address of required type found.\n", s);
+ }
+ else
+ Com_Printf("Sys_StringToSockaddr: Error resolving %s: %s\n", s, gai_strerror(retval));
+
+ if (res) freeaddrinfo(res);
+
+ return false;
+}
+
+/*
+=============
+Sys_SockaddrToString
+=============
+*/
+static void Sys_SockaddrToString(char *dest, int destlen, struct sockaddr *input)
+{
+ socklen_t inputlen;
+
+ if (input->sa_family == AF_INET6)
+ inputlen = sizeof(struct sockaddr_in6);
+ else
+ inputlen = sizeof(struct sockaddr_in);
+
+ if (getnameinfo(input, inputlen, dest, destlen, NULL, 0, NI_NUMERICHOST) && destlen > 0) *dest = '\0';
+}
+
+/*
+=============
+Sys_StringToAdr
+=============
+*/
+bool Sys_StringToAdr(const char *s, netadr_t *a, netadrtype_t family)
+{
+ struct sockaddr_storage sadr;
+ sa_family_t fam;
+
+ switch (family)
+ {
+ case NA_IP:
+ fam = AF_INET;
+ break;
+ case NA_IP6:
+ fam = AF_INET6;
+ break;
+ default:
+ fam = AF_UNSPEC;
+ break;
+ }
+ if (!Sys_StringToSockaddr(s, (struct sockaddr *)&sadr, sizeof(sadr), fam))
+ {
+ return false;
+ }
+
+ SockadrToNetadr((struct sockaddr *)&sadr, a);
+ return true;
+}
+
+/*
+===================
+NET_CompareBaseAdrMask
+
+Compare without port, and up to the bit number given in netmask.
+===================
+*/
+bool NET_CompareBaseAdrMask(netadr_t a, netadr_t b, int netmask)
+{
+ uint8_t cmpmask, *addra, *addrb;
+ int curbyte;
+
+ if (a.alternateProtocol != b.alternateProtocol) return false;
+
+ if (a.type != b.type) return false;
+
+ if (a.type == NA_LOOPBACK) return true;
+
+ if (a.type == NA_IP)
+ {
+ addra = (uint8_t *)&a.ip;
+ addrb = (uint8_t *)&b.ip;
+
+ if (netmask < 0 || netmask > 32) netmask = 32;
+ }
+ else if (a.type == NA_IP6)
+ {
+ addra = (uint8_t *)&a.ip6;
+ addrb = (uint8_t *)&b.ip6;
+
+ if (netmask < 0 || netmask > 128) netmask = 128;
+ }
+ else
+ {
+ Com_Printf("NET_CompareBaseAdr: bad address type\n");
+ return false;
+ }
+
+ curbyte = netmask >> 3;
+
+ if (curbyte && memcmp(addra, addrb, curbyte)) return false;
+
+ netmask &= 0x07;
+ if (netmask)
+ {
+ cmpmask = (1 << netmask) - 1;
+ cmpmask <<= 8 - netmask;
+
+ if ((addra[curbyte] & cmpmask) == (addrb[curbyte] & cmpmask)) return true;
+ }
+ else
+ return true;
+
+ return false;
+}
+
+/*
+===================
+NET_CompareBaseAdr
+
+Compares without the port
+===================
+*/
+bool NET_CompareBaseAdr(netadr_t a, netadr_t b) { return NET_CompareBaseAdrMask(a, b, -1); }
+const char *NET_AdrToString(netadr_t a)
+{
+ static char s[NET_ADDRSTRMAXLEN];
+
+ if (a.type == NA_LOOPBACK)
+ Com_sprintf(s, sizeof(s), "loopback");
+ else if (a.type == NA_IP || a.type == NA_IP6)
+ {
+ struct sockaddr_storage sadr;
+
+ memset(&sadr, 0, sizeof(sadr));
+ NetadrToSockadr(&a, (struct sockaddr *)&sadr);
+ Sys_SockaddrToString(s, sizeof(s), (struct sockaddr *)&sadr);
+ }
+
+ return s;
+}
+
+const char *NET_AdrToStringwPort(netadr_t a)
+{
+ static char s[NET_ADDRSTRMAXLEN];
+
+ if (a.type == NA_LOOPBACK)
+ Com_sprintf(s, sizeof(s), "loopback");
+ else if (a.type == NA_IP)
+ Com_sprintf(s, sizeof(s), "%s:%hu", NET_AdrToString(a), ntohs(a.port));
+ else if (a.type == NA_IP6)
+ Com_sprintf(s, sizeof(s), "[%s]:%hu", NET_AdrToString(a), ntohs(a.port));
+
+ return s;
+}
+
+bool NET_CompareAdr(netadr_t a, netadr_t b)
+{
+ if (!NET_CompareBaseAdr(a, b)) return false;
+
+ if (a.type == NA_IP || a.type == NA_IP6)
+ {
+ if (a.port == b.port) return true;
+ }
+ else
+ return true;
+
+ return false;
+}
+
+bool NET_IsLocalAddress(netadr_t adr) { return (bool)(adr.type == NA_LOOPBACK); }
+//=============================================================================
+
+/*
+==================
+NET_GetPacket
+
+Receive one packet
+==================
+*/
+bool NET_GetPacket(netadr_t *net_from, msg_t *net_message, fd_set *fdr)
+{
+ int a;
+ int ret;
+ struct sockaddr_storage from;
+ socklen_t fromlen;
+ int err;
+
+ for (a = 0; a < 3; ++a)
+ {
+ // indent
+ if (ip_sockets[a] != INVALID_SOCKET && FD_ISSET(ip_sockets[a], fdr))
+ {
+ fromlen = sizeof(from);
+ ret = recvfrom(
+ ip_sockets[a], (char *)net_message->data, net_message->maxsize, 0, (struct sockaddr *)&from, &fromlen);
+
+ if (ret == SOCKET_ERROR)
+ {
+ err = socketError;
+
+ if (err != EAGAIN && err != ECONNRESET) Com_Printf("NET_GetPacket: %s\n", NET_ErrorString());
+ }
+ else
+ {
+ memset(((struct sockaddr_in *)&from)->sin_zero, 0, 8);
+
+ if (usingSocks && memcmp(&from, &socksRelayAddr, fromlen) == 0)
+ {
+ if (ret < 10 || net_message->data[0] != 0 || net_message->data[1] != 0 ||
+ net_message->data[2] != 0 || net_message->data[3] != 1)
+ {
+ return false;
+ }
+ net_from->type = NA_IP;
+ net_from->ip[0] = net_message->data[4];
+ net_from->ip[1] = net_message->data[5];
+ net_from->ip[2] = net_message->data[6];
+ net_from->ip[3] = net_message->data[7];
+ net_from->port = *(short *)&net_message->data[8];
+ net_message->readcount = 10;
+ }
+ else
+ {
+ SockadrToNetadr((struct sockaddr *)&from, net_from);
+ net_message->readcount = 0;
+ }
+
+ net_from->alternateProtocol = a;
+
+ if (ret >= net_message->maxsize)
+ {
+ Com_Printf("Oversize packet from %s\n", NET_AdrToString(*net_from));
+ return false;
+ }
+
+ net_message->cursize = ret;
+ return true;
+ }
+ }
+
+ if (ip6_sockets[a] != INVALID_SOCKET && FD_ISSET(ip6_sockets[a], fdr))
+ {
+ fromlen = sizeof(from);
+ ret = recvfrom(
+ ip6_sockets[a], (char *)net_message->data, net_message->maxsize, 0, (struct sockaddr *)&from, &fromlen);
+
+ if (ret == SOCKET_ERROR)
+ {
+ err = socketError;
+
+ if (err != EAGAIN && err != ECONNRESET) Com_Printf("NET_GetPacket: %s\n", NET_ErrorString());
+ }
+ else
+ {
+ SockadrToNetadr((struct sockaddr *)&from, net_from);
+ net_message->readcount = 0;
+
+ net_from->alternateProtocol = a;
+
+ if (ret >= net_message->maxsize)
+ {
+ Com_Printf("Oversize packet from %s\n", NET_AdrToString(*net_from));
+ return false;
+ }
+
+ net_message->cursize = ret;
+ return true;
+ }
+ }
+
+ /*
+ TODO: accommodate
+ if(multicast6_socket != INVALID_SOCKET && multicast6_socket != ip6_socket && FD_ISSET(multicast6_socket, fdr))
+ {
+ fromlen = sizeof(from);
+ ret = recvfrom(multicast6_socket, (char*)net_message->data, net_message->maxsize, 0, (struct sockaddr *)
+ &from, &fromlen);
+
+ if (ret == SOCKET_ERROR)
+ {
+ err = socketError;
+
+ if( err != EAGAIN && err != ECONNRESET )
+ Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() );
+ }
+ else
+ {
+ SockadrToNetadr((struct sockaddr *) &from, net_from);
+ net_message->readcount = 0;
+
+ if(ret >= net_message->maxsize)
+ {
+ Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
+ return false;
+ }
+
+ net_message->cursize = ret;
+ return true;
+ }
+ }
+ */
+ // outdent
+ }
+
+ return false;
+}
+
+//=============================================================================
+
+static char socksBuf[4096];
+
+/*
+==================
+Sys_SendPacket
+==================
+*/
+void Sys_SendPacket(int length, const void *data, netadr_t to)
+{
+ int ret = SOCKET_ERROR;
+ struct sockaddr_storage addr;
+
+ if (to.type != NA_BROADCAST && to.type != NA_IP && to.type != NA_IP6 && to.type != NA_MULTICAST6)
+ {
+ Com_Error(ERR_FATAL, "Sys_SendPacket: bad address type");
+ return;
+ }
+
+ if ((ip_sockets[to.alternateProtocol] == INVALID_SOCKET && to.type == NA_IP) ||
+ (ip_sockets[to.alternateProtocol] == INVALID_SOCKET && to.type == NA_BROADCAST) ||
+ (ip6_sockets[to.alternateProtocol] == INVALID_SOCKET && to.type == NA_IP6) ||
+ (/* TODO: accommodate ip6_socket == INVALID_SOCKET && */ to.type == NA_MULTICAST6))
+ return;
+
+ if (to.type == NA_MULTICAST6 && (net_enabled->integer & NET_DISABLEMCAST)) return;
+
+ memset(&addr, 0, sizeof(addr));
+ NetadrToSockadr(&to, (struct sockaddr *)&addr);
+
+ if (usingSocks && to.type == NA_IP)
+ {
+ socksBuf[0] = 0; // reserved
+ socksBuf[1] = 0;
+ socksBuf[2] = 0; // fragment (not fragmented)
+ socksBuf[3] = 1; // address type: IPV4
+ *(int *)&socksBuf[4] = ((struct sockaddr_in *)&addr)->sin_addr.s_addr;
+ *(short *)&socksBuf[8] = ((struct sockaddr_in *)&addr)->sin_port;
+ memcpy(&socksBuf[10], data, length);
+ ret = sendto(ip_sockets[to.alternateProtocol], (const char *)socksBuf, length + 10, 0, &socksRelayAddr,
+ sizeof(socksRelayAddr));
+ }
+ else
+ {
+ if (addr.ss_family == AF_INET)
+ ret = sendto(ip_sockets[to.alternateProtocol], (const char *)data, length, 0, (struct sockaddr *)&addr,
+ sizeof(struct sockaddr_in));
+ else if (addr.ss_family == AF_INET6)
+ ret = sendto(ip6_sockets[to.alternateProtocol], (const char *)data, length, 0, (struct sockaddr *)&addr,
+ sizeof(struct sockaddr_in6));
+ }
+ if (ret == SOCKET_ERROR)
+ {
+ int err = socketError;
+
+ // wouldblock is silent
+ if (err == EAGAIN)
+ {
+ return;
+ }
+
+ // some PPP links do not allow broadcasts and return an error
+ if ((err == EADDRNOTAVAIL) && ((to.type == NA_BROADCAST)))
+ {
+ return;
+ }
+
+ Com_Printf("Sys_SendPacket: %s\n", NET_ErrorString());
+ }
+}
+
+//=============================================================================
+
+/*
+==================
+Sys_IsLANAddress
+
+LAN clients will have their rate var ignored
+==================
+*/
+bool Sys_IsLANAddress(netadr_t adr)
+{
+ int index, run, addrsize;
+ bool differed;
+ uint8_t *compareadr, *comparemask, *compareip;
+
+ if (adr.type == NA_LOOPBACK)
+ {
+ return true;
+ }
+
+ if (adr.type == NA_IP)
+ {
+ // RFC1918:
+ // 10.0.0.0 - 10.255.255.255 (10/8 prefix)
+ // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
+ // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
+ if (adr.ip[0] == 10) return true;
+ if (adr.ip[0] == 172 && (adr.ip[1] & 0xf0) == 16) return true;
+ if (adr.ip[0] == 192 && adr.ip[1] == 168) return true;
+
+ if (adr.ip[0] == 127) return true;
+ }
+ else if (adr.type == NA_IP6)
+ {
+ if (adr.ip6[0] == 0xfe && (adr.ip6[1] & 0xc0) == 0x80) return true;
+ if ((adr.ip6[0] & 0xfe) == 0xfc) return true;
+ }
+
+ // Now compare against the networks this computer is member of.
+ for (index = 0; index < numIP; index++)
+ {
+ if (localIP[index].type == adr.type)
+ {
+ if (adr.type == NA_IP)
+ {
+ compareip = (uint8_t *)&((struct sockaddr_in *)&localIP[index].addr)->sin_addr.s_addr;
+ comparemask = (uint8_t *)&((struct sockaddr_in *)&localIP[index].netmask)->sin_addr.s_addr;
+ compareadr = adr.ip;
+
+ addrsize = sizeof(adr.ip);
+ }
+ else
+ {
+ // TODO? should we check the scope_id here?
+
+ compareip = (uint8_t *)&((struct sockaddr_in6 *)&localIP[index].addr)->sin6_addr;
+ comparemask = (uint8_t *)&((struct sockaddr_in6 *)&localIP[index].netmask)->sin6_addr;
+ compareadr = adr.ip6;
+
+ addrsize = sizeof(adr.ip6);
+ }
+
+ differed = false;
+ for (run = 0; run < addrsize; run++)
+ {
+ if ((compareip[run] & comparemask[run]) != (compareadr[run] & comparemask[run]))
+ {
+ differed = true;
+ break;
+ }
+ }
+
+ if (!differed) return true;
+ }
+ }
+
+ return false;
+}
+
+/*
+==================
+Sys_ShowIP
+==================
+*/
+void Sys_ShowIP(void)
+{
+ int i;
+ char addrbuf[NET_ADDRSTRMAXLEN];
+
+ for (i = 0; i < numIP; i++)
+ {
+ Sys_SockaddrToString(addrbuf, sizeof(addrbuf), (struct sockaddr *)&localIP[i].addr);
+
+ if (localIP[i].type == NA_IP)
+ Com_Printf("IP: %s\n", addrbuf);
+ else if (localIP[i].type == NA_IP6)
+ Com_Printf("IP6: %s\n", addrbuf);
+ }
+}
+
+//=============================================================================
+
+/*
+====================
+NET_IPSocket
+====================
+*/
+SOCKET NET_IPSocket(int alternateProtocol, char *net_interface, int port, int *err)
+{
+ SOCKET newsocket;
+ struct sockaddr_in address;
+ ioctlarg_t _true = 1;
+ int i = 1;
+
+ *err = 0;
+
+ if (net_interface)
+ {
+ Com_Printf("Opening%s IP socket: %s:%i\n",
+ (alternateProtocol == 2 ? " alternate-2" : alternateProtocol == 1 ? " alternate-1" : ""), net_interface,
+ port);
+ }
+ else
+ {
+ Com_Printf("Opening%s IP socket: 0.0.0.0:%i\n",
+ (alternateProtocol == 2 ? " alternate-2" : alternateProtocol == 1 ? " alternate-1" : ""), port);
+ }
+
+ if ((newsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
+ {
+ *err = socketError;
+ Com_Printf("WARNING: NET_IPSocket: socket: %s\n", NET_ErrorString());
+ return newsocket;
+ }
+ // make it non-blocking
+ if (ioctlsocket(newsocket, FIONBIO, &_true) == SOCKET_ERROR)
+ {
+ Com_Printf("WARNING: NET_IPSocket: ioctl FIONBIO: %s\n", NET_ErrorString());
+ *err = socketError;
+ closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+
+ // make it broadcast capable
+ if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == SOCKET_ERROR)
+ {
+ Com_Printf("WARNING: NET_IPSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
+ }
+
+ if (!net_interface || !net_interface[0])
+ {
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ }
+ else
+ {
+ if (!Sys_StringToSockaddr(net_interface, (struct sockaddr *)&address, sizeof(address), AF_INET))
+ {
+ closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+ }
+
+ if (port == PORT_ANY)
+ {
+ address.sin_port = 0;
+ }
+ else
+ {
+ address.sin_port = htons((short)port);
+ }
+
+ if (bind(newsocket, (const sockaddr *)&address, sizeof(address)) == SOCKET_ERROR)
+ {
+ Com_Printf("WARNING: NET_IPSocket: bind: %s\n", NET_ErrorString());
+ *err = socketError;
+ closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+
+ return newsocket;
+}
+
+/*
+====================
+NET_IP6Socket
+====================
+*/
+SOCKET NET_IP6Socket(int alternateProtocol, char *net_interface, int port, struct sockaddr_in6 *bindto, int *err)
+{
+ SOCKET newsocket;
+ struct sockaddr_in6 address;
+ ioctlarg_t _true = 1;
+
+ *err = 0;
+
+ if (net_interface)
+ {
+ // Print the name in brackets if there is a colon:
+ if (Q_CountChar(net_interface, ':'))
+ Com_Printf("Opening%s IP6 socket: [%s]:%i\n",
+ (alternateProtocol == 2 ? " alternate-2" : alternateProtocol == 1 ? " alternate-1" : ""), net_interface,
+ port);
+ else
+ Com_Printf("Opening%s IP6 socket: %s:%i\n",
+ (alternateProtocol == 2 ? " alternate-2" : alternateProtocol == 1 ? " alternate-1" : ""), net_interface,
+ port);
+ }
+ else
+ Com_Printf("Opening%s IP6 socket: [::]:%i\n",
+ (alternateProtocol == 2 ? " alternate-2" : alternateProtocol == 1 ? " alternate-1" : ""), port);
+
+ if ((newsocket = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
+ {
+ *err = socketError;
+ Com_Printf("WARNING: NET_IP6Socket: socket: %s\n", NET_ErrorString());
+ return newsocket;
+ }
+
+ // make it non-blocking
+ if (ioctlsocket(newsocket, FIONBIO, &_true) == SOCKET_ERROR)
+ {
+ Com_Printf("WARNING: NET_IP6Socket: ioctl FIONBIO: %s\n", NET_ErrorString());
+ *err = socketError;
+ closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+
+#ifdef IPV6_V6ONLY
+ {
+ int i = 1;
+
+ // ipv4 addresses should not be allowed to connect via this socket.
+ if (setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&i, sizeof(i)) == SOCKET_ERROR)
+ {
+ // win32 systems don't seem to support this anyways.
+ Com_DPrintf("WARNING: NET_IP6Socket: setsockopt IPV6_V6ONLY: %s\n", NET_ErrorString());
+ }
+ }
+#endif
+
+ if (!net_interface || !net_interface[0])
+ {
+ address.sin6_family = AF_INET6;
+ address.sin6_addr = in6addr_any;
+ }
+ else
+ {
+ if (!Sys_StringToSockaddr(net_interface, (struct sockaddr *)&address, sizeof(address), AF_INET6))
+ {
+ closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+ }
+
+ if (port == PORT_ANY)
+ {
+ address.sin6_port = 0;
+ }
+ else
+ {
+ address.sin6_port = htons((short)port);
+ }
+
+ if (bind(newsocket, (const sockaddr *)&address, sizeof(address)) == SOCKET_ERROR)
+ {
+ Com_Printf("WARNING: NET_IP6Socket: bind: %s\n", NET_ErrorString());
+ *err = socketError;
+ closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+
+ if (bindto) *bindto = address;
+
+ return newsocket;
+}
+
+/*
+====================
+NET_SetMulticast
+Set the current multicast group
+====================
+*/
+void NET_SetMulticast6(void)
+{
+ struct sockaddr_in6 addr;
+
+ if (!*net_mcast6addr->string ||
+ !Sys_StringToSockaddr(net_mcast6addr->string, (struct sockaddr *)&addr, sizeof(addr), AF_INET6))
+ {
+ Com_Printf(
+ "WARNING: NET_JoinMulticast6: Incorrect multicast address given, "
+ "please set cvar %s to a sane value.\n",
+ net_mcast6addr->name);
+
+ Cvar_SetValue(net_enabled->name, net_enabled->integer | NET_DISABLEMCAST);
+
+ return;
+ }
+
+ memcpy(&curgroup.ipv6mr_multiaddr, &addr.sin6_addr, sizeof(curgroup.ipv6mr_multiaddr));
+
+ if (*net_mcast6iface->string)
+ {
+#ifdef _WIN32
+ curgroup.ipv6mr_interface = net_mcast6iface->integer;
+#else
+ curgroup.ipv6mr_interface = if_nametoindex(net_mcast6iface->string);
+#endif
+ }
+ else
+ curgroup.ipv6mr_interface = 0;
+}
+
+/*
+====================
+NET_JoinMulticast
+Join an ipv6 multicast group
+====================
+*/
+void NET_JoinMulticast6(void)
+{
+ /*
+ TODO: accommodate
+ int err;
+
+ if(ip6_socket == INVALID_SOCKET || multicast6_socket != INVALID_SOCKET || (net_enabled->integer & NET_DISABLEMCAST))
+ return;
+
+ if(IN6_IS_ADDR_MULTICAST(&boundto.sin6_addr) || IN6_IS_ADDR_UNSPECIFIED(&boundto.sin6_addr))
+ {
+ // The way the socket was bound does not prohibit receiving multi-cast packets. So we don't need to open a
+ new one.
+ multicast6_socket = ip6_socket;
+ }
+ else
+ {
+ if((multicast6_socket = NET_IP6Socket(net_mcast6addr->string, ntohs(boundto.sin6_port), NULL, &err)) ==
+ INVALID_SOCKET)
+ {
+ // If the OS does not support binding to multicast addresses, like WinXP, at least try with the
+ normal file descriptor.
+ multicast6_socket = ip6_socket;
+ }
+ }
+
+ if(curgroup.ipv6mr_interface)
+ {
+ if (setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ (char *) &curgroup.ipv6mr_interface, sizeof(curgroup.ipv6mr_interface)) < 0)
+ {
+ Com_Printf("NET_JoinMulticast6: Couldn't set scope on multicast socket: %s\n", NET_ErrorString());
+
+ if(multicast6_socket != ip6_socket)
+ {
+ closesocket(multicast6_socket);
+ multicast6_socket = INVALID_SOCKET;
+ return;
+ }
+ }
+ }
+
+ if (setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &curgroup, sizeof(curgroup)))
+ {
+ Com_Printf("NET_JoinMulticast6: Couldn't join multicast group: %s\n", NET_ErrorString());
+
+ if(multicast6_socket != ip6_socket)
+ {
+ closesocket(multicast6_socket);
+ multicast6_socket = INVALID_SOCKET;
+ return;
+ }
+ }
+ */
+}
+
+void NET_LeaveMulticast6()
+{
+ /*
+ TODO: accommodate
+ if(multicast6_socket != INVALID_SOCKET)
+ {
+ if(multicast6_socket != ip6_socket)
+ closesocket(multicast6_socket);
+ else
+ setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *) &curgroup, sizeof(curgroup));
+
+ multicast6_socket = INVALID_SOCKET;
+ }
+ */
+}
+
+/*
+====================
+NET_OpenSocks
+====================
+*/
+void NET_OpenSocks(int port)
+{
+ /*
+ TODO: accommodate
+ struct sockaddr_in address;
+ struct hostent *h;
+ int len;
+ bool rfc1929;
+ unsigned char buf[64];
+
+ usingSocks = false;
+
+ Com_Printf( "Opening connection to SOCKS server.\n" );
+
+ if ( ( socks_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET ) {
+ Com_Printf( "WARNING: NET_OpenSocks: socket: %s\n", NET_ErrorString() );
+ return;
+ }
+
+ h = gethostbyname( net_socksServer->string );
+ if ( h == NULL ) {
+ Com_Printf( "WARNING: NET_OpenSocks: gethostbyname: %s\n", NET_ErrorString() );
+ return;
+ }
+ if ( h->h_addrtype != AF_INET ) {
+ Com_Printf( "WARNING: NET_OpenSocks: gethostbyname: address type was not AF_INET\n" );
+ return;
+ }
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = *(int *)h->h_addr_list[0];
+ address.sin_port = htons( (short)net_socksPort->integer );
+
+ if ( connect( socks_socket, (struct sockaddr *)&address, sizeof( address ) ) == SOCKET_ERROR ) {
+ Com_Printf( "NET_OpenSocks: connect: %s\n", NET_ErrorString() );
+ return;
+ }
+
+ // send socks authentication handshake
+ if ( *net_socksUsername->string || *net_socksPassword->string ) {
+ rfc1929 = true;
+ }
+ else {
+ rfc1929 = false;
+ }
+
+ buf[0] = 5; // SOCKS version
+ // method count
+ if ( rfc1929 ) {
+ buf[1] = 2;
+ len = 4;
+ }
+ else {
+ buf[1] = 1;
+ len = 3;
+ }
+ buf[2] = 0; // method #1 - method id #00: no authentication
+ if ( rfc1929 ) {
+ buf[2] = 2; // method #2 - method id #02: username/password
+ }
+ if ( send( socks_socket, (void *)buf, len, 0 ) == SOCKET_ERROR ) {
+ Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
+ return;
+ }
+
+ // get the response
+ len = recv( socks_socket, (void *)buf, 64, 0 );
+ if ( len == SOCKET_ERROR ) {
+ Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
+ return;
+ }
+ if ( len != 2 || buf[0] != 5 ) {
+ Com_Printf( "NET_OpenSocks: bad response\n" );
+ return;
+ }
+ switch( buf[1] ) {
+ case 0: // no authentication
+ break;
+ case 2: // username/password authentication
+ break;
+ default:
+ Com_Printf( "NET_OpenSocks: request denied\n" );
+ return;
+ }
+
+ // do username/password authentication if needed
+ if ( buf[1] == 2 ) {
+ int ulen;
+ int plen;
+
+ // build the request
+ ulen = strlen( net_socksUsername->string );
+ plen = strlen( net_socksPassword->string );
+
+ buf[0] = 1; // username/password authentication version
+ buf[1] = ulen;
+ if ( ulen ) {
+ memcpy( &buf[2], net_socksUsername->string, ulen );
+ }
+ buf[2 + ulen] = plen;
+ if ( plen ) {
+ memcpy( &buf[3 + ulen], net_socksPassword->string, plen );
+ }
+
+ // send it
+ if ( send( socks_socket, (void *)buf, 3 + ulen + plen, 0 ) == SOCKET_ERROR ) {
+ Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
+ return;
+ }
+
+ // get the response
+ len = recv( socks_socket, (void *)buf, 64, 0 );
+ if ( len == SOCKET_ERROR ) {
+ Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
+ return;
+ }
+ if ( len != 2 || buf[0] != 1 ) {
+ Com_Printf( "NET_OpenSocks: bad response\n" );
+ return;
+ }
+ if ( buf[1] != 0 ) {
+ Com_Printf( "NET_OpenSocks: authentication failed\n" );
+ return;
+ }
+ }
+
+ // send the UDP associate request
+ buf[0] = 5; // SOCKS version
+ buf[1] = 3; // command: UDP associate
+ buf[2] = 0; // reserved
+ buf[3] = 1; // address type: IPV4
+ *(int *)&buf[4] = INADDR_ANY;
+ *(short *)&buf[8] = htons( (short)port ); // port
+ if ( send( socks_socket, (void *)buf, 10, 0 ) == SOCKET_ERROR ) {
+ Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
+ return;
+ }
+
+ // get the response
+ len = recv( socks_socket, (void *)buf, 64, 0 );
+ if( len == SOCKET_ERROR ) {
+ Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
+ return;
+ }
+ if( len < 2 || buf[0] != 5 ) {
+ Com_Printf( "NET_OpenSocks: bad response\n" );
+ return;
+ }
+ // check completion code
+ if( buf[1] != 0 ) {
+ Com_Printf( "NET_OpenSocks: request denied: %i\n", buf[1] );
+ return;
+ }
+ if( buf[3] != 1 ) {
+ Com_Printf( "NET_OpenSocks: relay address is not IPV4: %i\n", buf[3] );
+ return;
+ }
+ ((struct sockaddr_in *)&socksRelayAddr)->sin_family = AF_INET;
+ ((struct sockaddr_in *)&socksRelayAddr)->sin_addr.s_addr = *(int *)&buf[4];
+ ((struct sockaddr_in *)&socksRelayAddr)->sin_port = *(short *)&buf[8];
+ memset( ((struct sockaddr_in *)&socksRelayAddr)->sin_zero, 0, 8 );
+
+ usingSocks = true;
+ */
+}
+
+/*
+=====================
+NET_AddLocalAddress
+=====================
+*/
+static void NET_AddLocalAddress(char *ifname, struct sockaddr *addr, struct sockaddr *netmask)
+{
+ int addrlen;
+ sa_family_t family;
+
+ // only add addresses that have all required info.
+ if (!addr || !netmask || !ifname) return;
+
+ family = addr->sa_family;
+
+ if (numIP < MAX_IPS)
+ {
+ if (family == AF_INET)
+ {
+ addrlen = sizeof(struct sockaddr_in);
+ localIP[numIP].type = NA_IP;
+ }
+ else if (family == AF_INET6)
+ {
+ addrlen = sizeof(struct sockaddr_in6);
+ localIP[numIP].type = NA_IP6;
+ }
+ else
+ return;
+
+ Q_strncpyz(localIP[numIP].ifname, ifname, sizeof(localIP[numIP].ifname));
+
+ localIP[numIP].family = family;
+
+ memcpy(&localIP[numIP].addr, addr, addrlen);
+ memcpy(&localIP[numIP].netmask, netmask, addrlen);
+
+ numIP++;
+ }
+}
+
+#if defined(__linux__) || defined(__APPLE__) || defined(__BSD__)
+static void NET_GetLocalAddress(void)
+{
+ struct ifaddrs *ifap, *search;
+
+ numIP = 0;
+
+ if (getifaddrs(&ifap))
+ Com_Printf("NET_GetLocalAddress: Unable to get list of network interfaces: %s\n", NET_ErrorString());
+ else
+ {
+ for (search = ifap; search; search = search->ifa_next)
+ {
+ // Only add interfaces that are up.
+ if (ifap->ifa_flags & IFF_UP) NET_AddLocalAddress(search->ifa_name, search->ifa_addr, search->ifa_netmask);
+ }
+
+ freeifaddrs(ifap);
+
+ Sys_ShowIP();
+ }
+}
+#else
+static void NET_GetLocalAddress(void)
+{
+ char hostname[256];
+ struct addrinfo hint;
+ struct addrinfo *res = NULL;
+
+ numIP = 0;
+
+ if (gethostname(hostname, 256) == SOCKET_ERROR) return;
+
+ memset(&hint, 0, sizeof(hint));
+
+ hint.ai_family = AF_UNSPEC;
+ hint.ai_socktype = SOCK_DGRAM;
+
+ if (!getaddrinfo(hostname, NULL, &hint, &res))
+ {
+ struct sockaddr_in mask4;
+ struct sockaddr_in6 mask6;
+ struct addrinfo *search;
+
+ /* On operating systems where it's more difficult to find out the configured interfaces, we'll just assume a
+ * netmask with all bits set. */
+
+ memset(&mask4, 0, sizeof(mask4));
+ memset(&mask6, 0, sizeof(mask6));
+ mask4.sin_family = AF_INET;
+ memset(&mask4.sin_addr.s_addr, 0xFF, sizeof(mask4.sin_addr.s_addr));
+ mask6.sin6_family = AF_INET6;
+ memset(&mask6.sin6_addr, 0xFF, sizeof(mask6.sin6_addr));
+
+ // add all IPs from returned list.
+ for (search = res; search; search = search->ai_next)
+ {
+ if (search->ai_family == AF_INET)
+ NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *)&mask4);
+ else if (search->ai_family == AF_INET6)
+ NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *)&mask6);
+ }
+
+ Sys_ShowIP();
+ }
+
+ if (res) freeaddrinfo(res);
+}
+#endif
+
+/*
+====================
+NET_OpenIP
+====================
+*/
+void NET_OpenIP(void)
+{
+ int a;
+ int i;
+ int err;
+ int ports[3];
+ int port6s[3];
+
+ for (a = 0; a < 3; ++a)
+ {
+ ports[a] = net_ports[a]->integer;
+ port6s[a] = net_port6s[a]->integer;
+ }
+
+ NET_GetLocalAddress();
+
+ for (a = 0; a < 3; ++a)
+ {
+ // indent
+ if (a == 0 && (net_alternateProtocols->integer & NET_DISABLEPRIMPROTO)) continue;
+ if (a == 1 && !(net_alternateProtocols->integer & NET_ENABLEALT1PROTO)) continue;
+ if (a == 2 && !(net_alternateProtocols->integer & NET_ENABLEALT2PROTO)) continue;
+
+ // automatically scan for a valid port, so multiple
+ // dedicated servers can be started without requiring
+ // a different net_port for each one
+
+ if (net_enabled->integer & NET_ENABLEV6)
+ {
+ for (i = 0; i < 10; i++)
+ {
+ ip6_sockets[a] = NET_IP6Socket(a, net_ip6->string, port6s[a] + i, &boundto, &err);
+ if (ip6_sockets[a] != INVALID_SOCKET)
+ {
+ Cvar_SetValue((a == 2 ? "net_alt2port6" : a == 1 ? "net_alt1port6" : "net_port6"), port6s[a] + i);
+ break;
+ }
+ else
+ {
+ if (err == EAFNOSUPPORT) break;
+ }
+ }
+ if (ip6_sockets[a] == INVALID_SOCKET)
+ Com_Printf("WARNING: Couldn't bind to a%s v6 ip address.\n",
+ (a == 2 ? "n alternate-2" : a == 1 ? "n alternate-1" : ""));
+ }
+
+ if (net_enabled->integer & NET_ENABLEV4)
+ {
+ for (i = 0; i < 10; i++)
+ {
+ ip_sockets[a] = NET_IPSocket(a, net_ip->string, ports[a] + i, &err);
+ if (ip_sockets[a] != INVALID_SOCKET)
+ {
+ Cvar_SetValue((a == 2 ? "net_alt2port" : a == 1 ? "net_alt1port" : "net_port"), ports[a] + i);
+
+ if (net_socksEnabled->integer) NET_OpenSocks(ports[a] + i);
+
+ break;
+ }
+ else
+ {
+ if (err == EAFNOSUPPORT) break;
+ }
+ }
+
+ if (ip_sockets[a] == INVALID_SOCKET)
+ Com_Printf("WARNING: Couldn't bind to a%s v4 ip address.\n",
+ (a == 2 ? "n alternate-2" : a == 1 ? "n alternate-1" : ""));
+ }
+ // outdent
+ }
+}
+
+//===================================================================
+
+/*
+====================
+NET_GetCvars
+====================
+*/
+static bool NET_GetCvars(void)
+{
+ int modified;
+ int a;
+
+#ifdef DEDICATED
+ // I want server owners to explicitly turn on ipv6 support.
+ net_enabled = Cvar_Get("net_enabled", "1", CVAR_LATCH | CVAR_ARCHIVE);
+#else
+ /* End users have it enabled so they can connect to ipv6-only hosts, but ipv4 will be
+ * used if available due to ping */
+ net_enabled = Cvar_Get("net_enabled", "3", CVAR_LATCH | CVAR_ARCHIVE);
+#endif
+ modified = net_enabled->modified;
+ net_enabled->modified = false;
+
+ net_alternateProtocols = Cvar_Get("net_alternateProtocols", "3", CVAR_LATCH | CVAR_ARCHIVE);
+ modified += net_alternateProtocols->modified;
+ net_alternateProtocols->modified = false;
+
+ net_ip = Cvar_Get("net_ip", "0.0.0.0", CVAR_LATCH);
+ modified += net_ip->modified;
+ net_ip->modified = false;
+
+ net_ip6 = Cvar_Get("net_ip6", "::", CVAR_LATCH);
+ modified += net_ip6->modified;
+ net_ip6->modified = false;
+
+ for (a = 0; a < 3; ++a)
+ {
+ net_ports[a] = Cvar_Get((a == 2 ? "net_alt2port" : a == 1 ? "net_alt1port" : "net_port"),
+ (a == 2 ? XSTRING(ALT2PORT_SERVER) : a == 1 ? XSTRING(ALT1PORT_SERVER) : XSTRING(PORT_SERVER)), CVAR_LATCH);
+ modified += net_ports[a]->modified;
+ net_ports[a]->modified = false;
+
+ net_port6s[a] = Cvar_Get((a == 2 ? "net_alt2port6" : a == 1 ? "net_alt1port6" : "net_port6"),
+ (a == 2 ? XSTRING(ALT2PORT_SERVER) : a == 1 ? XSTRING(ALT1PORT_SERVER) : XSTRING(PORT_SERVER)), CVAR_LATCH);
+ modified += net_port6s[a]->modified;
+ net_port6s[a]->modified = false;
+ }
+
+ // Some cvars for configuring multicast options which facilitates scanning for servers on local subnets.
+ net_mcast6addr = Cvar_Get("net_mcast6addr", NET_MULTICAST_IP6, CVAR_LATCH | CVAR_ARCHIVE);
+ modified += net_mcast6addr->modified;
+ net_mcast6addr->modified = false;
+
+#ifdef _WIN32
+ net_mcast6iface = Cvar_Get("net_mcast6iface", "0", CVAR_LATCH | CVAR_ARCHIVE);
+#else
+ net_mcast6iface = Cvar_Get("net_mcast6iface", "", CVAR_LATCH | CVAR_ARCHIVE);
+#endif
+ modified += net_mcast6iface->modified;
+ net_mcast6iface->modified = false;
+
+ net_socksEnabled = Cvar_Get("net_socksEnabled", "0", CVAR_LATCH | CVAR_ARCHIVE);
+ modified += net_socksEnabled->modified;
+ net_socksEnabled->modified = false;
+
+ net_socksServer = Cvar_Get("net_socksServer", "", CVAR_LATCH | CVAR_ARCHIVE);
+ modified += net_socksServer->modified;
+ net_socksServer->modified = false;
+
+ net_socksPort = Cvar_Get("net_socksPort", "1080", CVAR_LATCH | CVAR_ARCHIVE);
+ modified += net_socksPort->modified;
+ net_socksPort->modified = false;
+
+ net_socksUsername = Cvar_Get("net_socksUsername", "", CVAR_LATCH | CVAR_ARCHIVE);
+ modified += net_socksUsername->modified;
+ net_socksUsername->modified = false;
+
+ net_socksPassword = Cvar_Get("net_socksPassword", "", CVAR_LATCH | CVAR_ARCHIVE);
+ modified += net_socksPassword->modified;
+ net_socksPassword->modified = false;
+
+ net_dropsim = Cvar_Get("net_dropsim", "", CVAR_TEMP);
+
+ return modified ? true : false;
+}
+
+/*
+====================
+NET_Config
+====================
+*/
+void NET_Config(bool enableNetworking)
+{
+ bool modified;
+ bool stop;
+ bool start;
+ int a;
+
+ // get any latched changes to cvars
+ modified = NET_GetCvars();
+
+ if (!net_enabled->integer)
+ {
+ enableNetworking = false;
+ }
+
+ // if enable state is the same and no cvars were modified, we have nothing to do
+ if (enableNetworking == networkingEnabled && !modified)
+ {
+ return;
+ }
+
+ if (enableNetworking == networkingEnabled)
+ {
+ if (enableNetworking)
+ {
+ stop = true;
+ start = true;
+ }
+ else
+ {
+ stop = false;
+ start = false;
+ }
+ }
+ else
+ {
+ if (enableNetworking)
+ {
+ stop = false;
+ start = true;
+ }
+ else
+ {
+ stop = true;
+ start = false;
+ }
+ networkingEnabled = enableNetworking;
+ }
+
+ if (stop)
+ {
+ for (a = 0; a < 3; ++a)
+ {
+ if (ip_sockets[a] != INVALID_SOCKET)
+ {
+ closesocket(ip_sockets[a]);
+ ip_sockets[a] = INVALID_SOCKET;
+ }
+
+ if (ip6_sockets[a] != INVALID_SOCKET)
+ {
+ closesocket(ip6_sockets[a]);
+ ip6_sockets[a] = INVALID_SOCKET;
+ }
+ }
+
+ /*
+ TODO: accommodate
+ if(multicast6_socket != INVALID_SOCKET)
+ {
+ if(multicast6_socket != ip6_socket)
+ closesocket(multicast6_socket);
+
+ multicast6_socket = INVALID_SOCKET;
+ }
+
+ if ( socks_socket != INVALID_SOCKET ) {
+ closesocket( socks_socket );
+ socks_socket = INVALID_SOCKET;
+ }
+ */
+ }
+
+ if (start)
+ {
+ if (net_enabled->integer)
+ {
+ NET_OpenIP();
+ NET_SetMulticast6();
+ }
+ }
+}
+
+/*
+====================
+NET_Init
+====================
+*/
+void NET_Init(void)
+{
+#ifdef _WIN32
+ int r;
+
+ r = WSAStartup(MAKEWORD(1, 1), &winsockdata);
+ if (r)
+ {
+ Com_Printf("WARNING: Winsock initialization failed, returned %d\n", r);
+ return;
+ }
+
+ winsockInitialized = true;
+ Com_Printf("Winsock Initialized\n");
+#endif
+
+ NET_Config(true);
+
+ Cmd_AddCommand("net_restart", NET_Restart_f);
+}
+
+/*
+====================
+NET_Shutdown
+====================
+*/
+void NET_Shutdown(void)
+{
+ if (!networkingEnabled)
+ {
+ return;
+ }
+
+ NET_Config(false);
+
+#ifdef _WIN32
+ WSACleanup();
+ winsockInitialized = false;
+#endif
+}
+
+/*
+====================
+NET_Event
+
+Called from NET_Sleep which uses select() to determine which sockets have seen action.
+====================
+*/
+
+void NET_Event(fd_set *fdr)
+{
+ uint8_t bufData[MAX_MSGLEN + 1];
+ netadr_t from;
+ msg_t netmsg;
+
+ memset(&from, 0, sizeof(from));
+
+ while (1)
+ {
+ MSG_Init(&netmsg, bufData, sizeof(bufData));
+
+ if (NET_GetPacket(&from, &netmsg, fdr))
+ {
+ if (net_dropsim->value > 0.0f && net_dropsim->value <= 100.0f)
+ {
+ // com_dropsim->value percent of incoming packets get dropped.
+ if (rand() < (int)(((double)RAND_MAX) / 100.0 * (double)net_dropsim->value))
+ continue; // drop this packet
+ }
+
+ if (com_sv_running->integer)
+ Com_RunAndTimeServerPacket(&from, &netmsg);
+ else
+ CL_PacketEvent(from, &netmsg);
+ }
+ else
+ break;
+ }
+}
+
+/*
+====================
+NET_Sleep
+
+Sleeps msec or until something happens on the network
+====================
+*/
+void NET_Sleep(int msec)
+{
+ struct timeval timeout;
+ fd_set fdr;
+ int retval;
+ int a;
+ SOCKET highestfd = INVALID_SOCKET;
+
+ if (msec < 0) msec = 0;
+
+ FD_ZERO(&fdr);
+
+ for (a = 0; a < 3; ++a)
+ {
+ if (ip_sockets[a] != INVALID_SOCKET)
+ {
+ FD_SET(ip_sockets[a], &fdr);
+
+ if (highestfd == INVALID_SOCKET || ip_sockets[a] > highestfd) highestfd = ip_sockets[a];
+ }
+ if (ip6_sockets[a] != INVALID_SOCKET)
+ {
+ FD_SET(ip6_sockets[a], &fdr);
+
+ if (highestfd == INVALID_SOCKET || ip6_sockets[a] > highestfd) highestfd = ip6_sockets[a];
+ }
+ }
+
+#ifdef _WIN32
+ if (highestfd == INVALID_SOCKET)
+ {
+ // windows ain't happy when select is called without valid FDs
+ SleepEx(msec, 0);
+ return;
+ }
+#endif
+
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+
+ retval = select(highestfd + 1, &fdr, NULL, NULL, &timeout);
+
+ if (retval == SOCKET_ERROR)
+ Com_Printf("Warning: select() syscall failed: %s\n", NET_ErrorString());
+ else if (retval > 0)
+ NET_Event(&fdr);
+}
+
+/*
+====================
+NET_Restart_f
+====================
+*/
+void NET_Restart_f(void) { NET_Config(true); }
diff --git a/src/qcommon/parse.cpp b/src/qcommon/parse.cpp
new file mode 100644
index 0000000..aa72dec
--- /dev/null
+++ b/src/qcommon/parse.cpp
@@ -0,0 +1,3725 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "files.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+//script flags
+#define SCFL_NOERRORS 0x0001
+#define SCFL_NOWARNINGS 0x0002
+#define SCFL_NOSTRINGWHITESPACES 0x0004
+#define SCFL_NOSTRINGESCAPECHARS 0x0008
+#define SCFL_PRIMITIVE 0x0010
+#define SCFL_NOBINARYNUMBERS 0x0020
+#define SCFL_NONUMBERVALUES 0x0040
+
+//token types
+#define TT_STRING 1 // string
+#define TT_LITERAL 2 // literal
+#define TT_NUMBER 3 // number
+#define TT_NAME 4 // name
+#define TT_PUNCTUATION 5 // punctuation
+
+//string sub type
+//---------------
+// the length of the string
+//literal sub type
+//----------------
+// the ASCII code of the literal
+//number sub type
+//---------------
+#define TT_DECIMAL 0x0008 // decimal number
+#define TT_HEX 0x0100 // hexadecimal number
+#define TT_OCTAL 0x0200 // octal number
+#define TT_BINARY 0x0400 // binary number
+#define TT_FLOAT 0x0800 // floating point number
+#define TT_INTEGER 0x1000 // integer number
+#define TT_LONG 0x2000 // long number
+#define TT_UNSIGNED 0x4000 // unsigned number
+//punctuation sub type
+//--------------------
+#define P_RSHIFT_ASSIGN 1
+#define P_LSHIFT_ASSIGN 2
+#define P_PARMS 3
+#define P_PRECOMPMERGE 4
+
+#define P_LOGIC_AND 5
+#define P_LOGIC_OR 6
+#define P_LOGIC_GEQ 7
+#define P_LOGIC_LEQ 8
+#define P_LOGIC_EQ 9
+#define P_LOGIC_UNEQ 10
+
+#define P_MUL_ASSIGN 11
+#define P_DIV_ASSIGN 12
+#define P_MOD_ASSIGN 13
+#define P_ADD_ASSIGN 14
+#define P_SUB_ASSIGN 15
+#define P_INC 16
+#define P_DEC 17
+
+#define P_BIN_AND_ASSIGN 18
+#define P_BIN_OR_ASSIGN 19
+#define P_BIN_XOR_ASSIGN 20
+#define P_RSHIFT 21
+#define P_LSHIFT 22
+
+#define P_POINTERREF 23
+#define P_CPP1 24
+#define P_CPP2 25
+#define P_MUL 26
+#define P_DIV 27
+#define P_MOD 28
+#define P_ADD 29
+#define P_SUB 30
+#define P_ASSIGN 31
+
+#define P_BIN_AND 32
+#define P_BIN_OR 33
+#define P_BIN_XOR 34
+#define P_BIN_NOT 35
+
+#define P_LOGIC_NOT 36
+#define P_LOGIC_GREATER 37
+#define P_LOGIC_LESS 38
+
+#define P_REF 39
+#define P_COMMA 40
+#define P_SEMICOLON 41
+#define P_COLON 42
+#define P_QUESTIONMARK 43
+
+#define P_PARENTHESESOPEN 44
+#define P_PARENTHESESCLOSE 45
+#define P_BRACEOPEN 46
+#define P_BRACECLOSE 47
+#define P_SQBRACKETOPEN 48
+#define P_SQBRACKETCLOSE 49
+#define P_BACKSLASH 50
+
+#define P_PRECOMP 51
+#define P_DOLLAR 52
+
+//name sub type
+//-------------
+// the length of the name
+
+//punctuation
+typedef struct punctuation_s
+{
+ const char *p; //punctuation character(s)
+ int n; //punctuation indication
+ struct punctuation_s *next; //next punctuation
+} punctuation_t;
+
+//token
+typedef struct token_s
+{
+ char string[MAX_TOKEN_CHARS]; //available token
+ int type; //last read token type
+ int subtype; //last read token sub type
+ unsigned long int intvalue; //integer value
+ double floatvalue; //floating point value
+ char *whitespace_p; //start of white space before token
+ char *endwhitespace_p; //start of white space before token
+ int line; //line the token was on
+ int linescrossed; //lines crossed in white space
+ struct token_s *next; //next token in chain
+} token_t;
+
+//script file
+typedef struct script_s
+{
+ char filename[1024]; //file name of the script
+ char *buffer; //buffer containing the script
+ char *script_p; //current pointer in the script
+ char *end_p; //pointer to the end of the script
+ char *lastscript_p; //script pointer before reading token
+ char *whitespace_p; //begin of the white space
+ char *endwhitespace_p;
+ int length; //length of the script in bytes
+ int line; //current line in script
+ int lastline; //line before reading token
+ int tokenavailable; //set by UnreadLastToken
+ int flags; //several script flags
+ punctuation_t *punctuations; //the punctuations used in the script
+ punctuation_t **punctuationtable;
+ token_t token; //available token
+ struct script_s *next; //next script in a chain
+} script_t;
+
+
+#define DEFINE_FIXED 0x0001
+
+#define BUILTIN_LINE 1
+#define BUILTIN_FILE 2
+#define BUILTIN_DATE 3
+#define BUILTIN_TIME 4
+#define BUILTIN_STDC 5
+
+#define INDENT_IF 0x0001
+#define INDENT_ELSE 0x0002
+#define INDENT_ELIF 0x0004
+#define INDENT_IFDEF 0x0008
+#define INDENT_IFNDEF 0x0010
+
+//macro definitions
+typedef struct define_s
+{
+ char *name; //define name
+ int flags; //define flags
+ int builtin; // > 0 if builtin define
+ int numparms; //number of define parameters
+ token_t *parms; //define parameters
+ token_t *tokens; //macro tokens (possibly containing parm tokens)
+ struct define_s *next; //next defined macro in a list
+ struct define_s *hashnext; //next define in the hash chain
+} define_t;
+
+//indents
+//used for conditional compilation directives:
+//#if, #else, #elif, #ifdef, #ifndef
+typedef struct indent_s
+{
+ int type; //indent type
+ int skip; //true if skipping current indent
+ script_t *script; //script the indent was in
+ struct indent_s *next; //next indent on the indent stack
+} indent_t;
+
+//source file
+typedef struct source_s
+{
+ char filename[MAX_QPATH]; //file name of the script
+ char includepath[MAX_QPATH]; //path to include files
+ punctuation_t *punctuations; //punctuations to use
+ script_t *scriptstack; //stack with scripts of the source
+ token_t *tokens; //tokens to read first
+ define_t *defines; //list with macro definitions
+ define_t **definehash; //hash chain with defines
+ indent_t *indentstack; //stack with indents
+ int skip; // > 0 if skipping conditional code
+ token_t token; //last read token
+} source_t;
+
+#define MAX_DEFINEPARMS 128
+
+//directive name with parse function
+typedef struct directive_s
+{
+ const char *name;
+ bool (*func)(source_t *source);
+} directive_t;
+
+#define DEFINEHASHSIZE 1024
+
+static bool Parse_ReadToken(source_t *source, token_t *token);
+static bool Parse_AddDefineToSourceFromString( source_t *source, const char *string );
+
+int numtokens;
+
+//list with global defines added to every source loaded
+define_t *globaldefines;
+
+//longer punctuations first
+punctuation_t default_punctuations[] =
+{
+ //binary operators
+ {">>=",P_RSHIFT_ASSIGN, NULL},
+ {"<<=",P_LSHIFT_ASSIGN, NULL},
+ //
+ {"...",P_PARMS, NULL},
+ //define merge operator
+ {"##",P_PRECOMPMERGE, NULL},
+ //logic operators
+ {"&&",P_LOGIC_AND, NULL},
+ {"||",P_LOGIC_OR, NULL},
+ {">=",P_LOGIC_GEQ, NULL},
+ {"<=",P_LOGIC_LEQ, NULL},
+ {"==",P_LOGIC_EQ, NULL},
+ {"!=",P_LOGIC_UNEQ, NULL},
+ //arithmatic operators
+ {"*=",P_MUL_ASSIGN, NULL},
+ {"/=",P_DIV_ASSIGN, NULL},
+ {"%=",P_MOD_ASSIGN, NULL},
+ {"+=",P_ADD_ASSIGN, NULL},
+ {"-=",P_SUB_ASSIGN, NULL},
+ {"++",P_INC, NULL},
+ {"--",P_DEC, NULL},
+ //binary operators
+ {"&=",P_BIN_AND_ASSIGN, NULL},
+ {"|=",P_BIN_OR_ASSIGN, NULL},
+ {"^=",P_BIN_XOR_ASSIGN, NULL},
+ {">>",P_RSHIFT, NULL},
+ {"<<",P_LSHIFT, NULL},
+ //reference operators
+ {"->",P_POINTERREF, NULL},
+ //C++
+ {"::",P_CPP1, NULL},
+ {".*",P_CPP2, NULL},
+ //arithmatic operators
+ {"*",P_MUL, NULL},
+ {"/",P_DIV, NULL},
+ {"%",P_MOD, NULL},
+ {"+",P_ADD, NULL},
+ {"-",P_SUB, NULL},
+ {"=",P_ASSIGN, NULL},
+ //binary operators
+ {"&",P_BIN_AND, NULL},
+ {"|",P_BIN_OR, NULL},
+ {"^",P_BIN_XOR, NULL},
+ {"~",P_BIN_NOT, NULL},
+ //logic operators
+ {"!",P_LOGIC_NOT, NULL},
+ {">",P_LOGIC_GREATER, NULL},
+ {"<",P_LOGIC_LESS, NULL},
+ //reference operator
+ {".",P_REF, NULL},
+ //seperators
+ {",",P_COMMA, NULL},
+ {";",P_SEMICOLON, NULL},
+ //label indication
+ {":",P_COLON, NULL},
+ //if statement
+ {"?",P_QUESTIONMARK, NULL},
+ //embracements
+ {"(",P_PARENTHESESOPEN, NULL},
+ {")",P_PARENTHESESCLOSE, NULL},
+ {"{",P_BRACEOPEN, NULL},
+ {"}",P_BRACECLOSE, NULL},
+ {"[",P_SQBRACKETOPEN, NULL},
+ {"]",P_SQBRACKETCLOSE, NULL},
+ //
+ {"\\",P_BACKSLASH, NULL},
+ //precompiler operator
+ {"#",P_PRECOMP, NULL},
+ {"$",P_DOLLAR, NULL},
+ {NULL, 0, NULL}
+};
+
+/*
+===============
+Parse_CreatePunctuationTable
+===============
+*/
+static void Parse_CreatePunctuationTable(script_t *script, punctuation_t *punctuations)
+{
+ int i;
+ punctuation_t *p, *lastp, *newp;
+
+ //get memory for the table
+ if (!script->punctuationtable)
+ script->punctuationtable = (punctuation_t **)Z_Malloc(256 * sizeof(punctuation_t *));
+
+ ::memset(script->punctuationtable, 0, 256 * sizeof(punctuation_t *));
+ //add the punctuations in the list to the punctuation table
+ for (i = 0; punctuations[i].p; i++)
+ {
+ newp = &punctuations[i];
+ lastp = NULL;
+ //sort the punctuations in this table entry on length (longer punctuations first)
+ for (p = script->punctuationtable[(unsigned int) newp->p[0]]; p; p = p->next)
+ {
+ if (strlen(p->p) < strlen(newp->p))
+ {
+ newp->next = p;
+ if (lastp) lastp->next = newp;
+ else script->punctuationtable[(unsigned int) newp->p[0]] = newp;
+ break;
+ }
+ lastp = p;
+ }
+ if (!p)
+ {
+ newp->next = NULL;
+ if (lastp) lastp->next = newp;
+ else script->punctuationtable[(unsigned int) newp->p[0]] = newp;
+ }
+ }
+}
+
+/*
+===============
+Parse_ScriptError
+===============
+*/
+__attribute__ ((format (printf, 2, 3))) static void QDECL Parse_ScriptError(script_t *script, const char *str, ...)
+{
+ char text[1024];
+ va_list ap;
+
+ if (script->flags & SCFL_NOERRORS) return;
+
+ va_start(ap, str);
+ vsprintf(text, str, ap);
+ va_end(ap);
+ Com_Printf( "file %s, line %d: %s\n", script->filename, script->line, text);
+}
+
+/*
+===============
+Parse_ScriptWarning
+===============
+*/
+__attribute__ ((format (printf, 2, 3))) static void QDECL Parse_ScriptWarning(script_t *script, const char *str, ...)
+{
+ char text[1024];
+ va_list ap;
+
+ if (script->flags & SCFL_NOWARNINGS) return;
+
+ va_start(ap, str);
+ vsprintf(text, str, ap);
+ va_end(ap);
+ Com_Printf( "file %s, line %d: %s\n", script->filename, script->line, text);
+}
+
+/*
+===============
+Parse_SetScriptPunctuations
+===============
+*/
+static void Parse_SetScriptPunctuations(script_t *script, punctuation_t *p)
+{
+ if (p) Parse_CreatePunctuationTable(script, p);
+ else Parse_CreatePunctuationTable(script, default_punctuations);
+ if (p) script->punctuations = p;
+ else script->punctuations = default_punctuations;
+}
+
+/*
+===============
+Parse_ReadWhiteSpace
+===============
+*/
+static bool Parse_ReadWhiteSpace(script_t *script)
+{
+ while(1)
+ {
+ //skip white space
+ while(*script->script_p <= ' ')
+ {
+ if (!*script->script_p) return false;
+ if (*script->script_p == '\n') script->line++;
+ script->script_p++;
+ }
+ //skip comments
+ if (*script->script_p == '/')
+ {
+ //comments //
+ if (*(script->script_p+1) == '/')
+ {
+ script->script_p++;
+ do
+ {
+ script->script_p++;
+ if (!*script->script_p) return false;
+ }
+ while(*script->script_p != '\n');
+ script->line++;
+ script->script_p++;
+ if (!*script->script_p) return false;
+ continue;
+ }
+ //comments /* */
+ else if (*(script->script_p+1) == '*')
+ {
+ script->script_p++;
+ do
+ {
+ script->script_p++;
+ if (!*script->script_p) return false;
+ if (*script->script_p == '\n') script->line++;
+ }
+ while(!(*script->script_p == '*' && *(script->script_p+1) == '/'));
+ script->script_p++;
+ if (!*script->script_p) return false;
+ script->script_p++;
+ if (!*script->script_p) return false;
+ continue;
+ }
+ }
+ break;
+ }
+ return true;
+}
+
+/*
+===============
+Parse_ReadEscapeCharacter
+===============
+*/
+static bool Parse_ReadEscapeCharacter(script_t *script, char *ch)
+{
+ int c, val, i;
+
+ //step over the leading '\\'
+ script->script_p++;
+ //determine the escape character
+ switch(*script->script_p)
+ {
+ case '\\': c = '\\'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'v': c = '\v'; break;
+ case 'b': c = '\b'; break;
+ case 'f': c = '\f'; break;
+ case 'a': c = '\a'; break;
+ case '\'': c = '\''; break;
+ case '\"': c = '\"'; break;
+ case '\?': c = '\?'; break;
+ case 'x':
+ {
+ script->script_p++;
+ for (i = 0, val = 0; ; i++, script->script_p++)
+ {
+ c = *script->script_p;
+ if (c >= '0' && c <= '9') c = c - '0';
+ else if (c >= 'A' && c <= 'Z') c = c - 'A' + 10;
+ else if (c >= 'a' && c <= 'z') c = c - 'a' + 10;
+ else break;
+ val = (val << 4) + c;
+ }
+ script->script_p--;
+ if (val > 0xFF)
+ {
+ Parse_ScriptWarning(script, "too large value in escape character");
+ val = 0xFF;
+ }
+ c = val;
+ break;
+ }
+ default: //NOTE: decimal ASCII code, NOT octal
+ {
+ if (*script->script_p < '0' || *script->script_p > '9') Parse_ScriptError(script, "unknown escape char");
+ for (i = 0, val = 0; ; i++, script->script_p++)
+ {
+ c = *script->script_p;
+ if (c >= '0' && c <= '9') c = c - '0';
+ else break;
+ val = val * 10 + c;
+ }
+ script->script_p--;
+ if (val > 0xFF)
+ {
+ Parse_ScriptWarning(script, "too large value in escape character");
+ val = 0xFF;
+ }
+ c = val;
+ break;
+ }
+ }
+ //step over the escape character or the last digit of the number
+ script->script_p++;
+ //store the escape character
+ *ch = c;
+ //succesfully read escape character
+ return true;
+}
+
+/*
+===============
+Parse_ReadString
+
+Reads C-like string. Escape characters are interpretted.
+Quotes are included with the string.
+Reads two strings with a white space between them as one string.
+===============
+*/
+static bool Parse_ReadString(script_t *script, token_t *token, int quote)
+{
+ int len, tmpline;
+ char *tmpscript_p;
+
+ if (quote == '\"') token->type = TT_STRING;
+ else token->type = TT_LITERAL;
+
+ len = 0;
+ //leading quote
+ token->string[len++] = *script->script_p++;
+ //
+ while(1)
+ {
+ //minus 2 because trailing double quote and zero have to be appended
+ if (len >= MAX_TOKEN_CHARS - 2)
+ {
+ Parse_ScriptError(script, "string longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS);
+ return false;
+ }
+ //if there is an escape character and
+ //if escape characters inside a string are allowed
+ if (*script->script_p == '\\' && !(script->flags & SCFL_NOSTRINGESCAPECHARS))
+ {
+ if (!Parse_ReadEscapeCharacter(script, &token->string[len]))
+ {
+ token->string[len] = 0;
+ return false;
+ }
+ len++;
+ }
+ //if a trailing quote
+ else if (*script->script_p == quote)
+ {
+ //step over the double quote
+ script->script_p++;
+ //if white spaces in a string are not allowed
+ if (script->flags & SCFL_NOSTRINGWHITESPACES) break;
+ //
+ tmpscript_p = script->script_p;
+ tmpline = script->line;
+ //read unusefull stuff between possible two following strings
+ if (!Parse_ReadWhiteSpace(script))
+ {
+ script->script_p = tmpscript_p;
+ script->line = tmpline;
+ break;
+ }
+ //if there's no leading double qoute
+ if (*script->script_p != quote)
+ {
+ script->script_p = tmpscript_p;
+ script->line = tmpline;
+ break;
+ }
+ //step over the new leading double quote
+ script->script_p++;
+ }
+ else
+ {
+ if (*script->script_p == '\0')
+ {
+ token->string[len] = 0;
+ Parse_ScriptError(script, "missing trailing quote");
+ return false;
+ }
+ if (*script->script_p == '\n')
+ {
+ token->string[len] = 0;
+ Parse_ScriptError(script, "newline inside string %s", token->string);
+ return false;
+ }
+ token->string[len++] = *script->script_p++;
+ }
+ }
+ //trailing quote
+ token->string[len++] = quote;
+ //end string with a zero
+ token->string[len] = '\0';
+ //the sub type is the length of the string
+ token->subtype = len;
+ return true;
+}
+
+/*
+===============
+Parse_ReadName
+===============
+*/
+static bool Parse_ReadName(script_t *script, token_t *token)
+{
+ int len = 0;
+ char c;
+
+ token->type = TT_NAME;
+ do
+ {
+ token->string[len++] = *script->script_p++;
+ if (len >= MAX_TOKEN_CHARS)
+ {
+ Parse_ScriptError(script, "name longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS);
+ return false;
+ }
+ c = *script->script_p;
+ } while ((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_');
+ token->string[len] = '\0';
+ //the sub type is the length of the name
+ token->subtype = len;
+ return true;
+}
+
+/*
+===============
+Parse_NumberValue
+===============
+*/
+static void Parse_NumberValue(char *string, int subtype, unsigned long int *intvalue,
+ double *floatvalue)
+{
+ unsigned long int dotfound = 0;
+
+ *intvalue = 0;
+ *floatvalue = 0;
+ //floating point number
+ if (subtype & TT_FLOAT)
+ {
+ while(*string)
+ {
+ if (*string == '.')
+ {
+ if (dotfound) return;
+ dotfound = 10;
+ string++;
+ }
+ if (dotfound)
+ {
+ *floatvalue = *floatvalue + (double) (*string - '0') /
+ (double) dotfound;
+ dotfound *= 10;
+ }
+ else
+ {
+ *floatvalue = *floatvalue * 10.0 + (double) (*string - '0');
+ }
+ string++;
+ }
+ *intvalue = (unsigned long) *floatvalue;
+ }
+ else if (subtype & TT_DECIMAL)
+ {
+ while(*string) *intvalue = *intvalue * 10 + (*string++ - '0');
+ *floatvalue = *intvalue;
+ }
+ else if (subtype & TT_HEX)
+ {
+ //step over the leading 0x or 0X
+ string += 2;
+ while(*string)
+ {
+ *intvalue <<= 4;
+ if (*string >= 'a' && *string <= 'f') *intvalue += *string - 'a' + 10;
+ else if (*string >= 'A' && *string <= 'F') *intvalue += *string - 'A' + 10;
+ else *intvalue += *string - '0';
+ string++;
+ }
+ *floatvalue = *intvalue;
+ }
+ else if (subtype & TT_OCTAL)
+ {
+ //step over the first zero
+ string += 1;
+ while(*string) *intvalue = (*intvalue << 3) + (*string++ - '0');
+ *floatvalue = *intvalue;
+ }
+ else if (subtype & TT_BINARY)
+ {
+ //step over the leading 0b or 0B
+ string += 2;
+ while(*string) *intvalue = (*intvalue << 1) + (*string++ - '0');
+ *floatvalue = *intvalue;
+ }
+}
+
+/*
+===============
+Parse_ReadNumber
+===============
+*/
+static bool Parse_ReadNumber(script_t *script, token_t *token)
+{
+ int len = 0, i;
+ int octal, dot;
+ char c;
+// unsigned long int intvalue = 0;
+// double floatvalue = 0;
+
+ token->type = TT_NUMBER;
+ //check for a hexadecimal number
+ if (*script->script_p == '0' &&
+ (*(script->script_p + 1) == 'x' ||
+ *(script->script_p + 1) == 'X'))
+ {
+ token->string[len++] = *script->script_p++;
+ token->string[len++] = *script->script_p++;
+ c = *script->script_p;
+ //hexadecimal
+ while((c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'f') ||
+ (c >= 'A' && c <= 'A'))
+ {
+ token->string[len++] = *script->script_p++;
+ if (len >= MAX_TOKEN_CHARS)
+ {
+ Parse_ScriptError(script, "hexadecimal number longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS);
+ return false;
+ }
+ c = *script->script_p;
+ }
+ token->subtype |= TT_HEX;
+ }
+#ifdef BINARYNUMBERS
+ //check for a binary number
+ else if (*script->script_p == '0' &&
+ (*(script->script_p + 1) == 'b' ||
+ *(script->script_p + 1) == 'B'))
+ {
+ token->string[len++] = *script->script_p++;
+ token->string[len++] = *script->script_p++;
+ c = *script->script_p;
+ //binary
+ while(c == '0' || c == '1')
+ {
+ token->string[len++] = *script->script_p++;
+ if (len >= MAX_TOKEN_CHARS)
+ {
+ Parse_ScriptError(script, "binary number longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS);
+ return false;
+ }
+ c = *script->script_p;
+ }
+ token->subtype |= TT_BINARY;
+ }
+#endif //BINARYNUMBERS
+ else //decimal or octal integer or floating point number
+ {
+ octal = false;
+ dot = false;
+ if (*script->script_p == '0') octal = true;
+ while(1)
+ {
+ c = *script->script_p;
+ if (c == '.') dot = true;
+ else if (c == '8' || c == '9') octal = false;
+ else if (c < '0' || c > '9') break;
+ token->string[len++] = *script->script_p++;
+ if (len >= MAX_TOKEN_CHARS - 1)
+ {
+ Parse_ScriptError(script, "number longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS);
+ return false;
+ }
+ }
+ if (octal) token->subtype |= TT_OCTAL;
+ else token->subtype |= TT_DECIMAL;
+ if (dot) token->subtype |= TT_FLOAT;
+ }
+ for (i = 0; i < 2; i++)
+ {
+ c = *script->script_p;
+ //check for a LONG number
+ if ( (c == 'l' || c == 'L')
+ && !(token->subtype & TT_LONG))
+ {
+ script->script_p++;
+ token->subtype |= TT_LONG;
+ }
+ //check for an UNSIGNED number
+ else if ( (c == 'u' || c == 'U')
+ && !(token->subtype & (TT_UNSIGNED | TT_FLOAT)))
+ {
+ script->script_p++;
+ token->subtype |= TT_UNSIGNED;
+ }
+ }
+ token->string[len] = '\0';
+ Parse_NumberValue(token->string, token->subtype, &token->intvalue, &token->floatvalue);
+ if (!(token->subtype & TT_FLOAT)) token->subtype |= TT_INTEGER;
+ return true;
+}
+
+/*
+===============
+Parse_ReadPunctuation
+===============
+*/
+static bool Parse_ReadPunctuation(script_t *script, token_t *token)
+{
+ int len;
+ const char *p;
+ punctuation_t *punc;
+
+ for (punc = script->punctuationtable[(unsigned int)*script->script_p]; punc; punc = punc->next)
+ {
+ p = punc->p;
+ len = strlen(p);
+ //if the script contains at least as much characters as the punctuation
+ if (script->script_p + len <= script->end_p)
+ {
+ //if the script contains the punctuation
+ if (!strncmp(script->script_p, p, len))
+ {
+ strncpy(token->string, p, MAX_TOKEN_CHARS);
+ script->script_p += len;
+ token->type = TT_PUNCTUATION;
+ //sub type is the number of the punctuation
+ token->subtype = punc->n;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/*
+===============
+Parse_ReadPrimitive
+===============
+*/
+static bool Parse_ReadPrimitive(script_t *script, token_t *token)
+{
+ int len;
+
+ len = 0;
+ while(*script->script_p > ' ' && *script->script_p != ';')
+ {
+ if (len >= MAX_TOKEN_CHARS)
+ {
+ Parse_ScriptError(script, "primitive token longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS);
+ return false;
+ }
+ token->string[len++] = *script->script_p++;
+ }
+ token->string[len] = 0;
+ //copy the token into the script structure
+ ::memcpy(&script->token, token, sizeof(token_t));
+ //primitive reading successfull
+ return true;
+}
+
+/*
+===============
+Parse_ReadScriptToken
+===============
+*/
+static bool Parse_ReadScriptToken(script_t *script, token_t *token)
+{
+ //if there is a token available (from UnreadToken)
+ if (script->tokenavailable)
+ {
+ script->tokenavailable = 0;
+ ::memcpy(token, &script->token, sizeof(token_t));
+ return true;
+ }
+ //save script pointer
+ script->lastscript_p = script->script_p;
+ //save line counter
+ script->lastline = script->line;
+ //clear the token stuff
+ ::memset(token, 0, sizeof(token_t));
+ //start of the white space
+ script->whitespace_p = script->script_p;
+ token->whitespace_p = script->script_p;
+ //read unusefull stuff
+ if (!Parse_ReadWhiteSpace(script)) return false;
+
+ script->endwhitespace_p = script->script_p;
+ token->endwhitespace_p = script->script_p;
+ //line the token is on
+ token->line = script->line;
+ //number of lines crossed before token
+ token->linescrossed = script->line - script->lastline;
+ //if there is a leading double quote
+ if (*script->script_p == '\"')
+ {
+ if (!Parse_ReadString(script, token, '\"')) return false;
+ }
+ //if an literal
+ else if (*script->script_p == '\'')
+ {
+ //if (!Parse_ReadLiteral(script, token)) return false;
+ if (!Parse_ReadString(script, token, '\'')) return false;
+ }
+ //if there is a number
+ else if ((*script->script_p >= '0' && *script->script_p <= '9') ||
+ (*script->script_p == '.' &&
+ (*(script->script_p + 1) >= '0' && *(script->script_p + 1) <= '9')))
+ {
+ if (!Parse_ReadNumber(script, token)) return 0;
+ }
+ //if this is a primitive script
+ else if (script->flags & SCFL_PRIMITIVE)
+ {
+ return Parse_ReadPrimitive(script, token);
+ }
+ //if there is a name
+ else if ((*script->script_p >= 'a' && *script->script_p <= 'z') ||
+ (*script->script_p >= 'A' && *script->script_p <= 'Z') ||
+ *script->script_p == '_')
+ {
+ if (!Parse_ReadName(script, token)) return false;
+ }
+ //check for punctuations
+ else if (!Parse_ReadPunctuation(script, token))
+ {
+ Parse_ScriptError(script, "can't read token");
+ return false;
+ }
+ //copy the token into the script structure
+ ::memcpy(&script->token, token, sizeof(token_t));
+ //succesfully read a token
+ return true;
+}
+
+/*
+===============
+Parse_StripDoubleQuotes
+===============
+*/
+static void Parse_StripDoubleQuotes(char *string)
+{
+ if (*string == '\"')
+ {
+ memmove( string, string + 1, strlen( string ) + 1 );
+ }
+ if (string[strlen(string)-1] == '\"')
+ {
+ string[strlen(string)-1] = '\0';
+ }
+}
+
+/*
+===============
+Parse_EndOfScript
+===============
+*/
+static bool Parse_EndOfScript(script_t *script)
+{
+ return script->script_p >= script->end_p;
+}
+
+/*
+===============
+Parse_LoadScriptFile
+===============
+*/
+static script_t *Parse_LoadScriptFile(const char *filename)
+{
+ fileHandle_t fp;
+ int length;
+ void *buffer;
+ script_t *script;
+
+ length = FS_FOpenFileRead( filename, &fp, false );
+ if (!fp) return NULL;
+
+ buffer = Z_Malloc(sizeof(script_t) + length + 1);
+ ::memset( buffer, 0, sizeof(script_t) + length + 1 );
+
+ script = (script_t *) buffer;
+ ::memset(script, 0, sizeof(script_t));
+ strcpy(script->filename, filename);
+ script->buffer = (char *) buffer + sizeof(script_t);
+ script->buffer[length] = 0;
+ script->length = length;
+ //pointer in script buffer
+ script->script_p = script->buffer;
+ //pointer in script buffer before reading token
+ script->lastscript_p = script->buffer;
+ //pointer to end of script buffer
+ script->end_p = &script->buffer[length];
+ //set if there's a token available in script->token
+ script->tokenavailable = 0;
+ //
+ script->line = 1;
+ script->lastline = 1;
+ //
+ Parse_SetScriptPunctuations(script, NULL);
+ //
+ FS_Read(script->buffer, length, fp);
+ FS_FCloseFile(fp);
+ //
+
+ return script;
+}
+
+/*
+===============
+Parse_LoadScriptMemory
+===============
+*/
+static script_t *Parse_LoadScriptMemory(const char *ptr, int length, const char *name)
+{
+ void *buffer;
+ script_t *script;
+
+ buffer = Z_Malloc(sizeof(script_t) + length + 1);
+ ::memset( buffer, 0, sizeof(script_t) + length + 1 );
+
+ script = (script_t *) buffer;
+ ::memset(script, 0, sizeof(script_t));
+ strcpy(script->filename, name);
+ script->buffer = (char *) buffer + sizeof(script_t);
+ script->buffer[length] = 0;
+ script->length = length;
+ //pointer in script buffer
+ script->script_p = script->buffer;
+ //pointer in script buffer before reading token
+ script->lastscript_p = script->buffer;
+ //pointer to end of script buffer
+ script->end_p = &script->buffer[length];
+ //set if there's a token available in script->token
+ script->tokenavailable = 0;
+ //
+ script->line = 1;
+ script->lastline = 1;
+ //
+ Parse_SetScriptPunctuations(script, NULL);
+ //
+ ::memcpy(script->buffer, ptr, length);
+ //
+ return script;
+}
+
+/*
+===============
+Parse_FreeScript
+===============
+*/
+static void Parse_FreeScript(script_t *script)
+{
+ if (script->punctuationtable) Z_Free(script->punctuationtable);
+ Z_Free(script);
+}
+
+/*
+===============
+Parse_SourceError
+===============
+*/
+__attribute__ ((format (printf, 2, 3))) static void QDECL Parse_SourceError(source_t *source, const char *str, ...)
+{
+ char text[1024];
+ va_list ap;
+
+ va_start(ap, str);
+ vsprintf(text, str, ap);
+ va_end(ap);
+ Com_Printf( "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
+}
+
+/*
+===============
+Parse_SourceWarning
+===============
+*/
+__attribute__ ((format (printf, 2, 3))) static void QDECL Parse_SourceWarning(source_t *source, const char *str, ...)
+{
+ char text[1024];
+ va_list ap;
+
+ va_start(ap, str);
+ vsprintf(text, str, ap);
+ va_end(ap);
+ Com_Printf( "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
+}
+
+/*
+===============
+Parse_PushIndent
+===============
+*/
+static void Parse_PushIndent(source_t *source, int type, int skip)
+{
+ indent_t *indent;
+
+ indent = (indent_t *) Z_Malloc(sizeof(indent_t));
+ indent->type = type;
+ indent->script = source->scriptstack;
+ indent->skip = (skip != 0);
+ source->skip += indent->skip;
+ indent->next = source->indentstack;
+ source->indentstack = indent;
+}
+
+/*
+===============
+Parse_PopIndent
+===============
+*/
+static void Parse_PopIndent(source_t *source, int *type, int *skip)
+{
+ indent_t *indent;
+
+ *type = 0;
+ *skip = 0;
+
+ indent = source->indentstack;
+ if (!indent) return;
+
+ //must be an indent from the current script
+ if (source->indentstack->script != source->scriptstack) return;
+
+ *type = indent->type;
+ *skip = indent->skip;
+ source->indentstack = source->indentstack->next;
+ source->skip -= indent->skip;
+ Z_Free(indent);
+}
+
+/*
+===============
+Parse_PushScript
+===============
+*/
+static void Parse_PushScript(source_t *source, script_t *script)
+{
+ script_t *s;
+
+ for (s = source->scriptstack; s; s = s->next)
+ {
+ if (!Q_stricmp(s->filename, script->filename))
+ {
+ Parse_SourceError(source, "%s recursively included", script->filename);
+ return;
+ }
+ }
+ //push the script on the script stack
+ script->next = source->scriptstack;
+ source->scriptstack = script;
+}
+
+/*
+===============
+Parse_CopyToken
+===============
+*/
+static token_t *Parse_CopyToken(token_t *token)
+{
+ token_t *t;
+
+// t = (token_t *) malloc(sizeof(token_t));
+ t = (token_t *) Z_Malloc(sizeof(token_t));
+// t = freetokens;
+ if (!t)
+ {
+ Com_Error(ERR_FATAL, "out of token space\n");
+ return NULL;
+ }
+// freetokens = freetokens->next;
+ ::memcpy(t, token, sizeof(token_t));
+ t->next = NULL;
+ numtokens++;
+ return t;
+}
+
+/*
+===============
+Parse_FreeToken
+===============
+*/
+static void Parse_FreeToken(token_t *token)
+{
+ //free(token);
+ Z_Free(token);
+// token->next = freetokens;
+// freetokens = token;
+ numtokens--;
+}
+
+/*
+===============
+Parse_ReadSourceToken
+===============
+*/
+static bool Parse_ReadSourceToken(source_t *source, token_t *token)
+{
+ token_t *t;
+ script_t *script;
+ int type, skip, lines;
+
+ lines = 0;
+ //if there's no token already available
+ while(!source->tokens)
+ {
+ //if there's a token to read from the script
+ if( Parse_ReadScriptToken( source->scriptstack, token ) )
+ {
+ token->linescrossed += lines;
+ return true;
+ }
+
+ // if lines were crossed before the end of the script, count them
+ lines += source->scriptstack->line - source->scriptstack->lastline;
+
+ //if at the end of the script
+ if (Parse_EndOfScript(source->scriptstack))
+ {
+ //remove all indents of the script
+ while(source->indentstack &&
+ source->indentstack->script == source->scriptstack)
+ {
+ Parse_SourceWarning(source, "missing #endif");
+ Parse_PopIndent(source, &type, &skip);
+ }
+ }
+ //if this was the initial script
+ if (!source->scriptstack->next) return false;
+ //remove the script and return to the last one
+ script = source->scriptstack;
+ source->scriptstack = source->scriptstack->next;
+ Parse_FreeScript(script);
+ }
+ //copy the already available token
+ ::memcpy(token, source->tokens, sizeof(token_t));
+ //free the read token
+ t = source->tokens;
+ source->tokens = source->tokens->next;
+ Parse_FreeToken(t);
+ return true;
+}
+
+/*
+===============
+Parse_UnreadSourceToken
+===============
+*/
+static bool Parse_UnreadSourceToken(source_t *source, token_t *token)
+{
+ token_t *t;
+
+ t = Parse_CopyToken(token);
+ t->next = source->tokens;
+ source->tokens = t;
+ return true;
+}
+
+/*
+===============
+Parse_ReadDefineParms
+===============
+*/
+static bool Parse_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms)
+{
+ token_t token, *t, *last;
+ int i, done, lastcomma, numparms, indent;
+
+ if (!Parse_ReadSourceToken(source, &token))
+ {
+ Parse_SourceError(source, "define %s missing parms", define->name);
+ return false;
+ }
+ //
+ if (define->numparms > maxparms)
+ {
+ Parse_SourceError(source, "define with more than %d parameters", maxparms);
+ return false;
+ }
+ //
+ for (i = 0; i < define->numparms; i++) parms[i] = NULL;
+ //if no leading "("
+ if (strcmp(token.string, "("))
+ {
+ Parse_UnreadSourceToken(source, &token);
+ Parse_SourceError(source, "define %s missing parms", define->name);
+ return false;
+ }
+ //read the define parameters
+ for (done = 0, numparms = 0, indent = 0; !done;)
+ {
+ if (numparms >= maxparms)
+ {
+ Parse_SourceError(source, "define %s with too many parms", define->name);
+ return false;
+ }
+ if (numparms >= define->numparms)
+ {
+ Parse_SourceWarning(source, "define %s has too many parms", define->name);
+ return false;
+ }
+ parms[numparms] = NULL;
+ lastcomma = 1;
+ last = NULL;
+ while(!done)
+ {
+ //
+ if (!Parse_ReadSourceToken(source, &token))
+ {
+ Parse_SourceError(source, "define %s incomplete", define->name);
+ return false;
+ }
+ //
+ if (!strcmp(token.string, ","))
+ {
+ if (indent <= 0)
+ {
+ if (lastcomma) Parse_SourceWarning(source, "too many comma's");
+ lastcomma = 1;
+ break;
+ }
+ }
+ lastcomma = 0;
+ //
+ if (!strcmp(token.string, "("))
+ {
+ indent++;
+ continue;
+ }
+ else if (!strcmp(token.string, ")"))
+ {
+ if (--indent <= 0)
+ {
+ if (!parms[define->numparms-1])
+ {
+ Parse_SourceWarning(source, "too few define parms");
+ }
+ done = 1;
+ break;
+ }
+ }
+ //
+ if (numparms < define->numparms)
+ {
+ //
+ t = Parse_CopyToken(&token);
+ t->next = NULL;
+ if (last) last->next = t;
+ else parms[numparms] = t;
+ last = t;
+ }
+ }
+ numparms++;
+ }
+ return true;
+}
+
+/*
+===============
+Parse_StringizeTokens
+===============
+*/
+static bool Parse_StringizeTokens(token_t *tokens, token_t *token)
+{
+ token_t *t;
+
+ token->type = TT_STRING;
+ token->whitespace_p = NULL;
+ token->endwhitespace_p = NULL;
+ token->string[0] = '\0';
+ strcat(token->string, "\"");
+ for (t = tokens; t; t = t->next)
+ {
+ strncat(token->string, t->string, MAX_TOKEN_CHARS - strlen(token->string));
+ }
+ strncat(token->string, "\"", MAX_TOKEN_CHARS - strlen(token->string));
+ return true;
+}
+
+/*
+===============
+Parse_MergeTokens
+===============
+*/
+static bool Parse_MergeTokens(token_t *t1, token_t *t2)
+{
+ //merging of a name with a name or number
+ if (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER))
+ {
+ strcat(t1->string, t2->string);
+ return true;
+ }
+ //merging of two strings
+ if (t1->type == TT_STRING && t2->type == TT_STRING)
+ {
+ //remove trailing double quote
+ t1->string[strlen(t1->string)-1] = '\0';
+ //concat without leading double quote
+ strcat(t1->string, &t2->string[1]);
+ return true;
+ }
+ //FIXME: merging of two number of the same sub type
+ return false;
+}
+
+/*
+===============
+Parse_NameHash
+===============
+*/
+//char primes[16] = {1, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47};
+static int Parse_NameHash(char *name)
+{
+ int hash, i;
+
+ hash = 0;
+ for (i = 0; name[i] != '\0'; i++)
+ {
+ hash += name[i] * (119 + i);
+ //hash += (name[i] << 7) + i;
+ //hash += (name[i] << (i&15));
+ }
+ hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1);
+ return hash;
+}
+
+/*
+===============
+Parse_AddDefineToHash
+===============
+*/
+static void Parse_AddDefineToHash(define_t *define, define_t **definehash)
+{
+ int hash;
+
+ hash = Parse_NameHash(define->name);
+ define->hashnext = definehash[hash];
+ definehash[hash] = define;
+}
+
+/*
+===============
+Parse_FindHashedDefine
+===============
+*/
+static define_t *Parse_FindHashedDefine(define_t **definehash, char *name)
+{
+ define_t *d;
+ int hash;
+
+ hash = Parse_NameHash(name);
+ for (d = definehash[hash]; d; d = d->hashnext)
+ {
+ if (!strcmp(d->name, name)) return d;
+ }
+ return NULL;
+}
+
+/*
+===============
+Parse_FindDefineParm
+===============
+*/
+static int Parse_FindDefineParm(define_t *define, char *name)
+{
+ token_t *p;
+ int i;
+
+ i = 0;
+ for (p = define->parms; p; p = p->next)
+ {
+ if (!strcmp(p->string, name)) return i;
+ i++;
+ }
+ return -1;
+}
+
+/*
+===============
+Parse_FreeDefine
+===============
+*/
+static void Parse_FreeDefine(define_t *define)
+{
+ token_t *t, *next;
+
+ //free the define parameters
+ for (t = define->parms; t; t = next)
+ {
+ next = t->next;
+ Parse_FreeToken(t);
+ }
+ //free the define tokens
+ for (t = define->tokens; t; t = next)
+ {
+ next = t->next;
+ Parse_FreeToken(t);
+ }
+ //free the define
+ Z_Free(define);
+}
+
+/*
+===============
+Parse_ExpandBuiltinDefine
+===============
+*/
+static bool Parse_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define,
+ token_t **firsttoken, token_t **lasttoken)
+{
+ token_t *token;
+ time_t t;
+
+ char *curtime;
+
+ token = Parse_CopyToken(deftoken);
+ switch(define->builtin)
+ {
+ case BUILTIN_LINE:
+ {
+ sprintf(token->string, "%d", deftoken->line);
+ token->intvalue = deftoken->line;
+ token->floatvalue = deftoken->line;
+ token->type = TT_NUMBER;
+ token->subtype = TT_DECIMAL | TT_INTEGER;
+ *firsttoken = token;
+ *lasttoken = token;
+ break;
+ }
+ case BUILTIN_FILE:
+ {
+ strcpy(token->string, source->scriptstack->filename);
+ token->type = TT_NAME;
+ token->subtype = strlen(token->string);
+ *firsttoken = token;
+ *lasttoken = token;
+ break;
+ }
+ case BUILTIN_DATE:
+ {
+ t = time(NULL);
+ curtime = ctime(&t);
+ strcpy(token->string, "\"");
+ strncat(token->string, curtime+4, 7);
+ strncat(token->string+7, curtime+20, 4);
+ strcat(token->string, "\"");
+ free(curtime);
+ token->type = TT_NAME;
+ token->subtype = strlen(token->string);
+ *firsttoken = token;
+ *lasttoken = token;
+ break;
+ }
+ case BUILTIN_TIME:
+ {
+ t = time(NULL);
+ curtime = ctime(&t);
+ strcpy(token->string, "\"");
+ strncat(token->string, curtime+11, 8);
+ strcat(token->string, "\"");
+ free(curtime);
+ token->type = TT_NAME;
+ token->subtype = strlen(token->string);
+ *firsttoken = token;
+ *lasttoken = token;
+ break;
+ }
+ case BUILTIN_STDC:
+ default:
+ {
+ *firsttoken = NULL;
+ *lasttoken = NULL;
+ break;
+ }
+ }
+ return true;
+}
+
+/*
+===============
+Parse_ExpandDefine
+===============
+*/
+static bool Parse_ExpandDefine(source_t *source, token_t *deftoken, define_t *define,
+ token_t **firsttoken, token_t **lasttoken)
+{
+ token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t;
+ token_t *t1, *t2, *first, *last, *nextpt, token;
+ int parmnum, i;
+
+ //if it is a builtin define
+ if (define->builtin)
+ {
+ return Parse_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken);
+ }
+ //if the define has parameters
+ if (define->numparms)
+ {
+ if (!Parse_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return false;
+ }
+ //empty list at first
+ first = NULL;
+ last = NULL;
+ //create a list with tokens of the expanded define
+ for (dt = define->tokens; dt; dt = dt->next)
+ {
+ parmnum = -1;
+ //if the token is a name, it could be a define parameter
+ if (dt->type == TT_NAME)
+ {
+ parmnum = Parse_FindDefineParm(define, dt->string);
+ }
+ //if it is a define parameter
+ if (parmnum >= 0)
+ {
+ for (pt = parms[parmnum]; pt; pt = pt->next)
+ {
+ t = Parse_CopyToken(pt);
+ //add the token to the list
+ t->next = NULL;
+ if (last) last->next = t;
+ else first = t;
+ last = t;
+ }
+ }
+ else
+ {
+ //if stringizing operator
+ if (dt->string[0] == '#' && dt->string[1] == '\0')
+ {
+ //the stringizing operator must be followed by a define parameter
+ if (dt->next) parmnum = Parse_FindDefineParm(define, dt->next->string);
+ else parmnum = -1;
+ //
+ if (parmnum >= 0)
+ {
+ //step over the stringizing operator
+ dt = dt->next;
+ //stringize the define parameter tokens
+ if (!Parse_StringizeTokens(parms[parmnum], &token))
+ {
+ Parse_SourceError(source, "can't stringize tokens");
+ return false;
+ }
+ t = Parse_CopyToken(&token);
+ }
+ else
+ {
+ Parse_SourceWarning(source, "stringizing operator without define parameter");
+ continue;
+ }
+ }
+ else
+ {
+ t = Parse_CopyToken(dt);
+ }
+ //add the token to the list
+ t->next = NULL;
+ if (last) last->next = t;
+ else first = t;
+ last = t;
+ }
+ }
+ //check for the merging operator
+ for (t = first; t; )
+ {
+ if (t->next)
+ {
+ //if the merging operator
+ if (t->next->string[0] == '#' && t->next->string[1] == '#')
+ {
+ t1 = t;
+ t2 = t->next->next;
+ if (t2)
+ {
+ if (!Parse_MergeTokens(t1, t2))
+ {
+ Parse_SourceError(source, "can't merge %s with %s", t1->string, t2->string);
+ return false;
+ }
+ Parse_FreeToken(t1->next);
+ t1->next = t2->next;
+ if (t2 == last) last = t1;
+ Parse_FreeToken(t2);
+ continue;
+ }
+ }
+ }
+ t = t->next;
+ }
+ //store the first and last token of the list
+ *firsttoken = first;
+ *lasttoken = last;
+ //free all the parameter tokens
+ for (i = 0; i < define->numparms; i++)
+ {
+ for (pt = parms[i]; pt; pt = nextpt)
+ {
+ nextpt = pt->next;
+ Parse_FreeToken(pt);
+ }
+ }
+ //
+ return true;
+}
+
+/*
+===============
+Parse_ExpandDefineIntoSource
+===============
+*/
+static bool Parse_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define)
+{
+ token_t *firsttoken, *lasttoken;
+
+ if (!Parse_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return false;
+
+ if (firsttoken && lasttoken)
+ {
+ lasttoken->next = source->tokens;
+ source->tokens = firsttoken;
+ return true;
+ }
+ return false;
+}
+
+/*
+===============
+Parse_ConvertPath
+===============
+*/
+static void Parse_ConvertPath(char *path)
+{
+ char *ptr;
+
+ //remove double path seperators
+ for (ptr = path; *ptr;)
+ {
+ if ((*ptr == '\\' || *ptr == '/') &&
+ (*(ptr+1) == '\\' || *(ptr+1) == '/'))
+ {
+ memmove(ptr, ptr+1, strlen(ptr));
+ }
+ else
+ {
+ ptr++;
+ }
+ }
+ //set OS dependent path seperators
+ for (ptr = path; *ptr;)
+ {
+ if (*ptr == '/' || *ptr == '\\') *ptr = PATH_SEP;
+ ptr++;
+ }
+}
+
+/*
+===============
+Parse_ReadLine
+
+reads a token from the current line, continues reading on the next
+line only if a backslash '\' is encountered.
+===============
+*/
+static bool Parse_ReadLine(source_t *source, token_t *token)
+{
+ int crossline;
+
+ crossline = 0;
+ do
+ {
+ if (!Parse_ReadSourceToken(source, token)) return false;
+
+ if (token->linescrossed > crossline)
+ {
+ Parse_UnreadSourceToken(source, token);
+ return false;
+ }
+ crossline = 1;
+ } while(!strcmp(token->string, "\\"));
+ return true;
+}
+
+/*
+===============
+Parse_OperatorPriority
+===============
+*/
+typedef struct operator_s
+{
+ int _operator;
+ int priority;
+ int parentheses;
+ struct operator_s *prev, *next;
+} operator_t;
+
+typedef struct value_s
+{
+ signed long int intvalue;
+ double floatvalue;
+ int parentheses;
+ struct value_s *prev, *next;
+} value_t;
+
+static bool Parse_OperatorPriority(int op)
+{
+ switch(op)
+ {
+ case P_MUL: return 15;
+ case P_DIV: return 15;
+ case P_MOD: return 15;
+ case P_ADD: return 14;
+ case P_SUB: return 14;
+
+ case P_LOGIC_AND: return 7;
+ case P_LOGIC_OR: return 6;
+ case P_LOGIC_GEQ: return 12;
+ case P_LOGIC_LEQ: return 12;
+ case P_LOGIC_EQ: return 11;
+ case P_LOGIC_UNEQ: return 11;
+
+ case P_LOGIC_NOT: return 16;
+ case P_LOGIC_GREATER: return 12;
+ case P_LOGIC_LESS: return 12;
+
+ case P_RSHIFT: return 13;
+ case P_LSHIFT: return 13;
+
+ case P_BIN_AND: return 10;
+ case P_BIN_OR: return 8;
+ case P_BIN_XOR: return 9;
+ case P_BIN_NOT: return 16;
+
+ case P_COLON: return 5;
+ case P_QUESTIONMARK: return 5;
+ }
+ return false;
+}
+
+#define MAX_VALUES 64
+#define MAX_OPERATORS 64
+#define AllocValue(val) \
+ if (numvalues >= MAX_VALUES) { \
+ Parse_SourceError(source, "out of value space\n"); \
+ error = 1; \
+ break; \
+ } \
+ else \
+ val = &value_heap[numvalues++];
+#define FreeValue(val)
+//
+#define AllocOperator(op) \
+ if (numoperators >= MAX_OPERATORS) { \
+ Parse_SourceError(source, "out of operator space\n"); \
+ error = 1; \
+ break; \
+ } \
+ else \
+ op = &operator_heap[numoperators++];
+#define FreeOperator(op)
+
+/*
+===============
+Parse_EvaluateTokens
+===============
+*/
+static bool Parse_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue,
+ double *floatvalue, int integer)
+{
+ operator_t *o, *firstoperator, *lastoperator;
+ value_t *v, *firstvalue, *lastvalue, *v1, *v2;
+ token_t *t;
+ int brace = 0;
+ int parentheses = 0;
+ int error = 0;
+ int lastwasvalue = 0;
+ int negativevalue = 0;
+ int questmarkintvalue = 0;
+ double questmarkfloatvalue = 0;
+ int gotquestmarkvalue = false;
+ //
+ operator_t operator_heap[MAX_OPERATORS];
+ int numoperators = 0;
+ value_t value_heap[MAX_VALUES];
+ int numvalues = 0;
+
+ firstoperator = lastoperator = NULL;
+ firstvalue = lastvalue = NULL;
+ if (intvalue) *intvalue = 0;
+ if (floatvalue) *floatvalue = 0;
+ for (t = tokens; t; t = t->next)
+ {
+ switch(t->type)
+ {
+ case TT_NAME:
+ {
+ if (lastwasvalue || negativevalue)
+ {
+ Parse_SourceError(source, "syntax error in #if/#elif");
+ error = 1;
+ break;
+ }
+ if (strcmp(t->string, "defined"))
+ {
+ Parse_SourceError(source, "undefined name %s in #if/#elif", t->string);
+ error = 1;
+ break;
+ }
+ t = t->next;
+ if (!strcmp(t->string, "("))
+ {
+ brace = true;
+ t = t->next;
+ }
+ if (!t || t->type != TT_NAME)
+ {
+ Parse_SourceError(source, "defined without name in #if/#elif");
+ error = 1;
+ break;
+ }
+ //v = (value_t *) Z_Malloc(sizeof(value_t));
+ AllocValue(v);
+ if (Parse_FindHashedDefine(source->definehash, t->string))
+ {
+ v->intvalue = 1;
+ v->floatvalue = 1;
+ }
+ else
+ {
+ v->intvalue = 0;
+ v->floatvalue = 0;
+ }
+ v->parentheses = parentheses;
+ v->next = NULL;
+ v->prev = lastvalue;
+ if (lastvalue) lastvalue->next = v;
+ else firstvalue = v;
+ lastvalue = v;
+ if (brace)
+ {
+ t = t->next;
+ if (!t || strcmp(t->string, ")"))
+ {
+ Parse_SourceError(source, "defined without ) in #if/#elif");
+ error = 1;
+ break;
+ }
+ }
+ brace = false;
+ // defined() creates a value
+ lastwasvalue = 1;
+ break;
+ }
+ case TT_NUMBER:
+ {
+ if (lastwasvalue)
+ {
+ Parse_SourceError(source, "syntax error in #if/#elif");
+ error = 1;
+ break;
+ }
+ //v = (value_t *) Z_Malloc(sizeof(value_t));
+ AllocValue(v);
+ if (negativevalue)
+ {
+ v->intvalue = - (signed int) t->intvalue;
+ v->floatvalue = - t->floatvalue;
+ }
+ else
+ {
+ v->intvalue = t->intvalue;
+ v->floatvalue = t->floatvalue;
+ }
+ v->parentheses = parentheses;
+ v->next = NULL;
+ v->prev = lastvalue;
+ if (lastvalue) lastvalue->next = v;
+ else firstvalue = v;
+ lastvalue = v;
+ //last token was a value
+ lastwasvalue = 1;
+ //
+ negativevalue = 0;
+ break;
+ }
+ case TT_PUNCTUATION:
+ {
+ if (negativevalue)
+ {
+ Parse_SourceError(source, "misplaced minus sign in #if/#elif");
+ error = 1;
+ break;
+ }
+ if (t->subtype == P_PARENTHESESOPEN)
+ {
+ parentheses++;
+ break;
+ }
+ else if (t->subtype == P_PARENTHESESCLOSE)
+ {
+ parentheses--;
+ if (parentheses < 0)
+ {
+ Parse_SourceError(source, "too many ) in #if/#elsif");
+ error = 1;
+ }
+ break;
+ }
+ //check for invalid operators on floating point values
+ if (!integer)
+ {
+ if (t->subtype == P_BIN_NOT || t->subtype == P_MOD ||
+ t->subtype == P_RSHIFT || t->subtype == P_LSHIFT ||
+ t->subtype == P_BIN_AND || t->subtype == P_BIN_OR ||
+ t->subtype == P_BIN_XOR)
+ {
+ Parse_SourceError(source, "illigal operator %s on floating point operands\n", t->string);
+ error = 1;
+ break;
+ }
+ }
+ switch(t->subtype)
+ {
+ case P_LOGIC_NOT:
+ case P_BIN_NOT:
+ {
+ if (lastwasvalue)
+ {
+ Parse_SourceError(source, "! or ~ after value in #if/#elif");
+ error = 1;
+ break;
+ }
+ break;
+ }
+ case P_INC:
+ case P_DEC:
+ {
+ Parse_SourceError(source, "++ or -- used in #if/#elif");
+ break;
+ }
+ case P_SUB:
+ {
+ if (!lastwasvalue)
+ {
+ negativevalue = 1;
+ break;
+ }
+ }
+
+ case P_MUL:
+ case P_DIV:
+ case P_MOD:
+ case P_ADD:
+
+ case P_LOGIC_AND:
+ case P_LOGIC_OR:
+ case P_LOGIC_GEQ:
+ case P_LOGIC_LEQ:
+ case P_LOGIC_EQ:
+ case P_LOGIC_UNEQ:
+
+ case P_LOGIC_GREATER:
+ case P_LOGIC_LESS:
+
+ case P_RSHIFT:
+ case P_LSHIFT:
+
+ case P_BIN_AND:
+ case P_BIN_OR:
+ case P_BIN_XOR:
+
+ case P_COLON:
+ case P_QUESTIONMARK:
+ {
+ if (!lastwasvalue)
+ {
+ Parse_SourceError(source, "operator %s after operator in #if/#elif", t->string);
+ error = 1;
+ break;
+ }
+ break;
+ }
+ default:
+ {
+ Parse_SourceError(source, "invalid operator %s in #if/#elif", t->string);
+ error = 1;
+ break;
+ }
+ }
+ if (!error && !negativevalue)
+ {
+ //o = (operator_t *) Z_Malloc(sizeof(operator_t));
+ AllocOperator(o);
+ o->_operator = t->subtype;
+ o->priority = Parse_OperatorPriority(t->subtype);
+ o->parentheses = parentheses;
+ o->next = NULL;
+ o->prev = lastoperator;
+ if (lastoperator) lastoperator->next = o;
+ else firstoperator = o;
+ lastoperator = o;
+ lastwasvalue = 0;
+ }
+ break;
+ }
+ default:
+ {
+ Parse_SourceError(source, "unknown %s in #if/#elif", t->string);
+ error = 1;
+ break;
+ }
+ }
+ if (error) break;
+ }
+ if (!error)
+ {
+ if (!lastwasvalue)
+ {
+ Parse_SourceError(source, "trailing operator in #if/#elif");
+ error = 1;
+ }
+ else if (parentheses)
+ {
+ Parse_SourceError(source, "too many ( in #if/#elif");
+ error = 1;
+ }
+ }
+ //
+ gotquestmarkvalue = false;
+ questmarkintvalue = 0;
+ questmarkfloatvalue = 0;
+ //while there are operators
+ while(!error && firstoperator)
+ {
+ v = firstvalue;
+ for (o = firstoperator; o->next; o = o->next)
+ {
+ //if the current operator is nested deeper in parentheses
+ //than the next operator
+ if (o->parentheses > o->next->parentheses) break;
+ //if the current and next operator are nested equally deep in parentheses
+ if (o->parentheses == o->next->parentheses)
+ {
+ //if the priority of the current operator is equal or higher
+ //than the priority of the next operator
+ if (o->priority >= o->next->priority) break;
+ }
+ //if the arity of the operator isn't equal to 1
+ if (o->_operator != P_LOGIC_NOT
+ && o->_operator != P_BIN_NOT) v = v->next;
+ //if there's no value or no next value
+ if (!v)
+ {
+ Parse_SourceError(source, "mising values in #if/#elif");
+ error = 1;
+ break;
+ }
+ }
+ if (error) break;
+ v1 = v;
+ v2 = v->next;
+ switch(o->_operator)
+ {
+ case P_LOGIC_NOT: v1->intvalue = !v1->intvalue;
+ v1->floatvalue = !v1->floatvalue; break;
+ case P_BIN_NOT: v1->intvalue = ~v1->intvalue;
+ break;
+ case P_MUL: v1->intvalue *= v2->intvalue;
+ v1->floatvalue *= v2->floatvalue; break;
+ case P_DIV: if (!v2->intvalue || !v2->floatvalue)
+ {
+ Parse_SourceError(source, "divide by zero in #if/#elif\n");
+ error = 1;
+ break;
+ }
+ v1->intvalue /= v2->intvalue;
+ v1->floatvalue /= v2->floatvalue; break;
+ case P_MOD: if (!v2->intvalue)
+ {
+ Parse_SourceError(source, "divide by zero in #if/#elif\n");
+ error = 1;
+ break;
+ }
+ v1->intvalue %= v2->intvalue; break;
+ case P_ADD: v1->intvalue += v2->intvalue;
+ v1->floatvalue += v2->floatvalue; break;
+ case P_SUB: v1->intvalue -= v2->intvalue;
+ v1->floatvalue -= v2->floatvalue; break;
+ case P_LOGIC_AND: v1->intvalue = v1->intvalue && v2->intvalue;
+ v1->floatvalue = v1->floatvalue && v2->floatvalue; break;
+ case P_LOGIC_OR: v1->intvalue = v1->intvalue || v2->intvalue;
+ v1->floatvalue = v1->floatvalue || v2->floatvalue; break;
+ case P_LOGIC_GEQ: v1->intvalue = v1->intvalue >= v2->intvalue;
+ v1->floatvalue = v1->floatvalue >= v2->floatvalue; break;
+ case P_LOGIC_LEQ: v1->intvalue = v1->intvalue <= v2->intvalue;
+ v1->floatvalue = v1->floatvalue <= v2->floatvalue; break;
+ case P_LOGIC_EQ: v1->intvalue = v1->intvalue == v2->intvalue;
+ v1->floatvalue = v1->floatvalue == v2->floatvalue; break;
+ case P_LOGIC_UNEQ: v1->intvalue = v1->intvalue != v2->intvalue;
+ v1->floatvalue = v1->floatvalue != v2->floatvalue; break;
+ case P_LOGIC_GREATER: v1->intvalue = v1->intvalue > v2->intvalue;
+ v1->floatvalue = v1->floatvalue > v2->floatvalue; break;
+ case P_LOGIC_LESS: v1->intvalue = v1->intvalue < v2->intvalue;
+ v1->floatvalue = v1->floatvalue < v2->floatvalue; break;
+ case P_RSHIFT: v1->intvalue >>= v2->intvalue;
+ break;
+ case P_LSHIFT: v1->intvalue <<= v2->intvalue;
+ break;
+ case P_BIN_AND: v1->intvalue &= v2->intvalue;
+ break;
+ case P_BIN_OR: v1->intvalue |= v2->intvalue;
+ break;
+ case P_BIN_XOR: v1->intvalue ^= v2->intvalue;
+ break;
+ case P_COLON:
+ {
+ if (!gotquestmarkvalue)
+ {
+ Parse_SourceError(source, ": without ? in #if/#elif");
+ error = 1;
+ break;
+ }
+ if (integer)
+ {
+ if (!questmarkintvalue) v1->intvalue = v2->intvalue;
+ }
+ else
+ {
+ if (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue;
+ }
+ gotquestmarkvalue = false;
+ break;
+ }
+ case P_QUESTIONMARK:
+ {
+ if (gotquestmarkvalue)
+ {
+ Parse_SourceError(source, "? after ? in #if/#elif");
+ error = 1;
+ break;
+ }
+ questmarkintvalue = v1->intvalue;
+ questmarkfloatvalue = v1->floatvalue;
+ gotquestmarkvalue = true;
+ break;
+ }
+ }
+ if (error) break;
+ //if not an operator with arity 1
+ if (o->_operator != P_LOGIC_NOT
+ && o->_operator != P_BIN_NOT)
+ {
+ //remove the second value if not question mark operator
+ if (o->_operator != P_QUESTIONMARK) v = v->next;
+ //
+ if (v->prev) v->prev->next = v->next;
+ else firstvalue = v->next;
+ if (v->next) v->next->prev = v->prev;
+ else lastvalue = v->prev;
+ //Z_Free(v);
+ FreeValue(v);
+ }
+ //remove the operator
+ if (o->prev) o->prev->next = o->next;
+ else firstoperator = o->next;
+ if (o->next) o->next->prev = o->prev;
+ else lastoperator = o->prev;
+ //Z_Free(o);
+ FreeOperator(o);
+ }
+ if (firstvalue)
+ {
+ if (intvalue) *intvalue = firstvalue->intvalue;
+ if (floatvalue) *floatvalue = firstvalue->floatvalue;
+ }
+ for (o = firstoperator; o; o = lastoperator)
+ {
+ lastoperator = o->next;
+ //Z_Free(o);
+ FreeOperator(o);
+ }
+ for (v = firstvalue; v; v = lastvalue)
+ {
+ lastvalue = v->next;
+ //Z_Free(v);
+ FreeValue(v);
+ }
+ if (!error) return true;
+ if (intvalue) *intvalue = 0;
+ if (floatvalue) *floatvalue = 0;
+ return false;
+}
+
+/*
+===============
+Parse_Evaluate
+===============
+*/
+static bool Parse_Evaluate(source_t *source, signed long int *intvalue,
+ double *floatvalue, int integer)
+{
+ token_t token, *firsttoken, *lasttoken;
+ token_t *t, *nexttoken;
+ define_t *define;
+ int defined = false;
+
+ if (intvalue) *intvalue = 0;
+ if (floatvalue) *floatvalue = 0;
+ //
+ if (!Parse_ReadLine(source, &token))
+ {
+ Parse_SourceError(source, "no value after #if/#elif");
+ return false;
+ }
+ firsttoken = NULL;
+ lasttoken = NULL;
+ do
+ {
+ //if the token is a name
+ if (token.type == TT_NAME)
+ {
+ if (defined)
+ {
+ defined = false;
+ t = Parse_CopyToken(&token);
+ t->next = NULL;
+ if (lasttoken) lasttoken->next = t;
+ else firsttoken = t;
+ lasttoken = t;
+ }
+ else if (!strcmp(token.string, "defined"))
+ {
+ defined = true;
+ t = Parse_CopyToken(&token);
+ t->next = NULL;
+ if (lasttoken) lasttoken->next = t;
+ else firsttoken = t;
+ lasttoken = t;
+ }
+ else
+ {
+ //then it must be a define
+ define = Parse_FindHashedDefine(source->definehash, token.string);
+ if (!define)
+ {
+ Parse_SourceError(source, "can't evaluate %s, not defined", token.string);
+ return false;
+ }
+ if (!Parse_ExpandDefineIntoSource(source, &token, define)) return false;
+ }
+ }
+ //if the token is a number or a punctuation
+ else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)
+ {
+ t = Parse_CopyToken(&token);
+ t->next = NULL;
+ if (lasttoken) lasttoken->next = t;
+ else firsttoken = t;
+ lasttoken = t;
+ }
+ else //can't evaluate the token
+ {
+ Parse_SourceError(source, "can't evaluate %s", token.string);
+ return false;
+ }
+ } while(Parse_ReadLine(source, &token));
+ //
+ if (!Parse_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return false;
+ //
+ for (t = firsttoken; t; t = nexttoken)
+ {
+ nexttoken = t->next;
+ Parse_FreeToken(t);
+ }
+ //
+ return true;
+}
+
+/*
+===============
+Parse_DollarEvaluate
+===============
+*/
+static bool Parse_DollarEvaluate(source_t *source, signed long int *intvalue,
+ double *floatvalue, int integer)
+{
+ int indent, defined = false;
+ token_t token, *firsttoken, *lasttoken;
+ token_t *t, *nexttoken;
+ define_t *define;
+
+ if (intvalue) *intvalue = 0;
+ if (floatvalue) *floatvalue = 0;
+ //
+ if (!Parse_ReadSourceToken(source, &token))
+ {
+ Parse_SourceError(source, "no leading ( after $evalint/$evalfloat");
+ return false;
+ }
+ if (!Parse_ReadSourceToken(source, &token))
+ {
+ Parse_SourceError(source, "nothing to evaluate");
+ return false;
+ }
+ indent = 1;
+ firsttoken = NULL;
+ lasttoken = NULL;
+ do
+ {
+ //if the token is a name
+ if (token.type == TT_NAME)
+ {
+ if (defined)
+ {
+ defined = false;
+ t = Parse_CopyToken(&token);
+ t->next = NULL;
+ if (lasttoken) lasttoken->next = t;
+ else firsttoken = t;
+ lasttoken = t;
+ }
+ else if (!strcmp(token.string, "defined"))
+ {
+ defined = true;
+ t = Parse_CopyToken(&token);
+ t->next = NULL;
+ if (lasttoken) lasttoken->next = t;
+ else firsttoken = t;
+ lasttoken = t;
+ }
+ else
+ {
+ //then it must be a define
+ define = Parse_FindHashedDefine(source->definehash, token.string);
+ if (!define)
+ {
+ Parse_SourceError(source, "can't evaluate %s, not defined", token.string);
+ return false;
+ }
+ if (!Parse_ExpandDefineIntoSource(source, &token, define)) return false;
+ }
+ }
+ //if the token is a number or a punctuation
+ else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)
+ {
+ if (*token.string == '(') indent++;
+ else if (*token.string == ')') indent--;
+ if (indent <= 0) break;
+ t = Parse_CopyToken(&token);
+ t->next = NULL;
+ if (lasttoken) lasttoken->next = t;
+ else firsttoken = t;
+ lasttoken = t;
+ }
+ else //can't evaluate the token
+ {
+ Parse_SourceError(source, "can't evaluate %s", token.string);
+ return false;
+ }
+ } while(Parse_ReadSourceToken(source, &token));
+ //
+ if (!Parse_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return false;
+ //
+ for (t = firsttoken; t; t = nexttoken)
+ {
+ nexttoken = t->next;
+ Parse_FreeToken(t);
+ }
+ //
+ return true;
+}
+
+/*
+===============
+Parse_Directive_include
+===============
+*/
+static bool Parse_Directive_include(source_t *source)
+{
+ script_t *script;
+ token_t token;
+ char path[MAX_QPATH];
+
+ if (source->skip > 0) return true;
+ //
+ if (!Parse_ReadSourceToken(source, &token))
+ {
+ Parse_SourceError(source, "#include without file name");
+ return false;
+ }
+ if (token.linescrossed > 0)
+ {
+ Parse_SourceError(source, "#include without file name");
+ return false;
+ }
+ if (token.type == TT_STRING)
+ {
+ Parse_StripDoubleQuotes(token.string);
+ Parse_ConvertPath(token.string);
+ script = Parse_LoadScriptFile(token.string);
+ if (!script)
+ {
+ strcpy(path, source->includepath);
+ strcat(path, token.string);
+ script = Parse_LoadScriptFile(path);
+ }
+ }
+ else if (token.type == TT_PUNCTUATION && *token.string == '<')
+ {
+ strcpy(path, source->includepath);
+ while(Parse_ReadSourceToken(source, &token))
+ {
+ if (token.linescrossed > 0)
+ {
+ Parse_UnreadSourceToken(source, &token);
+ break;
+ }
+ if (token.type == TT_PUNCTUATION && *token.string == '>') break;
+ strncat(path, token.string, MAX_QPATH - 1);
+ }
+ if (*token.string != '>')
+ {
+ Parse_SourceWarning(source, "#include missing trailing >");
+ }
+ if (!strlen(path))
+ {
+ Parse_SourceError(source, "#include without file name between < >");
+ return false;
+ }
+ Parse_ConvertPath(path);
+ script = Parse_LoadScriptFile(path);
+ }
+ else
+ {
+ Parse_SourceError(source, "#include without file name");
+ return false;
+ }
+ if (!script)
+ {
+ Parse_SourceError(source, "file %s not found", path);
+ return false;
+ }
+ Parse_PushScript(source, script);
+ return true;
+}
+
+/*
+===============
+Parse_WhiteSpaceBeforeToken
+===============
+*/
+static bool Parse_WhiteSpaceBeforeToken(token_t *token)
+{
+ return token->endwhitespace_p - token->whitespace_p > 0;
+}
+
+/*
+===============
+Parse_ClearTokenWhiteSpace
+===============
+*/
+static void Parse_ClearTokenWhiteSpace(token_t *token)
+{
+ token->whitespace_p = NULL;
+ token->endwhitespace_p = NULL;
+ token->linescrossed = 0;
+}
+
+/*
+===============
+Parse_Directive_undef
+===============
+*/
+static bool Parse_Directive_undef(source_t *source)
+{
+ token_t token;
+ define_t *define, *lastdefine;
+ int hash;
+
+ if (source->skip > 0) return true;
+ //
+ if (!Parse_ReadLine(source, &token))
+ {
+ Parse_SourceError(source, "undef without name");
+ return false;
+ }
+ if (token.type != TT_NAME)
+ {
+ Parse_UnreadSourceToken(source, &token);
+ Parse_SourceError(source, "expected name, found %s", token.string);
+ return false;
+ }
+
+ hash = Parse_NameHash(token.string);
+ for (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext)
+ {
+ if (!strcmp(define->name, token.string))
+ {
+ if (define->flags & DEFINE_FIXED)
+ {
+ Parse_SourceWarning(source, "can't undef %s", token.string);
+ }
+ else
+ {
+ if (lastdefine) lastdefine->hashnext = define->hashnext;
+ else source->definehash[hash] = define->hashnext;
+ Parse_FreeDefine(define);
+ }
+ break;
+ }
+ lastdefine = define;
+ }
+ return true;
+}
+
+/*
+===============
+Parse_Directive_elif
+===============
+*/
+static bool Parse_Directive_elif(source_t *source)
+{
+ signed long int value;
+ int type, skip;
+
+ Parse_PopIndent(source, &type, &skip);
+ if (!type || type == INDENT_ELSE)
+ {
+ Parse_SourceError(source, "misplaced #elif");
+ return false;
+ }
+ if (!Parse_Evaluate(source, &value, NULL, true)) return false;
+ skip = (value == 0);
+ Parse_PushIndent(source, INDENT_ELIF, skip);
+ return true;
+}
+
+/*
+===============
+Parse_Directive_if
+===============
+*/
+static bool Parse_Directive_if(source_t *source)
+{
+ signed long int value;
+ int skip;
+
+ if (!Parse_Evaluate(source, &value, NULL, true)) return false;
+ skip = (value == 0);
+ Parse_PushIndent(source, INDENT_IF, skip);
+ return true;
+}
+
+/*
+===============
+Parse_Directive_line
+===============
+*/
+static bool Parse_Directive_line(source_t *source)
+{
+ Parse_SourceError(source, "#line directive not supported");
+ return false;
+}
+
+/*
+===============
+Parse_Directive_error
+===============
+*/
+static bool Parse_Directive_error(source_t *source)
+{
+ token_t token;
+
+ strcpy(token.string, "");
+ Parse_ReadSourceToken(source, &token);
+ Parse_SourceError(source, "#error directive: %s", token.string);
+ return false;
+}
+
+/*
+===============
+Parse_Directive_pragma
+===============
+*/
+static bool Parse_Directive_pragma(source_t *source)
+{
+ token_t token;
+
+ Parse_SourceWarning(source, "#pragma directive not supported");
+ while(Parse_ReadLine(source, &token)) ;
+ return true;
+}
+
+/*
+===============
+Parse_UnreadSignToken
+===============
+*/
+static void Parse_UnreadSignToken(source_t *source)
+{
+ token_t token;
+
+ token.line = source->scriptstack->line;
+ token.whitespace_p = source->scriptstack->script_p;
+ token.endwhitespace_p = source->scriptstack->script_p;
+ token.linescrossed = 0;
+ strcpy(token.string, "-");
+ token.type = TT_PUNCTUATION;
+ token.subtype = P_SUB;
+ Parse_UnreadSourceToken(source, &token);
+}
+
+/*
+===============
+Parse_Directive_eval
+===============
+*/
+static bool Parse_Directive_eval(source_t *source)
+{
+ signed long int value;
+ token_t token;
+
+ if (!Parse_Evaluate(source, &value, NULL, true)) return false;
+ //
+ token.line = source->scriptstack->line;
+ token.whitespace_p = source->scriptstack->script_p;
+ token.endwhitespace_p = source->scriptstack->script_p;
+ token.linescrossed = 0;
+ sprintf(token.string, "%ld", labs(value));
+ token.type = TT_NUMBER;
+ token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
+ Parse_UnreadSourceToken(source, &token);
+ if (value < 0) Parse_UnreadSignToken(source);
+ return true;
+}
+
+/*
+===============
+Parse_Directive_evalfloat
+===============
+*/
+static bool Parse_Directive_evalfloat(source_t *source)
+{
+ double value;
+ token_t token;
+
+ if (!Parse_Evaluate(source, NULL, &value, false)) return false;
+ token.line = source->scriptstack->line;
+ token.whitespace_p = source->scriptstack->script_p;
+ token.endwhitespace_p = source->scriptstack->script_p;
+ token.linescrossed = 0;
+ sprintf(token.string, "%1.2f", fabs(value));
+ token.type = TT_NUMBER;
+ token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
+ Parse_UnreadSourceToken(source, &token);
+ if (value < 0) Parse_UnreadSignToken(source);
+ return true;
+}
+
+/*
+===============
+Parse_DollarDirective_evalint
+===============
+*/
+static bool Parse_DollarDirective_evalint(source_t *source)
+{
+ signed long int value;
+ token_t token;
+
+ if (!Parse_DollarEvaluate(source, &value, NULL, true)) return false;
+ //
+ token.line = source->scriptstack->line;
+ token.whitespace_p = source->scriptstack->script_p;
+ token.endwhitespace_p = source->scriptstack->script_p;
+ token.linescrossed = 0;
+ sprintf(token.string, "%ld", labs(value));
+ token.type = TT_NUMBER;
+ token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
+ token.intvalue = value;
+ token.floatvalue = value;
+ Parse_UnreadSourceToken(source, &token);
+ if (value < 0) Parse_UnreadSignToken(source);
+ return true;
+}
+
+/*
+===============
+Parse_DollarDirective_evalfloat
+===============
+*/
+static bool Parse_DollarDirective_evalfloat(source_t *source)
+{
+ double value;
+ token_t token;
+
+ if (!Parse_DollarEvaluate(source, NULL, &value, false)) return false;
+ token.line = source->scriptstack->line;
+ token.whitespace_p = source->scriptstack->script_p;
+ token.endwhitespace_p = source->scriptstack->script_p;
+ token.linescrossed = 0;
+ sprintf(token.string, "%1.2f", fabs(value));
+ token.type = TT_NUMBER;
+ token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
+ token.intvalue = (unsigned long) value;
+ token.floatvalue = value;
+ Parse_UnreadSourceToken(source, &token);
+ if (value < 0) Parse_UnreadSignToken(source);
+ return true;
+}
+
+/*
+===============
+Parse_ReadDollarDirective
+===============
+*/
+directive_t dollardirectives[20] =
+{
+ {"evalint", Parse_DollarDirective_evalint},
+ {"evalfloat", Parse_DollarDirective_evalfloat},
+ {NULL, NULL}
+};
+
+static bool Parse_ReadDollarDirective(source_t *source)
+{
+ token_t token;
+ int i;
+
+ //read the directive name
+ if (!Parse_ReadSourceToken(source, &token))
+ {
+ Parse_SourceError(source, "found $ without name");
+ return false;
+ }
+ //directive name must be on the same line
+ if (token.linescrossed > 0)
+ {
+ Parse_UnreadSourceToken(source, &token);
+ Parse_SourceError(source, "found $ at end of line");
+ return false;
+ }
+ //if if is a name
+ if (token.type == TT_NAME)
+ {
+ //find the precompiler directive
+ for (i = 0; dollardirectives[i].name; i++)
+ {
+ if (!strcmp(dollardirectives[i].name, token.string))
+ {
+ return dollardirectives[i].func(source);
+ }
+ }
+ }
+ Parse_UnreadSourceToken(source, &token);
+ Parse_SourceError(source, "unknown precompiler directive %s", token.string);
+ return false;
+}
+
+/*
+===============
+Parse_Directive_if_def
+===============
+*/
+static bool Parse_Directive_if_def(source_t *source, int type)
+{
+ token_t token;
+ define_t *d;
+ int skip;
+
+ if (!Parse_ReadLine(source, &token))
+ {
+ Parse_SourceError(source, "#ifdef without name");
+ return false;
+ }
+ if (token.type != TT_NAME)
+ {
+ Parse_UnreadSourceToken(source, &token);
+ Parse_SourceError(source, "expected name after #ifdef, found %s", token.string);
+ return false;
+ }
+ d = Parse_FindHashedDefine(source->definehash, token.string);
+ skip = (type == INDENT_IFDEF) == (d == NULL);
+ Parse_PushIndent(source, type, skip);
+ return true;
+}
+
+/*
+===============
+Parse_Directive_ifdef
+===============
+*/
+static bool Parse_Directive_ifdef(source_t *source)
+{
+ return Parse_Directive_if_def(source, INDENT_IFDEF);
+}
+
+/*
+===============
+Parse_Directive_ifndef
+===============
+*/
+static bool Parse_Directive_ifndef(source_t *source)
+{
+ return Parse_Directive_if_def(source, INDENT_IFNDEF);
+}
+
+/*
+===============
+Parse_Directive_else
+===============
+*/
+static bool Parse_Directive_else(source_t *source)
+{
+ int type, skip;
+
+ Parse_PopIndent(source, &type, &skip);
+ if (!type)
+ {
+ Parse_SourceError(source, "misplaced #else");
+ return false;
+ }
+ if (type == INDENT_ELSE)
+ {
+ Parse_SourceError(source, "#else after #else");
+ return false;
+ }
+ Parse_PushIndent(source, INDENT_ELSE, !skip);
+ return true;
+}
+
+/*
+===============
+Parse_Directive_endif
+===============
+*/
+static bool Parse_Directive_endif(source_t *source)
+{
+ int type, skip;
+
+ Parse_PopIndent(source, &type, &skip);
+ if (!type)
+ {
+ Parse_SourceError(source, "misplaced #endif");
+ return false;
+ }
+ return true;
+}
+
+/*
+===============
+Parse_CheckTokenString
+===============
+*/
+static bool Parse_CheckTokenString(source_t *source, const char *string)
+{
+ token_t tok;
+
+ if (!Parse_ReadToken(source, &tok)) return false;
+ //if the token is available
+ if (!strcmp(tok.string, string)) return true;
+ //
+ Parse_UnreadSourceToken(source, &tok);
+ return false;
+}
+
+/*
+===============
+Parse_Directive_define
+===============
+*/
+static bool Parse_Directive_define(source_t *source)
+{
+ token_t token, *t, *last;
+ define_t *define;
+
+ if (source->skip > 0) return true;
+ //
+ if (!Parse_ReadLine(source, &token))
+ {
+ Parse_SourceError(source, "#define without name");
+ return false;
+ }
+ if (token.type != TT_NAME)
+ {
+ Parse_UnreadSourceToken(source, &token);
+ Parse_SourceError(source, "expected name after #define, found %s", token.string);
+ return false;
+ }
+ //check if the define already exists
+ define = Parse_FindHashedDefine(source->definehash, token.string);
+ if (define)
+ {
+ if (define->flags & DEFINE_FIXED)
+ {
+ Parse_SourceError(source, "can't redefine %s", token.string);
+ return false;
+ }
+ Parse_SourceWarning(source, "redefinition of %s", token.string);
+ //unread the define name before executing the #undef directive
+ Parse_UnreadSourceToken(source, &token);
+ if (!Parse_Directive_undef(source)) return false;
+ //if the define was not removed (define->flags & DEFINE_FIXED)
+ define = Parse_FindHashedDefine(source->definehash, token.string);
+ }
+ //allocate define
+ define = (define_t *) Z_Malloc(sizeof(define_t) + strlen(token.string) + 1);
+ ::memset(define, 0, sizeof(define_t));
+ define->name = (char *) define + sizeof(define_t);
+ strcpy(define->name, token.string);
+ //add the define to the source
+ Parse_AddDefineToHash(define, source->definehash);
+ //if nothing is defined, just return
+ if (!Parse_ReadLine(source, &token)) return true;
+ //if it is a define with parameters
+ if (!Parse_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, "("))
+ {
+ //read the define parameters
+ last = NULL;
+ if (!Parse_CheckTokenString(source, ")"))
+ {
+ while(1)
+ {
+ if (!Parse_ReadLine(source, &token))
+ {
+ Parse_SourceError(source, "expected define parameter");
+ return false;
+ }
+ //if it isn't a name
+ if (token.type != TT_NAME)
+ {
+ Parse_SourceError(source, "invalid define parameter");
+ return false;
+ }
+ //
+ if (Parse_FindDefineParm(define, token.string) >= 0)
+ {
+ Parse_SourceError(source, "two the same define parameters");
+ return false;
+ }
+ //add the define parm
+ t = Parse_CopyToken(&token);
+ Parse_ClearTokenWhiteSpace(t);
+ t->next = NULL;
+ if (last) last->next = t;
+ else define->parms = t;
+ last = t;
+ define->numparms++;
+ //read next token
+ if (!Parse_ReadLine(source, &token))
+ {
+ Parse_SourceError(source, "define parameters not terminated");
+ return false;
+ }
+ //
+ if (!strcmp(token.string, ")")) break;
+ //then it must be a comma
+ if (strcmp(token.string, ","))
+ {
+ Parse_SourceError(source, "define not terminated");
+ return false;
+ }
+ }
+ }
+ if (!Parse_ReadLine(source, &token)) return true;
+ }
+ //read the defined stuff
+ last = NULL;
+ do
+ {
+ t = Parse_CopyToken(&token);
+ if (t->type == TT_NAME && !strcmp(t->string, define->name))
+ {
+ Parse_SourceError(source, "recursive define (removed recursion)");
+ continue;
+ }
+ Parse_ClearTokenWhiteSpace(t);
+ t->next = NULL;
+ if (last) last->next = t;
+ else define->tokens = t;
+ last = t;
+ } while(Parse_ReadLine(source, &token));
+ //
+ if (last)
+ {
+ //check for merge operators at the beginning or end
+ if (!strcmp(define->tokens->string, "##") ||
+ !strcmp(last->string, "##"))
+ {
+ Parse_SourceError(source, "define with misplaced ##");
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+===============
+Parse_ReadDirective
+===============
+*/
+directive_t directives[20] =
+{
+ {"if", Parse_Directive_if},
+ {"ifdef", Parse_Directive_ifdef},
+ {"ifndef", Parse_Directive_ifndef},
+ {"elif", Parse_Directive_elif},
+ {"else", Parse_Directive_else},
+ {"endif", Parse_Directive_endif},
+ {"include", Parse_Directive_include},
+ {"define", Parse_Directive_define},
+ {"undef", Parse_Directive_undef},
+ {"line", Parse_Directive_line},
+ {"error", Parse_Directive_error},
+ {"pragma", Parse_Directive_pragma},
+ {"eval", Parse_Directive_eval},
+ {"evalfloat", Parse_Directive_evalfloat},
+ {NULL, NULL}
+};
+
+static bool Parse_ReadDirective(source_t *source)
+{
+ token_t token;
+ int i;
+
+ //read the directive name
+ if (!Parse_ReadSourceToken(source, &token))
+ {
+ Parse_SourceError(source, "found # without name");
+ return false;
+ }
+ //directive name must be on the same line
+ if (token.linescrossed > 0)
+ {
+ Parse_UnreadSourceToken(source, &token);
+ Parse_SourceError(source, "found # at end of line");
+ return false;
+ }
+ //if if is a name
+ if (token.type == TT_NAME)
+ {
+ //find the precompiler directive
+ for (i = 0; directives[i].name; i++)
+ {
+ if (!strcmp(directives[i].name, token.string))
+ {
+ return directives[i].func(source);
+ }
+ }
+ }
+ Parse_SourceError(source, "unknown precompiler directive %s", token.string);
+ return false;
+}
+
+/*
+===============
+Parse_UnreadToken
+===============
+*/
+static void Parse_UnreadToken(source_t *source, token_t *token)
+{
+ Parse_UnreadSourceToken(source, token);
+}
+
+/*
+===============
+Parse_ReadEnumeration
+
+It is assumed that the 'enum' token has already been consumed
+This is fairly basic: it doesn't catch some fairly obvious errors like nested
+enums, and enumerated names conflict with #define parameters
+===============
+*/
+static bool Parse_ReadEnumeration( source_t *source )
+{
+ token_t newtoken;
+ int value;
+
+ if( !Parse_ReadToken( source, &newtoken ) )
+ return false;
+
+ if( newtoken.type != TT_PUNCTUATION || newtoken.subtype != P_BRACEOPEN )
+ {
+ Parse_SourceError( source, "Found %s when expecting {\n",
+ newtoken.string );
+ return false;
+ }
+
+ for( value = 0;; value++ )
+ {
+ token_t name;
+
+ // read the name
+ if( !Parse_ReadToken( source, &name ) )
+ break;
+
+ // it's ok for the enum to end immediately
+ if( name.type == TT_PUNCTUATION && name.subtype == P_BRACECLOSE )
+ {
+ if( !Parse_ReadToken( source, &name ) )
+ break;
+
+ // ignore trailing semicolon
+ if( name.type != TT_PUNCTUATION || name.subtype != P_SEMICOLON )
+ Parse_UnreadToken( source, &name );
+
+ return true;
+ }
+
+ // ... but not for it to do anything else
+ if( name.type != TT_NAME )
+ {
+ Parse_SourceError( source, "Found %s when expecting identifier\n",
+ name.string );
+ return false;
+ }
+
+ if( !Parse_ReadToken( source, &newtoken ) )
+ break;
+
+ if( newtoken.type != TT_PUNCTUATION )
+ {
+ Parse_SourceError( source, "Found %s when expecting , or = or }\n",
+ newtoken.string );
+ return false;
+ }
+
+ if( newtoken.subtype == P_ASSIGN )
+ {
+ int neg = 1;
+
+ if( !Parse_ReadToken( source, &newtoken ) )
+ break;
+
+ // Parse_ReadToken doesn't seem to read negative numbers, so we do it
+ // ourselves
+ if( newtoken.type == TT_PUNCTUATION && newtoken.subtype == P_SUB )
+ {
+ neg = -1;
+
+ // the next token should be the number
+ if( !Parse_ReadToken( source, &newtoken ) )
+ break;
+ }
+
+ if( newtoken.type != TT_NUMBER || !( newtoken.subtype & TT_INTEGER ) )
+ {
+ Parse_SourceError( source, "Found %s when expecting integer\n",
+ newtoken.string );
+ return false;
+ }
+
+ // this is somewhat silly, but cheap to check
+ if( neg == -1 && ( newtoken.subtype & TT_UNSIGNED ) )
+ {
+ Parse_SourceWarning( source, "Value in enumeration is negative and "
+ "unsigned\n" );
+ }
+
+ // set the new define value
+ value = newtoken.intvalue * neg;
+
+ if( !Parse_ReadToken( source, &newtoken ) )
+ break;
+ }
+
+ if( newtoken.type != TT_PUNCTUATION || ( newtoken.subtype != P_COMMA &&
+ newtoken.subtype != P_BRACECLOSE ) )
+ {
+ Parse_SourceError( source, "Found %s when expecting , or }\n",
+ newtoken.string );
+ return false;
+ }
+
+ if( !Parse_AddDefineToSourceFromString( source, va( "%s %d\n", name.string,
+ value ) ) )
+ {
+ Parse_SourceWarning( source, "Couldn't add define to source: %s = %d\n",
+ name.string, value );
+ return false;
+ }
+
+ if( newtoken.subtype == P_BRACECLOSE )
+ {
+ if( !Parse_ReadToken( source, &name ) )
+ break;
+
+ // ignore trailing semicolon
+ if( name.type != TT_PUNCTUATION || name.subtype != P_SEMICOLON )
+ Parse_UnreadToken( source, &name );
+
+ return true;
+ }
+ }
+
+ // got here if a ReadToken returned false
+ return false;
+}
+
+/*
+===============
+Parse_ReadToken
+===============
+*/
+static bool Parse_ReadToken(source_t *source, token_t *token)
+{
+ define_t *define;
+
+ while(1)
+ {
+ if (!Parse_ReadSourceToken(source, token)) return false;
+ //check for precompiler directives
+ if (token->type == TT_PUNCTUATION && *token->string == '#')
+ {
+ {
+ //read the precompiler directive
+ if (!Parse_ReadDirective(source)) return false;
+ continue;
+ }
+ }
+ if (token->type == TT_PUNCTUATION && *token->string == '$')
+ {
+ {
+ //read the precompiler directive
+ if (!Parse_ReadDollarDirective(source)) return false;
+ continue;
+ }
+ }
+ if( token->type == TT_NAME && !Q_stricmp( token->string, "enum" ) )
+ {
+ if( !Parse_ReadEnumeration( source ) )
+ return false;
+ continue;
+ }
+ // recursively concatenate strings that are behind each other still resolving defines
+ if (token->type == TT_STRING)
+ {
+ token_t newtoken;
+ if (Parse_ReadToken(source, &newtoken))
+ {
+ if (newtoken.type == TT_STRING)
+ {
+ token->string[strlen(token->string)-1] = '\0';
+ if (strlen(token->string) + strlen(newtoken.string+1) + 1 >= MAX_TOKEN_CHARS)
+ {
+ Parse_SourceError(source, "string longer than MAX_TOKEN_CHARS %d\n", MAX_TOKEN_CHARS);
+ return false;
+ }
+ strcat(token->string, newtoken.string+1);
+ }
+ else
+ {
+ Parse_UnreadToken(source, &newtoken);
+ }
+ }
+ }
+ //if skipping source because of conditional compilation
+ if (source->skip) continue;
+ //if the token is a name
+ if (token->type == TT_NAME)
+ {
+ //check if the name is a define macro
+ define = Parse_FindHashedDefine(source->definehash, token->string);
+ //if it is a define macro
+ if (define)
+ {
+ //expand the defined macro
+ if (!Parse_ExpandDefineIntoSource(source, token, define)) return false;
+ continue;
+ }
+ }
+ //copy token for unreading
+ ::memcpy(&source->token, token, sizeof(token_t));
+ //found a token
+ return true;
+ }
+}
+
+/*
+===============
+Parse_DefineFromString
+===============
+*/
+static define_t *Parse_DefineFromString(char *string)
+{
+ script_t *script;
+ source_t src;
+ token_t *t;
+ int res, i;
+ define_t *def;
+
+ script = Parse_LoadScriptMemory(string, strlen(string), "*extern");
+ //create a new source
+ ::memset(&src, 0, sizeof(source_t));
+ strncpy(src.filename, "*extern", MAX_QPATH);
+ src.scriptstack = script;
+ src.definehash = (define_t**)Z_Malloc(DEFINEHASHSIZE * sizeof(define_t *));
+ ::memset( src.definehash, 0, DEFINEHASHSIZE * sizeof(define_t *));
+ //create a define from the source
+ res = Parse_Directive_define(&src);
+ //free any tokens if left
+ for (t = src.tokens; t; t = src.tokens)
+ {
+ src.tokens = src.tokens->next;
+ Parse_FreeToken(t);
+ }
+ def = NULL;
+ for (i = 0; i < DEFINEHASHSIZE; i++)
+ {
+ if (src.definehash[i])
+ {
+ def = src.definehash[i];
+ break;
+ }
+ }
+ //
+ Z_Free(src.definehash);
+ //
+ Parse_FreeScript(script);
+ //if the define was created succesfully
+ if (res > 0) return def;
+ //free the define is created
+ if (src.defines) Parse_FreeDefine(def);
+ //
+ return NULL;
+}
+
+/*
+===============
+Parse_AddDefineToSourceFromString
+===============
+*/
+static bool Parse_AddDefineToSourceFromString( source_t *source, const char *string )
+{
+ Parse_PushScript( source, Parse_LoadScriptMemory(string, strlen(string), "*extern") );
+ return Parse_Directive_define( source );
+}
+
+/*
+===============
+Parse_AddGlobalDefine
+
+add a globals define that will be added to all opened sources
+===============
+*/
+bool Parse_AddGlobalDefine(char *string)
+{
+ define_t *define;
+
+ define = Parse_DefineFromString(string);
+ if (!define) return false;
+ define->next = globaldefines;
+ globaldefines = define;
+ return true;
+}
+
+/*
+===============
+Parse_CopyDefine
+===============
+*/
+static define_t *Parse_CopyDefine(define_t *define)
+{
+ define_t *newdefine;
+ token_t *token, *newtoken, *lasttoken;
+
+ newdefine = (define_t *) Z_Malloc(sizeof(define_t) + strlen(define->name) + 1);
+ //copy the define name
+ newdefine->name = (char *) newdefine + sizeof(define_t);
+ strcpy(newdefine->name, define->name);
+ newdefine->flags = define->flags;
+ newdefine->builtin = define->builtin;
+ newdefine->numparms = define->numparms;
+ //the define is not linked
+ newdefine->next = NULL;
+ newdefine->hashnext = NULL;
+ //copy the define tokens
+ newdefine->tokens = NULL;
+ for (lasttoken = NULL, token = define->tokens; token; token = token->next)
+ {
+ newtoken = Parse_CopyToken(token);
+ newtoken->next = NULL;
+ if (lasttoken) lasttoken->next = newtoken;
+ else newdefine->tokens = newtoken;
+ lasttoken = newtoken;
+ }
+ //copy the define parameters
+ newdefine->parms = NULL;
+ for (lasttoken = NULL, token = define->parms; token; token = token->next)
+ {
+ newtoken = Parse_CopyToken(token);
+ newtoken->next = NULL;
+ if (lasttoken) lasttoken->next = newtoken;
+ else newdefine->parms = newtoken;
+ lasttoken = newtoken;
+ }
+ return newdefine;
+}
+
+/*
+===============
+Parse_AddGlobalDefinesToSource
+===============
+*/
+static void Parse_AddGlobalDefinesToSource(source_t *source)
+{
+ define_t *define, *newdefine;
+
+ for (define = globaldefines; define; define = define->next)
+ {
+ newdefine = Parse_CopyDefine(define);
+ Parse_AddDefineToHash(newdefine, source->definehash);
+ }
+}
+
+/*
+===============
+Parse_LoadSourceFile
+===============
+*/
+static source_t *Parse_LoadSourceFile(const char *filename)
+{
+ source_t *source;
+ script_t *script;
+
+ script = Parse_LoadScriptFile(filename);
+ if (!script) return NULL;
+
+ script->next = NULL;
+
+ source = (source_t *) Z_Malloc(sizeof(source_t));
+ ::memset(source, 0, sizeof(source_t));
+
+ strncpy(source->filename, filename, MAX_QPATH);
+ source->scriptstack = script;
+ source->tokens = NULL;
+ source->defines = NULL;
+ source->indentstack = NULL;
+ source->skip = 0;
+
+ source->definehash = (define_t**)Z_Malloc(DEFINEHASHSIZE * sizeof(define_t *));
+ ::memset( source->definehash, 0, DEFINEHASHSIZE * sizeof(define_t *));
+ Parse_AddGlobalDefinesToSource(source);
+ return source;
+}
+
+/*
+===============
+Parse_FreeSource
+===============
+*/
+static void Parse_FreeSource(source_t *source)
+{
+ script_t *script;
+ token_t *token;
+ define_t *define;
+ indent_t *indent;
+ int i;
+
+ //Parse_PrintDefineHashTable(source->definehash);
+ //free all the scripts
+ while(source->scriptstack)
+ {
+ script = source->scriptstack;
+ source->scriptstack = source->scriptstack->next;
+ Parse_FreeScript(script);
+ }
+ //free all the tokens
+ while(source->tokens)
+ {
+ token = source->tokens;
+ source->tokens = source->tokens->next;
+ Parse_FreeToken(token);
+ }
+ for (i = 0; i < DEFINEHASHSIZE; i++)
+ {
+ while(source->definehash[i])
+ {
+ define = source->definehash[i];
+ source->definehash[i] = source->definehash[i]->hashnext;
+ Parse_FreeDefine(define);
+ }
+ }
+ //free all indents
+ while(source->indentstack)
+ {
+ indent = source->indentstack;
+ source->indentstack = source->indentstack->next;
+ Z_Free(indent);
+ }
+ //
+ if (source->definehash) Z_Free(source->definehash);
+ //free the source itself
+ Z_Free(source);
+}
+
+#define MAX_SOURCEFILES 64
+
+source_t *sourceFiles[MAX_SOURCEFILES];
+
+/*
+===============
+Parse_LoadSourceHandle
+===============
+*/
+int Parse_LoadSourceHandle(const char *filename)
+{
+ source_t *source;
+ int i;
+
+ for (i = 1; i < MAX_SOURCEFILES; i++)
+ {
+ if (!sourceFiles[i])
+ break;
+ }
+ if (i >= MAX_SOURCEFILES)
+ return 0;
+ source = Parse_LoadSourceFile(filename);
+ if (!source)
+ return 0;
+ sourceFiles[i] = source;
+ return i;
+}
+
+/*
+===============
+Parse_FreeSourceHandle
+===============
+*/
+bool Parse_FreeSourceHandle(int handle)
+{
+ if (handle < 1 || handle >= MAX_SOURCEFILES)
+ return false;
+ if (!sourceFiles[handle])
+ return false;
+
+ Parse_FreeSource(sourceFiles[handle]);
+ sourceFiles[handle] = NULL;
+ return true;
+}
+
+/*
+===============
+Parse_ReadTokenHandle
+===============
+*/
+bool Parse_ReadTokenHandle(int handle, pc_token_t *pc_token)
+{
+ token_t token;
+ bool ret;
+
+ if (handle < 1 || handle >= MAX_SOURCEFILES)
+ return false;
+ if (!sourceFiles[handle])
+ return false;
+
+ ret = Parse_ReadToken(sourceFiles[handle], &token);
+ strcpy(pc_token->string, token.string);
+ pc_token->type = token.type;
+ pc_token->subtype = token.subtype;
+ pc_token->intvalue = token.intvalue;
+ pc_token->floatvalue = token.floatvalue;
+ if (pc_token->type == TT_STRING)
+ Parse_StripDoubleQuotes(pc_token->string);
+ return ret;
+}
+
+/*
+===============
+Parse_SourceFileAndLine
+===============
+*/
+bool Parse_SourceFileAndLine(int handle, char *filename, int *line)
+{
+ if (handle < 1 || handle >= MAX_SOURCEFILES)
+ return false;
+ if (!sourceFiles[handle])
+ return false;
+
+ strcpy(filename, sourceFiles[handle]->filename);
+ if (sourceFiles[handle]->scriptstack)
+ *line = sourceFiles[handle]->scriptstack->line;
+ else
+ *line = 0;
+ return true;
+}
diff --git a/src/qcommon/puff.cpp b/src/qcommon/puff.cpp
new file mode 100644
index 0000000..6874b28
--- /dev/null
+++ b/src/qcommon/puff.cpp
@@ -0,0 +1,759 @@
+/*
+ * This is a modified version of Mark Adlers work,
+ * see below for the original copyright.
+ * 2006 - Joerg Dietrich <dietrich_joerg@gmx.de>
+ */
+
+/*
+ * puff.c
+ * Copyright (C) 2002-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in puff.h
+ * version 1.8, 9 Jan 2004
+ *
+ * puff.c is a simple inflate written to be an unambiguous way to specify the
+ * deflate format. It is not written for speed but rather simplicity. As a
+ * side benefit, this code might actually be useful when small code is more
+ * important than speed, such as bootstrap applications. For typical deflate
+ * data, zlib's inflate() is about four times as fast as puff(). zlib's
+ * inflate compiles to around 20K on my machine, whereas puff.c compiles to
+ * around 4K on my machine (a PowerPC using GNU cc). If the faster decode()
+ * function here is used, then puff() is only twice as slow as zlib's
+ * inflate().
+ *
+ * All dynamically allocated memory comes from the stack. The stack required
+ * is less than 2K bytes. This code is compatible with 16-bit int's and
+ * assumes that long's are at least 32 bits. puff.c uses the short data type,
+ * assumed to be 16 bits, for arrays in order to to conserve memory. The code
+ * works whether integers are stored big endian or little endian.
+ *
+ * In the comments below are "Format notes" that describe the inflate process
+ * and document some of the less obvious aspects of the format. This source
+ * code is meant to supplement RFC 1951, which formally describes the deflate
+ * format:
+ *
+ * http://www.zlib.org/rfc-deflate.html
+ */
+
+/*
+ * Change history:
+ *
+ * 1.0 10 Feb 2002 - First version
+ * 1.1 17 Feb 2002 - Clarifications of some comments and notes
+ * - Update puff() dest and source pointers on negative
+ * errors to facilitate debugging deflators
+ * - Remove longest from struct huffman -- not needed
+ * - Simplify offs[] index in construct()
+ * - Add input size and checking, using longjmp() to
+ * maintain easy readability
+ * - Use short data type for large arrays
+ * - Use pointers instead of long to specify source and
+ * destination sizes to avoid arbitrary 4 GB limits
+ * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!),
+ * but leave simple version for readabilty
+ * - Make sure invalid distances detected if pointers
+ * are 16 bits
+ * - Fix fixed codes table error
+ * - Provide a scanning mode for determining size of
+ * uncompressed data
+ * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Jean-loup]
+ * - Add a puff.h file for the interface
+ * - Add braces in puff() for else do [Jean-loup]
+ * - Use indexes instead of pointers for readability
+ * 1.4 31 Mar 2002 - Simplify construct() code set check
+ * - Fix some comments
+ * - Add FIXLCODES #define
+ * 1.5 6 Apr 2002 - Minor comment fixes
+ * 1.6 7 Aug 2002 - Minor format changes
+ * 1.7 3 Mar 2003 - Added test code for distribution
+ * - Added zlib-like license
+ * 1.8 9 Jan 2004 - Added some comments on no distance codes case
+ */
+
+#include "puff.h" /* prototype for puff() */
+
+#include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */
+
+#define local static /* for local function definitions */
+
+/*
+ * Maximums for allocations and loops. It is not useful to change these --
+ * they are fixed by the deflate format.
+ */
+#define MAXBITS 15 /* maximum bits in a code */
+#define MAXLCODES 286 /* maximum number of literal/length codes */
+#define MAXDCODES 30 /* maximum number of distance codes */
+#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */
+#define FIXLCODES 288 /* number of fixed literal/length codes */
+
+/* input and output state */
+struct state {
+ /* output state */
+ uint8_t *out; /* output buffer */
+ uint32_t outlen; /* available space at out */
+ uint32_t outcnt; /* bytes written to out so far */
+
+ /* input state */
+ uint8_t *in; /* input buffer */
+ uint32_t inlen; /* available input at in */
+ uint32_t incnt; /* bytes read so far */
+ int32_t bitbuf; /* bit buffer */
+ int32_t bitcnt; /* number of bits in bit buffer */
+
+ /* input limit error return state for bits() and decode() */
+ jmp_buf env;
+};
+
+/*
+ * Return need bits from the input stream. This always leaves less than
+ * eight bits in the buffer. bits() works properly for need == 0.
+ *
+ * Format notes:
+ *
+ * - Bits are stored in bytes from the least significant bit to the most
+ * significant bit. Therefore bits are dropped from the bottom of the bit
+ * buffer, using shift right, and new bytes are appended to the top of the
+ * bit buffer, using shift left.
+ */
+local int32_t bits(struct state *s, int32_t need)
+{
+ int32_t val; /* bit accumulator (can use up to 20 bits) */
+
+ /* load at least need bits into val */
+ val = s->bitbuf;
+ while (s->bitcnt < need) {
+ if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */
+ val |= (int32_t)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */
+ s->bitcnt += 8;
+ }
+
+ /* drop need bits and update buffer, always zero to seven bits left */
+ s->bitbuf = (int32_t)(val >> need);
+ s->bitcnt -= need;
+
+ /* return need bits, zeroing the bits above that */
+ return (int32_t)(val & ((1L << need) - 1));
+}
+
+/*
+ * Process a stored block.
+ *
+ * Format notes:
+ *
+ * - After the two-bit stored block type (00), the stored block length and
+ * stored bytes are byte-aligned for fast copying. Therefore any leftover
+ * bits in the byte that has the last bit of the type, as many as seven, are
+ * discarded. The value of the discarded bits are not defined and should not
+ * be checked against any expectation.
+ *
+ * - The second inverted copy of the stored block length does not have to be
+ * checked, but it's probably a good idea to do so anyway.
+ *
+ * - A stored block can have zero length. This is sometimes used to byte-align
+ * subsets of the compressed data for random access or partial recovery.
+ */
+local int32_t stored(struct state *s)
+{
+ uint32_t len; /* length of stored block */
+
+ /* discard leftover bits from current byte (assumes s->bitcnt < 8) */
+ s->bitbuf = 0;
+ s->bitcnt = 0;
+
+ /* get length and check against its one's complement */
+ if (s->incnt + 4 > s->inlen) return 2; /* not enough input */
+ len = s->in[s->incnt++];
+ len |= s->in[s->incnt++] << 8;
+ if (s->in[s->incnt++] != (~len & 0xff) ||
+ s->in[s->incnt++] != ((~len >> 8) & 0xff))
+ return -2; /* didn't match complement! */
+
+ /* copy len bytes from in to out */
+ if (s->incnt + len > s->inlen) return 2; /* not enough input */
+ if (s->out != NULL) {
+ if (s->outcnt + len > s->outlen)
+ return 1; /* not enough output space */
+ while (len--)
+ s->out[s->outcnt++] = s->in[s->incnt++];
+ }
+ else { /* just scanning */
+ s->outcnt += len;
+ s->incnt += len;
+ }
+
+ /* done with a valid stored block */
+ return 0;
+}
+
+/*
+ * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of
+ * each length, which for a canonical code are stepped through in order.
+ * symbol[] are the symbol values in canonical order, where the number of
+ * entries is the sum of the counts in count[]. The decoding process can be
+ * seen in the function decode() below.
+ */
+struct huffman {
+ int16_t *count; /* number of symbols of each length */
+ int16_t *symbol; /* canonically ordered symbols */
+};
+
+/*
+ * Decode a code from the stream s using huffman table h. Return the symbol or
+ * a negative value if there is an error. If all of the lengths are zero, i.e.
+ * an empty code, or if the code is incomplete and an invalid code is received,
+ * then -9 is returned after reading MAXBITS bits.
+ *
+ * Format notes:
+ *
+ * - The codes as stored in the compressed data are bit-reversed relative to
+ * a simple integer ordering of codes of the same lengths. Hence below the
+ * bits are pulled from the compressed data one at a time and used to
+ * build the code value reversed from what is in the stream in order to
+ * permit simple integer comparisons for decoding. A table-based decoding
+ * scheme (as used in zlib) does not need to do this reversal.
+ *
+ * - The first code for the shortest length is all zeros. Subsequent codes of
+ * the same length are simply integer increments of the previous code. When
+ * moving up a length, a zero bit is appended to the code. For a complete
+ * code, the last code of the longest length will be all ones.
+ *
+ * - Incomplete codes are handled by this decoder, since they are permitted
+ * in the deflate format. See the format notes for fixed() and dynamic().
+ */
+local int32_t decode(struct state *s, struct huffman *h)
+{
+ int32_t len; /* current number of bits in code */
+ int32_t code; /* len bits being decoded */
+ int32_t first; /* first code of length len */
+ int32_t count; /* number of codes of length len */
+ int32_t index; /* index of first code of length len in symbol table */
+ int32_t bitbuf; /* bits from stream */
+ int32_t left; /* bits left in next or left to process */
+ int16_t *next; /* next number of codes */
+
+ bitbuf = s->bitbuf;
+ left = s->bitcnt;
+ code = first = index = 0;
+ len = 1;
+ next = h->count + 1;
+ while (1) {
+ while (left--) {
+ code |= bitbuf & 1;
+ bitbuf >>= 1;
+ count = *next++;
+ if (code < first + count) { /* if length len, return symbol */
+ s->bitbuf = bitbuf;
+ s->bitcnt = (s->bitcnt - len) & 7;
+ return h->symbol[index + (code - first)];
+ }
+ index += count; /* else update for next length */
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ len++;
+ }
+ left = (MAXBITS+1) - len;
+ if (left == 0) break;
+ if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */
+ bitbuf = s->in[s->incnt++];
+ if (left > 8) left = 8;
+ }
+ return -9; /* ran out of codes */
+}
+
+/*
+ * Given the list of code lengths length[0..n-1] representing a canonical
+ * Huffman code for n symbols, construct the tables required to decode those
+ * codes. Those tables are the number of codes of each length, and the symbols
+ * sorted by length, retaining their original order within each length. The
+ * return value is zero for a complete code set, negative for an over-
+ * subscribed code set, and positive for an incomplete code set. The tables
+ * can be used if the return value is zero or positive, but they cannot be used
+ * if the return value is negative. If the return value is zero, it is not
+ * possible for decode() using that table to return an error--any stream of
+ * enough bits will resolve to a symbol. If the return value is positive, then
+ * it is possible for decode() using that table to return an error for received
+ * codes past the end of the incomplete lengths.
+ *
+ * Not used by decode(), but used for error checking, h->count[0] is the number
+ * of the n symbols not in the code. So n - h->count[0] is the number of
+ * codes. This is useful for checking for incomplete codes that have more than
+ * one symbol, which is an error in a dynamic block.
+ *
+ * Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS
+ * This is assured by the construction of the length arrays in dynamic() and
+ * fixed() and is not verified by construct().
+ *
+ * Format notes:
+ *
+ * - Permitted and expected examples of incomplete codes are one of the fixed
+ * codes and any code with a single symbol which in deflate is coded as one
+ * bit instead of zero bits. See the format notes for fixed() and dynamic().
+ *
+ * - Within a given code length, the symbols are kept in ascending order for
+ * the code bits definition.
+ */
+local int32_t construct(struct huffman *h, int16_t *length, int32_t n)
+{
+ int32_t symbol; /* current symbol when stepping through length[] */
+ int32_t len; /* current length when stepping through h->count[] */
+ int32_t left; /* number of possible codes left of current length */
+ int16_t offs[MAXBITS+1]; /* offsets in symbol table for each length */
+
+ /* count number of codes of each length */
+ for (len = 0; len <= MAXBITS; len++)
+ h->count[len] = 0;
+ for (symbol = 0; symbol < n; symbol++)
+ (h->count[length[symbol]])++; /* assumes lengths are within bounds */
+ if (h->count[0] == n) /* no codes! */
+ return 0; /* complete, but decode() will fail */
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1; /* one possible code of zero length */
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1; /* one more bit, double codes left */
+ left -= h->count[len]; /* deduct count from possible codes */
+ if (left < 0) return left; /* over-subscribed--return negative */
+ } /* left > 0 means incomplete */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + h->count[len];
+
+ /*
+ * put symbols in table sorted by length, by symbol order within each
+ * length
+ */
+ for (symbol = 0; symbol < n; symbol++)
+ if (length[symbol] != 0)
+ h->symbol[offs[length[symbol]]++] = symbol;
+
+ /* return zero for complete set, positive for incomplete set */
+ return left;
+}
+
+/*
+ * Decode literal/length and distance codes until an end-of-block code.
+ *
+ * Format notes:
+ *
+ * - Compressed data that is after the block type if fixed or after the code
+ * description if dynamic is a combination of literals and length/distance
+ * pairs terminated by and end-of-block code. Literals are simply Huffman
+ * coded bytes. A length/distance pair is a coded length followed by a
+ * coded distance to represent a string that occurs earlier in the
+ * uncompressed data that occurs again at the current location.
+ *
+ * - Literals, lengths, and the end-of-block code are combined into a single
+ * code of up to 286 symbols. They are 256 literals (0..255), 29 length
+ * symbols (257..285), and the end-of-block symbol (256).
+ *
+ * - There are 256 possible lengths (3..258), and so 29 symbols are not enough
+ * to represent all of those. Lengths 3..10 and 258 are in fact represented
+ * by just a length symbol. Lengths 11..257 are represented as a symbol and
+ * some number of extra bits that are added as an integer to the base length
+ * of the length symbol. The number of extra bits is determined by the base
+ * length symbol. These are in the static arrays below, lens[] for the base
+ * lengths and lext[] for the corresponding number of extra bits.
+ *
+ * - The reason that 258 gets its own symbol is that the longest length is used
+ * often in highly redundant files. Note that 258 can also be coded as the
+ * base value 227 plus the maximum extra value of 31. While a good deflate
+ * should never do this, it is not an error, and should be decoded properly.
+ *
+ * - If a length is decoded, including its extra bits if any, then it is
+ * followed a distance code. There are up to 30 distance symbols. Again
+ * there are many more possible distances (1..32768), so extra bits are added
+ * to a base value represented by the symbol. The distances 1..4 get their
+ * own symbol, but the rest require extra bits. The base distances and
+ * corresponding number of extra bits are below in the static arrays dist[]
+ * and dext[].
+ *
+ * - Literal bytes are simply written to the output. A length/distance pair is
+ * an instruction to copy previously uncompressed bytes to the output. The
+ * copy is from distance bytes back in the output stream, copying for length
+ * bytes.
+ *
+ * - Distances pointing before the beginning of the output data are not
+ * permitted.
+ *
+ * - Overlapped copies, where the length is greater than the distance, are
+ * allowed and common. For example, a distance of one and a length of 258
+ * simply copies the last byte 258 times. A distance of four and a length of
+ * twelve copies the last four bytes three times. A simple forward copy
+ * ignoring whether the length is greater than the distance or not implements
+ * this correctly. You should not use memcpy() since its behavior is not
+ * defined for overlapped arrays. You should not use memmove() or bcopy()
+ * since though their behavior -is- defined for overlapping arrays, it is
+ * defined to do the wrong thing in this case.
+ */
+local int32_t codes(struct state *s,
+ struct huffman *lencode,
+ struct huffman *distcode)
+{
+ int32_t symbol; /* decoded symbol */
+ int32_t len; /* length for copy */
+ uint32_t dist; /* distance for copy */
+ static const int16_t lens[29] = { /* Size base for length codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
+ static const int16_t lext[29] = { /* Extra bits for length codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
+ static const int16_t dists[30] = { /* Offset base for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+ static const int16_t dext[30] = { /* Extra bits for distance codes 0..29 */
+ 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};
+
+ /* decode literals and length/distance pairs */
+ do {
+ symbol = decode(s, lencode);
+ if (symbol < 0) return symbol; /* invalid symbol */
+ if (symbol < 256) { /* literal: symbol is the byte */
+ /* write out the literal */
+ if (s->out != NULL) {
+ if (s->outcnt == s->outlen) return 1;
+ s->out[s->outcnt] = symbol;
+ }
+ s->outcnt++;
+ }
+ else if (symbol > 256) { /* length */
+ /* get and compute length */
+ symbol -= 257;
+ if (symbol >= 29) return -9; /* invalid fixed code */
+ len = lens[symbol] + bits(s, lext[symbol]);
+
+ /* get and check distance */
+ symbol = decode(s, distcode);
+ if (symbol < 0) return symbol; /* invalid symbol */
+ dist = dists[symbol] + bits(s, dext[symbol]);
+ if (dist > s->outcnt)
+ return -10; /* distance too far back */
+
+ /* copy length bytes from distance bytes back */
+ if (s->out != NULL) {
+ if (s->outcnt + len > s->outlen) return 1;
+ while (len--) {
+ s->out[s->outcnt] = s->out[s->outcnt - dist];
+ s->outcnt++;
+ }
+ }
+ else
+ s->outcnt += len;
+ }
+ } while (symbol != 256); /* end of block symbol */
+
+ /* done with a valid fixed or dynamic block */
+ return 0;
+}
+
+/*
+ * Process a fixed codes block.
+ *
+ * Format notes:
+ *
+ * - This block type can be useful for compressing small amounts of data for
+ * which the size of the code descriptions in a dynamic block exceeds the
+ * benefit of custom codes for that block. For fixed codes, no bits are
+ * spent on code descriptions. Instead the code lengths for literal/length
+ * codes and distance codes are fixed. The specific lengths for each symbol
+ * can be seen in the "for" loops below.
+ *
+ * - The literal/length code is complete, but has two symbols that are invalid
+ * and should result in an error if received. This cannot be implemented
+ * simply as an incomplete code since those two symbols are in the "middle"
+ * of the code. They are eight bits long and the longest literal/length\
+ * code is nine bits. Therefore the code must be constructed with those
+ * symbols, and the invalid symbols must be detected after decoding.
+ *
+ * - The fixed distance codes also have two invalid symbols that should result
+ * in an error if received. Since all of the distance codes are the same
+ * length, this can be implemented as an incomplete code. Then the invalid
+ * codes are detected while decoding.
+ */
+local int32_t fixed(struct state *s)
+{
+ static int32_t virgin = 1;
+ static int16_t lencnt[MAXBITS+1], lensym[FIXLCODES];
+ static int16_t distcnt[MAXBITS+1], distsym[MAXDCODES];
+ static struct huffman lencode = {lencnt, lensym};
+ static struct huffman distcode = {distcnt, distsym};
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ int32_t symbol;
+ int16_t lengths[FIXLCODES];
+
+ /* literal/length table */
+ for (symbol = 0; symbol < 144; symbol++)
+ lengths[symbol] = 8;
+ for (; symbol < 256; symbol++)
+ lengths[symbol] = 9;
+ for (; symbol < 280; symbol++)
+ lengths[symbol] = 7;
+ for (; symbol < FIXLCODES; symbol++)
+ lengths[symbol] = 8;
+ construct(&lencode, lengths, FIXLCODES);
+
+ /* distance table */
+ for (symbol = 0; symbol < MAXDCODES; symbol++)
+ lengths[symbol] = 5;
+ construct(&distcode, lengths, MAXDCODES);
+
+ /* do this just once */
+ virgin = 0;
+ }
+
+ /* decode data until end-of-block code */
+ return codes(s, &lencode, &distcode);
+}
+
+/*
+ * Process a dynamic codes block.
+ *
+ * Format notes:
+ *
+ * - A dynamic block starts with a description of the literal/length and
+ * distance codes for that block. New dynamic blocks allow the compressor to
+ * rapidly adapt to changing data with new codes optimized for that data.
+ *
+ * - The codes used by the deflate format are "canonical", which means that
+ * the actual bits of the codes are generated in an unambiguous way simply
+ * from the number of bits in each code. Therefore the code descriptions
+ * are simply a list of code lengths for each symbol.
+ *
+ * - The code lengths are stored in order for the symbols, so lengths are
+ * provided for each of the literal/length symbols, and for each of the
+ * distance symbols.
+ *
+ * - If a symbol is not used in the block, this is represented by a zero as
+ * as the code length. This does not mean a zero-length code, but rather
+ * that no code should be created for this symbol. There is no way in the
+ * deflate format to represent a zero-length code.
+ *
+ * - The maximum number of bits in a code is 15, so the possible lengths for
+ * any code are 1..15.
+ *
+ * - The fact that a length of zero is not permitted for a code has an
+ * interesting consequence. Normally if only one symbol is used for a given
+ * code, then in fact that code could be represented with zero bits. However
+ * in deflate, that code has to be at least one bit. So for example, if
+ * only a single distance base symbol appears in a block, then it will be
+ * represented by a single code of length one, in particular one 0 bit. This
+ * is an incomplete code, since if a 1 bit is received, it has no meaning,
+ * and should result in an error. So incomplete distance codes of one symbol
+ * should be permitted, and the receipt of invalid codes should be handled.
+ *
+ * - It is also possible to have a single literal/length code, but that code
+ * must be the end-of-block code, since every dynamic block has one. This
+ * is not the most efficient way to create an empty block (an empty fixed
+ * block is fewer bits), but it is allowed by the format. So incomplete
+ * literal/length codes of one symbol should also be permitted.
+ *
+ * - If there are only literal codes and no lengths, then there are no distance
+ * codes. This is represented by one distance code with zero bits.
+ *
+ * - The list of up to 286 length/literal lengths and up to 30 distance lengths
+ * are themselves compressed using Huffman codes and run-length encoding. In
+ * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means
+ * that length, and the symbols 16, 17, and 18 are run-length instructions.
+ * Each of 16, 17, and 18 are follwed by extra bits to define the length of
+ * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10
+ * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols
+ * are common, hence the special coding for zero lengths.
+ *
+ * - The symbols for 0..18 are Huffman coded, and so that code must be
+ * described first. This is simply a sequence of up to 19 three-bit values
+ * representing no code (0) or the code length for that symbol (1..7).
+ *
+ * - A dynamic block starts with three fixed-size counts from which is computed
+ * the number of literal/length code lengths, the number of distance code
+ * lengths, and the number of code length code lengths (ok, you come up with
+ * a better name!) in the code descriptions. For the literal/length and
+ * distance codes, lengths after those provided are considered zero, i.e. no
+ * code. The code length code lengths are received in a permuted order (see
+ * the order[] array below) to make a short code length code length list more
+ * likely. As it turns out, very short and very long codes are less likely
+ * to be seen in a dynamic code description, hence what may appear initially
+ * to be a peculiar ordering.
+ *
+ * - Given the number of literal/length code lengths (nlen) and distance code
+ * lengths (ndist), then they are treated as one long list of nlen + ndist
+ * code lengths. Therefore run-length coding can and often does cross the
+ * boundary between the two sets of lengths.
+ *
+ * - So to summarize, the code description at the start of a dynamic block is
+ * three counts for the number of code lengths for the literal/length codes,
+ * the distance codes, and the code length codes. This is followed by the
+ * code length code lengths, three bits each. This is used to construct the
+ * code length code which is used to read the remainder of the lengths. Then
+ * the literal/length code lengths and distance lengths are read as a single
+ * set of lengths using the code length codes. Codes are constructed from
+ * the resulting two sets of lengths, and then finally you can start
+ * decoding actual compressed data in the block.
+ *
+ * - For reference, a "typical" size for the code description in a dynamic
+ * block is around 80 bytes.
+ */
+local int32_t dynamic(struct state *s)
+{
+ int32_t nlen, ndist, ncode; /* number of lengths in descriptor */
+ int32_t index; /* index of lengths[] */
+ int32_t err; /* construct() return value */
+ int16_t lengths[MAXCODES]; /* descriptor code lengths */
+ int16_t lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */
+ int16_t distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */
+ struct huffman lencode = {lencnt, lensym}; /* length code */
+ struct huffman distcode = {distcnt, distsym}; /* distance code */
+ static const int16_t order[19] = /* permutation of code length codes */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* get number of lengths in each table, check lengths */
+ nlen = bits(s, 5) + 257;
+ ndist = bits(s, 5) + 1;
+ ncode = bits(s, 4) + 4;
+ if (nlen > MAXLCODES || ndist > MAXDCODES)
+ return -3; /* bad counts */
+
+ /* read code length code lengths (really), missing lengths are zero */
+ for (index = 0; index < ncode; index++)
+ lengths[order[index]] = bits(s, 3);
+ for (; index < 19; index++)
+ lengths[order[index]] = 0;
+
+ /* build huffman table for code lengths codes (use lencode temporarily) */
+ err = construct(&lencode, lengths, 19);
+ if (err != 0) return -4; /* require complete code set here */
+
+ /* read length/literal and distance code length tables */
+ index = 0;
+ while (index < nlen + ndist) {
+ int32_t symbol; /* decoded value */
+ int32_t len; /* last length to repeat */
+
+ symbol = decode(s, &lencode);
+ if (symbol < 16) /* length in 0..15 */
+ lengths[index++] = symbol;
+ else { /* repeat instruction */
+ len = 0; /* assume repeating zeros */
+ if (symbol == 16) { /* repeat last length 3..6 times */
+ if (index == 0) return -5; /* no last length! */
+ len = lengths[index - 1]; /* last length */
+ symbol = 3 + bits(s, 2);
+ }
+ else if (symbol == 17) /* repeat zero 3..10 times */
+ symbol = 3 + bits(s, 3);
+ else /* == 18, repeat zero 11..138 times */
+ symbol = 11 + bits(s, 7);
+ if (index + symbol > nlen + ndist)
+ return -6; /* too many lengths! */
+ while (symbol--) /* repeat last or zero symbol times */
+ lengths[index++] = len;
+ }
+ }
+
+ /* build huffman table for literal/length codes */
+ err = construct(&lencode, lengths, nlen);
+ if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
+ return -7; /* only allow incomplete codes if just one code */
+
+ /* build huffman table for distance codes */
+ err = construct(&distcode, lengths + nlen, ndist);
+ if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1))
+ return -8; /* only allow incomplete codes if just one code */
+
+ /* decode data until end-of-block code */
+ return codes(s, &lencode, &distcode);
+}
+
+/*
+ * Inflate source to dest. On return, destlen and sourcelen are updated to the
+ * size of the uncompressed data and the size of the deflate data respectively.
+ * On success, the return value of puff() is zero. If there is an error in the
+ * source data, i.e. it is not in the deflate format, then a negative value is
+ * returned. If there is not enough input available or there is not enough
+ * output space, then a positive error is returned. In that case, destlen and
+ * sourcelen are not updated to facilitate retrying from the beginning with the
+ * provision of more input data or more output space. In the case of invalid
+ * inflate data (a negative error), the dest and source pointers are updated to
+ * facilitate the debugging of deflators.
+ *
+ * puff() also has a mode to determine the size of the uncompressed output with
+ * no output written. For this dest must be (uint8_t *)0. In this case,
+ * the input value of *destlen is ignored, and on return *destlen is set to the
+ * size of the uncompressed output.
+ *
+ * The return codes are:
+ *
+ * 2: available inflate data did not terminate
+ * 1: output space exhausted before completing inflate
+ * 0: successful inflate
+ * -1: invalid block type (type == 3)
+ * -2: stored block length did not match one's complement
+ * -3: dynamic block code description: too many length or distance codes
+ * -4: dynamic block code description: code lengths codes incomplete
+ * -5: dynamic block code description: repeat lengths with no first length
+ * -6: dynamic block code description: repeat more than specified lengths
+ * -7: dynamic block code description: invalid literal/length code lengths
+ * -8: dynamic block code description: invalid distance code lengths
+ * -9: invalid literal/length or distance code in fixed or dynamic block
+ * -10: distance is too far back in fixed or dynamic block
+ *
+ * Format notes:
+ *
+ * - Three bits are read for each block to determine the kind of block and
+ * whether or not it is the last block. Then the block is decoded and the
+ * process repeated if it was not the last block.
+ *
+ * - The leftover bits in the last byte of the deflate data after the last
+ * block (if it was a fixed or dynamic block) are undefined and have no
+ * expected values to check.
+ */
+int32_t puff(uint8_t *dest, /* pointer to destination pointer */
+ uint32_t *destlen, /* amount of output space */
+ uint8_t *source, /* pointer to source data pointer */
+ uint32_t *sourcelen) /* amount of input available */
+{
+ struct state s; /* input/output state */
+ int32_t last, type; /* block information */
+ int32_t err; /* return value */
+
+ /* initialize output state */
+ s.out = dest;
+ s.outlen = *destlen; /* ignored if dest is NULL */
+ s.outcnt = 0;
+
+ /* initialize input state */
+ s.in = source;
+ s.inlen = *sourcelen;
+ s.incnt = 0;
+ s.bitbuf = 0;
+ s.bitcnt = 0;
+
+ /* return if bits() or decode() tries to read past available input */
+ if (setjmp(s.env) != 0) /* if came back here via longjmp() */
+ err = 2; /* then skip do-loop, return error */
+ else {
+ /* process blocks until last block or error */
+ do {
+ last = bits(&s, 1); /* one if last block */
+ type = bits(&s, 2); /* block type 0..3 */
+ err = type == 0 ? stored(&s) :
+ (type == 1 ? fixed(&s) :
+ (type == 2 ? dynamic(&s) :
+ -1)); /* type == 3, invalid */
+ if (err != 0) break; /* return with error */
+ } while (!last);
+ }
+
+ /* update the lengths and return */
+ if (err <= 0) {
+ *destlen = s.outcnt;
+ *sourcelen = s.incnt;
+ }
+ return err;
+}
diff --git a/src/qcommon/puff.h b/src/qcommon/puff.h
new file mode 100644
index 0000000..14070f6
--- /dev/null
+++ b/src/qcommon/puff.h
@@ -0,0 +1,43 @@
+/*
+ * This is a modified version of Mark Adlers work,
+ * see below for the original copyright.
+ * 2006 - Joerg Dietrich <dietrich_joerg@gmx.de>
+ */
+
+/* puff.h
+ Copyright (C) 2002, 2003 Mark Adler, all rights reserved
+ version 1.7, 3 Mar 2002
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author 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.
+
+ Mark Adler madler@alumni.caltech.edu
+ */
+
+#ifndef __PUFF_H
+#define __PUFF_H
+
+#include "q_shared.h" /* for definitions of the <stdint.h> types */
+
+/*
+ * See puff.c for purpose and usage.
+ */
+int32_t puff(uint8_t *dest, /* pointer to destination pointer */
+ uint32_t *destlen, /* amount of output space */
+ uint8_t *source, /* pointer to source data pointer */
+ uint32_t *sourcelen); /* amount of input available */
+
+#endif // __PUFF_H
diff --git a/src/qcommon/q3_lauxlib.cpp b/src/qcommon/q3_lauxlib.cpp
new file mode 100644
index 0000000..ee7efa2
--- /dev/null
+++ b/src/qcommon/q3_lauxlib.cpp
@@ -0,0 +1,46 @@
+#include "q3_lauxlib.h"
+
+#include <sys/types.h>
+
+#include <cstdarg>
+#include <iostream>
+
+#include "sys/sys_shared.h"
+
+#include "cvar.h"
+#include "msg.h"
+#include "net.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+size_t qlua_writestring(const char* string, size_t n)
+{
+#ifndef DEDICATED
+ CL_ConsolePrint( string );
+#endif
+ Q_StripIndentMarker( const_cast<char*>(string) );
+ Sys_Print( string );
+
+ return n;
+}
+
+int qlua_writeline(void)
+{
+#ifndef DEDICATED
+ CL_ConsolePrint( "\n" );
+#endif
+ Sys_Print( "\n" );
+ return 0;
+}
+
+int qlua_writestringerror(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ char m[MAXPRINTMSG];
+ Q_vsnprintf(m, sizeof(m), fmt, ap);
+ va_end (ap);
+ Com_Printf(S_COLOR_YELLOW "%s\n", m);
+ return 0;
+}
+
diff --git a/src/qcommon/q3_lauxlib.h b/src/qcommon/q3_lauxlib.h
new file mode 100644
index 0000000..caba8e4
--- /dev/null
+++ b/src/qcommon/q3_lauxlib.h
@@ -0,0 +1,46 @@
+// This file is part of Tremulous.
+// Copyright © 2016 Victor Roemer (blowfish) <victor@badsec.org>
+// Copyright (C) 2015-2019 GrangerHub
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+#ifndef OVERRIDE_LAUXLIB_H
+#define OVERRIDE_LAUXLIB_H
+
+#include <stdarg.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+size_t qlua_writestring(const char* string, size_t n);
+int qlua_writeline(void);
+int qlua_writestringerror(const char *fmt, ...);
+
+#define lua_writestring qlua_writestring
+#define lua_writeline qlua_writeline
+#define lua_writestringerror qlua_writestringerror
+
+#define LUA_TMPNAMTEMPLATE "/tmp/tremulous_XXXXXX"
+
+// Because: src/lua-5.3.3/include/luaconf.h:69:9: warning: 'LUA_USE_POSIX' macro redefined [-Wmacro-redefined]
+//#ifndef _WIN32
+//#define LUA_USE_POSIX 1
+//#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/qcommon/q_math.c b/src/qcommon/q_math.c
index 2a641a9..9944850 100644
--- a/src/qcommon/q_math.c
+++ b/src/qcommon/q_math.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
//
@@ -36,133 +37,28 @@ vec3_t vec3_origin = {0,0,0};
vec3_t axisDefault[3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
-vec4_t colorBlack = {0.000f, 0.000f, 0.000f, 1.000f};
-vec4_t colorRed = {1.000f, 0.000f, 0.000f, 1.000f};
-vec4_t colorGreen = {0.000f, 1.000f, 0.000f, 1.000f};
-vec4_t colorBlue = {0.000f, 0.000f, 1.000f, 1.000f};
-vec4_t colorYellow = {1.000f, 1.000f, 0.000f, 1.000f};
-vec4_t colorMagenta = {1.000f, 0.000f, 1.000f, 1.000f};
-vec4_t colorCyan = {0.000f, 1.000f, 1.000f, 1.000f};
-vec4_t colorWhite = {1.000f, 1.000f, 1.000f, 1.000f};
-vec4_t colorGray = {0.502f, 0.502f, 0.502f, 1.000f};
-vec4_t colorOrange = {1.000f, 0.686f, 0.000f, 1.000f};
-vec4_t colorRoseBud = {0.996f, 0.671f, 0.604f, 1.000f};
-vec4_t colorPaleGreen = {0.596f, 0.984f, 0.596f, 1.000f};
-vec4_t colorPaleGolden = {0.933f, 0.910f, 0.667f, 1.000f};
-vec4_t colorColumbiaBlue = {0.608f, 0.867f, 1.000f, 1.000f};
-vec4_t colorPaleTurquoise = {0.686f, 0.933f, 0.933f, 1.000f};
-vec4_t colorPaleVioletRed = {0.859f, 0.439f, 0.576f, 1.000f};
-vec4_t colorPalacePaleWhite = {0.910f, 0.898f, 0.863f, 1.000f};
-vec4_t colorOlive = {0.231f, 0.235f, 0.212f, 1.000f};
-vec4_t colorTomato = {1.000f, 0.388f, 0.278f, 1.000f};
-vec4_t colorLime = {0.749f, 1.000f, 0.000f, 1.000f};
-vec4_t colorLemon = {1.000f, 0.969f, 0.000f, 1.000f};
-vec4_t colorBlueBerry = {0.310f, 0.525f, 0.969f, 1.000f};
-vec4_t colorTurquoise = {0.251f, 0.878f, 0.816f, 1.000f};
-vec4_t colorWildWatermelon = {0.992f, 0.357f, 0.471f, 1.000f};
-vec4_t colorSaltpan = {0.933f, 0.953f, 0.898f, 1.000f};
-vec4_t colorGrayChateau = {0.624f, 0.639f, 0.655f, 1.000f};
-vec4_t colorRust = {0.718f, 0.255f, 0.055f, 1.000f};
-vec4_t colorCopperGreen = {0.431f, 0.553f, 0.443f, 1.000f};
-vec4_t colorGold = {1.000f, 0.843f, 0.000f, 1.000f};
-vec4_t colorSteelBlue = {0.275f, 0.510f, 0.706f, 1.000f};
-vec4_t colorSteelGray = {0.482f, 0.565f, 0.584f, 1.000f};
-vec4_t colorBronze = {0.804f, 0.498f, 0.196f, 1.000f};
-vec4_t colorSilver = {0.753f, 0.753f, 0.753f, 1.000f};
-vec4_t colorDarkGray = {0.663f, 0.663f, 0.663f, 1.000f};
-vec4_t colorDarkOrange = {1.000f, 0.549f, 0.000f, 1.000f};
-vec4_t colorDarkGreen = {0.000f, 0.392f, 0.000f, 1.000f};
-vec4_t colorRedOrange = {1.000f, 0.247f, 0.204f, 1.000f};
-vec4_t colorForestGreen = {0.133f, 0.545f, 0.133f, 1.000f};
-vec4_t colorBrightSun = {0.926f, 0.741f, 0.173f, 1.000f};
-vec4_t colorMediumSlateBlue = {0.482f, 0.408f, 0.933f, 1.000f};
-vec4_t colorCeleste = {0.698f, 1.000f, 1.000f, 1.000f};
-vec4_t colorIronstone = {0.525f, 0.314f, 0.251f, 1.000f};
-vec4_t colorTimberwolf = {0.859f, 0.843f, 0.824f, 1.000f};
-vec4_t colorOnyx = {0.059f, 0.059f, 0.059f, 1.000f};
-vec4_t colorRosewood = {0.396f, 0.000f, 0.043f, 1.000f};
-vec4_t colorKokoda = {0.482f, 0.471f, 0.353f, 1.000f};
-vec4_t colorPorsche = {0.875f, 0.616f, 0.357f, 1.000f};
-vec4_t colorCloudBurst = {0.208f, 0.369f, 0.310f, 1.000f};
-vec4_t colorBlueDiane = {0.208f, 0.318f, 0.310f, 1.000f};
-vec4_t colorRope = {0.557f, 0.349f, 0.235f, 1.000f};
-vec4_t colorBlonde = {0.980f, 0.941f, 0.745f, 1.000f};
-vec4_t colorSmokeyBlack = {0.063f, 0.047f, 0.031f, 1.000f};
-vec4_t colorAmericanRose = {1.000f, 0.012f, 0.243f, 1.000f};
-vec4_t colorNeonGreen = {0.224f, 1.000f, 0.078f, 1.000f};
-vec4_t colorNeonYellow = {0.980f, 0.929f, 0.153f, 1.000f};
-vec4_t colorUltramarine = {0.071f, 0.039f, 0.561f, 1.000f};
-vec4_t colorTurquoiseBlue = {0.000f, 1.000f, 0.937f, 1.000f};
-vec4_t colorDarkMagenta = {0.545f, 0.000f, 0.545f, 1.000f};
-vec4_t colorMagicMint = {0.667f, 0.941f, 0.820f, 1.000f};
-vec4_t colorLightGray = {0.827f, 0.827f, 0.827f, 1.000f};
-vec4_t colorLightSalmon = {1.000f, 0.600f, 0.600f, 1.000f};
-vec4_t colorLightGreen = {0.565f, 0.933f, 0.565f, 1.000f};
-
-vec4_t g_color_table[62] =
+vec4_t colorBlack = {0, 0, 0, 1};
+vec4_t colorRed = {1, 0, 0, 1};
+vec4_t colorGreen = {0, 1, 0, 1};
+vec4_t colorBlue = {0, 0, 1, 1};
+vec4_t colorYellow = {1, 1, 0, 1};
+vec4_t colorMagenta= {1, 0, 1, 1};
+vec4_t colorCyan = {0, 1, 1, 1};
+vec4_t colorWhite = {1, 1, 1, 1};
+vec4_t colorLtGrey = {0.75, 0.75, 0.75, 1};
+vec4_t colorMdGrey = {0.5, 0.5, 0.5, 1};
+vec4_t colorDkGrey = {0.25, 0.25, 0.25, 1};
+
+vec4_t g_color_table[8] =
{
- {0.250f, 0.250f, 0.250f, 1.000f},
- {1.000f, 0.000f, 0.000f, 1.000f},
- {0.000f, 1.000f, 0.000f, 1.000f},
- {1.000f, 1.000f, 0.000f, 1.000f},
- {0.000f, 0.000f, 1.000f, 1.000f},
- {0.000f, 1.000f, 1.000f, 1.000f},
- {1.000f, 0.000f, 1.000f, 1.000f},
- {1.000f, 1.000f, 1.000f, 1.000f},
- {0.502f, 0.502f, 0.502f, 1.000f},
- {1.000f, 0.686f, 0.000f, 1.000f},
- {0.996f, 0.671f, 0.604f, 1.000f},
- {0.596f, 0.984f, 0.596f, 1.000f},
- {0.933f, 0.910f, 0.667f, 1.000f},
- {0.608f, 0.867f, 1.000f, 1.000f},
- {0.686f, 0.933f, 0.933f, 1.000f},
- {0.859f, 0.439f, 0.576f, 1.000f},
- {0.910f, 0.898f, 0.863f, 1.000f},
- {0.231f, 0.235f, 0.212f, 1.000f},
- {1.000f, 0.388f, 0.278f, 1.000f},
- {0.749f, 1.000f, 0.000f, 1.000f},
- {1.000f, 0.969f, 0.000f, 1.000f},
- {0.310f, 0.525f, 0.969f, 1.000f},
- {0.251f, 0.878f, 0.816f, 1.000f},
- {0.992f, 0.357f, 0.471f, 1.000f},
- {0.933f, 0.953f, 0.898f, 1.000f},
- {0.624f, 0.639f, 0.655f, 1.000f},
- {0.718f, 0.255f, 0.055f, 1.000f},
- {0.431f, 0.553f, 0.443f, 1.000f},
- {1.000f, 0.843f, 0.000f, 1.000f},
- {0.275f, 0.510f, 0.706f, 1.000f},
- {0.482f, 0.565f, 0.584f, 1.000f},
- {0.804f, 0.498f, 0.196f, 1.000f},
- {0.753f, 0.753f, 0.753f, 1.000f},
- {0.663f, 0.663f, 0.663f, 1.000f},
- {1.000f, 0.549f, 0.000f, 1.000f},
- {0.000f, 0.392f, 0.000f, 1.000f},
- {1.000f, 0.247f, 0.204f, 1.000f},
- {0.133f, 0.545f, 0.133f, 1.000f},
- {0.926f, 0.741f, 0.173f, 1.000f},
- {0.482f, 0.408f, 0.933f, 1.000f},
- {0.698f, 1.000f, 1.000f, 1.000f},
- {0.525f, 0.314f, 0.251f, 1.000f},
- {0.859f, 0.843f, 0.824f, 1.000f},
- {0.059f, 0.059f, 0.059f, 1.000f},
- {0.396f, 0.000f, 0.043f, 1.000f},
- {0.482f, 0.471f, 0.353f, 1.000f},
- {0.875f, 0.616f, 0.357f, 1.000f},
- {0.208f, 0.369f, 0.310f, 1.000f},
- {0.208f, 0.318f, 0.310f, 1.000f},
- {0.557f, 0.349f, 0.235f, 1.000f},
- {0.980f, 0.941f, 0.745f, 1.000f},
- {0.063f, 0.047f, 0.031f, 1.000f},
- {1.000f, 0.012f, 0.243f, 1.000f},
- {0.224f, 1.000f, 0.078f, 1.000f},
- {0.980f, 0.929f, 0.153f, 1.000f},
- {0.071f, 0.039f, 0.561f, 1.000f},
- {0.000f, 1.000f, 0.937f, 1.000f},
- {0.545f, 0.000f, 0.545f, 1.000f},
- {0.667f, 0.941f, 0.820f, 1.000f},
- {0.827f, 0.827f, 0.827f, 1.000f},
- {1.000f, 0.600f, 0.600f, 1.000f},
- {0.565f, 0.933f, 0.565f, 1.000f},
+ {0.2, 0.2, 0.2, 1.0},
+ {1.0, 0.0, 0.0, 1.0},
+ {0.0, 1.0, 0.0, 1.0},
+ {1.0, 1.0, 0.0, 1.0},
+ {0.0, 0.0, 1.0, 1.0},
+ {0.0, 1.0, 1.0, 1.0},
+ {1.0, 0.0, 1.0, 1.0},
+ {1.0, 1.0, 1.0, 1.0},
};
@@ -601,7 +497,7 @@ void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
inv_denom = 1.0f / DotProduct( normal, normal );
#ifndef Q3_VM
- assert( Q_fabs(inv_denom) != 0.0f ); // bk010122 - zero vectors get here
+ assert( Q_fabs(inv_denom) != 0.0f ); // zero vectors get here
#endif
inv_denom = 1.0f / inv_denom;
@@ -655,10 +551,7 @@ void VectorRotate( vec3_t in, vec3_t matrix[3], vec3_t out )
*/
float Q_rsqrt( float number )
{
- union {
- float f;
- int i;
- } t;
+ floatint_t t;
float x2, y;
const float threehalfs = 1.5F;
@@ -669,14 +562,14 @@ float Q_rsqrt( float number )
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
- //assert( !isnan(y) ); // bk010122 - FPE?
return y;
}
float Q_fabs( float f ) {
- int tmp = * ( int * ) &f;
- tmp &= 0x7FFFFFFF;
- return * ( float * ) &tmp;
+ floatint_t fi;
+ fi.f = f;
+ fi.i &= 0x7FFFFFFF;
+ return fi.f;
}
#endif
@@ -804,50 +697,14 @@ void SetPlaneSignbits (cplane_t *out) {
BoxOnPlaneSide
Returns 1, 2, or 1 + 2
-
-// this is the slow, general version
-int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
-{
- int i;
- float dist1, dist2;
- int sides;
- vec3_t corners[2];
-
- for (i=0 ; i<3 ; i++)
- {
- if (p->normal[i] < 0)
- {
- corners[0][i] = emins[i];
- corners[1][i] = emaxs[i];
- }
- else
- {
- corners[1][i] = emins[i];
- corners[0][i] = emaxs[i];
- }
- }
- dist1 = DotProduct (p->normal, corners[0]) - p->dist;
- dist2 = DotProduct (p->normal, corners[1]) - p->dist;
- sides = 0;
- if (dist1 >= 0)
- sides = 1;
- if (dist2 < 0)
- sides |= 2;
-
- return sides;
-}
-
==================
*/
-
-#if !id386
-
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, struct cplane_s *p)
{
- float dist1, dist2;
- int sides;
+ float dist[2];
+ int sides, b, i;
-// fast axial cases
+ // fast axial cases
if (p->type < 3)
{
if (p->dist <= emins[p->type])
@@ -857,291 +714,27 @@ int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
return 3;
}
-// general case
- switch (p->signbits)
+ // general case
+ dist[0] = dist[1] = 0;
+ if (p->signbits < 8) // >= 8: default case is original code (dist[0]=dist[1]=0)
{
- case 0:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- break;
- case 1:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- break;
- case 2:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- break;
- case 3:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- break;
- case 4:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- break;
- case 5:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- break;
- case 6:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- break;
- case 7:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- break;
- default:
- dist1 = dist2 = 0; // shut up compiler
- break;
+ for (i=0 ; i<3 ; i++)
+ {
+ b = (p->signbits >> i) & 1;
+ dist[ b] += p->normal[i]*emaxs[i];
+ dist[!b] += p->normal[i]*emins[i];
+ }
}
sides = 0;
- if (dist1 >= p->dist)
+ if (dist[0] >= p->dist)
sides = 1;
- if (dist2 < p->dist)
+ if (dist[1] < p->dist)
sides |= 2;
return sides;
}
-#elif __GNUC__
-// use matha.s
-#else
-#pragma warning( disable: 4035 )
-
-__declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
-{
- static int bops_initialized;
- static int Ljmptab[8];
-
- __asm {
-
- push ebx
-
- cmp bops_initialized, 1
- je initialized
- mov bops_initialized, 1
-
- mov Ljmptab[0*4], offset Lcase0
- mov Ljmptab[1*4], offset Lcase1
- mov Ljmptab[2*4], offset Lcase2
- mov Ljmptab[3*4], offset Lcase3
- mov Ljmptab[4*4], offset Lcase4
- mov Ljmptab[5*4], offset Lcase5
- mov Ljmptab[6*4], offset Lcase6
- mov Ljmptab[7*4], offset Lcase7
-
-initialized:
-
- mov edx,dword ptr[4+12+esp]
- mov ecx,dword ptr[4+4+esp]
- xor eax,eax
- mov ebx,dword ptr[4+8+esp]
- mov al,byte ptr[17+edx]
- cmp al,8
- jge Lerror
- fld dword ptr[0+edx]
- fld st(0)
- jmp dword ptr[Ljmptab+eax*4]
-Lcase0:
- fmul dword ptr[ebx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ebx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ebx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ecx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase1:
- fmul dword ptr[ecx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ebx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ebx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ecx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase2:
- fmul dword ptr[ebx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ecx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ebx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ecx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase3:
- fmul dword ptr[ecx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ecx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ebx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ecx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase4:
- fmul dword ptr[ebx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ebx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ecx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ebx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase5:
- fmul dword ptr[ecx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ebx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ecx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ebx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase6:
- fmul dword ptr[ebx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ecx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ecx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ebx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase7:
- fmul dword ptr[ecx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ecx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ecx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ebx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
-LSetSides:
- faddp st(2),st(0)
- fcomp dword ptr[12+edx]
- xor ecx,ecx
- fnstsw ax
- fcomp dword ptr[12+edx]
- and ah,1
- xor ah,1
- add cl,ah
- fnstsw ax
- and ah,1
- add ah,ah
- add cl,ah
- pop ebx
- mov eax,ecx
- ret
-Lerror:
- int 3
- }
-}
-#pragma warning( default: 4035 )
-#endif
/*
=================
@@ -1191,16 +784,64 @@ void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs ) {
}
}
+qboolean BoundsIntersect(const vec3_t mins, const vec3_t maxs,
+ const vec3_t mins2, const vec3_t maxs2)
+{
+ if ( maxs[0] < mins2[0] ||
+ maxs[1] < mins2[1] ||
+ maxs[2] < mins2[2] ||
+ mins[0] > maxs2[0] ||
+ mins[1] > maxs2[1] ||
+ mins[2] > maxs2[2])
+ {
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+qboolean BoundsIntersectSphere(const vec3_t mins, const vec3_t maxs,
+ const vec3_t origin, vec_t radius)
+{
+ if ( origin[0] - radius > maxs[0] ||
+ origin[0] + radius < mins[0] ||
+ origin[1] - radius > maxs[1] ||
+ origin[1] + radius < mins[1] ||
+ origin[2] - radius > maxs[2] ||
+ origin[2] + radius < mins[2])
+ {
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+qboolean BoundsIntersectPoint(const vec3_t mins, const vec3_t maxs,
+ const vec3_t origin)
+{
+ if ( origin[0] > maxs[0] ||
+ origin[0] < mins[0] ||
+ origin[1] > maxs[1] ||
+ origin[1] < mins[1] ||
+ origin[2] > maxs[2] ||
+ origin[2] < mins[2])
+ {
+ return qfalse;
+ }
+
+ return qtrue;
+}
vec_t VectorNormalize( vec3_t v ) {
- // NOTE: TTimo - Apple G4 altivec source uses double?
float length, ilength;
length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- length = sqrt (length);
if ( length ) {
- ilength = 1/length;
+ /* writing it this way allows gcc to recognize that rsqrt can be used */
+ ilength = 1/(float)sqrt (length);
+ /* sqrt(length) = length * (1 / sqrt(length)) */
+ length *= ilength;
v[0] *= ilength;
v[1] *= ilength;
v[2] *= ilength;
@@ -1213,21 +854,17 @@ vec_t VectorNormalize2( const vec3_t v, vec3_t out) {
float length, ilength;
length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- length = sqrt (length);
if (length)
{
-#ifndef Q3_VM // bk0101022 - FPE related
-// assert( ((Q_fabs(v[0])!=0.0f) || (Q_fabs(v[1])!=0.0f) || (Q_fabs(v[2])!=0.0f)) );
-#endif
- ilength = 1/length;
+ /* writing it this way allows gcc to recognize that rsqrt can be used */
+ ilength = 1/(float)sqrt (length);
+ /* sqrt(length) = length * (1 / sqrt(length)) */
+ length *= ilength;
out[0] = v[0]*ilength;
out[1] = v[1]*ilength;
out[2] = v[2]*ilength;
} else {
-#ifndef Q3_VM // bk0101022 - FPE related
-// assert( ((Q_fabs(v[0])==0.0f) && (Q_fabs(v[1])==0.0f) && (Q_fabs(v[2])==0.0f)) );
-#endif
VectorClear( out );
}
@@ -1653,15 +1290,40 @@ Don't pass doubles to this
*/
int Q_isnan( float x )
{
- union
- {
- float f;
- unsigned int i;
- } t;
+ floatint_t fi;
+
+ fi.f = x;
+ fi.ui &= 0x7FFFFFFF;
+ fi.ui = 0x7F800000 - fi.ui;
+
+ return (int)( (unsigned int)fi.ui >> 31 );
+}
+//------------------------------------------------------------------------
+
+#ifndef Q3_VM
+/*
+=====================
+Q_acos
- t.f = x;
- t.i &= 0x7FFFFFFF;
- t.i = 0x7F800000 - t.i;
+the msvc acos doesn't always return a value between -PI and PI:
- return (int)( (unsigned int)t.i >> 31 );
+int i;
+i = 1065353246;
+acos(*(float*) &i) == -1.#IND0
+
+=====================
+*/
+float Q_acos(float c) {
+ float angle;
+
+ angle = acos(c);
+
+ if (angle > M_PI) {
+ return (float)M_PI;
+ }
+ if (angle < -M_PI) {
+ return (float)M_PI;
+ }
+ return angle;
}
+#endif
diff --git a/src/qcommon/q_platform.h b/src/qcommon/q_platform.h
index 84b87b9..b72d285 100644
--- a/src/qcommon/q_platform.h
+++ b/src/qcommon/q_platform.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,20 +17,27 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
-//
+
#ifndef __Q_PLATFORM_H
#define __Q_PLATFORM_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
// this is for determining if we have an asm version of a C function
+#define idx64 0
+
#ifdef Q3_VM
#define id386 0
#define idppc 0
#define idppc_altivec 0
+#define idsparc 0
#else
@@ -59,12 +67,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define idppc_altivec 0
#endif
+#if defined(__sparc__) && !defined(C_ONLY)
+#define idsparc 1
+#else
+#define idsparc 0
+#endif
+
#endif
#ifndef __ASM_I386__ // don't include the C bits if included from qasm.h
// for windows fastcall option
#define QDECL
+#define QCALL
//================================================================= WIN64/32 ===
@@ -101,7 +116,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// For cl_updates.cpp
#define RELEASE_PACKAGE_NAME ( "release-mingw32-" ARCH_STRING ".zip" )
-
+ #define RELEASE_SIGNATURE_NAME ( "release-mingw32-" ARCH_STRING ".zip.sig" )
+ #define GRANGER_EXE ( "granger" EXE_EXT )
+
#elif defined(_WIN32) || defined(__WIN32__)
#undef QDECL
@@ -132,7 +149,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// For cl_updates.cpp
#define RELEASE_PACKAGE_NAME ( "release-mingw32-" ARCH_STRING ".zip" )
-
+ #define RELEASE_SIGNATURE_NAME ( "release-mingw32-" ARCH_STRING ".zip.sig" )
+ #define GRANGER_EXE ( "granger" EXE_EXT )
+
#endif
@@ -162,7 +181,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// For cl_updates.cpp
#define RELEASE_PACKAGE_NAME ( "release-darwin-" ARCH_STRING ".zip" )
-
+ #define RELEASE_SIGNATURE_NAME ( "release-darwin-" ARCH_STRING ".zip.sig" )
+ #define GRANGER_EXE ( "granger" EXE_EXT )
+
#endif
//================================================================= LINUX ===
@@ -194,6 +215,23 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# define Q3_LITTLE_ENDIAN
#undef idx64
#define idx64 1
+ #elif defined __arm__
+ # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ # error "Big endian ARM is not supported"
+ # endif
+ # if defined __armhf__
+ # define ARCH_STRING "armhf"
+ # define Q3_LITTLE_ENDIAN
+ # else
+ # define ARCH_STRING "armel"
+ # define Q3_LITTLE_ENDIAN
+ # endif
+ #elif defined __aarch64__
+ # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ # error "Big endian ARM is not supported"
+ # endif
+ # define ARCH_STRING "aarch64"
+ # define Q3_LITTLE_ENDIAN
#endif
#define DLL_EXT ".so"
@@ -201,6 +239,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// For cl_updates.cpp
#define RELEASE_PACKAGE_NAME ( "release-linux-" ARCH_STRING ".zip" )
+ #define RELEASE_SIGNATURE_NAME ( "release-linux-" ARCH_STRING ".zip.sig" )
+ #define GRANGER_EXE ( "granger" EXE_EXT )
#endif
@@ -336,51 +376,63 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//endianness
+void CopyShortSwap (void *dest, void *src);
+void CopyLongSwap (void *dest, void *src);
short ShortSwap (short l);
int LongSwap (int l);
float FloatSwap (const float *f);
#if defined( Q3_BIG_ENDIAN ) && defined( Q3_LITTLE_ENDIAN )
-#error "Endianness defined as both big and little"
+ #error "Endianness defined as both big and little"
#elif defined( Q3_BIG_ENDIAN )
-#define LittleShort(x) ShortSwap(x)
-#define LittleLong(x) LongSwap(x)
-#define LittleFloat(x) FloatSwap(&x)
-#define BigShort
-#define BigLong
-#define BigFloat
+ #define CopyLittleShort(dest, src) CopyShortSwap(dest, src)
+ #define CopyLittleLong(dest, src) CopyLongSwap(dest, src)
+ #define LittleShort(x) ShortSwap(x)
+ #define LittleLong(x) LongSwap(x)
+ #define LittleFloat(x) FloatSwap(&x)
+ #define BigShort
+ #define BigLong
+ #define BigFloat
#elif defined( Q3_LITTLE_ENDIAN )
-#define LittleShort
-#define LittleLong
-#define LittleFloat
-#define BigShort(x) ShortSwap(x)
-#define BigLong(x) LongSwap(x)
-#define BigFloat(x) FloatSwap(&x)
+ #define CopyLittleShort(dest, src) memcpy(dest, src, 2)
+ #define CopyLittleLong(dest, src) memcpy(dest, src, 4)
+ #define LittleShort
+ #define LittleLong
+ #define LittleFloat
+ #define BigShort(x) ShortSwap(x)
+ #define BigLong(x) LongSwap(x)
+ #define BigFloat(x) FloatSwap(&x)
#elif defined( Q3_VM )
-#define LittleShort
-#define LittleLong
-#define LittleFloat
-#define BigShort
-#define BigLong
-#define BigFloat
+ #define LittleShort
+ #define LittleLong
+ #define LittleFloat
+ #define BigShort
+ #define BigLong
+ #define BigFloat
#else
-#error "Endianness not defined"
+
+ #error "Endianness not defined"
+
#endif
//platform string
#ifdef NDEBUG
-#define PLATFORM_STRING OS_STRING "-" ARCH_STRING
+ #define PLATFORM_STRING OS_STRING "-" ARCH_STRING
#else
-#define PLATFORM_STRING OS_STRING "-" ARCH_STRING "-debug"
+ #define PLATFORM_STRING OS_STRING "-" ARCH_STRING "-debug"
+#endif
+
#endif
+#ifdef __cplusplus
+}
#endif
#endif
diff --git a/src/qcommon/q_shared.c b/src/qcommon/q_shared.c
index 2ac5537..938a7e5 100644
--- a/src/qcommon/q_shared.c
+++ b/src/qcommon/q_shared.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
//
@@ -56,50 +57,77 @@ char *COM_SkipPath (char *pathname)
/*
============
+COM_GetExtension
+============
+*/
+const char *COM_GetExtension( const char *name )
+{
+ const char *dot = strrchr(name, '.'), *slash;
+ if (dot && (!(slash = strrchr(name, '/')) || slash < dot))
+ return dot + 1;
+ else
+ return "";
+}
+
+
+/*
+============
COM_StripExtension
============
*/
-void COM_StripExtension( const char *in, char *out, int destsize ) {
- int length;
+void COM_StripExtension( const char *in, char *out, int destsize )
+{
+ const char *dot = strrchr(in, '.'), *slash;
- Q_strncpyz(out, in, destsize);
+ if (dot && (!(slash = strrchr(in, '/')) || slash < dot))
+ destsize = (destsize < dot-in+1 ? destsize : dot-in+1);
- length = strlen(out)-1;
- while (length > 0 && out[length] != '.')
+ if ( in == out && destsize > 1 )
+ out[destsize-1] = '\0';
+ else
+ Q_strncpyz(out, in, destsize);
+}
+
+/*
+============
+COM_CompareExtension
+
+string compare the end of the strings and return qtrue if strings match
+============
+*/
+qboolean COM_CompareExtension(const char *in, const char *ext)
+{
+ int inlen, extlen;
+
+ inlen = strlen(in);
+ extlen = strlen(ext);
+
+ if(extlen <= inlen)
{
- length--;
- if (out[length] == '/')
- return; // no extension
+ in += inlen - extlen;
+
+ if(!Q_stricmp(in, ext))
+ return qtrue;
}
- if (length)
- out[length] = 0;
+
+ return qfalse;
}
-
/*
==================
COM_DefaultExtension
+
+if path doesn't have an extension, then append
+ the specified one (which should include the .)
==================
*/
-void COM_DefaultExtension (char *path, int maxSize, const char *extension ) {
- char oldPath[MAX_QPATH];
- char *src;
-
-//
-// if path doesn't have a .EXT, append extension
-// (extension should include the .)
-//
- src = path + strlen(path) - 1;
-
- while (*src != '/' && src != path) {
- if ( *src == '.' ) {
- return; // it has an extension
- }
- src--;
- }
-
- Q_strncpyz( oldPath, path, sizeof( oldPath ) );
- Com_sprintf( path, maxSize, "%s%s", oldPath, extension );
+void COM_DefaultExtension( char *path, int maxSize, const char *extension )
+{
+ const char *dot = strrchr(path, '.'), *slash;
+ if (dot && (!(slash = strrchr(path, '/')) || slash < dot))
+ return;
+ else
+ Q_strcat(path, maxSize, extension);
}
/*
@@ -131,6 +159,24 @@ float BigFloat (const float *l) {return _BigFloat(l);}
float LittleFloat (const float *l) {return _LittleFloat(l);}
*/
+void CopyShortSwap(void *dest, void *src)
+{
+ byte *to = dest, *from = src;
+
+ to[0] = from[1];
+ to[1] = from[0];
+}
+
+void CopyLongSwap(void *dest, void *src)
+{
+ byte *to = dest, *from = src;
+
+ to[0] = from[3];
+ to[1] = from[2];
+ to[2] = from[1];
+ to[3] = from[0];
+}
+
short ShortSwap (short l)
{
byte b1,b2;
@@ -158,47 +204,17 @@ int LongSwap (int l)
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
-int LongNoSwap (int l)
-{
- return l;
-}
-
-qint64 Long64Swap (qint64 ll)
-{
- qint64 result;
-
- result.b0 = ll.b7;
- result.b1 = ll.b6;
- result.b2 = ll.b5;
- result.b3 = ll.b4;
- result.b4 = ll.b3;
- result.b5 = ll.b2;
- result.b6 = ll.b1;
- result.b7 = ll.b0;
-
- return result;
-}
-
-qint64 Long64NoSwap (qint64 ll)
+float FloatSwap(const float *f)
{
- return ll;
-}
-
-typedef union {
- float f;
- unsigned int i;
-} _FloatByteUnion;
-
-float FloatSwap (const float *f) {
- _FloatByteUnion out;
+ floatint_t out;
out.f = *f;
- out.i = LongSwap(out.i);
+ out.ui = LongSwap(out.ui);
return out.f;
}
-float FloatNoSwap (const float *f)
+float FloatNoSwap(const float *f)
{
return *f;
}
@@ -251,15 +267,22 @@ PARSING
static char com_token[MAX_TOKEN_CHARS];
static char com_parsename[MAX_TOKEN_CHARS];
static int com_lines;
+static int com_tokenline;
void COM_BeginParseSession( const char *name )
{
- com_lines = 0;
+ com_lines = 1;
+ com_tokenline = 0;
Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name);
}
int COM_GetCurrentParseLine( void )
{
+ if ( com_tokenline )
+ {
+ return com_tokenline;
+ }
+
return com_lines;
}
@@ -274,10 +297,10 @@ void COM_ParseError( char *format, ... )
static char string[4096];
va_start (argptr, format);
- vsprintf (string, format, argptr);
+ Q_vsnprintf (string, sizeof(string), format, argptr);
va_end (argptr);
- Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string);
+ Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, COM_GetCurrentParseLine(), string);
}
void COM_ParseWarning( char *format, ... )
@@ -286,10 +309,10 @@ void COM_ParseWarning( char *format, ... )
static char string[4096];
va_start (argptr, format);
- vsprintf (string, format, argptr);
+ Q_vsnprintf (string, sizeof(string), format, argptr);
va_end (argptr);
- Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string);
+ Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, COM_GetCurrentParseLine(), string);
}
/*
@@ -340,52 +363,53 @@ int COM_Compress( char *data_p ) {
in++;
if ( *in )
in += 2;
- // record when we hit a newline
- } else if ( c == '\n' || c == '\r' ) {
- newline = qtrue;
- in++;
- // record when we hit whitespace
- } else if ( c == ' ' || c == '\t') {
- whitespace = qtrue;
- in++;
- // an actual token
+ // record when we hit a newline
+ } else if ( c == '\n' || c == '\r' ) {
+ newline = qtrue;
+ in++;
+ // record when we hit whitespace
+ } else if ( c == ' ' || c == '\t') {
+ whitespace = qtrue;
+ in++;
+ // an actual token
} else {
- // if we have a pending newline, emit it (and it counts as whitespace)
- if (newline) {
- *out++ = '\n';
- newline = qfalse;
- whitespace = qfalse;
- } if (whitespace) {
- *out++ = ' ';
- whitespace = qfalse;
- }
-
- // copy quoted strings unmolested
- if (c == '"') {
- *out++ = c;
- in++;
- while (1) {
- c = *in;
- if (c && c != '"') {
- *out++ = c;
- in++;
- } else {
- break;
- }
- }
- if (c == '"') {
- *out++ = c;
- in++;
- }
- } else {
- *out = c;
- out++;
- in++;
- }
+ // if we have a pending newline, emit it (and it counts as whitespace)
+ if (newline) {
+ *out++ = '\n';
+ newline = qfalse;
+ whitespace = qfalse;
+ } if (whitespace) {
+ *out++ = ' ';
+ whitespace = qfalse;
+ }
+
+ // copy quoted strings unmolested
+ if (c == '"') {
+ *out++ = c;
+ in++;
+ while (1) {
+ c = *in;
+ if (c && c != '"') {
+ *out++ = c;
+ in++;
+ } else {
+ break;
+ }
+ }
+ if (c == '"') {
+ *out++ = c;
+ in++;
+ }
+ } else {
+ *out = c;
+ out++;
+ in++;
+ }
}
}
+
+ *out = 0;
}
- *out = 0;
return out - data_p;
}
@@ -398,6 +422,7 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
data = *data_p;
len = 0;
com_token[0] = 0;
+ com_tokenline = 0;
// make sure incoming data is valid
if ( !data )
@@ -437,6 +462,10 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
data += 2;
while ( *data && ( *data != '*' || data[1] != '/' ) )
{
+ if ( *data == '\n' )
+ {
+ com_lines++;
+ }
data++;
}
if ( *data )
@@ -450,6 +479,9 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
}
}
+ // token starts on this line
+ com_tokenline = com_lines;
+
// handle quoted strings
if (c == '\"')
{
@@ -463,6 +495,10 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
*data_p = ( char * ) data;
return com_token;
}
+ if ( c == '\n' )
+ {
+ com_lines++;
+ }
if (len < MAX_TOKEN_CHARS - 1)
{
com_token[len] = c;
@@ -481,8 +517,6 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
}
data++;
c = *data;
- if ( c == '\n' )
- com_lines++;
} while (c>32);
com_token[len] = 0;
@@ -491,62 +525,6 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
return com_token;
}
-
-#if 0
-// no longer used
-/*
-===============
-COM_ParseInfos
-===============
-*/
-int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) {
- char *token;
- int count;
- char key[MAX_TOKEN_CHARS];
-
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &buf );
- if ( !token[0] ) {
- break;
- }
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in info file\n" );
- break;
- }
-
- if ( count == max ) {
- Com_Printf( "Max infos exceeded\n" );
- break;
- }
-
- infos[count][0] = 0;
- while ( 1 ) {
- token = COM_ParseExt( &buf, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &buf, qfalse );
- if ( !token[0] ) {
- strcpy( token, "<NULL>" );
- }
- Info_SetValueForKey( infos[count], key, token );
- }
- count++;
- }
-
- return count;
-}
-#endif
-
-
/*
==================
COM_MatchToken
@@ -566,16 +544,14 @@ void COM_MatchToken( char **buf_p, char *match ) {
=================
SkipBracedSection
-The next token should be an open brace.
+The next token should be an open brace or set depth to 1 if already parsed it.
Skips until a matching close brace is found.
Internal brace depths are properly skipped.
=================
*/
-void SkipBracedSection (char **program) {
+qboolean SkipBracedSection (char **program, int depth) {
char *token;
- int depth;
- depth = 0;
do {
token = COM_ParseExt( program, qtrue );
if( token[1] == 0 ) {
@@ -587,6 +563,8 @@ void SkipBracedSection (char **program) {
}
}
} while( depth && *program );
+
+ return ( depth == 0 );
}
/*
@@ -599,6 +577,10 @@ void SkipRestOfLine ( char **data ) {
int c;
p = *data;
+
+ if ( !*p )
+ return;
+
while ( (c = *p++) != 0 ) {
if ( c == '\n' ) {
com_lines++;
@@ -648,6 +630,45 @@ void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m) {
COM_MatchToken( buf_p, ")" );
}
+/*
+===================
+Com_HexStrToInt
+===================
+*/
+int Com_HexStrToInt( const char *str )
+{
+ if ( !str || !str[ 0 ] )
+ return -1;
+
+ // check for hex code
+ if( str[ 0 ] == '0' && str[ 1 ] == 'x' )
+ {
+ size_t i;
+ int n = 0;
+
+ for( i = 2; i < strlen( str ); i++ )
+ {
+ char digit;
+
+ n *= 16;
+
+ digit = tolower( str[ i ] );
+
+ if( digit >= '0' && digit <= '9' )
+ digit -= '0';
+ else if( digit >= 'a' && digit <= 'f' )
+ digit = digit - 'a' + 10;
+ else
+ return -1;
+
+ n += digit;
+ }
+
+ return n;
+ }
+
+ return -1;
+}
/*
============================================================================
@@ -685,32 +706,56 @@ int Q_isalpha( int c )
return ( 0 );
}
-int Q_isdigit( int c )
+qboolean Q_isanumber( const char *s )
{
- if ((c >= '0' && c <= '9'))
- return ( 1 );
- return ( 0 );
+ char *p;
+ double UNUSED_VAR d;
+
+ if( *s == '\0' )
+ return qfalse;
+
+ d = strtod( s, &p );
+
+ return *p == '\0';
}
-char* Q_strrchr( const char* string, int c )
+qboolean Q_isintegral( float f )
{
- char cc = c;
- char *s;
- char *sp=(char *)0;
+ return (int)f == f;
+}
- s = (char*)string;
+#ifdef _MSC_VER
+/*
+=============
+Q_vsnprintf
+
+Special wrapper function for Microsoft's broken _vsnprintf() function.
+MinGW comes with its own snprintf() which is not broken.
+=============
+*/
+
+int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+ int retval;
+
+ retval = _vsnprintf(str, size, format, ap);
- while (*s)
+ if(retval < 0 || retval == size)
{
- if (*s == cc)
- sp = s;
- s++;
+ // Microsoft doesn't adhere to the C99 standard of vsnprintf,
+ // which states that the return value must be the number of
+ // bytes written if the output string had sufficient length.
+ //
+ // Obviously we cannot determine that value from Microsoft's
+ // implementation, so we have no choice but to return size.
+
+ str[size - 1] = '\0';
+ return size;
}
- if (cc == 0)
- sp = s;
-
- return sp;
+
+ return retval;
}
+#endif
/*
=============
@@ -720,7 +765,6 @@ Safe strncpy that ensures a trailing zero
=============
*/
void Q_strncpyz( char *dest, const char *src, int destsize ) {
- // bk001129 - also NULL dest
if ( !dest ) {
Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
}
@@ -738,7 +782,6 @@ void Q_strncpyz( char *dest, const char *src, int destsize ) {
int Q_stricmpn (const char *s1, const char *s2, int n) {
int c1, c2;
- // bk001129 - moved in 1.17 fix not in id codebase
if ( s1 == NULL ) {
if ( s2 == NULL )
return 0;
@@ -832,6 +875,38 @@ void Q_strcat( char *dest, int size, const char *src ) {
Q_strncpyz( dest + l1, src, size - l1 );
}
+/*
+* Find the first occurrence of find in s.
+*/
+const char *Q_stristr( const char *s, const char *find)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != 0)
+ {
+ if (c >= 'a' && c <= 'z')
+ {
+ c -= ('a' - 'A');
+ }
+ len = strlen(find);
+ do
+ {
+ do
+ {
+ if ((sc = *s++) == 0)
+ return NULL;
+ if (sc >= 'a' && sc <= 'z')
+ {
+ sc -= ('a' - 'A');
+ }
+ } while (sc != c);
+ } while (Q_stricmpn(s, find, len) != 0);
+ s--;
+ }
+ return s;
+}
+
int Q_PrintStrlen( const char *string ) {
int len;
@@ -877,29 +952,52 @@ char *Q_CleanStr( char *string ) {
return string;
}
+int Q_CountChar(const char *string, char tocount)
+{
+ int count;
+
+ for(count = 0; *string; string++)
+ {
+ if(*string == tocount)
+ count++;
+ }
+
+ return count;
+}
-void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
+void Q_StripIndentMarker(char *string)
+{
+ int i, j;
+
+ for (i = j = 0; string[i]; i++) {
+ if (string[i] != INDENT_MARKER) {
+ string[j++] = string[i];
+ }
+ }
+ string[j] = 0;
+}
+
+void Q_ParseNewlines( char *dest, const char *src, int destsize )
+{
+ for( ; *src && destsize > 1; src++, destsize-- )
+ *dest++ = ( ( *src == '\\' && *( ++src ) == 'n' ) ? '\n' : *src );
+ *dest++ = '\0';
+}
+
+int QDECL Com_sprintf(char *dest, int size, const char *fmt, ...)
+{
int len;
va_list argptr;
- char bigbuffer[32000]; // big, but small enough to fit in PPC stack
va_start (argptr,fmt);
- len = vsprintf (bigbuffer,fmt,argptr);
+ len = Q_vsnprintf(dest, size, fmt, argptr);
va_end (argptr);
- if ( len >= sizeof( bigbuffer ) ) {
- Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
- }
- if (len >= size) {
- Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
-#ifdef _DEBUG
- __asm {
- int 3;
- }
-#endif
- }
- Q_strncpyz (dest, bigbuffer, size );
-}
+ if(len >= size)
+ Com_Printf("Com_sprintf: Output length %d too short, require %d bytes.\n", size, len + 1);
+
+ return len;
+}
/*
============
@@ -907,20 +1005,19 @@ va
does a varargs printf into a temp buffer, so I don't need to have
varargs versions of all text functions.
-FIXME: make this buffer size safe someday
============
*/
-char * QDECL va( char *format, ... ) {
+const char * QDECL va(const char *format, ... ) {
va_list argptr;
- static char string[2][32000]; // in case va is called by nested functions
- static int index = 0;
- char *buf;
+ static char string[2][32000]; // in case va is called by nested functions
+ static int index = 0;
+ char *buf;
buf = string[index & 1];
index++;
va_start (argptr, format);
- vsprintf (buf, format,argptr);
+ Q_vsnprintf (buf, sizeof(*string), format, argptr);
va_end (argptr);
return buf;
@@ -1100,7 +1197,8 @@ void Info_RemoveKey( char *s, const char *key ) {
if (!strcmp (key, pkey) )
{
- strcpy (start, s); // remove this part
+ memmove(start, s, strlen(s) + 1); // remove this part
+
return;
}
@@ -1155,7 +1253,7 @@ void Info_RemoveKey_Big( char *s, const char *key ) {
if (!strcmp (key, pkey) )
{
- strcpy (start, s); // remove this part
+ memmove(start, s, strlen(s) + 1); // remove this part
return;
}
@@ -1241,6 +1339,7 @@ void Info_SetValueForKey( char *s, const char *key, const char *value ) {
Info_SetValueForKey_Big
Changes or adds a key/value pair
+Includes and retains zero-length values
==================
*/
void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
@@ -1261,14 +1360,15 @@ void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
}
Info_RemoveKey_Big (s, key);
- if (!value || !strlen(value))
+ if (!value)
return;
Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
if (strlen(newi) + strlen(s) >= BIG_INFO_STRING)
{
- Com_Printf ("BIG Info string length exceeded\n");
+ Com_Printf ("BIG Info string length exceeded: setting %s to %s "
+ "failed\n", key, value);
return;
}
@@ -1285,9 +1385,9 @@ void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
Com_CharIsOneOfCharset
==================
*/
-static qboolean Com_CharIsOneOfCharset( char c, char *set )
+static qboolean Com_CharIsOneOfCharset( char c, const char *set )
{
- int i;
+ size_t i;
for( i = 0; i < strlen( set ); i++ )
{
@@ -1303,7 +1403,7 @@ static qboolean Com_CharIsOneOfCharset( char c, char *set )
Com_SkipCharset
==================
*/
-char *Com_SkipCharset( char *s, char *sep )
+char *Com_SkipCharset( char *s, const char *sep )
{
char *p = s;
@@ -1323,7 +1423,7 @@ char *Com_SkipCharset( char *s, char *sep )
Com_SkipTokens
==================
*/
-char *Com_SkipTokens( char *s, int numTokens, char *sep )
+char *Com_SkipTokens( char *s, int numTokens, const char *sep )
{
int sepCount = 0;
char *p = s;
@@ -1345,3 +1445,85 @@ char *Com_SkipTokens( char *s, int numTokens, char *sep )
else
return s;
}
+
+/*
+============
+Com_ClientListContains
+============
+*/
+qboolean Com_ClientListContains( const clientList_t *list, int clientNum )
+{
+ if( clientNum < 0 || clientNum >= MAX_CLIENTS || !list )
+ return qfalse;
+ if( clientNum < 32 )
+ return ( ( list->lo & ( 1 << clientNum ) ) != 0 );
+ else
+ return ( ( list->hi & ( 1 << ( clientNum - 32 ) ) ) != 0 );
+}
+
+/*
+============
+Com_ClientListAdd
+============
+*/
+void Com_ClientListAdd( clientList_t *list, int clientNum )
+{
+ if( clientNum < 0 || clientNum >= MAX_CLIENTS || !list )
+ return;
+ if( clientNum < 32 )
+ list->lo |= ( 1 << clientNum );
+ else
+ list->hi |= ( 1 << ( clientNum - 32 ) );
+}
+
+/*
+============
+Com_ClientListRemove
+============
+*/
+void Com_ClientListRemove( clientList_t *list, int clientNum )
+{
+ if( clientNum < 0 || clientNum >= MAX_CLIENTS || !list )
+ return;
+ if( clientNum < 32 )
+ list->lo &= ~( 1 << clientNum );
+ else
+ list->hi &= ~( 1 << ( clientNum - 32 ) );
+}
+
+/*
+============
+Com_ClientListString
+============
+*/
+char *Com_ClientListString( const clientList_t *list )
+{
+ static char s[ 17 ];
+
+ s[ 0 ] = '\0';
+ if( !list )
+ return s;
+ Com_sprintf( s, sizeof( s ), "%08x%08x", list->hi, list->lo );
+ return s;
+}
+
+/*
+============
+Com_ClientListParse
+============
+*/
+void Com_ClientListParse( clientList_t *list, const char *s )
+{
+ char t[ 9 ];
+ if( !list )
+ return;
+ list->lo = 0;
+ list->hi = 0;
+ if( !s )
+ return;
+ if( strlen( s ) != 16 )
+ return;
+ Q_strncpyz( t, s, 9 );
+ sscanf( t, "%x", &list->hi );
+ sscanf( s + 8, "%x", &list->lo );
+}
diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h
index 06f1bb2..a854de8 100644
--- a/src/qcommon/q_shared.h
+++ b/src/qcommon/q_shared.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,28 +17,42 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
//
#ifndef __Q_SHARED_H
#define __Q_SHARED_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
// q_shared.h -- included first by ALL program modules.
// A user mod should never modify this file
-#define VERSION_NUMBER "1.1.0"
-#define Q3_VERSION "tremulous " VERSION_NUMBER
-#ifndef SVN_VERSION
-#define SVN_VERSION Q3_VERSION
+#define PRODUCT_NAME "tremulous"
+
+#ifndef PRODUCT_VERSION
+# define PRODUCT_VERSION "1.3.0 alpha"
#endif
-#define CLIENT_WINDOW_TITLE "Tremulous " VERSION_NUMBER
-#define CLIENT_WINDOW_ICON "Tremulous"
-#define CONSOLE_WINDOW_TITLE "Tremulous " VERSION_NUMBER " console"
-#define CONSOLE_WINDOW_ICON "Tremulous console"
-#define MAX_TEAMNAME 32
+#define CLIENT_WINDOW_TITLE "Tremulous " PRODUCT_VERSION
+#define CLIENT_WINDOW_MIN_TITLE "Tremulous"
+#define Q3_VERSION PRODUCT_NAME " " PRODUCT_VERSION
+
+#define GAMENAME_FOR_MASTER "Tremulous"
+#define HOMEPATH_NAME_UNIX ".tremulous"
+#define HOMEPATH_NAME_WIN "Tremulous"
+#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
+
+// Heartbeat for dpmaster protocol. You shouldn't change this unless you know what you're doing
+#define HEARTBEAT_FOR_MASTER GAMENAME_FOR_MASTER
+
+#define MAX_MASTER_SERVERS 5 // number of supported master servers
+
+#define DEMOEXT "dm_" // standard demo extension
#ifdef _MSC_VER
@@ -72,6 +87,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif
#endif
+#ifdef __GNUC__
+#define UNUSED_VAR __attribute__((unused))
+#else
+#define UNUSED_VAR
+#endif
+
#if (defined _MSC_VER)
#define Q_EXPORT __declspec(dllexport)
#elif (defined __SUNPRO_C)
@@ -100,7 +121,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifdef Q3_VM
-#include "../game/bg_lib.h"
+#include "game/bg_lib.h"
+
+typedef int intptr_t;
#else
@@ -114,60 +137,136 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <ctype.h>
#include <limits.h>
+#ifdef _MSC_VER
+ #include <io.h>
+
+ typedef __int64 int64_t;
+ typedef __int32 int32_t;
+ typedef __int16 int16_t;
+ typedef __int8 int8_t;
+ typedef unsigned __int64 uint64_t;
+ typedef unsigned __int32 uint32_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int8 uint8_t;
+
+ // vsnprintf is ISO/IEC 9899:1999
+ // abstracting this to make it portable
+ int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap);
+#else
+ #include <stdint.h>
+
+ #define Q_vsnprintf vsnprintf
+ #define Q_snprintf snprintf
#endif
-#include "q_platform.h"
+#endif
-//=============================================================
-#ifdef Q3_VM
- typedef int intptr_t;
-#else
- #ifndef _MSC_VER
- #include <stdint.h>
- #else
- #include <io.h>
- typedef __int64 int64_t;
- typedef __int32 int32_t;
- typedef __int16 int16_t;
- typedef __int8 int8_t;
- typedef unsigned __int64 uint64_t;
- typedef unsigned __int32 uint32_t;
- typedef unsigned __int16 uint16_t;
- typedef unsigned __int8 uint8_t;
- #endif
-#endif
+#include "qcommon/q_platform.h"
+
+//=============================================================
typedef unsigned char byte;
-typedef enum {qfalse, qtrue} qboolean;
+typedef enum {qfalse, qtrue} qboolean;
+
+typedef union {
+ float f;
+ int i;
+ unsigned int ui;
+} floatint_t;
typedef int qhandle_t;
typedef int sfxHandle_t;
typedef int fileHandle_t;
typedef int clipHandle_t;
-#define PAD(x,y) (((x)+(y)-1) & ~((y)-1))
+#define PAD(base, alignment) (((base)+(alignment)-1) & ~((alignment)-1))
+#define PADLEN(base, alignment) (PAD((base), (alignment)) - (base))
+
+#define PADP(base, alignment) ((void *) PAD((intptr_t) (base), (alignment)))
#ifdef __GNUC__
-#define ALIGN(x) __attribute__((aligned(x)))
+#define QALIGN(x) __attribute__((aligned(x)))
#else
-#define ALIGN(x)
+#define QALIGN(x)
#endif
#ifndef NULL
#define NULL ((void *)0)
#endif
+#define STRING(s) #s
+// expand constants before stringifying them
+#define XSTRING(s) STRING(s)
+
#define MAX_QINT 0x7fffffff
#define MIN_QINT (-MAX_QINT-1)
+#define ARRAY_LEN(x) (sizeof(x) / sizeof(*(x)))
+#define STRARRAY_LEN(x) (ARRAY_LEN(x) - 1)
// angle indexes
#define PITCH 0 // up / down
#define YAW 1 // left / right
#define ROLL 2 // fall over
+/* FILESYSTEM */
+enum FS_Mode {
+ FS_READ,
+ FS_WRITE,
+ FS_APPEND,
+ FS_APPEND_SYNC
+};
+
+enum FS_Origin {
+ FS_SEEK_CUR,
+ FS_SEEK_END,
+ FS_SEEK_SET
+};
+
+/* CVAR */
+
+#define CVAR_ARCHIVE 0x0001 // set to cause it to be saved to vars.rc
+// used for system variables, not for player
+// specific configurations
+#define CVAR_USERINFO 0x0002 // sent to server on connect or change
+#define CVAR_SERVERINFO 0x0004 // sent in response to front end requests
+#define CVAR_SYSTEMINFO 0x0008 // these cvars will be duplicated on all clients
+#define CVAR_INIT 0x0010 // don't allow change from console at all,
+// but can be set from the command line
+#define CVAR_LATCH 0x0020 // will only change when C code next does
+// a Cvar_Get(), so it can't be changed without proper initialization.
+// modified will be set, even though the value hasn't changed yet
+#define CVAR_ROM 0x0040 // display only, cannot be set by user at all
+#define CVAR_USER_CREATED 0x0080 // created by a set command
+#define CVAR_TEMP 0x0100 // can be set even when cheats are disabled, but is not archived
+#define CVAR_CHEAT 0x0200 // can not be changed if cheats are disabled
+#define CVAR_NORESTART 0x0400 // do not clear when a cvar_restart is issued
+
+#define CVAR_SERVER_CREATED 0x0800 // cvar was created by a server the client connected to.
+#define CVAR_VM_CREATED 0x1000 // cvar was created exclusively in one of the VMs.
+#define CVAR_PROTECTED 0x2000 // prevent modifying this var from VMs or the server
+#define CVAR_ALTERNATE_SYSTEMINFO 0x1000000
+// These flags are only returned by the Cvar_Flags() function
+#define CVAR_MODIFIED 0x40000000 // Cvar was modified
+#define CVAR_NONEXISTENT 0x80000000 // Cvar doesn't exist.
+
+#define MAX_CVAR_VALUE_STRING 256
+
+typedef int cvarHandle_t;
+
+// the modules that run in the virtual machine can't access the cvar_t directly,
+// so they must ask for structured updates
+typedef struct {
+ cvarHandle_t handle;
+ int modificationCount;
+ float value;
+ int integer;
+ char string[MAX_CVAR_VALUE_STRING];
+} vmCvar_t;
+
+
// the game guarantees that no string from the network will ever
// exceed MAX_STRING_CHARS
#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString
@@ -182,6 +281,7 @@ typedef int clipHandle_t;
#define BIG_INFO_KEY 8192
#define BIG_INFO_VALUE 8192
+#define MAX_NEWS_STRING 10000
#define MAX_QPATH 64 // max length of a quake game pathname
#ifdef PATH_MAX
@@ -193,7 +293,7 @@ typedef int clipHandle_t;
#define MAX_NAME_LENGTH 32 // max length of a client name
#define MAX_HOSTNAME_LENGTH 80 // max length of a host name
-#define MAX_SAY_TEXT 150
+#define MAX_SAY_TEXT 800
// paramters for command buffer stuffing
typedef enum {
@@ -203,7 +303,6 @@ typedef enum {
EXEC_APPEND // add to end of the command buffer (normal case)
} cbufExec_t;
-
//
// these aren't needed by any of the VMs. put in another header?
//
@@ -225,37 +324,20 @@ typedef enum {
// parameters to the main Error routine
typedef enum {
- ERR_FATAL, // exit the entire game with a popup window
- ERR_DROP, // print to console and disconnect from game
- ERR_SERVERDISCONNECT, // don't kill server
- ERR_DISCONNECT, // client disconnected from the server
- ERR_NEED_CD // pop up the need-cd dialog
+ ERR_FATAL, // exit the entire game with a popup window
+ ERR_DROP, // print to console and disconnect from game
+ ERR_SERVERDISCONNECT, // don't kill server
+ ERR_DISCONNECT, // client disconnected from the server
+ ERR_RECONNECT
} errorParm_t;
// font rendering values used by ui and cgame
-
-#define PROP_GAP_WIDTH 3
-#define PROP_SPACE_WIDTH 8
-#define PROP_HEIGHT 27
-#define PROP_SMALL_SIZE_SCALE 0.75
-
+//
#define BLINK_DIVISOR 200
#define PULSE_DIVISOR 75
-#define UI_LEFT 0x00000000 // default
-#define UI_CENTER 0x00000001
-#define UI_RIGHT 0x00000002
-#define UI_FORMATMASK 0x00000007
-#define UI_SMALLFONT 0x00000010
-#define UI_BIGFONT 0x00000020 // default
-#define UI_GIANTFONT 0x00000040
-#define UI_DROPSHADOW 0x00000800
-#define UI_BLINK 0x00001000
-#define UI_INVERSE 0x00002000
-#define UI_PULSE 0x00004000
-
-#if defined(_DEBUG) && !defined(BSPC)
+#if !defined(NDEBUG) && !defined(BSPC)
#define HUNK_DEBUG
#endif
@@ -267,19 +349,11 @@ typedef enum {
#ifdef HUNK_DEBUG
#define Hunk_Alloc( size, preference ) Hunk_AllocDebug(size, preference, #size, __FILE__, __LINE__)
-void *Hunk_AllocDebug( int size, ha_pref preference, char *label, char *file, int line );
+void *Hunk_AllocDebug( int size, ha_pref preference, const char *label, const char *file, int line );
#else
void *Hunk_Alloc( int size, ha_pref preference );
#endif
-#if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__APPLE__)
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
-// custom Snd_Memset implementation for glibc memset bug workaround
-void Snd_Memset (void* dest, const int val, const size_t count);
-#else
-#define Snd_Memset Com_Memset
-#endif
-
#define Com_Memset memset
#define Com_Memcpy memcpy
@@ -304,10 +378,6 @@ typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
typedef vec_t vec5_t[5];
-typedef int fixed4_t;
-typedef int fixed8_t;
-typedef int fixed16_t;
-
#ifndef M_PI
#define M_PI 3.14159265358979323846f // matches value in gcc v2 math.h
#endif
@@ -348,192 +418,37 @@ extern vec4_t colorYellow;
extern vec4_t colorMagenta;
extern vec4_t colorCyan;
extern vec4_t colorWhite;
-extern vec4_t colorGray;
-extern vec4_t colorOrange;
-extern vec4_t colorRoseBud;
-extern vec4_t colorPaleGreen;
-extern vec4_t colorPaleGolden;
-extern vec4_t colorColumbiaBlue;
-extern vec4_t colorPaleTurquoise;
-extern vec4_t colorPaleVioletRed;
-extern vec4_t colorPalacePaleWhite;
-extern vec4_t colorOlive;
-extern vec4_t colorTomato;
-extern vec4_t colorLime;
-extern vec4_t colorLemon;
-extern vec4_t colorBlueBerry;
-extern vec4_t colorTurquoise;
-extern vec4_t colorWildWatermelon;
-extern vec4_t colorSaltpan;
-extern vec4_t colorGrayChateau;
-extern vec4_t colorRust;
-extern vec4_t colorCopperGreen;
-extern vec4_t colorGold;
-extern vec4_t colorSteelBlue;
-extern vec4_t colorSteelGray;
-extern vec4_t colorBronze;
-extern vec4_t colorSilver;
-extern vec4_t colorDarkGray;
-extern vec4_t colorDarkOrange;
-extern vec4_t colorDarkGreen;
-extern vec4_t colorRedOrange;
-extern vec4_t colorForestGreen;
-extern vec4_t colorBrightSun;
-extern vec4_t colorMediumSlateBlue;
-extern vec4_t colorCeleste;
-extern vec4_t colorIronstone;
-extern vec4_t colorTimberwolf;
-extern vec4_t colorOnyx;
-extern vec4_t colorRosewood;
-extern vec4_t colorKokoda;
-extern vec4_t colorPorsche;
-extern vec4_t colorCloudBurst;
-extern vec4_t colorBlueDiane;
-extern vec4_t colorRope;
-extern vec4_t colorBlonde;
-extern vec4_t colorSmokeyBlack;
-extern vec4_t colorAmericanRose;
-extern vec4_t colorNeonGreen;
-extern vec4_t colorNeonYellow;
-extern vec4_t colorUltramarine;
-extern vec4_t colorTurquoiseBlue;
-extern vec4_t colorDarkMagenta;
-extern vec4_t colorMagicMint;
-extern vec4_t colorLightGray;
-extern vec4_t colorLightSalmon;
-extern vec4_t colorLightGreen;
+extern vec4_t colorLtGrey;
+extern vec4_t colorMdGrey;
+extern vec4_t colorDkGrey;
#define Q_COLOR_ESCAPE '^'
-#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE )
+#define Q_IsColorString(p) ((p) && *(p) == Q_COLOR_ESCAPE && *((p)+1) && isalnum(*((p)+1))) // ^[0-9a-zA-Z]
-#define COLOR_BLACK '0'
-#define COLOR_RED '1'
-#define COLOR_GREEN '2'
+#define COLOR_BLACK '0'
+#define COLOR_RED '1'
+#define COLOR_GREEN '2'
#define COLOR_YELLOW '3'
-#define COLOR_BLUE '4'
-#define COLOR_CYAN '5'
+#define COLOR_BLUE '4'
+#define COLOR_CYAN '5'
#define COLOR_MAGENTA '6'
-#define COLOR_WHITE '7'
-#define COLOR_GRAY '8'
-#define COLOR_ORANGE '9'
-#define COLOR_ROSE_BUD 'a'
-#define COLOR_PALE_GREEN 'b'
-#define COLOR_PALE_GOLDEN 'c'
-#define COLOR_COLUMBIA_BLUE 'd'
-#define COLOR_PALE_TURQUOISE 'e'
-#define COLOR_PALE_VIOLET_RED 'f'
-#define COLOR_PALACE_PALE_WHITE 'g'
-#define COLOR_OLIVE 'h'
-#define COLOR_TOMATO 'i'
-#define COLOR_LIME 'j'
-#define COLOR_LEMON 'k'
-#define COLOR_BLUE_BERRY 'l'
-#define COLOR_TURQUOISE 'm'
-#define COLOR_WILD_WATERMELON 'n'
-#define COLOR_SALTPAN 'o'
-#define COLOR_GRAY_CHATEAU 'p'
-#define COLOR_RUST 'q'
-#define COLOR_COPPER_GREEN 'r'
-#define COLOR_GOLD 's'
-#define COLOR_STEEL_BLUE 't'
-#define COLOR_STEEL_GRAY 'u'
-#define COLOR_BRONZE 'v'
-#define COLOR_SILVER 'w'
-#define COLOR_DARK_GRAY 'x'
-#define COLOR_DARK_ORANGE 'y'
-#define COLOR_DARK_GREEN 'z'
-#define COLOR_RED_ORANGE 'A'
-#define COLOR_FOREST_GREEN 'B'
-#define COLOR_BRIGHT_SUN 'C'
-#define COLOR_MEDIUM_SLATE_BLUE 'D'
-#define COLOR_CELESTE 'E'
-#define COLOR_IRONSTONE 'F'
-#define COLOR_TIMBERWOLF 'G'
-#define COLOR_ONYX 'H'
-#define COLOR_ROSEWOOD 'I'
-#define COLOR_KOKODA 'J'
-#define COLOR_PORSCHE 'K'
-#define COLOR_CLOUD_BURST 'L'
-#define COLOR_BLUE_DIANE 'M'
-#define COLOR_ROPE 'N'
-#define COLOR_BLONDE 'O'
-#define COLOR_SMOKEY_BLACK 'P'
-#define COLOR_AMERICAN_ROSE 'Q'
-#define COLOR_NEON_GREEN 'R'
-#define COLOR_NEON_YELLOW 'S'
-#define COLOR_ULTRAMARINE 'T'
-#define COLOR_TURQUOISE_BLUE 'U'
-#define COLOR_DARK_MAGENTA 'V'
-#define COLOR_MAGIC_MINT 'W'
-#define COLOR_LIGHT_GRAY 'X'
-#define COLOR_LIGHT_SALMON 'Y'
-#define COLOR_LIGHT_GREEN 'Z'
-#define ColorIndex(c) (((((c) >= '0') && ((c) <= '9')) ? ((c) - '0') : ((((c) >= 'a') && ((c) <= 'z')) ? ((c) - 'a' + 10) : ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 36) : 7))))
-
-#define S_COLOR_BLACK "^0"
-#define S_COLOR_RED "^1"
-#define S_COLOR_GREEN "^2"
-#define S_COLOR_YELLOW "^3"
-#define S_COLOR_BLUE "^4"
-#define S_COLOR_CYAN "^5"
-#define S_COLOR_MAGENTA "^6"
-#define S_COLOR_WHITE "^7"
-#define S_COLOR_GRAY '^8'
-#define S_COLOR_ORANGE '^9'
-#define S_COLOR_ROSE_BUD '^a'
-#define S_COLOR_PALE_GREEN '^b'
-#define S_COLOR_PALE_GOLDEN '^c'
-#define S_COLOR_COLUMBIA_BLUE '^d'
-#define S_COLOR_PALE_TURQUOISE '^e'
-#define S_COLOR_PALE_VIOLET_RED '^f'
-#define S_COLOR_PALACE_PALE_WHITE '^g'
-#define S_COLOR_OLIVE '^h'
-#define S_COLOR_TOMATO '^i'
-#define S_COLOR_LIME '^j'
-#define S_COLOR_LEMON '^k'
-#define S_COLOR_BLUE_BERRY '^l'
-#define S_COLOR_TURQUOISE '^m'
-#define S_COLOR_WILD_WATERMELON '^n'
-#define S_COLOR_SALTPAN '^o'
-#define S_COLOR_GRAY_CHATEAU '^p'
-#define S_COLOR_RUST '^q'
-#define S_COLOR_COPPER_GREEN '^r'
-#define S_COLOR_GOLD '^s'
-#define S_COLOR_STEEL_BLUE '^t'
-#define S_COLOR_STEEL_GRAY '^u'
-#define S_COLOR_BRONZE '^v'
-#define S_COLOR_SILVER '^w'
-#define S_COLOR_DARK_GRAY '^x'
-#define S_COLOR_DARK_ORANGE '^y'
-#define S_COLOR_DARK_GREEN '^z'
-#define S_COLOR_RED_ORANGE '^A'
-#define S_COLOR_FOREST_GREEN '^B'
-#define S_COLOR_BRIGHT_SUN '^C'
-#define S_COLOR_MEDIUM_SLATE_BLUE '^D'
-#define S_COLOR_CELESTE '^E'
-#define S_COLOR_IRONSTONE '^F'
-#define S_COLOR_TIMBERWOLF '^G'
-#define S_COLOR_ONYX '^H'
-#define S_COLOR_ROSEWOOD '^I'
-#define S_COLOR_KOKODA '^J'
-#define S_COLOR_PORSCHE '^K'
-#define S_COLOR_CLOUD_BURST '^L'
-#define S_COLOR_BLUE_DIANE '^M'
-#define S_COLOR_ROPE '^N'
-#define S_COLOR_BLONDE '^O'
-#define S_COLOR_SMOKEY_BLACK '^P'
-#define S_COLOR_AMERICAN_ROSE '^Q'
-#define S_COLOR_NEON_GREEN '^R'
-#define S_COLOR_NEON_YELLOW '^S'
-#define S_COLOR_ULTRAMARINE '^T'
-#define S_COLOR_TURQUOISE_BLUE '^U'
-#define S_COLOR_DARK_MAGENTA '^V'
-#define S_COLOR_MAGIC_MINT '^W'
-#define S_COLOR_LIGHT_GRAY '^X'
-#define S_COLOR_LIGHT_SALMON '^Y'
-#define S_COLOR_LIGHT_GREEN '^Z'
-
-extern vec4_t g_color_table[62];
+#define COLOR_WHITE '7'
+#define ColorIndexForNumber(c) ((c) & 0x07)
+#define ColorIndex(c) (ColorIndexForNumber((c) - '0'))
+
+#define S_COLOR_BLACK "^0"
+#define S_COLOR_RED "^1"
+#define S_COLOR_GREEN "^2"
+#define S_COLOR_YELLOW "^3"
+#define S_COLOR_BLUE "^4"
+#define S_COLOR_CYAN "^5"
+#define S_COLOR_MAGENTA "^6"
+#define S_COLOR_WHITE "^7"
+
+#define INDENT_MARKER '\v'
+void Q_StripIndentMarker(char *string);
+
+extern vec4_t g_color_table[8];
#define MAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b
#define MAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a
@@ -550,23 +465,57 @@ extern vec3_t axisDefault[3];
#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
-#if idppc
+int Q_isnan(float x);
+
+#if idx64
+ extern long qftolsse(float f);
+ extern int qvmftolsse(void);
+ extern void qsnapvectorsse(vec3_t vec);
+
+ #define Q_ftol qftolsse
+ #define Q_SnapVector qsnapvectorsse
+
+#elif id386
+ extern long QDECL qftolx87(float f);
+ extern long QDECL qftolsse(float f);
+ extern int QDECL qvmftolx87(void);
+ extern int QDECL qvmftolsse(void);
+ extern void QDECL qsnapvectorx87(vec3_t vec);
+ extern void QDECL qsnapvectorsse(vec3_t vec);
+ extern long (QDECL *Q_ftol)(float f);
+ extern void (QDECL *Q_SnapVector)(vec3_t vec);
+#else
+ // Q_ftol must expand to a function name so the pluggable renderer can take
+ // its address
+ #define Q_ftol lrintf
+ #define Q_SnapVector(vec)\
+ do\
+ {\
+ vec3_t *temp = (vec3_t*)(vec);\
+ \
+ (*temp)[0] = round((*temp)[0]);\
+ (*temp)[1] = round((*temp)[1]);\
+ (*temp)[2] = round((*temp)[2]);\
+ } while(0)
+#endif
+
+#if idppc
static ID_INLINE float Q_rsqrt( float number ) {
- float x = 0.5f * number;
- float y;
-#ifdef __GNUC__
- asm("frsqrte %0,%1" : "=f" (y) : "f" (number));
+ float x = 0.5f * number;
+ float y;
+#ifdef __GNUC__
+ asm("frsqrte %0,%1" : "=f" (y) : "f" (number));
#else
- y = __frsqrte( number );
+ y = __frsqrte( number );
#endif
- return y * (1.5f - (x * y * y));
- }
+ return y * (1.5f - (x * y * y));
+}
-#ifdef __GNUC__
+#ifdef __GNUC__
static ID_INLINE float Q_fabs(float x) {
float abs_x;
-
+
asm("fabs %0,%1" : "=f" (abs_x) : "f" (x));
return abs_x;
}
@@ -588,28 +537,15 @@ signed short ClampShort( int i );
int DirToByte( vec3_t dir );
void ByteToDir( int b, vec3_t dir );
-#if 1
-
#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2])
#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2])
#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])
#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s))
#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s))
-#define VectorLerp( f, s, e, r ) ((r)[0]=(s)[0]+(f)*((e)[0]-(s)[0]),\
+#define VectorLerp2( f, s, e, r ) ((r)[0]=(s)[0]+(f)*((e)[0]-(s)[0]),\
(r)[1]=(s)[1]+(f)*((e)[1]-(s)[1]),\
- (r)[2]=(s)[2]+(f)*((e)[2]-(s)[2]))
-
-#else
-
-#define DotProduct(x,y) _DotProduct(x,y)
-#define VectorSubtract(a,b,c) _VectorSubtract(a,b,c)
-#define VectorAdd(a,b,c) _VectorAdd(a,b,c)
-#define VectorCopy(a,b) _VectorCopy(a,b)
-#define VectorScale(v, s, o) _VectorScale(v,s,o)
-#define VectorMA(v, s, b, o) _VectorMA(v,s,b,o)
-
-#endif
+ (r)[2]=(s)[2]+(f)*((e)[2]-(s)[2]))
#ifdef Q3_VM
#ifdef VectorCopy
@@ -628,9 +564,18 @@ typedef struct {
#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z))
#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
#define Vector4Add(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3])
+#define Vector4Lerp( f, s, e, r ) ((r)[0]=(s)[0]+(f)*((e)[0]-(s)[0]),\
+ (r)[1]=(s)[1]+(f)*((e)[1]-(s)[1]),\
+ (r)[2]=(s)[2]+(f)*((e)[2]-(s)[2]),\
+ (r)[3]=(s)[3]+(f)*((e)[3]-(s)[3]))
+
+#define SnapVector(v) ( (v)[0] = (int)(v)[0],\
+ (v)[1] = (int)(v)[1],\
+ (v)[2] = (int)(v)[2] )
+
+#define Byte4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
-#define SnapVector(v) {v[0]=((int)(v[0]));v[1]=((int)(v[1]));v[2]=((int)(v[2]));}
-// just in case you do't want to use the macros
+// just in case you don't want to use the macros
vec_t _DotProduct( const vec3_t v1, const vec3_t v2 );
void _VectorSubtract( const vec3_t veca, const vec3_t vecb, vec3_t out );
void _VectorAdd( const vec3_t veca, const vec3_t vecb, vec3_t out );
@@ -651,12 +596,11 @@ void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs );
static ID_INLINE int VectorCompare( const vec3_t v1, const vec3_t v2 ) {
if (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2]) {
return 0;
- }
+ }
return 1;
}
-static ID_INLINE int VectorCompareEpsilon(
- const vec3_t v1, const vec3_t v2, float epsilon )
+static ID_INLINE int VectorCompareEpsilon( const vec3_t v1, const vec3_t v2, float epsilon )
{
vec3_t d;
@@ -728,7 +672,7 @@ vec_t VectorLengthSquared( const vec3_t v );
vec_t Distance( const vec3_t p1, const vec3_t p2 );
vec_t DistanceSquared( const vec3_t p1, const vec3_t p2 );
-
+
void VectorNormalizeFast( vec3_t v );
void VectorInverse( vec3_t v );
@@ -762,6 +706,13 @@ void AxisCopy( vec3_t in[3], vec3_t out[3] );
void SetPlaneSignbits( struct cplane_s *out );
int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane);
+qboolean BoundsIntersect(const vec3_t mins, const vec3_t maxs,
+ const vec3_t mins2, const vec3_t maxs2);
+qboolean BoundsIntersectSphere(const vec3_t mins, const vec3_t maxs,
+ const vec3_t origin, vec_t radius);
+qboolean BoundsIntersectPoint(const vec3_t mins, const vec3_t maxs,
+ const vec3_t origin);
+
float AngleMod(float a);
float LerpAngle (float from, float to, float frac);
float AngleSubtract( float a1, float a2 );
@@ -784,7 +735,6 @@ void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]);
void VectorMatrixMultiply( const vec3_t p, vec3_t m[ 3 ], vec3_t out );
void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
void PerpendicularVector( vec3_t dst, const vec3_t src );
-int Q_isnan( float x );
void GetPerpendicularViewVector( const vec3_t point, const vec3_t p1,
const vec3_t p2, vec3_t up );
@@ -818,7 +768,9 @@ vec_t DistanceBetweenLineSegments(
float Com_Clamp( float min, float max, float value );
char *COM_SkipPath( char *pathname );
+const char *COM_GetExtension( const char *name );
void COM_StripExtension(const char *in, char *out, int destsize);
+qboolean COM_CompareExtension(const char *in, const char *ext);
void COM_DefaultExtension( char *path, int maxSize, const char *extension );
void COM_BeginParseSession( const char *name );
@@ -828,7 +780,6 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreak );
int COM_Compress( char *data_p );
void COM_ParseError( char *format, ... ) __attribute__ ((format (printf, 1, 2)));
void COM_ParseWarning( char *format, ... ) __attribute__ ((format (printf, 1, 2)));
-//int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] );
#define MAX_TOKENLENGTH 1024
@@ -854,33 +805,32 @@ typedef struct pc_token_s
void COM_MatchToken( char**buf_p, char *match );
-void SkipBracedSection (char **program);
+qboolean SkipBracedSection (char **program, int depth);
void SkipRestOfLine ( char **data );
void Parse1DMatrix (char **buf_p, int x, float *m);
void Parse2DMatrix (char **buf_p, int y, int x, float *m);
void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m);
+int Com_HexStrToInt( const char *str );
-void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
+int QDECL Com_sprintf (char *dest, int size, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
-char *Com_SkipTokens( char *s, int numTokens, char *sep );
-char *Com_SkipCharset( char *s, char *sep );
+char *Com_SkipTokens( char *s, int numTokens, const char *sep );
+char *Com_SkipCharset( char *s, const char *sep );
void Com_RandomBytes( byte *string, int len );
-// mode parm for FS_FOpenFile
-typedef enum {
- FS_READ,
- FS_WRITE,
- FS_APPEND,
- FS_APPEND_SYNC
-} fsMode_t;
+typedef struct
+{
+ unsigned int hi;
+ unsigned int lo;
+} clientList_t;
-typedef enum {
- FS_SEEK_CUR,
- FS_SEEK_END,
- FS_SEEK_SET
-} fsOrigin_t;
+qboolean Com_ClientListContains( const clientList_t *list, int clientNum );
+void Com_ClientListAdd( clientList_t *list, int clientNum );
+void Com_ClientListRemove( clientList_t *list, int clientNum );
+char *Com_ClientListString( const clientList_t *list );
+void Com_ClientListParse( clientList_t *list, const char *s );
//=============================================
@@ -888,7 +838,8 @@ int Q_isprint( int c );
int Q_islower( int c );
int Q_isupper( int c );
int Q_isalpha( int c );
-int Q_isdigit( int c );
+qboolean Q_isanumber( const char *s );
+qboolean Q_isintegral( float f );
// portable case insensitive compare
int Q_stricmp (const char *s1, const char *s2);
@@ -896,7 +847,7 @@ int Q_strncmp (const char *s1, const char *s2, int n);
int Q_stricmpn (const char *s1, const char *s2, int n);
char *Q_strlwr( char *s1 );
char *Q_strupr( char *s1 );
-char *Q_strrchr( const char* string, int c );
+const char *Q_stristr( const char *s, const char *find);
// buffer size safe library replacements
void Q_strncpyz( char *dest, const char *src, int destsize );
@@ -906,37 +857,17 @@ void Q_strcat( char *dest, int size, const char *src );
int Q_PrintStrlen( const char *string );
// removes color sequences from string
char *Q_CleanStr( char *string );
+// parse "\n" into '\n'
+void Q_ParseNewlines( char *dest, const char *src, int destsize );
+// Count the number of char tocount encountered in string
+int Q_CountChar(const char *string, char tocount);
-//=============================================
-// 64-bit integers for global rankings interface
-// implemented as a struct for qvm compatibility
-typedef struct
-{
- byte b0;
- byte b1;
- byte b2;
- byte b3;
- byte b4;
- byte b5;
- byte b6;
- byte b7;
-} qint64;
+#define rc(x) va("%s^7", x) ///< shortcut for color reset after printing variable
//=============================================
-/*
-short BigShort(short l);
-short LittleShort(short l);
-int BigLong (int l);
-int LittleLong (int l);
-qint64 BigLong64 (qint64 l);
-qint64 LittleLong64 (qint64 l);
-float BigFloat (const float *l);
-float LittleFloat (const float *l);
-
-void Swap_Init (void);
-*/
-char * QDECL va(char *format, ...) __attribute__ ((format (printf, 1, 2)));
+
+const char * QDECL va(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
#define TRUNCATE_LENGTH 64
void Com_TruncateLongString( char *buffer, const char *s );
@@ -948,78 +879,32 @@ void Com_TruncateLongString( char *buffer, const char *s );
//
char *Info_ValueForKey( const char *s, const char *key );
void Info_RemoveKey( char *s, const char *key );
-void Info_RemoveKey_big( char *s, const char *key );
+void Info_RemoveKey_Big( char *s, const char *key );
void Info_SetValueForKey( char *s, const char *key, const char *value );
void Info_SetValueForKey_Big( char *s, const char *key, const char *value );
qboolean Info_Validate( const char *s );
void Info_NextPair( const char **s, char *key, char *value );
// this is only here so the functions in q_shared.c and bg_*.c can link
-void QDECL Com_Error( int level, const char *error, ... ) __attribute__ ((format (printf, 2, 3)));
+void QDECL Com_Error( int level, const char *error, ... ) __attribute__ ((noreturn, format(printf, 2, 3)));
void QDECL Com_Printf( const char *msg, ... ) __attribute__ ((format (printf, 1, 2)));
/*
-==========================================================
+==============================================================
-CVARS (console variables)
+VoIP
-Many variables can be used for cheating purposes, so when
-cheats is zero, force all unspecified variables to their
-default values.
-==========================================================
+==============================================================
*/
-#define CVAR_ARCHIVE 1 // set to cause it to be saved to vars.rc
- // used for system variables, not for player
- // specific configurations
-#define CVAR_USERINFO 2 // sent to server on connect or change
-#define CVAR_SERVERINFO 4 // sent in response to front end requests
-#define CVAR_SYSTEMINFO 8 // these cvars will be duplicated on all clients
-#define CVAR_INIT 16 // don't allow change from console at all,
- // but can be set from the command line
-#define CVAR_LATCH 32 // will only change when C code next does
- // a Cvar_Get(), so it can't be changed
- // without proper initialization. modified
- // will be set, even though the value hasn't
- // changed yet
-#define CVAR_ROM 64 // display only, cannot be set by user at all
-#define CVAR_USER_CREATED 128 // created by a set command
-#define CVAR_TEMP 256 // can be set even when cheats are disabled, but is not archived
-#define CVAR_CHEAT 512 // can not be changed if cheats are disabled
-#define CVAR_NORESTART 1024 // do not clear when a cvar_restart is issued
-
-#define CVAR_SERVER_CREATED 2048 // cvar was created by a server the client connected to.
-#define CVAR_NONEXISTENT 0xFFFFFFFF // Cvar doesn't exist.
-
-// nothing outside the Cvar_*() functions should modify these fields!
-typedef struct cvar_s {
- char *name;
- char *string;
- char *resetString; // cvar_restart will reset to this value
- char *latchedString; // for CVAR_LATCH vars
- int flags;
- qboolean modified; // set each time the cvar is changed
- int modificationCount; // incremented each time the cvar is changed
- float value; // atof( string )
- int integer; // atoi( string )
- struct cvar_s *next;
- struct cvar_s *hashNext;
-} cvar_t;
-
-#define MAX_CVAR_VALUE_STRING 256
-
-typedef int cvarHandle_t;
+// if you change the count of flags be sure to also change VOIP_FLAGNUM
+#define VOIP_SPATIAL 0x01 // spatialized voip message
+#define VOIP_DIRECT 0x02 // non-spatialized voip message
-// the modules that run in the virtual machine can't access the cvar_t directly,
-// so they must ask for structured updates
-typedef struct {
- cvarHandle_t handle;
- int modificationCount;
- float value;
- int integer;
- char string[MAX_CVAR_VALUE_STRING];
-} vmCvar_t;
+// number of flags voip knows. You will have to bump protocol version number if you
+// change this.
+#define VOIP_FLAGCNT 2
/*
==============================================================
@@ -1029,7 +914,7 @@ COLLISION DETECTION
==============================================================
*/
-#include "surfaceflags.h" // shared with the q3map utility
+#include "qcommon/surfaceflags.h" // shared with the q3map utility
// plane types are used to speed some tests
// 0-2 are axial planes
@@ -1070,7 +955,8 @@ typedef enum {
// a trace is returned when a box is swept through the world
typedef struct {
qboolean allsolid; // if true, plane is not valid
- qboolean startsolid; // if true, the initial point was in a solid area
+// FIXME: startsolid is supposed to be bool
+ int /*qboolean*/ startsolid; // if true, the initial point was in a solid area
float fraction; // time completed, 1.0 = didn't hit anything
vec3_t endpos; // final position
cplane_t plane; // surface normal at impact, transformed to world space
@@ -1083,15 +969,12 @@ typedef struct {
// trace->entityNum can also be 0 to (MAX_GENTITIES-1)
// or ENTITYNUM_NONE, ENTITYNUM_WORLD
-
-// markfragments are returned by CM_MarkFragments()
+// markfragments are returned by R_MarkFragments()
typedef struct {
int firstPoint;
int numPoints;
} markFragment_t;
-
-
typedef struct {
vec3_t origin;
vec3_t axis[3];
@@ -1104,7 +987,7 @@ typedef struct {
// if none of the catchers are active, bound key strings will be executed
#define KEYCATCH_CONSOLE 0x0001
#define KEYCATCH_UI 0x0002
-#define KEYCATCH_MESSAGE 0x0004
+#define KEYCATCH_MESSAGE 0x0004
#define KEYCATCH_CGAME 0x0008
@@ -1146,6 +1029,7 @@ typedef enum {
#define GENTITYNUM_BITS 10 // don't need to send any more
#define MAX_GENTITIES (1<<GENTITYNUM_BITS)
+#define GENTITYNUM_MASK (MAX_GENTITIES - 1)
// entitynums are communicated with GENTITY_BITS, so any reserved
// values that are going to be communcated over the net need to
@@ -1183,7 +1067,7 @@ typedef struct {
#define MAX_STATS 16
#define MAX_PERSISTANT 16
#define MAX_MISC 16
-#define MAX_WEAPONS 16
+#define MAX_WEAPONS 16
#define MAX_PS_EVENTS 2
@@ -1283,7 +1167,7 @@ typedef struct playerState_s {
//
#define BUTTON_ATTACK 1
#define BUTTON_TALK 2 // displays talk balloon and disables actions
-#define BUTTON_USE_HOLDABLE 4
+#define BUTTON_USE_HOLDABLE 4 // activate upgrade
#define BUTTON_GESTURE 8
#define BUTTON_WALKING 16 // walking can't just be infered from MOVE_RUN
// because a key pressed late in the frame will
@@ -1291,12 +1175,9 @@ typedef struct playerState_s {
// walking will use different animations and
// won't generate footsteps
#define BUTTON_ATTACK2 32
-#define BUTTON_NEGATIVE 64
-
-#define BUTTON_GETFLAG 128
-#define BUTTON_GUARDBASE 256
-#define BUTTON_PATROL 512
-#define BUTTON_FOLLOWME 1024
+#define BUTTON_DODGE 64 // start a dodge or sprint motion
+#define BUTTON_USE_EVOLVE 128 // use target or open evolve menu
+#define BUTTON_SPRINT 256
#define BUTTON_ANY 2048 // any key whatsoever
@@ -1308,7 +1189,7 @@ typedef struct usercmd_s {
int serverTime;
int angles[3];
int buttons;
- byte weapon; // weapon
+ byte weapon; // weapon
signed char forwardmove, rightmove, upmove;
} usercmd_t;
@@ -1324,7 +1205,7 @@ typedef enum {
TR_LINEAR_STOP,
TR_SINE, // value = base + sin( time / duration ) * delta
TR_GRAVITY,
- TR_BUOYANCY //TA: what the hell is this doing in here anyway?
+ TR_BUOYANCY
} trType_t;
typedef struct {
@@ -1362,7 +1243,7 @@ typedef struct entityState_s {
int otherEntityNum; // shotgun sources, etc
int otherEntityNum2;
- int groundEntityNum; // -1 = in air
+ int groundEntityNum; // ENTITYNUM_NONE = in air
int constantLight; // r + (g<<8) + (b<<16) + (intensity<<24)
int loopSound; // constantly loop this sound
@@ -1390,7 +1271,7 @@ typedef struct entityState_s {
typedef enum {
CA_UNINITIALIZED,
CA_DISCONNECTED, // not talking to a server
- CA_AUTHORIZING, // not used any more, was checking cd key
+ CA_AUTHORIZING, // not used any more, was checking cd key
CA_CONNECTING, // sending request packets to the server
CA_CHALLENGING, // sending challenge packets to the server
CA_CONNECTED, // netchan_t established, getting gamestate
@@ -1400,13 +1281,14 @@ typedef enum {
CA_CINEMATIC // playing a cinematic or a static pic, not connected to a server
} connstate_t;
-// font support
+// font support
#define GLYPH_START 0
#define GLYPH_END 255
#define GLYPH_CHARSTART 32
#define GLYPH_CHAREND 127
-#define GLYPHS_PER_FONT GLYPH_END - GLYPH_START + 1
+#define GLYPHS_PER_FONT (GLYPH_END - GLYPH_START + 1)
+
typedef struct {
int height; // number of scan lines
int top; // top of glyph in buffer
@@ -1449,11 +1331,11 @@ typedef struct qtime_s {
// server browser sources
-// TTimo: AS_MPLAYER is no longer used
-#define AS_GLOBAL 0
-#define AS_MPLAYER 1
-#define AS_LOCAL 2
-#define AS_FAVORITES 3
+// AS_MPLAYER is no longer used
+#define AS_GLOBAL 0
+#define AS_MPLAYER 1
+#define AS_LOCAL 2
+#define AS_FAVORITES 3
// cinematic states
@@ -1467,20 +1349,10 @@ typedef enum {
FMV_ID_WAIT
} e_status;
-typedef enum _flag_status {
- FLAG_ATBASE = 0,
- FLAG_TAKEN, // CTF
- FLAG_TAKEN_RED, // One Flag CTF
- FLAG_TAKEN_BLUE, // One Flag CTF
- FLAG_DROPPED
-} flagStatus_t;
-
typedef enum {
DS_NONE,
-
DS_PLAYBACK,
DS_RECORDING,
-
DS_NUM_DEMO_STATES
} demoState_t;
@@ -1490,12 +1362,31 @@ typedef enum {
#define MAX_PINGREQUESTS 32
#define MAX_SERVERSTATUSREQUESTS 16
-#define SAY_ALL 0
-#define SAY_TEAM 1
-#define SAY_TELL 2
-#define SAY_ACTION 3
-#define SAY_ACTION_T 4
-#define SAY_ADMINS 5
-#define SAY_HADMINS 6
+#define MAX_EMOTICON_NAME_LEN 16
+#define MAX_EMOTICONS 64
+typedef struct
+{
+ char name[ MAX_EMOTICON_NAME_LEN ];
+#ifndef GAME
+ int width;
+ qhandle_t shader;
+#endif
+} emoticon_t;
+
+// flags for com_downloadPrompt
+#define DLP_TYPE_MASK 0x0f
+#define DLP_IGNORE 0x01 // don't download anything
+#define DLP_CURL 0x02 // download via HTTP redirect
+#define DLP_UDP 0x04 // download from server
+#define DLP_SHOW 0x10 // prompt needs to be shown
+#define DLP_PROMPTED 0x20 // prompt has been processed by client
+#define DLP_STALE 0x40 // prompt is not being shown by UI VM
+
+#define LERP( a, b, w ) ( ( a ) * ( 1.0f - ( w ) ) + ( b ) * ( w ) )
+#define LUMA( red, green, blue ) ( 0.2126f * ( red ) + 0.7152f * ( green ) + 0.0722f * ( blue ) )
+
+#ifdef __cplusplus
+};
+#endif
#endif // __Q_SHARED_H
diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
new file mode 100644
index 0000000..f258ce9
--- /dev/null
+++ b/src/qcommon/qcommon.h
@@ -0,0 +1,413 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// qcommon.h -- definitions common between client and server, but not game.or ref modules
+#ifndef _QCOMMON_H_
+#define _QCOMMON_H_
+
+#include <stdbool.h>
+
+#include "cm_public.h"
+
+//Ignore __attribute__ on non-gcc platforms
+#ifndef __GNUC__
+#ifndef __attribute__
+#define __attribute__(x)
+#endif
+#endif
+
+struct netadr_t;
+struct msg_t;
+
+/*
+==============================================================
+
+PROTOCOL
+
+==============================================================
+*/
+
+#define PROTOCOL_VERSION 71
+
+// maintain a list of compatible protocols for demo playing
+// NOTE: that stuff only works with two digits protocols
+extern int demo_protocols[];
+
+// override on command line, config files etc.
+#ifndef MASTER_SERVER_NAME
+#define MASTER_SERVER_NAME "master.tremulous.net"
+#endif
+
+#define PORT_MASTER 30700
+#define PORT_SERVER 30720
+#define ALT1PORT_MASTER 30700
+#define ALT1PORT_SERVER 30721
+#define ALT2PORT_MASTER 30710
+#define ALT2PORT_SERVER 30722
+#define NUM_SERVER_PORTS 4 // broadcast scan this many ports after
+ // PORT_SERVER so a single machine can
+ // run multiple servers
+
+
+// the svc_strings[] array in cl_parse.c should mirror this
+//
+// server to client
+//
+enum svc_ops_e {
+ svc_bad,
+ svc_nop,
+ svc_gamestate,
+ svc_configstring, // [short] [string] only in gamestate messages
+ svc_baseline, // only in gamestate messages
+ svc_serverCommand, // [string] to be executed by client game module
+ svc_download, // [short] size [size bytes]
+ svc_snapshot,
+ svc_EOF,
+
+// new commands, supported only by ioquake3 protocol but not legacy
+ svc_voipSpeex, // not wrapped in USE_VOIP, so this value is reserved.
+ svc_voipOpus, //
+};
+
+
+//
+// client to server
+//
+enum clc_ops_e {
+ clc_bad,
+ clc_nop,
+ clc_move, // [[usercmd_t]
+ clc_moveNoDelta, // [[usercmd_t]
+ clc_clientCommand, // [string] message
+ clc_EOF,
+
+// new commands, supported only by ioquake3 protocol but not legacy
+ clc_voipSpeex, // not wrapped in USE_VOIP, so this value is reserved.
+ clc_voipOpus, //
+};
+
+//#include "cvar.h"
+
+typedef struct cvar_s cvar_t;
+
+/*
+==============================================================
+
+Edit fields and command line history/completion
+
+==============================================================
+*/
+
+#define MAX_EDIT_LINE 256
+typedef struct {
+ int cursor;
+ int scroll;
+ int widthInChars;
+ char buffer[MAX_EDIT_LINE];
+} field_t;
+
+void Field_Clear( field_t *edit );
+void Field_AutoComplete( field_t *edit );
+void Field_CompleteKeyname( void );
+void Field_CompleteFilename( const char *dir, const char *ext, bool stripExt, bool allowNonPureFilesOnDisk );
+void Field_CompleteCommand( char *cmd, bool doCommands, bool doCvars );
+void Field_CompletePlayerName( const char **names, int count );
+void Field_CompleteList( char *listJson );
+
+/*
+==============================================================
+
+MISC
+
+==============================================================
+*/
+
+// centralized and cleaned, that's the max string you can send to a Com_Printf / Com_DPrintf (above gets truncated)
+#define MAXPRINTMSG 4096
+
+
+typedef enum {
+ // SE_NONE must be zero
+ SE_NONE = 0, // evTime is still valid
+ SE_KEY, // evValue is a key code, evValue2 is the down flag
+ SE_CHAR, // evValue is an ascii char
+ SE_MOUSE, // evValue and evValue2 are relative signed x / y moves
+ SE_JOYSTICK_AXIS, // evValue is an axis number and evValue2 is the current state (-127 to 127)
+ SE_CONSOLE // evPtr is a char*
+} sysEventType_t;
+
+typedef struct {
+ int evTime;
+ sysEventType_t evType;
+ int evValue, evValue2;
+ int evPtrLength; // bytes of data pointed to by evPtr, for journaling
+ void *evPtr; // this must be manually freed if not NULL
+} sysEvent_t;
+
+void Com_QueueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr );
+int Com_EventLoop( void );
+sysEvent_t Com_GetSystemEvent( void );
+
+char *CopyString( const char *in );
+void Info_Print( const char *s );
+
+void Com_BeginRedirect (char *buffer, int buffersize, void (*flush)(char *));
+void Com_EndRedirect( void );
+
+//#ifndef __Q_SHARED_H
+void QDECL Com_Printf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2)));
+void QDECL Com_Error( int code, const char *fmt, ... ) __attribute__ ((noreturn, format(printf, 2, 3)));
+//#endif
+void QDECL Com_DPrintf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2)));
+void Engine_Exit(const char* p ) __attribute__ ((noreturn));
+void Com_Quit_f( void ) __attribute__ ((noreturn));
+void Com_GameRestart(int checksumFeed, bool disconnect);
+
+int Com_Milliseconds( void ); // will be journaled properly
+char *Com_MD5File(const char *filename, int length, const char *prefix, int prefix_len);
+int Com_Filter(const char* filter, char *name, int casesensitive);
+int Com_FilterPath(const char *filter, char *name, int casesensitive);
+int Com_RealTime(qtime_t *qtime);
+bool Com_SafeMode( void );
+void Com_RunAndTimeServerPacket(struct netadr_t *evFrom, struct msg_t *buf);
+
+bool Com_IsVoipTarget(uint8_t *voipTargets, int voipTargetsSize, int clientNum);
+
+void Com_StartupVariable( const char *match );
+// checks for and removes command line "+set var arg" constructs
+// if match is NULL, all set commands will be executed, otherwise
+// only a set with the exact name. Only used during startup.
+
+bool Com_PlayerNameToFieldString( char *str, int length, const char *name );
+bool Com_FieldStringToPlayerName( char *name, int length, const char *rawname );
+int QDECL Com_strCompare( const void *a, const void *b );
+
+
+extern cvar_t *com_developer;
+extern cvar_t *com_dedicated;
+extern cvar_t *com_speeds;
+extern cvar_t *com_timescale;
+extern cvar_t *com_sv_running;
+extern cvar_t *com_cl_running;
+extern cvar_t *com_version;
+extern cvar_t *com_buildScript; // for building release pak files
+extern cvar_t *com_journal;
+extern cvar_t *com_cameraMode;
+extern cvar_t *com_ansiColor;
+extern cvar_t *com_unfocused;
+extern cvar_t *com_maxfpsUnfocused;
+extern cvar_t *com_minimized;
+extern cvar_t *com_maxfpsMinimized;
+extern cvar_t *com_altivec;
+extern cvar_t *com_homepath;
+
+// both client and server must agree to pause
+extern cvar_t *cl_paused;
+extern cvar_t *sv_paused;
+
+extern cvar_t *cl_packetdelay;
+extern cvar_t *sv_packetdelay;
+
+extern cvar_t *com_gamename;
+
+// com_speeds times
+extern int time_game;
+extern int time_frontend;
+extern int time_backend; // renderer backend time
+
+extern int com_frameTime;
+
+extern bool com_errorEntered;
+extern bool com_fullyInitialized;
+
+extern fileHandle_t com_journalFile;
+extern fileHandle_t com_journalDataFile;
+
+typedef enum {
+ TAG_FREE,
+ TAG_GENERAL,
+ TAG_BOTLIB,
+ TAG_RENDERER,
+ TAG_SMALL,
+ TAG_STATIC
+} memtag_t;
+
+/*
+
+--- low memory ----
+server vm
+server clipmap
+---mark---
+renderer initialization (shaders, etc)
+UI vm
+cgame vm
+renderer map
+renderer models
+
+---free---
+
+temp file loading
+--- high memory ---
+
+*/
+
+#if !defined(NDEBUG) && !defined(BSPC)
+ #define ZONE_DEBUG
+#endif
+
+#ifdef ZONE_DEBUG
+#define Z_TagMalloc(size, tag) Z_TagMallocDebug(size, tag, #size, __FILE__, __LINE__)
+#define Z_Malloc(size) Z_MallocDebug(size, #size, __FILE__, __LINE__)
+#define S_Malloc(size) S_MallocDebug(size, #size, __FILE__, __LINE__)
+void *Z_TagMallocDebug( int size, int tag, const char *label, const char *file, int line ); // NOT 0 filled memory
+void *Z_MallocDebug( int size, const char *label, const char *file, int line ); // returns 0 filled memory
+void *S_MallocDebug( int size, const char *label, const char *file, int line ); // returns 0 filled memory
+#else
+void *Z_TagMalloc( int size, int tag ); // NOT 0 filled memory
+void *Z_Malloc( int size ); // returns 0 filled memory
+void *S_Malloc( int size ); // NOT 0 filled memory only for small allocations
+#endif
+void Z_Free( void *ptr );
+void Z_FreeTags( int tag );
+int Z_AvailableMemory( void );
+void Z_LogHeap( void );
+
+void Hunk_Clear( void );
+void Hunk_ClearToMark( void );
+void Hunk_SetMark( void );
+bool Hunk_CheckMark( void );
+void Hunk_ClearTempMemory( void );
+void *Hunk_AllocateTempMemory( int size );
+void Hunk_FreeTempMemory( void *buf );
+int Hunk_MemoryRemaining( void );
+void Hunk_Log( void);
+
+void Com_TouchMemory( void );
+
+// commandLine should not include the executable name (argv[0])
+void Com_Init( char *commandLine );
+void Com_Frame( void );
+void Com_Shutdown( void );
+
+
+/*
+==============================================================
+
+CLIENT / SERVER SYSTEMS
+
+==============================================================
+*/
+
+//
+// client interface
+//
+void CL_InitKeyCommands( void );
+// the keyboard binding interface must be setup before execing
+// config files, but the rest of client startup will happen later
+
+void CL_Init( void );
+void CL_Disconnect( bool showMainMenu );
+void CL_Shutdown(const char *finalmsg, bool disconnect, bool quit);
+void CL_Frame( int msec );
+bool CL_GameCommand( void );
+void CL_KeyEvent (int key, bool down, unsigned time);
+
+void CL_CharEvent( int key );
+// char events are for field typing, not game control
+
+void CL_MouseEvent( int dx, int dy, int time );
+
+void CL_JoystickEvent( int axis, int value, int time );
+
+void CL_PacketEvent( struct netadr_t from, struct msg_t *msg );
+
+void CL_ConsolePrint( const char *text );
+
+void CL_MapLoading( void );
+// do a screen update before starting to load a map
+// when the server is going to load a new map, the entire hunk
+// will be cleared, so the client must shutdown cgame, ui, and
+// the renderer
+
+void CL_ForwardCommandToServer( const char *string );
+// adds the current command line as a clc_clientCommand to the client message.
+// things like godmode, noclip, etc, are commands directed to the server,
+// so when they are typed in at the console, they will need to be forwarded.
+
+void CL_FlushMemory( void );
+// dump all memory on an error
+
+void CL_ShutdownAll(bool shutdownRef);
+// shutdown client
+
+void CL_StartHunkUsers( bool rendererOnly );
+// start all the client stuff using the hunk
+
+void Key_KeynameCompletion( void(*callback)(const char *s) );
+// for keyname autocompletion
+
+void Key_WriteBindings( fileHandle_t f );
+// for writing the config files
+
+void S_ClearSoundBuffer( void );
+// call before filesystem access
+
+void SCR_DebugGraph (float value); // FIXME: move logging to common?
+
+//
+// server interface
+//
+void SV_Init( void );
+void SV_Shutdown( const char *finalmsg );
+void SV_Frame( int msec );
+void SV_PacketEvent( struct netadr_t from, struct msg_t *msg );
+int SV_FrameMsec(void);
+bool SV_GameCommand( void );
+int SV_SendQueuedPackets(void);
+
+//
+// UI interface
+//
+bool UI_GameCommand( void );
+
+/*
+==============================================================
+
+NON-PORTABLE SYSTEM SERVICES
+
+==============================================================
+*/
+
+bool Parse_AddGlobalDefine(char *string);
+int Parse_LoadSourceHandle(const char *filename);
+bool Parse_FreeSourceHandle(int handle);
+bool Parse_ReadTokenHandle(int handle, pc_token_t *pc_token);
+bool Parse_SourceFileAndLine(int handle, char *filename, int *line);
+
+// flags for sv_allowDownload and cl_allowDownload
+#define DLF_ENABLE 1
+#define DLF_NO_REDIRECT 2
+#define DLF_NO_UDP 4
+#define DLF_NO_DISCONNECT 8
+
+#endif // _QCOMMON_H_
diff --git a/src/qcommon/qfiles.h b/src/qcommon/qfiles.h
index 7e901b7..91bcf04 100644
--- a/src/qcommon/qfiles.h
+++ b/src/qcommon/qfiles.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,19 +17,21 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
+
+// qfiles.h: quake file formats
+
#ifndef __QFILES_H__
#define __QFILES_H__
-//
-// qfiles.h: quake file formats
// This file must be identical in the quake and utils directories
-//
-//Ignore __attribute__ on non-gcc platforms
+#include "q_shared.h"
+
+// Ignore __attribute__ on non-gcc platforms
#ifndef __GNUC__
#ifndef __attribute__
#define __attribute__(x)
@@ -36,12 +39,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif
// surface geometry should not exceed these limits
-#define SHADER_MAX_VERTEXES 1000
-#define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES)
-
+#define SHADER_MAX_VERTEXES 1000
+#define SHADER_MAX_INDEXES (6 * SHADER_MAX_VERTEXES)
// the maximum size of game relative pathnames
-#define MAX_QPATH 64
+#define MAX_QPATH 64
/*
========================================================================
@@ -51,69 +53,25 @@ QVM files
========================================================================
*/
-#define VM_MAGIC 0x12721444
-#define VM_MAGIC_VER2 0x12721445
+#define VM_MAGIC 0x12721444
+#define VM_MAGIC_VER2 0x12721445
typedef struct {
- int vmMagic;
+ int vmMagic;
- int instructionCount;
+ int instructionCount;
- int codeOffset;
- int codeLength;
+ int codeOffset;
+ int codeLength;
- int dataOffset;
- int dataLength;
- int litLength; // ( dataLength - litLength ) should be byteswapped on load
- int bssLength; // zero filled memory appended to datalength
+ int dataOffset;
+ int dataLength;
+ int litLength; // ( dataLength - litLength ) should be byteswapped on load
+ int bssLength; // zero filled memory appended to datalength
- //!!! below here is VM_MAGIC_VER2 !!!
- int jtrgLength; // number of jump table targets
+ //!!! below here is VM_MAGIC_VER2 !!!
+ int jtrgLength; // number of jump table targets
} vmHeader_t;
-
-/*
-========================================================================
-
-PCX files are used for 8 bit images
-
-========================================================================
-*/
-
-typedef struct {
- char manufacturer;
- char version;
- char encoding;
- char bits_per_pixel;
- unsigned short xmin,ymin,xmax,ymax;
- unsigned short hres,vres;
- unsigned char palette[48];
- char reserved;
- char color_planes;
- unsigned short bytes_per_line;
- unsigned short palette_type;
- char filler[58];
- unsigned char data; // unbounded
-} pcx_t;
-
-
-/*
-========================================================================
-
-TGA files are used for 24/32 bit images
-
-========================================================================
-*/
-
-typedef struct _TargaHeader {
- unsigned char id_length, colormap_type, image_type;
- unsigned short colormap_index, colormap_length;
- unsigned char colormap_size;
- unsigned short x_origin, y_origin, width, height;
- unsigned char pixel_size, attributes;
-} TargaHeader;
-
-
-
/*
========================================================================
@@ -122,195 +80,112 @@ typedef struct _TargaHeader {
========================================================================
*/
-#define MD3_IDENT (('3'<<24)+('P'<<16)+('D'<<8)+'I')
-#define MD3_VERSION 15
+#define MD3_IDENT (('3' << 24) + ('P' << 16) + ('D' << 8) + 'I')
+#define MD3_VERSION 15
// limits
-#define MD3_MAX_LODS 3
-#define MD3_MAX_TRIANGLES 8192 // per surface
-#define MD3_MAX_VERTS 4096 // per surface
-#define MD3_MAX_SHADERS 256 // per surface
-#define MD3_MAX_FRAMES 1024 // per model
-#define MD3_MAX_SURFACES 32 // per model
-#define MD3_MAX_TAGS 16 // per frame
+#define MD3_MAX_LODS 3
+#define MD3_MAX_TRIANGLES 8192 // per surface
+#define MD3_MAX_VERTS 4096 // per surface
+#define MD3_MAX_SHADERS 256 // per surface
+#define MD3_MAX_FRAMES 1024 // per model
+#define MD3_MAX_SURFACES 32 // per model
+#define MD3_MAX_TAGS 16 // per frame
// vertex scales
-#define MD3_XYZ_SCALE (1.0/64)
+#define MD3_XYZ_SCALE (1.0 / 64)
typedef struct md3Frame_s {
- vec3_t bounds[2];
- vec3_t localOrigin;
- float radius;
- char name[16];
+ vec3_t bounds[2];
+ vec3_t localOrigin;
+ float radius;
+ char name[16];
} md3Frame_t;
typedef struct md3Tag_s {
- char name[MAX_QPATH]; // tag name
- vec3_t origin;
- vec3_t axis[3];
+ char name[MAX_QPATH]; // tag name
+ vec3_t origin;
+ vec3_t axis[3];
} md3Tag_t;
/*
** md3Surface_t
**
-** CHUNK SIZE
-** header sizeof( md3Surface_t )
-** shaders sizeof( md3Shader_t ) * numShaders
-** triangles[0] sizeof( md3Triangle_t ) * numTriangles
-** st sizeof( md3St_t ) * numVerts
-** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames
+** CHUNK SIZE
+** header sizeof( md3Surface_t )
+** shaders sizeof( md3Shader_t ) * numShaders
+** triangles[0] sizeof( md3Triangle_t ) * numTriangles
+** st sizeof( md3St_t ) * numVerts
+** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames
*/
typedef struct {
- int ident; //
+ int ident; //
- char name[MAX_QPATH]; // polyset name
+ char name[MAX_QPATH]; // polyset name
- int flags;
- int numFrames; // all surfaces in a model should have the same
+ int flags;
+ int numFrames; // all surfaces in a model should have the same
- int numShaders; // all surfaces in a model should have the same
- int numVerts;
+ int numShaders; // all surfaces in a model should have the same
+ int numVerts;
- int numTriangles;
- int ofsTriangles;
+ int numTriangles;
+ int ofsTriangles;
- int ofsShaders; // offset from start of md3Surface_t
- int ofsSt; // texture coords are common for all frames
- int ofsXyzNormals; // numVerts * numFrames
+ int ofsShaders; // offset from start of md3Surface_t
+ int ofsSt; // texture coords are common for all frames
+ int ofsXyzNormals; // numVerts * numFrames
- int ofsEnd; // next surface follows
+ int ofsEnd; // next surface follows
} md3Surface_t;
typedef struct {
- char name[MAX_QPATH];
- int shaderIndex; // for in-game use
+ char name[MAX_QPATH];
+ int shaderIndex; // for in-game use
} md3Shader_t;
typedef struct {
- int indexes[3];
+ int indexes[3];
} md3Triangle_t;
typedef struct {
- float st[2];
+ float st[2];
} md3St_t;
typedef struct {
- short xyz[3];
- short normal;
+ short xyz[3];
+ short normal;
} md3XyzNormal_t;
typedef struct {
- int ident;
- int version;
+ int ident;
+ int version;
- char name[MAX_QPATH]; // model name
+ char name[MAX_QPATH]; // model name
- int flags;
+ int flags;
- int numFrames;
- int numTags;
- int numSurfaces;
+ int numFrames;
+ int numTags;
+ int numSurfaces;
- int numSkins;
+ int numSkins;
- int ofsFrames; // offset for first frame
- int ofsTags; // numFrames * numTags
- int ofsSurfaces; // first surface, others follow
+ int ofsFrames; // offset for first frame
+ int ofsTags; // numFrames * numTags
+ int ofsSurfaces; // first surface, others follow
- int ofsEnd; // end of file
+ int ofsEnd; // end of file
} md3Header_t;
/*
==============================================================================
-MD4 file format
+MDR file format
==============================================================================
*/
-#define MD4_IDENT (('4'<<24)+('P'<<16)+('D'<<8)+'I')
-#define MD4_VERSION 1
-#define MD4_MAX_BONES 128
-
-typedef struct {
- int boneIndex; // these are indexes into the boneReferences,
- float boneWeight; // not the global per-frame bone list
- vec3_t offset;
-} md4Weight_t;
-
-typedef struct {
- vec3_t normal;
- vec2_t texCoords;
- int numWeights;
- md4Weight_t weights[1]; // variable sized
-} md4Vertex_t;
-
-typedef struct {
- int indexes[3];
-} md4Triangle_t;
-
-typedef struct {
- int ident;
-
- char name[MAX_QPATH]; // polyset name
- char shader[MAX_QPATH];
- int shaderIndex; // for in-game use
-
- int ofsHeader; // this will be a negative number
-
- int numVerts;
- int ofsVerts;
-
- int numTriangles;
- int ofsTriangles;
-
- // Bone references are a set of ints representing all the bones
- // present in any vertex weights for this surface. This is
- // needed because a model may have surfaces that need to be
- // drawn at different sort times, and we don't want to have
- // to re-interpolate all the bones for each surface.
- int numBoneReferences;
- int ofsBoneReferences;
-
- int ofsEnd; // next surface follows
-} md4Surface_t;
-
-typedef struct {
- float matrix[3][4];
-} md4Bone_t;
-
-typedef struct {
- vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
- vec3_t localOrigin; // midpoint of bounds, used for sphere cull
- float radius; // dist from localOrigin to corner
- md4Bone_t bones[1]; // [numBones]
-} md4Frame_t;
-
-typedef struct {
- int numSurfaces;
- int ofsSurfaces; // first surface, others follow
- int ofsEnd; // next lod follows
-} md4LOD_t;
-
-typedef struct {
- int ident;
- int version;
-
- char name[MAX_QPATH]; // model name
-
- // frames and bones are shared by all levels of detail
- int numFrames;
- int numBones;
- int ofsBoneNames; // char name[ MAX_QPATH ]
- int ofsFrames; // md4Frame_t[numFrames]
-
- // each level of detail has completely separate sets of surfaces
- int numLODs;
- int ofsLODs;
-
- int ofsEnd; // end of file
-} md4Header_t;
-
/*
* Here are the definitions for Ravensoft's model format of md4. Raven stores their
* playermodels in .mdr files, in some games, which are pretty much like the md4
@@ -326,116 +201,108 @@ typedef struct {
* - Thilo Schulz (arny@ats.s.bawue.de)
*/
-// If you want to enable support for Raven's .mdr / md4 format, uncomment the next
-// line.
-//#define RAVENMD4
-
-#ifdef RAVENMD4
-
-#define MDR_IDENT (('5'<<24)+('M'<<16)+('D'<<8)+'R')
-#define MDR_VERSION 2
-#define MDR_MAX_BONES 128
+#define MDR_IDENT (('5' << 24) + ('M' << 16) + ('D' << 8) + 'R')
+#define MDR_VERSION 2
+#define MDR_MAX_BONES 128
typedef struct {
- int boneIndex; // these are indexes into the boneReferences,
- float boneWeight; // not the global per-frame bone list
- vec3_t offset;
+ int boneIndex; // these are indexes into the boneReferences,
+ float boneWeight; // not the global per-frame bone list
+ vec3_t offset;
} mdrWeight_t;
typedef struct {
- vec3_t normal;
- vec2_t texCoords;
- int numWeights;
- mdrWeight_t weights[1]; // variable sized
+ vec3_t normal;
+ vec2_t texCoords;
+ int numWeights;
+ mdrWeight_t weights[1]; // variable sized
} mdrVertex_t;
typedef struct {
- int indexes[3];
+ int indexes[3];
} mdrTriangle_t;
typedef struct {
- int ident;
+ int ident;
- char name[MAX_QPATH]; // polyset name
- char shader[MAX_QPATH];
- int shaderIndex; // for in-game use
+ char name[MAX_QPATH]; // polyset name
+ char shader[MAX_QPATH];
+ int shaderIndex; // for in-game use
- int ofsHeader; // this will be a negative number
+ int ofsHeader; // this will be a negative number
- int numVerts;
- int ofsVerts;
+ int numVerts;
+ int ofsVerts;
- int numTriangles;
- int ofsTriangles;
+ int numTriangles;
+ int ofsTriangles;
- // Bone references are a set of ints representing all the bones
- // present in any vertex weights for this surface. This is
- // needed because a model may have surfaces that need to be
- // drawn at different sort times, and we don't want to have
- // to re-interpolate all the bones for each surface.
- int numBoneReferences;
- int ofsBoneReferences;
+ // Bone references are a set of ints representing all the bones
+ // present in any vertex weights for this surface. This is
+ // needed because a model may have surfaces that need to be
+ // drawn at different sort times, and we don't want to have
+ // to re-interpolate all the bones for each surface.
+ int numBoneReferences;
+ int ofsBoneReferences;
- int ofsEnd; // next surface follows
+ int ofsEnd; // next surface follows
} mdrSurface_t;
typedef struct {
- float matrix[3][4];
+ float matrix[3][4];
} mdrBone_t;
typedef struct {
- vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
- vec3_t localOrigin; // midpoint of bounds, used for sphere cull
- float radius; // dist from localOrigin to corner
- char name[16];
- mdrBone_t bones[1]; // [numBones]
+ vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
+ vec3_t localOrigin; // midpoint of bounds, used for sphere cull
+ float radius; // dist from localOrigin to corner
+ char name[16];
+ mdrBone_t bones[1]; // [numBones]
} mdrFrame_t;
typedef struct {
- unsigned char Comp[24]; // MC_COMP_BYTES is in MatComp.h, but don't want to couple
+ unsigned char Comp[24]; // MC_COMP_BYTES is in MatComp.h, but don't want to couple
} mdrCompBone_t;
typedef struct {
- vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
- vec3_t localOrigin; // midpoint of bounds, used for sphere cull
- float radius; // dist from localOrigin to corner
- mdrCompBone_t bones[1]; // [numBones]
+ vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
+ vec3_t localOrigin; // midpoint of bounds, used for sphere cull
+ float radius; // dist from localOrigin to corner
+ mdrCompBone_t bones[1]; // [numBones]
} mdrCompFrame_t;
typedef struct {
- int numSurfaces;
- int ofsSurfaces; // first surface, others follow
- int ofsEnd; // next lod follows
+ int numSurfaces;
+ int ofsSurfaces; // first surface, others follow
+ int ofsEnd; // next lod follows
} mdrLOD_t;
typedef struct {
- int boneIndex;
- char name[32];
+ int boneIndex;
+ char name[32];
} mdrTag_t;
typedef struct {
- int ident;
- int version;
+ int ident;
+ int version;
- char name[MAX_QPATH]; // model name
+ char name[MAX_QPATH]; // model name
- // frames and bones are shared by all levels of detail
- int numFrames;
- int numBones;
- int ofsFrames; // mdrFrame_t[numFrames]
+ // frames and bones are shared by all levels of detail
+ int numFrames;
+ int numBones;
+ int ofsFrames; // mdrFrame_t[numFrames]
- // each level of detail has completely separate sets of surfaces
- int numLODs;
- int ofsLODs;
+ // each level of detail has completely separate sets of surfaces
+ int numLODs;
+ int ofsLODs;
- int numTags;
- int ofsTags;
+ int numTags;
+ int ofsTags;
- int ofsEnd; // end of file
+ int ofsEnd; // end of file
} mdrHeader_t;
-#endif
-
/*
==============================================================================
@@ -444,183 +311,172 @@ typedef struct {
==============================================================================
*/
+#define BSP_IDENT (('P' << 24) + ('S' << 16) + ('B' << 8) + 'I')
+// little-endian "IBSP"
-#define BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'I')
- // little-endian "IBSP"
-
-#define BSP_VERSION 46
-
+#define BSP_VERSION 46
// there shouldn't be any problem with increasing these values at the
// expense of more memory allocation in the utilities
-#define MAX_MAP_MODELS 0x400
-#define MAX_MAP_BRUSHES 0x8000
-#define MAX_MAP_ENTITIES 0x800
-#define MAX_MAP_ENTSTRING 0x40000
-#define MAX_MAP_SHADERS 0x400
-
-#define MAX_MAP_AREAS 0x100 // MAX_MAP_AREA_BYTES in q_shared must match!
-#define MAX_MAP_FOGS 0x100
-#define MAX_MAP_PLANES 0x20000
-#define MAX_MAP_NODES 0x20000
-#define MAX_MAP_BRUSHSIDES 0x20000
-#define MAX_MAP_LEAFS 0x20000
-#define MAX_MAP_LEAFFACES 0x20000
-#define MAX_MAP_LEAFBRUSHES 0x40000
-#define MAX_MAP_PORTALS 0x20000
-#define MAX_MAP_LIGHTING 0x800000
-#define MAX_MAP_LIGHTGRID 0x800000
-#define MAX_MAP_VISIBILITY 0x200000
-
-#define MAX_MAP_DRAW_SURFS 0x20000
-#define MAX_MAP_DRAW_VERTS 0x80000
-#define MAX_MAP_DRAW_INDEXES 0x80000
-
+#define MAX_MAP_MODELS 0x400
+#define MAX_MAP_BRUSHES 0x8000
+#define MAX_MAP_ENTITIES 0x800
+#define MAX_MAP_ENTSTRING 0x40000
+#define MAX_MAP_SHADERS 0x400
+
+#define MAX_MAP_AREAS 0x100 // MAX_MAP_AREA_BYTES in q_shared must match!
+#define MAX_MAP_FOGS 0x100
+#define MAX_MAP_PLANES 0x20000
+#define MAX_MAP_NODES 0x20000
+#define MAX_MAP_BRUSHSIDES 0x20000
+#define MAX_MAP_LEAFS 0x20000
+#define MAX_MAP_LEAFFACES 0x20000
+#define MAX_MAP_LEAFBRUSHES 0x40000
+#define MAX_MAP_PORTALS 0x20000
+#define MAX_MAP_LIGHTING 0x800000
+#define MAX_MAP_LIGHTGRID 0x800000
+#define MAX_MAP_VISIBILITY 0x200000
+
+#define MAX_MAP_DRAW_SURFS 0x20000
+#define MAX_MAP_DRAW_VERTS 0x80000
+#define MAX_MAP_DRAW_INDEXES 0x80000
// key / value pair sizes in the entities lump
-#define MAX_KEY 32
-#define MAX_VALUE 1024
+#define MAX_KEY 32
+#define MAX_VALUE 1024
// the editor uses these predefined yaw angles to orient entities up or down
-#define ANGLE_UP -1
-#define ANGLE_DOWN -2
+#define ANGLE_UP -1
+#define ANGLE_DOWN -2
-#define LIGHTMAP_WIDTH 128
-#define LIGHTMAP_HEIGHT 128
+#define LIGHTMAP_WIDTH 128
+#define LIGHTMAP_HEIGHT 128
-#define MAX_WORLD_COORD ( 128*1024 )
-#define MIN_WORLD_COORD ( -128*1024 )
-#define WORLD_SIZE ( MAX_WORLD_COORD - MIN_WORLD_COORD )
+#define MAX_WORLD_COORD (128 * 1024)
+#define MIN_WORLD_COORD (-128 * 1024)
+#define WORLD_SIZE (MAX_WORLD_COORD - MIN_WORLD_COORD)
//=============================================================================
-
typedef struct {
- int fileofs, filelen;
+ int fileofs, filelen;
} lump_t;
-#define LUMP_ENTITIES 0
-#define LUMP_SHADERS 1
-#define LUMP_PLANES 2
-#define LUMP_NODES 3
-#define LUMP_LEAFS 4
-#define LUMP_LEAFSURFACES 5
-#define LUMP_LEAFBRUSHES 6
-#define LUMP_MODELS 7
-#define LUMP_BRUSHES 8
-#define LUMP_BRUSHSIDES 9
-#define LUMP_DRAWVERTS 10
-#define LUMP_DRAWINDEXES 11
-#define LUMP_FOGS 12
-#define LUMP_SURFACES 13
-#define LUMP_LIGHTMAPS 14
-#define LUMP_LIGHTGRID 15
-#define LUMP_VISIBILITY 16
-#define HEADER_LUMPS 17
-
-typedef struct {
- int ident;
- int version;
-
- lump_t lumps[HEADER_LUMPS];
+#define LUMP_ENTITIES 0
+#define LUMP_SHADERS 1
+#define LUMP_PLANES 2
+#define LUMP_NODES 3
+#define LUMP_LEAFS 4
+#define LUMP_LEAFSURFACES 5
+#define LUMP_LEAFBRUSHES 6
+#define LUMP_MODELS 7
+#define LUMP_BRUSHES 8
+#define LUMP_BRUSHSIDES 9
+#define LUMP_DRAWVERTS 10
+#define LUMP_DRAWINDEXES 11
+#define LUMP_FOGS 12
+#define LUMP_SURFACES 13
+#define LUMP_LIGHTMAPS 14
+#define LUMP_LIGHTGRID 15
+#define LUMP_VISIBILITY 16
+#define HEADER_LUMPS 17
+
+typedef struct {
+ int ident;
+ int version;
+
+ lump_t lumps[HEADER_LUMPS];
} dheader_t;
typedef struct {
- float mins[3], maxs[3];
- int firstSurface, numSurfaces;
- int firstBrush, numBrushes;
+ float mins[3], maxs[3];
+ int firstSurface, numSurfaces;
+ int firstBrush, numBrushes;
} dmodel_t;
typedef struct {
- char shader[MAX_QPATH];
- int surfaceFlags;
- int contentFlags;
+ char shader[MAX_QPATH];
+ int surfaceFlags;
+ int contentFlags;
} dshader_t;
// planes x^1 is allways the opposite of plane x
typedef struct {
- float normal[3];
- float dist;
+ float normal[3];
+ float dist;
} dplane_t;
typedef struct {
- int planeNum;
- int children[2]; // negative numbers are -(leafs+1), not nodes
- int mins[3]; // for frustom culling
- int maxs[3];
+ int planeNum;
+ int children[2]; // negative numbers are -(leafs+1), not nodes
+ int mins[3]; // for frustom culling
+ int maxs[3];
} dnode_t;
typedef struct {
- int cluster; // -1 = opaque cluster (do I still store these?)
- int area;
+ int cluster; // -1 = opaque cluster (do I still store these?)
+ int area;
- int mins[3]; // for frustum culling
- int maxs[3];
+ int mins[3]; // for frustum culling
+ int maxs[3];
- int firstLeafSurface;
- int numLeafSurfaces;
+ int firstLeafSurface;
+ int numLeafSurfaces;
- int firstLeafBrush;
- int numLeafBrushes;
+ int firstLeafBrush;
+ int numLeafBrushes;
} dleaf_t;
typedef struct {
- int planeNum; // positive plane side faces out of the leaf
- int shaderNum;
+ int planeNum; // positive plane side faces out of the leaf
+ int shaderNum;
} dbrushside_t;
typedef struct {
- int firstSide;
- int numSides;
- int shaderNum; // the shader that determines the contents flags
+ int firstSide;
+ int numSides;
+ int shaderNum; // the shader that determines the contents flags
} dbrush_t;
typedef struct {
- char shader[MAX_QPATH];
- int brushNum;
- int visibleSide; // the brush side that ray tests need to clip against (-1 == none)
+ char shader[MAX_QPATH];
+ int brushNum;
+ int visibleSide; // the brush side that ray tests need to clip against (-1 == none)
} dfog_t;
typedef struct {
- vec3_t xyz;
- float st[2];
- float lightmap[2];
- vec3_t normal;
- byte color[4];
+ vec3_t xyz;
+ float st[2];
+ float lightmap[2];
+ vec3_t normal;
+ byte color[4];
} drawVert_t;
-#define drawVert_t_cleared(x) drawVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}}
+#define drawVert_t_cleared(x) drawVert_t(x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}}
-typedef enum {
- MST_BAD,
- MST_PLANAR,
- MST_PATCH,
- MST_TRIANGLE_SOUP,
- MST_FLARE
-} mapSurfaceType_t;
+typedef enum { MST_BAD, MST_PLANAR, MST_PATCH, MST_TRIANGLE_SOUP, MST_FLARE } mapSurfaceType_t;
typedef struct {
- int shaderNum;
- int fogNum;
- int surfaceType;
+ int shaderNum;
+ int fogNum;
+ int surfaceType;
- int firstVert;
- int numVerts;
+ int firstVert;
+ int numVerts;
- int firstIndex;
- int numIndexes;
+ int firstIndex;
+ int numIndexes;
- int lightmapNum;
- int lightmapX, lightmapY;
- int lightmapWidth, lightmapHeight;
+ int lightmapNum;
+ int lightmapX, lightmapY;
+ int lightmapWidth, lightmapHeight;
- vec3_t lightmapOrigin;
- vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds
+ vec3_t lightmapOrigin;
+ vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds
- int patchWidth;
- int patchHeight;
+ int patchWidth;
+ int patchHeight;
} dsurface_t;
-
#endif
diff --git a/src/qcommon/surfaceflags.h b/src/qcommon/surfaceflags.h
index 31ece5c..f47006d 100644
--- a/src/qcommon/surfaceflags.h
+++ b/src/qcommon/surfaceflags.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
//
@@ -60,10 +61,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define CONTENTS_TRIGGER 0x40000000
#define CONTENTS_NODROP 0x80000000 // don't leave bodies or items (death fog, lava)
-//TA: custominfoparms below
+// custominfoparms below
#define CONTENTS_NOALIENBUILD 0x1000 //disallow alien building
-#define CONTENTS_NOHUMANBUILD 0x2000 //disallow alien building
-#define CONTENTS_NOBUILD 0x4000 //disallow alien building
+#define CONTENTS_NOHUMANBUILD 0x2000 //disallow human building
+#define CONTENTS_NOBUILD 0x4000 //disallow building
#define SURF_NODAMAGE 0x1 // never give falling damage
#define SURF_SLICK 0x2 // effects game physics
@@ -85,7 +86,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define SURF_NODLIGHT 0x20000 // don't dlight even if solid (solid lava, skies)
#define SURF_DUST 0x40000 // leave a dust trail when walking on this surface
-//TA: custominfoparms below
+// custominfoparms below
#define SURF_NOALIENBUILD 0x80000 //disallow alien building
-#define SURF_NOHUMANBUILD 0x100000 //disallow alien building
-#define SURF_NOBUILD 0x200000 //disallow alien building
+#define SURF_NOHUMANBUILD 0x100000 //disallow human building
+#define SURF_NOBUILD 0x200000 //disallow building
diff --git a/src/qcommon/unzip.cpp b/src/qcommon/unzip.cpp
new file mode 100644
index 0000000..8564ece
--- /dev/null
+++ b/src/qcommon/unzip.cpp
@@ -0,0 +1,1951 @@
+/* unzip.c -- IO for uncompress .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project
+
+ Copyright (C) 1998-2010 Gilles Vollant
+ http://www.winimage.com/zLibDll/minizip.html
+ Modifications of Unzip for Zip64
+ Copyright (C) 2007-2008 Even Rouault
+ Modifications for Zip64 support on both zip and unzip
+ Copyright (C) 2009-2010 Mathias Svensson
+ http://result42.com
+ Modifications for AES, PKWARE disk spanning
+ Copyright (C) 2010-2014 Nathan Moinvaziri
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+
+ Mar 8th, 2016 - Lucio Cosmo
+ Fixed support for 64bit builds for archives with "PKWARE" password.
+ Changed long, unsigned long, unsigned to unsigned int in
+ access functions to crctables and pkeys
+*/
+
+#define NOUNCRYPT
+#include "unzip.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cstddef>
+
+#include "q_shared.h"
+#include "qcommon.h"
+
+#include "zconf.h"
+#include "zlib.h"
+
+#ifdef HAVE_AES
+# define AES_METHOD (99)
+# define AES_PWVERIFYSIZE (2)
+# define AES_MAXSALTLENGTH (16)
+# define AES_AUTHCODESIZE (10)
+# define AES_HEADERSIZE (11)
+# define AES_KEYSIZE(mode) (64 + (mode * 64))
+
+# include "aes/aes.h"
+# include "aes/fileenc.h"
+#endif
+#ifndef NOUNCRYPT
+# include "crypt.h"
+#endif
+
+#ifndef static
+# define static static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#define DISKHEADERMAGIC (0x08074b50)
+#define LOCALHEADERMAGIC (0x04034b50)
+#define CENTRALHEADERMAGIC (0x02014b50)
+#define ENDHEADERMAGIC (0x06054b50)
+#define ZIP64ENDHEADERMAGIC (0x06064b50)
+#define ZIP64ENDLOCHEADERMAGIC (0x07064b50)
+
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZECENTRALHEADERLOCATOR (0x14) /* 20 */
+#define SIZEZIPLOCALHEADER (0x1e)
+
+#ifndef BUFREADCOMMENT
+# define BUFREADCOMMENT (0x400)
+#endif
+
+#ifndef UNZ_BUFSIZE
+# define UNZ_BUFSIZE (64 * 1024)
+#endif
+#ifndef UNZ_MAXFILENAMEINZIP
+# define UNZ_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (Z_Malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) Z_Free(p);}
+#endif
+
+const char unz_copyright[] =
+ " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+
+/* unz_file_info_interntal contain internal info about a file in zipfile*/
+typedef struct unz_file_info64_internal_s
+{
+ ZPOS64_T offset_curfile; /* relative offset of static header 8 bytes */
+ ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */
+#ifdef HAVE_AES
+ uLong aes_encryption_mode;
+ uLong aes_compression_method;
+ uLong aes_version;
+#endif
+} unz_file_info64_internal;
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile */
+typedef struct
+{
+ Bytef *read_buffer; /* internal buffer for compressed data */
+ z_stream stream; /* zLib stream structure for inflate */
+
+#ifdef HAVE_BZIP2
+ bz_stream bstream; /* bzLib stream structure for bziped */
+#endif
+#ifdef HAVE_AES
+ fcrypt_ctx aes_ctx;
+#endif
+
+ ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek */
+ uLong stream_initialised; /* flag set if stream structure is initialised */
+
+ ZPOS64_T offset_local_extrafield; /* offset of the static extra field */
+ uInt size_local_extrafield; /* size of the static extra field */
+ ZPOS64_T pos_local_extrafield; /* position in the static extra field in read */
+ ZPOS64_T total_out_64;
+
+ uLong crc32; /* crc32 of all data uncompressed */
+ uLong crc32_wait; /* crc32 we must obtain after decompress all */
+ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */
+ ZPOS64_T rest_read_uncompressed; /* number of byte to be obtained after decomp */
+
+ zlib_filefunc64_32_def z_filefunc;
+
+ voidpf filestream; /* io structore of the zipfile */
+ uLong compression_method; /* compression method (0==store) */
+ ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */
+ int raw;
+} file_in_zip64_read_info_s;
+
+/* unz64_s contain internal information about the zipfile */
+typedef struct
+{
+ zlib_filefunc64_32_def z_filefunc;
+ voidpf filestream; /* io structure of the current zipfile */
+ voidpf filestream_with_CD; /* io structure of the disk with the central directory */
+ unz_global_info64 gi; /* public global information */
+ ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/
+ ZPOS64_T num_file; /* number of the current file in the zipfile*/
+ ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/
+ ZPOS64_T current_file_ok; /* flag about the usability of the current file*/
+ ZPOS64_T central_pos; /* position of the beginning of the central dir*/
+ uLong number_disk; /* number of the current disk, used for spanning ZIP*/
+ ZPOS64_T size_central_dir; /* size of the central directory */
+ ZPOS64_T offset_central_dir; /* offset of start of central directory with
+ respect to the starting disk number */
+
+ unz_file_info64 cur_file_info; /* public info about the current file in zip*/
+ unz_file_info64_internal cur_file_info_internal;
+ /* private info about it*/
+ file_in_zip64_read_info_s* pfile_in_zip_read;
+ /* structure about the current file if we are decompressing it */
+ int isZip64; /* is the current file zip64 */
+#ifndef NOUNCRYPT
+ unsigned int keys[3]; /* keys defining the pseudo-random sequence */
+ const unsigned int* pcrc_32_tab;
+#endif
+} unz64_s;
+
+/* Translate date/time from Dos format to tm_unz (readable more easily) */
+static void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm)
+{
+ ZPOS64_T uDate = (ZPOS64_T)(ulDosDate>>16);
+
+ ptm->tm_mday = (uInt)(uDate&0x1f);
+ ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1);
+ ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980);
+ ptm->tm_hour = (uInt)((ulDosDate &0xF800)/0x800);
+ ptm->tm_min = (uInt)((ulDosDate&0x7E0)/0x20);
+ ptm->tm_sec = (uInt)(2*(ulDosDate&0x1f));
+
+#define unz64local_in_range(min, max, value) ((min) <= (value) && (value) <= (max))
+ if (!unz64local_in_range(0, 11, ptm->tm_mon) ||
+ !unz64local_in_range(1, 31, ptm->tm_mday) ||
+ !unz64local_in_range(0, 23, ptm->tm_hour) ||
+ !unz64local_in_range(0, 59, ptm->tm_min) ||
+ !unz64local_in_range(0, 59, ptm->tm_sec))
+ /* Invalid date stored, so don't return it. */
+ memset(ptm, 0, sizeof(tm_unz));
+#undef unz64local_in_range
+}
+
+/* Read a byte from a gz_stream; Return EOF for end of file. */
+static int unz64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi));
+static int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)
+{
+ unsigned char c;
+ int err = (int)ZREAD64(*pzlib_filefunc_def, filestream, &c, 1);
+ if (err == 1)
+ {
+ *pi = (int)c;
+ return UNZ_OK;
+ }
+ *pi = 0;
+ if (ZERROR64(*pzlib_filefunc_def, filestream))
+ return UNZ_ERRNO;
+ return UNZ_EOF;
+}
+
+static int unz64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
+static int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)
+{
+ uLong x;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x = (uLong)i;
+ if (err == UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x |= ((uLong)i)<<8;
+
+ if (err == UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+static int unz64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
+static int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)
+{
+ uLong x;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x = (uLong)i;
+ if (err == UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x |= ((uLong)i)<<8;
+ if (err == UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x |= ((uLong)i)<<16;
+ if (err == UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x += ((uLong)i)<<24;
+
+ if (err == UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+static int unz64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX));
+static int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)
+{
+ ZPOS64_T x;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x = (ZPOS64_T)i;
+ if (err == UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x |= ((ZPOS64_T)i)<<8;
+ if (err == UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x |= ((ZPOS64_T)i)<<16;
+ if (err == UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x |= ((ZPOS64_T)i)<<24;
+ if (err == UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x |= ((ZPOS64_T)i)<<32;
+ if (err == UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x |= ((ZPOS64_T)i)<<40;
+ if (err == UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x |= ((ZPOS64_T)i)<<48;
+ if (err == UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def, filestream, &i);
+ x |= ((ZPOS64_T)i)<<56;
+
+ if (err == UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+/* Locate the Central directory of a zip file (at the end, just before the global comment) */
+static ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
+static ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T file_size;
+ ZPOS64_T back_read = 4;
+ ZPOS64_T max_back = 0xffff; /* maximum size of global comment */
+ ZPOS64_T pos_found = 0;
+ uLong read_size;
+ ZPOS64_T read_pos;
+ int i;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT + 4);
+ if (buf == NULL)
+ return 0;
+
+ if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0)
+ {
+ TRYFREE(buf);
+ return 0;
+ }
+
+ file_size = ZTELL64(*pzlib_filefunc_def, filestream);
+
+ if (max_back > file_size)
+ max_back = file_size;
+
+ while (back_read < max_back)
+ {
+ if (back_read + BUFREADCOMMENT > max_back)
+ back_read = max_back;
+ else
+ back_read += BUFREADCOMMENT;
+
+ read_pos = file_size - back_read;
+ read_size = ((BUFREADCOMMENT + 4) < (file_size - read_pos)) ?
+ (BUFREADCOMMENT + 4) : (uLong)(file_size - read_pos);
+
+ if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ break;
+ if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size)
+ break;
+
+ for (i = (int)read_size-3; (i--) > 0;)
+ if (((*(buf+i)) == (ENDHEADERMAGIC & 0xff)) &&
+ ((*(buf+i+1)) == (ENDHEADERMAGIC >> 8 & 0xff)) &&
+ ((*(buf+i+2)) == (ENDHEADERMAGIC >> 16 & 0xff)) &&
+ ((*(buf+i+3)) == (ENDHEADERMAGIC >> 24 & 0xff)))
+ {
+ pos_found = read_pos+i;
+ break;
+ }
+
+ if (pos_found != 0)
+ break;
+ }
+ TRYFREE(buf);
+ return pos_found;
+}
+
+/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */
+static ZPOS64_T unz64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream,
+ const ZPOS64_T endcentraloffset));
+static ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream,
+ const ZPOS64_T endcentraloffset)
+{
+ ZPOS64_T offset;
+ uLong uL;
+
+ /* Zip64 end of central directory locator */
+ if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ return 0;
+
+ /* read locator signature */
+ if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK)
+ return 0;
+ if (uL != ZIP64ENDLOCHEADERMAGIC)
+ return 0;
+ /* number of the disk with the start of the zip64 end of central directory */
+ if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK)
+ return 0;
+ /* relative offset of the zip64 end of central directory record */
+ if (unz64local_getLong64(pzlib_filefunc_def, filestream, &offset) != UNZ_OK)
+ return 0;
+ /* total number of disks */
+ if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK)
+ return 0;
+ /* Goto end of central directory record */
+ if (ZSEEK64(*pzlib_filefunc_def, filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ return 0;
+ /* the signature */
+ if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK)
+ return 0;
+ if (uL != ZIP64ENDHEADERMAGIC)
+ return 0;
+
+ return offset;
+}
+
+static unzFile unzOpenInternal(const void *path, zlib_filefunc64_32_def* pzlib_filefunc64_32_def)
+{
+ unz64_s us;
+ unz64_s *s;
+ ZPOS64_T central_pos;
+ ZPOS64_T central_pos64;
+ uLong uL;
+ ZPOS64_T uL64;
+ voidpf filestream = NULL;
+ ZPOS64_T number_entry_CD;
+ int err = UNZ_OK;
+
+ if (unz_copyright[0]!=' ')
+ return NULL;
+
+ us.filestream = NULL;
+ us.filestream_with_CD = NULL;
+ us.z_filefunc.zseek32_file = NULL;
+ us.z_filefunc.ztell32_file = NULL;
+ if (pzlib_filefunc64_32_def == NULL)
+ fill_fopen64_filefunc(&us.z_filefunc.zfile_func64);
+ else
+ us.z_filefunc = *pzlib_filefunc64_32_def;
+
+ us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
+
+ if (us.filestream == NULL)
+ return NULL;
+
+ us.filestream_with_CD = us.filestream;
+ us.isZip64 = 0;
+
+ /* Search for end of central directory header */
+ central_pos = unz64local_SearchCentralDir(&us.z_filefunc, us.filestream);
+ if (central_pos)
+ {
+ if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err = UNZ_ERRNO;
+
+ /* the signature, already checked */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ /* number of this disk */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ us.number_disk = uL;
+ /* number of the disk with the start of the central directory */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,& uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ us.gi.number_disk_with_CD = uL;
+ /* total number of entries in the central directory on this disk */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ us.gi.number_entry = uL;
+ /* total number of entries in the central directory */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ number_entry_CD = uL;
+ if (number_entry_CD != us.gi.number_entry)
+ err = UNZ_BADZIPFILE;
+ /* size of the central directory */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ us.size_central_dir = uL;
+ /* offset of start of central directory with respect to the starting disk number */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ us.offset_central_dir = uL;
+ /* zipfile comment length */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream, &us.gi.size_comment) != UNZ_OK)
+ err = UNZ_ERRNO;
+
+ if (err == UNZ_OK)
+ {
+ /* Search for Zip64 end of central directory header */
+ central_pos64 = unz64local_SearchCentralDir64(&us.z_filefunc, us.filestream, central_pos);
+ if (central_pos64)
+ {
+ central_pos = central_pos64;
+ us.isZip64 = 1;
+
+ if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err = UNZ_ERRNO;
+
+ /* the signature, already checked */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ /* size of zip64 end of central directory record */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream, &uL64) != UNZ_OK)
+ err = UNZ_ERRNO;
+ /* version made by */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ /* version needed to extract */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ /* number of this disk */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream, &us.number_disk) != UNZ_OK)
+ err = UNZ_ERRNO;
+ /* number of the disk with the start of the central directory */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream, &us.gi.number_disk_with_CD) != UNZ_OK)
+ err = UNZ_ERRNO;
+ /* total number of entries in the central directory on this disk */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.gi.number_entry) != UNZ_OK)
+ err = UNZ_ERRNO;
+ /* total number of entries in the central directory */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream, &number_entry_CD) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (number_entry_CD != us.gi.number_entry)
+ err = UNZ_BADZIPFILE;
+ /* size of the central directory */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.size_central_dir) != UNZ_OK)
+ err = UNZ_ERRNO;
+ /* offset of start of central directory with respect to the starting disk number */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.offset_central_dir) != UNZ_OK)
+ err = UNZ_ERRNO;
+ }
+ else if ((us.gi.number_entry == 0xffff) || (us.size_central_dir == 0xffff) || (us.offset_central_dir == 0xffffffff))
+ err = UNZ_BADZIPFILE;
+ }
+ }
+ else
+ err = UNZ_ERRNO;
+
+ if ((err == UNZ_OK) && (central_pos < us.offset_central_dir + us.size_central_dir))
+ err = UNZ_BADZIPFILE;
+
+ if (err != UNZ_OK)
+ {
+ ZCLOSE64(us.z_filefunc, us.filestream);
+ return NULL;
+ }
+
+ if (us.gi.number_disk_with_CD == 0)
+ {
+ /* If there is only one disk open another stream so we don't have to seek between the CD
+ and the file headers constantly */
+ filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
+ if (filestream != NULL)
+ us.filestream = filestream;
+ }
+
+ /* Hack for zip files that have no respect for zip64
+ if ((central_pos > 0xffffffff) && (us.offset_central_dir < 0xffffffff))
+ us.offset_central_dir = central_pos - us.size_central_dir;*/
+
+ us.byte_before_the_zipfile = central_pos - (us.offset_central_dir + us.size_central_dir);
+ us.central_pos = central_pos;
+ us.pfile_in_zip_read = NULL;
+
+ s = (unz64_s*)ALLOC(sizeof(unz64_s));
+ if (s != NULL)
+ {
+ *s = us;
+ unzGoToFirstFile((unzFile)s);
+ }
+ return (unzFile)s;
+}
+
+extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def* pzlib_filefunc32_def)
+{
+ if (pzlib_filefunc32_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def);
+ return unzOpenInternal(path, &zlib_filefunc64_32_def_fill);
+ }
+ return unzOpenInternal(path, NULL);
+}
+
+extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ if (pzlib_filefunc_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+ zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+ zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+ return unzOpenInternal(path, &zlib_filefunc64_32_def_fill);
+ }
+ return unzOpenInternal(path, NULL);
+}
+
+extern unzFile ZEXPORT unzOpen(const char *path)
+{
+ return unzOpenInternal(path, NULL);
+}
+
+extern unzFile ZEXPORT unzOpen64(const void *path)
+{
+ return unzOpenInternal(path, NULL);
+}
+
+extern int ZEXPORT unzClose(unzFile file)
+{
+ unz64_s* s;
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+
+ if (s->pfile_in_zip_read != NULL)
+ unzCloseCurrentFile(file);
+
+ if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD))
+ ZCLOSE64(s->z_filefunc, s->filestream);
+ if (s->filestream_with_CD != NULL)
+ ZCLOSE64(s->z_filefunc, s->filestream_with_CD);
+
+ s->filestream = NULL;
+ s->filestream_with_CD = NULL;
+ TRYFREE(s);
+ return UNZ_OK;
+}
+
+/* Goto to the next available disk for spanned archives */
+static int unzGoToNextDisk OF((unzFile file));
+static int unzGoToNextDisk(unzFile file)
+{
+ unz64_s* s;
+ uLong number_disk_next = 0;
+
+ s = (unz64_s*)file;
+ if (s == NULL)
+ return UNZ_PARAMERROR;
+ number_disk_next = s->number_disk;
+
+ if ((s->pfile_in_zip_read != NULL) && (s->pfile_in_zip_read->rest_read_uncompressed > 0))
+ /* We are currently reading a file and we need the next sequential disk */
+ number_disk_next += 1;
+ else
+ /* Goto the disk for the current file */
+ number_disk_next = s->cur_file_info.disk_num_start;
+
+ if (number_disk_next != s->number_disk)
+ {
+ /* Switch disks */
+ if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD))
+ ZCLOSE64(s->z_filefunc, s->filestream);
+
+ if (number_disk_next == s->gi.number_disk_with_CD)
+ {
+ s->filestream = s->filestream_with_CD;
+ }
+ else
+ {
+ s->filestream = ZOPENDISK64(s->z_filefunc, s->filestream_with_CD, number_disk_next,
+ ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
+ }
+
+ if (s->filestream == NULL)
+ return UNZ_ERRNO;
+
+ s->number_disk = number_disk_next;
+ }
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32)
+{
+ unz64_s* s;
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ /* to do : check if number_entry is not truncated */
+ pglobal_info32->number_entry = (uLong)s->gi.number_entry;
+ pglobal_info32->size_comment = s->gi.size_comment;
+ pglobal_info32->number_disk_with_CD = s->gi.number_disk_with_CD;
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64* pglobal_info)
+{
+ unz64_s* s;
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ *pglobal_info = s->gi;
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uLong comment_size)
+{
+ unz64_s* s;
+ uLong bytes_to_read = comment_size;
+ if (file == NULL)
+ return (int)UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+
+ if (bytes_to_read > s->gi.size_comment)
+ bytes_to_read = s->gi.size_comment;
+
+ if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, s->central_pos + 22, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ return UNZ_ERRNO;
+
+ if (bytes_to_read>0)
+ {
+ *comment = 0;
+ if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, bytes_to_read) != bytes_to_read)
+ return UNZ_ERRNO;
+ }
+
+ if ((comment != NULL) && (comment_size > s->gi.size_comment))
+ *(comment+s->gi.size_comment) = 0;
+ return (int)bytes_to_read;
+}
+
+/* Get Info about the current file in the zipfile, with internal only info */
+static int unz64local_GetCurrentFileInfoInternal(unzFile file, unz_file_info64 *pfile_info,
+ unz_file_info64_internal *pfile_info_internal, char *filename, uLong filename_size, void *extrafield,
+ uLong extrafield_size, char *comment, uLong comment_size)
+{
+ unz64_s* s;
+ unz_file_info64 file_info;
+ unz_file_info64_internal file_info_internal;
+ ZPOS64_T bytes_to_read;
+ int err = UNZ_OK;
+ uLong uMagic;
+ long lSeek = 0;
+ ZPOS64_T current_pos = 0;
+ uLong acc = 0;
+ uLong uL;
+ ZPOS64_T uL64;
+
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+
+ if (ZSEEK64(s->z_filefunc, s->filestream_with_CD,
+ s->pos_in_central_dir + s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err = UNZ_ERRNO;
+
+ /* Check the magic */
+ if (err == UNZ_OK)
+ {
+ if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uMagic) != UNZ_OK)
+ err = UNZ_ERRNO;
+ else if (uMagic != CENTRALHEADERMAGIC)
+ err = UNZ_BADZIPFILE;
+ }
+
+ /* Read central directory header */
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.version) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.version_needed) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.flag) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.compression_method) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.dosDate) != UNZ_OK)
+ err = UNZ_ERRNO;
+ unz64local_DosDateToTmuDate(file_info.dosDate, &file_info.tmu_date);
+ if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.crc) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ file_info.compressed_size = uL;
+ if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ file_info.uncompressed_size = uL;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_filename) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_extra) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_comment) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.internal_fa) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.external_fa) != UNZ_OK)
+ err = UNZ_ERRNO;
+ /* Relative offset of static header */
+ if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+
+ file_info.size_file_extra_internal = 0;
+ file_info.disk_offset = uL;
+ file_info_internal.offset_curfile = uL;
+#ifdef HAVE_AES
+ file_info_internal.aes_compression_method = 0;
+ file_info_internal.aes_encryption_mode = 0;
+ file_info_internal.aes_version = 0;
+#endif
+
+ lSeek += file_info.size_filename;
+
+ if ((err == UNZ_OK) && (filename != NULL))
+ {
+ if (file_info.size_filename < filename_size)
+ {
+ *(filename+file_info.size_filename) = 0;
+ bytes_to_read = file_info.size_filename;
+ }
+ else
+ bytes_to_read = filename_size;
+
+ if ((file_info.size_filename > 0) && (filename_size > 0))
+ if (ZREAD64(s->z_filefunc, s->filestream_with_CD,filename, (uLong)bytes_to_read) != bytes_to_read)
+ err = UNZ_ERRNO;
+ lSeek -= (uLong)bytes_to_read;
+ }
+
+ /* Read extrafield */
+ if ((err == UNZ_OK) && (extrafield != NULL))
+ {
+ if (file_info.size_file_extra < extrafield_size)
+ bytes_to_read = file_info.size_file_extra;
+ else
+ bytes_to_read = extrafield_size;
+
+ if (lSeek != 0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) == 0)
+ lSeek=0;
+ else
+ err = UNZ_ERRNO;
+ }
+
+ if ((file_info.size_file_extra > 0) && (extrafield_size > 0))
+ if (ZREAD64(s->z_filefunc, s->filestream_with_CD, extrafield, (uLong)bytes_to_read) != bytes_to_read)
+ err = UNZ_ERRNO;
+ lSeek += file_info.size_file_extra - (uLong)bytes_to_read;
+ }
+ else
+ lSeek += file_info.size_file_extra;
+
+ if ((err == UNZ_OK) && (file_info.size_file_extra != 0))
+ {
+ if (lSeek != 0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) == 0)
+ lSeek=0;
+ else
+ err = UNZ_ERRNO;
+ }
+
+ /* We are going to parse the extra field so we need to move back */
+ current_pos = ZTELL64(s->z_filefunc, s->filestream_with_CD);
+ if (current_pos < file_info.size_file_extra)
+ err = UNZ_ERRNO;
+ current_pos -= file_info.size_file_extra;
+ if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, current_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err = UNZ_ERRNO;
+
+ while((err != UNZ_ERRNO) && (acc < file_info.size_file_extra))
+ {
+ uLong headerid;
+ uLong datasize;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &headerid) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &datasize) != UNZ_OK)
+ err = UNZ_ERRNO;
+
+ /* ZIP64 extra fields */
+ if (headerid == 0x0001)
+ {
+ /* Subtract size of ZIP64 field, since ZIP64 is handled internally */
+ file_info.size_file_extra_internal += 2 + 2 + datasize;
+
+ if (file_info.uncompressed_size == 0xffffffff)
+ {
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &file_info.uncompressed_size) != UNZ_OK)
+ err = UNZ_ERRNO;
+ }
+ if (file_info.compressed_size == 0xffffffff)
+ {
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &file_info.compressed_size) != UNZ_OK)
+ err = UNZ_ERRNO;
+ }
+ if (file_info_internal.offset_curfile == 0xffffffff)
+ {
+ /* Relative Header offset */
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &uL64) != UNZ_OK)
+ err = UNZ_ERRNO;
+ file_info_internal.offset_curfile = uL64;
+ file_info.disk_offset = uL64;
+ }
+ if (file_info.disk_num_start == 0xffffffff)
+ {
+ /* Disk Start Number */
+ if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK)
+ err = UNZ_ERRNO;
+ }
+ }
+#ifdef HAVE_AES
+ /* AES header */
+ else if (headerid == 0x9901)
+ {
+ /* Subtract size of AES field, since AES is handled internally */
+ file_info.size_file_extra_internal += 2 + 2 + datasize;
+
+ /* Verify version info */
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ /* Support AE-1 and AE-2 */
+ if (uL != 1 && uL != 2)
+ err = UNZ_ERRNO;
+ file_info_internal.aes_version = uL;
+ if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if ((char)uL != 'A')
+ err = UNZ_ERRNO;
+ if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if ((char)uL != 'E')
+ err = UNZ_ERRNO;
+ /* Get AES encryption strength and actual compression method */
+ if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ file_info_internal.aes_encryption_mode = uL;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ file_info_internal.aes_compression_method = uL;
+ }
+#endif
+ else
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream_with_CD,datasize, ZLIB_FILEFUNC_SEEK_CUR) != 0)
+ err = UNZ_ERRNO;
+ }
+
+ acc += 2 + 2 + datasize;
+ }
+ }
+
+ if (file_info.disk_num_start == s->gi.number_disk_with_CD)
+ file_info_internal.byte_before_the_zipfile = s->byte_before_the_zipfile;
+ else
+ file_info_internal.byte_before_the_zipfile = 0;
+
+ if ((err == UNZ_OK) && (comment != NULL))
+ {
+ if (file_info.size_file_comment < comment_size)
+ {
+ *(comment+file_info.size_file_comment) = 0;
+ bytes_to_read = file_info.size_file_comment;
+ }
+ else
+ bytes_to_read = comment_size;
+
+ if (lSeek != 0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) != 0)
+ err = UNZ_ERRNO;
+ }
+
+ if ((file_info.size_file_comment > 0) && (comment_size > 0))
+ if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, (uLong)bytes_to_read) != bytes_to_read)
+ err = UNZ_ERRNO;
+ lSeek += file_info.size_file_comment - (uLong)bytes_to_read;
+ }
+ else
+ lSeek += file_info.size_file_comment;
+
+ if ((err == UNZ_OK) && (pfile_info != NULL))
+ *pfile_info = file_info;
+
+ if ((err == UNZ_OK) && (pfile_info_internal != NULL))
+ *pfile_info_internal = file_info_internal;
+
+ return err;
+}
+
+extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info * pfile_info, char *filename,
+ uLong filename_size, void *extrafield, uLong extrafield_size, char* comment, uLong comment_size)
+{
+ unz_file_info64 file_info64;
+ int err;
+
+ err = unz64local_GetCurrentFileInfoInternal(file, &file_info64, NULL, filename, filename_size,
+ extrafield, extrafield_size, comment, comment_size);
+
+ if ((err == UNZ_OK) && (pfile_info != NULL))
+ {
+ pfile_info->version = file_info64.version;
+ pfile_info->version_needed = file_info64.version_needed;
+ pfile_info->flag = file_info64.flag;
+ pfile_info->compression_method = file_info64.compression_method;
+ pfile_info->dosDate = file_info64.dosDate;
+ pfile_info->crc = file_info64.crc;
+
+ pfile_info->size_filename = file_info64.size_filename;
+ pfile_info->size_file_extra = file_info64.size_file_extra - file_info64.size_file_extra_internal;
+ pfile_info->size_file_comment = file_info64.size_file_comment;
+
+ pfile_info->disk_num_start = file_info64.disk_num_start;
+ pfile_info->internal_fa = file_info64.internal_fa;
+ pfile_info->external_fa = file_info64.external_fa;
+
+ pfile_info->tmu_date = file_info64.tmu_date,
+
+ pfile_info->compressed_size = (uLong)file_info64.compressed_size;
+ pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size;
+
+ }
+ return err;
+}
+
+extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename,
+ uLong filename_size, void *extrafield, uLong extrafield_size, char* comment, uLong comment_size)
+{
+ return unz64local_GetCurrentFileInfoInternal(file, pfile_info, NULL, filename, filename_size,
+ extrafield, extrafield_size, comment,comment_size);
+}
+
+/* Read the static header of the current zipfile. Check the coherency of the static header and info in the
+ end of central directory about this file store in *piSizeVar the size of extra info in static header
+ (filename and size of extra field data) */
+static int unz64local_CheckCurrentFileCoherencyHeader(unz64_s* s, uInt* piSizeVar, ZPOS64_T *poffset_local_extrafield,
+ uInt *psize_local_extrafield)
+{
+ uLong uMagic, uL, uFlags;
+ uLong size_filename;
+ uLong size_extra_field;
+ int err = UNZ_OK;
+ int compression_method = 0;
+
+ *piSizeVar = 0;
+ *poffset_local_extrafield = 0;
+ *psize_local_extrafield = 0;
+
+ err = unzGoToNextDisk((unzFile)s);
+ if (err != UNZ_OK)
+ return err;
+
+ if (ZSEEK64(s->z_filefunc, s->filestream, s->cur_file_info_internal.offset_curfile +
+ s->cur_file_info_internal.byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ return UNZ_ERRNO;
+
+ if (err == UNZ_OK)
+ {
+ if (unz64local_getLong(&s->z_filefunc, s->filestream, &uMagic) != UNZ_OK)
+ err = UNZ_ERRNO;
+ else if (uMagic != LOCALHEADERMAGIC)
+ err = UNZ_BADZIPFILE;
+ }
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream, &uFlags) != UNZ_OK)
+ err = UNZ_ERRNO;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream, &uL) != UNZ_OK)
+ err = UNZ_ERRNO;
+ else if ((err == UNZ_OK) && (uL != s->cur_file_info.compression_method))
+ err = UNZ_BADZIPFILE;
+
+ compression_method = (int)s->cur_file_info.compression_method;
+#ifdef HAVE_AES
+ if (compression_method == AES_METHOD)
+ compression_method = (int)s->cur_file_info_internal.aes_compression_method;
+#endif
+
+ if ((err == UNZ_OK) && (compression_method != 0) &&
+#ifdef HAVE_BZIP2
+ (compression_method != Z_BZIP2ED) &&
+#endif
+ (compression_method != Z_DEFLATED))
+ err = UNZ_BADZIPFILE;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* date/time */
+ err = UNZ_ERRNO;
+ if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* crc */
+ err = UNZ_ERRNO;
+ else if ((err == UNZ_OK) && (uL != s->cur_file_info.crc) && ((uFlags & 8) == 0))
+ err = UNZ_BADZIPFILE;
+ if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* size compr */
+ err = UNZ_ERRNO;
+ else if ((uL != 0xffffffff) && (err == UNZ_OK) && (uL != s->cur_file_info.compressed_size) && ((uFlags & 8) == 0))
+ err = UNZ_BADZIPFILE;
+ if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* size uncompr */
+ err = UNZ_ERRNO;
+ else if ((uL != 0xffffffff) && (err == UNZ_OK) && (uL != s->cur_file_info.uncompressed_size) && ((uFlags & 8) == 0))
+ err = UNZ_BADZIPFILE;
+ if (unz64local_getShort(&s->z_filefunc, s->filestream, &size_filename) != UNZ_OK)
+ err = UNZ_ERRNO;
+ else if ((err == UNZ_OK) && (size_filename != s->cur_file_info.size_filename))
+ err = UNZ_BADZIPFILE;
+
+ *piSizeVar += (uInt)size_filename;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream, &size_extra_field) != UNZ_OK)
+ err = UNZ_ERRNO;
+ *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename;
+ *psize_local_extrafield = (uInt)size_extra_field;
+
+ *piSizeVar += (uInt)size_extra_field;
+
+ return err;
+}
+
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int* method, int* level, int raw, const char* password)
+{
+ int err = UNZ_OK;
+ int compression_method;
+ uInt iSizeVar;
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ ZPOS64_T offset_local_extrafield;
+ uInt size_local_extrafield;
+#ifndef NOUNCRYPT
+ char source[12];
+#else
+ if (password != NULL)
+ return UNZ_PARAMERROR;
+#endif
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_PARAMERROR;
+
+ if (s->pfile_in_zip_read != NULL)
+ unzCloseCurrentFile(file);
+
+ if (unz64local_CheckCurrentFileCoherencyHeader(s, &iSizeVar, &offset_local_extrafield, &size_local_extrafield) != UNZ_OK)
+ return UNZ_BADZIPFILE;
+
+ pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));
+ if (pfile_in_zip_read_info == NULL)
+ return UNZ_INTERNALERROR;
+
+ pfile_in_zip_read_info->read_buffer = (Bytef*)ALLOC(UNZ_BUFSIZE);
+ pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+ pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+ pfile_in_zip_read_info->pos_local_extrafield = 0;
+ pfile_in_zip_read_info->raw = raw;
+
+ if (pfile_in_zip_read_info->read_buffer == NULL)
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return UNZ_INTERNALERROR;
+ }
+
+ pfile_in_zip_read_info->stream_initialised = 0;
+
+ compression_method = (int)s->cur_file_info.compression_method;
+#ifdef HAVE_AES
+ if (compression_method == AES_METHOD)
+ compression_method = (int)s->cur_file_info_internal.aes_compression_method;
+#endif
+
+ if (method != NULL)
+ *method = compression_method;
+
+ if (level != NULL)
+ {
+ *level = 6;
+ switch (s->cur_file_info.flag & 0x06)
+ {
+ case 6 : *level = 1; break;
+ case 4 : *level = 2; break;
+ case 2 : *level = 9; break;
+ }
+ }
+
+ if ((compression_method != 0) &&
+#ifdef HAVE_BZIP2
+ (compression_method != Z_BZIP2ED) &&
+#endif
+ (compression_method != Z_DEFLATED))
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return UNZ_BADZIPFILE;
+ }
+
+ pfile_in_zip_read_info->crc32_wait = s->cur_file_info.crc;
+ pfile_in_zip_read_info->crc32 = 0;
+ pfile_in_zip_read_info->total_out_64 = 0;
+ pfile_in_zip_read_info->compression_method = compression_method;
+ pfile_in_zip_read_info->filestream = s->filestream;
+ pfile_in_zip_read_info->z_filefunc = s->z_filefunc;
+ if (s->number_disk == s->gi.number_disk_with_CD)
+ pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile;
+ else
+ pfile_in_zip_read_info->byte_before_the_zipfile = 0;
+ pfile_in_zip_read_info->stream.total_out = 0;
+ pfile_in_zip_read_info->stream.total_in = 0;
+ pfile_in_zip_read_info->stream.next_in = NULL;
+
+ if (!raw)
+ {
+ if (compression_method == Z_BZIP2ED)
+ {
+#ifdef HAVE_BZIP2
+ pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
+ pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
+ pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->bstream.state = (voidpf)0;
+
+ pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+ pfile_in_zip_read_info->stream.zfree = (free_func)0;
+ pfile_in_zip_read_info->stream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->stream.next_in = (voidpf)0;
+ pfile_in_zip_read_info->stream.avail_in = 0;
+
+ err = BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
+ if (err == Z_OK)
+ pfile_in_zip_read_info->stream_initialised = Z_BZIP2ED;
+ else
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return err;
+ }
+#else
+ pfile_in_zip_read_info->raw = 1;
+#endif
+ }
+ else if (compression_method == Z_DEFLATED)
+ {
+ pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+ pfile_in_zip_read_info->stream.zfree = (free_func)0;
+ pfile_in_zip_read_info->stream.opaque = (voidpf)s;
+ pfile_in_zip_read_info->stream.next_in = 0;
+ pfile_in_zip_read_info->stream.avail_in = 0;
+
+ err = inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+ if (err == Z_OK)
+ pfile_in_zip_read_info->stream_initialised = Z_DEFLATED;
+ else
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return err;
+ }
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END.
+ * In unzip, i don't wait absolutely Z_STREAM_END because I known the
+ * size of both compressed and uncompressed data
+ */
+ }
+ }
+
+ pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size;
+ pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size;
+ pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar;
+ pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+
+ s->pfile_in_zip_read = pfile_in_zip_read_info;
+
+#ifndef NOUNCRYPT
+ s->pcrc_32_tab = NULL;
+
+ if ((password != NULL) && ((s->cur_file_info.flag & 1) != 0))
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,
+ s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET) != 0)
+ return UNZ_INTERNALERROR;
+#ifdef HAVE_AES
+ if (s->cur_file_info.compression_method == AES_METHOD)
+ {
+ unsigned char passverify_archive[AES_PWVERIFYSIZE];
+ unsigned char passverify_password[AES_PWVERIFYSIZE];
+ unsigned char saltvalue[AES_MAXSALTLENGTH];
+ uInt saltlength;
+
+ if ((s->cur_file_info_internal.aes_encryption_mode < 1) ||
+ (s->cur_file_info_internal.aes_encryption_mode > 3))
+ return UNZ_INTERNALERROR;
+
+ saltlength = SALT_LENGTH(s->cur_file_info_internal.aes_encryption_mode);
+
+ if (ZREAD64(s->z_filefunc, s->filestream, saltvalue, saltlength) != saltlength)
+ return UNZ_INTERNALERROR;
+ if (ZREAD64(s->z_filefunc, s->filestream, passverify_archive, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE)
+ return UNZ_INTERNALERROR;
+
+ fcrypt_init(s->cur_file_info_internal.aes_encryption_mode, password, strlen(password), saltvalue,
+ passverify_password, &s->pfile_in_zip_read->aes_ctx);
+
+ if (memcmp(passverify_archive, passverify_password, AES_PWVERIFYSIZE) != 0)
+ return UNZ_BADPASSWORD;
+
+ s->pfile_in_zip_read->rest_read_compressed -= saltlength + AES_PWVERIFYSIZE;
+ s->pfile_in_zip_read->rest_read_compressed -= AES_AUTHCODESIZE;
+
+ s->pfile_in_zip_read->pos_in_zipfile += saltlength + AES_PWVERIFYSIZE;
+ }
+ else
+#endif
+ {
+ int i;
+ s->pcrc_32_tab = (const unsigned int*)get_crc_table();
+ init_keys(password, s->keys, s->pcrc_32_tab);
+
+ if (ZREAD64(s->z_filefunc, s->filestream, source, 12) < 12)
+ return UNZ_INTERNALERROR;
+
+ for (i = 0; i < 12; i++)
+ zdecode(s->keys, s->pcrc_32_tab, source[i]);
+
+ s->pfile_in_zip_read->rest_read_compressed -= 12;
+
+ s->pfile_in_zip_read->pos_in_zipfile += 12;
+ }
+ }
+#endif
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzOpenCurrentFile(unzFile file)
+{
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
+}
+
+extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char* password)
+{
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
+}
+
+extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int* method, int* level, int raw)
+{
+ return unzOpenCurrentFile3(file, method, level, raw, NULL);
+}
+
+/* Read bytes from the current file.
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if some bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */
+extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len)
+{
+ int err = UNZ_OK;
+ uInt read = 0;
+ unz64_s* s;
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+
+ if (s->pfile_in_zip_read == NULL)
+ return UNZ_PARAMERROR;
+ if (s->pfile_in_zip_read->read_buffer == NULL)
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (len == 0)
+ return 0;
+
+ s->pfile_in_zip_read->stream.next_out = (Bytef*)buf;
+ s->pfile_in_zip_read->stream.avail_out = (uInt)len;
+
+ if (s->pfile_in_zip_read->raw)
+ {
+ if (len > s->pfile_in_zip_read->rest_read_compressed + s->pfile_in_zip_read->stream.avail_in)
+ s->pfile_in_zip_read->stream.avail_out = (uInt)s->pfile_in_zip_read->rest_read_compressed +
+ s->pfile_in_zip_read->stream.avail_in;
+ }
+ else
+ {
+ if (len > s->pfile_in_zip_read->rest_read_uncompressed)
+ s->pfile_in_zip_read->stream.avail_out = (uInt)s->pfile_in_zip_read->rest_read_uncompressed;
+ }
+
+ while (s->pfile_in_zip_read->stream.avail_out > 0)
+ {
+ if (s->pfile_in_zip_read->stream.avail_in == 0)
+ {
+ uLong bytes_to_read = UNZ_BUFSIZE;
+ uLong bytes_not_read = 0;
+ uLong bytes_read = 0;
+ uLong total_bytes_read = 0;
+
+ if (s->pfile_in_zip_read->stream.next_in != NULL)
+ bytes_not_read = s->pfile_in_zip_read->read_buffer + UNZ_BUFSIZE -
+ s->pfile_in_zip_read->stream.next_in;
+ bytes_to_read -= bytes_not_read;
+ if (bytes_not_read > 0)
+ memcpy(s->pfile_in_zip_read->read_buffer, s->pfile_in_zip_read->stream.next_in, bytes_not_read);
+ if (s->pfile_in_zip_read->rest_read_compressed < bytes_to_read)
+ bytes_to_read = (uInt)s->pfile_in_zip_read->rest_read_compressed;
+
+ while (total_bytes_read != bytes_to_read)
+ {
+ if (ZSEEK64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
+ s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET) != 0)
+ return UNZ_ERRNO;
+
+ bytes_read = ZREAD64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
+ s->pfile_in_zip_read->read_buffer + bytes_not_read + total_bytes_read,
+ bytes_to_read - total_bytes_read);
+
+ total_bytes_read += bytes_read;
+ s->pfile_in_zip_read->pos_in_zipfile += bytes_read;
+
+ if (bytes_read == 0)
+ {
+ if (ZERROR64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream))
+ return UNZ_ERRNO;
+
+ err = unzGoToNextDisk(file);
+ if (err != UNZ_OK)
+ return err;
+
+ s->pfile_in_zip_read->pos_in_zipfile = 0;
+ s->pfile_in_zip_read->filestream = s->filestream;
+ }
+ }
+
+#ifndef NOUNCRYPT
+ if ((s->cur_file_info.flag & 1) != 0)
+ {
+#ifdef HAVE_AES
+ if (s->cur_file_info.compression_method == AES_METHOD)
+ {
+ fcrypt_decrypt(s->pfile_in_zip_read->read_buffer, bytes_to_read, &s->pfile_in_zip_read->aes_ctx);
+ }
+ else
+#endif
+ if (s->pcrc_32_tab != NULL)
+ {
+ uInt i;
+ for(i = 0; i < total_bytes_read; i++)
+ s->pfile_in_zip_read->read_buffer[i] =
+ zdecode(s->keys, s->pcrc_32_tab, s->pfile_in_zip_read->read_buffer[i]);
+ }
+ }
+#endif
+
+ s->pfile_in_zip_read->rest_read_compressed -= total_bytes_read;
+ s->pfile_in_zip_read->stream.next_in = (Bytef*)s->pfile_in_zip_read->read_buffer;
+ s->pfile_in_zip_read->stream.avail_in = (uInt)(bytes_not_read + total_bytes_read);
+ }
+
+ if ((s->pfile_in_zip_read->compression_method == 0) || (s->pfile_in_zip_read->raw))
+ {
+ uInt copy, i;
+
+ if ((s->pfile_in_zip_read->stream.avail_in == 0) &&
+ (s->pfile_in_zip_read->rest_read_compressed == 0))
+ return (read == 0) ? UNZ_EOF : read;
+
+ if (s->pfile_in_zip_read->stream.avail_out < s->pfile_in_zip_read->stream.avail_in)
+ copy = s->pfile_in_zip_read->stream.avail_out;
+ else
+ copy = s->pfile_in_zip_read->stream.avail_in;
+
+ for (i = 0; i < copy; i++)
+ *(s->pfile_in_zip_read->stream.next_out+i) =
+ *(s->pfile_in_zip_read->stream.next_in+i);
+
+ s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + copy;
+ s->pfile_in_zip_read->rest_read_uncompressed -= copy;
+ s->pfile_in_zip_read->crc32 = crc32(s->pfile_in_zip_read->crc32,
+ s->pfile_in_zip_read->stream.next_out, copy);
+
+ s->pfile_in_zip_read->stream.avail_in -= copy;
+ s->pfile_in_zip_read->stream.avail_out -= copy;
+ s->pfile_in_zip_read->stream.next_out += copy;
+ s->pfile_in_zip_read->stream.next_in += copy;
+ s->pfile_in_zip_read->stream.total_out += copy;
+ read += copy;
+ }
+ else if (s->pfile_in_zip_read->compression_method == Z_BZIP2ED)
+ {
+#ifdef HAVE_BZIP2
+ uLong total_out_before, total_out_after;
+ const Bytef *buf_before;
+ uLong out_bytes;
+
+ s->pfile_in_zip_read->bstream.next_in = (char*)s->pfile_in_zip_read->stream.next_in;
+ s->pfile_in_zip_read->bstream.avail_in = s->pfile_in_zip_read->stream.avail_in;
+ s->pfile_in_zip_read->bstream.total_in_lo32 = (uInt)s->pfile_in_zip_read->stream.total_in;
+ s->pfile_in_zip_read->bstream.total_in_hi32 = s->pfile_in_zip_read->stream.total_in >> 32;
+
+ s->pfile_in_zip_read->bstream.next_out = (char*)s->pfile_in_zip_read->stream.next_out;
+ s->pfile_in_zip_read->bstream.avail_out = s->pfile_in_zip_read->stream.avail_out;
+ s->pfile_in_zip_read->bstream.total_out_lo32 = (uInt)s->pfile_in_zip_read->stream.total_out;
+ s->pfile_in_zip_read->bstream.total_out_hi32 = s->pfile_in_zip_read->stream.total_out >> 32;
+
+ total_out_before = s->pfile_in_zip_read->bstream.total_out_lo32 +
+ (((uLong)s->pfile_in_zip_read->bstream.total_out_hi32) << 32);
+ buf_before = (const Bytef *)s->pfile_in_zip_read->bstream.next_out;
+
+ err = BZ2_bzDecompress(&s->pfile_in_zip_read->bstream);
+
+ total_out_after = s->pfile_in_zip_read->bstream.total_out_lo32 +
+ (((uLong)s->pfile_in_zip_read->bstream.total_out_hi32) << 32);
+
+ out_bytes = total_out_after-total_out_before;
+
+ s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + out_bytes;
+ s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
+ s->pfile_in_zip_read->crc32 = crc32(s->pfile_in_zip_read->crc32,buf_before, (uInt)(out_bytes));
+
+ read += (uInt)(total_out_after - total_out_before);
+
+ s->pfile_in_zip_read->stream.next_in = (Bytef*)s->pfile_in_zip_read->bstream.next_in;
+ s->pfile_in_zip_read->stream.avail_in = s->pfile_in_zip_read->bstream.avail_in;
+ s->pfile_in_zip_read->stream.total_in = s->pfile_in_zip_read->bstream.total_in_lo32;
+ s->pfile_in_zip_read->stream.next_out = (Bytef*)s->pfile_in_zip_read->bstream.next_out;
+ s->pfile_in_zip_read->stream.avail_out = s->pfile_in_zip_read->bstream.avail_out;
+ s->pfile_in_zip_read->stream.total_out = s->pfile_in_zip_read->bstream.total_out_lo32;
+
+ if (err == BZ_STREAM_END)
+ return (read == 0) ? UNZ_EOF : read;
+ if (err != BZ_OK)
+ break;
+#endif
+ }
+ else
+ {
+ ZPOS64_T total_out_before, total_out_after;
+ const Bytef *buf_before;
+ ZPOS64_T out_bytes;
+ int flush=Z_SYNC_FLUSH;
+
+ total_out_before = s->pfile_in_zip_read->stream.total_out;
+ buf_before = s->pfile_in_zip_read->stream.next_out;
+
+ /*
+ if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+ pfile_in_zip_read_info->stream.avail_out) &&
+ (pfile_in_zip_read_info->rest_read_compressed == 0))
+ flush = Z_FINISH;
+ */
+ err = inflate(&s->pfile_in_zip_read->stream,flush);
+
+ if ((err >= 0) && (s->pfile_in_zip_read->stream.msg != NULL))
+ err = Z_DATA_ERROR;
+
+ total_out_after = s->pfile_in_zip_read->stream.total_out;
+ out_bytes = total_out_after-total_out_before;
+
+ s->pfile_in_zip_read->total_out_64 += out_bytes;
+ s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
+ s->pfile_in_zip_read->crc32 =
+ crc32(s->pfile_in_zip_read->crc32,buf_before, (uInt)(out_bytes));
+
+ read += (uInt)(total_out_after - total_out_before);
+
+ if (err == Z_STREAM_END)
+ return (read == 0) ? UNZ_EOF : read;
+ if (err != Z_OK)
+ break;
+ }
+ }
+
+ if (err == Z_OK)
+ return read;
+ return err;
+}
+
+extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file)
+{
+ unz64_s* s;
+ s = (unz64_s*)file;
+ if (file == NULL)
+ return 0; /* UNZ_PARAMERROR */
+ if (s->pfile_in_zip_read == NULL)
+ return 0; /* UNZ_PARAMERROR */
+ return s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile;
+}
+
+extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len)
+{
+ unz64_s* s;
+ uInt read_now;
+ ZPOS64_T size_to_read;
+
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ if (s->pfile_in_zip_read == NULL)
+ return UNZ_PARAMERROR;
+
+ size_to_read = s->pfile_in_zip_read->size_local_extrafield - s->pfile_in_zip_read->pos_local_extrafield;
+
+ if (buf == NULL)
+ return (int)size_to_read;
+
+ if (len > size_to_read)
+ read_now = (uInt)size_to_read;
+ else
+ read_now = (uInt)len ;
+
+ if (read_now == 0)
+ return 0;
+
+ if (ZSEEK64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
+ s->pfile_in_zip_read->offset_local_extrafield + s->pfile_in_zip_read->pos_local_extrafield,
+ ZLIB_FILEFUNC_SEEK_SET) != 0)
+ return UNZ_ERRNO;
+
+ if (ZREAD64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream, buf, read_now) != read_now)
+ return UNZ_ERRNO;
+
+ return (int)read_now;
+}
+
+extern int ZEXPORT unzCloseCurrentFile(unzFile file)
+{
+ int err = UNZ_OK;
+
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info == NULL)
+ return UNZ_PARAMERROR;
+
+#ifdef HAVE_AES
+ if (s->cur_file_info.compression_method == AES_METHOD)
+ {
+ unsigned char authcode[AES_AUTHCODESIZE];
+ unsigned char rauthcode[AES_AUTHCODESIZE];
+
+ if (ZREAD64(s->z_filefunc, s->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE)
+ return UNZ_ERRNO;
+
+ if (fcrypt_end(rauthcode, &s->pfile_in_zip_read->aes_ctx) != AES_AUTHCODESIZE)
+ err = UNZ_CRCERROR;
+ if (memcmp(authcode, rauthcode, AES_AUTHCODESIZE) != 0)
+ err = UNZ_CRCERROR;
+ }
+ /* AES zip version AE-1 will expect a valid crc as well */
+ if ((s->cur_file_info.compression_method != AES_METHOD) ||
+ (s->cur_file_info_internal.aes_version == 0x0001))
+#endif
+ {
+ if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
+ (!pfile_in_zip_read_info->raw))
+ {
+ if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
+ err = UNZ_CRCERROR;
+ }
+ }
+
+ TRYFREE(pfile_in_zip_read_info->read_buffer);
+ pfile_in_zip_read_info->read_buffer = NULL;
+ if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
+ inflateEnd(&pfile_in_zip_read_info->stream);
+#ifdef HAVE_BZIP2
+ else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
+ BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
+#endif
+
+ pfile_in_zip_read_info->stream_initialised = 0;
+ TRYFREE(pfile_in_zip_read_info);
+
+ s->pfile_in_zip_read = NULL;
+
+ return err;
+}
+
+extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
+ uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)
+{
+ int err = UNZ_OK;
+ unz64_s* s;
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ s->pos_in_central_dir = s->offset_central_dir;
+ s->num_file = 0;
+ err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal,
+ filename,filename_size, extrafield,extrafield_size, comment,comment_size);
+ s->current_file_ok = (err == UNZ_OK);
+ if ((err == UNZ_OK) && (pfile_info != NULL))
+ memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64));
+ return err;
+}
+
+extern int ZEXPORT unzGoToFirstFile(unzFile file)
+{
+ return unzGoToFirstFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0);
+}
+
+extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
+ uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)
+{
+ unz64_s* s;
+ int err;
+
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */
+ if (s->num_file+1 == s->gi.number_entry)
+ return UNZ_END_OF_LIST_OF_FILE;
+ s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+ s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment;
+ s->num_file++;
+ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal,
+ filename, filename_size, extrafield,extrafield_size, comment,comment_size);
+ s->current_file_ok = (err == UNZ_OK);
+ if ((err == UNZ_OK) && (pfile_info != NULL))
+ memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64));
+ return err;
+}
+
+extern int ZEXPORT unzGoToNextFile(unzFile file)
+{
+ return unzGoToNextFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0);
+}
+
+extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func)
+{
+ unz64_s* s;
+ int err;
+ unz_file_info64 cur_file_info_saved;
+ unz_file_info64_internal cur_file_info_internal_saved;
+ ZPOS64_T num_file_saved;
+ ZPOS64_T pos_in_central_dir_saved;
+ char current_filename[UNZ_MAXFILENAMEINZIP+1];
+
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ if (strlen(filename) >= UNZ_MAXFILENAMEINZIP)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ /* Save the current state */
+ num_file_saved = s->num_file;
+ pos_in_central_dir_saved = s->pos_in_central_dir;
+ cur_file_info_saved = s->cur_file_info;
+ cur_file_info_internal_saved = s->cur_file_info_internal;
+
+ err = unzGoToFirstFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0);
+
+ while (err == UNZ_OK)
+ {
+ if (filename_compare_func != NULL)
+ err = filename_compare_func(file, current_filename, filename);
+ else
+ err = strcmp(current_filename, filename);
+ if (err == 0)
+ return UNZ_OK;
+ err = unzGoToNextFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0);
+ }
+
+ /* We failed, so restore the state of the 'current file' to where we were. */
+ s->num_file = num_file_saved;
+ s->pos_in_central_dir = pos_in_central_dir_saved;
+ s->cur_file_info = cur_file_info_saved;
+ s->cur_file_info_internal = cur_file_info_internal_saved;
+ return err;
+}
+
+extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos* file_pos)
+{
+ unz64_file_pos file_pos64;
+ int err = unzGetFilePos64(file,&file_pos64);
+ if (err == UNZ_OK)
+ {
+ file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory;
+ file_pos->num_of_file = (uLong)file_pos64.num_of_file;
+ }
+ return err;
+}
+
+extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos* file_pos)
+{
+ unz64_file_pos file_pos64;
+
+ if (file_pos == NULL)
+ return UNZ_PARAMERROR;
+ file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
+ file_pos64.num_of_file = file_pos->num_of_file;
+ return unzGoToFilePos64(file,&file_pos64);
+}
+
+extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos)
+{
+ unz64_s* s;
+
+ if (file == NULL || file_pos == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ file_pos->pos_in_zip_directory = s->pos_in_central_dir;
+ file_pos->num_of_file = s->num_file;
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos)
+{
+ unz64_s* s;
+ int err;
+
+ if (file == NULL || file_pos == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+
+ /* jump to the right spot */
+ s->pos_in_central_dir = file_pos->pos_in_zip_directory;
+ s->num_file = file_pos->num_of_file;
+
+ /* set the current file */
+ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal,NULL,0,NULL,0,NULL,0);
+ /* return results */
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+extern uLong ZEXPORT unzGetOffset(unzFile file)
+{
+ ZPOS64_T offset64;
+
+ if (file == NULL)
+ return 0; /* UNZ_PARAMERROR; */
+ offset64 = unzGetOffset64(file);
+ return (uLong)offset64;
+}
+
+extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file)
+{
+ unz64_s* s;
+
+ if (file == NULL)
+ return 0; /* UNZ_PARAMERROR; */
+ s = (unz64_s*)file;
+ if (!s->current_file_ok)
+ return 0;
+ if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)
+ if (s->num_file == s->gi.number_entry)
+ return 0;
+ return s->pos_in_central_dir;
+}
+
+extern int ZEXPORT unzSetOffset(unzFile file, uLong pos)
+{
+ return unzSetOffset64(file, pos);
+}
+
+extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos)
+{
+ unz64_s* s;
+ int err;
+
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ s->pos_in_central_dir = pos;
+ s->num_file = s->gi.number_entry; /* hack */
+
+ err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0);
+
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+extern z_off_t ZEXPORT unztell(unzFile file)
+{
+ unz64_s* s;
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ if (s->pfile_in_zip_read == NULL)
+ return UNZ_PARAMERROR;
+ return (z_off_t)s->pfile_in_zip_read->stream.total_out;
+}
+
+extern ZPOS64_T ZEXPORT unztell64(unzFile file)
+{
+ unz64_s* s;
+ if (file == NULL)
+ return (ZPOS64_T)-1;
+ s = (unz64_s*)file;
+ if (s->pfile_in_zip_read == NULL)
+ return (ZPOS64_T)-1;
+ return s->pfile_in_zip_read->total_out_64;
+}
+
+extern int ZEXPORT unzseek(unzFile file, z_off_t offset, int origin)
+{
+ return unzseek64(file, (ZPOS64_T)offset, origin);
+}
+
+extern int ZEXPORT unzseek64(unzFile file, ZPOS64_T offset, int origin)
+{
+ unz64_s* s;
+ ZPOS64_T stream_pos_begin;
+ ZPOS64_T stream_pos_end;
+ int isWithinBuffer;
+ ZPOS64_T position;
+
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+
+ s = (unz64_s*)file;
+
+ if (s->pfile_in_zip_read == NULL)
+ return UNZ_ERRNO;
+ if (s->pfile_in_zip_read->compression_method != 0)
+ return UNZ_ERRNO;
+
+ if (origin == SEEK_SET)
+ position = offset;
+ else if (origin == SEEK_CUR)
+ position = s->pfile_in_zip_read->total_out_64 + offset;
+ else if (origin == SEEK_END)
+ position = s->cur_file_info.compressed_size + offset;
+ else
+ return UNZ_PARAMERROR;
+
+ if (position > s->cur_file_info.compressed_size)
+ return UNZ_PARAMERROR;
+
+ stream_pos_end = s->pfile_in_zip_read->pos_in_zipfile;
+ stream_pos_begin = stream_pos_end;
+
+ if (stream_pos_begin > UNZ_BUFSIZE)
+ stream_pos_begin -= UNZ_BUFSIZE;
+ else
+ stream_pos_begin = 0;
+
+ isWithinBuffer = s->pfile_in_zip_read->stream.avail_in != 0 &&
+ (s->pfile_in_zip_read->rest_read_compressed != 0 || s->cur_file_info.compressed_size < UNZ_BUFSIZE) &&
+ position >= stream_pos_begin && position < stream_pos_end;
+
+ if (isWithinBuffer)
+ {
+ s->pfile_in_zip_read->stream.next_in += position - s->pfile_in_zip_read->total_out_64;
+ s->pfile_in_zip_read->stream.avail_in = (uInt)(stream_pos_end - position);
+ }
+ else
+ {
+ s->pfile_in_zip_read->stream.avail_in = 0;
+ s->pfile_in_zip_read->stream.next_in = 0;
+
+ s->pfile_in_zip_read->pos_in_zipfile = s->pfile_in_zip_read->offset_local_extrafield + position;
+ s->pfile_in_zip_read->rest_read_compressed = s->cur_file_info.compressed_size - position;
+ }
+
+ s->pfile_in_zip_read->rest_read_uncompressed -= (position - s->pfile_in_zip_read->total_out_64);
+ s->pfile_in_zip_read->stream.total_out = (uLong)position;
+ s->pfile_in_zip_read->total_out_64 = position;
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzeof(unzFile file)
+{
+ unz64_s* s;
+ if (file == NULL)
+ return UNZ_PARAMERROR;
+ s = (unz64_s*)file;
+ if (s->pfile_in_zip_read == NULL)
+ return UNZ_PARAMERROR;
+ if (s->pfile_in_zip_read->rest_read_uncompressed == 0)
+ return 1;
+ return 0;
+}
diff --git a/src/qcommon/unzip.h b/src/qcommon/unzip.h
new file mode 100644
index 0000000..09e930a
--- /dev/null
+++ b/src/qcommon/unzip.h
@@ -0,0 +1,321 @@
+/* unzip.h -- IO for uncompress .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project
+
+ Copyright (C) 1998-2010 Gilles Vollant
+ http://www.winimage.com/zLibDll/minizip.html
+ Modifications of Unzip for Zip64
+ Copyright (C) 2007-2008 Even Rouault
+ Modifications for Zip64 support on both zip and unzip
+ Copyright (C) 2009-2010 Mathias Svensson
+ http://result42.com
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef _UNZ_H
+#define _UNZ_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zconf.h"
+#include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__;
+typedef unzFile__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+#define UNZ_OK (0)
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO (Z_ERRNO)
+#define UNZ_EOF (0)
+#define UNZ_PARAMERROR (-102)
+#define UNZ_BADZIPFILE (-103)
+#define UNZ_INTERNALERROR (-104)
+#define UNZ_CRCERROR (-105)
+#define UNZ_BADPASSWORD (-106)
+
+/* tm_unz contain date/time info */
+typedef struct tm_unz_s
+{
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+ These data comes from the end of central dir */
+typedef struct unz_global_info64_s
+{
+ ZPOS64_T number_entry; /* total number of entries in the central dir on this disk */
+ uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/
+ uLong size_comment; /* size of the global comment of the zipfile */
+} unz_global_info64;
+
+typedef struct unz_global_info_s
+{
+ uLong number_entry; /* total number of entries in the central dir on this disk */
+ uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/
+ uLong size_comment; /* size of the global comment of the zipfile */
+} unz_global_info;
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info64_s
+{
+ uLong version; /* version made by 2 bytes */
+ uLong version_needed; /* version needed to extract 2 bytes */
+ uLong flag; /* general purpose bit flag 2 bytes */
+ uLong compression_method; /* compression method 2 bytes */
+ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
+ uLong crc; /* crc-32 4 bytes */
+ ZPOS64_T compressed_size; /* compressed size 8 bytes */
+ ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */
+ uLong size_filename; /* filename length 2 bytes */
+ uLong size_file_extra; /* extra field length 2 bytes */
+ uLong size_file_comment; /* file comment length 2 bytes */
+
+ uLong disk_num_start; /* disk number start 2 bytes */
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+
+ tm_unz tmu_date;
+ ZPOS64_T disk_offset;
+ uLong size_file_extra_internal;
+} unz_file_info64;
+
+typedef struct unz_file_info_s
+{
+ uLong version; /* version made by 2 bytes */
+ uLong version_needed; /* version needed to extract 2 bytes */
+ uLong flag; /* general purpose bit flag 2 bytes */
+ uLong compression_method; /* compression method 2 bytes */
+ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
+ uLong crc; /* crc-32 4 bytes */
+ uLong compressed_size; /* compressed size 4 bytes */
+ uLong uncompressed_size; /* uncompressed size 4 bytes */
+ uLong size_filename; /* filename length 2 bytes */
+ uLong size_file_extra; /* extra field length 2 bytes */
+ uLong size_file_comment; /* file comment length 2 bytes */
+
+ uLong disk_num_start; /* disk number start 2 bytes */
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+
+ tm_unz tmu_date;
+ uLong disk_offset;
+} unz_file_info;
+
+/***************************************************************************/
+/* Opening and close a zip file */
+
+extern unzFile ZEXPORT unzOpen OF((const char *path));
+extern unzFile ZEXPORT unzOpen64 OF((const void *path));
+/* Open a Zip file.
+
+ path should contain the full pathname (by example, on a Windows XP computer
+ "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip".
+ return NULL if zipfile cannot be opened or doesn't exist
+ return unzFile handle if no error
+
+ NOTE: The "64" function take a const void* pointer, because the path is just the value passed to the
+ open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
+ is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* does not describe the reality */
+
+extern unzFile ZEXPORT unzOpen2 OF((const char *path, zlib_filefunc_def* pzlib_filefunc_def));
+/* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write operations */
+extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, zlib_filefunc64_def* pzlib_filefunc_def));
+/* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write 64-bit operations */
+
+extern int ZEXPORT unzClose OF((unzFile file));
+/* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile,
+ these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+
+ return UNZ_OK if there is no error */
+
+extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info));
+extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, unz_global_info64 *pglobal_info));
+/* Write info about the ZipFile in the *pglobal_info structure.
+
+ return UNZ_OK if no error */
+
+extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *comment, uLong comment_size));
+/* Get the global comment string of the ZipFile, in the comment buffer.
+
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0 */
+
+/***************************************************************************/
+/* Reading the content of the current zipfile, you can open it, read data from it, and close it
+ (you can close it before reading all the file) */
+
+extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
+/* Open for reading data the current file in the zipfile.
+
+ return UNZ_OK if no error */
+
+extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password));
+/* Open for reading data the current file in the zipfile.
+ password is a crypting password
+
+ return UNZ_OK if no error */
+
+extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw));
+/* Same as unzOpenCurrentFile, but open for read raw the file (not uncompress)
+ if raw==1 *method will receive method of compression, *level will receive level of compression
+
+ NOTE: you can set level parameter as NULL (if you did not want known level,
+ but you CANNOT set method parameter as NULL */
+
+extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password));
+/* Same as unzOpenCurrentFile, but takes extra parameter password for encrypted files */
+
+extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len));
+/* Read bytes from the current file (opened by unzOpenCurrentFile)
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */
+
+extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *filename,
+ uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size));
+extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, unz_file_info64 *pfile_info, char *filename,
+ uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size));
+/* Get Info about the current file
+
+ pfile_info if != NULL, the *pfile_info structure will contain somes info about the current file
+ filename if != NULL, the file name string will be copied in filename
+ filename_size is the size of the filename buffer
+ extrafield if != NULL, the extra field information from the central header will be copied in to
+ extrafield_size is the size of the extraField buffer
+ comment if != NULL, the comment string of the file will be copied in to
+ comment_size is the size of the comment buffer */
+
+extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));
+
+extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len));
+/* Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+ more info in the local-header version than in the central-header)
+
+ if buf == NULL, it return the size of the local extra field
+ if buf != NULL, len is the size of the buffer, the extra header is copied in buf.
+
+ return number of bytes copied in buf, or (if <0) the error code */
+
+extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+/* Close the file in zip opened with unzOpenCurrentFile
+
+ return UNZ_CRCERROR if all the file was read but the CRC is not good */
+
+/***************************************************************************/
+/* Browse the directory of the zipfile */
+
+typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2);
+typedef int (*unzIteratorFunction)(unzFile file);
+typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename,
+ uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size);
+
+extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
+/* Set the current file of the zipfile to the first file.
+
+ return UNZ_OK if no error */
+
+extern int ZEXPORT unzGoToFirstFile2 OF((unzFile file, unz_file_info64 *pfile_info, char *filename,
+ uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size));
+/* Set the current file of the zipfile to the first file and retrieves the current info on success.
+ Not as seek intensive as unzGoToFirstFile + unzGetCurrentFileInfo.
+
+ return UNZ_OK if no error */
+
+extern int ZEXPORT unzGoToNextFile OF((unzFile file));
+/* Set the current file of the zipfile to the next file.
+
+ return UNZ_OK if no error
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */
+
+extern int ZEXPORT unzGoToNextFile2 OF((unzFile file, unz_file_info64 *pfile_info, char *filename,
+ uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size));
+/* Set the current file of the zipfile to the next file and retrieves the current
+ info on success. Does less seeking around than unzGotoNextFile + unzGetCurrentFileInfo.
+
+ return UNZ_OK if no error
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */
+
+extern int ZEXPORT unzLocateFile OF((unzFile file, const char *filename, unzFileNameComparer filename_compare_func));
+/* Try locate the file szFileName in the zipfile. For custom filename comparison pass in comparison function.
+
+ return UNZ_OK if the file is found (it becomes the current file)
+ return UNZ_END_OF_LIST_OF_FILE if the file is not found */
+
+/***************************************************************************/
+/* Raw access to zip file */
+
+typedef struct unz_file_pos_s
+{
+ uLong pos_in_zip_directory; /* offset in zip file directory */
+ uLong num_of_file; /* # of file */
+} unz_file_pos;
+
+extern int ZEXPORT unzGetFilePos OF((unzFile file, unz_file_pos* file_pos));
+extern int ZEXPORT unzGoToFilePos OF((unzFile file, unz_file_pos* file_pos));
+
+typedef struct unz64_file_pos_s
+{
+ ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */
+ ZPOS64_T num_of_file; /* # of file */
+} unz64_file_pos;
+
+extern int ZEXPORT unzGetFilePos64 OF((unzFile file, unz64_file_pos* file_pos));
+extern int ZEXPORT unzGoToFilePos64 OF((unzFile file, const unz64_file_pos* file_pos));
+
+extern uLong ZEXPORT unzGetOffset OF((unzFile file));
+extern ZPOS64_T ZEXPORT unzGetOffset64 OF((unzFile file));
+/* Get the current file offset */
+
+extern int ZEXPORT unzSetOffset OF((unzFile file, uLong pos));
+extern int ZEXPORT unzSetOffset64 OF((unzFile file, ZPOS64_T pos));
+/* Set the current file offset */
+
+extern z_off_t ZEXPORT unztell OF((unzFile file));
+extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file));
+/* return current position in uncompressed data */
+
+extern int ZEXPORT unzseek OF((unzFile file, z_off_t offset, int origin));
+extern int ZEXPORT unzseek64 OF((unzFile file, ZPOS64_T offset, int origin));
+/* Seek within the uncompressed data if compression method is storage */
+
+extern int ZEXPORT unzeof OF((unzFile file));
+/* return 1 if the end of file was reached, 0 elsewhere */
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UNZ_H */
diff --git a/src/qcommon/vm.cpp b/src/qcommon/vm.cpp
new file mode 100644
index 0000000..ab36a33
--- /dev/null
+++ b/src/qcommon/vm.cpp
@@ -0,0 +1,1020 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// vm.c -- virtual machine
+
+/*
+
+
+intermix code and data
+symbol table
+
+a dll has one imported function: VM_SystemCall
+and one exported function: Perform
+
+
+*/
+
+#include "vm.h"
+#include "vm_local.h"
+
+#include "sys/sys_shared.h"
+
+#include "cmd.h"
+#include "cvar.h"
+#include "files.h"
+
+vm_t *currentVM = NULL;
+vm_t *lastVM = NULL;
+int vm_debugLevel;
+
+// used by Com_Error to get rid of running vm's before longjmp
+static int forced_unload;
+
+#define MAX_VM 3
+vm_t vmTable[MAX_VM];
+
+
+void VM_VmInfo_f( void );
+void VM_VmProfile_f( void );
+
+
+
+#if 0 // 64bit!
+// converts a VM pointer to a C pointer and
+// checks to make sure that the range is acceptable
+void *VM_VM2C( vmptr_t p, int length ) {
+ return (void *)p;
+}
+#endif
+
+void VM_Debug( int level ) {
+ vm_debugLevel = level;
+}
+
+/*
+==============
+VM_Init
+==============
+*/
+void VM_Init( void ) {
+ Cvar_Get( "vm_cgame", "2", CVAR_ARCHIVE ); // !@# SHIP WITH SET TO 2
+ Cvar_Get( "vm_game", "2", CVAR_ARCHIVE ); // !@# SHIP WITH SET TO 2
+ Cvar_Get( "vm_ui", "2", CVAR_ARCHIVE ); // !@# SHIP WITH SET TO 2
+
+ Cmd_AddCommand ("vmprofile", VM_VmProfile_f );
+ Cmd_AddCommand ("vminfo", VM_VmInfo_f );
+
+ ::memset( vmTable, 0, sizeof( vmTable ) );
+}
+
+
+/*
+===============
+VM_ValueToSymbol
+
+Assumes a program counter value
+===============
+*/
+const char *VM_ValueToSymbol( vm_t *vm, int value ) {
+ vmSymbol_t *sym;
+ static char text[MAX_TOKEN_CHARS];
+
+ sym = vm->symbols;
+ if ( !sym ) {
+ return "NO SYMBOLS";
+ }
+
+ // find the symbol
+ while ( sym->next && sym->next->symValue <= value ) {
+ sym = sym->next;
+ }
+
+ if ( value == sym->symValue ) {
+ return sym->symName;
+ }
+
+ Com_sprintf( text, sizeof( text ), "%s+%i", sym->symName, value - sym->symValue );
+
+ return text;
+}
+
+/*
+===============
+VM_ValueToFunctionSymbol
+
+For profiling, find the symbol behind this value
+===============
+*/
+vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value ) {
+ vmSymbol_t *sym;
+ static vmSymbol_t nullSym;
+
+ sym = vm->symbols;
+ if ( !sym ) {
+ return &nullSym;
+ }
+
+ while ( sym->next && sym->next->symValue <= value ) {
+ sym = sym->next;
+ }
+
+ return sym;
+}
+
+
+/*
+===============
+VM_SymbolToValue
+===============
+*/
+int VM_SymbolToValue( vm_t *vm, const char *symbol ) {
+ vmSymbol_t *sym;
+
+ for ( sym = vm->symbols ; sym ; sym = sym->next ) {
+ if ( !strcmp( symbol, sym->symName ) ) {
+ return sym->symValue;
+ }
+ }
+ return 0;
+}
+
+
+/*
+=====================
+VM_SymbolForCompiledPointer
+=====================
+*/
+#if 0 // 64bit!
+const char *VM_SymbolForCompiledPointer( vm_t *vm, void *code ) {
+ int i;
+
+ if ( code < (void *)vm->codeBase ) {
+ return "Before code block";
+ }
+ if ( code >= (void *)(vm->codeBase + vm->codeLength) ) {
+ return "After code block";
+ }
+
+ // find which original instruction it is after
+ for ( i = 0 ; i < vm->codeLength ; i++ ) {
+ if ( (void *)vm->instructionPointers[i] > code ) {
+ break;
+ }
+ }
+ i--;
+
+ // now look up the bytecode instruction pointer
+ return VM_ValueToSymbol( vm, i );
+}
+#endif
+
+
+
+/*
+===============
+ParseHex
+===============
+*/
+int ParseHex( const char *text ) {
+ int value;
+ int c;
+
+ value = 0;
+ while ( ( c = *text++ ) != 0 ) {
+ if ( c >= '0' && c <= '9' ) {
+ value = value * 16 + c - '0';
+ continue;
+ }
+ if ( c >= 'a' && c <= 'f' ) {
+ value = value * 16 + 10 + c - 'a';
+ continue;
+ }
+ if ( c >= 'A' && c <= 'F' ) {
+ value = value * 16 + 10 + c - 'A';
+ continue;
+ }
+ }
+
+ return value;
+}
+
+/*
+===============
+VM_LoadSymbols
+===============
+*/
+void VM_LoadSymbols( vm_t *vm ) {
+ union {
+ char *c;
+ void *v;
+ } mapfile;
+ char *text_p, *token;
+ char name[MAX_QPATH];
+ char symbols[MAX_QPATH];
+ vmSymbol_t **prev, *sym;
+ int count;
+ int value;
+ int chars;
+ int segment;
+ int numInstructions;
+
+ // don't load symbols if not developer
+ if ( !com_developer->integer ) {
+ return;
+ }
+
+ COM_StripExtension(vm->name, name, sizeof(name));
+ Com_sprintf( symbols, sizeof( symbols ), "vm/%s.map", name );
+ FS_ReadFile( symbols, &mapfile.v );
+ if ( !mapfile.c ) {
+ Com_Printf( "Couldn't load symbol file: %s\n", symbols );
+ return;
+ }
+
+ numInstructions = vm->instructionCount;
+
+ // parse the symbols
+ text_p = mapfile.c;
+ prev = &vm->symbols;
+ count = 0;
+
+ while ( 1 ) {
+ token = COM_Parse( &text_p );
+ if ( !token[0] ) {
+ break;
+ }
+ segment = ParseHex( token );
+ if ( segment ) {
+ COM_Parse( &text_p );
+ COM_Parse( &text_p );
+ continue; // only load code segment values
+ }
+
+ token = COM_Parse( &text_p );
+ if ( !token[0] ) {
+ Com_Printf( "WARNING: incomplete line at end of file\n" );
+ break;
+ }
+ value = ParseHex( token );
+
+ token = COM_Parse( &text_p );
+ if ( !token[0] ) {
+ Com_Printf( "WARNING: incomplete line at end of file\n" );
+ break;
+ }
+ chars = strlen( token );
+ sym = (vmSymbol_t*)Hunk_Alloc( sizeof( *sym ) + chars, h_high );
+ *prev = sym;
+ prev = &sym->next;
+ sym->next = NULL;
+
+ // convert value from an instruction number to a code offset
+ if ( value >= 0 && value < numInstructions ) {
+ value = vm->instructionPointers[value];
+ }
+
+ sym->symValue = value;
+ Q_strncpyz( sym->symName, token, chars + 1 );
+
+ count++;
+ }
+
+ vm->numSymbols = count;
+ Com_Printf( "%i symbols parsed from %s\n", count, symbols );
+ FS_FreeFile( mapfile.v );
+}
+
+/*
+============
+VM_DllSyscall
+
+Dlls will call this directly
+
+ rcg010206 The horror; the horror.
+
+ The syscall mechanism relies on stack manipulation to get its args.
+ This is likely due to C's inability to pass "..." parameters to
+ a function in one clean chunk. On PowerPC Linux, these parameters
+ are not necessarily passed on the stack, so while (&arg[0] == arg)
+ is true, (&arg[1] == 2nd function parameter) is not necessarily
+ accurate, as arg's value might have been stored to the stack or
+ other piece of scratch memory to give it a valid address, but the
+ next parameter might still be sitting in a register.
+
+ Quake's syscall system also assumes that the stack grows downward,
+ and that any needed types can be squeezed, safely, into a signed int.
+
+ This hack below copies all needed values for an argument to a
+ array in memory, so that Quake can get the correct values. This can
+ also be used on systems where the stack grows upwards, as the
+ presumably standard and safe stdargs.h macros are used.
+
+ As for having enough space in a signed int for your datatypes, well,
+ it might be better to wait for DOOM 3 before you start porting. :)
+
+ The original code, while probably still inherently dangerous, seems
+ to work well enough for the platforms it already works on. Rather
+ than add the performance hit for those platforms, the original code
+ is still in use there.
+
+ For speed, we just grab 15 arguments, and don't worry about exactly
+ how many the syscall actually needs; the extra is thrown away.
+
+============
+*/
+__attribute__((no_sanitize_address))
+intptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) {
+#if !id386 || defined __clang__
+ // rcg010206 - see commentary above
+ intptr_t args[MAX_VMSYSCALL_ARGS];
+ int i;
+ va_list ap;
+
+ args[0] = arg;
+
+ va_start(ap, arg);
+ for (i = 1; i < ARRAY_LEN(args); i++)
+ args[i] = va_arg(ap, intptr_t);
+ va_end(ap);
+
+ return currentVM->systemCall( args );
+#else // original id code
+ return currentVM->systemCall( &arg );
+#endif
+}
+
+
+/*
+=================
+VM_LoadQVM
+
+Load a .qvm file
+=================
+*/
+vmHeader_t *VM_LoadQVM( vm_t *vm, bool alloc, bool unpure)
+{
+ int dataLength;
+ int i;
+ char filename[MAX_QPATH];
+ union {
+ vmHeader_t *h;
+ void *v;
+ } header;
+
+ // load the image
+ Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
+ Com_Printf( "Loading vm file %s...\n", filename );
+
+ FS_ReadFileDir(filename, vm->searchPath, unpure, &header.v);
+
+ if ( !header.h ) {
+ Com_Printf( "Failed.\n" );
+ VM_Free( vm );
+
+ Com_Printf(S_COLOR_YELLOW "Warning: Couldn't open VM file %s\n", filename);
+
+ return NULL;
+ }
+
+ // show where the qvm was loaded from
+ FS_Which(filename, vm->searchPath);
+
+ if( LittleLong( header.h->vmMagic ) == VM_MAGIC_VER2 ) {
+ Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
+
+ // byte swap the header
+ for ( i = 0 ; i < sizeof( vmHeader_t ) / 4 ; i++ ) {
+ ((int *)header.h)[i] = LittleLong( ((int *)header.h)[i] );
+ }
+
+ // validate
+ if ( header.h->jtrgLength < 0
+ || header.h->bssLength < 0
+ || header.h->dataLength < 0
+ || header.h->litLength < 0
+ || header.h->codeLength <= 0 )
+ {
+ VM_Free(vm);
+ FS_FreeFile(header.v);
+
+ Com_Printf(S_COLOR_YELLOW "Warning: %s has bad header\n", filename);
+ return NULL;
+ }
+ } else if( LittleLong( header.h->vmMagic ) == VM_MAGIC ) {
+ // byte swap the header
+ // sizeof( vmHeader_t ) - sizeof( int ) is the 1.32b vm header size
+ for ( i = 0 ; i < ( sizeof( vmHeader_t ) - sizeof( int ) ) / 4 ; i++ ) {
+ ((int *)header.h)[i] = LittleLong( ((int *)header.h)[i] );
+ }
+
+ // validate
+ if ( header.h->bssLength < 0
+ || header.h->dataLength < 0
+ || header.h->litLength < 0
+ || header.h->codeLength <= 0 )
+ {
+ VM_Free(vm);
+ FS_FreeFile(header.v);
+
+ Com_Printf(S_COLOR_YELLOW "Warning: %s has bad header\n", filename);
+ return NULL;
+ }
+ } else {
+ VM_Free( vm );
+ FS_FreeFile(header.v);
+
+ Com_Printf(S_COLOR_YELLOW "Warning: %s does not have a recognisable "
+ "magic number in its header\n", filename);
+ return NULL;
+ }
+
+ // round up to next power of 2 so all data operations can
+ // be mask protected
+ dataLength = header.h->dataLength + header.h->litLength +
+ header.h->bssLength;
+ for ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) {
+ }
+ dataLength = 1 << i;
+
+ if(alloc)
+ {
+ // allocate zero filled space for initialized and uninitialized data
+ vm->dataBase = (unsigned char*)Hunk_Alloc(dataLength, h_high);
+ vm->dataMask = dataLength - 1;
+ }
+ else
+ {
+ // clear the data, but make sure we're not clearing more than allocated
+ if(vm->dataMask + 1 != dataLength)
+ {
+ VM_Free(vm);
+ FS_FreeFile(header.v);
+
+ Com_Printf(S_COLOR_YELLOW "Warning: Data region size of %s not matching after "
+ "VM_Restart()\n", filename);
+ return NULL;
+ }
+
+ ::memset(vm->dataBase, 0, dataLength);
+ }
+
+ // copy the intialized data
+ ::memcpy( vm->dataBase, (byte *)header.h + header.h->dataOffset,
+ header.h->dataLength + header.h->litLength );
+
+ // byte swap the longs
+ for ( i = 0 ; i < header.h->dataLength ; i += 4 ) {
+ *(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) );
+ }
+
+ if(header.h->vmMagic == VM_MAGIC_VER2)
+ {
+ int previousNumJumpTableTargets = vm->numJumpTableTargets;
+
+ header.h->jtrgLength &= ~0x03;
+
+ vm->numJumpTableTargets = header.h->jtrgLength >> 2;
+ Com_Printf("Loading %d jump table targets\n", vm->numJumpTableTargets);
+
+ if(alloc)
+ {
+ vm->jumpTableTargets = (unsigned char*)Hunk_Alloc(header.h->jtrgLength, h_high);
+ }
+ else
+ {
+ if(vm->numJumpTableTargets != previousNumJumpTableTargets)
+ {
+ VM_Free(vm);
+ FS_FreeFile(header.v);
+
+ Com_Printf(S_COLOR_YELLOW "Warning: Jump table size of %s not matching after "
+ "VM_Restart()\n", filename);
+ return NULL;
+ }
+
+ ::memset(vm->jumpTableTargets, 0, header.h->jtrgLength);
+ }
+
+ ::memcpy(vm->jumpTableTargets, (byte *) header.h + header.h->dataOffset +
+ header.h->dataLength + header.h->litLength, header.h->jtrgLength);
+
+ // byte swap the longs
+ for ( i = 0 ; i < header.h->jtrgLength ; i += 4 ) {
+ *(int *)(vm->jumpTableTargets + i) = LittleLong( *(int *)(vm->jumpTableTargets + i ) );
+ }
+ }
+
+ return header.h;
+}
+
+/*
+=================
+VM_Restart
+
+Reload the data, but leave everything else in place
+This allows a server to do a map_restart without changing memory allocation
+
+We need to make sure that servers can access unpure QVMs (not contained in any pak)
+even if the client is pure, so take "unpure" as argument.
+=================
+*/
+vm_t *VM_Restart(vm_t *vm, bool unpure)
+{
+ vmHeader_t *header;
+
+ // DLL's can't be restarted in place
+ if ( vm->dllHandle ) {
+ char name[MAX_QPATH];
+ intptr_t (*systemCall)( intptr_t *parms );
+
+ systemCall = vm->systemCall;
+ Q_strncpyz( name, vm->name, sizeof( name ) );
+
+ VM_Free( vm );
+
+ vm = VM_Create( name, systemCall, VMI_NATIVE );
+ return vm;
+ }
+
+ // load the image
+ Com_Printf("VM_Restart()\n");
+
+ if(!(header = VM_LoadQVM(vm, false, unpure)))
+ {
+ Com_Error(ERR_DROP, "VM_Restart failed");
+ return NULL;
+ }
+
+ // free the original file
+ FS_FreeFile(header);
+
+ return vm;
+}
+
+/*
+================
+VM_Create
+
+If image ends in .qvm it will be interpreted, otherwise
+it will attempt to load as a system dll
+================
+*/
+vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
+ vmInterpret_t interpret ) {
+ vm_t *vm;
+ vmHeader_t *header;
+ int i, remaining, retval;
+ char filename[MAX_OSPATH];
+ void *startSearch = NULL;
+
+ if ( !module || !module[0] || !systemCalls ) {
+ Com_Error( ERR_FATAL, "VM_Create: bad parms" );
+ }
+
+ remaining = Hunk_MemoryRemaining();
+
+ // see if we already have the VM
+ for ( i = 0 ; i < MAX_VM ; i++ ) {
+ if (!Q_stricmp(vmTable[i].name, module)) {
+ vm = &vmTable[i];
+ return vm;
+ }
+ }
+
+ // find a free vm
+ for ( i = 0 ; i < MAX_VM ; i++ ) {
+ if ( !vmTable[i].name[0] ) {
+ break;
+ }
+ }
+
+ if ( i == MAX_VM ) {
+ Com_Error( ERR_FATAL, "VM_Create: no free vm_t" );
+ }
+
+ vm = &vmTable[i];
+
+ Q_strncpyz(vm->name, module, sizeof(vm->name));
+
+ do
+ {
+ retval = FS_FindVM(&startSearch, filename, sizeof(filename), module, (interpret == VMI_NATIVE));
+
+ if(retval == VMI_NATIVE)
+ {
+ Com_Printf("Try loading dll file %s\n", filename);
+
+ vm->dllHandle = Sys_LoadGameDll(filename, &vm->entryPoint, VM_DllSyscall);
+
+ if(vm->dllHandle)
+ {
+ vm->systemCall = systemCalls;
+ return vm;
+ }
+
+ Com_Printf("Failed loading dll, trying next\n");
+ }
+ else if(retval == VMI_COMPILED)
+ {
+ vm->searchPath = startSearch;
+ if((header = VM_LoadQVM(vm, true, false)))
+ break;
+
+ // VM_Free overwrites the name on failed load
+ Q_strncpyz(vm->name, module, sizeof(vm->name));
+ }
+ } while(retval >= 0);
+
+ if(retval < 0)
+ return NULL;
+
+ vm->systemCall = systemCalls;
+
+ // allocate space for the jump targets, which will be filled in by the compile/prep functions
+ vm->instructionCount = header->instructionCount;
+ vm->instructionPointers = (intptr_t*)Hunk_Alloc(vm->instructionCount * sizeof(*vm->instructionPointers), h_high);
+
+ // copy or compile the instructions
+ vm->codeLength = header->codeLength;
+
+ vm->compiled = false;
+
+#ifdef NO_VM_COMPILED
+ if(interpret >= VMI_COMPILED) {
+ Com_Printf("Architecture doesn't have a bytecode compiler, using interpreter\n");
+ interpret = VMI_BYTECODE;
+ }
+#else
+ if(interpret != VMI_BYTECODE)
+ {
+ vm->compiled = true;
+ VM_Compile( vm, header );
+ }
+#endif
+ // VM_Compile may have reset vm->compiled if compilation failed
+ if (!vm->compiled)
+ {
+ VM_PrepareInterpreter( vm, header );
+ }
+
+ // free the original file
+ FS_FreeFile( header );
+
+ // load the map file
+ VM_LoadSymbols( vm );
+
+ // the stack is implicitly at the end of the image
+ vm->programStack = vm->dataMask + 1;
+ vm->stackBottom = vm->programStack - PROGRAM_STACK_SIZE;
+
+ Com_Printf("%s loaded in %d bytes on the hunk\n", module, remaining - Hunk_MemoryRemaining());
+
+ return vm;
+}
+
+/*
+==============
+VM_Free
+==============
+*/
+void VM_Free( vm_t *vm ) {
+
+ if(!vm) {
+ return;
+ }
+
+ if(vm->callLevel) {
+ if(!forced_unload) {
+ Com_Error( ERR_FATAL, "VM_Free(%s) on running vm", vm->name );
+ return;
+ } else {
+ Com_Printf( "forcefully unloading %s vm\n", vm->name );
+ }
+ }
+
+ if(vm->destroy)
+ vm->destroy(vm);
+
+ if ( vm->dllHandle ) {
+ Sys_UnloadDll( vm->dllHandle );
+ ::memset( vm, 0, sizeof( *vm ) );
+ }
+#if 0 // now automatically freed by hunk
+ if ( vm->codeBase ) {
+ Z_Free( vm->codeBase );
+ }
+ if ( vm->dataBase ) {
+ Z_Free( vm->dataBase );
+ }
+ if ( vm->instructionPointers ) {
+ Z_Free( vm->instructionPointers );
+ }
+#endif
+ ::memset( vm, 0, sizeof( *vm ) );
+
+ currentVM = NULL;
+ lastVM = NULL;
+}
+
+void VM_Clear(void) {
+ int i;
+ for (i=0;i<MAX_VM; i++) {
+ VM_Free(&vmTable[i]);
+ }
+}
+
+void VM_Forced_Unload_Start(void) {
+ forced_unload = 1;
+}
+
+void VM_Forced_Unload_Done(void) {
+ forced_unload = 0;
+}
+
+void VM_ClearCallLevel(vm_t *vm) {
+ vm->callLevel = 0;
+}
+
+void *VM_ArgPtr( intptr_t intValue ) {
+ if ( !intValue ) {
+ return NULL;
+ }
+ // currentVM is missing on reconnect
+ if ( currentVM==NULL )
+ return NULL;
+
+ if ( currentVM->entryPoint ) {
+ return (void *)(currentVM->dataBase + intValue);
+ }
+ else {
+ return (void *)(currentVM->dataBase + (intValue & currentVM->dataMask));
+ }
+}
+
+void *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue ) {
+ if ( !intValue ) {
+ return NULL;
+ }
+
+ // currentVM is missing on reconnect here as well?
+ if ( currentVM==NULL )
+ return NULL;
+
+ //
+ if ( vm->entryPoint ) {
+ return (void *)(vm->dataBase + intValue);
+ }
+ else {
+ return (void *)(vm->dataBase + (intValue & vm->dataMask));
+ }
+}
+
+
+/*
+==============
+VM_Call
+
+
+Upon a system call, the stack will look like:
+
+sp+32 parm1
+sp+28 parm0
+sp+24 return value
+sp+20 return address
+sp+16 local1
+sp+14 local0
+sp+12 arg1
+sp+8 arg0
+sp+4 return stack
+sp return address
+
+An interpreted function will immediately execute
+an OP_ENTER instruction, which will subtract space for
+locals from sp
+==============
+*/
+__attribute__((no_sanitize_address))
+intptr_t QDECL VM_Call( vm_t *vm, int callnum, ... )
+{
+ vm_t *oldVM;
+ intptr_t r;
+
+ if(!vm || !vm->name[0])
+ Com_Error(ERR_FATAL, "VM_Call with NULL vm");
+
+ oldVM = currentVM;
+ currentVM = vm;
+ lastVM = vm;
+
+ if ( vm_debugLevel ) {
+ Com_Printf( "VM_Call( %d )\n", callnum );
+ }
+
+ ++vm->callLevel;
+ // if we have a dll loaded, call it directly
+ if ( vm->entryPoint ) {
+ //rcg010207 - see dissertation at top of VM_DllSyscall() in this file.
+ int args[MAX_VMMAIN_ARGS-1];
+ va_list ap;
+ va_start(ap, callnum);
+ for (unsigned i = 0; i < ARRAY_LEN(args); i++)
+ {
+ args[i] = va_arg(ap, int);
+ }
+ va_end(ap);
+
+ r = vm->entryPoint( callnum, args[0], args[1], args[2] );
+ } else {
+#if ( id386 || idsparc ) && !defined __clang__ // calling convention doesn't need conversion in some cases
+#ifndef NO_VM_COMPILED
+ if ( vm->compiled )
+ r = VM_CallCompiled( vm, (int*)&callnum );
+ else
+#endif
+ r = VM_CallInterpreted( vm, (int*)&callnum );
+#else
+ struct {
+ int callnum;
+ int args[MAX_VMMAIN_ARGS-1];
+ } a;
+ va_list ap;
+
+ a.callnum = callnum;
+ va_start(ap, callnum);
+ for (unsigned i = 0; i < ARRAY_LEN(a.args); i++)
+ {
+ a.args[i] = va_arg(ap, int);
+ }
+ va_end(ap);
+#ifndef NO_VM_COMPILED
+ if ( vm->compiled )
+ r = VM_CallCompiled( vm, &a.callnum );
+ else
+#endif
+ r = VM_CallInterpreted( vm, &a.callnum );
+#endif
+ }
+ --vm->callLevel;
+
+ if ( oldVM != NULL )
+ currentVM = oldVM;
+ return r;
+}
+
+//=================================================================
+
+static int QDECL VM_ProfileSort( const void *a, const void *b ) {
+ vmSymbol_t *sa, *sb;
+
+ sa = *(vmSymbol_t **)a;
+ sb = *(vmSymbol_t **)b;
+
+ if ( sa->profileCount < sb->profileCount ) {
+ return -1;
+ }
+ if ( sa->profileCount > sb->profileCount ) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+==============
+VM_VmProfile_f
+
+==============
+*/
+void VM_VmProfile_f( void ) {
+ vm_t *vm;
+ vmSymbol_t **sorted, *sym;
+ int i;
+ double total;
+
+ if ( !lastVM ) {
+ return;
+ }
+
+ vm = lastVM;
+
+ if ( !vm->numSymbols ) {
+ return;
+ }
+
+ sorted = (vmSymbol_t**)Z_Malloc( vm->numSymbols * sizeof( *sorted ) );
+ sorted[0] = vm->symbols;
+ total = sorted[0]->profileCount;
+ for ( i = 1 ; i < vm->numSymbols ; i++ ) {
+ sorted[i] = sorted[i-1]->next;
+ total += sorted[i]->profileCount;
+ }
+
+ qsort( sorted, vm->numSymbols, sizeof( *sorted ), VM_ProfileSort );
+
+ for ( i = 0 ; i < vm->numSymbols ; i++ ) {
+ int perc;
+
+ sym = sorted[i];
+
+ perc = 100 * (float) sym->profileCount / total;
+ Com_Printf( "%2i%% %9i %s\n", perc, sym->profileCount, sym->symName );
+ sym->profileCount = 0;
+ }
+
+ Com_Printf(" %9.0f total\n", total );
+
+ Z_Free( sorted );
+}
+
+/*
+==============
+VM_VmInfo_f
+
+==============
+*/
+void VM_VmInfo_f( void ) {
+ vm_t *vm;
+ int i;
+
+ Com_Printf( "Registered virtual machines:\n" );
+ for ( i = 0 ; i < MAX_VM ; i++ ) {
+ vm = &vmTable[i];
+ if ( !vm->name[0] ) {
+ break;
+ }
+ Com_Printf( "%s : ", vm->name );
+ if ( vm->dllHandle ) {
+ Com_Printf( "native\n" );
+ continue;
+ }
+ if ( vm->compiled ) {
+ Com_Printf( "compiled on load\n" );
+ } else {
+ Com_Printf( "interpreted\n" );
+ }
+ Com_Printf( " code length : %7i\n", vm->codeLength );
+ Com_Printf( " table length: %7i\n", vm->instructionCount*4 );
+ Com_Printf( " data length : %7i\n", vm->dataMask + 1 );
+ }
+}
+
+/*
+===============
+VM_LogSyscalls
+
+Insert calls to this while debugging the vm compiler
+===============
+*/
+void VM_LogSyscalls( int *args ) {
+ static int callnum;
+ static FILE *f;
+
+ if ( !f ) {
+ f = fopen("syscalls.log", "w" );
+ }
+ callnum++;
+ fprintf(f, "%i: %p (%i) = %i %i %i %i\n", callnum, (void*)(args - (int *)currentVM->dataBase),
+ args[0], args[1], args[2], args[3], args[4] );
+}
+
+/*
+=================
+VM_BlockCopy
+Executes a block copy operation within currentVM data space
+=================
+*/
+
+void VM_BlockCopy(unsigned int dest, unsigned int src, size_t n)
+{
+ unsigned int dataMask = currentVM->dataMask;
+
+ if ((dest & dataMask) != dest
+ || (src & dataMask) != src
+ || ((dest + n) & dataMask) != dest + n
+ || ((src + n) & dataMask) != src + n)
+ {
+ Com_Error(ERR_DROP, "OP_BLOCK_COPY out of range!");
+ }
+
+ ::memcpy(currentVM->dataBase + dest, currentVM->dataBase + src, n);
+}
diff --git a/src/qcommon/vm.h b/src/qcommon/vm.h
new file mode 100644
index 0000000..26705af
--- /dev/null
+++ b/src/qcommon/vm.h
@@ -0,0 +1,67 @@
+#ifndef QCOMMON_VM_H
+#define QCOMMON_VM_H 1
+
+#include "q_shared.h"
+
+/*
+==============================================================
+
+VIRTUAL MACHINE
+
+==============================================================
+*/
+
+typedef struct vm_s vm_t;
+
+typedef enum {
+ VMI_NATIVE,
+ VMI_BYTECODE,
+ VMI_COMPILED
+} vmInterpret_t;
+
+typedef enum {
+ TRAP_MEMSET = 100,
+ TRAP_MEMCPY,
+ TRAP_STRNCPY,
+ TRAP_SIN,
+ TRAP_COS,
+ TRAP_ATAN2,
+ TRAP_SQRT,
+ TRAP_MATRIXMULTIPLY,
+ TRAP_ANGLEVECTORS,
+ TRAP_PERPENDICULARVECTOR,
+ TRAP_FLOOR,
+ TRAP_CEIL,
+
+ TRAP_TESTPRINTINT,
+ TRAP_TESTPRINTFLOAT
+} sharedTraps_t;
+
+void VM_Init( void );
+vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), vmInterpret_t interpret );
+// module should be bare: "cgame", not "cgame.dll" or "vm/cgame.qvm"
+
+void VM_Free( vm_t *vm );
+void VM_Clear(void);
+void VM_Forced_Unload_Start(void);
+void VM_Forced_Unload_Done(void);
+void VM_ClearCallLevel(vm_t *vm);
+vm_t *VM_Restart(vm_t *vm, bool unpure);
+
+intptr_t QDECL VM_Call( vm_t *vm, int callNum, ... );
+
+void VM_Debug( int level );
+
+void *VM_ArgPtr( intptr_t intValue );
+void *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue );
+
+#define VMA(x) VM_ArgPtr(args[x])
+static ID_INLINE float _vmf(intptr_t x)
+{
+ floatint_t fi;
+ fi.i = (int) x;
+ return fi.f;
+}
+#define VMF(x) _vmf(args[x])
+
+#endif
diff --git a/src/qcommon/vm_interpreted.cpp b/src/qcommon/vm_interpreted.cpp
new file mode 100644
index 0000000..08cdfcd
--- /dev/null
+++ b/src/qcommon/vm_interpreted.cpp
@@ -0,0 +1,904 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "vm.h"
+#include "vm_local.h"
+
+//#define DEBUG_VM
+#ifdef DEBUG_VM
+static char *opnames[256] = {
+ "OP_UNDEF",
+
+ "OP_IGNORE",
+
+ "OP_BREAK",
+
+ "OP_ENTER",
+ "OP_LEAVE",
+ "OP_CALL",
+ "OP_PUSH",
+ "OP_POP",
+
+ "OP_CONST",
+
+ "OP_LOCAL",
+
+ "OP_JUMP",
+
+ //-------------------
+
+ "OP_EQ",
+ "OP_NE",
+
+ "OP_LTI",
+ "OP_LEI",
+ "OP_GTI",
+ "OP_GEI",
+
+ "OP_LTU",
+ "OP_LEU",
+ "OP_GTU",
+ "OP_GEU",
+
+ "OP_EQF",
+ "OP_NEF",
+
+ "OP_LTF",
+ "OP_LEF",
+ "OP_GTF",
+ "OP_GEF",
+
+ //-------------------
+
+ "OP_LOAD1",
+ "OP_LOAD2",
+ "OP_LOAD4",
+ "OP_STORE1",
+ "OP_STORE2",
+ "OP_STORE4",
+ "OP_ARG",
+
+ "OP_BLOCK_COPY",
+
+ //-------------------
+
+ "OP_SEX8",
+ "OP_SEX16",
+
+ "OP_NEGI",
+ "OP_ADD",
+ "OP_SUB",
+ "OP_DIVI",
+ "OP_DIVU",
+ "OP_MODI",
+ "OP_MODU",
+ "OP_MULI",
+ "OP_MULU",
+
+ "OP_BAND",
+ "OP_BOR",
+ "OP_BXOR",
+ "OP_BCOM",
+
+ "OP_LSH",
+ "OP_RSHI",
+ "OP_RSHU",
+
+ "OP_NEGF",
+ "OP_ADDF",
+ "OP_SUBF",
+ "OP_DIVF",
+ "OP_MULF",
+
+ "OP_CVIF",
+ "OP_CVFI"
+};
+#endif
+
+#if idppc
+
+//FIXME: these, um... look the same to me
+#if defined(__GNUC__)
+static ID_INLINE unsigned int loadWord(void *addr) {
+ unsigned int word;
+
+ asm("lwbrx %0,0,%1" : "=r" (word) : "r" (addr));
+ return word;
+}
+#else
+static ID_INLINE unsigned int __lwbrx(register void *addr,
+ register int offset) {
+ register unsigned int word;
+
+ asm("lwbrx %0,%2,%1" : "=r" (word) : "r" (addr), "b" (offset));
+ return word;
+}
+#define loadWord(addr) __lwbrx(addr,0)
+#endif
+
+#else
+ static ID_INLINE int loadWord(void *addr) {
+ int word;
+ memcpy(&word, addr, 4);
+ return LittleLong(word);
+ }
+#endif
+
+const char *VM_Indent( vm_t *vm ) {
+ const char *string = " ";
+ if ( vm->callLevel > 20 ) {
+ return string;
+ }
+ return string + 2 * ( 20 - vm->callLevel );
+}
+
+void VM_StackTrace( vm_t *vm, int programCounter, int programStack ) {
+ int count;
+
+ count = 0;
+ do {
+ Com_Printf( "%s\n", VM_ValueToSymbol( vm, programCounter ) );
+ programStack = *(int *)&vm->dataBase[programStack+4];
+ programCounter = *(int *)&vm->dataBase[programStack];
+ } while ( programCounter != -1 && ++count < 32 );
+
+}
+
+
+/*
+====================
+VM_PrepareInterpreter
+====================
+*/
+void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header ) {
+ int op;
+ int byte_pc;
+ int int_pc;
+ byte *code;
+ int instruction;
+ int *codeBase;
+
+ vm->codeBase = (unsigned char*)Hunk_Alloc( vm->codeLength*4, h_high ); // we're now int aligned
+// memcpy( vm->codeBase, (byte *)header + header->codeOffset, vm->codeLength );
+
+ // we don't need to translate the instructions, but we still need
+ // to find each instructions starting point for jumps
+ int_pc = byte_pc = 0;
+ instruction = 0;
+ code = (byte *)header + header->codeOffset;
+ codeBase = (int *)vm->codeBase;
+
+ // Copy and expand instructions to words while building instruction table
+ while ( instruction < header->instructionCount ) {
+ vm->instructionPointers[ instruction ] = int_pc;
+ instruction++;
+
+ op = (int)code[ byte_pc ];
+ codeBase[int_pc] = op;
+ if(byte_pc > header->codeLength)
+ Com_Error(ERR_DROP, "VM_PrepareInterpreter: pc > header->codeLength");
+
+ byte_pc++;
+ int_pc++;
+
+ // these are the only opcodes that aren't a single byte
+ switch ( op ) {
+ case OP_ENTER:
+ case OP_CONST:
+ case OP_LOCAL:
+ case OP_LEAVE:
+ case OP_EQ:
+ case OP_NE:
+ case OP_LTI:
+ case OP_LEI:
+ case OP_GTI:
+ case OP_GEI:
+ case OP_LTU:
+ case OP_LEU:
+ case OP_GTU:
+ case OP_GEU:
+ case OP_EQF:
+ case OP_NEF:
+ case OP_LTF:
+ case OP_LEF:
+ case OP_GTF:
+ case OP_GEF:
+ case OP_BLOCK_COPY:
+ codeBase[int_pc] = loadWord(&code[byte_pc]);
+ byte_pc += 4;
+ int_pc++;
+ break;
+ case OP_ARG:
+ codeBase[int_pc] = (int)code[byte_pc];
+ byte_pc++;
+ int_pc++;
+ break;
+ default:
+ break;
+ }
+
+ }
+ int_pc = 0;
+ instruction = 0;
+
+ // Now that the code has been expanded to int-sized opcodes, we'll translate instruction index
+ //into an index into codeBase[], which contains opcodes and operands.
+ while ( instruction < header->instructionCount ) {
+ op = codeBase[ int_pc ];
+ instruction++;
+ int_pc++;
+
+ switch ( op ) {
+ // These ops need to translate addresses in jumps from instruction index to int index
+ case OP_EQ:
+ case OP_NE:
+ case OP_LTI:
+ case OP_LEI:
+ case OP_GTI:
+ case OP_GEI:
+ case OP_LTU:
+ case OP_LEU:
+ case OP_GTU:
+ case OP_GEU:
+ case OP_EQF:
+ case OP_NEF:
+ case OP_LTF:
+ case OP_LEF:
+ case OP_GTF:
+ case OP_GEF:
+ if(codeBase[int_pc] < 0 || codeBase[int_pc] > vm->instructionCount)
+ Com_Error(ERR_DROP, "VM_PrepareInterpreter: Jump to invalid instruction number");
+
+ // codeBase[pc] is the instruction index. Convert that into an offset into
+ //the int-aligned codeBase[] by the lookup table.
+ codeBase[int_pc] = vm->instructionPointers[codeBase[int_pc]];
+ int_pc++;
+ break;
+
+ // These opcodes have an operand that isn't an instruction index
+ case OP_ENTER:
+ case OP_CONST:
+ case OP_LOCAL:
+ case OP_LEAVE:
+ case OP_BLOCK_COPY:
+ case OP_ARG:
+ int_pc++;
+ break;
+
+ default:
+ break;
+ }
+
+ }
+}
+
+/*
+==============
+VM_Call
+
+
+Upon a system call, the stack will look like:
+
+sp+32 parm1
+sp+28 parm0
+sp+24 return stack
+sp+20 return address
+sp+16 local1
+sp+14 local0
+sp+12 arg1
+sp+8 arg0
+sp+4 return stack
+sp return address
+
+An interpreted function will immediately execute
+an OP_ENTER instruction, which will subtract space for
+locals from sp
+==============
+*/
+
+#define DEBUGSTR va("%s%i", VM_Indent(vm), opStackOfs)
+
+int VM_CallInterpreted( vm_t *vm, int *args ) {
+ byte stack[OPSTACK_SIZE + 15];
+ int *opStack;
+ uint8_t opStackOfs;
+ int programCounter;
+ int programStack;
+ int stackOnEntry;
+ byte *image;
+ int *codeImage;
+ int v1;
+ int dataMask;
+ int arg;
+#ifdef DEBUG_VM
+ vmSymbol_t *profileSymbol;
+#endif
+
+ // interpret the code
+ vm->currentlyInterpreting = true;
+
+ // we might be called recursively, so this might not be the very top
+ programStack = stackOnEntry = vm->programStack;
+
+#ifdef DEBUG_VM
+ profileSymbol = VM_ValueToFunctionSymbol( vm, 0 );
+ // uncomment this for debugging breakpoints
+ vm->breakFunction = 0;
+#endif
+ // set up the stack frame
+
+ image = vm->dataBase;
+ codeImage = (int *)vm->codeBase;
+ dataMask = vm->dataMask;
+
+ programCounter = 0;
+
+ programStack -= ( 8 + 4 * MAX_VMMAIN_ARGS );
+
+ for ( arg = 0; arg < MAX_VMMAIN_ARGS; arg++ )
+ *(int *)&image[ programStack + 8 + arg * 4 ] = args[ arg ];
+
+ *(int *)&image[ programStack + 4 ] = 0; // return stack
+ *(int *)&image[ programStack ] = -1; // will terminate the loop on return
+
+ VM_Debug(0);
+
+ // leave a free spot at start of stack so
+ // that as long as opStack is valid, opStack-1 will
+ // not corrupt anything
+ opStack = (int*)PADP(stack, 16);
+ *opStack = 0xDEADBEEF;
+ opStackOfs = 0;
+
+// vm_debugLevel=2;
+ // main interpreter loop, will exit when a LEAVE instruction
+ // grabs the -1 program counter
+
+#define r2 codeImage[programCounter]
+
+ while ( 1 ) {
+ int opcode, r0, r1;
+// unsigned int r2;
+
+nextInstruction:
+ r0 = opStack[opStackOfs];
+ r1 = opStack[(uint8_t) (opStackOfs - 1)];
+nextInstruction2:
+#ifdef DEBUG_VM
+ if ( (unsigned)programCounter >= vm->codeLength ) {
+ Com_Error( ERR_DROP, "VM pc out of range" );
+ return 0;
+ }
+
+ if ( programStack <= vm->stackBottom ) {
+ Com_Error( ERR_DROP, "VM stack overflow" );
+ return 0;
+ }
+
+ if ( programStack & 3 ) {
+ Com_Error( ERR_DROP, "VM program stack misaligned" );
+ return 0;
+ }
+
+ if ( vm_debugLevel > 1 ) {
+ Com_Printf( "%s %s\n", DEBUGSTR, opnames[opcode] );
+ }
+ profileSymbol->profileCount++;
+#endif
+ opcode = codeImage[ programCounter++ ];
+
+ switch ( opcode ) {
+#ifdef DEBUG_VM
+ default:
+ Com_Error( ERR_DROP, "Bad VM instruction" ); // this should be scanned on load!
+ return 0;
+#endif
+ case OP_BREAK:
+ vm->breakCount++;
+ goto nextInstruction2;
+ case OP_CONST:
+ opStackOfs++;
+ r1 = r0;
+ r0 = opStack[opStackOfs] = r2;
+
+ programCounter += 1;
+ goto nextInstruction2;
+ case OP_LOCAL:
+ opStackOfs++;
+ r1 = r0;
+ r0 = opStack[opStackOfs] = r2+programStack;
+
+ programCounter += 1;
+ goto nextInstruction2;
+
+ case OP_LOAD4:
+#ifdef DEBUG_VM
+ if(opStack[opStackOfs] & 3)
+ {
+ Com_Error( ERR_DROP, "OP_LOAD4 misaligned" );
+ return 0;
+ }
+#endif
+ r0 = opStack[opStackOfs] = *(int *) &image[r0 & dataMask & ~3 ];
+ goto nextInstruction2;
+ case OP_LOAD2:
+ r0 = opStack[opStackOfs] = *(unsigned short *)&image[ r0&dataMask&~1 ];
+ goto nextInstruction2;
+ case OP_LOAD1:
+ r0 = opStack[opStackOfs] = image[ r0&dataMask ];
+ goto nextInstruction2;
+
+ case OP_STORE4:
+ *(int *)&image[ r1&(dataMask & ~3) ] = r0;
+ opStackOfs -= 2;
+ goto nextInstruction;
+ case OP_STORE2:
+ *(short *)&image[ r1&(dataMask & ~1) ] = r0;
+ opStackOfs -= 2;
+ goto nextInstruction;
+ case OP_STORE1:
+ image[ r1&dataMask ] = r0;
+ opStackOfs -= 2;
+ goto nextInstruction;
+
+ case OP_ARG:
+ // single byte offset from programStack
+ *(int *)&image[ (codeImage[programCounter] + programStack)&dataMask&~3 ] = r0;
+ opStackOfs--;
+ programCounter += 1;
+ goto nextInstruction;
+
+ case OP_BLOCK_COPY:
+ VM_BlockCopy(r1, r0, r2);
+ programCounter += 1;
+ opStackOfs -= 2;
+ goto nextInstruction;
+
+ case OP_CALL:
+ // save current program counter
+ *(int *)&image[ programStack ] = programCounter;
+
+ // jump to the location on the stack
+ programCounter = r0;
+ opStackOfs--;
+ if ( programCounter < 0 ) {
+ // system call
+ int r;
+// int temp;
+#ifdef DEBUG_VM
+ int stomped;
+
+ if ( vm_debugLevel ) {
+ Com_Printf( "%s---> systemcall(%i)\n", DEBUGSTR, -1 - programCounter );
+ }
+#endif
+ // save the stack to allow recursive VM entry
+// temp = vm->callLevel;
+ vm->programStack = programStack - 4;
+#ifdef DEBUG_VM
+ stomped = *(int *)&image[ programStack + 4 ];
+#endif
+ *(int *)&image[ programStack + 4 ] = -1 - programCounter;
+
+//VM_LogSyscalls( (int *)&image[ programStack + 4 ] );
+ {
+ // the vm has ints on the stack, we expect
+ // pointers so we might have to convert it
+ if (sizeof(intptr_t) != sizeof(int)) {
+ intptr_t argarr[ MAX_VMSYSCALL_ARGS ];
+ int *imagePtr = (int *)&image[ programStack ];
+ int i;
+ for (i = 0; i < ARRAY_LEN(argarr); ++i) {
+ argarr[i] = *(++imagePtr);
+ }
+ r = vm->systemCall( argarr );
+ } else {
+ intptr_t* argptr = (intptr_t *)&image[ programStack + 4 ];
+ r = vm->systemCall( argptr );
+ }
+ }
+
+#ifdef DEBUG_VM
+ // this is just our stack frame pointer, only needed
+ // for debugging
+ *(int *)&image[ programStack + 4 ] = stomped;
+#endif
+
+ // save return value
+ opStackOfs++;
+ opStack[opStackOfs] = r;
+ programCounter = *(int *)&image[ programStack ];
+// vm->callLevel = temp;
+#ifdef DEBUG_VM
+ if ( vm_debugLevel ) {
+ Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );
+ }
+#endif
+ } else if ( (unsigned)programCounter >= vm->instructionCount ) {
+ Com_Error( ERR_DROP, "VM program counter out of range in OP_CALL" );
+ return 0;
+ } else {
+ programCounter = vm->instructionPointers[ programCounter ];
+ }
+ goto nextInstruction;
+
+ // push and pop are only needed for discarded or bad function return values
+ case OP_PUSH:
+ opStackOfs++;
+ goto nextInstruction;
+ case OP_POP:
+ opStackOfs--;
+ goto nextInstruction;
+
+ case OP_ENTER:
+#ifdef DEBUG_VM
+ profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );
+#endif
+ // get size of stack frame
+ v1 = r2;
+
+ programCounter += 1;
+ programStack -= v1;
+#ifdef DEBUG_VM
+ // save old stack frame for debugging traces
+ *(int *)&image[programStack+4] = programStack + v1;
+ if ( vm_debugLevel ) {
+ Com_Printf( "%s---> %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter - 5 ) );
+ if ( vm->breakFunction && programCounter - 5 == vm->breakFunction ) {
+ // this is to allow setting breakpoints here in the debugger
+ vm->breakCount++;
+// vm_debugLevel = 2;
+// VM_StackTrace( vm, programCounter, programStack );
+ }
+// vm->callLevel++;
+ }
+#endif
+ goto nextInstruction;
+ case OP_LEAVE:
+ // remove our stack frame
+ v1 = r2;
+
+ programStack += v1;
+
+ // grab the saved program counter
+ programCounter = *(int *)&image[ programStack ];
+#ifdef DEBUG_VM
+ profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );
+ if ( vm_debugLevel ) {
+// vm->callLevel--;
+ Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );
+ }
+#endif
+ // check for leaving the VM
+ if ( programCounter == -1 ) {
+ goto done;
+ } else if ( (unsigned)programCounter >= vm->codeLength ) {
+ Com_Error( ERR_DROP, "VM program counter out of range in OP_LEAVE" );
+ return 0;
+ }
+ goto nextInstruction;
+
+ /*
+ ===================================================================
+ BRANCHES
+ ===================================================================
+ */
+
+ case OP_JUMP:
+ if ( (unsigned)r0 >= vm->instructionCount )
+ {
+ Com_Error( ERR_DROP, "VM program counter out of range in OP_JUMP" );
+ return 0;
+ }
+
+ programCounter = vm->instructionPointers[ r0 ];
+
+ opStackOfs--;
+ goto nextInstruction;
+
+ case OP_EQ:
+ opStackOfs -= 2;
+ if ( r1 == r0 ) {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_NE:
+ opStackOfs -= 2;
+ if ( r1 != r0 ) {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_LTI:
+ opStackOfs -= 2;
+ if ( r1 < r0 ) {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_LEI:
+ opStackOfs -= 2;
+ if ( r1 <= r0 ) {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_GTI:
+ opStackOfs -= 2;
+ if ( r1 > r0 ) {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_GEI:
+ opStackOfs -= 2;
+ if ( r1 >= r0 ) {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_LTU:
+ opStackOfs -= 2;
+ if ( ((unsigned)r1) < ((unsigned)r0) ) {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_LEU:
+ opStackOfs -= 2;
+ if ( ((unsigned)r1) <= ((unsigned)r0) ) {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_GTU:
+ opStackOfs -= 2;
+ if ( ((unsigned)r1) > ((unsigned)r0) ) {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_GEU:
+ opStackOfs -= 2;
+ if ( ((unsigned)r1) >= ((unsigned)r0) ) {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_EQF:
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] == ((float *) opStack)[(uint8_t) (opStackOfs + 2)])
+ {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_NEF:
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] != ((float *) opStack)[(uint8_t) (opStackOfs + 2)])
+ {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_LTF:
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] < ((float *) opStack)[(uint8_t) (opStackOfs + 2)])
+ {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_LEF:
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) ((uint8_t) (opStackOfs + 1))] <= ((float *) opStack)[(uint8_t) ((uint8_t) (opStackOfs + 2))])
+ {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_GTF:
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] > ((float *) opStack)[(uint8_t) (opStackOfs + 2)])
+ {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+ case OP_GEF:
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] >= ((float *) opStack)[(uint8_t) (opStackOfs + 2)])
+ {
+ programCounter = r2; //vm->instructionPointers[r2];
+ goto nextInstruction;
+ } else {
+ programCounter += 1;
+ goto nextInstruction;
+ }
+
+
+ //===================================================================
+
+ case OP_NEGI:
+ opStack[opStackOfs] = -r0;
+ goto nextInstruction;
+ case OP_ADD:
+ opStackOfs--;
+ opStack[opStackOfs] = r1 + r0;
+ goto nextInstruction;
+ case OP_SUB:
+ opStackOfs--;
+ opStack[opStackOfs] = r1 - r0;
+ goto nextInstruction;
+ case OP_DIVI:
+ opStackOfs--;
+ opStack[opStackOfs] = r1 / r0;
+ goto nextInstruction;
+ case OP_DIVU:
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) / ((unsigned) r0);
+ goto nextInstruction;
+ case OP_MODI:
+ opStackOfs--;
+ opStack[opStackOfs] = r1 % r0;
+ goto nextInstruction;
+ case OP_MODU:
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) % ((unsigned) r0);
+ goto nextInstruction;
+ case OP_MULI:
+ opStackOfs--;
+ opStack[opStackOfs] = r1 * r0;
+ goto nextInstruction;
+ case OP_MULU:
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) * ((unsigned) r0);
+ goto nextInstruction;
+
+ case OP_BAND:
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) & ((unsigned) r0);
+ goto nextInstruction;
+ case OP_BOR:
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) | ((unsigned) r0);
+ goto nextInstruction;
+ case OP_BXOR:
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) ^ ((unsigned) r0);
+ goto nextInstruction;
+ case OP_BCOM:
+ opStack[opStackOfs] = ~((unsigned) r0);
+ goto nextInstruction;
+
+ case OP_LSH:
+ opStackOfs--;
+ opStack[opStackOfs] = r1 << r0;
+ goto nextInstruction;
+ case OP_RSHI:
+ opStackOfs--;
+ opStack[opStackOfs] = r1 >> r0;
+ goto nextInstruction;
+ case OP_RSHU:
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) >> r0;
+ goto nextInstruction;
+
+ case OP_NEGF:
+ ((float *) opStack)[opStackOfs] = -((float *) opStack)[opStackOfs];
+ goto nextInstruction;
+ case OP_ADDF:
+ opStackOfs--;
+ ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] + ((float *) opStack)[(uint8_t) (opStackOfs + 1)];
+ goto nextInstruction;
+ case OP_SUBF:
+ opStackOfs--;
+ ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] - ((float *) opStack)[(uint8_t) (opStackOfs + 1)];
+ goto nextInstruction;
+ case OP_DIVF:
+ opStackOfs--;
+ ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] / ((float *) opStack)[(uint8_t) (opStackOfs + 1)];
+ goto nextInstruction;
+ case OP_MULF:
+ opStackOfs--;
+ ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] * ((float *) opStack)[(uint8_t) (opStackOfs + 1)];
+ goto nextInstruction;
+
+ case OP_CVIF:
+ ((float *) opStack)[opStackOfs] = (float) opStack[opStackOfs];
+ goto nextInstruction;
+ case OP_CVFI:
+ opStack[opStackOfs] = static_cast<int>(((float *) opStack)[opStackOfs]);
+ goto nextInstruction;
+ case OP_SEX8:
+ opStack[opStackOfs] = (signed char) opStack[opStackOfs];
+ goto nextInstruction;
+ case OP_SEX16:
+ opStack[opStackOfs] = (short) opStack[opStackOfs];
+ goto nextInstruction;
+ }
+ }
+
+done:
+ vm->currentlyInterpreting = false;
+
+ if (opStackOfs != 1 || *opStack != 0xDEADBEEF)
+ Com_Error(ERR_DROP, "Interpreter error: opStack[0] = %X, opStackOfs = %d", opStack[0], opStackOfs);
+
+ vm->programStack = stackOnEntry;
+
+ // return the result
+ return opStack[opStackOfs];
+}
diff --git a/src/qcommon/vm_local.h b/src/qcommon/vm_local.h
new file mode 100644
index 0000000..b4ce844
--- /dev/null
+++ b/src/qcommon/vm_local.h
@@ -0,0 +1,204 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "q_shared.h"
+#include "qcommon.h"
+
+// Max number of arguments to pass from engine to vm's vmMain function.
+// command number + 3 arguments
+#define MAX_VMMAIN_ARGS 4
+
+// Max number of arguments to pass from a vm to engine's syscall handler function for the vm.
+// syscall number + 9 arguments
+#define MAX_VMSYSCALL_ARGS 20
+
+// don't change, this is hardcoded into x86 VMs, opStack protection relies
+// on this
+#define OPSTACK_SIZE 1024
+#define OPSTACK_MASK (OPSTACK_SIZE-1)
+
+// don't change
+// Hardcoded in q3asm a reserved at end of bss
+#define PROGRAM_STACK_SIZE 0x10000
+#define PROGRAM_STACK_MASK (PROGRAM_STACK_SIZE-1)
+
+typedef enum {
+ OP_UNDEF,
+
+ OP_IGNORE,
+
+ OP_BREAK,
+
+ OP_ENTER,
+ OP_LEAVE,
+ OP_CALL,
+ OP_PUSH,
+ OP_POP,
+
+ OP_CONST,
+ OP_LOCAL,
+
+ OP_JUMP,
+
+ //-------------------
+
+ OP_EQ,
+ OP_NE,
+
+ OP_LTI,
+ OP_LEI,
+ OP_GTI,
+ OP_GEI,
+
+ OP_LTU,
+ OP_LEU,
+ OP_GTU,
+ OP_GEU,
+
+ OP_EQF,
+ OP_NEF,
+
+ OP_LTF,
+ OP_LEF,
+ OP_GTF,
+ OP_GEF,
+
+ //-------------------
+
+ OP_LOAD1,
+ OP_LOAD2,
+ OP_LOAD4,
+ OP_STORE1,
+ OP_STORE2,
+ OP_STORE4, // *(stack[top-1]) = stack[top]
+ OP_ARG,
+
+ OP_BLOCK_COPY,
+
+ //-------------------
+
+ OP_SEX8,
+ OP_SEX16,
+
+ OP_NEGI,
+ OP_ADD,
+ OP_SUB,
+ OP_DIVI,
+ OP_DIVU,
+ OP_MODI,
+ OP_MODU,
+ OP_MULI,
+ OP_MULU,
+
+ OP_BAND,
+ OP_BOR,
+ OP_BXOR,
+ OP_BCOM,
+
+ OP_LSH,
+ OP_RSHI,
+ OP_RSHU,
+
+ OP_NEGF,
+ OP_ADDF,
+ OP_SUBF,
+ OP_DIVF,
+ OP_MULF,
+
+ OP_CVIF,
+ OP_CVFI
+} opcode_t;
+
+
+
+typedef int vmptr_t;
+
+typedef struct vmSymbol_s {
+ struct vmSymbol_s *next;
+ int symValue;
+ int profileCount;
+ char symName[1]; // variable sized
+} vmSymbol_t;
+
+#define VM_OFFSET_PROGRAM_STACK 0
+#define VM_OFFSET_SYSTEM_CALL 4
+
+struct vm_s {
+ // DO NOT MOVE OR CHANGE THESE WITHOUT CHANGING THE VM_OFFSET_* DEFINES
+ // USED BY THE ASM CODE
+ int programStack; // the vm may be recursively entered
+ intptr_t (*systemCall)( intptr_t *parms );
+
+ //------------------------------------
+
+ char name[MAX_QPATH];
+ void *searchPath; // hint for FS_ReadFileDir()
+
+ // for dynamic linked modules
+ void *dllHandle;
+ intptr_t (QDECL *entryPoint)( int callNum, ... );
+ void (*destroy)(vm_t* self);
+
+ // for interpreted modules
+ bool currentlyInterpreting;
+
+ bool compiled;
+ byte *codeBase;
+ int entryOfs;
+ int codeLength;
+
+ intptr_t *instructionPointers;
+ int instructionCount;
+
+ byte *dataBase;
+ int dataMask;
+
+ int stackBottom; // if programStack < stackBottom, error
+
+ int numSymbols;
+ struct vmSymbol_s *symbols;
+
+ int callLevel; // counts recursive VM_Call
+ int breakFunction; // increment breakCount on function entry to this
+ int breakCount;
+
+ byte *jumpTableTargets;
+ int numJumpTableTargets;
+};
+
+
+extern vm_t *currentVM;
+extern int vm_debugLevel;
+
+void VM_Compile( vm_t *vm, vmHeader_t *header );
+int VM_CallCompiled( vm_t *vm, int *args );
+
+void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header );
+int VM_CallInterpreted( vm_t *vm, int *args );
+
+vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value );
+int VM_SymbolToValue( vm_t *vm, const char *symbol );
+const char *VM_ValueToSymbol( vm_t *vm, int value );
+void VM_LogSyscalls( int *args );
+
+void VM_BlockCopy(unsigned int dest, unsigned int src, size_t n);
diff --git a/src/qcommon/vm_x86.cpp b/src/qcommon/vm_x86.cpp
new file mode 100644
index 0000000..c3373aa
--- /dev/null
+++ b/src/qcommon/vm_x86.cpp
@@ -0,0 +1,1840 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// vm_x86.c -- load time compiler and execution environment for x86
+
+#include "vm.h"
+#include "vm_local.h"
+
+#ifdef _WIN32
+ #include <windows.h>
+#else
+ #ifdef __FreeBSD__
+ #include <sys/types.h>
+ #endif
+
+ #include <sys/mman.h> // for PROT_ stuff
+
+ /* need this on NX enabled systems (i386 with PAE kernel or
+ * noexec32=on x86_64) */
+ #define VM_X86_MMAP
+
+ // workaround for systems that use the old MAP_ANON macro
+ #ifndef MAP_ANONYMOUS
+ #define MAP_ANONYMOUS MAP_ANON
+ #endif
+#endif
+
+static void VM_Destroy_Compiled(vm_t* self);
+
+/*
+
+ eax scratch
+ ebx/bl opStack offset
+ ecx scratch (required for shifts)
+ edx scratch (required for divisions)
+ esi program stack
+ edi opStack base
+x86_64:
+ r8 vm->instructionPointers
+ r9 vm->dataBase
+
+*/
+
+#define VMFREE_BUFFERS() do {Z_Free(buf); Z_Free(jused);} while(0)
+static byte *buf = NULL;
+static byte *jused = NULL;
+static int jusedSize = 0;
+static int compiledOfs = 0;
+static byte *code = NULL;
+static int pc = 0;
+
+#define FTOL_PTR
+
+static int instruction, pass;
+static int lastConst = 0;
+static int oc0, oc1, pop0, pop1;
+static int jlabel;
+
+typedef enum
+{
+ LAST_COMMAND_NONE = 0,
+ LAST_COMMAND_MOV_STACK_EAX,
+ LAST_COMMAND_SUB_BL_1,
+ LAST_COMMAND_SUB_BL_2,
+} ELastCommand;
+
+typedef enum
+{
+ VM_JMP_VIOLATION = 0,
+ VM_BLOCK_COPY = 1
+} ESysCallType;
+
+static ELastCommand LastCommand;
+
+static int iss8(int32_t v)
+{
+ return (SCHAR_MIN <= v && v <= SCHAR_MAX);
+}
+
+#if 0
+static int isu8(uint32_t v)
+{
+ return (v <= UCHAR_MAX);
+}
+#endif
+
+static int NextConstant4(void)
+{
+ return (code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24));
+}
+
+static int Constant4( void ) {
+ int v;
+
+ v = NextConstant4();
+ pc += 4;
+ return v;
+}
+
+static int Constant1( void ) {
+ int v;
+
+ v = code[pc];
+ pc += 1;
+ return v;
+}
+
+static void Emit1( int v )
+{
+ buf[ compiledOfs ] = v;
+ compiledOfs++;
+
+ LastCommand = LAST_COMMAND_NONE;
+}
+
+static void Emit2(int v)
+{
+ Emit1(v & 255);
+ Emit1((v >> 8) & 255);
+}
+
+
+static void Emit4(int v)
+{
+ Emit1(v & 0xFF);
+ Emit1((v >> 8) & 0xFF);
+ Emit1((v >> 16) & 0xFF);
+ Emit1((v >> 24) & 0xFF);
+}
+
+static void EmitPtr(void *ptr)
+{
+ intptr_t v = (intptr_t) ptr;
+
+ Emit4(v);
+#if idx64
+ Emit1((v >> 32) & 0xFF);
+ Emit1((v >> 40) & 0xFF);
+ Emit1((v >> 48) & 0xFF);
+ Emit1((v >> 56) & 0xFF);
+#endif
+}
+
+static int Hex( int c ) {
+ if ( c >= 'a' && c <= 'f' ) {
+ return 10 + c - 'a';
+ }
+ if ( c >= 'A' && c <= 'F' ) {
+ return 10 + c - 'A';
+ }
+ if ( c >= '0' && c <= '9' ) {
+ return c - '0';
+ }
+
+ VMFREE_BUFFERS();
+ Com_Error( ERR_DROP, "Hex: bad char '%c'", c );
+
+ return 0;
+}
+static void EmitString( const char *string ) {
+ int c1, c2;
+ int v;
+
+ while ( 1 ) {
+ c1 = string[0];
+ c2 = string[1];
+
+ v = ( Hex( c1 ) << 4 ) | Hex( c2 );
+ Emit1( v );
+
+ if ( !string[2] ) {
+ break;
+ }
+ string += 3;
+ }
+}
+static void EmitRexString(byte rex, const char *string)
+{
+#if idx64
+ if(rex)
+ Emit1(rex);
+#endif
+
+ EmitString(string);
+}
+
+
+#define MASK_REG(modrm, mask) \
+ do { \
+ EmitString("81"); \
+ EmitString((modrm)); \
+ Emit4((mask)); \
+ } while(0)
+
+// add bl, bytes
+#define STACK_PUSH(bytes) \
+ do { \
+ EmitString("80 C3"); \
+ Emit1(bytes); \
+ } while(0)
+
+// sub bl, bytes
+#define STACK_POP(bytes) \
+ do { \
+ EmitString("80 EB"); \
+ Emit1(bytes); \
+ } while(0)
+
+static void EmitCommand(ELastCommand command)
+{
+ switch(command)
+ {
+ case LAST_COMMAND_MOV_STACK_EAX:
+ EmitString("89 04 9F"); // mov dword ptr [edi + ebx * 4], eax
+ break;
+
+ case LAST_COMMAND_SUB_BL_1:
+ STACK_POP(1); // sub bl, 1
+ break;
+
+ case LAST_COMMAND_SUB_BL_2:
+ STACK_POP(2); // sub bl, 2
+ break;
+ default:
+ break;
+ }
+ LastCommand = command;
+}
+
+static void EmitPushStack(vm_t *vm)
+{
+ if (!jlabel)
+ {
+ if(LastCommand == LAST_COMMAND_SUB_BL_1)
+ { // sub bl, 1
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ return;
+ }
+ if(LastCommand == LAST_COMMAND_SUB_BL_2)
+ { // sub bl, 2
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ STACK_POP(1); // sub bl, 1
+ return;
+ }
+ }
+
+ STACK_PUSH(1); // add bl, 1
+}
+
+static void EmitMovEAXStack(vm_t *vm, int andit)
+{
+ if(!jlabel)
+ {
+ if(LastCommand == LAST_COMMAND_MOV_STACK_EAX)
+ { // mov [edi + ebx * 4], eax
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ }
+ else if(pop1 == OP_CONST && buf[compiledOfs-7] == 0xC7 && buf[compiledOfs-6] == 0x04 && buf[compiledOfs - 5] == 0x9F)
+ { // mov [edi + ebx * 4], 0x12345678
+ compiledOfs -= 7;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ EmitString("B8"); // mov eax, 0x12345678
+
+ if(andit)
+ Emit4(lastConst & andit);
+ else
+ Emit4(lastConst);
+
+ return;
+ }
+ else if(pop1 != OP_DIVI && pop1 != OP_DIVU && pop1 != OP_MULI && pop1 != OP_MULU &&
+ pop1 != OP_STORE4 && pop1 != OP_STORE2 && pop1 != OP_STORE1)
+ {
+ EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4]
+ }
+ }
+ else
+ EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4]
+
+ if(andit)
+ {
+ EmitString("25"); // and eax, 0x12345678
+ Emit4(andit);
+ }
+}
+
+void EmitMovECXStack(vm_t *vm)
+{
+ if(!jlabel)
+ {
+ if(LastCommand == LAST_COMMAND_MOV_STACK_EAX) // mov [edi + ebx * 4], eax
+ {
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ EmitString("89 C1"); // mov ecx, eax
+ return;
+ }
+ if(pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
+ pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1)
+ {
+ EmitString("89 C1"); // mov ecx, eax
+ return;
+ }
+ }
+
+ EmitString("8B 0C 9F"); // mov ecx, dword ptr [edi + ebx * 4]
+}
+
+
+void EmitMovEDXStack(vm_t *vm, int andit)
+{
+ if(!jlabel)
+ {
+ if(LastCommand == LAST_COMMAND_MOV_STACK_EAX)
+ { // mov dword ptr [edi + ebx * 4], eax
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+
+ EmitString("8B D0"); // mov edx, eax
+ }
+ else if(pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
+ pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1)
+ {
+ EmitString("8B D0"); // mov edx, eax
+ }
+ else if(pop1 == OP_CONST && buf[compiledOfs-7] == 0xC7 && buf[compiledOfs-6] == 0x07 && buf[compiledOfs - 5] == 0x9F)
+ { // mov dword ptr [edi + ebx * 4], 0x12345678
+ compiledOfs -= 7;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ EmitString("BA"); // mov edx, 0x12345678
+
+ if(andit)
+ Emit4(lastConst & andit);
+ else
+ Emit4(lastConst);
+
+ return;
+ }
+ else
+ EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4]
+
+ }
+ else
+ EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4]
+
+ if(andit)
+ MASK_REG("E2", andit); // and edx, 0x12345678
+}
+
+#define JUSED(x) \
+ do { \
+ if (x < 0 || x >= vm->instructionCount) { \
+ VMFREE_BUFFERS(); \
+ Com_Error( ERR_DROP, \
+ "VM_CompileX86: jump target out of range at offset %d", pc ); \
+ } \
+ jused[x] = 1; \
+ } while(0)
+
+#define SET_JMPOFS(x) do { buf[(x)] = compiledOfs - ((x) + 1); } while(0)
+
+
+/*
+=================
+ErrJump
+Error handler for jump/call to invalid instruction number
+=================
+*/
+
+static void __attribute__((__noreturn__)) ErrJump(void)
+{
+ Com_Error(ERR_DROP, "program tried to execute code outside VM");
+}
+
+/*
+=================
+DoSyscall
+
+Assembler helper routines will write its arguments directly to global variables so as to
+work around different calling conventions
+=================
+*/
+
+int vm_syscallNum;
+int vm_programStack;
+int *vm_opStackBase;
+uint8_t vm_opStackOfs;
+intptr_t vm_arg;
+
+static void DoSyscall(void)
+{
+ vm_t *savedVM;
+
+ // save currentVM so as to allow for recursive VM entry
+ savedVM = currentVM;
+ // modify VM stack pointer for recursive VM entry
+ currentVM->programStack = vm_programStack - 4;
+
+ if(vm_syscallNum < 0)
+ {
+ int *data, *ret;
+#if idx64
+ int index;
+ intptr_t args[MAX_VMSYSCALL_ARGS];
+#endif
+
+ data = (int *) (savedVM->dataBase + vm_programStack + 4);
+ ret = &vm_opStackBase[vm_opStackOfs + 1];
+
+#if idx64
+ args[0] = ~vm_syscallNum;
+ for(index = 1; index < ARRAY_LEN(args); index++)
+ args[index] = data[index];
+
+ *ret = savedVM->systemCall(args);
+#else
+ data[0] = ~vm_syscallNum;
+ *ret = savedVM->systemCall((intptr_t *) data);
+#endif
+ }
+ else
+ {
+ switch(vm_syscallNum)
+ {
+ case VM_JMP_VIOLATION:
+ ErrJump();
+ break;
+ case VM_BLOCK_COPY:
+ if(vm_opStackOfs < 1)
+ Com_Error(ERR_DROP, "VM_BLOCK_COPY failed due to corrupted opStack");
+
+ VM_BlockCopy(vm_opStackBase[(vm_opStackOfs - 1)], vm_opStackBase[vm_opStackOfs], vm_arg);
+ break;
+ default:
+ Com_Error(ERR_DROP, "Unknown VM operation %d", vm_syscallNum);
+ break;
+ }
+ }
+
+ currentVM = savedVM;
+}
+
+/*
+=================
+EmitCallRel
+Relative call to vm->codeBase + callOfs
+=================
+*/
+
+void EmitCallRel(vm_t *vm, int callOfs)
+{
+ EmitString("E8"); // call 0x12345678
+ Emit4(callOfs - compiledOfs - 4);
+}
+
+/*
+=================
+EmitCallDoSyscall
+Call to DoSyscall()
+=================
+*/
+
+int EmitCallDoSyscall(vm_t *vm)
+{
+ // use edx register to store DoSyscall address
+ EmitRexString(0x48, "BA"); // mov edx, DoSyscall
+ EmitPtr((void*)DoSyscall);
+
+ // Push important registers to stack as we can't really make
+ // any assumptions about calling conventions.
+ EmitString("51"); // push ebx
+ EmitString("56"); // push esi
+ EmitString("57"); // push edi
+#if idx64
+ EmitRexString(0x41, "50"); // push r8
+ EmitRexString(0x41, "51"); // push r9
+#endif
+
+ // write arguments to global vars
+ // syscall number
+ EmitString("A3"); // mov [0x12345678], eax
+ EmitPtr(&vm_syscallNum);
+ // vm_programStack value
+ EmitString("89 F0"); // mov eax, esi
+ EmitString("A3"); // mov [0x12345678], eax
+ EmitPtr(&vm_programStack);
+ // vm_opStackOfs
+ EmitString("88 D8"); // mov al, bl
+ EmitString("A2"); // mov [0x12345678], al
+ EmitPtr(&vm_opStackOfs);
+ // vm_opStackBase
+ EmitRexString(0x48, "89 F8"); // mov eax, edi
+ EmitRexString(0x48, "A3"); // mov [0x12345678], eax
+ EmitPtr(&vm_opStackBase);
+ // vm_arg
+ EmitString("89 C8"); // mov eax, ecx
+ EmitString("A3"); // mov [0x12345678], eax
+ EmitPtr(&vm_arg);
+
+ // align the stack pointer to a 16-byte-boundary
+ EmitString("55"); // push ebp
+ EmitRexString(0x48, "89 E5"); // mov ebp, esp
+ EmitRexString(0x48, "83 E4 F0"); // and esp, 0xFFFFFFF0
+
+ // call the syscall wrapper function DoSyscall()
+
+ EmitString("FF D2"); // call edx
+
+ // reset the stack pointer to its previous value
+ EmitRexString(0x48, "89 EC"); // mov esp, ebp
+ EmitString("5D"); // pop ebp
+
+#if idx64
+ EmitRexString(0x41, "59"); // pop r9
+ EmitRexString(0x41, "58"); // pop r8
+#endif
+ EmitString("5F"); // pop edi
+ EmitString("5E"); // pop esi
+ EmitString("59"); // pop ebx
+
+ EmitString("C3"); // ret
+
+ return compiledOfs;
+}
+
+/*
+=================
+EmitCallErrJump
+Emit the code that triggers execution of the jump violation handler
+=================
+*/
+
+static void EmitCallErrJump(vm_t *vm, int sysCallOfs)
+{
+ EmitString("B8"); // mov eax, 0x12345678
+ Emit4(VM_JMP_VIOLATION);
+
+ EmitCallRel(vm, sysCallOfs);
+}
+
+/*
+=================
+EmitCallProcedure
+VM OP_CALL procedure for call destinations obtained at runtime
+=================
+*/
+
+int EmitCallProcedure(vm_t *vm, int sysCallOfs)
+{
+ int jmpSystemCall, jmpBadAddr;
+ int retval;
+
+ EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4]
+ STACK_POP(1); // sub bl, 1
+ EmitString("85 C0"); // test eax, eax
+
+ // Jump to syscall code, 1 byte offset should suffice
+ EmitString("7C"); // jl systemCall
+ jmpSystemCall = compiledOfs++;
+
+ /************ Call inside VM ************/
+
+ EmitString("81 F8"); // cmp eax, vm->instructionCount
+ Emit4(vm->instructionCount);
+
+ // Error jump if invalid jump target
+ EmitString("73"); // jae badAddr
+ jmpBadAddr = compiledOfs++;
+
+#if idx64
+ EmitRexString(0x49, "FF 14 C0"); // call qword ptr [r8 + eax * 8]
+#else
+ EmitString("FF 14 85"); // call dword ptr [vm->instructionPointers + eax * 4]
+ Emit4((intptr_t) vm->instructionPointers);
+#endif
+ EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("C3"); // ret
+
+ // badAddr:
+ SET_JMPOFS(jmpBadAddr);
+ EmitCallErrJump(vm, sysCallOfs);
+
+ /************ System Call ************/
+
+ // systemCall:
+ SET_JMPOFS(jmpSystemCall);
+ retval = compiledOfs;
+
+ EmitCallRel(vm, sysCallOfs);
+
+ // have opStack reg point at return value
+ STACK_PUSH(1); // add bl, 1
+ EmitString("C3"); // ret
+
+ return retval;
+}
+
+/*
+=================
+EmitJumpIns
+Jump to constant instruction number
+=================
+*/
+
+void EmitJumpIns(vm_t *vm, const char *jmpop, int cdest)
+{
+ JUSED(cdest);
+
+ EmitString(jmpop); // j??? 0x12345678
+
+ // we only know all the jump addresses in the third pass
+ if(pass == 2)
+ Emit4(vm->instructionPointers[cdest] - compiledOfs - 4);
+ else
+ compiledOfs += 4;
+}
+
+/*
+=================
+EmitCallIns
+Call to constant instruction number
+=================
+*/
+
+void EmitCallIns(vm_t *vm, int cdest)
+{
+ JUSED(cdest);
+
+ EmitString("E8"); // call 0x12345678
+
+ // we only know all the jump addresses in the third pass
+ if(pass == 2)
+ Emit4(vm->instructionPointers[cdest] - compiledOfs - 4);
+ else
+ compiledOfs += 4;
+}
+
+/*
+=================
+EmitCallConst
+Call to constant instruction number or syscall
+=================
+*/
+
+void EmitCallConst(vm_t *vm, int cdest, int callProcOfsSyscall)
+{
+ if(cdest < 0)
+ {
+ EmitString("B8"); // mov eax, cdest
+ Emit4(cdest);
+
+ EmitCallRel(vm, callProcOfsSyscall);
+ }
+ else
+ EmitCallIns(vm, cdest);
+}
+
+/*
+=================
+EmitBranchConditions
+Emits x86 branch condition as given in op
+=================
+*/
+void EmitBranchConditions(vm_t *vm, int op)
+{
+ switch(op)
+ {
+ case OP_EQ:
+ EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678
+ break;
+ case OP_NE:
+ EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678
+ break;
+ case OP_LTI:
+ EmitJumpIns(vm, "0F 8C", Constant4()); // jl 0x12345678
+ break;
+ case OP_LEI:
+ EmitJumpIns(vm, "0F 8E", Constant4()); // jle 0x12345678
+ break;
+ case OP_GTI:
+ EmitJumpIns(vm, "0F 8F", Constant4()); // jg 0x12345678
+ break;
+ case OP_GEI:
+ EmitJumpIns(vm, "0F 8D", Constant4()); // jge 0x12345678
+ break;
+ case OP_LTU:
+ EmitJumpIns(vm, "0F 82", Constant4()); // jb 0x12345678
+ break;
+ case OP_LEU:
+ EmitJumpIns(vm, "0F 86", Constant4()); // jbe 0x12345678
+ break;
+ case OP_GTU:
+ EmitJumpIns(vm, "0F 87", Constant4()); // ja 0x12345678
+ break;
+ case OP_GEU:
+ EmitJumpIns(vm, "0F 83", Constant4()); // jae 0x12345678
+ break;
+ }
+}
+
+
+/*
+=================
+ConstOptimize
+Constant values for immediately following instructions may be translated to immediate values
+instead of opStack operations, which will save expensive operations on memory
+=================
+*/
+
+static bool ConstOptimize(vm_t *vm, int callProcOfsSyscall)
+{
+ int v;
+ int op1;
+
+ // we can safely perform optimizations only in case if
+ // we are 100% sure that next instruction is not a jump label
+ if (vm->jumpTableTargets && !jused[instruction])
+ op1 = code[pc+4];
+ else
+ return false;
+
+ switch ( op1 ) {
+
+ case OP_LOAD4:
+ EmitPushStack(vm);
+#if idx64
+ EmitRexString(0x41, "8B 81"); // mov eax, dword ptr [r9 + 0x12345678]
+ Emit4(Constant4() & vm->dataMask);
+#else
+ EmitString("B8"); // mov eax, 0x12345678
+ EmitPtr(vm->dataBase + (Constant4() & vm->dataMask));
+ EmitString("8B 00"); // mov eax, dword ptr [eax]
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+
+ pc++; // OP_LOAD4
+ instruction += 1;
+ return true;
+
+ case OP_LOAD2:
+ EmitPushStack(vm);
+#if idx64
+ EmitRexString(0x41, "0F B7 81"); // movzx eax, word ptr [r9 + 0x12345678]
+ Emit4(Constant4() & vm->dataMask);
+#else
+ EmitString("B8"); // mov eax, 0x12345678
+ EmitPtr(vm->dataBase + (Constant4() & vm->dataMask));
+ EmitString("0F B7 00"); // movzx eax, word ptr [eax]
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+
+ pc++; // OP_LOAD2
+ instruction += 1;
+ return true;
+
+ case OP_LOAD1:
+ EmitPushStack(vm);
+#if idx64
+ EmitRexString(0x41, "0F B6 81"); // movzx eax, byte ptr [r9 + 0x12345678]
+ Emit4(Constant4() & vm->dataMask);
+#else
+ EmitString("B8"); // mov eax, 0x12345678
+ EmitPtr(vm->dataBase + (Constant4() & vm->dataMask));
+ EmitString("0F B6 00"); // movzx eax, byte ptr [eax]
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+
+ pc++; // OP_LOAD1
+ instruction += 1;
+ return true;
+
+ case OP_STORE4:
+ EmitMovEAXStack(vm, (vm->dataMask & ~3));
+#if idx64
+ EmitRexString(0x41, "C7 04 01"); // mov dword ptr [r9 + eax], 0x12345678
+ Emit4(Constant4());
+#else
+ EmitString("C7 80"); // mov dword ptr [eax + 0x12345678], 0x12345678
+ Emit4((intptr_t) vm->dataBase);
+ Emit4(Constant4());
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ pc++; // OP_STORE4
+ instruction += 1;
+ return true;
+
+ case OP_STORE2:
+ EmitMovEAXStack(vm, (vm->dataMask & ~1));
+#if idx64
+ Emit1(0x66); // mov word ptr [r9 + eax], 0x1234
+ EmitRexString(0x41, "C7 04 01");
+ Emit2(Constant4());
+#else
+ EmitString("66 C7 80"); // mov word ptr [eax + 0x12345678], 0x1234
+ Emit4((intptr_t) vm->dataBase);
+ Emit2(Constant4());
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+
+ pc++; // OP_STORE2
+ instruction += 1;
+ return true;
+
+ case OP_STORE1:
+ EmitMovEAXStack(vm, vm->dataMask);
+#if idx64
+ EmitRexString(0x41, "C6 04 01"); // mov byte [r9 + eax], 0x12
+ Emit1(Constant4());
+#else
+ EmitString("C6 80"); // mov byte ptr [eax + 0x12345678], 0x12
+ Emit4((intptr_t) vm->dataBase);
+ Emit1(Constant4());
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+
+ pc++; // OP_STORE1
+ instruction += 1;
+ return true;
+
+ case OP_ADD:
+ v = Constant4();
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("83 C0"); // add eax, 0x7F
+ Emit1(v);
+ }
+ else
+ {
+ EmitString("05"); // add eax, 0x12345678
+ Emit4(v);
+ }
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc++; // OP_ADD
+ instruction += 1;
+ return true;
+
+ case OP_SUB:
+ v = Constant4();
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("83 E8"); // sub eax, 0x7F
+ Emit1(v);
+ }
+ else
+ {
+ EmitString("2D"); // sub eax, 0x12345678
+ Emit4(v);
+ }
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc++; // OP_SUB
+ instruction += 1;
+ return true;
+
+ case OP_MULI:
+ v = Constant4();
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("6B C0"); // imul eax, 0x7F
+ Emit1(v);
+ }
+ else
+ {
+ EmitString("69 C0"); // imul eax, 0x12345678
+ Emit4(v);
+ }
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+ pc++; // OP_MULI
+ instruction += 1;
+
+ return true;
+
+ case OP_LSH:
+ v = NextConstant4();
+ if(v < 0 || v > 31)
+ break;
+
+ EmitMovEAXStack(vm, 0);
+ EmitString("C1 E0"); // shl eax, 0x12
+ Emit1(v);
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 5; // CONST + OP_LSH
+ instruction += 1;
+ return true;
+
+ case OP_RSHI:
+ v = NextConstant4();
+ if(v < 0 || v > 31)
+ break;
+
+ EmitMovEAXStack(vm, 0);
+ EmitString("C1 F8"); // sar eax, 0x12
+ Emit1(v);
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 5; // CONST + OP_RSHI
+ instruction += 1;
+ return true;
+
+ case OP_RSHU:
+ v = NextConstant4();
+ if(v < 0 || v > 31)
+ break;
+
+ EmitMovEAXStack(vm, 0);
+ EmitString("C1 E8"); // shr eax, 0x12
+ Emit1(v);
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 5; // CONST + OP_RSHU
+ instruction += 1;
+ return true;
+
+ case OP_BAND:
+ v = Constant4();
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("83 E0"); // and eax, 0x7F
+ Emit1(v);
+ }
+ else
+ {
+ EmitString("25"); // and eax, 0x12345678
+ Emit4(v);
+ }
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 1; // OP_BAND
+ instruction += 1;
+ return true;
+
+ case OP_BOR:
+ v = Constant4();
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("83 C8"); // or eax, 0x7F
+ Emit1(v);
+ }
+ else
+ {
+ EmitString("0D"); // or eax, 0x12345678
+ Emit4(v);
+ }
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 1; // OP_BOR
+ instruction += 1;
+ return true;
+
+ case OP_BXOR:
+ v = Constant4();
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("83 F0"); // xor eax, 0x7F
+ Emit1(v);
+ }
+ else
+ {
+ EmitString("35"); // xor eax, 0x12345678
+ Emit4(v);
+ }
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 1; // OP_BXOR
+ instruction += 1;
+ return true;
+
+ case OP_EQ:
+ case OP_NE:
+ case OP_LTI:
+ case OP_LEI:
+ case OP_GTI:
+ case OP_GEI:
+ case OP_LTU:
+ case OP_LEU:
+ case OP_GTU:
+ case OP_GEU:
+ EmitMovEAXStack(vm, 0);
+ EmitCommand(LAST_COMMAND_SUB_BL_1);
+ EmitString("3D"); // cmp eax, 0x12345678
+ Emit4(Constant4());
+
+ pc++; // OP_*
+ EmitBranchConditions(vm, op1);
+ instruction++;
+
+ return true;
+
+ case OP_EQF:
+ case OP_NEF:
+ if(NextConstant4())
+ break;
+ pc += 5; // CONST + OP_EQF|OP_NEF
+
+ EmitMovEAXStack(vm, 0);
+ EmitCommand(LAST_COMMAND_SUB_BL_1);
+ // floating point hack :)
+ EmitString("25"); // and eax, 0x7FFFFFFF
+ Emit4(0x7FFFFFFF);
+ if(op1 == OP_EQF)
+ EmitJumpIns(vm, "0F 84", Constant4()); // jz 0x12345678
+ else
+ EmitJumpIns(vm, "0F 85", Constant4()); // jnz 0x12345678
+
+ instruction += 1;
+ return true;
+
+
+ case OP_JUMP:
+ EmitJumpIns(vm, "E9", Constant4()); // jmp 0x12345678
+
+ pc += 1; // OP_JUMP
+ instruction += 1;
+ return true;
+
+ case OP_CALL:
+ v = Constant4();
+ EmitCallConst(vm, v, callProcOfsSyscall);
+
+ pc += 1; // OP_CALL
+ instruction += 1;
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+#if idx64
+ #define EAX "%%rax"
+ #define EBX "%%rbx"
+ #define ESP "%%rsp"
+ #define EDI "%%rdi"
+#else
+ #define EAX "%%eax"
+ #define EBX "%%ebx"
+ #define ESP "%%esp"
+ #define EDI "%%edi"
+#endif
+
+static int Q_VMftol(void)
+{
+ int retval;
+
+ __asm__ volatile
+ (
+ "movss (" EDI ", " EBX ", 4), %%xmm0\n"
+ "cvttss2si %%xmm0, %0\n"
+ : "=r" (retval)
+ :
+ : "%xmm0"
+ );
+
+ return retval;
+}
+
+/*
+=================
+VM_Compile
+=================
+*/
+void VM_Compile(vm_t *vm, vmHeader_t *header)
+{
+ int op;
+ int maxLength;
+ int v;
+ int i;
+ int callProcOfsSyscall, callProcOfs, callDoSyscallOfs;
+
+ jusedSize = header->instructionCount + 2;
+
+ // allocate a very large temp buffer, we will shrink it later
+ maxLength = header->codeLength * 8 + 64;
+ buf = (byte*)Z_Malloc(maxLength);
+ jused = (byte*)Z_Malloc(jusedSize);
+ code = (byte*)Z_Malloc(header->codeLength+32);
+
+ ::memset(jused, 0, jusedSize);
+ ::memset(buf, 0, maxLength);
+
+ // copy code in larger buffer and put some zeros at the end
+ // so we can safely look ahead for a few instructions in it
+ // without a chance to get false-positive because of some garbage bytes
+ ::memset(code, 0, header->codeLength+32);
+ ::memcpy(code, (byte *)header + header->codeOffset, header->codeLength );
+
+ // ensure that the optimisation pass knows about all the jump
+ // table targets
+ pc = -1; // a bogus value to be printed in out-of-bounds error messages
+ for( i = 0; i < vm->numJumpTableTargets; i++ ) {
+ JUSED( *(int *)(vm->jumpTableTargets + ( i * sizeof( int ) ) ) );
+ }
+
+ // Start buffer with x86-VM specific procedures
+ compiledOfs = 0;
+
+ callDoSyscallOfs = compiledOfs;
+ callProcOfs = EmitCallDoSyscall(vm);
+ callProcOfsSyscall = EmitCallProcedure(vm, callDoSyscallOfs);
+ vm->entryOfs = compiledOfs;
+
+ for(pass=0; pass < 3; pass++) {
+ oc0 = -23423;
+ oc1 = -234354;
+ pop0 = -43435;
+ pop1 = -545455;
+
+ // translate all instructions
+ pc = 0;
+ instruction = 0;
+ //code = (byte *)header + header->codeOffset;
+ compiledOfs = vm->entryOfs;
+
+ LastCommand = LAST_COMMAND_NONE;
+
+ while(instruction < header->instructionCount)
+ {
+ if(compiledOfs > maxLength - 16)
+ {
+ VMFREE_BUFFERS();
+ Com_Error(ERR_DROP, "VM_CompileX86: maxLength exceeded");
+ }
+
+ vm->instructionPointers[ instruction ] = compiledOfs;
+
+ if ( !vm->jumpTableTargets )
+ jlabel = 1;
+ else
+ jlabel = jused[ instruction ];
+
+ instruction++;
+
+ if(pc > header->codeLength)
+ {
+ VMFREE_BUFFERS();
+ Com_Error(ERR_DROP, "VM_CompileX86: pc > header->codeLength");
+ }
+
+ op = code[ pc ];
+ pc++;
+ switch ( op ) {
+ case 0:
+ break;
+ case OP_BREAK:
+ EmitString("CC"); // int 3
+ break;
+ case OP_ENTER:
+ EmitString("81 EE"); // sub esi, 0x12345678
+ Emit4(Constant4());
+ break;
+ case OP_CONST:
+ if(ConstOptimize(vm, callProcOfsSyscall))
+ break;
+
+ EmitPushStack(vm);
+ EmitString("C7 04 9F"); // mov dword ptr [edi + ebx * 4], 0x12345678
+ lastConst = Constant4();
+
+ Emit4(lastConst);
+ if(code[pc] == OP_JUMP)
+ JUSED(lastConst);
+
+ break;
+ case OP_LOCAL:
+ EmitPushStack(vm);
+ EmitString("8D 86"); // lea eax, [0x12345678 + esi]
+ oc0 = oc1;
+ oc1 = Constant4();
+ Emit4(oc1);
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+ break;
+ case OP_ARG:
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("8B D6"); // mov edx, esi
+ EmitString("81 C2"); // add edx, 0x12345678
+ Emit4((Constant1() & 0xFF));
+ MASK_REG("E2", vm->dataMask); // and edx, 0x12345678
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_CALL:
+ EmitCallRel(vm, callProcOfs);
+ break;
+ case OP_PUSH:
+ EmitPushStack(vm);
+ break;
+ case OP_POP:
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_LEAVE:
+ v = Constant4();
+ EmitString("81 C6"); // add esi, 0x12345678
+ Emit4(v);
+ EmitString("C3"); // ret
+ break;
+ case OP_LOAD4:
+ if (code[pc] == OP_CONST && code[pc+5] == OP_ADD && code[pc+6] == OP_STORE4)
+ {
+ if(oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+ compiledOfs -= 12;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ }
+
+ pc++; // OP_CONST
+ v = Constant4();
+
+ EmitMovEDXStack(vm, vm->dataMask);
+ if(v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+#if idx64
+ EmitRexString(0x41, "FF 04 11"); // inc dword ptr [r9 + edx]
+#else
+ EmitString("FF 82"); // inc dword ptr [edx + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ }
+ else
+ {
+#if idx64
+ EmitRexString(0x41, "8B 04 11"); // mov eax, dword ptr [r9 + edx]
+#else
+ EmitString("8B 82"); // mov eax, dword ptr [edx + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitString("05"); // add eax, v
+ Emit4(v);
+
+ if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ }
+ else
+ {
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4]
+ MASK_REG("E2", vm->dataMask); // and edx, 0x12345678
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ }
+ }
+
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ pc++; // OP_ADD
+ pc++; // OP_STORE
+ instruction += 3;
+ break;
+ }
+
+ if(code[pc] == OP_CONST && code[pc+5] == OP_SUB && code[pc+6] == OP_STORE4)
+ {
+ if(oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+ compiledOfs -= 12;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ }
+
+ pc++; // OP_CONST
+ v = Constant4();
+
+ EmitMovEDXStack(vm, vm->dataMask);
+ if(v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+#if idx64
+ EmitRexString(0x41, "FF 0C 11"); // dec dword ptr [r9 + edx]
+#else
+ EmitString("FF 8A"); // dec dword ptr [edx + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ }
+ else
+ {
+#if idx64
+ EmitRexString(0x41, "8B 04 11"); // mov eax, dword ptr [r9 + edx]
+#else
+ EmitString("8B 82"); // mov eax, dword ptr [edx + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitString("2D"); // sub eax, v
+ Emit4(v);
+
+ if(oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ }
+ else
+ {
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4]
+ MASK_REG("E2", vm->dataMask); // and edx, 0x12345678
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ }
+ }
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ pc++; // OP_SUB
+ pc++; // OP_STORE
+ instruction += 3;
+ break;
+ }
+
+ if(buf[compiledOfs - 3] == 0x89 && buf[compiledOfs - 2] == 0x04 && buf[compiledOfs - 1] == 0x9F)
+ {
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ MASK_REG("E0", vm->dataMask); // and eax, 0x12345678
+#if idx64
+ EmitRexString(0x41, "8B 04 01"); // mov eax, dword ptr [r9 + eax]
+#else
+ EmitString("8B 80"); // mov eax, dword ptr [eax + 0x1234567]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+ break;
+ }
+
+ EmitMovEAXStack(vm, vm->dataMask);
+#if idx64
+ EmitRexString(0x41, "8B 04 01"); // mov eax, dword ptr [r9 + eax]
+#else
+ EmitString("8B 80"); // mov eax, dword ptr [eax + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+ break;
+ case OP_LOAD2:
+ EmitMovEAXStack(vm, vm->dataMask);
+#if idx64
+ EmitRexString(0x41, "0F B7 04 01"); // movzx eax, word ptr [r9 + eax]
+#else
+ EmitString("0F B7 80"); // movzx eax, word ptr [eax + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+ break;
+ case OP_LOAD1:
+ EmitMovEAXStack(vm, vm->dataMask);
+#if idx64
+ EmitRexString(0x41, "0F B6 04 01"); // movzx eax, byte ptr [r9 + eax]
+#else
+ EmitString("0F B6 80"); // movzx eax, byte ptr [eax + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+ break;
+ case OP_STORE4:
+ EmitMovEAXStack(vm, 0);
+ EmitString("8B 54 9F FC"); // mov edx, dword ptr -4[edi + ebx * 4]
+ MASK_REG("E2", vm->dataMask & ~3); // and edx, 0x12345678
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
+ break;
+ case OP_STORE2:
+ EmitMovEAXStack(vm, 0);
+ EmitString("8B 54 9F FC"); // mov edx, dword ptr -4[edi + ebx * 4]
+ MASK_REG("E2", vm->dataMask & ~1); // and edx, 0x12345678
+#if idx64
+ Emit1(0x66); // mov word ptr [r9 + edx], eax
+ EmitRexString(0x41, "89 04 11");
+#else
+ EmitString("66 89 82"); // mov word ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
+ break;
+ case OP_STORE1:
+ EmitMovEAXStack(vm, 0);
+ EmitString("8B 54 9F FC"); // mov edx, dword ptr -4[edi + ebx * 4]
+ MASK_REG("E2", vm->dataMask); // and edx, 0x12345678
+#if idx64
+ EmitRexString(0x41, "88 04 11"); // mov byte ptr [r9 + edx], eax
+#else
+ EmitString("88 82"); // mov byte ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
+ break;
+
+ case OP_EQ:
+ case OP_NE:
+ case OP_LTI:
+ case OP_LEI:
+ case OP_GTI:
+ case OP_GEI:
+ case OP_LTU:
+ case OP_LEU:
+ case OP_GTU:
+ case OP_GEU:
+ EmitMovEAXStack(vm, 0);
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
+ EmitString("39 44 9F 04"); // cmp eax, dword ptr 4[edi + ebx * 4]
+
+ EmitBranchConditions(vm, op);
+ break;
+ case OP_EQF:
+ case OP_NEF:
+ case OP_LTF:
+ case OP_LEF:
+ case OP_GTF:
+ case OP_GEF:
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
+ EmitString("D9 44 9F 04"); // fld dword ptr 4[edi + ebx * 4]
+ EmitString("D8 5C 9F 08"); // fcomp dword ptr 8[edi + ebx * 4]
+ EmitString("DF E0"); // fnstsw ax
+
+ switch(op)
+ {
+ case OP_EQF:
+ EmitString("F6 C4 40"); // test ah,0x40
+ EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678
+ break;
+ case OP_NEF:
+ EmitString("F6 C4 40"); // test ah,0x40
+ EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678
+ break;
+ case OP_LTF:
+ EmitString("F6 C4 01"); // test ah,0x01
+ EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678
+ break;
+ case OP_LEF:
+ EmitString("F6 C4 41"); // test ah,0x41
+ EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678
+ break;
+ case OP_GTF:
+ EmitString("F6 C4 41"); // test ah,0x41
+ EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678
+ break;
+ case OP_GEF:
+ EmitString("F6 C4 01"); // test ah,0x01
+ EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678
+ break;
+ }
+ break;
+ case OP_NEGI:
+ EmitMovEAXStack(vm, 0);
+ EmitString("F7 D8"); // neg eax
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+ break;
+ case OP_ADD:
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("01 44 9F FC"); // add dword ptr -4[edi + ebx * 4], eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_SUB:
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("29 44 9F FC"); // sub dword ptr -4[edi + ebx * 4], eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_DIVI:
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("99"); // cdq
+ EmitString("F7 3C 9F"); // idiv dword ptr [edi + ebx * 4]
+ EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_DIVU:
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("33 D2"); // xor edx, edx
+ EmitString("F7 34 9F"); // div dword ptr [edi + ebx * 4]
+ EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_MODI:
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("99" ); // cdq
+ EmitString("F7 3C 9F"); // idiv dword ptr [edi + ebx * 4]
+ EmitString("89 54 9F FC"); // mov dword ptr -4[edi + ebx * 4],edx
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_MODU:
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("33 D2"); // xor edx, edx
+ EmitString("F7 34 9F"); // div dword ptr [edi + ebx * 4]
+ EmitString("89 54 9F FC"); // mov dword ptr -4[edi + ebx * 4],edx
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_MULI:
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("F7 2C 9F"); // imul dword ptr [edi + ebx * 4]
+ EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_MULU:
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("F7 24 9F"); // mul dword ptr [edi + ebx * 4]
+ EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_BAND:
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("21 44 9F FC"); // and dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_BOR:
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("09 44 9F FC"); // or dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_BXOR:
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("31 44 9F FC"); // xor dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_BCOM:
+ EmitString("F7 14 9F"); // not dword ptr [edi + ebx * 4]
+ break;
+ case OP_LSH:
+ EmitMovECXStack(vm);
+ EmitString("D3 64 9F FC"); // shl dword ptr -4[edi + ebx * 4], cl
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_RSHI:
+ EmitMovECXStack(vm);
+ EmitString("D3 7C 9F FC"); // sar dword ptr -4[edi + ebx * 4], cl
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_RSHU:
+ EmitMovECXStack(vm);
+ EmitString("D3 6C 9F FC"); // shr dword ptr -4[edi + ebx * 4], cl
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_NEGF:
+ EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4]
+ EmitString("D9 E0"); // fchs
+ EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4]
+ break;
+ case OP_ADDF:
+ EmitString("D9 44 9F FC"); // fld dword ptr -4[edi + ebx * 4]
+ EmitString("D8 04 9F"); // fadd dword ptr [edi + ebx * 4]
+ EmitString("D9 5C 9F FC"); // fstp dword ptr -4[edi + ebx * 4]
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ break;
+ case OP_SUBF:
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4]
+ EmitString("D8 64 9F 04"); // fsub dword ptr 4[edi + ebx * 4]
+ EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4]
+ break;
+ case OP_DIVF:
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4]
+ EmitString("D8 74 9F 04"); // fdiv dword ptr 4[edi + ebx * 4]
+ EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4]
+ break;
+ case OP_MULF:
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4]
+ EmitString("D8 4C 9F 04"); // fmul dword ptr 4[edi + ebx * 4]
+ EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4]
+ break;
+ case OP_CVIF:
+ EmitString("DB 04 9F"); // fild dword ptr [edi + ebx * 4]
+ EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4]
+ break;
+ case OP_CVFI:
+#ifndef FTOL_PTR // WHENHELLISFROZENOVER
+ // not IEEE complient, but simple and fast
+ EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4]
+ EmitString("DB 1C 9F"); // fistp dword ptr [edi + ebx * 4]
+#else // FTOL_PTR
+ // call the library conversion function
+ EmitRexString(0x48, "BA"); // mov edx, Q_VMftol
+ EmitPtr((void*)Q_VMftol);
+ EmitRexString(0x48, "FF D2"); // call edx
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+#endif
+ break;
+ case OP_SEX8:
+ EmitString("0F BE 04 9F"); // movsx eax, byte ptr [edi + ebx * 4]
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+ break;
+ case OP_SEX16:
+ EmitString("0F BF 04 9F"); // movsx eax, word ptr [edi + ebx * 4]
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+ break;
+
+ case OP_BLOCK_COPY:
+ EmitString("B8"); // mov eax, 0x12345678
+ Emit4(VM_BLOCK_COPY);
+ EmitString("B9"); // mov ecx, 0x12345678
+ Emit4(Constant4());
+
+ EmitCallRel(vm, callDoSyscallOfs);
+
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
+ break;
+
+ case OP_JUMP:
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("8B 44 9F 04"); // mov eax, dword ptr 4[edi + ebx * 4]
+ EmitString("81 F8"); // cmp eax, vm->instructionCount
+ Emit4(vm->instructionCount);
+#if idx64
+ EmitString("73 04"); // jae +4
+ EmitRexString(0x49, "FF 24 C0"); // jmp qword ptr [r8 + eax * 8]
+#else
+ EmitString("73 07"); // jae +7
+ EmitString("FF 24 85"); // jmp dword ptr [instructionPointers + eax * 4]
+ Emit4((intptr_t) vm->instructionPointers);
+#endif
+ EmitCallErrJump(vm, callDoSyscallOfs);
+ break;
+ default:
+ VMFREE_BUFFERS();
+ Com_Error(ERR_DROP, "VM_CompileX86: bad opcode %i at offset %i", op, pc);
+ }
+ pop0 = pop1;
+ pop1 = op;
+ }
+ }
+
+ // copy to an exact sized buffer with the appropriate permission bits
+ vm->codeLength = compiledOfs;
+#ifdef VM_X86_MMAP
+ vm->codeBase = (byte*)mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+ if(vm->codeBase == MAP_FAILED)
+ Com_Error(ERR_FATAL, "VM_CompileX86: can't mmap memory");
+#elif _WIN32
+ // allocate memory with EXECUTE permissions under windows.
+ vm->codeBase = (byte*)VirtualAlloc(NULL, compiledOfs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(!vm->codeBase)
+ Com_Error(ERR_FATAL, "VM_CompileX86: VirtualAlloc failed");
+#else
+ vm->codeBase = malloc(compiledOfs);
+ if(!vm->codeBase)
+ Com_Error(ERR_FATAL, "VM_CompileX86: malloc failed");
+#endif
+
+ ::memcpy( vm->codeBase, buf, compiledOfs );
+
+#ifdef VM_X86_MMAP
+ if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC))
+ Com_Error(ERR_FATAL, "VM_CompileX86: mprotect failed");
+#elif _WIN32
+ {
+ DWORD oldProtect = 0;
+
+ // remove write permissions.
+ if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect))
+ Com_Error(ERR_FATAL, "VM_CompileX86: VirtualProtect failed");
+ }
+#endif
+
+ Z_Free( code );
+ Z_Free( buf );
+ Z_Free( jused );
+ Com_Printf( "VM file %s compiled to %i bytes of code\n", vm->name, compiledOfs );
+
+ vm->destroy = VM_Destroy_Compiled;
+
+ // offset all the instruction pointers for the new location
+ for ( i = 0 ; i < header->instructionCount ; i++ ) {
+ vm->instructionPointers[i] += (intptr_t) vm->codeBase;
+ }
+}
+
+void VM_Destroy_Compiled(vm_t* self)
+{
+#ifdef VM_X86_MMAP
+ munmap(self->codeBase, self->codeLength);
+#elif _WIN32
+ VirtualFree(self->codeBase, 0, MEM_RELEASE);
+#else
+ free(self->codeBase);
+#endif
+}
+
+/*
+==============
+VM_CallCompiled
+
+This function is called directly by the generated code
+==============
+*/
+
+#if defined(_MSC_VER) && defined(idx64)
+extern uint8_t qvmcall64(int *programStack, int *opStack, intptr_t *instructionPointers, byte *dataBase);
+#endif
+
+int VM_CallCompiled(vm_t *vm, int *args)
+{
+ byte stack[OPSTACK_SIZE + 15];
+ void *entryPoint;
+ int programStack, stackOnEntry;
+ byte *image;
+ int *opStack;
+ int opStackOfs;
+ int arg;
+
+ currentVM = vm;
+
+ // interpret the code
+ vm->currentlyInterpreting = true;
+
+ // we might be called recursively, so this might not be the very top
+ programStack = stackOnEntry = vm->programStack;
+
+ // set up the stack frame
+ image = vm->dataBase;
+
+ programStack -= ( 8 + 4 * MAX_VMMAIN_ARGS );
+
+ for ( arg = 0; arg < MAX_VMMAIN_ARGS; arg++ )
+ *(int *)&image[ programStack + 8 + arg * 4 ] = args[ arg ];
+
+ *(int *)&image[ programStack + 4 ] = 0; // return stack
+ *(int *)&image[ programStack ] = -1; // will terminate the loop on return
+
+ // off we go into generated code...
+ entryPoint = vm->codeBase + vm->entryOfs;
+ opStack = (int*)PADP(stack, 16);
+ *opStack = 0xDEADBEEF;
+ opStackOfs = 0;
+
+#ifdef _MSC_VER
+ #if idx64
+ opStackOfs = qvmcall64(&programStack, opStack, vm->instructionPointers, vm->dataBase);
+ #else
+ __asm
+ {
+ pushad
+
+ mov esi, dword ptr programStack
+ mov edi, dword ptr opStack
+ mov ebx, dword ptr opStackOfs
+
+ call entryPoint
+
+ mov dword ptr opStackOfs, ebx
+ mov dword ptr opStack, edi
+ mov dword ptr programStack, esi
+
+ popad
+ }
+ #endif
+#elif idx64
+ __asm__ volatile(
+ "movq %5, %%rax\n"
+ "movq %3, %%r8\n"
+ "movq %4, %%r9\n"
+ "push %%r15\n"
+ "push %%r14\n"
+ "push %%r13\n"
+ "push %%r12\n"
+ "callq *%%rax\n"
+ "pop %%r12\n"
+ "pop %%r13\n"
+ "pop %%r14\n"
+ "pop %%r15\n"
+ : "+S" (programStack), "+D" (opStack), "+b" (opStackOfs)
+ : "g" (vm->instructionPointers), "g" (vm->dataBase), "g" (entryPoint)
+ : "cc", "memory", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11"
+ );
+#else
+ __asm__ volatile(
+ "calll *%3\n"
+ : "+S" (programStack), "+D" (opStack), "+b" (opStackOfs)
+ : "g" (entryPoint)
+ : "cc", "memory", "%eax", "%ecx", "%edx"
+ );
+#endif
+
+ if(opStackOfs != 1 || *opStack != 0xDEADBEEF)
+ {
+ Com_Error(ERR_DROP, "opStack corrupted in compiled code");
+ }
+ if(programStack != stackOnEntry - (8 + 4 * MAX_VMMAIN_ARGS))
+ Com_Error(ERR_DROP, "programStack corrupted in compiled code");
+
+ vm->programStack = stackOnEntry;
+
+ return opStack[opStackOfs];
+}
diff --git a/src/renderercommon/CMakeLists.txt b/src/renderercommon/CMakeLists.txt
new file mode 100644
index 0000000..6464d32
--- /dev/null
+++ b/src/renderercommon/CMakeLists.txt
@@ -0,0 +1,77 @@
+include(${CMAKE_SOURCE_DIR}/cmake/SDL2.cmake)
+
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c ${SDL2_INCLUDE_DIRS} )
+
+add_library(
+ renderercommon STATIC
+ iqm.h
+ qgl.h
+ tr_common.h
+ tr_font.cpp
+ tr_image_bmp.cpp
+ tr_image_jpg.cpp
+ tr_image_pcx.cpp
+ tr_image_png.cpp
+ tr_image_tga.cpp
+ tr_noise.cpp
+ tr_public.h
+ tr_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/../sdl/sdl_gamma.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/../sdl/sdl_glimp.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jaricom.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcapimin.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcapistd.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcarith.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jccoefct.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jccolor.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcdctmgr.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jchuff.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcinit.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcmainct.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcmarker.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcmaster.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcomapi.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcparam.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcprepct.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jcsample.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jctrans.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdapimin.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdapistd.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdarith.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdatadst.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdatasrc.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdcoefct.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdcolor.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jddctmgr.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdhuff.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdinput.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdmainct.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdmarker.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdmaster.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdmerge.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdpostct.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdsample.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jdtrans.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jerror.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jfdctflt.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jfdctfst.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jfdctint.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jidctflt.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jidctfst.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jidctint.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jmemmgr.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jmemnobs.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jquant1.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jquant2.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/jpeg-8c/jutils.c
+ )
+
+add_definitions(
+ -DFLOATING_POINT
+ -DHAVE_LRINTF
+ -DUSE_INTERNAL_JPEG
+ -DUSE_RENDERER_DLOPEN
+ ${SDL2_DEFINES}
+ )
+
+target_link_libraries( renderercommon ${SDL2_LIBRARIES} )
diff --git a/src/renderercommon/iqm.h b/src/renderercommon/iqm.h
new file mode 100644
index 0000000..3011efc
--- /dev/null
+++ b/src/renderercommon/iqm.h
@@ -0,0 +1,131 @@
+/*
+===========================================================================
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifndef __IQM_H__
+#define __IQM_H__
+
+#define IQM_MAGIC "INTERQUAKEMODEL"
+#define IQM_VERSION 2
+
+#define IQM_MAX_JOINTS 128
+
+typedef struct iqmheader
+{
+ char magic[16];
+ unsigned int version;
+ unsigned int filesize;
+ unsigned int flags;
+ unsigned int num_text, ofs_text;
+ unsigned int num_meshes, ofs_meshes;
+ unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
+ unsigned int num_triangles, ofs_triangles, ofs_adjacency;
+ unsigned int num_joints, ofs_joints;
+ unsigned int num_poses, ofs_poses;
+ unsigned int num_anims, ofs_anims;
+ unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
+ unsigned int num_comment, ofs_comment;
+ unsigned int num_extensions, ofs_extensions;
+} iqmHeader_t;
+
+typedef struct iqmmesh
+{
+ unsigned int name;
+ unsigned int material;
+ unsigned int first_vertex, num_vertexes;
+ unsigned int first_triangle, num_triangles;
+} iqmMesh_t;
+
+enum
+{
+ IQM_POSITION = 0,
+ IQM_TEXCOORD = 1,
+ IQM_NORMAL = 2,
+ IQM_TANGENT = 3,
+ IQM_BLENDINDEXES = 4,
+ IQM_BLENDWEIGHTS = 5,
+ IQM_COLOR = 6,
+ IQM_CUSTOM = 0x10
+};
+
+enum
+{
+ IQM_BYTE = 0,
+ IQM_UBYTE = 1,
+ IQM_SHORT = 2,
+ IQM_USHORT = 3,
+ IQM_INT = 4,
+ IQM_UINT = 5,
+ IQM_HALF = 6,
+ IQM_FLOAT = 7,
+ IQM_DOUBLE = 8,
+};
+
+typedef struct iqmtriangle
+{
+ unsigned int vertex[3];
+} iqmTriangle_t;
+
+typedef struct iqmjoint
+{
+ unsigned int name;
+ int parent;
+ float translate[3], rotate[4], scale[3];
+} iqmJoint_t;
+
+typedef struct iqmpose
+{
+ int parent;
+ unsigned int mask;
+ float channeloffset[10];
+ float channelscale[10];
+} iqmPose_t;
+
+typedef struct iqmanim
+{
+ unsigned int name;
+ unsigned int first_frame, num_frames;
+ float framerate;
+ unsigned int flags;
+} iqmAnim_t;
+
+enum
+{
+ IQM_LOOP = 1<<0
+};
+
+typedef struct iqmvertexarray
+{
+ unsigned int type;
+ unsigned int flags;
+ unsigned int format;
+ unsigned int size;
+ unsigned int offset;
+} iqmVertexArray_t;
+
+typedef struct iqmbounds
+{
+ float bbmin[3], bbmax[3];
+ float xyradius, radius;
+} iqmBounds_t;
+
+#endif
diff --git a/src/renderercommon/qgl.h b/src/renderercommon/qgl.h
new file mode 100644
index 0000000..4411daf
--- /dev/null
+++ b/src/renderercommon/qgl.h
@@ -0,0 +1,570 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+/*
+** QGL.H
+*/
+
+#ifndef __QGL_H__
+#define __QGL_H__
+
+#ifdef USE_LOCAL_HEADERS
+# include "SDL_opengl.h"
+#else
+# include <SDL_opengl.h>
+#endif
+
+extern void (APIENTRYP qglActiveTextureARB) (GLenum texture);
+extern void (APIENTRYP qglClientActiveTextureARB) (GLenum texture);
+extern void (APIENTRYP qglMultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t);
+
+extern void (APIENTRYP qglLockArraysEXT) (GLint first, GLsizei count);
+extern void (APIENTRYP qglUnlockArraysEXT) (void);
+
+
+//===========================================================================
+
+#define qglAccum glAccum
+#define qglAlphaFunc glAlphaFunc
+#define qglAreTexturesResident glAreTexturesResident
+#define qglArrayElement glArrayElement
+#define qglBegin glBegin
+#define qglBindTexture glBindTexture
+#define qglBitmap glBitmap
+#define qglBlendFunc glBlendFunc
+#define qglCallList glCallList
+#define qglCallLists glCallLists
+#define qglClear glClear
+#define qglClearAccum glClearAccum
+#define qglClearColor glClearColor
+#define qglClearDepth glClearDepth
+#define qglClearIndex glClearIndex
+#define qglClearStencil glClearStencil
+#define qglClipPlane glClipPlane
+#define qglColor3b glColor3b
+#define qglColor3bv glColor3bv
+#define qglColor3d glColor3d
+#define qglColor3dv glColor3dv
+#define qglColor3f glColor3f
+#define qglColor3fv glColor3fv
+#define qglColor3i glColor3i
+#define qglColor3iv glColor3iv
+#define qglColor3s glColor3s
+#define qglColor3sv glColor3sv
+#define qglColor3ub glColor3ub
+#define qglColor3ubv glColor3ubv
+#define qglColor3ui glColor3ui
+#define qglColor3uiv glColor3uiv
+#define qglColor3us glColor3us
+#define qglColor3usv glColor3usv
+#define qglColor4b glColor4b
+#define qglColor4bv glColor4bv
+#define qglColor4d glColor4d
+#define qglColor4dv glColor4dv
+#define qglColor4f glColor4f
+#define qglColor4fv glColor4fv
+#define qglColor4i glColor4i
+#define qglColor4iv glColor4iv
+#define qglColor4s glColor4s
+#define qglColor4sv glColor4sv
+#define qglColor4ub glColor4ub
+#define qglColor4ubv glColor4ubv
+#define qglColor4ui glColor4ui
+#define qglColor4uiv glColor4uiv
+#define qglColor4us glColor4us
+#define qglColor4usv glColor4usv
+#define qglColorMask glColorMask
+#define qglColorMaterial glColorMaterial
+#define qglColorPointer glColorPointer
+#define qglCopyPixels glCopyPixels
+#define qglCopyTexImage1D glCopyTexImage1D
+#define qglCopyTexImage2D glCopyTexImage2D
+#define qglCopyTexSubImage1D glCopyTexSubImage1D
+#define qglCopyTexSubImage2D glCopyTexSubImage2D
+#define qglCullFace glCullFace
+#define qglDeleteLists glDeleteLists
+#define qglDeleteTextures glDeleteTextures
+#define qglDepthFunc glDepthFunc
+#define qglDepthMask glDepthMask
+#define qglDepthRange glDepthRange
+#define qglDisable glDisable
+#define qglDisableClientState glDisableClientState
+#define qglDrawArrays glDrawArrays
+#define qglDrawBuffer glDrawBuffer
+#define qglDrawElements glDrawElements
+#define qglDrawPixels glDrawPixels
+#define qglEdgeFlag glEdgeFlag
+#define qglEdgeFlagPointer glEdgeFlagPointer
+#define qglEdgeFlagv glEdgeFlagv
+#define qglEnable glEnable
+#define qglEnableClientState glEnableClientState
+#define qglEnd glEnd
+#define qglEndList glEndList
+#define qglEvalCoord1d glEvalCoord1d
+#define qglEvalCoord1dv glEvalCoord1dv
+#define qglEvalCoord1f glEvalCoord1f
+#define qglEvalCoord1fv glEvalCoord1fv
+#define qglEvalCoord2d glEvalCoord2d
+#define qglEvalCoord2dv glEvalCoord2dv
+#define qglEvalCoord2f glEvalCoord2f
+#define qglEvalCoord2fv glEvalCoord2fv
+#define qglEvalMesh1 glEvalMesh1
+#define qglEvalMesh2 glEvalMesh2
+#define qglEvalPoint1 glEvalPoint1
+#define qglEvalPoint2 glEvalPoint2
+#define qglFeedbackBuffer glFeedbackBuffer
+#define qglFinish glFinish
+#define qglFlush glFlush
+#define qglFogf glFogf
+#define qglFogfv glFogfv
+#define qglFogi glFogi
+#define qglFogiv glFogiv
+#define qglFrontFace glFrontFace
+#define qglFrustum glFrustum
+#define qglGenLists glGenLists
+#define qglGenTextures glGenTextures
+#define qglGetBooleanv glGetBooleanv
+#define qglGetClipPlane glGetClipPlane
+#define qglGetDoublev glGetDoublev
+#define qglGetError glGetError
+#define qglGetFloatv glGetFloatv
+#define qglGetIntegerv glGetIntegerv
+#define qglGetLightfv glGetLightfv
+#define qglGetLightiv glGetLightiv
+#define qglGetMapdv glGetMapdv
+#define qglGetMapfv glGetMapfv
+#define qglGetMapiv glGetMapiv
+#define qglGetMaterialfv glGetMaterialfv
+#define qglGetMaterialiv glGetMaterialiv
+#define qglGetPixelMapfv glGetPixelMapfv
+#define qglGetPixelMapuiv glGetPixelMapuiv
+#define qglGetPixelMapusv glGetPixelMapusv
+#define qglGetPointerv glGetPointerv
+#define qglGetPolygonStipple glGetPolygonStipple
+#define qglGetString glGetString
+#define qglGetTexGendv glGetTexGendv
+#define qglGetTexGenfv glGetTexGenfv
+#define qglGetTexGeniv glGetTexGeniv
+#define qglGetTexImage glGetTexImage
+#define qglGetTexLevelParameterfv glGetTexLevelParameterfv
+#define qglGetTexLevelParameteriv glGetTexLevelParameteriv
+#define qglGetTexParameterfv glGetTexParameterfv
+#define qglGetTexParameteriv glGetTexParameteriv
+#define qglHint glHint
+#define qglIndexMask glIndexMask
+#define qglIndexPointer glIndexPointer
+#define qglIndexd glIndexd
+#define qglIndexdv glIndexdv
+#define qglIndexf glIndexf
+#define qglIndexfv glIndexfv
+#define qglIndexi glIndexi
+#define qglIndexiv glIndexiv
+#define qglIndexs glIndexs
+#define qglIndexsv glIndexsv
+#define qglIndexub glIndexub
+#define qglIndexubv glIndexubv
+#define qglInitNames glInitNames
+#define qglInterleavedArrays glInterleavedArrays
+#define qglIsEnabled glIsEnabled
+#define qglIsList glIsList
+#define qglIsTexture glIsTexture
+#define qglLightModelf glLightModelf
+#define qglLightModelfv glLightModelfv
+#define qglLightModeli glLightModeli
+#define qglLightModeliv glLightModeliv
+#define qglLightf glLightf
+#define qglLightfv glLightfv
+#define qglLighti glLighti
+#define qglLightiv glLightiv
+#define qglLineStipple glLineStipple
+#define qglLineWidth glLineWidth
+#define qglListBase glListBase
+#define qglLoadIdentity glLoadIdentity
+#define qglLoadMatrixd glLoadMatrixd
+#define qglLoadMatrixf glLoadMatrixf
+#define qglLoadName glLoadName
+#define qglLogicOp glLogicOp
+#define qglMap1d glMap1d
+#define qglMap1f glMap1f
+#define qglMap2d glMap2d
+#define qglMap2f glMap2f
+#define qglMapGrid1d glMapGrid1d
+#define qglMapGrid1f glMapGrid1f
+#define qglMapGrid2d glMapGrid2d
+#define qglMapGrid2f glMapGrid2f
+#define qglMaterialf glMaterialf
+#define qglMaterialfv glMaterialfv
+#define qglMateriali glMateriali
+#define qglMaterialiv glMaterialiv
+#define qglMatrixMode glMatrixMode
+#define qglMultMatrixd glMultMatrixd
+#define qglMultMatrixf glMultMatrixf
+#define qglNewList glNewList
+#define qglNormal3b glNormal3b
+#define qglNormal3bv glNormal3bv
+#define qglNormal3d glNormal3d
+#define qglNormal3dv glNormal3dv
+#define qglNormal3f glNormal3f
+#define qglNormal3fv glNormal3fv
+#define qglNormal3i glNormal3i
+#define qglNormal3iv glNormal3iv
+#define qglNormal3s glNormal3s
+#define qglNormal3sv glNormal3sv
+#define qglNormalPointer glNormalPointer
+#define qglOrtho glOrtho
+#define qglPassThrough glPassThrough
+#define qglPixelMapfv glPixelMapfv
+#define qglPixelMapuiv glPixelMapuiv
+#define qglPixelMapusv glPixelMapusv
+#define qglPixelStoref glPixelStoref
+#define qglPixelStorei glPixelStorei
+#define qglPixelTransferf glPixelTransferf
+#define qglPixelTransferi glPixelTransferi
+#define qglPixelZoom glPixelZoom
+#define qglPointSize glPointSize
+#define qglPolygonMode glPolygonMode
+#define qglPolygonOffset glPolygonOffset
+#define qglPolygonStipple glPolygonStipple
+#define qglPopAttrib glPopAttrib
+#define qglPopClientAttrib glPopClientAttrib
+#define qglPopMatrix glPopMatrix
+#define qglPopName glPopName
+#define qglPrioritizeTextures glPrioritizeTextures
+#define qglPushAttrib glPushAttrib
+#define qglPushClientAttrib glPushClientAttrib
+#define qglPushMatrix glPushMatrix
+#define qglPushName glPushName
+#define qglRasterPos2d glRasterPos2d
+#define qglRasterPos2dv glRasterPos2dv
+#define qglRasterPos2f glRasterPos2f
+#define qglRasterPos2fv glRasterPos2fv
+#define qglRasterPos2i glRasterPos2i
+#define qglRasterPos2iv glRasterPos2iv
+#define qglRasterPos2s glRasterPos2s
+#define qglRasterPos2sv glRasterPos2sv
+#define qglRasterPos3d glRasterPos3d
+#define qglRasterPos3dv glRasterPos3dv
+#define qglRasterPos3f glRasterPos3f
+#define qglRasterPos3fv glRasterPos3fv
+#define qglRasterPos3i glRasterPos3i
+#define qglRasterPos3iv glRasterPos3iv
+#define qglRasterPos3s glRasterPos3s
+#define qglRasterPos3sv glRasterPos3sv
+#define qglRasterPos4d glRasterPos4d
+#define qglRasterPos4dv glRasterPos4dv
+#define qglRasterPos4f glRasterPos4f
+#define qglRasterPos4fv glRasterPos4fv
+#define qglRasterPos4i glRasterPos4i
+#define qglRasterPos4iv glRasterPos4iv
+#define qglRasterPos4s glRasterPos4s
+#define qglRasterPos4sv glRasterPos4sv
+#define qglReadBuffer glReadBuffer
+#define qglReadPixels glReadPixels
+#define qglRectd glRectd
+#define qglRectdv glRectdv
+#define qglRectf glRectf
+#define qglRectfv glRectfv
+#define qglRecti glRecti
+#define qglRectiv glRectiv
+#define qglRects glRects
+#define qglRectsv glRectsv
+#define qglRenderMode glRenderMode
+#define qglRotated glRotated
+#define qglRotatef glRotatef
+#define qglScaled glScaled
+#define qglScalef glScalef
+#define qglScissor glScissor
+#define qglSelectBuffer glSelectBuffer
+#define qglShadeModel glShadeModel
+#define qglStencilFunc glStencilFunc
+#define qglStencilMask glStencilMask
+#define qglStencilOp glStencilOp
+#define qglTexCoord1d glTexCoord1d
+#define qglTexCoord1dv glTexCoord1dv
+#define qglTexCoord1f glTexCoord1f
+#define qglTexCoord1fv glTexCoord1fv
+#define qglTexCoord1i glTexCoord1i
+#define qglTexCoord1iv glTexCoord1iv
+#define qglTexCoord1s glTexCoord1s
+#define qglTexCoord1sv glTexCoord1sv
+#define qglTexCoord2d glTexCoord2d
+#define qglTexCoord2dv glTexCoord2dv
+#define qglTexCoord2f glTexCoord2f
+#define qglTexCoord2fv glTexCoord2fv
+#define qglTexCoord2i glTexCoord2i
+#define qglTexCoord2iv glTexCoord2iv
+#define qglTexCoord2s glTexCoord2s
+#define qglTexCoord2sv glTexCoord2sv
+#define qglTexCoord3d glTexCoord3d
+#define qglTexCoord3dv glTexCoord3dv
+#define qglTexCoord3f glTexCoord3f
+#define qglTexCoord3fv glTexCoord3fv
+#define qglTexCoord3i glTexCoord3i
+#define qglTexCoord3iv glTexCoord3iv
+#define qglTexCoord3s glTexCoord3s
+#define qglTexCoord3sv glTexCoord3sv
+#define qglTexCoord4d glTexCoord4d
+#define qglTexCoord4dv glTexCoord4dv
+#define qglTexCoord4f glTexCoord4f
+#define qglTexCoord4fv glTexCoord4fv
+#define qglTexCoord4i glTexCoord4i
+#define qglTexCoord4iv glTexCoord4iv
+#define qglTexCoord4s glTexCoord4s
+#define qglTexCoord4sv glTexCoord4sv
+#define qglTexCoordPointer glTexCoordPointer
+#define qglTexEnvf glTexEnvf
+#define qglTexEnvfv glTexEnvfv
+#define qglTexEnvi glTexEnvi
+#define qglTexEnviv glTexEnviv
+#define qglTexGend glTexGend
+#define qglTexGendv glTexGendv
+#define qglTexGenf glTexGenf
+#define qglTexGenfv glTexGenfv
+#define qglTexGeni glTexGeni
+#define qglTexGeniv glTexGeniv
+#define qglTexImage1D glTexImage1D
+#define qglTexImage2D glTexImage2D
+#define qglTexParameterf glTexParameterf
+#define qglTexParameterfv glTexParameterfv
+#define qglTexParameteri glTexParameteri
+#define qglTexParameteriv glTexParameteriv
+#define qglTexSubImage1D glTexSubImage1D
+#define qglTexSubImage2D glTexSubImage2D
+#define qglTranslated glTranslated
+#define qglTranslatef glTranslatef
+#define qglVertex2d glVertex2d
+#define qglVertex2dv glVertex2dv
+#define qglVertex2f glVertex2f
+#define qglVertex2fv glVertex2fv
+#define qglVertex2i glVertex2i
+#define qglVertex2iv glVertex2iv
+#define qglVertex2s glVertex2s
+#define qglVertex2sv glVertex2sv
+#define qglVertex3d glVertex3d
+#define qglVertex3dv glVertex3dv
+#define qglVertex3f glVertex3f
+#define qglVertex3fv glVertex3fv
+#define qglVertex3i glVertex3i
+#define qglVertex3iv glVertex3iv
+#define qglVertex3s glVertex3s
+#define qglVertex3sv glVertex3sv
+#define qglVertex4d glVertex4d
+#define qglVertex4dv glVertex4dv
+#define qglVertex4f glVertex4f
+#define qglVertex4fv glVertex4fv
+#define qglVertex4i glVertex4i
+#define qglVertex4iv glVertex4iv
+#define qglVertex4s glVertex4s
+#define qglVertex4sv glVertex4sv
+#define qglVertexPointer glVertexPointer
+#define qglViewport glViewport
+
+// GL function loader, based on https://gist.github.com/rygorous/16796a0c876cf8a5f542caddb55bce8a
+
+// OpenGL 1.3, was GL_ARB_texture_compression
+#define QGL_1_3_PROCS \
+ GLE(void, ActiveTexture, GLenum texture) \
+ GLE(void, CompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) \
+ GLE(void, CompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) \
+
+// OpenGL 1.5, was GL_ARB_vertex_buffer_object and GL_ARB_occlusion_query
+#define QGL_1_5_PROCS \
+ GLE(void, GenQueries, GLsizei n, GLuint *ids) \
+ GLE(void, DeleteQueries, GLsizei n, const GLuint *ids) \
+ GLE(void, BeginQuery, GLenum target, GLuint id) \
+ GLE(void, EndQuery, GLenum target) \
+ GLE(void, GetQueryObjectiv, GLuint id, GLenum pname, GLint *params) \
+ GLE(void, GetQueryObjectuiv, GLuint id, GLenum pname, GLuint *params) \
+ GLE(void, BindBuffer, GLenum target, GLuint buffer) \
+ GLE(void, DeleteBuffers, GLsizei n, const GLuint *buffers) \
+ GLE(void, GenBuffers, GLsizei n, GLuint *buffers) \
+ GLE(void, BufferData, GLenum target, GLsizeiptr size, const void *data, GLenum usage) \
+ GLE(void, BufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const void *data) \
+
+// OpenGL 2.0, was GL_ARB_shading_language_100, GL_ARB_vertex_program, GL_ARB_shader_objects, and GL_ARB_vertex_shader
+#define QGL_2_0_PROCS \
+ GLE(void, AttachShader, GLuint program, GLuint shader) \
+ GLE(void, BindAttribLocation, GLuint program, GLuint index, const GLchar *name) \
+ GLE(void, CompileShader, GLuint shader) \
+ GLE(GLuint, CreateProgram, void) \
+ GLE(GLuint, CreateShader, GLenum type) \
+ GLE(void, DeleteProgram, GLuint program) \
+ GLE(void, DeleteShader, GLuint shader) \
+ GLE(void, DetachShader, GLuint program, GLuint shader) \
+ GLE(void, DisableVertexAttribArray, GLuint index) \
+ GLE(void, EnableVertexAttribArray, GLuint index) \
+ GLE(void, GetActiveUniform, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) \
+ GLE(void, GetProgramiv, GLuint program, GLenum pname, GLint *params) \
+ GLE(void, GetProgramInfoLog, GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) \
+ GLE(void, GetShaderiv, GLuint shader, GLenum pname, GLint *params) \
+ GLE(void, GetShaderInfoLog, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) \
+ GLE(void, GetShaderSource, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) \
+ GLE(GLint, GetUniformLocation, GLuint program, const GLchar *name) \
+ GLE(void, LinkProgram, GLuint program) \
+ GLE(void, ShaderSource, GLuint shader, GLsizei count, const GLchar* *string, const GLint *length) \
+ GLE(void, UseProgram, GLuint program) \
+ GLE(void, Uniform1f, GLint location, GLfloat v0) \
+ GLE(void, Uniform2f, GLint location, GLfloat v0, GLfloat v1) \
+ GLE(void, Uniform3f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) \
+ GLE(void, Uniform4f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) \
+ GLE(void, Uniform1i, GLint location, GLint v0) \
+ GLE(void, Uniform1fv, GLint location, GLsizei count, const GLfloat *value) \
+ GLE(void, UniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) \
+ GLE(void, ValidateProgram, GLuint program) \
+ GLE(void, VertexAttribPointer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) \
+
+// GL_NVX_gpu_memory_info
+#ifndef GL_NVX_gpu_memory_info
+#define GL_NVX_gpu_memory_info
+#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047
+#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048
+#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049
+#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A
+#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B
+#endif
+
+// GL_ATI_meminfo
+#ifndef GL_ATI_meminfo
+#define GL_ATI_meminfo
+#define GL_VBO_FREE_MEMORY_ATI 0x87FB
+#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC
+#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD
+#endif
+
+// GL_ARB_texture_float
+#ifndef GL_ARB_texture_float
+#define GL_ARB_texture_float
+#define GL_TEXTURE_RED_TYPE_ARB 0x8C10
+#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11
+#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12
+#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13
+#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14
+#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15
+#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16
+#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17
+#define GL_RGBA32F_ARB 0x8814
+#define GL_RGB32F_ARB 0x8815
+#define GL_ALPHA32F_ARB 0x8816
+#define GL_INTENSITY32F_ARB 0x8817
+#define GL_LUMINANCE32F_ARB 0x8818
+#define GL_LUMINANCE_ALPHA32F_ARB 0x8819
+#define GL_RGBA16F_ARB 0x881A
+#define GL_RGB16F_ARB 0x881B
+#define GL_ALPHA16F_ARB 0x881C
+#define GL_INTENSITY16F_ARB 0x881D
+#define GL_LUMINANCE16F_ARB 0x881E
+#define GL_LUMINANCE_ALPHA16F_ARB 0x881F
+#endif
+
+#ifndef GL_ARB_half_float_pixel
+#define GL_ARB_half_float_pixel
+#define GL_HALF_FLOAT_ARB 0x140B
+#endif
+
+// OpenGL 3.0 specific
+#define QGL_3_0_PROCS \
+ GLE(const GLubyte *, GetStringi, GLenum name, GLuint index) \
+
+// GL_ARB_framebuffer_object, built-in to OpenGL 3.0
+#define QGL_ARB_framebuffer_object_PROCS \
+ GLE(void, BindRenderbuffer, GLenum target, GLuint renderbuffer) \
+ GLE(void, DeleteRenderbuffers, GLsizei n, const GLuint *renderbuffers) \
+ GLE(void, GenRenderbuffers, GLsizei n, GLuint *renderbuffers) \
+ GLE(void, RenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) \
+ GLE(void, BindFramebuffer, GLenum target, GLuint framebuffer) \
+ GLE(void, DeleteFramebuffers, GLsizei n, const GLuint *framebuffers) \
+ GLE(void, GenFramebuffers, GLsizei n, GLuint *framebuffers) \
+ GLE(GLenum, CheckFramebufferStatus, GLenum target) \
+ GLE(void, FramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) \
+ GLE(void, FramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) \
+ GLE(void, GenerateMipmap, GLenum target) \
+ GLE(void, BlitFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) \
+ GLE(void, RenderbufferStorageMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) \
+
+// GL_ARB_vertex_array_object, built-in to OpenGL 3.0
+#define QGL_ARB_vertex_array_object_PROCS \
+ GLE(void, BindVertexArray, GLuint array) \
+ GLE(void, DeleteVertexArrays, GLsizei n, const GLuint *arrays) \
+ GLE(void, GenVertexArrays, GLsizei n, GLuint *arrays) \
+
+#ifndef GL_ARB_texture_compression_rgtc
+#define GL_ARB_texture_compression_rgtc
+#define GL_COMPRESSED_RED_RGTC1 0x8DBB
+#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
+#define GL_COMPRESSED_RG_RGTC2 0x8DBD
+#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
+#endif
+
+#ifndef GL_ARB_texture_compression_bptc
+#define GL_ARB_texture_compression_bptc
+#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C
+#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D
+#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E
+#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F
+#endif
+
+#ifndef GL_ARB_depth_clamp
+#define GL_ARB_depth_clamp
+#define GL_DEPTH_CLAMP 0x864F
+#endif
+
+#ifndef GL_ARB_seamless_cube_map
+#define GL_ARB_seamless_cube_map
+#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
+#endif
+
+// GL_EXT_direct_state_access
+#define QGL_EXT_direct_state_access_PROCS \
+ GLE(GLvoid, BindMultiTextureEXT, GLenum texunit, GLenum target, GLuint texture) \
+ GLE(GLvoid, TextureParameterfEXT, GLuint texture, GLenum target, GLenum pname, GLfloat param) \
+ GLE(GLvoid, TextureParameteriEXT, GLuint texture, GLenum target, GLenum pname, GLint param) \
+ GLE(GLvoid, TextureImage2DEXT, GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) \
+ GLE(GLvoid, TextureSubImage2DEXT, GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) \
+ GLE(GLvoid, CopyTextureSubImage2DEXT, GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) \
+ GLE(GLvoid, CompressedTextureImage2DEXT, GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) \
+ GLE(GLvoid, CompressedTextureSubImage2DEXT, GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) \
+ GLE(GLvoid, GenerateTextureMipmapEXT, GLuint texture, GLenum target) \
+ GLE(GLvoid, ProgramUniform1iEXT, GLuint program, GLint location, GLint v0) \
+ GLE(GLvoid, ProgramUniform1fEXT, GLuint program, GLint location, GLfloat v0) \
+ GLE(GLvoid, ProgramUniform2fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1) \
+ GLE(GLvoid, ProgramUniform3fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) \
+ GLE(GLvoid, ProgramUniform4fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) \
+ GLE(GLvoid, ProgramUniform1fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value) \
+ GLE(GLvoid, ProgramUniformMatrix4fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) \
+ GLE(GLvoid, NamedRenderbufferStorageEXT, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) \
+ GLE(GLvoid, NamedRenderbufferStorageMultisampleEXT, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) \
+ GLE(GLenum, CheckNamedFramebufferStatusEXT, GLuint framebuffer, GLenum target) \
+ GLE(GLvoid, NamedFramebufferTexture2DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) \
+ GLE(GLvoid, NamedFramebufferRenderbufferEXT, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) \
+
+#define GLE(ret, name, ...) typedef ret APIENTRY name##proc(__VA_ARGS__); extern name##proc * qgl##name;
+QGL_1_3_PROCS;
+QGL_1_5_PROCS;
+QGL_2_0_PROCS;
+QGL_3_0_PROCS;
+QGL_ARB_framebuffer_object_PROCS;
+QGL_ARB_vertex_array_object_PROCS;
+QGL_EXT_direct_state_access_PROCS;
+#undef GLE
+
+#endif
diff --git a/src/renderercommon/tr_common.h b/src/renderercommon/tr_common.h
new file mode 100644
index 0000000..68e012f
--- /dev/null
+++ b/src/renderercommon/tr_common.h
@@ -0,0 +1,166 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#ifndef TR_COMMON_H
+#define TR_COMMON_H
+
+#include "qcommon/cvar.h"
+#include "qcommon/q_shared.h"
+#include "sys/sys_shared.h"
+
+#include "iqm.h"
+#include "qgl.h"
+#include "tr_public.h"
+
+typedef enum
+{
+ IMGTYPE_COLORALPHA, // for color, lightmap, diffuse, and specular
+ IMGTYPE_NORMAL,
+ IMGTYPE_NORMALHEIGHT,
+ IMGTYPE_DELUXE, // normals are swizzled, deluxe are not
+} imgType_t;
+
+typedef enum
+{
+ IMGFLAG_NONE = 0x0000,
+ IMGFLAG_MIPMAP = 0x0001,
+ IMGFLAG_PICMIP = 0x0002,
+ IMGFLAG_CUBEMAP = 0x0004,
+ IMGFLAG_NO_COMPRESSION = 0x0010,
+ IMGFLAG_NOLIGHTSCALE = 0x0020,
+ IMGFLAG_CLAMPTOEDGE = 0x0040,
+ IMGFLAG_GENNORMALMAP = 0x0100,
+} imgFlags_t;
+
+typedef struct image_s {
+ char imgName[MAX_QPATH]; // game path, including extension
+ int width, height; // source image
+ int uploadWidth, uploadHeight; // after power of two and picmip but not including clamp to MAX_TEXTURE_SIZE
+ GLuint texnum; // gl texture binding
+
+ int frameUsed; // for texture usage in frame statistics
+
+ int internalFormat;
+ int TMU; // only needed for voodoo2
+
+ imgType_t type;
+ int /*imgFlags_t*/ flags;
+
+ struct image_s* next;
+} image_t;
+
+// any change in the LIGHTMAP_* defines here MUST be reflected in
+// R_FindShader() in tr_bsp.c
+#define LIGHTMAP_2D -4 // shader is for 2D rendering
+#define LIGHTMAP_BY_VERTEX -3 // pre-lit triangle models
+#define LIGHTMAP_WHITEIMAGE -2
+#define LIGHTMAP_NONE -1
+
+extern refimport_t ri;
+extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared during ref re-init
+
+//
+// cvars
+//
+extern cvar_t *r_stencilbits; // number of desired stencil bits
+extern cvar_t *r_depthbits; // number of desired depth bits
+extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen
+extern cvar_t *r_alphabits; // number of desired alpha bits
+extern cvar_t *r_texturebits; // number of desired texture bits
+extern cvar_t *r_ext_multisample;
+ // 0 = use framebuffer depth
+ // 16 = use 16-bit textures
+ // 32 = use 32-bit textures
+ // all else = error
+
+extern cvar_t *r_width;
+extern cvar_t *r_height;
+extern cvar_t *r_pixelAspect;
+extern cvar_t *r_noborder;
+extern cvar_t *r_fullscreen;
+extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities
+extern cvar_t *r_drawBuffer;
+extern cvar_t *r_swapInterval;
+
+extern cvar_t *r_allowExtensions; // global enable/disable of OpenGL extensions
+extern cvar_t *r_ext_compressed_textures; // these control use of specific extensions
+extern cvar_t *r_ext_multitexture;
+extern cvar_t *r_ext_compiled_vertex_array;
+extern cvar_t *r_ext_texture_env_add;
+
+extern cvar_t *r_ext_texture_filter_anisotropic;
+extern cvar_t *r_ext_max_anisotropy;
+
+extern cvar_t *r_stereoEnabled;
+
+extern cvar_t *r_saveFontData;
+
+qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode );
+
+float R_NoiseGet4f( float x, float y, float z, double t );
+void R_NoiseInit( void );
+
+image_t *R_FindImageFile( const char *name, imgType_t type, int/*imgFlags_t*/ flags );
+image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgType_t type, int flags, int internalFormat );
+
+void R_IssuePendingRenderCommands( void );
+qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex );
+qhandle_t RE_RegisterShader( const char *name );
+qhandle_t RE_RegisterShaderNoMip( const char *name );
+qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage);
+
+// font stuff
+void R_InitFreeType( void );
+void R_DoneFreeType( void );
+void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);
+
+/*
+=============================================================
+
+IMAGE LOADERS
+
+=============================================================
+*/
+
+void R_LoadBMP( const char *name, byte **pic, int *width, int *height );
+void R_LoadJPG( const char *name, byte **pic, int *width, int *height );
+void R_LoadPCX( const char *name, byte **pic, int *width, int *height );
+void R_LoadPNG( const char *name, byte **pic, int *width, int *height );
+void R_LoadTGA( const char *name, byte **pic, int *width, int *height );
+
+/*
+====================================================================
+
+IMPLEMENTATION SPECIFIC FUNCTIONS
+
+====================================================================
+*/
+
+void GLimp_Init( bool );
+void GLimp_Shutdown( void );
+void GLimp_EndFrame( void );
+void GLimp_LogComment(const char *comment);
+void GLimp_Minimize(void);
+void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] );
+
+#endif
diff --git a/src/renderercommon/tr_font.cpp b/src/renderercommon/tr_font.cpp
new file mode 100644
index 0000000..c93b462
--- /dev/null
+++ b/src/renderercommon/tr_font.cpp
@@ -0,0 +1,562 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_font.c
+//
+//
+// The font system uses FreeType 2.x to render TrueType fonts for use within the game.
+// As of this writing ( Nov, 2000 ) Team Arena uses these fonts for all of the ui and
+// about 90% of the cgame presentation. A few areas of the CGAME were left uses the old
+// fonts since the code is shared with standard Q3A.
+//
+// If you include this font rendering code in a commercial product you MUST include the
+// following somewhere with your product, see www.freetype.org for specifics or changes.
+// The Freetype code also uses some hinting techniques that MIGHT infringe on patents
+// held by apple so be aware of that also.
+//
+// As of Q3A 1.25+ and Team Arena, we are shipping the game with the font rendering code
+// disabled. This removes any potential patent issues and it keeps us from having to
+// distribute an actual TrueTrype font which is 1. expensive to do and 2. seems to require
+// an act of god to accomplish.
+//
+// What we did was pre-render the fonts using FreeType ( which is why we leave the FreeType
+// credit in the credits ) and then saved off the glyph data and then hand touched up the
+// font bitmaps so they scale a bit better in GL.
+//
+// There are limitations in the way fonts are saved and reloaded in that it is based on
+// point size and not name. So if you pre-render Helvetica in 18 point and Impact in 18 point
+// you will end up with a single 18 point data file and image set. Typically you will want to
+// choose 3 sizes to best approximate the scaling you will be doing in the ui scripting system
+//
+// In the UI Scripting code, a scale of 1.0 is equal to a 48 point font. In Team Arena, we
+// use three or four scales, most of them exactly equaling the specific rendered size. We
+// rendered three sizes in Team Arena, 12, 16, and 20.
+//
+// To generate new font data you need to go through the following steps.
+// 1. delete the fontImage_x_xx.tga files and fontImage_xx.dat files from the fonts path.
+// 2. in a ui script, specificy a font, smallFont, and bigFont keyword with font name and
+// point size. the original TrueType fonts must exist in fonts at this point.
+// 3. run the game, you should see things normally.
+// 4. Exit the game and there will be three dat files and at least three tga files. The
+// tga's are in 256x256 pages so if it takes three images to render a 24 point font you
+// will end up with fontImage_0_24.tga through fontImage_2_24.tga
+// 5. In future runs of the game, the system looks for these images and data files when a s
+// specific point sized font is rendered and loads them for use.
+// 6. Because of the original beta nature of the FreeType code you will probably want to hand
+// touch the font bitmaps.
+//
+// Currently a define in the project turns on or off the FreeType code which is currently
+// defined out. To pre-render new fonts you need enable the define ( BUILD_FREETYPE ) and
+// uncheck the exclude from build check box in the FreeType2 area of the Renderer project.
+
+#include "tr_common.h"
+
+#include "qcommon/qcommon.h"
+
+#ifdef BUILD_FREETYPE
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_ERRORS_H
+#include FT_SYSTEM_H
+#include FT_IMAGE_H
+#include FT_OUTLINE_H
+
+#define _FLOOR(x) ((x) & -64)
+#define _CEIL(x) (((x)+63) & -64)
+#define _TRUNC(x) ((x) >> 6)
+
+FT_Library ftLibrary = NULL;
+#endif
+
+#define MAX_FONTS 6
+static int registeredFontCount = 0;
+static fontInfo_t registeredFont[MAX_FONTS];
+
+#ifdef BUILD_FREETYPE
+void R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) {
+ *left = _FLOOR( glyph->metrics.horiBearingX );
+ *right = _CEIL( glyph->metrics.horiBearingX + glyph->metrics.width );
+ *width = _TRUNC(*right - *left);
+
+ *top = _CEIL( glyph->metrics.horiBearingY );
+ *bottom = _FLOOR( glyph->metrics.horiBearingY - glyph->metrics.height );
+ *height = _TRUNC( *top - *bottom );
+ *pitch = ( qtrue ? (*width+3) & -4 : (*width+7) >> 3 );
+}
+
+
+FT_Bitmap *R_RenderGlyph(FT_GlyphSlot glyph, glyphInfo_t* glyphOut) {
+ FT_Bitmap *bit2;
+ int left, right, width, top, bottom, height, pitch, size;
+
+ R_GetGlyphInfo(glyph, &left, &right, &width, &top, &bottom, &height, &pitch);
+
+ if ( glyph->format == ft_glyph_format_outline ) {
+ size = pitch*height;
+
+ bit2 = ri.Malloc(sizeof(FT_Bitmap));
+
+ bit2->width = width;
+ bit2->rows = height;
+ bit2->pitch = pitch;
+ bit2->pixel_mode = ft_pixel_mode_grays;
+ //bit2->pixel_mode = ft_pixel_mode_mono;
+ bit2->buffer = ri.Malloc(pitch*height);
+ bit2->num_grays = 256;
+
+ Com_Memset( bit2->buffer, 0, size );
+
+ FT_Outline_Translate( &glyph->outline, -left, -bottom );
+
+ FT_Outline_Get_Bitmap( ftLibrary, &glyph->outline, bit2 );
+
+ glyphOut->height = height;
+ glyphOut->pitch = pitch;
+ glyphOut->top = (glyph->metrics.horiBearingY >> 6) + 1;
+ glyphOut->bottom = bottom;
+
+ return bit2;
+ } else {
+ ri.Printf(PRINT_ALL, "Non-outline fonts are not supported\n");
+ }
+ return NULL;
+}
+
+void WriteTGA (char *filename, byte *data, int width, int height) {
+ byte *buffer;
+ int i, c;
+ int row;
+ unsigned char *flip;
+ unsigned char *src, *dst;
+
+ buffer = ri.Malloc(width*height*4 + 18);
+ Com_Memset (buffer, 0, 18);
+ buffer[2] = 2; // uncompressed type
+ buffer[12] = width&255;
+ buffer[13] = width>>8;
+ buffer[14] = height&255;
+ buffer[15] = height>>8;
+ buffer[16] = 32; // pixel size
+
+ // swap rgb to bgr
+ c = 18 + width * height * 4;
+ for (i=18 ; i<c ; i+=4)
+ {
+ buffer[i] = data[i-18+2]; // blue
+ buffer[i+1] = data[i-18+1]; // green
+ buffer[i+2] = data[i-18+0]; // red
+ buffer[i+3] = data[i-18+3]; // alpha
+ }
+
+ // flip upside down
+ flip = (unsigned char *)ri.Malloc(width*4);
+ for(row = 0; row < height/2; row++)
+ {
+ src = buffer + 18 + row * 4 * width;
+ dst = buffer + 18 + (height - row - 1) * 4 * width;
+
+ Com_Memcpy(flip, src, width*4);
+ Com_Memcpy(src, dst, width*4);
+ Com_Memcpy(dst, flip, width*4);
+ }
+ ri.Free(flip);
+
+ ri.FS_WriteFile(filename, buffer, c);
+
+ //f = fopen (filename, "wb");
+ //fwrite (buffer, 1, c, f);
+ //fclose (f);
+
+ ri.Free (buffer);
+}
+
+static glyphInfo_t *RE_ConstructGlyphInfo(unsigned char *imageOut, int *xOut, int *yOut, int *maxHeight, FT_Face face, const unsigned char c, qboolean calcHeight) {
+ int i;
+ static glyphInfo_t glyph;
+ unsigned char *src, *dst;
+ float scaled_width, scaled_height;
+ FT_Bitmap *bitmap = NULL;
+
+ Com_Memset(&glyph, 0, sizeof(glyphInfo_t));
+ // make sure everything is here
+ if (face != NULL) {
+ FT_Load_Glyph(face, FT_Get_Char_Index( face, c), FT_LOAD_DEFAULT );
+ bitmap = R_RenderGlyph(face->glyph, &glyph);
+ if (bitmap) {
+ glyph.xSkip = (face->glyph->metrics.horiAdvance >> 6) + 1;
+ } else {
+ return &glyph;
+ }
+
+ if (glyph.height > *maxHeight) {
+ *maxHeight = glyph.height;
+ }
+
+ if (calcHeight) {
+ ri.Free(bitmap->buffer);
+ ri.Free(bitmap);
+ return &glyph;
+ }
+
+/*
+ // need to convert to power of 2 sizes so we do not get
+ // any scaling from the gl upload
+ for (scaled_width = 1 ; scaled_width < glyph.pitch ; scaled_width<<=1)
+ ;
+ for (scaled_height = 1 ; scaled_height < glyph.height ; scaled_height<<=1)
+ ;
+*/
+
+ scaled_width = glyph.pitch;
+ scaled_height = glyph.height;
+
+ // we need to make sure we fit
+ if (*xOut + scaled_width + 1 >= 255) {
+ *xOut = 0;
+ *yOut += *maxHeight + 1;
+ }
+
+ if (*yOut + *maxHeight + 1 >= 255) {
+ *yOut = -1;
+ *xOut = -1;
+ ri.Free(bitmap->buffer);
+ ri.Free(bitmap);
+ return &glyph;
+ }
+
+
+ src = bitmap->buffer;
+ dst = imageOut + (*yOut * 256) + *xOut;
+
+ if (bitmap->pixel_mode == ft_pixel_mode_mono) {
+ for (i = 0; i < glyph.height; i++) {
+ int j;
+ unsigned char *_src = src;
+ unsigned char *_dst = dst;
+ unsigned char mask = 0x80;
+ unsigned char val = *_src;
+ for (j = 0; j < glyph.pitch; j++) {
+ if (mask == 0x80) {
+ val = *_src++;
+ }
+ if (val & mask) {
+ *_dst = 0xff;
+ }
+ mask >>= 1;
+
+ if ( mask == 0 ) {
+ mask = 0x80;
+ }
+ _dst++;
+ }
+
+ src += glyph.pitch;
+ dst += 256;
+ }
+ } else {
+ for (i = 0; i < glyph.height; i++) {
+ Com_Memcpy(dst, src, glyph.pitch);
+ src += glyph.pitch;
+ dst += 256;
+ }
+ }
+
+ // we now have an 8 bit per pixel grey scale bitmap
+ // that is width wide and pf->ftSize->metrics.y_ppem tall
+
+ glyph.imageHeight = scaled_height;
+ glyph.imageWidth = scaled_width;
+ glyph.s = (float)*xOut / 256;
+ glyph.t = (float)*yOut / 256;
+ glyph.s2 = glyph.s + (float)scaled_width / 256;
+ glyph.t2 = glyph.t + (float)scaled_height / 256;
+
+ *xOut += scaled_width + 1;
+
+ ri.Free(bitmap->buffer);
+ ri.Free(bitmap);
+ }
+
+ return &glyph;
+}
+#endif
+
+static int fdOffset;
+static byte *fdFile;
+
+int readInt( void ) {
+ int i = fdFile[fdOffset]+(fdFile[fdOffset+1]<<8)+(fdFile[fdOffset+2]<<16)+(fdFile[fdOffset+3]<<24);
+ fdOffset += 4;
+ return i;
+}
+
+typedef union {
+ byte fred[4];
+ float ffred;
+} poor;
+
+float readFloat( void ) {
+ poor me;
+#if defined Q3_BIG_ENDIAN
+ me.fred[0] = fdFile[fdOffset+3];
+ me.fred[1] = fdFile[fdOffset+2];
+ me.fred[2] = fdFile[fdOffset+1];
+ me.fred[3] = fdFile[fdOffset+0];
+#elif defined Q3_LITTLE_ENDIAN
+ me.fred[0] = fdFile[fdOffset+0];
+ me.fred[1] = fdFile[fdOffset+1];
+ me.fred[2] = fdFile[fdOffset+2];
+ me.fred[3] = fdFile[fdOffset+3];
+#endif
+ fdOffset += 4;
+ return me.ffred;
+}
+
+void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {
+#ifdef BUILD_FREETYPE
+ FT_Face face;
+ int j, k, xOut, yOut, lastStart, imageNumber;
+ int scaledSize, newSize, maxHeight, left;
+ unsigned char *out, *imageBuff;
+ glyphInfo_t *glyph;
+ image_t *image;
+ qhandle_t h;
+ float max;
+ float dpi = 72;
+ float glyphScale;
+#endif
+ void *faceData;
+ int i, len;
+ char name[1024];
+
+ if (!fontName) {
+ ri.Printf(PRINT_ALL, "RE_RegisterFont: called with empty name\n");
+ return;
+ }
+
+ if (pointSize <= 0) {
+ pointSize = 12;
+ }
+
+ R_IssuePendingRenderCommands();
+
+ if (registeredFontCount >= MAX_FONTS) {
+ ri.Printf(PRINT_WARNING, "RE_RegisterFont: Too many fonts registered already.\n");
+ return;
+ }
+
+ Com_sprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize);
+ for (i = 0; i < registeredFontCount; i++) {
+ if (Q_stricmp(name, registeredFont[i].name) == 0) {
+ Com_Memcpy(font, &registeredFont[i], sizeof(fontInfo_t));
+ return;
+ }
+ }
+
+ len = ri.FS_ReadFile(name, NULL);
+ if (len == sizeof(fontInfo_t)) {
+ ri.FS_ReadFile(name, &faceData);
+ fdOffset = 0;
+ fdFile = (byte*)faceData;
+ for(i=0; i<GLYPHS_PER_FONT; i++) {
+ font->glyphs[i].height = readInt();
+ font->glyphs[i].top = readInt();
+ font->glyphs[i].bottom = readInt();
+ font->glyphs[i].pitch = readInt();
+ font->glyphs[i].xSkip = readInt();
+ font->glyphs[i].imageWidth = readInt();
+ font->glyphs[i].imageHeight = readInt();
+ font->glyphs[i].s = readFloat();
+ font->glyphs[i].t = readFloat();
+ font->glyphs[i].s2 = readFloat();
+ font->glyphs[i].t2 = readFloat();
+ font->glyphs[i].glyph = readInt();
+ Q_strncpyz(font->glyphs[i].shaderName, (const char *)&fdFile[fdOffset], sizeof(font->glyphs[i].shaderName));
+ fdOffset += sizeof(font->glyphs[i].shaderName);
+ }
+ font->glyphScale = readFloat();
+ Com_Memcpy(font->name, &fdFile[fdOffset], MAX_QPATH);
+
+// Com_Memcpy(font, faceData, sizeof(fontInfo_t));
+ Q_strncpyz(font->name, name, sizeof(font->name));
+ for (i = GLYPH_START; i <= GLYPH_END; i++) {
+ font->glyphs[i].glyph = RE_RegisterShaderNoMip(font->glyphs[i].shaderName);
+ }
+ Com_Memcpy(&registeredFont[registeredFontCount++], font, sizeof(fontInfo_t));
+ ri.FS_FreeFile(faceData);
+ return;
+ }
+
+#ifndef BUILD_FREETYPE
+ ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType code not available\n");
+#else
+ if (ftLibrary == NULL) {
+ ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType not initialized.\n");
+ return;
+ }
+
+ len = ri.FS_ReadFile(fontName, &faceData);
+ if (len <= 0) {
+ ri.Printf(PRINT_WARNING, "RE_RegisterFont: Unable to read font file '%s'\n", fontName);
+ return;
+ }
+
+ // allocate on the stack first in case we fail
+ if (FT_New_Memory_Face( ftLibrary, faceData, len, 0, &face )) {
+ ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType, unable to allocate new face.\n");
+ return;
+ }
+
+
+ if (FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi)) {
+ ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType, unable to set face char size.\n");
+ return;
+ }
+
+ //*font = &registeredFonts[registeredFontCount++];
+
+ // make a 256x256 image buffer, once it is full, register it, clean it and keep going
+ // until all glyphs are rendered
+
+ out = ri.Malloc(256*256);
+ if (out == NULL) {
+ ri.Printf(PRINT_WARNING, "RE_RegisterFont: ri.Malloc failure during output image creation.\n");
+ return;
+ }
+ Com_Memset(out, 0, 256*256);
+
+ maxHeight = 0;
+
+ for (i = GLYPH_START; i <= GLYPH_END; i++) {
+ RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qtrue);
+ }
+
+ xOut = 0;
+ yOut = 0;
+ i = GLYPH_START;
+ lastStart = i;
+ imageNumber = 0;
+
+ while ( i <= GLYPH_END + 1 ) {
+
+ if ( i == GLYPH_END + 1 ) {
+ // upload/save current image buffer
+ xOut = yOut = -1;
+ } else {
+ glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qfalse);
+ }
+
+ if (xOut == -1 || yOut == -1) {
+ // ran out of room
+ // we need to create an image from the bitmap, set all the handles in the glyphs to this point
+ //
+
+ scaledSize = 256*256;
+ newSize = scaledSize * 4;
+ imageBuff = ri.Malloc(newSize);
+ left = 0;
+ max = 0;
+ for ( k = 0; k < (scaledSize) ; k++ ) {
+ if (max < out[k]) {
+ max = out[k];
+ }
+ }
+
+ if (max > 0) {
+ max = 255/max;
+ }
+
+ for ( k = 0; k < (scaledSize) ; k++ ) {
+ imageBuff[left++] = 255;
+ imageBuff[left++] = 255;
+ imageBuff[left++] = 255;
+
+ imageBuff[left++] = ((float)out[k] * max);
+ }
+
+ Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i.tga", imageNumber++, pointSize);
+ if (r_saveFontData->integer) {
+ WriteTGA(name, imageBuff, 256, 256);
+ }
+
+ //Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i", imageNumber++, pointSize);
+ image = R_CreateImage(name, imageBuff, 256, 256, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 );
+ h = RE_RegisterShaderFromImage(name, LIGHTMAP_2D, image, qfalse);
+ for (j = lastStart; j < i; j++) {
+ font->glyphs[j].glyph = h;
+ Q_strncpyz(font->glyphs[j].shaderName, name, sizeof(font->glyphs[j].shaderName));
+ }
+ lastStart = i;
+ Com_Memset(out, 0, 256*256);
+ xOut = 0;
+ yOut = 0;
+ ri.Free(imageBuff);
+ if ( i == GLYPH_END + 1 )
+ i++;
+ } else {
+ Com_Memcpy(&font->glyphs[i], glyph, sizeof(glyphInfo_t));
+ i++;
+ }
+ }
+
+ // change the scale to be relative to 1 based on 72 dpi ( so dpi of 144 means a scale of .5 )
+ glyphScale = 72.0f / dpi;
+
+ // we also need to adjust the scale based on point size relative to 48 points as the ui scaling is based on a 48 point font
+ glyphScale *= 48.0f / pointSize;
+
+ registeredFont[registeredFontCount].glyphScale = glyphScale;
+ font->glyphScale = glyphScale;
+ Com_Memcpy(&registeredFont[registeredFontCount++], font, sizeof(fontInfo_t));
+
+ if (r_saveFontData->integer) {
+ ri.FS_WriteFile(va("fonts/fontImage_%i.dat", pointSize), font, sizeof(fontInfo_t));
+ }
+
+ ri.Free(out);
+
+ ri.FS_FreeFile(faceData);
+#endif
+}
+
+
+
+void R_InitFreeType(void) {
+#ifdef BUILD_FREETYPE
+ if (FT_Init_FreeType( &ftLibrary )) {
+ ri.Printf(PRINT_WARNING, "R_InitFreeType: Unable to initialize FreeType.\n");
+ }
+#endif
+ registeredFontCount = 0;
+}
+
+
+void R_DoneFreeType(void) {
+#ifdef BUILD_FREETYPE
+ if (ftLibrary) {
+ FT_Done_FreeType( ftLibrary );
+ ftLibrary = NULL;
+ }
+#endif
+ registeredFontCount = 0;
+}
diff --git a/src/renderercommon/tr_image_bmp.cpp b/src/renderercommon/tr_image_bmp.cpp
new file mode 100644
index 0000000..b3e51b7
--- /dev/null
+++ b/src/renderercommon/tr_image_bmp.cpp
@@ -0,0 +1,240 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_common.h"
+
+typedef struct
+{
+ char id[2];
+ unsigned fileSize;
+ unsigned reserved0;
+ unsigned bitmapDataOffset;
+ unsigned bitmapHeaderSize;
+ unsigned width;
+ unsigned height;
+ unsigned short planes;
+ unsigned short bitsPerPixel;
+ unsigned compression;
+ unsigned bitmapDataSize;
+ unsigned hRes;
+ unsigned vRes;
+ unsigned colors;
+ unsigned importantColors;
+ unsigned char palette[256][4];
+} BMPHeader_t;
+
+void R_LoadBMP( const char *name, byte **pic, int *width, int *height )
+{
+ int columns, rows;
+ unsigned numPixels;
+ byte *pixbuf;
+ int row, column;
+ byte *buf_p;
+ byte *end;
+ union {
+ byte *b;
+ void *v;
+ } buffer;
+ int length;
+ BMPHeader_t bmpHeader;
+ byte *bmpRGBA;
+
+ *pic = NULL;
+
+ if(width)
+ *width = 0;
+
+ if(height)
+ *height = 0;
+
+ //
+ // load the file
+ //
+ length = ri.FS_ReadFile( ( char * ) name, &buffer.v);
+ if (!buffer.b || length < 0) {
+ return;
+ }
+
+ if (length < 54)
+ {
+ ri.Error( ERR_DROP, "LoadBMP: header too short (%s)", name );
+ }
+
+ buf_p = buffer.b;
+ end = buffer.b + length;
+
+ bmpHeader.id[0] = *buf_p++;
+ bmpHeader.id[1] = *buf_p++;
+ bmpHeader.fileSize = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+ bmpHeader.reserved0 = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+ bmpHeader.bitmapDataOffset = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+ bmpHeader.bitmapHeaderSize = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+ bmpHeader.width = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+ bmpHeader.height = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+ bmpHeader.planes = LittleShort( * ( short * ) buf_p );
+ buf_p += 2;
+ bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p );
+ buf_p += 2;
+ bmpHeader.compression = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+ bmpHeader.bitmapDataSize = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+ bmpHeader.hRes = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+ bmpHeader.vRes = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+ bmpHeader.colors = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+ bmpHeader.importantColors = LittleLong( * ( int * ) buf_p );
+ buf_p += 4;
+
+ if ( bmpHeader.bitsPerPixel == 8 )
+ {
+ if (buf_p + sizeof(bmpHeader.palette) > end)
+ ri.Error( ERR_DROP, "LoadBMP: header too short (%s)", name );
+
+ Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
+ }
+
+ if (buffer.b + bmpHeader.bitmapDataOffset > end)
+ {
+ ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)", name );
+ }
+
+ buf_p = buffer.b + bmpHeader.bitmapDataOffset;
+
+ if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' )
+ {
+ ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)", name );
+ }
+ if ( bmpHeader.fileSize != length )
+ {
+ ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)", bmpHeader.fileSize, length, name );
+ }
+ if ( bmpHeader.compression != 0 )
+ {
+ ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)", name );
+ }
+ if ( bmpHeader.bitsPerPixel < 8 )
+ {
+ ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)", name );
+ }
+
+ switch ( bmpHeader.bitsPerPixel )
+ {
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'", bmpHeader.bitsPerPixel, name );
+ break;
+ }
+
+ columns = bmpHeader.width;
+ rows = bmpHeader.height;
+ if ( rows < 0 )
+ rows = -rows;
+ numPixels = columns * rows;
+
+ if(columns <= 0 || !rows || numPixels > 0x1FFFFFFF // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF
+ || ((numPixels * 4) / columns) / 4 != rows)
+ {
+ ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size", name);
+ }
+ if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end)
+ {
+ ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)", name);
+ }
+
+ if ( width )
+ *width = columns;
+ if ( height )
+ *height = rows;
+
+ bmpRGBA = (byte*)ri.Malloc( numPixels * 4 );
+ *pic = bmpRGBA;
+
+
+ for ( row = rows-1; row >= 0; row-- )
+ {
+ pixbuf = bmpRGBA + row*columns*4;
+
+ for ( column = 0; column < columns; column++ )
+ {
+ unsigned char red, green, blue, alpha;
+ int palIndex;
+ unsigned short shortPixel;
+
+ switch ( bmpHeader.bitsPerPixel )
+ {
+ case 8:
+ palIndex = *buf_p++;
+ *pixbuf++ = bmpHeader.palette[palIndex][2];
+ *pixbuf++ = bmpHeader.palette[palIndex][1];
+ *pixbuf++ = bmpHeader.palette[palIndex][0];
+ *pixbuf++ = 0xff;
+ break;
+ case 16:
+ shortPixel = * ( unsigned short * ) pixbuf;
+ pixbuf += 2;
+ *pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7;
+ *pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2;
+ *pixbuf++ = ( shortPixel & ( 31 ) ) << 3;
+ *pixbuf++ = 0xff;
+ break;
+
+ case 24:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = 255;
+ break;
+ case 32:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alpha = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = alpha;
+ break;
+ }
+ }
+ }
+
+ ri.FS_FreeFile( buffer.v );
+
+}
diff --git a/src/renderercommon/tr_image_jpg.cpp b/src/renderercommon/tr_image_jpg.cpp
new file mode 100644
index 0000000..9b6c1df
--- /dev/null
+++ b/src/renderercommon/tr_image_jpg.cpp
@@ -0,0 +1,479 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include <setjmp.h>
+
+#include "tr_common.h"
+
+/*
+ * Include file for users of JPEG library.
+ * You will need to have included system headers that define at least
+ * the typedefs FILE and size_t before you can include jpeglib.h.
+ * (stdio.h is sufficient on ANSI-conforming systems.)
+ * You may also wish to include "jerror.h".
+ */
+
+#ifdef USE_INTERNAL_JPEG
+# define JPEG_INTERNALS
+#endif
+
+#include <jpeglib.h>
+
+#ifndef USE_INTERNAL_JPEG
+# if JPEG_LIB_VERSION < 80 && !defined(MEM_SRCDST_SUPPORTED)
+# error Need system libjpeg >= 80 or jpeg_mem_ support
+# endif
+#endif
+
+/* Catching errors, as done in libjpeg's example.c */
+typedef struct q_jpeg_error_mgr_s
+{
+ struct jpeg_error_mgr pub; /* "public" fields */
+
+ jmp_buf setjmp_buffer; /* for return to caller */
+} q_jpeg_error_mgr_t;
+
+static void R_JPGErrorExit(j_common_ptr cinfo)
+{
+ char buffer[JMSG_LENGTH_MAX];
+
+ /* cinfo->err really points to a q_jpeg_error_mgr_s struct, so coerce pointer */
+ q_jpeg_error_mgr_t *jerr = (q_jpeg_error_mgr_t *)cinfo->err;
+
+ (*cinfo->err->format_message) (cinfo, buffer);
+
+ ri.Printf(PRINT_ALL, "Error: %s", buffer);
+
+ /* Return control to the setjmp point */
+ longjmp(jerr->setjmp_buffer, 1);
+}
+
+static void R_JPGOutputMessage(j_common_ptr cinfo)
+{
+ char buffer[JMSG_LENGTH_MAX];
+
+ /* Create the message */
+ (*cinfo->err->format_message) (cinfo, buffer);
+
+ /* Send it to stderr, adding a newline */
+ ri.Printf(PRINT_ALL, "%s\n", buffer);
+}
+
+void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *height)
+{
+ /* This struct contains the JPEG decompression parameters and pointers to
+ * working space (which is allocated as needed by the JPEG library).
+ */
+ struct jpeg_decompress_struct cinfo = {};
+
+ /* We use our private extension JPEG error handler.
+ * Note that this struct must live as long as the main JPEG parameter
+ * struct, to avoid dangling-pointer problems.
+ */
+ /* This struct represents a JPEG error handler. It is declared separately
+ * because applications often want to supply a specialized error handler
+ * (see the second half of this file for an example). But here we just
+ * take the easy way out and use the standard error handler, which will
+ * print a message on stderr and call exit() if compression fails.
+ * Note that this struct must live as long as the main JPEG parameter
+ * struct, to avoid dangling-pointer problems.
+ */
+ q_jpeg_error_mgr_t jerr;
+ /* More stuff */
+ JSAMPARRAY buffer; /* Output row buffer */
+ unsigned int row_stride; /* physical row width in output buffer */
+ unsigned int pixelcount, memcount;
+ unsigned int sindex, dindex;
+ byte *out;
+ int len;
+ union {
+ byte *b;
+ void *v;
+ } fbuffer;
+ byte *buf;
+
+ /* In this example we want to open the input file before doing anything else,
+ * so that the setjmp() error recovery below can assume the file is open.
+ * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
+ * requires it in order to read binary files.
+ */
+
+ len = ri.FS_ReadFile ( ( char * ) filename, &fbuffer.v);
+ if (!fbuffer.b || len < 0) {
+ return;
+ }
+
+ /* Step 1: allocate and initialize JPEG decompression object */
+
+ /* We have to set up the error handler first, in case the initialization
+ * step fails. (Unlikely, but it could happen if you are out of memory.)
+ * This routine fills in the contents of struct jerr, and returns jerr's
+ * address which we place into the link field in cinfo.
+ */
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ cinfo.err->error_exit = R_JPGErrorExit;
+ cinfo.err->output_message = R_JPGOutputMessage;
+
+ /* Establish the setjmp return context for R_JPGErrorExit to use. */
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_decompress(&cinfo);
+ ri.FS_FreeFile(fbuffer.v);
+
+ /* Append the filename to the error for easier debugging */
+ ri.Printf(PRINT_ALL, ", loading file %s\n", filename);
+ return;
+ }
+
+ /* Now we can initialize the JPEG decompression object. */
+ jpeg_create_decompress(&cinfo);
+
+ /* Step 2: specify data source (eg, a file) */
+
+ jpeg_mem_src(&cinfo, fbuffer.b, len);
+
+ /* Step 3: read file parameters with jpeg_read_header() */
+
+ (void) jpeg_read_header(&cinfo, TRUE);
+ /* We can ignore the return value from jpeg_read_header since
+ * (a) suspension is not possible with the stdio data source, and
+ * (b) we passed TRUE to reject a tables-only JPEG file as an error.
+ * See libjpeg.doc for more info.
+ */
+
+ /* Step 4: set parameters for decompression */
+
+ /*
+ * Make sure it always converts images to RGB color space. This will
+ * automatically convert 8-bit greyscale images to RGB as well.
+ */
+ cinfo.out_color_space = JCS_RGB;
+
+ /* Step 5: Start decompressor */
+
+ (void) jpeg_start_decompress(&cinfo);
+ /* We can ignore the return value since suspension is not possible
+ * with the stdio data source.
+ */
+
+ /* We may need to do some setup of our own at this point before reading
+ * the data. After jpeg_start_decompress() we have the correct scaled
+ * output image dimensions available, as well as the output colormap
+ * if we asked for color quantization.
+ * In this example, we need to make an output work buffer of the right size.
+ */
+ /* JSAMPLEs per row in output buffer */
+
+ pixelcount = cinfo.output_width * cinfo.output_height;
+
+ if(!cinfo.output_width || !cinfo.output_height
+ || ((pixelcount * 4) / cinfo.output_width) / 4 != cinfo.output_height
+ || pixelcount > 0x1FFFFFFF || cinfo.output_components != 3
+ )
+ {
+ // Free the memory to make sure we don't leak memory
+ ri.FS_FreeFile (fbuffer.v);
+ jpeg_destroy_decompress(&cinfo);
+
+ ri.Error(ERR_DROP, "LoadJPG: %s has an invalid image format: %dx%d*4=%d, components: %d", filename,
+ cinfo.output_width, cinfo.output_height, pixelcount * 4, cinfo.output_components);
+ }
+
+ memcount = pixelcount * 4;
+ row_stride = cinfo.output_width * cinfo.output_components;
+
+ out = (byte*)ri.Malloc(memcount);
+
+ *width = cinfo.output_width;
+ *height = cinfo.output_height;
+
+ /* Step 6: while (scan lines remain to be read) */
+ /* jpeg_read_scanlines(...); */
+
+ /* Here we use the library's state variable cinfo.output_scanline as the
+ * loop counter, so that we don't have to keep track ourselves.
+ */
+ while (cinfo.output_scanline < cinfo.output_height) {
+ /* jpeg_read_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could ask for
+ * more than one scanline at a time if that's more convenient.
+ */
+ buf = ((out+(row_stride*cinfo.output_scanline)));
+ buffer = &buf;
+ (void) jpeg_read_scanlines(&cinfo, buffer, 1);
+ }
+
+ buf = out;
+
+ // Expand from RGB to RGBA
+ sindex = pixelcount * cinfo.output_components;
+ dindex = memcount;
+
+ do
+ {
+ buf[--dindex] = 255;
+ buf[--dindex] = buf[--sindex];
+ buf[--dindex] = buf[--sindex];
+ buf[--dindex] = buf[--sindex];
+ } while(sindex);
+
+ *pic = out;
+
+ /* Step 7: Finish decompression */
+
+ jpeg_finish_decompress(&cinfo);
+ /* We can ignore the return value since suspension is not possible
+ * with the stdio data source.
+ */
+
+ /* Step 8: Release JPEG decompression object */
+
+ /* This is an important step since it will release a good deal of memory. */
+ jpeg_destroy_decompress(&cinfo);
+
+ /* After finish_decompress, we can close the input file.
+ * Here we postpone it until after no more JPEG errors are possible,
+ * so as to simplify the setjmp error logic above. (Actually, I don't
+ * think that jpeg_destroy can do an error exit, but why assume anything...)
+ */
+ ri.FS_FreeFile (fbuffer.v);
+
+ /* At this point you may want to check to see whether any corrupt-data
+ * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
+ */
+
+ /* And we're done! */
+}
+
+
+/* Expanded data destination object for stdio output */
+
+typedef struct {
+ struct jpeg_destination_mgr pub; /* public fields */
+
+ byte* outfile; /* target stream */
+ int size;
+} my_destination_mgr;
+
+typedef my_destination_mgr * my_dest_ptr;
+
+
+/*
+ * Initialize destination --- called by jpeg_start_compress
+ * before any data is actually written.
+ */
+
+static void
+init_destination (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ dest->pub.next_output_byte = dest->outfile;
+ dest->pub.free_in_buffer = dest->size;
+}
+
+
+/*
+ * Empty the output buffer --- called whenever buffer fills up.
+ *
+ * In typical applications, this should write the entire output buffer
+ * (ignoring the current state of next_output_byte & free_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been dumped.
+ *
+ * In applications that need to be able to suspend compression due to output
+ * overrun, a FALSE return indicates that the buffer cannot be emptied now.
+ * In this situation, the compressor will return to its caller (possibly with
+ * an indication that it has not accepted all the supplied scanlines). The
+ * application should resume compression after it has made more room in the
+ * output buffer. Note that there are substantial restrictions on the use of
+ * suspension --- see the documentation.
+ *
+ * When suspending, the compressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_output_byte & free_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point will be regenerated after resumption, so do not
+ * write it out when emptying the buffer externally.
+ */
+
+static boolean
+empty_output_buffer (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ jpeg_destroy_compress(cinfo);
+
+ // Make crash fatal or we would probably leak memory.
+ ri.Error(ERR_FATAL, "Output buffer for encoded JPEG image has insufficient size of %d bytes",
+ dest->size);
+
+ return FALSE;
+}
+
+/*
+ * Terminate destination --- called by jpeg_finish_compress
+ * after all data has been written. Usually needs to flush buffer.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+static void term_destination(j_compress_ptr cinfo)
+{
+}
+
+
+/*
+ * Prepare for output to a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing compression.
+ */
+
+static void
+jpegDest (j_compress_ptr cinfo, byte* outfile, int size)
+{
+ my_dest_ptr dest;
+
+ /* The destination object is made permanent so that multiple JPEG images
+ * can be written to the same file without re-executing jpeg_stdio_dest.
+ * This makes it dangerous to use this manager and a different destination
+ * manager serially with the same JPEG object, because their private object
+ * sizes may be different. Caveat programmer.
+ */
+ if (cinfo->dest == NULL) { /* first time for this JPEG object? */
+ cinfo->dest = (struct jpeg_destination_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ sizeof(my_destination_mgr));
+ }
+
+ dest = (my_dest_ptr) cinfo->dest;
+ dest->pub.init_destination = init_destination;
+ dest->pub.empty_output_buffer = empty_output_buffer;
+ dest->pub.term_destination = term_destination;
+ dest->outfile = outfile;
+ dest->size = size;
+}
+
+/*
+=================
+SaveJPGToBuffer
+
+Encodes JPEG from image in image_buffer and writes to buffer.
+Expects RGB input data
+=================
+*/
+size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality,
+ int image_width, int image_height, byte *image_buffer, int padding)
+{
+ struct jpeg_compress_struct cinfo;
+ q_jpeg_error_mgr_t jerr;
+ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
+ my_dest_ptr dest;
+ int row_stride; /* physical row width in image buffer */
+ size_t outcount;
+
+ /* Step 1: allocate and initialize JPEG compression object */
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ cinfo.err->error_exit = R_JPGErrorExit;
+ cinfo.err->output_message = R_JPGOutputMessage;
+
+ /* Establish the setjmp return context for R_JPGErrorExit to use. */
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object and return.
+ */
+ jpeg_destroy_compress(&cinfo);
+
+ ri.Printf(PRINT_ALL, "\n");
+ return 0;
+ }
+
+ /* 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. */
+ jpegDest(&cinfo, buffer, bufSize);
+
+ /* Step 3: set parameters for compression */
+ 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 */
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+ /* If quality is set high, disable chroma subsampling */
+ if (quality >= 85) {
+ cinfo.comp_info[0].h_samp_factor = 1;
+ cinfo.comp_info[0].v_samp_factor = 1;
+ }
+
+ /* Step 4: Start compressor */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Step 5: while (scan lines remain to be written) */
+ /* jpeg_write_scanlines(...); */
+ row_stride = image_width * cinfo.input_components + padding; /* 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.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
+ (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+ /* Step 6: Finish compression */
+ jpeg_finish_compress(&cinfo);
+
+ dest = (my_dest_ptr) cinfo.dest;
+ outcount = dest->size - dest->pub.free_in_buffer;
+
+ /* Step 7: release JPEG compression object */
+ jpeg_destroy_compress(&cinfo);
+
+ /* And we're done! */
+ return outcount;
+}
+
+void RE_SaveJPG(char * filename, int quality, int image_width, int image_height, byte *image_buffer, int padding)
+{
+ byte *out;
+ size_t bufSize;
+
+ bufSize = image_width * image_height * 3;
+ out = (byte*)ri.Hunk_AllocateTempMemory(bufSize);
+
+ bufSize = RE_SaveJPGToBuffer(out, bufSize, quality, image_width, image_height, image_buffer, padding);
+ ri.FS_WriteFile(filename, out, bufSize);
+
+ ri.Hunk_FreeTempMemory(out);
+}
diff --git a/src/renderercommon/tr_image_pcx.cpp b/src/renderercommon/tr_image_pcx.cpp
new file mode 100644
index 0000000..9308cfe
--- /dev/null
+++ b/src/renderercommon/tr_image_pcx.cpp
@@ -0,0 +1,177 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+ 2008 Ludwig Nussel
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_common.h"
+
+/*
+========================================================================
+
+PCX files are used for 8 bit images
+
+========================================================================
+*/
+
+typedef struct {
+ char manufacturer;
+ char version;
+ char encoding;
+ char bits_per_pixel;
+ unsigned short xmin,ymin,xmax,ymax;
+ unsigned short hres,vres;
+ unsigned char palette[48];
+ char reserved;
+ char color_planes;
+ unsigned short bytes_per_line;
+ unsigned short palette_type;
+ unsigned short hscreensize, vscreensize;
+ char filler[54];
+ unsigned char data[];
+} pcx_t;
+
+void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height)
+{
+ union {
+ byte *b;
+ void *v;
+ } raw;
+ byte *end;
+ pcx_t *pcx;
+ int len;
+ unsigned char dataByte = 0, runLength = 0;
+ byte *out, *pix;
+ unsigned short w, h;
+ byte *pic8;
+ byte *palette;
+ int i;
+ unsigned size = 0;
+
+ if (width)
+ *width = 0;
+ if (height)
+ *height = 0;
+ *pic = NULL;
+
+ //
+ // load the file
+ //
+ len = ri.FS_ReadFile( ( char * ) filename, &raw.v);
+ if (!raw.b || len < 0) {
+ return;
+ }
+
+ if((unsigned)len < sizeof(pcx_t))
+ {
+ ri.Printf (PRINT_ALL, "PCX truncated: %s\n", filename);
+ ri.FS_FreeFile (raw.v);
+ return;
+ }
+
+ //
+ // parse the PCX file
+ //
+ pcx = (pcx_t *)raw.b;
+ end = raw.b+len;
+
+ w = LittleShort(pcx->xmax)+1;
+ h = LittleShort(pcx->ymax)+1;
+ size = w*h;
+
+ if (pcx->manufacturer != 0x0a
+ || pcx->version != 5
+ || pcx->encoding != 1
+ || pcx->color_planes != 1
+ || pcx->bits_per_pixel != 8
+ || w >= 1024
+ || h >= 1024)
+ {
+ ri.Printf (PRINT_ALL, "Bad or unsupported pcx file %s (%dx%d@%d)\n", filename, w, h, pcx->bits_per_pixel);
+ return;
+ }
+
+ pix = pic8 = (byte*)ri.Malloc ( size );
+
+ raw.b = pcx->data;
+ // FIXME: should use bytes_per_line but original q3 didn't do that either
+ while(pix < pic8+size)
+ {
+ if(runLength > 0) {
+ *pix++ = dataByte;
+ --runLength;
+ continue;
+ }
+
+ if(raw.b+1 > end)
+ break;
+ dataByte = *raw.b++;
+
+ if((dataByte & 0xC0) == 0xC0)
+ {
+ if(raw.b+1 > end)
+ break;
+ runLength = dataByte & 0x3F;
+ dataByte = *raw.b++;
+ }
+ else
+ runLength = 1;
+ }
+
+ if(pix < pic8+size)
+ {
+ ri.Printf (PRINT_ALL, "PCX file truncated: %s\n", filename);
+ ri.FS_FreeFile (pcx);
+ ri.Free (pic8);
+ }
+
+ if (raw.b-(byte*)pcx >= end - (byte*)769 || end[-769] != 0x0c)
+ {
+ ri.Printf (PRINT_ALL, "PCX missing palette: %s\n", filename);
+ ri.FS_FreeFile (pcx);
+ ri.Free (pic8);
+ return;
+ }
+
+ palette = end-768;
+
+ pix = out = (byte*)ri.Malloc(4 * size );
+ for (i = 0 ; i < size ; i++)
+ {
+ unsigned char p = pic8[i];
+ pix[0] = palette[p*3];
+ pix[1] = palette[p*3 + 1];
+ pix[2] = palette[p*3 + 2];
+ pix[3] = 255;
+ pix += 4;
+ }
+
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
+
+ *pic = out;
+
+ ri.FS_FreeFile (pcx);
+ ri.Free (pic8);
+}
diff --git a/src/renderercommon/tr_image_png.cpp b/src/renderercommon/tr_image_png.cpp
new file mode 100644
index 0000000..6a3f6e8
--- /dev/null
+++ b/src/renderercommon/tr_image_png.cpp
@@ -0,0 +1,2486 @@
+/*
+===========================================================================
+ioquake3 png decoder
+Copyright (C) 2007,2008 Joerg Dietrich
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 3
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.
+===========================================================================
+*/
+
+#include "tr_common.h"
+
+#include "qcommon/puff.h"
+
+// we could limit the png size to a lower value here
+#ifndef INT_MAX
+#define INT_MAX 0x1fffffff
+#endif
+
+/*
+=================
+PNG LOADING
+=================
+*/
+
+/*
+ * Quake 3 image format : RGBA
+ */
+
+#define Q3IMAGE_BYTESPERPIXEL (4)
+
+/*
+ * PNG specifications
+ */
+
+/*
+ * The first 8 Bytes of every PNG-File are a fixed signature
+ * to identify the file as a PNG.
+ */
+
+#define PNG_Signature "\x89\x50\x4E\x47\xD\xA\x1A\xA"
+#define PNG_Signature_Size (8)
+
+/*
+ * After the signature diverse chunks follow.
+ * A chunk consists of a header and if Length
+ * is bigger than 0 a body and a CRC of the body follow.
+ */
+
+struct PNG_ChunkHeader
+{
+ uint32_t Length;
+ uint32_t Type;
+};
+
+#define PNG_ChunkHeader_Size (8)
+
+typedef uint32_t PNG_ChunkCRC;
+
+#define PNG_ChunkCRC_Size (4)
+
+/*
+ * We use the following ChunkTypes.
+ * All others are ignored.
+ */
+
+#define MAKE_CHUNKTYPE(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | ((d)))
+
+#define PNG_ChunkType_IHDR MAKE_CHUNKTYPE('I', 'H', 'D', 'R')
+#define PNG_ChunkType_PLTE MAKE_CHUNKTYPE('P', 'L', 'T', 'E')
+#define PNG_ChunkType_IDAT MAKE_CHUNKTYPE('I', 'D', 'A', 'T')
+#define PNG_ChunkType_IEND MAKE_CHUNKTYPE('I', 'E', 'N', 'D')
+#define PNG_ChunkType_tRNS MAKE_CHUNKTYPE('t', 'R', 'N', 'S')
+
+/*
+ * Per specification the first chunk after the signature SHALL be IHDR.
+ */
+
+struct PNG_Chunk_IHDR
+{
+ uint32_t Width;
+ uint32_t Height;
+ uint8_t BitDepth;
+ uint8_t ColourType;
+ uint8_t CompressionMethod;
+ uint8_t FilterMethod;
+ uint8_t InterlaceMethod;
+};
+
+#define PNG_Chunk_IHDR_Size (13)
+
+/*
+ * ColourTypes
+ */
+
+#define PNG_ColourType_Grey (0)
+#define PNG_ColourType_True (2)
+#define PNG_ColourType_Indexed (3)
+#define PNG_ColourType_GreyAlpha (4)
+#define PNG_ColourType_TrueAlpha (6)
+
+/*
+ * number of colour components
+ *
+ * Grey : 1 grey
+ * True : 1 R, 1 G, 1 B
+ * Indexed : 1 index
+ * GreyAlpha : 1 grey, 1 alpha
+ * TrueAlpha : 1 R, 1 G, 1 B, 1 alpha
+ */
+
+#define PNG_NumColourComponents_Grey (1)
+#define PNG_NumColourComponents_True (3)
+#define PNG_NumColourComponents_Indexed (1)
+#define PNG_NumColourComponents_GreyAlpha (2)
+#define PNG_NumColourComponents_TrueAlpha (4)
+
+/*
+ * For the different ColourTypes
+ * different BitDepths are specified.
+ */
+
+#define PNG_BitDepth_1 ( 1)
+#define PNG_BitDepth_2 ( 2)
+#define PNG_BitDepth_4 ( 4)
+#define PNG_BitDepth_8 ( 8)
+#define PNG_BitDepth_16 (16)
+
+/*
+ * Only one valid CompressionMethod is standardized.
+ */
+
+#define PNG_CompressionMethod_0 (0)
+
+/*
+ * Only one valid FilterMethod is currently standardized.
+ */
+
+#define PNG_FilterMethod_0 (0)
+
+/*
+ * This FilterMethod defines 5 FilterTypes
+ */
+
+#define PNG_FilterType_None (0)
+#define PNG_FilterType_Sub (1)
+#define PNG_FilterType_Up (2)
+#define PNG_FilterType_Average (3)
+#define PNG_FilterType_Paeth (4)
+
+/*
+ * Two InterlaceMethods are standardized :
+ * 0 - NonInterlaced
+ * 1 - Interlaced
+ */
+
+#define PNG_InterlaceMethod_NonInterlaced (0)
+#define PNG_InterlaceMethod_Interlaced (1)
+
+/*
+ * The Adam7 interlace method uses 7 passes.
+ */
+
+#define PNG_Adam7_NumPasses (7)
+
+/*
+ * The compressed data starts with a header ...
+ */
+
+struct PNG_ZlibHeader
+{
+ uint8_t CompressionMethod;
+ uint8_t Flags;
+};
+
+#define PNG_ZlibHeader_Size (2)
+
+/*
+ * ... and is followed by a check value
+ */
+
+#define PNG_ZlibCheckValue_Size (4)
+
+/*
+ * Some support functions for buffered files follow.
+ */
+
+/*
+ * buffered file representation
+ */
+
+struct BufferedFile
+{
+ byte *Buffer;
+ int Length;
+ byte *Ptr;
+ int BytesLeft;
+};
+
+/*
+ * Read a file into a buffer.
+ */
+
+static struct BufferedFile *ReadBufferedFile(const char *name)
+{
+ struct BufferedFile *BF;
+ union {
+ byte *b;
+ void *v;
+ } buffer;
+
+ /*
+ * input verification
+ */
+
+ if(!name)
+ {
+ return(NULL);
+ }
+
+ /*
+ * Allocate control struct.
+ */
+
+ BF = (struct BufferedFile*)ri.Malloc(sizeof(struct BufferedFile));
+ if(!BF)
+ {
+ return(NULL);
+ }
+
+ /*
+ * Initialize the structs components.
+ */
+
+ BF->Length = 0;
+ BF->Buffer = NULL;
+ BF->Ptr = NULL;
+ BF->BytesLeft = 0;
+
+ /*
+ * Read the file.
+ */
+
+ BF->Length = ri.FS_ReadFile((char *) name, &buffer.v);
+ BF->Buffer = buffer.b;
+
+ /*
+ * Did we get it? Is it big enough?
+ */
+
+ if(!(BF->Buffer && (BF->Length > 0)))
+ {
+ ri.Free(BF);
+
+ return(NULL);
+ }
+
+ /*
+ * Set the pointers and counters.
+ */
+
+ BF->Ptr = BF->Buffer;
+ BF->BytesLeft = BF->Length;
+
+ return(BF);
+}
+
+/*
+ * Close a buffered file.
+ */
+
+static void CloseBufferedFile(struct BufferedFile *BF)
+{
+ if(BF)
+ {
+ if(BF->Buffer)
+ {
+ ri.FS_FreeFile(BF->Buffer);
+ }
+
+ ri.Free(BF);
+ }
+}
+
+/*
+ * Get a pointer to the requested bytes.
+ */
+
+static void *BufferedFileRead(struct BufferedFile *BF, unsigned Length)
+{
+ void *RetVal;
+
+ /*
+ * input verification
+ */
+
+ if(!(BF && Length))
+ {
+ return(NULL);
+ }
+
+ /*
+ * not enough bytes left
+ */
+
+ if(Length > BF->BytesLeft)
+ {
+ return(NULL);
+ }
+
+ /*
+ * the pointer to the requested data
+ */
+
+ RetVal = BF->Ptr;
+
+ /*
+ * Raise the pointer and counter.
+ */
+
+ BF->Ptr += Length;
+ BF->BytesLeft -= Length;
+
+ return(RetVal);
+}
+
+/*
+ * Rewind the buffer.
+ */
+
+static qboolean BufferedFileRewind(struct BufferedFile *BF, unsigned Offset)
+{
+ unsigned BytesRead;
+
+ /*
+ * input verification
+ */
+
+ if(!BF)
+ {
+ return(qfalse);
+ }
+
+ /*
+ * special trick to rewind to the beginning of the buffer
+ */
+
+ if(Offset == (unsigned)-1)
+ {
+ BF->Ptr = BF->Buffer;
+ BF->BytesLeft = BF->Length;
+
+ return(qtrue);
+ }
+
+ /*
+ * How many bytes do we have already read?
+ */
+
+ BytesRead = BF->Ptr - BF->Buffer;
+
+ /*
+ * We can only rewind to the beginning of the BufferedFile.
+ */
+
+ if(Offset > BytesRead)
+ {
+ return(qfalse);
+ }
+
+ /*
+ * lower the pointer and counter.
+ */
+
+ BF->Ptr -= Offset;
+ BF->BytesLeft += Offset;
+
+ return(qtrue);
+}
+
+/*
+ * Skip some bytes.
+ */
+
+static qboolean BufferedFileSkip(struct BufferedFile *BF, unsigned Offset)
+{
+ /*
+ * input verification
+ */
+
+ if(!BF)
+ {
+ return(qfalse);
+ }
+
+ /*
+ * We can only skip to the end of the BufferedFile.
+ */
+
+ if(Offset > BF->BytesLeft)
+ {
+ return(qfalse);
+ }
+
+ /*
+ * lower the pointer and counter.
+ */
+
+ BF->Ptr += Offset;
+ BF->BytesLeft -= Offset;
+
+ return(qtrue);
+}
+
+/*
+ * Find a chunk
+ */
+
+static qboolean FindChunk(struct BufferedFile *BF, uint32_t ChunkType)
+{
+ struct PNG_ChunkHeader *CH;
+
+ uint32_t Length;
+ uint32_t Type;
+
+ /*
+ * input verification
+ */
+
+ if(!BF)
+ {
+ return(qfalse);
+ }
+
+ /*
+ * cycle trough the chunks
+ */
+
+ while(qtrue)
+ {
+ /*
+ * Read the chunk-header.
+ */
+
+ CH = (struct PNG_ChunkHeader*)BufferedFileRead(BF, PNG_ChunkHeader_Size);
+ if(!CH)
+ {
+ return(qfalse);
+ }
+
+ /*
+ * Do not swap the original types
+ * they might be needed later.
+ */
+
+ Length = BigLong(CH->Length);
+ Type = BigLong(CH->Type);
+
+ /*
+ * We found it!
+ */
+
+ if(Type == ChunkType)
+ {
+ /*
+ * Rewind to the start of the chunk.
+ */
+
+ BufferedFileRewind(BF, PNG_ChunkHeader_Size);
+
+ break;
+ }
+ else
+ {
+ /*
+ * Skip the rest of the chunk.
+ */
+
+ if(Length)
+ {
+ if(!BufferedFileSkip(BF, Length + PNG_ChunkCRC_Size))
+ {
+ return(qfalse);
+ }
+ }
+ }
+ }
+
+ return(qtrue);
+}
+
+/*
+ * Decompress all IDATs
+ */
+
+static uint32_t DecompressIDATs(struct BufferedFile *BF, uint8_t **Buffer)
+{
+ uint8_t *DecompressedData;
+ uint32_t DecompressedDataLength;
+
+ uint8_t *CompressedData;
+ uint8_t *CompressedDataPtr;
+ uint32_t CompressedDataLength;
+
+ struct PNG_ChunkHeader *CH;
+
+ uint32_t Length;
+ uint32_t Type;
+
+ int BytesToRewind;
+
+ int32_t puffResult;
+ uint8_t *puffDest;
+ uint32_t puffDestLen;
+ uint8_t *puffSrc;
+ uint32_t puffSrcLen;
+
+ /*
+ * input verification
+ */
+
+ if(!(BF && Buffer))
+ {
+ return(-1);
+ }
+
+ /*
+ * some zeroing
+ */
+
+ DecompressedData = NULL;
+ *Buffer = DecompressedData;
+
+ CompressedData = NULL;
+ CompressedDataLength = 0;
+
+ BytesToRewind = 0;
+
+ /*
+ * Find the first IDAT chunk.
+ */
+
+ if(!FindChunk(BF, PNG_ChunkType_IDAT))
+ {
+ return(-1);
+ }
+
+ /*
+ * Count the size of the uncompressed data
+ */
+
+ while(qtrue)
+ {
+ /*
+ * Read chunk header
+ */
+
+ CH = (struct PNG_ChunkHeader*)BufferedFileRead(BF, PNG_ChunkHeader_Size);
+ if(!CH)
+ {
+ /*
+ * Rewind to the start of this adventure
+ * and return unsuccessfull
+ */
+
+ BufferedFileRewind(BF, BytesToRewind);
+
+ return(-1);
+ }
+
+ /*
+ * Length and Type of chunk
+ */
+
+ Length = BigLong(CH->Length);
+ Type = BigLong(CH->Type);
+
+ /*
+ * We have reached the end of the IDAT chunks
+ */
+
+ if(!(Type == PNG_ChunkType_IDAT))
+ {
+ BufferedFileRewind(BF, PNG_ChunkHeader_Size);
+
+ break;
+ }
+
+ /*
+ * Add chunk header to count.
+ */
+
+ BytesToRewind += PNG_ChunkHeader_Size;
+
+ /*
+ * Skip to next chunk
+ */
+
+ if(Length)
+ {
+ if(!BufferedFileSkip(BF, Length + PNG_ChunkCRC_Size))
+ {
+ BufferedFileRewind(BF, BytesToRewind);
+
+ return(-1);
+ }
+
+ BytesToRewind += Length + PNG_ChunkCRC_Size;
+ CompressedDataLength += Length;
+ }
+ }
+
+ BufferedFileRewind(BF, BytesToRewind);
+
+ CompressedData = (uint8_t*)ri.Malloc(CompressedDataLength);
+ if(!CompressedData)
+ {
+ return(-1);
+ }
+
+ CompressedDataPtr = CompressedData;
+
+ /*
+ * Collect the compressed Data
+ */
+
+ while(qtrue)
+ {
+ /*
+ * Read chunk header
+ */
+
+ CH = (struct PNG_ChunkHeader*)BufferedFileRead(BF, PNG_ChunkHeader_Size);
+ if(!CH)
+ {
+ ri.Free(CompressedData);
+
+ return(-1);
+ }
+
+ /*
+ * Length and Type of chunk
+ */
+
+ Length = BigLong(CH->Length);
+ Type = BigLong(CH->Type);
+
+ /*
+ * We have reached the end of the IDAT chunks
+ */
+
+ if(!(Type == PNG_ChunkType_IDAT))
+ {
+ BufferedFileRewind(BF, PNG_ChunkHeader_Size);
+
+ break;
+ }
+
+ /*
+ * Copy the Data
+ */
+
+ if(Length)
+ {
+ uint8_t *OrigCompressedData;
+
+ OrigCompressedData = (uint8_t*)BufferedFileRead(BF, Length);
+ if(!OrigCompressedData)
+ {
+ ri.Free(CompressedData);
+
+ return(-1);
+ }
+
+ if(!BufferedFileSkip(BF, PNG_ChunkCRC_Size))
+ {
+ ri.Free(CompressedData);
+
+ return(-1);
+ }
+
+ memcpy(CompressedDataPtr, OrigCompressedData, Length);
+ CompressedDataPtr += Length;
+ }
+ }
+
+ /*
+ * Let puff() calculate the decompressed data length.
+ */
+
+ puffDest = NULL;
+ puffDestLen = 0;
+
+ /*
+ * The zlib header and checkvalue don't belong to the compressed data.
+ */
+
+ puffSrc = CompressedData + PNG_ZlibHeader_Size;
+ puffSrcLen = CompressedDataLength - PNG_ZlibHeader_Size - PNG_ZlibCheckValue_Size;
+
+ /*
+ * first puff() to calculate the size of the uncompressed data
+ */
+
+ puffResult = puff(puffDest, &puffDestLen, puffSrc, &puffSrcLen);
+ if(!((puffResult == 0) && (puffDestLen > 0)))
+ {
+ ri.Free(CompressedData);
+
+ return(-1);
+ }
+
+ /*
+ * Allocate the buffer for the uncompressed data.
+ */
+
+ DecompressedData = (uint8_t*)ri.Malloc(puffDestLen);
+ if(!DecompressedData)
+ {
+ ri.Free(CompressedData);
+
+ return(-1);
+ }
+
+ /*
+ * Set the input again in case something was changed by the last puff() .
+ */
+
+ puffDest = DecompressedData;
+ puffSrc = CompressedData + PNG_ZlibHeader_Size;
+ puffSrcLen = CompressedDataLength - PNG_ZlibHeader_Size - PNG_ZlibCheckValue_Size;
+
+ /*
+ * decompression puff()
+ */
+
+ puffResult = puff(puffDest, &puffDestLen, puffSrc, &puffSrcLen);
+
+ /*
+ * The compressed data is not needed anymore.
+ */
+
+ ri.Free(CompressedData);
+
+ /*
+ * Check if the last puff() was successfull.
+ */
+
+ if(!((puffResult == 0) && (puffDestLen > 0)))
+ {
+ ri.Free(DecompressedData);
+
+ return(-1);
+ }
+
+ /*
+ * Set the output of this function.
+ */
+
+ DecompressedDataLength = puffDestLen;
+ *Buffer = DecompressedData;
+
+ return(DecompressedDataLength);
+}
+
+/*
+ * the Paeth predictor
+ */
+
+static uint8_t PredictPaeth(uint8_t a, uint8_t b, uint8_t c)
+{
+ /*
+ * a == Left
+ * b == Up
+ * c == UpLeft
+ */
+
+ uint8_t Pr;
+ int p;
+ int pa, pb, pc;
+
+ p = ((int) a) + ((int) b) - ((int) c);
+ pa = abs(p - ((int) a));
+ pb = abs(p - ((int) b));
+ pc = abs(p - ((int) c));
+
+ if((pa <= pb) && (pa <= pc))
+ {
+ Pr = a;
+ }
+ else if(pb <= pc)
+ {
+ Pr = b;
+ }
+ else
+ {
+ Pr = c;
+ }
+
+ return(Pr);
+
+}
+
+/*
+ * Reverse the filters.
+ */
+
+static qboolean UnfilterImage(uint8_t *DecompressedData,
+ uint32_t ImageHeight,
+ uint32_t BytesPerScanline,
+ uint32_t BytesPerPixel)
+{
+ uint8_t *DecompPtr;
+ uint8_t FilterType;
+ uint8_t *PixelLeft, *PixelUp, *PixelUpLeft;
+ uint32_t w, h, p;
+
+ /*
+ * some zeros for the filters
+ */
+
+ uint8_t Zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+ /*
+ * input verification
+ */
+
+ if(!(DecompressedData && BytesPerPixel))
+ {
+ return(qfalse);
+ }
+
+ /*
+ * ImageHeight and BytesPerScanline can be zero in small interlaced images.
+ */
+
+ if((!ImageHeight) || (!BytesPerScanline))
+ {
+ return(qtrue);
+ }
+
+ /*
+ * Set the pointer to the start of the decompressed Data.
+ */
+
+ DecompPtr = DecompressedData;
+
+ /*
+ * Un-filtering is done in place.
+ */
+
+ /*
+ * Go trough all scanlines.
+ */
+
+ for(h = 0; h < ImageHeight; h++)
+ {
+ /*
+ * Every scanline starts with a FilterType byte.
+ */
+
+ FilterType = *DecompPtr;
+ DecompPtr++;
+
+ /*
+ * Left pixel of the first byte in a scanline is zero.
+ */
+
+ PixelLeft = Zeros;
+
+ /*
+ * Set PixelUp to previous line only if we are on the second line or above.
+ *
+ * Plus one byte for the FilterType
+ */
+
+ if(h > 0)
+ {
+ PixelUp = DecompPtr - (BytesPerScanline + 1);
+ }
+ else
+ {
+ PixelUp = Zeros;
+ }
+
+ /*
+ * The pixel left to the first pixel of the previous scanline is zero too.
+ */
+
+ PixelUpLeft = Zeros;
+
+ /*
+ * Cycle trough all pixels of the scanline.
+ */
+
+ for(w = 0; w < (BytesPerScanline / BytesPerPixel); w++)
+ {
+ /*
+ * Cycle trough the bytes of the pixel.
+ */
+
+ for(p = 0; p < BytesPerPixel; p++)
+ {
+ switch(FilterType)
+ {
+ case PNG_FilterType_None :
+ {
+ /*
+ * The byte is unfiltered.
+ */
+
+ break;
+ }
+
+ case PNG_FilterType_Sub :
+ {
+ DecompPtr[p] += PixelLeft[p];
+
+ break;
+ }
+
+ case PNG_FilterType_Up :
+ {
+ DecompPtr[p] += PixelUp[p];
+
+ break;
+ }
+
+ case PNG_FilterType_Average :
+ {
+ DecompPtr[p] += ((uint8_t) ((((uint16_t) PixelLeft[p]) + ((uint16_t) PixelUp[p])) / 2));
+
+ break;
+ }
+
+ case PNG_FilterType_Paeth :
+ {
+ DecompPtr[p] += PredictPaeth(PixelLeft[p], PixelUp[p], PixelUpLeft[p]);
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+ }
+
+ PixelLeft = DecompPtr;
+
+ /*
+ * We only have an upleft pixel if we are on the second line or above.
+ */
+
+ if(h > 0)
+ {
+ PixelUpLeft = DecompPtr - (BytesPerScanline + 1);
+ }
+
+ /*
+ * Skip to the next pixel.
+ */
+
+ DecompPtr += BytesPerPixel;
+
+ /*
+ * We only have a previous line if we are on the second line and above.
+ */
+
+ if(h > 0)
+ {
+ PixelUp = DecompPtr - (BytesPerScanline + 1);
+ }
+ }
+ }
+
+ return(qtrue);
+}
+
+/*
+ * Convert a raw input pixel to Quake 3 RGA format.
+ */
+
+static qboolean ConvertPixel(struct PNG_Chunk_IHDR *IHDR,
+ byte *OutPtr,
+ uint8_t *DecompPtr,
+ qboolean HasTransparentColour,
+ uint8_t *TransparentColour,
+ uint8_t *OutPal)
+{
+ /*
+ * input verification
+ */
+
+ if(!(IHDR && OutPtr && DecompPtr && TransparentColour && OutPal))
+ {
+ return(qfalse);
+ }
+
+ switch(IHDR->ColourType)
+ {
+ case PNG_ColourType_Grey :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_1 :
+ case PNG_BitDepth_2 :
+ case PNG_BitDepth_4 :
+ {
+ uint8_t Step;
+ uint8_t GreyValue;
+
+ Step = 0xFF / ((1 << IHDR->BitDepth) - 1);
+
+ GreyValue = DecompPtr[0] * Step;
+
+ OutPtr[0] = GreyValue;
+ OutPtr[1] = GreyValue;
+ OutPtr[2] = GreyValue;
+ OutPtr[3] = 0xFF;
+
+ /*
+ * Grey supports full transparency for one specified colour
+ */
+
+ if(HasTransparentColour)
+ {
+ if(TransparentColour[1] == DecompPtr[0])
+ {
+ OutPtr[3] = 0x00;
+ }
+ }
+
+
+ break;
+ }
+
+ case PNG_BitDepth_8 :
+ case PNG_BitDepth_16 :
+ {
+ OutPtr[0] = DecompPtr[0];
+ OutPtr[1] = DecompPtr[0];
+ OutPtr[2] = DecompPtr[0];
+ OutPtr[3] = 0xFF;
+
+ /*
+ * Grey supports full transparency for one specified colour
+ */
+
+ if(HasTransparentColour)
+ {
+ if(IHDR->BitDepth == PNG_BitDepth_8)
+ {
+ if(TransparentColour[1] == DecompPtr[0])
+ {
+ OutPtr[3] = 0x00;
+ }
+ }
+ else
+ {
+ if((TransparentColour[0] == DecompPtr[0]) && (TransparentColour[1] == DecompPtr[1]))
+ {
+ OutPtr[3] = 0x00;
+ }
+ }
+ }
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ case PNG_ColourType_True :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_8 :
+ {
+ OutPtr[0] = DecompPtr[0];
+ OutPtr[1] = DecompPtr[1];
+ OutPtr[2] = DecompPtr[2];
+ OutPtr[3] = 0xFF;
+
+ /*
+ * True supports full transparency for one specified colour
+ */
+
+ if(HasTransparentColour)
+ {
+ if((TransparentColour[1] == DecompPtr[0]) &&
+ (TransparentColour[3] == DecompPtr[1]) &&
+ (TransparentColour[5] == DecompPtr[2]))
+ {
+ OutPtr[3] = 0x00;
+ }
+ }
+
+ break;
+ }
+
+ case PNG_BitDepth_16 :
+ {
+ /*
+ * We use only the upper byte.
+ */
+
+ OutPtr[0] = DecompPtr[0];
+ OutPtr[1] = DecompPtr[2];
+ OutPtr[2] = DecompPtr[4];
+ OutPtr[3] = 0xFF;
+
+ /*
+ * True supports full transparency for one specified colour
+ */
+
+ if(HasTransparentColour)
+ {
+ if((TransparentColour[0] == DecompPtr[0]) && (TransparentColour[1] == DecompPtr[1]) &&
+ (TransparentColour[2] == DecompPtr[2]) && (TransparentColour[3] == DecompPtr[3]) &&
+ (TransparentColour[4] == DecompPtr[4]) && (TransparentColour[5] == DecompPtr[5]))
+ {
+ OutPtr[3] = 0x00;
+ }
+ }
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ case PNG_ColourType_Indexed :
+ {
+ OutPtr[0] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 0];
+ OutPtr[1] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 1];
+ OutPtr[2] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 2];
+ OutPtr[3] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 3];
+
+ break;
+ }
+
+ case PNG_ColourType_GreyAlpha :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_8 :
+ {
+ OutPtr[0] = DecompPtr[0];
+ OutPtr[1] = DecompPtr[0];
+ OutPtr[2] = DecompPtr[0];
+ OutPtr[3] = DecompPtr[1];
+
+ break;
+ }
+
+ case PNG_BitDepth_16 :
+ {
+ /*
+ * We use only the upper byte.
+ */
+
+ OutPtr[0] = DecompPtr[0];
+ OutPtr[1] = DecompPtr[0];
+ OutPtr[2] = DecompPtr[0];
+ OutPtr[3] = DecompPtr[2];
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ case PNG_ColourType_TrueAlpha :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_8 :
+ {
+ OutPtr[0] = DecompPtr[0];
+ OutPtr[1] = DecompPtr[1];
+ OutPtr[2] = DecompPtr[2];
+ OutPtr[3] = DecompPtr[3];
+
+ break;
+ }
+
+ case PNG_BitDepth_16 :
+ {
+ /*
+ * We use only the upper byte.
+ */
+
+ OutPtr[0] = DecompPtr[0];
+ OutPtr[1] = DecompPtr[2];
+ OutPtr[2] = DecompPtr[4];
+ OutPtr[3] = DecompPtr[6];
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ return(qtrue);
+}
+
+
+/*
+ * Decode a non-interlaced image.
+ */
+
+static qboolean DecodeImageNonInterlaced(struct PNG_Chunk_IHDR *IHDR,
+ byte *OutBuffer,
+ uint8_t *DecompressedData,
+ uint32_t DecompressedDataLength,
+ qboolean HasTransparentColour,
+ uint8_t *TransparentColour,
+ uint8_t *OutPal)
+{
+ uint32_t IHDR_Width;
+ uint32_t IHDR_Height;
+ uint32_t BytesPerScanline, BytesPerPixel, PixelsPerByte;
+ uint32_t w, h, p;
+ byte *OutPtr;
+ uint8_t *DecompPtr;
+
+ /*
+ * input verification
+ */
+
+ if(!(IHDR && OutBuffer && DecompressedData && DecompressedDataLength && TransparentColour && OutPal))
+ {
+ return(qfalse);
+ }
+
+ /*
+ * byte swapping
+ */
+
+ IHDR_Width = BigLong(IHDR->Width);
+ IHDR_Height = BigLong(IHDR->Height);
+
+ /*
+ * information for un-filtering
+ */
+
+ switch(IHDR->ColourType)
+ {
+ case PNG_ColourType_Grey :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_1 :
+ case PNG_BitDepth_2 :
+ case PNG_BitDepth_4 :
+ {
+ BytesPerPixel = 1;
+ PixelsPerByte = 8 / IHDR->BitDepth;
+
+ break;
+ }
+
+ case PNG_BitDepth_8 :
+ case PNG_BitDepth_16 :
+ {
+ BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_Grey;
+ PixelsPerByte = 1;
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ case PNG_ColourType_True :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_8 :
+ case PNG_BitDepth_16 :
+ {
+ BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_True;
+ PixelsPerByte = 1;
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ case PNG_ColourType_Indexed :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_1 :
+ case PNG_BitDepth_2 :
+ case PNG_BitDepth_4 :
+ {
+ BytesPerPixel = 1;
+ PixelsPerByte = 8 / IHDR->BitDepth;
+
+ break;
+ }
+
+ case PNG_BitDepth_8 :
+ {
+ BytesPerPixel = PNG_NumColourComponents_Indexed;
+ PixelsPerByte = 1;
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ case PNG_ColourType_GreyAlpha :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_8 :
+ case PNG_BitDepth_16 :
+ {
+ BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_GreyAlpha;
+ PixelsPerByte = 1;
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ case PNG_ColourType_TrueAlpha :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_8 :
+ case PNG_BitDepth_16 :
+ {
+ BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_TrueAlpha;
+ PixelsPerByte = 1;
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ /*
+ * Calculate the size of one scanline
+ */
+
+ BytesPerScanline = (IHDR_Width * BytesPerPixel + (PixelsPerByte - 1)) / PixelsPerByte;
+
+ /*
+ * Check if we have enough data for the whole image.
+ */
+
+ if(!(DecompressedDataLength == ((BytesPerScanline + 1) * IHDR_Height)))
+ {
+ return(qfalse);
+ }
+
+ /*
+ * Unfilter the image.
+ */
+
+ if(!UnfilterImage(DecompressedData, IHDR_Height, BytesPerScanline, BytesPerPixel))
+ {
+ return(qfalse);
+ }
+
+ /*
+ * Set the working pointers to the beginning of the buffers.
+ */
+
+ OutPtr = OutBuffer;
+ DecompPtr = DecompressedData;
+
+ /*
+ * Create the output image.
+ */
+
+ for(h = 0; h < IHDR_Height; h++)
+ {
+ /*
+ * Count the pixels on the scanline for those multipixel bytes
+ */
+
+ uint32_t CurrPixel;
+
+ /*
+ * skip FilterType
+ */
+
+ DecompPtr++;
+
+ /*
+ * Reset the pixel count.
+ */
+
+ CurrPixel = 0;
+
+ for(w = 0; w < (BytesPerScanline / BytesPerPixel); w++)
+ {
+ if(PixelsPerByte > 1)
+ {
+ uint8_t Mask;
+ uint32_t Shift;
+ uint8_t SinglePixel;
+
+ for(p = 0; p < PixelsPerByte; p++)
+ {
+ if(CurrPixel < IHDR_Width)
+ {
+ Mask = (1 << IHDR->BitDepth) - 1;
+ Shift = (PixelsPerByte - 1 - p) * IHDR->BitDepth;
+
+ SinglePixel = ((DecompPtr[0] & (Mask << Shift)) >> Shift);
+
+ if(!ConvertPixel(IHDR, OutPtr, &SinglePixel, HasTransparentColour, TransparentColour, OutPal))
+ {
+ return(qfalse);
+ }
+
+ OutPtr += Q3IMAGE_BYTESPERPIXEL;
+ CurrPixel++;
+ }
+ }
+
+ }
+ else
+ {
+ if(!ConvertPixel(IHDR, OutPtr, DecompPtr, HasTransparentColour, TransparentColour, OutPal))
+ {
+ return(qfalse);
+ }
+
+
+ OutPtr += Q3IMAGE_BYTESPERPIXEL;
+ }
+
+ DecompPtr += BytesPerPixel;
+ }
+ }
+
+ return(qtrue);
+}
+
+/*
+ * Decode an interlaced image.
+ */
+
+static qboolean DecodeImageInterlaced(struct PNG_Chunk_IHDR *IHDR,
+ byte *OutBuffer,
+ uint8_t *DecompressedData,
+ uint32_t DecompressedDataLength,
+ qboolean HasTransparentColour,
+ uint8_t *TransparentColour,
+ uint8_t *OutPal)
+{
+ uint32_t IHDR_Width;
+ uint32_t IHDR_Height;
+ uint32_t BytesPerScanline[PNG_Adam7_NumPasses], BytesPerPixel, PixelsPerByte;
+ uint32_t PassWidth[PNG_Adam7_NumPasses], PassHeight[PNG_Adam7_NumPasses];
+ uint32_t WSkip[PNG_Adam7_NumPasses], WOffset[PNG_Adam7_NumPasses], HSkip[PNG_Adam7_NumPasses], HOffset[PNG_Adam7_NumPasses];
+ uint32_t w, h, p, a;
+ byte *OutPtr;
+ uint8_t *DecompPtr;
+ uint32_t TargetLength;
+
+ /*
+ * input verification
+ */
+
+ if(!(IHDR && OutBuffer && DecompressedData && DecompressedDataLength && TransparentColour && OutPal))
+ {
+ return(qfalse);
+ }
+
+ /*
+ * byte swapping
+ */
+
+ IHDR_Width = BigLong(IHDR->Width);
+ IHDR_Height = BigLong(IHDR->Height);
+
+ /*
+ * Skip and Offset for the passes.
+ */
+
+ WSkip[0] = 8;
+ WOffset[0] = 0;
+ HSkip[0] = 8;
+ HOffset[0] = 0;
+
+ WSkip[1] = 8;
+ WOffset[1] = 4;
+ HSkip[1] = 8;
+ HOffset[1] = 0;
+
+ WSkip[2] = 4;
+ WOffset[2] = 0;
+ HSkip[2] = 8;
+ HOffset[2] = 4;
+
+ WSkip[3] = 4;
+ WOffset[3] = 2;
+ HSkip[3] = 4;
+ HOffset[3] = 0;
+
+ WSkip[4] = 2;
+ WOffset[4] = 0;
+ HSkip[4] = 4;
+ HOffset[4] = 2;
+
+ WSkip[5] = 2;
+ WOffset[5] = 1;
+ HSkip[5] = 2;
+ HOffset[5] = 0;
+
+ WSkip[6] = 1;
+ WOffset[6] = 0;
+ HSkip[6] = 2;
+ HOffset[6] = 1;
+
+ /*
+ * Calculate the sizes of the passes.
+ */
+
+ PassWidth[0] = (IHDR_Width + 7) / 8;
+ PassHeight[0] = (IHDR_Height + 7) / 8;
+
+ PassWidth[1] = (IHDR_Width + 3) / 8;
+ PassHeight[1] = (IHDR_Height + 7) / 8;
+
+ PassWidth[2] = (IHDR_Width + 3) / 4;
+ PassHeight[2] = (IHDR_Height + 3) / 8;
+
+ PassWidth[3] = (IHDR_Width + 1) / 4;
+ PassHeight[3] = (IHDR_Height + 3) / 4;
+
+ PassWidth[4] = (IHDR_Width + 1) / 2;
+ PassHeight[4] = (IHDR_Height + 1) / 4;
+
+ PassWidth[5] = (IHDR_Width + 0) / 2;
+ PassHeight[5] = (IHDR_Height + 1) / 2;
+
+ PassWidth[6] = (IHDR_Width + 0) / 1;
+ PassHeight[6] = (IHDR_Height + 0) / 2;
+
+ /*
+ * information for un-filtering
+ */
+
+ switch(IHDR->ColourType)
+ {
+ case PNG_ColourType_Grey :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_1 :
+ case PNG_BitDepth_2 :
+ case PNG_BitDepth_4 :
+ {
+ BytesPerPixel = 1;
+ PixelsPerByte = 8 / IHDR->BitDepth;
+
+ break;
+ }
+
+ case PNG_BitDepth_8 :
+ case PNG_BitDepth_16 :
+ {
+ BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_Grey;
+ PixelsPerByte = 1;
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ case PNG_ColourType_True :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_8 :
+ case PNG_BitDepth_16 :
+ {
+ BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_True;
+ PixelsPerByte = 1;
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ case PNG_ColourType_Indexed :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_1 :
+ case PNG_BitDepth_2 :
+ case PNG_BitDepth_4 :
+ {
+ BytesPerPixel = 1;
+ PixelsPerByte = 8 / IHDR->BitDepth;
+
+ break;
+ }
+
+ case PNG_BitDepth_8 :
+ {
+ BytesPerPixel = PNG_NumColourComponents_Indexed;
+ PixelsPerByte = 1;
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ case PNG_ColourType_GreyAlpha :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_8 :
+ case PNG_BitDepth_16 :
+ {
+ BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_GreyAlpha;
+ PixelsPerByte = 1;
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ case PNG_ColourType_TrueAlpha :
+ {
+ switch(IHDR->BitDepth)
+ {
+ case PNG_BitDepth_8 :
+ case PNG_BitDepth_16 :
+ {
+ BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_TrueAlpha;
+ PixelsPerByte = 1;
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ break;
+ }
+
+ default :
+ {
+ return(qfalse);
+ }
+ }
+
+ /*
+ * Calculate the size of the scanlines per pass
+ */
+
+ for(a = 0; a < PNG_Adam7_NumPasses; a++)
+ {
+ BytesPerScanline[a] = (PassWidth[a] * BytesPerPixel + (PixelsPerByte - 1)) / PixelsPerByte;
+ }
+
+ /*
+ * Calculate the size of all passes
+ */
+
+ TargetLength = 0;
+
+ for(a = 0; a < PNG_Adam7_NumPasses; a++)
+ {
+ TargetLength += ((BytesPerScanline[a] + (BytesPerScanline[a] ? 1 : 0)) * PassHeight[a]);
+ }
+
+ /*
+ * Check if we have enough data for the whole image.
+ */
+
+ if(!(DecompressedDataLength == TargetLength))
+ {
+ return(qfalse);
+ }
+
+ /*
+ * Unfilter the image.
+ */
+
+ DecompPtr = DecompressedData;
+
+ for(a = 0; a < PNG_Adam7_NumPasses; a++)
+ {
+ if(!UnfilterImage(DecompPtr, PassHeight[a], BytesPerScanline[a], BytesPerPixel))
+ {
+ return(qfalse);
+ }
+
+ DecompPtr += ((BytesPerScanline[a] + (BytesPerScanline[a] ? 1 : 0)) * PassHeight[a]);
+ }
+
+ /*
+ * Set the working pointers to the beginning of the buffers.
+ */
+
+ DecompPtr = DecompressedData;
+
+ /*
+ * Create the output image.
+ */
+
+ for(a = 0; a < PNG_Adam7_NumPasses; a++)
+ {
+ for(h = 0; h < PassHeight[a]; h++)
+ {
+ /*
+ * Count the pixels on the scanline for those multipixel bytes
+ */
+
+ uint32_t CurrPixel;
+
+ /*
+ * skip FilterType
+ * but only when the pass has a width bigger than zero
+ */
+
+ if(BytesPerScanline[a])
+ {
+ DecompPtr++;
+ }
+
+ /*
+ * Reset the pixel count.
+ */
+
+ CurrPixel = 0;
+
+ for(w = 0; w < (BytesPerScanline[a] / BytesPerPixel); w++)
+ {
+ if(PixelsPerByte > 1)
+ {
+ uint8_t Mask;
+ uint32_t Shift;
+ uint8_t SinglePixel;
+
+ for(p = 0; p < PixelsPerByte; p++)
+ {
+ if(CurrPixel < PassWidth[a])
+ {
+ Mask = (1 << IHDR->BitDepth) - 1;
+ Shift = (PixelsPerByte - 1 - p) * IHDR->BitDepth;
+
+ SinglePixel = ((DecompPtr[0] & (Mask << Shift)) >> Shift);
+
+ OutPtr = OutBuffer + (((((h * HSkip[a]) + HOffset[a]) * IHDR_Width) + ((CurrPixel * WSkip[a]) + WOffset[a])) * Q3IMAGE_BYTESPERPIXEL);
+
+ if(!ConvertPixel(IHDR, OutPtr, &SinglePixel, HasTransparentColour, TransparentColour, OutPal))
+ {
+ return(qfalse);
+ }
+
+ CurrPixel++;
+ }
+ }
+
+ }
+ else
+ {
+ OutPtr = OutBuffer + (((((h * HSkip[a]) + HOffset[a]) * IHDR_Width) + ((w * WSkip[a]) + WOffset[a])) * Q3IMAGE_BYTESPERPIXEL);
+
+ if(!ConvertPixel(IHDR, OutPtr, DecompPtr, HasTransparentColour, TransparentColour, OutPal))
+ {
+ return(qfalse);
+ }
+ }
+
+ DecompPtr += BytesPerPixel;
+ }
+ }
+ }
+
+ return(qtrue);
+}
+
+/*
+ * The PNG loader
+ */
+
+void R_LoadPNG(const char *name, byte **pic, int *width, int *height)
+{
+ struct BufferedFile *ThePNG;
+ byte *OutBuffer;
+ uint8_t *Signature;
+ struct PNG_ChunkHeader *CH;
+ uint32_t ChunkHeaderLength;
+ uint32_t ChunkHeaderType;
+ struct PNG_Chunk_IHDR *IHDR;
+ uint32_t IHDR_Width;
+ uint32_t IHDR_Height;
+ PNG_ChunkCRC *CRC;
+ uint8_t *InPal;
+ uint8_t *DecompressedData;
+ uint32_t DecompressedDataLength;
+ uint32_t i;
+
+ /*
+ * palette with 256 RGBA entries
+ */
+
+ uint8_t OutPal[1024];
+
+ /*
+ * transparent colour from the tRNS chunk
+ */
+
+ qboolean HasTransparentColour = qfalse;
+ uint8_t TransparentColour[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+ /*
+ * input verification
+ */
+
+ if(!(name && pic))
+ {
+ return;
+ }
+
+ /*
+ * Zero out return values.
+ */
+
+ *pic = NULL;
+
+ if(width)
+ {
+ *width = 0;
+ }
+
+ if(height)
+ {
+ *height = 0;
+ }
+
+ /*
+ * Read the file.
+ */
+
+ ThePNG = ReadBufferedFile(name);
+ if(!ThePNG)
+ {
+ return;
+ }
+
+ /*
+ * Read the siganture of the file.
+ */
+
+ Signature = (uint8_t*)BufferedFileRead(ThePNG, PNG_Signature_Size);
+ if(!Signature)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Is it a PNG?
+ */
+
+ if(memcmp(Signature, PNG_Signature, PNG_Signature_Size))
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Read the first chunk-header.
+ */
+
+ CH = (struct PNG_ChunkHeader*)BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
+ if(!CH)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * PNG multi-byte types are in Big Endian
+ */
+
+ ChunkHeaderLength = BigLong(CH->Length);
+ ChunkHeaderType = BigLong(CH->Type);
+
+ /*
+ * Check if the first chunk is an IHDR.
+ */
+
+ if(!((ChunkHeaderType == PNG_ChunkType_IHDR) && (ChunkHeaderLength == PNG_Chunk_IHDR_Size)))
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Read the IHDR.
+ */
+
+ IHDR = (struct PNG_Chunk_IHDR*)BufferedFileRead(ThePNG, PNG_Chunk_IHDR_Size);
+ if(!IHDR)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Read the CRC for IHDR
+ */
+
+ CRC = (PNG_ChunkCRC*)BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
+ if(!CRC)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Here we could check the CRC if we wanted to.
+ */
+
+ /*
+ * multi-byte type swapping
+ */
+
+ IHDR_Width = BigLong(IHDR->Width);
+ IHDR_Height = BigLong(IHDR->Height);
+
+ /*
+ * Check if Width and Height are valid.
+ */
+
+ if(!((IHDR_Width > 0) && (IHDR_Height > 0))
+ || IHDR_Width > INT_MAX / Q3IMAGE_BYTESPERPIXEL / IHDR_Height)
+ {
+ CloseBufferedFile(ThePNG);
+
+ ri.Printf( PRINT_WARNING, "%s: invalid image size\n", name );
+
+ return;
+ }
+
+ /*
+ * Do we need to check if the dimensions of the image are valid for Quake3?
+ */
+
+ /*
+ * Check if CompressionMethod and FilterMethod are valid.
+ */
+
+ if(!((IHDR->CompressionMethod == PNG_CompressionMethod_0) && (IHDR->FilterMethod == PNG_FilterMethod_0)))
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Check if InterlaceMethod is valid.
+ */
+
+ if(!((IHDR->InterlaceMethod == PNG_InterlaceMethod_NonInterlaced) || (IHDR->InterlaceMethod == PNG_InterlaceMethod_Interlaced)))
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Read palette for an indexed image.
+ */
+
+ if(IHDR->ColourType == PNG_ColourType_Indexed)
+ {
+ /*
+ * We need the palette first.
+ */
+
+ if(!FindChunk(ThePNG, PNG_ChunkType_PLTE))
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Read the chunk-header.
+ */
+
+ CH = (struct PNG_ChunkHeader*)BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
+ if(!CH)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * PNG multi-byte types are in Big Endian
+ */
+
+ ChunkHeaderLength = BigLong(CH->Length);
+ ChunkHeaderType = BigLong(CH->Type);
+
+ /*
+ * Check if the chunk is a PLTE.
+ */
+
+ if(!(ChunkHeaderType == PNG_ChunkType_PLTE))
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Check if Length is divisible by 3
+ */
+
+ if(ChunkHeaderLength % 3)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Read the raw palette data
+ */
+
+ InPal = (uint8_t*)BufferedFileRead(ThePNG, ChunkHeaderLength);
+ if(!InPal)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Read the CRC for the palette
+ */
+
+ CRC = (PNG_ChunkCRC*)BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
+ if(!CRC)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Set some default values.
+ */
+
+ for(i = 0; i < 256; i++)
+ {
+ OutPal[i * Q3IMAGE_BYTESPERPIXEL + 0] = 0x00;
+ OutPal[i * Q3IMAGE_BYTESPERPIXEL + 1] = 0x00;
+ OutPal[i * Q3IMAGE_BYTESPERPIXEL + 2] = 0x00;
+ OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = 0xFF;
+ }
+
+ /*
+ * Convert to the Quake3 RGBA-format.
+ */
+
+ for(i = 0; i < (ChunkHeaderLength / 3); i++)
+ {
+ OutPal[i * Q3IMAGE_BYTESPERPIXEL + 0] = InPal[i*3+0];
+ OutPal[i * Q3IMAGE_BYTESPERPIXEL + 1] = InPal[i*3+1];
+ OutPal[i * Q3IMAGE_BYTESPERPIXEL + 2] = InPal[i*3+2];
+ OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = 0xFF;
+ }
+ }
+
+ /*
+ * transparency information is sometimes stored in a tRNS chunk
+ */
+
+ /*
+ * Let's see if there is a tRNS chunk
+ */
+
+ if(FindChunk(ThePNG, PNG_ChunkType_tRNS))
+ {
+ uint8_t *Trans;
+
+ /*
+ * Read the chunk-header.
+ */
+
+ CH = (struct PNG_ChunkHeader*)BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
+ if(!CH)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * PNG multi-byte types are in Big Endian
+ */
+
+ ChunkHeaderLength = BigLong(CH->Length);
+ ChunkHeaderType = BigLong(CH->Type);
+
+ /*
+ * Check if the chunk is a tRNS.
+ */
+
+ if(!(ChunkHeaderType == PNG_ChunkType_tRNS))
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Read the transparency information.
+ */
+
+ Trans = (uint8_t*)BufferedFileRead(ThePNG, ChunkHeaderLength);
+ if(!Trans)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Read the CRC.
+ */
+
+ CRC = (PNG_ChunkCRC*)BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
+ if(!CRC)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Only for Grey, True and Indexed ColourType should tRNS exist.
+ */
+
+ switch(IHDR->ColourType)
+ {
+ case PNG_ColourType_Grey :
+ {
+ if(ChunkHeaderLength != 2)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ HasTransparentColour = qtrue;
+
+ /*
+ * Grey can have one colour which is completely transparent.
+ * This colour is always stored in 16 bits.
+ */
+
+ TransparentColour[0] = Trans[0];
+ TransparentColour[1] = Trans[1];
+
+ break;
+ }
+
+ case PNG_ColourType_True :
+ {
+ if(ChunkHeaderLength != 6)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ HasTransparentColour = qtrue;
+
+ /*
+ * True can have one colour which is completely transparent.
+ * This colour is always stored in 16 bits.
+ */
+
+ TransparentColour[0] = Trans[0];
+ TransparentColour[1] = Trans[1];
+ TransparentColour[2] = Trans[2];
+ TransparentColour[3] = Trans[3];
+ TransparentColour[4] = Trans[4];
+ TransparentColour[5] = Trans[5];
+
+ break;
+ }
+
+ case PNG_ColourType_Indexed :
+ {
+ /*
+ * Maximum of 256 one byte transparency entries.
+ */
+
+ if(ChunkHeaderLength > 256)
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ HasTransparentColour = qtrue;
+
+ /*
+ * alpha values for palette entries
+ */
+
+ for(i = 0; i < ChunkHeaderLength; i++)
+ {
+ OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = Trans[i];
+ }
+
+ break;
+ }
+
+ /*
+ * All other ColourTypes should not have tRNS chunks
+ */
+
+ default :
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+ }
+ }
+
+ /*
+ * Rewind to the start of the file.
+ */
+
+ if(!BufferedFileRewind(ThePNG, -1))
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Skip the signature
+ */
+
+ if(!BufferedFileSkip(ThePNG, PNG_Signature_Size))
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Decompress all IDAT chunks
+ */
+
+ DecompressedDataLength = DecompressIDATs(ThePNG, &DecompressedData);
+ if(!(DecompressedDataLength && DecompressedData))
+ {
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Allocate output buffer.
+ */
+
+ OutBuffer = (byte*)ri.Malloc(IHDR_Width * IHDR_Height * Q3IMAGE_BYTESPERPIXEL);
+ if(!OutBuffer)
+ {
+ ri.Free(DecompressedData);
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ /*
+ * Interlaced and Non-interlaced images need to be handled differently.
+ */
+
+ switch(IHDR->InterlaceMethod)
+ {
+ case PNG_InterlaceMethod_NonInterlaced :
+ {
+ if(!DecodeImageNonInterlaced(IHDR, OutBuffer, DecompressedData, DecompressedDataLength, HasTransparentColour, TransparentColour, OutPal))
+ {
+ ri.Free(OutBuffer);
+ ri.Free(DecompressedData);
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ break;
+ }
+
+ case PNG_InterlaceMethod_Interlaced :
+ {
+ if(!DecodeImageInterlaced(IHDR, OutBuffer, DecompressedData, DecompressedDataLength, HasTransparentColour, TransparentColour, OutPal))
+ {
+ ri.Free(OutBuffer);
+ ri.Free(DecompressedData);
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+
+ break;
+ }
+
+ default :
+ {
+ ri.Free(OutBuffer);
+ ri.Free(DecompressedData);
+ CloseBufferedFile(ThePNG);
+
+ return;
+ }
+ }
+
+ /*
+ * update the pointer to the image data
+ */
+
+ *pic = OutBuffer;
+
+ /*
+ * Fill width and height.
+ */
+
+ if(width)
+ {
+ *width = IHDR_Width;
+ }
+
+ if(height)
+ {
+ *height = IHDR_Height;
+ }
+
+ /*
+ * DecompressedData is not needed anymore.
+ */
+
+ ri.Free(DecompressedData);
+
+ /*
+ * We have all data, so close the file.
+ */
+
+ CloseBufferedFile(ThePNG);
+}
diff --git a/src/renderercommon/tr_image_tga.cpp b/src/renderercommon/tr_image_tga.cpp
new file mode 100644
index 0000000..c7f587d
--- /dev/null
+++ b/src/renderercommon/tr_image_tga.cpp
@@ -0,0 +1,317 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_common.h"
+
+/*
+========================================================================
+
+TGA files are used for 24/32 bit images
+
+========================================================================
+*/
+
+typedef struct _TargaHeader {
+ unsigned char id_length, colormap_type, image_type;
+ unsigned short colormap_index, colormap_length;
+ unsigned char colormap_size;
+ unsigned short x_origin, y_origin, width, height;
+ unsigned char pixel_size, attributes;
+} TargaHeader;
+
+void R_LoadTGA ( const char *name, byte **pic, int *width, int *height)
+{
+ unsigned columns, rows, numPixels;
+ byte *pixbuf;
+ int row, column;
+ byte *buf_p;
+ byte *end;
+ union {
+ byte *b;
+ void *v;
+ } buffer;
+ TargaHeader targa_header;
+ byte *targa_rgba;
+ int length;
+
+ *pic = NULL;
+
+ if(width)
+ *width = 0;
+ if(height)
+ *height = 0;
+
+ //
+ // load the file
+ //
+ length = ri.FS_ReadFile ( ( char * ) name, &buffer.v);
+ if (!buffer.b || length < 0) {
+ return;
+ }
+
+ if(length < 18)
+ {
+ ri.Error( ERR_DROP, "LoadTGA: header too short (%s)", name );
+ }
+
+ buf_p = buffer.b;
+ end = buffer.b + length;
+
+ targa_header.id_length = buf_p[0];
+ targa_header.colormap_type = buf_p[1];
+ targa_header.image_type = buf_p[2];
+
+ memcpy(&targa_header.colormap_index, &buf_p[3], 2);
+ memcpy(&targa_header.colormap_length, &buf_p[5], 2);
+ targa_header.colormap_size = buf_p[7];
+ memcpy(&targa_header.x_origin, &buf_p[8], 2);
+ memcpy(&targa_header.y_origin, &buf_p[10], 2);
+ memcpy(&targa_header.width, &buf_p[12], 2);
+ memcpy(&targa_header.height, &buf_p[14], 2);
+ targa_header.pixel_size = buf_p[16];
+ targa_header.attributes = buf_p[17];
+
+ targa_header.colormap_index = LittleShort(targa_header.colormap_index);
+ targa_header.colormap_length = LittleShort(targa_header.colormap_length);
+ targa_header.x_origin = LittleShort(targa_header.x_origin);
+ targa_header.y_origin = LittleShort(targa_header.y_origin);
+ targa_header.width = LittleShort(targa_header.width);
+ targa_header.height = LittleShort(targa_header.height);
+
+ buf_p += 18;
+
+ if (targa_header.image_type!=2
+ && targa_header.image_type!=10
+ && targa_header.image_type != 3 )
+ {
+ ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported");
+ }
+
+ if ( targa_header.colormap_type != 0 )
+ {
+ ri.Error( ERR_DROP, "LoadTGA: colormaps not supported" );
+ }
+
+ if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
+ {
+ ri.Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)");
+ }
+
+ columns = targa_header.width;
+ rows = targa_header.height;
+ numPixels = columns * rows * 4;
+
+ if(!columns || !rows || numPixels > 0x7FFFFFFF || numPixels / columns / 4 != rows)
+ {
+ ri.Error (ERR_DROP, "LoadTGA: %s has an invalid image size", name);
+ }
+
+
+ targa_rgba = (byte*)ri.Malloc (numPixels);
+
+ if (targa_header.id_length != 0)
+ {
+ if (buf_p + targa_header.id_length > end)
+ ri.Error( ERR_DROP, "LoadTGA: header too short (%s)", name );
+
+ buf_p += targa_header.id_length; // skip TARGA image comment
+ }
+
+ if ( targa_header.image_type==2 || targa_header.image_type == 3 )
+ {
+ if(buf_p + columns*rows*targa_header.pixel_size/8 > end)
+ {
+ ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name);
+ }
+
+ // Uncompressed RGB or gray scale image
+ for(row=rows-1; row>=0; row--)
+ {
+ pixbuf = targa_rgba + row*columns*4;
+ for(column=0; column<columns; column++)
+ {
+ unsigned char red,green,blue,alphabyte;
+ switch (targa_header.pixel_size)
+ {
+
+ case 8:
+ blue = *buf_p++;
+ green = blue;
+ red = blue;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = 255;
+ break;
+
+ case 24:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = 255;
+ break;
+ case 32:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = alphabyte;
+ break;
+ default:
+ ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'", targa_header.pixel_size, name );
+ break;
+ }
+ }
+ }
+ }
+ else if (targa_header.image_type==10) { // Runlength encoded RGB images
+ unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
+
+ for(row=rows-1; row>=0; row--) {
+ pixbuf = targa_rgba + row*columns*4;
+ for(column=0; column<columns; ) {
+ if(buf_p + 1 > end)
+ ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name);
+ packetHeader= *buf_p++;
+ packetSize = 1 + (packetHeader & 0x7f);
+ if (packetHeader & 0x80) { // run-length packet
+ if(buf_p + targa_header.pixel_size/8 > end)
+ ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name);
+ switch (targa_header.pixel_size) {
+ case 24:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = 255;
+ break;
+ case 32:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = *buf_p++;
+ break;
+ default:
+ ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'", targa_header.pixel_size, name );
+ break;
+ }
+
+ for(j=0;j<packetSize;j++) {
+ *pixbuf++=red;
+ *pixbuf++=green;
+ *pixbuf++=blue;
+ *pixbuf++=alphabyte;
+ column++;
+ if (column==columns) { // run spans across rows
+ column=0;
+ if (row>0)
+ row--;
+ else
+ goto breakOut;
+ pixbuf = targa_rgba + row*columns*4;
+ }
+ }
+ }
+ else { // non run-length packet
+
+ if(buf_p + targa_header.pixel_size/8*packetSize > end)
+ ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name);
+ for(j=0;j<packetSize;j++) {
+ switch (targa_header.pixel_size) {
+ case 24:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = 255;
+ break;
+ case 32:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = alphabyte;
+ break;
+ default:
+ ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'", targa_header.pixel_size, name );
+ break;
+ }
+ column++;
+ if (column==columns) { // pixel packet run spans across rows
+ column=0;
+ if (row>0)
+ row--;
+ else
+ goto breakOut;
+ pixbuf = targa_rgba + row*columns*4;
+ }
+ }
+ }
+ }
+ breakOut:;
+ }
+ }
+
+#if 0
+ // TTimo: this is the chunk of code to ensure a behavior that meets TGA specs
+ // bit 5 set => top-down
+ if (targa_header.attributes & 0x20) {
+ unsigned char *flip = (unsigned char*)malloc (columns*4);
+ unsigned char *src, *dst;
+
+ for (row = 0; row < rows/2; row++) {
+ src = targa_rgba + row * 4 * columns;
+ dst = targa_rgba + (rows - row - 1) * 4 * columns;
+
+ memcpy (flip, src, columns*4);
+ memcpy (src, dst, columns*4);
+ memcpy (dst, flip, columns*4);
+ }
+ free (flip);
+ }
+#endif
+ // instead we just print a warning
+ if (targa_header.attributes & 0x20) {
+ ri.Printf( PRINT_WARNING, "WARNING: '%s' TGA file header declares top-down image, ignoring\n", name);
+ }
+
+ if (width)
+ *width = columns;
+ if (height)
+ *height = rows;
+
+ *pic = targa_rgba;
+
+ ri.FS_FreeFile (buffer.v);
+}
diff --git a/src/renderercommon/tr_noise.cpp b/src/renderercommon/tr_noise.cpp
new file mode 100644
index 0000000..b31016b
--- /dev/null
+++ b/src/renderercommon/tr_noise.cpp
@@ -0,0 +1,93 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_noise.c
+#include "tr_common.h"
+
+#define NOISE_SIZE 256
+#define NOISE_MASK ( NOISE_SIZE - 1 )
+
+#define VAL( a ) s_noise_perm[ ( a ) & ( NOISE_MASK )]
+#define INDEX( x, y, z, t ) VAL( x + VAL( y + VAL( z + VAL( t ) ) ) )
+
+static float s_noise_table[NOISE_SIZE];
+static int s_noise_perm[NOISE_SIZE];
+
+static float GetNoiseValue( int x, int y, int z, int t )
+{
+ int index = INDEX( ( int ) x, ( int ) y, ( int ) z, ( int ) t );
+
+ return s_noise_table[index];
+}
+
+void R_NoiseInit( void )
+{
+ int i;
+
+ for ( i = 0; i < NOISE_SIZE; i++ )
+ {
+ s_noise_table[i] = ( float ) ( ( ( rand() / ( float ) RAND_MAX ) * 2.0 - 1.0 ) );
+ s_noise_perm[i] = ( unsigned char ) ( rand() / ( float ) RAND_MAX * 255 );
+ }
+}
+
+float R_NoiseGet4f( float x, float y, float z, double t )
+{
+ int i;
+ int ix, iy, iz, it;
+ float fx, fy, fz, ft;
+ float front[4];
+ float back[4];
+ float fvalue, bvalue, value[2], finalvalue;
+
+ ix = ( int ) floor( x );
+ fx = x - ix;
+ iy = ( int ) floor( y );
+ fy = y - iy;
+ iz = ( int ) floor( z );
+ fz = z - iz;
+ it = ( int ) floor( t );
+ ft = t - it;
+
+ for ( i = 0; i < 2; i++ )
+ {
+ front[0] = GetNoiseValue( ix, iy, iz, it + i );
+ front[1] = GetNoiseValue( ix+1, iy, iz, it + i );
+ front[2] = GetNoiseValue( ix, iy+1, iz, it + i );
+ front[3] = GetNoiseValue( ix+1, iy+1, iz, it + i );
+
+ back[0] = GetNoiseValue( ix, iy, iz + 1, it + i );
+ back[1] = GetNoiseValue( ix+1, iy, iz + 1, it + i );
+ back[2] = GetNoiseValue( ix, iy+1, iz + 1, it + i );
+ back[3] = GetNoiseValue( ix+1, iy+1, iz + 1, it + i );
+
+ fvalue = LERP( LERP( front[0], front[1], fx ), LERP( front[2], front[3], fx ), fy );
+ bvalue = LERP( LERP( back[0], back[1], fx ), LERP( back[2], back[3], fx ), fy );
+
+ value[i] = LERP( fvalue, bvalue, fz );
+ }
+
+ finalvalue = LERP( value[0], value[1], ft );
+
+ return finalvalue;
+}
diff --git a/src/renderercommon/tr_public.h b/src/renderercommon/tr_public.h
new file mode 100644
index 0000000..9d926d0
--- /dev/null
+++ b/src/renderercommon/tr_public.h
@@ -0,0 +1,199 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#ifndef __TR_PUBLIC_H
+#define __TR_PUBLIC_H
+
+#include "renderercommon/tr_types.h"
+
+#define REF_API_VERSION 8
+
+// AVI files have the start of pixel lines 4 byte-aligned
+#define AVI_LINE_PADDING 4
+
+//
+// these are the functions exported by the refresh module
+//
+typedef struct {
+ // called before the library is unloaded
+ // if the system is just reconfiguring, pass destroyWindow = qfalse,
+ // which will keep the screen from flashing to the desktop.
+ void (*Shutdown)( bool destroyWindow );
+
+ // All data that will be used in a level should be
+ // registered before rendering any frames to prevent disk hits,
+ // but they can still be registered at a later time
+ // if necessary.
+ //
+ // BeginRegistration makes any existing media pointers invalid
+ // and returns the current gl configuration, including screen width
+ // and height, which can be used by the client to intelligently
+ // size display elements
+ void (*BeginRegistration)( glconfig_t *config );
+ qhandle_t (*RegisterModel)( const char *name );
+ qhandle_t (*RegisterSkin)( const char *name );
+ qhandle_t (*RegisterShader)( const char *name );
+ qhandle_t (*RegisterShaderNoMip)( const char *name );
+ void (*LoadWorld)( const char *name );
+
+ // the vis data is a large enough block of data that we go to the trouble
+ // of sharing it with the clipmodel subsystem
+ void (*SetWorldVisData)( const byte *vis );
+
+ // EndRegistration will draw a tiny polygon with each texture, forcing
+ // them to be loaded into card memory
+ void (*EndRegistration)( void );
+
+ // a scene is built up by calls to R_ClearScene and the various R_Add functions.
+ // Nothing is drawn until R_RenderScene is called.
+ void (*ClearScene)( void );
+ void (*AddRefEntityToScene)( const refEntity_t *re );
+ void (*AddPolyToScene)( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
+ bool (*LightForPoint)( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
+ void (*AddLightToScene)( const vec3_t org, float intensity, float r, float g, float b );
+ void (*AddAdditiveLightToScene)( const vec3_t org, float intensity, float r, float g, float b );
+ void (*RenderScene)( const refdef_t *fd );
+
+ void (*SetColor)( const float *rgba ); // NULL = 1,1,1,1
+ void (*SetClipRegion)( const float *region );
+ void (*DrawStretchPic) ( float x, float y, float w, float h,
+ float s1, float t1, float s2, float t2, qhandle_t hShader ); // 0 = white
+
+ // Draw images for cinematic rendering, pass as 32 bit rgba
+ void (*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, bool dirty);
+ void (*UploadCinematic) (int w, int h, int cols, int rows, const byte *data, int client, bool dirty);
+
+ void (*BeginFrame)( stereoFrame_t stereoFrame );
+
+ // if the pointers are not NULL, timing info will be returned
+ void (*EndFrame)( int *frontEndMsec, int *backEndMsec );
+
+
+ int (*MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection,
+ int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
+
+ int (*LerpTag)( orientation_t *tag, qhandle_t model, int startFrame, int endFrame,
+ float frac, const char *tagName );
+ void (*ModelBounds)( qhandle_t model, vec3_t mins, vec3_t maxs );
+
+#ifdef __USEA3D
+ void (*A3D_RenderGeometry) (void *pVoidA3D, void *pVoidGeom, void *pVoidMat, void *pVoidGeomStatus);
+#endif
+ void (*RegisterFont)(const char *fontName, int pointSize, fontInfo_t *font);
+ void (*RemapShader)(const char *oldShader, const char *newShader, const char *offsetTime);
+ bool (*GetEntityToken)( char *buffer, int size );
+ bool (*inPVS)( const vec3_t p1, const vec3_t p2 );
+
+ void (*TakeVideoFrame)( int h, int w, byte* captureBuffer, byte *encodeBuffer, bool motionJpeg );
+} refexport_t;
+
+//
+// these are the functions imported by the refresh module
+//
+typedef struct {
+ // print message on the local console
+ void (QDECL *Printf)( int printLevel, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ // abort the game
+ void (QDECL *Error)( int errorLevel, const char *fmt, ...) __attribute__ ((noreturn, format (printf, 2, 3)));
+
+ // milliseconds should only be used for profiling, never
+ // for anything game related. Get time from the refdef
+ int (*Milliseconds)( void );
+
+ // stack based memory allocation for per-level things that
+ // won't be freed
+#ifdef HUNK_DEBUG
+ void *(*Hunk_AllocDebug)( int size, ha_pref pref, const char *label, const char *file, int line );
+#else
+ void *(*Hunk_Alloc)( int size, ha_pref pref );
+#endif
+ void *(*Hunk_AllocateTempMemory)( int size );
+ void (*Hunk_FreeTempMemory)( void *block );
+
+ // dynamic memory allocator for things that need to be freed
+ void *(*Malloc)( int bytes );
+ void (*Free)( void *buf );
+
+ cvar_t *(*Cvar_Get)( const char *name, const char *value, int flags );
+ void (*Cvar_Set)( const char *name, const char *value );
+ void (*Cvar_SetValue) (const char *name, float value);
+ void (*Cvar_CheckRange)( cvar_t *cv, float minVal, float maxVal, bool shouldBeIntegral );
+ void (*Cvar_SetDescription)( cvar_t *cv, const char *description );
+
+ int (*Cvar_VariableIntegerValue) (const char *var_name);
+
+ void (*Cmd_AddCommand)( const char *name, void(*cmd)(void) );
+ void (*Cmd_RemoveCommand)( const char *name );
+
+ int (*Cmd_Argc) (void);
+ const char* (*Cmd_Argv) (int i);
+
+ void (*Cmd_ExecuteText) (int exec_when, const char *text);
+
+ byte *(*CM_ClusterPVS)(int cluster);
+
+ // visualization for debugging collision detection
+ void (*CM_DrawDebugSurface)( void (*drawPoly)(int color, int numPoints, float *points) );
+
+ // a -1 return means the file does not exist
+ // NULL can be passed for buf to just determine existance
+ int (*FS_FileIsInPAK)( const char *name, int *pCheckSum );
+ long (*FS_ReadFile)( const char *name, void **buf );
+ void (*FS_FreeFile)( void *buf );
+ char ** (*FS_ListFiles)( const char *name, const char *extension, int *numfilesfound );
+ void (*FS_FreeFileList)( char **filelist );
+ void (*FS_WriteFile)( const char *qpath, const void *buffer, int size );
+ bool (*FS_FileExists)( const char *file );
+
+ // cinematic stuff
+ void (*CIN_UploadCinematic)(int handle);
+ int (*CIN_PlayCinematic)( const char *arg0, int xpos, int ypos, int width, int height, int bits);
+ e_status (*CIN_RunCinematic) (int handle);
+
+ void (*CL_WriteAVIVideoFrame)( const byte *buffer, int size );
+
+ // input event handling
+ void (*IN_Init)( void *windowData );
+ void (*IN_Shutdown)( void );
+ void (*IN_Restart)( void );
+
+ // system stuff
+ void (*Sys_GLimpSafeInit)( void );
+ void (*Sys_GLimpInit)( void );
+ bool (*Sys_LowPhysicalMemory)( void );
+} refimport_t;
+
+
+// this is the only function actually exported at the linker level
+// If the module can't init to a valid rendering state, NULL will be
+// returned.
+#ifdef USE_RENDERER_DLOPEN
+extern "C" {
+typedef refexport_t* (QDECL *GetRefAPI_t) (int apiVersion, refimport_t * rimp);
+}
+#else
+refexport_t* GetRefAPI( int apiVersion, refimport_t *rimp );
+#endif
+
+#endif // __TR_PUBLIC_H
diff --git a/src/renderer/tr_types.h b/src/renderercommon/tr_types.h
index 6db8c12..67f3733 100644
--- a/src/renderer/tr_types.h
+++ b/src/renderercommon/tr_types.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,36 +17,48 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
-//
+
#ifndef __TR_TYPES_H
#define __TR_TYPES_H
+#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces
-#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces
-#define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing
+#define REFENTITYNUM_BITS 10 // can't be increased without changing drawsurf bit packing
+#define REFENTITYNUM_MASK ((1<<REFENTITYNUM_BITS) - 1)
+// the last N-bit number (2^REFENTITYNUM_BITS - 1) is reserved for the special world refentity,
+// and this is reflected by the value of MAX_REFENTITIES (which therefore is not a power-of-2)
+#define MAX_REFENTITIES ((1<<REFENTITYNUM_BITS) - 1)
+#define REFENTITYNUM_WORLD ((1<<REFENTITYNUM_BITS) - 1)
// renderfx flags
-#define RF_MINLIGHT 1 // allways have some light (viewmodel, some items)
-#define RF_THIRD_PERSON 2 // don't draw through eyes, only mirrors (player bodies, chat sprites)
-#define RF_FIRST_PERSON 4 // only draw through eyes (view weapon, damage blood blob)
-#define RF_DEPTHHACK 8 // for view weapon Z crunching
-#define RF_NOSHADOW 64 // don't add stencil shadows
-
-#define RF_LIGHTING_ORIGIN 128 // use refEntity->lightingOrigin instead of refEntity->origin
- // for lighting. This allows entities to sink into the floor
- // with their origin going solid, and allows all parts of a
- // player to get the same lighting
-#define RF_SHADOW_PLANE 256 // use refEntity->shadowPlane
-#define RF_WRAP_FRAMES 512 // mod the model frames by the maxframes to allow continuous
- // animation without needing to know the frame count
+#define RF_MINLIGHT 0x0001 // allways have some light (viewmodel, some items)
+#define RF_THIRD_PERSON 0x0002 // don't draw through eyes, only mirrors (player bodies, chat sprites)
+#define RF_FIRST_PERSON 0x0004 // only draw through eyes (view weapon, damage blood blob)
+#define RF_DEPTHHACK 0x0008 // for view weapon Z crunching
+
+#define RF_CROSSHAIR 0x0010 // This item is a cross hair and will draw over everything similar to
+ // DEPTHHACK in stereo rendering mode, with the difference that the
+ // projection matrix won't be hacked to reduce the stereo separation as
+ // is done for the gun.
+
+#define RF_NOSHADOW 0x0040 // don't add stencil shadows
+
+#define RF_LIGHTING_ORIGIN 0x0080 // use refEntity->lightingOrigin instead of refEntity->origin
+ // for lighting. This allows entities to sink into the floor
+ // with their origin going solid, and allows all parts of a
+ // player to get the same lighting
+
+#define RF_SHADOW_PLANE 0x0100 // use refEntity->shadowPlane
+#define RF_WRAP_FRAMES 0x0200 // mod the model frames by the maxframes to allow continuous
+ // animation without needing to know the frame count
// refdef flags
-#define RDF_NOWORLDMODEL 1 // used for player configuration screen
-#define RDF_HYPERSPACE 4 // teleportation effect
+#define RDF_NOWORLDMODEL 0x0001 // used for player configuration screen
+#define RDF_HYPERSPACE 0x0004 // teleportation effect
typedef struct {
vec3_t xyz;
@@ -146,7 +159,8 @@ typedef enum {
*/
typedef enum {
TC_NONE,
- TC_S3TC
+ TC_S3TC, // this is for the GL_S3_s3tc extension.
+ TC_S3TC_ARB // this is for the GL_EXT_texture_compression_s3tc extension.
} textureCompression_t;
typedef enum {
@@ -176,7 +190,7 @@ typedef struct {
char extensions_string[BIG_INFO_STRING];
int maxTextureSize; // queried from GL
- int maxActiveTextures; // multitexture ability
+ int numTextureUnits; // multitexture ability
int colorBits, depthBits, stencilBits;
@@ -184,7 +198,7 @@ typedef struct {
glHardwareType_t hardwareType;
qboolean deviceSupportsGamma;
- textureCompression_t textureCompression;
+ int/*textureCompression_t*/ textureCompression;
qboolean textureEnvAddAvailable;
int vidWidth, vidHeight;
@@ -192,6 +206,7 @@ typedef struct {
// than scrWidth / scrHeight if the pixels are non-square
// normal screens should be 4/3, but wide aspect monitors may be 16/9
float windowAspect;
+ float displayAspect;
int displayFrequency;
@@ -200,35 +215,8 @@ typedef struct {
// used CDS.
qboolean isFullscreen;
qboolean stereoEnabled;
- qboolean smpActive; // dual processor
-
qboolean textureFilterAnisotropic;
int maxAnisotropy;
-
} glconfig_t;
-// FIXME: VM should be OS agnostic .. in theory
-
-/*
-#ifdef Q3_VM
-
-#define _3DFX_DRIVER_NAME "Voodoo"
-#define OPENGL_DRIVER_NAME "Default"
-
-#elif defined(_WIN32)
-*/
-
-#if defined(Q3_VM) || defined(_WIN32)
-
-#define _3DFX_DRIVER_NAME "3dfxvgl"
-#define OPENGL_DRIVER_NAME "opengl32"
-
-#else
-
-#define _3DFX_DRIVER_NAME "libMesaVoodooGL.so"
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=524
-#define OPENGL_DRIVER_NAME "libGL.so.1"
-
-#endif // !defined _WIN32
-
#endif // __TR_TYPES_H
diff --git a/src/renderergl1/CMakeLists.txt b/src/renderergl1/CMakeLists.txt
new file mode 100644
index 0000000..2e28420
--- /dev/null
+++ b/src/renderergl1/CMakeLists.txt
@@ -0,0 +1,67 @@
+include("${CMAKE_SOURCE_DIR}/cmake/SDL2.cmake")
+
+find_package(OpenGL)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../jpeg-8c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../renderercommon
+ ${SDL2_INCLUDE_DIRS}
+ )
+
+set(renderergl1_SRCS
+ tr_animation.cpp
+ tr_backend.cpp
+ tr_bsp.cpp
+ tr_cmds.cpp
+ tr_curve.cpp
+ tr_flares.cpp
+ tr_image.cpp
+ tr_init.cpp
+ tr_light.cpp
+ tr_local.h
+ tr_main.cpp
+ tr_marks.cpp
+ tr_mesh.cpp
+ tr_model.cpp
+ tr_model_iqm.cpp
+ tr_scene.cpp
+ tr_shade.cpp
+ tr_shade_calc.cpp
+ tr_shader.cpp
+ tr_shadows.cpp
+ tr_sky.cpp
+ tr_subs.cpp
+ tr_surface.cpp
+ tr_world.cpp
+ tr_local.h
+ ${CMAKE_SOURCE_DIR}/src/common/puff.cpp
+ ${CMAKE_SOURCE_DIR}/src/common/q_shared.c
+ ${CMAKE_SOURCE_DIR}/src/common/q_math.c
+ )
+
+if(NOT USE_RENDERER_DLOPEN)
+ add_library(
+ renderergl1 STATIC
+ ${renderergl1_SRCS}
+ )
+
+ target_link_libraries(
+ renderergl1 renderercommon
+ ${SDL2_LIBRARIES}
+ )
+else(NOT USE_RENDERER_DLOPEN)
+ add_library(
+ renderergl1 SHARED
+ ${renderergl1_SRCS}
+ )
+ target_link_libraries(
+ renderergl1
+ renderercommon
+ ${FRAMEWORKS}
+ ${OPENGL_LIBRARIES}
+ ${SDL2_LIBRARIES}
+ )
+
+endif(NOT USE_RENDERER_DLOPEN)
+
+
diff --git a/src/renderergl1/tr_animation.cpp b/src/renderergl1/tr_animation.cpp
new file mode 100644
index 0000000..c496cfd
--- /dev/null
+++ b/src/renderergl1/tr_animation.cpp
@@ -0,0 +1,523 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+/*
+
+All bones should be an identity orientation to display the mesh exactly
+as it is specified.
+
+For all other frames, the bones represent the transformation from the
+orientation of the bone in the base frame to the orientation in this
+frame.
+
+*/
+
+
+// copied and adapted from tr_mesh.c
+
+/*
+=============
+R_MDRCullModel
+=============
+*/
+
+static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) {
+ vec3_t bounds[2];
+ mdrFrame_t *oldFrame, *newFrame;
+ int i, frameSize;
+
+ frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
+
+ // compute frame pointers
+ newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
+ oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe);
+
+ // cull bounding sphere ONLY if this is not an upscaled entity
+ if ( !ent->e.nonNormalizedAxes )
+ {
+ if ( ent->e.frame == ent->e.oldframe )
+ {
+ switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
+ {
+ // Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend
+ // we do. After all, the purpose of mdrs are not that different, are they?
+
+ case CULL_OUT:
+ tr.pc.c_sphere_cull_md3_out++;
+ return CULL_OUT;
+
+ case CULL_IN:
+ tr.pc.c_sphere_cull_md3_in++;
+ return CULL_IN;
+
+ case CULL_CLIP:
+ tr.pc.c_sphere_cull_md3_clip++;
+ break;
+ }
+ }
+ else
+ {
+ int sphereCull, sphereCullB;
+
+ sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
+ if ( newFrame == oldFrame ) {
+ sphereCullB = sphereCull;
+ } else {
+ sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
+ }
+
+ if ( sphereCull == sphereCullB )
+ {
+ if ( sphereCull == CULL_OUT )
+ {
+ tr.pc.c_sphere_cull_md3_out++;
+ return CULL_OUT;
+ }
+ else if ( sphereCull == CULL_IN )
+ {
+ tr.pc.c_sphere_cull_md3_in++;
+ return CULL_IN;
+ }
+ else
+ {
+ tr.pc.c_sphere_cull_md3_clip++;
+ }
+ }
+ }
+ }
+
+ // calculate a bounding box in the current coordinate system
+ for (i = 0 ; i < 3 ; i++) {
+ bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
+ bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
+ }
+
+ switch ( R_CullLocalBox( bounds ) )
+ {
+ case CULL_IN:
+ tr.pc.c_box_cull_md3_in++;
+ return CULL_IN;
+ case CULL_CLIP:
+ tr.pc.c_box_cull_md3_clip++;
+ return CULL_CLIP;
+ case CULL_OUT:
+ default:
+ tr.pc.c_box_cull_md3_out++;
+ return CULL_OUT;
+ }
+}
+
+/*
+=================
+R_MDRComputeFogNum
+
+=================
+*/
+
+int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent ) {
+ int i, j;
+ fog_t *fog;
+ mdrFrame_t *mdrFrame;
+ vec3_t localOrigin;
+ int frameSize;
+
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ return 0;
+ }
+
+ frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
+
+ // FIXME: non-normalized axis issues
+ mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
+ VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin );
+ for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
+ fog = &tr.world->fogs[i];
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] ) {
+ break;
+ }
+ if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] ) {
+ break;
+ }
+ }
+ if ( j == 3 ) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+==============
+R_MDRAddAnimSurfaces
+==============
+*/
+
+// much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c
+
+void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
+ mdrHeader_t *header;
+ mdrSurface_t *surface;
+ mdrLOD_t *lod;
+ shader_t *shader;
+ skin_t *skin;
+ int i, j;
+ int lodnum = 0;
+ int fogNum = 0;
+ int cull;
+ bool personalModel;
+
+ header = (mdrHeader_t *) tr.currentModel->modelData;
+
+ personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
+
+ if ( ent->e.renderfx & RF_WRAP_FRAMES )
+ {
+ ent->e.frame %= header->numFrames;
+ ent->e.oldframe %= header->numFrames;
+ }
+
+ //
+ // Validate the frames so there is no chance of a crash.
+ // This will write directly into the entity structure, so
+ // when the surfaces are rendered, they don't need to be
+ // range checked again.
+ //
+ if ((ent->e.frame >= header->numFrames)
+ || (ent->e.frame < 0)
+ || (ent->e.oldframe >= header->numFrames)
+ || (ent->e.oldframe < 0) )
+ {
+ ri.Printf( PRINT_DEVELOPER, "R_MDRAddAnimSurfaces: no such frame %d to %d for '%s'\n",
+ ent->e.oldframe, ent->e.frame, tr.currentModel->name );
+ ent->e.frame = 0;
+ ent->e.oldframe = 0;
+ }
+
+ //
+ // cull the entire model if merged bounding box of both frames
+ // is outside the view frustum.
+ //
+ cull = R_MDRCullModel (header, ent);
+ if ( cull == CULL_OUT ) {
+ return;
+ }
+
+ // figure out the current LOD of the model we're rendering, and set the lod pointer respectively.
+ lodnum = R_ComputeLOD(ent);
+ // check whether this model has as that many LODs at all. If not, try the closest thing we got.
+ if(header->numLODs <= 0)
+ return;
+ if(header->numLODs <= lodnum)
+ lodnum = header->numLODs - 1;
+
+ lod = (mdrLOD_t *)( (byte *)header + header->ofsLODs);
+ for(i = 0; i < lodnum; i++)
+ {
+ lod = (mdrLOD_t *) ((byte *) lod + lod->ofsEnd);
+ }
+
+ // set up lighting
+ if ( !personalModel || r_shadows->integer > 1 )
+ {
+ R_SetupEntityLighting( &tr.refdef, ent );
+ }
+
+ // fogNum?
+ fogNum = R_MDRComputeFogNum( header, ent );
+
+ surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces );
+
+ for ( i = 0 ; i < lod->numSurfaces ; i++ )
+ {
+
+ if(ent->e.customShader)
+ shader = R_GetShaderByHandle(ent->e.customShader);
+ else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins)
+ {
+ skin = R_GetSkinByHandle(ent->e.customSkin);
+ shader = tr.defaultShader;
+
+ for(j = 0; j < skin->numSurfaces; j++)
+ {
+ if (!strcmp(skin->surfaces[j].name, surface->name))
+ {
+ shader = skin->surfaces[j].shader;
+ break;
+ }
+ }
+ }
+ else if(surface->shaderIndex > 0)
+ shader = R_GetShaderByHandle( surface->shaderIndex );
+ else
+ shader = tr.defaultShader;
+
+ // we will add shadows even if the main object isn't visible in the view
+
+ // stencil shadows can't do personal models unless I polyhedron clip
+ if ( !personalModel
+ && r_shadows->integer == 2
+ && fogNum == 0
+ && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
+ && shader->sort == SS_OPAQUE )
+ {
+ R_AddDrawSurf( (surfaceType_t*)surface, tr.shadowShader, 0, qfalse );
+ }
+
+ // projection shadows work fine with personal models
+ if ( r_shadows->integer == 3
+ && fogNum == 0
+ && (ent->e.renderfx & RF_SHADOW_PLANE )
+ && shader->sort == SS_OPAQUE )
+ {
+ R_AddDrawSurf( (surfaceType_t*)surface, tr.projectionShadowShader, 0, qfalse );
+ }
+
+ if (!personalModel)
+ R_AddDrawSurf( (surfaceType_t*)surface, shader, fogNum, qfalse );
+
+ surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
+ }
+}
+
+/*
+==============
+RB_MDRSurfaceAnim
+==============
+*/
+void RB_MDRSurfaceAnim( mdrSurface_t *surface )
+{
+ int i, j, k;
+ float frontlerp, backlerp;
+ int *triangles;
+ int indexes;
+ int baseIndex, baseVertex;
+ int numVerts;
+ mdrVertex_t *v;
+ mdrHeader_t *header;
+ mdrFrame_t *frame;
+ mdrFrame_t *oldFrame;
+ mdrBone_t bones[MDR_MAX_BONES], *bonePtr, *bone;
+
+ int frameSize;
+
+ // don't lerp if lerping off, or this is the only frame, or the last frame...
+ //
+ if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame)
+ {
+ backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used
+ frontlerp = 1;
+ }
+ else
+ {
+ backlerp = backEnd.currentEntity->e.backlerp;
+ frontlerp = 1.0f - backlerp;
+ }
+
+ header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader);
+
+ frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
+
+ frame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
+ backEnd.currentEntity->e.frame * frameSize );
+ oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
+ backEnd.currentEntity->e.oldframe * frameSize );
+
+ RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles * 3 );
+
+ triangles = (int *) ((byte *)surface + surface->ofsTriangles);
+ indexes = surface->numTriangles * 3;
+ baseIndex = tess.numIndexes;
+ baseVertex = tess.numVertexes;
+
+ // Set up all triangles.
+ for (j = 0 ; j < indexes ; j++)
+ {
+ tess.indexes[baseIndex + j] = baseVertex + triangles[j];
+ }
+ tess.numIndexes += indexes;
+
+ //
+ // lerp all the needed bones
+ //
+ if ( !backlerp )
+ {
+ // no lerping needed
+ bonePtr = frame->bones;
+ }
+ else
+ {
+ bonePtr = bones;
+
+ for ( i = 0 ; i < header->numBones*12 ; i++ )
+ {
+ ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i];
+ }
+ }
+
+ //
+ // deform the vertexes by the lerped bones
+ //
+ numVerts = surface->numVerts;
+ v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts);
+ for ( j = 0; j < numVerts; j++ )
+ {
+ vec3_t tempVert, tempNormal;
+ mdrWeight_t *w;
+
+ VectorClear( tempVert );
+ VectorClear( tempNormal );
+ w = v->weights;
+ for ( k = 0 ; k < v->numWeights ; k++, w++ )
+ {
+ bone = bonePtr + w->boneIndex;
+
+ tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] );
+ tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] );
+ tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] );
+
+ tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal );
+ tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal );
+ tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal );
+ }
+
+ tess.xyz[baseVertex + j][0] = tempVert[0];
+ tess.xyz[baseVertex + j][1] = tempVert[1];
+ tess.xyz[baseVertex + j][2] = tempVert[2];
+
+ tess.normal[baseVertex + j][0] = tempNormal[0];
+ tess.normal[baseVertex + j][1] = tempNormal[1];
+ tess.normal[baseVertex + j][2] = tempNormal[2];
+
+ tess.texCoords[baseVertex + j][0][0] = v->texCoords[0];
+ tess.texCoords[baseVertex + j][0][1] = v->texCoords[1];
+
+ v = (mdrVertex_t *)&v->weights[v->numWeights];
+ }
+
+ tess.numVertexes += surface->numVerts;
+}
+
+
+#define MC_MASK_X ((1<<(MC_BITS_X))-1)
+#define MC_MASK_Y ((1<<(MC_BITS_Y))-1)
+#define MC_MASK_Z ((1<<(MC_BITS_Z))-1)
+#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1)
+
+#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2))
+
+#define MC_POS_X (0)
+#define MC_SHIFT_X (0)
+
+#define MC_POS_Y ((((MC_BITS_X))/8))
+#define MC_SHIFT_Y ((((MC_BITS_X)%8)))
+
+#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8))
+#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8)))
+
+#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8))
+#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8)))
+
+#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8))
+#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8)))
+
+#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8))
+#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8)))
+
+#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8))
+#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8)))
+
+#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8))
+#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8)))
+
+#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8))
+#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8)))
+
+#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8))
+#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8)))
+
+#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8))
+#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8)))
+
+#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8))
+#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8)))
+
+void MC_UnCompress(float mat[3][4],const unsigned char * comp)
+{
+ int val;
+
+ val=(int)((unsigned short *)(comp))[0];
+ val-=1<<(MC_BITS_X-1);
+ mat[0][3]=((float)(val))*MC_SCALE_X;
+
+ val=(int)((unsigned short *)(comp))[1];
+ val-=1<<(MC_BITS_Y-1);
+ mat[1][3]=((float)(val))*MC_SCALE_Y;
+
+ val=(int)((unsigned short *)(comp))[2];
+ val-=1<<(MC_BITS_Z-1);
+ mat[2][3]=((float)(val))*MC_SCALE_Z;
+
+ val=(int)((unsigned short *)(comp))[3];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[0][0]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[4];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[0][1]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[5];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[0][2]=((float)(val))*MC_SCALE_VECT;
+
+
+ val=(int)((unsigned short *)(comp))[6];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[1][0]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[7];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[1][1]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[8];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[1][2]=((float)(val))*MC_SCALE_VECT;
+
+
+ val=(int)((unsigned short *)(comp))[9];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[2][0]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[10];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[2][1]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[11];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[2][2]=((float)(val))*MC_SCALE_VECT;
+}
diff --git a/src/renderergl1/tr_backend.cpp b/src/renderergl1/tr_backend.cpp
new file mode 100644
index 0000000..172228d
--- /dev/null
+++ b/src/renderergl1/tr_backend.cpp
@@ -0,0 +1,1163 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "tr_local.h"
+
+backEndData_t *backEndData;
+backEndState_t backEnd;
+
+
+static float s_flipMatrix[16] = {
+ // convert from our coordinate system (looking down X)
+ // to OpenGL's coordinate system (looking down -Z)
+ 0, 0, -1, 0,
+ -1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 0, 1
+};
+
+
+/*
+** GL_Bind
+*/
+void GL_Bind( image_t *image ) {
+ int texnum;
+
+ if ( !image ) {
+ ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" );
+ texnum = tr.defaultImage->texnum;
+ } else {
+ texnum = image->texnum;
+ }
+
+ if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option
+ texnum = tr.dlightImage->texnum;
+ }
+
+ if ( glState.currenttextures[glState.currenttmu] != texnum ) {
+ if ( image ) {
+ image->frameUsed = tr.frameCount;
+ }
+ glState.currenttextures[glState.currenttmu] = texnum;
+ qglBindTexture (GL_TEXTURE_2D, texnum);
+ }
+}
+
+/*
+** GL_SelectTexture
+*/
+void GL_SelectTexture( int unit )
+{
+ if ( glState.currenttmu == unit )
+ {
+ return;
+ }
+
+ if ( unit == 0 )
+ {
+ qglActiveTextureARB( GL_TEXTURE0_ARB );
+ GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE0_ARB )\n" );
+ qglClientActiveTextureARB( GL_TEXTURE0_ARB );
+ GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE0_ARB )\n" );
+ }
+ else if ( unit == 1 )
+ {
+ qglActiveTextureARB( GL_TEXTURE1_ARB );
+ GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE1_ARB )\n" );
+ qglClientActiveTextureARB( GL_TEXTURE1_ARB );
+ GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE1_ARB )\n" );
+ } else {
+ ri.Error( ERR_DROP, "GL_SelectTexture: unit = %i", unit );
+ }
+
+ glState.currenttmu = unit;
+}
+
+
+/*
+** GL_BindMultitexture
+*/
+void GL_BindMultitexture( image_t *image0, GLuint env0, image_t *image1, GLuint env1 ) {
+ int texnum0, texnum1;
+
+ texnum0 = image0->texnum;
+ texnum1 = image1->texnum;
+
+ if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option
+ texnum0 = texnum1 = tr.dlightImage->texnum;
+ }
+
+ if ( glState.currenttextures[1] != texnum1 ) {
+ GL_SelectTexture( 1 );
+ image1->frameUsed = tr.frameCount;
+ glState.currenttextures[1] = texnum1;
+ qglBindTexture( GL_TEXTURE_2D, texnum1 );
+ }
+ if ( glState.currenttextures[0] != texnum0 ) {
+ GL_SelectTexture( 0 );
+ image0->frameUsed = tr.frameCount;
+ glState.currenttextures[0] = texnum0;
+ qglBindTexture( GL_TEXTURE_2D, texnum0 );
+ }
+}
+
+
+/*
+** GL_Cull
+*/
+void GL_Cull( int cullType ) {
+ if ( glState.faceCulling == cullType ) {
+ return;
+ }
+
+ glState.faceCulling = cullType;
+
+ if ( cullType == CT_TWO_SIDED )
+ {
+ qglDisable( GL_CULL_FACE );
+ }
+ else
+ {
+ bool cullFront;
+ qglEnable( GL_CULL_FACE );
+
+ cullFront = (cullType == CT_FRONT_SIDED);
+ if ( backEnd.viewParms.isMirror )
+ {
+ cullFront = !cullFront;
+ }
+
+ qglCullFace( cullFront ? GL_FRONT : GL_BACK );
+ }
+}
+
+/*
+** GL_TexEnv
+*/
+void GL_TexEnv( int env )
+{
+ if ( env == glState.texEnv[glState.currenttmu] )
+ {
+ return;
+ }
+
+ glState.texEnv[glState.currenttmu] = env;
+
+
+ switch ( env )
+ {
+ case GL_MODULATE:
+ qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+ break;
+ case GL_REPLACE:
+ qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
+ break;
+ case GL_DECAL:
+ qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
+ break;
+ case GL_ADD:
+ qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
+ break;
+ default:
+ ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed", env );
+ break;
+ }
+}
+
+/*
+** GL_State
+**
+** This routine is responsible for setting the most commonly changed state
+** in Q3.
+*/
+void GL_State( unsigned long stateBits )
+{
+ unsigned long diff = stateBits ^ glState.glStateBits;
+
+ if ( !diff )
+ {
+ return;
+ }
+
+ //
+ // check depthFunc bits
+ //
+ if ( diff & GLS_DEPTHFUNC_EQUAL )
+ {
+ if ( stateBits & GLS_DEPTHFUNC_EQUAL )
+ {
+ qglDepthFunc( GL_EQUAL );
+ }
+ else
+ {
+ qglDepthFunc( GL_LEQUAL );
+ }
+ }
+
+ //
+ // check blend bits
+ //
+ if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
+ {
+ GLenum srcFactor = GL_ONE, dstFactor = GL_ONE;
+
+ if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
+ {
+ switch ( stateBits & GLS_SRCBLEND_BITS )
+ {
+ case GLS_SRCBLEND_ZERO:
+ srcFactor = GL_ZERO;
+ break;
+ case GLS_SRCBLEND_ONE:
+ srcFactor = GL_ONE;
+ break;
+ case GLS_SRCBLEND_DST_COLOR:
+ srcFactor = GL_DST_COLOR;
+ break;
+ case GLS_SRCBLEND_ONE_MINUS_DST_COLOR:
+ srcFactor = GL_ONE_MINUS_DST_COLOR;
+ break;
+ case GLS_SRCBLEND_SRC_ALPHA:
+ srcFactor = GL_SRC_ALPHA;
+ break;
+ case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:
+ srcFactor = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case GLS_SRCBLEND_DST_ALPHA:
+ srcFactor = GL_DST_ALPHA;
+ break;
+ case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:
+ srcFactor = GL_ONE_MINUS_DST_ALPHA;
+ break;
+ case GLS_SRCBLEND_ALPHA_SATURATE:
+ srcFactor = GL_SRC_ALPHA_SATURATE;
+ break;
+ default:
+ ri.Error( ERR_DROP, "GL_State: invalid src blend state bits" );
+ break;
+ }
+
+ switch ( stateBits & GLS_DSTBLEND_BITS )
+ {
+ case GLS_DSTBLEND_ZERO:
+ dstFactor = GL_ZERO;
+ break;
+ case GLS_DSTBLEND_ONE:
+ dstFactor = GL_ONE;
+ break;
+ case GLS_DSTBLEND_SRC_COLOR:
+ dstFactor = GL_SRC_COLOR;
+ break;
+ case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:
+ dstFactor = GL_ONE_MINUS_SRC_COLOR;
+ break;
+ case GLS_DSTBLEND_SRC_ALPHA:
+ dstFactor = GL_SRC_ALPHA;
+ break;
+ case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:
+ dstFactor = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case GLS_DSTBLEND_DST_ALPHA:
+ dstFactor = GL_DST_ALPHA;
+ break;
+ case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:
+ dstFactor = GL_ONE_MINUS_DST_ALPHA;
+ break;
+ default:
+ ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits" );
+ break;
+ }
+
+ qglEnable( GL_BLEND );
+ qglBlendFunc( srcFactor, dstFactor );
+ }
+ else
+ {
+ qglDisable( GL_BLEND );
+ }
+ }
+
+ //
+ // check depthmask
+ //
+ if ( diff & GLS_DEPTHMASK_TRUE )
+ {
+ if ( stateBits & GLS_DEPTHMASK_TRUE )
+ {
+ qglDepthMask( GL_TRUE );
+ }
+ else
+ {
+ qglDepthMask( GL_FALSE );
+ }
+ }
+
+ //
+ // fill/line mode
+ //
+ if ( diff & GLS_POLYMODE_LINE )
+ {
+ if ( stateBits & GLS_POLYMODE_LINE )
+ {
+ qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+ }
+ else
+ {
+ qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+ }
+ }
+
+ //
+ // depthtest
+ //
+ if ( diff & GLS_DEPTHTEST_DISABLE )
+ {
+ if ( stateBits & GLS_DEPTHTEST_DISABLE )
+ {
+ qglDisable( GL_DEPTH_TEST );
+ }
+ else
+ {
+ qglEnable( GL_DEPTH_TEST );
+ }
+ }
+
+ //
+ // alpha test
+ //
+ if ( diff & GLS_ATEST_BITS )
+ {
+ switch ( stateBits & GLS_ATEST_BITS )
+ {
+ case 0:
+ qglDisable( GL_ALPHA_TEST );
+ break;
+ case GLS_ATEST_GT_0:
+ qglEnable( GL_ALPHA_TEST );
+ qglAlphaFunc( GL_GREATER, 0.0f );
+ break;
+ case GLS_ATEST_LT_80:
+ qglEnable( GL_ALPHA_TEST );
+ qglAlphaFunc( GL_LESS, 0.5f );
+ break;
+ case GLS_ATEST_GE_80:
+ qglEnable( GL_ALPHA_TEST );
+ qglAlphaFunc( GL_GEQUAL, 0.5f );
+ break;
+ default:
+ assert( 0 );
+ break;
+ }
+ }
+
+ glState.glStateBits = stateBits;
+}
+
+
+
+/*
+================
+RB_Hyperspace
+
+A player has predicted a teleport, but hasn't arrived yet
+================
+*/
+static void RB_Hyperspace( void ) {
+ float c;
+
+ if ( !backEnd.isHyperspace ) {
+ // do initialization shit
+ }
+
+ c = ( backEnd.refdef.time & 255 ) / 255.0f;
+ qglClearColor( c, c, c, 1 );
+ qglClear( GL_COLOR_BUFFER_BIT );
+
+ backEnd.isHyperspace = true;
+}
+
+
+static void SetViewportAndScissor( void ) {
+ qglMatrixMode(GL_PROJECTION);
+ qglLoadMatrixf( backEnd.viewParms.projectionMatrix );
+ qglMatrixMode(GL_MODELVIEW);
+
+ // set the window clipping
+ qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
+ backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );
+ qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
+ backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );
+}
+
+/*
+=================
+RB_BeginDrawingView
+
+Any mirrored or portaled views have already been drawn, so prepare
+to actually render the visible surfaces for this view
+=================
+*/
+void RB_BeginDrawingView (void) {
+ int clearBits = 0;
+
+ // sync with gl if needed
+ if ( r_finish->integer == 1 && !glState.finishCalled ) {
+ qglFinish ();
+ glState.finishCalled = true;
+ }
+ if ( r_finish->integer == 0 ) {
+ glState.finishCalled = true;
+ }
+
+ // we will need to change the projection matrix before drawing
+ // 2D images again
+ backEnd.projection2D = false;
+
+ //
+ // set the modelview matrix for the viewer
+ //
+ SetViewportAndScissor();
+
+ // ensures that depth writes are enabled for the depth clear
+ GL_State( GLS_DEFAULT );
+ // clear relevant buffers
+ clearBits = GL_DEPTH_BUFFER_BIT;
+
+ if ( r_measureOverdraw->integer || r_shadows->integer == 2 )
+ {
+ clearBits |= GL_STENCIL_BUFFER_BIT;
+ }
+ if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) )
+ {
+ clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used
+ qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky
+ }
+ qglClear( clearBits );
+
+ if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )
+ {
+ RB_Hyperspace();
+ return;
+ }
+ else
+ {
+ backEnd.isHyperspace = false;
+ }
+
+ glState.faceCulling = -1; // force face culling to set next time
+
+ // we will only draw a sun if there was sky rendered in this view
+ backEnd.skyRenderedThisView = false;
+
+ // clip to the plane of the portal
+ if ( backEnd.viewParms.isPortal ) {
+ float plane[4];
+ GLdouble plane2[4];
+
+ plane[0] = backEnd.viewParms.portalPlane.normal[0];
+ plane[1] = backEnd.viewParms.portalPlane.normal[1];
+ plane[2] = backEnd.viewParms.portalPlane.normal[2];
+ plane[3] = backEnd.viewParms.portalPlane.dist;
+
+ plane2[0] = DotProduct (backEnd.viewParms.orientation.axis[0], plane);
+ plane2[1] = DotProduct (backEnd.viewParms.orientation.axis[1], plane);
+ plane2[2] = DotProduct (backEnd.viewParms.orientation.axis[2], plane);
+ plane2[3] = DotProduct (plane, backEnd.viewParms.orientation.origin) - plane[3];
+
+ qglLoadMatrixf( s_flipMatrix );
+ qglClipPlane (GL_CLIP_PLANE0, plane2);
+ qglEnable (GL_CLIP_PLANE0);
+ } else {
+ qglDisable (GL_CLIP_PLANE0);
+ }
+}
+
+
+/*
+==================
+RB_RenderDrawSurfList
+==================
+*/
+void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
+ shader_t *shader, *oldShader;
+ int fogNum, oldFogNum;
+ int entityNum, oldEntityNum;
+ int dlighted, oldDlighted;
+ bool depthRange, oldDepthRange, isCrosshair, wasCrosshair;
+ int i;
+ drawSurf_t *drawSurf;
+ int oldSort;
+ double originalTime;
+
+ // save original time for entity shader offsets
+ originalTime = backEnd.refdef.floatTime;
+
+ // clear the z buffer, set the modelview, etc
+ RB_BeginDrawingView ();
+
+ // draw everything
+ oldEntityNum = -1;
+ backEnd.currentEntity = &tr.worldEntity;
+ oldShader = NULL;
+ oldFogNum = -1;
+ oldDepthRange = false;
+ wasCrosshair = false;
+ oldDlighted = false;
+ oldSort = -1;
+ depthRange = false;
+
+ backEnd.pc.c_surfaces += numDrawSurfs;
+
+ for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) {
+ if ( drawSurf->sort == oldSort ) {
+ // fast path, same as previous sort
+ rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
+ continue;
+ }
+ oldSort = drawSurf->sort;
+ R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
+
+ //
+ // change the tess parameters if needed
+ // a "entityMergable" shader is a shader that can have surfaces from seperate
+ // entities merged into a single batch, like smoke and blood puff sprites
+ if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted
+ || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) {
+ if (oldShader != NULL) {
+ RB_EndSurface();
+ }
+ RB_BeginSurface( shader, fogNum );
+ oldShader = shader;
+ oldFogNum = fogNum;
+ oldDlighted = dlighted;
+ }
+
+ //
+ // change the modelview matrix if needed
+ //
+ if ( entityNum != oldEntityNum ) {
+ depthRange = isCrosshair = false;
+
+ if ( entityNum != REFENTITYNUM_WORLD ) {
+ backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
+ // FIXME: e.shaderTime must be passed as int to avoid fp-precision loss issues
+ backEnd.refdef.floatTime = originalTime - (double)backEnd.currentEntity->e.shaderTime;
+ // we have to reset the shaderTime as well otherwise image animations start
+ // from the wrong frame
+ tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
+
+ // set up the transformation matrix
+ R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.orientation );
+
+ // set up the dynamic lighting if needed
+ if ( backEnd.currentEntity->needDlights ) {
+ R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.orientation );
+ }
+
+ if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK)
+ {
+ // hack the depth range to prevent view model from poking into walls
+ depthRange = true;
+
+ if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR)
+ isCrosshair = true;
+ }
+ } else {
+ backEnd.currentEntity = &tr.worldEntity;
+ backEnd.refdef.floatTime = originalTime;
+ backEnd.orientation = backEnd.viewParms.world;
+ // we haveientation to reset the shaderTime as well otherwise image animations on
+ // the worientationld (like water) continue with the wrong frame
+ tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
+ R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.orientation );
+ }
+
+ qglLoadMatrixf( backEnd.orientation.modelMatrix );
+
+ //
+ // change depthrange. Also change projection matrix so first person weapon does not look like coming
+ // out of the screen.
+ //
+ if (oldDepthRange != depthRange || wasCrosshair != isCrosshair)
+ {
+ if (depthRange)
+ {
+ if(backEnd.viewParms.stereoFrame != STEREO_CENTER)
+ {
+ if(isCrosshair)
+ {
+ if(oldDepthRange)
+ {
+ // was not a crosshair but now is, change back proj matrix
+ qglMatrixMode(GL_PROJECTION);
+ qglLoadMatrixf(backEnd.viewParms.projectionMatrix);
+ qglMatrixMode(GL_MODELVIEW);
+ }
+ }
+ else
+ {
+ viewParms_t temp = backEnd.viewParms;
+
+ R_SetupProjection(&temp, r_znear->value, false);
+
+ qglMatrixMode(GL_PROJECTION);
+ qglLoadMatrixf(temp.projectionMatrix);
+ qglMatrixMode(GL_MODELVIEW);
+ }
+ }
+
+ if(!oldDepthRange)
+ qglDepthRange (0, 0.3);
+ }
+ else
+ {
+ if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER)
+ {
+ qglMatrixMode(GL_PROJECTION);
+ qglLoadMatrixf(backEnd.viewParms.projectionMatrix);
+ qglMatrixMode(GL_MODELVIEW);
+ }
+
+ qglDepthRange (0, 1);
+ }
+
+ oldDepthRange = depthRange;
+ wasCrosshair = isCrosshair;
+ }
+
+ oldEntityNum = entityNum;
+ }
+
+ // add the triangles for this surface
+ rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
+ }
+
+ backEnd.refdef.floatTime = originalTime;
+
+ // draw the contents of the last shader batch
+ if (oldShader != NULL) {
+ RB_EndSurface();
+ }
+
+ // go back to the world modelview matrix
+ qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
+ if ( depthRange ) {
+ qglDepthRange (0, 1);
+ }
+
+ if (r_drawSun->integer) {
+ RB_DrawSun(0.1, tr.sunShader);
+ }
+
+ // darken down any stencil shadows
+ RB_ShadowFinish();
+
+ // add light flares on lights that aren't obscured
+ RB_RenderFlares();
+}
+
+
+/*
+============================================================================
+
+RENDER BACK END FUNCTIONS
+
+============================================================================
+*/
+
+/*
+================
+RB_SetGL2D
+
+================
+*/
+void RB_SetGL2D (void) {
+ backEnd.projection2D = true;
+
+ // set 2D virtual screen size
+ qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
+ qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
+ qglMatrixMode(GL_PROJECTION);
+ qglLoadIdentity ();
+ qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1);
+ qglMatrixMode(GL_MODELVIEW);
+ qglLoadIdentity ();
+
+ GL_State( GLS_DEPTHTEST_DISABLE |
+ GLS_SRCBLEND_SRC_ALPHA |
+ GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
+
+ GL_Cull( CT_TWO_SIDED );
+ qglDisable( GL_CLIP_PLANE0 );
+
+ // set time for 2D shaders
+ backEnd.refdef.time = ri.Milliseconds();
+ backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f;
+}
+
+
+/*
+=============
+RE_StretchRaw
+
+FIXME: not exactly backend
+Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
+Used for cinematics.
+=============
+*/
+void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, bool dirty) {
+ int i, j;
+ int start, end;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ R_IssuePendingRenderCommands();
+
+ if ( tess.numIndexes ) {
+ RB_EndSurface();
+ }
+
+ // we definately want to sync every frame for the cinematics
+ qglFinish();
+
+ start = 0;
+ if ( r_speeds->integer ) {
+ start = ri.Milliseconds();
+ }
+
+ // make sure rows and cols are powers of 2
+ for ( i = 0 ; ( 1 << i ) < cols ; i++ ) {
+ }
+ for ( j = 0 ; ( 1 << j ) < rows ; j++ ) {
+ }
+ if ( ( 1 << i ) != cols || ( 1 << j ) != rows) {
+ ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
+ }
+
+ GL_Bind( tr.scratchImage[client] );
+
+ // if the scratchImage isn't in the format we want, specify it as a new texture
+ if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
+ tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
+ tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
+ qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
+ qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ } else {
+ if (dirty) {
+ // otherwise, just subimage upload it so that drivers can tell we are going to be changing
+ // it and don't try and do a texture compression
+ qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
+ }
+ }
+
+ if ( r_speeds->integer ) {
+ end = ri.Milliseconds();
+ ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start );
+ }
+
+ RB_SetGL2D();
+
+ qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
+
+ qglBegin (GL_QUADS);
+ qglTexCoord2f ( 0.5f / cols, 0.5f / rows );
+ qglVertex2f (x, y);
+ qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows );
+ qglVertex2f (x+w, y);
+ qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows );
+ qglVertex2f (x+w, y+h);
+ qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows );
+ qglVertex2f (x, y+h);
+ qglEnd ();
+}
+
+void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, bool dirty) {
+
+ GL_Bind( tr.scratchImage[client] );
+
+ // if the scratchImage isn't in the format we want, specify it as a new texture
+ if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
+ tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
+ tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
+ qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
+ qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ } else {
+ if (dirty) {
+ // otherwise, just subimage upload it so that drivers can tell we are going to be changing
+ // it and don't try and do a texture compression
+ qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
+ }
+ }
+}
+
+
+/*
+=============
+RB_SetColor
+
+=============
+*/
+const void *RB_SetColor( const void *data ) {
+ const setColorCommand_t *cmd;
+
+ cmd = (const setColorCommand_t *)data;
+
+ backEnd.color2D[0] = cmd->color[0] * 255;
+ backEnd.color2D[1] = cmd->color[1] * 255;
+ backEnd.color2D[2] = cmd->color[2] * 255;
+ backEnd.color2D[3] = cmd->color[3] * 255;
+
+ return (const void *)(cmd + 1);
+}
+
+/*
+=============
+RB_StretchPic
+=============
+*/
+const void *RB_StretchPic ( const void *data ) {
+ const stretchPicCommand_t *cmd;
+ shader_t *shader;
+ int numVerts, numIndexes;
+
+ cmd = (const stretchPicCommand_t *)data;
+
+ if ( !backEnd.projection2D ) {
+ RB_SetGL2D();
+ }
+
+ shader = cmd->shader;
+ if ( shader != tess.shader ) {
+ if ( tess.numIndexes ) {
+ RB_EndSurface();
+ }
+ backEnd.currentEntity = &backEnd.entity2D;
+ RB_BeginSurface( shader, 0 );
+ }
+
+ RB_CHECKOVERFLOW( 4, 6 );
+ numVerts = tess.numVertexes;
+ numIndexes = tess.numIndexes;
+
+ tess.numVertexes += 4;
+ tess.numIndexes += 6;
+
+ tess.indexes[ numIndexes ] = numVerts + 3;
+ tess.indexes[ numIndexes + 1 ] = numVerts + 0;
+ tess.indexes[ numIndexes + 2 ] = numVerts + 2;
+ tess.indexes[ numIndexes + 3 ] = numVerts + 2;
+ tess.indexes[ numIndexes + 4 ] = numVerts + 0;
+ tess.indexes[ numIndexes + 5 ] = numVerts + 1;
+
+ *(int *)tess.vertexColors[ numVerts ] =
+ *(int *)tess.vertexColors[ numVerts + 1 ] =
+ *(int *)tess.vertexColors[ numVerts + 2 ] =
+ *(int *)tess.vertexColors[ numVerts + 3 ] = *(int *)backEnd.color2D;
+
+ tess.xyz[ numVerts ][0] = cmd->x;
+ tess.xyz[ numVerts ][1] = cmd->y;
+ tess.xyz[ numVerts ][2] = 0;
+
+ tess.texCoords[ numVerts ][0][0] = cmd->s1;
+ tess.texCoords[ numVerts ][0][1] = cmd->t1;
+
+ tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w;
+ tess.xyz[ numVerts + 1 ][1] = cmd->y;
+ tess.xyz[ numVerts + 1 ][2] = 0;
+
+ tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2;
+ tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1;
+
+ tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w;
+ tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h;
+ tess.xyz[ numVerts + 2 ][2] = 0;
+
+ tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2;
+ tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2;
+
+ tess.xyz[ numVerts + 3 ][0] = cmd->x;
+ tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h;
+ tess.xyz[ numVerts + 3 ][2] = 0;
+
+ tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1;
+ tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2;
+
+ return (const void *)(cmd + 1);
+}
+
+
+/*
+=============
+RB_DrawSurfs
+
+=============
+*/
+const void *RB_DrawSurfs( const void *data ) {
+ const drawSurfsCommand_t *cmd;
+
+ // finish any 2D drawing if needed
+ if ( tess.numIndexes ) {
+ RB_EndSurface();
+ }
+
+ cmd = (const drawSurfsCommand_t *)data;
+
+ backEnd.refdef = cmd->refdef;
+ backEnd.viewParms = cmd->viewParms;
+
+ RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );
+
+ return (const void *)(cmd + 1);
+}
+
+
+/*
+=============
+RB_DrawBuffer
+
+=============
+*/
+const void *RB_DrawBuffer( const void *data ) {
+ const drawBufferCommand_t *cmd;
+
+ cmd = (const drawBufferCommand_t *)data;
+
+ qglDrawBuffer( cmd->buffer );
+
+ // clear screen for debugging
+ if ( r_clear->integer ) {
+ qglClearColor( 1, 0, 0.5, 1 );
+ qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+ }
+
+ return (const void *)(cmd + 1);
+}
+
+/*
+===============
+RB_ShowImages
+
+Draw all the images to the screen, on top of whatever
+was there. This is used to test for texture thrashing.
+
+Also called by RE_EndRegistration
+===============
+*/
+void RB_ShowImages( void ) {
+ int i;
+ image_t *image;
+ float x, y, w, h;
+ int start, end;
+
+ if ( !backEnd.projection2D ) {
+ RB_SetGL2D();
+ }
+
+ qglClear( GL_COLOR_BUFFER_BIT );
+
+ qglFinish();
+
+ start = ri.Milliseconds();
+
+ for ( i=0 ; i<tr.numImages ; i++ ) {
+ image = tr.images[i];
+
+ w = glConfig.vidWidth / 20;
+ h = glConfig.vidHeight / 15;
+ x = i % 20 * w;
+ y = i / 20 * h;
+
+ // show in proportional size in mode 2
+ if ( r_showImages->integer == 2 ) {
+ w *= image->uploadWidth / 512.0f;
+ h *= image->uploadHeight / 512.0f;
+ }
+
+ GL_Bind( image );
+ qglBegin (GL_QUADS);
+ qglTexCoord2f( 0, 0 );
+ qglVertex2f( x, y );
+ qglTexCoord2f( 1, 0 );
+ qglVertex2f( x + w, y );
+ qglTexCoord2f( 1, 1 );
+ qglVertex2f( x + w, y + h );
+ qglTexCoord2f( 0, 1 );
+ qglVertex2f( x, y + h );
+ qglEnd();
+ }
+
+ qglFinish();
+
+ end = ri.Milliseconds();
+ ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start );
+
+}
+
+/*
+=============
+RB_ColorMask
+
+=============
+*/
+const void *RB_ColorMask(const void *data)
+{
+ const colorMaskCommand_t *cmd = (const colorMaskCommand_t*)data;
+
+ qglColorMask(cmd->rgba[0], cmd->rgba[1], cmd->rgba[2], cmd->rgba[3]);
+
+ return (const void *)(cmd + 1);
+}
+
+/*
+=============
+RB_ClearDepth
+
+=============
+*/
+const void *RB_ClearDepth(const void *data)
+{
+ const clearDepthCommand_t *cmd = (const clearDepthCommand_t*)data;
+
+ if(tess.numIndexes)
+ RB_EndSurface();
+
+ // texture swapping test
+ if (r_showImages->integer)
+ RB_ShowImages();
+
+ qglClear(GL_DEPTH_BUFFER_BIT);
+
+ return (const void *)(cmd + 1);
+}
+
+/*
+=============
+RB_SwapBuffers
+
+=============
+*/
+const void *RB_SwapBuffers( const void *data ) {
+ const swapBuffersCommand_t *cmd;
+
+ // finish any 2D drawing if needed
+ if ( tess.numIndexes ) {
+ RB_EndSurface();
+ }
+
+ // texture swapping test
+ if ( r_showImages->integer ) {
+ RB_ShowImages();
+ }
+
+ cmd = (const swapBuffersCommand_t *)data;
+
+ // we measure overdraw by reading back the stencil buffer and
+ // counting up the number of increments that have happened
+ if ( r_measureOverdraw->integer ) {
+ int i;
+ long sum = 0;
+ unsigned char *stencilReadback;
+
+ stencilReadback = (unsigned char*)ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight );
+ qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback );
+
+ for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) {
+ sum += stencilReadback[i];
+ }
+
+ backEnd.pc.c_overDraw += sum;
+ ri.Hunk_FreeTempMemory( stencilReadback );
+ }
+
+
+ if ( !glState.finishCalled ) {
+ qglFinish();
+ }
+
+ GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" );
+
+ GLimp_EndFrame();
+
+ backEnd.projection2D = false;
+
+ return (const void *)(cmd + 1);
+}
+
+/*
+====================
+RB_ExecuteRenderCommands
+====================
+*/
+void RB_ExecuteRenderCommands( const void *data ) {
+ int t1, t2;
+
+ t1 = ri.Milliseconds ();
+
+ while ( 1 ) {
+ data = PADP(data, sizeof(void *));
+
+ switch ( *(const int *)data ) {
+ case RC_SET_COLOR:
+ data = RB_SetColor( data );
+ break;
+ case RC_STRETCH_PIC:
+ data = RB_StretchPic( data );
+ break;
+ case RC_DRAW_SURFS:
+ data = RB_DrawSurfs( data );
+ break;
+ case RC_DRAW_BUFFER:
+ data = RB_DrawBuffer( data );
+ break;
+ case RC_SWAP_BUFFERS:
+ data = RB_SwapBuffers( data );
+ break;
+ case RC_SCREENSHOT:
+ data = RB_TakeScreenshotCmd( data );
+ break;
+ case RC_VIDEOFRAME:
+ data = RB_TakeVideoFrameCmd( data );
+ break;
+ case RC_COLORMASK:
+ data = RB_ColorMask(data);
+ break;
+ case RC_CLEARDEPTH:
+ data = RB_ClearDepth(data);
+ break;
+ case RC_END_OF_LIST:
+ default:
+ // stop rendering
+ t2 = ri.Milliseconds ();
+ backEnd.pc.msec = t2 - t1;
+ return;
+ }
+ }
+
+}
diff --git a/src/renderergl1/tr_bsp.cpp b/src/renderergl1/tr_bsp.cpp
new file mode 100644
index 0000000..b15bc79
--- /dev/null
+++ b/src/renderergl1/tr_bsp.cpp
@@ -0,0 +1,1869 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_map.c
+
+#include "tr_local.h"
+
+/*
+
+Loads and prepares a map file for scene rendering.
+
+A single entry point:
+
+void RE_LoadWorldMap( const char *name );
+
+*/
+
+static world_t s_worldData;
+static byte *fileBase;
+
+int c_subdivisions;
+int c_gridVerts;
+
+//===============================================================================
+
+static void HSVtoRGB( float h, float s, float v, float rgb[3] )
+{
+ int i;
+ float f;
+ float p, q, t;
+
+ h *= 5;
+
+ i = floor( h );
+ f = h - i;
+
+ p = v * ( 1 - s );
+ q = v * ( 1 - s * f );
+ t = v * ( 1 - s * ( 1 - f ) );
+
+ switch ( i )
+ {
+ case 0:
+ rgb[0] = v;
+ rgb[1] = t;
+ rgb[2] = p;
+ break;
+ case 1:
+ rgb[0] = q;
+ rgb[1] = v;
+ rgb[2] = p;
+ break;
+ case 2:
+ rgb[0] = p;
+ rgb[1] = v;
+ rgb[2] = t;
+ break;
+ case 3:
+ rgb[0] = p;
+ rgb[1] = q;
+ rgb[2] = v;
+ break;
+ case 4:
+ rgb[0] = t;
+ rgb[1] = p;
+ rgb[2] = v;
+ break;
+ case 5:
+ rgb[0] = v;
+ rgb[1] = p;
+ rgb[2] = q;
+ break;
+ }
+}
+
+/*
+===============
+R_ColorShiftLightingBytes
+
+===============
+*/
+static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) {
+ int shift, r, g, b;
+
+ // shift the color data based on overbright range
+ shift = r_mapOverBrightBits->integer - tr.overbrightBits;
+
+ // shift the data based on overbright range
+ r = in[0] << shift;
+ g = in[1] << shift;
+ b = in[2] << shift;
+
+ // normalize by color instead of saturating to white
+ if ( ( r | g | b ) > 255 ) {
+ int max;
+
+ max = r > g ? r : g;
+ max = max > b ? max : b;
+ r = r * 255 / max;
+ g = g * 255 / max;
+ b = b * 255 / max;
+ }
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = in[3];
+}
+
+/*
+===============
+R_LoadLightmaps
+
+===============
+*/
+#define LIGHTMAP_SIZE 128
+static void R_LoadLightmaps( lump_t *l ) {
+ byte *buf, *buf_p;
+ int len;
+ byte image[LIGHTMAP_SIZE*LIGHTMAP_SIZE*4];
+ int i, j;
+ float maxIntensity = 0;
+ double sumIntensity = 0;
+
+ len = l->filelen;
+ if ( !len ) {
+ return;
+ }
+ buf = fileBase + l->fileofs;
+
+ // we are about to upload textures
+ R_IssuePendingRenderCommands();
+
+ // create all the lightmaps
+ tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3);
+ if ( tr.numLightmaps == 1 ) {
+ //FIXME: HACK: maps with only one lightmap turn up fullbright for some reason.
+ //this avoids this, but isn't the correct solution.
+ tr.numLightmaps++;
+ }
+
+ // if we are in r_vertexLight mode, we don't need the lightmaps at all
+ if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
+ return;
+ }
+
+ tr.lightmaps = (image_t**)ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low );
+ for ( i = 0 ; i < tr.numLightmaps ; i++ ) {
+ // expand the 24 bit on-disk to 32 bit
+ buf_p = buf + i * LIGHTMAP_SIZE*LIGHTMAP_SIZE * 3;
+
+ if ( r_lightmap->integer == 2 )
+ { // color code by intensity as development tool (FIXME: check range)
+ for ( j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ )
+ {
+ float r = buf_p[j*3+0];
+ float g = buf_p[j*3+1];
+ float b = buf_p[j*3+2];
+ float intensity;
+ float out[3] = {0.0, 0.0, 0.0};
+
+ intensity = 0.33f * r + 0.685f * g + 0.063f * b;
+
+ if ( intensity > 255 )
+ intensity = 1.0f;
+ else
+ intensity /= 255.0f;
+
+ if ( intensity > maxIntensity )
+ maxIntensity = intensity;
+
+ HSVtoRGB( intensity, 1.00, 0.50, out );
+
+ image[j*4+0] = out[0] * 255;
+ image[j*4+1] = out[1] * 255;
+ image[j*4+2] = out[2] * 255;
+ image[j*4+3] = 255;
+
+ sumIntensity += intensity;
+ }
+ } else {
+ for ( j = 0 ; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) {
+ R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] );
+ image[j*4+3] = 255;
+ }
+ }
+ tr.lightmaps[i] = R_CreateImage( va("*lightmap%d",i), image,
+ LIGHTMAP_SIZE, LIGHTMAP_SIZE, IMGTYPE_COLORALPHA,
+ IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, 0 );
+ }
+
+ if ( r_lightmap->integer == 2 ) {
+ ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) );
+ }
+}
+
+
+/*
+=================
+RE_SetWorldVisData
+
+This is called by the clipmodel subsystem so we can share the 1.8 megs of
+space in big maps...
+=================
+*/
+void RE_SetWorldVisData( const byte *vis ) {
+ tr.externalVisData = vis;
+}
+
+
+/*
+=================
+R_LoadVisibility
+=================
+*/
+static void R_LoadVisibility( lump_t *l ) {
+ int len;
+ byte *buf;
+
+ len = ( s_worldData.numClusters + 63 ) & ~63;
+ s_worldData.novis = (byte*)ri.Hunk_Alloc( len, h_low );
+ Com_Memset( s_worldData.novis, 0xff, len );
+
+ len = l->filelen;
+ if ( !len ) {
+ return;
+ }
+ buf = fileBase + l->fileofs;
+
+ s_worldData.numClusters = LittleLong( ((int *)buf)[0] );
+ s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] );
+
+ // CM_Load should have given us the vis data to share, so
+ // we don't need to allocate another copy
+ if ( tr.externalVisData ) {
+ s_worldData.vis = tr.externalVisData;
+ } else {
+ byte *dest;
+
+ dest = (byte*)ri.Hunk_Alloc( len - 8, h_low );
+ Com_Memcpy( dest, buf + 8, len - 8 );
+ s_worldData.vis = dest;
+ }
+}
+
+//===============================================================================
+
+
+/*
+===============
+ShaderForShaderNum
+===============
+*/
+static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) {
+ shader_t *shader;
+ dshader_t *dsh;
+
+ int _shaderNum = LittleLong( shaderNum );
+ if ( _shaderNum < 0 || _shaderNum >= s_worldData.numShaders ) {
+ ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", _shaderNum );
+ }
+ dsh = &s_worldData.shaders[ _shaderNum ];
+
+ if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
+ lightmapNum = LIGHTMAP_BY_VERTEX;
+ }
+
+ if ( r_fullbright->integer ) {
+ lightmapNum = LIGHTMAP_WHITEIMAGE;
+ }
+
+ shader = R_FindShader( dsh->shader, lightmapNum, true );
+
+ // if the shader had errors, just use default shader
+ if ( shader->defaultShader ) {
+ return tr.defaultShader;
+ }
+
+ return shader;
+}
+
+/*
+===============
+ParseFace
+===============
+*/
+static void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
+ int i, j;
+ srfSurfaceFace_t *cv;
+ int numPoints, numIndexes;
+ int lightmapNum;
+ int sfaceSize, ofsIndexes;
+
+ lightmapNum = LittleLong( ds->lightmapNum );
+
+ // get fog volume
+ surf->fogIndex = LittleLong( ds->fogNum ) + 1;
+
+ // get shader value
+ surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );
+ if ( r_singleShader->integer && !surf->shader->isSky ) {
+ surf->shader = tr.defaultShader;
+ }
+
+ numPoints = LittleLong( ds->numVerts );
+ if (numPoints > MAX_FACE_POINTS) {
+ ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numPoints);
+ numPoints = MAX_FACE_POINTS;
+ surf->shader = tr.defaultShader;
+ }
+
+ numIndexes = LittleLong( ds->numIndexes );
+
+ // create the srfSurfaceFace_t
+ sfaceSize = ( size_t ) &((srfSurfaceFace_t *)0)->points[numPoints];
+ ofsIndexes = sfaceSize;
+ sfaceSize += sizeof( int ) * numIndexes;
+
+ cv = (srfSurfaceFace_t*)ri.Hunk_Alloc( sfaceSize, h_low );
+ cv->surfaceType = SF_FACE;
+ cv->numPoints = numPoints;
+ cv->numIndices = numIndexes;
+ cv->ofsIndices = ofsIndexes;
+
+ verts += LittleLong( ds->firstVert );
+ for ( i = 0 ; i < numPoints ; i++ ) {
+ for ( j = 0 ; j < 3 ; j++ ) {
+ cv->points[i][j] = LittleFloat( verts[i].xyz[j] );
+ }
+ for ( j = 0 ; j < 2 ; j++ ) {
+ cv->points[i][3+j] = LittleFloat( verts[i].st[j] );
+ cv->points[i][5+j] = LittleFloat( verts[i].lightmap[j] );
+ }
+ R_ColorShiftLightingBytes( verts[i].color, (byte *)&cv->points[i][7] );
+ }
+
+ indexes += LittleLong( ds->firstIndex );
+ for ( i = 0 ; i < numIndexes ; i++ ) {
+ ((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] );
+ }
+
+ // take the plane information from the lightmap vector
+ for ( i = 0 ; i < 3 ; i++ ) {
+ cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
+ }
+ cv->plane.dist = DotProduct( cv->points[0], cv->plane.normal );
+ SetPlaneSignbits( &cv->plane );
+ cv->plane.type = PlaneTypeForNormal( cv->plane.normal );
+
+ surf->data = (surfaceType_t *)cv;
+}
+
+
+/*
+===============
+ParseMesh
+===============
+*/
+static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) {
+ srfGridMesh_t *grid;
+ int i, j;
+ int width, height, numPoints;
+ drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE];
+ int lightmapNum;
+ vec3_t bounds[2];
+ vec3_t tmpVec;
+ static surfaceType_t skipData = SF_SKIP;
+
+ lightmapNum = LittleLong( ds->lightmapNum );
+
+ // get fog volume
+ surf->fogIndex = LittleLong( ds->fogNum ) + 1;
+
+ // get shader value
+ surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );
+ if ( r_singleShader->integer && !surf->shader->isSky ) {
+ surf->shader = tr.defaultShader;
+ }
+
+ // we may have a nodraw surface, because they might still need to
+ // be around for movement clipping
+ if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) {
+ surf->data = &skipData;
+ return;
+ }
+
+ width = LittleLong( ds->patchWidth );
+ height = LittleLong( ds->patchHeight );
+
+ verts += LittleLong( ds->firstVert );
+ numPoints = width * height;
+ for ( i = 0 ; i < numPoints ; i++ ) {
+ for ( j = 0 ; j < 3 ; j++ ) {
+ points[i].xyz[j] = LittleFloat( verts[i].xyz[j] );
+ points[i].normal[j] = LittleFloat( verts[i].normal[j] );
+ }
+ for ( j = 0 ; j < 2 ; j++ ) {
+ points[i].st[j] = LittleFloat( verts[i].st[j] );
+ points[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );
+ }
+ R_ColorShiftLightingBytes( verts[i].color, points[i].color );
+ }
+
+ // pre-tesseleate
+ grid = R_SubdividePatchToGrid( width, height, points );
+ surf->data = (surfaceType_t *)grid;
+
+ // copy the level of detail origin, which is the center
+ // of the group of all curves that must subdivide the same
+ // to avoid cracking
+ for ( i = 0 ; i < 3 ; i++ ) {
+ bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] );
+ bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] );
+ }
+ VectorAdd( bounds[0], bounds[1], bounds[1] );
+ VectorScale( bounds[1], 0.5f, grid->lodOrigin );
+ VectorSubtract( bounds[0], grid->lodOrigin, tmpVec );
+ grid->lodRadius = VectorLength( tmpVec );
+}
+
+/*
+===============
+ParseTriSurf
+===============
+*/
+static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
+ srfTriangles_t *tri;
+ int i, j;
+ int numVerts, numIndexes;
+
+ // get fog volume
+ surf->fogIndex = LittleLong( ds->fogNum ) + 1;
+
+ // get shader
+ surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
+ if ( r_singleShader->integer && !surf->shader->isSky ) {
+ surf->shader = tr.defaultShader;
+ }
+
+ numVerts = LittleLong( ds->numVerts );
+ numIndexes = LittleLong( ds->numIndexes );
+
+ tri = (srfTriangles_t*)ri.Hunk_Alloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] )
+ + numIndexes * sizeof( tri->indexes[0] ), h_low );
+ tri->surfaceType = SF_TRIANGLES;
+ tri->numVerts = numVerts;
+ tri->numIndexes = numIndexes;
+ tri->verts = (drawVert_t *)(tri + 1);
+ tri->indexes = (int *)(tri->verts + tri->numVerts );
+
+ surf->data = (surfaceType_t *)tri;
+
+ // copy vertexes
+ ClearBounds( tri->bounds[0], tri->bounds[1] );
+ verts += LittleLong( ds->firstVert );
+ for ( i = 0 ; i < numVerts ; i++ ) {
+ for ( j = 0 ; j < 3 ; j++ ) {
+ tri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] );
+ tri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] );
+ }
+ AddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] );
+ for ( j = 0 ; j < 2 ; j++ ) {
+ tri->verts[i].st[j] = LittleFloat( verts[i].st[j] );
+ tri->verts[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );
+ }
+
+ R_ColorShiftLightingBytes( verts[i].color, tri->verts[i].color );
+ }
+
+ // copy indexes
+ indexes += LittleLong( ds->firstIndex );
+ for ( i = 0 ; i < numIndexes ; i++ ) {
+ tri->indexes[i] = LittleLong( indexes[i] );
+ if ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) {
+ ri.Error( ERR_DROP, "Bad index in triangle surface" );
+ }
+ }
+}
+
+/*
+===============
+ParseFlare
+===============
+*/
+static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
+ srfFlare_t *flare;
+ int i;
+
+ // get fog volume
+ surf->fogIndex = LittleLong( ds->fogNum ) + 1;
+
+ // get shader
+ surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
+ if ( r_singleShader->integer && !surf->shader->isSky ) {
+ surf->shader = tr.defaultShader;
+ }
+
+ flare = (srfFlare_t*)ri.Hunk_Alloc( sizeof( *flare ), h_low );
+ flare->surfaceType = SF_FLARE;
+
+ surf->data = (surfaceType_t *)flare;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] );
+ flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] );
+ flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
+ }
+}
+
+
+/*
+=================
+R_MergedWidthPoints
+
+returns true if there are grid points merged on a width edge
+=================
+*/
+int R_MergedWidthPoints(srfGridMesh_t *grid, int offset) {
+ int i, j;
+
+ for (i = 1; i < grid->width-1; i++) {
+ for (j = i + 1; j < grid->width-1; j++) {
+ if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue;
+ if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue;
+ if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue;
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+=================
+R_MergedHeightPoints
+
+returns true if there are grid points merged on a height edge
+=================
+*/
+int R_MergedHeightPoints(srfGridMesh_t *grid, int offset) {
+ int i, j;
+
+ for (i = 1; i < grid->height-1; i++) {
+ for (j = i + 1; j < grid->height-1; j++) {
+ if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue;
+ if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue;
+ if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue;
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+=================
+R_FixSharedVertexLodError_r
+
+NOTE: never sync LoD through grid edges with merged points!
+
+FIXME: write generalized version that also avoids cracks between a patch and one that meets half way?
+=================
+*/
+void R_FixSharedVertexLodError_r( int start, srfGridMesh_t *grid1 ) {
+ int j, k, l, m, n, offset1, offset2, touch;
+ srfGridMesh_t *grid2;
+
+ for ( j = start; j < s_worldData.numsurfaces; j++ ) {
+ //
+ grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;
+ // if this surface is not a grid
+ if ( grid2->surfaceType != SF_GRID ) continue;
+ // if the LOD errors are already fixed for this patch
+ if ( grid2->lodFixed == 2 ) continue;
+ // grids in the same LOD group should have the exact same lod radius
+ if ( grid1->lodRadius != grid2->lodRadius ) continue;
+ // grids in the same LOD group should have the exact same lod origin
+ if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;
+ if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;
+ if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;
+ //
+ touch = false;
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = (grid1->height-1) * grid1->width;
+ else offset1 = 0;
+ if (R_MergedWidthPoints(grid1, offset1)) continue;
+ for (k = 1; k < grid1->width-1; k++) {
+ for (m = 0; m < 2; m++) {
+
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ if (R_MergedWidthPoints(grid2, offset2)) continue;
+ for ( l = 1; l < grid2->width-1; l++) {
+ //
+ if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
+ if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
+ if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
+ // ok the points are equal and should have the same lod error
+ grid2->widthLodError[l] = grid1->widthLodError[k];
+ touch = true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ if (R_MergedHeightPoints(grid2, offset2)) continue;
+ for ( l = 1; l < grid2->height-1; l++) {
+ //
+ if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
+ if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
+ if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
+ // ok the points are equal and should have the same lod error
+ grid2->heightLodError[l] = grid1->widthLodError[k];
+ touch = true;
+ }
+ }
+ }
+ }
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = grid1->width-1;
+ else offset1 = 0;
+ if (R_MergedHeightPoints(grid1, offset1)) continue;
+ for (k = 1; k < grid1->height-1; k++) {
+ for (m = 0; m < 2; m++) {
+
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ if (R_MergedWidthPoints(grid2, offset2)) continue;
+ for ( l = 1; l < grid2->width-1; l++) {
+ //
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
+ // ok the points are equal and should have the same lod error
+ grid2->widthLodError[l] = grid1->heightLodError[k];
+ touch = true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ if (R_MergedHeightPoints(grid2, offset2)) continue;
+ for ( l = 1; l < grid2->height-1; l++) {
+ //
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
+ // ok the points are equal and should have the same lod error
+ grid2->heightLodError[l] = grid1->heightLodError[k];
+ touch = true;
+ }
+ }
+ }
+ }
+ if (touch) {
+ grid2->lodFixed = 2;
+ R_FixSharedVertexLodError_r ( start, grid2 );
+ //NOTE: this would be correct but makes things really slow
+ //grid2->lodFixed = 1;
+ }
+ }
+}
+
+/*
+=================
+R_FixSharedVertexLodError
+
+This function assumes that all patches in one group are nicely stitched together for the highest LoD.
+If this is not the case this function will still do its job but won't fix the highest LoD cracks.
+=================
+*/
+void R_FixSharedVertexLodError( void ) {
+ int i;
+ srfGridMesh_t *grid1;
+
+ for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
+ //
+ grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;
+ // if this surface is not a grid
+ if ( grid1->surfaceType != SF_GRID )
+ continue;
+ //
+ if ( grid1->lodFixed )
+ continue;
+ //
+ grid1->lodFixed = 2;
+ // recursively fix other patches in the same LOD group
+ R_FixSharedVertexLodError_r( i + 1, grid1);
+ }
+}
+
+
+/*
+===============
+R_StitchPatches
+===============
+*/
+int R_StitchPatches( int grid1num, int grid2num ) {
+ float *v1, *v2;
+ srfGridMesh_t *grid1, *grid2;
+ int k, l, m, n, offset1, offset2, row, column;
+
+ grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;
+ grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data;
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = (grid1->height-1) * grid1->width;
+ else offset1 = 0;
+ if (R_MergedWidthPoints(grid1, offset1))
+ continue;
+ for (k = 0; k < grid1->width-2; k += 2) {
+
+ for (m = 0; m < 2; m++) {
+
+ if ( grid2->width >= MAX_GRID_SIZE )
+ break;
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->width-1; l++) {
+ //
+ v1 = grid1->verts[k + offset1].xyz;
+ v2 = grid2->verts[l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[k + 2 + offset1].xyz;
+ v2 = grid2->verts[l + 1 + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[l + offset2].xyz;
+ v2 = grid2->verts[l + 1 + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert column into grid2 right after after column l
+ if (m) row = grid2->height-1;
+ else row = 0;
+ grid2 = R_GridInsertColumn( grid2, l+1, row,
+ grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (grid2->height >= MAX_GRID_SIZE)
+ break;
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->height-1; l++) {
+ //
+ v1 = grid1->verts[k + offset1].xyz;
+ v2 = grid2->verts[grid2->width * l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[k + 2 + offset1].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[grid2->width * l + offset2].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert row into grid2 right after after row l
+ if (m) column = grid2->width-1;
+ else column = 0;
+ grid2 = R_GridInsertRow( grid2, l+1, column,
+ grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ }
+ }
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = grid1->width-1;
+ else offset1 = 0;
+ if (R_MergedHeightPoints(grid1, offset1))
+ continue;
+ for (k = 0; k < grid1->height-2; k += 2) {
+ for (m = 0; m < 2; m++) {
+
+ if ( grid2->width >= MAX_GRID_SIZE )
+ break;
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->width-1; l++) {
+ //
+ v1 = grid1->verts[grid1->width * k + offset1].xyz;
+ v2 = grid2->verts[l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
+ v2 = grid2->verts[l + 1 + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[l + offset2].xyz;
+ v2 = grid2->verts[(l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert column into grid2 right after after column l
+ if (m) row = grid2->height-1;
+ else row = 0;
+ grid2 = R_GridInsertColumn( grid2, l+1, row,
+ grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (grid2->height >= MAX_GRID_SIZE)
+ break;
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->height-1; l++) {
+ //
+ v1 = grid1->verts[grid1->width * k + offset1].xyz;
+ v2 = grid2->verts[grid2->width * l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[grid2->width * l + offset2].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert row into grid2 right after after row l
+ if (m) column = grid2->width-1;
+ else column = 0;
+ grid2 = R_GridInsertRow( grid2, l+1, column,
+ grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ }
+ }
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = (grid1->height-1) * grid1->width;
+ else offset1 = 0;
+ if (R_MergedWidthPoints(grid1, offset1))
+ continue;
+ for (k = grid1->width-1; k > 1; k -= 2) {
+
+ for (m = 0; m < 2; m++) {
+
+ if ( !grid2 || grid2->width >= MAX_GRID_SIZE )
+ break;
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->width-1; l++) {
+ //
+ v1 = grid1->verts[k + offset1].xyz;
+ v2 = grid2->verts[l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[k - 2 + offset1].xyz;
+ v2 = grid2->verts[l + 1 + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[l + offset2].xyz;
+ v2 = grid2->verts[(l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert column into grid2 right after after column l
+ if (m) row = grid2->height-1;
+ else row = 0;
+ grid2 = R_GridInsertColumn( grid2, l+1, row,
+ grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (!grid2 || grid2->height >= MAX_GRID_SIZE)
+ break;
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->height-1; l++) {
+ //
+ v1 = grid1->verts[k + offset1].xyz;
+ v2 = grid2->verts[grid2->width * l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[k - 2 + offset1].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[grid2->width * l + offset2].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert row into grid2 right after after row l
+ if (m) column = grid2->width-1;
+ else column = 0;
+ grid2 = R_GridInsertRow( grid2, l+1, column,
+ grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);
+ if (!grid2)
+ break;
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ }
+ }
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = grid1->width-1;
+ else offset1 = 0;
+ if (R_MergedHeightPoints(grid1, offset1))
+ continue;
+ for (k = grid1->height-1; k > 1; k -= 2) {
+ for (m = 0; m < 2; m++) {
+
+ if ( !grid2 || grid2->width >= MAX_GRID_SIZE )
+ break;
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->width-1; l++) {
+ //
+ v1 = grid1->verts[grid1->width * k + offset1].xyz;
+ v2 = grid2->verts[l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
+ v2 = grid2->verts[l + 1 + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[l + offset2].xyz;
+ v2 = grid2->verts[(l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert column into grid2 right after after column l
+ if (m) row = grid2->height-1;
+ else row = 0;
+ grid2 = R_GridInsertColumn( grid2, l+1, row,
+ grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (!grid2 || grid2->height >= MAX_GRID_SIZE)
+ break;
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->height-1; l++) {
+ //
+ v1 = grid1->verts[grid1->width * k + offset1].xyz;
+ v2 = grid2->verts[grid2->width * l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[grid2->width * l + offset2].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert row into grid2 right after after row l
+ if (m) column = grid2->width-1;
+ else column = 0;
+ grid2 = R_GridInsertRow( grid2, l+1, column,
+ grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/*
+===============
+R_TryStitchPatch
+
+This function will try to stitch patches in the same LoD group together for the highest LoD.
+
+Only single missing vertice cracks will be fixed.
+
+Vertices will be joined at the patch side a crack is first found, at the other side
+of the patch (on the same row or column) the vertices will not be joined and cracks
+might still appear at that side.
+===============
+*/
+int R_TryStitchingPatch( int grid1num ) {
+ int j, numstitches;
+ srfGridMesh_t *grid1, *grid2;
+
+ numstitches = 0;
+ grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;
+ for ( j = 0; j < s_worldData.numsurfaces; j++ ) {
+ //
+ grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;
+ // if this surface is not a grid
+ if ( grid2->surfaceType != SF_GRID ) continue;
+ // grids in the same LOD group should have the exact same lod radius
+ if ( grid1->lodRadius != grid2->lodRadius ) continue;
+ // grids in the same LOD group should have the exact same lod origin
+ if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;
+ if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;
+ if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;
+ //
+ while (R_StitchPatches(grid1num, j))
+ {
+ numstitches++;
+ }
+ }
+ return numstitches;
+}
+
+/*
+===============
+R_StitchAllPatches
+===============
+*/
+void R_StitchAllPatches( void ) {
+ int i, stitched, numstitches;
+ srfGridMesh_t *grid1;
+
+ numstitches = 0;
+ do
+ {
+ stitched = false;
+ for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
+ //
+ grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;
+ // if this surface is not a grid
+ if ( grid1->surfaceType != SF_GRID )
+ continue;
+ //
+ if ( grid1->lodStitched )
+ continue;
+ //
+ grid1->lodStitched = true;
+ stitched = true;
+ //
+ numstitches += R_TryStitchingPatch( i );
+ }
+ }
+ while (stitched);
+ ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches );
+}
+
+/*
+===============
+R_MovePatchSurfacesToHunk
+===============
+*/
+void R_MovePatchSurfacesToHunk(void) {
+ int i, size;
+ srfGridMesh_t *grid, *hunkgrid;
+
+ for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
+ //
+ grid = (srfGridMesh_t *) s_worldData.surfaces[i].data;
+ // if this surface is not a grid
+ if ( grid->surfaceType != SF_GRID )
+ continue;
+ //
+ size = (grid->width * grid->height - 1) * sizeof( drawVert_t ) + sizeof( *grid );
+ hunkgrid = (srfGridMesh_t*)ri.Hunk_Alloc( size, h_low );
+ Com_Memcpy(hunkgrid, grid, size);
+
+ hunkgrid->widthLodError = (float*)ri.Hunk_Alloc( grid->width * 4, h_low );
+ Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 );
+
+ hunkgrid->heightLodError = (float*)ri.Hunk_Alloc( grid->height * 4, h_low );
+ Com_Memcpy( hunkgrid->heightLodError, grid->heightLodError, grid->height * 4 );
+
+ R_FreeSurfaceGridMesh( grid );
+
+ s_worldData.surfaces[i].data = (surfaceType_t*) hunkgrid;
+ }
+}
+
+/*
+===============
+R_LoadSurfaces
+===============
+*/
+static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) {
+ dsurface_t *in;
+ msurface_t *out;
+ drawVert_t *dv;
+ int *indexes;
+ int count;
+ int numFaces, numMeshes, numTriSurfs, numFlares;
+ int i;
+
+ numFaces = 0;
+ numMeshes = 0;
+ numTriSurfs = 0;
+ numFlares = 0;
+
+ in = (dsurface_t*)(fileBase + surfs->fileofs);
+ if (surfs->filelen % sizeof(*in))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ count = surfs->filelen / sizeof(*in);
+
+ dv = (drawVert_t*)(fileBase + verts->fileofs);
+ if (verts->filelen % sizeof(*dv))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+
+ indexes = (int*)(fileBase + indexLump->fileofs);
+ if ( indexLump->filelen % sizeof(*indexes))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+
+ out = (msurface_t*)ri.Hunk_Alloc ( count * sizeof(*out), h_low );
+
+ s_worldData.surfaces = out;
+ s_worldData.numsurfaces = count;
+
+ for ( i = 0 ; i < count ; i++, in++, out++ ) {
+ switch ( LittleLong( in->surfaceType ) ) {
+ case MST_PATCH:
+ ParseMesh ( in, dv, out );
+ numMeshes++;
+ break;
+ case MST_TRIANGLE_SOUP:
+ ParseTriSurf( in, dv, out, indexes );
+ numTriSurfs++;
+ break;
+ case MST_PLANAR:
+ ParseFace( in, dv, out, indexes );
+ numFaces++;
+ break;
+ case MST_FLARE:
+ ParseFlare( in, dv, out, indexes );
+ numFlares++;
+ break;
+ default:
+ ri.Error( ERR_DROP, "Bad surfaceType" );
+ }
+ }
+
+#ifdef PATCH_STITCHING
+ R_StitchAllPatches();
+#endif
+
+ R_FixSharedVertexLodError();
+
+#ifdef PATCH_STITCHING
+ R_MovePatchSurfacesToHunk();
+#endif
+
+ ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n",
+ numFaces, numMeshes, numTriSurfs, numFlares );
+}
+
+
+
+/*
+=================
+R_LoadSubmodels
+=================
+*/
+static void R_LoadSubmodels( lump_t *l ) {
+ dmodel_t *in;
+ bmodel_t *out;
+ int i, j, count;
+
+ in = (dmodel_t*)(fileBase + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ count = l->filelen / sizeof(*in);
+
+ s_worldData.bmodels = out = (bmodel_t*)ri.Hunk_Alloc( count * sizeof(*out), h_low );
+
+ for ( i=0 ; i<count ; i++, in++, out++ ) {
+ model_t *model;
+
+ model = R_AllocModel();
+
+ assert( model != NULL ); // this should never happen
+ if ( model == NULL ) {
+ ri.Error(ERR_DROP, "R_LoadSubmodels: R_AllocModel() failed");
+ }
+
+ model->type = MOD_BRUSH;
+ model->bmodel = out;
+ Com_sprintf( model->name, sizeof( model->name ), "*%d", i );
+
+ for (j=0 ; j<3 ; j++) {
+ out->bounds[0][j] = LittleFloat (in->mins[j]);
+ out->bounds[1][j] = LittleFloat (in->maxs[j]);
+ }
+
+ out->firstSurface = s_worldData.surfaces + LittleLong( in->firstSurface );
+ out->numSurfaces = LittleLong( in->numSurfaces );
+ }
+}
+
+
+
+//==================================================================
+
+/*
+=================
+R_SetParent
+=================
+*/
+static void R_SetParent (mnode_t *node, mnode_t *parent)
+{
+ node->parent = parent;
+ if (node->contents != -1)
+ return;
+ R_SetParent (node->children[0], node);
+ R_SetParent (node->children[1], node);
+}
+
+/*
+=================
+R_LoadNodesAndLeafs
+=================
+*/
+static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) {
+ int i, j, p;
+ dnode_t *in;
+ dleaf_t *inLeaf;
+ mnode_t *out;
+ int numNodes, numLeafs;
+
+ in = (dnode_t*)(fileBase + nodeLump->fileofs);
+ if (nodeLump->filelen % sizeof(dnode_t) ||
+ leafLump->filelen % sizeof(dleaf_t) ) {
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ }
+ numNodes = nodeLump->filelen / sizeof(dnode_t);
+ numLeafs = leafLump->filelen / sizeof(dleaf_t);
+
+ out = (mnode_t*)ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low);
+
+ s_worldData.nodes = out;
+ s_worldData.numnodes = numNodes + numLeafs;
+ s_worldData.numDecisionNodes = numNodes;
+
+ // load nodes
+ for ( i=0 ; i<numNodes; i++, in++, out++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ out->mins[j] = LittleLong (in->mins[j]);
+ out->maxs[j] = LittleLong (in->maxs[j]);
+ }
+
+ p = LittleLong(in->planeNum);
+ out->plane = s_worldData.planes + p;
+
+ out->contents = CONTENTS_NODE; // differentiate from leafs
+
+ for (j=0 ; j<2 ; j++)
+ {
+ p = LittleLong (in->children[j]);
+ if (p >= 0)
+ out->children[j] = s_worldData.nodes + p;
+ else
+ out->children[j] = s_worldData.nodes + numNodes + (-1 - p);
+ }
+ }
+
+ // load leafs
+ inLeaf = (dleaf_t*)(fileBase + leafLump->fileofs);
+ for ( i=0 ; i<numLeafs ; i++, inLeaf++, out++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ out->mins[j] = LittleLong (inLeaf->mins[j]);
+ out->maxs[j] = LittleLong (inLeaf->maxs[j]);
+ }
+
+ out->cluster = LittleLong(inLeaf->cluster);
+ out->area = LittleLong(inLeaf->area);
+
+ if ( out->cluster >= s_worldData.numClusters ) {
+ s_worldData.numClusters = out->cluster + 1;
+ }
+
+ out->firstmarksurface = s_worldData.marksurfaces +
+ LittleLong(inLeaf->firstLeafSurface);
+ out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces);
+ }
+
+ // chain decendants
+ R_SetParent (s_worldData.nodes, NULL);
+}
+
+//=============================================================================
+
+/*
+=================
+R_LoadShaders
+=================
+*/
+static void R_LoadShaders( lump_t *l ) {
+ int i, count;
+ dshader_t *in, *out;
+
+ in = (dshader_t*)(fileBase + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ count = l->filelen / sizeof(*in);
+ out = (dshader_t*)ri.Hunk_Alloc ( count*sizeof(*out), h_low );
+
+ s_worldData.shaders = out;
+ s_worldData.numShaders = count;
+
+ Com_Memcpy( out, in, count*sizeof(*out) );
+
+ for ( i=0 ; i<count ; i++ ) {
+ out[i].surfaceFlags = LittleLong( out[i].surfaceFlags );
+ out[i].contentFlags = LittleLong( out[i].contentFlags );
+ }
+}
+
+
+/*
+=================
+R_LoadMarksurfaces
+=================
+*/
+static void R_LoadMarksurfaces (lump_t *l)
+{
+ int i, j, count;
+ int *in;
+ msurface_t **out;
+
+ in = (int*)(fileBase + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ count = l->filelen / sizeof(*in);
+ out = (msurface_t**)ri.Hunk_Alloc ( count*sizeof(*out), h_low);
+
+ s_worldData.marksurfaces = out;
+ s_worldData.nummarksurfaces = count;
+
+ for ( i=0 ; i<count ; i++)
+ {
+ j = LittleLong(in[i]);
+ out[i] = s_worldData.surfaces + j;
+ }
+}
+
+
+/*
+=================
+R_LoadPlanes
+=================
+*/
+static void R_LoadPlanes( lump_t *l ) {
+ int i, j;
+ cplane_t *out;
+ dplane_t *in;
+ int count;
+ int bits;
+
+ in = (dplane_t*)(fileBase + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ count = l->filelen / sizeof(*in);
+ out = (cplane_t*)ri.Hunk_Alloc ( count*2*sizeof(*out), h_low);
+
+ s_worldData.planes = out;
+ s_worldData.numplanes = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++) {
+ bits = 0;
+ for (j=0 ; j<3 ; j++) {
+ out->normal[j] = LittleFloat (in->normal[j]);
+ if (out->normal[j] < 0) {
+ bits |= 1<<j;
+ }
+ }
+
+ out->dist = LittleFloat (in->dist);
+ out->type = PlaneTypeForNormal( out->normal );
+ out->signbits = bits;
+ }
+}
+
+/*
+=================
+R_LoadFogs
+
+=================
+*/
+static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) {
+ int i;
+ fog_t *out;
+ dfog_t *fogs;
+ dbrush_t *brushes, *brush;
+ dbrushside_t *sides;
+ int count, brushesCount, sidesCount;
+ int sideNum;
+ int planeNum;
+ shader_t *shader;
+ float d;
+ int firstSide;
+
+ fogs = (dfog_t*)(fileBase + l->fileofs);
+ if (l->filelen % sizeof(*fogs)) {
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ }
+ count = l->filelen / sizeof(*fogs);
+
+ // create fog structures for them
+ s_worldData.numfogs = count + 1;
+ s_worldData.fogs = (fog_t*)ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low);
+ out = s_worldData.fogs + 1;
+
+ if ( !count ) {
+ return;
+ }
+
+ brushes = (dbrush_t*)(fileBase + brushesLump->fileofs);
+ if (brushesLump->filelen % sizeof(*brushes)) {
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ }
+ brushesCount = brushesLump->filelen / sizeof(*brushes);
+
+ sides = (dbrushside_t*)(fileBase + sidesLump->fileofs);
+ if (sidesLump->filelen % sizeof(*sides)) {
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ }
+ sidesCount = sidesLump->filelen / sizeof(*sides);
+
+ for ( i=0 ; i<count ; i++, fogs++) {
+ out->originalBrushNumber = LittleLong( fogs->brushNum );
+
+ if ( (unsigned)out->originalBrushNumber >= brushesCount ) {
+ ri.Error( ERR_DROP, "fog brushNumber out of range" );
+ }
+ brush = brushes + out->originalBrushNumber;
+
+ firstSide = LittleLong( brush->firstSide );
+
+ if ( (unsigned)firstSide > sidesCount - 6 ) {
+ ri.Error( ERR_DROP, "fog brush sideNumber out of range" );
+ }
+
+ // brushes are always sorted with the axial sides first
+ sideNum = firstSide + 0;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist;
+
+ sideNum = firstSide + 1;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[1][0] = s_worldData.planes[ planeNum ].dist;
+
+ sideNum = firstSide + 2;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist;
+
+ sideNum = firstSide + 3;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[1][1] = s_worldData.planes[ planeNum ].dist;
+
+ sideNum = firstSide + 4;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist;
+
+ sideNum = firstSide + 5;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[1][2] = s_worldData.planes[ planeNum ].dist;
+
+ // get information from the shader for fog parameters
+ shader = R_FindShader( fogs->shader, LIGHTMAP_NONE, true );
+
+ out->parms = shader->fogParms;
+
+ out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight,
+ shader->fogParms.color[1] * tr.identityLight,
+ shader->fogParms.color[2] * tr.identityLight, 1.0 );
+
+ d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque;
+ out->tcScale = 1.0f / ( d * 8 );
+
+ // set the gradient vector
+ sideNum = LittleLong( fogs->visibleSide );
+
+ if ( sideNum == -1 ) {
+ out->hasSurface = false;
+ } else {
+ out->hasSurface = true;
+ planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum );
+ VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface );
+ out->surface[3] = -s_worldData.planes[ planeNum ].dist;
+ }
+
+ out++;
+ }
+
+}
+
+
+/*
+================
+R_LoadLightGrid
+
+================
+*/
+void R_LoadLightGrid( lump_t *l ) {
+ int i;
+ vec3_t maxs;
+ int numGridPoints;
+ world_t *w;
+ float *wMins, *wMaxs;
+
+ w = &s_worldData;
+
+ w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0];
+ w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1];
+ w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2];
+
+ wMins = w->bmodels[0].bounds[0];
+ wMaxs = w->bmodels[0].bounds[1];
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ w->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] );
+ maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] );
+ w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1;
+ }
+
+ numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2];
+
+ if ( l->filelen != numGridPoints * 8 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: light grid mismatch\n" );
+ w->lightGridData = NULL;
+ return;
+ }
+
+ w->lightGridData = (byte*)ri.Hunk_Alloc( l->filelen, h_low );
+ Com_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen );
+
+ // deal with overbright bits
+ for ( i = 0 ; i < numGridPoints ; i++ ) {
+ R_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] );
+ R_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] );
+ }
+}
+
+/*
+================
+R_LoadEntities
+================
+*/
+void R_LoadEntities( lump_t *l ) {
+ char *p, *token, *s;
+ char keyname[MAX_TOKEN_CHARS];
+ char value[MAX_TOKEN_CHARS];
+ world_t *w;
+
+ w = &s_worldData;
+ w->lightGridSize[0] = 64;
+ w->lightGridSize[1] = 64;
+ w->lightGridSize[2] = 128;
+
+ p = (char *)(fileBase + l->fileofs);
+
+ // store for reference by the cgame
+ w->entityString = (char*)ri.Hunk_Alloc( l->filelen + 1, h_low );
+ strcpy( w->entityString, p );
+ w->entityParsePoint = w->entityString;
+
+ token = COM_ParseExt( &p, qtrue );
+ if (!*token || *token != '{') {
+ return;
+ }
+
+ // only parse the world spawn
+ while ( 1 ) {
+ // parse key
+ token = COM_ParseExt( &p, qtrue );
+
+ if ( !*token || *token == '}' ) {
+ break;
+ }
+ Q_strncpyz(keyname, token, sizeof(keyname));
+
+ // parse value
+ token = COM_ParseExt( &p, qtrue );
+
+ if ( !*token || *token == '}' ) {
+ break;
+ }
+ Q_strncpyz(value, token, sizeof(value));
+
+ // check for remapping of shaders for vertex lighting
+ if (!Q_strncmp(keyname, "vertexremapshader", strlen("vertexremapshader")) ) {
+ s = strchr(value, ';');
+ if (!s) {
+ ri.Printf( PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value );
+ break;
+ }
+ *s++ = 0;
+ if (r_vertexLight->integer) {
+ R_RemapShader(value, s, "0");
+ }
+ continue;
+ }
+ // check for remapping of shaders
+ if (!Q_strncmp(keyname, "remapshader", strlen("remapshader")) ) {
+ s = strchr(value, ';');
+ if (!s) {
+ ri.Printf( PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value );
+ break;
+ }
+ *s++ = 0;
+ R_RemapShader(value, s, "0");
+ continue;
+ }
+ // check for a different grid size
+ if (!Q_stricmp(keyname, "gridsize")) {
+ sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] );
+ continue;
+ }
+ }
+}
+
+/*
+=================
+R_GetEntityToken
+=================
+*/
+bool R_GetEntityToken( char *buffer, int size ) {
+ const char *s;
+
+ s = COM_Parse( &s_worldData.entityParsePoint );
+ Q_strncpyz( buffer, s, size );
+ if ( !s_worldData.entityParsePoint && !s[0] ) {
+ s_worldData.entityParsePoint = s_worldData.entityString;
+ return false;
+ } else {
+ return true;
+ }
+}
+
+/*
+=================
+RE_LoadWorldMap
+
+Called directly from cgame
+=================
+*/
+void RE_LoadWorldMap( const char *name ) {
+ int i;
+ dheader_t *header;
+ union {
+ byte *b;
+ void *v;
+ } buffer;
+ byte *startMarker;
+
+ if ( tr.worldMapLoaded ) {
+ ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map" );
+ }
+
+ // set default sun direction to be used if it isn't
+ // overridden by a shader
+ tr.sunDirection[0] = 0.45f;
+ tr.sunDirection[1] = 0.3f;
+ tr.sunDirection[2] = 0.9f;
+
+ VectorNormalize( tr.sunDirection );
+
+ tr.worldMapLoaded = true;
+
+ // load it
+ ri.FS_ReadFile( name, &buffer.v );
+ if ( !buffer.b ) {
+ ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name);
+ }
+
+ // clear tr.world so if the level fails to load, the next
+ // try will not look at the partially loaded version
+ tr.world = NULL;
+
+ Com_Memset( &s_worldData, 0, sizeof( s_worldData ) );
+ Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) );
+
+ Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) );
+ COM_StripExtension(s_worldData.baseName, s_worldData.baseName, sizeof(s_worldData.baseName));
+
+ startMarker = (byte*)ri.Hunk_Alloc(0, h_low);
+ c_gridVerts = 0;
+
+ header = (dheader_t *)buffer.b;
+ fileBase = (byte *)header;
+
+ i = LittleLong (header->version);
+ if ( i != BSP_VERSION ) {
+ ri.Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)",
+ name, i, BSP_VERSION);
+ }
+
+ // swap all the lumps
+ for (i=0 ; i<sizeof(dheader_t)/4 ; i++) {
+ ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
+ }
+
+ // load into heap
+ R_LoadShaders( &header->lumps[LUMP_SHADERS] );
+ R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS] );
+ R_LoadPlanes (&header->lumps[LUMP_PLANES]);
+ R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] );
+ R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] );
+ R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]);
+ R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]);
+ R_LoadSubmodels (&header->lumps[LUMP_MODELS]);
+ R_LoadVisibility( &header->lumps[LUMP_VISIBILITY] );
+ R_LoadEntities( &header->lumps[LUMP_ENTITIES] );
+ R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] );
+
+ s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker;
+
+ // only set tr.world now that we know the entire level has loaded properly
+ tr.world = &s_worldData;
+
+ ri.FS_FreeFile( buffer.v );
+}
diff --git a/src/renderergl1/tr_cmds.cpp b/src/renderergl1/tr_cmds.cpp
new file mode 100644
index 0000000..12bfac4
--- /dev/null
+++ b/src/renderergl1/tr_cmds.cpp
@@ -0,0 +1,601 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "tr_local.h"
+
+/*
+=====================
+R_PerformanceCounters
+=====================
+*/
+void R_PerformanceCounters( void ) {
+ if ( !r_speeds->integer ) {
+ // clear the counters even if we aren't printing
+ Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
+ Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
+ return;
+ }
+
+ if (r_speeds->integer == 1) {
+ ri.Printf (PRINT_ALL, "%i/%i shaders/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n",
+ backEnd.pc.c_shaders, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes,
+ backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3,
+ R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) );
+ } else if (r_speeds->integer == 2) {
+ ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
+ tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out,
+ tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out );
+ ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
+ tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out,
+ tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out );
+ } else if (r_speeds->integer == 3) {
+ ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster );
+ } else if (r_speeds->integer == 4) {
+ if ( backEnd.pc.c_dlightVertexes ) {
+ ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n",
+ tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled,
+ backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 );
+ }
+ }
+ else if (r_speeds->integer == 5 )
+ {
+ ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar );
+ }
+ else if (r_speeds->integer == 6 )
+ {
+ ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n",
+ backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders );
+ }
+
+ Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
+ Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
+}
+
+
+/*
+====================
+R_IssueRenderCommands
+====================
+*/
+void R_IssueRenderCommands( bool runPerformanceCounters ) {
+ renderCommandList_t *cmdList;
+
+ cmdList = &backEndData->commands;
+ assert(cmdList);
+ // add an end-of-list command
+ *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST;
+
+ // clear it out, in case this is a sync and not a buffer flip
+ cmdList->used = 0;
+
+ if ( runPerformanceCounters ) {
+ R_PerformanceCounters();
+ }
+
+ // actually start the commands going
+ if ( !r_skipBackEnd->integer ) {
+ // let it start on the new batch
+ RB_ExecuteRenderCommands( cmdList->cmds );
+ }
+}
+
+
+/*
+====================
+R_IssuePendingRenderCommands
+
+Issue any pending commands and wait for them to complete.
+====================
+*/
+void R_IssuePendingRenderCommands( void ) {
+ if ( !tr.registered ) {
+ return;
+ }
+ R_IssueRenderCommands( false );
+}
+
+/*
+============
+R_GetCommandBufferReserved
+
+make sure there is enough command space
+============
+*/
+void *R_GetCommandBufferReserved( int bytes, int reservedBytes ) {
+ renderCommandList_t *cmdList;
+
+ cmdList = &backEndData->commands;
+ bytes = PAD(bytes, sizeof(void *));
+
+ // always leave room for the end of list command
+ if ( cmdList->used + bytes + sizeof( int ) + reservedBytes > MAX_RENDER_COMMANDS ) {
+ if ( bytes > MAX_RENDER_COMMANDS - sizeof( int ) ) {
+ ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
+ }
+ // if we run out of room, just start dropping commands
+ return NULL;
+ }
+
+ cmdList->used += bytes;
+
+ return cmdList->cmds + cmdList->used - bytes;
+}
+
+/*
+=============
+R_GetCommandBuffer
+
+returns NULL if there is not enough space for important commands
+=============
+*/
+void *R_GetCommandBuffer( int bytes ) {
+ return R_GetCommandBufferReserved( bytes, PAD( sizeof( swapBuffersCommand_t ), sizeof(void *) ) );
+}
+
+
+/*
+=============
+R_AddDrawSurfCmd
+
+=============
+*/
+void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) {
+ drawSurfsCommand_t *cmd;
+
+ cmd = (drawSurfsCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_DRAW_SURFS;
+
+ cmd->drawSurfs = drawSurfs;
+ cmd->numDrawSurfs = numDrawSurfs;
+
+ cmd->refdef = tr.refdef;
+ cmd->viewParms = tr.viewParms;
+}
+
+
+/*
+=============
+RE_SetColor
+
+Passing NULL will set the color to white
+=============
+*/
+void RE_SetColor( const float *rgba ) {
+ setColorCommand_t *cmd;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ cmd = (setColorCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_SET_COLOR;
+ if ( !rgba ) {
+ static float colorWhite[4] = { 1, 1, 1, 1 };
+
+ rgba = colorWhite;
+ }
+
+ cmd->color[0] = rgba[0];
+ cmd->color[1] = rgba[1];
+ cmd->color[2] = rgba[2];
+ cmd->color[3] = rgba[3];
+}
+
+/*
+=============
+R_ClipRegion
+=============
+*/
+static bool R_ClipRegion ( float *x, float *y, float *w, float *h,
+ float *s1, float *t1, float *s2, float *t2 ) {
+ float left, top, right, bottom;
+ float _s1, _t1, _s2, _t2;
+ float clipLeft, clipTop, clipRight, clipBottom;
+
+ if (tr.clipRegion[2] <= tr.clipRegion[0] ||
+ tr.clipRegion[3] <= tr.clipRegion[1] ) {
+ return false;
+ }
+
+ left = *x;
+ top = *y;
+ right = *x + *w;
+ bottom = *y + *h;
+
+ _s1 = *s1;
+ _t1 = *t1;
+ _s2 = *s2;
+ _t2 = *t2;
+
+ clipLeft = tr.clipRegion[0];
+ clipTop = tr.clipRegion[1];
+ clipRight = tr.clipRegion[2];
+ clipBottom = tr.clipRegion[3];
+
+ // Completely clipped away
+ if ( right <= clipLeft || left >= clipRight ||
+ bottom <= clipTop || top >= clipBottom ) {
+ return true;
+ }
+
+ // Clip left edge
+ if ( left < clipLeft ) {
+ float f = ( clipLeft - left ) / ( right - left );
+ *s1 = ( f * ( _s2 - _s1 ) ) + _s1;
+ *x = clipLeft;
+ *w -= ( clipLeft - left );
+ }
+
+ // Clip right edge
+ if ( right > clipRight ) {
+ float f = ( clipRight - right ) / ( left - right );
+ *s2 = ( f * ( _s1 - _s2 ) ) + _s2;
+ *w = clipRight - *x;
+ }
+
+ // Clip top edge
+ if ( top < clipTop ) {
+ float f = ( clipTop - top ) / ( bottom - top );
+ *t1 = ( f * ( _t2 - _t1 ) ) + _t1;
+ *y = clipTop;
+ *h -= ( clipTop - top );
+ }
+
+ // Clip bottom edge
+ if ( bottom > clipBottom ) {
+ float f = ( clipBottom - bottom ) / ( top - bottom );
+ *t2 = ( f * ( _t1 - _t2 ) ) + _t2;
+ *h = clipBottom - *y;
+ }
+
+ return false;
+}
+
+/*
+=============
+RE_SetClipRegion
+=============
+*/
+void RE_SetClipRegion( const float *region ) {
+ if ( region == NULL ) {
+ Com_Memset( tr.clipRegion, 0, sizeof( vec4_t ) );
+ } else {
+ Vector4Copy( region, tr.clipRegion );
+ }
+}
+
+/*
+=============
+RE_StretchPic
+=============
+*/
+void RE_StretchPic ( float x, float y, float w, float h,
+ float s1, float t1, float s2, float t2, qhandle_t hShader ) {
+ stretchPicCommand_t *cmd;
+
+ if (!tr.registered) {
+ return;
+ }
+ if (R_ClipRegion(&x, &y, &w, &h, &s1, &t1, &s2, &t2)) {
+ return;
+ }
+ cmd = (stretchPicCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_STRETCH_PIC;
+ cmd->shader = R_GetShaderByHandle( hShader );
+ cmd->x = x;
+ cmd->y = y;
+ cmd->w = w;
+ cmd->h = h;
+ cmd->s1 = s1;
+ cmd->t1 = t1;
+ cmd->s2 = s2;
+ cmd->t2 = t2;
+}
+
+#define MODE_RED_CYAN 1
+#define MODE_RED_BLUE 2
+#define MODE_RED_GREEN 3
+#define MODE_GREEN_MAGENTA 4
+#define MODE_MAX MODE_GREEN_MAGENTA
+
+void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode)
+{
+ rgba[0] = rgba[1] = rgba[2] = rgba[3] = GL_TRUE;
+
+ if(colormode > MODE_MAX)
+ {
+ if(stereoFrame == STEREO_LEFT)
+ stereoFrame = STEREO_RIGHT;
+ else if(stereoFrame == STEREO_RIGHT)
+ stereoFrame = STEREO_LEFT;
+
+ colormode -= MODE_MAX;
+ }
+
+ if(colormode == MODE_GREEN_MAGENTA)
+ {
+ if(stereoFrame == STEREO_LEFT)
+ rgba[0] = rgba[2] = GL_FALSE;
+ else if(stereoFrame == STEREO_RIGHT)
+ rgba[1] = GL_FALSE;
+ }
+ else
+ {
+ if(stereoFrame == STEREO_LEFT)
+ rgba[1] = rgba[2] = GL_FALSE;
+ else if(stereoFrame == STEREO_RIGHT)
+ {
+ rgba[0] = GL_FALSE;
+
+ if(colormode == MODE_RED_BLUE)
+ rgba[1] = GL_FALSE;
+ else if(colormode == MODE_RED_GREEN)
+ rgba[2] = GL_FALSE;
+ }
+ }
+}
+
+
+/*
+====================
+RE_BeginFrame
+
+If running in stereo, RE_BeginFrame will be called twice
+for each RE_EndFrame
+====================
+*/
+void RE_BeginFrame( stereoFrame_t stereoFrame ) {
+ drawBufferCommand_t *cmd = NULL;
+ colorMaskCommand_t *colcmd = NULL;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ glState.finishCalled = false;
+
+ tr.frameCount++;
+ tr.frameSceneNum = 0;
+
+ //
+ // do overdraw measurement
+ //
+ if ( r_measureOverdraw->integer )
+ {
+ if ( glConfig.stencilBits < 4 )
+ {
+ ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
+ ri.Cvar_Set( "r_measureOverdraw", "0" );
+ r_measureOverdraw->modified = false;
+ }
+ else if ( r_shadows->integer == 2 )
+ {
+ ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" );
+ ri.Cvar_Set( "r_measureOverdraw", "0" );
+ r_measureOverdraw->modified = false;
+ }
+ else
+ {
+ R_IssuePendingRenderCommands();
+ qglEnable( GL_STENCIL_TEST );
+ qglStencilMask( ~0U );
+ qglClearStencil( 0U );
+ qglStencilFunc( GL_ALWAYS, 0U, ~0U );
+ qglStencilOp( GL_KEEP, GL_INCR, GL_INCR );
+ }
+ r_measureOverdraw->modified = false;
+ }
+ else
+ {
+ // this is only reached if it was on and is now off
+ if ( r_measureOverdraw->modified ) {
+ R_IssuePendingRenderCommands();
+ qglDisable( GL_STENCIL_TEST );
+ }
+ r_measureOverdraw->modified = false;
+ }
+
+ //
+ // texturemode stuff
+ //
+ if ( r_textureMode->modified ) {
+ R_IssuePendingRenderCommands();
+ GL_TextureMode( r_textureMode->string );
+ r_textureMode->modified = false;
+ }
+
+ //
+ // gamma stuff
+ //
+ if ( r_gamma->modified ) {
+ r_gamma->modified = false;
+
+ R_IssuePendingRenderCommands();
+ R_SetColorMappings();
+ }
+
+ // check for errors
+ if ( !r_ignoreGLErrors->integer )
+ {
+ int err;
+
+ R_IssuePendingRenderCommands();
+ if ((err = qglGetError()) != GL_NO_ERROR)
+ ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err);
+ }
+
+ if (glConfig.stereoEnabled) {
+ if( !(cmd = (drawBufferCommand_t*)R_GetCommandBuffer(sizeof(*cmd))) )
+ return;
+
+ cmd->commandId = RC_DRAW_BUFFER;
+
+ if ( stereoFrame == STEREO_LEFT ) {
+ cmd->buffer = (int)GL_BACK_LEFT;
+ } else if ( stereoFrame == STEREO_RIGHT ) {
+ cmd->buffer = (int)GL_BACK_RIGHT;
+ } else {
+ ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
+ }
+ }
+ else
+ {
+ if(r_anaglyphMode->integer)
+ {
+ if(r_anaglyphMode->modified)
+ {
+ // clear both, front and backbuffer.
+ qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+ qglDrawBuffer(GL_FRONT);
+ qglClear(GL_COLOR_BUFFER_BIT);
+ qglDrawBuffer(GL_BACK);
+ qglClear(GL_COLOR_BUFFER_BIT);
+
+ r_anaglyphMode->modified = false;
+ }
+
+ if(stereoFrame == STEREO_LEFT)
+ {
+ if( !(cmd = (drawBufferCommand_t*)R_GetCommandBuffer(sizeof(*cmd))) )
+ return;
+
+ if( !(colcmd = (colorMaskCommand_t*)R_GetCommandBuffer(sizeof(*colcmd))) )
+ return;
+ }
+ else if(stereoFrame == STEREO_RIGHT)
+ {
+ clearDepthCommand_t *cldcmd;
+
+ if( !(cldcmd = (clearDepthCommand_t*)R_GetCommandBuffer(sizeof(*cldcmd))) )
+ return;
+
+ cldcmd->commandId = RC_CLEARDEPTH;
+
+ if( !(colcmd = (colorMaskCommand_t*)R_GetCommandBuffer(sizeof(*colcmd))) )
+ return;
+ }
+ else
+ ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
+
+ R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer);
+ colcmd->commandId = RC_COLORMASK;
+ }
+ else
+ {
+ if(stereoFrame != STEREO_CENTER)
+ ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
+
+ if( !(cmd = (drawBufferCommand_t*)R_GetCommandBuffer(sizeof(*cmd))) )
+ return;
+ }
+
+ if(cmd)
+ {
+ cmd->commandId = RC_DRAW_BUFFER;
+
+ if(r_anaglyphMode->modified)
+ {
+ qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ r_anaglyphMode->modified = false;
+ }
+
+ if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
+ cmd->buffer = (int)GL_FRONT;
+ else
+ cmd->buffer = (int)GL_BACK;
+ }
+ }
+
+ tr.refdef.stereoFrame = stereoFrame;
+}
+
+
+/*
+=============
+RE_EndFrame
+
+Returns the number of msec spent in the back end
+=============
+*/
+void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
+ swapBuffersCommand_t *cmd;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ cmd = (swapBuffersCommand_t*)R_GetCommandBufferReserved( sizeof( *cmd ), 0 );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_SWAP_BUFFERS;
+
+ R_IssueRenderCommands( true );
+
+ R_InitNextFrame();
+
+ if ( frontEndMsec ) {
+ *frontEndMsec = tr.frontEndMsec;
+ }
+ tr.frontEndMsec = 0;
+ if ( backEndMsec ) {
+ *backEndMsec = backEnd.pc.msec;
+ }
+ backEnd.pc.msec = 0;
+}
+
+/*
+=============
+RE_TakeVideoFrame
+=============
+*/
+void RE_TakeVideoFrame( int width, int height,
+ byte *captureBuffer, byte *encodeBuffer, bool motionJpeg )
+{
+ videoFrameCommand_t *cmd;
+
+ if( !tr.registered ) {
+ return;
+ }
+
+ cmd = (videoFrameCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if( !cmd ) {
+ return;
+ }
+
+ cmd->commandId = RC_VIDEOFRAME;
+
+ cmd->width = width;
+ cmd->height = height;
+ cmd->captureBuffer = captureBuffer;
+ cmd->encodeBuffer = encodeBuffer;
+ cmd->motionJpeg = motionJpeg;
+}
diff --git a/src/renderergl1/tr_curve.cpp b/src/renderergl1/tr_curve.cpp
new file mode 100644
index 0000000..a56d026
--- /dev/null
+++ b/src/renderergl1/tr_curve.cpp
@@ -0,0 +1,627 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+/*
+
+This file does all of the processing necessary to turn a raw grid of points
+read from the map file into a srfGridMesh_t ready for rendering.
+
+The level of detail solution is direction independent, based only on subdivided
+distance from the true curve.
+
+Only a single entry point:
+
+srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
+ drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
+
+*/
+
+
+/*
+============
+LerpDrawVert
+============
+*/
+static void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) {
+ out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]);
+ out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]);
+ out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]);
+
+ out->st[0] = 0.5f * (a->st[0] + b->st[0]);
+ out->st[1] = 0.5f * (a->st[1] + b->st[1]);
+
+ out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]);
+ out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]);
+
+ out->color[0] = (a->color[0] + b->color[0]) >> 1;
+ out->color[1] = (a->color[1] + b->color[1]) >> 1;
+ out->color[2] = (a->color[2] + b->color[2]) >> 1;
+ out->color[3] = (a->color[3] + b->color[3]) >> 1;
+}
+
+/*
+============
+Transpose
+============
+*/
+static void Transpose( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
+ int i, j;
+ drawVert_t temp;
+
+ if ( width > height ) {
+ for ( i = 0 ; i < height ; i++ ) {
+ for ( j = i + 1 ; j < width ; j++ ) {
+ if ( j < height ) {
+ // swap the value
+ temp = ctrl[j][i];
+ ctrl[j][i] = ctrl[i][j];
+ ctrl[i][j] = temp;
+ } else {
+ // just copy
+ ctrl[j][i] = ctrl[i][j];
+ }
+ }
+ }
+ } else {
+ for ( i = 0 ; i < width ; i++ ) {
+ for ( j = i + 1 ; j < height ; j++ ) {
+ if ( j < width ) {
+ // swap the value
+ temp = ctrl[i][j];
+ ctrl[i][j] = ctrl[j][i];
+ ctrl[j][i] = temp;
+ } else {
+ // just copy
+ ctrl[i][j] = ctrl[j][i];
+ }
+ }
+ }
+ }
+
+}
+
+
+/*
+=================
+MakeMeshNormals
+
+Handles all the complicated wrapping and degenerate cases
+=================
+*/
+static void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
+ int i, j, k, dist;
+ vec3_t normal;
+ vec3_t sum;
+ int count = 0;
+ vec3_t base;
+ vec3_t delta;
+ int x, y;
+ drawVert_t *dv;
+ vec3_t around[8], temp;
+ bool good[8];
+ bool wrapWidth, wrapHeight;
+ float len;
+ static int neighbors[8][2] = {
+ {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
+ };
+
+ wrapWidth = false;
+ for ( i = 0 ; i < height ; i++ ) {
+ VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta );
+ len = VectorLengthSquared( delta );
+ if ( len > 1.0 ) {
+ break;
+ }
+ }
+ if ( i == height ) {
+ wrapWidth = true;
+ }
+
+ wrapHeight = false;
+ for ( i = 0 ; i < width ; i++ ) {
+ VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta );
+ len = VectorLengthSquared( delta );
+ if ( len > 1.0 ) {
+ break;
+ }
+ }
+ if ( i == width) {
+ wrapHeight = true;
+ }
+
+
+ for ( i = 0 ; i < width ; i++ ) {
+ for ( j = 0 ; j < height ; j++ ) {
+ count = 0;
+ dv = &ctrl[j][i];
+ VectorCopy( dv->xyz, base );
+ for ( k = 0 ; k < 8 ; k++ ) {
+ VectorClear( around[k] );
+ good[k] = false;
+
+ for ( dist = 1 ; dist <= 3 ; dist++ ) {
+ x = i + neighbors[k][0] * dist;
+ y = j + neighbors[k][1] * dist;
+ if ( wrapWidth ) {
+ if ( x < 0 ) {
+ x = width - 1 + x;
+ } else if ( x >= width ) {
+ x = 1 + x - width;
+ }
+ }
+ if ( wrapHeight ) {
+ if ( y < 0 ) {
+ y = height - 1 + y;
+ } else if ( y >= height ) {
+ y = 1 + y - height;
+ }
+ }
+
+ if ( x < 0 || x >= width || y < 0 || y >= height ) {
+ break; // edge of patch
+ }
+ VectorSubtract( ctrl[y][x].xyz, base, temp );
+ if ( VectorNormalize2( temp, temp ) == 0 ) {
+ continue; // degenerate edge, get more dist
+ } else {
+ good[k] = true;
+ VectorCopy( temp, around[k] );
+ break; // good edge
+ }
+ }
+ }
+
+ VectorClear( sum );
+ for ( k = 0 ; k < 8 ; k++ ) {
+ if ( !good[k] || !good[(k+1)&7] ) {
+ continue; // didn't get two points
+ }
+ CrossProduct( around[(k+1)&7], around[k], normal );
+ if ( VectorNormalize2( normal, normal ) == 0 ) {
+ continue;
+ }
+ VectorAdd( normal, sum, sum );
+ count++;
+ }
+ //if ( count == 0 ) {
+ // printf("bad normal\n");
+ //}
+ VectorNormalize2( sum, dv->normal );
+ }
+ }
+}
+
+
+/*
+============
+InvertCtrl
+============
+*/
+static void InvertCtrl( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
+ int i, j;
+ drawVert_t temp;
+
+ for ( i = 0 ; i < height ; i++ ) {
+ for ( j = 0 ; j < width/2 ; j++ ) {
+ temp = ctrl[i][j];
+ ctrl[i][j] = ctrl[i][width-1-j];
+ ctrl[i][width-1-j] = temp;
+ }
+ }
+}
+
+
+/*
+=================
+InvertErrorTable
+=================
+*/
+static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) {
+ int i;
+ float copy[2][MAX_GRID_SIZE];
+
+ Com_Memcpy( copy, errorTable, sizeof( copy ) );
+
+ for ( i = 0 ; i < width ; i++ ) {
+ errorTable[1][i] = copy[0][i]; //[width-1-i];
+ }
+
+ for ( i = 0 ; i < height ; i++ ) {
+ errorTable[0][i] = copy[1][height-1-i];
+ }
+
+}
+
+/*
+==================
+PutPointsOnCurve
+==================
+*/
+static void PutPointsOnCurve( drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
+ int width, int height ) {
+ int i, j;
+ drawVert_t prev, next;
+
+ for ( i = 0 ; i < width ; i++ ) {
+ for ( j = 1 ; j < height ; j += 2 ) {
+ LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev );
+ LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next );
+ LerpDrawVert( &prev, &next, &ctrl[j][i] );
+ }
+ }
+
+
+ for ( j = 0 ; j < height ; j++ ) {
+ for ( i = 1 ; i < width ; i += 2 ) {
+ LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev );
+ LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next );
+ LerpDrawVert( &prev, &next, &ctrl[j][i] );
+ }
+ }
+}
+
+/*
+=================
+R_CreateSurfaceGridMesh
+=================
+*/
+srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height,
+ drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE] ) {
+ int i, j, size;
+ drawVert_t *vert;
+ vec3_t tmpVec;
+ srfGridMesh_t *grid;
+
+ // copy the results out to a grid
+ size = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid );
+
+#ifdef PATCH_STITCHING
+ grid = /*ri.Hunk_Alloc*/ (srfGridMesh_t*)ri.Malloc( size );
+ Com_Memset(grid, 0, size);
+
+ grid->widthLodError = /*ri.Hunk_Alloc*/ (float*)ri.Malloc( width * 4 );
+ Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
+
+ grid->heightLodError = /*ri.Hunk_Alloc*/ (float*)ri.Malloc( height * 4 );
+ Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
+#else
+ grid = ri.Hunk_Alloc( size );
+ Com_Memset(grid, 0, size);
+
+ grid->widthLodError = ri.Hunk_Alloc( width * 4 );
+ Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
+
+ grid->heightLodError = ri.Hunk_Alloc( height * 4 );
+ Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
+#endif
+
+ grid->width = width;
+ grid->height = height;
+ grid->surfaceType = SF_GRID;
+ ClearBounds( grid->meshBounds[0], grid->meshBounds[1] );
+ for ( i = 0 ; i < width ; i++ ) {
+ for ( j = 0 ; j < height ; j++ ) {
+ vert = &grid->verts[j*width+i];
+ *vert = ctrl[j][i];
+ AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] );
+ }
+ }
+
+ // compute local origin and bounds
+ VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin );
+ VectorScale( grid->localOrigin, 0.5f, grid->localOrigin );
+ VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec );
+ grid->meshRadius = VectorLength( tmpVec );
+
+ VectorCopy( grid->localOrigin, grid->lodOrigin );
+ grid->lodRadius = grid->meshRadius;
+ //
+ return grid;
+}
+
+/*
+=================
+R_FreeSurfaceGridMesh
+=================
+*/
+void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) {
+ ri.Free(grid->widthLodError);
+ ri.Free(grid->heightLodError);
+ ri.Free(grid);
+}
+
+/*
+=================
+R_SubdividePatchToGrid
+=================
+*/
+srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
+ drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
+ int i, j, k, l;
+ drawVert_t_cleared( prev );
+ drawVert_t_cleared( next );
+ drawVert_t_cleared( mid );
+ float len, maxLen;
+ int dir;
+ int t;
+ drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
+ float errorTable[2][MAX_GRID_SIZE];
+
+ for ( i = 0 ; i < width ; i++ ) {
+ for ( j = 0 ; j < height ; j++ ) {
+ ctrl[j][i] = points[j*width+i];
+ }
+ }
+
+ for ( dir = 0 ; dir < 2 ; dir++ ) {
+
+ for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {
+ errorTable[dir][j] = 0;
+ }
+
+ // horizontal subdivisions
+ for ( j = 0 ; j + 2 < width ; j += 2 ) {
+ // check subdivided midpoints against control points
+
+ // FIXME: also check midpoints of adjacent patches against the control points
+ // this would basically stitch all patches in the same LOD group together.
+
+ maxLen = 0;
+ for ( i = 0 ; i < height ; i++ ) {
+ vec3_t midxyz;
+ vec3_t midxyz2;
+ vec3_t dir;
+ vec3_t projected;
+ float d;
+
+ // calculate the point on the curve
+ for ( l = 0 ; l < 3 ; l++ ) {
+ midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2
+ + ctrl[i][j+2].xyz[l] ) * 0.25f;
+ }
+
+ // see how far off the line it is
+ // using dist-from-line will not account for internal
+ // texture warping, but it gives a lot less polygons than
+ // dist-from-midpoint
+ VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz );
+ VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir );
+ VectorNormalize( dir );
+
+ d = DotProduct( midxyz, dir );
+ VectorScale( dir, d, projected );
+ VectorSubtract( midxyz, projected, midxyz2);
+ len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later
+ if ( len > maxLen ) {
+ maxLen = len;
+ }
+ }
+
+ maxLen = sqrt(maxLen);
+
+ // if all the points are on the lines, remove the entire columns
+ if ( maxLen < 0.1f ) {
+ errorTable[dir][j+1] = 999;
+ continue;
+ }
+
+ // see if we want to insert subdivided columns
+ if ( width + 2 > MAX_GRID_SIZE ) {
+ errorTable[dir][j+1] = 1.0f/maxLen;
+ continue; // can't subdivide any more
+ }
+
+ if ( maxLen <= r_subdivisions->value ) {
+ errorTable[dir][j+1] = 1.0f/maxLen;
+ continue; // didn't need subdivision
+ }
+
+ errorTable[dir][j+2] = 1.0f/maxLen;
+
+ // insert two columns and replace the peak
+ width += 2;
+ for ( i = 0 ; i < height ; i++ ) {
+ LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev );
+ LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next );
+ LerpDrawVert( &prev, &next, &mid );
+
+ for ( k = width - 1 ; k > j + 3 ; k-- ) {
+ ctrl[i][k] = ctrl[i][k-2];
+ }
+ ctrl[i][j + 1] = prev;
+ ctrl[i][j + 2] = mid;
+ ctrl[i][j + 3] = next;
+ }
+
+ // back up and recheck this set again, it may need more subdivision
+ j -= 2;
+
+ }
+
+ Transpose( width, height, ctrl );
+ t = width;
+ width = height;
+ height = t;
+ }
+
+
+ // put all the aproximating points on the curve
+ PutPointsOnCurve( ctrl, width, height );
+
+ // cull out any rows or columns that are colinear
+ for ( i = 1 ; i < width-1 ; i++ ) {
+ if ( errorTable[0][i] != 999 ) {
+ continue;
+ }
+ for ( j = i+1 ; j < width ; j++ ) {
+ for ( k = 0 ; k < height ; k++ ) {
+ ctrl[k][j-1] = ctrl[k][j];
+ }
+ errorTable[0][j-1] = errorTable[0][j];
+ }
+ width--;
+ }
+
+ for ( i = 1 ; i < height-1 ; i++ ) {
+ if ( errorTable[1][i] != 999 ) {
+ continue;
+ }
+ for ( j = i+1 ; j < height ; j++ ) {
+ for ( k = 0 ; k < width ; k++ ) {
+ ctrl[j-1][k] = ctrl[j][k];
+ }
+ errorTable[1][j-1] = errorTable[1][j];
+ }
+ height--;
+ }
+
+#if 1
+ // flip for longest tristrips as an optimization
+ // the results should be visually identical with or
+ // without this step
+ if ( height > width ) {
+ Transpose( width, height, ctrl );
+ InvertErrorTable( errorTable, width, height );
+ t = width;
+ width = height;
+ height = t;
+ InvertCtrl( width, height, ctrl );
+ }
+#endif
+
+ // calculate normals
+ MakeMeshNormals( width, height, ctrl );
+
+ return R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
+}
+
+/*
+===============
+R_GridInsertColumn
+===============
+*/
+srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) {
+ int i, j;
+ int width, height, oldwidth;
+ drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
+ float errorTable[2][MAX_GRID_SIZE];
+ float lodRadius;
+ vec3_t lodOrigin;
+
+ oldwidth = 0;
+ width = grid->width + 1;
+ if (width > MAX_GRID_SIZE)
+ return NULL;
+ height = grid->height;
+ for (i = 0; i < width; i++) {
+ if (i == column) {
+ //insert new column
+ for (j = 0; j < grid->height; j++) {
+ LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] );
+ if (j == row)
+ VectorCopy(point, ctrl[j][i].xyz);
+ }
+ errorTable[0][i] = loderror;
+ continue;
+ }
+ errorTable[0][i] = grid->widthLodError[oldwidth];
+ for (j = 0; j < grid->height; j++) {
+ ctrl[j][i] = grid->verts[j * grid->width + oldwidth];
+ }
+ oldwidth++;
+ }
+ for (j = 0; j < grid->height; j++) {
+ errorTable[1][j] = grid->heightLodError[j];
+ }
+ // put all the aproximating points on the curve
+ //PutPointsOnCurve( ctrl, width, height );
+ // calculate normals
+ MakeMeshNormals( width, height, ctrl );
+
+ VectorCopy(grid->lodOrigin, lodOrigin);
+ lodRadius = grid->lodRadius;
+ // free the old grid
+ R_FreeSurfaceGridMesh(grid);
+ // create a new grid
+ grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
+ grid->lodRadius = lodRadius;
+ VectorCopy(lodOrigin, grid->lodOrigin);
+ return grid;
+}
+
+/*
+===============
+R_GridInsertRow
+===============
+*/
+srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) {
+ int i, j;
+ int width, height, oldheight;
+ drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
+ float errorTable[2][MAX_GRID_SIZE];
+ float lodRadius;
+ vec3_t lodOrigin;
+
+ oldheight = 0;
+ width = grid->width;
+ height = grid->height + 1;
+ if (height > MAX_GRID_SIZE)
+ return NULL;
+ for (i = 0; i < height; i++) {
+ if (i == row) {
+ //insert new row
+ for (j = 0; j < grid->width; j++) {
+ LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] );
+ if (j == column)
+ VectorCopy(point, ctrl[i][j].xyz);
+ }
+ errorTable[1][i] = loderror;
+ continue;
+ }
+ errorTable[1][i] = grid->heightLodError[oldheight];
+ for (j = 0; j < grid->width; j++) {
+ ctrl[i][j] = grid->verts[oldheight * grid->width + j];
+ }
+ oldheight++;
+ }
+ for (j = 0; j < grid->width; j++) {
+ errorTable[0][j] = grid->widthLodError[j];
+ }
+ // put all the aproximating points on the curve
+ //PutPointsOnCurve( ctrl, width, height );
+ // calculate normals
+ MakeMeshNormals( width, height, ctrl );
+
+ VectorCopy(grid->lodOrigin, lodOrigin);
+ lodRadius = grid->lodRadius;
+ // free the old grid
+ R_FreeSurfaceGridMesh(grid);
+ // create a new grid
+ grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
+ grid->lodRadius = lodRadius;
+ VectorCopy(lodOrigin, grid->lodOrigin);
+ return grid;
+}
diff --git a/src/renderergl1/tr_flares.cpp b/src/renderergl1/tr_flares.cpp
new file mode 100644
index 0000000..53ca050
--- /dev/null
+++ b/src/renderergl1/tr_flares.cpp
@@ -0,0 +1,540 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_flares.c
+
+#include "tr_local.h"
+
+/*
+=============================================================================
+
+LIGHT FLARES
+
+A light flare is an effect that takes place inside the eye when bright light
+sources are visible. The size of the flare relative to the screen is nearly
+constant, irrespective of distance, but the intensity should be proportional to the
+projected area of the light source.
+
+A surface that has been flagged as having a light flare will calculate the depth
+buffer value that its midpoint should have when the surface is added.
+
+After all opaque surfaces have been rendered, the depth buffer is read back for
+each flare in view. If the point has not been obscured by a closer surface, the
+flare should be drawn.
+
+Surfaces that have a repeated texture should never be flagged as flaring, because
+there will only be a single flare added at the midpoint of the polygon.
+
+To prevent abrupt popping, the intensity of the flare is interpolated up and
+down as it changes visibility. This involves scene to scene state, unlike almost
+all other aspects of the renderer, and is complicated by the fact that a single
+frame may have multiple scenes.
+
+RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially
+up to five or more times in a frame with 3D status bar icons).
+
+=============================================================================
+*/
+
+
+// flare states maintain visibility over multiple frames for fading
+// layers: view, mirror, menu
+typedef struct flare_s {
+ struct flare_s *next; // for active chain
+
+ int addedFrame;
+
+ bool inPortal; // true if in a portal view of the scene
+ int frameSceneNum;
+ void *surface;
+ int fogNum;
+
+ int fadeTime;
+
+ bool visible; // state of last test
+ float drawIntensity; // may be non 0 even if !visible due to fading
+
+ int windowX, windowY;
+ float eyeZ;
+
+ vec3_t origin;
+ vec3_t color;
+} flare_t;
+
+#define MAX_FLARES 256
+
+flare_t r_flareStructs[MAX_FLARES];
+flare_t *r_activeFlares, *r_inactiveFlares;
+
+int flareCoeff;
+
+/*
+==================
+R_SetFlareCoeff
+==================
+*/
+static void R_SetFlareCoeff( void ) {
+
+ if(r_flareCoeff->value == 0.0f)
+ flareCoeff = atof(FLARE_STDCOEFF);
+ else
+ flareCoeff = r_flareCoeff->value;
+}
+
+/*
+==================
+R_ClearFlares
+==================
+*/
+void R_ClearFlares( void ) {
+ int i;
+
+ Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) );
+ r_activeFlares = NULL;
+ r_inactiveFlares = NULL;
+
+ for ( i = 0 ; i < MAX_FLARES ; i++ ) {
+ r_flareStructs[i].next = r_inactiveFlares;
+ r_inactiveFlares = &r_flareStructs[i];
+ }
+
+ R_SetFlareCoeff();
+}
+
+
+/*
+==================
+RB_AddFlare
+
+This is called at surface tesselation time
+==================
+*/
+void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) {
+ int i;
+ flare_t *f;
+ vec3_t local;
+ float d = 1;
+ vec4_t eye, clip, normalized, window;
+
+ backEnd.pc.c_flareAdds++;
+
+ if(normal && (normal[0] || normal[1] || normal[2]))
+ {
+ VectorSubtract( backEnd.viewParms.orientation.origin, point, local );
+ VectorNormalizeFast(local);
+ d = DotProduct(local, normal);
+
+ // If the viewer is behind the flare don't add it.
+ if(d < 0)
+ return;
+ }
+
+ // if the point is off the screen, don't bother adding it
+ // calculate screen coordinates and depth
+ R_TransformModelToClip( point, backEnd.orientation.modelMatrix,
+ backEnd.viewParms.projectionMatrix, eye, clip );
+
+ // check to see if the point is completely off screen
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) {
+ return;
+ }
+ }
+
+ R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window );
+
+ if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
+ || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) {
+ return; // shouldn't happen, since we check the clip[] above, except for FP rounding
+ }
+
+ // see if a flare with a matching surface, scene, and view exists
+ for ( f = r_activeFlares ; f ; f = f->next ) {
+ if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum
+ && f->inPortal == backEnd.viewParms.isPortal ) {
+ break;
+ }
+ }
+
+ // allocate a new one
+ if (!f ) {
+ if ( !r_inactiveFlares ) {
+ // the list is completely full
+ return;
+ }
+ f = r_inactiveFlares;
+ r_inactiveFlares = r_inactiveFlares->next;
+ f->next = r_activeFlares;
+ r_activeFlares = f;
+
+ f->surface = surface;
+ f->frameSceneNum = backEnd.viewParms.frameSceneNum;
+ f->inPortal = backEnd.viewParms.isPortal;
+ f->addedFrame = -1;
+ }
+
+ if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) {
+ f->visible = false;
+ f->fadeTime = backEnd.refdef.time - 2000;
+ }
+
+ f->addedFrame = backEnd.viewParms.frameCount;
+ f->fogNum = fogNum;
+
+ VectorCopy(point, f->origin);
+ VectorCopy( color, f->color );
+
+ // fade the intensity of the flare down as the
+ // light surface turns away from the viewer
+ VectorScale( f->color, d, f->color );
+
+ // save info needed to test
+ f->windowX = backEnd.viewParms.viewportX + window[0];
+ f->windowY = backEnd.viewParms.viewportY + window[1];
+
+ f->eyeZ = eye[2];
+}
+
+/*
+==================
+RB_AddDlightFlares
+==================
+*/
+void RB_AddDlightFlares( void ) {
+ dlight_t *l;
+ int i, j, k;
+ fog_t *fog = NULL;
+
+ if ( !r_flares->integer ) {
+ return;
+ }
+
+ l = backEnd.refdef.dlights;
+
+ if(tr.world)
+ fog = tr.world->fogs;
+
+ for (i=0 ; i<backEnd.refdef.num_dlights ; i++, l++) {
+
+ if(fog)
+ {
+ // find which fog volume the light is in
+ for ( j = 1 ; j < tr.world->numfogs ; j++ ) {
+ fog = &tr.world->fogs[j];
+ for ( k = 0 ; k < 3 ; k++ ) {
+ if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) {
+ break;
+ }
+ }
+ if ( k == 3 ) {
+ break;
+ }
+ }
+ if ( j == tr.world->numfogs ) {
+ j = 0;
+ }
+ }
+ else
+ j = 0;
+
+ RB_AddFlare( (void *)l, j, l->origin, l->color, NULL );
+ }
+}
+
+/*
+===============================================================================
+
+FLARE BACK END
+
+===============================================================================
+*/
+
+/*
+==================
+RB_TestFlare
+==================
+*/
+void RB_TestFlare( flare_t *f ) {
+ float depth;
+ bool visible;
+ float fade;
+ float screenZ;
+
+ backEnd.pc.c_flareTests++;
+
+ // doing a readpixels is as good as doing a glFinish(), so
+ // don't bother with another sync
+ glState.finishCalled = false;
+
+ // read back the z buffer contents
+ qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth );
+
+ screenZ = backEnd.viewParms.projectionMatrix[14] /
+ ( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] );
+
+ visible = ( -f->eyeZ - -screenZ ) < 24;
+
+ if ( visible ) {
+ if ( !f->visible ) {
+ f->visible = true;
+ f->fadeTime = backEnd.refdef.time - 1;
+ }
+ fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value;
+ } else {
+ if ( f->visible ) {
+ f->visible = false;
+ f->fadeTime = backEnd.refdef.time - 1;
+ }
+ fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value;
+ }
+
+ if ( fade < 0 ) {
+ fade = 0;
+ }
+ if ( fade > 1 ) {
+ fade = 1;
+ }
+
+ f->drawIntensity = fade;
+}
+
+
+/*
+==================
+RB_RenderFlare
+==================
+*/
+void RB_RenderFlare( flare_t *f ) {
+ float size;
+ vec3_t color;
+ int iColor[3];
+ float distance, intensity, factor;
+ byte fogFactors[3] = {255, 255, 255};
+
+ backEnd.pc.c_flareRenders++;
+
+ // We don't want too big values anyways when dividing by distance.
+ if(f->eyeZ > -1.0f)
+ distance = 1.0f;
+ else
+ distance = -f->eyeZ;
+
+ // calculate the flare size..
+ size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance );
+
+/*
+ * This is an alternative to intensity scaling. It changes the size of the flare on screen instead
+ * with growing distance. See in the description at the top why this is not the way to go.
+ // size will change ~ 1/r.
+ size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f));
+*/
+
+/*
+ * As flare sizes stay nearly constant with increasing distance we must decrease the intensity
+ * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be
+ * got by considering the ratio of
+ * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare)
+ * An important requirement is:
+ * intensity <= 1 for all distances.
+ *
+ * The formula used here to compute the intensity is as follows:
+ * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2
+ * As you can see, the intensity will have a max. of 1 when the distance is 0.
+ * The coefficient flareCoeff will determine the falloff speed with increasing distance.
+ */
+
+ factor = distance + size * sqrt(flareCoeff);
+
+ intensity = flareCoeff * size * size / (factor * factor);
+
+ VectorScale(f->color, f->drawIntensity * intensity, color);
+
+ // Calculations for fogging
+ if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs)
+ {
+ tess.numVertexes = 1;
+ VectorCopy(f->origin, tess.xyz[0]);
+ tess.fogNum = f->fogNum;
+
+ RB_CalcModulateColorsByFog(fogFactors);
+
+ // We don't need to render the flare if colors are 0 anyways.
+ if(!(fogFactors[0] || fogFactors[1] || fogFactors[2]))
+ return;
+ }
+
+ iColor[0] = color[0] * fogFactors[0];
+ iColor[1] = color[1] * fogFactors[1];
+ iColor[2] = color[2] * fogFactors[2];
+
+ RB_BeginSurface( tr.flareShader, f->fogNum );
+
+ // FIXME: use quadstamp?
+ tess.xyz[tess.numVertexes][0] = f->windowX - size;
+ tess.xyz[tess.numVertexes][1] = f->windowY - size;
+ tess.texCoords[tess.numVertexes][0][0] = 0;
+ tess.texCoords[tess.numVertexes][0][1] = 0;
+ tess.vertexColors[tess.numVertexes][0] = iColor[0];
+ tess.vertexColors[tess.numVertexes][1] = iColor[1];
+ tess.vertexColors[tess.numVertexes][2] = iColor[2];
+ tess.vertexColors[tess.numVertexes][3] = 255;
+ tess.numVertexes++;
+
+ tess.xyz[tess.numVertexes][0] = f->windowX - size;
+ tess.xyz[tess.numVertexes][1] = f->windowY + size;
+ tess.texCoords[tess.numVertexes][0][0] = 0;
+ tess.texCoords[tess.numVertexes][0][1] = 1;
+ tess.vertexColors[tess.numVertexes][0] = iColor[0];
+ tess.vertexColors[tess.numVertexes][1] = iColor[1];
+ tess.vertexColors[tess.numVertexes][2] = iColor[2];
+ tess.vertexColors[tess.numVertexes][3] = 255;
+ tess.numVertexes++;
+
+ tess.xyz[tess.numVertexes][0] = f->windowX + size;
+ tess.xyz[tess.numVertexes][1] = f->windowY + size;
+ tess.texCoords[tess.numVertexes][0][0] = 1;
+ tess.texCoords[tess.numVertexes][0][1] = 1;
+ tess.vertexColors[tess.numVertexes][0] = iColor[0];
+ tess.vertexColors[tess.numVertexes][1] = iColor[1];
+ tess.vertexColors[tess.numVertexes][2] = iColor[2];
+ tess.vertexColors[tess.numVertexes][3] = 255;
+ tess.numVertexes++;
+
+ tess.xyz[tess.numVertexes][0] = f->windowX + size;
+ tess.xyz[tess.numVertexes][1] = f->windowY - size;
+ tess.texCoords[tess.numVertexes][0][0] = 1;
+ tess.texCoords[tess.numVertexes][0][1] = 0;
+ tess.vertexColors[tess.numVertexes][0] = iColor[0];
+ tess.vertexColors[tess.numVertexes][1] = iColor[1];
+ tess.vertexColors[tess.numVertexes][2] = iColor[2];
+ tess.vertexColors[tess.numVertexes][3] = 255;
+ tess.numVertexes++;
+
+ tess.indexes[tess.numIndexes++] = 0;
+ tess.indexes[tess.numIndexes++] = 1;
+ tess.indexes[tess.numIndexes++] = 2;
+ tess.indexes[tess.numIndexes++] = 0;
+ tess.indexes[tess.numIndexes++] = 2;
+ tess.indexes[tess.numIndexes++] = 3;
+
+ RB_EndSurface();
+}
+
+/*
+==================
+RB_RenderFlares
+
+Because flares are simulating an occular effect, they should be drawn after
+everything (all views) in the entire frame has been drawn.
+
+Because of the way portals use the depth buffer to mark off areas, the
+needed information would be lost after each view, so we are forced to draw
+flares after each view.
+
+The resulting artifact is that flares in mirrors or portals don't dim properly
+when occluded by something in the main view, and portal flares that should
+extend past the portal edge will be overwritten.
+==================
+*/
+void RB_RenderFlares (void) {
+ flare_t *f;
+ flare_t **prev;
+ bool draw;
+
+ if ( !r_flares->integer ) {
+ return;
+ }
+
+ if(r_flareCoeff->modified)
+ {
+ R_SetFlareCoeff();
+ r_flareCoeff->modified = false;
+ }
+
+ // Reset currentEntity to world so that any previously referenced entities
+ // don't have influence on the rendering of these flares (i.e. RF_ renderer flags).
+ backEnd.currentEntity = &tr.worldEntity;
+ backEnd.orientation = backEnd.viewParms.world;
+
+// RB_AddDlightFlares();
+
+ // perform z buffer readback on each flare in this view
+ draw = false;
+ prev = &r_activeFlares;
+ while ( ( f = *prev ) != NULL ) {
+ // throw out any flares that weren't added last frame
+ if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) {
+ *prev = f->next;
+ f->next = r_inactiveFlares;
+ r_inactiveFlares = f;
+ continue;
+ }
+
+ // don't draw any here that aren't from this scene / portal
+ f->drawIntensity = 0;
+ if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
+ && f->inPortal == backEnd.viewParms.isPortal ) {
+ RB_TestFlare( f );
+ if ( f->drawIntensity ) {
+ draw = true;
+ } else {
+ // this flare has completely faded out, so remove it from the chain
+ *prev = f->next;
+ f->next = r_inactiveFlares;
+ r_inactiveFlares = f;
+ continue;
+ }
+ }
+
+ prev = &f->next;
+ }
+
+ if ( !draw ) {
+ return; // none visible
+ }
+
+ if ( backEnd.viewParms.isPortal ) {
+ qglDisable (GL_CLIP_PLANE0);
+ }
+
+ qglPushMatrix();
+ qglLoadIdentity();
+ qglMatrixMode( GL_PROJECTION );
+ qglPushMatrix();
+ qglLoadIdentity();
+ qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
+ backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
+ -99999, 99999 );
+
+ for ( f = r_activeFlares ; f ; f = f->next ) {
+ if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
+ && f->inPortal == backEnd.viewParms.isPortal
+ && f->drawIntensity ) {
+ RB_RenderFlare( f );
+ }
+ }
+
+ qglPopMatrix();
+ qglMatrixMode( GL_MODELVIEW );
+ qglPopMatrix();
+}
diff --git a/src/renderergl1/tr_image.cpp b/src/renderergl1/tr_image.cpp
new file mode 100644
index 0000000..0863db7
--- /dev/null
+++ b/src/renderergl1/tr_image.cpp
@@ -0,0 +1,1680 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_image.c
+#include "tr_local.h"
+
+static byte s_intensitytable[256];
+static unsigned char s_gammatable[256];
+
+int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
+int gl_filter_max = GL_LINEAR;
+
+#define FILE_HASH_SIZE 1024
+static image_t* hashTable[FILE_HASH_SIZE];
+
+/*
+** R_GammaCorrect
+*/
+void R_GammaCorrect( byte *buffer, int bufSize ) {
+ int i;
+
+ for ( i = 0; i < bufSize; i++ ) {
+ buffer[i] = s_gammatable[buffer[i]];
+ }
+}
+
+struct textureMode_t {
+ const char *name;
+ int minimize, maximize;
+};
+
+textureMode_t modes[] = {
+ {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
+ {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
+ {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
+ {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
+ {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
+ {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
+};
+
+/*
+================
+return a hash value for the filename
+================
+*/
+static long generateHashValue( const char *fname ) {
+ int i;
+ long hash;
+ char letter;
+
+ hash = 0;
+ i = 0;
+ while (fname[i] != '\0') {
+ letter = tolower(fname[i]);
+ if (letter =='.') break; // don't include extension
+ if (letter =='\\') letter = '/'; // damn path names
+ hash+=(long)(letter)*(i+119);
+ i++;
+ }
+ hash &= (FILE_HASH_SIZE-1);
+ return hash;
+}
+
+/*
+===============
+GL_TextureMode
+===============
+*/
+void GL_TextureMode( const char *string ) {
+ int i;
+ image_t *glt;
+
+ for ( i=0 ; i< 6 ; i++ ) {
+ if ( !Q_stricmp( modes[i].name, string ) ) {
+ break;
+ }
+ }
+
+ // hack to prevent trilinear from being set on voodoo,
+ // because their driver freaks...
+ if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) {
+ ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" );
+ i = 3;
+ }
+
+
+ if ( i == 6 ) {
+ ri.Printf (PRINT_ALL, "bad filter name\n");
+ return;
+ }
+
+ gl_filter_min = modes[i].minimize;
+ gl_filter_max = modes[i].maximize;
+
+ // change all the existing mipmap texture objects
+ for ( i = 0 ; i < tr.numImages ; i++ ) {
+ glt = tr.images[ i ];
+ if ( glt->flags & IMGFLAG_MIPMAP ) {
+ GL_Bind (glt);
+ qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+ qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+ }
+ }
+}
+
+/*
+===============
+R_SumOfUsedImages
+===============
+*/
+int R_SumOfUsedImages( void ) {
+ int total;
+ int i;
+
+ total = 0;
+ for ( i = 0; i < tr.numImages; i++ ) {
+ if ( tr.images[i]->frameUsed == tr.frameCount ) {
+ total += tr.images[i]->uploadWidth * tr.images[i]->uploadHeight;
+ }
+ }
+
+ return total;
+}
+
+/*
+===============
+R_ImageList_f
+===============
+*/
+void R_ImageList_f( void ) {
+ int i;
+ int estTotalSize = 0;
+
+ ri.Printf(PRINT_ALL, "\n -w-- -h-- type -size- --name-------\n");
+
+ for ( i = 0 ; i < tr.numImages ; i++ )
+ {
+ image_t *image = tr.images[i];
+ const char *format = "???? ";
+ const char *sizeSuffix;
+ int estSize;
+ int displaySize;
+
+ estSize = image->uploadHeight * image->uploadWidth;
+
+ switch(image->internalFormat)
+ {
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+ format = "sDXT1";
+ // 64 bits per 16 pixels, so 4 bits per pixel
+ estSize /= 2;
+ break;
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+ format = "sDXT5";
+ // 128 bits per 16 pixels, so 1 byte per pixel
+ break;
+ case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB:
+ format = "sBPTC";
+ // 128 bits per 16 pixels, so 1 byte per pixel
+ break;
+ case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
+ format = "LATC ";
+ // 128 bits per 16 pixels, so 1 byte per pixel
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ format = "DXT1 ";
+ // 64 bits per 16 pixels, so 4 bits per pixel
+ estSize /= 2;
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ format = "DXT5 ";
+ // 128 bits per 16 pixels, so 1 byte per pixel
+ break;
+ case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB:
+ format = "BPTC ";
+ // 128 bits per 16 pixels, so 1 byte per pixel
+ break;
+ case GL_RGB4_S3TC:
+ format = "S3TC ";
+ // same as DXT1?
+ estSize /= 2;
+ break;
+ case GL_RGBA4:
+ case GL_RGBA8:
+ case GL_RGBA:
+ format = "RGBA ";
+ // 4 bytes per pixel
+ estSize *= 4;
+ break;
+ case GL_LUMINANCE8:
+ case GL_LUMINANCE16:
+ case GL_LUMINANCE:
+ format = "L ";
+ // 1 byte per pixel?
+ break;
+ case GL_RGB5:
+ case GL_RGB8:
+ case GL_RGB:
+ format = "RGB ";
+ // 3 bytes per pixel?
+ estSize *= 3;
+ break;
+ case GL_LUMINANCE8_ALPHA8:
+ case GL_LUMINANCE16_ALPHA16:
+ case GL_LUMINANCE_ALPHA:
+ format = "LA ";
+ // 2 bytes per pixel?
+ estSize *= 2;
+ break;
+ case GL_SRGB_EXT:
+ case GL_SRGB8_EXT:
+ format = "sRGB ";
+ // 3 bytes per pixel?
+ estSize *= 3;
+ break;
+ case GL_SRGB_ALPHA_EXT:
+ case GL_SRGB8_ALPHA8_EXT:
+ format = "sRGBA";
+ // 4 bytes per pixel?
+ estSize *= 4;
+ break;
+ case GL_SLUMINANCE_EXT:
+ case GL_SLUMINANCE8_EXT:
+ format = "sL ";
+ // 1 byte per pixel?
+ break;
+ case GL_SLUMINANCE_ALPHA_EXT:
+ case GL_SLUMINANCE8_ALPHA8_EXT:
+ format = "sLA ";
+ // 2 byte per pixel?
+ estSize *= 2;
+ break;
+ }
+
+ // mipmap adds about 50%
+ if (image->flags & IMGFLAG_MIPMAP)
+ estSize += estSize / 2;
+
+ sizeSuffix = "b ";
+ displaySize = estSize;
+
+ if (displaySize > 1024)
+ {
+ displaySize /= 1024;
+ sizeSuffix = "kb";
+ }
+
+ if (displaySize > 1024)
+ {
+ displaySize /= 1024;
+ sizeSuffix = "Mb";
+ }
+
+ if (displaySize > 1024)
+ {
+ displaySize /= 1024;
+ sizeSuffix = "Gb";
+ }
+
+ ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName);
+ estTotalSize += estSize;
+ }
+
+ ri.Printf (PRINT_ALL, " ---------\n");
+ ri.Printf (PRINT_ALL, " approx %i bytes\n", estTotalSize);
+ ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages );
+}
+
+//=======================================================================
+
+/*
+================
+ResampleTexture
+
+Used to resample images in a more general than quartering fashion.
+
+This will only be filtered properly if the resampled size
+is greater than half the original size.
+
+If a larger shrinking is needed, use the mipmap function
+before or after.
+================
+*/
+static void ResampleTexture( unsigned *in, int inwidth, int inheight, unsigned *out,
+ int outwidth, int outheight ) {
+ int i, j;
+ unsigned *inrow, *inrow2;
+ unsigned frac, fracstep;
+ unsigned p1[2048], p2[2048];
+ byte *pix1, *pix2, *pix3, *pix4;
+
+ if (outwidth>2048)
+ ri.Error(ERR_DROP, "ResampleTexture: max width");
+
+ fracstep = inwidth*0x10000/outwidth;
+
+ frac = fracstep>>2;
+ for ( i=0 ; i<outwidth ; i++ ) {
+ p1[i] = 4*(frac>>16);
+ frac += fracstep;
+ }
+ frac = 3*(fracstep>>2);
+ for ( i=0 ; i<outwidth ; i++ ) {
+ p2[i] = 4*(frac>>16);
+ frac += fracstep;
+ }
+
+ for (i=0 ; i<outheight ; i++, out += outwidth) {
+ inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);
+ inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);
+ for (j=0 ; j<outwidth ; j++) {
+ pix1 = (byte *)inrow + p1[j];
+ pix2 = (byte *)inrow + p2[j];
+ pix3 = (byte *)inrow2 + p1[j];
+ pix4 = (byte *)inrow2 + p2[j];
+ ((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;
+ ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;
+ ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;
+ ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;
+ }
+ }
+}
+
+/*
+================
+R_LightScaleTexture
+
+Scale up the pixel values in a texture to increase the
+lighting range
+================
+*/
+void R_LightScaleTexture (unsigned *in, int inwidth, int inheight, bool only_gamma )
+{
+ if ( only_gamma )
+ {
+ if ( !glConfig.deviceSupportsGamma )
+ {
+ int i, c;
+ byte *p;
+
+ p = (byte *)in;
+
+ c = inwidth*inheight;
+ for (i=0 ; i<c ; i++, p+=4)
+ {
+ p[0] = s_gammatable[p[0]];
+ p[1] = s_gammatable[p[1]];
+ p[2] = s_gammatable[p[2]];
+ }
+ }
+ }
+ else
+ {
+ int i, c;
+ byte *p;
+
+ p = (byte *)in;
+
+ c = inwidth*inheight;
+
+ if ( glConfig.deviceSupportsGamma )
+ {
+ for (i=0 ; i<c ; i++, p+=4)
+ {
+ p[0] = s_intensitytable[p[0]];
+ p[1] = s_intensitytable[p[1]];
+ p[2] = s_intensitytable[p[2]];
+ }
+ }
+ else
+ {
+ for (i=0 ; i<c ; i++, p+=4)
+ {
+ p[0] = s_gammatable[s_intensitytable[p[0]]];
+ p[1] = s_gammatable[s_intensitytable[p[1]]];
+ p[2] = s_gammatable[s_intensitytable[p[2]]];
+ }
+ }
+ }
+}
+
+
+/*
+================
+R_MipMap2
+
+Operates in place, quartering the size of the texture
+Proper linear filter
+================
+*/
+static void R_MipMap2( unsigned *in, int inWidth, int inHeight ) {
+ int i, j, k;
+ byte *outpix;
+ int inWidthMask, inHeightMask;
+ int total;
+ int outWidth, outHeight;
+ unsigned *temp;
+
+ outWidth = inWidth >> 1;
+ outHeight = inHeight >> 1;
+ temp = (unsigned*)ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 );
+
+ inWidthMask = inWidth - 1;
+ inHeightMask = inHeight - 1;
+
+ for ( i = 0 ; i < outHeight ; i++ ) {
+ for ( j = 0 ; j < outWidth ; j++ ) {
+ outpix = (byte *) ( temp + i * outWidth + j );
+ for ( k = 0 ; k < 4 ; k++ ) {
+ total =
+ 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
+ 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
+ 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
+ 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
+
+ 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
+ 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
+ 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
+ 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
+
+ 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
+ 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
+ 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
+ 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
+
+ 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
+ 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
+ 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
+ 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k];
+ outpix[k] = total / 36;
+ }
+ }
+ }
+
+ Com_Memcpy( in, temp, outWidth * outHeight * 4 );
+ ri.Hunk_FreeTempMemory( temp );
+}
+
+/*
+================
+R_MipMap
+
+Operates in place, quartering the size of the texture
+================
+*/
+static void R_MipMap (byte *in, int width, int height) {
+ int i, j;
+ byte *out;
+ int row;
+
+ if ( !r_simpleMipMaps->integer ) {
+ R_MipMap2( (unsigned *)in, width, height );
+ return;
+ }
+
+ if ( width == 1 && height == 1 ) {
+ return;
+ }
+
+ row = width * 4;
+ out = in;
+ width >>= 1;
+ height >>= 1;
+
+ if ( width == 0 || height == 0 ) {
+ width += height; // get largest
+ for (i=0 ; i<width ; i++, out+=4, in+=8 ) {
+ out[0] = ( in[0] + in[4] )>>1;
+ out[1] = ( in[1] + in[5] )>>1;
+ out[2] = ( in[2] + in[6] )>>1;
+ out[3] = ( in[3] + in[7] )>>1;
+ }
+ return;
+ }
+
+ for (i=0 ; i<height ; i++, in+=row) {
+ for (j=0 ; j<width ; j++, out+=4, in+=8) {
+ out[0] = (in[0] + in[4] + in[row+0] + in[row+4])>>2;
+ out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2;
+ out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2;
+ out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2;
+ }
+ }
+}
+
+
+/*
+==================
+R_BlendOverTexture
+
+Apply a color blend over a set of pixels
+==================
+*/
+static void R_BlendOverTexture( byte *data, int pixelCount, byte blend[4] ) {
+ int i;
+ int inverseAlpha;
+ int premult[3];
+
+ inverseAlpha = 255 - blend[3];
+ premult[0] = blend[0] * blend[3];
+ premult[1] = blend[1] * blend[3];
+ premult[2] = blend[2] * blend[3];
+
+ for ( i = 0 ; i < pixelCount ; i++, data+=4 ) {
+ data[0] = ( data[0] * inverseAlpha + premult[0] ) >> 9;
+ data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9;
+ data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9;
+ }
+}
+
+byte mipBlendColors[16][4] = {
+ {0,0,0,0},
+ {255,0,0,128},
+ {0,255,0,128},
+ {0,0,255,128},
+ {255,0,0,128},
+ {0,255,0,128},
+ {0,0,255,128},
+ {255,0,0,128},
+ {0,255,0,128},
+ {0,0,255,128},
+ {255,0,0,128},
+ {0,255,0,128},
+ {0,0,255,128},
+ {255,0,0,128},
+ {0,255,0,128},
+ {0,0,255,128},
+};
+
+
+/*
+===============
+Upload32
+
+===============
+*/
+static void Upload32( unsigned *data,
+ int width, int height,
+ bool mipmap,
+ bool picmip,
+ bool lightMap,
+ bool allowCompression,
+ int *format,
+ int *pUploadWidth, int *pUploadHeight )
+{
+ int samples;
+ unsigned *scaledBuffer = NULL;
+ unsigned *resampledBuffer = NULL;
+ int scaled_width, scaled_height;
+ int i, c;
+ byte *scan;
+ GLenum internalFormat = GL_RGB;
+ float rMax = 0, gMax = 0, bMax = 0;
+
+ //
+ // convert to exact power of 2 sizes
+ //
+ for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
+ ;
+ for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
+ ;
+ if ( r_roundImagesDown->integer && scaled_width > width )
+ scaled_width >>= 1;
+ if ( r_roundImagesDown->integer && scaled_height > height )
+ scaled_height >>= 1;
+
+ if ( scaled_width != width || scaled_height != height ) {
+ resampledBuffer = (unsigned*)ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 );
+ ResampleTexture (data, width, height, resampledBuffer, scaled_width, scaled_height);
+ data = resampledBuffer;
+ width = scaled_width;
+ height = scaled_height;
+ }
+
+ //
+ // perform optional picmip operation
+ //
+ if ( picmip ) {
+ scaled_width >>= r_picmip->integer;
+ scaled_height >>= r_picmip->integer;
+ }
+
+ //
+ // clamp to minimum size
+ //
+ if (scaled_width < 1) {
+ scaled_width = 1;
+ }
+ if (scaled_height < 1) {
+ scaled_height = 1;
+ }
+
+ //
+ // clamp to the current upper OpenGL limit
+ // scale both axis down equally so we don't have to
+ // deal with a half mip resampling
+ //
+ while ( scaled_width > glConfig.maxTextureSize
+ || scaled_height > glConfig.maxTextureSize ) {
+ scaled_width >>= 1;
+ scaled_height >>= 1;
+ }
+
+ scaledBuffer = (unsigned*)ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height );
+
+ //
+ // scan the texture for each channel's max values
+ // and verify if the alpha channel is being used or not
+ //
+ c = width*height;
+ scan = ((byte *)data);
+ samples = 3;
+
+ if( r_greyscale->integer )
+ {
+ for ( i = 0; i < c; i++ )
+ {
+ byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
+ scan[i*4] = luma;
+ scan[i*4 + 1] = luma;
+ scan[i*4 + 2] = luma;
+ }
+ }
+ else if( r_greyscale->value )
+ {
+ for ( i = 0; i < c; i++ )
+ {
+ float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
+ scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value);
+ scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value);
+ scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value);
+ }
+ }
+
+ if(lightMap)
+ {
+ if(r_greyscale->integer)
+ internalFormat = GL_LUMINANCE;
+ else
+ internalFormat = GL_RGB;
+ }
+ else
+ {
+ for ( i = 0; i < c; i++ )
+ {
+ if ( scan[i*4+0] > rMax )
+ {
+ rMax = scan[i*4+0];
+ }
+ if ( scan[i*4+1] > gMax )
+ {
+ gMax = scan[i*4+1];
+ }
+ if ( scan[i*4+2] > bMax )
+ {
+ bMax = scan[i*4+2];
+ }
+ if ( scan[i*4 + 3] != 255 )
+ {
+ samples = 4;
+ break;
+ }
+ }
+ // select proper internal format
+ if ( samples == 3 )
+ {
+ if(r_greyscale->integer)
+ {
+ if(r_texturebits->integer == 16)
+ internalFormat = GL_LUMINANCE8;
+ else if(r_texturebits->integer == 32)
+ internalFormat = GL_LUMINANCE16;
+ else
+ internalFormat = GL_LUMINANCE;
+ }
+ else
+ {
+ if ( allowCompression && glConfig.textureCompression == TC_S3TC_ARB )
+ {
+ internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ }
+ else if ( allowCompression && glConfig.textureCompression == TC_S3TC )
+ {
+ internalFormat = GL_RGB4_S3TC;
+ }
+ else if ( r_texturebits->integer == 16 )
+ {
+ internalFormat = GL_RGB5;
+ }
+ else if ( r_texturebits->integer == 32 )
+ {
+ internalFormat = GL_RGB8;
+ }
+ else
+ {
+ internalFormat = GL_RGB;
+ }
+ }
+ }
+ else if ( samples == 4 )
+ {
+ if(r_greyscale->integer)
+ {
+ if(r_texturebits->integer == 16)
+ internalFormat = GL_LUMINANCE8_ALPHA8;
+ else if(r_texturebits->integer == 32)
+ internalFormat = GL_LUMINANCE16_ALPHA16;
+ else
+ internalFormat = GL_LUMINANCE_ALPHA;
+ }
+ else
+ {
+ if ( r_texturebits->integer == 16 )
+ {
+ internalFormat = GL_RGBA4;
+ }
+ else if ( r_texturebits->integer == 32 )
+ {
+ internalFormat = GL_RGBA8;
+ }
+ else
+ {
+ internalFormat = GL_RGBA;
+ }
+ }
+ }
+ }
+
+ // copy or resample data as appropriate for first MIP level
+ if ( ( scaled_width == width ) &&
+ ( scaled_height == height ) ) {
+ if (!mipmap)
+ {
+ qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ *pUploadWidth = scaled_width;
+ *pUploadHeight = scaled_height;
+ *format = internalFormat;
+
+ goto done;
+ }
+ Com_Memcpy (scaledBuffer, data, width*height*4);
+ }
+ else
+ {
+ // use the normal mip-mapping function to go down from here
+ while ( width > scaled_width || height > scaled_height ) {
+ R_MipMap( (byte *)data, width, height );
+ width >>= 1;
+ height >>= 1;
+ if ( width < 1 ) {
+ width = 1;
+ }
+ if ( height < 1 ) {
+ height = 1;
+ }
+ }
+ Com_Memcpy( scaledBuffer, data, width * height * 4 );
+ }
+
+ R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !mipmap );
+
+ *pUploadWidth = scaled_width;
+ *pUploadHeight = scaled_height;
+ *format = internalFormat;
+
+ qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer );
+
+ if (mipmap)
+ {
+ int miplevel;
+
+ miplevel = 0;
+ while (scaled_width > 1 || scaled_height > 1)
+ {
+ R_MipMap( (byte *)scaledBuffer, scaled_width, scaled_height );
+ scaled_width >>= 1;
+ scaled_height >>= 1;
+ if (scaled_width < 1)
+ scaled_width = 1;
+ if (scaled_height < 1)
+ scaled_height = 1;
+ miplevel++;
+
+ if ( r_colorMipLevels->integer ) {
+ R_BlendOverTexture( (byte *)scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] );
+ }
+
+ qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer );
+ }
+ }
+done:
+
+ if (mipmap)
+ {
+ if ( glConfig.textureFilterAnisotropic )
+ qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
+ (GLint)Com_Clamp( 1, glConfig.maxAnisotropy, r_ext_max_anisotropy->integer ) );
+
+ qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+ qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+ }
+ else
+ {
+ if ( glConfig.textureFilterAnisotropic )
+ qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 );
+
+ qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ }
+
+ GL_CheckErrors();
+
+ if ( scaledBuffer != 0 )
+ ri.Hunk_FreeTempMemory( scaledBuffer );
+ if ( resampledBuffer != 0 )
+ ri.Hunk_FreeTempMemory( resampledBuffer );
+}
+
+
+/*
+================
+R_CreateImage
+
+This is the only way any image_t are created
+================
+*/
+image_t *R_CreateImage( const char *name, byte *pic, int width, int height,
+ imgType_t type, int flags, int internalFormat ) {
+ image_t *image;
+ bool isLightmap = false;
+ long hash;
+ int glWrapClampMode;
+
+ if (strlen(name) >= MAX_QPATH ) {
+ ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name);
+ }
+ if ( !strncmp( name, "*lightmap", 9 ) ) {
+ isLightmap = true;
+ }
+
+ if ( tr.numImages == MAX_DRAWIMAGES ) {
+ ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit");
+ }
+
+ image = tr.images[tr.numImages] = (image_t*)ri.Hunk_Alloc( sizeof( image_t ), h_low );
+ image->texnum = 1024 + tr.numImages;
+ tr.numImages++;
+
+ image->type = type;
+ image->flags = flags;
+
+ strcpy (image->imgName, name);
+
+ image->width = width;
+ image->height = height;
+ if (flags & IMGFLAG_CLAMPTOEDGE)
+ glWrapClampMode = GL_CLAMP_TO_EDGE;
+ else
+ glWrapClampMode = GL_REPEAT;
+
+ // lightmaps are always allocated on TMU 1
+ if ( qglActiveTextureARB && isLightmap ) {
+ image->TMU = 1;
+ } else {
+ image->TMU = 0;
+ }
+
+ if ( qglActiveTextureARB ) {
+ GL_SelectTexture( image->TMU );
+ }
+
+ GL_Bind(image);
+
+ Upload32( (unsigned *)pic, image->width, image->height,
+ (image->flags & IMGFLAG_MIPMAP) == IMGFLAG_MIPMAP,
+ (image->flags & IMGFLAG_PICMIP) == IMGFLAG_PICMIP,
+ isLightmap,
+ !(image->flags & IMGFLAG_NO_COMPRESSION),
+ &image->internalFormat,
+ &image->uploadWidth,
+ &image->uploadHeight );
+
+ qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode );
+ qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode );
+
+ glState.currenttextures[glState.currenttmu] = 0;
+ qglBindTexture( GL_TEXTURE_2D, 0 );
+
+ if ( image->TMU == 1 ) {
+ GL_SelectTexture( 0 );
+ }
+
+ hash = generateHashValue(name);
+ image->next = hashTable[hash];
+ hashTable[hash] = image;
+
+ return image;
+}
+
+//===================================================================
+
+struct imageExtToLoaderMap_t
+{
+ const char *ext;
+ void (*ImageLoader)( const char *, unsigned char **, int *, int * );
+};
+
+// Note that the ordering indicates the order of preference used
+// when there are multiple images of different formats available
+static imageExtToLoaderMap_t imageLoaders[ ] =
+{
+ { "tga", R_LoadTGA },
+ { "jpg", R_LoadJPG },
+ { "jpeg", R_LoadJPG },
+ { "png", R_LoadPNG },
+ { "pcx", R_LoadPCX },
+ { "bmp", R_LoadBMP }
+};
+
+static int numImageLoaders = ARRAY_LEN( imageLoaders );
+
+/*
+=================
+R_LoadImage
+
+Loads any of the supported image types into a cannonical
+32 bit format.
+=================
+*/
+void R_LoadImage( const char *name, byte **pic, int *width, int *height )
+{
+ bool orgNameFailed = false;
+ int orgLoader = -1;
+ int i;
+ char localName[ MAX_QPATH ];
+ const char *ext;
+ const char *altName;
+
+ *pic = NULL;
+ *width = 0;
+ *height = 0;
+
+ Q_strncpyz( localName, name, MAX_QPATH );
+
+ ext = COM_GetExtension( localName );
+
+ if( *ext )
+ {
+ // Look for the correct loader and use it
+ for( i = 0; i < numImageLoaders; i++ )
+ {
+ if( !Q_stricmp( ext, imageLoaders[ i ].ext ) )
+ {
+ // Load
+ imageLoaders[ i ].ImageLoader( localName, pic, width, height );
+ break;
+ }
+ }
+
+ // A loader was found
+ if( i < numImageLoaders )
+ {
+ if( *pic == NULL )
+ {
+ // Loader failed, most likely because the file isn't there;
+ // try again without the extension
+ orgNameFailed = true;
+ orgLoader = i;
+ COM_StripExtension( name, localName, MAX_QPATH );
+ }
+ else
+ {
+ // Something loaded
+ return;
+ }
+ }
+ }
+
+ // Try and find a suitable match using all
+ // the image formats supported
+ for( i = 0; i < numImageLoaders; i++ )
+ {
+ if (i == orgLoader)
+ continue;
+
+ altName = va( "%s.%s", localName, imageLoaders[ i ].ext );
+
+ // Load
+ imageLoaders[ i ].ImageLoader( altName, pic, width, height );
+
+ if( *pic )
+ {
+ if( orgNameFailed )
+ {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n",
+ name, altName );
+ }
+
+ break;
+ }
+ }
+}
+
+
+/*
+===============
+R_FindImageFile
+
+Finds or loads the given image.
+Returns NULL if it fails, not a default image.
+==============
+*/
+image_t *R_FindImageFile( const char *name, imgType_t type, int /*imgFlags_t*/ flags )
+{
+ image_t *image;
+ int width, height;
+ byte *pic;
+ long hash;
+
+ if (!name) {
+ return NULL;
+ }
+
+ hash = generateHashValue(name);
+
+ //
+ // see if the image is already loaded
+ //
+ for (image=hashTable[hash]; image; image=image->next) {
+ if ( !strcmp( name, image->imgName ) ) {
+ // the white image can be used with any set of parms, but other mismatches are errors
+ if ( strcmp( name, "*white" ) ) {
+ if ( image->flags != flags ) {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed flags (%i vs %i)\n", name, image->flags, flags );
+ }
+ }
+ return image;
+ }
+ }
+
+ //
+ // load the pic from disk
+ //
+ R_LoadImage( name, &pic, &width, &height );
+ if ( pic == NULL ) {
+ return NULL;
+ }
+
+ image = R_CreateImage( ( char * ) name, pic, width, height, type, flags, 0 );
+ ri.Free( pic );
+ return image;
+}
+
+
+/*
+================
+R_CreateDlightImage
+================
+*/
+#define DLIGHT_SIZE 16
+static void R_CreateDlightImage( void ) {
+ int x,y;
+ byte data[DLIGHT_SIZE][DLIGHT_SIZE][4];
+ int b;
+
+ // make a centered inverse-square falloff blob for dynamic lighting
+ for (x=0 ; x<DLIGHT_SIZE ; x++) {
+ for (y=0 ; y<DLIGHT_SIZE ; y++) {
+ float d;
+
+ d = ( DLIGHT_SIZE/2 - 0.5f - x ) * ( DLIGHT_SIZE/2 - 0.5f - x ) +
+ ( DLIGHT_SIZE/2 - 0.5f - y ) * ( DLIGHT_SIZE/2 - 0.5f - y );
+ b = 4000 / d;
+ if (b > 255) {
+ b = 255;
+ } else if ( b < 75 ) {
+ b = 0;
+ }
+ data[y][x][0] =
+ data[y][x][1] =
+ data[y][x][2] = b;
+ data[y][x][3] = 255;
+ }
+ }
+ tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 );
+}
+
+
+/*
+=================
+R_InitFogTable
+=================
+*/
+void R_InitFogTable( void ) {
+ int i;
+ float d;
+ float exp;
+
+ exp = 0.5;
+
+ for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) {
+ d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp );
+
+ tr.fogTable[i] = d;
+ }
+}
+
+/*
+================
+R_FogFactor
+
+Returns a 0.0 to 1.0 fog density value
+This is called for each texel of the fog texture on startup
+and for each vertex of transparent shaders in fog dynamically
+================
+*/
+float R_FogFactor( float s, float t ) {
+ float d;
+
+ s -= 1.0/512;
+ if ( s < 0 ) {
+ return 0;
+ }
+ if ( t < 1.0/32 ) {
+ return 0;
+ }
+ if ( t < 31.0/32 ) {
+ s *= (t - 1.0f/32.0f) / (30.0f/32.0f);
+ }
+
+ // we need to leave a lot of clamp range
+ s *= 8;
+
+ if ( s > 1.0 ) {
+ s = 1.0;
+ }
+
+ d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ];
+
+ return d;
+}
+
+/*
+================
+R_CreateFogImage
+================
+*/
+#define FOG_S 256
+#define FOG_T 32
+static void R_CreateFogImage( void ) {
+ int x,y;
+ byte *data;
+ float d;
+
+ data = (byte*)ri.Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 );
+
+ // S is distance, T is depth
+ for (x=0 ; x<FOG_S ; x++) {
+ for (y=0 ; y<FOG_T ; y++) {
+ d = R_FogFactor( ( x + 0.5f ) / FOG_S, ( y + 0.5f ) / FOG_T );
+
+ data[(y*FOG_S+x)*4+0] =
+ data[(y*FOG_S+x)*4+1] =
+ data[(y*FOG_S+x)*4+2] = 255;
+ data[(y*FOG_S+x)*4+3] = 255*d;
+ }
+ }
+ tr.fogImage = R_CreateImage("*fog", (byte *)data, FOG_S, FOG_T, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 );
+ ri.Hunk_FreeTempMemory( data );
+}
+
+/*
+==================
+R_CreateDefaultImage
+==================
+*/
+#define DEFAULT_SIZE 16
+static void R_CreateDefaultImage( void ) {
+ int x;
+ byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
+
+ // the default image will be a box, to allow you to see the mapping coordinates
+ Com_Memset( data, 32, sizeof( data ) );
+ for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
+ data[0][x][0] =
+ data[0][x][1] =
+ data[0][x][2] =
+ data[0][x][3] = 255;
+
+ data[x][0][0] =
+ data[x][0][1] =
+ data[x][0][2] =
+ data[x][0][3] = 255;
+
+ data[DEFAULT_SIZE-1][x][0] =
+ data[DEFAULT_SIZE-1][x][1] =
+ data[DEFAULT_SIZE-1][x][2] =
+ data[DEFAULT_SIZE-1][x][3] = 255;
+
+ data[x][DEFAULT_SIZE-1][0] =
+ data[x][DEFAULT_SIZE-1][1] =
+ data[x][DEFAULT_SIZE-1][2] =
+ data[x][DEFAULT_SIZE-1][3] = 255;
+ }
+ tr.defaultImage = R_CreateImage("*default", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_MIPMAP, 0);
+}
+
+/*
+==================
+R_CreateBuiltinImages
+==================
+*/
+void R_CreateBuiltinImages( void ) {
+ int x,y;
+ byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
+
+ R_CreateDefaultImage();
+
+ // we use a solid white image instead of disabling texturing
+ Com_Memset( data, 255, sizeof( data ) );
+ tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, IMGTYPE_COLORALPHA, IMGFLAG_NONE, 0);
+
+ // with overbright bits active, we need an image which is some fraction of full color,
+ // for default lightmaps, etc
+ for (x=0 ; x<DEFAULT_SIZE ; x++) {
+ for (y=0 ; y<DEFAULT_SIZE ; y++) {
+ data[y][x][0] =
+ data[y][x][1] =
+ data[y][x][2] = tr.identityLightByte;
+ data[y][x][3] = 255;
+ }
+ }
+
+ tr.identityLightImage = R_CreateImage("*identityLight", (byte *)data, 8, 8, IMGTYPE_COLORALPHA, IMGFLAG_NONE, 0);
+
+
+ for(x=0;x<32;x++) {
+ // scratchimage is usually used for cinematic drawing
+ tr.scratchImage[x] = R_CreateImage("*scratch", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_PICMIP | IMGFLAG_CLAMPTOEDGE, 0);
+ }
+
+ R_CreateDlightImage();
+ R_CreateFogImage();
+}
+
+
+/*
+===============
+R_SetColorMappings
+===============
+*/
+void R_SetColorMappings( void ) {
+ int i, j;
+ float g;
+ int inf;
+ int shift;
+
+ // setup the overbright lighting
+ tr.overbrightBits = r_overBrightBits->integer;
+ if ( !glConfig.deviceSupportsGamma ) {
+ tr.overbrightBits = 0; // need hardware gamma for overbright
+ }
+
+ // never overbright in windowed mode
+ if ( !glConfig.isFullscreen )
+ {
+ tr.overbrightBits = 0;
+ }
+
+ // allow 2 overbright bits in 24 bit, but only 1 in 16 bit
+ if ( glConfig.colorBits > 16 ) {
+ if ( tr.overbrightBits > 2 ) {
+ tr.overbrightBits = 2;
+ }
+ } else {
+ if ( tr.overbrightBits > 1 ) {
+ tr.overbrightBits = 1;
+ }
+ }
+ if ( tr.overbrightBits < 0 ) {
+ tr.overbrightBits = 0;
+ }
+
+ tr.identityLight = 1.0f / ( 1 << tr.overbrightBits );
+ tr.identityLightByte = 255 * tr.identityLight;
+
+
+ if ( r_intensity->value <= 1 ) {
+ ri.Cvar_Set( "r_intensity", "1" );
+ }
+
+ if ( r_gamma->value < 0.5f ) {
+ ri.Cvar_Set( "r_gamma", "0.5" );
+ } else if ( r_gamma->value > 3.0f ) {
+ ri.Cvar_Set( "r_gamma", "3.0" );
+ }
+
+ g = r_gamma->value;
+
+ shift = tr.overbrightBits;
+
+ for ( i = 0; i < 256; i++ ) {
+ if ( g == 1 ) {
+ inf = i;
+ } else {
+ inf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f;
+ }
+ inf <<= shift;
+ if (inf < 0) {
+ inf = 0;
+ }
+ if (inf > 255) {
+ inf = 255;
+ }
+ s_gammatable[i] = inf;
+ }
+
+ for (i=0 ; i<256 ; i++) {
+ j = i * r_intensity->value;
+ if (j > 255) {
+ j = 255;
+ }
+ s_intensitytable[i] = j;
+ }
+
+ if ( glConfig.deviceSupportsGamma )
+ {
+ GLimp_SetGamma( s_gammatable, s_gammatable, s_gammatable );
+ }
+}
+
+/*
+===============
+R_InitImages
+===============
+*/
+void R_InitImages( void ) {
+ Com_Memset(hashTable, 0, sizeof(hashTable));
+ // build brightness translation tables
+ R_SetColorMappings();
+
+ // create default texture and white texture
+ R_CreateBuiltinImages();
+}
+
+/*
+===============
+R_DeleteTextures
+===============
+*/
+void R_DeleteTextures( void ) {
+ int i;
+
+ for ( i=0; i<tr.numImages ; i++ ) {
+ qglDeleteTextures( 1, &tr.images[i]->texnum );
+ }
+ Com_Memset( tr.images, 0, sizeof( tr.images ) );
+
+ tr.numImages = 0;
+
+ Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) );
+ if ( qglActiveTextureARB ) {
+ GL_SelectTexture( 1 );
+ qglBindTexture( GL_TEXTURE_2D, 0 );
+ GL_SelectTexture( 0 );
+ qglBindTexture( GL_TEXTURE_2D, 0 );
+ } else {
+ qglBindTexture( GL_TEXTURE_2D, 0 );
+ }
+}
+
+/*
+============================================================================
+
+SKINS
+
+============================================================================
+*/
+
+/*
+==================
+CommaParse
+
+This is unfortunate, but the skin files aren't
+compatable with our normal parsing rules.
+==================
+*/
+static const char *CommaParse( char **data_p ) {
+ int c = 0, len;
+ char *data;
+ static char com_token[MAX_TOKEN_CHARS];
+
+ data = *data_p;
+ len = 0;
+ com_token[0] = 0;
+
+ // make sure incoming data is valid
+ if ( !data ) {
+ *data_p = NULL;
+ return com_token;
+ }
+
+ while ( 1 ) {
+ // skip whitespace
+ while( (c = *data) <= ' ') {
+ if( !c ) {
+ break;
+ }
+ data++;
+ }
+
+
+ c = *data;
+
+ // skip double slash comments
+ if ( c == '/' && data[1] == '/' )
+ {
+ data += 2;
+ while (*data && *data != '\n') {
+ data++;
+ }
+ }
+ // skip /* */ comments
+ else if ( c=='/' && data[1] == '*' )
+ {
+ data += 2;
+ while ( *data && ( *data != '*' || data[1] != '/' ) )
+ {
+ data++;
+ }
+ if ( *data )
+ {
+ data += 2;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if ( c == 0 ) {
+ return "";
+ }
+
+ // handle quoted strings
+ if (c == '\"')
+ {
+ data++;
+ while (1)
+ {
+ c = *data++;
+ if (c=='\"' || !c)
+ {
+ com_token[len] = 0;
+ *data_p = ( char * ) data;
+ return com_token;
+ }
+ if (len < MAX_TOKEN_CHARS - 1)
+ {
+ com_token[len] = c;
+ len++;
+ }
+ }
+ }
+
+ // parse a regular word
+ do
+ {
+ if (len < MAX_TOKEN_CHARS - 1)
+ {
+ com_token[len] = c;
+ len++;
+ }
+ data++;
+ c = *data;
+ } while (c>32 && c != ',' );
+
+ com_token[len] = 0;
+
+ *data_p = ( char * ) data;
+ return com_token;
+}
+
+
+/*
+===============
+RE_RegisterSkin
+
+===============
+*/
+qhandle_t RE_RegisterSkin( const char *name ) {
+ skinSurface_t parseSurfaces[MAX_SKIN_SURFACES];
+ qhandle_t hSkin;
+ skin_t *skin;
+ skinSurface_t *surf;
+ union {
+ char *c;
+ void *v;
+ } text;
+ char *text_p;
+ const char *token;
+ char surfName[MAX_QPATH];
+
+ if ( !name || !name[0] ) {
+ ri.Printf( PRINT_DEVELOPER, "Empty name passed to RE_RegisterSkin\n" );
+ return 0;
+ }
+
+ if ( strlen( name ) >= MAX_QPATH ) {
+ ri.Printf( PRINT_DEVELOPER, "Skin name exceeds MAX_QPATH\n" );
+ return 0;
+ }
+
+
+ // see if the skin is already loaded
+ for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) {
+ skin = tr.skins[hSkin];
+ if ( !Q_stricmp( skin->name, name ) ) {
+ if( skin->numSurfaces == 0 ) {
+ return 0; // default skin
+ }
+ return hSkin;
+ }
+ }
+
+ // allocate a new skin
+ if ( tr.numSkins == MAX_SKINS ) {
+ ri.Printf( PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name );
+ return 0;
+ }
+ tr.numSkins++;
+ skin = (skin_t*)ri.Hunk_Alloc( sizeof( skin_t ), h_low );
+ tr.skins[hSkin] = skin;
+ Q_strncpyz( skin->name, name, sizeof( skin->name ) );
+ skin->numSurfaces = 0;
+
+ R_IssuePendingRenderCommands();
+
+ // If not a .skin file, load as a single shader
+ if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) {
+ skin->numSurfaces = 1;
+ skin->surfaces = (skinSurface_t*)ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+ skin->surfaces[0].shader = R_FindShader( name, LIGHTMAP_NONE, true );
+ return hSkin;
+ }
+
+ // load and parse the skin file
+ ri.FS_ReadFile( name, &text.v );
+ if ( !text.c ) {
+ return 0;
+ }
+
+ int totalSurfaces = 0;
+ text_p = text.c;
+ while ( text_p && *text_p ) {
+ // get surface name
+ token = CommaParse( &text_p );
+ Q_strncpyz( surfName, token, sizeof( surfName ) );
+
+ if ( !token[0] ) {
+ break;
+ }
+ // lowercase the surface name so skin compares are faster
+ Q_strlwr( surfName );
+
+ if ( *text_p == ',' ) {
+ text_p++;
+ }
+
+ if ( strstr( token, "tag_" ) ) {
+ continue;
+ }
+
+ // parse the shader name
+ token = CommaParse( &text_p );
+
+
+ if ( skin->numSurfaces < MAX_SKIN_SURFACES ) {
+ surf = &parseSurfaces[skin->numSurfaces];
+ Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );
+ surf->shader = R_FindShader( token, LIGHTMAP_NONE, true );
+ skin->numSurfaces++;
+ }
+
+ totalSurfaces++;
+ }
+
+ ri.FS_FreeFile( text.v );
+
+ if ( totalSurfaces > MAX_SKIN_SURFACES ) {
+ ri.Printf( PRINT_WARNING, "WARNING: Ignoring excess surfaces (found %d, max is %d) in skin '%s'!\n",
+ totalSurfaces, MAX_SKIN_SURFACES, name );
+ }
+
+ // never let a skin have 0 shaders
+ if ( skin->numSurfaces == 0 ) {
+ return 0; // use default skin
+ }
+
+ // copy surfaces to skin
+ skin->surfaces = (skinSurface_t*)ri.Hunk_Alloc( skin->numSurfaces * sizeof( skinSurface_t ), h_low );
+ memcpy( skin->surfaces, parseSurfaces, skin->numSurfaces * sizeof( skinSurface_t ) );
+
+ return hSkin;
+}
+
+
+/*
+===============
+R_InitSkins
+===============
+*/
+void R_InitSkins( void ) {
+ skin_t *skin;
+
+ tr.numSkins = 1;
+
+ // make the default skin have all default shaders
+ skin = tr.skins[0] = (skin_t*)ri.Hunk_Alloc( sizeof( skin_t ), h_low );
+ Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name ) );
+ skin->numSurfaces = 1;
+ skin->surfaces = (skinSurface_t*)ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+ skin->surfaces[0].shader = tr.defaultShader;
+}
+
+/*
+===============
+R_GetSkinByHandle
+===============
+*/
+skin_t *R_GetSkinByHandle( qhandle_t hSkin ) {
+ if ( hSkin < 1 || hSkin >= tr.numSkins ) {
+ return tr.skins[0];
+ }
+ return tr.skins[ hSkin ];
+}
+
+/*
+===============
+R_SkinList_f
+===============
+*/
+void R_SkinList_f( void ) {
+ int i, j;
+ skin_t *skin;
+
+ ri.Printf (PRINT_ALL, "------------------\n");
+
+ for ( i = 0 ; i < tr.numSkins ; i++ ) {
+ skin = tr.skins[i];
+
+ ri.Printf( PRINT_ALL, "%3i:%s (%d surfaces)\n", i, skin->name, skin->numSurfaces );
+ for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
+ ri.Printf( PRINT_ALL, " %s = %s\n",
+ skin->surfaces[j].name, skin->surfaces[j].shader->name );
+ }
+ }
+ ri.Printf (PRINT_ALL, "------------------\n");
+}
diff --git a/src/renderergl1/tr_init.cpp b/src/renderergl1/tr_init.cpp
new file mode 100644
index 0000000..cbd5095
--- /dev/null
+++ b/src/renderergl1/tr_init.cpp
@@ -0,0 +1,1299 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_init.c -- functions that are not called every frame
+
+#include "tr_local.h"
+
+glconfig_t glConfig;
+glstate_t glState;
+
+static void GfxInfo_f( void );
+
+#ifdef USE_RENDERER_DLOPEN
+cvar_t *com_altivec;
+#endif
+
+cvar_t *r_flareSize;
+cvar_t *r_flareFade;
+cvar_t *r_flareCoeff;
+
+cvar_t *r_railWidth;
+cvar_t *r_railCoreWidth;
+cvar_t *r_railSegmentLength;
+
+cvar_t *r_ignoreFastPath;
+
+cvar_t *r_verbose;
+cvar_t *r_ignore;
+
+cvar_t *r_displayRefresh;
+
+cvar_t *r_detailTextures;
+
+cvar_t *r_znear;
+cvar_t *r_zproj;
+cvar_t *r_stereoSeparation;
+
+cvar_t *r_skipBackEnd;
+
+cvar_t *r_stereoEnabled;
+cvar_t *r_anaglyphMode;
+
+cvar_t *r_greyscale;
+
+cvar_t *r_ignorehwgamma;
+cvar_t *r_measureOverdraw;
+
+cvar_t *r_inGameVideo;
+cvar_t *r_fastsky;
+cvar_t *r_drawSun;
+cvar_t *r_dynamiclight;
+cvar_t *r_dlightBacks;
+
+cvar_t *r_lodbias;
+cvar_t *r_lodscale;
+
+cvar_t *r_norefresh;
+cvar_t *r_drawentities;
+cvar_t *r_drawworld;
+cvar_t *r_speeds;
+cvar_t *r_fullbright;
+cvar_t *r_novis;
+cvar_t *r_nocull;
+cvar_t *r_facePlaneCull;
+cvar_t *r_showcluster;
+cvar_t *r_nocurves;
+
+cvar_t *r_allowExtensions;
+
+cvar_t *r_ext_compressed_textures;
+cvar_t *r_ext_multitexture;
+cvar_t *r_ext_compiled_vertex_array;
+cvar_t *r_ext_texture_env_add;
+cvar_t *r_ext_texture_filter_anisotropic;
+cvar_t *r_ext_max_anisotropy;
+
+cvar_t *r_ignoreGLErrors;
+cvar_t *r_logFile;
+
+cvar_t *r_stencilbits;
+cvar_t *r_depthbits;
+cvar_t *r_colorbits;
+cvar_t *r_alphabits;
+cvar_t *r_primitives;
+cvar_t *r_texturebits;
+cvar_t *r_ext_multisample;
+
+cvar_t *r_drawBuffer;
+cvar_t *r_lightmap;
+cvar_t *r_vertexLight;
+cvar_t *r_uiFullScreen;
+cvar_t *r_shadows;
+cvar_t *r_flares;
+cvar_t *r_nobind;
+cvar_t *r_singleShader;
+cvar_t *r_roundImagesDown;
+cvar_t *r_colorMipLevels;
+cvar_t *r_picmip;
+cvar_t *r_showtris;
+cvar_t *r_showsky;
+cvar_t *r_shownormals;
+cvar_t *r_finish;
+cvar_t *r_clear;
+cvar_t *r_swapInterval;
+cvar_t *r_textureMode;
+cvar_t *r_offsetFactor;
+cvar_t *r_offsetUnits;
+cvar_t *r_gamma;
+cvar_t *r_intensity;
+cvar_t *r_lockpvs;
+cvar_t *r_noportals;
+cvar_t *r_portalOnly;
+
+cvar_t *r_subdivisions;
+cvar_t *r_lodCurveError;
+
+cvar_t *r_fullscreen;
+cvar_t *r_noborder;
+
+cvar_t *r_width;
+cvar_t *r_height;
+cvar_t *r_pixelAspect;
+
+cvar_t *r_overBrightBits;
+cvar_t *r_mapOverBrightBits;
+
+cvar_t *r_debugSurface;
+cvar_t *r_simpleMipMaps;
+
+cvar_t *r_showImages;
+
+cvar_t *r_ambientScale;
+cvar_t *r_directedScale;
+cvar_t *r_debugLight;
+cvar_t *r_debugSort;
+cvar_t *r_printShaders;
+cvar_t *r_saveFontData;
+
+cvar_t *r_marksOnTriangleMeshes;
+
+cvar_t *r_aviMotionJpegQuality;
+cvar_t *r_screenshotJpegQuality;
+
+cvar_t *r_maxpolys;
+int max_polys;
+cvar_t *r_maxpolyverts;
+int max_polyverts;
+
+#define GENERIC_HW_R_PICMIP_DEFAULT "0"
+#define GENERIC_HW_R_TEXTUREMODE_DEFAULT "GL_LINEAR_MIPMAP_LINEAR"
+
+/*
+** InitOpenGL
+**
+** This function is responsible for initializing a valid OpenGL subsystem. This
+** is done by calling GLimp_Init (which gives us a working OGL subsystem) then
+** setting variables, checking GL constants, and reporting the gfx system config
+** to the user.
+*/
+static void InitOpenGL( void )
+{
+ char renderer_buffer[1024];
+
+ //
+ // initialize OS specific portions of the renderer
+ //
+ // GLimp_Init directly or indirectly references the following cvars:
+ // - r_fullscreen
+ // - r_(width|height|pixelAspect)
+ // - r_(color|depth|stencil)bits
+ // - r_ignorehwgamma
+ // - r_gamma
+ //
+
+ if ( glConfig.vidWidth == 0 )
+ {
+ GLint temp;
+
+ GLimp_Init( qfalse );
+
+ strcpy( renderer_buffer, glConfig.renderer_string );
+ Q_strlwr( renderer_buffer );
+
+ // OpenGL driver constants
+ qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp );
+ glConfig.maxTextureSize = temp;
+
+ // stubbed or broken drivers may have reported 0...
+ if ( glConfig.maxTextureSize <= 0 )
+ {
+ glConfig.maxTextureSize = 0;
+ }
+ }
+
+ // set default state
+ GL_SetDefaultState();
+}
+
+/*
+==================
+GL_CheckErrors
+==================
+*/
+void GL_CheckErrors( void ) {
+ int err;
+ char s[64];
+
+ err = qglGetError();
+ if ( err == GL_NO_ERROR ) {
+ return;
+ }
+ if ( r_ignoreGLErrors->integer ) {
+ return;
+ }
+ switch( err ) {
+ case GL_INVALID_ENUM:
+ strcpy( s, "GL_INVALID_ENUM" );
+ break;
+ case GL_INVALID_VALUE:
+ strcpy( s, "GL_INVALID_VALUE" );
+ break;
+ case GL_INVALID_OPERATION:
+ strcpy( s, "GL_INVALID_OPERATION" );
+ break;
+ case GL_STACK_OVERFLOW:
+ strcpy( s, "GL_STACK_OVERFLOW" );
+ break;
+ case GL_STACK_UNDERFLOW:
+ strcpy( s, "GL_STACK_UNDERFLOW" );
+ break;
+ case GL_OUT_OF_MEMORY:
+ strcpy( s, "GL_OUT_OF_MEMORY" );
+ break;
+ default:
+ Com_sprintf( s, sizeof(s), "%i", err);
+ break;
+ }
+
+ ri.Error( ERR_FATAL, "GL_CheckErrors: %s", s );
+}
+
+
+/*
+==============================================================================
+
+ SCREEN SHOTS
+
+NOTE TTimo
+some thoughts about the screenshots system:
+screenshots get written in fs_homepath + fs_gamedir
+vanilla q3 .. baseq3/screenshots/ *.tga
+team arena .. missionpack/screenshots/ *.tga
+
+two commands: "screenshot" and "screenshotJPEG"
+we use statics to store a count and start writing the first screenshot/screenshot????.tga (.jpg) available
+(with FS_FileExists / FS_FOpenFileWrite calls)
+FIXME: the statics don't get a reinit between fs_game changes
+
+==============================================================================
+*/
+
+/*
+==================
+RB_ReadPixels
+
+Reads an image but takes care of alignment issues for reading RGB images.
+
+Reads a minimum offset for where the RGB data starts in the image from
+integer stored at pointer offset. When the function has returned the actual
+offset was written back to address offset. This address will always have an
+alignment of packAlign to ensure efficient copying.
+
+Stores the length of padding after a line of pixels to address padlen
+
+Return value must be freed with ri.Hunk_FreeTempMemory()
+==================
+*/
+
+byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *padlen)
+{
+ byte *buffer, *bufstart;
+ int padwidth, linelen;
+ GLint packAlign;
+
+ qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);
+
+ linelen = width * 3;
+ padwidth = PAD(linelen, packAlign);
+
+ // Allocate a few more bytes so that we can choose an alignment we like
+ buffer = (byte*)ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1);
+
+ bufstart = (byte*)PADP((intptr_t) buffer + *offset, packAlign);
+ qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart);
+
+ *offset = bufstart - buffer;
+ *padlen = padwidth - linelen;
+
+ return buffer;
+}
+
+/*
+==================
+RB_TakeScreenshot
+==================
+*/
+void RB_TakeScreenshot(int x, int y, int width, int height, char *fileName)
+{
+ byte *allbuf, *buffer;
+ byte *srcptr, *destptr;
+ byte *endline, *endmem;
+ byte temp;
+
+ int linelen, padlen;
+ size_t offset = 18, memcount;
+
+ allbuf = RB_ReadPixels(x, y, width, height, &offset, &padlen);
+ buffer = allbuf + offset - 18;
+
+ Com_Memset (buffer, 0, 18);
+ buffer[2] = 2; // uncompressed type
+ buffer[12] = width & 255;
+ buffer[13] = width >> 8;
+ buffer[14] = height & 255;
+ buffer[15] = height >> 8;
+ buffer[16] = 24; // pixel size
+
+ // swap rgb to bgr and remove padding from line endings
+ linelen = width * 3;
+
+ srcptr = destptr = allbuf + offset;
+ endmem = srcptr + (linelen + padlen) * height;
+
+ while(srcptr < endmem)
+ {
+ endline = srcptr + linelen;
+
+ while(srcptr < endline)
+ {
+ temp = srcptr[0];
+ *destptr++ = srcptr[2];
+ *destptr++ = srcptr[1];
+ *destptr++ = temp;
+
+ srcptr += 3;
+ }
+
+ // Skip the pad
+ srcptr += padlen;
+ }
+
+ memcount = linelen * height;
+
+ // gamma correct
+ if(glConfig.deviceSupportsGamma)
+ R_GammaCorrect(allbuf + offset, memcount);
+
+ ri.FS_WriteFile(fileName, buffer, memcount + 18);
+
+ ri.Hunk_FreeTempMemory(allbuf);
+}
+
+/*
+==================
+RB_TakeScreenshotJPEG
+==================
+*/
+
+void RB_TakeScreenshotJPEG(int x, int y, int width, int height, char *fileName)
+{
+ byte *buffer;
+ size_t offset = 0, memcount;
+ int padlen;
+
+ buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen);
+ memcount = (width * 3 + padlen) * height;
+
+ // gamma correct
+ if(glConfig.deviceSupportsGamma)
+ R_GammaCorrect(buffer + offset, memcount);
+
+ RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, buffer + offset, padlen);
+ ri.Hunk_FreeTempMemory(buffer);
+}
+
+/*
+==================
+RB_TakeScreenshotCmd
+==================
+*/
+const void *RB_TakeScreenshotCmd( const void *data ) {
+ const screenshotCommand_t *cmd;
+
+ cmd = (const screenshotCommand_t *)data;
+
+ if (cmd->jpeg)
+ RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
+ else
+ RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
+
+ return (const void *)(cmd + 1);
+}
+
+/*
+==================
+R_TakeScreenshot
+==================
+*/
+void R_TakeScreenshot( int x, int y, int width, int height, char *name, bool jpeg ) {
+ static char fileName[MAX_OSPATH]; // bad things if two screenshots per frame?
+ screenshotCommand_t *cmd;
+
+ cmd = (screenshotCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_SCREENSHOT;
+
+ cmd->x = x;
+ cmd->y = y;
+ cmd->width = width;
+ cmd->height = height;
+ Q_strncpyz( fileName, name, sizeof(fileName) );
+ cmd->fileName = fileName;
+ cmd->jpeg = jpeg;
+}
+
+/*
+==================
+R_ScreenshotFilename
+==================
+*/
+void R_ScreenshotFilename( int lastNumber, char *fileName ) {
+ int a,b,c,d;
+
+ if ( lastNumber < 0 || lastNumber > 9999 ) {
+ Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.tga" );
+ return;
+ }
+
+ a = lastNumber / 1000;
+ lastNumber -= a*1000;
+ b = lastNumber / 100;
+ lastNumber -= b*100;
+ c = lastNumber / 10;
+ lastNumber -= c*10;
+ d = lastNumber;
+
+ Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.tga"
+ , a, b, c, d );
+}
+
+/*
+==================
+R_ScreenshotFilename
+==================
+*/
+void R_ScreenshotFilenameJPEG( int lastNumber, char *fileName ) {
+ int a,b,c,d;
+
+ if ( lastNumber < 0 || lastNumber > 9999 ) {
+ Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.jpg" );
+ return;
+ }
+
+ a = lastNumber / 1000;
+ lastNumber -= a*1000;
+ b = lastNumber / 100;
+ lastNumber -= b*100;
+ c = lastNumber / 10;
+ lastNumber -= c*10;
+ d = lastNumber;
+
+ Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.jpg"
+ , a, b, c, d );
+}
+
+/*
+====================
+R_LevelShot
+
+levelshots are specialized 128*128 thumbnails for
+the menu system, sampled down from full screen distorted images
+====================
+*/
+void R_LevelShot( void ) {
+ char checkname[MAX_OSPATH];
+ byte *buffer;
+ byte *source, *allsource;
+ byte *src, *dst;
+ size_t offset = 0;
+ int padlen;
+ int x, y;
+ int r, g, b;
+ float xScale, yScale;
+ int xx, yy;
+
+ Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName);
+
+ allsource = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &padlen);
+ source = allsource + offset;
+
+ buffer = (byte*)ri.Hunk_AllocateTempMemory(128 * 128*3 + 18);
+ Com_Memset (buffer, 0, 18);
+ buffer[2] = 2; // uncompressed type
+ buffer[12] = 128;
+ buffer[14] = 128;
+ buffer[16] = 24; // pixel size
+
+ // resample from source
+ xScale = glConfig.vidWidth / 512.0f;
+ yScale = glConfig.vidHeight / 384.0f;
+ for ( y = 0 ; y < 128 ; y++ ) {
+ for ( x = 0 ; x < 128 ; x++ ) {
+ r = g = b = 0;
+ for ( yy = 0 ; yy < 3 ; yy++ ) {
+ for ( xx = 0 ; xx < 4 ; xx++ ) {
+ src = source + (3 * glConfig.vidWidth + padlen) * (int)((y*3 + yy) * yScale) +
+ 3 * (int) ((x*4 + xx) * xScale);
+ r += src[0];
+ g += src[1];
+ b += src[2];
+ }
+ }
+ dst = buffer + 18 + 3 * ( y * 128 + x );
+ dst[0] = b / 12;
+ dst[1] = g / 12;
+ dst[2] = r / 12;
+ }
+ }
+
+ // gamma correct
+ if ( glConfig.deviceSupportsGamma ) {
+ R_GammaCorrect( buffer + 18, 128 * 128 * 3 );
+ }
+
+ ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 );
+
+ ri.Hunk_FreeTempMemory(buffer);
+ ri.Hunk_FreeTempMemory(allsource);
+
+ ri.Printf( PRINT_ALL, "Wrote %s\n", checkname );
+}
+
+/*
+==================
+R_ScreenShot_f
+
+screenshot
+screenshot [silent]
+screenshot [levelshot]
+screenshot [filename]
+
+Doesn't print the pacifier message if there is a second arg
+==================
+*/
+void R_ScreenShot_f (void) {
+ char checkname[MAX_OSPATH];
+ static int lastNumber = -1;
+ bool silent;
+
+ if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) {
+ R_LevelShot();
+ return;
+ }
+
+ if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) {
+ silent = true;
+ } else {
+ silent = false;
+ }
+
+ if ( ri.Cmd_Argc() == 2 && !silent ) {
+ // explicit filename
+ Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv( 1 ) );
+ } else {
+ // scan for a free filename
+
+ // if we have saved a previous screenshot, don't scan
+ // again, because recording demo avis can involve
+ // thousands of shots
+ if ( lastNumber == -1 ) {
+ lastNumber = 0;
+ }
+ // scan for a free number
+ for ( ; lastNumber <= 9999 ; lastNumber++ ) {
+ R_ScreenshotFilename( lastNumber, checkname );
+
+ if (!ri.FS_FileExists( checkname ))
+ {
+ break; // file doesn't exist
+ }
+ }
+
+ if ( lastNumber >= 9999 ) {
+ ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n");
+ return;
+ }
+
+ lastNumber++;
+ }
+
+ R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, false );
+
+ if ( !silent ) {
+ ri.Printf (PRINT_ALL, "Wrote %s\n", checkname);
+ }
+}
+
+void R_ScreenShotJPEG_f (void) {
+ char checkname[MAX_OSPATH];
+ static int lastNumber = -1;
+ bool silent;
+
+ if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) {
+ R_LevelShot();
+ return;
+ }
+
+ if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) {
+ silent = true;
+ } else {
+ silent = false;
+ }
+
+ if ( ri.Cmd_Argc() == 2 && !silent ) {
+ // explicit filename
+ Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.jpg", ri.Cmd_Argv( 1 ) );
+ } else {
+ // scan for a free filename
+
+ // if we have saved a previous screenshot, don't scan
+ // again, because recording demo avis can involve
+ // thousands of shots
+ if ( lastNumber == -1 ) {
+ lastNumber = 0;
+ }
+ // scan for a free number
+ for ( ; lastNumber <= 9999 ; lastNumber++ ) {
+ R_ScreenshotFilenameJPEG( lastNumber, checkname );
+
+ if (!ri.FS_FileExists( checkname ))
+ {
+ break; // file doesn't exist
+ }
+ }
+
+ if ( lastNumber == 10000 ) {
+ ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n");
+ return;
+ }
+
+ lastNumber++;
+ }
+
+ R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, true );
+
+ if ( !silent ) {
+ ri.Printf (PRINT_ALL, "Wrote %s\n", checkname);
+ }
+}
+
+//============================================================================
+
+/*
+==================
+RB_TakeVideoFrameCmd
+==================
+*/
+const void *RB_TakeVideoFrameCmd( const void *data )
+{
+ const videoFrameCommand_t *cmd;
+ byte *cBuf;
+ size_t memcount, linelen;
+ int padwidth, avipadwidth, padlen, avipadlen;
+ GLint packAlign;
+
+ cmd = (const videoFrameCommand_t *)data;
+
+ qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);
+
+ linelen = cmd->width * 3;
+
+ // Alignment stuff for glReadPixels
+ padwidth = PAD(linelen, packAlign);
+ padlen = padwidth - linelen;
+ // AVI line padding
+ avipadwidth = PAD(linelen, AVI_LINE_PADDING);
+ avipadlen = avipadwidth - linelen;
+
+ cBuf = (byte*)PADP(cmd->captureBuffer, packAlign);
+
+ qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB,
+ GL_UNSIGNED_BYTE, cBuf);
+
+ memcount = padwidth * cmd->height;
+
+ // gamma correct
+ if(glConfig.deviceSupportsGamma)
+ R_GammaCorrect(cBuf, memcount);
+
+ if(cmd->motionJpeg)
+ {
+ memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height,
+ r_aviMotionJpegQuality->integer,
+ cmd->width, cmd->height, cBuf, padlen);
+ ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount);
+ }
+ else
+ {
+ byte *lineend, *memend;
+ byte *srcptr, *destptr;
+
+ srcptr = cBuf;
+ destptr = cmd->encodeBuffer;
+ memend = srcptr + memcount;
+
+ // swap R and B and remove line paddings
+ while(srcptr < memend)
+ {
+ lineend = srcptr + linelen;
+ while(srcptr < lineend)
+ {
+ *destptr++ = srcptr[2];
+ *destptr++ = srcptr[1];
+ *destptr++ = srcptr[0];
+ srcptr += 3;
+ }
+
+ Com_Memset(destptr, '\0', avipadlen);
+ destptr += avipadlen;
+
+ srcptr += padlen;
+ }
+
+ ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, avipadwidth * cmd->height);
+ }
+
+ return (const void *)(cmd + 1);
+}
+
+//============================================================================
+
+/*
+** GL_SetDefaultState
+*/
+void GL_SetDefaultState( void )
+{
+ qglClearDepth( 1.0f );
+
+ qglCullFace(GL_FRONT);
+
+ qglColor4f (1,1,1,1);
+
+ // initialize downstream texture unit if we're running
+ // in a multitexture environment
+ if ( qglActiveTextureARB ) {
+ GL_SelectTexture( 1 );
+ GL_TextureMode( r_textureMode->string );
+ GL_TexEnv( GL_MODULATE );
+ qglDisable( GL_TEXTURE_2D );
+ GL_SelectTexture( 0 );
+ }
+
+ qglEnable(GL_TEXTURE_2D);
+ GL_TextureMode( r_textureMode->string );
+ GL_TexEnv( GL_MODULATE );
+
+ qglShadeModel( GL_SMOOTH );
+ qglDepthFunc( GL_LEQUAL );
+
+ // the vertex array is always enabled, but the color and texture
+ // arrays are enabled and disabled around the compiled vertex array call
+ qglEnableClientState (GL_VERTEX_ARRAY);
+
+ //
+ // make sure our GL state vector is set correctly
+ //
+ glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE;
+
+ qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+ qglDepthMask( GL_TRUE );
+ qglDisable( GL_DEPTH_TEST );
+ qglEnable( GL_SCISSOR_TEST );
+ qglDisable( GL_CULL_FACE );
+ qglDisable( GL_BLEND );
+}
+
+/*
+================
+R_PrintLongString
+
+Workaround for ri.Printf's 1024 characters buffer limit.
+================
+*/
+void R_PrintLongString(const char *string) {
+ char buffer[1024];
+ const char *p;
+ int size = strlen(string);
+
+ p = string;
+ while(size > 0)
+ {
+ Q_strncpyz(buffer, p, sizeof (buffer) );
+ ri.Printf( PRINT_ALL, "%s", buffer );
+ p += 1023;
+ size -= 1023;
+ }
+}
+
+/*
+================
+GfxInfo_f
+================
+*/
+void GfxInfo_f( void )
+{
+ const char *enablestrings[] =
+ {
+ "disabled",
+ "enabled"
+ };
+ const char *fsstrings[] =
+ {
+ "windowed",
+ "fullscreen"
+ };
+
+ ri.Printf( PRINT_ALL, "\nGL_VENDOR: %s\n", glConfig.vendor_string );
+ ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string );
+ ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string );
+ ri.Printf( PRINT_ALL, "GL_EXTENSIONS: " );
+ R_PrintLongString( glConfig.extensions_string );
+ ri.Printf( PRINT_ALL, "\n" );
+ ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize );
+ ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.numTextureUnits );
+ ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits );
+ ri.Printf( PRINT_ALL, "MODE: %d x %d %s hz:", glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] );
+ if ( glConfig.displayFrequency )
+ {
+ ri.Printf( PRINT_ALL, "%d\n", glConfig.displayFrequency );
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "N/A\n" );
+ }
+ if ( glConfig.deviceSupportsGamma )
+ {
+ ri.Printf( PRINT_ALL, "GAMMA: hardware w/ %d overbright bits\n", tr.overbrightBits );
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "GAMMA: software w/ %d overbright bits\n", tr.overbrightBits );
+ }
+
+ // rendering primitives
+ {
+ int primitives;
+
+ // default is to use triangles if compiled vertex arrays are present
+ ri.Printf( PRINT_ALL, "rendering primitives: " );
+ primitives = r_primitives->integer;
+ if ( primitives == 0 ) {
+ if ( qglLockArraysEXT ) {
+ primitives = 2;
+ } else {
+ primitives = 1;
+ }
+ }
+ if ( primitives == -1 ) {
+ ri.Printf( PRINT_ALL, "none\n" );
+ } else if ( primitives == 2 ) {
+ ri.Printf( PRINT_ALL, "single glDrawElements\n" );
+ } else if ( primitives == 1 ) {
+ ri.Printf( PRINT_ALL, "multiple glArrayElement\n" );
+ } else if ( primitives == 3 ) {
+ ri.Printf( PRINT_ALL, "multiple glColor4ubv + glTexCoord2fv + glVertex3fv\n" );
+ }
+ }
+
+ ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string );
+ ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer );
+ ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer );
+ ri.Printf( PRINT_ALL, "multitexture: %s\n", enablestrings[qglActiveTextureARB != 0] );
+ ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] );
+ ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] );
+ ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] );
+ if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 )
+ {
+ ri.Printf( PRINT_ALL, "HACK: using vertex lightmap approximation\n" );
+ }
+ if ( glConfig.hardwareType == GLHW_RAGEPRO )
+ {
+ ri.Printf( PRINT_ALL, "HACK: ragePro approximations\n" );
+ }
+ if ( glConfig.hardwareType == GLHW_RIVA128 )
+ {
+ ri.Printf( PRINT_ALL, "HACK: riva128 approximations\n" );
+ }
+ if ( r_finish->integer ) {
+ ri.Printf( PRINT_ALL, "Forcing glFinish\n" );
+ }
+}
+
+/*
+===============
+R_Register
+===============
+*/
+void R_Register( void )
+{
+ #ifdef USE_RENDERER_DLOPEN
+ com_altivec = ri.Cvar_Get("com_altivec", "1", CVAR_ARCHIVE);
+ #endif
+
+ //
+ // latched and archived variables
+ //
+ r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH);
+ r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH);
+
+ r_picmip = ri.Cvar_Get ("r_picmip", GENERIC_HW_R_PICMIP_DEFAULT,
+ CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic",
+ "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "2", CVAR_ARCHIVE | CVAR_LATCH );
+
+ r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH );
+ ri.Cvar_CheckRange( r_picmip, 0, 16, true );
+ r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_alphabits = ri.Cvar_Get( "r_alphabits", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH );
+ r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ ri.Cvar_CheckRange( r_ext_multisample, 0, 4, true );
+ r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE );
+ r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ r_width = ri.Cvar_Get( "r_width", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_height = ri.Cvar_Get( "r_height", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_pixelAspect = ri.Cvar_Get( "r_pixelAspect", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_simpleMipMaps = ri.Cvar_Get( "r_simpleMipMaps", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0);
+ r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH);
+ r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ r_ignoreFastPath = ri.Cvar_Get( "r_ignoreFastPath", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ ri.Cvar_CheckRange(r_greyscale, 0, 1, false);
+
+ //
+ // temporary latched variables that can only change over a restart
+ //
+ r_displayRefresh = ri.Cvar_Get( "r_displayRefresh", "0", CVAR_LATCH );
+ ri.Cvar_CheckRange( r_displayRefresh, 0, 200, true );
+ r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT );
+ r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH );
+ r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH );
+ r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH );
+
+ //
+ // archived variables that can change at any time
+ //
+ r_lodCurveError = ri.Cvar_Get( "r_lodCurveError", "250", CVAR_ARCHIVE|CVAR_CHEAT );
+ r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE );
+ r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE );
+ r_znear = ri.Cvar_Get( "r_znear", "1", CVAR_CHEAT );
+ ri.Cvar_CheckRange( r_znear, 0.001f, 200, false );
+ r_zproj = ri.Cvar_Get( "r_zproj", "64", CVAR_ARCHIVE );
+ r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", CVAR_ARCHIVE );
+ r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE );
+ r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE );
+ r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE );
+ r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE );
+ r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE );
+ r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE );
+ r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE);
+ r_textureMode = ri.Cvar_Get( "r_textureMode",
+ GENERIC_HW_R_TEXTUREMODE_DEFAULT, CVAR_ARCHIVE );
+ r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0",
+ CVAR_ARCHIVE | CVAR_LATCH );
+ r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE );
+ r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE );
+
+ r_railWidth = ri.Cvar_Get( "r_railWidth", "16", CVAR_ARCHIVE );
+ r_railCoreWidth = ri.Cvar_Get( "r_railCoreWidth", "6", CVAR_ARCHIVE );
+ r_railSegmentLength = ri.Cvar_Get( "r_railSegmentLength", "32", CVAR_ARCHIVE );
+
+ r_primitives = ri.Cvar_Get( "r_primitives", "0", CVAR_ARCHIVE );
+
+ r_ambientScale = ri.Cvar_Get( "r_ambientScale", "0.6", CVAR_CHEAT );
+ r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT );
+
+ r_anaglyphMode = ri.Cvar_Get("r_anaglyphMode", "0", CVAR_ARCHIVE);
+
+ //
+ // temporary variables that can change at any time
+ //
+ r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_CHEAT|CVAR_TEMP );
+
+ r_debugLight = ri.Cvar_Get( "r_debuglight", "0", CVAR_TEMP );
+ r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT );
+ r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 );
+ r_saveFontData = ri.Cvar_Get( "r_saveFontData", "0", 0 );
+
+ r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT );
+ r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT );
+ r_lightmap = ri.Cvar_Get ("r_lightmap", "0", CVAR_CHEAT );
+ r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_CHEAT );
+
+ r_flareSize = ri.Cvar_Get ("r_flareSize", "40", CVAR_CHEAT);
+ r_flareFade = ri.Cvar_Get ("r_flareFade", "7", CVAR_CHEAT);
+ r_flareCoeff = ri.Cvar_Get ("r_flareCoeff", FLARE_STDCOEFF, CVAR_CHEAT);
+
+ r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT);
+
+ r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT );
+ r_lodscale = ri.Cvar_Get( "r_lodscale", "5", CVAR_CHEAT );
+ r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT);
+ r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT );
+ r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT );
+ r_nocull = ri.Cvar_Get ("r_nocull", "0", CVAR_CHEAT);
+ r_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT);
+ r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT);
+ r_speeds = ri.Cvar_Get ("r_speeds", "0", CVAR_CHEAT);
+ r_verbose = ri.Cvar_Get( "r_verbose", "0", CVAR_CHEAT );
+ r_logFile = ri.Cvar_Get( "r_logFile", "0", CVAR_CHEAT );
+ r_debugSurface = ri.Cvar_Get ("r_debugSurface", "0", CVAR_CHEAT);
+ r_nobind = ri.Cvar_Get ("r_nobind", "0", CVAR_CHEAT);
+ r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT);
+ r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT);
+ r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT);
+ r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT);
+ r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT );
+ r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT );
+ r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT );
+ r_lockpvs = ri.Cvar_Get ("r_lockpvs", "0", CVAR_CHEAT);
+ r_noportals = ri.Cvar_Get ("r_noportals", "0", CVAR_CHEAT);
+ r_shadows = ri.Cvar_Get( "cg_shadows", "1", 0 );
+
+ r_marksOnTriangleMeshes = ri.Cvar_Get("r_marksOnTriangleMeshes", "0", CVAR_ARCHIVE);
+
+ r_aviMotionJpegQuality = ri.Cvar_Get("r_aviMotionJpegQuality", "90", CVAR_ARCHIVE);
+ r_screenshotJpegQuality = ri.Cvar_Get("r_screenshotJpegQuality", "90", CVAR_ARCHIVE);
+
+ r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0);
+ r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0);
+
+ // make sure all the commands added here are also
+ // removed in R_Shutdown
+ ri.Cmd_AddCommand( "imagelist", R_ImageList_f );
+ ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f );
+ ri.Cmd_AddCommand( "skinlist", R_SkinList_f );
+ ri.Cmd_AddCommand( "modellist", R_Modellist_f );
+ ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
+ ri.Cmd_AddCommand( "screenshotJPEG", R_ScreenShotJPEG_f );
+ ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f );
+ ri.Cmd_AddCommand( "minimize", GLimp_Minimize );
+}
+
+/*
+===============
+R_Init
+===============
+*/
+void R_Init( void ) {
+ int err;
+ int i;
+ byte *ptr;
+
+ ri.Printf( PRINT_ALL, "----- R_Init -----\n" );
+
+ // clear all our internal state
+ Com_Memset( &tr, 0, sizeof( tr ) );
+ Com_Memset( &backEnd, 0, sizeof( backEnd ) );
+ Com_Memset( &tess, 0, sizeof( tess ) );
+
+// Swap_Init();
+
+ if ( (intptr_t)tess.xyz & 15 ) {
+ ri.Printf( PRINT_WARNING, "tess.xyz not 16 byte aligned\n" );
+ }
+ Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) );
+
+ //
+ // init function tables
+ //
+ for ( i = 0; i < FUNCTABLE_SIZE; i++ )
+ {
+ tr.sinTable[i] = sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) );
+ tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f;
+ tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE;
+ tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i];
+
+ if ( i < FUNCTABLE_SIZE / 2 )
+ {
+ if ( i < FUNCTABLE_SIZE / 4 )
+ {
+ tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 );
+ }
+ else
+ {
+ tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4];
+ }
+ }
+ else
+ {
+ tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2];
+ }
+ }
+
+ R_InitFogTable();
+
+ R_NoiseInit();
+
+ R_Register();
+
+ max_polys = r_maxpolys->integer;
+ if (max_polys < MAX_POLYS)
+ max_polys = MAX_POLYS;
+
+ max_polyverts = r_maxpolyverts->integer;
+ if (max_polyverts < MAX_POLYVERTS)
+ max_polyverts = MAX_POLYVERTS;
+
+ ptr = (byte*)ri.Hunk_Alloc( sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low);
+ backEndData = (backEndData_t *) ptr;
+ backEndData->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData ));
+ backEndData->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys);
+ R_InitNextFrame();
+
+ InitOpenGL();
+
+ R_InitImages();
+
+ R_InitShaders();
+
+ R_InitSkins();
+
+ R_ModelInit();
+
+ R_InitFreeType();
+
+
+ err = qglGetError();
+ if ( err != GL_NO_ERROR )
+ ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err);
+
+ // print info
+ GfxInfo_f();
+ ri.Printf( PRINT_ALL, "----- finished R_Init -----\n" );
+}
+
+/*
+===============
+RE_Shutdown
+===============
+*/
+void RE_Shutdown( bool destroyWindow ) {
+
+ ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow );
+
+ ri.Cmd_RemoveCommand("gfxinfo");
+ ri.Cmd_RemoveCommand("imagelist");
+ ri.Cmd_RemoveCommand("modellist");
+ ri.Cmd_RemoveCommand("screenshot");
+ ri.Cmd_RemoveCommand("screenshotJPEG");
+ ri.Cmd_RemoveCommand("shaderlist");
+ ri.Cmd_RemoveCommand("skinlist");
+ ri.Cmd_RemoveCommand("minimize");
+
+ if ( tr.registered ) {
+ R_IssuePendingRenderCommands();
+ R_DeleteTextures();
+ }
+
+ R_DoneFreeType();
+
+ // shut down platform specific OpenGL stuff
+ if ( destroyWindow ) {
+ GLimp_Shutdown();
+
+ Com_Memset( &glConfig, 0, sizeof( glConfig ) );
+ Com_Memset( &glState, 0, sizeof( glState ) );
+ }
+
+ tr.registered = false;
+}
+
+
+/*
+=============
+RE_EndRegistration
+
+Touch all images to make sure they are resident
+=============
+*/
+void RE_EndRegistration( void ) {
+ R_IssuePendingRenderCommands();
+ if (!ri.Sys_LowPhysicalMemory()) {
+ RB_ShowImages();
+ }
+}
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+GetRefAPI
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+#ifdef USE_RENDERER_DLOPEN
+extern "C" Q_EXPORT refexport_t* QDECL GetRefAPI ( int apiVersion, refimport_t *rimp ) {
+#else
+refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {
+#endif
+
+ static refexport_t re;
+
+ ri = *rimp;
+
+ Com_Memset( &re, 0, sizeof( re ) );
+
+ if ( apiVersion != REF_API_VERSION ) {
+ ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n",
+ REF_API_VERSION, apiVersion );
+ return NULL;
+ }
+
+ // the RE_ functions are Renderer Entry points
+
+ re.Shutdown = RE_Shutdown;
+
+ re.BeginRegistration = RE_BeginRegistration;
+ re.RegisterModel = RE_RegisterModel;
+ re.RegisterSkin = RE_RegisterSkin;
+ re.RegisterShader = RE_RegisterShader;
+ re.RegisterShaderNoMip = RE_RegisterShaderNoMip;
+ re.LoadWorld = RE_LoadWorldMap;
+ re.SetWorldVisData = RE_SetWorldVisData;
+ re.EndRegistration = RE_EndRegistration;
+
+ re.BeginFrame = RE_BeginFrame;
+ re.EndFrame = RE_EndFrame;
+
+ re.MarkFragments = R_MarkFragments;
+ re.LerpTag = R_LerpTag;
+ re.ModelBounds = R_ModelBounds;
+
+ re.ClearScene = RE_ClearScene;
+ re.AddRefEntityToScene = RE_AddRefEntityToScene;
+ re.AddPolyToScene = RE_AddPolyToScene;
+ re.LightForPoint = R_LightForPoint;
+ re.AddLightToScene = RE_AddLightToScene;
+ re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene;
+ re.RenderScene = RE_RenderScene;
+
+ re.SetColor = RE_SetColor;
+ re.SetClipRegion = RE_SetClipRegion;
+ re.DrawStretchPic = RE_StretchPic;
+ re.DrawStretchRaw = RE_StretchRaw;
+ re.UploadCinematic = RE_UploadCinematic;
+
+ re.RegisterFont = RE_RegisterFont;
+ re.RemapShader = R_RemapShader;
+ re.GetEntityToken = R_GetEntityToken;
+ re.inPVS = R_inPVS;
+
+ re.TakeVideoFrame = RE_TakeVideoFrame;
+
+ return &re;
+}
diff --git a/src/renderergl1/tr_light.cpp b/src/renderergl1/tr_light.cpp
new file mode 100644
index 0000000..5cf13a8
--- /dev/null
+++ b/src/renderergl1/tr_light.cpp
@@ -0,0 +1,402 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_light.c
+
+#include "tr_local.h"
+
+#define DLIGHT_AT_RADIUS 16
+// at the edge of a dlight's influence, this amount of light will be added
+
+#define DLIGHT_MINIMUM_RADIUS 16
+// never calculate a range less than this to prevent huge light numbers
+
+
+/*
+===============
+R_TransformDlights
+
+Transforms the origins of an array of dlights.
+Used by both the front end (for DlightBmodel) and
+the back end (before doing the lighting calculation)
+===============
+*/
+void R_TransformDlights( int count, dlight_t *dl, orientationr_t *orientation) {
+ int i;
+ vec3_t temp;
+
+ for ( i = 0 ; i < count ; i++, dl++ ) {
+ VectorSubtract( dl->origin, orientation->origin, temp );
+ dl->transformed[0] = DotProduct( temp, orientation->axis[0] );
+ dl->transformed[1] = DotProduct( temp, orientation->axis[1] );
+ dl->transformed[2] = DotProduct( temp, orientation->axis[2] );
+ }
+}
+
+/*
+=============
+R_DlightBmodel
+
+Determine which dynamic lights may effect this bmodel
+=============
+*/
+void R_DlightBmodel( bmodel_t *bmodel ) {
+ int i, j;
+ dlight_t *dl;
+ int mask;
+ msurface_t *surf;
+
+ // transform all the lights
+ R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.orientation );
+
+ mask = 0;
+ for ( i=0 ; i<tr.refdef.num_dlights ; i++ ) {
+ dl = &tr.refdef.dlights[i];
+
+ // see if the point is close enough to the bounds to matter
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) {
+ break;
+ }
+ if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) {
+ break;
+ }
+ }
+ if ( j < 3 ) {
+ continue;
+ }
+
+ // we need to check this light
+ mask |= 1 << i;
+ }
+
+ tr.currentEntity->needDlights = (mask != 0);
+
+ // set the dlight bits in all the surfaces
+ for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
+ surf = bmodel->firstSurface + i;
+
+ if ( *surf->data == SF_FACE ) {
+ ((srfSurfaceFace_t *)surf->data)->dlightBits = mask;
+ } else if ( *surf->data == SF_GRID ) {
+ ((srfGridMesh_t *)surf->data)->dlightBits = mask;
+ } else if ( *surf->data == SF_TRIANGLES ) {
+ ((srfTriangles_t *)surf->data)->dlightBits = mask;
+ }
+ }
+}
+
+
+/*
+=============================================================================
+
+LIGHT SAMPLING
+
+=============================================================================
+*/
+
+extern cvar_t *r_ambientScale;
+extern cvar_t *r_directedScale;
+extern cvar_t *r_debugLight;
+
+/*
+=================
+R_SetupEntityLightingGrid
+
+=================
+*/
+static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
+ vec3_t lightOrigin;
+ int pos[3];
+ int i, j;
+ byte *gridData;
+ float frac[3];
+ int gridStep[3];
+ vec3_t direction;
+ float totalFactor;
+
+ if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
+ // seperate lightOrigins are needed so an object that is
+ // sinking into the ground can still be lit, and so
+ // multi-part models can be lit identically
+ VectorCopy( ent->e.lightingOrigin, lightOrigin );
+ } else {
+ VectorCopy( ent->e.origin, lightOrigin );
+ }
+
+ VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ float v;
+
+ v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
+ pos[i] = floor( v );
+ frac[i] = v - pos[i];
+ if ( pos[i] < 0 ) {
+ pos[i] = 0;
+ } else if ( pos[i] > tr.world->lightGridBounds[i] - 1 ) {
+ pos[i] = tr.world->lightGridBounds[i] - 1;
+ }
+ }
+
+ VectorClear( ent->ambientLight );
+ VectorClear( ent->directedLight );
+ VectorClear( direction );
+
+ assert( tr.world->lightGridData ); // NULL with -nolight maps
+
+ // trilerp the light value
+ gridStep[0] = 8;
+ gridStep[1] = 8 * tr.world->lightGridBounds[0];
+ gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
+ gridData = tr.world->lightGridData + pos[0] * gridStep[0]
+ + pos[1] * gridStep[1] + pos[2] * gridStep[2];
+
+ totalFactor = 0;
+ for ( i = 0 ; i < 8 ; i++ ) {
+ float factor;
+ byte *data;
+ int lat, lng;
+ vec3_t normal;
+ #if idppc
+ float d0, d1, d2, d3, d4, d5;
+ #endif
+ factor = 1.0;
+ data = gridData;
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( i & (1<<j) ) {
+ if ( pos[j] + 1 > tr.world->lightGridBounds[j] - 1 ) {
+ break; // ignore values outside lightgrid
+ }
+ factor *= frac[j];
+ data += gridStep[j];
+ } else {
+ factor *= (1.0f - frac[j]);
+ }
+ }
+
+ if ( j != 3 ) {
+ continue;
+ }
+ if ( !(data[0]+data[1]+data[2]) ) {
+ continue; // ignore samples in walls
+ }
+ totalFactor += factor;
+ #if idppc
+ d0 = data[0]; d1 = data[1]; d2 = data[2];
+ d3 = data[3]; d4 = data[4]; d5 = data[5];
+
+ ent->ambientLight[0] += factor * d0;
+ ent->ambientLight[1] += factor * d1;
+ ent->ambientLight[2] += factor * d2;
+
+ ent->directedLight[0] += factor * d3;
+ ent->directedLight[1] += factor * d4;
+ ent->directedLight[2] += factor * d5;
+ #else
+ ent->ambientLight[0] += factor * data[0];
+ ent->ambientLight[1] += factor * data[1];
+ ent->ambientLight[2] += factor * data[2];
+
+ ent->directedLight[0] += factor * data[3];
+ ent->directedLight[1] += factor * data[4];
+ ent->directedLight[2] += factor * data[5];
+ #endif
+ lat = data[7];
+ lng = data[6];
+ lat *= (FUNCTABLE_SIZE/256);
+ lng *= (FUNCTABLE_SIZE/256);
+
+ // decode X as cos( lat ) * sin( long )
+ // decode Y as sin( lat ) * sin( long )
+ // decode Z as cos( long )
+
+ normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+ normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
+ normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+
+ VectorMA( direction, factor, normal, direction );
+ }
+
+ if ( totalFactor > 0 && totalFactor < 0.99 ) {
+ totalFactor = 1.0f / totalFactor;
+ VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
+ VectorScale( ent->directedLight, totalFactor, ent->directedLight );
+ }
+
+ VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
+ VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );
+
+ VectorNormalize2( direction, ent->lightDir );
+}
+
+
+/*
+===============
+LogLight
+===============
+*/
+static void LogLight( trRefEntity_t *ent ) {
+ int max1, max2;
+
+ if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) {
+ return;
+ }
+
+ max1 = ent->ambientLight[0];
+ if ( ent->ambientLight[1] > max1 ) {
+ max1 = ent->ambientLight[1];
+ } else if ( ent->ambientLight[2] > max1 ) {
+ max1 = ent->ambientLight[2];
+ }
+
+ max2 = ent->directedLight[0];
+ if ( ent->directedLight[1] > max2 ) {
+ max2 = ent->directedLight[1];
+ } else if ( ent->directedLight[2] > max2 ) {
+ max2 = ent->directedLight[2];
+ }
+
+ ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 );
+}
+
+/*
+=================
+R_SetupEntityLighting
+
+Calculates all the lighting values that will be used
+by the Calc_* functions
+=================
+*/
+void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
+ int i;
+ dlight_t *dl;
+ float power;
+ vec3_t dir;
+ float d;
+ vec3_t lightDir;
+ vec3_t lightOrigin;
+
+ // lighting calculations
+ if ( ent->lightingCalculated ) {
+ return;
+ }
+ ent->lightingCalculated = true;
+
+ //
+ // trace a sample point down to find ambient light
+ //
+ if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
+ // seperate lightOrigins are needed so an object that is
+ // sinking into the ground can still be lit, and so
+ // multi-part models can be lit identically
+ VectorCopy( ent->e.lightingOrigin, lightOrigin );
+ } else {
+ VectorCopy( ent->e.origin, lightOrigin );
+ }
+
+ // if NOWORLDMODEL, only use dynamic lights (menu system, etc)
+ if ( !(refdef->rdflags & RDF_NOWORLDMODEL )
+ && tr.world->lightGridData ) {
+ R_SetupEntityLightingGrid( ent );
+ } else {
+ ent->ambientLight[0] = ent->ambientLight[1] =
+ ent->ambientLight[2] = tr.identityLight * 150;
+ ent->directedLight[0] = ent->directedLight[1] =
+ ent->directedLight[2] = tr.identityLight * 150;
+ VectorCopy( tr.sunDirection, ent->lightDir );
+ }
+
+ // bonus items and view weapons have a fixed minimum add
+ if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) {
+ // give everything a minimum light add
+ ent->ambientLight[0] += tr.identityLight * 32;
+ ent->ambientLight[1] += tr.identityLight * 32;
+ ent->ambientLight[2] += tr.identityLight * 32;
+ }
+
+ //
+ // modify the light by dynamic lights
+ //
+ d = VectorLength( ent->directedLight );
+ VectorScale( ent->lightDir, d, lightDir );
+
+ for ( i = 0 ; i < refdef->num_dlights ; i++ ) {
+ dl = &refdef->dlights[i];
+ VectorSubtract( dl->origin, lightOrigin, dir );
+ d = VectorNormalize( dir );
+
+ power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius );
+ if ( d < DLIGHT_MINIMUM_RADIUS ) {
+ d = DLIGHT_MINIMUM_RADIUS;
+ }
+ d = power / ( d * d );
+
+ VectorMA( ent->directedLight, d, dl->color, ent->directedLight );
+ VectorMA( lightDir, d, dir, lightDir );
+ }
+
+ // clamp ambient
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( ent->ambientLight[i] > tr.identityLightByte ) {
+ ent->ambientLight[i] = tr.identityLightByte;
+ }
+ }
+
+ if ( r_debugLight->integer ) {
+ LogLight( ent );
+ }
+
+ // save out the byte packet version
+ ((byte *)&ent->ambientLightInt)[0] = static_cast<int>(ent->ambientLight[0]);
+ ((byte *)&ent->ambientLightInt)[1] = static_cast<int>(ent->ambientLight[1]);
+ ((byte *)&ent->ambientLightInt)[2] = static_cast<int>(ent->ambientLight[2]);
+ ((byte *)&ent->ambientLightInt)[3] = 0xff;
+
+ // transform the direction to local space
+ VectorNormalize( lightDir );
+ ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] );
+ ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] );
+ ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] );
+}
+
+/*
+=================
+R_LightForPoint
+=================
+*/
+bool R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir )
+{
+ trRefEntity_t ent;
+
+ if ( tr.world->lightGridData == NULL )
+ return false;
+
+ Com_Memset(&ent, 0, sizeof(ent));
+ VectorCopy( point, ent.e.origin );
+ R_SetupEntityLightingGrid( &ent );
+ VectorCopy(ent.ambientLight, ambientLight);
+ VectorCopy(ent.directedLight, directedLight);
+ VectorCopy(ent.lightDir, lightDir);
+
+ return true;
+}
diff --git a/src/renderergl1/tr_local.h b/src/renderergl1/tr_local.h
new file mode 100644
index 0000000..e954036
--- /dev/null
+++ b/src/renderergl1/tr_local.h
@@ -0,0 +1,1603 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+
+#ifndef TR_LOCAL_H
+#define TR_LOCAL_H
+
+#include <stdbool.h>
+
+#include "qcommon/cvar.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/qfiles.h"
+#include "qcommon/qcommon.h"
+
+#include "renderercommon/tr_common.h"
+
+#define GL_INDEX_TYPE GL_UNSIGNED_INT
+typedef unsigned int glIndex_t;
+
+// 14 bits
+// can't be increased without changing bit packing for drawsurfs
+// see QSORT_SHADERNUM_SHIFT
+#define SHADERNUM_BITS 14
+#define MAX_SHADERS (1<<SHADERNUM_BITS)
+
+
+
+typedef struct dlight_s {
+ vec3_t origin;
+ vec3_t color; // range from 0.0 to 1.0, should be color normalized
+ float radius;
+
+ vec3_t transformed; // origin in local coordinate system
+ int additive; // texture detail is lost tho when the lightmap is dark
+} dlight_t;
+
+
+// a trRefEntity_t has all the information passed in by
+// the client game, as well as some locally derived info
+typedef struct {
+ refEntity_t e;
+
+ float axisLength; // compensate for non-normalized axis
+
+ bool needDlights; // true for bmodels that touch a dlight
+ bool lightingCalculated;
+ vec3_t lightDir; // normalized direction towards light
+ vec3_t ambientLight; // color normalized to 0-255
+ int ambientLightInt; // 32 bit rgba packed
+ vec3_t directedLight;
+} trRefEntity_t;
+
+
+typedef struct {
+ vec3_t origin; // in world coordinates
+ vec3_t axis[3]; // orientation in world
+ vec3_t viewOrigin; // viewParms->or.origin in local coordinates
+ float modelMatrix[16];
+} orientationr_t;
+
+//===============================================================================
+
+typedef enum {
+ SS_BAD,
+ SS_PORTAL, // mirrors, portals, viewscreens
+ SS_ENVIRONMENT, // sky box
+ SS_OPAQUE, // opaque
+
+ SS_DECAL, // scorch marks, etc.
+ SS_SEE_THROUGH, // ladders, grates, grills that may have small blended edges
+ // in addition to alpha test
+ SS_BANNER,
+
+ SS_FOG,
+
+ SS_UNDERWATER, // for items that should be drawn in front of the water plane
+
+ SS_BLEND0, // regular transparency and filters
+ SS_BLEND1, // generally only used for additive type effects
+ SS_BLEND2,
+ SS_BLEND3,
+
+ SS_BLEND6,
+ SS_STENCIL_SHADOW,
+ SS_ALMOST_NEAREST, // gun smoke puffs
+
+ SS_NEAREST // blood blobs
+} shaderSort_t;
+
+
+#define MAX_SHADER_STAGES 8
+
+typedef enum {
+ GF_NONE,
+
+ GF_SIN,
+ GF_SQUARE,
+ GF_TRIANGLE,
+ GF_SAWTOOTH,
+ GF_INVERSE_SAWTOOTH,
+
+ GF_NOISE
+
+} genFunc_t;
+
+
+typedef enum {
+ DEFORM_NONE,
+ DEFORM_WAVE,
+ DEFORM_NORMALS,
+ DEFORM_BULGE,
+ DEFORM_MOVE,
+ DEFORM_PROJECTION_SHADOW,
+ DEFORM_AUTOSPRITE,
+ DEFORM_AUTOSPRITE2,
+ DEFORM_TEXT0,
+ DEFORM_TEXT1,
+ DEFORM_TEXT2,
+ DEFORM_TEXT3,
+ DEFORM_TEXT4,
+ DEFORM_TEXT5,
+ DEFORM_TEXT6,
+ DEFORM_TEXT7
+} deform_t;
+
+typedef enum {
+ AGEN_IDENTITY,
+ AGEN_SKIP,
+ AGEN_ENTITY,
+ AGEN_ONE_MINUS_ENTITY,
+ AGEN_VERTEX,
+ AGEN_ONE_MINUS_VERTEX,
+ AGEN_LIGHTING_SPECULAR,
+ AGEN_WAVEFORM,
+ AGEN_PORTAL,
+ AGEN_CONST
+} alphaGen_t;
+
+typedef enum {
+ CGEN_BAD,
+ CGEN_IDENTITY_LIGHTING, // tr.identityLight
+ CGEN_IDENTITY, // always (1,1,1,1)
+ CGEN_ENTITY, // grabbed from entity's modulate field
+ CGEN_ONE_MINUS_ENTITY, // grabbed from 1 - entity.modulate
+ CGEN_EXACT_VERTEX, // tess.vertexColors
+ CGEN_VERTEX, // tess.vertexColors * tr.identityLight
+ CGEN_ONE_MINUS_VERTEX,
+ CGEN_WAVEFORM, // programmatically generated
+ CGEN_LIGHTING_DIFFUSE,
+ CGEN_FOG, // standard fog
+ CGEN_CONST // fixed color
+} colorGen_t;
+
+typedef enum {
+ TCGEN_BAD,
+ TCGEN_IDENTITY, // clear to 0,0
+ TCGEN_LIGHTMAP,
+ TCGEN_TEXTURE,
+ TCGEN_ENVIRONMENT_MAPPED,
+ TCGEN_FOG,
+ TCGEN_VECTOR // S and T from world coordinates
+} texCoordGen_t;
+
+typedef enum {
+ ACFF_NONE,
+ ACFF_MODULATE_RGB,
+ ACFF_MODULATE_RGBA,
+ ACFF_MODULATE_ALPHA
+} acff_t;
+
+typedef struct {
+ genFunc_t func;
+
+ float base;
+ float amplitude;
+ float phase;
+ float frequency;
+} waveForm_t;
+
+#define TR_MAX_TEXMODS 4
+
+typedef enum {
+ TMOD_NONE,
+ TMOD_TRANSFORM,
+ TMOD_TURBULENT,
+ TMOD_SCROLL,
+ TMOD_SCALE,
+ TMOD_STRETCH,
+ TMOD_ROTATE,
+ TMOD_ENTITY_TRANSLATE
+} texMod_t;
+
+#define MAX_SHADER_DEFORMS 3
+typedef struct {
+ deform_t deformation; // vertex coordinate modification type
+
+ vec3_t moveVector;
+ waveForm_t deformationWave;
+ float deformationSpread;
+
+ float bulgeWidth;
+ float bulgeHeight;
+ float bulgeSpeed;
+} deformStage_t;
+
+
+typedef struct {
+ texMod_t type;
+
+ // used for TMOD_TURBULENT and TMOD_STRETCH
+ waveForm_t wave;
+
+ // used for TMOD_TRANSFORM
+ float matrix[2][2]; // s' = s * m[0][0] + t * m[1][0] + trans[0]
+ float translate[2]; // t' = s * m[0][1] + t * m[0][1] + trans[1]
+
+ // used for TMOD_SCALE
+ float scale[2]; // s *= scale[0]
+ // t *= scale[1]
+
+ // used for TMOD_SCROLL
+ float scroll[2]; // s' = s + scroll[0] * time
+ // t' = t + scroll[1] * time
+
+ // + = clockwise
+ // - = counterclockwise
+ float rotateSpeed;
+
+} texModInfo_t;
+
+
+#define MAX_IMAGE_ANIMATIONS 8
+
+typedef struct {
+ image_t *image[MAX_IMAGE_ANIMATIONS];
+ int numImageAnimations;
+ float imageAnimationSpeed;
+
+ texCoordGen_t tcGen;
+ vec3_t tcGenVectors[2];
+
+ int numTexMods;
+ texModInfo_t *texMods;
+
+ int videoMapHandle;
+ bool isLightmap;
+ bool isVideoMap;
+} textureBundle_t;
+
+#define NUM_TEXTURE_BUNDLES 2
+
+typedef struct {
+ bool active;
+
+ textureBundle_t bundle[NUM_TEXTURE_BUNDLES];
+
+ waveForm_t rgbWave;
+ colorGen_t rgbGen;
+
+ waveForm_t alphaWave;
+ alphaGen_t alphaGen;
+
+ byte constantColor[4]; // for CGEN_CONST and AGEN_CONST
+
+ unsigned stateBits; // GLS_xxxx mask
+
+ acff_t adjustColorsForFog;
+
+ bool isDetail;
+} shaderStage_t;
+
+struct shaderCommands_s;
+
+typedef enum {
+ CT_FRONT_SIDED,
+ CT_BACK_SIDED,
+ CT_TWO_SIDED
+} cullType_t;
+
+typedef enum {
+ FP_NONE, // surface is translucent and will just be adjusted properly
+ FP_EQUAL, // surface is opaque but possibly alpha tested
+ FP_LE // surface is trnaslucent, but still needs a fog pass (fog surface)
+} fogPass_t;
+
+typedef struct {
+ float cloudHeight;
+ image_t *outerbox[6], *innerbox[6];
+} skyParms_t;
+
+typedef struct {
+ vec3_t color;
+ float depthForOpaque;
+} fogParms_t;
+
+
+typedef struct shader_s {
+ char name[MAX_QPATH]; // game path, including extension
+ int lightmapIndex; // for a shader to match, both name and lightmapIndex must match
+
+ int index; // this shader == tr.shaders[index]
+ int sortedIndex; // this shader == tr.sortedShaders[sortedIndex]
+
+ float sort; // lower numbered shaders draw before higher numbered
+
+ bool defaultShader; // we want to return index 0 if the shader failed to
+ // load for some reason, but R_FindShader should
+ // still keep a name allocated for it, so if
+ // something calls RE_RegisterShader again with
+ // the same name, we don't try looking for it again
+
+ bool explicitlyDefined; // found in a .shader file
+
+ int surfaceFlags; // if explicitlyDefined, this will have SURF_* flags
+ int contentFlags;
+
+ bool entityMergable; // merge across entites optimizable (smoke, blood)
+
+ bool isSky;
+ skyParms_t sky;
+ fogParms_t fogParms;
+
+ float portalRange; // distance to fog out at
+
+ int multitextureEnv; // 0, GL_MODULATE, GL_ADD (FIXME: put in stage)
+
+ cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED
+ bool polygonOffset; // set for decals and other items that must be offset
+ bool noMipMaps; // for console fonts, 2D elements, etc.
+ bool noPicMip; // for images that must always be full resolution
+
+ fogPass_t fogPass; // draw a blended pass, possibly with depth test equals
+
+ bool needsNormal; // not all shaders will need all data to be gathered
+ bool needsST1;
+ bool needsST2;
+ bool needsColor;
+
+ int numDeforms;
+ deformStage_t deforms[MAX_SHADER_DEFORMS];
+
+ int numUnfoggedPasses;
+ shaderStage_t *stages[MAX_SHADER_STAGES];
+
+ void (*optimalStageIteratorFunc)( void );
+
+ double clampTime; // time this shader is clamped to
+ double timeOffset; // current time offset for this shader
+
+ struct shader_s *remappedShader; // current shader this one is remapped too
+
+ struct shader_s *next;
+} shader_t;
+
+
+// trRefdef_t holds everything that comes in refdef_t,
+// as well as the locally generated scene information
+typedef struct {
+ int x, y, width, height;
+ float fov_x, fov_y;
+ vec3_t vieworg;
+ vec3_t viewaxis[3]; // transformation matrix
+
+ stereoFrame_t stereoFrame;
+
+ int time; // time in milliseconds for shader effects and other time dependent rendering issues
+ int rdflags; // RDF_NOWORLDMODEL, etc
+
+ // 1 bits will prevent the associated area from rendering at all
+ byte areamask[MAX_MAP_AREA_BYTES];
+ bool areamaskModified; // true if areamask changed since last scene
+
+ double floatTime; // tr.refdef.time / 1000.0
+
+ // text messages for deform text shaders
+ char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];
+
+ int num_entities;
+ trRefEntity_t *entities;
+
+ int num_dlights;
+ struct dlight_s *dlights;
+
+ int numPolys;
+ struct srfPoly_s *polys;
+
+ int numDrawSurfs;
+ struct drawSurf_s *drawSurfs;
+
+
+} trRefdef_t;
+
+
+//=================================================================================
+
+// max surfaces per-skin
+// This is an arbitry limit. Vanilla Q3 only supported 32 surfaces in skins but failed to
+// enforce the maximum limit when reading skin files. It was possile to use more than 32
+// surfaces which accessed out of bounds memory past end of skin->surfaces hunk block.
+#define MAX_SKIN_SURFACES 256
+
+// skins allow models to be retextured without modifying the model file
+typedef struct {
+ char name[MAX_QPATH];
+ shader_t *shader;
+} skinSurface_t;
+
+typedef struct skin_s {
+ char name[MAX_QPATH]; // game path, including extension
+ int numSurfaces;
+ skinSurface_t *surfaces; // dynamically allocated array of surfaces
+} skin_t;
+
+
+typedef struct {
+ int originalBrushNumber;
+ vec3_t bounds[2];
+
+ unsigned colorInt; // in packed byte format
+ float tcScale; // texture coordinate vector scales
+ fogParms_t parms;
+
+ // for clipping distance in fog when outside
+ bool hasSurface;
+ float surface[4];
+} fog_t;
+
+typedef struct {
+ orientationr_t orientation;
+ orientationr_t world;
+ vec3_t pvsOrigin; // may be different than or.origin for portals
+ bool isPortal; // true if this view is through a portal
+ bool isMirror; // the portal is a mirror, invert the face culling
+ int frameSceneNum; // copied from tr.frameSceneNum
+ int frameCount; // copied from tr.frameCount
+ cplane_t portalPlane; // clip anything behind this if mirroring
+ int viewportX, viewportY, viewportWidth, viewportHeight;
+ float fovX, fovY;
+ float projectionMatrix[16];
+ cplane_t frustum[4];
+ vec3_t visBounds[2];
+ float zFar;
+ stereoFrame_t stereoFrame;
+} viewParms_t;
+
+
+/*
+==============================================================================
+
+SURFACES
+
+==============================================================================
+*/
+
+// any changes in surfaceType must be mirrored in rb_surfaceTable[]
+typedef enum {
+ SF_BAD,
+ SF_SKIP, // ignore
+ SF_FACE,
+ SF_GRID,
+ SF_TRIANGLES,
+ SF_POLY,
+ SF_MD3,
+ SF_MDR,
+ SF_IQM,
+ SF_FLARE,
+ SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
+
+ SF_NUM_SURFACE_TYPES,
+ SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
+} surfaceType_t;
+
+typedef struct drawSurf_s {
+ unsigned sort; // bit combination for fast compares
+ surfaceType_t *surface; // any of surface*_t
+} drawSurf_t;
+
+#define MAX_FACE_POINTS 64
+
+#define MAX_PATCH_SIZE 32 // max dimensions of a patch mesh in map file
+#define MAX_GRID_SIZE 65 // max dimensions of a grid mesh in memory
+
+// when cgame directly specifies a polygon, it becomes a srfPoly_t
+// as soon as it is called
+typedef struct srfPoly_s {
+ surfaceType_t surfaceType;
+ qhandle_t hShader;
+ int fogIndex;
+ int numVerts;
+ polyVert_t *verts;
+} srfPoly_t;
+
+
+typedef struct srfFlare_s {
+ surfaceType_t surfaceType;
+ vec3_t origin;
+ vec3_t normal;
+ vec3_t color;
+} srfFlare_t;
+
+typedef struct srfGridMesh_s {
+ surfaceType_t surfaceType;
+
+ // dynamic lighting information
+ int dlightBits;
+
+ // culling information
+ vec3_t meshBounds[2];
+ vec3_t localOrigin;
+ float meshRadius;
+
+ // lod information, which may be different
+ // than the culling information to allow for
+ // groups of curves that LOD as a unit
+ vec3_t lodOrigin;
+ float lodRadius;
+ int lodFixed;
+ int lodStitched;
+
+ // vertexes
+ int width, height;
+ float *widthLodError;
+ float *heightLodError;
+ drawVert_t verts[1]; // variable sized
+} srfGridMesh_t;
+
+
+
+#define VERTEXSIZE 8
+typedef struct {
+ surfaceType_t surfaceType;
+ cplane_t plane;
+
+ // dynamic lighting information
+ int dlightBits;
+
+ // triangle definitions (no normals at points)
+ int numPoints;
+ int numIndices;
+ int ofsIndices;
+ float points[1][VERTEXSIZE]; // variable sized
+ // there is a variable length list of indices here also
+} srfSurfaceFace_t;
+
+
+// misc_models in maps are turned into direct geometry by q3map
+typedef struct {
+ surfaceType_t surfaceType;
+
+ // dynamic lighting information
+ int dlightBits;
+
+ // culling information (FIXME: use this!)
+ vec3_t bounds[2];
+ vec3_t localOrigin;
+ float radius;
+
+ // triangle definitions
+ int numIndexes;
+ int *indexes;
+
+ int numVerts;
+ drawVert_t *verts;
+} srfTriangles_t;
+
+// inter-quake-model
+typedef struct {
+ int num_vertexes;
+ int num_triangles;
+ int num_frames;
+ int num_surfaces;
+ int num_joints;
+ int num_poses;
+ struct srfIQModel_s *surfaces;
+
+ float *positions;
+ float *texcoords;
+ float *normals;
+ float *tangents;
+ byte *blendIndexes;
+ union {
+ float *f;
+ byte *b;
+ } blendWeights;
+ byte *colors;
+ int *triangles;
+
+ // depending upon the exporter, blend indices and weights might be int/float
+ // as opposed to the recommended byte/byte, for example Noesis exports
+ // int/float whereas the official IQM tool exports byte/byte
+ byte blendWeightsType; // IQM_UBYTE or IQM_FLOAT
+
+ int *jointParents;
+ float *jointMats;
+ float *poseMats;
+ float *bounds;
+ char *names;
+} iqmData_t;
+
+// inter-quake-model surface
+typedef struct srfIQModel_s {
+ surfaceType_t surfaceType;
+ char name[MAX_QPATH];
+ shader_t *shader;
+ iqmData_t *data;
+ int first_vertex, num_vertexes;
+ int first_triangle, num_triangles;
+} srfIQModel_t;
+
+
+extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *);
+
+/*
+==============================================================================
+
+BRUSH MODELS
+
+==============================================================================
+*/
+
+
+//
+// in memory representation
+//
+
+#define SIDE_FRONT 0
+#define SIDE_BACK 1
+#define SIDE_ON 2
+
+typedef struct msurface_s {
+ int viewCount; // if == tr.viewCount, already added
+ struct shader_s *shader;
+ int fogIndex;
+
+ surfaceType_t *data; // any of srf*_t
+} msurface_t;
+
+
+
+#define CONTENTS_NODE -1
+typedef struct mnode_s {
+ // common with leaf and node
+ int contents; // -1 for nodes, to differentiate from leafs
+ int visframe; // node needs to be traversed if current
+ vec3_t mins, maxs; // for bounding box culling
+ struct mnode_s *parent;
+
+ // node specific
+ cplane_t *plane;
+ struct mnode_s *children[2];
+
+ // leaf specific
+ int cluster;
+ int area;
+
+ msurface_t **firstmarksurface;
+ int nummarksurfaces;
+} mnode_t;
+
+typedef struct {
+ vec3_t bounds[2]; // for culling
+ msurface_t *firstSurface;
+ int numSurfaces;
+} bmodel_t;
+
+typedef struct {
+ char name[MAX_QPATH]; // ie: maps/tim_dm2.bsp
+ char baseName[MAX_QPATH]; // ie: tim_dm2
+
+ int dataSize;
+
+ int numShaders;
+ dshader_t *shaders;
+
+ bmodel_t *bmodels;
+
+ int numplanes;
+ cplane_t *planes;
+
+ int numnodes; // includes leafs
+ int numDecisionNodes;
+ mnode_t *nodes;
+
+ int numsurfaces;
+ msurface_t *surfaces;
+
+ int nummarksurfaces;
+ msurface_t **marksurfaces;
+
+ int numfogs;
+ fog_t *fogs;
+
+ vec3_t lightGridOrigin;
+ vec3_t lightGridSize;
+ vec3_t lightGridInverseSize;
+ int lightGridBounds[3];
+ byte *lightGridData;
+
+
+ int numClusters;
+ int clusterBytes;
+ const byte *vis; // may be passed in by CM_LoadMap to save space
+
+ byte *novis; // clusterBytes of 0xff
+
+ char *entityString;
+ char *entityParsePoint;
+} world_t;
+
+//======================================================================
+
+typedef enum {
+ MOD_BAD,
+ MOD_BRUSH,
+ MOD_MESH,
+ MOD_MDR,
+ MOD_IQM
+} modtype_t;
+
+typedef struct model_s {
+ char name[MAX_QPATH];
+ modtype_t type;
+ int index; // model = tr.models[model->index]
+
+ int dataSize; // just for listing purposes
+ bmodel_t *bmodel; // only if type == MOD_BRUSH
+ md3Header_t *md3[MD3_MAX_LODS]; // only if type == MOD_MESH
+ void *modelData; // only if type == (MOD_MDR | MOD_IQM)
+
+ int numLods;
+} model_t;
+
+
+#define MAX_MOD_KNOWN 1024
+
+void R_ModelInit (void);
+model_t *R_GetModelByHandle( qhandle_t hModel );
+int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
+ float frac, const char *tagName );
+void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs );
+
+void R_Modellist_f (void);
+
+//====================================================
+
+#define MAX_DRAWIMAGES 2048
+#define MAX_SKINS 1024
+
+
+#define MAX_DRAWSURFS 0x10000
+#define DRAWSURF_MASK (MAX_DRAWSURFS-1)
+
+/*
+
+the drawsurf sort data is packed into a single 32 bit value so it can be
+compared quickly during the qsorting process
+
+the bits are allocated as follows:
+
+0 - 1 : dlightmap index
+//2 : used to be clipped flag REMOVED - 03.21.00 rad
+2 - 6 : fog index
+11 - 20 : entity index
+21 - 31 : sorted shader index
+
+ TTimo - 1.32
+0-1 : dlightmap index
+2-6 : fog index
+7-16 : entity index
+17-30 : sorted shader index
+*/
+#define QSORT_FOGNUM_SHIFT 2
+#define QSORT_REFENTITYNUM_SHIFT 7
+#define QSORT_SHADERNUM_SHIFT (QSORT_REFENTITYNUM_SHIFT+REFENTITYNUM_BITS)
+#if (QSORT_SHADERNUM_SHIFT+SHADERNUM_BITS) > 32
+ #error "Need to update sorting, too many bits."
+#endif
+
+extern int gl_filter_min, gl_filter_max;
+
+/*
+** performanceCounters_t
+*/
+typedef struct {
+ int c_sphere_cull_patch_in, c_sphere_cull_patch_clip, c_sphere_cull_patch_out;
+ int c_box_cull_patch_in, c_box_cull_patch_clip, c_box_cull_patch_out;
+ int c_sphere_cull_md3_in, c_sphere_cull_md3_clip, c_sphere_cull_md3_out;
+ int c_box_cull_md3_in, c_box_cull_md3_clip, c_box_cull_md3_out;
+
+ int c_leafs;
+ int c_dlightSurfaces;
+ int c_dlightSurfacesCulled;
+} frontEndCounters_t;
+
+#define FOG_TABLE_SIZE 256
+#define FUNCTABLE_SIZE 1024
+#define FUNCTABLE_SIZE2 10
+#define FUNCTABLE_MASK (FUNCTABLE_SIZE-1)
+
+
+// the renderer front end should never modify glstate_t
+typedef struct {
+ int currenttextures[2];
+ int currenttmu;
+ bool finishCalled;
+ int texEnv[2];
+ int faceCulling;
+ unsigned long glStateBits;
+} glstate_t;
+
+typedef struct {
+ int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes;
+ float c_overDraw;
+
+ int c_dlightVertexes;
+ int c_dlightIndexes;
+
+ int c_flareAdds;
+ int c_flareTests;
+ int c_flareRenders;
+
+ int msec; // total msec for backend run
+} backEndCounters_t;
+
+// all state modified by the back end is seperated
+// from the front end state
+typedef struct {
+ trRefdef_t refdef;
+ viewParms_t viewParms;
+ orientationr_t orientation;
+ backEndCounters_t pc;
+ bool isHyperspace;
+ trRefEntity_t *currentEntity;
+ bool skyRenderedThisView; // flag for drawing sun
+
+ bool projection2D; // if true, drawstretchpic doesn't need to change modes
+ byte color2D[4];
+ bool vertexes2D; // shader needs to be finished
+ trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering
+} backEndState_t;
+
+/*
+** trGlobals_t
+**
+** Most renderer globals are defined here.
+** backend functions should never modify any of these fields,
+** but may read fields that aren't dynamically modified
+** by the frontend.
+*/
+typedef struct {
+ bool registered; // cleared at shutdown, set at beginRegistration
+
+ int visCount; // incremented every time a new vis cluster is entered
+ int frameCount; // incremented every frame
+ int sceneCount; // incremented every scene
+ int viewCount; // incremented every view (twice a scene if portaled)
+ // and every R_MarkFragments call
+
+ int frameSceneNum; // zeroed at RE_BeginFrame
+
+ bool worldMapLoaded;
+ world_t *world;
+
+ const byte *externalVisData; // from RE_SetWorldVisData, shared with CM_Load
+
+ image_t *defaultImage;
+ image_t *scratchImage[32];
+ image_t *fogImage;
+ image_t *dlightImage; // inverse-quare highlight for projective adding
+ image_t *flareImage;
+ image_t *whiteImage; // full of 0xff
+ image_t *identityLightImage; // full of tr.identityLightByte
+
+ shader_t *defaultShader;
+ shader_t *shadowShader;
+ shader_t *projectionShadowShader;
+
+ shader_t *flareShader;
+ shader_t *sunShader;
+
+ int numLightmaps;
+ image_t **lightmaps;
+
+ trRefEntity_t *currentEntity;
+ trRefEntity_t worldEntity; // point currentEntity at this when rendering world
+ int currentEntityNum;
+ int shiftedEntityNum; // currentEntityNum << QSORT_REFENTITYNUM_SHIFT
+ model_t *currentModel;
+
+ viewParms_t viewParms;
+
+ float identityLight; // 1.0 / ( 1 << overbrightBits )
+ int identityLightByte; // identityLight * 255
+ int overbrightBits; // r_overbrightBits->integer, but set to 0 if no hw gamma
+
+ orientationr_t orientation; // for current entity
+
+ trRefdef_t refdef;
+
+ int viewCluster;
+
+ vec3_t sunLight; // from the sky shader for this level
+ vec3_t sunDirection;
+
+ frontEndCounters_t pc;
+ int frontEndMsec; // not in pc due to clearing issue
+
+ vec4_t clipRegion; // 2D clipping region
+
+ //
+ // put large tables at the end, so most elements will be
+ // within the +/32K indexed range on risc processors
+ //
+ model_t *models[MAX_MOD_KNOWN];
+ int numModels;
+
+ int numImages;
+ image_t *images[MAX_DRAWIMAGES];
+
+ // shader indexes from other modules will be looked up in tr.shaders[]
+ // shader indexes from drawsurfs will be looked up in sortedShaders[]
+ // lower indexed sortedShaders must be rendered first (opaque surfaces before translucent)
+ int numShaders;
+ shader_t *shaders[MAX_SHADERS];
+ shader_t *sortedShaders[MAX_SHADERS];
+
+ int numSkins;
+ skin_t *skins[MAX_SKINS];
+
+ float sinTable[FUNCTABLE_SIZE];
+ float squareTable[FUNCTABLE_SIZE];
+ float triangleTable[FUNCTABLE_SIZE];
+ float sawToothTable[FUNCTABLE_SIZE];
+ float inverseSawToothTable[FUNCTABLE_SIZE];
+ float fogTable[FOG_TABLE_SIZE];
+} trGlobals_t;
+
+extern backEndState_t backEnd;
+extern trGlobals_t tr;
+extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init
+
+//
+// cvars
+//
+extern cvar_t *r_flareSize;
+extern cvar_t *r_flareFade;
+// coefficient for the flare intensity falloff function.
+#define FLARE_STDCOEFF "150"
+extern cvar_t *r_flareCoeff;
+
+extern cvar_t *r_railWidth;
+extern cvar_t *r_railCoreWidth;
+extern cvar_t *r_railSegmentLength;
+
+extern cvar_t *r_ignore; // used for debugging anything
+extern cvar_t *r_verbose; // used for verbose debug spew
+extern cvar_t *r_ignoreFastPath; // allows us to ignore our Tess fast paths
+
+extern cvar_t *r_znear; // near Z clip plane
+extern cvar_t *r_zproj; // z distance of projection plane
+extern cvar_t *r_stereoSeparation; // separation of cameras for stereo rendering
+
+extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement
+
+extern cvar_t *r_lodbias; // push/pull LOD transitions
+extern cvar_t *r_lodscale;
+
+extern cvar_t *r_primitives; // "0" = based on compiled vertex array existance
+ // "1" = glDrawElemet tristrips
+ // "2" = glDrawElements triangles
+ // "-1" = no drawing
+
+extern cvar_t *r_inGameVideo; // controls whether in game video should be draw
+extern cvar_t *r_fastsky; // controls whether sky should be cleared or drawn
+extern cvar_t *r_drawSun; // controls drawing of sun quad
+extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled
+extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity
+
+extern cvar_t *r_norefresh; // bypasses the ref rendering
+extern cvar_t *r_drawentities; // disable/enable entity rendering
+extern cvar_t *r_drawworld; // disable/enable world rendering
+extern cvar_t *r_speeds; // various levels of information display
+extern cvar_t *r_detailTextures; // enables/disables detail texturing stages
+extern cvar_t *r_novis; // disable/enable usage of PVS
+extern cvar_t *r_nocull;
+extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back side test
+extern cvar_t *r_nocurves;
+extern cvar_t *r_showcluster;
+
+extern cvar_t *r_gamma;
+extern cvar_t *r_displayRefresh; // optional display refresh option
+extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities
+
+extern cvar_t *r_allowExtensions; // global enable/disable of OpenGL extensions
+extern cvar_t *r_ext_compressed_textures; // these control use of specific extensions
+extern cvar_t *r_ext_multitexture;
+extern cvar_t *r_ext_compiled_vertex_array;
+extern cvar_t *r_ext_texture_env_add;
+
+extern cvar_t *r_ext_texture_filter_anisotropic;
+extern cvar_t *r_ext_max_anisotropy;
+
+extern cvar_t *r_nobind; // turns off binding to appropriate textures
+extern cvar_t *r_singleShader; // make most world faces use default shader
+extern cvar_t *r_roundImagesDown;
+extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage
+extern cvar_t *r_picmip; // controls picmip values
+extern cvar_t *r_finish;
+extern cvar_t *r_textureMode;
+extern cvar_t *r_offsetFactor;
+extern cvar_t *r_offsetUnits;
+
+extern cvar_t *r_fullbright; // avoid lightmap pass
+extern cvar_t *r_lightmap; // render lightmaps only
+extern cvar_t *r_vertexLight; // vertex lighting mode for better performance
+extern cvar_t *r_uiFullScreen; // ui is running fullscreen
+
+extern cvar_t *r_logFile; // number of frames to emit GL logs
+extern cvar_t *r_showtris; // enables wireframe rendering of the world
+extern cvar_t *r_showsky; // forces sky in front of all surfaces
+extern cvar_t *r_shownormals; // draws wireframe normals
+extern cvar_t *r_clear; // force screen clear every frame
+
+extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection
+extern cvar_t *r_flares; // light flares
+
+extern cvar_t *r_intensity;
+
+extern cvar_t *r_lockpvs;
+extern cvar_t *r_noportals;
+extern cvar_t *r_portalOnly;
+
+extern cvar_t *r_subdivisions;
+extern cvar_t *r_lodCurveError;
+extern cvar_t *r_skipBackEnd;
+
+extern cvar_t *r_anaglyphMode;
+
+extern cvar_t *r_greyscale;
+
+extern cvar_t *r_ignoreGLErrors;
+
+extern cvar_t *r_overBrightBits;
+extern cvar_t *r_mapOverBrightBits;
+
+extern cvar_t *r_debugSurface;
+extern cvar_t *r_simpleMipMaps;
+
+extern cvar_t *r_showImages;
+extern cvar_t *r_debugSort;
+
+extern cvar_t *r_printShaders;
+
+extern cvar_t *r_marksOnTriangleMeshes;
+
+//====================================================================
+
+void R_SwapBuffers( int );
+
+void R_RenderView( viewParms_t *parms );
+
+void R_AddMD3Surfaces( trRefEntity_t *e );
+void R_AddNullModelSurfaces( trRefEntity_t *e );
+void R_AddBeamSurfaces( trRefEntity_t *e );
+void R_AddRailSurfaces( trRefEntity_t *e, bool isUnderwater );
+void R_AddLightningBoltSurfaces( trRefEntity_t *e );
+
+void R_AddPolygonSurfaces( void );
+
+void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
+ int *fogNum, int *dlightMap );
+
+void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );
+
+
+#define CULL_IN 0 // completely unclipped
+#define CULL_CLIP 1 // clipped by one or more planes
+#define CULL_OUT 2 // completely outside the clipping planes
+void R_LocalNormalToWorld (vec3_t local, vec3_t world);
+void R_LocalPointToWorld (vec3_t local, vec3_t world);
+int R_CullLocalBox (vec3_t bounds[2]);
+int R_CullPointAndRadius( vec3_t origin, float radius );
+int R_CullLocalPointAndRadius( vec3_t origin, float radius );
+
+void R_SetupProjection(viewParms_t *dest, float zProj, bool computeFrustum);
+void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *orientation );
+
+/*
+** GL wrapper/helper functions
+*/
+void GL_Bind( image_t *image );
+void GL_SetDefaultState (void);
+void GL_SelectTexture( int unit );
+void GL_TextureMode( const char *string );
+void GL_CheckErrors( void );
+void GL_State( unsigned long stateVector );
+void GL_TexEnv( int env );
+void GL_Cull( int cullType );
+
+#define GLS_SRCBLEND_ZERO 0x00000001
+#define GLS_SRCBLEND_ONE 0x00000002
+#define GLS_SRCBLEND_DST_COLOR 0x00000003
+#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004
+#define GLS_SRCBLEND_SRC_ALPHA 0x00000005
+#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006
+#define GLS_SRCBLEND_DST_ALPHA 0x00000007
+#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008
+#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009
+#define GLS_SRCBLEND_BITS 0x0000000f
+
+#define GLS_DSTBLEND_ZERO 0x00000010
+#define GLS_DSTBLEND_ONE 0x00000020
+#define GLS_DSTBLEND_SRC_COLOR 0x00000030
+#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040
+#define GLS_DSTBLEND_SRC_ALPHA 0x00000050
+#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060
+#define GLS_DSTBLEND_DST_ALPHA 0x00000070
+#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080
+#define GLS_DSTBLEND_BITS 0x000000f0
+
+#define GLS_DEPTHMASK_TRUE 0x00000100
+
+#define GLS_POLYMODE_LINE 0x00001000
+
+#define GLS_DEPTHTEST_DISABLE 0x00010000
+#define GLS_DEPTHFUNC_EQUAL 0x00020000
+
+#define GLS_ATEST_GT_0 0x10000000
+#define GLS_ATEST_LT_80 0x20000000
+#define GLS_ATEST_GE_80 0x40000000
+#define GLS_ATEST_BITS 0x70000000
+
+#define GLS_DEFAULT GLS_DEPTHMASK_TRUE
+
+void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, bool dirty);
+void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, bool dirty);
+
+void RE_BeginFrame( stereoFrame_t stereoFrame );
+void RE_BeginRegistration( glconfig_t *glconfig );
+void RE_LoadWorldMap( const char *mapname );
+void RE_SetWorldVisData( const byte *vis );
+qhandle_t RE_RegisterModel( const char *name );
+qhandle_t RE_RegisterSkin( const char *name );
+void RE_Shutdown( bool destroyWindow );
+
+bool R_GetEntityToken( char *buffer, int size );
+
+model_t *R_AllocModel( void );
+
+void R_Init( void );
+
+void R_SetColorMappings( void );
+void R_GammaCorrect( byte *buffer, int bufSize );
+
+void R_ImageList_f( void );
+void R_SkinList_f( void );
+// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516
+const void *RB_TakeScreenshotCmd( const void *data );
+void R_ScreenShot_f( void );
+
+void R_InitFogTable( void );
+float R_FogFactor( float s, float t );
+void R_InitImages( void );
+void R_DeleteTextures( void );
+int R_SumOfUsedImages( void );
+void R_InitSkins( void );
+skin_t *R_GetSkinByHandle( qhandle_t hSkin );
+
+int R_ComputeLOD( trRefEntity_t *ent );
+
+const void *RB_TakeVideoFrameCmd( const void *data );
+
+//
+// tr_shader.c
+//
+shader_t *R_FindShader( const char *name, int lightmapIndex, bool mipRawImage );
+shader_t *R_GetShaderByHandle( qhandle_t hShader );
+shader_t *R_GetShaderByState( int index, long *cycleTime );
+shader_t *R_FindShaderByName( const char *name );
+void R_InitShaders( void );
+void R_ShaderList_f( void );
+void R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset);
+
+/*
+====================================================================
+
+TESSELATOR/SHADER DECLARATIONS
+
+====================================================================
+*/
+typedef byte color4ub_t[4];
+
+typedef struct stageVars
+{
+ color4ub_t colors[SHADER_MAX_VERTEXES];
+ vec2_t texcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES];
+} stageVars_t;
+
+
+typedef struct shaderCommands_s
+{
+ glIndex_t indexes[SHADER_MAX_INDEXES] QALIGN(16);
+ vec4_t xyz[SHADER_MAX_VERTEXES] QALIGN(16);
+ vec4_t normal[SHADER_MAX_VERTEXES] QALIGN(16);
+ vec2_t texCoords[SHADER_MAX_VERTEXES][2] QALIGN(16);
+ color4ub_t vertexColors[SHADER_MAX_VERTEXES] QALIGN(16);
+ int vertexDlightBits[SHADER_MAX_VERTEXES] QALIGN(16);
+
+ stageVars_t svars QALIGN(16);
+
+ color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16);
+
+ shader_t *shader;
+ double shaderTime;
+ int fogNum;
+
+ int dlightBits; // or together of all vertexDlightBits
+
+ int numIndexes;
+ int numVertexes;
+
+ // info extracted from current shader
+ int numPasses;
+ void (*currentStageIteratorFunc)( void );
+ shaderStage_t **xstages;
+} shaderCommands_t;
+
+extern shaderCommands_t tess;
+
+void RB_BeginSurface(shader_t *shader, int fogNum );
+void RB_EndSurface(void);
+void RB_CheckOverflow( int verts, int indexes );
+#define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);}
+
+void RB_StageIteratorGeneric( void );
+void RB_StageIteratorSky( void );
+void RB_StageIteratorVertexLitTexture( void );
+void RB_StageIteratorLightmappedMultitexture( void );
+
+void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color );
+void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 );
+
+void RB_ShowImages( void );
+
+
+/*
+============================================================
+
+WORLD MAP
+
+============================================================
+*/
+
+void R_AddBrushModelSurfaces( trRefEntity_t *e );
+void R_AddWorldSurfaces( void );
+bool R_inPVS( const vec3_t p1, const vec3_t p2 );
+
+
+/*
+============================================================
+
+FLARES
+
+============================================================
+*/
+
+void R_ClearFlares( void );
+
+void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal );
+void RB_AddDlightFlares( void );
+void RB_RenderFlares (void);
+
+/*
+============================================================
+
+LIGHTS
+
+============================================================
+*/
+
+void R_DlightBmodel( bmodel_t *bmodel );
+void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent );
+void R_TransformDlights( int count, dlight_t *dl, orientationr_t *orientation );
+bool R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
+
+
+/*
+============================================================
+
+SHADOWS
+
+============================================================
+*/
+
+void RB_ShadowTessEnd( void );
+void RB_ShadowFinish( void );
+void RB_ProjectionShadowDeform( void );
+
+/*
+============================================================
+
+SKIES
+
+============================================================
+*/
+
+void R_BuildCloudData( shaderCommands_t *shader );
+void R_InitSkyTexCoords( float cloudLayerHeight );
+void R_DrawSkyBox( shaderCommands_t *shader );
+void RB_DrawSun( float scale, shader_t *shader );
+void RB_ClipSkyPolygons( shaderCommands_t *shader );
+
+/*
+============================================================
+
+CURVE TESSELATION
+
+============================================================
+*/
+
+#define PATCH_STITCHING
+
+srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
+ drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] );
+srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror );
+srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror );
+void R_FreeSurfaceGridMesh( srfGridMesh_t *grid );
+
+/*
+============================================================
+
+MARKERS, POLYGON PROJECTION ON WORLD POLYGONS
+
+============================================================
+*/
+
+int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
+ int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
+
+
+/*
+============================================================
+
+SCENE GENERATION
+
+============================================================
+*/
+
+void R_InitNextFrame( void );
+
+void RE_ClearScene( void );
+void RE_AddRefEntityToScene( const refEntity_t *ent );
+void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
+void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
+void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b );
+void RE_RenderScene( const refdef_t *fd );
+
+/*
+=============================================================
+
+UNCOMPRESSING BONES
+
+=============================================================
+*/
+
+#define MC_BITS_X (16)
+#define MC_BITS_Y (16)
+#define MC_BITS_Z (16)
+#define MC_BITS_VECT (16)
+
+#define MC_SCALE_X (1.0f/64)
+#define MC_SCALE_Y (1.0f/64)
+#define MC_SCALE_Z (1.0f/64)
+
+void MC_UnCompress(float mat[3][4],const unsigned char * comp);
+
+/*
+=============================================================
+
+ANIMATED MODELS
+
+=============================================================
+*/
+
+void R_MDRAddAnimSurfaces( trRefEntity_t *ent );
+void RB_MDRSurfaceAnim( mdrSurface_t *surface );
+bool R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name );
+void R_AddIQMSurfaces( trRefEntity_t *ent );
+void RB_IQMSurfaceAnim( surfaceType_t *surface );
+int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
+ int startFrame, int endFrame,
+ float frac, const char *tagName );
+
+/*
+=============================================================
+=============================================================
+*/
+void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
+ vec4_t eye, vec4_t dst );
+void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window );
+
+void RB_DeformTessGeometry( void );
+
+void RB_CalcEnvironmentTexCoords( float *dstTexCoords );
+void RB_CalcFogTexCoords( float *dstTexCoords );
+void RB_CalcScrollTexCoords( const float scroll[2], float *dstTexCoords );
+void RB_CalcRotateTexCoords( float rotSpeed, float *dstTexCoords );
+void RB_CalcScaleTexCoords( const float scale[2], float *dstTexCoords );
+void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *dstTexCoords );
+void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *dstTexCoords );
+void RB_CalcModulateColorsByFog( unsigned char *dstColors );
+void RB_CalcModulateAlphasByFog( unsigned char *dstColors );
+void RB_CalcModulateRGBAsByFog( unsigned char *dstColors );
+void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors );
+void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors );
+void RB_CalcAlphaFromEntity( unsigned char *dstColors );
+void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors );
+void RB_CalcStretchTexCoords( const waveForm_t *wf, float *texCoords );
+void RB_CalcColorFromEntity( unsigned char *dstColors );
+void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors );
+void RB_CalcSpecularAlpha( unsigned char *alphas );
+void RB_CalcDiffuseColor( unsigned char *colors );
+
+/*
+=============================================================
+
+RENDERER BACK END FUNCTIONS
+
+=============================================================
+*/
+
+void RB_ExecuteRenderCommands( const void *data );
+
+/*
+=============================================================
+
+RENDERER BACK END COMMAND QUEUE
+
+=============================================================
+*/
+
+#define MAX_RENDER_COMMANDS 0x40000
+
+typedef struct {
+ byte cmds[MAX_RENDER_COMMANDS];
+ int used;
+} renderCommandList_t;
+
+typedef struct {
+ int commandId;
+ float color[4];
+} setColorCommand_t;
+
+typedef struct {
+ int commandId;
+ int buffer;
+} drawBufferCommand_t;
+
+typedef struct {
+ int commandId;
+ image_t *image;
+ int width;
+ int height;
+ void *data;
+} subImageCommand_t;
+
+typedef struct {
+ int commandId;
+} swapBuffersCommand_t;
+
+typedef struct {
+ int commandId;
+ int buffer;
+} endFrameCommand_t;
+
+typedef struct {
+ int commandId;
+ shader_t *shader;
+ float x, y;
+ float w, h;
+ float s1, t1;
+ float s2, t2;
+} stretchPicCommand_t;
+
+typedef struct {
+ int commandId;
+ trRefdef_t refdef;
+ viewParms_t viewParms;
+ drawSurf_t *drawSurfs;
+ int numDrawSurfs;
+} drawSurfsCommand_t;
+
+typedef struct {
+ int commandId;
+ int x;
+ int y;
+ int width;
+ int height;
+ char *fileName;
+ bool jpeg;
+} screenshotCommand_t;
+
+typedef struct {
+ int commandId;
+ int width;
+ int height;
+ byte *captureBuffer;
+ byte *encodeBuffer;
+ bool motionJpeg;
+} videoFrameCommand_t;
+
+typedef struct
+{
+ int commandId;
+
+ GLboolean rgba[4];
+} colorMaskCommand_t;
+
+typedef struct
+{
+ int commandId;
+} clearDepthCommand_t;
+
+typedef enum {
+ RC_END_OF_LIST,
+ RC_SET_COLOR,
+ RC_STRETCH_PIC,
+ RC_DRAW_SURFS,
+ RC_DRAW_BUFFER,
+ RC_SWAP_BUFFERS,
+ RC_SCREENSHOT,
+ RC_VIDEOFRAME,
+ RC_COLORMASK,
+ RC_CLEARDEPTH
+} renderCommand_t;
+
+
+// these are sort of arbitrary limits.
+// the limits apply to the sum of all scenes in a frame --
+// the main view, all the 3D icons, etc
+#define MAX_POLYS 600
+#define MAX_POLYVERTS 3000
+
+// all of the information needed by the back end must be
+// contained in a backEndData_t
+typedef struct {
+ drawSurf_t drawSurfs[MAX_DRAWSURFS];
+ dlight_t dlights[MAX_DLIGHTS];
+ trRefEntity_t entities[MAX_REFENTITIES];
+ srfPoly_t *polys;//[MAX_POLYS];
+ polyVert_t *polyVerts;//[MAX_POLYVERTS];
+ renderCommandList_t commands;
+} backEndData_t;
+
+extern int max_polys;
+extern int max_polyverts;
+
+extern backEndData_t *backEndData; // the second one may not be allocated
+
+
+void *R_GetCommandBuffer( int bytes );
+void RB_ExecuteRenderCommands( const void *data );
+
+void R_IssuePendingRenderCommands( void );
+
+void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs );
+
+void RE_SetColor( const float *rgba );
+void RE_SetClipRegion( const float *region );
+void RE_StretchPic ( float x, float y, float w, float h,
+ float s1, float t1, float s2, float t2, qhandle_t hShader );
+void RE_BeginFrame( stereoFrame_t stereoFrame );
+void RE_EndFrame( int *frontEndMsec, int *backEndMsec );
+void RE_SaveJPG(char * filename, int quality, int image_width, int image_height,
+ unsigned char *image_buffer, int padding);
+size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality,
+ int image_width, int image_height, byte *image_buffer, int padding);
+void RE_TakeVideoFrame( int width, int height,
+ byte *captureBuffer, byte *encodeBuffer, bool motionJpeg );
+
+
+#endif //TR_LOCAL_H
diff --git a/src/renderergl1/tr_main.cpp b/src/renderergl1/tr_main.cpp
new file mode 100644
index 0000000..1be6ae7
--- /dev/null
+++ b/src/renderergl1/tr_main.cpp
@@ -0,0 +1,1394 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_main.c -- main control flow for each frame
+
+#include "tr_local.h"
+
+#include <string.h> // memcpy
+
+trGlobals_t tr;
+
+static float s_flipMatrix[16] = {
+ // convert from our coordinate system (looking down X)
+ // to OpenGL's coordinate system (looking down -Z)
+ 0, 0, -1, 0,
+ -1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 0, 1
+};
+
+
+refimport_t ri;
+
+// entities that will have procedurally generated surfaces will just
+// point at this for their sorting surface
+surfaceType_t entitySurface = SF_ENTITY;
+
+/*
+=================
+R_CullLocalBox
+
+Returns CULL_IN, CULL_CLIP, or CULL_OUT
+=================
+*/
+int R_CullLocalBox (vec3_t bounds[2]) {
+ int i, j;
+ vec3_t transformed[8];
+ float dists[8];
+ vec3_t v;
+ cplane_t *frust;
+ int anyBack;
+ int front, back;
+
+ if ( r_nocull->integer ) {
+ return CULL_CLIP;
+ }
+
+ // transform into world space
+ for (i = 0 ; i < 8 ; i++) {
+ v[0] = bounds[i&1][0];
+ v[1] = bounds[(i>>1)&1][1];
+ v[2] = bounds[(i>>2)&1][2];
+
+ VectorCopy( tr.orientation.origin, transformed[i] );
+ VectorMA( transformed[i], v[0], tr.orientation.axis[0], transformed[i] );
+ VectorMA( transformed[i], v[1], tr.orientation.axis[1], transformed[i] );
+ VectorMA( transformed[i], v[2], tr.orientation.axis[2], transformed[i] );
+ }
+
+ // check against frustum planes
+ anyBack = 0;
+ for (i = 0 ; i < 4 ; i++) {
+ frust = &tr.viewParms.frustum[i];
+
+ front = back = 0;
+ for (j = 0 ; j < 8 ; j++) {
+ dists[j] = DotProduct(transformed[j], frust->normal);
+ if ( dists[j] > frust->dist ) {
+ front = 1;
+ if ( back ) {
+ break; // a point is in front
+ }
+ } else {
+ back = 1;
+ }
+ }
+ if ( !front ) {
+ // all points were behind one of the planes
+ return CULL_OUT;
+ }
+ anyBack |= back;
+ }
+
+ if ( !anyBack ) {
+ return CULL_IN; // completely inside frustum
+ }
+
+ return CULL_CLIP; // partially clipped
+}
+
+/*
+** R_CullLocalPointAndRadius
+*/
+int R_CullLocalPointAndRadius( vec3_t pt, float radius )
+{
+ vec3_t transformed;
+
+ R_LocalPointToWorld( pt, transformed );
+
+ return R_CullPointAndRadius( transformed, radius );
+}
+
+/*
+** R_CullPointAndRadius
+*/
+int R_CullPointAndRadius( vec3_t pt, float radius )
+{
+ int i;
+ float dist;
+ cplane_t *frust;
+ bool mightBeClipped = false;
+
+ if ( r_nocull->integer ) {
+ return CULL_CLIP;
+ }
+
+ // check against frustum planes
+ for (i = 0 ; i < 4 ; i++)
+ {
+ frust = &tr.viewParms.frustum[i];
+
+ dist = DotProduct( pt, frust->normal) - frust->dist;
+ if ( dist < -radius )
+ {
+ return CULL_OUT;
+ }
+ else if ( dist <= radius )
+ {
+ mightBeClipped = true;
+ }
+ }
+
+ if ( mightBeClipped )
+ {
+ return CULL_CLIP;
+ }
+
+ return CULL_IN; // completely inside frustum
+}
+
+
+/*
+=================
+R_LocalNormalToWorld
+
+=================
+*/
+void R_LocalNormalToWorld (vec3_t local, vec3_t world) {
+ world[0] = local[0] * tr.orientation.axis[0][0] + local[1] * tr.orientation.axis[1][0] + local[2] * tr.orientation.axis[2][0];
+ world[1] = local[0] * tr.orientation.axis[0][1] + local[1] * tr.orientation.axis[1][1] + local[2] * tr.orientation.axis[2][1];
+ world[2] = local[0] * tr.orientation.axis[0][2] + local[1] * tr.orientation.axis[1][2] + local[2] * tr.orientation.axis[2][2];
+}
+
+/*
+=================
+R_LocalPointToWorld
+
+=================
+*/
+void R_LocalPointToWorld (vec3_t local, vec3_t world) {
+ world[0] = local[0] * tr.orientation.axis[0][0] + local[1] * tr.orientation.axis[1][0] + local[2] * tr.orientation.axis[2][0] + tr.orientation.origin[0];
+ world[1] = local[0] * tr.orientation.axis[0][1] + local[1] * tr.orientation.axis[1][1] + local[2] * tr.orientation.axis[2][1] + tr.orientation.origin[1];
+ world[2] = local[0] * tr.orientation.axis[0][2] + local[1] * tr.orientation.axis[1][2] + local[2] * tr.orientation.axis[2][2] + tr.orientation.origin[2];
+}
+
+/*
+=================
+R_WorldToLocal
+
+=================
+*/
+void R_WorldToLocal (vec3_t world, vec3_t local) {
+ local[0] = DotProduct(world, tr.orientation.axis[0]);
+ local[1] = DotProduct(world, tr.orientation.axis[1]);
+ local[2] = DotProduct(world, tr.orientation.axis[2]);
+}
+
+/*
+==========================
+R_TransformModelToClip
+
+==========================
+*/
+void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
+ vec4_t eye, vec4_t dst ) {
+ int i;
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ eye[i] =
+ src[0] * modelMatrix[ i + 0 * 4 ] +
+ src[1] * modelMatrix[ i + 1 * 4 ] +
+ src[2] * modelMatrix[ i + 2 * 4 ] +
+ 1 * modelMatrix[ i + 3 * 4 ];
+ }
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ dst[i] =
+ eye[0] * projectionMatrix[ i + 0 * 4 ] +
+ eye[1] * projectionMatrix[ i + 1 * 4 ] +
+ eye[2] * projectionMatrix[ i + 2 * 4 ] +
+ eye[3] * projectionMatrix[ i + 3 * 4 ];
+ }
+}
+
+/*
+==========================
+R_TransformClipToWindow
+
+==========================
+*/
+void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) {
+ normalized[0] = clip[0] / clip[3];
+ normalized[1] = clip[1] / clip[3];
+ normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
+
+ window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth;
+ window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight;
+ window[2] = normalized[2];
+
+ window[0] = (int) ( window[0] + 0.5 );
+ window[1] = (int) ( window[1] + 0.5 );
+}
+
+
+/*
+==========================
+myGlMultMatrix
+
+==========================
+*/
+void myGlMultMatrix( const float *a, const float *b, float *out ) {
+ int i, j;
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ for ( j = 0 ; j < 4 ; j++ ) {
+ out[ i * 4 + j ] =
+ a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
+ + a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
+ + a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
+ + a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
+ }
+ }
+}
+
+/*
+=================
+R_RotateForEntity
+
+Generates an orientation for an entity and viewParms
+Does NOT produce any GL calls
+Called by both the front end and the back end
+=================
+*/
+void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
+ orientationr_t *orientation ) {
+ float glMatrix[16];
+ vec3_t delta;
+ float axisLength;
+
+ if ( ent->e.reType != RT_MODEL ) {
+ *orientation = viewParms->world;
+ return;
+ }
+
+ VectorCopy( ent->e.origin, orientation->origin );
+
+ VectorCopy( ent->e.axis[0], orientation->axis[0] );
+ VectorCopy( ent->e.axis[1], orientation->axis[1] );
+ VectorCopy( ent->e.axis[2], orientation->axis[2] );
+
+ glMatrix[0] = orientation->axis[0][0];
+ glMatrix[4] = orientation->axis[1][0];
+ glMatrix[8] = orientation->axis[2][0];
+ glMatrix[12] = orientation->origin[0];
+
+ glMatrix[1] = orientation->axis[0][1];
+ glMatrix[5] = orientation->axis[1][1];
+ glMatrix[9] = orientation->axis[2][1];
+ glMatrix[13] = orientation->origin[1];
+
+ glMatrix[2] = orientation->axis[0][2];
+ glMatrix[6] = orientation->axis[1][2];
+ glMatrix[10] = orientation->axis[2][2];
+ glMatrix[14] = orientation->origin[2];
+
+ glMatrix[3] = 0;
+ glMatrix[7] = 0;
+ glMatrix[11] = 0;
+ glMatrix[15] = 1;
+
+ myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, orientation->modelMatrix );
+
+ // calculate the viewer origin in the model's space
+ // needed for fog, specular, and environment mapping
+ VectorSubtract( viewParms->orientation.origin, orientation->origin, delta );
+
+ // compensate for scale in the axes if necessary
+ if ( ent->e.nonNormalizedAxes ) {
+ axisLength = VectorLength( ent->e.axis[0] );
+ if ( !axisLength ) {
+ axisLength = 0;
+ } else {
+ axisLength = 1.0f / axisLength;
+ }
+ } else {
+ axisLength = 1.0f;
+ }
+
+ orientation->viewOrigin[0] = DotProduct( delta, orientation->axis[0] ) * axisLength;
+ orientation->viewOrigin[1] = DotProduct( delta, orientation->axis[1] ) * axisLength;
+ orientation->viewOrigin[2] = DotProduct( delta, orientation->axis[2] ) * axisLength;
+}
+
+/*
+=================
+R_RotateForViewer
+
+Sets up the modelview matrix for a given viewParm
+=================
+*/
+void R_RotateForViewer (void)
+{
+ float viewerMatrix[16];
+ vec3_t origin;
+
+ Com_Memset (&tr.orientation, 0, sizeof(tr.orientation));
+ tr.orientation.axis[0][0] = 1;
+ tr.orientation.axis[1][1] = 1;
+ tr.orientation.axis[2][2] = 1;
+ VectorCopy (tr.viewParms.orientation.origin, tr.orientation.viewOrigin);
+
+ // transform by the camera placement
+ VectorCopy( tr.viewParms.orientation.origin, origin );
+
+ viewerMatrix[0] = tr.viewParms.orientation.axis[0][0];
+ viewerMatrix[4] = tr.viewParms.orientation.axis[0][1];
+ viewerMatrix[8] = tr.viewParms.orientation.axis[0][2];
+ viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
+
+ viewerMatrix[1] = tr.viewParms.orientation.axis[1][0];
+ viewerMatrix[5] = tr.viewParms.orientation.axis[1][1];
+ viewerMatrix[9] = tr.viewParms.orientation.axis[1][2];
+ viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
+
+ viewerMatrix[2] = tr.viewParms.orientation.axis[2][0];
+ viewerMatrix[6] = tr.viewParms.orientation.axis[2][1];
+ viewerMatrix[10] = tr.viewParms.orientation.axis[2][2];
+ viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
+
+ viewerMatrix[3] = 0;
+ viewerMatrix[7] = 0;
+ viewerMatrix[11] = 0;
+ viewerMatrix[15] = 1;
+
+ // convert from our coordinate system (looking down X)
+ // to OpenGL's coordinate system (looking down -Z)
+ myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.orientation.modelMatrix );
+
+ tr.viewParms.world = tr.orientation;
+
+}
+
+/*
+** SetFarClip
+*/
+static void R_SetFarClip( void )
+{
+ float farthestCornerDistance = 0;
+ int i;
+
+ // if not rendering the world (icons, menus, etc)
+ // set a 2k far clip plane
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ tr.viewParms.zFar = 2048;
+ return;
+ }
+
+ //
+ // set far clipping planes dynamically
+ //
+ farthestCornerDistance = 0;
+ for ( i = 0; i < 8; i++ )
+ {
+ vec3_t v;
+ vec3_t vecTo;
+ float distance;
+
+ if ( i & 1 )
+ {
+ v[0] = tr.viewParms.visBounds[0][0];
+ }
+ else
+ {
+ v[0] = tr.viewParms.visBounds[1][0];
+ }
+
+ if ( i & 2 )
+ {
+ v[1] = tr.viewParms.visBounds[0][1];
+ }
+ else
+ {
+ v[1] = tr.viewParms.visBounds[1][1];
+ }
+
+ if ( i & 4 )
+ {
+ v[2] = tr.viewParms.visBounds[0][2];
+ }
+ else
+ {
+ v[2] = tr.viewParms.visBounds[1][2];
+ }
+
+ VectorSubtract( v, tr.viewParms.orientation.origin, vecTo );
+
+ distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2];
+
+ if ( distance > farthestCornerDistance )
+ {
+ farthestCornerDistance = distance;
+ }
+ }
+ tr.viewParms.zFar = sqrt( farthestCornerDistance );
+}
+
+/*
+=================
+R_SetupFrustum
+
+Set up the culling frustum planes for the current view using the results we got from computing the first two rows of
+the projection matrix.
+=================
+*/
+void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float stereoSep)
+{
+ vec3_t ofsorigin;
+ float oppleg, adjleg, length;
+ int i;
+
+ if(stereoSep == 0 && xmin == -xmax)
+ {
+ // symmetric case can be simplified
+ VectorCopy(dest->orientation.origin, ofsorigin);
+
+ length = sqrt(xmax * xmax + zProj * zProj);
+ oppleg = xmax / length;
+ adjleg = zProj / length;
+
+ VectorScale(dest->orientation.axis[0], oppleg, dest->frustum[0].normal);
+ VectorMA(dest->frustum[0].normal, adjleg, dest->orientation.axis[1], dest->frustum[0].normal);
+
+ VectorScale(dest->orientation.axis[0], oppleg, dest->frustum[1].normal);
+ VectorMA(dest->frustum[1].normal, -adjleg, dest->orientation.axis[1], dest->frustum[1].normal);
+ }
+ else
+ {
+ // In stereo rendering, due to the modification of the projection matrix, dest->orientation.origin is not the
+ // actual origin that we're rendering so offset the tip of the view pyramid.
+ VectorMA(dest->orientation.origin, stereoSep, dest->orientation.axis[1], ofsorigin);
+
+ oppleg = xmax + stereoSep;
+ length = sqrt(oppleg * oppleg + zProj * zProj);
+ VectorScale(dest->orientation.axis[0], oppleg / length, dest->frustum[0].normal);
+ VectorMA(dest->frustum[0].normal, zProj / length, dest->orientation.axis[1], dest->frustum[0].normal);
+
+ oppleg = xmin + stereoSep;
+ length = sqrt(oppleg * oppleg + zProj * zProj);
+ VectorScale(dest->orientation.axis[0], -oppleg / length, dest->frustum[1].normal);
+ VectorMA(dest->frustum[1].normal, -zProj / length, dest->orientation.axis[1], dest->frustum[1].normal);
+ }
+
+ length = sqrt(ymax * ymax + zProj * zProj);
+ oppleg = ymax / length;
+ adjleg = zProj / length;
+
+ VectorScale(dest->orientation.axis[0], oppleg, dest->frustum[2].normal);
+ VectorMA(dest->frustum[2].normal, adjleg, dest->orientation.axis[2], dest->frustum[2].normal);
+
+ VectorScale(dest->orientation.axis[0], oppleg, dest->frustum[3].normal);
+ VectorMA(dest->frustum[3].normal, -adjleg, dest->orientation.axis[2], dest->frustum[3].normal);
+
+ for (i=0 ; i<4 ; i++) {
+ dest->frustum[i].type = PLANE_NON_AXIAL;
+ dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal);
+ SetPlaneSignbits( &dest->frustum[i] );
+ }
+}
+
+/*
+===============
+R_SetupProjection
+===============
+*/
+void R_SetupProjection(viewParms_t *dest, float zProj, bool computeFrustum)
+{
+ float xmin, xmax, ymin, ymax;
+ float width, height, stereoSep = r_stereoSeparation->value;
+
+ /*
+ * offset the view origin of the viewer for stereo rendering
+ * by setting the projection matrix appropriately.
+ */
+
+ if(stereoSep != 0)
+ {
+ if(dest->stereoFrame == STEREO_LEFT)
+ stereoSep = zProj / stereoSep;
+ else if(dest->stereoFrame == STEREO_RIGHT)
+ stereoSep = zProj / -stereoSep;
+ else
+ stereoSep = 0;
+ }
+
+ ymax = zProj * tan(dest->fovY * M_PI / 360.0f);
+ ymin = -ymax;
+
+ xmax = zProj * tan(dest->fovX * M_PI / 360.0f);
+ xmin = -xmax;
+
+ width = xmax - xmin;
+ height = ymax - ymin;
+
+ dest->projectionMatrix[0] = 2 * zProj / width;
+ dest->projectionMatrix[4] = 0;
+ dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width;
+ dest->projectionMatrix[12] = 2 * zProj * stereoSep / width;
+
+ dest->projectionMatrix[1] = 0;
+ dest->projectionMatrix[5] = 2 * zProj / height;
+ dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
+ dest->projectionMatrix[13] = 0;
+
+ dest->projectionMatrix[3] = 0;
+ dest->projectionMatrix[7] = 0;
+ dest->projectionMatrix[11] = -1;
+ dest->projectionMatrix[15] = 0;
+
+ // Now that we have all the data for the projection matrix we can also setup the view frustum.
+ if(computeFrustum)
+ R_SetupFrustum(dest, xmin, xmax, ymax, zProj, stereoSep);
+}
+
+/*
+===============
+R_SetupProjectionZ
+
+Sets the z-component transformation part in the projection matrix
+===============
+*/
+void R_SetupProjectionZ(viewParms_t *dest)
+{
+ float zNear, zFar, depth;
+
+ zNear = r_znear->value;
+ zFar = dest->zFar;
+ depth = zFar - zNear;
+
+ dest->projectionMatrix[2] = 0;
+ dest->projectionMatrix[6] = 0;
+ dest->projectionMatrix[10] = -( zFar + zNear ) / depth;
+ dest->projectionMatrix[14] = -2 * zFar * zNear / depth;
+}
+
+/*
+=================
+R_MirrorPoint
+=================
+*/
+void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
+ int i;
+ vec3_t local;
+ vec3_t transformed;
+ float d;
+
+ VectorSubtract( in, surface->origin, local );
+
+ VectorClear( transformed );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ d = DotProduct(local, surface->axis[i]);
+ VectorMA( transformed, d, camera->axis[i], transformed );
+ }
+
+ VectorAdd( transformed, camera->origin, out );
+}
+
+void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
+ int i;
+ float d;
+
+ VectorClear( out );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ d = DotProduct(in, surface->axis[i]);
+ VectorMA( out, d, camera->axis[i], out );
+ }
+}
+
+
+/*
+=============
+R_PlaneForSurface
+=============
+*/
+void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) {
+ srfTriangles_t *tri;
+ srfPoly_t *poly;
+ drawVert_t *v1, *v2, *v3;
+ vec4_t plane4;
+
+ if (!surfType) {
+ Com_Memset (plane, 0, sizeof(*plane));
+ plane->normal[0] = 1;
+ return;
+ }
+ switch (*surfType) {
+ case SF_FACE:
+ *plane = ((srfSurfaceFace_t *)surfType)->plane;
+ return;
+ case SF_TRIANGLES:
+ tri = (srfTriangles_t *)surfType;
+ v1 = tri->verts + tri->indexes[0];
+ v2 = tri->verts + tri->indexes[1];
+ v3 = tri->verts + tri->indexes[2];
+ PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz );
+ VectorCopy( plane4, plane->normal );
+ plane->dist = plane4[3];
+ return;
+ case SF_POLY:
+ poly = (srfPoly_t *)surfType;
+ PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz );
+ VectorCopy( plane4, plane->normal );
+ plane->dist = plane4[3];
+ return;
+ default:
+ Com_Memset (plane, 0, sizeof(*plane));
+ plane->normal[0] = 1;
+ return;
+ }
+}
+
+/*
+=================
+R_GetPortalOrientation
+
+entityNum is the entity that the portal surface is a part of, which may
+be moving and rotating.
+
+Returns true if it should be mirrored
+=================
+*/
+bool R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum,
+ orientation_t *surface, orientation_t *camera,
+ vec3_t pvsOrigin, bool *mirror ) {
+ int i;
+ cplane_t originalPlane, plane;
+ trRefEntity_t *e;
+ float d;
+ vec3_t transformed;
+
+ // create plane axis for the portal we are seeing
+ R_PlaneForSurface( drawSurf->surface, &originalPlane );
+
+ // rotate the plane if necessary
+ if ( entityNum != REFENTITYNUM_WORLD ) {
+ tr.currentEntityNum = entityNum;
+ tr.currentEntity = &tr.refdef.entities[entityNum];
+
+ // get the orientation of the entity
+ R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.orientation );
+
+ // rotate the plane, but keep the non-rotated version for matching
+ // against the portalSurface entities
+ R_LocalNormalToWorld( originalPlane.normal, plane.normal );
+ plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.orientation.origin );
+
+ // translate the original plane
+ originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.orientation.origin );
+ } else {
+ plane = originalPlane;
+ }
+
+ VectorCopy( plane.normal, surface->axis[0] );
+ PerpendicularVector( surface->axis[1], surface->axis[0] );
+ CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] );
+
+ // locate the portal entity closest to this plane.
+ // origin will be the origin of the portal, origin2 will be
+ // the origin of the camera
+ for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) {
+ e = &tr.refdef.entities[i];
+ if ( e->e.reType != RT_PORTALSURFACE ) {
+ continue;
+ }
+
+ d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
+ if ( d > 64 || d < -64) {
+ continue;
+ }
+
+ // get the pvsOrigin from the entity
+ VectorCopy( e->e.oldorigin, pvsOrigin );
+
+ // if the entity is just a mirror, don't use as a camera point
+ if ( e->e.oldorigin[0] == e->e.origin[0] &&
+ e->e.oldorigin[1] == e->e.origin[1] &&
+ e->e.oldorigin[2] == e->e.origin[2] ) {
+ VectorScale( plane.normal, plane.dist, surface->origin );
+ VectorCopy( surface->origin, camera->origin );
+ VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] );
+ VectorCopy( surface->axis[1], camera->axis[1] );
+ VectorCopy( surface->axis[2], camera->axis[2] );
+
+ *mirror = true;
+ return true;
+ }
+
+ // project the origin onto the surface plane to get
+ // an origin point we can rotate around
+ d = DotProduct( e->e.origin, plane.normal ) - plane.dist;
+ VectorMA( e->e.origin, -d, surface->axis[0], surface->origin );
+
+ // now get the camera origin and orientation
+ VectorCopy( e->e.oldorigin, camera->origin );
+ AxisCopy( e->e.axis, camera->axis );
+ VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] );
+ VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] );
+
+ // optionally rotate
+ if ( e->e.oldframe ) {
+ // if a speed is specified
+ if ( e->e.frame ) {
+ // continuous rotate
+ d = (tr.refdef.time/1000.0f) * e->e.frame;
+ VectorCopy( camera->axis[1], transformed );
+ RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
+ CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
+ } else {
+ // bobbing rotate, with skinNum being the rotation offset
+ d = sin( tr.refdef.time * 0.003f );
+ d = e->e.skinNum + d * 4;
+ VectorCopy( camera->axis[1], transformed );
+ RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
+ CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
+ }
+ }
+ else if ( e->e.skinNum ) {
+ d = e->e.skinNum;
+ VectorCopy( camera->axis[1], transformed );
+ RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
+ CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
+ }
+ *mirror = false;
+ return true;
+ }
+
+ // if we didn't locate a portal entity, don't render anything.
+ // We don't want to just treat it as a mirror, because without a
+ // portal entity the server won't have communicated a proper entity set
+ // in the snapshot
+
+ // unfortunately, with local movement prediction it is easily possible
+ // to see a surface before the server has communicated the matching
+ // portal surface entity, so we don't want to print anything here...
+
+ //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" );
+
+ return false;
+}
+
+static bool IsMirror( const drawSurf_t *drawSurf, int entityNum )
+{
+ int i;
+ cplane_t originalPlane, plane;
+ trRefEntity_t *e;
+ float d;
+
+ // create plane axis for the portal we are seeing
+ R_PlaneForSurface( drawSurf->surface, &originalPlane );
+
+ // rotate the plane if necessary
+ if ( entityNum != REFENTITYNUM_WORLD )
+ {
+ tr.currentEntityNum = entityNum;
+ tr.currentEntity = &tr.refdef.entities[entityNum];
+
+ // get the orientation of the entity
+ R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.orientation );
+
+ // rotate the plane, but keep the non-rotated version for matching
+ // against the portalSurface entities
+ R_LocalNormalToWorld( originalPlane.normal, plane.normal );
+ plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.orientation.origin );
+
+ // translate the original plane
+ originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.orientation.origin );
+ }
+
+ // locate the portal entity closest to this plane.
+ // origin will be the origin of the portal, origin2 will be
+ // the origin of the camera
+ for ( i = 0 ; i < tr.refdef.num_entities ; i++ )
+ {
+ e = &tr.refdef.entities[i];
+ if ( e->e.reType != RT_PORTALSURFACE ) {
+ continue;
+ }
+
+ d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
+ if ( d > 64 || d < -64) {
+ continue;
+ }
+
+ // if the entity is just a mirror, don't use as a camera point
+ if ( e->e.oldorigin[0] == e->e.origin[0] &&
+ e->e.oldorigin[1] == e->e.origin[1] &&
+ e->e.oldorigin[2] == e->e.origin[2] )
+ {
+ return true;
+ }
+
+ return false;
+ }
+ return false;
+}
+
+/*
+** SurfIsOffscreen
+**
+** Determines if a surface is completely offscreen.
+*/
+static bool SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {
+ float shortest = 100000000;
+ int entityNum;
+ int numTriangles;
+ shader_t *shader;
+ int fogNum;
+ int dlighted;
+ vec4_t clip, eye;
+ int i;
+ unsigned int pointOr = 0;
+ unsigned int pointAnd = (unsigned int)~0;
+
+ R_RotateForViewer();
+
+ R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
+ RB_BeginSurface( shader, fogNum );
+ rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
+
+ assert( tess.numVertexes < 128 );
+
+ for ( i = 0; i < tess.numVertexes; i++ )
+ {
+ int j;
+ unsigned int pointFlags = 0;
+
+ R_TransformModelToClip( tess.xyz[i], tr.orientation.modelMatrix, tr.viewParms.projectionMatrix, eye, clip );
+
+ for ( j = 0; j < 3; j++ )
+ {
+ if ( clip[j] >= clip[3] )
+ {
+ pointFlags |= (1 << (j*2));
+ }
+ else if ( clip[j] <= -clip[3] )
+ {
+ pointFlags |= ( 1 << (j*2+1));
+ }
+ }
+ pointAnd &= pointFlags;
+ pointOr |= pointFlags;
+ }
+
+ // trivially reject
+ if ( pointAnd )
+ {
+ return true;
+ }
+
+ // determine if this surface is backfaced and also determine the distance
+ // to the nearest vertex so we can cull based on portal range. Culling
+ // based on vertex distance isn't 100% correct (we should be checking for
+ // range to the surface), but it's good enough for the types of portals
+ // we have in the game right now.
+ numTriangles = tess.numIndexes / 3;
+
+ for ( i = 0; i < tess.numIndexes; i += 3 )
+ {
+ vec3_t normal;
+ float len;
+
+ VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.orientation.origin, normal );
+
+ len = VectorLengthSquared( normal ); // lose the sqrt
+ if ( len < shortest )
+ {
+ shortest = len;
+ }
+
+ if ( DotProduct( normal, tess.normal[tess.indexes[i]] ) >= 0 )
+ {
+ numTriangles--;
+ }
+ }
+ if ( !numTriangles )
+ {
+ return true;
+ }
+
+ // mirrors can early out at this point, since we don't do a fade over distance
+ // with them (although we could)
+ if ( IsMirror( drawSurf, entityNum ) )
+ {
+ return false;
+ }
+
+ if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+========================
+R_MirrorViewBySurface
+
+Returns true if another view has been rendered
+========================
+*/
+bool R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) {
+ vec4_t clipDest[128];
+ viewParms_t newParms;
+ viewParms_t oldParms;
+ orientation_t surface, camera;
+
+ // don't recursively mirror
+ if (tr.viewParms.isPortal) {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" );
+ return false;
+ }
+
+ if ( r_noportals->integer || (r_fastsky->integer == 1) ) {
+ return false;
+ }
+
+ // trivially reject portal/mirror
+ if ( SurfIsOffscreen( drawSurf, clipDest ) ) {
+ return false;
+ }
+
+ // save old viewParms so we can return to it after the mirror view
+ oldParms = tr.viewParms;
+
+ newParms = tr.viewParms;
+ newParms.isPortal = true;
+ if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera,
+ newParms.pvsOrigin, &newParms.isMirror ) ) {
+ return false; // bad portal, no portalentity
+ }
+
+ R_MirrorPoint (oldParms.orientation.origin, &surface, &camera, newParms.orientation.origin );
+
+ VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal );
+ newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal );
+
+ R_MirrorVector (oldParms.orientation.axis[0], &surface, &camera, newParms.orientation.axis[0]);
+ R_MirrorVector (oldParms.orientation.axis[1], &surface, &camera, newParms.orientation.axis[1]);
+ R_MirrorVector (oldParms.orientation.axis[2], &surface, &camera, newParms.orientation.axis[2]);
+
+ // OPTIMIZE: restrict the viewport on the mirrored view
+
+ // render the mirror view
+ R_RenderView (&newParms);
+
+ tr.viewParms = oldParms;
+
+ return true;
+}
+
+/*
+=================
+R_SpriteFogNum
+
+See if a sprite is inside a fog volume
+=================
+*/
+int R_SpriteFogNum( trRefEntity_t *ent ) {
+ int i, j;
+ fog_t *fog;
+
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ return 0;
+ }
+
+ if ( ent->e.renderfx & RF_CROSSHAIR ) {
+ return 0;
+ }
+
+ for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
+ fog = &tr.world->fogs[i];
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) {
+ break;
+ }
+ if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) {
+ break;
+ }
+ }
+ if ( j == 3 ) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+/*
+==========================================================================================
+
+DRAWSURF SORTING
+
+==========================================================================================
+*/
+
+/*
+===============
+R_Radix
+===============
+*/
+static ID_INLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest )
+{
+ int count[ 256 ] = { 0 };
+ int index[ 256 ];
+ int i;
+ unsigned char *sortKey = NULL;
+ unsigned char *end = NULL;
+
+ sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
+ end = sortKey + ( size * sizeof( drawSurf_t ) );
+ for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) )
+ ++count[ *sortKey ];
+
+ index[ 0 ] = 0;
+
+ for( i = 1; i < 256; ++i )
+ index[ i ] = index[ i - 1 ] + count[ i - 1 ];
+
+ sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
+ for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) )
+ dest[ index[ *sortKey ]++ ] = source[ i ];
+}
+
+/*
+===============
+R_RadixSort
+
+Radix sort with 4 byte size buckets
+===============
+*/
+static void R_RadixSort( drawSurf_t *source, int size )
+{
+ static drawSurf_t scratch[ MAX_DRAWSURFS ];
+#ifdef Q3_LITTLE_ENDIAN
+ R_Radix( 0, size, source, scratch );
+ R_Radix( 1, size, scratch, source );
+ R_Radix( 2, size, source, scratch );
+ R_Radix( 3, size, scratch, source );
+#else
+ R_Radix( 3, size, source, scratch );
+ R_Radix( 2, size, scratch, source );
+ R_Radix( 1, size, source, scratch );
+ R_Radix( 0, size, scratch, source );
+#endif //Q3_LITTLE_ENDIAN
+}
+
+//==========================================================================================
+
+/*
+=================
+R_AddDrawSurf
+=================
+*/
+void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
+ int fogIndex, int dlightMap ) {
+ int index;
+
+ // instead of checking for overflow, we just mask the index
+ // so it wraps around
+ index = tr.refdef.numDrawSurfs & DRAWSURF_MASK;
+ // the sort data is packed into a single 32 bit value so it can be
+ // compared quickly during the qsorting process
+ tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT)
+ | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
+ tr.refdef.drawSurfs[index].surface = surface;
+ tr.refdef.numDrawSurfs++;
+}
+
+/*
+=================
+R_DecomposeSort
+=================
+*/
+void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
+ int *fogNum, int *dlightMap ) {
+ *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31;
+ *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ];
+ *entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK;
+ *dlightMap = sort & 3;
+}
+
+/*
+=================
+R_SortDrawSurfs
+=================
+*/
+void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
+ shader_t *shader;
+ int fogNum;
+ int entityNum;
+ int dlighted;
+ int i;
+
+ // it is possible for some views to not have any surfaces
+ if ( numDrawSurfs < 1 ) {
+ // we still need to add it for hyperspace cases
+ R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
+ return;
+ }
+
+ // sort the drawsurfs by sort type, then orientation, then shader
+ R_RadixSort( drawSurfs, numDrawSurfs );
+
+ // check for any pass through drawing, which
+ // may cause another view to be rendered first
+ for ( i = 0 ; i < numDrawSurfs ; i++ ) {
+ R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted );
+
+ if ( shader->sort > SS_PORTAL ) {
+ break;
+ }
+
+ // no shader should ever have this sort type
+ if ( shader->sort == SS_BAD ) {
+ ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name );
+ }
+
+ // if the mirror was completely clipped away, we may need to check another surface
+ if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) {
+ // this is a debug option to see exactly what is being mirrored
+ if ( r_portalOnly->integer ) {
+ return;
+ }
+ break; // only one mirror view at a time
+ }
+ }
+
+ R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
+}
+
+/*
+=============
+R_AddEntitySurfaces
+=============
+*/
+void R_AddEntitySurfaces (void) {
+ trRefEntity_t *ent;
+ shader_t *shader;
+
+ if ( !r_drawentities->integer ) {
+ return;
+ }
+
+ for ( tr.currentEntityNum = 0;
+ tr.currentEntityNum < tr.refdef.num_entities;
+ tr.currentEntityNum++ ) {
+ ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum];
+
+ ent->needDlights = false;
+
+ // preshift the value we are going to OR into the drawsurf sort
+ tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
+
+ //
+ // the weapon model must be handled special --
+ // we don't want the hacked weapon position showing in
+ // mirrors, because the true body position will already be drawn
+ //
+ if ( (ent->e.renderfx & RF_FIRST_PERSON) && tr.viewParms.isPortal) {
+ continue;
+ }
+
+ // simple generated models, like sprites and beams, are not culled
+ switch ( ent->e.reType ) {
+ case RT_PORTALSURFACE:
+ break; // don't draw anything
+ case RT_SPRITE:
+ case RT_BEAM:
+ case RT_LIGHTNING:
+ case RT_RAIL_CORE:
+ case RT_RAIL_RINGS:
+ // self blood sprites, talk balloons, etc should not be drawn in the primary
+ // view. We can't just do this check for all entities, because md3
+ // entities may still want to cast shadows from them
+ if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {
+ continue;
+ }
+ shader = R_GetShaderByHandle( ent->e.customShader );
+ R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0 );
+ break;
+
+ case RT_MODEL:
+ // we must set up parts of tr.orientation for model culling
+ R_RotateForEntity( ent, &tr.viewParms, &tr.orientation );
+
+ tr.currentModel = R_GetModelByHandle( ent->e.hModel );
+ if (!tr.currentModel) {
+ R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 );
+ } else {
+ switch ( tr.currentModel->type ) {
+ case MOD_MESH:
+ R_AddMD3Surfaces( ent );
+ break;
+ case MOD_MDR:
+ R_MDRAddAnimSurfaces( ent );
+ break;
+ case MOD_IQM:
+ R_AddIQMSurfaces( ent );
+ break;
+ case MOD_BRUSH:
+ R_AddBrushModelSurfaces( ent );
+ break;
+ case MOD_BAD: // null model axis
+ if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {
+ break;
+ }
+ R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 );
+ break;
+ default:
+ ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" );
+ break;
+ }
+ }
+ break;
+ default:
+ ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" );
+ }
+ }
+
+}
+
+
+/*
+====================
+R_GenerateDrawSurfs
+====================
+*/
+void R_GenerateDrawSurfs( void ) {
+ R_AddWorldSurfaces ();
+
+ R_AddPolygonSurfaces();
+
+ // set the projection matrix with the minimum zfar
+ // now that we have the world bounded
+ // this needs to be done before entities are
+ // added, because they use the projection
+ // matrix for lod calculation
+
+ // dynamically compute far clip plane distance
+ R_SetFarClip();
+
+ // we know the size of the clipping volume. Now set the rest of the projection matrix.
+ R_SetupProjectionZ (&tr.viewParms);
+
+ R_AddEntitySurfaces ();
+}
+
+/*
+================
+R_DebugPolygon
+================
+*/
+void R_DebugPolygon( int color, int numPoints, float *points ) {
+ int i;
+
+ GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+
+ // draw solid shade
+
+ qglColor3f( color&1, (color>>1)&1, (color>>2)&1 );
+ qglBegin( GL_POLYGON );
+ for ( i = 0 ; i < numPoints ; i++ ) {
+ qglVertex3fv( points + i * 3 );
+ }
+ qglEnd();
+
+ // draw wireframe outline
+ GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+ qglDepthRange( 0, 0 );
+ qglColor3f( 1, 1, 1 );
+ qglBegin( GL_POLYGON );
+ for ( i = 0 ; i < numPoints ; i++ ) {
+ qglVertex3fv( points + i * 3 );
+ }
+ qglEnd();
+ qglDepthRange( 0, 1 );
+}
+
+/*
+====================
+R_DebugGraphics
+
+Visualization aid for movement clipping debugging
+====================
+*/
+void R_DebugGraphics( void ) {
+ if ( !r_debugSurface->integer ) {
+ return;
+ }
+
+ R_IssuePendingRenderCommands();
+
+ GL_Bind( tr.whiteImage);
+ GL_Cull( CT_FRONT_SIDED );
+ ri.CM_DrawDebugSurface( R_DebugPolygon );
+}
+
+
+/*
+================
+R_RenderView
+
+A view may be either the actual camera view,
+or a mirror / remote location
+================
+*/
+void R_RenderView (viewParms_t *parms) {
+ int firstDrawSurf;
+ int numDrawSurfs;
+
+ if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
+ return;
+ }
+
+ tr.viewCount++;
+
+ tr.viewParms = *parms;
+ tr.viewParms.frameSceneNum = tr.frameSceneNum;
+ tr.viewParms.frameCount = tr.frameCount;
+
+ firstDrawSurf = tr.refdef.numDrawSurfs;
+
+ tr.viewCount++;
+
+ // set viewParms.world
+ R_RotateForViewer ();
+
+ R_SetupProjection(&tr.viewParms, r_zproj->value, true);
+
+ R_GenerateDrawSurfs();
+
+ // if we overflowed MAX_DRAWSURFS, the drawsurfs
+ // wrapped around in the buffer and we will be missing
+ // the first surfaces, not the last ones
+ numDrawSurfs = tr.refdef.numDrawSurfs;
+ if ( numDrawSurfs > MAX_DRAWSURFS ) {
+ numDrawSurfs = MAX_DRAWSURFS;
+ }
+
+ R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, numDrawSurfs - firstDrawSurf );
+
+ // draw main system development information (surface outlines, etc)
+ R_DebugGraphics();
+}
diff --git a/src/renderergl1/tr_marks.cpp b/src/renderergl1/tr_marks.cpp
new file mode 100644
index 0000000..e2c3583
--- /dev/null
+++ b/src/renderergl1/tr_marks.cpp
@@ -0,0 +1,459 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_marks.c -- polygon projection on the world polygons
+
+#include "tr_local.h"
+//#include "assert.h"
+
+#define MAX_VERTS_ON_POLY 64
+
+#define MARKER_OFFSET 0 // 1
+
+/*
+=============
+R_ChopPolyBehindPlane
+
+Out must have space for two more vertexes than in
+=============
+*/
+#define SIDE_FRONT 0
+#define SIDE_BACK 1
+#define SIDE_ON 2
+static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY],
+ int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY],
+ vec3_t normal, vec_t dist, vec_t epsilon) {
+ float dists[MAX_VERTS_ON_POLY+4] = { 0 };
+ int sides[MAX_VERTS_ON_POLY+4] = { 0 };
+ int counts[3];
+ float dot;
+ int i, j;
+ float *p1, *p2, *clip;
+ float d;
+
+ // don't clip if it might overflow
+ if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) {
+ *numOutPoints = 0;
+ return;
+ }
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+ // determine sides for each point
+ for ( i = 0 ; i < numInPoints ; i++ ) {
+ dot = DotProduct( inPoints[i], normal );
+ dot -= dist;
+ dists[i] = dot;
+ if ( dot > epsilon ) {
+ sides[i] = SIDE_FRONT;
+ } else if ( dot < -epsilon ) {
+ sides[i] = SIDE_BACK;
+ } else {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ *numOutPoints = 0;
+
+ if ( !counts[0] ) {
+ return;
+ }
+ if ( !counts[1] ) {
+ *numOutPoints = numInPoints;
+ Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) );
+ return;
+ }
+
+ for ( i = 0 ; i < numInPoints ; i++ ) {
+ p1 = inPoints[i];
+ clip = outPoints[ *numOutPoints ];
+
+ if ( sides[i] == SIDE_ON ) {
+ VectorCopy( p1, clip );
+ (*numOutPoints)++;
+ continue;
+ }
+
+ if ( sides[i] == SIDE_FRONT ) {
+ VectorCopy( p1, clip );
+ (*numOutPoints)++;
+ clip = outPoints[ *numOutPoints ];
+ }
+
+ if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
+ continue;
+ }
+
+ // generate a split point
+ p2 = inPoints[ (i+1) % numInPoints ];
+
+ d = dists[i] - dists[i+1];
+ if ( d == 0 ) {
+ dot = 0;
+ } else {
+ dot = dists[i] / d;
+ }
+
+ // clip xyz
+
+ for (j=0 ; j<3 ; j++) {
+ clip[j] = p1[j] + dot * ( p2[j] - p1[j] );
+ }
+
+ (*numOutPoints)++;
+ }
+}
+
+/*
+=================
+R_BoxSurfaces_r
+
+=================
+*/
+void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) {
+
+ int s, c;
+ msurface_t *surf, **mark;
+
+ // do the tail recursion in a loop
+ while ( node->contents == -1 ) {
+ s = BoxOnPlaneSide( mins, maxs, node->plane );
+ if (s == 1) {
+ node = node->children[0];
+ } else if (s == 2) {
+ node = node->children[1];
+ } else {
+ R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir);
+ node = node->children[1];
+ }
+ }
+
+ // add the individual surfaces
+ mark = node->firstmarksurface;
+ c = node->nummarksurfaces;
+ while (c--) {
+ //
+ if (*listlength >= listsize) break;
+ //
+ surf = *mark;
+ // check if the surface has NOIMPACT or NOMARKS set
+ if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
+ || ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
+ surf->viewCount = tr.viewCount;
+ }
+ // extra check for surfaces to avoid list overflows
+ else if (*(surf->data) == SF_FACE) {
+ // the face plane should go through the box
+ s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane );
+ if (s == 1 || s == 2) {
+ surf->viewCount = tr.viewCount;
+ } else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) {
+ // don't add faces that make sharp angles with the projection direction
+ surf->viewCount = tr.viewCount;
+ }
+ }
+ else if (*(surfaceType_t *) (surf->data) != SF_GRID &&
+ *(surfaceType_t *) (surf->data) != SF_TRIANGLES)
+ surf->viewCount = tr.viewCount;
+ // check the viewCount because the surface may have
+ // already been added if it spans multiple leafs
+ if (surf->viewCount != tr.viewCount) {
+ surf->viewCount = tr.viewCount;
+ list[*listlength] = (surfaceType_t *) surf->data;
+ (*listlength)++;
+ }
+ mark++;
+ }
+}
+
+/*
+=================
+R_AddMarkFragments
+
+=================
+*/
+void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],
+ int numPlanes, vec3_t *normals, float *dists,
+ int maxPoints, vec3_t pointBuffer,
+ int maxFragments, markFragment_t *fragmentBuffer,
+ int *returnedPoints, int *returnedFragments,
+ vec3_t mins, vec3_t maxs) {
+ int pingPong, i;
+ markFragment_t *mf;
+
+ // chop the surface by all the bounding planes of the to be projected polygon
+ pingPong = 0;
+
+ for ( i = 0 ; i < numPlanes ; i++ ) {
+
+ R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],
+ &numClipPoints, clipPoints[!pingPong],
+ normals[i], dists[i], 0.5 );
+ pingPong ^= 1;
+ if ( numClipPoints == 0 ) {
+ break;
+ }
+ }
+ // completely clipped away?
+ if ( numClipPoints == 0 ) {
+ return;
+ }
+
+ // add this fragment to the returned list
+ if ( numClipPoints + (*returnedPoints) > maxPoints ) {
+ return; // not enough space for this polygon
+ }
+ /*
+ // all the clip points should be within the bounding box
+ for ( i = 0 ; i < numClipPoints ; i++ ) {
+ int j;
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;
+ if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;
+ }
+ if (j < 3) break;
+ }
+ if (i < numClipPoints) return;
+ */
+
+ mf = fragmentBuffer + (*returnedFragments);
+ mf->firstPoint = (*returnedPoints);
+ mf->numPoints = numClipPoints;
+ Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );
+
+ (*returnedPoints) += numClipPoints;
+ (*returnedFragments)++;
+}
+
+/*
+=================
+R_MarkFragments
+
+=================
+*/
+int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
+ int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
+ int numsurfaces, numPlanes;
+ int i, j, k, m, n;
+ surfaceType_t *surfaces[64];
+ vec3_t mins, maxs;
+ int returnedFragments;
+ int returnedPoints;
+ vec3_t normals[MAX_VERTS_ON_POLY+2];
+ float dists[MAX_VERTS_ON_POLY+2];
+ vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
+ int numClipPoints;
+ float *v;
+ srfGridMesh_t *cv;
+ drawVert_t *dv;
+ vec3_t normal;
+ vec3_t projectionDir;
+ vec3_t v1, v2;
+ int *indexes;
+
+ if (numPoints <= 0) {
+ return 0;
+ }
+
+ //increment view count for double check prevention
+ tr.viewCount++;
+
+ //
+ VectorNormalize2( projection, projectionDir );
+ // find all the brushes that are to be considered
+ ClearBounds( mins, maxs );
+ for ( i = 0 ; i < numPoints ; i++ ) {
+ vec3_t temp;
+
+ AddPointToBounds( points[i], mins, maxs );
+ VectorAdd( points[i], projection, temp );
+ AddPointToBounds( temp, mins, maxs );
+ // make sure we get all the leafs (also the one(s) in front of the hit surface)
+ VectorMA( points[i], -20, projectionDir, temp );
+ AddPointToBounds( temp, mins, maxs );
+ }
+
+ if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;
+ // create the bounding planes for the to be projected polygon
+ for ( i = 0 ; i < numPoints ; i++ ) {
+ VectorSubtract(points[(i+1)%numPoints], points[i], v1);
+ VectorAdd(points[i], projection, v2);
+ VectorSubtract(points[i], v2, v2);
+ CrossProduct(v1, v2, normals[i]);
+ VectorNormalizeFast(normals[i]);
+ dists[i] = DotProduct(normals[i], points[i]);
+ }
+ // add near and far clipping planes for projection
+ VectorCopy(projectionDir, normals[numPoints]);
+ dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
+ VectorCopy(projectionDir, normals[numPoints+1]);
+ VectorInverse(normals[numPoints+1]);
+ dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;
+ numPlanes = numPoints + 2;
+
+ numsurfaces = 0;
+ R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
+ //assert(numsurfaces <= 64);
+ //assert(numsurfaces != 64);
+
+ returnedPoints = 0;
+ returnedFragments = 0;
+
+ for ( i = 0 ; i < numsurfaces ; i++ ) {
+
+ if (*surfaces[i] == SF_GRID) {
+
+ cv = (srfGridMesh_t *) surfaces[i];
+ for ( m = 0 ; m < cv->height - 1 ; m++ ) {
+ for ( n = 0 ; n < cv->width - 1 ; n++ ) {
+ // We triangulate the grid and chop all triangles within
+ // the bounding planes of the to be projected polygon.
+ // LOD is not taken into account, not such a big deal though.
+ //
+ // It's probably much nicer to chop the grid itself and deal
+ // with this grid as a normal SF_GRID surface so LOD will
+ // be applied. However the LOD of that chopped grid must
+ // be synced with the LOD of the original curve.
+ // One way to do this; the chopped grid shares vertices with
+ // the original curve. When LOD is applied to the original
+ // curve the unused vertices are flagged. Now the chopped curve
+ // should skip the flagged vertices. This still leaves the
+ // problems with the vertices at the chopped grid edges.
+ //
+ // To avoid issues when LOD applied to "hollow curves" (like
+ // the ones around many jump pads) we now just add a 2 unit
+ // offset to the triangle vertices.
+ // The offset is added in the vertex normal vector direction
+ // so all triangles will still fit together.
+ // The 2 unit offset should avoid pretty much all LOD problems.
+
+ numClipPoints = 3;
+
+ dv = cv->verts + m * cv->width + n;
+
+ VectorCopy(dv[0].xyz, clipPoints[0][0]);
+ VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
+ VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
+ VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
+ VectorCopy(dv[1].xyz, clipPoints[0][2]);
+ VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
+ // check the normal of this triangle
+ VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
+ VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
+ CrossProduct(v1, v2, normal);
+ VectorNormalizeFast(normal);
+ if (DotProduct(normal, projectionDir) < -0.1) {
+ // add the fragments of this triangle
+ R_AddMarkFragments(numClipPoints, clipPoints,
+ numPlanes, normals, dists,
+ maxPoints, pointBuffer,
+ maxFragments, fragmentBuffer,
+ &returnedPoints, &returnedFragments, mins, maxs);
+
+ if ( returnedFragments == maxFragments ) {
+ return returnedFragments; // not enough space for more fragments
+ }
+ }
+
+ VectorCopy(dv[1].xyz, clipPoints[0][0]);
+ VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
+ VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
+ VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
+ VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
+ VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]);
+ // check the normal of this triangle
+ VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
+ VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
+ CrossProduct(v1, v2, normal);
+ VectorNormalizeFast(normal);
+ if (DotProduct(normal, projectionDir) < -0.05) {
+ // add the fragments of this triangle
+ R_AddMarkFragments(numClipPoints, clipPoints,
+ numPlanes, normals, dists,
+ maxPoints, pointBuffer,
+ maxFragments, fragmentBuffer,
+ &returnedPoints, &returnedFragments, mins, maxs);
+
+ if ( returnedFragments == maxFragments ) {
+ return returnedFragments; // not enough space for more fragments
+ }
+ }
+ }
+ }
+ }
+ else if (*surfaces[i] == SF_FACE) {
+
+ srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i];
+
+ // check the normal of this face
+ if (DotProduct(surf->plane.normal, projectionDir) > -0.5) {
+ continue;
+ }
+
+ indexes = (int *)( (byte *)surf + surf->ofsIndices );
+ for ( k = 0 ; k < surf->numIndices ; k += 3 ) {
+ for ( j = 0 ; j < 3 ; j++ ) {
+ v = surf->points[0] + VERTEXSIZE * indexes[k+j];;
+ VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
+ }
+
+ // add the fragments of this face
+ R_AddMarkFragments( 3 , clipPoints,
+ numPlanes, normals, dists,
+ maxPoints, pointBuffer,
+ maxFragments, fragmentBuffer,
+ &returnedPoints, &returnedFragments, mins, maxs);
+ if ( returnedFragments == maxFragments ) {
+ return returnedFragments; // not enough space for more fragments
+ }
+ }
+ }
+ else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
+
+ srfTriangles_t *surf = (srfTriangles_t *) surfaces[i];
+
+ for (k = 0; k < surf->numIndexes; k += 3)
+ {
+ for(j = 0; j < 3; j++)
+ {
+ v = surf->verts[surf->indexes[k + j]].xyz;
+ VectorMA(v, MARKER_OFFSET, surf->verts[surf->indexes[k + j]].normal, clipPoints[0][j]);
+ }
+
+ // add the fragments of this face
+ R_AddMarkFragments(3, clipPoints,
+ numPlanes, normals, dists,
+ maxPoints, pointBuffer,
+ maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
+ if(returnedFragments == maxFragments)
+ {
+ return returnedFragments; // not enough space for more fragments
+ }
+ }
+ }
+ }
+ return returnedFragments;
+}
diff --git a/src/renderergl1/tr_mesh.cpp b/src/renderergl1/tr_mesh.cpp
new file mode 100644
index 0000000..d8ca7e0
--- /dev/null
+++ b/src/renderergl1/tr_mesh.cpp
@@ -0,0 +1,413 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_mesh.c: triangle model functions
+
+#include "tr_local.h"
+
+static float ProjectRadius( float r, vec3_t location )
+{
+ float pr;
+ float dist;
+ float c;
+ vec3_t p;
+ float projected[4];
+
+ c = DotProduct( tr.viewParms.orientation.axis[0], tr.viewParms.orientation.origin );
+ dist = DotProduct( tr.viewParms.orientation.axis[0], location ) - c;
+
+ if ( dist <= 0 )
+ return 0;
+
+ p[0] = 0;
+ p[1] = fabs( r );
+ p[2] = -dist;
+
+ projected[0] = p[0] * tr.viewParms.projectionMatrix[0] +
+ p[1] * tr.viewParms.projectionMatrix[4] +
+ p[2] * tr.viewParms.projectionMatrix[8] +
+ tr.viewParms.projectionMatrix[12];
+
+ projected[1] = p[0] * tr.viewParms.projectionMatrix[1] +
+ p[1] * tr.viewParms.projectionMatrix[5] +
+ p[2] * tr.viewParms.projectionMatrix[9] +
+ tr.viewParms.projectionMatrix[13];
+
+ projected[2] = p[0] * tr.viewParms.projectionMatrix[2] +
+ p[1] * tr.viewParms.projectionMatrix[6] +
+ p[2] * tr.viewParms.projectionMatrix[10] +
+ tr.viewParms.projectionMatrix[14];
+
+ projected[3] = p[0] * tr.viewParms.projectionMatrix[3] +
+ p[1] * tr.viewParms.projectionMatrix[7] +
+ p[2] * tr.viewParms.projectionMatrix[11] +
+ tr.viewParms.projectionMatrix[15];
+
+
+ pr = projected[1] / projected[3];
+
+ if ( pr > 1.0f )
+ pr = 1.0f;
+
+ return pr;
+}
+
+/*
+=============
+R_CullModel
+=============
+*/
+static int R_CullModel( md3Header_t *header, trRefEntity_t *ent ) {
+ vec3_t bounds[2];
+ md3Frame_t *oldFrame, *newFrame;
+ int i;
+
+ // compute frame pointers
+ newFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
+ oldFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe;
+
+ // cull bounding sphere ONLY if this is not an upscaled entity
+ if ( !ent->e.nonNormalizedAxes )
+ {
+ if ( ent->e.frame == ent->e.oldframe )
+ {
+ switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
+ {
+ case CULL_OUT:
+ tr.pc.c_sphere_cull_md3_out++;
+ return CULL_OUT;
+
+ case CULL_IN:
+ tr.pc.c_sphere_cull_md3_in++;
+ return CULL_IN;
+
+ case CULL_CLIP:
+ tr.pc.c_sphere_cull_md3_clip++;
+ break;
+ }
+ }
+ else
+ {
+ int sphereCull, sphereCullB;
+
+ sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
+ if ( newFrame == oldFrame ) {
+ sphereCullB = sphereCull;
+ } else {
+ sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
+ }
+
+ if ( sphereCull == sphereCullB )
+ {
+ if ( sphereCull == CULL_OUT )
+ {
+ tr.pc.c_sphere_cull_md3_out++;
+ return CULL_OUT;
+ }
+ else if ( sphereCull == CULL_IN )
+ {
+ tr.pc.c_sphere_cull_md3_in++;
+ return CULL_IN;
+ }
+ else
+ {
+ tr.pc.c_sphere_cull_md3_clip++;
+ }
+ }
+ }
+ }
+
+ // calculate a bounding box in the current coordinate system
+ for (i = 0 ; i < 3 ; i++) {
+ bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
+ bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
+ }
+
+ switch ( R_CullLocalBox( bounds ) )
+ {
+ case CULL_IN:
+ tr.pc.c_box_cull_md3_in++;
+ return CULL_IN;
+ case CULL_CLIP:
+ tr.pc.c_box_cull_md3_clip++;
+ return CULL_CLIP;
+ case CULL_OUT:
+ default:
+ tr.pc.c_box_cull_md3_out++;
+ return CULL_OUT;
+ }
+}
+
+
+/*
+=================
+R_ComputeLOD
+
+=================
+*/
+int R_ComputeLOD( trRefEntity_t *ent ) {
+ float radius;
+ float flod, lodscale;
+ float projectedRadius;
+ md3Frame_t *frame;
+ mdrHeader_t *mdr;
+ mdrFrame_t *mdrframe;
+ int lod;
+
+ if ( tr.currentModel->numLods < 2 )
+ {
+ // model has only 1 LOD level, skip computations and bias
+ lod = 0;
+ }
+ else
+ {
+ // multiple LODs exist, so compute projected bounding sphere
+ // and use that as a criteria for selecting LOD
+
+ if(tr.currentModel->type == MOD_MDR)
+ {
+ int frameSize;
+ mdr = (mdrHeader_t *) tr.currentModel->modelData;
+ frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]);
+
+ mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame);
+
+ radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]);
+ }
+ else
+ {
+ frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
+
+ frame += ent->e.frame;
+
+ radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] );
+ }
+
+ if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 )
+ {
+ lodscale = r_lodscale->value;
+ if (lodscale > 20) lodscale = 20;
+ flod = 1.0f - projectedRadius * lodscale;
+ }
+ else
+ {
+ // object intersects near view plane, e.g. view weapon
+ flod = 0;
+ }
+
+ flod *= tr.currentModel->numLods;
+ lod = static_cast<int>(flod);
+
+ if ( lod < 0 )
+ {
+ lod = 0;
+ }
+ else if ( lod >= tr.currentModel->numLods )
+ {
+ lod = tr.currentModel->numLods - 1;
+ }
+ }
+
+ lod += r_lodbias->integer;
+
+ if ( lod >= tr.currentModel->numLods )
+ lod = tr.currentModel->numLods - 1;
+ if ( lod < 0 )
+ lod = 0;
+
+ return lod;
+}
+
+/*
+=================
+R_ComputeFogNum
+
+=================
+*/
+int R_ComputeFogNum( md3Header_t *header, trRefEntity_t *ent ) {
+ int i, j;
+ fog_t *fog;
+ md3Frame_t *md3Frame;
+ vec3_t localOrigin;
+
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ return 0;
+ }
+
+ // FIXME: non-normalized axis issues
+ md3Frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
+ VectorAdd( ent->e.origin, md3Frame->localOrigin, localOrigin );
+ for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
+ fog = &tr.world->fogs[i];
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( localOrigin[j] - md3Frame->radius >= fog->bounds[1][j] ) {
+ break;
+ }
+ if ( localOrigin[j] + md3Frame->radius <= fog->bounds[0][j] ) {
+ break;
+ }
+ }
+ if ( j == 3 ) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+/*
+=================
+R_AddMD3Surfaces
+
+=================
+*/
+void R_AddMD3Surfaces( trRefEntity_t *ent ) {
+ int i;
+ md3Header_t *header = NULL;
+ md3Surface_t *surface = NULL;
+ md3Shader_t *md3Shader = NULL;
+ shader_t *shader = NULL;
+ int cull;
+ int lod;
+ int fogNum;
+ bool personalModel;
+
+ // don't add third_person objects if not in a portal
+ personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
+
+ if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
+ ent->e.frame %= tr.currentModel->md3[0]->numFrames;
+ ent->e.oldframe %= tr.currentModel->md3[0]->numFrames;
+ }
+
+ //
+ // Validate the frames so there is no chance of a crash.
+ // This will write directly into the entity structure, so
+ // when the surfaces are rendered, they don't need to be
+ // range checked again.
+ //
+ if ( (ent->e.frame >= tr.currentModel->md3[0]->numFrames)
+ || (ent->e.frame < 0)
+ || (ent->e.oldframe >= tr.currentModel->md3[0]->numFrames)
+ || (ent->e.oldframe < 0) ) {
+ ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n",
+ ent->e.oldframe, ent->e.frame,
+ tr.currentModel->name );
+ ent->e.frame = 0;
+ ent->e.oldframe = 0;
+ }
+
+ //
+ // compute LOD
+ //
+ lod = R_ComputeLOD( ent );
+
+ header = tr.currentModel->md3[lod];
+
+ //
+ // cull the entire model if merged bounding box of both frames
+ // is outside the view frustum.
+ //
+ cull = R_CullModel ( header, ent );
+ if ( cull == CULL_OUT ) {
+ return;
+ }
+
+ //
+ // set up lighting now that we know we aren't culled
+ //
+ if ( !personalModel || r_shadows->integer > 1 ) {
+ R_SetupEntityLighting( &tr.refdef, ent );
+ }
+
+ //
+ // see if we are in a fog volume
+ //
+ fogNum = R_ComputeFogNum( header, ent );
+
+ //
+ // draw all surfaces
+ //
+ surface = (md3Surface_t *)( (byte *)header + header->ofsSurfaces );
+ for ( i = 0 ; i < header->numSurfaces ; i++ ) {
+
+ if ( ent->e.customShader ) {
+ shader = R_GetShaderByHandle( ent->e.customShader );
+ } else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) {
+ skin_t *skin;
+ int j;
+
+ skin = R_GetSkinByHandle( ent->e.customSkin );
+
+ // match the surface name to something in the skin file
+ shader = tr.defaultShader;
+ for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
+ // the names have both been lowercased
+ if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+ shader = skin->surfaces[j].shader;
+ break;
+ }
+ }
+ if (shader == tr.defaultShader) {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name);
+ }
+ else if (shader->defaultShader) {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
+ }
+ } else if ( surface->numShaders <= 0 ) {
+ shader = tr.defaultShader;
+ } else {
+ md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders );
+ md3Shader += ent->e.skinNum % surface->numShaders;
+ shader = tr.shaders[ md3Shader->shaderIndex ];
+ }
+
+
+ // we will add shadows even if the main object isn't visible in the view
+
+ // stencil shadows can't do personal models unless I polyhedron clip
+ if ( !personalModel
+ && r_shadows->integer == 2
+ && fogNum == 0
+ && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
+ && shader->sort == SS_OPAQUE ) {
+ R_AddDrawSurf( (surfaceType_t*)surface, tr.shadowShader, 0, false );
+ }
+
+ // projection shadows work fine with personal models
+ if ( r_shadows->integer == 3
+ && fogNum == 0
+ && (ent->e.renderfx & RF_SHADOW_PLANE )
+ && shader->sort == SS_OPAQUE ) {
+ R_AddDrawSurf( (surfaceType_t*)surface, tr.projectionShadowShader, 0, false );
+ }
+
+ // don't add third_person objects if not viewing through a portal
+ if ( !personalModel ) {
+ R_AddDrawSurf( (surfaceType_t*)surface, shader, fogNum, false );
+ }
+
+ surface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd );
+ }
+
+}
diff --git a/src/renderergl1/tr_model.cpp b/src/renderergl1/tr_model.cpp
new file mode 100644
index 0000000..5afd51d
--- /dev/null
+++ b/src/renderergl1/tr_model.cpp
@@ -0,0 +1,1120 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_models.c -- model loading and caching
+
+#include "tr_local.h"
+
+#define LL(x) x=LittleLong(x)
+
+static bool R_LoadMD3(model_t *mod, int lod, void *buffer, const char *name );
+static bool R_LoadMDR(model_t *mod, void *buffer, int filesize, const char *name );
+
+/*
+====================
+R_RegisterMD3
+====================
+*/
+qhandle_t R_RegisterMD3(const char *name, model_t *mod)
+{
+ union {
+ unsigned *u;
+ void *v;
+ } buf;
+ int lod;
+ int ident;
+ bool loaded = false;
+ int numLoaded;
+ char filename[MAX_QPATH], namebuf[MAX_QPATH+20];
+ char *fext, defex[] = "md3";
+
+ numLoaded = 0;
+
+ strcpy(filename, name);
+
+ fext = strchr(filename, '.');
+ if(!fext)
+ fext = defex;
+ else
+ {
+ *fext = '\0';
+ fext++;
+ }
+
+ for (lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod--)
+ {
+ if(lod)
+ Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext);
+ else
+ Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext);
+
+ ri.FS_ReadFile( namebuf, &buf.v );
+ if(!buf.u)
+ continue;
+
+ ident = LittleLong(* (unsigned *) buf.u);
+ if (ident == MD3_IDENT)
+ loaded = R_LoadMD3(mod, lod, buf.u, name);
+ else
+ ri.Printf(PRINT_WARNING,"R_RegisterMD3: unknown fileid for %s\n", name);
+
+ ri.FS_FreeFile(buf.v);
+
+ if(loaded)
+ {
+ mod->numLods++;
+ numLoaded++;
+ }
+ else
+ break;
+ }
+
+ if(numLoaded)
+ {
+ // duplicate into higher lod spots that weren't
+ // loaded, in case the user changes r_lodbias on the fly
+ for(lod--; lod >= 0; lod--)
+ {
+ mod->numLods++;
+ mod->md3[lod] = mod->md3[lod + 1];
+ }
+
+ return mod->index;
+ }
+
+ ri.Printf(PRINT_DEVELOPER, "R_RegisterMD3: couldn't load %s\n", name);
+
+ mod->type = MOD_BAD;
+ return 0;
+}
+
+/*
+====================
+R_RegisterMDR
+====================
+*/
+qhandle_t R_RegisterMDR(const char *name, model_t *mod)
+{
+ union {
+ unsigned *u;
+ void *v;
+ } buf;
+ int ident;
+ bool loaded = false;
+ int filesize;
+
+ filesize = ri.FS_ReadFile(name, (void **) &buf.v);
+ if(!buf.u)
+ {
+ mod->type = MOD_BAD;
+ return 0;
+ }
+
+ ident = LittleLong(*(unsigned *)buf.u);
+ if(ident == MDR_IDENT)
+ loaded = R_LoadMDR(mod, buf.u, filesize, name);
+
+ ri.FS_FreeFile (buf.v);
+
+ if(!loaded)
+ {
+ ri.Printf(PRINT_WARNING,"R_RegisterMDR: couldn't load mdr file %s\n", name);
+ mod->type = MOD_BAD;
+ return 0;
+ }
+
+ return mod->index;
+}
+
+/*
+====================
+R_RegisterIQM
+====================
+*/
+qhandle_t R_RegisterIQM(const char *name, model_t *mod)
+{
+ union {
+ unsigned *u;
+ void *v;
+ } buf;
+ bool loaded = false;
+ int filesize;
+
+ filesize = ri.FS_ReadFile(name, (void **) &buf.v);
+ if(!buf.u)
+ {
+ mod->type = MOD_BAD;
+ return 0;
+ }
+
+ loaded = R_LoadIQM(mod, buf.u, filesize, name);
+
+ ri.FS_FreeFile (buf.v);
+
+ if(!loaded)
+ {
+ ri.Printf(PRINT_WARNING,"R_RegisterIQM: couldn't load iqm file %s\n", name);
+ mod->type = MOD_BAD;
+ return 0;
+ }
+
+ return mod->index;
+}
+
+
+struct modelExtToLoaderMap_t
+{
+ const char *ext;
+ qhandle_t (*ModelLoader)( const char *, model_t * );
+};
+
+// Note that the ordering indicates the order of preference used
+// when there are multiple models of different formats available
+static modelExtToLoaderMap_t modelLoaders[ ] =
+{
+ { "iqm", R_RegisterIQM },
+ { "mdr", R_RegisterMDR },
+ { "md3", R_RegisterMD3 }
+};
+
+static int numModelLoaders = ARRAY_LEN(modelLoaders);
+
+//===============================================================================
+
+/*
+** R_GetModelByHandle
+*/
+model_t *R_GetModelByHandle( qhandle_t index ) {
+ model_t *mod;
+
+ // out of range gets the defualt model
+ if ( index < 1 || index >= tr.numModels ) {
+ return tr.models[0];
+ }
+
+ mod = tr.models[index];
+
+ return mod;
+}
+
+//===============================================================================
+
+/*
+** R_AllocModel
+*/
+model_t *R_AllocModel( void ) {
+ model_t *mod;
+
+ if ( tr.numModels == MAX_MOD_KNOWN ) {
+ return NULL;
+ }
+
+ mod = (model_t*)ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low );
+ mod->index = tr.numModels;
+ tr.models[tr.numModels] = mod;
+ tr.numModels++;
+
+ return mod;
+}
+
+/*
+====================
+RE_RegisterModel
+
+Loads in a model for the given name
+
+Zero will be returned if the model fails to load.
+An entry will be retained for failed models as an
+optimization to prevent disk rescanning if they are
+asked for again.
+====================
+*/
+qhandle_t RE_RegisterModel( const char *name ) {
+ model_t *mod;
+ qhandle_t hModel;
+ bool orgNameFailed = false;
+ int orgLoader = -1;
+ int i;
+ char localName[ MAX_QPATH ];
+ const char *ext;
+ char altName[ MAX_QPATH ];
+
+ if ( !name || !name[0] ) {
+ ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" );
+ return 0;
+ }
+
+ if ( strlen( name ) >= MAX_QPATH ) {
+ ri.Printf( PRINT_ALL, "Model name exceeds MAX_QPATH\n" );
+ return 0;
+ }
+
+ //
+ // search the currently loaded models
+ //
+ for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) {
+ mod = tr.models[hModel];
+ if ( !strcmp( mod->name, name ) ) {
+ if( mod->type == MOD_BAD ) {
+ return 0;
+ }
+ return hModel;
+ }
+ }
+
+ // allocate a new model_t
+
+ if ( ( mod = R_AllocModel() ) == NULL ) {
+ ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name);
+ return 0;
+ }
+
+ // only set the name after the model has been successfully loaded
+ Q_strncpyz( mod->name, name, sizeof( mod->name ) );
+
+
+ R_IssuePendingRenderCommands();
+
+ mod->type = MOD_BAD;
+ mod->numLods = 0;
+
+ //
+ // load the files
+ //
+ Q_strncpyz( localName, name, MAX_QPATH );
+
+ ext = COM_GetExtension( localName );
+
+ if( *ext )
+ {
+ // Look for the correct loader and use it
+ for( i = 0; i < numModelLoaders; i++ )
+ {
+ if( !Q_stricmp( ext, modelLoaders[ i ].ext ) )
+ {
+ // Load
+ hModel = modelLoaders[ i ].ModelLoader( localName, mod );
+ break;
+ }
+ }
+
+ // A loader was found
+ if( i < numModelLoaders )
+ {
+ if( !hModel )
+ {
+ // Loader failed, most likely because the file isn't there;
+ // try again without the extension
+ orgNameFailed = true;
+ orgLoader = i;
+ COM_StripExtension( name, localName, MAX_QPATH );
+ }
+ else
+ {
+ // Something loaded
+ return mod->index;
+ }
+ }
+ }
+
+ // Try and find a suitable match using all
+ // the model formats supported
+ for( i = 0; i < numModelLoaders; i++ )
+ {
+ if (i == orgLoader)
+ continue;
+
+ Com_sprintf( altName, sizeof (altName), "%s.%s", localName, modelLoaders[ i ].ext );
+
+ // Load
+ hModel = modelLoaders[ i ].ModelLoader( altName, mod );
+
+ if( hModel )
+ {
+ if( orgNameFailed )
+ {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n",
+ name, altName );
+ }
+
+ break;
+ }
+ }
+
+ return hModel;
+}
+
+/*
+=================
+R_LoadMD3
+=================
+*/
+static bool R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) {
+ int i, j;
+ md3Header_t *pinmodel;
+ md3Frame_t *frame;
+ md3Surface_t *surf;
+ md3Shader_t *shader;
+ md3Triangle_t *tri;
+ md3St_t *st;
+ md3XyzNormal_t *xyz;
+ md3Tag_t *tag;
+ int version;
+ int size;
+
+ pinmodel = (md3Header_t *)buffer;
+
+ version = LittleLong (pinmodel->version);
+ if (version != MD3_VERSION) {
+ ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
+ mod_name, version, MD3_VERSION);
+ return false;
+ }
+
+ mod->type = MOD_MESH;
+ size = LittleLong(pinmodel->ofsEnd);
+ mod->dataSize += size;
+ mod->md3[lod] = (md3Header_t*)ri.Hunk_Alloc( size, h_low );
+
+ Com_Memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) );
+
+ LL(mod->md3[lod]->ident);
+ LL(mod->md3[lod]->version);
+ LL(mod->md3[lod]->numFrames);
+ LL(mod->md3[lod]->numTags);
+ LL(mod->md3[lod]->numSurfaces);
+ LL(mod->md3[lod]->ofsFrames);
+ LL(mod->md3[lod]->ofsTags);
+ LL(mod->md3[lod]->ofsSurfaces);
+ LL(mod->md3[lod]->ofsEnd);
+
+ if ( mod->md3[lod]->numFrames < 1 ) {
+ ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
+ return false;
+ }
+
+ // swap all the frames
+ frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
+ for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
+ frame->radius = LittleFloat( frame->radius );
+ for ( j = 0 ; j < 3 ; j++ ) {
+ frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
+ frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
+ frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
+ }
+ }
+
+ // swap all the tags
+ tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
+ for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
+ for ( j = 0 ; j < 3 ; j++ ) {
+ tag->origin[j] = LittleFloat( tag->origin[j] );
+ tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
+ tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
+ tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
+ }
+ }
+
+ // swap all the surfaces
+ surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
+ for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
+
+ LL(surf->ident);
+ LL(surf->flags);
+ LL(surf->numFrames);
+ LL(surf->numShaders);
+ LL(surf->numTriangles);
+ LL(surf->ofsTriangles);
+ LL(surf->numVerts);
+ LL(surf->ofsShaders);
+ LL(surf->ofsSt);
+ LL(surf->ofsXyzNormals);
+ LL(surf->ofsEnd);
+
+ if ( surf->numVerts >= SHADER_MAX_VERTEXES ) {
+ ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on %s (%i).\n",
+ mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface",
+ surf->numVerts );
+ return false;
+ }
+ if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) {
+ ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on %s (%i).\n",
+ mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface",
+ surf->numTriangles );
+ return false;
+ }
+
+ // change to surface identifier
+ surf->ident = SF_MD3;
+
+ // lowercase the surface name so skin compares are faster
+ Q_strlwr( surf->name );
+
+ // strip off a trailing _1 or _2
+ // this is a crutch for q3data being a mess
+ j = strlen( surf->name );
+ if ( j > 2 && surf->name[j-2] == '_' ) {
+ surf->name[j-2] = 0;
+ }
+
+ // register the shaders
+ shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
+ for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
+ shader_t *sh;
+
+ sh = R_FindShader( shader->name, LIGHTMAP_NONE, true );
+ if ( sh->defaultShader ) {
+ shader->shaderIndex = 0;
+ } else {
+ shader->shaderIndex = sh->index;
+ }
+ }
+
+ // swap all the triangles
+ tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
+ for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
+ LL(tri->indexes[0]);
+ LL(tri->indexes[1]);
+ LL(tri->indexes[2]);
+ }
+
+ // swap all the ST
+ st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
+ for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
+ st->st[0] = LittleFloat( st->st[0] );
+ st->st[1] = LittleFloat( st->st[1] );
+ }
+
+ // swap all the XyzNormals
+ xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
+ for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
+ {
+ xyz->xyz[0] = LittleShort( xyz->xyz[0] );
+ xyz->xyz[1] = LittleShort( xyz->xyz[1] );
+ xyz->xyz[2] = LittleShort( xyz->xyz[2] );
+
+ xyz->normal = LittleShort( xyz->normal );
+ }
+
+
+ // find the next surface
+ surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
+ }
+
+ return true;
+}
+
+
+
+/*
+=================
+R_LoadMDR
+=================
+*/
+static bool R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name )
+{
+ int i, j, k, l;
+ mdrHeader_t *pinmodel, *mdr;
+ mdrFrame_t *frame;
+ mdrLOD_t *lod, *curlod;
+ mdrSurface_t *surf, *cursurf;
+ mdrTriangle_t *tri, *curtri;
+ mdrVertex_t *v, *curv;
+ mdrWeight_t *weight, *curweight;
+ mdrTag_t *tag, *curtag;
+ size_t size;
+ shader_t *sh;
+
+ pinmodel = (mdrHeader_t *)buffer;
+
+ pinmodel->version = LittleLong(pinmodel->version);
+ if (pinmodel->version != MDR_VERSION)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION);
+ return false;
+ }
+
+ size = LittleLong(pinmodel->ofsEnd);
+
+ if(size > filesize)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name);
+ return false;
+ }
+
+ mod->type = MOD_MDR;
+
+ LL(pinmodel->numFrames);
+ LL(pinmodel->numBones);
+ LL(pinmodel->ofsFrames);
+
+ // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame
+ // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target mdr.
+ if(pinmodel->ofsFrames < 0)
+ {
+ // mdrFrame_t is larger than mdrCompFrame_t:
+ size += pinmodel->numFrames * sizeof(frame->name);
+ // now add enough space for the uncompressed bones.
+ size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t)));
+ }
+
+ // simple bounds check
+ if(pinmodel->numBones < 0 ||
+ sizeof(*mdr) + pinmodel->numFrames * (sizeof(*frame) + (pinmodel->numBones - 1) * sizeof(*frame->bones)) > size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ mod->dataSize += size;
+ mod->modelData = mdr = (mdrHeader_t*)ri.Hunk_Alloc( size, h_low );
+
+ // Copy all the values over from the file and fix endian issues in the process, if necessary.
+
+ mdr->ident = LittleLong(pinmodel->ident);
+ mdr->version = pinmodel->version; // Don't need to swap byte order on this one, we already did above.
+ Q_strncpyz(mdr->name, pinmodel->name, sizeof(mdr->name));
+ mdr->numFrames = pinmodel->numFrames;
+ mdr->numBones = pinmodel->numBones;
+ mdr->numLODs = LittleLong(pinmodel->numLODs);
+ mdr->numTags = LittleLong(pinmodel->numTags);
+ // We don't care about the other offset values, we'll generate them ourselves while loading.
+
+ mod->numLods = mdr->numLODs;
+
+ if ( mdr->numFrames < 1 )
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name);
+ return false;
+ }
+
+ /* The first frame will be put into the first free space after the header */
+ frame = (mdrFrame_t *)(mdr + 1);
+ mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr);
+
+ if (pinmodel->ofsFrames < 0)
+ {
+ mdrCompFrame_t *cframe;
+
+ // compressed model...
+ cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames);
+
+ for(i = 0; i < mdr->numFrames; i++)
+ {
+ for(j = 0; j < 3; j++)
+ {
+ frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]);
+ frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]);
+ frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]);
+ }
+
+ frame->radius = LittleFloat(cframe->radius);
+ frame->name[0] = '\0'; // No name supplied in the compressed version.
+
+ for(j = 0; j < mdr->numBones; j++)
+ {
+ for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++)
+ {
+ // Do swapping for the uncompressing functions. They seem to use shorts
+ // values only, so I assume this will work. Never tested it on other
+ // platforms, though.
+
+ ((unsigned short *)(cframe->bones[j].Comp))[k] =
+ LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] );
+ }
+
+ /* Now do the actual uncompressing */
+ MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp);
+ }
+
+ // Next Frame...
+ cframe = (mdrCompFrame_t *) &cframe->bones[j];
+ frame = (mdrFrame_t *) &frame->bones[j];
+ }
+ }
+ else
+ {
+ mdrFrame_t *curframe;
+
+ // uncompressed model...
+ //
+
+ curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames);
+
+ // swap all the frames
+ for ( i = 0 ; i < mdr->numFrames ; i++)
+ {
+ for(j = 0; j < 3; j++)
+ {
+ frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]);
+ frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]);
+ frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]);
+ }
+
+ frame->radius = LittleFloat(curframe->radius);
+ Q_strncpyz(frame->name, curframe->name, sizeof(frame->name));
+
+ for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++)
+ {
+ ((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] );
+ }
+
+ curframe = (mdrFrame_t *) &curframe->bones[mdr->numBones];
+ frame = (mdrFrame_t *) &frame->bones[mdr->numBones];
+ }
+ }
+
+ // frame should now point to the first free address after all frames.
+ lod = (mdrLOD_t *) frame;
+ mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr);
+
+ curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs));
+
+ // swap all the LOD's
+ for ( l = 0 ; l < mdr->numLODs ; l++)
+ {
+ // simple bounds check
+ if((byte *) (lod + 1) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ lod->numSurfaces = LittleLong(curlod->numSurfaces);
+
+ // swap all the surfaces
+ surf = (mdrSurface_t *) (lod + 1);
+ lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod);
+ cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces));
+
+ for ( i = 0 ; i < lod->numSurfaces ; i++)
+ {
+ // simple bounds check
+ if((byte *) (surf + 1) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ // first do some copying stuff
+
+ surf->ident = SF_MDR;
+ Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name));
+ Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader));
+
+ surf->ofsHeader = (byte *) mdr - (byte *) surf;
+
+ surf->numVerts = LittleLong(cursurf->numVerts);
+ surf->numTriangles = LittleLong(cursurf->numTriangles);
+ // numBoneReferences and BoneReferences generally seem to be unused
+
+ // now do the checks that may fail.
+ if ( surf->numVerts >= SHADER_MAX_VERTEXES )
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on %s (%i).\n",
+ mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface",
+ surf->numVerts );
+ return false;
+ }
+ if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES )
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on %s (%i).\n",
+ mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface",
+ surf->numTriangles );
+ return false;
+ }
+ // lowercase the surface name so skin compares are faster
+ Q_strlwr( surf->name );
+
+ // register the shaders
+ sh = R_FindShader(surf->shader, LIGHTMAP_NONE, true);
+ if ( sh->defaultShader ) {
+ surf->shaderIndex = 0;
+ } else {
+ surf->shaderIndex = sh->index;
+ }
+
+ // now copy the vertexes.
+ v = (mdrVertex_t *) (surf + 1);
+ surf->ofsVerts = (int)((byte *) v - (byte *) surf);
+ curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts));
+
+ for(j = 0; j < surf->numVerts; j++)
+ {
+ LL(curv->numWeights);
+
+ // simple bounds check
+ if(curv->numWeights < 0 || (byte *) (v + 1) + (curv->numWeights - 1) * sizeof(*weight) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ v->normal[0] = LittleFloat(curv->normal[0]);
+ v->normal[1] = LittleFloat(curv->normal[1]);
+ v->normal[2] = LittleFloat(curv->normal[2]);
+
+ v->texCoords[0] = LittleFloat(curv->texCoords[0]);
+ v->texCoords[1] = LittleFloat(curv->texCoords[1]);
+
+ v->numWeights = curv->numWeights;
+ weight = &v->weights[0];
+ curweight = &curv->weights[0];
+
+ // Now copy all the weights
+ for(k = 0; k < v->numWeights; k++)
+ {
+ weight->boneIndex = LittleLong(curweight->boneIndex);
+ weight->boneWeight = LittleFloat(curweight->boneWeight);
+
+ weight->offset[0] = LittleFloat(curweight->offset[0]);
+ weight->offset[1] = LittleFloat(curweight->offset[1]);
+ weight->offset[2] = LittleFloat(curweight->offset[2]);
+
+ weight++;
+ curweight++;
+ }
+
+ v = (mdrVertex_t *) weight;
+ curv = (mdrVertex_t *) curweight;
+ }
+
+ // we know the offset to the triangles now:
+ tri = (mdrTriangle_t *) v;
+ surf->ofsTriangles = (int)((byte *) tri - (byte *) surf);
+ curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles));
+
+ // simple bounds check
+ if(surf->numTriangles < 0 || (byte *) (tri + surf->numTriangles) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ for(j = 0; j < surf->numTriangles; j++)
+ {
+ tri->indexes[0] = LittleLong(curtri->indexes[0]);
+ tri->indexes[1] = LittleLong(curtri->indexes[1]);
+ tri->indexes[2] = LittleLong(curtri->indexes[2]);
+
+ tri++;
+ curtri++;
+ }
+
+ // tri now points to the end of the surface.
+ surf->ofsEnd = (byte *) tri - (byte *) surf;
+ surf = (mdrSurface_t *) tri;
+
+ // find the next surface.
+ cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd));
+ }
+
+ // surf points to the next lod now.
+ lod->ofsEnd = (int)((byte *) surf - (byte *) lod);
+ lod = (mdrLOD_t *) surf;
+
+ // find the next LOD.
+ curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd));
+ }
+
+ // lod points to the first tag now, so update the offset too.
+ tag = (mdrTag_t *) lod;
+ mdr->ofsTags = (int)((byte *) tag - (byte *) mdr);
+ curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags));
+
+ // simple bounds check
+ if(mdr->numTags < 0 || (byte *) (tag + mdr->numTags) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ for (i = 0 ; i < mdr->numTags ; i++)
+ {
+ tag->boneIndex = LittleLong(curtag->boneIndex);
+ Q_strncpyz(tag->name, curtag->name, sizeof(tag->name));
+
+ tag++;
+ curtag++;
+ }
+
+ // And finally we know the real offset to the end.
+ mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr);
+
+ // phew! we're done.
+
+ return true;
+}
+
+
+
+//=============================================================================
+
+/*
+** RE_BeginRegistration
+*/
+void RE_BeginRegistration( glconfig_t *glconfigOut ) {
+
+ R_Init();
+
+ *glconfigOut = glConfig;
+
+ R_IssuePendingRenderCommands();
+
+ tr.viewCluster = -1; // force markleafs to regenerate
+ R_ClearFlares();
+ RE_ClearScene();
+
+ tr.registered = true;
+}
+
+//=============================================================================
+
+/*
+===============
+R_ModelInit
+===============
+*/
+void R_ModelInit( void ) {
+ model_t *mod;
+
+ // leave a space for NULL model
+ tr.numModels = 0;
+
+ mod = R_AllocModel();
+ mod->type = MOD_BAD;
+}
+
+
+/*
+================
+R_Modellist_f
+================
+*/
+void R_Modellist_f( void ) {
+ int i, j;
+ model_t *mod;
+ int total;
+ int lods;
+
+ total = 0;
+ for ( i = 1 ; i < tr.numModels; i++ ) {
+ mod = tr.models[i];
+ lods = 1;
+ for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) {
+ if ( mod->md3[j] && mod->md3[j] != mod->md3[j-1] ) {
+ lods++;
+ }
+ }
+ ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name );
+ total += mod->dataSize;
+ }
+ ri.Printf( PRINT_ALL, "%8i : Total models\n", total );
+
+#if 0 // not working right with new hunk
+ if ( tr.world ) {
+ ri.Printf( PRINT_ALL, "\n%8i : %s\n", tr.world->dataSize, tr.world->name );
+ }
+#endif
+}
+
+
+//=============================================================================
+
+
+/*
+================
+R_GetTag
+================
+*/
+static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) {
+ md3Tag_t *tag;
+ int i;
+
+ if ( frame >= mod->numFrames ) {
+ // it is possible to have a bad frame while changing models, so don't error
+ frame = mod->numFrames - 1;
+ }
+
+ tag = (md3Tag_t *)((byte *)mod + mod->ofsTags) + frame * mod->numTags;
+ for ( i = 0 ; i < mod->numTags ; i++, tag++ ) {
+ if ( !strcmp( tag->name, tagName ) ) {
+ return tag; // found it
+ }
+ }
+
+ return NULL;
+}
+
+md3Tag_t *R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t * dest)
+{
+ int i, j, k;
+ int frameSize;
+ mdrFrame_t *frame;
+ mdrTag_t *tag;
+
+ if ( framenum >= mod->numFrames )
+ {
+ // it is possible to have a bad frame while changing models, so don't error
+ framenum = mod->numFrames - 1;
+ }
+
+ tag = (mdrTag_t *)((byte *)mod + mod->ofsTags);
+ for ( i = 0 ; i < mod->numTags ; i++, tag++ )
+ {
+ if ( !strcmp( tag->name, tagName ) )
+ {
+ Q_strncpyz(dest->name, tag->name, sizeof(dest->name));
+
+ // uncompressed model...
+ //
+ frameSize = (intptr_t)( &((mdrFrame_t *)0)->bones[ mod->numBones ] );
+ frame = (mdrFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize );
+
+ for (j = 0; j < 3; j++)
+ {
+ for (k = 0; k < 3; k++)
+ dest->axis[j][k] = frame->bones[tag->boneIndex].matrix[k][j];
+ }
+
+ dest->origin[0] = frame->bones[tag->boneIndex].matrix[0][3];
+ dest->origin[1] = frame->bones[tag->boneIndex].matrix[1][3];
+ dest->origin[2] = frame->bones[tag->boneIndex].matrix[2][3];
+
+ return dest;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+================
+R_LerpTag
+================
+*/
+int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
+ float frac, const char *tagName ) {
+ md3Tag_t *start, *end;
+ md3Tag_t start_space, end_space;
+ int i;
+ float frontLerp, backLerp;
+ model_t *model;
+
+ model = R_GetModelByHandle( handle );
+ if ( !model->md3[0] )
+ {
+ if(model->type == MOD_MDR)
+ {
+ start = R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, &start_space);
+ end = R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, &end_space);
+ }
+ else if( model->type == MOD_IQM ) {
+ return R_IQMLerpTag( tag, (iqmData_t*)model->modelData,
+ startFrame, endFrame,
+ frac, tagName );
+ } else {
+ start = end = NULL;
+ }
+ }
+ else
+ {
+ start = R_GetTag( model->md3[0], startFrame, tagName );
+ end = R_GetTag( model->md3[0], endFrame, tagName );
+ }
+
+ if ( !start || !end ) {
+ AxisClear( tag->axis );
+ VectorClear( tag->origin );
+ return false;
+ }
+
+ frontLerp = frac;
+ backLerp = 1.0f - frac;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ tag->origin[i] = start->origin[i] * backLerp + end->origin[i] * frontLerp;
+ tag->axis[0][i] = start->axis[0][i] * backLerp + end->axis[0][i] * frontLerp;
+ tag->axis[1][i] = start->axis[1][i] * backLerp + end->axis[1][i] * frontLerp;
+ tag->axis[2][i] = start->axis[2][i] * backLerp + end->axis[2][i] * frontLerp;
+ }
+ VectorNormalize( tag->axis[0] );
+ VectorNormalize( tag->axis[1] );
+ VectorNormalize( tag->axis[2] );
+ return true;
+}
+
+
+/*
+====================
+R_ModelBounds
+====================
+*/
+void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) {
+ model_t *model;
+
+ model = R_GetModelByHandle( handle );
+
+ if(model->type == MOD_BRUSH) {
+ VectorCopy( model->bmodel->bounds[0], mins );
+ VectorCopy( model->bmodel->bounds[1], maxs );
+
+ return;
+ } else if (model->type == MOD_MESH) {
+ md3Header_t *header;
+ md3Frame_t *frame;
+
+ header = model->md3[0];
+ frame = (md3Frame_t *) ((byte *)header + header->ofsFrames);
+
+ VectorCopy( frame->bounds[0], mins );
+ VectorCopy( frame->bounds[1], maxs );
+
+ return;
+ } else if (model->type == MOD_MDR) {
+ mdrHeader_t *header;
+ mdrFrame_t *frame;
+
+ header = (mdrHeader_t *)model->modelData;
+ frame = (mdrFrame_t *) ((byte *)header + header->ofsFrames);
+
+ VectorCopy( frame->bounds[0], mins );
+ VectorCopy( frame->bounds[1], maxs );
+
+ return;
+ } else if(model->type == MOD_IQM) {
+ iqmData_t *iqmData;
+
+ iqmData = (iqmData_t*)model->modelData;
+
+ if(iqmData->bounds)
+ {
+ VectorCopy(iqmData->bounds, mins);
+ VectorCopy(iqmData->bounds + 3, maxs);
+ return;
+ }
+ }
+
+ VectorClear( mins );
+ VectorClear( maxs );
+}
diff --git a/src/renderergl1/tr_model_iqm.cpp b/src/renderergl1/tr_model_iqm.cpp
new file mode 100644
index 0000000..680aecd
--- /dev/null
+++ b/src/renderergl1/tr_model_iqm.cpp
@@ -0,0 +1,1187 @@
+/*
+===========================================================================
+Copyright (C) 2011 Thilo Schulz <thilo@tjps.eu>
+Copyright (C) 2011 Matthias Bentrup <matthias.bentrup@googlemail.com>
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+#define LL(x) x=LittleLong(x)
+
+// 3x4 identity matrix
+static float identityMatrix[12] = {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0
+};
+
+static bool IQM_CheckRange( iqmHeader_t *header, int offset,
+ int count,int size ) {
+ // return true if the range specified by offset, count and size
+ // doesn't fit into the file
+ return ( count <= 0 ||
+ offset < 0 ||
+ offset > header->filesize ||
+ offset + count * size < 0 ||
+ offset + count * size > header->filesize );
+}
+// "multiply" 3x4 matrices, these are assumed to be the top 3 rows
+// of a 4x4 matrix with the last row = (0 0 0 1)
+static void Matrix34Multiply( float *a, float *b, float *out ) {
+ out[ 0] = a[0] * b[0] + a[1] * b[4] + a[ 2] * b[ 8];
+ out[ 1] = a[0] * b[1] + a[1] * b[5] + a[ 2] * b[ 9];
+ out[ 2] = a[0] * b[2] + a[1] * b[6] + a[ 2] * b[10];
+ out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3];
+ out[ 4] = a[4] * b[0] + a[5] * b[4] + a[ 6] * b[ 8];
+ out[ 5] = a[4] * b[1] + a[5] * b[5] + a[ 6] * b[ 9];
+ out[ 6] = a[4] * b[2] + a[5] * b[6] + a[ 6] * b[10];
+ out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7];
+ out[ 8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[ 8];
+ out[ 9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[ 9];
+ out[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10];
+ out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11];
+}
+static void Matrix34Multiply_OnlySetOrigin( float *a, float *b, float *out ) {
+ out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3];
+ out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7];
+ out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11];
+}
+static void InterpolateMatrix( float *a, float *b, float lerp, float *mat ) {
+ float unLerp = 1.0f - lerp;
+
+ mat[ 0] = a[ 0] * unLerp + b[ 0] * lerp;
+ mat[ 1] = a[ 1] * unLerp + b[ 1] * lerp;
+ mat[ 2] = a[ 2] * unLerp + b[ 2] * lerp;
+ mat[ 3] = a[ 3] * unLerp + b[ 3] * lerp;
+ mat[ 4] = a[ 4] * unLerp + b[ 4] * lerp;
+ mat[ 5] = a[ 5] * unLerp + b[ 5] * lerp;
+ mat[ 6] = a[ 6] * unLerp + b[ 6] * lerp;
+ mat[ 7] = a[ 7] * unLerp + b[ 7] * lerp;
+ mat[ 8] = a[ 8] * unLerp + b[ 8] * lerp;
+ mat[ 9] = a[ 9] * unLerp + b[ 9] * lerp;
+ mat[10] = a[10] * unLerp + b[10] * lerp;
+ mat[11] = a[11] * unLerp + b[11] * lerp;
+}
+static void JointToMatrix( vec4_t rot, vec3_t scale, vec3_t trans,
+ float *mat ) {
+ float xx = 2.0f * rot[0] * rot[0];
+ float yy = 2.0f * rot[1] * rot[1];
+ float zz = 2.0f * rot[2] * rot[2];
+ float xy = 2.0f * rot[0] * rot[1];
+ float xz = 2.0f * rot[0] * rot[2];
+ float yz = 2.0f * rot[1] * rot[2];
+ float wx = 2.0f * rot[3] * rot[0];
+ float wy = 2.0f * rot[3] * rot[1];
+ float wz = 2.0f * rot[3] * rot[2];
+
+ mat[ 0] = scale[0] * (1.0f - (yy + zz));
+ mat[ 1] = scale[0] * (xy - wz);
+ mat[ 2] = scale[0] * (xz + wy);
+ mat[ 3] = trans[0];
+ mat[ 4] = scale[1] * (xy + wz);
+ mat[ 5] = scale[1] * (1.0f - (xx + zz));
+ mat[ 6] = scale[1] * (yz - wx);
+ mat[ 7] = trans[1];
+ mat[ 8] = scale[2] * (xz - wy);
+ mat[ 9] = scale[2] * (yz + wx);
+ mat[10] = scale[2] * (1.0f - (xx + yy));
+ mat[11] = trans[2];
+}
+static void Matrix34Invert( float *inMat, float *outMat )
+{
+ vec3_t trans;
+ float invSqrLen, *v;
+
+ outMat[ 0] = inMat[ 0]; outMat[ 1] = inMat[ 4]; outMat[ 2] = inMat[ 8];
+ outMat[ 4] = inMat[ 1]; outMat[ 5] = inMat[ 5]; outMat[ 6] = inMat[ 9];
+ outMat[ 8] = inMat[ 2]; outMat[ 9] = inMat[ 6]; outMat[10] = inMat[10];
+
+ v = outMat + 0; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
+ v = outMat + 4; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
+ v = outMat + 8; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
+
+ trans[0] = inMat[ 3];
+ trans[1] = inMat[ 7];
+ trans[2] = inMat[11];
+
+ outMat[ 3] = -DotProduct(outMat + 0, trans);
+ outMat[ 7] = -DotProduct(outMat + 4, trans);
+ outMat[11] = -DotProduct(outMat + 8, trans);
+}
+
+/*
+=================
+R_LoadIQM
+
+Load an IQM model and compute the joint matrices for every frame.
+=================
+*/
+bool R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_name ) {
+ iqmHeader_t *header;
+ iqmVertexArray_t *vertexarray;
+ iqmTriangle_t *triangle;
+ iqmMesh_t *mesh;
+ iqmJoint_t *joint;
+ iqmPose_t *pose;
+ iqmBounds_t *bounds;
+ unsigned short *framedata;
+ char *str;
+ int i, j;
+ float jointInvMats[IQM_MAX_JOINTS * 12] = {0.0f};
+ float *mat, *matInv;
+ size_t size, joint_names;
+ iqmData_t *iqmData;
+ srfIQModel_t *surface;
+ char meshName[MAX_QPATH];
+ byte blendIndexesType, blendWeightsType;
+
+ if( filesize < sizeof(iqmHeader_t) ) {
+ return false;
+ }
+
+ header = (iqmHeader_t *)buffer;
+ if( Q_strncmp( header->magic, IQM_MAGIC, sizeof(header->magic) ) ) {
+ return false;
+ }
+
+ LL( header->version );
+ if( header->version != IQM_VERSION ) {
+ ri.Printf(PRINT_WARNING, "R_LoadIQM: %s is a unsupported IQM version (%d), only version %d is supported.\n",
+ mod_name, header->version, IQM_VERSION);
+ return false;
+ }
+
+ LL( header->filesize );
+ if( header->filesize > filesize || header->filesize > 16<<20 ) {
+ return false;
+ }
+
+ LL( header->flags );
+ LL( header->num_text );
+ LL( header->ofs_text );
+ LL( header->num_meshes );
+ LL( header->ofs_meshes );
+ LL( header->num_vertexarrays );
+ LL( header->num_vertexes );
+ LL( header->ofs_vertexarrays );
+ LL( header->num_triangles );
+ LL( header->ofs_triangles );
+ LL( header->ofs_adjacency );
+ LL( header->num_joints );
+ LL( header->ofs_joints );
+ LL( header->num_poses );
+ LL( header->ofs_poses );
+ LL( header->num_anims );
+ LL( header->ofs_anims );
+ LL( header->num_frames );
+ LL( header->num_framechannels );
+ LL( header->ofs_frames );
+ LL( header->ofs_bounds );
+ LL( header->num_comment );
+ LL( header->ofs_comment );
+ LL( header->num_extensions );
+ LL( header->ofs_extensions );
+
+ // check ioq3 joint limit
+ if ( header->num_joints > IQM_MAX_JOINTS ) {
+ ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %d joints (%d).\n",
+ mod_name, IQM_MAX_JOINTS, header->num_joints);
+ return false;
+ }
+
+ blendIndexesType = blendWeightsType = IQM_UBYTE;
+
+ // check and swap vertex arrays
+ if( IQM_CheckRange( header, header->ofs_vertexarrays,
+ header->num_vertexarrays,
+ sizeof(iqmVertexArray_t) ) ) {
+ return false;
+ }
+ vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays);
+ for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) {
+ int n, *intPtr;
+
+ if( vertexarray->size <= 0 || vertexarray->size > 4 ) {
+ return false;
+ }
+
+ // total number of values
+ n = header->num_vertexes * vertexarray->size;
+
+ switch( vertexarray->format ) {
+ case IQM_BYTE:
+ case IQM_UBYTE:
+ // 1 byte, no swapping necessary
+ if( IQM_CheckRange( header, vertexarray->offset,
+ n, sizeof(byte) ) ) {
+ return false;
+ }
+ break;
+ case IQM_INT:
+ case IQM_UINT:
+ case IQM_FLOAT:
+ // 4-byte swap
+ if( IQM_CheckRange( header, vertexarray->offset,
+ n, sizeof(float) ) ) {
+ return false;
+ }
+ intPtr = (int *)((byte *)header + vertexarray->offset);
+ for( j = 0; j < n; j++, intPtr++ ) {
+ LL( *intPtr );
+ }
+ break;
+ default:
+ // not supported
+ return false;
+ break;
+ }
+
+ switch( vertexarray->type ) {
+ case IQM_POSITION:
+ case IQM_NORMAL:
+ if( vertexarray->format != IQM_FLOAT ||
+ vertexarray->size != 3 ) {
+ return false;
+ }
+ break;
+ case IQM_TANGENT:
+ if( vertexarray->format != IQM_FLOAT ||
+ vertexarray->size != 4 ) {
+ return false;
+ }
+ break;
+ case IQM_TEXCOORD:
+ if( vertexarray->format != IQM_FLOAT ||
+ vertexarray->size != 2 ) {
+ return false;
+ }
+ break;
+ case IQM_BLENDINDEXES:
+ if( (vertexarray->format != IQM_INT &&
+ vertexarray->format != IQM_UBYTE) ||
+ vertexarray->size != 4 ) {
+ return false;
+ }
+ blendIndexesType = vertexarray->format;
+ break;
+ case IQM_BLENDWEIGHTS:
+ if( (vertexarray->format != IQM_FLOAT &&
+ vertexarray->format != IQM_UBYTE) ||
+ vertexarray->size != 4 ) {
+ return false;
+ }
+ blendWeightsType = vertexarray->format;
+ break;
+ case IQM_COLOR:
+ if( vertexarray->format != IQM_UBYTE ||
+ vertexarray->size != 4 ) {
+ return false;
+ }
+ break;
+ }
+ }
+
+ // check and swap triangles
+ if( IQM_CheckRange( header, header->ofs_triangles,
+ header->num_triangles, sizeof(iqmTriangle_t) ) ) {
+ return false;
+ }
+ triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles);
+ for( i = 0; i < header->num_triangles; i++, triangle++ ) {
+ LL( triangle->vertex[0] );
+ LL( triangle->vertex[1] );
+ LL( triangle->vertex[2] );
+
+ if( triangle->vertex[0] > header->num_vertexes ||
+ triangle->vertex[1] > header->num_vertexes ||
+ triangle->vertex[2] > header->num_vertexes ) {
+ return false;
+ }
+ }
+
+ // check and swap meshes
+ if( IQM_CheckRange( header, header->ofs_meshes,
+ header->num_meshes, sizeof(iqmMesh_t) ) ) {
+ return false;
+ }
+ mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes);
+ for( i = 0; i < header->num_meshes; i++, mesh++) {
+ LL( mesh->name );
+ LL( mesh->material );
+ LL( mesh->first_vertex );
+ LL( mesh->num_vertexes );
+ LL( mesh->first_triangle );
+ LL( mesh->num_triangles );
+
+ if ( mesh->name < header->num_text ) {
+ Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) );
+ } else {
+ meshName[0] = '\0';
+ }
+
+ // check ioq3 limits
+ if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES )
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n",
+ mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface",
+ mesh->num_vertexes );
+ return false;
+ }
+ if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES )
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n",
+ mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface",
+ mesh->num_triangles );
+ return false;
+ }
+
+ if( mesh->first_vertex >= header->num_vertexes ||
+ mesh->first_vertex + mesh->num_vertexes > header->num_vertexes ||
+ mesh->first_triangle >= header->num_triangles ||
+ mesh->first_triangle + mesh->num_triangles > header->num_triangles ||
+ mesh->name >= header->num_text ||
+ mesh->material >= header->num_text ) {
+ return false;
+ }
+ }
+
+ if( header->num_poses != header->num_joints && header->num_poses != 0 ) {
+ ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n",
+ mod_name, header->num_poses, header->num_joints );
+ return false;
+ }
+
+ joint_names = 0;
+
+ if ( header->num_joints )
+ {
+ // check and swap joints
+ if( IQM_CheckRange( header, header->ofs_joints,
+ header->num_joints, sizeof(iqmJoint_t) ) ) {
+ return false;
+ }
+ joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
+ for( i = 0; i < header->num_joints; i++, joint++ ) {
+ LL( joint->name );
+ LL( joint->parent );
+ LL( joint->translate[0] );
+ LL( joint->translate[1] );
+ LL( joint->translate[2] );
+ LL( joint->rotate[0] );
+ LL( joint->rotate[1] );
+ LL( joint->rotate[2] );
+ LL( joint->rotate[3] );
+ LL( joint->scale[0] );
+ LL( joint->scale[1] );
+ LL( joint->scale[2] );
+
+ if( joint->parent < -1 ||
+ joint->parent >= (int)header->num_joints ||
+ joint->name >= (int)header->num_text ) {
+ return false;
+ }
+ joint_names += strlen( (char *)header + header->ofs_text +
+ joint->name ) + 1;
+ }
+ }
+
+ if ( header->num_poses )
+ {
+ // check and swap poses
+ if( IQM_CheckRange( header, header->ofs_poses,
+ header->num_poses, sizeof(iqmPose_t) ) ) {
+ return false;
+ }
+ pose = (iqmPose_t *)((byte *)header + header->ofs_poses);
+ for( i = 0; i < header->num_poses; i++, pose++ ) {
+ LL( pose->parent );
+ LL( pose->mask );
+ LL( pose->channeloffset[0] );
+ LL( pose->channeloffset[1] );
+ LL( pose->channeloffset[2] );
+ LL( pose->channeloffset[3] );
+ LL( pose->channeloffset[4] );
+ LL( pose->channeloffset[5] );
+ LL( pose->channeloffset[6] );
+ LL( pose->channeloffset[7] );
+ LL( pose->channeloffset[8] );
+ LL( pose->channeloffset[9] );
+ LL( pose->channelscale[0] );
+ LL( pose->channelscale[1] );
+ LL( pose->channelscale[2] );
+ LL( pose->channelscale[3] );
+ LL( pose->channelscale[4] );
+ LL( pose->channelscale[5] );
+ LL( pose->channelscale[6] );
+ LL( pose->channelscale[7] );
+ LL( pose->channelscale[8] );
+ LL( pose->channelscale[9] );
+ }
+ }
+
+ if (header->ofs_bounds)
+ {
+ // check and swap model bounds
+ if(IQM_CheckRange(header, header->ofs_bounds,
+ header->num_frames, sizeof(*bounds)))
+ {
+ return false;
+ }
+ bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds);
+ for(i = 0; i < header->num_frames; i++)
+ {
+ LL(bounds->bbmin[0]);
+ LL(bounds->bbmin[1]);
+ LL(bounds->bbmin[2]);
+ LL(bounds->bbmax[0]);
+ LL(bounds->bbmax[1]);
+ LL(bounds->bbmax[2]);
+
+ bounds++;
+ }
+ }
+
+ // allocate the model and copy the data
+ size = sizeof(iqmData_t);
+ size += header->num_meshes * sizeof( srfIQModel_t );
+ size += header->num_joints * 12 * sizeof( float ); // joint mats
+ size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats
+ if(header->ofs_bounds)
+ size += header->num_frames * 6 * sizeof(float); // model bounds
+ size += header->num_vertexes * 3 * sizeof(float); // positions
+ size += header->num_vertexes * 2 * sizeof(float); // texcoords
+ size += header->num_vertexes * 3 * sizeof(float); // normals
+ size += header->num_vertexes * 4 * sizeof(float); // tangents
+ size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes
+ size += header->num_vertexes * 4 * sizeof(byte); // colors
+ size += header->num_joints * sizeof(int); // parents
+ size += header->num_triangles * 3 * sizeof(int); // triangles
+ size += joint_names; // joint names
+
+ // blendWeights
+ if (blendWeightsType == IQM_FLOAT) {
+ size += header->num_vertexes * 4 * sizeof(float);
+ } else {
+ size += header->num_vertexes * 4 * sizeof(byte);
+ }
+
+ mod->type = MOD_IQM;
+ iqmData = (iqmData_t *)ri.Hunk_Alloc( size, h_low );
+ mod->modelData = iqmData;
+
+ // fill header
+ iqmData->num_vertexes = header->num_vertexes;
+ iqmData->num_triangles = header->num_triangles;
+ iqmData->num_frames = header->num_frames;
+ iqmData->num_surfaces = header->num_meshes;
+ iqmData->num_joints = header->num_joints;
+ iqmData->num_poses = header->num_poses;
+ iqmData->blendWeightsType = blendWeightsType;
+ iqmData->surfaces = (srfIQModel_t *)(iqmData + 1);
+ iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces);
+ iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints;
+ if(header->ofs_bounds)
+ {
+ iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames;
+ iqmData->positions = iqmData->bounds + 6 * header->num_frames;
+ }
+ else
+ iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames;
+ iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes;
+ iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes;
+ iqmData->tangents = iqmData->normals + 3 * header->num_vertexes;
+ iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes);
+
+ if(blendWeightsType == IQM_FLOAT) {
+ iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes);
+ iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes);
+ } else {
+ iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes;
+ iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes;
+ }
+
+ iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes);
+ iqmData->triangles = iqmData->jointParents + header->num_joints;
+ iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles);
+
+ if ( header->num_joints == 0 )
+ iqmData->jointMats = NULL;
+
+ if ( header->num_poses == 0 )
+ iqmData->poseMats = NULL;
+
+ // calculate joint matrices and their inverses
+ // joint inverses are needed only until the pose matrices are calculated
+ mat = iqmData->jointMats;
+ matInv = jointInvMats;
+ joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
+ for( i = 0; i < header->num_joints; i++, joint++ ) {
+ float baseFrame[12], invBaseFrame[12];
+
+ JointToMatrix( joint->rotate, joint->scale, joint->translate, baseFrame );
+ Matrix34Invert( baseFrame, invBaseFrame );
+
+ if ( joint->parent >= 0 )
+ {
+ Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat );
+ mat += 12;
+ Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv );
+ matInv += 12;
+ }
+ else
+ {
+ Com_Memcpy( mat, baseFrame, sizeof(baseFrame) );
+ mat += 12;
+ Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) );
+ matInv += 12;
+ }
+ }
+
+ // calculate pose matrices
+ framedata = (unsigned short *)((byte *)header + header->ofs_frames);
+ mat = iqmData->poseMats;
+ for( i = 0; i < header->num_frames; i++ ) {
+ pose = (iqmPose_t *)((byte *)header + header->ofs_poses);
+ for( j = 0; j < header->num_poses; j++, pose++ ) {
+ vec3_t translate;
+ vec4_t rotate;
+ vec3_t scale;
+ float mat1[12], mat2[12];
+
+ translate[0] = pose->channeloffset[0];
+ if( pose->mask & 0x001)
+ translate[0] += *framedata++ * pose->channelscale[0];
+ translate[1] = pose->channeloffset[1];
+ if( pose->mask & 0x002)
+ translate[1] += *framedata++ * pose->channelscale[1];
+ translate[2] = pose->channeloffset[2];
+ if( pose->mask & 0x004)
+ translate[2] += *framedata++ * pose->channelscale[2];
+
+ rotate[0] = pose->channeloffset[3];
+ if( pose->mask & 0x008)
+ rotate[0] += *framedata++ * pose->channelscale[3];
+ rotate[1] = pose->channeloffset[4];
+ if( pose->mask & 0x010)
+ rotate[1] += *framedata++ * pose->channelscale[4];
+ rotate[2] = pose->channeloffset[5];
+ if( pose->mask & 0x020)
+ rotate[2] += *framedata++ * pose->channelscale[5];
+ rotate[3] = pose->channeloffset[6];
+ if( pose->mask & 0x040)
+ rotate[3] += *framedata++ * pose->channelscale[6];
+
+ scale[0] = pose->channeloffset[7];
+ if( pose->mask & 0x080)
+ scale[0] += *framedata++ * pose->channelscale[7];
+ scale[1] = pose->channeloffset[8];
+ if( pose->mask & 0x100)
+ scale[1] += *framedata++ * pose->channelscale[8];
+ scale[2] = pose->channeloffset[9];
+ if( pose->mask & 0x200)
+ scale[2] += *framedata++ * pose->channelscale[9];
+
+ // construct transformation matrix
+ JointToMatrix( rotate, scale, translate, mat1 );
+
+ if( pose->parent >= 0 ) {
+ Matrix34Multiply( iqmData->jointMats + 12 * pose->parent,
+ mat1, mat2 );
+ } else {
+ Com_Memcpy( mat2, mat1, sizeof(mat1) );
+ }
+
+ Matrix34Multiply( mat2, jointInvMats + 12 * j, mat );
+ mat += 12;
+ }
+ }
+
+ // register shaders
+ // overwrite the material offset with the shader index
+ mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes);
+ surface = iqmData->surfaces;
+ str = (char *)header + header->ofs_text;
+ for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) {
+ surface->surfaceType = SF_IQM;
+ Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name));
+ Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster
+ surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, true );
+ if( surface->shader->defaultShader )
+ surface->shader = tr.defaultShader;
+ surface->data = iqmData;
+ surface->first_vertex = mesh->first_vertex;
+ surface->num_vertexes = mesh->num_vertexes;
+ surface->first_triangle = mesh->first_triangle;
+ surface->num_triangles = mesh->num_triangles;
+ }
+
+ // copy vertexarrays and indexes
+ vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays);
+ for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) {
+ int n;
+
+ // total number of values
+ n = header->num_vertexes * vertexarray->size;
+
+ switch( vertexarray->type ) {
+ case IQM_POSITION:
+ Com_Memcpy( iqmData->positions,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(float) );
+ break;
+ case IQM_NORMAL:
+ Com_Memcpy( iqmData->normals,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(float) );
+ break;
+ case IQM_TANGENT:
+ Com_Memcpy( iqmData->tangents,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(float) );
+ break;
+ case IQM_TEXCOORD:
+ Com_Memcpy( iqmData->texcoords,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(float) );
+ break;
+ case IQM_BLENDINDEXES:
+ if( blendIndexesType == IQM_INT ) {
+ int *data = (int*)((byte*)header + vertexarray->offset);
+ for ( j = 0; j < n; j++ ) {
+ iqmData->blendIndexes[j] = (byte)data[j];
+ }
+ } else {
+ Com_Memcpy( iqmData->blendIndexes,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(byte) );
+ }
+ break;
+ case IQM_BLENDWEIGHTS:
+ if( blendWeightsType == IQM_FLOAT ) {
+ Com_Memcpy( iqmData->blendWeights.f,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(float) );
+ } else {
+ Com_Memcpy( iqmData->blendWeights.b,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(byte) );
+ }
+ break;
+ case IQM_COLOR:
+ Com_Memcpy( iqmData->colors,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(byte) );
+ break;
+ }
+ }
+
+ // copy joint parents
+ joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
+ for( i = 0; i < header->num_joints; i++, joint++ ) {
+ iqmData->jointParents[i] = joint->parent;
+ }
+
+ // copy triangles
+ triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles);
+ for( i = 0; i < header->num_triangles; i++, triangle++ ) {
+ iqmData->triangles[3*i+0] = triangle->vertex[0];
+ iqmData->triangles[3*i+1] = triangle->vertex[1];
+ iqmData->triangles[3*i+2] = triangle->vertex[2];
+ }
+
+ // copy joint names
+ str = iqmData->names;
+ joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
+ for( i = 0; i < header->num_joints; i++, joint++ ) {
+ char *name = (char *)header + header->ofs_text +
+ joint->name;
+ int len = strlen( name ) + 1;
+ Com_Memcpy( str, name, len );
+ str += len;
+ }
+
+ // copy model bounds
+ if(header->ofs_bounds)
+ {
+ mat = iqmData->bounds;
+ bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds);
+ for(i = 0; i < header->num_frames; i++)
+ {
+ mat[0] = bounds->bbmin[0];
+ mat[1] = bounds->bbmin[1];
+ mat[2] = bounds->bbmin[2];
+ mat[3] = bounds->bbmax[0];
+ mat[4] = bounds->bbmax[1];
+ mat[5] = bounds->bbmax[2];
+
+ mat += 6;
+ bounds++;
+ }
+ }
+
+ return true;
+}
+
+/*
+=============
+R_CullIQM
+=============
+*/
+static int R_CullIQM( iqmData_t *data, trRefEntity_t *ent ) {
+ vec3_t bounds[2];
+ vec_t *oldBounds, *newBounds;
+ int i;
+
+ if (!data->bounds) {
+ tr.pc.c_box_cull_md3_clip++;
+ return CULL_CLIP;
+ }
+
+ // compute bounds pointers
+ oldBounds = data->bounds + 6*ent->e.oldframe;
+ newBounds = data->bounds + 6*ent->e.frame;
+
+ // calculate a bounding box in the current coordinate system
+ for (i = 0 ; i < 3 ; i++) {
+ bounds[0][i] = oldBounds[i] < newBounds[i] ? oldBounds[i] : newBounds[i];
+ bounds[1][i] = oldBounds[i+3] > newBounds[i+3] ? oldBounds[i+3] : newBounds[i+3];
+ }
+
+ switch ( R_CullLocalBox( bounds ) )
+ {
+ case CULL_IN:
+ tr.pc.c_box_cull_md3_in++;
+ return CULL_IN;
+ case CULL_CLIP:
+ tr.pc.c_box_cull_md3_clip++;
+ return CULL_CLIP;
+ case CULL_OUT:
+ default:
+ tr.pc.c_box_cull_md3_out++;
+ return CULL_OUT;
+ }
+}
+
+/*
+=================
+R_ComputeIQMFogNum
+
+=================
+*/
+int R_ComputeIQMFogNum( iqmData_t *data, trRefEntity_t *ent ) {
+ int i, j;
+ fog_t *fog;
+ const vec_t *bounds;
+ const vec_t defaultBounds[6] = { -8, -8, -8, 8, 8, 8 };
+ vec3_t diag, center;
+ vec3_t localOrigin;
+ vec_t radius;
+
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ return 0;
+ }
+
+ // FIXME: non-normalized axis issues
+ if (data->bounds) {
+ bounds = data->bounds + 6*ent->e.frame;
+ } else {
+ bounds = defaultBounds;
+ }
+ VectorSubtract( bounds+3, bounds, diag );
+ VectorMA( bounds, 0.5f, diag, center );
+ VectorAdd( ent->e.origin, center, localOrigin );
+ radius = 0.5f * VectorLength( diag );
+
+ for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
+ fog = &tr.world->fogs[i];
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( localOrigin[j] - radius >= fog->bounds[1][j] ) {
+ break;
+ }
+ if ( localOrigin[j] + radius <= fog->bounds[0][j] ) {
+ break;
+ }
+ }
+ if ( j == 3 ) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+/*
+=================
+R_AddIQMSurfaces
+
+Add all surfaces of this model
+=================
+*/
+void R_AddIQMSurfaces( trRefEntity_t *ent ) {
+ iqmData_t *data;
+ srfIQModel_t *surface;
+ int i, j;
+ bool personalModel;
+ int cull;
+ int fogNum;
+ shader_t *shader;
+ skin_t *skin;
+
+ data = (iqmData_t*)tr.currentModel->modelData;
+ surface = data->surfaces;
+
+ // don't add third_person objects if not in a portal
+ personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
+
+ if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
+ ent->e.frame %= data->num_frames;
+ ent->e.oldframe %= data->num_frames;
+ }
+
+ //
+ // Validate the frames so there is no chance of a crash.
+ // This will write directly into the entity structure, so
+ // when the surfaces are rendered, they don't need to be
+ // range checked again.
+ //
+ if ( (ent->e.frame >= data->num_frames)
+ || (ent->e.frame < 0)
+ || (ent->e.oldframe >= data->num_frames)
+ || (ent->e.oldframe < 0) ) {
+ ri.Printf( PRINT_DEVELOPER, "R_AddIQMSurfaces: no such frame %d to %d for '%s'\n",
+ ent->e.oldframe, ent->e.frame,
+ tr.currentModel->name );
+ ent->e.frame = 0;
+ ent->e.oldframe = 0;
+ }
+
+ //
+ // cull the entire model if merged bounding box of both frames
+ // is outside the view frustum.
+ //
+ cull = R_CullIQM ( data, ent );
+ if ( cull == CULL_OUT ) {
+ return;
+ }
+
+ //
+ // set up lighting now that we know we aren't culled
+ //
+ if ( !personalModel || r_shadows->integer > 1 ) {
+ R_SetupEntityLighting( &tr.refdef, ent );
+ }
+
+ //
+ // see if we are in a fog volume
+ //
+ fogNum = R_ComputeIQMFogNum( data, ent );
+
+ for ( i = 0 ; i < data->num_surfaces ; i++ ) {
+ if(ent->e.customShader)
+ shader = R_GetShaderByHandle( ent->e.customShader );
+ else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins)
+ {
+ skin = R_GetSkinByHandle(ent->e.customSkin);
+ shader = tr.defaultShader;
+
+ for(j = 0; j < skin->numSurfaces; j++)
+ {
+ if (!strcmp(skin->surfaces[j].name, surface->name))
+ {
+ shader = skin->surfaces[j].shader;
+ break;
+ }
+ }
+ } else {
+ shader = surface->shader;
+ }
+
+ // we will add shadows even if the main object isn't visible in the view
+
+ // stencil shadows can't do personal models unless I polyhedron clip
+ if ( !personalModel
+ && r_shadows->integer == 2
+ && fogNum == 0
+ && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
+ && shader->sort == SS_OPAQUE ) {
+ R_AddDrawSurf( (surfaceType_t*)surface, tr.shadowShader, 0, 0 );
+ }
+
+ // projection shadows work fine with personal models
+ if ( r_shadows->integer == 3
+ && fogNum == 0
+ && (ent->e.renderfx & RF_SHADOW_PLANE )
+ && shader->sort == SS_OPAQUE ) {
+ R_AddDrawSurf( (surfaceType_t*)surface, tr.projectionShadowShader, 0, 0 );
+ }
+
+ if( !personalModel ) {
+ R_AddDrawSurf( (surfaceType_t*)surface, shader, fogNum, 0 );
+ }
+
+ surface++;
+ }
+}
+
+
+static void ComputePoseMats( iqmData_t *data, int frame, int oldframe,
+ float backlerp, float *mat ) {
+ float *mat1, *mat2;
+ int *joint = data->jointParents;
+ int i;
+
+ if ( data->num_poses == 0 ) {
+ for( i = 0; i < data->num_joints; i++, joint++ ) {
+ if( *joint >= 0 ) {
+ Matrix34Multiply( mat + 12 * *joint,
+ identityMatrix, mat + 12*i );
+ } else {
+ Com_Memcpy( mat + 12*i, identityMatrix, 12 * sizeof(float) );
+ }
+ }
+ return;
+ }
+
+ if ( oldframe == frame ) {
+ mat1 = data->poseMats + 12 * data->num_poses * frame;
+ for( i = 0; i < data->num_poses; i++, joint++ ) {
+ if( *joint >= 0 ) {
+ Matrix34Multiply( mat + 12 * *joint,
+ mat1 + 12*i, mat + 12*i );
+ } else {
+ Com_Memcpy( mat + 12*i, mat1 + 12*i, 12 * sizeof(float) );
+ }
+ }
+ } else {
+ mat1 = data->poseMats + 12 * data->num_poses * frame;
+ mat2 = data->poseMats + 12 * data->num_poses * oldframe;
+
+ for( i = 0; i < data->num_poses; i++, joint++ ) {
+ if( *joint >= 0 ) {
+ float tmpMat[12];
+ InterpolateMatrix( mat1 + 12*i, mat2 + 12*i,
+ backlerp, tmpMat );
+ Matrix34Multiply( mat + 12 * *joint,
+ tmpMat, mat + 12*i );
+
+ } else {
+ InterpolateMatrix( mat1 + 12*i, mat2 + 12*i,
+ backlerp, mat );
+ }
+ }
+ }
+}
+
+static void ComputeJointMats( iqmData_t *data, int frame, int oldframe,
+ float backlerp, float *mat ) {
+ float *mat1;
+ int i;
+
+ ComputePoseMats( data, frame, oldframe, backlerp, mat );
+
+ for( i = 0; i < data->num_joints; i++ ) {
+ float outmat[12];
+ mat1 = mat + 12 * i;
+
+ Com_Memcpy(outmat, mat1, sizeof(outmat));
+
+ Matrix34Multiply_OnlySetOrigin( outmat, data->jointMats + 12 * i, mat1 );
+ }
+}
+
+
+/*
+=================
+RB_AddIQMSurfaces
+
+Compute vertices for this model surface
+=================
+*/
+void RB_IQMSurfaceAnim( surfaceType_t *surface ) {
+ srfIQModel_t *surf = (srfIQModel_t *)surface;
+ iqmData_t *data = surf->data;
+ float jointMats[IQM_MAX_JOINTS * 12];
+ int i;
+
+ vec4_t *outXYZ;
+ vec4_t *outNormal;
+ vec2_t (*outTexCoord)[2];
+ color4ub_t *outColor;
+
+ int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0;
+ int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0;
+ float backlerp = backEnd.currentEntity->e.backlerp;
+
+ int *tri;
+ glIndex_t *ptr;
+ glIndex_t base;
+
+ RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 );
+
+ outXYZ = &tess.xyz[tess.numVertexes];
+ outNormal = &tess.normal[tess.numVertexes];
+ outTexCoord = &tess.texCoords[tess.numVertexes];
+ outColor = &tess.vertexColors[tess.numVertexes];
+
+ // compute interpolated joint matrices
+ if ( data->num_poses > 0 ) {
+ ComputePoseMats( data, frame, oldframe, backlerp, jointMats );
+ }
+
+ // transform vertexes and fill other data
+ for( i = 0; i < surf->num_vertexes;
+ i++, outXYZ++, outNormal++, outTexCoord++, outColor++ ) {
+ int j, k;
+ float vtxMat[12];
+ float nrmMat[9];
+ int vtx = i + surf->first_vertex;
+ float blendWeights[4];
+ int numWeights;
+
+ for ( numWeights = 0; numWeights < 4; numWeights++ ) {
+ if ( data->blendWeightsType == IQM_FLOAT )
+ blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights];
+ else
+ blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f;
+
+ if ( blendWeights[numWeights] <= 0 )
+ break;
+ }
+
+ if ( data->num_poses == 0 || numWeights == 0 ) {
+ // no blend joint, use identity matrix.
+ Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) );
+ } else {
+ // compute the vertex matrix by blending the up to
+ // four blend weights
+ Com_Memset( vtxMat, 0, 12 * sizeof (float) );
+ for( j = 0; j < numWeights; j++ ) {
+ for( k = 0; k < 12; k++ ) {
+ vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k];
+ }
+ }
+ }
+
+ // compute the normal matrix as transpose of the adjoint
+ // of the vertex matrix
+ nrmMat[ 0] = vtxMat[ 5]*vtxMat[10] - vtxMat[ 6]*vtxMat[ 9];
+ nrmMat[ 1] = vtxMat[ 6]*vtxMat[ 8] - vtxMat[ 4]*vtxMat[10];
+ nrmMat[ 2] = vtxMat[ 4]*vtxMat[ 9] - vtxMat[ 5]*vtxMat[ 8];
+ nrmMat[ 3] = vtxMat[ 2]*vtxMat[ 9] - vtxMat[ 1]*vtxMat[10];
+ nrmMat[ 4] = vtxMat[ 0]*vtxMat[10] - vtxMat[ 2]*vtxMat[ 8];
+ nrmMat[ 5] = vtxMat[ 1]*vtxMat[ 8] - vtxMat[ 0]*vtxMat[ 9];
+ nrmMat[ 6] = vtxMat[ 1]*vtxMat[ 6] - vtxMat[ 2]*vtxMat[ 5];
+ nrmMat[ 7] = vtxMat[ 2]*vtxMat[ 4] - vtxMat[ 0]*vtxMat[ 6];
+ nrmMat[ 8] = vtxMat[ 0]*vtxMat[ 5] - vtxMat[ 1]*vtxMat[ 4];
+
+ (*outTexCoord)[0][0] = data->texcoords[2*vtx + 0];
+ (*outTexCoord)[0][1] = data->texcoords[2*vtx + 1];
+ (*outTexCoord)[1][0] = (*outTexCoord)[0][0];
+ (*outTexCoord)[1][1] = (*outTexCoord)[0][1];
+
+ (*outXYZ)[0] =
+ vtxMat[ 0] * data->positions[3*vtx+0] +
+ vtxMat[ 1] * data->positions[3*vtx+1] +
+ vtxMat[ 2] * data->positions[3*vtx+2] +
+ vtxMat[ 3];
+ (*outXYZ)[1] =
+ vtxMat[ 4] * data->positions[3*vtx+0] +
+ vtxMat[ 5] * data->positions[3*vtx+1] +
+ vtxMat[ 6] * data->positions[3*vtx+2] +
+ vtxMat[ 7];
+ (*outXYZ)[2] =
+ vtxMat[ 8] * data->positions[3*vtx+0] +
+ vtxMat[ 9] * data->positions[3*vtx+1] +
+ vtxMat[10] * data->positions[3*vtx+2] +
+ vtxMat[11];
+ (*outXYZ)[3] = 1.0f;
+
+ (*outNormal)[0] =
+ nrmMat[ 0] * data->normals[3*vtx+0] +
+ nrmMat[ 1] * data->normals[3*vtx+1] +
+ nrmMat[ 2] * data->normals[3*vtx+2];
+ (*outNormal)[1] =
+ nrmMat[ 3] * data->normals[3*vtx+0] +
+ nrmMat[ 4] * data->normals[3*vtx+1] +
+ nrmMat[ 5] * data->normals[3*vtx+2];
+ (*outNormal)[2] =
+ nrmMat[ 6] * data->normals[3*vtx+0] +
+ nrmMat[ 7] * data->normals[3*vtx+1] +
+ nrmMat[ 8] * data->normals[3*vtx+2];
+ (*outNormal)[3] = 0.0f;
+
+ (*outColor)[0] = data->colors[4*vtx+0];
+ (*outColor)[1] = data->colors[4*vtx+1];
+ (*outColor)[2] = data->colors[4*vtx+2];
+ (*outColor)[3] = data->colors[4*vtx+3];
+ }
+
+ tri = data->triangles + 3 * surf->first_triangle;
+ ptr = &tess.indexes[tess.numIndexes];
+ base = tess.numVertexes;
+
+ for( i = 0; i < surf->num_triangles; i++ ) {
+ *ptr++ = base + (*tri++ - surf->first_vertex);
+ *ptr++ = base + (*tri++ - surf->first_vertex);
+ *ptr++ = base + (*tri++ - surf->first_vertex);
+ }
+
+ tess.numIndexes += 3 * surf->num_triangles;
+ tess.numVertexes += surf->num_vertexes;
+}
+
+int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
+ int startFrame, int endFrame,
+ float frac, const char *tagName ) {
+ float jointMats[IQM_MAX_JOINTS * 12];
+ int joint;
+ char *names = data->names;
+
+ // get joint number by reading the joint names
+ for( joint = 0; joint < data->num_joints; joint++ ) {
+ if( !strcmp( tagName, names ) )
+ break;
+ names += strlen( names ) + 1;
+ }
+ if( joint >= data->num_joints ) {
+ AxisClear( tag->axis );
+ VectorClear( tag->origin );
+ return false;
+ }
+
+ ComputeJointMats( data, startFrame, endFrame, frac, jointMats );
+
+ tag->axis[0][0] = jointMats[12 * joint + 0];
+ tag->axis[1][0] = jointMats[12 * joint + 1];
+ tag->axis[2][0] = jointMats[12 * joint + 2];
+ tag->origin[0] = jointMats[12 * joint + 3];
+ tag->axis[0][1] = jointMats[12 * joint + 4];
+ tag->axis[1][1] = jointMats[12 * joint + 5];
+ tag->axis[2][1] = jointMats[12 * joint + 6];
+ tag->origin[1] = jointMats[12 * joint + 7];
+ tag->axis[0][2] = jointMats[12 * joint + 8];
+ tag->axis[1][2] = jointMats[12 * joint + 9];
+ tag->axis[2][2] = jointMats[12 * joint + 10];
+ tag->origin[2] = jointMats[12 * joint + 11];
+
+ return true;
+}
diff --git a/src/renderergl1/tr_scene.cpp b/src/renderergl1/tr_scene.cpp
new file mode 100644
index 0000000..a6ed132
--- /dev/null
+++ b/src/renderergl1/tr_scene.cpp
@@ -0,0 +1,413 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+int r_firstSceneDrawSurf;
+
+int r_numdlights;
+int r_firstSceneDlight;
+
+int r_numentities;
+int r_firstSceneEntity;
+
+int r_numpolys;
+int r_firstScenePoly;
+
+int r_numpolyverts;
+
+
+/*
+====================
+R_InitNextFrame
+
+====================
+*/
+void R_InitNextFrame( void ) {
+ backEndData->commands.used = 0;
+
+ r_firstSceneDrawSurf = 0;
+
+ r_numdlights = 0;
+ r_firstSceneDlight = 0;
+
+ r_numentities = 0;
+ r_firstSceneEntity = 0;
+
+ r_numpolys = 0;
+ r_firstScenePoly = 0;
+
+ r_numpolyverts = 0;
+}
+
+
+/*
+====================
+RE_ClearScene
+
+====================
+*/
+void RE_ClearScene( void ) {
+ r_firstSceneDlight = r_numdlights;
+ r_firstSceneEntity = r_numentities;
+ r_firstScenePoly = r_numpolys;
+}
+
+/*
+===========================================================================
+
+DISCRETE POLYS
+
+===========================================================================
+*/
+
+/*
+=====================
+R_AddPolygonSurfaces
+
+Adds all the scene's polys into this view's drawsurf list
+=====================
+*/
+void R_AddPolygonSurfaces( void ) {
+ int i;
+ shader_t *sh;
+ srfPoly_t *poly;
+
+ tr.currentEntityNum = REFENTITYNUM_WORLD;
+ tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
+
+ for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {
+ sh = R_GetShaderByHandle( poly->hShader );
+ R_AddDrawSurf( (surfaceType_t*)poly, sh, poly->fogIndex, false );
+ }
+}
+
+/*
+=====================
+RE_AddPolyToScene
+
+=====================
+*/
+void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {
+ srfPoly_t *poly;
+ int i, j;
+ int fogIndex;
+ fog_t *fog;
+ vec3_t bounds[2];
+
+ if ( !tr.registered ) {
+ return;
+ }
+
+ if ( !hShader ) {
+ ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n");
+ return;
+ }
+
+ for ( j = 0; j < numPolys; j++ ) {
+ if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) {
+ /*
+ NOTE TTimo this was initially a PRINT_WARNING
+ but it happens a lot with high fighting scenes and particles
+ since we don't plan on changing the const and making for room for those effects
+ simply cut this message to developer only
+ */
+ ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n");
+ return;
+ }
+
+ poly = &backEndData->polys[r_numpolys];
+ poly->surfaceType = SF_POLY;
+ poly->hShader = hShader;
+ poly->numVerts = numVerts;
+ poly->verts = &backEndData->polyVerts[r_numpolyverts];
+
+ Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) );
+
+ if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
+ poly->verts->modulate[0] = 255;
+ poly->verts->modulate[1] = 255;
+ poly->verts->modulate[2] = 255;
+ poly->verts->modulate[3] = 255;
+ }
+ // done.
+ r_numpolys++;
+ r_numpolyverts += numVerts;
+
+ // if no world is loaded
+ if ( tr.world == NULL ) {
+ fogIndex = 0;
+ }
+ // see if it is in a fog volume
+ else if ( tr.world->numfogs == 1 ) {
+ fogIndex = 0;
+ } else {
+ // find which fog volume the poly is in
+ VectorCopy( poly->verts[0].xyz, bounds[0] );
+ VectorCopy( poly->verts[0].xyz, bounds[1] );
+ for ( i = 1 ; i < poly->numVerts ; i++ ) {
+ AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
+ }
+ for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
+ fog = &tr.world->fogs[fogIndex];
+ if ( bounds[1][0] >= fog->bounds[0][0]
+ && bounds[1][1] >= fog->bounds[0][1]
+ && bounds[1][2] >= fog->bounds[0][2]
+ && bounds[0][0] <= fog->bounds[1][0]
+ && bounds[0][1] <= fog->bounds[1][1]
+ && bounds[0][2] <= fog->bounds[1][2] ) {
+ break;
+ }
+ }
+ if ( fogIndex == tr.world->numfogs ) {
+ fogIndex = 0;
+ }
+ }
+ poly->fogIndex = fogIndex;
+ }
+}
+
+
+//=================================================================================
+
+
+/*
+=====================
+RE_AddRefEntityToScene
+
+=====================
+*/
+void RE_AddRefEntityToScene( const refEntity_t *ent ) {
+ if ( !tr.registered ) {
+ return;
+ }
+ if ( r_numentities >= MAX_REFENTITIES ) {
+ ri.Printf(PRINT_DEVELOPER, "RE_AddRefEntityToScene: Dropping refEntity, reached MAX_REFENTITIES\n");
+ return;
+ }
+ if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
+ static bool firstTime = true;
+ if (firstTime) {
+ firstTime = false;
+ ri.Printf( PRINT_WARNING, "RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n");
+ }
+ return;
+ }
+ if ( (int)ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
+ ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
+ }
+
+ backEndData->entities[r_numentities].e = *ent;
+ backEndData->entities[r_numentities].lightingCalculated = false;
+
+ r_numentities++;
+}
+
+
+/*
+=====================
+RE_AddDynamicLightToScene
+
+=====================
+*/
+void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) {
+ dlight_t *dl;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ if ( r_numdlights >= MAX_DLIGHTS ) {
+ return;
+ }
+ if ( intensity <= 0 ) {
+ return;
+ }
+ // these cards don't have the correct blend mode
+ if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
+ return;
+ }
+ dl = &backEndData->dlights[r_numdlights++];
+ VectorCopy (org, dl->origin);
+ dl->radius = intensity;
+ dl->color[0] = r;
+ dl->color[1] = g;
+ dl->color[2] = b;
+ dl->additive = additive;
+}
+
+/*
+=====================
+RE_AddLightToScene
+
+=====================
+*/
+void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
+ RE_AddDynamicLightToScene( org, intensity, r, g, b, false );
+}
+
+/*
+=====================
+RE_AddAdditiveLightToScene
+
+=====================
+*/
+void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
+ RE_AddDynamicLightToScene( org, intensity, r, g, b, true );
+}
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+RE_RenderScene
+
+Draw a 3D view into a part of the window, then return
+to 2D drawing.
+
+Rendering a scene may require multiple views to be rendered
+to handle mirrors,
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void RE_RenderScene( const refdef_t *fd ) {
+ viewParms_t parms;
+ int startTime;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ GLimp_LogComment( "====== RE_RenderScene =====\n" );
+
+ if ( r_norefresh->integer ) {
+ return;
+ }
+
+ startTime = ri.Milliseconds();
+
+ if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
+ ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
+ }
+
+ Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
+
+ tr.refdef.x = fd->x;
+ tr.refdef.y = fd->y;
+ tr.refdef.width = fd->width;
+ tr.refdef.height = fd->height;
+ tr.refdef.fov_x = fd->fov_x;
+ tr.refdef.fov_y = fd->fov_y;
+
+ VectorCopy( fd->vieworg, tr.refdef.vieworg );
+ VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );
+ VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );
+ VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
+
+ tr.refdef.time = fd->time;
+ tr.refdef.rdflags = fd->rdflags;
+
+ // copy the areamask data over and note if it has changed, which
+ // will force a reset of the visible leafs even if the view hasn't moved
+ tr.refdef.areamaskModified = false;
+ if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) {
+ int areaDiff;
+ int i;
+
+ // compare the area bits
+ areaDiff = 0;
+ for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) {
+ areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i];
+ ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i];
+ }
+
+ if ( areaDiff ) {
+ // a door just opened or something
+ tr.refdef.areamaskModified = true;
+ }
+ }
+
+
+ // derived info
+
+ tr.refdef.floatTime = tr.refdef.time * 0.001;
+
+ tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
+ tr.refdef.drawSurfs = backEndData->drawSurfs;
+
+ tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
+ tr.refdef.entities = &backEndData->entities[r_firstSceneEntity];
+
+ tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
+ tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight];
+
+ tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
+ tr.refdef.polys = &backEndData->polys[r_firstScenePoly];
+
+ // turn off dynamic lighting globally by clearing all the
+ // dlights if it needs to be disabled or if vertex lighting is enabled
+ if ( r_dynamiclight->integer == 0 ||
+ r_vertexLight->integer == 1 ||
+ glConfig.hardwareType == GLHW_PERMEDIA2 ) {
+ tr.refdef.num_dlights = 0;
+ }
+
+ // a single frame may have multiple scenes draw inside it --
+ // a 3D game view, 3D status bar renderings, 3D menus, etc.
+ // They need to be distinguished by the light flare code, because
+ // the visibility state for a given surface may be different in
+ // each scene / view.
+ tr.frameSceneNum++;
+ tr.sceneCount++;
+
+ // setup view parms for the initial view
+ //
+ // set up viewport
+ // The refdef takes 0-at-the-top y coordinates, so
+ // convert to GL's 0-at-the-bottom space
+ //
+ Com_Memset( &parms, 0, sizeof( parms ) );
+ parms.viewportX = tr.refdef.x;
+ parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
+ parms.viewportWidth = tr.refdef.width;
+ parms.viewportHeight = tr.refdef.height;
+ parms.isPortal = false;
+
+ parms.fovX = tr.refdef.fov_x;
+ parms.fovY = tr.refdef.fov_y;
+
+ parms.stereoFrame = tr.refdef.stereoFrame;
+
+ VectorCopy( fd->vieworg, parms.orientation.origin );
+ VectorCopy( fd->viewaxis[0], parms.orientation.axis[0] );
+ VectorCopy( fd->viewaxis[1], parms.orientation.axis[1] );
+ VectorCopy( fd->viewaxis[2], parms.orientation.axis[2] );
+
+ VectorCopy( fd->vieworg, parms.pvsOrigin );
+
+ R_RenderView( &parms );
+
+ // the next scene rendered in this frame will tack on after this one
+ r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
+ r_firstSceneEntity = r_numentities;
+ r_firstSceneDlight = r_numdlights;
+ r_firstScenePoly = r_numpolys;
+
+ tr.frontEndMsec += ri.Milliseconds() - startTime;
+}
diff --git a/src/renderergl1/tr_shade.cpp b/src/renderergl1/tr_shade.cpp
new file mode 100644
index 0000000..a4139eb
--- /dev/null
+++ b/src/renderergl1/tr_shade.cpp
@@ -0,0 +1,1522 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_shade.c
+
+#include "tr_local.h"
+#if idppc_altivec && !defined(__APPLE__)
+#include <altivec.h>
+#endif
+
+/*
+
+ THIS ENTIRE FILE IS BACK END
+
+ This file deals with applying shaders to surface data in the tess struct.
+*/
+
+/*
+================
+R_ArrayElementDiscrete
+
+This is just for OpenGL conformance testing, it should never be the fastest
+================
+*/
+static void APIENTRY R_ArrayElementDiscrete( GLint index ) {
+ qglColor4ubv( tess.svars.colors[ index ] );
+ if ( glState.currenttmu ) {
+ qglMultiTexCoord2fARB( 0, tess.svars.texcoords[ 0 ][ index ][0], tess.svars.texcoords[ 0 ][ index ][1] );
+ qglMultiTexCoord2fARB( 1, tess.svars.texcoords[ 1 ][ index ][0], tess.svars.texcoords[ 1 ][ index ][1] );
+ } else {
+ qglTexCoord2fv( tess.svars.texcoords[ 0 ][ index ] );
+ }
+ qglVertex3fv( tess.xyz[ index ] );
+}
+
+/*
+===================
+R_DrawStripElements
+
+===================
+*/
+static int c_vertexes; // for seeing how long our average strips are
+static int c_begins;
+static void R_DrawStripElements( int numIndexes, const glIndex_t *indexes, void ( APIENTRY *element )(GLint) ) {
+ int i;
+ int last[3] = { -1, -1, -1 };
+ bool even;
+
+ c_begins++;
+
+ if ( numIndexes <= 0 ) {
+ return;
+ }
+
+ qglBegin( GL_TRIANGLE_STRIP );
+
+ // prime the strip
+ element( indexes[0] );
+ element( indexes[1] );
+ element( indexes[2] );
+ c_vertexes += 3;
+
+ last[0] = indexes[0];
+ last[1] = indexes[1];
+ last[2] = indexes[2];
+
+ even = false;
+
+ for ( i = 3; i < numIndexes; i += 3 )
+ {
+ // odd numbered triangle in potential strip
+ if ( !even )
+ {
+ // check previous triangle to see if we're continuing a strip
+ if ( ( indexes[i+0] == last[2] ) && ( indexes[i+1] == last[1] ) )
+ {
+ element( indexes[i+2] );
+ c_vertexes++;
+ assert( indexes[i+2] < tess.numVertexes );
+ even = true;
+ }
+ // otherwise we're done with this strip so finish it and start
+ // a new one
+ else
+ {
+ qglEnd();
+
+ qglBegin( GL_TRIANGLE_STRIP );
+ c_begins++;
+
+ element( indexes[i+0] );
+ element( indexes[i+1] );
+ element( indexes[i+2] );
+
+ c_vertexes += 3;
+
+ even = false;
+ }
+ }
+ else
+ {
+ // check previous triangle to see if we're continuing a strip
+ if ( ( last[2] == indexes[i+1] ) && ( last[0] == indexes[i+0] ) )
+ {
+ element( indexes[i+2] );
+ c_vertexes++;
+
+ even = false;
+ }
+ // otherwise we're done with this strip so finish it and start
+ // a new one
+ else
+ {
+ qglEnd();
+
+ qglBegin( GL_TRIANGLE_STRIP );
+ c_begins++;
+
+ element( indexes[i+0] );
+ element( indexes[i+1] );
+ element( indexes[i+2] );
+ c_vertexes += 3;
+
+ even = false;
+ }
+ }
+
+ // cache the last three vertices
+ last[0] = indexes[i+0];
+ last[1] = indexes[i+1];
+ last[2] = indexes[i+2];
+ }
+
+ qglEnd();
+}
+
+
+
+/*
+==================
+R_DrawElements
+
+Optionally performs our own glDrawElements that looks for strip conditions
+instead of using the single glDrawElements call that may be inefficient
+without compiled vertex arrays.
+==================
+*/
+static void R_DrawElements( int numIndexes, const glIndex_t *indexes ) {
+ int primitives;
+
+ primitives = r_primitives->integer;
+
+ // default is to use triangles if compiled vertex arrays are present
+ if ( primitives == 0 ) {
+ if ( qglLockArraysEXT ) {
+ primitives = 2;
+ } else {
+ primitives = 1;
+ }
+ }
+
+
+ if ( primitives == 2 ) {
+ qglDrawElements( GL_TRIANGLES,
+ numIndexes,
+ GL_INDEX_TYPE,
+ indexes );
+ return;
+ }
+
+ if ( primitives == 1 ) {
+ R_DrawStripElements( numIndexes, indexes, qglArrayElement );
+ return;
+ }
+
+ if ( primitives == 3 ) {
+ R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete );
+ return;
+ }
+
+ // anything else will cause no drawing
+}
+
+
+/*
+=============================================================
+
+SURFACE SHADERS
+
+=============================================================
+*/
+
+shaderCommands_t tess;
+static bool setArraysOnce;
+
+/*
+=================
+R_BindAnimatedImage
+
+=================
+*/
+static void R_BindAnimatedImage( textureBundle_t *bundle ) {
+
+ if ( bundle->isVideoMap ) {
+ ri.CIN_RunCinematic(bundle->videoMapHandle);
+ ri.CIN_UploadCinematic(bundle->videoMapHandle);
+ return;
+ }
+
+ if ( bundle->numImageAnimations <= 1 ) {
+ GL_Bind( bundle->image[0] );
+ return;
+ }
+
+ // it is necessary to do this messy calc to make sure animations line up
+ // exactly with waveforms of the same frequency
+ int i = static_cast<int>(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE) >> FUNCTABLE_SIZE2;
+ if ( i < 0 )
+ {
+ i = 0; // may happen with shader time offsets
+ }
+ i %= bundle->numImageAnimations;
+
+ GL_Bind( bundle->image[ i ] );
+}
+
+/*
+================
+DrawTris
+
+Draws triangle outlines for debugging
+================
+*/
+static void DrawTris (shaderCommands_t *input) {
+ GL_Bind( tr.whiteImage );
+ qglColor3f (1,1,1);
+
+ GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
+ qglDepthRange( 0, 0 );
+
+ qglDisableClientState (GL_COLOR_ARRAY);
+ qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD
+
+ if (qglLockArraysEXT) {
+ qglLockArraysEXT(0, input->numVertexes);
+ GLimp_LogComment( "glLockArraysEXT\n" );
+ }
+
+ R_DrawElements( input->numIndexes, input->indexes );
+
+ if (qglUnlockArraysEXT) {
+ qglUnlockArraysEXT();
+ GLimp_LogComment( "glUnlockArraysEXT\n" );
+ }
+ qglDepthRange( 0, 1 );
+}
+
+
+/*
+================
+DrawNormals
+
+Draws vertex normals for debugging
+================
+*/
+static void DrawNormals (shaderCommands_t *input) {
+ int i;
+ vec3_t temp;
+
+ GL_Bind( tr.whiteImage );
+ qglColor3f (1,1,1);
+ qglDepthRange( 0, 0 ); // never occluded
+ GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
+
+ qglBegin (GL_LINES);
+ for (i = 0 ; i < input->numVertexes ; i++) {
+ qglVertex3fv (input->xyz[i]);
+ VectorMA (input->xyz[i], 2, input->normal[i], temp);
+ qglVertex3fv (temp);
+ }
+ qglEnd ();
+
+ qglDepthRange( 0, 1 );
+}
+
+/*
+==============
+RB_BeginSurface
+
+We must set some things up before beginning any tesselation,
+because a surface may be forced to perform a RB_End due
+to overflow.
+==============
+*/
+void RB_BeginSurface( shader_t *shader, int fogNum ) {
+
+ shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader;
+
+ tess.numIndexes = 0;
+ tess.numVertexes = 0;
+ tess.shader = state;
+ tess.fogNum = fogNum;
+ tess.dlightBits = 0; // will be OR'd in by surface functions
+ tess.xstages = state->stages;
+ tess.numPasses = state->numUnfoggedPasses;
+ tess.currentStageIteratorFunc = state->optimalStageIteratorFunc;
+
+ tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
+ if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) {
+ tess.shaderTime = tess.shader->clampTime;
+ }
+
+
+}
+
+/*
+===================
+DrawMultitextured
+
+output = t0 * t1 or t0 + t1
+
+t0 = most upstream according to spec
+t1 = most downstream according to spec
+===================
+*/
+static void DrawMultitextured( shaderCommands_t *input, int stage ) {
+ shaderStage_t *pStage;
+
+ pStage = tess.xstages[stage];
+
+ GL_State( pStage->stateBits );
+
+ // this is an ugly hack to work around a GeForce driver
+ // bug with multitexture and clip planes
+ if ( backEnd.viewParms.isPortal ) {
+ qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+ }
+
+ //
+ // base
+ //
+ GL_SelectTexture( 0 );
+ qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
+ R_BindAnimatedImage( &pStage->bundle[0] );
+
+ //
+ // lightmap/secondary pass
+ //
+ GL_SelectTexture( 1 );
+ qglEnable( GL_TEXTURE_2D );
+ qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
+
+ if ( r_lightmap->integer ) {
+ GL_TexEnv( GL_REPLACE );
+ } else {
+ GL_TexEnv( tess.shader->multitextureEnv );
+ }
+
+ qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[1] );
+
+ R_BindAnimatedImage( &pStage->bundle[1] );
+
+ R_DrawElements( input->numIndexes, input->indexes );
+
+ //
+ // disable texturing on TEXTURE1, then select TEXTURE0
+ //
+ //qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
+ qglDisable( GL_TEXTURE_2D );
+
+ GL_SelectTexture( 0 );
+}
+
+
+
+/*
+===================
+ProjectDlightTexture
+
+Perform dynamic lighting with another rendering pass
+===================
+*/
+#if idppc_altivec
+static void ProjectDlightTexture_altivec( void ) {
+ int i, l;
+ vec_t origin0, origin1, origin2;
+ float texCoords0, texCoords1;
+ vector float floatColorVec0, floatColorVec1;
+ vector float modulateVec, colorVec, zero;
+ vector short colorShort;
+ vector signed int colorInt;
+ vector unsigned char floatColorVecPerm, modulatePerm, colorChar;
+ vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0xff);
+ float *texCoords;
+ byte *colors;
+ byte clipBits[SHADER_MAX_VERTEXES];
+ float texCoordsArray[SHADER_MAX_VERTEXES][2];
+ byte colorArray[SHADER_MAX_VERTEXES][4];
+ glIndex_t hitIndexes[SHADER_MAX_INDEXES];
+ int numIndexes;
+ float scale;
+ float radius;
+ vec3_t floatColor;
+ float modulate = 0.0f;
+
+ if ( !backEnd.refdef.num_dlights ) {
+ return;
+ }
+
+ // There has to be a better way to do this so that floatColor
+ // and/or modulate are already 16-byte aligned.
+ floatColorVecPerm = vec_lvsl(0,(float *)floatColor);
+ modulatePerm = vec_lvsl(0,(float *)&modulate);
+ modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0);
+ zero = (vector float)vec_splat_s8(0);
+
+ for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
+ dlight_t *dl;
+
+ if ( !( tess.dlightBits & ( 1 << l ) ) ) {
+ continue; // this surface definately doesn't have any of this light
+ }
+ texCoords = texCoordsArray[0];
+ colors = colorArray[0];
+
+ dl = &backEnd.refdef.dlights[l];
+ origin0 = dl->transformed[0];
+ origin1 = dl->transformed[1];
+ origin2 = dl->transformed[2];
+ radius = dl->radius;
+ scale = 1.0f / radius;
+
+ if(r_greyscale->integer)
+ {
+ float luminance;
+
+ luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f;
+ floatColor[0] = floatColor[1] = floatColor[2] = luminance;
+ }
+ else if(r_greyscale->value)
+ {
+ float luminance;
+
+ luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f;
+ floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value);
+ floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value);
+ floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value);
+ }
+ else
+ {
+ floatColor[0] = dl->color[0] * 255.0f;
+ floatColor[1] = dl->color[1] * 255.0f;
+ floatColor[2] = dl->color[2] * 255.0f;
+ }
+ floatColorVec0 = vec_ld(0, floatColor);
+ floatColorVec1 = vec_ld(11, floatColor);
+ floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm);
+ for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
+ int clip = 0;
+ vec_t dist0, dist1, dist2;
+
+ dist0 = origin0 - tess.xyz[i][0];
+ dist1 = origin1 - tess.xyz[i][1];
+ dist2 = origin2 - tess.xyz[i][2];
+
+ backEnd.pc.c_dlightVertexes++;
+
+ texCoords0 = 0.5f + dist0 * scale;
+ texCoords1 = 0.5f + dist1 * scale;
+
+ if( !r_dlightBacks->integer &&
+ // dist . tess.normal[i]
+ ( dist0 * tess.normal[i][0] +
+ dist1 * tess.normal[i][1] +
+ dist2 * tess.normal[i][2] ) < 0.0f ) {
+ clip = 63;
+ } else {
+ if ( texCoords0 < 0.0f ) {
+ clip |= 1;
+ } else if ( texCoords0 > 1.0f ) {
+ clip |= 2;
+ }
+ if ( texCoords1 < 0.0f ) {
+ clip |= 4;
+ } else if ( texCoords1 > 1.0f ) {
+ clip |= 8;
+ }
+ texCoords[0] = texCoords0;
+ texCoords[1] = texCoords1;
+
+ // modulate the strength based on the height and color
+ if ( dist2 > radius ) {
+ clip |= 16;
+ modulate = 0.0f;
+ } else if ( dist2 < -radius ) {
+ clip |= 32;
+ modulate = 0.0f;
+ } else {
+ dist2 = Q_fabs(dist2);
+ if ( dist2 < radius * 0.5f ) {
+ modulate = 1.0f;
+ } else {
+ modulate = 2.0f * (radius - dist2) * scale;
+ }
+ }
+ }
+ clipBits[i] = clip;
+
+ modulateVec = vec_ld(0,(float *)&modulate);
+ modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm);
+ colorVec = vec_madd(floatColorVec0,modulateVec,zero);
+ colorInt = vec_cts(colorVec,0); // RGBx
+ colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx
+ colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx
+ colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255
+ vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color
+ }
+
+ // build a list of triangles that need light
+ numIndexes = 0;
+ for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
+ int a, b, c;
+
+ a = tess.indexes[i];
+ b = tess.indexes[i+1];
+ c = tess.indexes[i+2];
+ if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
+ continue; // not lighted
+ }
+ hitIndexes[numIndexes] = a;
+ hitIndexes[numIndexes+1] = b;
+ hitIndexes[numIndexes+2] = c;
+ numIndexes += 3;
+ }
+
+ if ( !numIndexes ) {
+ continue;
+ }
+
+ qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
+
+ qglEnableClientState( GL_COLOR_ARRAY );
+ qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );
+
+ GL_Bind( tr.dlightImage );
+ // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
+ // where they aren't rendered
+ if ( dl->additive ) {
+ GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
+ }
+ else {
+ GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
+ }
+ R_DrawElements( numIndexes, hitIndexes );
+ backEnd.pc.c_totalIndexes += numIndexes;
+ backEnd.pc.c_dlightIndexes += numIndexes;
+ }
+}
+#endif
+
+
+static void ProjectDlightTexture_scalar( void ) {
+ int i, l;
+ vec3_t origin;
+ float *texCoords;
+ byte *colors;
+ byte clipBits[SHADER_MAX_VERTEXES];
+ float texCoordsArray[SHADER_MAX_VERTEXES][2];
+ byte colorArray[SHADER_MAX_VERTEXES][4];
+ glIndex_t hitIndexes[SHADER_MAX_INDEXES];
+ int numIndexes;
+ float scale;
+ float radius;
+ vec3_t floatColor;
+ float modulate = 0.0f;
+
+ if ( !backEnd.refdef.num_dlights ) {
+ return;
+ }
+
+ for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
+ dlight_t *dl;
+
+ if ( !( tess.dlightBits & ( 1 << l ) ) ) {
+ continue; // this surface definately doesn't have any of this light
+ }
+ texCoords = texCoordsArray[0];
+ colors = colorArray[0];
+
+ dl = &backEnd.refdef.dlights[l];
+ VectorCopy( dl->transformed, origin );
+ radius = dl->radius;
+ scale = 1.0f / radius;
+
+ if(r_greyscale->integer)
+ {
+ float luminance;
+
+ luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f;
+ floatColor[0] = floatColor[1] = floatColor[2] = luminance;
+ }
+ else if(r_greyscale->value)
+ {
+ float luminance;
+
+ luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f;
+ floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value);
+ floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value);
+ floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value);
+ }
+ else
+ {
+ floatColor[0] = dl->color[0] * 255.0f;
+ floatColor[1] = dl->color[1] * 255.0f;
+ floatColor[2] = dl->color[2] * 255.0f;
+ }
+
+ for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
+ int clip = 0;
+ vec3_t dist;
+
+ VectorSubtract( origin, tess.xyz[i], dist );
+
+ backEnd.pc.c_dlightVertexes++;
+
+ texCoords[0] = 0.5f + dist[0] * scale;
+ texCoords[1] = 0.5f + dist[1] * scale;
+
+ if( !r_dlightBacks->integer &&
+ // dist . tess.normal[i]
+ ( dist[0] * tess.normal[i][0] +
+ dist[1] * tess.normal[i][1] +
+ dist[2] * tess.normal[i][2] ) < 0.0f ) {
+ clip = 63;
+ } else {
+ if ( texCoords[0] < 0.0f ) {
+ clip |= 1;
+ } else if ( texCoords[0] > 1.0f ) {
+ clip |= 2;
+ }
+ if ( texCoords[1] < 0.0f ) {
+ clip |= 4;
+ } else if ( texCoords[1] > 1.0f ) {
+ clip |= 8;
+ }
+ texCoords[0] = texCoords[0];
+ texCoords[1] = texCoords[1];
+
+ // modulate the strength based on the height and color
+ if ( dist[2] > radius ) {
+ clip |= 16;
+ modulate = 0.0f;
+ } else if ( dist[2] < -radius ) {
+ clip |= 32;
+ modulate = 0.0f;
+ } else {
+ dist[2] = Q_fabs(dist[2]);
+ if ( dist[2] < radius * 0.5f ) {
+ modulate = 1.0f;
+ } else {
+ modulate = 2.0f * (radius - dist[2]) * scale;
+ }
+ }
+ }
+ clipBits[i] = clip;
+ colors[0] = static_cast<int>(floatColor[0] * modulate);
+ colors[1] = static_cast<int>(floatColor[1] * modulate);
+ colors[2] = static_cast<int>(floatColor[2] * modulate);
+ colors[3] = 255;
+ }
+
+ // build a list of triangles that need light
+ numIndexes = 0;
+ for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
+ int a, b, c;
+
+ a = tess.indexes[i];
+ b = tess.indexes[i+1];
+ c = tess.indexes[i+2];
+ if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
+ continue; // not lighted
+ }
+ hitIndexes[numIndexes] = a;
+ hitIndexes[numIndexes+1] = b;
+ hitIndexes[numIndexes+2] = c;
+ numIndexes += 3;
+ }
+
+ if ( !numIndexes ) {
+ continue;
+ }
+
+ qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
+
+ qglEnableClientState( GL_COLOR_ARRAY );
+ qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );
+
+ GL_Bind( tr.dlightImage );
+ // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
+ // where they aren't rendered
+ if ( dl->additive ) {
+ GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
+ }
+ else {
+ GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
+ }
+ R_DrawElements( numIndexes, hitIndexes );
+ backEnd.pc.c_totalIndexes += numIndexes;
+ backEnd.pc.c_dlightIndexes += numIndexes;
+ }
+}
+
+static void ProjectDlightTexture( void ) {
+#if idppc_altivec
+ if (com_altivec->integer) {
+ // must be in a seperate function or G3 systems will crash.
+ ProjectDlightTexture_altivec();
+ return;
+ }
+#endif
+ ProjectDlightTexture_scalar();
+}
+
+
+/*
+===================
+RB_FogPass
+
+Blends a fog texture on top of everything else
+===================
+*/
+static void RB_FogPass( void ) {
+ fog_t *fog;
+ int i;
+
+ qglEnableClientState( GL_COLOR_ARRAY );
+ qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
+
+ qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
+ qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );
+
+ fog = tr.world->fogs + tess.fogNum;
+
+ for ( i = 0; i < tess.numVertexes; i++ ) {
+ * ( int * )&tess.svars.colors[i] = fog->colorInt;
+ }
+
+ RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] );
+
+ GL_Bind( tr.fogImage );
+
+ if ( tess.shader->fogPass == FP_EQUAL ) {
+ GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
+ } else {
+ GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
+ }
+
+ R_DrawElements( tess.numIndexes, tess.indexes );
+}
+
+/*
+===============
+ComputeColors
+===============
+*/
+static void ComputeColors( shaderStage_t *pStage )
+{
+ int i;
+
+ //
+ // rgbGen
+ //
+ switch ( pStage->rgbGen )
+ {
+ case CGEN_IDENTITY:
+ Com_Memset( tess.svars.colors, 0xff, tess.numVertexes * 4 );
+ break;
+ default:
+ case CGEN_IDENTITY_LIGHTING:
+ Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 );
+ break;
+ case CGEN_LIGHTING_DIFFUSE:
+ RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors );
+ break;
+ case CGEN_EXACT_VERTEX:
+ Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );
+ break;
+ case CGEN_CONST:
+ for ( i = 0; i < tess.numVertexes; i++ ) {
+ *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor;
+ }
+ break;
+ case CGEN_VERTEX:
+ if ( tr.identityLight == 1 )
+ {
+ Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );
+ }
+ else
+ {
+ for ( i = 0; i < tess.numVertexes; i++ )
+ {
+ tess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight;
+ tess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight;
+ tess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight;
+ tess.svars.colors[i][3] = tess.vertexColors[i][3];
+ }
+ }
+ break;
+ case CGEN_ONE_MINUS_VERTEX:
+ if ( tr.identityLight == 1 )
+ {
+ for ( i = 0; i < tess.numVertexes; i++ )
+ {
+ tess.svars.colors[i][0] = 255 - tess.vertexColors[i][0];
+ tess.svars.colors[i][1] = 255 - tess.vertexColors[i][1];
+ tess.svars.colors[i][2] = 255 - tess.vertexColors[i][2];
+ }
+ }
+ else
+ {
+ for ( i = 0; i < tess.numVertexes; i++ )
+ {
+ tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight;
+ tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight;
+ tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight;
+ }
+ }
+ break;
+ case CGEN_FOG:
+ {
+ fog_t *fog;
+
+ fog = tr.world->fogs + tess.fogNum;
+
+ for ( i = 0; i < tess.numVertexes; i++ ) {
+ * ( int * )&tess.svars.colors[i] = fog->colorInt;
+ }
+ }
+ break;
+ case CGEN_WAVEFORM:
+ RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors );
+ break;
+ case CGEN_ENTITY:
+ RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors );
+ break;
+ case CGEN_ONE_MINUS_ENTITY:
+ RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );
+ break;
+ }
+
+ //
+ // alphaGen
+ //
+ switch ( pStage->alphaGen )
+ {
+ case AGEN_SKIP:
+ break;
+ case AGEN_IDENTITY:
+ if ( pStage->rgbGen != CGEN_IDENTITY ) {
+ if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) ||
+ pStage->rgbGen != CGEN_VERTEX ) {
+ for ( i = 0; i < tess.numVertexes; i++ ) {
+ tess.svars.colors[i][3] = 0xff;
+ }
+ }
+ }
+ break;
+ case AGEN_CONST:
+ if ( pStage->rgbGen != CGEN_CONST ) {
+ for ( i = 0; i < tess.numVertexes; i++ ) {
+ tess.svars.colors[i][3] = pStage->constantColor[3];
+ }
+ }
+ break;
+ case AGEN_WAVEFORM:
+ RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors );
+ break;
+ case AGEN_LIGHTING_SPECULAR:
+ RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors );
+ break;
+ case AGEN_ENTITY:
+ RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors );
+ break;
+ case AGEN_ONE_MINUS_ENTITY:
+ RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );
+ break;
+ case AGEN_VERTEX:
+ if ( pStage->rgbGen != CGEN_VERTEX ) {
+ for ( i = 0; i < tess.numVertexes; i++ ) {
+ tess.svars.colors[i][3] = tess.vertexColors[i][3];
+ }
+ }
+ break;
+ case AGEN_ONE_MINUS_VERTEX:
+ for ( i = 0; i < tess.numVertexes; i++ )
+ {
+ tess.svars.colors[i][3] = 255 - tess.vertexColors[i][3];
+ }
+ break;
+ case AGEN_PORTAL:
+ {
+ unsigned char alpha;
+
+ for ( i = 0; i < tess.numVertexes; i++ )
+ {
+ float len;
+ vec3_t v;
+
+ VectorSubtract( tess.xyz[i], backEnd.viewParms.orientation.origin, v );
+ len = VectorLength( v );
+
+ len /= tess.shader->portalRange;
+
+ if ( len < 0 )
+ {
+ alpha = 0;
+ }
+ else if ( len > 1 )
+ {
+ alpha = 0xff;
+ }
+ else
+ {
+ alpha = len * 0xff;
+ }
+
+ tess.svars.colors[i][3] = alpha;
+ }
+ }
+ break;
+ }
+
+ //
+ // fog adjustment for colors to fade out as fog increases
+ //
+ if ( tess.fogNum )
+ {
+ switch ( pStage->adjustColorsForFog )
+ {
+ case ACFF_MODULATE_RGB:
+ RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors );
+ break;
+ case ACFF_MODULATE_ALPHA:
+ RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors );
+ break;
+ case ACFF_MODULATE_RGBA:
+ RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors );
+ break;
+ case ACFF_NONE:
+ break;
+ }
+ }
+
+ // if in greyscale rendering mode turn all color values into greyscale.
+ if(r_greyscale->integer)
+ {
+ int scale;
+ for(i = 0; i < tess.numVertexes; i++)
+ {
+ scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]);
+ tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale;
+ }
+ }
+ else if(r_greyscale->value)
+ {
+ float scale;
+
+ for(i = 0; i < tess.numVertexes; i++)
+ {
+ scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]);
+ tess.svars.colors[i][0] = LERP(tess.svars.colors[i][0], scale, r_greyscale->value);
+ tess.svars.colors[i][1] = LERP(tess.svars.colors[i][1], scale, r_greyscale->value);
+ tess.svars.colors[i][2] = LERP(tess.svars.colors[i][2], scale, r_greyscale->value);
+ }
+ }
+}
+
+/*
+===============
+ComputeTexCoords
+===============
+*/
+static void ComputeTexCoords( shaderStage_t *pStage ) {
+ int i;
+ int b;
+
+ for ( b = 0; b < NUM_TEXTURE_BUNDLES; b++ ) {
+ int tm;
+
+ //
+ // generate the texture coordinates
+ //
+ switch ( pStage->bundle[b].tcGen )
+ {
+ case TCGEN_IDENTITY:
+ Com_Memset( tess.svars.texcoords[b], 0, sizeof( float ) * 2 * tess.numVertexes );
+ break;
+ case TCGEN_TEXTURE:
+ for ( i = 0 ; i < tess.numVertexes ; i++ ) {
+ tess.svars.texcoords[b][i][0] = tess.texCoords[i][0][0];
+ tess.svars.texcoords[b][i][1] = tess.texCoords[i][0][1];
+ }
+ break;
+ case TCGEN_LIGHTMAP:
+ for ( i = 0 ; i < tess.numVertexes ; i++ ) {
+ tess.svars.texcoords[b][i][0] = tess.texCoords[i][1][0];
+ tess.svars.texcoords[b][i][1] = tess.texCoords[i][1][1];
+ }
+ break;
+ case TCGEN_VECTOR:
+ for ( i = 0 ; i < tess.numVertexes ; i++ ) {
+ tess.svars.texcoords[b][i][0] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[0] );
+ tess.svars.texcoords[b][i][1] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[1] );
+ }
+ break;
+ case TCGEN_FOG:
+ RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[b] );
+ break;
+ case TCGEN_ENVIRONMENT_MAPPED:
+ RB_CalcEnvironmentTexCoords( ( float * ) tess.svars.texcoords[b] );
+ break;
+ case TCGEN_BAD:
+ return;
+ }
+
+ //
+ // alter texture coordinates
+ //
+ for ( tm = 0; tm < pStage->bundle[b].numTexMods ; tm++ ) {
+ switch ( pStage->bundle[b].texMods[tm].type )
+ {
+ case TMOD_NONE:
+ tm = TR_MAX_TEXMODS; // break out of for loop
+ break;
+
+ case TMOD_TURBULENT:
+ RB_CalcTurbulentTexCoords( &pStage->bundle[b].texMods[tm].wave,
+ ( float * ) tess.svars.texcoords[b] );
+ break;
+
+ case TMOD_ENTITY_TRANSLATE:
+ RB_CalcScrollTexCoords( backEnd.currentEntity->e.shaderTexCoord,
+ ( float * ) tess.svars.texcoords[b] );
+ break;
+
+ case TMOD_SCROLL:
+ RB_CalcScrollTexCoords( pStage->bundle[b].texMods[tm].scroll,
+ ( float * ) tess.svars.texcoords[b] );
+ break;
+
+ case TMOD_SCALE:
+ RB_CalcScaleTexCoords( pStage->bundle[b].texMods[tm].scale,
+ ( float * ) tess.svars.texcoords[b] );
+ break;
+
+ case TMOD_STRETCH:
+ RB_CalcStretchTexCoords( &pStage->bundle[b].texMods[tm].wave,
+ ( float * ) tess.svars.texcoords[b] );
+ break;
+
+ case TMOD_TRANSFORM:
+ RB_CalcTransformTexCoords( &pStage->bundle[b].texMods[tm],
+ ( float * ) tess.svars.texcoords[b] );
+ break;
+
+ case TMOD_ROTATE:
+ RB_CalcRotateTexCoords( pStage->bundle[b].texMods[tm].rotateSpeed,
+ ( float * ) tess.svars.texcoords[b] );
+ break;
+
+ default:
+ ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'", pStage->bundle[b].texMods[tm].type, tess.shader->name );
+ break;
+ }
+ }
+ }
+}
+
+/*
+** RB_IterateStagesGeneric
+*/
+static void RB_IterateStagesGeneric( shaderCommands_t *input )
+{
+ int stage;
+
+ for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ )
+ {
+ shaderStage_t *pStage = tess.xstages[stage];
+
+ if ( !pStage )
+ {
+ break;
+ }
+
+ ComputeColors( pStage );
+ ComputeTexCoords( pStage );
+
+ if ( !setArraysOnce )
+ {
+ qglEnableClientState( GL_COLOR_ARRAY );
+ qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors );
+ }
+
+ //
+ // do multitexture
+ //
+ if ( pStage->bundle[1].image[0] != 0 )
+ {
+ DrawMultitextured( input, stage );
+ }
+ else
+ {
+ if ( !setArraysOnce )
+ {
+ qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
+ }
+
+ //
+ // set state
+ //
+ R_BindAnimatedImage( &pStage->bundle[0] );
+
+ GL_State( pStage->stateBits );
+
+ //
+ // draw
+ //
+ R_DrawElements( input->numIndexes, input->indexes );
+ }
+ // allow skipping out to show just lightmaps during development
+ if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) )
+ {
+ break;
+ }
+ }
+}
+
+
+/*
+** RB_StageIteratorGeneric
+*/
+void RB_StageIteratorGeneric( void )
+{
+ shaderCommands_t *input;
+ shader_t *shader;
+
+ input = &tess;
+ shader = input->shader;
+
+ RB_DeformTessGeometry();
+
+ //
+ // log this call
+ //
+ if ( r_logFile->integer )
+ {
+ // don't just call LogComment, or we will get
+ // a call to va() every frame!
+ char *msg = (char*)va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name);
+ GLimp_LogComment( msg );
+ }
+
+ //
+ // set face culling appropriately
+ //
+ GL_Cull( shader->cullType );
+
+ // set polygon offset if necessary
+ if ( shader->polygonOffset )
+ {
+ qglEnable( GL_POLYGON_OFFSET_FILL );
+ qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );
+ }
+
+ //
+ // if there is only a single pass then we can enable color
+ // and texture arrays before we compile, otherwise we need
+ // to avoid compiling those arrays since they will change
+ // during multipass rendering
+ //
+ if ( tess.numPasses > 1 || shader->multitextureEnv )
+ {
+ setArraysOnce = false;
+ qglDisableClientState (GL_COLOR_ARRAY);
+ qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
+ }
+ else
+ {
+ setArraysOnce = true;
+
+ qglEnableClientState( GL_COLOR_ARRAY);
+ qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
+
+ qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
+ qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );
+ }
+
+ //
+ // lock XYZ
+ //
+ qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD
+ if (qglLockArraysEXT)
+ {
+ qglLockArraysEXT(0, input->numVertexes);
+ GLimp_LogComment( "glLockArraysEXT\n" );
+ }
+
+ //
+ // enable color and texcoord arrays after the lock if necessary
+ //
+ if ( !setArraysOnce )
+ {
+ qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ qglEnableClientState( GL_COLOR_ARRAY );
+ }
+
+ //
+ // call shader function
+ //
+ RB_IterateStagesGeneric( input );
+
+ //
+ // now do any dynamic lighting needed
+ //
+ if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE
+ && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) {
+ ProjectDlightTexture();
+ }
+
+ //
+ // now do fog
+ //
+ if ( tess.fogNum && tess.shader->fogPass ) {
+ RB_FogPass();
+ }
+
+ //
+ // unlock arrays
+ //
+ if (qglUnlockArraysEXT)
+ {
+ qglUnlockArraysEXT();
+ GLimp_LogComment( "glUnlockArraysEXT\n" );
+ }
+
+ //
+ // reset polygon offset
+ //
+ if ( shader->polygonOffset )
+ {
+ qglDisable( GL_POLYGON_OFFSET_FILL );
+ }
+}
+
+
+/*
+** RB_StageIteratorVertexLitTexture
+*/
+void RB_StageIteratorVertexLitTexture( void )
+{
+ shaderCommands_t *input;
+ shader_t *shader;
+
+ input = &tess;
+ shader = input->shader;
+
+ //
+ // compute colors
+ //
+ RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors );
+
+ //
+ // log this call
+ //
+ if ( r_logFile->integer )
+ {
+ // don't just call LogComment, or we will get
+ // a call to va() every frame!
+ GLimp_LogComment( (char*)va("--- RB_StageIteratorVertexLitTexturedUnfogged( %s ) ---\n", tess.shader->name) );
+ }
+
+ //
+ // set face culling appropriately
+ //
+ GL_Cull( shader->cullType );
+
+ //
+ // set arrays and lock
+ //
+ qglEnableClientState( GL_COLOR_ARRAY);
+ qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
+
+ qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
+ qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] );
+ qglVertexPointer (3, GL_FLOAT, 16, input->xyz);
+
+ if ( qglLockArraysEXT )
+ {
+ qglLockArraysEXT(0, input->numVertexes);
+ GLimp_LogComment( "glLockArraysEXT\n" );
+ }
+
+ //
+ // call special shade routine
+ //
+ R_BindAnimatedImage( &tess.xstages[0]->bundle[0] );
+ GL_State( tess.xstages[0]->stateBits );
+ R_DrawElements( input->numIndexes, input->indexes );
+
+ //
+ // now do any dynamic lighting needed
+ //
+ if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) {
+ ProjectDlightTexture();
+ }
+
+ //
+ // now do fog
+ //
+ if ( tess.fogNum && tess.shader->fogPass ) {
+ RB_FogPass();
+ }
+
+ //
+ // unlock arrays
+ //
+ if (qglUnlockArraysEXT)
+ {
+ qglUnlockArraysEXT();
+ GLimp_LogComment( "glUnlockArraysEXT\n" );
+ }
+}
+
+//define REPLACE_MODE
+
+void RB_StageIteratorLightmappedMultitexture( void ) {
+ shaderCommands_t *input;
+ shader_t *shader;
+
+ input = &tess;
+ shader = input->shader;
+
+ //
+ // log this call
+ //
+ if ( r_logFile->integer ) {
+ // don't just call LogComment, or we will get
+ // a call to va() every frame!
+ GLimp_LogComment( (char*)va("--- RB_StageIteratorLightmappedMultitexture( %s ) ---\n", tess.shader->name) );
+ }
+
+ //
+ // set face culling appropriately
+ //
+ GL_Cull( shader->cullType );
+
+ //
+ // set color, pointers, and lock
+ //
+ GL_State( GLS_DEFAULT );
+ qglVertexPointer( 3, GL_FLOAT, 16, input->xyz );
+
+#ifdef REPLACE_MODE
+ qglDisableClientState( GL_COLOR_ARRAY );
+ qglColor3f( 1, 1, 1 );
+ qglShadeModel( GL_FLAT );
+#else
+ qglEnableClientState( GL_COLOR_ARRAY );
+ qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.constantColor255 );
+#endif
+
+ //
+ // select base stage
+ //
+ GL_SelectTexture( 0 );
+
+ qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ R_BindAnimatedImage( &tess.xstages[0]->bundle[0] );
+ qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] );
+
+ //
+ // configure second stage
+ //
+ GL_SelectTexture( 1 );
+ qglEnable( GL_TEXTURE_2D );
+ if ( r_lightmap->integer ) {
+ GL_TexEnv( GL_REPLACE );
+ } else {
+ GL_TexEnv( GL_MODULATE );
+ }
+ R_BindAnimatedImage( &tess.xstages[0]->bundle[1] );
+ qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][1] );
+
+ //
+ // lock arrays
+ //
+ if ( qglLockArraysEXT ) {
+ qglLockArraysEXT(0, input->numVertexes);
+ GLimp_LogComment( "glLockArraysEXT\n" );
+ }
+
+ R_DrawElements( input->numIndexes, input->indexes );
+
+ //
+ // disable texturing on TEXTURE1, then select TEXTURE0
+ //
+ qglDisable( GL_TEXTURE_2D );
+ qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
+
+ GL_SelectTexture( 0 );
+#ifdef REPLACE_MODE
+ GL_TexEnv( GL_MODULATE );
+ qglShadeModel( GL_SMOOTH );
+#endif
+
+ //
+ // now do any dynamic lighting needed
+ //
+ if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) {
+ ProjectDlightTexture();
+ }
+
+ //
+ // now do fog
+ //
+ if ( tess.fogNum && tess.shader->fogPass ) {
+ RB_FogPass();
+ }
+
+ //
+ // unlock arrays
+ //
+ if ( qglUnlockArraysEXT ) {
+ qglUnlockArraysEXT();
+ GLimp_LogComment( "glUnlockArraysEXT\n" );
+ }
+}
+
+/*
+** RB_EndSurface
+*/
+void RB_EndSurface( void ) {
+ shaderCommands_t *input;
+
+ input = &tess;
+
+ if (input->numIndexes == 0) {
+ return;
+ }
+
+ if (input->indexes[SHADER_MAX_INDEXES-1] != 0) {
+ ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit");
+ }
+ if (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) {
+ ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit");
+ }
+
+ if ( tess.shader == tr.shadowShader ) {
+ RB_ShadowTessEnd();
+ return;
+ }
+
+ // for debugging of sort order issues, stop rendering after a given sort value
+ if ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) {
+ return;
+ }
+
+ //
+ // update performance counters
+ //
+ backEnd.pc.c_shaders++;
+ backEnd.pc.c_vertexes += tess.numVertexes;
+ backEnd.pc.c_indexes += tess.numIndexes;
+ backEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses;
+
+ //
+ // call off to shader specific tess end function
+ //
+ tess.currentStageIteratorFunc();
+
+ //
+ // draw debugging stuff
+ //
+ if ( r_showtris->integer ) {
+ DrawTris (input);
+ }
+ if ( r_shownormals->integer ) {
+ DrawNormals (input);
+ }
+ // clear shader so we can tell we don't have any unclosed surfaces
+ tess.numIndexes = 0;
+
+ GLimp_LogComment( "----------\n" );
+}
diff --git a/src/renderergl1/tr_shade_calc.cpp b/src/renderergl1/tr_shade_calc.cpp
new file mode 100644
index 0000000..6ce47c8
--- /dev/null
+++ b/src/renderergl1/tr_shade_calc.cpp
@@ -0,0 +1,1212 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_shade_calc.c
+
+#include "tr_local.h"
+#if idppc_altivec && !defined(__APPLE__)
+#include <altivec.h>
+#endif
+
+
+#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ static_cast<int64_t>( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
+
+static float *TableForFunc( genFunc_t func )
+{
+ switch ( func )
+ {
+ case GF_SIN:
+ return tr.sinTable;
+ case GF_TRIANGLE:
+ return tr.triangleTable;
+ case GF_SQUARE:
+ return tr.squareTable;
+ case GF_SAWTOOTH:
+ return tr.sawToothTable;
+ case GF_INVERSE_SAWTOOTH:
+ return tr.inverseSawToothTable;
+ case GF_NONE:
+ default:
+ break;
+ }
+
+ ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'", func, tess.shader->name );
+ return NULL;
+}
+
+/*
+** EvalWaveForm
+**
+** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly
+*/
+static float EvalWaveForm( const waveForm_t *wf )
+{
+ float *table;
+
+ table = TableForFunc( wf->func );
+
+ return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency );
+}
+
+static float EvalWaveFormClamped( const waveForm_t *wf )
+{
+ float glow = EvalWaveForm( wf );
+
+ if ( glow < 0 )
+ {
+ return 0;
+ }
+
+ if ( glow > 1 )
+ {
+ return 1;
+ }
+
+ return glow;
+}
+
+/*
+** RB_CalcStretchTexCoords
+*/
+void RB_CalcStretchTexCoords( const waveForm_t *wf, float *st )
+{
+ float p;
+ texModInfo_t tmi;
+
+ p = 1.0f / EvalWaveForm( wf );
+
+ tmi.matrix[0][0] = p;
+ tmi.matrix[1][0] = 0;
+ tmi.translate[0] = 0.5f - 0.5f * p;
+
+ tmi.matrix[0][1] = 0;
+ tmi.matrix[1][1] = p;
+ tmi.translate[1] = 0.5f - 0.5f * p;
+
+ RB_CalcTransformTexCoords( &tmi, st );
+}
+
+/*
+====================================================================
+
+DEFORMATIONS
+
+====================================================================
+*/
+
+/*
+========================
+RB_CalcDeformVertexes
+
+========================
+*/
+void RB_CalcDeformVertexes( deformStage_t *ds )
+{
+ int i;
+ vec3_t offset;
+ float scale;
+ float *xyz = ( float * ) tess.xyz;
+ float *normal = ( float * ) tess.normal;
+ float *table;
+
+ if ( ds->deformationWave.frequency == 0 )
+ {
+ scale = EvalWaveForm( &ds->deformationWave );
+
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
+ {
+ VectorScale( normal, scale, offset );
+
+ xyz[0] += offset[0];
+ xyz[1] += offset[1];
+ xyz[2] += offset[2];
+ }
+ }
+ else
+ {
+ table = TableForFunc( ds->deformationWave.func );
+
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
+ {
+ float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
+
+ scale = WAVEVALUE( table, ds->deformationWave.base,
+ ds->deformationWave.amplitude,
+ ds->deformationWave.phase + off,
+ ds->deformationWave.frequency );
+
+ VectorScale( normal, scale, offset );
+
+ xyz[0] += offset[0];
+ xyz[1] += offset[1];
+ xyz[2] += offset[2];
+ }
+ }
+}
+
+/*
+=========================
+RB_CalcDeformNormals
+
+Wiggle the normals for wavy environment mapping
+=========================
+*/
+void RB_CalcDeformNormals( deformStage_t *ds ) {
+ int i;
+ float scale;
+ float *xyz = ( float * ) tess.xyz;
+ float *normal = ( float * ) tess.normal;
+
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) {
+ scale = 0.98f;
+ scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
+ tess.shaderTime * ds->deformationWave.frequency );
+ normal[ 0 ] += ds->deformationWave.amplitude * scale;
+
+ scale = 0.98f;
+ scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
+ tess.shaderTime * ds->deformationWave.frequency );
+ normal[ 1 ] += ds->deformationWave.amplitude * scale;
+
+ scale = 0.98f;
+ scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
+ tess.shaderTime * ds->deformationWave.frequency );
+ normal[ 2 ] += ds->deformationWave.amplitude * scale;
+
+ VectorNormalizeFast( normal );
+ }
+}
+
+/*
+========================
+RB_CalcBulgeVertexes
+
+========================
+*/
+void RB_CalcBulgeVertexes( deformStage_t *ds ) {
+ int i;
+ const float *st = ( const float * ) tess.texCoords[0];
+ float *xyz = ( float * ) tess.xyz;
+ float *normal = ( float * ) tess.normal;
+
+ double now = backEnd.refdef.time * 0.001 * ds->bulgeSpeed;
+
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) {
+ int64_t off;
+ float scale;
+
+ off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now );
+
+ scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight;
+
+ xyz[0] += normal[0] * scale;
+ xyz[1] += normal[1] * scale;
+ xyz[2] += normal[2] * scale;
+ }
+}
+
+
+/*
+======================
+RB_CalcMoveVertexes
+
+A deformation that can move an entire surface along a wave path
+======================
+*/
+void RB_CalcMoveVertexes( deformStage_t *ds ) {
+ int i;
+ float *xyz;
+ float *table;
+ float scale;
+ vec3_t offset;
+
+ table = TableForFunc( ds->deformationWave.func );
+
+ scale = WAVEVALUE( table, ds->deformationWave.base,
+ ds->deformationWave.amplitude,
+ ds->deformationWave.phase,
+ ds->deformationWave.frequency );
+
+ VectorScale( ds->moveVector, scale, offset );
+
+ xyz = ( float * ) tess.xyz;
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
+ VectorAdd( xyz, offset, xyz );
+ }
+}
+
+
+/*
+=============
+DeformText
+
+Change a polygon into a bunch of text polygons
+=============
+*/
+void DeformText( const char *text ) {
+ int i;
+ vec3_t origin, width, height;
+ int len;
+ int ch;
+ byte color[4];
+ float bottom, top;
+ vec3_t mid;
+
+ height[0] = 0;
+ height[1] = 0;
+ height[2] = -1;
+ CrossProduct( tess.normal[0], height, width );
+
+ // find the midpoint of the box
+ VectorClear( mid );
+ bottom = 999999;
+ top = -999999;
+ for ( i = 0 ; i < 4 ; i++ ) {
+ VectorAdd( tess.xyz[i], mid, mid );
+ if ( tess.xyz[i][2] < bottom ) {
+ bottom = tess.xyz[i][2];
+ }
+ if ( tess.xyz[i][2] > top ) {
+ top = tess.xyz[i][2];
+ }
+ }
+ VectorScale( mid, 0.25f, origin );
+
+ // determine the individual character size
+ height[0] = 0;
+ height[1] = 0;
+ height[2] = ( top - bottom ) * 0.5f;
+
+ VectorScale( width, height[2] * -0.75f, width );
+
+ // determine the starting position
+ len = strlen( text );
+ VectorMA( origin, (len-1), width, origin );
+
+ // clear the shader indexes
+ tess.numIndexes = 0;
+ tess.numVertexes = 0;
+
+ color[0] = color[1] = color[2] = color[3] = 255;
+
+ // draw each character
+ for ( i = 0 ; i < len ; i++ ) {
+ ch = text[i];
+ ch &= 255;
+
+ if ( ch != ' ' ) {
+ int row, col;
+ float frow, fcol, size;
+
+ row = ch>>4;
+ col = ch&15;
+
+ frow = row*0.0625f;
+ fcol = col*0.0625f;
+ size = 0.0625f;
+
+ RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size );
+ }
+ VectorMA( origin, -2, width, origin );
+ }
+}
+
+/*
+==================
+GlobalVectorToLocal
+==================
+*/
+static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) {
+ out[0] = DotProduct( in, backEnd.orientation.axis[0] );
+ out[1] = DotProduct( in, backEnd.orientation.axis[1] );
+ out[2] = DotProduct( in, backEnd.orientation.axis[2] );
+}
+
+/*
+=====================
+AutospriteDeform
+
+Assuming all the triangles for this shader are independant
+quads, rebuild them as forward facing sprites
+=====================
+*/
+static void AutospriteDeform( void ) {
+ int i;
+ int oldVerts;
+ float *xyz;
+ vec3_t mid, delta;
+ float radius;
+ vec3_t left, up;
+ vec3_t leftDir, upDir;
+
+ if ( tess.numVertexes & 3 ) {
+ ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count\n", tess.shader->name );
+ }
+ if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
+ ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count\n", tess.shader->name );
+ }
+
+ oldVerts = tess.numVertexes;
+ tess.numVertexes = 0;
+ tess.numIndexes = 0;
+
+ if ( backEnd.currentEntity != &tr.worldEntity ) {
+ GlobalVectorToLocal( backEnd.viewParms.orientation.axis[1], leftDir );
+ GlobalVectorToLocal( backEnd.viewParms.orientation.axis[2], upDir );
+ } else {
+ VectorCopy( backEnd.viewParms.orientation.axis[1], leftDir );
+ VectorCopy( backEnd.viewParms.orientation.axis[2], upDir );
+ }
+
+ for ( i = 0 ; i < oldVerts ; i+=4 ) {
+ // find the midpoint
+ xyz = tess.xyz[i];
+
+ mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]);
+ mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]);
+ mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]);
+
+ VectorSubtract( xyz, mid, delta );
+ radius = VectorLength( delta ) * 0.707f; // / sqrt(2)
+
+ VectorScale( leftDir, radius, left );
+ VectorScale( upDir, radius, up );
+
+ if ( backEnd.viewParms.isMirror ) {
+ VectorSubtract( vec3_origin, left, left );
+ }
+
+ // compensate for scale in the axes if necessary
+ if ( backEnd.currentEntity->e.nonNormalizedAxes ) {
+ float axisLength;
+ axisLength = VectorLength( backEnd.currentEntity->e.axis[0] );
+ if ( !axisLength ) {
+ axisLength = 0;
+ } else {
+ axisLength = 1.0f / axisLength;
+ }
+ VectorScale(left, axisLength, left);
+ VectorScale(up, axisLength, up);
+ }
+
+ RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] );
+ }
+}
+
+
+/*
+=====================
+Autosprite2Deform
+
+Autosprite2 will pivot a rectangular quad along the center of its long axis
+=====================
+*/
+int edgeVerts[6][2] = {
+ { 0, 1 },
+ { 0, 2 },
+ { 0, 3 },
+ { 1, 2 },
+ { 1, 3 },
+ { 2, 3 }
+};
+
+static void Autosprite2Deform( void ) {
+ int i, j, k;
+ int indexes;
+ float *xyz;
+ vec3_t forward;
+
+ if ( tess.numVertexes & 3 ) {
+ ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count", tess.shader->name );
+ }
+ if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
+ ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count", tess.shader->name );
+ }
+
+ if ( backEnd.currentEntity != &tr.worldEntity ) {
+ GlobalVectorToLocal( backEnd.viewParms.orientation.axis[0], forward );
+ } else {
+ VectorCopy( backEnd.viewParms.orientation.axis[0], forward );
+ }
+
+ // this is a lot of work for two triangles...
+ // we could precalculate a lot of it is an issue, but it would mess up
+ // the shader abstraction
+ for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) {
+ float lengths[2];
+ int nums[2];
+ vec3_t mid[2];
+ vec3_t major, minor;
+ float *v1, *v2;
+
+ // find the midpoint
+ xyz = tess.xyz[i];
+
+ // identify the two shortest edges
+ nums[0] = nums[1] = 0;
+ lengths[0] = lengths[1] = 999999;
+
+ for ( j = 0 ; j < 6 ; j++ ) {
+ float l;
+ vec3_t temp;
+
+ v1 = xyz + 4 * edgeVerts[j][0];
+ v2 = xyz + 4 * edgeVerts[j][1];
+
+ VectorSubtract( v1, v2, temp );
+
+ l = DotProduct( temp, temp );
+ if ( l < lengths[0] ) {
+ nums[1] = nums[0];
+ lengths[1] = lengths[0];
+ nums[0] = j;
+ lengths[0] = l;
+ } else if ( l < lengths[1] ) {
+ nums[1] = j;
+ lengths[1] = l;
+ }
+ }
+
+ for ( j = 0 ; j < 2 ; j++ ) {
+ v1 = xyz + 4 * edgeVerts[nums[j]][0];
+ v2 = xyz + 4 * edgeVerts[nums[j]][1];
+
+ mid[j][0] = 0.5f * (v1[0] + v2[0]);
+ mid[j][1] = 0.5f * (v1[1] + v2[1]);
+ mid[j][2] = 0.5f * (v1[2] + v2[2]);
+ }
+
+ // find the vector of the major axis
+ VectorSubtract( mid[1], mid[0], major );
+
+ // cross this with the view direction to get minor axis
+ CrossProduct( major, forward, minor );
+ VectorNormalize( minor );
+
+ // re-project the points
+ for ( j = 0 ; j < 2 ; j++ ) {
+ float l;
+
+ v1 = xyz + 4 * edgeVerts[nums[j]][0];
+ v2 = xyz + 4 * edgeVerts[nums[j]][1];
+
+ l = 0.5 * sqrt( lengths[j] );
+
+ // we need to see which direction this edge
+ // is used to determine direction of projection
+ for ( k = 0 ; k < 5 ; k++ ) {
+ if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0]
+ && tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) {
+ break;
+ }
+ }
+
+ if ( k == 5 ) {
+ VectorMA( mid[j], l, minor, v1 );
+ VectorMA( mid[j], -l, minor, v2 );
+ } else {
+ VectorMA( mid[j], -l, minor, v1 );
+ VectorMA( mid[j], l, minor, v2 );
+ }
+ }
+ }
+}
+
+
+/*
+=====================
+RB_DeformTessGeometry
+
+=====================
+*/
+void RB_DeformTessGeometry( void ) {
+ int i;
+ deformStage_t *ds;
+
+ for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) {
+ ds = &tess.shader->deforms[ i ];
+
+ switch ( ds->deformation ) {
+ case DEFORM_NONE:
+ break;
+ case DEFORM_NORMALS:
+ RB_CalcDeformNormals( ds );
+ break;
+ case DEFORM_WAVE:
+ RB_CalcDeformVertexes( ds );
+ break;
+ case DEFORM_BULGE:
+ RB_CalcBulgeVertexes( ds );
+ break;
+ case DEFORM_MOVE:
+ RB_CalcMoveVertexes( ds );
+ break;
+ case DEFORM_PROJECTION_SHADOW:
+ RB_ProjectionShadowDeform();
+ break;
+ case DEFORM_AUTOSPRITE:
+ AutospriteDeform();
+ break;
+ case DEFORM_AUTOSPRITE2:
+ Autosprite2Deform();
+ break;
+ case DEFORM_TEXT0:
+ case DEFORM_TEXT1:
+ case DEFORM_TEXT2:
+ case DEFORM_TEXT3:
+ case DEFORM_TEXT4:
+ case DEFORM_TEXT5:
+ case DEFORM_TEXT6:
+ case DEFORM_TEXT7:
+ DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] );
+ break;
+ }
+ }
+}
+
+/*
+====================================================================
+
+COLORS
+
+====================================================================
+*/
+
+
+/*
+** RB_CalcColorFromEntity
+*/
+void RB_CalcColorFromEntity( unsigned char *dstColors )
+{
+ int i;
+ int *pColors = ( int * ) dstColors;
+ int c;
+
+ if ( !backEnd.currentEntity )
+ return;
+
+ c = * ( int * ) backEnd.currentEntity->e.shaderRGBA;
+
+ for ( i = 0; i < tess.numVertexes; i++, pColors++ )
+ {
+ *pColors = c;
+ }
+}
+
+/*
+** RB_CalcColorFromOneMinusEntity
+*/
+void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors )
+{
+ int i;
+ int *pColors = ( int * ) dstColors;
+ unsigned char invModulate[4];
+ int c;
+
+ if ( !backEnd.currentEntity )
+ return;
+
+ invModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0];
+ invModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1];
+ invModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2];
+ invModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3]; // this trashes alpha, but the AGEN block fixes it
+
+ c = * ( int * ) invModulate;
+
+ for ( i = 0; i < tess.numVertexes; i++, pColors++ )
+ {
+ *pColors = c;
+ }
+}
+
+/*
+** RB_CalcAlphaFromEntity
+*/
+void RB_CalcAlphaFromEntity( unsigned char *dstColors )
+{
+ int i;
+
+ if ( !backEnd.currentEntity )
+ return;
+
+ dstColors += 3;
+
+ for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
+ {
+ *dstColors = backEnd.currentEntity->e.shaderRGBA[3];
+ }
+}
+
+/*
+** RB_CalcAlphaFromOneMinusEntity
+*/
+void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors )
+{
+ int i;
+
+ if ( !backEnd.currentEntity )
+ return;
+
+ dstColors += 3;
+
+ for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
+ {
+ *dstColors = 0xff - backEnd.currentEntity->e.shaderRGBA[3];
+ }
+}
+
+/*
+** RB_CalcWaveColor
+*/
+void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors )
+{
+ int i;
+ int v;
+ float glow;
+ int *colors = ( int * ) dstColors;
+ byte color[4];
+
+
+ if ( wf->func == GF_NOISE ) {
+ glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude;
+ } else {
+ glow = EvalWaveForm( wf ) * tr.identityLight;
+ }
+
+ if ( glow < 0 ) {
+ glow = 0;
+ }
+ else if ( glow > 1 ) {
+ glow = 1;
+ }
+
+ v = static_cast<int>(255 * glow);
+ color[0] = color[1] = color[2] = v;
+ color[3] = 255;
+ v = *(int *)color;
+
+ for ( i = 0; i < tess.numVertexes; i++, colors++ ) {
+ *colors = v;
+ }
+}
+
+/*
+** RB_CalcWaveAlpha
+*/
+void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors )
+{
+ int i;
+ int v;
+ float glow;
+
+ glow = EvalWaveFormClamped( wf );
+
+ v = 255 * glow;
+
+ for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
+ {
+ dstColors[3] = v;
+ }
+}
+
+/*
+** RB_CalcModulateColorsByFog
+*/
+void RB_CalcModulateColorsByFog( unsigned char *colors ) {
+ int i;
+ float texCoords[SHADER_MAX_VERTEXES][2];
+
+ // calculate texcoords so we can derive density
+ // this is not wasted, because it would only have
+ // been previously called if the surface was opaque
+ RB_CalcFogTexCoords( texCoords[0] );
+
+ for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
+ float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
+ colors[0] *= f;
+ colors[1] *= f;
+ colors[2] *= f;
+ }
+}
+
+/*
+** RB_CalcModulateAlphasByFog
+*/
+void RB_CalcModulateAlphasByFog( unsigned char *colors ) {
+ int i;
+ float texCoords[SHADER_MAX_VERTEXES][2];
+
+ // calculate texcoords so we can derive density
+ // this is not wasted, because it would only have
+ // been previously called if the surface was opaque
+ RB_CalcFogTexCoords( texCoords[0] );
+
+ for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
+ float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
+ colors[3] *= f;
+ }
+}
+
+/*
+** RB_CalcModulateRGBAsByFog
+*/
+void RB_CalcModulateRGBAsByFog( unsigned char *colors ) {
+ int i;
+ float texCoords[SHADER_MAX_VERTEXES][2] = {{0.0f}};
+
+ // calculate texcoords so we can derive density
+ // this is not wasted, because it would only have
+ // been previously called if the surface was opaque
+ RB_CalcFogTexCoords( texCoords[0] );
+
+ for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
+ float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
+ colors[0] *= f;
+ colors[1] *= f;
+ colors[2] *= f;
+ colors[3] *= f;
+ }
+}
+
+
+/*
+====================================================================
+
+TEX COORDS
+
+====================================================================
+*/
+
+/*
+========================
+RB_CalcFogTexCoords
+
+To do the clipped fog plane really correctly, we should use
+projected textures, but I don't trust the drivers and it
+doesn't fit our shader data.
+========================
+*/
+void RB_CalcFogTexCoords( float *st ) {
+ int i;
+ float *v;
+ float s, t;
+ float eyeT;
+ bool eyeOutside;
+ fog_t *fog;
+ vec3_t local;
+ vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
+
+ fog = tr.world->fogs + tess.fogNum;
+
+ // all fogging distance is based on world Z units
+ VectorSubtract( backEnd.orientation.origin, backEnd.viewParms.orientation.origin, local );
+ fogDistanceVector[0] = -backEnd.orientation.modelMatrix[2];
+ fogDistanceVector[1] = -backEnd.orientation.modelMatrix[6];
+ fogDistanceVector[2] = -backEnd.orientation.modelMatrix[10];
+ fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.orientation.axis[0] );
+
+ // scale the fog vectors based on the fog's thickness
+ fogDistanceVector[0] *= fog->tcScale;
+ fogDistanceVector[1] *= fog->tcScale;
+ fogDistanceVector[2] *= fog->tcScale;
+ fogDistanceVector[3] *= fog->tcScale;
+
+ // rotate the gradient vector for this orientation
+ if ( fog->hasSurface ) {
+ fogDepthVector[0] = fog->surface[0] * backEnd.orientation.axis[0][0] +
+ fog->surface[1] * backEnd.orientation.axis[0][1] + fog->surface[2] * backEnd.orientation.axis[0][2];
+ fogDepthVector[1] = fog->surface[0] * backEnd.orientation.axis[1][0] +
+ fog->surface[1] * backEnd.orientation.axis[1][1] + fog->surface[2] * backEnd.orientation.axis[1][2];
+ fogDepthVector[2] = fog->surface[0] * backEnd.orientation.axis[2][0] +
+ fog->surface[1] * backEnd.orientation.axis[2][1] + fog->surface[2] * backEnd.orientation.axis[2][2];
+ fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.orientation.origin, fog->surface );
+
+ eyeT = DotProduct( backEnd.orientation.viewOrigin, fogDepthVector ) + fogDepthVector[3];
+ } else {
+ eyeT = 1; // non-surface fog always has eye inside
+ }
+
+ // see if the viewpoint is outside
+ // this is needed for clipping distance even for constant fog
+
+ if ( eyeT < 0 ) {
+ eyeOutside = true;
+ } else {
+ eyeOutside = false;
+ }
+
+ fogDistanceVector[3] += 1.0/512;
+
+ // calculate density for each point
+ for (i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4) {
+ // calculate the length in fog
+ s = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3];
+ t = DotProduct( v, fogDepthVector ) + fogDepthVector[3];
+
+ // partially clipped fogs use the T axis
+ if ( eyeOutside ) {
+ if ( t < 1.0 ) {
+ t = 1.0/32; // point is outside, so no fogging
+ } else {
+ t = 1.0/32 + 30.0/32 * t / ( t - eyeT ); // cut the distance at the fog plane
+ }
+ } else {
+ if ( t < 0 ) {
+ t = 1.0/32; // point is outside, so no fogging
+ } else {
+ t = 31.0/32;
+ }
+ }
+
+ st[0] = s;
+ st[1] = t;
+ st += 2;
+ }
+}
+
+
+
+/*
+** RB_CalcEnvironmentTexCoords
+*/
+void RB_CalcEnvironmentTexCoords( float *st )
+{
+ int i;
+ float *v, *normal;
+ vec3_t viewer, reflected;
+ float d;
+
+ v = tess.xyz[0];
+ normal = tess.normal[0];
+
+ for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 )
+ {
+ VectorSubtract (backEnd.orientation.viewOrigin, v, viewer);
+ VectorNormalizeFast (viewer);
+
+ d = DotProduct (normal, viewer);
+
+ reflected[0] = normal[0]*2*d - viewer[0];
+ reflected[1] = normal[1]*2*d - viewer[1];
+ reflected[2] = normal[2]*2*d - viewer[2];
+
+ st[0] = 0.5 + reflected[1] * 0.5;
+ st[1] = 0.5 - reflected[2] * 0.5;
+ }
+}
+
+/*
+** RB_CalcTurbulentTexCoords
+*/
+void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st )
+{
+ int i;
+ double now = ( wf->phase + tess.shaderTime * wf->frequency );
+
+ for ( i = 0; i < tess.numVertexes; i++, st += 2 )
+ {
+ float s = st[0];
+ float t = st[1];
+
+ st[0] = s + tr.sinTable[ ( static_cast<int64_t>( ( ( tess.xyz[i][0] + tess.xyz[i][2] )* 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude;
+ st[1] = t + tr.sinTable[ ( static_cast<int64_t>( ( tess.xyz[i][1] * 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude;
+ }
+}
+
+/*
+** RB_CalcScaleTexCoords
+*/
+void RB_CalcScaleTexCoords( const float scale[2], float *st )
+{
+ int i;
+
+ for ( i = 0; i < tess.numVertexes; i++, st += 2 )
+ {
+ st[0] *= scale[0];
+ st[1] *= scale[1];
+ }
+}
+
+/*
+** RB_CalcScrollTexCoords
+*/
+void RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st )
+{
+ int i;
+ double timeScale = tess.shaderTime;
+ double adjustedScrollS = scrollSpeed[0] * timeScale;
+ double adjustedScrollT = scrollSpeed[1] * timeScale;
+
+ // clamp so coordinates don't continuously get larger, causing problems
+ // with hardware limits
+ adjustedScrollS = adjustedScrollS - floor( adjustedScrollS );
+ adjustedScrollT = adjustedScrollT - floor( adjustedScrollT );
+
+ for ( i = 0; i < tess.numVertexes; i++, st += 2 )
+ {
+ st[0] += adjustedScrollS;
+ st[1] += adjustedScrollT;
+ }
+}
+
+/*
+** RB_CalcTransformTexCoords
+*/
+void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st )
+{
+ int i;
+
+ for ( i = 0; i < tess.numVertexes; i++, st += 2 )
+ {
+ float s = st[0];
+ float t = st[1];
+
+ st[0] = s * tmi->matrix[0][0] + t * tmi->matrix[1][0] + tmi->translate[0];
+ st[1] = s * tmi->matrix[0][1] + t * tmi->matrix[1][1] + tmi->translate[1];
+ }
+}
+
+/*
+** RB_CalcRotateTexCoords
+*/
+void RB_CalcRotateTexCoords( float degsPerSecond, float *st )
+{
+ double timeScale = tess.shaderTime;
+ double degs;
+ int i;
+ float sinValue, cosValue;
+ texModInfo_t tmi;
+
+ degs = -degsPerSecond * timeScale;
+ i = degs * ( FUNCTABLE_SIZE / 360.0f );
+
+ sinValue = tr.sinTable[ i & FUNCTABLE_MASK ];
+ cosValue = tr.sinTable[ ( i + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ];
+
+ tmi.matrix[0][0] = cosValue;
+ tmi.matrix[1][0] = -sinValue;
+ tmi.translate[0] = 0.5 - 0.5 * cosValue + 0.5 * sinValue;
+
+ tmi.matrix[0][1] = sinValue;
+ tmi.matrix[1][1] = cosValue;
+ tmi.translate[1] = 0.5 - 0.5 * sinValue - 0.5 * cosValue;
+
+ RB_CalcTransformTexCoords( &tmi, st );
+}
+
+
+/*
+** RB_CalcSpecularAlpha
+**
+** Calculates specular coefficient and places it in the alpha channel
+*/
+vec3_t lightOrigin = { -960, 1980, 96 }; // FIXME: track dynamically
+
+void RB_CalcSpecularAlpha( unsigned char *alphas ) {
+ int i;
+ float *v, *normal;
+ vec3_t viewer, reflected;
+ float l, d;
+ int b;
+ vec3_t lightDir;
+ int numVertexes;
+
+ v = tess.xyz[0];
+ normal = tess.normal[0];
+
+ alphas += 3;
+
+ numVertexes = tess.numVertexes;
+ for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4, alphas += 4) {
+ float ilength;
+
+ VectorSubtract( lightOrigin, v, lightDir );
+// ilength = Q_rsqrt( DotProduct( lightDir, lightDir ) );
+ VectorNormalizeFast( lightDir );
+
+ // calculate the specular color
+ d = DotProduct (normal, lightDir);
+// d *= ilength;
+
+ // we don't optimize for the d < 0 case since this tends to
+ // cause visual artifacts such as faceted "snapping"
+ reflected[0] = normal[0]*2*d - lightDir[0];
+ reflected[1] = normal[1]*2*d - lightDir[1];
+ reflected[2] = normal[2]*2*d - lightDir[2];
+
+ VectorSubtract (backEnd.orientation.viewOrigin, v, viewer);
+ ilength = Q_rsqrt( DotProduct( viewer, viewer ) );
+ l = DotProduct (reflected, viewer);
+ l *= ilength;
+
+ if (l < 0) {
+ b = 0;
+ } else {
+ l = l*l;
+ l = l*l;
+ b = l * 255;
+ if (b > 255) {
+ b = 255;
+ }
+ }
+
+ *alphas = b;
+ }
+}
+
+/*
+** RB_CalcDiffuseColor
+**
+** The basic vertex lighting calc
+*/
+#if idppc_altivec
+static void RB_CalcDiffuseColor_altivec( unsigned char *colors )
+{
+ int i;
+ float *v, *normal;
+ trRefEntity_t *ent;
+ int ambientLightInt;
+ vec3_t lightDir;
+ int numVertexes;
+ vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0xff);
+ vector float ambientLightVec;
+ vector float directedLightVec;
+ vector float lightDirVec;
+ vector float normalVec0, normalVec1;
+ vector float incomingVec0, incomingVec1, incomingVec2;
+ vector float zero, jVec;
+ vector signed int jVecInt;
+ vector signed short jVecShort;
+ vector unsigned char jVecChar, normalPerm;
+ ent = backEnd.currentEntity;
+ ambientLightInt = ent->ambientLightInt;
+ // A lot of this could be simplified if we made sure
+ // entities light info was 16-byte aligned.
+ jVecChar = vec_lvsl(0, ent->ambientLight);
+ ambientLightVec = vec_ld(0, (vector float *)ent->ambientLight);
+ jVec = vec_ld(11, (vector float *)ent->ambientLight);
+ ambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar);
+
+ jVecChar = vec_lvsl(0, ent->directedLight);
+ directedLightVec = vec_ld(0,(vector float *)ent->directedLight);
+ jVec = vec_ld(11,(vector float *)ent->directedLight);
+ directedLightVec = vec_perm(directedLightVec,jVec,jVecChar);
+
+ jVecChar = vec_lvsl(0, ent->lightDir);
+ lightDirVec = vec_ld(0,(vector float *)ent->lightDir);
+ jVec = vec_ld(11,(vector float *)ent->lightDir);
+ lightDirVec = vec_perm(lightDirVec,jVec,jVecChar);
+
+ zero = (vector float)vec_splat_s8(0);
+ VectorCopy( ent->lightDir, lightDir );
+
+ v = tess.xyz[0];
+ normal = tess.normal[0];
+
+ normalPerm = vec_lvsl(0,normal);
+ numVertexes = tess.numVertexes;
+ for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) {
+ normalVec0 = vec_ld(0,(vector float *)normal);
+ normalVec1 = vec_ld(11,(vector float *)normal);
+ normalVec0 = vec_perm(normalVec0,normalVec1,normalPerm);
+ incomingVec0 = vec_madd(normalVec0, lightDirVec, zero);
+ incomingVec1 = vec_sld(incomingVec0,incomingVec0,4);
+ incomingVec2 = vec_add(incomingVec0,incomingVec1);
+ incomingVec1 = vec_sld(incomingVec1,incomingVec1,4);
+ incomingVec2 = vec_add(incomingVec2,incomingVec1);
+ incomingVec0 = vec_splat(incomingVec2,0);
+ incomingVec0 = vec_max(incomingVec0,zero);
+ normalPerm = vec_lvsl(12,normal);
+ jVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec);
+ jVecInt = vec_cts(jVec,0); // RGBx
+ jVecShort = vec_pack(jVecInt,jVecInt); // RGBxRGBx
+ jVecChar = vec_packsu(jVecShort,jVecShort); // RGBxRGBxRGBxRGBx
+ jVecChar = vec_sel(jVecChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255
+ vec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]); // store color
+ }
+}
+#endif
+
+static void RB_CalcDiffuseColor_scalar( unsigned char *colors )
+{
+ int i, j;
+ float *v, *normal;
+ float incoming;
+ trRefEntity_t *ent;
+ int ambientLightInt;
+ vec3_t ambientLight;
+ vec3_t lightDir;
+ vec3_t directedLight;
+ int numVertexes;
+ ent = backEnd.currentEntity;
+ ambientLightInt = ent->ambientLightInt;
+ VectorCopy( ent->ambientLight, ambientLight );
+ VectorCopy( ent->directedLight, directedLight );
+ VectorCopy( ent->lightDir, lightDir );
+
+ v = tess.xyz[0];
+ normal = tess.normal[0];
+
+ numVertexes = tess.numVertexes;
+ for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) {
+ incoming = DotProduct (normal, lightDir);
+ if ( incoming <= 0 ) {
+ *(int *)&colors[i*4] = ambientLightInt;
+ continue;
+ }
+ j = static_cast<int>(ambientLight[0] + incoming * directedLight[0]);
+ if ( j > 255 ) {
+ j = 255;
+ }
+ colors[i*4+0] = j;
+
+ j = static_cast<int>(ambientLight[1] + incoming * directedLight[1]);
+ if ( j > 255 ) {
+ j = 255;
+ }
+ colors[i*4+1] = j;
+
+ j = static_cast<int>(ambientLight[2] + incoming * directedLight[2]);
+ if ( j > 255 ) {
+ j = 255;
+ }
+ colors[i*4+2] = j;
+
+ colors[i*4+3] = 255;
+ }
+}
+
+void RB_CalcDiffuseColor( unsigned char *colors )
+{
+#if idppc_altivec
+ if (com_altivec->integer) {
+ // must be in a seperate function or G3 systems will crash.
+ RB_CalcDiffuseColor_altivec( colors );
+ return;
+ }
+#endif
+ RB_CalcDiffuseColor_scalar( colors );
+}
diff --git a/src/renderergl1/tr_shader.cpp b/src/renderergl1/tr_shader.cpp
new file mode 100644
index 0000000..db9f140
--- /dev/null
+++ b/src/renderergl1/tr_shader.cpp
@@ -0,0 +1,3158 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "tr_local.h"
+
+// tr_shader.c -- this file deals with the parsing and definition of shaders
+
+static char *s_shaderText;
+
+// the shader is parsed into these global variables, then copied into
+// dynamically allocated memory if it is valid.
+static shaderStage_t stages[MAX_SHADER_STAGES];
+static shader_t shader;
+static texModInfo_t texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS];
+
+#define FILE_HASH_SIZE 1024
+static shader_t* hashTable[FILE_HASH_SIZE];
+
+#define MAX_SHADERTEXT_HASH 2048
+static char **shaderTextHashTable[MAX_SHADERTEXT_HASH];
+
+/*
+================
+return a hash value for the filename
+================
+*/
+#ifdef __GNUCC__
+ #warning TODO: check if long is ok here
+#endif
+static long generateHashValue( const char *fname, const int size ) {
+ int i;
+ long hash;
+ char letter;
+
+ hash = 0;
+ i = 0;
+ while (fname[i] != '\0') {
+ letter = tolower(fname[i]);
+ if (letter =='.') break; // don't include extension
+ if (letter =='\\') letter = '/'; // damn path names
+ if (letter == PATH_SEP) letter = '/'; // damn path names
+ hash+=(long)(letter)*(i+119);
+ i++;
+ }
+ hash = (hash ^ (hash >> 10) ^ (hash >> 20));
+ hash &= (size-1);
+ return hash;
+}
+
+void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) {
+ char strippedName[MAX_QPATH];
+ int hash;
+ shader_t *sh, *sh2;
+ qhandle_t h;
+
+ sh = R_FindShaderByName( shaderName );
+ if (sh == NULL || sh == tr.defaultShader) {
+ h = RE_RegisterShaderLightMap(shaderName, 0);
+ sh = R_GetShaderByHandle(h);
+ }
+ if (sh == NULL || sh == tr.defaultShader) {
+ ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName );
+ return;
+ }
+
+ sh2 = R_FindShaderByName( newShaderName );
+ if (sh2 == NULL || sh2 == tr.defaultShader) {
+ h = RE_RegisterShaderLightMap(newShaderName, 0);
+ sh2 = R_GetShaderByHandle(h);
+ }
+
+ if (sh2 == NULL || sh2 == tr.defaultShader) {
+ ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName );
+ return;
+ }
+
+ // remap all the shaders with the given name
+ // even tho they might have different lightmaps
+ COM_StripExtension(shaderName, strippedName, sizeof(strippedName));
+ hash = generateHashValue(strippedName, FILE_HASH_SIZE);
+ for (sh = hashTable[hash]; sh; sh = sh->next) {
+ if (Q_stricmp(sh->name, strippedName) == 0) {
+ if (sh != sh2) {
+ sh->remappedShader = sh2;
+ } else {
+ sh->remappedShader = NULL;
+ }
+ }
+ }
+ if (timeOffset) {
+ sh2->timeOffset = atof(timeOffset);
+ }
+}
+
+/*
+===============
+ParseVector
+===============
+*/
+static bool ParseVector( char **text, int count, float *v ) {
+ char *token;
+ int i;
+
+ // FIXME: spaces are currently required after parens, should change parseext...
+ token = COM_ParseExt( text, qfalse );
+ if ( strcmp( token, "(" ) ) {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ for ( i = 0 ; i < count ; i++ ) {
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] ) {
+ ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name );
+ return false;
+ }
+ v[i] = atof( token );
+ }
+
+ token = COM_ParseExt( text, qfalse );
+ if ( strcmp( token, ")" ) ) {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ return true;
+}
+
+
+/*
+===============
+NameToAFunc
+===============
+*/
+static unsigned NameToAFunc( const char *funcname )
+{
+ if ( !Q_stricmp( funcname, "GT0" ) )
+ {
+ return GLS_ATEST_GT_0;
+ }
+ else if ( !Q_stricmp( funcname, "LT128" ) )
+ {
+ return GLS_ATEST_LT_80;
+ }
+ else if ( !Q_stricmp( funcname, "GE128" ) )
+ {
+ return GLS_ATEST_GE_80;
+ }
+
+ ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name );
+ return 0;
+}
+
+
+/*
+===============
+NameToSrcBlendMode
+===============
+*/
+static int NameToSrcBlendMode( const char *name )
+{
+ if ( !Q_stricmp( name, "GL_ONE" ) )
+ {
+ return GLS_SRCBLEND_ONE;
+ }
+ else if ( !Q_stricmp( name, "GL_ZERO" ) )
+ {
+ return GLS_SRCBLEND_ZERO;
+ }
+ else if ( !Q_stricmp( name, "GL_DST_COLOR" ) )
+ {
+ return GLS_SRCBLEND_DST_COLOR;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) )
+ {
+ return GLS_SRCBLEND_ONE_MINUS_DST_COLOR;
+ }
+ else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
+ {
+ return GLS_SRCBLEND_SRC_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
+ {
+ return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
+ {
+ return GLS_SRCBLEND_DST_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
+ {
+ return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) )
+ {
+ return GLS_SRCBLEND_ALPHA_SATURATE;
+ }
+
+ ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
+ return GLS_SRCBLEND_ONE;
+}
+
+/*
+===============
+NameToDstBlendMode
+===============
+*/
+static int NameToDstBlendMode( const char *name )
+{
+ if ( !Q_stricmp( name, "GL_ONE" ) )
+ {
+ return GLS_DSTBLEND_ONE;
+ }
+ else if ( !Q_stricmp( name, "GL_ZERO" ) )
+ {
+ return GLS_DSTBLEND_ZERO;
+ }
+ else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
+ {
+ return GLS_DSTBLEND_SRC_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
+ {
+ return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
+ {
+ return GLS_DSTBLEND_DST_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
+ {
+ return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) )
+ {
+ return GLS_DSTBLEND_SRC_COLOR;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) )
+ {
+ return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR;
+ }
+
+ ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
+ return GLS_DSTBLEND_ONE;
+}
+
+/*
+===============
+NameToGenFunc
+===============
+*/
+static genFunc_t NameToGenFunc( const char *funcname )
+{
+ if ( !Q_stricmp( funcname, "sin" ) )
+ {
+ return GF_SIN;
+ }
+ else if ( !Q_stricmp( funcname, "square" ) )
+ {
+ return GF_SQUARE;
+ }
+ else if ( !Q_stricmp( funcname, "triangle" ) )
+ {
+ return GF_TRIANGLE;
+ }
+ else if ( !Q_stricmp( funcname, "sawtooth" ) )
+ {
+ return GF_SAWTOOTH;
+ }
+ else if ( !Q_stricmp( funcname, "inversesawtooth" ) )
+ {
+ return GF_INVERSE_SAWTOOTH;
+ }
+ else if ( !Q_stricmp( funcname, "noise" ) )
+ {
+ return GF_NOISE;
+ }
+
+ ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name );
+ return GF_SIN;
+}
+
+
+/*
+===================
+ParseWaveForm
+===================
+*/
+static void ParseWaveForm( char **text, waveForm_t *wave )
+{
+ char *token;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ return;
+ }
+ wave->func = NameToGenFunc( token );
+
+ // BASE, AMP, PHASE, FREQ
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ return;
+ }
+ wave->base = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ return;
+ }
+ wave->amplitude = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ return;
+ }
+ wave->phase = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ return;
+ }
+ wave->frequency = atof( token );
+}
+
+
+/*
+===================
+ParseTexMod
+===================
+*/
+static void ParseTexMod( char *_text, shaderStage_t *stage )
+{
+ const char *token;
+ char **text = &_text;
+ texModInfo_t *tmi;
+
+ if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) {
+ ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'", shader.name );
+ return;
+ }
+
+ tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods];
+ stage->bundle[0].numTexMods++;
+
+ token = COM_ParseExt( text, qfalse );
+
+ //
+ // turb
+ //
+ if ( !Q_stricmp( token, "turb" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.base = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.amplitude = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.phase = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.frequency = atof( token );
+
+ tmi->type = TMOD_TURBULENT;
+ }
+ //
+ // scale
+ //
+ else if ( !Q_stricmp( token, "scale" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->scale[0] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->scale[1] = atof( token );
+ tmi->type = TMOD_SCALE;
+ }
+ //
+ // scroll
+ //
+ else if ( !Q_stricmp( token, "scroll" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->scroll[0] = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->scroll[1] = atof( token );
+ tmi->type = TMOD_SCROLL;
+ }
+ //
+ // stretch
+ //
+ else if ( !Q_stricmp( token, "stretch" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.func = NameToGenFunc( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.base = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.amplitude = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.phase = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.frequency = atof( token );
+
+ tmi->type = TMOD_STRETCH;
+ }
+ //
+ // transform
+ //
+ else if ( !Q_stricmp( token, "transform" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->matrix[0][0] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->matrix[0][1] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->matrix[1][0] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->matrix[1][1] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->translate[0] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->translate[1] = atof( token );
+
+ tmi->type = TMOD_TRANSFORM;
+ }
+ //
+ // rotate
+ //
+ else if ( !Q_stricmp( token, "rotate" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->rotateSpeed = atof( token );
+ tmi->type = TMOD_ROTATE;
+ }
+ //
+ // entityTranslate
+ //
+ else if ( !Q_stricmp( token, "entityTranslate" ) )
+ {
+ tmi->type = TMOD_ENTITY_TRANSLATE;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name );
+ }
+}
+
+
+/*
+===================
+ParseStage
+===================
+*/
+static bool ParseStage( shaderStage_t *stage, char **text )
+{
+ char *token;
+ int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0;
+ bool depthMaskExplicit = false;
+
+ stage->active = true;
+
+ while ( 1 )
+ {
+ token = COM_ParseExt( text, qtrue );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" );
+ return false;
+ }
+
+ if ( token[0] == '}' )
+ {
+ break;
+ }
+ //
+ // map <name>
+ //
+ else if ( !Q_stricmp( token, "map" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ if ( !Q_stricmp( token, "$whiteimage" ) )
+ {
+ stage->bundle[0].image[0] = tr.whiteImage;
+ continue;
+ }
+ else if ( !Q_stricmp( token, "$lightmap" ) )
+ {
+ stage->bundle[0].isLightmap = true;
+ if ( shader.lightmapIndex < 0 || !tr.lightmaps ) {
+ stage->bundle[0].image[0] = tr.whiteImage;
+ } else {
+ stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
+ }
+ continue;
+ }
+ else
+ {
+ imgType_t type = IMGTYPE_COLORALPHA;
+ int /*imgFlags_t*/ flags = IMGFLAG_NONE;
+
+ if (!shader.noMipMaps)
+ flags |= IMGFLAG_MIPMAP;
+
+ if (!shader.noPicMip)
+ flags |= IMGFLAG_PICMIP;
+
+ stage->bundle[0].image[0] = R_FindImageFile( token, type, flags );
+
+ if ( !stage->bundle[0].image[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
+ return false;
+ }
+ }
+ }
+ //
+ // clampmap <name>
+ //
+ else if ( !Q_stricmp( token, "clampmap" ) )
+ {
+ imgType_t type = IMGTYPE_COLORALPHA;
+ int/*imgFlags_t*/ flags = IMGFLAG_CLAMPTOEDGE;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ if (!shader.noMipMaps)
+ flags |= IMGFLAG_MIPMAP;
+
+ if (!shader.noPicMip)
+ flags |= IMGFLAG_PICMIP;
+
+ stage->bundle[0].image[0] = R_FindImageFile( token, type, flags );
+ if ( !stage->bundle[0].image[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
+ return false;
+ }
+ }
+ //
+ // animMap <frequency> <image1> .... <imageN>
+ //
+ else if ( !Q_stricmp( token, "animMap" ) )
+ {
+ int totalImages = 0;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMap' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+ stage->bundle[0].imageAnimationSpeed = atof( token );
+
+ // parse up to MAX_IMAGE_ANIMATIONS animations
+ while ( 1 ) {
+ int num;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] ) {
+ break;
+ }
+ num = stage->bundle[0].numImageAnimations;
+ if ( num < MAX_IMAGE_ANIMATIONS ) {
+ int/*imgFlags_t*/ flags = IMGFLAG_NONE;
+
+ if (!shader.noMipMaps)
+ flags |= IMGFLAG_MIPMAP;
+
+ if (!shader.noPicMip)
+ flags |= IMGFLAG_PICMIP;
+
+ stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags );
+ if ( !stage->bundle[0].image[num] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
+ return false;
+ }
+ stage->bundle[0].numImageAnimations++;
+ }
+ totalImages++;
+ }
+
+ if ( totalImages > MAX_IMAGE_ANIMATIONS ) {
+ ri.Printf( PRINT_WARNING, "WARNING: ignoring excess images for 'animMap' (found %d, max is %d) in shader '%s'\n",
+ totalImages, MAX_IMAGE_ANIMATIONS, shader.name );
+ }
+ }
+ else if ( !Q_stricmp( token, "videoMap" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+ stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader));
+ if (stage->bundle[0].videoMapHandle != -1) {
+ stage->bundle[0].isVideoMap = true;
+ stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle];
+ } else {
+ ri.Printf( PRINT_WARNING, "WARNING: could not load '%s' for 'videoMap' keyword in shader '%s'\n", token, shader.name );
+ }
+ }
+
+ //
+ // alphafunc <func>
+ //
+ else if ( !Q_stricmp( token, "alphaFunc" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ atestBits = NameToAFunc( token );
+ }
+ //
+ // depthFunc <func>
+ //
+ else if ( !Q_stricmp( token, "depthfunc" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ if ( !Q_stricmp( token, "lequal" ) )
+ {
+ depthFuncBits = 0;
+ }
+ else if ( !Q_stricmp( token, "equal" ) )
+ {
+ depthFuncBits = GLS_DEPTHFUNC_EQUAL;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name );
+ continue;
+ }
+ }
+ //
+ // detail
+ //
+ else if ( !Q_stricmp( token, "detail" ) )
+ {
+ stage->isDetail = true;
+ }
+ //
+ // blendfunc <srcFactor> <dstFactor>
+ // or blendfunc <add|filter|blend>
+ //
+ else if ( !Q_stricmp( token, "blendfunc" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
+ continue;
+ }
+ // check for "simple" blends first
+ if ( !Q_stricmp( token, "add" ) ) {
+ blendSrcBits = GLS_SRCBLEND_ONE;
+ blendDstBits = GLS_DSTBLEND_ONE;
+ } else if ( !Q_stricmp( token, "filter" ) ) {
+ blendSrcBits = GLS_SRCBLEND_DST_COLOR;
+ blendDstBits = GLS_DSTBLEND_ZERO;
+ } else if ( !Q_stricmp( token, "blend" ) ) {
+ blendSrcBits = GLS_SRCBLEND_SRC_ALPHA;
+ blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
+ } else {
+ // complex double blends
+ blendSrcBits = NameToSrcBlendMode( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
+ continue;
+ }
+ blendDstBits = NameToDstBlendMode( token );
+ }
+
+ // clear depth mask for blended surfaces
+ if ( !depthMaskExplicit )
+ {
+ depthMaskBits = 0;
+ }
+ }
+ //
+ // rgbGen
+ //
+ else if ( !Q_stricmp( token, "rgbGen" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ if ( !Q_stricmp( token, "wave" ) )
+ {
+ ParseWaveForm( text, &stage->rgbWave );
+ stage->rgbGen = CGEN_WAVEFORM;
+ }
+ else if ( !Q_stricmp( token, "const" ) )
+ {
+ vec3_t color;
+
+ VectorClear( color );
+
+ ParseVector( text, 3, color );
+ stage->constantColor[0] = 255 * color[0];
+ stage->constantColor[1] = 255 * color[1];
+ stage->constantColor[2] = 255 * color[2];
+
+ stage->rgbGen = CGEN_CONST;
+ }
+ else if ( !Q_stricmp( token, "identity" ) )
+ {
+ stage->rgbGen = CGEN_IDENTITY;
+ }
+ else if ( !Q_stricmp( token, "identityLighting" ) )
+ {
+ stage->rgbGen = CGEN_IDENTITY_LIGHTING;
+ }
+ else if ( !Q_stricmp( token, "entity" ) )
+ {
+ stage->rgbGen = CGEN_ENTITY;
+ }
+ else if ( !Q_stricmp( token, "oneMinusEntity" ) )
+ {
+ stage->rgbGen = CGEN_ONE_MINUS_ENTITY;
+ }
+ else if ( !Q_stricmp( token, "vertex" ) )
+ {
+ stage->rgbGen = CGEN_VERTEX;
+ if ( stage->alphaGen == 0 ) {
+ stage->alphaGen = AGEN_VERTEX;
+ }
+ }
+ else if ( !Q_stricmp( token, "exactVertex" ) )
+ {
+ stage->rgbGen = CGEN_EXACT_VERTEX;
+ }
+ else if ( !Q_stricmp( token, "lightingDiffuse" ) )
+ {
+ stage->rgbGen = CGEN_LIGHTING_DIFFUSE;
+ }
+ else if ( !Q_stricmp( token, "oneMinusVertex" ) )
+ {
+ stage->rgbGen = CGEN_ONE_MINUS_VERTEX;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name );
+ continue;
+ }
+ }
+ //
+ // alphaGen
+ //
+ else if ( !Q_stricmp( token, "alphaGen" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ if ( !Q_stricmp( token, "wave" ) )
+ {
+ ParseWaveForm( text, &stage->alphaWave );
+ stage->alphaGen = AGEN_WAVEFORM;
+ }
+ else if ( !Q_stricmp( token, "const" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ stage->constantColor[3] = 255 * atof( token );
+ stage->alphaGen = AGEN_CONST;
+ }
+ else if ( !Q_stricmp( token, "identity" ) )
+ {
+ stage->alphaGen = AGEN_IDENTITY;
+ }
+ else if ( !Q_stricmp( token, "entity" ) )
+ {
+ stage->alphaGen = AGEN_ENTITY;
+ }
+ else if ( !Q_stricmp( token, "oneMinusEntity" ) )
+ {
+ stage->alphaGen = AGEN_ONE_MINUS_ENTITY;
+ }
+ else if ( !Q_stricmp( token, "vertex" ) )
+ {
+ stage->alphaGen = AGEN_VERTEX;
+ }
+ else if ( !Q_stricmp( token, "lightingSpecular" ) )
+ {
+ stage->alphaGen = AGEN_LIGHTING_SPECULAR;
+ }
+ else if ( !Q_stricmp( token, "oneMinusVertex" ) )
+ {
+ stage->alphaGen = AGEN_ONE_MINUS_VERTEX;
+ }
+ else if ( !Q_stricmp( token, "portal" ) )
+ {
+ stage->alphaGen = AGEN_PORTAL;
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ shader.portalRange = 256;
+ ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name );
+ }
+ else
+ {
+ shader.portalRange = atof( token );
+ }
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name );
+ continue;
+ }
+ }
+ //
+ // tcGen <function>
+ //
+ else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ if ( !Q_stricmp( token, "environment" ) )
+ {
+ stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED;
+ }
+ else if ( !Q_stricmp( token, "lightmap" ) )
+ {
+ stage->bundle[0].tcGen = TCGEN_LIGHTMAP;
+ }
+ else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) )
+ {
+ stage->bundle[0].tcGen = TCGEN_TEXTURE;
+ }
+ else if ( !Q_stricmp( token, "vector" ) )
+ {
+ ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] );
+ ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] );
+
+ stage->bundle[0].tcGen = TCGEN_VECTOR;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name );
+ }
+ }
+ //
+ // tcMod <type> <...>
+ //
+ else if ( !Q_stricmp( token, "tcMod" ) )
+ {
+ char buffer[1024] = "";
+
+ while ( 1 )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ break;
+ Q_strcat( buffer, sizeof (buffer), token );
+ Q_strcat( buffer, sizeof (buffer), " " );
+ }
+
+ ParseTexMod( buffer, stage );
+
+ continue;
+ }
+ //
+ // depthmask
+ //
+ else if ( !Q_stricmp( token, "depthwrite" ) )
+ {
+ depthMaskBits = GLS_DEPTHMASK_TRUE;
+ depthMaskExplicit = true;
+
+ continue;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name );
+ return false;
+ }
+ }
+
+ //
+ // if cgen isn't explicitly specified, use either identity or identitylighting
+ //
+ if ( stage->rgbGen == CGEN_BAD ) {
+ if ( blendSrcBits == 0 ||
+ blendSrcBits == GLS_SRCBLEND_ONE ||
+ blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) {
+ stage->rgbGen = CGEN_IDENTITY_LIGHTING;
+ } else {
+ stage->rgbGen = CGEN_IDENTITY;
+ }
+ }
+
+
+ //
+ // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending
+ //
+ if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) &&
+ ( blendDstBits == GLS_DSTBLEND_ZERO ) )
+ {
+ blendDstBits = blendSrcBits = 0;
+ depthMaskBits = GLS_DEPTHMASK_TRUE;
+ }
+
+ // decide which agens we can skip
+ if ( stage->alphaGen == AGEN_IDENTITY ) {
+ if ( stage->rgbGen == CGEN_IDENTITY
+ || stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) {
+ stage->alphaGen = AGEN_SKIP;
+ }
+ }
+
+ //
+ // compute state bits
+ //
+ stage->stateBits = depthMaskBits |
+ blendSrcBits | blendDstBits |
+ atestBits |
+ depthFuncBits;
+
+ return true;
+}
+
+/*
+===============
+ParseDeform
+
+deformVertexes wave <spread> <waveform> <base> <amplitude> <phase> <frequency>
+deformVertexes normal <frequency> <amplitude>
+deformVertexes move <vector> <waveform> <base> <amplitude> <phase> <frequency>
+deformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed>
+deformVertexes projectionShadow
+deformVertexes autoSprite
+deformVertexes autoSprite2
+deformVertexes text[0-7]
+===============
+*/
+static void ParseDeform( char **text ) {
+ char *token;
+ deformStage_t *ds;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name );
+ return;
+ }
+
+ if ( shader.numDeforms == MAX_SHADER_DEFORMS ) {
+ ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name );
+ return;
+ }
+
+ ds = &shader.deforms[ shader.numDeforms ];
+ shader.numDeforms++;
+
+ if ( !Q_stricmp( token, "projectionShadow" ) ) {
+ ds->deformation = DEFORM_PROJECTION_SHADOW;
+ return;
+ }
+
+ if ( !Q_stricmp( token, "autosprite" ) ) {
+ ds->deformation = DEFORM_AUTOSPRITE;
+ return;
+ }
+
+ if ( !Q_stricmp( token, "autosprite2" ) ) {
+ ds->deformation = DEFORM_AUTOSPRITE2;
+ return;
+ }
+
+ if ( !Q_stricmpn( token, "text", 4 ) ) {
+ int n;
+
+ n = token[4] - '0';
+ if ( n < 0 || n > 7 ) {
+ n = 0;
+ }
+ ds->deformation = (deform_t)(DEFORM_TEXT0 + n);
+ return;
+ }
+
+ if ( !Q_stricmp( token, "bulge" ) ) {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->bulgeWidth = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->bulgeHeight = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->bulgeSpeed = atof( token );
+
+ ds->deformation = DEFORM_BULGE;
+ return;
+ }
+
+ if ( !Q_stricmp( token, "wave" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ return;
+ }
+
+ if ( atof( token ) != 0 )
+ {
+ ds->deformationSpread = 1.0f / atof( token );
+ }
+ else
+ {
+ ds->deformationSpread = 100.0f;
+ ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name );
+ }
+
+ ParseWaveForm( text, &ds->deformationWave );
+ ds->deformation = DEFORM_WAVE;
+ return;
+ }
+
+ if ( !Q_stricmp( token, "normal" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->deformationWave.amplitude = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->deformationWave.frequency = atof( token );
+
+ ds->deformation = DEFORM_NORMALS;
+ return;
+ }
+
+ if ( !Q_stricmp( token, "move" ) ) {
+ int i;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->moveVector[i] = atof( token );
+ }
+
+ ParseWaveForm( text, &ds->deformationWave );
+ ds->deformation = DEFORM_MOVE;
+ return;
+ }
+
+ ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name );
+}
+
+
+/*
+===============
+ParseSkyParms
+
+skyParms <outerbox> <cloudheight> <innerbox>
+===============
+*/
+static void ParseSkyParms( char **text ) {
+ char *token;
+ const char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+ char pathname[MAX_QPATH];
+ int i;
+ int/*imgFlags_t*/ imgFlags = IMGFLAG_MIPMAP | IMGFLAG_PICMIP;
+
+ // outerbox
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
+ return;
+ }
+ if ( strcmp( token, "-" ) ) {
+ for (i=0 ; i<6 ; i++) {
+ Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
+ , token, suf[i] );
+ shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags | IMGFLAG_CLAMPTOEDGE );
+
+ if ( !shader.sky.outerbox[i] ) {
+ shader.sky.outerbox[i] = tr.defaultImage;
+ }
+ }
+ }
+
+ // cloudheight
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
+ return;
+ }
+ shader.sky.cloudHeight = atof( token );
+ if ( !shader.sky.cloudHeight ) {
+ shader.sky.cloudHeight = 512;
+ }
+ R_InitSkyTexCoords( shader.sky.cloudHeight );
+
+
+ // innerbox
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
+ return;
+ }
+ if ( strcmp( token, "-" ) ) {
+ for (i=0 ; i<6 ; i++) {
+ Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
+ , token, suf[i] );
+ shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags );
+ if ( !shader.sky.innerbox[i] ) {
+ shader.sky.innerbox[i] = tr.defaultImage;
+ }
+ }
+ }
+
+ shader.isSky = true;
+}
+
+
+/*
+=================
+ParseSort
+=================
+*/
+void ParseSort( char **text ) {
+ char *token;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name );
+ return;
+ }
+
+ if ( !Q_stricmp( token, "portal" ) ) {
+ shader.sort = SS_PORTAL;
+ } else if ( !Q_stricmp( token, "sky" ) ) {
+ shader.sort = SS_ENVIRONMENT;
+ } else if ( !Q_stricmp( token, "opaque" ) ) {
+ shader.sort = SS_OPAQUE;
+ }else if ( !Q_stricmp( token, "decal" ) ) {
+ shader.sort = SS_DECAL;
+ } else if ( !Q_stricmp( token, "seeThrough" ) ) {
+ shader.sort = SS_SEE_THROUGH;
+ } else if ( !Q_stricmp( token, "banner" ) ) {
+ shader.sort = SS_BANNER;
+ } else if ( !Q_stricmp( token, "additive" ) ) {
+ shader.sort = SS_BLEND1;
+ } else if ( !Q_stricmp( token, "nearest" ) ) {
+ shader.sort = SS_NEAREST;
+ } else if ( !Q_stricmp( token, "underwater" ) ) {
+ shader.sort = SS_UNDERWATER;
+ } else {
+ shader.sort = atof( token );
+ }
+}
+
+
+
+// this table is also present in q3map
+
+struct infoParm_t {
+ const char *name;
+ unsigned clearSolid, surfaceFlags, contents;
+};
+
+infoParm_t infoParms[] = {
+ // server relevant contents
+ {"water", 1, 0, CONTENTS_WATER },
+ {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging
+ {"lava", 1, 0, CONTENTS_LAVA }, // very damaging
+ {"playerclip", 1, 0, CONTENTS_PLAYERCLIP },
+ {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP },
+ {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc)
+ {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag
+
+ // utility relevant attributes
+ {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes
+ {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces
+ {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp
+ {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas
+ {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas
+ {"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots
+ {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots
+
+ {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering
+ {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map
+ {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it
+ {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis
+ {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter
+
+ // server attributes
+ {"slick", 0, SURF_SLICK, 0 },
+ {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks
+ {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode
+ {"ladder", 0, SURF_LADDER, 0 },
+ {"nodamage", 0, SURF_NODAMAGE, 0 },
+ {"metalsteps", 0, SURF_METALSTEPS,0 },
+ {"flesh", 0, SURF_FLESH, 0 },
+ {"nosteps", 0, SURF_NOSTEPS, 0 },
+
+ // drawsurf attributes
+ {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap)
+ {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes
+ {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap
+ {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights
+ {"dust", 0, SURF_DUST, 0} // leave a dust trail when walking on this surface
+};
+
+
+/*
+===============
+ParseSurfaceParm
+
+surfaceparm <name>
+===============
+*/
+static void ParseSurfaceParm( char **text ) {
+ char *token;
+ int numInfoParms = ARRAY_LEN( infoParms );
+ int i;
+
+ token = COM_ParseExt( text, qfalse );
+ for ( i = 0 ; i < numInfoParms ; i++ ) {
+ if ( !Q_stricmp( token, infoParms[i].name ) ) {
+ shader.surfaceFlags |= infoParms[i].surfaceFlags;
+ shader.contentFlags |= infoParms[i].contents;
+#if 0
+ if ( infoParms[i].clearSolid ) {
+ si->contents &= ~CONTENTS_SOLID;
+ }
+#endif
+ break;
+ }
+ }
+}
+
+/*
+=================
+ParseShader
+
+The current text pointer is at the explicit text definition of the
+shader. Parse it into the global shader variable. Later functions
+will optimize it.
+=================
+*/
+static bool ParseShader( char **text )
+{
+ char *token;
+ int s;
+
+ s = 0;
+
+ token = COM_ParseExt( text, qtrue );
+ if ( token[0] != '{' )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name );
+ return false;
+ }
+
+ while ( 1 )
+ {
+ token = COM_ParseExt( text, qtrue );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name );
+ return false;
+ }
+
+ // end of shader definition
+ if ( token[0] == '}' )
+ {
+ break;
+ }
+ // stage definition
+ else if ( token[0] == '{' )
+ {
+ if ( s >= MAX_SHADER_STAGES ) {
+ ri.Printf( PRINT_WARNING, "WARNING: too many stages in shader %s (max is %i)\n", shader.name, MAX_SHADER_STAGES );
+ return false;
+ }
+
+ if ( !ParseStage( &stages[s], text ) )
+ {
+ return false;
+ }
+ stages[s].active = true;
+ s++;
+
+ continue;
+ }
+ // skip stuff that only the QuakeEdRadient needs
+ else if ( !Q_stricmpn( token, "qer", 3 ) ) {
+ SkipRestOfLine( text );
+ continue;
+ }
+ // sun parms
+ else if ( !Q_stricmp( token, "q3map_sun" ) || !Q_stricmp( token, "q3map_sunExt" ) ) {
+ float a, b;
+
+ token = COM_ParseExt( text, qfalse );
+ tr.sunLight[0] = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ tr.sunLight[1] = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ tr.sunLight[2] = atof( token );
+
+ VectorNormalize( tr.sunLight );
+
+ token = COM_ParseExt( text, qfalse );
+ a = atof( token );
+ VectorScale( tr.sunLight, a, tr.sunLight);
+
+ token = COM_ParseExt( text, qfalse );
+ a = atof( token );
+ a = a / 180 * M_PI;
+
+ token = COM_ParseExt( text, qfalse );
+ b = atof( token );
+ b = b / 180 * M_PI;
+
+ tr.sunDirection[0] = cos( a ) * cos( b );
+ tr.sunDirection[1] = sin( a ) * cos( b );
+ tr.sunDirection[2] = sin( b );
+
+ SkipRestOfLine( text );
+ continue;
+ }
+ else if ( !Q_stricmp( token, "deformVertexes" ) ) {
+ ParseDeform( text );
+ continue;
+ }
+ else if ( !Q_stricmp( token, "tesssize" ) ) {
+ SkipRestOfLine( text );
+ continue;
+ }
+ else if ( !Q_stricmp( token, "clampTime" ) ) {
+ token = COM_ParseExt( text, qfalse );
+ if (token[0]) {
+ shader.clampTime = atof(token);
+ }
+ }
+ // skip stuff that only the q3map needs
+ else if ( !Q_stricmpn( token, "q3map", 5 ) ) {
+ SkipRestOfLine( text );
+ continue;
+ }
+ // skip stuff that only q3map or the server needs
+ else if ( !Q_stricmp( token, "surfaceParm" ) ) {
+ ParseSurfaceParm( text );
+ continue;
+ }
+ // no mip maps
+ else if ( !Q_stricmp( token, "nomipmaps" ) )
+ {
+ shader.noMipMaps = true;
+ shader.noPicMip = true;
+ continue;
+ }
+ // no picmip adjustment
+ else if ( !Q_stricmp( token, "nopicmip" ) )
+ {
+ shader.noPicMip = true;
+ continue;
+ }
+ // polygonOffset
+ else if ( !Q_stricmp( token, "polygonOffset" ) )
+ {
+ shader.polygonOffset = true;
+ continue;
+ }
+ // entityMergable, allowing sprite surfaces from multiple entities
+ // to be merged into one batch. This is a savings for smoke
+ // puffs and blood, but can't be used for anything where the
+ // shader calcs (not the surface function) reference the entity color or scroll
+ else if ( !Q_stricmp( token, "entityMergable" ) )
+ {
+ shader.entityMergable = true;
+ continue;
+ }
+ // fogParms
+ else if ( !Q_stricmp( token, "fogParms" ) )
+ {
+ if ( !ParseVector( text, 3, shader.fogParms.color ) ) {
+ return false;
+ }
+
+ if ( r_greyscale->integer )
+ {
+ float luminance;
+
+ luminance = LUMA( shader.fogParms.color[0], shader.fogParms.color[1], shader.fogParms.color[2] );
+ VectorSet( shader.fogParms.color, luminance, luminance, luminance );
+ }
+ else if ( r_greyscale->value )
+ {
+ float luminance;
+
+ luminance = LUMA( shader.fogParms.color[0], shader.fogParms.color[1], shader.fogParms.color[2] );
+ shader.fogParms.color[0] = LERP( shader.fogParms.color[0], luminance, r_greyscale->value );
+ shader.fogParms.color[1] = LERP( shader.fogParms.color[1], luminance, r_greyscale->value );
+ shader.fogParms.color[2] = LERP( shader.fogParms.color[2], luminance, r_greyscale->value );
+ }
+
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name );
+ continue;
+ }
+ shader.fogParms.depthForOpaque = atof( token );
+
+ // skip any old gradient directions
+ SkipRestOfLine( text );
+ continue;
+ }
+ // portal
+ else if ( !Q_stricmp(token, "portal") )
+ {
+ shader.sort = SS_PORTAL;
+ continue;
+ }
+ // skyparms <cloudheight> <outerbox> <innerbox>
+ else if ( !Q_stricmp( token, "skyparms" ) )
+ {
+ ParseSkyParms( text );
+ continue;
+ }
+ // light <value> determines flaring in q3map, not needed here
+ else if ( !Q_stricmp(token, "light") )
+ {
+ (void)COM_ParseExt( text, qfalse );
+ continue;
+ }
+ // cull <face>
+ else if ( !Q_stricmp( token, "cull") )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) )
+ {
+ shader.cullType = CT_TWO_SIDED;
+ }
+ else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) )
+ {
+ shader.cullType = CT_BACK_SIDED;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name );
+ }
+ continue;
+ }
+ // sort
+ else if ( !Q_stricmp( token, "sort" ) )
+ {
+ ParseSort( text );
+ continue;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name );
+ return false;
+ }
+ }
+
+ //
+ // ignore shaders that don't have any stages, unless it is a sky or fog
+ //
+ if ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) {
+ return false;
+ }
+
+ shader.explicitlyDefined = true;
+
+ return true;
+}
+
+/*
+========================================================================================
+
+SHADER OPTIMIZATION AND FOGGING
+
+========================================================================================
+*/
+
+/*
+===================
+ComputeStageIteratorFunc
+
+See if we can use on of the simple fastpath stage functions,
+otherwise set to the generic stage function
+===================
+*/
+static void ComputeStageIteratorFunc( void )
+{
+ shader.optimalStageIteratorFunc = RB_StageIteratorGeneric;
+
+ //
+ // see if this should go into the sky path
+ //
+ if ( shader.isSky )
+ {
+ shader.optimalStageIteratorFunc = RB_StageIteratorSky;
+ return;
+ }
+
+ if ( r_ignoreFastPath->integer )
+ {
+ return;
+ }
+
+ //
+ // see if this can go into the vertex lit fast path
+ //
+ if ( shader.numUnfoggedPasses == 1 )
+ {
+ if ( stages[0].rgbGen == CGEN_LIGHTING_DIFFUSE )
+ {
+ if ( stages[0].alphaGen == AGEN_IDENTITY )
+ {
+ if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE )
+ {
+ if ( !shader.polygonOffset )
+ {
+ if ( !shader.multitextureEnv )
+ {
+ if ( !shader.numDeforms )
+ {
+ shader.optimalStageIteratorFunc = RB_StageIteratorVertexLitTexture;
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // see if this can go into an optimized LM, multitextured path
+ //
+ if ( shader.numUnfoggedPasses == 1 )
+ {
+ if ( ( stages[0].rgbGen == CGEN_IDENTITY ) && ( stages[0].alphaGen == AGEN_IDENTITY ) )
+ {
+ if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE &&
+ stages[0].bundle[1].tcGen == TCGEN_LIGHTMAP )
+ {
+ if ( !shader.polygonOffset )
+ {
+ if ( !shader.numDeforms )
+ {
+ if ( shader.multitextureEnv )
+ {
+ shader.optimalStageIteratorFunc = RB_StageIteratorLightmappedMultitexture;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+typedef struct {
+ int blendA;
+ int blendB;
+
+ int multitextureEnv;
+ int multitextureBlend;
+} collapse_t;
+
+static collapse_t collapse[] = {
+ { 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
+ GL_MODULATE, 0 },
+
+ { 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
+ GL_MODULATE, 0 },
+
+ { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
+ GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
+
+ { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
+ GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
+
+ { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
+ GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
+
+ { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
+ GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
+
+ { 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
+ GL_ADD, 0 },
+
+ { GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
+ GL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE },
+#if 0
+ { 0, GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA,
+ GL_DECAL, 0 },
+#endif
+ { -1 }
+};
+
+/*
+================
+CollapseMultitexture
+
+Attempt to combine two stages into a single multitexture stage
+FIXME: I think modulated add + modulated add collapses incorrectly
+=================
+*/
+static bool CollapseMultitexture( void ) {
+ int abits, bbits;
+ int i;
+ textureBundle_t tmpBundle;
+
+ if ( !qglActiveTextureARB ) {
+ return false;
+ }
+
+ // make sure both stages are active
+ if ( !stages[0].active || !stages[1].active ) {
+ return false;
+ }
+
+ // on voodoo2, don't combine different tmus
+ if ( glConfig.driverType == GLDRV_VOODOO ) {
+ if ( stages[0].bundle[0].image[0]->TMU ==
+ stages[1].bundle[0].image[0]->TMU ) {
+ return false;
+ }
+ }
+
+ abits = stages[0].stateBits;
+ bbits = stages[1].stateBits;
+
+ // make sure that both stages have identical state other than blend modes
+ if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) !=
+ ( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) {
+ return false;
+ }
+
+ abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
+ bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
+
+ // search for a valid multitexture blend function
+ for ( i = 0; collapse[i].blendA != -1 ; i++ ) {
+ if ( abits == collapse[i].blendA
+ && bbits == collapse[i].blendB ) {
+ break;
+ }
+ }
+
+ // nothing found
+ if ( collapse[i].blendA == -1 ) {
+ return false;
+ }
+
+ // GL_ADD is a separate extension
+ if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) {
+ return false;
+ }
+
+ // make sure waveforms have identical parameters
+ if ( ( stages[0].rgbGen != stages[1].rgbGen ) ||
+ ( stages[0].alphaGen != stages[1].alphaGen ) ) {
+ return false;
+ }
+
+ // an add collapse can only have identity colors
+ if ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) {
+ return false;
+ }
+
+ if ( stages[0].rgbGen == CGEN_WAVEFORM )
+ {
+ if ( memcmp( &stages[0].rgbWave,
+ &stages[1].rgbWave,
+ sizeof( stages[0].rgbWave ) ) )
+ {
+ return false;
+ }
+ }
+ if ( stages[0].alphaGen == AGEN_WAVEFORM )
+ {
+ if ( memcmp( &stages[0].alphaWave,
+ &stages[1].alphaWave,
+ sizeof( stages[0].alphaWave ) ) )
+ {
+ return false;
+ }
+ }
+
+
+ // make sure that lightmaps are in bundle 1 for 3dfx
+ if ( stages[0].bundle[0].isLightmap )
+ {
+ tmpBundle = stages[0].bundle[0];
+ stages[0].bundle[0] = stages[1].bundle[0];
+ stages[0].bundle[1] = tmpBundle;
+ }
+ else
+ {
+ stages[0].bundle[1] = stages[1].bundle[0];
+ }
+
+ // set the new blend state bits
+ shader.multitextureEnv = collapse[i].multitextureEnv;
+ stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
+ stages[0].stateBits |= collapse[i].multitextureBlend;
+
+ //
+ // move down subsequent shaders
+ //
+ memmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) );
+ Com_Memset( &stages[MAX_SHADER_STAGES-1], 0, sizeof( stages[0] ) );
+
+ return true;
+}
+
+/*
+=============
+
+FixRenderCommandList
+https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
+Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated
+but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces
+to be rendered with bad shaders. To fix this, need to go through all render commands and fix
+sortedIndex.
+==============
+*/
+static void FixRenderCommandList( int newShader ) {
+ renderCommandList_t *cmdList = &backEndData->commands;
+
+ if( cmdList ) {
+ const void *curCmd = cmdList->cmds;
+
+ while ( 1 ) {
+ curCmd = PADP(curCmd, sizeof(void *));
+
+ switch ( *(const int *)curCmd ) {
+ case RC_SET_COLOR:
+ {
+ const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd;
+ curCmd = (const void *)(sc_cmd + 1);
+ break;
+ }
+ case RC_STRETCH_PIC:
+ {
+ const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd;
+ curCmd = (const void *)(sp_cmd + 1);
+ break;
+ }
+ case RC_DRAW_SURFS:
+ {
+ int i;
+ drawSurf_t *drawSurf;
+ shader_t *shader;
+ int fogNum;
+ int entityNum;
+ int dlightMap;
+ int sortedIndex;
+ const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd;
+
+ for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) {
+ R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap );
+ sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1));
+ if( sortedIndex >= newShader ) {
+ sortedIndex++;
+ drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
+ }
+ }
+ curCmd = (const void *)(ds_cmd + 1);
+ break;
+ }
+ case RC_DRAW_BUFFER:
+ {
+ const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd;
+ curCmd = (const void *)(db_cmd + 1);
+ break;
+ }
+ case RC_SWAP_BUFFERS:
+ {
+ const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd;
+ curCmd = (const void *)(sb_cmd + 1);
+ break;
+ }
+ case RC_END_OF_LIST:
+ default:
+ return;
+ }
+ }
+ }
+}
+
+/*
+==============
+SortNewShader
+
+Positions the most recently created shader in the tr.sortedShaders[]
+array so that the shader->sort key is sorted relative to the other
+shaders.
+
+Sets shader->sortedIndex
+==============
+*/
+static void SortNewShader( void ) {
+ int i;
+ float sort;
+ shader_t *newShader;
+
+ newShader = tr.shaders[ tr.numShaders - 1 ];
+ sort = newShader->sort;
+
+ for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) {
+ if ( tr.sortedShaders[ i ]->sort <= sort ) {
+ break;
+ }
+ tr.sortedShaders[i+1] = tr.sortedShaders[i];
+ tr.sortedShaders[i+1]->sortedIndex++;
+ }
+
+ // Arnout: fix rendercommandlist
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
+ FixRenderCommandList( i+1 );
+
+ newShader->sortedIndex = i+1;
+ tr.sortedShaders[i+1] = newShader;
+}
+
+
+/*
+====================
+GeneratePermanentShader
+====================
+*/
+static shader_t *GeneratePermanentShader( void ) {
+ shader_t *newShader;
+ int i, b;
+ int size, hash;
+
+ if ( tr.numShaders == MAX_SHADERS ) {
+ ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n");
+ return tr.defaultShader;
+ }
+
+ newShader = (shader_t*)ri.Hunk_Alloc( sizeof( shader_t ), h_low );
+
+ *newShader = shader;
+
+ if ( shader.sort <= SS_OPAQUE ) {
+ newShader->fogPass = FP_EQUAL;
+ } else if ( shader.contentFlags & CONTENTS_FOG ) {
+ newShader->fogPass = FP_LE;
+ }
+
+ tr.shaders[ tr.numShaders ] = newShader;
+ newShader->index = tr.numShaders;
+
+ tr.sortedShaders[ tr.numShaders ] = newShader;
+ newShader->sortedIndex = tr.numShaders;
+
+ tr.numShaders++;
+
+ for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) {
+ if ( !stages[i].active ) {
+ break;
+ }
+ newShader->stages[i] = (shaderStage_t*)ri.Hunk_Alloc( sizeof( stages[i] ), h_low );
+ *newShader->stages[i] = stages[i];
+
+ for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) {
+ size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t );
+ newShader->stages[i]->bundle[b].texMods = (texModInfo_t*)ri.Hunk_Alloc( size, h_low );
+ Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size );
+ }
+ }
+
+ SortNewShader();
+
+ hash = generateHashValue(newShader->name, FILE_HASH_SIZE);
+ newShader->next = hashTable[hash];
+ hashTable[hash] = newShader;
+
+ return newShader;
+}
+
+/*
+=================
+VertexLightingCollapse
+
+If vertex lighting is enabled, only render a single
+pass, trying to guess which is the correct one to best aproximate
+what it is supposed to look like.
+=================
+*/
+static void VertexLightingCollapse( void ) {
+ int stage;
+ shaderStage_t *bestStage;
+ int bestImageRank;
+ int rank;
+
+ // if we aren't opaque, just use the first pass
+ if ( shader.sort == SS_OPAQUE ) {
+
+ // pick the best texture for the single pass
+ bestStage = &stages[0];
+ bestImageRank = -999999;
+
+ for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {
+ shaderStage_t *pStage = &stages[stage];
+
+ if ( !pStage->active ) {
+ break;
+ }
+ rank = 0;
+
+ if ( pStage->bundle[0].isLightmap ) {
+ rank -= 100;
+ }
+ if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) {
+ rank -= 5;
+ }
+ if ( pStage->bundle[0].numTexMods ) {
+ rank -= 5;
+ }
+ if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) {
+ rank -= 3;
+ }
+
+ if ( rank > bestImageRank ) {
+ bestImageRank = rank;
+ bestStage = pStage;
+ }
+ }
+
+ stages[0].bundle[0] = bestStage->bundle[0];
+ stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
+ stages[0].stateBits |= GLS_DEPTHMASK_TRUE;
+ if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
+ stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
+ } else {
+ stages[0].rgbGen = CGEN_EXACT_VERTEX;
+ }
+ stages[0].alphaGen = AGEN_SKIP;
+ } else {
+ // don't use a lightmap (tesla coils)
+ if ( stages[0].bundle[0].isLightmap ) {
+ stages[0] = stages[1];
+ }
+
+ // if we were in a cross-fade cgen, hack it to normal
+ if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) {
+ stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
+ }
+ if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH )
+ && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) {
+ stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
+ }
+ if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH )
+ && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) {
+ stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
+ }
+ }
+
+ for ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) {
+ shaderStage_t *pStage = &stages[stage];
+
+ if ( !pStage->active ) {
+ break;
+ }
+
+ Com_Memset( pStage, 0, sizeof( *pStage ) );
+ }
+}
+
+/*
+===============
+InitShader
+===============
+*/
+static void InitShader( const char *name, int lightmapIndex ) {
+ int i;
+
+ // clear the global shader
+ Com_Memset( &shader, 0, sizeof( shader ) );
+ Com_Memset( &stages, 0, sizeof( stages ) );
+
+ Q_strncpyz( shader.name, name, sizeof( shader.name ) );
+ shader.lightmapIndex = lightmapIndex;
+
+ for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
+ stages[i].bundle[0].texMods = texMods[i];
+ }
+}
+
+/*
+=========================
+FinishShader
+
+Returns a freshly allocated shader with all the needed info
+from the current global working shader
+=========================
+*/
+static shader_t *FinishShader( void ) {
+ int stage;
+ bool hasLightmapStage;
+ bool vertexLightmap;
+
+ hasLightmapStage = false;
+ vertexLightmap = false;
+
+ //
+ // set sky stuff appropriate
+ //
+ if ( shader.isSky ) {
+ shader.sort = SS_ENVIRONMENT;
+ }
+
+ //
+ // set polygon offset
+ //
+ if ( shader.polygonOffset && !shader.sort ) {
+ shader.sort = SS_DECAL;
+ }
+
+ //
+ // set appropriate stage information
+ //
+ for ( stage = 0; stage < MAX_SHADER_STAGES; ) {
+ shaderStage_t *pStage = &stages[stage];
+
+ if ( !pStage->active ) {
+ break;
+ }
+
+ // check for a missing texture
+ if ( !pStage->bundle[0].image[0] ) {
+ ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name );
+ pStage->active = false;
+ stage++;
+ continue;
+ }
+
+ //
+ // ditch this stage if it's detail and detail textures are disabled
+ //
+ if ( pStage->isDetail && !r_detailTextures->integer )
+ {
+ int index;
+
+ for(index = stage + 1; index < MAX_SHADER_STAGES; index++)
+ {
+ if(!stages[index].active)
+ break;
+ }
+
+ if(index < MAX_SHADER_STAGES)
+ memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage));
+ else
+ {
+ if(stage + 1 < MAX_SHADER_STAGES)
+ memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage - 1));
+
+ Com_Memset(&stages[index - 1], 0, sizeof(*stages));
+ }
+
+ continue;
+ }
+
+ //
+ // default texture coordinate generation
+ //
+ if ( pStage->bundle[0].isLightmap ) {
+ if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
+ pStage->bundle[0].tcGen = TCGEN_LIGHTMAP;
+ }
+ hasLightmapStage = true;
+ } else {
+ if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
+ pStage->bundle[0].tcGen = TCGEN_TEXTURE;
+ }
+ }
+
+
+ // not a true lightmap but we want to leave existing
+ // behaviour in place and not print out a warning
+ //if (pStage->rgbGen == CGEN_VERTEX) {
+ // vertexLightmap = true;
+ //}
+
+
+
+ //
+ // determine sort order and fog color adjustment
+ //
+ if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) &&
+ ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) {
+ int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS;
+ int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS;
+
+ // fog color adjustment only works for blend modes that have a contribution
+ // that aproaches 0 as the modulate values aproach 0 --
+ // GL_ONE, GL_ONE
+ // GL_ZERO, GL_ONE_MINUS_SRC_COLOR
+ // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
+
+ // modulate, additive
+ if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) ||
+ ( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) {
+ pStage->adjustColorsForFog = ACFF_MODULATE_RGB;
+ }
+ // strict blend
+ else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
+ {
+ pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA;
+ }
+ // premultiplied alpha
+ else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
+ {
+ pStage->adjustColorsForFog = ACFF_MODULATE_RGBA;
+ } else {
+ // we can't adjust this one correctly, so it won't be exactly correct in fog
+ }
+
+ // don't screw with sort order if this is a portal or environment
+ if ( !shader.sort ) {
+ // see through item, like a grill or grate
+ if ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) {
+ shader.sort = SS_SEE_THROUGH;
+ } else {
+ shader.sort = SS_BLEND0;
+ }
+ }
+ }
+
+ stage++;
+ }
+
+ // there are times when you will need to manually apply a sort to
+ // opaque alpha tested shaders that have later blend passes
+ if ( !shader.sort ) {
+ shader.sort = SS_OPAQUE;
+ }
+
+ //
+ // if we are in r_vertexLight mode, never use a lightmap texture
+ //
+ if ( stage > 1 && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) {
+ VertexLightingCollapse();
+ stage = 1;
+ hasLightmapStage = false;
+ }
+
+ //
+ // look for multitexture potential
+ //
+ if ( stage > 1 && CollapseMultitexture() ) {
+ stage--;
+ }
+
+ if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) {
+ if (vertexLightmap) {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name );
+ } else {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name );
+ shader.lightmapIndex = LIGHTMAP_NONE;
+ }
+ }
+
+
+ //
+ // compute number of passes
+ //
+ shader.numUnfoggedPasses = stage;
+
+ // fogonly shaders don't have any normal passes
+ if (stage == 0 && !shader.isSky)
+ shader.sort = SS_FOG;
+
+ // determine which stage iterator function is appropriate
+ ComputeStageIteratorFunc();
+
+ return GeneratePermanentShader();
+}
+
+//========================================================================================
+
+/*
+====================
+FindShaderInShaderText
+
+Scans the combined text description of all the shader files for
+the given shader name.
+
+return NULL if not found
+
+If found, it will return a valid shader
+=====================
+*/
+static char *FindShaderInShaderText( const char *shadername ) {
+
+ char *token, *p;
+
+ int i, hash;
+
+ hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH);
+
+ if(shaderTextHashTable[hash])
+ {
+ for (i = 0; shaderTextHashTable[hash][i]; i++)
+ {
+ p = shaderTextHashTable[hash][i];
+ token = COM_ParseExt(&p, qtrue);
+
+ if(!Q_stricmp(token, shadername))
+ return p;
+ }
+ }
+
+ p = s_shaderText;
+
+ if ( !p ) {
+ return NULL;
+ }
+
+ // look for label
+ while ( 1 ) {
+ token = COM_ParseExt( &p, qtrue );
+ if ( token[0] == 0 ) {
+ break;
+ }
+
+ if ( !Q_stricmp( token, shadername ) ) {
+ return p;
+ }
+ else {
+ // skip the definition
+ SkipBracedSection( &p, 0 );
+ }
+ }
+
+ return NULL;
+}
+
+
+/*
+==================
+R_FindShaderByName
+
+Will always return a valid shader, but it might be the
+default shader if the real one can't be found.
+==================
+*/
+shader_t *R_FindShaderByName( const char *name ) {
+ char strippedName[MAX_QPATH];
+ int hash;
+ shader_t *sh;
+
+ if ( (name==NULL) || (name[0] == 0) ) {
+ return tr.defaultShader;
+ }
+
+ COM_StripExtension(name, strippedName, sizeof(strippedName));
+
+ hash = generateHashValue(strippedName, FILE_HASH_SIZE);
+
+ //
+ // see if the shader is already loaded
+ //
+ for (sh=hashTable[hash]; sh; sh=sh->next) {
+ // NOTE: if there was no shader or image available with the name strippedName
+ // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
+ // have to check all default shaders otherwise for every call to R_FindShader
+ // with that same strippedName a new default shader is created.
+ if (Q_stricmp(sh->name, strippedName) == 0) {
+ // match found
+ return sh;
+ }
+ }
+
+ return tr.defaultShader;
+}
+
+
+/*
+===============
+R_FindShader
+
+Will always return a valid shader, but it might be the
+default shader if the real one can't be found.
+
+In the interest of not requiring an explicit shader text entry to
+be defined for every single image used in the game, three default
+shader behaviors can be auto-created for any image:
+
+If lightmapIndex == LIGHTMAP_NONE, then the image will have
+dynamic diffuse lighting applied to it, as apropriate for most
+entity skin surfaces.
+
+If lightmapIndex == LIGHTMAP_2D, then the image will be used
+for 2D rendering unless an explicit shader is found
+
+If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use
+the vertex rgba modulate values, as apropriate for misc_model
+pre-lit surfaces.
+
+Other lightmapIndex values will have a lightmap stage created
+and src*dest blending applied with the texture, as apropriate for
+most world construction surfaces.
+
+===============
+*/
+shader_t *R_FindShader( const char *name, int lightmapIndex, bool mipRawImage ) {
+ char strippedName[MAX_QPATH];
+ int hash;
+ char *shaderText;
+ image_t *image;
+ shader_t *sh;
+
+ if ( name[0] == 0 ) {
+ return tr.defaultShader;
+ }
+
+ // use (fullbright) vertex lighting if the bsp file doesn't have
+ // lightmaps
+ if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) {
+ lightmapIndex = LIGHTMAP_BY_VERTEX;
+ } else if ( lightmapIndex < LIGHTMAP_2D ) {
+ // negative lightmap indexes cause stray pointers (think tr.lightmaps[lightmapIndex])
+ ri.Printf( PRINT_WARNING, "WARNING: shader '%s' has invalid lightmap index of %d\n", name, lightmapIndex );
+ lightmapIndex = LIGHTMAP_BY_VERTEX;
+ }
+
+ COM_StripExtension(name, strippedName, sizeof(strippedName));
+
+ hash = generateHashValue(strippedName, FILE_HASH_SIZE);
+
+ //
+ // see if the shader is already loaded
+ //
+ for (sh = hashTable[hash]; sh; sh = sh->next) {
+ // NOTE: if there was no shader or image available with the name strippedName
+ // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
+ // have to check all default shaders otherwise for every call to R_FindShader
+ // with that same strippedName a new default shader is created.
+ if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&
+ !Q_stricmp(sh->name, strippedName)) {
+ // match found
+ return sh;
+ }
+ }
+
+ InitShader( strippedName, lightmapIndex );
+
+ // FIXME: set these "need" values apropriately
+ shader.needsNormal = true;
+ shader.needsST1 = true;
+ shader.needsST2 = true;
+ shader.needsColor = true;
+
+ //
+ // attempt to define shader from an explicit parameter file
+ //
+ shaderText = FindShaderInShaderText( strippedName );
+ if ( shaderText ) {
+ // enable this when building a pak file to get a global list
+ // of all explicit shaders
+ if ( r_printShaders->integer ) {
+ ri.Printf( PRINT_ALL, "*SHADER* %s\n", name );
+ }
+
+ if ( !ParseShader( &shaderText ) ) {
+ // had errors, so use default shader
+ shader.defaultShader = true;
+ }
+ sh = FinishShader();
+ return sh;
+ }
+
+
+ //
+ // if not defined in the in-memory shader descriptions,
+ // look for a single supported image file
+ //
+ {
+ int/*imgFlags_t*/ flags;
+
+ flags = IMGFLAG_NONE;
+
+ if (mipRawImage)
+ {
+ flags |= IMGFLAG_MIPMAP | IMGFLAG_PICMIP;
+ }
+ else
+ {
+ flags |= IMGFLAG_CLAMPTOEDGE;
+ }
+
+ image = R_FindImageFile( name, IMGTYPE_COLORALPHA, flags );
+ if ( !image ) {
+ ri.Printf( PRINT_DEVELOPER, "Couldn't find image file for shader %s\n", name );
+ shader.defaultShader = true;
+ return FinishShader();
+ }
+ }
+
+ //
+ // create the default shading commands
+ //
+ if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
+ // dynamic colors at vertexes
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
+ stages[0].stateBits = GLS_DEFAULT;
+ } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
+ // explicit colors at vertexes
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_EXACT_VERTEX;
+ stages[0].alphaGen = AGEN_SKIP;
+ stages[0].stateBits = GLS_DEFAULT;
+ } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
+ // GUI elements
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_VERTEX;
+ stages[0].alphaGen = AGEN_VERTEX;
+ stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
+ GLS_SRCBLEND_SRC_ALPHA |
+ GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
+ } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
+ // fullbright level
+ stages[0].bundle[0].image[0] = tr.whiteImage;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
+ stages[0].stateBits = GLS_DEFAULT;
+
+ stages[1].bundle[0].image[0] = image;
+ stages[1].active = true;
+ stages[1].rgbGen = CGEN_IDENTITY;
+ stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
+ } else {
+ // two pass lightmap
+ stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
+ stages[0].bundle[0].isLightmap = true;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
+ // for identitylight
+ stages[0].stateBits = GLS_DEFAULT;
+
+ stages[1].bundle[0].image[0] = image;
+ stages[1].active = true;
+ stages[1].rgbGen = CGEN_IDENTITY;
+ stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
+ }
+
+ return FinishShader();
+}
+
+
+qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, bool mipRawImage) {
+ int hash;
+ shader_t *sh;
+
+ hash = generateHashValue(name, FILE_HASH_SIZE);
+
+ // probably not necessary since this function
+ // only gets called from tr_font.c with lightmapIndex == LIGHTMAP_2D
+ // but better safe than sorry.
+ if ( lightmapIndex >= tr.numLightmaps ) {
+ lightmapIndex = LIGHTMAP_WHITEIMAGE;
+ }
+
+ //
+ // see if the shader is already loaded
+ //
+ for (sh=hashTable[hash]; sh; sh=sh->next) {
+ // NOTE: if there was no shader or image available with the name strippedName
+ // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
+ // have to check all default shaders otherwise for every call to R_FindShader
+ // with that same strippedName a new default shader is created.
+ if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&
+ // index by name
+ !Q_stricmp(sh->name, name)) {
+ // match found
+ return sh->index;
+ }
+ }
+
+ InitShader( name, lightmapIndex );
+
+ // FIXME: set these "need" values apropriately
+ shader.needsNormal = true;
+ shader.needsST1 = true;
+ shader.needsST2 = true;
+ shader.needsColor = true;
+
+ //
+ // create the default shading commands
+ //
+ if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
+ // dynamic colors at vertexes
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
+ stages[0].stateBits = GLS_DEFAULT;
+ } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
+ // explicit colors at vertexes
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_EXACT_VERTEX;
+ stages[0].alphaGen = AGEN_SKIP;
+ stages[0].stateBits = GLS_DEFAULT;
+ } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
+ // GUI elements
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_VERTEX;
+ stages[0].alphaGen = AGEN_VERTEX;
+ stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
+ GLS_SRCBLEND_SRC_ALPHA |
+ GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
+ } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
+ // fullbright level
+ stages[0].bundle[0].image[0] = tr.whiteImage;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
+ stages[0].stateBits = GLS_DEFAULT;
+
+ stages[1].bundle[0].image[0] = image;
+ stages[1].active = true;
+ stages[1].rgbGen = CGEN_IDENTITY;
+ stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
+ } else {
+ // two pass lightmap
+ stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
+ stages[0].bundle[0].isLightmap = true;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
+ // for identitylight
+ stages[0].stateBits = GLS_DEFAULT;
+
+ stages[1].bundle[0].image[0] = image;
+ stages[1].active = true;
+ stages[1].rgbGen = CGEN_IDENTITY;
+ stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
+ }
+
+ sh = FinishShader();
+ return sh->index;
+}
+
+
+/*
+====================
+RE_RegisterShader
+
+This is the exported shader entry point for the rest of the system
+It will always return an index that will be valid.
+
+This should really only be used for explicit shaders, because there is no
+way to ask for different implicit lighting modes (vertex, lightmap, etc)
+====================
+*/
+qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) {
+ shader_t *sh;
+
+ if ( strlen( name ) >= MAX_QPATH ) {
+ ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
+ return 0;
+ }
+
+ sh = R_FindShader( name, lightmapIndex, true );
+
+ // we want to return 0 if the shader failed to
+ // load for some reason, but R_FindShader should
+ // still keep a name allocated for it, so if
+ // something calls RE_RegisterShader again with
+ // the same name, we don't try looking for it again
+ if ( sh->defaultShader ) {
+ return 0;
+ }
+
+ return sh->index;
+}
+
+
+/*
+====================
+RE_RegisterShader
+
+This is the exported shader entry point for the rest of the system
+It will always return an index that will be valid.
+
+This should really only be used for explicit shaders, because there is no
+way to ask for different implicit lighting modes (vertex, lightmap, etc)
+====================
+*/
+qhandle_t RE_RegisterShader( const char *name ) {
+ shader_t *sh;
+
+ if ( strlen( name ) >= MAX_QPATH ) {
+ ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
+ return 0;
+ }
+
+ sh = R_FindShader( name, LIGHTMAP_2D, true );
+
+ // we want to return 0 if the shader failed to
+ // load for some reason, but R_FindShader should
+ // still keep a name allocated for it, so if
+ // something calls RE_RegisterShader again with
+ // the same name, we don't try looking for it again
+ if ( sh->defaultShader ) {
+ return 0;
+ }
+
+ return sh->index;
+}
+
+
+/*
+====================
+RE_RegisterShaderNoMip
+
+For menu graphics that should never be picmiped
+====================
+*/
+qhandle_t RE_RegisterShaderNoMip( const char *name ) {
+ shader_t *sh;
+
+ if ( strlen( name ) >= MAX_QPATH ) {
+ ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
+ return 0;
+ }
+
+ sh = R_FindShader( name, LIGHTMAP_2D, false );
+
+ // we want to return 0 if the shader failed to
+ // load for some reason, but R_FindShader should
+ // still keep a name allocated for it, so if
+ // something calls RE_RegisterShader again with
+ // the same name, we don't try looking for it again
+ if ( sh->defaultShader ) {
+ return 0;
+ }
+
+ return sh->index;
+}
+
+/*
+====================
+R_GetShaderByHandle
+
+When a handle is passed in by another module, this range checks
+it and returns a valid (possibly default) shader_t to be used internally.
+====================
+*/
+shader_t *R_GetShaderByHandle( qhandle_t hShader ) {
+ if ( hShader < 0 ) {
+ ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
+ return tr.defaultShader;
+ }
+ if ( hShader >= tr.numShaders ) {
+ ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
+ return tr.defaultShader;
+ }
+ return tr.shaders[hShader];
+}
+
+/*
+===============
+R_ShaderList_f
+
+Dump information on all valid shaders to the console
+A second parameter will cause it to print in sorted order
+===============
+*/
+void R_ShaderList_f (void) {
+ int i;
+ int count;
+ shader_t *shader;
+
+ ri.Printf (PRINT_ALL, "-----------------------\n");
+
+ count = 0;
+ for ( i = 0 ; i < tr.numShaders ; i++ ) {
+ if ( ri.Cmd_Argc() > 1 ) {
+ shader = tr.sortedShaders[i];
+ } else {
+ shader = tr.shaders[i];
+ }
+
+ ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses );
+
+ if (shader->lightmapIndex >= 0 ) {
+ ri.Printf (PRINT_ALL, "L ");
+ } else {
+ ri.Printf (PRINT_ALL, " ");
+ }
+ if ( shader->multitextureEnv == GL_ADD ) {
+ ri.Printf( PRINT_ALL, "MT(a) " );
+ } else if ( shader->multitextureEnv == GL_MODULATE ) {
+ ri.Printf( PRINT_ALL, "MT(m) " );
+ } else if ( shader->multitextureEnv == GL_DECAL ) {
+ ri.Printf( PRINT_ALL, "MT(d) " );
+ } else {
+ ri.Printf( PRINT_ALL, " " );
+ }
+ if ( shader->explicitlyDefined ) {
+ ri.Printf( PRINT_ALL, "E " );
+ } else {
+ ri.Printf( PRINT_ALL, " " );
+ }
+
+ if ( shader->optimalStageIteratorFunc == RB_StageIteratorGeneric ) {
+ ri.Printf( PRINT_ALL, "gen " );
+ } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorSky ) {
+ ri.Printf( PRINT_ALL, "sky " );
+ } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorLightmappedMultitexture ) {
+ ri.Printf( PRINT_ALL, "lmmt" );
+ } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorVertexLitTexture ) {
+ ri.Printf( PRINT_ALL, "vlt " );
+ } else {
+ ri.Printf( PRINT_ALL, " " );
+ }
+
+ if ( shader->defaultShader ) {
+ ri.Printf (PRINT_ALL, ": %s (DEFAULTED)\n", shader->name);
+ } else {
+ ri.Printf (PRINT_ALL, ": %s\n", shader->name);
+ }
+ count++;
+ }
+ ri.Printf (PRINT_ALL, "%i total shaders\n", count);
+ ri.Printf (PRINT_ALL, "------------------\n");
+}
+
+/*
+====================
+ScanAndLoadShaderFiles
+
+Finds and loads all .shader files, combining them into
+a single large text block that can be scanned for shader names
+=====================
+*/
+#define MAX_SHADER_FILES 4096
+static void ScanAndLoadShaderFiles( void )
+{
+ char **shaderFiles;
+ char *buffers[MAX_SHADER_FILES] = {0};
+ char *p;
+ int numShaderFiles;
+ int i;
+ char *oldp, *token, *hashMem, *textEnd;
+ int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size;
+ char shaderName[MAX_QPATH];
+ int shaderLine;
+
+ long sum = 0, summand;
+ // scan for shader files
+ shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles );
+
+ if ( !shaderFiles || !numShaderFiles )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" );
+ return;
+ }
+
+ if ( numShaderFiles > MAX_SHADER_FILES ) {
+ numShaderFiles = MAX_SHADER_FILES;
+ }
+
+ // load and parse shader files
+ for ( i = 0; i < numShaderFiles; i++ )
+ {
+ char filename[MAX_QPATH];
+
+ Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
+ ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename );
+ summand = ri.FS_ReadFile( filename, (void **)&buffers[i] );
+
+ if ( !buffers[i] )
+ ri.Error( ERR_DROP, "Couldn't load %s", filename );
+
+ // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders.
+ p = buffers[i];
+ COM_BeginParseSession(filename);
+ while(1)
+ {
+ token = COM_ParseExt(&p, qtrue);
+
+ if(!*token)
+ break;
+
+ Q_strncpyz(shaderName, token, sizeof(shaderName));
+ shaderLine = COM_GetCurrentParseLine();
+
+ token = COM_ParseExt(&p, qtrue);
+ if(token[0] != '{' || token[1] != '\0')
+ {
+ ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing opening brace",
+ filename, shaderName, shaderLine);
+ if (token[0])
+ {
+ ri.Printf(PRINT_WARNING, " (found \"%s\" on line %d)", token, COM_GetCurrentParseLine());
+ }
+ ri.Printf(PRINT_WARNING, ".\n");
+ ri.FS_FreeFile(buffers[i]);
+ buffers[i] = NULL;
+ break;
+ }
+
+ if(!SkipBracedSection(&p, 1))
+ {
+ ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n",
+ filename, shaderName, shaderLine);
+ ri.FS_FreeFile(buffers[i]);
+ buffers[i] = NULL;
+ break;
+ }
+ }
+
+
+ if (buffers[i])
+ sum += summand;
+ }
+
+ // build single large buffer
+ s_shaderText = (char*)ri.Hunk_Alloc( sum + numShaderFiles*2, h_low );
+ s_shaderText[ 0 ] = '\0';
+ textEnd = s_shaderText;
+
+ // free in reverse order, so the temp files are all dumped
+ for ( i = numShaderFiles - 1; i >= 0 ; i-- )
+ {
+ if ( !buffers[i] )
+ continue;
+
+ strcat( textEnd, buffers[i] );
+ strcat( textEnd, "\n" );
+ textEnd += strlen( textEnd );
+ ri.FS_FreeFile( buffers[i] );
+ }
+
+ COM_Compress( s_shaderText );
+
+ // free up memory
+ ri.FS_FreeFileList( shaderFiles );
+
+ Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
+ size = 0;
+
+ p = s_shaderText;
+ // look for shader names
+ while ( 1 ) {
+ token = COM_ParseExt( &p, qtrue );
+ if ( token[0] == 0 ) {
+ break;
+ }
+
+ hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
+ shaderTextHashTableSizes[hash]++;
+ size++;
+ SkipBracedSection(&p, 0);
+ }
+
+ size += MAX_SHADERTEXT_HASH;
+
+ hashMem = (char*)ri.Hunk_Alloc( size * sizeof(char *), h_low );
+
+ for (i = 0; i < MAX_SHADERTEXT_HASH; i++) {
+ shaderTextHashTable[i] = (char **) hashMem;
+ hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *));
+ }
+
+ Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
+
+ p = s_shaderText;
+ // look for shader names
+ while ( 1 ) {
+ oldp = p;
+ token = COM_ParseExt( &p, qtrue );
+ if ( token[0] == 0 ) {
+ break;
+ }
+
+ hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
+ shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp;
+
+ SkipBracedSection(&p, 0);
+ }
+
+ return;
+
+}
+
+
+/*
+====================
+CreateInternalShaders
+====================
+*/
+static void CreateInternalShaders( void ) {
+ tr.numShaders = 0;
+
+ // init the default shader
+ InitShader( "<default>", LIGHTMAP_NONE );
+ stages[0].bundle[0].image[0] = tr.defaultImage;
+ stages[0].active = true;
+ stages[0].stateBits = GLS_DEFAULT;
+ tr.defaultShader = FinishShader();
+
+ // shadow shader is just a marker
+ Q_strncpyz( shader.name, "<stencil shadow>", sizeof( shader.name ) );
+ shader.sort = SS_STENCIL_SHADOW;
+ tr.shadowShader = FinishShader();
+}
+
+static void CreateExternalShaders( void ) {
+ tr.projectionShadowShader = R_FindShader( "projectionShadow", LIGHTMAP_NONE, true );
+ tr.flareShader = R_FindShader( "flareShader", LIGHTMAP_NONE, true );
+
+ // Hack to make fogging work correctly on flares. Fog colors are calculated
+ // in tr_flare.c already.
+ if(!tr.flareShader->defaultShader)
+ {
+ int index;
+
+ for(index = 0; index < tr.flareShader->numUnfoggedPasses; index++)
+ {
+ tr.flareShader->stages[index]->adjustColorsForFog = ACFF_NONE;
+ tr.flareShader->stages[index]->stateBits |= GLS_DEPTHTEST_DISABLE;
+ }
+ }
+
+ tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, true );
+}
+
+/*
+==================
+R_InitShaders
+==================
+*/
+void R_InitShaders( void ) {
+ ri.Printf( PRINT_ALL, "Initializing Shaders\n" );
+
+ Com_Memset(hashTable, 0, sizeof(hashTable));
+
+ CreateInternalShaders();
+
+ ScanAndLoadShaderFiles();
+
+ CreateExternalShaders();
+}
diff --git a/src/renderergl1/tr_shadows.cpp b/src/renderergl1/tr_shadows.cpp
new file mode 100644
index 0000000..8d6ae56
--- /dev/null
+++ b/src/renderergl1/tr_shadows.cpp
@@ -0,0 +1,327 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "tr_local.h"
+
+
+/*
+
+ for a projection shadow:
+
+ point[x] += light vector * ( z - shadow plane )
+ point[y] +=
+ point[z] = shadow plane
+
+ 1 0 light[x] / light[z]
+
+*/
+
+typedef struct {
+ int i2;
+ int facing;
+} edgeDef_t;
+
+#define MAX_EDGE_DEFS 32
+
+static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];
+static int numEdgeDefs[SHADER_MAX_VERTEXES];
+static int facing[SHADER_MAX_INDEXES/3];
+static vec3_t shadowXyz[SHADER_MAX_VERTEXES];
+
+void R_AddEdgeDef( int i1, int i2, int facing ) {
+ int c;
+
+ c = numEdgeDefs[ i1 ];
+ if ( c == MAX_EDGE_DEFS ) {
+ return; // overflow
+ }
+ edgeDefs[ i1 ][ c ].i2 = i2;
+ edgeDefs[ i1 ][ c ].facing = facing;
+
+ numEdgeDefs[ i1 ]++;
+}
+
+void R_RenderShadowEdges( void ) {
+ int i;
+
+#if 0
+ int numTris;
+
+ // dumb way -- render every triangle's edges
+ numTris = tess.numIndexes / 3;
+
+ for ( i = 0 ; i < numTris ; i++ ) {
+ int i1, i2, i3;
+
+ if ( !facing[i] ) {
+ continue;
+ }
+
+ i1 = tess.indexes[ i*3 + 0 ];
+ i2 = tess.indexes[ i*3 + 1 ];
+ i3 = tess.indexes[ i*3 + 2 ];
+
+ qglBegin( GL_TRIANGLE_STRIP );
+ qglVertex3fv( tess.xyz[ i1 ] );
+ qglVertex3fv( shadowXyz[ i1 ] );
+ qglVertex3fv( tess.xyz[ i2 ] );
+ qglVertex3fv( shadowXyz[ i2 ] );
+ qglVertex3fv( tess.xyz[ i3 ] );
+ qglVertex3fv( shadowXyz[ i3 ] );
+ qglVertex3fv( tess.xyz[ i1 ] );
+ qglVertex3fv( shadowXyz[ i1 ] );
+ qglEnd();
+ }
+#else
+ int c, c2;
+ int j, k;
+ int i2;
+ int c_edges, c_rejected;
+ int hit[2];
+
+ // an edge is NOT a silhouette edge if its face doesn't face the light,
+ // or if it has a reverse paired edge that also faces the light.
+ // A well behaved polyhedron would have exactly two faces for each edge,
+ // but lots of models have dangling edges or overfanned edges
+ c_edges = 0;
+ c_rejected = 0;
+
+ for ( i = 0 ; i < tess.numVertexes ; i++ ) {
+ c = numEdgeDefs[ i ];
+ for ( j = 0 ; j < c ; j++ ) {
+ if ( !edgeDefs[ i ][ j ].facing ) {
+ continue;
+ }
+
+ hit[0] = 0;
+ hit[1] = 0;
+
+ i2 = edgeDefs[ i ][ j ].i2;
+ c2 = numEdgeDefs[ i2 ];
+ for ( k = 0 ; k < c2 ; k++ ) {
+ if ( edgeDefs[ i2 ][ k ].i2 == i ) {
+ hit[ edgeDefs[ i2 ][ k ].facing ]++;
+ }
+ }
+
+ // if it doesn't share the edge with another front facing
+ // triangle, it is a sil edge
+ if ( hit[ 1 ] == 0 ) {
+ qglBegin( GL_TRIANGLE_STRIP );
+ qglVertex3fv( tess.xyz[ i ] );
+ qglVertex3fv( shadowXyz[ i ] );
+ qglVertex3fv( tess.xyz[ i2 ] );
+ qglVertex3fv( shadowXyz[ i2 ] );
+ qglEnd();
+ c_edges++;
+ } else {
+ c_rejected++;
+ }
+ }
+ }
+#endif
+}
+
+/*
+=================
+RB_ShadowTessEnd
+
+triangleFromEdge[ v1 ][ v2 ]
+
+
+ set triangle from edge( v1, v2, tri )
+ if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) {
+ }
+=================
+*/
+void RB_ShadowTessEnd( void ) {
+ int i;
+ int numTris;
+ vec3_t lightDir;
+ GLboolean rgba[4];
+
+ if ( glConfig.stencilBits < 4 ) {
+ return;
+ }
+
+ VectorCopy( backEnd.currentEntity->lightDir, lightDir );
+
+ // project vertexes away from light direction
+ for ( i = 0 ; i < tess.numVertexes ; i++ ) {
+ VectorMA( tess.xyz[i], -512, lightDir, shadowXyz[i] );
+ }
+
+ // decide which triangles face the light
+ Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes );
+
+ numTris = tess.numIndexes / 3;
+ for ( i = 0 ; i < numTris ; i++ ) {
+ int i1, i2, i3;
+ vec3_t d1, d2, normal;
+ float *v1, *v2, *v3;
+ float d;
+
+ i1 = tess.indexes[ i*3 + 0 ];
+ i2 = tess.indexes[ i*3 + 1 ];
+ i3 = tess.indexes[ i*3 + 2 ];
+
+ v1 = tess.xyz[ i1 ];
+ v2 = tess.xyz[ i2 ];
+ v3 = tess.xyz[ i3 ];
+
+ VectorSubtract( v2, v1, d1 );
+ VectorSubtract( v3, v1, d2 );
+ CrossProduct( d1, d2, normal );
+
+ d = DotProduct( normal, lightDir );
+ if ( d > 0 ) {
+ facing[ i ] = 1;
+ } else {
+ facing[ i ] = 0;
+ }
+
+ // create the edges
+ R_AddEdgeDef( i1, i2, facing[ i ] );
+ R_AddEdgeDef( i2, i3, facing[ i ] );
+ R_AddEdgeDef( i3, i1, facing[ i ] );
+ }
+
+ // draw the silhouette edges
+
+ GL_Bind( tr.whiteImage );
+ GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
+ qglColor3f( 0.2f, 0.2f, 0.2f );
+
+ // don't write to the color buffer
+ qglGetBooleanv(GL_COLOR_WRITEMASK, rgba);
+ qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
+
+ qglEnable( GL_STENCIL_TEST );
+ qglStencilFunc( GL_ALWAYS, 1, 255 );
+
+ GL_Cull( CT_BACK_SIDED );
+ qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
+
+ R_RenderShadowEdges();
+
+ GL_Cull( CT_FRONT_SIDED );
+ qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
+
+ R_RenderShadowEdges();
+
+
+ // reenable writing to the color buffer
+ qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]);
+}
+
+
+/*
+=================
+RB_ShadowFinish
+
+Darken everything that is is a shadow volume.
+We have to delay this until everything has been shadowed,
+because otherwise shadows from different body parts would
+overlap and double darken.
+=================
+*/
+void RB_ShadowFinish( void ) {
+ if ( r_shadows->integer != 2 ) {
+ return;
+ }
+ if ( glConfig.stencilBits < 4 ) {
+ return;
+ }
+ qglEnable( GL_STENCIL_TEST );
+ qglStencilFunc( GL_NOTEQUAL, 0, 255 );
+
+ qglDisable (GL_CLIP_PLANE0);
+ GL_Cull( CT_TWO_SIDED );
+
+ GL_Bind( tr.whiteImage );
+
+ qglLoadIdentity ();
+
+ qglColor3f( 0.6f, 0.6f, 0.6f );
+ GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO );
+
+// qglColor3f( 1, 0, 0 );
+// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
+
+ qglBegin( GL_QUADS );
+ qglVertex3f( -100, 100, -10 );
+ qglVertex3f( 100, 100, -10 );
+ qglVertex3f( 100, -100, -10 );
+ qglVertex3f( -100, -100, -10 );
+ qglEnd ();
+
+ qglColor4f(1,1,1,1);
+ qglDisable( GL_STENCIL_TEST );
+}
+
+
+/*
+=================
+RB_ProjectionShadowDeform
+
+=================
+*/
+void RB_ProjectionShadowDeform( void ) {
+ float *xyz;
+ int i;
+ float h;
+ vec3_t ground;
+ vec3_t light;
+ float groundDist;
+ float d;
+ vec3_t lightDir;
+
+ xyz = ( float * ) tess.xyz;
+
+ ground[0] = backEnd.orientation.axis[0][2];
+ ground[1] = backEnd.orientation.axis[1][2];
+ ground[2] = backEnd.orientation.axis[2][2];
+
+ groundDist = backEnd.orientation.origin[2] - backEnd.currentEntity->e.shadowPlane;
+
+ VectorCopy( backEnd.currentEntity->lightDir, lightDir );
+ d = DotProduct( lightDir, ground );
+ // don't let the shadows get too long or go negative
+ if ( d < 0.5 ) {
+ VectorMA( lightDir, (0.5 - d), ground, lightDir );
+ d = DotProduct( lightDir, ground );
+ }
+ d = 1.0 / d;
+
+ light[0] = lightDir[0] * d;
+ light[1] = lightDir[1] * d;
+ light[2] = lightDir[2] * d;
+
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
+ h = DotProduct( xyz, ground ) + groundDist;
+
+ xyz[0] -= light[0] * h;
+ xyz[1] -= light[1] * h;
+ xyz[2] -= light[2] * h;
+ }
+}
diff --git a/src/renderergl1/tr_sky.cpp b/src/renderergl1/tr_sky.cpp
new file mode 100644
index 0000000..6dd9c45
--- /dev/null
+++ b/src/renderergl1/tr_sky.cpp
@@ -0,0 +1,796 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_sky.c
+#include "tr_local.h"
+
+#define SKY_SUBDIVISIONS 8
+#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2)
+
+static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
+static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
+
+/*
+===================================================================================
+
+POLYGON TO BOX SIDE PROJECTION
+
+===================================================================================
+*/
+
+static vec3_t sky_clip[6] =
+{
+ {1,1,0},
+ {1,-1,0},
+ {0,-1,1},
+ {0,1,1},
+ {1,0,1},
+ {-1,0,1}
+};
+
+static float sky_mins[2][6], sky_maxs[2][6];
+static float sky_min, sky_max;
+
+/*
+================
+AddSkyPolygon
+================
+*/
+static void AddSkyPolygon (int nump, vec3_t vecs)
+{
+ int i,j;
+ vec3_t v, av;
+ float s, t, dv;
+ int axis;
+ float *vp;
+ // s = [0]/[2], t = [1]/[2]
+ static int vec_to_st[6][3] =
+ {
+ {-2,3,1},
+ {2,3,-1},
+
+ {1,3,2},
+ {-1,3,-2},
+
+ {-2,-1,3},
+ {-2,1,-3}
+
+ // {-1,2,3},
+ // {1,2,-3}
+ };
+
+ // decide which face it maps to
+ VectorCopy (vec3_origin, v);
+ for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
+ {
+ VectorAdd (vp, v, v);
+ }
+ av[0] = fabs(v[0]);
+ av[1] = fabs(v[1]);
+ av[2] = fabs(v[2]);
+ if (av[0] > av[1] && av[0] > av[2])
+ {
+ if (v[0] < 0)
+ axis = 1;
+ else
+ axis = 0;
+ }
+ else if (av[1] > av[2] && av[1] > av[0])
+ {
+ if (v[1] < 0)
+ axis = 3;
+ else
+ axis = 2;
+ }
+ else
+ {
+ if (v[2] < 0)
+ axis = 5;
+ else
+ axis = 4;
+ }
+
+ // project new texture coords
+ for (i=0 ; i<nump ; i++, vecs+=3)
+ {
+ j = vec_to_st[axis][2];
+ if (j > 0)
+ dv = vecs[j - 1];
+ else
+ dv = -vecs[-j - 1];
+ if (dv < 0.001)
+ continue; // don't divide by zero
+ j = vec_to_st[axis][0];
+ if (j < 0)
+ s = -vecs[-j -1] / dv;
+ else
+ s = vecs[j-1] / dv;
+ j = vec_to_st[axis][1];
+ if (j < 0)
+ t = -vecs[-j -1] / dv;
+ else
+ t = vecs[j-1] / dv;
+
+ if (s < sky_mins[0][axis])
+ sky_mins[0][axis] = s;
+ if (t < sky_mins[1][axis])
+ sky_mins[1][axis] = t;
+ if (s > sky_maxs[0][axis])
+ sky_maxs[0][axis] = s;
+ if (t > sky_maxs[1][axis])
+ sky_maxs[1][axis] = t;
+ }
+}
+
+#define ON_EPSILON 0.1f // point on plane side epsilon
+#define MAX_CLIP_VERTS 64
+/*
+================
+ClipSkyPolygon
+================
+*/
+static void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
+{
+ float *norm;
+ float *v;
+ bool front, back;
+ float d, e;
+ float dists[MAX_CLIP_VERTS];
+ int sides[MAX_CLIP_VERTS];
+ vec3_t newv[2][MAX_CLIP_VERTS];
+ int newc[2];
+ int i, j;
+
+ if (nump > MAX_CLIP_VERTS-2)
+ ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS");
+ if (stage == 6)
+ { // fully clipped, so draw it
+ AddSkyPolygon (nump, vecs);
+ return;
+ }
+
+ front = back = false;
+ norm = sky_clip[stage];
+ for (i=0, v = vecs ; i<nump ; i++, v+=3)
+ {
+ d = DotProduct (v, norm);
+ if (d > ON_EPSILON)
+ {
+ front = true;
+ sides[i] = SIDE_FRONT;
+ }
+ else if (d < -ON_EPSILON)
+ {
+ back = true;
+ sides[i] = SIDE_BACK;
+ }
+ else
+ sides[i] = SIDE_ON;
+ dists[i] = d;
+ }
+
+ if (!front || !back)
+ { // not clipped
+ ClipSkyPolygon (nump, vecs, stage+1);
+ return;
+ }
+
+ // clip it
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+ VectorCopy (vecs, (vecs+(i*3)) );
+ newc[0] = newc[1] = 0;
+
+ for (i=0, v = vecs ; i<nump ; i++, v+=3)
+ {
+ switch (sides[i])
+ {
+ case SIDE_FRONT:
+ VectorCopy (v, newv[0][newc[0]]);
+ newc[0]++;
+ break;
+ case SIDE_BACK:
+ VectorCopy (v, newv[1][newc[1]]);
+ newc[1]++;
+ break;
+ case SIDE_ON:
+ VectorCopy (v, newv[0][newc[0]]);
+ newc[0]++;
+ VectorCopy (v, newv[1][newc[1]]);
+ newc[1]++;
+ break;
+ }
+
+ if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ d = dists[i] / (dists[i] - dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ {
+ e = v[j] + d*(v[j+3] - v[j]);
+ newv[0][newc[0]][j] = e;
+ newv[1][newc[1]][j] = e;
+ }
+ newc[0]++;
+ newc[1]++;
+ }
+
+ // continue
+ ClipSkyPolygon (newc[0], newv[0][0], stage+1);
+ ClipSkyPolygon (newc[1], newv[1][0], stage+1);
+}
+
+/*
+==============
+ClearSkyBox
+==============
+*/
+static void ClearSkyBox (void) {
+ int i;
+
+ for (i=0 ; i<6 ; i++) {
+ sky_mins[0][i] = sky_mins[1][i] = 9999;
+ sky_maxs[0][i] = sky_maxs[1][i] = -9999;
+ }
+}
+
+/*
+================
+RB_ClipSkyPolygons
+================
+*/
+void RB_ClipSkyPolygons( shaderCommands_t *input )
+{
+ vec3_t p[5]; // need one extra point for clipping
+ int i, j;
+
+ ClearSkyBox();
+
+ for ( i = 0; i < input->numIndexes; i += 3 )
+ {
+ for (j = 0 ; j < 3 ; j++)
+ {
+ VectorSubtract( input->xyz[input->indexes[i+j]],
+ backEnd.viewParms.orientation.origin,
+ p[j] );
+ }
+ ClipSkyPolygon( 3, p[0], 0 );
+ }
+}
+
+/*
+===================================================================================
+
+CLOUD VERTEX GENERATION
+
+===================================================================================
+*/
+
+/*
+** MakeSkyVec
+**
+** Parms: s, t range from -1 to 1
+*/
+static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ )
+{
+ // 1 = s, 2 = t, 3 = 2048
+ static int st_to_vec[6][3] =
+ {
+ {3,-1,2},
+ {-3,1,2},
+
+ {1,3,2},
+ {-1,-3,2},
+
+ {-2,-1,3}, // 0 degrees yaw, look straight up
+ {2,-1,-3} // look straight down
+ };
+
+ vec3_t b;
+ int j, k;
+ float boxSize;
+
+ boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
+ b[0] = s*boxSize;
+ b[1] = t*boxSize;
+ b[2] = boxSize;
+
+ for (j=0 ; j<3 ; j++)
+ {
+ k = st_to_vec[axis][j];
+ if (k < 0)
+ {
+ outXYZ[j] = -b[-k - 1];
+ }
+ else
+ {
+ outXYZ[j] = b[k - 1];
+ }
+ }
+
+ // avoid bilerp seam
+ s = (s+1)*0.5;
+ t = (t+1)*0.5;
+ if (s < sky_min)
+ {
+ s = sky_min;
+ }
+ else if (s > sky_max)
+ {
+ s = sky_max;
+ }
+
+ if (t < sky_min)
+ {
+ t = sky_min;
+ }
+ else if (t > sky_max)
+ {
+ t = sky_max;
+ }
+
+ t = 1.0 - t;
+
+
+ if ( outSt )
+ {
+ outSt[0] = s;
+ outSt[1] = t;
+ }
+}
+
+static int sky_texorder[6] = {0,2,1,3,4,5};
+static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
+static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
+
+static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
+{
+ int s, t;
+
+ GL_Bind( image );
+
+ for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
+ {
+ qglBegin( GL_TRIANGLE_STRIP );
+
+ for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
+ {
+ qglTexCoord2fv( s_skyTexCoords[t][s] );
+ qglVertex3fv( s_skyPoints[t][s] );
+
+ qglTexCoord2fv( s_skyTexCoords[t+1][s] );
+ qglVertex3fv( s_skyPoints[t+1][s] );
+ }
+
+ qglEnd();
+ }
+}
+
+static void DrawSkyBox( shader_t *shader )
+{
+ int i;
+
+ sky_min = 0;
+ sky_max = 1;
+
+ Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );
+
+ for (i=0 ; i<6 ; i++)
+ {
+ int sky_mins_subd[2], sky_maxs_subd[2];
+ int s, t;
+
+ sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+
+ if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
+ ( sky_mins[1][i] >= sky_maxs[1][i] ) )
+ {
+ continue;
+ }
+
+ sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;
+ sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;
+ sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;
+ sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;
+
+ if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
+ if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
+
+ if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
+ if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
+
+ //
+ // iterate through the subdivisions
+ //
+ for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
+ {
+ for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
+ {
+ MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ i,
+ s_skyTexCoords[t][s],
+ s_skyPoints[t][s] );
+ }
+ }
+
+ DrawSkySide( shader->sky.outerbox[sky_texorder[i]],
+ sky_mins_subd,
+ sky_maxs_subd );
+ }
+
+}
+
+static void FillCloudySkySide( const int mins[2], const int maxs[2], bool addIndexes )
+{
+ int s, t;
+ int vertexStart = tess.numVertexes;
+ int tHeight, sWidth;
+
+ tHeight = maxs[1] - mins[1] + 1;
+ sWidth = maxs[0] - mins[0] + 1;
+
+ for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
+ {
+ for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
+ {
+ VectorAdd( s_skyPoints[t][s], backEnd.viewParms.orientation.origin, tess.xyz[tess.numVertexes] );
+ tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0];
+ tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1];
+
+ tess.numVertexes++;
+
+ if ( tess.numVertexes >= SHADER_MAX_VERTEXES )
+ {
+ ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()" );
+ }
+ }
+ }
+
+ // only add indexes for one pass, otherwise it would draw multiple times for each pass
+ if ( addIndexes ) {
+ for ( t = 0; t < tHeight-1; t++ )
+ {
+ for ( s = 0; s < sWidth-1; s++ )
+ {
+ tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );
+ tess.numIndexes++;
+ tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
+ tess.numIndexes++;
+ tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
+ tess.numIndexes++;
+
+ tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
+ tess.numIndexes++;
+ tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );
+ tess.numIndexes++;
+ tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
+ tess.numIndexes++;
+ }
+ }
+ }
+}
+
+static void FillCloudBox( const shader_t *shader, int stage )
+{
+ int i;
+
+ for ( i =0; i < 6; i++ )
+ {
+ int sky_mins_subd[2], sky_maxs_subd[2];
+ int s, t;
+ float MIN_T;
+
+ if ( 1 ) // FIXME? shader->sky.fullClouds )
+ {
+ MIN_T = -HALF_SKY_SUBDIVISIONS;
+
+ // still don't want to draw the bottom, even if fullClouds
+ if ( i == 5 )
+ continue;
+ }
+ else
+ {
+ switch( i )
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ MIN_T = -1;
+ break;
+ case 5:
+ // don't draw clouds beneath you
+ continue;
+ case 4: // top
+ default:
+ MIN_T = -HALF_SKY_SUBDIVISIONS;
+ break;
+ }
+ }
+
+ sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+
+ if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
+ ( sky_mins[1][i] >= sky_maxs[1][i] ) )
+ {
+ continue;
+ }
+
+ sky_mins_subd[0] = static_cast<int>(sky_mins[0][i] * HALF_SKY_SUBDIVISIONS);
+ sky_mins_subd[1] = static_cast<int>(sky_mins[1][i] * HALF_SKY_SUBDIVISIONS);
+ sky_maxs_subd[0] = static_cast<int>(sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS);
+ sky_maxs_subd[1] = static_cast<int>(sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS);
+
+ if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
+ if ( sky_mins_subd[1] < MIN_T )
+ sky_mins_subd[1] = MIN_T;
+ else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
+
+ if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
+ if ( sky_maxs_subd[1] < MIN_T )
+ sky_maxs_subd[1] = MIN_T;
+ else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
+
+ //
+ // iterate through the subdivisions
+ //
+ for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
+ {
+ for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
+ {
+ MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ i,
+ NULL,
+ s_skyPoints[t][s] );
+
+ s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];
+ s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];
+ }
+ }
+
+ // only add indexes for first stage
+ FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) );
+ }
+}
+
+/*
+** R_BuildCloudData
+*/
+void R_BuildCloudData( shaderCommands_t *input )
+{
+ int i;
+ shader_t *shader;
+
+ shader = input->shader;
+
+ assert( shader->isSky );
+
+ sky_min = 1.0 / 256.0f; // FIXME: not correct?
+ sky_max = 255.0 / 256.0f;
+
+ // set up for drawing
+ tess.numIndexes = 0;
+ tess.numVertexes = 0;
+
+ if ( shader->sky.cloudHeight )
+ {
+ for ( i = 0; i < MAX_SHADER_STAGES; i++ )
+ {
+ if ( !tess.xstages[i] ) {
+ break;
+ }
+ FillCloudBox( shader, i );
+ }
+ }
+}
+
+/*
+** R_InitSkyTexCoords
+** Called when a sky shader is parsed
+*/
+#define SQR( a ) ((a)*(a))
+void R_InitSkyTexCoords( float heightCloud )
+{
+ int i, s, t;
+ float radiusWorld = 4096;
+ float p;
+ float sRad, tRad;
+ vec3_t skyVec;
+ vec3_t v;
+
+ // init zfar so MakeSkyVec works even though
+ // a world hasn't been bounded
+ backEnd.viewParms.zFar = 1024;
+
+ for ( i = 0; i < 6; i++ )
+ {
+ for ( t = 0; t <= SKY_SUBDIVISIONS; t++ )
+ {
+ for ( s = 0; s <= SKY_SUBDIVISIONS; s++ )
+ {
+ // compute vector from view origin to sky side integral point
+ MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ i,
+ NULL,
+ skyVec );
+
+ // compute parametric value 'p' that intersects with cloud layer
+ p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *
+ ( -2 * skyVec[2] * radiusWorld +
+ 2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) +
+ 2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +
+ SQR( skyVec[0] ) * SQR( heightCloud ) +
+ 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +
+ SQR( skyVec[1] ) * SQR( heightCloud ) +
+ 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +
+ SQR( skyVec[2] ) * SQR( heightCloud ) ) );
+
+ s_cloudTexP[i][t][s] = p;
+
+ // compute intersection point based on p
+ VectorScale( skyVec, p, v );
+ v[2] += radiusWorld;
+
+ // compute vector from world origin to intersection point 'v'
+ VectorNormalize( v );
+
+ sRad = Q_acos( v[0] );
+ tRad = Q_acos( v[1] );
+
+ s_cloudTexCoords[i][t][s][0] = sRad;
+ s_cloudTexCoords[i][t][s][1] = tRad;
+ }
+ }
+ }
+}
+
+//======================================================================================
+
+/*
+** RB_DrawSun
+*/
+void RB_DrawSun( float scale, shader_t *shader ) {
+ float size;
+ float dist;
+ vec3_t origin, vec1, vec2;
+ byte sunColor[4] = { 255, 255, 255, 255 };
+
+ if ( !backEnd.skyRenderedThisView ) {
+ return;
+ }
+
+ qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
+ qglTranslatef (backEnd.viewParms.orientation.origin[0], backEnd.viewParms.orientation.origin[1], backEnd.viewParms.orientation.origin[2]);
+
+ dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
+ size = dist * scale;
+
+ VectorScale( tr.sunDirection, dist, origin );
+ PerpendicularVector( vec1, tr.sunDirection );
+ CrossProduct( tr.sunDirection, vec1, vec2 );
+
+ VectorScale( vec1, size, vec1 );
+ VectorScale( vec2, size, vec2 );
+
+ // farthest depth range
+ qglDepthRange( 1.0, 1.0 );
+
+ RB_BeginSurface( shader, 0 );
+
+ RB_AddQuadStamp(origin, vec1, vec2, sunColor);
+
+ RB_EndSurface();
+
+ // back to normal depth range
+ qglDepthRange( 0.0, 1.0 );
+}
+
+
+
+
+/*
+================
+RB_StageIteratorSky
+
+All of the visible sky triangles are in tess
+
+Other things could be stuck in here, like birds in the sky, etc
+================
+*/
+void RB_StageIteratorSky( void ) {
+ if ( r_fastsky->integer ) {
+ return;
+ }
+
+ // go through all the polygons and project them onto
+ // the sky box to see which blocks on each side need
+ // to be drawn
+ RB_ClipSkyPolygons( &tess );
+
+ // r_showsky will let all the sky blocks be drawn in
+ // front of everything to allow developers to see how
+ // much sky is getting sucked in
+ if ( r_showsky->integer ) {
+ qglDepthRange( 0.0, 0.0 );
+ } else {
+ qglDepthRange( 1.0, 1.0 );
+ }
+
+ // draw the outer skybox
+ if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
+ qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
+
+ qglPushMatrix ();
+ GL_State( 0 );
+ GL_Cull( CT_FRONT_SIDED );
+ qglTranslatef (backEnd.viewParms.orientation.origin[0], backEnd.viewParms.orientation.origin[1], backEnd.viewParms.orientation.origin[2]);
+
+ DrawSkyBox( tess.shader );
+
+ qglPopMatrix();
+ }
+
+ // generate the vertexes for all the clouds, which will be drawn
+ // by the generic shader routine
+ R_BuildCloudData( &tess );
+
+ RB_StageIteratorGeneric();
+
+ // draw the inner skybox
+
+
+ // back to normal depth range
+ qglDepthRange( 0.0, 1.0 );
+
+ // note that sky was drawn so we will draw a sun later
+ backEnd.skyRenderedThisView = true;
+}
diff --git a/src/renderergl1/tr_subs.cpp b/src/renderergl1/tr_subs.cpp
new file mode 100644
index 0000000..ba93467
--- /dev/null
+++ b/src/renderergl1/tr_subs.cpp
@@ -0,0 +1,50 @@
+/*
+===========================================================================
+Copyright (C) 2010 James Canete (use.less01@gmail.com)
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_subs.c - common function replacements for modular renderer
+
+#include "tr_local.h"
+
+void QDECL Com_Printf( const char *msg, ... )
+{
+ va_list argptr;
+ char text[1024];
+
+ va_start(argptr, msg);
+ Q_vsnprintf(text, sizeof(text), msg, argptr);
+ va_end(argptr);
+
+ ri.Printf(PRINT_ALL, "%s", text);
+}
+
+void QDECL Com_Error( int level, const char *error, ... )
+{
+ va_list argptr;
+ char text[1024];
+
+ va_start(argptr, error);
+ Q_vsnprintf(text, sizeof(text), error, argptr);
+ va_end(argptr);
+
+ ri.Error(level, "%s", text);
+}
diff --git a/src/renderergl1/tr_surface.cpp b/src/renderergl1/tr_surface.cpp
new file mode 100644
index 0000000..176dcb5
--- /dev/null
+++ b/src/renderergl1/tr_surface.cpp
@@ -0,0 +1,1239 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_surf.c
+#include "tr_local.h"
+#if idppc_altivec && !defined(__APPLE__)
+#include <altivec.h>
+#endif
+
+/*
+
+ THIS ENTIRE FILE IS BACK END
+
+backEnd.currentEntity will be valid.
+
+Tess_Begin has already been called for the surface's shader.
+
+The modelview matrix will be set.
+
+It is safe to actually issue drawing commands here if you don't want to
+use the shader system.
+*/
+
+
+//============================================================================
+
+
+/*
+==============
+RB_CheckOverflow
+==============
+*/
+void RB_CheckOverflow( int verts, int indexes ) {
+ if (tess.numVertexes + verts < SHADER_MAX_VERTEXES
+ && tess.numIndexes + indexes < SHADER_MAX_INDEXES) {
+ return;
+ }
+
+ RB_EndSurface();
+
+ if ( verts >= SHADER_MAX_VERTEXES ) {
+ ri.Error(ERR_DROP, "RB_CheckOverflow: verts > MAX (%d > %d)", verts, SHADER_MAX_VERTEXES );
+ }
+ if ( indexes >= SHADER_MAX_INDEXES ) {
+ ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES );
+ }
+
+ RB_BeginSurface(tess.shader, tess.fogNum );
+}
+
+
+/*
+==============
+RB_AddQuadStampExt
+==============
+*/
+void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ) {
+ vec3_t normal;
+ int ndx;
+
+ RB_CHECKOVERFLOW( 4, 6 );
+
+ ndx = tess.numVertexes;
+
+ // triangle indexes for a simple quad
+ tess.indexes[ tess.numIndexes ] = ndx;
+ tess.indexes[ tess.numIndexes + 1 ] = ndx + 1;
+ tess.indexes[ tess.numIndexes + 2 ] = ndx + 3;
+
+ tess.indexes[ tess.numIndexes + 3 ] = ndx + 3;
+ tess.indexes[ tess.numIndexes + 4 ] = ndx + 1;
+ tess.indexes[ tess.numIndexes + 5 ] = ndx + 2;
+
+ tess.xyz[ndx][0] = origin[0] + left[0] + up[0];
+ tess.xyz[ndx][1] = origin[1] + left[1] + up[1];
+ tess.xyz[ndx][2] = origin[2] + left[2] + up[2];
+
+ tess.xyz[ndx+1][0] = origin[0] - left[0] + up[0];
+ tess.xyz[ndx+1][1] = origin[1] - left[1] + up[1];
+ tess.xyz[ndx+1][2] = origin[2] - left[2] + up[2];
+
+ tess.xyz[ndx+2][0] = origin[0] - left[0] - up[0];
+ tess.xyz[ndx+2][1] = origin[1] - left[1] - up[1];
+ tess.xyz[ndx+2][2] = origin[2] - left[2] - up[2];
+
+ tess.xyz[ndx+3][0] = origin[0] + left[0] - up[0];
+ tess.xyz[ndx+3][1] = origin[1] + left[1] - up[1];
+ tess.xyz[ndx+3][2] = origin[2] + left[2] - up[2];
+
+
+ // constant normal all the way around
+ VectorSubtract( vec3_origin, backEnd.viewParms.orientation.axis[0], normal );
+
+ tess.normal[ndx][0] = tess.normal[ndx+1][0] = tess.normal[ndx+2][0] = tess.normal[ndx+3][0] = normal[0];
+ tess.normal[ndx][1] = tess.normal[ndx+1][1] = tess.normal[ndx+2][1] = tess.normal[ndx+3][1] = normal[1];
+ tess.normal[ndx][2] = tess.normal[ndx+1][2] = tess.normal[ndx+2][2] = tess.normal[ndx+3][2] = normal[2];
+
+ // standard square texture coordinates
+ tess.texCoords[ndx][0][0] = tess.texCoords[ndx][1][0] = s1;
+ tess.texCoords[ndx][0][1] = tess.texCoords[ndx][1][1] = t1;
+
+ tess.texCoords[ndx+1][0][0] = tess.texCoords[ndx+1][1][0] = s2;
+ tess.texCoords[ndx+1][0][1] = tess.texCoords[ndx+1][1][1] = t1;
+
+ tess.texCoords[ndx+2][0][0] = tess.texCoords[ndx+2][1][0] = s2;
+ tess.texCoords[ndx+2][0][1] = tess.texCoords[ndx+2][1][1] = t2;
+
+ tess.texCoords[ndx+3][0][0] = tess.texCoords[ndx+3][1][0] = s1;
+ tess.texCoords[ndx+3][0][1] = tess.texCoords[ndx+3][1][1] = t2;
+
+ // constant color all the way around
+ // should this be identity and let the shader specify from entity?
+ * ( unsigned int * ) &tess.vertexColors[ndx] =
+ * ( unsigned int * ) &tess.vertexColors[ndx+1] =
+ * ( unsigned int * ) &tess.vertexColors[ndx+2] =
+ * ( unsigned int * ) &tess.vertexColors[ndx+3] =
+ * ( unsigned int * )color;
+
+
+ tess.numVertexes += 4;
+ tess.numIndexes += 6;
+}
+
+/*
+==============
+RB_AddQuadStamp
+==============
+*/
+void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ) {
+ RB_AddQuadStampExt( origin, left, up, color, 0, 0, 1, 1 );
+}
+
+/*
+==============
+RB_SurfaceSprite
+==============
+*/
+static void RB_SurfaceSprite( void ) {
+ vec3_t left, up;
+ float radius;
+
+ // calculate the xyz locations for the four corners
+ radius = backEnd.currentEntity->e.radius;
+ if ( backEnd.currentEntity->e.rotation == 0 ) {
+ VectorScale( backEnd.viewParms.orientation.axis[1], radius, left );
+ VectorScale( backEnd.viewParms.orientation.axis[2], radius, up );
+ } else {
+ float s, c;
+ float ang;
+
+ ang = M_PI * backEnd.currentEntity->e.rotation / 180;
+ s = sin( ang );
+ c = cos( ang );
+
+ VectorScale( backEnd.viewParms.orientation.axis[1], c * radius, left );
+ VectorMA( left, -s * radius, backEnd.viewParms.orientation.axis[2], left );
+
+ VectorScale( backEnd.viewParms.orientation.axis[2], c * radius, up );
+ VectorMA( up, s * radius, backEnd.viewParms.orientation.axis[1], up );
+ }
+ if ( backEnd.viewParms.isMirror ) {
+ VectorSubtract( vec3_origin, left, left );
+ }
+
+ RB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, backEnd.currentEntity->e.shaderRGBA );
+}
+
+
+/*
+=============
+RB_SurfacePolychain
+=============
+*/
+static void RB_SurfacePolychain( srfPoly_t *p ) {
+ int i;
+ int numv;
+
+ RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) );
+
+ // fan triangles into the tess array
+ numv = tess.numVertexes;
+ for ( i = 0; i < p->numVerts; i++ ) {
+ VectorCopy( p->verts[i].xyz, tess.xyz[numv] );
+ tess.texCoords[numv][0][0] = p->verts[i].st[0];
+ tess.texCoords[numv][0][1] = p->verts[i].st[1];
+ *(int *)&tess.vertexColors[numv] = *(int *)p->verts[ i ].modulate;
+
+ numv++;
+ }
+
+ // generate fan indexes into the tess array
+ for ( i = 0; i < p->numVerts-2; i++ ) {
+ tess.indexes[tess.numIndexes + 0] = tess.numVertexes;
+ tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1;
+ tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2;
+ tess.numIndexes += 3;
+ }
+
+ tess.numVertexes = numv;
+}
+
+
+/*
+=============
+RB_SurfaceTriangles
+=============
+*/
+static void RB_SurfaceTriangles( srfTriangles_t *srf ) {
+ int i;
+ drawVert_t *dv;
+ float *xyz, *normal, *texCoords;
+ byte *color;
+ int dlightBits;
+ bool needsNormal;
+
+ dlightBits = srf->dlightBits;
+ tess.dlightBits |= dlightBits;
+
+ RB_CHECKOVERFLOW( srf->numVerts, srf->numIndexes );
+
+ for ( i = 0 ; i < srf->numIndexes ; i += 3 ) {
+ tess.indexes[ tess.numIndexes + i + 0 ] = tess.numVertexes + srf->indexes[ i + 0 ];
+ tess.indexes[ tess.numIndexes + i + 1 ] = tess.numVertexes + srf->indexes[ i + 1 ];
+ tess.indexes[ tess.numIndexes + i + 2 ] = tess.numVertexes + srf->indexes[ i + 2 ];
+ }
+ tess.numIndexes += srf->numIndexes;
+
+ dv = srf->verts;
+ xyz = tess.xyz[ tess.numVertexes ];
+ normal = tess.normal[ tess.numVertexes ];
+ texCoords = tess.texCoords[ tess.numVertexes ][0];
+ color = tess.vertexColors[ tess.numVertexes ];
+ needsNormal = tess.shader->needsNormal;
+
+ for ( i = 0 ; i < srf->numVerts ; i++, dv++, xyz += 4, normal += 4, texCoords += 4, color += 4 ) {
+ xyz[0] = dv->xyz[0];
+ xyz[1] = dv->xyz[1];
+ xyz[2] = dv->xyz[2];
+
+ if ( needsNormal ) {
+ normal[0] = dv->normal[0];
+ normal[1] = dv->normal[1];
+ normal[2] = dv->normal[2];
+ }
+
+ texCoords[0] = dv->st[0];
+ texCoords[1] = dv->st[1];
+
+ texCoords[2] = dv->lightmap[0];
+ texCoords[3] = dv->lightmap[1];
+
+ *(int *)color = *(int *)dv->color;
+ }
+
+ for ( i = 0 ; i < srf->numVerts ; i++ ) {
+ tess.vertexDlightBits[ tess.numVertexes + i] = dlightBits;
+ }
+
+ tess.numVertexes += srf->numVerts;
+}
+
+
+
+/*
+==============
+RB_SurfaceBeam
+==============
+*/
+static void RB_SurfaceBeam( void )
+{
+#define NUM_BEAM_SEGS 6
+ refEntity_t *e;
+ int i;
+ vec3_t perpvec;
+ vec3_t direction, normalized_direction;
+ vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
+ vec3_t oldorigin, origin;
+
+ e = &backEnd.currentEntity->e;
+
+ oldorigin[0] = e->oldorigin[0];
+ oldorigin[1] = e->oldorigin[1];
+ oldorigin[2] = e->oldorigin[2];
+
+ origin[0] = e->origin[0];
+ origin[1] = e->origin[1];
+ origin[2] = e->origin[2];
+
+ normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
+ normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
+ normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
+
+ if ( VectorNormalize( normalized_direction ) == 0 )
+ return;
+
+ PerpendicularVector( perpvec, normalized_direction );
+
+ VectorScale( perpvec, 4, perpvec );
+
+ for ( i = 0; i < NUM_BEAM_SEGS ; i++ )
+ {
+ RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
+// VectorAdd( start_points[i], origin, start_points[i] );
+ VectorAdd( start_points[i], direction, end_points[i] );
+ }
+
+ GL_Bind( tr.whiteImage );
+
+ GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+
+ qglColor3f( 1, 0, 0 );
+
+ qglBegin( GL_TRIANGLE_STRIP );
+ for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) {
+ qglVertex3fv( start_points[ i % NUM_BEAM_SEGS] );
+ qglVertex3fv( end_points[ i % NUM_BEAM_SEGS] );
+ }
+ qglEnd();
+}
+
+//================================================================================
+
+static void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, float len, float spanWidth )
+{
+ float spanWidth2;
+ int vbase;
+ float t = len / 256.0f;
+
+ RB_CHECKOVERFLOW( 4, 6 );
+
+ vbase = tess.numVertexes;
+
+ spanWidth2 = -spanWidth;
+
+ // FIXME: use quad stamp?
+ VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] );
+ tess.texCoords[tess.numVertexes][0][0] = 0;
+ tess.texCoords[tess.numVertexes][0][1] = 0;
+ tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25;
+ tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25;
+ tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25;
+ tess.numVertexes++;
+
+ VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] );
+ tess.texCoords[tess.numVertexes][0][0] = 0;
+ tess.texCoords[tess.numVertexes][0][1] = 1;
+ tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
+ tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
+ tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
+ tess.numVertexes++;
+
+ VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] );
+
+ tess.texCoords[tess.numVertexes][0][0] = t;
+ tess.texCoords[tess.numVertexes][0][1] = 0;
+ tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
+ tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
+ tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
+ tess.numVertexes++;
+
+ VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] );
+ tess.texCoords[tess.numVertexes][0][0] = t;
+ tess.texCoords[tess.numVertexes][0][1] = 1;
+ tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
+ tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
+ tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
+ tess.numVertexes++;
+
+ tess.indexes[tess.numIndexes++] = vbase;
+ tess.indexes[tess.numIndexes++] = vbase + 1;
+ tess.indexes[tess.numIndexes++] = vbase + 2;
+
+ tess.indexes[tess.numIndexes++] = vbase + 2;
+ tess.indexes[tess.numIndexes++] = vbase + 1;
+ tess.indexes[tess.numIndexes++] = vbase + 3;
+}
+
+static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, const vec3_t right, const vec3_t up )
+{
+ int i;
+ vec3_t pos[4];
+ vec3_t v;
+ int spanWidth = r_railWidth->integer;
+ float c, s;
+ float scale;
+
+ if ( numSegs > 1 )
+ numSegs--;
+ if ( !numSegs )
+ return;
+
+ scale = 0.25;
+
+ for ( i = 0; i < 4; i++ )
+ {
+ c = cos( DEG2RAD( 45 + i * 90 ) );
+ s = sin( DEG2RAD( 45 + i * 90 ) );
+ v[0] = ( right[0] * c + up[0] * s ) * scale * spanWidth;
+ v[1] = ( right[1] * c + up[1] * s ) * scale * spanWidth;
+ v[2] = ( right[2] * c + up[2] * s ) * scale * spanWidth;
+ VectorAdd( start, v, pos[i] );
+
+ if ( numSegs > 1 )
+ {
+ // offset by 1 segment if we're doing a long distance shot
+ VectorAdd( pos[i], dir, pos[i] );
+ }
+ }
+
+ for ( i = 0; i < numSegs; i++ )
+ {
+ int j;
+
+ RB_CHECKOVERFLOW( 4, 6 );
+
+ for ( j = 0; j < 4; j++ )
+ {
+ VectorCopy( pos[j], tess.xyz[tess.numVertexes] );
+ tess.texCoords[tess.numVertexes][0][0] = ( j < 2 );
+ tess.texCoords[tess.numVertexes][0][1] = ( j && j != 3 );
+ tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
+ tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
+ tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
+ tess.numVertexes++;
+
+ VectorAdd( pos[j], dir, pos[j] );
+ }
+
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 0;
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1;
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3;
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3;
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1;
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 2;
+ }
+}
+
+/*
+** RB_SurfaceRailRinges
+*/
+static void RB_SurfaceRailRings( void ) {
+ refEntity_t *e;
+ int numSegs;
+ int len;
+ vec3_t vec;
+ vec3_t right, up;
+ vec3_t start, end;
+
+ e = &backEnd.currentEntity->e;
+
+ VectorCopy( e->oldorigin, start );
+ VectorCopy( e->origin, end );
+
+ // compute variables
+ VectorSubtract( end, start, vec );
+ len = VectorNormalize( vec );
+ MakeNormalVectors( vec, right, up );
+ numSegs = ( len ) / r_railSegmentLength->value;
+ if ( numSegs <= 0 ) {
+ numSegs = 1;
+ }
+
+ VectorScale( vec, r_railSegmentLength->value, vec );
+
+ DoRailDiscs( numSegs, start, vec, right, up );
+}
+
+/*
+** RB_SurfaceRailCore
+*/
+static void RB_SurfaceRailCore( void ) {
+ refEntity_t *e;
+ int len;
+ vec3_t right;
+ vec3_t vec;
+ vec3_t start, end;
+ vec3_t v1, v2;
+
+ e = &backEnd.currentEntity->e;
+
+ VectorCopy( e->oldorigin, start );
+ VectorCopy( e->origin, end );
+
+ VectorSubtract( end, start, vec );
+ len = VectorNormalize( vec );
+
+ // compute side vector
+ VectorSubtract( start, backEnd.viewParms.orientation.origin, v1 );
+ VectorNormalize( v1 );
+ VectorSubtract( end, backEnd.viewParms.orientation.origin, v2 );
+ VectorNormalize( v2 );
+ CrossProduct( v1, v2, right );
+ VectorNormalize( right );
+
+ DoRailCore( start, end, right, len, r_railCoreWidth->integer );
+}
+
+/*
+** RB_SurfaceLightningBolt
+*/
+static void RB_SurfaceLightningBolt( void ) {
+ refEntity_t *e;
+ int len;
+ vec3_t right;
+ vec3_t vec;
+ vec3_t start, end;
+ vec3_t v1, v2;
+ int i;
+
+ e = &backEnd.currentEntity->e;
+
+ VectorCopy( e->oldorigin, end );
+ VectorCopy( e->origin, start );
+
+ // compute variables
+ VectorSubtract( end, start, vec );
+ len = VectorNormalize( vec );
+
+ // compute side vector
+ VectorSubtract( start, backEnd.viewParms.orientation.origin, v1 );
+ VectorNormalize( v1 );
+ VectorSubtract( end, backEnd.viewParms.orientation.origin, v2 );
+ VectorNormalize( v2 );
+ CrossProduct( v1, v2, right );
+ VectorNormalize( right );
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ vec3_t temp;
+
+ DoRailCore( start, end, right, len, 8 );
+ RotatePointAroundVector( temp, vec, right, 45 );
+ VectorCopy( temp, right );
+ }
+}
+
+/*
+** VectorArrayNormalize
+*
+* The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0)
+* This means that we don't have to worry about zero length or enormously long vectors.
+*/
+static void VectorArrayNormalize(vec4_t *normals, unsigned int count)
+{
+// assert(count);
+
+#if idppc
+ {
+ float half = 0.5;
+ float one = 1.0;
+ float *components = (float *)normals;
+
+ // Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction,
+ // runs *much* faster than calling sqrt(). We'll use a single Newton-Raphson
+ // refinement step to get a little more precision. This seems to yeild results
+ // that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5).
+ // (That is, for the given input range of about 0.6 to 2.0).
+ do {
+ float x, y, z;
+ float B, y0, y1;
+
+ x = components[0];
+ y = components[1];
+ z = components[2];
+ components += 4;
+ B = x*x + y*y + z*z;
+
+#ifdef __GNUC__
+ asm("frsqrte %0,%1" : "=f" (y0) : "f" (B));
+#else
+ y0 = __frsqrte(B);
+#endif
+ y1 = y0 + half*y0*(one - B*y0*y0);
+
+ x = x * y1;
+ y = y * y1;
+ components[-4] = x;
+ z = z * y1;
+ components[-3] = y;
+ components[-2] = z;
+ } while(count--);
+ }
+#else // No assembly version for this architecture, or C_ONLY defined
+ // given the input, it's safe to call VectorNormalizeFast
+ while (count--) {
+ VectorNormalizeFast(normals[0]);
+ normals++;
+ }
+#endif
+
+}
+
+
+
+/*
+** LerpMeshVertexes
+*/
+#if idppc_altivec
+static void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp)
+{
+ short *oldXyz, *newXyz, *oldNormals, *newNormals;
+ float *outXyz, *outNormal;
+ float oldXyzScale QALIGN(16);
+ float newXyzScale QALIGN(16);
+ float oldNormalScale QALIGN(16);
+ float newNormalScale QALIGN(16);
+ int vertNum;
+ unsigned lat, lng;
+ int numVerts;
+
+ outXyz = tess.xyz[tess.numVertexes];
+ outNormal = tess.normal[tess.numVertexes];
+
+ newXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
+ + (backEnd.currentEntity->e.frame * surf->numVerts * 4);
+ newNormals = newXyz + 3;
+
+ newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp);
+ newNormalScale = 1.0 - backlerp;
+
+ numVerts = surf->numVerts;
+
+ if ( backlerp == 0 ) {
+ vector signed short newNormalsVec0;
+ vector signed short newNormalsVec1;
+ vector signed int newNormalsIntVec;
+ vector float newNormalsFloatVec;
+ vector float newXyzScaleVec;
+ vector unsigned char newNormalsLoadPermute;
+ vector unsigned char newNormalsStorePermute;
+ vector float zero;
+
+ newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec);
+ newXyzScaleVec = *(vector float *)&newXyzScale;
+ newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute);
+ newXyzScaleVec = vec_splat(newXyzScaleVec,0);
+ newNormalsLoadPermute = vec_lvsl(0,newXyz);
+ newNormalsStorePermute = vec_lvsr(0,outXyz);
+ zero = (vector float)vec_splat_s8(0);
+ //
+ // just copy the vertexes
+ //
+ for (vertNum=0 ; vertNum < numVerts ; vertNum++,
+ newXyz += 4, newNormals += 4,
+ outXyz += 4, outNormal += 4)
+ {
+ newNormalsLoadPermute = vec_lvsl(0,newXyz);
+ newNormalsStorePermute = vec_lvsr(0,outXyz);
+ newNormalsVec0 = vec_ld(0,newXyz);
+ newNormalsVec1 = vec_ld(16,newXyz);
+ newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute);
+ newNormalsIntVec = vec_unpackh(newNormalsVec0);
+ newNormalsFloatVec = vec_ctf(newNormalsIntVec,0);
+ newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero);
+ newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute);
+ //outXyz[0] = newXyz[0] * newXyzScale;
+ //outXyz[1] = newXyz[1] * newXyzScale;
+ //outXyz[2] = newXyz[2] * newXyzScale;
+
+ lat = ( newNormals[0] >> 8 ) & 0xff;
+ lng = ( newNormals[0] & 0xff );
+ lat *= (FUNCTABLE_SIZE/256);
+ lng *= (FUNCTABLE_SIZE/256);
+
+ // decode X as cos( lat ) * sin( long )
+ // decode Y as sin( lat ) * sin( long )
+ // decode Z as cos( long )
+
+ outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+ outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
+ outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+
+ vec_ste(newNormalsFloatVec,0,outXyz);
+ vec_ste(newNormalsFloatVec,4,outXyz);
+ vec_ste(newNormalsFloatVec,8,outXyz);
+ }
+ } else {
+ //
+ // interpolate and copy the vertex and normal
+ //
+ oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
+ + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4);
+ oldNormals = oldXyz + 3;
+
+ oldXyzScale = MD3_XYZ_SCALE * backlerp;
+ oldNormalScale = backlerp;
+
+ for (vertNum=0 ; vertNum < numVerts ; vertNum++,
+ oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4,
+ outXyz += 4, outNormal += 4)
+ {
+ vec3_t uncompressedOldNormal, uncompressedNewNormal;
+
+ // interpolate the xyz
+ outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;
+ outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;
+ outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;
+
+ // FIXME: interpolate lat/long instead?
+ lat = ( newNormals[0] >> 8 ) & 0xff;
+ lng = ( newNormals[0] & 0xff );
+ lat *= 4;
+ lng *= 4;
+ uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+ uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
+ uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+
+ lat = ( oldNormals[0] >> 8 ) & 0xff;
+ lng = ( oldNormals[0] & 0xff );
+ lat *= 4;
+ lng *= 4;
+
+ uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+ uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
+ uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+
+ outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale;
+ outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale;
+ outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale;
+
+// VectorNormalize (outNormal);
+ }
+ VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts);
+ }
+}
+#endif
+
+static void LerpMeshVertexes_scalar(md3Surface_t *surf, float backlerp)
+{
+ short *oldXyz, *newXyz, *oldNormals, *newNormals;
+ float *outXyz, *outNormal;
+ float oldXyzScale, newXyzScale;
+ float oldNormalScale, newNormalScale;
+ int vertNum;
+ unsigned lat, lng;
+ int numVerts;
+
+ outXyz = tess.xyz[tess.numVertexes];
+ outNormal = tess.normal[tess.numVertexes];
+
+ newXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
+ + (backEnd.currentEntity->e.frame * surf->numVerts * 4);
+ newNormals = newXyz + 3;
+
+ newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp);
+ newNormalScale = 1.0 - backlerp;
+
+ numVerts = surf->numVerts;
+
+ if ( backlerp == 0 ) {
+ //
+ // just copy the vertexes
+ //
+ for (vertNum=0 ; vertNum < numVerts ; vertNum++,
+ newXyz += 4, newNormals += 4,
+ outXyz += 4, outNormal += 4)
+ {
+
+ outXyz[0] = newXyz[0] * newXyzScale;
+ outXyz[1] = newXyz[1] * newXyzScale;
+ outXyz[2] = newXyz[2] * newXyzScale;
+
+ lat = ( newNormals[0] >> 8 ) & 0xff;
+ lng = ( newNormals[0] & 0xff );
+ lat *= (FUNCTABLE_SIZE/256);
+ lng *= (FUNCTABLE_SIZE/256);
+
+ // decode X as cos( lat ) * sin( long )
+ // decode Y as sin( lat ) * sin( long )
+ // decode Z as cos( long )
+
+ outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+ outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
+ outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+ }
+ } else {
+ //
+ // interpolate and copy the vertex and normal
+ //
+ oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
+ + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4);
+ oldNormals = oldXyz + 3;
+
+ oldXyzScale = MD3_XYZ_SCALE * backlerp;
+ oldNormalScale = backlerp;
+
+ for (vertNum=0 ; vertNum < numVerts ; vertNum++,
+ oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4,
+ outXyz += 4, outNormal += 4)
+ {
+ vec3_t uncompressedOldNormal, uncompressedNewNormal;
+
+ // interpolate the xyz
+ outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;
+ outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;
+ outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;
+
+ // FIXME: interpolate lat/long instead?
+ lat = ( newNormals[0] >> 8 ) & 0xff;
+ lng = ( newNormals[0] & 0xff );
+ lat *= 4;
+ lng *= 4;
+ uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+ uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
+ uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+
+ lat = ( oldNormals[0] >> 8 ) & 0xff;
+ lng = ( oldNormals[0] & 0xff );
+ lat *= 4;
+ lng *= 4;
+
+ uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+ uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
+ uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+
+ outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale;
+ outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale;
+ outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale;
+
+// VectorNormalize (outNormal);
+ }
+ VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts);
+ }
+}
+
+static void LerpMeshVertexes(md3Surface_t *surf, float backlerp)
+{
+#if idppc_altivec
+ if (com_altivec->integer) {
+ // must be in a seperate function or G3 systems will crash.
+ LerpMeshVertexes_altivec( surf, backlerp );
+ return;
+ }
+#endif // idppc_altivec
+ LerpMeshVertexes_scalar( surf, backlerp );
+}
+
+
+/*
+=============
+RB_SurfaceMesh
+=============
+*/
+static void RB_SurfaceMesh(md3Surface_t *surface) {
+ int j;
+ float backlerp;
+ int *triangles;
+ float *texCoords;
+ int indexes;
+ int Bob, Doug;
+ int numVerts;
+
+ if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) {
+ backlerp = 0;
+ } else {
+ backlerp = backEnd.currentEntity->e.backlerp;
+ }
+
+ RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles*3 );
+
+ LerpMeshVertexes (surface, backlerp);
+
+ triangles = (int *) ((byte *)surface + surface->ofsTriangles);
+ indexes = surface->numTriangles * 3;
+ Bob = tess.numIndexes;
+ Doug = tess.numVertexes;
+ for (j = 0 ; j < indexes ; j++) {
+ tess.indexes[Bob + j] = Doug + triangles[j];
+ }
+ tess.numIndexes += indexes;
+
+ texCoords = (float *) ((byte *)surface + surface->ofsSt);
+
+ numVerts = surface->numVerts;
+ for ( j = 0; j < numVerts; j++ ) {
+ tess.texCoords[Doug + j][0][0] = texCoords[j*2+0];
+ tess.texCoords[Doug + j][0][1] = texCoords[j*2+1];
+ // FIXME: fill in lightmapST for completeness?
+ }
+
+ tess.numVertexes += surface->numVerts;
+
+}
+
+
+/*
+==============
+RB_SurfaceFace
+==============
+*/
+static void RB_SurfaceFace( srfSurfaceFace_t *surf ) {
+ int i;
+ unsigned *indices;
+ glIndex_t *tessIndexes;
+ float *v;
+ float *normal;
+ int ndx;
+ int Bob;
+ int numPoints;
+ int dlightBits;
+
+ RB_CHECKOVERFLOW( surf->numPoints, surf->numIndices );
+
+ dlightBits = surf->dlightBits;
+ tess.dlightBits |= dlightBits;
+
+ indices = ( unsigned * ) ( ( ( char * ) surf ) + surf->ofsIndices );
+
+ Bob = tess.numVertexes;
+ tessIndexes = tess.indexes + tess.numIndexes;
+ for ( i = surf->numIndices-1 ; i >= 0 ; i-- ) {
+ tessIndexes[i] = indices[i] + Bob;
+ }
+
+ tess.numIndexes += surf->numIndices;
+
+ numPoints = surf->numPoints;
+
+ if ( tess.shader->needsNormal ) {
+ normal = surf->plane.normal;
+ for ( i = 0, ndx = tess.numVertexes; i < numPoints; i++, ndx++ ) {
+ VectorCopy( normal, tess.normal[ndx] );
+ }
+ }
+
+ for ( i = 0, v = surf->points[0], ndx = tess.numVertexes; i < numPoints; i++, v += VERTEXSIZE, ndx++ ) {
+ VectorCopy( v, tess.xyz[ndx]);
+ tess.texCoords[ndx][0][0] = v[3];
+ tess.texCoords[ndx][0][1] = v[4];
+ tess.texCoords[ndx][1][0] = v[5];
+ tess.texCoords[ndx][1][1] = v[6];
+ * ( unsigned int * ) &tess.vertexColors[ndx] = * ( unsigned int * ) &v[7];
+ tess.vertexDlightBits[ndx] = dlightBits;
+ }
+
+
+ tess.numVertexes += surf->numPoints;
+}
+
+
+static float LodErrorForVolume( vec3_t local, float radius ) {
+ vec3_t world;
+ float d;
+
+ // never let it go negative
+ if ( r_lodCurveError->value < 0 ) {
+ return 0;
+ }
+
+ world[0] = local[0] * backEnd.orientation.axis[0][0] + local[1] * backEnd.orientation.axis[1][0] +
+ local[2] * backEnd.orientation.axis[2][0] + backEnd.orientation.origin[0];
+ world[1] = local[0] * backEnd.orientation.axis[0][1] + local[1] * backEnd.orientation.axis[1][1] +
+ local[2] * backEnd.orientation.axis[2][1] + backEnd.orientation.origin[1];
+ world[2] = local[0] * backEnd.orientation.axis[0][2] + local[1] * backEnd.orientation.axis[1][2] +
+ local[2] * backEnd.orientation.axis[2][2] + backEnd.orientation.origin[2];
+
+ VectorSubtract( world, backEnd.viewParms.orientation.origin, world );
+ d = DotProduct( world, backEnd.viewParms.orientation.axis[0] );
+
+ if ( d < 0 ) {
+ d = -d;
+ }
+ d -= radius;
+ if ( d < 1 ) {
+ d = 1;
+ }
+
+ return r_lodCurveError->value / d;
+}
+
+/*
+=============
+RB_SurfaceGrid
+
+Just copy the grid of points and triangulate
+=============
+*/
+static void RB_SurfaceGrid( srfGridMesh_t *cv ) {
+ int i, j;
+ float *xyz;
+ float *texCoords;
+ float *normal;
+ unsigned char *color;
+ drawVert_t *dv;
+ int rows, irows, vrows;
+ int used;
+ int widthTable[MAX_GRID_SIZE];
+ int heightTable[MAX_GRID_SIZE];
+ float lodError;
+ int lodWidth, lodHeight;
+ int numVertexes;
+ int dlightBits;
+ int *vDlightBits;
+ bool needsNormal;
+
+ dlightBits = cv->dlightBits;
+ tess.dlightBits |= dlightBits;
+
+ // determine the allowable discrepance
+ lodError = LodErrorForVolume( cv->lodOrigin, cv->lodRadius );
+
+ // determine which rows and columns of the subdivision
+ // we are actually going to use
+ widthTable[0] = 0;
+ lodWidth = 1;
+ for ( i = 1 ; i < cv->width-1 ; i++ ) {
+ if ( cv->widthLodError[i] <= lodError ) {
+ widthTable[lodWidth] = i;
+ lodWidth++;
+ }
+ }
+ widthTable[lodWidth] = cv->width-1;
+ lodWidth++;
+
+ heightTable[0] = 0;
+ lodHeight = 1;
+ for ( i = 1 ; i < cv->height-1 ; i++ ) {
+ if ( cv->heightLodError[i] <= lodError ) {
+ heightTable[lodHeight] = i;
+ lodHeight++;
+ }
+ }
+ heightTable[lodHeight] = cv->height-1;
+ lodHeight++;
+
+
+ // very large grids may have more points or indexes than can be fit
+ // in the tess structure, so we may have to issue it in multiple passes
+
+ used = 0;
+ while ( used < lodHeight - 1 ) {
+ // see how many rows of both verts and indexes we can add without overflowing
+ do {
+ vrows = ( SHADER_MAX_VERTEXES - tess.numVertexes ) / lodWidth;
+ irows = ( SHADER_MAX_INDEXES - tess.numIndexes ) / ( lodWidth * 6 );
+
+ // if we don't have enough space for at least one strip, flush the buffer
+ if ( vrows < 2 || irows < 1 ) {
+ RB_EndSurface();
+ RB_BeginSurface(tess.shader, tess.fogNum );
+ } else {
+ break;
+ }
+ } while ( 1 );
+
+ rows = irows;
+ if ( vrows < irows + 1 ) {
+ rows = vrows - 1;
+ }
+ if ( used + rows > lodHeight ) {
+ rows = lodHeight - used;
+ }
+
+ numVertexes = tess.numVertexes;
+
+ xyz = tess.xyz[numVertexes];
+ normal = tess.normal[numVertexes];
+ texCoords = tess.texCoords[numVertexes][0];
+ color = ( unsigned char * ) &tess.vertexColors[numVertexes];
+ vDlightBits = &tess.vertexDlightBits[numVertexes];
+ needsNormal = tess.shader->needsNormal;
+
+ for ( i = 0 ; i < rows ; i++ ) {
+ for ( j = 0 ; j < lodWidth ; j++ ) {
+ dv = cv->verts + heightTable[ used + i ] * cv->width
+ + widthTable[ j ];
+
+ xyz[0] = dv->xyz[0];
+ xyz[1] = dv->xyz[1];
+ xyz[2] = dv->xyz[2];
+ texCoords[0] = dv->st[0];
+ texCoords[1] = dv->st[1];
+ texCoords[2] = dv->lightmap[0];
+ texCoords[3] = dv->lightmap[1];
+ if ( needsNormal ) {
+ normal[0] = dv->normal[0];
+ normal[1] = dv->normal[1];
+ normal[2] = dv->normal[2];
+ }
+ * ( unsigned int * ) color = * ( unsigned int * ) dv->color;
+ *vDlightBits++ = dlightBits;
+ xyz += 4;
+ normal += 4;
+ texCoords += 4;
+ color += 4;
+ }
+ }
+
+
+ // add the indexes
+ {
+ int numIndexes;
+ int w, h;
+
+ h = rows - 1;
+ w = lodWidth - 1;
+ numIndexes = tess.numIndexes;
+ for (i = 0 ; i < h ; i++) {
+ for (j = 0 ; j < w ; j++) {
+ int v1, v2, v3, v4;
+
+ // vertex order to be reckognized as tristrips
+ v1 = numVertexes + i*lodWidth + j + 1;
+ v2 = v1 - 1;
+ v3 = v2 + lodWidth;
+ v4 = v3 + 1;
+
+ tess.indexes[numIndexes] = v2;
+ tess.indexes[numIndexes+1] = v3;
+ tess.indexes[numIndexes+2] = v1;
+
+ tess.indexes[numIndexes+3] = v1;
+ tess.indexes[numIndexes+4] = v3;
+ tess.indexes[numIndexes+5] = v4;
+ numIndexes += 6;
+ }
+ }
+
+ tess.numIndexes = numIndexes;
+ }
+
+ tess.numVertexes += rows * lodWidth;
+
+ used += rows - 1;
+ }
+}
+
+
+/*
+===========================================================================
+
+NULL MODEL
+
+===========================================================================
+*/
+
+/*
+===================
+RB_SurfaceAxis
+
+Draws x/y/z lines from the origin for orientation debugging
+===================
+*/
+static void RB_SurfaceAxis( void ) {
+ GL_Bind( tr.whiteImage );
+ GL_State( GLS_DEFAULT );
+ qglLineWidth( 3 );
+ qglBegin( GL_LINES );
+ qglColor3f( 1,0,0 );
+ qglVertex3f( 0,0,0 );
+ qglVertex3f( 16,0,0 );
+ qglColor3f( 0,1,0 );
+ qglVertex3f( 0,0,0 );
+ qglVertex3f( 0,16,0 );
+ qglColor3f( 0,0,1 );
+ qglVertex3f( 0,0,0 );
+ qglVertex3f( 0,0,16 );
+ qglEnd();
+ qglLineWidth( 1 );
+}
+
+//===========================================================================
+
+/*
+====================
+RB_SurfaceEntity
+
+Entities that have a single procedurally generated surface
+====================
+*/
+static void RB_SurfaceEntity( surfaceType_t *surfType ) {
+ switch( backEnd.currentEntity->e.reType ) {
+ case RT_SPRITE:
+ RB_SurfaceSprite();
+ break;
+ case RT_BEAM:
+ RB_SurfaceBeam();
+ break;
+ case RT_RAIL_CORE:
+ RB_SurfaceRailCore();
+ break;
+ case RT_RAIL_RINGS:
+ RB_SurfaceRailRings();
+ break;
+ case RT_LIGHTNING:
+ RB_SurfaceLightningBolt();
+ break;
+ default:
+ RB_SurfaceAxis();
+ break;
+ }
+}
+
+static void RB_SurfaceBad( surfaceType_t *surfType ) {
+ ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" );
+}
+
+static void RB_SurfaceFlare(srfFlare_t *surf)
+{
+ if (r_flares->integer)
+ RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal);
+}
+
+static void RB_SurfaceSkip( void *surf ) {
+}
+
+
+void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = {
+ (void(*)(void*))RB_SurfaceBad, // SF_BAD,
+ (void(*)(void*))RB_SurfaceSkip, // SF_SKIP,
+ (void(*)(void*))RB_SurfaceFace, // SF_FACE,
+ (void(*)(void*))RB_SurfaceGrid, // SF_GRID,
+ (void(*)(void*))RB_SurfaceTriangles, // SF_TRIANGLES,
+ (void(*)(void*))RB_SurfacePolychain, // SF_POLY,
+ (void(*)(void*))RB_SurfaceMesh, // SF_MD3,
+ (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR,
+ (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM,
+ (void(*)(void*))RB_SurfaceFlare, // SF_FLARE,
+ (void(*)(void*))RB_SurfaceEntity // SF_ENTITY
+};
diff --git a/src/renderergl1/tr_world.cpp b/src/renderergl1/tr_world.cpp
new file mode 100644
index 0000000..7e59d51
--- /dev/null
+++ b/src/renderergl1/tr_world.cpp
@@ -0,0 +1,670 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "tr_local.h"
+
+
+
+/*
+=================
+R_CullTriSurf
+
+Returns true if the grid is completely culled away.
+Also sets the clipped hint bit in tess
+=================
+*/
+static bool R_CullTriSurf( srfTriangles_t *cv ) {
+ int boxCull;
+
+ boxCull = R_CullLocalBox( cv->bounds );
+
+ if ( boxCull == CULL_OUT ) {
+ return true;
+ }
+ return false;
+}
+
+/*
+=================
+R_CullGrid
+
+Returns true if the grid is completely culled away.
+Also sets the clipped hint bit in tess
+=================
+*/
+static bool R_CullGrid( srfGridMesh_t *cv ) {
+ int boxCull;
+ int sphereCull;
+
+ if ( r_nocurves->integer ) {
+ return true;
+ }
+
+ if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) {
+ sphereCull = R_CullLocalPointAndRadius( cv->localOrigin, cv->meshRadius );
+ } else {
+ sphereCull = R_CullPointAndRadius( cv->localOrigin, cv->meshRadius );
+ }
+
+ // check for trivial reject
+ if ( sphereCull == CULL_OUT )
+ {
+ tr.pc.c_sphere_cull_patch_out++;
+ return true;
+ }
+ // check bounding box if necessary
+ else if ( sphereCull == CULL_CLIP )
+ {
+ tr.pc.c_sphere_cull_patch_clip++;
+
+ boxCull = R_CullLocalBox( cv->meshBounds );
+
+ if ( boxCull == CULL_OUT )
+ {
+ tr.pc.c_box_cull_patch_out++;
+ return true;
+ }
+ else if ( boxCull == CULL_IN )
+ {
+ tr.pc.c_box_cull_patch_in++;
+ }
+ else
+ {
+ tr.pc.c_box_cull_patch_clip++;
+ }
+ }
+ else
+ {
+ tr.pc.c_sphere_cull_patch_in++;
+ }
+
+ return false;
+}
+
+
+/*
+================
+R_CullSurface
+
+Tries to back face cull surfaces before they are lighted or
+added to the sorting list.
+
+This will also allow mirrors on both sides of a model without recursion.
+================
+*/
+static bool R_CullSurface( surfaceType_t *surface, shader_t *shader ) {
+ srfSurfaceFace_t *sface;
+ float d;
+
+ if ( r_nocull->integer ) {
+ return false;
+ }
+
+ if ( *surface == SF_GRID ) {
+ return R_CullGrid( (srfGridMesh_t *)surface );
+ }
+
+ if ( *surface == SF_TRIANGLES ) {
+ return R_CullTriSurf( (srfTriangles_t *)surface );
+ }
+
+ if ( *surface != SF_FACE ) {
+ return false;
+ }
+
+ if ( shader->cullType == CT_TWO_SIDED ) {
+ return false;
+ }
+
+ // face culling
+ if ( !r_facePlaneCull->integer ) {
+ return false;
+ }
+
+ sface = ( srfSurfaceFace_t * ) surface;
+ d = DotProduct (tr.orientation.viewOrigin, sface->plane.normal);
+
+ // don't cull exactly on the plane, because there are levels of rounding
+ // through the BSP, ICD, and hardware that may cause pixel gaps if an
+ // epsilon isn't allowed here
+ if ( shader->cullType == CT_FRONT_SIDED ) {
+ if ( d < sface->plane.dist - 8 ) {
+ return true;
+ }
+ } else {
+ if ( d > sface->plane.dist + 8 ) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+static int R_DlightFace( srfSurfaceFace_t *face, int dlightBits ) {
+ float d;
+ int i;
+ dlight_t *dl;
+
+ for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
+ if ( ! ( dlightBits & ( 1 << i ) ) ) {
+ continue;
+ }
+ dl = &tr.refdef.dlights[i];
+ d = DotProduct( dl->origin, face->plane.normal ) - face->plane.dist;
+ if ( d < -dl->radius || d > dl->radius ) {
+ // dlight doesn't reach the plane
+ dlightBits &= ~( 1 << i );
+ }
+ }
+
+ if ( !dlightBits ) {
+ tr.pc.c_dlightSurfacesCulled++;
+ }
+
+ face->dlightBits = dlightBits;
+ return dlightBits;
+}
+
+static int R_DlightGrid( srfGridMesh_t *grid, int dlightBits ) {
+ int i;
+ dlight_t *dl;
+
+ for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
+ if ( ! ( dlightBits & ( 1 << i ) ) ) {
+ continue;
+ }
+ dl = &tr.refdef.dlights[i];
+ if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]
+ || dl->origin[0] + dl->radius < grid->meshBounds[0][0]
+ || dl->origin[1] - dl->radius > grid->meshBounds[1][1]
+ || dl->origin[1] + dl->radius < grid->meshBounds[0][1]
+ || dl->origin[2] - dl->radius > grid->meshBounds[1][2]
+ || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {
+ // dlight doesn't reach the bounds
+ dlightBits &= ~( 1 << i );
+ }
+ }
+
+ if ( !dlightBits ) {
+ tr.pc.c_dlightSurfacesCulled++;
+ }
+
+ grid->dlightBits = dlightBits;
+ return dlightBits;
+}
+
+
+static int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) {
+ // FIXME: more dlight culling to trisurfs...
+ surf->dlightBits = dlightBits;
+ return dlightBits;
+#if 0
+ int i;
+ dlight_t *dl;
+
+ for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
+ if ( ! ( dlightBits & ( 1 << i ) ) ) {
+ continue;
+ }
+ dl = &tr.refdef.dlights[i];
+ if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]
+ || dl->origin[0] + dl->radius < grid->meshBounds[0][0]
+ || dl->origin[1] - dl->radius > grid->meshBounds[1][1]
+ || dl->origin[1] + dl->radius < grid->meshBounds[0][1]
+ || dl->origin[2] - dl->radius > grid->meshBounds[1][2]
+ || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {
+ // dlight doesn't reach the bounds
+ dlightBits &= ~( 1 << i );
+ }
+ }
+
+ if ( !dlightBits ) {
+ tr.pc.c_dlightSurfacesCulled++;
+ }
+
+ grid->dlightBits = dlightBits;
+ return dlightBits;
+#endif
+}
+
+/*
+====================
+R_DlightSurface
+
+The given surface is going to be drawn, and it touches a leaf
+that is touched by one or more dlights, so try to throw out
+more dlights if possible.
+====================
+*/
+static int R_DlightSurface( msurface_t *surf, int dlightBits ) {
+ if ( *surf->data == SF_FACE ) {
+ dlightBits = R_DlightFace( (srfSurfaceFace_t *)surf->data, dlightBits );
+ } else if ( *surf->data == SF_GRID ) {
+ dlightBits = R_DlightGrid( (srfGridMesh_t *)surf->data, dlightBits );
+ } else if ( *surf->data == SF_TRIANGLES ) {
+ dlightBits = R_DlightTrisurf( (srfTriangles_t *)surf->data, dlightBits );
+ } else {
+ dlightBits = 0;
+ }
+
+ if ( dlightBits ) {
+ tr.pc.c_dlightSurfaces++;
+ }
+
+ return dlightBits;
+}
+
+
+
+/*
+======================
+R_AddWorldSurface
+======================
+*/
+static void R_AddWorldSurface( msurface_t *surf, int dlightBits ) {
+ if ( surf->viewCount == tr.viewCount ) {
+ return; // already in this view
+ }
+
+ surf->viewCount = tr.viewCount;
+ // FIXME: bmodel fog?
+
+ // try to cull before dlighting or adding
+ if ( R_CullSurface( surf->data, surf->shader ) ) {
+ return;
+ }
+
+ // check for dlighting
+ if ( dlightBits ) {
+ dlightBits = R_DlightSurface( surf, dlightBits );
+ dlightBits = ( dlightBits != 0 );
+ }
+
+ R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits );
+}
+
+/*
+=============================================================
+
+ BRUSH MODELS
+
+=============================================================
+*/
+
+/*
+=================
+R_AddBrushModelSurfaces
+=================
+*/
+void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {
+ bmodel_t *bmodel;
+ int clip;
+ model_t *pModel;
+ int i;
+
+ pModel = R_GetModelByHandle( ent->e.hModel );
+
+ bmodel = pModel->bmodel;
+
+ clip = R_CullLocalBox( bmodel->bounds );
+ if ( clip == CULL_OUT ) {
+ return;
+ }
+
+ R_SetupEntityLighting( &tr.refdef, ent );
+ R_DlightBmodel( bmodel );
+
+ for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
+ R_AddWorldSurface( bmodel->firstSurface + i, tr.currentEntity->needDlights );
+ }
+}
+
+
+/*
+=============================================================
+
+ WORLD MODEL
+
+=============================================================
+*/
+
+
+/*
+================
+R_RecursiveWorldNode
+================
+*/
+static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) {
+
+ do {
+ int newDlights[2];
+
+ // if the node wasn't marked as potentially visible, exit
+ if (node->visframe != tr.visCount) {
+ return;
+ }
+
+ // if the bounding volume is outside the frustum, nothing
+ // inside can be visible OPTIMIZE: don't do this all the way to leafs?
+
+ if ( !r_nocull->integer ) {
+ int r;
+
+ if ( planeBits & 1 ) {
+ r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);
+ if (r == 2) {
+ return; // culled
+ }
+ if ( r == 1 ) {
+ planeBits &= ~1; // all descendants will also be in front
+ }
+ }
+
+ if ( planeBits & 2 ) {
+ r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);
+ if (r == 2) {
+ return; // culled
+ }
+ if ( r == 1 ) {
+ planeBits &= ~2; // all descendants will also be in front
+ }
+ }
+
+ if ( planeBits & 4 ) {
+ r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);
+ if (r == 2) {
+ return; // culled
+ }
+ if ( r == 1 ) {
+ planeBits &= ~4; // all descendants will also be in front
+ }
+ }
+
+ if ( planeBits & 8 ) {
+ r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);
+ if (r == 2) {
+ return; // culled
+ }
+ if ( r == 1 ) {
+ planeBits &= ~8; // all descendants will also be in front
+ }
+ }
+
+ }
+
+ if ( node->contents != -1 ) {
+ break;
+ }
+
+ // node is just a decision point, so go down both sides
+ // since we don't care about sort orders, just go positive to negative
+
+ // determine which dlights are needed
+ newDlights[0] = 0;
+ newDlights[1] = 0;
+ if ( dlightBits ) {
+ int i;
+
+ for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
+ dlight_t *dl;
+ float dist;
+
+ if ( dlightBits & ( 1 << i ) ) {
+ dl = &tr.refdef.dlights[i];
+ dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist;
+
+ if ( dist > -dl->radius ) {
+ newDlights[0] |= ( 1 << i );
+ }
+ if ( dist < dl->radius ) {
+ newDlights[1] |= ( 1 << i );
+ }
+ }
+ }
+ }
+
+ // recurse down the children, front side first
+ R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0] );
+
+ // tail recurse
+ node = node->children[1];
+ dlightBits = newDlights[1];
+ } while ( 1 );
+
+ {
+ // leaf node, so add mark surfaces
+ int c;
+ msurface_t *surf, **mark;
+
+ tr.pc.c_leafs++;
+
+ // add to z buffer bounds
+ if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) {
+ tr.viewParms.visBounds[0][0] = node->mins[0];
+ }
+ if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) {
+ tr.viewParms.visBounds[0][1] = node->mins[1];
+ }
+ if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) {
+ tr.viewParms.visBounds[0][2] = node->mins[2];
+ }
+
+ if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) {
+ tr.viewParms.visBounds[1][0] = node->maxs[0];
+ }
+ if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) {
+ tr.viewParms.visBounds[1][1] = node->maxs[1];
+ }
+ if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) {
+ tr.viewParms.visBounds[1][2] = node->maxs[2];
+ }
+
+ // add the individual surfaces
+ mark = node->firstmarksurface;
+ c = node->nummarksurfaces;
+ while (c--) {
+ // the surface may have already been added if it
+ // spans multiple leafs
+ surf = *mark;
+ R_AddWorldSurface( surf, dlightBits );
+ mark++;
+ }
+ }
+
+}
+
+
+/*
+===============
+R_PointInLeaf
+===============
+*/
+static mnode_t *R_PointInLeaf( const vec3_t p ) {
+ mnode_t *node;
+ float d;
+ cplane_t *plane;
+
+ if ( !tr.world ) {
+ ri.Error (ERR_DROP, "R_PointInLeaf: bad model");
+ }
+
+ node = tr.world->nodes;
+ while( 1 ) {
+ if (node->contents != -1) {
+ break;
+ }
+ plane = node->plane;
+ d = DotProduct (p,plane->normal) - plane->dist;
+ if (d > 0) {
+ node = node->children[0];
+ } else {
+ node = node->children[1];
+ }
+ }
+
+ return node;
+}
+
+/*
+==============
+R_ClusterPVS
+==============
+*/
+static const byte *R_ClusterPVS (int cluster) {
+ if (!tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) {
+ return tr.world->novis;
+ }
+
+ return tr.world->vis + cluster * tr.world->clusterBytes;
+}
+
+/*
+=================
+R_inPVS
+=================
+*/
+bool R_inPVS( const vec3_t p1, const vec3_t p2 ) {
+ mnode_t *leaf;
+ byte *vis;
+
+ leaf = R_PointInLeaf( p1 );
+ vis = ri.CM_ClusterPVS( leaf->cluster ); // why not R_ClusterPVS ??
+ leaf = R_PointInLeaf( p2 );
+
+ if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) {
+ return false;
+ }
+ return true;
+}
+
+/*
+===============
+R_MarkLeaves
+
+Mark the leaves and nodes that are in the PVS for the current
+cluster
+===============
+*/
+static void R_MarkLeaves (void) {
+ const byte *vis;
+ mnode_t *leaf, *parent;
+ int i;
+ int cluster;
+
+ // lockpvs lets designers walk around to determine the
+ // extent of the current pvs
+ if ( r_lockpvs->integer ) {
+ return;
+ }
+
+ // current viewcluster
+ leaf = R_PointInLeaf( tr.viewParms.pvsOrigin );
+ cluster = leaf->cluster;
+
+ // if the cluster is the same and the area visibility matrix
+ // hasn't changed, we don't need to mark everything again
+
+ // if r_showcluster was just turned on, remark everything
+ if ( tr.viewCluster == cluster && !tr.refdef.areamaskModified
+ && !r_showcluster->modified ) {
+ return;
+ }
+
+ if ( r_showcluster->modified || r_showcluster->integer ) {
+ r_showcluster->modified = false;
+ if ( r_showcluster->integer ) {
+ ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area );
+ }
+ }
+
+ tr.visCount++;
+ tr.viewCluster = cluster;
+
+ if ( r_novis->integer || tr.viewCluster == -1 ) {
+ for (i=0 ; i<tr.world->numnodes ; i++) {
+ if (tr.world->nodes[i].contents != CONTENTS_SOLID) {
+ tr.world->nodes[i].visframe = tr.visCount;
+ }
+ }
+ return;
+ }
+
+ vis = R_ClusterPVS (tr.viewCluster);
+
+ for (i=0,leaf=tr.world->nodes ; i<tr.world->numnodes ; i++, leaf++) {
+ cluster = leaf->cluster;
+ if ( cluster < 0 || cluster >= tr.world->numClusters ) {
+ continue;
+ }
+
+ // check general pvs
+ if ( !(vis[cluster>>3] & (1<<(cluster&7))) ) {
+ continue;
+ }
+
+ // check for door connection
+ if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) {
+ continue; // not visible
+ }
+
+ parent = leaf;
+ do {
+ if (parent->visframe == tr.visCount)
+ break;
+ parent->visframe = tr.visCount;
+ parent = parent->parent;
+ } while (parent);
+ }
+}
+
+
+/*
+=============
+R_AddWorldSurfaces
+=============
+*/
+void R_AddWorldSurfaces (void) {
+ if ( !r_drawworld->integer ) {
+ return;
+ }
+
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ return;
+ }
+
+ tr.currentEntityNum = REFENTITYNUM_WORLD;
+ tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
+
+ // determine which leaves are in the PVS / areamask
+ R_MarkLeaves ();
+
+ // clear out the visible min/max
+ ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );
+
+ // perform frustum culling and add all the potentially visible surfaces
+ if ( tr.refdef.num_dlights > 32 ) {
+ tr.refdef.num_dlights = 32 ;
+ }
+ R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1 );
+}
diff --git a/src/renderergl2/CMakeLists.txt b/src/renderergl2/CMakeLists.txt
new file mode 100644
index 0000000..b821436
--- /dev/null
+++ b/src/renderergl2/CMakeLists.txt
@@ -0,0 +1,146 @@
+include("${CMAKE_SOURCE_DIR}/cmake/SDL2.cmake")
+
+find_package(OpenGL)
+
+set(PARENT_DIR ${CMAKE_SOURCE_DIR}/src)
+include_directories(
+ ${PARENT_DIR}/jpeg-8c
+ ${PARENT_DIR}/renderercommon
+ ${PARENT_DIR}/nettle-3.3
+ ${SDL2_INCLUDE_DIRS}
+ )
+
+set(GLSL_SHADERS
+ glsl/bokeh_fp.glsl
+ glsl/bokeh_vp.glsl
+ glsl/calclevels4x_fp.glsl
+ glsl/calclevels4x_vp.glsl
+ glsl/depthblur_fp.glsl
+ glsl/depthblur_vp.glsl
+ glsl/dlight_fp.glsl
+ glsl/dlight_vp.glsl
+ glsl/down4x_fp.glsl
+ glsl/down4x_vp.glsl
+ glsl/fogpass_fp.glsl
+ glsl/fogpass_vp.glsl
+ glsl/generic_fp.glsl
+ glsl/generic_vp.glsl
+ glsl/lightall_fp.glsl
+ glsl/lightall_vp.glsl
+ glsl/pshadow_fp.glsl
+ glsl/pshadow_vp.glsl
+ glsl/shadowfill_fp.glsl
+ glsl/shadowfill_vp.glsl
+ glsl/shadowmask_fp.glsl
+ glsl/shadowmask_vp.glsl
+ glsl/ssao_fp.glsl
+ glsl/ssao_vp.glsl
+ glsl/texturecolor_fp.glsl
+ glsl/texturecolor_vp.glsl
+ glsl/tonemap_fp.glsl
+ glsl/tonemap_vp.glsl
+ )
+
+# Converts ^^^GSLS shaders^^^ into const char* C-strings.
+file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/glsl/)
+foreach(shader ${GLSL_SHADERS})
+ set(in ${CMAKE_CURRENT_SOURCE_DIR}/${shader})
+
+ get_filename_component(out ${in} NAME_WE)
+ set(out ${CMAKE_CURRENT_BINARY_DIR}/glsl/${out}.c)
+
+ get_filename_component(shader ${shader} NAME_WE)
+ message(STATUS "-- Generating embeded GLSL ${shader}")
+
+ file(READ ${in} contents HEX)
+ file(WRITE ${out} "const char *fallbackShader_${shader} = \"")
+
+ string(LENGTH "${contents}" contents_length)
+ math(EXPR contents_length "${contents_length} - 1")
+
+ foreach(iter RANGE 0 ${contents_length} 2)
+ string(SUBSTRING ${contents} ${iter} 2 line)
+ file(APPEND "${out}" "\\x${line}")
+ endforeach()
+ file(APPEND "${out}" "\";\n")
+
+ list(APPEND renderergl2_SHADERS "${out}")
+ set_source_files_properties(${out} PROPERTIES GENERATED TRUE)
+endforeach(shader)
+
+set(renderergl2_SRCS
+ ${renderergl2_SHADERS}
+ tr_local.h
+ tr_dsa.h
+ tr_extramath.h
+ tr_extratypes.h
+ tr_fbo.h
+ tr_postprocess.h
+ tr_animation.cpp
+ tr_backend.cpp
+ tr_bsp.cpp
+ tr_cmds.cpp
+ tr_curve.cpp
+ tr_dsa.cpp
+ tr_extensions.cpp
+ tr_extramath.cpp
+ tr_fbo.cpp
+ tr_flares.cpp
+ tr_glsl.cpp
+ tr_image.cpp
+ tr_image_dds.cpp
+ tr_init.cpp
+ tr_light.cpp
+ tr_main.cpp
+ tr_marks.cpp
+ tr_mesh.cpp
+ tr_model.cpp
+ tr_model_iqm.cpp
+ tr_postprocess.cpp
+ tr_scene.cpp
+ tr_shade.cpp
+ tr_shade_calc.cpp
+ tr_shader.cpp
+ tr_shadows.cpp
+ tr_sky.cpp
+ tr_subs.cpp
+ tr_surface.cpp
+ tr_vbo.cpp
+ tr_world.cpp
+ ${CMAKE_SOURCE_DIR}/src/common/puff.cpp
+ ${CMAKE_SOURCE_DIR}/src/common/q_shared.c
+ ${CMAKE_SOURCE_DIR}/src/common/q_math.c
+ )
+
+if(NOT USE_RENDERER_DLOPEN)
+
+ add_library(
+ renderergl2 STATIC
+ ${renderergl2_SRCS})
+
+ target_link_libraries(
+ renderergl2 renderercommon
+ ${SDL2_LIBRARIES})
+
+else(NOT USE_RENDERER_DLOPEN)
+
+ add_library(
+ renderergl2 SHARED
+ ${renderergl2_SRCS}
+ )
+
+ target_link_libraries(
+ renderergl2
+ renderercommon
+ ${FRAMEWORKS}
+ ${OPENGL_LIBRARIES}
+ ${SDL2_LIBRARIES}
+ )
+ add_custom_command(
+ TARGET renderergl2
+ POST_BUILD COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${CMAKE_CURRENT_BINARY_DIR}/librenderergl2${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/renderer_opengl2${CMAKE_SHARED_LIBRARY_SUFFIX}
+ )
+
+endif(NOT USE_RENDERER_DLOPEN)
+
diff --git a/src/renderergl2/glsl/bokeh_fp.glsl b/src/renderergl2/glsl/bokeh_fp.glsl
new file mode 100644
index 0000000..d08816a
--- /dev/null
+++ b/src/renderergl2/glsl/bokeh_fp.glsl
@@ -0,0 +1,70 @@
+uniform sampler2D u_TextureMap;
+
+uniform vec4 u_Color;
+
+uniform vec2 u_InvTexRes;
+varying vec2 var_TexCoords;
+
+void main()
+{
+ vec4 color;
+ vec2 tc;
+
+#if 0
+ float c[7] = float[7](1.0, 0.9659258263, 0.8660254038, 0.7071067812, 0.5, 0.2588190451, 0.0);
+
+ tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[6]); color = texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[5]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[2], c[4]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[3], c[3]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[4], c[2]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[5], c[1]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[6], c[0]); color += texture2D(u_TextureMap, tc);
+
+ tc = var_TexCoords + u_InvTexRes * vec2( c[1], -c[5]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[2], -c[4]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[3], -c[3]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[4], -c[2]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[5], -c[1]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[6], -c[0]); color += texture2D(u_TextureMap, tc);
+
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[0], c[6]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[1], c[5]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[2], c[4]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[3], c[3]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[4], c[2]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[5], c[1]); color += texture2D(u_TextureMap, tc);
+
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[1], -c[5]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[2], -c[4]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[3], -c[3]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[4], -c[2]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[5], -c[1]); color += texture2D(u_TextureMap, tc);
+
+ gl_FragColor = color * 0.04166667 * u_Color;
+#endif
+
+ float c[5] = float[5](1.0, 0.9238795325, 0.7071067812, 0.3826834324, 0.0);
+
+ tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[4]); color = texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[3]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[2], c[2]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[3], c[1]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[4], c[0]); color += texture2D(u_TextureMap, tc);
+
+ tc = var_TexCoords + u_InvTexRes * vec2( c[1], -c[3]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[2], -c[2]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[3], -c[1]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( c[4], -c[0]); color += texture2D(u_TextureMap, tc);
+
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[0], c[4]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[1], c[3]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[2], c[2]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[3], c[1]); color += texture2D(u_TextureMap, tc);
+
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[1], -c[3]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[2], -c[2]); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( -c[3], -c[1]); color += texture2D(u_TextureMap, tc);
+
+ gl_FragColor = color * 0.0625 * u_Color;
+}
diff --git a/src/renderergl2/glsl/bokeh_vp.glsl b/src/renderergl2/glsl/bokeh_vp.glsl
new file mode 100644
index 0000000..bdaa74a
--- /dev/null
+++ b/src/renderergl2/glsl/bokeh_vp.glsl
@@ -0,0 +1,13 @@
+attribute vec3 attr_Position;
+attribute vec4 attr_TexCoord0;
+
+uniform mat4 u_ModelViewProjectionMatrix;
+
+varying vec2 var_TexCoords;
+
+
+void main()
+{
+ gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0);
+ var_TexCoords = attr_TexCoord0.st;
+}
diff --git a/src/renderergl2/glsl/calclevels4x_fp.glsl b/src/renderergl2/glsl/calclevels4x_fp.glsl
new file mode 100644
index 0000000..8246c4b
--- /dev/null
+++ b/src/renderergl2/glsl/calclevels4x_fp.glsl
@@ -0,0 +1,60 @@
+uniform sampler2D u_TextureMap;
+
+uniform vec4 u_Color;
+
+uniform vec2 u_InvTexRes;
+varying vec2 var_TexCoords;
+
+const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721); //vec3(0.299, 0.587, 0.114);
+
+vec3 GetValues(vec2 offset, vec3 current)
+{
+ vec2 tc = var_TexCoords + u_InvTexRes * offset;
+ vec3 minAvgMax = texture2D(u_TextureMap, tc).rgb;
+
+#ifdef FIRST_PASS
+
+ #if defined(USE_PBR)
+ minAvgMax *= minAvgMax;
+ #endif
+
+ float lumi = max(dot(LUMINANCE_VECTOR, minAvgMax), 0.000001);
+ float loglumi = clamp(log2(lumi), -10.0, 10.0);
+ minAvgMax = vec3(loglumi * 0.05 + 0.5);
+#endif
+
+ return vec3(min(current.x, minAvgMax.x), current.y + minAvgMax.y, max(current.z, minAvgMax.z));
+}
+
+void main()
+{
+ vec3 current = vec3(1.0, 0.0, 0.0);
+
+#ifdef FIRST_PASS
+ current = GetValues(vec2( 0.0, 0.0), current);
+#else
+ current = GetValues(vec2(-1.5, -1.5), current);
+ current = GetValues(vec2(-0.5, -1.5), current);
+ current = GetValues(vec2( 0.5, -1.5), current);
+ current = GetValues(vec2( 1.5, -1.5), current);
+
+ current = GetValues(vec2(-1.5, -0.5), current);
+ current = GetValues(vec2(-0.5, -0.5), current);
+ current = GetValues(vec2( 0.5, -0.5), current);
+ current = GetValues(vec2( 1.5, -0.5), current);
+
+ current = GetValues(vec2(-1.5, 0.5), current);
+ current = GetValues(vec2(-0.5, 0.5), current);
+ current = GetValues(vec2( 0.5, 0.5), current);
+ current = GetValues(vec2( 1.5, 0.5), current);
+
+ current = GetValues(vec2(-1.5, 1.5), current);
+ current = GetValues(vec2(-0.5, 1.5), current);
+ current = GetValues(vec2( 0.5, 1.5), current);
+ current = GetValues(vec2( 1.5, 1.5), current);
+
+ current.y *= 0.0625;
+#endif
+
+ gl_FragColor = vec4(current, 1.0f);
+}
diff --git a/src/renderergl2/glsl/calclevels4x_vp.glsl b/src/renderergl2/glsl/calclevels4x_vp.glsl
new file mode 100644
index 0000000..bdaa74a
--- /dev/null
+++ b/src/renderergl2/glsl/calclevels4x_vp.glsl
@@ -0,0 +1,13 @@
+attribute vec3 attr_Position;
+attribute vec4 attr_TexCoord0;
+
+uniform mat4 u_ModelViewProjectionMatrix;
+
+varying vec2 var_TexCoords;
+
+
+void main()
+{
+ gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0);
+ var_TexCoords = attr_TexCoord0.st;
+}
diff --git a/src/renderergl2/glsl/depthblur_fp.glsl b/src/renderergl2/glsl/depthblur_fp.glsl
new file mode 100644
index 0000000..d71b348
--- /dev/null
+++ b/src/renderergl2/glsl/depthblur_fp.glsl
@@ -0,0 +1,82 @@
+uniform sampler2D u_ScreenImageMap;
+uniform sampler2D u_ScreenDepthMap;
+
+uniform vec4 u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
+varying vec2 var_ScreenTex;
+
+//float gauss[8] = float[8](0.17, 0.17, 0.16, 0.14, 0.12, 0.1, 0.08, 0.06);
+//float gauss[5] = float[5](0.30, 0.23, 0.097, 0.024, 0.0033);
+float gauss[4] = float[4](0.40, 0.24, 0.054, 0.0044);
+//float gauss[3] = float[3](0.60, 0.19, 0.0066);
+#define BLUR_SIZE 4
+
+#if !defined(USE_DEPTH)
+//#define USE_GAUSS
+#endif
+
+float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear)
+{
+ float sampleZDivW = texture2D(depthMap, tex).r;
+ return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
+}
+
+vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar, vec2 scale)
+{
+
+#if defined(USE_DEPTH)
+ float depthCenter = getLinearDepth(depthMap, tex, zFarDivZNear);
+ vec2 slope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y));
+ scale /= clamp(zFarDivZNear * depthCenter / 32.0, 1.0, 2.0);
+#endif
+
+#if defined(USE_HORIZONTAL_BLUR)
+ vec2 direction = vec2(scale.x * 2.0, 0.0);
+ vec2 nudge = vec2(0.0, scale.y * 0.5);
+#else // if defined(USE_VERTICAL_BLUR)
+ vec2 direction = vec2(0.0, scale.y * 2.0);
+ vec2 nudge = vec2(-scale.x * 0.5, 0.0);
+#endif
+
+#if defined(USE_GAUSS)
+ vec4 result = texture2D(imageMap, tex) * gauss[0];
+ float total = gauss[0];
+#else
+ vec4 result = texture2D(imageMap, tex);
+ float total = 1.0;
+#endif
+
+ float zLimit = 5.0 / zFar;
+ int i, j;
+ for (i = 0; i < 2; i++)
+ {
+ for (j = 1; j < BLUR_SIZE; j++)
+ {
+ vec2 offset = direction * (float(j) - 0.25) + nudge;
+#if defined(USE_DEPTH)
+ float depthSample = getLinearDepth(depthMap, tex + offset, zFarDivZNear);
+ float depthExpected = depthCenter + dot(slope, offset);
+ float useSample = float(abs(depthSample - depthExpected) < zLimit);
+#else
+ float useSample = 1.0;
+#endif
+#if defined(USE_GAUSS)
+ result += texture2D(imageMap, tex + offset) * (gauss[j] * useSample);
+ total += gauss[j] * useSample;
+#else
+ result += texture2D(imageMap, tex + offset) * useSample;
+ total += useSample;
+#endif
+ nudge = -nudge;
+ }
+
+ direction = -direction;
+ nudge = -nudge;
+ }
+
+ return result / total;
+}
+
+void main()
+{
+ gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y, u_ViewInfo.zw);
+}
diff --git a/src/renderergl2/glsl/depthblur_vp.glsl b/src/renderergl2/glsl/depthblur_vp.glsl
new file mode 100644
index 0000000..9c47660
--- /dev/null
+++ b/src/renderergl2/glsl/depthblur_vp.glsl
@@ -0,0 +1,16 @@
+attribute vec4 attr_Position;
+attribute vec4 attr_TexCoord0;
+
+uniform vec4 u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
+
+varying vec2 var_ScreenTex;
+
+void main()
+{
+ gl_Position = attr_Position;
+ vec2 wh = vec2(1.0) / u_ViewInfo.zw - vec2(1.0);
+ var_ScreenTex = (floor(attr_TexCoord0.xy * wh) + vec2(0.5)) * u_ViewInfo.zw;
+
+ //vec2 screenCoords = gl_Position.xy / gl_Position.w;
+ //var_ScreenTex = screenCoords * 0.5 + 0.5;
+}
diff --git a/src/renderergl2/glsl/dlight_fp.glsl b/src/renderergl2/glsl/dlight_fp.glsl
new file mode 100644
index 0000000..41be049
--- /dev/null
+++ b/src/renderergl2/glsl/dlight_fp.glsl
@@ -0,0 +1,32 @@
+uniform sampler2D u_DiffuseMap;
+
+uniform int u_AlphaTest;
+
+varying vec2 var_Tex1;
+varying vec4 var_Color;
+
+
+void main()
+{
+ vec4 color = texture2D(u_DiffuseMap, var_Tex1);
+
+ float alpha = color.a * var_Color.a;
+ if (u_AlphaTest == 1)
+ {
+ if (alpha == 0.0)
+ discard;
+ }
+ else if (u_AlphaTest == 2)
+ {
+ if (alpha >= 0.5)
+ discard;
+ }
+ else if (u_AlphaTest == 3)
+ {
+ if (alpha < 0.5)
+ discard;
+ }
+
+ gl_FragColor.rgb = color.rgb * var_Color.rgb;
+ gl_FragColor.a = alpha;
+}
diff --git a/src/renderergl2/glsl/dlight_vp.glsl b/src/renderergl2/glsl/dlight_vp.glsl
new file mode 100644
index 0000000..c326bd7
--- /dev/null
+++ b/src/renderergl2/glsl/dlight_vp.glsl
@@ -0,0 +1,92 @@
+attribute vec3 attr_Position;
+attribute vec4 attr_TexCoord0;
+attribute vec3 attr_Normal;
+
+uniform vec4 u_DlightInfo;
+
+#if defined(USE_DEFORM_VERTEXES)
+uniform int u_DeformGen;
+uniform float u_DeformParams[5];
+uniform float u_Time;
+#endif
+
+uniform vec4 u_Color;
+uniform mat4 u_ModelViewProjectionMatrix;
+
+varying vec2 var_Tex1;
+varying vec4 var_Color;
+
+#if defined(USE_DEFORM_VERTEXES)
+vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st)
+{
+ if (u_DeformGen == 0)
+ {
+ return pos;
+ }
+
+ float base = u_DeformParams[0];
+ float amplitude = u_DeformParams[1];
+ float phase = u_DeformParams[2];
+ float frequency = u_DeformParams[3];
+ float spread = u_DeformParams[4];
+
+ if (u_DeformGen == DGEN_BULGE)
+ {
+ phase *= st.x;
+ }
+ else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH)
+ {
+ phase += dot(pos.xyz, vec3(spread));
+ }
+
+ float value = phase + (u_Time * frequency);
+ float func;
+
+ if (u_DeformGen == DGEN_WAVE_SIN)
+ {
+ func = sin(value * 2.0 * M_PI);
+ }
+ else if (u_DeformGen == DGEN_WAVE_SQUARE)
+ {
+ func = sign(0.5 - fract(value));
+ }
+ else if (u_DeformGen == DGEN_WAVE_TRIANGLE)
+ {
+ func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0;
+ }
+ else if (u_DeformGen == DGEN_WAVE_SAWTOOTH)
+ {
+ func = fract(value);
+ }
+ else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)
+ {
+ func = (1.0 - fract(value));
+ }
+ else // if (u_DeformGen == DGEN_BULGE)
+ {
+ func = sin(value);
+ }
+
+ return pos + normal * (base + func * amplitude);
+}
+#endif
+
+void main()
+{
+ vec3 position = attr_Position;
+ vec3 normal = attr_Normal;
+
+#if defined(USE_DEFORM_VERTEXES)
+ position = DeformPosition(position, normal, attr_TexCoord0.st);
+#endif
+
+ gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0);
+
+ vec3 dist = u_DlightInfo.xyz - position;
+
+ var_Tex1 = dist.xy * u_DlightInfo.a + vec2(0.5);
+ float dlightmod = step(0.0, dot(dist, normal));
+ dlightmod *= clamp(2.0 * (1.0 - abs(dist.z) * u_DlightInfo.a), 0.0, 1.0);
+
+ var_Color = u_Color * dlightmod;
+}
diff --git a/src/renderergl2/glsl/down4x_fp.glsl b/src/renderergl2/glsl/down4x_fp.glsl
new file mode 100644
index 0000000..0f88fb2
--- /dev/null
+++ b/src/renderergl2/glsl/down4x_fp.glsl
@@ -0,0 +1,34 @@
+uniform sampler2D u_TextureMap;
+
+uniform vec2 u_InvTexRes;
+varying vec2 var_TexCoords;
+
+void main()
+{
+ vec4 color;
+ vec2 tc;
+
+ tc = var_TexCoords + u_InvTexRes * vec2(-1.5, -1.5); color = texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2(-0.5, -1.5); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( 0.5, -1.5); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( 1.5, -1.5); color += texture2D(u_TextureMap, tc);
+
+ tc = var_TexCoords + u_InvTexRes * vec2(-1.5, -0.5); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2(-0.5, -0.5); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( 0.5, -0.5); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( 1.5, -0.5); color += texture2D(u_TextureMap, tc);
+
+ tc = var_TexCoords + u_InvTexRes * vec2(-1.5, 0.5); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2(-0.5, 0.5); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( 0.5, 0.5); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( 1.5, 0.5); color += texture2D(u_TextureMap, tc);
+
+ tc = var_TexCoords + u_InvTexRes * vec2(-1.5, 1.5); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2(-0.5, 1.5); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( 0.5, 1.5); color += texture2D(u_TextureMap, tc);
+ tc = var_TexCoords + u_InvTexRes * vec2( 1.5, 1.5); color += texture2D(u_TextureMap, tc);
+
+ color *= 0.0625;
+
+ gl_FragColor = color;
+}
diff --git a/src/renderergl2/glsl/down4x_vp.glsl b/src/renderergl2/glsl/down4x_vp.glsl
new file mode 100644
index 0000000..bdaa74a
--- /dev/null
+++ b/src/renderergl2/glsl/down4x_vp.glsl
@@ -0,0 +1,13 @@
+attribute vec3 attr_Position;
+attribute vec4 attr_TexCoord0;
+
+uniform mat4 u_ModelViewProjectionMatrix;
+
+varying vec2 var_TexCoords;
+
+
+void main()
+{
+ gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0);
+ var_TexCoords = attr_TexCoord0.st;
+}
diff --git a/src/renderergl2/glsl/fogpass_fp.glsl b/src/renderergl2/glsl/fogpass_fp.glsl
new file mode 100644
index 0000000..e2ad465
--- /dev/null
+++ b/src/renderergl2/glsl/fogpass_fp.glsl
@@ -0,0 +1,9 @@
+uniform vec4 u_Color;
+
+varying float var_Scale;
+
+void main()
+{
+ gl_FragColor = u_Color;
+ gl_FragColor.a = sqrt(clamp(var_Scale, 0.0, 1.0));
+}
diff --git a/src/renderergl2/glsl/fogpass_vp.glsl b/src/renderergl2/glsl/fogpass_vp.glsl
new file mode 100644
index 0000000..c8ec9a9
--- /dev/null
+++ b/src/renderergl2/glsl/fogpass_vp.glsl
@@ -0,0 +1,117 @@
+attribute vec3 attr_Position;
+attribute vec3 attr_Normal;
+
+attribute vec4 attr_TexCoord0;
+
+#if defined(USE_VERTEX_ANIMATION)
+attribute vec3 attr_Position2;
+attribute vec3 attr_Normal2;
+#endif
+
+uniform vec4 u_FogDistance;
+uniform vec4 u_FogDepth;
+uniform float u_FogEyeT;
+
+#if defined(USE_DEFORM_VERTEXES)
+uniform int u_DeformGen;
+uniform float u_DeformParams[5];
+#endif
+
+uniform float u_Time;
+uniform mat4 u_ModelViewProjectionMatrix;
+
+#if defined(USE_VERTEX_ANIMATION)
+uniform float u_VertexLerp;
+#endif
+
+uniform vec4 u_Color;
+
+varying float var_Scale;
+
+#if defined(USE_DEFORM_VERTEXES)
+vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st)
+{
+ if (u_DeformGen == 0)
+ {
+ return pos;
+ }
+
+ float base = u_DeformParams[0];
+ float amplitude = u_DeformParams[1];
+ float phase = u_DeformParams[2];
+ float frequency = u_DeformParams[3];
+ float spread = u_DeformParams[4];
+
+ if (u_DeformGen == DGEN_BULGE)
+ {
+ phase *= st.x;
+ }
+ else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH)
+ {
+ phase += dot(pos.xyz, vec3(spread));
+ }
+
+ float value = phase + (u_Time * frequency);
+ float func;
+
+ if (u_DeformGen == DGEN_WAVE_SIN)
+ {
+ func = sin(value * 2.0 * M_PI);
+ }
+ else if (u_DeformGen == DGEN_WAVE_SQUARE)
+ {
+ func = sign(0.5 - fract(value));
+ }
+ else if (u_DeformGen == DGEN_WAVE_TRIANGLE)
+ {
+ func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0;
+ }
+ else if (u_DeformGen == DGEN_WAVE_SAWTOOTH)
+ {
+ func = fract(value);
+ }
+ else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)
+ {
+ func = (1.0 - fract(value));
+ }
+ else // if (u_DeformGen == DGEN_BULGE)
+ {
+ func = sin(value);
+ }
+
+ return pos + normal * (base + func * amplitude);
+}
+#endif
+
+float CalcFog(vec3 position)
+{
+ float s = dot(vec4(position, 1.0), u_FogDistance) * 8.0;
+ float t = dot(vec4(position, 1.0), u_FogDepth);
+
+ float eyeOutside = float(u_FogEyeT < 0.0);
+ float fogged = float(t >= eyeOutside);
+
+ t += 1e-6;
+ t *= fogged / (t - u_FogEyeT * eyeOutside);
+
+ return s * t;
+}
+
+void main()
+{
+#if defined(USE_VERTEX_ANIMATION)
+ vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
+ vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
+#else
+ vec3 position = attr_Position;
+ vec3 normal = attr_Normal;
+#endif
+
+#if defined(USE_DEFORM_VERTEXES)
+ position.xyz = DeformPosition(position.xyz, normal, attr_TexCoord0.st);
+#endif
+
+ gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0);
+
+ var_Scale = CalcFog(position) * u_Color.a * u_Color.a;
+}
diff --git a/src/renderergl2/glsl/generic_fp.glsl b/src/renderergl2/glsl/generic_fp.glsl
new file mode 100644
index 0000000..c0a4940
--- /dev/null
+++ b/src/renderergl2/glsl/generic_fp.glsl
@@ -0,0 +1,33 @@
+uniform sampler2D u_DiffuseMap;
+
+uniform int u_AlphaTest;
+
+varying vec2 var_DiffuseTex;
+
+varying vec4 var_Color;
+
+
+void main()
+{
+ vec4 color = texture2D(u_DiffuseMap, var_DiffuseTex);
+
+ float alpha = color.a * var_Color.a;
+ if (u_AlphaTest == 1)
+ {
+ if (alpha == 0.0)
+ discard;
+ }
+ else if (u_AlphaTest == 2)
+ {
+ if (alpha >= 0.5)
+ discard;
+ }
+ else if (u_AlphaTest == 3)
+ {
+ if (alpha < 0.5)
+ discard;
+ }
+
+ gl_FragColor.rgb = color.rgb * var_Color.rgb;
+ gl_FragColor.a = alpha;
+}
diff --git a/src/renderergl2/glsl/generic_vp.glsl b/src/renderergl2/glsl/generic_vp.glsl
new file mode 100644
index 0000000..bbe08e8
--- /dev/null
+++ b/src/renderergl2/glsl/generic_vp.glsl
@@ -0,0 +1,239 @@
+attribute vec3 attr_Position;
+attribute vec3 attr_Normal;
+
+#if defined(USE_VERTEX_ANIMATION)
+attribute vec3 attr_Position2;
+attribute vec3 attr_Normal2;
+#endif
+
+attribute vec4 attr_Color;
+attribute vec4 attr_TexCoord0;
+
+#if defined(USE_TCGEN)
+attribute vec4 attr_TexCoord1;
+#endif
+
+uniform vec4 u_DiffuseTexMatrix;
+uniform vec4 u_DiffuseTexOffTurb;
+
+#if defined(USE_TCGEN) || defined(USE_RGBAGEN)
+uniform vec3 u_LocalViewOrigin;
+#endif
+
+#if defined(USE_TCGEN)
+uniform int u_TCGen0;
+uniform vec3 u_TCGen0Vector0;
+uniform vec3 u_TCGen0Vector1;
+#endif
+
+#if defined(USE_FOG)
+uniform vec4 u_FogDistance;
+uniform vec4 u_FogDepth;
+uniform float u_FogEyeT;
+uniform vec4 u_FogColorMask;
+#endif
+
+#if defined(USE_DEFORM_VERTEXES)
+uniform int u_DeformGen;
+uniform float u_DeformParams[5];
+uniform float u_Time;
+#endif
+
+uniform mat4 u_ModelViewProjectionMatrix;
+uniform vec4 u_BaseColor;
+uniform vec4 u_VertColor;
+
+#if defined(USE_RGBAGEN)
+uniform int u_ColorGen;
+uniform int u_AlphaGen;
+uniform vec3 u_AmbientLight;
+uniform vec3 u_DirectedLight;
+uniform vec3 u_ModelLightDir;
+uniform float u_PortalRange;
+#endif
+
+#if defined(USE_VERTEX_ANIMATION)
+uniform float u_VertexLerp;
+#endif
+
+varying vec2 var_DiffuseTex;
+varying vec4 var_Color;
+
+#if defined(USE_DEFORM_VERTEXES)
+vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st)
+{
+ float base = u_DeformParams[0];
+ float amplitude = u_DeformParams[1];
+ float phase = u_DeformParams[2];
+ float frequency = u_DeformParams[3];
+ float spread = u_DeformParams[4];
+
+ if (u_DeformGen == DGEN_BULGE)
+ {
+ phase *= st.x;
+ }
+ else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH)
+ {
+ phase += dot(pos.xyz, vec3(spread));
+ }
+
+ float value = phase + (u_Time * frequency);
+ float func;
+
+ if (u_DeformGen == DGEN_WAVE_SIN)
+ {
+ func = sin(value * 2.0 * M_PI);
+ }
+ else if (u_DeformGen == DGEN_WAVE_SQUARE)
+ {
+ func = sign(fract(0.5 - value));
+ }
+ else if (u_DeformGen == DGEN_WAVE_TRIANGLE)
+ {
+ func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0;
+ }
+ else if (u_DeformGen == DGEN_WAVE_SAWTOOTH)
+ {
+ func = fract(value);
+ }
+ else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)
+ {
+ func = (1.0 - fract(value));
+ }
+ else // if (u_DeformGen == DGEN_BULGE)
+ {
+ func = sin(value);
+ }
+
+ return pos + normal * (base + func * amplitude);
+}
+#endif
+
+#if defined(USE_TCGEN)
+vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 TCGenVector1)
+{
+ vec2 tex = attr_TexCoord0.st;
+
+ if (TCGen == TCGEN_LIGHTMAP)
+ {
+ tex = attr_TexCoord1.st;
+ }
+ else if (TCGen == TCGEN_ENVIRONMENT_MAPPED)
+ {
+ vec3 viewer = normalize(u_LocalViewOrigin - position);
+ vec2 ref = reflect(viewer, normal).yz;
+ tex.s = ref.x * -0.5 + 0.5;
+ tex.t = ref.y * 0.5 + 0.5;
+ }
+ else if (TCGen == TCGEN_VECTOR)
+ {
+ tex = vec2(dot(position, TCGenVector0), dot(position, TCGenVector1));
+ }
+
+ return tex;
+}
+#endif
+
+#if defined(USE_TCMOD)
+vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb)
+{
+ float amplitude = offTurb.z;
+ float phase = offTurb.w * 2.0 * M_PI;
+ vec2 st2;
+ st2.x = st.x * texMatrix.x + (st.y * texMatrix.z + offTurb.x);
+ st2.y = st.x * texMatrix.y + (st.y * texMatrix.w + offTurb.y);
+
+ vec2 offsetPos = vec2(position.x + position.z, position.y);
+
+ vec2 texOffset = sin(offsetPos * (2.0 * M_PI / 1024.0) + vec2(phase));
+
+ return st2 + texOffset * amplitude;
+}
+#endif
+
+#if defined(USE_RGBAGEN)
+vec4 CalcColor(vec3 position, vec3 normal)
+{
+ vec4 color = u_VertColor * attr_Color + u_BaseColor;
+
+ if (u_ColorGen == CGEN_LIGHTING_DIFFUSE)
+ {
+ float incoming = clamp(dot(normal, u_ModelLightDir), 0.0, 1.0);
+
+ color.rgb = clamp(u_DirectedLight * incoming + u_AmbientLight, 0.0, 1.0);
+ }
+
+ vec3 viewer = u_LocalViewOrigin - position;
+
+ if (u_AlphaGen == AGEN_LIGHTING_SPECULAR)
+ {
+ vec3 lightDir = normalize(vec3(-960.0, 1980.0, 96.0) - position);
+ vec3 reflected = -reflect(lightDir, normal);
+
+ color.a = clamp(dot(reflected, normalize(viewer)), 0.0, 1.0);
+ color.a *= color.a;
+ color.a *= color.a;
+ }
+ else if (u_AlphaGen == AGEN_PORTAL)
+ {
+ color.a = clamp(length(viewer) / u_PortalRange, 0.0, 1.0);
+ }
+
+ return color;
+}
+#endif
+
+#if defined(USE_FOG)
+float CalcFog(vec3 position)
+{
+ float s = dot(vec4(position, 1.0), u_FogDistance) * 8.0;
+ float t = dot(vec4(position, 1.0), u_FogDepth);
+
+ float eyeOutside = float(u_FogEyeT < 0.0);
+ float fogged = float(t >= eyeOutside);
+
+ t += 1e-6;
+ t *= fogged / (t - u_FogEyeT * eyeOutside);
+
+ return s * t;
+}
+#endif
+
+void main()
+{
+#if defined(USE_VERTEX_ANIMATION)
+ vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
+ vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
+#else
+ vec3 position = attr_Position;
+ vec3 normal = attr_Normal;
+#endif
+
+#if defined(USE_DEFORM_VERTEXES)
+ position = DeformPosition(position, normal, attr_TexCoord0.st);
+#endif
+
+ gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0);
+
+#if defined(USE_TCGEN)
+ vec2 tex = GenTexCoords(u_TCGen0, position, normal, u_TCGen0Vector0, u_TCGen0Vector1);
+#else
+ vec2 tex = attr_TexCoord0.st;
+#endif
+
+#if defined(USE_TCMOD)
+ var_DiffuseTex = ModTexCoords(tex, position, u_DiffuseTexMatrix, u_DiffuseTexOffTurb);
+#else
+ var_DiffuseTex = tex;
+#endif
+
+#if defined(USE_RGBAGEN)
+ var_Color = CalcColor(position, normal);
+#else
+ var_Color = u_VertColor * attr_Color + u_BaseColor;
+#endif
+
+#if defined(USE_FOG)
+ var_Color *= vec4(1.0) - u_FogColorMask * sqrt(clamp(CalcFog(position), 0.0, 1.0));
+#endif
+}
diff --git a/src/renderergl2/glsl/lightall_fp.glsl b/src/renderergl2/glsl/lightall_fp.glsl
new file mode 100644
index 0000000..8e7c9b4
--- /dev/null
+++ b/src/renderergl2/glsl/lightall_fp.glsl
@@ -0,0 +1,429 @@
+uniform sampler2D u_DiffuseMap;
+
+#if defined(USE_LIGHTMAP)
+uniform sampler2D u_LightMap;
+#endif
+
+#if defined(USE_NORMALMAP)
+uniform sampler2D u_NormalMap;
+#endif
+
+#if defined(USE_DELUXEMAP)
+uniform sampler2D u_DeluxeMap;
+#endif
+
+#if defined(USE_SPECULARMAP)
+uniform sampler2D u_SpecularMap;
+#endif
+
+#if defined(USE_SHADOWMAP)
+uniform sampler2D u_ShadowMap;
+#endif
+
+#if defined(USE_CUBEMAP)
+uniform samplerCube u_CubeMap;
+#endif
+
+#if defined(USE_NORMALMAP) || defined(USE_DELUXEMAP) || defined(USE_SPECULARMAP) || defined(USE_CUBEMAP)
+// y = deluxe, w = cube
+uniform vec4 u_EnableTextures;
+#endif
+
+#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
+uniform vec3 u_PrimaryLightColor;
+uniform vec3 u_PrimaryLightAmbient;
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+uniform vec4 u_NormalScale;
+uniform vec4 u_SpecularScale;
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+#if defined(USE_CUBEMAP)
+uniform vec4 u_CubeMapInfo;
+#endif
+#endif
+
+uniform int u_AlphaTest;
+
+varying vec4 var_TexCoords;
+
+varying vec4 var_Color;
+#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
+varying vec4 var_ColorAmbient;
+#endif
+
+#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
+varying vec4 var_Normal;
+varying vec4 var_Tangent;
+varying vec4 var_Bitangent;
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+varying vec4 var_LightDir;
+#endif
+
+#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
+varying vec4 var_PrimaryLightDir;
+#endif
+
+
+#define EPSILON 0.00000001
+
+#if defined(USE_PARALLAXMAP)
+float SampleDepth(sampler2D normalMap, vec2 t)
+{
+ #if defined(SWIZZLE_NORMALMAP)
+ return 1.0 - texture2D(normalMap, t).r;
+ #else
+ return 1.0 - texture2D(normalMap, t).a;
+ #endif
+}
+
+float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap)
+{
+ const int linearSearchSteps = 16;
+ const int binarySearchSteps = 6;
+
+ // current size of search window
+ float size = 1.0 / float(linearSearchSteps);
+
+ // current depth position
+ float depth = 0.0;
+
+ // best match found (starts with last position 1.0)
+ float bestDepth = 1.0;
+
+ // texture depth at best depth
+ float texDepth = 0.0;
+
+ float prevT = SampleDepth(normalMap, dp);
+ float prevTexDepth = prevT;
+
+ // search front to back for first point inside object
+ for(int i = 0; i < linearSearchSteps - 1; ++i)
+ {
+ depth += size;
+
+ float t = SampleDepth(normalMap, dp + ds * depth);
+
+ if(bestDepth > 0.996) // if no depth found yet
+ if(depth >= t)
+ {
+ bestDepth = depth; // store best depth
+ texDepth = t;
+ prevTexDepth = prevT;
+ }
+ prevT = t;
+ }
+
+ depth = bestDepth;
+
+#if !defined (USE_RELIEFMAP)
+ float div = 1.0 / (1.0 + (prevTexDepth - texDepth) * float(linearSearchSteps));
+ bestDepth -= (depth - size - prevTexDepth) * div;
+#else
+ // recurse around first point (depth) for closest match
+ for(int i = 0; i < binarySearchSteps; ++i)
+ {
+ size *= 0.5;
+
+ float t = SampleDepth(normalMap, dp + ds * depth);
+
+ if(depth >= t)
+ {
+ bestDepth = depth;
+ depth -= 2.0 * size;
+ }
+
+ depth += size;
+ }
+#endif
+
+ return bestDepth;
+}
+#endif
+
+vec3 CalcDiffuse(vec3 diffuseAlbedo, float NH, float EH, float roughness)
+{
+#if defined(USE_BURLEY)
+ // modified from https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf
+ float fd90 = -0.5 + EH * EH * roughness;
+ float burley = 1.0 + fd90 * 0.04 / NH;
+ burley *= burley;
+ return diffuseAlbedo * burley;
+#else
+ return diffuseAlbedo;
+#endif
+}
+
+vec3 EnvironmentBRDF(float roughness, float NE, vec3 specular)
+{
+ // from http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf
+ float v = 1.0 - max(roughness, NE);
+ v *= v * v;
+ return vec3(v) + specular;
+}
+
+vec3 CalcSpecular(vec3 specular, float NH, float EH, float roughness)
+{
+ // from http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf
+ float rr = roughness*roughness;
+ float rrrr = rr*rr;
+ float d = (NH * NH) * (rrrr - 1.0) + 1.0;
+ float v = (EH * EH) * (roughness + 0.5);
+ return specular * (rrrr / (4.0 * d * d * v));
+}
+
+
+float CalcLightAttenuation(float point, float normDist)
+{
+ // zero light at 1.0, approximating q3 style
+ // also don't attenuate directional light
+ float attenuation = (0.5 * normDist - 1.5) * point + 1.0;
+
+ // clamp attenuation
+ #if defined(NO_LIGHT_CLAMP)
+ attenuation = max(attenuation, 0.0);
+ #else
+ attenuation = clamp(attenuation, 0.0, 1.0);
+ #endif
+
+ return attenuation;
+}
+
+
+void main()
+{
+ vec3 viewDir, lightColor, ambientColor, reflectance;
+ vec3 L, N, E, H;
+ float NL, NH, NE, EH, attenuation;
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+ mat3 tangentToWorld = mat3(var_Tangent.xyz, var_Bitangent.xyz, var_Normal.xyz);
+ viewDir = vec3(var_Normal.w, var_Tangent.w, var_Bitangent.w);
+ E = normalize(viewDir);
+#endif
+
+ lightColor = var_Color.rgb;
+
+#if defined(USE_LIGHTMAP)
+ vec4 lightmapColor = texture2D(u_LightMap, var_TexCoords.zw);
+ #if defined(RGBM_LIGHTMAP)
+ lightmapColor.rgb *= lightmapColor.a;
+ #endif
+ #if defined(USE_PBR) && !defined(USE_FAST_LIGHT)
+ lightmapColor.rgb *= lightmapColor.rgb;
+ #endif
+ lightColor *= lightmapColor.rgb;
+#endif
+
+ vec2 texCoords = var_TexCoords.xy;
+
+#if defined(USE_PARALLAXMAP)
+ vec3 offsetDir = viewDir * tangentToWorld;
+
+ offsetDir.xy *= -u_NormalScale.a / offsetDir.z;
+
+ texCoords += offsetDir.xy * RayIntersectDisplaceMap(texCoords, offsetDir.xy, u_NormalMap);
+#endif
+
+ vec4 diffuse = texture2D(u_DiffuseMap, texCoords);
+
+ float alpha = diffuse.a * var_Color.a;
+ if (u_AlphaTest == 1)
+ {
+ if (alpha == 0.0)
+ discard;
+ }
+ else if (u_AlphaTest == 2)
+ {
+ if (alpha >= 0.5)
+ discard;
+ }
+ else if (u_AlphaTest == 3)
+ {
+ if (alpha < 0.5)
+ discard;
+ }
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+ L = var_LightDir.xyz;
+ #if defined(USE_DELUXEMAP)
+ L += (texture2D(u_DeluxeMap, var_TexCoords.zw).xyz - vec3(0.5)) * u_EnableTextures.y;
+ #endif
+ float sqrLightDist = dot(L, L);
+ L /= sqrt(sqrLightDist);
+
+ #if defined(USE_LIGHT_VECTOR)
+ attenuation = CalcLightAttenuation(float(var_LightDir.w > 0.0), var_LightDir.w / sqrLightDist);
+ #else
+ attenuation = 1.0;
+ #endif
+
+ #if defined(USE_NORMALMAP)
+ #if defined(SWIZZLE_NORMALMAP)
+ N.xy = texture2D(u_NormalMap, texCoords).ag - vec2(0.5);
+ #else
+ N.xy = texture2D(u_NormalMap, texCoords).rg - vec2(0.5);
+ #endif
+ N.xy *= u_NormalScale.xy;
+ N.z = sqrt(clamp((0.25 - N.x * N.x) - N.y * N.y, 0.0, 1.0));
+ N = tangentToWorld * N;
+ #else
+ N = var_Normal.xyz;
+ #endif
+
+ N = normalize(N);
+
+ #if defined(USE_SHADOWMAP)
+ vec2 shadowTex = gl_FragCoord.xy * r_FBufScale;
+ float shadowValue = texture2D(u_ShadowMap, shadowTex).r;
+
+ // surfaces not facing the light are always shadowed
+ shadowValue *= clamp(dot(N, var_PrimaryLightDir.xyz), 0.0, 1.0);
+
+ #if defined(SHADOWMAP_MODULATE)
+ lightColor *= shadowValue * (1.0 - u_PrimaryLightAmbient.r) + u_PrimaryLightAmbient.r;
+ #endif
+ #endif
+
+ #if !defined(USE_LIGHT_VECTOR)
+ ambientColor = lightColor;
+ float surfNL = clamp(dot(var_Normal.xyz, L), 0.0, 1.0);
+
+ // reserve 25% ambient to avoid black areas on normalmaps
+ lightColor *= 0.75;
+
+ // Scale the incoming light to compensate for the baked-in light angle
+ // attenuation.
+ lightColor /= max(surfNL, 0.25);
+
+ // Recover any unused light as ambient, in case attenuation is over 4x or
+ // light is below the surface
+ ambientColor = max(ambientColor - lightColor * surfNL, vec3(0.0));
+ #else
+ ambientColor = var_ColorAmbient.rgb;
+ #endif
+
+ NL = clamp(dot(N, L), 0.0, 1.0);
+ NE = clamp(dot(N, E), 0.0, 1.0);
+
+ #if defined(USE_SPECULARMAP)
+ vec4 specular = texture2D(u_SpecularMap, texCoords);
+ #else
+ vec4 specular = vec4(1.0);
+ #endif
+ specular *= u_SpecularScale;
+
+ #if defined(USE_PBR)
+ diffuse.rgb *= diffuse.rgb;
+ #endif
+
+ #if defined(USE_PBR)
+ // diffuse rgb is base color
+ // specular red is gloss
+ // specular green is metallicness
+ float gloss = specular.r;
+ float metal = specular.g;
+ specular.rgb = metal * diffuse.rgb + vec3(0.04 - 0.04 * metal);
+ diffuse.rgb *= 1.0 - metal;
+ #else
+ // diffuse rgb is diffuse
+ // specular rgb is specular reflectance at normal incidence
+ // specular alpha is gloss
+ float gloss = specular.a;
+
+ // adjust diffuse by specular reflectance, to maintain energy conservation
+ diffuse.rgb *= vec3(1.0) - specular.rgb;
+ #endif
+
+ #if defined(GLOSS_IS_GLOSS)
+ float roughness = exp2(-3.0 * gloss);
+ #elif defined(GLOSS_IS_SMOOTHNESS)
+ float roughness = 1.0 - gloss;
+ #elif defined(GLOSS_IS_ROUGHNESS)
+ float roughness = gloss;
+ #elif defined(GLOSS_IS_SHININESS)
+ float roughness = pow(2.0 / (8190.0 * gloss + 2.0), 0.25);
+ #endif
+
+ reflectance = CalcDiffuse(diffuse.rgb, NH, EH, roughness);
+
+ gl_FragColor.rgb = lightColor * reflectance * (attenuation * NL);
+ gl_FragColor.rgb += ambientColor * diffuse.rgb;
+
+ #if defined(USE_CUBEMAP)
+ reflectance = EnvironmentBRDF(roughness, NE, specular.rgb);
+
+ vec3 R = reflect(E, N);
+
+ // parallax corrected cubemap (cheaper trick)
+ // from http://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
+ vec3 parallax = u_CubeMapInfo.xyz + u_CubeMapInfo.w * viewDir;
+
+ vec3 cubeLightColor = textureCubeLod(u_CubeMap, R + parallax, ROUGHNESS_MIPS * roughness).rgb * u_EnableTextures.w;
+
+ // normalize cubemap based on last roughness mip (~diffuse)
+ // multiplying cubemap values by lighting below depends on either this or the cubemap being normalized at generation
+ //vec3 cubeLightDiffuse = max(textureCubeLod(u_CubeMap, N, ROUGHNESS_MIPS).rgb, 0.5 / 255.0);
+ //cubeLightColor /= dot(cubeLightDiffuse, vec3(0.2125, 0.7154, 0.0721));
+
+ #if defined(USE_PBR)
+ cubeLightColor *= cubeLightColor;
+ #endif
+
+ // multiply cubemap values by lighting
+ // not technically correct, but helps make reflections look less unnatural
+ //cubeLightColor *= lightColor * (attenuation * NL) + ambientColor;
+
+ gl_FragColor.rgb += cubeLightColor * reflectance;
+ #endif
+
+ #if defined(USE_PRIMARY_LIGHT) || defined(SHADOWMAP_MODULATE)
+ vec3 L2, H2;
+ float NL2, EH2, NH2;
+
+ L2 = var_PrimaryLightDir.xyz;
+
+ // enable when point lights are supported as primary lights
+ //sqrLightDist = dot(L2, L2);
+ //L2 /= sqrt(sqrLightDist);
+
+ NL2 = clamp(dot(N, L2), 0.0, 1.0);
+ H2 = normalize(L2 + E);
+ EH2 = clamp(dot(E, H2), 0.0, 1.0);
+ NH2 = clamp(dot(N, H2), 0.0, 1.0);
+
+ reflectance = CalcSpecular(specular.rgb, NH2, EH2, roughness);
+
+ // bit of a hack, with modulated shadowmaps, ignore diffuse
+ #if !defined(SHADOWMAP_MODULATE)
+ reflectance += CalcDiffuse(diffuse.rgb, NH2, EH2, roughness);
+ #endif
+
+ lightColor = u_PrimaryLightColor;
+
+ #if defined(USE_SHADOWMAP)
+ lightColor *= shadowValue;
+ #endif
+
+ // enable when point lights are supported as primary lights
+ //lightColor *= CalcLightAttenuation(float(u_PrimaryLightDir.w > 0.0), u_PrimaryLightDir.w / sqrLightDist);
+
+ gl_FragColor.rgb += lightColor * reflectance * NL2;
+ #endif
+
+ #if defined(USE_PBR)
+ gl_FragColor.rgb = sqrt(gl_FragColor.rgb);
+ #endif
+
+#else
+
+ gl_FragColor.rgb = diffuse.rgb * lightColor;
+
+#endif
+
+ gl_FragColor.a = alpha;
+}
diff --git a/src/renderergl2/glsl/lightall_vp.glsl b/src/renderergl2/glsl/lightall_vp.glsl
new file mode 100644
index 0000000..e5b3c4f
--- /dev/null
+++ b/src/renderergl2/glsl/lightall_vp.glsl
@@ -0,0 +1,246 @@
+attribute vec4 attr_TexCoord0;
+#if defined(USE_LIGHTMAP) || defined(USE_TCGEN)
+attribute vec4 attr_TexCoord1;
+#endif
+attribute vec4 attr_Color;
+
+attribute vec3 attr_Position;
+attribute vec3 attr_Normal;
+attribute vec4 attr_Tangent;
+
+#if defined(USE_VERTEX_ANIMATION)
+attribute vec3 attr_Position2;
+attribute vec3 attr_Normal2;
+attribute vec4 attr_Tangent2;
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR)
+attribute vec3 attr_LightDirection;
+#endif
+
+#if defined(USE_DELUXEMAP)
+uniform vec4 u_EnableTextures; // x = normal, y = deluxe, z = specular, w = cube
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+uniform vec3 u_ViewOrigin;
+#endif
+
+#if defined(USE_TCGEN)
+uniform int u_TCGen0;
+uniform vec3 u_TCGen0Vector0;
+uniform vec3 u_TCGen0Vector1;
+uniform vec3 u_LocalViewOrigin;
+#endif
+
+#if defined(USE_TCMOD)
+uniform vec4 u_DiffuseTexMatrix;
+uniform vec4 u_DiffuseTexOffTurb;
+#endif
+
+uniform mat4 u_ModelViewProjectionMatrix;
+uniform vec4 u_BaseColor;
+uniform vec4 u_VertColor;
+
+#if defined(USE_MODELMATRIX)
+uniform mat4 u_ModelMatrix;
+#endif
+
+#if defined(USE_VERTEX_ANIMATION)
+uniform float u_VertexLerp;
+#endif
+
+#if defined(USE_LIGHT_VECTOR)
+uniform vec4 u_LightOrigin;
+uniform float u_LightRadius;
+uniform vec3 u_DirectedLight;
+uniform vec3 u_AmbientLight;
+#endif
+
+#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
+uniform vec4 u_PrimaryLightOrigin;
+uniform float u_PrimaryLightRadius;
+#endif
+
+varying vec4 var_TexCoords;
+
+varying vec4 var_Color;
+#if defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT)
+varying vec4 var_ColorAmbient;
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+varying vec4 var_Normal;
+varying vec4 var_Tangent;
+varying vec4 var_Bitangent;
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+varying vec4 var_LightDir;
+#endif
+
+#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
+varying vec4 var_PrimaryLightDir;
+#endif
+
+#if defined(USE_TCGEN)
+vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 TCGenVector1)
+{
+ vec2 tex = attr_TexCoord0.st;
+
+ if (TCGen == TCGEN_LIGHTMAP)
+ {
+ tex = attr_TexCoord1.st;
+ }
+ else if (TCGen == TCGEN_ENVIRONMENT_MAPPED)
+ {
+ vec3 viewer = normalize(u_LocalViewOrigin - position);
+ vec2 ref = reflect(viewer, normal).yz;
+ tex.s = ref.x * -0.5 + 0.5;
+ tex.t = ref.y * 0.5 + 0.5;
+ }
+ else if (TCGen == TCGEN_VECTOR)
+ {
+ tex = vec2(dot(position, TCGenVector0), dot(position, TCGenVector1));
+ }
+
+ return tex;
+}
+#endif
+
+#if defined(USE_TCMOD)
+vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb)
+{
+ float amplitude = offTurb.z;
+ float phase = offTurb.w * 2.0 * M_PI;
+ vec2 st2;
+ st2.x = st.x * texMatrix.x + (st.y * texMatrix.z + offTurb.x);
+ st2.y = st.x * texMatrix.y + (st.y * texMatrix.w + offTurb.y);
+
+ vec2 offsetPos = vec2(position.x + position.z, position.y);
+
+ vec2 texOffset = sin(offsetPos * (2.0 * M_PI / 1024.0) + vec2(phase));
+
+ return st2 + texOffset * amplitude;
+}
+#endif
+
+
+float CalcLightAttenuation(float point, float normDist)
+{
+ // zero light at 1.0, approximating q3 style
+ // also don't attenuate directional light
+ float attenuation = (0.5 * normDist - 1.5) * point + 1.0;
+
+ // clamp attenuation
+ #if defined(NO_LIGHT_CLAMP)
+ attenuation = max(attenuation, 0.0);
+ #else
+ attenuation = clamp(attenuation, 0.0, 1.0);
+ #endif
+
+ return attenuation;
+}
+
+
+void main()
+{
+#if defined(USE_VERTEX_ANIMATION)
+ vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
+ vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
+ #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+ vec3 tangent = mix(attr_Tangent.xyz, attr_Tangent2.xyz, u_VertexLerp);
+ #endif
+#else
+ vec3 position = attr_Position;
+ vec3 normal = attr_Normal;
+ #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+ vec3 tangent = attr_Tangent.xyz;
+ #endif
+#endif
+
+#if defined(USE_TCGEN)
+ vec2 texCoords = GenTexCoords(u_TCGen0, position, normal, u_TCGen0Vector0, u_TCGen0Vector1);
+#else
+ vec2 texCoords = attr_TexCoord0.st;
+#endif
+
+#if defined(USE_TCMOD)
+ var_TexCoords.xy = ModTexCoords(texCoords, position, u_DiffuseTexMatrix, u_DiffuseTexOffTurb);
+#else
+ var_TexCoords.xy = texCoords;
+#endif
+
+ gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0);
+
+#if defined(USE_MODELMATRIX)
+ position = (u_ModelMatrix * vec4(position, 1.0)).xyz;
+ normal = (u_ModelMatrix * vec4(normal, 0.0)).xyz;
+ #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+ tangent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz;
+ #endif
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+ vec3 bitangent = cross(normal, tangent) * attr_Tangent.w;
+#endif
+
+#if defined(USE_LIGHT_VECTOR)
+ vec3 L = u_LightOrigin.xyz - (position * u_LightOrigin.w);
+#elif defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+ vec3 L = attr_LightDirection;
+ #if defined(USE_MODELMATRIX)
+ L = (u_ModelMatrix * vec4(L, 0.0)).xyz;
+ #endif
+#endif
+
+#if defined(USE_LIGHTMAP)
+ var_TexCoords.zw = attr_TexCoord1.st;
+#endif
+
+ var_Color = u_VertColor * attr_Color + u_BaseColor;
+
+#if defined(USE_LIGHT_VECTOR)
+ #if defined(USE_FAST_LIGHT)
+ float sqrLightDist = dot(L, L);
+ float NL = clamp(dot(normalize(normal), L) / sqrt(sqrLightDist), 0.0, 1.0);
+ float attenuation = CalcLightAttenuation(u_LightOrigin.w, u_LightRadius * u_LightRadius / sqrLightDist);
+
+ var_Color.rgb *= u_DirectedLight * (attenuation * NL) + u_AmbientLight;
+ #else
+ var_ColorAmbient.rgb = u_AmbientLight * var_Color.rgb;
+ var_Color.rgb *= u_DirectedLight;
+ #if defined(USE_PBR)
+ var_ColorAmbient.rgb *= var_ColorAmbient.rgb;
+ #endif
+ #endif
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) && defined(USE_PBR)
+ var_Color.rgb *= var_Color.rgb;
+#endif
+
+#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
+ var_PrimaryLightDir.xyz = u_PrimaryLightOrigin.xyz - (position * u_PrimaryLightOrigin.w);
+ var_PrimaryLightDir.w = u_PrimaryLightRadius * u_PrimaryLightRadius;
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+ #if defined(USE_LIGHT_VECTOR)
+ var_LightDir = vec4(L, u_LightRadius * u_LightRadius);
+ #else
+ var_LightDir = vec4(L, 0.0);
+ #endif
+ #if defined(USE_DELUXEMAP)
+ var_LightDir -= u_EnableTextures.y * var_LightDir;
+ #endif
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+ vec3 viewDir = u_ViewOrigin - position;
+ // store view direction in tangent space to save on varyings
+ var_Normal = vec4(normal, viewDir.x);
+ var_Tangent = vec4(tangent, viewDir.y);
+ var_Bitangent = vec4(bitangent, viewDir.z);
+#endif
+}
diff --git a/src/renderergl2/glsl/pshadow_fp.glsl b/src/renderergl2/glsl/pshadow_fp.glsl
new file mode 100644
index 0000000..c196f48
--- /dev/null
+++ b/src/renderergl2/glsl/pshadow_fp.glsl
@@ -0,0 +1,78 @@
+uniform sampler2D u_ShadowMap;
+
+uniform vec3 u_LightForward;
+uniform vec3 u_LightUp;
+uniform vec3 u_LightRight;
+uniform vec4 u_LightOrigin;
+uniform float u_LightRadius;
+varying vec3 var_Position;
+varying vec3 var_Normal;
+
+void main()
+{
+ vec3 lightToPos = var_Position - u_LightOrigin.xyz;
+ vec2 st = vec2(-dot(u_LightRight, lightToPos), dot(u_LightUp, lightToPos));
+
+ float fade = length(st);
+
+#if defined(USE_DISCARD)
+ if (fade >= 1.0)
+ {
+ discard;
+ }
+#endif
+
+ fade = clamp(8.0 - fade * 8.0, 0.0, 1.0);
+
+ st = st * 0.5 + vec2(0.5);
+
+#if defined(USE_SOLID_PSHADOWS)
+ float intensity = max(sign(u_LightRadius - length(lightToPos)), 0.0);
+#else
+ float intensity = clamp((1.0 - dot(lightToPos, lightToPos) / (u_LightRadius * u_LightRadius)) * 2.0, 0.0, 1.0);
+#endif
+
+ float lightDist = length(lightToPos);
+ float dist;
+
+#if defined(USE_DISCARD)
+ if (dot(u_LightForward, lightToPos) <= 0.0)
+ {
+ discard;
+ }
+
+ if (dot(var_Normal, lightToPos) > 0.0)
+ {
+ discard;
+ }
+#else
+ intensity *= max(sign(dot(u_LightForward, lightToPos)), 0.0);
+ intensity *= max(sign(-dot(var_Normal, lightToPos)), 0.0);
+#endif
+
+ intensity *= fade;
+
+ float part;
+#if defined(USE_PCF)
+ part = float(texture2D(u_ShadowMap, st + vec2(-1.0/512.0, -1.0/512.0)).r != 1.0);
+ part += float(texture2D(u_ShadowMap, st + vec2( 1.0/512.0, -1.0/512.0)).r != 1.0);
+ part += float(texture2D(u_ShadowMap, st + vec2(-1.0/512.0, 1.0/512.0)).r != 1.0);
+ part += float(texture2D(u_ShadowMap, st + vec2( 1.0/512.0, 1.0/512.0)).r != 1.0);
+#else
+ part = float(texture2D(u_ShadowMap, st).r != 1.0);
+#endif
+
+ if (part <= 0.0)
+ {
+ discard;
+ }
+
+#if defined(USE_PCF)
+ intensity *= part * 0.25;
+#else
+ intensity *= part;
+#endif
+
+ gl_FragColor.rgb = vec3(0);
+ gl_FragColor.a = clamp(intensity, 0.0, 0.75);
+}
diff --git a/src/renderergl2/glsl/pshadow_vp.glsl b/src/renderergl2/glsl/pshadow_vp.glsl
new file mode 100644
index 0000000..07a4985
--- /dev/null
+++ b/src/renderergl2/glsl/pshadow_vp.glsl
@@ -0,0 +1,15 @@
+attribute vec3 attr_Position;
+attribute vec3 attr_Normal;
+
+uniform mat4 u_ModelViewProjectionMatrix;
+varying vec3 var_Position;
+varying vec3 var_Normal;
+
+
+void main()
+{
+ gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0);
+
+ var_Position = attr_Position;
+ var_Normal = attr_Normal;
+}
diff --git a/src/renderergl2/glsl/shadowfill_fp.glsl b/src/renderergl2/glsl/shadowfill_fp.glsl
new file mode 100644
index 0000000..150f3d1
--- /dev/null
+++ b/src/renderergl2/glsl/shadowfill_fp.glsl
@@ -0,0 +1,41 @@
+uniform vec4 u_LightOrigin;
+uniform float u_LightRadius;
+
+varying vec3 var_Position;
+
+void main()
+{
+#if defined(USE_DEPTH)
+ float depth = length(u_LightOrigin.xyz - var_Position) / u_LightRadius;
+ #if 0
+ // 32 bit precision
+ const vec4 bitSh = vec4( 256 * 256 * 256, 256 * 256, 256, 1);
+ const vec4 bitMsk = vec4( 0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
+
+ vec4 comp;
+ comp = depth * bitSh;
+ comp.xyz = fract(comp.xyz);
+ comp -= comp.xxyz * bitMsk;
+ gl_FragColor = comp;
+ #endif
+
+ #if 1
+ // 24 bit precision
+ const vec3 bitSh = vec3( 256 * 256, 256, 1);
+ const vec3 bitMsk = vec3( 0, 1.0 / 256.0, 1.0 / 256.0);
+
+ vec3 comp;
+ comp = depth * bitSh;
+ comp.xy = fract(comp.xy);
+ comp -= comp.xxy * bitMsk;
+ gl_FragColor = vec4(comp, 1.0);
+ #endif
+
+ #if 0
+ // 8 bit precision
+ gl_FragColor = vec4(depth, depth, depth, 1);
+ #endif
+#else
+ gl_FragColor = vec4(0, 0, 0, 1);
+#endif
+}
diff --git a/src/renderergl2/glsl/shadowfill_vp.glsl b/src/renderergl2/glsl/shadowfill_vp.glsl
new file mode 100644
index 0000000..7de901b
--- /dev/null
+++ b/src/renderergl2/glsl/shadowfill_vp.glsl
@@ -0,0 +1,89 @@
+attribute vec3 attr_Position;
+attribute vec3 attr_Normal;
+attribute vec4 attr_TexCoord0;
+
+//#if defined(USE_VERTEX_ANIMATION)
+attribute vec3 attr_Position2;
+attribute vec3 attr_Normal2;
+//#endif
+
+//#if defined(USE_DEFORM_VERTEXES)
+uniform int u_DeformGen;
+uniform float u_DeformParams[5];
+//#endif
+
+uniform float u_Time;
+uniform mat4 u_ModelViewProjectionMatrix;
+
+uniform mat4 u_ModelMatrix;
+
+//#if defined(USE_VERTEX_ANIMATION)
+uniform float u_VertexLerp;
+//#endif
+
+varying vec3 var_Position;
+
+vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st)
+{
+ if (u_DeformGen == 0)
+ {
+ return pos;
+ }
+
+ float base = u_DeformParams[0];
+ float amplitude = u_DeformParams[1];
+ float phase = u_DeformParams[2];
+ float frequency = u_DeformParams[3];
+ float spread = u_DeformParams[4];
+
+ if (u_DeformGen == DGEN_BULGE)
+ {
+ phase *= st.x;
+ }
+ else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH)
+ {
+ phase += dot(pos.xyz, vec3(spread));
+ }
+
+ float value = phase + (u_Time * frequency);
+ float func;
+
+ if (u_DeformGen == DGEN_WAVE_SIN)
+ {
+ func = sin(value * 2.0 * M_PI);
+ }
+ else if (u_DeformGen == DGEN_WAVE_SQUARE)
+ {
+ func = sign(0.5 - fract(value));
+ }
+ else if (u_DeformGen == DGEN_WAVE_TRIANGLE)
+ {
+ func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0;
+ }
+ else if (u_DeformGen == DGEN_WAVE_SAWTOOTH)
+ {
+ func = fract(value);
+ }
+ else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)
+ {
+ func = (1.0 - fract(value));
+ }
+ else // if (u_DeformGen == DGEN_BULGE)
+ {
+ func = sin(value);
+ }
+
+ return pos + normal * (base + func * amplitude);
+}
+
+void main()
+{
+ vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
+ vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
+
+ position = DeformPosition(position, normal, attr_TexCoord0.st);
+
+ gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0);
+
+ var_Position = (u_ModelMatrix * vec4(position, 1.0)).xyz;
+}
diff --git a/src/renderergl2/glsl/shadowmask_fp.glsl b/src/renderergl2/glsl/shadowmask_fp.glsl
new file mode 100644
index 0000000..2b57e3b
--- /dev/null
+++ b/src/renderergl2/glsl/shadowmask_fp.glsl
@@ -0,0 +1,143 @@
+uniform sampler2D u_ScreenDepthMap;
+
+uniform sampler2DShadow u_ShadowMap;
+#if defined(USE_SHADOW_CASCADE)
+uniform sampler2DShadow u_ShadowMap2;
+uniform sampler2DShadow u_ShadowMap3;
+uniform sampler2DShadow u_ShadowMap4;
+#endif
+
+uniform mat4 u_ShadowMvp;
+#if defined(USE_SHADOW_CASCADE)
+uniform mat4 u_ShadowMvp2;
+uniform mat4 u_ShadowMvp3;
+uniform mat4 u_ShadowMvp4;
+#endif
+
+uniform vec3 u_ViewOrigin;
+uniform vec4 u_ViewInfo; // zfar / znear, zfar
+
+varying vec2 var_DepthTex;
+varying vec3 var_ViewDir;
+
+// depth is GL_DEPTH_COMPONENT24
+// so the maximum error is 1.0 / 2^24
+#define DEPTH_MAX_ERROR 0.000000059604644775390625
+
+// Input: It uses texture coords as the random number seed.
+// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive.
+// Author: Michael Pohoreski
+// Copyright: Copyleft 2012 :-)
+// Source: http://stackoverflow.com/questions/5149544/can-i-generate-a-random-number-inside-a-pixel-shader
+
+float random( const vec2 p )
+{
+ // We need irrationals for pseudo randomness.
+ // Most (all?) known transcendental numbers will (generally) work.
+ const vec2 r = vec2(
+ 23.1406926327792690, // e^pi (Gelfond's constant)
+ 2.6651441426902251); // 2^sqrt(2) (Gelfond-Schneider constant)
+ //return fract( cos( mod( 123456789., 1e-7 + 256. * dot(p,r) ) ) );
+ return mod( 123456789., 1e-7 + 256. * dot(p,r) );
+}
+
+float PCF(const sampler2DShadow shadowmap, const vec2 st, const float dist)
+{
+ float mult;
+ float scale = 2.0 / r_shadowMapSize;
+
+#if 0
+ // from http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html
+ vec2 offset = vec2(greaterThan(fract(var_DepthTex.xy * r_FBufScale * 0.5), vec2(0.25)));
+ offset.y += offset.x;
+ if (offset.y > 1.1) offset.y = 0.0;
+
+ mult = shadow2D(shadowmap, vec3(st + (offset + vec2(-1.5, 0.5)) * scale, dist))
+ + shadow2D(shadowmap, vec3(st + (offset + vec2( 0.5, 0.5)) * scale, dist))
+ + shadow2D(shadowmap, vec3(st + (offset + vec2(-1.5, -1.5)) * scale, dist))
+ + shadow2D(shadowmap, vec3(st + (offset + vec2( 0.5, -1.5)) * scale, dist));
+
+ mult *= 0.25;
+#endif
+
+#if defined(USE_SHADOW_FILTER)
+ float r = random(var_DepthTex.xy);
+ float sinr = sin(r) * scale;
+ float cosr = cos(r) * scale;
+ mat2 rmat = mat2(cosr, sinr, -sinr, cosr);
+
+ mult = shadow2D(shadowmap, vec3(st + rmat * vec2(-0.7055767, 0.196515), dist));
+ mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.3524343, -0.7791386), dist));
+ mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.2391056, 0.9189604), dist));
+ #if defined(USE_SHADOW_FILTER2)
+ mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.07580382, -0.09224417), dist));
+ mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.5784913, -0.002528916), dist));
+ mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.192888, 0.4064181), dist));
+ mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.6335801, -0.5247476), dist));
+ mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.5579782, 0.7491854), dist));
+ mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.7320465, 0.6317794), dist));
+
+ mult *= 0.11111;
+ #else
+ mult *= 0.33333;
+ #endif
+#else
+ mult = shadow2D(shadowmap, vec3(st, dist));
+#endif
+
+ return mult;
+}
+
+float getLinearDepth(sampler2D depthMap, vec2 tex, float zFarDivZNear)
+{
+ float sampleZDivW = texture2D(depthMap, tex).r - DEPTH_MAX_ERROR;
+ return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
+}
+
+void main()
+{
+ float result;
+
+ float depth = getLinearDepth(u_ScreenDepthMap, var_DepthTex, u_ViewInfo.x);
+ vec4 biasPos = vec4(u_ViewOrigin + var_ViewDir * (depth - 0.5 / u_ViewInfo.x), 1.0);
+
+ vec4 shadowpos = u_ShadowMvp * biasPos;
+
+#if defined(USE_SHADOW_CASCADE)
+ if (all(lessThan(abs(shadowpos.xyz), vec3(abs(shadowpos.w)))))
+ {
+#endif
+ shadowpos.xyz = shadowpos.xyz * (0.5 / shadowpos.w) + vec3(0.5);
+ result = PCF(u_ShadowMap, shadowpos.xy, shadowpos.z);
+#if defined(USE_SHADOW_CASCADE)
+ }
+ else
+ {
+ shadowpos = u_ShadowMvp2 * biasPos;
+
+ if (all(lessThan(abs(shadowpos.xyz), vec3(abs(shadowpos.w)))))
+ {
+ shadowpos.xyz = shadowpos.xyz * (0.5 / shadowpos.w) + vec3(0.5);
+ result = PCF(u_ShadowMap2, shadowpos.xy, shadowpos.z);
+ }
+ else
+ {
+ shadowpos = u_ShadowMvp3 * biasPos;
+
+ if (all(lessThan(abs(shadowpos.xyz), vec3(abs(shadowpos.w)))))
+ {
+ shadowpos.xyz = shadowpos.xyz * (0.5 / shadowpos.w) + vec3(0.5);
+ result = PCF(u_ShadowMap3, shadowpos.xy, shadowpos.z);
+ }
+ else
+ {
+ shadowpos = u_ShadowMvp4 * biasPos;
+ shadowpos.xyz = shadowpos.xyz * (0.5 / shadowpos.w) + vec3(0.5);
+ result = PCF(u_ShadowMap4, shadowpos.xy, shadowpos.z);
+ }
+ }
+ }
+#endif
+
+ gl_FragColor = vec4(vec3(result), 1.0);
+}
diff --git a/src/renderergl2/glsl/shadowmask_vp.glsl b/src/renderergl2/glsl/shadowmask_vp.glsl
new file mode 100644
index 0000000..13166a2
--- /dev/null
+++ b/src/renderergl2/glsl/shadowmask_vp.glsl
@@ -0,0 +1,18 @@
+attribute vec4 attr_Position;
+attribute vec4 attr_TexCoord0;
+
+uniform vec3 u_ViewForward;
+uniform vec3 u_ViewLeft;
+uniform vec3 u_ViewUp;
+uniform vec4 u_ViewInfo; // zfar / znear
+
+varying vec2 var_DepthTex;
+varying vec3 var_ViewDir;
+
+void main()
+{
+ gl_Position = attr_Position;
+ vec2 screenCoords = gl_Position.xy / gl_Position.w;
+ var_DepthTex = attr_TexCoord0.xy;
+ var_ViewDir = u_ViewForward + u_ViewLeft * -screenCoords.x + u_ViewUp * screenCoords.y;
+}
diff --git a/src/renderergl2/glsl/ssao_fp.glsl b/src/renderergl2/glsl/ssao_fp.glsl
new file mode 100644
index 0000000..93f6185
--- /dev/null
+++ b/src/renderergl2/glsl/ssao_fp.glsl
@@ -0,0 +1,86 @@
+uniform sampler2D u_ScreenDepthMap;
+
+uniform vec4 u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
+
+varying vec2 var_ScreenTex;
+
+vec2 poissonDisc[9] = vec2[9](
+vec2(-0.7055767, 0.196515), vec2(0.3524343, -0.7791386),
+vec2(0.2391056, 0.9189604), vec2(-0.07580382, -0.09224417),
+vec2(0.5784913, -0.002528916), vec2(0.192888, 0.4064181),
+vec2(-0.6335801, -0.5247476), vec2(-0.5579782, 0.7491854),
+vec2(0.7320465, 0.6317794)
+);
+#define NUM_SAMPLES 3
+
+// Input: It uses texture coords as the random number seed.
+// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive.
+// Author: Michael Pohoreski
+// Copyright: Copyleft 2012 :-)
+// Source: http://stackoverflow.com/questions/5149544/can-i-generate-a-random-number-inside-a-pixel-shader
+
+float random( const vec2 p )
+{
+ // We need irrationals for pseudo randomness.
+ // Most (all?) known transcendental numbers will (generally) work.
+ const vec2 r = vec2(
+ 23.1406926327792690, // e^pi (Gelfond's constant)
+ 2.6651441426902251); // 2^sqrt(2) (Gelfond-Schneider constant)
+ //return fract( cos( mod( 123456789., 1e-7 + 256. * dot(p,r) ) ) );
+ return mod( 123456789., 1e-7 + 256. * dot(p,r) );
+}
+
+mat2 randomRotation( const vec2 p )
+{
+ float r = random(p);
+ float sinr = sin(r);
+ float cosr = cos(r);
+ return mat2(cosr, sinr, -sinr, cosr);
+}
+
+float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear)
+{
+ float sampleZDivW = texture2D(depthMap, tex).r;
+ return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
+}
+
+float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar, const vec2 scale)
+{
+ float result = 0;
+
+ float sampleZ = getLinearDepth(depthMap, tex, zFarDivZNear);
+ float scaleZ = zFarDivZNear * sampleZ;
+
+ vec2 slope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y));
+
+ if (length(slope) * zFar > 5000.0)
+ return 1.0;
+
+ vec2 offsetScale = vec2(scale * 1024.0 / scaleZ);
+
+ mat2 rmat = randomRotation(tex);
+
+ float invZFar = 1.0 / zFar;
+ float zLimit = 20.0 * invZFar;
+ int i;
+ for (i = 0; i < NUM_SAMPLES; i++)
+ {
+ vec2 offset = rmat * poissonDisc[i] * offsetScale;
+ float sampleDiff = getLinearDepth(depthMap, tex + offset, zFarDivZNear) - sampleZ;
+
+ bool s1 = abs(sampleDiff) > zLimit;
+ bool s2 = sampleDiff + invZFar > dot(slope, offset);
+ result += float(s1 || s2);
+ }
+
+ result *= 1.0 / float(NUM_SAMPLES);
+
+ return result;
+}
+
+void main()
+{
+ float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y, u_ViewInfo.wz);
+
+ gl_FragColor = vec4(vec3(result), 1.0);
+}
diff --git a/src/renderergl2/glsl/ssao_vp.glsl b/src/renderergl2/glsl/ssao_vp.glsl
new file mode 100644
index 0000000..9c46a79
--- /dev/null
+++ b/src/renderergl2/glsl/ssao_vp.glsl
@@ -0,0 +1,12 @@
+attribute vec4 attr_Position;
+attribute vec4 attr_TexCoord0;
+
+varying vec2 var_ScreenTex;
+
+void main()
+{
+ gl_Position = attr_Position;
+ var_ScreenTex = attr_TexCoord0.xy;
+ //vec2 screenCoords = gl_Position.xy / gl_Position.w;
+ //var_ScreenTex = screenCoords * 0.5 + 0.5;
+}
diff --git a/src/renderergl2/glsl/texturecolor_fp.glsl b/src/renderergl2/glsl/texturecolor_fp.glsl
new file mode 100644
index 0000000..7c9046e
--- /dev/null
+++ b/src/renderergl2/glsl/texturecolor_fp.glsl
@@ -0,0 +1,10 @@
+uniform sampler2D u_DiffuseMap;
+uniform vec4 u_Color;
+
+varying vec2 var_Tex1;
+
+
+void main()
+{
+ gl_FragColor = texture2D(u_DiffuseMap, var_Tex1) * u_Color;
+}
diff --git a/src/renderergl2/glsl/texturecolor_vp.glsl b/src/renderergl2/glsl/texturecolor_vp.glsl
new file mode 100644
index 0000000..552cd93
--- /dev/null
+++ b/src/renderergl2/glsl/texturecolor_vp.glsl
@@ -0,0 +1,13 @@
+attribute vec3 attr_Position;
+attribute vec4 attr_TexCoord0;
+
+uniform mat4 u_ModelViewProjectionMatrix;
+
+varying vec2 var_Tex1;
+
+
+void main()
+{
+ gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0);
+ var_Tex1 = attr_TexCoord0.st;
+}
diff --git a/src/renderergl2/glsl/tonemap_fp.glsl b/src/renderergl2/glsl/tonemap_fp.glsl
new file mode 100644
index 0000000..9e24e24
--- /dev/null
+++ b/src/renderergl2/glsl/tonemap_fp.glsl
@@ -0,0 +1,57 @@
+uniform sampler2D u_TextureMap;
+uniform sampler2D u_LevelsMap;
+
+uniform vec4 u_Color;
+
+
+uniform vec2 u_AutoExposureMinMax;
+uniform vec3 u_ToneMinAvgMaxLinear;
+
+varying vec2 var_TexCoords;
+varying float var_InvWhite;
+
+const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721); //vec3(0.299, 0.587, 0.114);
+
+float FilmicTonemap(float x)
+{
+ const float SS = 0.22; // Shoulder Strength
+ const float LS = 0.30; // Linear Strength
+ const float LA = 0.10; // Linear Angle
+ const float TS = 0.20; // Toe Strength
+ const float TAN = 0.01; // Toe Angle Numerator
+ const float TAD = 0.30; // Toe Angle Denominator
+
+ return ((x*(SS*x+LA*LS)+TS*TAN)/(x*(SS*x+LS)+TS*TAD)) - TAN/TAD;
+}
+
+void main()
+{
+ vec4 color = texture2D(u_TextureMap, var_TexCoords) * u_Color;
+
+#if defined(USE_PBR)
+ color.rgb *= color.rgb;
+#endif
+
+ vec3 minAvgMax = texture2D(u_LevelsMap, var_TexCoords).rgb;
+ vec3 logMinAvgMaxLum = clamp(minAvgMax * 20.0 - 10.0, -u_AutoExposureMinMax.y, -u_AutoExposureMinMax.x);
+
+ float invAvgLum = u_ToneMinAvgMaxLinear.y * exp2(-logMinAvgMaxLum.y);
+
+ color.rgb = color.rgb * invAvgLum - u_ToneMinAvgMaxLinear.xxx;
+ color.rgb = max(vec3(0.0), color.rgb);
+
+ color.r = FilmicTonemap(color.r);
+ color.g = FilmicTonemap(color.g);
+ color.b = FilmicTonemap(color.b);
+
+ color.rgb = clamp(color.rgb * var_InvWhite, 0.0, 1.0);
+
+#if defined(USE_PBR)
+ color.rgb = sqrt(color.rgb);
+#endif
+
+ // add a bit of dither to reduce banding
+ color.rgb += vec3(1.0/510.0 * mod(gl_FragCoord.x + gl_FragCoord.y, 2.0) - 1.0/1020.0);
+
+ gl_FragColor = color;
+}
diff --git a/src/renderergl2/glsl/tonemap_vp.glsl b/src/renderergl2/glsl/tonemap_vp.glsl
new file mode 100644
index 0000000..577c0a1
--- /dev/null
+++ b/src/renderergl2/glsl/tonemap_vp.glsl
@@ -0,0 +1,27 @@
+attribute vec3 attr_Position;
+attribute vec4 attr_TexCoord0;
+
+uniform mat4 u_ModelViewProjectionMatrix;
+uniform vec3 u_ToneMinAvgMaxLinear;
+
+varying vec2 var_TexCoords;
+varying float var_InvWhite;
+
+float FilmicTonemap(float x)
+{
+ const float SS = 0.22; // Shoulder Strength
+ const float LS = 0.30; // Linear Strength
+ const float LA = 0.10; // Linear Angle
+ const float TS = 0.20; // Toe Strength
+ const float TAN = 0.01; // Toe Angle Numerator
+ const float TAD = 0.30; // Toe Angle Denominator
+
+ return ((x*(SS*x+LA*LS)+TS*TAN)/(x*(SS*x+LS)+TS*TAD)) - TAN/TAD;
+}
+
+void main()
+{
+ gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0);
+ var_TexCoords = attr_TexCoord0.st;
+ var_InvWhite = 1.0 / FilmicTonemap(u_ToneMinAvgMaxLinear.z - u_ToneMinAvgMaxLinear.x);
+}
diff --git a/src/renderergl2/tr_animation.cpp b/src/renderergl2/tr_animation.cpp
new file mode 100644
index 0000000..55dddd7
--- /dev/null
+++ b/src/renderergl2/tr_animation.cpp
@@ -0,0 +1,525 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+/*
+
+All bones should be an identity orientation to display the mesh exactly
+as it is specified.
+
+For all other frames, the bones represent the transformation from the
+orientation of the bone in the base frame to the orientation in this
+frame.
+
+*/
+
+
+// copied and adapted from tr_mesh.c
+
+/*
+=============
+R_MDRCullModel
+=============
+*/
+
+static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) {
+ vec3_t bounds[2];
+ mdrFrame_t *oldFrame, *newFrame;
+ int i, frameSize;
+
+ frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
+
+ // compute frame pointers
+ newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
+ oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe);
+
+ // cull bounding sphere ONLY if this is not an upscaled entity
+ if ( !ent->e.nonNormalizedAxes )
+ {
+ if ( ent->e.frame == ent->e.oldframe )
+ {
+ switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
+ {
+ // Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend
+ // we do. After all, the purpose of mdrs are not that different, are they?
+
+ case CULL_OUT:
+ tr.pc.c_sphere_cull_md3_out++;
+ return CULL_OUT;
+
+ case CULL_IN:
+ tr.pc.c_sphere_cull_md3_in++;
+ return CULL_IN;
+
+ case CULL_CLIP:
+ tr.pc.c_sphere_cull_md3_clip++;
+ break;
+ }
+ }
+ else
+ {
+ int sphereCull, sphereCullB;
+
+ sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
+ if ( newFrame == oldFrame ) {
+ sphereCullB = sphereCull;
+ } else {
+ sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
+ }
+
+ if ( sphereCull == sphereCullB )
+ {
+ if ( sphereCull == CULL_OUT )
+ {
+ tr.pc.c_sphere_cull_md3_out++;
+ return CULL_OUT;
+ }
+ else if ( sphereCull == CULL_IN )
+ {
+ tr.pc.c_sphere_cull_md3_in++;
+ return CULL_IN;
+ }
+ else
+ {
+ tr.pc.c_sphere_cull_md3_clip++;
+ }
+ }
+ }
+ }
+
+ // calculate a bounding box in the current coordinate system
+ for (i = 0 ; i < 3 ; i++) {
+ bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
+ bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
+ }
+
+ switch ( R_CullLocalBox( bounds ) )
+ {
+ case CULL_IN:
+ tr.pc.c_box_cull_md3_in++;
+ return CULL_IN;
+ case CULL_CLIP:
+ tr.pc.c_box_cull_md3_clip++;
+ return CULL_CLIP;
+ case CULL_OUT:
+ default:
+ tr.pc.c_box_cull_md3_out++;
+ return CULL_OUT;
+ }
+}
+
+/*
+=================
+R_MDRComputeFogNum
+
+=================
+*/
+
+int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent ) {
+ int i, j;
+ fog_t *fog;
+ mdrFrame_t *mdrFrame;
+ vec3_t localOrigin;
+ int frameSize;
+
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ return 0;
+ }
+
+ frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
+
+ // FIXME: non-normalized axis issues
+ mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
+ VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin );
+ for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
+ fog = &tr.world->fogs[i];
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] ) {
+ break;
+ }
+ if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] ) {
+ break;
+ }
+ }
+ if ( j == 3 ) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+==============
+R_MDRAddAnimSurfaces
+==============
+*/
+
+// much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c
+
+void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
+ mdrHeader_t *header;
+ mdrSurface_t *surface;
+ mdrLOD_t *lod;
+ shader_t *shader;
+ skin_t *skin;
+ int i, j;
+ int lodnum = 0;
+ int fogNum = 0;
+ int cull;
+ int cubemapIndex;
+ bool personalModel;
+
+ header = (mdrHeader_t *) tr.currentModel->modelData;
+
+ personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal
+ || (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)));
+
+ if ( ent->e.renderfx & RF_WRAP_FRAMES )
+ {
+ ent->e.frame %= header->numFrames;
+ ent->e.oldframe %= header->numFrames;
+ }
+
+ //
+ // Validate the frames so there is no chance of a crash.
+ // This will write directly into the entity structure, so
+ // when the surfaces are rendered, they don't need to be
+ // range checked again.
+ //
+ if ((ent->e.frame >= header->numFrames)
+ || (ent->e.frame < 0)
+ || (ent->e.oldframe >= header->numFrames)
+ || (ent->e.oldframe < 0) )
+ {
+ ri.Printf( PRINT_DEVELOPER, "R_MDRAddAnimSurfaces: no such frame %d to %d for '%s'\n",
+ ent->e.oldframe, ent->e.frame, tr.currentModel->name );
+ ent->e.frame = 0;
+ ent->e.oldframe = 0;
+ }
+
+ //
+ // cull the entire model if merged bounding box of both frames
+ // is outside the view frustum.
+ //
+ cull = R_MDRCullModel (header, ent);
+ if ( cull == CULL_OUT ) {
+ return;
+ }
+
+ // figure out the current LOD of the model we're rendering, and set the lod pointer respectively.
+ lodnum = R_ComputeLOD(ent);
+ // check whether this model has as that many LODs at all. If not, try the closest thing we got.
+ if(header->numLODs <= 0)
+ return;
+ if(header->numLODs <= lodnum)
+ lodnum = header->numLODs - 1;
+
+ lod = (mdrLOD_t *)( (byte *)header + header->ofsLODs);
+ for(i = 0; i < lodnum; i++)
+ {
+ lod = (mdrLOD_t *) ((byte *) lod + lod->ofsEnd);
+ }
+
+ // set up lighting
+ if ( !personalModel || r_shadows->integer > 1 )
+ {
+ R_SetupEntityLighting( &tr.refdef, ent );
+ }
+
+ // fogNum?
+ fogNum = R_MDRComputeFogNum( header, ent );
+
+ cubemapIndex = R_CubemapForPoint(ent->e.origin);
+
+ surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces );
+
+ for ( i = 0 ; i < lod->numSurfaces ; i++ )
+ {
+
+ if(ent->e.customShader)
+ shader = R_GetShaderByHandle(ent->e.customShader);
+ else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins)
+ {
+ skin = R_GetSkinByHandle(ent->e.customSkin);
+ shader = tr.defaultShader;
+
+ for(j = 0; j < skin->numSurfaces; j++)
+ {
+ if (!strcmp(skin->surfaces[j].name, surface->name))
+ {
+ shader = skin->surfaces[j].shader;
+ break;
+ }
+ }
+ }
+ else if(surface->shaderIndex > 0)
+ shader = R_GetShaderByHandle( surface->shaderIndex );
+ else
+ shader = tr.defaultShader;
+
+ // we will add shadows even if the main object isn't visible in the view
+
+ // stencil shadows can't do personal models unless I polyhedron clip
+ if ( !personalModel
+ && r_shadows->integer == 2
+ && fogNum == 0
+ && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
+ && shader->sort == SS_OPAQUE )
+ {
+ R_AddDrawSurf( (surfaceType_t*)surface, tr.shadowShader, 0, false, false, 0 );
+ }
+
+ // projection shadows work fine with personal models
+ if ( r_shadows->integer == 3
+ && fogNum == 0
+ && (ent->e.renderfx & RF_SHADOW_PLANE )
+ && shader->sort == SS_OPAQUE )
+ {
+ R_AddDrawSurf( (surfaceType_t*)surface, tr.projectionShadowShader, 0, false, false, 0 );
+ }
+
+ if (!personalModel)
+ R_AddDrawSurf( (surfaceType_t*)surface, shader, fogNum, false, false, cubemapIndex );
+
+ surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
+ }
+}
+
+/*
+==============
+RB_MDRSurfaceAnim
+==============
+*/
+void RB_MDRSurfaceAnim( mdrSurface_t *surface )
+{
+ int i, j, k;
+ float frontlerp, backlerp;
+ int *triangles;
+ int indexes;
+ int baseIndex, baseVertex;
+ int numVerts;
+ mdrVertex_t *v;
+ mdrHeader_t *header;
+ mdrFrame_t *frame;
+ mdrFrame_t *oldFrame;
+ mdrBone_t bones[MDR_MAX_BONES], *bonePtr, *bone;
+
+ int frameSize;
+
+ // don't lerp if lerping off, or this is the only frame, or the last frame...
+ //
+ if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame)
+ {
+ backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used
+ frontlerp = 1;
+ }
+ else
+ {
+ backlerp = backEnd.currentEntity->e.backlerp;
+ frontlerp = 1.0f - backlerp;
+ }
+
+ header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader);
+
+ frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
+
+ frame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
+ backEnd.currentEntity->e.frame * frameSize );
+ oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
+ backEnd.currentEntity->e.oldframe * frameSize );
+
+ RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles * 3 );
+
+ triangles = (int *) ((byte *)surface + surface->ofsTriangles);
+ indexes = surface->numTriangles * 3;
+ baseIndex = tess.numIndexes;
+ baseVertex = tess.numVertexes;
+
+ // Set up all triangles.
+ for (j = 0 ; j < indexes ; j++)
+ {
+ tess.indexes[baseIndex + j] = baseVertex + triangles[j];
+ }
+ tess.numIndexes += indexes;
+
+ //
+ // lerp all the needed bones
+ //
+ if ( !backlerp )
+ {
+ // no lerping needed
+ bonePtr = frame->bones;
+ }
+ else
+ {
+ bonePtr = bones;
+
+ for ( i = 0 ; i < header->numBones*12 ; i++ )
+ {
+ ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i];
+ }
+ }
+
+ //
+ // deform the vertexes by the lerped bones
+ //
+ numVerts = surface->numVerts;
+ v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts);
+ for ( j = 0; j < numVerts; j++ )
+ {
+ vec3_t tempVert, tempNormal;
+ mdrWeight_t *w;
+
+ VectorClear( tempVert );
+ VectorClear( tempNormal );
+ w = v->weights;
+ for ( k = 0 ; k < v->numWeights ; k++, w++ )
+ {
+ bone = bonePtr + w->boneIndex;
+
+ tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] );
+ tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] );
+ tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] );
+
+ tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal );
+ tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal );
+ tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal );
+ }
+
+ tess.xyz[baseVertex + j][0] = tempVert[0];
+ tess.xyz[baseVertex + j][1] = tempVert[1];
+ tess.xyz[baseVertex + j][2] = tempVert[2];
+
+ R_VaoPackNormal(tess.normal[baseVertex + j], tempNormal);
+
+ tess.texCoords[baseVertex + j][0] = v->texCoords[0];
+ tess.texCoords[baseVertex + j][1] = v->texCoords[1];
+
+ v = (mdrVertex_t *)&v->weights[v->numWeights];
+ }
+
+ tess.numVertexes += surface->numVerts;
+}
+
+
+#define MC_MASK_X ((1<<(MC_BITS_X))-1)
+#define MC_MASK_Y ((1<<(MC_BITS_Y))-1)
+#define MC_MASK_Z ((1<<(MC_BITS_Z))-1)
+#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1)
+
+#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2))
+
+#define MC_POS_X (0)
+#define MC_SHIFT_X (0)
+
+#define MC_POS_Y ((((MC_BITS_X))/8))
+#define MC_SHIFT_Y ((((MC_BITS_X)%8)))
+
+#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8))
+#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8)))
+
+#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8))
+#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8)))
+
+#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8))
+#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8)))
+
+#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8))
+#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8)))
+
+#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8))
+#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8)))
+
+#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8))
+#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8)))
+
+#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8))
+#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8)))
+
+#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8))
+#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8)))
+
+#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8))
+#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8)))
+
+#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8))
+#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8)))
+
+void MC_UnCompress(float mat[3][4],const unsigned char * comp)
+{
+ int val;
+
+ val=(int)((unsigned short *)(comp))[0];
+ val-=1<<(MC_BITS_X-1);
+ mat[0][3]=((float)(val))*MC_SCALE_X;
+
+ val=(int)((unsigned short *)(comp))[1];
+ val-=1<<(MC_BITS_Y-1);
+ mat[1][3]=((float)(val))*MC_SCALE_Y;
+
+ val=(int)((unsigned short *)(comp))[2];
+ val-=1<<(MC_BITS_Z-1);
+ mat[2][3]=((float)(val))*MC_SCALE_Z;
+
+ val=(int)((unsigned short *)(comp))[3];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[0][0]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[4];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[0][1]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[5];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[0][2]=((float)(val))*MC_SCALE_VECT;
+
+
+ val=(int)((unsigned short *)(comp))[6];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[1][0]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[7];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[1][1]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[8];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[1][2]=((float)(val))*MC_SCALE_VECT;
+
+
+ val=(int)((unsigned short *)(comp))[9];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[2][0]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[10];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[2][1]=((float)(val))*MC_SCALE_VECT;
+
+ val=(int)((unsigned short *)(comp))[11];
+ val-=1<<(MC_BITS_VECT-1);
+ mat[2][2]=((float)(val))*MC_SCALE_VECT;
+}
diff --git a/src/renderergl2/tr_backend.cpp b/src/renderergl2/tr_backend.cpp
new file mode 100644
index 0000000..3459f58
--- /dev/null
+++ b/src/renderergl2/tr_backend.cpp
@@ -0,0 +1,1817 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "tr_local.h"
+#include "tr_fbo.h"
+#include "tr_dsa.h"
+
+backEndData_t *backEndData;
+backEndState_t backEnd;
+
+
+static float s_flipMatrix[16] = {
+ // convert from our coordinate system (looking down X)
+ // to OpenGL's coordinate system (looking down -Z)
+ 0, 0, -1, 0,
+ -1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 0, 1
+};
+
+
+/*
+** GL_BindToTMU
+*/
+void GL_BindToTMU( image_t *image, int tmu )
+{
+ GLuint texture = (tmu == TB_COLORMAP) ? tr.defaultImage->texnum : 0;
+ GLenum target = GL_TEXTURE_2D;
+
+ if (image)
+ {
+ if (image->flags & IMGFLAG_CUBEMAP)
+ target = GL_TEXTURE_CUBE_MAP;
+
+ image->frameUsed = tr.frameCount;
+ texture = image->texnum;
+ }
+ else
+ {
+ ri.Printf(PRINT_WARNING, "GL_BindToTMU: NULL image\n");
+ }
+
+ GL_BindMultiTexture(GL_TEXTURE0_ARB + tmu, target, texture);
+}
+
+
+/*
+** GL_Cull
+*/
+void GL_Cull( int cullType ) {
+ if ( glState.faceCulling == cullType ) {
+ return;
+ }
+
+ if ( cullType == CT_TWO_SIDED )
+ {
+ qglDisable( GL_CULL_FACE );
+ }
+ else
+ {
+ bool cullFront = (cullType == CT_FRONT_SIDED);
+
+ if ( glState.faceCulling == CT_TWO_SIDED )
+ qglEnable( GL_CULL_FACE );
+
+ if ( glState.faceCullFront != cullFront )
+ qglCullFace( cullFront ? GL_FRONT : GL_BACK );
+
+ glState.faceCullFront = cullFront;
+ }
+
+ glState.faceCulling = cullType;
+}
+
+/*
+** GL_State
+**
+** This routine is responsible for setting the most commonly changed state
+** in Q3.
+*/
+void GL_State( unsigned long stateBits )
+{
+ unsigned long diff = stateBits ^ glState.glStateBits;
+
+ if ( !diff )
+ {
+ return;
+ }
+
+ //
+ // check depthFunc bits
+ //
+ if ( diff & GLS_DEPTHFUNC_BITS )
+ {
+ if ( stateBits & GLS_DEPTHFUNC_EQUAL )
+ {
+ qglDepthFunc( GL_EQUAL );
+ }
+ else if ( stateBits & GLS_DEPTHFUNC_GREATER)
+ {
+ qglDepthFunc( GL_GREATER );
+ }
+ else
+ {
+ qglDepthFunc( GL_LEQUAL );
+ }
+ }
+
+ //
+ // check blend bits
+ //
+ if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
+ {
+ uint32_t oldState = glState.glStateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS );
+ uint32_t newState = stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS );
+ uint32_t storedState = glState.storedGlState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS );
+
+ if (oldState == 0)
+ {
+ qglEnable( GL_BLEND );
+ }
+ else if (newState == 0)
+ {
+ qglDisable( GL_BLEND );
+ }
+
+ if (newState != 0 && storedState != newState)
+ {
+ GLenum srcFactor = GL_ONE, dstFactor = GL_ONE;
+
+ glState.storedGlState &= ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS );
+ glState.storedGlState |= newState;
+
+ switch ( stateBits & GLS_SRCBLEND_BITS )
+ {
+ case GLS_SRCBLEND_ZERO:
+ srcFactor = GL_ZERO;
+ break;
+ case GLS_SRCBLEND_ONE:
+ srcFactor = GL_ONE;
+ break;
+ case GLS_SRCBLEND_DST_COLOR:
+ srcFactor = GL_DST_COLOR;
+ break;
+ case GLS_SRCBLEND_ONE_MINUS_DST_COLOR:
+ srcFactor = GL_ONE_MINUS_DST_COLOR;
+ break;
+ case GLS_SRCBLEND_SRC_ALPHA:
+ srcFactor = GL_SRC_ALPHA;
+ break;
+ case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:
+ srcFactor = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case GLS_SRCBLEND_DST_ALPHA:
+ srcFactor = GL_DST_ALPHA;
+ break;
+ case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:
+ srcFactor = GL_ONE_MINUS_DST_ALPHA;
+ break;
+ case GLS_SRCBLEND_ALPHA_SATURATE:
+ srcFactor = GL_SRC_ALPHA_SATURATE;
+ break;
+ default:
+ ri.Error( ERR_DROP, "GL_State: invalid src blend state bits" );
+ break;
+ }
+
+ switch ( stateBits & GLS_DSTBLEND_BITS )
+ {
+ case GLS_DSTBLEND_ZERO:
+ dstFactor = GL_ZERO;
+ break;
+ case GLS_DSTBLEND_ONE:
+ dstFactor = GL_ONE;
+ break;
+ case GLS_DSTBLEND_SRC_COLOR:
+ dstFactor = GL_SRC_COLOR;
+ break;
+ case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:
+ dstFactor = GL_ONE_MINUS_SRC_COLOR;
+ break;
+ case GLS_DSTBLEND_SRC_ALPHA:
+ dstFactor = GL_SRC_ALPHA;
+ break;
+ case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:
+ dstFactor = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case GLS_DSTBLEND_DST_ALPHA:
+ dstFactor = GL_DST_ALPHA;
+ break;
+ case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:
+ dstFactor = GL_ONE_MINUS_DST_ALPHA;
+ break;
+ default:
+ ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits" );
+ break;
+ }
+
+ qglBlendFunc( srcFactor, dstFactor );
+ }
+ }
+
+ //
+ // check depthmask
+ //
+ if ( diff & GLS_DEPTHMASK_TRUE )
+ {
+ if ( stateBits & GLS_DEPTHMASK_TRUE )
+ {
+ qglDepthMask( GL_TRUE );
+ }
+ else
+ {
+ qglDepthMask( GL_FALSE );
+ }
+ }
+
+ //
+ // fill/line mode
+ //
+ if ( diff & GLS_POLYMODE_LINE )
+ {
+ if ( stateBits & GLS_POLYMODE_LINE )
+ {
+ qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+ }
+ else
+ {
+ qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+ }
+ }
+
+ //
+ // depthtest
+ //
+ if ( diff & GLS_DEPTHTEST_DISABLE )
+ {
+ if ( stateBits & GLS_DEPTHTEST_DISABLE )
+ {
+ qglDisable( GL_DEPTH_TEST );
+ }
+ else
+ {
+ qglEnable( GL_DEPTH_TEST );
+ }
+ }
+
+ glState.glStateBits = stateBits;
+}
+
+
+void GL_SetProjectionMatrix(mat4_t matrix)
+{
+ Mat4Copy(matrix, glState.projection);
+ Mat4Multiply(glState.projection, glState.modelview, glState.modelviewProjection);
+}
+
+
+void GL_SetModelviewMatrix(mat4_t matrix)
+{
+ Mat4Copy(matrix, glState.modelview);
+ Mat4Multiply(glState.projection, glState.modelview, glState.modelviewProjection);
+}
+
+
+/*
+================
+RB_Hyperspace
+
+A player has predicted a teleport, but hasn't arrived yet
+================
+*/
+static void RB_Hyperspace( void ) {
+ float c;
+
+ if ( !backEnd.isHyperspace ) {
+ // do initialization shit
+ }
+
+ c = ( backEnd.refdef.time & 255 ) / 255.0f;
+ qglClearColor( c, c, c, 1 );
+ qglClear( GL_COLOR_BUFFER_BIT );
+ qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+ backEnd.isHyperspace = true;
+}
+
+
+static void SetViewportAndScissor( void ) {
+ GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix );
+
+ // set the window clipping
+ qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
+ backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );
+ qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
+ backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );
+}
+
+/*
+=================
+RB_BeginDrawingView
+
+
+to actually render the visible surfaces for this view
+=================
+*/
+void RB_BeginDrawingView (void) {
+ int clearBits = 0;
+
+ // sync with gl if needed
+ if ( r_finish->integer == 1 && !glState.finishCalled ) {
+ qglFinish ();
+ glState.finishCalled = true;
+ }
+ if ( r_finish->integer == 0 ) {
+ glState.finishCalled = true;
+ }
+
+ // we will need to change the projection matrix before drawing
+ // 2D images again
+ backEnd.projection2D = false;
+
+ if (glRefConfig.framebufferObject)
+ {
+ FBO_t *fbo = backEnd.viewParms.targetFbo;
+
+ // FIXME: HUGE HACK: render to the screen fbo if we've already postprocessed the frame and aren't drawing more world
+ // drawing more world check is in case of double renders, such as skyportals
+ if (fbo == NULL && !(backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)))
+ fbo = tr.renderFbo;
+
+ if (tr.renderCubeFbo && fbo == tr.renderCubeFbo)
+ {
+ cubemap_t *cubemap = &tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex];
+ FBO_AttachImage(fbo, cubemap->image, GL_COLOR_ATTACHMENT0_EXT, backEnd.viewParms.targetFboLayer);
+ }
+
+ FBO_Bind(fbo);
+ }
+
+ //
+ // set the modelview matrix for the viewer
+ //
+ SetViewportAndScissor();
+
+ // ensures that depth writes are enabled for the depth clear
+ GL_State( GLS_DEFAULT );
+ // clear relevant buffers
+ clearBits = GL_DEPTH_BUFFER_BIT;
+
+ if ( r_measureOverdraw->integer || r_shadows->integer == 2 )
+ {
+ clearBits |= GL_STENCIL_BUFFER_BIT;
+ }
+ if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) )
+ {
+ clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used
+ }
+
+ // clear to black for cube maps
+ if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo)
+ {
+ clearBits |= GL_COLOR_BUFFER_BIT;
+ }
+
+ qglClear( clearBits );
+
+ if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )
+ {
+ RB_Hyperspace();
+ return;
+ }
+ else
+ {
+ backEnd.isHyperspace = false;
+ }
+
+ // we will only draw a sun if there was sky rendered in this view
+ backEnd.skyRenderedThisView = false;
+
+ // clip to the plane of the portal
+ if ( backEnd.viewParms.isPortal ) {
+#if 0
+ float plane[4];
+ GLdouble plane2[4];
+
+ plane[0] = backEnd.viewParms.portalPlane.normal[0];
+ plane[1] = backEnd.viewParms.portalPlane.normal[1];
+ plane[2] = backEnd.viewParms.portalPlane.normal[2];
+ plane[3] = backEnd.viewParms.portalPlane.dist;
+
+ plane2[0] = DotProduct (backEnd.viewParms.orientation.axis[0], plane);
+ plane2[1] = DotProduct (backEnd.viewParms.orientation.axis[1], plane);
+ plane2[2] = DotProduct (backEnd.viewParms.orientation.axis[2], plane);
+ plane2[3] = DotProduct (plane, backEnd.viewParms.orientation.origin) - plane[3];
+#endif
+ GL_SetModelviewMatrix( s_flipMatrix );
+ }
+}
+
+
+/*
+==================
+RB_RenderDrawSurfList
+==================
+*/
+void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
+ shader_t *shader, *oldShader;
+ int fogNum, oldFogNum;
+ int entityNum, oldEntityNum;
+ int dlighted, oldDlighted;
+ int pshadowed, oldPshadowed;
+ int cubemapIndex, oldCubemapIndex;
+ bool depthRange, oldDepthRange, isCrosshair, wasCrosshair;
+ int i;
+ drawSurf_t *drawSurf;
+ int oldSort;
+ FBO_t* fbo = NULL;
+ bool inQuery = false;
+
+ float depth[2];
+
+
+ // save original time for entity shader offsets
+ double originalTime = backEnd.refdef.floatTime;
+
+ fbo = glState.currentFBO;
+
+ // draw everything
+ oldEntityNum = -1;
+ backEnd.currentEntity = &tr.worldEntity;
+ oldShader = NULL;
+ oldFogNum = -1;
+ oldDepthRange = false;
+ wasCrosshair = false;
+ oldDlighted = false;
+ oldPshadowed = false;
+ oldCubemapIndex = -1;
+ oldSort = -1;
+
+ depth[0] = 0.f;
+ depth[1] = 1.f;
+
+ backEnd.pc.c_surfaces += numDrawSurfs;
+
+ for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) {
+ if ( drawSurf->sort == oldSort && drawSurf->cubemapIndex == oldCubemapIndex) {
+ if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE)
+ continue;
+
+ // fast path, same as previous sort
+ rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
+ continue;
+ }
+ oldSort = drawSurf->sort;
+ R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed );
+ cubemapIndex = drawSurf->cubemapIndex;
+
+ //
+ // change the tess parameters if needed
+ // a "entityMergable" shader is a shader that can have surfaces from seperate
+ // entities merged into a single batch, like smoke and blood puff sprites
+ if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || cubemapIndex != oldCubemapIndex
+ || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) {
+ if (oldShader != NULL) {
+ RB_EndSurface();
+ }
+ RB_BeginSurface( shader, fogNum, cubemapIndex );
+ backEnd.pc.c_surfBatches++;
+ oldShader = shader;
+ oldFogNum = fogNum;
+ oldDlighted = dlighted;
+ oldPshadowed = pshadowed;
+ oldCubemapIndex = cubemapIndex;
+ }
+
+ if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE)
+ continue;
+
+ //
+ // change the modelview matrix if needed
+ //
+ if ( entityNum != oldEntityNum ) {
+ bool sunflare = false;
+ depthRange = isCrosshair = false;
+
+ if ( entityNum != REFENTITYNUM_WORLD ) {
+ backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
+
+ // FIXME: e.shaderTime must be passed as int to avoid fp-precision loss issues
+ backEnd.refdef.floatTime = originalTime - (double)backEnd.currentEntity->e.shaderTime;
+
+ // we have to reset the shaderTime as well otherwise image animations start
+ // from the wrong frame
+ tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
+
+ // set up the transformation matrix
+ R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.orientation );
+
+ // set up the dynamic lighting if needed
+ if ( backEnd.currentEntity->needDlights ) {
+ R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.orientation );
+ }
+
+ if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK)
+ {
+ // hack the depth range to prevent view model from poking into walls
+ depthRange = true;
+
+ if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR)
+ isCrosshair = true;
+ }
+ } else {
+ backEnd.currentEntity = &tr.worldEntity;
+ backEnd.refdef.floatTime = originalTime;
+ backEnd.orientation = backEnd.viewParms.world;
+ // we have to reset the shaderTime as well otherwise image animations on
+ // the world (like water) continue with the wrong frame
+ tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
+ R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.orientation );
+ }
+
+ GL_SetModelviewMatrix( backEnd.orientation.modelMatrix );
+
+ //
+ // change depthrange. Also change projection matrix so first person weapon does not look like coming
+ // out of the screen.
+ //
+ if (oldDepthRange != depthRange || wasCrosshair != isCrosshair)
+ {
+ if (depthRange)
+ {
+ if(backEnd.viewParms.stereoFrame != STEREO_CENTER)
+ {
+ if(isCrosshair)
+ {
+ if(oldDepthRange)
+ {
+ // was not a crosshair but now is, change back proj matrix
+ GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix );
+ }
+ }
+ else
+ {
+ viewParms_t temp = backEnd.viewParms;
+
+ R_SetupProjection(&temp, r_znear->value, 0, false);
+
+ GL_SetProjectionMatrix( temp.projectionMatrix );
+ }
+ }
+
+ if(!oldDepthRange)
+ {
+ depth[0] = 0;
+ depth[1] = 0.3f;
+ qglDepthRange (depth[0], depth[1]);
+ }
+ }
+ else
+ {
+ if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER)
+ {
+ GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix );
+ }
+
+ if (!sunflare)
+ qglDepthRange (0, 1);
+
+ depth[0] = 0;
+ depth[1] = 1;
+ }
+
+ oldDepthRange = depthRange;
+ wasCrosshair = isCrosshair;
+ }
+
+ oldEntityNum = entityNum;
+ }
+
+ // add the triangles for this surface
+ rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
+ }
+
+ backEnd.refdef.floatTime = originalTime;
+
+ // draw the contents of the last shader batch
+ if (oldShader != NULL) {
+ RB_EndSurface();
+ }
+
+ if (inQuery) {
+ qglEndQuery(GL_SAMPLES_PASSED);
+ }
+
+ if (glRefConfig.framebufferObject)
+ FBO_Bind(fbo);
+
+ // go back to the world modelview matrix
+
+ GL_SetModelviewMatrix( backEnd.viewParms.world.modelMatrix );
+
+ qglDepthRange (0, 1);
+}
+
+
+/*
+============================================================================
+
+RENDER BACK END FUNCTIONS
+
+============================================================================
+*/
+
+/*
+================
+RB_SetGL2D
+
+================
+*/
+void RB_SetGL2D (void) {
+ mat4_t matrix;
+ int width, height;
+
+ if (backEnd.projection2D && backEnd.last2DFBO == glState.currentFBO)
+ return;
+
+ backEnd.projection2D = true;
+ backEnd.last2DFBO = glState.currentFBO;
+
+ if (glState.currentFBO)
+ {
+ width = glState.currentFBO->width;
+ height = glState.currentFBO->height;
+ }
+ else
+ {
+ width = glConfig.vidWidth;
+ height = glConfig.vidHeight;
+ }
+
+ // set 2D virtual screen size
+ qglViewport( 0, 0, width, height );
+ qglScissor( 0, 0, width, height );
+
+ Mat4Ortho(0, width, height, 0, 0, 1, matrix);
+ GL_SetProjectionMatrix(matrix);
+ Mat4Identity(matrix);
+ GL_SetModelviewMatrix(matrix);
+
+ GL_State( GLS_DEPTHTEST_DISABLE |
+ GLS_SRCBLEND_SRC_ALPHA |
+ GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
+
+ GL_Cull( CT_TWO_SIDED );
+ qglDisable( GL_CLIP_PLANE0 );
+
+ // set time for 2D shaders
+ backEnd.refdef.time = ri.Milliseconds();
+ backEnd.refdef.floatTime = backEnd.refdef.time * 0.001;
+}
+
+
+/*
+=============
+RE_StretchRaw
+
+FIXME: not exactly backend
+Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
+Used for cinematics.
+=============
+*/
+void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, bool dirty) {
+ int i, j;
+ int start, end;
+ vec4_t quadVerts[4];
+ vec2_t texCoords[4];
+
+ if ( !tr.registered ) {
+ return;
+ }
+ R_IssuePendingRenderCommands();
+
+ if ( tess.numIndexes ) {
+ RB_EndSurface();
+ }
+
+ // we definately want to sync every frame for the cinematics
+ qglFinish();
+
+ start = 0;
+ if ( r_speeds->integer ) {
+ start = ri.Milliseconds();
+ }
+
+ // make sure rows and cols are powers of 2
+ for ( i = 0 ; ( 1 << i ) < cols ; i++ ) {
+ }
+ for ( j = 0 ; ( 1 << j ) < rows ; j++ ) {
+ }
+ if ( ( 1 << i ) != cols || ( 1 << j ) != rows) {
+ ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
+ }
+
+ RE_UploadCinematic (w, h, cols, rows, data, client, dirty);
+ GL_BindToTMU(tr.scratchImage[client], TB_COLORMAP);
+
+ if ( r_speeds->integer ) {
+ end = ri.Milliseconds();
+ ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start );
+ }
+
+ // FIXME: HUGE hack
+ if (glRefConfig.framebufferObject)
+ {
+ FBO_Bind(backEnd.framePostProcessed ? NULL : tr.renderFbo);
+ }
+
+ RB_SetGL2D();
+
+ VectorSet4(quadVerts[0], x, y, 0.0f, 1.0f);
+ VectorSet4(quadVerts[1], x + w, y, 0.0f, 1.0f);
+ VectorSet4(quadVerts[2], x + w, y + h, 0.0f, 1.0f);
+ VectorSet4(quadVerts[3], x, y + h, 0.0f, 1.0f);
+
+ VectorSet2(texCoords[0], 0.5f / cols, 0.5f / rows);
+ VectorSet2(texCoords[1], (cols - 0.5f) / cols, 0.5f / rows);
+ VectorSet2(texCoords[2], (cols - 0.5f) / cols, (rows - 0.5f) / rows);
+ VectorSet2(texCoords[3], 0.5f / cols, (rows - 0.5f) / rows);
+
+ GLSL_BindProgram(&tr.textureColorShader);
+
+ GLSL_SetUniformMat4(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+ GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite);
+
+ RB_InstantQuad2(quadVerts, texCoords);
+}
+
+void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, bool dirty) {
+ GLuint texture;
+
+ if (!tr.scratchImage[client])
+ {
+ ri.Printf(PRINT_WARNING, "RE_UploadCinematic: scratch images not initialized\n");
+ return;
+ }
+
+ texture = tr.scratchImage[client]->texnum;
+
+ // if the scratchImage isn't in the format we want, specify it as a new texture
+ if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
+ tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
+ tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
+ qglTextureImage2DEXT(texture, GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ } else {
+ if (dirty) {
+ // otherwise, just subimage upload it so that drivers can tell we are going to be changing
+ // it and don't try and do a texture compression
+ qglTextureSubImage2DEXT(texture, GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ }
+ }
+}
+
+
+/*
+=============
+RB_SetColor
+
+=============
+*/
+const void *RB_SetColor( const void *data ) {
+ const setColorCommand_t *cmd;
+
+ cmd = (const setColorCommand_t *)data;
+
+ backEnd.color2D[0] = cmd->color[0] * 255;
+ backEnd.color2D[1] = cmd->color[1] * 255;
+ backEnd.color2D[2] = cmd->color[2] * 255;
+ backEnd.color2D[3] = cmd->color[3] * 255;
+
+ return (const void *)(cmd + 1);
+}
+
+/*
+=============
+RB_StretchPic
+=============
+*/
+const void *RB_StretchPic ( const void *data ) {
+ const stretchPicCommand_t *cmd;
+ shader_t *shader;
+ int numVerts, numIndexes;
+
+ cmd = (const stretchPicCommand_t *)data;
+
+ // FIXME: HUGE hack
+ if (glRefConfig.framebufferObject)
+ FBO_Bind(backEnd.framePostProcessed ? NULL : tr.renderFbo);
+
+ RB_SetGL2D();
+
+ shader = cmd->shader;
+ if ( shader != tess.shader ) {
+ if ( tess.numIndexes ) {
+ RB_EndSurface();
+ }
+ backEnd.currentEntity = &backEnd.entity2D;
+ RB_BeginSurface( shader, 0, 0 );
+ }
+
+ RB_CHECKOVERFLOW( 4, 6 );
+ numVerts = tess.numVertexes;
+ numIndexes = tess.numIndexes;
+
+ tess.numVertexes += 4;
+ tess.numIndexes += 6;
+
+ tess.indexes[ numIndexes ] = numVerts + 3;
+ tess.indexes[ numIndexes + 1 ] = numVerts + 0;
+ tess.indexes[ numIndexes + 2 ] = numVerts + 2;
+ tess.indexes[ numIndexes + 3 ] = numVerts + 2;
+ tess.indexes[ numIndexes + 4 ] = numVerts + 0;
+ tess.indexes[ numIndexes + 5 ] = numVerts + 1;
+
+ {
+ uint16_t color[4];
+
+ VectorScale4(backEnd.color2D, 257, color);
+
+ VectorCopy4(color, tess.color[ numVerts ]);
+ VectorCopy4(color, tess.color[ numVerts + 1]);
+ VectorCopy4(color, tess.color[ numVerts + 2]);
+ VectorCopy4(color, tess.color[ numVerts + 3 ]);
+ }
+
+ tess.xyz[ numVerts ][0] = cmd->x;
+ tess.xyz[ numVerts ][1] = cmd->y;
+ tess.xyz[ numVerts ][2] = 0;
+
+ tess.texCoords[ numVerts ][0] = cmd->s1;
+ tess.texCoords[ numVerts ][1] = cmd->t1;
+
+ tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w;
+ tess.xyz[ numVerts + 1 ][1] = cmd->y;
+ tess.xyz[ numVerts + 1 ][2] = 0;
+
+ tess.texCoords[ numVerts + 1 ][0] = cmd->s2;
+ tess.texCoords[ numVerts + 1 ][1] = cmd->t1;
+
+ tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w;
+ tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h;
+ tess.xyz[ numVerts + 2 ][2] = 0;
+
+ tess.texCoords[ numVerts + 2 ][0] = cmd->s2;
+ tess.texCoords[ numVerts + 2 ][1] = cmd->t2;
+
+ tess.xyz[ numVerts + 3 ][0] = cmd->x;
+ tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h;
+ tess.xyz[ numVerts + 3 ][2] = 0;
+
+ tess.texCoords[ numVerts + 3 ][0] = cmd->s1;
+ tess.texCoords[ numVerts + 3 ][1] = cmd->t2;
+
+ return (const void *)(cmd + 1);
+}
+
+
+/*
+=============
+RB_DrawSurfs
+
+=============
+*/
+const void *RB_DrawSurfs( const void *data ) {
+ const drawSurfsCommand_t *cmd;
+ bool isShadowView;
+
+ // finish any 2D drawing if needed
+ if ( tess.numIndexes ) {
+ RB_EndSurface();
+ }
+
+ cmd = (const drawSurfsCommand_t *)data;
+
+ backEnd.refdef = cmd->refdef;
+ backEnd.viewParms = cmd->viewParms;
+
+ isShadowView = !!(backEnd.viewParms.flags & VPF_DEPTHSHADOW);
+
+ // clear the z buffer, set the modelview, etc
+ RB_BeginDrawingView ();
+
+ if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp)
+ {
+ qglEnable(GL_DEPTH_CLAMP);
+ }
+
+ if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || isShadowView))
+ {
+ FBO_t *oldFbo = glState.currentFBO;
+ vec4_t viewInfo;
+
+ VectorSet4(viewInfo, backEnd.viewParms.zFar / r_znear->value, backEnd.viewParms.zFar, 0.0, 0.0);
+
+ backEnd.depthFill = true;
+ qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );
+ qglColorMask(!backEnd.colorMask[0], !backEnd.colorMask[1], !backEnd.colorMask[2], !backEnd.colorMask[3]);
+ backEnd.depthFill = false;
+
+ if (!isShadowView)
+ {
+ if (tr.msaaResolveFbo)
+ {
+ // If we're using multisampling, resolve the depth first
+ FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+ else if (tr.renderFbo == NULL && tr.renderDepthImage)
+ {
+ // If we're rendering directly to the screen, copy the depth to a texture
+ // This is incredibly slow on Intel Graphics, so just skip it on there
+ if (!glRefConfig.intelGraphics)
+ qglCopyTextureSubImage2DEXT(tr.renderDepthImage->texnum, GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
+ }
+
+ if (tr.hdrDepthFbo)
+ {
+ // need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image
+ vec4_t srcTexCoords;
+
+ VectorSet4(srcTexCoords, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ FBO_BlitFromTexture(tr.renderDepthImage, srcTexCoords, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0);
+ }
+
+ if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT)
+ {
+ vec4_t quadVerts[4];
+ vec2_t texCoords[4];
+ vec4_t box;
+
+ FBO_Bind(tr.screenShadowFbo);
+
+ box[0] = backEnd.viewParms.viewportX * tr.screenShadowFbo->width / (float)glConfig.vidWidth;
+ box[1] = backEnd.viewParms.viewportY * tr.screenShadowFbo->height / (float)glConfig.vidHeight;
+ box[2] = backEnd.viewParms.viewportWidth * tr.screenShadowFbo->width / (float)glConfig.vidWidth;
+ box[3] = backEnd.viewParms.viewportHeight * tr.screenShadowFbo->height / (float)glConfig.vidHeight;
+
+ qglViewport(box[0], box[1], box[2], box[3]);
+ qglScissor(box[0], box[1], box[2], box[3]);
+
+ box[0] = backEnd.viewParms.viewportX / (float)glConfig.vidWidth;
+ box[1] = backEnd.viewParms.viewportY / (float)glConfig.vidHeight;
+ box[2] = box[0] + backEnd.viewParms.viewportWidth / (float)glConfig.vidWidth;
+ box[3] = box[1] + backEnd.viewParms.viewportHeight / (float)glConfig.vidHeight;
+
+ texCoords[0][0] = box[0]; texCoords[0][1] = box[3];
+ texCoords[1][0] = box[2]; texCoords[1][1] = box[3];
+ texCoords[2][0] = box[2]; texCoords[2][1] = box[1];
+ texCoords[3][0] = box[0]; texCoords[3][1] = box[1];
+
+ box[0] = -1.0f;
+ box[1] = -1.0f;
+ box[2] = 1.0f;
+ box[3] = 1.0f;
+
+ VectorSet4(quadVerts[0], box[0], box[3], 0, 1);
+ VectorSet4(quadVerts[1], box[2], box[3], 0, 1);
+ VectorSet4(quadVerts[2], box[2], box[1], 0, 1);
+ VectorSet4(quadVerts[3], box[0], box[1], 0, 1);
+
+ GL_State(GLS_DEPTHTEST_DISABLE);
+
+ GLSL_BindProgram(&tr.shadowmaskShader);
+
+ GL_BindToTMU(tr.renderDepthImage, TB_COLORMAP);
+
+ if (r_shadowCascadeZFar->integer != 0)
+ {
+ GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP);
+ GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2);
+ GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3);
+ GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP4);
+
+ GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]);
+ GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]);
+ GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]);
+ GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP4, backEnd.refdef.sunShadowMvp[3]);
+ }
+ else
+ {
+ GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP);
+ GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[3]);
+ }
+
+ GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg);
+ {
+ vec3_t viewVector;
+
+ float zmax = backEnd.viewParms.zFar;
+ float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f);
+ float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f);
+
+ VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector);
+ GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector);
+ VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector);
+ GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWLEFT, viewVector);
+ VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector);
+ GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP, viewVector);
+
+ GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo);
+ }
+
+ RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
+
+ if (r_shadowBlur->integer)
+ {
+ viewInfo[2] = 1.0f / (float)(tr.screenScratchFbo->width);
+ viewInfo[3] = 1.0f / (float)(tr.screenScratchFbo->height);
+
+ FBO_Bind(tr.screenScratchFbo);
+
+ GLSL_BindProgram(&tr.depthBlurShader[0]);
+
+ GL_BindToTMU(tr.screenShadowImage, TB_COLORMAP);
+ GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
+
+ GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo);
+
+ RB_InstantQuad2(quadVerts, texCoords);
+
+ FBO_Bind(tr.screenShadowFbo);
+
+ GLSL_BindProgram(&tr.depthBlurShader[1]);
+
+ GL_BindToTMU(tr.screenScratchImage, TB_COLORMAP);
+ GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
+
+ GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo);
+
+ RB_InstantQuad2(quadVerts, texCoords);
+ }
+ }
+
+ if (r_ssao->integer)
+ {
+ vec4_t quadVerts[4];
+ vec2_t texCoords[4];
+
+ viewInfo[2] = 1.0f / ((float)(tr.quarterImage[0]->width) * tan(backEnd.viewParms.fovX * M_PI / 360.0f) * 2.0f);
+ viewInfo[3] = 1.0f / ((float)(tr.quarterImage[0]->height) * tan(backEnd.viewParms.fovY * M_PI / 360.0f) * 2.0f);
+ viewInfo[3] *= (float)backEnd.viewParms.viewportHeight / (float)backEnd.viewParms.viewportWidth;
+
+ FBO_Bind(tr.quarterFbo[0]);
+
+ qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height);
+ qglScissor(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height);
+
+ VectorSet4(quadVerts[0], -1, 1, 0, 1);
+ VectorSet4(quadVerts[1], 1, 1, 0, 1);
+ VectorSet4(quadVerts[2], 1, -1, 0, 1);
+ VectorSet4(quadVerts[3], -1, -1, 0, 1);
+
+ texCoords[0][0] = 0; texCoords[0][1] = 1;
+ texCoords[1][0] = 1; texCoords[1][1] = 1;
+ texCoords[2][0] = 1; texCoords[2][1] = 0;
+ texCoords[3][0] = 0; texCoords[3][1] = 0;
+
+ GL_State( GLS_DEPTHTEST_DISABLE );
+
+ GLSL_BindProgram(&tr.ssaoShader);
+
+ GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP);
+
+ GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo);
+
+ RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
+
+
+ viewInfo[2] = 1.0f / (float)(tr.quarterImage[0]->width);
+ viewInfo[3] = 1.0f / (float)(tr.quarterImage[0]->height);
+
+ FBO_Bind(tr.quarterFbo[1]);
+
+ qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height);
+ qglScissor(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height);
+
+ GLSL_BindProgram(&tr.depthBlurShader[0]);
+
+ GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP);
+ GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
+
+ GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo);
+
+ RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
+
+
+ FBO_Bind(tr.screenSsaoFbo);
+
+ qglViewport(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height);
+ qglScissor(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height);
+
+ GLSL_BindProgram(&tr.depthBlurShader[1]);
+
+ GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP);
+ GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
+
+ GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo);
+
+
+ RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
+ }
+ }
+
+ // reset viewport and scissor
+ FBO_Bind(oldFbo);
+ SetViewportAndScissor();
+ }
+
+ if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp)
+ {
+ qglDisable(GL_DEPTH_CLAMP);
+ }
+
+ if (!isShadowView)
+ {
+ RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );
+
+ if (r_drawSun->integer)
+ {
+ RB_DrawSun(0.1, tr.sunShader);
+ }
+
+ if (glRefConfig.framebufferObject && r_drawSunRays->integer)
+ {
+ FBO_t *oldFbo = glState.currentFBO;
+ FBO_Bind(tr.sunRaysFbo);
+
+ qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
+ qglClear( GL_COLOR_BUFFER_BIT );
+
+ if (glRefConfig.occlusionQuery)
+ {
+ tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = true;
+ qglBeginQuery(GL_SAMPLES_PASSED, tr.sunFlareQuery[tr.sunFlareQueryIndex]);
+ }
+
+ RB_DrawSun(0.3, tr.sunFlareShader);
+
+ if (glRefConfig.occlusionQuery)
+ {
+ qglEndQuery(GL_SAMPLES_PASSED);
+ }
+
+ FBO_Bind(oldFbo);
+ }
+
+ // darken down any stencil shadows
+ RB_ShadowFinish();
+
+ // add light flares on lights that aren't obscured
+ RB_RenderFlares();
+ }
+
+ if (glRefConfig.framebufferObject && tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo)
+ {
+ cubemap_t *cubemap = &tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex];
+
+ FBO_Bind(NULL);
+ if (cubemap && cubemap->image)
+ qglGenerateTextureMipmapEXT(cubemap->image->texnum, GL_TEXTURE_CUBE_MAP);
+ }
+
+ return (const void *)(cmd + 1);
+}
+
+
+/*
+=============
+RB_DrawBuffer
+
+=============
+*/
+const void *RB_DrawBuffer( const void *data ) {
+ const drawBufferCommand_t *cmd;
+
+ cmd = (const drawBufferCommand_t *)data;
+
+ // finish any 2D drawing if needed
+ if(tess.numIndexes)
+ RB_EndSurface();
+
+ if (glRefConfig.framebufferObject)
+ FBO_Bind(NULL);
+
+ qglDrawBuffer( cmd->buffer );
+
+ // clear screen for debugging
+ if ( r_clear->integer ) {
+ qglClearColor( 1, 0, 0.5, 1 );
+ qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+ }
+
+ return (const void *)(cmd + 1);
+}
+
+/*
+===============
+RB_ShowImages
+
+Draw all the images to the screen, on top of whatever
+was there. This is used to test for texture thrashing.
+
+Also called by RE_EndRegistration
+===============
+*/
+void RB_ShowImages( void ) {
+ int i;
+ image_t *image;
+ float x, y, w, h;
+ int start, end;
+
+ RB_SetGL2D();
+
+ qglClear( GL_COLOR_BUFFER_BIT );
+
+ qglFinish();
+
+ start = ri.Milliseconds();
+
+ for ( i=0 ; i<tr.numImages ; i++ ) {
+ image = tr.images[i];
+
+ w = glConfig.vidWidth / 20;
+ h = glConfig.vidHeight / 15;
+ x = i % 20 * w;
+ y = i / 20 * h;
+
+ // show in proportional size in mode 2
+ if ( r_showImages->integer == 2 ) {
+ w *= image->uploadWidth / 512.0f;
+ h *= image->uploadHeight / 512.0f;
+ }
+
+ {
+ vec4_t quadVerts[4];
+
+ GL_BindToTMU(image, TB_COLORMAP);
+
+ VectorSet4(quadVerts[0], x, y, 0, 1);
+ VectorSet4(quadVerts[1], x + w, y, 0, 1);
+ VectorSet4(quadVerts[2], x + w, y + h, 0, 1);
+ VectorSet4(quadVerts[3], x, y + h, 0, 1);
+
+ RB_InstantQuad(quadVerts);
+ }
+ }
+
+ qglFinish();
+
+ end = ri.Milliseconds();
+ ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start );
+
+}
+
+/*
+=============
+RB_ColorMask
+
+=============
+*/
+const void *RB_ColorMask(const void *data)
+{
+ const colorMaskCommand_t *cmd = (colorMaskCommand_t*)data;
+
+ // finish any 2D drawing if needed
+ if(tess.numIndexes)
+ RB_EndSurface();
+
+ if (glRefConfig.framebufferObject)
+ {
+ // reverse color mask, so 0 0 0 0 is the default
+ backEnd.colorMask[0] = !cmd->rgba[0];
+ backEnd.colorMask[1] = !cmd->rgba[1];
+ backEnd.colorMask[2] = !cmd->rgba[2];
+ backEnd.colorMask[3] = !cmd->rgba[3];
+ }
+
+ qglColorMask(cmd->rgba[0], cmd->rgba[1], cmd->rgba[2], cmd->rgba[3]);
+
+ return (const void *)(cmd + 1);
+}
+
+/*
+=============
+RB_ClearDepth
+
+=============
+*/
+const void *RB_ClearDepth(const void *data)
+{
+ const clearDepthCommand_t *cmd = (clearDepthCommand_t*)data;
+
+ // finish any 2D drawing if needed
+ if(tess.numIndexes)
+ RB_EndSurface();
+
+ // texture swapping test
+ if (r_showImages->integer)
+ RB_ShowImages();
+
+ if (glRefConfig.framebufferObject)
+ {
+ if (!tr.renderFbo || backEnd.framePostProcessed)
+ {
+ FBO_Bind(NULL);
+ }
+ else
+ {
+ FBO_Bind(tr.renderFbo);
+ }
+ }
+
+ qglClear(GL_DEPTH_BUFFER_BIT);
+
+ // if we're doing MSAA, clear the depth texture for the resolve buffer
+ if (tr.msaaResolveFbo)
+ {
+ FBO_Bind(tr.msaaResolveFbo);
+ qglClear(GL_DEPTH_BUFFER_BIT);
+ }
+
+
+ return (const void *)(cmd + 1);
+}
+
+
+/*
+=============
+RB_SwapBuffers
+
+=============
+*/
+const void *RB_SwapBuffers( const void *data ) {
+ const swapBuffersCommand_t *cmd;
+
+ // finish any 2D drawing if needed
+ if ( tess.numIndexes ) {
+ RB_EndSurface();
+ }
+
+ // texture swapping test
+ if ( r_showImages->integer ) {
+ RB_ShowImages();
+ }
+
+ cmd = (const swapBuffersCommand_t *)data;
+
+ // we measure overdraw by reading back the stencil buffer and
+ // counting up the number of increments that have happened
+ if ( r_measureOverdraw->integer ) {
+ int i;
+ long sum = 0;
+ unsigned char *stencilReadback;
+
+ stencilReadback = (unsigned char*)ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight );
+ qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback );
+
+ for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) {
+ sum += stencilReadback[i];
+ }
+
+ backEnd.pc.c_overDraw += sum;
+ ri.Hunk_FreeTempMemory( stencilReadback );
+ }
+
+ if (glRefConfig.framebufferObject)
+ {
+ if (!backEnd.framePostProcessed)
+ {
+ if (tr.msaaResolveFbo && r_hdr->integer)
+ {
+ // Resolving an RGB16F MSAA FBO to the screen messes with the brightness, so resolve to an RGB16F FBO first
+ FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ FBO_FastBlit(tr.msaaResolveFbo, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ }
+ else if (tr.renderFbo)
+ {
+ FBO_FastBlit(tr.renderFbo, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ }
+ }
+ }
+
+ if ( !glState.finishCalled ) {
+ qglFinish();
+ }
+
+ GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" );
+
+ GLimp_EndFrame();
+
+ backEnd.framePostProcessed = false;
+ backEnd.projection2D = false;
+
+ return (const void *)(cmd + 1);
+}
+
+/*
+=============
+RB_CapShadowMap
+
+=============
+*/
+const void *RB_CapShadowMap(const void *data)
+{
+ const capShadowmapCommand_t *cmd = (capShadowmapCommand_t*)data;
+
+ // finish any 2D drawing if needed
+ if(tess.numIndexes)
+ RB_EndSurface();
+
+ if (cmd->map != -1)
+ {
+ if (cmd->cubeSide != -1)
+ {
+ if (tr.shadowCubemaps[cmd->map])
+ {
+ qglCopyTextureSubImage2DEXT(tr.shadowCubemaps[cmd->map]->texnum, GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, 0, 0, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE);
+ }
+ }
+ else
+ {
+ if (tr.pshadowMaps[cmd->map])
+ {
+ qglCopyTextureSubImage2DEXT(tr.pshadowMaps[cmd->map]->texnum, GL_TEXTURE_2D, 0, 0, 0, backEnd.refdef.x, glConfig.vidHeight - (backEnd.refdef.y + PSHADOW_MAP_SIZE), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE);
+ }
+ }
+ }
+
+ return (const void *)(cmd + 1);
+}
+
+
+/*
+=============
+RB_PostProcess
+
+=============
+*/
+const void *RB_PostProcess(const void *data)
+{
+ const postProcessCommand_t *cmd = (const postProcessCommand_t*)data;
+ FBO_t *srcFbo;
+ ivec4_t srcBox, dstBox;
+ bool autoExposure;
+
+ // finish any 2D drawing if needed
+ if(tess.numIndexes)
+ RB_EndSurface();
+
+ if (!glRefConfig.framebufferObject || !r_postProcess->integer)
+ {
+ // do nothing
+ return (const void *)(cmd + 1);
+ }
+
+ if (cmd)
+ {
+ backEnd.refdef = cmd->refdef;
+ backEnd.viewParms = cmd->viewParms;
+ }
+
+ srcFbo = tr.renderFbo;
+ if (tr.msaaResolveFbo)
+ {
+ // Resolve the MSAA before anything else
+ // Can't resolve just part of the MSAA FBO, so multiple views will suffer a performance hit here
+ FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ srcFbo = tr.msaaResolveFbo;
+ }
+
+ dstBox[0] = backEnd.viewParms.viewportX;
+ dstBox[1] = backEnd.viewParms.viewportY;
+ dstBox[2] = backEnd.viewParms.viewportWidth;
+ dstBox[3] = backEnd.viewParms.viewportHeight;
+
+ if (r_ssao->integer)
+ {
+ srcBox[0] = backEnd.viewParms.viewportX * tr.screenSsaoImage->width / (float)glConfig.vidWidth;
+ srcBox[1] = backEnd.viewParms.viewportY * tr.screenSsaoImage->height / (float)glConfig.vidHeight;
+ srcBox[2] = backEnd.viewParms.viewportWidth * tr.screenSsaoImage->width / (float)glConfig.vidWidth;
+ srcBox[3] = backEnd.viewParms.viewportHeight * tr.screenSsaoImage->height / (float)glConfig.vidHeight;
+
+ FBO_Blit(tr.screenSsaoFbo, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO);
+ }
+
+ srcBox[0] = backEnd.viewParms.viewportX;
+ srcBox[1] = backEnd.viewParms.viewportY;
+ srcBox[2] = backEnd.viewParms.viewportWidth;
+ srcBox[3] = backEnd.viewParms.viewportHeight;
+
+ if (srcFbo)
+ {
+ if (r_hdr->integer && (r_toneMap->integer || r_forceToneMap->integer))
+ {
+ autoExposure = r_autoExposure->integer || r_forceAutoExposure->integer;
+ RB_ToneMap(srcFbo, srcBox, NULL, dstBox, autoExposure);
+ }
+ else if (r_cameraExposure->value == 0.0f)
+ {
+ FBO_FastBlit(srcFbo, srcBox, NULL, dstBox, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ }
+ else
+ {
+ vec4_t color;
+
+ color[0] =
+ color[1] =
+ color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value);
+ color[3] = 1.0f;
+
+ FBO_Blit(srcFbo, srcBox, NULL, NULL, dstBox, NULL, color, 0);
+ }
+ }
+
+ if (r_drawSunRays->integer)
+ RB_SunRays(NULL, srcBox, NULL, dstBox);
+
+ if (1)
+ RB_BokehBlur(NULL, srcBox, NULL, dstBox, backEnd.refdef.blurFactor);
+ else
+ RB_GaussianBlur(backEnd.refdef.blurFactor);
+
+#if 0
+ if (0)
+ {
+ vec4_t quadVerts[4];
+ vec2_t texCoords[4];
+ ivec4_t iQtrBox;
+ vec4_t box;
+ vec4_t viewInfo;
+ static float scale = 5.0f;
+
+ scale -= 0.005f;
+ if (scale < 0.01f)
+ scale = 5.0f;
+
+ FBO_FastBlit(NULL, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+
+ iQtrBox[0] = backEnd.viewParms.viewportX * tr.quarterImage[0]->width / (float)glConfig.vidWidth;
+ iQtrBox[1] = backEnd.viewParms.viewportY * tr.quarterImage[0]->height / (float)glConfig.vidHeight;
+ iQtrBox[2] = backEnd.viewParms.viewportWidth * tr.quarterImage[0]->width / (float)glConfig.vidWidth;
+ iQtrBox[3] = backEnd.viewParms.viewportHeight * tr.quarterImage[0]->height / (float)glConfig.vidHeight;
+
+ qglViewport(iQtrBox[0], iQtrBox[1], iQtrBox[2], iQtrBox[3]);
+ qglScissor(iQtrBox[0], iQtrBox[1], iQtrBox[2], iQtrBox[3]);
+
+ VectorSet4(box, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ texCoords[0][0] = box[0]; texCoords[0][1] = box[3];
+ texCoords[1][0] = box[2]; texCoords[1][1] = box[3];
+ texCoords[2][0] = box[2]; texCoords[2][1] = box[1];
+ texCoords[3][0] = box[0]; texCoords[3][1] = box[1];
+
+ VectorSet4(box, -1.0f, -1.0f, 1.0f, 1.0f);
+
+ VectorSet4(quadVerts[0], box[0], box[3], 0, 1);
+ VectorSet4(quadVerts[1], box[2], box[3], 0, 1);
+ VectorSet4(quadVerts[2], box[2], box[1], 0, 1);
+ VectorSet4(quadVerts[3], box[0], box[1], 0, 1);
+
+ GL_State(GLS_DEPTHTEST_DISABLE);
+
+
+ VectorSet4(viewInfo, backEnd.viewParms.zFar / r_znear->value, backEnd.viewParms.zFar, 0.0, 0.0);
+
+ viewInfo[2] = scale / (float)(tr.quarterImage[0]->width);
+ viewInfo[3] = scale / (float)(tr.quarterImage[0]->height);
+
+ FBO_Bind(tr.quarterFbo[1]);
+ GLSL_BindProgram(&tr.depthBlurShader[2]);
+ GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP);
+ GLSL_SetUniformVec4(&tr.depthBlurShader[2], UNIFORM_VIEWINFO, viewInfo);
+ RB_InstantQuad2(quadVerts, texCoords);
+
+ FBO_Bind(tr.quarterFbo[0]);
+ GLSL_BindProgram(&tr.depthBlurShader[3]);
+ GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP);
+ GLSL_SetUniformVec4(&tr.depthBlurShader[3], UNIFORM_VIEWINFO, viewInfo);
+ RB_InstantQuad2(quadVerts, texCoords);
+
+ SetViewportAndScissor();
+
+ FBO_FastBlit(tr.quarterFbo[1], NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ FBO_Bind(NULL);
+ }
+#endif
+
+ if (0 && r_sunlightMode->integer)
+ {
+ ivec4_t dstBox;
+ VectorSet4(dstBox, 0, glConfig.vidHeight - 128, 128, 128);
+ FBO_BlitFromTexture(tr.sunShadowDepthImage[0], NULL, NULL, NULL, dstBox, NULL, NULL, 0);
+ VectorSet4(dstBox, 128, glConfig.vidHeight - 128, 128, 128);
+ FBO_BlitFromTexture(tr.sunShadowDepthImage[1], NULL, NULL, NULL, dstBox, NULL, NULL, 0);
+ VectorSet4(dstBox, 256, glConfig.vidHeight - 128, 128, 128);
+ FBO_BlitFromTexture(tr.sunShadowDepthImage[2], NULL, NULL, NULL, dstBox, NULL, NULL, 0);
+ VectorSet4(dstBox, 384, glConfig.vidHeight - 128, 128, 128);
+ FBO_BlitFromTexture(tr.sunShadowDepthImage[3], NULL, NULL, NULL, dstBox, NULL, NULL, 0);
+ }
+
+ if (0 && r_shadows->integer == 4)
+ {
+ ivec4_t dstBox;
+ VectorSet4(dstBox, 512 + 0, glConfig.vidHeight - 128, 128, 128);
+ FBO_BlitFromTexture(tr.pshadowMaps[0], NULL, NULL, NULL, dstBox, NULL, NULL, 0);
+ VectorSet4(dstBox, 512 + 128, glConfig.vidHeight - 128, 128, 128);
+ FBO_BlitFromTexture(tr.pshadowMaps[1], NULL, NULL, NULL, dstBox, NULL, NULL, 0);
+ VectorSet4(dstBox, 512 + 256, glConfig.vidHeight - 128, 128, 128);
+ FBO_BlitFromTexture(tr.pshadowMaps[2], NULL, NULL, NULL, dstBox, NULL, NULL, 0);
+ VectorSet4(dstBox, 512 + 384, glConfig.vidHeight - 128, 128, 128);
+ FBO_BlitFromTexture(tr.pshadowMaps[3], NULL, NULL, NULL, dstBox, NULL, NULL, 0);
+ }
+
+ if (0)
+ {
+ ivec4_t dstBox;
+ VectorSet4(dstBox, 256, glConfig.vidHeight - 256, 256, 256);
+ FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0);
+ VectorSet4(dstBox, 512, glConfig.vidHeight - 256, 256, 256);
+ FBO_BlitFromTexture(tr.screenShadowImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0);
+ }
+
+ if (0)
+ {
+ ivec4_t dstBox;
+ VectorSet4(dstBox, 256, glConfig.vidHeight - 256, 256, 256);
+ FBO_BlitFromTexture(tr.sunRaysImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0);
+ }
+
+#if 0
+ if (r_cubeMapping->integer && tr.numCubemaps)
+ {
+ ivec4_t dstBox;
+ int cubemapIndex = R_CubemapForPoint( backEnd.viewParms.orientation.origin );
+
+ if (cubemapIndex)
+ {
+ VectorSet4(dstBox, 0, glConfig.vidHeight - 256, 256, 256);
+ //FBO_BlitFromTexture(tr.renderCubeImage, NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0);
+ FBO_BlitFromTexture(tr.cubemaps[cubemapIndex - 1].image, NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0);
+ }
+ }
+#endif
+
+ backEnd.framePostProcessed = true;
+
+ return (const void *)(cmd + 1);
+}
+
+// FIXME: put this function declaration elsewhere
+void R_SaveDDS(const char *filename, byte *pic, int width, int height, int depth);
+
+/*
+=============
+RB_ExportCubemaps
+
+=============
+*/
+const void *RB_ExportCubemaps(const void *data)
+{
+ const exportCubemapsCommand_t *cmd = (const exportCubemapsCommand_t*)data;
+
+ // finish any 2D drawing if needed
+ if (tess.numIndexes)
+ RB_EndSurface();
+
+ if (!glRefConfig.framebufferObject || !tr.world || tr.numCubemaps == 0)
+ {
+ // do nothing
+ ri.Printf(PRINT_ALL, "Nothing to export!\n");
+ return (const void *)(cmd + 1);
+ }
+
+ if (cmd)
+ {
+ FBO_t *oldFbo = glState.currentFBO;
+ int sideSize = r_cubemapSize->integer * r_cubemapSize->integer * 4;
+ byte *cubemapPixels = (byte*)ri.Malloc(sideSize * 6);
+ int i, j;
+
+ FBO_Bind(tr.renderCubeFbo);
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ char filename[MAX_QPATH];
+ cubemap_t *cubemap = &tr.cubemaps[i];
+ byte *p = cubemapPixels;
+
+ for (j = 0; j < 6; j++)
+ {
+ FBO_AttachImage(tr.renderCubeFbo, cubemap->image, GL_COLOR_ATTACHMENT0_EXT, j);
+ qglReadPixels(0, 0, r_cubemapSize->integer, r_cubemapSize->integer, GL_RGBA, GL_UNSIGNED_BYTE, p);
+ p += sideSize;
+ }
+
+ if (cubemap->name[0])
+ {
+ COM_StripExtension(cubemap->name, filename, MAX_QPATH);
+ Q_strcat(filename, MAX_QPATH, ".dds");
+ }
+ else
+ {
+ Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/%03d.dds", tr.world->baseName, i);
+ }
+
+ R_SaveDDS(filename, cubemapPixels, r_cubemapSize->integer, r_cubemapSize->integer, 6);
+ ri.Printf(PRINT_ALL, "Saved cubemap %d as %s\n", i, filename);
+ }
+
+ FBO_Bind(oldFbo);
+
+ ri.Free(cubemapPixels);
+ }
+
+ return (const void *)(cmd + 1);
+}
+
+
+/*
+====================
+RB_ExecuteRenderCommands
+====================
+*/
+void RB_ExecuteRenderCommands( const void *data ) {
+ int t1, t2;
+
+ t1 = ri.Milliseconds ();
+
+ while ( 1 ) {
+ data = PADP(data, sizeof(void *));
+
+ switch ( *(const int *)data ) {
+ case RC_SET_COLOR:
+ data = RB_SetColor( data );
+ break;
+ case RC_STRETCH_PIC:
+ data = RB_StretchPic( data );
+ break;
+ case RC_DRAW_SURFS:
+ data = RB_DrawSurfs( data );
+ break;
+ case RC_DRAW_BUFFER:
+ data = RB_DrawBuffer( data );
+ break;
+ case RC_SWAP_BUFFERS:
+ data = RB_SwapBuffers( data );
+ break;
+ case RC_SCREENSHOT:
+ data = RB_TakeScreenshotCmd( data );
+ break;
+ case RC_VIDEOFRAME:
+ data = RB_TakeVideoFrameCmd( data );
+ break;
+ case RC_COLORMASK:
+ data = RB_ColorMask(data);
+ break;
+ case RC_CLEARDEPTH:
+ data = RB_ClearDepth(data);
+ break;
+ case RC_CAPSHADOWMAP:
+ data = RB_CapShadowMap(data);
+ break;
+ case RC_POSTPROCESS:
+ data = RB_PostProcess(data);
+ break;
+ case RC_EXPORT_CUBEMAPS:
+ data = RB_ExportCubemaps(data);
+ break;
+ case RC_END_OF_LIST:
+ default:
+ // finish any 2D drawing if needed
+ if(tess.numIndexes)
+ RB_EndSurface();
+
+ // stop rendering
+ t2 = ri.Milliseconds ();
+ backEnd.pc.msec = t2 - t1;
+ return;
+ }
+ }
+
+}
diff --git a/src/renderergl2/tr_bsp.cpp b/src/renderergl2/tr_bsp.cpp
new file mode 100644
index 0000000..3bf74b5
--- /dev/null
+++ b/src/renderergl2/tr_bsp.cpp
@@ -0,0 +1,3046 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_map.c
+
+#include "tr_local.h"
+
+#define JSON_IMPLEMENTATION
+#include "qcommon/json.h"
+#undef JSON_IMPLEMENTATION
+
+/*
+
+Loads and prepares a map file for scene rendering.
+
+A single entry point:
+
+void RE_LoadWorldMap( const char *name );
+
+*/
+
+static world_t s_worldData;
+static byte *fileBase;
+
+int c_subdivisions;
+int c_gridVerts;
+
+//===============================================================================
+
+static void HSVtoRGB( float h, float s, float v, float rgb[3] )
+{
+ int i;
+ float f;
+ float p, q, t;
+
+ h *= 5;
+
+ i = floor( h );
+ f = h - i;
+
+ p = v * ( 1 - s );
+ q = v * ( 1 - s * f );
+ t = v * ( 1 - s * ( 1 - f ) );
+
+ switch ( i )
+ {
+ case 0:
+ rgb[0] = v;
+ rgb[1] = t;
+ rgb[2] = p;
+ break;
+ case 1:
+ rgb[0] = q;
+ rgb[1] = v;
+ rgb[2] = p;
+ break;
+ case 2:
+ rgb[0] = p;
+ rgb[1] = v;
+ rgb[2] = t;
+ break;
+ case 3:
+ rgb[0] = p;
+ rgb[1] = q;
+ rgb[2] = v;
+ break;
+ case 4:
+ rgb[0] = t;
+ rgb[1] = p;
+ rgb[2] = v;
+ break;
+ case 5:
+ rgb[0] = v;
+ rgb[1] = p;
+ rgb[2] = q;
+ break;
+ }
+}
+
+/*
+===============
+R_ColorShiftLightingBytes
+
+===============
+*/
+static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) {
+ int shift, r, g, b;
+
+ // shift the color data based on overbright range
+ shift = r_mapOverBrightBits->integer - tr.overbrightBits;
+
+ // shift the data based on overbright range
+ r = in[0] << shift;
+ g = in[1] << shift;
+ b = in[2] << shift;
+
+ // Minimum values
+ if(r < r_mapLightmapMin->integer){
+ r = r_mapLightmapMin->integer;
+ }
+ if(g < r_mapLightmapMin->integer){
+ g = r_mapLightmapMin->integer;
+ }
+ if(b < r_mapLightmapMin->integer){
+ b = r_mapLightmapMin->integer;
+ }
+
+ // normalize by color instead of saturating to white
+ if ( ( r | g | b ) > 255 ) {
+ int max;
+
+ max = r > g ? r : g;
+ max = max > b ? max : b;
+ r = r * 255 / max;
+ g = g * 255 / max;
+ b = b * 255 / max;
+ }
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = in[3];
+}
+
+
+/*
+===============
+R_ColorShiftLightingFloats
+
+===============
+*/
+static void R_ColorShiftLightingFloats(float in[4], float out[4])
+{
+ float r, g, b;
+ float scale = (1 << (r_mapOverBrightBits->integer - tr.overbrightBits)) / 255.0f;
+
+ r = in[0] * scale;
+ g = in[1] * scale;
+ b = in[2] * scale;
+
+ // Minimum values
+ if(r < r_mapLightmapMin->value / 255.0f){
+ r = r_mapLightmapMin->value / 255.0f;
+ }
+ if(g < r_mapLightmapMin->value / 255.0f){
+ g = r_mapLightmapMin->value / 255.0f;
+ }
+ if(b < r_mapLightmapMin->value / 255.0f){
+ b = r_mapLightmapMin->value / 255.0f;
+ }
+
+ // normalize by color instead of saturating to white
+ if ( r > 1 || g > 1 || b > 1 ) {
+ float max;
+
+ max = r > g ? r : g;
+ max = max > b ? max : b;
+ r = r / max;
+ g = g / max;
+ b = b / max;
+ }
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = in[3];
+}
+
+// Modified from http://graphicrants.blogspot.jp/2009/04/rgbm-color-encoding.html
+void ColorToRGBM(const vec3_t color, unsigned char rgbm[4])
+{
+ vec3_t sample;
+ float maxComponent;
+
+ VectorCopy(color, sample);
+
+ maxComponent = MAX(sample[0], sample[1]);
+ maxComponent = MAX(maxComponent, sample[2]);
+ maxComponent = CLAMP(maxComponent, 1.0f/255.0f, 1.0f);
+
+ rgbm[3] = (unsigned char) ceil(maxComponent * 255.0f);
+ maxComponent = 255.0f / rgbm[3];
+
+ VectorScale(sample, maxComponent, sample);
+
+ rgbm[0] = (unsigned char) (sample[0] * 255);
+ rgbm[1] = (unsigned char) (sample[1] * 255);
+ rgbm[2] = (unsigned char) (sample[2] * 255);
+}
+
+void ColorToRGB16(const vec3_t color, uint16_t rgb16[3])
+{
+ rgb16[0] = color[0] * 65535.0f + 0.5f;
+ rgb16[1] = color[1] * 65535.0f + 0.5f;
+ rgb16[2] = color[2] * 65535.0f + 0.5f;
+}
+
+
+/*
+===============
+R_LoadLightmaps
+
+===============
+*/
+#define DEFAULT_LIGHTMAP_SIZE 128
+static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) {
+ int/*imgFlags_t*/ imgFlags = IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE;
+ byte *buf, *buf_p;
+ dsurface_t *surf;
+ int len;
+ byte *image;
+ int i, j, numLightmaps, textureInternalFormat = 0;
+ int numLightmapsPerPage = 16;
+ float maxIntensity = 0;
+ double sumIntensity = 0;
+
+ len = l->filelen;
+ if ( !len ) {
+ return;
+ }
+ buf = fileBase + l->fileofs;
+
+ // we are about to upload textures
+ R_IssuePendingRenderCommands();
+
+ tr.lightmapSize = DEFAULT_LIGHTMAP_SIZE;
+ numLightmaps = len / (tr.lightmapSize * tr.lightmapSize * 3);
+
+ // check for deluxe mapping
+ if (numLightmaps <= 1)
+ {
+ tr.worldDeluxeMapping = false;
+ }
+ else
+ {
+ tr.worldDeluxeMapping = true;
+ for( i = 0, surf = (dsurface_t *)(fileBase + surfs->fileofs);
+ i < surfs->filelen / sizeof(dsurface_t); i++, surf++ ) {
+ int lightmapNum = LittleLong( surf->lightmapNum );
+
+ if ( lightmapNum >= 0 && (lightmapNum & 1) != 0 ) {
+ tr.worldDeluxeMapping = false;
+ break;
+ }
+ }
+ }
+
+ image = (byte*)ri.Malloc(tr.lightmapSize * tr.lightmapSize * 4 * 2);
+
+ if (tr.worldDeluxeMapping)
+ numLightmaps >>= 1;
+
+ // Use fat lightmaps of an appropriate size.
+ if (r_mergeLightmaps->integer)
+ {
+ int maxLightmapsPerAxis = glConfig.maxTextureSize / tr.lightmapSize;
+ int lightmapCols = 4, lightmapRows = 4;
+
+ // Increase width at first, then height.
+ while (lightmapCols * lightmapRows < numLightmaps && lightmapCols != maxLightmapsPerAxis)
+ lightmapCols <<= 1;
+
+ while (lightmapCols * lightmapRows < numLightmaps && lightmapRows != maxLightmapsPerAxis)
+ lightmapRows <<= 1;
+
+ tr.fatLightmapCols = lightmapCols;
+ tr.fatLightmapRows = lightmapRows;
+ numLightmapsPerPage = lightmapCols * lightmapRows;
+
+ tr.numLightmaps = (numLightmaps + (numLightmapsPerPage - 1)) / numLightmapsPerPage;
+ }
+ else
+ {
+ tr.numLightmaps = numLightmaps;
+ }
+
+ tr.lightmaps = (image_t**)ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low );
+
+ if (tr.worldDeluxeMapping)
+ tr.deluxemaps = (image_t**)ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low );
+
+ textureInternalFormat = GL_RGBA8;
+ if (r_hdr->integer)
+ {
+ // Check for the first hdr lightmap, if it exists, use GL_RGBA16 for textures.
+ char filename[MAX_QPATH];
+
+ Com_sprintf(filename, sizeof(filename), "maps/%s/lm_0000.hdr", s_worldData.baseName);
+ if (ri.FS_FileExists(filename))
+ textureInternalFormat = GL_RGBA16;
+ }
+
+ if (r_mergeLightmaps->integer)
+ {
+ int width = tr.fatLightmapCols * tr.lightmapSize;
+ int height = tr.fatLightmapRows * tr.lightmapSize;
+
+ for (i = 0; i < tr.numLightmaps; i++)
+ {
+ tr.lightmaps[i] = R_CreateImage(va("_fatlightmap%d", i), NULL, width, height, IMGTYPE_COLORALPHA, imgFlags, textureInternalFormat);
+
+ if (tr.worldDeluxeMapping)
+ tr.deluxemaps[i] = R_CreateImage(va("_fatdeluxemap%d", i), NULL, width, height, IMGTYPE_DELUXE, imgFlags, 0);
+ }
+ }
+
+ for(i = 0; i < numLightmaps; i++)
+ {
+ int xoff = 0, yoff = 0;
+ int lightmapnum = i;
+ // expand the 24 bit on-disk to 32 bit
+
+ if (r_mergeLightmaps->integer)
+ {
+ int lightmaponpage = i % numLightmapsPerPage;
+ xoff = (lightmaponpage % tr.fatLightmapCols) * tr.lightmapSize;
+ yoff = (lightmaponpage / tr.fatLightmapCols) * tr.lightmapSize;
+
+ lightmapnum /= numLightmapsPerPage;
+ }
+
+ // if (tr.worldLightmapping)
+ {
+ char filename[MAX_QPATH];
+ byte *hdrLightmap = NULL;
+ int size = 0;
+
+ // look for hdr lightmaps
+ if (textureInternalFormat == GL_RGBA16)
+ {
+ Com_sprintf( filename, sizeof( filename ), "maps/%s/lm_%04d.hdr", s_worldData.baseName, i * (tr.worldDeluxeMapping ? 2 : 1) );
+ //ri.Printf(PRINT_ALL, "looking for %s\n", filename);
+
+ size = ri.FS_ReadFile(filename, (void **)&hdrLightmap);
+ }
+
+ if (hdrLightmap)
+ {
+ byte *p = hdrLightmap, *end = hdrLightmap + size;
+ //ri.Printf(PRINT_ALL, "found!\n");
+
+ /* FIXME: don't just skip over this header and actually parse it */
+ while (p < end && !(*p == '\n' && *(p+1) == '\n'))
+ p++;
+
+ p += 2;
+
+ while (p < end && !(*p == '\n'))
+ p++;
+
+ p++;
+
+ if (p >= end)
+ ri.Error(ERR_DROP, "Bad header for %s!", filename);
+
+ buf_p = p;
+
+#if 0 // HDRFILE_RGBE
+ if ((int)(end - hdrLightmap) != tr.lightmapSize * tr.lightmapSize * 4)
+ ri.Error(ERR_DROP, "Bad size for %s (%i)!", filename, size);
+#else // HDRFILE_FLOAT
+ if ((int)(end - hdrLightmap) != tr.lightmapSize * tr.lightmapSize * 12)
+ ri.Error(ERR_DROP, "Bad size for %s (%i)!", filename, size);
+#endif
+ }
+ else
+ {
+ int imgOffset = tr.worldDeluxeMapping ? i * 2 : i;
+ buf_p = buf + imgOffset * tr.lightmapSize * tr.lightmapSize * 3;
+ }
+
+ for ( j = 0 ; j < tr.lightmapSize * tr.lightmapSize; j++ )
+ {
+ if (hdrLightmap)
+ {
+ vec4_t color;
+
+#if 0 // HDRFILE_RGBE
+ float exponent = exp2(buf_p[j*4+3] - 128);
+
+ color[0] = buf_p[j*4+0] * exponent;
+ color[1] = buf_p[j*4+1] * exponent;
+ color[2] = buf_p[j*4+2] * exponent;
+#else // HDRFILE_FLOAT
+ memcpy(color, &buf_p[j*12], 12);
+
+ color[0] = LittleFloat(color[0]);
+ color[1] = LittleFloat(color[1]);
+ color[2] = LittleFloat(color[2]);
+#endif
+ color[3] = 1.0f;
+
+ R_ColorShiftLightingFloats(color, color);
+
+ ColorToRGB16(color, (uint16_t *)(&image[j * 8]));
+ ((uint16_t *)(&image[j * 8]))[3] = 65535;
+ }
+ else if (textureInternalFormat == GL_RGBA16)
+ {
+ vec4_t color;
+
+ //hack: convert LDR lightmap to HDR one
+ color[0] = MAX(buf_p[j*3+0], 0.499f);
+ color[1] = MAX(buf_p[j*3+1], 0.499f);
+ color[2] = MAX(buf_p[j*3+2], 0.499f);
+
+ // if under an arbitrary value (say 12) grey it out
+ // this prevents weird splotches in dimly lit areas
+ if (color[0] + color[1] + color[2] < 12.0f)
+ {
+ float avg = (color[0] + color[1] + color[2]) * 0.3333f;
+ color[0] = avg;
+ color[1] = avg;
+ color[2] = avg;
+ }
+ color[3] = 1.0f;
+
+ R_ColorShiftLightingFloats(color, color);
+
+ ColorToRGB16(color, (uint16_t *)(&image[j * 8]));
+ ((uint16_t *)(&image[j * 8]))[3] = 65535;
+ }
+ else
+ {
+ if ( r_lightmap->integer == 2 )
+ { // color code by intensity as development tool (FIXME: check range)
+ float r = buf_p[j*3+0];
+ float g = buf_p[j*3+1];
+ float b = buf_p[j*3+2];
+ float intensity;
+ float out[3] = {0.0, 0.0, 0.0};
+
+ intensity = 0.33f * r + 0.685f * g + 0.063f * b;
+
+ if ( intensity > 255 )
+ intensity = 1.0f;
+ else
+ intensity /= 255.0f;
+
+ if ( intensity > maxIntensity )
+ maxIntensity = intensity;
+
+ HSVtoRGB( intensity, 1.00, 0.50, out );
+
+ image[j*4+0] = out[0] * 255;
+ image[j*4+1] = out[1] * 255;
+ image[j*4+2] = out[2] * 255;
+ image[j*4+3] = 255;
+
+ sumIntensity += intensity;
+ }
+ else
+ {
+ R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] );
+ image[j*4+3] = 255;
+ }
+ }
+ }
+
+ if (r_mergeLightmaps->integer)
+ R_UpdateSubImage(tr.lightmaps[lightmapnum], image, xoff, yoff, tr.lightmapSize, tr.lightmapSize, textureInternalFormat);
+ else
+ tr.lightmaps[i] = R_CreateImage(va("*lightmap%d", i), image, tr.lightmapSize, tr.lightmapSize, IMGTYPE_COLORALPHA, imgFlags, textureInternalFormat );
+
+ if (hdrLightmap)
+ ri.FS_FreeFile(hdrLightmap);
+ }
+
+ if (tr.worldDeluxeMapping)
+ {
+ buf_p = buf + (i * 2 + 1) * tr.lightmapSize * tr.lightmapSize * 3;
+
+ for ( j = 0 ; j < tr.lightmapSize * tr.lightmapSize; j++ ) {
+ image[j*4+0] = buf_p[j*3+0];
+ image[j*4+1] = buf_p[j*3+1];
+ image[j*4+2] = buf_p[j*3+2];
+
+ // make 0,0,0 into 127,127,127
+ if ((image[j*4+0] == 0) && (image[j*4+1] == 0) && (image[j*4+2] == 0))
+ {
+ image[j*4+0] =
+ image[j*4+1] =
+ image[j*4+2] = 127;
+ }
+
+ image[j*4+3] = 255;
+ }
+
+ if (r_mergeLightmaps->integer)
+ R_UpdateSubImage(tr.deluxemaps[lightmapnum], image, xoff, yoff, tr.lightmapSize, tr.lightmapSize, GL_RGBA8 );
+ else
+ tr.deluxemaps[i] = R_CreateImage(va("*deluxemap%d", i), image, tr.lightmapSize, tr.lightmapSize, IMGTYPE_DELUXE, imgFlags, 0 );
+ }
+ }
+
+ if ( r_lightmap->integer == 2 ) {
+ ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) );
+ }
+
+ ri.Free(image);
+}
+
+
+static float FatPackU(float input, int lightmapnum)
+{
+ if (lightmapnum < 0)
+ return input;
+
+ if (tr.worldDeluxeMapping)
+ lightmapnum >>= 1;
+
+ if (tr.fatLightmapCols > 0)
+ {
+ lightmapnum %= (tr.fatLightmapCols * tr.fatLightmapRows);
+ return (input + (lightmapnum % tr.fatLightmapCols)) / (float)(tr.fatLightmapCols);
+ }
+
+ return input;
+}
+
+static float FatPackV(float input, int lightmapnum)
+{
+ if (lightmapnum < 0)
+ return input;
+
+ if (tr.worldDeluxeMapping)
+ lightmapnum >>= 1;
+
+ if (tr.fatLightmapCols > 0)
+ {
+ lightmapnum %= (tr.fatLightmapCols * tr.fatLightmapRows);
+ return (input + (lightmapnum / tr.fatLightmapCols)) / (float)(tr.fatLightmapRows);
+ }
+
+ return input;
+}
+
+
+static int FatLightmap(int lightmapnum)
+{
+ if (lightmapnum < 0)
+ return lightmapnum;
+
+ if (tr.worldDeluxeMapping)
+ lightmapnum >>= 1;
+
+ if (tr.fatLightmapCols > 0)
+ return lightmapnum / (tr.fatLightmapCols * tr.fatLightmapRows);
+
+ return lightmapnum;
+}
+
+/*
+=================
+RE_SetWorldVisData
+
+This is called by the clipmodel subsystem so we can share the 1.8 megs of
+space in big maps...
+=================
+*/
+void RE_SetWorldVisData( const byte *vis ) {
+ tr.externalVisData = vis;
+}
+
+
+/*
+=================
+R_LoadVisibility
+=================
+*/
+static void R_LoadVisibility( lump_t *l ) {
+ int len;
+ byte *buf;
+
+ len = l->filelen;
+ if ( !len ) {
+ return;
+ }
+ buf = fileBase + l->fileofs;
+
+ s_worldData.numClusters = LittleLong( ((int *)buf)[0] );
+ s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] );
+
+ // CM_Load should have given us the vis data to share, so
+ // we don't need to allocate another copy
+ if ( tr.externalVisData ) {
+ s_worldData.vis = tr.externalVisData;
+ } else {
+ byte *dest = (byte*)ri.Hunk_Alloc( len - 8, h_low );
+ Com_Memcpy( dest, buf + 8, len - 8 );
+ s_worldData.vis = dest;
+ }
+}
+
+//===============================================================================
+
+
+/*
+===============
+ShaderForShaderNum
+===============
+*/
+static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) {
+ shader_t *shader;
+ dshader_t *dsh;
+
+ int _shaderNum = LittleLong( shaderNum );
+ if ( _shaderNum < 0 || _shaderNum >= s_worldData.numShaders ) {
+ ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", _shaderNum );
+ }
+ dsh = &s_worldData.shaders[ _shaderNum ];
+
+ if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
+ lightmapNum = LIGHTMAP_BY_VERTEX;
+ }
+
+ if ( r_fullbright->integer ) {
+ lightmapNum = LIGHTMAP_WHITEIMAGE;
+ }
+
+ shader = R_FindShader( dsh->shader, lightmapNum, true );
+
+ // if the shader had errors, just use default shader
+ if ( shader->defaultShader ) {
+ return tr.defaultShader;
+ }
+
+ return shader;
+}
+
+void LoadDrawVertToSrfVert(srfVert_t *s, drawVert_t *d, int realLightmapNum, float hdrVertColors[3], vec3_t *bounds)
+{
+ vec4_t v;
+
+ s->xyz[0] = LittleFloat(d->xyz[0]);
+ s->xyz[1] = LittleFloat(d->xyz[1]);
+ s->xyz[2] = LittleFloat(d->xyz[2]);
+
+ if (bounds)
+ AddPointToBounds(s->xyz, bounds[0], bounds[1]);
+
+ s->st[0] = LittleFloat(d->st[0]);
+ s->st[1] = LittleFloat(d->st[1]);
+
+ if (realLightmapNum >= 0)
+ {
+ s->lightmap[0] = FatPackU(LittleFloat(d->lightmap[0]), realLightmapNum);
+ s->lightmap[1] = FatPackV(LittleFloat(d->lightmap[1]), realLightmapNum);
+ }
+ else
+ {
+ s->lightmap[0] = LittleFloat(d->lightmap[0]);
+ s->lightmap[1] = LittleFloat(d->lightmap[1]);
+ }
+
+ v[0] = LittleFloat(d->normal[0]);
+ v[1] = LittleFloat(d->normal[1]);
+ v[2] = LittleFloat(d->normal[2]);
+
+ R_VaoPackNormal(s->normal, v);
+
+ if (hdrVertColors)
+ {
+ v[0] = hdrVertColors[0];
+ v[1] = hdrVertColors[1];
+ v[2] = hdrVertColors[2];
+ }
+ else
+ {
+ //hack: convert LDR vertex colors to HDR
+ if (r_hdr->integer)
+ {
+ v[0] = MAX(d->color[0], 0.499f);
+ v[1] = MAX(d->color[1], 0.499f);
+ v[2] = MAX(d->color[2], 0.499f);
+ }
+ else
+ {
+ v[0] = d->color[0];
+ v[1] = d->color[1];
+ v[2] = d->color[2];
+ }
+
+ }
+ v[3] = d->color[3] / 255.0f;
+
+ R_ColorShiftLightingFloats(v, v);
+ R_VaoPackColor(s->color, v);
+}
+
+
+/*
+===============
+ParseFace
+===============
+*/
+static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf, int *indexes ) {
+ int i, j;
+ srfBspSurface_t *cv;
+ glIndex_t *tri;
+ int numVerts, numIndexes, badTriangles;
+ int realLightmapNum;
+
+ realLightmapNum = LittleLong( ds->lightmapNum );
+
+ // get fog volume
+ surf->fogIndex = LittleLong( ds->fogNum ) + 1;
+
+ // get shader value
+ surf->shader = ShaderForShaderNum( ds->shaderNum, FatLightmap(realLightmapNum) );
+ if ( r_singleShader->integer && !surf->shader->isSky ) {
+ surf->shader = tr.defaultShader;
+ }
+
+ numVerts = LittleLong(ds->numVerts);
+ if (numVerts > MAX_FACE_POINTS) {
+ ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numVerts);
+ numVerts = MAX_FACE_POINTS;
+ surf->shader = tr.defaultShader;
+ }
+
+ numIndexes = LittleLong(ds->numIndexes);
+
+ //cv = ri.Hunk_Alloc(sizeof(*cv), h_low);
+ cv = (srfBspSurface_t*)surf->data;
+ cv->surfaceType = SF_FACE;
+
+ cv->numIndexes = numIndexes;
+ cv->indexes = (glIndex_t*)ri.Hunk_Alloc(numIndexes * sizeof(cv->indexes[0]), h_low);
+
+ cv->numVerts = numVerts;
+ cv->verts = (srfVert_t*)ri.Hunk_Alloc(numVerts * sizeof(cv->verts[0]), h_low);
+
+ // copy vertexes
+ surf->cullinfo.type = CULLINFO_PLANE | CULLINFO_BOX;
+ ClearBounds(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]);
+ verts += LittleLong(ds->firstVert);
+ for(i = 0; i < numVerts; i++)
+ LoadDrawVertToSrfVert(&cv->verts[i], &verts[i], realLightmapNum, hdrVertColors ? hdrVertColors + (ds->firstVert + i) * 3 : NULL, surf->cullinfo.bounds);
+
+ // copy triangles
+ badTriangles = 0;
+ indexes += LittleLong(ds->firstIndex);
+ for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3)
+ {
+ for(j = 0; j < 3; j++)
+ {
+ tri[j] = LittleLong(indexes[i + j]);
+
+ if(tri[j] >= numVerts)
+ {
+ ri.Error(ERR_DROP, "Bad index in face surface");
+ }
+ }
+
+ if ((tri[0] == tri[1]) || (tri[1] == tri[2]) || (tri[0] == tri[2]))
+ {
+ tri -= 3;
+ badTriangles++;
+ }
+ }
+
+ if (badTriangles)
+ {
+ ri.Printf(PRINT_WARNING, "Face has bad triangles, originally shader %s %d tris %d verts, now %d tris\n", surf->shader->name, numIndexes / 3, numVerts, numIndexes / 3 - badTriangles);
+ cv->numIndexes -= badTriangles * 3;
+ }
+
+ // take the plane information from the lightmap vector
+ for ( i = 0 ; i < 3 ; i++ ) {
+ cv->cullPlane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
+ }
+ cv->cullPlane.dist = DotProduct( cv->verts[0].xyz, cv->cullPlane.normal );
+ SetPlaneSignbits( &cv->cullPlane );
+ cv->cullPlane.type = PlaneTypeForNormal( cv->cullPlane.normal );
+ surf->cullinfo.plane = cv->cullPlane;
+
+ surf->data = (surfaceType_t *)cv;
+
+ // Calculate tangent spaces
+ {
+ srfVert_t *dv[3];
+
+ for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3)
+ {
+ dv[0] = &cv->verts[tri[0]];
+ dv[1] = &cv->verts[tri[1]];
+ dv[2] = &cv->verts[tri[2]];
+
+ R_CalcTangentVectors(dv);
+ }
+ }
+}
+
+
+/*
+===============
+ParseMesh
+===============
+*/
+static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf ) {
+ srfBspSurface_t *grid = (srfBspSurface_t *)surf->data;
+ int i;
+ int width, height, numPoints;
+ srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE];
+ vec3_t bounds[2];
+ vec3_t tmpVec;
+ static surfaceType_t skipData = SF_SKIP;
+ int realLightmapNum;
+
+ realLightmapNum = LittleLong( ds->lightmapNum );
+
+ // get fog volume
+ surf->fogIndex = LittleLong( ds->fogNum ) + 1;
+
+ // get shader value
+ surf->shader = ShaderForShaderNum( ds->shaderNum, FatLightmap(realLightmapNum) );
+ if ( r_singleShader->integer && !surf->shader->isSky ) {
+ surf->shader = tr.defaultShader;
+ }
+
+ // we may have a nodraw surface, because they might still need to
+ // be around for movement clipping
+ if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) {
+ surf->data = &skipData;
+ return;
+ }
+
+ width = LittleLong( ds->patchWidth );
+ height = LittleLong( ds->patchHeight );
+
+ if(width < 0 || width > MAX_PATCH_SIZE || height < 0 || height > MAX_PATCH_SIZE)
+ ri.Error(ERR_DROP, "ParseMesh: bad size");
+
+ verts += LittleLong( ds->firstVert );
+ numPoints = width * height;
+ for(i = 0; i < numPoints; i++)
+ LoadDrawVertToSrfVert(&points[i], &verts[i], realLightmapNum, hdrVertColors ? hdrVertColors + (ds->firstVert + i) * 3 : NULL, NULL);
+
+ // pre-tesseleate
+ R_SubdividePatchToGrid( grid, width, height, points );
+
+ // copy the level of detail origin, which is the center
+ // of the group of all curves that must subdivide the same
+ // to avoid cracking
+ for ( i = 0 ; i < 3 ; i++ ) {
+ bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] );
+ bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] );
+ }
+ VectorAdd( bounds[0], bounds[1], bounds[1] );
+ VectorScale( bounds[1], 0.5f, grid->lodOrigin );
+ VectorSubtract( bounds[0], grid->lodOrigin, tmpVec );
+ grid->lodRadius = VectorLength( tmpVec );
+
+ surf->cullinfo.type = CULLINFO_BOX | CULLINFO_SPHERE;
+ VectorCopy(grid->cullBounds[0], surf->cullinfo.bounds[0]);
+ VectorCopy(grid->cullBounds[1], surf->cullinfo.bounds[1]);
+ VectorCopy(grid->cullOrigin, surf->cullinfo.localOrigin);
+ surf->cullinfo.radius = grid->cullRadius;
+}
+
+/*
+===============
+ParseTriSurf
+===============
+*/
+static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf, int *indexes ) {
+ srfBspSurface_t *cv;
+ glIndex_t *tri;
+ int i, j;
+ int numVerts, numIndexes, badTriangles;
+
+ // get fog volume
+ surf->fogIndex = LittleLong( ds->fogNum ) + 1;
+
+ // get shader
+ surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
+ if ( r_singleShader->integer && !surf->shader->isSky ) {
+ surf->shader = tr.defaultShader;
+ }
+
+ numVerts = LittleLong(ds->numVerts);
+ numIndexes = LittleLong(ds->numIndexes);
+
+ //cv = ri.Hunk_Alloc(sizeof(*cv), h_low);
+ cv = (srfBspSurface_t*)surf->data;
+ cv->surfaceType = SF_TRIANGLES;
+
+ cv->numIndexes = numIndexes;
+ cv->indexes = (glIndex_t*)ri.Hunk_Alloc(numIndexes * sizeof(cv->indexes[0]), h_low);
+
+ cv->numVerts = numVerts;
+ cv->verts = (srfVert_t*)ri.Hunk_Alloc(numVerts * sizeof(cv->verts[0]), h_low);
+
+ surf->data = (surfaceType_t *) cv;
+
+ // copy vertexes
+ surf->cullinfo.type = CULLINFO_BOX;
+ ClearBounds(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]);
+ verts += LittleLong(ds->firstVert);
+ for(i = 0; i < numVerts; i++)
+ LoadDrawVertToSrfVert(&cv->verts[i], &verts[i], -1, hdrVertColors ? hdrVertColors + (ds->firstVert + i) * 3 : NULL, surf->cullinfo.bounds);
+
+ // copy triangles
+ badTriangles = 0;
+ indexes += LittleLong(ds->firstIndex);
+ for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3)
+ {
+ for(j = 0; j < 3; j++)
+ {
+ tri[j] = LittleLong(indexes[i + j]);
+
+ if(tri[j] >= numVerts)
+ {
+ ri.Error(ERR_DROP, "Bad index in face surface");
+ }
+ }
+
+ if ((tri[0] == tri[1]) || (tri[1] == tri[2]) || (tri[0] == tri[2]))
+ {
+ tri -= 3;
+ badTriangles++;
+ }
+ }
+
+ if (badTriangles)
+ {
+ ri.Printf(PRINT_WARNING, "Trisurf has bad triangles, originally shader %s %d tris %d verts, now %d tris\n", surf->shader->name, numIndexes / 3, numVerts, numIndexes / 3 - badTriangles);
+ cv->numIndexes -= badTriangles * 3;
+ }
+
+ // Calculate tangent spaces
+ {
+ srfVert_t *dv[3];
+
+ for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3)
+ {
+ dv[0] = &cv->verts[tri[0]];
+ dv[1] = &cv->verts[tri[1]];
+ dv[2] = &cv->verts[tri[2]];
+
+ R_CalcTangentVectors(dv);
+ }
+ }
+}
+
+/*
+===============
+ParseFlare
+===============
+*/
+static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
+ srfFlare_t *flare;
+ int i;
+
+ // get fog volume
+ surf->fogIndex = LittleLong( ds->fogNum ) + 1;
+
+ // get shader
+ surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
+ if ( r_singleShader->integer && !surf->shader->isSky ) {
+ surf->shader = tr.defaultShader;
+ }
+
+ //flare = ri.Hunk_Alloc( sizeof( *flare ), h_low );
+ flare = (srfFlare_t*)surf->data;
+ flare->surfaceType = SF_FLARE;
+
+ surf->data = (surfaceType_t *)flare;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] );
+ flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] );
+ flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
+ }
+
+ surf->cullinfo.type = CULLINFO_NONE;
+}
+
+
+/*
+=================
+R_MergedWidthPoints
+
+returns true if there are grid points merged on a width edge
+=================
+*/
+int R_MergedWidthPoints(srfBspSurface_t *grid, int offset) {
+ int i, j;
+
+ for (i = 1; i < grid->width-1; i++) {
+ for (j = i + 1; j < grid->width-1; j++) {
+ if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue;
+ if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue;
+ if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue;
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+=================
+R_MergedHeightPoints
+
+returns true if there are grid points merged on a height edge
+=================
+*/
+int R_MergedHeightPoints(srfBspSurface_t *grid, int offset) {
+ int i, j;
+
+ for (i = 1; i < grid->height-1; i++) {
+ for (j = i + 1; j < grid->height-1; j++) {
+ if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue;
+ if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue;
+ if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue;
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+=================
+R_FixSharedVertexLodError_r
+
+NOTE: never sync LoD through grid edges with merged points!
+
+FIXME: write generalized version that also avoids cracks between a patch and one that meets half way?
+=================
+*/
+void R_FixSharedVertexLodError_r( int start, srfBspSurface_t *grid1 ) {
+ int j, k, l, m, n, offset1, offset2, touch;
+ srfBspSurface_t *grid2;
+
+ for ( j = start; j < s_worldData.numsurfaces; j++ ) {
+ //
+ grid2 = (srfBspSurface_t *) s_worldData.surfaces[j].data;
+ // if this surface is not a grid
+ if ( grid2->surfaceType != SF_GRID ) continue;
+ // if the LOD errors are already fixed for this patch
+ if ( grid2->lodFixed == 2 ) continue;
+ // grids in the same LOD group should have the exact same lod radius
+ if ( grid1->lodRadius != grid2->lodRadius ) continue;
+ // grids in the same LOD group should have the exact same lod origin
+ if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;
+ if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;
+ if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;
+ //
+ touch = false;
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = (grid1->height-1) * grid1->width;
+ else offset1 = 0;
+ if (R_MergedWidthPoints(grid1, offset1)) continue;
+ for (k = 1; k < grid1->width-1; k++) {
+ for (m = 0; m < 2; m++) {
+
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ if (R_MergedWidthPoints(grid2, offset2)) continue;
+ for ( l = 1; l < grid2->width-1; l++) {
+ //
+ if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
+ if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
+ if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
+ // ok the points are equal and should have the same lod error
+ grid2->widthLodError[l] = grid1->widthLodError[k];
+ touch = true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ if (R_MergedHeightPoints(grid2, offset2)) continue;
+ for ( l = 1; l < grid2->height-1; l++) {
+ //
+ if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
+ if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
+ if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
+ // ok the points are equal and should have the same lod error
+ grid2->heightLodError[l] = grid1->widthLodError[k];
+ touch = true;
+ }
+ }
+ }
+ }
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = grid1->width-1;
+ else offset1 = 0;
+ if (R_MergedHeightPoints(grid1, offset1)) continue;
+ for (k = 1; k < grid1->height-1; k++) {
+ for (m = 0; m < 2; m++) {
+
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ if (R_MergedWidthPoints(grid2, offset2)) continue;
+ for ( l = 1; l < grid2->width-1; l++) {
+ //
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
+ // ok the points are equal and should have the same lod error
+ grid2->widthLodError[l] = grid1->heightLodError[k];
+ touch = true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ if (R_MergedHeightPoints(grid2, offset2)) continue;
+ for ( l = 1; l < grid2->height-1; l++) {
+ //
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
+ if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
+ // ok the points are equal and should have the same lod error
+ grid2->heightLodError[l] = grid1->heightLodError[k];
+ touch = true;
+ }
+ }
+ }
+ }
+ if (touch) {
+ grid2->lodFixed = 2;
+ R_FixSharedVertexLodError_r ( start, grid2 );
+ //NOTE: this would be correct but makes things really slow
+ //grid2->lodFixed = 1;
+ }
+ }
+}
+
+/*
+=================
+R_FixSharedVertexLodError
+
+This function assumes that all patches in one group are nicely stitched together for the highest LoD.
+If this is not the case this function will still do its job but won't fix the highest LoD cracks.
+=================
+*/
+void R_FixSharedVertexLodError( void ) {
+ int i;
+ srfBspSurface_t *grid1;
+
+ for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
+ //
+ grid1 = (srfBspSurface_t *) s_worldData.surfaces[i].data;
+ // if this surface is not a grid
+ if ( grid1->surfaceType != SF_GRID )
+ continue;
+ //
+ if ( grid1->lodFixed )
+ continue;
+ //
+ grid1->lodFixed = 2;
+ // recursively fix other patches in the same LOD group
+ R_FixSharedVertexLodError_r( i + 1, grid1);
+ }
+}
+
+
+/*
+===============
+R_StitchPatches
+===============
+*/
+int R_StitchPatches( int grid1num, int grid2num ) {
+ float *v1, *v2;
+ srfBspSurface_t *grid1, *grid2;
+ int k, l, m, n, offset1, offset2, row, column;
+
+ grid1 = (srfBspSurface_t *) s_worldData.surfaces[grid1num].data;
+ grid2 = (srfBspSurface_t *) s_worldData.surfaces[grid2num].data;
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = (grid1->height-1) * grid1->width;
+ else offset1 = 0;
+ if (R_MergedWidthPoints(grid1, offset1))
+ continue;
+ for (k = 0; k < grid1->width-2; k += 2) {
+
+ for (m = 0; m < 2; m++) {
+
+ if ( grid2->width >= MAX_GRID_SIZE )
+ break;
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->width-1; l++) {
+ //
+ v1 = grid1->verts[k + offset1].xyz;
+ v2 = grid2->verts[l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[k + 2 + offset1].xyz;
+ v2 = grid2->verts[l + 1 + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[l + offset2].xyz;
+ v2 = grid2->verts[l + 1 + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert column into grid2 right after after column l
+ if (m) row = grid2->height-1;
+ else row = 0;
+ R_GridInsertColumn( grid2, l+1, row,
+ grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (grid2->height >= MAX_GRID_SIZE)
+ break;
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->height-1; l++) {
+ //
+ v1 = grid1->verts[k + offset1].xyz;
+ v2 = grid2->verts[grid2->width * l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[k + 2 + offset1].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[grid2->width * l + offset2].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert row into grid2 right after after row l
+ if (m) column = grid2->width-1;
+ else column = 0;
+ R_GridInsertRow( grid2, l+1, column,
+ grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ }
+ }
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = grid1->width-1;
+ else offset1 = 0;
+ if (R_MergedHeightPoints(grid1, offset1))
+ continue;
+ for (k = 0; k < grid1->height-2; k += 2) {
+ for (m = 0; m < 2; m++) {
+
+ if ( grid2->width >= MAX_GRID_SIZE )
+ break;
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->width-1; l++) {
+ //
+ v1 = grid1->verts[grid1->width * k + offset1].xyz;
+ v2 = grid2->verts[l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
+ v2 = grid2->verts[l + 1 + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[l + offset2].xyz;
+ v2 = grid2->verts[(l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert column into grid2 right after after column l
+ if (m) row = grid2->height-1;
+ else row = 0;
+ R_GridInsertColumn( grid2, l+1, row,
+ grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (grid2->height >= MAX_GRID_SIZE)
+ break;
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->height-1; l++) {
+ //
+ v1 = grid1->verts[grid1->width * k + offset1].xyz;
+ v2 = grid2->verts[grid2->width * l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[grid2->width * l + offset2].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert row into grid2 right after after row l
+ if (m) column = grid2->width-1;
+ else column = 0;
+ R_GridInsertRow( grid2, l+1, column,
+ grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ }
+ }
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = (grid1->height-1) * grid1->width;
+ else offset1 = 0;
+ if (R_MergedWidthPoints(grid1, offset1))
+ continue;
+ for (k = grid1->width-1; k > 1; k -= 2) {
+
+ for (m = 0; m < 2; m++) {
+
+ if ( !grid2 || grid2->width >= MAX_GRID_SIZE )
+ break;
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->width-1; l++) {
+ //
+ v1 = grid1->verts[k + offset1].xyz;
+ v2 = grid2->verts[l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[k - 2 + offset1].xyz;
+ v2 = grid2->verts[l + 1 + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[l + offset2].xyz;
+ v2 = grid2->verts[(l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert column into grid2 right after after column l
+ if (m) row = grid2->height-1;
+ else row = 0;
+ R_GridInsertColumn( grid2, l+1, row,
+ grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (!grid2 || grid2->height >= MAX_GRID_SIZE)
+ break;
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->height-1; l++) {
+ //
+ v1 = grid1->verts[k + offset1].xyz;
+ v2 = grid2->verts[grid2->width * l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[k - 2 + offset1].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[grid2->width * l + offset2].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert row into grid2 right after after row l
+ if (m) column = grid2->width-1;
+ else column = 0;
+ R_GridInsertRow( grid2, l+1, column,
+ grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);
+ if (!grid2)
+ break;
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ }
+ }
+ for (n = 0; n < 2; n++) {
+ //
+ if (n) offset1 = grid1->width-1;
+ else offset1 = 0;
+ if (R_MergedHeightPoints(grid1, offset1))
+ continue;
+ for (k = grid1->height-1; k > 1; k -= 2) {
+ for (m = 0; m < 2; m++) {
+
+ if (!grid2 || grid2->width >= MAX_GRID_SIZE )
+ break;
+ if (m) offset2 = (grid2->height-1) * grid2->width;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->width-1; l++) {
+ //
+ v1 = grid1->verts[grid1->width * k + offset1].xyz;
+ v2 = grid2->verts[l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
+ v2 = grid2->verts[l + 1 + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[l + offset2].xyz;
+ v2 = grid2->verts[(l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert column into grid2 right after after column l
+ if (m) row = grid2->height-1;
+ else row = 0;
+ R_GridInsertColumn( grid2, l+1, row,
+ grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ for (m = 0; m < 2; m++) {
+
+ if (!grid2 || grid2->height >= MAX_GRID_SIZE)
+ break;
+ if (m) offset2 = grid2->width-1;
+ else offset2 = 0;
+ for ( l = 0; l < grid2->height-1; l++) {
+ //
+ v1 = grid1->verts[grid1->width * k + offset1].xyz;
+ v2 = grid2->verts[grid2->width * l + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+
+ v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) > .1)
+ continue;
+ if ( fabs(v1[1] - v2[1]) > .1)
+ continue;
+ if ( fabs(v1[2] - v2[2]) > .1)
+ continue;
+ //
+ v1 = grid2->verts[grid2->width * l + offset2].xyz;
+ v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
+ if ( fabs(v1[0] - v2[0]) < .01 &&
+ fabs(v1[1] - v2[1]) < .01 &&
+ fabs(v1[2] - v2[2]) < .01)
+ continue;
+ //
+ //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
+ // insert row into grid2 right after after row l
+ if (m) column = grid2->width-1;
+ else column = 0;
+ R_GridInsertRow( grid2, l+1, column,
+ grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);
+ grid2->lodStitched = false;
+ s_worldData.surfaces[grid2num].data = (surfaceType_t*) grid2;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/*
+===============
+R_TryStitchPatch
+
+This function will try to stitch patches in the same LoD group together for the highest LoD.
+
+Only single missing vertice cracks will be fixed.
+
+Vertices will be joined at the patch side a crack is first found, at the other side
+of the patch (on the same row or column) the vertices will not be joined and cracks
+might still appear at that side.
+===============
+*/
+int R_TryStitchingPatch( int grid1num ) {
+ int j, numstitches;
+ srfBspSurface_t *grid1, *grid2;
+
+ numstitches = 0;
+ grid1 = (srfBspSurface_t *) s_worldData.surfaces[grid1num].data;
+ for ( j = 0; j < s_worldData.numsurfaces; j++ ) {
+ //
+ grid2 = (srfBspSurface_t *) s_worldData.surfaces[j].data;
+ // if this surface is not a grid
+ if ( grid2->surfaceType != SF_GRID ) continue;
+ // grids in the same LOD group should have the exact same lod radius
+ if ( grid1->lodRadius != grid2->lodRadius ) continue;
+ // grids in the same LOD group should have the exact same lod origin
+ if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;
+ if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;
+ if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;
+ //
+ while (R_StitchPatches(grid1num, j))
+ {
+ numstitches++;
+ }
+ }
+ return numstitches;
+}
+
+/*
+===============
+R_StitchAllPatches
+===============
+*/
+void R_StitchAllPatches( void ) {
+ int i, stitched, numstitches;
+ srfBspSurface_t *grid1;
+
+ numstitches = 0;
+ do
+ {
+ stitched = false;
+ for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
+ //
+ grid1 = (srfBspSurface_t *) s_worldData.surfaces[i].data;
+ // if this surface is not a grid
+ if ( grid1->surfaceType != SF_GRID )
+ continue;
+ //
+ if ( grid1->lodStitched )
+ continue;
+ //
+ grid1->lodStitched = true;
+ stitched = true;
+ //
+ numstitches += R_TryStitchingPatch( i );
+ }
+ }
+ while (stitched);
+ ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches );
+}
+
+/*
+===============
+R_MovePatchSurfacesToHunk
+===============
+*/
+void R_MovePatchSurfacesToHunk(void) {
+ int i;
+ srfBspSurface_t *grid;
+
+ for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
+ void *copyFrom;
+ //
+ grid = (srfBspSurface_t *) s_worldData.surfaces[i].data;
+ // if this surface is not a grid
+ if ( grid->surfaceType != SF_GRID )
+ continue;
+ //
+
+ copyFrom = grid->widthLodError;
+ grid->widthLodError = (float*)ri.Hunk_Alloc( grid->width * 4, h_low );
+ Com_Memcpy(grid->widthLodError, copyFrom, grid->width * 4);
+ ri.Free(copyFrom);
+
+ copyFrom = grid->heightLodError;
+ grid->heightLodError = (float*)ri.Hunk_Alloc(grid->height * 4, h_low);
+ Com_Memcpy(grid->heightLodError, copyFrom, grid->height * 4);
+ ri.Free(copyFrom);
+
+ copyFrom = grid->indexes;
+ grid->indexes = (glIndex_t*)ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low);
+ Com_Memcpy(grid->indexes, copyFrom, grid->numIndexes * sizeof(glIndex_t));
+ ri.Free(copyFrom);
+
+ copyFrom = grid->verts;
+ grid->verts = (srfVert_t*)ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low);
+ Com_Memcpy(grid->verts, copyFrom, grid->numVerts * sizeof(srfVert_t));
+ ri.Free(copyFrom);
+ }
+}
+
+
+/*
+===============
+R_LoadSurfaces
+===============
+*/
+static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) {
+ dsurface_t *in;
+ msurface_t *out;
+ drawVert_t *dv;
+ int *indexes;
+ int count;
+ int numFaces, numMeshes, numTriSurfs, numFlares;
+ int i;
+ float *hdrVertColors = NULL;
+
+ numFaces = 0;
+ numMeshes = 0;
+ numTriSurfs = 0;
+ numFlares = 0;
+
+ if (surfs->filelen % sizeof(*in))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ count = surfs->filelen / sizeof(*in);
+
+ dv = (drawVert_t*)(fileBase + verts->fileofs);
+ if (verts->filelen % sizeof(*dv))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+
+ indexes = (int*)(fileBase + indexLump->fileofs);
+ if ( indexLump->filelen % sizeof(*indexes))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+
+ out = (msurface_t*)ri.Hunk_Alloc ( count * sizeof(*out), h_low );
+
+ s_worldData.surfaces = out;
+ s_worldData.numsurfaces = count;
+ s_worldData.surfacesViewCount = (int*)ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesViewCount), h_low );
+ s_worldData.surfacesDlightBits = (int*)ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesDlightBits), h_low );
+ s_worldData.surfacesPshadowBits = (int*)ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesPshadowBits), h_low );
+
+ // load hdr vertex colors
+ if (r_hdr->integer)
+ {
+ char filename[MAX_QPATH];
+ int size;
+
+ Com_sprintf( filename, sizeof( filename ), "maps/%s/vertlight.raw", s_worldData.baseName);
+ //ri.Printf(PRINT_ALL, "looking for %s\n", filename);
+
+ size = ri.FS_ReadFile(filename, (void **)&hdrVertColors);
+
+ if (hdrVertColors)
+ {
+ //ri.Printf(PRINT_ALL, "Found!\n");
+ if (size != sizeof(float) * 3 * (verts->filelen / sizeof(*dv)))
+ ri.Error(ERR_DROP, "Bad size for %s (%i, expected %i)!", filename, size, (int)((sizeof(float)) * 3 * (verts->filelen / sizeof(*dv))));
+ }
+ }
+
+
+ // Two passes, allocate surfaces first, then load them full of data
+ // This ensures surfaces are close together to reduce L2 cache misses when using VAOs,
+ // which don't actually use the verts and indexes
+ in = (dsurface_t*)(fileBase + surfs->fileofs);
+ out = s_worldData.surfaces;
+ for ( i = 0 ; i < count ; i++, in++, out++ ) {
+ switch ( LittleLong( in->surfaceType ) ) {
+ case MST_PATCH:
+ out->data = (surfaceType_t*)ri.Hunk_Alloc( sizeof(srfBspSurface_t), h_low);
+ break;
+ case MST_TRIANGLE_SOUP:
+ out->data = (surfaceType_t*)ri.Hunk_Alloc( sizeof(srfBspSurface_t), h_low);
+ break;
+ case MST_PLANAR:
+ out->data = (surfaceType_t*)ri.Hunk_Alloc( sizeof(srfBspSurface_t), h_low);
+ break;
+ case MST_FLARE:
+ out->data = (surfaceType_t*)ri.Hunk_Alloc( sizeof(srfFlare_t), h_low);
+ break;
+ default:
+ break;
+ }
+ }
+
+ in = (dsurface_t*)(fileBase + surfs->fileofs);
+ out = s_worldData.surfaces;
+ for ( i = 0 ; i < count ; i++, in++, out++ ) {
+ switch ( LittleLong( in->surfaceType ) ) {
+ case MST_PATCH:
+ ParseMesh ( in, dv, hdrVertColors, out );
+ numMeshes++;
+ break;
+ case MST_TRIANGLE_SOUP:
+ ParseTriSurf( in, dv, hdrVertColors, out, indexes );
+ numTriSurfs++;
+ break;
+ case MST_PLANAR:
+ ParseFace( in, dv, hdrVertColors, out, indexes );
+ numFaces++;
+ break;
+ case MST_FLARE:
+ ParseFlare( in, dv, out, indexes );
+ numFlares++;
+ break;
+ default:
+ ri.Error( ERR_DROP, "Bad surfaceType" );
+ }
+ }
+
+ if (hdrVertColors)
+ {
+ ri.FS_FreeFile(hdrVertColors);
+ }
+
+#ifdef PATCH_STITCHING
+ R_StitchAllPatches();
+#endif
+
+ R_FixSharedVertexLodError();
+
+#ifdef PATCH_STITCHING
+ R_MovePatchSurfacesToHunk();
+#endif
+
+ ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n",
+ numFaces, numMeshes, numTriSurfs, numFlares );
+}
+
+
+
+/*
+=================
+R_LoadSubmodels
+=================
+*/
+static void R_LoadSubmodels( lump_t *l ) {
+ dmodel_t *in;
+ bmodel_t *out;
+ int i, j, count;
+
+ in = (dmodel_t*)(fileBase + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ count = l->filelen / sizeof(*in);
+
+ s_worldData.numBModels = count;
+ s_worldData.bmodels = out = (bmodel_t*)ri.Hunk_Alloc( count * sizeof(*out), h_low );
+
+ for ( i=0 ; i<count ; i++, in++, out++ ) {
+ model_t *model;
+
+ model = R_AllocModel();
+
+ assert( model != NULL ); // this should never happen
+ if ( model == NULL ) {
+ ri.Error(ERR_DROP, "R_LoadSubmodels: R_AllocModel() failed");
+ }
+
+ model->type = MOD_BRUSH;
+ model->bmodel = out;
+ Com_sprintf( model->name, sizeof( model->name ), "*%d", i );
+
+ for (j=0 ; j<3 ; j++) {
+ out->bounds[0][j] = LittleFloat (in->mins[j]);
+ out->bounds[1][j] = LittleFloat (in->maxs[j]);
+ }
+
+ out->firstSurface = LittleLong( in->firstSurface );
+ out->numSurfaces = LittleLong( in->numSurfaces );
+
+ if(i == 0)
+ {
+ // Add this for limiting VAO surface creation
+ s_worldData.numWorldSurfaces = out->numSurfaces;
+ }
+ }
+}
+
+
+
+//==================================================================
+
+/*
+=================
+R_SetParent
+=================
+*/
+static void R_SetParent (mnode_t *node, mnode_t *parent)
+{
+ node->parent = parent;
+ if (node->contents != -1)
+ return;
+ R_SetParent (node->children[0], node);
+ R_SetParent (node->children[1], node);
+}
+
+/*
+=================
+R_LoadNodesAndLeafs
+=================
+*/
+static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) {
+ int i, j, p;
+ dnode_t *in;
+ dleaf_t *inLeaf;
+ mnode_t *out;
+ int numNodes, numLeafs;
+
+ in = (dnode_t*)(fileBase + nodeLump->fileofs);
+ if (nodeLump->filelen % sizeof(dnode_t) ||
+ leafLump->filelen % sizeof(dleaf_t) ) {
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ }
+ numNodes = nodeLump->filelen / sizeof(dnode_t);
+ numLeafs = leafLump->filelen / sizeof(dleaf_t);
+
+ out = (mnode_t*)ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low);
+
+ s_worldData.nodes = out;
+ s_worldData.numnodes = numNodes + numLeafs;
+ s_worldData.numDecisionNodes = numNodes;
+
+ // load nodes
+ for ( i=0 ; i<numNodes; i++, in++, out++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ out->mins[j] = LittleLong (in->mins[j]);
+ out->maxs[j] = LittleLong (in->maxs[j]);
+ }
+
+ p = LittleLong(in->planeNum);
+ out->plane = s_worldData.planes + p;
+
+ out->contents = CONTENTS_NODE; // differentiate from leafs
+
+ for (j=0 ; j<2 ; j++)
+ {
+ p = LittleLong (in->children[j]);
+ if (p >= 0)
+ out->children[j] = s_worldData.nodes + p;
+ else
+ out->children[j] = s_worldData.nodes + numNodes + (-1 - p);
+ }
+ }
+
+ // load leafs
+ inLeaf = (dleaf_t*)(fileBase + leafLump->fileofs);
+ for ( i=0 ; i<numLeafs ; i++, inLeaf++, out++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ out->mins[j] = LittleLong (inLeaf->mins[j]);
+ out->maxs[j] = LittleLong (inLeaf->maxs[j]);
+ }
+
+ out->cluster = LittleLong(inLeaf->cluster);
+ out->area = LittleLong(inLeaf->area);
+
+ if ( out->cluster >= s_worldData.numClusters ) {
+ s_worldData.numClusters = out->cluster + 1;
+ }
+
+ out->firstmarksurface = LittleLong(inLeaf->firstLeafSurface);
+ out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces);
+ }
+
+ // chain decendants
+ R_SetParent (s_worldData.nodes, NULL);
+}
+
+//=============================================================================
+
+/*
+=================
+R_LoadShaders
+=================
+*/
+static void R_LoadShaders( lump_t *l ) {
+ int i, count;
+ dshader_t *in, *out;
+
+ in = (dshader_t*)(fileBase + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ count = l->filelen / sizeof(*in);
+ out = (dshader_t*)ri.Hunk_Alloc ( count*sizeof(*out), h_low );
+
+ s_worldData.shaders = out;
+ s_worldData.numShaders = count;
+
+ Com_Memcpy( out, in, count*sizeof(*out) );
+
+ for ( i=0 ; i<count ; i++ ) {
+ out[i].surfaceFlags = LittleLong( out[i].surfaceFlags );
+ out[i].contentFlags = LittleLong( out[i].contentFlags );
+ }
+}
+
+
+/*
+=================
+R_LoadMarksurfaces
+=================
+*/
+static void R_LoadMarksurfaces (lump_t *l)
+{
+ int i, j, count;
+ int *in;
+ int *out;
+
+ in = (int*)(fileBase + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ count = l->filelen / sizeof(*in);
+ out = (int*)ri.Hunk_Alloc ( count*sizeof(*out), h_low);
+
+ s_worldData.marksurfaces = out;
+ s_worldData.nummarksurfaces = count;
+
+ for ( i=0 ; i<count ; i++)
+ {
+ j = LittleLong(in[i]);
+ out[i] = j;
+ }
+}
+
+
+/*
+=================
+R_LoadPlanes
+=================
+*/
+static void R_LoadPlanes( lump_t *l ) {
+ int i, j;
+ cplane_t *out;
+ dplane_t *in;
+ int count;
+ int bits;
+
+ in = (dplane_t*)(fileBase + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ count = l->filelen / sizeof(*in);
+ out = (cplane_t*)ri.Hunk_Alloc ( count*2*sizeof(*out), h_low);
+
+ s_worldData.planes = out;
+ s_worldData.numplanes = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++) {
+ bits = 0;
+ for (j=0 ; j<3 ; j++) {
+ out->normal[j] = LittleFloat (in->normal[j]);
+ if (out->normal[j] < 0) {
+ bits |= 1<<j;
+ }
+ }
+
+ out->dist = LittleFloat (in->dist);
+ out->type = PlaneTypeForNormal( out->normal );
+ out->signbits = bits;
+ }
+}
+
+/*
+=================
+R_LoadFogs
+
+=================
+*/
+static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) {
+ int i;
+ fog_t *out;
+ dfog_t *fogs;
+ dbrush_t *brushes, *brush;
+ dbrushside_t *sides;
+ int count, brushesCount, sidesCount;
+ int sideNum;
+ int planeNum;
+ shader_t *shader;
+ float d;
+ int firstSide;
+
+ fogs = (dfog_t*)(fileBase + l->fileofs);
+ if (l->filelen % sizeof(*fogs)) {
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ }
+ count = l->filelen / sizeof(*fogs);
+
+ // create fog strucutres for them
+ s_worldData.numfogs = count + 1;
+ s_worldData.fogs = (fog_t*)ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low);
+ out = s_worldData.fogs + 1;
+
+ if ( !count ) {
+ return;
+ }
+
+ brushes = (dbrush_t*)(fileBase + brushesLump->fileofs);
+ if (brushesLump->filelen % sizeof(*brushes)) {
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ }
+ brushesCount = brushesLump->filelen / sizeof(*brushes);
+
+ sides = (dbrushside_t*)(fileBase + sidesLump->fileofs);
+ if (sidesLump->filelen % sizeof(*sides)) {
+ ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
+ }
+ sidesCount = sidesLump->filelen / sizeof(*sides);
+
+ for ( i=0 ; i<count ; i++, fogs++) {
+ out->originalBrushNumber = LittleLong( fogs->brushNum );
+
+ if ( (unsigned)out->originalBrushNumber >= brushesCount ) {
+ ri.Error( ERR_DROP, "fog brushNumber out of range" );
+ }
+ brush = brushes + out->originalBrushNumber;
+
+ firstSide = LittleLong( brush->firstSide );
+
+ if ( (unsigned)firstSide > sidesCount - 6 ) {
+ ri.Error( ERR_DROP, "fog brush sideNumber out of range" );
+ }
+
+ // brushes are always sorted with the axial sides first
+ sideNum = firstSide + 0;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist;
+
+ sideNum = firstSide + 1;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[1][0] = s_worldData.planes[ planeNum ].dist;
+
+ sideNum = firstSide + 2;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist;
+
+ sideNum = firstSide + 3;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[1][1] = s_worldData.planes[ planeNum ].dist;
+
+ sideNum = firstSide + 4;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist;
+
+ sideNum = firstSide + 5;
+ planeNum = LittleLong( sides[ sideNum ].planeNum );
+ out->bounds[1][2] = s_worldData.planes[ planeNum ].dist;
+
+ // get information from the shader for fog parameters
+ shader = R_FindShader( fogs->shader, LIGHTMAP_NONE, true );
+
+ out->parms = shader->fogParms;
+
+ out->colorInt = ColorBytes4 ( shader->fogParms.color[0],
+ shader->fogParms.color[1],
+ shader->fogParms.color[2], 1.0 );
+
+ d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque;
+ out->tcScale = 1.0f / ( d * 8 );
+
+ // set the gradient vector
+ sideNum = LittleLong( fogs->visibleSide );
+
+ if ( sideNum == -1 ) {
+ out->hasSurface = false;
+ } else {
+ out->hasSurface = true;
+ planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum );
+ VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface );
+ out->surface[3] = -s_worldData.planes[ planeNum ].dist;
+ }
+
+ out++;
+ }
+
+}
+
+
+/*
+================
+R_LoadLightGrid
+
+================
+*/
+void R_LoadLightGrid( lump_t *l ) {
+ int i;
+ vec3_t maxs;
+ int numGridPoints;
+ world_t *w;
+ float *wMins, *wMaxs;
+
+ w = &s_worldData;
+
+ w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0];
+ w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1];
+ w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2];
+
+ wMins = w->bmodels[0].bounds[0];
+ wMaxs = w->bmodels[0].bounds[1];
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ w->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] );
+ maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] );
+ w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1;
+ }
+
+ numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2];
+
+ if ( l->filelen != numGridPoints * 8 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: light grid mismatch\n" );
+ w->lightGridData = NULL;
+ return;
+ }
+
+ w->lightGridData = (byte*)ri.Hunk_Alloc( l->filelen, h_low );
+ Com_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen );
+
+ // deal with overbright bits
+ for ( i = 0 ; i < numGridPoints ; i++ ) {
+ R_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] );
+ R_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] );
+ }
+
+ // load hdr lightgrid
+ if (r_hdr->integer)
+ {
+ char filename[MAX_QPATH];
+ float *hdrLightGrid;
+ int size;
+
+ Com_sprintf( filename, sizeof( filename ), "maps/%s/lightgrid.raw", s_worldData.baseName);
+ //ri.Printf(PRINT_ALL, "looking for %s\n", filename);
+
+ size = ri.FS_ReadFile(filename, (void **)&hdrLightGrid);
+
+ if (hdrLightGrid)
+ {
+ //ri.Printf(PRINT_ALL, "found!\n");
+
+ if (size != sizeof(float) * 6 * numGridPoints)
+ ri.Error(ERR_DROP, "Bad size for %s (%i, expected %i)!", filename, size, (int)(sizeof(float)) * 6 * numGridPoints);
+
+ w->lightGrid16 = (uint16_t*)ri.Hunk_Alloc(sizeof(w->lightGrid16) * 6 * numGridPoints, h_low);
+
+ for (i = 0; i < numGridPoints ; i++)
+ {
+ vec4_t c;
+
+ c[0] = hdrLightGrid[i * 6];
+ c[1] = hdrLightGrid[i * 6 + 1];
+ c[2] = hdrLightGrid[i * 6 + 2];
+ c[3] = 1.0f;
+
+ R_ColorShiftLightingFloats(c, c);
+ ColorToRGB16(c, &w->lightGrid16[i * 6]);
+
+ c[0] = hdrLightGrid[i * 6 + 3];
+ c[1] = hdrLightGrid[i * 6 + 4];
+ c[2] = hdrLightGrid[i * 6 + 5];
+ c[3] = 1.0f;
+
+ R_ColorShiftLightingFloats(c, c);
+ ColorToRGB16(c, &w->lightGrid16[i * 6 + 3]);
+ }
+ }
+ else if (0)
+ {
+ // promote 8-bit lightgrid to 16-bit
+ w->lightGrid16 = (uint16_t*)ri.Hunk_Alloc(sizeof(w->lightGrid16) * 6 * numGridPoints, h_low);
+
+ for (i = 0; i < numGridPoints; i++)
+ {
+ w->lightGrid16[i * 6] = w->lightGridData[i * 8] * 257;
+ w->lightGrid16[i * 6 + 1] = w->lightGridData[i * 8 + 1] * 257;
+ w->lightGrid16[i * 6 + 2] = w->lightGridData[i * 8 + 2] * 257;
+ w->lightGrid16[i * 6 + 3] = w->lightGridData[i * 8 + 3] * 257;
+ w->lightGrid16[i * 6 + 4] = w->lightGridData[i * 8 + 4] * 257;
+ w->lightGrid16[i * 6 + 5] = w->lightGridData[i * 8 + 5] * 257;
+ }
+ }
+
+ if (hdrLightGrid)
+ ri.FS_FreeFile(hdrLightGrid);
+ }
+}
+
+/*
+================
+R_LoadEntities
+================
+*/
+void R_LoadEntities( lump_t *l ) {
+ char *p, *token;
+ char *s;
+ char keyname[MAX_TOKEN_CHARS];
+ char value[MAX_TOKEN_CHARS];
+ world_t *w;
+
+ w = &s_worldData;
+ w->lightGridSize[0] = 64;
+ w->lightGridSize[1] = 64;
+ w->lightGridSize[2] = 128;
+
+ p = (char *)(fileBase + l->fileofs);
+
+ // store for reference by the cgame
+ w->entityString = (char*)ri.Hunk_Alloc( l->filelen + 1, h_low );
+ strcpy( w->entityString, p );
+ w->entityParsePoint = w->entityString;
+
+ token = COM_ParseExt( &p, qtrue );
+ if (!*token || *token != '{') {
+ return;
+ }
+
+ // only parse the world spawn
+ while ( 1 ) {
+ // parse key
+ token = COM_ParseExt( &p, qtrue );
+
+ if ( !*token || *token == '}' ) {
+ break;
+ }
+ Q_strncpyz(keyname, token, sizeof(keyname));
+
+ // parse value
+ token = COM_ParseExt( &p, qtrue );
+
+ if ( !*token || *token == '}' ) {
+ break;
+ }
+ Q_strncpyz(value, token, sizeof(value));
+
+ // check for remapping of shaders for vertex lighting
+ if (!Q_strncmp(keyname, "vertexremapshader", strlen("vertexremapshader")) ) {
+ s = strchr(value, ';');
+ if (!s) {
+ ri.Printf( PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value );
+ break;
+ }
+ *s++ = 0;
+ if (r_vertexLight->integer) {
+ R_RemapShader(value, s, "0");
+ }
+ continue;
+ }
+ // check for remapping of shaders
+ if (!Q_strncmp(keyname, "remapshader", strlen("remapshader")) ) {
+ s = strchr(value, ';');
+ if (!s) {
+ ri.Printf( PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value );
+ break;
+ }
+ *s++ = 0;
+ R_RemapShader(value, s, "0");
+ continue;
+ }
+ // check for a different grid size
+ if (!Q_stricmp(keyname, "gridsize")) {
+ sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] );
+ continue;
+ }
+
+ // check for auto exposure
+ if (!Q_stricmp(keyname, "autoExposureMinMax")) {
+ sscanf(value, "%f %f", &tr.autoExposureMinMax[0], &tr.autoExposureMinMax[1]);
+ continue;
+ }
+ }
+}
+
+/*
+=================
+R_GetEntityToken
+=================
+*/
+bool R_GetEntityToken( char *buffer, int size ) {
+ const char *s;
+
+ s = COM_Parse( &s_worldData.entityParsePoint );
+ Q_strncpyz( buffer, s, size );
+ if ( !s_worldData.entityParsePoint && !s[0] ) {
+ s_worldData.entityParsePoint = s_worldData.entityString;
+ return false;
+ } else {
+ return true;
+ }
+}
+
+#ifndef MAX_SPAWN_VARS
+#define MAX_SPAWN_VARS 64
+#endif
+
+// derived from G_ParseSpawnVars() in g_spawn.c
+bool R_ParseSpawnVars( char *spawnVarChars, int maxSpawnVarChars, int *numSpawnVars, char *spawnVars[MAX_SPAWN_VARS][2] )
+{
+ char keyname[MAX_TOKEN_CHARS];
+ char com_token[MAX_TOKEN_CHARS];
+ int numSpawnVarChars = 0;
+
+ *numSpawnVars = 0;
+
+ // parse the opening brace
+ if ( !R_GetEntityToken( com_token, sizeof( com_token ) ) ) {
+ // end of spawn string
+ return false;
+ }
+ if ( com_token[0] != '{' ) {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: found %s when expecting {\n",com_token );
+ return false;
+ }
+
+ // go through all the key / value pairs
+ while ( 1 ) {
+ int keyLength, tokenLength;
+
+ // parse key
+ if ( !R_GetEntityToken( keyname, sizeof( keyname ) ) ) {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: EOF without closing brace\n" );
+ return false;
+ }
+
+ if ( keyname[0] == '}' ) {
+ break;
+ }
+
+ // parse value
+ if ( !R_GetEntityToken( com_token, sizeof( com_token ) ) ) {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: EOF without closing brace\n" );
+ return false;
+ }
+
+ if ( com_token[0] == '}' ) {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: closing brace without data\n" );
+ return false;
+ }
+
+ if ( *numSpawnVars == MAX_SPAWN_VARS ) {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: MAX_SPAWN_VARS\n" );
+ return false;
+ }
+
+ keyLength = strlen(keyname) + 1;
+ tokenLength = strlen(com_token) + 1;
+
+ if (numSpawnVarChars + keyLength + tokenLength > maxSpawnVarChars)
+ {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: MAX_SPAWN_VAR_CHARS\n" );
+ return false;
+ }
+
+ strcpy(spawnVarChars + numSpawnVarChars, keyname);
+ spawnVars[ *numSpawnVars ][0] = spawnVarChars + numSpawnVarChars;
+ numSpawnVarChars += keyLength;
+
+ strcpy(spawnVarChars + numSpawnVarChars, com_token);
+ spawnVars[ *numSpawnVars ][1] = spawnVarChars + numSpawnVarChars;
+ numSpawnVarChars += tokenLength;
+
+ (*numSpawnVars)++;
+ }
+
+ return true;
+}
+
+void R_LoadEnvironmentJson(const char *baseName)
+{
+ char filename[MAX_QPATH];
+
+ union {
+ char *c;
+ void *v;
+ } buffer;
+ char *bufferEnd;
+
+ const char *cubemapArrayJson;
+ int filelen, i;
+
+ Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/env.json", baseName);
+
+ filelen = ri.FS_ReadFile(filename, &buffer.v);
+ if (!buffer.c)
+ return;
+ bufferEnd = buffer.c + filelen;
+
+ if (JSON_ValueGetType(buffer.c, bufferEnd) != JSONTYPE_OBJECT)
+ {
+ ri.Printf(PRINT_ALL, "Bad %s: does not start with a object\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ cubemapArrayJson = JSON_ObjectGetNamedValue(buffer.c, bufferEnd, "Cubemaps");
+ if (!cubemapArrayJson)
+ {
+ ri.Printf(PRINT_ALL, "Bad %s: no Cubemaps\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ if (JSON_ValueGetType(cubemapArrayJson, bufferEnd) != JSONTYPE_ARRAY)
+ {
+ ri.Printf(PRINT_ALL, "Bad %s: Cubemaps not an array\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ tr.numCubemaps = JSON_ArrayGetIndex(cubemapArrayJson, bufferEnd, NULL, 0);
+ tr.cubemaps = (cubemap_t*)ri.Hunk_Alloc(tr.numCubemaps * sizeof(*tr.cubemaps), h_low);
+ memset(tr.cubemaps, 0, tr.numCubemaps * sizeof(*tr.cubemaps));
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ cubemap_t *cubemap = &tr.cubemaps[i];
+ const char *cubemapJson, *keyValueJson, *indexes[3];
+ int j;
+
+ cubemapJson = JSON_ArrayGetValue(cubemapArrayJson, bufferEnd, i);
+
+ keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Name");
+ if (!JSON_ValueGetString(keyValueJson, bufferEnd, cubemap->name, MAX_QPATH))
+ cubemap->name[0] = '\0';
+
+ keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Position");
+ JSON_ArrayGetIndex(keyValueJson, bufferEnd, indexes, 3);
+ for (j = 0; j < 3; j++)
+ cubemap->origin[j] = JSON_ValueGetFloat(indexes[j], bufferEnd);
+
+ cubemap->parallaxRadius = 1000.0f;
+ keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Radius");
+ if (keyValueJson)
+ cubemap->parallaxRadius = JSON_ValueGetFloat(keyValueJson, bufferEnd);
+ }
+
+ ri.FS_FreeFile(buffer.v);
+}
+
+void R_LoadCubemapEntities(const char *cubemapEntityName)
+{
+ char spawnVarChars[2048];
+ int numSpawnVars;
+ char *spawnVars[MAX_SPAWN_VARS][2];
+ int numCubemaps = 0;
+
+ // count cubemaps
+ numCubemaps = 0;
+ while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars))
+ {
+ int i;
+
+ for (i = 0; i < numSpawnVars; i++)
+ {
+ if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName))
+ numCubemaps++;
+ }
+ }
+
+ if (!numCubemaps)
+ return;
+
+ tr.numCubemaps = numCubemaps;
+ tr.cubemaps = (cubemap_t*)ri.Hunk_Alloc(tr.numCubemaps * sizeof(*tr.cubemaps), h_low);
+ memset(tr.cubemaps, 0, tr.numCubemaps * sizeof(*tr.cubemaps));
+
+ numCubemaps = 0;
+ while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars))
+ {
+ int i;
+ char name[MAX_QPATH];
+ bool isCubemap = false;
+ bool originSet = false;
+ vec3_t origin;
+ float parallaxRadius = 1000.0f;
+
+ name[0] = '\0';
+ for (i = 0; i < numSpawnVars; i++)
+ {
+ if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName))
+ isCubemap = true;
+
+ if (!Q_stricmp(spawnVars[i][0], "name"))
+ Q_strncpyz(name, spawnVars[i][1], MAX_QPATH);
+
+ if (!Q_stricmp(spawnVars[i][0], "origin"))
+ {
+ sscanf(spawnVars[i][1], "%f %f %f", &origin[0], &origin[1], &origin[2]);
+ originSet = true;
+ }
+ else if (!Q_stricmp(spawnVars[i][0], "radius"))
+ {
+ sscanf(spawnVars[i][1], "%f", &parallaxRadius);
+ }
+ }
+
+ if (isCubemap && originSet)
+ {
+ cubemap_t *cubemap = &tr.cubemaps[numCubemaps];
+ Q_strncpyz(cubemap->name, name, MAX_QPATH);
+ VectorCopy(origin, cubemap->origin);
+ cubemap->parallaxRadius = parallaxRadius;
+ numCubemaps++;
+ }
+ }
+}
+
+void R_AssignCubemapsToWorldSurfaces(void)
+{
+ world_t *w;
+ int i;
+
+ w = &s_worldData;
+
+ for (i = 0; i < w->numsurfaces; i++)
+ {
+ msurface_t *surf = &w->surfaces[i];
+ vec3_t surfOrigin;
+
+ if (surf->cullinfo.type & CULLINFO_SPHERE)
+ {
+ VectorCopy(surf->cullinfo.localOrigin, surfOrigin);
+ }
+ else if (surf->cullinfo.type & CULLINFO_BOX)
+ {
+ surfOrigin[0] = (surf->cullinfo.bounds[0][0] + surf->cullinfo.bounds[1][0]) * 0.5f;
+ surfOrigin[1] = (surf->cullinfo.bounds[0][1] + surf->cullinfo.bounds[1][1]) * 0.5f;
+ surfOrigin[2] = (surf->cullinfo.bounds[0][2] + surf->cullinfo.bounds[1][2]) * 0.5f;
+ }
+ else
+ {
+ //ri.Printf(PRINT_ALL, "surface %d has no cubemap\n", i);
+ continue;
+ }
+
+ surf->cubemapIndex = R_CubemapForPoint(surfOrigin);
+ //ri.Printf(PRINT_ALL, "surface %d has cubemap %d\n", i, surf->cubemapIndex);
+ }
+}
+
+
+void R_LoadCubemaps(void)
+{
+ int i;
+ int/*imgFlags_t*/ flags = IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_NOLIGHTSCALE | IMGFLAG_CUBEMAP;
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ char filename[MAX_QPATH];
+ cubemap_t *cubemap = &tr.cubemaps[i];
+
+ Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/%03d.dds", tr.world->baseName, i);
+
+ cubemap->image = R_FindImageFile(filename, IMGTYPE_COLORALPHA, flags);
+ }
+}
+
+
+void R_RenderMissingCubemaps(void)
+{
+ int i, j;
+ int/*imgFlags_t*/ flags = IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_NOLIGHTSCALE | IMGFLAG_CUBEMAP;
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ if (!tr.cubemaps[i].image)
+ {
+ tr.cubemaps[i].image = R_CreateImage(va("*cubeMap%d", i), NULL,
+ r_cubemapSize->integer, r_cubemapSize->integer,
+ IMGTYPE_COLORALPHA, flags, GL_RGBA8);
+
+ for (j = 0; j < 6; j++)
+ {
+ RE_ClearScene();
+ R_RenderCubemapSide(i, j, false);
+ R_IssuePendingRenderCommands();
+ R_InitNextFrame();
+ }
+ }
+ }
+}
+
+
+void R_CalcVertexLightDirs( void )
+{
+ int i, k;
+ msurface_t *surface;
+
+ for(k = 0, surface = &s_worldData.surfaces[0]; k < s_worldData.numsurfaces /* s_worldData.numWorldSurfaces */; k++, surface++)
+ {
+ srfBspSurface_t *bspSurf = (srfBspSurface_t *) surface->data;
+
+ switch(bspSurf->surfaceType)
+ {
+ case SF_FACE:
+ case SF_GRID:
+ case SF_TRIANGLES:
+ for(i = 0; i < bspSurf->numVerts; i++)
+ {
+ vec3_t lightDir;
+ vec3_t normal;
+
+ R_VaoUnpackNormal(normal, bspSurf->verts[i].normal);
+ R_LightDirForPoint( bspSurf->verts[i].xyz, lightDir, normal, &s_worldData );
+ R_VaoPackNormal(bspSurf->verts[i].lightdir, lightDir);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+
+/*
+=================
+RE_LoadWorldMap
+
+Called directly from cgame
+=================
+*/
+void RE_LoadWorldMap( const char *name ) {
+ int i;
+ dheader_t *header;
+ union {
+ byte *b;
+ void *v;
+ } buffer;
+ byte *startMarker;
+
+ if ( tr.worldMapLoaded ) {
+ ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map" );
+ }
+
+ // set default map light scale
+ tr.sunShadowScale = 0.5f;
+
+ // set default sun direction to be used if it isn't
+ // overridden by a shader
+ tr.sunDirection[0] = 0.45f;
+ tr.sunDirection[1] = 0.3f;
+ tr.sunDirection[2] = 0.9f;
+
+ VectorNormalize( tr.sunDirection );
+
+ // set default autoexposure settings
+ tr.autoExposureMinMax[0] = -2.0f;
+ tr.autoExposureMinMax[1] = 2.0f;
+
+ // set default tone mapping settings
+ tr.toneMinAvgMaxLevel[0] = -8.0f;
+ tr.toneMinAvgMaxLevel[1] = -2.0f;
+ tr.toneMinAvgMaxLevel[2] = 0.0f;
+
+ // reset last cascade sun direction so last shadow cascade is rerendered
+ VectorClear(tr.lastCascadeSunDirection);
+
+ tr.worldMapLoaded = true;
+
+ // load it
+ ri.FS_ReadFile( name, &buffer.v );
+ if ( !buffer.b ) {
+ ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name);
+ }
+
+ // clear tr.world so if the level fails to load, the next
+ // try will not look at the partially loaded version
+ tr.world = NULL;
+
+ Com_Memset( &s_worldData, 0, sizeof( s_worldData ) );
+ Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) );
+
+ Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) );
+ COM_StripExtension(s_worldData.baseName, s_worldData.baseName, sizeof(s_worldData.baseName));
+
+ startMarker = (byte*)ri.Hunk_Alloc(0, h_low);
+ c_gridVerts = 0;
+
+ header = (dheader_t *)buffer.b;
+ fileBase = (byte *)header;
+
+ i = LittleLong (header->version);
+ if ( i != BSP_VERSION ) {
+ ri.Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)",
+ name, i, BSP_VERSION);
+ }
+
+ // swap all the lumps
+ for (i=0 ; i<sizeof(dheader_t)/4 ; i++) {
+ ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
+ }
+
+ // load into heap
+ R_LoadEntities( &header->lumps[LUMP_ENTITIES] );
+ R_LoadShaders( &header->lumps[LUMP_SHADERS] );
+ R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS], &header->lumps[LUMP_SURFACES] );
+ R_LoadPlanes (&header->lumps[LUMP_PLANES]);
+ R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] );
+ R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] );
+ R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]);
+ R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]);
+ R_LoadSubmodels (&header->lumps[LUMP_MODELS]);
+ R_LoadVisibility( &header->lumps[LUMP_VISIBILITY] );
+ R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] );
+
+ // determine vertex light directions
+ R_CalcVertexLightDirs();
+
+ // determine which parts of the map are in sunlight
+ if (0)
+ {
+ world_t *w;
+ uint8_t *primaryLightGrid, *data;
+ int lightGridSize;
+ int i;
+
+ w = &s_worldData;
+
+ lightGridSize = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2];
+ primaryLightGrid = (uint8_t*)ri.Malloc(lightGridSize * sizeof(*primaryLightGrid));
+
+ memset(primaryLightGrid, 0, lightGridSize * sizeof(*primaryLightGrid));
+
+ data = w->lightGridData;
+ for (i = 0; i < lightGridSize; i++, data += 8)
+ {
+ int lat, lng;
+ vec3_t gridLightDir, gridLightCol;
+
+ // skip samples in wall
+ if (!(data[0]+data[1]+data[2]+data[3]+data[4]+data[5]) )
+ continue;
+
+ gridLightCol[0] = ByteToFloat(data[3]);
+ gridLightCol[1] = ByteToFloat(data[4]);
+ gridLightCol[2] = ByteToFloat(data[5]);
+ (void)gridLightCol; // Suppress unused-but-set-variable warning
+
+ lat = data[7];
+ lng = data[6];
+ lat *= (FUNCTABLE_SIZE/256);
+ lng *= (FUNCTABLE_SIZE/256);
+
+ // decode X as cos( lat ) * sin( long )
+ // decode Y as sin( lat ) * sin( long )
+ // decode Z as cos( long )
+
+ gridLightDir[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+ gridLightDir[1] = tr.sinTable[lat] * tr.sinTable[lng];
+ gridLightDir[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+
+ // FIXME: magic number for determining if light direction is close enough to sunlight
+ if (DotProduct(gridLightDir, tr.sunDirection) > 0.75f)
+ {
+ primaryLightGrid[i] = 1;
+ }
+ else
+ {
+ primaryLightGrid[i] = 255;
+ }
+ }
+
+ if (0)
+ {
+ int i;
+ byte *buffer = (byte*)ri.Malloc(w->lightGridBounds[0] * w->lightGridBounds[1] * 3 + 18);
+ byte *out;
+ uint8_t *in;
+ char fileName[MAX_QPATH];
+
+ Com_Memset (buffer, 0, 18);
+ buffer[2] = 2; // uncompressed type
+ buffer[12] = w->lightGridBounds[0] & 255;
+ buffer[13] = w->lightGridBounds[0] >> 8;
+ buffer[14] = w->lightGridBounds[1] & 255;
+ buffer[15] = w->lightGridBounds[1] >> 8;
+ buffer[16] = 24; // pixel size
+
+ in = primaryLightGrid;
+ for (i = 0; i < w->lightGridBounds[2]; i++)
+ {
+ int j;
+
+ sprintf(fileName, "primarylg%d.tga", i);
+
+ out = buffer + 18;
+ for (j = 0; j < w->lightGridBounds[0] * w->lightGridBounds[1]; j++)
+ {
+ if (*in == 1)
+ {
+ *out++ = 255;
+ *out++ = 255;
+ *out++ = 255;
+ }
+ else if (*in == 255)
+ {
+ *out++ = 64;
+ *out++ = 64;
+ *out++ = 64;
+ }
+ else
+ {
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ }
+ in++;
+ }
+
+ ri.FS_WriteFile(fileName, buffer, w->lightGridBounds[0] * w->lightGridBounds[1] * 3 + 18);
+ }
+
+ ri.Free(buffer);
+ }
+
+ for (i = 0; i < w->numWorldSurfaces; i++)
+ {
+ msurface_t *surf = w->surfaces + i;
+ cullinfo_t *ci = &surf->cullinfo;
+
+ if(ci->type & CULLINFO_PLANE)
+ {
+ if (DotProduct(ci->plane.normal, tr.sunDirection) <= 0.0f)
+ {
+ //ri.Printf(PRINT_ALL, "surface %d is not oriented towards sunlight\n", i);
+ continue;
+ }
+ }
+
+ if(ci->type & CULLINFO_BOX)
+ {
+ int ibounds[2][3], x, y, z, goodSamples, numSamples;
+ vec3_t lightOrigin;
+
+ VectorSubtract( ci->bounds[0], w->lightGridOrigin, lightOrigin );
+
+ ibounds[0][0] = floor(lightOrigin[0] * w->lightGridInverseSize[0]);
+ ibounds[0][1] = floor(lightOrigin[1] * w->lightGridInverseSize[1]);
+ ibounds[0][2] = floor(lightOrigin[2] * w->lightGridInverseSize[2]);
+
+ VectorSubtract( ci->bounds[1], w->lightGridOrigin, lightOrigin );
+
+ ibounds[1][0] = ceil(lightOrigin[0] * w->lightGridInverseSize[0]);
+ ibounds[1][1] = ceil(lightOrigin[1] * w->lightGridInverseSize[1]);
+ ibounds[1][2] = ceil(lightOrigin[2] * w->lightGridInverseSize[2]);
+
+ ibounds[0][0] = CLAMP(ibounds[0][0], 0, w->lightGridSize[0]);
+ ibounds[0][1] = CLAMP(ibounds[0][1], 0, w->lightGridSize[1]);
+ ibounds[0][2] = CLAMP(ibounds[0][2], 0, w->lightGridSize[2]);
+
+ ibounds[1][0] = CLAMP(ibounds[1][0], 0, w->lightGridSize[0]);
+ ibounds[1][1] = CLAMP(ibounds[1][1], 0, w->lightGridSize[1]);
+ ibounds[1][2] = CLAMP(ibounds[1][2], 0, w->lightGridSize[2]);
+
+ /*
+ ri.Printf(PRINT_ALL, "surf %d bounds (%f %f %f)-(%f %f %f) ibounds (%d %d %d)-(%d %d %d)\n", i,
+ ci->bounds[0][0], ci->bounds[0][1], ci->bounds[0][2],
+ ci->bounds[1][0], ci->bounds[1][1], ci->bounds[1][2],
+ ibounds[0][0], ibounds[0][1], ibounds[0][2],
+ ibounds[1][0], ibounds[1][1], ibounds[1][2]);
+ */
+
+ goodSamples = 0;
+ numSamples = 0;
+ for (x = ibounds[0][0]; x <= ibounds[1][0]; x++)
+ {
+ for (y = ibounds[0][1]; y <= ibounds[1][1]; y++)
+ {
+ for (z = ibounds[0][2]; z <= ibounds[1][2]; z++)
+ {
+ uint8_t primaryLight = primaryLightGrid[x * 8 + y * 8 * w->lightGridBounds[0] + z * 8 * w->lightGridBounds[0] * w->lightGridBounds[2]];
+
+ if (primaryLight == 0)
+ continue;
+
+ numSamples++;
+
+ if (primaryLight == 1)
+ goodSamples++;
+ }
+ }
+ }
+
+ // FIXME: magic number for determining whether object is mostly in sunlight
+ if (goodSamples > numSamples * 0.75f)
+ {
+ //ri.Printf(PRINT_ALL, "surface %d is in sunlight\n", i);
+ //surf->primaryLight = 1;
+ }
+ }
+ }
+
+ ri.Free(primaryLightGrid);
+ }
+
+ // load cubemaps
+ if (r_cubeMapping->integer)
+ {
+ // Try loading an env.json file first
+ R_LoadEnvironmentJson(s_worldData.baseName);
+
+ if (!tr.numCubemaps)
+ {
+ R_LoadCubemapEntities("misc_cubemap");
+ }
+
+ if (!tr.numCubemaps)
+ {
+ // location names are an assured way to get an even distribution
+ R_LoadCubemapEntities("target_location");
+ }
+
+ if (!tr.numCubemaps)
+ {
+ // try misc_models
+ R_LoadCubemapEntities("misc_model");
+ }
+
+ if (tr.numCubemaps)
+ {
+ R_AssignCubemapsToWorldSurfaces();
+ }
+ }
+
+ s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker;
+
+ // only set tr.world now that we know the entire level has loaded properly
+ tr.world = &s_worldData;
+
+ // make sure the VAO glState entry is safe
+ R_BindNullVao();
+
+ // Render or load all cubemaps
+ if (r_cubeMapping->integer && tr.numCubemaps && glRefConfig.framebufferObject)
+ {
+ R_LoadCubemaps();
+ R_RenderMissingCubemaps();
+ }
+
+ ri.FS_FreeFile( buffer.v );
+}
diff --git a/src/renderergl2/tr_cmds.cpp b/src/renderergl2/tr_cmds.cpp
new file mode 100644
index 0000000..d7eecd2
--- /dev/null
+++ b/src/renderergl2/tr_cmds.cpp
@@ -0,0 +1,672 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "tr_local.h"
+
+/*
+=====================
+R_PerformanceCounters
+=====================
+*/
+void R_PerformanceCounters( void ) {
+ if ( !r_speeds->integer ) {
+ // clear the counters even if we aren't printing
+ Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
+ Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
+ return;
+ }
+
+ if (r_speeds->integer == 1) {
+ ri.Printf (PRINT_ALL, "%i/%i/%i shaders/batches/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n",
+ backEnd.pc.c_shaders, backEnd.pc.c_surfBatches, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes,
+ backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3,
+ R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) );
+ } else if (r_speeds->integer == 2) {
+ ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
+ tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out,
+ tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out );
+ ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
+ tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out,
+ tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out );
+ } else if (r_speeds->integer == 3) {
+ ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster );
+ } else if (r_speeds->integer == 4) {
+ if ( backEnd.pc.c_dlightVertexes ) {
+ ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n",
+ tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled,
+ backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 );
+ }
+ }
+ else if (r_speeds->integer == 5 )
+ {
+ ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar );
+ }
+ else if (r_speeds->integer == 6 )
+ {
+ ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n",
+ backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders );
+ }
+ else if (r_speeds->integer == 7 )
+ {
+ ri.Printf( PRINT_ALL, "VAO draws: static %i dynamic %i\n",
+ backEnd.pc.c_staticVaoDraws, backEnd.pc.c_dynamicVaoDraws);
+ ri.Printf( PRINT_ALL, "GLSL binds: %i draws: gen %i light %i fog %i dlight %i\n",
+ backEnd.pc.c_glslShaderBinds, backEnd.pc.c_genericDraws, backEnd.pc.c_lightallDraws, backEnd.pc.c_fogDraws, backEnd.pc.c_dlightDraws);
+ }
+
+ Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
+ Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
+}
+
+
+/*
+====================
+R_IssueRenderCommands
+====================
+*/
+void R_IssueRenderCommands( bool runPerformanceCounters ) {
+ renderCommandList_t *cmdList;
+
+ cmdList = &backEndData->commands;
+ assert(cmdList);
+ // add an end-of-list command
+ *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST;
+
+ // clear it out, in case this is a sync and not a buffer flip
+ cmdList->used = 0;
+
+ if ( runPerformanceCounters ) {
+ R_PerformanceCounters();
+ }
+
+ // actually start the commands going
+ if ( !r_skipBackEnd->integer ) {
+ // let it start on the new batch
+ RB_ExecuteRenderCommands( cmdList->cmds );
+ }
+}
+
+
+/*
+====================
+R_IssuePendingRenderCommands
+
+Issue any pending commands and wait for them to complete.
+====================
+*/
+void R_IssuePendingRenderCommands( void ) {
+ if ( !tr.registered ) {
+ return;
+ }
+ R_IssueRenderCommands( false );
+}
+
+/*
+============
+R_GetCommandBufferReserved
+
+make sure there is enough command space
+============
+*/
+void *R_GetCommandBufferReserved( int bytes, int reservedBytes ) {
+ renderCommandList_t *cmdList;
+
+ cmdList = &backEndData->commands;
+ bytes = PAD(bytes, sizeof(void *));
+
+ // always leave room for the end of list command
+ if ( cmdList->used + bytes + sizeof( int ) + reservedBytes > MAX_RENDER_COMMANDS ) {
+ if ( bytes > MAX_RENDER_COMMANDS - sizeof( int ) ) {
+ ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
+ }
+ // if we run out of room, just start dropping commands
+ return NULL;
+ }
+
+ cmdList->used += bytes;
+
+ return cmdList->cmds + cmdList->used - bytes;
+}
+
+/*
+=============
+R_GetCommandBuffer
+
+returns NULL if there is not enough space for important commands
+=============
+*/
+void *R_GetCommandBuffer( int bytes ) {
+ return R_GetCommandBufferReserved( bytes, PAD( sizeof( swapBuffersCommand_t ), sizeof(void *) ) );
+}
+
+
+/*
+=============
+R_AddDrawSurfCmd
+
+=============
+*/
+void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) {
+ drawSurfsCommand_t *cmd;
+
+ cmd = (drawSurfsCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_DRAW_SURFS;
+
+ cmd->drawSurfs = drawSurfs;
+ cmd->numDrawSurfs = numDrawSurfs;
+
+ cmd->refdef = tr.refdef;
+ cmd->viewParms = tr.viewParms;
+}
+
+
+/*
+=============
+R_AddCapShadowmapCmd
+
+=============
+*/
+void R_AddCapShadowmapCmd( int map, int cubeSide ) {
+ capShadowmapCommand_t *cmd;
+
+ cmd = (capShadowmapCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_CAPSHADOWMAP;
+
+ cmd->map = map;
+ cmd->cubeSide = cubeSide;
+}
+
+
+/*
+=============
+R_PostProcessingCmd
+
+=============
+*/
+void R_AddPostProcessCmd( ) {
+ postProcessCommand_t *cmd;
+
+ cmd = (postProcessCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_POSTPROCESS;
+
+ cmd->refdef = tr.refdef;
+ cmd->viewParms = tr.viewParms;
+}
+
+/*
+=============
+RE_SetColor
+
+Passing NULL will set the color to white
+=============
+*/
+void RE_SetColor( const float *rgba ) {
+ setColorCommand_t *cmd;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ cmd = (setColorCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_SET_COLOR;
+ if ( !rgba ) {
+ static float colorWhite[4] = { 1, 1, 1, 1 };
+
+ rgba = colorWhite;
+ }
+
+ cmd->color[0] = rgba[0];
+ cmd->color[1] = rgba[1];
+ cmd->color[2] = rgba[2];
+ cmd->color[3] = rgba[3];
+}
+
+/*
+=============
+R_ClipRegion
+=============
+*/
+static bool R_ClipRegion ( float *x, float *y, float *w, float *h,
+ float *s1, float *t1, float *s2, float *t2 ) {
+ float left, top, right, bottom;
+ float _s1, _t1, _s2, _t2;
+ float clipLeft, clipTop, clipRight, clipBottom;
+
+ if (tr.clipRegion[2] <= tr.clipRegion[0] ||
+ tr.clipRegion[3] <= tr.clipRegion[1] ) {
+ return false;
+ }
+
+ left = *x;
+ top = *y;
+ right = *x + *w;
+ bottom = *y + *h;
+
+ _s1 = *s1;
+ _t1 = *t1;
+ _s2 = *s2;
+ _t2 = *t2;
+
+ clipLeft = tr.clipRegion[0];
+ clipTop = tr.clipRegion[1];
+ clipRight = tr.clipRegion[2];
+ clipBottom = tr.clipRegion[3];
+
+ // Completely clipped away
+ if ( right <= clipLeft || left >= clipRight ||
+ bottom <= clipTop || top >= clipBottom ) {
+ return true;
+ }
+
+ // Clip left edge
+ if ( left < clipLeft ) {
+ float f = ( clipLeft - left ) / ( right - left );
+ *s1 = ( f * ( _s2 - _s1 ) ) + _s1;
+ *x = clipLeft;
+ *w -= ( clipLeft - left );
+ }
+
+ // Clip right edge
+ if ( right > clipRight ) {
+ float f = ( clipRight - right ) / ( left - right );
+ *s2 = ( f * ( _s1 - _s2 ) ) + _s2;
+ *w = clipRight - *x;
+ }
+
+ // Clip top edge
+ if ( top < clipTop ) {
+ float f = ( clipTop - top ) / ( bottom - top );
+ *t1 = ( f * ( _t2 - _t1 ) ) + _t1;
+ *y = clipTop;
+ *h -= ( clipTop - top );
+ }
+
+ // Clip bottom edge
+ if ( bottom > clipBottom ) {
+ float f = ( clipBottom - bottom ) / ( top - bottom );
+ *t2 = ( f * ( _t1 - _t2 ) ) + _t2;
+ *h = clipBottom - *y;
+ }
+
+ return false;
+}
+
+/*
+=============
+RE_SetClipRegion
+=============
+*/
+void RE_SetClipRegion( const float *region ) {
+ if ( region == NULL ) {
+ Com_Memset( tr.clipRegion, 0, sizeof( vec4_t ) );
+ } else {
+ Vector4Copy( region, tr.clipRegion );
+ }
+}
+
+/*
+=============
+RE_StretchPic
+=============
+*/
+void RE_StretchPic ( float x, float y, float w, float h,
+ float s1, float t1, float s2, float t2, qhandle_t hShader ) {
+ stretchPicCommand_t *cmd;
+
+ if (!tr.registered) {
+ return;
+ }
+ if (R_ClipRegion(&x, &y, &w, &h, &s1, &t1, &s2, &t2)) {
+ return;
+ }
+ cmd = (stretchPicCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_STRETCH_PIC;
+ cmd->shader = R_GetShaderByHandle( hShader );
+ cmd->x = x;
+ cmd->y = y;
+ cmd->w = w;
+ cmd->h = h;
+ cmd->s1 = s1;
+ cmd->t1 = t1;
+ cmd->s2 = s2;
+ cmd->t2 = t2;
+}
+
+#define MODE_RED_CYAN 1
+#define MODE_RED_BLUE 2
+#define MODE_RED_GREEN 3
+#define MODE_GREEN_MAGENTA 4
+#define MODE_MAX MODE_GREEN_MAGENTA
+
+void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode)
+{
+ rgba[0] = rgba[1] = rgba[2] = rgba[3] = GL_TRUE;
+
+ if(colormode > MODE_MAX)
+ {
+ if(stereoFrame == STEREO_LEFT)
+ stereoFrame = STEREO_RIGHT;
+ else if(stereoFrame == STEREO_RIGHT)
+ stereoFrame = STEREO_LEFT;
+
+ colormode -= MODE_MAX;
+ }
+
+ if(colormode == MODE_GREEN_MAGENTA)
+ {
+ if(stereoFrame == STEREO_LEFT)
+ rgba[0] = rgba[2] = GL_FALSE;
+ else if(stereoFrame == STEREO_RIGHT)
+ rgba[1] = GL_FALSE;
+ }
+ else
+ {
+ if(stereoFrame == STEREO_LEFT)
+ rgba[1] = rgba[2] = GL_FALSE;
+ else if(stereoFrame == STEREO_RIGHT)
+ {
+ rgba[0] = GL_FALSE;
+
+ if(colormode == MODE_RED_BLUE)
+ rgba[1] = GL_FALSE;
+ else if(colormode == MODE_RED_GREEN)
+ rgba[2] = GL_FALSE;
+ }
+ }
+}
+
+
+/*
+====================
+RE_BeginFrame
+
+If running in stereo, RE_BeginFrame will be called twice
+for each RE_EndFrame
+====================
+*/
+void RE_BeginFrame( stereoFrame_t stereoFrame ) {
+ drawBufferCommand_t *cmd = NULL;
+ colorMaskCommand_t *colcmd = NULL;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ glState.finishCalled = false;
+
+ tr.frameCount++;
+ tr.frameSceneNum = 0;
+
+ //
+ // do overdraw measurement
+ //
+ if ( r_measureOverdraw->integer )
+ {
+ if ( glConfig.stencilBits < 4 )
+ {
+ ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
+ ri.Cvar_Set( "r_measureOverdraw", "0" );
+ r_measureOverdraw->modified = false;
+ }
+ else if ( r_shadows->integer == 2 )
+ {
+ ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" );
+ ri.Cvar_Set( "r_measureOverdraw", "0" );
+ r_measureOverdraw->modified = false;
+ }
+ else
+ {
+ R_IssuePendingRenderCommands();
+ qglEnable( GL_STENCIL_TEST );
+ qglStencilMask( ~0U );
+ qglClearStencil( 0U );
+ qglStencilFunc( GL_ALWAYS, 0U, ~0U );
+ qglStencilOp( GL_KEEP, GL_INCR, GL_INCR );
+ }
+ r_measureOverdraw->modified = false;
+ }
+ else
+ {
+ // this is only reached if it was on and is now off
+ if ( r_measureOverdraw->modified ) {
+ R_IssuePendingRenderCommands();
+ qglDisable( GL_STENCIL_TEST );
+ }
+ r_measureOverdraw->modified = false;
+ }
+
+ //
+ // texturemode stuff
+ //
+ if ( r_textureMode->modified ) {
+ R_IssuePendingRenderCommands();
+ GL_TextureMode( r_textureMode->string );
+ r_textureMode->modified = false;
+ }
+
+ //
+ // gamma stuff
+ //
+ if ( r_gamma->modified ) {
+ r_gamma->modified = false;
+
+ R_IssuePendingRenderCommands();
+ R_SetColorMappings();
+ }
+
+ // check for errors
+ if ( !r_ignoreGLErrors->integer )
+ {
+ int err;
+
+ R_IssuePendingRenderCommands();
+ if ((err = qglGetError()) != GL_NO_ERROR)
+ ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err);
+ }
+
+ if (glConfig.stereoEnabled) {
+ if( !(cmd = (drawBufferCommand_t*)R_GetCommandBuffer(sizeof(*cmd))) )
+ return;
+
+ cmd->commandId = RC_DRAW_BUFFER;
+
+ if ( stereoFrame == STEREO_LEFT ) {
+ cmd->buffer = (int)GL_BACK_LEFT;
+ } else if ( stereoFrame == STEREO_RIGHT ) {
+ cmd->buffer = (int)GL_BACK_RIGHT;
+ } else {
+ ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
+ }
+ }
+ else
+ {
+ if(r_anaglyphMode->integer)
+ {
+ if(r_anaglyphMode->modified)
+ {
+ // clear both, front and backbuffer.
+ qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ backEnd.colorMask[0] = GL_FALSE;
+ backEnd.colorMask[1] = GL_FALSE;
+ backEnd.colorMask[2] = GL_FALSE;
+ backEnd.colorMask[3] = GL_FALSE;
+
+ if (glRefConfig.framebufferObject)
+ {
+ // clear all framebuffers
+ if (tr.msaaResolveFbo)
+ {
+ FBO_Bind(tr.msaaResolveFbo);
+ qglClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ if (tr.renderFbo)
+ {
+ FBO_Bind(tr.renderFbo);
+ qglClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ FBO_Bind(NULL);
+ }
+
+ qglDrawBuffer(GL_FRONT);
+ qglClear(GL_COLOR_BUFFER_BIT);
+ qglDrawBuffer(GL_BACK);
+ qglClear(GL_COLOR_BUFFER_BIT);
+
+ r_anaglyphMode->modified = false;
+ }
+
+ if(stereoFrame == STEREO_LEFT)
+ {
+ if( !(cmd = (drawBufferCommand_t*)R_GetCommandBuffer(sizeof(*cmd))) )
+ return;
+
+ if( !(colcmd = (colorMaskCommand_t*)R_GetCommandBuffer(sizeof(*colcmd))) )
+ return;
+ }
+ else if(stereoFrame == STEREO_RIGHT)
+ {
+ clearDepthCommand_t *cldcmd;
+
+ if( !(cldcmd = (clearDepthCommand_t*)R_GetCommandBuffer(sizeof(*cldcmd))) )
+ return;
+
+ cldcmd->commandId = RC_CLEARDEPTH;
+
+ if( !(colcmd = (colorMaskCommand_t*)R_GetCommandBuffer(sizeof(*colcmd))) )
+ return;
+ }
+ else
+ ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
+
+ R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer);
+ colcmd->commandId = RC_COLORMASK;
+ }
+ else
+ {
+ if(stereoFrame != STEREO_CENTER)
+ ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
+
+ if( !(cmd = (drawBufferCommand_t*)R_GetCommandBuffer(sizeof(*cmd))) )
+ return;
+ }
+
+ if(cmd)
+ {
+ cmd->commandId = RC_DRAW_BUFFER;
+
+ if(r_anaglyphMode->modified)
+ {
+ qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ backEnd.colorMask[0] = 0;
+ backEnd.colorMask[1] = 0;
+ backEnd.colorMask[2] = 0;
+ backEnd.colorMask[3] = 0;
+ r_anaglyphMode->modified = false;
+ }
+
+ if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
+ cmd->buffer = (int)GL_FRONT;
+ else
+ cmd->buffer = (int)GL_BACK;
+ }
+ }
+
+ tr.refdef.stereoFrame = stereoFrame;
+}
+
+
+/*
+=============
+RE_EndFrame
+
+Returns the number of msec spent in the back end
+=============
+*/
+void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
+ swapBuffersCommand_t *cmd;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ cmd = (swapBuffersCommand_t*)R_GetCommandBufferReserved( sizeof( *cmd ), 0 );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_SWAP_BUFFERS;
+
+ R_IssueRenderCommands( true );
+
+ R_InitNextFrame();
+
+ if ( frontEndMsec ) {
+ *frontEndMsec = tr.frontEndMsec;
+ }
+ tr.frontEndMsec = 0;
+ if ( backEndMsec ) {
+ *backEndMsec = backEnd.pc.msec;
+ }
+ backEnd.pc.msec = 0;
+}
+
+/*
+=============
+RE_TakeVideoFrame
+=============
+*/
+void RE_TakeVideoFrame( int width, int height,
+ byte *captureBuffer, byte *encodeBuffer, bool motionJpeg )
+{
+ videoFrameCommand_t *cmd;
+
+ if( !tr.registered ) {
+ return;
+ }
+
+ cmd = (videoFrameCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if( !cmd ) {
+ return;
+ }
+
+ cmd->commandId = RC_VIDEOFRAME;
+
+ cmd->width = width;
+ cmd->height = height;
+ cmd->captureBuffer = captureBuffer;
+ cmd->encodeBuffer = encodeBuffer;
+ cmd->motionJpeg = motionJpeg;
+}
diff --git a/src/renderergl2/tr_curve.cpp b/src/renderergl2/tr_curve.cpp
new file mode 100644
index 0000000..20aef7f
--- /dev/null
+++ b/src/renderergl2/tr_curve.cpp
@@ -0,0 +1,741 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+/*
+
+This file does all of the processing necessary to turn a raw grid of points
+read from the map file into a srfBspSurface_t ready for rendering.
+
+The level of detail solution is direction independent, based only on subdivided
+distance from the true curve.
+
+Only a single entry point:
+
+srfBspSurface_t *R_SubdividePatchToGrid( int width, int height,
+ srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
+
+*/
+
+
+/*
+============
+LerpDrawVert
+============
+*/
+static void LerpDrawVert( srfVert_t *a, srfVert_t *b, srfVert_t *out ) {
+ out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]);
+ out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]);
+ out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]);
+
+ out->st[0] = 0.5f * (a->st[0] + b->st[0]);
+ out->st[1] = 0.5f * (a->st[1] + b->st[1]);
+
+ out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]);
+ out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]);
+
+ out->color[0] = ((int)a->color[0] + (int)b->color[0]) >> 1;
+ out->color[1] = ((int)a->color[1] + (int)b->color[1]) >> 1;
+ out->color[2] = ((int)a->color[2] + (int)b->color[2]) >> 1;
+ out->color[3] = ((int)a->color[3] + (int)b->color[3]) >> 1;
+}
+
+/*
+============
+Transpose
+============
+*/
+static void Transpose( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
+ int i, j;
+ srfVert_t temp;
+
+ if ( width > height ) {
+ for ( i = 0 ; i < height ; i++ ) {
+ for ( j = i + 1 ; j < width ; j++ ) {
+ if ( j < height ) {
+ // swap the value
+ temp = ctrl[j][i];
+ ctrl[j][i] = ctrl[i][j];
+ ctrl[i][j] = temp;
+ } else {
+ // just copy
+ ctrl[j][i] = ctrl[i][j];
+ }
+ }
+ }
+ } else {
+ for ( i = 0 ; i < width ; i++ ) {
+ for ( j = i + 1 ; j < height ; j++ ) {
+ if ( j < width ) {
+ // swap the value
+ temp = ctrl[i][j];
+ ctrl[i][j] = ctrl[j][i];
+ ctrl[j][i] = temp;
+ } else {
+ // just copy
+ ctrl[i][j] = ctrl[j][i];
+ }
+ }
+ }
+ }
+
+}
+
+
+/*
+=================
+MakeMeshNormals
+
+Handles all the complicated wrapping and degenerate cases
+=================
+*/
+static void MakeMeshNormals( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
+ int i, j, k, dist;
+ vec3_t normal;
+ vec3_t sum;
+ int count = 0;
+ vec3_t base;
+ vec3_t delta;
+ int x, y;
+ srfVert_t *dv;
+ vec3_t around[8], temp;
+ bool good[8];
+ bool wrapWidth, wrapHeight;
+ float len;
+static int neighbors[8][2] = {
+ {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
+ };
+
+ wrapWidth = false;
+ for ( i = 0 ; i < height ; i++ ) {
+ VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta );
+ len = VectorLengthSquared( delta );
+ if ( len > 1.0 ) {
+ break;
+ }
+ }
+ if ( i == height ) {
+ wrapWidth = true;
+ }
+
+ wrapHeight = false;
+ for ( i = 0 ; i < width ; i++ ) {
+ VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta );
+ len = VectorLengthSquared( delta );
+ if ( len > 1.0 ) {
+ break;
+ }
+ }
+ if ( i == width) {
+ wrapHeight = true;
+ }
+
+
+ for ( i = 0 ; i < width ; i++ ) {
+ for ( j = 0 ; j < height ; j++ ) {
+ count = 0;
+ dv = &ctrl[j][i];
+ VectorCopy( dv->xyz, base );
+ for ( k = 0 ; k < 8 ; k++ ) {
+ VectorClear( around[k] );
+ good[k] = false;
+
+ for ( dist = 1 ; dist <= 3 ; dist++ ) {
+ x = i + neighbors[k][0] * dist;
+ y = j + neighbors[k][1] * dist;
+ if ( wrapWidth ) {
+ if ( x < 0 ) {
+ x = width - 1 + x;
+ } else if ( x >= width ) {
+ x = 1 + x - width;
+ }
+ }
+ if ( wrapHeight ) {
+ if ( y < 0 ) {
+ y = height - 1 + y;
+ } else if ( y >= height ) {
+ y = 1 + y - height;
+ }
+ }
+
+ if ( x < 0 || x >= width || y < 0 || y >= height ) {
+ break; // edge of patch
+ }
+ VectorSubtract( ctrl[y][x].xyz, base, temp );
+ if ( VectorNormalize2( temp, temp ) == 0 ) {
+ continue; // degenerate edge, get more dist
+ } else {
+ good[k] = true;
+ VectorCopy( temp, around[k] );
+ break; // good edge
+ }
+ }
+ }
+
+ VectorClear( sum );
+ for ( k = 0 ; k < 8 ; k++ ) {
+ if ( !good[k] || !good[(k+1)&7] ) {
+ continue; // didn't get two points
+ }
+ CrossProduct( around[(k+1)&7], around[k], normal );
+ if ( VectorNormalize2( normal, normal ) == 0 ) {
+ continue;
+ }
+ VectorAdd( normal, sum, sum );
+ count++;
+ }
+ //if ( count == 0 ) {
+ // printf("bad normal\n");
+ //}
+ {
+ vec3_t fNormal;
+ VectorNormalize2(sum, fNormal);
+ R_VaoPackNormal(dv->normal, fNormal);
+ }
+ }
+ }
+}
+
+static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int numIndexes,
+ glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3])
+{
+ int i, j;
+ srfVert_t *dv[3];
+ static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE];
+ glIndex_t *tri;
+
+ // FIXME: use more elegant way
+ for(i = 0; i < width; i++)
+ {
+ for(j = 0; j < height; j++)
+ {
+ dv[0] = &ctrl2[j * width + i];
+ *dv[0] = ctrl[j][i];
+ }
+ }
+
+ for(i = 0, tri = indexes; i < numIndexes; i += 3, tri += 3)
+ {
+ dv[0] = &ctrl2[tri[0]];
+ dv[1] = &ctrl2[tri[1]];
+ dv[2] = &ctrl2[tri[2]];
+
+ R_CalcTangentVectors(dv);
+ }
+
+ for(i = 0; i < width; i++)
+ {
+ for(j = 0; j < height; j++)
+ {
+ dv[0] = &ctrl2[j * width + i];
+ dv[1] = &ctrl[j][i];
+
+ VectorCopy4(dv[0]->tangent, dv[1]->tangent);
+ }
+ }
+}
+
+
+static int MakeMeshIndexes(int width, int height, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3])
+{
+ int i, j;
+ int numIndexes;
+ int w, h;
+
+ h = height - 1;
+ w = width - 1;
+ numIndexes = 0;
+ for(i = 0; i < h; i++)
+ {
+ for(j = 0; j < w; j++)
+ {
+ int v1, v2, v3, v4;
+
+ // vertex order to be reckognized as tristrips
+ v1 = i * width + j + 1;
+ v2 = v1 - 1;
+ v3 = v2 + width;
+ v4 = v3 + 1;
+
+ indexes[numIndexes++] = v2;
+ indexes[numIndexes++] = v3;
+ indexes[numIndexes++] = v1;
+
+ indexes[numIndexes++] = v1;
+ indexes[numIndexes++] = v3;
+ indexes[numIndexes++] = v4;
+ }
+ }
+
+ return numIndexes;
+}
+
+
+/*
+============
+InvertCtrl
+============
+*/
+static void InvertCtrl( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
+ int i, j;
+ srfVert_t temp;
+
+ for ( i = 0 ; i < height ; i++ ) {
+ for ( j = 0 ; j < width/2 ; j++ ) {
+ temp = ctrl[i][j];
+ ctrl[i][j] = ctrl[i][width-1-j];
+ ctrl[i][width-1-j] = temp;
+ }
+ }
+}
+
+
+/*
+=================
+InvertErrorTable
+=================
+*/
+static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) {
+ int i;
+ float copy[2][MAX_GRID_SIZE];
+
+ Com_Memcpy( copy, errorTable, sizeof( copy ) );
+
+ for ( i = 0 ; i < width ; i++ ) {
+ errorTable[1][i] = copy[0][i]; //[width-1-i];
+ }
+
+ for ( i = 0 ; i < height ; i++ ) {
+ errorTable[0][i] = copy[1][height-1-i];
+ }
+
+}
+
+/*
+==================
+PutPointsOnCurve
+==================
+*/
+static void PutPointsOnCurve( srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
+ int width, int height ) {
+ int i, j;
+ srfVert_t prev, next;
+
+ for ( i = 0 ; i < width ; i++ ) {
+ for ( j = 1 ; j < height ; j += 2 ) {
+ LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev );
+ LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next );
+ LerpDrawVert( &prev, &next, &ctrl[j][i] );
+ }
+ }
+
+
+ for ( j = 0 ; j < height ; j++ ) {
+ for ( i = 1 ; i < width ; i += 2 ) {
+ LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev );
+ LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next );
+ LerpDrawVert( &prev, &next, &ctrl[j][i] );
+ }
+ }
+}
+
+/*
+=================
+R_CreateSurfaceGridMesh
+=================
+*/
+void R_CreateSurfaceGridMesh(srfBspSurface_t *grid, int width, int height,
+ srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE],
+ int numIndexes, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) {
+ int i, j;
+ srfVert_t *vert;
+ vec3_t tmpVec;
+
+ // copy the results out to a grid
+ Com_Memset(grid, 0, sizeof(*grid));
+
+#ifdef PATCH_STITCHING
+ grid->widthLodError = (float*)/*ri.Hunk_Alloc*/ ri.Malloc( width * 4 );
+ Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
+
+ grid->heightLodError = (float*)/*ri.Hunk_Alloc*/ ri.Malloc( height * 4 );
+ Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
+
+ grid->numIndexes = numIndexes;
+ grid->indexes = (glIndex_t*)ri.Malloc(grid->numIndexes * sizeof(glIndex_t));
+ Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t));
+
+ grid->numVerts = (width * height);
+ grid->verts = (srfVert_t*)ri.Malloc(grid->numVerts * sizeof(srfVert_t));
+#else
+ grid->widthLodError = ri.Hunk_Alloc( width * 4 );
+ Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
+
+ grid->heightLodError = ri.Hunk_Alloc( height * 4 );
+ Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
+
+ grid->numIndexes = numIndexes;
+ grid->indexes = ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low);
+ Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t));
+
+ grid->numVerts = (width * height);
+ grid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low);
+#endif
+
+ grid->width = width;
+ grid->height = height;
+ grid->surfaceType = SF_GRID;
+ ClearBounds( grid->cullBounds[0], grid->cullBounds[1] );
+ for ( i = 0 ; i < width ; i++ ) {
+ for ( j = 0 ; j < height ; j++ ) {
+ vert = &grid->verts[j*width+i];
+ *vert = ctrl[j][i];
+ AddPointToBounds( vert->xyz, grid->cullBounds[0], grid->cullBounds[1] );
+ }
+ }
+
+ // compute local origin and bounds
+ VectorAdd( grid->cullBounds[0], grid->cullBounds[1], grid->cullOrigin );
+ VectorScale( grid->cullOrigin, 0.5f, grid->cullOrigin );
+ VectorSubtract( grid->cullBounds[0], grid->cullOrigin, tmpVec );
+ grid->cullRadius = VectorLength( tmpVec );
+
+ VectorCopy( grid->cullOrigin, grid->lodOrigin );
+ grid->lodRadius = grid->cullRadius;
+ //
+}
+
+/*
+=================
+R_FreeSurfaceGridMesh
+=================
+*/
+static void R_FreeSurfaceGridMeshData( srfBspSurface_t *grid ) {
+ ri.Free(grid->widthLodError);
+ ri.Free(grid->heightLodError);
+ ri.Free(grid->indexes);
+ ri.Free(grid->verts);
+}
+
+/*
+=================
+R_SubdividePatchToGrid
+=================
+*/
+void R_SubdividePatchToGrid( srfBspSurface_t *grid, int width, int height,
+ srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
+ int i, j, k, l;
+ srfVert_t_cleared( prev );
+ srfVert_t_cleared( next );
+ srfVert_t_cleared( mid );
+ float len, maxLen;
+ int dir;
+ int t;
+ srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
+ float errorTable[2][MAX_GRID_SIZE];
+ int numIndexes;
+ static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3];
+ int consecutiveComplete;
+
+ for ( i = 0 ; i < width ; i++ ) {
+ for ( j = 0 ; j < height ; j++ ) {
+ ctrl[j][i] = points[j*width+i];
+ }
+ }
+
+ for ( dir = 0 ; dir < 2 ; dir++ ) {
+
+ for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {
+ errorTable[dir][j] = 0;
+ }
+
+ consecutiveComplete = 0;
+
+ // horizontal subdivisions
+ for ( j = 0 ; ; j = (j + 2) % (width - 1) ) {
+ // check subdivided midpoints against control points
+
+ // FIXME: also check midpoints of adjacent patches against the control points
+ // this would basically stitch all patches in the same LOD group together.
+
+ maxLen = 0;
+ for ( i = 0 ; i < height ; i++ ) {
+ vec3_t midxyz;
+ vec3_t midxyz2;
+ vec3_t dir;
+ vec3_t projected;
+ float d;
+
+ // calculate the point on the curve
+ for ( l = 0 ; l < 3 ; l++ ) {
+ midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2
+ + ctrl[i][j+2].xyz[l] ) * 0.25f;
+ }
+
+ // see how far off the line it is
+ // using dist-from-line will not account for internal
+ // texture warping, but it gives a lot less polygons than
+ // dist-from-midpoint
+ VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz );
+ VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir );
+ VectorNormalize( dir );
+
+ d = DotProduct( midxyz, dir );
+ VectorScale( dir, d, projected );
+ VectorSubtract( midxyz, projected, midxyz2);
+ len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later
+ if ( len > maxLen ) {
+ maxLen = len;
+ }
+ }
+
+ maxLen = sqrt(maxLen);
+
+ // if all the points are on the lines, remove the entire columns
+ if ( maxLen < 0.1f ) {
+ errorTable[dir][j+1] = 999;
+ // if we go over the whole grid twice without adding any columns, stop
+ if (++consecutiveComplete >= width)
+ break;
+ continue;
+ }
+
+ // see if we want to insert subdivided columns
+ if ( width + 2 > MAX_GRID_SIZE ) {
+ errorTable[dir][j+1] = 1.0f/maxLen;
+ break; // can't subdivide any more
+ }
+
+ if ( maxLen <= r_subdivisions->value ) {
+ errorTable[dir][j+1] = 1.0f/maxLen;
+ // if we go over the whole grid twice without adding any columns, stop
+ if (++consecutiveComplete >= width)
+ break;
+ continue; // didn't need subdivision
+ }
+
+ errorTable[dir][j+2] = 1.0f/maxLen;
+
+ consecutiveComplete = 0;
+
+ // insert two columns and replace the peak
+ width += 2;
+ for ( i = 0 ; i < height ; i++ ) {
+ LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev );
+ LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next );
+ LerpDrawVert( &prev, &next, &mid );
+
+ for ( k = width - 1 ; k > j + 3 ; k-- ) {
+ ctrl[i][k] = ctrl[i][k-2];
+ }
+ ctrl[i][j + 1] = prev;
+ ctrl[i][j + 2] = mid;
+ ctrl[i][j + 3] = next;
+ }
+
+ // skip the new one, we'll get it on the next pass
+ j += 2;
+ }
+
+ Transpose( width, height, ctrl );
+ t = width;
+ width = height;
+ height = t;
+ }
+
+
+ // put all the aproximating points on the curve
+ PutPointsOnCurve( ctrl, width, height );
+
+ // cull out any rows or columns that are colinear
+ for ( i = 1 ; i < width-1 ; i++ ) {
+ if ( errorTable[0][i] != 999 ) {
+ continue;
+ }
+ for ( j = i+1 ; j < width ; j++ ) {
+ for ( k = 0 ; k < height ; k++ ) {
+ ctrl[k][j-1] = ctrl[k][j];
+ }
+ errorTable[0][j-1] = errorTable[0][j];
+ }
+ width--;
+ }
+
+ for ( i = 1 ; i < height-1 ; i++ ) {
+ if ( errorTable[1][i] != 999 ) {
+ continue;
+ }
+ for ( j = i+1 ; j < height ; j++ ) {
+ for ( k = 0 ; k < width ; k++ ) {
+ ctrl[j-1][k] = ctrl[j][k];
+ }
+ errorTable[1][j-1] = errorTable[1][j];
+ }
+ height--;
+ }
+
+#if 1
+ // flip for longest tristrips as an optimization
+ // the results should be visually identical with or
+ // without this step
+ if ( height > width ) {
+ Transpose( width, height, ctrl );
+ InvertErrorTable( errorTable, width, height );
+ t = width;
+ width = height;
+ height = t;
+ InvertCtrl( width, height, ctrl );
+ }
+#endif
+
+ // calculate indexes
+ numIndexes = MakeMeshIndexes(width, height, indexes);
+
+ // calculate normals
+ MakeMeshNormals( width, height, ctrl );
+ MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes);
+
+ R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes);
+}
+
+/*
+===============
+R_GridInsertColumn
+===============
+*/
+void R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ) {
+ int i, j;
+ int width, height, oldwidth;
+ srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
+ float errorTable[2][MAX_GRID_SIZE];
+ float lodRadius;
+ vec3_t lodOrigin;
+ int numIndexes;
+ static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3];
+
+ oldwidth = 0;
+ width = grid->width + 1;
+ if (width > MAX_GRID_SIZE)
+ return;
+ height = grid->height;
+ for (i = 0; i < width; i++) {
+ if (i == column) {
+ //insert new column
+ for (j = 0; j < grid->height; j++) {
+ LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] );
+ if (j == row)
+ VectorCopy(point, ctrl[j][i].xyz);
+ }
+ errorTable[0][i] = loderror;
+ continue;
+ }
+ errorTable[0][i] = grid->widthLodError[oldwidth];
+ for (j = 0; j < grid->height; j++) {
+ ctrl[j][i] = grid->verts[j * grid->width + oldwidth];
+ }
+ oldwidth++;
+ }
+ for (j = 0; j < grid->height; j++) {
+ errorTable[1][j] = grid->heightLodError[j];
+ }
+ // put all the aproximating points on the curve
+ //PutPointsOnCurve( ctrl, width, height );
+
+ // calculate indexes
+ numIndexes = MakeMeshIndexes(width, height, indexes);
+
+ // calculate normals
+ MakeMeshNormals( width, height, ctrl );
+ MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes);
+
+ VectorCopy(grid->lodOrigin, lodOrigin);
+ lodRadius = grid->lodRadius;
+ // free the old grid
+ R_FreeSurfaceGridMeshData(grid);
+ // create a new grid
+ R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes);
+ grid->lodRadius = lodRadius;
+ VectorCopy(lodOrigin, grid->lodOrigin);
+}
+
+/*
+===============
+R_GridInsertRow
+===============
+*/
+void R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ) {
+ int i, j;
+ int width, height, oldheight;
+ srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
+ float errorTable[2][MAX_GRID_SIZE];
+ float lodRadius;
+ vec3_t lodOrigin;
+ int numIndexes;
+ static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3];
+
+ oldheight = 0;
+ width = grid->width;
+ height = grid->height + 1;
+ if (height > MAX_GRID_SIZE)
+ return;
+ for (i = 0; i < height; i++) {
+ if (i == row) {
+ //insert new row
+ for (j = 0; j < grid->width; j++) {
+ LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] );
+ if (j == column)
+ VectorCopy(point, ctrl[i][j].xyz);
+ }
+ errorTable[1][i] = loderror;
+ continue;
+ }
+ errorTable[1][i] = grid->heightLodError[oldheight];
+ for (j = 0; j < grid->width; j++) {
+ ctrl[i][j] = grid->verts[oldheight * grid->width + j];
+ }
+ oldheight++;
+ }
+ for (j = 0; j < grid->width; j++) {
+ errorTable[0][j] = grid->widthLodError[j];
+ }
+ // put all the aproximating points on the curve
+ //PutPointsOnCurve( ctrl, width, height );
+
+ // calculate indexes
+ numIndexes = MakeMeshIndexes(width, height, indexes);
+
+ // calculate normals
+ MakeMeshNormals( width, height, ctrl );
+ MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes);
+
+ VectorCopy(grid->lodOrigin, lodOrigin);
+ lodRadius = grid->lodRadius;
+ // free the old grid
+ R_FreeSurfaceGridMeshData(grid);
+ // create a new grid
+ R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes);
+ grid->lodRadius = lodRadius;
+ VectorCopy(lodOrigin, grid->lodOrigin);
+}
diff --git a/src/renderergl2/tr_dsa.cpp b/src/renderergl2/tr_dsa.cpp
new file mode 100644
index 0000000..8ea42bc
--- /dev/null
+++ b/src/renderergl2/tr_dsa.cpp
@@ -0,0 +1,287 @@
+/*
+===========================================================================
+Copyright (C) 2016 James Canete
+Copyright (C) 2015-2019 GrangerHub
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 3
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+#include "tr_dsa.h"
+
+static struct
+{
+ GLuint textures[NUM_TEXTURE_BUNDLES];
+ GLenum texunit;
+
+ GLuint program;
+
+ GLuint drawFramebuffer;
+ GLuint readFramebuffer;
+ GLuint renderbuffer;
+}
+glDsaState;
+
+void GL_BindNullTextures()
+{
+ int i;
+
+ if (glRefConfig.directStateAccess)
+ {
+ for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
+ {
+ qglBindMultiTextureEXT(GL_TEXTURE0 + i, GL_TEXTURE_2D, 0);
+ glDsaState.textures[i] = 0;
+ }
+ }
+ else
+ {
+ for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
+ {
+ qglActiveTexture(GL_TEXTURE0 + i);
+ qglBindTexture(GL_TEXTURE_2D, 0);
+ glDsaState.textures[i] = 0;
+ }
+
+ qglActiveTexture(GL_TEXTURE0);
+ glDsaState.texunit = GL_TEXTURE0;
+ }
+}
+
+int GL_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture)
+{
+ GLuint tmu = texunit - GL_TEXTURE0;
+
+ if (glDsaState.textures[tmu] == texture)
+ return 0;
+
+ if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
+ target = GL_TEXTURE_CUBE_MAP;
+
+ qglBindMultiTextureEXT(texunit, target, texture);
+ glDsaState.textures[tmu] = texture;
+ return 1;
+}
+
+GLvoid APIENTRY GLDSA_BindMultiTextureEXT(GLenum texunit, GLenum target, GLuint texture)
+{
+ if (glDsaState.texunit != texunit)
+ {
+ qglActiveTexture(texunit);
+ glDsaState.texunit = texunit;
+ }
+
+ qglBindTexture(target, texture);
+}
+
+GLvoid APIENTRY GLDSA_TextureParameterfEXT(GLuint texture, GLenum target, GLenum pname, GLfloat param)
+{
+ GL_BindMultiTexture(glDsaState.texunit, target, texture);
+ qglTexParameterf(target, pname, param);
+}
+
+GLvoid APIENTRY GLDSA_TextureParameteriEXT(GLuint texture, GLenum target, GLenum pname, GLint param)
+{
+ GL_BindMultiTexture(glDsaState.texunit, target, texture);
+ qglTexParameteri(target, pname, param);
+}
+
+GLvoid APIENTRY GLDSA_TextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLint internalformat,
+ GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+{
+ GL_BindMultiTexture(glDsaState.texunit, target, texture);
+ qglTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+}
+
+GLvoid APIENTRY GLDSA_TextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
+{
+ GL_BindMultiTexture(glDsaState.texunit, target, texture);
+ qglTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+
+GLvoid APIENTRY GLDSA_CopyTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ GL_BindMultiTexture(glDsaState.texunit, target, texture);
+ qglCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+}
+
+GLvoid APIENTRY GLDSA_CompressedTextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
+{
+ GL_BindMultiTexture(glDsaState.texunit, target, texture);
+ qglCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
+}
+
+GLvoid APIENTRY GLDSA_CompressedTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
+ GLsizei imageSize, const GLvoid *data)
+{
+ GL_BindMultiTexture(glDsaState.texunit, target, texture);
+ qglCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+
+GLvoid APIENTRY GLDSA_GenerateTextureMipmapEXT(GLuint texture, GLenum target)
+{
+ GL_BindMultiTexture(glDsaState.texunit, target, texture);
+ qglGenerateMipmap(target);
+}
+
+void GL_BindNullProgram()
+{
+ qglUseProgram(0);
+ glDsaState.program = 0;
+}
+
+int GL_UseProgram(GLuint program)
+{
+ if (glDsaState.program == program)
+ return 0;
+
+ qglUseProgram(program);
+ glDsaState.program = program;
+ return 1;
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform1iEXT(GLuint program, GLint location, GLint v0)
+{
+ GL_UseProgram(program);
+ qglUniform1i(location, v0);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform1fEXT(GLuint program, GLint location, GLfloat v0)
+{
+ GL_UseProgram(program);
+ qglUniform1f(location, v0);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform2fEXT(GLuint program, GLint location,
+ GLfloat v0, GLfloat v1)
+{
+ GL_UseProgram(program);
+ qglUniform2f(location, v0, v1);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform3fEXT(GLuint program, GLint location,
+ GLfloat v0, GLfloat v1, GLfloat v2)
+{
+ GL_UseProgram(program);
+ qglUniform3f(location, v0, v1, v2);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform4fEXT(GLuint program, GLint location,
+ GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
+{
+ GL_UseProgram(program);
+ qglUniform4f(location, v0, v1, v2, v3);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform1fvEXT(GLuint program, GLint location,
+ GLsizei count, const GLfloat *value)
+{
+ GL_UseProgram(program);
+ qglUniform1fv(location, count, value);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fvEXT(GLuint program, GLint location,
+ GLsizei count, GLboolean transpose,
+ const GLfloat *value)
+{
+ GL_UseProgram(program);
+ qglUniformMatrix4fv(location, count, transpose, value);
+}
+
+void GL_BindNullFramebuffers()
+{
+ qglBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDsaState.drawFramebuffer = glDsaState.readFramebuffer = 0;
+ qglBindRenderbuffer(GL_RENDERBUFFER, 0);
+ glDsaState.renderbuffer = 0;
+}
+
+void GL_BindFramebuffer(GLenum target, GLuint framebuffer)
+{
+ switch (target)
+ {
+ case GL_FRAMEBUFFER:
+ if (framebuffer != glDsaState.drawFramebuffer || framebuffer != glDsaState.readFramebuffer)
+ {
+ qglBindFramebuffer(target, framebuffer);
+ glDsaState.drawFramebuffer = glDsaState.readFramebuffer = framebuffer;
+ }
+ break;
+
+ case GL_DRAW_FRAMEBUFFER:
+ if (framebuffer != glDsaState.drawFramebuffer)
+ {
+ qglBindFramebuffer(target, framebuffer);
+ glDsaState.drawFramebuffer = framebuffer;
+ }
+ break;
+
+ case GL_READ_FRAMEBUFFER:
+ if (framebuffer != glDsaState.readFramebuffer)
+ {
+ qglBindFramebuffer(target, framebuffer);
+ glDsaState.readFramebuffer = framebuffer;
+ }
+ break;
+ }
+}
+
+void GL_BindRenderbuffer(GLuint renderbuffer)
+{
+ if (renderbuffer != glDsaState.renderbuffer)
+ {
+ qglBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
+ glDsaState.renderbuffer = renderbuffer;
+ }
+}
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorageEXT(GLuint renderbuffer,
+ GLenum internalformat, GLsizei width, GLsizei height)
+{
+ GL_BindRenderbuffer(renderbuffer);
+ qglRenderbufferStorage(GL_RENDERBUFFER, internalformat, width, height);
+}
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer,
+ GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+{
+ GL_BindRenderbuffer(renderbuffer);
+ qglRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalformat, width, height);
+}
+
+GLenum APIENTRY GLDSA_CheckNamedFramebufferStatusEXT(GLuint framebuffer, GLenum target)
+{
+ GL_BindFramebuffer(target, framebuffer);
+ return qglCheckFramebufferStatus(target);
+}
+
+GLvoid APIENTRY GLDSA_NamedFramebufferTexture2DEXT(GLuint framebuffer,
+ GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+ GL_BindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ qglFramebufferTexture2D(GL_FRAMEBUFFER, attachment, textarget, texture, level);
+}
+
+GLvoid APIENTRY GLDSA_NamedFramebufferRenderbufferEXT(GLuint framebuffer,
+ GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+ GL_BindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ qglFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, renderbuffertarget, renderbuffer);
+}
diff --git a/src/renderergl2/tr_dsa.h b/src/renderergl2/tr_dsa.h
new file mode 100644
index 0000000..92c6563
--- /dev/null
+++ b/src/renderergl2/tr_dsa.h
@@ -0,0 +1,80 @@
+/*
+===========================================================================
+Copyright (C) 2016 James Canete
+Copyright (C) 2015-2019 GrangerHub
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 3
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.
+===========================================================================
+*/
+
+#ifndef __TR_DSA_H__
+#define __TR_DSA_H__
+
+#include "renderercommon/qgl.h"
+
+void GL_BindNullTextures(void);
+int GL_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture);
+
+GLvoid APIENTRY GLDSA_BindMultiTextureEXT(GLenum texunit, GLenum target, GLuint texture);
+GLvoid APIENTRY GLDSA_TextureParameterfEXT(GLuint texture, GLenum target, GLenum pname, GLfloat param);
+GLvoid APIENTRY GLDSA_TextureParameteriEXT(GLuint texture, GLenum target, GLenum pname, GLint param);
+GLvoid APIENTRY GLDSA_TextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLint internalformat,
+ GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+GLvoid APIENTRY GLDSA_TextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+GLvoid APIENTRY GLDSA_CopyTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint x, GLint y, GLsizei width, GLsizei height);
+GLvoid APIENTRY GLDSA_CompressedTextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+GLvoid APIENTRY GLDSA_CompressedTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
+ GLsizei imageSize, const GLvoid *data);
+
+GLvoid APIENTRY GLDSA_GenerateTextureMipmapEXT(GLuint texture, GLenum target);
+
+void GL_BindNullProgram(void);
+int GL_UseProgram(GLuint program);
+
+GLvoid APIENTRY GLDSA_ProgramUniform1iEXT(GLuint program, GLint location, GLint v0);
+GLvoid APIENTRY GLDSA_ProgramUniform1fEXT(GLuint program, GLint location, GLfloat v0);
+GLvoid APIENTRY GLDSA_ProgramUniform2fEXT(GLuint program, GLint location,
+ GLfloat v0, GLfloat v1);
+GLvoid APIENTRY GLDSA_ProgramUniform3fEXT(GLuint program, GLint location,
+ GLfloat v0, GLfloat v1, GLfloat v2);
+GLvoid APIENTRY GLDSA_ProgramUniform4fEXT(GLuint program, GLint location,
+ GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLvoid APIENTRY GLDSA_ProgramUniform1fvEXT(GLuint program, GLint location,
+ GLsizei count, const GLfloat *value);
+GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fvEXT(GLuint program, GLint location,
+ GLsizei count, GLboolean transpose,
+ const GLfloat *value);
+
+void GL_BindNullFramebuffers(void);
+void GL_BindFramebuffer(GLenum target, GLuint framebuffer);
+void GL_BindRenderbuffer(GLuint renderbuffer);
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorageEXT(GLuint renderbuffer,
+ GLenum internalformat, GLsizei width, GLsizei height);
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer,
+ GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+
+GLenum APIENTRY GLDSA_CheckNamedFramebufferStatusEXT(GLuint framebuffer, GLenum target);
+GLvoid APIENTRY GLDSA_NamedFramebufferTexture2DEXT(GLuint framebuffer,
+ GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLvoid APIENTRY GLDSA_NamedFramebufferRenderbufferEXT(GLuint framebuffer,
+ GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+
+
+#endif
diff --git a/src/renderergl2/tr_extensions.cpp b/src/renderergl2/tr_extensions.cpp
new file mode 100644
index 0000000..6f73d29
--- /dev/null
+++ b/src/renderergl2/tr_extensions.cpp
@@ -0,0 +1,279 @@
+/*
+===========================================================================
+Copyright (C) 2011 James Canete (use.less01@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous Arena source code.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_extensions.c - extensions needed by the renderer not in sdl_glimp.c
+
+#ifdef USE_LOCAL_HEADERS
+#include "SDL.h"
+#else
+#include <SDL.h>
+#endif
+
+#include "tr_local.h"
+#include "tr_dsa.h"
+
+#define GLE(ret, name, ...) name##proc *qgl##name;
+QGL_1_3_PROCS;
+QGL_1_5_PROCS;
+QGL_2_0_PROCS;
+QGL_3_0_PROCS;
+QGL_ARB_framebuffer_object_PROCS;
+QGL_ARB_vertex_array_object_PROCS;
+QGL_EXT_direct_state_access_PROCS;
+#undef GLE
+
+void GLimp_InitExtraExtensions()
+{
+ const char *extension;
+ const char *result[3] = {"...ignoring %s\n", "...using %s\n", "...%s not found\n"};
+
+ // Check OpenGL version
+ sscanf(glConfig.version_string, "%d.%d", &glRefConfig.openglMajorVersion, &glRefConfig.openglMinorVersion);
+ if (glRefConfig.openglMajorVersion < 2) ri.Error(ERR_FATAL, "OpenGL 2.0 required!");
+ ri.Printf(PRINT_ALL, "...using OpenGL %s\n", glConfig.version_string);
+
+ bool q_gl_version_at_least_3_0 = (glRefConfig.openglMajorVersion >= 3);
+ bool q_gl_version_at_least_3_2 = (glRefConfig.openglMajorVersion > 3 ||
+ (glRefConfig.openglMajorVersion == 3 && glRefConfig.openglMinorVersion > 2));
+
+ // Check if we need Intel graphics specific fixes.
+ glRefConfig.intelGraphics = qfalse;
+ if (strstr((char *)qglGetString(GL_RENDERER), "Intel")) glRefConfig.intelGraphics = qtrue;
+
+ // set DSA fallbacks
+#define GLE(ret, name, ...) qgl##name = GLDSA_##name;
+ QGL_EXT_direct_state_access_PROCS;
+#undef GLE
+
+ // GL function loader, based on https://gist.github.com/rygorous/16796a0c876cf8a5f542caddb55bce8a
+#define GLE(ret, name, ...) qgl##name = (name##proc *)SDL_GL_GetProcAddress("gl" #name);
+
+ // OpenGL 1.3, was GL_ARB_texture_compression
+ QGL_1_3_PROCS;
+
+ // OpenGL 1.5, was GL_ARB_vertex_buffer_object and GL_ARB_occlusion_query
+ QGL_1_5_PROCS;
+ glRefConfig.occlusionQuery = qtrue;
+
+ // OpenGL 2.0, was GL_ARB_shading_language_100, GL_ARB_vertex_program, GL_ARB_shader_objects, and
+ // GL_ARB_vertex_shader
+ QGL_2_0_PROCS;
+
+ // OpenGL 3.0 - no matching extension
+ // QGL_*_PROCS becomes several functions, do not remove {}
+ if (q_gl_version_at_least_3_0)
+ {
+ QGL_3_0_PROCS;
+ }
+
+ // OpenGL 3.0 - GL_ARB_framebuffer_object
+ extension = "GL_ARB_framebuffer_object";
+ glRefConfig.framebufferObject = qfalse;
+ glRefConfig.framebufferBlit = qfalse;
+ glRefConfig.framebufferMultisample = qfalse;
+ if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension))
+ {
+ glRefConfig.framebufferObject = !!r_ext_framebuffer_object->integer;
+ glRefConfig.framebufferBlit = qtrue;
+ glRefConfig.framebufferMultisample = qtrue;
+
+ qglGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glRefConfig.maxRenderbufferSize);
+ qglGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &glRefConfig.maxColorAttachments);
+
+ QGL_ARB_framebuffer_object_PROCS;
+
+ ri.Printf(PRINT_ALL, result[glRefConfig.framebufferObject], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+ // OpenGL 3.0 - GL_ARB_vertex_array_object
+ extension = "GL_ARB_vertex_array_object";
+ glRefConfig.vertexArrayObject = qfalse;
+ if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension))
+ {
+ if (q_gl_version_at_least_3_0)
+ {
+ // force VAO, core context requires it
+ glRefConfig.vertexArrayObject = qtrue;
+ }
+ else
+ {
+ glRefConfig.vertexArrayObject = !!r_arb_vertex_array_object->integer;
+ }
+
+ QGL_ARB_vertex_array_object_PROCS;
+
+ ri.Printf(PRINT_ALL, result[glRefConfig.vertexArrayObject], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+ // OpenGL 3.0 - GL_ARB_texture_float
+ extension = "GL_ARB_texture_float";
+ glRefConfig.textureFloat = qfalse;
+ if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension))
+ {
+ glRefConfig.textureFloat = !!r_ext_texture_float->integer;
+
+ ri.Printf(PRINT_ALL, result[glRefConfig.textureFloat], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+ // OpenGL 3.2 - GL_ARB_depth_clamp
+ extension = "GL_ARB_depth_clamp";
+ glRefConfig.depthClamp = qfalse;
+ if (q_gl_version_at_least_3_2 || SDL_GL_ExtensionSupported(extension))
+ {
+ glRefConfig.depthClamp = qtrue;
+
+ ri.Printf(PRINT_ALL, result[glRefConfig.depthClamp], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+ // OpenGL 3.2 - GL_ARB_seamless_cube_map
+ extension = "GL_ARB_seamless_cube_map";
+ glRefConfig.seamlessCubeMap = qfalse;
+ if (q_gl_version_at_least_3_2 || SDL_GL_ExtensionSupported(extension))
+ {
+ glRefConfig.seamlessCubeMap = !!r_arb_seamless_cube_map->integer;
+
+ ri.Printf(PRINT_ALL, result[glRefConfig.seamlessCubeMap], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+ // Determine GLSL version
+ if (1)
+ {
+ char version[256];
+
+ Q_strncpyz(version, (char *)qglGetString(GL_SHADING_LANGUAGE_VERSION), sizeof(version));
+
+ sscanf(version, "%d.%d", &glRefConfig.glslMajorVersion, &glRefConfig.glslMinorVersion);
+
+ ri.Printf(PRINT_ALL, "...using GLSL version %s\n", version);
+ }
+
+ glRefConfig.memInfo = MI_NONE;
+
+ // GL_NVX_gpu_memory_info
+ extension = "GL_NVX_gpu_memory_info";
+ if (SDL_GL_ExtensionSupported(extension))
+ {
+ glRefConfig.memInfo = MI_NVX;
+
+ ri.Printf(PRINT_ALL, result[1], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+ // GL_ATI_meminfo
+ extension = "GL_ATI_meminfo";
+ if (SDL_GL_ExtensionSupported(extension))
+ {
+ if (glRefConfig.memInfo == MI_NONE)
+ {
+ glRefConfig.memInfo = MI_ATI;
+
+ ri.Printf(PRINT_ALL, result[1], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[0], extension);
+ }
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+ glRefConfig.textureCompression = TCR_NONE;
+
+ // GL_ARB_texture_compression_rgtc
+ extension = "GL_ARB_texture_compression_rgtc";
+ if (SDL_GL_ExtensionSupported(extension))
+ {
+ bool useRgtc = r_ext_compressed_textures->integer >= 1;
+
+ if (useRgtc) glRefConfig.textureCompression |= TCR_RGTC;
+
+ ri.Printf(PRINT_ALL, result[useRgtc], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+ glRefConfig.swizzleNormalmap = r_ext_compressed_textures->integer && !(glRefConfig.textureCompression & TCR_RGTC);
+
+ // GL_ARB_texture_compression_bptc
+ extension = "GL_ARB_texture_compression_bptc";
+ if (SDL_GL_ExtensionSupported(extension))
+ {
+ bool useBptc = r_ext_compressed_textures->integer >= 2;
+
+ if (useBptc) glRefConfig.textureCompression |= TCR_BPTC;
+
+ ri.Printf(PRINT_ALL, result[useBptc], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+ // GL_EXT_direct_state_access
+ extension = "GL_EXT_direct_state_access";
+ glRefConfig.directStateAccess = qfalse;
+ if (SDL_GL_ExtensionSupported(extension))
+ {
+ glRefConfig.directStateAccess = !!r_ext_direct_state_access->integer;
+
+ // QGL_*_PROCS becomes several functions, do not remove {}
+ if (glRefConfig.directStateAccess)
+ {
+ QGL_EXT_direct_state_access_PROCS;
+ }
+
+ ri.Printf(PRINT_ALL, result[glRefConfig.directStateAccess], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+#undef GLE
+}
diff --git a/src/renderergl2/tr_extramath.cpp b/src/renderergl2/tr_extramath.cpp
new file mode 100644
index 0000000..abe75fa
--- /dev/null
+++ b/src/renderergl2/tr_extramath.cpp
@@ -0,0 +1,248 @@
+/*
+===========================================================================
+Copyright (C) 2010 James Canete (use.less01@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_extramath.c - extra math needed by the renderer not in qmath.c
+
+#include "tr_local.h"
+
+// Some matrix helper functions
+// FIXME: do these already exist in ioq3 and I don't know about them?
+
+void Mat4Zero( mat4_t out )
+{
+ out[ 0] = 0.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f;
+ out[ 1] = 0.0f; out[ 5] = 0.0f; out[ 9] = 0.0f; out[13] = 0.0f;
+ out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 0.0f; out[14] = 0.0f;
+ out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 0.0f;
+}
+
+void Mat4Identity( mat4_t out )
+{
+ out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f;
+ out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = 0.0f;
+ out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = 0.0f;
+ out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
+}
+
+void Mat4Copy( const mat4_t in, mat4_t out )
+{
+ out[ 0] = in[ 0]; out[ 4] = in[ 4]; out[ 8] = in[ 8]; out[12] = in[12];
+ out[ 1] = in[ 1]; out[ 5] = in[ 5]; out[ 9] = in[ 9]; out[13] = in[13];
+ out[ 2] = in[ 2]; out[ 6] = in[ 6]; out[10] = in[10]; out[14] = in[14];
+ out[ 3] = in[ 3]; out[ 7] = in[ 7]; out[11] = in[11]; out[15] = in[15];
+}
+
+void Mat4Multiply( const mat4_t in1, const mat4_t in2, mat4_t out )
+{
+ out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3];
+ out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3];
+ out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3];
+ out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3];
+
+ out[ 4] = in1[ 0] * in2[ 4] + in1[ 4] * in2[ 5] + in1[ 8] * in2[ 6] + in1[12] * in2[ 7];
+ out[ 5] = in1[ 1] * in2[ 4] + in1[ 5] * in2[ 5] + in1[ 9] * in2[ 6] + in1[13] * in2[ 7];
+ out[ 6] = in1[ 2] * in2[ 4] + in1[ 6] * in2[ 5] + in1[10] * in2[ 6] + in1[14] * in2[ 7];
+ out[ 7] = in1[ 3] * in2[ 4] + in1[ 7] * in2[ 5] + in1[11] * in2[ 6] + in1[15] * in2[ 7];
+
+ out[ 8] = in1[ 0] * in2[ 8] + in1[ 4] * in2[ 9] + in1[ 8] * in2[10] + in1[12] * in2[11];
+ out[ 9] = in1[ 1] * in2[ 8] + in1[ 5] * in2[ 9] + in1[ 9] * in2[10] + in1[13] * in2[11];
+ out[10] = in1[ 2] * in2[ 8] + in1[ 6] * in2[ 9] + in1[10] * in2[10] + in1[14] * in2[11];
+ out[11] = in1[ 3] * in2[ 8] + in1[ 7] * in2[ 9] + in1[11] * in2[10] + in1[15] * in2[11];
+
+ out[12] = in1[ 0] * in2[12] + in1[ 4] * in2[13] + in1[ 8] * in2[14] + in1[12] * in2[15];
+ out[13] = in1[ 1] * in2[12] + in1[ 5] * in2[13] + in1[ 9] * in2[14] + in1[13] * in2[15];
+ out[14] = in1[ 2] * in2[12] + in1[ 6] * in2[13] + in1[10] * in2[14] + in1[14] * in2[15];
+ out[15] = in1[ 3] * in2[12] + in1[ 7] * in2[13] + in1[11] * in2[14] + in1[15] * in2[15];
+}
+
+void Mat4Transform( const mat4_t in1, const vec4_t in2, vec4_t out )
+{
+ out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3];
+ out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3];
+ out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3];
+ out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3];
+}
+
+bool Mat4Compare( const mat4_t a, const mat4_t b )
+{
+ return !(a[ 0] != b[ 0] || a[ 4] != b[ 4] || a[ 8] != b[ 8] || a[12] != b[12] ||
+ a[ 1] != b[ 1] || a[ 5] != b[ 5] || a[ 9] != b[ 9] || a[13] != b[13] ||
+ a[ 2] != b[ 2] || a[ 6] != b[ 6] || a[10] != b[10] || a[14] != b[14] ||
+ a[ 3] != b[ 3] || a[ 7] != b[ 7] || a[11] != b[11] || a[15] != b[15]);
+}
+
+void Mat4Dump( const mat4_t in )
+{
+ ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 0], in[ 4], in[ 8], in[12]);
+ ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 1], in[ 5], in[ 9], in[13]);
+ ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 2], in[ 6], in[10], in[14]);
+ ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 3], in[ 7], in[11], in[15]);
+}
+
+void Mat4Translation( vec3_t vec, mat4_t out )
+{
+ out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = vec[0];
+ out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = vec[1];
+ out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = vec[2];
+ out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
+}
+
+void Mat4Ortho( float left, float right, float bottom, float top, float znear, float zfar, mat4_t out )
+{
+ out[ 0] = 2.0f / (right - left); out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = -(right + left) / (right - left);
+ out[ 1] = 0.0f; out[ 5] = 2.0f / (top - bottom); out[ 9] = 0.0f; out[13] = -(top + bottom) / (top - bottom);
+ out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 2.0f / (zfar - znear); out[14] = -(zfar + znear) / (zfar - znear);
+ out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
+}
+
+void Mat4View(vec3_t axes[3], vec3_t origin, mat4_t out)
+{
+ out[0] = axes[0][0];
+ out[1] = axes[1][0];
+ out[2] = axes[2][0];
+ out[3] = 0;
+
+ out[4] = axes[0][1];
+ out[5] = axes[1][1];
+ out[6] = axes[2][1];
+ out[7] = 0;
+
+ out[8] = axes[0][2];
+ out[9] = axes[1][2];
+ out[10] = axes[2][2];
+ out[11] = 0;
+
+ out[12] = -DotProduct(origin, axes[0]);
+ out[13] = -DotProduct(origin, axes[1]);
+ out[14] = -DotProduct(origin, axes[2]);
+ out[15] = 1;
+}
+
+void Mat4SimpleInverse( const mat4_t in, mat4_t out)
+{
+ vec3_t v;
+ float invSqrLen;
+
+ VectorCopy(in + 0, v);
+ invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
+ out[ 0] = v[0]; out[ 4] = v[1]; out[ 8] = v[2]; out[12] = -DotProduct(v, &in[12]);
+
+ VectorCopy(in + 4, v);
+ invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
+ out[ 1] = v[0]; out[ 5] = v[1]; out[ 9] = v[2]; out[13] = -DotProduct(v, &in[12]);
+
+ VectorCopy(in + 8, v);
+ invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
+ out[ 2] = v[0]; out[ 6] = v[1]; out[10] = v[2]; out[14] = -DotProduct(v, &in[12]);
+
+ out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
+}
+
+void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c)
+{
+ c[0] = a[0] * (1.0f - lerp) + b[0] * lerp;
+ c[1] = a[1] * (1.0f - lerp) + b[1] * lerp;
+ c[2] = a[2] * (1.0f - lerp) + b[2] * lerp;
+}
+
+bool SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2)
+{
+ float radiusSum = radius1 + radius2;
+ vec3_t diff;
+
+ VectorSubtract(origin1, origin2, diff);
+
+ if (DotProduct(diff, diff) <= radiusSum * radiusSum)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3)
+{
+ vec3_t diff;
+
+ VectorScale(origin1, 0.5f, origin3);
+ VectorMA(origin3, 0.5f, origin2, origin3);
+
+ VectorSubtract(origin1, origin2, diff);
+ *radius3 = VectorLength(diff) * 0.5f + MAX(radius1, radius2);
+}
+
+int NextPowerOfTwo(int in)
+{
+ int out;
+
+ for (out = 1; out < in; out <<= 1)
+ ;
+
+ return out;
+}
+
+union f32_u {
+ float f;
+ uint32_t ui;
+ struct {
+ unsigned int fraction:23;
+ unsigned int exponent:8;
+ unsigned int sign:1;
+ } pack;
+};
+
+union f16_u {
+ uint16_t ui;
+ struct {
+ unsigned int fraction:10;
+ unsigned int exponent:5;
+ unsigned int sign:1;
+ } pack;
+};
+
+uint16_t FloatToHalf(float in)
+{
+ union f32_u f32;
+ union f16_u f16;
+
+ f32.f = in;
+
+ f16.pack.exponent = CLAMP((int)(f32.pack.exponent) - 112, 0, 31);
+ f16.pack.fraction = f32.pack.fraction >> 13;
+ f16.pack.sign = f32.pack.sign;
+
+ return f16.ui;
+}
+
+float HalfToFloat(uint16_t in)
+{
+ union f32_u f32;
+ union f16_u f16;
+
+ f16.ui = in;
+
+ f32.pack.exponent = (int)(f16.pack.exponent) + 112;
+ f32.pack.fraction = f16.pack.fraction << 13;
+ f32.pack.sign = f16.pack.sign;
+
+ return f32.f;
+}
diff --git a/src/renderergl2/tr_extramath.h b/src/renderergl2/tr_extramath.h
new file mode 100644
index 0000000..20c9278
--- /dev/null
+++ b/src/renderergl2/tr_extramath.h
@@ -0,0 +1,104 @@
+/*
+===========================================================================
+Copyright (C) 2010 James Canete (use.less01@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_extramath.h
+
+#ifndef __TR_EXTRAMATH_H__
+#define __TR_EXTRAMATH_H__
+
+typedef vec_t mat4_t[16];
+typedef int ivec2_t[2];
+typedef int ivec3_t[3];
+typedef int ivec4_t[4];
+
+void Mat4Zero( mat4_t out );
+void Mat4Identity( mat4_t out );
+void Mat4Copy( const mat4_t in, mat4_t out );
+void Mat4Multiply( const mat4_t in1, const mat4_t in2, mat4_t out );
+void Mat4Transform( const mat4_t in1, const vec4_t in2, vec4_t out );
+bool Mat4Compare(const mat4_t a, const mat4_t b);
+void Mat4Dump( const mat4_t in );
+void Mat4Translation( vec3_t vec, mat4_t out );
+void Mat4Ortho( float left, float right, float bottom, float top, float znear, float zfar, mat4_t out );
+void Mat4View(vec3_t axes[3], vec3_t origin, mat4_t out);
+void Mat4SimpleInverse( const mat4_t in, mat4_t out);
+
+#define VectorCopy2(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1])
+#define VectorSet2(v,x,y) ((v)[0]=(x),(v)[1]=(y));
+
+#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
+#define VectorSet4(v,x,y,z,w) ((v)[0]=(x),(v)[1]=(y),(v)[2]=(z),(v)[3]=(w))
+#define DotProduct4(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2] + (a)[3]*(b)[3])
+#define VectorScale4(a,b,c) ((c)[0]=(a)[0]*(b),(c)[1]=(a)[1]*(b),(c)[2]=(a)[2]*(b),(c)[3]=(a)[3]*(b))
+
+#define VectorCopy5(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3],(b)[4]=(a)[4])
+
+#define OffsetByteToFloat(a) ((float)(a) * 1.0f/127.5f - 1.0f)
+#define FloatToOffsetByte(a) (byte)((a) * 127.5f + 128.0f)
+#define ByteToFloat(a) ((float)(a) * 1.0f/255.0f)
+#define FloatToByte(a) (byte)((a) * 255.0f)
+
+static ID_INLINE int VectorCompare4(const vec4_t v1, const vec4_t v2)
+{
+ if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3])
+ {
+ return 0;
+ }
+ return 1;
+}
+
+static ID_INLINE int VectorCompare5(const vec5_t v1, const vec5_t v2)
+{
+ if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3] || v1[4] != v2[4])
+ {
+ return 0;
+ }
+ return 1;
+}
+
+void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c);
+
+
+bool SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2);
+void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3);
+
+#ifndef SGN
+#define SGN(x) (((x) >= 0) ? !!(x) : -1)
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef CLAMP
+#define CLAMP(a,b,c) MIN(MAX((a),(b)),(c))
+#endif
+
+int NextPowerOfTwo(int in);
+unsigned short FloatToHalf(float in);
+float HalfToFloat(unsigned short in);
+
+#endif
diff --git a/src/renderergl2/tr_extratypes.h b/src/renderergl2/tr_extratypes.h
new file mode 100644
index 0000000..c5c99c8
--- /dev/null
+++ b/src/renderergl2/tr_extratypes.h
@@ -0,0 +1,40 @@
+/*
+===========================================================================
+Copyright (C) 2009-2011 Andrei Drexler, Richard Allen, James Canete
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifndef __TR_EXTRATYPES_H__
+#define __TR_EXTRATYPES_H__
+
+// tr_extratypes.h, for mods that want to extend tr_types.h without losing compatibility with original VMs
+
+// extra refdef flags start at 0x0008
+#define RDF_NOFOG 0x0008 // don't apply fog to polys added using RE_AddPolyToScene
+#define RDF_EXTRA 0x0010 // Makro - refdefex_t to follow after refdef_t
+#define RDF_SUNLIGHT 0x0020 // SmileTheory - render sunlight and shadows
+
+typedef struct {
+ float blurFactor;
+ float sunDir[3];
+ float sunCol[3];
+ float sunAmbCol[3];
+} refdefex_t;
+
+#endif
diff --git a/src/renderergl2/tr_fbo.cpp b/src/renderergl2/tr_fbo.cpp
new file mode 100644
index 0000000..5120540
--- /dev/null
+++ b/src/renderergl2/tr_fbo.cpp
@@ -0,0 +1,659 @@
+/*
+===========================================================================
+Copyright (C) 2006 Kirk Barnes
+Copyright (C) 2006-2008 Robert Beckebans <trebor_7@users.sourceforge.net>
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_fbo.c
+#include "tr_local.h"
+
+#include "tr_dsa.h"
+
+/*
+=============
+R_CheckFBO
+=============
+*/
+bool R_CheckFBO(const FBO_t * fbo)
+{
+ GLenum code = qglCheckNamedFramebufferStatusEXT(fbo->frameBuffer, GL_FRAMEBUFFER);
+
+ if(code == GL_FRAMEBUFFER_COMPLETE)
+ return true;
+
+ // an error occured
+ switch (code)
+ {
+ case GL_FRAMEBUFFER_UNSUPPORTED:
+ ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Unsupported framebuffer format\n", fbo->name);
+ break;
+
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+ ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete attachment\n", fbo->name);
+ break;
+
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+ ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing attachment\n", fbo->name);
+ break;
+
+ case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
+ ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing draw buffer\n", fbo->name);
+ break;
+
+ case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
+ ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing read buffer\n", fbo->name);
+ break;
+
+ default:
+ ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) unknown error 0x%X\n", fbo->name, code);
+ break;
+ }
+
+ return false;
+}
+
+/*
+============
+FBO_Create
+============
+*/
+FBO_t *FBO_Create(const char *name, int width, int height)
+{
+ FBO_t *fbo;
+
+ if(strlen(name) >= MAX_QPATH)
+ {
+ ri.Error(ERR_DROP, "FBO_Create: \"%s\" is too long", name);
+ }
+
+ if(width <= 0 || width > glRefConfig.maxRenderbufferSize)
+ {
+ ri.Error(ERR_DROP, "FBO_Create: bad width %i", width);
+ }
+
+ if(height <= 0 || height > glRefConfig.maxRenderbufferSize)
+ {
+ ri.Error(ERR_DROP, "FBO_Create: bad height %i", height);
+ }
+
+ if(tr.numFBOs == MAX_FBOS)
+ {
+ ri.Error(ERR_DROP, "FBO_Create: MAX_FBOS hit");
+ }
+
+ fbo = tr.fbos[tr.numFBOs] = (FBO_t*)ri.Hunk_Alloc(sizeof(*fbo), h_low);
+ Q_strncpyz(fbo->name, name, sizeof(fbo->name));
+ fbo->index = tr.numFBOs++;
+ fbo->width = width;
+ fbo->height = height;
+
+ qglGenFramebuffers(1, &fbo->frameBuffer);
+
+ return fbo;
+}
+
+/*
+=================
+FBO_CreateBuffer
+=================
+*/
+void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
+{
+ uint32_t *pRenderBuffer;
+ GLenum attachment;
+ bool absent;
+
+ switch(format)
+ {
+ case GL_RGB:
+ case GL_RGBA:
+ case GL_RGB8:
+ case GL_RGBA8:
+ case GL_RGB16F_ARB:
+ case GL_RGBA16F_ARB:
+ case GL_RGB32F_ARB:
+ case GL_RGBA32F_ARB:
+ fbo->colorFormat = format;
+ pRenderBuffer = &fbo->colorBuffers[index];
+ attachment = GL_COLOR_ATTACHMENT0 + index;
+ break;
+
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_COMPONENT16_ARB:
+ case GL_DEPTH_COMPONENT24_ARB:
+ case GL_DEPTH_COMPONENT32_ARB:
+ fbo->depthFormat = format;
+ pRenderBuffer = &fbo->depthBuffer;
+ attachment = GL_DEPTH_ATTACHMENT;
+ break;
+
+ case GL_STENCIL_INDEX:
+ case GL_STENCIL_INDEX1:
+ case GL_STENCIL_INDEX4:
+ case GL_STENCIL_INDEX8:
+ case GL_STENCIL_INDEX16:
+ fbo->stencilFormat = format;
+ pRenderBuffer = &fbo->stencilBuffer;
+ attachment = GL_STENCIL_ATTACHMENT;
+ break;
+
+ case GL_DEPTH_STENCIL:
+ case GL_DEPTH24_STENCIL8:
+ fbo->packedDepthStencilFormat = format;
+ pRenderBuffer = &fbo->packedDepthStencilBuffer;
+ attachment = 0; // special for stencil and depth
+ break;
+
+ default:
+ ri.Printf(PRINT_WARNING, "FBO_CreateBuffer: invalid format %d\n", format);
+ return;
+ }
+
+ absent = *pRenderBuffer == 0;
+ if (absent)
+ qglGenRenderbuffers(1, pRenderBuffer);
+
+ if (multisample && glRefConfig.framebufferMultisample)
+ qglNamedRenderbufferStorageMultisampleEXT(*pRenderBuffer, multisample, format, fbo->width, fbo->height);
+ else
+ qglNamedRenderbufferStorageEXT(*pRenderBuffer, format, fbo->width, fbo->height);
+
+ if(absent)
+ {
+ if (attachment == 0)
+ {
+ qglNamedFramebufferRenderbufferEXT(fbo->frameBuffer, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *pRenderBuffer);
+ qglNamedFramebufferRenderbufferEXT(fbo->frameBuffer, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *pRenderBuffer);
+ }
+ else
+ {
+ qglNamedFramebufferRenderbufferEXT(fbo->frameBuffer, attachment, GL_RENDERBUFFER, *pRenderBuffer);
+ }
+ }
+}
+
+
+/*
+=================
+FBO_AttachImage
+=================
+*/
+void FBO_AttachImage(FBO_t *fbo, image_t *image, GLenum attachment, GLuint cubemapside)
+{
+ GLenum target = GL_TEXTURE_2D;
+ int index;
+
+ if (image->flags & IMGFLAG_CUBEMAP)
+ target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + cubemapside;
+
+ qglNamedFramebufferTexture2DEXT(fbo->frameBuffer, attachment, target, image->texnum, 0);
+ index = attachment - GL_COLOR_ATTACHMENT0;
+ if (index >= 0 && index <= 15)
+ fbo->colorImage[index] = image;
+}
+
+
+/*
+============
+FBO_Bind
+============
+*/
+void FBO_Bind(FBO_t * fbo)
+{
+ if (!glRefConfig.framebufferObject)
+ {
+ ri.Printf(PRINT_WARNING, "FBO_Bind() called without framebuffers enabled!\n");
+ return;
+ }
+
+ if (glState.currentFBO == fbo)
+ return;
+
+ if (r_logFile->integer)
+ {
+ // don't just call LogComment, or we will get a call to va() every frame!
+ GLimp_LogComment((char*)va("--- FBO_Bind( %s ) ---\n", fbo ? fbo->name : "NULL"));
+ }
+
+ GL_BindFramebuffer(GL_FRAMEBUFFER, fbo ? fbo->frameBuffer : 0);
+ glState.currentFBO = fbo;
+}
+
+/*
+============
+FBO_Init
+============
+*/
+void FBO_Init(void)
+{
+ int i;
+ int hdrFormat, multisample = 0;
+
+ ri.Printf(PRINT_ALL, "------- FBO_Init -------\n");
+
+ if(!glRefConfig.framebufferObject)
+ return;
+
+ tr.numFBOs = 0;
+
+ GL_CheckErrors();
+
+ R_IssuePendingRenderCommands();
+
+ hdrFormat = GL_RGBA8;
+ if (r_hdr->integer && glRefConfig.textureFloat)
+ hdrFormat = GL_RGBA16F_ARB;
+
+ if (glRefConfig.framebufferMultisample)
+ qglGetIntegerv(GL_MAX_SAMPLES, &multisample);
+
+ if (r_ext_framebuffer_multisample->integer < multisample)
+ multisample = r_ext_framebuffer_multisample->integer;
+
+ if (multisample < 2 || !glRefConfig.framebufferBlit)
+ multisample = 0;
+
+ if (multisample != r_ext_framebuffer_multisample->integer)
+ ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample);
+
+ // only create a render FBO if we need to resolve MSAA or do HDR
+ // otherwise just render straight to the screen (tr.renderFbo = NULL)
+ if (multisample && glRefConfig.framebufferMultisample)
+ {
+ tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
+ FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample);
+ FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24, 0, multisample);
+ R_CheckFBO(tr.renderFbo);
+
+ tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height);
+ FBO_AttachImage(tr.msaaResolveFbo, tr.renderImage, GL_COLOR_ATTACHMENT0, 0);
+ FBO_AttachImage(tr.msaaResolveFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
+ R_CheckFBO(tr.msaaResolveFbo);
+ }
+ else if (r_hdr->integer)
+ {
+ tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
+ FBO_AttachImage(tr.renderFbo, tr.renderImage, GL_COLOR_ATTACHMENT0, 0);
+ FBO_AttachImage(tr.renderFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
+ R_CheckFBO(tr.renderFbo);
+ }
+
+ // clear render buffer
+ // this fixes the corrupt screen bug with r_hdr 1 on older hardware
+ if (tr.renderFbo)
+ {
+ GL_BindFramebuffer(GL_FRAMEBUFFER, tr.renderFbo->frameBuffer);
+ qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+ }
+
+ if (tr.screenScratchImage)
+ {
+ tr.screenScratchFbo = FBO_Create("screenScratch", tr.screenScratchImage->width, tr.screenScratchImage->height);
+ FBO_AttachImage(tr.screenScratchFbo, tr.screenScratchImage, GL_COLOR_ATTACHMENT0, 0);
+ FBO_AttachImage(tr.screenScratchFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
+ R_CheckFBO(tr.screenScratchFbo);
+ }
+
+ if (tr.sunRaysImage)
+ {
+ tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height);
+ FBO_AttachImage(tr.sunRaysFbo, tr.sunRaysImage, GL_COLOR_ATTACHMENT0, 0);
+ FBO_AttachImage(tr.sunRaysFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
+ R_CheckFBO(tr.sunRaysFbo);
+ }
+
+ if (MAX_DRAWN_PSHADOWS && tr.pshadowMaps[0])
+ {
+ for( i = 0; i < MAX_DRAWN_PSHADOWS; i++)
+ {
+ tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height);
+ // FIXME: this next line wastes 16mb with 16x512x512 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments
+ FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0);
+ FBO_AttachImage(tr.pshadowFbos[i], tr.pshadowMaps[i], GL_DEPTH_ATTACHMENT, 0);
+ R_CheckFBO(tr.pshadowFbos[i]);
+ }
+ }
+
+ if (tr.sunShadowDepthImage[0])
+ {
+ for (i = 0; i < 4; i++)
+ {
+ tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height);
+ // FIXME: this next line wastes 16mb with 4x1024x1024 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments
+ // This at least gets sun shadows working on older GPUs (Intel)
+ FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0);
+ FBO_AttachImage(tr.sunShadowFbo[i], tr.sunShadowDepthImage[i], GL_DEPTH_ATTACHMENT, 0);
+ R_CheckFBO(tr.sunShadowFbo[i]);
+ }
+ }
+
+ if (tr.screenShadowImage)
+ {
+ tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height);
+ FBO_AttachImage(tr.screenShadowFbo, tr.screenShadowImage, GL_COLOR_ATTACHMENT0, 0);
+ R_CheckFBO(tr.screenShadowFbo);
+ }
+
+ if (tr.textureScratchImage[0])
+ {
+ for (i = 0; i < 2; i++)
+ {
+ tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
+ FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0, 0);
+ R_CheckFBO(tr.textureScratchFbo[i]);
+ }
+ }
+
+ if (tr.calcLevelsImage)
+ {
+ tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height);
+ FBO_AttachImage(tr.calcLevelsFbo, tr.calcLevelsImage, GL_COLOR_ATTACHMENT0, 0);
+ R_CheckFBO(tr.calcLevelsFbo);
+ }
+
+ if (tr.targetLevelsImage)
+ {
+ tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height);
+ FBO_AttachImage(tr.targetLevelsFbo, tr.targetLevelsImage, GL_COLOR_ATTACHMENT0, 0);
+ R_CheckFBO(tr.targetLevelsFbo);
+ }
+
+ if (tr.quarterImage[0])
+ {
+ for (i = 0; i < 2; i++)
+ {
+ tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
+ FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0, 0);
+ R_CheckFBO(tr.quarterFbo[i]);
+ }
+ }
+
+ if (tr.hdrDepthImage)
+ {
+ tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height);
+ FBO_AttachImage(tr.hdrDepthFbo, tr.hdrDepthImage, GL_COLOR_ATTACHMENT0, 0);
+ R_CheckFBO(tr.hdrDepthFbo);
+ }
+
+ if (tr.screenSsaoImage)
+ {
+ tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height);
+ FBO_AttachImage(tr.screenSsaoFbo, tr.screenSsaoImage, GL_COLOR_ATTACHMENT0, 0);
+ R_CheckFBO(tr.screenSsaoFbo);
+ }
+
+ if (tr.renderCubeImage)
+ {
+ tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height);
+ FBO_AttachImage(tr.renderCubeFbo, tr.renderCubeImage, GL_COLOR_ATTACHMENT0, 0);
+ FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
+ R_CheckFBO(tr.renderCubeFbo);
+ }
+
+ GL_CheckErrors();
+
+ GL_BindFramebuffer(GL_FRAMEBUFFER, 0);
+ glState.currentFBO = NULL;
+}
+
+/*
+============
+FBO_Shutdown
+============
+*/
+void FBO_Shutdown(void)
+{
+ int i, j;
+ FBO_t *fbo;
+
+ ri.Printf(PRINT_ALL, "------- FBO_Shutdown -------\n");
+
+ if(!glRefConfig.framebufferObject)
+ return;
+
+ FBO_Bind(NULL);
+
+ for(i = 0; i < tr.numFBOs; i++)
+ {
+ fbo = tr.fbos[i];
+
+ for(j = 0; j < glRefConfig.maxColorAttachments; j++)
+ {
+ if(fbo->colorBuffers[j])
+ qglDeleteRenderbuffers(1, &fbo->colorBuffers[j]);
+ }
+
+ if(fbo->depthBuffer)
+ qglDeleteRenderbuffers(1, &fbo->depthBuffer);
+
+ if(fbo->stencilBuffer)
+ qglDeleteRenderbuffers(1, &fbo->stencilBuffer);
+
+ if(fbo->frameBuffer)
+ qglDeleteFramebuffers(1, &fbo->frameBuffer);
+ }
+}
+
+/*
+============
+R_FBOList_f
+============
+*/
+void R_FBOList_f(void)
+{
+ int i;
+ FBO_t *fbo;
+
+ if(!glRefConfig.framebufferObject)
+ {
+ ri.Printf(PRINT_ALL, "GL_EXT_framebuffer_object is not available.\n");
+ return;
+ }
+
+ ri.Printf(PRINT_ALL, " size name\n");
+ ri.Printf(PRINT_ALL, "----------------------------------------------------------\n");
+
+ for(i = 0; i < tr.numFBOs; i++)
+ {
+ fbo = tr.fbos[i];
+
+ ri.Printf(PRINT_ALL, " %4i: %4i %4i %s\n", i, fbo->width, fbo->height, fbo->name);
+ }
+
+ ri.Printf(PRINT_ALL, " %i FBOs\n", tr.numFBOs);
+}
+
+void FBO_BlitFromTexture(struct image_s *src, vec4_t inSrcTexCorners, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend)
+{
+ ivec4_t dstBox;
+ vec4_t color;
+ vec4_t quadVerts[4];
+ vec2_t texCoords[4];
+ vec2_t invTexRes;
+ FBO_t *oldFbo = glState.currentFBO;
+ mat4_t projection;
+ int width, height;
+
+ if (!src)
+ {
+ ri.Printf(PRINT_WARNING, "Tried to blit from a NULL texture!\n");
+ return;
+ }
+
+ width = dst ? dst->width : glConfig.vidWidth;
+ height = dst ? dst->height : glConfig.vidHeight;
+
+ if (inSrcTexCorners)
+ {
+ VectorSet2(texCoords[0], inSrcTexCorners[0], inSrcTexCorners[1]);
+ VectorSet2(texCoords[1], inSrcTexCorners[2], inSrcTexCorners[1]);
+ VectorSet2(texCoords[2], inSrcTexCorners[2], inSrcTexCorners[3]);
+ VectorSet2(texCoords[3], inSrcTexCorners[0], inSrcTexCorners[3]);
+ }
+ else
+ {
+ VectorSet2(texCoords[0], 0.0f, 1.0f);
+ VectorSet2(texCoords[1], 1.0f, 1.0f);
+ VectorSet2(texCoords[2], 1.0f, 0.0f);
+ VectorSet2(texCoords[3], 0.0f, 0.0f);
+ }
+
+ // framebuffers are 0 bottom, Y up.
+ if (inDstBox)
+ {
+ dstBox[0] = inDstBox[0];
+ dstBox[1] = height - inDstBox[1] - inDstBox[3];
+ dstBox[2] = inDstBox[0] + inDstBox[2];
+ dstBox[3] = height - inDstBox[1];
+ }
+ else
+ {
+ VectorSet4(dstBox, 0, height, width, 0);
+ }
+
+ if (inSrcTexScale)
+ {
+ VectorCopy2(inSrcTexScale, invTexRes);
+ }
+ else
+ {
+ VectorSet2(invTexRes, 1.0f, 1.0f);
+ }
+
+ if (inColor)
+ {
+ VectorCopy4(inColor, color);
+ }
+ else
+ {
+ VectorCopy4(colorWhite, color);
+ }
+
+ if (!shaderProgram)
+ {
+ shaderProgram = &tr.textureColorShader;
+ }
+
+ FBO_Bind(dst);
+
+ qglViewport( 0, 0, width, height );
+ qglScissor( 0, 0, width, height );
+
+ Mat4Ortho(0, width, height, 0, 0, 1, projection);
+
+ GL_Cull( CT_TWO_SIDED );
+
+ GL_BindToTMU(src, TB_COLORMAP);
+
+ VectorSet4(quadVerts[0], dstBox[0], dstBox[1], 0.0f, 1.0f);
+ VectorSet4(quadVerts[1], dstBox[2], dstBox[1], 0.0f, 1.0f);
+ VectorSet4(quadVerts[2], dstBox[2], dstBox[3], 0.0f, 1.0f);
+ VectorSet4(quadVerts[3], dstBox[0], dstBox[3], 0.0f, 1.0f);
+
+ invTexRes[0] /= src->width;
+ invTexRes[1] /= src->height;
+
+ GL_State( blend );
+
+ GLSL_BindProgram(shaderProgram);
+
+ GLSL_SetUniformMat4(shaderProgram, UNIFORM_MODELVIEWPROJECTIONMATRIX, projection);
+ GLSL_SetUniformVec4(shaderProgram, UNIFORM_COLOR, color);
+ GLSL_SetUniformVec2(shaderProgram, UNIFORM_INVTEXRES, invTexRes);
+ GLSL_SetUniformVec2(shaderProgram, UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax);
+ GLSL_SetUniformVec3(shaderProgram, UNIFORM_TONEMINAVGMAXLINEAR, tr.refdef.toneMinAvgMaxLinear);
+
+ RB_InstantQuad2(quadVerts, texCoords);
+
+ FBO_Bind(oldFbo);
+}
+
+void FBO_Blit(FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend)
+{
+ vec4_t srcTexCorners;
+
+ if (!src)
+ {
+ ri.Printf(PRINT_WARNING, "Tried to blit from a NULL FBO!\n");
+ return;
+ }
+
+ if (inSrcBox)
+ {
+ srcTexCorners[0] = inSrcBox[0] / (float)src->width;
+ srcTexCorners[1] = (inSrcBox[1] + inSrcBox[3]) / (float)src->height;
+ srcTexCorners[2] = (inSrcBox[0] + inSrcBox[2]) / (float)src->width;
+ srcTexCorners[3] = inSrcBox[1] / (float)src->height;
+ }
+ else
+ {
+ VectorSet4(srcTexCorners, 0.0f, 0.0f, 1.0f, 1.0f);
+ }
+
+ FBO_BlitFromTexture(src->colorImage[0], srcTexCorners, srcTexScale, dst, dstBox, shaderProgram, color, blend | GLS_DEPTHTEST_DISABLE);
+}
+
+void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter)
+{
+ ivec4_t srcBoxFinal, dstBoxFinal;
+ GLuint srcFb, dstFb;
+
+ if (!glRefConfig.framebufferBlit)
+ {
+ FBO_Blit(src, srcBox, NULL, dst, dstBox, NULL, NULL, 0);
+ return;
+ }
+
+ srcFb = src ? src->frameBuffer : 0;
+ dstFb = dst ? dst->frameBuffer : 0;
+
+ if (!srcBox)
+ {
+ int width = src ? src->width : glConfig.vidWidth;
+ int height = src ? src->height : glConfig.vidHeight;
+
+ VectorSet4(srcBoxFinal, 0, 0, width, height);
+ }
+ else
+ {
+ VectorSet4(srcBoxFinal, srcBox[0], srcBox[1], srcBox[0] + srcBox[2], srcBox[1] + srcBox[3]);
+ }
+
+ if (!dstBox)
+ {
+ int width = dst ? dst->width : glConfig.vidWidth;
+ int height = dst ? dst->height : glConfig.vidHeight;
+
+ VectorSet4(dstBoxFinal, 0, 0, width, height);
+ }
+ else
+ {
+ VectorSet4(dstBoxFinal, dstBox[0], dstBox[1], dstBox[0] + dstBox[2], dstBox[1] + dstBox[3]);
+ }
+
+ GL_BindFramebuffer(GL_READ_FRAMEBUFFER, srcFb);
+ GL_BindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFb);
+ qglBlitFramebuffer(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3],
+ dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3],
+ buffers, filter);
+
+ GL_BindFramebuffer(GL_FRAMEBUFFER, 0);
+ glState.currentFBO = NULL;
+}
diff --git a/src/renderergl2/tr_fbo.h b/src/renderergl2/tr_fbo.h
new file mode 100644
index 0000000..efd317b
--- /dev/null
+++ b/src/renderergl2/tr_fbo.h
@@ -0,0 +1,66 @@
+/*
+===========================================================================
+Copyright (C) 2010 James Canete (use.less01@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_fbo.h
+
+#ifndef __TR_FBO_H__
+#define __TR_FBO_H__
+
+struct image_s;
+struct shaderProgram_s;
+
+typedef struct FBO_s
+{
+ char name[MAX_QPATH];
+
+ int index;
+
+ uint32_t frameBuffer;
+
+ uint32_t colorBuffers[16];
+ int colorFormat;
+ struct image_s *colorImage[16];
+
+ uint32_t depthBuffer;
+ int depthFormat;
+
+ uint32_t stencilBuffer;
+ int stencilFormat;
+
+ uint32_t packedDepthStencilBuffer;
+ int packedDepthStencilFormat;
+
+ int width;
+ int height;
+} FBO_t;
+
+void FBO_AttachImage(FBO_t *fbo, image_t *image, GLenum attachment, GLuint cubemapside);
+void FBO_Bind(FBO_t *fbo);
+void FBO_Init(void);
+void FBO_Shutdown(void);
+
+void FBO_BlitFromTexture(struct image_s *src, vec4_t inSrcTexCorners, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend);
+void FBO_Blit(FBO_t *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend);
+void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter);
+
+
+#endif
diff --git a/src/renderergl2/tr_flares.cpp b/src/renderergl2/tr_flares.cpp
new file mode 100644
index 0000000..e2f38c8
--- /dev/null
+++ b/src/renderergl2/tr_flares.cpp
@@ -0,0 +1,554 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_flares.c
+
+#include "tr_local.h"
+
+/*
+=============================================================================
+
+LIGHT FLARES
+
+A light flare is an effect that takes place inside the eye when bright light
+sources are visible. The size of the flare reletive to the screen is nearly
+constant, irrespective of distance, but the intensity should be proportional to the
+projected area of the light source.
+
+A surface that has been flagged as having a light flare will calculate the depth
+buffer value that its midpoint should have when the surface is added.
+
+After all opaque surfaces have been rendered, the depth buffer is read back for
+each flare in view. If the point has not been obscured by a closer surface, the
+flare should be drawn.
+
+Surfaces that have a repeated texture should never be flagged as flaring, because
+there will only be a single flare added at the midpoint of the polygon.
+
+To prevent abrupt popping, the intensity of the flare is interpolated up and
+down as it changes visibility. This involves scene to scene state, unlike almost
+all other aspects of the renderer, and is complicated by the fact that a single
+frame may have multiple scenes.
+
+RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially
+up to five or more times in a frame with 3D status bar icons).
+
+=============================================================================
+*/
+
+
+// flare states maintain visibility over multiple frames for fading
+// layers: view, mirror, menu
+typedef struct flare_s {
+ struct flare_s *next; // for active chain
+
+ int addedFrame;
+
+ bool inPortal; // true if in a portal view of the scene
+ int frameSceneNum;
+ void *surface;
+ int fogNum;
+
+ int fadeTime;
+
+ bool visible; // state of last test
+ float drawIntensity; // may be non 0 even if !visible due to fading
+
+ int windowX, windowY;
+ float eyeZ;
+
+ vec3_t origin;
+ vec3_t color;
+} flare_t;
+
+#define MAX_FLARES 128
+
+flare_t r_flareStructs[MAX_FLARES];
+flare_t *r_activeFlares, *r_inactiveFlares;
+
+int flareCoeff;
+
+/*
+==================
+R_SetFlareCoeff
+==================
+*/
+static void R_SetFlareCoeff( void ) {
+
+ if(r_flareCoeff->value == 0.0f)
+ flareCoeff = atof(FLARE_STDCOEFF);
+ else
+ flareCoeff = r_flareCoeff->value;
+}
+
+/*
+==================
+R_ClearFlares
+==================
+*/
+void R_ClearFlares( void ) {
+ int i;
+
+ Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) );
+ r_activeFlares = NULL;
+ r_inactiveFlares = NULL;
+
+ for ( i = 0 ; i < MAX_FLARES ; i++ ) {
+ r_flareStructs[i].next = r_inactiveFlares;
+ r_inactiveFlares = &r_flareStructs[i];
+ }
+
+ R_SetFlareCoeff();
+}
+
+
+/*
+==================
+RB_AddFlare
+
+This is called at surface tesselation time
+==================
+*/
+void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) {
+ int i;
+ flare_t *f;
+ vec3_t local;
+ float d = 1;
+ vec4_t eye, clip, normalized, window;
+
+ backEnd.pc.c_flareAdds++;
+
+ if(normal && (normal[0] || normal[1] || normal[2]))
+ {
+ VectorSubtract( backEnd.viewParms.orientation.origin, point, local );
+ VectorNormalizeFast(local);
+ d = DotProduct(local, normal);
+
+ // If the viewer is behind the flare don't add it.
+ if(d < 0)
+ return;
+ }
+
+ // if the point is off the screen, don't bother adding it
+ // calculate screen coordinates and depth
+ R_TransformModelToClip( point, backEnd.orientation.modelMatrix,
+ backEnd.viewParms.projectionMatrix, eye, clip );
+
+ // check to see if the point is completely off screen
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) {
+ return;
+ }
+ }
+
+ R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window );
+
+ if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
+ || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) {
+ return; // shouldn't happen, since we check the clip[] above, except for FP rounding
+ }
+
+ // see if a flare with a matching surface, scene, and view exists
+ for ( f = r_activeFlares ; f ; f = f->next ) {
+ if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum
+ && f->inPortal == backEnd.viewParms.isPortal ) {
+ break;
+ }
+ }
+
+ // allocate a new one
+ if (!f ) {
+ if ( !r_inactiveFlares ) {
+ // the list is completely full
+ return;
+ }
+ f = r_inactiveFlares;
+ r_inactiveFlares = r_inactiveFlares->next;
+ f->next = r_activeFlares;
+ r_activeFlares = f;
+
+ f->surface = surface;
+ f->frameSceneNum = backEnd.viewParms.frameSceneNum;
+ f->inPortal = backEnd.viewParms.isPortal;
+ f->addedFrame = -1;
+ }
+
+ if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) {
+ f->visible = false;
+ f->fadeTime = backEnd.refdef.time - 2000;
+ }
+
+ f->addedFrame = backEnd.viewParms.frameCount;
+ f->fogNum = fogNum;
+
+ VectorCopy(point, f->origin);
+ VectorCopy( color, f->color );
+
+ // fade the intensity of the flare down as the
+ // light surface turns away from the viewer
+ VectorScale( f->color, d, f->color );
+
+ // save info needed to test
+ f->windowX = backEnd.viewParms.viewportX + window[0];
+ f->windowY = backEnd.viewParms.viewportY + window[1];
+
+ f->eyeZ = eye[2];
+}
+
+/*
+==================
+RB_AddDlightFlares
+==================
+*/
+void RB_AddDlightFlares( void ) {
+ dlight_t *l;
+ int i, j, k;
+ fog_t *fog = NULL;
+
+ if ( !r_flares->integer ) {
+ return;
+ }
+
+ l = backEnd.refdef.dlights;
+
+ if(tr.world)
+ fog = tr.world->fogs;
+
+ for (i=0 ; i<backEnd.refdef.num_dlights ; i++, l++) {
+
+ if(fog)
+ {
+ // find which fog volume the light is in
+ for ( j = 1 ; j < tr.world->numfogs ; j++ ) {
+ fog = &tr.world->fogs[j];
+ for ( k = 0 ; k < 3 ; k++ ) {
+ if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) {
+ break;
+ }
+ }
+ if ( k == 3 ) {
+ break;
+ }
+ }
+ if ( j == tr.world->numfogs ) {
+ j = 0;
+ }
+ }
+ else
+ j = 0;
+
+ RB_AddFlare( (void *)l, j, l->origin, l->color, NULL );
+ }
+}
+
+/*
+===============================================================================
+
+FLARE BACK END
+
+===============================================================================
+*/
+
+/*
+==================
+RB_TestFlare
+==================
+*/
+void RB_TestFlare( flare_t *f ) {
+ float depth;
+ bool visible;
+ float fade;
+ float screenZ;
+ FBO_t *oldFbo;
+
+ backEnd.pc.c_flareTests++;
+
+ // doing a readpixels is as good as doing a glFinish(), so
+ // don't bother with another sync
+ glState.finishCalled = false;
+
+ // if we're doing multisample rendering, read from the correct FBO
+ oldFbo = glState.currentFBO;
+ if (tr.msaaResolveFbo)
+ {
+ FBO_Bind(tr.msaaResolveFbo);
+ }
+
+ // read back the z buffer contents
+ qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth );
+
+ // if we're doing multisample rendering, switch to the old FBO
+ if (tr.msaaResolveFbo)
+ {
+ FBO_Bind(oldFbo);
+ }
+
+ screenZ = backEnd.viewParms.projectionMatrix[14] /
+ ( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] );
+
+ visible = ( -f->eyeZ - -screenZ ) < 24;
+
+ if ( visible ) {
+ if ( !f->visible ) {
+ f->visible = true;
+ f->fadeTime = backEnd.refdef.time - 1;
+ }
+ fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value;
+ } else {
+ if ( f->visible ) {
+ f->visible = false;
+ f->fadeTime = backEnd.refdef.time - 1;
+ }
+ fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value;
+ }
+
+ if ( fade < 0 ) {
+ fade = 0;
+ }
+ if ( fade > 1 ) {
+ fade = 1;
+ }
+
+ f->drawIntensity = fade;
+}
+
+
+/*
+==================
+RB_RenderFlare
+==================
+*/
+void RB_RenderFlare( flare_t *f ) {
+ float size;
+ vec3_t color;
+ int iColor[3];
+ float distance, intensity, factor;
+ byte fogFactors[3] = {255, 255, 255};
+
+ backEnd.pc.c_flareRenders++;
+
+ // We don't want too big values anyways when dividing by distance.
+ if(f->eyeZ > -1.0f)
+ distance = 1.0f;
+ else
+ distance = -f->eyeZ;
+
+ // calculate the flare size..
+ size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance );
+
+/*
+ * This is an alternative to intensity scaling. It changes the size of the flare on screen instead
+ * with growing distance. See in the description at the top why this is not the way to go.
+ // size will change ~ 1/r.
+ size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f));
+*/
+
+/*
+ * As flare sizes stay nearly constant with increasing distance we must decrease the intensity
+ * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be
+ * got by considering the ratio of
+ * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare)
+ * An important requirement is:
+ * intensity <= 1 for all distances.
+ *
+ * The formula used here to compute the intensity is as follows:
+ * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2
+ * As you can see, the intensity will have a max. of 1 when the distance is 0.
+ * The coefficient flareCoeff will determine the falloff speed with increasing distance.
+ */
+
+ factor = distance + size * sqrt(flareCoeff);
+
+ intensity = flareCoeff * size * size / (factor * factor);
+
+ VectorScale(f->color, f->drawIntensity * intensity, color);
+
+ // Calculations for fogging
+ if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs)
+ {
+ tess.numVertexes = 1;
+ VectorCopy(f->origin, tess.xyz[0]);
+ tess.fogNum = f->fogNum;
+
+ RB_CalcModulateColorsByFog(fogFactors);
+
+ // We don't need to render the flare if colors are 0 anyways.
+ if(!(fogFactors[0] || fogFactors[1] || fogFactors[2]))
+ return;
+ }
+
+ iColor[0] = color[0] * fogFactors[0] * 257;
+ iColor[1] = color[1] * fogFactors[1] * 257;
+ iColor[2] = color[2] * fogFactors[2] * 257;
+
+ RB_BeginSurface( tr.flareShader, f->fogNum, 0 );
+
+ // FIXME: use quadstamp?
+ tess.xyz[tess.numVertexes][0] = f->windowX - size;
+ tess.xyz[tess.numVertexes][1] = f->windowY - size;
+ tess.texCoords[tess.numVertexes][0] = 0;
+ tess.texCoords[tess.numVertexes][1] = 0;
+ tess.color[tess.numVertexes][0] = iColor[0];
+ tess.color[tess.numVertexes][1] = iColor[1];
+ tess.color[tess.numVertexes][2] = iColor[2];
+ tess.color[tess.numVertexes][3] = 65535;
+ tess.numVertexes++;
+
+ tess.xyz[tess.numVertexes][0] = f->windowX - size;
+ tess.xyz[tess.numVertexes][1] = f->windowY + size;
+ tess.texCoords[tess.numVertexes][0] = 0;
+ tess.texCoords[tess.numVertexes][1] = 1;
+ tess.color[tess.numVertexes][0] = iColor[0];
+ tess.color[tess.numVertexes][1] = iColor[1];
+ tess.color[tess.numVertexes][2] = iColor[2];
+ tess.color[tess.numVertexes][3] = 65535;
+ tess.numVertexes++;
+
+ tess.xyz[tess.numVertexes][0] = f->windowX + size;
+ tess.xyz[tess.numVertexes][1] = f->windowY + size;
+ tess.texCoords[tess.numVertexes][0] = 1;
+ tess.texCoords[tess.numVertexes][1] = 1;
+ tess.color[tess.numVertexes][0] = iColor[0];
+ tess.color[tess.numVertexes][1] = iColor[1];
+ tess.color[tess.numVertexes][2] = iColor[2];
+ tess.color[tess.numVertexes][3] = 65535;
+ tess.numVertexes++;
+
+ tess.xyz[tess.numVertexes][0] = f->windowX + size;
+ tess.xyz[tess.numVertexes][1] = f->windowY - size;
+ tess.texCoords[tess.numVertexes][0] = 1;
+ tess.texCoords[tess.numVertexes][1] = 0;
+ tess.color[tess.numVertexes][0] = iColor[0];
+ tess.color[tess.numVertexes][1] = iColor[1];
+ tess.color[tess.numVertexes][2] = iColor[2];
+ tess.color[tess.numVertexes][3] = 65535;
+ tess.numVertexes++;
+
+ tess.indexes[tess.numIndexes++] = 0;
+ tess.indexes[tess.numIndexes++] = 1;
+ tess.indexes[tess.numIndexes++] = 2;
+ tess.indexes[tess.numIndexes++] = 0;
+ tess.indexes[tess.numIndexes++] = 2;
+ tess.indexes[tess.numIndexes++] = 3;
+
+ RB_EndSurface();
+}
+
+/*
+==================
+RB_RenderFlares
+
+Because flares are simulating an occular effect, they should be drawn after
+everything (all views) in the entire frame has been drawn.
+
+Because of the way portals use the depth buffer to mark off areas, the
+needed information would be lost after each view, so we are forced to draw
+flares after each view.
+
+The resulting artifact is that flares in mirrors or portals don't dim properly
+when occluded by something in the main view, and portal flares that should
+extend past the portal edge will be overwritten.
+==================
+*/
+void RB_RenderFlares (void) {
+ flare_t *f;
+ flare_t **prev;
+ bool draw;
+ mat4_t oldmodelview, oldprojection, matrix;
+
+ if ( !r_flares->integer ) {
+ return;
+ }
+
+ if(r_flareCoeff->modified)
+ {
+ R_SetFlareCoeff();
+ r_flareCoeff->modified = false;
+ }
+
+ // Reset currentEntity to world so that any previously referenced entities
+ // don't have influence on the rendering of these flares (i.e. RF_ renderer flags).
+ backEnd.currentEntity = &tr.worldEntity;
+ backEnd.orientation = backEnd.viewParms.world;
+
+// RB_AddDlightFlares();
+
+ // perform z buffer readback on each flare in this view
+ draw = false;
+ prev = &r_activeFlares;
+ while ( ( f = *prev ) != NULL ) {
+ // throw out any flares that weren't added last frame
+ if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) {
+ *prev = f->next;
+ f->next = r_inactiveFlares;
+ r_inactiveFlares = f;
+ continue;
+ }
+
+ // don't draw any here that aren't from this scene / portal
+ f->drawIntensity = 0;
+ if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
+ && f->inPortal == backEnd.viewParms.isPortal ) {
+ RB_TestFlare( f );
+ if ( f->drawIntensity ) {
+ draw = true;
+ } else {
+ // this flare has completely faded out, so remove it from the chain
+ *prev = f->next;
+ f->next = r_inactiveFlares;
+ r_inactiveFlares = f;
+ continue;
+ }
+ }
+
+ prev = &f->next;
+ }
+
+ if ( !draw ) {
+ return; // none visible
+ }
+
+ if ( backEnd.viewParms.isPortal ) {
+ qglDisable (GL_CLIP_PLANE0);
+ }
+
+ Mat4Copy(glState.projection, oldprojection);
+ Mat4Copy(glState.modelview, oldmodelview);
+ Mat4Identity(matrix);
+ GL_SetModelviewMatrix(matrix);
+ Mat4Ortho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
+ backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
+ -99999, 99999, matrix );
+ GL_SetProjectionMatrix(matrix);
+
+ for ( f = r_activeFlares ; f ; f = f->next ) {
+ if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
+ && f->inPortal == backEnd.viewParms.isPortal
+ && f->drawIntensity ) {
+ RB_RenderFlare( f );
+ }
+ }
+
+ GL_SetProjectionMatrix(oldprojection);
+ GL_SetModelviewMatrix(oldmodelview);
+}
diff --git a/src/renderergl2/tr_glsl.cpp b/src/renderergl2/tr_glsl.cpp
new file mode 100644
index 0000000..469cb7c
--- /dev/null
+++ b/src/renderergl2/tr_glsl.cpp
@@ -0,0 +1,1470 @@
+/*
+===========================================================================
+Copyright (C) 2006-2009 Robert Beckebans <trebor_7@users.sourceforge.net>
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_glsl.c
+#include "tr_local.h"
+
+#include "tr_dsa.h"
+
+extern const char *fallbackShader_bokeh_vp;
+extern const char *fallbackShader_bokeh_fp;
+extern const char *fallbackShader_calclevels4x_vp;
+extern const char *fallbackShader_calclevels4x_fp;
+extern const char *fallbackShader_depthblur_vp;
+extern const char *fallbackShader_depthblur_fp;
+extern const char *fallbackShader_dlight_vp;
+extern const char *fallbackShader_dlight_fp;
+extern const char *fallbackShader_down4x_vp;
+extern const char *fallbackShader_down4x_fp;
+extern const char *fallbackShader_fogpass_vp;
+extern const char *fallbackShader_fogpass_fp;
+extern const char *fallbackShader_generic_vp;
+extern const char *fallbackShader_generic_fp;
+extern const char *fallbackShader_lightall_vp;
+extern const char *fallbackShader_lightall_fp;
+extern const char *fallbackShader_pshadow_vp;
+extern const char *fallbackShader_pshadow_fp;
+extern const char *fallbackShader_shadowfill_vp;
+extern const char *fallbackShader_shadowfill_fp;
+extern const char *fallbackShader_shadowmask_vp;
+extern const char *fallbackShader_shadowmask_fp;
+extern const char *fallbackShader_ssao_vp;
+extern const char *fallbackShader_ssao_fp;
+extern const char *fallbackShader_texturecolor_vp;
+extern const char *fallbackShader_texturecolor_fp;
+extern const char *fallbackShader_tonemap_vp;
+extern const char *fallbackShader_tonemap_fp;
+
+struct uniformInfo_t
+{
+ const char *name;
+ int type;
+};
+
+// These must be in the same order as in uniform_t in tr_local.h.
+static uniformInfo_t uniformsInfo[] =
+{
+ { "u_DiffuseMap", GLSL_INT },
+ { "u_LightMap", GLSL_INT },
+ { "u_NormalMap", GLSL_INT },
+ { "u_DeluxeMap", GLSL_INT },
+ { "u_SpecularMap", GLSL_INT },
+
+ { "u_TextureMap", GLSL_INT },
+ { "u_LevelsMap", GLSL_INT },
+ { "u_CubeMap", GLSL_INT },
+
+ { "u_ScreenImageMap", GLSL_INT },
+ { "u_ScreenDepthMap", GLSL_INT },
+
+ { "u_ShadowMap", GLSL_INT },
+ { "u_ShadowMap2", GLSL_INT },
+ { "u_ShadowMap3", GLSL_INT },
+ { "u_ShadowMap4", GLSL_INT },
+
+ { "u_ShadowMvp", GLSL_MAT16 },
+ { "u_ShadowMvp2", GLSL_MAT16 },
+ { "u_ShadowMvp3", GLSL_MAT16 },
+ { "u_ShadowMvp4", GLSL_MAT16 },
+
+ { "u_EnableTextures", GLSL_VEC4 },
+
+ { "u_DiffuseTexMatrix", GLSL_VEC4 },
+ { "u_DiffuseTexOffTurb", GLSL_VEC4 },
+
+ { "u_TCGen0", GLSL_INT },
+ { "u_TCGen0Vector0", GLSL_VEC3 },
+ { "u_TCGen0Vector1", GLSL_VEC3 },
+
+ { "u_DeformGen", GLSL_INT },
+ { "u_DeformParams", GLSL_FLOAT5 },
+
+ { "u_ColorGen", GLSL_INT },
+ { "u_AlphaGen", GLSL_INT },
+ { "u_Color", GLSL_VEC4 },
+ { "u_BaseColor", GLSL_VEC4 },
+ { "u_VertColor", GLSL_VEC4 },
+
+ { "u_DlightInfo", GLSL_VEC4 },
+ { "u_LightForward", GLSL_VEC3 },
+ { "u_LightUp", GLSL_VEC3 },
+ { "u_LightRight", GLSL_VEC3 },
+ { "u_LightOrigin", GLSL_VEC4 },
+ { "u_ModelLightDir", GLSL_VEC3 },
+ { "u_LightRadius", GLSL_FLOAT },
+ { "u_AmbientLight", GLSL_VEC3 },
+ { "u_DirectedLight", GLSL_VEC3 },
+
+ { "u_PortalRange", GLSL_FLOAT },
+
+ { "u_FogDistance", GLSL_VEC4 },
+ { "u_FogDepth", GLSL_VEC4 },
+ { "u_FogEyeT", GLSL_FLOAT },
+ { "u_FogColorMask", GLSL_VEC4 },
+
+ { "u_ModelMatrix", GLSL_MAT16 },
+ { "u_ModelViewProjectionMatrix", GLSL_MAT16 },
+
+ { "u_Time", GLSL_FLOAT },
+ { "u_VertexLerp" , GLSL_FLOAT },
+ { "u_NormalScale", GLSL_VEC4 },
+ { "u_SpecularScale", GLSL_VEC4 },
+
+ { "u_ViewInfo", GLSL_VEC4 },
+ { "u_ViewOrigin", GLSL_VEC3 },
+ { "u_LocalViewOrigin", GLSL_VEC3 },
+ { "u_ViewForward", GLSL_VEC3 },
+ { "u_ViewLeft", GLSL_VEC3 },
+ { "u_ViewUp", GLSL_VEC3 },
+
+ { "u_InvTexRes", GLSL_VEC2 },
+ { "u_AutoExposureMinMax", GLSL_VEC2 },
+ { "u_ToneMinAvgMaxLinear", GLSL_VEC3 },
+
+ { "u_PrimaryLightOrigin", GLSL_VEC4 },
+ { "u_PrimaryLightColor", GLSL_VEC3 },
+ { "u_PrimaryLightAmbient", GLSL_VEC3 },
+ { "u_PrimaryLightRadius", GLSL_FLOAT },
+
+ { "u_CubeMapInfo", GLSL_VEC4 },
+
+ { "u_AlphaTest", GLSL_INT },
+};
+
+typedef enum
+{
+ GLSL_PRINTLOG_PROGRAM_INFO,
+ GLSL_PRINTLOG_SHADER_INFO,
+ GLSL_PRINTLOG_SHADER_SOURCE
+}
+glslPrintLog_t;
+
+static void GLSL_PrintLog(GLuint programOrShader, glslPrintLog_t type, bool developerOnly)
+{
+ char *msg;
+ static char msgPart[1024];
+ int maxLength = 0;
+ int i;
+ int printLevel = developerOnly ? PRINT_DEVELOPER : PRINT_ALL;
+
+ switch (type)
+ {
+ case GLSL_PRINTLOG_PROGRAM_INFO:
+ ri.Printf(printLevel, "Program info log:\n");
+ qglGetProgramiv(programOrShader, GL_INFO_LOG_LENGTH, &maxLength);
+ break;
+
+ case GLSL_PRINTLOG_SHADER_INFO:
+ ri.Printf(printLevel, "Shader info log:\n");
+ qglGetShaderiv(programOrShader, GL_INFO_LOG_LENGTH, &maxLength);
+ break;
+
+ case GLSL_PRINTLOG_SHADER_SOURCE:
+ ri.Printf(printLevel, "Shader source:\n");
+ qglGetShaderiv(programOrShader, GL_SHADER_SOURCE_LENGTH, &maxLength);
+ break;
+ }
+
+ if (maxLength <= 0)
+ {
+ ri.Printf(printLevel, "None.\n");
+ return;
+ }
+
+ if (maxLength < 1023)
+ msg = msgPart;
+ else
+ msg = (char*)ri.Malloc(maxLength);
+
+ switch (type)
+ {
+ case GLSL_PRINTLOG_PROGRAM_INFO:
+ qglGetProgramInfoLog(programOrShader, maxLength, &maxLength, msg);
+ break;
+
+ case GLSL_PRINTLOG_SHADER_INFO:
+ qglGetShaderInfoLog(programOrShader, maxLength, &maxLength, msg);
+ break;
+
+ case GLSL_PRINTLOG_SHADER_SOURCE:
+ qglGetShaderSource(programOrShader, maxLength, &maxLength, msg);
+ break;
+ }
+
+ if (maxLength < 1023)
+ {
+ msgPart[maxLength + 1] = '\0';
+
+ ri.Printf(printLevel, "%s\n", msgPart);
+ }
+ else
+ {
+ for(i = 0; i < maxLength; i += 1023)
+ {
+ Q_strncpyz(msgPart, msg + i, sizeof(msgPart));
+
+ ri.Printf(printLevel, "%s", msgPart);
+ }
+
+ ri.Printf(printLevel, "\n");
+
+ ri.Free(msg);
+ }
+
+}
+
+static void GLSL_GetShaderHeader( GLenum shaderType, const GLchar *extra, char *dest, int size )
+{
+ float fbufWidthScale, fbufHeightScale;
+
+ dest[0] = '\0';
+
+ // HACK: abuse the GLSL preprocessor to turn GLSL 1.20 shaders into 1.30 ones
+ if(glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 30))
+ {
+ Q_strcat(dest, size, "#version 150\n");
+
+ if(shaderType == GL_VERTEX_SHADER)
+ {
+ Q_strcat(dest, size, "#define attribute in\n");
+ Q_strcat(dest, size, "#define varying out\n");
+ }
+ else
+ {
+ Q_strcat(dest, size, "#define varying in\n");
+
+ Q_strcat(dest, size, "out vec4 out_Color;\n");
+ Q_strcat(dest, size, "#define gl_FragColor out_Color\n");
+ Q_strcat(dest, size, "#define texture2D texture\n");
+ Q_strcat(dest, size, "#define textureCubeLod textureLod\n");
+ Q_strcat(dest, size, "#define shadow2D texture\n");
+ }
+ }
+ else
+ {
+ Q_strcat(dest, size, "#version 120\n");
+ Q_strcat(dest, size, "#define shadow2D(a,b) shadow2D(a,b).r \n");
+ }
+
+ // HACK: add some macros to avoid extra uniforms and save speed and code maintenance
+ //Q_strcat(dest, size,
+ // va("#ifndef r_SpecularExponent\n#define r_SpecularExponent %f\n#endif\n", r_specularExponent->value));
+ //Q_strcat(dest, size,
+ // va("#ifndef r_SpecularScale\n#define r_SpecularScale %f\n#endif\n", r_specularScale->value));
+ //Q_strcat(dest, size,
+ // va("#ifndef r_NormalScale\n#define r_NormalScale %f\n#endif\n", r_normalScale->value));
+
+
+ Q_strcat(dest, size, "#ifndef M_PI\n#define M_PI 3.14159265358979323846\n#endif\n");
+
+ //Q_strcat(dest, size, va("#ifndef MAX_SHADOWMAPS\n#define MAX_SHADOWMAPS %i\n#endif\n", MAX_SHADOWMAPS));
+
+ Q_strcat(dest, size,
+ va("#ifndef deformGen_t\n"
+ "#define deformGen_t\n"
+ "#define DGEN_WAVE_SIN %i\n"
+ "#define DGEN_WAVE_SQUARE %i\n"
+ "#define DGEN_WAVE_TRIANGLE %i\n"
+ "#define DGEN_WAVE_SAWTOOTH %i\n"
+ "#define DGEN_WAVE_INVERSE_SAWTOOTH %i\n"
+ "#define DGEN_BULGE %i\n"
+ "#define DGEN_MOVE %i\n"
+ "#endif\n",
+ DGEN_WAVE_SIN,
+ DGEN_WAVE_SQUARE,
+ DGEN_WAVE_TRIANGLE,
+ DGEN_WAVE_SAWTOOTH,
+ DGEN_WAVE_INVERSE_SAWTOOTH,
+ DGEN_BULGE,
+ DGEN_MOVE));
+
+ Q_strcat(dest, size,
+ va("#ifndef tcGen_t\n"
+ "#define tcGen_t\n"
+ "#define TCGEN_LIGHTMAP %i\n"
+ "#define TCGEN_TEXTURE %i\n"
+ "#define TCGEN_ENVIRONMENT_MAPPED %i\n"
+ "#define TCGEN_FOG %i\n"
+ "#define TCGEN_VECTOR %i\n"
+ "#endif\n",
+ TCGEN_LIGHTMAP,
+ TCGEN_TEXTURE,
+ TCGEN_ENVIRONMENT_MAPPED,
+ TCGEN_FOG,
+ TCGEN_VECTOR));
+
+ Q_strcat(dest, size,
+ va("#ifndef colorGen_t\n"
+ "#define colorGen_t\n"
+ "#define CGEN_LIGHTING_DIFFUSE %i\n"
+ "#endif\n",
+ CGEN_LIGHTING_DIFFUSE));
+
+ Q_strcat(dest, size,
+ va("#ifndef alphaGen_t\n"
+ "#define alphaGen_t\n"
+ "#define AGEN_LIGHTING_SPECULAR %i\n"
+ "#define AGEN_PORTAL %i\n"
+ "#endif\n",
+ AGEN_LIGHTING_SPECULAR,
+ AGEN_PORTAL));
+
+ Q_strcat(dest, size,
+ va("#ifndef texenv_t\n"
+ "#define texenv_t\n"
+ "#define TEXENV_MODULATE %i\n"
+ "#define TEXENV_ADD %i\n"
+ "#define TEXENV_REPLACE %i\n"
+ "#endif\n",
+ GL_MODULATE,
+ GL_ADD,
+ GL_REPLACE));
+
+ fbufWidthScale = 1.0f / ((float)glConfig.vidWidth);
+ fbufHeightScale = 1.0f / ((float)glConfig.vidHeight);
+ Q_strcat(dest, size,
+ va("#ifndef r_FBufScale\n#define r_FBufScale vec2(%f, %f)\n#endif\n", fbufWidthScale, fbufHeightScale));
+
+ if (r_pbr->integer)
+ Q_strcat(dest, size, "#define USE_PBR\n");
+
+ if (r_cubeMapping->integer)
+ {
+ int cubeMipSize = r_cubemapSize->integer;
+ int numRoughnessMips = 0;
+
+ while (cubeMipSize)
+ {
+ cubeMipSize >>= 1;
+ numRoughnessMips++;
+ }
+ numRoughnessMips = MAX(1, numRoughnessMips - 2);
+ Q_strcat(dest, size, va("#define ROUGHNESS_MIPS float(%d)\n", numRoughnessMips));
+ }
+
+ if (extra)
+ {
+ Q_strcat(dest, size, extra);
+ }
+
+ // OK we added a lot of stuff but if we do something bad in the GLSL shaders then we want the proper line
+ // so we have to reset the line counting
+ Q_strcat(dest, size, "#line 0\n");
+}
+
+static int GLSL_CompileGPUShader(GLuint program, GLuint *prevShader, const GLchar *buffer, int size, GLenum shaderType)
+{
+ GLint compiled;
+ GLuint shader;
+
+ shader = qglCreateShader(shaderType);
+
+ qglShaderSource(shader, 1, (const GLchar **)&buffer, &size);
+
+ // compile shader
+ qglCompileShader(shader);
+
+ // check if shader compiled
+ qglGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if(!compiled)
+ {
+ GLSL_PrintLog(shader, GLSL_PRINTLOG_SHADER_SOURCE, false);
+ GLSL_PrintLog(shader, GLSL_PRINTLOG_SHADER_INFO, false);
+ ri.Error(ERR_DROP, "Couldn't compile shader");
+ return 0;
+ }
+
+ if (*prevShader)
+ {
+ qglDetachShader(program, *prevShader);
+ qglDeleteShader(*prevShader);
+ }
+
+ // attach shader to program
+ qglAttachShader(program, shader);
+
+ *prevShader = shader;
+
+ return 1;
+}
+
+static int GLSL_LoadGPUShaderText(const char *name, const char *fallback,
+ GLenum shaderType, char *dest, int destSize)
+{
+ char filename[MAX_QPATH];
+ GLchar *buffer = NULL;
+ const GLchar *shaderText = NULL;
+ int size;
+ int result;
+
+ if(shaderType == GL_VERTEX_SHADER)
+ {
+ Com_sprintf(filename, sizeof(filename), "glsl/%s_vp.glsl", name);
+ }
+ else
+ {
+ Com_sprintf(filename, sizeof(filename), "glsl/%s_fp.glsl", name);
+ }
+
+ if ( r_externalGLSL->integer ) {
+ size = ri.FS_ReadFile(filename, (void **)&buffer);
+ } else {
+ size = 0;
+ buffer = NULL;
+ }
+
+ if(!buffer)
+ {
+ if (fallback)
+ {
+ ri.Printf(PRINT_DEVELOPER, "...loading built-in '%s'\n", filename);
+ shaderText = fallback;
+ size = strlen(shaderText);
+ }
+ else
+ {
+ ri.Printf(PRINT_DEVELOPER, "couldn't load '%s'\n", filename);
+ return 0;
+ }
+ }
+ else
+ {
+ ri.Printf(PRINT_DEVELOPER, "...loading '%s'\n", filename);
+ shaderText = buffer;
+ }
+
+ if (size > destSize)
+ {
+ result = 0;
+ }
+ else
+ {
+ Q_strncpyz(dest, shaderText, size + 1);
+ result = 1;
+ }
+
+ if (buffer)
+ {
+ ri.FS_FreeFile(buffer);
+ }
+
+ return result;
+}
+
+static void GLSL_LinkProgram(GLuint program)
+{
+ GLint linked;
+
+ qglLinkProgram(program);
+
+ qglGetProgramiv(program, GL_LINK_STATUS, &linked);
+ if(!linked)
+ {
+ GLSL_PrintLog(program, GLSL_PRINTLOG_PROGRAM_INFO, false);
+ ri.Error(ERR_DROP, "shaders failed to link");
+ }
+}
+
+static void GLSL_ValidateProgram(GLuint program)
+{
+ GLint validated;
+
+ qglValidateProgram(program);
+
+ qglGetProgramiv(program, GL_VALIDATE_STATUS, &validated);
+ if(!validated)
+ {
+ GLSL_PrintLog(program, GLSL_PRINTLOG_PROGRAM_INFO, false);
+ ri.Error(ERR_DROP, "shaders failed to validate");
+ }
+}
+
+static void GLSL_ShowProgramUniforms(GLuint program)
+{
+ int i, count, size;
+ GLenum type;
+ char uniformName[1000];
+
+ // query the number of active uniforms
+ qglGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count);
+
+ // Loop over each of the active uniforms, and set their value
+ for(i = 0; i < count; i++)
+ {
+ qglGetActiveUniform(program, i, sizeof(uniformName), NULL, &size, &type, uniformName);
+
+ ri.Printf(PRINT_DEVELOPER, "active uniform: '%s'\n", uniformName);
+ }
+}
+
+static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int attribs, const char *vpCode, const char *fpCode)
+{
+ ri.Printf(PRINT_DEVELOPER, "------- GPU shader -------\n");
+
+ if(strlen(name) >= MAX_QPATH)
+ {
+ ri.Error(ERR_DROP, "GLSL_InitGPUShader2: \"%s\" is too long", name);
+ }
+
+ Q_strncpyz(program->name, name, sizeof(program->name));
+
+ program->program = qglCreateProgram();
+ program->attribs = attribs;
+
+ if (!(GLSL_CompileGPUShader(program->program, &program->vertexShader, vpCode, strlen(vpCode), GL_VERTEX_SHADER)))
+ {
+ ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_VERTEX_SHADER\n", name);
+ qglDeleteProgram(program->program);
+ return 0;
+ }
+
+ if(fpCode)
+ {
+ if(!(GLSL_CompileGPUShader(program->program, &program->fragmentShader, fpCode, strlen(fpCode), GL_FRAGMENT_SHADER)))
+ {
+ ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_FRAGMENT_SHADER\n", name);
+ qglDeleteProgram(program->program);
+ return 0;
+ }
+ }
+
+ if(attribs & ATTR_POSITION)
+ qglBindAttribLocation(program->program, ATTR_INDEX_POSITION, "attr_Position");
+
+ if(attribs & ATTR_TEXCOORD)
+ qglBindAttribLocation(program->program, ATTR_INDEX_TEXCOORD, "attr_TexCoord0");
+
+ if(attribs & ATTR_LIGHTCOORD)
+ qglBindAttribLocation(program->program, ATTR_INDEX_LIGHTCOORD, "attr_TexCoord1");
+
+// if(attribs & ATTR_TEXCOORD2)
+// qglBindAttribLocation(program->program, ATTR_INDEX_TEXCOORD2, "attr_TexCoord2");
+
+// if(attribs & ATTR_TEXCOORD3)
+// qglBindAttribLocation(program->program, ATTR_INDEX_TEXCOORD3, "attr_TexCoord3");
+
+ if(attribs & ATTR_TANGENT)
+ qglBindAttribLocation(program->program, ATTR_INDEX_TANGENT, "attr_Tangent");
+
+ if(attribs & ATTR_NORMAL)
+ qglBindAttribLocation(program->program, ATTR_INDEX_NORMAL, "attr_Normal");
+
+ if(attribs & ATTR_COLOR)
+ qglBindAttribLocation(program->program, ATTR_INDEX_COLOR, "attr_Color");
+
+ if(attribs & ATTR_PAINTCOLOR)
+ qglBindAttribLocation(program->program, ATTR_INDEX_PAINTCOLOR, "attr_PaintColor");
+
+ if(attribs & ATTR_LIGHTDIRECTION)
+ qglBindAttribLocation(program->program, ATTR_INDEX_LIGHTDIRECTION, "attr_LightDirection");
+
+ if(attribs & ATTR_POSITION2)
+ qglBindAttribLocation(program->program, ATTR_INDEX_POSITION2, "attr_Position2");
+
+ if(attribs & ATTR_NORMAL2)
+ qglBindAttribLocation(program->program, ATTR_INDEX_NORMAL2, "attr_Normal2");
+
+ if(attribs & ATTR_TANGENT2)
+ qglBindAttribLocation(program->program, ATTR_INDEX_TANGENT2, "attr_Tangent2");
+
+ GLSL_LinkProgram(program->program);
+
+ return 1;
+}
+
+static int GLSL_InitGPUShader(shaderProgram_t * program, const char *name,
+ int attribs, bool fragmentShader, const GLchar *extra, bool addHeader,
+ const char *fallback_vp, const char *fallback_fp)
+{
+ char vpCode[32000];
+ char fpCode[32000];
+ char *postHeader;
+ int size;
+ int result;
+
+ size = sizeof(vpCode);
+ if (addHeader)
+ {
+ GLSL_GetShaderHeader(GL_VERTEX_SHADER, extra, vpCode, size);
+ postHeader = &vpCode[strlen(vpCode)];
+ size -= strlen(vpCode);
+ }
+ else
+ {
+ postHeader = &vpCode[0];
+ }
+
+ if (!GLSL_LoadGPUShaderText(name, fallback_vp, GL_VERTEX_SHADER, postHeader, size))
+ {
+ return 0;
+ }
+
+ if (fragmentShader)
+ {
+ size = sizeof(fpCode);
+ if (addHeader)
+ {
+ GLSL_GetShaderHeader(GL_FRAGMENT_SHADER, extra, fpCode, size);
+ postHeader = &fpCode[strlen(fpCode)];
+ size -= strlen(fpCode);
+ }
+ else
+ {
+ postHeader = &fpCode[0];
+ }
+
+ if (!GLSL_LoadGPUShaderText(name, fallback_fp, GL_FRAGMENT_SHADER, postHeader, size))
+ {
+ return 0;
+ }
+ }
+
+ result = GLSL_InitGPUShader2(program, name, attribs, vpCode, fragmentShader ? fpCode : NULL);
+
+ return result;
+}
+
+void GLSL_InitUniforms(shaderProgram_t *program)
+{
+ int i, size;
+
+ GLint *uniforms = program->uniforms;
+
+ size = 0;
+ for (i = 0; i < UNIFORM_COUNT; i++)
+ {
+ uniforms[i] = qglGetUniformLocation(program->program, uniformsInfo[i].name);
+
+ if (uniforms[i] == -1)
+ continue;
+
+ program->uniformBufferOffsets[i] = size;
+
+ switch(uniformsInfo[i].type)
+ {
+ case GLSL_INT:
+ size += sizeof(GLint);
+ break;
+ case GLSL_FLOAT:
+ size += sizeof(GLfloat);
+ break;
+ case GLSL_FLOAT5:
+ size += sizeof(vec_t) * 5;
+ break;
+ case GLSL_VEC2:
+ size += sizeof(vec_t) * 2;
+ break;
+ case GLSL_VEC3:
+ size += sizeof(vec_t) * 3;
+ break;
+ case GLSL_VEC4:
+ size += sizeof(vec_t) * 4;
+ break;
+ case GLSL_MAT16:
+ size += sizeof(vec_t) * 16;
+ break;
+ default:
+ break;
+ }
+ }
+
+ program->uniformBuffer = (char*)ri.Malloc(size);
+}
+
+void GLSL_FinishGPUShader(shaderProgram_t *program)
+{
+ //GLSL_ValidateProgram(program->program);
+ GLSL_ShowProgramUniforms(program->program);
+ GL_CheckErrors();
+}
+
+void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value)
+{
+ GLint *uniforms = program->uniforms;
+ GLint *compare = (GLint *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]);
+
+ if (uniforms[uniformNum] == -1)
+ return;
+
+ if (uniformsInfo[uniformNum].type != GLSL_INT)
+ {
+ ri.Printf( PRINT_WARNING, "GLSL_SetUniformInt: wrong type for uniform %i in program %s\n", uniformNum, program->name);
+ return;
+ }
+
+ if (value == *compare)
+ {
+ return;
+ }
+
+ *compare = value;
+
+ qglProgramUniform1iEXT(program->program, uniforms[uniformNum], value);
+}
+
+void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value)
+{
+ GLint *uniforms = program->uniforms;
+ GLfloat *compare = (GLfloat *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]);
+
+ if (uniforms[uniformNum] == -1)
+ return;
+
+ if (uniformsInfo[uniformNum].type != GLSL_FLOAT)
+ {
+ ri.Printf( PRINT_WARNING, "GLSL_SetUniformFloat: wrong type for uniform %i in program %s\n", uniformNum, program->name);
+ return;
+ }
+
+ if (value == *compare)
+ {
+ return;
+ }
+
+ *compare = value;
+
+ qglProgramUniform1fEXT(program->program, uniforms[uniformNum], value);
+}
+
+void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v)
+{
+ GLint *uniforms = program->uniforms;
+ vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]);
+
+ if (uniforms[uniformNum] == -1)
+ return;
+
+ if (uniformsInfo[uniformNum].type != GLSL_VEC2)
+ {
+ ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec2: wrong type for uniform %i in program %s\n", uniformNum, program->name);
+ return;
+ }
+
+ if (v[0] == compare[0] && v[1] == compare[1])
+ {
+ return;
+ }
+
+ compare[0] = v[0];
+ compare[1] = v[1];
+
+ qglProgramUniform2fEXT(program->program, uniforms[uniformNum], v[0], v[1]);
+}
+
+void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v)
+{
+ GLint *uniforms = program->uniforms;
+ vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]);
+
+ if (uniforms[uniformNum] == -1)
+ return;
+
+ if (uniformsInfo[uniformNum].type != GLSL_VEC3)
+ {
+ ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec3: wrong type for uniform %i in program %s\n", uniformNum, program->name);
+ return;
+ }
+
+ if (VectorCompare(v, compare))
+ {
+ return;
+ }
+
+ VectorCopy(v, compare);
+
+ qglProgramUniform3fEXT(program->program, uniforms[uniformNum], v[0], v[1], v[2]);
+}
+
+void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v)
+{
+ GLint *uniforms = program->uniforms;
+ vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]);
+
+ if (uniforms[uniformNum] == -1)
+ return;
+
+ if (uniformsInfo[uniformNum].type != GLSL_VEC4)
+ {
+ ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec4: wrong type for uniform %i in program %s\n", uniformNum, program->name);
+ return;
+ }
+
+ if (VectorCompare4(v, compare))
+ {
+ return;
+ }
+
+ VectorCopy4(v, compare);
+
+ qglProgramUniform4fEXT(program->program, uniforms[uniformNum], v[0], v[1], v[2], v[3]);
+}
+
+void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v)
+{
+ GLint *uniforms = program->uniforms;
+ vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]);
+
+ if (uniforms[uniformNum] == -1)
+ return;
+
+ if (uniformsInfo[uniformNum].type != GLSL_FLOAT5)
+ {
+ ri.Printf( PRINT_WARNING, "GLSL_SetUniformFloat5: wrong type for uniform %i in program %s\n", uniformNum, program->name);
+ return;
+ }
+
+ if (VectorCompare5(v, compare))
+ {
+ return;
+ }
+
+ VectorCopy5(v, compare);
+
+ qglProgramUniform1fvEXT(program->program, uniforms[uniformNum], 5, v);
+}
+
+void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix)
+{
+ GLint *uniforms = program->uniforms;
+ vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]);
+
+ if (uniforms[uniformNum] == -1)
+ return;
+
+ if (uniformsInfo[uniformNum].type != GLSL_MAT16)
+ {
+ ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4: wrong type for uniform %i in program %s\n", uniformNum, program->name);
+ return;
+ }
+
+ if (Mat4Compare(matrix, compare))
+ {
+ return;
+ }
+
+ Mat4Copy(matrix, compare);
+
+ qglProgramUniformMatrix4fvEXT(program->program, uniforms[uniformNum], 1, GL_FALSE, matrix);
+}
+
+void GLSL_DeleteGPUShader(shaderProgram_t *program)
+{
+ if(program->program)
+ {
+ if (program->vertexShader)
+ {
+ qglDetachShader(program->program, program->vertexShader);
+ qglDeleteShader(program->vertexShader);
+ }
+
+ if (program->fragmentShader)
+ {
+ qglDetachShader(program->program, program->fragmentShader);
+ qglDeleteShader(program->fragmentShader);
+ }
+
+ qglDeleteProgram(program->program);
+
+ if (program->uniformBuffer)
+ {
+ ri.Free(program->uniformBuffer);
+ }
+
+ Com_Memset(program, 0, sizeof(*program));
+ }
+}
+
+void GLSL_InitGPUShaders(void)
+{
+ int startTime, endTime;
+ int i;
+ char extradefines[1024];
+ int attribs;
+ int numGenShaders = 0, numLightShaders = 0, numEtcShaders = 0;
+
+ ri.Printf(PRINT_ALL, "------- GLSL_InitGPUShaders -------\n");
+
+ R_IssuePendingRenderCommands();
+
+ startTime = ri.Milliseconds();
+
+ for (i = 0; i < GENERICDEF_COUNT; i++)
+ {
+ attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_NORMAL | ATTR_COLOR;
+ extradefines[0] = '\0';
+
+ if (i & GENERICDEF_USE_DEFORM_VERTEXES)
+ Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n");
+
+ if (i & GENERICDEF_USE_TCGEN_AND_TCMOD)
+ {
+ Q_strcat(extradefines, 1024, "#define USE_TCGEN\n");
+ Q_strcat(extradefines, 1024, "#define USE_TCMOD\n");
+ }
+
+ if (i & GENERICDEF_USE_VERTEX_ANIMATION)
+ {
+ Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
+ attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
+ }
+
+ if (i & GENERICDEF_USE_FOG)
+ Q_strcat(extradefines, 1024, "#define USE_FOG\n");
+
+ if (i & GENERICDEF_USE_RGBAGEN)
+ Q_strcat(extradefines, 1024, "#define USE_RGBAGEN\n");
+
+ if (!GLSL_InitGPUShader(&tr.genericShader[i], "generic", attribs, true, extradefines, true, fallbackShader_generic_vp, fallbackShader_generic_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load generic shader!");
+ }
+
+ GLSL_InitUniforms(&tr.genericShader[i]);
+
+ GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP);
+ GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP);
+
+ GLSL_FinishGPUShader(&tr.genericShader[i]);
+
+ numGenShaders++;
+ }
+
+
+ attribs = ATTR_POSITION | ATTR_TEXCOORD;
+
+ if (!GLSL_InitGPUShader(&tr.textureColorShader, "texturecolor", attribs, true, extradefines, true, fallbackShader_texturecolor_vp, fallbackShader_texturecolor_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load texturecolor shader!");
+ }
+
+ GLSL_InitUniforms(&tr.textureColorShader);
+
+ GLSL_SetUniformInt(&tr.textureColorShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
+
+ GLSL_FinishGPUShader(&tr.textureColorShader);
+
+ numEtcShaders++;
+
+ for (i = 0; i < FOGDEF_COUNT; i++)
+ {
+ attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD;
+ extradefines[0] = '\0';
+
+ if (i & FOGDEF_USE_DEFORM_VERTEXES)
+ Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n");
+
+ if (i & FOGDEF_USE_VERTEX_ANIMATION)
+ Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
+
+ if (!GLSL_InitGPUShader(&tr.fogShader[i], "fogpass", attribs, true, extradefines, true, fallbackShader_fogpass_vp, fallbackShader_fogpass_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load fogpass shader!");
+ }
+
+ GLSL_InitUniforms(&tr.fogShader[i]);
+ GLSL_FinishGPUShader(&tr.fogShader[i]);
+
+ numEtcShaders++;
+ }
+
+
+ for (i = 0; i < DLIGHTDEF_COUNT; i++)
+ {
+ attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD;
+ extradefines[0] = '\0';
+
+ if (i & DLIGHTDEF_USE_DEFORM_VERTEXES)
+ {
+ Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n");
+ }
+
+ if (!GLSL_InitGPUShader(&tr.dlightShader[i], "dlight", attribs, true, extradefines, true, fallbackShader_dlight_vp, fallbackShader_dlight_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load dlight shader!");
+ }
+
+ GLSL_InitUniforms(&tr.dlightShader[i]);
+
+ GLSL_SetUniformInt(&tr.dlightShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP);
+
+ GLSL_FinishGPUShader(&tr.dlightShader[i]);
+
+ numEtcShaders++;
+ }
+
+
+ for (i = 0; i < LIGHTDEF_COUNT; i++)
+ {
+ int lightType = i & LIGHTDEF_LIGHTTYPE_MASK;
+ bool fastLight = !(r_normalMapping->integer || r_specularMapping->integer);
+
+ // skip impossible combos
+ if ((i & LIGHTDEF_USE_PARALLAXMAP) && !r_parallaxMapping->integer)
+ continue;
+
+ if ((i & LIGHTDEF_USE_SHADOWMAP) && (!lightType || !r_sunlightMode->integer))
+ continue;
+
+ attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL;
+
+ extradefines[0] = '\0';
+
+ if (r_dlightMode->integer >= 2)
+ Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n");
+
+ if (glRefConfig.swizzleNormalmap)
+ Q_strcat(extradefines, 1024, "#define SWIZZLE_NORMALMAP\n");
+
+ if (lightType)
+ {
+ Q_strcat(extradefines, 1024, "#define USE_LIGHT\n");
+
+ if (fastLight)
+ Q_strcat(extradefines, 1024, "#define USE_FAST_LIGHT\n");
+
+ switch (lightType)
+ {
+ case LIGHTDEF_USE_LIGHTMAP:
+ Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n");
+ if (r_deluxeMapping->integer && !fastLight)
+ Q_strcat(extradefines, 1024, "#define USE_DELUXEMAP\n");
+ attribs |= ATTR_LIGHTCOORD | ATTR_LIGHTDIRECTION;
+ break;
+ case LIGHTDEF_USE_LIGHT_VECTOR:
+ Q_strcat(extradefines, 1024, "#define USE_LIGHT_VECTOR\n");
+ break;
+ case LIGHTDEF_USE_LIGHT_VERTEX:
+ Q_strcat(extradefines, 1024, "#define USE_LIGHT_VERTEX\n");
+ attribs |= ATTR_LIGHTDIRECTION;
+ break;
+ default:
+ break;
+ }
+
+ if (r_normalMapping->integer)
+ {
+ Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n");
+
+ attribs |= ATTR_TANGENT;
+
+ if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer)
+ {
+ Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n");
+ if (r_parallaxMapping->integer > 1)
+ Q_strcat(extradefines, 1024, "#define USE_RELIEFMAP\n");
+ }
+ }
+
+ if (r_specularMapping->integer)
+ Q_strcat(extradefines, 1024, "#define USE_SPECULARMAP\n");
+
+ if (r_cubeMapping->integer)
+ Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n");
+
+ switch (r_glossType->integer)
+ {
+ case 0:
+ default:
+ Q_strcat(extradefines, 1024, "#define GLOSS_IS_GLOSS\n");
+ break;
+ case 1:
+ Q_strcat(extradefines, 1024, "#define GLOSS_IS_SMOOTHNESS\n");
+ break;
+ case 2:
+ Q_strcat(extradefines, 1024, "#define GLOSS_IS_ROUGHNESS\n");
+ break;
+ case 3:
+ Q_strcat(extradefines, 1024, "#define GLOSS_IS_SHININESS\n");
+ break;
+ }
+ }
+
+ if (i & LIGHTDEF_USE_SHADOWMAP)
+ {
+ Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n");
+
+ if (r_sunlightMode->integer == 1)
+ Q_strcat(extradefines, 1024, "#define SHADOWMAP_MODULATE\n");
+ else if (r_sunlightMode->integer == 2)
+ Q_strcat(extradefines, 1024, "#define USE_PRIMARY_LIGHT\n");
+ }
+
+ if (i & LIGHTDEF_USE_TCGEN_AND_TCMOD)
+ {
+ Q_strcat(extradefines, 1024, "#define USE_TCGEN\n");
+ Q_strcat(extradefines, 1024, "#define USE_TCMOD\n");
+ }
+
+ if (i & LIGHTDEF_ENTITY)
+ {
+ Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n#define USE_MODELMATRIX\n");
+ attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
+
+ if (r_normalMapping->integer)
+ {
+ attribs |= ATTR_TANGENT2;
+ }
+ }
+
+ if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, true, extradefines, true, fallbackShader_lightall_vp, fallbackShader_lightall_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load lightall shader!");
+ }
+
+ GLSL_InitUniforms(&tr.lightallShader[i]);
+
+ GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP);
+ GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP);
+ GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_NORMALMAP, TB_NORMALMAP);
+ GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DELUXEMAP, TB_DELUXEMAP);
+ GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SPECULARMAP, TB_SPECULARMAP);
+ GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SHADOWMAP, TB_SHADOWMAP);
+ GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_CUBEMAP, TB_CUBEMAP);
+
+ GLSL_FinishGPUShader(&tr.lightallShader[i]);
+
+ numLightShaders++;
+ }
+
+ attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD;
+
+ extradefines[0] = '\0';
+
+ if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, true, extradefines, true, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load shadowfill shader!");
+ }
+
+ GLSL_InitUniforms(&tr.shadowmapShader);
+ GLSL_FinishGPUShader(&tr.shadowmapShader);
+
+ numEtcShaders++;
+
+ attribs = ATTR_POSITION | ATTR_NORMAL;
+ extradefines[0] = '\0';
+
+ Q_strcat(extradefines, 1024, "#define USE_PCF\n#define USE_DISCARD\n");
+
+ if (!GLSL_InitGPUShader(&tr.pshadowShader, "pshadow", attribs, true, extradefines, true, fallbackShader_pshadow_vp, fallbackShader_pshadow_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load pshadow shader!");
+ }
+
+ GLSL_InitUniforms(&tr.pshadowShader);
+
+ GLSL_SetUniformInt(&tr.pshadowShader, UNIFORM_SHADOWMAP, TB_DIFFUSEMAP);
+
+ GLSL_FinishGPUShader(&tr.pshadowShader);
+
+ numEtcShaders++;
+
+
+ attribs = ATTR_POSITION | ATTR_TEXCOORD;
+ extradefines[0] = '\0';
+
+ if (!GLSL_InitGPUShader(&tr.down4xShader, "down4x", attribs, true, extradefines, true, fallbackShader_down4x_vp, fallbackShader_down4x_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load down4x shader!");
+ }
+
+ GLSL_InitUniforms(&tr.down4xShader);
+
+ GLSL_SetUniformInt(&tr.down4xShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
+
+ GLSL_FinishGPUShader(&tr.down4xShader);
+
+ numEtcShaders++;
+
+
+ attribs = ATTR_POSITION | ATTR_TEXCOORD;
+ extradefines[0] = '\0';
+
+ if (!GLSL_InitGPUShader(&tr.bokehShader, "bokeh", attribs, true, extradefines, true, fallbackShader_bokeh_vp, fallbackShader_bokeh_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load bokeh shader!");
+ }
+
+ GLSL_InitUniforms(&tr.bokehShader);
+
+ GLSL_SetUniformInt(&tr.bokehShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
+
+ GLSL_FinishGPUShader(&tr.bokehShader);
+
+ numEtcShaders++;
+
+
+ attribs = ATTR_POSITION | ATTR_TEXCOORD;
+ extradefines[0] = '\0';
+
+ if (!GLSL_InitGPUShader(&tr.tonemapShader, "tonemap", attribs, true, extradefines, true, fallbackShader_tonemap_vp, fallbackShader_tonemap_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load tonemap shader!");
+ }
+
+ GLSL_InitUniforms(&tr.tonemapShader);
+
+ GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_TEXTUREMAP, TB_COLORMAP);
+ GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_LEVELSMAP, TB_LEVELSMAP);
+
+ GLSL_FinishGPUShader(&tr.tonemapShader);
+
+ numEtcShaders++;
+
+
+ for (i = 0; i < 2; i++)
+ {
+ attribs = ATTR_POSITION | ATTR_TEXCOORD;
+ extradefines[0] = '\0';
+
+ if (!i)
+ Q_strcat(extradefines, 1024, "#define FIRST_PASS\n");
+
+ if (!GLSL_InitGPUShader(&tr.calclevels4xShader[i], "calclevels4x", attribs, true, extradefines, true, fallbackShader_calclevels4x_vp, fallbackShader_calclevels4x_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load calclevels4x shader!");
+ }
+
+ GLSL_InitUniforms(&tr.calclevels4xShader[i]);
+
+ GLSL_SetUniformInt(&tr.calclevels4xShader[i], UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
+
+ GLSL_FinishGPUShader(&tr.calclevels4xShader[i]);
+
+ numEtcShaders++;
+ }
+
+
+ attribs = ATTR_POSITION | ATTR_TEXCOORD;
+ extradefines[0] = '\0';
+
+ if (r_shadowFilter->integer >= 1)
+ Q_strcat(extradefines, 1024, "#define USE_SHADOW_FILTER\n");
+
+ if (r_shadowFilter->integer >= 2)
+ Q_strcat(extradefines, 1024, "#define USE_SHADOW_FILTER2\n");
+
+ if (r_shadowCascadeZFar->integer != 0)
+ Q_strcat(extradefines, 1024, "#define USE_SHADOW_CASCADE\n");
+
+ Q_strcat(extradefines, 1024, va("#define r_shadowMapSize %f\n", r_shadowMapSize->value));
+ Q_strcat(extradefines, 1024, va("#define r_shadowCascadeZFar %f\n", r_shadowCascadeZFar->value));
+
+
+ if (!GLSL_InitGPUShader(&tr.shadowmaskShader, "shadowmask", attribs, true, extradefines, true, fallbackShader_shadowmask_vp, fallbackShader_shadowmask_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load shadowmask shader!");
+ }
+
+ GLSL_InitUniforms(&tr.shadowmaskShader);
+
+ GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP);
+ GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP, TB_SHADOWMAP);
+ GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP2, TB_SHADOWMAP2);
+ GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP3, TB_SHADOWMAP3);
+ GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP4, TB_SHADOWMAP4);
+
+ GLSL_FinishGPUShader(&tr.shadowmaskShader);
+
+ numEtcShaders++;
+
+
+ attribs = ATTR_POSITION | ATTR_TEXCOORD;
+ extradefines[0] = '\0';
+
+ if (!GLSL_InitGPUShader(&tr.ssaoShader, "ssao", attribs, true, extradefines, true, fallbackShader_ssao_vp, fallbackShader_ssao_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load ssao shader!");
+ }
+
+ GLSL_InitUniforms(&tr.ssaoShader);
+
+ GLSL_SetUniformInt(&tr.ssaoShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP);
+
+ GLSL_FinishGPUShader(&tr.ssaoShader);
+
+ numEtcShaders++;
+
+
+ for (i = 0; i < 4; i++)
+ {
+ attribs = ATTR_POSITION | ATTR_TEXCOORD;
+ extradefines[0] = '\0';
+
+ if (i & 1)
+ Q_strcat(extradefines, 1024, "#define USE_VERTICAL_BLUR\n");
+ else
+ Q_strcat(extradefines, 1024, "#define USE_HORIZONTAL_BLUR\n");
+
+ if (!(i & 2))
+ Q_strcat(extradefines, 1024, "#define USE_DEPTH\n");
+
+
+ if (!GLSL_InitGPUShader(&tr.depthBlurShader[i], "depthBlur", attribs, true, extradefines, true, fallbackShader_depthblur_vp, fallbackShader_depthblur_fp))
+ {
+ ri.Error(ERR_FATAL, "Could not load depthBlur shader!");
+ }
+
+ GLSL_InitUniforms(&tr.depthBlurShader[i]);
+
+ GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENIMAGEMAP, TB_COLORMAP);
+ GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENDEPTHMAP, TB_LIGHTMAP);
+
+ GLSL_FinishGPUShader(&tr.depthBlurShader[i]);
+
+ numEtcShaders++;
+ }
+
+#if 0
+ attribs = ATTR_POSITION | ATTR_TEXCOORD;
+ extradefines[0] = '\0';
+
+ if (!GLSL_InitGPUShader(&tr.testcubeShader, "testcube", attribs, true, extradefines, true, NULL, NULL))
+ {
+ ri.Error(ERR_FATAL, "Could not load testcube shader!");
+ }
+
+ GLSL_InitUniforms(&tr.testcubeShader);
+
+ GLSL_SetUniformInt(&tr.testcubeShader, UNIFORM_TEXTUREMAP, TB_COLORMAP);
+
+ GLSL_FinishGPUShader(&tr.testcubeShader);
+
+ numEtcShaders++;
+#endif
+
+
+ endTime = ri.Milliseconds();
+
+ ri.Printf(PRINT_ALL, "loaded %i GLSL shaders (%i gen %i light %i etc) in %5.2f seconds\n",
+ numGenShaders + numLightShaders + numEtcShaders, numGenShaders, numLightShaders,
+ numEtcShaders, (endTime - startTime) / 1000.0);
+}
+
+void GLSL_ShutdownGPUShaders(void)
+{
+ int i;
+
+ ri.Printf(PRINT_ALL, "------- GLSL_ShutdownGPUShaders -------\n");
+
+ for (i = 0; i < ATTR_INDEX_COUNT; i++)
+ qglDisableVertexAttribArray(i);
+
+ GL_BindNullProgram();
+
+ for ( i = 0; i < GENERICDEF_COUNT; i++)
+ GLSL_DeleteGPUShader(&tr.genericShader[i]);
+
+ GLSL_DeleteGPUShader(&tr.textureColorShader);
+
+ for ( i = 0; i < FOGDEF_COUNT; i++)
+ GLSL_DeleteGPUShader(&tr.fogShader[i]);
+
+ for ( i = 0; i < DLIGHTDEF_COUNT; i++)
+ GLSL_DeleteGPUShader(&tr.dlightShader[i]);
+
+ for ( i = 0; i < LIGHTDEF_COUNT; i++)
+ GLSL_DeleteGPUShader(&tr.lightallShader[i]);
+
+ GLSL_DeleteGPUShader(&tr.shadowmapShader);
+ GLSL_DeleteGPUShader(&tr.pshadowShader);
+ GLSL_DeleteGPUShader(&tr.down4xShader);
+ GLSL_DeleteGPUShader(&tr.bokehShader);
+ GLSL_DeleteGPUShader(&tr.tonemapShader);
+
+ for ( i = 0; i < 2; i++)
+ GLSL_DeleteGPUShader(&tr.calclevels4xShader[i]);
+
+ GLSL_DeleteGPUShader(&tr.shadowmaskShader);
+ GLSL_DeleteGPUShader(&tr.ssaoShader);
+
+ for ( i = 0; i < 4; i++)
+ GLSL_DeleteGPUShader(&tr.depthBlurShader[i]);
+}
+
+
+void GLSL_BindProgram(shaderProgram_t * program)
+{
+ GLuint programObject = program ? program->program : 0;
+ const char *name = program ? program->name : "NULL";
+
+ if(r_logFile->integer)
+ {
+ // don't just call LogComment, or we will get a call to va() every frame!
+ GLimp_LogComment((char*)va("--- GLSL_BindProgram( %s ) ---\n", name));
+ }
+
+ if (GL_UseProgram(programObject))
+ backEnd.pc.c_glslShaderBinds++;
+}
+
+
+shaderProgram_t *GLSL_GetGenericShaderProgram(int stage)
+{
+ shaderStage_t *pStage = tess.xstages[stage];
+ int shaderAttribs = 0;
+
+ if (tess.fogNum && pStage->adjustColorsForFog)
+ {
+ shaderAttribs |= GENERICDEF_USE_FOG;
+ }
+
+ switch (pStage->rgbGen)
+ {
+ case CGEN_LIGHTING_DIFFUSE:
+ shaderAttribs |= GENERICDEF_USE_RGBAGEN;
+ break;
+ default:
+ break;
+ }
+
+ switch (pStage->alphaGen)
+ {
+ case AGEN_LIGHTING_SPECULAR:
+ case AGEN_PORTAL:
+ shaderAttribs |= GENERICDEF_USE_RGBAGEN;
+ break;
+ default:
+ break;
+ }
+
+ if (pStage->bundle[0].tcGen != TCGEN_TEXTURE)
+ {
+ shaderAttribs |= GENERICDEF_USE_TCGEN_AND_TCMOD;
+ }
+
+ if (tess.shader->numDeforms && !ShaderRequiresCPUDeforms(tess.shader))
+ {
+ shaderAttribs |= GENERICDEF_USE_DEFORM_VERTEXES;
+ }
+
+ if (glState.vertexAnimation)
+ {
+ shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION;
+ }
+
+ if (pStage->bundle[0].numTexMods)
+ {
+ shaderAttribs |= GENERICDEF_USE_TCGEN_AND_TCMOD;
+ }
+
+ return &tr.genericShader[shaderAttribs];
+}
diff --git a/src/renderergl2/tr_image.cpp b/src/renderergl2/tr_image.cpp
new file mode 100644
index 0000000..5e29ff7
--- /dev/null
+++ b/src/renderergl2/tr_image.cpp
@@ -0,0 +1,3235 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_image.c
+#include "tr_local.h"
+
+#include "tr_dsa.h"
+
+static byte s_intensitytable[256];
+static unsigned char s_gammatable[256];
+
+int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
+int gl_filter_max = GL_LINEAR;
+
+#define FILE_HASH_SIZE 1024
+static image_t* hashTable[FILE_HASH_SIZE];
+
+/*
+** R_GammaCorrect
+*/
+void R_GammaCorrect( byte *buffer, int bufSize ) {
+ int i;
+
+ for ( i = 0; i < bufSize; i++ ) {
+ buffer[i] = s_gammatable[buffer[i]];
+ }
+}
+
+struct textureMode_t {
+ const char *name;
+ int minimize, maximize;
+};
+
+textureMode_t modes[] = {
+ {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
+ {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
+ {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
+ {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
+ {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
+ {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
+};
+
+/*
+================
+return a hash value for the filename
+================
+*/
+static long generateHashValue( const char *fname ) {
+ int i;
+ long hash;
+ char letter;
+
+ hash = 0;
+ i = 0;
+ while (fname[i] != '\0') {
+ letter = tolower(fname[i]);
+ if (letter =='.') break; // don't include extension
+ if (letter =='\\') letter = '/'; // damn path names
+ hash+=(long)(letter)*(i+119);
+ i++;
+ }
+ hash &= (FILE_HASH_SIZE-1);
+ return hash;
+}
+
+/*
+===============
+GL_TextureMode
+===============
+*/
+void GL_TextureMode( const char *string ) {
+ int i;
+ image_t *glt;
+
+ for ( i=0 ; i< 6 ; i++ ) {
+ if ( !Q_stricmp( modes[i].name, string ) ) {
+ break;
+ }
+ }
+
+ // hack to prevent trilinear from being set on voodoo,
+ // because their driver freaks...
+ if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) {
+ ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" );
+ i = 3;
+ }
+
+
+ if ( i == 6 ) {
+ ri.Printf (PRINT_ALL, "bad filter name\n");
+ return;
+ }
+
+ gl_filter_min = modes[i].minimize;
+ gl_filter_max = modes[i].maximize;
+
+ // change all the existing mipmap texture objects
+ for ( i = 0 ; i < tr.numImages ; i++ ) {
+ glt = tr.images[ i ];
+ if ( glt->flags & IMGFLAG_MIPMAP && !(glt->flags & IMGFLAG_CUBEMAP)) {
+ qglTextureParameterfEXT(glt->texnum, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+ qglTextureParameterfEXT(glt->texnum, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+ }
+ }
+}
+
+/*
+===============
+R_SumOfUsedImages
+===============
+*/
+int R_SumOfUsedImages( void ) {
+ int total;
+ int i;
+
+ total = 0;
+ for ( i = 0; i < tr.numImages; i++ ) {
+ if ( tr.images[i]->frameUsed == tr.frameCount ) {
+ total += tr.images[i]->uploadWidth * tr.images[i]->uploadHeight;
+ }
+ }
+
+ return total;
+}
+
+/*
+===============
+R_ImageList_f
+===============
+*/
+void R_ImageList_f( void ) {
+ int i;
+ int estTotalSize = 0;
+
+ ri.Printf(PRINT_ALL, "\n -w-- -h-- -type-- -size- --name-------\n");
+
+ for ( i = 0 ; i < tr.numImages ; i++ )
+ {
+ image_t *image = tr.images[i];
+ const char *format = "???? ";
+ const char *sizeSuffix;
+ int estSize;
+ int displaySize;
+
+ estSize = image->uploadHeight * image->uploadWidth;
+
+ switch(image->internalFormat)
+ {
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+ format = "sDXT1 ";
+ // 64 bits per 16 pixels, so 4 bits per pixel
+ estSize /= 2;
+ break;
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+ format = "sDXT5 ";
+ // 128 bits per 16 pixels, so 1 byte per pixel
+ break;
+ case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB:
+ format = "sBPTC ";
+ // 128 bits per 16 pixels, so 1 byte per pixel
+ break;
+ case GL_COMPRESSED_RG_RGTC2:
+ format = "RGTC2 ";
+ // 128 bits per 16 pixels, so 1 byte per pixel
+ break;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ format = "DXT1 ";
+ // 64 bits per 16 pixels, so 4 bits per pixel
+ estSize /= 2;
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ format = "DXT1a ";
+ // 64 bits per 16 pixels, so 4 bits per pixel
+ estSize /= 2;
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ format = "DXT5 ";
+ // 128 bits per 16 pixels, so 1 byte per pixel
+ break;
+ case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB:
+ format = "BPTC ";
+ // 128 bits per 16 pixels, so 1 byte per pixel
+ break;
+ case GL_RGB4_S3TC:
+ format = "S3TC ";
+ // same as DXT1?
+ estSize /= 2;
+ break;
+ case GL_RGBA16F:
+ format = "RGBA16F";
+ // 8 bytes per pixel
+ estSize *= 8;
+ break;
+ case GL_RGBA16:
+ format = "RGBA16 ";
+ // 8 bytes per pixel
+ estSize *= 8;
+ break;
+ case GL_RGBA4:
+ case GL_RGBA8:
+ case GL_RGBA:
+ format = "RGBA ";
+ // 4 bytes per pixel
+ estSize *= 4;
+ break;
+ case GL_LUMINANCE8:
+ case GL_LUMINANCE16:
+ case GL_LUMINANCE:
+ format = "L ";
+ // 1 byte per pixel?
+ break;
+ case GL_RGB5:
+ case GL_RGB8:
+ case GL_RGB:
+ format = "RGB ";
+ // 3 bytes per pixel?
+ estSize *= 3;
+ break;
+ case GL_LUMINANCE8_ALPHA8:
+ case GL_LUMINANCE16_ALPHA16:
+ case GL_LUMINANCE_ALPHA:
+ format = "LA ";
+ // 2 bytes per pixel?
+ estSize *= 2;
+ break;
+ case GL_SRGB_EXT:
+ case GL_SRGB8_EXT:
+ format = "sRGB ";
+ // 3 bytes per pixel?
+ estSize *= 3;
+ break;
+ case GL_SRGB_ALPHA_EXT:
+ case GL_SRGB8_ALPHA8_EXT:
+ format = "sRGBA ";
+ // 4 bytes per pixel?
+ estSize *= 4;
+ break;
+ case GL_SLUMINANCE_EXT:
+ case GL_SLUMINANCE8_EXT:
+ format = "sL ";
+ // 1 byte per pixel?
+ break;
+ case GL_SLUMINANCE_ALPHA_EXT:
+ case GL_SLUMINANCE8_ALPHA8_EXT:
+ format = "sLA ";
+ // 2 byte per pixel?
+ estSize *= 2;
+ break;
+ case GL_DEPTH_COMPONENT16:
+ format = "Depth16";
+ // 2 bytes per pixel
+ estSize *= 2;
+ break;
+ case GL_DEPTH_COMPONENT24:
+ format = "Depth24";
+ // 3 bytes per pixel
+ estSize *= 3;
+ break;
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_COMPONENT32:
+ format = "Depth32";
+ // 4 bytes per pixel
+ estSize *= 4;
+ break;
+ }
+
+ // mipmap adds about 50%
+ if (image->flags & IMGFLAG_MIPMAP)
+ estSize += estSize / 2;
+
+ sizeSuffix = "b ";
+ displaySize = estSize;
+
+ if (displaySize > 1024)
+ {
+ displaySize /= 1024;
+ sizeSuffix = "kb";
+ }
+
+ if (displaySize > 1024)
+ {
+ displaySize /= 1024;
+ sizeSuffix = "Mb";
+ }
+
+ if (displaySize > 1024)
+ {
+ displaySize /= 1024;
+ sizeSuffix = "Gb";
+ }
+
+ ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName);
+ estTotalSize += estSize;
+ }
+
+ ri.Printf (PRINT_ALL, " ---------\n");
+ ri.Printf (PRINT_ALL, " approx %i bytes\n", estTotalSize);
+ ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages );
+}
+
+//=======================================================================
+
+/*
+================
+ResampleTexture
+
+Used to resample images in a more general than quartering fashion.
+
+This will only be filtered properly if the resampled size
+is greater than half the original size.
+
+If a larger shrinking is needed, use the mipmap function
+before or after.
+================
+*/
+static void ResampleTexture( byte *in, int inwidth, int inheight, byte *out,
+ int outwidth, int outheight ) {
+ int i, j;
+ byte *inrow, *inrow2;
+ int frac, fracstep;
+ int p1[2048], p2[2048];
+ byte *pix1, *pix2, *pix3, *pix4;
+
+ if (outwidth>2048)
+ ri.Error(ERR_DROP, "ResampleTexture: max width");
+
+ fracstep = inwidth*0x10000/outwidth;
+
+ frac = fracstep>>2;
+ for ( i=0 ; i<outwidth ; i++ ) {
+ p1[i] = 4*(frac>>16);
+ frac += fracstep;
+ }
+ frac = 3*(fracstep>>2);
+ for ( i=0 ; i<outwidth ; i++ ) {
+ p2[i] = 4*(frac>>16);
+ frac += fracstep;
+ }
+
+ for (i=0 ; i<outheight ; i++) {
+ inrow = in + 4*inwidth*(int)((i+0.25)*inheight/outheight);
+ inrow2 = in + 4*inwidth*(int)((i+0.75)*inheight/outheight);
+ for (j=0 ; j<outwidth ; j++) {
+ pix1 = inrow + p1[j];
+ pix2 = inrow + p2[j];
+ pix3 = inrow2 + p1[j];
+ pix4 = inrow2 + p2[j];
+ *out++ = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;
+ *out++ = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;
+ *out++ = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;
+ *out++ = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;
+ }
+ }
+}
+
+static void RGBAtoYCoCgA(const byte *in, byte *out, int width, int height)
+{
+ int x, y;
+
+ for (y = 0; y < height; y++)
+ {
+ const byte *inbyte = in + y * width * 4;
+ byte *outbyte = out + y * width * 4;
+
+ for (x = 0; x < width; x++)
+ {
+ byte r, g, b, a, rb2;
+
+ r = *inbyte++;
+ g = *inbyte++;
+ b = *inbyte++;
+ a = *inbyte++;
+ rb2 = (r + b) >> 1;
+
+ *outbyte++ = (g + rb2) >> 1; // Y = R/4 + G/2 + B/4
+ *outbyte++ = (r - b + 256) >> 1; // Co = R/2 - B/2
+ *outbyte++ = (g - rb2 + 256) >> 1; // Cg = -R/4 + G/2 - B/4
+ *outbyte++ = a;
+ }
+ }
+}
+
+static void YCoCgAtoRGBA(const byte *in, byte *out, int width, int height)
+{
+ int x, y;
+
+ for (y = 0; y < height; y++)
+ {
+ const byte *inbyte = in + y * width * 4;
+ byte *outbyte = out + y * width * 4;
+
+ for (x = 0; x < width; x++)
+ {
+ byte _Y, Co, Cg, a;
+
+ _Y = *inbyte++;
+ Co = *inbyte++;
+ Cg = *inbyte++;
+ a = *inbyte++;
+
+ *outbyte++ = CLAMP(_Y + Co - Cg, 0, 255); // R = Y + Co - Cg
+ *outbyte++ = CLAMP(_Y + Cg - 128, 0, 255); // G = Y + Cg
+ *outbyte++ = CLAMP(_Y - Co - Cg + 256, 0, 255); // B = Y - Co - Cg
+ *outbyte++ = a;
+ }
+ }
+}
+
+
+// uses a sobel filter to change a texture to a normal map
+static void RGBAtoNormal(const byte *in, byte *out, int width, int height, bool clampToEdge)
+{
+ int x, y, max;
+
+ // convert to heightmap, storing in alpha
+ // same as converting to Y in YCoCg
+ max = 1;
+ for (y = 0; y < height; y++)
+ {
+ const byte *inbyte = in + y * width * 4;
+ byte *outbyte = out + y * width * 4 + 3;
+
+ for (x = 0; x < width; x++)
+ {
+ byte result = (inbyte[0] >> 2) + (inbyte[1] >> 1) + (inbyte[2] >> 2);
+ result = result * result / 255; // Make linear
+ *outbyte = result;
+ max = MAX(max, *outbyte);
+ outbyte += 4;
+ inbyte += 4;
+ }
+ }
+
+ // level out heights
+ if (max < 255)
+ {
+ for (y = 0; y < height; y++)
+ {
+ byte *outbyte = out + y * width * 4 + 3;
+
+ for (x = 0; x < width; x++)
+ {
+ *outbyte = *outbyte + (255 - max);
+ outbyte += 4;
+ }
+ }
+ }
+
+
+ // now run sobel filter over height values to generate X and Y
+ // then normalize
+ for (y = 0; y < height; y++)
+ {
+ byte *outbyte = out + y * width * 4;
+
+ for (x = 0; x < width; x++)
+ {
+ // 0 1 2
+ // 3 4 5
+ // 6 7 8
+
+ byte s[9];
+ int x2, y2, i;
+ vec3_t normal;
+
+ i = 0;
+ for (y2 = -1; y2 <= 1; y2++)
+ {
+ int src_y = y + y2;
+
+ if (clampToEdge)
+ {
+ src_y = CLAMP(src_y, 0, height - 1);
+ }
+ else
+ {
+ src_y = (src_y + height) % height;
+ }
+
+
+ for (x2 = -1; x2 <= 1; x2++)
+ {
+ int src_x = x + x2;
+
+ if (clampToEdge)
+ {
+ src_x = CLAMP(src_x, 0, width - 1);
+ }
+ else
+ {
+ src_x = (src_x + width) % width;
+ }
+
+ s[i++] = *(out + (src_y * width + src_x) * 4 + 3);
+ }
+ }
+
+ normal[0] = s[0] - s[2]
+ + 2 * s[3] - 2 * s[5]
+ + s[6] - s[8];
+
+ normal[1] = s[0] + 2 * s[1] + s[2]
+
+ - s[6] - 2 * s[7] - s[8];
+
+ normal[2] = s[4] * 4;
+
+ if (!VectorNormalize2(normal, normal))
+ {
+ VectorSet(normal, 0, 0, 1);
+ }
+
+ *outbyte++ = FloatToOffsetByte(normal[0]);
+ *outbyte++ = FloatToOffsetByte(normal[1]);
+ *outbyte++ = FloatToOffsetByte(normal[2]);
+ outbyte++;
+ }
+ }
+}
+
+#define COPYSAMPLE(a,b) *(unsigned int *)(a) = *(unsigned int *)(b)
+
+// based on Fast Curve Based Interpolation
+// from Fast Artifacts-Free Image Interpolation (http://www.andreagiachetti.it/icbi/)
+// assumes data has a 2 pixel thick border of clamped or wrapped data
+// expects data to be a grid with even (0, 0), (2, 0), (0, 2), (2, 2) etc pixels filled
+// only performs FCBI on specified component
+static void DoFCBI(byte *in, byte *out, int width, int height, int component)
+{
+ int x, y;
+ byte *outbyte, *inbyte;
+
+ // copy in to out
+ for (y = 2; y < height - 2; y += 2)
+ {
+ inbyte = in + (y * width + 2) * 4 + component;
+ outbyte = out + (y * width + 2) * 4 + component;
+
+ for (x = 2; x < width - 2; x += 2)
+ {
+ *outbyte = *inbyte;
+ outbyte += 8;
+ inbyte += 8;
+ }
+ }
+
+ for (y = 3; y < height - 3; y += 2)
+ {
+ // diagonals
+ //
+ // NWp - northwest interpolated pixel
+ // NEp - northeast interpolated pixel
+ // NWd - northwest first derivative
+ // NEd - northeast first derivative
+ // NWdd - northwest second derivative
+ // NEdd - northeast second derivative
+ //
+ // Uses these samples:
+ //
+ // 0
+ // - - a - b - -
+ // - - - - - - -
+ // c - d - e - f
+ // 0 - - - - - - -
+ // g - h - i - j
+ // - - - - - - -
+ // - - k - l - -
+ //
+ // x+2 uses these samples:
+ //
+ // 0
+ // - - - - a - b - -
+ // - - - - - - - - -
+ // - - c - d - e - f
+ // 0 - - - - - - - - -
+ // - - g - h - i - j
+ // - - - - - - - - -
+ // - - - - k - l - -
+ //
+ // so we can reuse 8 of them on next iteration
+ //
+ // a=b, c=d, d=e, e=f, g=h, h=i, i=j, k=l
+ //
+ // only b, f, j, and l need to be sampled on next iteration
+
+ byte sa, sb, sc, sd, se, sf, sg, sh, si, sj, sk, sl;
+ byte *line1, *line2, *line3, *line4;
+
+ x = 3;
+
+ // optimization one
+ // SAMPLE2(sa, x-1, y-3);
+ //SAMPLE2(sc, x-3, y-1); SAMPLE2(sd, x-1, y-1); SAMPLE2(se, x+1, y-1);
+ //SAMPLE2(sg, x-3, y+1); SAMPLE2(sh, x-1, y+1); SAMPLE2(si, x+1, y+1);
+ // SAMPLE2(sk, x-1, y+3);
+
+ // optimization two
+ line1 = in + ((y - 3) * width + (x - 1)) * 4 + component;
+ line2 = in + ((y - 1) * width + (x - 3)) * 4 + component;
+ line3 = in + ((y + 1) * width + (x - 3)) * 4 + component;
+ line4 = in + ((y + 3) * width + (x - 1)) * 4 + component;
+
+ // COPYSAMPLE(sa, line1); line1 += 8;
+ //COPYSAMPLE(sc, line2); line2 += 8; COPYSAMPLE(sd, line2); line2 += 8; COPYSAMPLE(se, line2); line2 += 8;
+ //COPYSAMPLE(sg, line3); line3 += 8; COPYSAMPLE(sh, line3); line3 += 8; COPYSAMPLE(si, line3); line3 += 8;
+ // COPYSAMPLE(sk, line4); line4 += 8;
+
+ sa = *line1; line1 += 8;
+ sc = *line2; line2 += 8; sd = *line2; line2 += 8; se = *line2; line2 += 8;
+ sg = *line3; line3 += 8; sh = *line3; line3 += 8; si = *line3; line3 += 8;
+ sk = *line4; line4 += 8;
+
+ outbyte = out + (y * width + x) * 4 + component;
+
+ for ( ; x < width - 3; x += 2)
+ {
+ int NWd, NEd, NWp, NEp;
+
+ // original
+ // SAMPLE2(sa, x-1, y-3); SAMPLE2(sb, x+1, y-3);
+ //SAMPLE2(sc, x-3, y-1); SAMPLE2(sd, x-1, y-1); SAMPLE2(se, x+1, y-1); SAMPLE2(sf, x+3, y-1);
+ //SAMPLE2(sg, x-3, y+1); SAMPLE2(sh, x-1, y+1); SAMPLE2(si, x+1, y+1); SAMPLE2(sj, x+3, y+1);
+ // SAMPLE2(sk, x-1, y+3); SAMPLE2(sl, x+1, y+3);
+
+ // optimization one
+ //SAMPLE2(sb, x+1, y-3);
+ //SAMPLE2(sf, x+3, y-1);
+ //SAMPLE2(sj, x+3, y+1);
+ //SAMPLE2(sl, x+1, y+3);
+
+ // optimization two
+ //COPYSAMPLE(sb, line1); line1 += 8;
+ //COPYSAMPLE(sf, line2); line2 += 8;
+ //COPYSAMPLE(sj, line3); line3 += 8;
+ //COPYSAMPLE(sl, line4); line4 += 8;
+
+ sb = *line1; line1 += 8;
+ sf = *line2; line2 += 8;
+ sj = *line3; line3 += 8;
+ sl = *line4; line4 += 8;
+
+ NWp = sd + si;
+ NEp = se + sh;
+ NWd = abs(sd - si);
+ NEd = abs(se - sh);
+
+ if (NWd > 100 || NEd > 100 || abs(NWp-NEp) > 200)
+ {
+ if (NWd < NEd)
+ *outbyte = NWp >> 1;
+ else
+ *outbyte = NEp >> 1;
+ }
+ else
+ {
+ int NWdd, NEdd;
+
+ //NEdd = abs(sg + sd + sb - 3 * (se + sh) + sk + si + sf);
+ //NWdd = abs(sa + se + sj - 3 * (sd + si) + sc + sh + sl);
+ NEdd = abs(sg + sb - 3 * NEp + sk + sf + NWp);
+ NWdd = abs(sa + sj - 3 * NWp + sc + sl + NEp);
+
+ if (NWdd > NEdd)
+ *outbyte = NWp >> 1;
+ else
+ *outbyte = NEp >> 1;
+ }
+
+ outbyte += 8;
+
+ // COPYSAMPLE(sa, sb);
+ //COPYSAMPLE(sc, sd); COPYSAMPLE(sd, se); COPYSAMPLE(se, sf);
+ //COPYSAMPLE(sg, sh); COPYSAMPLE(sh, si); COPYSAMPLE(si, sj);
+ // COPYSAMPLE(sk, sl);
+
+ sa = sb;
+ sc = sd; sd = se; se = sf;
+ sg = sh; sh = si; si = sj;
+ sk = sl;
+ }
+ }
+
+ // hack: copy out to in again
+ for (y = 3; y < height - 3; y += 2)
+ {
+ inbyte = out + (y * width + 3) * 4 + component;
+ outbyte = in + (y * width + 3) * 4 + component;
+
+ for (x = 3; x < width - 3; x += 2)
+ {
+ *outbyte = *inbyte;
+ outbyte += 8;
+ inbyte += 8;
+ }
+ }
+
+ for (y = 2; y < height - 3; y++)
+ {
+ // horizontal & vertical
+ //
+ // hp - horizontally interpolated pixel
+ // vp - vertically interpolated pixel
+ // hd - horizontal first derivative
+ // vd - vertical first derivative
+ // hdd - horizontal second derivative
+ // vdd - vertical second derivative
+ // Uses these samples:
+ //
+ // 0
+ // - a - b -
+ // c - d - e
+ // 0 - f - g -
+ // h - i - j
+ // - k - l -
+ //
+ // x+2 uses these samples:
+ //
+ // 0
+ // - - - a - b -
+ // - - c - d - e
+ // 0 - - - f - g -
+ // - - h - i - j
+ // - - - k - l -
+ //
+ // so we can reuse 7 of them on next iteration
+ //
+ // a=b, c=d, d=e, f=g, h=i, i=j, k=l
+ //
+ // only b, e, g, j, and l need to be sampled on next iteration
+
+ byte sa, sb, sc, sd, se, sf, sg, sh, si, sj, sk, sl;
+ byte *line1, *line2, *line3, *line4, *line5;
+
+ //x = (y + 1) % 2;
+ x = (y + 1) % 2 + 2;
+
+ // optimization one
+ // SAMPLE2(sa, x-1, y-2);
+ //SAMPLE2(sc, x-2, y-1); SAMPLE2(sd, x, y-1);
+ // SAMPLE2(sf, x-1, y );
+ //SAMPLE2(sh, x-2, y+1); SAMPLE2(si, x, y+1);
+ // SAMPLE2(sk, x-1, y+2);
+
+ line1 = in + ((y - 2) * width + (x - 1)) * 4 + component;
+ line2 = in + ((y - 1) * width + (x - 2)) * 4 + component;
+ line3 = in + ((y ) * width + (x - 1)) * 4 + component;
+ line4 = in + ((y + 1) * width + (x - 2)) * 4 + component;
+ line5 = in + ((y + 2) * width + (x - 1)) * 4 + component;
+
+ // COPYSAMPLE(sa, line1); line1 += 8;
+ //COPYSAMPLE(sc, line2); line2 += 8; COPYSAMPLE(sd, line2); line2 += 8;
+ // COPYSAMPLE(sf, line3); line3 += 8;
+ //COPYSAMPLE(sh, line4); line4 += 8; COPYSAMPLE(si, line4); line4 += 8;
+ // COPYSAMPLE(sk, line5); line5 += 8;
+
+ sa = *line1; line1 += 8;
+ sc = *line2; line2 += 8; sd = *line2; line2 += 8;
+ sf = *line3; line3 += 8;
+ sh = *line4; line4 += 8; si = *line4; line4 += 8;
+ sk = *line5; line5 += 8;
+
+ outbyte = out + (y * width + x) * 4 + component;
+
+ for ( ; x < width - 3; x+=2)
+ {
+ int hd, vd, hp, vp;
+
+ // SAMPLE2(sa, x-1, y-2); SAMPLE2(sb, x+1, y-2);
+ //SAMPLE2(sc, x-2, y-1); SAMPLE2(sd, x, y-1); SAMPLE2(se, x+2, y-1);
+ // SAMPLE2(sf, x-1, y ); SAMPLE2(sg, x+1, y );
+ //SAMPLE2(sh, x-2, y+1); SAMPLE2(si, x, y+1); SAMPLE2(sj, x+2, y+1);
+ // SAMPLE2(sk, x-1, y+2); SAMPLE2(sl, x+1, y+2);
+
+ // optimization one
+ //SAMPLE2(sb, x+1, y-2);
+ //SAMPLE2(se, x+2, y-1);
+ //SAMPLE2(sg, x+1, y );
+ //SAMPLE2(sj, x+2, y+1);
+ //SAMPLE2(sl, x+1, y+2);
+
+ //COPYSAMPLE(sb, line1); line1 += 8;
+ //COPYSAMPLE(se, line2); line2 += 8;
+ //COPYSAMPLE(sg, line3); line3 += 8;
+ //COPYSAMPLE(sj, line4); line4 += 8;
+ //COPYSAMPLE(sl, line5); line5 += 8;
+
+ sb = *line1; line1 += 8;
+ se = *line2; line2 += 8;
+ sg = *line3; line3 += 8;
+ sj = *line4; line4 += 8;
+ sl = *line5; line5 += 8;
+
+ hp = sf + sg;
+ vp = sd + si;
+ hd = abs(sf - sg);
+ vd = abs(sd - si);
+
+ if (hd > 100 || vd > 100 || abs(hp-vp) > 200)
+ {
+ if (hd < vd)
+ *outbyte = hp >> 1;
+ else
+ *outbyte = vp >> 1;
+ }
+ else
+ {
+ int hdd, vdd;
+
+ //hdd = abs(sc[i] + sd[i] + se[i] - 3 * (sf[i] + sg[i]) + sh[i] + si[i] + sj[i]);
+ //vdd = abs(sa[i] + sf[i] + sk[i] - 3 * (sd[i] + si[i]) + sb[i] + sg[i] + sl[i]);
+
+ hdd = abs(sc + se - 3 * hp + sh + sj + vp);
+ vdd = abs(sa + sk - 3 * vp + sb + sl + hp);
+
+ if (hdd > vdd)
+ *outbyte = hp >> 1;
+ else
+ *outbyte = vp >> 1;
+ }
+
+ outbyte += 8;
+
+ // COPYSAMPLE(sa, sb);
+ //COPYSAMPLE(sc, sd); COPYSAMPLE(sd, se);
+ // COPYSAMPLE(sf, sg);
+ //COPYSAMPLE(sh, si); COPYSAMPLE(si, sj);
+ // COPYSAMPLE(sk, sl);
+ sa = sb;
+ sc = sd; sd = se;
+ sf = sg;
+ sh = si; si = sj;
+ sk = sl;
+ }
+ }
+}
+
+// Similar to FCBI, but throws out the second order derivatives for speed
+static void DoFCBIQuick(byte *in, byte *out, int width, int height, int component)
+{
+ int x, y;
+ byte *outbyte, *inbyte;
+
+ // copy in to out
+ for (y = 2; y < height - 2; y += 2)
+ {
+ inbyte = in + (y * width + 2) * 4 + component;
+ outbyte = out + (y * width + 2) * 4 + component;
+
+ for (x = 2; x < width - 2; x += 2)
+ {
+ *outbyte = *inbyte;
+ outbyte += 8;
+ inbyte += 8;
+ }
+ }
+
+ for (y = 3; y < height - 4; y += 2)
+ {
+ byte sd, se, sh, si;
+ byte *line2, *line3;
+
+ x = 3;
+
+ line2 = in + ((y - 1) * width + (x - 1)) * 4 + component;
+ line3 = in + ((y + 1) * width + (x - 1)) * 4 + component;
+
+ sd = *line2; line2 += 8;
+ sh = *line3; line3 += 8;
+
+ outbyte = out + (y * width + x) * 4 + component;
+
+ for ( ; x < width - 4; x += 2)
+ {
+ int NWd, NEd, NWp, NEp;
+
+ se = *line2; line2 += 8;
+ si = *line3; line3 += 8;
+
+ NWp = sd + si;
+ NEp = se + sh;
+ NWd = abs(sd - si);
+ NEd = abs(se - sh);
+
+ if (NWd < NEd)
+ *outbyte = NWp >> 1;
+ else
+ *outbyte = NEp >> 1;
+
+ outbyte += 8;
+
+ sd = se;
+ sh = si;
+ }
+ }
+
+ // hack: copy out to in again
+ for (y = 3; y < height - 3; y += 2)
+ {
+ inbyte = out + (y * width + 3) * 4 + component;
+ outbyte = in + (y * width + 3) * 4 + component;
+
+ for (x = 3; x < width - 3; x += 2)
+ {
+ *outbyte = *inbyte;
+ outbyte += 8;
+ inbyte += 8;
+ }
+ }
+
+ for (y = 2; y < height - 3; y++)
+ {
+ byte sd, sf, sg, si;
+ byte *line2, *line3, *line4;
+
+ x = (y + 1) % 2 + 2;
+
+ line2 = in + ((y - 1) * width + (x )) * 4 + component;
+ line3 = in + ((y ) * width + (x - 1)) * 4 + component;
+ line4 = in + ((y + 1) * width + (x )) * 4 + component;
+
+ outbyte = out + (y * width + x) * 4 + component;
+
+ sf = *line3; line3 += 8;
+
+ for ( ; x < width - 3; x+=2)
+ {
+ int hd, vd, hp, vp;
+
+ sd = *line2; line2 += 8;
+ sg = *line3; line3 += 8;
+ si = *line4; line4 += 8;
+
+ hp = sf + sg;
+ vp = sd + si;
+ hd = abs(sf - sg);
+ vd = abs(sd - si);
+
+ if (hd < vd)
+ *outbyte = hp >> 1;
+ else
+ *outbyte = vp >> 1;
+
+ outbyte += 8;
+
+ sf = sg;
+ }
+ }
+}
+
+// Similar to DoFCBIQuick, but just takes the average instead of checking derivatives
+// as well, this operates on all four components
+static void DoLinear(byte *in, byte *out, int width, int height)
+{
+ int x, y, i;
+ byte *outbyte, *inbyte;
+
+ // copy in to out
+ for (y = 2; y < height - 2; y += 2)
+ {
+ x = 2;
+
+ inbyte = in + (y * width + x) * 4;
+ outbyte = out + (y * width + x) * 4;
+
+ for ( ; x < width - 2; x += 2)
+ {
+ COPYSAMPLE(outbyte, inbyte);
+ outbyte += 8;
+ inbyte += 8;
+ }
+ }
+
+ for (y = 1; y < height - 1; y += 2)
+ {
+ byte sd[4] = {0}, se[4] = {0}, sh[4] = {0}, si[4] = {0};
+ byte *line2, *line3;
+
+ x = 1;
+
+ line2 = in + ((y - 1) * width + (x - 1)) * 4;
+ line3 = in + ((y + 1) * width + (x - 1)) * 4;
+
+ COPYSAMPLE(sd, line2); line2 += 8;
+ COPYSAMPLE(sh, line3); line3 += 8;
+
+ outbyte = out + (y * width + x) * 4;
+
+ for ( ; x < width - 1; x += 2)
+ {
+ COPYSAMPLE(se, line2); line2 += 8;
+ COPYSAMPLE(si, line3); line3 += 8;
+
+ for (i = 0; i < 4; i++)
+ {
+ *outbyte++ = (sd[i] + si[i] + se[i] + sh[i]) >> 2;
+ }
+
+ outbyte += 4;
+
+ COPYSAMPLE(sd, se);
+ COPYSAMPLE(sh, si);
+ }
+ }
+
+ // hack: copy out to in again
+ for (y = 1; y < height - 1; y += 2)
+ {
+ x = 1;
+
+ inbyte = out + (y * width + x) * 4;
+ outbyte = in + (y * width + x) * 4;
+
+ for ( ; x < width - 1; x += 2)
+ {
+ COPYSAMPLE(outbyte, inbyte);
+ outbyte += 8;
+ inbyte += 8;
+ }
+ }
+
+ for (y = 1; y < height - 1; y++)
+ {
+ byte sd[4], sf[4], sg[4], si[4];
+ byte *line2, *line3, *line4;
+
+ x = y % 2 + 1;
+
+ line2 = in + ((y - 1) * width + (x )) * 4;
+ line3 = in + ((y ) * width + (x - 1)) * 4;
+ line4 = in + ((y + 1) * width + (x )) * 4;
+
+ COPYSAMPLE(sf, line3); line3 += 8;
+
+ outbyte = out + (y * width + x) * 4;
+
+ for ( ; x < width - 1; x += 2)
+ {
+ COPYSAMPLE(sd, line2); line2 += 8;
+ COPYSAMPLE(sg, line3); line3 += 8;
+ COPYSAMPLE(si, line4); line4 += 8;
+
+ for (i = 0; i < 4; i++)
+ {
+ *outbyte++ = (sf[i] + sg[i] + sd[i] + si[i]) >> 2;
+ }
+
+ outbyte += 4;
+
+ COPYSAMPLE(sf, sg);
+ }
+ }
+}
+
+
+static void ExpandHalfTextureToGrid( byte *data, int width, int height)
+{
+ int x, y;
+
+ for (y = height / 2; y > 0; y--)
+ {
+ byte *outbyte = data + ((y * 2 - 1) * (width) - 2) * 4;
+ byte *inbyte = data + (y * (width / 2) - 1) * 4;
+
+ for (x = width / 2; x > 0; x--)
+ {
+ COPYSAMPLE(outbyte, inbyte);
+
+ outbyte -= 8;
+ inbyte -= 4;
+ }
+ }
+}
+
+static void FillInNormalizedZ(const byte *in, byte *out, int width, int height)
+{
+ int x, y;
+
+ for (y = 0; y < height; y++)
+ {
+ const byte *inbyte = in + y * width * 4;
+ byte *outbyte = out + y * width * 4;
+
+ for (x = 0; x < width; x++)
+ {
+ byte nx, ny, nz, h;
+ float fnx, fny, fll, fnz;
+
+ nx = *inbyte++;
+ ny = *inbyte++;
+ inbyte++;
+ h = *inbyte++;
+
+ fnx = OffsetByteToFloat(nx);
+ fny = OffsetByteToFloat(ny);
+ fll = 1.0f - fnx * fnx - fny * fny;
+ if (fll >= 0.0f)
+ fnz = (float)sqrt(fll);
+ else
+ fnz = 0.0f;
+
+ nz = FloatToOffsetByte(fnz);
+
+ *outbyte++ = nx;
+ *outbyte++ = ny;
+ *outbyte++ = nz;
+ *outbyte++ = h;
+ }
+ }
+}
+
+
+// size must be even
+#define WORKBLOCK_SIZE 128
+#define WORKBLOCK_BORDER 4
+#define WORKBLOCK_REALSIZE (WORKBLOCK_SIZE + WORKBLOCK_BORDER * 2)
+
+// assumes that data has already been expanded into a 2x2 grid
+static void FCBIByBlock(byte *data, int width, int height, bool clampToEdge, bool normalized)
+{
+ byte workdata[WORKBLOCK_REALSIZE * WORKBLOCK_REALSIZE * 4];
+ byte outdata[WORKBLOCK_REALSIZE * WORKBLOCK_REALSIZE * 4];
+ byte *inbyte, *outbyte;
+ int x, y;
+ int srcx, srcy;
+
+ ExpandHalfTextureToGrid(data, width, height);
+
+ for (y = 0; y < height; y += WORKBLOCK_SIZE)
+ {
+ for (x = 0; x < width; x += WORKBLOCK_SIZE)
+ {
+ int x2, y2;
+ int workwidth, workheight, fullworkwidth, fullworkheight;
+
+ workwidth = MIN(WORKBLOCK_SIZE, width - x);
+ workheight = MIN(WORKBLOCK_SIZE, height - y);
+
+ fullworkwidth = workwidth + WORKBLOCK_BORDER * 2;
+ fullworkheight = workheight + WORKBLOCK_BORDER * 2;
+
+ //memset(workdata, 0, WORKBLOCK_REALSIZE * WORKBLOCK_REALSIZE * 4);
+
+ // fill in work block
+ for (y2 = 0; y2 < fullworkheight; y2 += 2)
+ {
+ srcy = y + y2 - WORKBLOCK_BORDER;
+
+ if (clampToEdge)
+ {
+ srcy = CLAMP(srcy, 0, height - 2);
+ }
+ else
+ {
+ srcy = (srcy + height) % height;
+ }
+
+ outbyte = workdata + y2 * fullworkwidth * 4;
+ inbyte = data + srcy * width * 4;
+
+ for (x2 = 0; x2 < fullworkwidth; x2 += 2)
+ {
+ srcx = x + x2 - WORKBLOCK_BORDER;
+
+ if (clampToEdge)
+ {
+ srcx = CLAMP(srcx, 0, width - 2);
+ }
+ else
+ {
+ srcx = (srcx + width) % width;
+ }
+
+ COPYSAMPLE(outbyte, inbyte + srcx * 4);
+ outbyte += 8;
+ }
+ }
+
+ // submit work block
+ DoLinear(workdata, outdata, fullworkwidth, fullworkheight);
+
+ if (!normalized)
+ {
+ switch (r_imageUpsampleType->integer)
+ {
+ case 0:
+ break;
+ case 1:
+ DoFCBIQuick(workdata, outdata, fullworkwidth, fullworkheight, 0);
+ break;
+ case 2:
+ default:
+ DoFCBI(workdata, outdata, fullworkwidth, fullworkheight, 0);
+ break;
+ }
+ }
+ else
+ {
+ switch (r_imageUpsampleType->integer)
+ {
+ case 0:
+ break;
+ case 1:
+ DoFCBIQuick(workdata, outdata, fullworkwidth, fullworkheight, 0);
+ DoFCBIQuick(workdata, outdata, fullworkwidth, fullworkheight, 1);
+ break;
+ case 2:
+ default:
+ DoFCBI(workdata, outdata, fullworkwidth, fullworkheight, 0);
+ DoFCBI(workdata, outdata, fullworkwidth, fullworkheight, 1);
+ break;
+ }
+ }
+
+ // copy back work block
+ for (y2 = 0; y2 < workheight; y2++)
+ {
+ inbyte = outdata + ((y2 + WORKBLOCK_BORDER) * fullworkwidth + WORKBLOCK_BORDER) * 4;
+ outbyte = data + ((y + y2) * width + x) * 4;
+ for (x2 = 0; x2 < workwidth; x2++)
+ {
+ COPYSAMPLE(outbyte, inbyte);
+ outbyte += 4;
+ inbyte += 4;
+ }
+ }
+ }
+ }
+}
+#undef COPYSAMPLE
+
+/*
+================
+R_LightScaleTexture
+
+Scale up the pixel values in a texture to increase the
+lighting range
+================
+*/
+void R_LightScaleTexture (byte *in, int inwidth, int inheight, bool only_gamma )
+{
+ if ( only_gamma )
+ {
+ if ( !glConfig.deviceSupportsGamma )
+ {
+ int i, c;
+ byte *p;
+
+ p = in;
+
+ c = inwidth*inheight;
+ for (i=0 ; i<c ; i++, p+=4)
+ {
+ p[0] = s_gammatable[p[0]];
+ p[1] = s_gammatable[p[1]];
+ p[2] = s_gammatable[p[2]];
+ }
+ }
+ }
+ else
+ {
+ int i, c;
+ byte *p;
+
+ p = in;
+
+ c = inwidth*inheight;
+
+ if ( glConfig.deviceSupportsGamma )
+ {
+ for (i=0 ; i<c ; i++, p+=4)
+ {
+ p[0] = s_intensitytable[p[0]];
+ p[1] = s_intensitytable[p[1]];
+ p[2] = s_intensitytable[p[2]];
+ }
+ }
+ else
+ {
+ for (i=0 ; i<c ; i++, p+=4)
+ {
+ p[0] = s_gammatable[s_intensitytable[p[0]]];
+ p[1] = s_gammatable[s_intensitytable[p[1]]];
+ p[2] = s_gammatable[s_intensitytable[p[2]]];
+ }
+ }
+ }
+}
+
+
+/*
+================
+R_MipMapsRGB
+
+Operates in place, quartering the size of the texture
+Colors are gamma correct
+================
+*/
+static void R_MipMapsRGB( byte *in, int inWidth, int inHeight)
+{
+ int x, y, c, stride;
+ const byte *in2;
+ float total;
+ static float downmipSrgbLookup[256];
+ static int downmipSrgbLookupSet = 0;
+ byte *out = in;
+
+ if (!downmipSrgbLookupSet) {
+ for (x = 0; x < 256; x++)
+ downmipSrgbLookup[x] = powf(x / 255.0f, 2.2f) * 0.25f;
+ downmipSrgbLookupSet = 1;
+ }
+
+ if (inWidth == 1 && inHeight == 1)
+ return;
+
+ if (inWidth == 1 || inHeight == 1) {
+ for (x = (inWidth * inHeight) >> 1; x; x--) {
+ for (c = 3; c; c--, in++) {
+ total = (downmipSrgbLookup[*(in)] + downmipSrgbLookup[*(in + 4)]) * 2.0f;
+
+ *out++ = (byte)(powf(total, 1.0f / 2.2f) * 255.0f);
+ }
+ *out++ = (*(in) + *(in + 4)) >> 1; in += 5;
+ }
+
+ return;
+ }
+
+ stride = inWidth * 4;
+ inWidth >>= 1; inHeight >>= 1;
+
+ in2 = in + stride;
+ for (y = inHeight; y; y--, in += stride, in2 += stride) {
+ for (x = inWidth; x; x--) {
+ for (c = 3; c; c--, in++, in2++) {
+ total = downmipSrgbLookup[*(in)] + downmipSrgbLookup[*(in + 4)]
+ + downmipSrgbLookup[*(in2)] + downmipSrgbLookup[*(in2 + 4)];
+
+ *out++ = (byte)(powf(total, 1.0f / 2.2f) * 255.0f);
+ }
+
+ *out++ = (*(in) + *(in + 4) + *(in2) + *(in2 + 4)) >> 2; in += 5, in2 += 5;
+ }
+ }
+}
+
+
+static void R_MipMapNormalHeight (const byte *in, byte *out, int width, int height, bool swizzle)
+{
+ int i, j;
+ int row;
+ int sx = swizzle ? 3 : 0;
+ int sa = swizzle ? 0 : 3;
+
+ if ( width == 1 && height == 1 ) {
+ return;
+ }
+
+ row = width * 4;
+ width >>= 1;
+ height >>= 1;
+
+ for (i=0 ; i<height ; i++, in+=row) {
+ for (j=0 ; j<width ; j++, out+=4, in+=8) {
+ vec3_t v;
+
+ v[0] = OffsetByteToFloat(in[sx ]);
+ v[1] = OffsetByteToFloat(in[ 1]);
+ v[2] = OffsetByteToFloat(in[ 2]);
+
+ v[0] += OffsetByteToFloat(in[sx +4]);
+ v[1] += OffsetByteToFloat(in[ 5]);
+ v[2] += OffsetByteToFloat(in[ 6]);
+
+ v[0] += OffsetByteToFloat(in[sx+row ]);
+ v[1] += OffsetByteToFloat(in[ row+1]);
+ v[2] += OffsetByteToFloat(in[ row+2]);
+
+ v[0] += OffsetByteToFloat(in[sx+row+4]);
+ v[1] += OffsetByteToFloat(in[ row+5]);
+ v[2] += OffsetByteToFloat(in[ row+6]);
+
+ VectorNormalizeFast(v);
+
+ //v[0] *= 0.25f;
+ //v[1] *= 0.25f;
+ //v[2] = 1.0f - v[0] * v[0] - v[1] * v[1];
+ //v[2] = sqrt(MAX(v[2], 0.0f));
+
+ out[sx] = FloatToOffsetByte(v[0]);
+ out[1 ] = FloatToOffsetByte(v[1]);
+ out[2 ] = FloatToOffsetByte(v[2]);
+ out[sa] = MAX(MAX(in[sa], in[sa+4]), MAX(in[sa+row], in[sa+row+4]));
+ }
+ }
+}
+
+
+/*
+==================
+R_BlendOverTexture
+
+Apply a color blend over a set of pixels
+==================
+*/
+static void R_BlendOverTexture( byte *data, int pixelCount, byte blend[4] ) {
+ int i;
+ int inverseAlpha;
+ int premult[3];
+
+ inverseAlpha = 255 - blend[3];
+ premult[0] = blend[0] * blend[3];
+ premult[1] = blend[1] * blend[3];
+ premult[2] = blend[2] * blend[3];
+
+ for ( i = 0 ; i < pixelCount ; i++, data+=4 ) {
+ data[0] = ( data[0] * inverseAlpha + premult[0] ) >> 9;
+ data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9;
+ data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9;
+ }
+}
+
+byte mipBlendColors[16][4] = {
+ {0,0,0,0},
+ {255,0,0,128},
+ {0,255,0,128},
+ {0,0,255,128},
+ {255,0,0,128},
+ {0,255,0,128},
+ {0,0,255,128},
+ {255,0,0,128},
+ {0,255,0,128},
+ {0,0,255,128},
+ {255,0,0,128},
+ {0,255,0,128},
+ {0,0,255,128},
+ {255,0,0,128},
+ {0,255,0,128},
+ {0,0,255,128},
+};
+
+static void RawImage_SwizzleRA( byte *data, int width, int height )
+{
+ int i;
+ byte *ptr = data, swap;
+
+ for (i=0; i<width*height; i++, ptr+=4)
+ {
+ // swap red and alpha
+ swap = ptr[0];
+ ptr[0] = ptr[3];
+ ptr[3] = swap;
+ }
+}
+
+
+/*
+===============
+RawImage_ScaleToPower2
+
+===============
+*/
+static bool RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_height, imgType_t type, int/*imgFlags_t*/ flags, byte **resampledBuffer)
+{
+ int width = *inout_width;
+ int height = *inout_height;
+ int scaled_width;
+ int scaled_height;
+ bool picmip = flags & IMGFLAG_PICMIP;
+ bool mipmap = flags & IMGFLAG_MIPMAP;
+ bool clampToEdge = flags & IMGFLAG_CLAMPTOEDGE;
+ bool scaled;
+
+ //
+ // convert to exact power of 2 sizes
+ //
+ if (!mipmap)
+ {
+ scaled_width = width;
+ scaled_height = height;
+ }
+ else
+ {
+ scaled_width = NextPowerOfTwo(width);
+ scaled_height = NextPowerOfTwo(height);
+ }
+
+ if ( r_roundImagesDown->integer && scaled_width > width )
+ scaled_width >>= 1;
+ if ( r_roundImagesDown->integer && scaled_height > height )
+ scaled_height >>= 1;
+
+ if ( picmip && data && resampledBuffer && r_imageUpsample->integer &&
+ scaled_width < r_imageUpsampleMaxSize->integer && scaled_height < r_imageUpsampleMaxSize->integer)
+ {
+ int finalwidth, finalheight;
+ //int startTime, endTime;
+
+ //startTime = ri.Milliseconds();
+
+ finalwidth = scaled_width << r_imageUpsample->integer;
+ finalheight = scaled_height << r_imageUpsample->integer;
+
+ while ( finalwidth > r_imageUpsampleMaxSize->integer
+ || finalheight > r_imageUpsampleMaxSize->integer ) {
+ finalwidth >>= 1;
+ finalheight >>= 1;
+ }
+
+ while ( finalwidth > glConfig.maxTextureSize
+ || finalheight > glConfig.maxTextureSize ) {
+ finalwidth >>= 1;
+ finalheight >>= 1;
+ }
+
+ *resampledBuffer = (byte*)ri.Hunk_AllocateTempMemory( finalwidth * finalheight * 4 );
+
+ if (scaled_width != width || scaled_height != height)
+ ResampleTexture (*data, width, height, *resampledBuffer, scaled_width, scaled_height);
+ else
+ Com_Memcpy(*resampledBuffer, *data, width * height * 4);
+
+ if (type == IMGTYPE_COLORALPHA)
+ RGBAtoYCoCgA(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height);
+
+ while (scaled_width < finalwidth || scaled_height < finalheight)
+ {
+ scaled_width <<= 1;
+ scaled_height <<= 1;
+
+ FCBIByBlock(*resampledBuffer, scaled_width, scaled_height, clampToEdge, (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT));
+ }
+
+ if (type == IMGTYPE_COLORALPHA)
+ YCoCgAtoRGBA(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height);
+ else if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
+ FillInNormalizedZ(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height);
+
+ //endTime = ri.Milliseconds();
+
+ //ri.Printf(PRINT_ALL, "upsampled %dx%d to %dx%d in %dms\n", width, height, scaled_width, scaled_height, endTime - startTime);
+
+ *data = *resampledBuffer;
+ }
+ else if ( scaled_width != width || scaled_height != height )
+ {
+ if (data && resampledBuffer)
+ {
+ *resampledBuffer = (byte*)ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 );
+ ResampleTexture (*data, width, height, *resampledBuffer, scaled_width, scaled_height);
+ *data = *resampledBuffer;
+ }
+ }
+
+ width = scaled_width;
+ height = scaled_height;
+
+ //
+ // perform optional picmip operation
+ //
+ if ( picmip ) {
+ scaled_width >>= r_picmip->integer;
+ scaled_height >>= r_picmip->integer;
+ }
+
+ //
+ // clamp to the current upper OpenGL limit
+ // scale both axis down equally so we don't have to
+ // deal with a half mip resampling
+ //
+ while ( scaled_width > glConfig.maxTextureSize
+ || scaled_height > glConfig.maxTextureSize ) {
+ scaled_width >>= 1;
+ scaled_height >>= 1;
+ }
+
+ //
+ // clamp to minimum size
+ //
+ scaled_width = MAX(1, scaled_width);
+ scaled_height = MAX(1, scaled_height);
+
+ scaled = (width != scaled_width) || (height != scaled_height);
+
+ //
+ // rescale texture to new size using existing mipmap functions
+ //
+ if (data)
+ {
+ while (width > scaled_width || height > scaled_height)
+ {
+ if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
+ R_MipMapNormalHeight(*data, *data, width, height, false);
+ else
+ R_MipMapsRGB(*data, width, height);
+
+ width = MAX(1, width >> 1);
+ height = MAX(1, height >> 1);
+ }
+ }
+
+ *inout_width = width;
+ *inout_height = height;
+
+ return scaled;
+}
+
+
+static bool RawImage_HasAlpha(const byte *scan, int numPixels)
+{
+ int i;
+
+ if (!scan)
+ return true;
+
+ for ( i = 0; i < numPixels; i++ )
+ {
+ if ( scan[i*4 + 3] != 255 )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picFormat, bool lightMap, imgType_t type, int/*imgFlags_t*/ flags)
+{
+ int samples = 3;
+ GLenum internalFormat = GL_RGB;
+ bool forceNoCompression = (flags & IMGFLAG_NO_COMPRESSION);
+ bool normalmap = (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT);
+
+ if (picFormat != GL_RGBA8)
+ return picFormat;
+
+ if(normalmap)
+ {
+ if ((type == IMGTYPE_NORMALHEIGHT) && RawImage_HasAlpha(data, numPixels) && r_parallaxMapping->integer)
+ {
+ if (!forceNoCompression && glRefConfig.textureCompression & TCR_BPTC)
+ {
+ internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
+ }
+ else if (!forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB)
+ {
+ internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ }
+ else if ( r_texturebits->integer == 16 )
+ {
+ internalFormat = GL_RGBA4;
+ }
+ else if ( r_texturebits->integer == 32 )
+ {
+ internalFormat = GL_RGBA8;
+ }
+ else
+ {
+ internalFormat = GL_RGBA;
+ }
+ }
+ else
+ {
+ if (!forceNoCompression && glRefConfig.textureCompression & TCR_RGTC)
+ {
+ internalFormat = GL_COMPRESSED_RG_RGTC2;
+ }
+ else if (!forceNoCompression && glRefConfig.textureCompression & TCR_BPTC)
+ {
+ internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
+ }
+ else if (!forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB)
+ {
+ internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ }
+ else if (r_texturebits->integer == 16)
+ {
+ internalFormat = GL_RGB5;
+ }
+ else if (r_texturebits->integer == 32)
+ {
+ internalFormat = GL_RGB8;
+ }
+ else
+ {
+ internalFormat = GL_RGB;
+ }
+ }
+ }
+ else if(lightMap)
+ {
+ if(r_greyscale->integer)
+ internalFormat = GL_LUMINANCE;
+ else
+ internalFormat = GL_RGBA;
+ }
+ else
+ {
+ if (RawImage_HasAlpha(data, numPixels))
+ {
+ samples = 4;
+ }
+
+ // select proper internal format
+ if ( samples == 3 )
+ {
+ if(r_greyscale->integer)
+ {
+ if(r_texturebits->integer == 16)
+ internalFormat = GL_LUMINANCE8;
+ else if(r_texturebits->integer == 32)
+ internalFormat = GL_LUMINANCE16;
+ else
+ internalFormat = GL_LUMINANCE;
+ }
+ else
+ {
+ if ( !forceNoCompression && (glRefConfig.textureCompression & TCR_BPTC) )
+ {
+ internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
+ }
+ else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB )
+ {
+ internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ }
+ else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC )
+ {
+ internalFormat = GL_RGB4_S3TC;
+ }
+ else if ( r_texturebits->integer == 16 )
+ {
+ internalFormat = GL_RGB5;
+ }
+ else if ( r_texturebits->integer == 32 )
+ {
+ internalFormat = GL_RGB8;
+ }
+ else
+ {
+ internalFormat = GL_RGB;
+ }
+ }
+ }
+ else if ( samples == 4 )
+ {
+ if(r_greyscale->integer)
+ {
+ if(r_texturebits->integer == 16)
+ internalFormat = GL_LUMINANCE8_ALPHA8;
+ else if(r_texturebits->integer == 32)
+ internalFormat = GL_LUMINANCE16_ALPHA16;
+ else
+ internalFormat = GL_LUMINANCE_ALPHA;
+ }
+ else
+ {
+ if ( !forceNoCompression && (glRefConfig.textureCompression & TCR_BPTC) )
+ {
+ internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
+ }
+ else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB )
+ {
+ internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ }
+ else if ( r_texturebits->integer == 16 )
+ {
+ internalFormat = GL_RGBA4;
+ }
+ else if ( r_texturebits->integer == 32 )
+ {
+ internalFormat = GL_RGBA8;
+ }
+ else
+ {
+ internalFormat = GL_RGBA;
+ }
+ }
+ }
+ }
+
+ return internalFormat;
+}
+
+static void CompressMonoBlock(byte outdata[8], const byte indata[16])
+{
+ int hi, lo, diff, bias, outbyte, shift, i;
+ byte *p = outdata;
+
+ hi = lo = indata[0];
+ for (i = 1; i < 16; i++)
+ {
+ hi = MAX(indata[i], hi);
+ lo = MIN(indata[i], lo);
+ }
+
+ *p++ = hi;
+ *p++ = lo;
+
+ diff = hi - lo;
+
+ if (diff == 0)
+ {
+ outbyte = (hi == 255) ? 255 : 0;
+
+ for (i = 0; i < 6; i++)
+ *p++ = outbyte;
+
+ return;
+ }
+
+ bias = diff / 2 - lo * 7;
+ outbyte = shift = 0;
+ for (i = 0; i < 16; i++)
+ {
+ const byte fixIndex[8] = { 1, 7, 6, 5, 4, 3, 2, 0 };
+ byte index = fixIndex[(indata[i] * 7 + bias) / diff];
+
+ outbyte |= index << shift;
+ shift += 3;
+ if (shift >= 8)
+ {
+ *p++ = outbyte & 0xff;
+ shift -= 8;
+ outbyte >>= 8;
+ }
+ }
+}
+
+static void RawImage_UploadToRgtc2Texture(GLuint texture, int miplevel, int x, int y, int width, int height, byte *data)
+{
+ int wBlocks, hBlocks, iy, ix, size;
+ byte *compressedData, *p;
+
+ wBlocks = (width + 3) / 4;
+ hBlocks = (height + 3) / 4;
+ size = wBlocks * hBlocks * 16;
+
+ p = compressedData = (byte*)ri.Hunk_AllocateTempMemory(size);
+ for (iy = 0; iy < height; iy += 4)
+ {
+ int oh = MIN(4, height - iy);
+
+ for (ix = 0; ix < width; ix += 4)
+ {
+ byte workingData[16];
+ int component;
+
+ int ow = MIN(4, width - ix);
+
+ for (component = 0; component < 2; component++)
+ {
+ int ox, oy;
+
+ for (oy = 0; oy < oh; oy++)
+ for (ox = 0; ox < ow; ox++)
+ workingData[oy * 4 + ox] = data[((iy + oy) * width + ix + ox) * 4 + component];
+
+ // dupe data to fill
+ for (oy = 0; oy < 4; oy++)
+ for (ox = (oy < oh) ? ow : 0; ox < 4; ox++)
+ workingData[oy * 4 + ox] = workingData[(oy % oh) * 4 + ox % ow];
+
+ CompressMonoBlock(p, workingData);
+ p += 8;
+ }
+ }
+ }
+
+ // FIXME: Won't work for x/y that aren't multiples of 4.
+ qglCompressedTextureSubImage2DEXT(texture, GL_TEXTURE_2D, miplevel, x, y, width, height, GL_COMPRESSED_RG_RGTC2, size, compressedData);
+
+ ri.Hunk_FreeTempMemory(compressedData);
+}
+
+static int CalculateMipSize(int width, int height, GLenum picFormat)
+{
+ int numBlocks = ((width + 3) / 4) * ((height + 3) / 4);
+ int numPixels = width * height;
+
+ switch (picFormat)
+ {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RED_RGTC1:
+ case GL_COMPRESSED_SIGNED_RED_RGTC1:
+ return numBlocks * 8;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+ case GL_COMPRESSED_RG_RGTC2:
+ case GL_COMPRESSED_SIGNED_RG_RGTC2:
+ case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB:
+ case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB:
+ case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB:
+ case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB:
+ return numBlocks * 16;
+
+ case GL_RGBA8:
+ case GL_SRGB8_ALPHA8_EXT:
+ return numPixels * 4;
+
+ case GL_RGBA16:
+ return numPixels * 8;
+
+ default:
+ ri.Printf(PRINT_ALL, "Unsupported texture format %08x\n", picFormat);
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static GLenum PixelDataFormatFromInternalFormat(GLenum internalFormat)
+{
+ switch (internalFormat)
+ {
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_COMPONENT16_ARB:
+ case GL_DEPTH_COMPONENT24_ARB:
+ case GL_DEPTH_COMPONENT32_ARB:
+ return GL_DEPTH_COMPONENT;
+ default:
+ return GL_RGBA;
+ break;
+ }
+}
+
+static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y,
+ int width, int height, GLenum target, GLenum picFormat,
+ int numMips, GLenum internalFormat, imgType_t type, int/*imgFlags_t*/ flags, bool subtexture )
+{
+ GLenum dataFormat, dataType;
+ bool rgtc = internalFormat == GL_COMPRESSED_RG_RGTC2;
+ bool rgba8 = picFormat == GL_RGBA8 || picFormat == GL_SRGB8_ALPHA8_EXT;
+ bool rgba = rgba8 || picFormat == GL_RGBA16;
+ bool mipmap = !!(flags & IMGFLAG_MIPMAP);
+ int size, miplevel;
+ bool lastMip = false;
+
+ dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
+ dataType = picFormat == GL_RGBA16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
+
+ miplevel = 0;
+ do
+ {
+ lastMip = (width == 1 && height == 1) || !mipmap;
+ size = CalculateMipSize(width, height, picFormat);
+
+ if (!rgba)
+ {
+ qglCompressedTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, picFormat, size, data);
+ }
+ else
+ {
+ if (rgba8 && miplevel != 0 && r_colorMipLevels->integer)
+ R_BlendOverTexture((byte *)data, width * height, mipBlendColors[miplevel]);
+
+ if (rgba8 && rgtc)
+ RawImage_UploadToRgtc2Texture(texture, miplevel, x, y, width, height, data);
+ else
+ qglTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, dataFormat, dataType, data);
+ }
+
+ if (!lastMip && numMips < 2)
+ {
+ if (glRefConfig.framebufferObject)
+ {
+ qglGenerateTextureMipmapEXT(texture, target);
+ break;
+ }
+ else if (rgba8)
+ {
+ if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
+ R_MipMapNormalHeight(data, data, width, height, glRefConfig.swizzleNormalmap);
+ else
+ R_MipMapsRGB(data, width, height);
+ }
+ }
+
+ x >>= 1;
+ y >>= 1;
+ width = MAX(1, width >> 1);
+ height = MAX(1, height >> 1);
+ miplevel++;
+
+ if (numMips > 1)
+ {
+ data += size;
+ numMips--;
+ }
+ }
+ while (!lastMip);
+}
+
+
+/*
+===============
+Upload32
+
+===============
+*/
+static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, image_t *image, bool scaled)
+{
+ int i, c;
+ byte *scan;
+
+ imgType_t type = image->type;
+ int/*imgFlags_t*/ flags = image->flags;
+ GLenum internalFormat = image->internalFormat;
+ bool rgba8 = picFormat == GL_RGBA8 || picFormat == GL_SRGB8_ALPHA8_EXT;
+ bool mipmap = !!(flags & IMGFLAG_MIPMAP) && (rgba8 || numMips > 1);
+ bool cubemap = !!(flags & IMGFLAG_CUBEMAP);
+
+ // These operations cannot be performed on non-rgba8 images.
+ if (rgba8 && !cubemap)
+ {
+ c = width*height;
+ scan = data;
+
+ if (type == IMGTYPE_COLORALPHA)
+ {
+ if( r_greyscale->integer )
+ {
+ for ( i = 0; i < c; i++ )
+ {
+ byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
+ scan[i*4] = luma;
+ scan[i*4 + 1] = luma;
+ scan[i*4 + 2] = luma;
+ }
+ }
+ else if( r_greyscale->value )
+ {
+ for ( i = 0; i < c; i++ )
+ {
+ float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
+ scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value);
+ scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value);
+ scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value);
+ }
+ }
+
+ // This corresponds to what the OpenGL1 renderer does.
+ if (!(flags & IMGFLAG_NOLIGHTSCALE) && (scaled || mipmap))
+ R_LightScaleTexture(data, width, height, !mipmap);
+ }
+
+ if (glRefConfig.swizzleNormalmap && (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT))
+ RawImage_SwizzleRA(data, width, height);
+ }
+
+ if (cubemap)
+ {
+ for (i = 0; i < 6; i++)
+ {
+ int w2 = width, h2 = height;
+ RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, picFormat, numMips, internalFormat, type, flags, false);
+ for (c = numMips; c; c--)
+ {
+ data += CalculateMipSize(w2, h2, picFormat);
+ w2 = MAX(1, w2 >> 1);
+ h2 = MAX(1, h2 >> 1);
+ }
+ }
+ }
+ else
+ {
+ RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_2D, picFormat, numMips, internalFormat, type, flags, false);
+ }
+
+ GL_CheckErrors();
+}
+
+
+/*
+================
+R_CreateImage2
+
+This is the only way any image_t are created
+================
+*/
+image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLenum picFormat, int numMips, imgType_t type, int/*imgFlags_t*/ flags, int internalFormat ) {
+ byte *resampledBuffer = NULL;
+ image_t *image;
+ bool isLightmap = false, scaled = false;
+ long hash;
+ int glWrapClampMode, mipWidth, mipHeight, miplevel;
+ bool rgba8 = picFormat == GL_RGBA8 || picFormat == GL_SRGB8_ALPHA8_EXT;
+ bool mipmap = !!(flags & IMGFLAG_MIPMAP);
+ bool cubemap = !!(flags & IMGFLAG_CUBEMAP);
+ bool picmip = !!(flags & IMGFLAG_PICMIP);
+ bool lastMip;
+ GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
+ GLenum dataFormat;
+
+ if (strlen(name) >= MAX_QPATH ) {
+ ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name);
+ }
+ if ( !strncmp( name, "*lightmap", 9 ) ) {
+ isLightmap = true;
+ }
+
+ if ( tr.numImages == MAX_DRAWIMAGES ) {
+ ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit");
+ }
+
+ image = tr.images[tr.numImages] = (image_t*)ri.Hunk_Alloc( sizeof( image_t ), h_low );
+ qglGenTextures(1, &image->texnum);
+ tr.numImages++;
+
+ image->type = type;
+ image->flags = flags;
+
+ strcpy (image->imgName, name);
+
+ image->width = width;
+ image->height = height;
+ if (flags & IMGFLAG_CLAMPTOEDGE)
+ glWrapClampMode = GL_CLAMP_TO_EDGE;
+ else
+ glWrapClampMode = GL_REPEAT;
+
+ if (!internalFormat)
+ internalFormat = RawImage_GetFormat(pic, width * height, picFormat, isLightmap, image->type, image->flags);
+
+ image->internalFormat = internalFormat;
+
+ // Possibly scale image before uploading.
+ // if not rgba8 and uploading an image, skip picmips.
+ if (!cubemap)
+ {
+ if (rgba8)
+ scaled = RawImage_ScaleToPower2(&pic, &width, &height, type, flags, &resampledBuffer);
+ else if (pic && picmip)
+ {
+ for (miplevel = r_picmip->integer; miplevel > 0 && numMips > 1; miplevel--, numMips--)
+ {
+ int size = CalculateMipSize(width, height, picFormat);
+ width = MAX(1, width >> 1);
+ height = MAX(1, height >> 1);
+ pic += size;
+ }
+ }
+ }
+
+ image->uploadWidth = width;
+ image->uploadHeight = height;
+
+ // Allocate texture storage so we don't have to worry about it later.
+ dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
+ mipWidth = width;
+ mipHeight = height;
+ miplevel = 0;
+ do
+ {
+ lastMip = !mipmap || (mipWidth == 1 && mipHeight == 1);
+ if (cubemap)
+ {
+ int i;
+
+ for (i = 0; i < 6; i++)
+ qglTextureImage2DEXT(image->texnum, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, GL_UNSIGNED_BYTE, NULL);
+ }
+ else
+ {
+ qglTextureImage2DEXT(image->texnum, GL_TEXTURE_2D, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, GL_UNSIGNED_BYTE, NULL);
+ }
+
+ mipWidth = MAX(1, mipWidth >> 1);
+ mipHeight = MAX(1, mipHeight >> 1);
+ miplevel++;
+ }
+ while (!lastMip);
+
+ // Upload data.
+ if (pic)
+ Upload32(pic, 0, 0, width, height, picFormat, numMips, image, scaled);
+
+ if (resampledBuffer != NULL)
+ ri.Hunk_FreeTempMemory(resampledBuffer);
+
+ // Set all necessary texture parameters.
+ qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_S, glWrapClampMode);
+ qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_T, glWrapClampMode);
+
+ if (cubemap)
+ qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_R, glWrapClampMode);
+
+ if (glConfig.textureFilterAnisotropic && !cubemap)
+ qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT,
+ mipmap ? (GLint)Com_Clamp(1, glConfig.maxAnisotropy, r_ext_max_anisotropy->integer) : 1);
+
+ switch(internalFormat)
+ {
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_COMPONENT16_ARB:
+ case GL_DEPTH_COMPONENT24_ARB:
+ case GL_DEPTH_COMPONENT32_ARB:
+ // Fix for sampling depth buffer on old nVidia cards.
+ // from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844
+ qglTextureParameterfEXT(image->texnum, textureTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
+ qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ break;
+ default:
+ qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, mipmap ? gl_filter_min : GL_LINEAR);
+ qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, mipmap ? gl_filter_max : GL_LINEAR);
+ break;
+ }
+
+ GL_CheckErrors();
+
+ hash = generateHashValue(name);
+ image->next = hashTable[hash];
+ hashTable[hash] = image;
+
+ return image;
+}
+
+
+/*
+================
+R_CreateImage
+
+Wrapper for R_CreateImage2(), for the old parameters.
+================
+*/
+image_t *R_CreateImage(const char *name, byte *pic, int width, int height,
+ imgType_t type, int/*imgFlags_t*/ flags, int internalFormat)
+{
+ return R_CreateImage2(name, pic, width, height, GL_RGBA8, 0, type, flags, internalFormat);
+}
+
+
+void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height, GLenum picFormat )
+{
+ Upload32(pic, x, y, width, height, picFormat, 0, image, false);
+}
+
+//===================================================================
+
+// Prototype for dds loader function which isn't common to both renderers
+void R_LoadDDS(const char *filename, byte **pic, int *width, int *height, GLenum *picFormat, int *numMips);
+
+typedef struct
+{
+ const char *ext;
+ void (*ImageLoader)( const char *, unsigned char **, int *, int * );
+} imageExtToLoaderMap_t;
+
+// Note that the ordering indicates the order of preference used
+// when there are multiple images of different formats available
+static imageExtToLoaderMap_t imageLoaders[ ] =
+{
+ { "png", R_LoadPNG },
+ { "tga", R_LoadTGA },
+ { "jpg", R_LoadJPG },
+ { "jpeg", R_LoadJPG },
+ { "pcx", R_LoadPCX },
+ { "bmp", R_LoadBMP }
+};
+
+static int numImageLoaders = ARRAY_LEN( imageLoaders );
+
+/*
+=================
+R_LoadImage
+
+Loads any of the supported image types into a cannonical
+32 bit format.
+=================
+*/
+void R_LoadImage( const char *name, byte **pic, int *width, int *height, GLenum *picFormat, int *numMips )
+{
+ bool orgNameFailed = false;
+ int orgLoader = -1;
+ int i;
+ char localName[ MAX_QPATH ];
+ const char *ext;
+ const char *altName;
+
+ *pic = NULL;
+ *width = 0;
+ *height = 0;
+ *picFormat = GL_RGBA8;
+ *numMips = 0;
+
+ Q_strncpyz( localName, name, MAX_QPATH );
+
+ ext = COM_GetExtension( localName );
+
+ // If compressed textures are enabled, try loading a DDS first, it'll load fastest
+ if (r_ext_compressed_textures->integer)
+ {
+ char ddsName[MAX_QPATH];
+
+ COM_StripExtension(name, ddsName, MAX_QPATH);
+ Q_strcat(ddsName, MAX_QPATH, ".dds");
+
+ R_LoadDDS(ddsName, pic, width, height, picFormat, numMips);
+
+ // If loaded, we're done.
+ if (*pic)
+ return;
+ }
+
+ if( *ext )
+ {
+ // Look for the correct loader and use it
+ for( i = 0; i < numImageLoaders; i++ )
+ {
+ if( !Q_stricmp( ext, imageLoaders[ i ].ext ) )
+ {
+ // Load
+ imageLoaders[ i ].ImageLoader( localName, pic, width, height );
+ break;
+ }
+ }
+
+ // A loader was found
+ if( i < numImageLoaders )
+ {
+ if( *pic == NULL )
+ {
+ // Loader failed, most likely because the file isn't there;
+ // try again without the extension
+ orgNameFailed = true;
+ orgLoader = i;
+ COM_StripExtension( name, localName, MAX_QPATH );
+ }
+ else
+ {
+ // Something loaded
+ return;
+ }
+ }
+ }
+
+ // Try and find a suitable match using all
+ // the image formats supported
+ for( i = 0; i < numImageLoaders; i++ )
+ {
+ if (i == orgLoader)
+ continue;
+
+ altName = va( "%s.%s", localName, imageLoaders[ i ].ext );
+
+ // Load
+ imageLoaders[ i ].ImageLoader( altName, pic, width, height );
+
+ if( *pic )
+ {
+ if( orgNameFailed )
+ {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n",
+ name, altName );
+ }
+
+ break;
+ }
+ }
+}
+
+
+/*
+===============
+R_FindImageFile
+
+Finds or loads the given image.
+Returns NULL if it fails, not a default image.
+==============
+*/
+image_t *R_FindImageFile( const char *name, imgType_t type, int/*imgFlags_t*/ flags )
+{
+ image_t *image;
+ int width, height;
+ byte *pic;
+ GLenum picFormat;
+ int picNumMips;
+ long hash;
+ int/*imgFlags_t*/ checkFlagsTrue, checkFlagsFalse;
+
+ if (!name) {
+ return NULL;
+ }
+
+ hash = generateHashValue(name);
+
+ //
+ // see if the image is already loaded
+ //
+ for (image=hashTable[hash]; image; image=image->next) {
+ if ( !strcmp( name, image->imgName ) ) {
+ // the white image can be used with any set of parms, but other mismatches are errors
+ if ( strcmp( name, "*white" ) ) {
+ if ( image->flags != flags ) {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed flags (%i vs %i)\n", name, image->flags, flags );
+ }
+ }
+ return image;
+ }
+ }
+
+ //
+ // load the pic from disk
+ //
+ R_LoadImage( name, &pic, &width, &height, &picFormat, &picNumMips );
+ if ( pic == NULL ) {
+ return NULL;
+ }
+
+ checkFlagsTrue = IMGFLAG_PICMIP | IMGFLAG_MIPMAP | IMGFLAG_GENNORMALMAP;
+ checkFlagsFalse = IMGFLAG_CUBEMAP;
+ if (r_normalMapping->integer && (picFormat == GL_RGBA8) && (type == IMGTYPE_COLORALPHA) &&
+ ((flags & checkFlagsTrue) == checkFlagsTrue) && !(flags & checkFlagsFalse))
+ {
+ char normalName[MAX_QPATH];
+ image_t *normalImage;
+ int normalWidth, normalHeight;
+ int/*imgFlags_t*/ normalFlags;
+
+ normalFlags = (flags & ~IMGFLAG_GENNORMALMAP) | IMGFLAG_NOLIGHTSCALE;
+
+ COM_StripExtension(name, normalName, MAX_QPATH);
+ Q_strcat(normalName, MAX_QPATH, "_n");
+
+ // find normalmap in case it's there
+ normalImage = R_FindImageFile(normalName, IMGTYPE_NORMAL, normalFlags);
+
+ // if not, generate it
+ if (normalImage == NULL)
+ {
+ byte *normalPic;
+ int x, y;
+
+ normalWidth = width;
+ normalHeight = height;
+ normalPic = (byte*)ri.Malloc(width * height * 4);
+ RGBAtoNormal(pic, normalPic, width, height, flags & IMGFLAG_CLAMPTOEDGE);
+
+#if 1
+ // Brighten up the original image to work with the normal map
+ RGBAtoYCoCgA(pic, pic, width, height);
+ for (y = 0; y < height; y++)
+ {
+ byte *picbyte = pic + y * width * 4;
+ byte *normbyte = normalPic + y * width * 4;
+ for (x = 0; x < width; x++)
+ {
+ int div = MAX(normbyte[2] - 127, 16);
+ picbyte[0] = CLAMP(picbyte[0] * 128 / div, 0, 255);
+ picbyte += 4;
+ normbyte += 4;
+ }
+ }
+ YCoCgAtoRGBA(pic, pic, width, height);
+#else
+ // Blur original image's luma to work with the normal map
+ {
+ byte *blurPic;
+
+ RGBAtoYCoCgA(pic, pic, width, height);
+ blurPic = ri.Malloc(width * height);
+
+ for (y = 1; y < height - 1; y++)
+ {
+ byte *picbyte = pic + y * width * 4;
+ byte *blurbyte = blurPic + y * width;
+
+ picbyte += 4;
+ blurbyte += 1;
+
+ for (x = 1; x < width - 1; x++)
+ {
+ int result;
+
+ result = *(picbyte - (width + 1) * 4) + *(picbyte - width * 4) + *(picbyte - (width - 1) * 4) +
+ *(picbyte - 1 * 4) + *(picbyte ) + *(picbyte + 1 * 4) +
+ *(picbyte + (width - 1) * 4) + *(picbyte + width * 4) + *(picbyte + (width + 1) * 4);
+
+ result /= 9;
+
+ *blurbyte = result;
+ picbyte += 4;
+ blurbyte += 1;
+ }
+ }
+
+ // FIXME: do borders
+
+ for (y = 1; y < height - 1; y++)
+ {
+ byte *picbyte = pic + y * width * 4;
+ byte *blurbyte = blurPic + y * width;
+
+ picbyte += 4;
+ blurbyte += 1;
+
+ for (x = 1; x < width - 1; x++)
+ {
+ picbyte[0] = *blurbyte;
+ picbyte += 4;
+ blurbyte += 1;
+ }
+ }
+
+ ri.Free(blurPic);
+
+ YCoCgAtoRGBA(pic, pic, width, height);
+ }
+#endif
+
+ R_CreateImage( normalName, normalPic, normalWidth, normalHeight, IMGTYPE_NORMAL, normalFlags, 0 );
+ ri.Free( normalPic );
+ }
+ }
+
+ // force mipmaps off if image is compressed but doesn't have enough mips
+ if ((flags & IMGFLAG_MIPMAP) && picFormat != GL_RGBA8 && picFormat != GL_SRGB8_ALPHA8_EXT)
+ {
+ int wh = MAX(width, height);
+ int neededMips = 0;
+ while (wh)
+ {
+ neededMips++;
+ wh >>= 1;
+ }
+ if (neededMips > picNumMips)
+ flags &= ~IMGFLAG_MIPMAP;
+ }
+
+ image = R_CreateImage2( ( char * ) name, pic, width, height, picFormat, picNumMips, type, flags, 0 );
+ ri.Free( pic );
+ return image;
+}
+
+
+/*
+================
+R_CreateDlightImage
+================
+*/
+#define DLIGHT_SIZE 16
+static void R_CreateDlightImage( void ) {
+ int x,y;
+ byte data[DLIGHT_SIZE][DLIGHT_SIZE][4];
+ int b;
+
+ // make a centered inverse-square falloff blob for dynamic lighting
+ for (x=0 ; x<DLIGHT_SIZE ; x++) {
+ for (y=0 ; y<DLIGHT_SIZE ; y++) {
+ float d;
+
+ d = ( DLIGHT_SIZE/2 - 0.5f - x ) * ( DLIGHT_SIZE/2 - 0.5f - x ) +
+ ( DLIGHT_SIZE/2 - 0.5f - y ) * ( DLIGHT_SIZE/2 - 0.5f - y );
+ b = 4000 / d;
+ if (b > 255) {
+ b = 255;
+ } else if ( b < 75 ) {
+ b = 0;
+ }
+ data[y][x][0] =
+ data[y][x][1] =
+ data[y][x][2] = b;
+ data[y][x][3] = 255;
+ }
+ }
+ tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 );
+}
+
+
+/*
+=================
+R_InitFogTable
+=================
+*/
+void R_InitFogTable( void ) {
+ int i;
+ float d;
+ float exp;
+
+ exp = 0.5;
+
+ for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) {
+ d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp );
+
+ tr.fogTable[i] = d;
+ }
+}
+
+/*
+================
+R_FogFactor
+
+Returns a 0.0 to 1.0 fog density value
+This is called for each texel of the fog texture on startup
+and for each vertex of transparent shaders in fog dynamically
+================
+*/
+float R_FogFactor( float s, float t ) {
+ float d;
+
+ s -= 1.0/512;
+ if ( s < 0 ) {
+ return 0;
+ }
+ if ( t < 1.0/32 ) {
+ return 0;
+ }
+ if ( t < 31.0/32 ) {
+ s *= (t - 1.0f/32.0f) / (30.0f/32.0f);
+ }
+
+ // we need to leave a lot of clamp range
+ s *= 8;
+
+ if ( s > 1.0 ) {
+ s = 1.0;
+ }
+
+ d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ];
+
+ return d;
+}
+
+/*
+================
+R_CreateFogImage
+================
+*/
+#define FOG_S 256
+#define FOG_T 32
+static void R_CreateFogImage( void ) {
+ int x,y;
+ byte *data;
+ float d;
+
+ data = (byte*)ri.Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 );
+
+ // S is distance, T is depth
+ for (x=0 ; x<FOG_S ; x++) {
+ for (y=0 ; y<FOG_T ; y++) {
+ d = R_FogFactor( ( x + 0.5f ) / FOG_S, ( y + 0.5f ) / FOG_T );
+
+ data[(y*FOG_S+x)*4+0] =
+ data[(y*FOG_S+x)*4+1] =
+ data[(y*FOG_S+x)*4+2] = 255;
+ data[(y*FOG_S+x)*4+3] = 255*d;
+ }
+ }
+ tr.fogImage = R_CreateImage("*fog", (byte *)data, FOG_S, FOG_T, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 );
+ ri.Hunk_FreeTempMemory( data );
+}
+
+/*
+==================
+R_CreateDefaultImage
+==================
+*/
+#define DEFAULT_SIZE 16
+static void R_CreateDefaultImage( void ) {
+ int x;
+ byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
+
+ // the default image will be a box, to allow you to see the mapping coordinates
+ Com_Memset( data, 32, sizeof( data ) );
+ for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
+ data[0][x][0] =
+ data[0][x][1] =
+ data[0][x][2] =
+ data[0][x][3] = 255;
+
+ data[x][0][0] =
+ data[x][0][1] =
+ data[x][0][2] =
+ data[x][0][3] = 255;
+
+ data[DEFAULT_SIZE-1][x][0] =
+ data[DEFAULT_SIZE-1][x][1] =
+ data[DEFAULT_SIZE-1][x][2] =
+ data[DEFAULT_SIZE-1][x][3] = 255;
+
+ data[x][DEFAULT_SIZE-1][0] =
+ data[x][DEFAULT_SIZE-1][1] =
+ data[x][DEFAULT_SIZE-1][2] =
+ data[x][DEFAULT_SIZE-1][3] = 255;
+ }
+ tr.defaultImage = R_CreateImage("*default", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_MIPMAP, 0);
+}
+
+/*
+==================
+R_CreateBuiltinImages
+==================
+*/
+void R_CreateBuiltinImages( void ) {
+ int x,y;
+ byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
+
+ R_CreateDefaultImage();
+
+ // we use a solid white image instead of disabling texturing
+ Com_Memset( data, 255, sizeof( data ) );
+ tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, IMGTYPE_COLORALPHA, IMGFLAG_NONE, 0);
+
+ if (r_dlightMode->integer >= 2)
+ {
+ for( x = 0; x < MAX_DLIGHTS; x++)
+ {
+ tr.shadowCubemaps[x] = R_CreateImage(va("*shadowcubemap%i", x), NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE | IMGFLAG_CUBEMAP, 0);
+ }
+ }
+
+ // with overbright bits active, we need an image which is some fraction of full color,
+ // for default lightmaps, etc
+ for (x=0 ; x<DEFAULT_SIZE ; x++) {
+ for (y=0 ; y<DEFAULT_SIZE ; y++) {
+ data[y][x][0] =
+ data[y][x][1] =
+ data[y][x][2] = tr.identityLightByte;
+ data[y][x][3] = 255;
+ }
+ }
+
+ tr.identityLightImage = R_CreateImage("*identityLight", (byte *)data, 8, 8, IMGTYPE_COLORALPHA, IMGFLAG_NONE, 0);
+
+
+ for(x=0;x<32;x++) {
+ // scratchimage is usually used for cinematic drawing
+ tr.scratchImage[x] = R_CreateImage("*scratch", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_PICMIP | IMGFLAG_CLAMPTOEDGE, 0);
+ }
+
+ R_CreateDlightImage();
+ R_CreateFogImage();
+
+ if (glRefConfig.framebufferObject)
+ {
+ int width, height, hdrFormat, rgbFormat;
+
+ width = glConfig.vidWidth;
+ height = glConfig.vidHeight;
+
+ hdrFormat = GL_RGBA8;
+ if (r_hdr->integer && glRefConfig.textureFloat)
+ hdrFormat = GL_RGBA16F_ARB;
+
+ rgbFormat = GL_RGBA8;
+
+ tr.renderImage = R_CreateImage("_render", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat);
+
+ if (r_shadowBlur->integer)
+ tr.screenScratchImage = R_CreateImage("screenScratch", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat);
+
+ //if (r_shadowBlur->integer || r_ssao->integer)
+ // tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB);
+ if (r_shadowBlur->integer || r_ssao->integer)
+ tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_R32F);
+
+ if (r_drawSunRays->integer)
+ tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat);
+
+ tr.renderDepthImage = R_CreateImage("*renderdepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB);
+ tr.textureDepthImage = R_CreateImage("*texturedepth", NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB);
+
+ {
+ byte *p;
+
+ data[0][0][0] = 0;
+ data[0][0][1] = 0.45f * 255;
+ data[0][0][2] = 255;
+ data[0][0][3] = 255;
+ p = (byte*)data;
+
+ tr.calcLevelsImage = R_CreateImage("*calcLevels", p, 1, 1, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat);
+ tr.targetLevelsImage = R_CreateImage("*targetLevels", p, 1, 1, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat);
+ tr.fixedLevelsImage = R_CreateImage("*fixedLevels", p, 1, 1, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat);
+ }
+
+ for (x = 0; x < 2; x++)
+ {
+ tr.textureScratchImage[x] = R_CreateImage(va("*textureScratch%d", x), NULL, 256, 256, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8);
+ }
+ for (x = 0; x < 2; x++)
+ {
+ tr.quarterImage[x] = R_CreateImage(va("*quarter%d", x), NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8);
+ }
+
+ if (r_ssao->integer)
+ {
+ tr.screenSsaoImage = R_CreateImage("*screenSsao", NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8);
+ }
+
+ for( x = 0; x < MAX_DRAWN_PSHADOWS; x++)
+ {
+ tr.pshadowMaps[x] = R_CreateImage(va("*shadowmap%i", x), NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24);
+ //qglTextureParameterfEXT(tr.pshadowMaps[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
+ //qglTextureParameterfEXT(tr.pshadowMaps[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ }
+
+ if (r_sunlightMode->integer)
+ {
+ for ( x = 0; x < 4; x++)
+ {
+ tr.sunShadowDepthImage[x] = R_CreateImage(va("*sunshadowdepth%i", x), NULL, r_shadowMapSize->integer, r_shadowMapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB);
+ qglTextureParameterfEXT(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
+ qglTextureParameterfEXT(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ }
+
+ tr.screenShadowImage = R_CreateImage("*screenShadow", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8);
+ }
+
+ if (r_cubeMapping->integer)
+ {
+ tr.renderCubeImage = R_CreateImage("*renderCube", NULL, r_cubemapSize->integer, r_cubemapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, rgbFormat);
+ }
+ }
+}
+
+
+/*
+===============
+R_SetColorMappings
+===============
+*/
+void R_SetColorMappings( void ) {
+ int i, j;
+ float g;
+ int inf;
+
+ // setup the overbright lighting
+ tr.overbrightBits = r_overBrightBits->integer;
+
+ // allow 2 overbright bits
+ if ( tr.overbrightBits > 2 ) {
+ tr.overbrightBits = 2;
+ } else if ( tr.overbrightBits < 0 ) {
+ tr.overbrightBits = 0;
+ }
+
+ // don't allow more overbright bits than map overbright bits
+ if ( tr.overbrightBits > r_mapOverBrightBits->integer ) {
+ tr.overbrightBits = r_mapOverBrightBits->integer;
+ }
+
+ tr.identityLight = 1.0f / ( 1 << tr.overbrightBits );
+ tr.identityLightByte = 255 * tr.identityLight;
+
+
+ if ( r_intensity->value <= 1 ) {
+ ri.Cvar_Set( "r_intensity", "1" );
+ }
+
+ if ( r_gamma->value < 0.5f ) {
+ ri.Cvar_Set( "r_gamma", "0.5" );
+ } else if ( r_gamma->value > 3.0f ) {
+ ri.Cvar_Set( "r_gamma", "3.0" );
+ }
+
+ g = r_gamma->value;
+
+ for ( i = 0; i < 256; i++ ) {
+ if ( g == 1 ) {
+ inf = i;
+ } else {
+ inf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f;
+ }
+
+ if (inf < 0) {
+ inf = 0;
+ }
+ if (inf > 255) {
+ inf = 255;
+ }
+ s_gammatable[i] = inf;
+ }
+
+ for (i=0 ; i<256 ; i++) {
+ j = i * r_intensity->value;
+ if (j > 255) {
+ j = 255;
+ }
+ s_intensitytable[i] = j;
+ }
+
+ if ( glConfig.deviceSupportsGamma )
+ {
+ GLimp_SetGamma( s_gammatable, s_gammatable, s_gammatable );
+ }
+}
+
+/*
+===============
+R_InitImages
+===============
+*/
+void R_InitImages( void ) {
+ Com_Memset(hashTable, 0, sizeof(hashTable));
+ // build brightness translation tables
+ R_SetColorMappings();
+
+ // create default texture and white texture
+ R_CreateBuiltinImages();
+}
+
+/*
+===============
+R_DeleteTextures
+===============
+*/
+void R_DeleteTextures( void ) {
+ int i;
+
+ for ( i=0; i<tr.numImages ; i++ ) {
+ qglDeleteTextures( 1, &tr.images[i]->texnum );
+ }
+ Com_Memset( tr.images, 0, sizeof( tr.images ) );
+
+ tr.numImages = 0;
+
+ GL_BindNullTextures();
+}
+
+/*
+============================================================================
+
+SKINS
+
+============================================================================
+*/
+
+/*
+==================
+CommaParse
+
+This is unfortunate, but the skin files aren't
+compatable with our normal parsing rules.
+==================
+*/
+static const char *CommaParse( char **data_p ) {
+ int c = 0, len;
+ char *data;
+ static char com_token[MAX_TOKEN_CHARS];
+
+ data = *data_p;
+ len = 0;
+ com_token[0] = 0;
+
+ // make sure incoming data is valid
+ if ( !data ) {
+ *data_p = NULL;
+ return com_token;
+ }
+
+ while ( 1 ) {
+ // skip whitespace
+ while( (c = *data) <= ' ') {
+ if( !c ) {
+ break;
+ }
+ data++;
+ }
+
+
+ c = *data;
+
+ // skip double slash comments
+ if ( c == '/' && data[1] == '/' )
+ {
+ data += 2;
+ while (*data && *data != '\n') {
+ data++;
+ }
+ }
+ // skip /* */ comments
+ else if ( c=='/' && data[1] == '*' )
+ {
+ data += 2;
+ while ( *data && ( *data != '*' || data[1] != '/' ) )
+ {
+ data++;
+ }
+ if ( *data )
+ {
+ data += 2;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if ( c == 0 ) {
+ return "";
+ }
+
+ // handle quoted strings
+ if (c == '\"')
+ {
+ data++;
+ while (1)
+ {
+ c = *data++;
+ if (c=='\"' || !c)
+ {
+ com_token[len] = 0;
+ *data_p = ( char * ) data;
+ return com_token;
+ }
+ if (len < MAX_TOKEN_CHARS - 1)
+ {
+ com_token[len] = c;
+ len++;
+ }
+ }
+ }
+
+ // parse a regular word
+ do
+ {
+ if (len < MAX_TOKEN_CHARS - 1)
+ {
+ com_token[len] = c;
+ len++;
+ }
+ data++;
+ c = *data;
+ } while (c>32 && c != ',' );
+
+ com_token[len] = 0;
+
+ *data_p = ( char * ) data;
+ return com_token;
+}
+
+
+/*
+===============
+RE_RegisterSkin
+
+===============
+*/
+qhandle_t RE_RegisterSkin( const char *name ) {
+ skinSurface_t parseSurfaces[MAX_SKIN_SURFACES];
+ qhandle_t hSkin;
+ skin_t *skin;
+ skinSurface_t *surf;
+ union {
+ char *c;
+ void *v;
+ } text;
+ char *text_p;
+ const char *token;
+ char surfName[MAX_QPATH];
+
+ if ( !name || !name[0] ) {
+ ri.Printf( PRINT_DEVELOPER, "Empty name passed to RE_RegisterSkin\n" );
+ return 0;
+ }
+
+ if ( strlen( name ) >= MAX_QPATH ) {
+ ri.Printf( PRINT_DEVELOPER, "Skin name exceeds MAX_QPATH\n" );
+ return 0;
+ }
+
+
+ // see if the skin is already loaded
+ for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) {
+ skin = tr.skins[hSkin];
+ if ( !Q_stricmp( skin->name, name ) ) {
+ if( skin->numSurfaces == 0 ) {
+ return 0; // default skin
+ }
+ return hSkin;
+ }
+ }
+
+ // allocate a new skin
+ if ( tr.numSkins == MAX_SKINS ) {
+ ri.Printf( PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name );
+ return 0;
+ }
+ tr.numSkins++;
+ skin = (skin_t*)ri.Hunk_Alloc( sizeof( skin_t ), h_low );
+ tr.skins[hSkin] = skin;
+ Q_strncpyz( skin->name, name, sizeof( skin->name ) );
+ skin->numSurfaces = 0;
+
+ R_IssuePendingRenderCommands();
+
+ // If not a .skin file, load as a single shader
+ if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) {
+ skin->numSurfaces = 1;
+ skin->surfaces = (skinSurface_t*)ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+ skin->surfaces[0].shader = R_FindShader( name, LIGHTMAP_NONE, true );
+ return hSkin;
+ }
+
+ // load and parse the skin file
+ ri.FS_ReadFile( name, &text.v );
+ if ( !text.c ) {
+ return 0;
+ }
+
+ int totalSurfaces = 0;
+ text_p = text.c;
+ while ( text_p && *text_p ) {
+ // get surface name
+ token = CommaParse( &text_p );
+ Q_strncpyz( surfName, token, sizeof( surfName ) );
+
+ if ( !token[0] ) {
+ break;
+ }
+ // lowercase the surface name so skin compares are faster
+ Q_strlwr( surfName );
+
+ if ( *text_p == ',' ) {
+ text_p++;
+ }
+
+ if ( strstr( token, "tag_" ) ) {
+ continue;
+ }
+
+ // parse the shader name
+ token = CommaParse( &text_p );
+
+ if ( skin->numSurfaces < MAX_SKIN_SURFACES ) {
+ surf = &parseSurfaces[skin->numSurfaces];
+ Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );
+ surf->shader = R_FindShader( token, LIGHTMAP_NONE, true );
+ skin->numSurfaces++;
+ }
+
+ totalSurfaces++;
+ }
+
+ ri.FS_FreeFile( text.v );
+
+ if ( totalSurfaces > MAX_SKIN_SURFACES ) {
+ ri.Printf( PRINT_WARNING, "WARNING: Ignoring excess surfaces (found %d, max is %d) in skin '%s'!\n",
+ totalSurfaces, MAX_SKIN_SURFACES, name );
+ }
+
+ // never let a skin have 0 shaders
+ if ( skin->numSurfaces == 0 ) {
+ return 0; // use default skin
+ }
+
+ // copy surfaces to skin
+ skin->surfaces = (skinSurface_t*)ri.Hunk_Alloc( skin->numSurfaces * sizeof( skinSurface_t ), h_low );
+ memcpy( skin->surfaces, parseSurfaces, skin->numSurfaces * sizeof( skinSurface_t ) );
+
+ return hSkin;
+}
+
+
+/*
+===============
+R_InitSkins
+===============
+*/
+void R_InitSkins( void ) {
+ skin_t *skin;
+
+ tr.numSkins = 1;
+
+ // make the default skin have all default shaders
+ skin = tr.skins[0] = (skin_t*)ri.Hunk_Alloc( sizeof( skin_t ), h_low );
+ Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name ) );
+ skin->numSurfaces = 1;
+ skin->surfaces = (skinSurface_t*)ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
+ skin->surfaces[0].shader = tr.defaultShader;
+}
+
+/*
+===============
+R_GetSkinByHandle
+===============
+*/
+skin_t *R_GetSkinByHandle( qhandle_t hSkin ) {
+ if ( hSkin < 1 || hSkin >= tr.numSkins ) {
+ return tr.skins[0];
+ }
+ return tr.skins[ hSkin ];
+}
+
+/*
+===============
+R_SkinList_f
+===============
+*/
+void R_SkinList_f( void ) {
+ int i, j;
+ skin_t *skin;
+
+ ri.Printf (PRINT_ALL, "------------------\n");
+
+ for ( i = 0 ; i < tr.numSkins ; i++ ) {
+ skin = tr.skins[i];
+
+ ri.Printf( PRINT_ALL, "%3i:%s (%d surfaces)\n", i, skin->name, skin->numSurfaces );
+ for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
+ ri.Printf( PRINT_ALL, " %s = %s\n",
+ skin->surfaces[j].name, skin->surfaces[j].shader->name );
+ }
+ }
+ ri.Printf (PRINT_ALL, "------------------\n");
+}
diff --git a/src/renderergl2/tr_image_dds.cpp b/src/renderergl2/tr_image_dds.cpp
new file mode 100644
index 0000000..7c52ffb
--- /dev/null
+++ b/src/renderergl2/tr_image_dds.cpp
@@ -0,0 +1,499 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+ 2015 James Canete
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "renderercommon/tr_common.h"
+
+typedef unsigned int ui32_t;
+
+typedef struct ddsHeader_s
+{
+ ui32_t headerSize;
+ ui32_t flags;
+ ui32_t height;
+ ui32_t width;
+ ui32_t pitchOrFirstMipSize;
+ ui32_t volumeDepth;
+ ui32_t numMips;
+ ui32_t reserved1[11];
+ ui32_t always_0x00000020;
+ ui32_t pixelFormatFlags;
+ ui32_t fourCC;
+ ui32_t rgbBitCount;
+ ui32_t rBitMask;
+ ui32_t gBitMask;
+ ui32_t bBitMask;
+ ui32_t aBitMask;
+ ui32_t caps;
+ ui32_t caps2;
+ ui32_t caps3;
+ ui32_t caps4;
+ ui32_t reserved2;
+}
+ddsHeader_t;
+
+// flags:
+#define _DDSFLAGS_REQUIRED 0x001007
+#define _DDSFLAGS_PITCH 0x8
+#define _DDSFLAGS_MIPMAPCOUNT 0x20000
+#define _DDSFLAGS_FIRSTMIPSIZE 0x80000
+#define _DDSFLAGS_VOLUMEDEPTH 0x800000
+
+// pixelFormatFlags:
+#define DDSPF_ALPHAPIXELS 0x1
+#define DDSPF_ALPHA 0x2
+#define DDSPF_FOURCC 0x4
+#define DDSPF_RGB 0x40
+#define DDSPF_YUV 0x200
+#define DDSPF_LUMINANCE 0x20000
+
+// caps:
+#define DDSCAPS_COMPLEX 0x8
+#define DDSCAPS_MIPMAP 0x400000
+#define DDSCAPS_REQUIRED 0x1000
+
+// caps2:
+#define DDSCAPS2_CUBEMAP 0xFE00
+#define DDSCAPS2_VOLUME 0x200000
+
+typedef struct ddsHeaderDxt10_s
+{
+ ui32_t dxgiFormat;
+ ui32_t dimensions;
+ ui32_t miscFlags;
+ ui32_t arraySize;
+ ui32_t miscFlags2;
+}
+ddsHeaderDxt10_t;
+
+// dxgiFormat
+// from http://msdn.microsoft.com/en-us/library/windows/desktop/bb173059%28v=vs.85%29.aspx
+typedef enum DXGI_FORMAT {
+ DXGI_FORMAT_UNKNOWN = 0,
+ DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,
+ DXGI_FORMAT_R32G32B32A32_FLOAT = 2,
+ DXGI_FORMAT_R32G32B32A32_UINT = 3,
+ DXGI_FORMAT_R32G32B32A32_SINT = 4,
+ DXGI_FORMAT_R32G32B32_TYPELESS = 5,
+ DXGI_FORMAT_R32G32B32_FLOAT = 6,
+ DXGI_FORMAT_R32G32B32_UINT = 7,
+ DXGI_FORMAT_R32G32B32_SINT = 8,
+ DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,
+ DXGI_FORMAT_R16G16B16A16_FLOAT = 10,
+ DXGI_FORMAT_R16G16B16A16_UNORM = 11,
+ DXGI_FORMAT_R16G16B16A16_UINT = 12,
+ DXGI_FORMAT_R16G16B16A16_SNORM = 13,
+ DXGI_FORMAT_R16G16B16A16_SINT = 14,
+ DXGI_FORMAT_R32G32_TYPELESS = 15,
+ DXGI_FORMAT_R32G32_FLOAT = 16,
+ DXGI_FORMAT_R32G32_UINT = 17,
+ DXGI_FORMAT_R32G32_SINT = 18,
+ DXGI_FORMAT_R32G8X24_TYPELESS = 19,
+ DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,
+ DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,
+ DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,
+ DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,
+ DXGI_FORMAT_R10G10B10A2_UNORM = 24,
+ DXGI_FORMAT_R10G10B10A2_UINT = 25,
+ DXGI_FORMAT_R11G11B10_FLOAT = 26,
+ DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,
+ DXGI_FORMAT_R8G8B8A8_UNORM = 28,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,
+ DXGI_FORMAT_R8G8B8A8_UINT = 30,
+ DXGI_FORMAT_R8G8B8A8_SNORM = 31,
+ DXGI_FORMAT_R8G8B8A8_SINT = 32,
+ DXGI_FORMAT_R16G16_TYPELESS = 33,
+ DXGI_FORMAT_R16G16_FLOAT = 34,
+ DXGI_FORMAT_R16G16_UNORM = 35,
+ DXGI_FORMAT_R16G16_UINT = 36,
+ DXGI_FORMAT_R16G16_SNORM = 37,
+ DXGI_FORMAT_R16G16_SINT = 38,
+ DXGI_FORMAT_R32_TYPELESS = 39,
+ DXGI_FORMAT_D32_FLOAT = 40,
+ DXGI_FORMAT_R32_FLOAT = 41,
+ DXGI_FORMAT_R32_UINT = 42,
+ DXGI_FORMAT_R32_SINT = 43,
+ DXGI_FORMAT_R24G8_TYPELESS = 44,
+ DXGI_FORMAT_D24_UNORM_S8_UINT = 45,
+ DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,
+ DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,
+ DXGI_FORMAT_R8G8_TYPELESS = 48,
+ DXGI_FORMAT_R8G8_UNORM = 49,
+ DXGI_FORMAT_R8G8_UINT = 50,
+ DXGI_FORMAT_R8G8_SNORM = 51,
+ DXGI_FORMAT_R8G8_SINT = 52,
+ DXGI_FORMAT_R16_TYPELESS = 53,
+ DXGI_FORMAT_R16_FLOAT = 54,
+ DXGI_FORMAT_D16_UNORM = 55,
+ DXGI_FORMAT_R16_UNORM = 56,
+ DXGI_FORMAT_R16_UINT = 57,
+ DXGI_FORMAT_R16_SNORM = 58,
+ DXGI_FORMAT_R16_SINT = 59,
+ DXGI_FORMAT_R8_TYPELESS = 60,
+ DXGI_FORMAT_R8_UNORM = 61,
+ DXGI_FORMAT_R8_UINT = 62,
+ DXGI_FORMAT_R8_SNORM = 63,
+ DXGI_FORMAT_R8_SINT = 64,
+ DXGI_FORMAT_A8_UNORM = 65,
+ DXGI_FORMAT_R1_UNORM = 66,
+ DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,
+ DXGI_FORMAT_R8G8_B8G8_UNORM = 68,
+ DXGI_FORMAT_G8R8_G8B8_UNORM = 69,
+ DXGI_FORMAT_BC1_TYPELESS = 70,
+ DXGI_FORMAT_BC1_UNORM = 71,
+ DXGI_FORMAT_BC1_UNORM_SRGB = 72,
+ DXGI_FORMAT_BC2_TYPELESS = 73,
+ DXGI_FORMAT_BC2_UNORM = 74,
+ DXGI_FORMAT_BC2_UNORM_SRGB = 75,
+ DXGI_FORMAT_BC3_TYPELESS = 76,
+ DXGI_FORMAT_BC3_UNORM = 77,
+ DXGI_FORMAT_BC3_UNORM_SRGB = 78,
+ DXGI_FORMAT_BC4_TYPELESS = 79,
+ DXGI_FORMAT_BC4_UNORM = 80,
+ DXGI_FORMAT_BC4_SNORM = 81,
+ DXGI_FORMAT_BC5_TYPELESS = 82,
+ DXGI_FORMAT_BC5_UNORM = 83,
+ DXGI_FORMAT_BC5_SNORM = 84,
+ DXGI_FORMAT_B5G6R5_UNORM = 85,
+ DXGI_FORMAT_B5G5R5A1_UNORM = 86,
+ DXGI_FORMAT_B8G8R8A8_UNORM = 87,
+ DXGI_FORMAT_B8G8R8X8_UNORM = 88,
+ DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89,
+ DXGI_FORMAT_B8G8R8A8_TYPELESS = 90,
+ DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91,
+ DXGI_FORMAT_B8G8R8X8_TYPELESS = 92,
+ DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93,
+ DXGI_FORMAT_BC6H_TYPELESS = 94,
+ DXGI_FORMAT_BC6H_UF16 = 95,
+ DXGI_FORMAT_BC6H_SF16 = 96,
+ DXGI_FORMAT_BC7_TYPELESS = 97,
+ DXGI_FORMAT_BC7_UNORM = 98,
+ DXGI_FORMAT_BC7_UNORM_SRGB = 99,
+ DXGI_FORMAT_AYUV = 100,
+ DXGI_FORMAT_Y410 = 101,
+ DXGI_FORMAT_Y416 = 102,
+ DXGI_FORMAT_NV12 = 103,
+ DXGI_FORMAT_P010 = 104,
+ DXGI_FORMAT_P016 = 105,
+ DXGI_FORMAT_420_OPAQUE = 106,
+ DXGI_FORMAT_YUY2 = 107,
+ DXGI_FORMAT_Y210 = 108,
+ DXGI_FORMAT_Y216 = 109,
+ DXGI_FORMAT_NV11 = 110,
+ DXGI_FORMAT_AI44 = 111,
+ DXGI_FORMAT_IA44 = 112,
+ DXGI_FORMAT_P8 = 113,
+ DXGI_FORMAT_A8P8 = 114,
+ DXGI_FORMAT_B4G4R4A4_UNORM = 115,
+ DXGI_FORMAT_FORCE_UINT = 0xffffffffUL
+} DXGI_FORMAT;
+
+#define EncodeFourCC(x) ((((ui32_t)((x)[0])) ) | \
+ (((ui32_t)((x)[1])) << 8 ) | \
+ (((ui32_t)((x)[2])) << 16) | \
+ (((ui32_t)((x)[3])) << 24) )
+
+
+void R_LoadDDS ( const char *filename, byte **pic, int *width, int *height, GLenum *picFormat, int *numMips )
+{
+ union {
+ byte *b;
+ void *v;
+ } buffer;
+ int len;
+ ddsHeader_t *ddsHeader = NULL;
+ ddsHeaderDxt10_t *ddsHeaderDxt10 = NULL;
+ byte *data;
+
+ if (!picFormat)
+ {
+ ri.Printf(PRINT_ERROR, "R_LoadDDS() called without picFormat parameter!");
+ return;
+ }
+
+ if (width)
+ *width = 0;
+ if (height)
+ *height = 0;
+ if (picFormat)
+ *picFormat = GL_RGBA8;
+ if (numMips)
+ *numMips = 1;
+
+ *pic = NULL;
+
+ //
+ // load the file
+ //
+ len = ri.FS_ReadFile( ( char * ) filename, &buffer.v);
+ if (!buffer.b || len < 0) {
+ return;
+ }
+
+ //
+ // reject files that are too small to hold even a header
+ //
+ if (len < 4 + sizeof(*ddsHeader))
+ {
+ ri.Printf(PRINT_ALL, "File %s is too small to be a DDS file.\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ //
+ // reject files that don't start with "DDS "
+ //
+ if (*((ui32_t *)(buffer.b)) != EncodeFourCC("DDS "))
+ {
+ ri.Printf(PRINT_ALL, "File %s is not a DDS file.\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ //
+ // parse header and dx10 header if available
+ //
+ ddsHeader = (ddsHeader_t *)(buffer.b + 4);
+ if ((ddsHeader->pixelFormatFlags & DDSPF_FOURCC) && ddsHeader->fourCC == EncodeFourCC("DX10"))
+ {
+ if (len < 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10))
+ {
+ ri.Printf(PRINT_ALL, "File %s indicates a DX10 header it is too small to contain.\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ ddsHeaderDxt10 = (ddsHeaderDxt10_t *)(buffer.b + 4 + sizeof(ddsHeader_t));
+ data = buffer.b + 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10);
+ len -= 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10);
+ }
+ else
+ {
+ data = buffer.b + 4 + sizeof(*ddsHeader);
+ len -= 4 + sizeof(*ddsHeader);
+ }
+
+ if (width)
+ *width = ddsHeader->width;
+ if (height)
+ *height = ddsHeader->height;
+
+ if (numMips)
+ {
+ if (ddsHeader->flags & _DDSFLAGS_MIPMAPCOUNT)
+ *numMips = ddsHeader->numMips;
+ else
+ *numMips = 1;
+ }
+
+ // FIXME: handle cube map
+ //if ((ddsHeader->caps2 & DDSCAPS2_CUBEMAP) == DDSCAPS2_CUBEMAP)
+
+ //
+ // Convert DXGI format/FourCC into OpenGL format
+ //
+ if (ddsHeaderDxt10)
+ {
+ switch (ddsHeaderDxt10->dxgiFormat)
+ {
+ case DXGI_FORMAT_BC1_TYPELESS:
+ case DXGI_FORMAT_BC1_UNORM:
+ // FIXME: check for GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
+ *picFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ break;
+
+ case DXGI_FORMAT_BC1_UNORM_SRGB:
+ // FIXME: check for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
+ *picFormat = GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
+ break;
+
+ case DXGI_FORMAT_BC2_TYPELESS:
+ case DXGI_FORMAT_BC2_UNORM:
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ break;
+
+ case DXGI_FORMAT_BC2_UNORM_SRGB:
+ *picFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
+ break;
+
+ case DXGI_FORMAT_BC3_TYPELESS:
+ case DXGI_FORMAT_BC3_UNORM:
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ break;
+
+ case DXGI_FORMAT_BC3_UNORM_SRGB:
+ *picFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
+ break;
+
+ case DXGI_FORMAT_BC4_TYPELESS:
+ case DXGI_FORMAT_BC4_UNORM:
+ *picFormat = GL_COMPRESSED_RED_RGTC1;
+ break;
+
+ case DXGI_FORMAT_BC4_SNORM:
+ *picFormat = GL_COMPRESSED_SIGNED_RED_RGTC1;
+ break;
+
+ case DXGI_FORMAT_BC5_TYPELESS:
+ case DXGI_FORMAT_BC5_UNORM:
+ *picFormat = GL_COMPRESSED_RG_RGTC2;
+ break;
+
+ case DXGI_FORMAT_BC5_SNORM:
+ *picFormat = GL_COMPRESSED_SIGNED_RG_RGTC2;
+ break;
+
+ case DXGI_FORMAT_BC6H_TYPELESS:
+ case DXGI_FORMAT_BC6H_UF16:
+ *picFormat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB;
+ break;
+
+ case DXGI_FORMAT_BC6H_SF16:
+ *picFormat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB;
+ break;
+
+ case DXGI_FORMAT_BC7_TYPELESS:
+ case DXGI_FORMAT_BC7_UNORM:
+ *picFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
+ break;
+
+ case DXGI_FORMAT_BC7_UNORM_SRGB:
+ *picFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB;
+ break;
+
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ *picFormat = GL_SRGB8_ALPHA8_EXT;
+ break;
+
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ case DXGI_FORMAT_R8G8B8A8_SNORM:
+ *picFormat = GL_RGBA8;
+ break;
+
+ default:
+ ri.Printf(PRINT_ALL, "DDS File %s has unsupported DXGI format %d.", filename, ddsHeaderDxt10->dxgiFormat);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ break;
+ }
+ }
+ else
+ {
+ if (ddsHeader->pixelFormatFlags & DDSPF_FOURCC)
+ {
+ if (ddsHeader->fourCC == EncodeFourCC("DXT1"))
+ *picFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ else if (ddsHeader->fourCC == EncodeFourCC("DXT2"))
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ else if (ddsHeader->fourCC == EncodeFourCC("DXT3"))
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ else if (ddsHeader->fourCC == EncodeFourCC("DXT4"))
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ else if (ddsHeader->fourCC == EncodeFourCC("DXT5"))
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ else if (ddsHeader->fourCC == EncodeFourCC("ATI1"))
+ *picFormat = GL_COMPRESSED_RED_RGTC1;
+ else if (ddsHeader->fourCC == EncodeFourCC("BC4U"))
+ *picFormat = GL_COMPRESSED_RED_RGTC1;
+ else if (ddsHeader->fourCC == EncodeFourCC("BC4S"))
+ *picFormat = GL_COMPRESSED_SIGNED_RED_RGTC1;
+ else if (ddsHeader->fourCC == EncodeFourCC("ATI2"))
+ *picFormat = GL_COMPRESSED_RG_RGTC2;
+ else if (ddsHeader->fourCC == EncodeFourCC("BC5U"))
+ *picFormat = GL_COMPRESSED_RG_RGTC2;
+ else if (ddsHeader->fourCC == EncodeFourCC("BC5S"))
+ *picFormat = GL_COMPRESSED_SIGNED_RG_RGTC2;
+ else
+ {
+ ri.Printf(PRINT_ALL, "DDS File %s has unsupported FourCC.", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+ }
+ else if (ddsHeader->pixelFormatFlags == (DDSPF_RGB | DDSPF_ALPHAPIXELS)
+ && ddsHeader->rgbBitCount == 32
+ && ddsHeader->rBitMask == 0x000000ff
+ && ddsHeader->gBitMask == 0x0000ff00
+ && ddsHeader->bBitMask == 0x00ff0000
+ && ddsHeader->aBitMask == 0xff000000)
+ {
+ *picFormat = GL_RGBA8;
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, "DDS File %s has unsupported RGBA format.", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+ }
+
+ *pic = (byte*)ri.Malloc(len);
+ Com_Memcpy(*pic, data, len);
+
+ ri.FS_FreeFile(buffer.v);
+}
+
+void R_SaveDDS(const char *filename, byte *pic, int width, int height, int depth)
+{
+ byte *data;
+ ddsHeader_t *ddsHeader;
+ int picSize, size;
+
+ if (!depth)
+ depth = 1;
+
+ picSize = width * height * depth * 4;
+ size = 4 + sizeof(*ddsHeader) + picSize;
+ data = (byte*)ri.Malloc(size);
+
+ data[0] = 'D';
+ data[1] = 'D';
+ data[2] = 'S';
+ data[3] = ' ';
+
+ ddsHeader = (ddsHeader_t *)(data + 4);
+ memset(ddsHeader, 0, sizeof(ddsHeader_t));
+
+ ddsHeader->headerSize = 0x7c;
+ ddsHeader->flags = _DDSFLAGS_REQUIRED;
+ ddsHeader->height = height;
+ ddsHeader->width = width;
+ ddsHeader->always_0x00000020 = 0x00000020;
+ ddsHeader->caps = DDSCAPS_COMPLEX | DDSCAPS_REQUIRED;
+
+ if (depth == 6)
+ ddsHeader->caps2 = DDSCAPS2_CUBEMAP;
+
+ ddsHeader->pixelFormatFlags = DDSPF_RGB | DDSPF_ALPHAPIXELS;
+ ddsHeader->rgbBitCount = 32;
+ ddsHeader->rBitMask = 0x000000ff;
+ ddsHeader->gBitMask = 0x0000ff00;
+ ddsHeader->bBitMask = 0x00ff0000;
+ ddsHeader->aBitMask = 0xff000000;
+
+ Com_Memcpy(data + 4 + sizeof(*ddsHeader), pic, picSize);
+
+ ri.FS_WriteFile(filename, data, size);
+
+ ri.Free(data);
+}
diff --git a/src/renderergl2/tr_init.cpp b/src/renderergl2/tr_init.cpp
new file mode 100644
index 0000000..12e46a2
--- /dev/null
+++ b/src/renderergl2/tr_init.cpp
@@ -0,0 +1,1534 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_init.c -- functions that are not called every frame
+
+#include "tr_local.h"
+
+#include "tr_dsa.h"
+
+glconfig_t glConfig;
+glRefConfig_t glRefConfig;
+bool textureFilterAnisotropic = false;
+int maxAnisotropy = 0;
+float displayAspect = 0.0f;
+
+glstate_t glState;
+
+static void GfxInfo_f( void );
+static void GfxMemInfo_f( void );
+
+#ifdef USE_RENDERER_DLOPEN
+cvar_t *com_altivec;
+#endif
+
+cvar_t *r_flareSize;
+cvar_t *r_flareFade;
+cvar_t *r_flareCoeff;
+
+cvar_t *r_railWidth;
+cvar_t *r_railCoreWidth;
+cvar_t *r_railSegmentLength;
+
+cvar_t *r_verbose;
+cvar_t *r_ignore;
+
+cvar_t *r_detailTextures;
+
+cvar_t *r_znear;
+cvar_t *r_zproj;
+cvar_t *r_stereoSeparation;
+
+cvar_t *r_skipBackEnd;
+
+cvar_t *r_stereoEnabled;
+cvar_t *r_anaglyphMode;
+
+cvar_t *r_greyscale;
+
+cvar_t *r_ignorehwgamma;
+cvar_t *r_measureOverdraw;
+
+cvar_t *r_inGameVideo;
+cvar_t *r_fastsky;
+cvar_t *r_drawSun;
+cvar_t *r_dynamiclight;
+cvar_t *r_dlightBacks;
+
+cvar_t *r_lodbias;
+cvar_t *r_lodscale;
+
+cvar_t *r_norefresh;
+cvar_t *r_drawentities;
+cvar_t *r_drawworld;
+cvar_t *r_speeds;
+cvar_t *r_fullbright;
+cvar_t *r_novis;
+cvar_t *r_nocull;
+cvar_t *r_facePlaneCull;
+cvar_t *r_showcluster;
+cvar_t *r_nocurves;
+
+cvar_t *r_allowExtensions;
+
+cvar_t *r_ext_compressed_textures;
+cvar_t *r_ext_multitexture;
+cvar_t *r_ext_compiled_vertex_array;
+cvar_t *r_ext_texture_env_add;
+cvar_t *r_ext_texture_filter_anisotropic;
+cvar_t *r_ext_max_anisotropy;
+
+cvar_t *r_ext_framebuffer_object;
+cvar_t *r_ext_texture_float;
+cvar_t *r_ext_framebuffer_multisample;
+cvar_t *r_arb_seamless_cube_map;
+cvar_t *r_arb_vertex_array_object;
+cvar_t *r_ext_direct_state_access;
+
+cvar_t *r_cameraExposure;
+
+cvar_t *r_externalGLSL;
+
+cvar_t *r_hdr;
+cvar_t *r_floatLightmap;
+cvar_t *r_postProcess;
+
+cvar_t *r_toneMap;
+cvar_t *r_forceToneMap;
+cvar_t *r_forceToneMapMin;
+cvar_t *r_forceToneMapAvg;
+cvar_t *r_forceToneMapMax;
+
+cvar_t *r_autoExposure;
+cvar_t *r_forceAutoExposure;
+cvar_t *r_forceAutoExposureMin;
+cvar_t *r_forceAutoExposureMax;
+
+cvar_t *r_depthPrepass;
+cvar_t *r_ssao;
+
+cvar_t *r_normalMapping;
+cvar_t *r_specularMapping;
+cvar_t *r_deluxeMapping;
+cvar_t *r_parallaxMapping;
+cvar_t *r_cubeMapping;
+cvar_t *r_cubemapSize;
+cvar_t *r_pbr;
+cvar_t *r_baseNormalX;
+cvar_t *r_baseNormalY;
+cvar_t *r_baseParallax;
+cvar_t *r_baseSpecular;
+cvar_t *r_baseGloss;
+cvar_t *r_glossType;
+cvar_t *r_mergeLightmaps;
+cvar_t *r_dlightMode;
+cvar_t *r_pshadowDist;
+cvar_t *r_imageUpsample;
+cvar_t *r_imageUpsampleMaxSize;
+cvar_t *r_imageUpsampleType;
+cvar_t *r_genNormalMaps;
+cvar_t *r_forceSun;
+cvar_t *r_forceSunLightScale;
+cvar_t *r_forceSunAmbientScale;
+cvar_t *r_sunlightMode;
+cvar_t *r_drawSunRays;
+cvar_t *r_sunShadows;
+cvar_t *r_shadowFilter;
+cvar_t *r_shadowBlur;
+cvar_t *r_shadowMapSize;
+cvar_t *r_shadowCascadeZNear;
+cvar_t *r_shadowCascadeZFar;
+cvar_t *r_shadowCascadeZBias;
+cvar_t *r_ignoreDstAlpha;
+
+cvar_t *r_ignoreGLErrors;
+cvar_t *r_logFile;
+
+cvar_t *r_stencilbits;
+cvar_t *r_depthbits;
+cvar_t *r_colorbits;
+cvar_t *r_alphabits;
+cvar_t *r_texturebits;
+cvar_t *r_ext_multisample;
+
+cvar_t *r_drawBuffer;
+cvar_t *r_lightmap;
+cvar_t *r_vertexLight;
+cvar_t *r_uiFullScreen;
+cvar_t *r_shadows;
+cvar_t *r_flares;
+cvar_t *r_mode;
+cvar_t *r_nobind;
+cvar_t *r_singleShader;
+cvar_t *r_roundImagesDown;
+cvar_t *r_colorMipLevels;
+cvar_t *r_picmip;
+cvar_t *r_showtris;
+cvar_t *r_showsky;
+cvar_t *r_shownormals;
+cvar_t *r_finish;
+cvar_t *r_clear;
+cvar_t *r_swapInterval;
+cvar_t *r_textureMode;
+cvar_t *r_offsetFactor;
+cvar_t *r_offsetUnits;
+cvar_t *r_gamma;
+cvar_t *r_intensity;
+cvar_t *r_lockpvs;
+cvar_t *r_noportals;
+cvar_t *r_portalOnly;
+
+cvar_t *r_subdivisions;
+cvar_t *r_lodCurveError;
+
+cvar_t *r_fullscreen;
+cvar_t *r_noborder;
+
+cvar_t *r_width;
+cvar_t *r_height;
+cvar_t *r_pixelAspect;
+
+cvar_t *r_overBrightBits;
+cvar_t *r_mapOverBrightBits;
+
+cvar_t *r_mapLightmapMin;
+
+cvar_t *r_debugSurface;
+cvar_t *r_simpleMipMaps;
+
+cvar_t *r_showImages;
+
+cvar_t *r_ambientScale;
+cvar_t *r_directedScale;
+cvar_t *r_debugLight;
+cvar_t *r_debugSort;
+cvar_t *r_printShaders;
+cvar_t *r_saveFontData;
+
+cvar_t *r_marksOnTriangleMeshes;
+
+cvar_t *r_aviMotionJpegQuality;
+cvar_t *r_screenshotJpegQuality;
+
+cvar_t *r_maxpolys;
+int max_polys;
+cvar_t *r_maxpolyverts;
+int max_polyverts;
+
+/*
+** InitOpenGL
+**
+** This function is responsible for initializing a valid OpenGL subsystem. This
+** is done by calling GLimp_Init (which gives us a working OGL subsystem) then
+** setting variables, checking GL constants, and reporting the gfx system config
+** to the user.
+*/
+static void InitOpenGL( void )
+{
+ char renderer_buffer[1024];
+
+ //
+ // initialize OS specific portions of the renderer
+ //
+ // GLimp_Init directly or indirectly references the following cvars:
+ // - r_fullscreen
+ // - r_mode
+ // - r_(color|depth|stencil)bits
+ // - r_ignorehwgamma
+ // - r_gamma
+ //
+
+ if ( glConfig.vidWidth == 0 )
+ {
+ GLint temp;
+
+ GLimp_Init( qtrue );
+ GLimp_InitExtraExtensions();
+
+ strcpy( renderer_buffer, glConfig.renderer_string );
+ Q_strlwr( renderer_buffer );
+
+ // OpenGL driver constants
+ qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp );
+ glConfig.maxTextureSize = temp;
+
+ // stubbed or broken drivers may have reported 0...
+ if ( glConfig.maxTextureSize <= 0 )
+ {
+ glConfig.maxTextureSize = 0;
+ }
+ }
+
+ // set default state
+ GL_SetDefaultState();
+}
+
+/*
+==================
+GL_CheckErrors
+==================
+*/
+void GL_CheckErrs( const char *file, int line ) {
+ int err;
+ char s[64];
+
+ err = qglGetError();
+ if ( err == GL_NO_ERROR ) {
+ return;
+ }
+ if ( r_ignoreGLErrors->integer ) {
+ return;
+ }
+ switch( err ) {
+ case GL_INVALID_ENUM:
+ strcpy( s, "GL_INVALID_ENUM" );
+ break;
+ case GL_INVALID_VALUE:
+ strcpy( s, "GL_INVALID_VALUE" );
+ break;
+ case GL_INVALID_OPERATION:
+ strcpy( s, "GL_INVALID_OPERATION" );
+ break;
+ case GL_STACK_OVERFLOW:
+ strcpy( s, "GL_STACK_OVERFLOW" );
+ break;
+ case GL_STACK_UNDERFLOW:
+ strcpy( s, "GL_STACK_UNDERFLOW" );
+ break;
+ case GL_OUT_OF_MEMORY:
+ strcpy( s, "GL_OUT_OF_MEMORY" );
+ break;
+ default:
+ Com_sprintf( s, sizeof(s), "%i", err);
+ break;
+ }
+
+ ri.Error( ERR_FATAL, "GL_CheckErrors: %s in %s at line %d", s , file, line);
+}
+
+
+/*
+==============================================================================
+
+ SCREEN SHOTS
+
+NOTE TTimo
+some thoughts about the screenshots system:
+screenshots get written in fs_homepath + fs_gamedir
+vanilla q3 .. baseq3/screenshots/ *.tga
+team arena .. missionpack/screenshots/ *.tga
+
+two commands: "screenshot" and "screenshotJPEG"
+we use statics to store a count and start writing the first screenshot/screenshot????.tga (.jpg) available
+(with FS_FileExists / FS_FOpenFileWrite calls)
+FIXME: the statics don't get a reinit between fs_game changes
+
+==============================================================================
+*/
+
+/*
+==================
+RB_ReadPixels
+
+Reads an image but takes care of alignment issues for reading RGB images.
+
+Reads a minimum offset for where the RGB data starts in the image from
+integer stored at pointer offset. When the function has returned the actual
+offset was written back to address offset. This address will always have an
+alignment of packAlign to ensure efficient copying.
+
+Stores the length of padding after a line of pixels to address padlen
+
+Return value must be freed with ri.Hunk_FreeTempMemory()
+==================
+*/
+
+byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *padlen)
+{
+ byte *buffer, *bufstart;
+ int padwidth, linelen;
+ GLint packAlign;
+
+ qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);
+
+ linelen = width * 3;
+ padwidth = PAD(linelen, packAlign);
+
+ // Allocate a few more bytes so that we can choose an alignment we like
+ buffer = (byte*)ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1);
+
+ bufstart = (byte*)PADP((intptr_t) buffer + *offset, packAlign);
+
+ qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart);
+
+ *offset = bufstart - buffer;
+ *padlen = padwidth - linelen;
+
+ return buffer;
+}
+
+/*
+==================
+RB_TakeScreenshot
+==================
+*/
+void RB_TakeScreenshot(int x, int y, int width, int height, char *fileName)
+{
+ byte *allbuf, *buffer;
+ byte *srcptr, *destptr;
+ byte *endline, *endmem;
+ byte temp;
+
+ int linelen, padlen;
+ size_t offset = 18, memcount;
+
+ allbuf = RB_ReadPixels(x, y, width, height, &offset, &padlen);
+ buffer = allbuf + offset - 18;
+
+ Com_Memset (buffer, 0, 18);
+ buffer[2] = 2; // uncompressed type
+ buffer[12] = width & 255;
+ buffer[13] = width >> 8;
+ buffer[14] = height & 255;
+ buffer[15] = height >> 8;
+ buffer[16] = 24; // pixel size
+
+ // swap rgb to bgr and remove padding from line endings
+ linelen = width * 3;
+
+ srcptr = destptr = allbuf + offset;
+ endmem = srcptr + (linelen + padlen) * height;
+
+ while(srcptr < endmem)
+ {
+ endline = srcptr + linelen;
+
+ while(srcptr < endline)
+ {
+ temp = srcptr[0];
+ *destptr++ = srcptr[2];
+ *destptr++ = srcptr[1];
+ *destptr++ = temp;
+
+ srcptr += 3;
+ }
+
+ // Skip the pad
+ srcptr += padlen;
+ }
+
+ memcount = linelen * height;
+
+ // gamma correct
+ if(glConfig.deviceSupportsGamma)
+ R_GammaCorrect(allbuf + offset, memcount);
+
+ ri.FS_WriteFile(fileName, buffer, memcount + 18);
+
+ ri.Hunk_FreeTempMemory(allbuf);
+}
+
+/*
+==================
+RB_TakeScreenshotJPEG
+==================
+*/
+
+void RB_TakeScreenshotJPEG(int x, int y, int width, int height, char *fileName)
+{
+ byte *buffer;
+ size_t offset = 0, memcount;
+ int padlen;
+
+ buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen);
+ memcount = (width * 3 + padlen) * height;
+
+ // gamma correct
+ if(glConfig.deviceSupportsGamma)
+ R_GammaCorrect(buffer + offset, memcount);
+
+ RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, buffer + offset, padlen);
+ ri.Hunk_FreeTempMemory(buffer);
+}
+
+/*
+==================
+RB_TakeScreenshotCmd
+==================
+*/
+const void *RB_TakeScreenshotCmd( const void *data ) {
+ const screenshotCommand_t *cmd;
+
+ cmd = (const screenshotCommand_t *)data;
+
+ // finish any 2D drawing if needed
+ if(tess.numIndexes)
+ RB_EndSurface();
+
+ if (cmd->jpeg)
+ RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
+ else
+ RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
+
+ return (const void *)(cmd + 1);
+}
+
+/*
+==================
+R_TakeScreenshot
+==================
+*/
+void R_TakeScreenshot( int x, int y, int width, int height, char *name, bool jpeg ) {
+ static char fileName[MAX_OSPATH]; // bad things if two screenshots per frame?
+ screenshotCommand_t *cmd;
+
+ cmd = (screenshotCommand_t*)R_GetCommandBuffer( sizeof( *cmd ) );
+ if ( !cmd ) {
+ return;
+ }
+ cmd->commandId = RC_SCREENSHOT;
+
+ cmd->x = x;
+ cmd->y = y;
+ cmd->width = width;
+ cmd->height = height;
+ Q_strncpyz( fileName, name, sizeof(fileName) );
+ cmd->fileName = fileName;
+ cmd->jpeg = jpeg;
+}
+
+/*
+==================
+R_ScreenshotFilename
+==================
+*/
+void R_ScreenshotFilename( int lastNumber, char *fileName ) {
+ int a,b,c,d;
+
+ if ( lastNumber < 0 || lastNumber > 9999 ) {
+ Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.tga" );
+ return;
+ }
+
+ a = lastNumber / 1000;
+ lastNumber -= a*1000;
+ b = lastNumber / 100;
+ lastNumber -= b*100;
+ c = lastNumber / 10;
+ lastNumber -= c*10;
+ d = lastNumber;
+
+ Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.tga"
+ , a, b, c, d );
+}
+
+/*
+==================
+R_ScreenshotFilename
+==================
+*/
+void R_ScreenshotFilenameJPEG( int lastNumber, char *fileName ) {
+ int a,b,c,d;
+
+ if ( lastNumber < 0 || lastNumber > 9999 ) {
+ Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.jpg" );
+ return;
+ }
+
+ a = lastNumber / 1000;
+ lastNumber -= a*1000;
+ b = lastNumber / 100;
+ lastNumber -= b*100;
+ c = lastNumber / 10;
+ lastNumber -= c*10;
+ d = lastNumber;
+
+ Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.jpg"
+ , a, b, c, d );
+}
+
+/*
+====================
+R_LevelShot
+
+levelshots are specialized 128*128 thumbnails for
+the menu system, sampled down from full screen distorted images
+====================
+*/
+void R_LevelShot( void ) {
+ char checkname[MAX_OSPATH];
+ byte *buffer;
+ byte *source, *allsource;
+ byte *src, *dst;
+ size_t offset = 0;
+ int padlen;
+ int x, y;
+ int r, g, b;
+ float xScale, yScale;
+ int xx, yy;
+
+ Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName);
+
+ allsource = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &padlen);
+ source = allsource + offset;
+
+ buffer = (byte*)ri.Hunk_AllocateTempMemory(128 * 128*3 + 18);
+ Com_Memset (buffer, 0, 18);
+ buffer[2] = 2; // uncompressed type
+ buffer[12] = 128;
+ buffer[14] = 128;
+ buffer[16] = 24; // pixel size
+
+ // resample from source
+ xScale = glConfig.vidWidth / 512.0f;
+ yScale = glConfig.vidHeight / 384.0f;
+ for ( y = 0 ; y < 128 ; y++ ) {
+ for ( x = 0 ; x < 128 ; x++ ) {
+ r = g = b = 0;
+ for ( yy = 0 ; yy < 3 ; yy++ ) {
+ for ( xx = 0 ; xx < 4 ; xx++ ) {
+ src = source + (3 * glConfig.vidWidth + padlen) * (int)((y*3 + yy) * yScale) +
+ 3 * (int) ((x*4 + xx) * xScale);
+ r += src[0];
+ g += src[1];
+ b += src[2];
+ }
+ }
+ dst = buffer + 18 + 3 * ( y * 128 + x );
+ dst[0] = b / 12;
+ dst[1] = g / 12;
+ dst[2] = r / 12;
+ }
+ }
+
+ // gamma correct
+ if ( glConfig.deviceSupportsGamma ) {
+ R_GammaCorrect( buffer + 18, 128 * 128 * 3 );
+ }
+
+ ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 );
+
+ ri.Hunk_FreeTempMemory(buffer);
+ ri.Hunk_FreeTempMemory(allsource);
+
+ ri.Printf( PRINT_ALL, "Wrote %s\n", checkname );
+}
+
+/*
+==================
+R_ScreenShot_f
+
+screenshot
+screenshot [silent]
+screenshot [levelshot]
+screenshot [filename]
+
+Doesn't print the pacifier message if there is a second arg
+==================
+*/
+void R_ScreenShot_f (void) {
+ char checkname[MAX_OSPATH];
+ static int lastNumber = -1;
+ bool silent;
+
+ if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) {
+ R_LevelShot();
+ return;
+ }
+
+ if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) {
+ silent = true;
+ } else {
+ silent = false;
+ }
+
+ if ( ri.Cmd_Argc() == 2 && !silent ) {
+ // explicit filename
+ Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv( 1 ) );
+ } else {
+ // scan for a free filename
+
+ // if we have saved a previous screenshot, don't scan
+ // again, because recording demo avis can involve
+ // thousands of shots
+ if ( lastNumber == -1 ) {
+ lastNumber = 0;
+ }
+ // scan for a free number
+ for ( ; lastNumber <= 9999 ; lastNumber++ ) {
+ R_ScreenshotFilename( lastNumber, checkname );
+
+ if (!ri.FS_FileExists( checkname ))
+ {
+ break; // file doesn't exist
+ }
+ }
+
+ if ( lastNumber >= 9999 ) {
+ ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n");
+ return;
+ }
+
+ lastNumber++;
+ }
+
+ R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, false );
+
+ if ( !silent ) {
+ ri.Printf (PRINT_ALL, "Wrote %s\n", checkname);
+ }
+}
+
+void R_ScreenShotJPEG_f (void) {
+ char checkname[MAX_OSPATH];
+ static int lastNumber = -1;
+ bool silent;
+
+ if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) {
+ R_LevelShot();
+ return;
+ }
+
+ if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) {
+ silent = true;
+ } else {
+ silent = false;
+ }
+
+ if ( ri.Cmd_Argc() == 2 && !silent ) {
+ // explicit filename
+ Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.jpg", ri.Cmd_Argv( 1 ) );
+ } else {
+ // scan for a free filename
+
+ // if we have saved a previous screenshot, don't scan
+ // again, because recording demo avis can involve
+ // thousands of shots
+ if ( lastNumber == -1 ) {
+ lastNumber = 0;
+ }
+ // scan for a free number
+ for ( ; lastNumber <= 9999 ; lastNumber++ ) {
+ R_ScreenshotFilenameJPEG( lastNumber, checkname );
+
+ if (!ri.FS_FileExists( checkname ))
+ {
+ break; // file doesn't exist
+ }
+ }
+
+ if ( lastNumber == 10000 ) {
+ ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n");
+ return;
+ }
+
+ lastNumber++;
+ }
+
+ R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, true );
+
+ if ( !silent ) {
+ ri.Printf (PRINT_ALL, "Wrote %s\n", checkname);
+ }
+}
+
+//============================================================================
+
+/*
+==================
+R_ExportCubemaps
+==================
+*/
+void R_ExportCubemaps(void)
+{
+ exportCubemapsCommand_t *cmd;
+
+ cmd = (exportCubemapsCommand_t*)R_GetCommandBuffer(sizeof(*cmd));
+ if (!cmd) {
+ return;
+ }
+ cmd->commandId = RC_EXPORT_CUBEMAPS;
+}
+
+
+/*
+==================
+R_ExportCubemaps_f
+==================
+*/
+void R_ExportCubemaps_f(void)
+{
+ R_ExportCubemaps();
+}
+
+//============================================================================
+
+/*
+==================
+RB_TakeVideoFrameCmd
+==================
+*/
+const void *RB_TakeVideoFrameCmd( const void *data )
+{
+ const videoFrameCommand_t *cmd;
+ byte *cBuf;
+ size_t memcount, linelen;
+ int padwidth, avipadwidth, padlen, avipadlen;
+ GLint packAlign;
+
+ // finish any 2D drawing if needed
+ if(tess.numIndexes)
+ RB_EndSurface();
+
+ cmd = (const videoFrameCommand_t *)data;
+
+ qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);
+
+ linelen = cmd->width * 3;
+
+ // Alignment stuff for glReadPixels
+ padwidth = PAD(linelen, packAlign);
+ padlen = padwidth - linelen;
+ // AVI line padding
+ avipadwidth = PAD(linelen, AVI_LINE_PADDING);
+ avipadlen = avipadwidth - linelen;
+
+ cBuf = (byte*)PADP(cmd->captureBuffer, packAlign);
+
+ qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB,
+ GL_UNSIGNED_BYTE, cBuf);
+
+ memcount = padwidth * cmd->height;
+
+ // gamma correct
+ if(glConfig.deviceSupportsGamma)
+ R_GammaCorrect(cBuf, memcount);
+
+ if(cmd->motionJpeg)
+ {
+ memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height,
+ r_aviMotionJpegQuality->integer,
+ cmd->width, cmd->height, cBuf, padlen);
+ ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount);
+ }
+ else
+ {
+ byte *lineend, *memend;
+ byte *srcptr, *destptr;
+
+ srcptr = cBuf;
+ destptr = cmd->encodeBuffer;
+ memend = srcptr + memcount;
+
+ // swap R and B and remove line paddings
+ while(srcptr < memend)
+ {
+ lineend = srcptr + linelen;
+ while(srcptr < lineend)
+ {
+ *destptr++ = srcptr[2];
+ *destptr++ = srcptr[1];
+ *destptr++ = srcptr[0];
+ srcptr += 3;
+ }
+
+ Com_Memset(destptr, '\0', avipadlen);
+ destptr += avipadlen;
+
+ srcptr += padlen;
+ }
+
+ ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, avipadwidth * cmd->height);
+ }
+
+ return (const void *)(cmd + 1);
+}
+
+//============================================================================
+
+/*
+** GL_SetDefaultState
+*/
+void GL_SetDefaultState( void )
+{
+ qglClearDepth( 1.0f );
+
+ qglCullFace(GL_FRONT);
+
+ GL_BindNullTextures();
+
+ if (glRefConfig.framebufferObject)
+ GL_BindNullFramebuffers();
+
+ GL_TextureMode( r_textureMode->string );
+
+ //qglShadeModel( GL_SMOOTH );
+ qglDepthFunc( GL_LEQUAL );
+
+ //
+ // make sure our GL state vector is set correctly
+ //
+ glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE;
+ glState.storedGlState = 0;
+ glState.faceCulling = CT_TWO_SIDED;
+ glState.faceCullFront = true;
+
+ GL_BindNullProgram();
+
+ if (glRefConfig.vertexArrayObject)
+ qglBindVertexArray(0);
+
+ qglBindBuffer(GL_ARRAY_BUFFER, 0);
+ qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glState.currentVao = NULL;
+ glState.vertexAttribsEnabled = 0;
+
+ qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+ qglDepthMask( GL_TRUE );
+ qglDisable( GL_DEPTH_TEST );
+ qglEnable( GL_SCISSOR_TEST );
+ qglDisable( GL_CULL_FACE );
+ qglDisable( GL_BLEND );
+
+ if (glRefConfig.seamlessCubeMap)
+ qglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+
+ // GL_POLYGON_OFFSET_FILL will be glEnable()d when this is used
+ qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );
+
+ qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky
+}
+
+/*
+================
+R_PrintLongString
+
+Workaround for ri.Printf's 1024 characters buffer limit.
+================
+*/
+void R_PrintLongString(const char *string) {
+ char buffer[1024];
+ const char *p;
+ int size = strlen(string);
+
+ p = string;
+ while(size > 0)
+ {
+ Q_strncpyz(buffer, p, sizeof (buffer) );
+ ri.Printf( PRINT_ALL, "%s", buffer );
+ p += 1023;
+ size -= 1023;
+ }
+}
+
+/*
+================
+GfxInfo_f
+================
+*/
+void GfxInfo_f( void )
+{
+ const char *enablestrings[] =
+ {
+ "disabled",
+ "enabled"
+ };
+ const char *fsstrings[] =
+ {
+ "windowed",
+ "fullscreen"
+ };
+
+ ri.Printf( PRINT_ALL, "\nGL_VENDOR: %s\n", glConfig.vendor_string );
+ ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string );
+ ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string );
+ ri.Printf( PRINT_ALL, "GL_EXTENSIONS: " );
+ R_PrintLongString( glConfig.extensions_string );
+ ri.Printf( PRINT_ALL, "\n" );
+ ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize );
+ ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.numTextureUnits );
+ ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits );
+ ri.Printf( PRINT_ALL, "MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] );
+ if ( glConfig.displayFrequency )
+ {
+ ri.Printf( PRINT_ALL, "%d\n", glConfig.displayFrequency );
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "N/A\n" );
+ }
+ if ( glConfig.deviceSupportsGamma )
+ {
+ ri.Printf( PRINT_ALL, "GAMMA: hardware w/ %d overbright bits\n", tr.overbrightBits );
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "GAMMA: software w/ %d overbright bits\n", tr.overbrightBits );
+ }
+
+ ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string );
+ ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer );
+ ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer );
+ ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] );
+ ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] );
+ ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] );
+ if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 )
+ {
+ ri.Printf( PRINT_ALL, "HACK: using vertex lightmap approximation\n" );
+ }
+ if ( glConfig.hardwareType == GLHW_RAGEPRO )
+ {
+ ri.Printf( PRINT_ALL, "HACK: ragePro approximations\n" );
+ }
+ if ( glConfig.hardwareType == GLHW_RIVA128 )
+ {
+ ri.Printf( PRINT_ALL, "HACK: riva128 approximations\n" );
+ }
+ if ( r_finish->integer ) {
+ ri.Printf( PRINT_ALL, "Forcing glFinish\n" );
+ }
+}
+
+/*
+================
+GfxMemInfo_f
+================
+*/
+void GfxMemInfo_f( void )
+{
+ switch (glRefConfig.memInfo)
+ {
+ case MI_NONE:
+ {
+ ri.Printf(PRINT_ALL, "No extension found for GPU memory info.\n");
+ }
+ break;
+ case MI_NVX:
+ {
+ int value;
+
+ qglGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &value);
+ ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX: %ikb\n", value);
+
+ qglGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &value);
+ ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: %ikb\n", value);
+
+ qglGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &value);
+ ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX: %ikb\n", value);
+
+ qglGetIntegerv(GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX, &value);
+ ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_EVICTION_COUNT_NVX: %i\n", value);
+
+ qglGetIntegerv(GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX, &value);
+ ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_EVICTED_MEMORY_NVX: %ikb\n", value);
+ }
+ break;
+ case MI_ATI:
+ {
+ // GL_ATI_meminfo
+ int value[4];
+
+ qglGetIntegerv(GL_VBO_FREE_MEMORY_ATI, &value[0]);
+ ri.Printf(PRINT_ALL, "VBO_FREE_MEMORY_ATI: %ikb total %ikb largest aux: %ikb total %ikb largest\n", value[0], value[1], value[2], value[3]);
+
+ qglGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, &value[0]);
+ ri.Printf(PRINT_ALL, "TEXTURE_FREE_MEMORY_ATI: %ikb total %ikb largest aux: %ikb total %ikb largest\n", value[0], value[1], value[2], value[3]);
+
+ qglGetIntegerv(GL_RENDERBUFFER_FREE_MEMORY_ATI, &value[0]);
+ ri.Printf(PRINT_ALL, "RENDERBUFFER_FREE_MEMORY_ATI: %ikb total %ikb largest aux: %ikb total %ikb largest\n", value[0], value[1], value[2], value[3]);
+ }
+ break;
+ }
+}
+
+/*
+===============
+R_Register
+===============
+*/
+void R_Register( void )
+{
+ #ifdef USE_RENDERER_DLOPEN
+ com_altivec = ri.Cvar_Get("com_altivec", "1", CVAR_ARCHIVE);
+ #endif
+
+ //
+ // latched and archived variables
+ //
+ r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH);
+ r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH);
+
+ r_ext_framebuffer_object = ri.Cvar_Get( "r_ext_framebuffer_object", "1", CVAR_ARCHIVE | CVAR_LATCH);
+ r_ext_texture_float = ri.Cvar_Get( "r_ext_texture_float", "1", CVAR_ARCHIVE | CVAR_LATCH);
+ r_ext_framebuffer_multisample = ri.Cvar_Get( "r_ext_framebuffer_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ r_arb_seamless_cube_map = ri.Cvar_Get( "r_arb_seamless_cube_map", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ r_arb_vertex_array_object = ri.Cvar_Get( "r_arb_vertex_array_object", "1", CVAR_ARCHIVE | CVAR_LATCH);
+ r_ext_direct_state_access = ri.Cvar_Get("r_ext_direct_state_access", "1", CVAR_ARCHIVE | CVAR_LATCH);
+
+ r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic",
+ "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "2", CVAR_ARCHIVE | CVAR_LATCH );
+
+ r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH );
+ ri.Cvar_CheckRange( r_picmip, 0, 16, true );
+ r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_alphabits = ri.Cvar_Get( "r_alphabits", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH );
+ r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ ri.Cvar_CheckRange( r_ext_multisample, 0, 4, true );
+ r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ r_mode = ri.Cvar_Get( "r_mode", "-2", CVAR_ARCHIVE | CVAR_LATCH );
+ r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE );
+ r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ r_width = ri.Cvar_Get( "r_width", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_height = ri.Cvar_Get( "r_height", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_pixelAspect = ri.Cvar_Get( "r_pixelAspect", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_simpleMipMaps = ri.Cvar_Get( "r_simpleMipMaps", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0);
+ r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH);
+ r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ ri.Cvar_CheckRange(r_greyscale, 0, 1, false);
+
+ r_externalGLSL = ri.Cvar_Get( "r_externalGLSL", "0", CVAR_LATCH );
+
+ r_hdr = ri.Cvar_Get( "r_hdr", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_floatLightmap = ri.Cvar_Get( "r_floatLightmap", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_postProcess = ri.Cvar_Get( "r_postProcess", "1", CVAR_ARCHIVE );
+
+ r_toneMap = ri.Cvar_Get( "r_toneMap", "1", CVAR_ARCHIVE );
+ r_forceToneMap = ri.Cvar_Get( "r_forceToneMap", "0", CVAR_CHEAT );
+ r_forceToneMapMin = ri.Cvar_Get( "r_forceToneMapMin", "-8.0", CVAR_CHEAT );
+ r_forceToneMapAvg = ri.Cvar_Get( "r_forceToneMapAvg", "-2.0", CVAR_CHEAT );
+ r_forceToneMapMax = ri.Cvar_Get( "r_forceToneMapMax", "0.0", CVAR_CHEAT );
+
+ r_autoExposure = ri.Cvar_Get( "r_autoExposure", "1", CVAR_ARCHIVE );
+ r_forceAutoExposure = ri.Cvar_Get( "r_forceAutoExposure", "0", CVAR_CHEAT );
+ r_forceAutoExposureMin = ri.Cvar_Get( "r_forceAutoExposureMin", "-2.0", CVAR_CHEAT );
+ r_forceAutoExposureMax = ri.Cvar_Get( "r_forceAutoExposureMax", "2.0", CVAR_CHEAT );
+
+ r_cameraExposure = ri.Cvar_Get( "r_cameraExposure", "0", CVAR_CHEAT );
+
+ r_depthPrepass = ri.Cvar_Get( "r_depthPrepass", "1", CVAR_ARCHIVE );
+ r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE );
+
+ r_normalMapping = ri.Cvar_Get( "r_normalMapping", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_specularMapping = ri.Cvar_Get( "r_specularMapping", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_deluxeMapping = ri.Cvar_Get( "r_deluxeMapping", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_parallaxMapping = ri.Cvar_Get( "r_parallaxMapping", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_cubeMapping = ri.Cvar_Get( "r_cubeMapping", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_cubemapSize = ri.Cvar_Get( "r_cubemapSize", "128", CVAR_ARCHIVE | CVAR_LATCH );
+ r_pbr = ri.Cvar_Get("r_pbr", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ r_baseNormalX = ri.Cvar_Get( "r_baseNormalX", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_baseNormalY = ri.Cvar_Get( "r_baseNormalY", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_baseParallax = ri.Cvar_Get( "r_baseParallax", "0.05", CVAR_ARCHIVE | CVAR_LATCH );
+ r_baseSpecular = ri.Cvar_Get( "r_baseSpecular", "0.04", CVAR_ARCHIVE | CVAR_LATCH );
+ r_baseGloss = ri.Cvar_Get( "r_baseGloss", "0.3", CVAR_ARCHIVE | CVAR_LATCH );
+ r_glossType = ri.Cvar_Get("r_glossType", "1", CVAR_ARCHIVE | CVAR_LATCH);
+ r_dlightMode = ri.Cvar_Get( "r_dlightMode", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_pshadowDist = ri.Cvar_Get( "r_pshadowDist", "128", CVAR_ARCHIVE );
+ r_mergeLightmaps = ri.Cvar_Get( "r_mergeLightmaps", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_imageUpsample = ri.Cvar_Get( "r_imageUpsample", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_imageUpsampleMaxSize = ri.Cvar_Get( "r_imageUpsampleMaxSize", "1024", CVAR_ARCHIVE | CVAR_LATCH );
+ r_imageUpsampleType = ri.Cvar_Get( "r_imageUpsampleType", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_genNormalMaps = ri.Cvar_Get( "r_genNormalMaps", "0", CVAR_ARCHIVE | CVAR_LATCH );
+
+ r_forceSun = ri.Cvar_Get( "r_forceSun", "0", CVAR_CHEAT );
+ r_forceSunLightScale = ri.Cvar_Get( "r_forceSunLightScale", "1.0", CVAR_CHEAT );
+ r_forceSunAmbientScale = ri.Cvar_Get( "r_forceSunAmbientScale", "0.5", CVAR_CHEAT );
+ r_drawSunRays = ri.Cvar_Get( "r_drawSunRays", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_sunlightMode = ri.Cvar_Get( "r_sunlightMode", "1", CVAR_ARCHIVE | CVAR_LATCH );
+
+ r_sunShadows = ri.Cvar_Get( "r_sunShadows", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_shadowFilter = ri.Cvar_Get( "r_shadowFilter", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_shadowBlur = ri.Cvar_Get("r_shadowBlur", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ r_shadowMapSize = ri.Cvar_Get("r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH);
+ r_shadowCascadeZNear = ri.Cvar_Get( "r_shadowCascadeZNear", "8", CVAR_ARCHIVE | CVAR_LATCH );
+ r_shadowCascadeZFar = ri.Cvar_Get( "r_shadowCascadeZFar", "1024", CVAR_ARCHIVE | CVAR_LATCH );
+ r_shadowCascadeZBias = ri.Cvar_Get( "r_shadowCascadeZBias", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ignoreDstAlpha = ri.Cvar_Get( "r_ignoreDstAlpha", "1", CVAR_ARCHIVE | CVAR_LATCH );
+
+ //
+ // temporary latched variables that can only change over a restart
+ //
+ r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT );
+ r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH );
+ r_mapLightmapMin = ri.Cvar_Get ("r_mapLightmapMin", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH );
+
+ //
+ // archived variables that can change at any time
+ //
+ r_lodCurveError = ri.Cvar_Get( "r_lodCurveError", "250", CVAR_ARCHIVE|CVAR_CHEAT );
+ r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE );
+ r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE );
+ r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT );
+ ri.Cvar_CheckRange( r_znear, 0.001f, 200, false );
+ r_zproj = ri.Cvar_Get( "r_zproj", "64", CVAR_ARCHIVE );
+ r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", CVAR_ARCHIVE );
+ r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE );
+ r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE );
+ r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE );
+ r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE );
+ r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE );
+ r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE );
+ r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE);
+ r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE );
+ r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0",
+ CVAR_ARCHIVE | CVAR_LATCH );
+ r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE );
+ r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE );
+
+ r_railWidth = ri.Cvar_Get( "r_railWidth", "16", CVAR_ARCHIVE );
+ r_railCoreWidth = ri.Cvar_Get( "r_railCoreWidth", "6", CVAR_ARCHIVE );
+ r_railSegmentLength = ri.Cvar_Get( "r_railSegmentLength", "32", CVAR_ARCHIVE );
+
+ r_ambientScale = ri.Cvar_Get( "r_ambientScale", "0.6", CVAR_CHEAT );
+ r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT );
+
+ r_anaglyphMode = ri.Cvar_Get("r_anaglyphMode", "0", CVAR_ARCHIVE);
+
+ //
+ // temporary variables that can change at any time
+ //
+ r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_CHEAT|CVAR_TEMP );
+
+ r_debugLight = ri.Cvar_Get( "r_debuglight", "0", CVAR_TEMP );
+ r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT );
+ r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 );
+ r_saveFontData = ri.Cvar_Get( "r_saveFontData", "0", 0 );
+
+ r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT );
+ r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT );
+ r_lightmap = ri.Cvar_Get ("r_lightmap", "0", 0 );
+ r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_CHEAT );
+
+ r_flareSize = ri.Cvar_Get ("r_flareSize", "40", CVAR_CHEAT);
+ r_flareFade = ri.Cvar_Get ("r_flareFade", "7", CVAR_CHEAT);
+ r_flareCoeff = ri.Cvar_Get ("r_flareCoeff", FLARE_STDCOEFF, CVAR_CHEAT);
+
+ r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT);
+
+ r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT );
+ r_lodscale = ri.Cvar_Get( "r_lodscale", "5", CVAR_CHEAT );
+ r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT);
+ r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT );
+ r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT );
+ r_nocull = ri.Cvar_Get ("r_nocull", "0", CVAR_CHEAT);
+ r_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT);
+ r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT);
+ r_speeds = ri.Cvar_Get ("r_speeds", "0", CVAR_CHEAT);
+ r_verbose = ri.Cvar_Get( "r_verbose", "0", CVAR_CHEAT );
+ r_logFile = ri.Cvar_Get( "r_logFile", "0", CVAR_CHEAT );
+ r_debugSurface = ri.Cvar_Get ("r_debugSurface", "0", CVAR_CHEAT);
+ r_nobind = ri.Cvar_Get ("r_nobind", "0", CVAR_CHEAT);
+ r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT);
+ r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT);
+ r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT);
+ r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT);
+ r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT );
+ r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT );
+ r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT );
+ r_lockpvs = ri.Cvar_Get ("r_lockpvs", "0", CVAR_CHEAT);
+ r_noportals = ri.Cvar_Get ("r_noportals", "0", CVAR_CHEAT);
+ r_shadows = ri.Cvar_Get( "cg_shadows", "1", 0 );
+
+ r_marksOnTriangleMeshes = ri.Cvar_Get("r_marksOnTriangleMeshes", "0", CVAR_ARCHIVE);
+
+ r_aviMotionJpegQuality = ri.Cvar_Get("r_aviMotionJpegQuality", "90", CVAR_ARCHIVE);
+ r_screenshotJpegQuality = ri.Cvar_Get("r_screenshotJpegQuality", "90", CVAR_ARCHIVE);
+
+ r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0);
+ r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0);
+
+ // make sure all the commands added here are also
+ // removed in R_Shutdown
+ ri.Cmd_AddCommand( "imagelist", R_ImageList_f );
+ ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f );
+ ri.Cmd_AddCommand( "skinlist", R_SkinList_f );
+ ri.Cmd_AddCommand( "modellist", R_Modellist_f );
+ ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
+ ri.Cmd_AddCommand( "screenshotJPEG", R_ScreenShotJPEG_f );
+ ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f );
+ ri.Cmd_AddCommand( "minimize", GLimp_Minimize );
+ ri.Cmd_AddCommand( "gfxmeminfo", GfxMemInfo_f );
+ ri.Cmd_AddCommand( "exportCubemaps", R_ExportCubemaps_f );
+}
+
+void R_InitQueries(void)
+{
+ if (!glRefConfig.occlusionQuery)
+ return;
+
+ if (r_drawSunRays->integer)
+ qglGenQueries(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery);
+}
+
+void R_ShutDownQueries(void)
+{
+ if (!glRefConfig.occlusionQuery)
+ return;
+
+ if (r_drawSunRays->integer)
+ qglDeleteQueries(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery);
+}
+
+/*
+===============
+R_Init
+===============
+*/
+void R_Init( void ) {
+ int err;
+ int i;
+ byte *ptr;
+
+ ri.Printf( PRINT_ALL, "----- R_Init -----\n" );
+
+ // clear all our internal state
+ Com_Memset( &tr, 0, sizeof( tr ) );
+ Com_Memset( &backEnd, 0, sizeof( backEnd ) );
+ Com_Memset( &tess, 0, sizeof( tess ) );
+
+// Swap_Init();
+
+ if ( (intptr_t)tess.xyz & 15 ) {
+ ri.Printf( PRINT_WARNING, "tess.xyz not 16 byte aligned\n" );
+ }
+ //Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) );
+
+ //
+ // init function tables
+ //
+ for ( i = 0; i < FUNCTABLE_SIZE; i++ )
+ {
+ tr.sinTable[i] = sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) );
+ tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f;
+ tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE;
+ tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i];
+
+ if ( i < FUNCTABLE_SIZE / 2 )
+ {
+ if ( i < FUNCTABLE_SIZE / 4 )
+ {
+ tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 );
+ }
+ else
+ {
+ tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4];
+ }
+ }
+ else
+ {
+ tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2];
+ }
+ }
+
+ R_InitFogTable();
+
+ R_NoiseInit();
+
+ R_Register();
+
+ max_polys = r_maxpolys->integer;
+ if (max_polys < MAX_POLYS)
+ max_polys = MAX_POLYS;
+
+ max_polyverts = r_maxpolyverts->integer;
+ if (max_polyverts < MAX_POLYVERTS)
+ max_polyverts = MAX_POLYVERTS;
+
+ ptr = (byte*)ri.Hunk_Alloc( sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low);
+ backEndData = (backEndData_t *) ptr;
+ backEndData->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData ));
+ backEndData->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys);
+ R_InitNextFrame();
+
+ InitOpenGL();
+
+ R_InitImages();
+
+ if (glRefConfig.framebufferObject)
+ FBO_Init();
+
+ GLSL_InitGPUShaders();
+
+ R_InitVaos();
+
+ R_InitShaders();
+
+ R_InitSkins();
+
+ R_ModelInit();
+
+ R_InitFreeType();
+
+ R_InitQueries();
+
+
+ err = qglGetError();
+ if ( err != GL_NO_ERROR )
+ ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err);
+
+ // print info
+ GfxInfo_f();
+ ri.Printf( PRINT_ALL, "----- finished R_Init -----\n" );
+}
+
+/*
+===============
+RE_Shutdown
+===============
+*/
+void RE_Shutdown( bool destroyWindow ) {
+
+ ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow );
+
+ ri.Cmd_RemoveCommand("exportCubemaps");
+ ri.Cmd_RemoveCommand("gfxinfo");
+ ri.Cmd_RemoveCommand("gfxmeminfo");
+ ri.Cmd_RemoveCommand("imagelist");
+ ri.Cmd_RemoveCommand("minimize");
+ ri.Cmd_RemoveCommand("modellist");
+ ri.Cmd_RemoveCommand("screenshot");
+ ri.Cmd_RemoveCommand("screenshotJPEG");
+ ri.Cmd_RemoveCommand("shaderlist");
+ ri.Cmd_RemoveCommand("skinlist");
+
+ if ( tr.registered ) {
+ R_IssuePendingRenderCommands();
+ R_ShutDownQueries();
+ if (glRefConfig.framebufferObject)
+ FBO_Shutdown();
+ R_DeleteTextures();
+ R_ShutdownVaos();
+ GLSL_ShutdownGPUShaders();
+ }
+
+ R_DoneFreeType();
+
+ // shut down platform specific OpenGL stuff
+ if ( destroyWindow ) {
+ GLimp_Shutdown();
+
+ Com_Memset( &glConfig, 0, sizeof( glConfig ) );
+ Com_Memset( &glState, 0, sizeof( glState ) );
+ }
+
+ tr.registered = false;
+}
+
+
+/*
+=============
+RE_EndRegistration
+
+Touch all images to make sure they are resident
+=============
+*/
+void RE_EndRegistration( void ) {
+ R_IssuePendingRenderCommands();
+ if (!ri.Sys_LowPhysicalMemory()) {
+ RB_ShowImages();
+ }
+}
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+GetRefAPI
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+#ifdef USE_RENDERER_DLOPEN
+extern "C" Q_EXPORT refexport_t* QDECL GetRefAPI ( int apiVersion, refimport_t *rimp ) {
+#else
+refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {
+#endif
+
+ static refexport_t re;
+
+ ri = *rimp;
+
+ Com_Memset( &re, 0, sizeof( re ) );
+
+ if ( apiVersion != REF_API_VERSION ) {
+ ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n",
+ REF_API_VERSION, apiVersion );
+ return NULL;
+ }
+
+ // the RE_ functions are Renderer Entry points
+
+ re.Shutdown = RE_Shutdown;
+
+ re.BeginRegistration = RE_BeginRegistration;
+ re.RegisterModel = RE_RegisterModel;
+ re.RegisterSkin = RE_RegisterSkin;
+ re.RegisterShader = RE_RegisterShader;
+ re.RegisterShaderNoMip = RE_RegisterShaderNoMip;
+ re.LoadWorld = RE_LoadWorldMap;
+ re.SetWorldVisData = RE_SetWorldVisData;
+ re.EndRegistration = RE_EndRegistration;
+
+ re.BeginFrame = RE_BeginFrame;
+ re.EndFrame = RE_EndFrame;
+
+ re.MarkFragments = R_MarkFragments;
+ re.LerpTag = R_LerpTag;
+ re.ModelBounds = R_ModelBounds;
+
+ re.ClearScene = RE_ClearScene;
+ re.AddRefEntityToScene = RE_AddRefEntityToScene;
+ re.AddPolyToScene = RE_AddPolyToScene;
+ re.LightForPoint = R_LightForPoint;
+ re.AddLightToScene = RE_AddLightToScene;
+ re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene;
+ re.RenderScene = RE_RenderScene;
+
+ re.SetColor = RE_SetColor;
+ re.SetClipRegion = RE_SetClipRegion;
+ re.DrawStretchPic = RE_StretchPic;
+ re.DrawStretchRaw = RE_StretchRaw;
+ re.UploadCinematic = RE_UploadCinematic;
+
+ re.RegisterFont = RE_RegisterFont;
+ re.RemapShader = R_RemapShader;
+ re.GetEntityToken = R_GetEntityToken;
+ re.inPVS = R_inPVS;
+
+ re.TakeVideoFrame = RE_TakeVideoFrame;
+
+ return &re;
+}
diff --git a/src/renderergl2/tr_light.cpp b/src/renderergl2/tr_light.cpp
new file mode 100644
index 0000000..d14217f
--- /dev/null
+++ b/src/renderergl2/tr_light.cpp
@@ -0,0 +1,513 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_light.c
+
+#include "tr_local.h"
+
+#define DLIGHT_AT_RADIUS 16
+// at the edge of a dlight's influence, this amount of light will be added
+
+#define DLIGHT_MINIMUM_RADIUS 16
+// never calculate a range less than this to prevent huge light numbers
+
+
+/*
+===============
+R_TransformDlights
+
+Transforms the origins of an array of dlights.
+Used by both the front end (for DlightBmodel) and
+the back end (before doing the lighting calculation)
+===============
+*/
+void R_TransformDlights( int count, dlight_t *dl, orientationr_t *orientation) {
+ int i;
+ vec3_t temp;
+
+ for ( i = 0 ; i < count ; i++, dl++ ) {
+ VectorSubtract( dl->origin, orientation->origin, temp );
+ dl->transformed[0] = DotProduct( temp, orientation->axis[0] );
+ dl->transformed[1] = DotProduct( temp, orientation->axis[1] );
+ dl->transformed[2] = DotProduct( temp, orientation->axis[2] );
+ }
+}
+
+/*
+=============
+R_DlightBmodel
+
+Determine which dynamic lights may effect this bmodel
+=============
+*/
+void R_DlightBmodel( bmodel_t *bmodel ) {
+ int i, j;
+ dlight_t *dl;
+ int mask;
+ msurface_t *surf;
+
+ // transform all the lights
+ R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.orientation );
+
+ mask = 0;
+ for ( i=0 ; i<tr.refdef.num_dlights ; i++ ) {
+ dl = &tr.refdef.dlights[i];
+
+ // see if the point is close enough to the bounds to matter
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) {
+ break;
+ }
+ if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) {
+ break;
+ }
+ }
+ if ( j < 3 ) {
+ continue;
+ }
+
+ // we need to check this light
+ mask |= 1 << i;
+ }
+
+ tr.currentEntity->needDlights = (mask != 0);
+
+ // set the dlight bits in all the surfaces
+ for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
+ surf = tr.world->surfaces + bmodel->firstSurface + i;
+
+ switch(*surf->data)
+ {
+ case SF_FACE:
+ case SF_GRID:
+ case SF_TRIANGLES:
+ ((srfBspSurface_t *)surf->data)->dlightBits = mask;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+
+/*
+=============================================================================
+
+LIGHT SAMPLING
+
+=============================================================================
+*/
+
+extern cvar_t *r_ambientScale;
+extern cvar_t *r_directedScale;
+extern cvar_t *r_debugLight;
+
+/*
+=================
+R_SetupEntityLightingGrid
+
+=================
+*/
+static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) {
+ vec3_t lightOrigin;
+ int pos[3];
+ int i, j;
+ byte *gridData;
+ float frac[3];
+ int gridStep[3];
+ vec3_t direction;
+ float totalFactor;
+
+ if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
+ // seperate lightOrigins are needed so an object that is
+ // sinking into the ground can still be lit, and so
+ // multi-part models can be lit identically
+ VectorCopy( ent->e.lightingOrigin, lightOrigin );
+ } else {
+ VectorCopy( ent->e.origin, lightOrigin );
+ }
+
+ VectorSubtract( lightOrigin, world->lightGridOrigin, lightOrigin );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ float v;
+
+ v = lightOrigin[i]*world->lightGridInverseSize[i];
+ pos[i] = floor( v );
+ frac[i] = v - pos[i];
+ if ( pos[i] < 0 ) {
+ pos[i] = 0;
+ } else if ( pos[i] > world->lightGridBounds[i] - 1 ) {
+ pos[i] = world->lightGridBounds[i] - 1;
+ }
+ }
+
+ VectorClear( ent->ambientLight );
+ VectorClear( ent->directedLight );
+ VectorClear( direction );
+
+ assert( world->lightGridData ); // NULL with -nolight maps
+
+ // trilerp the light value
+ gridStep[0] = 8;
+ gridStep[1] = 8 * world->lightGridBounds[0];
+ gridStep[2] = 8 * world->lightGridBounds[0] * world->lightGridBounds[1];
+ gridData = world->lightGridData + pos[0] * gridStep[0]
+ + pos[1] * gridStep[1] + pos[2] * gridStep[2];
+
+ totalFactor = 0;
+ for ( i = 0 ; i < 8 ; i++ ) {
+ float factor;
+ byte *data;
+ int lat, lng;
+ vec3_t normal;
+ #if idppc
+ float d0, d1, d2, d3, d4, d5;
+ #endif
+ factor = 1.0;
+ data = gridData;
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( i & (1<<j) ) {
+ if ( pos[j] + 1 > world->lightGridBounds[j] - 1 ) {
+ break; // ignore values outside lightgrid
+ }
+ factor *= frac[j];
+ data += gridStep[j];
+ } else {
+ factor *= (1.0f - frac[j]);
+ }
+ }
+
+ if ( j != 3 ) {
+ continue;
+ }
+
+ if (world->lightGrid16)
+ {
+ uint16_t *data16 = world->lightGrid16 + (int)(data - world->lightGridData) / 8 * 6;
+ if (!(data16[0]+data16[1]+data16[2]+data16[3]+data16[4]+data16[5])) {
+ continue; // ignore samples in walls
+ }
+ }
+ else
+ {
+ if (!(data[0]+data[1]+data[2]+data[3]+data[4]+data[5]) ) {
+ continue; // ignore samples in walls
+ }
+ }
+ totalFactor += factor;
+ #if idppc
+ d0 = data[0]; d1 = data[1]; d2 = data[2];
+ d3 = data[3]; d4 = data[4]; d5 = data[5];
+
+ ent->ambientLight[0] += factor * d0;
+ ent->ambientLight[1] += factor * d1;
+ ent->ambientLight[2] += factor * d2;
+
+ ent->directedLight[0] += factor * d3;
+ ent->directedLight[1] += factor * d4;
+ ent->directedLight[2] += factor * d5;
+ #else
+ if (world->lightGrid16)
+ {
+ // FIXME: this is hideous
+ uint16_t *data16 = world->lightGrid16 + (int)(data - world->lightGridData) / 8 * 6;
+
+ ent->ambientLight[0] += factor * data16[0] / 257.0f;
+ ent->ambientLight[1] += factor * data16[1] / 257.0f;
+ ent->ambientLight[2] += factor * data16[2] / 257.0f;
+
+ ent->directedLight[0] += factor * data16[3] / 257.0f;
+ ent->directedLight[1] += factor * data16[4] / 257.0f;
+ ent->directedLight[2] += factor * data16[5] / 257.0f;
+ }
+ else
+ {
+ ent->ambientLight[0] += factor * data[0];
+ ent->ambientLight[1] += factor * data[1];
+ ent->ambientLight[2] += factor * data[2];
+
+ ent->directedLight[0] += factor * data[3];
+ ent->directedLight[1] += factor * data[4];
+ ent->directedLight[2] += factor * data[5];
+ }
+ #endif
+ lat = data[7];
+ lng = data[6];
+ lat *= (FUNCTABLE_SIZE/256);
+ lng *= (FUNCTABLE_SIZE/256);
+
+ // decode X as cos( lat ) * sin( long )
+ // decode Y as sin( lat ) * sin( long )
+ // decode Z as cos( long )
+
+ normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+ normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
+ normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+
+ VectorMA( direction, factor, normal, direction );
+ }
+
+ if ( totalFactor > 0 && totalFactor < 0.99 ) {
+ totalFactor = 1.0f / totalFactor;
+ VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
+ VectorScale( ent->directedLight, totalFactor, ent->directedLight );
+ }
+
+ VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
+ VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );
+
+ VectorNormalize2( direction, ent->lightDir );
+}
+
+
+/*
+===============
+LogLight
+===============
+*/
+static void LogLight( trRefEntity_t *ent ) {
+ int max1, max2;
+
+ if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) {
+ return;
+ }
+
+ max1 = ent->ambientLight[0];
+ if ( ent->ambientLight[1] > max1 ) {
+ max1 = ent->ambientLight[1];
+ } else if ( ent->ambientLight[2] > max1 ) {
+ max1 = ent->ambientLight[2];
+ }
+
+ max2 = ent->directedLight[0];
+ if ( ent->directedLight[1] > max2 ) {
+ max2 = ent->directedLight[1];
+ } else if ( ent->directedLight[2] > max2 ) {
+ max2 = ent->directedLight[2];
+ }
+
+ ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 );
+}
+
+/*
+=================
+R_SetupEntityLighting
+
+Calculates all the lighting values that will be used
+by the Calc_* functions
+=================
+*/
+void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
+ int i;
+ dlight_t *dl;
+ float power;
+ vec3_t dir;
+ float d;
+ vec3_t lightDir;
+ vec3_t lightOrigin;
+
+ // lighting calculations
+ if ( ent->lightingCalculated ) {
+ return;
+ }
+ ent->lightingCalculated = true;
+
+ //
+ // trace a sample point down to find ambient light
+ //
+ if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
+ // seperate lightOrigins are needed so an object that is
+ // sinking into the ground can still be lit, and so
+ // multi-part models can be lit identically
+ VectorCopy( ent->e.lightingOrigin, lightOrigin );
+ } else {
+ VectorCopy( ent->e.origin, lightOrigin );
+ }
+
+ // if NOWORLDMODEL, only use dynamic lights (menu system, etc)
+ if ( !(refdef->rdflags & RDF_NOWORLDMODEL )
+ && tr.world->lightGridData ) {
+ R_SetupEntityLightingGrid( ent, tr.world );
+ } else {
+ ent->ambientLight[0] = ent->ambientLight[1] =
+ ent->ambientLight[2] = tr.identityLight * 150;
+ ent->directedLight[0] = ent->directedLight[1] =
+ ent->directedLight[2] = tr.identityLight * 150;
+ VectorCopy( tr.sunDirection, ent->lightDir );
+ }
+
+ // bonus items and view weapons have a fixed minimum add
+ if ( !r_hdr->integer /* ent->e.renderfx & RF_MINLIGHT */ ) {
+ // give everything a minimum light add
+ ent->ambientLight[0] += tr.identityLight * 32;
+ ent->ambientLight[1] += tr.identityLight * 32;
+ ent->ambientLight[2] += tr.identityLight * 32;
+ }
+
+ //
+ // modify the light by dynamic lights
+ //
+ d = VectorLength( ent->directedLight );
+ VectorScale( ent->lightDir, d, lightDir );
+
+ for ( i = 0 ; i < refdef->num_dlights ; i++ ) {
+ dl = &refdef->dlights[i];
+ VectorSubtract( dl->origin, lightOrigin, dir );
+ d = VectorNormalize( dir );
+
+ power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius );
+ if ( d < DLIGHT_MINIMUM_RADIUS ) {
+ d = DLIGHT_MINIMUM_RADIUS;
+ }
+ d = power / ( d * d );
+
+ VectorMA( ent->directedLight, d, dl->color, ent->directedLight );
+ VectorMA( lightDir, d, dir, lightDir );
+ }
+
+ // clamp lights
+ // FIXME: old renderer clamps (ambient + NL * directed) per vertex
+ // check if that's worth implementing
+ {
+ float r, g, b, max;
+
+ r = ent->ambientLight[0];
+ g = ent->ambientLight[1];
+ b = ent->ambientLight[2];
+
+ max = MAX(MAX(r, g), b);
+
+ if (max > 255.0f)
+ {
+ max = 255.0f / max;
+ ent->ambientLight[0] *= max;
+ ent->ambientLight[1] *= max;
+ ent->ambientLight[2] *= max;
+ }
+
+ r = ent->directedLight[0];
+ g = ent->directedLight[1];
+ b = ent->directedLight[2];
+
+ max = MAX(MAX(r, g), b);
+
+ if (max > 255.0f)
+ {
+ max = 255.0f / max;
+ ent->directedLight[0] *= max;
+ ent->directedLight[1] *= max;
+ ent->directedLight[2] *= max;
+ }
+ }
+
+
+ if ( r_debugLight->integer ) {
+ LogLight( ent );
+ }
+
+ // save out the byte packet version
+ ((byte *)&ent->ambientLightInt)[0] = static_cast<int>(ent->ambientLight[0]);
+ ((byte *)&ent->ambientLightInt)[1] = static_cast<int>(ent->ambientLight[1]);
+ ((byte *)&ent->ambientLightInt)[2] = static_cast<int>(ent->ambientLight[2]);
+ ((byte *)&ent->ambientLightInt)[3] = 0xff;
+
+ // transform the direction to local space
+ VectorNormalize( lightDir );
+ ent->modelLightDir[0] = DotProduct( lightDir, ent->e.axis[0] );
+ ent->modelLightDir[1] = DotProduct( lightDir, ent->e.axis[1] );
+ ent->modelLightDir[2] = DotProduct( lightDir, ent->e.axis[2] );
+
+ VectorCopy(lightDir, ent->lightDir);
+}
+
+/*
+=================
+R_LightForPoint
+=================
+*/
+bool R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir )
+{
+ trRefEntity_t ent;
+
+ if ( tr.world->lightGridData == NULL )
+ return false;
+
+ Com_Memset(&ent, 0, sizeof(ent));
+ VectorCopy( point, ent.e.origin );
+ R_SetupEntityLightingGrid( &ent, tr.world );
+ VectorCopy(ent.ambientLight, ambientLight);
+ VectorCopy(ent.directedLight, directedLight);
+ VectorCopy(ent.lightDir, lightDir);
+
+ return true;
+}
+
+
+bool R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *world )
+{
+ trRefEntity_t ent;
+
+ if ( world->lightGridData == NULL )
+ return false;
+
+ Com_Memset(&ent, 0, sizeof(ent));
+ VectorCopy( point, ent.e.origin );
+ R_SetupEntityLightingGrid( &ent, world );
+
+ if (DotProduct(ent.lightDir, normal) > 0.2f)
+ VectorCopy(ent.lightDir, lightDir);
+ else
+ VectorCopy(normal, lightDir);
+
+ return true;
+}
+
+
+int R_CubemapForPoint( vec3_t point )
+{
+ int cubemapIndex = -1;
+
+ if (r_cubeMapping->integer && tr.numCubemaps)
+ {
+ int i;
+ vec_t shortest = (float)WORLD_SIZE * (float)WORLD_SIZE;
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ vec3_t diff;
+ vec_t length;
+
+ VectorSubtract(point, tr.cubemaps[i].origin, diff);
+ length = DotProduct(diff, diff);
+
+ if (shortest > length)
+ {
+ shortest = length;
+ cubemapIndex = i;
+ }
+ }
+ }
+
+ return cubemapIndex + 1;
+}
diff --git a/src/renderergl2/tr_local.h b/src/renderergl2/tr_local.h
new file mode 100644
index 0000000..39df925
--- /dev/null
+++ b/src/renderergl2/tr_local.h
@@ -0,0 +1,2422 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+
+#ifndef TR_LOCAL_H
+#define TR_LOCAL_H
+
+#include <stdbool.h>
+
+#include "qcommon/cvar.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/qfiles.h"
+#include "qcommon/qcommon.h"
+#include "renderercommon/tr_public.h"
+#include "renderercommon/tr_common.h"
+#include "tr_extratypes.h"
+#include "tr_extramath.h"
+#include "tr_fbo.h"
+#include "tr_postprocess.h"
+#include "renderercommon/iqm.h"
+
+#define GL_INDEX_TYPE GL_UNSIGNED_INT
+typedef unsigned int glIndex_t;
+
+#define BUFFER_OFFSET(i) ((char *)NULL + (i))
+
+// 14 bits
+// can't be increased without changing bit packing for drawsurfs
+// see QSORT_SHADERNUM_SHIFT
+#define SHADERNUM_BITS 14
+#define MAX_SHADERS (1<<SHADERNUM_BITS)
+
+#define MAX_FBOS 64
+#define MAX_VISCOUNTS 5
+#define MAX_VAOS 4096
+
+#define MAX_CALC_PSHADOWS 64
+#define MAX_DRAWN_PSHADOWS 16 // do not increase past 32, because bit flags are used on surfaces
+#define PSHADOW_MAP_SIZE 512
+
+typedef struct cubemap_s {
+ char name[MAX_QPATH];
+ vec3_t origin;
+ float parallaxRadius;
+ image_t *image;
+} cubemap_t;
+
+typedef struct dlight_s {
+ vec3_t origin;
+ vec3_t color; // range from 0.0 to 1.0, should be color normalized
+ float radius;
+
+ vec3_t transformed; // origin in local coordinate system
+ int additive; // texture detail is lost tho when the lightmap is dark
+} dlight_t;
+
+
+// a trRefEntity_t has all the information passed in by
+// the client game, as well as some locally derived info
+typedef struct {
+ refEntity_t e;
+
+ float axisLength; // compensate for non-normalized axis
+
+ bool needDlights; // true for bmodels that touch a dlight
+ bool lightingCalculated;
+ bool mirrored; // mirrored matrix, needs reversed culling
+ vec3_t lightDir; // normalized direction towards light, in world space
+ vec3_t modelLightDir; // normalized direction towards light, in model space
+ vec3_t ambientLight; // color normalized to 0-255
+ int ambientLightInt; // 32 bit rgba packed
+ vec3_t directedLight;
+} trRefEntity_t;
+
+
+typedef struct {
+ vec3_t origin; // in world coordinates
+ vec3_t axis[3]; // orientation in world
+ vec3_t viewOrigin; // viewParms->or.origin in local coordinates
+ float modelMatrix[16];
+ float transformMatrix[16];
+} orientationr_t;
+
+// Ensure this is >= the ATTR_INDEX_COUNT enum below
+#define VAO_MAX_ATTRIBS 16
+
+typedef enum
+{
+ VAO_USAGE_STATIC,
+ VAO_USAGE_DYNAMIC
+} vaoUsage_t;
+
+typedef struct vaoAttrib_s
+{
+ uint32_t enabled;
+ uint32_t count;
+ uint32_t type;
+ uint32_t normalized;
+ uint32_t stride;
+ uint32_t offset;
+}
+vaoAttrib_t;
+
+typedef struct vao_s
+{
+ char name[MAX_QPATH];
+
+ uint32_t vao;
+
+ uint32_t vertexesVBO;
+ int vertexesSize; // amount of memory data allocated for all vertices in bytes
+ vaoAttrib_t attribs[VAO_MAX_ATTRIBS];
+
+ uint32_t frameSize; // bytes to skip per frame when doing vertex animation
+
+ uint32_t indexesIBO;
+ int indexesSize; // amount of memory data allocated for all triangles in bytes
+} vao_t;
+
+//===============================================================================
+
+typedef enum {
+ SS_BAD,
+ SS_PORTAL, // mirrors, portals, viewscreens
+ SS_ENVIRONMENT, // sky box
+ SS_OPAQUE, // opaque
+
+ SS_DECAL, // scorch marks, etc.
+ SS_SEE_THROUGH, // ladders, grates, grills that may have small blended edges
+ // in addition to alpha test
+ SS_BANNER,
+
+ SS_FOG,
+
+ SS_UNDERWATER, // for items that should be drawn in front of the water plane
+
+ SS_BLEND0, // regular transparency and filters
+ SS_BLEND1, // generally only used for additive type effects
+ SS_BLEND2,
+ SS_BLEND3,
+
+ SS_BLEND6,
+ SS_STENCIL_SHADOW,
+ SS_ALMOST_NEAREST, // gun smoke puffs
+
+ SS_NEAREST // blood blobs
+} shaderSort_t;
+
+
+#define MAX_SHADER_STAGES 8
+
+typedef enum {
+ GF_NONE,
+
+ GF_SIN,
+ GF_SQUARE,
+ GF_TRIANGLE,
+ GF_SAWTOOTH,
+ GF_INVERSE_SAWTOOTH,
+
+ GF_NOISE
+
+} genFunc_t;
+
+
+typedef enum {
+ DEFORM_NONE,
+ DEFORM_WAVE,
+ DEFORM_NORMALS,
+ DEFORM_BULGE,
+ DEFORM_MOVE,
+ DEFORM_PROJECTION_SHADOW,
+ DEFORM_AUTOSPRITE,
+ DEFORM_AUTOSPRITE2,
+ DEFORM_TEXT0,
+ DEFORM_TEXT1,
+ DEFORM_TEXT2,
+ DEFORM_TEXT3,
+ DEFORM_TEXT4,
+ DEFORM_TEXT5,
+ DEFORM_TEXT6,
+ DEFORM_TEXT7
+} deform_t;
+
+// deformVertexes types that can be handled by the GPU
+typedef enum
+{
+ // do not edit: same as genFunc_t
+
+ DGEN_NONE,
+ DGEN_WAVE_SIN,
+ DGEN_WAVE_SQUARE,
+ DGEN_WAVE_TRIANGLE,
+ DGEN_WAVE_SAWTOOTH,
+ DGEN_WAVE_INVERSE_SAWTOOTH,
+ DGEN_WAVE_NOISE,
+
+ // do not edit until this line
+
+ DGEN_BULGE,
+ DGEN_MOVE
+} deformGen_t;
+
+typedef enum {
+ AGEN_IDENTITY,
+ AGEN_SKIP,
+ AGEN_ENTITY,
+ AGEN_ONE_MINUS_ENTITY,
+ AGEN_VERTEX,
+ AGEN_ONE_MINUS_VERTEX,
+ AGEN_LIGHTING_SPECULAR,
+ AGEN_WAVEFORM,
+ AGEN_PORTAL,
+ AGEN_CONST,
+} alphaGen_t;
+
+typedef enum {
+ CGEN_BAD,
+ CGEN_IDENTITY_LIGHTING, // tr.identityLight
+ CGEN_IDENTITY, // always (1,1,1,1)
+ CGEN_ENTITY, // grabbed from entity's modulate field
+ CGEN_ONE_MINUS_ENTITY, // grabbed from 1 - entity.modulate
+ CGEN_EXACT_VERTEX, // tess.vertexColors
+ CGEN_VERTEX, // tess.vertexColors * tr.identityLight
+ CGEN_EXACT_VERTEX_LIT, // like CGEN_EXACT_VERTEX but takes a light direction from the lightgrid
+ CGEN_VERTEX_LIT, // like CGEN_VERTEX but takes a light direction from the lightgrid
+ CGEN_ONE_MINUS_VERTEX,
+ CGEN_WAVEFORM, // programmatically generated
+ CGEN_LIGHTING_DIFFUSE,
+ CGEN_FOG, // standard fog
+ CGEN_CONST // fixed color
+} colorGen_t;
+
+typedef enum {
+ TCGEN_BAD,
+ TCGEN_IDENTITY, // clear to 0,0
+ TCGEN_LIGHTMAP,
+ TCGEN_TEXTURE,
+ TCGEN_ENVIRONMENT_MAPPED,
+ TCGEN_FOG,
+ TCGEN_VECTOR // S and T from world coordinates
+} texCoordGen_t;
+
+typedef enum {
+ ACFF_NONE,
+ ACFF_MODULATE_RGB,
+ ACFF_MODULATE_RGBA,
+ ACFF_MODULATE_ALPHA
+} acff_t;
+
+typedef struct {
+ genFunc_t func;
+
+ float base;
+ float amplitude;
+ float phase;
+ float frequency;
+} waveForm_t;
+
+#define TR_MAX_TEXMODS 4
+
+typedef enum {
+ TMOD_NONE,
+ TMOD_TRANSFORM,
+ TMOD_TURBULENT,
+ TMOD_SCROLL,
+ TMOD_SCALE,
+ TMOD_STRETCH,
+ TMOD_ROTATE,
+ TMOD_ENTITY_TRANSLATE
+} texMod_t;
+
+#define MAX_SHADER_DEFORMS 3
+typedef struct {
+ deform_t deformation; // vertex coordinate modification type
+
+ vec3_t moveVector;
+ waveForm_t deformationWave;
+ float deformationSpread;
+
+ float bulgeWidth;
+ float bulgeHeight;
+ float bulgeSpeed;
+} deformStage_t;
+
+
+typedef struct {
+ texMod_t type;
+
+ // used for TMOD_TURBULENT and TMOD_STRETCH
+ waveForm_t wave;
+
+ // used for TMOD_TRANSFORM
+ float matrix[2][2]; // s' = s * m[0][0] + t * m[1][0] + trans[0]
+ float translate[2]; // t' = s * m[0][1] + t * m[0][1] + trans[1]
+
+ // used for TMOD_SCALE
+ float scale[2]; // s *= scale[0]
+ // t *= scale[1]
+
+ // used for TMOD_SCROLL
+ float scroll[2]; // s' = s + scroll[0] * time
+ // t' = t + scroll[1] * time
+
+ // + = clockwise
+ // - = counterclockwise
+ float rotateSpeed;
+
+} texModInfo_t;
+
+
+#define MAX_IMAGE_ANIMATIONS 8
+
+typedef struct {
+ image_t *image[MAX_IMAGE_ANIMATIONS];
+ int numImageAnimations;
+ float imageAnimationSpeed;
+
+ texCoordGen_t tcGen;
+ vec3_t tcGenVectors[2];
+
+ int numTexMods;
+ texModInfo_t *texMods;
+
+ int videoMapHandle;
+ bool isLightmap;
+ bool isVideoMap;
+} textureBundle_t;
+
+enum
+{
+ TB_COLORMAP = 0,
+ TB_DIFFUSEMAP = 0,
+ TB_LIGHTMAP = 1,
+ TB_LEVELSMAP = 1,
+ TB_SHADOWMAP3 = 1,
+ TB_NORMALMAP = 2,
+ TB_DELUXEMAP = 3,
+ TB_SHADOWMAP2 = 3,
+ TB_SPECULARMAP = 4,
+ TB_SHADOWMAP = 5,
+ TB_CUBEMAP = 6,
+ TB_SHADOWMAP4 = 6,
+ NUM_TEXTURE_BUNDLES = 7
+};
+
+typedef enum
+{
+ // material shader stage types
+ ST_COLORMAP = 0, // vanilla Q3A style shader treatening
+ ST_DIFFUSEMAP = 0, // treat color and diffusemap the same
+ ST_NORMALMAP,
+ ST_NORMALPARALLAXMAP,
+ ST_SPECULARMAP,
+ ST_GLSL
+} stageType_t;
+
+typedef struct {
+ bool active;
+
+ textureBundle_t bundle[NUM_TEXTURE_BUNDLES];
+
+ waveForm_t rgbWave;
+ colorGen_t rgbGen;
+
+ waveForm_t alphaWave;
+ alphaGen_t alphaGen;
+
+ byte constantColor[4]; // for CGEN_CONST and AGEN_CONST
+
+ unsigned stateBits; // GLS_xxxx mask
+
+ acff_t adjustColorsForFog;
+
+ bool isDetail;
+
+ stageType_t type;
+ struct shaderProgram_s *glslShaderGroup;
+ int glslShaderIndex;
+
+ vec4_t normalScale;
+ vec4_t specularScale;
+
+} shaderStage_t;
+
+struct shaderCommands_s;
+
+typedef enum {
+ CT_FRONT_SIDED,
+ CT_BACK_SIDED,
+ CT_TWO_SIDED
+} cullType_t;
+
+typedef enum {
+ FP_NONE, // surface is translucent and will just be adjusted properly
+ FP_EQUAL, // surface is opaque but possibly alpha tested
+ FP_LE // surface is trnaslucent, but still needs a fog pass (fog surface)
+} fogPass_t;
+
+typedef struct {
+ float cloudHeight;
+ image_t *outerbox[6], *innerbox[6];
+} skyParms_t;
+
+typedef struct {
+ vec3_t color;
+ float depthForOpaque;
+} fogParms_t;
+
+
+typedef struct shader_s {
+ char name[MAX_QPATH]; // game path, including extension
+ int lightmapIndex; // for a shader to match, both name and lightmapIndex must match
+
+ int index; // this shader == tr.shaders[index]
+ int sortedIndex; // this shader == tr.sortedShaders[sortedIndex]
+
+ float sort; // lower numbered shaders draw before higher numbered
+
+ bool defaultShader; // we want to return index 0 if the shader failed to
+ // load for some reason, but R_FindShader should
+ // still keep a name allocated for it, so if
+ // something calls RE_RegisterShader again with
+ // the same name, we don't try looking for it again
+
+ bool explicitlyDefined; // found in a .shader file
+
+ int surfaceFlags; // if explicitlyDefined, this will have SURF_* flags
+ int contentFlags;
+
+ bool entityMergable; // merge across entites optimizable (smoke, blood)
+
+ bool isSky;
+ skyParms_t sky;
+ fogParms_t fogParms;
+
+ float portalRange; // distance to fog out at
+ bool isPortal;
+
+ cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED
+ bool polygonOffset; // set for decals and other items that must be offset
+ bool noMipMaps; // for console fonts, 2D elements, etc.
+ bool noPicMip; // for images that must always be full resolution
+
+ fogPass_t fogPass; // draw a blended pass, possibly with depth test equals
+
+ int vertexAttribs; // not all shaders will need all data to be gathered
+
+ int numDeforms;
+ deformStage_t deforms[MAX_SHADER_DEFORMS];
+
+ int numUnfoggedPasses;
+ shaderStage_t *stages[MAX_SHADER_STAGES];
+
+ void (*optimalStageIteratorFunc)( void );
+
+ double clampTime; // time this shader is clamped to
+ double timeOffset; // current time offset for this shader
+
+ struct shader_s *remappedShader; // current shader this one is remapped too
+
+ struct shader_s *next;
+} shader_t;
+
+bool ShaderRequiresCPUDeforms(const shader_t*);
+
+enum
+{
+ ATTR_INDEX_POSITION = 0,
+ ATTR_INDEX_TEXCOORD = 1,
+ ATTR_INDEX_LIGHTCOORD = 2,
+ ATTR_INDEX_TANGENT = 3,
+ ATTR_INDEX_NORMAL = 4,
+ ATTR_INDEX_COLOR = 5,
+ ATTR_INDEX_PAINTCOLOR = 6,
+ ATTR_INDEX_LIGHTDIRECTION = 7,
+ ATTR_INDEX_BONE_INDEXES = 8,
+ ATTR_INDEX_BONE_WEIGHTS = 9,
+
+ // GPU vertex animations
+ ATTR_INDEX_POSITION2 = 10,
+ ATTR_INDEX_TANGENT2 = 11,
+ ATTR_INDEX_NORMAL2 = 12,
+
+ ATTR_INDEX_COUNT = 13
+};
+
+enum
+{
+ ATTR_POSITION = 1 << ATTR_INDEX_POSITION,
+ ATTR_TEXCOORD = 1 << ATTR_INDEX_TEXCOORD,
+ ATTR_LIGHTCOORD = 1 << ATTR_INDEX_LIGHTCOORD,
+ ATTR_TANGENT = 1 << ATTR_INDEX_TANGENT,
+ ATTR_NORMAL = 1 << ATTR_INDEX_NORMAL,
+ ATTR_COLOR = 1 << ATTR_INDEX_COLOR,
+ ATTR_PAINTCOLOR = 1 << ATTR_INDEX_PAINTCOLOR,
+ ATTR_LIGHTDIRECTION = 1 << ATTR_INDEX_LIGHTDIRECTION,
+ ATTR_BONE_INDEXES = 1 << ATTR_INDEX_BONE_INDEXES,
+ ATTR_BONE_WEIGHTS = 1 << ATTR_INDEX_BONE_WEIGHTS,
+
+ // for .md3 interpolation
+ ATTR_POSITION2 = 1 << ATTR_INDEX_POSITION2,
+ ATTR_TANGENT2 = 1 << ATTR_INDEX_TANGENT2,
+ ATTR_NORMAL2 = 1 << ATTR_INDEX_NORMAL2,
+
+ ATTR_DEFAULT = ATTR_POSITION,
+ ATTR_BITS = ATTR_POSITION |
+ ATTR_TEXCOORD |
+ ATTR_LIGHTCOORD |
+ ATTR_TANGENT |
+ ATTR_NORMAL |
+ ATTR_COLOR |
+ ATTR_PAINTCOLOR |
+ ATTR_LIGHTDIRECTION |
+ ATTR_BONE_INDEXES |
+ ATTR_BONE_WEIGHTS |
+ ATTR_POSITION2 |
+ ATTR_TANGENT2 |
+ ATTR_NORMAL2
+};
+
+enum
+{
+ GENERICDEF_USE_DEFORM_VERTEXES = 0x0001,
+ GENERICDEF_USE_TCGEN_AND_TCMOD = 0x0002,
+ GENERICDEF_USE_VERTEX_ANIMATION = 0x0004,
+ GENERICDEF_USE_FOG = 0x0008,
+ GENERICDEF_USE_RGBAGEN = 0x0010,
+ GENERICDEF_ALL = 0x001F,
+ GENERICDEF_COUNT = 0x0020,
+};
+
+enum
+{
+ FOGDEF_USE_DEFORM_VERTEXES = 0x0001,
+ FOGDEF_USE_VERTEX_ANIMATION = 0x0002,
+ FOGDEF_ALL = 0x0003,
+ FOGDEF_COUNT = 0x0004,
+};
+
+enum
+{
+ DLIGHTDEF_USE_DEFORM_VERTEXES = 0x0001,
+ DLIGHTDEF_ALL = 0x0001,
+ DLIGHTDEF_COUNT = 0x0002,
+};
+
+enum
+{
+ LIGHTDEF_USE_LIGHTMAP = 0x0001,
+ LIGHTDEF_USE_LIGHT_VECTOR = 0x0002,
+ LIGHTDEF_USE_LIGHT_VERTEX = 0x0003,
+ LIGHTDEF_LIGHTTYPE_MASK = 0x0003,
+ LIGHTDEF_ENTITY = 0x0004,
+ LIGHTDEF_USE_TCGEN_AND_TCMOD = 0x0008,
+ LIGHTDEF_USE_PARALLAXMAP = 0x0010,
+ LIGHTDEF_USE_SHADOWMAP = 0x0020,
+ LIGHTDEF_ALL = 0x003F,
+ LIGHTDEF_COUNT = 0x0040
+};
+
+enum
+{
+ GLSL_INT,
+ GLSL_FLOAT,
+ GLSL_FLOAT5,
+ GLSL_VEC2,
+ GLSL_VEC3,
+ GLSL_VEC4,
+ GLSL_MAT16
+};
+
+typedef enum
+{
+ UNIFORM_DIFFUSEMAP = 0,
+ UNIFORM_LIGHTMAP,
+ UNIFORM_NORMALMAP,
+ UNIFORM_DELUXEMAP,
+ UNIFORM_SPECULARMAP,
+
+ UNIFORM_TEXTUREMAP,
+ UNIFORM_LEVELSMAP,
+ UNIFORM_CUBEMAP,
+
+ UNIFORM_SCREENIMAGEMAP,
+ UNIFORM_SCREENDEPTHMAP,
+
+ UNIFORM_SHADOWMAP,
+ UNIFORM_SHADOWMAP2,
+ UNIFORM_SHADOWMAP3,
+ UNIFORM_SHADOWMAP4,
+
+ UNIFORM_SHADOWMVP,
+ UNIFORM_SHADOWMVP2,
+ UNIFORM_SHADOWMVP3,
+ UNIFORM_SHADOWMVP4,
+
+ UNIFORM_ENABLETEXTURES,
+
+ UNIFORM_DIFFUSETEXMATRIX,
+ UNIFORM_DIFFUSETEXOFFTURB,
+
+ UNIFORM_TCGEN0,
+ UNIFORM_TCGEN0VECTOR0,
+ UNIFORM_TCGEN0VECTOR1,
+
+ UNIFORM_DEFORMGEN,
+ UNIFORM_DEFORMPARAMS,
+
+ UNIFORM_COLORGEN,
+ UNIFORM_ALPHAGEN,
+ UNIFORM_COLOR,
+ UNIFORM_BASECOLOR,
+ UNIFORM_VERTCOLOR,
+
+ UNIFORM_DLIGHTINFO,
+ UNIFORM_LIGHTFORWARD,
+ UNIFORM_LIGHTUP,
+ UNIFORM_LIGHTRIGHT,
+ UNIFORM_LIGHTORIGIN,
+ UNIFORM_MODELLIGHTDIR,
+ UNIFORM_LIGHTRADIUS,
+ UNIFORM_AMBIENTLIGHT,
+ UNIFORM_DIRECTEDLIGHT,
+
+ UNIFORM_PORTALRANGE,
+
+ UNIFORM_FOGDISTANCE,
+ UNIFORM_FOGDEPTH,
+ UNIFORM_FOGEYET,
+ UNIFORM_FOGCOLORMASK,
+
+ UNIFORM_MODELMATRIX,
+ UNIFORM_MODELVIEWPROJECTIONMATRIX,
+
+ UNIFORM_TIME,
+ UNIFORM_VERTEXLERP,
+ UNIFORM_NORMALSCALE,
+ UNIFORM_SPECULARSCALE,
+
+ UNIFORM_VIEWINFO, // znear, zfar, width/2, height/2
+ UNIFORM_VIEWORIGIN,
+ UNIFORM_LOCALVIEWORIGIN,
+ UNIFORM_VIEWFORWARD,
+ UNIFORM_VIEWLEFT,
+ UNIFORM_VIEWUP,
+
+ UNIFORM_INVTEXRES,
+ UNIFORM_AUTOEXPOSUREMINMAX,
+ UNIFORM_TONEMINAVGMAXLINEAR,
+
+ UNIFORM_PRIMARYLIGHTORIGIN,
+ UNIFORM_PRIMARYLIGHTCOLOR,
+ UNIFORM_PRIMARYLIGHTAMBIENT,
+ UNIFORM_PRIMARYLIGHTRADIUS,
+
+ UNIFORM_CUBEMAPINFO,
+
+ UNIFORM_ALPHATEST,
+
+ UNIFORM_COUNT
+} uniform_t;
+
+// shaderProgram_t represents a pair of one
+// GLSL vertex and one GLSL fragment shader
+typedef struct shaderProgram_s
+{
+ char name[MAX_QPATH];
+
+ GLuint program;
+ GLuint vertexShader;
+ GLuint fragmentShader;
+ uint32_t attribs; // vertex array attributes
+
+ // uniform parameters
+ GLint uniforms[UNIFORM_COUNT];
+ short uniformBufferOffsets[UNIFORM_COUNT]; // max 32767/64=511 uniforms
+ char *uniformBuffer;
+} shaderProgram_t;
+
+// trRefdef_t holds everything that comes in refdef_t,
+// as well as the locally generated scene information
+typedef struct {
+ int x, y, width, height;
+ float fov_x, fov_y;
+ vec3_t vieworg;
+ vec3_t viewaxis[3]; // transformation matrix
+
+ stereoFrame_t stereoFrame;
+
+ int time; // time in milliseconds for shader effects and other time dependent rendering issues
+ int rdflags; // RDF_NOWORLDMODEL, etc
+
+ // 1 bits will prevent the associated area from rendering at all
+ byte areamask[MAX_MAP_AREA_BYTES];
+ bool areamaskModified; // true if areamask changed since last scene
+
+ double floatTime; // tr.refdef.time / 1000.0
+
+ float blurFactor;
+
+ // text messages for deform text shaders
+ char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];
+
+ int num_entities;
+ trRefEntity_t *entities;
+
+ int num_dlights;
+ struct dlight_s *dlights;
+
+ int numPolys;
+ struct srfPoly_s *polys;
+
+ int numDrawSurfs;
+ struct drawSurf_s *drawSurfs;
+
+ unsigned int dlightMask;
+ int num_pshadows;
+ struct pshadow_s *pshadows;
+
+ float sunShadowMvp[4][16];
+ float sunDir[4];
+ float sunCol[4];
+ float sunAmbCol[4];
+
+ float autoExposureMinMax[2];
+ float toneMinAvgMaxLinear[3];
+} trRefdef_t;
+
+
+//=================================================================================
+
+// max surfaces per-skin
+// This is an arbitry limit. Vanilla Q3 only supported 32 surfaces in skins but failed to
+// enforce the maximum limit when reading skin files. It was possile to use more than 32
+// surfaces which accessed out of bounds memory past end of skin->surfaces hunk block.
+#define MAX_SKIN_SURFACES 256
+
+// skins allow models to be retextured without modifying the model file
+typedef struct {
+ char name[MAX_QPATH];
+ shader_t *shader;
+} skinSurface_t;
+
+typedef struct skin_s {
+ char name[MAX_QPATH]; // game path, including extension
+ int numSurfaces;
+ skinSurface_t *surfaces; // dynamically allocated array of surfaces
+} skin_t;
+
+
+typedef struct {
+ int originalBrushNumber;
+ vec3_t bounds[2];
+
+ unsigned colorInt; // in packed byte format
+ float tcScale; // texture coordinate vector scales
+ fogParms_t parms;
+
+ // for clipping distance in fog when outside
+ bool hasSurface;
+ float surface[4];
+} fog_t;
+
+typedef enum {
+ VPF_NONE = 0x00,
+ VPF_NOVIEWMODEL = 0x01,
+ VPF_SHADOWMAP = 0x02,
+ VPF_DEPTHSHADOW = 0x04,
+ VPF_DEPTHCLAMP = 0x08,
+ VPF_ORTHOGRAPHIC = 0x10,
+ VPF_USESUNLIGHT = 0x20,
+ VPF_FARPLANEFRUSTUM = 0x40,
+ VPF_NOCUBEMAPS = 0x80
+} viewParmFlags_t;
+
+typedef struct {
+ orientationr_t orientation;
+ orientationr_t world;
+ vec3_t pvsOrigin; // may be different than or.origin for portals
+ bool isPortal; // true if this view is through a portal
+ bool isMirror; // the portal is a mirror, invert the face culling
+ int/*viewParmFlags_t*/ flags;
+ int frameSceneNum; // copied from tr.frameSceneNum
+ int frameCount; // copied from tr.frameCount
+ cplane_t portalPlane; // clip anything behind this if mirroring
+ int viewportX, viewportY, viewportWidth, viewportHeight;
+ FBO_t *targetFbo;
+ int targetFboLayer;
+ int targetFboCubemapIndex;
+ float fovX, fovY;
+ float projectionMatrix[16];
+ cplane_t frustum[5];
+ vec3_t visBounds[2];
+ float zFar;
+ float zNear;
+ stereoFrame_t stereoFrame;
+} viewParms_t;
+
+
+/*
+==============================================================================
+
+SURFACES
+
+==============================================================================
+*/
+typedef byte color4ub_t[4];
+
+// any changes in surfaceType must be mirrored in rb_surfaceTable[]
+typedef enum {
+ SF_BAD,
+ SF_SKIP, // ignore
+ SF_FACE,
+ SF_GRID,
+ SF_TRIANGLES,
+ SF_POLY,
+ SF_MDV,
+ SF_MDR,
+ SF_IQM,
+ SF_FLARE,
+ SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
+ SF_VAO_MDVMESH,
+
+ SF_NUM_SURFACE_TYPES,
+ SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
+} surfaceType_t;
+
+typedef struct drawSurf_s {
+ unsigned int sort; // bit combination for fast compares
+ int cubemapIndex;
+ surfaceType_t *surface; // any of surface*_t
+} drawSurf_t;
+
+#define MAX_FACE_POINTS 64
+
+#define MAX_PATCH_SIZE 32 // max dimensions of a patch mesh in map file
+#define MAX_GRID_SIZE 65 // max dimensions of a grid mesh in memory
+
+// when cgame directly specifies a polygon, it becomes a srfPoly_t
+// as soon as it is called
+typedef struct srfPoly_s {
+ surfaceType_t surfaceType;
+ qhandle_t hShader;
+ int fogIndex;
+ int numVerts;
+ polyVert_t *verts;
+} srfPoly_t;
+
+
+typedef struct srfFlare_s {
+ surfaceType_t surfaceType;
+ vec3_t origin;
+ vec3_t normal;
+ vec3_t color;
+} srfFlare_t;
+
+typedef struct
+{
+ vec3_t xyz;
+ vec2_t st;
+ vec2_t lightmap;
+ int16_t normal[4];
+ int16_t tangent[4];
+ int16_t lightdir[4];
+ uint16_t color[4];
+
+#if DEBUG_OPTIMIZEVERTICES
+ unsigned int id;
+#endif
+} srfVert_t;
+
+#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}
+
+// srfBspSurface_t covers SF_GRID, SF_TRIANGLES and SF_POLY
+typedef struct srfBspSurface_s
+{
+ surfaceType_t surfaceType;
+
+ // dynamic lighting information
+ int dlightBits;
+ int pshadowBits;
+
+ // culling information
+ vec3_t cullBounds[2];
+ vec3_t cullOrigin;
+ float cullRadius;
+ cplane_t cullPlane;
+
+ // indexes
+ int numIndexes;
+ glIndex_t *indexes;
+
+ // vertexes
+ int numVerts;
+ srfVert_t *verts;
+
+ // SF_GRID specific variables after here
+
+ // lod information, which may be different
+ // than the culling information to allow for
+ // groups of curves that LOD as a unit
+ vec3_t lodOrigin;
+ float lodRadius;
+ int lodFixed;
+ int lodStitched;
+
+ // vertexes
+ int width, height;
+ float *widthLodError;
+ float *heightLodError;
+} srfBspSurface_t;
+
+// inter-quake-model
+typedef struct {
+ int num_vertexes;
+ int num_triangles;
+ int num_frames;
+ int num_surfaces;
+ int num_joints;
+ int num_poses;
+ struct srfIQModel_s *surfaces;
+
+ float *positions;
+ float *texcoords;
+ float *normals;
+ float *tangents;
+ byte *blendIndexes;
+ union {
+ float *f;
+ byte *b;
+ } blendWeights;
+ byte *colors;
+ int *triangles;
+
+ // depending upon the exporter, blend indices and weights might be int/float
+ // as opposed to the recommended byte/byte, for example Noesis exports
+ // int/float whereas the official IQM tool exports byte/byte
+ byte blendWeightsType; // IQM_UBYTE or IQM_FLOAT
+
+ int *jointParents;
+ float *jointMats;
+ float *poseMats;
+ float *bounds;
+ char *names;
+} iqmData_t;
+
+// inter-quake-model surface
+typedef struct srfIQModel_s {
+ surfaceType_t surfaceType;
+ char name[MAX_QPATH];
+ shader_t *shader;
+ iqmData_t *data;
+ int first_vertex, num_vertexes;
+ int first_triangle, num_triangles;
+} srfIQModel_t;
+
+typedef struct srfVaoMdvMesh_s
+{
+ surfaceType_t surfaceType;
+
+ struct mdvModel_s *mdvModel;
+ struct mdvSurface_s *mdvSurface;
+
+ // backEnd stats
+ int numIndexes;
+ int numVerts;
+ glIndex_t minIndex;
+ glIndex_t maxIndex;
+
+ // static render data
+ vao_t *vao;
+} srfVaoMdvMesh_t;
+
+extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *);
+
+/*
+==============================================================================
+
+SHADOWS
+
+==============================================================================
+*/
+
+typedef struct pshadow_s
+{
+ float sort;
+
+ int numEntities;
+ int entityNums[8];
+ vec3_t entityOrigins[8];
+ float entityRadiuses[8];
+
+ float viewRadius;
+ vec3_t viewOrigin;
+
+ vec3_t lightViewAxis[3];
+ vec3_t lightOrigin;
+ float lightRadius;
+ cplane_t cullPlane;
+} pshadow_t;
+
+
+/*
+==============================================================================
+
+BRUSH MODELS
+
+==============================================================================
+*/
+
+
+//
+// in memory representation
+//
+
+#define SIDE_FRONT 0
+#define SIDE_BACK 1
+#define SIDE_ON 2
+
+#define CULLINFO_NONE 0
+#define CULLINFO_BOX 1
+#define CULLINFO_SPHERE 2
+#define CULLINFO_PLANE 4
+
+typedef struct cullinfo_s {
+ int type;
+ vec3_t bounds[2];
+ vec3_t localOrigin;
+ float radius;
+ cplane_t plane;
+} cullinfo_t;
+
+typedef struct msurface_s {
+ //int viewCount; // if == tr.viewCount, already added
+ struct shader_s *shader;
+ int fogIndex;
+ int cubemapIndex;
+ cullinfo_t cullinfo;
+
+ surfaceType_t *data; // any of srf*_t
+} msurface_t;
+
+
+#define CONTENTS_NODE -1
+typedef struct mnode_s {
+ // common with leaf and node
+ int contents; // -1 for nodes, to differentiate from leafs
+ int visCounts[MAX_VISCOUNTS]; // node needs to be traversed if current
+ vec3_t mins, maxs; // for bounding box culling
+ struct mnode_s *parent;
+
+ // node specific
+ cplane_t *plane;
+ struct mnode_s *children[2];
+
+ // leaf specific
+ int cluster;
+ int area;
+
+ int firstmarksurface;
+ int nummarksurfaces;
+} mnode_t;
+
+typedef struct {
+ vec3_t bounds[2]; // for culling
+ int firstSurface;
+ int numSurfaces;
+} bmodel_t;
+
+typedef struct {
+ char name[MAX_QPATH]; // ie: maps/tim_dm2.bsp
+ char baseName[MAX_QPATH]; // ie: tim_dm2
+
+ int dataSize;
+
+ int numShaders;
+ dshader_t *shaders;
+
+ int numBModels;
+ bmodel_t *bmodels;
+
+ int numplanes;
+ cplane_t *planes;
+
+ int numnodes; // includes leafs
+ int numDecisionNodes;
+ mnode_t *nodes;
+
+ int numWorldSurfaces;
+
+ int numsurfaces;
+ msurface_t *surfaces;
+ int *surfacesViewCount;
+ int *surfacesDlightBits;
+ int *surfacesPshadowBits;
+
+ int nummarksurfaces;
+ int *marksurfaces;
+
+ int numfogs;
+ fog_t *fogs;
+
+ vec3_t lightGridOrigin;
+ vec3_t lightGridSize;
+ vec3_t lightGridInverseSize;
+ int lightGridBounds[3];
+ byte *lightGridData;
+ uint16_t *lightGrid16;
+
+
+ int numClusters;
+ int clusterBytes;
+ const byte *vis; // may be passed in by CM_LoadMap to save space
+
+ char *entityString;
+ char *entityParsePoint;
+} world_t;
+
+
+/*
+==============================================================================
+MDV MODELS - meta format for vertex animation models like .md2, .md3, .mdc
+==============================================================================
+*/
+typedef struct
+{
+ float bounds[2][3];
+ float localOrigin[3];
+ float radius;
+} mdvFrame_t;
+
+typedef struct
+{
+ float origin[3];
+ float axis[3][3];
+} mdvTag_t;
+
+typedef struct
+{
+ char name[MAX_QPATH]; // tag name
+} mdvTagName_t;
+
+typedef struct
+{
+ vec3_t xyz;
+ int16_t normal[4];
+ int16_t tangent[4];
+} mdvVertex_t;
+
+typedef struct
+{
+ float st[2];
+} mdvSt_t;
+
+typedef struct mdvSurface_s
+{
+ surfaceType_t surfaceType;
+
+ char name[MAX_QPATH]; // polyset name
+
+ int numShaderIndexes;
+ int *shaderIndexes;
+
+ int numVerts;
+ mdvVertex_t *verts;
+ mdvSt_t *st;
+
+ int numIndexes;
+ glIndex_t *indexes;
+
+ struct mdvModel_s *model;
+} mdvSurface_t;
+
+typedef struct mdvModel_s
+{
+ int numFrames;
+ mdvFrame_t *frames;
+
+ int numTags;
+ mdvTag_t *tags;
+ mdvTagName_t *tagNames;
+
+ int numSurfaces;
+ mdvSurface_t *surfaces;
+
+ int numVaoSurfaces;
+ srfVaoMdvMesh_t *vaoSurfaces;
+
+ int numSkins;
+} mdvModel_t;
+
+
+//======================================================================
+
+typedef enum {
+ MOD_BAD,
+ MOD_BRUSH,
+ MOD_MESH,
+ MOD_MDR,
+ MOD_IQM
+} modtype_t;
+
+typedef struct model_s {
+ char name[MAX_QPATH];
+ modtype_t type;
+ int index; // model = tr.models[model->index]
+
+ int dataSize; // just for listing purposes
+ bmodel_t *bmodel; // only if type == MOD_BRUSH
+ mdvModel_t *mdv[MD3_MAX_LODS]; // only if type == MOD_MESH
+ void *modelData; // only if type == (MOD_MDR | MOD_IQM)
+
+ int numLods;
+} model_t;
+
+
+#define MAX_MOD_KNOWN 1024
+
+void R_ModelInit (void);
+model_t *R_GetModelByHandle( qhandle_t hModel );
+int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
+ float frac, const char *tagName );
+void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs );
+
+void R_Modellist_f (void);
+
+//====================================================
+
+#define MAX_DRAWIMAGES 2048
+#define MAX_SKINS 1024
+
+
+#define MAX_DRAWSURFS 0x10000
+#define DRAWSURF_MASK (MAX_DRAWSURFS-1)
+
+/*
+
+the drawsurf sort data is packed into a single 32 bit value so it can be
+compared quickly during the qsorting process
+
+the bits are allocated as follows:
+
+0 - 1 : dlightmap index
+//2 : used to be clipped flag REMOVED - 03.21.00 rad
+2 - 6 : fog index
+11 - 20 : entity index
+21 - 31 : sorted shader index
+
+ TTimo - 1.32
+0-1 : dlightmap index
+2-6 : fog index
+7-16 : entity index
+17-30 : sorted shader index
+
+ SmileTheory - for pshadows
+17-31 : sorted shader index
+7-16 : entity index
+2-6 : fog index
+1 : pshadow flag
+0 : dlight flag
+*/
+#define QSORT_FOGNUM_SHIFT 2
+#define QSORT_REFENTITYNUM_SHIFT 7
+#define QSORT_SHADERNUM_SHIFT (QSORT_REFENTITYNUM_SHIFT+REFENTITYNUM_BITS)
+#if (QSORT_SHADERNUM_SHIFT+SHADERNUM_BITS) > 32
+ #error "Need to update sorting, too many bits."
+#endif
+#define QSORT_PSHADOW_SHIFT 1
+
+extern int gl_filter_min, gl_filter_max;
+
+/*
+** performanceCounters_t
+*/
+typedef struct {
+ int c_sphere_cull_patch_in, c_sphere_cull_patch_clip, c_sphere_cull_patch_out;
+ int c_box_cull_patch_in, c_box_cull_patch_clip, c_box_cull_patch_out;
+ int c_sphere_cull_md3_in, c_sphere_cull_md3_clip, c_sphere_cull_md3_out;
+ int c_box_cull_md3_in, c_box_cull_md3_clip, c_box_cull_md3_out;
+
+ int c_leafs;
+ int c_dlightSurfaces;
+ int c_dlightSurfacesCulled;
+} frontEndCounters_t;
+
+#define FOG_TABLE_SIZE 256
+#define FUNCTABLE_SIZE 1024
+#define FUNCTABLE_SIZE2 10
+#define FUNCTABLE_MASK (FUNCTABLE_SIZE-1)
+
+
+// the renderer front end should never modify glstate_t
+typedef struct {
+ bool finishCalled;
+ int texEnv[2];
+ int faceCulling;
+ int faceCullFront;
+ uint32_t glStateBits;
+ uint32_t storedGlState;
+ float vertexAttribsInterpolation;
+ bool vertexAnimation;
+ uint32_t vertexAttribsEnabled; // global if no VAOs, tess only otherwise
+ FBO_t *currentFBO;
+ vao_t *currentVao;
+ mat4_t modelview;
+ mat4_t projection;
+ mat4_t modelviewProjection;
+} glstate_t;
+
+typedef enum {
+ MI_NONE,
+ MI_NVX,
+ MI_ATI
+} memInfo_t;
+
+typedef enum {
+ TCR_NONE = 0x0000,
+ TCR_RGTC = 0x0001,
+ TCR_BPTC = 0x0002,
+} textureCompressionRef_t;
+
+// We can't change glConfig_t without breaking DLL/vms compatibility, so
+// store extensions we have here.
+typedef struct {
+ int openglMajorVersion;
+ int openglMinorVersion;
+
+ bool intelGraphics;
+
+ bool occlusionQuery;
+
+ int glslMajorVersion;
+ int glslMinorVersion;
+
+ memInfo_t memInfo;
+
+ bool framebufferObject;
+ int maxRenderbufferSize;
+ int maxColorAttachments;
+
+ bool textureFloat;
+ int /*textureCompressionRef_t*/ textureCompression;
+ bool swizzleNormalmap;
+
+ bool framebufferMultisample;
+ bool framebufferBlit;
+
+ bool depthClamp;
+ bool seamlessCubeMap;
+
+ bool vertexArrayObject;
+ bool directStateAccess;
+} glRefConfig_t;
+
+
+typedef struct {
+ int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes;
+ int c_surfBatches;
+ float c_overDraw;
+
+ int c_vaoBinds;
+ int c_vaoVertexes;
+ int c_vaoIndexes;
+
+ int c_staticVaoDraws;
+ int c_dynamicVaoDraws;
+
+ int c_dlightVertexes;
+ int c_dlightIndexes;
+
+ int c_flareAdds;
+ int c_flareTests;
+ int c_flareRenders;
+
+ int c_glslShaderBinds;
+ int c_genericDraws;
+ int c_lightallDraws;
+ int c_fogDraws;
+ int c_dlightDraws;
+
+ int msec; // total msec for backend run
+} backEndCounters_t;
+
+// all state modified by the back end is seperated
+// from the front end state
+typedef struct {
+ trRefdef_t refdef;
+ viewParms_t viewParms;
+ orientationr_t orientation;
+ backEndCounters_t pc;
+ bool isHyperspace;
+ trRefEntity_t *currentEntity;
+ bool skyRenderedThisView; // flag for drawing sun
+
+ bool projection2D; // if true, drawstretchpic doesn't need to change modes
+ byte color2D[4];
+ bool vertexes2D; // shader needs to be finished
+ trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering
+
+ FBO_t *last2DFBO;
+ bool colorMask[4];
+ bool framePostProcessed;
+ bool depthFill;
+} backEndState_t;
+
+/*
+** trGlobals_t
+**
+** Most renderer globals are defined here.
+** backend functions should never modify any of these fields,
+** but may read fields that aren't dynamically modified
+** by the frontend.
+*/
+typedef struct {
+ bool registered; // cleared at shutdown, set at beginRegistration
+
+ int visIndex;
+ int visClusters[MAX_VISCOUNTS];
+ int visCounts[MAX_VISCOUNTS]; // incremented every time a new vis cluster is entered
+
+ int frameCount; // incremented every frame
+ int sceneCount; // incremented every scene
+ int viewCount; // incremented every view (twice a scene if portaled)
+ // and every R_MarkFragments call
+
+ int frameSceneNum; // zeroed at RE_BeginFrame
+
+ bool worldMapLoaded;
+ bool worldDeluxeMapping;
+ vec2_t autoExposureMinMax;
+ vec3_t toneMinAvgMaxLevel;
+ world_t *world;
+
+ const byte *externalVisData; // from RE_SetWorldVisData, shared with CM_Load
+
+ image_t *defaultImage;
+ image_t *scratchImage[32];
+ image_t *fogImage;
+ image_t *dlightImage; // inverse-quare highlight for projective adding
+ image_t *flareImage;
+ image_t *whiteImage; // full of 0xff
+ image_t *identityLightImage; // full of tr.identityLightByte
+
+ image_t *shadowCubemaps[MAX_DLIGHTS];
+
+
+ image_t *renderImage;
+ image_t *sunRaysImage;
+ image_t *renderDepthImage;
+ image_t *pshadowMaps[MAX_DRAWN_PSHADOWS];
+ image_t *screenScratchImage;
+ image_t *textureScratchImage[2];
+ image_t *quarterImage[2];
+ image_t *calcLevelsImage;
+ image_t *targetLevelsImage;
+ image_t *fixedLevelsImage;
+ image_t *sunShadowDepthImage[4];
+ image_t *screenShadowImage;
+ image_t *screenSsaoImage;
+ image_t *hdrDepthImage;
+ image_t *renderCubeImage;
+
+ image_t *textureDepthImage;
+
+ FBO_t *renderFbo;
+ FBO_t *msaaResolveFbo;
+ FBO_t *sunRaysFbo;
+ FBO_t *depthFbo;
+ FBO_t *pshadowFbos[MAX_DRAWN_PSHADOWS];
+ FBO_t *screenScratchFbo;
+ FBO_t *textureScratchFbo[2];
+ FBO_t *quarterFbo[2];
+ FBO_t *calcLevelsFbo;
+ FBO_t *targetLevelsFbo;
+ FBO_t *sunShadowFbo[4];
+ FBO_t *screenShadowFbo;
+ FBO_t *screenSsaoFbo;
+ FBO_t *hdrDepthFbo;
+ FBO_t *renderCubeFbo;
+
+ shader_t *defaultShader;
+ shader_t *shadowShader;
+ shader_t *projectionShadowShader;
+
+ shader_t *flareShader;
+ shader_t *sunShader;
+ shader_t *sunFlareShader;
+
+ int numLightmaps;
+ int lightmapSize;
+ image_t **lightmaps;
+ image_t **deluxemaps;
+
+ int fatLightmapCols;
+ int fatLightmapRows;
+
+ int numCubemaps;
+ cubemap_t *cubemaps;
+
+ trRefEntity_t *currentEntity;
+ trRefEntity_t worldEntity; // point currentEntity at this when rendering world
+ int currentEntityNum;
+ int shiftedEntityNum; // currentEntityNum << QSORT_REFENTITYNUM_SHIFT
+ model_t *currentModel;
+
+ //
+ // GPU shader programs
+ //
+ shaderProgram_t genericShader[GENERICDEF_COUNT];
+ shaderProgram_t textureColorShader;
+ shaderProgram_t fogShader[FOGDEF_COUNT];
+ shaderProgram_t dlightShader[DLIGHTDEF_COUNT];
+ shaderProgram_t lightallShader[LIGHTDEF_COUNT];
+ shaderProgram_t shadowmapShader;
+ shaderProgram_t pshadowShader;
+ shaderProgram_t down4xShader;
+ shaderProgram_t bokehShader;
+ shaderProgram_t tonemapShader;
+ shaderProgram_t calclevels4xShader[2];
+ shaderProgram_t shadowmaskShader;
+ shaderProgram_t ssaoShader;
+ shaderProgram_t depthBlurShader[4];
+ shaderProgram_t testcubeShader;
+
+
+ // -----------------------------------------
+
+ viewParms_t viewParms;
+
+ float identityLight; // 1.0 / ( 1 << overbrightBits )
+ int identityLightByte; // identityLight * 255
+ int overbrightBits; // r_overbrightBits->integer, but set to 0 if no hw gamma
+
+ orientationr_t orientation; // for current entity
+
+ trRefdef_t refdef;
+
+ int viewCluster;
+
+ float sunShadowScale;
+
+ bool sunShadows;
+ vec3_t sunLight; // from the sky shader for this level
+ vec3_t sunDirection;
+ vec3_t lastCascadeSunDirection;
+ float lastCascadeSunMvp[16];
+
+ frontEndCounters_t pc;
+ int frontEndMsec; // not in pc due to clearing issue
+
+ vec4_t clipRegion; // 2D clipping region
+
+ //
+ // put large tables at the end, so most elements will be
+ // within the +/32K indexed range on risc processors
+ //
+ model_t *models[MAX_MOD_KNOWN];
+ int numModels;
+
+ int numImages;
+ image_t *images[MAX_DRAWIMAGES];
+
+ int numFBOs;
+ FBO_t *fbos[MAX_FBOS];
+
+ int numVaos;
+ vao_t *vaos[MAX_VAOS];
+
+ // shader indexes from other modules will be looked up in tr.shaders[]
+ // shader indexes from drawsurfs will be looked up in sortedShaders[]
+ // lower indexed sortedShaders must be rendered first (opaque surfaces before translucent)
+ int numShaders;
+ shader_t *shaders[MAX_SHADERS];
+ shader_t *sortedShaders[MAX_SHADERS];
+
+ int numSkins;
+ skin_t *skins[MAX_SKINS];
+
+ GLuint sunFlareQuery[2];
+ int sunFlareQueryIndex;
+ bool sunFlareQueryActive[2];
+
+ float sinTable[FUNCTABLE_SIZE];
+ float squareTable[FUNCTABLE_SIZE];
+ float triangleTable[FUNCTABLE_SIZE];
+ float sawToothTable[FUNCTABLE_SIZE];
+ float inverseSawToothTable[FUNCTABLE_SIZE];
+ float fogTable[FOG_TABLE_SIZE];
+} trGlobals_t;
+
+extern backEndState_t backEnd;
+extern trGlobals_t tr;
+extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init
+extern glRefConfig_t glRefConfig;
+
+//
+// cvars
+//
+extern cvar_t *r_flareSize;
+extern cvar_t *r_flareFade;
+// coefficient for the flare intensity falloff function.
+#define FLARE_STDCOEFF "150"
+extern cvar_t *r_flareCoeff;
+
+extern cvar_t *r_railWidth;
+extern cvar_t *r_railCoreWidth;
+extern cvar_t *r_railSegmentLength;
+
+extern cvar_t *r_ignore; // used for debugging anything
+extern cvar_t *r_verbose; // used for verbose debug spew
+
+extern cvar_t *r_znear; // near Z clip plane
+extern cvar_t *r_zproj; // z distance of projection plane
+extern cvar_t *r_stereoSeparation; // separation of cameras for stereo rendering
+
+extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement
+
+extern cvar_t *r_lodbias; // push/pull LOD transitions
+extern cvar_t *r_lodscale;
+
+extern cvar_t *r_inGameVideo; // controls whether in game video should be draw
+extern cvar_t *r_fastsky; // controls whether sky should be cleared or drawn
+extern cvar_t *r_drawSun; // controls drawing of sun quad
+extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled
+extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity
+
+extern cvar_t *r_norefresh; // bypasses the ref rendering
+extern cvar_t *r_drawentities; // disable/enable entity rendering
+extern cvar_t *r_drawworld; // disable/enable world rendering
+extern cvar_t *r_speeds; // various levels of information display
+extern cvar_t *r_detailTextures; // enables/disables detail texturing stages
+extern cvar_t *r_novis; // disable/enable usage of PVS
+extern cvar_t *r_nocull;
+extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back side test
+extern cvar_t *r_nocurves;
+extern cvar_t *r_showcluster;
+
+extern cvar_t *r_gamma;
+
+extern cvar_t *r_ext_framebuffer_object;
+extern cvar_t *r_ext_texture_float;
+extern cvar_t *r_ext_framebuffer_multisample;
+extern cvar_t *r_arb_seamless_cube_map;
+extern cvar_t *r_arb_vertex_array_object;
+extern cvar_t *r_ext_direct_state_access;
+
+extern cvar_t *r_nobind; // turns off binding to appropriate textures
+extern cvar_t *r_singleShader; // make most world faces use default shader
+extern cvar_t *r_roundImagesDown;
+extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage
+extern cvar_t *r_picmip; // controls picmip values
+extern cvar_t *r_finish;
+extern cvar_t *r_textureMode;
+extern cvar_t *r_offsetFactor;
+extern cvar_t *r_offsetUnits;
+
+extern cvar_t *r_fullbright; // avoid lightmap pass
+extern cvar_t *r_lightmap; // render lightmaps only
+extern cvar_t *r_vertexLight; // vertex lighting mode for better performance
+extern cvar_t *r_uiFullScreen; // ui is running fullscreen
+
+extern cvar_t *r_logFile; // number of frames to emit GL logs
+extern cvar_t *r_showtris; // enables wireframe rendering of the world
+extern cvar_t *r_showsky; // forces sky in front of all surfaces
+extern cvar_t *r_shownormals; // draws wireframe normals
+extern cvar_t *r_clear; // force screen clear every frame
+
+extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection
+extern cvar_t *r_flares; // light flares
+
+extern cvar_t *r_intensity;
+
+extern cvar_t *r_lockpvs;
+extern cvar_t *r_noportals;
+extern cvar_t *r_portalOnly;
+
+extern cvar_t *r_subdivisions;
+extern cvar_t *r_lodCurveError;
+extern cvar_t *r_skipBackEnd;
+
+extern cvar_t *r_anaglyphMode;
+
+extern cvar_t *r_externalGLSL;
+
+extern cvar_t *r_hdr;
+extern cvar_t *r_floatLightmap;
+extern cvar_t *r_postProcess;
+
+extern cvar_t *r_toneMap;
+extern cvar_t *r_forceToneMap;
+extern cvar_t *r_forceToneMapMin;
+extern cvar_t *r_forceToneMapAvg;
+extern cvar_t *r_forceToneMapMax;
+
+extern cvar_t *r_autoExposure;
+extern cvar_t *r_forceAutoExposure;
+extern cvar_t *r_forceAutoExposureMin;
+extern cvar_t *r_forceAutoExposureMax;
+
+extern cvar_t *r_cameraExposure;
+
+extern cvar_t *r_depthPrepass;
+extern cvar_t *r_ssao;
+
+extern cvar_t *r_normalMapping;
+extern cvar_t *r_specularMapping;
+extern cvar_t *r_deluxeMapping;
+extern cvar_t *r_parallaxMapping;
+extern cvar_t *r_cubeMapping;
+extern cvar_t *r_cubemapSize;
+extern cvar_t *r_pbr;
+extern cvar_t *r_baseNormalX;
+extern cvar_t *r_baseNormalY;
+extern cvar_t *r_baseParallax;
+extern cvar_t *r_baseSpecular;
+extern cvar_t *r_baseGloss;
+extern cvar_t *r_glossType;
+extern cvar_t *r_dlightMode;
+extern cvar_t *r_pshadowDist;
+extern cvar_t *r_mergeLightmaps;
+extern cvar_t *r_imageUpsample;
+extern cvar_t *r_imageUpsampleMaxSize;
+extern cvar_t *r_imageUpsampleType;
+extern cvar_t *r_genNormalMaps;
+extern cvar_t *r_forceSun;
+extern cvar_t *r_forceSunLightScale;
+extern cvar_t *r_forceSunAmbientScale;
+extern cvar_t *r_sunlightMode;
+extern cvar_t *r_drawSunRays;
+extern cvar_t *r_sunShadows;
+extern cvar_t *r_shadowFilter;
+extern cvar_t *r_shadowBlur;
+extern cvar_t *r_shadowMapSize;
+extern cvar_t *r_shadowCascadeZNear;
+extern cvar_t *r_shadowCascadeZFar;
+extern cvar_t *r_shadowCascadeZBias;
+extern cvar_t *r_ignoreDstAlpha;
+
+extern cvar_t *r_greyscale;
+
+extern cvar_t *r_ignoreGLErrors;
+
+extern cvar_t *r_overBrightBits;
+extern cvar_t *r_mapOverBrightBits;
+
+extern cvar_t *r_mapLightmapMin;
+
+extern cvar_t *r_debugSurface;
+extern cvar_t *r_simpleMipMaps;
+
+extern cvar_t *r_showImages;
+extern cvar_t *r_debugSort;
+
+extern cvar_t *r_printShaders;
+
+extern cvar_t *r_marksOnTriangleMeshes;
+
+//====================================================================
+
+void R_SwapBuffers( int );
+
+void R_RenderView( viewParms_t *parms );
+void R_RenderDlightCubemaps(const refdef_t *fd);
+void R_RenderPshadowMaps(const refdef_t *fd);
+void R_RenderSunShadowMaps(const refdef_t *fd, int level);
+void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, bool subscene );
+
+void R_AddMD3Surfaces( trRefEntity_t *e );
+void R_AddNullModelSurfaces( trRefEntity_t *e );
+void R_AddBeamSurfaces( trRefEntity_t *e );
+void R_AddRailSurfaces( trRefEntity_t *e, bool isUnderwater );
+void R_AddLightningBoltSurfaces( trRefEntity_t *e );
+
+void R_AddPolygonSurfaces( void );
+
+void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
+ int *fogNum, int *dlightMap, int *pshadowMap );
+
+void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
+ int fogIndex, int dlightMap, int pshadowMap, int cubemap );
+
+void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2,
+ const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3);
+vec_t R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, const vec3_t normal, const vec3_t sdir, const vec3_t tdir);
+bool R_CalcTangentVectors(srfVert_t * dv[3]);
+
+#define CULL_IN 0 // completely unclipped
+#define CULL_CLIP 1 // clipped by one or more planes
+#define CULL_OUT 2 // completely outside the clipping planes
+void R_LocalNormalToWorld (const vec3_t local, vec3_t world);
+void R_LocalPointToWorld (const vec3_t local, vec3_t world);
+int R_CullBox (vec3_t bounds[2]);
+int R_CullLocalBox (vec3_t bounds[2]);
+int R_CullPointAndRadiusEx( const vec3_t origin, float radius, const cplane_t* frustum, int numPlanes );
+int R_CullPointAndRadius( const vec3_t origin, float radius );
+int R_CullLocalPointAndRadius( const vec3_t origin, float radius );
+
+void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, bool computeFrustum);
+void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *orientation );
+
+/*
+** GL wrapper/helper functions
+*/
+void GL_BindToTMU( image_t *image, int tmu );
+void GL_SetDefaultState (void);
+void GL_TextureMode( const char *string );
+void GL_CheckErrs( const char *file, int line );
+#define GL_CheckErrors(...) GL_CheckErrs(__FILE__, __LINE__)
+void GL_State( unsigned long stateVector );
+void GL_SetProjectionMatrix(mat4_t matrix);
+void GL_SetModelviewMatrix(mat4_t matrix);
+void GL_Cull( int cullType );
+
+#define GLS_SRCBLEND_ZERO 0x00000001
+#define GLS_SRCBLEND_ONE 0x00000002
+#define GLS_SRCBLEND_DST_COLOR 0x00000003
+#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004
+#define GLS_SRCBLEND_SRC_ALPHA 0x00000005
+#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006
+#define GLS_SRCBLEND_DST_ALPHA 0x00000007
+#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008
+#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009
+#define GLS_SRCBLEND_BITS 0x0000000f
+
+#define GLS_DSTBLEND_ZERO 0x00000010
+#define GLS_DSTBLEND_ONE 0x00000020
+#define GLS_DSTBLEND_SRC_COLOR 0x00000030
+#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040
+#define GLS_DSTBLEND_SRC_ALPHA 0x00000050
+#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060
+#define GLS_DSTBLEND_DST_ALPHA 0x00000070
+#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080
+#define GLS_DSTBLEND_BITS 0x000000f0
+
+#define GLS_DEPTHMASK_TRUE 0x00000100
+
+#define GLS_POLYMODE_LINE 0x00001000
+
+#define GLS_DEPTHTEST_DISABLE 0x00010000
+#define GLS_DEPTHFUNC_EQUAL 0x00020000
+#define GLS_DEPTHFUNC_GREATER 0x00040000
+#define GLS_DEPTHFUNC_BITS 0x00060000
+
+#define GLS_ATEST_GT_0 0x10000000
+#define GLS_ATEST_LT_80 0x20000000
+#define GLS_ATEST_GE_80 0x40000000
+#define GLS_ATEST_BITS 0x70000000
+
+#define GLS_DEFAULT GLS_DEPTHMASK_TRUE
+
+void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, bool dirty);
+void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, bool dirty);
+
+void RE_BeginFrame( stereoFrame_t stereoFrame );
+void RE_BeginRegistration( glconfig_t *glconfig );
+void RE_LoadWorldMap( const char *mapname );
+void RE_SetWorldVisData( const byte *vis );
+qhandle_t RE_RegisterModel( const char *name );
+qhandle_t RE_RegisterSkin( const char *name );
+void RE_Shutdown( bool destroyWindow );
+
+bool R_GetEntityToken( char *buffer, int size );
+
+model_t *R_AllocModel( void );
+
+void R_Init( void );
+void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height, GLenum picFormat );
+
+void R_SetColorMappings( void );
+void R_GammaCorrect( byte *buffer, int bufSize );
+
+void R_ImageList_f( void );
+void R_SkinList_f( void );
+// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516
+const void *RB_TakeScreenshotCmd( const void *data );
+void R_ScreenShot_f( void );
+
+void R_InitFogTable( void );
+float R_FogFactor( float s, float t );
+void R_InitImages( void );
+void R_DeleteTextures( void );
+int R_SumOfUsedImages( void );
+void R_InitSkins( void );
+skin_t *R_GetSkinByHandle( qhandle_t hSkin );
+
+int R_ComputeLOD( trRefEntity_t *ent );
+
+const void *RB_TakeVideoFrameCmd( const void *data );
+
+//
+// tr_shader.c
+//
+shader_t *R_FindShader( const char *name, int lightmapIndex, bool mipRawImage );
+shader_t *R_GetShaderByHandle( qhandle_t hShader );
+shader_t *R_GetShaderByState( int index, long *cycleTime );
+shader_t *R_FindShaderByName( const char *name );
+void R_InitShaders( void );
+void R_ShaderList_f( void );
+void R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset);
+
+/*
+====================================================================
+
+IMPLEMENTATION SPECIFIC FUNCTIONS
+
+====================================================================
+*/
+
+void GLimp_InitExtraExtensions( void );
+
+/*
+====================================================================
+
+TESSELATOR/SHADER DECLARATIONS
+
+====================================================================
+*/
+
+typedef struct stageVars
+{
+ color4ub_t colors[SHADER_MAX_VERTEXES];
+ vec2_t texcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES];
+} stageVars_t;
+
+typedef struct shaderCommands_s
+{
+ glIndex_t indexes[SHADER_MAX_INDEXES] QALIGN(16);
+ vec4_t xyz[SHADER_MAX_VERTEXES] QALIGN(16);
+ int16_t normal[SHADER_MAX_VERTEXES][4] QALIGN(16);
+ int16_t tangent[SHADER_MAX_VERTEXES][4] QALIGN(16);
+ vec2_t texCoords[SHADER_MAX_VERTEXES] QALIGN(16);
+ vec2_t lightCoords[SHADER_MAX_VERTEXES] QALIGN(16);
+ uint16_t color[SHADER_MAX_VERTEXES][4] QALIGN(16);
+ int16_t lightdir[SHADER_MAX_VERTEXES][4] QALIGN(16);
+ //int vertexDlightBits[SHADER_MAX_VERTEXES] QALIGN(16);
+
+ void *attribPointers[ATTR_INDEX_COUNT];
+ vao_t *vao;
+ bool useInternalVao;
+ bool useCacheVao;
+
+ stageVars_t svars QALIGN(16);
+
+ //color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16);
+
+ shader_t *shader;
+ double shaderTime;
+ int fogNum;
+ int cubemapIndex;
+
+ int dlightBits; // or together of all vertexDlightBits
+ int pshadowBits;
+
+ int firstIndex;
+ int numIndexes;
+ int numVertexes;
+
+ // info extracted from current shader
+ int numPasses;
+ void (*currentStageIteratorFunc)( void );
+ shaderStage_t **xstages;
+} shaderCommands_t;
+
+extern shaderCommands_t tess;
+
+void RB_BeginSurface(shader_t *shader, int fogNum, int cubemapIndex );
+void RB_EndSurface(void);
+void RB_CheckOverflow( int verts, int indexes );
+#define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);}
+
+void R_DrawElements( int numIndexes, glIndex_t firstIndex );
+void RB_StageIteratorGeneric( void );
+void RB_StageIteratorSky( void );
+void RB_StageIteratorVertexLitTexture( void );
+void RB_StageIteratorLightmappedMultitexture( void );
+
+void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, float color[4] );
+void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], float s1, float t1, float s2, float t2 );
+void RB_InstantQuad( vec4_t quadVerts[4] );
+//void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4], vec4_t color, shaderProgram_t *sp, vec2_t invTexRes);
+void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4]);
+
+void RB_ShowImages( void );
+
+
+/*
+============================================================
+
+WORLD MAP
+
+============================================================
+*/
+
+void R_AddBrushModelSurfaces( trRefEntity_t *e );
+void R_AddWorldSurfaces( void );
+bool R_inPVS( const vec3_t p1, const vec3_t p2 );
+
+
+/*
+============================================================
+
+FLARES
+
+============================================================
+*/
+
+void R_ClearFlares( void );
+
+void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal );
+void RB_AddDlightFlares( void );
+void RB_RenderFlares (void);
+
+/*
+============================================================
+
+LIGHTS
+
+============================================================
+*/
+
+void R_DlightBmodel( bmodel_t *bmodel );
+void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent );
+void R_TransformDlights( int count, dlight_t *dl, orientationr_t *orientation );
+bool R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
+bool R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *world );
+int R_CubemapForPoint( vec3_t point );
+
+
+/*
+============================================================
+
+SHADOWS
+
+============================================================
+*/
+
+void RB_ShadowTessEnd( void );
+void RB_ShadowFinish( void );
+void RB_ProjectionShadowDeform( void );
+
+/*
+============================================================
+
+SKIES
+
+============================================================
+*/
+
+void R_BuildCloudData( shaderCommands_t *shader );
+void R_InitSkyTexCoords( float cloudLayerHeight );
+void R_DrawSkyBox( shaderCommands_t *shader );
+void RB_DrawSun( float scale, shader_t *shader );
+void RB_ClipSkyPolygons( shaderCommands_t *shader );
+
+/*
+============================================================
+
+CURVE TESSELATION
+
+============================================================
+*/
+
+#define PATCH_STITCHING
+
+void R_SubdividePatchToGrid( srfBspSurface_t *grid, int width, int height,
+ srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] );
+void R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror );
+void R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror );
+
+/*
+============================================================
+
+MARKERS, POLYGON PROJECTION ON WORLD POLYGONS
+
+============================================================
+*/
+
+int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
+ int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
+
+
+/*
+============================================================
+
+VERTEX BUFFER OBJECTS
+
+============================================================
+*/
+
+void R_VaoPackTangent(int16_t *out, vec4_t v);
+void R_VaoPackNormal(int16_t *out, vec3_t v);
+void R_VaoPackColor(uint16_t *out, vec4_t c);
+void R_VaoUnpackTangent(vec4_t v, int16_t *pack);
+void R_VaoUnpackNormal(vec3_t v, int16_t *pack);
+
+vao_t *R_CreateVao(const char *name, byte *vertexes, int vertexesSize, byte *indexes, int indexesSize, vaoUsage_t usage);
+vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int numIndexes, glIndex_t *inIndexes);
+
+void R_BindVao(vao_t *vao);
+void R_BindNullVao(void);
+
+void Vao_SetVertexPointers(vao_t *vao);
+
+void R_InitVaos(void);
+void R_ShutdownVaos(void);
+void R_VaoList_f(void);
+
+void RB_UpdateTessVao(unsigned int attribBits);
+
+void VaoCache_Commit(void);
+void VaoCache_Init(void);
+void VaoCache_BindVao(void);
+void VaoCache_CheckAdd(bool *endSurface, bool *recycleVertexBuffer, bool *recycleIndexBuffer, int numVerts, int numIndexes);
+void VaoCache_RecycleVertexBuffer(void);
+void VaoCache_RecycleIndexBuffer(void);
+void VaoCache_InitNewSurfaceSet(void);
+void VaoCache_AddSurface(srfVert_t *verts, int numVerts, glIndex_t *indexes, int numIndexes);
+
+/*
+============================================================
+
+GLSL
+
+============================================================
+*/
+
+void GLSL_InitGPUShaders(void);
+void GLSL_ShutdownGPUShaders(void);
+void GLSL_VertexAttribPointers(uint32_t attribBits);
+void GLSL_BindProgram(shaderProgram_t * program);
+
+void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value);
+void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value);
+void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v);
+void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v);
+void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v);
+void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v);
+void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix);
+
+shaderProgram_t *GLSL_GetGenericShaderProgram(int stage);
+
+/*
+============================================================
+
+SCENE GENERATION
+
+============================================================
+*/
+
+void R_InitNextFrame( void );
+
+void RE_ClearScene( void );
+void RE_AddRefEntityToScene( const refEntity_t *ent );
+void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
+void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
+void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b );
+void RE_BeginScene( const refdef_t *fd );
+void RE_RenderScene( const refdef_t *fd );
+void RE_EndScene( void );
+
+/*
+=============================================================
+
+UNCOMPRESSING BONES
+
+=============================================================
+*/
+
+#define MC_BITS_X (16)
+#define MC_BITS_Y (16)
+#define MC_BITS_Z (16)
+#define MC_BITS_VECT (16)
+
+#define MC_SCALE_X (1.0f/64)
+#define MC_SCALE_Y (1.0f/64)
+#define MC_SCALE_Z (1.0f/64)
+
+void MC_UnCompress(float mat[3][4],const unsigned char * comp);
+
+/*
+=============================================================
+
+ANIMATED MODELS
+
+=============================================================
+*/
+
+void R_MDRAddAnimSurfaces( trRefEntity_t *ent );
+void RB_MDRSurfaceAnim( mdrSurface_t *surface );
+bool R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name );
+void R_AddIQMSurfaces( trRefEntity_t *ent );
+void RB_IQMSurfaceAnim( surfaceType_t *surface );
+int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
+ int startFrame, int endFrame,
+ float frac, const char *tagName );
+
+/*
+=============================================================
+=============================================================
+*/
+void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
+ vec4_t eye, vec4_t dst );
+void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window );
+
+void RB_DeformTessGeometry( void );
+
+void RB_CalcFogTexCoords( float *dstTexCoords );
+
+void RB_CalcScaleTexMatrix( const float scale[2], float *matrix );
+void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix );
+void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix );
+void RB_CalcTurbulentFactors( const waveForm_t *wf, float *amplitude, float *now );
+void RB_CalcTransformTexMatrix( const texModInfo_t *tmi, float *matrix );
+void RB_CalcStretchTexMatrix( const waveForm_t *wf, float *matrix );
+
+void RB_CalcModulateColorsByFog( unsigned char *dstColors );
+float RB_CalcWaveAlphaSingle( const waveForm_t *wf );
+float RB_CalcWaveColorSingle( const waveForm_t *wf );
+
+/*
+=============================================================
+
+RENDERER BACK END FUNCTIONS
+
+=============================================================
+*/
+
+void RB_ExecuteRenderCommands( const void *data );
+
+/*
+=============================================================
+
+RENDERER BACK END COMMAND QUEUE
+
+=============================================================
+*/
+
+#define MAX_RENDER_COMMANDS 0x40000
+
+typedef struct {
+ byte cmds[MAX_RENDER_COMMANDS];
+ int used;
+} renderCommandList_t;
+
+typedef struct {
+ int commandId;
+ float color[4];
+} setColorCommand_t;
+
+typedef struct {
+ int commandId;
+ int buffer;
+} drawBufferCommand_t;
+
+typedef struct {
+ int commandId;
+ image_t *image;
+ int width;
+ int height;
+ void *data;
+} subImageCommand_t;
+
+typedef struct {
+ int commandId;
+} swapBuffersCommand_t;
+
+typedef struct {
+ int commandId;
+ int buffer;
+} endFrameCommand_t;
+
+typedef struct {
+ int commandId;
+ shader_t *shader;
+ float x, y;
+ float w, h;
+ float s1, t1;
+ float s2, t2;
+} stretchPicCommand_t;
+
+typedef struct {
+ int commandId;
+ trRefdef_t refdef;
+ viewParms_t viewParms;
+ drawSurf_t *drawSurfs;
+ int numDrawSurfs;
+} drawSurfsCommand_t;
+
+typedef struct {
+ int commandId;
+ int x;
+ int y;
+ int width;
+ int height;
+ char *fileName;
+ bool jpeg;
+} screenshotCommand_t;
+
+typedef struct {
+ int commandId;
+ int width;
+ int height;
+ byte *captureBuffer;
+ byte *encodeBuffer;
+ bool motionJpeg;
+} videoFrameCommand_t;
+
+typedef struct
+{
+ int commandId;
+
+ GLboolean rgba[4];
+} colorMaskCommand_t;
+
+typedef struct
+{
+ int commandId;
+} clearDepthCommand_t;
+
+typedef struct {
+ int commandId;
+ int map;
+ int cubeSide;
+} capShadowmapCommand_t;
+
+typedef struct {
+ int commandId;
+ trRefdef_t refdef;
+ viewParms_t viewParms;
+} postProcessCommand_t;
+
+typedef struct {
+ int commandId;
+} exportCubemapsCommand_t;
+
+typedef enum {
+ RC_END_OF_LIST,
+ RC_SET_COLOR,
+ RC_STRETCH_PIC,
+ RC_DRAW_SURFS,
+ RC_DRAW_BUFFER,
+ RC_SWAP_BUFFERS,
+ RC_SCREENSHOT,
+ RC_VIDEOFRAME,
+ RC_COLORMASK,
+ RC_CLEARDEPTH,
+ RC_CAPSHADOWMAP,
+ RC_POSTPROCESS,
+ RC_EXPORT_CUBEMAPS
+} renderCommand_t;
+
+
+// these are sort of arbitrary limits.
+// the limits apply to the sum of all scenes in a frame --
+// the main view, all the 3D icons, etc
+#define MAX_POLYS 600
+#define MAX_POLYVERTS 3000
+
+// all of the information needed by the back end must be
+// contained in a backEndData_t
+typedef struct {
+ drawSurf_t drawSurfs[MAX_DRAWSURFS];
+ dlight_t dlights[MAX_DLIGHTS];
+ trRefEntity_t entities[MAX_REFENTITIES];
+ srfPoly_t *polys;//[MAX_POLYS];
+ polyVert_t *polyVerts;//[MAX_POLYVERTS];
+ pshadow_t pshadows[MAX_CALC_PSHADOWS];
+ renderCommandList_t commands;
+} backEndData_t;
+
+extern int max_polys;
+extern int max_polyverts;
+
+extern backEndData_t *backEndData; // the second one may not be allocated
+
+
+void *R_GetCommandBuffer( int bytes );
+void RB_ExecuteRenderCommands( const void *data );
+
+void R_IssuePendingRenderCommands( void );
+
+void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs );
+void R_AddCapShadowmapCmd( int dlight, int cubeSide );
+void R_AddPostProcessCmd (void);
+
+void RE_SetColor( const float *rgba );
+void RE_SetClipRegion( const float *region );
+void RE_StretchPic ( float x, float y, float w, float h,
+ float s1, float t1, float s2, float t2, qhandle_t hShader );
+void RE_BeginFrame( stereoFrame_t stereoFrame );
+void RE_EndFrame( int *frontEndMsec, int *backEndMsec );
+void RE_SaveJPG(char * filename, int quality, int image_width, int image_height,
+ unsigned char *image_buffer, int padding);
+size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality,
+ int image_width, int image_height, byte *image_buffer, int padding);
+void RE_TakeVideoFrame( int width, int height,
+ byte *captureBuffer, byte *encodeBuffer, bool motionJpeg );
+
+
+#endif //TR_LOCAL_H
diff --git a/src/renderergl2/tr_main.cpp b/src/renderergl2/tr_main.cpp
new file mode 100644
index 0000000..d9eb3ee
--- /dev/null
+++ b/src/renderergl2/tr_main.cpp
@@ -0,0 +1,2669 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_main.c -- main control flow for each frame
+
+#include "tr_local.h"
+
+#include <string.h> // memcpy
+
+trGlobals_t tr;
+
+static float s_flipMatrix[16] = {
+ // convert from our coordinate system (looking down X)
+ // to OpenGL's coordinate system (looking down -Z)
+ 0, 0, -1, 0,
+ -1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 0, 1
+};
+
+
+refimport_t ri;
+
+// entities that will have procedurally generated surfaces will just
+// point at this for their sorting surface
+surfaceType_t entitySurface = SF_ENTITY;
+
+/*
+================
+R_CompareVert
+================
+*/
+bool R_CompareVert(srfVert_t * v1, srfVert_t * v2, bool checkST)
+{
+ int i;
+
+ for(i = 0; i < 3; i++)
+ {
+ if(floor(v1->xyz[i] + 0.1) != floor(v2->xyz[i] + 0.1))
+ {
+ return false;
+ }
+
+ if(checkST && ((v1->st[0] != v2->st[0]) || (v1->st[1] != v2->st[1])))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*
+http://www.terathon.com/code/tangent.html
+*/
+void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2,
+ const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3)
+{
+ float x1, x2, y1, y2, z1, z2;
+ float s1, s2, t1, t2, r;
+
+ x1 = v2[0] - v1[0];
+ x2 = v3[0] - v1[0];
+ y1 = v2[1] - v1[1];
+ y2 = v3[1] - v1[1];
+ z1 = v2[2] - v1[2];
+ z2 = v3[2] - v1[2];
+
+ s1 = w2[0] - w1[0];
+ s2 = w3[0] - w1[0];
+ t1 = w2[1] - w1[1];
+ t2 = w3[1] - w1[1];
+
+ r = s1 * t2 - s2 * t1;
+ if (r) r = 1.0f / r;
+
+ VectorSet(sdir, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
+ VectorSet(tdir, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
+}
+
+/*
+=============
+R_CalcTangentSpace
+
+Lengyel, Eric. �Computing Tangent Space Basis Vectors for an Arbitrary Mesh�. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/src/tangent.html
+=============
+*/
+vec_t R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, const vec3_t normal, const vec3_t sdir, const vec3_t tdir)
+{
+ vec3_t n_cross_t;
+ vec_t n_dot_t, handedness;
+
+ // Gram-Schmidt orthogonalize
+ n_dot_t = DotProduct(normal, sdir);
+ VectorMA(sdir, -n_dot_t, normal, tangent);
+ VectorNormalize(tangent);
+
+ // Calculate handedness
+ CrossProduct(normal, sdir, n_cross_t);
+ handedness = (DotProduct(n_cross_t, tdir) < 0.0f) ? -1.0f : 1.0f;
+
+ // Calculate orthogonal bitangent, if necessary
+ if (bitangent)
+ CrossProduct(normal, tangent, bitangent);
+
+ return handedness;
+}
+
+bool R_CalcTangentVectors(srfVert_t * dv[3])
+{
+ int i;
+ float bb, s, t;
+ vec3_t bary;
+
+
+ /* calculate barycentric basis for the triangle */
+ bb = (dv[1]->st[0] - dv[0]->st[0]) * (dv[2]->st[1] - dv[0]->st[1]) - (dv[2]->st[0] - dv[0]->st[0]) * (dv[1]->st[1] - dv[0]->st[1]);
+ if(fabs(bb) < 0.00000001f)
+ return false;
+
+ /* do each vertex */
+ for(i = 0; i < 3; i++)
+ {
+ vec4_t tangent;
+ vec3_t normal, bitangent, nxt;
+
+ // calculate s tangent vector
+ s = dv[i]->st[0] + 10.0f;
+ t = dv[i]->st[1];
+ bary[0] = ((dv[1]->st[0] - s) * (dv[2]->st[1] - t) - (dv[2]->st[0] - s) * (dv[1]->st[1] - t)) / bb;
+ bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb;
+ bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb;
+
+ tangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0];
+ tangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1];
+ tangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2];
+
+ VectorSubtract(tangent, dv[i]->xyz, tangent);
+ VectorNormalize(tangent);
+
+ // calculate t tangent vector
+ s = dv[i]->st[0];
+ t = dv[i]->st[1] + 10.0f;
+ bary[0] = ((dv[1]->st[0] - s) * (dv[2]->st[1] - t) - (dv[2]->st[0] - s) * (dv[1]->st[1] - t)) / bb;
+ bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb;
+ bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb;
+
+ bitangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0];
+ bitangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1];
+ bitangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2];
+
+ VectorSubtract(bitangent, dv[i]->xyz, bitangent);
+ VectorNormalize(bitangent);
+
+ // store bitangent handedness
+ R_VaoUnpackNormal(normal, dv[i]->normal);
+ CrossProduct(normal, tangent, nxt);
+ tangent[3] = (DotProduct(nxt, bitangent) < 0.0f) ? -1.0f : 1.0f;
+
+ R_VaoPackTangent(dv[i]->tangent, tangent);
+
+ // debug code
+ //% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,
+ //% stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] );
+ }
+
+ return true;
+}
+
+
+/*
+=================
+R_CullLocalBox
+
+Returns CULL_IN, CULL_CLIP, or CULL_OUT
+=================
+*/
+int R_CullLocalBox(vec3_t localBounds[2]) {
+#if 0
+ int i, j;
+ vec3_t transformed[8];
+ float dists[8];
+ vec3_t v;
+ cplane_t *frust;
+ int anyBack;
+ int front, back;
+
+ if ( r_nocull->integer ) {
+ return CULL_CLIP;
+ }
+
+ // transform into world space
+ for (i = 0 ; i < 8 ; i++) {
+ v[0] = bounds[i&1][0];
+ v[1] = bounds[(i>>1)&1][1];
+ v[2] = bounds[(i>>2)&1][2];
+
+ VectorCopy( tr.orientation.origin, transformed[i] );
+ VectorMA( transformed[i], v[0], tr.orientation.axis[0], transformed[i] );
+ VectorMA( transformed[i], v[1], tr.orientation.axis[1], transformed[i] );
+ VectorMA( transformed[i], v[2], tr.orientation.axis[2], transformed[i] );
+ }
+
+ // check against frustum planes
+ anyBack = 0;
+ for (i = 0 ; i < 4 ; i++) {
+ frust = &tr.viewParms.frustum[i];
+
+ front = back = 0;
+ for (j = 0 ; j < 8 ; j++) {
+ dists[j] = DotProduct(transformed[j], frust->normal);
+ if ( dists[j] > frust->dist ) {
+ front = 1;
+ if ( back ) {
+ break; // a point is in front
+ }
+ } else {
+ back = 1;
+ }
+ }
+ if ( !front ) {
+ // all points were behind one of the planes
+ return CULL_OUT;
+ }
+ anyBack |= back;
+ }
+
+ if ( !anyBack ) {
+ return CULL_IN; // completely inside frustum
+ }
+
+ return CULL_CLIP; // partially clipped
+#else
+ int j;
+ vec3_t transformed;
+ vec3_t v;
+ vec3_t worldBounds[2];
+
+ if(r_nocull->integer)
+ {
+ return CULL_CLIP;
+ }
+
+ // transform into world space
+ ClearBounds(worldBounds[0], worldBounds[1]);
+
+ for(j = 0; j < 8; j++)
+ {
+ v[0] = localBounds[j & 1][0];
+ v[1] = localBounds[(j >> 1) & 1][1];
+ v[2] = localBounds[(j >> 2) & 1][2];
+
+ R_LocalPointToWorld(v, transformed);
+
+ AddPointToBounds(transformed, worldBounds[0], worldBounds[1]);
+ }
+
+ return R_CullBox(worldBounds);
+#endif
+}
+
+/*
+=================
+R_CullBox
+
+Returns CULL_IN, CULL_CLIP, or CULL_OUT
+=================
+*/
+int R_CullBox(vec3_t worldBounds[2]) {
+ int i;
+ cplane_t *frust;
+ bool anyClip;
+ int r, numPlanes;
+
+ numPlanes = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4;
+
+ // check against frustum planes
+ anyClip = false;
+ for(i = 0; i < numPlanes; i++)
+ {
+ frust = &tr.viewParms.frustum[i];
+
+ r = BoxOnPlaneSide(worldBounds[0], worldBounds[1], frust);
+
+ if(r == 2)
+ {
+ // completely outside frustum
+ return CULL_OUT;
+ }
+ if(r == 3)
+ {
+ anyClip = true;
+ }
+ }
+
+ if(!anyClip)
+ {
+ // completely inside frustum
+ return CULL_IN;
+ }
+
+ // partially clipped
+ return CULL_CLIP;
+}
+
+/*
+** R_CullLocalPointAndRadius
+*/
+int R_CullLocalPointAndRadius( const vec3_t pt, float radius )
+{
+ vec3_t transformed;
+
+ R_LocalPointToWorld( pt, transformed );
+
+ return R_CullPointAndRadius( transformed, radius );
+}
+
+/*
+** R_CullPointAndRadius
+*/
+int R_CullPointAndRadiusEx( const vec3_t pt, float radius, const cplane_t* frustum, int numPlanes )
+{
+ int i;
+ float dist;
+ const cplane_t *frust;
+ bool mightBeClipped = false;
+
+ if ( r_nocull->integer ) {
+ return CULL_CLIP;
+ }
+
+ // check against frustum planes
+ for (i = 0 ; i < numPlanes ; i++)
+ {
+ frust = &frustum[i];
+
+ dist = DotProduct( pt, frust->normal) - frust->dist;
+ if ( dist < -radius )
+ {
+ return CULL_OUT;
+ }
+ else if ( dist <= radius )
+ {
+ mightBeClipped = true;
+ }
+ }
+
+ if ( mightBeClipped )
+ {
+ return CULL_CLIP;
+ }
+
+ return CULL_IN; // completely inside frustum
+}
+
+/*
+** R_CullPointAndRadius
+*/
+int R_CullPointAndRadius( const vec3_t pt, float radius )
+{
+ return R_CullPointAndRadiusEx(pt, radius, tr.viewParms.frustum, (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4);
+}
+
+/*
+=================
+R_LocalNormalToWorld
+
+=================
+*/
+void R_LocalNormalToWorld (const vec3_t local, vec3_t world) {
+ world[0] = local[0] * tr.orientation.axis[0][0] + local[1] * tr.orientation.axis[1][0] + local[2] * tr.orientation.axis[2][0];
+ world[1] = local[0] * tr.orientation.axis[0][1] + local[1] * tr.orientation.axis[1][1] + local[2] * tr.orientation.axis[2][1];
+ world[2] = local[0] * tr.orientation.axis[0][2] + local[1] * tr.orientation.axis[1][2] + local[2] * tr.orientation.axis[2][2];
+}
+
+/*
+=================
+R_LocalPointToWorld
+
+=================
+*/
+void R_LocalPointToWorld (const vec3_t local, vec3_t world) {
+ world[0] = local[0] * tr.orientation.axis[0][0] + local[1] * tr.orientation.axis[1][0] + local[2] * tr.orientation.axis[2][0] + tr.orientation.origin[0];
+ world[1] = local[0] * tr.orientation.axis[0][1] + local[1] * tr.orientation.axis[1][1] + local[2] * tr.orientation.axis[2][1] + tr.orientation.origin[1];
+ world[2] = local[0] * tr.orientation.axis[0][2] + local[1] * tr.orientation.axis[1][2] + local[2] * tr.orientation.axis[2][2] + tr.orientation.origin[2];
+}
+
+/*
+=================
+R_WorldToLocal
+
+=================
+*/
+void R_WorldToLocal (const vec3_t world, vec3_t local) {
+ local[0] = DotProduct(world, tr.orientation.axis[0]);
+ local[1] = DotProduct(world, tr.orientation.axis[1]);
+ local[2] = DotProduct(world, tr.orientation.axis[2]);
+}
+
+/*
+==========================
+R_TransformModelToClip
+
+==========================
+*/
+void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
+ vec4_t eye, vec4_t dst ) {
+ int i;
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ eye[i] =
+ src[0] * modelMatrix[ i + 0 * 4 ] +
+ src[1] * modelMatrix[ i + 1 * 4 ] +
+ src[2] * modelMatrix[ i + 2 * 4 ] +
+ 1 * modelMatrix[ i + 3 * 4 ];
+ }
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ dst[i] =
+ eye[0] * projectionMatrix[ i + 0 * 4 ] +
+ eye[1] * projectionMatrix[ i + 1 * 4 ] +
+ eye[2] * projectionMatrix[ i + 2 * 4 ] +
+ eye[3] * projectionMatrix[ i + 3 * 4 ];
+ }
+}
+
+/*
+==========================
+R_TransformClipToWindow
+
+==========================
+*/
+void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) {
+ normalized[0] = clip[0] / clip[3];
+ normalized[1] = clip[1] / clip[3];
+ normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
+
+ window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth;
+ window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight;
+ window[2] = normalized[2];
+
+ window[0] = (int) ( window[0] + 0.5 );
+ window[1] = (int) ( window[1] + 0.5 );
+}
+
+
+/*
+==========================
+myGlMultMatrix
+
+==========================
+*/
+void myGlMultMatrix( const float *a, const float *b, float *out ) {
+ int i, j;
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ for ( j = 0 ; j < 4 ; j++ ) {
+ out[ i * 4 + j ] =
+ a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
+ + a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
+ + a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
+ + a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
+ }
+ }
+}
+
+/*
+=================
+R_RotateForEntity
+
+Generates an orientation for an entity and viewParms
+Does NOT produce any GL calls
+Called by both the front end and the back end
+=================
+*/
+void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
+ orientationr_t *orientation ) {
+ float glMatrix[16];
+ vec3_t delta;
+ float axisLength;
+
+ if ( ent->e.reType != RT_MODEL ) {
+ *orientation = viewParms->world;
+ return;
+ }
+
+ VectorCopy( ent->e.origin, orientation->origin );
+
+ VectorCopy( ent->e.axis[0], orientation->axis[0] );
+ VectorCopy( ent->e.axis[1], orientation->axis[1] );
+ VectorCopy( ent->e.axis[2], orientation->axis[2] );
+
+ glMatrix[0] = orientation->axis[0][0];
+ glMatrix[4] = orientation->axis[1][0];
+ glMatrix[8] = orientation->axis[2][0];
+ glMatrix[12] = orientation->origin[0];
+
+ glMatrix[1] = orientation->axis[0][1];
+ glMatrix[5] = orientation->axis[1][1];
+ glMatrix[9] = orientation->axis[2][1];
+ glMatrix[13] = orientation->origin[1];
+
+ glMatrix[2] = orientation->axis[0][2];
+ glMatrix[6] = orientation->axis[1][2];
+ glMatrix[10] = orientation->axis[2][2];
+ glMatrix[14] = orientation->origin[2];
+
+ glMatrix[3] = 0;
+ glMatrix[7] = 0;
+ glMatrix[11] = 0;
+ glMatrix[15] = 1;
+
+ Mat4Copy(glMatrix, orientation->transformMatrix);
+ myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, orientation->modelMatrix );
+
+ // calculate the viewer origin in the model's space
+ // needed for fog, specular, and environment mapping
+ VectorSubtract( viewParms->orientation.origin, orientation->origin, delta );
+
+ // compensate for scale in the axes if necessary
+ if ( ent->e.nonNormalizedAxes ) {
+ axisLength = VectorLength( ent->e.axis[0] );
+ if ( !axisLength ) {
+ axisLength = 0;
+ } else {
+ axisLength = 1.0f / axisLength;
+ }
+ } else {
+ axisLength = 1.0f;
+ }
+
+ orientation->viewOrigin[0] = DotProduct( delta, orientation->axis[0] ) * axisLength;
+ orientation->viewOrigin[1] = DotProduct( delta, orientation->axis[1] ) * axisLength;
+ orientation->viewOrigin[2] = DotProduct( delta, orientation->axis[2] ) * axisLength;
+}
+
+/*
+=================
+R_RotateForViewer
+
+Sets up the modelview matrix for a given viewParm
+=================
+*/
+void R_RotateForViewer (void)
+{
+ float viewerMatrix[16];
+ vec3_t origin;
+
+ Com_Memset (&tr.orientation, 0, sizeof(tr.orientation));
+ tr.orientation.axis[0][0] = 1;
+ tr.orientation.axis[1][1] = 1;
+ tr.orientation.axis[2][2] = 1;
+ VectorCopy (tr.viewParms.orientation.origin, tr.orientation.viewOrigin);
+
+ // transform by the camera placement
+ VectorCopy( tr.viewParms.orientation.origin, origin );
+
+ viewerMatrix[0] = tr.viewParms.orientation.axis[0][0];
+ viewerMatrix[4] = tr.viewParms.orientation.axis[0][1];
+ viewerMatrix[8] = tr.viewParms.orientation.axis[0][2];
+ viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
+
+ viewerMatrix[1] = tr.viewParms.orientation.axis[1][0];
+ viewerMatrix[5] = tr.viewParms.orientation.axis[1][1];
+ viewerMatrix[9] = tr.viewParms.orientation.axis[1][2];
+ viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
+
+ viewerMatrix[2] = tr.viewParms.orientation.axis[2][0];
+ viewerMatrix[6] = tr.viewParms.orientation.axis[2][1];
+ viewerMatrix[10] = tr.viewParms.orientation.axis[2][2];
+ viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
+
+ viewerMatrix[3] = 0;
+ viewerMatrix[7] = 0;
+ viewerMatrix[11] = 0;
+ viewerMatrix[15] = 1;
+
+ // convert from our coordinate system (looking down X)
+ // to OpenGL's coordinate system (looking down -Z)
+ myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.orientation.modelMatrix );
+
+ tr.viewParms.world = tr.orientation;
+
+}
+
+/*
+** SetFarClip
+*/
+static void R_SetFarClip( void )
+{
+ float farthestCornerDistance = 0;
+ int i;
+
+ // if not rendering the world (icons, menus, etc)
+ // set a 2k far clip plane
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ tr.viewParms.zFar = 2048;
+ return;
+ }
+
+ //
+ // set far clipping planes dynamically
+ //
+ farthestCornerDistance = 0;
+ for ( i = 0; i < 8; i++ )
+ {
+ vec3_t v;
+ vec3_t vecTo;
+ float distance;
+
+ if ( i & 1 )
+ {
+ v[0] = tr.viewParms.visBounds[0][0];
+ }
+ else
+ {
+ v[0] = tr.viewParms.visBounds[1][0];
+ }
+
+ if ( i & 2 )
+ {
+ v[1] = tr.viewParms.visBounds[0][1];
+ }
+ else
+ {
+ v[1] = tr.viewParms.visBounds[1][1];
+ }
+
+ if ( i & 4 )
+ {
+ v[2] = tr.viewParms.visBounds[0][2];
+ }
+ else
+ {
+ v[2] = tr.viewParms.visBounds[1][2];
+ }
+
+ VectorSubtract( v, tr.viewParms.orientation.origin, vecTo );
+
+ distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2];
+
+ if ( distance > farthestCornerDistance )
+ {
+ farthestCornerDistance = distance;
+ }
+ }
+ tr.viewParms.zFar = sqrt( farthestCornerDistance );
+}
+
+/*
+=================
+R_SetupFrustum
+
+Set up the culling frustum planes for the current view using the results we got from computing the first two rows of
+the projection matrix.
+=================
+*/
+void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float zFar, float stereoSep)
+{
+ vec3_t ofsorigin;
+ float oppleg, adjleg, length;
+ int i;
+
+ if(stereoSep == 0 && xmin == -xmax)
+ {
+ // symmetric case can be simplified
+ VectorCopy(dest->orientation.origin, ofsorigin);
+
+ length = sqrt(xmax * xmax + zProj * zProj);
+ oppleg = xmax / length;
+ adjleg = zProj / length;
+
+ VectorScale(dest->orientation.axis[0], oppleg, dest->frustum[0].normal);
+ VectorMA(dest->frustum[0].normal, adjleg, dest->orientation.axis[1], dest->frustum[0].normal);
+
+ VectorScale(dest->orientation.axis[0], oppleg, dest->frustum[1].normal);
+ VectorMA(dest->frustum[1].normal, -adjleg, dest->orientation.axis[1], dest->frustum[1].normal);
+ }
+ else
+ {
+ // In stereo rendering, due to the modification of the projection matrix, dest->orientation.origin is not the
+ // actual origin that we're rendering so offset the tip of the view pyramid.
+ VectorMA(dest->orientation.origin, stereoSep, dest->orientation.axis[1], ofsorigin);
+
+ oppleg = xmax + stereoSep;
+ length = sqrt(oppleg * oppleg + zProj * zProj);
+ VectorScale(dest->orientation.axis[0], oppleg / length, dest->frustum[0].normal);
+ VectorMA(dest->frustum[0].normal, zProj / length, dest->orientation.axis[1], dest->frustum[0].normal);
+
+ oppleg = xmin + stereoSep;
+ length = sqrt(oppleg * oppleg + zProj * zProj);
+ VectorScale(dest->orientation.axis[0], -oppleg / length, dest->frustum[1].normal);
+ VectorMA(dest->frustum[1].normal, -zProj / length, dest->orientation.axis[1], dest->frustum[1].normal);
+ }
+
+ length = sqrt(ymax * ymax + zProj * zProj);
+ oppleg = ymax / length;
+ adjleg = zProj / length;
+
+ VectorScale(dest->orientation.axis[0], oppleg, dest->frustum[2].normal);
+ VectorMA(dest->frustum[2].normal, adjleg, dest->orientation.axis[2], dest->frustum[2].normal);
+
+ VectorScale(dest->orientation.axis[0], oppleg, dest->frustum[3].normal);
+ VectorMA(dest->frustum[3].normal, -adjleg, dest->orientation.axis[2], dest->frustum[3].normal);
+
+ for (i=0 ; i<4 ; i++) {
+ dest->frustum[i].type = PLANE_NON_AXIAL;
+ dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal);
+ SetPlaneSignbits( &dest->frustum[i] );
+ }
+
+ if (zFar != 0.0f)
+ {
+ vec3_t farpoint;
+
+ VectorMA(ofsorigin, zFar, dest->orientation.axis[0], farpoint);
+ VectorScale(dest->orientation.axis[0], -1.0f, dest->frustum[4].normal);
+
+ dest->frustum[4].type = PLANE_NON_AXIAL;
+ dest->frustum[4].dist = DotProduct (farpoint, dest->frustum[4].normal);
+ SetPlaneSignbits( &dest->frustum[4] );
+ dest->flags |= VPF_FARPLANEFRUSTUM;
+ }
+}
+
+/*
+===============
+R_SetupProjection
+===============
+*/
+void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, bool computeFrustum)
+{
+ float xmin, xmax, ymin, ymax;
+ float width, height, stereoSep = r_stereoSeparation->value;
+
+ /*
+ * offset the view origin of the viewer for stereo rendering
+ * by setting the projection matrix appropriately.
+ */
+
+ if(stereoSep != 0)
+ {
+ if(dest->stereoFrame == STEREO_LEFT)
+ stereoSep = zProj / stereoSep;
+ else if(dest->stereoFrame == STEREO_RIGHT)
+ stereoSep = zProj / -stereoSep;
+ else
+ stereoSep = 0;
+ }
+
+ ymax = zProj * tan(dest->fovY * M_PI / 360.0f);
+ ymin = -ymax;
+
+ xmax = zProj * tan(dest->fovX * M_PI / 360.0f);
+ xmin = -xmax;
+
+ width = xmax - xmin;
+ height = ymax - ymin;
+
+ dest->projectionMatrix[0] = 2 * zProj / width;
+ dest->projectionMatrix[4] = 0;
+ dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width;
+ dest->projectionMatrix[12] = 2 * zProj * stereoSep / width;
+
+ dest->projectionMatrix[1] = 0;
+ dest->projectionMatrix[5] = 2 * zProj / height;
+ dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
+ dest->projectionMatrix[13] = 0;
+
+ dest->projectionMatrix[3] = 0;
+ dest->projectionMatrix[7] = 0;
+ dest->projectionMatrix[11] = -1;
+ dest->projectionMatrix[15] = 0;
+
+ // Now that we have all the data for the projection matrix we can also setup the view frustum.
+ if(computeFrustum)
+ R_SetupFrustum(dest, xmin, xmax, ymax, zProj, zFar, stereoSep);
+}
+
+/*
+===============
+R_SetupProjectionZ
+
+Sets the z-component transformation part in the projection matrix
+===============
+*/
+void R_SetupProjectionZ(viewParms_t *dest)
+{
+ float zNear, zFar, depth;
+
+ zNear = r_znear->value;
+ zFar = dest->zFar;
+
+ depth = zFar - zNear;
+
+ dest->projectionMatrix[2] = 0;
+ dest->projectionMatrix[6] = 0;
+ dest->projectionMatrix[10] = -( zFar + zNear ) / depth;
+ dest->projectionMatrix[14] = -2 * zFar * zNear / depth;
+
+ if (dest->isPortal)
+ {
+ float plane[4];
+ float plane2[4];
+ vec4_t q, c;
+
+ // transform portal plane into camera space
+ plane[0] = dest->portalPlane.normal[0];
+ plane[1] = dest->portalPlane.normal[1];
+ plane[2] = dest->portalPlane.normal[2];
+ plane[3] = dest->portalPlane.dist;
+
+ plane2[0] = -DotProduct (dest->orientation.axis[1], plane);
+ plane2[1] = DotProduct (dest->orientation.axis[2], plane);
+ plane2[2] = -DotProduct (dest->orientation.axis[0], plane);
+ plane2[3] = DotProduct (plane, dest->orientation.origin) - plane[3];
+
+ // Lengyel, Eric. "Modifying the Projection Matrix to Perform Oblique Near-plane Clipping".
+ // Terathon Software 3D Graphics Library, 2004. http://www.terathon.com/code/oblique.html
+ q[0] = (SGN(plane2[0]) + dest->projectionMatrix[8]) / dest->projectionMatrix[0];
+ q[1] = (SGN(plane2[1]) + dest->projectionMatrix[9]) / dest->projectionMatrix[5];
+ q[2] = -1.0f;
+ q[3] = (1.0f + dest->projectionMatrix[10]) / dest->projectionMatrix[14];
+
+ VectorScale4(plane2, 2.0f / DotProduct4(plane2, q), c);
+
+ dest->projectionMatrix[2] = c[0];
+ dest->projectionMatrix[6] = c[1];
+ dest->projectionMatrix[10] = c[2] + 1.0f;
+ dest->projectionMatrix[14] = c[3];
+
+ }
+
+}
+
+/*
+===============
+R_SetupProjectionOrtho
+===============
+*/
+void R_SetupProjectionOrtho(viewParms_t *dest, vec3_t viewBounds[2])
+{
+ float xmin, xmax, ymin, ymax, znear, zfar;
+ //viewParms_t *dest = &tr.viewParms;
+ int i;
+ vec3_t pop;
+
+ // Quake3: Projection:
+ //
+ // Z X Y Z
+ // | / | /
+ // |/ |/
+ // Y--+ +--X
+
+ xmin = viewBounds[0][1];
+ xmax = viewBounds[1][1];
+ ymin = -viewBounds[1][2];
+ ymax = -viewBounds[0][2];
+ znear = viewBounds[0][0];
+ zfar = viewBounds[1][0];
+
+ dest->projectionMatrix[0] = 2 / (xmax - xmin);
+ dest->projectionMatrix[4] = 0;
+ dest->projectionMatrix[8] = 0;
+ dest->projectionMatrix[12] = (xmax + xmin) / (xmax - xmin);
+
+ dest->projectionMatrix[1] = 0;
+ dest->projectionMatrix[5] = 2 / (ymax - ymin);
+ dest->projectionMatrix[9] = 0;
+ dest->projectionMatrix[13] = (ymax + ymin) / (ymax - ymin);
+
+ dest->projectionMatrix[2] = 0;
+ dest->projectionMatrix[6] = 0;
+ dest->projectionMatrix[10] = -2 / (zfar - znear);
+ dest->projectionMatrix[14] = -(zfar + znear) / (zfar - znear);
+
+ dest->projectionMatrix[3] = 0;
+ dest->projectionMatrix[7] = 0;
+ dest->projectionMatrix[11] = 0;
+ dest->projectionMatrix[15] = 1;
+
+ VectorScale(dest->orientation.axis[1], 1.0f, dest->frustum[0].normal);
+ VectorMA(dest->orientation.origin, viewBounds[0][1], dest->frustum[0].normal, pop);
+ dest->frustum[0].dist = DotProduct(pop, dest->frustum[0].normal);
+
+ VectorScale(dest->orientation.axis[1], -1.0f, dest->frustum[1].normal);
+ VectorMA(dest->orientation.origin, -viewBounds[1][1], dest->frustum[1].normal, pop);
+ dest->frustum[1].dist = DotProduct(pop, dest->frustum[1].normal);
+
+ VectorScale(dest->orientation.axis[2], 1.0f, dest->frustum[2].normal);
+ VectorMA(dest->orientation.origin, viewBounds[0][2], dest->frustum[2].normal, pop);
+ dest->frustum[2].dist = DotProduct(pop, dest->frustum[2].normal);
+
+ VectorScale(dest->orientation.axis[2], -1.0f, dest->frustum[3].normal);
+ VectorMA(dest->orientation.origin, -viewBounds[1][2], dest->frustum[3].normal, pop);
+ dest->frustum[3].dist = DotProduct(pop, dest->frustum[3].normal);
+
+ VectorScale(dest->orientation.axis[0], -1.0f, dest->frustum[4].normal);
+ VectorMA(dest->orientation.origin, -viewBounds[1][0], dest->frustum[4].normal, pop);
+ dest->frustum[4].dist = DotProduct(pop, dest->frustum[4].normal);
+
+ for (i = 0; i < 5; i++)
+ {
+ dest->frustum[i].type = PLANE_NON_AXIAL;
+ SetPlaneSignbits (&dest->frustum[i]);
+ }
+
+ dest->flags |= VPF_FARPLANEFRUSTUM;
+}
+
+/*
+=================
+R_MirrorPoint
+=================
+*/
+void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
+ int i;
+ vec3_t local;
+ vec3_t transformed;
+ float d;
+
+ VectorSubtract( in, surface->origin, local );
+
+ VectorClear( transformed );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ d = DotProduct(local, surface->axis[i]);
+ VectorMA( transformed, d, camera->axis[i], transformed );
+ }
+
+ VectorAdd( transformed, camera->origin, out );
+}
+
+void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
+ int i;
+ float d;
+
+ VectorClear( out );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ d = DotProduct(in, surface->axis[i]);
+ VectorMA( out, d, camera->axis[i], out );
+ }
+}
+
+
+/*
+=============
+R_PlaneForSurface
+=============
+*/
+void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) {
+ srfBspSurface_t *tri;
+ srfPoly_t *poly;
+ srfVert_t *v1, *v2, *v3;
+ vec4_t plane4;
+
+ if (!surfType) {
+ Com_Memset (plane, 0, sizeof(*plane));
+ plane->normal[0] = 1;
+ return;
+ }
+ switch (*surfType) {
+ case SF_FACE:
+ *plane = ((srfBspSurface_t *)surfType)->cullPlane;
+ return;
+ case SF_TRIANGLES:
+ tri = (srfBspSurface_t *)surfType;
+ v1 = tri->verts + tri->indexes[0];
+ v2 = tri->verts + tri->indexes[1];
+ v3 = tri->verts + tri->indexes[2];
+ PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz );
+ VectorCopy( plane4, plane->normal );
+ plane->dist = plane4[3];
+ return;
+ case SF_POLY:
+ poly = (srfPoly_t *)surfType;
+ PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz );
+ VectorCopy( plane4, plane->normal );
+ plane->dist = plane4[3];
+ return;
+ default:
+ Com_Memset (plane, 0, sizeof(*plane));
+ plane->normal[0] = 1;
+ return;
+ }
+}
+
+/*
+=================
+R_GetPortalOrientation
+
+entityNum is the entity that the portal surface is a part of, which may
+be moving and rotating.
+
+Returns true if it should be mirrored
+=================
+*/
+bool R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum,
+ orientation_t *surface, orientation_t *camera,
+ vec3_t pvsOrigin, bool *mirror ) {
+ int i;
+ cplane_t originalPlane, plane;
+ trRefEntity_t *e;
+ float d;
+ vec3_t transformed;
+
+ // create plane axis for the portal we are seeing
+ R_PlaneForSurface( drawSurf->surface, &originalPlane );
+
+ // rotate the plane if necessary
+ if ( entityNum != REFENTITYNUM_WORLD ) {
+ tr.currentEntityNum = entityNum;
+ tr.currentEntity = &tr.refdef.entities[entityNum];
+
+ // get the orientation of the entity
+ R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.orientation );
+
+ // rotate the plane, but keep the non-rotated version for matching
+ // against the portalSurface entities
+ R_LocalNormalToWorld( originalPlane.normal, plane.normal );
+ plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.orientation.origin );
+
+ // translate the original plane
+ originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.orientation.origin );
+ } else {
+ plane = originalPlane;
+ }
+
+ VectorCopy( plane.normal, surface->axis[0] );
+ PerpendicularVector( surface->axis[1], surface->axis[0] );
+ CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] );
+
+ // locate the portal entity closest to this plane.
+ // origin will be the origin of the portal, origin2 will be
+ // the origin of the camera
+ for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) {
+ e = &tr.refdef.entities[i];
+ if ( e->e.reType != RT_PORTALSURFACE ) {
+ continue;
+ }
+
+ d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
+ if ( d > 64 || d < -64) {
+ continue;
+ }
+
+ // get the pvsOrigin from the entity
+ VectorCopy( e->e.oldorigin, pvsOrigin );
+
+ // if the entity is just a mirror, don't use as a camera point
+ if ( e->e.oldorigin[0] == e->e.origin[0] &&
+ e->e.oldorigin[1] == e->e.origin[1] &&
+ e->e.oldorigin[2] == e->e.origin[2] ) {
+ VectorScale( plane.normal, plane.dist, surface->origin );
+ VectorCopy( surface->origin, camera->origin );
+ VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] );
+ VectorCopy( surface->axis[1], camera->axis[1] );
+ VectorCopy( surface->axis[2], camera->axis[2] );
+
+ *mirror = true;
+ return true;
+ }
+
+ // project the origin onto the surface plane to get
+ // an origin point we can rotate around
+ d = DotProduct( e->e.origin, plane.normal ) - plane.dist;
+ VectorMA( e->e.origin, -d, surface->axis[0], surface->origin );
+
+ // now get the camera origin and orientation
+ VectorCopy( e->e.oldorigin, camera->origin );
+ AxisCopy( e->e.axis, camera->axis );
+ VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] );
+ VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] );
+
+ // optionally rotate
+ if ( e->e.oldframe ) {
+ // if a speed is specified
+ if ( e->e.frame ) {
+ // continuous rotate
+ d = (tr.refdef.time/1000.0f) * e->e.frame;
+ VectorCopy( camera->axis[1], transformed );
+ RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
+ CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
+ } else {
+ // bobbing rotate, with skinNum being the rotation offset
+ d = sin( tr.refdef.time * 0.003f );
+ d = e->e.skinNum + d * 4;
+ VectorCopy( camera->axis[1], transformed );
+ RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
+ CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
+ }
+ }
+ else if ( e->e.skinNum ) {
+ d = e->e.skinNum;
+ VectorCopy( camera->axis[1], transformed );
+ RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
+ CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
+ }
+ *mirror = false;
+ return true;
+ }
+
+ // if we didn't locate a portal entity, don't render anything.
+ // We don't want to just treat it as a mirror, because without a
+ // portal entity the server won't have communicated a proper entity set
+ // in the snapshot
+
+ // unfortunately, with local movement prediction it is easily possible
+ // to see a surface before the server has communicated the matching
+ // portal surface entity, so we don't want to print anything here...
+
+ //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" );
+
+ return false;
+}
+
+static bool IsMirror( const drawSurf_t *drawSurf, int entityNum )
+{
+ int i;
+ cplane_t originalPlane, plane;
+ trRefEntity_t *e;
+ float d;
+
+ // create plane axis for the portal we are seeing
+ R_PlaneForSurface( drawSurf->surface, &originalPlane );
+
+ // rotate the plane if necessary
+ if ( entityNum != REFENTITYNUM_WORLD )
+ {
+ tr.currentEntityNum = entityNum;
+ tr.currentEntity = &tr.refdef.entities[entityNum];
+
+ // get the orientation of the entity
+ R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.orientation );
+
+ // rotate the plane, but keep the non-rotated version for matching
+ // against the portalSurface entities
+ R_LocalNormalToWorld( originalPlane.normal, plane.normal );
+ plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.orientation.origin );
+
+ // translate the original plane
+ originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.orientation.origin );
+ }
+
+ // locate the portal entity closest to this plane.
+ // origin will be the origin of the portal, origin2 will be
+ // the origin of the camera
+ for ( i = 0 ; i < tr.refdef.num_entities ; i++ )
+ {
+ e = &tr.refdef.entities[i];
+ if ( e->e.reType != RT_PORTALSURFACE ) {
+ continue;
+ }
+
+ d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
+ if ( d > 64 || d < -64) {
+ continue;
+ }
+
+ // if the entity is just a mirror, don't use as a camera point
+ if ( e->e.oldorigin[0] == e->e.origin[0] &&
+ e->e.oldorigin[1] == e->e.origin[1] &&
+ e->e.oldorigin[2] == e->e.origin[2] )
+ {
+ return true;
+ }
+
+ return false;
+ }
+ return false;
+}
+
+/*
+** SurfIsOffscreen
+**
+** Determines if a surface is completely offscreen.
+*/
+static bool SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {
+ float shortest = 100000000;
+ int entityNum;
+ int numTriangles;
+ shader_t *shader;
+ int fogNum;
+ int dlighted;
+ int pshadowed;
+ vec4_t clip, eye;
+ int i;
+ unsigned int pointOr = 0;
+ unsigned int pointAnd = (unsigned int)~0;
+
+ R_RotateForViewer();
+
+ R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed );
+ RB_BeginSurface( shader, fogNum, drawSurf->cubemapIndex);
+ rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
+
+ assert( tess.numVertexes < 128 );
+
+ for ( i = 0; i < tess.numVertexes; i++ )
+ {
+ int j;
+ unsigned int pointFlags = 0;
+
+ R_TransformModelToClip( tess.xyz[i], tr.orientation.modelMatrix, tr.viewParms.projectionMatrix, eye, clip );
+
+ for ( j = 0; j < 3; j++ )
+ {
+ if ( clip[j] >= clip[3] )
+ {
+ pointFlags |= (1 << (j*2));
+ }
+ else if ( clip[j] <= -clip[3] )
+ {
+ pointFlags |= ( 1 << (j*2+1));
+ }
+ }
+ pointAnd &= pointFlags;
+ pointOr |= pointFlags;
+ }
+
+ // trivially reject
+ if ( pointAnd )
+ {
+ return true;
+ }
+
+ // determine if this surface is backfaced and also determine the distance
+ // to the nearest vertex so we can cull based on portal range. Culling
+ // based on vertex distance isn't 100% correct (we should be checking for
+ // range to the surface), but it's good enough for the types of portals
+ // we have in the game right now.
+ numTriangles = tess.numIndexes / 3;
+
+ for ( i = 0; i < tess.numIndexes; i += 3 )
+ {
+ vec3_t normal, tNormal;
+
+ float len;
+
+ VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.orientation.origin, normal );
+
+ len = VectorLengthSquared( normal ); // lose the sqrt
+ if ( len < shortest )
+ {
+ shortest = len;
+ }
+
+ R_VaoUnpackNormal(tNormal, tess.normal[tess.indexes[i]]);
+
+ if ( DotProduct( normal, tNormal ) >= 0 )
+ {
+ numTriangles--;
+ }
+ }
+ if ( !numTriangles )
+ {
+ return true;
+ }
+
+ // mirrors can early out at this point, since we don't do a fade over distance
+ // with them (although we could)
+ if ( IsMirror( drawSurf, entityNum ) )
+ {
+ return false;
+ }
+
+ if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+========================
+R_MirrorViewBySurface
+
+Returns true if another view has been rendered
+========================
+*/
+bool R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) {
+ vec4_t clipDest[128];
+ viewParms_t newParms;
+ viewParms_t oldParms;
+ orientation_t surface, camera;
+
+ // don't recursively mirror
+ if (tr.viewParms.isPortal) {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" );
+ return false;
+ }
+
+ if ( r_noportals->integer || (r_fastsky->integer == 1) ) {
+ return false;
+ }
+
+ // trivially reject portal/mirror
+ if ( SurfIsOffscreen( drawSurf, clipDest ) ) {
+ return false;
+ }
+
+ // save old viewParms so we can return to it after the mirror view
+ oldParms = tr.viewParms;
+
+ newParms = tr.viewParms;
+ newParms.isPortal = true;
+ newParms.zFar = 0.0f;
+ newParms.flags &= ~VPF_FARPLANEFRUSTUM;
+ if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera,
+ newParms.pvsOrigin, &newParms.isMirror ) ) {
+ return false; // bad portal, no portalentity
+ }
+
+ // Never draw viewmodels in portal or mirror views.
+ newParms.flags |= VPF_NOVIEWMODEL;
+
+ R_MirrorPoint (oldParms.orientation.origin, &surface, &camera, newParms.orientation.origin );
+
+ VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal );
+ newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal );
+
+ R_MirrorVector (oldParms.orientation.axis[0], &surface, &camera, newParms.orientation.axis[0]);
+ R_MirrorVector (oldParms.orientation.axis[1], &surface, &camera, newParms.orientation.axis[1]);
+ R_MirrorVector (oldParms.orientation.axis[2], &surface, &camera, newParms.orientation.axis[2]);
+
+ // OPTIMIZE: restrict the viewport on the mirrored view
+
+ // render the mirror view
+ R_RenderView (&newParms);
+
+ tr.viewParms = oldParms;
+
+ return true;
+}
+
+/*
+=================
+R_SpriteFogNum
+
+See if a sprite is inside a fog volume
+=================
+*/
+int R_SpriteFogNum( trRefEntity_t *ent ) {
+ int i, j;
+ fog_t *fog;
+
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ return 0;
+ }
+
+ if ( ent->e.renderfx & RF_CROSSHAIR ) {
+ return 0;
+ }
+
+ for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
+ fog = &tr.world->fogs[i];
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) {
+ break;
+ }
+ if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) {
+ break;
+ }
+ }
+ if ( j == 3 ) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+/*
+==========================================================================================
+
+DRAWSURF SORTING
+
+==========================================================================================
+*/
+
+/*
+===============
+R_Radix
+===============
+*/
+static ID_INLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest )
+{
+ int count[ 256 ] = { 0 };
+ int index[ 256 ];
+ int i;
+ unsigned char *sortKey = NULL;
+ unsigned char *end = NULL;
+
+ sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
+ end = sortKey + ( size * sizeof( drawSurf_t ) );
+ for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) )
+ ++count[ *sortKey ];
+
+ index[ 0 ] = 0;
+
+ for( i = 1; i < 256; ++i )
+ index[ i ] = index[ i - 1 ] + count[ i - 1 ];
+
+ sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
+ for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) )
+ dest[ index[ *sortKey ]++ ] = source[ i ];
+}
+
+/*
+===============
+R_RadixSort
+
+Radix sort with 4 byte size buckets
+===============
+*/
+static void R_RadixSort( drawSurf_t *source, int size )
+{
+ static drawSurf_t scratch[ MAX_DRAWSURFS ];
+#ifdef Q3_LITTLE_ENDIAN
+ R_Radix( 0, size, source, scratch );
+ R_Radix( 1, size, scratch, source );
+ R_Radix( 2, size, source, scratch );
+ R_Radix( 3, size, scratch, source );
+#else
+ R_Radix( 3, size, source, scratch );
+ R_Radix( 2, size, scratch, source );
+ R_Radix( 1, size, source, scratch );
+ R_Radix( 0, size, scratch, source );
+#endif //Q3_LITTLE_ENDIAN
+}
+
+//==========================================================================================
+
+/*
+=================
+R_AddDrawSurf
+=================
+*/
+void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
+ int fogIndex, int dlightMap, int pshadowMap, int cubemap ) {
+ int index;
+
+ // instead of checking for overflow, we just mask the index
+ // so it wraps around
+ index = tr.refdef.numDrawSurfs & DRAWSURF_MASK;
+ // the sort data is packed into a single 32 bit value so it can be
+ // compared quickly during the qsorting process
+ tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT)
+ | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT )
+ | ((int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap;
+ tr.refdef.drawSurfs[index].cubemapIndex = cubemap;
+ tr.refdef.drawSurfs[index].surface = surface;
+ tr.refdef.numDrawSurfs++;
+}
+
+/*
+=================
+R_DecomposeSort
+=================
+*/
+void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
+ int *fogNum, int *dlightMap, int *pshadowMap ) {
+ *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31;
+ *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ];
+ *entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK;
+ *pshadowMap = (sort >> QSORT_PSHADOW_SHIFT ) & 1;
+ *dlightMap = sort & 1;
+}
+
+/*
+=================
+R_SortDrawSurfs
+=================
+*/
+void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
+ shader_t *shader;
+ int fogNum;
+ int entityNum;
+ int dlighted;
+ int pshadowed;
+ int i;
+
+ //ri.Printf(PRINT_ALL, "firstDrawSurf %d numDrawSurfs %d\n", (int)(drawSurfs - tr.refdef.drawSurfs), numDrawSurfs);
+
+ // it is possible for some views to not have any surfaces
+ if ( numDrawSurfs < 1 ) {
+ // we still need to add it for hyperspace cases
+ R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
+ return;
+ }
+
+ // sort the drawsurfs by sort type, then orientation, then shader
+ R_RadixSort( drawSurfs, numDrawSurfs );
+
+ // skip pass through drawing if rendering a shadow map
+ if (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW))
+ {
+ R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
+ return;
+ }
+
+ // check for any pass through drawing, which
+ // may cause another view to be rendered first
+ for ( i = 0 ; i < numDrawSurfs ; i++ ) {
+ R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed );
+
+ if ( shader->sort > SS_PORTAL ) {
+ break;
+ }
+
+ // no shader should ever have this sort type
+ if ( shader->sort == SS_BAD ) {
+ ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name );
+ }
+
+ // if the mirror was completely clipped away, we may need to check another surface
+ if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) {
+ // this is a debug option to see exactly what is being mirrored
+ if ( r_portalOnly->integer ) {
+ return;
+ }
+ break; // only one mirror view at a time
+ }
+ }
+
+ R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
+}
+
+static void R_AddEntitySurface (int entityNum)
+{
+ trRefEntity_t *ent;
+ shader_t *shader;
+
+ tr.currentEntityNum = entityNum;
+
+ ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum];
+
+ ent->needDlights = false;
+
+ // preshift the value we are going to OR into the drawsurf sort
+ tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
+
+ //
+ // the weapon model must be handled special --
+ // we don't want the hacked weapon position showing in
+ // mirrors, because the true body position will already be drawn
+ //
+ if ( (ent->e.renderfx & RF_FIRST_PERSON) && (tr.viewParms.flags & VPF_NOVIEWMODEL)) {
+ return;
+ }
+
+ // simple generated models, like sprites and beams, are not culled
+ switch ( ent->e.reType ) {
+ case RT_PORTALSURFACE:
+ break; // don't draw anything
+ case RT_SPRITE:
+ case RT_BEAM:
+ case RT_LIGHTNING:
+ case RT_RAIL_CORE:
+ case RT_RAIL_RINGS:
+ // self blood sprites, talk balloons, etc should not be drawn in the primary
+ // view. We can't just do this check for all entities, because md3
+ // entities may still want to cast shadows from them
+ if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {
+ return;
+ }
+ shader = R_GetShaderByHandle( ent->e.customShader );
+ R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0, 0, 0 /*cubeMap*/ );
+ break;
+
+ case RT_MODEL:
+ // we must set up parts of tr.or for model culling
+ R_RotateForEntity( ent, &tr.viewParms, &tr.orientation );
+
+ tr.currentModel = R_GetModelByHandle( ent->e.hModel );
+ if (!tr.currentModel) {
+ R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 /*cubeMap*/ );
+ } else {
+ switch ( tr.currentModel->type ) {
+ case MOD_MESH:
+ R_AddMD3Surfaces( ent );
+ break;
+ case MOD_MDR:
+ R_MDRAddAnimSurfaces( ent );
+ break;
+ case MOD_IQM:
+ R_AddIQMSurfaces( ent );
+ break;
+ case MOD_BRUSH:
+ R_AddBrushModelSurfaces( ent );
+ break;
+ case MOD_BAD: // null model axis
+ if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {
+ break;
+ }
+ R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 );
+ break;
+ default:
+ ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" );
+ break;
+ }
+ }
+ break;
+ default:
+ ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" );
+ }
+}
+
+/*
+=============
+R_AddEntitySurfaces
+=============
+*/
+void R_AddEntitySurfaces (void) {
+ int i;
+
+ if ( !r_drawentities->integer ) {
+ return;
+ }
+
+ for ( i = 0; i < tr.refdef.num_entities; i++)
+ R_AddEntitySurface(i);
+}
+
+
+/*
+====================
+R_GenerateDrawSurfs
+====================
+*/
+void R_GenerateDrawSurfs( void ) {
+ R_AddWorldSurfaces ();
+
+ R_AddPolygonSurfaces();
+
+ // set the projection matrix with the minimum zfar
+ // now that we have the world bounded
+ // this needs to be done before entities are
+ // added, because they use the projection
+ // matrix for lod calculation
+
+ // dynamically compute far clip plane distance
+ if (!(tr.viewParms.flags & VPF_SHADOWMAP))
+ {
+ R_SetFarClip();
+ }
+
+ // we know the size of the clipping volume. Now set the rest of the projection matrix.
+ R_SetupProjectionZ (&tr.viewParms);
+
+ R_AddEntitySurfaces ();
+}
+
+/*
+================
+R_DebugPolygon
+================
+*/
+void R_DebugPolygon( int color, int numPoints, float *points ) {
+ // FIXME: implement this
+#if 0
+ int i;
+
+ GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+
+ // draw solid shade
+
+ qglColor3f( color&1, (color>>1)&1, (color>>2)&1 );
+ qglBegin( GL_POLYGON );
+ for ( i = 0 ; i < numPoints ; i++ ) {
+ qglVertex3fv( points + i * 3 );
+ }
+ qglEnd();
+
+ // draw wireframe outline
+ GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+ qglDepthRange( 0, 0 );
+ qglColor3f( 1, 1, 1 );
+ qglBegin( GL_POLYGON );
+ for ( i = 0 ; i < numPoints ; i++ ) {
+ qglVertex3fv( points + i * 3 );
+ }
+ qglEnd();
+ qglDepthRange( 0, 1 );
+#endif
+}
+
+/*
+====================
+R_DebugGraphics
+
+Visualization aid for movement clipping debugging
+====================
+*/
+void R_DebugGraphics( void ) {
+ if ( !r_debugSurface->integer ) {
+ return;
+ }
+
+ R_IssuePendingRenderCommands();
+
+ GL_BindToTMU(tr.whiteImage, TB_COLORMAP);
+ GL_Cull( CT_FRONT_SIDED );
+ ri.CM_DrawDebugSurface( R_DebugPolygon );
+}
+
+
+/*
+================
+R_RenderView
+
+A view may be either the actual camera view,
+or a mirror / remote location
+================
+*/
+void R_RenderView (viewParms_t *parms) {
+ int firstDrawSurf;
+ int numDrawSurfs;
+
+ if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
+ return;
+ }
+
+ tr.viewCount++;
+
+ tr.viewParms = *parms;
+ tr.viewParms.frameSceneNum = tr.frameSceneNum;
+ tr.viewParms.frameCount = tr.frameCount;
+
+ firstDrawSurf = tr.refdef.numDrawSurfs;
+
+ tr.viewCount++;
+
+ // set viewParms.world
+ R_RotateForViewer ();
+
+ R_SetupProjection(&tr.viewParms, r_zproj->value, tr.viewParms.zFar, true);
+
+ R_GenerateDrawSurfs();
+
+ // if we overflowed MAX_DRAWSURFS, the drawsurfs
+ // wrapped around in the buffer and we will be missing
+ // the first surfaces, not the last ones
+ numDrawSurfs = tr.refdef.numDrawSurfs;
+ if ( numDrawSurfs > MAX_DRAWSURFS ) {
+ numDrawSurfs = MAX_DRAWSURFS;
+ }
+
+ R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, numDrawSurfs - firstDrawSurf );
+
+ // draw main system development information (surface outlines, etc)
+ R_DebugGraphics();
+}
+
+
+void R_RenderDlightCubemaps(const refdef_t *fd)
+{
+ int i;
+
+ for (i = 0; i < tr.refdef.num_dlights; i++)
+ {
+ viewParms_t shadowParms;
+ int j;
+
+ // use previous frame to determine visible dlights
+ if ((1 << i) & tr.refdef.dlightMask)
+ continue;
+
+ Com_Memset( &shadowParms, 0, sizeof( shadowParms ) );
+
+ shadowParms.viewportX = tr.refdef.x;
+ shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + PSHADOW_MAP_SIZE );
+ shadowParms.viewportWidth = PSHADOW_MAP_SIZE;
+ shadowParms.viewportHeight = PSHADOW_MAP_SIZE;
+ shadowParms.isPortal = false;
+ shadowParms.isMirror = true; // because it is
+
+ shadowParms.fovX = 90;
+ shadowParms.fovY = 90;
+
+ shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL;
+ shadowParms.zFar = tr.refdef.dlights[i].radius;
+
+ VectorCopy( tr.refdef.dlights[i].origin, shadowParms.orientation.origin );
+
+ for (j = 0; j < 6; j++)
+ {
+ switch(j)
+ {
+ case 0:
+ // -X
+ VectorSet( shadowParms.orientation.axis[0], -1, 0, 0);
+ VectorSet( shadowParms.orientation.axis[1], 0, 0, -1);
+ VectorSet( shadowParms.orientation.axis[2], 0, 1, 0);
+ break;
+ case 1:
+ // +X
+ VectorSet( shadowParms.orientation.axis[0], 1, 0, 0);
+ VectorSet( shadowParms.orientation.axis[1], 0, 0, 1);
+ VectorSet( shadowParms.orientation.axis[2], 0, 1, 0);
+ break;
+ case 2:
+ // -Y
+ VectorSet( shadowParms.orientation.axis[0], 0, -1, 0);
+ VectorSet( shadowParms.orientation.axis[1], 1, 0, 0);
+ VectorSet( shadowParms.orientation.axis[2], 0, 0, -1);
+ break;
+ case 3:
+ // +Y
+ VectorSet( shadowParms.orientation.axis[0], 0, 1, 0);
+ VectorSet( shadowParms.orientation.axis[1], 1, 0, 0);
+ VectorSet( shadowParms.orientation.axis[2], 0, 0, 1);
+ break;
+ case 4:
+ // -Z
+ VectorSet( shadowParms.orientation.axis[0], 0, 0, -1);
+ VectorSet( shadowParms.orientation.axis[1], 1, 0, 0);
+ VectorSet( shadowParms.orientation.axis[2], 0, 1, 0);
+ break;
+ case 5:
+ // +Z
+ VectorSet( shadowParms.orientation.axis[0], 0, 0, 1);
+ VectorSet( shadowParms.orientation.axis[1], -1, 0, 0);
+ VectorSet( shadowParms.orientation.axis[2], 0, 1, 0);
+ break;
+ }
+
+ R_RenderView(&shadowParms);
+ R_AddCapShadowmapCmd( i, j );
+ }
+ }
+}
+
+
+void R_RenderPshadowMaps(const refdef_t *fd)
+{
+ viewParms_t shadowParms;
+ int i;
+
+ // first, make a list of shadows
+ for ( i = 0; i < tr.refdef.num_entities; i++)
+ {
+ trRefEntity_t *ent = &tr.refdef.entities[i];
+
+ if((ent->e.renderfx & (RF_FIRST_PERSON | RF_NOSHADOW)))
+ continue;
+
+ //if((ent->e.renderfx & RF_THIRD_PERSON))
+ //continue;
+
+ if (ent->e.reType == RT_MODEL)
+ {
+ model_t *model = R_GetModelByHandle( ent->e.hModel );
+ pshadow_t shadow;
+ float radius = 0.0f;
+ float scale = 1.0f;
+ vec3_t diff;
+ int j;
+
+ if (!model)
+ continue;
+
+ if (ent->e.nonNormalizedAxes)
+ {
+ scale = VectorLength( ent->e.axis[0] );
+ }
+
+ switch (model->type)
+ {
+ case MOD_MESH:
+ {
+ mdvFrame_t *frame = &model->mdv[0]->frames[ent->e.frame];
+
+ radius = frame->radius * scale;
+ }
+ break;
+
+ case MOD_MDR:
+ {
+ // FIXME: never actually tested this
+ mdrHeader_t *header = (mdrHeader_t*)model->modelData;
+ int frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
+ mdrFrame_t *frame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
+
+ radius = frame->radius;
+ }
+ break;
+ case MOD_IQM:
+ {
+ // FIXME: never actually tested this
+ iqmData_t *data = (iqmData_t*)model->modelData;
+ vec3_t diag;
+ float *framebounds;
+
+ framebounds = data->bounds + 6*ent->e.frame;
+ VectorSubtract( framebounds+3, framebounds, diag );
+ radius = 0.5f * VectorLength( diag );
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (!radius)
+ continue;
+
+ // Cull entities that are behind the viewer by more than lightRadius
+ VectorSubtract(ent->e.origin, fd->vieworg, diff);
+ if (DotProduct(diff, fd->viewaxis[0]) < -r_pshadowDist->value)
+ continue;
+
+ memset(&shadow, 0, sizeof(shadow));
+
+ shadow.numEntities = 1;
+ shadow.entityNums[0] = i;
+ shadow.viewRadius = radius;
+ shadow.lightRadius = r_pshadowDist->value;
+ VectorCopy(ent->e.origin, shadow.viewOrigin);
+ shadow.sort = DotProduct(diff, diff) / (radius * radius);
+ VectorCopy(ent->e.origin, shadow.entityOrigins[0]);
+ shadow.entityRadiuses[0] = radius;
+
+ for (j = 0; j < MAX_CALC_PSHADOWS; j++)
+ {
+ pshadow_t swap;
+
+ if (j + 1 > tr.refdef.num_pshadows)
+ {
+ tr.refdef.num_pshadows = j + 1;
+ tr.refdef.pshadows[j] = shadow;
+ break;
+ }
+
+ // sort shadows by distance from camera divided by radius
+ // FIXME: sort better
+ if (tr.refdef.pshadows[j].sort <= shadow.sort)
+ continue;
+
+ swap = tr.refdef.pshadows[j];
+ tr.refdef.pshadows[j] = shadow;
+ shadow = swap;
+ }
+ }
+ }
+
+ // next, merge touching pshadows
+ for ( i = 0; i < tr.refdef.num_pshadows; i++)
+ {
+ pshadow_t *ps1 = &tr.refdef.pshadows[i];
+ int j;
+
+ for (j = i + 1; j < tr.refdef.num_pshadows; j++)
+ {
+ pshadow_t *ps2 = &tr.refdef.pshadows[j];
+ int k;
+ bool touch;
+
+ if (ps1->numEntities == 8)
+ break;
+
+ touch = false;
+ if (SpheresIntersect(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius))
+ {
+ for (k = 0; k < ps1->numEntities; k++)
+ {
+ if (SpheresIntersect(ps1->entityOrigins[k], ps1->entityRadiuses[k], ps2->viewOrigin, ps2->viewRadius))
+ {
+ touch = true;
+ break;
+ }
+ }
+ }
+
+ if (touch)
+ {
+ vec3_t newOrigin;
+ float newRadius;
+
+ BoundingSphereOfSpheres(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius, newOrigin, &newRadius);
+ VectorCopy(newOrigin, ps1->viewOrigin);
+ ps1->viewRadius = newRadius;
+
+ ps1->entityNums[ps1->numEntities] = ps2->entityNums[0];
+ VectorCopy(ps2->viewOrigin, ps1->entityOrigins[ps1->numEntities]);
+ ps1->entityRadiuses[ps1->numEntities] = ps2->viewRadius;
+
+ ps1->numEntities++;
+
+ for (k = j; k < tr.refdef.num_pshadows - 1; k++)
+ {
+ tr.refdef.pshadows[k] = tr.refdef.pshadows[k + 1];
+ }
+
+ j--;
+ tr.refdef.num_pshadows--;
+ }
+ }
+ }
+
+ // cap number of drawn pshadows
+ if (tr.refdef.num_pshadows > MAX_DRAWN_PSHADOWS)
+ {
+ tr.refdef.num_pshadows = MAX_DRAWN_PSHADOWS;
+ }
+
+ // next, fill up the rest of the shadow info
+ for ( i = 0; i < tr.refdef.num_pshadows; i++)
+ {
+ pshadow_t *shadow = &tr.refdef.pshadows[i];
+ vec3_t up;
+ vec3_t ambientLight, directedLight, lightDir;
+
+ VectorSet(lightDir, 0.57735f, 0.57735f, 0.57735f);
+#if 1
+ R_LightForPoint(shadow->viewOrigin, ambientLight, directedLight, lightDir);
+
+ // sometimes there's no light
+ if (DotProduct(lightDir, lightDir) < 0.9f)
+ VectorSet(lightDir, 0.0f, 0.0f, 1.0f);
+#endif
+
+ if (shadow->viewRadius * 3.0f > shadow->lightRadius)
+ {
+ shadow->lightRadius = shadow->viewRadius * 3.0f;
+ }
+
+ VectorMA(shadow->viewOrigin, shadow->viewRadius, lightDir, shadow->lightOrigin);
+
+ // make up a projection, up doesn't matter
+ VectorScale(lightDir, -1.0f, shadow->lightViewAxis[0]);
+ VectorSet(up, 0, 0, -1);
+
+ if ( fabsf(DotProduct(up, shadow->lightViewAxis[0])) > 0.9f )
+ {
+ VectorSet(up, -1, 0, 0);
+ }
+
+ CrossProduct(shadow->lightViewAxis[0], up, shadow->lightViewAxis[1]);
+ VectorNormalize(shadow->lightViewAxis[1]);
+ CrossProduct(shadow->lightViewAxis[0], shadow->lightViewAxis[1], shadow->lightViewAxis[2]);
+
+ VectorCopy(shadow->lightViewAxis[0], shadow->cullPlane.normal);
+ shadow->cullPlane.dist = DotProduct(shadow->cullPlane.normal, shadow->lightOrigin);
+ shadow->cullPlane.type = PLANE_NON_AXIAL;
+ SetPlaneSignbits(&shadow->cullPlane);
+ }
+
+ // next, render shadowmaps
+ for ( i = 0; i < tr.refdef.num_pshadows; i++)
+ {
+ int firstDrawSurf;
+ pshadow_t *shadow = &tr.refdef.pshadows[i];
+ int j;
+
+ Com_Memset( &shadowParms, 0, sizeof( shadowParms ) );
+
+ if (glRefConfig.framebufferObject)
+ {
+ shadowParms.viewportX = 0;
+ shadowParms.viewportY = 0;
+ }
+ else
+ {
+ shadowParms.viewportX = tr.refdef.x;
+ shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + PSHADOW_MAP_SIZE );
+ }
+ shadowParms.viewportWidth = PSHADOW_MAP_SIZE;
+ shadowParms.viewportHeight = PSHADOW_MAP_SIZE;
+ shadowParms.isPortal = false;
+ shadowParms.isMirror = false;
+
+ shadowParms.fovX = 90;
+ shadowParms.fovY = 90;
+
+ if (glRefConfig.framebufferObject)
+ shadowParms.targetFbo = tr.pshadowFbos[i];
+
+ shadowParms.flags = VPF_DEPTHSHADOW | VPF_NOVIEWMODEL;
+ shadowParms.zFar = shadow->lightRadius;
+
+ VectorCopy(shadow->lightOrigin, shadowParms.orientation.origin);
+
+ VectorCopy(shadow->lightViewAxis[0], shadowParms.orientation.axis[0]);
+ VectorCopy(shadow->lightViewAxis[1], shadowParms.orientation.axis[1]);
+ VectorCopy(shadow->lightViewAxis[2], shadowParms.orientation.axis[2]);
+
+ {
+ tr.viewCount++;
+
+ tr.viewParms = shadowParms;
+ tr.viewParms.frameSceneNum = tr.frameSceneNum;
+ tr.viewParms.frameCount = tr.frameCount;
+
+ firstDrawSurf = tr.refdef.numDrawSurfs;
+
+ tr.viewCount++;
+
+ // set viewParms.world
+ R_RotateForViewer ();
+
+ {
+ float xmin, xmax, ymin, ymax, znear, zfar;
+ viewParms_t *dest = &tr.viewParms;
+ vec3_t pop;
+
+ xmin = ymin = -shadow->viewRadius;
+ xmax = ymax = shadow->viewRadius;
+ znear = 0;
+ zfar = shadow->lightRadius;
+
+ dest->projectionMatrix[0] = 2 / (xmax - xmin);
+ dest->projectionMatrix[4] = 0;
+ dest->projectionMatrix[8] = (xmax + xmin) / (xmax - xmin);
+ dest->projectionMatrix[12] =0;
+
+ dest->projectionMatrix[1] = 0;
+ dest->projectionMatrix[5] = 2 / (ymax - ymin);
+ dest->projectionMatrix[9] = ( ymax + ymin ) / (ymax - ymin); // normally 0
+ dest->projectionMatrix[13] = 0;
+
+ dest->projectionMatrix[2] = 0;
+ dest->projectionMatrix[6] = 0;
+ dest->projectionMatrix[10] = 2 / (zfar - znear);
+ dest->projectionMatrix[14] = 0;
+
+ dest->projectionMatrix[3] = 0;
+ dest->projectionMatrix[7] = 0;
+ dest->projectionMatrix[11] = 0;
+ dest->projectionMatrix[15] = 1;
+
+ VectorScale(dest->orientation.axis[1], 1.0f, dest->frustum[0].normal);
+ VectorMA(dest->orientation.origin, -shadow->viewRadius, dest->frustum[0].normal, pop);
+ dest->frustum[0].dist = DotProduct(pop, dest->frustum[0].normal);
+
+ VectorScale(dest->orientation.axis[1], -1.0f, dest->frustum[1].normal);
+ VectorMA(dest->orientation.origin, -shadow->viewRadius, dest->frustum[1].normal, pop);
+ dest->frustum[1].dist = DotProduct(pop, dest->frustum[1].normal);
+
+ VectorScale(dest->orientation.axis[2], 1.0f, dest->frustum[2].normal);
+ VectorMA(dest->orientation.origin, -shadow->viewRadius, dest->frustum[2].normal, pop);
+ dest->frustum[2].dist = DotProduct(pop, dest->frustum[2].normal);
+
+ VectorScale(dest->orientation.axis[2], -1.0f, dest->frustum[3].normal);
+ VectorMA(dest->orientation.origin, -shadow->viewRadius, dest->frustum[3].normal, pop);
+ dest->frustum[3].dist = DotProduct(pop, dest->frustum[3].normal);
+
+ VectorScale(dest->orientation.axis[0], -1.0f, dest->frustum[4].normal);
+ VectorMA(dest->orientation.origin, -shadow->lightRadius, dest->frustum[4].normal, pop);
+ dest->frustum[4].dist = DotProduct(pop, dest->frustum[4].normal);
+
+ for (j = 0; j < 5; j++)
+ {
+ dest->frustum[j].type = PLANE_NON_AXIAL;
+ SetPlaneSignbits (&dest->frustum[j]);
+ }
+
+ dest->flags |= VPF_FARPLANEFRUSTUM;
+ }
+
+ for (j = 0; j < shadow->numEntities; j++)
+ {
+ R_AddEntitySurface(shadow->entityNums[j]);
+ }
+
+ R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );
+
+ if (!glRefConfig.framebufferObject)
+ R_AddCapShadowmapCmd( i, -1 );
+ }
+ }
+}
+
+static float CalcSplit(float n, float f, float i, float m)
+{
+ return (n * pow(f / n, i / m) + (f - n) * i / m) / 2.0f;
+}
+
+
+void R_RenderSunShadowMaps(const refdef_t *fd, int level)
+{
+ viewParms_t shadowParms;
+ vec4_t lightDir, lightCol;
+ vec3_t lightViewAxis[3];
+ vec3_t lightOrigin;
+ float splitZNear, splitZFar, splitBias;
+ float viewZNear, viewZFar;
+ vec3_t lightviewBounds[2];
+ bool lightViewIndependentOfCameraView = false;
+
+ if (r_forceSun->integer == 2)
+ {
+ int scale = 32768;
+ float angle = (fd->time % scale) / (float)scale * M_PI;
+ lightDir[0] = cos(angle);
+ lightDir[1] = sin(35.0f * M_PI / 180.0f);
+ lightDir[2] = sin(angle) * cos(35.0f * M_PI / 180.0f);
+ lightDir[3] = 0.0f;
+
+ if (1) //((fd->time % (scale * 2)) < scale)
+ {
+ lightCol[0] =
+ lightCol[1] =
+ lightCol[2] = CLAMP(sin(angle) * 2.0f, 0.0f, 1.0f) * 2.0f;
+ lightCol[3] = 1.0f;
+ }
+ else
+ {
+ lightCol[0] =
+ lightCol[1] =
+ lightCol[2] = CLAMP(sin(angle) * 2.0f * 0.1f, 0.0f, 0.1f);
+ lightCol[3] = 1.0f;
+ }
+
+ VectorCopy4(lightDir, tr.refdef.sunDir);
+ VectorCopy4(lightCol, tr.refdef.sunCol);
+ VectorScale4(lightCol, 0.2f, tr.refdef.sunAmbCol);
+ }
+ else
+ {
+ VectorCopy4(tr.refdef.sunDir, lightDir);
+ }
+
+ viewZNear = r_shadowCascadeZNear->value;
+ viewZFar = r_shadowCascadeZFar->value;
+ splitBias = r_shadowCascadeZBias->value;
+
+ switch(level)
+ {
+ case 0:
+ default:
+ //splitZNear = r_znear->value;
+ //splitZFar = 256;
+ splitZNear = viewZNear;
+ splitZFar = CalcSplit(viewZNear, viewZFar, 1, 3) + splitBias;
+ break;
+ case 1:
+ splitZNear = CalcSplit(viewZNear, viewZFar, 1, 3) + splitBias;
+ splitZFar = CalcSplit(viewZNear, viewZFar, 2, 3) + splitBias;
+ //splitZNear = 256;
+ //splitZFar = 896;
+ break;
+ case 2:
+ splitZNear = CalcSplit(viewZNear, viewZFar, 2, 3) + splitBias;
+ splitZFar = viewZFar;
+ //splitZNear = 896;
+ //splitZFar = 3072;
+ break;
+ }
+
+ if (level != 3)
+ VectorCopy(fd->vieworg, lightOrigin);
+ else
+ VectorCopy(tr.world->lightGridOrigin, lightOrigin);
+
+ // Make up a projection
+ VectorScale(lightDir, -1.0f, lightViewAxis[0]);
+
+ if (level == 3 || lightViewIndependentOfCameraView)
+ {
+ // Use world up as light view up
+ VectorSet(lightViewAxis[2], 0, 0, 1);
+ }
+ else if (level == 0)
+ {
+ // Level 0 tries to use a diamond texture orientation relative to camera view
+ // Use halfway between camera view forward and left for light view up
+ VectorAdd(fd->viewaxis[0], fd->viewaxis[1], lightViewAxis[2]);
+ }
+ else
+ {
+ // Use camera view up as light view up
+ VectorCopy(fd->viewaxis[2], lightViewAxis[2]);
+ }
+
+ // Check if too close to parallel to light direction
+ if (fabsf(DotProduct(lightViewAxis[2], lightViewAxis[0])) > 0.9f)
+ {
+ if (level == 3 || lightViewIndependentOfCameraView)
+ {
+ // Use world left as light view up
+ VectorSet(lightViewAxis[2], 0, 1, 0);
+ }
+ else if (level == 0)
+ {
+ // Level 0 tries to use a diamond texture orientation relative to camera view
+ // Use halfway between camera view forward and up for light view up
+ VectorAdd(fd->viewaxis[0], fd->viewaxis[2], lightViewAxis[2]);
+ }
+ else
+ {
+ // Use camera view left as light view up
+ VectorCopy(fd->viewaxis[1], lightViewAxis[2]);
+ }
+ }
+
+ // clean axes
+ CrossProduct(lightViewAxis[2], lightViewAxis[0], lightViewAxis[1]);
+ VectorNormalize(lightViewAxis[1]);
+ CrossProduct(lightViewAxis[0], lightViewAxis[1], lightViewAxis[2]);
+
+ // Create bounds for light projection using slice of view projection
+ {
+ mat4_t lightViewMatrix;
+ vec4_t point, base, lightViewPoint;
+ float lx, ly;
+
+ base[3] = 1;
+ point[3] = 1;
+ lightViewPoint[3] = 1;
+
+ Mat4View(lightViewAxis, lightOrigin, lightViewMatrix);
+
+ ClearBounds(lightviewBounds[0], lightviewBounds[1]);
+
+ if (level != 3)
+ {
+ // add view near plane
+ lx = splitZNear * tan(fd->fov_x * M_PI / 360.0f);
+ ly = splitZNear * tan(fd->fov_y * M_PI / 360.0f);
+ VectorMA(fd->vieworg, splitZNear, fd->viewaxis[0], base);
+
+ VectorMA(base, lx, fd->viewaxis[1], point);
+ VectorMA(point, ly, fd->viewaxis[2], point);
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ VectorMA(base, -lx, fd->viewaxis[1], point);
+ VectorMA(point, ly, fd->viewaxis[2], point);
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ VectorMA(base, lx, fd->viewaxis[1], point);
+ VectorMA(point, -ly, fd->viewaxis[2], point);
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ VectorMA(base, -lx, fd->viewaxis[1], point);
+ VectorMA(point, -ly, fd->viewaxis[2], point);
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+
+ // add view far plane
+ lx = splitZFar * tan(fd->fov_x * M_PI / 360.0f);
+ ly = splitZFar * tan(fd->fov_y * M_PI / 360.0f);
+ VectorMA(fd->vieworg, splitZFar, fd->viewaxis[0], base);
+
+ VectorMA(base, lx, fd->viewaxis[1], point);
+ VectorMA(point, ly, fd->viewaxis[2], point);
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ VectorMA(base, -lx, fd->viewaxis[1], point);
+ VectorMA(point, ly, fd->viewaxis[2], point);
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ VectorMA(base, lx, fd->viewaxis[1], point);
+ VectorMA(point, -ly, fd->viewaxis[2], point);
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ VectorMA(base, -lx, fd->viewaxis[1], point);
+ VectorMA(point, -ly, fd->viewaxis[2], point);
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+ }
+ else
+ {
+ // use light grid size as level size
+ // FIXME: could be tighter
+ vec3_t bounds;
+
+ bounds[0] = tr.world->lightGridSize[0] * tr.world->lightGridBounds[0];
+ bounds[1] = tr.world->lightGridSize[1] * tr.world->lightGridBounds[1];
+ bounds[2] = tr.world->lightGridSize[2] * tr.world->lightGridBounds[2];
+
+ point[0] = tr.world->lightGridOrigin[0];
+ point[1] = tr.world->lightGridOrigin[1];
+ point[2] = tr.world->lightGridOrigin[2];
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ point[0] = tr.world->lightGridOrigin[0] + bounds[0];
+ point[1] = tr.world->lightGridOrigin[1];
+ point[2] = tr.world->lightGridOrigin[2];
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ point[0] = tr.world->lightGridOrigin[0];
+ point[1] = tr.world->lightGridOrigin[1] + bounds[1];
+ point[2] = tr.world->lightGridOrigin[2];
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ point[0] = tr.world->lightGridOrigin[0] + bounds[0];
+ point[1] = tr.world->lightGridOrigin[1] + bounds[1];
+ point[2] = tr.world->lightGridOrigin[2];
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ point[0] = tr.world->lightGridOrigin[0];
+ point[1] = tr.world->lightGridOrigin[1];
+ point[2] = tr.world->lightGridOrigin[2] + bounds[2];
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ point[0] = tr.world->lightGridOrigin[0] + bounds[0];
+ point[1] = tr.world->lightGridOrigin[1];
+ point[2] = tr.world->lightGridOrigin[2] + bounds[2];
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ point[0] = tr.world->lightGridOrigin[0];
+ point[1] = tr.world->lightGridOrigin[1] + bounds[1];
+ point[2] = tr.world->lightGridOrigin[2] + bounds[2];
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+
+ point[0] = tr.world->lightGridOrigin[0] + bounds[0];
+ point[1] = tr.world->lightGridOrigin[1] + bounds[1];
+ point[2] = tr.world->lightGridOrigin[2] + bounds[2];
+ Mat4Transform(lightViewMatrix, point, lightViewPoint);
+ AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
+ }
+
+ if (!glRefConfig.depthClamp)
+ lightviewBounds[0][0] = lightviewBounds[1][0] - 8192;
+
+ // Moving the Light in Texel-Sized Increments
+ // from http://msdn.microsoft.com/en-us/library/windows/desktop/ee416324%28v=vs.85%29.aspx
+ //
+ if (lightViewIndependentOfCameraView)
+ {
+ float cascadeBound, worldUnitsPerTexel, invWorldUnitsPerTexel;
+
+ cascadeBound = MAX(lightviewBounds[1][0] - lightviewBounds[0][0], lightviewBounds[1][1] - lightviewBounds[0][1]);
+ cascadeBound = MAX(cascadeBound, lightviewBounds[1][2] - lightviewBounds[0][2]);
+ worldUnitsPerTexel = cascadeBound / tr.sunShadowFbo[level]->width;
+ invWorldUnitsPerTexel = 1.0f / worldUnitsPerTexel;
+
+ VectorScale(lightviewBounds[0], invWorldUnitsPerTexel, lightviewBounds[0]);
+ lightviewBounds[0][0] = floor(lightviewBounds[0][0]);
+ lightviewBounds[0][1] = floor(lightviewBounds[0][1]);
+ lightviewBounds[0][2] = floor(lightviewBounds[0][2]);
+ VectorScale(lightviewBounds[0], worldUnitsPerTexel, lightviewBounds[0]);
+
+ VectorScale(lightviewBounds[1], invWorldUnitsPerTexel, lightviewBounds[1]);
+ lightviewBounds[1][0] = floor(lightviewBounds[1][0]);
+ lightviewBounds[1][1] = floor(lightviewBounds[1][1]);
+ lightviewBounds[1][2] = floor(lightviewBounds[1][2]);
+ VectorScale(lightviewBounds[1], worldUnitsPerTexel, lightviewBounds[1]);
+ }
+
+ //ri.Printf(PRINT_ALL, "level %d znear %f zfar %f\n", level, lightviewBounds[0][0], lightviewBounds[1][0]);
+ //ri.Printf(PRINT_ALL, "xmin %f xmax %f ymin %f ymax %f\n", lightviewBounds[0][1], lightviewBounds[1][1], -lightviewBounds[1][2], -lightviewBounds[0][2]);
+ }
+
+ {
+ int firstDrawSurf;
+
+ Com_Memset( &shadowParms, 0, sizeof( shadowParms ) );
+
+ if (glRefConfig.framebufferObject)
+ {
+ shadowParms.viewportX = 0;
+ shadowParms.viewportY = 0;
+ }
+ else
+ {
+ shadowParms.viewportX = tr.refdef.x;
+ shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.sunShadowFbo[level]->height );
+ }
+ shadowParms.viewportWidth = tr.sunShadowFbo[level]->width;
+ shadowParms.viewportHeight = tr.sunShadowFbo[level]->height;
+ shadowParms.isPortal = false;
+ shadowParms.isMirror = false;
+
+ shadowParms.fovX = 90;
+ shadowParms.fovY = 90;
+
+ if (glRefConfig.framebufferObject)
+ shadowParms.targetFbo = tr.sunShadowFbo[level];
+
+ shadowParms.flags = VPF_DEPTHSHADOW | VPF_DEPTHCLAMP | VPF_ORTHOGRAPHIC | VPF_NOVIEWMODEL;
+ shadowParms.zFar = lightviewBounds[1][0];
+
+ VectorCopy(lightOrigin, shadowParms.orientation.origin);
+
+ VectorCopy(lightViewAxis[0], shadowParms.orientation.axis[0]);
+ VectorCopy(lightViewAxis[1], shadowParms.orientation.axis[1]);
+ VectorCopy(lightViewAxis[2], shadowParms.orientation.axis[2]);
+
+ VectorCopy(lightOrigin, shadowParms.pvsOrigin );
+
+ {
+ tr.viewCount++;
+
+ tr.viewParms = shadowParms;
+ tr.viewParms.frameSceneNum = tr.frameSceneNum;
+ tr.viewParms.frameCount = tr.frameCount;
+
+ firstDrawSurf = tr.refdef.numDrawSurfs;
+
+ tr.viewCount++;
+
+ // set viewParms.world
+ R_RotateForViewer ();
+
+ R_SetupProjectionOrtho(&tr.viewParms, lightviewBounds);
+
+ R_AddWorldSurfaces ();
+
+ R_AddPolygonSurfaces();
+
+ R_AddEntitySurfaces ();
+
+ R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );
+ }
+
+ Mat4Multiply(tr.viewParms.projectionMatrix, tr.viewParms.world.modelMatrix, tr.refdef.sunShadowMvp[level]);
+ }
+}
+
+void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, bool subscene )
+{
+ refdef_t refdef;
+ viewParms_t parms;
+
+ memset( &refdef, 0, sizeof( refdef ) );
+ refdef.rdflags = 0;
+ VectorCopy(tr.cubemaps[cubemapIndex].origin, refdef.vieworg);
+
+ switch(cubemapSide)
+ {
+ case 0:
+ // -X
+ VectorSet( refdef.viewaxis[0], -1, 0, 0);
+ VectorSet( refdef.viewaxis[1], 0, 0, -1);
+ VectorSet( refdef.viewaxis[2], 0, 1, 0);
+ break;
+ case 1:
+ // +X
+ VectorSet( refdef.viewaxis[0], 1, 0, 0);
+ VectorSet( refdef.viewaxis[1], 0, 0, 1);
+ VectorSet( refdef.viewaxis[2], 0, 1, 0);
+ break;
+ case 2:
+ // -Y
+ VectorSet( refdef.viewaxis[0], 0, -1, 0);
+ VectorSet( refdef.viewaxis[1], 1, 0, 0);
+ VectorSet( refdef.viewaxis[2], 0, 0, -1);
+ break;
+ case 3:
+ // +Y
+ VectorSet( refdef.viewaxis[0], 0, 1, 0);
+ VectorSet( refdef.viewaxis[1], 1, 0, 0);
+ VectorSet( refdef.viewaxis[2], 0, 0, 1);
+ break;
+ case 4:
+ // -Z
+ VectorSet( refdef.viewaxis[0], 0, 0, -1);
+ VectorSet( refdef.viewaxis[1], 1, 0, 0);
+ VectorSet( refdef.viewaxis[2], 0, 1, 0);
+ break;
+ case 5:
+ // +Z
+ VectorSet( refdef.viewaxis[0], 0, 0, 1);
+ VectorSet( refdef.viewaxis[1], -1, 0, 0);
+ VectorSet( refdef.viewaxis[2], 0, 1, 0);
+ break;
+ }
+
+ refdef.fov_x = 90;
+ refdef.fov_y = 90;
+
+ refdef.x = 0;
+ refdef.y = 0;
+ refdef.width = tr.renderCubeFbo->width;
+ refdef.height = tr.renderCubeFbo->height;
+
+ refdef.time = 0;
+
+ if (!subscene)
+ {
+ RE_BeginScene(&refdef);
+
+ // FIXME: sun shadows aren't rendered correctly in cubemaps
+ // fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first
+ if(0) //(glRefConfig.framebufferObject && r_sunlightMode->integer && (r_forceSun->integer || tr.sunShadows))
+ {
+ R_RenderSunShadowMaps(&refdef, 0);
+ R_RenderSunShadowMaps(&refdef, 1);
+ R_RenderSunShadowMaps(&refdef, 2);
+ R_RenderSunShadowMaps(&refdef, 3);
+ }
+ }
+
+ {
+ vec3_t ambient, directed, lightDir;
+ float scale;
+
+ R_LightForPoint(tr.refdef.vieworg, ambient, directed, lightDir);
+ scale = directed[0] + directed[1] + directed[2] + ambient[0] + ambient[1] + ambient[2] + 1.0f;
+
+ // only print message for first side
+ if (scale < 1.0001f && cubemapSide == 0)
+ {
+ ri.Printf(PRINT_ALL, "cubemap %d %s (%f, %f, %f) is outside the lightgrid or inside a wall!\n", cubemapIndex, tr.cubemaps[cubemapIndex].name, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]);
+ }
+ }
+
+ Com_Memset( &parms, 0, sizeof( parms ) );
+
+ parms.viewportX = 0;
+ parms.viewportY = 0;
+ parms.viewportWidth = tr.renderCubeFbo->width;
+ parms.viewportHeight = tr.renderCubeFbo->height;
+ parms.isPortal = false;
+ parms.isMirror = true;
+ parms.flags = VPF_NOVIEWMODEL | VPF_NOCUBEMAPS;
+
+ parms.fovX = 90;
+ parms.fovY = 90;
+
+ VectorCopy( refdef.vieworg, parms.orientation.origin );
+ VectorCopy( refdef.viewaxis[0], parms.orientation.axis[0] );
+ VectorCopy( refdef.viewaxis[1], parms.orientation.axis[1] );
+ VectorCopy( refdef.viewaxis[2], parms.orientation.axis[2] );
+
+ VectorCopy( refdef.vieworg, parms.pvsOrigin );
+
+ // FIXME: sun shadows aren't rendered correctly in cubemaps
+ // fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first
+ if (0) //(r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows))
+ {
+ parms.flags = VPF_USESUNLIGHT;
+ }
+
+ parms.targetFbo = tr.renderCubeFbo;
+ parms.targetFboLayer = cubemapSide;
+ parms.targetFboCubemapIndex = cubemapIndex;
+
+ R_RenderView(&parms);
+
+ if (!subscene)
+ RE_EndScene();
+}
diff --git a/src/renderergl2/tr_marks.cpp b/src/renderergl2/tr_marks.cpp
new file mode 100644
index 0000000..b56005a
--- /dev/null
+++ b/src/renderergl2/tr_marks.cpp
@@ -0,0 +1,472 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_marks.c -- polygon projection on the world polygons
+
+#include "tr_local.h"
+//#include "assert.h"
+
+#define MAX_VERTS_ON_POLY 64
+
+#define MARKER_OFFSET 0 // 1
+
+/*
+=============
+R_ChopPolyBehindPlane
+
+Out must have space for two more vertexes than in
+=============
+*/
+#define SIDE_FRONT 0
+#define SIDE_BACK 1
+#define SIDE_ON 2
+static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY],
+ int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY],
+ vec3_t normal, vec_t dist, vec_t epsilon) {
+ float dists[MAX_VERTS_ON_POLY+4] = { 0 };
+ int sides[MAX_VERTS_ON_POLY+4] = { 0 };
+ int counts[3];
+ float dot;
+ int i, j;
+ float *p1, *p2, *clip;
+ float d;
+
+ // don't clip if it might overflow
+ if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) {
+ *numOutPoints = 0;
+ return;
+ }
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+ // determine sides for each point
+ for ( i = 0 ; i < numInPoints ; i++ ) {
+ dot = DotProduct( inPoints[i], normal );
+ dot -= dist;
+ dists[i] = dot;
+ if ( dot > epsilon ) {
+ sides[i] = SIDE_FRONT;
+ } else if ( dot < -epsilon ) {
+ sides[i] = SIDE_BACK;
+ } else {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ *numOutPoints = 0;
+
+ if ( !counts[0] ) {
+ return;
+ }
+ if ( !counts[1] ) {
+ *numOutPoints = numInPoints;
+ Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) );
+ return;
+ }
+
+ for ( i = 0 ; i < numInPoints ; i++ ) {
+ p1 = inPoints[i];
+ clip = outPoints[ *numOutPoints ];
+
+ if ( sides[i] == SIDE_ON ) {
+ VectorCopy( p1, clip );
+ (*numOutPoints)++;
+ continue;
+ }
+
+ if ( sides[i] == SIDE_FRONT ) {
+ VectorCopy( p1, clip );
+ (*numOutPoints)++;
+ clip = outPoints[ *numOutPoints ];
+ }
+
+ if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
+ continue;
+ }
+
+ // generate a split point
+ p2 = inPoints[ (i+1) % numInPoints ];
+
+ d = dists[i] - dists[i+1];
+ if ( d == 0 ) {
+ dot = 0;
+ } else {
+ dot = dists[i] / d;
+ }
+
+ // clip xyz
+
+ for (j=0 ; j<3 ; j++) {
+ clip[j] = p1[j] + dot * ( p2[j] - p1[j] );
+ }
+
+ (*numOutPoints)++;
+ }
+}
+
+/*
+=================
+R_BoxSurfaces_r
+
+=================
+*/
+void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) {
+
+ int s, c;
+ msurface_t *surf;
+ int *mark;
+
+ // do the tail recursion in a loop
+ while ( node->contents == -1 ) {
+ s = BoxOnPlaneSide( mins, maxs, node->plane );
+ if (s == 1) {
+ node = node->children[0];
+ } else if (s == 2) {
+ node = node->children[1];
+ } else {
+ R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir);
+ node = node->children[1];
+ }
+ }
+
+ // add the individual surfaces
+ mark = tr.world->marksurfaces + node->firstmarksurface;
+ c = node->nummarksurfaces;
+ while (c--) {
+ int *surfViewCount;
+ //
+ if (*listlength >= listsize) break;
+ //
+ surfViewCount = &tr.world->surfacesViewCount[*mark];
+ surf = tr.world->surfaces + *mark;
+ // check if the surface has NOIMPACT or NOMARKS set
+ if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
+ || ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
+ *surfViewCount = tr.viewCount;
+ }
+ // extra check for surfaces to avoid list overflows
+ else if (*(surf->data) == SF_FACE) {
+ // the face plane should go through the box
+ s = BoxOnPlaneSide( mins, maxs, &surf->cullinfo.plane );
+ if (s == 1 || s == 2) {
+ *surfViewCount = tr.viewCount;
+ } else if (DotProduct(surf->cullinfo.plane.normal, dir) > -0.5) {
+ // don't add faces that make sharp angles with the projection direction
+ *surfViewCount = tr.viewCount;
+ }
+ }
+ else if (*(surf->data) != SF_GRID &&
+ *(surf->data) != SF_TRIANGLES)
+ *surfViewCount = tr.viewCount;
+ // check the viewCount because the surface may have
+ // already been added if it spans multiple leafs
+ if (*surfViewCount != tr.viewCount) {
+ *surfViewCount = tr.viewCount;
+ list[*listlength] = surf->data;
+ (*listlength)++;
+ }
+ mark++;
+ }
+}
+
+/*
+=================
+R_AddMarkFragments
+
+=================
+*/
+void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],
+ int numPlanes, vec3_t *normals, float *dists,
+ int maxPoints, vec3_t pointBuffer,
+ int maxFragments, markFragment_t *fragmentBuffer,
+ int *returnedPoints, int *returnedFragments,
+ vec3_t mins, vec3_t maxs) {
+ int pingPong, i;
+ markFragment_t *mf;
+
+ // chop the surface by all the bounding planes of the to be projected polygon
+ pingPong = 0;
+
+ for ( i = 0 ; i < numPlanes ; i++ ) {
+
+ R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],
+ &numClipPoints, clipPoints[!pingPong],
+ normals[i], dists[i], 0.5 );
+ pingPong ^= 1;
+ if ( numClipPoints == 0 ) {
+ break;
+ }
+ }
+ // completely clipped away?
+ if ( numClipPoints == 0 ) {
+ return;
+ }
+
+ // add this fragment to the returned list
+ if ( numClipPoints + (*returnedPoints) > maxPoints ) {
+ return; // not enough space for this polygon
+ }
+ /*
+ // all the clip points should be within the bounding box
+ for ( i = 0 ; i < numClipPoints ; i++ ) {
+ int j;
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;
+ if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;
+ }
+ if (j < 3) break;
+ }
+ if (i < numClipPoints) return;
+ */
+
+ mf = fragmentBuffer + (*returnedFragments);
+ mf->firstPoint = (*returnedPoints);
+ mf->numPoints = numClipPoints;
+ Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );
+
+ (*returnedPoints) += numClipPoints;
+ (*returnedFragments)++;
+}
+
+/*
+=================
+R_MarkFragments
+
+=================
+*/
+int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
+ int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
+ int numsurfaces, numPlanes;
+ int i, j, k, m, n;
+ surfaceType_t *surfaces[64];
+ vec3_t mins, maxs;
+ int returnedFragments;
+ int returnedPoints;
+ vec3_t normals[MAX_VERTS_ON_POLY+2];
+ float dists[MAX_VERTS_ON_POLY+2];
+ vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
+ int numClipPoints;
+ float *v;
+ srfBspSurface_t *cv;
+ glIndex_t *tri;
+ srfVert_t *dv;
+ vec3_t normal;
+ vec3_t projectionDir;
+ vec3_t v1, v2;
+
+ if (numPoints <= 0) {
+ return 0;
+ }
+
+ //increment view count for double check prevention
+ tr.viewCount++;
+
+ //
+ VectorNormalize2( projection, projectionDir );
+ // find all the brushes that are to be considered
+ ClearBounds( mins, maxs );
+ for ( i = 0 ; i < numPoints ; i++ ) {
+ vec3_t temp;
+
+ AddPointToBounds( points[i], mins, maxs );
+ VectorAdd( points[i], projection, temp );
+ AddPointToBounds( temp, mins, maxs );
+ // make sure we get all the leafs (also the one(s) in front of the hit surface)
+ VectorMA( points[i], -20, projectionDir, temp );
+ AddPointToBounds( temp, mins, maxs );
+ }
+
+ if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;
+ // create the bounding planes for the to be projected polygon
+ for ( i = 0 ; i < numPoints ; i++ ) {
+ VectorSubtract(points[(i+1)%numPoints], points[i], v1);
+ VectorAdd(points[i], projection, v2);
+ VectorSubtract(points[i], v2, v2);
+ CrossProduct(v1, v2, normals[i]);
+ VectorNormalizeFast(normals[i]);
+ dists[i] = DotProduct(normals[i], points[i]);
+ }
+ // add near and far clipping planes for projection
+ VectorCopy(projectionDir, normals[numPoints]);
+ dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
+ VectorCopy(projectionDir, normals[numPoints+1]);
+ VectorInverse(normals[numPoints+1]);
+ dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;
+ numPlanes = numPoints + 2;
+
+ numsurfaces = 0;
+ R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
+ //assert(numsurfaces <= 64);
+ //assert(numsurfaces != 64);
+
+ returnedPoints = 0;
+ returnedFragments = 0;
+
+ for ( i = 0 ; i < numsurfaces ; i++ ) {
+
+ if (*surfaces[i] == SF_GRID) {
+
+ cv = (srfBspSurface_t *) surfaces[i];
+ for ( m = 0 ; m < cv->height - 1 ; m++ ) {
+ for ( n = 0 ; n < cv->width - 1 ; n++ ) {
+ // We triangulate the grid and chop all triangles within
+ // the bounding planes of the to be projected polygon.
+ // LOD is not taken into account, not such a big deal though.
+ //
+ // It's probably much nicer to chop the grid itself and deal
+ // with this grid as a normal SF_GRID surface so LOD will
+ // be applied. However the LOD of that chopped grid must
+ // be synced with the LOD of the original curve.
+ // One way to do this; the chopped grid shares vertices with
+ // the original curve. When LOD is applied to the original
+ // curve the unused vertices are flagged. Now the chopped curve
+ // should skip the flagged vertices. This still leaves the
+ // problems with the vertices at the chopped grid edges.
+ //
+ // To avoid issues when LOD applied to "hollow curves" (like
+ // the ones around many jump pads) we now just add a 2 unit
+ // offset to the triangle vertices.
+ // The offset is added in the vertex normal vector direction
+ // so all triangles will still fit together.
+ // The 2 unit offset should avoid pretty much all LOD problems.
+ vec3_t fNormal;
+
+ numClipPoints = 3;
+
+ dv = cv->verts + m * cv->width + n;
+
+ VectorCopy(dv[0].xyz, clipPoints[0][0]);
+ R_VaoUnpackNormal(fNormal, dv[0].normal);
+ VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
+ VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
+ R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
+ VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
+ VectorCopy(dv[1].xyz, clipPoints[0][2]);
+ R_VaoUnpackNormal(fNormal, dv[1].normal);
+ VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
+ // check the normal of this triangle
+ VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
+ VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
+ CrossProduct(v1, v2, normal);
+ VectorNormalizeFast(normal);
+ if (DotProduct(normal, projectionDir) < -0.1) {
+ // add the fragments of this triangle
+ R_AddMarkFragments(numClipPoints, clipPoints,
+ numPlanes, normals, dists,
+ maxPoints, pointBuffer,
+ maxFragments, fragmentBuffer,
+ &returnedPoints, &returnedFragments, mins, maxs);
+
+ if ( returnedFragments == maxFragments ) {
+ return returnedFragments; // not enough space for more fragments
+ }
+ }
+
+ VectorCopy(dv[1].xyz, clipPoints[0][0]);
+ R_VaoUnpackNormal(fNormal, dv[1].normal);
+ VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
+ VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
+ R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
+ VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
+ VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
+ R_VaoUnpackNormal(fNormal, dv[cv->width + 1].normal);
+ VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
+ // check the normal of this triangle
+ VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
+ VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
+ CrossProduct(v1, v2, normal);
+ VectorNormalizeFast(normal);
+ if (DotProduct(normal, projectionDir) < -0.05) {
+ // add the fragments of this triangle
+ R_AddMarkFragments(numClipPoints, clipPoints,
+ numPlanes, normals, dists,
+ maxPoints, pointBuffer,
+ maxFragments, fragmentBuffer,
+ &returnedPoints, &returnedFragments, mins, maxs);
+
+ if ( returnedFragments == maxFragments ) {
+ return returnedFragments; // not enough space for more fragments
+ }
+ }
+ }
+ }
+ }
+ else if (*surfaces[i] == SF_FACE) {
+
+ srfBspSurface_t *surf = ( srfBspSurface_t * ) surfaces[i];
+
+ // check the normal of this face
+ if (DotProduct(surf->cullPlane.normal, projectionDir) > -0.5) {
+ continue;
+ }
+
+ for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
+ {
+ for(j = 0; j < 3; j++)
+ {
+ v = surf->verts[tri[j]].xyz;
+ VectorMA(v, MARKER_OFFSET, surf->cullPlane.normal, clipPoints[0][j]);
+ }
+
+ // add the fragments of this face
+ R_AddMarkFragments( 3 , clipPoints,
+ numPlanes, normals, dists,
+ maxPoints, pointBuffer,
+ maxFragments, fragmentBuffer,
+ &returnedPoints, &returnedFragments, mins, maxs);
+ if ( returnedFragments == maxFragments ) {
+ return returnedFragments; // not enough space for more fragments
+ }
+ }
+ }
+ else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
+
+ srfBspSurface_t *surf = (srfBspSurface_t *) surfaces[i];
+
+ for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
+ {
+ for(j = 0; j < 3; j++)
+ {
+ vec3_t fNormal;
+ v = surf->verts[tri[j]].xyz;
+ R_VaoUnpackNormal(fNormal, surf->verts[tri[j]].normal);
+ VectorMA(v, MARKER_OFFSET, fNormal, clipPoints[0][j]);
+ }
+
+ // add the fragments of this face
+ R_AddMarkFragments(3, clipPoints,
+ numPlanes, normals, dists,
+ maxPoints, pointBuffer,
+ maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
+ if(returnedFragments == maxFragments)
+ {
+ return returnedFragments; // not enough space for more fragments
+ }
+ }
+ }
+ }
+ return returnedFragments;
+}
diff --git a/src/renderergl2/tr_mesh.cpp b/src/renderergl2/tr_mesh.cpp
new file mode 100644
index 0000000..2761f83
--- /dev/null
+++ b/src/renderergl2/tr_mesh.cpp
@@ -0,0 +1,418 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_mesh.c: triangle model functions
+
+#include "tr_local.h"
+
+static float ProjectRadius( float r, vec3_t location )
+{
+ float pr;
+ float dist;
+ float c;
+ vec3_t p;
+ float projected[4];
+
+ c = DotProduct( tr.viewParms.orientation.axis[0], tr.viewParms.orientation.origin );
+ dist = DotProduct( tr.viewParms.orientation.axis[0], location ) - c;
+
+ if ( dist <= 0 )
+ return 0;
+
+ p[0] = 0;
+ p[1] = fabs( r );
+ p[2] = -dist;
+
+ projected[0] = p[0] * tr.viewParms.projectionMatrix[0] +
+ p[1] * tr.viewParms.projectionMatrix[4] +
+ p[2] * tr.viewParms.projectionMatrix[8] +
+ tr.viewParms.projectionMatrix[12];
+
+ projected[1] = p[0] * tr.viewParms.projectionMatrix[1] +
+ p[1] * tr.viewParms.projectionMatrix[5] +
+ p[2] * tr.viewParms.projectionMatrix[9] +
+ tr.viewParms.projectionMatrix[13];
+
+ projected[2] = p[0] * tr.viewParms.projectionMatrix[2] +
+ p[1] * tr.viewParms.projectionMatrix[6] +
+ p[2] * tr.viewParms.projectionMatrix[10] +
+ tr.viewParms.projectionMatrix[14];
+
+ projected[3] = p[0] * tr.viewParms.projectionMatrix[3] +
+ p[1] * tr.viewParms.projectionMatrix[7] +
+ p[2] * tr.viewParms.projectionMatrix[11] +
+ tr.viewParms.projectionMatrix[15];
+
+
+ pr = projected[1] / projected[3];
+
+ if ( pr > 1.0f )
+ pr = 1.0f;
+
+ return pr;
+}
+
+/*
+=============
+R_CullModel
+=============
+*/
+static int R_CullModel( mdvModel_t *model, trRefEntity_t *ent ) {
+ vec3_t bounds[2];
+ mdvFrame_t *oldFrame, *newFrame;
+ int i;
+
+ // compute frame pointers
+ newFrame = model->frames + ent->e.frame;
+ oldFrame = model->frames + ent->e.oldframe;
+
+ // cull bounding sphere ONLY if this is not an upscaled entity
+ if ( !ent->e.nonNormalizedAxes )
+ {
+ if ( ent->e.frame == ent->e.oldframe )
+ {
+ switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
+ {
+ case CULL_OUT:
+ tr.pc.c_sphere_cull_md3_out++;
+ return CULL_OUT;
+
+ case CULL_IN:
+ tr.pc.c_sphere_cull_md3_in++;
+ return CULL_IN;
+
+ case CULL_CLIP:
+ tr.pc.c_sphere_cull_md3_clip++;
+ break;
+ }
+ }
+ else
+ {
+ int sphereCull, sphereCullB;
+
+ sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
+ if ( newFrame == oldFrame ) {
+ sphereCullB = sphereCull;
+ } else {
+ sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
+ }
+
+ if ( sphereCull == sphereCullB )
+ {
+ if ( sphereCull == CULL_OUT )
+ {
+ tr.pc.c_sphere_cull_md3_out++;
+ return CULL_OUT;
+ }
+ else if ( sphereCull == CULL_IN )
+ {
+ tr.pc.c_sphere_cull_md3_in++;
+ return CULL_IN;
+ }
+ else
+ {
+ tr.pc.c_sphere_cull_md3_clip++;
+ }
+ }
+ }
+ }
+
+ // calculate a bounding box in the current coordinate system
+ for (i = 0 ; i < 3 ; i++) {
+ bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
+ bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
+ }
+
+ switch ( R_CullLocalBox( bounds ) )
+ {
+ case CULL_IN:
+ tr.pc.c_box_cull_md3_in++;
+ return CULL_IN;
+ case CULL_CLIP:
+ tr.pc.c_box_cull_md3_clip++;
+ return CULL_CLIP;
+ case CULL_OUT:
+ default:
+ tr.pc.c_box_cull_md3_out++;
+ return CULL_OUT;
+ }
+}
+
+
+/*
+=================
+R_ComputeLOD
+
+=================
+*/
+int R_ComputeLOD( trRefEntity_t *ent ) {
+ float radius;
+ float flod, lodscale;
+ float projectedRadius;
+ mdvFrame_t *frame;
+ mdrHeader_t *mdr;
+ mdrFrame_t *mdrframe;
+ int lod;
+
+ if ( tr.currentModel->numLods < 2 )
+ {
+ // model has only 1 LOD level, skip computations and bias
+ lod = 0;
+ }
+ else
+ {
+ // multiple LODs exist, so compute projected bounding sphere
+ // and use that as a criteria for selecting LOD
+
+ if(tr.currentModel->type == MOD_MDR)
+ {
+ int frameSize;
+ mdr = (mdrHeader_t *) tr.currentModel->modelData;
+ frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]);
+
+ mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame);
+
+ radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]);
+ }
+ else
+ {
+ //frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
+ frame = tr.currentModel->mdv[0]->frames;
+
+ frame += ent->e.frame;
+
+ radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] );
+ }
+
+ if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 )
+ {
+ lodscale = r_lodscale->value;
+ if (lodscale > 20) lodscale = 20;
+ flod = 1.0f - projectedRadius * lodscale;
+ }
+ else
+ {
+ // object intersects near view plane, e.g. view weapon
+ flod = 0;
+ }
+
+ flod *= tr.currentModel->numLods;
+ lod = static_cast<int>(flod);
+
+ if ( lod < 0 )
+ {
+ lod = 0;
+ }
+ else if ( lod >= tr.currentModel->numLods )
+ {
+ lod = tr.currentModel->numLods - 1;
+ }
+ }
+
+ lod += r_lodbias->integer;
+
+ if ( lod >= tr.currentModel->numLods )
+ lod = tr.currentModel->numLods - 1;
+ if ( lod < 0 )
+ lod = 0;
+
+ return lod;
+}
+
+/*
+=================
+R_ComputeFogNum
+
+=================
+*/
+int R_ComputeFogNum( mdvModel_t *model, trRefEntity_t *ent ) {
+ int i, j;
+ fog_t *fog;
+ mdvFrame_t *mdvFrame;
+ vec3_t localOrigin;
+
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ return 0;
+ }
+
+ // FIXME: non-normalized axis issues
+ mdvFrame = model->frames + ent->e.frame;
+ VectorAdd( ent->e.origin, mdvFrame->localOrigin, localOrigin );
+ for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
+ fog = &tr.world->fogs[i];
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( localOrigin[j] - mdvFrame->radius >= fog->bounds[1][j] ) {
+ break;
+ }
+ if ( localOrigin[j] + mdvFrame->radius <= fog->bounds[0][j] ) {
+ break;
+ }
+ }
+ if ( j == 3 ) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+/*
+=================
+R_AddMD3Surfaces
+
+=================
+*/
+void R_AddMD3Surfaces( trRefEntity_t *ent ) {
+ int i;
+ mdvModel_t *model = NULL;
+ mdvSurface_t *surface = NULL;
+ shader_t *shader = NULL;
+ int cull;
+ int lod;
+ int fogNum;
+ int cubemapIndex;
+ bool personalModel;
+
+ // don't add third_person objects if not in a portal
+ personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal
+ || (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)));
+
+ if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
+ ent->e.frame %= tr.currentModel->mdv[0]->numFrames;
+ ent->e.oldframe %= tr.currentModel->mdv[0]->numFrames;
+ }
+
+ //
+ // Validate the frames so there is no chance of a crash.
+ // This will write directly into the entity structure, so
+ // when the surfaces are rendered, they don't need to be
+ // range checked again.
+ //
+ if ( (ent->e.frame >= tr.currentModel->mdv[0]->numFrames)
+ || (ent->e.frame < 0)
+ || (ent->e.oldframe >= tr.currentModel->mdv[0]->numFrames)
+ || (ent->e.oldframe < 0) ) {
+ ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n",
+ ent->e.oldframe, ent->e.frame,
+ tr.currentModel->name );
+ ent->e.frame = 0;
+ ent->e.oldframe = 0;
+ }
+
+ //
+ // compute LOD
+ //
+ lod = R_ComputeLOD( ent );
+
+ model = tr.currentModel->mdv[lod];
+
+ //
+ // cull the entire model if merged bounding box of both frames
+ // is outside the view frustum.
+ //
+ cull = R_CullModel ( model, ent );
+ if ( cull == CULL_OUT ) {
+ return;
+ }
+
+ //
+ // set up lighting now that we know we aren't culled
+ //
+ if ( !personalModel || r_shadows->integer > 1 ) {
+ R_SetupEntityLighting( &tr.refdef, ent );
+ }
+
+ //
+ // see if we are in a fog volume
+ //
+ fogNum = R_ComputeFogNum( model, ent );
+
+ cubemapIndex = R_CubemapForPoint(ent->e.origin);
+
+ //
+ // draw all surfaces
+ //
+ surface = model->surfaces;
+ for ( i = 0 ; i < model->numSurfaces ; i++ ) {
+
+ if ( ent->e.customShader ) {
+ shader = R_GetShaderByHandle( ent->e.customShader );
+ } else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) {
+ skin_t *skin;
+ int j;
+
+ skin = R_GetSkinByHandle( ent->e.customSkin );
+
+ // match the surface name to something in the skin file
+ shader = tr.defaultShader;
+ for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
+ // the names have both been lowercased
+ if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
+ shader = skin->surfaces[j].shader;
+ break;
+ }
+ }
+ if (shader == tr.defaultShader) {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name);
+ }
+ else if (shader->defaultShader) {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
+ }
+ //} else if ( surface->numShaders <= 0 ) {
+ //shader = tr.defaultShader;
+ } else {
+ //md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders );
+ //md3Shader += ent->e.skinNum % surface->numShaders;
+ //shader = tr.shaders[ md3Shader->shaderIndex ];
+ shader = tr.shaders[ surface->shaderIndexes[ ent->e.skinNum % surface->numShaderIndexes ] ];
+ }
+
+ // we will add shadows even if the main object isn't visible in the view
+
+ // stencil shadows can't do personal models unless I polyhedron clip
+ if ( !personalModel
+ && r_shadows->integer == 2
+ && fogNum == 0
+ && !(ent->e.renderfx & (RF_NOSHADOW|RF_DEPTHHACK))
+ && shader->sort == SS_OPAQUE )
+ {
+ R_AddDrawSurf( (surfaceType_t*)&model->vaoSurfaces[i], tr.shadowShader, 0, false, false, 0);
+ }
+
+ // projection shadows work fine with personal models
+ if ( r_shadows->integer == 3
+ && fogNum == 0
+ && (ent->e.renderfx & RF_SHADOW_PLANE )
+ && shader->sort == SS_OPAQUE )
+ {
+ R_AddDrawSurf( (surfaceType_t*)&model->vaoSurfaces[i], tr.projectionShadowShader, 0, false, false, 0 );
+ }
+
+ // don't add third_person objects if not viewing through a portal
+ if ( !personalModel )
+ R_AddDrawSurf((surfaceType_t*)&model->vaoSurfaces[i], shader, fogNum, false, false, cubemapIndex );
+
+ surface++;
+ }
+
+}
diff --git a/src/renderergl2/tr_model.cpp b/src/renderergl2/tr_model.cpp
new file mode 100644
index 0000000..6e3b984
--- /dev/null
+++ b/src/renderergl2/tr_model.cpp
@@ -0,0 +1,1419 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_models.c -- model loading and caching
+
+#include "tr_local.h"
+
+#define LL(x) x=LittleLong(x)
+
+static bool R_LoadMD3(model_t *mod, int lod, void *buffer, int bufferSize, const char *modName);
+static bool R_LoadMDR(model_t *mod, void *buffer, int filesize, const char *name );
+
+/*
+====================
+R_RegisterMD3
+====================
+*/
+qhandle_t R_RegisterMD3(const char *name, model_t *mod)
+{
+ union {
+ unsigned *u;
+ void *v;
+ } buf;
+ int size;
+ int lod;
+ int ident;
+ bool loaded = false;
+ int numLoaded;
+ char filename[MAX_QPATH], namebuf[MAX_QPATH+20];
+ char *fext, defex[] = "md3";
+
+ numLoaded = 0;
+
+ strcpy(filename, name);
+
+ fext = strchr(filename, '.');
+ if(!fext)
+ fext = defex;
+ else
+ {
+ *fext = '\0';
+ fext++;
+ }
+
+ for (lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod--)
+ {
+ if(lod)
+ Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext);
+ else
+ Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext);
+
+ size = ri.FS_ReadFile( namebuf, &buf.v );
+ if(!buf.u)
+ continue;
+
+ ident = LittleLong(* (unsigned *) buf.u);
+ if (ident == MD3_IDENT)
+ loaded = R_LoadMD3(mod, lod, buf.u, size, name);
+ else
+ ri.Printf(PRINT_WARNING,"R_RegisterMD3: unknown fileid for %s\n", name);
+
+ ri.FS_FreeFile(buf.v);
+
+ if(loaded)
+ {
+ mod->numLods++;
+ numLoaded++;
+ }
+ else
+ break;
+ }
+
+ if(numLoaded)
+ {
+ // duplicate into higher lod spots that weren't
+ // loaded, in case the user changes r_lodbias on the fly
+ for(lod--; lod >= 0; lod--)
+ {
+ mod->numLods++;
+ mod->mdv[lod] = mod->mdv[lod + 1];
+ }
+
+ return mod->index;
+ }
+
+ ri.Printf(PRINT_DEVELOPER, "R_RegisterMD3: couldn't load %s\n", name);
+
+ mod->type = MOD_BAD;
+ return 0;
+}
+
+/*
+====================
+R_RegisterMDR
+====================
+*/
+qhandle_t R_RegisterMDR(const char *name, model_t *mod)
+{
+ union {
+ unsigned *u;
+ void *v;
+ } buf;
+ int ident;
+ bool loaded = false;
+ int filesize;
+
+ filesize = ri.FS_ReadFile(name, (void **) &buf.v);
+ if(!buf.u)
+ {
+ mod->type = MOD_BAD;
+ return 0;
+ }
+
+ ident = LittleLong(*(unsigned *)buf.u);
+ if(ident == MDR_IDENT)
+ loaded = R_LoadMDR(mod, buf.u, filesize, name);
+
+ ri.FS_FreeFile (buf.v);
+
+ if(!loaded)
+ {
+ ri.Printf(PRINT_WARNING,"R_RegisterMDR: couldn't load mdr file %s\n", name);
+ mod->type = MOD_BAD;
+ return 0;
+ }
+
+ return mod->index;
+}
+
+/*
+====================
+R_RegisterIQM
+====================
+*/
+qhandle_t R_RegisterIQM(const char *name, model_t *mod)
+{
+ union {
+ unsigned *u;
+ void *v;
+ } buf;
+ bool loaded = false;
+ int filesize;
+
+ filesize = ri.FS_ReadFile(name, (void **) &buf.v);
+ if(!buf.u)
+ {
+ mod->type = MOD_BAD;
+ return 0;
+ }
+
+ loaded = R_LoadIQM(mod, buf.u, filesize, name);
+
+ ri.FS_FreeFile (buf.v);
+
+ if(!loaded)
+ {
+ ri.Printf(PRINT_WARNING,"R_RegisterIQM: couldn't load iqm file %s\n", name);
+ mod->type = MOD_BAD;
+ return 0;
+ }
+
+ return mod->index;
+}
+
+
+struct modelExtToLoaderMap_t
+{
+ const char *ext;
+ qhandle_t (*ModelLoader)( const char *, model_t * );
+};
+
+// Note that the ordering indicates the order of preference used
+// when there are multiple models of different formats available
+static modelExtToLoaderMap_t modelLoaders[ ] =
+{
+ { "iqm", R_RegisterIQM },
+ { "mdr", R_RegisterMDR },
+ { "md3", R_RegisterMD3 }
+};
+
+static int numModelLoaders = ARRAY_LEN(modelLoaders);
+
+//===============================================================================
+
+/*
+** R_GetModelByHandle
+*/
+model_t *R_GetModelByHandle( qhandle_t index ) {
+ model_t *mod;
+
+ // out of range gets the defualt model
+ if ( index < 1 || index >= tr.numModels ) {
+ return tr.models[0];
+ }
+
+ mod = tr.models[index];
+
+ return mod;
+}
+
+//===============================================================================
+
+/*
+** R_AllocModel
+*/
+model_t *R_AllocModel( void ) {
+ model_t *mod;
+
+ if ( tr.numModels == MAX_MOD_KNOWN ) {
+ return NULL;
+ }
+
+ mod = (model_t*)ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low );
+ mod->index = tr.numModels;
+ tr.models[tr.numModels] = mod;
+ tr.numModels++;
+
+ return mod;
+}
+
+/*
+====================
+RE_RegisterModel
+
+Loads in a model for the given name
+
+Zero will be returned if the model fails to load.
+An entry will be retained for failed models as an
+optimization to prevent disk rescanning if they are
+asked for again.
+====================
+*/
+qhandle_t RE_RegisterModel( const char *name ) {
+ model_t *mod;
+ qhandle_t hModel;
+ bool orgNameFailed = false;
+ int orgLoader = -1;
+ int i;
+ char localName[ MAX_QPATH ];
+ const char *ext;
+ char altName[ MAX_QPATH ];
+
+ if ( !name || !name[0] ) {
+ ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" );
+ return 0;
+ }
+
+ if ( strlen( name ) >= MAX_QPATH ) {
+ ri.Printf( PRINT_ALL, "Model name exceeds MAX_QPATH\n" );
+ return 0;
+ }
+
+ //
+ // search the currently loaded models
+ //
+ for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) {
+ mod = tr.models[hModel];
+ if ( !strcmp( mod->name, name ) ) {
+ if( mod->type == MOD_BAD ) {
+ return 0;
+ }
+ return hModel;
+ }
+ }
+
+ // allocate a new model_t
+
+ if ( ( mod = R_AllocModel() ) == NULL ) {
+ ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name);
+ return 0;
+ }
+
+ // only set the name after the model has been successfully loaded
+ Q_strncpyz( mod->name, name, sizeof( mod->name ) );
+
+
+ R_IssuePendingRenderCommands();
+
+ mod->type = MOD_BAD;
+ mod->numLods = 0;
+
+ //
+ // load the files
+ //
+ Q_strncpyz( localName, name, MAX_QPATH );
+
+ ext = COM_GetExtension( localName );
+
+ if( *ext )
+ {
+ // Look for the correct loader and use it
+ for( i = 0; i < numModelLoaders; i++ )
+ {
+ if( !Q_stricmp( ext, modelLoaders[ i ].ext ) )
+ {
+ // Load
+ hModel = modelLoaders[ i ].ModelLoader( localName, mod );
+ break;
+ }
+ }
+
+ // A loader was found
+ if( i < numModelLoaders )
+ {
+ if( !hModel )
+ {
+ // Loader failed, most likely because the file isn't there;
+ // try again without the extension
+ orgNameFailed = true;
+ orgLoader = i;
+ COM_StripExtension( name, localName, MAX_QPATH );
+ }
+ else
+ {
+ // Something loaded
+ return mod->index;
+ }
+ }
+ }
+
+ // Try and find a suitable match using all
+ // the model formats supported
+ for( i = 0; i < numModelLoaders; i++ )
+ {
+ if (i == orgLoader)
+ continue;
+
+ Com_sprintf( altName, sizeof (altName), "%s.%s", localName, modelLoaders[ i ].ext );
+
+ // Load
+ hModel = modelLoaders[ i ].ModelLoader( altName, mod );
+
+ if( hModel )
+ {
+ if( orgNameFailed )
+ {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n",
+ name, altName );
+ }
+
+ break;
+ }
+ }
+
+ return hModel;
+}
+
+/*
+=================
+R_LoadMD3
+=================
+*/
+static bool R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, const char *modName)
+{
+ int f, i, j;
+
+ md3Header_t *md3Model;
+ md3Frame_t *md3Frame;
+ md3Surface_t *md3Surf;
+ md3Shader_t *md3Shader;
+ md3Triangle_t *md3Tri;
+ md3St_t *md3st;
+ md3XyzNormal_t *md3xyz;
+ md3Tag_t *md3Tag;
+
+ mdvModel_t *mdvModel;
+ mdvFrame_t *frame;
+ mdvSurface_t *surf;//, *surface;
+ int *shaderIndex;
+ glIndex_t *tri;
+ mdvVertex_t *v;
+ mdvSt_t *st;
+ mdvTag_t *tag;
+ mdvTagName_t *tagName;
+
+ int version;
+ int size;
+
+ md3Model = (md3Header_t *) buffer;
+
+ version = LittleLong(md3Model->version);
+ if(version != MD3_VERSION)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n", modName, version, MD3_VERSION);
+ return false;
+ }
+
+ mod->type = MOD_MESH;
+ size = LittleLong(md3Model->ofsEnd);
+ mod->dataSize += size;
+ mdvModel = mod->mdv[lod] = (mdvModel_t*)ri.Hunk_Alloc(sizeof(mdvModel_t), h_low);
+
+// Com_Memcpy(mod->md3[lod], buffer, LittleLong(md3Model->ofsEnd));
+
+ LL(md3Model->ident);
+ LL(md3Model->version);
+ LL(md3Model->numFrames);
+ LL(md3Model->numTags);
+ LL(md3Model->numSurfaces);
+ LL(md3Model->ofsFrames);
+ LL(md3Model->ofsTags);
+ LL(md3Model->ofsSurfaces);
+ LL(md3Model->ofsEnd);
+
+ if(md3Model->numFrames < 1)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has no frames\n", modName);
+ return false;
+ }
+
+ // swap all the frames
+ mdvModel->numFrames = md3Model->numFrames;
+ mdvModel->frames = frame = (mdvFrame_t*)ri.Hunk_Alloc(sizeof(*frame) * md3Model->numFrames, h_low);
+
+ md3Frame = (md3Frame_t *) ((byte *) md3Model + md3Model->ofsFrames);
+ for(i = 0; i < md3Model->numFrames; i++, frame++, md3Frame++)
+ {
+ frame->radius = LittleFloat(md3Frame->radius);
+ for(j = 0; j < 3; j++)
+ {
+ frame->bounds[0][j] = LittleFloat(md3Frame->bounds[0][j]);
+ frame->bounds[1][j] = LittleFloat(md3Frame->bounds[1][j]);
+ frame->localOrigin[j] = LittleFloat(md3Frame->localOrigin[j]);
+ }
+ }
+
+ // swap all the tags
+ mdvModel->numTags = md3Model->numTags;
+ mdvModel->tags = tag = (mdvTag_t*)ri.Hunk_Alloc(sizeof(*tag) * (md3Model->numTags * md3Model->numFrames), h_low);
+
+ md3Tag = (md3Tag_t *) ((byte *) md3Model + md3Model->ofsTags);
+ for(i = 0; i < md3Model->numTags * md3Model->numFrames; i++, tag++, md3Tag++)
+ {
+ for(j = 0; j < 3; j++)
+ {
+ tag->origin[j] = LittleFloat(md3Tag->origin[j]);
+ tag->axis[0][j] = LittleFloat(md3Tag->axis[0][j]);
+ tag->axis[1][j] = LittleFloat(md3Tag->axis[1][j]);
+ tag->axis[2][j] = LittleFloat(md3Tag->axis[2][j]);
+ }
+ }
+
+
+ mdvModel->tagNames = tagName = (mdvTagName_t*)ri.Hunk_Alloc(sizeof(*tagName) * (md3Model->numTags), h_low);
+
+ md3Tag = (md3Tag_t *) ((byte *) md3Model + md3Model->ofsTags);
+ for(i = 0; i < md3Model->numTags; i++, tagName++, md3Tag++)
+ {
+ Q_strncpyz(tagName->name, md3Tag->name, sizeof(tagName->name));
+ }
+
+ // swap all the surfaces
+ mdvModel->numSurfaces = md3Model->numSurfaces;
+ mdvModel->surfaces = surf = (mdvSurface_t*)ri.Hunk_Alloc(sizeof(*surf) * md3Model->numSurfaces, h_low);
+
+ md3Surf = (md3Surface_t *) ((byte *) md3Model + md3Model->ofsSurfaces);
+ for(i = 0; i < md3Model->numSurfaces; i++)
+ {
+ LL(md3Surf->ident);
+ LL(md3Surf->flags);
+ LL(md3Surf->numFrames);
+ LL(md3Surf->numShaders);
+ LL(md3Surf->numTriangles);
+ LL(md3Surf->ofsTriangles);
+ LL(md3Surf->numVerts);
+ LL(md3Surf->ofsShaders);
+ LL(md3Surf->ofsSt);
+ LL(md3Surf->ofsXyzNormals);
+ LL(md3Surf->ofsEnd);
+
+ if(md3Surf->numVerts >= SHADER_MAX_VERTEXES)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on %s (%i).\n",
+ modName, SHADER_MAX_VERTEXES - 1, md3Surf->name[0] ? md3Surf->name : "a surface",
+ md3Surf->numVerts );
+ return false;
+ }
+ if(md3Surf->numTriangles * 3 >= SHADER_MAX_INDEXES)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on %s (%i).\n",
+ modName, ( SHADER_MAX_INDEXES / 3 ) - 1, md3Surf->name[0] ? md3Surf->name : "a surface",
+ md3Surf->numTriangles );
+ return false;
+ }
+
+ // change to surface identifier
+ surf->surfaceType = SF_MDV;
+
+ // give pointer to model for Tess_SurfaceMDX
+ surf->model = mdvModel;
+
+ // copy surface name
+ Q_strncpyz(surf->name, md3Surf->name, sizeof(surf->name));
+
+ // lowercase the surface name so skin compares are faster
+ Q_strlwr(surf->name);
+
+ // strip off a trailing _1 or _2
+ // this is a crutch for q3data being a mess
+ j = strlen(surf->name);
+ if(j > 2 && surf->name[j - 2] == '_')
+ {
+ surf->name[j - 2] = 0;
+ }
+
+ // register the shaders
+ surf->numShaderIndexes = md3Surf->numShaders;
+ surf->shaderIndexes = shaderIndex = (int*)ri.Hunk_Alloc(sizeof(*shaderIndex) * md3Surf->numShaders, h_low);
+
+ md3Shader = (md3Shader_t *) ((byte *) md3Surf + md3Surf->ofsShaders);
+ for(j = 0; j < md3Surf->numShaders; j++, shaderIndex++, md3Shader++)
+ {
+ shader_t *sh;
+
+ sh = R_FindShader(md3Shader->name, LIGHTMAP_NONE, true);
+ if(sh->defaultShader)
+ {
+ *shaderIndex = 0;
+ }
+ else
+ {
+ *shaderIndex = sh->index;
+ }
+ }
+
+ // swap all the triangles
+ surf->numIndexes = md3Surf->numTriangles * 3;
+ surf->indexes = tri = (glIndex_t*)ri.Hunk_Alloc(sizeof(*tri) * 3 * md3Surf->numTriangles, h_low);
+
+ md3Tri = (md3Triangle_t *) ((byte *) md3Surf + md3Surf->ofsTriangles);
+ for(j = 0; j < md3Surf->numTriangles; j++, tri += 3, md3Tri++)
+ {
+ tri[0] = LittleLong(md3Tri->indexes[0]);
+ tri[1] = LittleLong(md3Tri->indexes[1]);
+ tri[2] = LittleLong(md3Tri->indexes[2]);
+ }
+
+ // swap all the XyzNormals
+ surf->numVerts = md3Surf->numVerts;
+ surf->verts = v = (mdvVertex_t*)ri.Hunk_Alloc(sizeof(*v) * (md3Surf->numVerts * md3Surf->numFrames), h_low);
+
+ md3xyz = (md3XyzNormal_t *) ((byte *) md3Surf + md3Surf->ofsXyzNormals);
+ for(j = 0; j < md3Surf->numVerts * md3Surf->numFrames; j++, md3xyz++, v++)
+ {
+ unsigned lat, lng;
+ unsigned short normal;
+ vec3_t fNormal;
+
+ v->xyz[0] = LittleShort(md3xyz->xyz[0]) * MD3_XYZ_SCALE;
+ v->xyz[1] = LittleShort(md3xyz->xyz[1]) * MD3_XYZ_SCALE;
+ v->xyz[2] = LittleShort(md3xyz->xyz[2]) * MD3_XYZ_SCALE;
+
+ normal = LittleShort(md3xyz->normal);
+
+ lat = ( normal >> 8 ) & 0xff;
+ lng = ( normal & 0xff );
+ lat *= (FUNCTABLE_SIZE/256);
+ lng *= (FUNCTABLE_SIZE/256);
+
+ // decode X as cos( lat ) * sin( long )
+ // decode Y as sin( lat ) * sin( long )
+ // decode Z as cos( long )
+
+ fNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
+ fNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
+ fNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
+
+ R_VaoPackNormal(v->normal, fNormal);
+ }
+
+ // swap all the ST
+ surf->st = st = (mdvSt_t*)ri.Hunk_Alloc(sizeof(*st) * md3Surf->numVerts, h_low);
+
+ md3st = (md3St_t *) ((byte *) md3Surf + md3Surf->ofsSt);
+ for(j = 0; j < md3Surf->numVerts; j++, md3st++, st++)
+ {
+ st->st[0] = LittleFloat(md3st->st[0]);
+ st->st[1] = LittleFloat(md3st->st[1]);
+ }
+
+ // calc tangent spaces
+ {
+ vec3_t *sdirs = (vec3_t*)ri.Malloc(sizeof(*sdirs) * surf->numVerts * mdvModel->numFrames);
+ vec3_t *tdirs = (vec3_t*)ri.Malloc(sizeof(*tdirs) * surf->numVerts * mdvModel->numFrames);
+
+ for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++)
+ {
+ VectorClear(sdirs[j]);
+ VectorClear(tdirs[j]);
+ }
+
+ for(f = 0; f < mdvModel->numFrames; f++)
+ {
+ for(j = 0, tri = surf->indexes; j < surf->numIndexes; j += 3, tri += 3)
+ {
+ vec3_t sdir, tdir;
+ const float *v0, *v1, *v2, *t0, *t1, *t2;
+ glIndex_t index0, index1, index2;
+
+ index0 = surf->numVerts * f + tri[0];
+ index1 = surf->numVerts * f + tri[1];
+ index2 = surf->numVerts * f + tri[2];
+
+ v0 = surf->verts[index0].xyz;
+ v1 = surf->verts[index1].xyz;
+ v2 = surf->verts[index2].xyz;
+
+ t0 = surf->st[tri[0]].st;
+ t1 = surf->st[tri[1]].st;
+ t2 = surf->st[tri[2]].st;
+
+ R_CalcTexDirs(sdir, tdir, v0, v1, v2, t0, t1, t2);
+
+ VectorAdd(sdir, sdirs[index0], sdirs[index0]);
+ VectorAdd(sdir, sdirs[index1], sdirs[index1]);
+ VectorAdd(sdir, sdirs[index2], sdirs[index2]);
+ VectorAdd(tdir, tdirs[index0], tdirs[index0]);
+ VectorAdd(tdir, tdirs[index1], tdirs[index1]);
+ VectorAdd(tdir, tdirs[index2], tdirs[index2]);
+ }
+ }
+
+ for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++)
+ {
+ vec3_t normal;
+ vec4_t tangent;
+
+ VectorNormalize(sdirs[j]);
+ VectorNormalize(tdirs[j]);
+
+ R_VaoUnpackNormal(normal, v->normal);
+
+ tangent[3] = R_CalcTangentSpace(tangent, NULL, normal, sdirs[j], tdirs[j]);
+
+ R_VaoPackTangent(v->tangent, tangent);
+ }
+
+ ri.Free(sdirs);
+ ri.Free(tdirs);
+ }
+
+ // find the next surface
+ md3Surf = (md3Surface_t *) ((byte *) md3Surf + md3Surf->ofsEnd);
+ surf++;
+ }
+
+ {
+ srfVaoMdvMesh_t *vaoSurf;
+
+ mdvModel->numVaoSurfaces = mdvModel->numSurfaces;
+ mdvModel->vaoSurfaces = (srfVaoMdvMesh_t*)ri.Hunk_Alloc(sizeof(*mdvModel->vaoSurfaces) * mdvModel->numSurfaces, h_low);
+
+ vaoSurf = mdvModel->vaoSurfaces;
+ surf = mdvModel->surfaces;
+ for (i = 0; i < mdvModel->numSurfaces; i++, vaoSurf++, surf++)
+ {
+ uint32_t offset_xyz, offset_st, offset_normal, offset_tangent;
+ uint32_t stride_xyz, stride_st, stride_normal, stride_tangent;
+ uint32_t dataSize, dataOfs;
+ uint8_t *data;
+
+ if (mdvModel->numFrames > 1)
+ {
+ // vertex animation, store texcoords first, then position/normal/tangents
+ offset_st = 0;
+ offset_xyz = surf->numVerts * sizeof(vec2_t);
+ offset_normal = offset_xyz + sizeof(vec3_t);
+ offset_tangent = offset_normal + sizeof(int16_t) * 4;
+ stride_st = sizeof(vec2_t);
+ stride_xyz = sizeof(vec3_t) + sizeof(int16_t) * 4;
+ stride_xyz += sizeof(int16_t) * 4;
+ stride_normal = stride_tangent = stride_xyz;
+
+ dataSize = offset_xyz + surf->numVerts * mdvModel->numFrames * stride_xyz;
+ }
+ else
+ {
+ // no animation, interleave everything
+ offset_xyz = 0;
+ offset_st = offset_xyz + sizeof(vec3_t);
+ offset_normal = offset_st + sizeof(vec2_t);
+ offset_tangent = offset_normal + sizeof(int16_t) * 4;
+ stride_xyz = offset_tangent + sizeof(int16_t) * 4;
+ stride_st = stride_normal = stride_tangent = stride_xyz;
+
+ dataSize = surf->numVerts * stride_xyz;
+ }
+
+
+ data = (uint8_t*)ri.Malloc(dataSize);
+ dataOfs = 0;
+
+ if (mdvModel->numFrames > 1)
+ {
+ st = surf->st;
+ for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
+ memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
+ dataOfs += sizeof(st->st);
+ }
+
+ v = surf->verts;
+ for ( j = 0; j < surf->numVerts * mdvModel->numFrames ; j++, v++ )
+ {
+ // xyz
+ memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
+ dataOfs += sizeof(vec3_t);
+
+ // normal
+ memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4);
+ dataOfs += sizeof(int16_t) * 4;
+
+ // tangent
+ memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4);
+ dataOfs += sizeof(int16_t) * 4;
+ }
+ }
+ else
+ {
+ v = surf->verts;
+ st = surf->st;
+ for ( j = 0; j < surf->numVerts; j++, v++, st++ )
+ {
+ // xyz
+ memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
+ dataOfs += sizeof(v->xyz);
+
+ // st
+ memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
+ dataOfs += sizeof(st->st);
+
+ // normal
+ memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4);
+ dataOfs += sizeof(int16_t) * 4;
+
+ // tangent
+ memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4);
+ dataOfs += sizeof(int16_t) * 4;
+ }
+ }
+
+ vaoSurf->surfaceType = SF_VAO_MDVMESH;
+ vaoSurf->mdvModel = mdvModel;
+ vaoSurf->mdvSurface = surf;
+ vaoSurf->numIndexes = surf->numIndexes;
+ vaoSurf->numVerts = surf->numVerts;
+
+ vaoSurf->minIndex = 0;
+ vaoSurf->maxIndex = surf->numVerts - 1;
+
+ vaoSurf->vao = R_CreateVao(va("staticMD3Mesh_VAO '%s'", surf->name), data, dataSize, (byte *)surf->indexes, surf->numIndexes * sizeof(*surf->indexes), VAO_USAGE_STATIC);
+
+ vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
+ vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
+ vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1;
+ vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
+
+ vaoSurf->vao->attribs[ATTR_INDEX_POSITION].count = 3;
+ vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].count = 2;
+ vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].count = 4;
+ vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4;
+
+ vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
+ vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT;
+ vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT;
+ vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT;
+
+ vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
+ vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
+ vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE;
+ vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
+
+ vaoSurf->vao->attribs[ATTR_INDEX_POSITION].offset = offset_xyz;
+ vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].offset = offset_st;
+ vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].offset = offset_normal;
+ vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].offset = offset_tangent;
+
+ vaoSurf->vao->attribs[ATTR_INDEX_POSITION].stride = stride_xyz;
+ vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].stride = stride_st;
+ vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].stride = stride_normal;
+ vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].stride = stride_tangent;
+
+ if (mdvModel->numFrames > 1)
+ {
+ vaoSurf->vao->attribs[ATTR_INDEX_POSITION2] = vaoSurf->vao->attribs[ATTR_INDEX_POSITION];
+ vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2 ] = vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ];
+ vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ] = vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ];
+
+ vaoSurf->vao->frameSize = stride_xyz * surf->numVerts;
+ }
+
+ Vao_SetVertexPointers(vaoSurf->vao);
+
+ ri.Free(data);
+ }
+ }
+
+ return true;
+}
+
+
+
+/*
+=================
+R_LoadMDR
+=================
+*/
+static bool R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name )
+{
+ int i, j, k, l;
+ mdrHeader_t *pinmodel, *mdr;
+ mdrFrame_t *frame;
+ mdrLOD_t *lod, *curlod;
+ mdrSurface_t *surf, *cursurf;
+ mdrTriangle_t *tri, *curtri;
+ mdrVertex_t *v, *curv;
+ mdrWeight_t *weight, *curweight;
+ mdrTag_t *tag, *curtag;
+ int size;
+ shader_t *sh;
+
+ pinmodel = (mdrHeader_t *)buffer;
+
+ pinmodel->version = LittleLong(pinmodel->version);
+ if (pinmodel->version != MDR_VERSION)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION);
+ return false;
+ }
+
+ size = LittleLong(pinmodel->ofsEnd);
+
+ if(size > filesize)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name);
+ return false;
+ }
+
+ mod->type = MOD_MDR;
+
+ LL(pinmodel->numFrames);
+ LL(pinmodel->numBones);
+ LL(pinmodel->ofsFrames);
+
+ // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame
+ // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target mdr.
+ if(pinmodel->ofsFrames < 0)
+ {
+ // mdrFrame_t is larger than mdrCompFrame_t:
+ size += pinmodel->numFrames * sizeof(frame->name);
+ // now add enough space for the uncompressed bones.
+ size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t)));
+ }
+
+ // simple bounds check
+ if(pinmodel->numBones < 0 ||
+ sizeof(*mdr) + pinmodel->numFrames * (sizeof(*frame) + (pinmodel->numBones - 1) * sizeof(*frame->bones)) > size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ mod->dataSize += size;
+ mod->modelData = mdr = (mdrHeader_t*)ri.Hunk_Alloc( size, h_low );
+
+ // Copy all the values over from the file and fix endian issues in the process, if necessary.
+
+ mdr->ident = LittleLong(pinmodel->ident);
+ mdr->version = pinmodel->version; // Don't need to swap byte order on this one, we already did above.
+ Q_strncpyz(mdr->name, pinmodel->name, sizeof(mdr->name));
+ mdr->numFrames = pinmodel->numFrames;
+ mdr->numBones = pinmodel->numBones;
+ mdr->numLODs = LittleLong(pinmodel->numLODs);
+ mdr->numTags = LittleLong(pinmodel->numTags);
+ // We don't care about the other offset values, we'll generate them ourselves while loading.
+
+ mod->numLods = mdr->numLODs;
+
+ if ( mdr->numFrames < 1 )
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name);
+ return false;
+ }
+
+ /* The first frame will be put into the first free space after the header */
+ frame = (mdrFrame_t *)(mdr + 1);
+ mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr);
+
+ if (pinmodel->ofsFrames < 0)
+ {
+ mdrCompFrame_t *cframe;
+
+ // compressed model...
+ cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames);
+
+ for(i = 0; i < mdr->numFrames; i++)
+ {
+ for(j = 0; j < 3; j++)
+ {
+ frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]);
+ frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]);
+ frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]);
+ }
+
+ frame->radius = LittleFloat(cframe->radius);
+ frame->name[0] = '\0'; // No name supplied in the compressed version.
+
+ for(j = 0; j < mdr->numBones; j++)
+ {
+ for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++)
+ {
+ // Do swapping for the uncompressing functions. They seem to use shorts
+ // values only, so I assume this will work. Never tested it on other
+ // platforms, though.
+
+ ((unsigned short *)(cframe->bones[j].Comp))[k] =
+ LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] );
+ }
+
+ /* Now do the actual uncompressing */
+ MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp);
+ }
+
+ // Next Frame...
+ cframe = (mdrCompFrame_t *) &cframe->bones[j];
+ frame = (mdrFrame_t *) &frame->bones[j];
+ }
+ }
+ else
+ {
+ mdrFrame_t *curframe;
+
+ // uncompressed model...
+ //
+
+ curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames);
+
+ // swap all the frames
+ for ( i = 0 ; i < mdr->numFrames ; i++)
+ {
+ for(j = 0; j < 3; j++)
+ {
+ frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]);
+ frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]);
+ frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]);
+ }
+
+ frame->radius = LittleFloat(curframe->radius);
+ Q_strncpyz(frame->name, curframe->name, sizeof(frame->name));
+
+ for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++)
+ {
+ ((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] );
+ }
+
+ curframe = (mdrFrame_t *) &curframe->bones[mdr->numBones];
+ frame = (mdrFrame_t *) &frame->bones[mdr->numBones];
+ }
+ }
+
+ // frame should now point to the first free address after all frames.
+ lod = (mdrLOD_t *) frame;
+ mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr);
+
+ curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs));
+
+ // swap all the LOD's
+ for ( l = 0 ; l < mdr->numLODs ; l++)
+ {
+ // simple bounds check
+ if((byte *) (lod + 1) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ lod->numSurfaces = LittleLong(curlod->numSurfaces);
+
+ // swap all the surfaces
+ surf = (mdrSurface_t *) (lod + 1);
+ lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod);
+ cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces));
+
+ for ( i = 0 ; i < lod->numSurfaces ; i++)
+ {
+ // simple bounds check
+ if((byte *) (surf + 1) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ // first do some copying stuff
+
+ surf->ident = SF_MDR;
+ Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name));
+ Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader));
+
+ surf->ofsHeader = (byte *) mdr - (byte *) surf;
+
+ surf->numVerts = LittleLong(cursurf->numVerts);
+ surf->numTriangles = LittleLong(cursurf->numTriangles);
+ // numBoneReferences and BoneReferences generally seem to be unused
+
+ // now do the checks that may fail.
+ if ( surf->numVerts >= SHADER_MAX_VERTEXES )
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on %s (%i).\n",
+ mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface",
+ surf->numVerts );
+ return false;
+ }
+ if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES )
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on %s (%i).\n",
+ mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface",
+ surf->numTriangles );
+ return false;
+ }
+ // lowercase the surface name so skin compares are faster
+ Q_strlwr( surf->name );
+
+ // register the shaders
+ sh = R_FindShader(surf->shader, LIGHTMAP_NONE, true);
+ if ( sh->defaultShader ) {
+ surf->shaderIndex = 0;
+ } else {
+ surf->shaderIndex = sh->index;
+ }
+
+ // now copy the vertexes.
+ v = (mdrVertex_t *) (surf + 1);
+ surf->ofsVerts = (int)((byte *) v - (byte *) surf);
+ curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts));
+
+ for(j = 0; j < surf->numVerts; j++)
+ {
+ LL(curv->numWeights);
+
+ // simple bounds check
+ if(curv->numWeights < 0 || (byte *) (v + 1) + (curv->numWeights - 1) * sizeof(*weight) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ v->normal[0] = LittleFloat(curv->normal[0]);
+ v->normal[1] = LittleFloat(curv->normal[1]);
+ v->normal[2] = LittleFloat(curv->normal[2]);
+
+ v->texCoords[0] = LittleFloat(curv->texCoords[0]);
+ v->texCoords[1] = LittleFloat(curv->texCoords[1]);
+
+ v->numWeights = curv->numWeights;
+ weight = &v->weights[0];
+ curweight = &curv->weights[0];
+
+ // Now copy all the weights
+ for(k = 0; k < v->numWeights; k++)
+ {
+ weight->boneIndex = LittleLong(curweight->boneIndex);
+ weight->boneWeight = LittleFloat(curweight->boneWeight);
+
+ weight->offset[0] = LittleFloat(curweight->offset[0]);
+ weight->offset[1] = LittleFloat(curweight->offset[1]);
+ weight->offset[2] = LittleFloat(curweight->offset[2]);
+
+ weight++;
+ curweight++;
+ }
+
+ v = (mdrVertex_t *) weight;
+ curv = (mdrVertex_t *) curweight;
+ }
+
+ // we know the offset to the triangles now:
+ tri = (mdrTriangle_t *) v;
+ surf->ofsTriangles = (int)((byte *) tri - (byte *) surf);
+ curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles));
+
+ // simple bounds check
+ if(surf->numTriangles < 0 || (byte *) (tri + surf->numTriangles) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ for(j = 0; j < surf->numTriangles; j++)
+ {
+ tri->indexes[0] = LittleLong(curtri->indexes[0]);
+ tri->indexes[1] = LittleLong(curtri->indexes[1]);
+ tri->indexes[2] = LittleLong(curtri->indexes[2]);
+
+ tri++;
+ curtri++;
+ }
+
+ // tri now points to the end of the surface.
+ surf->ofsEnd = (byte *) tri - (byte *) surf;
+ surf = (mdrSurface_t *) tri;
+
+ // find the next surface.
+ cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd));
+ }
+
+ // surf points to the next lod now.
+ lod->ofsEnd = (int)((byte *) surf - (byte *) lod);
+ lod = (mdrLOD_t *) surf;
+
+ // find the next LOD.
+ curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd));
+ }
+
+ // lod points to the first tag now, so update the offset too.
+ tag = (mdrTag_t *) lod;
+ mdr->ofsTags = (int)((byte *) tag - (byte *) mdr);
+ curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags));
+
+ // simple bounds check
+ if(mdr->numTags < 0 || (byte *) (tag + mdr->numTags) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return false;
+ }
+
+ for (i = 0 ; i < mdr->numTags ; i++)
+ {
+ tag->boneIndex = LittleLong(curtag->boneIndex);
+ Q_strncpyz(tag->name, curtag->name, sizeof(tag->name));
+
+ tag++;
+ curtag++;
+ }
+
+ // And finally we know the real offset to the end.
+ mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr);
+
+ // phew! we're done.
+
+ return true;
+}
+
+
+
+//=============================================================================
+
+/*
+** RE_BeginRegistration
+*/
+void RE_BeginRegistration( glconfig_t *glconfigOut ) {
+ int i;
+
+ R_Init();
+
+ *glconfigOut = glConfig;
+
+ R_IssuePendingRenderCommands();
+
+ tr.visIndex = 0;
+ // force markleafs to regenerate
+ for(i = 0; i < MAX_VISCOUNTS; i++) {
+ tr.visClusters[i] = -2;
+ }
+
+ R_ClearFlares();
+ RE_ClearScene();
+
+ tr.registered = true;
+}
+
+//=============================================================================
+
+/*
+===============
+R_ModelInit
+===============
+*/
+void R_ModelInit( void ) {
+ model_t *mod;
+
+ // leave a space for NULL model
+ tr.numModels = 0;
+
+ mod = R_AllocModel();
+ mod->type = MOD_BAD;
+}
+
+
+/*
+================
+R_Modellist_f
+================
+*/
+void R_Modellist_f( void ) {
+ int i, j;
+ model_t *mod;
+ int total;
+ int lods;
+
+ total = 0;
+ for ( i = 1 ; i < tr.numModels; i++ ) {
+ mod = tr.models[i];
+ lods = 1;
+ for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) {
+ if ( mod->mdv[j] && mod->mdv[j] != mod->mdv[j-1] ) {
+ lods++;
+ }
+ }
+ ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name );
+ total += mod->dataSize;
+ }
+ ri.Printf( PRINT_ALL, "%8i : Total models\n", total );
+
+#if 0 // not working right with new hunk
+ if ( tr.world ) {
+ ri.Printf( PRINT_ALL, "\n%8i : %s\n", tr.world->dataSize, tr.world->name );
+ }
+#endif
+}
+
+
+//=============================================================================
+
+
+/*
+================
+R_GetTag
+================
+*/
+static mdvTag_t *R_GetTag( mdvModel_t *mod, int frame, const char *_tagName ) {
+ int i;
+ mdvTag_t *tag;
+ mdvTagName_t *tagName;
+
+ if ( frame >= mod->numFrames ) {
+ // it is possible to have a bad frame while changing models, so don't error
+ frame = mod->numFrames - 1;
+ }
+
+ tag = mod->tags + frame * mod->numTags;
+ tagName = mod->tagNames;
+ for(i = 0; i < mod->numTags; i++, tag++, tagName++)
+ {
+ if(!strcmp(tagName->name, _tagName))
+ {
+ return tag;
+ }
+ }
+
+ return NULL;
+}
+
+mdvTag_t *R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, mdvTag_t * dest)
+{
+ int i, j, k;
+ int frameSize;
+ mdrFrame_t *frame;
+ mdrTag_t *tag;
+
+ if ( framenum >= mod->numFrames )
+ {
+ // it is possible to have a bad frame while changing models, so don't error
+ framenum = mod->numFrames - 1;
+ }
+
+ tag = (mdrTag_t *)((byte *)mod + mod->ofsTags);
+ for ( i = 0 ; i < mod->numTags ; i++, tag++ )
+ {
+ if ( !strcmp( tag->name, tagName ) )
+ {
+ // uncompressed model...
+ //
+ frameSize = (intptr_t)( &((mdrFrame_t *)0)->bones[ mod->numBones ] );
+ frame = (mdrFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize );
+
+ for (j = 0; j < 3; j++)
+ {
+ for (k = 0; k < 3; k++)
+ dest->axis[j][k] = frame->bones[tag->boneIndex].matrix[k][j];
+ }
+
+ dest->origin[0] = frame->bones[tag->boneIndex].matrix[0][3];
+ dest->origin[1] = frame->bones[tag->boneIndex].matrix[1][3];
+ dest->origin[2] = frame->bones[tag->boneIndex].matrix[2][3];
+
+ return dest;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+================
+R_LerpTag
+================
+*/
+int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
+ float frac, const char *tagName ) {
+ mdvTag_t *start, *end;
+ mdvTag_t start_space, end_space;
+ int i;
+ float frontLerp, backLerp;
+ model_t *model;
+
+ model = R_GetModelByHandle( handle );
+ if ( !model->mdv[0] )
+ {
+ if(model->type == MOD_MDR)
+ {
+ start = R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, &start_space);
+ end = R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, &end_space);
+ }
+ else if( model->type == MOD_IQM ) {
+ return R_IQMLerpTag( tag, (iqmData_t*)model->modelData, startFrame, endFrame, frac, tagName );
+ } else {
+ start = end = NULL;
+ }
+ }
+ else
+ {
+ start = R_GetTag( model->mdv[0], startFrame, tagName );
+ end = R_GetTag( model->mdv[0], endFrame, tagName );
+ }
+
+ if ( !start || !end ) {
+ AxisClear( tag->axis );
+ VectorClear( tag->origin );
+ return false;
+ }
+
+ frontLerp = frac;
+ backLerp = 1.0f - frac;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ tag->origin[i] = start->origin[i] * backLerp + end->origin[i] * frontLerp;
+ tag->axis[0][i] = start->axis[0][i] * backLerp + end->axis[0][i] * frontLerp;
+ tag->axis[1][i] = start->axis[1][i] * backLerp + end->axis[1][i] * frontLerp;
+ tag->axis[2][i] = start->axis[2][i] * backLerp + end->axis[2][i] * frontLerp;
+ }
+ VectorNormalize( tag->axis[0] );
+ VectorNormalize( tag->axis[1] );
+ VectorNormalize( tag->axis[2] );
+ return true;
+}
+
+
+/*
+====================
+R_ModelBounds
+====================
+*/
+void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) {
+ model_t *model;
+
+ model = R_GetModelByHandle( handle );
+
+ if(model->type == MOD_BRUSH) {
+ VectorCopy( model->bmodel->bounds[0], mins );
+ VectorCopy( model->bmodel->bounds[1], maxs );
+
+ return;
+ } else if (model->type == MOD_MESH) {
+ mdvModel_t *header;
+ mdvFrame_t *frame;
+
+ header = model->mdv[0];
+ frame = header->frames;
+
+ VectorCopy( frame->bounds[0], mins );
+ VectorCopy( frame->bounds[1], maxs );
+
+ return;
+ } else if (model->type == MOD_MDR) {
+ mdrHeader_t *header;
+ mdrFrame_t *frame;
+
+ header = (mdrHeader_t *)model->modelData;
+ frame = (mdrFrame_t *) ((byte *)header + header->ofsFrames);
+
+ VectorCopy( frame->bounds[0], mins );
+ VectorCopy( frame->bounds[1], maxs );
+
+ return;
+ } else if(model->type == MOD_IQM) {
+ iqmData_t *iqmData;
+
+ iqmData = (iqmData_t*)model->modelData;
+
+ if(iqmData->bounds)
+ {
+ VectorCopy(iqmData->bounds, mins);
+ VectorCopy(iqmData->bounds + 3, maxs);
+ return;
+ }
+ }
+
+ VectorClear( mins );
+ VectorClear( maxs );
+}
diff --git a/src/renderergl2/tr_model_iqm.cpp b/src/renderergl2/tr_model_iqm.cpp
new file mode 100644
index 0000000..40ce9da
--- /dev/null
+++ b/src/renderergl2/tr_model_iqm.cpp
@@ -0,0 +1,1196 @@
+/*
+===========================================================================
+Copyright (C) 2011 Thilo Schulz <thilo@tjps.eu>
+Copyright (C) 2011 Matthias Bentrup <matthias.bentrup@googlemail.com>
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+#define LL(x) x=LittleLong(x)
+
+// 3x4 identity matrix
+static float identityMatrix[12] = {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0
+};
+
+static bool IQM_CheckRange( iqmHeader_t *header, int offset,
+ int count,int size ) {
+ // return true if the range specified by offset, count and size
+ // doesn't fit into the file
+ return ( count <= 0 ||
+ offset < 0 ||
+ offset > header->filesize ||
+ offset + count * size < 0 ||
+ offset + count * size > header->filesize );
+}
+// "multiply" 3x4 matrices, these are assumed to be the top 3 rows
+// of a 4x4 matrix with the last row = (0 0 0 1)
+static void Matrix34Multiply( float *a, float *b, float *out ) {
+ out[ 0] = a[0] * b[0] + a[1] * b[4] + a[ 2] * b[ 8];
+ out[ 1] = a[0] * b[1] + a[1] * b[5] + a[ 2] * b[ 9];
+ out[ 2] = a[0] * b[2] + a[1] * b[6] + a[ 2] * b[10];
+ out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3];
+ out[ 4] = a[4] * b[0] + a[5] * b[4] + a[ 6] * b[ 8];
+ out[ 5] = a[4] * b[1] + a[5] * b[5] + a[ 6] * b[ 9];
+ out[ 6] = a[4] * b[2] + a[5] * b[6] + a[ 6] * b[10];
+ out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7];
+ out[ 8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[ 8];
+ out[ 9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[ 9];
+ out[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10];
+ out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11];
+}
+static void Matrix34Multiply_OnlySetOrigin( float *a, float *b, float *out ) {
+ out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3];
+ out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7];
+ out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11];
+}
+static void InterpolateMatrix( float *a, float *b, float lerp, float *mat ) {
+ float unLerp = 1.0f - lerp;
+
+ mat[ 0] = a[ 0] * unLerp + b[ 0] * lerp;
+ mat[ 1] = a[ 1] * unLerp + b[ 1] * lerp;
+ mat[ 2] = a[ 2] * unLerp + b[ 2] * lerp;
+ mat[ 3] = a[ 3] * unLerp + b[ 3] * lerp;
+ mat[ 4] = a[ 4] * unLerp + b[ 4] * lerp;
+ mat[ 5] = a[ 5] * unLerp + b[ 5] * lerp;
+ mat[ 6] = a[ 6] * unLerp + b[ 6] * lerp;
+ mat[ 7] = a[ 7] * unLerp + b[ 7] * lerp;
+ mat[ 8] = a[ 8] * unLerp + b[ 8] * lerp;
+ mat[ 9] = a[ 9] * unLerp + b[ 9] * lerp;
+ mat[10] = a[10] * unLerp + b[10] * lerp;
+ mat[11] = a[11] * unLerp + b[11] * lerp;
+}
+static void JointToMatrix( vec4_t rot, vec3_t scale, vec3_t trans,
+ float *mat ) {
+ float xx = 2.0f * rot[0] * rot[0];
+ float yy = 2.0f * rot[1] * rot[1];
+ float zz = 2.0f * rot[2] * rot[2];
+ float xy = 2.0f * rot[0] * rot[1];
+ float xz = 2.0f * rot[0] * rot[2];
+ float yz = 2.0f * rot[1] * rot[2];
+ float wx = 2.0f * rot[3] * rot[0];
+ float wy = 2.0f * rot[3] * rot[1];
+ float wz = 2.0f * rot[3] * rot[2];
+
+ mat[ 0] = scale[0] * (1.0f - (yy + zz));
+ mat[ 1] = scale[0] * (xy - wz);
+ mat[ 2] = scale[0] * (xz + wy);
+ mat[ 3] = trans[0];
+ mat[ 4] = scale[1] * (xy + wz);
+ mat[ 5] = scale[1] * (1.0f - (xx + zz));
+ mat[ 6] = scale[1] * (yz - wx);
+ mat[ 7] = trans[1];
+ mat[ 8] = scale[2] * (xz - wy);
+ mat[ 9] = scale[2] * (yz + wx);
+ mat[10] = scale[2] * (1.0f - (xx + yy));
+ mat[11] = trans[2];
+}
+static void Matrix34Invert( float *inMat, float *outMat )
+{
+ vec3_t trans;
+ float invSqrLen, *v;
+
+ outMat[ 0] = inMat[ 0]; outMat[ 1] = inMat[ 4]; outMat[ 2] = inMat[ 8];
+ outMat[ 4] = inMat[ 1]; outMat[ 5] = inMat[ 5]; outMat[ 6] = inMat[ 9];
+ outMat[ 8] = inMat[ 2]; outMat[ 9] = inMat[ 6]; outMat[10] = inMat[10];
+
+ v = outMat + 0; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
+ v = outMat + 4; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
+ v = outMat + 8; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
+
+ trans[0] = inMat[ 3];
+ trans[1] = inMat[ 7];
+ trans[2] = inMat[11];
+
+ outMat[ 3] = -DotProduct(outMat + 0, trans);
+ outMat[ 7] = -DotProduct(outMat + 4, trans);
+ outMat[11] = -DotProduct(outMat + 8, trans);
+}
+
+/*
+=================
+R_LoadIQM
+
+Load an IQM model and compute the joint matrices for every frame.
+=================
+*/
+bool R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_name ) {
+ iqmHeader_t *header;
+ iqmVertexArray_t *vertexarray;
+ iqmTriangle_t *triangle;
+ iqmMesh_t *mesh;
+ iqmJoint_t *joint;
+ iqmPose_t *pose;
+ iqmBounds_t *bounds;
+ unsigned short *framedata;
+ char *str;
+ int i, j;
+ float jointInvMats[IQM_MAX_JOINTS * 12] = {0.0f};
+ float *mat, *matInv;
+ size_t size, joint_names;
+ iqmData_t *iqmData;
+ srfIQModel_t *surface;
+ char meshName[MAX_QPATH];
+ byte blendIndexesType, blendWeightsType;
+
+ if( filesize < sizeof(iqmHeader_t) ) {
+ return false;
+ }
+
+ header = (iqmHeader_t *)buffer;
+ if( Q_strncmp( header->magic, IQM_MAGIC, sizeof(header->magic) ) ) {
+ return false;
+ }
+
+ LL( header->version );
+ if( header->version != IQM_VERSION ) {
+ ri.Printf(PRINT_WARNING, "R_LoadIQM: %s is a unsupported IQM version (%d), only version %d is supported.\n",
+ mod_name, header->version, IQM_VERSION);
+ return false;
+ }
+
+ LL( header->filesize );
+ if( header->filesize > filesize || header->filesize > 16<<20 ) {
+ return false;
+ }
+
+ LL( header->flags );
+ LL( header->num_text );
+ LL( header->ofs_text );
+ LL( header->num_meshes );
+ LL( header->ofs_meshes );
+ LL( header->num_vertexarrays );
+ LL( header->num_vertexes );
+ LL( header->ofs_vertexarrays );
+ LL( header->num_triangles );
+ LL( header->ofs_triangles );
+ LL( header->ofs_adjacency );
+ LL( header->num_joints );
+ LL( header->ofs_joints );
+ LL( header->num_poses );
+ LL( header->ofs_poses );
+ LL( header->num_anims );
+ LL( header->ofs_anims );
+ LL( header->num_frames );
+ LL( header->num_framechannels );
+ LL( header->ofs_frames );
+ LL( header->ofs_bounds );
+ LL( header->num_comment );
+ LL( header->ofs_comment );
+ LL( header->num_extensions );
+ LL( header->ofs_extensions );
+
+ // check ioq3 joint limit
+ if ( header->num_joints > IQM_MAX_JOINTS ) {
+ ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %d joints (%d).\n",
+ mod_name, IQM_MAX_JOINTS, header->num_joints);
+ return false;
+ }
+
+ blendIndexesType = blendWeightsType = IQM_UBYTE;
+
+ // check and swap vertex arrays
+ if( IQM_CheckRange( header, header->ofs_vertexarrays,
+ header->num_vertexarrays,
+ sizeof(iqmVertexArray_t) ) ) {
+ return false;
+ }
+ vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays);
+ for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) {
+ int n, *intPtr;
+
+ if( vertexarray->size <= 0 || vertexarray->size > 4 ) {
+ return false;
+ }
+
+ // total number of values
+ n = header->num_vertexes * vertexarray->size;
+
+ switch( vertexarray->format ) {
+ case IQM_BYTE:
+ case IQM_UBYTE:
+ // 1 byte, no swapping necessary
+ if( IQM_CheckRange( header, vertexarray->offset,
+ n, sizeof(byte) ) ) {
+ return false;
+ }
+ break;
+ case IQM_INT:
+ case IQM_UINT:
+ case IQM_FLOAT:
+ // 4-byte swap
+ if( IQM_CheckRange( header, vertexarray->offset,
+ n, sizeof(float) ) ) {
+ return false;
+ }
+ intPtr = (int *)((byte *)header + vertexarray->offset);
+ for( j = 0; j < n; j++, intPtr++ ) {
+ LL( *intPtr );
+ }
+ break;
+ default:
+ // not supported
+ return false;
+ break;
+ }
+
+ switch( vertexarray->type ) {
+ case IQM_POSITION:
+ case IQM_NORMAL:
+ if( vertexarray->format != IQM_FLOAT ||
+ vertexarray->size != 3 ) {
+ return false;
+ }
+ break;
+ case IQM_TANGENT:
+ if( vertexarray->format != IQM_FLOAT ||
+ vertexarray->size != 4 ) {
+ return false;
+ }
+ break;
+ case IQM_TEXCOORD:
+ if( vertexarray->format != IQM_FLOAT ||
+ vertexarray->size != 2 ) {
+ return false;
+ }
+ break;
+ case IQM_BLENDINDEXES:
+ if( (vertexarray->format != IQM_INT &&
+ vertexarray->format != IQM_UBYTE) ||
+ vertexarray->size != 4 ) {
+ return false;
+ }
+ blendIndexesType = vertexarray->format;
+ break;
+ case IQM_BLENDWEIGHTS:
+ if( (vertexarray->format != IQM_FLOAT &&
+ vertexarray->format != IQM_UBYTE) ||
+ vertexarray->size != 4 ) {
+ return false;
+ }
+ blendWeightsType = vertexarray->format;
+ break;
+ case IQM_COLOR:
+ if( vertexarray->format != IQM_UBYTE ||
+ vertexarray->size != 4 ) {
+ return false;
+ }
+ break;
+ }
+ }
+
+ // check and swap triangles
+ if( IQM_CheckRange( header, header->ofs_triangles,
+ header->num_triangles, sizeof(iqmTriangle_t) ) ) {
+ return false;
+ }
+ triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles);
+ for( i = 0; i < header->num_triangles; i++, triangle++ ) {
+ LL( triangle->vertex[0] );
+ LL( triangle->vertex[1] );
+ LL( triangle->vertex[2] );
+
+ if( triangle->vertex[0] > header->num_vertexes ||
+ triangle->vertex[1] > header->num_vertexes ||
+ triangle->vertex[2] > header->num_vertexes ) {
+ return false;
+ }
+ }
+
+ // check and swap meshes
+ if( IQM_CheckRange( header, header->ofs_meshes,
+ header->num_meshes, sizeof(iqmMesh_t) ) ) {
+ return false;
+ }
+ mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes);
+ for( i = 0; i < header->num_meshes; i++, mesh++) {
+ LL( mesh->name );
+ LL( mesh->material );
+ LL( mesh->first_vertex );
+ LL( mesh->num_vertexes );
+ LL( mesh->first_triangle );
+ LL( mesh->num_triangles );
+
+ if ( mesh->name < header->num_text ) {
+ Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) );
+ } else {
+ meshName[0] = '\0';
+ }
+
+ // check ioq3 limits
+ if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES )
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n",
+ mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface",
+ mesh->num_vertexes );
+ return false;
+ }
+ if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES )
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n",
+ mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface",
+ mesh->num_triangles );
+ return false;
+ }
+
+ if( mesh->first_vertex >= header->num_vertexes ||
+ mesh->first_vertex + mesh->num_vertexes > header->num_vertexes ||
+ mesh->first_triangle >= header->num_triangles ||
+ mesh->first_triangle + mesh->num_triangles > header->num_triangles ||
+ mesh->name >= header->num_text ||
+ mesh->material >= header->num_text ) {
+ return false;
+ }
+ }
+
+ if( header->num_poses != header->num_joints && header->num_poses != 0 ) {
+ ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n",
+ mod_name, header->num_poses, header->num_joints );
+ return false;
+ }
+
+ joint_names = 0;
+
+ if ( header->num_joints )
+ {
+ // check and swap joints
+ if( IQM_CheckRange( header, header->ofs_joints,
+ header->num_joints, sizeof(iqmJoint_t) ) ) {
+ return false;
+ }
+ joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
+ for( i = 0; i < header->num_joints; i++, joint++ ) {
+ LL( joint->name );
+ LL( joint->parent );
+ LL( joint->translate[0] );
+ LL( joint->translate[1] );
+ LL( joint->translate[2] );
+ LL( joint->rotate[0] );
+ LL( joint->rotate[1] );
+ LL( joint->rotate[2] );
+ LL( joint->rotate[3] );
+ LL( joint->scale[0] );
+ LL( joint->scale[1] );
+ LL( joint->scale[2] );
+
+ if( joint->parent < -1 ||
+ joint->parent >= (int)header->num_joints ||
+ joint->name >= (int)header->num_text ) {
+ return false;
+ }
+ joint_names += strlen( (char *)header + header->ofs_text +
+ joint->name ) + 1;
+ }
+ }
+
+ if ( header->num_poses )
+ {
+ // check and swap poses
+ if( IQM_CheckRange( header, header->ofs_poses,
+ header->num_poses, sizeof(iqmPose_t) ) ) {
+ return false;
+ }
+ pose = (iqmPose_t *)((byte *)header + header->ofs_poses);
+ for( i = 0; i < header->num_poses; i++, pose++ ) {
+ LL( pose->parent );
+ LL( pose->mask );
+ LL( pose->channeloffset[0] );
+ LL( pose->channeloffset[1] );
+ LL( pose->channeloffset[2] );
+ LL( pose->channeloffset[3] );
+ LL( pose->channeloffset[4] );
+ LL( pose->channeloffset[5] );
+ LL( pose->channeloffset[6] );
+ LL( pose->channeloffset[7] );
+ LL( pose->channeloffset[8] );
+ LL( pose->channeloffset[9] );
+ LL( pose->channelscale[0] );
+ LL( pose->channelscale[1] );
+ LL( pose->channelscale[2] );
+ LL( pose->channelscale[3] );
+ LL( pose->channelscale[4] );
+ LL( pose->channelscale[5] );
+ LL( pose->channelscale[6] );
+ LL( pose->channelscale[7] );
+ LL( pose->channelscale[8] );
+ LL( pose->channelscale[9] );
+ }
+ }
+
+ if (header->ofs_bounds)
+ {
+ // check and swap model bounds
+ if(IQM_CheckRange(header, header->ofs_bounds,
+ header->num_frames, sizeof(*bounds)))
+ {
+ return false;
+ }
+ bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds);
+ for(i = 0; i < header->num_frames; i++)
+ {
+ LL(bounds->bbmin[0]);
+ LL(bounds->bbmin[1]);
+ LL(bounds->bbmin[2]);
+ LL(bounds->bbmax[0]);
+ LL(bounds->bbmax[1]);
+ LL(bounds->bbmax[2]);
+
+ bounds++;
+ }
+ }
+
+ // allocate the model and copy the data
+ size = sizeof(iqmData_t);
+ size += header->num_meshes * sizeof( srfIQModel_t );
+ size += header->num_joints * 12 * sizeof( float ); // joint mats
+ size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats
+ if(header->ofs_bounds)
+ size += header->num_frames * 6 * sizeof(float); // model bounds
+ size += header->num_vertexes * 3 * sizeof(float); // positions
+ size += header->num_vertexes * 2 * sizeof(float); // texcoords
+ size += header->num_vertexes * 3 * sizeof(float); // normals
+ size += header->num_vertexes * 4 * sizeof(float); // tangents
+ size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes
+ size += header->num_vertexes * 4 * sizeof(byte); // colors
+ size += header->num_joints * sizeof(int); // parents
+ size += header->num_triangles * 3 * sizeof(int); // triangles
+ size += joint_names; // joint names
+
+ // blendWeights
+ if (blendWeightsType == IQM_FLOAT) {
+ size += header->num_vertexes * 4 * sizeof(float);
+ } else {
+ size += header->num_vertexes * 4 * sizeof(byte);
+ }
+
+ mod->type = MOD_IQM;
+ iqmData = (iqmData_t *)ri.Hunk_Alloc( size, h_low );
+ mod->modelData = iqmData;
+
+ // fill header
+ iqmData->num_vertexes = header->num_vertexes;
+ iqmData->num_triangles = header->num_triangles;
+ iqmData->num_frames = header->num_frames;
+ iqmData->num_surfaces = header->num_meshes;
+ iqmData->num_joints = header->num_joints;
+ iqmData->num_poses = header->num_poses;
+ iqmData->blendWeightsType = blendWeightsType;
+ iqmData->surfaces = (srfIQModel_t *)(iqmData + 1);
+ iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces);
+ iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints;
+ if(header->ofs_bounds)
+ {
+ iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames;
+ iqmData->positions = iqmData->bounds + 6 * header->num_frames;
+ }
+ else
+ iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames;
+ iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes;
+ iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes;
+ iqmData->tangents = iqmData->normals + 3 * header->num_vertexes;
+ iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes);
+
+ if(blendWeightsType == IQM_FLOAT) {
+ iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes);
+ iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes);
+ } else {
+ iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes;
+ iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes;
+ }
+
+ iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes);
+ iqmData->triangles = iqmData->jointParents + header->num_joints;
+ iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles);
+
+ if ( header->num_joints == 0 )
+ iqmData->jointMats = NULL;
+
+ if ( header->num_poses == 0 )
+ iqmData->poseMats = NULL;
+
+ // calculate joint matrices and their inverses
+ // joint inverses are needed only until the pose matrices are calculated
+ mat = iqmData->jointMats;
+ matInv = jointInvMats;
+ joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
+ for( i = 0; i < header->num_joints; i++, joint++ ) {
+ float baseFrame[12], invBaseFrame[12];
+
+ JointToMatrix( joint->rotate, joint->scale, joint->translate, baseFrame );
+ Matrix34Invert( baseFrame, invBaseFrame );
+
+ if ( joint->parent >= 0 )
+ {
+ Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat );
+ mat += 12;
+ Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv );
+ matInv += 12;
+ }
+ else
+ {
+ Com_Memcpy( mat, baseFrame, sizeof(baseFrame) );
+ mat += 12;
+ Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) );
+ matInv += 12;
+ }
+ }
+
+ // calculate pose matrices
+ framedata = (unsigned short *)((byte *)header + header->ofs_frames);
+ mat = iqmData->poseMats;
+ for( i = 0; i < header->num_frames; i++ ) {
+ pose = (iqmPose_t *)((byte *)header + header->ofs_poses);
+ for( j = 0; j < header->num_poses; j++, pose++ ) {
+ vec3_t translate;
+ vec4_t rotate;
+ vec3_t scale;
+ float mat1[12], mat2[12];
+
+ translate[0] = pose->channeloffset[0];
+ if( pose->mask & 0x001)
+ translate[0] += *framedata++ * pose->channelscale[0];
+ translate[1] = pose->channeloffset[1];
+ if( pose->mask & 0x002)
+ translate[1] += *framedata++ * pose->channelscale[1];
+ translate[2] = pose->channeloffset[2];
+ if( pose->mask & 0x004)
+ translate[2] += *framedata++ * pose->channelscale[2];
+
+ rotate[0] = pose->channeloffset[3];
+ if( pose->mask & 0x008)
+ rotate[0] += *framedata++ * pose->channelscale[3];
+ rotate[1] = pose->channeloffset[4];
+ if( pose->mask & 0x010)
+ rotate[1] += *framedata++ * pose->channelscale[4];
+ rotate[2] = pose->channeloffset[5];
+ if( pose->mask & 0x020)
+ rotate[2] += *framedata++ * pose->channelscale[5];
+ rotate[3] = pose->channeloffset[6];
+ if( pose->mask & 0x040)
+ rotate[3] += *framedata++ * pose->channelscale[6];
+
+ scale[0] = pose->channeloffset[7];
+ if( pose->mask & 0x080)
+ scale[0] += *framedata++ * pose->channelscale[7];
+ scale[1] = pose->channeloffset[8];
+ if( pose->mask & 0x100)
+ scale[1] += *framedata++ * pose->channelscale[8];
+ scale[2] = pose->channeloffset[9];
+ if( pose->mask & 0x200)
+ scale[2] += *framedata++ * pose->channelscale[9];
+
+ // construct transformation matrix
+ JointToMatrix( rotate, scale, translate, mat1 );
+
+ if( pose->parent >= 0 ) {
+ Matrix34Multiply( iqmData->jointMats + 12 * pose->parent,
+ mat1, mat2 );
+ } else {
+ Com_Memcpy( mat2, mat1, sizeof(mat1) );
+ }
+
+ Matrix34Multiply( mat2, jointInvMats + 12 * j, mat );
+ mat += 12;
+ }
+ }
+
+ // register shaders
+ // overwrite the material offset with the shader index
+ mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes);
+ surface = iqmData->surfaces;
+ str = (char *)header + header->ofs_text;
+ for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) {
+ surface->surfaceType = SF_IQM;
+ Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name));
+ Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster
+ surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, true );
+ if( surface->shader->defaultShader )
+ surface->shader = tr.defaultShader;
+ surface->data = iqmData;
+ surface->first_vertex = mesh->first_vertex;
+ surface->num_vertexes = mesh->num_vertexes;
+ surface->first_triangle = mesh->first_triangle;
+ surface->num_triangles = mesh->num_triangles;
+ }
+
+ // copy vertexarrays and indexes
+ vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays);
+ for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) {
+ int n;
+
+ // total number of values
+ n = header->num_vertexes * vertexarray->size;
+
+ switch( vertexarray->type ) {
+ case IQM_POSITION:
+ Com_Memcpy( iqmData->positions,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(float) );
+ break;
+ case IQM_NORMAL:
+ Com_Memcpy( iqmData->normals,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(float) );
+ break;
+ case IQM_TANGENT:
+ Com_Memcpy( iqmData->tangents,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(float) );
+ break;
+ case IQM_TEXCOORD:
+ Com_Memcpy( iqmData->texcoords,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(float) );
+ break;
+ case IQM_BLENDINDEXES:
+ if( blendIndexesType == IQM_INT ) {
+ int *data = (int*)((byte*)header + vertexarray->offset);
+ for ( j = 0; j < n; j++ ) {
+ iqmData->blendIndexes[j] = (byte)data[j];
+ }
+ } else {
+ Com_Memcpy( iqmData->blendIndexes,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(byte) );
+ }
+ break;
+ case IQM_BLENDWEIGHTS:
+ if( blendWeightsType == IQM_FLOAT ) {
+ Com_Memcpy( iqmData->blendWeights.f,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(float) );
+ } else {
+ Com_Memcpy( iqmData->blendWeights.b,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(byte) );
+ }
+ break;
+ case IQM_COLOR:
+ Com_Memcpy( iqmData->colors,
+ (byte *)header + vertexarray->offset,
+ n * sizeof(byte) );
+ break;
+ }
+ }
+
+ // copy joint parents
+ joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
+ for( i = 0; i < header->num_joints; i++, joint++ ) {
+ iqmData->jointParents[i] = joint->parent;
+ }
+
+ // copy triangles
+ triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles);
+ for( i = 0; i < header->num_triangles; i++, triangle++ ) {
+ iqmData->triangles[3*i+0] = triangle->vertex[0];
+ iqmData->triangles[3*i+1] = triangle->vertex[1];
+ iqmData->triangles[3*i+2] = triangle->vertex[2];
+ }
+
+ // copy joint names
+ str = iqmData->names;
+ joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
+ for( i = 0; i < header->num_joints; i++, joint++ ) {
+ char *name = (char *)header + header->ofs_text +
+ joint->name;
+ int len = strlen( name ) + 1;
+ Com_Memcpy( str, name, len );
+ str += len;
+ }
+
+ // copy model bounds
+ if(header->ofs_bounds)
+ {
+ mat = iqmData->bounds;
+ bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds);
+ for(i = 0; i < header->num_frames; i++)
+ {
+ mat[0] = bounds->bbmin[0];
+ mat[1] = bounds->bbmin[1];
+ mat[2] = bounds->bbmin[2];
+ mat[3] = bounds->bbmax[0];
+ mat[4] = bounds->bbmax[1];
+ mat[5] = bounds->bbmax[2];
+
+ mat += 6;
+ bounds++;
+ }
+ }
+
+ return true;
+}
+
+/*
+=============
+R_CullIQM
+=============
+*/
+static int R_CullIQM( iqmData_t *data, trRefEntity_t *ent ) {
+ vec3_t bounds[2];
+ vec_t *oldBounds, *newBounds;
+ int i;
+
+ if (!data->bounds) {
+ tr.pc.c_box_cull_md3_clip++;
+ return CULL_CLIP;
+ }
+
+ // compute bounds pointers
+ oldBounds = data->bounds + 6*ent->e.oldframe;
+ newBounds = data->bounds + 6*ent->e.frame;
+
+ // calculate a bounding box in the current coordinate system
+ for (i = 0 ; i < 3 ; i++) {
+ bounds[0][i] = oldBounds[i] < newBounds[i] ? oldBounds[i] : newBounds[i];
+ bounds[1][i] = oldBounds[i+3] > newBounds[i+3] ? oldBounds[i+3] : newBounds[i+3];
+ }
+
+ switch ( R_CullLocalBox( bounds ) )
+ {
+ case CULL_IN:
+ tr.pc.c_box_cull_md3_in++;
+ return CULL_IN;
+ case CULL_CLIP:
+ tr.pc.c_box_cull_md3_clip++;
+ return CULL_CLIP;
+ case CULL_OUT:
+ default:
+ tr.pc.c_box_cull_md3_out++;
+ return CULL_OUT;
+ }
+}
+
+/*
+=================
+R_ComputeIQMFogNum
+
+=================
+*/
+int R_ComputeIQMFogNum( iqmData_t *data, trRefEntity_t *ent ) {
+ int i, j;
+ fog_t *fog;
+ const vec_t *bounds;
+ const vec_t defaultBounds[6] = { -8, -8, -8, 8, 8, 8 };
+ vec3_t diag, center;
+ vec3_t localOrigin;
+ vec_t radius;
+
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ return 0;
+ }
+
+ // FIXME: non-normalized axis issues
+ if (data->bounds) {
+ bounds = data->bounds + 6*ent->e.frame;
+ } else {
+ bounds = defaultBounds;
+ }
+ VectorSubtract( bounds+3, bounds, diag );
+ VectorMA( bounds, 0.5f, diag, center );
+ VectorAdd( ent->e.origin, center, localOrigin );
+ radius = 0.5f * VectorLength( diag );
+
+ for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
+ fog = &tr.world->fogs[i];
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( localOrigin[j] - radius >= fog->bounds[1][j] ) {
+ break;
+ }
+ if ( localOrigin[j] + radius <= fog->bounds[0][j] ) {
+ break;
+ }
+ }
+ if ( j == 3 ) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+/*
+=================
+R_AddIQMSurfaces
+
+Add all surfaces of this model
+=================
+*/
+void R_AddIQMSurfaces( trRefEntity_t *ent ) {
+ iqmData_t *data;
+ srfIQModel_t *surface;
+ int i, j;
+ bool personalModel;
+ int cull;
+ int fogNum;
+ int cubemapIndex;
+ shader_t *shader;
+ skin_t *skin;
+
+ data = (iqmData_t*)tr.currentModel->modelData;
+ surface = data->surfaces;
+
+ // don't add third_person objects if not in a portal
+ personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal
+ || (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)));
+
+
+ if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
+ ent->e.frame %= data->num_frames;
+ ent->e.oldframe %= data->num_frames;
+ }
+
+ //
+ // Validate the frames so there is no chance of a crash.
+ // This will write directly into the entity structure, so
+ // when the surfaces are rendered, they don't need to be
+ // range checked again.
+ //
+ if ( (ent->e.frame >= data->num_frames)
+ || (ent->e.frame < 0)
+ || (ent->e.oldframe >= data->num_frames)
+ || (ent->e.oldframe < 0) ) {
+ ri.Printf( PRINT_DEVELOPER, "R_AddIQMSurfaces: no such frame %d to %d for '%s'\n",
+ ent->e.oldframe, ent->e.frame,
+ tr.currentModel->name );
+ ent->e.frame = 0;
+ ent->e.oldframe = 0;
+ }
+
+ //
+ // cull the entire model if merged bounding box of both frames
+ // is outside the view frustum.
+ //
+ cull = R_CullIQM ( data, ent );
+ if ( cull == CULL_OUT ) {
+ return;
+ }
+
+ //
+ // set up lighting now that we know we aren't culled
+ //
+ if ( !personalModel || r_shadows->integer > 1 ) {
+ R_SetupEntityLighting( &tr.refdef, ent );
+ }
+
+ //
+ // see if we are in a fog volume
+ //
+ fogNum = R_ComputeIQMFogNum( data, ent );
+
+ cubemapIndex = R_CubemapForPoint(ent->e.origin);
+
+ for ( i = 0 ; i < data->num_surfaces ; i++ ) {
+ if(ent->e.customShader)
+ shader = R_GetShaderByHandle( ent->e.customShader );
+ else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins)
+ {
+ skin = R_GetSkinByHandle(ent->e.customSkin);
+ shader = tr.defaultShader;
+
+ for(j = 0; j < skin->numSurfaces; j++)
+ {
+ if (!strcmp(skin->surfaces[j].name, surface->name))
+ {
+ shader = skin->surfaces[j].shader;
+ break;
+ }
+ }
+ } else {
+ shader = surface->shader;
+ }
+
+ // we will add shadows even if the main object isn't visible in the view
+
+ // stencil shadows can't do personal models unless I polyhedron clip
+ if ( !personalModel
+ && r_shadows->integer == 2
+ && fogNum == 0
+ && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
+ && shader->sort == SS_OPAQUE ) {
+ R_AddDrawSurf( (surfaceType_t*)surface, tr.shadowShader, 0, 0, 0, 0 );
+ }
+
+ // projection shadows work fine with personal models
+ if ( r_shadows->integer == 3
+ && fogNum == 0
+ && (ent->e.renderfx & RF_SHADOW_PLANE )
+ && shader->sort == SS_OPAQUE ) {
+ R_AddDrawSurf( (surfaceType_t*)surface, tr.projectionShadowShader, 0, 0, 0, 0 );
+ }
+
+ if( !personalModel ) {
+ R_AddDrawSurf( (surfaceType_t*)surface, shader, fogNum, 0, 0, cubemapIndex );
+ }
+
+ surface++;
+ }
+}
+
+
+static void ComputePoseMats( iqmData_t *data, int frame, int oldframe,
+ float backlerp, float *mat ) {
+ float *mat1, *mat2;
+ int *joint = data->jointParents;
+ int i;
+
+ if ( data->num_poses == 0 ) {
+ for( i = 0; i < data->num_joints; i++, joint++ ) {
+ if( *joint >= 0 ) {
+ Matrix34Multiply( mat + 12 * *joint,
+ identityMatrix, mat + 12*i );
+ } else {
+ Com_Memcpy( mat + 12*i, identityMatrix, 12 * sizeof(float) );
+ }
+ }
+ return;
+ }
+
+ if ( oldframe == frame ) {
+ mat1 = data->poseMats + 12 * data->num_poses * frame;
+ for( i = 0; i < data->num_poses; i++, joint++ ) {
+ if( *joint >= 0 ) {
+ Matrix34Multiply( mat + 12 * *joint,
+ mat1 + 12*i, mat + 12*i );
+ } else {
+ Com_Memcpy( mat + 12*i, mat1 + 12*i, 12 * sizeof(float) );
+ }
+ }
+ } else {
+ mat1 = data->poseMats + 12 * data->num_poses * frame;
+ mat2 = data->poseMats + 12 * data->num_poses * oldframe;
+
+ for( i = 0; i < data->num_poses; i++, joint++ ) {
+ if( *joint >= 0 ) {
+ float tmpMat[12];
+ InterpolateMatrix( mat1 + 12*i, mat2 + 12*i,
+ backlerp, tmpMat );
+ Matrix34Multiply( mat + 12 * *joint,
+ tmpMat, mat + 12*i );
+
+ } else {
+ InterpolateMatrix( mat1 + 12*i, mat2 + 12*i,
+ backlerp, mat );
+ }
+ }
+ }
+}
+
+static void ComputeJointMats( iqmData_t *data, int frame, int oldframe,
+ float backlerp, float *mat ) {
+ float *mat1;
+ int i;
+
+ ComputePoseMats( data, frame, oldframe, backlerp, mat );
+
+ for( i = 0; i < data->num_joints; i++ ) {
+ float outmat[12];
+ mat1 = mat + 12 * i;
+
+ Com_Memcpy(outmat, mat1, sizeof(outmat));
+
+ Matrix34Multiply_OnlySetOrigin( outmat, data->jointMats + 12 * i, mat1 );
+ }
+}
+
+
+/*
+=================
+RB_AddIQMSurfaces
+
+Compute vertices for this model surface
+=================
+*/
+void RB_IQMSurfaceAnim( surfaceType_t *surface ) {
+ srfIQModel_t *surf = (srfIQModel_t *)surface;
+ iqmData_t *data = surf->data;
+ float jointMats[IQM_MAX_JOINTS * 12];
+ int i;
+
+ vec4_t *outXYZ;
+ int16_t *outNormal;
+ int16_t *outTangent;
+ vec2_t *outTexCoord;
+ uint16_t *outColor;
+
+ int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0;
+ int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0;
+ float backlerp = backEnd.currentEntity->e.backlerp;
+
+ int *tri;
+ glIndex_t *ptr;
+ glIndex_t base;
+
+ RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 );
+
+ outXYZ = &tess.xyz[tess.numVertexes];
+ outNormal = tess.normal[tess.numVertexes];
+ outTangent = tess.tangent[tess.numVertexes];
+ outTexCoord = &tess.texCoords[tess.numVertexes];
+ outColor = tess.color[tess.numVertexes];
+
+ // compute interpolated joint matrices
+ if ( data->num_poses > 0 ) {
+ ComputePoseMats( data, frame, oldframe, backlerp, jointMats );
+ }
+
+ // transform vertexes and fill other data
+ for( i = 0; i < surf->num_vertexes;
+ i++, outXYZ++, outNormal+=4, outTexCoord++, outColor+=4 ) {
+ int j, k;
+ float vtxMat[12];
+ float nrmMat[9];
+ int vtx = i + surf->first_vertex;
+ float blendWeights[4];
+ int numWeights;
+
+ for ( numWeights = 0; numWeights < 4; numWeights++ ) {
+ if ( data->blendWeightsType == IQM_FLOAT )
+ blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights];
+ else
+ blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f;
+
+ if ( blendWeights[numWeights] <= 0 )
+ break;
+ }
+
+ if ( data->num_poses == 0 || numWeights == 0 ) {
+ // no blend joint, use identity matrix.
+ Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) );
+ } else {
+ // compute the vertex matrix by blending the up to
+ // four blend weights
+ Com_Memset( vtxMat, 0, 12 * sizeof (float) );
+ for( j = 0; j < numWeights; j++ ) {
+ for( k = 0; k < 12; k++ ) {
+ vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k];
+ }
+ }
+ }
+
+ // compute the normal matrix as transpose of the adjoint
+ // of the vertex matrix
+ nrmMat[ 0] = vtxMat[ 5]*vtxMat[10] - vtxMat[ 6]*vtxMat[ 9];
+ nrmMat[ 1] = vtxMat[ 6]*vtxMat[ 8] - vtxMat[ 4]*vtxMat[10];
+ nrmMat[ 2] = vtxMat[ 4]*vtxMat[ 9] - vtxMat[ 5]*vtxMat[ 8];
+ nrmMat[ 3] = vtxMat[ 2]*vtxMat[ 9] - vtxMat[ 1]*vtxMat[10];
+ nrmMat[ 4] = vtxMat[ 0]*vtxMat[10] - vtxMat[ 2]*vtxMat[ 8];
+ nrmMat[ 5] = vtxMat[ 1]*vtxMat[ 8] - vtxMat[ 0]*vtxMat[ 9];
+ nrmMat[ 6] = vtxMat[ 1]*vtxMat[ 6] - vtxMat[ 2]*vtxMat[ 5];
+ nrmMat[ 7] = vtxMat[ 2]*vtxMat[ 4] - vtxMat[ 0]*vtxMat[ 6];
+ nrmMat[ 8] = vtxMat[ 0]*vtxMat[ 5] - vtxMat[ 1]*vtxMat[ 4];
+
+ (*outTexCoord)[0] = data->texcoords[2*vtx + 0];
+ (*outTexCoord)[1] = data->texcoords[2*vtx + 1];
+
+ (*outXYZ)[0] =
+ vtxMat[ 0] * data->positions[3*vtx+0] +
+ vtxMat[ 1] * data->positions[3*vtx+1] +
+ vtxMat[ 2] * data->positions[3*vtx+2] +
+ vtxMat[ 3];
+ (*outXYZ)[1] =
+ vtxMat[ 4] * data->positions[3*vtx+0] +
+ vtxMat[ 5] * data->positions[3*vtx+1] +
+ vtxMat[ 6] * data->positions[3*vtx+2] +
+ vtxMat[ 7];
+ (*outXYZ)[2] =
+ vtxMat[ 8] * data->positions[3*vtx+0] +
+ vtxMat[ 9] * data->positions[3*vtx+1] +
+ vtxMat[10] * data->positions[3*vtx+2] +
+ vtxMat[11];
+ (*outXYZ)[3] = 1.0f;
+
+ {
+ vec3_t normal;
+ vec4_t tangent;
+
+ normal[0] = DotProduct(&nrmMat[0], &data->normals[3*vtx]);
+ normal[1] = DotProduct(&nrmMat[3], &data->normals[3*vtx]);
+ normal[2] = DotProduct(&nrmMat[6], &data->normals[3*vtx]);
+
+ R_VaoPackNormal(outNormal, normal);
+
+ tangent[0] = DotProduct(&nrmMat[0], &data->tangents[4*vtx]);
+ tangent[1] = DotProduct(&nrmMat[3], &data->tangents[4*vtx]);
+ tangent[2] = DotProduct(&nrmMat[6], &data->tangents[4*vtx]);
+ tangent[3] = data->tangents[4*vtx+3];
+
+ R_VaoPackTangent(outTangent, tangent);
+ outTangent+=4;
+ }
+
+ outColor[0] = data->colors[4*vtx+0] * 257;
+ outColor[1] = data->colors[4*vtx+1] * 257;
+ outColor[2] = data->colors[4*vtx+2] * 257;
+ outColor[3] = data->colors[4*vtx+3] * 257;
+ }
+
+ tri = data->triangles + 3 * surf->first_triangle;
+ ptr = &tess.indexes[tess.numIndexes];
+ base = tess.numVertexes;
+
+ for( i = 0; i < surf->num_triangles; i++ ) {
+ *ptr++ = base + (*tri++ - surf->first_vertex);
+ *ptr++ = base + (*tri++ - surf->first_vertex);
+ *ptr++ = base + (*tri++ - surf->first_vertex);
+ }
+
+ tess.numIndexes += 3 * surf->num_triangles;
+ tess.numVertexes += surf->num_vertexes;
+}
+
+int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
+ int startFrame, int endFrame,
+ float frac, const char *tagName ) {
+ float jointMats[IQM_MAX_JOINTS * 12];
+ int joint;
+ char *names = data->names;
+
+ // get joint number by reading the joint names
+ for( joint = 0; joint < data->num_joints; joint++ ) {
+ if( !strcmp( tagName, names ) )
+ break;
+ names += strlen( names ) + 1;
+ }
+ if( joint >= data->num_joints ) {
+ AxisClear( tag->axis );
+ VectorClear( tag->origin );
+ return false;
+ }
+
+ ComputeJointMats( data, startFrame, endFrame, frac, jointMats );
+
+ tag->axis[0][0] = jointMats[12 * joint + 0];
+ tag->axis[1][0] = jointMats[12 * joint + 1];
+ tag->axis[2][0] = jointMats[12 * joint + 2];
+ tag->origin[0] = jointMats[12 * joint + 3];
+ tag->axis[0][1] = jointMats[12 * joint + 4];
+ tag->axis[1][1] = jointMats[12 * joint + 5];
+ tag->axis[2][1] = jointMats[12 * joint + 6];
+ tag->origin[1] = jointMats[12 * joint + 7];
+ tag->axis[0][2] = jointMats[12 * joint + 8];
+ tag->axis[1][2] = jointMats[12 * joint + 9];
+ tag->axis[2][2] = jointMats[12 * joint + 10];
+ tag->origin[2] = jointMats[12 * joint + 11];
+
+ return true;
+}
diff --git a/src/renderergl2/tr_postprocess.cpp b/src/renderergl2/tr_postprocess.cpp
new file mode 100644
index 0000000..7d00d01
--- /dev/null
+++ b/src/renderergl2/tr_postprocess.cpp
@@ -0,0 +1,484 @@
+/*
+===========================================================================
+Copyright (C) 2011 Andrei Drexler, Richard Allen, James Canete
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+void RB_ToneMap(FBO_t *hdrFbo, ivec4_t hdrBox, FBO_t *ldrFbo, ivec4_t ldrBox, int autoExposure)
+{
+ ivec4_t srcBox, dstBox;
+ vec4_t color;
+ static int lastFrameCount = 0;
+
+ if (autoExposure)
+ {
+ if (lastFrameCount == 0 || tr.frameCount < lastFrameCount || tr.frameCount - lastFrameCount > 5)
+ {
+ // determine average log luminance
+ FBO_t *srcFbo, *dstFbo, *tmp;
+ int size = 256;
+
+ lastFrameCount = tr.frameCount;
+
+ VectorSet4(dstBox, 0, 0, size, size);
+
+ FBO_Blit(hdrFbo, hdrBox, NULL, tr.textureScratchFbo[0], dstBox, &tr.calclevels4xShader[0], NULL, 0);
+
+ srcFbo = tr.textureScratchFbo[0];
+ dstFbo = tr.textureScratchFbo[1];
+
+ // downscale to 1x1 texture
+ while (size > 1)
+ {
+ VectorSet4(srcBox, 0, 0, size, size);
+ //size >>= 2;
+ size >>= 1;
+ VectorSet4(dstBox, 0, 0, size, size);
+
+ if (size == 1)
+ dstFbo = tr.targetLevelsFbo;
+
+ //FBO_Blit(targetFbo, srcBox, NULL, tr.textureScratchFbo[nextScratch], dstBox, &tr.calclevels4xShader[1], NULL, 0);
+ FBO_FastBlit(srcFbo, srcBox, dstFbo, dstBox, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+
+ tmp = srcFbo;
+ srcFbo = dstFbo;
+ dstFbo = tmp;
+ }
+ }
+
+ // blend with old log luminance for gradual change
+ VectorSet4(srcBox, 0, 0, 0, 0);
+
+ color[0] =
+ color[1] =
+ color[2] = 1.0f;
+ if (glRefConfig.textureFloat)
+ color[3] = 0.03f;
+ else
+ color[3] = 0.1f;
+
+ FBO_Blit(tr.targetLevelsFbo, srcBox, NULL, tr.calcLevelsFbo, NULL, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
+ }
+
+ // tonemap
+ color[0] =
+ color[1] =
+ color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value);
+ color[3] = 1.0f;
+
+ if (autoExposure)
+ GL_BindToTMU(tr.calcLevelsImage, TB_LEVELSMAP);
+ else
+ GL_BindToTMU(tr.fixedLevelsImage, TB_LEVELSMAP);
+
+ FBO_Blit(hdrFbo, hdrBox, NULL, ldrFbo, ldrBox, &tr.tonemapShader, color, 0);
+}
+
+/*
+=============
+RB_BokehBlur
+
+
+Blurs a part of one framebuffer to another.
+
+Framebuffers can be identical.
+=============
+*/
+void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float blur)
+{
+// ivec4_t srcBox, dstBox;
+ vec4_t color;
+
+ blur *= 10.0f;
+
+ if (blur < 0.004f)
+ return;
+
+ if (glRefConfig.framebufferObject)
+ {
+ // bokeh blur
+ if (blur > 0.0f)
+ {
+ ivec4_t quarterBox;
+
+ quarterBox[0] = 0;
+ quarterBox[1] = tr.quarterFbo[0]->height;
+ quarterBox[2] = tr.quarterFbo[0]->width;
+ quarterBox[3] = -tr.quarterFbo[0]->height;
+
+ // create a quarter texture
+ //FBO_Blit(NULL, NULL, NULL, tr.quarterFbo[0], NULL, NULL, NULL, 0);
+ FBO_FastBlit(src, srcBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ }
+
+#ifndef HQ_BLUR
+ if (blur > 1.0f)
+ {
+ // create a 1/16th texture
+ //FBO_Blit(tr.quarterFbo[0], NULL, NULL, tr.textureScratchFbo[0], NULL, NULL, NULL, 0);
+ FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ }
+#endif
+
+ if (blur > 0.0f && blur <= 1.0f)
+ {
+ // Crossfade original with quarter texture
+ VectorSet4(color, 1, 1, 1, blur);
+
+ FBO_Blit(tr.quarterFbo[0], NULL, NULL, dst, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
+ }
+#ifndef HQ_BLUR
+ // ok blur, but can see some pixelization
+ else if (blur > 1.0f && blur <= 2.0f)
+ {
+ // crossfade quarter texture with 1/16th texture
+ FBO_Blit(tr.quarterFbo[0], NULL, NULL, dst, dstBox, NULL, NULL, 0);
+
+ VectorSet4(color, 1, 1, 1, blur - 1.0f);
+
+ FBO_Blit(tr.textureScratchFbo[0], NULL, NULL, dst, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
+ }
+ else if (blur > 2.0f)
+ {
+ // blur 1/16th texture then replace
+ int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ vec2_t blurTexScale;
+ float subblur;
+
+ subblur = ((blur - 2.0f) / 2.0f) / 3.0f * (float)(i + 1);
+
+ blurTexScale[0] =
+ blurTexScale[1] = subblur;
+
+ color[0] =
+ color[1] =
+ color[2] = 0.5f;
+ color[3] = 1.0f;
+
+ if (i != 0)
+ FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
+ else
+ FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, 0);
+ }
+
+ FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, dst, dstBox, NULL, NULL, 0);
+ }
+#else // higher quality blur, but slower
+ else if (blur > 1.0f)
+ {
+ // blur quarter texture then replace
+ int i;
+
+ src = tr.quarterFbo[0];
+ dst = tr.quarterFbo[1];
+
+ VectorSet4(color, 0.5f, 0.5f, 0.5f, 1);
+
+ for (i = 0; i < 2; i++)
+ {
+ vec2_t blurTexScale;
+ float subblur;
+
+ subblur = (blur - 1.0f) / 2.0f * (float)(i + 1);
+
+ blurTexScale[0] =
+ blurTexScale[1] = subblur;
+
+ color[0] =
+ color[1] =
+ color[2] = 1.0f;
+ if (i != 0)
+ color[3] = 1.0f;
+ else
+ color[3] = 0.5f;
+
+ FBO_Blit(tr.quarterFbo[0], NULL, blurTexScale, tr.quarterFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
+ }
+
+ FBO_Blit(tr.quarterFbo[1], NULL, NULL, dst, dstBox, NULL, NULL, 0);
+ }
+#endif
+ }
+}
+
+
+static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha)
+{
+ ivec4_t srcBox, dstBox;
+ int srcWidth, srcHeight;
+ vec4_t color;
+ const float inc = 1.f / passes;
+ const float mul = powf(stretch, inc);
+ float scale;
+
+ alpha *= inc;
+ VectorSet4(color, alpha, alpha, alpha, 1.0f);
+
+ srcWidth = srcFbo ? srcFbo->width : glConfig.vidWidth;
+ srcHeight = srcFbo ? srcFbo->height : glConfig.vidHeight;
+
+ VectorSet4(srcBox, 0, 0, srcWidth, srcHeight);
+
+ VectorSet4(dstBox, x, y, w, h);
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, 0);
+
+ --passes;
+ scale = mul;
+ while (passes > 0)
+ {
+ float iscale = 1.f / scale;
+ float s0 = xcenter * (1.f - iscale);
+ float t0 = (1.0f - ycenter) * (1.f - iscale);
+
+ srcBox[0] = s0 * srcWidth;
+ srcBox[1] = t0 * srcHeight;
+ srcBox[2] = iscale * srcWidth;
+ srcBox[3] = iscale * srcHeight;
+
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+
+ scale *= mul;
+ --passes;
+ }
+}
+
+
+static bool RB_UpdateSunFlareVis(void)
+{
+ GLuint sampleCount = 0;
+ if (!glRefConfig.occlusionQuery)
+ return true;
+
+ tr.sunFlareQueryIndex ^= 1;
+ if (!tr.sunFlareQueryActive[tr.sunFlareQueryIndex])
+ return true;
+
+ /* debug code */
+ if (0)
+ {
+ int iter;
+ for (iter=0 ; ; ++iter)
+ {
+ GLint available = 0;
+ qglGetQueryObjectiv(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE, &available);
+ if (available)
+ break;
+ }
+
+ ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter);
+ }
+
+ qglGetQueryObjectuiv(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT, &sampleCount);
+ return sampleCount > 0;
+}
+
+void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
+{
+ vec4_t color;
+ float dot;
+ const float cutoff = 0.25f;
+ bool colorize = true;
+
+// float w, h, w2, h2;
+ mat4_t mvp;
+ vec4_t pos, hpos;
+
+ dot = DotProduct(tr.sunDirection, backEnd.viewParms.orientation.axis[0]);
+ if (dot < cutoff)
+ return;
+
+ if (!RB_UpdateSunFlareVis())
+ return;
+
+ // From RB_DrawSun()
+ {
+ float dist;
+ mat4_t trans, model;
+
+ Mat4Translation( backEnd.viewParms.orientation.origin, trans );
+ Mat4Multiply( backEnd.viewParms.world.modelMatrix, trans, model );
+ Mat4Multiply(backEnd.viewParms.projectionMatrix, model, mvp);
+
+ dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
+
+ VectorScale( tr.sunDirection, dist, pos );
+ }
+
+ // project sun point
+ //Mat4Multiply(backEnd.viewParms.projectionMatrix, backEnd.viewParms.world.modelMatrix, mvp);
+ Mat4Transform(mvp, pos, hpos);
+
+ // transform to UV coords
+ hpos[3] = 0.5f / hpos[3];
+
+ pos[0] = 0.5f + hpos[0] * hpos[3];
+ pos[1] = 0.5f + hpos[1] * hpos[3];
+
+ // initialize quarter buffers
+ {
+ float mul = 1.f;
+ ivec4_t rayBox, quarterBox;
+ int srcWidth = srcFbo ? srcFbo->width : glConfig.vidWidth;
+ int srcHeight = srcFbo ? srcFbo->height : glConfig.vidHeight;
+
+ VectorSet4(color, mul, mul, mul, 1);
+
+ rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / srcWidth;
+ rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / srcHeight;
+ rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / srcWidth;
+ rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / srcHeight;
+
+ quarterBox[0] = 0;
+ quarterBox[1] = tr.quarterFbo[0]->height;
+ quarterBox[2] = tr.quarterFbo[0]->width;
+ quarterBox[3] = -tr.quarterFbo[0]->height;
+
+ // first, downsample the framebuffer
+ if (colorize)
+ {
+ FBO_FastBlit(srcFbo, srcBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ FBO_Blit(tr.sunRaysFbo, rayBox, NULL, tr.quarterFbo[0], quarterBox, NULL, color, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO);
+ }
+ else
+ {
+ FBO_FastBlit(tr.sunRaysFbo, rayBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ }
+ }
+
+ // radial blur passes, ping-ponging between the two quarter-size buffers
+ {
+ const float stretch_add = 2.f/3.f;
+ float stretch = 1.f + stretch_add;
+ int i;
+ for (i=0; i<2; ++i)
+ {
+ RB_RadialBlur(tr.quarterFbo[i&1], tr.quarterFbo[(~i) & 1], 5, stretch, 0.f, 0.f, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height, pos[0], pos[1], 1.125f);
+ stretch += stretch_add;
+ }
+ }
+
+ // add result back on top of the main buffer
+ {
+ float mul = 1.f;
+
+ VectorSet4(color, mul, mul, mul, 1);
+
+ FBO_Blit(tr.quarterFbo[0], NULL, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
+ }
+}
+
+static void RB_BlurAxis(FBO_t *srcFbo, FBO_t *dstFbo, float strength, bool horizontal)
+{
+ float dx, dy;
+ float xmul, ymul;
+ float weights[3] = {
+ 0.227027027f,
+ 0.316216216f,
+ 0.070270270f,
+ };
+ float offsets[3] = {
+ 0.f,
+ 1.3846153846f,
+ 3.2307692308f,
+ };
+
+ xmul = horizontal;
+ ymul = 1.f - xmul;
+
+ xmul *= strength;
+ ymul *= strength;
+
+ {
+ ivec4_t srcBox, dstBox;
+ vec4_t color;
+
+ VectorSet4(color, weights[0], weights[0], weights[0], 1.0f);
+ VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
+ VectorSet4(dstBox, 0, 0, dstFbo->width, dstFbo->height);
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, 0);
+
+ VectorSet4(color, weights[1], weights[1], weights[1], 1.0f);
+ dx = offsets[1] * xmul;
+ dy = offsets[1] * ymul;
+ VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
+ VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
+
+ VectorSet4(color, weights[2], weights[2], weights[2], 1.0f);
+ dx = offsets[2] * xmul;
+ dy = offsets[2] * ymul;
+ VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
+ VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
+ }
+}
+
+static void RB_HBlur(FBO_t *srcFbo, FBO_t *dstFbo, float strength)
+{
+ RB_BlurAxis(srcFbo, dstFbo, strength, true);
+}
+
+static void RB_VBlur(FBO_t *srcFbo, FBO_t *dstFbo, float strength)
+{
+ RB_BlurAxis(srcFbo, dstFbo, strength, false);
+}
+
+void RB_GaussianBlur(float blur)
+{
+ //float mul = 1.f;
+ float factor = Com_Clamp(0.f, 1.f, blur);
+
+ if (factor <= 0.f)
+ return;
+
+ {
+ ivec4_t srcBox, dstBox;
+ vec4_t color;
+
+ VectorSet4(color, 1, 1, 1, 1);
+
+ // first, downsample the framebuffer
+ FBO_FastBlit(NULL, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+
+ // set the alpha channel
+ qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
+ FBO_BlitFromTexture(tr.whiteImage, NULL, NULL, tr.textureScratchFbo[0], NULL, NULL, color, GLS_DEPTHTEST_DISABLE);
+ qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ // blur the tiny buffer horizontally and vertically
+ RB_HBlur(tr.textureScratchFbo[0], tr.textureScratchFbo[1], factor);
+ RB_VBlur(tr.textureScratchFbo[1], tr.textureScratchFbo[0], factor);
+
+ // finally, merge back to framebuffer
+ VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
+ VectorSet4(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
+ color[3] = factor;
+ FBO_Blit(tr.textureScratchFbo[0], srcBox, NULL, NULL, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
+ }
+}
diff --git a/src/renderergl2/tr_postprocess.h b/src/renderergl2/tr_postprocess.h
new file mode 100644
index 0000000..de00b88
--- /dev/null
+++ b/src/renderergl2/tr_postprocess.h
@@ -0,0 +1,34 @@
+/*
+===========================================================================
+Copyright (C) 2011 Andrei Drexler, Richard Allen, James Canete
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifndef TR_POSTPROCESS_H
+#define TR_POSTPROCESS_H
+
+#include "tr_fbo.h"
+
+void RB_ToneMap(FBO_t *hdrFbo, ivec4_t hdrBox, FBO_t *ldrFbo, ivec4_t ldrBox, int autoExposure);
+void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float blur);
+void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox);
+void RB_GaussianBlur(float blur);
+
+#endif
diff --git a/src/renderergl2/tr_scene.cpp b/src/renderergl2/tr_scene.cpp
new file mode 100644
index 0000000..67ab0d3
--- /dev/null
+++ b/src/renderergl2/tr_scene.cpp
@@ -0,0 +1,575 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+int r_firstSceneDrawSurf;
+
+int r_numdlights;
+int r_firstSceneDlight;
+
+int r_numentities;
+int r_firstSceneEntity;
+
+int r_numpolys;
+int r_firstScenePoly;
+
+int r_numpolyverts;
+
+
+/*
+====================
+R_InitNextFrame
+
+====================
+*/
+void R_InitNextFrame( void ) {
+ backEndData->commands.used = 0;
+
+ r_firstSceneDrawSurf = 0;
+
+ r_numdlights = 0;
+ r_firstSceneDlight = 0;
+
+ r_numentities = 0;
+ r_firstSceneEntity = 0;
+
+ r_numpolys = 0;
+ r_firstScenePoly = 0;
+
+ r_numpolyverts = 0;
+}
+
+
+/*
+====================
+RE_ClearScene
+
+====================
+*/
+void RE_ClearScene( void ) {
+ r_firstSceneDlight = r_numdlights;
+ r_firstSceneEntity = r_numentities;
+ r_firstScenePoly = r_numpolys;
+}
+
+/*
+===========================================================================
+
+DISCRETE POLYS
+
+===========================================================================
+*/
+
+/*
+=====================
+R_AddPolygonSurfaces
+
+Adds all the scene's polys into this view's drawsurf list
+=====================
+*/
+void R_AddPolygonSurfaces( void ) {
+ int i;
+ shader_t *sh;
+ srfPoly_t *poly;
+ int fogMask;
+
+ tr.currentEntityNum = REFENTITYNUM_WORLD;
+ tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
+ fogMask = -((tr.refdef.rdflags & RDF_NOFOG) == 0);
+
+ for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {
+ sh = R_GetShaderByHandle( poly->hShader );
+ R_AddDrawSurf( (surfaceType_t*)poly, sh, poly->fogIndex & fogMask, false, false, 0 /*cubeMap*/ );
+ }
+}
+
+/*
+=====================
+RE_AddPolyToScene
+
+=====================
+*/
+void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {
+ srfPoly_t *poly;
+ int i, j;
+ int fogIndex;
+ fog_t *fog;
+ vec3_t bounds[2];
+
+ if ( !tr.registered ) {
+ return;
+ }
+
+ if ( !hShader ) {
+ // This isn't a useful warning, and an hShader of zero isn't a null shader, it's
+ // the default shader.
+ //ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n");
+ //return;
+ }
+
+ for ( j = 0; j < numPolys; j++ ) {
+ if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) {
+ /*
+ NOTE TTimo this was initially a PRINT_WARNING
+ but it happens a lot with high fighting scenes and particles
+ since we don't plan on changing the const and making for room for those effects
+ simply cut this message to developer only
+ */
+ ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n");
+ return;
+ }
+
+ poly = &backEndData->polys[r_numpolys];
+ poly->surfaceType = SF_POLY;
+ poly->hShader = hShader;
+ poly->numVerts = numVerts;
+ poly->verts = &backEndData->polyVerts[r_numpolyverts];
+
+ Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) );
+
+ if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
+ poly->verts->modulate[0] = 255;
+ poly->verts->modulate[1] = 255;
+ poly->verts->modulate[2] = 255;
+ poly->verts->modulate[3] = 255;
+ }
+ // done.
+ r_numpolys++;
+ r_numpolyverts += numVerts;
+
+ // if no world is loaded
+ if ( tr.world == NULL ) {
+ fogIndex = 0;
+ }
+ // see if it is in a fog volume
+ else if ( tr.world->numfogs == 1 ) {
+ fogIndex = 0;
+ } else {
+ // find which fog volume the poly is in
+ VectorCopy( poly->verts[0].xyz, bounds[0] );
+ VectorCopy( poly->verts[0].xyz, bounds[1] );
+ for ( i = 1 ; i < poly->numVerts ; i++ ) {
+ AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
+ }
+ for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
+ fog = &tr.world->fogs[fogIndex];
+ if ( bounds[1][0] >= fog->bounds[0][0]
+ && bounds[1][1] >= fog->bounds[0][1]
+ && bounds[1][2] >= fog->bounds[0][2]
+ && bounds[0][0] <= fog->bounds[1][0]
+ && bounds[0][1] <= fog->bounds[1][1]
+ && bounds[0][2] <= fog->bounds[1][2] ) {
+ break;
+ }
+ }
+ if ( fogIndex == tr.world->numfogs ) {
+ fogIndex = 0;
+ }
+ }
+ poly->fogIndex = fogIndex;
+ }
+}
+
+
+//=================================================================================
+
+
+/*
+=====================
+RE_AddRefEntityToScene
+
+=====================
+*/
+void RE_AddRefEntityToScene( const refEntity_t *ent ) {
+ vec3_t cross;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ if ( r_numentities >= MAX_REFENTITIES ) {
+ ri.Printf(PRINT_DEVELOPER, "RE_AddRefEntityToScene: Dropping refEntity, reached MAX_REFENTITIES\n");
+ return;
+ }
+ if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
+ static bool firstTime = true;
+ if (firstTime) {
+ firstTime = false;
+ ri.Printf( PRINT_WARNING, "RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n");
+ }
+ return;
+ }
+ if ( (int)ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
+ ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
+ }
+
+ backEndData->entities[r_numentities].e = *ent;
+ backEndData->entities[r_numentities].lightingCalculated = false;
+
+ CrossProduct(ent->axis[0], ent->axis[1], cross);
+ backEndData->entities[r_numentities].mirrored = (DotProduct(ent->axis[2], cross) < 0.f);
+
+ r_numentities++;
+}
+
+
+/*
+=====================
+RE_AddDynamicLightToScene
+
+=====================
+*/
+void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) {
+ dlight_t *dl;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ if ( r_numdlights >= MAX_DLIGHTS ) {
+ return;
+ }
+ if ( intensity <= 0 ) {
+ return;
+ }
+ // these cards don't have the correct blend mode
+ if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
+ return;
+ }
+ dl = &backEndData->dlights[r_numdlights++];
+ VectorCopy (org, dl->origin);
+ dl->radius = intensity;
+ dl->color[0] = r;
+ dl->color[1] = g;
+ dl->color[2] = b;
+ dl->additive = additive;
+}
+
+/*
+=====================
+RE_AddLightToScene
+
+=====================
+*/
+void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
+ RE_AddDynamicLightToScene( org, intensity, r, g, b, false );
+}
+
+/*
+=====================
+RE_AddAdditiveLightToScene
+
+=====================
+*/
+void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
+ RE_AddDynamicLightToScene( org, intensity, r, g, b, true );
+}
+
+
+void RE_BeginScene(const refdef_t *fd)
+{
+ Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
+
+ tr.refdef.x = fd->x;
+ tr.refdef.y = fd->y;
+ tr.refdef.width = fd->width;
+ tr.refdef.height = fd->height;
+ tr.refdef.fov_x = fd->fov_x;
+ tr.refdef.fov_y = fd->fov_y;
+
+ VectorCopy( fd->vieworg, tr.refdef.vieworg );
+ VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );
+ VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );
+ VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
+
+ tr.refdef.time = fd->time;
+ tr.refdef.rdflags = fd->rdflags;
+
+ // copy the areamask data over and note if it has changed, which
+ // will force a reset of the visible leafs even if the view hasn't moved
+ tr.refdef.areamaskModified = false;
+ if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) {
+ int areaDiff;
+ int i;
+
+ // compare the area bits
+ areaDiff = 0;
+ for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) {
+ areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i];
+ ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i];
+ }
+
+ if ( areaDiff ) {
+ // a door just opened or something
+ tr.refdef.areamaskModified = true;
+ }
+ }
+
+ tr.refdef.sunDir[3] = 0.0f;
+ tr.refdef.sunCol[3] = 1.0f;
+ tr.refdef.sunAmbCol[3] = 1.0f;
+
+ VectorCopy(tr.sunDirection, tr.refdef.sunDir);
+ if ( (tr.refdef.rdflags & RDF_NOWORLDMODEL) || !(r_depthPrepass->value) ){
+ VectorSet(tr.refdef.sunCol, 0, 0, 0);
+ VectorSet(tr.refdef.sunAmbCol, 0, 0, 0);
+ }
+ else
+ {
+ float scale = (1 << r_mapOverBrightBits->integer) / 255.0f;
+
+ if (r_forceSun->integer)
+ VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol);
+ else
+ VectorScale(tr.sunLight, scale, tr.refdef.sunCol);
+
+ if (r_sunlightMode->integer == 1)
+ {
+ tr.refdef.sunAmbCol[0] =
+ tr.refdef.sunAmbCol[1] =
+ tr.refdef.sunAmbCol[2] = r_forceSun->integer ? r_forceSunAmbientScale->value : tr.sunShadowScale;
+ }
+ else
+ {
+ if (r_forceSun->integer)
+ VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol);
+ else
+ VectorScale(tr.sunLight, scale * tr.sunShadowScale, tr.refdef.sunAmbCol);
+ }
+ }
+
+ if (r_forceAutoExposure->integer)
+ {
+ tr.refdef.autoExposureMinMax[0] = r_forceAutoExposureMin->value;
+ tr.refdef.autoExposureMinMax[1] = r_forceAutoExposureMax->value;
+ }
+ else
+ {
+ tr.refdef.autoExposureMinMax[0] = tr.autoExposureMinMax[0];
+ tr.refdef.autoExposureMinMax[1] = tr.autoExposureMinMax[1];
+ }
+
+ if (r_forceToneMap->integer)
+ {
+ tr.refdef.toneMinAvgMaxLinear[0] = pow(2, r_forceToneMapMin->value);
+ tr.refdef.toneMinAvgMaxLinear[1] = pow(2, r_forceToneMapAvg->value);
+ tr.refdef.toneMinAvgMaxLinear[2] = pow(2, r_forceToneMapMax->value);
+ }
+ else
+ {
+ tr.refdef.toneMinAvgMaxLinear[0] = pow(2, tr.toneMinAvgMaxLevel[0]);
+ tr.refdef.toneMinAvgMaxLinear[1] = pow(2, tr.toneMinAvgMaxLevel[1]);
+ tr.refdef.toneMinAvgMaxLinear[2] = pow(2, tr.toneMinAvgMaxLevel[2]);
+ }
+
+ // Makro - copy exta info if present
+ if (fd->rdflags & RDF_EXTRA) {
+ const refdefex_t* extra = (const refdefex_t*) (fd+1);
+
+ tr.refdef.blurFactor = extra->blurFactor;
+
+ if (fd->rdflags & RDF_SUNLIGHT)
+ {
+ VectorCopy(extra->sunDir, tr.refdef.sunDir);
+ VectorCopy(extra->sunCol, tr.refdef.sunCol);
+ VectorCopy(extra->sunAmbCol, tr.refdef.sunAmbCol);
+ }
+ }
+ else
+ {
+ tr.refdef.blurFactor = 0.0f;
+ }
+
+ // derived info
+
+ tr.refdef.floatTime = tr.refdef.time * 0.001;
+
+ tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
+ tr.refdef.drawSurfs = backEndData->drawSurfs;
+
+ tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
+ tr.refdef.entities = &backEndData->entities[r_firstSceneEntity];
+
+ tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
+ tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight];
+
+ tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
+ tr.refdef.polys = &backEndData->polys[r_firstScenePoly];
+
+ tr.refdef.num_pshadows = 0;
+ tr.refdef.pshadows = &backEndData->pshadows[0];
+
+ // turn off dynamic lighting globally by clearing all the
+ // dlights if it needs to be disabled or if vertex lighting is enabled
+ if ( r_dynamiclight->integer == 0 ||
+ r_vertexLight->integer == 1 ||
+ glConfig.hardwareType == GLHW_PERMEDIA2 ) {
+ tr.refdef.num_dlights = 0;
+ }
+
+ // a single frame may have multiple scenes draw inside it --
+ // a 3D game view, 3D status bar renderings, 3D menus, etc.
+ // They need to be distinguished by the light flare code, because
+ // the visibility state for a given surface may be different in
+ // each scene / view.
+ tr.frameSceneNum++;
+ tr.sceneCount++;
+}
+
+
+void RE_EndScene()
+{
+ // the next scene rendered in this frame will tack on after this one
+ r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
+ r_firstSceneEntity = r_numentities;
+ r_firstSceneDlight = r_numdlights;
+ r_firstScenePoly = r_numpolys;
+}
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+RE_RenderScene
+
+Draw a 3D view into a part of the window, then return
+to 2D drawing.
+
+Rendering a scene may require multiple views to be rendered
+to handle mirrors,
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void RE_RenderScene( const refdef_t *fd ) {
+ viewParms_t parms;
+ int startTime;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ GLimp_LogComment( "====== RE_RenderScene =====\n" );
+
+ if ( r_norefresh->integer ) {
+ return;
+ }
+
+ startTime = ri.Milliseconds();
+
+ if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
+ ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
+ }
+
+ RE_BeginScene(fd);
+
+ // SmileTheory: playing with shadow mapping
+ if (!( fd->rdflags & RDF_NOWORLDMODEL ) && tr.refdef.num_dlights && r_dlightMode->integer >= 2)
+ {
+ R_RenderDlightCubemaps(fd);
+ }
+
+ /* playing with more shadows */
+ if(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ) && r_shadows->integer == 4)
+ {
+ R_RenderPshadowMaps(fd);
+ }
+
+ // playing with even more shadows
+ if(glRefConfig.framebufferObject && r_sunlightMode->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows))
+ {
+ if (r_shadowCascadeZFar->integer != 0)
+ {
+ R_RenderSunShadowMaps(fd, 0);
+ R_RenderSunShadowMaps(fd, 1);
+ R_RenderSunShadowMaps(fd, 2);
+ }
+ else
+ {
+ Mat4Zero(tr.refdef.sunShadowMvp[0]);
+ Mat4Zero(tr.refdef.sunShadowMvp[1]);
+ Mat4Zero(tr.refdef.sunShadowMvp[2]);
+ }
+
+ // only rerender last cascade if sun has changed position
+ if (r_forceSun->integer == 2 || !VectorCompare(tr.refdef.sunDir, tr.lastCascadeSunDirection))
+ {
+ VectorCopy(tr.refdef.sunDir, tr.lastCascadeSunDirection);
+ R_RenderSunShadowMaps(fd, 3);
+ Mat4Copy(tr.refdef.sunShadowMvp[3], tr.lastCascadeSunMvp);
+ }
+ else
+ {
+ Mat4Copy(tr.lastCascadeSunMvp, tr.refdef.sunShadowMvp[3]);
+ }
+ }
+
+ // playing with cube maps
+ // this is where dynamic cubemaps would be rendered
+ if (0) //(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ))
+ {
+ int i, j;
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ for (j = 0; j < 6; j++)
+ {
+ R_RenderCubemapSide(i, j, true);
+ }
+ }
+ }
+
+ // setup view parms for the initial view
+ //
+ // set up viewport
+ // The refdef takes 0-at-the-top y coordinates, so
+ // convert to GL's 0-at-the-bottom space
+ //
+ Com_Memset( &parms, 0, sizeof( parms ) );
+ parms.viewportX = tr.refdef.x;
+ parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
+ parms.viewportWidth = tr.refdef.width;
+ parms.viewportHeight = tr.refdef.height;
+ parms.isPortal = false;
+
+ parms.fovX = tr.refdef.fov_x;
+ parms.fovY = tr.refdef.fov_y;
+
+ parms.stereoFrame = tr.refdef.stereoFrame;
+
+ VectorCopy( fd->vieworg, parms.orientation.origin );
+ VectorCopy( fd->viewaxis[0], parms.orientation.axis[0] );
+ VectorCopy( fd->viewaxis[1], parms.orientation.axis[1] );
+ VectorCopy( fd->viewaxis[2], parms.orientation.axis[2] );
+
+ VectorCopy( fd->vieworg, parms.pvsOrigin );
+
+ if(!( fd->rdflags & RDF_NOWORLDMODEL ) && r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows))
+ {
+ parms.flags = VPF_USESUNLIGHT;
+ }
+
+ R_RenderView( &parms );
+
+ if(!( fd->rdflags & RDF_NOWORLDMODEL ))
+ R_AddPostProcessCmd();
+
+ RE_EndScene();
+
+ tr.frontEndMsec += ri.Milliseconds() - startTime;
+}
diff --git a/src/renderergl2/tr_shade.cpp b/src/renderergl2/tr_shade.cpp
new file mode 100644
index 0000000..8f9e871
--- /dev/null
+++ b/src/renderergl2/tr_shade.cpp
@@ -0,0 +1,1634 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_shade.c
+
+#include "tr_local.h"
+#if idppc_altivec && !defined(__APPLE__)
+#include <altivec.h>
+#endif
+
+/*
+
+ THIS ENTIRE FILE IS BACK END
+
+ This file deals with applying shaders to surface data in the tess struct.
+*/
+
+
+/*
+==================
+R_DrawElements
+
+==================
+*/
+
+void R_DrawElements( int numIndexes, glIndex_t firstIndex)
+{
+ qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t)));
+}
+
+
+/*
+=============================================================
+
+SURFACE SHADERS
+
+=============================================================
+*/
+
+shaderCommands_t tess;
+
+
+/*
+=================
+R_BindAnimatedImageToTMU
+
+=================
+*/
+static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) {
+
+ if ( bundle->isVideoMap ) {
+ ri.CIN_RunCinematic(bundle->videoMapHandle);
+ ri.CIN_UploadCinematic(bundle->videoMapHandle);
+ GL_BindToTMU(tr.scratchImage[bundle->videoMapHandle], tmu);
+ return;
+ }
+
+ if ( bundle->numImageAnimations <= 1 ) {
+ GL_BindToTMU( bundle->image[0], tmu);
+ return;
+ }
+
+ // it is necessary to do this messy calc to make sure animations line up
+ // exactly with waveforms of the same frequency
+ int i = static_cast<int>(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE) >> FUNCTABLE_SIZE2;
+
+ if ( i < 0 )
+ {
+ i = 0; // may happen with shader time offsets
+ }
+ i %= bundle->numImageAnimations;
+
+ GL_BindToTMU( bundle->image[ i ], tmu );
+}
+
+
+/*
+================
+DrawTris
+
+Draws triangle outlines for debugging
+================
+*/
+static void DrawTris (shaderCommands_t *input) {
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
+
+ GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
+ qglDepthRange( 0, 0 );
+
+ {
+ shaderProgram_t *sp = &tr.textureColorShader;
+ vec4_t color;
+
+ GLSL_BindProgram(sp);
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+ VectorSet4(color, 1, 1, 1, 1);
+ GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color);
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
+
+ R_DrawElements(input->numIndexes, input->firstIndex);
+ }
+
+ qglDepthRange( 0, 1 );
+}
+
+
+/*
+================
+DrawNormals
+
+Draws vertex normals for debugging
+================
+*/
+static void DrawNormals (shaderCommands_t *input) {
+ //FIXME: implement this
+}
+
+/*
+==============
+RB_BeginSurface
+
+We must set some things up before beginning any tesselation,
+because a surface may be forced to perform a RB_End due
+to overflow.
+==============
+*/
+void RB_BeginSurface( shader_t *shader, int fogNum, int cubemapIndex ) {
+
+ shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader;
+
+ tess.numIndexes = 0;
+ tess.firstIndex = 0;
+ tess.numVertexes = 0;
+ tess.shader = state;
+ tess.fogNum = fogNum;
+ tess.cubemapIndex = cubemapIndex;
+ tess.dlightBits = 0; // will be OR'd in by surface functions
+ tess.pshadowBits = 0; // will be OR'd in by surface functions
+ tess.xstages = state->stages;
+ tess.numPasses = state->numUnfoggedPasses;
+ tess.currentStageIteratorFunc = state->optimalStageIteratorFunc;
+ tess.useInternalVao = true;
+ tess.useCacheVao = false;
+
+ tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
+ if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) {
+ tess.shaderTime = tess.shader->clampTime;
+ }
+
+ if (backEnd.viewParms.flags & VPF_SHADOWMAP)
+ {
+ tess.currentStageIteratorFunc = RB_StageIteratorGeneric;
+ }
+}
+
+
+
+extern float EvalWaveForm( const waveForm_t *wf );
+extern float EvalWaveFormClamped( const waveForm_t *wf );
+
+
+static void ComputeTexMods( shaderStage_t *pStage, int bundleNum, float *outMatrix, float *outOffTurb)
+{
+ int tm;
+ float matrix[6], currentmatrix[6];
+ textureBundle_t *bundle = &pStage->bundle[bundleNum];
+
+ matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = 0.0f;
+ matrix[1] = 0.0f; matrix[3] = 1.0f; matrix[5] = 0.0f;
+
+ currentmatrix[0] = 1.0f; currentmatrix[2] = 0.0f; currentmatrix[4] = 0.0f;
+ currentmatrix[1] = 0.0f; currentmatrix[3] = 1.0f; currentmatrix[5] = 0.0f;
+
+ outMatrix[0] = 1.0f; outMatrix[2] = 0.0f;
+ outMatrix[1] = 0.0f; outMatrix[3] = 1.0f;
+
+ outOffTurb[0] = 0.0f; outOffTurb[1] = 0.0f; outOffTurb[2] = 0.0f; outOffTurb[3] = 0.0f;
+
+ for ( tm = 0; tm < bundle->numTexMods ; tm++ ) {
+ switch ( bundle->texMods[tm].type )
+ {
+
+ case TMOD_NONE:
+ tm = TR_MAX_TEXMODS; // break out of for loop
+ break;
+
+ case TMOD_TURBULENT:
+ RB_CalcTurbulentFactors(&bundle->texMods[tm].wave, &outOffTurb[2], &outOffTurb[3]);
+ break;
+
+ case TMOD_ENTITY_TRANSLATE:
+ RB_CalcScrollTexMatrix( backEnd.currentEntity->e.shaderTexCoord, matrix );
+ break;
+
+ case TMOD_SCROLL:
+ RB_CalcScrollTexMatrix( bundle->texMods[tm].scroll,
+ matrix );
+ break;
+
+ case TMOD_SCALE:
+ RB_CalcScaleTexMatrix( bundle->texMods[tm].scale,
+ matrix );
+ break;
+
+ case TMOD_STRETCH:
+ RB_CalcStretchTexMatrix( &bundle->texMods[tm].wave,
+ matrix );
+ break;
+
+ case TMOD_TRANSFORM:
+ RB_CalcTransformTexMatrix( &bundle->texMods[tm],
+ matrix );
+ break;
+
+ case TMOD_ROTATE:
+ RB_CalcRotateTexMatrix( bundle->texMods[tm].rotateSpeed,
+ matrix );
+ break;
+
+ default:
+ ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'", bundle->texMods[tm].type, tess.shader->name );
+ break;
+ }
+
+ switch ( bundle->texMods[tm].type )
+ {
+ case TMOD_NONE:
+ case TMOD_TURBULENT:
+ default:
+ break;
+
+ case TMOD_ENTITY_TRANSLATE:
+ case TMOD_SCROLL:
+ case TMOD_SCALE:
+ case TMOD_STRETCH:
+ case TMOD_TRANSFORM:
+ case TMOD_ROTATE:
+ outMatrix[0] = matrix[0] * currentmatrix[0] + matrix[2] * currentmatrix[1];
+ outMatrix[1] = matrix[1] * currentmatrix[0] + matrix[3] * currentmatrix[1];
+
+ outMatrix[2] = matrix[0] * currentmatrix[2] + matrix[2] * currentmatrix[3];
+ outMatrix[3] = matrix[1] * currentmatrix[2] + matrix[3] * currentmatrix[3];
+
+ outOffTurb[0] = matrix[0] * currentmatrix[4] + matrix[2] * currentmatrix[5] + matrix[4];
+ outOffTurb[1] = matrix[1] * currentmatrix[4] + matrix[3] * currentmatrix[5] + matrix[5];
+
+ currentmatrix[0] = outMatrix[0];
+ currentmatrix[1] = outMatrix[1];
+ currentmatrix[2] = outMatrix[2];
+ currentmatrix[3] = outMatrix[3];
+ currentmatrix[4] = outOffTurb[0];
+ currentmatrix[5] = outOffTurb[1];
+ break;
+ }
+ }
+}
+
+
+static void ComputeDeformValues(int *deformGen, vec5_t deformParams)
+{
+ // u_DeformGen
+ *deformGen = DGEN_NONE;
+ if(!ShaderRequiresCPUDeforms(tess.shader))
+ {
+ deformStage_t *ds;
+
+ // only support the first one
+ ds = &tess.shader->deforms[0];
+
+ switch (ds->deformation)
+ {
+ case DEFORM_WAVE:
+ *deformGen = ds->deformationWave.func;
+
+ deformParams[0] = ds->deformationWave.base;
+ deformParams[1] = ds->deformationWave.amplitude;
+ deformParams[2] = ds->deformationWave.phase;
+ deformParams[3] = ds->deformationWave.frequency;
+ deformParams[4] = ds->deformationSpread;
+ break;
+
+ case DEFORM_BULGE:
+ *deformGen = DGEN_BULGE;
+
+ deformParams[0] = 0;
+ deformParams[1] = ds->bulgeHeight; // amplitude
+ deformParams[2] = ds->bulgeWidth; // phase
+ deformParams[3] = ds->bulgeSpeed; // frequency
+ deformParams[4] = 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+
+static void ProjectDlightTexture( void ) {
+ int l;
+ vec3_t origin;
+ float scale;
+ float radius;
+ int deformGen;
+ vec5_t deformParams;
+
+ if ( !backEnd.refdef.num_dlights ) {
+ return;
+ }
+
+ ComputeDeformValues(&deformGen, deformParams);
+
+ for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
+ dlight_t *dl;
+ shaderProgram_t *sp;
+ vec4_t vector;
+
+ if ( !( tess.dlightBits & ( 1 << l ) ) ) {
+ continue; // this surface definately doesn't have any of this light
+ }
+
+ dl = &backEnd.refdef.dlights[l];
+ VectorCopy( dl->transformed, origin );
+ radius = dl->radius;
+ scale = 1.0f / radius;
+
+ sp = &tr.dlightShader[deformGen == DGEN_NONE ? 0 : 1];
+
+ backEnd.pc.c_dlightDraws++;
+
+ GLSL_BindProgram(sp);
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+
+ GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
+
+ GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
+ if (deformGen != DGEN_NONE)
+ {
+ GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
+ GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
+ }
+
+ vector[0] = dl->color[0];
+ vector[1] = dl->color[1];
+ vector[2] = dl->color[2];
+ vector[3] = 1.0f;
+ GLSL_SetUniformVec4(sp, UNIFORM_COLOR, vector);
+
+ vector[0] = origin[0];
+ vector[1] = origin[1];
+ vector[2] = origin[2];
+ vector[3] = scale;
+ GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector);
+
+ GL_BindToTMU( tr.dlightImage, TB_COLORMAP );
+
+ // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
+ // where they aren't rendered
+ if ( dl->additive ) {
+ GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
+ }
+ else {
+ GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
+ }
+
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 1);
+
+ R_DrawElements(tess.numIndexes, tess.firstIndex);
+
+ backEnd.pc.c_totalIndexes += tess.numIndexes;
+ backEnd.pc.c_dlightIndexes += tess.numIndexes;
+ backEnd.pc.c_dlightVertexes += tess.numVertexes;
+ }
+}
+
+
+static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t vertColor, int blend )
+{
+ bool isBlend = ((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_DST_COLOR)
+ || ((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR)
+ || ((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_SRC_COLOR)
+ || ((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR);
+
+ bool is2DDraw = backEnd.currentEntity == &backEnd.entity2D;
+
+ float overbright = (isBlend || is2DDraw) ? 1.0f : (float)(1 << tr.overbrightBits);
+
+ fog_t *fog;
+
+ baseColor[0] =
+ baseColor[1] =
+ baseColor[2] =
+ baseColor[3] = 1.0f;
+
+ vertColor[0] =
+ vertColor[1] =
+ vertColor[2] =
+ vertColor[3] = 0.0f;
+
+ //
+ // rgbGen
+ //
+ switch ( pStage->rgbGen )
+ {
+ case CGEN_EXACT_VERTEX:
+ case CGEN_EXACT_VERTEX_LIT:
+ baseColor[0] =
+ baseColor[1] =
+ baseColor[2] =
+ baseColor[3] = 0.0f;
+
+ vertColor[0] =
+ vertColor[1] =
+ vertColor[2] = overbright;
+ vertColor[3] = 1.0f;
+ break;
+ case CGEN_CONST:
+ baseColor[0] = pStage->constantColor[0] / 255.0f;
+ baseColor[1] = pStage->constantColor[1] / 255.0f;
+ baseColor[2] = pStage->constantColor[2] / 255.0f;
+ baseColor[3] = pStage->constantColor[3] / 255.0f;
+ break;
+ case CGEN_VERTEX:
+ case CGEN_VERTEX_LIT:
+ baseColor[0] =
+ baseColor[1] =
+ baseColor[2] =
+ baseColor[3] = 0.0f;
+
+ vertColor[0] =
+ vertColor[1] =
+ vertColor[2] =
+ vertColor[3] = 1.0f;
+ break;
+ case CGEN_ONE_MINUS_VERTEX:
+ baseColor[0] =
+ baseColor[1] =
+ baseColor[2] = 1.0f;
+
+ vertColor[0] =
+ vertColor[1] =
+ vertColor[2] = -1.0f;
+ break;
+ case CGEN_FOG:
+ fog = tr.world->fogs + tess.fogNum;
+
+ baseColor[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f;
+ baseColor[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f;
+ baseColor[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f;
+ baseColor[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f;
+ break;
+ case CGEN_WAVEFORM:
+ baseColor[0] =
+ baseColor[1] =
+ baseColor[2] = RB_CalcWaveColorSingle( &pStage->rgbWave );
+ break;
+ case CGEN_ENTITY:
+ if (backEnd.currentEntity)
+ {
+ baseColor[0] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[0] / 255.0f;
+ baseColor[1] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[1] / 255.0f;
+ baseColor[2] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f;
+ baseColor[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f;
+ }
+ break;
+ case CGEN_ONE_MINUS_ENTITY:
+ if (backEnd.currentEntity)
+ {
+ baseColor[0] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[0] / 255.0f;
+ baseColor[1] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[1] / 255.0f;
+ baseColor[2] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f;
+ baseColor[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f;
+ }
+ break;
+ case CGEN_IDENTITY:
+ case CGEN_LIGHTING_DIFFUSE:
+ baseColor[0] =
+ baseColor[1] =
+ baseColor[2] = overbright;
+ break;
+ case CGEN_IDENTITY_LIGHTING:
+ case CGEN_BAD:
+ break;
+ }
+
+ //
+ // alphaGen
+ //
+ switch ( pStage->alphaGen )
+ {
+ case AGEN_SKIP:
+ break;
+ case AGEN_CONST:
+ baseColor[3] = pStage->constantColor[3] / 255.0f;
+ vertColor[3] = 0.0f;
+ break;
+ case AGEN_WAVEFORM:
+ baseColor[3] = RB_CalcWaveAlphaSingle( &pStage->alphaWave );
+ vertColor[3] = 0.0f;
+ break;
+ case AGEN_ENTITY:
+ if (backEnd.currentEntity)
+ {
+ baseColor[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f;
+ }
+ vertColor[3] = 0.0f;
+ break;
+ case AGEN_ONE_MINUS_ENTITY:
+ if (backEnd.currentEntity)
+ {
+ baseColor[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f;
+ }
+ vertColor[3] = 0.0f;
+ break;
+ case AGEN_VERTEX:
+ baseColor[3] = 0.0f;
+ vertColor[3] = 1.0f;
+ break;
+ case AGEN_ONE_MINUS_VERTEX:
+ baseColor[3] = 1.0f;
+ vertColor[3] = -1.0f;
+ break;
+ case AGEN_IDENTITY:
+ case AGEN_LIGHTING_SPECULAR:
+ case AGEN_PORTAL:
+ // Done entirely in vertex program
+ baseColor[3] = 1.0f;
+ vertColor[3] = 0.0f;
+ break;
+ }
+
+ // FIXME: find some way to implement this.
+#if 0
+ // if in greyscale rendering mode turn all color values into greyscale.
+ if(r_greyscale->integer)
+ {
+ int scale;
+
+ for(i = 0; i < tess.numVertexes; i++)
+ {
+ scale = (tess.svars.colors[i][0] + tess.svars.colors[i][1] + tess.svars.colors[i][2]) / 3;
+ tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale;
+ }
+ }
+#endif
+}
+
+
+static void ComputeFogValues(vec4_t fogDistanceVector, vec4_t fogDepthVector, float *eyeT)
+{
+ // from RB_CalcFogTexCoords()
+ fog_t *fog;
+ vec3_t local;
+
+ if (!tess.fogNum)
+ return;
+
+ fog = tr.world->fogs + tess.fogNum;
+
+ VectorSubtract( backEnd.orientation.origin, backEnd.viewParms.orientation.origin, local );
+ fogDistanceVector[0] = -backEnd.orientation.modelMatrix[2];
+ fogDistanceVector[1] = -backEnd.orientation.modelMatrix[6];
+ fogDistanceVector[2] = -backEnd.orientation.modelMatrix[10];
+ fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.orientation.axis[0] );
+
+ // scale the fog vectors based on the fog's thickness
+ VectorScale4(fogDistanceVector, fog->tcScale, fogDistanceVector);
+
+ // rotate the gradient vector for this orientation
+ if ( fog->hasSurface ) {
+ fogDepthVector[0] = fog->surface[0] * backEnd.orientation.axis[0][0] +
+ fog->surface[1] * backEnd.orientation.axis[0][1] + fog->surface[2] * backEnd.orientation.axis[0][2];
+ fogDepthVector[1] = fog->surface[0] * backEnd.orientation.axis[1][0] +
+ fog->surface[1] * backEnd.orientation.axis[1][1] + fog->surface[2] * backEnd.orientation.axis[1][2];
+ fogDepthVector[2] = fog->surface[0] * backEnd.orientation.axis[2][0] +
+ fog->surface[1] * backEnd.orientation.axis[2][1] + fog->surface[2] * backEnd.orientation.axis[2][2];
+ fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.orientation.origin, fog->surface );
+
+ *eyeT = DotProduct( backEnd.orientation.viewOrigin, fogDepthVector ) + fogDepthVector[3];
+ } else {
+ *eyeT = 1; // non-surface fog always has eye inside
+ }
+}
+
+
+static void ComputeFogColorMask( shaderStage_t *pStage, vec4_t fogColorMask )
+{
+ switch(pStage->adjustColorsForFog)
+ {
+ case ACFF_MODULATE_RGB:
+ fogColorMask[0] =
+ fogColorMask[1] =
+ fogColorMask[2] = 1.0f;
+ fogColorMask[3] = 0.0f;
+ break;
+ case ACFF_MODULATE_ALPHA:
+ fogColorMask[0] =
+ fogColorMask[1] =
+ fogColorMask[2] = 0.0f;
+ fogColorMask[3] = 1.0f;
+ break;
+ case ACFF_MODULATE_RGBA:
+ fogColorMask[0] =
+ fogColorMask[1] =
+ fogColorMask[2] =
+ fogColorMask[3] = 1.0f;
+ break;
+ default:
+ fogColorMask[0] =
+ fogColorMask[1] =
+ fogColorMask[2] =
+ fogColorMask[3] = 0.0f;
+ break;
+ }
+}
+
+
+static void ForwardDlight( void ) {
+ int l;
+ //vec3_t origin;
+ //float scale;
+ float radius;
+
+ int deformGen;
+ vec5_t deformParams;
+
+ vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
+ float eyeT = 0;
+
+ shaderCommands_t *input = &tess;
+ shaderStage_t *pStage = tess.xstages[0];
+
+ if ( !backEnd.refdef.num_dlights ) {
+ return;
+ }
+
+ ComputeDeformValues(&deformGen, deformParams);
+
+ ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT);
+
+ for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
+ dlight_t *dl;
+ shaderProgram_t *sp;
+ vec4_t vector;
+ vec4_t texMatrix;
+ vec4_t texOffTurb;
+
+ if ( !( tess.dlightBits & ( 1 << l ) ) ) {
+ continue; // this surface definately doesn't have any of this light
+ }
+
+ dl = &backEnd.refdef.dlights[l];
+ //VectorCopy( dl->transformed, origin );
+ radius = dl->radius;
+ //scale = 1.0f / radius;
+
+ //if (pStage->glslShaderGroup == tr.lightallShader)
+ {
+ int index = pStage->glslShaderIndex;
+
+ index &= ~LIGHTDEF_LIGHTTYPE_MASK;
+ index |= LIGHTDEF_USE_LIGHT_VECTOR;
+
+ sp = &tr.lightallShader[index];
+ }
+
+ backEnd.pc.c_lightallDraws++;
+
+ GLSL_BindProgram(sp);
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+ GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.orientation.origin);
+ GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.orientation.viewOrigin);
+
+ GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
+
+ GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
+ if (deformGen != DGEN_NONE)
+ {
+ GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
+ GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
+ }
+
+ if ( input->fogNum ) {
+ vec4_t fogColorMask;
+
+ GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector);
+ GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector);
+ GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT);
+
+ ComputeFogColorMask(pStage, fogColorMask);
+
+ GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask);
+ }
+
+ {
+ vec4_t baseColor;
+ vec4_t vertColor;
+
+ ComputeShaderColors(pStage, baseColor, vertColor, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
+
+ GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor);
+ GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor);
+ }
+
+ if (pStage->alphaGen == AGEN_PORTAL)
+ {
+ GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange);
+ }
+
+ GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen);
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen);
+
+ GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, dl->color);
+
+ VectorSet(vector, 0, 0, 0);
+ GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vector);
+
+ VectorCopy(dl->origin, vector);
+ vector[3] = 1.0f;
+ GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector);
+
+ GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius);
+
+ GLSL_SetUniformVec4(sp, UNIFORM_NORMALSCALE, pStage->normalScale);
+ GLSL_SetUniformVec4(sp, UNIFORM_SPECULARSCALE, pStage->specularScale);
+
+ // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
+ // where they aren't rendered
+ GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.orientation.transformMatrix);
+
+ if (pStage->bundle[TB_DIFFUSEMAP].image[0])
+ R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP);
+
+ // bind textures that are sampled and used in the glsl shader, and
+ // bind whiteImage to textures that are sampled but zeroed in the glsl shader
+ //
+ // alternatives:
+ // - use the last bound texture
+ // -> costs more to sample a higher res texture then throw out the result
+ // - disable texture sampling in glsl shader with #ifdefs, as before
+ // -> increases the number of shaders that must be compiled
+ //
+
+ if (pStage->bundle[TB_NORMALMAP].image[0])
+ {
+ R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP);
+ }
+ else if (r_normalMapping->integer)
+ GL_BindToTMU( tr.whiteImage, TB_NORMALMAP );
+
+ if (pStage->bundle[TB_SPECULARMAP].image[0])
+ {
+ R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP);
+ }
+ else if (r_specularMapping->integer)
+ GL_BindToTMU( tr.whiteImage, TB_SPECULARMAP );
+
+ {
+ vec4_t enableTextures;
+
+ VectorSet4(enableTextures, 0.0f, 0.0f, 0.0f, 0.0f);
+ GLSL_SetUniformVec4(sp, UNIFORM_ENABLETEXTURES, enableTextures);
+ }
+
+ if (r_dlightMode->integer >= 2)
+ GL_BindToTMU(tr.shadowCubemaps[l], TB_SHADOWMAP);
+
+ ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb );
+ GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix);
+ GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb);
+
+ GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen);
+
+ //
+ // draw
+ //
+
+ R_DrawElements(input->numIndexes, input->firstIndex);
+
+ backEnd.pc.c_totalIndexes += tess.numIndexes;
+ backEnd.pc.c_dlightIndexes += tess.numIndexes;
+ backEnd.pc.c_dlightVertexes += tess.numVertexes;
+ }
+}
+
+
+static void ProjectPshadowVBOGLSL( void ) {
+ int l;
+ vec3_t origin;
+ float radius;
+
+ int deformGen;
+ vec5_t deformParams;
+
+ shaderCommands_t *input = &tess;
+
+ if ( !backEnd.refdef.num_pshadows ) {
+ return;
+ }
+
+ ComputeDeformValues(&deformGen, deformParams);
+
+ for ( l = 0 ; l < backEnd.refdef.num_pshadows ; l++ ) {
+ pshadow_t *ps;
+ shaderProgram_t *sp;
+ vec4_t vector;
+
+ if ( !( tess.pshadowBits & ( 1 << l ) ) ) {
+ continue; // this surface definately doesn't have any of this shadow
+ }
+
+ ps = &backEnd.refdef.pshadows[l];
+ VectorCopy( ps->lightOrigin, origin );
+ radius = ps->lightRadius;
+
+ sp = &tr.pshadowShader;
+
+ GLSL_BindProgram(sp);
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+
+ VectorCopy(origin, vector);
+ vector[3] = 1.0f;
+ GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector);
+
+ VectorScale(ps->lightViewAxis[0], 1.0f / ps->viewRadius, vector);
+ GLSL_SetUniformVec3(sp, UNIFORM_LIGHTFORWARD, vector);
+
+ VectorScale(ps->lightViewAxis[1], 1.0f / ps->viewRadius, vector);
+ GLSL_SetUniformVec3(sp, UNIFORM_LIGHTRIGHT, vector);
+
+ VectorScale(ps->lightViewAxis[2], 1.0f / ps->viewRadius, vector);
+ GLSL_SetUniformVec3(sp, UNIFORM_LIGHTUP, vector);
+
+ GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius);
+
+ // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
+ // where they aren't rendered
+ GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
+
+ GL_BindToTMU( tr.pshadowMaps[l], TB_DIFFUSEMAP );
+
+ //
+ // draw
+ //
+
+ R_DrawElements(input->numIndexes, input->firstIndex);
+
+ backEnd.pc.c_totalIndexes += tess.numIndexes;
+ //backEnd.pc.c_dlightIndexes += tess.numIndexes;
+ }
+}
+
+
+
+/*
+===================
+RB_FogPass
+
+Blends a fog texture on top of everything else
+===================
+*/
+static void RB_FogPass( void ) {
+ fog_t *fog;
+ vec4_t color;
+ vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
+ float eyeT = 0;
+ shaderProgram_t *sp;
+
+ int deformGen;
+ vec5_t deformParams;
+
+ ComputeDeformValues(&deformGen, deformParams);
+
+ {
+ int index = 0;
+
+ if (deformGen != DGEN_NONE)
+ index |= FOGDEF_USE_DEFORM_VERTEXES;
+
+ if (glState.vertexAnimation)
+ index |= FOGDEF_USE_VERTEX_ANIMATION;
+
+ sp = &tr.fogShader[index];
+ }
+
+ backEnd.pc.c_fogDraws++;
+
+ GLSL_BindProgram(sp);
+
+ fog = tr.world->fogs + tess.fogNum;
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+
+ GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
+
+ GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
+ if (deformGen != DGEN_NONE)
+ {
+ GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
+ GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
+ }
+
+ color[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f;
+ color[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f;
+ color[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f;
+ color[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f;
+ GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color);
+
+ ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT);
+
+ GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector);
+ GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector);
+ GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT);
+
+ if ( tess.shader->fogPass == FP_EQUAL ) {
+ GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
+ } else {
+ GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
+ }
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
+
+ R_DrawElements(tess.numIndexes, tess.firstIndex);
+}
+
+
+static unsigned int RB_CalcShaderVertexAttribs( shaderCommands_t *input )
+{
+ unsigned int vertexAttribs = input->shader->vertexAttribs;
+
+ if(glState.vertexAnimation)
+ {
+ vertexAttribs |= ATTR_POSITION2;
+ if (vertexAttribs & ATTR_NORMAL)
+ {
+ vertexAttribs |= ATTR_NORMAL2;
+ vertexAttribs |= ATTR_TANGENT2;
+ }
+ }
+
+ return vertexAttribs;
+}
+
+static void RB_IterateStagesGeneric( shaderCommands_t *input )
+{
+ int stage;
+
+ vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
+ float eyeT = 0;
+
+ int deformGen;
+ vec5_t deformParams;
+
+ bool renderToCubemap = tr.renderCubeFbo && glState.currentFBO == tr.renderCubeFbo;
+
+ ComputeDeformValues(&deformGen, deformParams);
+
+ ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT);
+
+ for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ )
+ {
+ shaderStage_t *pStage = input->xstages[stage];
+ shaderProgram_t *sp;
+ vec4_t texMatrix;
+ vec4_t texOffTurb;
+
+ if ( !pStage )
+ {
+ break;
+ }
+
+ if (backEnd.depthFill)
+ {
+ if (pStage->glslShaderGroup == tr.lightallShader)
+ {
+ int index = 0;
+
+ if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
+ {
+ index |= LIGHTDEF_ENTITY;
+ }
+
+ if (pStage->stateBits & GLS_ATEST_BITS)
+ {
+ index |= LIGHTDEF_USE_TCGEN_AND_TCMOD;
+ }
+
+ sp = &pStage->glslShaderGroup[index];
+ }
+ else
+ {
+ int shaderAttribs = 0;
+
+ if (tess.shader->numDeforms && !ShaderRequiresCPUDeforms(tess.shader))
+ {
+ shaderAttribs |= GENERICDEF_USE_DEFORM_VERTEXES;
+ }
+
+ if (glState.vertexAnimation)
+ {
+ shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION;
+ }
+
+ if (pStage->stateBits & GLS_ATEST_BITS)
+ {
+ shaderAttribs |= GENERICDEF_USE_TCGEN_AND_TCMOD;
+ }
+
+ sp = &tr.genericShader[shaderAttribs];
+ }
+ }
+ else if (pStage->glslShaderGroup == tr.lightallShader)
+ {
+ int index = pStage->glslShaderIndex;
+
+ if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
+ {
+ index |= LIGHTDEF_ENTITY;
+ }
+
+ if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (index & LIGHTDEF_LIGHTTYPE_MASK))
+ {
+ index |= LIGHTDEF_USE_SHADOWMAP;
+ }
+
+ if (r_lightmap->integer && ((index & LIGHTDEF_LIGHTTYPE_MASK) == LIGHTDEF_USE_LIGHTMAP))
+ {
+ index = LIGHTDEF_USE_TCGEN_AND_TCMOD;
+ }
+
+ sp = &pStage->glslShaderGroup[index];
+
+ backEnd.pc.c_lightallDraws++;
+ }
+ else
+ {
+ sp = GLSL_GetGenericShaderProgram(stage);
+
+ backEnd.pc.c_genericDraws++;
+ }
+
+ GLSL_BindProgram(sp);
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+ GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.orientation.origin);
+ GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.orientation.viewOrigin);
+
+ GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
+
+ GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
+ if (deformGen != DGEN_NONE)
+ {
+ GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
+ GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
+ }
+
+ if ( input->fogNum ) {
+ GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector);
+ GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector);
+ GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT);
+ }
+
+ GL_State( pStage->stateBits );
+ if ((pStage->stateBits & GLS_ATEST_BITS) == GLS_ATEST_GT_0)
+ {
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 1);
+ }
+ else if ((pStage->stateBits & GLS_ATEST_BITS) == GLS_ATEST_LT_80)
+ {
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 2);
+ }
+ else if ((pStage->stateBits & GLS_ATEST_BITS) == GLS_ATEST_GE_80)
+ {
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 3);
+ }
+ else
+ {
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
+ }
+
+
+ {
+ vec4_t baseColor;
+ vec4_t vertColor;
+
+ ComputeShaderColors(pStage, baseColor, vertColor, pStage->stateBits);
+
+ GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor);
+ GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor);
+ }
+
+ if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE)
+ {
+ vec4_t vec;
+
+ VectorScale(backEnd.currentEntity->ambientLight, 1.0f / 255.0f, vec);
+ GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vec);
+
+ VectorScale(backEnd.currentEntity->directedLight, 1.0f / 255.0f, vec);
+ GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, vec);
+
+ VectorCopy(backEnd.currentEntity->lightDir, vec);
+ vec[3] = 0.0f;
+ GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vec);
+ GLSL_SetUniformVec3(sp, UNIFORM_MODELLIGHTDIR, backEnd.currentEntity->modelLightDir);
+
+ GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, 0.0f);
+ }
+
+ if (pStage->alphaGen == AGEN_PORTAL)
+ {
+ GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange);
+ }
+
+ GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen);
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen);
+
+ if ( input->fogNum )
+ {
+ vec4_t fogColorMask;
+
+ ComputeFogColorMask(pStage, fogColorMask);
+
+ GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask);
+ }
+
+ if (r_lightmap->integer)
+ {
+ vec4_t v;
+ VectorSet4(v, 1.0f, 0.0f, 0.0f, 1.0f);
+ GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, v);
+ VectorSet4(v, 0.0f, 0.0f, 0.0f, 0.0f);
+ GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, v);
+
+ GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, TCGEN_LIGHTMAP);
+ }
+ else
+ {
+ ComputeTexMods(pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb);
+ GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix);
+ GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb);
+
+ GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen);
+ if (pStage->bundle[0].tcGen == TCGEN_VECTOR)
+ {
+ vec3_t vec;
+
+ VectorCopy(pStage->bundle[0].tcGenVectors[0], vec);
+ GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR0, vec);
+ VectorCopy(pStage->bundle[0].tcGenVectors[1], vec);
+ GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR1, vec);
+ }
+ }
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.orientation.transformMatrix);
+
+ GLSL_SetUniformVec4(sp, UNIFORM_NORMALSCALE, pStage->normalScale);
+
+ {
+ vec4_t specularScale;
+ Vector4Copy(pStage->specularScale, specularScale);
+
+ if (renderToCubemap)
+ {
+ // force specular to nonmetal if rendering cubemaps
+ if (r_pbr->integer)
+ specularScale[1] = 0.0f;
+ }
+
+ GLSL_SetUniformVec4(sp, UNIFORM_SPECULARSCALE, specularScale);
+ }
+
+ //GLSL_SetUniformFloat(sp, UNIFORM_MAPLIGHTSCALE, backEnd.refdef.mapLightScale);
+
+ //
+ // do multitexture
+ //
+ if ( backEnd.depthFill )
+ {
+ if (!(pStage->stateBits & GLS_ATEST_BITS))
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
+ else if ( pStage->bundle[TB_COLORMAP].image[0] != 0 )
+ R_BindAnimatedImageToTMU( &pStage->bundle[TB_COLORMAP], TB_COLORMAP );
+ }
+ else if ( pStage->glslShaderGroup == tr.lightallShader )
+ {
+ int i;
+ vec4_t enableTextures;
+
+ if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK))
+ {
+ // FIXME: screenShadowImage is NULL if no framebuffers
+ if (tr.screenShadowImage)
+ GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP);
+ GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTAMBIENT, backEnd.refdef.sunAmbCol);
+ if (r_pbr->integer)
+ {
+ vec3_t color;
+
+ color[0] = backEnd.refdef.sunCol[0] * backEnd.refdef.sunCol[0];
+ color[1] = backEnd.refdef.sunCol[1] * backEnd.refdef.sunCol[1];
+ color[2] = backEnd.refdef.sunCol[2] * backEnd.refdef.sunCol[2];
+ GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTCOLOR, color);
+ }
+ else
+ {
+ GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTCOLOR, backEnd.refdef.sunCol);
+ }
+ GLSL_SetUniformVec4(sp, UNIFORM_PRIMARYLIGHTORIGIN, backEnd.refdef.sunDir);
+ }
+
+ VectorSet4(enableTextures, 0, 0, 0, 0);
+ if ((r_lightmap->integer == 1 || r_lightmap->integer == 2) && pStage->bundle[TB_LIGHTMAP].image[0])
+ {
+ for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
+ {
+ if (i == TB_COLORMAP)
+ R_BindAnimatedImageToTMU( &pStage->bundle[TB_LIGHTMAP], i);
+ else
+ GL_BindToTMU( tr.whiteImage, i );
+ }
+ }
+ else if (r_lightmap->integer == 3 && pStage->bundle[TB_DELUXEMAP].image[0])
+ {
+ for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
+ {
+ if (i == TB_COLORMAP)
+ R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], i);
+ else
+ GL_BindToTMU( tr.whiteImage, i );
+ }
+ }
+ else
+ {
+ bool light = (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) != 0;
+ bool fastLight = !(r_normalMapping->integer || r_specularMapping->integer);
+
+ if (pStage->bundle[TB_DIFFUSEMAP].image[0])
+ R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP);
+
+ if (pStage->bundle[TB_LIGHTMAP].image[0])
+ R_BindAnimatedImageToTMU( &pStage->bundle[TB_LIGHTMAP], TB_LIGHTMAP);
+
+ // bind textures that are sampled and used in the glsl shader, and
+ // bind whiteImage to textures that are sampled but zeroed in the glsl shader
+ //
+ // alternatives:
+ // - use the last bound texture
+ // -> costs more to sample a higher res texture then throw out the result
+ // - disable texture sampling in glsl shader with #ifdefs, as before
+ // -> increases the number of shaders that must be compiled
+ //
+ if (light && !fastLight)
+ {
+ if (pStage->bundle[TB_NORMALMAP].image[0])
+ {
+ R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP);
+ enableTextures[0] = 1.0f;
+ }
+ else if (r_normalMapping->integer)
+ GL_BindToTMU( tr.whiteImage, TB_NORMALMAP );
+
+ if (pStage->bundle[TB_DELUXEMAP].image[0])
+ {
+ R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], TB_DELUXEMAP);
+ enableTextures[1] = 1.0f;
+ }
+ else if (r_deluxeMapping->integer)
+ GL_BindToTMU( tr.whiteImage, TB_DELUXEMAP );
+
+ if (pStage->bundle[TB_SPECULARMAP].image[0])
+ {
+ R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP);
+ enableTextures[2] = 1.0f;
+ }
+ else if (r_specularMapping->integer)
+ GL_BindToTMU( tr.whiteImage, TB_SPECULARMAP );
+ }
+
+ enableTextures[3] = (r_cubeMapping->integer && !(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex) ? 1.0f : 0.0f;
+ }
+
+ GLSL_SetUniformVec4(sp, UNIFORM_ENABLETEXTURES, enableTextures);
+ }
+ else if ( pStage->bundle[1].image[0] != 0 )
+ {
+ R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 );
+ R_BindAnimatedImageToTMU( &pStage->bundle[1], 1 );
+ }
+ else
+ {
+ //
+ // set state
+ //
+ R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 );
+ }
+
+ //
+ // testing cube map
+ //
+ if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex && r_cubeMapping->integer)
+ {
+ vec4_t vec;
+ cubemap_t *cubemap = &tr.cubemaps[input->cubemapIndex - 1];
+
+ // FIXME: cubemap image could be NULL if cubemap isn't renderer or loaded
+ if (cubemap->image)
+ GL_BindToTMU( cubemap->image, TB_CUBEMAP);
+
+ VectorSubtract(cubemap->origin, backEnd.viewParms.orientation.origin, vec);
+ vec[3] = 1.0f;
+
+ VectorScale4(vec, 1.0f / cubemap->parallaxRadius, vec);
+
+ GLSL_SetUniformVec4(sp, UNIFORM_CUBEMAPINFO, vec);
+ }
+
+ //
+ // draw
+ //
+ R_DrawElements(input->numIndexes, input->firstIndex);
+
+ // allow skipping out to show just lightmaps during development
+ if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) )
+ {
+ break;
+ }
+
+ if (backEnd.depthFill)
+ break;
+ }
+}
+
+
+static void RB_RenderShadowmap( shaderCommands_t *input )
+{
+ int deformGen;
+ vec5_t deformParams;
+
+ ComputeDeformValues(&deformGen, deformParams);
+
+ {
+ shaderProgram_t *sp = &tr.shadowmapShader;
+
+ vec4_t vector;
+
+ GLSL_BindProgram(sp);
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.orientation.transformMatrix);
+
+ GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
+
+ GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
+ if (deformGen != DGEN_NONE)
+ {
+ GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
+ GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
+ }
+
+ VectorCopy(backEnd.viewParms.orientation.origin, vector);
+ vector[3] = 1.0f;
+ GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector);
+ GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, backEnd.viewParms.zFar);
+
+ GL_State( 0 );
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
+
+ //
+ // do multitexture
+ //
+ //if ( pStage->glslShaderGroup )
+ {
+ //
+ // draw
+ //
+
+ R_DrawElements(input->numIndexes, input->firstIndex);
+ }
+ }
+}
+
+
+
+/*
+** RB_StageIteratorGeneric
+*/
+void RB_StageIteratorGeneric( void )
+{
+ shaderCommands_t *input;
+ unsigned int vertexAttribs = 0;
+
+ input = &tess;
+
+ if (!input->numVertexes || !input->numIndexes)
+ {
+ return;
+ }
+
+ if (tess.useInternalVao)
+ {
+ RB_DeformTessGeometry();
+ }
+
+ vertexAttribs = RB_CalcShaderVertexAttribs( input );
+
+ if (tess.useInternalVao)
+ {
+ RB_UpdateTessVao(vertexAttribs);
+ }
+ else
+ {
+ backEnd.pc.c_staticVaoDraws++;
+ }
+
+ //
+ // log this call
+ //
+ if ( r_logFile->integer )
+ {
+ // don't just call LogComment, or we will get
+ // a call to va() every frame!
+ GLimp_LogComment( (char*)va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) );
+ }
+
+ //
+ // set face culling appropriately
+ //
+ if (input->shader->cullType == CT_TWO_SIDED)
+ {
+ GL_Cull( CT_TWO_SIDED );
+ }
+ else
+ {
+ bool cullFront = (input->shader->cullType == CT_FRONT_SIDED);
+
+ if ( backEnd.viewParms.flags & VPF_DEPTHSHADOW )
+ cullFront = !cullFront;
+
+ if ( backEnd.viewParms.isMirror )
+ cullFront = !cullFront;
+
+ if ( backEnd.currentEntity && backEnd.currentEntity->mirrored )
+ cullFront = !cullFront;
+
+ if (cullFront)
+ GL_Cull( CT_FRONT_SIDED );
+ else
+ GL_Cull( CT_BACK_SIDED );
+ }
+
+ // set polygon offset if necessary
+ if ( input->shader->polygonOffset )
+ {
+ qglEnable( GL_POLYGON_OFFSET_FILL );
+ }
+
+ //
+ // render depth if in depthfill mode
+ //
+ if (backEnd.depthFill)
+ {
+ RB_IterateStagesGeneric( input );
+
+ //
+ // reset polygon offset
+ //
+ if ( input->shader->polygonOffset )
+ {
+ qglDisable( GL_POLYGON_OFFSET_FILL );
+ }
+
+ return;
+ }
+
+ //
+ // render shadowmap if in shadowmap mode
+ //
+ if (backEnd.viewParms.flags & VPF_SHADOWMAP)
+ {
+ if ( input->shader->sort == SS_OPAQUE )
+ {
+ RB_RenderShadowmap( input );
+ }
+ //
+ // reset polygon offset
+ //
+ if ( input->shader->polygonOffset )
+ {
+ qglDisable( GL_POLYGON_OFFSET_FILL );
+ }
+
+ return;
+ }
+
+ //
+ //
+ // call shader function
+ //
+ RB_IterateStagesGeneric( input );
+
+ //
+ // pshadows!
+ //
+ if (glRefConfig.framebufferObject && r_shadows->integer == 4 && tess.pshadowBits
+ && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) {
+ ProjectPshadowVBOGLSL();
+ }
+
+
+ //
+ // now do any dynamic lighting needed
+ //
+ if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE && r_lightmap->integer == 0
+ && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) {
+ if (tess.shader->numUnfoggedPasses == 1 && tess.xstages[0]->glslShaderGroup == tr.lightallShader
+ && (tess.xstages[0]->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && r_dlightMode->integer)
+ {
+ ForwardDlight();
+ }
+ else
+ {
+ ProjectDlightTexture();
+ }
+ }
+
+ //
+ // now do fog
+ //
+ if ( tess.fogNum && tess.shader->fogPass ) {
+ RB_FogPass();
+ }
+
+ //
+ // reset polygon offset
+ //
+ if ( input->shader->polygonOffset )
+ {
+ qglDisable( GL_POLYGON_OFFSET_FILL );
+ }
+}
+
+/*
+** RB_EndSurface
+*/
+void RB_EndSurface( void ) {
+ shaderCommands_t *input;
+
+ input = &tess;
+
+ if (input->numIndexes == 0 || input->numVertexes == 0) {
+ return;
+ }
+
+ if (input->indexes[SHADER_MAX_INDEXES-1] != 0) {
+ ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit");
+ }
+ if (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) {
+ ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit");
+ }
+
+ if ( tess.shader == tr.shadowShader ) {
+ RB_ShadowTessEnd();
+ return;
+ }
+
+ // for debugging of sort order issues, stop rendering after a given sort value
+ if ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) {
+ return;
+ }
+
+ if (tess.useCacheVao)
+ {
+ // upload indexes now
+ VaoCache_Commit();
+ }
+
+ //
+ // update performance counters
+ //
+ backEnd.pc.c_shaders++;
+ backEnd.pc.c_vertexes += tess.numVertexes;
+ backEnd.pc.c_indexes += tess.numIndexes;
+ backEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses;
+
+ //
+ // call off to shader specific tess end function
+ //
+ tess.currentStageIteratorFunc();
+
+ //
+ // draw debugging stuff
+ //
+ if ( r_showtris->integer ) {
+ DrawTris (input);
+ }
+ if ( r_shownormals->integer ) {
+ DrawNormals (input);
+ }
+ // clear shader so we can tell we don't have any unclosed surfaces
+ tess.numIndexes = 0;
+ tess.numVertexes = 0;
+ tess.firstIndex = 0;
+
+ GLimp_LogComment( "----------\n" );
+}
diff --git a/src/renderergl2/tr_shade_calc.cpp b/src/renderergl2/tr_shade_calc.cpp
new file mode 100644
index 0000000..182020b
--- /dev/null
+++ b/src/renderergl2/tr_shade_calc.cpp
@@ -0,0 +1,843 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_shade_calc.c
+
+#include "tr_local.h"
+#if idppc_altivec && !defined(__APPLE__)
+#include <altivec.h>
+#endif
+
+
+#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ static_cast<int64_t>( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
+
+static float *TableForFunc( genFunc_t func )
+{
+ switch ( func )
+ {
+ case GF_SIN:
+ return tr.sinTable;
+ case GF_TRIANGLE:
+ return tr.triangleTable;
+ case GF_SQUARE:
+ return tr.squareTable;
+ case GF_SAWTOOTH:
+ return tr.sawToothTable;
+ case GF_INVERSE_SAWTOOTH:
+ return tr.inverseSawToothTable;
+ case GF_NONE:
+ default:
+ break;
+ }
+
+ ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'", func, tess.shader->name );
+ return NULL;
+}
+
+/*
+** EvalWaveForm
+**
+** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly
+*/
+static float EvalWaveForm( const waveForm_t *wf )
+{
+ float *table;
+
+ table = TableForFunc( wf->func );
+
+ return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency );
+}
+
+static float EvalWaveFormClamped( const waveForm_t *wf )
+{
+ float glow = EvalWaveForm( wf );
+
+ if ( glow < 0 )
+ {
+ return 0;
+ }
+
+ if ( glow > 1 )
+ {
+ return 1;
+ }
+
+ return glow;
+}
+
+/*
+** RB_CalcStretchTexMatrix
+*/
+void RB_CalcStretchTexMatrix( const waveForm_t *wf, float *matrix )
+{
+ float p;
+
+ p = 1.0f / EvalWaveForm( wf );
+
+ matrix[0] = p; matrix[2] = 0; matrix[4] = 0.5f - 0.5f * p;
+ matrix[1] = 0; matrix[3] = p; matrix[5] = 0.5f - 0.5f * p;
+}
+
+/*
+====================================================================
+
+DEFORMATIONS
+
+====================================================================
+*/
+
+/*
+========================
+RB_CalcDeformVertexes
+
+========================
+*/
+void RB_CalcDeformVertexes( deformStage_t *ds )
+{
+ int i;
+ vec3_t offset;
+ float scale;
+ float *xyz = ( float * ) tess.xyz;
+ int16_t *normal = tess.normal[0];
+ float *table;
+
+ if ( ds->deformationWave.frequency == 0 )
+ {
+ scale = EvalWaveForm( &ds->deformationWave );
+
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
+ {
+ R_VaoUnpackNormal(offset, normal);
+
+ xyz[0] += offset[0] * scale;
+ xyz[1] += offset[1] * scale;
+ xyz[2] += offset[2] * scale;
+ }
+ }
+ else
+ {
+ table = TableForFunc( ds->deformationWave.func );
+
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
+ {
+ float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
+
+ scale = WAVEVALUE( table, ds->deformationWave.base,
+ ds->deformationWave.amplitude,
+ ds->deformationWave.phase + off,
+ ds->deformationWave.frequency );
+
+ R_VaoUnpackNormal(offset, normal);
+
+ xyz[0] += offset[0] * scale;
+ xyz[1] += offset[1] * scale;
+ xyz[2] += offset[2] * scale;
+ }
+ }
+}
+
+/*
+=========================
+RB_CalcDeformNormals
+
+Wiggle the normals for wavy environment mapping
+=========================
+*/
+void RB_CalcDeformNormals( deformStage_t *ds ) {
+ int i;
+ float scale;
+ float *xyz = ( float * ) tess.xyz;
+ int16_t *normal = tess.normal[0];
+
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) {
+ vec3_t fNormal;
+
+ R_VaoUnpackNormal(fNormal, normal);
+
+ scale = 0.98f;
+ scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
+ tess.shaderTime * ds->deformationWave.frequency );
+ fNormal[ 0 ] += ds->deformationWave.amplitude * scale;
+
+ scale = 0.98f;
+ scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
+ tess.shaderTime * ds->deformationWave.frequency );
+ fNormal[ 1 ] += ds->deformationWave.amplitude * scale;
+
+ scale = 0.98f;
+ scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
+ tess.shaderTime * ds->deformationWave.frequency );
+ fNormal[ 2 ] += ds->deformationWave.amplitude * scale;
+
+ VectorNormalizeFast( fNormal );
+
+ R_VaoPackNormal(normal, fNormal);
+ }
+}
+
+/*
+========================
+RB_CalcBulgeVertexes
+
+========================
+*/
+void RB_CalcBulgeVertexes( deformStage_t *ds ) {
+ int i;
+ const float *st = ( const float * ) tess.texCoords[0];
+ float *xyz = ( float * ) tess.xyz;
+ int16_t *normal = tess.normal[0];
+
+ double now = backEnd.refdef.time * 0.001 * ds->bulgeSpeed;
+
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 2, normal += 4 ) {
+ int64_t off;
+ float scale;
+ vec3_t fNormal;
+
+ R_VaoUnpackNormal(fNormal, normal);
+
+ off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now );
+
+ scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight;
+
+ xyz[0] += fNormal[0] * scale;
+ xyz[1] += fNormal[1] * scale;
+ xyz[2] += fNormal[2] * scale;
+ }
+}
+
+
+/*
+======================
+RB_CalcMoveVertexes
+
+A deformation that can move an entire surface along a wave path
+======================
+*/
+void RB_CalcMoveVertexes( deformStage_t *ds ) {
+ int i;
+ float *xyz;
+ float *table;
+ float scale;
+ vec3_t offset;
+
+ table = TableForFunc( ds->deformationWave.func );
+
+ scale = WAVEVALUE( table, ds->deformationWave.base,
+ ds->deformationWave.amplitude,
+ ds->deformationWave.phase,
+ ds->deformationWave.frequency );
+
+ VectorScale( ds->moveVector, scale, offset );
+
+ xyz = ( float * ) tess.xyz;
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
+ VectorAdd( xyz, offset, xyz );
+ }
+}
+
+
+/*
+=============
+DeformText
+
+Change a polygon into a bunch of text polygons
+=============
+*/
+void DeformText( const char *text ) {
+ int i;
+ vec3_t origin, width, height;
+ int len;
+ int ch;
+ float color[4];
+ float bottom, top;
+ vec3_t mid;
+ vec3_t fNormal;
+
+ height[0] = 0;
+ height[1] = 0;
+ height[2] = -1;
+
+ R_VaoUnpackNormal(fNormal, tess.normal[0]);
+ CrossProduct( fNormal, height, width );
+
+ // find the midpoint of the box
+ VectorClear( mid );
+ bottom = 999999;
+ top = -999999;
+ for ( i = 0 ; i < 4 ; i++ ) {
+ VectorAdd( tess.xyz[i], mid, mid );
+ if ( tess.xyz[i][2] < bottom ) {
+ bottom = tess.xyz[i][2];
+ }
+ if ( tess.xyz[i][2] > top ) {
+ top = tess.xyz[i][2];
+ }
+ }
+ VectorScale( mid, 0.25f, origin );
+
+ // determine the individual character size
+ height[0] = 0;
+ height[1] = 0;
+ height[2] = ( top - bottom ) * 0.5f;
+
+ VectorScale( width, height[2] * -0.75f, width );
+
+ // determine the starting position
+ len = strlen( text );
+ VectorMA( origin, (len-1), width, origin );
+
+ // clear the shader indexes
+ tess.numIndexes = 0;
+ tess.numVertexes = 0;
+ tess.firstIndex = 0;
+
+ color[0] = color[1] = color[2] = color[3] = 1.0f;
+
+ // draw each character
+ for ( i = 0 ; i < len ; i++ ) {
+ ch = text[i];
+ ch &= 255;
+
+ if ( ch != ' ' ) {
+ int row, col;
+ float frow, fcol, size;
+
+ row = ch>>4;
+ col = ch&15;
+
+ frow = row*0.0625f;
+ fcol = col*0.0625f;
+ size = 0.0625f;
+
+ RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size );
+ }
+ VectorMA( origin, -2, width, origin );
+ }
+}
+
+/*
+==================
+GlobalVectorToLocal
+==================
+*/
+static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) {
+ out[0] = DotProduct( in, backEnd.orientation.axis[0] );
+ out[1] = DotProduct( in, backEnd.orientation.axis[1] );
+ out[2] = DotProduct( in, backEnd.orientation.axis[2] );
+}
+
+/*
+=====================
+AutospriteDeform
+
+Assuming all the triangles for this shader are independant
+quads, rebuild them as forward facing sprites
+=====================
+*/
+static void AutospriteDeform( void ) {
+ int i;
+ int oldVerts;
+ float *xyz;
+ vec3_t mid, delta;
+ float radius;
+ vec3_t left, up;
+ vec3_t leftDir, upDir;
+
+ if ( tess.numVertexes & 3 ) {
+ ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count\n", tess.shader->name );
+ }
+ if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
+ ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count\n", tess.shader->name );
+ }
+
+ oldVerts = tess.numVertexes;
+ tess.numVertexes = 0;
+ tess.numIndexes = 0;
+ tess.firstIndex = 0;
+
+ if ( backEnd.currentEntity != &tr.worldEntity ) {
+ GlobalVectorToLocal( backEnd.viewParms.orientation.axis[1], leftDir );
+ GlobalVectorToLocal( backEnd.viewParms.orientation.axis[2], upDir );
+ } else {
+ VectorCopy( backEnd.viewParms.orientation.axis[1], leftDir );
+ VectorCopy( backEnd.viewParms.orientation.axis[2], upDir );
+ }
+
+ for ( i = 0 ; i < oldVerts ; i+=4 ) {
+ vec4_t color;
+ // find the midpoint
+ xyz = tess.xyz[i];
+
+ mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]);
+ mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]);
+ mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]);
+
+ VectorSubtract( xyz, mid, delta );
+ radius = VectorLength( delta ) * 0.707f; // / sqrt(2)
+
+ VectorScale( leftDir, radius, left );
+ VectorScale( upDir, radius, up );
+
+ if ( backEnd.viewParms.isMirror ) {
+ VectorSubtract( vec3_origin, left, left );
+ }
+
+ // compensate for scale in the axes if necessary
+ if ( backEnd.currentEntity->e.nonNormalizedAxes ) {
+ float axisLength;
+ axisLength = VectorLength( backEnd.currentEntity->e.axis[0] );
+ if ( !axisLength ) {
+ axisLength = 0;
+ } else {
+ axisLength = 1.0f / axisLength;
+ }
+ VectorScale(left, axisLength, left);
+ VectorScale(up, axisLength, up);
+ }
+
+ VectorScale4(tess.color[i], 1.0f / 65535.0f, color);
+ RB_AddQuadStamp( mid, left, up, color );
+ }
+}
+
+
+/*
+=====================
+Autosprite2Deform
+
+Autosprite2 will pivot a rectangular quad along the center of its long axis
+=====================
+*/
+int edgeVerts[6][2] = {
+ { 0, 1 },
+ { 0, 2 },
+ { 0, 3 },
+ { 1, 2 },
+ { 1, 3 },
+ { 2, 3 }
+};
+
+static void Autosprite2Deform( void ) {
+ int i, j, k;
+ int indexes;
+ float *xyz;
+ vec3_t forward;
+
+ if ( tess.numVertexes & 3 ) {
+ ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count\n", tess.shader->name );
+ }
+ if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
+ ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count\n", tess.shader->name );
+ }
+
+ if ( backEnd.currentEntity != &tr.worldEntity ) {
+ GlobalVectorToLocal( backEnd.viewParms.orientation.axis[0], forward );
+ } else {
+ VectorCopy( backEnd.viewParms.orientation.axis[0], forward );
+ }
+
+ // this is a lot of work for two triangles...
+ // we could precalculate a lot of it is an issue, but it would mess up
+ // the shader abstraction
+ for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) {
+ float lengths[2];
+ int nums[2];
+ vec3_t mid[2];
+ vec3_t major, minor;
+ float *v1, *v2;
+
+ // find the midpoint
+ xyz = tess.xyz[i];
+
+ // identify the two shortest edges
+ nums[0] = nums[1] = 0;
+ lengths[0] = lengths[1] = 999999;
+
+ for ( j = 0 ; j < 6 ; j++ ) {
+ float l;
+ vec3_t temp;
+
+ v1 = xyz + 4 * edgeVerts[j][0];
+ v2 = xyz + 4 * edgeVerts[j][1];
+
+ VectorSubtract( v1, v2, temp );
+
+ l = DotProduct( temp, temp );
+ if ( l < lengths[0] ) {
+ nums[1] = nums[0];
+ lengths[1] = lengths[0];
+ nums[0] = j;
+ lengths[0] = l;
+ } else if ( l < lengths[1] ) {
+ nums[1] = j;
+ lengths[1] = l;
+ }
+ }
+
+ for ( j = 0 ; j < 2 ; j++ ) {
+ v1 = xyz + 4 * edgeVerts[nums[j]][0];
+ v2 = xyz + 4 * edgeVerts[nums[j]][1];
+
+ mid[j][0] = 0.5f * (v1[0] + v2[0]);
+ mid[j][1] = 0.5f * (v1[1] + v2[1]);
+ mid[j][2] = 0.5f * (v1[2] + v2[2]);
+ }
+
+ // find the vector of the major axis
+ VectorSubtract( mid[1], mid[0], major );
+
+ // cross this with the view direction to get minor axis
+ CrossProduct( major, forward, minor );
+ VectorNormalize( minor );
+
+ // re-project the points
+ for ( j = 0 ; j < 2 ; j++ ) {
+ float l;
+
+ v1 = xyz + 4 * edgeVerts[nums[j]][0];
+ v2 = xyz + 4 * edgeVerts[nums[j]][1];
+
+ l = 0.5 * sqrt( lengths[j] );
+
+ // we need to see which direction this edge
+ // is used to determine direction of projection
+ for ( k = 0 ; k < 5 ; k++ ) {
+ if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0]
+ && tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) {
+ break;
+ }
+ }
+
+ if ( k == 5 ) {
+ VectorMA( mid[j], l, minor, v1 );
+ VectorMA( mid[j], -l, minor, v2 );
+ } else {
+ VectorMA( mid[j], -l, minor, v1 );
+ VectorMA( mid[j], l, minor, v2 );
+ }
+ }
+ }
+}
+
+
+/*
+=====================
+RB_DeformTessGeometry
+
+=====================
+*/
+void RB_DeformTessGeometry( void ) {
+ int i;
+ deformStage_t *ds;
+
+ if(!ShaderRequiresCPUDeforms(tess.shader))
+ {
+ // we don't need the following CPU deforms
+ return;
+ }
+
+ for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) {
+ ds = &tess.shader->deforms[ i ];
+
+ switch ( ds->deformation ) {
+ case DEFORM_NONE:
+ break;
+ case DEFORM_NORMALS:
+ RB_CalcDeformNormals( ds );
+ break;
+ case DEFORM_WAVE:
+ RB_CalcDeformVertexes( ds );
+ break;
+ case DEFORM_BULGE:
+ RB_CalcBulgeVertexes( ds );
+ break;
+ case DEFORM_MOVE:
+ RB_CalcMoveVertexes( ds );
+ break;
+ case DEFORM_PROJECTION_SHADOW:
+ RB_ProjectionShadowDeform();
+ break;
+ case DEFORM_AUTOSPRITE:
+ AutospriteDeform();
+ break;
+ case DEFORM_AUTOSPRITE2:
+ Autosprite2Deform();
+ break;
+ case DEFORM_TEXT0:
+ case DEFORM_TEXT1:
+ case DEFORM_TEXT2:
+ case DEFORM_TEXT3:
+ case DEFORM_TEXT4:
+ case DEFORM_TEXT5:
+ case DEFORM_TEXT6:
+ case DEFORM_TEXT7:
+ DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] );
+ break;
+ }
+ }
+}
+
+/*
+====================================================================
+
+COLORS
+
+====================================================================
+*/
+
+
+/*
+** RB_CalcWaveColorSingle
+*/
+float RB_CalcWaveColorSingle( const waveForm_t *wf )
+{
+ float glow;
+
+ if ( wf->func == GF_NOISE ) {
+ glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude;
+ } else {
+ glow = EvalWaveForm( wf ) * tr.identityLight;
+ }
+
+ if ( glow < 0 ) {
+ glow = 0;
+ }
+ else if ( glow > 1 ) {
+ glow = 1;
+ }
+
+ return glow;
+}
+
+/*
+** RB_CalcWaveAlphaSingle
+*/
+float RB_CalcWaveAlphaSingle( const waveForm_t *wf )
+{
+ return EvalWaveFormClamped( wf );
+}
+
+/*
+** RB_CalcModulateColorsByFog
+*/
+void RB_CalcModulateColorsByFog( unsigned char *colors ) {
+ int i;
+ float texCoords[SHADER_MAX_VERTEXES][2] = {{0.0f}};
+
+ // calculate texcoords so we can derive density
+ // this is not wasted, because it would only have
+ // been previously called if the surface was opaque
+ RB_CalcFogTexCoords( texCoords[0] );
+
+ for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
+ float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
+ colors[0] *= f;
+ colors[1] *= f;
+ colors[2] *= f;
+ }
+}
+
+
+/*
+====================================================================
+
+TEX COORDS
+
+====================================================================
+*/
+
+/*
+========================
+RB_CalcFogTexCoords
+
+To do the clipped fog plane really correctly, we should use
+projected textures, but I don't trust the drivers and it
+doesn't fit our shader data.
+========================
+*/
+void RB_CalcFogTexCoords( float *st ) {
+ int i;
+ float *v;
+ float s, t;
+ float eyeT;
+ bool eyeOutside;
+ fog_t *fog;
+ vec3_t local;
+ vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
+
+ fog = tr.world->fogs + tess.fogNum;
+
+ // all fogging distance is based on world Z units
+ VectorSubtract( backEnd.orientation.origin, backEnd.viewParms.orientation.origin, local );
+ fogDistanceVector[0] = -backEnd.orientation.modelMatrix[2];
+ fogDistanceVector[1] = -backEnd.orientation.modelMatrix[6];
+ fogDistanceVector[2] = -backEnd.orientation.modelMatrix[10];
+ fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.orientation.axis[0] );
+
+ // scale the fog vectors based on the fog's thickness
+ fogDistanceVector[0] *= fog->tcScale;
+ fogDistanceVector[1] *= fog->tcScale;
+ fogDistanceVector[2] *= fog->tcScale;
+ fogDistanceVector[3] *= fog->tcScale;
+
+ // rotate the gradient vector for this orientation
+ if ( fog->hasSurface ) {
+ fogDepthVector[0] = fog->surface[0] * backEnd.orientation.axis[0][0] +
+ fog->surface[1] * backEnd.orientation.axis[0][1] + fog->surface[2] * backEnd.orientation.axis[0][2];
+ fogDepthVector[1] = fog->surface[0] * backEnd.orientation.axis[1][0] +
+ fog->surface[1] * backEnd.orientation.axis[1][1] + fog->surface[2] * backEnd.orientation.axis[1][2];
+ fogDepthVector[2] = fog->surface[0] * backEnd.orientation.axis[2][0] +
+ fog->surface[1] * backEnd.orientation.axis[2][1] + fog->surface[2] * backEnd.orientation.axis[2][2];
+ fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.orientation.origin, fog->surface );
+
+ eyeT = DotProduct( backEnd.orientation.viewOrigin, fogDepthVector ) + fogDepthVector[3];
+ } else {
+ eyeT = 1; // non-surface fog always has eye inside
+ }
+
+ // see if the viewpoint is outside
+ // this is needed for clipping distance even for constant fog
+
+ if ( eyeT < 0 ) {
+ eyeOutside = true;
+ } else {
+ eyeOutside = false;
+ }
+
+ fogDistanceVector[3] += 1.0/512;
+
+ // calculate density for each point
+ for (i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4) {
+ // calculate the length in fog
+ s = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3];
+ t = DotProduct( v, fogDepthVector ) + fogDepthVector[3];
+
+ // partially clipped fogs use the T axis
+ if ( eyeOutside ) {
+ if ( t < 1.0 ) {
+ t = 1.0/32; // point is outside, so no fogging
+ } else {
+ t = 1.0/32 + 30.0/32 * t / ( t - eyeT ); // cut the distance at the fog plane
+ }
+ } else {
+ if ( t < 0 ) {
+ t = 1.0/32; // point is outside, so no fogging
+ } else {
+ t = 31.0/32;
+ }
+ }
+
+ st[0] = s;
+ st[1] = t;
+ st += 2;
+ }
+}
+
+/*
+** RB_CalcTurbulentFactors
+*/
+void RB_CalcTurbulentFactors( const waveForm_t *wf, float *amplitude, float *now )
+{
+ *now = wf->phase + tess.shaderTime * wf->frequency;
+ *amplitude = wf->amplitude;
+}
+
+/*
+** RB_CalcScaleTexMatrix
+*/
+void RB_CalcScaleTexMatrix( const float scale[2], float *matrix )
+{
+ matrix[0] = scale[0]; matrix[2] = 0.0f; matrix[4] = 0.0f;
+ matrix[1] = 0.0f; matrix[3] = scale[1]; matrix[5] = 0.0f;
+}
+
+/*
+** RB_CalcScrollTexMatrix
+*/
+void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix )
+{
+ double timeScale = tess.shaderTime;
+ double adjustedScrollS = scrollSpeed[0] * timeScale;
+ double adjustedScrollT = scrollSpeed[1] * timeScale;
+
+ // clamp so coordinates don't continuously get larger, causing problems
+ // with hardware limits
+ adjustedScrollS -= floor( adjustedScrollS );
+ adjustedScrollT -= floor( adjustedScrollT );
+
+ matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = adjustedScrollS;
+ matrix[1] = 0.0f; matrix[3] = 1.0f; matrix[5] = adjustedScrollT;
+}
+
+/*
+** RB_CalcTransformTexMatrix
+*/
+void RB_CalcTransformTexMatrix( const texModInfo_t *tmi, float *matrix )
+{
+ matrix[0] = tmi->matrix[0][0]; matrix[2] = tmi->matrix[1][0]; matrix[4] = tmi->translate[0];
+ matrix[1] = tmi->matrix[0][1]; matrix[3] = tmi->matrix[1][1]; matrix[5] = tmi->translate[1];
+}
+
+/*
+** RB_CalcRotateTexMatrix
+*/
+void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix )
+{
+ double timeScale = tess.shaderTime;
+ double degs;
+ float sinValue, cosValue;
+
+ degs = -degsPerSecond * timeScale;
+ int i = degs * ( FUNCTABLE_SIZE / 360.0f );
+
+ sinValue = tr.sinTable[ i & FUNCTABLE_MASK ];
+ cosValue = tr.sinTable[ ( i + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ];
+
+ matrix[0] = cosValue; matrix[2] = -sinValue; matrix[4] = 0.5 - 0.5 * cosValue + 0.5 * sinValue;
+ matrix[1] = sinValue; matrix[3] = cosValue; matrix[5] = 0.5 - 0.5 * sinValue - 0.5 * cosValue;
+}
+
+bool ShaderRequiresCPUDeforms(const shader_t * shader)
+{
+ if(shader->numDeforms)
+ {
+ const deformStage_t *ds = &shader->deforms[0];
+
+ if (shader->numDeforms > 1)
+ return true;
+
+ switch (ds->deformation)
+ {
+ case DEFORM_WAVE:
+ case DEFORM_BULGE:
+ // need CPU deforms at high level-times to avoid floating point percision loss
+ return ( backEnd.refdef.floatTime != (float)backEnd.refdef.floatTime );
+
+ default:
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/src/renderergl2/tr_shader.cpp b/src/renderergl2/tr_shader.cpp
new file mode 100644
index 0000000..b3ebacf
--- /dev/null
+++ b/src/renderergl2/tr_shader.cpp
@@ -0,0 +1,3891 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "tr_local.h"
+
+// tr_shader.c -- this file deals with the parsing and definition of shaders
+
+static char *s_shaderText;
+
+// the shader is parsed into these global variables, then copied into
+// dynamically allocated memory if it is valid.
+static shaderStage_t stages[MAX_SHADER_STAGES];
+static shader_t shader;
+static texModInfo_t texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS];
+
+#define FILE_HASH_SIZE 1024
+static shader_t* hashTable[FILE_HASH_SIZE];
+
+#define MAX_SHADERTEXT_HASH 2048
+static char **shaderTextHashTable[MAX_SHADERTEXT_HASH];
+
+/*
+================
+return a hash value for the filename
+================
+*/
+#ifdef __GNUCC__
+ #warning TODO: check if long is ok here
+#endif
+static long generateHashValue( const char *fname, const int size ) {
+ int i;
+ long hash;
+ char letter;
+
+ hash = 0;
+ i = 0;
+ while (fname[i] != '\0') {
+ letter = tolower(fname[i]);
+ if (letter =='.') break; // don't include extension
+ if (letter =='\\') letter = '/'; // damn path names
+ if (letter == PATH_SEP) letter = '/'; // damn path names
+ hash+=(long)(letter)*(i+119);
+ i++;
+ }
+ hash = (hash ^ (hash >> 10) ^ (hash >> 20));
+ hash &= (size-1);
+ return hash;
+}
+
+void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) {
+ char strippedName[MAX_QPATH];
+ int hash;
+ shader_t *sh, *sh2;
+ qhandle_t h;
+
+ sh = R_FindShaderByName( shaderName );
+ if (sh == NULL || sh == tr.defaultShader) {
+ h = RE_RegisterShaderLightMap(shaderName, 0);
+ sh = R_GetShaderByHandle(h);
+ }
+ if (sh == NULL || sh == tr.defaultShader) {
+ ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName );
+ return;
+ }
+
+ sh2 = R_FindShaderByName( newShaderName );
+ if (sh2 == NULL || sh2 == tr.defaultShader) {
+ h = RE_RegisterShaderLightMap(newShaderName, 0);
+ sh2 = R_GetShaderByHandle(h);
+ }
+
+ if (sh2 == NULL || sh2 == tr.defaultShader) {
+ ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName );
+ return;
+ }
+
+ // remap all the shaders with the given name
+ // even tho they might have different lightmaps
+ COM_StripExtension(shaderName, strippedName, sizeof(strippedName));
+ hash = generateHashValue(strippedName, FILE_HASH_SIZE);
+ for (sh = hashTable[hash]; sh; sh = sh->next) {
+ if (Q_stricmp(sh->name, strippedName) == 0) {
+ if (sh != sh2) {
+ sh->remappedShader = sh2;
+ } else {
+ sh->remappedShader = NULL;
+ }
+ }
+ }
+ if (timeOffset) {
+ sh2->timeOffset = atof(timeOffset);
+ }
+}
+
+/*
+===============
+ParseVector
+===============
+*/
+static bool ParseVector( char **text, int count, float *v ) {
+ char *token;
+ int i;
+
+ // FIXME: spaces are currently required after parens, should change parseext...
+ token = COM_ParseExt( text, qfalse );
+ if ( strcmp( token, "(" ) ) {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ for ( i = 0 ; i < count ; i++ ) {
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] ) {
+ ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name );
+ return false;
+ }
+ v[i] = atof( token );
+ }
+
+ token = COM_ParseExt( text, qfalse );
+ if ( strcmp( token, ")" ) ) {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ return true;
+}
+
+
+/*
+===============
+NameToAFunc
+===============
+*/
+static unsigned NameToAFunc( const char *funcname )
+{
+ if ( !Q_stricmp( funcname, "GT0" ) )
+ {
+ return GLS_ATEST_GT_0;
+ }
+ else if ( !Q_stricmp( funcname, "LT128" ) )
+ {
+ return GLS_ATEST_LT_80;
+ }
+ else if ( !Q_stricmp( funcname, "GE128" ) )
+ {
+ return GLS_ATEST_GE_80;
+ }
+
+ ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name );
+ return 0;
+}
+
+
+/*
+===============
+NameToSrcBlendMode
+===============
+*/
+static int NameToSrcBlendMode( const char *name )
+{
+ if ( !Q_stricmp( name, "GL_ONE" ) )
+ {
+ return GLS_SRCBLEND_ONE;
+ }
+ else if ( !Q_stricmp( name, "GL_ZERO" ) )
+ {
+ return GLS_SRCBLEND_ZERO;
+ }
+ else if ( !Q_stricmp( name, "GL_DST_COLOR" ) )
+ {
+ return GLS_SRCBLEND_DST_COLOR;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) )
+ {
+ return GLS_SRCBLEND_ONE_MINUS_DST_COLOR;
+ }
+ else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
+ {
+ return GLS_SRCBLEND_SRC_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
+ {
+ return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
+ {
+ if (r_ignoreDstAlpha->integer)
+ return GLS_SRCBLEND_ONE;
+
+ return GLS_SRCBLEND_DST_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
+ {
+ if (r_ignoreDstAlpha->integer)
+ return GLS_SRCBLEND_ZERO;
+
+ return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) )
+ {
+ return GLS_SRCBLEND_ALPHA_SATURATE;
+ }
+
+ ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
+ return GLS_SRCBLEND_ONE;
+}
+
+/*
+===============
+NameToDstBlendMode
+===============
+*/
+static int NameToDstBlendMode( const char *name )
+{
+ if ( !Q_stricmp( name, "GL_ONE" ) )
+ {
+ return GLS_DSTBLEND_ONE;
+ }
+ else if ( !Q_stricmp( name, "GL_ZERO" ) )
+ {
+ return GLS_DSTBLEND_ZERO;
+ }
+ else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
+ {
+ return GLS_DSTBLEND_SRC_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
+ {
+ return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
+ {
+ if (r_ignoreDstAlpha->integer)
+ return GLS_DSTBLEND_ONE;
+
+ return GLS_DSTBLEND_DST_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
+ {
+ if (r_ignoreDstAlpha->integer)
+ return GLS_DSTBLEND_ZERO;
+
+ return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA;
+ }
+ else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) )
+ {
+ return GLS_DSTBLEND_SRC_COLOR;
+ }
+ else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) )
+ {
+ return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR;
+ }
+
+ ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
+ return GLS_DSTBLEND_ONE;
+}
+
+/*
+===============
+NameToGenFunc
+===============
+*/
+static genFunc_t NameToGenFunc( const char *funcname )
+{
+ if ( !Q_stricmp( funcname, "sin" ) )
+ {
+ return GF_SIN;
+ }
+ else if ( !Q_stricmp( funcname, "square" ) )
+ {
+ return GF_SQUARE;
+ }
+ else if ( !Q_stricmp( funcname, "triangle" ) )
+ {
+ return GF_TRIANGLE;
+ }
+ else if ( !Q_stricmp( funcname, "sawtooth" ) )
+ {
+ return GF_SAWTOOTH;
+ }
+ else if ( !Q_stricmp( funcname, "inversesawtooth" ) )
+ {
+ return GF_INVERSE_SAWTOOTH;
+ }
+ else if ( !Q_stricmp( funcname, "noise" ) )
+ {
+ return GF_NOISE;
+ }
+
+ ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name );
+ return GF_SIN;
+}
+
+
+/*
+===================
+ParseWaveForm
+===================
+*/
+static void ParseWaveForm( char **text, waveForm_t *wave )
+{
+ char *token;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ return;
+ }
+ wave->func = NameToGenFunc( token );
+
+ // BASE, AMP, PHASE, FREQ
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ return;
+ }
+ wave->base = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ return;
+ }
+ wave->amplitude = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ return;
+ }
+ wave->phase = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ return;
+ }
+ wave->frequency = atof( token );
+}
+
+
+/*
+===================
+ParseTexMod
+===================
+*/
+static void ParseTexMod( char *_text, shaderStage_t *stage )
+{
+ const char *token;
+ char **text = &_text;
+ texModInfo_t *tmi;
+
+ if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) {
+ ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'", shader.name );
+ return;
+ }
+
+ tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods];
+ stage->bundle[0].numTexMods++;
+
+ token = COM_ParseExt( text, qfalse );
+
+ //
+ // turb
+ //
+ if ( !Q_stricmp( token, "turb" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.base = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.amplitude = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.phase = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.frequency = atof( token );
+
+ tmi->type = TMOD_TURBULENT;
+ }
+ //
+ // scale
+ //
+ else if ( !Q_stricmp( token, "scale" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->scale[0] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->scale[1] = atof( token );
+ tmi->type = TMOD_SCALE;
+ }
+ //
+ // scroll
+ //
+ else if ( !Q_stricmp( token, "scroll" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->scroll[0] = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->scroll[1] = atof( token );
+ tmi->type = TMOD_SCROLL;
+ }
+ //
+ // stretch
+ //
+ else if ( !Q_stricmp( token, "stretch" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.func = NameToGenFunc( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.base = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.amplitude = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.phase = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->wave.frequency = atof( token );
+
+ tmi->type = TMOD_STRETCH;
+ }
+ //
+ // transform
+ //
+ else if ( !Q_stricmp( token, "transform" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->matrix[0][0] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->matrix[0][1] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->matrix[1][0] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->matrix[1][1] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->translate[0] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->translate[1] = atof( token );
+
+ tmi->type = TMOD_TRANSFORM;
+ }
+ //
+ // rotate
+ //
+ else if ( !Q_stricmp( token, "rotate" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name );
+ return;
+ }
+ tmi->rotateSpeed = atof( token );
+ tmi->type = TMOD_ROTATE;
+ }
+ //
+ // entityTranslate
+ //
+ else if ( !Q_stricmp( token, "entityTranslate" ) )
+ {
+ tmi->type = TMOD_ENTITY_TRANSLATE;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name );
+ }
+}
+
+
+/*
+===================
+ParseStage
+===================
+*/
+static bool ParseStage( shaderStage_t *stage, char **text )
+{
+ char *token;
+ int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0;
+ bool depthMaskExplicit = false;
+
+ stage->active = true;
+
+ while ( 1 )
+ {
+ token = COM_ParseExt( text, qtrue );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" );
+ return false;
+ }
+
+ if ( token[0] == '}' )
+ {
+ break;
+ }
+ //
+ // map <name>
+ //
+ else if ( !Q_stricmp( token, "map" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ if ( !Q_stricmp( token, "$whiteimage" ) )
+ {
+ stage->bundle[0].image[0] = tr.whiteImage;
+ continue;
+ }
+ else if ( !Q_stricmp( token, "$lightmap" ) )
+ {
+ stage->bundle[0].isLightmap = true;
+ if ( shader.lightmapIndex < 0 || !tr.lightmaps ) {
+ stage->bundle[0].image[0] = tr.whiteImage;
+ } else {
+ stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
+ }
+ continue;
+ }
+ else if ( !Q_stricmp( token, "$deluxemap" ) )
+ {
+ if (!tr.worldDeluxeMapping)
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: shader '%s' wants a deluxe map in a map compiled without them\n", shader.name );
+ return false;
+ }
+
+ stage->bundle[0].isLightmap = true;
+ if ( shader.lightmapIndex < 0 ) {
+ stage->bundle[0].image[0] = tr.whiteImage;
+ } else {
+ stage->bundle[0].image[0] = tr.deluxemaps[shader.lightmapIndex];
+ }
+ continue;
+ }
+ else
+ {
+ imgType_t type = IMGTYPE_COLORALPHA;
+ int/*imgFlags_t*/ flags = IMGFLAG_NONE;
+
+ if (!shader.noMipMaps)
+ flags |= IMGFLAG_MIPMAP;
+
+ if (!shader.noPicMip)
+ flags |= IMGFLAG_PICMIP;
+
+ if (stage->type == ST_NORMALMAP || stage->type == ST_NORMALPARALLAXMAP)
+ {
+ type = IMGTYPE_NORMAL;
+ flags |= IMGFLAG_NOLIGHTSCALE;
+
+ if (stage->type == ST_NORMALPARALLAXMAP)
+ type = IMGTYPE_NORMALHEIGHT;
+ }
+ else
+ {
+ if (r_genNormalMaps->integer)
+ flags |= IMGFLAG_GENNORMALMAP;
+ }
+
+ stage->bundle[0].image[0] = R_FindImageFile( token, type, flags );
+
+ if ( !stage->bundle[0].image[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
+ return false;
+ }
+ }
+ }
+ //
+ // clampmap <name>
+ //
+ else if ( !Q_stricmp( token, "clampmap" ) )
+ {
+ imgType_t type = IMGTYPE_COLORALPHA;
+ int/*imgFlags_t*/ flags = IMGFLAG_CLAMPTOEDGE;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ if (!shader.noMipMaps)
+ flags |= IMGFLAG_MIPMAP;
+
+ if (!shader.noPicMip)
+ flags |= IMGFLAG_PICMIP;
+
+ if (stage->type == ST_NORMALMAP || stage->type == ST_NORMALPARALLAXMAP)
+ {
+ type = IMGTYPE_NORMAL;
+ flags |= IMGFLAG_NOLIGHTSCALE;
+
+ if (stage->type == ST_NORMALPARALLAXMAP)
+ type = IMGTYPE_NORMALHEIGHT;
+ }
+ else
+ {
+ if (r_genNormalMaps->integer)
+ flags |= IMGFLAG_GENNORMALMAP;
+ }
+
+
+ stage->bundle[0].image[0] = R_FindImageFile( token, type, flags );
+ if ( !stage->bundle[0].image[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
+ return false;
+ }
+ }
+ //
+ // animMap <frequency> <image1> .... <imageN>
+ //
+ else if ( !Q_stricmp( token, "animMap" ) )
+ {
+ int totalImages = 0;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMap' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+ stage->bundle[0].imageAnimationSpeed = atof( token );
+
+ // parse up to MAX_IMAGE_ANIMATIONS animations
+ while ( 1 ) {
+ int num;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] ) {
+ break;
+ }
+ num = stage->bundle[0].numImageAnimations;
+ if ( num < MAX_IMAGE_ANIMATIONS ) {
+ int/*imgFlags_t*/ flags = IMGFLAG_NONE;
+
+ if (!shader.noMipMaps)
+ flags |= IMGFLAG_MIPMAP;
+
+ if (!shader.noPicMip)
+ flags |= IMGFLAG_PICMIP;
+
+ stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags );
+ if ( !stage->bundle[0].image[num] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
+ return false;
+ }
+ stage->bundle[0].numImageAnimations++;
+ }
+ totalImages++;
+ }
+
+ if ( totalImages > MAX_IMAGE_ANIMATIONS )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: ignoring excess images for 'animMap' (found %d, max is %d) in shader '%s'\n",
+ totalImages, MAX_IMAGE_ANIMATIONS, shader.name );
+ }
+ }
+ else if ( !Q_stricmp( token, "videoMap" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+ stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader));
+ if (stage->bundle[0].videoMapHandle != -1) {
+ stage->bundle[0].isVideoMap = true;
+ stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle];
+ } else {
+ ri.Printf( PRINT_WARNING, "WARNING: could not load '%s' for 'videoMap' keyword in shader '%s'\n", token, shader.name );
+ }
+ }
+ //
+ // alphafunc <func>
+ //
+ else if ( !Q_stricmp( token, "alphaFunc" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ atestBits = NameToAFunc( token );
+ }
+ //
+ // depthFunc <func>
+ //
+ else if ( !Q_stricmp( token, "depthfunc" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name );
+ return false;
+ }
+
+ if ( !Q_stricmp( token, "lequal" ) )
+ {
+ depthFuncBits = 0;
+ }
+ else if ( !Q_stricmp( token, "equal" ) )
+ {
+ depthFuncBits = GLS_DEPTHFUNC_EQUAL;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name );
+ continue;
+ }
+ }
+ //
+ // detail
+ //
+ else if ( !Q_stricmp( token, "detail" ) )
+ {
+ stage->isDetail = true;
+ }
+ //
+ // blendfunc <srcFactor> <dstFactor>
+ // or blendfunc <add|filter|blend>
+ //
+ else if ( !Q_stricmp( token, "blendfunc" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
+ continue;
+ }
+ // check for "simple" blends first
+ if ( !Q_stricmp( token, "add" ) ) {
+ blendSrcBits = GLS_SRCBLEND_ONE;
+ blendDstBits = GLS_DSTBLEND_ONE;
+ } else if ( !Q_stricmp( token, "filter" ) ) {
+ blendSrcBits = GLS_SRCBLEND_DST_COLOR;
+ blendDstBits = GLS_DSTBLEND_ZERO;
+ } else if ( !Q_stricmp( token, "blend" ) ) {
+ blendSrcBits = GLS_SRCBLEND_SRC_ALPHA;
+ blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
+ } else {
+ // complex double blends
+ blendSrcBits = NameToSrcBlendMode( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
+ continue;
+ }
+ blendDstBits = NameToDstBlendMode( token );
+ }
+
+ // clear depth mask for blended surfaces
+ if ( !depthMaskExplicit )
+ {
+ depthMaskBits = 0;
+ }
+ }
+ //
+ // stage <type>
+ //
+ else if(!Q_stricmp(token, "stage"))
+ {
+ token = COM_ParseExt(text, qfalse);
+ if(token[0] == 0)
+ {
+ ri.Printf(PRINT_WARNING, "WARNING: missing parameters for stage in shader '%s'\n", shader.name);
+ continue;
+ }
+
+ if(!Q_stricmp(token, "diffuseMap"))
+ {
+ stage->type = ST_DIFFUSEMAP;
+ }
+ else if(!Q_stricmp(token, "normalMap") || !Q_stricmp(token, "bumpMap"))
+ {
+ stage->type = ST_NORMALMAP;
+ VectorSet4(stage->normalScale, r_baseNormalX->value, r_baseNormalY->value, 1.0f, r_baseParallax->value);
+ }
+ else if(!Q_stricmp(token, "normalParallaxMap") || !Q_stricmp(token, "bumpParallaxMap"))
+ {
+ if (r_parallaxMapping->integer)
+ stage->type = ST_NORMALPARALLAXMAP;
+ else
+ stage->type = ST_NORMALMAP;
+ VectorSet4(stage->normalScale, r_baseNormalX->value, r_baseNormalY->value, 1.0f, r_baseParallax->value);
+ }
+ else if(!Q_stricmp(token, "specularMap"))
+ {
+ stage->type = ST_SPECULARMAP;
+ VectorSet4(stage->specularScale, 1.0f, 1.0f, 1.0f, 1.0f);
+ }
+ else
+ {
+ ri.Printf(PRINT_WARNING, "WARNING: unknown stage parameter '%s' in shader '%s'\n", token, shader.name);
+ continue;
+ }
+ }
+ //
+ // specularReflectance <value>
+ //
+ else if (!Q_stricmp(token, "specularreflectance"))
+ {
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular reflectance in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ if (r_pbr->integer)
+ {
+ // interpret specularReflectance < 0.5 as nonmetal
+ stage->specularScale[1] = (atof(token) < 0.5f) ? 0.0f : 1.0f;
+ }
+ else
+ {
+ stage->specularScale[0] =
+ stage->specularScale[1] =
+ stage->specularScale[2] = atof( token );
+ }
+ }
+ //
+ // specularExponent <value>
+ //
+ else if (!Q_stricmp(token, "specularexponent"))
+ {
+ float exponent;
+
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular exponent in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ exponent = atof( token );
+
+ if (r_pbr->integer)
+ stage->specularScale[0] = 1.0f - powf(2.0f / (exponent + 2.0), 0.25);
+ else
+ {
+ // Change shininess to gloss
+ // Assumes max exponent of 8190 and min of 0, must change here if altered in lightall_fp.glsl
+ exponent = CLAMP(exponent, 0.0f, 8190.0f);
+ stage->specularScale[3] = (log2f(exponent + 2.0f) - 1.0f) / 12.0f;
+ }
+ }
+ //
+ // gloss <value>
+ //
+ else if (!Q_stricmp(token, "gloss"))
+ {
+ float gloss;
+
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for gloss in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ gloss = atof(token);
+
+ if (r_pbr->integer)
+ stage->specularScale[0] = 1.0f - exp2f(-3.0f * gloss);
+ else
+ stage->specularScale[3] = gloss;
+ }
+ //
+ // roughness <value>
+ //
+ else if (!Q_stricmp(token, "roughness"))
+ {
+ float roughness;
+
+ token = COM_ParseExt(text, qfalse);
+ if (token[0] == 0)
+ {
+ ri.Printf(PRINT_WARNING, "WARNING: missing parameter for roughness in shader '%s'\n", shader.name);
+ continue;
+ }
+
+ roughness = atof(token);
+
+ if (r_pbr->integer)
+ stage->specularScale[0] = 1.0 - roughness;
+ else
+ {
+ if (roughness >= 0.125)
+ stage->specularScale[3] = log2f(1.0f / roughness) / 3.0f;
+ else
+ stage->specularScale[3] = 1.0f;
+ }
+ }
+ //
+ // parallaxDepth <value>
+ //
+ else if (!Q_stricmp(token, "parallaxdepth"))
+ {
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for parallaxDepth in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ stage->normalScale[3] = atof( token );
+ }
+ //
+ // normalScale <xy>
+ // or normalScale <x> <y>
+ // or normalScale <x> <y> <height>
+ //
+ else if (!Q_stricmp(token, "normalscale"))
+ {
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for normalScale in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ stage->normalScale[0] = atof( token );
+
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ // one value, applies to X/Y
+ stage->normalScale[1] = stage->normalScale[0];
+ continue;
+ }
+
+ stage->normalScale[1] = atof( token );
+
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ // two values, no height
+ continue;
+ }
+
+ stage->normalScale[3] = atof( token );
+ }
+ //
+ // specularScale <rgb> <gloss>
+ // or specularScale <metallic> <smoothness> with r_pbr 1
+ // or specularScale <r> <g> <b>
+ // or specularScale <r> <g> <b> <gloss>
+ //
+ else if (!Q_stricmp(token, "specularscale"))
+ {
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specularScale in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ stage->specularScale[0] = atof( token );
+
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specularScale in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ stage->specularScale[1] = atof( token );
+
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ if (r_pbr->integer)
+ {
+ // two values, metallic then smoothness
+ float smoothness = stage->specularScale[1];
+ stage->specularScale[1] = (stage->specularScale[0] < 0.5f) ? 0.0f : 1.0f;
+ stage->specularScale[0] = smoothness;
+ }
+ {
+ // two values, rgb then gloss
+ stage->specularScale[3] = stage->specularScale[1];
+ stage->specularScale[1] =
+ stage->specularScale[2] = stage->specularScale[0];
+ }
+ continue;
+ }
+
+ stage->specularScale[2] = atof( token );
+
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ // three values, rgb
+ continue;
+ }
+
+ stage->specularScale[2] = atof( token );
+
+ }
+ //
+ // rgbGen
+ //
+ else if ( !Q_stricmp( token, "rgbGen" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ if ( !Q_stricmp( token, "wave" ) )
+ {
+ ParseWaveForm( text, &stage->rgbWave );
+ stage->rgbGen = CGEN_WAVEFORM;
+ }
+ else if ( !Q_stricmp( token, "const" ) )
+ {
+ vec3_t color;
+
+ VectorClear( color );
+
+ ParseVector( text, 3, color );
+ stage->constantColor[0] = 255 * color[0];
+ stage->constantColor[1] = 255 * color[1];
+ stage->constantColor[2] = 255 * color[2];
+
+ stage->rgbGen = CGEN_CONST;
+ }
+ else if ( !Q_stricmp( token, "identity" ) )
+ {
+ stage->rgbGen = CGEN_IDENTITY;
+ }
+ else if ( !Q_stricmp( token, "identityLighting" ) )
+ {
+ stage->rgbGen = CGEN_IDENTITY_LIGHTING;
+ }
+ else if ( !Q_stricmp( token, "entity" ) )
+ {
+ stage->rgbGen = CGEN_ENTITY;
+ }
+ else if ( !Q_stricmp( token, "oneMinusEntity" ) )
+ {
+ stage->rgbGen = CGEN_ONE_MINUS_ENTITY;
+ }
+ else if ( !Q_stricmp( token, "vertex" ) )
+ {
+ stage->rgbGen = CGEN_VERTEX;
+ if ( stage->alphaGen == 0 ) {
+ stage->alphaGen = AGEN_VERTEX;
+ }
+ }
+ else if ( !Q_stricmp( token, "exactVertex" ) )
+ {
+ stage->rgbGen = CGEN_EXACT_VERTEX;
+ }
+ else if ( !Q_stricmp( token, "vertexLit" ) )
+ {
+ stage->rgbGen = CGEN_VERTEX_LIT;
+ if ( stage->alphaGen == 0 ) {
+ stage->alphaGen = AGEN_VERTEX;
+ }
+ }
+ else if ( !Q_stricmp( token, "exactVertexLit" ) )
+ {
+ stage->rgbGen = CGEN_EXACT_VERTEX_LIT;
+ }
+ else if ( !Q_stricmp( token, "lightingDiffuse" ) )
+ {
+ stage->rgbGen = CGEN_LIGHTING_DIFFUSE;
+ }
+ else if ( !Q_stricmp( token, "oneMinusVertex" ) )
+ {
+ stage->rgbGen = CGEN_ONE_MINUS_VERTEX;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name );
+ continue;
+ }
+ }
+ //
+ // alphaGen
+ //
+ else if ( !Q_stricmp( token, "alphaGen" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ if ( !Q_stricmp( token, "wave" ) )
+ {
+ ParseWaveForm( text, &stage->alphaWave );
+ stage->alphaGen = AGEN_WAVEFORM;
+ }
+ else if ( !Q_stricmp( token, "const" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ stage->constantColor[3] = 255 * atof( token );
+ stage->alphaGen = AGEN_CONST;
+ }
+ else if ( !Q_stricmp( token, "identity" ) )
+ {
+ stage->alphaGen = AGEN_IDENTITY;
+ }
+ else if ( !Q_stricmp( token, "entity" ) )
+ {
+ stage->alphaGen = AGEN_ENTITY;
+ }
+ else if ( !Q_stricmp( token, "oneMinusEntity" ) )
+ {
+ stage->alphaGen = AGEN_ONE_MINUS_ENTITY;
+ }
+ else if ( !Q_stricmp( token, "vertex" ) )
+ {
+ stage->alphaGen = AGEN_VERTEX;
+ }
+ else if ( !Q_stricmp( token, "lightingSpecular" ) )
+ {
+ stage->alphaGen = AGEN_LIGHTING_SPECULAR;
+ }
+ else if ( !Q_stricmp( token, "oneMinusVertex" ) )
+ {
+ stage->alphaGen = AGEN_ONE_MINUS_VERTEX;
+ }
+ else if ( !Q_stricmp( token, "portal" ) )
+ {
+ stage->alphaGen = AGEN_PORTAL;
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ shader.portalRange = 256;
+ ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name );
+ }
+ else
+ {
+ shader.portalRange = atof( token );
+ }
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name );
+ continue;
+ }
+ }
+ //
+ // tcGen <function>
+ //
+ else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ if ( !Q_stricmp( token, "environment" ) )
+ {
+ stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED;
+ }
+ else if ( !Q_stricmp( token, "lightmap" ) )
+ {
+ stage->bundle[0].tcGen = TCGEN_LIGHTMAP;
+ }
+ else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) )
+ {
+ stage->bundle[0].tcGen = TCGEN_TEXTURE;
+ }
+ else if ( !Q_stricmp( token, "vector" ) )
+ {
+ ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] );
+ ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] );
+
+ stage->bundle[0].tcGen = TCGEN_VECTOR;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name );
+ }
+ }
+ //
+ // tcMod <type> <...>
+ //
+ else if ( !Q_stricmp( token, "tcMod" ) )
+ {
+ char buffer[1024] = "";
+
+ while ( 1 )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ break;
+ Q_strcat( buffer, sizeof (buffer), token );
+ Q_strcat( buffer, sizeof (buffer), " " );
+ }
+
+ ParseTexMod( buffer, stage );
+
+ continue;
+ }
+ //
+ // depthmask
+ //
+ else if ( !Q_stricmp( token, "depthwrite" ) )
+ {
+ depthMaskBits = GLS_DEPTHMASK_TRUE;
+ depthMaskExplicit = true;
+
+ continue;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name );
+ return false;
+ }
+ }
+
+ //
+ // if cgen isn't explicitly specified, use either identity or identitylighting
+ //
+ if ( stage->rgbGen == CGEN_BAD ) {
+ if ( blendSrcBits == 0 ||
+ blendSrcBits == GLS_SRCBLEND_ONE ||
+ blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) {
+ stage->rgbGen = CGEN_IDENTITY_LIGHTING;
+ } else {
+ stage->rgbGen = CGEN_IDENTITY;
+ }
+ }
+
+
+ //
+ // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending
+ //
+ if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) &&
+ ( blendDstBits == GLS_DSTBLEND_ZERO ) )
+ {
+ blendDstBits = blendSrcBits = 0;
+ depthMaskBits = GLS_DEPTHMASK_TRUE;
+ }
+
+ // decide which agens we can skip
+ if ( stage->alphaGen == AGEN_IDENTITY ) {
+ if ( stage->rgbGen == CGEN_IDENTITY
+ || stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) {
+ stage->alphaGen = AGEN_SKIP;
+ }
+ }
+
+ //
+ // compute state bits
+ //
+ stage->stateBits = depthMaskBits |
+ blendSrcBits | blendDstBits |
+ atestBits |
+ depthFuncBits;
+
+ return true;
+}
+
+/*
+===============
+ParseDeform
+
+deformVertexes wave <spread> <waveform> <base> <amplitude> <phase> <frequency>
+deformVertexes normal <frequency> <amplitude>
+deformVertexes move <vector> <waveform> <base> <amplitude> <phase> <frequency>
+deformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed>
+deformVertexes projectionShadow
+deformVertexes autoSprite
+deformVertexes autoSprite2
+deformVertexes text[0-7]
+===============
+*/
+static void ParseDeform( char **text ) {
+ char *token;
+ deformStage_t *ds;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name );
+ return;
+ }
+
+ if ( shader.numDeforms == MAX_SHADER_DEFORMS ) {
+ ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name );
+ return;
+ }
+
+ ds = &shader.deforms[ shader.numDeforms ];
+ shader.numDeforms++;
+
+ if ( !Q_stricmp( token, "projectionShadow" ) ) {
+ ds->deformation = DEFORM_PROJECTION_SHADOW;
+ return;
+ }
+
+ if ( !Q_stricmp( token, "autosprite" ) ) {
+ ds->deformation = DEFORM_AUTOSPRITE;
+ return;
+ }
+
+ if ( !Q_stricmp( token, "autosprite2" ) ) {
+ ds->deformation = DEFORM_AUTOSPRITE2;
+ return;
+ }
+
+ if ( !Q_stricmpn( token, "text", 4 ) ) {
+ int n;
+
+ n = token[4] - '0';
+ if ( n < 0 || n > 7 ) {
+ n = 0;
+ }
+ ds->deformation = (deform_t)(DEFORM_TEXT0 + n);
+ return;
+ }
+
+ if ( !Q_stricmp( token, "bulge" ) ) {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->bulgeWidth = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->bulgeHeight = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->bulgeSpeed = atof( token );
+
+ ds->deformation = DEFORM_BULGE;
+ return;
+ }
+
+ if ( !Q_stricmp( token, "wave" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ return;
+ }
+
+ if ( atof( token ) != 0 )
+ {
+ ds->deformationSpread = 1.0f / atof( token );
+ }
+ else
+ {
+ ds->deformationSpread = 100.0f;
+ ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name );
+ }
+
+ ParseWaveForm( text, &ds->deformationWave );
+ ds->deformation = DEFORM_WAVE;
+ return;
+ }
+
+ if ( !Q_stricmp( token, "normal" ) )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->deformationWave.amplitude = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->deformationWave.frequency = atof( token );
+
+ ds->deformation = DEFORM_NORMALS;
+ return;
+ }
+
+ if ( !Q_stricmp( token, "move" ) ) {
+ int i;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ return;
+ }
+ ds->moveVector[i] = atof( token );
+ }
+
+ ParseWaveForm( text, &ds->deformationWave );
+ ds->deformation = DEFORM_MOVE;
+ return;
+ }
+
+ ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name );
+}
+
+
+/*
+===============
+ParseSkyParms
+
+skyParms <outerbox> <cloudheight> <innerbox>
+===============
+*/
+static void ParseSkyParms( char **text ) {
+ char *token;
+ static const char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+ char pathname[MAX_QPATH];
+ int i;
+ int/*imgFlags_t*/ imgFlags = IMGFLAG_MIPMAP | IMGFLAG_PICMIP;
+
+ // outerbox
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
+ return;
+ }
+ if ( strcmp( token, "-" ) ) {
+ for (i=0 ; i<6 ; i++) {
+ Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
+ , token, suf[i] );
+ shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags | IMGFLAG_CLAMPTOEDGE );
+
+ if ( !shader.sky.outerbox[i] ) {
+ shader.sky.outerbox[i] = tr.defaultImage;
+ }
+ }
+ }
+
+ // cloudheight
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
+ return;
+ }
+ shader.sky.cloudHeight = atof( token );
+ if ( !shader.sky.cloudHeight ) {
+ shader.sky.cloudHeight = 512;
+ }
+ R_InitSkyTexCoords( shader.sky.cloudHeight );
+
+
+ // innerbox
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
+ return;
+ }
+ if ( strcmp( token, "-" ) ) {
+ for (i=0 ; i<6 ; i++) {
+ Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
+ , token, suf[i] );
+ shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags );
+ if ( !shader.sky.innerbox[i] ) {
+ shader.sky.innerbox[i] = tr.defaultImage;
+ }
+ }
+ }
+
+ shader.isSky = true;
+}
+
+
+/*
+=================
+ParseSort
+=================
+*/
+void ParseSort( char **text ) {
+ char *token;
+
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 ) {
+ ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name );
+ return;
+ }
+
+ if ( !Q_stricmp( token, "portal" ) ) {
+ shader.sort = SS_PORTAL;
+ } else if ( !Q_stricmp( token, "sky" ) ) {
+ shader.sort = SS_ENVIRONMENT;
+ } else if ( !Q_stricmp( token, "opaque" ) ) {
+ shader.sort = SS_OPAQUE;
+ }else if ( !Q_stricmp( token, "decal" ) ) {
+ shader.sort = SS_DECAL;
+ } else if ( !Q_stricmp( token, "seeThrough" ) ) {
+ shader.sort = SS_SEE_THROUGH;
+ } else if ( !Q_stricmp( token, "banner" ) ) {
+ shader.sort = SS_BANNER;
+ } else if ( !Q_stricmp( token, "additive" ) ) {
+ shader.sort = SS_BLEND1;
+ } else if ( !Q_stricmp( token, "nearest" ) ) {
+ shader.sort = SS_NEAREST;
+ } else if ( !Q_stricmp( token, "underwater" ) ) {
+ shader.sort = SS_UNDERWATER;
+ } else {
+ shader.sort = atof( token );
+ }
+}
+
+
+
+// this table is also present in q3map
+
+typedef struct {
+ const char *name;
+ unsigned clearSolid, surfaceFlags, contents;
+} infoParm_t;
+
+infoParm_t infoParms[] = {
+ // server relevant contents
+ {"water", 1, 0, CONTENTS_WATER },
+ {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging
+ {"lava", 1, 0, CONTENTS_LAVA }, // very damaging
+ {"playerclip", 1, 0, CONTENTS_PLAYERCLIP },
+ {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP },
+ {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc)
+ {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag
+
+ // utility relevant attributes
+ {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes
+ {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces
+ {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp
+ {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas
+ {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas
+ {"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots
+ {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots
+
+ {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering
+ {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map
+ {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it
+ {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis
+ {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter
+
+ // server attributes
+ {"slick", 0, SURF_SLICK, 0 },
+ {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks
+ {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode
+ {"ladder", 0, SURF_LADDER, 0 },
+ {"nodamage", 0, SURF_NODAMAGE, 0 },
+ {"metalsteps", 0, SURF_METALSTEPS,0 },
+ {"flesh", 0, SURF_FLESH, 0 },
+ {"nosteps", 0, SURF_NOSTEPS, 0 },
+
+ // drawsurf attributes
+ {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap)
+ {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes
+ {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap
+ {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights
+ {"dust", 0, SURF_DUST, 0} // leave a dust trail when walking on this surface
+};
+
+
+/*
+===============
+ParseSurfaceParm
+
+surfaceparm <name>
+===============
+*/
+static void ParseSurfaceParm( char **text ) {
+ char *token;
+ int numInfoParms = ARRAY_LEN( infoParms );
+ int i;
+
+ token = COM_ParseExt( text, qfalse );
+ for ( i = 0 ; i < numInfoParms ; i++ ) {
+ if ( !Q_stricmp( token, infoParms[i].name ) ) {
+ shader.surfaceFlags |= infoParms[i].surfaceFlags;
+ shader.contentFlags |= infoParms[i].contents;
+#if 0
+ if ( infoParms[i].clearSolid ) {
+ si->contents &= ~CONTENTS_SOLID;
+ }
+#endif
+ break;
+ }
+ }
+}
+
+/*
+=================
+ParseShader
+
+The current text pointer is at the explicit text definition of the
+shader. Parse it into the global shader variable. Later functions
+will optimize it.
+=================
+*/
+static bool ParseShader( char **text )
+{
+ char *token;
+ int s;
+
+ s = 0;
+
+ token = COM_ParseExt( text, qtrue );
+ if ( token[0] != '{' )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name );
+ return false;
+ }
+
+ while ( 1 )
+ {
+ token = COM_ParseExt( text, qtrue );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name );
+ return false;
+ }
+
+ // end of shader definition
+ if ( token[0] == '}' )
+ {
+ break;
+ }
+ // stage definition
+ else if ( token[0] == '{' )
+ {
+ if ( s >= MAX_SHADER_STAGES ) {
+ ri.Printf( PRINT_WARNING, "WARNING: too many stages in shader %s (max is %i)\n", shader.name, MAX_SHADER_STAGES );
+ return false;
+ }
+
+ if ( !ParseStage( &stages[s], text ) )
+ {
+ return false;
+ }
+ stages[s].active = true;
+ s++;
+
+ continue;
+ }
+ // skip stuff that only the QuakeEdRadient needs
+ else if ( !Q_stricmpn( token, "qer", 3 ) ) {
+ SkipRestOfLine( text );
+ continue;
+ }
+ // sun parms
+ else if ( !Q_stricmp( token, "q3map_sun" ) || !Q_stricmp( token, "q3map_sunExt" ) || !Q_stricmp( token, "q3gl2_sun" ) ) {
+ float a, b;
+ bool isGL2Sun = false;
+
+ if (!Q_stricmp( token, "q3gl2_sun" ) && r_sunShadows->integer )
+ {
+ isGL2Sun = true;
+ tr.sunShadows = true;
+ }
+
+ token = COM_ParseExt( text, qfalse );
+ tr.sunLight[0] = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ tr.sunLight[1] = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ tr.sunLight[2] = atof( token );
+
+ VectorNormalize( tr.sunLight );
+
+ token = COM_ParseExt( text, qfalse );
+ a = atof( token );
+ VectorScale( tr.sunLight, a, tr.sunLight);
+
+ token = COM_ParseExt( text, qfalse );
+ a = atof( token );
+ a = a / 180 * M_PI;
+
+ token = COM_ParseExt( text, qfalse );
+ b = atof( token );
+ b = b / 180 * M_PI;
+
+ tr.sunDirection[0] = cos( a ) * cos( b );
+ tr.sunDirection[1] = sin( a ) * cos( b );
+ tr.sunDirection[2] = sin( b );
+
+ if (isGL2Sun)
+ {
+ token = COM_ParseExt( text, qfalse );
+ tr.sunShadowScale = atof(token);
+
+ // parse twice, since older shaders may include mapLightScale before sunShadowScale
+ token = COM_ParseExt( text, qfalse );
+ if (token[0])
+ tr.sunShadowScale = atof(token);
+ }
+
+ SkipRestOfLine( text );
+ continue;
+ }
+ // tonemap parms
+ else if ( !Q_stricmp( token, "q3gl2_tonemap" ) ) {
+ token = COM_ParseExt( text, qfalse );
+ tr.toneMinAvgMaxLevel[0] = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ tr.toneMinAvgMaxLevel[1] = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ tr.toneMinAvgMaxLevel[2] = atof( token );
+
+ token = COM_ParseExt( text, qfalse );
+ tr.autoExposureMinMax[0] = atof( token );
+ token = COM_ParseExt( text, qfalse );
+ tr.autoExposureMinMax[1] = atof( token );
+
+ SkipRestOfLine( text );
+ continue;
+ }
+ else if ( !Q_stricmp( token, "deformVertexes" ) ) {
+ ParseDeform( text );
+ continue;
+ }
+ else if ( !Q_stricmp( token, "tesssize" ) ) {
+ SkipRestOfLine( text );
+ continue;
+ }
+ else if ( !Q_stricmp( token, "clampTime" ) ) {
+ token = COM_ParseExt( text, qfalse );
+ if (token[0]) {
+ shader.clampTime = atof(token);
+ }
+ }
+ // skip stuff that only the q3map needs
+ else if ( !Q_stricmpn( token, "q3map", 5 ) ) {
+ SkipRestOfLine( text );
+ continue;
+ }
+ // skip stuff that only q3map or the server needs
+ else if ( !Q_stricmp( token, "surfaceParm" ) ) {
+ ParseSurfaceParm( text );
+ continue;
+ }
+ // no mip maps
+ else if ( !Q_stricmp( token, "nomipmaps" ) )
+ {
+ shader.noMipMaps = true;
+ shader.noPicMip = true;
+ continue;
+ }
+ // no picmip adjustment
+ else if ( !Q_stricmp( token, "nopicmip" ) )
+ {
+ shader.noPicMip = true;
+ continue;
+ }
+ // polygonOffset
+ else if ( !Q_stricmp( token, "polygonOffset" ) )
+ {
+ shader.polygonOffset = true;
+ continue;
+ }
+ // entityMergable, allowing sprite surfaces from multiple entities
+ // to be merged into one batch. This is a savings for smoke
+ // puffs and blood, but can't be used for anything where the
+ // shader calcs (not the surface function) reference the entity color or scroll
+ else if ( !Q_stricmp( token, "entityMergable" ) )
+ {
+ shader.entityMergable = true;
+ continue;
+ }
+ // fogParms
+ else if ( !Q_stricmp( token, "fogParms" ) )
+ {
+ if ( !ParseVector( text, 3, shader.fogParms.color ) ) {
+ return false;
+ }
+
+ if ( r_greyscale->integer )
+ {
+ float luminance;
+
+ luminance = LUMA( shader.fogParms.color[0], shader.fogParms.color[1], shader.fogParms.color[2] );
+ VectorSet( shader.fogParms.color, luminance, luminance, luminance );
+ }
+ else if ( r_greyscale->value )
+ {
+ float luminance;
+
+ luminance = LUMA( shader.fogParms.color[0], shader.fogParms.color[1], shader.fogParms.color[2] );
+ shader.fogParms.color[0] = LERP( shader.fogParms.color[0], luminance, r_greyscale->value );
+ shader.fogParms.color[1] = LERP( shader.fogParms.color[1], luminance, r_greyscale->value );
+ shader.fogParms.color[2] = LERP( shader.fogParms.color[2], luminance, r_greyscale->value );
+ }
+
+ token = COM_ParseExt( text, qfalse );
+ if ( !token[0] )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name );
+ continue;
+ }
+ shader.fogParms.depthForOpaque = atof( token );
+
+ // skip any old gradient directions
+ SkipRestOfLine( text );
+ continue;
+ }
+ // portal
+ else if ( !Q_stricmp(token, "portal") )
+ {
+ shader.sort = SS_PORTAL;
+ shader.isPortal = true;
+ continue;
+ }
+ // skyparms <cloudheight> <outerbox> <innerbox>
+ else if ( !Q_stricmp( token, "skyparms" ) )
+ {
+ ParseSkyParms( text );
+ continue;
+ }
+ // light <value> determines flaring in q3map, not needed here
+ else if ( !Q_stricmp(token, "light") )
+ {
+ COM_ParseExt( text, qfalse );
+ continue;
+ }
+ // cull <face>
+ else if ( !Q_stricmp( token, "cull") )
+ {
+ token = COM_ParseExt( text, qfalse );
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name );
+ continue;
+ }
+
+ if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) )
+ {
+ shader.cullType = CT_TWO_SIDED;
+ }
+ else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) )
+ {
+ shader.cullType = CT_BACK_SIDED;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name );
+ }
+ continue;
+ }
+ // sort
+ else if ( !Q_stricmp( token, "sort" ) )
+ {
+ ParseSort( text );
+ continue;
+ }
+ else
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name );
+ return false;
+ }
+ }
+
+ //
+ // ignore shaders that don't have any stages, unless it is a sky or fog
+ //
+ if ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) {
+ return false;
+ }
+
+ shader.explicitlyDefined = true;
+
+ return true;
+}
+
+/*
+========================================================================================
+
+SHADER OPTIMIZATION AND FOGGING
+
+========================================================================================
+*/
+
+/*
+===================
+ComputeStageIteratorFunc
+
+See if we can use on of the simple fastpath stage functions,
+otherwise set to the generic stage function
+===================
+*/
+static void ComputeStageIteratorFunc( void )
+{
+ shader.optimalStageIteratorFunc = RB_StageIteratorGeneric;
+
+ //
+ // see if this should go into the sky path
+ //
+ if ( shader.isSky )
+ {
+ shader.optimalStageIteratorFunc = RB_StageIteratorSky;
+ return;
+ }
+}
+
+/*
+===================
+ComputeVertexAttribs
+
+Check which vertex attributes we only need, so we
+don't need to submit/copy all of them.
+===================
+*/
+static void ComputeVertexAttribs(void)
+{
+ int i, stage;
+
+ // dlights always need ATTR_NORMAL
+ shader.vertexAttribs = ATTR_POSITION | ATTR_NORMAL;
+
+ // portals always need normals, for SurfIsOffscreen()
+ if (shader.isPortal)
+ {
+ shader.vertexAttribs |= ATTR_NORMAL;
+ }
+
+ if (shader.defaultShader)
+ {
+ shader.vertexAttribs |= ATTR_TEXCOORD;
+ return;
+ }
+
+ if(shader.numDeforms)
+ {
+ for ( i = 0; i < shader.numDeforms; i++)
+ {
+ deformStage_t *ds = &shader.deforms[i];
+
+ switch (ds->deformation)
+ {
+ case DEFORM_BULGE:
+ shader.vertexAttribs |= ATTR_NORMAL | ATTR_TEXCOORD;
+ break;
+
+ case DEFORM_AUTOSPRITE:
+ shader.vertexAttribs |= ATTR_NORMAL | ATTR_COLOR;
+ break;
+
+ case DEFORM_WAVE:
+ case DEFORM_NORMALS:
+ case DEFORM_TEXT0:
+ case DEFORM_TEXT1:
+ case DEFORM_TEXT2:
+ case DEFORM_TEXT3:
+ case DEFORM_TEXT4:
+ case DEFORM_TEXT5:
+ case DEFORM_TEXT6:
+ case DEFORM_TEXT7:
+ shader.vertexAttribs |= ATTR_NORMAL;
+ break;
+
+ default:
+ case DEFORM_NONE:
+ case DEFORM_MOVE:
+ case DEFORM_PROJECTION_SHADOW:
+ case DEFORM_AUTOSPRITE2:
+ break;
+ }
+ }
+ }
+
+ for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ )
+ {
+ shaderStage_t *pStage = &stages[stage];
+
+ if ( !pStage->active )
+ {
+ break;
+ }
+
+ if (pStage->glslShaderGroup == tr.lightallShader)
+ {
+ shader.vertexAttribs |= ATTR_NORMAL;
+
+ if ((pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && !(r_normalMapping->integer == 0 && r_specularMapping->integer == 0))
+ {
+ shader.vertexAttribs |= ATTR_TANGENT;
+ }
+
+ switch (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK)
+ {
+ case LIGHTDEF_USE_LIGHTMAP:
+ case LIGHTDEF_USE_LIGHT_VERTEX:
+ shader.vertexAttribs |= ATTR_LIGHTDIRECTION;
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
+ {
+ if ( pStage->bundle[i].image[0] == 0 )
+ {
+ continue;
+ }
+
+ switch(pStage->bundle[i].tcGen)
+ {
+ case TCGEN_TEXTURE:
+ shader.vertexAttribs |= ATTR_TEXCOORD;
+ break;
+ case TCGEN_LIGHTMAP:
+ shader.vertexAttribs |= ATTR_LIGHTCOORD;
+ break;
+ case TCGEN_ENVIRONMENT_MAPPED:
+ shader.vertexAttribs |= ATTR_NORMAL;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ switch(pStage->rgbGen)
+ {
+ case CGEN_EXACT_VERTEX:
+ case CGEN_VERTEX:
+ case CGEN_EXACT_VERTEX_LIT:
+ case CGEN_VERTEX_LIT:
+ case CGEN_ONE_MINUS_VERTEX:
+ shader.vertexAttribs |= ATTR_COLOR;
+ break;
+
+ case CGEN_LIGHTING_DIFFUSE:
+ shader.vertexAttribs |= ATTR_NORMAL;
+ break;
+
+ default:
+ break;
+ }
+
+ switch(pStage->alphaGen)
+ {
+ case AGEN_LIGHTING_SPECULAR:
+ shader.vertexAttribs |= ATTR_NORMAL;
+ break;
+
+ case AGEN_VERTEX:
+ case AGEN_ONE_MINUS_VERTEX:
+ shader.vertexAttribs |= ATTR_COLOR;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+
+static void CollapseStagesToLightall(shaderStage_t *diffuse,
+ shaderStage_t *normal, shaderStage_t *specular, shaderStage_t *lightmap,
+ bool useLightVector, bool useLightVertex, bool parallax, bool tcgen)
+{
+ int defs = 0;
+
+ //ri.Printf(PRINT_ALL, "shader %s has diffuse %s", shader.name, diffuse->bundle[0].image[0]->imgName);
+
+ // reuse diffuse, mark others inactive
+ diffuse->type = ST_GLSL;
+
+ if (lightmap)
+ {
+ //ri.Printf(PRINT_ALL, ", lightmap");
+ diffuse->bundle[TB_LIGHTMAP] = lightmap->bundle[0];
+ defs |= LIGHTDEF_USE_LIGHTMAP;
+ }
+ else if (useLightVector)
+ {
+ defs |= LIGHTDEF_USE_LIGHT_VECTOR;
+ }
+ else if (useLightVertex)
+ {
+ defs |= LIGHTDEF_USE_LIGHT_VERTEX;
+ }
+
+ if (r_deluxeMapping->integer && tr.worldDeluxeMapping && lightmap)
+ {
+ //ri.Printf(PRINT_ALL, ", deluxemap");
+ diffuse->bundle[TB_DELUXEMAP] = lightmap->bundle[0];
+ diffuse->bundle[TB_DELUXEMAP].image[0] = tr.deluxemaps[shader.lightmapIndex];
+ }
+
+ if (r_normalMapping->integer)
+ {
+ image_t *diffuseImg;
+ if (normal)
+ {
+ //ri.Printf(PRINT_ALL, ", normalmap %s", normal->bundle[0].image[0]->imgName);
+ diffuse->bundle[TB_NORMALMAP] = normal->bundle[0];
+ if (parallax && r_parallaxMapping->integer)
+ defs |= LIGHTDEF_USE_PARALLAXMAP;
+
+ VectorCopy4(normal->normalScale, diffuse->normalScale);
+ }
+ else if ((lightmap || useLightVector || useLightVertex) && (diffuseImg = diffuse->bundle[TB_DIFFUSEMAP].image[0]))
+ {
+ char normalName[MAX_QPATH];
+ image_t *normalImg;
+ int/*imgFlags_t*/ normalFlags = (diffuseImg->flags & ~IMGFLAG_GENNORMALMAP) | IMGFLAG_NOLIGHTSCALE;
+
+ // try a normalheight image first
+ COM_StripExtension(diffuseImg->imgName, normalName, MAX_QPATH);
+ Q_strcat(normalName, MAX_QPATH, "_nh");
+
+ normalImg = R_FindImageFile(normalName, IMGTYPE_NORMALHEIGHT, normalFlags);
+
+ if (normalImg)
+ {
+ parallax = true;
+ }
+ else
+ {
+ // try a normal image ("_n" suffix)
+ normalName[strlen(normalName) - 1] = '\0';
+ normalImg = R_FindImageFile(normalName, IMGTYPE_NORMAL, normalFlags);
+ }
+
+ if (normalImg)
+ {
+ diffuse->bundle[TB_NORMALMAP] = diffuse->bundle[0];
+ diffuse->bundle[TB_NORMALMAP].numImageAnimations = 0;
+ diffuse->bundle[TB_NORMALMAP].image[0] = normalImg;
+
+ if (parallax && r_parallaxMapping->integer)
+ defs |= LIGHTDEF_USE_PARALLAXMAP;
+
+ VectorSet4(diffuse->normalScale, r_baseNormalX->value, r_baseNormalY->value, 1.0f, r_baseParallax->value);
+ }
+ }
+ }
+
+ if (r_specularMapping->integer)
+ {
+ image_t *diffuseImg;
+ if (specular)
+ {
+ //ri.Printf(PRINT_ALL, ", specularmap %s", specular->bundle[0].image[0]->imgName);
+ diffuse->bundle[TB_SPECULARMAP] = specular->bundle[0];
+ VectorCopy4(specular->specularScale, diffuse->specularScale);
+ }
+ else if ((lightmap || useLightVector || useLightVertex) && (diffuseImg = diffuse->bundle[TB_DIFFUSEMAP].image[0]))
+ {
+ char specularName[MAX_QPATH];
+ image_t *specularImg;
+ int/*imgFlags_t*/ specularFlags = (diffuseImg->flags & ~IMGFLAG_GENNORMALMAP) | IMGFLAG_NOLIGHTSCALE;
+
+ COM_StripExtension(diffuseImg->imgName, specularName, MAX_QPATH);
+ Q_strcat(specularName, MAX_QPATH, "_s");
+
+ specularImg = R_FindImageFile(specularName, IMGTYPE_COLORALPHA, specularFlags);
+
+ if (specularImg)
+ {
+ diffuse->bundle[TB_SPECULARMAP] = diffuse->bundle[0];
+ diffuse->bundle[TB_SPECULARMAP].numImageAnimations = 0;
+ diffuse->bundle[TB_SPECULARMAP].image[0] = specularImg;
+
+ VectorSet4(diffuse->specularScale, 1.0f, 1.0f, 1.0f, 1.0f);
+ }
+ }
+ }
+
+ if (tcgen || diffuse->bundle[0].numTexMods)
+ {
+ defs |= LIGHTDEF_USE_TCGEN_AND_TCMOD;
+ }
+
+ //ri.Printf(PRINT_ALL, ".\n");
+
+ diffuse->glslShaderGroup = tr.lightallShader;
+ diffuse->glslShaderIndex = defs;
+}
+
+
+static int CollapseStagesToGLSL(void)
+{
+ int i, j, numStages;
+ bool skip = false;
+
+ // skip shaders with deforms
+ if (shader.numDeforms != 0)
+ {
+ skip = true;
+ }
+
+ if (!skip)
+ {
+ // if 2+ stages and first stage is lightmap, switch them
+ // this makes it easier for the later bits to process
+ if (stages[0].active && stages[0].bundle[0].tcGen == TCGEN_LIGHTMAP && stages[1].active)
+ {
+ int blendBits = stages[1].stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
+
+ if (blendBits == (GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO)
+ || blendBits == (GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR))
+ {
+ int stateBits0 = stages[0].stateBits;
+ int stateBits1 = stages[1].stateBits;
+ shaderStage_t swapStage;
+
+ swapStage = stages[0];
+ stages[0] = stages[1];
+ stages[1] = swapStage;
+
+ stages[0].stateBits = stateBits0;
+ stages[1].stateBits = stateBits1;
+ }
+ }
+ }
+
+ if (!skip)
+ {
+ // scan for shaders that aren't supported
+ for (i = 0; i < MAX_SHADER_STAGES; i++)
+ {
+ shaderStage_t *pStage = &stages[i];
+
+ if (!pStage->active)
+ continue;
+
+ if (pStage->adjustColorsForFog)
+ {
+ skip = true;
+ break;
+ }
+
+ if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP)
+ {
+ int blendBits = pStage->stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
+
+ if (blendBits != (GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO)
+ && blendBits != (GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR))
+ {
+ skip = true;
+ break;
+ }
+ }
+
+ switch(pStage->bundle[0].tcGen)
+ {
+ case TCGEN_TEXTURE:
+ case TCGEN_LIGHTMAP:
+ case TCGEN_ENVIRONMENT_MAPPED:
+ case TCGEN_VECTOR:
+ break;
+ default:
+ skip = true;
+ break;
+ }
+
+ switch(pStage->alphaGen)
+ {
+ case AGEN_LIGHTING_SPECULAR:
+ case AGEN_PORTAL:
+ skip = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (!skip)
+ {
+ for (i = 0; i < MAX_SHADER_STAGES; i++)
+ {
+ shaderStage_t *pStage = &stages[i];
+ shaderStage_t *diffuse, *normal, *specular, *lightmap;
+ bool parallax, tcgen, diffuselit, vertexlit;
+
+ if (!pStage->active)
+ continue;
+
+ // skip normal and specular maps
+ if (pStage->type != ST_COLORMAP)
+ continue;
+
+ // skip lightmaps
+ if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP)
+ continue;
+
+ diffuse = pStage;
+ normal = NULL;
+ parallax = false;
+ specular = NULL;
+ lightmap = NULL;
+
+ // we have a diffuse map, find matching normal, specular, and lightmap
+ for (j = i + 1; j < MAX_SHADER_STAGES; j++)
+ {
+ shaderStage_t *pStage2 = &stages[j];
+
+ if (!pStage2->active)
+ continue;
+
+ switch(pStage2->type)
+ {
+ case ST_NORMALMAP:
+ if (!normal)
+ {
+ normal = pStage2;
+ }
+ break;
+
+ case ST_NORMALPARALLAXMAP:
+ if (!normal)
+ {
+ normal = pStage2;
+ parallax = true;
+ }
+ break;
+
+ case ST_SPECULARMAP:
+ if (!specular)
+ {
+ specular = pStage2;
+ }
+ break;
+
+ case ST_COLORMAP:
+ if (pStage2->bundle[0].tcGen == TCGEN_LIGHTMAP)
+ {
+ lightmap = pStage2;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ tcgen = false;
+ if (diffuse->bundle[0].tcGen == TCGEN_ENVIRONMENT_MAPPED
+ || diffuse->bundle[0].tcGen == TCGEN_LIGHTMAP
+ || diffuse->bundle[0].tcGen == TCGEN_VECTOR)
+ {
+ tcgen = true;
+ }
+
+ diffuselit = false;
+ if (diffuse->rgbGen == CGEN_LIGHTING_DIFFUSE)
+ {
+ diffuselit = true;
+ }
+
+ vertexlit = false;
+ if (diffuse->rgbGen == CGEN_VERTEX_LIT || diffuse->rgbGen == CGEN_EXACT_VERTEX_LIT)
+ {
+ vertexlit = true;
+ }
+
+ CollapseStagesToLightall(diffuse, normal, specular, lightmap, diffuselit, vertexlit, parallax, tcgen);
+ }
+
+ // deactivate lightmap stages
+ for (i = 0; i < MAX_SHADER_STAGES; i++)
+ {
+ shaderStage_t *pStage = &stages[i];
+
+ if (!pStage->active)
+ continue;
+
+ if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP)
+ {
+ pStage->active = false;
+ }
+ }
+ }
+
+ // deactivate normal and specular stages
+ for (i = 0; i < MAX_SHADER_STAGES; i++)
+ {
+ shaderStage_t *pStage = &stages[i];
+
+ if (!pStage->active)
+ continue;
+
+ if (pStage->type == ST_NORMALMAP)
+ {
+ pStage->active = false;
+ }
+
+ if (pStage->type == ST_NORMALPARALLAXMAP)
+ {
+ pStage->active = false;
+ }
+
+ if (pStage->type == ST_SPECULARMAP)
+ {
+ pStage->active = false;
+ }
+ }
+
+ // remove inactive stages
+ numStages = 0;
+ for (i = 0; i < MAX_SHADER_STAGES; i++)
+ {
+ if (!stages[i].active)
+ continue;
+
+ if (i == numStages)
+ {
+ numStages++;
+ continue;
+ }
+
+ stages[numStages] = stages[i];
+ stages[i].active = false;
+ numStages++;
+ }
+
+ // convert any remaining lightmap stages to a lighting pass with a white texture
+ // only do this with r_sunlightMode non-zero, as it's only for correct shadows.
+ if (r_sunlightMode->integer && shader.numDeforms == 0)
+ {
+ for (i = 0; i < MAX_SHADER_STAGES; i++)
+ {
+ shaderStage_t *pStage = &stages[i];
+
+ if (!pStage->active)
+ continue;
+
+ if (pStage->adjustColorsForFog)
+ continue;
+
+ if (pStage->bundle[TB_DIFFUSEMAP].tcGen == TCGEN_LIGHTMAP)
+ {
+ pStage->glslShaderGroup = tr.lightallShader;
+ pStage->glslShaderIndex = LIGHTDEF_USE_LIGHTMAP;
+ pStage->bundle[TB_LIGHTMAP] = pStage->bundle[TB_DIFFUSEMAP];
+ pStage->bundle[TB_DIFFUSEMAP].image[0] = tr.whiteImage;
+ pStage->bundle[TB_DIFFUSEMAP].isLightmap = false;
+ pStage->bundle[TB_DIFFUSEMAP].tcGen = TCGEN_TEXTURE;
+ }
+ }
+ }
+
+ // convert any remaining lightingdiffuse stages to a lighting pass
+ if (shader.numDeforms == 0)
+ {
+ for (i = 0; i < MAX_SHADER_STAGES; i++)
+ {
+ shaderStage_t *pStage = &stages[i];
+
+ if (!pStage->active)
+ continue;
+
+ if (pStage->adjustColorsForFog)
+ continue;
+
+ if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE)
+ {
+ pStage->glslShaderGroup = tr.lightallShader;
+ pStage->glslShaderIndex = LIGHTDEF_USE_LIGHT_VECTOR;
+
+ if (pStage->bundle[0].tcGen != TCGEN_TEXTURE || pStage->bundle[0].numTexMods != 0)
+ pStage->glslShaderIndex |= LIGHTDEF_USE_TCGEN_AND_TCMOD;
+ }
+ }
+ }
+
+ return numStages;
+}
+
+/*
+=============
+
+FixRenderCommandList
+https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
+Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated
+but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces
+to be rendered with bad shaders. To fix this, need to go through all render commands and fix
+sortedIndex.
+==============
+*/
+static void FixRenderCommandList( int newShader ) {
+ renderCommandList_t *cmdList = &backEndData->commands;
+
+ if( cmdList ) {
+ const void *curCmd = cmdList->cmds;
+
+ while ( 1 ) {
+ curCmd = PADP(curCmd, sizeof(void *));
+
+ switch ( *(const int *)curCmd ) {
+ case RC_SET_COLOR:
+ {
+ const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd;
+ curCmd = (const void *)(sc_cmd + 1);
+ break;
+ }
+ case RC_STRETCH_PIC:
+ {
+ const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd;
+ curCmd = (const void *)(sp_cmd + 1);
+ break;
+ }
+ case RC_DRAW_SURFS:
+ {
+ int i;
+ drawSurf_t *drawSurf;
+ shader_t *shader;
+ int fogNum;
+ int entityNum;
+ int dlightMap;
+ int pshadowMap;
+ int sortedIndex;
+ const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd;
+
+ for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) {
+ R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap, &pshadowMap );
+ sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1));
+ if( sortedIndex >= newShader ) {
+ sortedIndex++;
+ drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | ( (int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap;
+ }
+ }
+ curCmd = (const void *)(ds_cmd + 1);
+ break;
+ }
+ case RC_DRAW_BUFFER:
+ {
+ const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd;
+ curCmd = (const void *)(db_cmd + 1);
+ break;
+ }
+ case RC_SWAP_BUFFERS:
+ {
+ const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd;
+ curCmd = (const void *)(sb_cmd + 1);
+ break;
+ }
+ case RC_END_OF_LIST:
+ default:
+ return;
+ }
+ }
+ }
+}
+
+/*
+==============
+SortNewShader
+
+Positions the most recently created shader in the tr.sortedShaders[]
+array so that the shader->sort key is sorted reletive to the other
+shaders.
+
+Sets shader->sortedIndex
+==============
+*/
+static void SortNewShader( void ) {
+ int i;
+ float sort;
+ shader_t *newShader;
+
+ newShader = tr.shaders[ tr.numShaders - 1 ];
+ sort = newShader->sort;
+
+ for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) {
+ if ( tr.sortedShaders[ i ]->sort <= sort ) {
+ break;
+ }
+ tr.sortedShaders[i+1] = tr.sortedShaders[i];
+ tr.sortedShaders[i+1]->sortedIndex++;
+ }
+
+ // Arnout: fix rendercommandlist
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
+ FixRenderCommandList( i+1 );
+
+ newShader->sortedIndex = i+1;
+ tr.sortedShaders[i+1] = newShader;
+}
+
+
+/*
+====================
+GeneratePermanentShader
+====================
+*/
+static shader_t *GeneratePermanentShader( void ) {
+ shader_t *newShader;
+ int i, b;
+ int size, hash;
+
+ if ( tr.numShaders == MAX_SHADERS ) {
+ ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n");
+ return tr.defaultShader;
+ }
+
+ newShader = (shader_t*)ri.Hunk_Alloc( sizeof( shader_t ), h_low );
+
+ *newShader = shader;
+
+ if ( shader.sort <= SS_OPAQUE ) {
+ newShader->fogPass = FP_EQUAL;
+ } else if ( shader.contentFlags & CONTENTS_FOG ) {
+ newShader->fogPass = FP_LE;
+ }
+
+ tr.shaders[ tr.numShaders ] = newShader;
+ newShader->index = tr.numShaders;
+
+ tr.sortedShaders[ tr.numShaders ] = newShader;
+ newShader->sortedIndex = tr.numShaders;
+
+ tr.numShaders++;
+
+ for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) {
+ if ( !stages[i].active ) {
+ break;
+ }
+ newShader->stages[i] = (shaderStage_t*)ri.Hunk_Alloc( sizeof( stages[i] ), h_low );
+ *newShader->stages[i] = stages[i];
+
+ for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) {
+ size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t );
+ newShader->stages[i]->bundle[b].texMods = (texModInfo_t*)ri.Hunk_Alloc( size, h_low );
+ Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size );
+ }
+ }
+
+ SortNewShader();
+
+ hash = generateHashValue(newShader->name, FILE_HASH_SIZE);
+ newShader->next = hashTable[hash];
+ hashTable[hash] = newShader;
+
+ return newShader;
+}
+
+/*
+=================
+VertexLightingCollapse
+
+If vertex lighting is enabled, only render a single
+pass, trying to guess which is the correct one to best aproximate
+what it is supposed to look like.
+=================
+*/
+static void VertexLightingCollapse( void ) {
+ int stage;
+ shaderStage_t *bestStage;
+ int bestImageRank;
+ int rank;
+
+ // if we aren't opaque, just use the first pass
+ if ( shader.sort == SS_OPAQUE ) {
+
+ // pick the best texture for the single pass
+ bestStage = &stages[0];
+ bestImageRank = -999999;
+
+ for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {
+ shaderStage_t *pStage = &stages[stage];
+
+ if ( !pStage->active ) {
+ break;
+ }
+ rank = 0;
+
+ if ( pStage->bundle[0].isLightmap ) {
+ rank -= 100;
+ }
+ if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) {
+ rank -= 5;
+ }
+ if ( pStage->bundle[0].numTexMods ) {
+ rank -= 5;
+ }
+ if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) {
+ rank -= 3;
+ }
+
+ if ( rank > bestImageRank ) {
+ bestImageRank = rank;
+ bestStage = pStage;
+ }
+ }
+
+ stages[0].bundle[0] = bestStage->bundle[0];
+ stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
+ stages[0].stateBits |= GLS_DEPTHMASK_TRUE;
+ if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
+ stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
+ } else {
+ stages[0].rgbGen = CGEN_EXACT_VERTEX;
+ }
+ stages[0].alphaGen = AGEN_SKIP;
+ } else {
+ // don't use a lightmap (tesla coils)
+ if ( stages[0].bundle[0].isLightmap ) {
+ stages[0] = stages[1];
+ }
+
+ // if we were in a cross-fade cgen, hack it to normal
+ if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) {
+ stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
+ }
+ if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH )
+ && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) {
+ stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
+ }
+ if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH )
+ && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) {
+ stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
+ }
+ }
+
+ for ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) {
+ shaderStage_t *pStage = &stages[stage];
+
+ if ( !pStage->active ) {
+ break;
+ }
+
+ Com_Memset( pStage, 0, sizeof( *pStage ) );
+ }
+}
+
+/*
+===============
+InitShader
+===============
+*/
+static void InitShader( const char *name, int lightmapIndex ) {
+ int i;
+
+ // clear the global shader
+ Com_Memset( &shader, 0, sizeof( shader ) );
+ Com_Memset( &stages, 0, sizeof( stages ) );
+
+ Q_strncpyz( shader.name, name, sizeof( shader.name ) );
+ shader.lightmapIndex = lightmapIndex;
+
+ for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
+ stages[i].bundle[0].texMods = texMods[i];
+
+ // default normal/specular
+ VectorSet4(stages[i].normalScale, 0.0f, 0.0f, 0.0f, 0.0f);
+ if (r_pbr->integer)
+ {
+ stages[i].specularScale[0] = r_baseGloss->value;
+ }
+ else
+ {
+ stages[i].specularScale[0] =
+ stages[i].specularScale[1] =
+ stages[i].specularScale[2] = r_baseSpecular->value;
+ stages[i].specularScale[3] = r_baseGloss->value;
+ }
+ }
+}
+
+/*
+=========================
+FinishShader
+
+Returns a freshly allocated shader with all the needed info
+from the current global working shader
+=========================
+*/
+static shader_t *FinishShader( void ) {
+ int stage;
+ bool hasLightmapStage;
+ bool vertexLightmap;
+
+ hasLightmapStage = false;
+ vertexLightmap = false;
+
+ //
+ // set sky stuff appropriate
+ //
+ if ( shader.isSky ) {
+ shader.sort = SS_ENVIRONMENT;
+ }
+
+ //
+ // set polygon offset
+ //
+ if ( shader.polygonOffset && !shader.sort ) {
+ shader.sort = SS_DECAL;
+ }
+
+ //
+ // set appropriate stage information
+ //
+ for ( stage = 0; stage < MAX_SHADER_STAGES; ) {
+ shaderStage_t *pStage = &stages[stage];
+
+ if ( !pStage->active ) {
+ break;
+ }
+
+ // check for a missing texture
+ if ( !pStage->bundle[0].image[0] ) {
+ ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name );
+ pStage->active = false;
+ stage++;
+ continue;
+ }
+
+ //
+ // ditch this stage if it's detail and detail textures are disabled
+ //
+ if ( pStage->isDetail && !r_detailTextures->integer )
+ {
+ int index;
+
+ for(index = stage + 1; index < MAX_SHADER_STAGES; index++)
+ {
+ if(!stages[index].active)
+ break;
+ }
+
+ if(index < MAX_SHADER_STAGES)
+ memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage));
+ else
+ {
+ if(stage + 1 < MAX_SHADER_STAGES)
+ memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage - 1));
+
+ Com_Memset(&stages[index - 1], 0, sizeof(*stages));
+ }
+
+ continue;
+ }
+
+ //
+ // default texture coordinate generation
+ //
+ if ( pStage->bundle[0].isLightmap ) {
+ if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
+ pStage->bundle[0].tcGen = TCGEN_LIGHTMAP;
+ }
+ hasLightmapStage = true;
+ } else {
+ if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
+ pStage->bundle[0].tcGen = TCGEN_TEXTURE;
+ }
+ }
+
+
+ // not a true lightmap but we want to leave existing
+ // behaviour in place and not print out a warning
+ //if (pStage->rgbGen == CGEN_VERTEX) {
+ // vertexLightmap = true;
+ //}
+
+
+
+ //
+ // determine sort order and fog color adjustment
+ //
+ if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) &&
+ ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) {
+ int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS;
+ int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS;
+
+ // fog color adjustment only works for blend modes that have a contribution
+ // that aproaches 0 as the modulate values aproach 0 --
+ // GL_ONE, GL_ONE
+ // GL_ZERO, GL_ONE_MINUS_SRC_COLOR
+ // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
+
+ // modulate, additive
+ if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) ||
+ ( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) {
+ pStage->adjustColorsForFog = ACFF_MODULATE_RGB;
+ }
+ // strict blend
+ else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
+ {
+ pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA;
+ }
+ // premultiplied alpha
+ else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
+ {
+ pStage->adjustColorsForFog = ACFF_MODULATE_RGBA;
+ } else {
+ // we can't adjust this one correctly, so it won't be exactly correct in fog
+ }
+
+ // don't screw with sort order if this is a portal or environment
+ if ( !shader.sort ) {
+ // see through item, like a grill or grate
+ if ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) {
+ shader.sort = SS_SEE_THROUGH;
+ } else {
+ shader.sort = SS_BLEND0;
+ }
+ }
+ }
+
+ stage++;
+ }
+
+ // there are times when you will need to manually apply a sort to
+ // opaque alpha tested shaders that have later blend passes
+ if ( !shader.sort ) {
+ shader.sort = SS_OPAQUE;
+ }
+
+ //
+ // if we are in r_vertexLight mode, never use a lightmap texture
+ //
+ if ( stage > 1 && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) {
+ VertexLightingCollapse();
+ hasLightmapStage = false;
+ }
+
+ //
+ // look for multitexture potential
+ //
+ stage = CollapseStagesToGLSL();
+
+ if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) {
+ if (vertexLightmap) {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name );
+ } else {
+ ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name );
+ // Don't set this, it will just add duplicate shaders to the hash
+ //shader.lightmapIndex = LIGHTMAP_NONE;
+ }
+ }
+
+
+ //
+ // compute number of passes
+ //
+ shader.numUnfoggedPasses = stage;
+
+ // fogonly shaders don't have any normal passes
+ if (stage == 0 && !shader.isSky)
+ shader.sort = SS_FOG;
+
+ // determine which stage iterator function is appropriate
+ ComputeStageIteratorFunc();
+
+ // determine which vertex attributes this shader needs
+ ComputeVertexAttribs();
+
+ return GeneratePermanentShader();
+}
+
+//========================================================================================
+
+/*
+====================
+FindShaderInShaderText
+
+Scans the combined text description of all the shader files for
+the given shader name.
+
+return NULL if not found
+
+If found, it will return a valid shader
+=====================
+*/
+static char *FindShaderInShaderText( const char *shadername ) {
+
+ char *token, *p;
+
+ int i, hash;
+
+ hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH);
+
+ if(shaderTextHashTable[hash])
+ {
+ for (i = 0; shaderTextHashTable[hash][i]; i++)
+ {
+ p = shaderTextHashTable[hash][i];
+ token = COM_ParseExt(&p, qtrue);
+
+ if(!Q_stricmp(token, shadername))
+ return p;
+ }
+ }
+
+ p = s_shaderText;
+
+ if ( !p ) {
+ return NULL;
+ }
+
+ // look for label
+ while ( 1 ) {
+ token = COM_ParseExt( &p, qtrue );
+ if ( token[0] == 0 ) {
+ break;
+ }
+
+ if ( !Q_stricmp( token, shadername ) ) {
+ return p;
+ }
+ else {
+ // skip the definition
+ SkipBracedSection( &p, 0 );
+ }
+ }
+
+ return NULL;
+}
+
+
+/*
+==================
+R_FindShaderByName
+
+Will always return a valid shader, but it might be the
+default shader if the real one can't be found.
+==================
+*/
+shader_t *R_FindShaderByName( const char *name ) {
+ char strippedName[MAX_QPATH];
+ int hash;
+ shader_t *sh;
+
+ if ( (name==NULL) || (name[0] == 0) ) {
+ return tr.defaultShader;
+ }
+
+ COM_StripExtension(name, strippedName, sizeof(strippedName));
+
+ hash = generateHashValue(strippedName, FILE_HASH_SIZE);
+
+ //
+ // see if the shader is already loaded
+ //
+ for (sh=hashTable[hash]; sh; sh=sh->next) {
+ // NOTE: if there was no shader or image available with the name strippedName
+ // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
+ // have to check all default shaders otherwise for every call to R_FindShader
+ // with that same strippedName a new default shader is created.
+ if (Q_stricmp(sh->name, strippedName) == 0) {
+ // match found
+ return sh;
+ }
+ }
+
+ return tr.defaultShader;
+}
+
+
+/*
+===============
+R_FindShader
+
+Will always return a valid shader, but it might be the
+default shader if the real one can't be found.
+
+In the interest of not requiring an explicit shader text entry to
+be defined for every single image used in the game, three default
+shader behaviors can be auto-created for any image:
+
+If lightmapIndex == LIGHTMAP_NONE, then the image will have
+dynamic diffuse lighting applied to it, as apropriate for most
+entity skin surfaces.
+
+If lightmapIndex == LIGHTMAP_2D, then the image will be used
+for 2D rendering unless an explicit shader is found
+
+If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use
+the vertex rgba modulate values, as apropriate for misc_model
+pre-lit surfaces.
+
+Other lightmapIndex values will have a lightmap stage created
+and src*dest blending applied with the texture, as apropriate for
+most world construction surfaces.
+
+===============
+*/
+shader_t *R_FindShader( const char *name, int lightmapIndex, bool mipRawImage ) {
+ char strippedName[MAX_QPATH];
+ int hash;
+ char *shaderText;
+ image_t *image;
+ shader_t *sh;
+
+ if ( name[0] == 0 ) {
+ return tr.defaultShader;
+ }
+
+ // use (fullbright) vertex lighting if the bsp file doesn't have
+ // lightmaps
+ if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) {
+ lightmapIndex = LIGHTMAP_BY_VERTEX;
+ } else if ( lightmapIndex < LIGHTMAP_2D ) {
+ // negative lightmap indexes cause stray pointers (think tr.lightmaps[lightmapIndex])
+ ri.Printf( PRINT_WARNING, "WARNING: shader '%s' has invalid lightmap index of %d\n", name, lightmapIndex );
+ lightmapIndex = LIGHTMAP_BY_VERTEX;
+ }
+
+ COM_StripExtension(name, strippedName, sizeof(strippedName));
+
+ hash = generateHashValue(strippedName, FILE_HASH_SIZE);
+
+ //
+ // see if the shader is already loaded
+ //
+ for (sh = hashTable[hash]; sh; sh = sh->next) {
+ // NOTE: if there was no shader or image available with the name strippedName
+ // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
+ // have to check all default shaders otherwise for every call to R_FindShader
+ // with that same strippedName a new default shader is created.
+ if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&
+ !Q_stricmp(sh->name, strippedName)) {
+ // match found
+ return sh;
+ }
+ }
+
+ InitShader( strippedName, lightmapIndex );
+
+ //
+ // attempt to define shader from an explicit parameter file
+ //
+ shaderText = FindShaderInShaderText( strippedName );
+ if ( shaderText ) {
+ // enable this when building a pak file to get a global list
+ // of all explicit shaders
+ if ( r_printShaders->integer ) {
+ ri.Printf( PRINT_ALL, "*SHADER* %s\n", name );
+ }
+
+ if ( !ParseShader( &shaderText ) ) {
+ // had errors, so use default shader
+ shader.defaultShader = true;
+ }
+ sh = FinishShader();
+ return sh;
+ }
+
+
+ //
+ // if not defined in the in-memory shader descriptions,
+ // look for a single supported image file
+ //
+ {
+ int/*imgFlags_t*/ flags;
+
+ flags = IMGFLAG_NONE;
+
+ if (mipRawImage)
+ {
+ flags |= IMGFLAG_MIPMAP | IMGFLAG_PICMIP;
+
+ if (r_genNormalMaps->integer)
+ flags |= IMGFLAG_GENNORMALMAP;
+ }
+ else
+ {
+ flags |= IMGFLAG_CLAMPTOEDGE;
+ }
+
+ image = R_FindImageFile( name, IMGTYPE_COLORALPHA, flags );
+ if ( !image ) {
+ ri.Printf( PRINT_DEVELOPER, "Couldn't find image file for shader %s\n", name );
+ shader.defaultShader = true;
+ return FinishShader();
+ }
+ }
+
+ //
+ // create the default shading commands
+ //
+ if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
+ // dynamic colors at vertexes
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
+ stages[0].stateBits = GLS_DEFAULT;
+ } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
+ // explicit colors at vertexes
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_EXACT_VERTEX;
+ stages[0].alphaGen = AGEN_SKIP;
+ stages[0].stateBits = GLS_DEFAULT;
+ } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
+ // GUI elements
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_VERTEX;
+ stages[0].alphaGen = AGEN_VERTEX;
+ stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
+ GLS_SRCBLEND_SRC_ALPHA |
+ GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
+ } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
+ // fullbright level
+ stages[0].bundle[0].image[0] = tr.whiteImage;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
+ stages[0].stateBits = GLS_DEFAULT;
+
+ stages[1].bundle[0].image[0] = image;
+ stages[1].active = true;
+ stages[1].rgbGen = CGEN_IDENTITY;
+ stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
+ } else {
+ // two pass lightmap
+ stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
+ stages[0].bundle[0].isLightmap = true;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
+ // for identitylight
+ stages[0].stateBits = GLS_DEFAULT;
+
+ stages[1].bundle[0].image[0] = image;
+ stages[1].active = true;
+ stages[1].rgbGen = CGEN_IDENTITY;
+ stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
+ }
+
+ return FinishShader();
+}
+
+
+qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, bool mipRawImage) {
+ int hash;
+ shader_t *sh;
+
+ hash = generateHashValue(name, FILE_HASH_SIZE);
+
+ // probably not necessary since this function
+ // only gets called from tr_font.c with lightmapIndex == LIGHTMAP_2D
+ // but better safe than sorry.
+ if ( lightmapIndex >= tr.numLightmaps ) {
+ lightmapIndex = LIGHTMAP_WHITEIMAGE;
+ }
+
+ //
+ // see if the shader is already loaded
+ //
+ for (sh=hashTable[hash]; sh; sh=sh->next) {
+ // NOTE: if there was no shader or image available with the name strippedName
+ // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
+ // have to check all default shaders otherwise for every call to R_FindShader
+ // with that same strippedName a new default shader is created.
+ if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&
+ // index by name
+ !Q_stricmp(sh->name, name)) {
+ // match found
+ return sh->index;
+ }
+ }
+
+ InitShader( name, lightmapIndex );
+
+ //
+ // create the default shading commands
+ //
+ if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
+ // dynamic colors at vertexes
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
+ stages[0].stateBits = GLS_DEFAULT;
+ } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
+ // explicit colors at vertexes
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_EXACT_VERTEX;
+ stages[0].alphaGen = AGEN_SKIP;
+ stages[0].stateBits = GLS_DEFAULT;
+ } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
+ // GUI elements
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_VERTEX;
+ stages[0].alphaGen = AGEN_VERTEX;
+ stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
+ GLS_SRCBLEND_SRC_ALPHA |
+ GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
+ } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
+ // fullbright level
+ stages[0].bundle[0].image[0] = tr.whiteImage;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
+ stages[0].stateBits = GLS_DEFAULT;
+
+ stages[1].bundle[0].image[0] = image;
+ stages[1].active = true;
+ stages[1].rgbGen = CGEN_IDENTITY;
+ stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
+ } else {
+ // two pass lightmap
+ stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
+ stages[0].bundle[0].isLightmap = true;
+ stages[0].active = true;
+ stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
+ // for identitylight
+ stages[0].stateBits = GLS_DEFAULT;
+
+ stages[1].bundle[0].image[0] = image;
+ stages[1].active = true;
+ stages[1].rgbGen = CGEN_IDENTITY;
+ stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
+ }
+
+ sh = FinishShader();
+ return sh->index;
+}
+
+
+/*
+====================
+RE_RegisterShader
+
+This is the exported shader entry point for the rest of the system
+It will always return an index that will be valid.
+
+This should really only be used for explicit shaders, because there is no
+way to ask for different implicit lighting modes (vertex, lightmap, etc)
+====================
+*/
+qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) {
+ shader_t *sh;
+
+ if ( strlen( name ) >= MAX_QPATH ) {
+ ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
+ return 0;
+ }
+
+ sh = R_FindShader( name, lightmapIndex, true );
+
+ // we want to return 0 if the shader failed to
+ // load for some reason, but R_FindShader should
+ // still keep a name allocated for it, so if
+ // something calls RE_RegisterShader again with
+ // the same name, we don't try looking for it again
+ if ( sh->defaultShader ) {
+ return 0;
+ }
+
+ return sh->index;
+}
+
+
+/*
+====================
+RE_RegisterShader
+
+This is the exported shader entry point for the rest of the system
+It will always return an index that will be valid.
+
+This should really only be used for explicit shaders, because there is no
+way to ask for different implicit lighting modes (vertex, lightmap, etc)
+====================
+*/
+qhandle_t RE_RegisterShader( const char *name ) {
+ shader_t *sh;
+
+ if ( strlen( name ) >= MAX_QPATH ) {
+ ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
+ return 0;
+ }
+
+ sh = R_FindShader( name, LIGHTMAP_2D, true );
+
+ // we want to return 0 if the shader failed to
+ // load for some reason, but R_FindShader should
+ // still keep a name allocated for it, so if
+ // something calls RE_RegisterShader again with
+ // the same name, we don't try looking for it again
+ if ( sh->defaultShader ) {
+ return 0;
+ }
+
+ return sh->index;
+}
+
+
+/*
+====================
+RE_RegisterShaderNoMip
+
+For menu graphics that should never be picmiped
+====================
+*/
+qhandle_t RE_RegisterShaderNoMip( const char *name ) {
+ shader_t *sh;
+
+ if ( strlen( name ) >= MAX_QPATH ) {
+ ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
+ return 0;
+ }
+
+ sh = R_FindShader( name, LIGHTMAP_2D, false );
+
+ // we want to return 0 if the shader failed to
+ // load for some reason, but R_FindShader should
+ // still keep a name allocated for it, so if
+ // something calls RE_RegisterShader again with
+ // the same name, we don't try looking for it again
+ if ( sh->defaultShader ) {
+ return 0;
+ }
+
+ return sh->index;
+}
+
+/*
+====================
+R_GetShaderByHandle
+
+When a handle is passed in by another module, this range checks
+it and returns a valid (possibly default) shader_t to be used internally.
+====================
+*/
+shader_t *R_GetShaderByHandle( qhandle_t hShader ) {
+ if ( hShader < 0 ) {
+ ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
+ return tr.defaultShader;
+ }
+ if ( hShader >= tr.numShaders ) {
+ ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
+ return tr.defaultShader;
+ }
+ return tr.shaders[hShader];
+}
+
+/*
+===============
+R_ShaderList_f
+
+Dump information on all valid shaders to the console
+A second parameter will cause it to print in sorted order
+===============
+*/
+void R_ShaderList_f (void) {
+ int i;
+ int count;
+ shader_t *shader;
+
+ ri.Printf (PRINT_ALL, "-----------------------\n");
+
+ count = 0;
+ for ( i = 0 ; i < tr.numShaders ; i++ ) {
+ if ( ri.Cmd_Argc() > 1 ) {
+ shader = tr.sortedShaders[i];
+ } else {
+ shader = tr.shaders[i];
+ }
+
+ ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses );
+
+ if (shader->lightmapIndex >= 0 ) {
+ ri.Printf (PRINT_ALL, "L ");
+ } else {
+ ri.Printf (PRINT_ALL, " ");
+ }
+ if ( shader->explicitlyDefined ) {
+ ri.Printf( PRINT_ALL, "E " );
+ } else {
+ ri.Printf( PRINT_ALL, " " );
+ }
+
+ if ( shader->optimalStageIteratorFunc == RB_StageIteratorGeneric ) {
+ ri.Printf( PRINT_ALL, "gen " );
+ } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorSky ) {
+ ri.Printf( PRINT_ALL, "sky " );
+ } else {
+ ri.Printf( PRINT_ALL, " " );
+ }
+
+ if ( shader->defaultShader ) {
+ ri.Printf (PRINT_ALL, ": %s (DEFAULTED)\n", shader->name);
+ } else {
+ ri.Printf (PRINT_ALL, ": %s\n", shader->name);
+ }
+ count++;
+ }
+ ri.Printf (PRINT_ALL, "%i total shaders\n", count);
+ ri.Printf (PRINT_ALL, "------------------\n");
+}
+
+/*
+====================
+ScanAndLoadShaderFiles
+
+Finds and loads all .shader files, combining them into
+a single large text block that can be scanned for shader names
+=====================
+*/
+#define MAX_SHADER_FILES 4096
+static void ScanAndLoadShaderFiles( void )
+{
+ char **shaderFiles;
+ char *buffers[MAX_SHADER_FILES] = {NULL};
+ char *p;
+ int numShaderFiles;
+ int i;
+ char *oldp, *token, *hashMem, *textEnd;
+ int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size;
+ char shaderName[MAX_QPATH];
+ int shaderLine;
+
+ long sum = 0, summand;
+ // scan for shader files
+ shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles );
+
+ if ( !shaderFiles || !numShaderFiles )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" );
+ return;
+ }
+
+ if ( numShaderFiles > MAX_SHADER_FILES ) {
+ numShaderFiles = MAX_SHADER_FILES;
+ }
+
+ // load and parse shader files
+ for ( i = 0; i < numShaderFiles; i++ )
+ {
+ char filename[MAX_QPATH];
+
+ // look for a .mtr file first
+ {
+ char *ext;
+ Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
+ if ( (ext = strrchr(filename, '.')) )
+ {
+ strcpy(ext, ".mtr");
+ }
+
+ if ( ri.FS_ReadFile( filename, NULL ) <= 0 )
+ {
+ Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
+ }
+ }
+
+ ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename );
+ summand = ri.FS_ReadFile( filename, (void **)&buffers[i] );
+
+ if ( !buffers[i] )
+ ri.Error( ERR_DROP, "Couldn't load %s", filename );
+
+ // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders.
+ p = buffers[i];
+ COM_BeginParseSession(filename);
+ while(1)
+ {
+ token = COM_ParseExt(&p, qtrue);
+
+ if(!*token)
+ break;
+
+ Q_strncpyz(shaderName, token, sizeof(shaderName));
+ shaderLine = COM_GetCurrentParseLine();
+
+ token = COM_ParseExt(&p, qtrue);
+ if(token[0] != '{' || token[1] != '\0')
+ {
+ ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing opening brace",
+ filename, shaderName, shaderLine);
+ if (token[0])
+ {
+ ri.Printf(PRINT_WARNING, " (found \"%s\" on line %d)", token, COM_GetCurrentParseLine());
+ }
+ ri.Printf(PRINT_WARNING, ".\n");
+ ri.FS_FreeFile(buffers[i]);
+ buffers[i] = NULL;
+ break;
+ }
+
+ if(!SkipBracedSection(&p, 1))
+ {
+ ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n",
+ filename, shaderName, shaderLine);
+ ri.FS_FreeFile(buffers[i]);
+ buffers[i] = NULL;
+ break;
+ }
+ }
+
+
+ if (buffers[i])
+ sum += summand;
+ }
+
+ // build single large buffer
+ s_shaderText = (char*)ri.Hunk_Alloc( sum + numShaderFiles*2, h_low );
+ s_shaderText[ 0 ] = '\0';
+ textEnd = s_shaderText;
+
+ // free in reverse order, so the temp files are all dumped
+ for ( i = numShaderFiles - 1; i >= 0 ; i-- )
+ {
+ if ( !buffers[i] )
+ continue;
+
+ strcat( textEnd, buffers[i] );
+ strcat( textEnd, "\n" );
+ textEnd += strlen( textEnd );
+ ri.FS_FreeFile( buffers[i] );
+ }
+
+ COM_Compress( s_shaderText );
+
+ // free up memory
+ ri.FS_FreeFileList( shaderFiles );
+
+ Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
+ size = 0;
+
+ p = s_shaderText;
+ // look for shader names
+ while ( 1 ) {
+ token = COM_ParseExt( &p, qtrue );
+ if ( token[0] == 0 ) {
+ break;
+ }
+
+ hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
+ shaderTextHashTableSizes[hash]++;
+ size++;
+ SkipBracedSection(&p, 0);
+ }
+
+ size += MAX_SHADERTEXT_HASH;
+
+ hashMem = (char*)ri.Hunk_Alloc( size * sizeof(char *), h_low );
+
+ for (i = 0; i < MAX_SHADERTEXT_HASH; i++) {
+ shaderTextHashTable[i] = (char **) hashMem;
+ hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *));
+ }
+
+ Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
+
+ p = s_shaderText;
+ // look for shader names
+ while ( 1 ) {
+ oldp = p;
+ token = COM_ParseExt( &p, qtrue );
+ if ( token[0] == 0 ) {
+ break;
+ }
+
+ hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
+ shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp;
+
+ SkipBracedSection(&p, 0);
+ }
+
+ return;
+
+}
+
+
+/*
+====================
+CreateInternalShaders
+====================
+*/
+static void CreateInternalShaders( void ) {
+ tr.numShaders = 0;
+
+ // init the default shader
+ InitShader( "<default>", LIGHTMAP_NONE );
+ stages[0].bundle[0].image[0] = tr.defaultImage;
+ stages[0].active = true;
+ stages[0].stateBits = GLS_DEFAULT;
+ tr.defaultShader = FinishShader();
+
+ // shadow shader is just a marker
+ Q_strncpyz( shader.name, "<stencil shadow>", sizeof( shader.name ) );
+ shader.sort = SS_STENCIL_SHADOW;
+ tr.shadowShader = FinishShader();
+}
+
+static void CreateExternalShaders( void ) {
+ tr.projectionShadowShader = R_FindShader( "projectionShadow", LIGHTMAP_NONE, true );
+ tr.flareShader = R_FindShader( "flareShader", LIGHTMAP_NONE, true );
+
+ // Hack to make fogging work correctly on flares. Fog colors are calculated
+ // in tr_flare.c already.
+ if(!tr.flareShader->defaultShader)
+ {
+ int index;
+
+ for(index = 0; index < tr.flareShader->numUnfoggedPasses; index++)
+ {
+ tr.flareShader->stages[index]->adjustColorsForFog = ACFF_NONE;
+ tr.flareShader->stages[index]->stateBits |= GLS_DEPTHTEST_DISABLE;
+ }
+ }
+
+ tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, true );
+
+ tr.sunFlareShader = R_FindShader( "gfx/2d/sunflare", LIGHTMAP_NONE, true);
+
+ // HACK: if sunflare is missing, make one using the flare image or dlight image
+ if (tr.sunFlareShader->defaultShader)
+ {
+ image_t *image;
+
+ if (!tr.flareShader->defaultShader && tr.flareShader->stages[0] && tr.flareShader->stages[0]->bundle[0].image[0])
+ image = tr.flareShader->stages[0]->bundle[0].image[0];
+ else
+ image = tr.dlightImage;
+
+ InitShader( "gfx/2d/sunflare", LIGHTMAP_NONE );
+ stages[0].bundle[0].image[0] = image;
+ stages[0].active = true;
+ stages[0].stateBits = GLS_DEFAULT;
+ tr.sunFlareShader = FinishShader();
+ }
+
+}
+
+/*
+==================
+R_InitShaders
+==================
+*/
+void R_InitShaders( void ) {
+ ri.Printf( PRINT_ALL, "Initializing Shaders\n" );
+
+ Com_Memset(hashTable, 0, sizeof(hashTable));
+
+ CreateInternalShaders();
+
+ ScanAndLoadShaderFiles();
+
+ CreateExternalShaders();
+}
diff --git a/src/renderergl2/tr_shadows.cpp b/src/renderergl2/tr_shadows.cpp
new file mode 100644
index 0000000..a602c31
--- /dev/null
+++ b/src/renderergl2/tr_shadows.cpp
@@ -0,0 +1,327 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "tr_local.h"
+
+
+/*
+
+ for a projection shadow:
+
+ point[x] += light vector * ( z - shadow plane )
+ point[y] +=
+ point[z] = shadow plane
+
+ 1 0 light[x] / light[z]
+
+*/
+
+typedef struct {
+ int i2;
+ int facing;
+} edgeDef_t;
+
+#define MAX_EDGE_DEFS 32
+
+static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];
+static int numEdgeDefs[SHADER_MAX_VERTEXES];
+static int facing[SHADER_MAX_INDEXES/3];
+static vec3_t shadowXyz[SHADER_MAX_VERTEXES];
+
+void R_AddEdgeDef( int i1, int i2, int facing ) {
+ int c;
+
+ c = numEdgeDefs[ i1 ];
+ if ( c == MAX_EDGE_DEFS ) {
+ return; // overflow
+ }
+ edgeDefs[ i1 ][ c ].i2 = i2;
+ edgeDefs[ i1 ][ c ].facing = facing;
+
+ numEdgeDefs[ i1 ]++;
+}
+
+void R_RenderShadowEdges( void ) {
+ int i;
+
+#if 0
+ int numTris;
+
+ // dumb way -- render every triangle's edges
+ numTris = tess.numIndexes / 3;
+
+ for ( i = 0 ; i < numTris ; i++ ) {
+ int i1, i2, i3;
+
+ if ( !facing[i] ) {
+ continue;
+ }
+
+ i1 = tess.indexes[ i*3 + 0 ];
+ i2 = tess.indexes[ i*3 + 1 ];
+ i3 = tess.indexes[ i*3 + 2 ];
+
+ qglBegin( GL_TRIANGLE_STRIP );
+ qglVertex3fv( tess.xyz[ i1 ] );
+ qglVertex3fv( shadowXyz[ i1 ] );
+ qglVertex3fv( tess.xyz[ i2 ] );
+ qglVertex3fv( shadowXyz[ i2 ] );
+ qglVertex3fv( tess.xyz[ i3 ] );
+ qglVertex3fv( shadowXyz[ i3 ] );
+ qglVertex3fv( tess.xyz[ i1 ] );
+ qglVertex3fv( shadowXyz[ i1 ] );
+ qglEnd();
+ }
+#else
+ int c, c2;
+ int j, k;
+ int i2;
+ int c_edges, c_rejected;
+ int hit[2];
+
+ // an edge is NOT a silhouette edge if its face doesn't face the light,
+ // or if it has a reverse paired edge that also faces the light.
+ // A well behaved polyhedron would have exactly two faces for each edge,
+ // but lots of models have dangling edges or overfanned edges
+ c_edges = 0;
+ c_rejected = 0;
+
+ for ( i = 0 ; i < tess.numVertexes ; i++ ) {
+ c = numEdgeDefs[ i ];
+ for ( j = 0 ; j < c ; j++ ) {
+ if ( !edgeDefs[ i ][ j ].facing ) {
+ continue;
+ }
+
+ hit[0] = 0;
+ hit[1] = 0;
+
+ i2 = edgeDefs[ i ][ j ].i2;
+ c2 = numEdgeDefs[ i2 ];
+ for ( k = 0 ; k < c2 ; k++ ) {
+ if ( edgeDefs[ i2 ][ k ].i2 == i ) {
+ hit[ edgeDefs[ i2 ][ k ].facing ]++;
+ }
+ }
+
+ // if it doesn't share the edge with another front facing
+ // triangle, it is a sil edge
+ if ( hit[ 1 ] == 0 ) {
+ qglBegin( GL_TRIANGLE_STRIP );
+ qglVertex3fv( tess.xyz[ i ] );
+ qglVertex3fv( shadowXyz[ i ] );
+ qglVertex3fv( tess.xyz[ i2 ] );
+ qglVertex3fv( shadowXyz[ i2 ] );
+ qglEnd();
+ c_edges++;
+ } else {
+ c_rejected++;
+ }
+ }
+ }
+#endif
+}
+
+/*
+=================
+RB_ShadowTessEnd
+
+triangleFromEdge[ v1 ][ v2 ]
+
+
+ set triangle from edge( v1, v2, tri )
+ if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) {
+ }
+=================
+*/
+void RB_ShadowTessEnd( void ) {
+ int i;
+ int numTris;
+ vec3_t lightDir;
+ GLboolean rgba[4];
+
+ if ( glConfig.stencilBits < 4 ) {
+ return;
+ }
+
+ VectorCopy( backEnd.currentEntity->modelLightDir, lightDir );
+
+ // project vertexes away from light direction
+ for ( i = 0 ; i < tess.numVertexes ; i++ ) {
+ VectorMA( tess.xyz[i], -512, lightDir, shadowXyz[i] );
+ }
+
+ // decide which triangles face the light
+ Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes );
+
+ numTris = tess.numIndexes / 3;
+ for ( i = 0 ; i < numTris ; i++ ) {
+ int i1, i2, i3;
+ vec3_t d1, d2, normal;
+ float *v1, *v2, *v3;
+ float d;
+
+ i1 = tess.indexes[ i*3 + 0 ];
+ i2 = tess.indexes[ i*3 + 1 ];
+ i3 = tess.indexes[ i*3 + 2 ];
+
+ v1 = tess.xyz[ i1 ];
+ v2 = tess.xyz[ i2 ];
+ v3 = tess.xyz[ i3 ];
+
+ VectorSubtract( v2, v1, d1 );
+ VectorSubtract( v3, v1, d2 );
+ CrossProduct( d1, d2, normal );
+
+ d = DotProduct( normal, lightDir );
+ if ( d > 0 ) {
+ facing[ i ] = 1;
+ } else {
+ facing[ i ] = 0;
+ }
+
+ // create the edges
+ R_AddEdgeDef( i1, i2, facing[ i ] );
+ R_AddEdgeDef( i2, i3, facing[ i ] );
+ R_AddEdgeDef( i3, i1, facing[ i ] );
+ }
+
+ // draw the silhouette edges
+
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
+ GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
+ qglColor3f( 0.2f, 0.2f, 0.2f );
+
+ // don't write to the color buffer
+ qglGetBooleanv(GL_COLOR_WRITEMASK, rgba);
+ qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
+
+ qglEnable( GL_STENCIL_TEST );
+ qglStencilFunc( GL_ALWAYS, 1, 255 );
+
+ GL_Cull( CT_BACK_SIDED );
+ qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
+
+ R_RenderShadowEdges();
+
+ GL_Cull( CT_FRONT_SIDED );
+ qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
+
+ R_RenderShadowEdges();
+
+
+ // reenable writing to the color buffer
+ qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]);
+}
+
+
+/*
+=================
+RB_ShadowFinish
+
+Darken everything that is is a shadow volume.
+We have to delay this until everything has been shadowed,
+because otherwise shadows from different body parts would
+overlap and double darken.
+=================
+*/
+void RB_ShadowFinish( void ) {
+ if ( r_shadows->integer != 2 ) {
+ return;
+ }
+ if ( glConfig.stencilBits < 4 ) {
+ return;
+ }
+ qglEnable( GL_STENCIL_TEST );
+ qglStencilFunc( GL_NOTEQUAL, 0, 255 );
+
+ qglDisable (GL_CLIP_PLANE0);
+ GL_Cull( CT_TWO_SIDED );
+
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
+
+ qglLoadIdentity ();
+
+ qglColor3f( 0.6f, 0.6f, 0.6f );
+ GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO );
+
+// qglColor3f( 1, 0, 0 );
+// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
+
+ qglBegin( GL_QUADS );
+ qglVertex3f( -100, 100, -10 );
+ qglVertex3f( 100, 100, -10 );
+ qglVertex3f( 100, -100, -10 );
+ qglVertex3f( -100, -100, -10 );
+ qglEnd ();
+
+ qglColor4f(1,1,1,1);
+ qglDisable( GL_STENCIL_TEST );
+}
+
+
+/*
+=================
+RB_ProjectionShadowDeform
+
+=================
+*/
+void RB_ProjectionShadowDeform( void ) {
+ float *xyz;
+ int i;
+ float h;
+ vec3_t ground;
+ vec3_t light;
+ float groundDist;
+ float d;
+ vec3_t lightDir;
+
+ xyz = ( float * ) tess.xyz;
+
+ ground[0] = backEnd.orientation.axis[0][2];
+ ground[1] = backEnd.orientation.axis[1][2];
+ ground[2] = backEnd.orientation.axis[2][2];
+
+ groundDist = backEnd.orientation.origin[2] - backEnd.currentEntity->e.shadowPlane;
+
+ VectorCopy( backEnd.currentEntity->modelLightDir, lightDir );
+ d = DotProduct( lightDir, ground );
+ // don't let the shadows get too long or go negative
+ if ( d < 0.5 ) {
+ VectorMA( lightDir, (0.5 - d), ground, lightDir );
+ d = DotProduct( lightDir, ground );
+ }
+ d = 1.0 / d;
+
+ light[0] = lightDir[0] * d;
+ light[1] = lightDir[1] * d;
+ light[2] = lightDir[2] * d;
+
+ for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
+ h = DotProduct( xyz, ground ) + groundDist;
+
+ xyz[0] -= light[0] * h;
+ xyz[1] -= light[1] * h;
+ xyz[2] -= light[2] * h;
+ }
+}
diff --git a/src/renderergl2/tr_sky.cpp b/src/renderergl2/tr_sky.cpp
new file mode 100644
index 0000000..98fb451
--- /dev/null
+++ b/src/renderergl2/tr_sky.cpp
@@ -0,0 +1,904 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_sky.c
+#include "tr_local.h"
+
+#define SKY_SUBDIVISIONS 8
+#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2)
+
+static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
+static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
+
+/*
+===================================================================================
+
+POLYGON TO BOX SIDE PROJECTION
+
+===================================================================================
+*/
+
+static vec3_t sky_clip[6] =
+{
+ {1,1,0},
+ {1,-1,0},
+ {0,-1,1},
+ {0,1,1},
+ {1,0,1},
+ {-1,0,1}
+};
+
+static float sky_mins[2][6], sky_maxs[2][6];
+static float sky_min, sky_max;
+
+/*
+================
+AddSkyPolygon
+================
+*/
+static void AddSkyPolygon (int nump, vec3_t vecs)
+{
+ int i,j;
+ vec3_t v, av;
+ float s, t, dv;
+ int axis;
+ float *vp;
+ // s = [0]/[2], t = [1]/[2]
+ static int vec_to_st[6][3] =
+ {
+ {-2,3,1},
+ {2,3,-1},
+
+ {1,3,2},
+ {-1,3,-2},
+
+ {-2,-1,3},
+ {-2,1,-3}
+
+ // {-1,2,3},
+ // {1,2,-3}
+ };
+
+ // decide which face it maps to
+ VectorCopy (vec3_origin, v);
+ for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
+ {
+ VectorAdd (vp, v, v);
+ }
+ av[0] = fabs(v[0]);
+ av[1] = fabs(v[1]);
+ av[2] = fabs(v[2]);
+ if (av[0] > av[1] && av[0] > av[2])
+ {
+ if (v[0] < 0)
+ axis = 1;
+ else
+ axis = 0;
+ }
+ else if (av[1] > av[2] && av[1] > av[0])
+ {
+ if (v[1] < 0)
+ axis = 3;
+ else
+ axis = 2;
+ }
+ else
+ {
+ if (v[2] < 0)
+ axis = 5;
+ else
+ axis = 4;
+ }
+
+ // project new texture coords
+ for (i=0 ; i<nump ; i++, vecs+=3)
+ {
+ j = vec_to_st[axis][2];
+ if (j > 0)
+ dv = vecs[j - 1];
+ else
+ dv = -vecs[-j - 1];
+ if (dv < 0.001)
+ continue; // don't divide by zero
+ j = vec_to_st[axis][0];
+ if (j < 0)
+ s = -vecs[-j -1] / dv;
+ else
+ s = vecs[j-1] / dv;
+ j = vec_to_st[axis][1];
+ if (j < 0)
+ t = -vecs[-j -1] / dv;
+ else
+ t = vecs[j-1] / dv;
+
+ if (s < sky_mins[0][axis])
+ sky_mins[0][axis] = s;
+ if (t < sky_mins[1][axis])
+ sky_mins[1][axis] = t;
+ if (s > sky_maxs[0][axis])
+ sky_maxs[0][axis] = s;
+ if (t > sky_maxs[1][axis])
+ sky_maxs[1][axis] = t;
+ }
+}
+
+#define ON_EPSILON 0.1f // point on plane side epsilon
+#define MAX_CLIP_VERTS 64
+/*
+================
+ClipSkyPolygon
+================
+*/
+static void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
+{
+ float *norm;
+ float *v;
+ bool front, back;
+ float d, e;
+ float dists[MAX_CLIP_VERTS];
+ int sides[MAX_CLIP_VERTS];
+ vec3_t newv[2][MAX_CLIP_VERTS];
+ int newc[2];
+ int i, j;
+
+ if (nump > MAX_CLIP_VERTS-2)
+ ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS");
+ if (stage == 6)
+ { // fully clipped, so draw it
+ AddSkyPolygon (nump, vecs);
+ return;
+ }
+
+ front = back = false;
+ norm = sky_clip[stage];
+ for (i=0, v = vecs ; i<nump ; i++, v+=3)
+ {
+ d = DotProduct (v, norm);
+ if (d > ON_EPSILON)
+ {
+ front = true;
+ sides[i] = SIDE_FRONT;
+ }
+ else if (d < -ON_EPSILON)
+ {
+ back = true;
+ sides[i] = SIDE_BACK;
+ }
+ else
+ sides[i] = SIDE_ON;
+ dists[i] = d;
+ }
+
+ if (!front || !back)
+ { // not clipped
+ ClipSkyPolygon (nump, vecs, stage+1);
+ return;
+ }
+
+ // clip it
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+ VectorCopy (vecs, (vecs+(i*3)) );
+ newc[0] = newc[1] = 0;
+
+ for (i=0, v = vecs ; i<nump ; i++, v+=3)
+ {
+ switch (sides[i])
+ {
+ case SIDE_FRONT:
+ VectorCopy (v, newv[0][newc[0]]);
+ newc[0]++;
+ break;
+ case SIDE_BACK:
+ VectorCopy (v, newv[1][newc[1]]);
+ newc[1]++;
+ break;
+ case SIDE_ON:
+ VectorCopy (v, newv[0][newc[0]]);
+ newc[0]++;
+ VectorCopy (v, newv[1][newc[1]]);
+ newc[1]++;
+ break;
+ }
+
+ if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ d = dists[i] / (dists[i] - dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ {
+ e = v[j] + d*(v[j+3] - v[j]);
+ newv[0][newc[0]][j] = e;
+ newv[1][newc[1]][j] = e;
+ }
+ newc[0]++;
+ newc[1]++;
+ }
+
+ // continue
+ ClipSkyPolygon (newc[0], newv[0][0], stage+1);
+ ClipSkyPolygon (newc[1], newv[1][0], stage+1);
+}
+
+/*
+==============
+ClearSkyBox
+==============
+*/
+static void ClearSkyBox (void) {
+ int i;
+
+ for (i=0 ; i<6 ; i++) {
+ sky_mins[0][i] = sky_mins[1][i] = 9999;
+ sky_maxs[0][i] = sky_maxs[1][i] = -9999;
+ }
+}
+
+/*
+================
+RB_ClipSkyPolygons
+================
+*/
+void RB_ClipSkyPolygons( shaderCommands_t *input )
+{
+ vec3_t p[5]; // need one extra point for clipping
+ int i, j;
+
+ ClearSkyBox();
+
+ for ( i = 0; i < input->numIndexes; i += 3 )
+ {
+ for (j = 0 ; j < 3 ; j++)
+ {
+ VectorSubtract( input->xyz[input->indexes[i+j]],
+ backEnd.viewParms.orientation.origin,
+ p[j] );
+ }
+ ClipSkyPolygon( 3, p[0], 0 );
+ }
+}
+
+/*
+===================================================================================
+
+CLOUD VERTEX GENERATION
+
+===================================================================================
+*/
+
+/*
+** MakeSkyVec
+**
+** Parms: s, t range from -1 to 1
+*/
+static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ )
+{
+ // 1 = s, 2 = t, 3 = 2048
+ static int st_to_vec[6][3] =
+ {
+ {3,-1,2},
+ {-3,1,2},
+
+ {1,3,2},
+ {-1,-3,2},
+
+ {-2,-1,3}, // 0 degrees yaw, look straight up
+ {2,-1,-3} // look straight down
+ };
+
+ vec3_t b;
+ int j, k;
+ float boxSize;
+
+ boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
+ b[0] = s*boxSize;
+ b[1] = t*boxSize;
+ b[2] = boxSize;
+
+ for (j=0 ; j<3 ; j++)
+ {
+ k = st_to_vec[axis][j];
+ if (k < 0)
+ {
+ outXYZ[j] = -b[-k - 1];
+ }
+ else
+ {
+ outXYZ[j] = b[k - 1];
+ }
+ }
+
+ // avoid bilerp seam
+ s = (s+1)*0.5;
+ t = (t+1)*0.5;
+ if (s < sky_min)
+ {
+ s = sky_min;
+ }
+ else if (s > sky_max)
+ {
+ s = sky_max;
+ }
+
+ if (t < sky_min)
+ {
+ t = sky_min;
+ }
+ else if (t > sky_max)
+ {
+ t = sky_max;
+ }
+
+ t = 1.0 - t;
+
+
+ if ( outSt )
+ {
+ outSt[0] = s;
+ outSt[1] = t;
+ }
+}
+
+static int sky_texorder[6] = {0,2,1,3,4,5};
+static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
+static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
+
+static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
+{
+ int s, t;
+ int firstVertex = tess.numVertexes;
+ //int firstIndex = tess.numIndexes;
+ vec4_t color;
+
+ //tess.numVertexes = 0;
+ //tess.numIndexes = 0;
+ tess.firstIndex = tess.numIndexes;
+
+ GL_BindToTMU( image, TB_COLORMAP );
+ GL_Cull( CT_TWO_SIDED );
+
+ for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
+ {
+ for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
+ {
+ tess.xyz[tess.numVertexes][0] = s_skyPoints[t][s][0];
+ tess.xyz[tess.numVertexes][1] = s_skyPoints[t][s][1];
+ tess.xyz[tess.numVertexes][2] = s_skyPoints[t][s][2];
+ tess.xyz[tess.numVertexes][3] = 1.0;
+
+ tess.texCoords[tess.numVertexes][0] = s_skyTexCoords[t][s][0];
+ tess.texCoords[tess.numVertexes][1] = s_skyTexCoords[t][s][1];
+
+ tess.numVertexes++;
+
+ if(tess.numVertexes >= SHADER_MAX_VERTEXES)
+ {
+ ri.Error(ERR_DROP, "SHADER_MAX_VERTEXES hit in DrawSkySideVBO()");
+ }
+ }
+ }
+
+ for ( t = 0; t < maxs[1] - mins[1]; t++ )
+ {
+ for ( s = 0; s < maxs[0] - mins[0]; s++ )
+ {
+ if (tess.numIndexes + 6 >= SHADER_MAX_INDEXES)
+ {
+ ri.Error(ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySideVBO()");
+ }
+
+ tess.indexes[tess.numIndexes++] = s + t * (maxs[0] - mins[0] + 1) + firstVertex;
+ tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
+ tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex;
+
+ tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex;
+ tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
+ tess.indexes[tess.numIndexes++] = (s + 1) + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
+ }
+ }
+
+ // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function
+ RB_UpdateTessVao(ATTR_POSITION | ATTR_TEXCOORD);
+/*
+ {
+ shaderProgram_t *sp = &tr.textureColorShader;
+
+ GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD);
+ GLSL_BindProgram(sp);
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+
+ color[0] =
+ color[1] =
+ color[2] = tr.identityLight;
+ color[3] = 1.0f;
+ GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color);
+ }
+*/
+ {
+ shaderProgram_t *sp = &tr.lightallShader[0];
+ vec4_t vector;
+
+ GLSL_BindProgram(sp);
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+
+ color[0] =
+ color[1] =
+ color[2] =
+ color[3] = 1.0f;
+ GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color);
+
+ color[0] =
+ color[1] =
+ color[2] =
+ color[3] = 0.0f;
+ GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, color);
+
+ VectorSet4(vector, 1.0, 0.0, 0.0, 1.0);
+ GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector);
+
+ VectorSet4(vector, 0.0, 0.0, 0.0, 0.0);
+ GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector);
+
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
+ }
+
+ R_DrawElements(tess.numIndexes - tess.firstIndex, tess.firstIndex);
+
+ //qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(glIndex_t)));
+
+ //R_BindNullVBO();
+ //R_BindNullIBO();
+
+ tess.numIndexes = tess.firstIndex;
+ tess.numVertexes = firstVertex;
+ tess.firstIndex = 0;
+}
+
+static void DrawSkyBox( shader_t *shader )
+{
+ int i;
+
+ sky_min = 0;
+ sky_max = 1;
+
+ Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );
+
+ for (i=0 ; i<6 ; i++)
+ {
+ int sky_mins_subd[2], sky_maxs_subd[2];
+ int s, t;
+
+ sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+
+ if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
+ ( sky_mins[1][i] >= sky_maxs[1][i] ) )
+ {
+ continue;
+ }
+
+ sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;
+ sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;
+ sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;
+ sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;
+
+ if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
+ if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
+
+ if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
+ if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
+
+ //
+ // iterate through the subdivisions
+ //
+ for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
+ {
+ for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
+ {
+ MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ i,
+ s_skyTexCoords[t][s],
+ s_skyPoints[t][s] );
+ }
+ }
+
+ DrawSkySide( shader->sky.outerbox[sky_texorder[i]],
+ sky_mins_subd,
+ sky_maxs_subd );
+ }
+
+}
+
+static void FillCloudySkySide( const int mins[2], const int maxs[2], bool addIndexes )
+{
+ int s, t;
+ int vertexStart = tess.numVertexes;
+ int tHeight, sWidth;
+
+ tHeight = maxs[1] - mins[1] + 1;
+ sWidth = maxs[0] - mins[0] + 1;
+
+ for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
+ {
+ for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
+ {
+ VectorAdd( s_skyPoints[t][s], backEnd.viewParms.orientation.origin, tess.xyz[tess.numVertexes] );
+ tess.texCoords[tess.numVertexes][0] = s_skyTexCoords[t][s][0];
+ tess.texCoords[tess.numVertexes][1] = s_skyTexCoords[t][s][1];
+
+ tess.numVertexes++;
+
+ if ( tess.numVertexes >= SHADER_MAX_VERTEXES )
+ {
+ ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()" );
+ }
+ }
+ }
+
+ // only add indexes for one pass, otherwise it would draw multiple times for each pass
+ if ( addIndexes ) {
+ for ( t = 0; t < tHeight-1; t++ )
+ {
+ for ( s = 0; s < sWidth-1; s++ )
+ {
+ tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );
+ tess.numIndexes++;
+ tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
+ tess.numIndexes++;
+ tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
+ tess.numIndexes++;
+
+ tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
+ tess.numIndexes++;
+ tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );
+ tess.numIndexes++;
+ tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
+ tess.numIndexes++;
+ }
+ }
+ }
+}
+
+static void FillCloudBox( const shader_t *shader, int stage )
+{
+ int i;
+
+ for ( i =0; i < 6; i++ )
+ {
+ int sky_mins_subd[2], sky_maxs_subd[2];
+ int s, t;
+ float MIN_T;
+
+ if ( 1 ) // FIXME? shader->sky.fullClouds )
+ {
+ MIN_T = -HALF_SKY_SUBDIVISIONS;
+
+ // still don't want to draw the bottom, even if fullClouds
+ if ( i == 5 )
+ continue;
+ }
+ else
+ {
+ switch( i )
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ MIN_T = -1;
+ break;
+ case 5:
+ // don't draw clouds beneath you
+ continue;
+ case 4: // top
+ default:
+ MIN_T = -HALF_SKY_SUBDIVISIONS;
+ break;
+ }
+ }
+
+ sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+ sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
+
+ if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
+ ( sky_mins[1][i] >= sky_maxs[1][i] ) )
+ {
+ continue;
+ }
+
+ sky_mins_subd[0] = static_cast<int>(sky_mins[0][i] * HALF_SKY_SUBDIVISIONS);
+ sky_mins_subd[1] = static_cast<int>(sky_mins[1][i] * HALF_SKY_SUBDIVISIONS);
+ sky_maxs_subd[0] = static_cast<int>(sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS);
+ sky_maxs_subd[1] = static_cast<int>(sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS);
+
+ if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
+ if ( sky_mins_subd[1] < MIN_T )
+ sky_mins_subd[1] = MIN_T;
+ else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
+ sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
+
+ if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
+ else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
+ if ( sky_maxs_subd[1] < MIN_T )
+ sky_maxs_subd[1] = MIN_T;
+ else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
+ sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
+
+ //
+ // iterate through the subdivisions
+ //
+ for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
+ {
+ for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
+ {
+ MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ i,
+ NULL,
+ s_skyPoints[t][s] );
+
+ s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];
+ s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];
+ }
+ }
+
+ // only add indexes for first stage
+ FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) );
+ }
+}
+
+/*
+** R_BuildCloudData
+*/
+void R_BuildCloudData( shaderCommands_t *input )
+{
+ int i;
+ shader_t *shader;
+
+ shader = input->shader;
+
+ assert( shader->isSky );
+
+ sky_min = 1.0 / 256.0f; // FIXME: not correct?
+ sky_max = 255.0 / 256.0f;
+
+ // set up for drawing
+ tess.numIndexes = 0;
+ tess.numVertexes = 0;
+ tess.firstIndex = 0;
+
+ if ( shader->sky.cloudHeight )
+ {
+ for ( i = 0; i < MAX_SHADER_STAGES; i++ )
+ {
+ if ( !tess.xstages[i] ) {
+ break;
+ }
+ FillCloudBox( shader, i );
+ }
+ }
+}
+
+/*
+** R_InitSkyTexCoords
+** Called when a sky shader is parsed
+*/
+#define SQR( a ) ((a)*(a))
+void R_InitSkyTexCoords( float heightCloud )
+{
+ int i, s, t;
+ float radiusWorld = 4096;
+ float p;
+ float sRad, tRad;
+ vec3_t skyVec;
+ vec3_t v;
+
+ // init zfar so MakeSkyVec works even though
+ // a world hasn't been bounded
+ backEnd.viewParms.zFar = 1024;
+
+ for ( i = 0; i < 6; i++ )
+ {
+ for ( t = 0; t <= SKY_SUBDIVISIONS; t++ )
+ {
+ for ( s = 0; s <= SKY_SUBDIVISIONS; s++ )
+ {
+ // compute vector from view origin to sky side integral point
+ MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
+ i,
+ NULL,
+ skyVec );
+
+ // compute parametric value 'p' that intersects with cloud layer
+ p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *
+ ( -2 * skyVec[2] * radiusWorld +
+ 2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) +
+ 2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +
+ SQR( skyVec[0] ) * SQR( heightCloud ) +
+ 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +
+ SQR( skyVec[1] ) * SQR( heightCloud ) +
+ 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +
+ SQR( skyVec[2] ) * SQR( heightCloud ) ) );
+
+ s_cloudTexP[i][t][s] = p;
+
+ // compute intersection point based on p
+ VectorScale( skyVec, p, v );
+ v[2] += radiusWorld;
+
+ // compute vector from world origin to intersection point 'v'
+ VectorNormalize( v );
+
+ sRad = Q_acos( v[0] );
+ tRad = Q_acos( v[1] );
+
+ s_cloudTexCoords[i][t][s][0] = sRad;
+ s_cloudTexCoords[i][t][s][1] = tRad;
+ }
+ }
+ }
+}
+
+//======================================================================================
+
+/*
+** RB_DrawSun
+*/
+void RB_DrawSun( float scale, shader_t *shader ) {
+ float size;
+ float dist;
+ vec3_t origin, vec1, vec2;
+
+ if ( !backEnd.skyRenderedThisView ) {
+ return;
+ }
+
+ //qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
+ //qglTranslatef (backEnd.viewParms.orientation.origin[0], backEnd.viewParms.orientation.origin[1], backEnd.viewParms.orientation.origin[2]);
+ {
+ // FIXME: this could be a lot cleaner
+ mat4_t translation, modelview;
+
+ Mat4Translation( backEnd.viewParms.orientation.origin, translation );
+ Mat4Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview );
+ GL_SetModelviewMatrix( modelview );
+ }
+
+ dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
+ size = dist * scale;
+
+ VectorScale( tr.sunDirection, dist, origin );
+ PerpendicularVector( vec1, tr.sunDirection );
+ CrossProduct( tr.sunDirection, vec1, vec2 );
+
+ VectorScale( vec1, size, vec1 );
+ VectorScale( vec2, size, vec2 );
+
+ // farthest depth range
+ qglDepthRange( 1.0, 1.0 );
+
+ RB_BeginSurface( shader, 0, 0 );
+
+ RB_AddQuadStamp(origin, vec1, vec2, colorWhite);
+
+ RB_EndSurface();
+
+ // back to normal depth range
+ qglDepthRange( 0.0, 1.0 );
+}
+
+
+
+
+/*
+================
+RB_StageIteratorSky
+
+All of the visible sky triangles are in tess
+
+Other things could be stuck in here, like birds in the sky, etc
+================
+*/
+void RB_StageIteratorSky( void ) {
+ if ( r_fastsky->integer ) {
+ return;
+ }
+
+ // go through all the polygons and project them onto
+ // the sky box to see which blocks on each side need
+ // to be drawn
+ RB_ClipSkyPolygons( &tess );
+
+ // r_showsky will let all the sky blocks be drawn in
+ // front of everything to allow developers to see how
+ // much sky is getting sucked in
+ if ( r_showsky->integer ) {
+ qglDepthRange( 0.0, 0.0 );
+ } else {
+ qglDepthRange( 1.0, 1.0 );
+ }
+
+ // draw the outer skybox
+ if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
+ mat4_t oldmodelview;
+
+ GL_State( 0 );
+ GL_Cull( CT_FRONT_SIDED );
+ //qglTranslatef (backEnd.viewParms.orientation.origin[0], backEnd.viewParms.orientation.origin[1], backEnd.viewParms.orientation.origin[2]);
+
+ {
+ // FIXME: this could be a lot cleaner
+ mat4_t trans, product;
+
+ Mat4Copy( glState.modelview, oldmodelview );
+ Mat4Translation( backEnd.viewParms.orientation.origin, trans );
+ Mat4Multiply( glState.modelview, trans, product );
+ GL_SetModelviewMatrix( product );
+
+ }
+
+ DrawSkyBox( tess.shader );
+
+ GL_SetModelviewMatrix( oldmodelview );
+ }
+
+ // generate the vertexes for all the clouds, which will be drawn
+ // by the generic shader routine
+ R_BuildCloudData( &tess );
+
+ RB_StageIteratorGeneric();
+
+ // draw the inner skybox
+
+
+ // back to normal depth range
+ qglDepthRange( 0.0, 1.0 );
+
+ // note that sky was drawn so we will draw a sun later
+ backEnd.skyRenderedThisView = true;
+}
diff --git a/src/renderergl2/tr_subs.cpp b/src/renderergl2/tr_subs.cpp
new file mode 100644
index 0000000..e7040e5
--- /dev/null
+++ b/src/renderergl2/tr_subs.cpp
@@ -0,0 +1,49 @@
+/*
+===========================================================================
+Copyright (C) 2010 James Canete (use.less01@gmail.com)
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_subs.c - common function replacements for modular renderer
+
+#include "tr_local.h"
+
+void QDECL Com_Printf( const char *msg, ... )
+{
+ va_list argptr;
+ char text[1024];
+
+ va_start(argptr, msg);
+ Q_vsnprintf(text, sizeof(text), msg, argptr);
+ va_end(argptr);
+
+ ri.Printf(PRINT_ALL, "%s", text);
+}
+
+void QDECL Com_Error( int level, const char *error, ... )
+{
+ va_list argptr;
+ char text[1024];
+
+ va_start(argptr, error);
+ Q_vsnprintf(text, sizeof(text), error, argptr);
+ va_end(argptr);
+
+ ri.Error(level, "%s", text);
+}
diff --git a/src/renderergl2/tr_surface.cpp b/src/renderergl2/tr_surface.cpp
new file mode 100644
index 0000000..39f2c34
--- /dev/null
+++ b/src/renderergl2/tr_surface.cpp
@@ -0,0 +1,1320 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_surf.c
+#include "tr_local.h"
+#if idppc_altivec && !defined(__APPLE__)
+#include <altivec.h>
+#endif
+
+/*
+
+ THIS ENTIRE FILE IS BACK END
+
+backEnd.currentEntity will be valid.
+
+Tess_Begin has already been called for the surface's shader.
+
+The modelview matrix will be set.
+
+It is safe to actually issue drawing commands here if you don't want to
+use the shader system.
+*/
+
+
+//============================================================================
+
+
+/*
+==============
+RB_CheckOverflow
+==============
+*/
+void RB_CheckOverflow( int verts, int indexes ) {
+ if (tess.numVertexes + verts < SHADER_MAX_VERTEXES
+ && tess.numIndexes + indexes < SHADER_MAX_INDEXES) {
+ return;
+ }
+
+ RB_EndSurface();
+
+ if ( verts >= SHADER_MAX_VERTEXES ) {
+ ri.Error(ERR_DROP, "RB_CheckOverflow: verts > MAX (%d > %d)", verts, SHADER_MAX_VERTEXES );
+ }
+ if ( indexes >= SHADER_MAX_INDEXES ) {
+ ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES );
+ }
+
+ RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex );
+}
+
+void RB_CheckVao(vao_t *vao)
+{
+ if (vao != glState.currentVao)
+ {
+ RB_EndSurface();
+ RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex);
+
+ R_BindVao(vao);
+ }
+
+ if (vao != tess.vao)
+ tess.useInternalVao = false;
+}
+
+
+/*
+==============
+RB_AddQuadStampExt
+==============
+*/
+void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], float s1, float t1, float s2, float t2 ) {
+ vec3_t normal;
+ int16_t iNormal[4];
+ uint16_t iColor[4];
+ int ndx;
+
+ RB_CheckVao(tess.vao);
+
+ RB_CHECKOVERFLOW( 4, 6 );
+
+ ndx = tess.numVertexes;
+
+ // triangle indexes for a simple quad
+ tess.indexes[ tess.numIndexes ] = ndx;
+ tess.indexes[ tess.numIndexes + 1 ] = ndx + 1;
+ tess.indexes[ tess.numIndexes + 2 ] = ndx + 3;
+
+ tess.indexes[ tess.numIndexes + 3 ] = ndx + 3;
+ tess.indexes[ tess.numIndexes + 4 ] = ndx + 1;
+ tess.indexes[ tess.numIndexes + 5 ] = ndx + 2;
+
+ tess.xyz[ndx][0] = origin[0] + left[0] + up[0];
+ tess.xyz[ndx][1] = origin[1] + left[1] + up[1];
+ tess.xyz[ndx][2] = origin[2] + left[2] + up[2];
+
+ tess.xyz[ndx+1][0] = origin[0] - left[0] + up[0];
+ tess.xyz[ndx+1][1] = origin[1] - left[1] + up[1];
+ tess.xyz[ndx+1][2] = origin[2] - left[2] + up[2];
+
+ tess.xyz[ndx+2][0] = origin[0] - left[0] - up[0];
+ tess.xyz[ndx+2][1] = origin[1] - left[1] - up[1];
+ tess.xyz[ndx+2][2] = origin[2] - left[2] - up[2];
+
+ tess.xyz[ndx+3][0] = origin[0] + left[0] - up[0];
+ tess.xyz[ndx+3][1] = origin[1] + left[1] - up[1];
+ tess.xyz[ndx+3][2] = origin[2] + left[2] - up[2];
+
+
+ // constant normal all the way around
+ VectorSubtract( vec3_origin, backEnd.viewParms.orientation.axis[0], normal );
+
+ R_VaoPackNormal(iNormal, normal);
+
+ VectorCopy4(iNormal, tess.normal[ndx]);
+ VectorCopy4(iNormal, tess.normal[ndx + 1]);
+ VectorCopy4(iNormal, tess.normal[ndx + 2]);
+ VectorCopy4(iNormal, tess.normal[ndx + 3]);
+
+ // standard square texture coordinates
+ VectorSet2(tess.texCoords[ndx], s1, t1);
+ VectorSet2(tess.lightCoords[ndx], s1, t1);
+
+ VectorSet2(tess.texCoords[ndx+1], s2, t1);
+ VectorSet2(tess.lightCoords[ndx+1], s2, t1);
+
+ VectorSet2(tess.texCoords[ndx+2], s2, t2);
+ VectorSet2(tess.lightCoords[ndx+2], s2, t2);
+
+ VectorSet2(tess.texCoords[ndx+3], s1, t2);
+ VectorSet2(tess.lightCoords[ndx+3], s1, t2);
+
+ // constant color all the way around
+ // should this be identity and let the shader specify from entity?
+
+ R_VaoPackColor(iColor, color);
+
+ VectorCopy4(iColor, tess.color[ndx]);
+ VectorCopy4(iColor, tess.color[ndx + 1]);
+ VectorCopy4(iColor, tess.color[ndx + 2]);
+ VectorCopy4(iColor, tess.color[ndx + 3]);
+
+ tess.numVertexes += 4;
+ tess.numIndexes += 6;
+}
+
+/*
+==============
+RB_AddQuadStamp
+==============
+*/
+void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, float color[4] ) {
+ RB_AddQuadStampExt( origin, left, up, color, 0, 0, 1, 1 );
+}
+
+
+/*
+==============
+RB_InstantQuad
+
+based on Tess_InstantQuad from xreal
+==============
+*/
+void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4])
+{
+ GLimp_LogComment("--- RB_InstantQuad2 ---\n");
+
+ tess.numVertexes = 0;
+ tess.numIndexes = 0;
+ tess.firstIndex = 0;
+
+ VectorCopy4(quadVerts[0], tess.xyz[tess.numVertexes]);
+ VectorCopy2(texCoords[0], tess.texCoords[tess.numVertexes]);
+ tess.numVertexes++;
+
+ VectorCopy4(quadVerts[1], tess.xyz[tess.numVertexes]);
+ VectorCopy2(texCoords[1], tess.texCoords[tess.numVertexes]);
+ tess.numVertexes++;
+
+ VectorCopy4(quadVerts[2], tess.xyz[tess.numVertexes]);
+ VectorCopy2(texCoords[2], tess.texCoords[tess.numVertexes]);
+ tess.numVertexes++;
+
+ VectorCopy4(quadVerts[3], tess.xyz[tess.numVertexes]);
+ VectorCopy2(texCoords[3], tess.texCoords[tess.numVertexes]);
+ tess.numVertexes++;
+
+ tess.indexes[tess.numIndexes++] = 0;
+ tess.indexes[tess.numIndexes++] = 1;
+ tess.indexes[tess.numIndexes++] = 2;
+ tess.indexes[tess.numIndexes++] = 0;
+ tess.indexes[tess.numIndexes++] = 2;
+ tess.indexes[tess.numIndexes++] = 3;
+
+ RB_UpdateTessVao(ATTR_POSITION | ATTR_TEXCOORD);
+
+ R_DrawElements(tess.numIndexes, tess.firstIndex);
+
+ tess.numIndexes = 0;
+ tess.numVertexes = 0;
+ tess.firstIndex = 0;
+}
+
+
+void RB_InstantQuad(vec4_t quadVerts[4])
+{
+ vec2_t texCoords[4];
+
+ VectorSet2(texCoords[0], 0.0f, 0.0f);
+ VectorSet2(texCoords[1], 1.0f, 0.0f);
+ VectorSet2(texCoords[2], 1.0f, 1.0f);
+ VectorSet2(texCoords[3], 0.0f, 1.0f);
+
+ GLSL_BindProgram(&tr.textureColorShader);
+
+ GLSL_SetUniformMat4(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+ GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite);
+
+ RB_InstantQuad2(quadVerts, texCoords);
+}
+
+
+/*
+==============
+RB_SurfaceSprite
+==============
+*/
+static void RB_SurfaceSprite( void ) {
+ vec3_t left, up;
+ float radius;
+ float colors[4];
+ trRefEntity_t *ent = backEnd.currentEntity;
+
+ // calculate the xyz locations for the four corners
+ radius = ent->e.radius;
+ if ( ent->e.rotation == 0 ) {
+ VectorScale( backEnd.viewParms.orientation.axis[1], radius, left );
+ VectorScale( backEnd.viewParms.orientation.axis[2], radius, up );
+ } else {
+ float s, c;
+ float ang;
+
+ ang = M_PI * ent->e.rotation / 180;
+ s = sin( ang );
+ c = cos( ang );
+
+ VectorScale( backEnd.viewParms.orientation.axis[1], c * radius, left );
+ VectorMA( left, -s * radius, backEnd.viewParms.orientation.axis[2], left );
+
+ VectorScale( backEnd.viewParms.orientation.axis[2], c * radius, up );
+ VectorMA( up, s * radius, backEnd.viewParms.orientation.axis[1], up );
+ }
+ if ( backEnd.viewParms.isMirror ) {
+ VectorSubtract( vec3_origin, left, left );
+ }
+
+ VectorScale4(ent->e.shaderRGBA, 1.0f / 255.0f, colors);
+
+ RB_AddQuadStamp( ent->e.origin, left, up, colors );
+}
+
+
+/*
+=============
+RB_SurfacePolychain
+=============
+*/
+static void RB_SurfacePolychain( srfPoly_t *p ) {
+ int i;
+ int numv;
+
+ RB_CheckVao(tess.vao);
+
+ RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) );
+
+ // fan triangles into the tess array
+ numv = tess.numVertexes;
+ for ( i = 0; i < p->numVerts; i++ ) {
+ VectorCopy( p->verts[i].xyz, tess.xyz[numv] );
+ tess.texCoords[numv][0] = p->verts[i].st[0];
+ tess.texCoords[numv][1] = p->verts[i].st[1];
+ tess.color[numv][0] = (int)p->verts[i].modulate[0] * 257;
+ tess.color[numv][1] = (int)p->verts[i].modulate[1] * 257;
+ tess.color[numv][2] = (int)p->verts[i].modulate[2] * 257;
+ tess.color[numv][3] = (int)p->verts[i].modulate[3] * 257;
+
+ numv++;
+ }
+
+ // generate fan indexes into the tess array
+ for ( i = 0; i < p->numVerts-2; i++ ) {
+ tess.indexes[tess.numIndexes + 0] = tess.numVertexes;
+ tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1;
+ tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2;
+ tess.numIndexes += 3;
+ }
+
+ tess.numVertexes = numv;
+}
+
+static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIndexes, glIndex_t *indexes, int dlightBits, int pshadowBits)
+{
+ int i;
+ glIndex_t *inIndex;
+ srfVert_t *dv;
+ float *xyz, *texCoords, *lightCoords;
+ int16_t *lightdir;
+ int16_t *normal;
+ int16_t *tangent;
+ glIndex_t *outIndex;
+ uint16_t *color;
+
+ RB_CheckVao(tess.vao);
+
+ RB_CHECKOVERFLOW( numVerts, numIndexes );
+
+ inIndex = indexes;
+ outIndex = &tess.indexes[ tess.numIndexes ];
+ for ( i = 0 ; i < numIndexes ; i++ ) {
+ *outIndex++ = tess.numVertexes + *inIndex++;
+ }
+ tess.numIndexes += numIndexes;
+
+ if ( tess.shader->vertexAttribs & ATTR_POSITION )
+ {
+ dv = verts;
+ xyz = tess.xyz[ tess.numVertexes ];
+ for ( i = 0 ; i < numVerts ; i++, dv++, xyz+=4 )
+ VectorCopy(dv->xyz, xyz);
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_NORMAL )
+ {
+ dv = verts;
+ normal = tess.normal[ tess.numVertexes ];
+ for ( i = 0 ; i < numVerts ; i++, dv++, normal+=4 )
+ VectorCopy4(dv->normal, normal);
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_TANGENT )
+ {
+ dv = verts;
+ tangent = tess.tangent[ tess.numVertexes ];
+ for ( i = 0 ; i < numVerts ; i++, dv++, tangent+=4 )
+ VectorCopy4(dv->tangent, tangent);
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_TEXCOORD )
+ {
+ dv = verts;
+ texCoords = tess.texCoords[tess.numVertexes];
+ for ( i = 0 ; i < numVerts ; i++, dv++, texCoords+=2 )
+ VectorCopy2(dv->st, texCoords);
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_LIGHTCOORD )
+ {
+ dv = verts;
+ lightCoords = tess.lightCoords[ tess.numVertexes ];
+ for ( i = 0 ; i < numVerts ; i++, dv++, lightCoords+=2 )
+ VectorCopy2(dv->lightmap, lightCoords);
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_COLOR )
+ {
+ dv = verts;
+ color = tess.color[ tess.numVertexes ];
+ for ( i = 0 ; i < numVerts ; i++, dv++, color+=4 )
+ VectorCopy4(dv->color, color);
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION )
+ {
+ dv = verts;
+ lightdir = tess.lightdir[ tess.numVertexes ];
+ for ( i = 0 ; i < numVerts ; i++, dv++, lightdir+=4 )
+ VectorCopy4(dv->lightdir, lightdir);
+ }
+
+#if 0 // nothing even uses vertex dlightbits
+ for ( i = 0 ; i < numVerts ; i++ ) {
+ tess.vertexDlightBits[ tess.numVertexes + i ] = dlightBits;
+ }
+#endif
+
+ tess.dlightBits |= dlightBits;
+ tess.pshadowBits |= pshadowBits;
+
+ tess.numVertexes += numVerts;
+}
+
+static bool RB_SurfaceVaoCached(int numVerts, srfVert_t *verts, int numIndexes, glIndex_t *indexes, int dlightBits, int pshadowBits)
+{
+ bool recycleVertexBuffer = false;
+ bool recycleIndexBuffer = false;
+ bool endSurface = false;
+
+ if (!(!ShaderRequiresCPUDeforms(tess.shader) && !tess.shader->isSky && !tess.shader->isPortal))
+ return false;
+
+ if (!numIndexes || !numVerts)
+ return false;
+
+ VaoCache_BindVao();
+
+ tess.dlightBits |= dlightBits;
+ tess.pshadowBits |= pshadowBits;
+
+ VaoCache_CheckAdd(&endSurface, &recycleVertexBuffer, &recycleIndexBuffer, numVerts, numIndexes);
+
+ if (endSurface)
+ {
+ RB_EndSurface();
+ RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex);
+ }
+
+ if (recycleVertexBuffer)
+ VaoCache_RecycleVertexBuffer();
+
+ if (recycleIndexBuffer)
+ VaoCache_RecycleIndexBuffer();
+
+ if (!tess.numVertexes)
+ VaoCache_InitNewSurfaceSet();
+
+ VaoCache_AddSurface(verts, numVerts, indexes, numIndexes);
+
+ tess.numIndexes += numIndexes;
+ tess.numVertexes += numVerts;
+ tess.useInternalVao = false;
+ tess.useCacheVao = true;
+
+ return true;
+}
+
+/*
+=============
+RB_SurfaceTriangles
+=============
+*/
+static void RB_SurfaceTriangles( srfBspSurface_t *srf ) {
+ if (RB_SurfaceVaoCached(srf->numVerts, srf->verts, srf->numIndexes,
+ srf->indexes, srf->dlightBits, srf->pshadowBits))
+ {
+ return;
+ }
+
+ RB_SurfaceVertsAndIndexes(srf->numVerts, srf->verts, srf->numIndexes,
+ srf->indexes, srf->dlightBits, srf->pshadowBits);
+}
+
+
+
+/*
+==============
+RB_SurfaceBeam
+==============
+*/
+static void RB_SurfaceBeam( void )
+{
+#define NUM_BEAM_SEGS 6
+ refEntity_t *e;
+ shaderProgram_t *sp = &tr.textureColorShader;
+ int i;
+ vec3_t perpvec;
+ vec3_t direction, normalized_direction;
+ vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
+ vec3_t oldorigin, origin;
+
+ e = &backEnd.currentEntity->e;
+
+ oldorigin[0] = e->oldorigin[0];
+ oldorigin[1] = e->oldorigin[1];
+ oldorigin[2] = e->oldorigin[2];
+
+ origin[0] = e->origin[0];
+ origin[1] = e->origin[1];
+ origin[2] = e->origin[2];
+
+ normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
+ normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
+ normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
+
+ if ( VectorNormalize( normalized_direction ) == 0 )
+ return;
+
+ PerpendicularVector( perpvec, normalized_direction );
+
+ VectorScale( perpvec, 4, perpvec );
+
+ for ( i = 0; i < NUM_BEAM_SEGS ; i++ )
+ {
+ RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
+// VectorAdd( start_points[i], origin, start_points[i] );
+ VectorAdd( start_points[i], direction, end_points[i] );
+ }
+
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
+
+ GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+
+ // FIXME: Quake3 doesn't use this, so I never tested it
+ tess.numVertexes = 0;
+ tess.numIndexes = 0;
+ tess.firstIndex = 0;
+
+ for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) {
+ VectorCopy(start_points[ i % NUM_BEAM_SEGS ], tess.xyz[tess.numVertexes++]);
+ VectorCopy(end_points [ i % NUM_BEAM_SEGS ], tess.xyz[tess.numVertexes++]);
+ }
+
+ for ( i = 0; i < NUM_BEAM_SEGS; i++ ) {
+ tess.indexes[tess.numIndexes++] = i * 2;
+ tess.indexes[tess.numIndexes++] = (i + 1) * 2;
+ tess.indexes[tess.numIndexes++] = 1 + i * 2;
+
+ tess.indexes[tess.numIndexes++] = 1 + i * 2;
+ tess.indexes[tess.numIndexes++] = (i + 1) * 2;
+ tess.indexes[tess.numIndexes++] = 1 + (i + 1) * 2;
+ }
+
+ // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function
+ RB_UpdateTessVao(ATTR_POSITION);
+
+ GLSL_BindProgram(sp);
+
+ GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
+
+ GLSL_SetUniformVec4(sp, UNIFORM_COLOR, colorRed);
+
+ GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
+
+ R_DrawElements(tess.numIndexes, tess.firstIndex);
+
+ tess.numIndexes = 0;
+ tess.numVertexes = 0;
+ tess.firstIndex = 0;
+}
+
+//================================================================================
+
+static void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, float len, float spanWidth )
+{
+ float spanWidth2;
+ int vbase;
+ float t = len / 256.0f;
+
+ RB_CheckVao(tess.vao);
+
+ RB_CHECKOVERFLOW( 4, 6 );
+
+ vbase = tess.numVertexes;
+
+ spanWidth2 = -spanWidth;
+
+ // FIXME: use quad stamp?
+ VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] );
+ tess.texCoords[tess.numVertexes][0] = 0;
+ tess.texCoords[tess.numVertexes][1] = 0;
+ tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25f * 257.0f;
+ tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25f * 257.0f;
+ tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25f * 257.0f;
+ tess.numVertexes++;
+
+ VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] );
+ tess.texCoords[tess.numVertexes][0] = 0;
+ tess.texCoords[tess.numVertexes][1] = 1;
+ tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257;
+ tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257;
+ tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257;
+ tess.numVertexes++;
+
+ VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] );
+
+ tess.texCoords[tess.numVertexes][0] = t;
+ tess.texCoords[tess.numVertexes][1] = 0;
+ tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257;
+ tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257;
+ tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257;
+ tess.numVertexes++;
+
+ VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] );
+ tess.texCoords[tess.numVertexes][0] = t;
+ tess.texCoords[tess.numVertexes][1] = 1;
+ tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257;
+ tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257;
+ tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257;
+ tess.numVertexes++;
+
+ tess.indexes[tess.numIndexes++] = vbase;
+ tess.indexes[tess.numIndexes++] = vbase + 1;
+ tess.indexes[tess.numIndexes++] = vbase + 2;
+
+ tess.indexes[tess.numIndexes++] = vbase + 2;
+ tess.indexes[tess.numIndexes++] = vbase + 1;
+ tess.indexes[tess.numIndexes++] = vbase + 3;
+}
+
+static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, const vec3_t right, const vec3_t up )
+{
+ int i;
+ vec3_t pos[4];
+ vec3_t v;
+ int spanWidth = r_railWidth->integer;
+ float c, s;
+ float scale;
+
+ if ( numSegs > 1 )
+ numSegs--;
+ if ( !numSegs )
+ return;
+
+ scale = 0.25;
+
+ for ( i = 0; i < 4; i++ )
+ {
+ c = cos( DEG2RAD( 45 + i * 90 ) );
+ s = sin( DEG2RAD( 45 + i * 90 ) );
+ v[0] = ( right[0] * c + up[0] * s ) * scale * spanWidth;
+ v[1] = ( right[1] * c + up[1] * s ) * scale * spanWidth;
+ v[2] = ( right[2] * c + up[2] * s ) * scale * spanWidth;
+ VectorAdd( start, v, pos[i] );
+
+ if ( numSegs > 1 )
+ {
+ // offset by 1 segment if we're doing a long distance shot
+ VectorAdd( pos[i], dir, pos[i] );
+ }
+ }
+
+ RB_CheckVao(tess.vao);
+
+ for ( i = 0; i < numSegs; i++ )
+ {
+ int j;
+
+ RB_CHECKOVERFLOW( 4, 6 );
+
+ for ( j = 0; j < 4; j++ )
+ {
+ VectorCopy( pos[j], tess.xyz[tess.numVertexes] );
+ tess.texCoords[tess.numVertexes][0] = (j < 2);
+ tess.texCoords[tess.numVertexes][1] = (j && j != 3);
+ tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257;
+ tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257;
+ tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257;
+ tess.numVertexes++;
+
+ VectorAdd( pos[j], dir, pos[j] );
+ }
+
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 0;
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1;
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3;
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3;
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1;
+ tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 2;
+ }
+}
+
+/*
+** RB_SurfaceRailRinges
+*/
+static void RB_SurfaceRailRings( void ) {
+ refEntity_t *e;
+ int numSegs;
+ int len;
+ vec3_t vec;
+ vec3_t right, up;
+ vec3_t start, end;
+
+ e = &backEnd.currentEntity->e;
+
+ VectorCopy( e->oldorigin, start );
+ VectorCopy( e->origin, end );
+
+ // compute variables
+ VectorSubtract( end, start, vec );
+ len = VectorNormalize( vec );
+ MakeNormalVectors( vec, right, up );
+ numSegs = ( len ) / r_railSegmentLength->value;
+ if ( numSegs <= 0 ) {
+ numSegs = 1;
+ }
+
+ VectorScale( vec, r_railSegmentLength->value, vec );
+
+ DoRailDiscs( numSegs, start, vec, right, up );
+}
+
+/*
+** RB_SurfaceRailCore
+*/
+static void RB_SurfaceRailCore( void ) {
+ refEntity_t *e;
+ int len;
+ vec3_t right;
+ vec3_t vec;
+ vec3_t start, end;
+ vec3_t v1, v2;
+
+ e = &backEnd.currentEntity->e;
+
+ VectorCopy( e->oldorigin, start );
+ VectorCopy( e->origin, end );
+
+ VectorSubtract( end, start, vec );
+ len = VectorNormalize( vec );
+
+ // compute side vector
+ VectorSubtract( start, backEnd.viewParms.orientation.origin, v1 );
+ VectorNormalize( v1 );
+ VectorSubtract( end, backEnd.viewParms.orientation.origin, v2 );
+ VectorNormalize( v2 );
+ CrossProduct( v1, v2, right );
+ VectorNormalize( right );
+
+ DoRailCore( start, end, right, len, r_railCoreWidth->integer );
+}
+
+/*
+** RB_SurfaceLightningBolt
+*/
+static void RB_SurfaceLightningBolt( void ) {
+ refEntity_t *e;
+ int len;
+ vec3_t right;
+ vec3_t vec;
+ vec3_t start, end;
+ vec3_t v1, v2;
+ int i;
+
+ e = &backEnd.currentEntity->e;
+
+ VectorCopy( e->oldorigin, end );
+ VectorCopy( e->origin, start );
+
+ // compute variables
+ VectorSubtract( end, start, vec );
+ len = VectorNormalize( vec );
+
+ // compute side vector
+ VectorSubtract( start, backEnd.viewParms.orientation.origin, v1 );
+ VectorNormalize( v1 );
+ VectorSubtract( end, backEnd.viewParms.orientation.origin, v2 );
+ VectorNormalize( v2 );
+ CrossProduct( v1, v2, right );
+ VectorNormalize( right );
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ vec3_t temp;
+
+ DoRailCore( start, end, right, len, 8 );
+ RotatePointAroundVector( temp, vec, right, 45 );
+ VectorCopy( temp, right );
+ }
+}
+
+
+static void LerpMeshVertexes(mdvSurface_t *surf, float backlerp)
+{
+ float *outXyz;
+ int16_t *outNormal, *outTangent;
+ mdvVertex_t *newVerts;
+ int vertNum;
+
+ newVerts = surf->verts + backEnd.currentEntity->e.frame * surf->numVerts;
+
+ outXyz = tess.xyz[tess.numVertexes];
+ outNormal = tess.normal[tess.numVertexes];
+ outTangent = tess.tangent[tess.numVertexes];
+
+ if (backlerp == 0)
+ {
+ //
+ // just copy the vertexes
+ //
+
+ for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++)
+ {
+ VectorCopy(newVerts->xyz, outXyz);
+ VectorCopy4(newVerts->normal, outNormal);
+ VectorCopy4(newVerts->tangent, outTangent);
+
+ newVerts++;
+ outXyz += 4;
+ outNormal += 4;
+ outTangent += 4;
+ }
+ }
+ else
+ {
+ //
+ // interpolate and copy the vertex and normal
+ //
+
+ mdvVertex_t *oldVerts;
+
+ oldVerts = surf->verts + backEnd.currentEntity->e.oldframe * surf->numVerts;
+
+ for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++)
+ {
+ VectorLerp(newVerts->xyz, oldVerts->xyz, backlerp, outXyz);
+
+ outNormal[0] = (int16_t)(newVerts->normal[0] * (1.0f - backlerp) + oldVerts->normal[0] * backlerp);
+ outNormal[1] = (int16_t)(newVerts->normal[1] * (1.0f - backlerp) + oldVerts->normal[1] * backlerp);
+ outNormal[2] = (int16_t)(newVerts->normal[2] * (1.0f - backlerp) + oldVerts->normal[2] * backlerp);
+ outNormal[3] = 0;
+
+ outTangent[0] = (int16_t)(newVerts->tangent[0] * (1.0f - backlerp) + oldVerts->tangent[0] * backlerp);
+ outTangent[1] = (int16_t)(newVerts->tangent[1] * (1.0f - backlerp) + oldVerts->tangent[1] * backlerp);
+ outTangent[2] = (int16_t)(newVerts->tangent[2] * (1.0f - backlerp) + oldVerts->tangent[2] * backlerp);
+ outTangent[3] = newVerts->tangent[3];
+
+ newVerts++;
+ oldVerts++;
+ outXyz += 4;
+ outNormal += 4;
+ outTangent += 4;
+ }
+ }
+
+}
+
+
+/*
+=============
+RB_SurfaceMesh
+=============
+*/
+static void RB_SurfaceMesh(mdvSurface_t *surface) {
+ int j;
+ float backlerp;
+ mdvSt_t *texCoords;
+ int Bob, Doug;
+ int numVerts;
+
+ if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) {
+ backlerp = 0;
+ } else {
+ backlerp = backEnd.currentEntity->e.backlerp;
+ }
+
+ RB_CheckVao(tess.vao);
+
+ RB_CHECKOVERFLOW( surface->numVerts, surface->numIndexes );
+
+ LerpMeshVertexes (surface, backlerp);
+
+ Bob = tess.numIndexes;
+ Doug = tess.numVertexes;
+ for (j = 0 ; j < surface->numIndexes ; j++) {
+ tess.indexes[Bob + j] = Doug + surface->indexes[j];
+ }
+ tess.numIndexes += surface->numIndexes;
+
+ texCoords = surface->st;
+
+ numVerts = surface->numVerts;
+ for ( j = 0; j < numVerts; j++ ) {
+ tess.texCoords[Doug + j][0] = texCoords[j].st[0];
+ tess.texCoords[Doug + j][1] = texCoords[j].st[1];
+ // FIXME: fill in lightmapST for completeness?
+ }
+
+ tess.numVertexes += surface->numVerts;
+
+}
+
+
+/*
+==============
+RB_SurfaceFace
+==============
+*/
+static void RB_SurfaceFace( srfBspSurface_t *srf ) {
+ if (RB_SurfaceVaoCached(srf->numVerts, srf->verts, srf->numIndexes,
+ srf->indexes, srf->dlightBits, srf->pshadowBits))
+ {
+ return;
+ }
+
+ RB_SurfaceVertsAndIndexes(srf->numVerts, srf->verts, srf->numIndexes,
+ srf->indexes, srf->dlightBits, srf->pshadowBits);
+}
+
+
+static float LodErrorForVolume( vec3_t local, float radius ) {
+ vec3_t world;
+ float d;
+
+ // never let it go negative
+ if ( r_lodCurveError->value < 0 ) {
+ return 0;
+ }
+
+ world[0] = local[0] * backEnd.orientation.axis[0][0] + local[1] * backEnd.orientation.axis[1][0] +
+ local[2] * backEnd.orientation.axis[2][0] + backEnd.orientation.origin[0];
+ world[1] = local[0] * backEnd.orientation.axis[0][1] + local[1] * backEnd.orientation.axis[1][1] +
+ local[2] * backEnd.orientation.axis[2][1] + backEnd.orientation.origin[1];
+ world[2] = local[0] * backEnd.orientation.axis[0][2] + local[1] * backEnd.orientation.axis[1][2] +
+ local[2] * backEnd.orientation.axis[2][2] + backEnd.orientation.origin[2];
+
+ VectorSubtract( world, backEnd.viewParms.orientation.origin, world );
+ d = DotProduct( world, backEnd.viewParms.orientation.axis[0] );
+
+ if ( d < 0 ) {
+ d = -d;
+ }
+ d -= radius;
+ if ( d < 1 ) {
+ d = 1;
+ }
+
+ return r_lodCurveError->value / d;
+}
+
+/*
+=============
+RB_SurfaceGrid
+
+Just copy the grid of points and triangulate
+=============
+*/
+static void RB_SurfaceGrid( srfBspSurface_t *srf ) {
+ int i, j;
+ float *xyz;
+ float *texCoords, *lightCoords;
+ int16_t *normal;
+ int16_t *tangent;
+ uint16_t *color;
+ int16_t *lightdir;
+ srfVert_t *dv;
+ int rows, irows, vrows;
+ int used;
+ int widthTable[MAX_GRID_SIZE];
+ int heightTable[MAX_GRID_SIZE];
+ float lodError;
+ int lodWidth, lodHeight;
+ int numVertexes;
+ int dlightBits;
+ int pshadowBits;
+ //int *vDlightBits;
+
+ if (RB_SurfaceVaoCached(srf->numVerts, srf->verts, srf->numIndexes,
+ srf->indexes, srf->dlightBits, srf->pshadowBits))
+ {
+ return;
+ }
+
+ RB_CheckVao(tess.vao);
+
+ dlightBits = srf->dlightBits;
+ tess.dlightBits |= dlightBits;
+
+ pshadowBits = srf->pshadowBits;
+ tess.pshadowBits |= pshadowBits;
+
+ // determine the allowable discrepance
+ lodError = LodErrorForVolume( srf->lodOrigin, srf->lodRadius );
+
+ // determine which rows and columns of the subdivision
+ // we are actually going to use
+ widthTable[0] = 0;
+ lodWidth = 1;
+ for ( i = 1 ; i < srf->width-1 ; i++ ) {
+ if ( srf->widthLodError[i] <= lodError ) {
+ widthTable[lodWidth] = i;
+ lodWidth++;
+ }
+ }
+ widthTable[lodWidth] = srf->width-1;
+ lodWidth++;
+
+ heightTable[0] = 0;
+ lodHeight = 1;
+ for ( i = 1 ; i < srf->height-1 ; i++ ) {
+ if ( srf->heightLodError[i] <= lodError ) {
+ heightTable[lodHeight] = i;
+ lodHeight++;
+ }
+ }
+ heightTable[lodHeight] = srf->height-1;
+ lodHeight++;
+
+
+ // very large grids may have more points or indexes than can be fit
+ // in the tess structure, so we may have to issue it in multiple passes
+
+ used = 0;
+ while ( used < lodHeight - 1 ) {
+ // see how many rows of both verts and indexes we can add without overflowing
+ do {
+ vrows = ( SHADER_MAX_VERTEXES - tess.numVertexes ) / lodWidth;
+ irows = ( SHADER_MAX_INDEXES - tess.numIndexes ) / ( lodWidth * 6 );
+
+ // if we don't have enough space for at least one strip, flush the buffer
+ if ( vrows < 2 || irows < 1 ) {
+ RB_EndSurface();
+ RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex );
+ } else {
+ break;
+ }
+ } while ( 1 );
+
+ rows = irows;
+ if ( vrows < irows + 1 ) {
+ rows = vrows - 1;
+ }
+ if ( used + rows > lodHeight ) {
+ rows = lodHeight - used;
+ }
+
+ numVertexes = tess.numVertexes;
+
+ xyz = tess.xyz[numVertexes];
+ normal = tess.normal[numVertexes];
+ tangent = tess.tangent[numVertexes];
+ texCoords = tess.texCoords[numVertexes];
+ lightCoords = tess.lightCoords[numVertexes];
+ color = tess.color[numVertexes];
+ lightdir = tess.lightdir[numVertexes];
+ //vDlightBits = &tess.vertexDlightBits[numVertexes];
+
+ for ( i = 0 ; i < rows ; i++ ) {
+ for ( j = 0 ; j < lodWidth ; j++ ) {
+ dv = srf->verts + heightTable[ used + i ] * srf->width
+ + widthTable[ j ];
+
+ if ( tess.shader->vertexAttribs & ATTR_POSITION )
+ {
+ VectorCopy(dv->xyz, xyz);
+ xyz += 4;
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_NORMAL )
+ {
+ VectorCopy4(dv->normal, normal);
+ normal += 4;
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_TANGENT )
+ {
+ VectorCopy4(dv->tangent, tangent);
+ tangent += 4;
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_TEXCOORD )
+ {
+ VectorCopy2(dv->st, texCoords);
+ texCoords += 2;
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_LIGHTCOORD )
+ {
+ VectorCopy2(dv->lightmap, lightCoords);
+ lightCoords += 2;
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_COLOR )
+ {
+ VectorCopy4(dv->color, color);
+ color += 4;
+ }
+
+ if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION )
+ {
+ VectorCopy4(dv->lightdir, lightdir);
+ lightdir += 4;
+ }
+
+ //*vDlightBits++ = dlightBits;
+ }
+ }
+
+
+ // add the indexes
+ {
+ int numIndexes;
+ int w, h;
+
+ h = rows - 1;
+ w = lodWidth - 1;
+ numIndexes = tess.numIndexes;
+ for (i = 0 ; i < h ; i++) {
+ for (j = 0 ; j < w ; j++) {
+ int v1, v2, v3, v4;
+
+ // vertex order to be reckognized as tristrips
+ v1 = numVertexes + i*lodWidth + j + 1;
+ v2 = v1 - 1;
+ v3 = v2 + lodWidth;
+ v4 = v3 + 1;
+
+ tess.indexes[numIndexes] = v2;
+ tess.indexes[numIndexes+1] = v3;
+ tess.indexes[numIndexes+2] = v1;
+
+ tess.indexes[numIndexes+3] = v1;
+ tess.indexes[numIndexes+4] = v3;
+ tess.indexes[numIndexes+5] = v4;
+ numIndexes += 6;
+ }
+ }
+
+ tess.numIndexes = numIndexes;
+ }
+
+ tess.numVertexes += rows * lodWidth;
+
+ used += rows - 1;
+ }
+}
+
+
+/*
+===========================================================================
+
+NULL MODEL
+
+===========================================================================
+*/
+
+/*
+===================
+RB_SurfaceAxis
+
+Draws x/y/z lines from the origin for orientation debugging
+===================
+*/
+static void RB_SurfaceAxis( void ) {
+ // FIXME: implement this
+#if 0
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
+ GL_State( GLS_DEFAULT );
+ qglLineWidth( 3 );
+ qglBegin( GL_LINES );
+ qglColor3f( 1,0,0 );
+ qglVertex3f( 0,0,0 );
+ qglVertex3f( 16,0,0 );
+ qglColor3f( 0,1,0 );
+ qglVertex3f( 0,0,0 );
+ qglVertex3f( 0,16,0 );
+ qglColor3f( 0,0,1 );
+ qglVertex3f( 0,0,0 );
+ qglVertex3f( 0,0,16 );
+ qglEnd();
+ qglLineWidth( 1 );
+#endif
+}
+
+//===========================================================================
+
+/*
+====================
+RB_SurfaceEntity
+
+Entities that have a single procedurally generated surface
+====================
+*/
+static void RB_SurfaceEntity( surfaceType_t *surfType ) {
+ switch( backEnd.currentEntity->e.reType ) {
+ case RT_SPRITE:
+ RB_SurfaceSprite();
+ break;
+ case RT_BEAM:
+ RB_SurfaceBeam();
+ break;
+ case RT_RAIL_CORE:
+ RB_SurfaceRailCore();
+ break;
+ case RT_RAIL_RINGS:
+ RB_SurfaceRailRings();
+ break;
+ case RT_LIGHTNING:
+ RB_SurfaceLightningBolt();
+ break;
+ default:
+ RB_SurfaceAxis();
+ break;
+ }
+}
+
+static void RB_SurfaceBad( surfaceType_t *surfType ) {
+ ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" );
+}
+
+static void RB_SurfaceFlare(srfFlare_t *surf)
+{
+ if (r_flares->integer)
+ RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal);
+}
+
+void RB_SurfaceVaoMdvMesh(srfVaoMdvMesh_t * surface)
+{
+ //mdvModel_t *mdvModel;
+ //mdvSurface_t *mdvSurface;
+ refEntity_t *refEnt;
+
+ GLimp_LogComment("--- RB_SurfaceVaoMdvMesh ---\n");
+
+ if (ShaderRequiresCPUDeforms(tess.shader))
+ {
+ RB_SurfaceMesh(surface->mdvSurface);
+ return;
+ }
+
+ if(!surface->vao)
+ return;
+
+ //RB_CheckVao(surface->vao);
+ RB_EndSurface();
+ RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex);
+
+ R_BindVao(surface->vao);
+
+ tess.useInternalVao = false;
+
+ tess.numIndexes = surface->numIndexes;
+ tess.numVertexes = surface->numVerts;
+
+ //mdvModel = surface->mdvModel;
+ //mdvSurface = surface->mdvSurface;
+
+ refEnt = &backEnd.currentEntity->e;
+
+ glState.vertexAttribsInterpolation = (refEnt->oldframe == refEnt->frame) ? 0.0f : refEnt->backlerp;
+
+ if (surface->mdvModel->numFrames > 1)
+ {
+ int frameOffset, attribIndex;
+ vaoAttrib_t *vAtb;
+
+ glState.vertexAnimation = true;
+
+ if (glRefConfig.vertexArrayObject)
+ {
+ qglBindBuffer(GL_ARRAY_BUFFER, surface->vao->vertexesVBO);
+ }
+
+ frameOffset = refEnt->frame * surface->vao->frameSize;
+
+ attribIndex = ATTR_INDEX_POSITION;
+ vAtb = &surface->vao->attribs[attribIndex];
+ qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+ attribIndex = ATTR_INDEX_NORMAL;
+ vAtb = &surface->vao->attribs[attribIndex];
+ qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+ attribIndex = ATTR_INDEX_TANGENT;
+ vAtb = &surface->vao->attribs[attribIndex];
+ qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+ frameOffset = refEnt->oldframe * surface->vao->frameSize;
+
+ attribIndex = ATTR_INDEX_POSITION2;
+ vAtb = &surface->vao->attribs[attribIndex];
+ qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+ attribIndex = ATTR_INDEX_NORMAL2;
+ vAtb = &surface->vao->attribs[attribIndex];
+ qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+ attribIndex = ATTR_INDEX_TANGENT2;
+ vAtb = &surface->vao->attribs[attribIndex];
+ qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+
+ if (!glRefConfig.vertexArrayObject)
+ {
+ attribIndex = ATTR_INDEX_TEXCOORD;
+ vAtb = &surface->vao->attribs[attribIndex];
+ qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset));
+ }
+ }
+
+ RB_EndSurface();
+
+ // So we don't lerp surfaces that shouldn't be lerped
+ glState.vertexAnimation = false;
+}
+
+static void RB_SurfaceSkip( void *surf ) {
+}
+
+
+void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = {
+ (void(*)(void*))RB_SurfaceBad, // SF_BAD,
+ (void(*)(void*))RB_SurfaceSkip, // SF_SKIP,
+ (void(*)(void*))RB_SurfaceFace, // SF_FACE,
+ (void(*)(void*))RB_SurfaceGrid, // SF_GRID,
+ (void(*)(void*))RB_SurfaceTriangles, // SF_TRIANGLES,
+ (void(*)(void*))RB_SurfacePolychain, // SF_POLY,
+ (void(*)(void*))RB_SurfaceMesh, // SF_MDV,
+ (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR,
+ (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM,
+ (void(*)(void*))RB_SurfaceFlare, // SF_FLARE,
+ (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY
+ (void(*)(void*))RB_SurfaceVaoMdvMesh, // SF_VAO_MDVMESH
+};
diff --git a/src/renderergl2/tr_vbo.cpp b/src/renderergl2/tr_vbo.cpp
new file mode 100644
index 0000000..58836cd
--- /dev/null
+++ b/src/renderergl2/tr_vbo.cpp
@@ -0,0 +1,945 @@
+/*
+===========================================================================
+Copyright (C) 2007-2009 Robert Beckebans <trebor_7@users.sourceforge.net>
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// tr_vbo.c
+#include "tr_local.h"
+
+
+void R_VaoPackTangent(int16_t *out, vec4_t v)
+{
+ out[0] = v[0] * 32767.0f + (v[0] > 0.0f ? 0.5f : -0.5f);
+ out[1] = v[1] * 32767.0f + (v[1] > 0.0f ? 0.5f : -0.5f);
+ out[2] = v[2] * 32767.0f + (v[2] > 0.0f ? 0.5f : -0.5f);
+ out[3] = v[3] * 32767.0f + (v[3] > 0.0f ? 0.5f : -0.5f);
+}
+
+void R_VaoPackNormal(int16_t *out, vec3_t v)
+{
+ out[0] = v[0] * 32767.0f + (v[0] > 0.0f ? 0.5f : -0.5f);
+ out[1] = v[1] * 32767.0f + (v[1] > 0.0f ? 0.5f : -0.5f);
+ out[2] = v[2] * 32767.0f + (v[2] > 0.0f ? 0.5f : -0.5f);
+ out[3] = 0;
+}
+
+void R_VaoPackColor(uint16_t *out, vec4_t c)
+{
+ out[0] = c[0] * 65535.0f + 0.5f;
+ out[1] = c[1] * 65535.0f + 0.5f;
+ out[2] = c[2] * 65535.0f + 0.5f;
+ out[3] = c[3] * 65535.0f + 0.5f;
+}
+
+void R_VaoUnpackTangent(vec4_t v, int16_t *pack)
+{
+ v[0] = pack[0] / 32767.0f;
+ v[1] = pack[1] / 32767.0f;
+ v[2] = pack[2] / 32767.0f;
+ v[3] = pack[3] / 32767.0f;
+}
+
+void R_VaoUnpackNormal(vec3_t v, int16_t *pack)
+{
+ v[0] = pack[0] / 32767.0f;
+ v[1] = pack[1] / 32767.0f;
+ v[2] = pack[2] / 32767.0f;
+}
+
+void Vao_SetVertexPointers(vao_t *vao)
+{
+ int attribIndex;
+
+ // set vertex pointers
+ for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++)
+ {
+ uint32_t attribBit = 1 << attribIndex;
+ vaoAttrib_t *vAtb = &vao->attribs[attribIndex];
+
+ if (vAtb->enabled)
+ {
+ qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset));
+ if (glRefConfig.vertexArrayObject || !(glState.vertexAttribsEnabled & attribBit))
+ qglEnableVertexAttribArray(attribIndex);
+
+ if (!glRefConfig.vertexArrayObject || vao == tess.vao)
+ glState.vertexAttribsEnabled |= attribBit;
+ }
+ else
+ {
+ // don't disable vertex attribs when using vertex array objects
+ // Vao_SetVertexPointers is only called during init when using VAOs, and vertex attribs start disabled anyway
+ if (!glRefConfig.vertexArrayObject && (glState.vertexAttribsEnabled & attribBit))
+ qglDisableVertexAttribArray(attribIndex);
+
+ if (!glRefConfig.vertexArrayObject || vao == tess.vao)
+ glState.vertexAttribsEnabled &= ~attribBit;
+ }
+ }
+}
+
+/*
+============
+R_CreateVao
+============
+*/
+vao_t *R_CreateVao(const char *name, byte *vertexes, int vertexesSize, byte *indexes, int indexesSize, vaoUsage_t usage)
+{
+ vao_t *vao;
+ int glUsage;
+
+ switch (usage)
+ {
+ case VAO_USAGE_STATIC:
+ glUsage = GL_STATIC_DRAW;
+ break;
+
+ case VAO_USAGE_DYNAMIC:
+ glUsage = GL_DYNAMIC_DRAW;
+ break;
+
+ default:
+ Com_Error(ERR_FATAL, "bad vaoUsage_t given: %i", usage);
+ return NULL;
+ }
+
+ if(strlen(name) >= MAX_QPATH)
+ {
+ ri.Error(ERR_DROP, "R_CreateVao: \"%s\" is too long", name);
+ }
+
+ if ( tr.numVaos == MAX_VAOS ) {
+ ri.Error( ERR_DROP, "R_CreateVao: MAX_VAOS hit");
+ }
+
+ R_IssuePendingRenderCommands();
+
+ vao = tr.vaos[tr.numVaos] = (vao_t*)ri.Hunk_Alloc(sizeof(*vao), h_low);
+ tr.numVaos++;
+
+ memset(vao, 0, sizeof(*vao));
+
+ Q_strncpyz(vao->name, name, sizeof(vao->name));
+
+
+ if (glRefConfig.vertexArrayObject)
+ {
+ qglGenVertexArrays(1, &vao->vao);
+ qglBindVertexArray(vao->vao);
+ }
+
+
+ vao->vertexesSize = vertexesSize;
+
+ qglGenBuffers(1, &vao->vertexesVBO);
+
+ qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO);
+ qglBufferData(GL_ARRAY_BUFFER, vertexesSize, vertexes, glUsage);
+
+
+ vao->indexesSize = indexesSize;
+
+ qglGenBuffers(1, &vao->indexesIBO);
+
+ qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO);
+ qglBufferData(GL_ELEMENT_ARRAY_BUFFER, indexesSize, indexes, glUsage);
+
+
+ glState.currentVao = vao;
+
+ GL_CheckErrors();
+
+ return vao;
+}
+
+/*
+============
+R_CreateVao2
+============
+*/
+vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int numIndexes, glIndex_t *indexes)
+{
+ vao_t *vao;
+ int i;
+
+ byte *data;
+ int dataSize;
+ int dataOfs;
+
+ int glUsage = GL_STATIC_DRAW;
+
+ if(!numVertexes || !numIndexes)
+ return NULL;
+
+ if(strlen(name) >= MAX_QPATH)
+ {
+ ri.Error(ERR_DROP, "R_CreateVao2: \"%s\" is too long", name);
+ }
+
+ if ( tr.numVaos == MAX_VAOS ) {
+ ri.Error( ERR_DROP, "R_CreateVao2: MAX_VAOS hit");
+ }
+
+ R_IssuePendingRenderCommands();
+
+ vao = tr.vaos[tr.numVaos] = (vao_t*)ri.Hunk_Alloc(sizeof(*vao), h_low);
+ tr.numVaos++;
+
+ memset(vao, 0, sizeof(*vao));
+
+ Q_strncpyz(vao->name, name, sizeof(vao->name));
+
+ // since these vertex attributes are never altered, interleave them
+ vao->attribs[ATTR_INDEX_POSITION ].enabled = 1;
+ vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1;
+ vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
+ vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1;
+ vao->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1;
+ vao->attribs[ATTR_INDEX_COLOR ].enabled = 1;
+ vao->attribs[ATTR_INDEX_LIGHTDIRECTION].enabled = 1;
+
+ vao->attribs[ATTR_INDEX_POSITION ].count = 3;
+ vao->attribs[ATTR_INDEX_NORMAL ].count = 4;
+ vao->attribs[ATTR_INDEX_TANGENT ].count = 4;
+ vao->attribs[ATTR_INDEX_TEXCOORD ].count = 2;
+ vao->attribs[ATTR_INDEX_LIGHTCOORD ].count = 2;
+ vao->attribs[ATTR_INDEX_COLOR ].count = 4;
+ vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4;
+
+ vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT;
+ vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT;
+ vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT;
+ vao->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT;
+ vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = GL_FLOAT;
+ vao->attribs[ATTR_INDEX_COLOR ].type = GL_UNSIGNED_SHORT;
+ vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT;
+
+ vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE;
+ vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE;
+ vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
+ vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE;
+ vao->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE;
+ vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_TRUE;
+ vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE;
+
+ vao->attribs[ATTR_INDEX_POSITION ].offset = 0; dataSize = sizeof(verts[0].xyz);
+ vao->attribs[ATTR_INDEX_NORMAL ].offset = dataSize; dataSize += sizeof(verts[0].normal);
+ vao->attribs[ATTR_INDEX_TANGENT ].offset = dataSize; dataSize += sizeof(verts[0].tangent);
+ vao->attribs[ATTR_INDEX_TEXCOORD ].offset = dataSize; dataSize += sizeof(verts[0].st);
+ vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = dataSize; dataSize += sizeof(verts[0].lightmap);
+ vao->attribs[ATTR_INDEX_COLOR ].offset = dataSize; dataSize += sizeof(verts[0].color);
+ vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(verts[0].lightdir);
+
+ vao->attribs[ATTR_INDEX_POSITION ].stride = dataSize;
+ vao->attribs[ATTR_INDEX_NORMAL ].stride = dataSize;
+ vao->attribs[ATTR_INDEX_TANGENT ].stride = dataSize;
+ vao->attribs[ATTR_INDEX_TEXCOORD ].stride = dataSize;
+ vao->attribs[ATTR_INDEX_LIGHTCOORD ].stride = dataSize;
+ vao->attribs[ATTR_INDEX_COLOR ].stride = dataSize;
+ vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = dataSize;
+
+
+ if (glRefConfig.vertexArrayObject)
+ {
+ qglGenVertexArrays(1, &vao->vao);
+ qglBindVertexArray(vao->vao);
+ }
+
+
+ // create VBO
+ dataSize *= numVertexes;
+ data = (byte*)ri.Hunk_AllocateTempMemory(dataSize);
+ dataOfs = 0;
+
+ for (i = 0; i < numVertexes; i++)
+ {
+ // xyz
+ memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz));
+ dataOfs += sizeof(verts[i].xyz);
+
+ // normal
+ memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal));
+ dataOfs += sizeof(verts[i].normal);
+
+ // tangent
+ memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent));
+ dataOfs += sizeof(verts[i].tangent);
+
+ // texcoords
+ memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st));
+ dataOfs += sizeof(verts[i].st);
+
+ // lightmap texcoords
+ memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap));
+ dataOfs += sizeof(verts[i].lightmap);
+
+ // colors
+ memcpy(data + dataOfs, &verts[i].color, sizeof(verts[i].color));
+ dataOfs += sizeof(verts[i].color);
+
+ // light directions
+ memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir));
+ dataOfs += sizeof(verts[i].lightdir);
+ }
+
+ vao->vertexesSize = dataSize;
+
+ qglGenBuffers(1, &vao->vertexesVBO);
+
+ qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO);
+ qglBufferData(GL_ARRAY_BUFFER, vao->vertexesSize, data, glUsage);
+
+
+ // create IBO
+ vao->indexesSize = numIndexes * sizeof(glIndex_t);
+
+ qglGenBuffers(1, &vao->indexesIBO);
+
+ qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO);
+ qglBufferData(GL_ELEMENT_ARRAY_BUFFER, vao->indexesSize, indexes, glUsage);
+
+
+ Vao_SetVertexPointers(vao);
+
+
+ glState.currentVao = vao;
+
+ GL_CheckErrors();
+
+ ri.Hunk_FreeTempMemory(data);
+
+ return vao;
+}
+
+
+/*
+============
+R_BindVao
+============
+*/
+void R_BindVao(vao_t * vao)
+{
+ if(!vao)
+ {
+ //R_BindNullVao();
+ ri.Error(ERR_DROP, "R_BindVao: NULL vao");
+ return;
+ }
+
+ if(r_logFile->integer)
+ {
+ // don't just call LogComment, or we will get a call to va() every frame!
+ GLimp_LogComment((char*)va("--- R_BindVao( %s ) ---\n", vao->name));
+ }
+
+ if(glState.currentVao != vao)
+ {
+ glState.currentVao = vao;
+
+ glState.vertexAttribsInterpolation = 0;
+ glState.vertexAnimation = false;
+ backEnd.pc.c_vaoBinds++;
+
+ if (glRefConfig.vertexArrayObject)
+ {
+ qglBindVertexArray(vao->vao);
+
+ // Intel Graphics doesn't save GL_ELEMENT_ARRAY_BUFFER binding with VAO binding.
+ if (glRefConfig.intelGraphics || vao == tess.vao)
+ qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO);
+
+ // tess VAO always has buffers bound
+ if (vao == tess.vao)
+ qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO);
+ }
+ else
+ {
+ qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO);
+ qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO);
+
+ // tess VAO doesn't have vertex pointers set until data is uploaded
+ if (vao != tess.vao)
+ Vao_SetVertexPointers(vao);
+ }
+ }
+}
+
+/*
+============
+R_BindNullVao
+============
+*/
+void R_BindNullVao(void)
+{
+ GLimp_LogComment("--- R_BindNullVao ---\n");
+
+ if(glState.currentVao)
+ {
+ if (glRefConfig.vertexArrayObject)
+ {
+ qglBindVertexArray(0);
+
+ // why you no save GL_ELEMENT_ARRAY_BUFFER binding, Intel?
+ if (1) qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ else
+ {
+ qglBindBuffer(GL_ARRAY_BUFFER, 0);
+ qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ glState.currentVao = NULL;
+ }
+
+ GL_CheckErrors();
+}
+
+
+/*
+============
+R_InitVaos
+============
+*/
+void R_InitVaos(void)
+{
+ int vertexesSize, indexesSize;
+ int offset;
+
+ ri.Printf(PRINT_ALL, "------- R_InitVaos -------\n");
+
+ tr.numVaos = 0;
+
+ vertexesSize = sizeof(tess.xyz[0]);
+ vertexesSize += sizeof(tess.normal[0]);
+ vertexesSize += sizeof(tess.tangent[0]);
+ vertexesSize += sizeof(tess.color[0]);
+ vertexesSize += sizeof(tess.texCoords[0]);
+ vertexesSize += sizeof(tess.lightCoords[0]);
+ vertexesSize += sizeof(tess.lightdir[0]);
+ vertexesSize *= SHADER_MAX_VERTEXES;
+
+ indexesSize = sizeof(tess.indexes[0]) * SHADER_MAX_INDEXES;
+
+ tess.vao = R_CreateVao("tessVertexArray_VAO", NULL, vertexesSize, NULL, indexesSize, VAO_USAGE_DYNAMIC);
+
+ offset = 0;
+
+ tess.vao->attribs[ATTR_INDEX_POSITION ].enabled = 1;
+ tess.vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1;
+ tess.vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
+ tess.vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1;
+ tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1;
+ tess.vao->attribs[ATTR_INDEX_COLOR ].enabled = 1;
+ tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].enabled = 1;
+
+ tess.vao->attribs[ATTR_INDEX_POSITION ].count = 3;
+ tess.vao->attribs[ATTR_INDEX_NORMAL ].count = 4;
+ tess.vao->attribs[ATTR_INDEX_TANGENT ].count = 4;
+ tess.vao->attribs[ATTR_INDEX_TEXCOORD ].count = 2;
+ tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].count = 2;
+ tess.vao->attribs[ATTR_INDEX_COLOR ].count = 4;
+ tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4;
+
+ tess.vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT;
+ tess.vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT;
+ tess.vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT;
+ tess.vao->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT;
+ tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = GL_FLOAT;
+ tess.vao->attribs[ATTR_INDEX_COLOR ].type = GL_UNSIGNED_SHORT;
+ tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT;
+
+ tess.vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE;
+ tess.vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE;
+ tess.vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
+ tess.vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE;
+ tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE;
+ tess.vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_TRUE;
+ tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE;
+
+ tess.vao->attribs[ATTR_INDEX_POSITION ].offset = offset; offset += sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES;
+ tess.vao->attribs[ATTR_INDEX_NORMAL ].offset = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES;
+ tess.vao->attribs[ATTR_INDEX_TANGENT ].offset = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES;
+ tess.vao->attribs[ATTR_INDEX_TEXCOORD ].offset = offset; offset += sizeof(tess.texCoords[0]) * SHADER_MAX_VERTEXES;
+ tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = offset; offset += sizeof(tess.lightCoords[0]) * SHADER_MAX_VERTEXES;
+ tess.vao->attribs[ATTR_INDEX_COLOR ].offset = offset; offset += sizeof(tess.color[0]) * SHADER_MAX_VERTEXES;
+ tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = offset;
+
+ tess.vao->attribs[ATTR_INDEX_POSITION ].stride = sizeof(tess.xyz[0]);
+ tess.vao->attribs[ATTR_INDEX_NORMAL ].stride = sizeof(tess.normal[0]);
+ tess.vao->attribs[ATTR_INDEX_TANGENT ].stride = sizeof(tess.tangent[0]);
+ tess.vao->attribs[ATTR_INDEX_TEXCOORD ].stride = sizeof(tess.texCoords[0]);
+ tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].stride = sizeof(tess.lightCoords[0]);
+ tess.vao->attribs[ATTR_INDEX_COLOR ].stride = sizeof(tess.color[0]);
+ tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = sizeof(tess.lightdir[0]);
+
+ tess.attribPointers[ATTR_INDEX_POSITION] = tess.xyz;
+ tess.attribPointers[ATTR_INDEX_NORMAL] = tess.normal;
+ tess.attribPointers[ATTR_INDEX_TANGENT] = tess.tangent;
+ tess.attribPointers[ATTR_INDEX_TEXCOORD] = tess.texCoords;
+ tess.attribPointers[ATTR_INDEX_LIGHTCOORD] = tess.lightCoords;
+ tess.attribPointers[ATTR_INDEX_COLOR] = tess.color;
+ tess.attribPointers[ATTR_INDEX_LIGHTDIRECTION] = tess.lightdir;
+
+ Vao_SetVertexPointers(tess.vao);
+
+ R_BindNullVao();
+
+ VaoCache_Init();
+
+ GL_CheckErrors();
+}
+
+/*
+============
+R_ShutdownVaos
+============
+*/
+void R_ShutdownVaos(void)
+{
+ int i;
+ vao_t *vao;
+
+ ri.Printf(PRINT_ALL, "------- R_ShutdownVaos -------\n");
+
+ R_BindNullVao();
+
+ for(i = 0; i < tr.numVaos; i++)
+ {
+ vao = tr.vaos[i];
+
+ if(vao->vao)
+ qglDeleteVertexArrays(1, &vao->vao);
+
+ if(vao->vertexesVBO)
+ {
+ qglDeleteBuffers(1, &vao->vertexesVBO);
+ }
+
+ if(vao->indexesIBO)
+ {
+ qglDeleteBuffers(1, &vao->indexesIBO);
+ }
+ }
+
+ tr.numVaos = 0;
+}
+
+/*
+============
+R_VaoList_f
+============
+*/
+void R_VaoList_f(void)
+{
+ int i;
+ vao_t *vao;
+ int vertexesSize = 0;
+ int indexesSize = 0;
+
+ ri.Printf(PRINT_ALL, " size name\n");
+ ri.Printf(PRINT_ALL, "----------------------------------------------------------\n");
+
+ for(i = 0; i < tr.numVaos; i++)
+ {
+ vao = tr.vaos[i];
+
+ ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vao->vertexesSize / (1024 * 1024),
+ (vao->vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vao->name);
+
+ vertexesSize += vao->vertexesSize;
+ }
+
+ for(i = 0; i < tr.numVaos; i++)
+ {
+ vao = tr.vaos[i];
+
+ ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vao->indexesSize / (1024 * 1024),
+ (vao->indexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vao->name);
+
+ indexesSize += vao->indexesSize;
+ }
+
+ ri.Printf(PRINT_ALL, " %i total VAOs\n", tr.numVaos);
+ ri.Printf(PRINT_ALL, " %d.%02d MB total vertices memory\n", vertexesSize / (1024 * 1024),
+ (vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024));
+ ri.Printf(PRINT_ALL, " %d.%02d MB total triangle indices memory\n", indexesSize / (1024 * 1024),
+ (indexesSize % (1024 * 1024)) * 100 / (1024 * 1024));
+}
+
+
+/*
+==============
+RB_UpdateTessVao
+
+Adapted from Tess_UpdateVBOs from xreal
+
+Update the default VAO to replace the client side vertex arrays
+==============
+*/
+void RB_UpdateTessVao(unsigned int attribBits)
+{
+ GLimp_LogComment("--- RB_UpdateTessVao ---\n");
+
+ backEnd.pc.c_dynamicVaoDraws++;
+
+ // update the default VAO
+ if(tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES && tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES)
+ {
+ int attribIndex;
+ int attribUpload;
+
+ R_BindVao(tess.vao);
+
+ // orphan old vertex buffer so we don't stall on it
+ qglBufferData(GL_ARRAY_BUFFER, tess.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW);
+
+ // if nothing to set, set everything
+ if(!(attribBits & ATTR_BITS))
+ attribBits = ATTR_BITS;
+
+ attribUpload = attribBits;
+
+ for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++)
+ {
+ uint32_t attribBit = 1 << attribIndex;
+ vaoAttrib_t *vAtb = &tess.vao->attribs[attribIndex];
+
+ if (attribUpload & attribBit)
+ {
+ // note: tess has a VBO where stride == size
+ qglBufferSubData(GL_ARRAY_BUFFER, vAtb->offset, tess.numVertexes * vAtb->stride, tess.attribPointers[attribIndex]);
+ }
+
+ if (attribBits & attribBit)
+ {
+ if (!glRefConfig.vertexArrayObject)
+ qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset));
+
+ if (!(glState.vertexAttribsEnabled & attribBit))
+ {
+ qglEnableVertexAttribArray(attribIndex);
+ glState.vertexAttribsEnabled |= attribBit;
+ }
+ }
+ else
+ {
+ if ((glState.vertexAttribsEnabled & attribBit))
+ {
+ qglDisableVertexAttribArray(attribIndex);
+ glState.vertexAttribsEnabled &= ~attribBit;
+ }
+ }
+ }
+
+ // orphan old index buffer so we don't stall on it
+ qglBufferData(GL_ELEMENT_ARRAY_BUFFER, tess.vao->indexesSize, NULL, GL_DYNAMIC_DRAW);
+
+ qglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes);
+ }
+}
+
+typedef struct bufferCacheEntry_s
+{
+ void *data;
+ int size;
+ int bufferOffset;
+}
+bufferCacheEntry_t;
+
+typedef struct queuedSurface_s
+{
+ srfVert_t *vertexes;
+ int numVerts;
+ glIndex_t *indexes;
+ int numIndexes;
+}
+queuedSurface_t;
+
+#define VAOCACHE_MAX_BUFFERED_SURFACES (1 << 16)
+#define VAOCACHE_VERTEX_BUFFER_SIZE 12 * 1024 * 1024
+#define VAOCACHE_INDEX_BUFFER_SIZE 12 * 1024 * 1024
+
+#define VAOCACHE_MAX_QUEUED_VERTEXES (1 << 16)
+#define VAOCACHE_MAX_QUEUED_INDEXES (VAOCACHE_MAX_QUEUED_VERTEXES * 6 / 4)
+
+#define VAOCACHE_MAX_QUEUED_SURFACES 4096
+
+static struct
+{
+ vao_t *vao;
+ bufferCacheEntry_t indexEntries[VAOCACHE_MAX_BUFFERED_SURFACES];
+ int indexChainLengths[VAOCACHE_MAX_BUFFERED_SURFACES];
+ int numIndexEntries;
+ int vertexOffset;
+ int indexOffset;
+
+ srfVert_t vertexes[VAOCACHE_MAX_QUEUED_VERTEXES];
+ int vertexCommitSize;
+
+ glIndex_t indexes[VAOCACHE_MAX_QUEUED_INDEXES];
+ int indexCommitSize;
+
+ queuedSurface_t surfaceQueue[VAOCACHE_MAX_QUEUED_SURFACES];
+ int numSurfacesQueued;
+}
+vc = { 0 };
+
+void VaoCache_Commit(void)
+{
+ bufferCacheEntry_t *entry1;
+ queuedSurface_t *surf, *end = vc.surfaceQueue + vc.numSurfacesQueued;
+
+ R_BindVao(vc.vao);
+
+ // search entire cache for exact chain of indexes
+ // FIXME: use faster search
+ for (entry1 = vc.indexEntries; entry1 < vc.indexEntries + vc.numIndexEntries;)
+ {
+ int chainLength = vc.indexChainLengths[entry1 - vc.indexEntries];
+
+ if (chainLength == vc.numSurfacesQueued)
+ {
+ bufferCacheEntry_t *entry2 = entry1;
+ for (surf = vc.surfaceQueue; surf < end; surf++, entry2++)
+ {
+ if (surf->indexes != entry2->data || (surf->numIndexes * sizeof(glIndex_t)) != entry2->size)
+ break;
+ }
+
+ if (surf == end)
+ break;
+ }
+
+ entry1 += chainLength;
+ }
+
+ // if found, use that
+ if (entry1 < vc.indexEntries + vc.numIndexEntries)
+ {
+ tess.firstIndex = entry1->bufferOffset / sizeof(glIndex_t);
+ //ri.Printf(PRINT_ALL, "firstIndex %d numIndexes %d\n", tess.firstIndex, tess.numIndexes);
+ //ri.Printf(PRINT_ALL, "vc.numIndexEntries %d\n", vc.numIndexEntries);
+ }
+ // if not, rebuffer all the indexes but reuse any existing vertexes
+ else
+ {
+ srfVert_t *dstVertex = vc.vertexes;
+ glIndex_t *dstIndex = vc.indexes;
+ int *indexChainLength = vc.indexChainLengths + vc.numIndexEntries;
+
+ tess.firstIndex = vc.indexOffset / sizeof(glIndex_t);
+ vc.vertexCommitSize = 0;
+ vc.indexCommitSize = 0;
+ for (surf = vc.surfaceQueue; surf < end; surf++)
+ {
+ srfVert_t *srcVertex = surf->vertexes;
+ glIndex_t *srcIndex = surf->indexes;
+ int vertexesSize = surf->numVerts * sizeof(srfVert_t);
+ int indexesSize = surf->numIndexes * sizeof(glIndex_t);
+ int i, indexOffset = (vc.vertexOffset + vc.vertexCommitSize) / sizeof(srfVert_t);
+
+ for (i = 0; i < surf->numVerts; i++)
+ *dstVertex++ = *srcVertex++;
+
+ vc.vertexCommitSize += vertexesSize;
+
+ entry1 = vc.indexEntries + vc.numIndexEntries;
+ entry1->data = surf->indexes;
+ entry1->size = indexesSize;
+ entry1->bufferOffset = vc.indexOffset + vc.indexCommitSize;
+ vc.numIndexEntries++;
+
+ *indexChainLength++ = ((surf == vc.surfaceQueue) ? vc.numSurfacesQueued : 0);
+
+ for (i = 0; i < surf->numIndexes; i++)
+ *dstIndex++ = *srcIndex++ + indexOffset;
+
+ vc.indexCommitSize += indexesSize;
+ }
+
+ //ri.Printf(PRINT_ALL, "committing %d to %d, %d to %d\n", vc.vertexCommitSize, vc.vertexOffset, vc.indexCommitSize, vc.indexOffset);
+
+ if (vc.vertexCommitSize)
+ {
+ qglBindBuffer(GL_ARRAY_BUFFER, vc.vao->vertexesVBO);
+ qglBufferSubData(GL_ARRAY_BUFFER, vc.vertexOffset, vc.vertexCommitSize, vc.vertexes);
+ vc.vertexOffset += vc.vertexCommitSize;
+ }
+
+ if (vc.indexCommitSize)
+ {
+ qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesIBO);
+ qglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, vc.indexOffset, vc.indexCommitSize, vc.indexes);
+ vc.indexOffset += vc.indexCommitSize;
+ }
+ }
+}
+
+void VaoCache_Init(void)
+{
+ srfVert_t vert;
+ int dataSize;
+
+ vc.vao = R_CreateVao("VaoCache", NULL, VAOCACHE_VERTEX_BUFFER_SIZE, NULL, VAOCACHE_INDEX_BUFFER_SIZE, VAO_USAGE_DYNAMIC);
+
+ vc.vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
+ vc.vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
+ vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].enabled = 1;
+ vc.vao->attribs[ATTR_INDEX_NORMAL].enabled = 1;
+ vc.vao->attribs[ATTR_INDEX_TANGENT].enabled = 1;
+ vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].enabled = 1;
+ vc.vao->attribs[ATTR_INDEX_COLOR].enabled = 1;
+
+ vc.vao->attribs[ATTR_INDEX_POSITION].count = 3;
+ vc.vao->attribs[ATTR_INDEX_TEXCOORD].count = 2;
+ vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].count = 2;
+ vc.vao->attribs[ATTR_INDEX_NORMAL].count = 4;
+ vc.vao->attribs[ATTR_INDEX_TANGENT].count = 4;
+ vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4;
+ vc.vao->attribs[ATTR_INDEX_COLOR].count = 4;
+
+ vc.vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
+ vc.vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT;
+ vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].type = GL_FLOAT;
+ vc.vao->attribs[ATTR_INDEX_NORMAL].type = GL_SHORT;
+ vc.vao->attribs[ATTR_INDEX_TANGENT].type = GL_SHORT;
+ vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT;
+ vc.vao->attribs[ATTR_INDEX_COLOR].type = GL_UNSIGNED_SHORT;
+
+ vc.vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
+ vc.vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
+ vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].normalized = GL_FALSE;
+ vc.vao->attribs[ATTR_INDEX_NORMAL].normalized = GL_TRUE;
+ vc.vao->attribs[ATTR_INDEX_TANGENT].normalized = GL_TRUE;
+ vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE;
+ vc.vao->attribs[ATTR_INDEX_COLOR].normalized = GL_TRUE;
+
+ vc.vao->attribs[ATTR_INDEX_POSITION].offset = 0; dataSize = sizeof(vert.xyz);
+ vc.vao->attribs[ATTR_INDEX_TEXCOORD].offset = dataSize; dataSize += sizeof(vert.st);
+ vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].offset = dataSize; dataSize += sizeof(vert.lightmap);
+ vc.vao->attribs[ATTR_INDEX_NORMAL].offset = dataSize; dataSize += sizeof(vert.normal);
+ vc.vao->attribs[ATTR_INDEX_TANGENT].offset = dataSize; dataSize += sizeof(vert.tangent);
+ vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(vert.lightdir);
+ vc.vao->attribs[ATTR_INDEX_COLOR].offset = dataSize; dataSize += sizeof(vert.color);
+
+ vc.vao->attribs[ATTR_INDEX_POSITION].stride = dataSize;
+ vc.vao->attribs[ATTR_INDEX_TEXCOORD].stride = dataSize;
+ vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].stride = dataSize;
+ vc.vao->attribs[ATTR_INDEX_NORMAL].stride = dataSize;
+ vc.vao->attribs[ATTR_INDEX_TANGENT].stride = dataSize;
+ vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = dataSize;
+ vc.vao->attribs[ATTR_INDEX_COLOR].stride = dataSize;
+
+ Vao_SetVertexPointers(vc.vao);
+
+ vc.numIndexEntries = 0;
+ vc.vertexOffset = 0;
+ vc.indexOffset = 0;
+ vc.vertexCommitSize = 0;
+ vc.indexCommitSize = 0;
+ vc.numSurfacesQueued = 0;
+}
+
+void VaoCache_BindVao(void)
+{
+ R_BindVao(vc.vao);
+}
+
+void VaoCache_CheckAdd(bool *endSurface, bool *recycleVertexBuffer, bool *recycleIndexBuffer, int numVerts, int numIndexes)
+{
+ int vertexesSize = sizeof(srfVert_t) * numVerts;
+ int indexesSize = sizeof(glIndex_t) * numIndexes;
+
+ if (vc.vao->vertexesSize < vc.vertexOffset + vc.vertexCommitSize + vertexesSize)
+ {
+ //ri.Printf(PRINT_ALL, "out of space in vertex cache: %d < %d + %d + %d\n", vc.vao->vertexesSize, vc.vertexOffset, vc.vertexCommitSize, vertexesSize);
+ *recycleVertexBuffer = true;
+ *recycleIndexBuffer = true;
+ *endSurface = true;
+ }
+
+ if (vc.vao->indexesSize < vc.indexOffset + vc.indexCommitSize + indexesSize)
+ {
+ //ri.Printf(PRINT_ALL, "out of space in index cache\n");
+ *recycleIndexBuffer = true;
+ *endSurface = true;
+ }
+
+ if (vc.numIndexEntries + vc.numSurfacesQueued >= VAOCACHE_MAX_BUFFERED_SURFACES)
+ {
+ //ri.Printf(PRINT_ALL, "out of surfaces in index cache\n");
+ *recycleIndexBuffer = true;
+ *endSurface = true;
+ }
+
+ if (vc.numSurfacesQueued == VAOCACHE_MAX_QUEUED_SURFACES)
+ {
+ //ri.Printf(PRINT_ALL, "out of queued surfaces\n");
+ *endSurface = true;
+ }
+
+ if (VAOCACHE_MAX_QUEUED_VERTEXES * sizeof(srfVert_t) < vc.vertexCommitSize + vertexesSize)
+ {
+ //ri.Printf(PRINT_ALL, "out of queued vertexes\n");
+ *endSurface = true;
+ }
+
+ if (VAOCACHE_MAX_QUEUED_INDEXES * sizeof(glIndex_t) < vc.indexCommitSize + indexesSize)
+ {
+ //ri.Printf(PRINT_ALL, "out of queued indexes\n");
+ *endSurface = true;
+ }
+}
+
+void VaoCache_RecycleVertexBuffer(void)
+{
+ qglBindBuffer(GL_ARRAY_BUFFER, vc.vao->vertexesVBO);
+ qglBufferData(GL_ARRAY_BUFFER, vc.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW);
+ vc.vertexOffset = 0;
+}
+
+void VaoCache_RecycleIndexBuffer(void)
+{
+ qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesIBO);
+ qglBufferData(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesSize, NULL, GL_DYNAMIC_DRAW);
+ vc.indexOffset = 0;
+ vc.numIndexEntries = 0;
+}
+
+void VaoCache_InitNewSurfaceSet(void)
+{
+ vc.vertexCommitSize = 0;
+ vc.indexCommitSize = 0;
+ vc.numSurfacesQueued = 0;
+}
+
+void VaoCache_AddSurface(srfVert_t *verts, int numVerts, glIndex_t *indexes, int numIndexes)
+{
+ int vertexesSize = sizeof(srfVert_t) * numVerts;
+ int indexesSize = sizeof(glIndex_t) * numIndexes;
+ queuedSurface_t *queueEntry = vc.surfaceQueue + vc.numSurfacesQueued;
+ queueEntry->vertexes = verts;
+ queueEntry->numVerts = numVerts;
+ queueEntry->indexes = indexes;
+ queueEntry->numIndexes = numIndexes;
+ vc.numSurfacesQueued++;
+
+ vc.vertexCommitSize += vertexesSize;
+ vc.indexCommitSize += indexesSize;
+}
diff --git a/src/renderergl2/tr_world.cpp b/src/renderergl2/tr_world.cpp
new file mode 100644
index 0000000..0361a88
--- /dev/null
+++ b/src/renderergl2/tr_world.cpp
@@ -0,0 +1,811 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#include "tr_local.h"
+
+
+
+/*
+================
+R_CullSurface
+
+Tries to cull surfaces before they are lighted or
+added to the sorting list.
+================
+*/
+static bool R_CullSurface( msurface_t *surf ) {
+ if ( r_nocull->integer || surf->cullinfo.type == CULLINFO_NONE) {
+ return false;
+ }
+
+ if ( *surf->data == SF_GRID && r_nocurves->integer ) {
+ return true;
+ }
+
+ if (surf->cullinfo.type & CULLINFO_PLANE)
+ {
+ // Only true for SF_FACE, so treat like its own function
+ float d;
+ cullType_t ct;
+
+ if ( !r_facePlaneCull->integer ) {
+ return false;
+ }
+
+ ct = surf->shader->cullType;
+
+ if (ct == CT_TWO_SIDED)
+ {
+ return false;
+ }
+
+ // don't cull for depth shadow
+ /*
+ if ( tr.viewParms.flags & VPF_DEPTHSHADOW )
+ {
+ return false;
+ }
+ */
+
+ // shadowmaps draw back surfaces
+ if ( tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW) )
+ {
+ if (ct == CT_FRONT_SIDED)
+ {
+ ct = CT_BACK_SIDED;
+ }
+ else
+ {
+ ct = CT_FRONT_SIDED;
+ }
+ }
+
+ // do proper cull for orthographic projection
+ if (tr.viewParms.flags & VPF_ORTHOGRAPHIC) {
+ d = DotProduct(tr.viewParms.orientation.axis[0], surf->cullinfo.plane.normal);
+ if ( ct == CT_FRONT_SIDED ) {
+ if (d > 0)
+ return true;
+ } else {
+ if (d < 0)
+ return true;
+ }
+ return false;
+ }
+
+ d = DotProduct (tr.orientation.viewOrigin, surf->cullinfo.plane.normal);
+
+ // don't cull exactly on the plane, because there are levels of rounding
+ // through the BSP, ICD, and hardware that may cause pixel gaps if an
+ // epsilon isn't allowed here
+ if ( ct == CT_FRONT_SIDED ) {
+ if ( d < surf->cullinfo.plane.dist - 8 ) {
+ return true;
+ }
+ } else {
+ if ( d > surf->cullinfo.plane.dist + 8 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ if (surf->cullinfo.type & CULLINFO_SPHERE)
+ {
+ int sphereCull;
+
+ if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) {
+ sphereCull = R_CullLocalPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius );
+ } else {
+ sphereCull = R_CullPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius );
+ }
+
+ if ( sphereCull == CULL_OUT )
+ {
+ return true;
+ }
+ }
+
+ if (surf->cullinfo.type & CULLINFO_BOX)
+ {
+ int boxCull;
+
+ if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) {
+ boxCull = R_CullLocalBox( surf->cullinfo.bounds );
+ } else {
+ boxCull = R_CullBox( surf->cullinfo.bounds );
+ }
+
+ if ( boxCull == CULL_OUT )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/*
+====================
+R_DlightSurface
+
+The given surface is going to be drawn, and it touches a leaf
+that is touched by one or more dlights, so try to throw out
+more dlights if possible.
+====================
+*/
+static int R_DlightSurface( msurface_t *surf, int dlightBits ) {
+ float d;
+ int i;
+ dlight_t *dl;
+
+ if ( surf->cullinfo.type & CULLINFO_PLANE )
+ {
+ for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
+ if ( ! ( dlightBits & ( 1 << i ) ) ) {
+ continue;
+ }
+ dl = &tr.refdef.dlights[i];
+ d = DotProduct( dl->origin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist;
+ if ( d < -dl->radius || d > dl->radius ) {
+ // dlight doesn't reach the plane
+ dlightBits &= ~( 1 << i );
+ }
+ }
+ }
+
+ if ( surf->cullinfo.type & CULLINFO_BOX )
+ {
+ for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
+ if ( ! ( dlightBits & ( 1 << i ) ) ) {
+ continue;
+ }
+ dl = &tr.refdef.dlights[i];
+ if ( dl->origin[0] - dl->radius > surf->cullinfo.bounds[1][0]
+ || dl->origin[0] + dl->radius < surf->cullinfo.bounds[0][0]
+ || dl->origin[1] - dl->radius > surf->cullinfo.bounds[1][1]
+ || dl->origin[1] + dl->radius < surf->cullinfo.bounds[0][1]
+ || dl->origin[2] - dl->radius > surf->cullinfo.bounds[1][2]
+ || dl->origin[2] + dl->radius < surf->cullinfo.bounds[0][2] ) {
+ // dlight doesn't reach the bounds
+ dlightBits &= ~( 1 << i );
+ }
+ }
+ }
+
+ if ( surf->cullinfo.type & CULLINFO_SPHERE )
+ {
+ for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
+ if ( ! ( dlightBits & ( 1 << i ) ) ) {
+ continue;
+ }
+ dl = &tr.refdef.dlights[i];
+ if (!SpheresIntersect(dl->origin, dl->radius, surf->cullinfo.localOrigin, surf->cullinfo.radius))
+ {
+ // dlight doesn't reach the bounds
+ dlightBits &= ~( 1 << i );
+ }
+ }
+ }
+
+ switch(*surf->data)
+ {
+ case SF_FACE:
+ case SF_GRID:
+ case SF_TRIANGLES:
+ ((srfBspSurface_t *)surf->data)->dlightBits = dlightBits;
+ break;
+
+ default:
+ dlightBits = 0;
+ break;
+ }
+
+ if ( dlightBits ) {
+ tr.pc.c_dlightSurfaces++;
+ } else {
+ tr.pc.c_dlightSurfacesCulled++;
+ }
+
+ return dlightBits;
+}
+
+/*
+====================
+R_PshadowSurface
+
+Just like R_DlightSurface, cull any we can
+====================
+*/
+static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) {
+ float d;
+ int i;
+ pshadow_t *ps;
+
+ if ( surf->cullinfo.type & CULLINFO_PLANE )
+ {
+ for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
+ if ( ! ( pshadowBits & ( 1 << i ) ) ) {
+ continue;
+ }
+ ps = &tr.refdef.pshadows[i];
+ d = DotProduct( ps->lightOrigin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist;
+ if ( d < -ps->lightRadius || d > ps->lightRadius ) {
+ // pshadow doesn't reach the plane
+ pshadowBits &= ~( 1 << i );
+ }
+ }
+ }
+
+ if ( surf->cullinfo.type & CULLINFO_BOX )
+ {
+ for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
+ if ( ! ( pshadowBits & ( 1 << i ) ) ) {
+ continue;
+ }
+ ps = &tr.refdef.pshadows[i];
+ if ( ps->lightOrigin[0] - ps->lightRadius > surf->cullinfo.bounds[1][0]
+ || ps->lightOrigin[0] + ps->lightRadius < surf->cullinfo.bounds[0][0]
+ || ps->lightOrigin[1] - ps->lightRadius > surf->cullinfo.bounds[1][1]
+ || ps->lightOrigin[1] + ps->lightRadius < surf->cullinfo.bounds[0][1]
+ || ps->lightOrigin[2] - ps->lightRadius > surf->cullinfo.bounds[1][2]
+ || ps->lightOrigin[2] + ps->lightRadius < surf->cullinfo.bounds[0][2]
+ || BoxOnPlaneSide(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1], &ps->cullPlane) == 2 ) {
+ // pshadow doesn't reach the bounds
+ pshadowBits &= ~( 1 << i );
+ }
+ }
+ }
+
+ if ( surf->cullinfo.type & CULLINFO_SPHERE )
+ {
+ for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
+ if ( ! ( pshadowBits & ( 1 << i ) ) ) {
+ continue;
+ }
+ ps = &tr.refdef.pshadows[i];
+ if (!SpheresIntersect(ps->viewOrigin, ps->viewRadius, surf->cullinfo.localOrigin, surf->cullinfo.radius)
+ || DotProduct( surf->cullinfo.localOrigin, ps->cullPlane.normal ) - ps->cullPlane.dist < -surf->cullinfo.radius)
+ {
+ // pshadow doesn't reach the bounds
+ pshadowBits &= ~( 1 << i );
+ }
+ }
+ }
+
+ switch(*surf->data)
+ {
+ case SF_FACE:
+ case SF_GRID:
+ case SF_TRIANGLES:
+ ((srfBspSurface_t *)surf->data)->pshadowBits = pshadowBits;
+ break;
+
+ default:
+ pshadowBits = 0;
+ break;
+ }
+
+ if ( pshadowBits ) {
+ //tr.pc.c_dlightSurfaces++;
+ }
+
+ return pshadowBits;
+}
+
+
+/*
+======================
+R_AddWorldSurface
+======================
+*/
+static void R_AddWorldSurface( msurface_t *surf, int dlightBits, int pshadowBits ) {
+ // FIXME: bmodel fog?
+
+ // try to cull before dlighting or adding
+ if ( R_CullSurface( surf ) ) {
+ return;
+ }
+
+ // check for dlighting
+ /*if ( dlightBits ) */{
+ dlightBits = R_DlightSurface( surf, dlightBits );
+ dlightBits = ( dlightBits != 0 );
+ }
+
+ // check for pshadows
+ /*if ( pshadowBits ) */{
+ pshadowBits = R_PshadowSurface( surf, pshadowBits);
+ pshadowBits = ( pshadowBits != 0 );
+ }
+
+ R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits, pshadowBits, surf->cubemapIndex );
+}
+
+/*
+=============================================================
+
+ BRUSH MODELS
+
+=============================================================
+*/
+
+/*
+=================
+R_AddBrushModelSurfaces
+=================
+*/
+void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {
+ bmodel_t *bmodel;
+ int clip;
+ model_t *pModel;
+ int i;
+
+ pModel = R_GetModelByHandle( ent->e.hModel );
+
+ bmodel = pModel->bmodel;
+
+ clip = R_CullLocalBox( bmodel->bounds );
+ if ( clip == CULL_OUT ) {
+ return;
+ }
+
+ R_SetupEntityLighting( &tr.refdef, ent );
+ R_DlightBmodel( bmodel );
+
+ for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
+ int surf = bmodel->firstSurface + i;
+
+ if (tr.world->surfacesViewCount[surf] != tr.viewCount)
+ {
+ tr.world->surfacesViewCount[surf] = tr.viewCount;
+ R_AddWorldSurface( tr.world->surfaces + surf, tr.currentEntity->needDlights, 0 );
+ }
+ }
+}
+
+
+/*
+=============================================================
+
+ WORLD MODEL
+
+=============================================================
+*/
+
+
+/*
+================
+R_RecursiveWorldNode
+================
+*/
+static void R_RecursiveWorldNode( mnode_t *node, uint32_t planeBits, uint32_t dlightBits, uint32_t pshadowBits ) {
+
+ do {
+ uint32_t newDlights[2];
+ uint32_t newPShadows[2];
+
+ // if the node wasn't marked as potentially visible, exit
+ // pvs is skipped for depth shadows
+ if (!(tr.viewParms.flags & VPF_DEPTHSHADOW) && node->visCounts[tr.visIndex] != tr.visCounts[tr.visIndex]) {
+ return;
+ }
+
+ // if the bounding volume is outside the frustum, nothing
+ // inside can be visible OPTIMIZE: don't do this all the way to leafs?
+
+ if ( !r_nocull->integer ) {
+ int r;
+
+ if ( planeBits & 1 ) {
+ r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);
+ if (r == 2) {
+ return; // culled
+ }
+ if ( r == 1 ) {
+ planeBits &= ~1; // all descendants will also be in front
+ }
+ }
+
+ if ( planeBits & 2 ) {
+ r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);
+ if (r == 2) {
+ return; // culled
+ }
+ if ( r == 1 ) {
+ planeBits &= ~2; // all descendants will also be in front
+ }
+ }
+
+ if ( planeBits & 4 ) {
+ r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);
+ if (r == 2) {
+ return; // culled
+ }
+ if ( r == 1 ) {
+ planeBits &= ~4; // all descendants will also be in front
+ }
+ }
+
+ if ( planeBits & 8 ) {
+ r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);
+ if (r == 2) {
+ return; // culled
+ }
+ if ( r == 1 ) {
+ planeBits &= ~8; // all descendants will also be in front
+ }
+ }
+
+ if ( planeBits & 16 ) {
+ r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[4]);
+ if (r == 2) {
+ return; // culled
+ }
+ if ( r == 1 ) {
+ planeBits &= ~16; // all descendants will also be in front
+ }
+ }
+ }
+
+ if ( node->contents != -1 ) {
+ break;
+ }
+
+ // node is just a decision point, so go down both sides
+ // since we don't care about sort orders, just go positive to negative
+
+ // determine which dlights are needed
+ newDlights[0] = 0;
+ newDlights[1] = 0;
+ if ( dlightBits ) {
+ int i;
+
+ for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
+ dlight_t *dl;
+ float dist;
+
+ if ( dlightBits & ( 1 << i ) ) {
+ dl = &tr.refdef.dlights[i];
+ dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist;
+
+ if ( dist > -dl->radius ) {
+ newDlights[0] |= ( 1 << i );
+ }
+ if ( dist < dl->radius ) {
+ newDlights[1] |= ( 1 << i );
+ }
+ }
+ }
+ }
+
+ newPShadows[0] = 0;
+ newPShadows[1] = 0;
+ if ( pshadowBits ) {
+ int i;
+
+ for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
+ pshadow_t *shadow;
+ float dist;
+
+ if ( pshadowBits & ( 1 << i ) ) {
+ shadow = &tr.refdef.pshadows[i];
+ dist = DotProduct( shadow->lightOrigin, node->plane->normal ) - node->plane->dist;
+
+ if ( dist > -shadow->lightRadius ) {
+ newPShadows[0] |= ( 1 << i );
+ }
+ if ( dist < shadow->lightRadius ) {
+ newPShadows[1] |= ( 1 << i );
+ }
+ }
+ }
+ }
+
+ // recurse down the children, front side first
+ R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0], newPShadows[0] );
+
+ // tail recurse
+ node = node->children[1];
+ dlightBits = newDlights[1];
+ pshadowBits = newPShadows[1];
+ } while ( 1 );
+
+ {
+ // leaf node, so add mark surfaces
+ int c;
+ int surf, *view;
+
+ tr.pc.c_leafs++;
+
+ // add to z buffer bounds
+ if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) {
+ tr.viewParms.visBounds[0][0] = node->mins[0];
+ }
+ if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) {
+ tr.viewParms.visBounds[0][1] = node->mins[1];
+ }
+ if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) {
+ tr.viewParms.visBounds[0][2] = node->mins[2];
+ }
+
+ if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) {
+ tr.viewParms.visBounds[1][0] = node->maxs[0];
+ }
+ if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) {
+ tr.viewParms.visBounds[1][1] = node->maxs[1];
+ }
+ if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) {
+ tr.viewParms.visBounds[1][2] = node->maxs[2];
+ }
+
+ // add surfaces
+ view = tr.world->marksurfaces + node->firstmarksurface;
+
+ c = node->nummarksurfaces;
+ while (c--) {
+ // just mark it as visible, so we don't jump out of the cache derefencing the surface
+ surf = *view;
+ if (tr.world->surfacesViewCount[surf] != tr.viewCount)
+ {
+ tr.world->surfacesViewCount[surf] = tr.viewCount;
+ tr.world->surfacesDlightBits[surf] = dlightBits;
+ tr.world->surfacesPshadowBits[surf] = pshadowBits;
+ }
+ else
+ {
+ tr.world->surfacesDlightBits[surf] |= dlightBits;
+ tr.world->surfacesPshadowBits[surf] |= pshadowBits;
+ }
+ view++;
+ }
+ }
+
+}
+
+
+/*
+===============
+R_PointInLeaf
+===============
+*/
+static mnode_t *R_PointInLeaf( const vec3_t p ) {
+ mnode_t *node;
+ float d;
+ cplane_t *plane;
+
+ if ( !tr.world ) {
+ ri.Error (ERR_DROP, "R_PointInLeaf: bad model");
+ }
+
+ node = tr.world->nodes;
+ while( 1 ) {
+ if (node->contents != -1) {
+ break;
+ }
+ plane = node->plane;
+ d = DotProduct (p,plane->normal) - plane->dist;
+ if (d > 0) {
+ node = node->children[0];
+ } else {
+ node = node->children[1];
+ }
+ }
+
+ return node;
+}
+
+/*
+==============
+R_ClusterPVS
+==============
+*/
+static const byte *R_ClusterPVS (int cluster) {
+ if (!tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) {
+ return NULL;
+ }
+
+ return tr.world->vis + cluster * tr.world->clusterBytes;
+}
+
+/*
+=================
+R_inPVS
+=================
+*/
+bool R_inPVS( const vec3_t p1, const vec3_t p2 ) {
+ mnode_t *leaf;
+ byte *vis;
+
+ leaf = R_PointInLeaf( p1 );
+ vis = ri.CM_ClusterPVS( leaf->cluster ); // why not R_ClusterPVS ??
+ leaf = R_PointInLeaf( p2 );
+
+ if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) {
+ return false;
+ }
+ return true;
+}
+
+/*
+===============
+R_MarkLeaves
+
+Mark the leaves and nodes that are in the PVS for the current
+cluster
+===============
+*/
+static void R_MarkLeaves (void) {
+ const byte *vis;
+ mnode_t *leaf, *parent;
+ int i;
+ int cluster;
+
+ // lockpvs lets designers walk around to determine the
+ // extent of the current pvs
+ if ( r_lockpvs->integer ) {
+ return;
+ }
+
+ // current viewcluster
+ leaf = R_PointInLeaf( tr.viewParms.pvsOrigin );
+ cluster = leaf->cluster;
+
+ // if the cluster is the same and the area visibility matrix
+ // hasn't changed, we don't need to mark everything again
+
+ for(i = 0; i < MAX_VISCOUNTS; i++)
+ {
+ // if the areamask or r_showcluster was modified, invalidate all visclusters
+ // this caused doors to open into undrawn areas
+ if (tr.refdef.areamaskModified || r_showcluster->modified)
+ {
+ tr.visClusters[i] = -2;
+ }
+ else if(tr.visClusters[i] == cluster)
+ {
+ if(tr.visClusters[i] != tr.visClusters[tr.visIndex] && r_showcluster->integer)
+ {
+ ri.Printf(PRINT_ALL, "found cluster:%i area:%i index:%i\n", cluster, leaf->area, i);
+ }
+ tr.visIndex = i;
+ return;
+ }
+ }
+
+ tr.visIndex = (tr.visIndex + 1) % MAX_VISCOUNTS;
+ tr.visCounts[tr.visIndex]++;
+ tr.visClusters[tr.visIndex] = cluster;
+
+ if ( r_showcluster->modified || r_showcluster->integer ) {
+ r_showcluster->modified = false;
+ if ( r_showcluster->integer ) {
+ ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area );
+ }
+ }
+
+ vis = R_ClusterPVS(tr.visClusters[tr.visIndex]);
+
+ for (i=0,leaf=tr.world->nodes ; i<tr.world->numnodes ; i++, leaf++) {
+ cluster = leaf->cluster;
+ if ( cluster < 0 || cluster >= tr.world->numClusters ) {
+ continue;
+ }
+
+ // check general pvs
+ if ( vis && !(vis[cluster>>3] & (1<<(cluster&7))) ) {
+ continue;
+ }
+
+ // check for door connection
+ if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) {
+ continue; // not visible
+ }
+
+ parent = leaf;
+ do {
+ if(parent->visCounts[tr.visIndex] == tr.visCounts[tr.visIndex])
+ break;
+ parent->visCounts[tr.visIndex] = tr.visCounts[tr.visIndex];
+ parent = parent->parent;
+ } while (parent);
+ }
+}
+
+
+/*
+=============
+R_AddWorldSurfaces
+=============
+*/
+void R_AddWorldSurfaces (void) {
+ uint32_t planeBits, dlightBits, pshadowBits;
+
+ if ( !r_drawworld->integer ) {
+ return;
+ }
+
+ if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+ return;
+ }
+
+ tr.currentEntityNum = REFENTITYNUM_WORLD;
+ tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
+
+ // determine which leaves are in the PVS / areamask
+ if (!(tr.viewParms.flags & VPF_DEPTHSHADOW))
+ R_MarkLeaves ();
+
+ // clear out the visible min/max
+ ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );
+
+ // perform frustum culling and flag all the potentially visible surfaces
+ if ( tr.refdef.num_dlights > MAX_DLIGHTS ) {
+ tr.refdef.num_dlights = MAX_DLIGHTS ;
+ }
+
+ if ( tr.refdef.num_pshadows > MAX_DRAWN_PSHADOWS ) {
+ tr.refdef.num_pshadows = MAX_DRAWN_PSHADOWS;
+ }
+
+ planeBits = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 31 : 15;
+
+ if ( tr.viewParms.flags & VPF_DEPTHSHADOW )
+ {
+ dlightBits = 0;
+ pshadowBits = 0;
+ }
+ else if ( !(tr.viewParms.flags & VPF_SHADOWMAP) )
+ {
+ dlightBits = ( 1ULL << tr.refdef.num_dlights ) - 1;
+ pshadowBits = ( 1ULL << tr.refdef.num_pshadows ) - 1;
+ }
+ else
+ {
+ dlightBits = ( 1ULL << tr.refdef.num_dlights ) - 1;
+ pshadowBits = 0;
+ }
+
+ R_RecursiveWorldNode( tr.world->nodes, planeBits, dlightBits, pshadowBits);
+
+ // now add all the potentially visible surfaces
+ // also mask invisible dlights for next frame
+ {
+ int i;
+
+ tr.refdef.dlightMask = 0;
+
+ for (i = 0; i < tr.world->numWorldSurfaces; i++)
+ {
+ if (tr.world->surfacesViewCount[i] != tr.viewCount)
+ continue;
+
+ R_AddWorldSurface( tr.world->surfaces + i, tr.world->surfacesDlightBits[i], tr.world->surfacesPshadowBits[i] );
+ tr.refdef.dlightMask |= tr.world->surfacesDlightBits[i];
+ }
+
+ tr.refdef.dlightMask = ~tr.refdef.dlightMask;
+ }
+}
diff --git a/src/script/CMakeLists.txt b/src/script/CMakeLists.txt
new file mode 100644
index 0000000..d7741f7
--- /dev/null
+++ b/src/script/CMakeLists.txt
@@ -0,0 +1,35 @@
+add_library(
+ script_api STATIC
+ client.h
+ cvar.h
+ http_client.h
+ lnettlelib.c
+ lnettlelib.h
+ lnettlelib.h
+ nettle.h
+ rapidjson.h
+ rapidjson/document.cpp
+ rapidjson/file.hpp
+ rapidjson/luax.hpp
+ rapidjson/rapidjson.cpp
+ rapidjson/schema.cpp
+ rapidjson/userdata.hpp
+ rapidjson/values.cpp
+ rapidjson/values.hpp
+ )
+
+
+include_directories(
+ # these are in global namespace
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/lua-5.3.3/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/sol
+ ${CMAKE_CURRENT_SOURCE_DIR}/../common
+ # these have they're own namespace
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/nettle-3.3
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../external/rapidjson
+ )
+
+target_link_libraries(
+ script_api
+ lua
+ )
diff --git a/src/script/bind.h b/src/script/bind.h
new file mode 100644
index 0000000..a1e93e9
--- /dev/null
+++ b/src/script/bind.h
@@ -0,0 +1,107 @@
+//
+// This file is part of Tremulous.
+// Copyright © 2016 Victor Roemer (blowfish) <victor@badsec.org>
+// Copyright (C) 2015-2019 GrangerHub
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __cplusplus
+#error __file__ " is only available to C++"
+#endif
+
+#ifndef SCRIPT_KEY_H
+#define SCRIPT_KEY_H
+
+#include "client/client.h"
+#include "client/keys.h"
+
+namespace sol
+{
+ class state;
+};
+
+namespace script
+{
+ class InvalidKey : public std::exception {
+ public:
+ virtual const char* what() const throw()
+ { return "Invalid Key"; }
+ };
+
+ struct Bind {
+ private:
+ qkey_t *my = nullptr;
+ int keynum = 0;
+
+ Bind() = delete;
+
+ public:
+ Bind(qkey_t* key)
+ : my(key)
+ { }
+
+ Bind(std::string key)
+ {
+ keynum = Key_StringToKeynum(key.c_str());
+ if ( keynum < 0 ) throw InvalidKey();
+ my = &keys[ keynum ];
+ }
+
+ Bind(std::string key, std::string cmd)
+ {
+ keynum = Key_StringToKeynum(key.c_str());
+ if ( keynum < 0 ) throw InvalidKey();
+ my = &keys[ keynum ];
+ Key_SetBinding(keynum, cmd.c_str());
+ }
+
+ Bind(std::string key, std::string cmd, bool overwrite)
+ {
+ keynum = Key_StringToKeynum(key.c_str());
+ if ( keynum < 0 ) throw InvalidKey();
+ my = &keys[ keynum ];
+ if ( !my->binding || overwrite )
+ Key_SetBinding(keynum, cmd.c_str());
+ }
+
+ std::string get_value()
+ { return my->binding; }
+
+ void set_value(std::string cmd) {
+ if ( my->binding ) Z_Free( my->binding );
+ my->binding = CopyString(cmd.c_str());
+ // consider this like modifying an archived cvar, so the file
+ // write will be triggered at the next oportunity
+ cvar_modifiedFlags |= CVAR_ARCHIVE;
+ }
+
+ };
+
+ namespace keybind
+ {
+ static inline void init(sol::state&& lua)
+ {
+ lua.new_usertype<Bind>(
+ "bind", sol::constructors<sol::types<std::string>,
+ sol::types<std::string, std::string>,
+ sol::types<std::string, std::string, bool>>(),
+ "value", sol::property(&Bind::get_value, &Bind::set_value)
+ //"key", sol::property(&Bind::get_key)
+ );
+ }
+ };
+};
+
+#endif
diff --git a/src/script/client.h b/src/script/client.h
new file mode 100644
index 0000000..ee90771
--- /dev/null
+++ b/src/script/client.h
@@ -0,0 +1,54 @@
+//
+// This file is part of Tremulous.
+// Copyright © 2016 Victor Roemer (blowfish) <victor@badsec.org>
+// Copyright (C) 2015-2019 GrangerHub
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __cplusplus
+#error __file__ " is only available to C++"
+#endif
+
+#ifndef SCRIPT_CLIENT_H
+#define SCRIPT_CLIENT_H
+
+#include <iostream>
+
+#include "client/client.h"
+#include "client/keys.h"
+
+namespace sol
+{
+ class state;
+};
+
+namespace script
+{
+ struct Client {};
+
+ namespace client
+ {
+ static inline void init(sol::state&& lua)
+ {
+ lua.new_usertype<Client>( "client",
+ "addReliableCommand", &CL_AddReliableCommand
+ //"disconnect", &CL_Disconnect_f,
+ //"reconnect", &CL_Reconnect_f,
+ );
+ }
+ };
+};
+
+#endif
diff --git a/src/script/cmd.h b/src/script/cmd.h
new file mode 100644
index 0000000..718658a
--- /dev/null
+++ b/src/script/cmd.h
@@ -0,0 +1,50 @@
+//
+// This file is part of Tremulous.
+// Copyright © 2016 Victor Roemer (blowfish) <victor@badsec.org>
+// Copyright (C) 2015-2019 GrangerHub
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __cplusplus
+#error __file__ " is only available to C++"
+#endif
+
+#ifndef SCRIPT_CMD_H
+#define SCRIPT_CMD_H
+
+#include "qcommon/cmd.h"
+
+namespace sol
+{
+ class state;
+};
+
+namespace script
+{
+ struct Cmd { };
+
+ namespace cmd
+ {
+ static inline void init(sol::state&& lua)
+ {
+ lua.new_usertype<Cmd>(
+ "cmd",
+ "execute", &Cmd_ExecuteString
+ );
+ }
+ };
+};
+
+#endif
diff --git a/src/script/cvar.h b/src/script/cvar.h
new file mode 100644
index 0000000..a5eb90c
--- /dev/null
+++ b/src/script/cvar.h
@@ -0,0 +1,146 @@
+// This file is part of Tremulous.
+// Copyright © 2016 Victor Roemer (blowfish) <victor@badsec.org>
+// Copyright (C) 2015-2019 GrangerHub
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+// It's quite possible this is _way over the top_ but I've been toying
+// with several ideas. -Victor
+
+#ifndef __cplusplus
+#error __file__ " is only available to C++"
+#endif
+
+#ifndef SCRIPT_CVAR_H
+#define SCRIPT_CVAR_H
+
+#include <iostream>
+#include <exception>
+
+#include "qcommon/cvar.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+namespace sol
+{
+ class state;
+};
+
+namespace script
+{
+ ////////////////////////////////////////////// Exceptions ////////////
+ class CvarInvalidName : public std::exception {
+ public:
+ virtual const char* what() const throw()
+ { return "cvar name is invalid"; }
+ };
+
+ class CvarNotFound : public std::exception {
+ public:
+ virtual const char* what() const throw()
+ { return "cvar does not exist"; }
+ };
+
+ class CvarReadOnly : public std::exception {
+ public:
+ virtual const char *what() const throw()
+ { return "cvar is readonly"; }
+ };
+
+ class CvarWriteProtected : public std::exception {
+ public:
+ virtual const char *what() const throw()
+ { return "cvar is write protected"; }
+ };
+
+ class CvarCheatProtected : public std::exception {
+ public:
+ virtual const char *what() const throw()
+ { return "cvar is cheat protected"; }
+ };
+
+ class CvarLatchedUnsupported : public std::exception {
+ public:
+ virtual const char *what() const throw()
+ { return "modifying latched cvars is unsupported"; }
+ };
+
+ extern "C" cvar_t *cvar_cheats;
+ ////////////////////////////////////////////// class Cvar ////////////
+ struct Cvar {
+ private:
+ cvar_s *my = nullptr;
+
+ Cvar() = delete;
+
+ public:
+ Cvar(cvar_s* var)
+ : my(var)
+ { }
+
+ Cvar(std::string name)
+ { my = Cvar_Get(name.c_str(), "", 0); }
+
+ Cvar(std::string name, std::string value)
+ { my = Cvar_Get(name.c_str(), value.c_str(), CVAR_ARCHIVE); }
+
+ Cvar(std::string name, std::string value, int flags)
+ { my = Cvar_Get(name.c_str(), value.c_str(), flags); }
+
+ void set_value(const char*value)
+ {
+ if ( !my )
+ throw CvarNotFound();
+ else if ( my->flags & CVAR_ROM )
+ throw CvarReadOnly();
+ else if ( my->flags & CVAR_INIT )
+ throw CvarWriteProtected();
+ else if ( my->flags & CVAR_CHEAT && !cvar_cheats->integer )
+ throw CvarCheatProtected();
+ else if ( (my->flags & CVAR_LATCH) )
+ throw CvarLatchedUnsupported();
+ else if ( !value )
+ value = my->resetString;
+ value = Cvar_Validate(my, value, false);
+
+ cvar_modifiedFlags |= my->flags;
+
+ my->modified = true;
+ my->modificationCount++;
+ my->string = CopyString(value);
+ my->value = atof(my->string);
+ my->integer = atoi(my->string);
+ }
+
+ std::string get_value()
+ { return my->string; }
+
+ std::string get_key()
+ { return my->name; }
+ };
+
+ namespace cvar {
+ static inline void init(sol::state&& lua)
+ {
+ lua.new_usertype<Cvar>(
+ "cvar", sol::constructors<sol::types<std::string>,
+ sol::types<std::string, std::string>,
+ sol::types<std::string, std::string, int>>(),
+ "value", sol::property(&Cvar::get_value, &Cvar::set_value),
+ "key", sol::property(&Cvar::get_key)
+ );
+ }
+ };
+};
+#endif
diff --git a/src/script/http_client.h b/src/script/http_client.h
new file mode 100644
index 0000000..2556090
--- /dev/null
+++ b/src/script/http_client.h
@@ -0,0 +1,65 @@
+// This file is part of Tremulous.
+// Copyright © 2016 Victor Roemer (blowfish) <victor@badsec.org>
+// Copyright (C) 2015-2019 GrangerHub
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+// It's quite possible this is _way over the top_ but I've been toying
+// with several ideas. -Victor
+
+#ifndef __cplusplus
+#error __file__ " is only available to C++"
+#endif
+
+#ifndef SCRIPT_RESTCLIENT_H
+#define SCRIPT_RESTCLIENT_H
+
+#include <iostream>
+#include "restclient/restclient.h"
+
+namespace sol
+{
+ class state;
+};
+
+namespace script
+{
+ // No Exceptions at this time
+
+ struct HttpClient
+ { };
+
+ namespace http_client
+ {
+ //using namespace RestClient;
+ static inline void init(sol::state&& lua)
+ {
+
+ lua.new_usertype<RestClient::Response>( "HttpResponse",
+ "code", &RestClient::Response::code,
+ "body", &RestClient::Response::body
+ //"headers", &RestClient::Response::headers
+ );
+
+ lua.new_usertype<HttpClient>( "http",
+ "get", &RestClient::get,
+ "post", &RestClient::post,
+ "put", &RestClient::put,
+ "delete", &RestClient::del
+ );
+ }
+ };
+};
+
+#endif
diff --git a/src/script/lnettlelib.c b/src/script/lnettlelib.c
new file mode 100644
index 0000000..f1aedfa
--- /dev/null
+++ b/src/script/lnettlelib.c
@@ -0,0 +1,94 @@
+#include <string.h>
+
+#include "lauxlib.h"
+#include "lua.h"
+#include "nettle/sha2.h"
+
+//#include "../qcommon/q3_lauxlib.h" FIXME? This doesn't seem to be hooked correctly into tremded.exe
+
+#define SHA256_CTX "sha256_ctx*"
+
+static int lsha256(lua_State *L)
+{
+ struct sha256_ctx *ctx;
+
+ ctx = (struct sha256_ctx *)lua_newuserdata(L, sizeof(struct sha256_ctx));
+ luaL_setmetatable(L, SHA256_CTX);
+ sha256_init(ctx);
+ return 1;
+}
+
+static int lsha256_digest(lua_State *L)
+{
+ struct sha256_ctx *ctx;
+ char digest[SHA256_DIGEST_SIZE];
+
+ ctx = luaL_checkudata(L, 1, SHA256_CTX);
+ sha256_digest(ctx, sizeof(digest), digest);
+ lua_pushlstring(L, digest, sizeof(digest));
+ return 1;
+}
+
+static int lsha256_update(lua_State *L)
+{
+ struct sha256_ctx *ctx;
+ const char *data;
+ size_t len;
+
+ ctx = luaL_checkudata(L, 1, SHA256_CTX);
+ if (lua_isnil(L, 2)) {
+ return 0;
+ }
+ data = luaL_tolstring(L, 2, &len);
+ nettle_sha256_update(ctx, len, data);
+ return 0;
+}
+
+static int lsha256_tostring(lua_State *L)
+{
+ struct sha256_ctx *ctx, ctx2;
+ char digest[SHA256_DIGEST_SIZE];
+ char hex[SHA256_DIGEST_SIZE*2+1];
+ int i;
+
+ ctx = luaL_checkudata(L, 1, SHA256_CTX);
+ memcpy(&ctx2, ctx, sizeof(struct sha256_ctx));
+
+ sha256_digest(&ctx2, sizeof(digest), digest);
+ for (i = 0; i < sizeof(digest); i++) {
+ sprintf(hex + 2 * i, "%02hhx", digest[i]);
+ }
+
+ lua_pushstring(L, hex);
+ return 1;
+}
+
+/* functions for 'nettle' library */
+static const luaL_Reg nettlelib[] = {
+ {"sha256", lsha256},
+ {NULL, NULL}
+};
+
+/* functions for sha256 objects */
+static const luaL_Reg lsha256_methods[] = {
+ {"digest", lsha256_digest},
+ {"update", lsha256_update},
+ {"__tostring", lsha256_tostring},
+ {NULL, NULL}
+};
+
+static void createmeta (lua_State *L)
+{
+ luaL_newmetatable(L, SHA256_CTX); /* create metatable for file handles */
+ lua_pushvalue(L, -1); /* push metatable */
+ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
+ luaL_setfuncs(L, lsha256_methods, 0); /* add file methods to new metatable */
+ lua_pop(L, 1); /* pop new metatable */
+}
+
+LUAMOD_API int luaopen_nettle (lua_State *L)
+{
+ luaL_newlib(L, nettlelib);
+ createmeta(L);
+ return 1;
+}
diff --git a/src/script/lnettlelib.h b/src/script/lnettlelib.h
new file mode 100644
index 0000000..c9609f9
--- /dev/null
+++ b/src/script/lnettlelib.h
@@ -0,0 +1,15 @@
+#ifndef lnettlelib_h
+#define lnettlelib_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LUA_NETTLELIBNAME "nettle"
+LUAMOD_API int (luaopen_nettle) (lua_State *L);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* lnettlelib_h */
diff --git a/src/script/nettle.h b/src/script/nettle.h
new file mode 100644
index 0000000..87e8c26
--- /dev/null
+++ b/src/script/nettle.h
@@ -0,0 +1,41 @@
+//
+// This file is part of Tremulous.
+// Copyright © 2016 Victor Roemer (blowfish) <victor@badsec.org>
+// Copyright (C) 2015-2019 GrangerHub
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __cplusplus
+#error __file__ " is only available to C++"
+#endif
+
+#ifndef SCRIPT_NETTLE_H
+#define SCRIPT_NETTLE_H
+
+#include <iostream>
+
+#include "lua.hpp"
+#include "sol.hpp"
+
+#include "lnettlelib.h"
+
+namespace script {
+ namespace nettle {
+ static inline void init(sol::state&& lua)
+ { lua.require("nettle", luaopen_nettle, 1); }
+ };
+};
+
+#endif
diff --git a/src/script/rapidjson.h b/src/script/rapidjson.h
new file mode 100644
index 0000000..0603bb7
--- /dev/null
+++ b/src/script/rapidjson.h
@@ -0,0 +1,52 @@
+//
+// This file is part of Tremulous.
+// Copyright © 2016 Victor Roemer (blowfish) <victor@badsec.org>
+// Copyright (C) 2015-2019 GrangerHub
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __cplusplus
+#error __file__ " is only available to C++"
+#endif
+
+#ifndef SCRIPT_RAPIDJSON_H
+#define SCRIPT_RAPIDJSON_H
+
+#include <iostream>
+
+#include "lua.hpp"
+#include "sol.hpp"
+
+namespace sol
+{
+ class state;
+};
+
+extern "C" int luaopen_rapidjson(lua_State* L);
+
+namespace script
+{
+ // No Exceptions at this time
+
+ namespace rapidjson
+ {
+ static inline void init(sol::state&& lua)
+ {
+ lua.require("rapidjson", luaopen_rapidjson, 1);
+ }
+ };
+};
+
+#endif
diff --git a/src/script/rapidjson/LICENSE b/src/script/rapidjson/LICENSE
new file mode 100644
index 0000000..5a331f8
--- /dev/null
+++ b/src/script/rapidjson/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2015 Xpol Wan
+
+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
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/src/script/rapidjson/document.cpp b/src/script/rapidjson/document.cpp
new file mode 100644
index 0000000..2487eb6
--- /dev/null
+++ b/src/script/rapidjson/document.cpp
@@ -0,0 +1,194 @@
+
+#include <cstdio>
+#include <vector>
+#include <fstream>
+
+#include "userdata.hpp"
+#include "values.hpp"
+#include "file.hpp"
+
+#include "lua.hpp"
+#include "rapidjson.h"
+
+using namespace rapidjson;
+
+template<>
+const char* const Userdata<Document>::metatable = "rapidjson.Document";
+
+template<>
+Document* Userdata<Document>::construct(lua_State * L)
+{
+ auto t = lua_type(L, 1);
+ if (t != LUA_TNONE && t != LUA_TSTRING && t != LUA_TTABLE)
+ {
+ luax::typerror(L, 1, "none, string or table");
+ return nullptr;
+ }
+
+ auto doc = new Document();
+ if (t == LUA_TSTRING)
+ {
+ size_t len;
+ const char* s = luaL_checklstring(L, 1, &len);
+ doc->Parse(s, len);
+ }
+ else if (t == LUA_TTABLE)
+ {
+ values::toDocument(L, 1, doc);
+ }
+ return doc;
+}
+
+static int pushParseResult(lua_State* L, Document* doc)
+{
+ auto err = doc->GetParseError();
+ if (err != kParseErrorNone)
+ {
+ lua_pushnil(L);
+ lua_pushfstring(L, "%s (at Offset %d)", GetParseError_En(err), doc->GetErrorOffset());
+ return 2;
+ }
+
+ lua_pushboolean(L, 1);
+ return 1;
+}
+
+static int Document_parse(lua_State* L)
+{
+ Document* doc = Userdata<Document>::get(L, 1);
+
+ size_t l = 0;
+ auto s = luaL_checklstring(L, 2, &l);
+ doc->Parse(s, l);
+
+ return pushParseResult(L, doc);
+}
+
+static int Document_parseFile(lua_State* L)
+{
+ auto doc = Userdata<Document>::get(L, 1);
+
+ auto s = luaL_checkstring(L, 2);
+ std::ifstream ifs(s);
+ IStreamWrapper isw(ifs);
+
+ doc->ParseStream(isw);
+
+ return pushParseResult(L, doc);;
+}
+
+/**
+ * doc:get('path'[, default])
+ */
+static int Document_get(lua_State* L)
+{
+ auto doc = Userdata<Document>::check(L, 1);
+ auto s = luaL_checkstring(L, 2);
+ Pointer ptr(s);
+ auto v = ptr.Get(*doc);
+
+ if (!v)
+ {
+ if (lua_gettop(L) >= 3)
+ {
+ lua_pushvalue(L, 3);
+ }
+ else
+ {
+ lua_pushnil(L);
+ }
+ }
+ else
+ {
+ values::push(L, *v);
+ }
+ return 1;
+}
+
+static int Document_set(lua_State* L)
+{
+ auto doc = Userdata<Document>::check(L, 1);
+ Pointer ptr(luaL_checkstring(L, 2));
+ auto v = values::toValue(L, 3, doc->GetAllocator());
+
+ ptr.Set(*doc, v, doc->GetAllocator());
+
+ return 0;
+}
+
+/**
+ * local jsonstr = doc:stringify(
+ {pretty=false})
+ */
+static int Document_stringify(lua_State* L)
+{
+ auto doc = Userdata<Document>::check(L, 1);
+
+ auto pretty = luax::optboolfield(L, 2, "pretty", false);
+
+ StringBuffer sb;
+ if (pretty)
+ {
+ PrettyWriter<StringBuffer> writer(sb);
+ doc->Accept(writer);
+ }
+ else
+ {
+ Writer<StringBuffer> writer(sb);
+ doc->Accept(writer);
+ }
+ lua_pushlstring(L, sb.GetString(), sb.GetSize());
+
+ return 1;
+}
+
+/**
+ * doc:save(filename,
+ {pretty=false, sort_keys=false})
+ */
+static int Document_save(lua_State* L)
+{
+ auto doc = Userdata<Document>::check(L, 1);
+ auto filename = luaL_checkstring(L, 2);
+ auto pretty = luax::optboolfield(L, 3, "pretty", false);
+
+ auto fp = file::open(filename, "wb");
+ char buffer[512];
+ FileWriteStream fs(fp, buffer, sizeof(buffer));
+
+ if (pretty)
+ {
+ PrettyWriter<FileWriteStream> writer(fs);
+ doc->Accept(writer);
+ }
+ else
+ {
+ Writer<FileWriteStream> writer(fs);
+ doc->Accept(writer);
+ }
+ fclose(fp);
+
+ return 0;
+}
+
+template <>
+const luaL_Reg* Userdata<Document>::methods()
+{
+ static const luaL_Reg reg[] =
+ {
+ { "parse", Document_parse },
+ { "parseFile", Document_parseFile },
+
+ { "__gc", metamethod_gc },
+ { "__tostring", metamethod_tostring },
+
+ { "get", Document_get },
+ { "set", Document_set },
+
+ { "stringify", Document_stringify },
+ { "save", Document_save },
+
+ { nullptr, nullptr }
+ };
+ return reg;
+}
diff --git a/src/script/rapidjson/file.hpp b/src/script/rapidjson/file.hpp
new file mode 100644
index 0000000..5e098d4
--- /dev/null
+++ b/src/script/rapidjson/file.hpp
@@ -0,0 +1,21 @@
+#ifndef __LUA_RAPIDJSION_FILE_HPP__
+#define __LUA_RAPIDJSION_FILE_HPP__
+
+#include <cstdio>
+
+namespace file
+{
+ inline FILE* open(const char* filename, const char* mode)
+ {
+#if WIN32
+ FILE* fp = nullptr;
+ fopen_s(&fp, filename, mode);
+ return fp;
+#else
+ return fopen(filename, mode);
+#endif
+ }
+}
+
+#endif
+
diff --git a/src/script/rapidjson/luax.hpp b/src/script/rapidjson/luax.hpp
new file mode 100644
index 0000000..e8ea7c6
--- /dev/null
+++ b/src/script/rapidjson/luax.hpp
@@ -0,0 +1,82 @@
+#ifndef __LUA_RAPIDJSION_LUACOMPAT_H__
+#define __LUA_RAPIDJSION_LUACOMPAT_H__
+
+#include <cmath>
+#include <limits>
+#include <cstdint>
+
+#include "qcommon/q3_lauxlib.h"
+
+#include "lua.hpp"
+
+namespace luax
+{
+ inline void setfuncs(lua_State* L, const luaL_Reg* funcs)
+ { luaL_setfuncs(L, funcs, 0); }
+
+ inline size_t rawlen(lua_State* L, int idx)
+ { return lua_rawlen(L, idx); }
+
+ inline bool isinteger(lua_State* L, int idx, int64_t* out = nullptr)
+ {
+ if (lua_isinteger(L, idx)) // but it maybe not detect all integers.
+ {
+ if (out)
+ *out = lua_tointeger(L, idx);
+ return true;
+ }
+
+ double intpart;
+ if (std::modf(lua_tonumber(L, idx), &intpart) == 0.0)
+ {
+ if (std::numeric_limits<lua_Integer>::min() <= intpart
+ && intpart <= std::numeric_limits<lua_Integer>::max())
+ {
+ if (out)
+ *out = static_cast<int64_t>(intpart);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ inline int typerror(lua_State* L, int narg, const char* tname)
+ {
+ const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, luaL_typename(L, narg));
+ return luaL_argerror(L, narg, msg);
+ }
+
+ inline bool optboolfield(lua_State* L, int idx, const char* name, bool def)
+ {
+ auto v = def;
+ auto t = lua_type(L, idx);
+
+ if (t != LUA_TTABLE && t != LUA_TNONE)
+ luax::typerror(L, idx, "table");
+
+ if (t != LUA_TNONE)
+ {
+ lua_getfield(L, idx, name);
+ if (!lua_isnoneornil(L, -1))
+ v = lua_toboolean(L, -1) != 0;
+ lua_pop(L, 1);
+ }
+
+ return v;
+ }
+
+ inline int optintfield(lua_State* L, int idx, const char* name, int def)
+ {
+ auto v = def;
+ lua_getfield(L, idx, name);
+
+ if (lua_isnumber(L, -1))
+ v = static_cast<int>(lua_tointeger(L, -1));
+
+ lua_pop(L, 1);
+ return v;
+ }
+
+}
+
+#endif
diff --git a/src/script/rapidjson/rapidjson.cpp b/src/script/rapidjson/rapidjson.cpp
new file mode 100644
index 0000000..9e87812
--- /dev/null
+++ b/src/script/rapidjson/rapidjson.cpp
@@ -0,0 +1,414 @@
+
+#include <limits>
+#include <cstdio>
+#include <vector>
+#include <algorithm>
+
+#include "userdata.hpp"
+#include "values.hpp"
+#include "luax.hpp"
+#include "file.hpp"
+
+#include "lua.hpp"
+#include "rapidjson.h"
+
+using namespace rapidjson;
+
+#ifndef LUA_RAPIDJSON_VERSION
+#define LUA_RAPIDJSON_VERSION "1.0.0"
+#endif
+
+static void createSharedMeta(lua_State* L, const char* meta, const char* type)
+{
+ luaL_newmetatable(L, meta);
+ lua_pushstring(L, type);
+ lua_setfield(L, -2, "__jsontype");
+ lua_pop(L, 1);
+}
+
+static int makeTableType(lua_State* L, int idx, const char* meta, const char* type)
+{
+ auto isnoarg = lua_isnoneornil(L, idx);
+ auto istable = lua_istable(L, idx);
+ if (!isnoarg && !istable)
+ return luaL_argerror(L, idx, "optional table excepted");
+
+ if (isnoarg)
+ lua_createtable(L, 0, 0);
+ else // is table.
+ {
+ lua_pushvalue(L, idx);
+ if (lua_getmetatable(L, -1))
+ {
+ // already have a metatable, just set the __jsontype field.
+
+ lua_pushstring(L, type);
+ lua_setfield(L, -2, "__jsontype");
+ lua_pop(L, 1);
+ return 1;
+ }
+ // else fall through
+ }
+
+ // Now we have a table without meta table
+ luaL_getmetatable(L, meta);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int json_object(lua_State* L)
+{
+ return makeTableType(L, 1, "json.object", "object");
+}
+
+static int json_array(lua_State* L)
+{
+ return makeTableType(L, 1, "json.array", "array");
+}
+
+template<typename Stream>
+int decode(lua_State* L, Stream* s)
+{
+ auto top = lua_gettop(L);
+ values::ToLuaHandler handler(L);
+ Reader reader;
+
+ ParseResult r = reader.Parse(*s, handler);
+ if (!r)
+ {
+ lua_settop(L, top);
+ lua_pushnil(L);
+ lua_pushfstring(L, "%s (%d)", GetParseError_En(r.Code()), r.Offset());
+ return 2;
+ }
+
+ return 1;
+}
+
+static int json_decode(lua_State* L)
+{
+ size_t len = 0;
+ auto contents = luaL_checklstring(L, 1, &len);
+ StringStream s(contents);
+ return decode(L, &s);
+}
+
+static int json_load(lua_State* L)
+{
+ auto filename = luaL_checklstring(L, 1, nullptr);
+ auto fp = file::open(filename, "rb");
+ if (!fp)
+ luaL_error(L, "error while open file: %s", filename);
+
+ char buffer[512];
+ FileReadStream fs(fp, buffer, sizeof(buffer));
+ AutoUTFInputStream<unsigned, FileReadStream> eis(fs);
+
+ auto n = decode(L, &eis);
+
+ fclose(fp);
+ return n;
+}
+
+struct Key
+{
+ Key(const char* k, SizeType l) : key(k), size(l)
+ {}
+ bool operator<(const Key& rhs) const
+ {
+ return strcmp(key, rhs.key) < 0;
+ }
+ const char* key;
+ SizeType size;
+};
+
+class Encoder
+{
+ bool pretty;
+ bool sort_keys;
+ int max_depth;
+ static const int MAX_DEPTH_DEFAULT = 128;
+ public:
+ Encoder(lua_State*L, int opt) : pretty(false), sort_keys(false), max_depth(MAX_DEPTH_DEFAULT)
+ {
+ if (lua_isnoneornil(L, opt))
+ return;
+ luaL_checktype(L, opt, LUA_TTABLE);
+
+ pretty = luax::optboolfield(L, opt, "pretty", false);
+ sort_keys = luax::optboolfield(L, opt, "sort_keys", false);
+ max_depth = luax::optintfield(L, opt, "max_depth", MAX_DEPTH_DEFAULT);
+ }
+
+ private:
+ template<typename Writer>
+ void encodeValue(lua_State* L, Writer* writer, int idx, int depth = 0)
+ {
+ size_t len;
+ const char* s;
+ int64_t integer;
+ auto t = lua_type(L, idx);
+ switch (t)
+ {
+ case LUA_TBOOLEAN:
+ writer->Bool(lua_toboolean(L, idx) != 0);
+ return;
+ case LUA_TNUMBER:
+ if (luax::isinteger(L, idx, &integer))
+ writer->Int64(integer);
+ else
+ {
+ if (!writer->Double(lua_tonumber(L, idx)))
+ luaL_error(L, "error while encode double value.");
+ }
+ return;
+ case LUA_TSTRING:
+ s = lua_tolstring(L, idx, &len);
+ writer->String(s, static_cast<SizeType>(len));
+ return;
+ case LUA_TTABLE:
+ return encodeTable(L, writer, idx, depth + 1);
+ case LUA_TNIL:
+ writer->Null();
+ return;
+ case LUA_TFUNCTION:
+ if (values::isnull(L, idx))
+ {
+ writer->Null();
+ return;
+ }
+ // otherwise fall thought
+ case LUA_TLIGHTUSERDATA: // fall thought
+ case LUA_TUSERDATA: // fall thought
+ case LUA_TTHREAD: // fall thought
+ case LUA_TNONE: // fall thought
+ default:
+ luaL_error(L, "value type : %s", lua_typename(L, t));
+ }
+ }
+
+ template<typename Writer>
+ void encodeTable(lua_State* L, Writer* writer, int idx, int depth)
+ {
+ if (depth > max_depth)
+ luaL_error(L, "nested too depth");
+
+ if (!lua_checkstack(L, 4)) // requires at least 4 slots in stack: table, key, value, key
+ luaL_error(L, "stack overflow");
+
+ lua_pushvalue(L, idx);
+ if (values::isarray(L, -1))
+ {
+ encodeArray(L, writer, depth);
+ lua_pop(L, 1);
+ return;
+ }
+
+ // is object.
+ if (!sort_keys)
+ {
+ encodeObject(L, writer, depth);
+ lua_pop(L, 1);
+ return;
+ }
+
+ lua_pushnil(L);
+ std::vector<Key> keys;
+
+ while (lua_next(L, -2))
+ {
+
+
+ if (lua_type(L, -2) == LUA_TSTRING)
+ {
+ size_t len = 0;
+ auto key = lua_tolstring(L, -2, &len);
+ keys.push_back(Key(key, static_cast<SizeType>(len)));
+ }
+
+ // pop value, leaving original key
+ lua_pop(L, 1);
+
+ }
+
+ encodeObject(L, writer, depth, keys);
+ lua_pop(L, 1);
+ }
+
+ template<typename Writer>
+ void encodeObject(lua_State* L, Writer* writer, int depth)
+ {
+ writer->StartObject();
+
+
+ lua_pushnil(L);
+ while (lua_next(L, -2))
+ {
+
+ if (lua_type(L, -2) == LUA_TSTRING)
+ {
+ size_t len = 0;
+ auto key = lua_tolstring(L, -2, &len);
+ writer->Key(key, static_cast<SizeType>(len));
+ encodeValue(L, writer, -1, depth);
+ }
+
+ // pop value, leaving original key
+ lua_pop(L, 1);
+
+ }
+
+ writer->EndObject();
+ }
+
+ template<typename Writer>
+ void encodeObject(lua_State* L, Writer* writer, int depth, std::vector<Key> &keys)
+ {
+
+ writer->StartObject();
+ std::sort(keys.begin(), keys.end());
+
+ std::vector<Key>::const_iterator i = keys.begin();
+ std::vector<Key>::const_iterator e = keys.end();
+ for ( auto const& i : keys )
+ {
+ writer->Key(i.key, static_cast<SizeType>(i.size));
+ lua_pushlstring(L, i.key, i.size);
+ lua_gettable(L, -2);
+ encodeValue(L, writer, -1, depth);
+ lua_pop(L, 1);
+ }
+
+ writer->EndObject();
+ }
+
+ template<typename Writer>
+ void encodeArray(lua_State* L, Writer* writer, int depth)
+ {
+
+ writer->StartArray();
+ auto MAX = static_cast<int>(luax::rawlen(L, -1)); // lua_rawlen always returns value >= 0
+ for (auto n = 1; n <= MAX; ++n)
+ {
+ lua_rawgeti(L, -1, n);
+ encodeValue(L, writer, -1, depth);
+ lua_pop(L, 1);
+ }
+ writer->EndArray();
+
+ }
+
+ public:
+ template<typename Stream>
+ void encode(lua_State* L, Stream* s, int idx)
+ {
+ if (pretty)
+ {
+ PrettyWriter<Stream> writer(*s);
+ encodeValue(L, &writer, idx);
+ }
+ else
+ {
+ Writer<Stream> writer(*s);
+ encodeValue(L, &writer, idx);
+ }
+ }
+};
+
+static int json_encode(lua_State* L)
+{
+ try
+ {
+ Encoder encode(L, 2);
+ StringBuffer s;
+ encode.encode(L, &s, 1);
+ lua_pushlstring(L, s.GetString(), s.GetSize());
+ return 1;
+ }
+ catch (...)
+ {
+ luaL_error(L, "error while encoding");
+ }
+ return 0;
+}
+
+static int json_dump(lua_State* L)
+{
+ Encoder encoder(L, 3);
+
+ auto filename = luaL_checkstring(L, 2);
+ auto fp = file::open(filename, "wb");
+ if (fp == nullptr)
+ luaL_error(L, "error while open file: %s", filename);
+
+ char buffer[512];
+ FileWriteStream fs(fp, buffer, sizeof(buffer));
+ encoder.encode(L, &fs, 1);
+ fclose(fp);
+ return 0;
+}
+
+namespace values
+{
+ static auto nullref = LUA_NOREF;
+ /**
+ * Returns rapidjson.null.
+ */
+ int json_null(lua_State* L)
+ {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, nullref);
+ return 1;
+ }
+}
+
+static const luaL_Reg methods[] =
+{
+ // string <--> lua table
+ { "decode", json_decode },
+ { "encode", json_encode },
+
+ // file <--> lua table
+ { "load", json_load },
+ { "dump", json_dump },
+
+ // special tags and functions
+ { "null", values::json_null },
+ { "object", json_object },
+ { "array", json_array },
+
+ // JSON types
+ { "Document", Userdata<Document>::create },
+ { "SchemaDocument", Userdata<SchemaDocument>::create },
+ { "SchemaValidator", Userdata<SchemaValidator>::create },
+
+ {nullptr, nullptr }
+};
+
+extern "C"
+{
+ LUALIB_API int luaopen_rapidjson(lua_State* L)
+ {
+ lua_newtable(L);
+
+ luax::setfuncs(L, methods);
+
+ lua_pushliteral(L, "rapidjson");
+ lua_setfield(L, -2, "_NAME");
+
+ lua_pushliteral(L, LUA_RAPIDJSON_VERSION);
+ lua_setfield(L, -2, "_VERSION");
+
+ lua_getfield(L, -1, "null");
+ values::nullref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+
+ createSharedMeta(L, "json.object", "object");
+ createSharedMeta(L, "json.array", "array");
+
+ Userdata<Document>::luaopen(L);
+ Userdata<SchemaDocument>::luaopen(L);
+ Userdata<SchemaValidator>::luaopen(L);
+
+ return 1;
+ }
+}
diff --git a/src/script/rapidjson/schema.cpp b/src/script/rapidjson/schema.cpp
new file mode 100644
index 0000000..ade5736
--- /dev/null
+++ b/src/script/rapidjson/schema.cpp
@@ -0,0 +1,116 @@
+
+#include "userdata.hpp"
+#include "values.hpp"
+
+#include "lua.hpp"
+#include "rapidjson.h"
+
+using namespace rapidjson;
+
+template<>
+const char* const Userdata<SchemaDocument>::metatable = "rapidjson.SchemaDocument";
+
+template<>
+SchemaDocument* Userdata<SchemaDocument>::construct(lua_State * L)
+{
+ switch (lua_type(L, 1))
+ {
+ case LUA_TNONE:
+ return new SchemaDocument(Document()); // empty schema
+ case LUA_TSTRING:
+ {
+ auto d = Document();
+ size_t len = 0;
+ auto s = lua_tolstring(L, 1, &len);
+ d.Parse(s, len);
+ return new SchemaDocument(d);
+ }
+ case LUA_TTABLE:
+ {
+ auto doc = Document();
+ values::toDocument(L, 1, &doc);
+ return new SchemaDocument(doc);
+ }
+ case LUA_TUSERDATA:
+ {
+ auto doc = Userdata<Document>::check(L, 1);
+ return new SchemaDocument(*doc);
+ }
+ default:
+ luax::typerror(L, 1, "none, string, table or rapidjson.Document");
+ return nullptr; // Just make compiler happy
+ }
+}
+
+template <>
+const luaL_Reg* Userdata<SchemaDocument>::methods()
+{
+ static const luaL_Reg reg[] =
+ {
+ { "__gc", metamethod_gc },
+ { nullptr, nullptr }
+ };
+ return reg;
+}
+
+template<>
+const char* const Userdata<SchemaValidator>::metatable = "rapidjson.SchemaValidator";
+
+template<>
+SchemaValidator* Userdata<SchemaValidator>::construct(lua_State * L)
+{
+ auto sd = Userdata<SchemaDocument>::check(L, 1);
+ return new SchemaValidator(*sd);
+}
+
+static void pushValidator_error(lua_State* L, SchemaValidator* validator)
+{
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+
+ luaL_addstring(&b, "invalid \"");
+ luaL_addstring(&b, validator->GetInvalidSchemaKeyword());
+ luaL_addstring(&b, "\" in docuement at pointer \"");
+
+ // docuement pointer
+ StringBuffer sb;
+ validator->GetInvalidDocumentPointer().StringifyUriFragment(sb);
+ luaL_addlstring(&b, sb.GetString(), sb.GetSize());
+ luaL_addchar(&b, '"');
+
+ luaL_pushresult(&b);
+}
+
+static int SchemaValidator_validate(lua_State* L)
+{
+ auto validator = Userdata<SchemaValidator>::check(L, 1);
+ auto doc = Userdata<Document>::check(L, 2);
+ auto ok = doc->Accept(*validator);
+ lua_pushboolean(L, ok);
+ int nr;
+
+ if (ok)
+ {
+ nr = 1;
+ }
+ else
+ {
+ pushValidator_error(L, validator);
+ nr = 2;
+ }
+ validator->Reset();
+
+ return nr;
+}
+
+template <>
+const luaL_Reg* Userdata<SchemaValidator>::methods()
+{
+ static const luaL_Reg reg[] =
+ {
+ { "__gc", metamethod_gc },
+ { "validate", SchemaValidator_validate },
+ { nullptr, nullptr }
+ };
+ return reg;
+}
diff --git a/src/script/rapidjson/userdata.hpp b/src/script/rapidjson/userdata.hpp
new file mode 100644
index 0000000..1127bac
--- /dev/null
+++ b/src/script/rapidjson/userdata.hpp
@@ -0,0 +1,112 @@
+#ifndef __LUA_RAPIDJSON_USERDATA_HPP__
+#define __LUA_RAPIDJSON_USERDATA_HPP__
+
+
+#include "qcommon/q3_lauxlib.h"
+
+#include "luax.hpp"
+
+#include "lua.hpp"
+#include "rapidjson.h"
+
+template <typename T>
+struct Userdata
+{
+ static int create(lua_State* L)
+ {
+ push(L, construct(L));
+ return 1;
+ }
+
+ static T* construct(lua_State* L);
+
+ static void luaopen(lua_State* L)
+ {
+ luaL_newmetatable(L, metatable);
+ lua_pushvalue(L, -1);
+ luax::setfuncs(L, methods());
+ lua_setfield(L, -2, "__index");
+ lua_pop(L, 1);
+ }
+
+ static const luaL_Reg* methods();
+
+ static void push(lua_State* L, T* c)
+ {
+ if (!c)
+ {
+ lua_pushnil(L);
+ return;
+ }
+
+ T** ud = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(*ud)));
+ if (!ud)
+ luaL_error(L, "Out of memory");
+
+ *ud = c;
+
+ luaL_getmetatable(L, metatable);
+ lua_setmetatable(L, -2);
+ }
+
+ static T** getUserdata(lua_State* L, int idx)
+ {
+ return reinterpret_cast<T**>(lua_touserdata(L, idx));
+ }
+
+
+ static T* get(lua_State* L, int idx)
+ {
+ auto p = getUserdata(L, idx);
+ if (p && *p )
+ {
+ if (lua_getmetatable(L, idx))
+ { /* does it have a metatable? */
+ luaL_getmetatable(L, metatable); /* get correct metatable */
+ if (lua_rawequal(L, -1, -2))
+ { /* does it have the correct mt? */
+ lua_pop(L, 2); /* remove both metatables */
+ return *p;
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ static T* check(lua_State* L, int idx)
+ {
+ auto ud = reinterpret_cast<T**>(luaL_checkudata(L, idx, metatable));
+ if (!*ud)
+ luaL_error(L, "%s already closed", metatable);
+ return *ud;
+ }
+
+ static int metamethod_gc(lua_State* L)
+ {
+ T** ud = reinterpret_cast<T**>(luaL_checkudata(L, 1, metatable));
+ if (*ud)
+ {
+ delete *ud;
+ *ud = nullptr;
+ }
+ return 0;
+ }
+
+ static int metamethod_tostring(lua_State* L)
+ {
+ auto ud = getUserdata(L, 1);
+ if (*ud)
+ {
+ lua_pushfstring(L, "%s (%p)", metatable, *ud);
+ }
+ else
+ {
+ lua_pushfstring(L, "%s (closed)", metatable);
+ }
+ return 1;
+ }
+
+ static const char* const metatable;
+};
+
+#endif
diff --git a/src/script/rapidjson/values.cpp b/src/script/rapidjson/values.cpp
new file mode 100644
index 0000000..1d9c892
--- /dev/null
+++ b/src/script/rapidjson/values.cpp
@@ -0,0 +1,108 @@
+
+#include "values.hpp"
+#include "luax.hpp"
+
+using rapidjson::Value;
+using rapidjson::SizeType;
+
+namespace values
+{
+ namespace details
+ {
+ static Value NumberValue(lua_State* L, int idx);
+ static Value StringValue(lua_State* L, int idx, Allocator& allocator);
+ static Value TableValue(lua_State* L, int idx, int depth, Allocator& allocator);
+ static Value ObjectValue(lua_State* L, int idx, int depth, Allocator& allocator);
+ static Value ArrayValue(lua_State* L, int idx, int depth, Allocator& allocator);
+
+ Value toValue(lua_State* L, int idx, int depth, Allocator& allocator)
+ {
+ auto t = lua_type(L, idx);
+ switch (t)
+ {
+ case LUA_TBOOLEAN:
+ return Value(lua_toboolean(L, idx) != 0);
+ case LUA_TNUMBER:
+ return NumberValue(L, idx);
+ case LUA_TSTRING:
+ return StringValue(L, idx, allocator);
+ case LUA_TTABLE:
+ return TableValue(L, idx, depth + 1, allocator);
+ case LUA_TNIL:
+ return Value();
+ case LUA_TFUNCTION:
+ if (isnull(L, idx))
+ return Value();
+ // otherwise fall thought
+ case LUA_TLIGHTUSERDATA: // fall thought
+ case LUA_TUSERDATA: // fall thought
+ case LUA_TTHREAD: // fall thought
+ case LUA_TNONE: // fall thought
+ default:
+ luaL_error(L, "value type %s is not a valid json value", lua_typename(L, t));
+ return Value(); // Just make compiler happy
+ }
+ }
+
+ Value NumberValue(lua_State* L, int idx)
+ {
+ int64_t integer;
+ return luax::isinteger(L, idx, &integer) ? Value(integer) : Value(lua_tonumber(L, idx));
+ }
+
+ Value StringValue(lua_State* L, int idx, Allocator& allocator)
+ {
+ size_t len;
+ const char* s = lua_tolstring(L, idx, &len);
+ return Value(s, static_cast<SizeType>(len), allocator);
+ }
+
+ Value TableValue(lua_State* L, int idx, int depth, Allocator& allocator)
+ {
+ if (depth > 1024)
+ luaL_error(L, "nested too depth");
+
+ if (!lua_checkstack(L, 4)) // requires at least 4 slots in stack: table, key, value, key
+ luaL_error(L, "stack overflow");
+
+ return isarray(L, idx) ? ArrayValue(L, idx, depth, allocator) : ObjectValue(L, idx, depth, allocator);
+ }
+
+ Value ObjectValue(lua_State* L, int idx, int depth, Allocator& allocator)
+ {
+ Value object(rapidjson::kObjectType);
+ lua_pushvalue(L, idx);
+ lua_pushnil(L);
+ while (lua_next(L, -2))
+ {
+
+ if (lua_type(L, -2) == LUA_TSTRING)
+ {
+ object.AddMember(StringValue(L, -2, allocator), toValue(L, -1, depth, allocator), allocator);
+ }
+
+ // pop value, leaving original key
+ lua_pop(L, 1);
+
+ }
+
+ lua_pop(L, 1);
+ return object;
+ }
+
+ Value ArrayValue(lua_State* L, int idx, int depth, Allocator& allocator)
+ {
+ Value array(rapidjson::kArrayType);
+ auto MAX = static_cast<int>(luax::rawlen(L, idx)); // luax::rawlen always returns size_t (>= 0)
+ for (auto n = 1; n <= MAX; ++n)
+ {
+ lua_rawgeti(L, idx, n);
+ array.PushBack(toValue(L, -1, depth, allocator), allocator);
+ lua_pop(L, 1);
+ }
+
+
+ return array;
+ }
+ }
+}
diff --git a/src/script/rapidjson/values.hpp b/src/script/rapidjson/values.hpp
new file mode 100644
index 0000000..7fb3abe
--- /dev/null
+++ b/src/script/rapidjson/values.hpp
@@ -0,0 +1,245 @@
+#ifndef __LUA_RAPIDJSON_TOLUAHANDLER_HPP__
+#define __LUA_RAPIDJSON_TOLUAHANDLER_HPP__
+
+#include <vector>
+
+
+#include "qcommon/q3_lauxlib.h"
+#include "lua.hpp"
+#include "rapidjson.h"
+
+#include "luax.hpp"
+namespace values
+{
+ typedef rapidjson::Document::AllocatorType Allocator;
+
+ int json_null(lua_State* L);
+
+ inline bool isnull(lua_State* L, int idx)
+ {
+ lua_pushvalue(L, idx); // [value]
+
+ json_null(L); // [value, json.null]
+ auto is = lua_rawequal(L, -1, -2) != 0;
+ lua_pop(L, 2); // []
+
+ return is;
+ }
+
+ inline bool hasJsonType(lua_State* L, int idx, bool& isarray)
+ {
+ auto has = false;
+ if (lua_getmetatable(L, idx))
+ {
+ // [metatable]
+ lua_getfield(L, -1, "__jsontype"); // [metatable, metatable.__jsontype]
+ if (lua_isstring(L, -1))
+ {
+ size_t len;
+ auto s = lua_tolstring(L, -1, &len);
+ isarray = strncmp(s, "array", 6) == 0;
+ has = true;
+ }
+ lua_pop(L, 2); // []
+ }
+
+ return has;
+ }
+
+ inline bool isarray(lua_State* L, int idx)
+ {
+ auto arr = false;
+ if (hasJsonType(L, idx, arr)) // any table with a meta field __jsontype set to 'array' are arrays
+ return arr;
+
+ return luax::rawlen(L, idx) > 0; // any table has length > 0 are treat as array.
+ }
+
+ /**
+ * Handle json SAX events and create Lua object.
+ */
+ struct ToLuaHandler
+ {
+ explicit ToLuaHandler(lua_State* aL) : L(aL)
+ { stack_.reserve(32); }
+
+ bool Null()
+ {
+ json_null(L);
+ context_.submit(L);
+ return true;
+ }
+ bool Bool(bool b)
+ {
+ lua_pushboolean(L, b);
+ context_.submit(L);
+ return true;
+ }
+ bool Int(int i)
+ {
+ lua_pushinteger(L, i);
+ context_.submit(L);
+ return true;
+ }
+ bool Uint(unsigned u)
+ {
+ if (sizeof(lua_Integer) > sizeof(unsigned int) || u <= static_cast<unsigned>(std::numeric_limits<lua_Integer>::max()))
+ lua_pushinteger(L, static_cast<lua_Integer>(u));
+ else
+ lua_pushnumber(L, static_cast<lua_Number>(u));
+ context_.submit(L);
+ return true;
+ }
+ bool Int64(int64_t i)
+ {
+ if (sizeof(lua_Integer) >= sizeof(int64_t) || (i <= std::numeric_limits<lua_Integer>::max() && i >= std::numeric_limits<lua_Integer>::min()))
+ lua_pushinteger(L, static_cast<lua_Integer>(i));
+ else
+ lua_pushnumber(L, static_cast<lua_Number>(i));
+ context_.submit(L);
+ return true;
+ }
+ bool Uint64(uint64_t u)
+ {
+ if (sizeof(lua_Integer) > sizeof(uint64_t) || u <= static_cast<uint64_t>(std::numeric_limits<lua_Integer>::max()))
+ lua_pushinteger(L, static_cast<lua_Integer>(u));
+ else
+ lua_pushnumber(L, static_cast<lua_Number>(u));
+ context_.submit(L);
+ return true;
+ }
+ bool Double(double d)
+ {
+ lua_pushnumber(L, static_cast<lua_Number>(d));
+ context_.submit(L);
+ return true;
+ }
+ bool RawNumber(const char* str, rapidjson::SizeType length, bool copy)
+ {
+ lua_getglobal(L, "tonumber");
+ lua_pushlstring(L, str, length);
+ lua_call(L, 1, 1);
+ context_.submit(L);
+ return true;
+ }
+ bool String(const char* str, rapidjson::SizeType length, bool copy)
+ {
+ lua_pushlstring(L, str, length);
+ context_.submit(L);
+ return true;
+ }
+ bool StartObject()
+ {
+ lua_createtable(L, 0, 0); // [..., object]
+
+ // mark as object.
+ luaL_getmetatable(L, "json.object"); //[..., object, json.object]
+ lua_setmetatable(L, -2); // [..., object]
+
+ stack_.push_back(context_);
+ context_ = Ctx::Object();
+ return true;
+ }
+ bool Key(const char* str, rapidjson::SizeType length, bool copy) const
+ {
+ lua_pushlstring(L, str, length);
+ return true;
+ }
+ bool EndObject(rapidjson::SizeType memberCount)
+ {
+ context_ = stack_.back();
+ stack_.pop_back();
+ context_.submit(L);
+ return true;
+ }
+ bool StartArray()
+ {
+ lua_createtable(L, 0, 0);
+
+ // mark as array.
+ luaL_getmetatable(L, "json.array"); //[..., array, json.array]
+ lua_setmetatable(L, -2); // [..., array]
+
+ stack_.push_back(context_);
+ context_ = Ctx::Array();
+ return true;
+ }
+ bool EndArray(rapidjson::SizeType elementCount)
+ {
+ assert(elementCount == context_.index_);
+ context_ = stack_.back();
+ stack_.pop_back();
+ context_.submit(L);
+ return true;
+ }
+ private:
+
+
+ struct Ctx
+ {
+ Ctx() : index_(0), fn_(&topFn) {}
+ Ctx(const Ctx& rhs) : index_(rhs.index_), fn_(rhs.fn_) {}
+
+ const Ctx& operator=(const Ctx& rhs)
+ {
+ if (this != &rhs)
+ {
+ index_ = rhs.index_;
+ fn_ = rhs.fn_;
+ }
+ return *this;
+ }
+
+ static Ctx Object()
+ { return Ctx(&objectFn); }
+
+ static Ctx Array()
+ { return Ctx(&arrayFn); }
+
+ void submit(lua_State* L)
+ { fn_(L, this); }
+
+ int index_;
+
+ void(*fn_)(lua_State* L, Ctx* ctx);
+
+ private:
+ explicit Ctx(void(*f)(lua_State* L, Ctx* ctx)) : index_(0), fn_(f) {}
+
+ static void objectFn(lua_State* L, Ctx* ctx)
+ { lua_rawset(L, -3); }
+
+ static void arrayFn(lua_State* L, Ctx* ctx)
+ { lua_rawseti(L, -2, ++ctx->index_); }
+
+ static void topFn(lua_State* L, Ctx* ctx) {}
+ };
+
+ lua_State* L;
+ std::vector < Ctx > stack_;
+ Ctx context_;
+ };
+
+ namespace details
+ {
+ rapidjson::Value toValue(lua_State* L, int idx, int depth, Allocator& allocator);
+ }
+
+ inline rapidjson::Value toValue(lua_State* L, int idx, Allocator& allocator)
+ {
+ return details::toValue(L, idx, 0, allocator);
+ }
+
+ inline void toDocument(lua_State* L, int idx, rapidjson::Document* doc)
+ {
+ details::toValue(L, idx, 0, doc->GetAllocator()).Swap(*doc);
+ }
+
+ inline void push(lua_State* L, const rapidjson::Value& v)
+ {
+ ToLuaHandler handler(L);
+ v.Accept(handler);
+ }
+}
+
+#endif
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
new file mode 100644
index 0000000..20dbe32
--- /dev/null
+++ b/src/sdl/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library (
+ sdl STATIC
+ sdl_gamma.cpp
+ sdl_glimp.cpp
+ sdl_icon.h
+ sdl_input.cpp
+ sdl_snd.cpp
+)
diff --git a/src/sdl/sdl_gamma.cpp b/src/sdl/sdl_gamma.cpp
new file mode 100644
index 0000000..372fdf2
--- /dev/null
+++ b/src/sdl/sdl_gamma.cpp
@@ -0,0 +1,100 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifdef USE_LOCAL_HEADERS
+# include "SDL.h"
+#else
+# include <SDL.h>
+#endif
+
+#include "qcommon/cvar.h"
+#include "qcommon/qcommon.h"
+#include "renderercommon/tr_common.h"
+
+extern SDL_Window *SDL_window;
+
+/*
+=================
+GLimp_SetGamma
+=================
+*/
+void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] )
+{
+ Uint16 table[3][256];
+ int i, j;
+
+ if( !glConfig.deviceSupportsGamma || r_ignorehwgamma->integer > 0 )
+ return;
+
+ for (i = 0; i < 256; i++)
+ {
+ table[0][i] = ( ( ( Uint16 ) red[i] ) << 8 ) | red[i];
+ table[1][i] = ( ( ( Uint16 ) green[i] ) << 8 ) | green[i];
+ table[2][i] = ( ( ( Uint16 ) blue[i] ) << 8 ) | blue[i];
+ }
+
+#ifdef _WIN32
+ // Win2K and newer put this odd restriction on gamma ramps...
+ {
+ OSVERSIONINFO vinfo;
+
+ vinfo.dwOSVersionInfoSize = sizeof( vinfo );
+ GetVersionEx( &vinfo );
+ if( vinfo.dwMajorVersion >= 5 && vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
+ {
+ ri.Printf( PRINT_DEVELOPER, "performing gamma clamp.\n" );
+ for( j = 0 ; j < 3 ; j++ )
+ {
+ for( i = 0 ; i < 128 ; i++ )
+ {
+ if( table[ j ] [ i] > ( ( 128 + i ) << 8 ) )
+ table[ j ][ i ] = ( 128 + i ) << 8;
+ }
+
+ if( table[ j ] [127 ] > 254 << 8 )
+ table[ j ][ 127 ] = 254 << 8;
+ }
+ }
+ }
+#endif
+
+ // enforce constantly increasing
+ for (j = 0; j < 3; j++)
+ {
+ for (i = 1; i < 256; i++)
+ {
+ if (table[j][i] < table[j][i-1])
+ table[j][i] = table[j][i-1];
+ }
+ }
+
+ if (SDL_SetWindowGammaRamp(SDL_window, table[0], table[1], table[2]) < 0)
+ {
+ ri.Printf( PRINT_DEVELOPER, "SDL_SetWindowGammaRamp() failed: %s\n", SDL_GetError() );
+ }
+}
diff --git a/src/sdl/sdl_glimp.cpp b/src/sdl/sdl_glimp.cpp
new file mode 100644
index 0000000..9ecd224
--- /dev/null
+++ b/src/sdl/sdl_glimp.cpp
@@ -0,0 +1,935 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifdef USE_LOCAL_HEADERS
+# include "SDL.h"
+#else
+# include <SDL.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "renderercommon/tr_common.h"
+#include "qcommon/cvar.h"
+#include "sys/sys_local.h"
+#include "sdl_icon.h"
+
+typedef enum
+{
+ RSERR_OK,
+
+ RSERR_INVALID_FULLSCREEN,
+ RSERR_INVALID_MODE,
+
+ RSERR_UNKNOWN
+} rserr_t;
+
+SDL_Window *SDL_window = NULL;
+static SDL_GLContext SDL_glContext = NULL;
+
+cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obtained
+cvar_t *r_allowResize; // make window resizable
+cvar_t *r_centerWindow;
+cvar_t *r_sdlDriver;
+
+void (APIENTRYP qglActiveTextureARB) (GLenum texture);
+void (APIENTRYP qglClientActiveTextureARB) (GLenum texture);
+void (APIENTRYP qglMultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t);
+
+void (APIENTRYP qglLockArraysEXT) (GLint first, GLsizei count);
+void (APIENTRYP qglUnlockArraysEXT) (void);
+
+/*
+===============
+GLimp_Shutdown
+===============
+*/
+void GLimp_Shutdown( void )
+{
+ float oldDisplayAspect = glConfig.displayAspect;
+
+ ri.IN_Shutdown();
+
+ SDL_QuitSubSystem( SDL_INIT_VIDEO );
+
+ glConfig.displayAspect = oldDisplayAspect;
+}
+
+/*
+===============
+GLimp_Minimize
+
+Minimize the game so that user is back at the desktop
+===============
+*/
+void GLimp_Minimize( void )
+{
+ SDL_MinimizeWindow( SDL_window );
+}
+
+
+/*
+===============
+GLimp_LogComment
+===============
+*/
+void GLimp_LogComment( const char *comment )
+{
+}
+
+/*
+===============
+GLimp_CompareModes
+===============
+*/
+static int GLimp_CompareModes( const void *a, const void *b )
+{
+ const float ASPECT_EPSILON = 0.001f;
+ SDL_Rect *modeA = (SDL_Rect *)a;
+ SDL_Rect *modeB = (SDL_Rect *)b;
+ float aspectA = (float)modeA->w / (float)modeA->h;
+ float aspectB = (float)modeB->w / (float)modeB->h;
+ int areaA = modeA->w * modeA->h;
+ int areaB = modeB->w * modeB->h;
+ float aspectDiffA = fabs( aspectA - glConfig.displayAspect );
+ float aspectDiffB = fabs( aspectB - glConfig.displayAspect );
+ float aspectDiffsDiff = aspectDiffA - aspectDiffB;
+
+ if( aspectDiffsDiff > ASPECT_EPSILON )
+ return 1;
+ else if( aspectDiffsDiff < -ASPECT_EPSILON )
+ return -1;
+ else
+ return areaA - areaB;
+}
+
+
+/*
+===============
+GLimp_DetectAvailableModes
+===============
+*/
+static void GLimp_DetectAvailableModes(void)
+{
+ int i, j;
+ char buf[ MAX_STRING_CHARS ] = { 0 };
+ int numSDLModes;
+ SDL_Rect *modes;
+ int numModes = 0;
+
+ SDL_DisplayMode windowMode;
+ int display = SDL_GetWindowDisplayIndex( SDL_window );
+ if( display < 0 )
+ {
+ ri.Printf( PRINT_WARNING, "Couldn't get window display index, no resolutions detected: %s\n", SDL_GetError() );
+ return;
+ }
+ numSDLModes = SDL_GetNumDisplayModes( display );
+
+ if( SDL_GetWindowDisplayMode( SDL_window, &windowMode ) < 0 || numSDLModes <= 0 )
+ {
+ ri.Printf( PRINT_WARNING, "Couldn't get window display mode, no resolutions detected: %s\n", SDL_GetError() );
+ return;
+ }
+
+ modes = (SDL_Rect*)SDL_calloc( (size_t)numSDLModes, sizeof( SDL_Rect ) );
+ if ( !modes )
+ {
+ ri.Error( ERR_FATAL, "Out of memory" );
+ }
+
+ for( i = 0; i < numSDLModes; i++ )
+ {
+ SDL_DisplayMode mode;
+
+ if( SDL_GetDisplayMode( display, i, &mode ) < 0 )
+ continue;
+
+ if( !mode.w || !mode.h )
+ {
+ ri.Printf( PRINT_ALL, "Display supports any resolution\n" );
+ SDL_free( modes );
+ return;
+ }
+
+ if( windowMode.format != mode.format )
+ continue;
+
+ // SDL can give the same resolution with different refresh rates.
+ // Only list resolution once.
+ for( j = 0; j < numModes; j++ )
+ {
+ if( mode.w == modes[ j ].w && mode.h == modes[ j ].h )
+ break;
+ }
+
+ if( j != numModes )
+ continue;
+
+ modes[ numModes ].w = mode.w;
+ modes[ numModes ].h = mode.h;
+ numModes++;
+ }
+
+ if( numModes > 1 )
+ qsort( modes, numModes, sizeof( SDL_Rect ), GLimp_CompareModes );
+
+ for( i = 0; i < numModes; i++ )
+ {
+ const char *newModeString = va( "%ux%u ", modes[ i ].w, modes[ i ].h );
+
+ if( strlen( newModeString ) < (int)sizeof( buf ) - strlen( buf ) )
+ Q_strcat( buf, sizeof( buf ), newModeString );
+ else
+ ri.Printf( PRINT_WARNING, "Skipping mode %ux%u, buffer too small\n", modes[ i ].w, modes[ i ].h );
+ }
+
+ if( *buf )
+ {
+ buf[ strlen( buf ) - 1 ] = 0;
+ ri.Printf( PRINT_ALL, "Available modes: '%s'\n", buf );
+ ri.Cvar_Set( "r_availableModes", buf );
+ }
+ SDL_free( modes );
+}
+
+#define R_FAILSAFE_WIDTH 640
+#define R_FAILSAFE_HEIGHT 480
+
+/*
+===============
+GLimp_SetMode
+===============
+*/
+static int GLimp_SetMode( bool failSafe, bool fullscreen, bool noborder, bool coreContext )
+{
+ const char *glstring;
+ int perChannelColorBits;
+ int colorBits, alphaBits, depthBits, stencilBits;
+ int samples;
+ int i = 0;
+ SDL_Surface *icon = NULL;
+ Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL;
+ SDL_DisplayMode desktopMode;
+ int display = 0;
+ int x = SDL_WINDOWPOS_UNDEFINED, y = SDL_WINDOWPOS_UNDEFINED;
+
+ ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");
+
+ if ( r_allowResize->integer )
+ flags |= SDL_WINDOW_RESIZABLE;
+
+#ifdef USE_ICON
+ icon = SDL_CreateRGBSurfaceFrom(
+ (void *)CLIENT_WINDOW_ICON.pixel_data,
+ CLIENT_WINDOW_ICON.width,
+ CLIENT_WINDOW_ICON.height,
+ CLIENT_WINDOW_ICON.bytes_per_pixel * 8,
+ CLIENT_WINDOW_ICON.bytes_per_pixel * CLIENT_WINDOW_ICON.width,
+#ifdef Q3_LITTLE_ENDIAN
+ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
+#else
+ 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
+#endif
+ );
+#endif
+
+ // If a window exists, note its display index
+ if( SDL_window != NULL )
+ {
+ display = SDL_GetWindowDisplayIndex( SDL_window );
+ if( display < 0 )
+ {
+ ri.Printf( PRINT_DEVELOPER, "SDL_GetWindowDisplayIndex() failed: %s\n", SDL_GetError() );
+ }
+ }
+
+ if( display >= 0 && SDL_GetDesktopDisplayMode( display, &desktopMode ) == 0 )
+ {
+ glConfig.displayAspect = (float)desktopMode.w / (float)desktopMode.h;
+
+ ri.Printf( PRINT_ALL, "Display aspect: %.3f\n", glConfig.displayAspect );
+ }
+ else
+ {
+ Com_Memset( &desktopMode, 0, sizeof( SDL_DisplayMode ) );
+
+ ri.Printf( PRINT_ALL,
+ "Cannot determine display aspect, assuming 1.333\n" );
+ }
+
+ if( !failSafe )
+ {
+ if( r_width->integer > 0 && r_height->integer > 0 )
+ {
+ glConfig.vidWidth = r_width->integer;
+ glConfig.vidHeight = r_height->integer;
+ }
+ else if( desktopMode.h > 0 )
+ {
+ // use desktop video resolution
+ glConfig.vidWidth = desktopMode.w;
+ glConfig.vidHeight = desktopMode.h;
+ }
+ else
+ {
+ glConfig.vidWidth = 640;
+ glConfig.vidHeight = 480;
+ ri.Printf( PRINT_ALL,
+ "Cannot determine display resolution, assuming 640x480\n" );
+ }
+
+ glConfig.windowAspect = (float)glConfig.vidWidth /
+ ( (float)glConfig.vidHeight * r_pixelAspect->value );
+ }
+ else if( glConfig.vidWidth != R_FAILSAFE_WIDTH &&
+ glConfig.vidHeight != R_FAILSAFE_HEIGHT )
+ {
+ ri.Printf( PRINT_ALL, "Setting mode %dx%d failed, falling back on mode %dx%d\n",
+ glConfig.vidWidth, glConfig.vidHeight, R_FAILSAFE_WIDTH, R_FAILSAFE_HEIGHT );
+
+ glConfig.vidWidth = R_FAILSAFE_WIDTH;
+ glConfig.vidHeight = R_FAILSAFE_HEIGHT;
+ glConfig.windowAspect = 1.0f;
+ }
+ else
+ return RSERR_INVALID_MODE;
+
+ ri.Printf (PRINT_ALL, "...setting mode %dx%d\n", glConfig.vidWidth, glConfig.vidHeight);
+
+ // Center window
+ if( r_centerWindow->integer && !fullscreen )
+ {
+ x = ( desktopMode.w / 2 ) - ( glConfig.vidWidth / 2 );
+ y = ( desktopMode.h / 2 ) - ( glConfig.vidHeight / 2 );
+ }
+
+ // Destroy existing state if it exists
+ if( SDL_glContext != NULL )
+ {
+ SDL_GL_DeleteContext( SDL_glContext );
+ SDL_glContext = NULL;
+ }
+
+ if( SDL_window != NULL )
+ {
+ SDL_GetWindowPosition( SDL_window, &x, &y );
+ ri.Printf( PRINT_DEVELOPER, "Existing window at %dx%d before being destroyed\n", x, y );
+ SDL_DestroyWindow( SDL_window );
+ SDL_window = NULL;
+ }
+
+ if( fullscreen )
+ {
+ flags |= SDL_WINDOW_FULLSCREEN;
+ glConfig.isFullscreen = qtrue;
+ }
+ else
+ {
+ if( noborder )
+ flags |= SDL_WINDOW_BORDERLESS;
+
+ glConfig.isFullscreen = qfalse;
+ }
+
+ colorBits = r_colorbits->value;
+ if ((!colorBits) || (colorBits >= 32))
+ colorBits = 24;
+
+ alphaBits = r_alphabits->value;
+
+ if (!r_depthbits->value)
+ depthBits = 24;
+ else
+ depthBits = r_depthbits->value;
+
+ stencilBits = r_stencilbits->value;
+ samples = r_ext_multisample->value;
+
+ for (i = 0; i < 16; i++)
+ {
+ int testColorBits, testDepthBits, testStencilBits;
+
+ // 0 - default
+ // 1 - minus colorBits
+ // 2 - minus depthBits
+ // 3 - minus stencil
+ if ((i % 4) == 0 && i)
+ {
+ // one pass, reduce
+ switch (i / 4)
+ {
+ case 2 :
+ if (colorBits == 24)
+ colorBits = 16;
+ break;
+ case 1 :
+ if (depthBits == 24)
+ depthBits = 16;
+ else if (depthBits == 16)
+ depthBits = 8;
+ case 3 :
+ if (stencilBits == 24)
+ stencilBits = 16;
+ else if (stencilBits == 16)
+ stencilBits = 8;
+ }
+ }
+
+ testColorBits = colorBits;
+ testDepthBits = depthBits;
+ testStencilBits = stencilBits;
+
+ if ((i % 4) == 3)
+ { // reduce colorBits
+ if (testColorBits == 24)
+ testColorBits = 16;
+ }
+
+ if ((i % 4) == 2)
+ { // reduce depthBits
+ if (testDepthBits == 24)
+ testDepthBits = 16;
+ else if (testDepthBits == 16)
+ testDepthBits = 8;
+ }
+
+ if ((i % 4) == 1)
+ { // reduce stencilBits
+ if (testStencilBits == 24)
+ testStencilBits = 16;
+ else if (testStencilBits == 16)
+ testStencilBits = 8;
+ else
+ testStencilBits = 0;
+ }
+
+ if (testColorBits == 24)
+ perChannelColorBits = 8;
+ else
+ perChannelColorBits = 4;
+
+#ifdef __sgi /* Fix for SGIs grabbing too many bits of color */
+ if (perChannelColorBits == 4)
+ perChannelColorBits = 0; /* Use minimum size for 16-bit color */
+
+ /* Need alpha or else SGIs choose 36+ bit RGB mode */
+ if (alphaBits < 1)
+ alphaBits = 1;
+#endif
+
+ SDL_GL_SetAttribute( SDL_GL_RED_SIZE, perChannelColorBits );
+ SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, perChannelColorBits );
+ SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, perChannelColorBits );
+ SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, alphaBits );
+ SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, testDepthBits );
+ SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, testStencilBits );
+
+ SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0 );
+ SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, samples );
+
+ if(r_stereoEnabled->integer)
+ {
+ glConfig.stereoEnabled = qtrue;
+ SDL_GL_SetAttribute(SDL_GL_STEREO, 1);
+ }
+ else
+ {
+ glConfig.stereoEnabled = qfalse;
+ SDL_GL_SetAttribute(SDL_GL_STEREO, 0);
+ }
+
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+
+#if 0 // if multisampling is enabled on X11, this causes create window to fail.
+ // If not allowing software GL, demand accelerated
+ if( !r_allowSoftwareGL->integer )
+ SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
+#endif
+
+ if( ( SDL_window = SDL_CreateWindow( CLIENT_WINDOW_TITLE, x, y,
+ glConfig.vidWidth, glConfig.vidHeight, flags ) ) == NULL )
+ {
+ ri.Printf( PRINT_DEVELOPER, "SDL_CreateWindow failed: %s\n", SDL_GetError( ) );
+ continue;
+ }
+
+ if( fullscreen )
+ {
+ SDL_DisplayMode mode;
+
+ switch( testColorBits )
+ {
+ case 16: mode.format = SDL_PIXELFORMAT_RGB565; break;
+ case 24: mode.format = SDL_PIXELFORMAT_RGB24; break;
+ default: ri.Printf( PRINT_DEVELOPER, "testColorBits is %d, can't fullscreen\n", testColorBits ); continue;
+ }
+
+ mode.w = glConfig.vidWidth;
+ mode.h = glConfig.vidHeight;
+ mode.refresh_rate = glConfig.displayFrequency = ri.Cvar_VariableIntegerValue( "r_displayRefresh" );
+ mode.driverdata = NULL;
+
+ if( SDL_SetWindowDisplayMode( SDL_window, &mode ) < 0 )
+ {
+ ri.Printf( PRINT_DEVELOPER, "SDL_SetWindowDisplayMode failed: %s\n", SDL_GetError( ) );
+ continue;
+ }
+ }
+
+ SDL_SetWindowIcon( SDL_window, icon );
+
+ if (coreContext)
+ {
+ int profileMask, majorVersion, minorVersion;
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profileMask);
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion);
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion);
+
+ ri.Printf(PRINT_ALL, "Trying to get an OpenGL 3.2 core context\n");
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
+ if ((SDL_glContext = SDL_GL_CreateContext(SDL_window)) == NULL)
+ {
+ ri.Printf(PRINT_ALL, "SDL_GL_CreateContext failed: %s\n", SDL_GetError());
+ ri.Printf(PRINT_ALL, "Reverting to default context\n");
+
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profileMask);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minorVersion);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, "SDL_GL_CreateContext succeeded.\n");
+
+ const char *renderer = (const char*)qglGetString(GL_RENDERER);
+ if (renderer && (strstr(renderer, "Software Renderer") || strstr(renderer, "Software Rasterizer")))
+ {
+ ri.Printf(PRINT_ALL, "GL_RENDERER is %s, rejecting context\n", renderer);
+
+ SDL_GL_DeleteContext(SDL_glContext);
+ SDL_glContext = NULL;
+
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profileMask);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minorVersion);
+ }
+ }
+ }
+ else
+ {
+ SDL_glContext = NULL;
+ }
+
+ if( !SDL_glContext && ( SDL_glContext = SDL_GL_CreateContext( SDL_window ) ) == NULL )
+ {
+ ri.Printf( PRINT_DEVELOPER, "SDL_GL_CreateContext failed: %s\n", SDL_GetError( ) );
+ continue;
+ }
+
+ qglClearColor( 0, 0, 0, 1 );
+ qglClear( GL_COLOR_BUFFER_BIT );
+ SDL_GL_SwapWindow( SDL_window );
+
+ if( SDL_GL_SetSwapInterval( r_swapInterval->integer ) == -1 )
+ {
+ ri.Printf( PRINT_DEVELOPER, "SDL_GL_SetSwapInterval failed: %s\n", SDL_GetError( ) );
+ }
+
+ glConfig.colorBits = testColorBits;
+ glConfig.depthBits = testDepthBits;
+ glConfig.stencilBits = testStencilBits;
+
+ ri.Printf( PRINT_ALL, "Using %d color bits, %d depth, %d stencil display.\n",
+ glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits );
+ break;
+ }
+
+ SDL_FreeSurface( icon );
+
+ if( !SDL_window )
+ {
+ ri.Printf( PRINT_ALL, "Couldn't get a visual\n" );
+ return RSERR_INVALID_MODE;
+ }
+
+ GLimp_DetectAvailableModes();
+
+ glstring = (char *) qglGetString (GL_RENDERER);
+ ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glstring );
+
+ return RSERR_OK;
+}
+
+/*
+===============
+GLimp_StartDriverAndSetMode
+===============
+*/
+static bool GLimp_StartDriverAndSetMode( bool failSafe, bool fullscreen, bool noborder, bool gl3Core )
+{
+ if (!SDL_WasInit(SDL_INIT_VIDEO))
+ {
+
+ if (SDL_Init(SDL_INIT_VIDEO) != 0)
+ {
+ ri.Printf( PRINT_ALL, "SDL_Init( SDL_INIT_VIDEO ) FAILED (%s)\n", SDL_GetError());
+ return false;
+ }
+
+ const char *driverName = SDL_GetCurrentVideoDriver( );
+ ri.Printf( PRINT_ALL, "SDL using driver \"%s\"\n", driverName );
+ ri.Cvar_Set( "r_sdlDriver", driverName );
+ }
+
+ if (fullscreen && ri.Cvar_VariableIntegerValue( "in_nograb" ) )
+ {
+ ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n");
+ ri.Cvar_Set( "r_fullscreen", "0" );
+ r_fullscreen->modified = qfalse;
+ fullscreen = false;
+ }
+
+ rserr_t err = (rserr_t)GLimp_SetMode( failSafe, fullscreen, noborder, gl3Core );
+
+ switch ( err )
+ {
+ case RSERR_INVALID_FULLSCREEN:
+ ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" );
+ return false;
+ case RSERR_INVALID_MODE:
+ ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode\n" );
+ return false;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static bool GLimp_HaveExtension(const char *ext)
+{
+ const char *ptr = Q_stristr( glConfig.extensions_string, ext );
+ if (ptr == NULL)
+ return qfalse;
+ ptr += strlen(ext);
+ return ((*ptr == ' ') || (*ptr == '\0')); // verify it's complete string.
+}
+
+
+/*
+===============
+GLimp_InitExtensions
+===============
+*/
+static void GLimp_InitExtensions( void )
+{
+ if ( !r_allowExtensions->integer )
+ {
+ ri.Printf( PRINT_ALL, "* IGNORING OPENGL EXTENSIONS *\n" );
+ return;
+ }
+
+ ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" );
+
+ glConfig.textureCompression = TC_NONE;
+
+ // GL_EXT_texture_compression_s3tc
+ if ( GLimp_HaveExtension( "GL_ARB_texture_compression" ) &&
+ GLimp_HaveExtension( "GL_EXT_texture_compression_s3tc" ) )
+ {
+ if ( r_ext_compressed_textures->value )
+ {
+ glConfig.textureCompression = TC_S3TC_ARB;
+ ri.Printf( PRINT_ALL, "...using GL_EXT_texture_compression_s3tc\n" );
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_compression_s3tc\n" );
+ }
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...GL_EXT_texture_compression_s3tc not found\n" );
+ }
+
+ // GL_S3_s3tc ... legacy extension before GL_EXT_texture_compression_s3tc.
+ if (glConfig.textureCompression == TC_NONE)
+ {
+ if ( GLimp_HaveExtension( "GL_S3_s3tc" ) )
+ {
+ if ( r_ext_compressed_textures->value )
+ {
+ glConfig.textureCompression = TC_S3TC;
+ ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" );
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" );
+ }
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" );
+ }
+ }
+
+
+ // GL_EXT_texture_env_add
+ glConfig.textureEnvAddAvailable = qfalse;
+ if ( GLimp_HaveExtension( "GL_EXT_texture_env_add" ) )
+ {
+ if ( r_ext_texture_env_add->integer )
+ {
+ glConfig.textureEnvAddAvailable = qtrue;
+ ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" );
+ }
+ else
+ {
+ glConfig.textureEnvAddAvailable = qfalse;
+ ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" );
+ }
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" );
+ }
+
+ // GL_ARB_multitexture
+ qglMultiTexCoord2fARB = NULL;
+ qglActiveTextureARB = NULL;
+ qglClientActiveTextureARB = NULL;
+ if ( GLimp_HaveExtension( "GL_ARB_multitexture" ) )
+ {
+ if ( r_ext_multitexture->value )
+ {
+ qglMultiTexCoord2fARB = (decltype(qglMultiTexCoord2fARB)) SDL_GL_GetProcAddress( "glMultiTexCoord2fARB" );
+ qglActiveTextureARB = (decltype(qglActiveTextureARB)) SDL_GL_GetProcAddress( "glActiveTextureARB" );
+ qglClientActiveTextureARB = (decltype(qglClientActiveTextureARB)) SDL_GL_GetProcAddress( "glClientActiveTextureARB" );
+
+ if ( qglActiveTextureARB )
+ {
+ GLint glint = 0;
+ qglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &glint );
+ glConfig.numTextureUnits = (int) glint;
+ if ( glConfig.numTextureUnits > 1 )
+ {
+ ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" );
+ }
+ else
+ {
+ qglMultiTexCoord2fARB = NULL;
+ qglActiveTextureARB = NULL;
+ qglClientActiveTextureARB = NULL;
+ ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" );
+ }
+ }
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" );
+ }
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" );
+ }
+
+ // GL_EXT_compiled_vertex_array
+ if ( GLimp_HaveExtension( "GL_EXT_compiled_vertex_array" ) )
+ {
+ if ( r_ext_compiled_vertex_array->value )
+ {
+ ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" );
+ qglLockArraysEXT = ( void ( APIENTRY * )( GLint, GLint ) ) SDL_GL_GetProcAddress( "glLockArraysEXT" );
+ qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) SDL_GL_GetProcAddress( "glUnlockArraysEXT" );
+ if (!qglLockArraysEXT || !qglUnlockArraysEXT)
+ {
+ ri.Error (ERR_FATAL, "bad getprocaddress");
+ }
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" );
+ }
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" );
+ }
+
+ glConfig.textureFilterAnisotropic = qfalse;
+ if ( GLimp_HaveExtension( "GL_EXT_texture_filter_anisotropic" ) )
+ {
+ if ( r_ext_texture_filter_anisotropic->integer ) {
+ qglGetIntegerv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, (GLint *)&glConfig.maxAnisotropy );
+ if ( glConfig.maxAnisotropy <= 0 ) {
+ ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not properly supported!\n" );
+ glConfig.maxAnisotropy = 0;
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic (max: %i)\n", glConfig.maxAnisotropy );
+ glConfig.textureFilterAnisotropic = qtrue;
+ }
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" );
+ }
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" );
+ }
+}
+
+/*
+===============
+GLimp_Init
+
+This routine is responsible for initializing the OS specific portions
+of OpenGL
+===============
+*/
+void GLimp_Init(bool coreContext)
+{
+ ri.Printf( PRINT_DEVELOPER, "Glimp_Init( )\n" );
+
+ r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH );
+ r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM );
+ r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE | CVAR_LATCH );
+
+#ifndef DEBUG
+ if( ri.Cvar_VariableIntegerValue( "com_abnormalExit" ) )
+ {
+ ri.Cvar_Set( "r_width", va( "%d", R_FAILSAFE_WIDTH ) );
+ ri.Cvar_Set( "r_height", va( "%d", R_FAILSAFE_HEIGHT ) );
+ ri.Cvar_Set( "r_fullscreen", "0" );
+ ri.Cvar_Set( "r_centerWindow", "0" );
+ ri.Cvar_Set( "com_abnormalExit", "0" );
+ }
+#endif
+
+ ri.Sys_GLimpInit( );
+
+ // Create the window and set up the context
+ if( GLimp_StartDriverAndSetMode( false, r_fullscreen->integer, r_noborder->integer, coreContext ) )
+ goto success;
+
+ // Try again, this time in a platform specific "safe mode"
+ ri.Sys_GLimpSafeInit( );
+
+ if( GLimp_StartDriverAndSetMode( false, r_fullscreen->integer, false, coreContext ) )
+ goto success;
+
+ // Finally, try the default screen resolution
+ if( GLimp_StartDriverAndSetMode( true, r_fullscreen->integer, false, coreContext ) )
+ goto success;
+
+ // Nothing worked, give up
+ ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem" );
+
+success:
+ // These values force the UI to disable driver selection
+ glConfig.driverType = GLDRV_ICD;
+ glConfig.hardwareType = GLHW_GENERIC;
+
+ // Only using SDL_SetWindowBrightness to determine if hardware gamma is supported
+ glConfig.deviceSupportsGamma = (qboolean)(!r_ignorehwgamma->integer && SDL_SetWindowBrightness( SDL_window, 1.0f ) >= 0);
+
+ // get our config strings
+ Q_strncpyz( glConfig.vendor_string, (char *) qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) );
+ Q_strncpyz( glConfig.renderer_string, (char *) qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) );
+ if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n')
+ glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0;
+ Q_strncpyz( glConfig.version_string, (char *) qglGetString (GL_VERSION), sizeof( glConfig.version_string ) );
+ if (qglGetString(GL_EXTENSIONS))
+ Q_strncpyz( glConfig.extensions_string, (char *) qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) );
+ else
+ Q_strncpyz( glConfig.extensions_string, "Not available (core context, fixme)", sizeof( glConfig.extensions_string ) );
+
+ // initialize extensions
+ GLimp_InitExtensions( );
+
+ ri.Cvar_Get( "r_availableModes", "", CVAR_ROM );
+
+ // This depends on SDL_INIT_VIDEO, hence having it here
+ ri.IN_Init( SDL_window );
+}
+
+
+/*
+===============
+GLimp_EndFrame
+
+Responsible for doing a swapbuffers
+===============
+*/
+void GLimp_EndFrame( void )
+{
+ // don't flip if drawing to front buffer
+ if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 )
+ {
+ SDL_GL_SwapWindow( SDL_window );
+ }
+
+ if( r_fullscreen->modified )
+ {
+ int fullscreen;
+ bool needToToggle;
+ bool sdlToggled = false;
+
+ // Find out the current state
+ fullscreen = !!( SDL_GetWindowFlags( SDL_window ) & SDL_WINDOW_FULLSCREEN );
+
+ if( r_fullscreen->integer && ri.Cvar_VariableIntegerValue( "in_nograb" ) )
+ {
+ ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n");
+ ri.Cvar_Set( "r_fullscreen", "0" );
+ r_fullscreen->modified = false;
+ }
+
+ // Is the state we want different from the current state?
+ needToToggle = !!r_fullscreen->integer != fullscreen;
+
+ if( needToToggle )
+ {
+ sdlToggled = SDL_SetWindowFullscreen( SDL_window, r_fullscreen->integer ) >= 0;
+
+ // SDL_WM_ToggleFullScreen didn't work, so do it the slow way
+ if( !sdlToggled )
+ ri.Cmd_ExecuteText(EXEC_APPEND, "vid_restart\n");
+
+ ri.IN_Restart( );
+ }
+
+ r_fullscreen->modified = false;
+ }
+}
diff --git a/src/sdl/sdl_icon.h b/src/sdl/sdl_icon.h
new file mode 100644
index 0000000..03f7420
--- /dev/null
+++ b/src/sdl/sdl_icon.h
@@ -0,0 +1,138 @@
+/* GIMP RGBA C-Source image dump (sdl_icon.h) */
+
+static const struct {
+ unsigned int width;
+ unsigned int height;
+ unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */
+ unsigned char pixel_data[32 * 32 * 4 + 1];
+} CLIENT_WINDOW_ICON = {
+ 32, 32, 4,
+ "\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\17\17\17\34\17\17"
+ "\17U\17\17\17""9\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\30\30\30q\2\2\2\306\5\5\5\377\4\4\4\343\33\33\33"
+ "\252\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\31\31"
+ "\31\216\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\3\3\3\377\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%%%9\0\0"
+ "\0\0\0\0\0\0\10\10\10q\16\16\16q\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\11\11\11\377\0\0\0\377\0"
+ "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\13\13\13q\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\14\14\14q\15\15\15\343\16\16\16"
+ """9\0\0\0\0\12\12\12\252\10\10\10\377\30\30\30U\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\3\3\3\377\0\0\0\377"
+ "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\252\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\12\12\12\216\3\3\3\377\2\2\2\252\0\0\0"
+ "\0\0\0\0\0\37\37\37""9\3\3\3\377\3\3\3\306\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\2\2\2\377\0\0\0\377\0"
+ "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\3\3\3\343\15\15\15""9\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\14\14\14q\3\3\3\377\2\2\2\377\5\5\5""9\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\16\16\16\306\2\2\2\377\2\2\2\306\5\5\5\34\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\36\36\36\252\0\0\0\377\0\0\0"
+ "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\13\13\13\306\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\13\13\13\216\3\3\3\377\4\4\4\377\15\15\15U\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\17\17\17\34\14\14\14\306\1\1\1\377\2\2\2\306"
+ "\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\36\36\36\252\0\0"
+ "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
+ "U\0\0\0\0\0\0\0\0(((9\16\16\16\252\3\3\3\377\0\0\0\377\16\16\16\306\36\36"
+ "\36\34\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\306\0\0\0\377"
+ "\3\3\3\306\3\3\3\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\36\36\36q\0\0"
+ "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\6\343\31\31"
+ "\31""9\0\0\0\0\0\0\0\0\0\0\0\216\0\0\0\377\2\2\2\377\12\12\12\306\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\26\26\26U\7\7\7"
+ "\377\0\0\0\377\3\3\3\306\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\3\3\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\6\252\0"
+ "\0\0\0\15\15\15""9\6\6\6\252\0\0\0\377\0\0\0\377\12\12\12\306\16\16\16\34"
+ "\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"
+ "\6\6\6q\1\1\1\377\0\0\0\377\4\4\4\306\5\5\5\34\0\0\0\0\0\0\0\0\22\22\22\34"
+ "\32\32\32\306\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
+ "\21\21\21\216\33\33\33\306\3\3\3\377\0\0\0\377\1\1\1\377\11\11\11\306\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\3\3\3\216\1\1\1\377\1\1\1\377\4\4\4\306\0\0\0\0\0\0"
+ "\0\0\14\14\14U\4\4\4\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
+ "\0\0\0\377\4\4\4\306\3\3\3\377\0\0\0\377\0\0\0\377\11\11\11\306\15\15\15"
+ "\34\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\5\5\5\252\0\0\0\377\0\0\0\377\3\3\3\377"
+ "\5\5\5\377\3\3\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
+ "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\343\12\12\12\252\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\16\16\16""9\7\7\7\377\0\0\0\377\0\0"
+ "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
+ "\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2\2\377\2\2\2""9\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\2\2\2q\3\3\3\377\0\0"
+ "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
+ "\377\0\0\0\377\0\0\0\377\0\0\0U\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\20\20\20\216\5\5\5\377\0\0"
+ "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
+ "\377\0\0\0\377\0\0\0\306\0\0\0\252\0\0\0\252\0\0\0\252\0\0\0\252\0\0\0\252"
+ "\0\0\0\252\12\12\12\252\36\36\36""9\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\15\15\15U\6\6"
+ "\6\306\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
+ "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\252\0\0\0\252"
+ "\0\0\0\252\0\0\0\252\12\12\12\252\36\36\36""9\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\14\14\14""9\4\4\4\252"
+ "\4\4\4\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
+ "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2\2\216\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\31\31\31U\20\20\20\306\5\5\5\377\0\0\0\377\0\0\0\377"
+ "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
+ "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\12\12\12\343\26"
+ "\26\26""9\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\10\10\10\377\0\0\0\377\5\5\5\377\5\5\5\377"
+ "\0\0\0U\6\6\6\306\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
+ "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\24\24\24"
+ """9\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\"\"\"\252###\252\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\21\21\21""9\7\7\7\343\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
+ "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\20\20\20\306"
+ "\30\30\30\34\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\7\7\7\252\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
+ "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\3\3\3\377\22\22"
+ "\22\306\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\23\23\23U\6\6\6\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
+ "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
+ "\22\22\22\306\36\36\36\34\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\14\14\14\306\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
+ "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2\2\377\4\4\4\216\3\3\3\216\2\2"
+ "\2\377\5\5\5\377\17\17\17U\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\2\2\2\377\4\4\4\377\1\1\1\252\1\1\1\252\4\4\4\377\0\0\0\377\0"
+ "\0\0\377\0\0\0\377\0\0\0\377\2\2\2\377\11\11\11q\0\0\0\0\0\0\0\0\6\6\6q\2"
+ "\2\2\377\4\4\4\377\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\14\14"
+ "\14q\0\0\0\377\6\6\6\216\0\0\0\0\0\0\0\0\15\15\15U\2\2\2\306\0\0\0\377\0"
+ "\0\0\377\1\1\1\306\7\7\7U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\5\5\5\216\1\1\1"
+ "\377\3\3\3q\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\3\3\3\252\2\2\2\377\5"
+ "\5\5U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\31\31""9\31\31\31\252\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\26\26\26""9\13\13\13\343\5\5\5\377"
+ "\30\30\30\216\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\2\2\2\252\6\6\6\377\21\21\21"
+ "U\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\26\26\26""9\10\10\10\377\14\14\14\377\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\32\32\32U\11\11\11\377\0\0\0\252\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\2\2\2""9\12\12\12\343\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\32\32\32U\11\11\11\377\33\33\33\252\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%%%9\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\32\32\32""9\12\12\12"
+ "\343\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\17\17\17""9\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",
+};
+
diff --git a/src/sdl/sdl_input.cpp b/src/sdl/sdl_input.cpp
new file mode 100644
index 0000000..1e1056a
--- /dev/null
+++ b/src/sdl/sdl_input.cpp
@@ -0,0 +1,1336 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+#ifdef USE_LOCAL_HEADERS
+# include "SDL.h"
+#else
+# include <SDL.h>
+#endif
+
+#include "client/client.h"
+#include "sys/sys_local.h"
+
+static cvar_t *in_keyboardDebug = NULL;
+
+static SDL_GameController *gamepad = NULL;
+static SDL_Joystick *stick = NULL;
+
+static bool mouseAvailable = false;
+static bool mouseActive = false;
+
+static cvar_t *in_mouse = NULL;
+static cvar_t *in_nograb;
+
+static cvar_t *in_joystick = NULL;
+static cvar_t *in_joystickThreshold = NULL;
+static cvar_t *in_joystickNo = NULL;
+static cvar_t *in_joystickUseAnalog = NULL;
+
+static int vidRestartTime = 0;
+static int in_eventTime = 0;
+
+static SDL_Window *SDL_window = NULL;
+
+#define CTRL(a) ((a)-'a'+1)
+
+/*
+===============
+IN_PrintKey
+===============
+*/
+static void IN_PrintKey( const SDL_Keysym *keysym, keyNum_t key, bool down )
+{
+ if( down )
+ Com_Printf( "+ " );
+ else
+ Com_Printf( " " );
+
+ Com_Printf( "Scancode: 0x%02x(%s) Sym: 0x%02x(%s)",
+ keysym->scancode, SDL_GetScancodeName( keysym->scancode ),
+ keysym->sym, SDL_GetKeyName( keysym->sym ) );
+
+ if( keysym->mod & KMOD_LSHIFT ) Com_Printf( " KMOD_LSHIFT" );
+ if( keysym->mod & KMOD_RSHIFT ) Com_Printf( " KMOD_RSHIFT" );
+ if( keysym->mod & KMOD_LCTRL ) Com_Printf( " KMOD_LCTRL" );
+ if( keysym->mod & KMOD_RCTRL ) Com_Printf( " KMOD_RCTRL" );
+ if( keysym->mod & KMOD_LALT ) Com_Printf( " KMOD_LALT" );
+ if( keysym->mod & KMOD_RALT ) Com_Printf( " KMOD_RALT" );
+ if( keysym->mod & KMOD_LGUI ) Com_Printf( " KMOD_LGUI" );
+ if( keysym->mod & KMOD_RGUI ) Com_Printf( " KMOD_RGUI" );
+ if( keysym->mod & KMOD_NUM ) Com_Printf( " KMOD_NUM" );
+ if( keysym->mod & KMOD_CAPS ) Com_Printf( " KMOD_CAPS" );
+ if( keysym->mod & KMOD_MODE ) Com_Printf( " KMOD_MODE" );
+ if( keysym->mod & KMOD_RESERVED ) Com_Printf( " KMOD_RESERVED" );
+
+ Com_Printf( " Q:0x%02x(%s)\n", key, Key_KeynumToString( key ) );
+}
+
+#define MAX_CONSOLE_KEYS 16
+
+/*
+===============
+IN_IsConsoleKey
+
+TODO: If the SDL_Scancode situation improves, use it instead of
+ both of these methods
+===============
+*/
+static bool IN_IsConsoleKey( keyNum_t key, int character )
+{
+ typedef struct consoleKey_s
+ {
+ enum
+ {
+ QUAKE_KEY,
+ CHARACTER
+ } type;
+
+ union
+ {
+ keyNum_t key;
+ int character;
+ } u;
+ } consoleKey_t;
+
+ static consoleKey_t consoleKeys[ MAX_CONSOLE_KEYS ];
+ static int numConsoleKeys = 0;
+ int i;
+
+ // Only parse the variable when it changes
+ if( cl_consoleKeys->modified )
+ {
+ char *text_p, *token;
+
+ cl_consoleKeys->modified = qfalse;
+ text_p = cl_consoleKeys->string;
+ numConsoleKeys = 0;
+
+ while( numConsoleKeys < MAX_CONSOLE_KEYS )
+ {
+ consoleKey_t *c = &consoleKeys[ numConsoleKeys ];
+ int charCode = 0;
+
+ token = COM_Parse( &text_p );
+ if( !token[ 0 ] )
+ break;
+
+ if( strlen( token ) == 4 )
+ charCode = Com_HexStrToInt( token );
+
+ if( charCode > 0 )
+ {
+ c->type = consoleKey_s::CHARACTER;
+ c->u.character = charCode;
+ }
+ else
+ {
+ c->type = consoleKey_s::QUAKE_KEY;
+ c->u.key = (keyNum_t)Key_StringToKeynum( token );
+
+ // 0 isn't a key
+ if( c->u.key <= 0 )
+ continue;
+ }
+
+ numConsoleKeys++;
+ }
+ }
+
+ // If the character is the same as the key, prefer the character
+ if( key == character )
+ key = (keyNum_t)0;
+
+ for( i = 0; i < numConsoleKeys; i++ )
+ {
+ consoleKey_t *c = &consoleKeys[ i ];
+
+ switch( c->type )
+ {
+ case consoleKey_s::QUAKE_KEY:
+ if( key && c->u.key == key )
+ return true;
+ break;
+
+ case consoleKey_s::CHARACTER:
+ if( c->u.character == character )
+ return true;
+ break;
+ }
+ }
+
+ return false;
+}
+
+/*
+===============
+IN_TranslateSDLToQ3Key
+===============
+*/
+static keyNum_t IN_TranslateSDLToQ3Key( SDL_Keysym *keysym, bool down )
+{
+ keyNum_t key = (keyNum_t)0;
+
+ if( keysym->scancode >= SDL_SCANCODE_1 && keysym->scancode <= SDL_SCANCODE_0 )
+ {
+ // Always map the number keys as such even if they actually map
+ // to other characters (eg, "1" is "&" on an AZERTY keyboard).
+ // This is required for SDL before 2.0.6, except on Windows
+ // which already had this behavior.
+ if( keysym->scancode == SDL_SCANCODE_0 )
+ key = static_cast<keyNum_t>('0');
+ else
+ key = static_cast<keyNum_t>('1' + keysym->scancode - SDL_SCANCODE_1);
+ }
+ else if( keysym->sym >= SDLK_SPACE && keysym->sym < SDLK_DELETE )
+ {
+ // These happen to match the ASCII chars
+ key = (keyNum_t)keysym->sym;
+ }
+ else
+ {
+ switch( keysym->sym )
+ {
+ case SDLK_PAGEUP: key = K_PGUP; break;
+ case SDLK_KP_9: key = K_KP_PGUP; break;
+ case SDLK_PAGEDOWN: key = K_PGDN; break;
+ case SDLK_KP_3: key = K_KP_PGDN; break;
+ case SDLK_KP_7: key = K_KP_HOME; break;
+ case SDLK_HOME: key = K_HOME; break;
+ case SDLK_KP_1: key = K_KP_END; break;
+ case SDLK_END: key = K_END; break;
+ case SDLK_KP_4: key = K_KP_LEFTARROW; break;
+ case SDLK_LEFT: key = K_LEFTARROW; break;
+ case SDLK_KP_6: key = K_KP_RIGHTARROW; break;
+ case SDLK_RIGHT: key = K_RIGHTARROW; break;
+ case SDLK_KP_2: key = K_KP_DOWNARROW; break;
+ case SDLK_DOWN: key = K_DOWNARROW; break;
+ case SDLK_KP_8: key = K_KP_UPARROW; break;
+ case SDLK_UP: key = K_UPARROW; break;
+ case SDLK_ESCAPE: key = K_ESCAPE; break;
+ case SDLK_KP_ENTER: key = K_KP_ENTER; break;
+ case SDLK_RETURN: key = K_ENTER; break;
+ case SDLK_TAB: key = K_TAB; break;
+ case SDLK_F1: key = K_F1; break;
+ case SDLK_F2: key = K_F2; break;
+ case SDLK_F3: key = K_F3; break;
+ case SDLK_F4: key = K_F4; break;
+ case SDLK_F5: key = K_F5; break;
+ case SDLK_F6: key = K_F6; break;
+ case SDLK_F7: key = K_F7; break;
+ case SDLK_F8: key = K_F8; break;
+ case SDLK_F9: key = K_F9; break;
+ case SDLK_F10: key = K_F10; break;
+ case SDLK_F11: key = K_F11; break;
+ case SDLK_F12: key = K_F12; break;
+ case SDLK_F13: key = K_F13; break;
+ case SDLK_F14: key = K_F14; break;
+ case SDLK_F15: key = K_F15; break;
+
+ case SDLK_BACKSPACE: key = K_BACKSPACE; break;
+ case SDLK_KP_PERIOD: key = K_KP_DEL; break;
+ case SDLK_DELETE: key = K_DEL; break;
+ case SDLK_PAUSE: key = K_PAUSE; break;
+
+ case SDLK_LSHIFT:
+ case SDLK_RSHIFT: key = K_SHIFT; break;
+
+ case SDLK_LCTRL:
+ case SDLK_RCTRL: key = K_CTRL; break;
+
+#ifdef __APPLE__
+ case SDLK_RGUI:
+ case SDLK_LGUI: key = K_COMMAND; break;
+#else
+ case SDLK_RGUI:
+ case SDLK_LGUI: key = K_SUPER; break;
+#endif
+
+ case SDLK_RALT:
+ case SDLK_LALT: key = K_ALT; break;
+
+ case SDLK_KP_5: key = K_KP_5; break;
+ case SDLK_INSERT: key = K_INS; break;
+ case SDLK_KP_0: key = K_KP_INS; break;
+ case SDLK_KP_MULTIPLY: key = K_KP_STAR; break;
+ case SDLK_KP_PLUS: key = K_KP_PLUS; break;
+ case SDLK_KP_MINUS: key = K_KP_MINUS; break;
+ case SDLK_KP_DIVIDE: key = K_KP_SLASH; break;
+
+ case SDLK_MODE: key = K_MODE; break;
+ case SDLK_HELP: key = K_HELP; break;
+ case SDLK_PRINTSCREEN: key = K_PRINT; break;
+ case SDLK_SYSREQ: key = K_SYSREQ; break;
+ case SDLK_MENU: key = K_MENU; break;
+ case SDLK_APPLICATION: key = K_MENU; break;
+ case SDLK_POWER: key = K_POWER; break;
+ case SDLK_UNDO: key = K_UNDO; break;
+ case SDLK_SCROLLLOCK: key = K_SCROLLOCK; break;
+ case SDLK_NUMLOCKCLEAR: key = K_KP_NUMLOCK; break;
+ case SDLK_CAPSLOCK: key = K_CAPSLOCK; break;
+
+ default:
+ if( !( keysym->sym & SDLK_SCANCODE_MASK ) && keysym->scancode <= 95 )
+ {
+ // Map Unicode characters to 95 world keys using the key's scan code.
+ // FIXME: There aren't enough world keys to cover all the scancodes.
+ // Maybe create a map of scancode to quake key at start up and on
+ // key map change; allocate world key numbers as needed similar
+ // to SDL 1.2.
+ key = static_cast<keyNum_t>(K_WORLD_0 + (int)keysym->scancode);
+ }
+ break;
+ }
+ }
+
+ if( in_keyboardDebug->integer )
+ IN_PrintKey( keysym, key, down );
+
+ if( IN_IsConsoleKey( key, 0 ) )
+ {
+ // Console keys can't be bound or generate characters
+ key = K_CONSOLE;
+ }
+
+ return key;
+}
+
+/*
+===============
+IN_GobbleMotionEvents
+===============
+*/
+static void IN_GobbleMotionEvents( void )
+{
+ SDL_Event dummy[ 1 ];
+ int val = 0;
+
+ // Gobble any mouse motion events
+ SDL_PumpEvents( );
+ while( ( val = SDL_PeepEvents( dummy, 1, SDL_GETEVENT,
+ SDL_MOUSEMOTION, SDL_MOUSEMOTION ) ) > 0 ) { }
+
+ if ( val < 0 )
+ Com_Printf( "IN_GobbleMotionEvents failed: %s\n", SDL_GetError( ) );
+}
+
+/*
+===============
+IN_GetUIMousePosition
+===============
+*/
+static void IN_GetUIMousePosition( int *x, int *y )
+{
+ if( cls.ui )
+ {
+ int pos = VM_Call( cls.ui, UI_MOUSE_POSITION );
+ *x = pos & 0xFFFF;
+ *y = ( pos >> 16 ) & 0xFFFF;
+
+ *x = cls.glconfig.vidWidth * *x / 640;
+ *y = cls.glconfig.vidHeight * *y / 480;
+ }
+ else
+ {
+ *x = cls.glconfig.vidWidth / 2;
+ *y = cls.glconfig.vidHeight / 2;
+ }
+}
+
+/*
+===============
+IN_SetUIMousePosition
+===============
+*/
+static void IN_SetUIMousePosition( int x, int y )
+{
+ if( cls.ui )
+ {
+ x = x * 640 / cls.glconfig.vidWidth;
+ y = y * 480 / cls.glconfig.vidHeight;
+ VM_Call( cls.ui, UI_SET_MOUSE_POSITION, x, y );
+ }
+}
+
+/*
+===============
+IN_ActivateMouse
+===============
+*/
+static void IN_ActivateMouse( void )
+{
+ if (!mouseAvailable || !SDL_WasInit( SDL_INIT_VIDEO ) )
+ return;
+
+ if( !mouseActive )
+ {
+ SDL_SetRelativeMouseMode( SDL_TRUE );
+ SDL_SetWindowGrab( SDL_window, SDL_TRUE );
+
+ IN_GobbleMotionEvents( );
+ }
+
+ // in_nograb makes no sense in fullscreen mode
+ if( !cls.glconfig.isFullscreen )
+ {
+ if( in_nograb->modified || !mouseActive )
+ {
+ if( in_nograb->integer )
+ {
+ SDL_SetRelativeMouseMode( SDL_FALSE );
+ SDL_SetWindowGrab( SDL_window, SDL_FALSE );
+ }
+ else
+ {
+ SDL_SetRelativeMouseMode( SDL_TRUE );
+ SDL_SetWindowGrab( SDL_window, SDL_TRUE );
+ }
+ in_nograb->modified = qfalse;
+ }
+ }
+
+ mouseActive = true;
+}
+
+/*
+===============
+IN_DeactivateMouse
+===============
+*/
+static void IN_DeactivateMouse( void )
+{
+ if( !SDL_WasInit( SDL_INIT_VIDEO ) )
+ return;
+
+ // Always show the cursor when the mouse is disabled,
+ // but not when fullscreen
+ if( !cls.glconfig.isFullscreen )
+ {
+ if( ( Key_GetCatcher( ) == KEYCATCH_UI ) &&
+ SDL_GetWindowFlags( SDL_window ) & SDL_WINDOW_MOUSE_FOCUS )
+ SDL_ShowCursor( 0 );
+ else
+ SDL_ShowCursor( 1 );
+ }
+
+ if( !mouseAvailable )
+ return;
+
+ if( mouseActive )
+ {
+ IN_GobbleMotionEvents( );
+
+ SDL_SetWindowGrab( SDL_window, SDL_FALSE );
+ SDL_SetRelativeMouseMode( SDL_FALSE );
+
+ // Don't warp the mouse unless the cursor is within the window
+ if( SDL_GetWindowFlags( SDL_window ) & SDL_WINDOW_MOUSE_FOCUS && cls.uiInterface != 2 )
+ {
+ int x, y;
+ IN_GetUIMousePosition( &x, &y );
+ SDL_WarpMouseInWindow( SDL_window, x, y );
+ }
+
+ mouseActive = false;
+ }
+}
+
+// We translate axes movement into keypresses
+static int joy_keys[16] = {
+ K_LEFTARROW, K_RIGHTARROW,
+ K_UPARROW, K_DOWNARROW,
+ K_JOY17, K_JOY18,
+ K_JOY19, K_JOY20,
+ K_JOY21, K_JOY22,
+ K_JOY23, K_JOY24,
+ K_JOY25, K_JOY26,
+ K_JOY27, K_JOY28
+};
+
+// translate hat events into keypresses
+// the 4 highest buttons are used for the first hat ...
+static int hat_keys[16] = {
+ K_JOY29, K_JOY30,
+ K_JOY31, K_JOY32,
+ K_JOY25, K_JOY26,
+ K_JOY27, K_JOY28,
+ K_JOY21, K_JOY22,
+ K_JOY23, K_JOY24,
+ K_JOY17, K_JOY18,
+ K_JOY19, K_JOY20
+};
+
+
+struct
+{
+ bool buttons[SDL_CONTROLLER_BUTTON_MAX + 1]; // +1 because old max was 16, current SDL_CONTROLLER_BUTTON_MAX is 15
+ unsigned int oldaxes;
+ int oldaaxes[MAX_JOYSTICK_AXIS];
+ unsigned int oldhats;
+} stick_state;
+
+
+/*
+===============
+IN_InitJoystick
+===============
+*/
+static void IN_InitJoystick( void )
+{
+ int i = 0;
+ int total = 0;
+ char buf[16384] = "";
+
+ if (gamepad)
+ SDL_GameControllerClose(gamepad);
+
+ if (stick != NULL)
+ SDL_JoystickClose(stick);
+
+ stick = NULL;
+ gamepad = NULL;
+ memset(&stick_state, '\0', sizeof (stick_state));
+
+ // SDL 2.0.4 requires SDL_INIT_JOYSTICK to be initialized separately from
+ // SDL_INIT_GAMECONTROLLER for SDL_JoystickOpen() to work correctly,
+ // despite https://wiki.libsdl.org/SDL_Init (retrieved 2016-08-16)
+ // indicating SDL_INIT_JOYSTICK should be initialized automatically.
+ if (!SDL_WasInit(SDL_INIT_JOYSTICK))
+ {
+ Com_DPrintf("Calling SDL_Init(SDL_INIT_JOYSTICK)...\n");
+ if (SDL_Init(SDL_INIT_JOYSTICK) != 0)
+ {
+ Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) failed: %s\n", SDL_GetError());
+ return;
+ }
+ Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) passed.\n");
+ }
+
+ if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER))
+ {
+ Com_DPrintf("Calling SDL_Init(SDL_INIT_GAMECONTROLLER)...\n");
+ if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0)
+ {
+ Com_DPrintf("SDL_Init(SDL_INIT_GAMECONTROLLER) failed: %s\n", SDL_GetError());
+ return;
+ }
+ Com_DPrintf("SDL_Init(SDL_INIT_GAMECONTROLLER) passed.\n");
+ }
+
+ total = SDL_NumJoysticks();
+ Com_DPrintf("%d possible joysticks\n", total);
+
+ // Print list and build cvar to allow ui to select joystick.
+ for (i = 0; i < total; i++)
+ {
+ Q_strcat(buf, sizeof(buf), SDL_JoystickNameForIndex(i));
+ Q_strcat(buf, sizeof(buf), "\n");
+ }
+
+ Cvar_Get( "in_availableJoysticks", buf, CVAR_ROM );
+
+ if( !in_joystick->integer ) {
+ Com_DPrintf( "Joystick is not active.\n" );
+ SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
+ return;
+ }
+
+ in_joystickNo = Cvar_Get( "in_joystickNo", "0", CVAR_ARCHIVE );
+ if( in_joystickNo->integer < 0 || in_joystickNo->integer >= total )
+ Cvar_Set( "in_joystickNo", "0" );
+
+ in_joystickUseAnalog = Cvar_Get( "in_joystickUseAnalog", "0", CVAR_ARCHIVE );
+
+ stick = SDL_JoystickOpen( in_joystickNo->integer );
+
+ if (stick == NULL) {
+ Com_DPrintf( "No joystick opened: %s\n", SDL_GetError() );
+ return;
+ }
+
+ if (SDL_IsGameController(in_joystickNo->integer))
+ gamepad = SDL_GameControllerOpen(in_joystickNo->integer);
+
+ Com_DPrintf( "Joystick %d opened\n", in_joystickNo->integer );
+ Com_DPrintf( "Name: %s\n", SDL_JoystickNameForIndex(in_joystickNo->integer) );
+ Com_DPrintf( "Axes: %d\n", SDL_JoystickNumAxes(stick) );
+ Com_DPrintf( "Hats: %d\n", SDL_JoystickNumHats(stick) );
+ Com_DPrintf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) );
+ Com_DPrintf( "Balls: %d\n", SDL_JoystickNumBalls(stick) );
+ Com_DPrintf( "Use Analog: %s\n", in_joystickUseAnalog->integer ? "Yes" : "No" );
+ Com_DPrintf( "Is gamepad: %s\n", gamepad ? "Yes" : "No" );
+
+ SDL_JoystickEventState(SDL_QUERY);
+ SDL_GameControllerEventState(SDL_QUERY);
+}
+
+/*
+===============
+IN_ShutdownJoystick
+===============
+*/
+static void IN_ShutdownJoystick( void )
+{
+ if ( !SDL_WasInit( SDL_INIT_GAMECONTROLLER ) )
+ return;
+
+ if ( !SDL_WasInit( SDL_INIT_JOYSTICK ) )
+ return;
+
+ if (gamepad)
+ {
+ SDL_GameControllerClose(gamepad);
+ gamepad = NULL;
+ }
+
+ if (stick)
+ {
+ SDL_JoystickClose(stick);
+ stick = NULL;
+ }
+
+ SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
+ SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+}
+
+
+static bool KeyToAxisAndSign(int keynum, int *outAxis, int *outSign)
+{
+ if (!keynum)
+ return false;
+
+ const char* bind = Key_GetBinding(keynum);
+
+ if (!bind || *bind != '+')
+ return false;
+
+ *outSign = 0;
+
+ if (Q_stricmp(bind, "+forward") == 0)
+ {
+ *outAxis = j_forward_axis->integer;
+ *outSign = j_forward->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+back") == 0)
+ {
+ *outAxis = j_forward_axis->integer;
+ *outSign = j_forward->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+moveleft") == 0)
+ {
+ *outAxis = j_side_axis->integer;
+ *outSign = j_side->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+moveright") == 0)
+ {
+ *outAxis = j_side_axis->integer;
+ *outSign = j_side->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+lookup") == 0)
+ {
+ *outAxis = j_pitch_axis->integer;
+ *outSign = j_pitch->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+lookdown") == 0)
+ {
+ *outAxis = j_pitch_axis->integer;
+ *outSign = j_pitch->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+left") == 0)
+ {
+ *outAxis = j_yaw_axis->integer;
+ *outSign = j_yaw->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+right") == 0)
+ {
+ *outAxis = j_yaw_axis->integer;
+ *outSign = j_yaw->value > 0.0f ? -1 : 1;
+ }
+ else if (Q_stricmp(bind, "+moveup") == 0)
+ {
+ *outAxis = j_up_axis->integer;
+ *outSign = j_up->value > 0.0f ? 1 : -1;
+ }
+ else if (Q_stricmp(bind, "+movedown") == 0)
+ {
+ *outAxis = j_up_axis->integer;
+ *outSign = j_up->value > 0.0f ? -1 : 1;
+ }
+
+ return *outSign != 0;
+}
+
+/*
+===============
+IN_GamepadMove
+===============
+*/
+static void IN_GamepadMove( void )
+{
+ int i;
+ int translatedAxes[MAX_JOYSTICK_AXIS];
+ bool translatedAxesSet[MAX_JOYSTICK_AXIS];
+
+ SDL_GameControllerUpdate();
+
+ // check buttons
+ for (i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++)
+ {
+ bool pressed = SDL_GameControllerGetButton(gamepad, (SDL_GameControllerButton)(SDL_CONTROLLER_BUTTON_A + i));
+ if (pressed != stick_state.buttons[i])
+ {
+ Com_QueueEvent(in_eventTime, SE_KEY, K_PAD0_A + i, pressed, 0, NULL);
+ stick_state.buttons[i] = pressed;
+ }
+ }
+
+ // must defer translated axes until all real axes are processed
+ // must be done this way to prevent a later mapped axis from zeroing out a previous one
+ if (in_joystickUseAnalog->integer)
+ {
+ for (i = 0; i < MAX_JOYSTICK_AXIS; i++)
+ {
+ translatedAxes[i] = 0;
+ translatedAxesSet[i] = false;
+ }
+ }
+
+ // check axes
+ for (i = 0; i < SDL_CONTROLLER_AXIS_MAX; i++)
+ {
+ int axis = SDL_GameControllerGetAxis(gamepad, (SDL_GameControllerAxis)(SDL_CONTROLLER_AXIS_LEFTX + i));
+ int oldAxis = stick_state.oldaaxes[i];
+
+ // Smoothly ramp from dead zone to maximum value
+ float f = ((float)abs(axis) / 32767.0f - in_joystickThreshold->value) / (1.0f - in_joystickThreshold->value);
+
+ if (f < 0.0f)
+ f = 0.0f;
+
+ axis = (int)(32767 * ((axis < 0) ? -f : f));
+
+ if (axis != oldAxis)
+ {
+ const int negMap[SDL_CONTROLLER_AXIS_MAX] = { K_PAD0_LEFTSTICK_LEFT, K_PAD0_LEFTSTICK_UP, K_PAD0_RIGHTSTICK_LEFT, K_PAD0_RIGHTSTICK_UP, 0, 0 };
+ const int posMap[SDL_CONTROLLER_AXIS_MAX] = { K_PAD0_LEFTSTICK_RIGHT, K_PAD0_LEFTSTICK_DOWN, K_PAD0_RIGHTSTICK_RIGHT, K_PAD0_RIGHTSTICK_DOWN, K_PAD0_LEFTTRIGGER, K_PAD0_RIGHTTRIGGER };
+
+ bool posAnalog = false, negAnalog = false;
+ int negKey = negMap[i];
+ int posKey = posMap[i];
+
+ if (in_joystickUseAnalog->integer)
+ {
+ int posAxis = 0, posSign = 0, negAxis = 0, negSign = 0;
+
+ // get axes and axes signs for keys if available
+ posAnalog = KeyToAxisAndSign(posKey, &posAxis, &posSign);
+ negAnalog = KeyToAxisAndSign(negKey, &negAxis, &negSign);
+
+ // positive to negative/neutral -> keyup if axis hasn't yet been set
+ if (posAnalog && !translatedAxesSet[posAxis] && oldAxis > 0 && axis <= 0)
+ {
+ translatedAxes[posAxis] = 0;
+ translatedAxesSet[posAxis] = true;
+ }
+
+ // negative to positive/neutral -> keyup if axis hasn't yet been set
+ if (negAnalog && !translatedAxesSet[negAxis] && oldAxis < 0 && axis >= 0)
+ {
+ translatedAxes[negAxis] = 0;
+ translatedAxesSet[negAxis] = true;
+ }
+
+ // negative/neutral to positive -> keydown
+ if (posAnalog && axis > 0)
+ {
+ translatedAxes[posAxis] = axis * posSign;
+ translatedAxesSet[posAxis] = true;
+ }
+
+ // positive/neutral to negative -> keydown
+ if (negAnalog && axis < 0)
+ {
+ translatedAxes[negAxis] = -axis * negSign;
+ translatedAxesSet[negAxis] = true;
+ }
+ }
+
+ // keyups first so they get overridden by keydowns later
+
+ // positive to negative/neutral -> keyup
+ if (!posAnalog && posKey && oldAxis > 0 && axis <= 0)
+ Com_QueueEvent(in_eventTime, SE_KEY, posKey, false, 0, NULL);
+
+ // negative to positive/neutral -> keyup
+ if (!negAnalog && negKey && oldAxis < 0 && axis >= 0)
+ Com_QueueEvent(in_eventTime, SE_KEY, negKey, false, 0, NULL);
+
+ // negative/neutral to positive -> keydown
+ if (!posAnalog && posKey && oldAxis <= 0 && axis > 0)
+ Com_QueueEvent(in_eventTime, SE_KEY, posKey, true, 0, NULL);
+
+ // positive/neutral to negative -> keydown
+ if (!negAnalog && negKey && oldAxis >= 0 && axis < 0)
+ Com_QueueEvent(in_eventTime, SE_KEY, negKey, true, 0, NULL);
+
+ stick_state.oldaaxes[i] = axis;
+ }
+ }
+
+ // set translated axes
+ if (in_joystickUseAnalog->integer)
+ {
+ for (i = 0; i < MAX_JOYSTICK_AXIS; i++)
+ {
+ if (translatedAxesSet[i])
+ Com_QueueEvent(in_eventTime, SE_JOYSTICK_AXIS, i, translatedAxes[i], 0, NULL);
+ }
+ }
+}
+
+
+/*
+===============
+IN_JoyMove
+===============
+*/
+static void IN_JoyMove( void )
+{
+ unsigned int axes = 0;
+ unsigned int hats = 0;
+ int total = 0;
+ int i = 0;
+
+ if (gamepad)
+ {
+ IN_GamepadMove();
+ return;
+ }
+
+ if (!stick)
+ return;
+
+ SDL_JoystickUpdate();
+
+ // update the ball state.
+ total = SDL_JoystickNumBalls(stick);
+ if (total > 0)
+ {
+ int balldx = 0;
+ int balldy = 0;
+ for (i = 0; i < total; i++)
+ {
+ int dx = 0;
+ int dy = 0;
+ SDL_JoystickGetBall(stick, i, &dx, &dy);
+ balldx += dx;
+ balldy += dy;
+ }
+ if (balldx || balldy)
+ {
+ // !!! FIXME: is this good for stick balls, or just mice?
+ // Scale like the mouse input...
+ if (abs(balldx) > 1)
+ balldx *= 2;
+ if (abs(balldy) > 1)
+ balldy *= 2;
+ Com_QueueEvent(in_eventTime, SE_MOUSE, balldx, balldy, 0, NULL);
+ }
+ }
+
+ // now query the stick buttons...
+ total = SDL_JoystickNumButtons(stick);
+ if (total > 0)
+ {
+ if (total > ARRAY_LEN(stick_state.buttons))
+ total = ARRAY_LEN(stick_state.buttons);
+ for (i = 0; i < total; i++)
+ {
+ bool pressed = (SDL_JoystickGetButton(stick, i) != 0);
+ if (pressed != stick_state.buttons[i])
+ {
+ Com_QueueEvent(in_eventTime, SE_KEY, K_JOY1 + i, pressed, 0, NULL );
+ stick_state.buttons[i] = pressed;
+ }
+ }
+ }
+
+ // look at the hats...
+ total = SDL_JoystickNumHats(stick);
+ if (total > 0)
+ {
+ if (total > 4) total = 4;
+ for (i = 0; i < total; i++)
+ {
+ ((Uint8 *)&hats)[i] = SDL_JoystickGetHat(stick, i);
+ }
+ }
+
+ // update hat state
+ if (hats != stick_state.oldhats)
+ {
+ for( i = 0; i < 4; i++ ) {
+ if( ((Uint8 *)&hats)[i] != ((Uint8 *)&stick_state.oldhats)[i] ) {
+ // release event
+ switch( ((Uint8 *)&stick_state.oldhats)[i] ) {
+ case SDL_HAT_UP:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 0], false, 0, NULL );
+ break;
+ case SDL_HAT_RIGHT:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 1], false, 0, NULL );
+ break;
+ case SDL_HAT_DOWN:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 2], false, 0, NULL );
+ break;
+ case SDL_HAT_LEFT:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 3], false, 0, NULL );
+ break;
+ case SDL_HAT_RIGHTUP:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 0], false, 0, NULL );
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 1], false, 0, NULL );
+ break;
+ case SDL_HAT_RIGHTDOWN:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 2], false, 0, NULL );
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 1], false, 0, NULL );
+ break;
+ case SDL_HAT_LEFTUP:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 0], false, 0, NULL );
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 3], false, 0, NULL );
+ break;
+ case SDL_HAT_LEFTDOWN:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 2], false, 0, NULL );
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 3], false, 0, NULL );
+ break;
+ default:
+ break;
+ }
+ // press event
+ switch( ((Uint8 *)&hats)[i] ) {
+ case SDL_HAT_UP:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 0], true, 0, NULL );
+ break;
+ case SDL_HAT_RIGHT:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 1], true, 0, NULL );
+ break;
+ case SDL_HAT_DOWN:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 2], true, 0, NULL );
+ break;
+ case SDL_HAT_LEFT:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 3], true, 0, NULL );
+ break;
+ case SDL_HAT_RIGHTUP:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 0], true, 0, NULL );
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 1], true, 0, NULL );
+ break;
+ case SDL_HAT_RIGHTDOWN:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 2], true, 0, NULL );
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 1], true, 0, NULL );
+ break;
+ case SDL_HAT_LEFTUP:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 0], true, 0, NULL );
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 3], true, 0, NULL );
+ break;
+ case SDL_HAT_LEFTDOWN:
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 2], true, 0, NULL );
+ Com_QueueEvent(in_eventTime, SE_KEY, hat_keys[4*i + 3], true, 0, NULL );
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // save hat state
+ stick_state.oldhats = hats;
+
+ // finally, look at the axes...
+ total = SDL_JoystickNumAxes(stick);
+ if (total > 0)
+ {
+ if (in_joystickUseAnalog->integer)
+ {
+ if (total > MAX_JOYSTICK_AXIS) total = MAX_JOYSTICK_AXIS;
+ for (i = 0; i < total; i++)
+ {
+ Sint16 axis = SDL_JoystickGetAxis(stick, i);
+ float f = ( (float) abs(axis) ) / 32767.0f;
+
+ if( f < in_joystickThreshold->value ) axis = 0;
+
+ if ( axis != stick_state.oldaaxes[i] )
+ {
+ Com_QueueEvent(in_eventTime, SE_JOYSTICK_AXIS, i, axis, 0, NULL );
+ stick_state.oldaaxes[i] = axis;
+ }
+ }
+ }
+ else
+ {
+ if (total > 16) total = 16;
+ for (i = 0; i < total; i++)
+ {
+ Sint16 axis = SDL_JoystickGetAxis(stick, i);
+ float f = ( (float) axis ) / 32767.0f;
+ if( f < -in_joystickThreshold->value ) {
+ axes |= ( 1 << ( i * 2 ) );
+ } else if( f > in_joystickThreshold->value ) {
+ axes |= ( 1 << ( ( i * 2 ) + 1 ) );
+ }
+ }
+ }
+ }
+
+ /* Time to update axes state based on old vs. new. */
+ if (axes != stick_state.oldaxes)
+ {
+ for( i = 0; i < 16; i++ ) {
+ if( ( axes & ( 1 << i ) ) && !( stick_state.oldaxes & ( 1 << i ) ) ) {
+ Com_QueueEvent(in_eventTime, SE_KEY, joy_keys[i], true, 0, NULL );
+ }
+
+ if( !( axes & ( 1 << i ) ) && ( stick_state.oldaxes & ( 1 << i ) ) ) {
+ Com_QueueEvent(in_eventTime, SE_KEY, joy_keys[i], false, 0, NULL );
+ }
+ }
+ }
+
+ /* Save for future generations. */
+ stick_state.oldaxes = axes;
+}
+
+/*
+===============
+IN_ProcessEvents
+===============
+*/
+static void IN_ProcessEvents( void )
+{
+ SDL_Event e;
+ keyNum_t key = (keyNum_t)0;
+ static keyNum_t lastKeyDown = (keyNum_t)0;
+
+ if( !SDL_WasInit( SDL_INIT_VIDEO ) )
+ return;
+
+ while( SDL_PollEvent( &e ) )
+ {
+ switch( e.type )
+ {
+ case SDL_KEYDOWN:
+ if ( e.key.repeat && Key_GetCatcher( ) == 0 )
+ break;
+
+ if( ( key = IN_TranslateSDLToQ3Key( &e.key.keysym, true ) ) )
+ Com_QueueEvent(in_eventTime, SE_KEY, key, true, 0, NULL );
+
+ if( key == K_BACKSPACE )
+ Com_QueueEvent(in_eventTime, SE_CHAR, CTRL('h'), 0, 0, NULL );
+ else if( keys[K_CTRL].down && key >= 'a' && key <= 'z' )
+ Com_QueueEvent(in_eventTime, SE_CHAR, CTRL(key), 0, 0, NULL );
+
+ lastKeyDown = key;
+ break;
+
+ case SDL_KEYUP:
+ if( ( key = IN_TranslateSDLToQ3Key( &e.key.keysym, false ) ) )
+ Com_QueueEvent(in_eventTime, SE_KEY, key, false, 0, NULL );
+
+ lastKeyDown = (keyNum_t)0;
+ break;
+
+ case SDL_TEXTINPUT:
+ if( lastKeyDown != K_CONSOLE )
+ {
+ char *c = e.text.text;
+
+ // Quick and dirty UTF-8 to UTF-32 conversion
+ while( *c )
+ {
+ int utf32 = 0;
+
+ if( ( *c & 0x80 ) == 0 )
+ utf32 = *c++;
+ else if( ( *c & 0xE0 ) == 0xC0 ) // 110x xxxx
+ {
+ utf32 |= ( *c++ & 0x1F ) << 6;
+ utf32 |= ( *c++ & 0x3F );
+ }
+ else if( ( *c & 0xF0 ) == 0xE0 ) // 1110 xxxx
+ {
+ utf32 |= ( *c++ & 0x0F ) << 12;
+ utf32 |= ( *c++ & 0x3F ) << 6;
+ utf32 |= ( *c++ & 0x3F );
+ }
+ else if( ( *c & 0xF8 ) == 0xF0 ) // 1111 0xxx
+ {
+ utf32 |= ( *c++ & 0x07 ) << 18;
+ utf32 |= ( *c++ & 0x3F ) << 12;
+ utf32 |= ( *c++ & 0x3F ) << 6;
+ utf32 |= ( *c++ & 0x3F );
+ }
+ else
+ {
+ Com_DPrintf( "Unrecognised UTF-8 lead byte: 0x%x\n", (unsigned int)*c );
+ c++;
+ }
+
+ if( utf32 != 0 )
+ {
+ if( IN_IsConsoleKey( (keyNum_t)0, utf32 ) )
+ {
+ Com_QueueEvent(in_eventTime, SE_KEY, K_CONSOLE, true, 0, NULL );
+ Com_QueueEvent(in_eventTime, SE_KEY, K_CONSOLE, false, 0, NULL );
+ }
+ else
+ Com_QueueEvent(in_eventTime, SE_CHAR, utf32, 0, 0, NULL );
+ }
+ }
+ }
+ break;
+
+ case SDL_MOUSEMOTION:
+ if( mouseActive )
+ {
+ if( !e.motion.xrel && !e.motion.yrel )
+ break;
+ Com_QueueEvent(in_eventTime, SE_MOUSE, e.motion.xrel, e.motion.yrel, 0, NULL );
+ }
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEBUTTONUP:
+ {
+ int b;
+ switch( e.button.button )
+ {
+ case 1: b = K_MOUSE1; break;
+ case 2: b = K_MOUSE3; break;
+ case 3: b = K_MOUSE2; break;
+ case 4: b = K_MOUSE4; break;
+ case 5: b = K_MOUSE5; break;
+ default: b = K_AUX1 + ( e.button.button - 8 ) % 16; break;
+ }
+ Com_QueueEvent(in_eventTime, SE_KEY, b,
+ ( e.type == SDL_MOUSEBUTTONDOWN ? true : false ), 0, NULL );
+ }
+ break;
+
+ case SDL_MOUSEWHEEL:
+ if( e.wheel.y > 0 )
+ {
+ Com_QueueEvent(in_eventTime, SE_KEY, K_MWHEELUP, true, 0, NULL );
+ Com_QueueEvent(in_eventTime, SE_KEY, K_MWHEELUP, false, 0, NULL );
+ }
+ else if( e.wheel.y < 0 )
+ {
+ Com_QueueEvent(in_eventTime, SE_KEY, K_MWHEELDOWN, true, 0, NULL );
+ Com_QueueEvent(in_eventTime, SE_KEY, K_MWHEELDOWN, false, 0, NULL );
+ }
+ break;
+
+ case SDL_CONTROLLERDEVICEADDED:
+ case SDL_CONTROLLERDEVICEREMOVED:
+ if (in_joystick->integer)
+ IN_InitJoystick();
+ break;
+
+ case SDL_QUIT:
+ Cbuf_ExecuteText(EXEC_NOW, "quit \"Closed window\"\n");
+ break;
+
+ case SDL_WINDOWEVENT:
+ switch( e.window.event )
+ {
+ case SDL_WINDOWEVENT_RESIZED:
+ {
+ int width, height;
+
+ width = e.window.data1;
+ height = e.window.data2;
+
+ // ignore this event on fullscreen
+ if ( cls.glconfig.isFullscreen )
+ break;
+
+ // check if size actually changed
+ if( cls.glconfig.vidWidth == width && cls.glconfig.vidHeight == height )
+ {
+ break;
+ }
+
+ Cvar_SetValue( "r_width", width );
+ Cvar_SetValue( "r_height", height );
+
+ // Wait until user stops dragging for 1 second, so
+ // we aren't constantly recreating the GL context while
+ // he tries to drag...
+ vidRestartTime = Sys_Milliseconds( ) + 1000;
+ }
+ break;
+
+ case SDL_WINDOWEVENT_MINIMIZED: Cvar_SetValue( "com_minimized", 1 ); break;
+ case SDL_WINDOWEVENT_RESTORED:
+ case SDL_WINDOWEVENT_MAXIMIZED: Cvar_SetValue( "com_minimized", 0 ); break;
+ case SDL_WINDOWEVENT_FOCUS_LOST: Cvar_SetValue( "com_unfocused", 1 ); break;
+ case SDL_WINDOWEVENT_FOCUS_GAINED: Cvar_SetValue( "com_unfocused", 0 ); break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/*
+===============
+IN_Frame
+===============
+*/
+void IN_Frame( void )
+{
+ bool loading;
+ bool cursorShowing;
+ int x, y;
+
+ IN_JoyMove( );
+
+ // If not DISCONNECTED (main menu) or ACTIVE (in game), we're loading
+ loading = ( clc.state != CA_DISCONNECTED && clc.state != CA_ACTIVE );
+ cursorShowing = Key_GetCatcher( ) & KEYCATCH_UI;
+
+ if( !cls.glconfig.isFullscreen && ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) )
+ {
+ // Console is down in windowed mode
+ IN_DeactivateMouse( );
+ }
+ else if( !cls.glconfig.isFullscreen && loading )
+ {
+ // Loading in windowed mode
+ IN_DeactivateMouse( );
+ }
+ else if( !cls.glconfig.isFullscreen && cursorShowing && cls.uiInterface != 2 )
+ {
+ // Use WM cursor when not fullscreen
+ IN_DeactivateMouse( );
+ }
+ else if( !( SDL_GetWindowFlags( SDL_window ) & SDL_WINDOW_INPUT_FOCUS ) )
+ {
+ // Window not got focus
+ IN_DeactivateMouse( );
+ }
+ else
+ IN_ActivateMouse( );
+
+ if( !mouseActive && cls.uiInterface != 2 )
+ {
+ SDL_GetMouseState( &x, &y );
+ IN_SetUIMousePosition( x, y );
+ }
+
+ IN_ProcessEvents( );
+
+ // Set event time for next frame to earliest possible time an event could happen
+ in_eventTime = Sys_Milliseconds();
+
+ // In case we had to delay actual restart of video system
+ if( ( vidRestartTime != 0 ) && ( vidRestartTime < Sys_Milliseconds( ) ) )
+ {
+ vidRestartTime = 0;
+ Cbuf_AddText( "vid_restart\n" );
+ }
+}
+
+/*
+===============
+IN_Init
+===============
+*/
+void IN_Init( void *windowData )
+{
+ int appState;
+
+ if( !SDL_WasInit( SDL_INIT_VIDEO ) )
+ {
+ Com_Error( ERR_FATAL, "IN_Init called before SDL_Init( SDL_INIT_VIDEO )" );
+ return;
+ }
+
+ SDL_window = (SDL_Window *)windowData;
+
+ Com_DPrintf( "\n------- Input Initialization -------\n" );
+
+ in_keyboardDebug = Cvar_Get( "in_keyboardDebug", "0", CVAR_ARCHIVE );
+
+ // mouse variables
+ in_mouse = Cvar_Get( "in_mouse", "1", CVAR_ARCHIVE );
+ in_nograb = Cvar_Get( "in_nograb", "0", CVAR_ARCHIVE );
+
+ in_joystick = Cvar_Get( "in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH );
+ in_joystickThreshold = Cvar_Get( "joy_threshold", "0.15", CVAR_ARCHIVE );
+
+ SDL_StartTextInput( );
+
+ mouseAvailable = ( in_mouse->value != 0 );
+ IN_DeactivateMouse( );
+
+ appState = SDL_GetWindowFlags( SDL_window );
+ Cvar_SetValue( "com_unfocused", !( appState & SDL_WINDOW_INPUT_FOCUS ) );
+ Cvar_SetValue( "com_minimized", appState & SDL_WINDOW_MINIMIZED );
+
+ IN_InitJoystick( );
+ Com_DPrintf( "------------------------------------\n" );
+}
+
+/*
+===============
+IN_Shutdown
+===============
+*/
+void IN_Shutdown( void )
+{
+ SDL_StopTextInput( );
+
+ IN_DeactivateMouse( );
+ mouseAvailable = false;
+
+ IN_ShutdownJoystick( );
+
+ SDL_window = NULL;
+}
+
+/*
+===============
+IN_Restart
+===============
+*/
+void IN_Restart( void )
+{
+ IN_ShutdownJoystick( );
+ IN_Init( SDL_window );
+}
diff --git a/src/sdl/sdl_snd.cpp b/src/sdl/sdl_snd.cpp
new file mode 100644
index 0000000..4689cc5
--- /dev/null
+++ b/src/sdl/sdl_snd.cpp
@@ -0,0 +1,298 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include <cstdlib>
+#include <cstdio>
+
+#ifdef USE_LOCAL_HEADERS
+# include "SDL.h"
+#else
+# include <SDL.h>
+#endif
+
+#include "client/snd_local.h"
+#include "qcommon/cvar.h"
+#include "qcommon/q_shared.h"
+
+bool snd_inited = false;
+
+cvar_t *s_sdlBits;
+cvar_t *s_sdlSpeed;
+cvar_t *s_sdlChannels;
+cvar_t *s_sdlDevSamps;
+cvar_t *s_sdlMixSamps;
+
+/* The audio callback. All the magic happens here. */
+static int dmapos = 0;
+static int dmasize = 0;
+
+/*
+===============
+SNDDMA_AudioCallback
+===============
+*/
+static void SNDDMA_AudioCallback(void *userdata, Uint8 *stream, int len)
+{
+ int pos = (dmapos * (dma.samplebits/8));
+ if (pos >= dmasize)
+ dmapos = pos = 0;
+
+ if (!snd_inited) /* shouldn't happen, but just in case... */
+ {
+ memset(stream, '\0', len);
+ return;
+ }
+ else
+ {
+ int tobufend = dmasize - pos; /* bytes to buffer's end. */
+ int len1 = len;
+ int len2 = 0;
+
+ if (len1 > tobufend)
+ {
+ len1 = tobufend;
+ len2 = len - len1;
+ }
+ memcpy(stream, dma.buffer + pos, len1);
+ if (len2 <= 0)
+ dmapos += (len1 / (dma.samplebits/8));
+ else /* wraparound? */
+ {
+ memcpy(stream+len1, dma.buffer, len2);
+ dmapos = (len2 / (dma.samplebits/8));
+ }
+ }
+
+ if (dmapos >= dmasize)
+ dmapos = 0;
+}
+
+static struct
+{
+ Uint16 enumFormat;
+ const char* stringFormat;
+} formatToStringTable[ ] =
+{
+ { AUDIO_U8, "AUDIO_U8" },
+ { AUDIO_S8, "AUDIO_S8" },
+ { AUDIO_U16LSB, "AUDIO_U16LSB" },
+ { AUDIO_S16LSB, "AUDIO_S16LSB" },
+ { AUDIO_U16MSB, "AUDIO_U16MSB" },
+ { AUDIO_S16MSB, "AUDIO_S16MSB" }
+};
+
+static int formatToStringTableSize = ARRAY_LEN( formatToStringTable );
+
+/*
+===============
+SNDDMA_PrintAudiospec
+===============
+*/
+static void SNDDMA_PrintAudiospec(const char *str, const SDL_AudioSpec *spec)
+{
+ int i;
+ const char *fmt = NULL;
+
+ Com_Printf("%s:\n", str);
+
+ for( i = 0; i < formatToStringTableSize; i++ ) {
+ if( spec->format == formatToStringTable[ i ].enumFormat ) {
+ fmt = formatToStringTable[ i ].stringFormat;
+ }
+ }
+
+ if( fmt ) {
+ Com_Printf( " Format: %s\n", fmt );
+ } else {
+ Com_Printf( " Format: " S_COLOR_RED "UNKNOWN\n");
+ }
+
+ Com_Printf( " Freq: %d\n", (int) spec->freq );
+ Com_Printf( " Samples: %d\n", (int) spec->samples );
+ Com_Printf( " Channels: %d\n", (int) spec->channels );
+}
+
+/*
+===============
+SNDDMA_Init
+===============
+*/
+bool SNDDMA_Init(void)
+{
+ SDL_AudioSpec desired;
+ SDL_AudioSpec obtained;
+ int tmp;
+
+ if (snd_inited)
+ return true;
+
+ if (!s_sdlBits) {
+ s_sdlBits = Cvar_Get("s_sdlBits", "16", CVAR_ARCHIVE);
+ s_sdlSpeed = Cvar_Get("s_sdlSpeed", "0", CVAR_ARCHIVE);
+ s_sdlChannels = Cvar_Get("s_sdlChannels", "2", CVAR_ARCHIVE);
+ s_sdlDevSamps = Cvar_Get("s_sdlDevSamps", "0", CVAR_ARCHIVE);
+ s_sdlMixSamps = Cvar_Get("s_sdlMixSamps", "0", CVAR_ARCHIVE);
+ }
+
+ Com_Printf( "SDL_Init( SDL_INIT_AUDIO )... " );
+
+ if (!SDL_WasInit(SDL_INIT_AUDIO))
+ {
+ if (SDL_Init(SDL_INIT_AUDIO) != 0)
+ {
+ Com_Printf( "FAILED (%s)\n", SDL_GetError( ) );
+ return false;
+ }
+ }
+
+ Com_Printf( "OK\n" );
+
+ Com_Printf( "SDL audio driver is \"%s\".\n", SDL_GetCurrentAudioDriver( ) );
+
+ memset(&desired, '\0', sizeof (desired));
+ memset(&obtained, '\0', sizeof (obtained));
+
+ tmp = ((int) s_sdlBits->value);
+ if ((tmp != 16) && (tmp != 8))
+ tmp = 16;
+
+ desired.freq = (int) s_sdlSpeed->value;
+ if(!desired.freq) desired.freq = 22050;
+ desired.format = ((tmp == 16) ? AUDIO_S16SYS : AUDIO_U8);
+
+ // I dunno if this is the best idea, but I'll give it a try...
+ // should probably check a cvar for this...
+ if (s_sdlDevSamps->value)
+ desired.samples = s_sdlDevSamps->value;
+ else
+ {
+ // just pick a sane default.
+ if (desired.freq <= 11025)
+ desired.samples = 256;
+ else if (desired.freq <= 22050)
+ desired.samples = 512;
+ else if (desired.freq <= 44100)
+ desired.samples = 1024;
+ else
+ desired.samples = 2048; // (*shrug*)
+ }
+
+ desired.channels = (int) s_sdlChannels->value;
+ desired.callback = SNDDMA_AudioCallback;
+
+ if (SDL_OpenAudio(&desired, &obtained) == -1)
+ {
+ Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError());
+ SDL_QuitSubSystem(SDL_INIT_AUDIO);
+ return false;
+ }
+
+ SNDDMA_PrintAudiospec("SDL_AudioSpec", &obtained);
+
+ // dma.samples needs to be big, or id's mixer will just refuse to
+ // work at all; we need to keep it significantly bigger than the
+ // amount of SDL callback samples, and just copy a little each time
+ // the callback runs.
+ // 32768 is what the OSS driver filled in here on my system. I don't
+ // know if it's a good value overall, but at least we know it's
+ // reasonable...this is why I let the user override.
+ tmp = s_sdlMixSamps->value;
+ if (!tmp)
+ tmp = (obtained.samples * obtained.channels) * 10;
+
+ if (tmp & (tmp - 1)) // not a power of two? Seems to confuse something.
+ {
+ int val = 1;
+ while (val < tmp)
+ val <<= 1;
+
+ tmp = val;
+ }
+
+ dmapos = 0;
+ dma.samplebits = obtained.format & 0xFF; // first byte of format is bits.
+ dma.channels = obtained.channels;
+ dma.samples = tmp;
+ dma.submission_chunk = 1;
+ dma.speed = obtained.freq;
+ dmasize = (dma.samples * (dma.samplebits/8));
+ dma.buffer = (byte*)calloc(1, dmasize);
+
+ Com_Printf("Starting SDL audio callback...\n");
+ SDL_PauseAudio(0); // start callback.
+
+ Com_Printf("SDL audio initialized.\n");
+ snd_inited = true;
+ return true;
+}
+
+/*
+===============
+SNDDMA_GetDMAPos
+===============
+*/
+int SNDDMA_GetDMAPos(void)
+{
+ return dmapos;
+}
+
+/*
+===============
+SNDDMA_Shutdown
+===============
+*/
+void SNDDMA_Shutdown(void)
+{
+ Com_Printf("Closing SDL audio device...\n");
+ SDL_PauseAudio(1);
+ SDL_CloseAudio();
+ SDL_QuitSubSystem(SDL_INIT_AUDIO);
+ free(dma.buffer);
+ dma.buffer = NULL;
+ dmapos = dmasize = 0;
+ snd_inited = false;
+ Com_Printf("SDL audio device shut down.\n");
+}
+
+/*
+===============
+SNDDMA_Submit
+
+Send sound to device if buffer isn't really the dma buffer
+===============
+*/
+void SNDDMA_Submit(void)
+{
+ SDL_UnlockAudio();
+}
+
+/*
+===============
+SNDDMA_BeginPainting
+===============
+*/
+void SNDDMA_BeginPainting (void)
+{
+ SDL_LockAudio();
+}
diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt
new file mode 100644
index 0000000..98f3a23
--- /dev/null
+++ b/src/server/CMakeLists.txt
@@ -0,0 +1,114 @@
+
+#
+## .dMMMb dMMMMMP dMMMMb dMP dMP dMMMMMP dMMMMb
+## dMP" VP dMP dMP.dMP dMP dMP dMP dMP.dMP
+## VMMMb dMMMP dMMMMK" dMP dMP dMMMP dMMMMK"
+## dP .dMP dMP dMP"AMF YMvAP" dMP dMP"AMF
+## VMMMP" dMMMMMP dMP dMP VP" dMMMMMP dMP dMP
+#
+
+add_definitions(
+ -DDEDICATED
+ -DUSE_LOCAL_HEADERS
+ -DPRODUCT_VERSION="1.2.0 pre-release"
+ -DUSE_VOIP
+ -DNDEBUG
+ )
+
+set(EXTERNAL_DIR ${CMAKE_SOURCE_DIR}/external)
+set(PARENT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
+if(APPLE)
+set(APPLE_SOURCES ${PARENT_DIR}/sys/sys_osx.mm)
+endif(APPLE)
+
+add_executable(
+ tremded
+ #
+ server.h
+ #
+ sv_ccmds.cpp
+ sv_client.cpp
+ sv_game.cpp
+ sv_init.cpp
+ sv_main.cpp
+ sv_net_chan.cpp
+ sv_snapshot.cpp
+ sv_world.cpp
+ #
+ ${PARENT_DIR}/qcommon/cm_load.cpp
+ ${PARENT_DIR}/qcommon/cm_patch.cpp
+ ${PARENT_DIR}/qcommon/cm_polylib.cpp
+ ${PARENT_DIR}/qcommon/cm_test.cpp
+ ${PARENT_DIR}/qcommon/cm_trace.cpp
+ ${PARENT_DIR}/qcommon/cmd.cpp
+ ${PARENT_DIR}/qcommon/common.cpp
+ ${PARENT_DIR}/qcommon/crypto.cpp
+ ${PARENT_DIR}/qcommon/cvar.cpp
+ ${PARENT_DIR}/qcommon/files.cpp
+ ${PARENT_DIR}/qcommon/huffman.cpp
+ ${PARENT_DIR}/qcommon/huffman.h
+ ${PARENT_DIR}/qcommon/ioapi.cpp
+ ${PARENT_DIR}/qcommon/md4.cpp
+ ${PARENT_DIR}/qcommon/msg.h
+ ${PARENT_DIR}/qcommon/msg.cpp
+ ${PARENT_DIR}/qcommon/net.h
+ ${PARENT_DIR}/qcommon/net_chan.cpp
+ ${PARENT_DIR}/qcommon/net_ip.cpp
+ ${PARENT_DIR}/qcommon/parse.cpp
+ ${PARENT_DIR}/qcommon/q3_lauxlib.cpp
+ ${PARENT_DIR}/qcommon/q_math.c
+ ${PARENT_DIR}/qcommon/q_shared.c
+ ${PARENT_DIR}/qcommon/unzip.cpp
+ ${PARENT_DIR}/qcommon/vm.cpp
+ ${PARENT_DIR}/qcommon/vm_interpreted.cpp
+ ${PARENT_DIR}/qcommon/vm_x86.cpp
+ #
+ ${PARENT_DIR}/null/null_client.cpp
+ ${PARENT_DIR}/null/null_input.cpp
+ ${PARENT_DIR}/null/null_snddma.cpp
+ #
+ ${PARENT_DIR}/asm/snapvector.c
+ #
+ ${PARENT_DIR}/sys/con_log.cpp
+ ${PARENT_DIR}/sys/con_tty.cpp
+ ${PARENT_DIR}/sys/sys_main.cpp
+ ${PARENT_DIR}/sys/sys_unix.cpp
+ ${PARENT_DIR}/sys/sys_shared.h
+ ${APPLE_SOURCES}
+ #
+ ${EXTERNAL_DIR}/zlib/adler32.c
+ ${EXTERNAL_DIR}/zlib/crc32.c
+ ${EXTERNAL_DIR}/zlib/inffast.c
+ ${EXTERNAL_DIR}/zlib/inflate.c
+ ${EXTERNAL_DIR}/zlib/inftrees.c
+ ${EXTERNAL_DIR}/zlib/zutil.c
+ )
+
+if(APPLE)
+ # FIXME Prefixed with "lua" to prevent cmake from doing "-l-framework Cocoa"
+ set(FRAMEWORKS "-framework Cocoa -framework Security -framework OpenAL -framework IOKit")
+else(APPLE)
+ if(UNIX)
+ set(SYSLIBS dl rt)
+ endif(UNIX)
+endif(APPLE)
+
+target_link_libraries(
+ tremded
+ #
+ lua
+ script_api
+ nettle
+ zlib
+ ${FRAMEWORKS}
+ ${SYSLIBS}
+ )
+
+include_directories(
+ ${PARENT_DIR}/script
+ ${EXTERNAL_DIR}/lua-5.3.3/include
+ ${EXTERNAL_DIR}/sol
+ ${EXTERNAL_DIR}/script/rapidjson
+ ${EXTERNAL_DIR}/nettle-3.3
+ ${EXTERNAL_DIR}/zlib
+ )
diff --git a/src/server/server.h b/src/server/server.h
new file mode 100644
index 0000000..a07b66c
--- /dev/null
+++ b/src/server/server.h
@@ -0,0 +1,529 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2012-2018 ET:Legacy team <mail@etlegacy.com>
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// server.h
+
+#ifndef SERVER_H
+#define SERVER_H 1
+
+#include "game/g_public.h"
+#include "qcommon/cmd.h"
+#include "qcommon/crypto.h"
+#include "qcommon/cvar.h"
+#include "qcommon/files.h"
+#include "qcommon/huffman.h"
+#include "qcommon/msg.h"
+#include "qcommon/net.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+#include "qcommon/vm.h"
+#include "sys/sys_shared.h"
+
+//=============================================================================
+
+#define PERS_SCORE 0 // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!!
+#define CS_WARMUP 5 // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!!
+
+// server attack protection
+#define SVP_IOQ3 0x0001 ///< 1 - ioQuake3 way
+#define SVP_OWOLF 0x0002 ///< 2 - OpenWolf way
+#define SVP_CONSOLE 0x0004 ///< 4 - console print
+
+#define MAX_ENT_CLUSTERS 16
+
+#ifdef USE_VOIP
+#define VOIP_QUEUE_LENGTH 64
+struct voipServerPacket_t {
+ int generation;
+ int sequence;
+ int frames;
+ int len;
+ int sender;
+ int flags;
+ byte data[4000];
+};
+#endif // USE_VOIP
+
+struct svEntity_t {
+ struct worldSector_t *worldSector;
+ svEntity_t *nextEntityInWorldSector;
+
+ entityState_t baseline; // for delta compression of initial sighting
+ int numClusters; // if -1, use headnode instead
+ int clusternums[MAX_ENT_CLUSTERS];
+ int lastCluster; // if all the clusters don't fit in clusternums
+ int areanum, areanum2;
+ int snapshotCounter; // used to prevent double adding from portal views
+};
+
+enum serverState_t {
+ SS_DEAD, // no map loaded
+ SS_LOADING, // spawning level entities
+ SS_GAME // actively running
+};
+
+struct configString_t {
+ char *s;
+ bool restricted; // if true, don't send to clientList
+ clientList_t clientList;
+};
+
+struct server_t {
+ serverState_t state;
+ bool restarting; // if true, send configstring changes during SS_LOADING
+ int serverId; // changes each server start
+ int restartedServerId; // serverId before a map_restart
+ int checksumFeed; // the feed key that we use to compute the pure checksum strings
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
+ // the serverId associated with the current checksumFeed (always <= serverId)
+ int checksumFeedServerId;
+ int snapshotCounter; // incremented for each snapshot built
+ int timeResidual; // <= 1000 / sv_frame->value
+ int nextFrameTime; // when time > nextFrameTime, process world
+ configString_t configstrings[MAX_CONFIGSTRINGS];
+ svEntity_t svEntities[MAX_GENTITIES];
+
+ char *entityParsePoint; // used during game VM init
+
+ // the game virtual machine will update these on init and changes
+ sharedEntity_t *gentities;
+ int gentitySize;
+ int num_entities; // current number, <= MAX_GENTITIES
+
+ playerState_t *gameClients;
+ int gameClientSize; // will be > sizeof(playerState_t) due to game private data
+
+ int restartTime;
+ int time;
+
+ vm_t *gvm; // game virtual machine
+};
+
+struct clientSnapshot_t {
+ int areabytes;
+ byte areabits[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
+ playerState_t ps;
+ int num_entities;
+ int first_entity; // into the circular sv_packet_entities[]
+ // the entities MUST be in increasing state number
+ // order, otherwise the delta compression will fail
+ int messageSent; // time the message was transmitted
+ int messageAcked; // time the message was acked
+ int messageSize; // used to rate drop packets
+};
+
+enum clientState_t {
+ CS_FREE, // can be reused for a new connection
+ CS_ZOMBIE, // client has been disconnected, but don't reuse
+ // connection for a couple seconds
+ CS_CONNECTED, // has been assigned to a client_t, but no gamestate yet
+ CS_PRIMED, // gamestate has been sent, but client hasn't sent a usercmd
+ CS_ACTIVE // client is fully in game
+};
+
+struct netchan_buffer_t {
+ msg_t msg;
+ byte msgBuffer[MAX_MSGLEN];
+ netchan_buffer_t *next;
+};
+
+struct client_t {
+ clientState_t state;
+ char userinfo[MAX_INFO_STRING]; // name, etc
+ char userinfobuffer[MAX_INFO_STRING]; ///< used for buffering of user info
+
+ char reliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];
+ int reliableSequence; // last added reliable message, not necesarily sent or acknowledged yet
+ int reliableAcknowledge; // last acknowledged reliable message
+ int reliableSent; // last sent reliable message, not necesarily acknowledged yet
+ int messageAcknowledge;
+
+ int gamestateMessageNum; // netchan->outgoingSequence of gamestate
+ int challenge;
+
+ usercmd_t lastUsercmd;
+ int lastMessageNum; // for delta compression
+ int lastClientCommand; // reliable client message sequence
+ char lastClientCommandString[MAX_STRING_CHARS];
+ sharedEntity_t *gentity; // SV_GentityNum(clientnum)
+ char name[MAX_NAME_LENGTH]; // extracted from userinfo, high bits masked
+
+ // downloading
+ char downloadName[MAX_QPATH]; // if not empty string, we are downloading
+ fileHandle_t download; // file being downloaded
+ int downloadSize; // total bytes (can't use EOF because of paks)
+ int downloadCount; // bytes sent
+ int downloadClientBlock; // last block we sent to the client, awaiting ack
+ int downloadCurrentBlock; // current block number
+ int downloadXmitBlock; // last block we xmited
+ unsigned char *downloadBlocks[MAX_DOWNLOAD_WINDOW]; // the buffers for the download blocks
+ int downloadBlockSize[MAX_DOWNLOAD_WINDOW];
+ bool downloadEOF; // We have sent the EOF block
+ int downloadSendTime; // time we last got an ack from the client
+
+ int deltaMessage; // frame last client usercmd message
+ int nextReliableTime; // svs.time when another reliable command will be allowed
+ int nextReliableUserTime; // svs.time when another userinfo change will be allowed
+ int lastPacketTime; // svs.time when packet was last received
+ int lastConnectTime; // svs.time when connection started
+ int lastSnapshotTime; // svs.time of last sent snapshot
+ bool rateDelayed; // true if nextSnapshotTime was set based on rate instead of snapshotMsec
+ int timeoutCount; // must timeout a few frames in a row so debugging doesn't break
+ clientSnapshot_t frames[PACKET_BACKUP]; // updates can be delta'd from here
+ int ping;
+ int rate; // bytes / second
+ int snapshotMsec; // requests a snapshot every snapshotMsec unless rate choked
+ int pureAuthentic;
+ bool gotCP; // TTimo - additional flag to distinguish between a bad pure checksum, and no cp command at all
+ netchan_t netchan;
+ // TTimo
+ // queuing outgoing fragmented messages to send them properly, without udp packet bursts
+ // in case large fragmented messages are stacking up
+ // buffer them into this queue, and hand them out to netchan as needed
+ netchan_buffer_t *netchan_start_queue;
+ netchan_buffer_t **netchan_end_queue;
+
+ char fingerprint[SHA256_DIGEST_SIZE * 2 + 1];
+
+#ifdef USE_VOIP
+ bool hasVoip;
+ bool muteAllVoip;
+ bool ignoreVoipFromClient[MAX_CLIENTS];
+ voipServerPacket_t *voipPacket[VOIP_QUEUE_LENGTH];
+ size_t queuedVoipPackets;
+ int queuedVoipIndex;
+#endif
+
+ int oldServerTime;
+ bool csUpdated[MAX_CONFIGSTRINGS];
+};
+
+//=============================================================================
+#define STATFRAMES 200 ///< 5 seconds - assumed we run 40 fps
+
+/**
+ * @struct svstats_t
+ * @brief
+ */
+struct svstats_t {
+ double active;
+ double idle;
+ int count;
+
+ double latched_active;
+ double latched_idle;
+
+ float cpu;
+ float avg;
+};
+
+// MAX_CHALLENGES is made large to prevent a denial
+// of service attack that could cycle all of them
+// out before legitimate users connected
+#define MAX_CHALLENGES 2048
+// Allow a certain amount of challenges to have the same IP address
+// to make it a bit harder to DOS one single IP address from connecting
+// while not allowing a single ip to grab all challenge resources
+#define MAX_CHALLENGES_MULTI (MAX_CHALLENGES / 2)
+
+#define AUTHORIZE_TIMEOUT 5000
+
+struct challenge_t {
+ netadr_t adr;
+ int challenge;
+ char challenge2[33];
+ int clientChallenge; // challenge number coming from the client
+ int time; // time the last packet was sent to the autherize server
+ int pingTime; // time the challenge response was sent to client
+ int firstTime; // time the adr was first used, for authorize timeout checks
+ bool wasrefused;
+ bool connected;
+};
+
+/**
+ * @struct receipt_t
+ * @brief
+ */
+struct receipt_t {
+ netadr_t adr;
+ int time;
+};
+
+/**
+ * @def MAX_INFO_RECEIPTS
+ * @brief the maximum number of getstatus+getinfo responses that we send in
+ * a two second time period.
+ */
+#define MAX_INFO_RECEIPTS 48
+
+/**
+ * @struct tempBan_s
+ * @typedef tempBan_t
+ * @brief
+ */
+struct tempBan_t {
+ netadr_t adr;
+ int endtime;
+};
+
+#define MAX_TEMPBAN_ADDRESSES MAX_CLIENTS
+
+#define SERVER_PERFORMANCECOUNTER_FRAMES 600
+#define SERVER_PERFORMANCECOUNTER_SAMPLES 6
+
+// this structure will be cleared only when the game dll changes
+struct serverStatic_t {
+ bool initialized; // sv_init has completed
+
+ int time; // will be strictly increasing across level changes
+
+ int snapFlagServerBit; // ^= SNAPFLAG_SERVERCOUNT every SV_SpawnServer()
+
+ client_t *clients; // [sv_maxclients->integer];
+ int numSnapshotEntities; // sv_maxclients->integer*PACKET_BACKUP*MAX_SNAPSHOT_ENTITIES
+ int nextSnapshotEntities; // next snapshotEntities to use
+ entityState_t *snapshotEntities; // [numSnapshotEntities]
+ int nextHeartbeatTime;
+ challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
+ receipt_t infoReceipts[MAX_INFO_RECEIPTS];
+ netadr_t redirectAddress; // for rcon return messages
+
+ netadr_t authorizeAddress; // for rcon return messages
+
+ int sampleTimes[SERVER_PERFORMANCECOUNTER_SAMPLES];
+ int currentSampleIndex;
+ int totalFrameTime;
+ int currentFrameIndex;
+ int serverLoad;
+ svstats_t stats;
+};
+
+//=============================================================================
+
+extern serverStatic_t svs; // persistant server info across maps
+extern server_t sv; // cleared each map
+
+extern cvar_t *sv_fps;
+extern cvar_t *sv_timeout;
+extern cvar_t *sv_zombietime;
+extern cvar_t *sv_rconPassword;
+extern cvar_t *sv_privatePassword;
+extern cvar_t *sv_allowDownload;
+extern cvar_t *sv_maxclients;
+
+extern cvar_t *sv_privateClients;
+extern cvar_t *sv_hostname;
+extern cvar_t *sv_masters[3][MAX_MASTER_SERVERS];
+extern cvar_t *sv_reconnectlimit;
+extern cvar_t *sv_showloss;
+extern cvar_t *sv_padPackets;
+extern cvar_t *sv_killserver;
+extern cvar_t *sv_mapname;
+extern cvar_t *sv_mapChecksum;
+extern cvar_t *sv_serverid;
+extern cvar_t *sv_minRate;
+extern cvar_t *sv_maxRate;
+extern cvar_t *sv_dlRate;
+extern cvar_t *sv_minPing;
+extern cvar_t *sv_maxPing;
+extern cvar_t *sv_pure;
+extern cvar_t *sv_lanForceRate;
+extern cvar_t *sv_banFile;
+
+extern cvar_t *sv_protect;
+extern cvar_t *sv_protectLog;
+
+#ifdef USE_VOIP
+extern cvar_t *sv_voip;
+extern cvar_t *sv_voipProtocol;
+#endif
+
+extern cvar_t *sv_rsaAuth;
+
+extern cvar_t *sv_schachtmeisterPort;
+
+//===========================================================
+
+//
+// sv_main.c
+//
+struct leakyBucket_t {
+ netadrtype_t type;
+
+ union {
+ byte _4[4];
+ byte _6[16];
+ } ipv;
+
+ int lastTime;
+ signed char burst;
+
+ long hash;
+
+ leakyBucket_t *prev, *next;
+};
+
+extern leakyBucket_t outboundLeakyBucket;
+
+bool SVC_RateLimit(leakyBucket_t *bucket, int burst, int period);
+bool SVC_RateLimitAddress(netadr_t from, int burst, int period);
+
+void SV_FinalMessage(const char *message);
+void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+
+void SV_AddOperatorCommands(void);
+void SV_RemoveOperatorCommands(void);
+
+void SV_MasterShutdown(void);
+int SV_RateMsec(client_t *client);
+
+//
+// sv_init.c
+//
+void SV_SetConfigstring(int index, const char *val);
+void SV_GetConfigstring(int index, char *buffer, int bufferSize);
+void SV_SetConfigstringRestrictions(int index, const clientList_t *clientList);
+void SV_UpdateConfigstrings(client_t *client);
+
+void SV_SetUserinfo(int index, const char *val);
+void SV_GetUserinfo(int index, char *buffer, int bufferSize);
+
+void SV_ChangeMaxClients(void);
+void SV_SpawnServer(char *server);
+void SV_WriteAttackLog(const char *log);
+
+#ifdef NDEBUG
+#define SV_WriteAttackLogD(x)
+#else
+#define SV_WriteAttackLogD(x) SV_WriteAttackLog(x)
+#endif
+
+//
+// sv_client.c
+//
+void SV_GetChallenge(netadr_t from);
+
+void SV_DirectConnect(netadr_t from);
+
+void SV_ExecuteClientMessage(client_t *cl, msg_t *msg);
+void SV_UserinfoChanged(client_t *cl);
+
+void SV_ClientEnterWorld(client_t *client, usercmd_t *cmd);
+void SV_FreeClient(client_t *client);
+void SV_DropClient(client_t *drop, const char *reason);
+
+void SV_ExecuteClientCommand(client_t *cl, const char *s, bool clientOK);
+void SV_ClientThink(client_t *cl, usercmd_t *cmd);
+
+int SV_WriteDownloadToClient(client_t *cl, msg_t *msg);
+int SV_SendDownloadMessages(void);
+int SV_SendQueuedMessages(void);
+
+//
+// sv_ccmds.c
+//
+void SV_Heartbeat_f(void);
+
+//
+// sv_snapshot.c
+//
+void SV_AddServerCommand(client_t *client, const char *cmd);
+void SV_UpdateServerCommandsToClient(client_t *client, msg_t *msg);
+void SV_WriteFrameToClient(client_t *client, msg_t *msg);
+void SV_SendMessageToClient(msg_t *msg, client_t *client);
+void SV_SendClientMessages(void);
+void SV_SendClientSnapshot(client_t *client);
+
+//
+// sv_game.c
+//
+int SV_NumForGentity(sharedEntity_t *ent);
+sharedEntity_t *SV_GentityNum(int num);
+playerState_t *SV_GameClientNum(int num);
+svEntity_t *SV_SvEntityForGentity(sharedEntity_t *gEnt);
+sharedEntity_t *SV_GEntityForSvEntity(svEntity_t *svEnt);
+void SV_InitGameProgs(void);
+void SV_ShutdownGameProgs(void);
+void SV_RestartGameProgs(void);
+bool SV_inPVS(const vec3_t p1, const vec3_t p2);
+
+//============================================================
+//
+// high level object sorting to reduce interaction tests
+//
+
+void SV_ClearWorld(void);
+// called after the world model has been loaded, before linking any entities
+
+void SV_UnlinkEntity(sharedEntity_t *ent);
+// call before removing an entity, and before trying to move one,
+// so it doesn't clip against itself
+
+void SV_LinkEntity(sharedEntity_t *ent);
+// Needs to be called any time an entity changes origin, mins, maxs,
+// or solid. Automatically unlinks if needed.
+// sets ent->r.absmin and ent->r.absmax
+// sets ent->leafnums[] for pvs determination even if the entity
+// is not solid
+
+clipHandle_t SV_ClipHandleForEntity(const sharedEntity_t *ent);
+
+void SV_SectorList_f(void);
+
+int SV_AreaEntities(const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount);
+// fills in a table of entity numbers with entities that have bounding boxes
+// that intersect the given area. It is possible for a non-axial bmodel
+// to be returned that doesn't actually intersect the area on an exact
+// test.
+// returns the number of pointers filled in
+// The world entity is never returned in this list.
+
+int SV_PointContents(const vec3_t p, int passEntityNum);
+// returns the CONTENTS_* value from the world and all entities at the given point.
+
+void SV_Trace(trace_t *results, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int passEntityNum,
+ int contentmask, traceType_t type);
+// mins and maxs are relative
+
+// if the entire move stays in a solid volume, trace.allsolid will be set,
+// trace.startsolid will be set, and trace.fraction will be 0
+
+// if the starting point is in a solid, it will be allowed to move out
+// to an open area
+
+// passEntityNum is explicitly excluded from clipping checks (normally ENTITYNUM_NONE)
+
+void SV_ClipToEntity(trace_t *trace, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
+ int entityNum, int contentmask, traceType_t type);
+// clip to a specific entity
+
+//
+// sv_net_chan.c
+//
+void SV_Netchan_Transmit(client_t *client, msg_t *msg);
+int SV_Netchan_TransmitNextFragment(client_t *client);
+bool SV_Netchan_Process(client_t *client, msg_t *msg);
+void SV_Netchan_FreeQueue(client_t *client);
+
+#endif
diff --git a/src/server/sv_admin.cpp b/src/server/sv_admin.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/server/sv_admin.cpp
diff --git a/src/server/sv_admin.h b/src/server/sv_admin.h
new file mode 100644
index 0000000..b261457
--- /dev/null
+++ b/src/server/sv_admin.h
@@ -0,0 +1,61 @@
+//
+// This file is part of Tremulous.
+// Copyright © 2017 Victor Roemer (blowfish) <victor@badsec.org>
+// Copyright (C) 2015-2019 GrangerHub
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+
+#pragma once
+
+#include <iostream>
+
+using std::string;
+
+typedef char fingerprint_t[64];
+typedef char guid_t[33];
+typedef char name_t[MAX_NAME_LENGTH];
+typedef char err_t[MAX_STRING_CHARS];
+
+struct AdminFlag {
+ unsigned id;
+ name_t name;
+};
+
+struct AdminLevel {
+ name_t name;
+ admin_flags_t flags;
+ unsigned level;
+};
+
+struct Admin {
+ bool flag(const name_t flagname)
+ { }
+
+ bool deny(const name_t flagname)
+ { }
+
+ guid_t guid;
+ name_t name;
+
+private:
+ admin_flags_t flags;
+ admin_flags_t denied;
+ unsigned level;
+};
+
+class AdminMgr {
+ bool add(Admin&);
+ bool remove(Admin&);
+}
diff --git a/src/server/sv_ccmds.cpp b/src/server/sv_ccmds.cpp
new file mode 100644
index 0000000..5c8902d
--- /dev/null
+++ b/src/server/sv_ccmds.cpp
@@ -0,0 +1,441 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2012-2018 ET:Legacy team <mail@etlegacy.com>
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include <arpa/inet.h>
+#include "server.h"
+
+/*
+===============================================================================
+
+OPERATOR CONSOLE ONLY COMMANDS
+
+These commands can only be entered from stdin or by a remote operator datagram
+===============================================================================
+*/
+
+/*
+==================
+SV_Map_f
+
+Restart the server on a different map
+==================
+*/
+static void SV_Map_f( void ) {
+ const char *cmd;
+ const char *map;
+ bool cheat;
+ char expanded[MAX_QPATH];
+ char mapname[MAX_QPATH];
+ int a;
+ int i;
+
+ map = Cmd_Argv(1);
+ if ( !map ) {
+ return;
+ }
+
+ // make sure the level exists before trying to change, so that
+ // a typo at the server console won't end the game
+ Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map);
+ if ( FS_ReadFile (expanded, NULL) == -1 ) {
+ Com_Printf ("Can't find map %s\n", expanded);
+ return;
+ }
+
+ cmd = Cmd_Argv(0);
+ if ( !Q_stricmp( cmd, "devmap" ) ) {
+ cheat = true;
+ } else {
+ cheat = false;
+ }
+
+ // save the map name here cause on a map restart we reload the autogen.cfg
+ // and thus nuke the arguments of the map command
+ Q_strncpyz(mapname, map, sizeof(mapname));
+
+ // start up the map
+ SV_SpawnServer( mapname );
+
+ // set the cheat value
+ // if the level was started with "map <levelname>", then
+ // cheats will not be allowed. If started with "devmap <levelname>"
+ // then cheats will be allowed
+ if ( cheat ) {
+ Cvar_Set( "sv_cheats", "1" );
+ } else {
+ Cvar_Set( "sv_cheats", "0" );
+ }
+
+ // This forces the local master server IP address cache
+ // to be updated on sending the next heartbeat
+ for( a = 0; a < 3; ++a )
+ for( i = 0; i < MAX_MASTER_SERVERS; i++ )
+ sv_masters[ a ][ i ]->modified = true;
+}
+
+/*
+================
+SV_MapRestart_f
+
+Completely restarts a level, but doesn't send a new gamestate to the clients.
+This allows fair starts with variable load times.
+================
+*/
+static void SV_MapRestart_f( void ) {
+ int i;
+ client_t *client;
+ char *denied;
+ int delay;
+
+ // make sure we aren't restarting twice in the same frame
+ if ( com_frameTime == sv.serverId ) {
+ return;
+ }
+
+ // make sure server is running
+ if ( !com_sv_running->integer ) {
+ Com_Printf( "Server is not running.\n" );
+ return;
+ }
+
+ if ( sv.restartTime ) {
+ return;
+ }
+
+ if (Cmd_Argc() > 1 ) {
+ delay = atoi( Cmd_Argv(1) );
+ }
+ else {
+ delay = 0;
+ }
+ if( delay && !Cvar_VariableValue("g_doWarmup") ) {
+ sv.restartTime = sv.time + delay * 1000;
+ SV_SetConfigstring( CS_WARMUP, va("%i", sv.restartTime) );
+ return;
+ }
+
+ // check for changes in variables that can't just be restarted
+ // check for maxclients change
+ if ( sv_maxclients->modified ) {
+ char mapname[MAX_QPATH];
+
+ Com_Printf( "variable change -- restarting.\n" );
+ // restart the map the slow way
+ Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );
+
+ SV_SpawnServer( mapname );
+ return;
+ }
+
+ // toggle the server bit so clients can detect that a
+ // map_restart has happened
+ svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;
+
+ // generate a new serverid
+ // TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
+ sv.serverId = com_frameTime;
+ Cvar_Set( "sv_serverid", va("%i", sv.serverId ) );
+
+ // if a map_restart occurs while a client is changing maps, we need
+ // to give them the correct time so that when they finish loading
+ // they don't violate the backwards time check in cl_cgame.c
+ for (i=0 ; i<sv_maxclients->integer ; i++) {
+ if (svs.clients[i].state == CS_PRIMED) {
+ svs.clients[i].oldServerTime = sv.restartTime;
+ }
+ }
+
+ // reset all the vm data in place without changing memory allocation
+ // note that we do NOT set sv.state = SS_LOADING, so configstrings that
+ // had been changed from their default values will generate broadcast updates
+ sv.state = SS_LOADING;
+ sv.restarting = true;
+
+ SV_RestartGameProgs();
+
+ // run a few frames to allow everything to settle
+ for (i = 0; i < 3; i++)
+ {
+ VM_Call (sv.gvm, GAME_RUN_FRAME, sv.time);
+ sv.time += 100;
+ svs.time += 100;
+ }
+
+ sv.state = SS_GAME;
+ sv.restarting = false;
+
+ // connect and begin all the clients
+ for (i=0 ; i<sv_maxclients->integer ; i++) {
+ client = &svs.clients[i];
+
+ // send the new gamestate to all connected clients
+ if ( client->state < CS_CONNECTED) {
+ continue;
+ }
+
+ // add the map_restart command
+ SV_AddServerCommand( client, "map_restart\n" );
+
+ // connect the client again, without the firstTime flag
+ denied = (char*)VM_ExplicitArgPtr( sv.gvm, VM_Call( sv.gvm, GAME_CLIENT_CONNECT, i, false ) );
+ if ( denied ) {
+ // this generally shouldn't happen, because the client
+ // was connected before the level change
+ SV_DropClient( client, denied );
+ Com_Printf( "SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i );
+ continue;
+ }
+
+ if(client->state == CS_ACTIVE)
+ SV_ClientEnterWorld(client, &client->lastUsercmd);
+ else
+ {
+ // If we don't reset client->lastUsercmd and are restarting during map load,
+ // the client will hang because we'll use the last Usercmd from the previous map,
+ // which is wrong obviously.
+ SV_ClientEnterWorld(client, NULL);
+ }
+ }
+
+ // run another frame to allow things to look at all the players
+ VM_Call (sv.gvm, GAME_RUN_FRAME, sv.time);
+ sv.time += 100;
+ svs.time += 100;
+}
+
+
+//===============================================================
+
+/**
+ * @brief SV_Status_f
+ */
+static void SV_Status_f(void) {
+ int i;
+ client_t *cl;
+ playerState_t *ps;
+ const char *s;
+ int ping;
+ unsigned int maxNameLength;
+
+ // make sure server is running
+ if (!com_sv_running->integer) {
+ Com_Printf("Server is not running.\n");
+ return;
+ }
+
+ Com_Printf("cpu server utilization: %i %%\n"
+ "avg response time : %i ms\n"
+ "server time : %i\n"
+ "internal time : %i\n"
+ "map : %s\n\n"
+ "num score ping name lastmsg address qport rate lastConnectTime\n"
+ "--- ----- ---- ----------------------------------- ------- --------------------- ----- ----- ---------------\n",
+ ( int ) svs.stats.cpu,
+ ( int ) svs.stats.avg,
+ svs.time,
+ Sys_Milliseconds(),
+ sv_mapname->string);
+
+ for (i = 0, cl = svs.clients ; i < sv_maxclients->integer ; i++, cl++) {
+ Com_Printf("%3i ", i);
+ ps = SV_GameClientNum(i);
+ Com_Printf("%5i ", ps->persistant[PERS_SCORE]);
+
+ if (cl->state == CS_CONNECTED) {
+ Com_Printf("CNCT ");
+ } else if (cl->state == CS_ZOMBIE) {
+ Com_Printf("ZMBI ");
+ } else {
+ ping = cl->ping < 9999 ? cl->ping : 9999;
+ Com_Printf("%4i ", ping);
+ }
+
+ s = NET_AdrToString(cl->netchan.remoteAddress);
+
+ // extend the name length by couting extra color characters to keep well formated output
+ maxNameLength = sizeof(cl->name) + (strlen(cl->name) - Q_PrintStrlen(cl->name)) + 1;
+
+ Com_Printf("%-*s %7i %-21s %5i %5i %i\n", maxNameLength, rc(cl->name), svs.time - cl->lastPacketTime, s, cl->netchan.qport, cl->rate, svs.time - cl->lastConnectTime);
+ }
+
+ Com_Printf("\n");
+}
+
+
+/*
+==================
+SV_Heartbeat_f
+
+Also called by SV_DropClient, SV_DirectConnect, and SV_SpawnServer
+==================
+*/
+void SV_Heartbeat_f( void ) {
+ svs.nextHeartbeatTime = -9999999;
+}
+
+
+/*
+===========
+SV_Serverinfo_f
+
+Examine the serverinfo string
+===========
+*/
+static void SV_Serverinfo_f( void ) {
+ // make sure server is running
+ if ( !com_sv_running->integer ) {
+ Com_Printf( "Server is not running.\n" );
+ return;
+ }
+
+ Com_Printf ("Server info settings:\n");
+ Info_Print ( Cvar_InfoString( CVAR_SERVERINFO ) );
+}
+
+
+/*
+===========
+SV_Systeminfo_f
+
+Examine the systeminfo string
+===========
+*/
+static void SV_Systeminfo_f( void ) {
+ // make sure server is running
+ if ( !com_sv_running->integer ) {
+ Com_Printf( "Server is not running.\n" );
+ return;
+ }
+
+ Com_Printf ("System info settings:\n");
+ Info_Print ( Cvar_InfoString_Big( CVAR_SYSTEMINFO ) );
+}
+
+
+/*
+=================
+SV_KillServer
+=================
+*/
+static void SV_KillServer_f( void ) {
+ SV_Shutdown( "killserver" );
+}
+
+static void SV_SMQ_f( void ) {
+ static qboolean schmResolved = qfalse;
+ static netadr_t schmAddress;
+
+ if ( !schmResolved ) {
+ schmResolved = qtrue;
+ NET_StringToAdr( "127.0.0.1", &schmAddress, NA_IP );
+ schmAddress.port = 1337;
+ }
+
+ if ( sv_schachtmeisterPort->modified &&
+ sv_schachtmeisterPort->integer >= 1 && sv_schachtmeisterPort->integer <= 65535 )
+ {
+ schmAddress.port = htons(sv_schachtmeisterPort->integer);
+ }
+
+ if ( Cmd_Argc() >= 3 && !Q_stricmp( Cmd_Argv( 1 ), "ipa" ) ) { // compatibility with out-of-date crapware conceived in the future
+ NET_OutOfBandPrint( NS_SERVER, schmAddress, "sm2query %s", Cmd_ArgsFrom( 2 ) );
+ Com_Printf( "^3query [^7sm2query %s^3]\n", Cmd_ArgsFrom( 2 ) ); // DELME
+ } else {
+ char args[ MAX_STRING_CHARS ];
+ char *p;
+ int s, i;
+
+ p = args;
+ s = sizeof( args );
+
+ for ( i = 1; i < Cmd_Argc(); ++i )
+ {
+ int l;
+ Com_sprintf( p, s, " \"%s\"", Cmd_Argv( i ) );
+ l = strlen( p );
+ s -= l;
+ p += l;
+ }
+
+ NET_OutOfBandPrint( NS_SERVER, schmAddress, "sm2query%s", args );
+ Com_Printf( "^3query [^7sm2query%s^3]\n", args ); // DELME
+ }
+}
+
+//===========================================================
+
+/*
+==================
+SV_CompleteMapName
+==================
+*/
+static void SV_CompleteMapName( char *args, int argNum ) {
+ if( argNum == 2 ) {
+ Field_CompleteFilename( "maps", "bsp", true, false );
+ }
+}
+
+/*
+==================
+SV_AddOperatorCommands
+==================
+*/
+void SV_AddOperatorCommands( void ) {
+ static bool initialized = false;
+
+ if ( initialized ) {
+ return;
+ }
+ initialized = true;
+
+ Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
+ Cmd_AddCommand ("status", SV_Status_f);
+ Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
+ Cmd_AddCommand ("systeminfo", SV_Systeminfo_f);
+ Cmd_AddCommand ("map_restart", SV_MapRestart_f);
+ Cmd_AddCommand ("sectorlist", SV_SectorList_f);
+ Cmd_AddCommand ("map", SV_Map_f);
+ Cmd_SetCommandCompletionFunc( "map", SV_CompleteMapName );
+ Cmd_AddCommand ("devmap", SV_Map_f);
+ Cmd_SetCommandCompletionFunc( "devmap", SV_CompleteMapName );
+ Cmd_AddCommand ("killserver", SV_KillServer_f);
+ Cmd_AddCommand ("smq", SV_SMQ_f);
+}
+
+/*
+==================
+SV_RemoveOperatorCommands
+==================
+*/
+void SV_RemoveOperatorCommands( void ) {
+#if 0
+ // removing these won't let the server start again
+ Cmd_RemoveCommand ("heartbeat");
+ Cmd_RemoveCommand ("serverinfo");
+ Cmd_RemoveCommand ("systeminfo");
+ Cmd_RemoveCommand ("map_restart");
+ Cmd_RemoveCommand ("sectorlist");
+#endif
+}
diff --git a/src/server/sv_client.cpp b/src/server/sv_client.cpp
new file mode 100644
index 0000000..0a54a32
--- /dev/null
+++ b/src/server/sv_client.cpp
@@ -0,0 +1,1949 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2012-2018 ET:Legacy team <mail@etlegacy.com>
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// sv_client.c -- server code for dealing with clients
+
+#include "server.h"
+
+static void SV_CloseDownload( client_t *cl );
+
+/*
+=================
+SV_RSA_VerifySignature
+
+Verifies the signature of data and on success it returns the sha256
+fingerprint of the public key. pubkey, signature, and fingerprint
+are all base 16 encoded strings.
+
+Returns true on success
+=================
+*/
+static bool SV_RSA_VerifySignature( const char *pubkey, const char *signature, const char *data, char *fingerprint )
+{
+ struct rsa_public_key public_key;
+ struct sha256_ctx sha256_hash;
+ uint8_t buf[RSA_STRING_LENGTH];
+ int err;
+ mpz_t n;
+
+ if ( !*pubkey || !*signature )
+ return false;
+
+ // load public key
+ rsa_public_key_init( &public_key );
+ mpz_set_ui( public_key.e, RSA_PUBLIC_EXPONENT );
+ err = mpz_set_str( public_key.n, pubkey, 16 );
+ if ( err ) {
+ rsa_public_key_clear( &public_key );
+ return false;
+ }
+
+ err = !rsa_public_key_prepare( &public_key );
+ if ( err ) {
+ rsa_public_key_clear( &public_key );
+ return false;
+ }
+
+ // load signature
+ mpz_init( n );
+ err = mpz_set_str( n, signature, 16 );
+ if ( err ) {
+ mpz_clear( n );
+ rsa_public_key_clear( &public_key );
+ return false;
+ }
+
+ // hash data
+ sha256_init( &sha256_hash );
+ sha256_update( &sha256_hash, strlen(data), (uint8_t *) data);
+
+ if ( !rsa_sha256_verify( &public_key, &sha256_hash, n ) ) {
+ mpz_clear( n );
+ rsa_public_key_clear( &public_key );
+ return false;
+ }
+
+ // VERIFIED, save the sha256 fingerprint of the key
+ nettle_mpz_get_str_256( sizeof(buf), buf, public_key.n );
+
+ sha256_update( &sha256_hash, sizeof(buf), buf );
+ sha256_digest( &sha256_hash, SHA256_DIGEST_SIZE, buf );
+
+ nettle_mpz_set_str_256_u( n, SHA256_DIGEST_SIZE, buf );
+ mpz_get_str( fingerprint, 16, n );
+
+ mpz_clear( n );
+ rsa_public_key_clear( &public_key );
+ return true;
+}
+
+/*
+=================
+SV_GetChallenge
+
+A "getchallenge" OOB command has been received
+Returns a challenge number that can be used
+in a subsequent connectResponse command.
+We do this to prevent denial of service attacks that
+flood the server with invalid connection IPs. With a
+challenge, they must give a valid IP address.
+
+If we are authorizing, a challenge request will cause a packet
+to be sent to the authorize server.
+
+When an authorizeip is returned, a challenge response will be
+sent to that ip.
+
+ioquake3: we added a possibility for clients to add a challenge
+to their packets, to make it more difficult for malicious servers
+to hi-jack client connections.
+Also, the auth stuff is completely disabled for com_standalone games
+as well as IPv6 connections, since there is no way to use the
+v4-only auth server for these new types of connections.
+=================
+*/
+void SV_GetChallenge(netadr_t from)
+{
+ int i;
+ int oldest;
+ int oldestTime;
+ int oldestClientTime;
+ int clientChallenge;
+ challenge_t *challenge;
+ bool wasfound = false;
+ byte buf[16];
+ mpz_t n;
+
+ if (sv_protect->integer & SVP_IOQ3)
+ if ( SVC_RateLimitAddress( from, 10, 1000 ) ) {
+ {
+ Com_DPrintf( "SV_GetChallenge: rate limit from %s exceeded, dropping request\n",
+ // Prevent using getchallenge as an amplifier
+ NET_AdrToString( from ) );
+ if (SVC_RateLimitAddress(from, 10, 1000))
+ return;
+ {
+ }
+ SV_WriteAttackLog(va("SV_GetChallenge: rate limit from %s exceeded, dropping request\n",
+ NET_AdrToString(from)));
+ return;
+ }
+
+
+ // Allow getchallenge to be DoSed relatively easily, but prevent
+ // Allow getchallenge to be DoSed relatively easily, but prevent
+ // excess outbound bandwidth usage when being flooded inbound
+ // excess outbound bandwidth usage when being flooded inbound
+ if ( SVC_RateLimit( &outboundLeakyBucket, 10, 100 ) ) {
+ if (SVC_RateLimit(&outboundLeakyBucket, 10, 100))
+ Com_DPrintf( "SV_GetChallenge: rate limit exceeded, dropping request\n" );
+ {
+ return;
+ SV_WriteAttackLog("SV_GetChallenge: rate limit exceeded, dropping request\n");
+ return;
+ }
+ }
+ }
+
+ oldest = 0;
+ oldestClientTime = oldestTime = 0x7fffffff;
+
+ // see if we already have a challenge for this ip
+ challenge = &svs.challenges[0];
+ clientChallenge = atoi(Cmd_Argv(1));
+
+ for(i = 0 ; i < MAX_CHALLENGES ; i++, challenge++)
+ {
+ if(!challenge->connected && NET_CompareAdr(from, challenge->adr))
+ {
+ wasfound = true;
+
+ if(challenge->time < oldestClientTime)
+ oldestClientTime = challenge->time;
+ }
+
+ if(wasfound && i >= MAX_CHALLENGES_MULTI)
+ {
+ i = MAX_CHALLENGES;
+ break;
+ }
+
+ if(challenge->time < oldestTime)
+ {
+ oldestTime = challenge->time;
+ oldest = i;
+ }
+ }
+
+ if (i == MAX_CHALLENGES)
+ {
+ // this is the first time this client has asked for a challenge
+ challenge = &svs.challenges[oldest];
+ challenge->clientChallenge = clientChallenge;
+ challenge->adr = from;
+ challenge->firstTime = svs.time;
+ challenge->connected = false;
+
+ if ( sv_rsaAuth->integer ) {
+ Sys_CryptoRandomBytes( buf, sizeof(buf) );
+ nettle_mpz_init_set_str_256_u( n, sizeof(buf), buf );
+ mpz_get_str( challenge->challenge2, 16, n );
+ mpz_clear( n );
+ }
+ }
+
+ // always generate a new challenge number, so the client cannot circumvent sv_maxping
+ challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time;
+ challenge->wasrefused = false;
+ challenge->time = svs.time;
+ challenge->pingTime = svs.time;
+
+ if ( sv_rsaAuth->integer ) {
+ NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %d %d %d %s",
+ challenge->challenge, clientChallenge, PROTOCOL_VERSION, challenge->challenge2 );
+ }
+ else {
+ NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %d %d %d",
+ challenge->challenge, clientChallenge, PROTOCOL_VERSION );
+ }
+}
+
+/*
+==================
+SV_DirectConnect
+
+A "connect" OOB command has been received
+==================
+*/
+void SV_DirectConnect( netadr_t from ) {
+ char userinfo[MAX_INFO_STRING];
+ int i;
+ client_t *cl, *newcl;
+ client_t temp;
+ sharedEntity_t *ent;
+ int clientNum;
+ int version;
+ int qport;
+ int challenge;
+ char *password;
+ int startIndex;
+ intptr_t denied;
+ int count;
+ const char *ip;
+ char *challenge2;
+ bool challenge2Verified = false;
+
+ Com_DPrintf ("SVC_DirectConnect ()\n");
+
+ // Prevent using connect as an amplifier
+ if (sv_protect->integer & SVP_IOQ3)
+ {
+ if(SVC_RateLimitAddress(from, 10, 1000))
+ {
+ SV_WriteAttackLog(va("Bad direct connect - rate limit from %s exceeded, dropping request\n",
+ NET_AdrToString(from)));
+ return;
+ }
+ }
+
+ Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) );
+
+ version = atoi( Info_ValueForKey( userinfo, "protocol" ) );
+ if ( version != PROTOCOL_VERSION && version != 70 && version != 69 ) {
+ NET_OutOfBandPrint(NS_SERVER, from, "print\nServer uses either protocol version %i, 70 or 69 "
+ "(yours is %i).\n", PROTOCOL_VERSION, version);
+ Com_DPrintf(" rejected connect from version %i\n", version);
+ return;
+ }
+
+ challenge = atoi( Info_ValueForKey( userinfo, "challenge" ) );
+ qport = atoi( Info_ValueForKey( userinfo, "qport" ) );
+
+ // quick reject
+ for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
+ if ( cl->state == CS_FREE ) {
+ continue;
+ }
+ if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )
+ && ( cl->netchan.qport == qport
+ || from.port == cl->netchan.remoteAddress.port ) ) {
+ if (( svs.time - cl->lastConnectTime)
+ < (sv_reconnectlimit->integer * 1000)) {
+ Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (from));
+ return;
+ }
+ break;
+ }
+ }
+
+ // don't let "ip" overflow userinfo string
+ if ( NET_IsLocalAddress (from) )
+ ip = "localhost";
+ else
+ ip = (char *)NET_AdrToString( from );
+ if( ( strlen( ip ) + strlen( userinfo ) + 4 ) >= MAX_INFO_STRING ) {
+ NET_OutOfBandPrint( NS_SERVER, from,
+ "print\nUserinfo string length exceeded. "
+ "Try removing setu cvars from your config.\n" );
+ return;
+ }
+ Info_SetValueForKey( userinfo, "ip", ip );
+
+ // see if the challenge is valid (LAN clients don't need to challenge)
+ if (!NET_IsLocalAddress(from))
+ {
+ int ping;
+ challenge_t *challengeptr;
+
+ for (i=0; i<MAX_CHALLENGES; i++)
+ {
+ if (NET_CompareAdr(from, svs.challenges[i].adr))
+ {
+ if(challenge == svs.challenges[i].challenge)
+ break;
+ }
+ }
+ if (i == MAX_CHALLENGES)
+ {
+ NET_OutOfBandPrint( NS_SERVER, from, "print\nNo or bad challenge for your address.\n" );
+ return;
+ }
+
+ if ( sv_rsaAuth->integer )
+ {
+ challenge2 = Info_ValueForKey( userinfo, "challenge2" );
+ if ( !Q_stricmp( challenge2, svs.challenges[i].challenge2 ) )
+ {
+ challenge2Verified = true;
+ }
+ }
+
+ challengeptr = &svs.challenges[i];
+
+ if(challengeptr->wasrefused)
+ {
+ // Return silently, so that error messages written by the server keep being displayed.
+ return;
+ }
+
+ ping = svs.time - challengeptr->pingTime;
+
+ // never reject a LAN client based on ping
+ if ( !Sys_IsLANAddress( from ) )
+ {
+ if ( sv_minPing->value && ping < sv_minPing->value ) {
+ NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for high pings only\n" );
+ Com_DPrintf ("Client %i rejected on a too low ping\n", i);
+ challengeptr->wasrefused = true;
+ return;
+ }
+ if ( sv_maxPing->value && ping > sv_maxPing->value ) {
+ NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for low pings only\n" );
+ Com_DPrintf ("Client %i rejected on a too high ping\n", i);
+ challengeptr->wasrefused = true;
+ return;
+ }
+ }
+
+ Com_Printf("Client %i connecting with %i challenge ping\n", i, ping);
+ challengeptr->connected = true;
+ }
+
+ // ignore any fingerprint set by the client
+ char fingerprint[SHA256_DIGEST_SIZE * 2 + 1];
+ Info_RemoveKey(userinfo, "fingerprint");
+ fingerprint[0] = '\0';
+
+ if ( sv_rsaAuth->integer && (NET_IsLocalAddress(from) || challenge2Verified) )
+ {
+ if ( SV_RSA_VerifySignature(Cmd_Argv(2), Cmd_Argv(3), Cmd_Argv(1), fingerprint) )
+ {
+ if( strlen(fingerprint) + strlen(userinfo) + 13 >= MAX_INFO_STRING )
+ {
+ NET_OutOfBandPrint( NS_SERVER, from, "print\nUserinfo string length exceeded.\n" );
+ return;
+ }
+ Info_SetValueForKey( userinfo, "fingerprint", fingerprint );
+ Com_DPrintf( "Public key fingerprint: %s\n", fingerprint );
+ }
+ }
+
+ newcl = &temp;
+ ::memset(newcl, 0, sizeof(client_t));
+
+ // if there is already a slot for this ip, reuse it
+ for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++)
+ {
+ if ( cl->state == CS_FREE )
+ continue;
+
+ if ( NET_CompareBaseAdr(from, cl->netchan.remoteAddress)
+ && (cl->netchan.qport == qport || from.port == cl->netchan.remoteAddress.port) )
+ {
+ Com_Printf ("%s:reconnect\n", NET_AdrToString (from));
+ newcl = cl;
+
+ // this doesn't work because it nukes the players userinfo
+ // disconnect the client from the game first so any flags the
+ // player might have are dropped
+ // VM_Call( sv.gvm, GAME_CLIENT_DISCONNECT, newcl - svs.clients );
+ goto gotnewcl;
+ }
+ }
+
+ // find a client slot
+ // if "sv_privateClients" is set > 0, then that number
+ // of client slots will be reserved for connections that
+ // have "password" set to the value of "sv_privatePassword"
+ // Info requests will report the maxclients as if the private
+ // slots didn't exist, to prevent people from trying to connect
+ // to a full server.
+ // This is to allow us to reserve a couple slots here on our
+ // servers so we can play without having to kick people.
+
+ // check for privateClient password
+ password = Info_ValueForKey( userinfo, "password" );
+ if ( *password && !strcmp( password, sv_privatePassword->string ) ) {
+ startIndex = 0;
+ } else {
+ // skip past the reserved slots
+ startIndex = sv_privateClients->integer;
+ }
+
+ newcl = NULL;
+ for ( i = startIndex; i < sv_maxclients->integer ; i++ ) {
+ cl = &svs.clients[i];
+ if (cl->state == CS_FREE) {
+ newcl = cl;
+ break;
+ }
+ }
+
+ if ( !newcl ) {
+ if ( NET_IsLocalAddress( from ) ) {
+ Com_Error( ERR_FATAL, "server is full on local connect" );
+ return;
+ }
+ else {
+ NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is full\n" );
+ Com_DPrintf ("Rejected a connection.\n");
+ return;
+ }
+ }
+
+ // we got a newcl, so reset the reliableSequence and reliableAcknowledge
+ cl->reliableAcknowledge = 0;
+ cl->reliableSequence = 0;
+
+gotnewcl:
+ // build a new connection
+ // accept the new client
+ // this is the only place a client_t is ever initialized
+ *newcl = temp;
+ clientNum = newcl - svs.clients;
+ ent = SV_GentityNum( clientNum );
+ newcl->gentity = ent;
+
+ Cvar_Set( va( "sv_clAltProto%i", clientNum ), ( version == 69 ? "2" : version == 70 ? "1" : "0" ) );
+
+ // save the challenge
+ newcl->challenge = challenge;
+
+ // save the address
+ Netchan_Setup((version == 69 ? 2 : version == 70 ? 1 : 0), NS_SERVER, &newcl->netchan, from, qport, challenge);
+ // init the netchan queue
+ newcl->netchan_end_queue = &newcl->netchan_start_queue;
+
+ // save the fingerprint
+ Q_strncpyz( newcl->fingerprint, fingerprint, sizeof(newcl->fingerprint) );
+
+ // save the userinfo
+ Q_strncpyz( newcl->userinfo, userinfo, sizeof(newcl->userinfo) );
+
+ // get the game a chance to reject this connection or modify the userinfo
+ denied = VM_Call( sv.gvm, GAME_CLIENT_CONNECT, clientNum, true ); // firstTime = true
+ if ( denied ) {
+ // we can't just use VM_ArgPtr, because that is only valid inside a VM_Call
+ char *str = (char*)VM_ExplicitArgPtr( sv.gvm, denied );
+
+ NET_OutOfBandPrint( NS_SERVER, from, "print\n%s\n", str );
+ Com_DPrintf ("Game rejected a connection: %s.\n", str);
+ return;
+ }
+
+ SV_UserinfoChanged( newcl );
+
+ // send the connect packet to the client
+ NET_OutOfBandPrint(NS_SERVER, from, "connectResponse %d", challenge);
+
+ Com_DPrintf( "Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name );
+
+ newcl->state = CS_CONNECTED;
+ newcl->lastSnapshotTime = 0;
+ newcl->lastPacketTime = svs.time;
+ newcl->lastConnectTime = svs.time;
+
+ // when we receive the first packet from the client, we will
+ // notice that it is from a different serverid and that the
+ // gamestate message was not just sent, forcing a retransmit
+ newcl->gamestateMessageNum = -1;
+
+ // if this was the first client on the server, or the last client
+ // the server can hold, send a heartbeat to the master.
+ count = 0;
+ for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
+ if ( svs.clients[i].state >= CS_CONNECTED )
+ count++;
+ }
+ if ( count == 1 || count == sv_maxclients->integer ) {
+ SV_Heartbeat_f();
+ }
+}
+
+/*
+=====================
+SV_FreeClient
+
+Destructor for data allocated in a client structure
+=====================
+*/
+void SV_FreeClient(client_t *client)
+{
+#ifdef USE_VOIP
+ int index;
+
+ for(index = client->queuedVoipIndex; index < client->queuedVoipPackets; index++)
+ {
+ index %= ARRAY_LEN(client->voipPacket);
+
+ Z_Free(client->voipPacket[index]);
+ }
+
+ client->queuedVoipPackets = 0;
+#endif
+
+ SV_Netchan_FreeQueue(client);
+ SV_CloseDownload(client);
+}
+
+/*
+=====================
+SV_DropClient
+
+Called when the player is totally leaving the server, either willingly
+or unwillingly. This is NOT called if the entire server is quiting
+or crashing -- SV_FinalMessage() will handle that
+=====================
+*/
+void SV_DropClient( client_t *drop, const char *reason ) {
+ int i;
+ challenge_t *challenge;
+
+ if ( drop->state == CS_ZOMBIE ) {
+ return; // already dropped
+ }
+
+ // see if we already have a challenge for this ip
+ challenge = &svs.challenges[0];
+
+ for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) {
+ if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) {
+ ::memset(challenge, 0, sizeof(*challenge));
+ break;
+ }
+ }
+
+ // Free all allocated data on the client structure
+ SV_FreeClient(drop);
+
+ // tell everyone why they got dropped
+ SV_SendServerCommand( NULL, "print \"%s" S_COLOR_WHITE " %s\n\"", drop->name, reason );
+
+ // call the prog function for removing a client
+ // this will remove the body, among other things
+ VM_Call( sv.gvm, GAME_CLIENT_DISCONNECT, drop - svs.clients );
+
+ // add the disconnect command
+ SV_SendServerCommand( drop, "disconnect \"%s\"", reason);
+
+ // nuke user info
+ SV_SetUserinfo( drop - svs.clients, "" );
+
+ Com_DPrintf( "Going to CS_ZOMBIE for %s\n", drop->name );
+ drop->state = CS_ZOMBIE; // become free in a few seconds
+
+ // if this was the last client on the server, send a heartbeat
+ // to the master so it is known the server is empty
+ // send a heartbeat now so the master will get up to date info
+ // if there is already a slot for this ip, reuse it
+ for (i=0 ; i < sv_maxclients->integer ; i++ ) {
+ if ( svs.clients[i].state >= CS_CONNECTED ) {
+ break;
+ }
+ }
+ if ( i == sv_maxclients->integer ) {
+ SV_Heartbeat_f();
+ }
+}
+
+extern char alternateInfos[2][2][BIG_INFO_STRING];
+
+/*
+================
+SV_SendClientGameState
+
+Sends the first message from the server to a connected client.
+This will be sent on the initial connection and upon each new map load.
+
+It will be resent if the client acknowledges a later message but has
+the wrong gamestate.
+================
+*/
+static void SV_SendClientGameState( client_t *client ) {
+ int start;
+ entityState_t *base, nullstate;
+ msg_t msg;
+ byte msgBuffer[MAX_MSGLEN];
+ const char *configstring;
+
+ Com_DPrintf ("SV_SendClientGameState() for %s\n", client->name);
+ Com_DPrintf( "Going from CS_CONNECTED to CS_PRIMED for %s\n", client->name );
+ client->state = CS_PRIMED;
+ client->pureAuthentic = 0;
+ client->gotCP = false;
+
+ // when we receive the first packet from the client, we will
+ // notice that it is from a different serverid and that the
+ // gamestate message was not just sent, forcing a retransmit
+ client->gamestateMessageNum = client->netchan.outgoingSequence;
+
+ MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) );
+
+ // NOTE, MRE: all server->client messages now acknowledge
+ // let the client know which reliable clientCommands we have received
+ MSG_WriteLong( &msg, client->lastClientCommand );
+
+ // send any server commands waiting to be sent first.
+ // we have to do this cause we send the client->reliableSequence
+ // with a gamestate and it sets the clc.serverCommandSequence at
+ // the client side
+ SV_UpdateServerCommandsToClient( client, &msg );
+
+ // send the gamestate
+ MSG_WriteByte( &msg, svc_gamestate );
+ MSG_WriteLong( &msg, client->reliableSequence );
+
+ // write the configstrings
+ for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) {
+ if ( start <= CS_SYSTEMINFO && client->netchan.alternateProtocol != 0 ) {
+ configstring = alternateInfos[start][ client->netchan.alternateProtocol - 1 ];
+ } else {
+ configstring = sv.configstrings[start].s;
+ }
+
+ if (configstring[0]) {
+ MSG_WriteByte( &msg, svc_configstring );
+ MSG_WriteShort( &msg, start );
+ MSG_WriteBigString( &msg, configstring );
+ }
+ }
+
+ // write the baselines
+ ::memset( &nullstate, 0, sizeof( nullstate ) );
+ for ( start = 0 ; start < MAX_GENTITIES; start++ ) {
+ base = &sv.svEntities[start].baseline;
+ if ( !base->number ) {
+ continue;
+ }
+ MSG_WriteByte( &msg, svc_baseline );
+ MSG_WriteDeltaEntity( client->netchan.alternateProtocol, &msg, &nullstate, base, true );
+ }
+
+ MSG_WriteByte( &msg, svc_EOF );
+
+ MSG_WriteLong( &msg, client - svs.clients);
+
+ // write the checksum feed
+ MSG_WriteLong( &msg, sv.checksumFeed);
+
+ // deliver this to the client
+ SV_SendMessageToClient( &msg, client );
+}
+
+
+/*
+==================
+SV_ClientEnterWorld
+==================
+*/
+void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) {
+ int clientNum;
+ sharedEntity_t *ent;
+
+ Com_DPrintf( "Going from CS_PRIMED to CS_ACTIVE for %s\n", client->name );
+ client->state = CS_ACTIVE;
+
+ // resend all configstrings using the cs commands since these are
+ // no longer sent when the client is CS_PRIMED
+ SV_UpdateConfigstrings( client );
+
+ // set up the entity for the client
+ clientNum = client - svs.clients;
+ ent = SV_GentityNum( clientNum );
+ ent->s.number = clientNum;
+ client->gentity = ent;
+
+ client->deltaMessage = -1;
+ client->lastSnapshotTime = 0; // generate a snapshot immediately
+
+ if(cmd)
+ memcpy(&client->lastUsercmd, cmd, sizeof(client->lastUsercmd));
+ else
+ memset(&client->lastUsercmd, '\0', sizeof(client->lastUsercmd));
+
+ // call the game begin function
+ VM_Call( sv.gvm, GAME_CLIENT_BEGIN, client - svs.clients );
+}
+
+/*
+============================================================
+
+CLIENT COMMAND EXECUTION
+
+============================================================
+*/
+
+/*
+==================
+SV_CloseDownload
+
+clear/free any download vars
+==================
+*/
+static void SV_CloseDownload( client_t *cl ) {
+ int i;
+
+ // EOF
+ if (cl->download) {
+ FS_FCloseFile( cl->download );
+ }
+ cl->download = 0;
+ *cl->downloadName = 0;
+
+ // Free the temporary buffer space
+ for (i = 0; i < MAX_DOWNLOAD_WINDOW; i++) {
+ if (cl->downloadBlocks[i]) {
+ Z_Free(cl->downloadBlocks[i]);
+ cl->downloadBlocks[i] = NULL;
+ }
+ }
+
+}
+
+/*
+==================
+SV_StopDownload_f
+
+Abort a download if in progress
+==================
+*/
+static void SV_StopDownload_f( client_t *cl ) {
+ if (*cl->downloadName)
+ Com_DPrintf( "clientDownload: %d : file \"%s\" aborted\n", (int) (cl - svs.clients), cl->downloadName );
+
+ SV_CloseDownload( cl );
+}
+
+/*
+==================
+SV_DoneDownload_f
+
+Downloads are finished
+==================
+*/
+static void SV_DoneDownload_f( client_t *cl ) {
+ if ( cl->state == CS_ACTIVE )
+ return;
+
+ Com_DPrintf( "clientDownload: %s Done\n", cl->name);
+ // resend the game state to update any clients that entered during the download
+ SV_SendClientGameState(cl);
+}
+
+/*
+==================
+SV_NextDownload_f
+
+The argument will be the last acknowledged block from the client, it should be
+the same as cl->downloadClientBlock
+==================
+*/
+static void SV_NextDownload_f( client_t *cl )
+{
+ int block = atoi( Cmd_Argv(1) );
+
+ if (block == cl->downloadClientBlock) {
+ Com_DPrintf( "clientDownload: %d : client acknowledge of block %d\n", (int) (cl - svs.clients), block );
+
+ // Find out if we are done. A zero-length block indicates EOF
+ if (cl->downloadBlockSize[cl->downloadClientBlock % MAX_DOWNLOAD_WINDOW] == 0) {
+ Com_Printf( "clientDownload: %d : file \"%s\" completed\n", (int) (cl - svs.clients), cl->downloadName );
+ SV_CloseDownload( cl );
+ return;
+ }
+
+ cl->downloadSendTime = svs.time;
+ cl->downloadClientBlock++;
+ return;
+ }
+ // We aren't getting an acknowledge for the correct block, drop the client
+ // FIXME: this is bad... the client will never parse the disconnect message
+ // because the cgame isn't loaded yet
+ SV_DropClient( cl, "broken download" );
+}
+
+/*
+==================
+SV_BeginDownload_f
+==================
+*/
+static void SV_BeginDownload_f( client_t *cl ) {
+
+ // Kill any existing download
+ SV_CloseDownload( cl );
+
+ // cl->downloadName is non-zero now, SV_WriteDownloadToClient will see this and open
+ // the file itself
+ Q_strncpyz( cl->downloadName, Cmd_Argv(1), sizeof(cl->downloadName) );
+}
+
+/*
+==================
+SV_WriteDownloadToClient
+
+Check to see if the client wants a file, open it if needed and start pumping the client
+Fill up msg with data, return number of download blocks added
+==================
+*/
+int SV_WriteDownloadToClient(client_t *cl, msg_t *msg)
+{
+ int curindex;
+ int unreferenced = 1;
+ char errorMessage[1024];
+ char pakbuf[MAX_QPATH], *pakptr;
+ int numRefPaks;
+
+ if (!*cl->downloadName)
+ return 0; // Nothing being downloaded
+
+ if(!cl->download)
+ {
+ // Chop off filename extension.
+ Com_sprintf(pakbuf, sizeof(pakbuf), "%s", cl->downloadName);
+ pakptr = strrchr(pakbuf, '.');
+
+ if(pakptr)
+ {
+ *pakptr = '\0';
+
+ // Check for pk3 filename extension
+ if(!Q_stricmp(pakptr + 1, "pk3"))
+ {
+ const char *referencedPaks = FS_ReferencedPakNames( cl->netchan.alternateProtocol == 2 );
+
+ // Check whether the file appears in the list of referenced
+ // paks to prevent downloading of arbitrary files.
+ Cmd_TokenizeStringIgnoreQuotes(referencedPaks);
+ numRefPaks = Cmd_Argc();
+
+ for(curindex = 0; curindex < numRefPaks; curindex++)
+ {
+ if(!FS_FilenameCompare(Cmd_Argv(curindex), pakbuf))
+ {
+ unreferenced = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ cl->download = 0;
+
+ // We open the file here
+ if ( !(sv_allowDownload->integer & DLF_ENABLE) ||
+ (sv_allowDownload->integer & DLF_NO_UDP) ||
+ unreferenced ||
+ ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) < 0 ) {
+ // cannot auto-download file
+ if(unreferenced)
+ {
+ Com_Printf("clientDownload: %d : \"%s\" is not referenced and cannot be downloaded.\n", (int) (cl - svs.clients), cl->downloadName);
+ Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" is not referenced and cannot be downloaded.", cl->downloadName);
+ }
+ else if ( !(sv_allowDownload->integer & DLF_ENABLE) ||
+ (sv_allowDownload->integer & DLF_NO_UDP) ) {
+
+ Com_Printf("clientDownload: %d : \"%s\" download disabled\n", (int) (cl - svs.clients), cl->downloadName);
+ if (sv_pure->integer) {
+ Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n"
+ "You will need to get this file elsewhere before you "
+ "can connect to this pure server.\n", cl->downloadName);
+ } else {
+ Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n"
+ "The server you are connecting to is not a pure server, "
+ "set autodownload to No in your settings and you might be "
+ "able to join the game anyway.\n", cl->downloadName);
+ }
+ } else {
+ // NOTE TTimo this is NOT supposed to happen unless bug in our filesystem scheme?
+ // if the pk3 is referenced, it must have been found somewhere in the filesystem
+ Com_Printf("clientDownload: %d : \"%s\" file not found on server\n", (int) (cl - svs.clients), cl->downloadName);
+ Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" not found on server for autodownloading.\n", cl->downloadName);
+ }
+ MSG_WriteByte( msg, svc_download );
+ MSG_WriteShort( msg, 0 ); // client is expecting block zero
+ MSG_WriteLong( msg, -1 ); // illegal file size
+ MSG_WriteString( msg, errorMessage );
+
+ *cl->downloadName = 0;
+
+ if(cl->download)
+ FS_FCloseFile(cl->download);
+
+ return 1;
+ }
+
+ Com_Printf( "clientDownload: %d : beginning \"%s\"\n", (int) (cl - svs.clients), cl->downloadName );
+
+ // Init
+ cl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0;
+ cl->downloadCount = 0;
+ cl->downloadEOF = false;
+ }
+
+ // Perform any reads that we need to
+ while (cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW &&
+ cl->downloadSize != cl->downloadCount) {
+
+ curindex = (cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW);
+
+ if (!cl->downloadBlocks[curindex])
+ cl->downloadBlocks[curindex] = (unsigned char*)Z_Malloc(MAX_DOWNLOAD_BLKSIZE);
+
+ cl->downloadBlockSize[curindex] = FS_Read( cl->downloadBlocks[curindex], MAX_DOWNLOAD_BLKSIZE, cl->download );
+
+ if (cl->downloadBlockSize[curindex] < 0) {
+ // EOF right now
+ cl->downloadCount = cl->downloadSize;
+ break;
+ }
+
+ cl->downloadCount += cl->downloadBlockSize[curindex];
+
+ // Load in next block
+ cl->downloadCurrentBlock++;
+ }
+
+ // Check to see if we have eof condition and add the EOF block
+ if (cl->downloadCount == cl->downloadSize
+ && !cl->downloadEOF
+ && cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW)
+ {
+ cl->downloadBlockSize[cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW] = 0;
+ cl->downloadCurrentBlock++;
+
+ cl->downloadEOF = true; // We have added the EOF block
+ }
+
+ if (cl->downloadClientBlock == cl->downloadCurrentBlock)
+ return 0; // Nothing to transmit
+
+ // Write out the next section of the file, if we have already reached our window,
+ // automatically start retransmitting
+ if (cl->downloadXmitBlock == cl->downloadCurrentBlock)
+ {
+ // We have transmitted the complete window, should we start resending?
+ if (svs.time - cl->downloadSendTime > 1000)
+ cl->downloadXmitBlock = cl->downloadClientBlock;
+ else
+ return 0;
+ }
+
+ // Send current block
+ curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW);
+
+ MSG_WriteByte( msg, svc_download );
+ MSG_WriteShort( msg, cl->downloadXmitBlock );
+
+ // block zero is special, contains file size
+ if ( cl->downloadXmitBlock == 0 )
+ MSG_WriteLong( msg, cl->downloadSize );
+
+ MSG_WriteShort( msg, cl->downloadBlockSize[curindex] );
+
+ // Write the block
+ if(cl->downloadBlockSize[curindex])
+ MSG_WriteData(msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex]);
+
+ Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock );
+
+ // Move on to the next block
+ // It will get sent with next snap shot. The rate will keep us in line.
+ cl->downloadXmitBlock++;
+ cl->downloadSendTime = svs.time;
+
+ return 1;
+}
+
+/*
+==================
+SV_SendQueuedMessages
+
+Send one round of fragments, or queued messages to all clients that have data pending.
+Return the shortest time interval for sending next packet to client
+==================
+*/
+
+int SV_SendQueuedMessages(void)
+{
+ int i, retval = -1, nextFragT;
+ client_t *cl;
+
+ for(i=0; i < sv_maxclients->integer; i++)
+ {
+ cl = &svs.clients[i];
+
+ if(cl->state)
+ {
+ nextFragT = SV_RateMsec(cl);
+
+ if(!nextFragT)
+ nextFragT = SV_Netchan_TransmitNextFragment(cl);
+
+ if(nextFragT >= 0 && (retval == -1 || retval > nextFragT))
+ retval = nextFragT;
+ }
+ }
+
+ return retval;
+}
+
+
+/*
+==================
+SV_SendDownloadMessages
+
+Send one round of download messages to all clients
+==================
+*/
+
+int SV_SendDownloadMessages(void)
+{
+ int i, numDLs = 0, retval;
+ client_t *cl;
+ msg_t msg;
+ byte msgBuffer[MAX_MSGLEN];
+
+ for(i=0; i < sv_maxclients->integer; i++)
+ {
+ cl = &svs.clients[i];
+
+ if(cl->state && *cl->downloadName)
+ {
+ MSG_Init(&msg, msgBuffer, sizeof(msgBuffer));
+ MSG_WriteLong(&msg, cl->lastClientCommand);
+
+ retval = SV_WriteDownloadToClient(cl, &msg);
+
+ if(retval)
+ {
+ MSG_WriteByte(&msg, svc_EOF);
+ SV_Netchan_Transmit(cl, &msg);
+ numDLs += retval;
+ }
+ }
+ }
+
+ return numDLs;
+}
+
+/*
+=================
+SV_Disconnect_f
+
+The client is going to disconnect, so remove the connection immediately FIXME: move to game?
+=================
+*/
+static void SV_Disconnect_f( client_t *cl ) {
+ SV_DropClient( cl, "disconnected" );
+}
+
+/*
+=================
+SV_VerifyPaks_f
+
+If we are pure, disconnect the client if they do no meet the following conditions:
+
+1. the first two checksums match our view of cgame and ui
+2. there are no any additional checksums that we do not have
+
+This routine would be a bit simpler with a goto but i abstained
+
+=================
+*/
+static void SV_VerifyPaks_f( client_t *cl ) {
+ int nChkSum1, nChkSum2, nClientPaks, nServerPaks, i, j, nCurArg;
+ int nClientChkSum[1024];
+ int nServerChkSum[1024];
+ const char *pPaks, *pArg;
+ bool bGood = true;
+
+ // if we are pure, we "expect" the client to load certain things from
+ // certain pk3 files, namely we want the client to have loaded the
+ // ui and cgame that we think should be loaded based on the pure setting
+ //
+ if ( sv_pure->integer != 0 ) {
+
+ nChkSum1 = nChkSum2 = 0;
+ // we run the game, so determine which cgame and ui the client "should" be running
+ bGood = (FS_FileIsInPAK_A((cl->netchan.alternateProtocol == 2), "vm/cgame.qvm", &nChkSum1) == 1);
+ if (bGood)
+ bGood = (FS_FileIsInPAK_A((cl->netchan.alternateProtocol == 2), "vm/ui.qvm", &nChkSum2) == 1);
+
+ nClientPaks = Cmd_Argc();
+
+ // start at arg 2 ( skip serverId cl_paks )
+ nCurArg = 1;
+
+ pArg = Cmd_Argv(nCurArg++);
+ if(!pArg) {
+ bGood = false;
+ }
+ else
+ {
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
+ // we may get incoming cp sequences from a previous checksumFeed, which we need to ignore
+ // since serverId is a frame count, it always goes up
+ if (atoi(pArg) < sv.checksumFeedServerId)
+ {
+ Com_DPrintf("ignoring outdated cp command from client %s\n", cl->name);
+ return;
+ }
+ }
+
+ // we basically use this while loop to avoid using 'goto' :)
+ while (bGood) {
+
+ // must be at least 6: "cl_paks cgame ui @ firstref ... numChecksums"
+ // numChecksums is encoded
+ if (nClientPaks < 6) {
+ bGood = false;
+ break;
+ }
+ // verify first to be the cgame checksum
+ pArg = Cmd_Argv(nCurArg++);
+ if (!pArg || *pArg == '@' || atoi(pArg) != nChkSum1 ) {
+ bGood = false;
+ break;
+ }
+ // verify the second to be the ui checksum
+ pArg = Cmd_Argv(nCurArg++);
+ if (!pArg || *pArg == '@' || atoi(pArg) != nChkSum2 ) {
+ bGood = false;
+ break;
+ }
+ // should be sitting at the delimeter now
+ pArg = Cmd_Argv(nCurArg++);
+ if (*pArg != '@') {
+ bGood = false;
+ break;
+ }
+ // store checksums since tokenization is not re-entrant
+ for (i = 0; nCurArg < nClientPaks; i++) {
+ nClientChkSum[i] = atoi(Cmd_Argv(nCurArg++));
+ }
+
+ // store number to compare against (minus one cause the last is the number of checksums)
+ nClientPaks = i - 1;
+
+ // make sure none of the client check sums are the same
+ // so the client can't send 5 the same checksums
+ for (i = 0; i < nClientPaks; i++) {
+ for (j = 0; j < nClientPaks; j++) {
+ if (i == j)
+ continue;
+ if (nClientChkSum[i] == nClientChkSum[j]) {
+ bGood = false;
+ break;
+ }
+ }
+ if (bGood == false)
+ break;
+ }
+ if (bGood == false)
+ break;
+
+ // get the pure checksums of the pk3 files loaded by the server
+ pPaks = FS_LoadedPakPureChecksums(cl->netchan.alternateProtocol == 2);
+ Cmd_TokenizeString( pPaks );
+ nServerPaks = Cmd_Argc();
+ if (nServerPaks > 1024)
+ nServerPaks = 1024;
+
+ for (i = 0; i < nServerPaks; i++) {
+ nServerChkSum[i] = atoi(Cmd_Argv(i));
+ }
+
+ // check if the client has provided any pure checksums of pk3 files not loaded by the server
+ for (i = 0; i < nClientPaks; i++) {
+ for (j = 0; j < nServerPaks; j++) {
+ if (nClientChkSum[i] == nServerChkSum[j]) {
+ break;
+ }
+ }
+ if (j >= nServerPaks) {
+ bGood = false;
+ break;
+ }
+ }
+ if ( bGood == false ) {
+ break;
+ }
+
+ // check if the number of checksums was correct
+ nChkSum1 = sv.checksumFeed;
+ for (i = 0; i < nClientPaks; i++) {
+ nChkSum1 ^= nClientChkSum[i];
+ }
+ nChkSum1 ^= nClientPaks;
+ if (nChkSum1 != nClientChkSum[nClientPaks]) {
+ bGood = false;
+ break;
+ }
+
+ // break out
+ break;
+ }
+
+ cl->gotCP = true;
+
+ if (bGood) {
+ cl->pureAuthentic = 1;
+ }
+ else {
+ cl->pureAuthentic = 0;
+ cl->lastSnapshotTime = 0;
+ cl->state = CS_ACTIVE;
+ SV_SendClientSnapshot( cl );
+ SV_SendServerCommand( cl, "disconnect \"Unpure Client. "
+ "You may need to enable in-game downloads "
+ "to connect to this server (set "
+ "cl_allowDownload 1)\"" );
+ SV_DropClient( cl, "Unpure client detected. Invalid .PK3 files referenced!" );
+ }
+ }
+}
+
+/*
+=================
+SV_ResetPureClient_f
+=================
+*/
+static void SV_ResetPureClient_f( client_t *cl ) {
+ cl->pureAuthentic = 0;
+ cl->gotCP = false;
+}
+
+/*
+=================
+SV_UserinfoChanged
+
+Pull specific info from a newly changed userinfo string
+into a more C friendly form.
+=================
+*/
+void SV_UserinfoChanged( client_t *cl ) {
+ char *val;
+ const char *ip;
+ int i;
+ int len;
+
+ // name for C code
+ Q_strncpyz( cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name) );
+
+ // rate command
+
+ // if the client is on the same subnet as the server and we aren't running an
+ // internet public server, assume they don't need a rate choke
+ if ( Sys_IsLANAddress( cl->netchan.remoteAddress ) && com_dedicated->integer != 2 && sv_lanForceRate->integer == 1) {
+ cl->rate = 99999; // lans should not rate limit
+ } else {
+ val = Info_ValueForKey (cl->userinfo, "rate");
+ if (strlen(val)) {
+ i = atoi(val);
+ cl->rate = i;
+ if (cl->rate < 1000) {
+ cl->rate = 1000;
+ } else if (cl->rate > 90000) {
+ cl->rate = 90000;
+ }
+ } else {
+ cl->rate = 3000;
+ }
+ }
+ val = Info_ValueForKey (cl->userinfo, "handicap");
+ if (strlen(val)) {
+ i = atoi(val);
+ if (i<=0 || i>100 || strlen(val) > 4) {
+ Info_SetValueForKey( cl->userinfo, "handicap", "100" );
+ }
+ }
+
+ // snaps command
+ val = Info_ValueForKey (cl->userinfo, "snaps");
+
+ if(strlen(val))
+ {
+ i = atoi(val);
+
+ if(i < 1)
+ i = 1;
+ else if(i > sv_fps->integer)
+ i = sv_fps->integer;
+
+ i = 1000 / i;
+ }
+ else
+ i = 50;
+
+ if(i != cl->snapshotMsec)
+ {
+ // Reset last sent snapshot so we avoid desync between server frame time and snapshot send time
+ cl->lastSnapshotTime = 0;
+ cl->snapshotMsec = i;
+ }
+
+#ifdef USE_VOIP
+ val = Info_ValueForKey(cl->userinfo, "cl_voipProtocol");
+ cl->hasVoip = !Q_stricmp( val, "opus" );
+#endif
+
+ // TTimo
+ // maintain the IP information
+ // the banning code relies on this being consistently present
+ if( NET_IsLocalAddress(cl->netchan.remoteAddress) )
+ ip = "localhost";
+ else
+ ip = (char*)NET_AdrToString( cl->netchan.remoteAddress );
+
+ val = Info_ValueForKey( cl->userinfo, "ip" );
+ if( val[0] )
+ len = strlen( ip ) - strlen( val ) + strlen( cl->userinfo );
+ else
+ len = strlen( ip ) + 4 + strlen( cl->userinfo );
+
+ if( len >= MAX_INFO_STRING )
+ SV_DropClient( cl, "userinfo string length exceeded" );
+ else
+ Info_SetValueForKey( cl->userinfo, "ip", ip );
+
+ val = Info_ValueForKey( cl->userinfo, "fingerprint" );
+ if( val[0] )
+ len = strlen(cl->fingerprint) - strlen(val) + strlen(cl->userinfo);
+ else
+ len = strlen(cl->fingerprint) + 13 + strlen(cl->userinfo);
+
+ if( len >= MAX_INFO_STRING )
+ SV_DropClient( cl, "userinfo string length exceeded" );
+ else
+ Info_SetValueForKey( cl->userinfo, "fingerprint", cl->fingerprint );
+}
+
+
+/*
+==================
+SV_UpdateUserinfo_f
+==================
+*/
+static void SV_UpdateUserinfo_f( client_t *cl ) {
+ Q_strncpyz( cl->userinfo, Cmd_Argv(1), sizeof(cl->userinfo) );
+
+ SV_UserinfoChanged( cl );
+ // call prog code to allow overrides
+ VM_Call( sv.gvm, GAME_CLIENT_USERINFO_CHANGED, cl - svs.clients );
+}
+
+
+#ifdef USE_VOIP
+static void SV_UpdateVoipIgnore(client_t *cl, const char *idstr, bool ignore)
+{
+ if ((*idstr >= '0') && (*idstr <= '9')) {
+ const int id = atoi(idstr);
+ if ((id >= 0) && (id < MAX_CLIENTS)) {
+ cl->ignoreVoipFromClient[id] = ignore;
+ }
+ }
+}
+
+/*
+==================
+SV_Voip_f
+==================
+*/
+static void SV_Voip_f( client_t *cl )
+{
+ const char *cmd = Cmd_Argv(1);
+ if (strcmp(cmd, "ignore") == 0) {
+ SV_UpdateVoipIgnore(cl, Cmd_Argv(2), true);
+ } else if (strcmp(cmd, "unignore") == 0) {
+ SV_UpdateVoipIgnore(cl, Cmd_Argv(2), false);
+ } else if (strcmp(cmd, "muteall") == 0) {
+ cl->muteAllVoip = true;
+ } else if (strcmp(cmd, "unmuteall") == 0) {
+ cl->muteAllVoip = false;
+ }
+}
+#endif
+
+
+typedef struct {
+ const char *name;
+ void (*func)( client_t *cl );
+} ucmd_t;
+
+static ucmd_t ucmds[] = {
+ {"userinfo", SV_UpdateUserinfo_f},
+ {"disconnect", SV_Disconnect_f},
+ {"cp", SV_VerifyPaks_f},
+ {"vdr", SV_ResetPureClient_f},
+ {"download", SV_BeginDownload_f},
+ {"nextdl", SV_NextDownload_f},
+ {"stopdl", SV_StopDownload_f},
+ {"donedl", SV_DoneDownload_f},
+
+#ifdef USE_VOIP
+ {"voip", SV_Voip_f},
+#endif
+
+ {NULL, NULL}
+};
+
+/*
+==================
+SV_ExecuteClientCommand
+
+Also called by bot code
+==================
+*/
+void SV_ExecuteClientCommand( client_t *cl, const char *s, bool clientOK ) {
+ ucmd_t *u;
+ bool bProcessed = false;
+
+ Cmd_TokenizeString( s );
+
+ // see if it is a server level command
+ for (u=ucmds ; u->name ; u++) {
+ if (!strcmp (Cmd_Argv(0), u->name) ) {
+ u->func( cl );
+ bProcessed = true;
+ break;
+ }
+ }
+
+ if (clientOK) {
+ // pass unknown strings to the game
+ if (!u->name && sv.state == SS_GAME && (cl->state == CS_ACTIVE || cl->state == CS_PRIMED)) {
+ VM_Call( sv.gvm, GAME_CLIENT_COMMAND, cl - svs.clients );
+ }
+ }
+ else if (!bProcessed)
+ Com_DPrintf( "client text ignored for %s: %s\n", cl->name, Cmd_Argv(0) );
+}
+
+/*
+===============
+SV_ClientCommand
+===============
+*/
+static bool SV_ClientCommand( client_t *cl, msg_t *msg ) {
+ int seq;
+ const char *s;
+ bool clientOk = true;
+
+ seq = MSG_ReadLong( msg );
+ s = MSG_ReadString( msg );
+
+ // see if we have already executed it
+ if ( cl->lastClientCommand >= seq ) {
+ return true;
+ }
+
+ Com_DPrintf( "clientCommand: %s : %i : %s\n", cl->name, seq, s );
+
+ // drop the connection if we have somehow lost commands
+ if ( seq > cl->lastClientCommand + 1 ) {
+ Com_Printf( "Client %s lost %i clientCommands\n", cl->name,
+ seq - cl->lastClientCommand + 1 );
+ SV_DropClient( cl, "Lost reliable commands" );
+ return false;
+ }
+
+ // malicious users may try using too many string commands
+ // to lag other players. If we decide that we want to stall
+ // the command, we will stop processing the rest of the packet,
+ // including the usercmd. This causes flooders to lag themselves
+ // but not other people
+ // We don't do this when the client hasn't been active yet since it's
+ // normal to spam a lot of commands when downloading
+#if 0 // flood protection in game for trem
+ if ( !com_cl_running->integer &&
+ cl->state >= CS_ACTIVE &&
+ sv_floodProtect->integer &&
+ svs.time < cl->nextReliableTime ) {
+ // ignore any other text messages from this client but let them keep playing
+ // TTimo - moved the ignored verbose to the actual processing in SV_ExecuteClientCommand, only printing if the core doesn't intercept
+ clientOk = false;
+ }
+#endif
+
+ // don't allow another command for one second
+ cl->nextReliableTime = svs.time + 1000;
+
+ SV_ExecuteClientCommand( cl, s, clientOk );
+
+ cl->lastClientCommand = seq;
+ Com_sprintf(cl->lastClientCommandString, sizeof(cl->lastClientCommandString), "%s", s);
+
+ return true; // continue procesing
+}
+
+
+//==================================================================================
+
+
+/*
+==================
+SV_ClientThink
+
+Also called by bot code
+==================
+*/
+void SV_ClientThink (client_t *cl, usercmd_t *cmd) {
+ cl->lastUsercmd = *cmd;
+
+ if ( cl->state != CS_ACTIVE ) {
+ return; // may have been kicked during the last usercmd
+ }
+
+ VM_Call( sv.gvm, GAME_CLIENT_THINK, cl - svs.clients );
+}
+
+/*
+==================
+SV_UserMove
+
+The message usually contains all the movement commands
+that were in the last three packets, so that the information
+in dropped packets can be recovered.
+
+On very fast clients, there may be multiple usercmd packed into
+each of the backup packets.
+==================
+*/
+static void SV_UserMove( client_t *cl, msg_t *msg, bool delta ) {
+ int i, key;
+ int cmdCount;
+ usercmd_t nullcmd;
+ usercmd_t cmds[MAX_PACKET_USERCMDS];
+ usercmd_t *cmd, *oldcmd;
+
+ if ( delta ) {
+ cl->deltaMessage = cl->messageAcknowledge;
+ } else {
+ cl->deltaMessage = -1;
+ }
+
+ cmdCount = MSG_ReadByte( msg );
+
+ if ( cmdCount < 1 ) {
+ Com_Printf( "cmdCount < 1\n" );
+ return;
+ }
+
+ if ( cmdCount > MAX_PACKET_USERCMDS ) {
+ Com_Printf( "cmdCount > MAX_PACKET_USERCMDS\n" );
+ return;
+ }
+
+ // use the checksum feed in the key
+ key = sv.checksumFeed;
+ // also use the message acknowledge
+ key ^= cl->messageAcknowledge;
+ // also use the last acknowledged server command in the key
+ key ^= MSG_HashKey(cl->netchan.alternateProtocol, cl->reliableCommands[ cl->reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ], 32);
+
+ ::memset( &nullcmd, 0, sizeof(nullcmd) );
+ oldcmd = &nullcmd;
+ for ( i = 0 ; i < cmdCount ; i++ ) {
+ cmd = &cmds[i];
+ MSG_ReadDeltaUsercmdKey( msg, key, oldcmd, cmd );
+ oldcmd = cmd;
+ }
+
+ // save time for ping calculation
+ cl->frames[ cl->messageAcknowledge & PACKET_MASK ].messageAcked = svs.time;
+
+ // TTimo
+ // catch the no-cp-yet situation before SV_ClientEnterWorld
+ // if CS_ACTIVE, then it's time to trigger a new gamestate emission
+ // if not, then we are getting remaining parasite usermove commands, which we should ignore
+ if (sv_pure->integer != 0 && cl->pureAuthentic == 0 && !cl->gotCP) {
+ if (cl->state == CS_ACTIVE)
+ {
+ // we didn't get a cp yet, don't assume anything and just send the gamestate all over again
+ Com_DPrintf( "%s: didn't get cp command, resending gamestate\n", cl->name);
+ SV_SendClientGameState( cl );
+ }
+ return;
+ }
+
+ // if this is the first usercmd we have received
+ // this gamestate, put the client into the world
+ if ( cl->state == CS_PRIMED ) {
+ SV_ClientEnterWorld( cl, &cmds[0] );
+ // the moves can be processed normaly
+ }
+
+ // a bad cp command was sent, drop the client
+ if (sv_pure->integer != 0 && cl->pureAuthentic == 0) {
+ SV_DropClient( cl, "Cannot validate pure client!");
+ return;
+ }
+
+ if ( cl->state != CS_ACTIVE ) {
+ cl->deltaMessage = -1;
+ return;
+ }
+
+ // usually, the first couple commands will be duplicates
+ // of ones we have previously received, but the servertimes
+ // in the commands will cause them to be immediately discarded
+ for ( i = 0 ; i < cmdCount ; i++ ) {
+ // if this is a cmd from before a map_restart ignore it
+ if ( cmds[i].serverTime > cmds[cmdCount-1].serverTime ) {
+ continue;
+ }
+ // extremely lagged or cmd from before a map_restart
+ //if ( cmds[i].serverTime > svs.time + 3000 ) {
+ // continue;
+ //}
+ // don't execute if this is an old cmd which is already executed
+ // these old cmds are included when cl_packetdup > 0
+ if ( cmds[i].serverTime <= cl->lastUsercmd.serverTime ) {
+ continue;
+ }
+ SV_ClientThink (cl, &cmds[ i ]);
+ }
+}
+
+
+#ifdef USE_VOIP
+/*
+==================
+SV_ShouldIgnoreVoipSender
+
+Blocking of voip packets based on source client
+==================
+*/
+
+static bool SV_ShouldIgnoreVoipSender(const client_t *cl)
+{
+ if (!sv_voip->integer)
+ return true; // VoIP disabled on this server.
+ else if (!cl->hasVoip) // client doesn't have VoIP support?!
+ return true;
+
+ // !!! FIXME: implement player blacklist.
+
+ return false; // don't ignore.
+}
+
+static void SV_UserVoip(client_t *cl, msg_t *msg, bool ignoreData)
+{
+ int sender, generation, sequence, frames;
+ uint8_t recips[(MAX_CLIENTS + 7) / 8];
+ int recip1 = 0, recip2 = 0, recip3 = 0; // silence warning
+ int flags = 0;
+ byte encoded[sizeof(cl->voipPacket[0]->data)];
+ client_t *client = NULL;
+ voipServerPacket_t *packet = NULL;
+ int i;
+
+ sender = cl - svs.clients;
+ generation = MSG_ReadByte(msg);
+ sequence = MSG_ReadLong(msg);
+ frames = MSG_ReadByte(msg);
+ if (cl->netchan.alternateProtocol == 0) {
+ MSG_ReadData(msg, recips, sizeof(recips));
+ flags = MSG_ReadByte(msg);
+ } else {
+ recip1 = MSG_ReadLong(msg);
+ recip2 = MSG_ReadLong(msg);
+ recip3 = MSG_ReadLong(msg);
+ }
+ size_t packetsize = MSG_ReadShort(msg);
+
+ if (msg->readcount > msg->cursize)
+ return; // short/invalid packet, bail.
+
+ if (packetsize > sizeof(encoded)) { // overlarge packet?
+ size_t bytesleft = packetsize;
+ while (bytesleft) {
+ size_t br = bytesleft;
+ if (br > sizeof(encoded))
+ br = sizeof(encoded);
+ MSG_ReadData(msg, encoded, br);
+ bytesleft -= br;
+ }
+ return; // overlarge packet, bail.
+ }
+
+ MSG_ReadData(msg, encoded, packetsize);
+
+ if (ignoreData || SV_ShouldIgnoreVoipSender(cl))
+ return; // Blacklisted, disabled, etc.
+
+ // !!! FIXME: see if we read past end of msg...
+
+ // !!! FIXME: reject if not opus data.
+ // !!! FIXME: decide if this is bogus data?
+
+ // decide who needs this VoIP packet sent to them...
+ for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {
+ if (client->state != CS_ACTIVE)
+ continue; // not in the game yet, don't send to this guy.
+ else if (i == sender)
+ continue; // don't send voice packet back to original author.
+ else if (!client->hasVoip)
+ continue; // no VoIP support, or unsupported protocol
+ else if (client->muteAllVoip)
+ continue; // client is ignoring everyone.
+ else if (client->ignoreVoipFromClient[sender])
+ continue; // client is ignoring this talker.
+ else if (*cl->downloadName) // !!! FIXME: possible to DoS?
+ continue; // no VoIP allowed if downloading, to save bandwidth.
+
+ if (cl->netchan.alternateProtocol == 0) {
+ if(Com_IsVoipTarget(recips, sizeof(recips), i))
+ flags |= VOIP_DIRECT;
+ else
+ flags &= ~VOIP_DIRECT;
+ } else {
+ if (i < 31 && (recip1 & (1 << (i - 0))) == 0)
+ continue; // not addressed to this player.
+ else if (i >= 31 && i < 62 && (recip2 & (1 << (i - 31))) == 0)
+ continue; // not addressed to this player.
+ else if (i >= 62 && (recip3 & (1 << (i - 62))) == 0)
+ continue; // not addressed to this player.
+
+ flags |= VOIP_DIRECT;
+ }
+
+ if (!(flags & (VOIP_SPATIAL | VOIP_DIRECT)))
+ continue; // not addressed to this player.
+
+ // Transmit this packet to the client.
+ if (client->queuedVoipPackets >= ARRAY_LEN(client->voipPacket)) {
+ Com_Printf("Too many VoIP packets queued for client #%d\n", i);
+ continue; // no room for another packet right now.
+ }
+
+ packet = (voipServerPacket_t*)Z_Malloc(sizeof(*packet));
+ packet->sender = sender;
+ packet->frames = frames;
+ packet->len = packetsize;
+ packet->generation = generation;
+ packet->sequence = sequence;
+ packet->flags = flags;
+ memcpy(packet->data, encoded, packetsize);
+
+ client->voipPacket[(client->queuedVoipIndex + client->queuedVoipPackets) % ARRAY_LEN(client->voipPacket)] = packet;
+ client->queuedVoipPackets++;
+ }
+}
+#endif
+
+
+
+/*
+===========================================================================
+
+USER CMD EXECUTION
+
+===========================================================================
+*/
+
+/*
+===================
+SV_ExecuteClientMessage
+
+Parse a client packet
+===================
+*/
+void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
+ int c;
+ int serverId;
+
+ MSG_Bitstream(msg);
+
+ serverId = MSG_ReadLong( msg );
+ cl->messageAcknowledge = MSG_ReadLong( msg );
+
+ if (cl->messageAcknowledge < 0) {
+ // usually only hackers create messages like this
+ // it is more annoying for them to let them hanging
+#ifndef NDEBUG
+ SV_DropClient( cl, "DEBUG: illegible client message" );
+#endif
+ return;
+ }
+
+ cl->reliableAcknowledge = MSG_ReadLong( msg );
+
+ // NOTE: when the client message is fux0red the acknowledgement numbers
+ // can be out of range, this could cause the server to send thousands of server
+ // commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient
+ if (cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS) {
+ // usually only hackers create messages like this
+ // it is more annoying for them to let them hanging
+#ifndef NDEBUG
+ SV_DropClient( cl, "DEBUG: illegible client message" );
+#endif
+ cl->reliableAcknowledge = cl->reliableSequence;
+ return;
+ }
+ // if this is a usercmd from a previous gamestate,
+ // ignore it or retransmit the current gamestate
+ //
+ // if the client was downloading, let it stay at whatever serverId and
+ // gamestate it was at. This allows it to keep downloading even when
+ // the gamestate changes. After the download is finished, we'll
+ // notice and send it a new game state
+ //
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=536
+ // don't drop as long as previous command was a nextdl, after a dl is done, downloadName is set back to ""
+ // but we still need to read the next message to move to next download or send gamestate
+ // I don't like this hack though, it must have been working fine at some point, suspecting the fix is somewhere else
+ if ( serverId != sv.serverId && !*cl->downloadName && !strstr(cl->lastClientCommandString, "nextdl") ) {
+ if ( serverId >= sv.restartedServerId && serverId < sv.serverId ) { // TTimo - use a comparison here to catch multiple map_restart
+ // they just haven't caught the map_restart yet
+ Com_DPrintf("%s : ignoring pre map_restart / outdated client message\n", cl->name);
+ return;
+ }
+ // if we can tell that the client has dropped the last
+ // gamestate we sent them, resend it
+ if ( cl->messageAcknowledge > cl->gamestateMessageNum ) {
+ Com_DPrintf( "%s : dropped gamestate, resending\n", cl->name );
+ SV_SendClientGameState( cl );
+ }
+ return;
+ }
+
+ // this client has acknowledged the new gamestate so it's
+ // safe to start sending it the real time again
+ if( cl->oldServerTime && serverId == sv.serverId ){
+ Com_DPrintf( "%s acknowledged gamestate\n", cl->name );
+ cl->oldServerTime = 0;
+ }
+
+ // read optional clientCommand strings
+ do {
+ c = MSG_ReadByte( msg );
+
+ if ( cl->netchan.alternateProtocol != 0 ) {
+ // See if this is an extension command after the EOF, which means we
+ // got data that a legacy server should ignore.
+ if ( c == clc_EOF && MSG_LookaheadByte( msg ) == clc_voipSpeex ) {
+ MSG_ReadByte( msg ); // throw the clc_extension byte away.
+ c = MSG_ReadByte( msg ); // something legacy servers can't do!
+ if ( c == clc_voipSpeex + 1 ) {
+ c = clc_voipSpeex;
+ }
+ // sometimes you get a clc_extension at end of stream...dangling
+ // bits in the huffman decoder giving a bogus value?
+ if ( c == -1 ) {
+ c = clc_EOF;
+ }
+ }
+
+ if ( c == svc_voipSpeex ) {
+ c = svc_voipSpeex + 1;
+ } else if ( c == svc_voipSpeex + 1 ) {
+ c = svc_voipSpeex;
+ }
+ }
+
+ if ( c == clc_EOF ) {
+ break;
+ }
+
+ if ( c != clc_clientCommand ) {
+ break;
+ }
+ if ( !SV_ClientCommand( cl, msg ) ) {
+ return; // we couldn't execute it because of the flood protection
+ }
+ if (cl->state == CS_ZOMBIE) {
+ return; // disconnect command
+ }
+ } while ( 1 );
+
+ // skip legacy speex voip data
+ if ( c == clc_voipSpeex ) {
+#ifdef USE_VOIP
+ SV_UserVoip( cl, msg, true );
+ c = MSG_ReadByte( msg );
+#endif
+ }
+
+ // read optional voip data
+ if ( c == clc_voipOpus ) {
+#ifdef USE_VOIP
+ SV_UserVoip( cl, msg, false );
+ c = MSG_ReadByte( msg );
+#endif
+ }
+
+ // read the usercmd_t
+ if ( c == clc_move ) {
+ SV_UserMove( cl, msg, true );
+ } else if ( c == clc_moveNoDelta ) {
+ SV_UserMove( cl, msg, false );
+ } else if ( c != clc_EOF ) {
+ Com_Printf( "WARNING: bad command byte for client %i\n", (int) (cl - svs.clients) );
+ }
+// if ( msg->readcount != msg->cursize ) {
+// Com_Printf( "WARNING: Junk at end of packet for client %i\n", cl - svs.clients );
+// }
+}
diff --git a/src/server/sv_game.cpp b/src/server/sv_game.cpp
new file mode 100644
index 0000000..23e5212
--- /dev/null
+++ b/src/server/sv_game.cpp
@@ -0,0 +1,602 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+// sv_game.c -- interface to the game dll
+
+#include "server.h"
+
+// these functions must be used instead of pointer arithmetic, because
+// the game allocates gentities with private information after the server shared part
+int SV_NumForGentity( sharedEntity_t *ent ) {
+ int num;
+
+ num = ( (byte *)ent - (byte *)sv.gentities ) / sv.gentitySize;
+
+ return num;
+}
+
+sharedEntity_t *SV_GentityNum( int num ) {
+ sharedEntity_t *ent;
+
+ ent = (sharedEntity_t *)((byte *)sv.gentities + sv.gentitySize*(num));
+
+ return ent;
+}
+
+playerState_t *SV_GameClientNum( int num ) {
+ playerState_t *ps;
+
+ ps = (playerState_t *)((byte *)sv.gameClients + sv.gameClientSize*(num));
+
+ return ps;
+}
+
+svEntity_t *SV_SvEntityForGentity( sharedEntity_t *gEnt ) {
+ if ( !gEnt || gEnt->s.number < 0 || gEnt->s.number >= MAX_GENTITIES ) {
+ Com_Error( ERR_DROP, "SV_SvEntityForGentity: bad gEnt" );
+ }
+ return &sv.svEntities[ gEnt->s.number ];
+}
+
+sharedEntity_t *SV_GEntityForSvEntity( svEntity_t *svEnt ) {
+ int num;
+
+ num = svEnt - sv.svEntities;
+ return SV_GentityNum( num );
+}
+
+/*
+===============
+SV_GameSendServerCommand
+
+Sends a command string to a client
+===============
+*/
+void SV_GameSendServerCommand( int clientNum, const char *text ) {
+ if ( clientNum == -1 ) {
+ SV_SendServerCommand( NULL, "%s", text );
+ } else {
+ if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
+ return;
+ }
+ SV_SendServerCommand( svs.clients + clientNum, "%s", text );
+ }
+}
+
+
+/*
+===============
+SV_GameDropClient
+
+Disconnects the client with a message
+===============
+*/
+void SV_GameDropClient( int clientNum, const char *reason ) {
+ if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
+ return;
+ }
+ SV_DropClient( svs.clients + clientNum, reason );
+}
+
+
+/*
+=================
+SV_SetBrushModel
+
+sets mins and maxs for inline bmodels
+=================
+*/
+void SV_SetBrushModel( sharedEntity_t *ent, const char *name ) {
+ clipHandle_t h;
+ vec3_t mins, maxs;
+
+ if (!name) {
+ Com_Error( ERR_DROP, "SV_SetBrushModel: NULL" );
+ }
+
+ if (name[0] != '*') {
+ Com_Error( ERR_DROP, "SV_SetBrushModel: %s isn't a brush model", name );
+ }
+
+
+ ent->s.modelindex = atoi( name + 1 );
+
+ h = CM_InlineModel( ent->s.modelindex );
+ CM_ModelBounds( h, mins, maxs );
+ VectorCopy (mins, ent->r.mins);
+ VectorCopy (maxs, ent->r.maxs);
+ ent->r.bmodel = qtrue;
+
+ ent->r.contents = -1; // we don't know exactly what is in the brushes
+
+ SV_LinkEntity( ent ); // FIXME: remove
+}
+
+
+
+/*
+=================
+SV_inPVS
+
+Also checks portalareas so that doors block sight
+=================
+*/
+bool SV_inPVS (const vec3_t p1, const vec3_t p2)
+{
+ int leafnum;
+ int cluster;
+ int area1, area2;
+ byte *mask;
+
+ leafnum = CM_PointLeafnum (p1);
+ cluster = CM_LeafCluster (leafnum);
+ area1 = CM_LeafArea (leafnum);
+ mask = CM_ClusterPVS (cluster);
+
+ leafnum = CM_PointLeafnum (p2);
+ cluster = CM_LeafCluster (leafnum);
+ area2 = CM_LeafArea (leafnum);
+
+ if ( mask && !(mask[cluster>>3] & (1<<(cluster&7))) )
+ return false;
+
+ if (!CM_AreasConnected (area1, area2))
+ return false; // a door blocks sight
+
+ return true;
+}
+
+
+/*
+=================
+SV_inPVSIgnorePortals
+
+Does NOT check portalareas
+=================
+*/
+bool SV_inPVSIgnorePortals( const vec3_t p1, const vec3_t p2)
+{
+ int leafnum;
+ int cluster;
+ byte *mask;
+
+ leafnum = CM_PointLeafnum (p1);
+ cluster = CM_LeafCluster (leafnum);
+ mask = CM_ClusterPVS (cluster);
+
+ leafnum = CM_PointLeafnum (p2);
+ cluster = CM_LeafCluster (leafnum);
+
+ if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
+ return false;
+
+ return true;
+}
+
+
+/*
+========================
+SV_AdjustAreaPortalState
+========================
+*/
+void SV_AdjustAreaPortalState( sharedEntity_t *ent, bool open ) {
+ svEntity_t *svEnt;
+
+ svEnt = SV_SvEntityForGentity( ent );
+ if ( svEnt->areanum2 == -1 ) {
+ return;
+ }
+ CM_AdjustAreaPortalState( svEnt->areanum, svEnt->areanum2, open );
+}
+
+
+/*
+==================
+SV_EntityContact
+==================
+*/
+bool SV_EntityContact( vec3_t mins, vec3_t maxs, const sharedEntity_t *gEnt, traceType_t type ) {
+ const float *origin, *angles;
+ clipHandle_t ch;
+ trace_t trace;
+
+ // check for exact collision
+ origin = gEnt->r.currentOrigin;
+ angles = gEnt->r.currentAngles;
+
+ ch = SV_ClipHandleForEntity( gEnt );
+ CM_TransformedBoxTrace ( &trace, vec3_origin, vec3_origin, mins, maxs,
+ ch, -1, origin, angles, type );
+
+ return trace.startsolid;
+}
+
+
+/*
+===============
+SV_GetServerinfo
+
+===============
+*/
+void SV_GetServerinfo( char *buffer, int bufferSize ) {
+ if ( bufferSize < 1 ) {
+ Com_Error( ERR_DROP, "SV_GetServerinfo: bufferSize == %i", bufferSize );
+ }
+ Q_strncpyz( buffer, Cvar_InfoString( CVAR_SERVERINFO ), bufferSize );
+}
+
+/*
+===============
+SV_LocateGameData
+
+===============
+*/
+void SV_LocateGameData( sharedEntity_t *gEnts, int numGEntities, int sizeofGEntity_t,
+ playerState_t *clients, int sizeofGameClient ) {
+ sv.gentities = gEnts;
+ sv.gentitySize = sizeofGEntity_t;
+ sv.num_entities = numGEntities;
+
+ sv.gameClients = clients;
+ sv.gameClientSize = sizeofGameClient;
+}
+
+
+/*
+===============
+SV_GetUsercmd
+
+===============
+*/
+void SV_GetUsercmd( int clientNum, usercmd_t *cmd ) {
+ if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
+ Com_Error( ERR_DROP, "SV_GetUsercmd: bad clientNum:%i", clientNum );
+ }
+ *cmd = svs.clients[clientNum].lastUsercmd;
+}
+
+//==============================================
+
+static int FloatAsInt( float f ) {
+ floatint_t fi;
+ fi.f = f;
+ return fi.i;
+}
+
+/*
+====================
+SV_GameSystemCalls
+
+The module is making a system call
+====================
+*/
+intptr_t SV_GameSystemCalls( intptr_t *args ) {
+ switch( args[0] )
+ {
+ case G_PRINT:
+ Com_Printf( "%s", (const char*)VMA(1) );
+ return 0;
+ case G_ERROR:
+ Com_Error( ERR_DROP, "%s", (const char*)VMA(1) );
+ return 0;
+ case G_MILLISECONDS:
+ return Sys_Milliseconds();
+ case G_CVAR_REGISTER:
+ Cvar_Register( (vmCvar_t*)VMA(1), (const char*)VMA(2), (const char*)VMA(3), args[4] );
+ return 0;
+ case G_CVAR_UPDATE:
+ Cvar_Update( (vmCvar_t*)VMA(1) );
+ return 0;
+ case G_CVAR_SET:
+ Cvar_SetSafe( (const char *)VMA(1), (const char *)VMA(2) );
+ return 0;
+ case G_CVAR_VARIABLE_INTEGER_VALUE:
+ return Cvar_VariableIntegerValue( (const char *)VMA(1) );
+ case G_CVAR_VARIABLE_STRING_BUFFER:
+ Cvar_VariableStringBuffer( (const char*)VMA(1), (char*)VMA(2), args[3] );
+ return 0;
+ case G_ARGC:
+ return Cmd_Argc();
+ case G_ARGV:
+ Cmd_ArgvBuffer( args[1], (char*)VMA(2), args[3] );
+ return 0;
+ case G_SEND_CONSOLE_COMMAND:
+ Cbuf_ExecuteText( args[1], (const char*)VMA(2) );
+ return 0;
+
+ case G_FS_FOPEN_FILE:
+ return FS_FOpenFileByMode( (const char*)VMA(1), (fileHandle_t*)VMA(2), (FS_Mode)args[3] );
+ case G_FS_READ:
+ FS_Read( VMA(1), args[2], args[3] );
+ return 0;
+ case G_FS_WRITE:
+ FS_Write( VMA(1), args[2], args[3] );
+ return 0;
+ case G_FS_FCLOSE_FILE:
+ FS_FCloseFile( args[1] );
+ return 0;
+ case G_FS_GETFILELIST:
+ return FS_GetFileList( (const char*)VMA(1), (const char*)VMA(2), (char*)VMA(3), args[4] );
+ case G_FS_GETFILTEREDFILES:
+ return FS_GetFilteredFiles( (const char*)VMA(1), (const char*)VMA(2), (char*)VMA(3), (char*)VMA(4), args[5] );
+ case G_FS_SEEK:
+ return FS_Seek( args[1], args[2], (FS_Origin)args[3] );
+ case G_LOCATE_GAME_DATA:
+ SV_LocateGameData( (sharedEntity_t*)VMA(1), args[2], args[3], (playerState_t*)VMA(4), args[5] );
+ return 0;
+ case G_DROP_CLIENT:
+ SV_GameDropClient( args[1], (const char*)VMA(2) );
+ return 0;
+ case G_SEND_SERVER_COMMAND:
+ SV_GameSendServerCommand( args[1], (const char*)VMA(2) );
+ return 0;
+ case G_LINKENTITY:
+ SV_LinkEntity( (sharedEntity_t*)VMA(1) );
+ return 0;
+ case G_UNLINKENTITY:
+ SV_UnlinkEntity( (sharedEntity_t*)VMA(1) );
+ return 0;
+ case G_ENTITIES_IN_BOX:
+ return SV_AreaEntities( (const vec_t*)VMA(1), (const vec_t*)VMA(2), (int*)VMA(3), args[4] );
+ case G_ENTITY_CONTACT:
+ return SV_EntityContact( (vec_t*)VMA(1), (vec_t*)VMA(2), (const sharedEntity_t*)VMA(3), TT_AABB );
+ case G_ENTITY_CONTACTCAPSULE:
+ return SV_EntityContact( (vec_t*)VMA(1), (vec_t*)VMA(2), (const sharedEntity_t*)VMA(3), TT_CAPSULE );
+ case G_TRACE:
+ SV_Trace( (trace_t*)VMA(1), (const vec_t*)VMA(2), (vec_t*)VMA(3), (vec_t*)VMA(4), (const vec_t*)VMA(5), args[6], args[7], TT_AABB );
+ return 0;
+ case G_TRACECAPSULE:
+ SV_Trace( (trace_t*)VMA(1), (const vec_t*)VMA(2), (vec_t*)VMA(3), (vec_t*)VMA(4), (const vec_t*)VMA(5), args[6], args[7], TT_CAPSULE );
+ return 0;
+ case G_POINT_CONTENTS:
+ return SV_PointContents( (const vec_t*)VMA(1), args[2] );
+ case G_SET_BRUSH_MODEL:
+ SV_SetBrushModel( (sharedEntity_t*)VMA(1), (const char*)VMA(2) );
+ return 0;
+ case G_IN_PVS:
+ return SV_inPVS( (const vec_t*)VMA(1), (const vec_t*)VMA(2) );
+ case G_IN_PVS_IGNORE_PORTALS:
+ return SV_inPVSIgnorePortals( (const vec_t*)VMA(1), (const vec_t*)VMA(2) );
+
+ case G_SET_CONFIGSTRING:
+ SV_SetConfigstring( args[1], (const char*)VMA(2) );
+ return 0;
+ case G_GET_CONFIGSTRING:
+ SV_GetConfigstring( args[1], (char*)VMA(2), args[3] );
+ return 0;
+ case G_SET_CONFIGSTRING_RESTRICTIONS:
+ SV_SetConfigstringRestrictions( args[1], (clientList_t*)VMA(2) );
+ return 0;
+ case G_SET_USERINFO:
+ SV_SetUserinfo( args[1], (const char*)VMA(2) );
+ return 0;
+ case G_GET_USERINFO:
+ SV_GetUserinfo( args[1], (char*)VMA(2), args[3] );
+ return 0;
+ case G_GET_SERVERINFO:
+ SV_GetServerinfo( (char*)VMA(1), args[2] );
+ return 0;
+ case G_ADJUST_AREA_PORTAL_STATE:
+ SV_AdjustAreaPortalState( (sharedEntity_t*)VMA(1), (bool)args[2] );
+ return 0;
+ case G_AREAS_CONNECTED:
+ return CM_AreasConnected( args[1], args[2] );
+
+ case G_GET_USERCMD:
+ SV_GetUsercmd( args[1], (usercmd_t*)VMA(2) );
+ return 0;
+ case G_GET_ENTITY_TOKEN:
+ {
+ const char *s;
+
+ s = COM_Parse( &sv.entityParsePoint );
+ Q_strncpyz( (char*)VMA(1), s, args[2] );
+ if ( !sv.entityParsePoint && !s[0] ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ case G_REAL_TIME:
+ return Com_RealTime( (qtime_t*)VMA(1) );
+ case G_SNAPVECTOR:
+ Q_SnapVector( (vec_t*)VMA(1) );
+ return 0;
+
+ case G_SEND_GAMESTAT:
+ return 0;
+
+ //====================================
+
+ case G_PARSE_ADD_GLOBAL_DEFINE:
+ return Parse_AddGlobalDefine( (char*)VMA(1) );
+ case G_PARSE_LOAD_SOURCE:
+ return Parse_LoadSourceHandle( (const char*)VMA(1) );
+ case G_PARSE_FREE_SOURCE:
+ return Parse_FreeSourceHandle( args[1] );
+ case G_PARSE_READ_TOKEN:
+ return Parse_ReadTokenHandle( args[1], (pc_token_t*)VMA(2) );
+ case G_PARSE_SOURCE_FILE_AND_LINE:
+ return Parse_SourceFileAndLine( args[1], (char*)VMA(2), (int*)VMA(3) );
+
+ case G_ADDCOMMAND:
+ Cmd_AddCommand( (const char*)VMA(1), NULL );
+ return 0;
+ case G_REMOVECOMMAND:
+ Cmd_RemoveCommand( (const char*)VMA(1) );
+ return 0;
+
+ case TRAP_MEMSET:
+ ::memset( VMA(1), args[2], args[3] );
+ return 0;
+
+ case TRAP_MEMCPY:
+ ::memcpy( VMA(1), VMA(2), args[3] );
+ return 0;
+
+ case TRAP_STRNCPY:
+ ::strncpy( (char*)VMA(1), (const char*)VMA(2), args[3] );
+ return args[1];
+
+ case TRAP_SIN:
+ return FloatAsInt( sin( VMF(1) ) );
+
+ case TRAP_COS:
+ return FloatAsInt( cos( VMF(1) ) );
+
+ case TRAP_ATAN2:
+ return FloatAsInt( atan2( VMF(1), VMF(2) ) );
+
+ case TRAP_SQRT:
+ return FloatAsInt( sqrt( VMF(1) ) );
+
+ case TRAP_MATRIXMULTIPLY:
+ {
+ // XXX C++ is made this annoying
+ float (&in1)[3][3] = *reinterpret_cast<float (*)[3][3]>(VMA(1));
+ float (&in2)[3][3] = *reinterpret_cast<float (*)[3][3]>(VMA(2));
+ float (&in3)[3][3] = *reinterpret_cast<float (*)[3][3]>(VMA(3));
+ MatrixMultiply( in1, in2, in3 );
+ return 0;
+ }
+
+ case TRAP_ANGLEVECTORS:
+ AngleVectors( (const vec_t*)VMA(1), (vec_t*)VMA(2), (vec_t*)VMA(3), (vec_t*)VMA(4) );
+ return 0;
+
+ case TRAP_PERPENDICULARVECTOR:
+ PerpendicularVector( (vec_t*)VMA(1), (const vec_t*)VMA(2) );
+ return 0;
+
+ case TRAP_FLOOR:
+ return FloatAsInt( floor( VMF(1) ) );
+
+ case TRAP_CEIL:
+ return FloatAsInt( ceil( VMF(1) ) );
+
+ default:
+ Com_Error( ERR_DROP, "Bad game system trap: %ld", (long int) args[0] );
+ }
+ return 0;
+}
+
+/*
+===============
+SV_ShutdownGameProgs
+
+Called every time a map changes
+===============
+*/
+void SV_ShutdownGameProgs( void ) {
+ if ( !sv.gvm ) {
+ return;
+ }
+ VM_Call( sv.gvm, GAME_SHUTDOWN, false );
+ VM_Free( sv.gvm );
+ sv.gvm = NULL;
+}
+
+/*
+==================
+SV_InitGameVM
+
+Called for both a full init and a restart
+==================
+*/
+static void SV_InitGameVM( bool restart ) {
+ int i;
+
+ // start the entity parsing at the beginning
+ sv.entityParsePoint = CM_EntityString();
+
+ // clear all gentity pointers that might still be set from
+ // a previous level
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=522
+ // now done before GAME_INIT call
+ for ( i = 0 ; i < sv_maxclients->integer ; i++ ) {
+ svs.clients[i].gentity = NULL;
+ }
+
+ // use the current msec count for a random seed
+ // init for this gamestate
+ VM_Call (sv.gvm, GAME_INIT, sv.time, Com_Milliseconds(), restart);
+}
+
+
+
+/*
+===================
+SV_RestartGameProgs
+
+Called on a map_restart, but not on a normal map change
+===================
+*/
+void SV_RestartGameProgs( void ) {
+ if ( !sv.gvm ) {
+ return;
+ }
+ VM_Call( sv.gvm, GAME_SHUTDOWN, true );
+
+ // do a restart instead of a free
+ sv.gvm = VM_Restart(sv.gvm, true);
+ if ( !sv.gvm ) {
+ Com_Error( ERR_FATAL, "VM_Restart on game failed" );
+ }
+
+ SV_InitGameVM( true );
+}
+
+
+/*
+===============
+SV_InitGameProgs
+
+Called on a normal map change, not on a map_restart
+===============
+*/
+void SV_InitGameProgs( void ) {
+ // load the dll or bytecode
+ sv.gvm = VM_Create( "game", SV_GameSystemCalls, (vmInterpret_t)Cvar_VariableValue( "vm_game" ) );
+ if ( !sv.gvm ) {
+ Com_Error( ERR_FATAL, "VM_Create on game failed" );
+ }
+
+ SV_InitGameVM( false );
+}
+
+
+/*
+====================
+SV_GameCommand
+
+See if the current console command is claimed by the game
+====================
+*/
+bool SV_GameCommand( void ) {
+ if ( sv.state != SS_GAME ) {
+ return false;
+ }
+
+ return (bool)VM_Call( sv.gvm, GAME_CONSOLE_COMMAND );
+}
diff --git a/src/server/sv_init.cpp b/src/server/sv_init.cpp
new file mode 100644
index 0000000..8c7729e
--- /dev/null
+++ b/src/server/sv_init.cpp
@@ -0,0 +1,1004 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2012-2018 ET:Legacy team <mail@etlegacy.com>
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "server.h"
+
+#include "qcommon/cvar.h"
+
+// Attack log file is started when server is init (!= sv_running 1!)
+// we even log attacks when the server is waiting for rcon and doesn't run a map
+int attHandle = 0; // server attack log file handle
+
+char alternateInfos[2][2][BIG_INFO_STRING];
+
+/*
+===============
+SV_SendConfigstring
+
+Creates and sends the server command necessary to update the CS index for the
+given client
+===============
+*/
+static void SV_SendConfigstring(client_t *client, int i)
+{
+ const char *configstring;
+ int maxChunkSize = MAX_STRING_CHARS - 24;
+ int len;
+
+ if (sv.configstrings[i].restricted &&
+ Com_ClientListContains(&sv.configstrings[i].clientList, client - svs.clients))
+ {
+ // Send a blank config string for this client if it's listed
+ SV_SendServerCommand(client, "cs %i \"\"\n", i);
+ return;
+ }
+
+ if (i <= CS_SYSTEMINFO && client->netchan.alternateProtocol != 0)
+ {
+ configstring = alternateInfos[i][client->netchan.alternateProtocol - 1];
+ }
+ else
+ {
+ configstring = sv.configstrings[i].s;
+ }
+
+ len = strlen(configstring);
+
+ if (len >= maxChunkSize)
+ {
+ int sent = 0;
+ int remaining = len;
+ const char *cmd;
+ char buf[MAX_STRING_CHARS];
+
+ while (remaining > 0)
+ {
+ if (sent == 0)
+ {
+ cmd = "bcs0";
+ }
+ else if (remaining < maxChunkSize)
+ {
+ cmd = "bcs2";
+ }
+ else
+ {
+ cmd = "bcs1";
+ }
+ Q_strncpyz(buf, &configstring[sent], maxChunkSize);
+
+ SV_SendServerCommand(client, "%s %i \"%s\"\n", cmd, i, buf);
+
+ sent += (maxChunkSize - 1);
+ remaining -= (maxChunkSize - 1);
+ }
+ }
+ else
+ {
+ // standard cs, just send it
+ SV_SendServerCommand(client, "cs %i \"%s\"\n", i, configstring);
+ }
+}
+
+/*
+===============
+SV_UpdateConfigstrings
+
+Called when a client goes from CS_PRIMED to CS_ACTIVE. Updates all
+Configstring indexes that have changed while the client was in CS_PRIMED
+===============
+*/
+void SV_UpdateConfigstrings(client_t *client)
+{
+ for (int i = 0; i < MAX_CONFIGSTRINGS; i++)
+ {
+ // if the CS hasn't changed since we went to CS_PRIMED, ignore
+ if (!client->csUpdated[i]) continue;
+
+ // do not always send server info to all clients
+ if (i == CS_SERVERINFO && client->gentity && (client->gentity->r.svFlags & SVF_NOSERVERINFO))
+ {
+ continue;
+ }
+
+ SV_SendConfigstring(client, i);
+ client->csUpdated[i] = false;
+ }
+}
+
+/*
+===============
+SV_SetConfigstring
+
+===============
+*/
+void SV_SetConfigstring(int idx, const char *val)
+{
+ bool modified[3] = {false, false, false};
+ int i;
+ client_t *client;
+
+ if (idx < 0 || idx >= MAX_CONFIGSTRINGS)
+ {
+ Com_Error(ERR_DROP, "SV_SetConfigstring: bad idx %i", idx);
+ }
+
+ if (!val)
+ {
+ val = "";
+ }
+
+ if (idx <= CS_SYSTEMINFO)
+ {
+ for (i = 1; i < 3; ++i)
+ {
+ char info[BIG_INFO_STRING];
+
+ Q_strncpyz(info, val, sizeof(info));
+ if (idx == CS_SERVERINFO)
+ {
+ Info_SetValueForKey_Big(info, "protocol", (i == 1 ? "70" : "69"));
+ }
+ else if (i == 2)
+ {
+ Info_SetValueForKey_Big(info, "sv_paks", Cvar_VariableString("sv_alternatePaks"));
+ Info_SetValueForKey_Big(info, "sv_pakNames", Cvar_VariableString("sv_alternatePakNames"));
+ Info_SetValueForKey_Big(info, "sv_referencedPaks", Cvar_VariableString("sv_referencedAlternatePaks"));
+ Info_SetValueForKey_Big(
+ info, "sv_referencedPakNames", Cvar_VariableString("sv_referencedAlternatePakNames"));
+ Info_SetValueForKey_Big(info, "cl_allowDownload", "1, you should set it yourself");
+ if (!(sv_allowDownload->integer & DLF_NO_REDIRECT))
+ {
+ Info_SetValueForKey_Big(info, "sv_wwwBaseURL", Cvar_VariableString("sv_dlUrl"));
+ Info_SetValueForKey_Big(
+ info, "sv_wwwDownload", Cvar_VariableString("1, you should set it yourself"));
+ }
+ }
+
+ if (strcmp(info, alternateInfos[idx][i - 1]))
+ {
+ modified[i] = true;
+ strcpy(alternateInfos[idx][i - 1], info);
+ }
+ }
+
+ if (strcmp(val, sv.configstrings[idx].s))
+ {
+ modified[0] = true;
+ Z_Free(sv.configstrings[idx].s);
+ sv.configstrings[idx].s = CopyString(val);
+ }
+
+ if (!modified[0] && !modified[1] && !modified[2])
+ {
+ return;
+ }
+ }
+ else
+ {
+ // don't bother broadcasting an update if no change
+ if (!strcmp(val, sv.configstrings[idx].s))
+ {
+ return;
+ }
+
+ // change the string in sv
+ Z_Free(sv.configstrings[idx].s);
+ sv.configstrings[idx].s = CopyString(val);
+ }
+
+ // send it to all the clients if we aren't
+ // spawning a new server
+ if (sv.state == SS_GAME || sv.restarting)
+ {
+ // send the data to all relevent clients
+ for (i = 0, client = svs.clients; i < sv_maxclients->integer; i++, client++)
+ {
+ if (idx <= CS_SYSTEMINFO && !modified[client->netchan.alternateProtocol])
+ {
+ continue;
+ }
+
+ if (client->state < CS_ACTIVE)
+ {
+ if (client->state == CS_PRIMED) client->csUpdated[idx] = true;
+ continue;
+ }
+ // do not always send server info to all clients
+ if (idx == CS_SERVERINFO && client->gentity && (client->gentity->r.svFlags & SVF_NOSERVERINFO))
+ {
+ continue;
+ }
+
+ SV_SendConfigstring(client, idx);
+ }
+ }
+}
+
+/*
+===============
+SV_GetConfigstring
+
+===============
+*/
+void SV_GetConfigstring(int idx, char *buffer, int bufferSize)
+{
+ if (bufferSize < 1)
+ {
+ Com_Error(ERR_DROP, "SV_GetConfigstring: bufferSize == %i", bufferSize);
+ }
+ if (idx < 0 || idx >= MAX_CONFIGSTRINGS)
+ {
+ Com_Error(ERR_DROP, "SV_GetConfigstring: bad idx %i", idx);
+ }
+ if (!sv.configstrings[idx].s)
+ {
+ buffer[0] = 0;
+ return;
+ }
+
+ Q_strncpyz(buffer, sv.configstrings[idx].s, bufferSize);
+}
+
+/*
+===============
+SV_SetConfigstringRestrictions
+===============
+*/
+void SV_SetConfigstringRestrictions(int idx, const clientList_t *clientList)
+{
+ int i;
+ clientList_t oldClientList = sv.configstrings[idx].clientList;
+
+ sv.configstrings[idx].clientList = *clientList;
+ sv.configstrings[idx].restricted = true;
+
+ for (i = 0; i < sv_maxclients->integer; i++)
+ {
+ if (svs.clients[i].state >= CS_CONNECTED)
+ {
+ if (Com_ClientListContains(&oldClientList, i) != Com_ClientListContains(clientList, i))
+ {
+ // A client has left or joined the restricted list, so update
+ SV_SendConfigstring(&svs.clients[i], idx);
+ }
+ }
+ }
+}
+
+/*
+===============
+SV_SetUserinfo
+
+===============
+*/
+void SV_SetUserinfo(int idx, const char *val)
+{
+ if (idx < 0 || idx >= sv_maxclients->integer)
+ {
+ Com_Error(ERR_DROP, "SV_SetUserinfo: bad idx %i", idx);
+ }
+
+ if (!val)
+ {
+ val = "";
+ }
+
+ Q_strncpyz(svs.clients[idx].userinfo, val, sizeof(svs.clients[idx].userinfo));
+ Q_strncpyz(svs.clients[idx].name, Info_ValueForKey(val, "name"), sizeof(svs.clients[idx].name));
+}
+
+/*
+===============
+SV_GetUserinfo
+
+===============
+*/
+void SV_GetUserinfo(int idx, char *buffer, int bufferSize)
+{
+ if (bufferSize < 1)
+ {
+ Com_Error(ERR_DROP, "SV_GetUserinfo: bufferSize == %i", bufferSize);
+ }
+ if (idx < 0 || idx >= sv_maxclients->integer)
+ {
+ Com_Error(ERR_DROP, "SV_GetUserinfo: bad idx %i", idx);
+ }
+ Q_strncpyz(buffer, svs.clients[idx].userinfo, bufferSize);
+}
+
+/*
+================
+SV_CreateBaseline
+
+Entity baselines are used to compress non-delta messages
+to the clients -- only the fields that differ from the
+baseline will be transmitted
+================
+*/
+static void SV_CreateBaseline(void)
+{
+ sharedEntity_t *svent;
+ int entnum;
+
+ for (entnum = 1; entnum < sv.num_entities; entnum++)
+ {
+ svent = SV_GentityNum(entnum);
+ if (!svent->r.linked)
+ {
+ continue;
+ }
+ svent->s.number = entnum;
+
+ //
+ // take current state as baseline
+ //
+ sv.svEntities[entnum].baseline = svent->s;
+ }
+}
+
+/*
+===============
+SV_BoundMaxClients
+
+===============
+*/
+static void SV_BoundMaxClients(int minimum)
+{
+ // get the current maxclients value
+ Cvar_Get("sv_maxclients", "8", 0);
+
+ sv_maxclients->modified = false;
+
+ if (sv_maxclients->integer < minimum)
+ {
+ Cvar_Set("sv_maxclients", va("%i", minimum));
+ }
+ else if (sv_maxclients->integer > MAX_CLIENTS)
+ {
+ Cvar_Set("sv_maxclients", va("%i", MAX_CLIENTS));
+ }
+}
+
+/*
+===============
+SV_Startup
+
+Called when a host starts a map when it wasn't running
+one before. Successive map or map_restart commands will
+NOT cause this to be called, unless the game is exited to
+the menu system first.
+===============
+*/
+static void SV_Startup(void)
+{
+ if (svs.initialized)
+ {
+ Com_Error(ERR_FATAL, "SV_Startup: svs.initialized");
+ }
+ SV_BoundMaxClients(1);
+
+ svs.clients = (client_t *)Z_Malloc(sizeof(client_t) * sv_maxclients->integer);
+ if (com_dedicated->integer)
+ {
+ svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES;
+ }
+ else
+ {
+ // we don't need nearly as many when playing locally
+ svs.numSnapshotEntities = sv_maxclients->integer * 4 * MAX_SNAPSHOT_ENTITIES;
+ }
+ svs.initialized = true;
+
+ // Don't respect sv_killserver unless a server is actually running
+ if (sv_killserver->integer)
+ {
+ Cvar_Set("sv_killserver", "0");
+ }
+
+ Cvar_Set("sv_running", "1");
+
+ // Join the ipv6 multicast group now that a map is running so clients can scan for us on the local network.
+ NET_JoinMulticast6();
+}
+
+/*
+==================
+SV_ChangeMaxClients
+==================
+*/
+void SV_ChangeMaxClients(void)
+{
+ int oldMaxClients;
+ int i;
+ client_t *oldClients;
+ int count;
+
+ // get the highest client number in use
+ count = 0;
+ for (i = 0; i < sv_maxclients->integer; i++)
+ {
+ if (svs.clients[i].state >= CS_CONNECTED)
+ {
+ if (i > count) count = i;
+ }
+ }
+ count++;
+
+ oldMaxClients = sv_maxclients->integer;
+ // never go below the highest client number in use
+ SV_BoundMaxClients(count);
+ // if still the same
+ if (sv_maxclients->integer == oldMaxClients)
+ {
+ return;
+ }
+
+ oldClients = (client_t *)Hunk_AllocateTempMemory(count * sizeof(client_t));
+ // copy the clients to hunk memory
+ for (i = 0; i < count; i++)
+ {
+ if (svs.clients[i].state >= CS_CONNECTED)
+ {
+ oldClients[i] = svs.clients[i];
+ }
+ else
+ {
+ ::memset(&oldClients[i], 0, sizeof(client_t));
+ }
+ }
+
+ // free old clients arrays
+ Z_Free(svs.clients);
+
+ // allocate new clients
+ svs.clients = (client_t *)Z_Malloc(sv_maxclients->integer * sizeof(client_t));
+ ::memset(svs.clients, 0, sv_maxclients->integer * sizeof(client_t));
+
+ // copy the clients over
+ for (i = 0; i < count; i++)
+ {
+ if (oldClients[i].state >= CS_CONNECTED)
+ {
+ svs.clients[i] = oldClients[i];
+ }
+ }
+
+ // free the old clients on the hunk
+ Hunk_FreeTempMemory(oldClients);
+
+ // allocate new snapshot entities
+ if (com_dedicated->integer)
+ {
+ svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES;
+ }
+ else
+ {
+ // we don't need nearly as many when playing locally
+ svs.numSnapshotEntities = sv_maxclients->integer * 4 * MAX_SNAPSHOT_ENTITIES;
+ }
+}
+
+/*
+================
+SV_ClearServer
+================
+*/
+static void SV_ClearServer(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_CONFIGSTRINGS; i++)
+ {
+ if (i <= CS_SYSTEMINFO)
+ {
+ alternateInfos[i][0][0] = alternateInfos[i][1][0] = '\0';
+ }
+ if (sv.configstrings[i].s)
+ {
+ Z_Free(sv.configstrings[i].s);
+ }
+ }
+ ::memset(&sv, 0, sizeof(sv));
+}
+
+/*
+================
+SV_TouchCGame
+
+Touch the cgame.qvm so that a pure client can load it if it's in a seperate pk3
+================
+*/
+static void SV_TouchCGame(void)
+{
+ fileHandle_t f;
+ char filename[MAX_QPATH];
+
+ Com_sprintf(filename, sizeof(filename), "vm/%s.qvm", "cgame");
+ FS_FOpenFileRead(filename, &f, false);
+ if (f)
+ {
+ FS_FCloseFile(f);
+ }
+}
+
+/*
+================
+SV_SpawnServer
+
+Change the server to a new map, taking all connected
+clients along with it.
+This is NOT called for map_restart
+================
+*/
+void SV_SpawnServer(char *server)
+{
+ int i;
+ int checksum;
+ char systemInfo[16384];
+ const char *p;
+
+ // shut down the existing game if it is running
+ SV_ShutdownGameProgs();
+
+ Com_Printf("------ Server Initialization ------\n");
+ Com_Printf("Server: %s\n", server);
+
+ // if not running a dedicated server CL_MapLoading will connect the client to the server
+ // also print some status stuff
+ CL_MapLoading();
+
+ // make sure all the client stuff is unloaded
+ CL_ShutdownAll(false);
+
+ // clear the whole hunk because we're (re)loading the server
+ Hunk_Clear();
+
+ // clear collision map data
+ CM_ClearMap();
+
+ // init client structures and svs.numSnapshotEntities
+ if (!Cvar_VariableValue("sv_running"))
+ {
+ SV_Startup();
+ }
+ else
+ {
+ // check for maxclients change
+ if (sv_maxclients->modified)
+ {
+ SV_ChangeMaxClients();
+ }
+ }
+
+ // clear pak references
+ FS_ClearPakReferences(0);
+
+ // allocate the snapshot entities on the hunk
+ svs.snapshotEntities = (entityState_t *)Hunk_Alloc(sizeof(entityState_t) * svs.numSnapshotEntities, h_high);
+ svs.nextSnapshotEntities = 0;
+
+ // toggle the server bit so clients can detect that a
+ // server has changed
+ svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;
+
+ for (i = 0; i < sv_maxclients->integer; i++)
+ {
+ // save when the server started for each client already connected
+ if (svs.clients[i].state >= CS_CONNECTED)
+ {
+ svs.clients[i].oldServerTime = sv.time;
+ }
+ }
+
+ // wipe the entire per-level structure
+ SV_ClearServer();
+ for (i = 0; i < MAX_CONFIGSTRINGS; i++)
+ {
+ if (i <= CS_SYSTEMINFO)
+ {
+ alternateInfos[i][0][0] = alternateInfos[i][1][0] = '\0';
+ }
+ sv.configstrings[i].s = CopyString("");
+ sv.configstrings[i].restricted = false;
+ ::memset(&sv.configstrings[i].clientList, 0, sizeof(clientList_t));
+ }
+
+ // make sure we are not paused
+ Cvar_Set("cl_paused", "0");
+
+ // get a new checksum feed and restart the file system
+ sv.checksumFeed = (((int)rand() << 16) ^ rand()) ^ Com_Milliseconds();
+ FS_Restart(sv.checksumFeed);
+
+ // advertise GPP-compatible extensions
+ Cvar_Set("sv_gppExtension", "1");
+
+ CM_LoadMap(va("maps/%s.bsp", server), false, &checksum);
+
+ // set serverinfo visible name
+ Cvar_Set("mapname", server);
+
+ Cvar_Set("sv_mapChecksum", va("%i", checksum));
+
+ // serverid should be different each time
+ sv.serverId = com_frameTime;
+ sv.restartedServerId = sv.serverId; // I suppose the init here is just to be safe
+ sv.checksumFeedServerId = sv.serverId;
+ Cvar_Set("sv_serverid", va("%i", sv.serverId));
+
+ // clear physics interaction links
+ SV_ClearWorld();
+
+ // media configstring setting should be done during
+ // the loading stage, so connected clients don't have
+ // to load during actual gameplay
+ sv.state = SS_LOADING;
+
+ // load and spawn all other entities
+ SV_InitGameProgs();
+
+ // run a few frames to allow everything to settle
+ for (i = 0; i < 3; i++)
+ {
+ VM_Call(sv.gvm, GAME_RUN_FRAME, sv.time);
+ sv.time += 100;
+ svs.time += 100;
+ }
+
+ // create a baseline for more efficient communications
+ SV_CreateBaseline();
+
+ for (i = 0; i < sv_maxclients->integer; i++)
+ {
+ // send the new gamestate to all connected clients
+ if (svs.clients[i].state >= CS_CONNECTED)
+ {
+ char *denied;
+
+ // connect the client again
+ denied =
+ (char *)VM_ExplicitArgPtr(sv.gvm, VM_Call(sv.gvm, GAME_CLIENT_CONNECT, i, false)); // firstTime = false
+ if (denied)
+ {
+ // this generally shouldn't happen, because the client
+ // was connected before the level change
+ SV_DropClient(&svs.clients[i], denied);
+ }
+ else
+ {
+ // when we get the next packet from a connected client,
+ // the new gamestate will be sent
+ svs.clients[i].state = CS_CONNECTED;
+ }
+ }
+ }
+
+ // run another frame to allow things to look at all the players
+ VM_Call(sv.gvm, GAME_RUN_FRAME, sv.time);
+ sv.time += 100;
+ svs.time += 100;
+
+ if (sv_pure->integer)
+ {
+ // the server sends these to the clients so they will only
+ // load pk3s also loaded at the server
+ p = FS_LoadedPakChecksums(false);
+ Cvar_Set("sv_paks", p);
+ p = FS_LoadedPakChecksums(true);
+ Cvar_Set("sv_alternatePaks", p);
+ if (strlen(p) == 0)
+ {
+ Com_Printf("WARNING: sv_pure set but no PK3 files loaded\n");
+ }
+ p = FS_LoadedPakNames(false);
+ Cvar_Set("sv_pakNames", p);
+ p = FS_LoadedPakNames(true);
+ Cvar_Set("sv_alternatePakNames", p);
+
+ // if a dedicated pure server we need to touch the cgame because it could be in a
+ // seperate pk3 file and the client will need to load the latest cgame.qvm
+ if (com_dedicated->integer)
+ {
+ SV_TouchCGame();
+ }
+ }
+ else
+ {
+ Cvar_Set("sv_paks", "");
+ Cvar_Set("sv_pakNames", "");
+ Cvar_Set("sv_alternatePaks", "");
+ Cvar_Set("sv_alternatePakNames", "");
+ }
+ // the server sends these to the clients so they can figure
+ // out which pk3s should be auto-downloaded
+ p = FS_ReferencedPakChecksums(false);
+ Cvar_Set("sv_referencedPaks", p);
+ p = FS_ReferencedPakChecksums(true);
+ Cvar_Set("sv_referencedAlternatePaks", p);
+ p = FS_ReferencedPakNames(false);
+ Cvar_Set("sv_referencedPakNames", p);
+ p = FS_ReferencedPakNames(true);
+ Cvar_Set("sv_referencedAlternatePakNames", p);
+
+ // save systeminfo and serverinfo strings
+ Q_strncpyz(systemInfo, Cvar_InfoString_Big(CVAR_SYSTEMINFO), sizeof(systemInfo));
+ cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;
+ SV_SetConfigstring(CS_SYSTEMINFO, systemInfo);
+
+ SV_SetConfigstring(CS_SERVERINFO, Cvar_InfoString(CVAR_SERVERINFO));
+ cvar_modifiedFlags &= ~CVAR_SERVERINFO;
+
+ // any media configstring setting now should issue a warning
+ // and any configstring changes should be reliably transmitted
+ // to all clients
+ sv.state = SS_GAME;
+
+ // send a heartbeat now so the master will get up to date info
+ SV_Heartbeat_f();
+
+ Hunk_SetMark();
+
+#ifndef DEDICATED
+ if (com_dedicated->integer)
+ {
+ // restart renderer in order to show console for dedicated servers
+ // launched through the regular binary
+ CL_StartHunkUsers(true);
+ }
+#endif
+
+ Com_Printf("-----------------------------------\n");
+}
+
+/**
+ * @brief SV_WriteAttackLog
+ * @param[in] log
+ */
+void SV_WriteAttackLog(const char *log)
+{
+ if (attHandle > 0)
+ {
+ char string[512]; // 512 chars seem enough here
+ qtime_t time;
+
+ Com_RealTime(&time);
+ Com_sprintf(string, sizeof(string), "%i/%i/%i %i:%i:%i %s", 1900 + time.tm_year, time.tm_mday, time.tm_mon + 1, time.tm_hour, time.tm_min, time.tm_sec, log);
+ (void) FS_Write(string, strlen(string), attHandle);
+ }
+
+ if (sv_protect->integer & SVP_CONSOLE)
+ {
+ Com_Printf("%s", log);
+ }
+}
+
+/**
+ * @brief SV_InitAttackLog
+ */
+void SV_InitAttackLog()
+{
+ if (sv_protectLog->string[0] == '\0')
+ {
+ Com_Printf("Not logging server attacks to disk.\n");
+ }
+ else
+ {
+ // in sync so admins can check this at runtime
+ FS_FOpenFileByMode(sv_protectLog->string, &attHandle, FS_APPEND_SYNC);
+
+ if (attHandle <= 0)
+ {
+ Com_Printf("WARNING: Couldn't open server attack logfile %s\n", sv_protectLog->string);
+ }
+ else
+ {
+ Com_Printf("Logging server attacks to %s\n", sv_protectLog->string);
+ SV_WriteAttackLog("-------------------------------------------------------------------------------\n");
+ SV_WriteAttackLog("Start server attack log\n");
+ SV_WriteAttackLog("-------------------------------------------------------------------------------\n");
+ }
+ }
+}
+
+/**
+ * @brief SV_CloseAttackLog
+ */
+void SV_CloseAttackLog()
+{
+ if (attHandle > 0)
+ {
+ SV_WriteAttackLog("-------------------------------------------------------------------------------\n");
+ SV_WriteAttackLog("End server attack log\n");
+ SV_WriteAttackLog("-------------------------------------------------------------------------------\n");
+ Com_Printf("Server attack log closed \n");
+ }
+
+ FS_FCloseFile(attHandle);
+
+ attHandle = 0; // local handle
+}
+
+/*
+===============
+SV_Init
+
+Only called at main exe startup, not for each game
+===============
+*/
+void SV_Init(void)
+{
+ SV_AddOperatorCommands();
+
+ // serverinfo vars
+ Cvar_Get("timelimit", "0", CVAR_SERVERINFO);
+ Cvar_Get("sv_keywords", "", CVAR_SERVERINFO);
+ sv_mapname = Cvar_Get("mapname", "nomap", CVAR_SERVERINFO | CVAR_ROM);
+ sv_privateClients = Cvar_Get("sv_privateClients", "0", CVAR_SERVERINFO);
+ sv_hostname = Cvar_Get("sv_hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE);
+ sv_maxclients = Cvar_Get("sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
+
+ sv_minRate = Cvar_Get("sv_minRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO);
+ sv_maxRate = Cvar_Get("sv_maxRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO);
+ sv_dlRate = Cvar_Get("sv_dlRate", "100", CVAR_ARCHIVE | CVAR_SERVERINFO);
+ sv_minPing = Cvar_Get("sv_minPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO);
+ sv_maxPing = Cvar_Get("sv_maxPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO);
+
+ // systeminfo
+ Cvar_Get("sv_cheats", "1", CVAR_SYSTEMINFO | CVAR_ROM);
+ sv_serverid = Cvar_Get("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM);
+ sv_pure = Cvar_Get("sv_pure", "1", CVAR_SYSTEMINFO);
+#ifdef USE_VOIP
+ sv_voip = Cvar_Get("sv_voip", "1", CVAR_LATCH);
+ Cvar_CheckRange(sv_voip, 0, 1, true);
+ sv_voipProtocol = Cvar_Get("sv_voipProtocol", sv_voip->integer ? "opus" : "", CVAR_SYSTEMINFO | CVAR_ROM);
+#endif
+ Cvar_Get("sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM);
+ Cvar_Get("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM);
+ Cvar_Get("sv_referencedPaks", "", CVAR_SYSTEMINFO | CVAR_ROM);
+ Cvar_Get("sv_referencedPakNames", "", CVAR_SYSTEMINFO | CVAR_ROM);
+ Cvar_Get("sv_alternatePaks", "", CVAR_ALTERNATE_SYSTEMINFO | CVAR_ROM);
+ Cvar_Get("sv_alternatePakNames", "", CVAR_ALTERNATE_SYSTEMINFO | CVAR_ROM);
+ Cvar_Get("sv_referencedAlternatePaks", "", CVAR_ALTERNATE_SYSTEMINFO | CVAR_ROM);
+ Cvar_Get("sv_referencedAlternatePakNames", "", CVAR_ALTERNATE_SYSTEMINFO | CVAR_ROM);
+
+ // server vars
+ sv_rconPassword = Cvar_Get("rconPassword", "", CVAR_TEMP);
+ sv_privatePassword = Cvar_Get("sv_privatePassword", "", CVAR_TEMP);
+ sv_fps = Cvar_Get("sv_fps", "40", CVAR_TEMP);
+ sv_timeout = Cvar_Get("sv_timeout", "200", CVAR_TEMP);
+ sv_zombietime = Cvar_Get("sv_zombietime", "2", CVAR_TEMP);
+
+ sv_allowDownload = Cvar_Get("sv_allowDownload", "0", CVAR_SERVERINFO);
+ Cvar_Get("sv_dlURL", "http://downloads.tremulous.net", CVAR_SERVERINFO | CVAR_ARCHIVE);
+
+ sv_protect = Cvar_Get("sv_protect", "3", CVAR_ARCHIVE);
+ sv_protectLog = Cvar_Get("sv_protectLog", "sv_protect.log", CVAR_ARCHIVE);
+ SV_InitAttackLog();
+
+ for (int a = 0; a < 3; ++a)
+ {
+ sv_masters[a][0] = Cvar_Get(va("sv_%smaster1", (a == 2 ? "alt2" : a == 1 ? "alt1" : "")), MASTER_SERVER_NAME, 0);
+ for (int i = 1; i < MAX_MASTER_SERVERS; i++)
+ sv_masters[a][i] = Cvar_Get(va("sv_%smaster%d", (a == 2 ? "alt2" : a == 1 ? "alt1" : ""), i + 1), "", CVAR_ARCHIVE);
+ }
+
+ sv_reconnectlimit = Cvar_Get("sv_reconnectlimit", "3", 0);
+ sv_showloss = Cvar_Get("sv_showloss", "0", 0);
+ sv_padPackets = Cvar_Get("sv_padPackets", "0", 0);
+ sv_killserver = Cvar_Get("sv_killserver", "0", 0);
+ sv_mapChecksum = Cvar_Get("sv_mapChecksum", "", CVAR_ROM);
+ sv_lanForceRate = Cvar_Get("sv_lanForceRate", "1", CVAR_ARCHIVE);
+ sv_rsaAuth = Cvar_Get("sv_rsaAuth", "1", CVAR_INIT | CVAR_PROTECTED);
+ sv_schachtmeisterPort = Cvar_Get ("sv_schachtmeisterPort", "1337", CVAR_ARCHIVE);
+}
+
+/*
+==================
+SV_FinalMessage
+
+Used by SV_Shutdown to send a final message to all
+connected clients before the server goes down. The messages are sent immediately,
+not just stuck on the outgoing message list, because the server is going
+to totally exit after returning from this function.
+==================
+*/
+void SV_FinalMessage(const char *message)
+{
+ client_t *cl;
+
+ // send it twice, ignoring rate
+ for (int j = 0; j < 2; j++)
+ {
+ int i;
+ for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++)
+ {
+ if (cl->state >= CS_CONNECTED)
+ {
+ // don't send a disconnect to a local client
+ if (cl->netchan.remoteAddress.type != NA_LOOPBACK)
+ {
+ SV_SendServerCommand(cl, "print \"%s\n\"\n", message);
+ SV_SendServerCommand(cl, "disconnect \"%s\"", message);
+ }
+ // force a snapshot to be sent
+ cl->lastSnapshotTime = 0;
+ SV_SendClientSnapshot(cl);
+ }
+ }
+ }
+}
+
+/*
+================
+SV_Shutdown
+
+Called when each game quits,
+before Sys_Quit or Sys_Error
+================
+*/
+void SV_Shutdown(const char *finalmsg)
+{
+ // close attack log
+ SV_CloseAttackLog();
+
+ if (!com_sv_running || !com_sv_running->integer)
+ {
+ return;
+ }
+
+ Com_Printf("----- Server Shutdown (%s) -----\n", finalmsg);
+
+ NET_LeaveMulticast6();
+
+ if (svs.clients && !com_errorEntered)
+ {
+ SV_FinalMessage(finalmsg);
+ }
+
+ SV_RemoveOperatorCommands();
+ SV_MasterShutdown();
+ SV_ShutdownGameProgs();
+
+ // free current level
+ SV_ClearServer();
+
+ // free server static data
+ if (svs.clients)
+ {
+ for (int i = 0; i < sv_maxclients->integer; i++)
+ SV_FreeClient(&svs.clients[i]);
+
+ Z_Free(svs.clients);
+ }
+ ::memset(&svs, 0, sizeof(svs));
+
+ Cvar_Set("sv_running", "0");
+
+ Com_Printf("---------------------------\n");
+
+ // disconnect any local clients
+ if (sv_killserver->integer != 2) CL_Disconnect(false);
+}
diff --git a/src/server/sv_main.cpp b/src/server/sv_main.cpp
new file mode 100644
index 0000000..f5c3b98
--- /dev/null
+++ b/src/server/sv_main.cpp
@@ -0,0 +1,1551 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2012-2018 ET:Legacy team <mail@etlegacy.com>
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "server.h"
+
+#include <iostream>
+
+#ifdef USE_VOIP
+cvar_t *sv_voip;
+cvar_t *sv_voipProtocol;
+#endif
+
+serverStatic_t svs; // persistant server info
+server_t sv {}; // local server
+
+cvar_t *sv_fps = NULL; // time rate for running non-clients
+cvar_t *sv_timeout; // seconds without any message
+cvar_t *sv_zombietime; // seconds to sink messages after disconnect
+cvar_t *sv_rconPassword; // password for remote server commands
+cvar_t *sv_privatePassword; // password for the privateClient slots
+cvar_t *sv_allowDownload;
+cvar_t *sv_maxclients;
+
+cvar_t *sv_privateClients; // number of clients reserved for password
+cvar_t *sv_hostname;
+cvar_t *sv_masters[3][MAX_MASTER_SERVERS]; // master server IP addresses
+cvar_t *sv_reconnectlimit; // minimum seconds between connect messages
+cvar_t *sv_showloss; // report when usercmds are lost
+cvar_t *sv_padPackets; // add nop bytes to messages
+cvar_t *sv_killserver; // menu system can set to 1 to shut server down
+cvar_t *sv_mapname;
+cvar_t *sv_mapChecksum;
+cvar_t *sv_serverid;
+cvar_t *sv_minRate;
+cvar_t *sv_maxRate;
+cvar_t *sv_dlRate;
+cvar_t *sv_minPing;
+cvar_t *sv_maxPing;
+cvar_t *sv_pure;
+cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491)
+cvar_t *sv_banFile;
+
+cvar_t *sv_rsaAuth;
+
+cvar_t *sv_schachtmeisterPort;
+
+// server attack protection
+cvar_t *sv_protect; // 0 - unprotected
+ // 1 - ioquake3 method (default)
+ // 2 - OpenWolf method
+ // 4 - prints attack info to console (when ioquake3 or OPenWolf method is set)
+cvar_t *sv_protectLog; // name of log file
+
+/*
+=============================================================================
+
+EVENT MESSAGES
+
+=============================================================================
+*/
+
+/*
+===============
+SV_ExpandNewlines
+
+Converts newlines to "\n" so a line prints nicer
+===============
+*/
+static char *SV_ExpandNewlines( char *in ) {
+ static char string[1024];
+ int l;
+
+ l = 0;
+ while ( *in && l < sizeof(string) - 3 ) {
+ if ( *in == '\n' ) {
+ string[l++] = '\\';
+ string[l++] = 'n';
+ } else {
+ string[l++] = *in;
+ }
+ in++;
+ }
+ string[l] = 0;
+
+ return string;
+}
+
+/*
+======================
+SV_ReplacePendingServerCommands
+
+FIXME: This is ugly
+======================
+*/
+#if 0 // unused
+static bool SV_ReplacePendingServerCommands( client_t *client, const char *cmd )
+{
+ int i, index, csnum1, csnum2;
+
+ for ( i = client->reliableSent+1; i <= client->reliableSequence; i++ ) {
+ index = i & ( MAX_RELIABLE_COMMANDS - 1 );
+ //
+ if ( !Q_strncmp(cmd, client->reliableCommands[ index ], strlen("cs")) )
+ {
+ sscanf(cmd, "cs %i", &csnum1);
+ sscanf(client->reliableCommands[ index ], "cs %i", &csnum2);
+ if ( csnum1 == csnum2 )
+ {
+ Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );
+ return true;
+ }
+ }
+ }
+ return false;
+}
+#endif
+
+/*
+======================
+SV_AddServerCommand
+
+The given command will be transmitted to the client, and is guaranteed to
+not have future snapshot_t executed before it is executed
+======================
+*/
+void SV_AddServerCommand( client_t *client, const char *cmd ) {
+ int index, i;
+
+ // this is very ugly but it's also a waste to for instance send multiple config string updates
+ // for the same config string index in one snapshot
+// if ( SV_ReplacePendingServerCommands( client, cmd ) ) {
+// return;
+// }
+
+ // do not send commands until the gamestate has been sent
+ if( client->state < CS_PRIMED )
+ return;
+
+ client->reliableSequence++;
+ // if we would be losing an old command that hasn't been acknowledged,
+ // we must drop the connection
+ // we check == instead of >= so a broadcast print added by SV_DropClient()
+ // doesn't cause a recursive drop client
+ if ( client->reliableSequence - client->reliableAcknowledge == MAX_RELIABLE_COMMANDS + 1 ) {
+ Com_Printf( "===== pending server commands =====\n" );
+ for ( i = client->reliableAcknowledge + 1 ; i <= client->reliableSequence ; i++ ) {
+ Com_Printf( "cmd %5d: %s\n", i, client->reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
+ }
+ Com_Printf( "cmd %5d: %s\n", i, cmd );
+ SV_DropClient( client, "Server command overflow" );
+ return;
+ }
+ index = client->reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );
+ Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );
+}
+
+/*
+=================
+SV_SendServerCommand
+
+Sends a reliable command string to be interpreted by
+the client game module: "cp", "print", "chat", etc
+A NULL client will broadcast to all clients
+=================
+*/
+void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
+ va_list argptr;
+ byte message[MAX_MSGLEN];
+ client_t *client;
+ int j;
+
+ va_start(argptr, fmt);
+ Q_vsnprintf((char*)message, sizeof(message), fmt,argptr);
+ va_end(argptr);
+
+ // Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt
+ // The actual cause of the bug is probably further downstream
+ // and should maybe be addressed later, but this certainly
+ // fixes the problem for now.
+ // Summary: The bug is that messages longer than 1022 are not
+ // allowed downstream and there is a buffer overflow issue
+ // affecting network traffic etc. Therefore, one way to stop
+ // this from happening is stopping the packet here. Ideally,
+ // we should increase the size of the downstream message.
+ if ( strlen ((char *)message) > 1022 ) {
+ SV_WriteAttackLog( va( "SV_SendServerCommand( %ld, %.20s... ) length %ld > 1022, "
+ "dropping to avoid server buffer overflow.\n",
+ cl - svs.clients, message, strlen( (char *)message ) ) );
+ SV_WriteAttackLog( va( "Full message: [%s]\n", message ) );
+ return;
+ }
+
+ if ( cl != NULL ) {
+ SV_AddServerCommand( cl, (char *)message );
+ return;
+ }
+
+ // hack to echo broadcast prints to console
+ if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5) ) {
+ Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) );
+ }
+
+ // send the data to all relevent clients
+ for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) {
+ SV_AddServerCommand( client, (char *)message );
+ }
+}
+
+
+/*
+==============================================================================
+
+MASTER SERVER FUNCTIONS
+
+==============================================================================
+*/
+
+/*
+================
+SV_MasterHeartbeat
+
+Send a message to the masters every few minutes to
+let it know we are alive, and log information.
+We will also have a heartbeat sent when a server
+changes from empty to non-empty, and full to non-full,
+but not on every player enter or exit.
+================
+*/
+#define HEARTBEAT_MSEC 300*1000
+void SV_MasterHeartbeat(const char *message)
+{
+ static netadr_t adrs[3][MAX_MASTER_SERVERS][2]; // [2] for v4 and v6 address for the same address string.
+ int a;
+ int i;
+ int res;
+ int netenabled;
+ int netAlternateProtocols;
+
+ netenabled = Cvar_VariableIntegerValue("net_enabled");
+ netAlternateProtocols = Cvar_VariableIntegerValue("net_alternateProtocols");
+
+ // "dedicated 1" is for lan play, "dedicated 2" is for inet public play
+ if (!com_dedicated || com_dedicated->integer != 2 || !(netenabled & (NET_ENABLEV4 | NET_ENABLEV6)))
+ return; // only dedicated servers send heartbeats
+
+ // if not time yet, don't send anything
+ if ( svs.time < svs.nextHeartbeatTime )
+ return;
+
+ svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC;
+
+ for (a = 0; a < 3; ++a)
+ {
+ // indent
+ if(a == 0 && (netAlternateProtocols & NET_DISABLEPRIMPROTO))
+ continue;
+ if(a == 1 && !(netAlternateProtocols & NET_ENABLEALT1PROTO))
+ continue;
+ if(a == 2 && !(netAlternateProtocols & NET_ENABLEALT2PROTO))
+ continue;
+
+ // send to group masters
+ for (i = 0; i < MAX_MASTER_SERVERS; i++)
+ {
+ if(!sv_masters[a][i]->string[0])
+ continue;
+
+ // see if we haven't already resolved the name
+ // resolving usually causes hitches on win95, so only
+ // do it when needed
+ if(sv_masters[a][i]->modified || (adrs[a][i][0].type == NA_BAD && adrs[a][i][1].type == NA_BAD))
+ {
+ sv_masters[a][i]->modified = false;
+
+ if(netenabled & NET_ENABLEV4)
+ {
+ Com_Printf("Resolving %s (IPv4)\n", sv_masters[a][i]->string);
+ res = NET_StringToAdr(sv_masters[a][i]->string, &adrs[a][i][0], NA_IP);
+ adrs[a][i][0].alternateProtocol = a;
+
+ if(res == 2)
+ {
+ // if no port was specified, use the default master port
+ adrs[a][i][0].port = BigShort(a == 2 ? ALT2PORT_MASTER : a == 1 ? ALT1PORT_MASTER : PORT_MASTER);
+ }
+
+ if(res)
+ Com_Printf( "%s resolved to %s\n", sv_masters[a][i]->string, NET_AdrToStringwPort(adrs[a][i][0]));
+ else
+ Com_Printf( "%s has no IPv4 address.\n", sv_masters[a][i]->string);
+ }
+
+ if(netenabled & NET_ENABLEV6)
+ {
+ Com_Printf("Resolving %s (IPv6)\n", sv_masters[a][i]->string);
+ res = NET_StringToAdr(sv_masters[a][i]->string, &adrs[a][i][1], NA_IP6);
+ adrs[a][i][1].alternateProtocol = a;
+
+ if(res == 2)
+ {
+ // if no port was specified, use the default master port
+ adrs[a][i][1].port = BigShort(a == 2 ? ALT2PORT_MASTER : a == 1 ? ALT1PORT_MASTER : PORT_MASTER);
+ }
+
+ if(res)
+ Com_Printf( "%s resolved to %s\n", sv_masters[a][i]->string, NET_AdrToStringwPort(adrs[a][i][1]));
+ else
+ Com_Printf( "%s has no IPv6 address.\n", sv_masters[a][i]->string);
+ }
+
+ if(adrs[a][i][0].type == NA_BAD && adrs[a][i][1].type == NA_BAD)
+ {
+ Com_Printf("Couldn't resolve address: %s\n", sv_masters[a][i]->string);
+ Cvar_Set(sv_masters[a][i]->name, "");
+ sv_masters[a][i]->modified = false;
+ continue;
+ }
+ }
+
+
+ Com_Printf ("Sending%s heartbeat to %s\n", (a == 2 ? " alternate-2" : a == 1 ? " alternate-1" : ""), sv_masters[a][i]->string );
+
+ // this command should be changed if the server info / status format
+ // ever incompatably changes
+
+ if(adrs[a][i][0].type != NA_BAD)
+ NET_OutOfBandPrint( NS_SERVER, adrs[a][i][0], "heartbeat %s\n", message);
+ if(adrs[a][i][1].type != NA_BAD)
+ NET_OutOfBandPrint( NS_SERVER, adrs[a][i][1], "heartbeat %s\n", message);
+ }
+ // outdent
+ }
+}
+
+/*
+=================
+SV_MasterShutdown
+
+Informs all masters that this server is going down
+=================
+*/
+void SV_MasterShutdown( void ) {
+ // send a heartbeat right now
+ svs.nextHeartbeatTime = -9999;
+ SV_MasterHeartbeat(HEARTBEAT_FOR_MASTER);
+
+ // send it again to minimize chance of drops
+ svs.nextHeartbeatTime = -9999;
+ SV_MasterHeartbeat(HEARTBEAT_FOR_MASTER);
+
+ // when the master tries to poll the server, it won't respond, so
+ // it will be removed from the list
+}
+
+/*
+==============================================================================
+
+CONNECTIONLESS COMMANDS
+
+==============================================================================
+*/
+
+// This is deliberately quite large to make it more of an effort to DoS
+#define MAX_BUCKETS 16384
+#define MAX_HASHES 1024
+
+static leakyBucket_t buckets[ MAX_BUCKETS ];
+static leakyBucket_t *bucketHashes[ MAX_HASHES ];
+leakyBucket_t outboundLeakyBucket;
+
+/*
+================
+SVC_HashForAddress
+================
+*/
+static long SVC_HashForAddress( netadr_t address ) {
+ byte *ip = NULL;
+ size_t size = 0;
+ int i;
+ long hash = 0;
+
+ switch ( address.type ) {
+ case NA_IP: ip = address.ip; size = 4; break;
+ case NA_IP6: ip = address.ip6; size = 16; break;
+ default: break;
+ }
+
+ for ( i = 0; i < size; i++ ) {
+ hash += (long)( ip[ i ] ) * ( i + 119 );
+ }
+
+ hash = ( hash ^ ( hash >> 10 ) ^ ( hash >> 20 ) );
+ hash &= ( MAX_HASHES - 1 );
+
+ return hash;
+}
+
+/*
+================
+SVC_BucketForAddress
+
+Find or allocate a bucket for an address
+================
+*/
+static leakyBucket_t *SVC_BucketForAddress( netadr_t address, int burst, int period ) {
+ leakyBucket_t *bucket = NULL;
+ long hash = SVC_HashForAddress( address );
+ int now = Sys_Milliseconds();
+
+ for ( bucket = bucketHashes[ hash ]; bucket; bucket = bucket->next )
+ {
+ switch ( bucket->type )
+ {
+ case NA_IP:
+ if ( ::memcmp( bucket->ipv._4, address.ip, 4 ) == 0 )
+ return bucket;
+ break;
+
+ case NA_IP6:
+ if ( ::memcmp( bucket->ipv._6, address.ip6, 16 ) == 0 )
+ return bucket;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ for ( int i = 0; i < MAX_BUCKETS; i++ )
+ {
+ int interval;
+
+ bucket = &buckets[ i ];
+ interval = now - bucket->lastTime;
+
+ // Reclaim expired buckets
+ if ( bucket->lastTime > 0 && ( interval > ( burst * period ) ||
+ interval < 0 ) ) {
+ if ( bucket->prev != NULL ) {
+ bucket->prev->next = bucket->next;
+ } else {
+ bucketHashes[ bucket->hash ] = bucket->next;
+ }
+
+ if ( bucket->next != NULL ) {
+ bucket->next->prev = bucket->prev;
+ }
+
+ ::memset( bucket, 0, sizeof( leakyBucket_t ) );
+ }
+
+ if ( bucket->type == NA_BAD ) {
+ bucket->type = address.type;
+ switch ( address.type ) {
+ case NA_IP: ::memcpy( bucket->ipv._4, address.ip, 4 ); break;
+ case NA_IP6: ::memcpy( bucket->ipv._6, address.ip6, 16 ); break;
+ default: break;
+ }
+
+ bucket->lastTime = now;
+ bucket->burst = 0;
+ bucket->hash = hash;
+
+ // Add to the head of the relevant hash chain
+ bucket->next = bucketHashes[ hash ];
+ if ( bucketHashes[ hash ] != NULL ) {
+ bucketHashes[ hash ]->prev = bucket;
+ }
+
+ bucket->prev = NULL;
+ bucketHashes[ hash ] = bucket;
+
+ return bucket;
+ }
+ }
+
+ // Couldn't allocate a bucket for this address
+ // Write the info to the attack log since this is relevant information as the system is malfunctioning
+ SV_WriteAttackLogD(va("SVC_BucketForAddress: Could not allocate a bucket for client from %s\n", NET_AdrToString(address)));
+
+ return NULL;
+}
+
+/*
+================
+SVC_RateLimit
+ *
+ * @param[in,out] bucket
+ * @param[in] burst
+ * @param[in] period
+ * @return
+ *
+ * @note Don't call if sv_protect 1 (SVP_IOQ3) flag is not set!
+================
+*/
+bool SVC_RateLimit( leakyBucket_t *bucket, int burst, int period )
+{
+ if ( bucket != NULL )
+ {
+ int now = Sys_Milliseconds();
+ int interval = now - bucket->lastTime;
+ int expired = interval / period;
+ int expiredRemainder = interval % period;
+
+ if ( expired > bucket->burst || interval < 0 )
+ {
+ bucket->burst = 0;
+ bucket->lastTime = now;
+ }
+ else
+ {
+ bucket->burst -= expired;
+ bucket->lastTime = now - expiredRemainder;
+ }
+
+ if ( bucket->burst < burst )
+ {
+ bucket->burst++;
+ return false;
+ }
+ else
+ {
+ SV_WriteAttackLogD(va("SVC_RateLimit: burst limit exceeded for bucket: %i limit: %i\n", bucket->burst, burst));
+ }
+ }
+
+ return true;
+}
+
+/*
+================
+SVC_RateLimitAddress
+
+Rate limit for a particular address
+================
+*/
+bool SVC_RateLimitAddress( netadr_t from, int burst, int period )
+{
+ leakyBucket_t *bucket = SVC_BucketForAddress( from, burst, period );
+ return SVC_RateLimit( bucket, burst, period );
+}
+
+/*
+================
+SVC_Status
+
+Responds with all the info that qplug or qspy can see about the server
+and all connected players. Used for getting detailed information after
+the simple info query.
+================
+*/
+static void SVC_Status( netadr_t from ) {
+ char player[1024];
+ char status[MAX_MSGLEN];
+ int i;
+ client_t *cl;
+ playerState_t *ps;
+ int statusLength;
+ int playerLength;
+ char infostring[MAX_INFO_STRING];
+
+ if (sv_protect->integer & SVP_IOQ3) {
+ // Prevent using getstatus as an amplifier
+ if (SVC_RateLimitAddress(from, 10, 1000)) {
+ SV_WriteAttackLog(va("SVC_Status: rate limit from %s exceeded, dropping request\n",
+ NET_AdrToString(from)));
+ return;
+ }
+
+ // Allow getstatus to be DoSed relatively easily, but prevent
+ // excess outbound bandwidth usage when being flooded inbound
+ if (SVC_RateLimit(&outboundLeakyBucket, 10, 100)) {
+ SV_WriteAttackLog("SVC_Status: rate limit exceeded, dropping request\n");
+ return;
+ }
+ }
+
+ // A maximum challenge length of 128 should be more than plenty.
+ if (strlen(Cmd_Argv(1)) > 128) {
+ SV_WriteAttackLog(va("SVC_Status: challenge length exceeded from %s, dropping request\n", NET_AdrToString(from)));
+ return;
+ }
+
+ strcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO ) );
+
+ // echo back the parameter to status. so master servers can use it as a challenge
+ // to prevent timed spoofed reply packets that add ghost servers
+ Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );
+
+ if ( from.alternateProtocol != 0 )
+ Info_SetValueForKey( infostring, "protocol", from.alternateProtocol == 2 ? "69" : "70" );
+
+ status[0] = 0;
+ statusLength = 0;
+
+ for (i=0 ; i < sv_maxclients->integer ; i++) {
+ cl = &svs.clients[i];
+ if ( cl->state >= CS_CONNECTED ) {
+ ps = SV_GameClientNum( i );
+ Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n",
+ ps->persistant[PERS_SCORE], cl->ping, cl->name);
+ playerLength = strlen(player);
+ if (statusLength + playerLength >= sizeof(status) ) {
+ break; // can't hold any more
+ }
+ strcpy (status + statusLength, player);
+ statusLength += playerLength;
+ }
+ }
+
+ NET_OutOfBandPrint( NS_SERVER, from, "statusResponse\n%s\n%s", infostring, status );
+}
+
+/*
+================
+SVC_Info
+
+Responds with a short info message that should be enough to determine
+if a user is interested in a server to do a full status
+================
+*/
+void SVC_Info( netadr_t from ) {
+ int i, count;
+ const char *gamedir;
+ char infostring[MAX_INFO_STRING];
+
+ if (sv_protect->integer & SVP_IOQ3) {
+ // Prevent using getinfo as an amplifier
+ if (SVC_RateLimitAddress(from, 10, 1000)) {
+ SV_WriteAttackLog(va("SVC_Info: rate limit from %s exceeded, dropping request\n",
+ NET_AdrToString(from)));
+ return;
+ }
+
+ // Allow getinfo to be DoSed relatively easily, but prevent
+ // excess outbound bandwidth usage when being flooded inbound
+ if (SVC_RateLimit(&outboundLeakyBucket, 10, 100)) {
+ SV_WriteAttackLog("SVC_Info: rate limit exceeded, dropping request\n");
+ return;
+ }
+ }
+
+ // Check whether Cmd_Argv(1) has a sane length. This was not done in the original Quake3 version which led
+ // to the Infostring bug discovered by Luigi Auriemma. See http://aluigi.altervista.org/ for the advisory.
+ // A maximum challenge length of 128 should be more than plenty.
+ if (strlen(Cmd_Argv(1)) > 128) {
+ SV_WriteAttackLog(va("SVC_Info: challenge length from %s exceeded, dropping request\n", NET_AdrToString(from)));
+ return;
+ }
+
+ // don't count privateclients
+ count = 0;
+ for ( i = sv_privateClients->integer ; i < sv_maxclients->integer ; i++ ) {
+ if ( svs.clients[i].state >= CS_CONNECTED ) {
+ count++;
+ }
+ }
+
+ infostring[0] = 0;
+
+ // echo back the parameter to status. so servers can use it as a challenge
+ // to prevent timed spoofed reply packets that add ghost servers
+ Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );
+
+ Info_SetValueForKey( infostring, "protocol", va("%i", from.alternateProtocol == 2 ? 69 : from.alternateProtocol == 1 ? 70 : PROTOCOL_VERSION) );
+ Info_SetValueForKey( infostring, "gamename", com_gamename->string );
+ Info_SetValueForKey( infostring, "hostname", sv_hostname->string );
+ Info_SetValueForKey( infostring, "mapname", sv_mapname->string );
+ Info_SetValueForKey( infostring, "clients", va("%i", count) );
+ Info_SetValueForKey( infostring, "sv_maxclients",
+ va("%i", sv_maxclients->integer - sv_privateClients->integer ) );
+ Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) );
+
+#ifdef USE_VOIP
+ if (sv_voipProtocol->string && *sv_voipProtocol->string) {
+ Info_SetValueForKey( infostring, "voip", sv_voipProtocol->string );
+ }
+#endif
+
+ if( sv_minPing->integer ) {
+ Info_SetValueForKey( infostring, "minPing", va("%i", sv_minPing->integer) );
+ }
+ if( sv_maxPing->integer ) {
+ Info_SetValueForKey( infostring, "maxPing", va("%i", sv_maxPing->integer) );
+ }
+ gamedir = Cvar_VariableString( "fs_game" );
+ if( *gamedir ) {
+ Info_SetValueForKey( infostring, "game", gamedir );
+ }
+
+ NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring );
+}
+
+/*
+================
+SVC_FlushRedirect
+
+================
+*/
+static void SV_FlushRedirect( char *outputbuf ) {
+ NET_OutOfBandPrint( NS_SERVER, svs.redirectAddress, "print\n%s", outputbuf );
+}
+
+/**
+ * @brief DRDoS stands for "Distributed Reflected Denial of Service".
+ * See here: http://www.lemuria.org/security/application-drdos.html
+ *
+ * If the address isn't NA_IP, it's automatically denied.
+ *
+ * @return false if we're good.
+ * otherwise true means we need to block.
+ *
+ * @note Don't call this if sv_protect 2 flag is not set!
+ */
+bool SV_CheckDRDoS(netadr_t from) {
+ int i;
+ int globalCount;
+ int specificCount;
+ int timeNow;
+ receipt_t *receipt;
+ netadr_t exactFrom;
+ int oldest;
+ int oldestTime;
+ static int lastGlobalLogTime = 0;
+ static int lastSpecificLogTime = 0;
+
+ // Usually the network is smart enough to not allow incoming UDP packets
+ // with a source address being a spoofed LAN address. Even if that's not
+ // the case, sending packets to other hosts in the LAN is not a big deal.
+ // NA_LOOPBACK qualifies as a LAN address.
+ if (Sys_IsLANAddress(from)) {
+ return false;
+ }
+
+ timeNow = svs.time;
+ exactFrom = from;
+
+ // Time has wrapped
+ if (lastGlobalLogTime > timeNow || lastSpecificLogTime > timeNow) {
+ lastGlobalLogTime = 0;
+ lastSpecificLogTime = 0;
+
+ // just setting time to 1 (cannot be 0 as then globalCount would not be counted)
+ for (i = 0; i < MAX_INFO_RECEIPTS; i++) {
+ if (svs.infoReceipts[i].time) {
+ svs.infoReceipts[i].time = 1; // hack it so we count globalCount correctly
+ }
+ }
+ }
+
+ if (from.type == NA_IP) {
+ from.ip[3] = 0; // xx.xx.xx.0
+ } else {
+ from.ip6[15] = 0;
+ }
+
+ // Count receipts in last 2 seconds.
+ globalCount = 0;
+ specificCount = 0;
+ receipt = &svs.infoReceipts[0];
+ oldest = 0;
+ oldestTime = 0x7fffffff;
+ for (i = 0; i < MAX_INFO_RECEIPTS; i++, receipt++) {
+ if (receipt->time + 2000 > timeNow) {
+ if (receipt->time) {
+ // When the server starts, all receipt times are at zero. Furthermore,
+ // svs.time is close to zero. We check that the receipt time is already
+ // set so that during the first two seconds after server starts, queries
+ // from the master servers don't get ignored. As a consequence a potentially
+ // unlimited number of getinfo+getstatus responses may be sent during the
+ // first frame of a server's life.
+ globalCount++;
+ }
+ if (NET_CompareBaseAdr(from, receipt->adr)) {
+ specificCount++;
+ }
+ }
+ if (receipt->time < oldestTime) {
+ oldestTime = receipt->time;
+ oldest = i;
+ }
+ }
+
+ if (globalCount == MAX_INFO_RECEIPTS) { // All receipts happened in last 2 seconds.
+ if (lastGlobalLogTime + 1000 <= timeNow) { // Limit one log every second.
+ SV_WriteAttackLog("Detected flood of getinfo/getstatus connectionless packets\n");
+ lastGlobalLogTime = timeNow;
+ }
+
+ return true;
+ }
+ if (specificCount >= 3) { // Already sent 3 to this IP in last 2 seconds.
+ if (lastSpecificLogTime + 1000 <= timeNow) { // Limit one log every second.
+ SV_WriteAttackLog(va("Possible DRDoS attack to address %s, ignoring getinfo/getstatus connectionless packet\n",
+ NET_AdrToString(exactFrom)));
+ lastSpecificLogTime = timeNow;
+ }
+
+ return true;
+ }
+
+ receipt = &svs.infoReceipts[oldest];
+ receipt->adr = from;
+ receipt->time = timeNow;
+ return false;
+}
+
+/*
+===============
+SVC_RemoteCommand
+
+An rcon packet arrived from the network.
+Shift down the remaining args
+Redirect all printfs
+===============
+*/
+static void SVC_RemoteCommand( netadr_t from, msg_t *msg ) {
+ bool valid;
+ char remaining[1024];
+ // TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc.
+ // (OOB messages are the bottleneck here)
+#define SV_OUTPUTBUF_LENGTH (1024 - 16)
+ char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
+ char *cmd_aux;
+
+ // Prevent using rcon as an amplifier and make dictionary attacks impractical
+ if ((sv_protect->integer & SVP_IOQ3) && SVC_RateLimitAddress(from, 10, 1000)) {
+ SV_WriteAttackLog(va("Bad rcon - rate limit from %s exceeded, dropping request\n",
+ NET_AdrToString(from)));
+ return;
+ }
+
+ if ( !strlen( sv_rconPassword->string ) ||
+ strcmp (Cmd_Argv(1), sv_rconPassword->string) ) {
+ static leakyBucket_t bucket;
+
+ // Make DoS via rcon impractical
+ if ((sv_protect->integer & SVP_IOQ3) && SVC_RateLimit(&bucket, 10, 1000)) {
+ SV_WriteAttackLog("Bad rcon - rate limit exceeded, dropping request\n");
+ return;
+ }
+
+ valid = false;
+ Com_Printf ("Bad rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) );
+ } else {
+ valid = true;
+ Com_Printf ("Rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) );
+ SV_WriteAttackLog(va("Rcon from %s: %s\n", NET_AdrToString(from), Cmd_Argv(2)));
+ }
+
+ // start redirecting all print outputs to the packet
+ svs.redirectAddress = from;
+ Com_BeginRedirect (sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
+
+ if ( !strlen( sv_rconPassword->string ) ) {
+ Com_Printf ("No rconpassword set on the server.\n");
+ } else if ( !valid ) {
+ Com_Printf ("Bad rconpassword.\n");
+ SV_WriteAttackLog(va("Bad rconpassword from %s\n", NET_AdrToString(from)));
+ } else {
+ remaining[0] = 0;
+
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543
+ // get the command directly, "rcon <pass> <command>" to avoid quoting issues
+ // extract the command by walking
+ // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing
+ cmd_aux = Cmd_Cmd();
+ cmd_aux+=4;
+ while(cmd_aux[0]==' ')
+ cmd_aux++;
+ while(cmd_aux[0] && cmd_aux[0]!=' ') // password
+ cmd_aux++;
+ while(cmd_aux[0]==' ')
+ cmd_aux++;
+
+ Q_strcat( remaining, sizeof(remaining), cmd_aux);
+
+ Cmd_ExecuteString (remaining);
+
+ }
+
+ Com_EndRedirect ();
+}
+
+static void SVC_SchachtmeisterResponse( netadr_t from ) {
+
+ int tmp[ 4 ];
+
+ if ( !( from.type == NA_IP && from.ip[0] == 127 ) ) {
+ return;
+ }
+
+ if ( Cmd_Argc() >= 2 && sscanf( Cmd_Argv( 1 ), "%i.%i.%i.%i", &tmp[ 0 ], &tmp[ 1 ], &tmp[ 2 ], &tmp[ 3 ] ) == 4 ) { // compatibility with out-of-date crapware conceived in the future
+ char cmdl[ MAX_STRING_CHARS ];
+ Com_sprintf( cmdl, sizeof( cmdl ), "smr ipa %s", Cmd_ArgsFrom( 1 ) );
+ Cmd_TokenizeString( cmdl );
+ } else {
+ strcpy( Cmd_Argv( 0 ), "smr" );
+ }
+
+ SV_GameCommand();
+}
+
+/*
+=================
+SV_ConnectionlessPacket
+
+A connectionless packet has four leading 0xff
+characters to distinguish it from a game channel.
+Clients that are in the game can still send
+connectionless packets.
+=================
+*/
+static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
+ char *s;
+ const char *c;
+
+ MSG_BeginReadingOOB( msg );
+ MSG_ReadLong( msg ); // skip the -1 marker
+
+ if (!Q_strncmp("connect", (char *) &msg->data[4], 7)) {
+ Huff_Decompress(msg, 12);
+ }
+
+ s = MSG_ReadStringLine( msg );
+ Cmd_TokenizeString( s );
+
+ c = Cmd_Argv(0);
+ Com_DPrintf ("SV packet %s : %s\n", NET_AdrToString(from), c);
+
+ if (!Q_stricmp(c, "getstatus")) {
+ if ((sv_protect->integer & SVP_OWOLF) && SV_CheckDRDoS(from)) {
+ return;
+ }
+
+ SVC_Status( from );
+ } else if (!Q_stricmp(c, "getinfo")) {
+ if ((sv_protect->integer & SVP_OWOLF) && SV_CheckDRDoS(from)) {
+ return;
+ }
+
+ SVC_Info( from );
+ } else if (!Q_stricmp(c, "getchallenge")) {
+ if ((sv_protect->integer & SVP_OWOLF) && SV_CheckDRDoS(from)) {
+ return;
+ }
+
+ SV_GetChallenge(from);
+ } else if (!Q_stricmp(c, "connect")) {
+ SV_DirectConnect( from );
+ } else if (!Q_stricmp(c, "rcon")) {
+ SVC_RemoteCommand( from, msg );
+ } else if (!Q_stricmp(c, "disconnect")) {
+ // if a client starts up a local server, we may see some spurious
+ // server disconnect messages when their new server sees our final
+ // sequenced messages to the old client
+ } else if (!Q_stricmp(c, "sm2reply")) {
+ SVC_SchachtmeisterResponse( from );
+ Com_Printf( "^2response [^7%s^2]\n", s );
+ } else {
+ SV_WriteAttackLog(va("bad connectionless packet from %s:\n%s\n" // changed from Com_DPrintf to print in attack log
+ , NET_AdrToString(from), s)); // this was never reported to admins before so they might be confused
+ } // note: if protect log isn't set we do Com_Printf
+}
+
+//============================================================================
+
+/*
+=================
+SV_PacketEvent
+=================
+*/
+void SV_PacketEvent( netadr_t from, msg_t *msg ) {
+ int i;
+ client_t *cl;
+ int qport;
+
+ // check for connectionless packet (0xffffffff) first
+ if ( msg->cursize >= 4 && *(int *)msg->data == -1) {
+ SV_ConnectionlessPacket( from, msg );
+ return;
+ }
+
+ // read the qport out of the message so we can fix up
+ // stupid address translating routers
+ MSG_BeginReadingOOB( msg );
+ MSG_ReadLong( msg ); // sequence number
+ qport = MSG_ReadShort( msg ) & 0xffff;
+
+ // find which client the message is from
+ for (i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
+ if (cl->state == CS_FREE) {
+ continue;
+ }
+ if ( !NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) ) {
+ continue;
+ }
+ // it is possible to have multiple clients from a single IP
+ // address, so they are differentiated by the qport variable
+ if (cl->netchan.qport != qport) {
+ continue;
+ }
+
+ // the IP port can't be used to differentiate them, because
+ // some address translating routers periodically change UDP
+ // port assignments
+ if (cl->netchan.remoteAddress.port != from.port) {
+ Com_Printf( "SV_PacketEvent: fixing up a translated port\n" );
+ cl->netchan.remoteAddress.port = from.port;
+ }
+
+ // make sure it is a valid, in sequence packet
+ if (SV_Netchan_Process(cl, msg)) {
+ // zombie clients still need to do the Netchan_Process
+ // to make sure they don't need to retransmit the final
+ // reliable message, but they don't do any other processing
+ if (cl->state != CS_ZOMBIE) {
+ cl->lastPacketTime = svs.time; // don't timeout
+ SV_ExecuteClientMessage( cl, msg );
+ }
+ }
+ return;
+ }
+}
+
+
+/*
+===================
+SV_CalcPings
+
+Updates the cl->ping variables
+===================
+*/
+static void SV_CalcPings( void ) {
+ int i, j;
+ client_t *cl;
+ int total, count;
+ int delta;
+ playerState_t *ps;
+
+ for (i=0 ; i < sv_maxclients->integer ; i++) {
+ cl = &svs.clients[i];
+ if ( cl->state != CS_ACTIVE ) {
+ cl->ping = 999;
+ continue;
+ }
+ if ( !cl->gentity ) {
+ cl->ping = 999;
+ continue;
+ }
+
+ total = 0;
+ count = 0;
+ for ( j = 0 ; j < PACKET_BACKUP ; j++ ) {
+ if ( cl->frames[j].messageAcked <= 0 ) {
+ continue;
+ }
+ delta = cl->frames[j].messageAcked - cl->frames[j].messageSent;
+ count++;
+ total += delta;
+ }
+ if (!count) {
+ cl->ping = 999;
+ } else {
+ cl->ping = total/count;
+ if ( cl->ping > 999 ) {
+ cl->ping = 999;
+ }
+ }
+
+ // let the game dll know about the ping
+ ps = SV_GameClientNum( i );
+ ps->ping = cl->ping;
+ }
+}
+
+/*
+==================
+SV_CheckTimeouts
+
+If a packet has not been received from a client for timeout->integer
+seconds, drop the conneciton. Server time is used instead of
+realtime to avoid dropping the local client while debugging.
+
+When a client is normally dropped, the client_t goes into a zombie state
+for a few seconds to make sure any final reliable message gets resent
+if necessary
+==================
+*/
+static void SV_CheckTimeouts( void ) {
+ int i;
+ client_t *cl;
+ int droppoint;
+ int zombiepoint;
+
+ droppoint = svs.time - 1000 * sv_timeout->integer;
+ zombiepoint = svs.time - 1000 * sv_zombietime->integer;
+
+ for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
+ // message times may be wrong across a changelevel
+ if (cl->lastPacketTime > svs.time) {
+ cl->lastPacketTime = svs.time;
+ }
+
+ if (cl->state == CS_ZOMBIE
+ && cl->lastPacketTime < zombiepoint) {
+ // using the client id cause the cl->name is empty at this point
+ Com_DPrintf( "Going from CS_ZOMBIE to CS_FREE for client %d\n", i );
+ cl->state = CS_FREE; // can now be reused
+ continue;
+ }
+ if ( cl->state >= CS_CONNECTED && cl->lastPacketTime < droppoint) {
+ // wait several frames so a debugger session doesn't
+ // cause a timeout
+ if ( ++cl->timeoutCount > 5 ) {
+ SV_DropClient (cl, "timed out");
+ cl->state = CS_FREE; // don't bother with zombie state
+ }
+ } else {
+ cl->timeoutCount = 0;
+ }
+ }
+}
+
+
+/*
+==================
+SV_CheckPaused
+==================
+*/
+static bool SV_CheckPaused( void ) {
+ int count;
+ client_t *cl;
+ int i;
+
+ if ( !cl_paused->integer ) {
+ return false;
+ }
+
+ // only pause if there is just a single client connected
+ count = 0;
+ for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
+ if ( cl->state >= CS_CONNECTED ) {
+ count++;
+ }
+ }
+
+ if ( count > 1 ) {
+ // don't pause
+ if (sv_paused->integer)
+ Cvar_Set("sv_paused", "0");
+ return false;
+ }
+
+ if (!sv_paused->integer)
+ Cvar_Set("sv_paused", "1");
+ return true;
+}
+
+/*
+==================
+SV_FrameMsec
+Return time in millseconds until processing of the next server frame.
+==================
+*/
+int SV_FrameMsec()
+{
+ if(sv_fps)
+ {
+ int frameMsec;
+
+ frameMsec = 1000.0f / sv_fps->value;
+
+ if(frameMsec < sv.timeResidual)
+ return 0;
+ else
+ return frameMsec - sv.timeResidual;
+ }
+ else
+ return 1;
+}
+
+#define CPU_USAGE_WARNING 70
+#define FRAME_TIME_WARNING 30
+
+/*
+==================
+SV_Frame
+
+Player movement occurs as a result of packet events, which
+happen before SV_Frame is called
+==================
+*/
+void SV_Frame( int msec ) {
+ int frameMsec;
+ int startTime;
+ int frameStartTime = 0;
+ static int start, end;
+
+ start = Sys_Milliseconds();
+ svs.stats.idle += ( double )(start - end) / 1000;
+
+ // the menu kills the server with this cvar
+ if ( sv_killserver->integer ) {
+ SV_Shutdown ("Server was killed");
+ Cvar_Set( "sv_killserver", "0" );
+ return;
+ }
+
+ if (!com_sv_running->integer)
+ {
+ // Running as a server, but no map loaded
+#ifdef DEDICATED
+ // Block until something interesting happens
+ Sys_Sleep(-1);
+#endif
+
+ return;
+ }
+
+ // allow pause if only the local client is connected
+ if ( SV_CheckPaused() ) {
+ return;
+ }
+
+ if (com_dedicated->integer)
+ {
+ frameStartTime = Sys_Milliseconds();
+ }
+
+ // if it isn't time for the next frame, do nothing
+ if ( sv_fps->integer < 1 ) {
+ Cvar_Set( "sv_fps", "10" );
+ }
+
+ frameMsec = 1000 / sv_fps->integer * com_timescale->value;
+ // don't let it scale below 1ms
+ if(frameMsec < 1)
+ {
+ Cvar_Set("timescale", va("%f", sv_fps->integer / 1000.0f));
+ frameMsec = 1;
+ }
+
+ sv.timeResidual += msec;
+
+ // if time is about to hit the 32nd bit, kick all clients
+ // and clear sv.time, rather
+ // than checking for negative time wraparound everywhere.
+ // 2giga-milliseconds = 23 days, so it won't be too often
+ if ( svs.time > 0x70000000 ) {
+ SV_Shutdown( "Restarting server due to time wrapping" );
+ Cbuf_AddText( va( "map \"%s\"\n", Cvar_VariableString( "mapname" ) ) );
+ return;
+ }
+ // this can happen considerably earlier when lots of clients play and the map doesn't change
+ if ( svs.nextSnapshotEntities >= 0x7FFFFFFE - svs.numSnapshotEntities ) {
+ SV_Shutdown( "Restarting server due to numSnapshotEntities wrapping" );
+ Cbuf_AddText( va( "map \"%s\"\n", Cvar_VariableString( "mapname" ) ) );
+ return;
+ }
+
+ if( sv.restartTime && sv.time >= sv.restartTime ) {
+ sv.restartTime = 0;
+ Cbuf_AddText( "map_restart 0\n" );
+ return;
+ }
+
+ // update infostrings if anything has been changed
+ if ( cvar_modifiedFlags & CVAR_SERVERINFO ) {
+ SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );
+ cvar_modifiedFlags &= ~CVAR_SERVERINFO;
+ }
+ if ( cvar_modifiedFlags & CVAR_SYSTEMINFO ) {
+ SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString_Big( CVAR_SYSTEMINFO ) );
+ cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;
+ }
+
+ if ( com_speeds->integer ) {
+ startTime = Sys_Milliseconds ();
+ } else {
+ startTime = 0; // quite a compiler warning
+ }
+
+ // update ping based on the all received frames
+ SV_CalcPings();
+
+ // run the game simulation in chunks
+ while ( sv.timeResidual >= frameMsec ) {
+ sv.timeResidual -= frameMsec;
+ svs.time += frameMsec;
+ sv.time += frameMsec;
+
+ // let everything in the world think and move
+ VM_Call (sv.gvm, GAME_RUN_FRAME, sv.time);
+ }
+
+ if ( com_speeds->integer ) {
+ time_game = Sys_Milliseconds () - startTime;
+ }
+
+ // check timeouts
+ SV_CheckTimeouts();
+
+ // send messages back to the clients
+ SV_SendClientMessages();
+
+ // send a heartbeat to the master if needed
+ SV_MasterHeartbeat(HEARTBEAT_FOR_MASTER);
+
+ if (com_dedicated->integer)
+ {
+ int frameEndTime = Sys_Milliseconds();
+
+ svs.totalFrameTime += (frameEndTime - frameStartTime);
+
+ // we may send warnings (similar to watchdog) to the game in case the frametime is unacceptable
+ //Com_Printf("FRAMETIME frame: %i total %i\n", frameEndTime - frameStartTime, svs.totalFrameTime);
+
+ svs.currentFrameIndex++;
+
+ //if( svs.currentFrameIndex % 50 == 0 )
+ // Com_Printf( "currentFrameIndex: %i\n", svs.currentFrameIndex );
+
+ if (svs.currentFrameIndex == SERVER_PERFORMANCECOUNTER_FRAMES)
+ {
+ int averageFrameTime = svs.totalFrameTime / SERVER_PERFORMANCECOUNTER_FRAMES;
+
+ svs.sampleTimes[svs.currentSampleIndex % SERVER_PERFORMANCECOUNTER_SAMPLES] = averageFrameTime;
+ svs.currentSampleIndex++;
+
+ if (svs.currentSampleIndex > SERVER_PERFORMANCECOUNTER_SAMPLES)
+ {
+ int totalTime = 0, i;
+
+ for (i = 0; i < SERVER_PERFORMANCECOUNTER_SAMPLES; i++)
+ {
+ totalTime += svs.sampleTimes[i];
+ }
+
+ if (!totalTime)
+ {
+ totalTime = 1;
+ }
+
+ averageFrameTime = totalTime / SERVER_PERFORMANCECOUNTER_SAMPLES;
+
+ svs.serverLoad = (int)((averageFrameTime / (float)frameMsec) * 100);
+ }
+
+ //Com_Printf( "serverload: %i (%i/%i)\n", svs.serverLoad, averageFrameTime, frameMsec );
+
+ svs.totalFrameTime = 0;
+ svs.currentFrameIndex = 0;
+ }
+ }
+ else
+ {
+ svs.serverLoad = -1;
+ }
+
+ // collect timing statistics
+ // - the above 2.60 performance thingy is just inaccurate (30 seconds 'stats')
+ // to give good warning messages and is only done for dedicated
+ end = Sys_Milliseconds();
+ svs.stats.active += (( double )(end - start)) / 1000;
+
+ if (++svs.stats.count == STATFRAMES) // 5 seconds
+ {
+ svs.stats.latched_active = svs.stats.active;
+ svs.stats.latched_idle = svs.stats.idle;
+ svs.stats.active = 0;
+ svs.stats.idle = 0;
+ svs.stats.count = 0;
+
+ svs.stats.cpu = svs.stats.latched_active + svs.stats.latched_idle;
+
+ if (svs.stats.cpu != 0.f)
+ {
+ svs.stats.cpu = 100 * svs.stats.latched_active / svs.stats.cpu;
+ }
+
+ svs.stats.avg = 1000 * svs.stats.latched_active / STATFRAMES;
+
+ // FIXME: add mail, IRC, player info etc for both warnings
+ // TODO: inspect/adjust these values and/or add cvars
+ if (svs.stats.cpu > CPU_USAGE_WARNING)
+ {
+ Com_Printf("^3WARNING: Server CPU has reached a critical usage of %i%%\n", (int) svs.stats.cpu);
+ }
+
+ if (svs.stats.avg > FRAME_TIME_WARNING)
+ {
+ Com_Printf("^3WARNING: Average frame time has reached a critical value of %ims\n", (int) svs.stats.avg);
+ }
+ }
+}
+
+/*
+====================
+SV_RateMsec
+
+Return the number of msec until another message can be sent to
+a client based on its rate settings
+====================
+*/
+
+#define UDPIP_HEADER_SIZE 28
+#define UDPIP6_HEADER_SIZE 48
+
+int SV_RateMsec(client_t *client)
+{
+ int rate, rateMsec;
+ int messageSize;
+
+ messageSize = client->netchan.lastSentSize;
+ rate = client->rate;
+
+ if(sv_maxRate->integer)
+ {
+ if(sv_maxRate->integer < 1000)
+ Cvar_Set( "sv_MaxRate", "1000" );
+ if(sv_maxRate->integer < rate)
+ rate = sv_maxRate->integer;
+ }
+
+ if(sv_minRate->integer)
+ {
+ if(sv_minRate->integer < 1000)
+ Cvar_Set("sv_minRate", "1000");
+ if(sv_minRate->integer > rate)
+ rate = sv_minRate->integer;
+ }
+
+ if(client->netchan.remoteAddress.type == NA_IP6)
+ messageSize += UDPIP6_HEADER_SIZE;
+ else
+ messageSize += UDPIP_HEADER_SIZE;
+
+ rate = (int)(rate * com_timescale->value);
+ if(rate < 1)
+ rate = 1;
+ rateMsec = messageSize * 1000 / rate;
+ rate = Sys_Milliseconds() - client->netchan.lastSentTime;
+
+ if(rate > rateMsec)
+ return 0;
+ else
+ return rateMsec - rate;
+}
+
+/*
+====================
+SV_SendQueuedPackets
+
+Send download messages and queued packets in the time that we're idle, i.e.
+not computing a server frame or sending client snapshots.
+Return the time in msec until we expect to be called next
+====================
+*/
+
+int SV_SendQueuedPackets()
+{
+ int numBlocks;
+ int dlStart, deltaT, delayT;
+ static int dlNextRound = 0;
+ int timeVal = INT_MAX;
+
+ // Send out fragmented packets now that we're idle
+ delayT = SV_SendQueuedMessages();
+ if(delayT >= 0)
+ timeVal = delayT;
+
+ if(sv_dlRate->integer)
+ {
+ // Rate limiting. This is very imprecise for high
+ // download rates due to millisecond timedelta resolution
+ dlStart = Sys_Milliseconds();
+ deltaT = dlNextRound - dlStart;
+
+ if(deltaT > 0)
+ {
+ if(deltaT < timeVal)
+ timeVal = deltaT + 1;
+ }
+ else
+ {
+ numBlocks = SV_SendDownloadMessages();
+
+ if(numBlocks)
+ {
+ // There are active downloads
+ deltaT = Sys_Milliseconds() - dlStart;
+
+ delayT = 1000 * numBlocks * MAX_DOWNLOAD_BLKSIZE;
+ delayT /= sv_dlRate->integer * 1024;
+
+ if(delayT <= deltaT + 1)
+ {
+ // Sending the last round of download messages
+ // took too long for given rate, don't wait for
+ // next round, but always enforce a 1ms delay
+ // between DL message rounds so we don't hog
+ // all of the bandwidth. This will result in an
+ // effective maximum rate of 1MB/s per user, but the
+ // low download window size limits this anyways.
+ if(timeVal > 2)
+ timeVal = 2;
+
+ dlNextRound = dlStart + deltaT + 1;
+ }
+ else
+ {
+ dlNextRound = dlStart + delayT;
+ delayT -= deltaT;
+
+ if(delayT < timeVal)
+ timeVal = delayT;
+ }
+ }
+ }
+ }
+ else
+ {
+ if(SV_SendDownloadMessages())
+ timeVal = 0;
+ }
+
+ return timeVal;
+}
diff --git a/src/server/sv_net_chan.cpp b/src/server/sv_net_chan.cpp
new file mode 100644
index 0000000..f8d9b7e
--- /dev/null
+++ b/src/server/sv_net_chan.cpp
@@ -0,0 +1,259 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "server.h"
+
+#include "qcommon/q_shared.h"
+#include "qcommon/msg.h"
+#include "qcommon/net.h"
+#include "qcommon/qcommon.h"
+
+/*
+==============
+SV_Netchan_Encode
+
+ // first four bytes of the data are always:
+ long reliableAcknowledge;
+
+==============
+*/
+static void SV_Netchan_Encode( client_t *client, msg_t *msg ) {
+ long i, index;
+ byte key, *string;
+ int srdc, sbit;
+ bool soob;
+
+ if ( msg->cursize < SV_ENCODE_START ) {
+ return;
+ }
+
+ srdc = msg->readcount;
+ sbit = msg->bit;
+ soob = msg->oob;
+
+ msg->bit = 0;
+ msg->readcount = 0;
+ msg->oob = false;
+
+ /* reliableAcknowledge = */ MSG_ReadLong(msg);
+
+ msg->oob = soob;
+ msg->bit = sbit;
+ msg->readcount = srdc;
+
+ string = (byte *)client->lastClientCommandString;
+ index = 0;
+ // xor the client challenge with the netchan sequence number
+ key = client->challenge ^ client->netchan.outgoingSequence;
+ for (i = SV_ENCODE_START; i < msg->cursize; i++) {
+ // modify the key with the last received and with this message acknowledged client command
+ if (!string[index])
+ index = 0;
+ if ( string[index] > 127 || (client->netchan.alternateProtocol == 2 && string[index] == '%'))
+ {
+ key ^= '.' << (i & 1);
+ }
+ else
+ {
+ key ^= string[index] << (i & 1);
+ }
+ index++;
+ // encode the data with this key
+ *(msg->data + i) = *(msg->data + i) ^ key;
+ }
+}
+
+/*
+==============
+SV_Netchan_Decode
+
+ // first 12 bytes of the data are always:
+ long serverId;
+ long messageAcknowledge;
+ long reliableAcknowledge;
+
+==============
+*/
+static void SV_Netchan_Decode( client_t *client, msg_t *msg ) {
+ int serverId, messageAcknowledge, reliableAcknowledge;
+ int i, index, srdc, sbit;
+ bool soob;
+ byte key, *string;
+
+ srdc = msg->readcount;
+ sbit = msg->bit;
+ soob = msg->oob;
+
+ msg->oob = false;
+
+ serverId = MSG_ReadLong(msg);
+ messageAcknowledge = MSG_ReadLong(msg);
+ reliableAcknowledge = MSG_ReadLong(msg);
+
+ msg->oob = soob;
+ msg->bit = sbit;
+ msg->readcount = srdc;
+
+ string = (byte *)client->reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ];
+ index = 0;
+
+ key = client->challenge ^ serverId ^ messageAcknowledge;
+ for (i = msg->readcount + SV_DECODE_START; i < msg->cursize; i++) {
+ // modify the key with the last sent and acknowledged server command
+ if (!string[index])
+ index = 0;
+ if (string[index] > 127 || (client->netchan.alternateProtocol == 2 && string[index] == '%')) {
+ key ^= '.' << (i & 1);
+ }
+ else {
+ key ^= string[index] << (i & 1);
+ }
+ index++;
+ // decode the data with this key
+ *(msg->data + i) = *(msg->data + i) ^ key;
+ }
+}
+
+/*
+=================
+SV_Netchan_FreeQueue
+=================
+*/
+void SV_Netchan_FreeQueue(client_t *client)
+{
+ netchan_buffer_t *netbuf, *next;
+
+ for(netbuf = client->netchan_start_queue; netbuf; netbuf = next)
+ {
+ next = netbuf->next;
+ Z_Free(netbuf);
+ }
+
+ client->netchan_start_queue = NULL;
+ client->netchan_end_queue = &client->netchan_start_queue;
+}
+
+/*
+=================
+SV_Netchan_TransmitNextInQueue
+=================
+*/
+void SV_Netchan_TransmitNextInQueue(client_t *client)
+{
+ netchan_buffer_t *netbuf;
+
+ Com_DPrintf("#462 Netchan_TransmitNextFragment: popping a queued message for transmit\n");
+ netbuf = client->netchan_start_queue;
+
+ Netchan_Transmit(&client->netchan, netbuf->msg.cursize, netbuf->msg.data);
+
+ // pop from queue
+ client->netchan_start_queue = netbuf->next;
+ if(!client->netchan_start_queue)
+ {
+ Com_DPrintf("#462 Netchan_TransmitNextFragment: emptied queue\n");
+ client->netchan_end_queue = &client->netchan_start_queue;
+ }
+ else
+ Com_DPrintf("#462 Netchan_TransmitNextFragment: remaining queued message\n");
+
+ Z_Free(netbuf);
+}
+
+/*
+=================
+SV_Netchan_TransmitNextFragment
+Transmit the next fragment and the next queued packet
+Return number of ms until next message can be sent based on throughput given by client rate,
+-1 if no packet was sent.
+=================
+*/
+
+int SV_Netchan_TransmitNextFragment(client_t *client)
+{
+ if(client->netchan.unsentFragments)
+ {
+ Netchan_TransmitNextFragment(&client->netchan);
+ return SV_RateMsec(client);
+ }
+ else if(client->netchan_start_queue)
+ {
+ SV_Netchan_TransmitNextInQueue(client);
+ return SV_RateMsec(client);
+ }
+
+ return -1;
+}
+
+
+/*
+===============
+SV_Netchan_Transmit
+TTimo
+https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=462
+if there are some unsent fragments (which may happen if the snapshots
+and the gamestate are fragmenting, and collide on send for instance)
+then buffer them and make sure they get sent in correct order
+================
+*/
+
+void SV_Netchan_Transmit( client_t *client, msg_t *msg)
+{
+ MSG_WriteByte( msg, svc_EOF );
+
+ if(client->netchan.unsentFragments || client->netchan_start_queue)
+ {
+ netchan_buffer_t *netbuf;
+ Com_DPrintf("#462 SV_Netchan_Transmit: unsent fragments, stacked\n");
+ netbuf = (netchan_buffer_t *) Z_Malloc(sizeof(netchan_buffer_t));
+ // store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending
+ MSG_Copy(&netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg);
+ netbuf->next = NULL;
+ // insert it in the queue, the message will be encoded and sent later
+ *client->netchan_end_queue = netbuf;
+ client->netchan_end_queue = &(*client->netchan_end_queue)->next;
+ }
+ else
+ {
+ if (client->netchan.alternateProtocol != 0)
+ SV_Netchan_Encode( client, msg );
+ Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
+ }
+}
+
+/*
+=================
+Netchan_SV_Process
+=================
+*/
+bool SV_Netchan_Process( client_t *client, msg_t *msg )
+{
+ bool ret = Netchan_Process( &client->netchan, msg );
+ if (!ret) return false;
+
+ if (client->netchan.alternateProtocol != 0)
+ SV_Netchan_Decode( client, msg );
+
+ return true;
+}
diff --git a/src/server/sv_snapshot.cpp b/src/server/sv_snapshot.cpp
new file mode 100644
index 0000000..07dd210
--- /dev/null
+++ b/src/server/sv_snapshot.cpp
@@ -0,0 +1,749 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "server.h"
+
+/*
+=============================================================================
+
+Delta encode a client frame onto the network channel
+
+A normal server packet will look like:
+
+4 sequence number (high bit set if an oversize fragment)
+<optional reliable commands>
+1 svc_snapshot
+4 last client reliable command
+4 serverTime
+1 lastframe for delta compression
+1 snapFlags
+1 areaBytes
+<areabytes>
+<playerstate>
+<packetentities>
+
+=============================================================================
+*/
+
+/*
+=============
+SV_EmitPacketEntities
+
+Writes a delta update of an entityState_t list to the message.
+=============
+*/
+static void SV_EmitPacketEntities(int alternateProtocol, clientSnapshot_t *from, clientSnapshot_t *to, msg_t *msg)
+{
+ entityState_t *oldent, *newent;
+ int oldindex, newindex;
+ int oldnum, newnum;
+ int from_num_entities;
+
+ // generate the delta update
+ if (!from)
+ {
+ from_num_entities = 0;
+ }
+ else
+ {
+ from_num_entities = from->num_entities;
+ }
+
+ newent = NULL;
+ oldent = NULL;
+ newindex = 0;
+ oldindex = 0;
+ while (newindex < to->num_entities || oldindex < from_num_entities)
+ {
+ if (newindex >= to->num_entities)
+ {
+ newnum = 9999;
+ }
+ else
+ {
+ newent = &svs.snapshotEntities[(to->first_entity + newindex) % svs.numSnapshotEntities];
+ newnum = newent->number;
+ }
+
+ if (oldindex >= from_num_entities)
+ {
+ oldnum = 9999;
+ }
+ else
+ {
+ oldent = &svs.snapshotEntities[(from->first_entity + oldindex) % svs.numSnapshotEntities];
+ oldnum = oldent->number;
+ }
+
+ if (newnum == oldnum)
+ {
+ // delta update from old position
+ // because the force parm is false, this will not result
+ // in any bytes being emited if the entity has not changed at all
+ MSG_WriteDeltaEntity(alternateProtocol, msg, oldent, newent, false);
+ oldindex++;
+ newindex++;
+ continue;
+ }
+
+ if (newnum < oldnum)
+ {
+ // this is a new entity, send it from the baseline
+ MSG_WriteDeltaEntity(alternateProtocol, msg, &sv.svEntities[newnum].baseline, newent, true);
+ newindex++;
+ continue;
+ }
+
+ if (newnum > oldnum)
+ {
+ // the old entity isn't present in the new message
+ MSG_WriteDeltaEntity(alternateProtocol, msg, oldent, NULL, true);
+ oldindex++;
+ continue;
+ }
+ }
+
+ MSG_WriteBits(msg, (MAX_GENTITIES - 1), GENTITYNUM_BITS); // end of packetentities
+}
+
+/*
+==================
+SV_WriteSnapshotToClient
+==================
+*/
+static void SV_WriteSnapshotToClient(client_t *client, msg_t *msg)
+{
+ clientSnapshot_t *frame, *oldframe;
+ int lastframe;
+ int i;
+ int snapFlags;
+
+ // this is the snapshot we are creating
+ frame = &client->frames[client->netchan.outgoingSequence & PACKET_MASK];
+
+ // try to use a previous frame as the source for delta compressing the snapshot
+ if (client->deltaMessage <= 0 || client->state != CS_ACTIVE)
+ {
+ // client is asking for a retransmit
+ oldframe = NULL;
+ lastframe = 0;
+ }
+ else if (client->netchan.outgoingSequence - client->deltaMessage >= (PACKET_BACKUP - 3))
+ {
+ // client hasn't gotten a good message through in a long time
+ Com_DPrintf("%s: Delta request from out of date packet.\n", client->name);
+ oldframe = NULL;
+ lastframe = 0;
+ }
+ else
+ {
+ // we have a valid snapshot to delta from
+ oldframe = &client->frames[client->deltaMessage & PACKET_MASK];
+ lastframe = client->netchan.outgoingSequence - client->deltaMessage;
+
+ // the snapshot's entities may still have rolled off the buffer, though
+ if (oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities)
+ {
+ Com_DPrintf("%s: Delta request from out of date entities.\n", client->name);
+ oldframe = NULL;
+ lastframe = 0;
+ }
+ }
+
+ MSG_WriteByte(msg, svc_snapshot);
+
+ // NOTE, MRE: now sent at the start of every message from server to client
+ // let the client know which reliable clientCommands we have received
+ // MSG_WriteLong( msg, client->lastClientCommand );
+
+ // send over the current server time so the client can drift
+ // its view of time to try to match
+ if (client->oldServerTime)
+ {
+ // The server has not yet got an acknowledgement of the
+ // new gamestate from this client, so continue to send it
+ // a time as if the server has not restarted. Note from
+ // the client's perspective this time is strictly speaking
+ // incorrect, but since it'll be busy loading a map at
+ // the time it doesn't really matter.
+ MSG_WriteLong(msg, sv.time + client->oldServerTime);
+ }
+ else
+ {
+ MSG_WriteLong(msg, sv.time);
+ }
+
+ // what we are delta'ing from
+ MSG_WriteByte(msg, lastframe);
+
+ snapFlags = svs.snapFlagServerBit;
+ if (client->rateDelayed)
+ {
+ snapFlags |= SNAPFLAG_RATE_DELAYED;
+ }
+ if (client->state != CS_ACTIVE)
+ {
+ snapFlags |= SNAPFLAG_NOT_ACTIVE;
+ }
+
+ MSG_WriteByte(msg, snapFlags);
+
+ // send over the areabits
+ MSG_WriteByte(msg, frame->areabytes);
+ MSG_WriteData(msg, frame->areabits, frame->areabytes);
+
+ // delta encode the playerstate
+ if (oldframe)
+ {
+ MSG_WriteDeltaPlayerstate(client->netchan.alternateProtocol, msg, &oldframe->ps, &frame->ps);
+ }
+ else
+ {
+ MSG_WriteDeltaPlayerstate(client->netchan.alternateProtocol, msg, NULL, &frame->ps);
+ }
+
+ // delta encode the entities
+ SV_EmitPacketEntities(client->netchan.alternateProtocol, oldframe, frame, msg);
+
+ // padding for rate debugging
+ if (sv_padPackets->integer)
+ {
+ for (i = 0; i < sv_padPackets->integer; i++)
+ {
+ MSG_WriteByte(msg, svc_nop);
+ }
+ }
+}
+
+/*
+==================
+SV_UpdateServerCommandsToClient
+
+(re)send all server commands the client hasn't acknowledged yet
+==================
+*/
+void SV_UpdateServerCommandsToClient(client_t *client, msg_t *msg)
+{
+ int i;
+
+ // write any unacknowledged serverCommands
+ for (i = client->reliableAcknowledge + 1; i <= client->reliableSequence; i++)
+ {
+ MSG_WriteByte(msg, svc_serverCommand);
+ MSG_WriteLong(msg, i);
+ MSG_WriteString(msg, client->reliableCommands[i & (MAX_RELIABLE_COMMANDS - 1)]);
+ }
+ client->reliableSent = client->reliableSequence;
+}
+
+/*
+=============================================================================
+
+Build a client snapshot structure
+
+=============================================================================
+*/
+
+typedef struct {
+ int numSnapshotEntities;
+ int snapshotEntities[MAX_SNAPSHOT_ENTITIES];
+} snapshotEntityNumbers_t;
+
+/*
+=======================
+SV_QsortEntityNumbers
+=======================
+*/
+static int QDECL SV_QsortEntityNumbers(const void *a, const void *b)
+{
+ int *ea, *eb;
+
+ ea = (int *)a;
+ eb = (int *)b;
+
+ if (*ea == *eb)
+ {
+ Com_Error(ERR_DROP, "SV_QsortEntityStates: duplicated entity");
+ }
+
+ if (*ea < *eb)
+ {
+ return -1;
+ }
+
+ return 1;
+}
+
+/*
+===============
+SV_AddEntToSnapshot
+===============
+*/
+static void SV_AddEntToSnapshot(svEntity_t *svEnt, sharedEntity_t *gEnt, snapshotEntityNumbers_t *eNums)
+{
+ // if we have already added this entity to this snapshot, don't add again
+ if (svEnt->snapshotCounter == sv.snapshotCounter)
+ {
+ return;
+ }
+ svEnt->snapshotCounter = sv.snapshotCounter;
+
+ // if we are full, silently discard entities
+ if (eNums->numSnapshotEntities == MAX_SNAPSHOT_ENTITIES)
+ {
+ return;
+ }
+
+ eNums->snapshotEntities[eNums->numSnapshotEntities] = gEnt->s.number;
+ eNums->numSnapshotEntities++;
+}
+
+/*
+===============
+SV_AddEntitiesVisibleFromPoint
+===============
+*/
+static void SV_AddEntitiesVisibleFromPoint(vec3_t origin, clientSnapshot_t *frame, snapshotEntityNumbers_t *eNums)
+{
+ int e, i;
+ sharedEntity_t *ent;
+ svEntity_t *svEnt;
+ int l;
+ int clientarea, clientcluster;
+ int leafnum;
+ byte *clientpvs;
+ byte *bitvector;
+
+ // during an error shutdown message we may need to transmit
+ // the shutdown message after the server has shutdown, so
+ // specfically check for it
+ if (!sv.state)
+ {
+ return;
+ }
+
+ leafnum = CM_PointLeafnum(origin);
+ clientarea = CM_LeafArea(leafnum);
+ clientcluster = CM_LeafCluster(leafnum);
+
+ // calculate the visible areas
+ frame->areabytes = CM_WriteAreaBits(frame->areabits, clientarea);
+
+ clientpvs = CM_ClusterPVS(clientcluster);
+
+ for (e = 0; e < sv.num_entities; e++)
+ {
+ ent = SV_GentityNum(e);
+
+ // never send entities that aren't linked in
+ if (!ent->r.linked)
+ {
+ continue;
+ }
+
+ if (ent->s.number != e)
+ {
+ Com_DPrintf("FIXING ENT->S.NUMBER!!!\n");
+ ent->s.number = e;
+ }
+
+ // entities can be flagged to explicitly not be sent to the client
+ if (ent->r.svFlags & SVF_NOCLIENT)
+ {
+ continue;
+ }
+
+ // entities can be flagged to be sent to only one client
+ if (ent->r.svFlags & SVF_SINGLECLIENT)
+ {
+ if (ent->r.singleClient != frame->ps.clientNum)
+ {
+ continue;
+ }
+ }
+ // entities can be flagged to be sent to everyone but one client
+ if (ent->r.svFlags & SVF_NOTSINGLECLIENT)
+ {
+ if (ent->r.singleClient == frame->ps.clientNum)
+ {
+ continue;
+ }
+ }
+ // entities can be flagged to be sent to a given mask of clients
+ if (ent->r.svFlags & SVF_CLIENTMASK)
+ {
+ if (frame->ps.clientNum >= 32)
+ {
+ if (~ent->r.hack.generic1 & (1 << (frame->ps.clientNum - 32))) continue;
+ }
+ else
+ {
+ if (~ent->r.singleClient & (1 << frame->ps.clientNum)) continue;
+ }
+ }
+
+ svEnt = SV_SvEntityForGentity(ent);
+
+ // don't double add an entity through portals
+ if (svEnt->snapshotCounter == sv.snapshotCounter)
+ {
+ continue;
+ }
+
+ // broadcast entities are always sent
+ if (ent->r.svFlags & SVF_BROADCAST)
+ {
+ SV_AddEntToSnapshot(svEnt, ent, eNums);
+ continue;
+ }
+
+ // ignore if not touching a PV leaf
+ // check area
+ if (!CM_AreasConnected(clientarea, svEnt->areanum))
+ {
+ // doors can legally straddle two areas, so
+ // we may need to check another one
+ if (!CM_AreasConnected(clientarea, svEnt->areanum2))
+ {
+ continue; // blocked by a door
+ }
+ }
+
+ bitvector = clientpvs;
+
+ // check individual leafs
+ if (!svEnt->numClusters)
+ {
+ continue;
+ }
+ l = 0;
+ for (i = 0; i < svEnt->numClusters; i++)
+ {
+ l = svEnt->clusternums[i];
+ if (bitvector[l >> 3] & (1 << (l & 7)))
+ {
+ break;
+ }
+ }
+
+ // if we haven't found it to be visible,
+ // check overflow clusters that coudln't be stored
+ if (i == svEnt->numClusters)
+ {
+ if (svEnt->lastCluster)
+ {
+ for (; l <= svEnt->lastCluster; l++)
+ {
+ if (bitvector[l >> 3] & (1 << (l & 7)))
+ {
+ break;
+ }
+ }
+ if (l == svEnt->lastCluster)
+ {
+ continue; // not visible
+ }
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ // add it
+ SV_AddEntToSnapshot(svEnt, ent, eNums);
+
+ // if it's a portal entity, add everything visible from its camera position
+ if (ent->r.svFlags & SVF_PORTAL)
+ {
+ if (ent->s.generic1)
+ {
+ vec3_t dir;
+ VectorSubtract(ent->r.currentOrigin, origin, dir);
+ if (VectorLengthSquared(dir) > (float)ent->s.generic1 * ent->s.generic1)
+ {
+ continue;
+ }
+ }
+ SV_AddEntitiesVisibleFromPoint(ent->s.origin2, frame, eNums);
+ }
+ }
+}
+
+/*
+=============
+SV_BuildClientSnapshot
+
+Decides which entities are going to be visible to the client, and
+copies off the playerstate and areabits.
+
+This properly handles multiple recursive portals, but the render
+currently doesn't.
+
+For viewing through other player's eyes, clent can be something other than client->gentity
+=============
+*/
+static void SV_BuildClientSnapshot(client_t *client)
+{
+ vec3_t org;
+ clientSnapshot_t *frame;
+ snapshotEntityNumbers_t entityNumbers;
+ int i;
+ sharedEntity_t *ent;
+ entityState_t *state;
+ svEntity_t *svEnt;
+ sharedEntity_t *clent;
+ int clientNum;
+ playerState_t *ps;
+
+ // bump the counter used to prevent double adding
+ sv.snapshotCounter++;
+
+ // this is the frame we are creating
+ frame = &client->frames[client->netchan.outgoingSequence & PACKET_MASK];
+
+ // clear everything in this snapshot
+ entityNumbers.numSnapshotEntities = 0;
+ ::memset(frame->areabits, 0, sizeof(frame->areabits));
+
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=62
+ frame->num_entities = 0;
+
+ clent = client->gentity;
+ if (!clent || client->state == CS_ZOMBIE)
+ {
+ return;
+ }
+
+ // grab the current playerState_t
+ ps = SV_GameClientNum(client - svs.clients);
+ frame->ps = *ps;
+
+ // never send client's own entity, because it can
+ // be regenerated from the playerstate
+ clientNum = frame->ps.clientNum;
+ if (clientNum < 0 || clientNum >= MAX_GENTITIES)
+ {
+ Com_Error(ERR_DROP, "SV_SvEntityForGentity: bad gEnt");
+ }
+ svEnt = &sv.svEntities[clientNum];
+
+ svEnt->snapshotCounter = sv.snapshotCounter;
+
+ // find the client's viewpoint
+ VectorCopy(ps->origin, org);
+ org[2] += ps->viewheight;
+
+ // add all the entities directly visible to the eye, which
+ // may include portal entities that merge other viewpoints
+ SV_AddEntitiesVisibleFromPoint(org, frame, &entityNumbers);
+
+ // if there were portals visible, there may be out of order entities
+ // in the list which will need to be resorted for the delta compression
+ // to work correctly. This also catches the error condition
+ // of an entity being included twice.
+ qsort(entityNumbers.snapshotEntities, entityNumbers.numSnapshotEntities, sizeof(entityNumbers.snapshotEntities[0]),
+ SV_QsortEntityNumbers);
+
+ // now that all viewpoint's areabits have been OR'd together, invert
+ // all of them to make it a mask vector, which is what the renderer wants
+ for (i = 0; i < MAX_MAP_AREA_BYTES / 4; i++)
+ {
+ ((int *)frame->areabits)[i] = ((int *)frame->areabits)[i] ^ -1;
+ }
+
+ // copy the entity states out
+ frame->num_entities = 0;
+ frame->first_entity = svs.nextSnapshotEntities;
+ for (i = 0; i < entityNumbers.numSnapshotEntities; i++)
+ {
+ ent = SV_GentityNum(entityNumbers.snapshotEntities[i]);
+ state = &svs.snapshotEntities[svs.nextSnapshotEntities % svs.numSnapshotEntities];
+ *state = ent->s;
+ svs.nextSnapshotEntities++;
+ // this should never hit, map should always be restarted first in SV_Frame
+ if (svs.nextSnapshotEntities >= 0x7FFFFFFE)
+ {
+ Com_Error(ERR_FATAL, "svs.nextSnapshotEntities wrapped");
+ }
+ frame->num_entities++;
+ }
+}
+
+#ifdef USE_VOIP
+/*
+==================
+SV_WriteVoipToClient
+
+Check to see if there is any VoIP queued for a client, and send if there is.
+==================
+*/
+static void SV_WriteVoipToClient(client_t *cl, msg_t *msg)
+{
+ int totalbytes = 0;
+ int i;
+ voipServerPacket_t *packet;
+
+ if (cl->queuedVoipPackets)
+ {
+ // Write as many VoIP packets as we reasonably can...
+ for (i = 0; i < cl->queuedVoipPackets; i++)
+ {
+ packet = cl->voipPacket[(i + cl->queuedVoipIndex) % ARRAY_LEN(cl->voipPacket)];
+
+ if (!*cl->downloadName)
+ {
+ totalbytes += packet->len;
+ if (totalbytes > (msg->maxsize - msg->cursize) / 2) break;
+
+ if (cl->netchan.alternateProtocol != 0) MSG_WriteByte(msg, svc_EOF);
+ MSG_WriteByte(msg, svc_voipSpeex);
+ if (cl->netchan.alternateProtocol != 0) MSG_WriteByte(msg, svc_voipSpeex + 1);
+ MSG_WriteShort(msg, packet->sender);
+ MSG_WriteByte(msg, (byte)packet->generation);
+ MSG_WriteLong(msg, packet->sequence);
+ MSG_WriteByte(msg, packet->frames);
+ MSG_WriteShort(msg, packet->len);
+ if (cl->netchan.alternateProtocol == 0) MSG_WriteBits(msg, packet->flags, VOIP_FLAGCNT);
+ MSG_WriteData(msg, packet->data, packet->len);
+ }
+
+ Z_Free(packet);
+ }
+
+ cl->queuedVoipPackets -= i;
+ cl->queuedVoipIndex += i;
+ cl->queuedVoipIndex %= ARRAY_LEN(cl->voipPacket);
+ }
+}
+#endif
+
+/*
+=======================
+SV_SendMessageToClient
+
+Called by SV_SendClientSnapshot and SV_SendClientGameState
+=======================
+*/
+void SV_SendMessageToClient(msg_t *msg, client_t *client)
+{
+ // record information about the message
+ client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = msg->cursize;
+ client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = svs.time;
+ client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageAcked = -1;
+
+ // send the datagram
+ SV_Netchan_Transmit(client, msg);
+}
+
+/*
+=======================
+SV_SendClientSnapshot
+
+Also called by SV_FinalMessage
+
+=======================
+*/
+void SV_SendClientSnapshot(client_t *client)
+{
+ byte msg_buf[MAX_MSGLEN];
+ msg_t msg;
+
+ // build the snapshot
+ SV_BuildClientSnapshot(client);
+
+ MSG_Init(&msg, msg_buf, sizeof(msg_buf));
+ msg.allowoverflow = true;
+
+ // NOTE, MRE: all server->client messages now acknowledge
+ // let the client know which reliable clientCommands we have received
+ MSG_WriteLong(&msg, client->lastClientCommand);
+
+ // (re)send any reliable server commands
+ SV_UpdateServerCommandsToClient(client, &msg);
+
+ // send over all the relevant entityState_t
+ // and the playerState_t
+ SV_WriteSnapshotToClient(client, &msg);
+
+#ifdef USE_VOIP
+ SV_WriteVoipToClient(client, &msg);
+#endif
+
+ // check for overflow
+ if (msg.overflowed)
+ {
+ Com_Printf("WARNING: msg overflowed for %s\n", client->name);
+ MSG_Clear(&msg);
+ }
+
+ SV_SendMessageToClient(&msg, client);
+}
+
+/*
+=======================
+SV_SendClientMessages
+=======================
+*/
+void SV_SendClientMessages(void)
+{
+ int i;
+ client_t *c;
+
+ // send a message to each connected client
+ for (i = 0; i < sv_maxclients->integer; i++)
+ {
+ c = &svs.clients[i];
+
+ if (!c->state) continue; // not connected
+
+ if (svs.time - c->lastSnapshotTime < c->snapshotMsec * com_timescale->value) continue; // It's not time yet
+
+ if (*c->downloadName) continue; // Client is downloading, don't send snapshots
+
+ if (c->netchan.unsentFragments || c->netchan_start_queue)
+ {
+ c->rateDelayed = true;
+ continue; // Drop this snapshot if the packet queue is still full or delta compression will break
+ }
+
+ if (!(c->netchan.remoteAddress.type == NA_LOOPBACK ||
+ (sv_lanForceRate->integer && Sys_IsLANAddress(c->netchan.remoteAddress))))
+ {
+ // rate control for clients not on LAN
+
+ if (SV_RateMsec(c) > 0)
+ {
+ // Not enough time since last packet passed through the line
+ c->rateDelayed = true;
+ continue;
+ }
+ }
+
+ // generate and send a new message
+ SV_SendClientSnapshot(c);
+ c->lastSnapshotTime = svs.time;
+ c->rateDelayed = false;
+ }
+}
diff --git a/src/server/sv_world.cpp b/src/server/sv_world.cpp
new file mode 100644
index 0000000..fd0710e
--- /dev/null
+++ b/src/server/sv_world.cpp
@@ -0,0 +1,745 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// world.c -- world query functions
+
+#include "server.h"
+
+/*
+================
+SV_ClipHandleForEntity
+
+Returns a headnode that can be used for testing or clipping to a
+given entity. If the entity is a bsp model, the headnode will
+be returned, otherwise a custom box tree will be constructed.
+================
+*/
+clipHandle_t SV_ClipHandleForEntity(const sharedEntity_t *ent)
+{
+ if (ent->r.bmodel)
+ {
+ // explicit hulls in the BSP model
+ return CM_InlineModel(ent->s.modelindex);
+ }
+ if (ent->r.svFlags & SVF_CAPSULE)
+ {
+ // create a temp capsule from bounding box sizes
+ return CM_TempBoxModel(ent->r.mins, ent->r.maxs, true);
+ }
+
+ // create a temp tree from bounding box sizes
+ return CM_TempBoxModel(ent->r.mins, ent->r.maxs, qfalse);
+}
+
+/*
+===============================================================================
+
+ENTITY CHECKING
+
+To avoid linearly searching through lists of entities during environment testing,
+the world is carved up with an evenly spaced, axially aligned bsp tree. Entities
+are kept in chains either at the final leafs, or at the first node that splits
+them, which prevents having to deal with multiple fragments of a single entity.
+
+===============================================================================
+*/
+
+struct worldSector_t {
+ int axis; // -1 = leaf node
+ float dist;
+ worldSector_t *children[2];
+ svEntity_t *entities;
+};
+
+#define AREA_DEPTH 4
+#define AREA_NODES 64
+
+worldSector_t sv_worldSectors[AREA_NODES];
+int sv_numworldSectors;
+
+/*
+===============
+SV_SectorList_f
+===============
+*/
+void SV_SectorList_f(void)
+{
+ int i, c;
+ worldSector_t *sec;
+ svEntity_t *ent;
+
+ for (i = 0; i < AREA_NODES; i++)
+ {
+ sec = &sv_worldSectors[i];
+
+ c = 0;
+ for (ent = sec->entities; ent; ent = ent->nextEntityInWorldSector)
+ {
+ c++;
+ }
+ Com_Printf("sector %i: %i entities\n", i, c);
+ }
+}
+
+/*
+===============
+SV_CreateworldSector
+
+Builds a uniformly subdivided tree for the given world size
+===============
+*/
+static worldSector_t *SV_CreateworldSector(int depth, vec3_t mins, vec3_t maxs)
+{
+ worldSector_t *anode;
+ vec3_t size;
+ vec3_t mins1, maxs1, mins2, maxs2;
+
+ anode = &sv_worldSectors[sv_numworldSectors];
+ sv_numworldSectors++;
+
+ if (depth == AREA_DEPTH)
+ {
+ anode->axis = -1;
+ anode->children[0] = anode->children[1] = NULL;
+ return anode;
+ }
+
+ VectorSubtract(maxs, mins, size);
+ if (size[0] > size[1])
+ {
+ anode->axis = 0;
+ }
+ else
+ {
+ anode->axis = 1;
+ }
+
+ anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
+ VectorCopy(mins, mins1);
+ VectorCopy(mins, mins2);
+ VectorCopy(maxs, maxs1);
+ VectorCopy(maxs, maxs2);
+
+ maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
+
+ anode->children[0] = SV_CreateworldSector(depth + 1, mins2, maxs2);
+ anode->children[1] = SV_CreateworldSector(depth + 1, mins1, maxs1);
+
+ return anode;
+}
+
+/*
+===============
+SV_ClearWorld
+
+===============
+*/
+void SV_ClearWorld(void)
+{
+ clipHandle_t h;
+ vec3_t mins, maxs;
+
+ ::memset(sv_worldSectors, 0, sizeof(sv_worldSectors));
+ sv_numworldSectors = 0;
+
+ // get world map bounds
+ h = CM_InlineModel(0);
+ CM_ModelBounds(h, mins, maxs);
+ SV_CreateworldSector(0, mins, maxs);
+}
+
+/*
+===============
+SV_UnlinkEntity
+
+===============
+*/
+void SV_UnlinkEntity(sharedEntity_t *gEnt)
+{
+ svEntity_t *ent;
+ svEntity_t *scan;
+ worldSector_t *ws;
+
+ ent = SV_SvEntityForGentity(gEnt);
+
+ gEnt->r.linked = qfalse;
+
+ ws = ent->worldSector;
+ if (!ws)
+ {
+ return; // not linked in anywhere
+ }
+ ent->worldSector = NULL;
+
+ if (ws->entities == ent)
+ {
+ ws->entities = ent->nextEntityInWorldSector;
+ return;
+ }
+
+ for (scan = ws->entities; scan; scan = scan->nextEntityInWorldSector)
+ {
+ if (scan->nextEntityInWorldSector == ent)
+ {
+ scan->nextEntityInWorldSector = ent->nextEntityInWorldSector;
+ return;
+ }
+ }
+
+ Com_Printf("WARNING: SV_UnlinkEntity: not found in worldSector\n");
+}
+
+/*
+===============
+SV_LinkEntity
+
+===============
+*/
+#define MAX_TOTAL_ENT_LEAFS 128
+void SV_LinkEntity(sharedEntity_t *gEnt)
+{
+ worldSector_t *node;
+ int leafs[MAX_TOTAL_ENT_LEAFS];
+ int cluster;
+ int num_leafs;
+ int i, j, k;
+ int area;
+ int lastLeaf;
+ float *origin, *angles;
+ svEntity_t *ent;
+
+ ent = SV_SvEntityForGentity(gEnt);
+
+ if (ent->worldSector)
+ {
+ SV_UnlinkEntity(gEnt); // unlink from old position
+ }
+
+ // encode the size into the entityState_t for client prediction
+ if (gEnt->r.bmodel)
+ {
+ gEnt->s.solid = SOLID_BMODEL; // a solid_box will never create this value
+ }
+ else if (gEnt->r.contents & (CONTENTS_SOLID | CONTENTS_BODY))
+ {
+ // assume that x/y are equal and symetric
+ i = gEnt->r.maxs[0];
+ if (i < 1) i = 1;
+ if (i > 255) i = 255;
+
+ // z is not symetric
+ j = (-gEnt->r.mins[2]);
+ if (j < 1) j = 1;
+ if (j > 255) j = 255;
+
+ // and z maxs can be negative...
+ k = (gEnt->r.maxs[2] + 32);
+ if (k < 1) k = 1;
+ if (k > 255) k = 255;
+
+ gEnt->s.solid = (k << 16) | (j << 8) | i;
+ }
+ else
+ {
+ gEnt->s.solid = 0;
+ }
+
+ // get the position
+ origin = gEnt->r.currentOrigin;
+ angles = gEnt->r.currentAngles;
+
+ // set the abs box
+ if (gEnt->r.bmodel && (angles[0] || angles[1] || angles[2]))
+ {
+ // expand for rotation
+ float max;
+
+ max = RadiusFromBounds(gEnt->r.mins, gEnt->r.maxs);
+ for (i = 0; i < 3; i++)
+ {
+ gEnt->r.absmin[i] = origin[i] - max;
+ gEnt->r.absmax[i] = origin[i] + max;
+ }
+ }
+ else
+ {
+ // normal
+ VectorAdd(origin, gEnt->r.mins, gEnt->r.absmin);
+ VectorAdd(origin, gEnt->r.maxs, gEnt->r.absmax);
+ }
+
+ // because movement is clipped an epsilon away from an actual edge,
+ // we must fully check even when bounding boxes don't quite touch
+ gEnt->r.absmin[0] -= 1;
+ gEnt->r.absmin[1] -= 1;
+ gEnt->r.absmin[2] -= 1;
+ gEnt->r.absmax[0] += 1;
+ gEnt->r.absmax[1] += 1;
+ gEnt->r.absmax[2] += 1;
+
+ // link to PVS leafs
+ ent->numClusters = 0;
+ ent->lastCluster = 0;
+ ent->areanum = -1;
+ ent->areanum2 = -1;
+
+ // get all leafs, including solids
+ num_leafs = CM_BoxLeafnums(gEnt->r.absmin, gEnt->r.absmax, leafs, MAX_TOTAL_ENT_LEAFS, &lastLeaf);
+
+ // if none of the leafs were inside the map, the
+ // entity is outside the world and can be considered unlinked
+ if (!num_leafs)
+ {
+ return;
+ }
+
+ // set areas, even from clusters that don't fit in the entity array
+ for (i = 0; i < num_leafs; i++)
+ {
+ area = CM_LeafArea(leafs[i]);
+ if (area != -1)
+ {
+ // doors may legally straggle two areas,
+ // but nothing should evern need more than that
+ if (ent->areanum != -1 && ent->areanum != area)
+ {
+ if (ent->areanum2 != -1 && ent->areanum2 != area && sv.state == SS_LOADING)
+ {
+ Com_DPrintf("Object %i touching 3 areas at %f %f %f\n", gEnt->s.number, gEnt->r.absmin[0],
+ gEnt->r.absmin[1], gEnt->r.absmin[2]);
+ }
+ ent->areanum2 = area;
+ }
+ else
+ {
+ ent->areanum = area;
+ }
+ }
+ }
+
+ // store as many explicit clusters as we can
+ ent->numClusters = 0;
+ for (i = 0; i < num_leafs; i++)
+ {
+ cluster = CM_LeafCluster(leafs[i]);
+ if (cluster != -1)
+ {
+ ent->clusternums[ent->numClusters++] = cluster;
+ if (ent->numClusters == MAX_ENT_CLUSTERS)
+ {
+ break;
+ }
+ }
+ }
+
+ // store off a last cluster if we need to
+ if (i != num_leafs)
+ {
+ ent->lastCluster = CM_LeafCluster(lastLeaf);
+ }
+
+ gEnt->r.linkcount++;
+
+ // find the first world sector node that the ent's box crosses
+ node = sv_worldSectors;
+ for ( ;; )
+ {
+ if (node->axis == -1)
+ break;
+
+ if (gEnt->r.absmin[node->axis] > node->dist)
+ node = node->children[0];
+ else if (gEnt->r.absmax[node->axis] < node->dist)
+ node = node->children[1];
+ else
+ break; // crosses the node
+ }
+
+ // link it in
+ ent->worldSector = node;
+ ent->nextEntityInWorldSector = node->entities;
+ node->entities = ent;
+
+ gEnt->r.linked = qtrue;
+}
+
+/*
+============================================================================
+
+AREA QUERY
+
+Fills in a list of all entities who's absmin / absmax intersects the given
+bounds. This does NOT mean that they actually touch in the case of bmodels.
+============================================================================
+*/
+
+struct areaParms_t {
+ const float *mins;
+ const float *maxs;
+ int *list;
+ int count;
+ int maxcount;
+};
+
+/*
+====================
+SV_AreaEntities_r
+
+====================
+*/
+static void SV_AreaEntities_r(worldSector_t *node, areaParms_t *ap)
+{
+ svEntity_t *check, *next;
+ sharedEntity_t *gcheck;
+
+ for (check = node->entities; check; check = next)
+ {
+ next = check->nextEntityInWorldSector;
+
+ gcheck = SV_GEntityForSvEntity(check);
+
+ if (gcheck->r.absmin[0] > ap->maxs[0] || gcheck->r.absmin[1] > ap->maxs[1] ||
+ gcheck->r.absmin[2] > ap->maxs[2] || gcheck->r.absmax[0] < ap->mins[0] ||
+ gcheck->r.absmax[1] < ap->mins[1] || gcheck->r.absmax[2] < ap->mins[2])
+ {
+ continue;
+ }
+
+ if (ap->count == ap->maxcount)
+ {
+ Com_Printf("SV_AreaEntities: MAXCOUNT\n");
+ return;
+ }
+
+ ap->list[ap->count] = check - sv.svEntities;
+ ap->count++;
+ }
+
+ if (node->axis == -1)
+ {
+ return; // terminal node
+ }
+
+ // recurse down both sides
+ if (ap->maxs[node->axis] > node->dist)
+ {
+ SV_AreaEntities_r(node->children[0], ap);
+ }
+ if (ap->mins[node->axis] < node->dist)
+ {
+ SV_AreaEntities_r(node->children[1], ap);
+ }
+}
+
+/*
+================
+SV_AreaEntities
+================
+*/
+int SV_AreaEntities(const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount)
+{
+ areaParms_t ap;
+
+ ap.mins = mins;
+ ap.maxs = maxs;
+ ap.list = entityList;
+ ap.count = 0;
+ ap.maxcount = maxcount;
+
+ SV_AreaEntities_r(sv_worldSectors, &ap);
+
+ return ap.count;
+}
+
+//===========================================================================
+
+struct moveclip_t {
+ vec3_t boxmins;
+ vec3_t boxmaxs; // enclose the test object along entire move
+ const float *mins;
+ const float *maxs; // size of the moving object
+ const float *start;
+ vec3_t end;
+ trace_t trace;
+ int passEntityNum;
+ int contentmask;
+ traceType_t collisionType;
+};
+
+/*
+====================
+SV_ClipToEntity
+
+====================
+*/
+void SV_ClipToEntity(trace_t *trace, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
+ int entityNum, int contentmask, traceType_t type)
+{
+ sharedEntity_t *touch;
+ clipHandle_t clipHandle;
+ float *origin, *angles;
+
+ touch = SV_GentityNum(entityNum);
+
+ ::memset(trace, 0, sizeof(trace_t));
+
+ // if it doesn't have any brushes of a type we
+ // are looking for, ignore it
+ if (!(contentmask & touch->r.contents))
+ {
+ trace->fraction = 1.0;
+ return;
+ }
+
+ // might intersect, so do an exact clip
+ clipHandle = SV_ClipHandleForEntity(touch);
+
+ origin = touch->r.currentOrigin;
+ angles = touch->r.currentAngles;
+
+ if (!touch->r.bmodel)
+ {
+ angles = vec3_origin; // boxes don't rotate
+ }
+
+ CM_TransformedBoxTrace(trace, (float *)start, (float *)end, (float *)mins, (float *)maxs, clipHandle, contentmask,
+ origin, angles, type);
+
+ if (trace->fraction < 1)
+ {
+ trace->entityNum = touch->s.number;
+ }
+}
+
+/*
+====================
+SV_ClipMoveToEntities
+
+====================
+*/
+static void SV_ClipMoveToEntities(moveclip_t *clip)
+{
+ int i, num;
+ int touchlist[MAX_GENTITIES];
+ sharedEntity_t *touch;
+ int passOwnerNum;
+ trace_t trace;
+ clipHandle_t clipHandle;
+ float *origin, *angles;
+
+ num = SV_AreaEntities(clip->boxmins, clip->boxmaxs, touchlist, MAX_GENTITIES);
+
+ if (clip->passEntityNum != ENTITYNUM_NONE)
+ {
+ passOwnerNum = (SV_GentityNum(clip->passEntityNum))->r.ownerNum;
+ if (passOwnerNum == ENTITYNUM_NONE)
+ {
+ passOwnerNum = -1;
+ }
+ }
+ else
+ {
+ passOwnerNum = -1;
+ }
+
+ for (i = 0; i < num; i++)
+ {
+ if (clip->trace.allsolid)
+ {
+ return;
+ }
+ touch = SV_GentityNum(touchlist[i]);
+
+ // see if we should ignore this entity
+ if (clip->passEntityNum != ENTITYNUM_NONE)
+ {
+ if (touchlist[i] == clip->passEntityNum)
+ {
+ continue; // don't clip against the pass entity
+ }
+ if (touch->r.ownerNum == clip->passEntityNum)
+ {
+ continue; // don't clip against own missiles
+ }
+ if (touch->r.ownerNum == passOwnerNum)
+ {
+ continue; // don't clip against other missiles from our owner
+ }
+ }
+
+ // if it doesn't have any brushes of a type we
+ // are looking for, ignore it
+ if (!(clip->contentmask & touch->r.contents))
+ {
+ continue;
+ }
+
+ // might intersect, so do an exact clip
+ clipHandle = SV_ClipHandleForEntity(touch);
+
+ origin = touch->r.currentOrigin;
+ angles = touch->r.currentAngles;
+
+ if (!touch->r.bmodel)
+ {
+ angles = vec3_origin; // boxes don't rotate
+ }
+
+ CM_TransformedBoxTrace(&trace, (float *)clip->start, (float *)clip->end, (float *)clip->mins,
+ (float *)clip->maxs, clipHandle, clip->contentmask, origin, angles, clip->collisionType);
+
+ if (trace.allsolid)
+ {
+ clip->trace.allsolid = qtrue;
+ trace.entityNum = touch->s.number;
+ }
+ else if (trace.startsolid)
+ {
+ clip->trace.startsolid = qtrue;
+ trace.entityNum = touch->s.number;
+ }
+
+ if (trace.fraction < clip->trace.fraction)
+ {
+ int oldStart;
+
+ // make sure we keep a startsolid from a previous trace
+ oldStart = clip->trace.startsolid;
+
+ trace.entityNum = touch->s.number;
+ clip->trace = trace;
+ clip->trace.startsolid |= oldStart;
+ }
+ }
+}
+
+/*
+==================
+SV_Trace
+
+Moves the given mins/maxs volume through the world from start to end.
+passEntityNum and entities owned by passEntityNum are explicitly not checked.
+==================
+*/
+void SV_Trace(trace_t *results, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int passEntityNum,
+ int contentmask, traceType_t type)
+{
+ moveclip_t clip;
+ int i;
+
+ if (!mins)
+ {
+ mins = vec3_origin;
+ }
+ if (!maxs)
+ {
+ maxs = vec3_origin;
+ }
+
+ ::memset(&clip, 0, sizeof(moveclip_t));
+
+ // clip to world
+ CM_BoxTrace(&clip.trace, start, end, mins, maxs, 0, contentmask, type);
+ clip.trace.entityNum = clip.trace.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
+ if (clip.trace.fraction == 0)
+ {
+ *results = clip.trace;
+ return; // blocked immediately by the world
+ }
+
+ clip.contentmask = contentmask;
+ clip.start = start;
+ // VectorCopy( clip.trace.endpos, clip.end );
+ VectorCopy(end, clip.end);
+ clip.mins = mins;
+ clip.maxs = maxs;
+ clip.passEntityNum = passEntityNum;
+ clip.collisionType = type;
+
+ // create the bounding box of the entire move
+ // we can limit it to the part of the move not
+ // already clipped off by the world, which can be
+ // a significant savings for line of sight and shot traces
+ for (i = 0; i < 3; i++)
+ {
+ if (end[i] > start[i])
+ {
+ clip.boxmins[i] = clip.start[i] + clip.mins[i] - 1;
+ clip.boxmaxs[i] = clip.end[i] + clip.maxs[i] + 1;
+ }
+ else
+ {
+ clip.boxmins[i] = clip.end[i] + clip.mins[i] - 1;
+ clip.boxmaxs[i] = clip.start[i] + clip.maxs[i] + 1;
+ }
+ }
+
+ // clip to other solid entities
+ SV_ClipMoveToEntities(&clip);
+
+ *results = clip.trace;
+}
+
+/*
+=============
+SV_PointContents
+=============
+*/
+int SV_PointContents(const vec3_t p, int passEntityNum)
+{
+ int touch[MAX_GENTITIES];
+ sharedEntity_t *hit;
+ int i, num;
+ int contents, c2;
+ clipHandle_t clipHandle;
+ float *angles;
+
+ // get base contents from world
+ contents = CM_PointContents(p, 0);
+
+ // or in contents from all the other entities
+ num = SV_AreaEntities(p, p, touch, MAX_GENTITIES);
+
+ for (i = 0; i < num; i++)
+ {
+ if (touch[i] == passEntityNum)
+ {
+ continue;
+ }
+ hit = SV_GentityNum(touch[i]);
+ // might intersect, so do an exact clip
+ clipHandle = SV_ClipHandleForEntity(hit);
+ angles = hit->r.currentAngles;
+ if (!hit->r.bmodel)
+ {
+ angles = vec3_origin; // boxes don't rotate
+ }
+
+ c2 = CM_TransformedPointContents(p, clipHandle, hit->r.currentOrigin, angles);
+
+ contents |= c2;
+ }
+
+ return contents;
+}
diff --git a/src/sys/CMakeLists.txt b/src/sys/CMakeLists.txt
new file mode 100644
index 0000000..5d7ae9b
--- /dev/null
+++ b/src/sys/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_library (
+ sys STATIC
+ con_log.cpp
+ con_passive.cpp
+ con_tty.cpp
+ con_win32.cpp
+ sys_loadlib.h
+ sys_local.h
+ sys_main.cpp
+ sys_unix.cpp
+ sys_win32.cpp
+ win_resource.h
+)
+
+set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14" )
diff --git a/src/sys/con_log.cpp b/src/sys/con_log.cpp
new file mode 100644
index 0000000..eaa81b0
--- /dev/null
+++ b/src/sys/con_log.cpp
@@ -0,0 +1,132 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "sys_local.h"
+
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+#define MAX_LOG 32768
+
+static char consoleLog[ MAX_LOG ];
+static unsigned int writePos = 0;
+static unsigned int readPos = 0;
+
+/*
+==================
+CON_LogSize
+==================
+*/
+unsigned int CON_LogSize( void )
+{
+ if( readPos <= writePos )
+ return writePos - readPos;
+ else
+ return writePos + MAX_LOG - readPos;
+}
+
+/*
+==================
+CON_LogFree
+==================
+*/
+static unsigned int CON_LogFree( void )
+{
+ return MAX_LOG - CON_LogSize( ) - 1;
+}
+
+/*
+==================
+CON_LogWrite
+==================
+*/
+unsigned int CON_LogWrite( const char *in )
+{
+ unsigned int length = strlen( in );
+ unsigned int firstChunk;
+ unsigned int secondChunk;
+
+ while( CON_LogFree( ) < length && CON_LogSize( ) > 0 )
+ {
+ // Free enough space
+ while( consoleLog[ readPos ] != '\n' && CON_LogSize( ) > 1 )
+ readPos = ( readPos + 1 ) % MAX_LOG;
+
+ // Skip past the '\n'
+ readPos = ( readPos + 1 ) % MAX_LOG;
+ }
+
+ if( CON_LogFree( ) < length )
+ return 0;
+
+ if( writePos + length > MAX_LOG )
+ {
+ firstChunk = MAX_LOG - writePos;
+ secondChunk = length - firstChunk;
+ }
+ else
+ {
+ firstChunk = length;
+ secondChunk = 0;
+ }
+
+ Com_Memcpy( consoleLog + writePos, in, firstChunk );
+ Com_Memcpy( consoleLog, in + firstChunk, secondChunk );
+
+ writePos = ( writePos + length ) % MAX_LOG;
+
+ return length;
+}
+
+/*
+==================
+CON_LogRead
+==================
+*/
+unsigned int CON_LogRead( char *out, unsigned int outSize )
+{
+ unsigned int firstChunk;
+ unsigned int secondChunk;
+
+ if( CON_LogSize( ) < outSize )
+ outSize = CON_LogSize( );
+
+ if( readPos + outSize > MAX_LOG )
+ {
+ firstChunk = MAX_LOG - readPos;
+ secondChunk = outSize - firstChunk;
+ }
+ else
+ {
+ firstChunk = outSize;
+ secondChunk = 0;
+ }
+
+ Com_Memcpy( out, consoleLog + readPos, firstChunk );
+ Com_Memcpy( out + firstChunk, out, secondChunk );
+
+ readPos = ( readPos + outSize ) % MAX_LOG;
+
+ return outSize;
+}
diff --git a/src/sys/con_passive.cpp b/src/sys/con_passive.cpp
new file mode 100644
index 0000000..35918e5
--- /dev/null
+++ b/src/sys/con_passive.cpp
@@ -0,0 +1,72 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "sys_local.h"
+
+#include "qcommon/cvar.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+#include <stdio.h>
+
+/*
+==================
+CON_Shutdown
+==================
+*/
+void CON_Shutdown( void )
+{
+}
+
+/*
+==================
+CON_Init
+==================
+*/
+void CON_Init( void )
+{
+}
+
+/*
+==================
+CON_Input
+==================
+*/
+char *CON_Input( void )
+{
+ return NULL;
+}
+
+/*
+==================
+CON_Print
+==================
+*/
+void CON_Print( const char *msg )
+{
+ if( com_ansiColor && com_ansiColor->integer )
+ Sys_AnsiColorPrint( msg );
+ else
+ fputs( msg, stderr );
+}
diff --git a/src/sys/con_tty.cpp b/src/sys/con_tty.cpp
new file mode 100644
index 0000000..660c160
--- /dev/null
+++ b/src/sys/con_tty.cpp
@@ -0,0 +1,552 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "sys_local.h"
+
+#include <fcntl.h>
+#include <sys/time.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <csignal>
+
+#ifndef DEDICATED
+#include "client/client.h"
+#endif
+#include "qcommon/cvar.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+/*
+=============================================================
+tty console routines
+
+NOTE: if the user is editing a line when something gets printed to the early
+console then it won't look good so we provide CON_Hide and CON_Show to be
+called before and after a stdout or stderr output
+=============================================================
+*/
+
+extern bool stdinIsATTY;
+
+static bool stdin_active = false;
+// general flag to tell about tty console mode
+static bool ttycon_on = false;
+static int ttycon_hide = 0;
+static int ttycon_show_overdue = 0;
+
+// some key codes that the terminal may be using, initialised on start up
+static int TTY_erase;
+static int TTY_eof;
+
+static struct termios TTY_tc;
+
+static field_t TTY_con;
+
+// This is somewhat of aduplicate of the graphical console history
+// but it's safer more modular to have our own here
+#define CON_HISTORY 32
+static field_t ttyEditLines[ CON_HISTORY ];
+static int hist_current = -1, hist_count = 0;
+
+#ifndef DEDICATED
+// Don't use "]" as it would be the same as in-game console,
+// this makes it clear where input came from.
+#define TTY_CONSOLE_PROMPT "tty]"
+#else
+#define TTY_CONSOLE_PROMPT "]"
+#endif
+
+/*
+==================
+CON_FlushIn
+
+Flush stdin, I suspect some terminals are sending a LOT of shit
+FIXME relevant?
+==================
+*/
+static void CON_FlushIn( void )
+{
+ char key;
+ while (read(STDIN_FILENO, &key, 1)!=-1);
+}
+
+/*
+==================
+CON_Back
+
+Output a backspace
+
+NOTE: it seems on some terminals just sending '\b' is not enough so instead we
+send "\b \b"
+(FIXME there may be a way to find out if '\b' alone would work though)
+==================
+*/
+static void CON_Back( void )
+{
+ char key;
+ size_t UNUSED_VAR size;
+
+ key = '\b';
+ size = write(STDOUT_FILENO, &key, 1);
+ key = ' ';
+ size = write(STDOUT_FILENO, &key, 1);
+ key = '\b';
+ size = write(STDOUT_FILENO, &key, 1);
+}
+
+/*
+==================
+CON_Hide
+
+Clear the display of the line currently edited
+bring cursor back to beginning of line
+==================
+*/
+static void CON_Hide( void )
+{
+ if( ttycon_on )
+ {
+ int i;
+ if (ttycon_hide)
+ {
+ ttycon_hide++;
+ return;
+ }
+ if (TTY_con.cursor>0)
+ {
+ for (i=0; i<TTY_con.cursor; i++)
+ {
+ CON_Back();
+ }
+ }
+ // Delete prompt
+ for (i = strlen(TTY_CONSOLE_PROMPT); i > 0; i--) {
+ CON_Back();
+ }
+ ttycon_hide++;
+ }
+}
+
+/*
+==================
+CON_Show
+
+Show the current line
+FIXME need to position the cursor if needed?
+==================
+*/
+static void CON_Show( void )
+{
+ if( ttycon_on )
+ {
+ int i;
+
+ assert(ttycon_hide>0);
+ ttycon_hide--;
+ if (ttycon_hide == 0)
+ {
+ size_t UNUSED_VAR size;
+ size = write(STDOUT_FILENO, TTY_CONSOLE_PROMPT, strlen(TTY_CONSOLE_PROMPT));
+ if (TTY_con.cursor)
+ {
+ for (i=0; i<TTY_con.cursor; i++)
+ {
+ size = write(STDOUT_FILENO, TTY_con.buffer+i, 1);
+ }
+ }
+ }
+ }
+}
+
+/*
+==================
+CON_Shutdown
+
+Never exit without calling this, or your terminal will be left in a pretty bad state
+==================
+*/
+void CON_Shutdown( void )
+{
+ if (ttycon_on)
+ {
+ CON_Hide();
+ tcsetattr (STDIN_FILENO, TCSADRAIN, &TTY_tc);
+ }
+
+ // Restore blocking to stdin reads
+ fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
+}
+
+/*
+==================
+Hist_Add
+==================
+*/
+void Hist_Add(field_t *field)
+{
+ int i;
+
+ // Don't save blank lines in history.
+ if (!field->cursor)
+ return;
+
+ assert(hist_count <= CON_HISTORY);
+ assert(hist_count >= 0);
+ assert(hist_current >= -1);
+ assert(hist_current <= hist_count);
+ // make some room
+ for (i=CON_HISTORY-1; i>0; i--)
+ {
+ ttyEditLines[i] = ttyEditLines[i-1];
+ }
+ ttyEditLines[0] = *field;
+ if (hist_count<CON_HISTORY)
+ {
+ hist_count++;
+ }
+ hist_current = -1; // re-init
+}
+
+/*
+==================
+Hist_Prev
+==================
+*/
+field_t *Hist_Prev( void )
+{
+ int hist_prev;
+ assert(hist_count <= CON_HISTORY);
+ assert(hist_count >= 0);
+ assert(hist_current >= -1);
+ assert(hist_current <= hist_count);
+ hist_prev = hist_current + 1;
+ if (hist_prev >= hist_count)
+ {
+ return NULL;
+ }
+ hist_current++;
+ return &(ttyEditLines[hist_current]);
+}
+
+/*
+==================
+Hist_Next
+==================
+*/
+field_t *Hist_Next( void )
+{
+ assert(hist_count <= CON_HISTORY);
+ assert(hist_count >= 0);
+ assert(hist_current >= -1);
+ assert(hist_current <= hist_count);
+ if (hist_current >= 0)
+ {
+ hist_current--;
+ }
+ if (hist_current == -1)
+ {
+ return NULL;
+ }
+ return &(ttyEditLines[hist_current]);
+}
+
+/*
+==================
+CON_SigCont
+Reinitialize console input after receiving SIGCONT, as on Linux the terminal seems to lose all
+set attributes if user did CTRL+Z and then does fg again.
+==================
+*/
+
+void CON_SigCont(int signum)
+{
+ CON_Init();
+}
+
+/*
+==================
+CON_Init
+
+Initialize the console input (tty mode if possible)
+==================
+*/
+void CON_Init( void )
+{
+ struct termios tc;
+
+ // If the process is backgrounded (running non interactively)
+ // then SIGTTIN or SIGTOU is emitted, if not caught, turns into a SIGSTP
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+
+ // If SIGCONT is received, reinitialize console
+ signal(SIGCONT, CON_SigCont);
+
+ // Make stdin reads non-blocking
+ fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK );
+
+ if (!stdinIsATTY)
+ {
+ Com_Printf("tty console mode disabled\n");
+ ttycon_on = false;
+ stdin_active = true;
+ return;
+ }
+
+ Field_Clear(&TTY_con);
+ tcgetattr (STDIN_FILENO, &TTY_tc);
+ TTY_erase = TTY_tc.c_cc[VERASE];
+ TTY_eof = TTY_tc.c_cc[VEOF];
+ tc = TTY_tc;
+
+ /*
+ ECHO: don't echo input characters
+ ICANON: enable canonical mode. This enables the special
+ characters EOF, EOL, EOL2, ERASE, KILL, REPRINT,
+ STATUS, and WERASE, and buffers by lines.
+ ISIG: when any of the characters INTR, QUIT, SUSP, or
+ DSUSP are received, generate the corresponding signal
+ */
+ tc.c_lflag &= ~(ECHO | ICANON);
+
+ /*
+ ISTRIP strip off bit 8
+ INPCK enable input parity checking
+ */
+ tc.c_iflag &= ~(ISTRIP | INPCK);
+ tc.c_cc[VMIN] = 1;
+ tc.c_cc[VTIME] = 0;
+ tcsetattr (STDIN_FILENO, TCSADRAIN, &tc);
+ ttycon_on = true;
+ ttycon_hide = 1; // Mark as hidden, so prompt is shown in CON_Show
+ CON_Show();
+}
+
+/*
+==================
+CON_Input
+==================
+*/
+char *CON_Input( void )
+{
+ // we use this when sending back commands
+ static char text[MAX_EDIT_LINE];
+ int avail;
+ char key;
+ field_t *history;
+ size_t UNUSED_VAR size;
+
+ if(ttycon_on)
+ {
+ avail = read(STDIN_FILENO, &key, 1);
+ if (avail != -1)
+ {
+ // we have something
+ // backspace?
+ // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere
+ if ((key == TTY_erase) || (key == 127) || (key == 8))
+ {
+ if (TTY_con.cursor > 0)
+ {
+ TTY_con.cursor--;
+ TTY_con.buffer[TTY_con.cursor] = '\0';
+ CON_Back();
+ }
+ return NULL;
+ }
+ // check if this is a control char
+ if ((key) && (key) < ' ')
+ {
+ if (key == '\n')
+ {
+#ifndef DEDICATED
+ // if not in the game explicitly prepend a slash if needed
+ if (clc.state != CA_ACTIVE && TTY_con.cursor &&
+ TTY_con.buffer[0] != '/' && TTY_con.buffer[0] != '\\')
+ {
+ memmove(TTY_con.buffer + 1, TTY_con.buffer, sizeof(TTY_con.buffer) - 1);
+ TTY_con.buffer[0] = '\\';
+ TTY_con.cursor++;
+ }
+
+ if (TTY_con.buffer[0] == '/' || TTY_con.buffer[0] == '\\') {
+ Q_strncpyz(text, TTY_con.buffer + 1, sizeof(text));
+ } else if (TTY_con.cursor) {
+ Com_sprintf(text, sizeof(text), "cmd say %s", TTY_con.buffer);
+ } else {
+ text[0] = '\0';
+ }
+
+ // push it in history
+ Hist_Add(&TTY_con);
+ CON_Hide();
+ Com_Printf("%s%s\n", TTY_CONSOLE_PROMPT, TTY_con.buffer);
+ Field_Clear(&TTY_con);
+ CON_Show();
+#else
+ // push it in history
+ Hist_Add(&TTY_con);
+ Q_strncpyz(text, TTY_con.buffer, sizeof(text));
+ Field_Clear(&TTY_con);
+ key = '\n';
+ size = write(STDOUT_FILENO, &key, 1);
+ size = write(STDOUT_FILENO, TTY_CONSOLE_PROMPT, strlen(TTY_CONSOLE_PROMPT));
+#endif
+ return text;
+ }
+ if (key == '\t')
+ {
+ CON_Hide();
+ Field_AutoComplete( &TTY_con );
+ CON_Show();
+ return NULL;
+ }
+ avail = read(STDIN_FILENO, &key, 1);
+ if (avail != -1)
+ {
+ // VT 100 keys
+ if (key == '[' || key == 'O')
+ {
+ avail = read(STDIN_FILENO, &key, 1);
+ if (avail != -1)
+ {
+ switch (key)
+ {
+ case 'A':
+ history = Hist_Prev();
+ if (history)
+ {
+ CON_Hide();
+ TTY_con = *history;
+ CON_Show();
+ }
+ CON_FlushIn();
+ return NULL;
+ break;
+ case 'B':
+ history = Hist_Next();
+ CON_Hide();
+ if (history)
+ {
+ TTY_con = *history;
+ } else
+ {
+ Field_Clear(&TTY_con);
+ }
+ CON_Show();
+ CON_FlushIn();
+ return NULL;
+ break;
+ case 'C':
+ return NULL;
+ case 'D':
+ return NULL;
+ }
+ }
+ }
+ }
+ Com_DPrintf("droping ISCTL sequence: %d, TTY_erase: %d\n", key, TTY_erase);
+ CON_FlushIn();
+ return NULL;
+ }
+ if (TTY_con.cursor >= sizeof(text) - 1)
+ return NULL;
+ // push regular character
+ TTY_con.buffer[TTY_con.cursor] = key;
+ TTY_con.cursor++; // next char will always be '\0'
+ // print the current line (this is differential)
+ size = write(STDOUT_FILENO, &key, 1);
+ }
+
+ return NULL;
+ }
+ else if (stdin_active)
+ {
+ int len;
+ fd_set fdset;
+ struct timeval timeout;
+
+ FD_ZERO(&fdset);
+ FD_SET(STDIN_FILENO, &fdset); // stdin
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ if(select (STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(STDIN_FILENO, &fdset))
+ return NULL;
+
+ len = read(STDIN_FILENO, text, sizeof(text));
+ if (len == 0)
+ { // eof!
+ stdin_active = false;
+ return NULL;
+ }
+
+ if (len < 1)
+ return NULL;
+ text[len-1] = 0; // rip off the /n and terminate
+
+ return text;
+ }
+ return NULL;
+}
+
+/*
+==================
+CON_Print
+==================
+*/
+void CON_Print( const char *msg )
+{
+ if (!msg[0])
+ return;
+
+ CON_Hide( );
+
+ if( com_ansiColor && com_ansiColor->integer )
+ Sys_AnsiColorPrint( msg );
+ else
+ fputs( msg, stderr );
+
+ if (!ttycon_on) {
+ // CON_Hide didn't do anything.
+ return;
+ }
+
+ // Only print prompt when msg ends with a newline, otherwise the console
+ // might get garbled when output does not fit on one line.
+ if (msg[strlen(msg) - 1] == '\n') {
+ CON_Show();
+
+ // Run CON_Show the number of times it was deferred.
+ while (ttycon_show_overdue > 0) {
+ CON_Show();
+ ttycon_show_overdue--;
+ }
+ }
+ else
+ {
+ // Defer calling CON_Show
+ ttycon_show_overdue++;
+ }
+}
diff --git a/src/sys/con_win32.cpp b/src/sys/con_win32.cpp
new file mode 100644
index 0000000..8d8783a
--- /dev/null
+++ b/src/sys/con_win32.cpp
@@ -0,0 +1,558 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "sys_local.h"
+
+#include <windows.h>
+
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+#define QCONSOLE_HISTORY 32
+
+static WORD qconsole_attrib;
+static WORD qconsole_backgroundAttrib;
+
+// saved console status
+static DWORD qconsole_orig_mode;
+static CONSOLE_CURSOR_INFO qconsole_orig_cursorinfo;
+
+// cmd history
+static char qconsole_history[ QCONSOLE_HISTORY ][ MAX_EDIT_LINE ];
+static int qconsole_history_pos = -1;
+static int qconsole_history_lines = 0;
+static int qconsole_history_oldest = 0;
+
+// current edit buffer
+static char qconsole_line[ MAX_EDIT_LINE ];
+static int qconsole_linelen = 0;
+static bool qconsole_drawinput = true;
+static int qconsole_cursor;
+
+static HANDLE qconsole_hout;
+static HANDLE qconsole_hin;
+
+/*
+==================
+CON_ColorCharToAttrib
+
+Convert Quake color character to Windows text attrib
+==================
+*/
+static WORD CON_ColorCharToAttrib( char color ) {
+ WORD attrib;
+
+ if ( color == COLOR_WHITE )
+ {
+ // use console's foreground and background colors
+ attrib = qconsole_attrib;
+ }
+ else
+ {
+ float *rgba = g_color_table[ ColorIndex( color ) ];
+
+ // set foreground color
+ attrib = ( rgba[0] >= 0.5 ? FOREGROUND_RED : 0 ) |
+ ( rgba[1] >= 0.5 ? FOREGROUND_GREEN : 0 ) |
+ ( rgba[2] >= 0.5 ? FOREGROUND_BLUE : 0 ) |
+ ( rgba[3] >= 0.5 ? FOREGROUND_INTENSITY : 0 );
+
+ // use console's background color
+ attrib |= qconsole_backgroundAttrib;
+ }
+
+ return attrib;
+}
+
+/*
+==================
+CON_CtrlHandler
+
+The Windows Console doesn't use signals for terminating the application
+with Ctrl-C, logging off, window closing, etc. Instead it uses a special
+handler routine. Fortunately, the values for Ctrl signals don't seem to
+overlap with true signal codes that Windows provides, so calling
+Sys_SigHandler() with those numbers should be safe for generating unique
+shutdown messages.
+==================
+*/
+static BOOL WINAPI CON_CtrlHandler( DWORD sig )
+{
+ Sys_SigHandler( sig );
+ return TRUE;
+}
+
+/*
+==================
+CON_HistAdd
+==================
+*/
+static void CON_HistAdd( void )
+{
+ Q_strncpyz( qconsole_history[ qconsole_history_oldest ], qconsole_line,
+ sizeof( qconsole_history[ qconsole_history_oldest ] ) );
+
+ if( qconsole_history_lines < QCONSOLE_HISTORY )
+ qconsole_history_lines++;
+
+ if( qconsole_history_oldest >= QCONSOLE_HISTORY - 1 )
+ qconsole_history_oldest = 0;
+ else
+ qconsole_history_oldest++;
+
+ qconsole_history_pos = qconsole_history_oldest;
+}
+
+/*
+==================
+CON_HistPrev
+==================
+*/
+static void CON_HistPrev( void )
+{
+ int pos;
+
+ pos = ( qconsole_history_pos < 1 ) ?
+ ( QCONSOLE_HISTORY - 1 ) : ( qconsole_history_pos - 1 );
+
+ // don' t allow looping through history
+ if( pos == qconsole_history_oldest || pos >= qconsole_history_lines )
+ return;
+
+ qconsole_history_pos = pos;
+ Q_strncpyz( qconsole_line, qconsole_history[ qconsole_history_pos ],
+ sizeof( qconsole_line ) );
+ qconsole_linelen = strlen( qconsole_line );
+ qconsole_cursor = qconsole_linelen;
+}
+
+/*
+==================
+CON_HistNext
+==================
+*/
+static void CON_HistNext( void )
+{
+ int pos;
+
+ // don' t allow looping through history
+ if( qconsole_history_pos == qconsole_history_oldest )
+ return;
+
+ pos = ( qconsole_history_pos >= QCONSOLE_HISTORY - 1 ) ?
+ 0 : ( qconsole_history_pos + 1 );
+
+ // clear the edit buffer if they try to advance to a future command
+ if( pos == qconsole_history_oldest )
+ {
+ qconsole_history_pos = pos;
+ qconsole_line[ 0 ] = '\0';
+ qconsole_linelen = 0;
+ qconsole_cursor = qconsole_linelen;
+ return;
+ }
+
+ qconsole_history_pos = pos;
+ Q_strncpyz( qconsole_line, qconsole_history[ qconsole_history_pos ],
+ sizeof( qconsole_line ) );
+ qconsole_linelen = strlen( qconsole_line );
+ qconsole_cursor = qconsole_linelen;
+}
+
+
+/*
+==================
+CON_Show
+==================
+*/
+static void CON_Show( void )
+{
+ CONSOLE_SCREEN_BUFFER_INFO binfo;
+ COORD writeSize = { MAX_EDIT_LINE, 1 };
+ COORD writePos = { 0, 0 };
+ SMALL_RECT writeArea = { 0, 0, 0, 0 };
+ COORD cursorPos;
+ int i;
+ CHAR_INFO line[ MAX_EDIT_LINE ];
+ WORD attrib;
+
+ GetConsoleScreenBufferInfo( qconsole_hout, &binfo );
+
+ // if we're in the middle of printf, don't bother writing the buffer
+ if( !qconsole_drawinput )
+ return;
+
+ writeArea.Left = 0;
+ writeArea.Top = binfo.dwCursorPosition.Y;
+ writeArea.Bottom = binfo.dwCursorPosition.Y;
+ writeArea.Right = MAX_EDIT_LINE;
+
+ // set color to white
+ attrib = CON_ColorCharToAttrib( COLOR_WHITE );
+
+ // build a space-padded CHAR_INFO array
+ for( i = 0; i < MAX_EDIT_LINE; i++ )
+ {
+ if( i < qconsole_linelen )
+ {
+ if( i + 1 < qconsole_linelen && Q_IsColorString( qconsole_line + i ) )
+ attrib = CON_ColorCharToAttrib( *( qconsole_line + i + 1 ) );
+
+ line[ i ].Char.AsciiChar = qconsole_line[ i ];
+ }
+ else
+ line[ i ].Char.AsciiChar = ' ';
+
+ line[ i ].Attributes = attrib;
+ }
+
+ if( qconsole_linelen > binfo.srWindow.Right )
+ {
+ WriteConsoleOutput( qconsole_hout,
+ line + (qconsole_linelen - binfo.srWindow.Right ),
+ writeSize, writePos, &writeArea );
+ }
+ else
+ {
+ WriteConsoleOutput( qconsole_hout, line, writeSize,
+ writePos, &writeArea );
+ }
+
+ // set curor position
+ cursorPos.Y = binfo.dwCursorPosition.Y;
+ cursorPos.X = qconsole_cursor < qconsole_linelen
+ ? qconsole_cursor
+ : qconsole_linelen > binfo.srWindow.Right
+ ? binfo.srWindow.Right
+ : qconsole_linelen;
+
+ SetConsoleCursorPosition( qconsole_hout, cursorPos );
+}
+
+/*
+==================
+CON_Hide
+==================
+*/
+static void CON_Hide( void )
+{
+ int realLen;
+
+ realLen = qconsole_linelen;
+
+ // remove input line from console output buffer
+ qconsole_linelen = 0;
+ CON_Show( );
+
+ qconsole_linelen = realLen;
+}
+
+
+/*
+==================
+CON_Shutdown
+==================
+*/
+void CON_Shutdown( void )
+{
+ CON_Hide( );
+ SetConsoleMode( qconsole_hin, qconsole_orig_mode );
+ SetConsoleCursorInfo( qconsole_hout, &qconsole_orig_cursorinfo );
+ SetConsoleTextAttribute( qconsole_hout, qconsole_attrib );
+ CloseHandle( qconsole_hout );
+ CloseHandle( qconsole_hin );
+}
+
+/*
+==================
+CON_Init
+==================
+*/
+void CON_Init( void )
+{
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ int i;
+
+ // handle Ctrl-C or other console termination
+ SetConsoleCtrlHandler( CON_CtrlHandler, TRUE );
+
+ qconsole_hin = GetStdHandle( STD_INPUT_HANDLE );
+ if( qconsole_hin == INVALID_HANDLE_VALUE )
+ return;
+
+ qconsole_hout = GetStdHandle( STD_OUTPUT_HANDLE );
+ if( qconsole_hout == INVALID_HANDLE_VALUE )
+ return;
+
+ GetConsoleMode( qconsole_hin, &qconsole_orig_mode );
+
+ // allow mouse wheel scrolling
+ SetConsoleMode( qconsole_hin,
+ qconsole_orig_mode & ~ENABLE_MOUSE_INPUT );
+
+ FlushConsoleInputBuffer( qconsole_hin );
+
+ GetConsoleScreenBufferInfo( qconsole_hout, &info );
+ qconsole_attrib = info.wAttributes;
+ qconsole_backgroundAttrib = qconsole_attrib & (BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_RED|BACKGROUND_INTENSITY);
+
+ SetConsoleTitle("Tremulous Dedicated Server Console");
+
+ // initialize history
+ for( i = 0; i < QCONSOLE_HISTORY; i++ )
+ qconsole_history[ i ][ 0 ] = '\0';
+
+ // set text color to white
+ SetConsoleTextAttribute( qconsole_hout, CON_ColorCharToAttrib( COLOR_WHITE ) );
+}
+
+/*
+==================
+CON_Input
+==================
+*/
+char *CON_Input( void )
+{
+ INPUT_RECORD buff[ MAX_EDIT_LINE ];
+ DWORD count = 0, events = 0;
+ WORD key = 0;
+ int i;
+ int newlinepos = -1;
+
+ if( !GetNumberOfConsoleInputEvents( qconsole_hin, &events ) )
+ return NULL;
+
+ if( events < 1 )
+ return NULL;
+
+ // if we have overflowed, start dropping oldest input events
+ if( events >= MAX_EDIT_LINE )
+ {
+ ReadConsoleInput( qconsole_hin, buff, 1, &events );
+ return NULL;
+ }
+
+ if( !ReadConsoleInput( qconsole_hin, buff, events, &count ) )
+ return NULL;
+
+ FlushConsoleInputBuffer( qconsole_hin );
+
+ for( i = 0; i < count; i++ )
+ {
+ if( buff[ i ].EventType != KEY_EVENT )
+ continue;
+ if( !buff[ i ].Event.KeyEvent.bKeyDown )
+ continue;
+
+ key = buff[ i ].Event.KeyEvent.wVirtualKeyCode;
+
+ if( key == VK_RETURN )
+ {
+ newlinepos = i;
+ qconsole_cursor = 0;
+ break;
+ }
+ else if( key == VK_UP )
+ {
+ CON_HistPrev();
+ break;
+ }
+ else if( key == VK_DOWN )
+ {
+ CON_HistNext();
+ break;
+ }
+ else if( key == VK_LEFT )
+ {
+ qconsole_cursor--;
+ if ( qconsole_cursor < 0 )
+ {
+ qconsole_cursor = 0;
+ }
+ break;
+ }
+ else if( key == VK_RIGHT )
+ {
+ qconsole_cursor++;
+ if ( qconsole_cursor > qconsole_linelen )
+ {
+ qconsole_cursor = qconsole_linelen;
+ }
+ break;
+ }
+ else if( key == VK_HOME )
+ {
+ qconsole_cursor = 0;
+ break;
+ }
+ else if( key == VK_END )
+ {
+ qconsole_cursor = qconsole_linelen;
+ break;
+ }
+ else if( key == VK_TAB )
+ {
+ field_t f;
+
+ Q_strncpyz( f.buffer, qconsole_line,
+ sizeof( f.buffer ) );
+ Field_AutoComplete( &f );
+ Q_strncpyz( qconsole_line, f.buffer,
+ sizeof( qconsole_line ) );
+ qconsole_linelen = strlen( qconsole_line );
+ qconsole_cursor = qconsole_linelen;
+ break;
+ }
+
+ if( qconsole_linelen < sizeof( qconsole_line ) - 1 )
+ {
+ char c = buff[ i ].Event.KeyEvent.uChar.AsciiChar;
+
+ if( key == VK_BACK )
+ {
+ if ( qconsole_cursor > 0 )
+ {
+ int newlen = ( qconsole_linelen > 0 ) ? qconsole_linelen - 1 : 0;
+ if ( qconsole_cursor < qconsole_linelen )
+ {
+ memmove( qconsole_line + qconsole_cursor - 1,
+ qconsole_line + qconsole_cursor,
+ qconsole_linelen - qconsole_cursor );
+ }
+
+ qconsole_line[ newlen ] = '\0';
+ qconsole_linelen = newlen;
+ qconsole_cursor--;
+ }
+ }
+ else if( c )
+ {
+ if ( qconsole_linelen > qconsole_cursor )
+ {
+ memmove( qconsole_line + qconsole_cursor + 1,
+ qconsole_line + qconsole_cursor,
+ qconsole_linelen - qconsole_cursor );
+ }
+
+ qconsole_line[ qconsole_cursor++ ] = c;
+
+ qconsole_linelen++;
+ qconsole_line[ qconsole_linelen ] = '\0';
+ }
+ }
+ }
+
+ if( newlinepos < 0) {
+ CON_Show();
+ return NULL;
+ }
+
+ if( !qconsole_linelen )
+ {
+ CON_Show();
+ Com_Printf( "\n" );
+ return NULL;
+ }
+
+ qconsole_linelen = 0;
+ CON_Show();
+
+ CON_HistAdd();
+ Com_Printf( "%s\n", qconsole_line );
+
+ return qconsole_line;
+}
+
+/*
+=================
+CON_WindowsColorPrint
+
+Set text colors based on Q3 color codes
+=================
+*/
+void CON_WindowsColorPrint( const char *msg )
+{
+ static char buffer[ MAXPRINTMSG ];
+ int length = 0;
+
+ while( *msg )
+ {
+ qconsole_drawinput = ( *msg == '\n' );
+
+ if( Q_IsColorString( msg ) || *msg == '\n' )
+ {
+ // First empty the buffer
+ if( length > 0 )
+ {
+ buffer[ length ] = '\0';
+ fputs( buffer, stderr );
+ length = 0;
+ }
+
+ if( *msg == '\n' )
+ {
+ // Reset color and then add the newline
+ SetConsoleTextAttribute( qconsole_hout, CON_ColorCharToAttrib( COLOR_WHITE ) );
+ fputs( "\n", stderr );
+ msg++;
+ }
+ else
+ {
+ // Set the color
+ SetConsoleTextAttribute( qconsole_hout, CON_ColorCharToAttrib( *( msg + 1 ) ) );
+ msg += 2;
+ }
+ }
+ else
+ {
+ if( length >= MAXPRINTMSG - 1 )
+ break;
+
+ buffer[ length ] = *msg;
+ length++;
+ msg++;
+ }
+ }
+
+ // Empty anything still left in the buffer
+ if( length > 0 )
+ {
+ buffer[ length ] = '\0';
+ fputs( buffer, stderr );
+ }
+}
+
+/*
+==================
+CON_Print
+==================
+*/
+void CON_Print( const char *msg )
+{
+ CON_Hide( );
+
+ CON_WindowsColorPrint( msg );
+
+ CON_Show( );
+}
diff --git a/src/sys/dialog.h b/src/sys/dialog.h
new file mode 100644
index 0000000..b96368a
--- /dev/null
+++ b/src/sys/dialog.h
@@ -0,0 +1,40 @@
+// This file is part of Tremulous.
+// Copyright © 2016 Victor Roemer (blowfish) <victor@badsec.org>
+// Copyright (C) 2015-2019 GrangerHub
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+#ifndef SYS_DIALOG_H
+#define SYS_DIALOG_H
+
+enum dialogResult_t
+{
+ DR_YES = 0,
+ DR_NO = 1,
+ DR_OK = 0,
+ DR_CANCEL = 1
+};
+
+enum dialogType_t
+{
+ DT_INFO,
+ DT_WARNING,
+ DT_ERROR,
+ DT_YES_NO,
+ DT_OK_CANCEL
+};
+
+dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title );
+
+#endif
diff --git a/src/sys/sys_loadlib.h b/src/sys/sys_loadlib.h
new file mode 100644
index 0000000..10baebc
--- /dev/null
+++ b/src/sys/sys_loadlib.h
@@ -0,0 +1,57 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#ifndef _SYS_LOADLIB_H_
+#define _SYS_LOADLIB_H_
+
+#ifdef DEDICATED
+# ifdef _WIN32
+# include <windows.h>
+# define Sys_LoadLibrary(f) (void*)LoadLibrary(f)
+# define Sys_UnloadLibrary(h) FreeLibrary((HMODULE)h)
+# define Sys_LoadFunction(h,fn) (void*)GetProcAddress((HMODULE)h,fn)
+# define Sys_LibraryError() "unknown"
+# else
+# include <dlfcn.h>
+# define Sys_LoadLibrary(f) dlopen(f,RTLD_NOW)
+# define Sys_UnloadLibrary(h) dlclose(h)
+# define Sys_LoadFunction(h,fn) dlsym(h,fn)
+# define Sys_LibraryError() dlerror()
+# endif
+#else
+# ifdef USE_LOCAL_HEADERS
+# include "SDL.h"
+# include "SDL_loadso.h"
+# else
+# include <SDL.h>
+# include <SDL_loadso.h>
+# endif
+# define Sys_LoadLibrary(f) SDL_LoadObject(f)
+# define Sys_UnloadLibrary(h) SDL_UnloadObject(h)
+# define Sys_LoadFunction(h,fn) SDL_LoadFunction(h,fn)
+# define Sys_LibraryError() SDL_GetError()
+#endif
+
+void * QDECL Sys_LoadDll(const char *name, bool useSystemLib);
+
+#endif
diff --git a/src/sys/sys_local.h b/src/sys/sys_local.h
new file mode 100644
index 0000000..f309bfe
--- /dev/null
+++ b/src/sys/sys_local.h
@@ -0,0 +1,58 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+#ifndef _SYS_LOCAL_H_
+#define _SYS_LOCAL_H_
+
+#include "sys_shared.h"
+
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+
+// Require a minimum version of SDL
+#define MINSDL_MAJOR 2
+#define MINSDL_MINOR 0
+#define MINSDL_PATCH 0
+
+// Console
+void CON_Shutdown( void );
+void CON_Init( void );
+char *CON_Input( void );
+void CON_Print( const char *message );
+
+unsigned int CON_LogSize( void );
+unsigned int CON_LogWrite( const char *in );
+unsigned int CON_LogRead( char *out, unsigned int outSize );
+
+void Sys_GLimpSafeInit( void );
+void Sys_GLimpInit( void );
+void Sys_PlatformInit( void );
+void Sys_PlatformExit( void );
+void Sys_SigHandler( int signal ) __attribute__ ((noreturn));
+void Sys_ErrorDialog( const char *error );
+void Sys_AnsiColorPrint( const char *msg );
+
+int Sys_PID( void );
+bool Sys_PIDIsRunning( int pid );
+
+#endif
diff --git a/src/sys/sys_main.cpp b/src/sys/sys_main.cpp
new file mode 100644
index 0000000..efc1ecb
--- /dev/null
+++ b/src/sys/sys_main.cpp
@@ -0,0 +1,798 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "sys_local.h"
+
+#include <setjmp.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <cctype>
+#include <cerrno>
+#include <climits>
+#include <csignal>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cstring>
+#include <iostream>
+
+#include "lua.hpp"
+#include "sol.hpp"
+#ifndef DEDICATED
+#ifdef USE_LOCAL_HEADERS
+# include "SDL.h"
+# include "SDL_cpuinfo.h"
+#else
+# include <SDL.h>
+# include <SDL_cpuinfo.h>
+#endif
+#endif
+
+#include "qcommon/files.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+#include "qcommon/vm.h"
+#ifndef DEDICATED
+#include "script/bind.h"
+#include "script/client.h"
+#include "script/http_client.h"
+#endif
+#include "script/cmd.h"
+#include "script/cvar.h"
+#include "script/rapidjson.h"
+#include "script/nettle.h"
+
+#include "dialog.h"
+#include "sys_loadlib.h"
+
+sol::state lua;
+
+static char binaryPath[ MAX_OSPATH ] = { 0 };
+static char installPath[ MAX_OSPATH ] = { 0 };
+
+/*
+=================
+Sys_SetBinaryPath
+=================
+*/
+void Sys_SetBinaryPath(const char *path)
+{
+ Q_strncpyz(binaryPath, path, sizeof(binaryPath));
+}
+
+/*
+=================
+Sys_BinaryPath
+=================
+*/
+char *Sys_BinaryPath(void)
+{
+ return binaryPath;
+}
+
+/*
+=================
+Sys_SetDefaultInstallPath
+=================
+*/
+void Sys_SetDefaultInstallPath(const char *path)
+{
+ Q_strncpyz(installPath, path, sizeof(installPath));
+}
+
+/*
+=================
+Sys_DefaultInstallPath
+=================
+*/
+char *Sys_DefaultInstallPath(void)
+{
+ return installPath;
+}
+
+/*
+=================
+Sys_DefaultAppPath
+=================
+*/
+char *Sys_DefaultAppPath(void)
+{
+ return Sys_BinaryPath();
+}
+
+/*
+=================
+Sys_In_Restart_f
+
+Restart the input subsystem
+=================
+*/
+void Sys_In_Restart_f( void )
+{
+ IN_Restart( );
+}
+
+/*
+=================
+Sys_ConsoleInput
+
+Handle new console input
+=================
+*/
+char *Sys_ConsoleInput(void)
+{
+ return CON_Input( );
+}
+
+/*
+==================
+Sys_GetClipboardData
+==================
+*/
+char *Sys_GetClipboardData(void)
+{
+ char *data = NULL;
+#ifndef DEDICATED
+ char *cliptext;
+
+ if ( ( cliptext = SDL_GetClipboardText() ) != NULL ) {
+ if ( cliptext[0] != '\0' ) {
+ size_t bufsize = strlen( cliptext ) + 1;
+
+ data = (char*)Z_Malloc( bufsize );
+ Q_strncpyz( data, cliptext, bufsize );
+
+ // find first listed char and set to '\0'
+ strtok( data, "\n\r\b" );
+ }
+ SDL_free( cliptext );
+ }
+#endif
+ return data;
+}
+
+#ifdef DEDICATED
+# define PID_FILENAME PRODUCT_NAME "_server.pid"
+#else
+# define PID_FILENAME PRODUCT_NAME ".pid"
+#endif
+
+/*
+=================
+Sys_PIDFileName
+=================
+*/
+static std::string Sys_PIDFileName( void )
+{
+ const char *homePath = Cvar_VariableString( "fs_homepath" );
+ std::string pidfile;
+
+ if( *homePath != '\0' )
+ {
+ pidfile += homePath;
+ pidfile += "/";
+ pidfile += PID_FILENAME;
+ }
+
+ return pidfile;
+}
+
+/*
+=================
+Sys_WritePIDFile
+
+Return true if there is an existing stale PID file
+=================
+*/
+bool Sys_WritePIDFile( void )
+{
+ const char *pidFile = Sys_PIDFileName( ).c_str();
+ FILE *f;
+ bool stale = false;
+
+ if( pidFile == NULL )
+ return false;
+
+ // First, check if the pid file is already there
+ if( ( f = fopen( pidFile, "r" ) ) != NULL )
+ {
+ char pidBuffer[ 64 ] = { 0 };
+ int pid;
+
+ pid = fread( pidBuffer, sizeof( char ), sizeof( pidBuffer ) - 1, f );
+ fclose( f );
+
+ if(pid > 0)
+ {
+ pid = atoi( pidBuffer );
+ if( !Sys_PIDIsRunning( pid ) )
+ stale = true;
+ }
+ else
+ stale = true;
+ }
+
+ if( ( f = fopen( pidFile, "w" ) ) != NULL )
+ {
+ fprintf( f, "%d", Sys_PID( ) );
+ fclose( f );
+ }
+ else
+ Com_Printf( S_COLOR_YELLOW "Couldn't write %s.\n", pidFile );
+
+ return stale;
+}
+
+/*
+=================
+Sys_Exit
+
+Single exit point (regular exit or in case of error)
+=================
+*/
+static __attribute__ ((noreturn)) void Sys_Exit( int exitCode )
+{
+ CON_Shutdown( );
+
+#ifndef DEDICATED
+ SDL_Quit( );
+#endif
+
+ if( exitCode < 2 )
+ {
+ // Normal exit
+ const char *pidFile = Sys_PIDFileName( ).c_str();
+ if( pidFile != NULL )
+ remove( pidFile );
+ }
+
+ NET_Shutdown( );
+
+ Sys_PlatformExit( );
+
+ exit( exitCode );
+}
+
+/*
+=================
+Sys_Quit
+=================
+*/
+void Sys_Quit( void )
+{
+ Sys_Exit( 0 );
+}
+
+/*
+=================
+Sys_GetProcessorFeatures
+=================
+*/
+cpuFeatures_t Sys_GetProcessorFeatures( void )
+{
+ cpuFeatures_t features = CF_NONE;
+
+#ifndef DEDICATED
+ if( SDL_HasRDTSC( ) ) features |= CF_RDTSC;
+ if( SDL_Has3DNow( ) ) features |= CF_3DNOW;
+ if( SDL_HasMMX( ) ) features |= CF_MMX;
+ if( SDL_HasSSE( ) ) features |= CF_SSE;
+ if( SDL_HasSSE2( ) ) features |= CF_SSE2;
+ if( SDL_HasAltiVec( ) ) features |= CF_ALTIVEC;
+#endif
+
+ return features;
+}
+
+void Sys_Script_f( void )
+{
+ std::string args = Cmd_Args();
+ lua.script(args);
+}
+
+void Sys_ScriptFile_f( void )
+{
+ std::string args = Cmd_Args();
+ lua.script_file(args);
+}
+/*
+=================
+Sys_Init
+=================
+*/
+void Sys_Init(void)
+{
+ Cmd_AddCommand( "in_restart", Sys_In_Restart_f );
+ Cmd_AddCommand( "script", Sys_Script_f );
+ Cmd_AddCommand( "script_file", Sys_ScriptFile_f );
+ Cvar_Set( "arch", OS_STRING " " ARCH_STRING );
+ Cvar_Set( "username", "UnnamedPlayer" );
+}
+
+/*
+=================
+Sys_AnsiColorPrint
+Transform Q3 colour codes to ANSI escape sequences
+=================
+*/
+// FIXME -bbq This could be more extensible
+void Sys_AnsiColorPrint( const char *msg )
+{
+ static char buffer[ MAXPRINTMSG ];
+ int length = 0;
+ static int q3ToAnsi[ 8 ] =
+ {
+ 7, // COLOR_BLACK
+ 31, // COLOR_RED
+ 32, // COLOR_GREEN
+ 33, // COLOR_YELLOW
+ 34, // COLOR_BLUE
+ 36, // COLOR_CYAN
+ 35, // COLOR_MAGENTA
+ 0 // COLOR_WHITE
+ };
+
+ while( *msg )
+ {
+ if( Q_IsColorString( msg ) || *msg == '\n' )
+ {
+ // First empty the buffer
+ if( length > 0 )
+ {
+ buffer[ length ] = '\0';
+ fputs( buffer, stderr );
+ length = 0;
+ }
+
+ if( *msg == '\n' )
+ {
+ // Issue a reset and then the newline
+ fputs( "\033[0m\n", stderr );
+ msg++;
+ }
+ else
+ {
+ // Print the color code (reset first to clear potential inverse (black))
+ Com_sprintf( buffer, sizeof( buffer ), "\033[0m\033[%dm",
+ q3ToAnsi[ ColorIndex( *( msg + 1 ) ) ] );
+ fputs( buffer, stderr );
+ msg += 2;
+ }
+ }
+ else
+ {
+ if( length >= MAXPRINTMSG - 1 )
+ break;
+
+ buffer[ length ] = *msg;
+ length++;
+ msg++;
+ }
+ }
+
+ // Empty anything still left in the buffer
+ if( length > 0 )
+ {
+ buffer[ length ] = '\0';
+ fputs( buffer, stderr );
+ }
+}
+
+/*
+=================
+Sys_Print
+=================
+*/
+void Sys_Print( const char *msg )
+{
+ CON_LogWrite( msg );
+ CON_Print( msg );
+}
+
+/*
+=================
+Sys_Error
+=================
+*/
+void Sys_Error( const char *error, ... )
+{
+ va_list argptr;
+ char string[1024];
+
+ va_start (argptr,error);
+ Q_vsnprintf (string, sizeof(string), error, argptr);
+ va_end (argptr);
+
+ Sys_ErrorDialog( string );
+
+ Sys_Exit( 3 );
+}
+
+/*
+============
+Sys_FileTime
+
+returns -1 if not present
+============
+*/
+int Sys_FileTime( char *path )
+{
+ struct stat buf;
+
+ if (stat (path,&buf) == -1)
+ return -1;
+
+ return buf.st_mtime;
+}
+
+/*
+=================
+Sys_UnloadDll
+=================
+*/
+void Sys_UnloadDll( void *dllHandle )
+{
+ if( !dllHandle )
+ {
+ Com_Printf("Sys_UnloadDll(NULL)\n");
+ return;
+ }
+
+ Sys_UnloadLibrary(dllHandle);
+}
+
+/*
+=================
+Sys_LoadDll
+
+First try to load library name from system library path,
+from executable path, then fs_basepath.
+=================
+*/
+void *Sys_LoadDll(const char *name, bool useSystemLib)
+{
+ void *dllhandle;
+
+ if (!Sys_DllExtension(name))
+ {
+ Com_Printf("Refusing to load library \"%s\": Extension not allowed.\n", name);
+ return nullptr;
+ }
+
+ if(useSystemLib)
+ Com_Printf("Trying to load \"%s\"...\n", name);
+
+ if(!useSystemLib || !(dllhandle = Sys_LoadLibrary(name)))
+ {
+ const char *topDir;
+ char libPath[MAX_OSPATH];
+
+ topDir = Sys_BinaryPath();
+
+ if(!*topDir)
+ topDir = ".";
+
+ Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, topDir);
+
+ int len = Com_sprintf(libPath, sizeof(libPath), "%s%c%s", topDir, PATH_SEP, name);
+ if(len < sizeof(libPath))
+ {
+ Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, topDir);
+ dllhandle = Sys_LoadLibrary(libPath);
+ }
+ else
+ {
+ Com_Printf("Skipping trying to load \"%s\" from \"%s\", file name is too long.\n", name, topDir);
+ }
+
+ if (!dllhandle)
+ {
+ const char *basePath = Cvar_VariableString("fs_basepath");
+
+ if(!basePath || !*basePath)
+ basePath = ".";
+
+ if(FS_FilenameCompare(topDir, basePath))
+ {
+ Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, basePath);
+ len = Com_sprintf(libPath, sizeof(libPath), "%s%c%s", basePath, PATH_SEP, name);
+ if(len < sizeof(libPath))
+ {
+ Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, basePath);
+ dllhandle = Sys_LoadLibrary(libPath);
+ }
+ else
+ {
+ Com_Printf("Skipping trying to load \"%s\" from \"%s\", file name is too long.\n", name, basePath);
+ }
+ }
+
+ if(!dllhandle)
+ Com_Printf("Loading \"%s\" failed\n", name);
+ }
+ }
+
+ return dllhandle;
+}
+
+/*
+=================
+Sys_LoadGameDll
+
+Used to load a development dll instead of a virtual machine
+=================
+*/
+using Entry = void (*)(intptr_t (*syscallptr)(intptr_t, ...));
+using EntryPoint = intptr_t (QDECL *)(int, ...);
+using SysCalls = intptr_t (*)(intptr_t, ...);
+
+void *Sys_LoadGameDll(const char *name, EntryPoint* entryPoint, SysCalls systemcalls)
+{
+ void *libHandle;
+
+ assert(name);
+
+ if (!Sys_DllExtension(name))
+ {
+ Com_Printf("Refusing to load library \"%s\": Extension not allowed.\n", name);
+ return nullptr;
+ }
+
+ Com_Printf( "Loading DLL file: %s\n", name);
+ libHandle = Sys_LoadLibrary(name);
+
+ if(!libHandle)
+ {
+ Com_Printf("Sys_LoadGameDll(%s) failed:\n\"%s\"\n", name, Sys_LibraryError());
+ return NULL;
+ }
+
+ Entry entry = (Entry)Sys_LoadFunction( libHandle, "dllEntry" );
+ *entryPoint = (EntryPoint)Sys_LoadFunction( libHandle, "vmMain" );
+
+ if ( !*entryPoint || !entry )
+ {
+ Com_Printf ( "Sys_LoadGameDll(%s) failed to find vmMain function:\n\"%s\" !\n", name, Sys_LibraryError( ) );
+ Sys_UnloadLibrary(libHandle);
+ return NULL;
+ }
+
+ Com_Printf ( "Sys_LoadGameDll(%s) found vmMain function at %p\n", name, *entryPoint );
+ entry( systemcalls );
+
+ return libHandle;
+}
+
+/*
+=================
+Sys_ParseArgs
+=================
+*/
+void Sys_ParseArgs( int argc, char **argv )
+{
+ if( argc == 2 )
+ {
+ if( !strcmp( argv[1], "--version" ) ||
+ !strcmp( argv[1], "-v" ) )
+ {
+ const char* date = __DATE__;
+#ifdef DEDICATED
+ fprintf( stdout, Q3_VERSION " dedicated server (%s)\n", date );
+#else
+ fprintf( stdout, Q3_VERSION " client (%s)\n", date );
+#endif
+ Sys_Exit( 0 );
+ }
+ }
+}
+
+/*
+=================
+Sys_SigHandler
+=================
+*/
+void Sys_SigHandler( int signal )
+{
+ static bool signalcaught = false;
+
+ if( signalcaught )
+ {
+ std::cerr << "DOUBLE SIGNAL FAULT: Received signal "
+ << signal << std::endl;
+ }
+ else
+ {
+ char const* msg = va("Received signal %d", signal);
+
+ signalcaught = true;
+ VM_Forced_Unload_Start();
+#ifndef DEDICATED
+ CL_Shutdown(va("Received signal %d", signal), true, true);
+#endif
+ SV_Shutdown(msg);
+ VM_Forced_Unload_Done();
+ }
+
+ if( signal == SIGTERM || signal == SIGINT )
+ Sys_Exit( 1 );
+
+ Sys_Exit( 2 );
+}
+
+#ifndef DEFAULT_BASEDIR
+# ifdef __APPLE__
+# define DEFAULT_BASEDIR Sys_StripAppBundle(Sys_BinaryPath())
+# else
+# define DEFAULT_BASEDIR Sys_BinaryPath()
+# endif
+#endif
+
+#ifdef __APPLE__
+/*
+=================
+Sys_StripAppBundle
+
+Discovers if passed dir is suffixed with the directory structure of a Mac OS X
+.app bundle. If it is, the .app directory structure is stripped off the end and
+the result is returned. If not, dir is returned untouched.
+=================
+*/
+const char *Sys_StripAppBundle( const char *dir )
+{
+ static char cwd[MAX_OSPATH];
+
+ Q_strncpyz(cwd, dir, sizeof(cwd));
+ if(strcmp(Sys_Basename(cwd), "MacOS"))
+ return dir;
+ Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
+ if(strcmp(Sys_Basename(cwd), "Contents"))
+ return dir;
+ Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
+ if(!strstr(Sys_Basename(cwd), ".app"))
+ return dir;
+ Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
+ return cwd;
+}
+#endif
+
+#ifndef DEDICATED
+
+void SDLVersionCheck()
+{
+#if !SDL_VERSION_ATLEAST(MINSDL_MAJOR,MINSDL_MINOR,MINSDL_PATCH)
+#error A more recent version of SDL is required
+#endif
+ SDL_version ver;
+ SDL_GetVersion( &ver );
+#define MINSDL_VERSION XSTRING(MINSDL_MAJOR) "." \
+ XSTRING(MINSDL_MINOR) "." \
+ XSTRING(MINSDL_PATCH)
+ if( SDL_VERSIONNUM(ver.major, ver.minor, ver.patch)
+ < SDL_VERSIONNUM(MINSDL_MAJOR, MINSDL_MINOR, MINSDL_PATCH) )
+ {
+ Sys_Dialog( DT_ERROR, va( "SDL version " MINSDL_VERSION " or greater is required, "
+ "but only version %d.%d.%d was found. You may be able to obtain a more recent copy "
+ "from http://www.libsdl.org/.", ver.major, ver.minor, ver.patch ), "SDL Library Too Old" );
+ Sys_Exit( 1 );
+ }
+}
+#endif
+
+
+/*
+=================
+main
+=================
+*/
+int main( int argc, char **argv )
+{
+#ifndef DEDICATED
+ SDLVersionCheck();
+#endif
+ Sys_PlatformInit( );
+
+ // Set the initial time base
+ Sys_Milliseconds( );
+
+#ifdef __APPLE__
+ // This is passed if we are launched by double-clicking
+ if ( argc >= 2 )
+ if ( Q_strncmp( argv[1], "-psn", 4 ) == 0 )
+ argc = 1;
+#endif
+
+ Sys_ParseArgs( argc, argv );
+ Sys_SetBinaryPath( Sys_Dirname( argv[ 0 ] ) );
+ Sys_SetDefaultInstallPath( DEFAULT_BASEDIR );
+
+ // Concatenate the command line for passing to Com_Init
+ char args[MAX_STRING_CHARS];
+ args[0] = '\0';
+
+ for( int i = 1; i < argc; i++ )
+ {
+ const bool ws = strchr(argv[i], ' ') ? true : false;
+
+ if (ws) Q_strcat(args, sizeof(args), "\"");
+ Q_strcat(args, sizeof(args), argv[i]);
+ if (ws) Q_strcat(args, sizeof(args), "\"");
+ Q_strcat(args, sizeof(args), " " );
+ }
+
+ CON_Init( );
+ Com_Init( args );
+ NET_Init( );
+
+ lua.open_libraries
+ (
+ sol::lib::base,
+ sol::lib::package,
+#if !defined(SOL_LUAJIT) // Not with LuaJIT.
+ sol::lib::coroutine,
+#endif
+ sol::lib::string,
+ sol::lib::table,
+ sol::lib::math,
+ sol::lib::bit32,
+ sol::lib::io,
+ sol::lib::os,
+ sol::lib::debug,
+ sol::lib::utf8 // Only with Lua 5.3; ommiting ifdef on purpose. -bbq
+#if defined(SOL_LUAJIT) // Only with LuaJIT.
+ ,sol::lib::ffi,
+ sol::lib::jit
+#endif
+ );
+
+ script::cvar::init(std::move(lua));
+ script::cmd::init(std::move(lua));
+ script::rapidjson::init(std::move(lua));
+ script::nettle::init(std::move(lua));
+
+#ifndef DEDICATED
+ script::client::init(std::move(lua));
+ script::keybind::init(std::move(lua));
+ script::http_client::init(std::move(lua));
+#endif
+
+ for ( ;; )
+ {
+ try
+ {
+ Com_Frame( );
+ }
+ catch (sol::error& e)
+ {
+ Com_Printf(S_COLOR_YELLOW "%s\n", e.what());
+ }
+ }
+
+ return 0;
+}
diff --git a/src/sys/sys_osx.mm b/src/sys/sys_osx.mm
new file mode 100644
index 0000000..36caa40
--- /dev/null
+++ b/src/sys/sys_osx.mm
@@ -0,0 +1,103 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2009 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#ifndef __APPLE__
+#error This file is for Mac OS X only. You probably should not compile it.
+#endif
+
+// Please note that this file is just some Mac-specific bits. Most of the
+// Mac OS X code is shared with other Unix platforms in sys_unix.c ...
+
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+#include "dialog.h"
+#include "sys_local.h"
+
+//#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+#import <Carbon/Carbon.h>
+#import <Cocoa/Cocoa.h>
+//
+//#import <AppKit/AppKitDefines.h>
+//#import <Foundation/NSObject.h>
+//#import <Foundation/NSArray.h>
+//#import <Foundation/NSDictionary.h>
+//#import <AppKit/NSAlert.h>
+
+/*
+==============
+Sys_Dialog
+
+Display an OS X dialog box
+==============
+*/
+dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title )
+{
+ dialogResult_t result = DR_OK;
+ NSAlert *alert = [NSAlert new];
+
+ [alert setMessageText: [NSString stringWithUTF8String: title]];
+ [alert setInformativeText: [NSString stringWithUTF8String: message]];
+
+ if( type == DT_ERROR )
+ [alert setAlertStyle: NSCriticalAlertStyle];
+ else
+ [alert setAlertStyle: NSWarningAlertStyle];
+
+ switch( type )
+ {
+ default:
+ [alert runModal];
+ result = DR_OK;
+ break;
+
+ case DT_YES_NO:
+ [alert addButtonWithTitle: @"Yes"];
+ [alert addButtonWithTitle: @"No"];
+ switch( [alert runModal] )
+ {
+ default:
+ case NSAlertFirstButtonReturn: result = DR_YES; break;
+ case NSAlertSecondButtonReturn: result = DR_NO; break;
+ }
+ break;
+
+ case DT_OK_CANCEL:
+ [alert addButtonWithTitle: @"OK"];
+ [alert addButtonWithTitle: @"Cancel"];
+
+ switch( [alert runModal] )
+ {
+ default:
+ case NSAlertFirstButtonReturn: result = DR_OK; break;
+ case NSAlertSecondButtonReturn: result = DR_CANCEL; break;
+ }
+ break;
+ }
+
+ [alert release];
+
+ return result;
+}
diff --git a/src/sys/sys_shared.h b/src/sys/sys_shared.h
new file mode 100644
index 0000000..283ae3a
--- /dev/null
+++ b/src/sys/sys_shared.h
@@ -0,0 +1,111 @@
+/*
+
+ This File is part of Tremulous.
+ Copyright (C) 2016, wtfbbqhax <victor@badsec.org>.
+ Copyright (C) 2015-2019, GrangerHub <grangerhub.com>.
+
+*/
+
+#ifndef SYS_SHARED_H
+#define SYS_SHARED_H 1
+
+#include <stdio.h>
+
+#include "qcommon/qcommon.h"
+#include "qcommon/net.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_JOYSTICK_AXIS 16
+
+typedef int cpuFeatures_t;
+enum CPU_FEATURES {
+ CF_NONE = 0,
+ CF_RDTSC = 1 << 0,
+ CF_MMX = 1 << 1,
+ CF_MMX_EXT = 1 << 2,
+ CF_3DNOW = 1 << 3,
+ CF_3DNOW_EXT = 1 << 4,
+ CF_SSE = 1 << 5,
+ CF_SSE2 = 1 << 6,
+ CF_ALTIVEC = 1 << 7
+};
+
+struct netadr_t;
+enum netadrtype_t;
+
+void Sys_Init(void);
+
+// general development dll loading for virtual machine testing
+void *QDECL Sys_LoadGameDll(const char *name,
+ intptr_t(QDECL **entryPoint)(int, ...),
+ intptr_t(QDECL *systemcalls)(intptr_t, ...));
+
+void Sys_UnloadDll(void *dllHandle);
+bool Sys_DllExtension(const char *name);
+
+void QDECL Sys_Error(const char *error, ...) __attribute__((noreturn, format(printf, 1, 2)));
+void Sys_Quit(void) __attribute__((noreturn));
+
+char *Sys_GetClipboardData(void); // note that this isn't journaled...
+
+void Sys_Print(const char *msg);
+
+// Sys_Milliseconds should only be used for profiling purposes,
+// any game related timing information should come from event timestamps
+int Sys_Milliseconds(void);
+
+bool Sys_RandomBytes(byte *string, int len);
+
+void Sys_CryptoRandomBytes(byte *string, int len);
+
+// the system console is shown when a dedicated server is running
+void Sys_DisplaySystemConsole(bool show);
+
+cpuFeatures_t Sys_GetProcessorFeatures(void);
+
+void Sys_SetErrorText(const char *text);
+
+FILE *Sys_FOpen(const char *ospath, const char *mode);
+bool Sys_Mkdir(const char *path);
+FILE *Sys_Mkfifo(const char *ospath);
+bool Sys_OpenWithDefault( const char *path );
+char *Sys_Cwd(void);
+void Sys_SetDefaultInstallPath(const char *path);
+char *Sys_DefaultInstallPath(void);
+
+#ifdef __APPLE__
+char *Sys_DefaultAppPath(void);
+#endif
+
+void Sys_SetDefaultHomePath(const char *path);
+char *Sys_DefaultHomePath(void);
+const char *Sys_Dirname(char *path);
+const char *Sys_Basename(char *path);
+char *Sys_ConsoleInput(void);
+
+char **Sys_ListFiles(const char *directory, const char *extension,
+ const char *filter,
+ int *numfiles, bool wantsubs);
+void Sys_FreeFileList(char **list);
+void Sys_Sleep(int msec);
+
+bool Sys_LowPhysicalMemory(void);
+
+void Sys_SetEnv(const char *name, const char *value);
+
+bool Sys_WritePIDFile(void);
+
+// Input subsystem
+void IN_Init( void *windowData );
+void IN_Frame( void );
+void IN_Shutdown( void );
+void IN_Restart( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/sys/sys_unix.cpp b/src/sys/sys_unix.cpp
new file mode 100644
index 0000000..e55655c
--- /dev/null
+++ b/src/sys/sys_unix.cpp
@@ -0,0 +1,1006 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "qcommon/cvar.h"
+#include "qcommon/files.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+#include "dialog.h"
+#include "sys_local.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <pwd.h>
+#include <libgen.h>
+#include <fcntl.h>
+#include <fenv.h>
+#include <sys/wait.h>
+
+bool stdinIsATTY;
+
+// Used to determine where to store user-specific files
+static char homePath[ MAX_OSPATH ] = { 0 };
+
+/*
+==================
+Sys_DefaultHomePath
+==================
+*/
+char *Sys_DefaultHomePath(void)
+{
+ char *p;
+
+ if( !*homePath && com_homepath != NULL )
+ {
+ if( ( p = getenv( "HOME" ) ) != NULL )
+ {
+ Com_sprintf(homePath, sizeof(homePath), "%s%c", p, PATH_SEP);
+#ifdef __APPLE__
+ Q_strcat(homePath, sizeof(homePath),
+ "Library/Application Support/");
+
+ if(com_homepath->string[0])
+ Q_strcat(homePath, sizeof(homePath), com_homepath->string);
+ else
+ Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_MACOSX);
+#else
+ if(com_homepath->string[0])
+ Q_strcat(homePath, sizeof(homePath), com_homepath->string);
+ else
+ Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_UNIX);
+#endif
+ }
+ }
+
+ return homePath;
+}
+
+/*
+================
+Sys_Milliseconds
+================
+*/
+/* base time in seconds, that's our origin
+ timeval:tv_sec is an int:
+ assuming this wraps every 0x7fffffff - ~68 years since the Epoch (1970) - we're safe till 2038 */
+unsigned long sys_timeBase = 0;
+/* current time in ms, using sys_timeBase as origin
+ NOTE: sys_timeBase*1000 + curtime -> ms since the Epoch
+ 0x7fffffff ms - ~24 days
+ although timeval:tv_usec is an int, I'm not sure wether it is actually used as an unsigned int
+ (which would affect the wrap period) */
+int curtime;
+int Sys_Milliseconds (void)
+{
+ struct timeval tp;
+
+ gettimeofday(&tp, NULL);
+
+ if (!sys_timeBase)
+ {
+ sys_timeBase = tp.tv_sec;
+ return tp.tv_usec/1000;
+ }
+
+ curtime = (tp.tv_sec - sys_timeBase)*1000 + tp.tv_usec/1000;
+
+ return curtime;
+}
+
+/*
+==================
+Sys_RandomBytes
+==================
+*/
+bool Sys_RandomBytes( byte *string, int len )
+{
+ FILE *fp;
+
+ fp = fopen( "/dev/urandom", "r" );
+ if( !fp )
+ return false;
+
+ setvbuf( fp, NULL, _IONBF, 0 ); // don't buffer reads from /dev/urandom
+
+ if( fread( string, sizeof( byte ), len, fp ) != len )
+ {
+ fclose( fp );
+ return false;
+ }
+
+ fclose( fp );
+ return true;
+}
+
+/*
+==================
+Sys_GetCurrentUser
+==================
+*/
+const char *Sys_GetCurrentUser( void )
+{
+ struct passwd *p;
+
+ if ( (p = getpwuid( getuid() )) == NULL ) {
+ return "player";
+ }
+ return p->pw_name;
+}
+
+/*
+==================
+Sys_CryptoRandomBytes
+==================
+*/
+void Sys_CryptoRandomBytes( byte *string, int len )
+{
+ if ( !Sys_RandomBytes( string, len ) )
+ Com_Error( ERR_FATAL, "Sys_CryptoRandomBytes: error reading /dev/urandom" );
+}
+
+#define MEM_THRESHOLD 96*1024*1024
+
+/*
+==================
+Sys_LowPhysicalMemory
+
+TODO
+==================
+*/
+bool Sys_LowPhysicalMemory( void )
+{
+ return false;
+}
+
+/*
+==================
+Sys_Basename
+==================
+*/
+const char *Sys_Basename( char *path )
+{
+ return basename( path );
+}
+
+/*
+==================
+Sys_Dirname
+==================
+*/
+const char *Sys_Dirname( char* path )
+{
+ return dirname( path );
+}
+
+/*
+==============
+Sys_FOpen
+==============
+*/
+FILE *Sys_FOpen( const char *ospath, const char *mode ) {
+ struct stat buf;
+
+ // check if path exists and is a directory
+ if ( !stat( ospath, &buf ) && S_ISDIR( buf.st_mode ) )
+ return NULL;
+
+ return fopen( ospath, mode );
+}
+
+/*
+==================
+Sys_Mkdir
+==================
+*/
+bool Sys_Mkdir( const char *path )
+{
+ int result = mkdir( path, 0750 );
+
+ if( result != 0 )
+ return (bool)(errno == EEXIST);
+
+ return true;
+}
+
+/*
+==================
+Sys_Mkfifo
+==================
+*/
+FILE *Sys_Mkfifo( const char *ospath )
+{
+ FILE *fifo;
+ int result;
+ int fn;
+ struct stat buf;
+
+ // if file already exists AND is a pipefile, remove it
+ if( !stat( ospath, &buf ) && S_ISFIFO( buf.st_mode ) )
+ FS_Remove( ospath );
+
+ result = mkfifo( ospath, 0600 );
+ if( result != 0 )
+ return NULL;
+
+ fifo = fopen( ospath, "w+" );
+ if( fifo )
+ {
+ fn = fileno( fifo );
+ fcntl( fn, F_SETFL, O_NONBLOCK );
+ }
+
+ return fifo;
+}
+
+/*
+==============
+Sys_OpenWithDefault
+
+Opens a path with the default application
+==============
+*/
+bool Sys_OpenWithDefault( const char *path )
+{
+ int status;
+ int exitNum;
+ pid_t pid;
+
+ Com_Printf( S_COLOR_WHITE "Sys_OpenWithDefault: opening %s .....\n",
+ path );
+
+ // attempt to start child process
+ pid = fork();
+
+ if( pid < 0 )
+ {
+ // failed to start the child process
+ Com_Printf( S_COLOR_RED "Sys_OpenWithDefault: %s\n" S_COLOR_WHITE,
+ strerror( exitNum ) );
+ return false;
+ }
+ else if ( pid == 0 )
+ {
+ //child proccess
+ char *argv[3];
+ char tempPath[MAX_OSPATH];
+ char openCmd[MAX_OSPATH];
+
+ ::memset( tempPath, 0, sizeof( tempPath ) );
+ ::memset( openCmd, 0, sizeof( openCmd ) );
+
+ Q_strcat( tempPath, sizeof(tempPath), path );
+
+ argv[1] = tempPath;
+ argv[2] = NULL;
+
+#ifdef __APPLE__
+ Q_strcat( openCmd, sizeof(openCmd), "open");
+#else
+ Q_strcat( openCmd, sizeof(openCmd), "xdg-open");
+#endif
+
+ argv[0] = openCmd;
+
+ // attempt to open the path
+ if( execvp( argv[0], argv ) < 0 )
+ {
+ //failure
+ exit( errno );
+ }
+
+ //success
+ exit(0);
+ }
+
+ wait( &status );
+ exitNum = WEXITSTATUS( status );
+
+ if( !exitNum )
+ {
+ return true;
+ }
+ else
+ {
+ Com_Printf( S_COLOR_RED "Sys_OpenWithDefault: %s\n" S_COLOR_WHITE, strerror( exitNum ) );
+ return false;
+ }
+}
+
+/*
+==================
+Sys_Cwd
+==================
+*/
+char *Sys_Cwd( void )
+{
+ static char cwd[MAX_OSPATH];
+
+ char *result = getcwd( cwd, sizeof( cwd ) - 1 );
+ if( result != cwd )
+ return NULL;
+
+ cwd[MAX_OSPATH-1] = 0;
+
+ return cwd;
+}
+
+/*
+==============================================================
+
+DIRECTORY SCANNING
+
+==============================================================
+*/
+
+#define MAX_FOUND_FILES 0x1000
+
+/*
+==================
+Sys_ListFilteredFiles
+==================
+*/
+void Sys_ListFilteredFiles( const char *basedir, const char *subdirs,
+ const char *filter, char **list, int *numfiles )
+{
+ char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
+ char filename[MAX_OSPATH];
+ DIR *fdir;
+ struct dirent *d;
+ struct stat st;
+
+ if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
+ return;
+ }
+
+ if (strlen(subdirs)) {
+ Com_sprintf( search, sizeof(search), "%s/%s", basedir, subdirs );
+ }
+ else {
+ Com_sprintf( search, sizeof(search), "%s", basedir );
+ }
+
+ if ((fdir = opendir(search)) == NULL) {
+ return;
+ }
+
+ while ((d = readdir(fdir)) != NULL) {
+ Com_sprintf(filename, sizeof(filename), "%s/%s", search, d->d_name);
+ if (stat(filename, &st) == -1)
+ continue;
+
+ if (st.st_mode & S_IFDIR) {
+ if (Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, "..")) {
+ if (strlen(subdirs)) {
+ Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s/%s", subdirs, d->d_name);
+ }
+ else {
+ Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", d->d_name);
+ }
+ Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
+ }
+ }
+ if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
+ break;
+ }
+ Com_sprintf( filename, sizeof(filename), "%s/%s", subdirs, d->d_name );
+ if (!Com_FilterPath( filter, filename, false ))
+ continue;
+ list[ *numfiles ] = CopyString( filename );
+ (*numfiles)++;
+ }
+
+ closedir(fdir);
+}
+
+/*
+==================
+Sys_ListFiles
+==================
+*/
+char **Sys_ListFiles( const char *directory, const char *extension,
+ const char *filter, int *numfiles, bool wantsubs )
+{
+ struct dirent *d;
+ DIR *fdir;
+ bool dironly = wantsubs;
+ char search[MAX_OSPATH];
+ int nfiles;
+ char **listCopy;
+ char *list[MAX_FOUND_FILES];
+ int i;
+ struct stat st;
+
+ int extLen;
+
+ if (filter) {
+
+ nfiles = 0;
+ Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
+
+ list[ nfiles ] = NULL;
+ *numfiles = nfiles;
+
+ if (!nfiles)
+ return NULL;
+
+ listCopy = (char**)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
+ for ( i = 0 ; i < nfiles ; i++ ) {
+ listCopy[i] = list[i];
+ }
+ listCopy[i] = NULL;
+
+ return listCopy;
+ }
+
+ if ( !extension)
+ extension = "";
+
+ if ( extension[0] == '/' && extension[1] == 0 ) {
+ extension = "";
+ dironly = true;
+ }
+
+ extLen = strlen( extension );
+
+ // search
+ nfiles = 0;
+
+ if ((fdir = opendir(directory)) == NULL) {
+ *numfiles = 0;
+ return NULL;
+ }
+
+ while ((d = readdir(fdir)) != NULL) {
+ Com_sprintf(search, sizeof(search), "%s/%s", directory, d->d_name);
+ if (stat(search, &st) == -1)
+ continue;
+ if ((dironly && !(st.st_mode & S_IFDIR)) ||
+ (!dironly && (st.st_mode & S_IFDIR)))
+ continue;
+
+ if (*extension) {
+ if ( strlen( d->d_name ) < extLen ||
+ Q_stricmp(
+ d->d_name + strlen( d->d_name ) - extLen,
+ extension ) ) {
+ continue; // didn't match
+ }
+ }
+
+ if ( nfiles == MAX_FOUND_FILES - 1 )
+ break;
+ list[ nfiles ] = CopyString( d->d_name );
+ nfiles++;
+ }
+
+ list[ nfiles ] = NULL;
+
+ closedir(fdir);
+
+ // return a copy of the list
+ *numfiles = nfiles;
+
+ if ( !nfiles ) {
+ return NULL;
+ }
+
+ listCopy = (char**)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
+ for ( i = 0 ; i < nfiles ; i++ ) {
+ listCopy[i] = list[i];
+ }
+ listCopy[i] = NULL;
+
+ return listCopy;
+}
+
+/*
+==================
+Sys_FreeFileList
+==================
+*/
+void Sys_FreeFileList( char **list )
+{
+ int i;
+
+ if ( !list ) {
+ return;
+ }
+
+ for ( i = 0 ; list[i] ; i++ ) {
+ Z_Free( list[i] );
+ }
+
+ Z_Free( list );
+}
+
+/*
+==================
+Sys_Sleep
+
+Block execution for msec or until input is recieved.
+==================
+*/
+void Sys_Sleep( int msec )
+{
+ if( msec == 0 )
+ return;
+
+ if( stdinIsATTY )
+ {
+ fd_set fdset;
+
+ FD_ZERO(&fdset);
+ FD_SET(STDIN_FILENO, &fdset);
+ if( msec < 0 )
+ {
+ select(STDIN_FILENO + 1, &fdset, NULL, NULL, NULL);
+ }
+ else
+ {
+ struct timeval timeout;
+
+ timeout.tv_sec = msec/1000;
+ timeout.tv_usec = (msec%1000)*1000;
+ select(STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout);
+ }
+ }
+ else
+ {
+ // With nothing to select() on, we can't wait indefinitely
+ if( msec < 0 )
+ msec = 10;
+
+ usleep( msec * 1000 );
+ }
+}
+
+/*
+==============
+Sys_ErrorDialog
+
+Display an error message
+==============
+*/
+void Sys_ErrorDialog( const char *error )
+{
+ char buffer[ 1024 ];
+ unsigned int size;
+ int f = -1;
+ const char *homepath = Cvar_VariableString( "fs_homepath" );
+ const char *gamedir = Cvar_VariableString( "fs_game" );
+ const char *fileName = "crashlog.txt";
+ char *dirpath = FS_BuildOSPath( homepath, gamedir, "");
+ char *ospath = FS_BuildOSPath( homepath, gamedir, fileName );
+
+ Sys_Print( va( "%s\n", error ) );
+
+#ifndef DEDICATED
+ Sys_Dialog( DT_ERROR, va( "%s. See \"%s\" for details.", error, ospath ), "Error" );
+#endif
+
+ // Make sure the write path for the crashlog exists...
+
+ if(!Sys_Mkdir(homepath))
+ {
+ Com_Printf("ERROR: couldn't create path '%s' for crash log.\n", homepath);
+ return;
+ }
+
+ if(!Sys_Mkdir(dirpath))
+ {
+ Com_Printf("ERROR: couldn't create path '%s' for crash log.\n", dirpath);
+ return;
+ }
+
+ // We might be crashing because we maxed out the Quake MAX_FILE_HANDLES,
+ // which will come through here, so we don't want to recurse forever by
+ // calling FS_FOpenFileWrite()...use the Unix system APIs instead.
+ f = open( ospath, O_CREAT | O_TRUNC | O_WRONLY, 0640 );
+ if( f == -1 )
+ {
+ Com_Printf( "ERROR: couldn't open %s\n", fileName );
+ return;
+ }
+
+ // We're crashing, so we don't care much if write() or close() fails.
+ while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 ) {
+ if( write( f, buffer, size ) != size ) {
+ Com_Printf( "ERROR: couldn't fully write to %s\n", fileName );
+ break;
+ }
+ }
+
+ close( f );
+}
+
+#ifndef __APPLE__
+static char execBuffer[ 1024 ];
+static char *execBufferPointer;
+static char *execArgv[ 16 ];
+static int execArgc;
+
+/*
+==============
+Sys_ClearExecBuffer
+==============
+*/
+static void Sys_ClearExecBuffer( void )
+{
+ execBufferPointer = execBuffer;
+ ::memset( execArgv, 0, sizeof( execArgv ) );
+ execArgc = 0;
+}
+
+/*
+==============
+Sys_AppendToExecBuffer
+==============
+*/
+static void Sys_AppendToExecBuffer( const char *text )
+{
+ size_t size = sizeof( execBuffer ) - ( execBufferPointer - execBuffer );
+ int length = strlen( text ) + 1;
+
+ if( length > size || execArgc >= ARRAY_LEN( execArgv ) )
+ return;
+
+ Q_strncpyz( execBufferPointer, text, size );
+ execArgv[ execArgc++ ] = execBufferPointer;
+
+ execBufferPointer += length;
+}
+
+/*
+==============
+Sys_Exec
+==============
+*/
+static int Sys_Exec( void )
+{
+ pid_t pid = fork( );
+
+ if( pid < 0 )
+ return -1;
+
+ if( pid )
+ {
+ // Parent
+ int exitCode;
+
+ wait( &exitCode );
+
+ return WEXITSTATUS( exitCode );
+ }
+ else
+ {
+ // Child
+ execvp( execArgv[ 0 ], execArgv );
+
+ // Failed to execute
+ exit( -1 );
+
+ return -1;
+ }
+}
+
+/*
+==============
+Sys_ZenityCommand
+==============
+*/
+static void Sys_ZenityCommand( dialogType_t type, const char *message, const char *title )
+{
+ Sys_ClearExecBuffer( );
+ Sys_AppendToExecBuffer( "zenity" );
+
+ switch( type )
+ {
+ default:
+ case DT_INFO: Sys_AppendToExecBuffer( "--info" ); break;
+ case DT_WARNING: Sys_AppendToExecBuffer( "--warning" ); break;
+ case DT_ERROR: Sys_AppendToExecBuffer( "--error" ); break;
+ case DT_YES_NO:
+ Sys_AppendToExecBuffer( "--question" );
+ Sys_AppendToExecBuffer( "--ok-label=Yes" );
+ Sys_AppendToExecBuffer( "--cancel-label=No" );
+ break;
+
+ case DT_OK_CANCEL:
+ Sys_AppendToExecBuffer( "--question" );
+ Sys_AppendToExecBuffer( "--ok-label=OK" );
+ Sys_AppendToExecBuffer( "--cancel-label=Cancel" );
+ break;
+ }
+
+ Sys_AppendToExecBuffer( va( "--text=%s", message ) );
+ Sys_AppendToExecBuffer( va( "--title=%s", title ) );
+}
+
+/*
+==============
+Sys_KdialogCommand
+==============
+*/
+static void Sys_KdialogCommand( dialogType_t type, const char *message, const char *title )
+{
+ Sys_ClearExecBuffer( );
+ Sys_AppendToExecBuffer( "kdialog" );
+
+ switch( type )
+ {
+ default:
+ case DT_INFO: Sys_AppendToExecBuffer( "--msgbox" ); break;
+ case DT_WARNING: Sys_AppendToExecBuffer( "--sorry" ); break;
+ case DT_ERROR: Sys_AppendToExecBuffer( "--error" ); break;
+ case DT_YES_NO: Sys_AppendToExecBuffer( "--warningyesno" ); break;
+ case DT_OK_CANCEL: Sys_AppendToExecBuffer( "--warningcontinuecancel" ); break;
+ }
+
+ Sys_AppendToExecBuffer( message );
+ Sys_AppendToExecBuffer( va( "--title=%s", title ) );
+}
+
+/*
+==============
+Sys_XmessageCommand
+==============
+*/
+static void Sys_XmessageCommand( dialogType_t type, const char *message, const char *title )
+{
+ Sys_ClearExecBuffer( );
+ Sys_AppendToExecBuffer( "xmessage" );
+ Sys_AppendToExecBuffer( "-buttons" );
+
+ switch( type )
+ {
+ default: Sys_AppendToExecBuffer( "OK:0" ); break;
+ case DT_YES_NO: Sys_AppendToExecBuffer( "Yes:0,No:1" ); break;
+ case DT_OK_CANCEL: Sys_AppendToExecBuffer( "OK:0,Cancel:1" ); break;
+ }
+
+ Sys_AppendToExecBuffer( "-center" );
+ Sys_AppendToExecBuffer( message );
+}
+
+/*
+==============
+Sys_Dialog
+
+Display a *nix dialog box
+==============
+*/
+dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title )
+{
+ typedef enum
+ {
+ NONE = 0,
+ ZENITY,
+ KDIALOG,
+ XMESSAGE,
+ NUM_DIALOG_PROGRAMS
+ } dialogCommandType_t;
+ typedef void (*dialogCommandBuilder_t)( dialogType_t, const char *, const char * );
+
+ const char *session = getenv( "DESKTOP_SESSION" );
+ bool tried[ NUM_DIALOG_PROGRAMS ] = { false };
+ dialogCommandBuilder_t commands[ NUM_DIALOG_PROGRAMS ] = { NULL };
+ dialogCommandType_t preferredCommandType = NONE;
+ int i;
+
+ commands[ ZENITY ] = &Sys_ZenityCommand;
+ commands[ KDIALOG ] = &Sys_KdialogCommand;
+ commands[ XMESSAGE ] = &Sys_XmessageCommand;
+
+ // This may not be the best way
+ if( !Q_stricmp( session, "gnome" ) )
+ preferredCommandType = ZENITY;
+ else if( !Q_stricmp( session, "kde" ) )
+ preferredCommandType = KDIALOG;
+
+ for( i = NONE + 1; i < NUM_DIALOG_PROGRAMS; i++ )
+ {
+ if( preferredCommandType != NONE && preferredCommandType != i )
+ continue;
+
+ if( !tried[ i ] )
+ {
+ int exitCode;
+
+ commands[ i ]( type, message, title );
+ exitCode = Sys_Exec( );
+
+ if( exitCode >= 0 )
+ {
+ switch( type )
+ {
+ case DT_YES_NO: return exitCode ? DR_NO : DR_YES;
+ case DT_OK_CANCEL: return exitCode ? DR_CANCEL : DR_OK;
+ default: return DR_OK;
+ }
+ }
+
+ tried[ i ] = true;
+
+ // The preference failed, so start again in order
+ if( preferredCommandType != NONE )
+ {
+ preferredCommandType = NONE;
+ i = NONE + 1;
+ }
+ }
+ }
+
+ Com_DPrintf( S_COLOR_YELLOW "WARNING: failed to show a dialog\n" );
+ return DR_OK;
+}
+#endif
+
+/*
+==============
+Sys_GLimpSafeInit
+
+Unix specific "safe" GL implementation initialisation
+==============
+*/
+void Sys_GLimpSafeInit( void )
+{
+ // NOP
+}
+
+/*
+==============
+Sys_GLimpInit
+
+Unix specific GL implementation initialisation
+==============
+*/
+void Sys_GLimpInit( void )
+{
+ // NOP
+}
+
+void Sys_SetFloatEnv(void)
+{
+ // rounding toward nearest
+ fesetround(FE_TONEAREST);
+}
+
+/*
+==============
+Sys_PlatformInit
+
+Unix specific initialisation
+==============
+*/
+void Sys_PlatformInit( void )
+{
+ const char* term = getenv( "TERM" );
+
+ signal( SIGHUP, Sys_SigHandler );
+ signal( SIGQUIT, Sys_SigHandler );
+ signal( SIGTRAP, Sys_SigHandler );
+ signal( SIGABRT, Sys_SigHandler );
+ signal( SIGBUS, Sys_SigHandler );
+
+ Sys_SetFloatEnv();
+
+ stdinIsATTY = isatty( STDIN_FILENO ) &&
+ !( term && ( !strcmp( term, "raw" ) || !strcmp( term, "dumb" ) ) );
+}
+
+/*
+==============
+Sys_PlatformExit
+
+Unix specific deinitialisation
+==============
+*/
+void Sys_PlatformExit( void )
+{
+}
+
+/*
+==============
+Sys_SetEnv
+
+set/unset environment variables (empty value removes it)
+==============
+*/
+
+void Sys_SetEnv(const char *name, const char *value)
+{
+ if(value && *value)
+ setenv(name, value, 1);
+ else
+ unsetenv(name);
+}
+
+/*
+==============
+Sys_PID
+==============
+*/
+int Sys_PID( void )
+{
+ return getpid( );
+}
+
+/*
+==============
+Sys_PIDIsRunning
+==============
+*/
+bool Sys_PIDIsRunning( int pid )
+{
+ return kill( pid, 0 ) == 0;
+}
+
+
+/*
+=================
+Sys_DllExtension
+
+Check if filename should be allowed to be loaded as a DLL.
+=================
+*/
+bool Sys_DllExtension( const char *name )
+{
+ const char *p;
+ char c = 0;
+
+ if ( COM_CompareExtension(name, DLL_EXT) )
+ return true;
+
+ // Check for format of filename.so.1.2.3
+ p = strstr( name, DLL_EXT "." );
+
+ if ( p )
+ {
+ p += strlen( DLL_EXT );
+
+ // Check if .so is only followed for periods and numbers.
+ while ( *p )
+ {
+ c = *p;
+
+ if ( !isdigit( c ) && c != '.' )
+ return false;
+
+ p++;
+ }
+
+ // Don't allow filename to end in a period. file.so., file.so.0., etc
+ if ( c != '.' )
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/sys/sys_win32.cpp b/src/sys/sys_win32.cpp
new file mode 100644
index 0000000..0ec1f2c
--- /dev/null
+++ b/src/sys/sys_win32.cpp
@@ -0,0 +1,842 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "qcommon/q_shared.h"
+#include "qcommon/qcommon.h"
+#include "dialog.h"
+#include "sys_local.h"
+
+#include <windows.h>
+#include <lmerr.h>
+#include <lmcons.h>
+#include <lmwksta.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <direct.h>
+#include <io.h>
+#include <conio.h>
+#include <wincrypt.h>
+#include <shlobj.h>
+#include <psapi.h>
+#include <float.h>
+#include <shellapi.h>
+
+#ifndef DEDICATED
+static UINT timerResolution = 0;
+#endif
+
+/*
+================
+Sys_SetFPUCW
+Set FPU control word to default value
+================
+*/
+
+#ifndef _RC_CHOP
+// mingw doesn't seem to have these defined :(
+
+ #define _MCW_EM 0x0008001fU
+ #define _MCW_RC 0x00000300U
+ #define _MCW_PC 0x00030000U
+ #define _RC_NEAR 0x00000000U
+ #define _PC_53 0x00010000U
+
+ extern "C" unsigned int _controlfp(unsigned int _new, unsigned int mask);
+#endif
+
+#define FPUCWMASK1 (_MCW_RC | _MCW_EM)
+#define FPUCW (_RC_NEAR | _MCW_EM | _PC_53)
+
+#if idx64
+#define FPUCWMASK (FPUCWMASK1)
+#else
+#define FPUCWMASK (FPUCWMASK1 | _MCW_PC)
+#endif
+
+void Sys_SetFloatEnv(void)
+{
+ _controlfp(FPUCW, FPUCWMASK);
+}
+
+/*
+================
+Sys_Milliseconds
+================
+*/
+int sys_timeBase;
+int Sys_Milliseconds (void)
+{
+ int sys_curtime;
+ static bool initialized = false;
+
+ if (!initialized) {
+ sys_timeBase = timeGetTime();
+ initialized = true;
+ }
+ sys_curtime = timeGetTime() - sys_timeBase;
+
+ return sys_curtime;
+}
+
+/*
+================
+Sys_RandomBytes
+================
+*/
+bool Sys_RandomBytes( byte *string, int len )
+{
+ HCRYPTPROV prov;
+
+ if( !CryptAcquireContext( &prov, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) ) {
+
+ return false;
+ }
+
+ if( !CryptGenRandom( prov, len, (BYTE *)string ) ) {
+ CryptReleaseContext( prov, 0 );
+ return false;
+ }
+ CryptReleaseContext( prov, 0 );
+ return true;
+}
+
+/*
+================
+Sys_GetCurrentUser
+================
+*/
+char *Sys_GetCurrentUser( void )
+{
+ static char s_userName[1024];
+ unsigned long size = sizeof( s_userName );
+
+ if( !GetUserName( s_userName, &size ) )
+ strcpy( s_userName, "player" );
+
+ if( !s_userName[0] )
+ {
+ strcpy( s_userName, "player" );
+ }
+
+ return s_userName;
+}
+
+/*
+==================
+Sys_CryptoRandomBytes
+==================
+*/
+void Sys_CryptoRandomBytes( byte *string, int len )
+{
+ if ( !Sys_RandomBytes( string, len ) )
+ Com_Error( ERR_FATAL, "Sys_CryptoRandomBytes: error generating random data" );
+}
+
+#define MEM_THRESHOLD 96*1024*1024
+
+/*
+==================
+Sys_LowPhysicalMemory
+==================
+*/
+bool Sys_LowPhysicalMemory( void )
+{
+ MEMORYSTATUS stat;
+ GlobalMemoryStatus (&stat);
+ return (stat.dwTotalPhys <= MEM_THRESHOLD) ? true : false;
+}
+
+/*
+==============
+Sys_Basename
+==============
+*/
+const char *Sys_Basename( char *path )
+{
+ static char base[ MAX_OSPATH ] = { 0 };
+ int length;
+
+ length = strlen( path ) - 1;
+
+ // Skip trailing slashes
+ while( length > 0 && path[ length ] == '\\' )
+ length--;
+
+ while( length > 0 && path[ length - 1 ] != '\\' )
+ length--;
+
+ Q_strncpyz( base, &path[ length ], sizeof( base ) );
+
+ length = strlen( base ) - 1;
+
+ // Strip trailing slashes
+ while( length > 0 && base[ length ] == '\\' )
+ base[ length-- ] = '\0';
+
+ return base;
+}
+
+/*
+==============
+Sys_Dirname
+==============
+*/
+const char *Sys_Dirname( char *path )
+{
+ static char dir[ MAX_OSPATH ] = { 0 };
+ int length;
+
+ Q_strncpyz( dir, path, sizeof( dir ) );
+ length = strlen( dir ) - 1;
+
+ while( length > 0 && dir[ length ] != '\\' )
+ length--;
+
+ dir[ length ] = '\0';
+
+ return dir;
+}
+
+/*
+==============
+Sys_FOpen
+==============
+*/
+FILE *Sys_FOpen( const char *ospath, const char *mode ) {
+ return fopen( ospath, mode );
+}
+
+/*
+==============
+Sys_Mkdir
+==============
+*/
+bool Sys_Mkdir( const char *path )
+{
+ if( !CreateDirectory( path, NULL ) )
+ {
+ if( GetLastError( ) != ERROR_ALREADY_EXISTS )
+ return false;
+ }
+
+ return true;
+}
+
+/*
+==================
+Sys_Mkfifo
+Noop on windows because named pipes do not function the same way
+==================
+*/
+FILE *Sys_Mkfifo( const char *ospath )
+{
+ return NULL;
+}
+
+/*
+==============
+Sys_OpenWithDefault
+
+Opens a path with the default application
+==============
+*/
+bool Sys_OpenWithDefault( const char *path )
+{
+ HINSTANCE hInst;
+ uint64_t err;
+
+ Com_Printf( S_COLOR_WHITE "Sys_OpenWithDefault: opening %s .....\n", path );
+
+ hInst = ShellExecute(0, "open", path, 0, 0 , SW_SHOWNORMAL );
+ err = (uint64_t)hInst;
+
+ if( err > 32 )
+ {
+ //success
+ return true;
+ }
+
+ // failure
+ switch ( err )
+ {
+ case 0:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: The operating system is out of memory or resources.\n",
+ "warning" );
+ break;
+
+ case ERROR_FILE_NOT_FOUND:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: The specified file was not found.\n",
+ "warning" );
+ break;
+
+ case ERROR_PATH_NOT_FOUND:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: The specified path was not found.\n",
+ "warning" );
+ break;
+
+ case ERROR_BAD_FORMAT:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: The .exe file is invalid (non-Win32 .exe or error in .exe image).\n",
+ "warning" );
+ break;
+
+ case SE_ERR_ACCESSDENIED:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: The operating system denied access to the specified file.\n",
+ "warning" );
+ break;
+
+ case SE_ERR_ASSOCINCOMPLETE:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: The file name association is incomplete or invalid.\n",
+ "warning" );
+ break;
+
+ case SE_ERR_DDEBUSY:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: The DDE transaction could not be completed because other DDE transactions were being processed.\n",
+ "warning" );
+ break;
+
+ case SE_ERR_DDEFAIL:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: The DDE transaction failed.\n",
+ "warning" );
+ break;
+
+ case SE_ERR_DDETIMEOUT:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: The DDE transaction could not be completed because the request timed out.\n",
+ "warning" );
+ break;
+
+ case SE_ERR_DLLNOTFOUND:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: The specified DLL was not found.\n",
+ "warning" );
+ break;
+
+ case SE_ERR_NOASSOC:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable.\n",
+ "warning" );
+ break;
+
+ case SE_ERR_OOM:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: There was not enough memory to complete the operation.\n",
+ "warning" );
+ break;
+
+ case SE_ERR_SHARE:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: A sharing violation occurred.\n",
+ "warning" );
+ break;
+
+ default:
+ Sys_Dialog( DT_WARNING,
+ "Sys_OpenWithDefault: Failed to open path.\n",
+ "warning" );
+ break;
+ }
+
+ return false;
+}
+
+/*
+==============
+Sys_Cwd
+==============
+*/
+char *Sys_Cwd( void ) {
+ static char cwd[MAX_OSPATH];
+
+ _getcwd( cwd, sizeof( cwd ) - 1 );
+ cwd[MAX_OSPATH-1] = 0;
+
+ return cwd;
+}
+
+/*
+==============================================================
+
+DIRECTORY SCANNING
+
+==============================================================
+*/
+
+#define MAX_FOUND_FILES 0x1000
+
+/*
+==============
+Sys_ListFilteredFiles
+==============
+*/
+void Sys_ListFilteredFiles( const char *basedir, const char *subdirs,
+ const char *filter, char **list, int *numfiles )
+{
+ char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
+ char filename[MAX_OSPATH];
+ intptr_t findhandle;
+ struct _finddata_t findinfo;
+
+ if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
+ return;
+ }
+
+ if (strlen(subdirs)) {
+ Com_sprintf( search, sizeof(search), "%s\\%s\\*", basedir, subdirs );
+ }
+ else {
+ Com_sprintf( search, sizeof(search), "%s\\*", basedir );
+ }
+
+ findhandle = _findfirst (search, &findinfo);
+ if (findhandle == -1) {
+ return;
+ }
+
+ do {
+ if (findinfo.attrib & _A_SUBDIR) {
+ if (Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..")) {
+ if (strlen(subdirs)) {
+ Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s\\%s", subdirs, findinfo.name);
+ }
+ else {
+ Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", findinfo.name);
+ }
+ Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
+ }
+ }
+ if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
+ break;
+ }
+ Com_sprintf( filename, sizeof(filename), "%s\\%s", subdirs, findinfo.name );
+ if (!Com_FilterPath( filter, filename, false ))
+ continue;
+ list[ *numfiles ] = CopyString( filename );
+ (*numfiles)++;
+ } while ( _findnext (findhandle, &findinfo) != -1 );
+
+ _findclose (findhandle);
+}
+
+/*
+==============
+strgtr
+==============
+*/
+static bool strgtr(const char *s0, const char *s1)
+{
+ int l0, l1, i;
+
+ l0 = strlen(s0);
+ l1 = strlen(s1);
+
+ if (l1<l0) {
+ l0 = l1;
+ }
+
+ for(i=0;i<l0;i++) {
+ if (s1[i] > s0[i]) {
+ return true;
+ }
+ if (s1[i] < s0[i]) {
+ return false;
+ }
+ }
+ return false;
+}
+
+/*
+==============
+Sys_ListFiles
+==============
+*/
+char **Sys_ListFiles( const char *directory, const char *extension,
+ const char *filter, int *numfiles, bool wantsubs )
+{
+ char search[MAX_OSPATH];
+ int nfiles;
+ char **listCopy;
+ char *list[MAX_FOUND_FILES];
+ struct _finddata_t findinfo;
+ intptr_t findhandle;
+ int flag;
+ int i;
+ int extLen;
+
+ if (filter) {
+
+ nfiles = 0;
+ Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
+
+ list[ nfiles ] = 0;
+ *numfiles = nfiles;
+
+ if (!nfiles)
+ return NULL;
+
+ listCopy = (char**)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
+ for ( i = 0 ; i < nfiles ; i++ ) {
+ listCopy[i] = list[i];
+ }
+ listCopy[i] = NULL;
+
+ return listCopy;
+ }
+
+ if ( !extension) {
+ extension = "";
+ }
+
+ // passing a slash as extension will find directories
+ if ( extension[0] == '/' && extension[1] == 0 ) {
+ extension = "";
+ flag = 0;
+ } else {
+ flag = _A_SUBDIR;
+ }
+
+ extLen = strlen( extension );
+
+ Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension );
+
+ // search
+ nfiles = 0;
+
+ findhandle = _findfirst (search, &findinfo);
+ if (findhandle == -1) {
+ *numfiles = 0;
+ return NULL;
+ }
+
+ do {
+ if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) {
+ if (*extension) {
+ if ( strlen( findinfo.name ) < extLen ||
+ Q_stricmp(
+ findinfo.name + strlen( findinfo.name ) - extLen,
+ extension ) ) {
+ continue; // didn't match
+ }
+ }
+ if ( nfiles == MAX_FOUND_FILES - 1 ) {
+ break;
+ }
+ list[ nfiles ] = CopyString( findinfo.name );
+ nfiles++;
+ }
+ } while ( _findnext (findhandle, &findinfo) != -1 );
+
+ list[ nfiles ] = 0;
+
+ _findclose (findhandle);
+
+ // return a copy of the list
+ *numfiles = nfiles;
+
+ if ( !nfiles ) {
+ return NULL;
+ }
+
+ listCopy = (char**)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
+ for ( i = 0 ; i < nfiles ; i++ ) {
+ listCopy[i] = list[i];
+ }
+ listCopy[i] = NULL;
+
+ do {
+ flag = 0;
+ for(i=1; i<nfiles; i++) {
+ if (strgtr(listCopy[i-1], listCopy[i])) {
+ char *temp = listCopy[i];
+ listCopy[i] = listCopy[i-1];
+ listCopy[i-1] = temp;
+ flag = 1;
+ }
+ }
+ } while(flag);
+
+ return listCopy;
+}
+
+/*
+==============
+Sys_FreeFileList
+==============
+*/
+void Sys_FreeFileList( char **list )
+{
+ int i;
+
+ if ( !list ) {
+ return;
+ }
+
+ for ( i = 0 ; list[i] ; i++ ) {
+ Z_Free( list[i] );
+ }
+
+ Z_Free( list );
+}
+
+
+/*
+==============
+Sys_Sleep
+
+Block execution for msec or until input is received.
+==============
+*/
+void Sys_Sleep( int msec )
+{
+ if( msec == 0 )
+ return;
+
+#ifdef DEDICATED
+ if( msec < 0 )
+ WaitForSingleObject( GetStdHandle( STD_INPUT_HANDLE ), INFINITE );
+ else
+ WaitForSingleObject( GetStdHandle( STD_INPUT_HANDLE ), msec );
+#else
+ // Client Sys_Sleep doesn't support waiting on stdin
+ if( msec < 0 )
+ return;
+
+ Sleep( msec );
+#endif
+}
+
+/*
+==============
+Sys_ErrorDialog
+
+Display an error message
+==============
+*/
+void Sys_ErrorDialog( const char *error )
+{
+ if( Sys_Dialog( DT_YES_NO, va( "%s. Copy console log to clipboard?", error ),
+ "Error" ) == DR_YES )
+ {
+ HGLOBAL memoryHandle;
+ char *clipMemory;
+
+ memoryHandle = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, CON_LogSize( ) + 1 );
+ clipMemory = (char *)GlobalLock( memoryHandle );
+
+ if( clipMemory )
+ {
+ char *p = clipMemory;
+ char buffer[ 1024 ];
+ unsigned int size;
+
+ while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 )
+ {
+ memcpy( p, buffer, size );
+ p += size;
+ }
+
+ *p = '\0';
+
+ if( OpenClipboard( NULL ) && EmptyClipboard( ) )
+ SetClipboardData( CF_TEXT, memoryHandle );
+
+ GlobalUnlock( clipMemory );
+ CloseClipboard( );
+ }
+ }
+}
+
+/*
+==============
+Sys_Dialog
+
+Display a win32 dialog box
+==============
+*/
+dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title )
+{
+ UINT uType;
+
+ switch( type )
+ {
+ default:
+ case DT_INFO: uType = MB_ICONINFORMATION|MB_OK; break;
+ case DT_WARNING: uType = MB_ICONWARNING|MB_OK; break;
+ case DT_ERROR: uType = MB_ICONERROR|MB_OK; break;
+ case DT_YES_NO: uType = MB_ICONQUESTION|MB_YESNO; break;
+ case DT_OK_CANCEL: uType = MB_ICONWARNING|MB_OKCANCEL; break;
+ }
+
+ switch( MessageBox( NULL, message, title, uType ) )
+ {
+ default:
+ case IDOK: return DR_OK;
+ case IDCANCEL: return DR_CANCEL;
+ case IDYES: return DR_YES;
+ case IDNO: return DR_NO;
+ }
+}
+
+/*
+==============
+Sys_GLimpSafeInit
+
+Windows specific "safe" GL implementation initialisation
+==============
+*/
+void Sys_GLimpSafeInit( void )
+{
+}
+
+/*
+==============
+Sys_GLimpInit
+
+Windows specific GL implementation initialisation
+==============
+*/
+void Sys_GLimpInit( void )
+{
+}
+
+/*
+==============
+Sys_PlatformInit
+
+Windows specific initialisation
+==============
+*/
+void Sys_PlatformInit( void )
+{
+#ifndef DEDICATED
+ TIMECAPS ptc;
+#endif
+
+ Sys_SetFloatEnv();
+
+#ifndef DEDICATED
+ if(timeGetDevCaps(&ptc, sizeof(ptc)) == MMSYSERR_NOERROR)
+ {
+ timerResolution = ptc.wPeriodMin;
+
+ if(timerResolution > 1)
+ {
+ Com_Printf("Warning: Minimum supported timer resolution is %ums "
+ "on this system, recommended resolution 1ms\n", timerResolution);
+ }
+
+ timeBeginPeriod(timerResolution);
+ }
+ else
+ timerResolution = 0;
+#endif
+}
+
+/*
+==============
+Sys_PlatformExit
+
+Windows specific initialisation
+==============
+*/
+void Sys_PlatformExit( void )
+{
+#ifndef DEDICATED
+ if(timerResolution)
+ timeEndPeriod(timerResolution);
+#endif
+}
+
+/*
+==============
+Sys_SetEnv
+
+set/unset environment variables (empty value removes it)
+==============
+*/
+void Sys_SetEnv(const char *name, const char *value)
+{
+ if(value)
+ _putenv(va("%s=%s", name, value));
+ else
+ _putenv(va("%s=", name));
+}
+
+/*
+==============
+Sys_PID
+==============
+*/
+int Sys_PID( void )
+{
+ return GetCurrentProcessId( );
+}
+
+/*
+==============
+Sys_PIDIsRunning
+==============
+*/
+bool Sys_PIDIsRunning( int pid )
+{
+ DWORD processes[ 1024 ];
+ DWORD numBytes, numProcesses;
+ int i;
+
+ if( !EnumProcesses( processes, sizeof( processes ), &numBytes ) )
+ return false; // Assume it's not running
+
+ numProcesses = numBytes / sizeof( DWORD );
+
+ // Search for the pid
+ for( i = 0; i < numProcesses; i++ )
+ {
+ if( processes[ i ] == pid )
+ return true;
+ }
+
+ return false;
+}
+
+/*
+=================
+Sys_DllExtension
+
+Check if filename should be allowed to be loaded as a DLL.
+=================
+*/
+bool Sys_DllExtension( const char *name )
+{
+ return COM_CompareExtension( name, DLL_EXT );
+}
diff --git a/src/sys/sys_win32_default_homepath.cpp b/src/sys/sys_win32_default_homepath.cpp
new file mode 100644
index 0000000..1c4a149
--- /dev/null
+++ b/src/sys/sys_win32_default_homepath.cpp
@@ -0,0 +1,52 @@
+#include "sys_local.h"
+
+#include "qcommon/cvar.h"
+#include "qcommon/q_shared.h"
+#include "qcommon/q_platform.h"
+
+#include <windows.h>
+#include <lmerr.h>
+#include <lmcons.h>
+#include <lmwksta.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <direct.h>
+#include <io.h>
+#include <conio.h>
+#include <wincrypt.h>
+#include <shlobj.h>
+#include <psapi.h>
+#include <float.h>
+
+// Used to determine where to store user-specific files
+static char homePath[ MAX_OSPATH ] = { 0 };
+
+/*
+================
+Sys_DefaultHomePath
+================
+*/
+char *Sys_DefaultHomePath( void )
+{
+ TCHAR szPath[MAX_PATH];
+
+ if(!*homePath && com_homepath)
+ {
+ if( !SUCCEEDED( SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, 0, szPath ) ) )
+ {
+ Com_Printf("Unable to detect CSIDL_APPDATA\n");
+ return NULL;
+ }
+
+ Com_sprintf(homePath, sizeof(homePath), "%s%c", szPath, PATH_SEP);
+
+ if(com_homepath->string[0])
+ Q_strcat(homePath, sizeof(homePath), com_homepath->string);
+ else
+ Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_WIN);
+ }
+
+ return homePath;
+}
+
diff --git a/src/sys/win_resource.h b/src/sys/win_resource.h
new file mode 100644
index 0000000..8c8783a
--- /dev/null
+++ b/src/sys/win_resource.h
@@ -0,0 +1,46 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by winquake.rc
+//
+#define IDS_STRING1 1
+#define IDI_ICON1 1
+#define IDB_BITMAP1 1
+#define IDB_BITMAP2 128
+#define IDC_CURSOR1 129
+#define IDC_CURSOR2 130
+#define IDC_CURSOR3 131
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 132
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1005
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/sys/win_resource.rc b/src/sys/win_resource.rc
new file mode 100644
index 0000000..6f5d82a
--- /dev/null
+++ b/src/sys/win_resource.rc
@@ -0,0 +1,72 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "win_resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <winresrc.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 DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""winres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON1 ICON DISCARDABLE "misc/tremulous.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_STRING1 "Tremulous"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
new file mode 100644
index 0000000..c54f9ce
--- /dev/null
+++ b/src/tools/CMakeLists.txt
@@ -0,0 +1,145 @@
+# _______ ___ ___ _______ __ __
+# | | | | | | .----.-----.--------.-----.|__| |.-----.----.
+# | - _| | | | | __| _ | | _ || | || -__| _|
+# |_______|\_____/|__|_|__| |____|_____|__|__|__| __||__|__||_____|__|
+# |__|
+# TODO: DO NOT build unless building a QVM
+
+
+# _ _
+# | || |
+# | || | ,_ __,
+# |/ |/ \_| | / | / |
+# |__/\_/ \_/|_/ |_/\_/|/
+# /|
+# \|
+
+add_executable(
+ lburg
+ lcc/lburg/lburg.c
+ lcc/lburg/gram.c
+ )
+
+
+# ___
+# / \
+# __, __/ __, , _ _ _
+# / | \/ | / \_/ |/ |/ |
+# \_/|_/\___/\_/|_/ \/ | | |_/
+# |\
+# |/
+#
+
+add_executable(
+ q3asm
+ asm/q3asm.c
+ asm/cmdlib.c
+ )
+
+target_include_directories( q3asm PUBLIC lcc/src lcc/lburg )
+
+
+# ___ _
+# / \| |
+# __, __/| | __ __
+# / | \|/ / /
+# \_/|_/\___/|__/\___/\___/
+# |\
+# |/
+#
+
+add_executable(
+ q3lcc
+ lcc/etc/bytecode.c
+ lcc/etc/lcc.c
+ )
+
+target_include_directories( q3lcc PUBLIC lcc/src lcc/lburg )
+
+# ___
+# / \
+# __, __/ __ _ _
+#/ | \/ |/ \_|/ \_
+#\_/|_/\___/\___/|__/ |__/
+# |\ /| /|
+# |/ \| \|
+#
+
+add_executable(
+ q3cpp
+ #
+ lcc/cpp/cpp.c
+ lcc/cpp/lex.c
+ lcc/cpp/nlist.c
+ lcc/cpp/tokens.c
+ lcc/cpp/macro.c
+ lcc/cpp/eval.c
+ lcc/cpp/include.c
+ lcc/cpp/hideset.c
+ lcc/cpp/getopt.c
+ lcc/cpp/unix.c
+ )
+
+target_include_directories( q3cpp PUBLIC lcc/src lcc/lburg )
+
+# ___
+# / \
+# __, __/ ,_ __ __
+# / | \/ | / /
+# \_/|_/\___/ |_/\___/\___/
+# |\
+# |/
+#
+
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dagcheck.c
+ COMMAND lburg
+ ARGS ${CMAKE_CURRENT_SOURCE_DIR}/lcc/src/dagcheck.md dagcheck.c
+ DEPENDS lburg lcc/src/dagcheck.md
+ )
+set_source_files_properties(dagcheck.c PROPERTIES GENERATED TRUE)
+
+add_executable(
+ q3rcc
+ lcc/src/alloc.c
+ lcc/src/bind.c
+ lcc/src/bytecode.c
+ lcc/src/dag.c
+ ${CMAKE_CURRENT_BINARY_DIR}/dagcheck.c
+ lcc/src/decl.c
+ lcc/src/enode.c
+ lcc/src/error.c
+ lcc/src/event.c
+ lcc/src/expr.c
+ lcc/src/gen.c
+ lcc/src/init.c
+ lcc/src/inits.c
+ lcc/src/input.c
+ lcc/src/lex.c
+ lcc/src/list.c
+ lcc/src/main.c
+ lcc/src/null.c
+ lcc/src/output.c
+ lcc/src/prof.c
+ lcc/src/profio.c
+ lcc/src/simp.c
+ lcc/src/stmt.c
+ lcc/src/string.c
+ lcc/src/sym.c
+ lcc/src/symbolic.c
+ lcc/src/trace.c
+ lcc/src/tree.c
+ lcc/src/types.c
+ )
+
+target_include_directories( q3rcc PUBLIC lcc/src lcc/lburg )
+
+set_property(
+ TARGET lburg q3asm q3lcc q3cpp q3rcc
+ PROPERTY RUNTIME_OUTPUT_DIRECTORY
+ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/qvm_tools
+ )
+
+# Victor Roemer (wtfbbqhax), <victor@badsec.org>.
+cmake_minimum_required(VERSION 3.5)
+project(QVMCompiler C)
diff --git a/src/tools/asm/cmdlib.c b/src/tools/asm/cmdlib.c
index 5929d95..9d530b3 100644
--- a/src/tools/asm/cmdlib.c
+++ b/src/tools/asm/cmdlib.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cmdlib.c
diff --git a/src/tools/asm/cmdlib.h b/src/tools/asm/cmdlib.h
index 3b2f2db..78aeabd 100644
--- a/src/tools/asm/cmdlib.h
+++ b/src/tools/asm/cmdlib.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// cmdlib.h
diff --git a/src/tools/asm/mathlib.h b/src/tools/asm/mathlib.h
index 71bbabb..32e43e7 100644
--- a/src/tools/asm/mathlib.h
+++ b/src/tools/asm/mathlib.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
#ifndef __MATHLIB__
diff --git a/src/tools/asm/opstrings.h b/src/tools/asm/opstrings.h
index 0bf81ab..ce8837c 100644
--- a/src/tools/asm/opstrings.h
+++ b/src/tools/asm/opstrings.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
{ "BREAK", OP_BREAK },
@@ -172,5 +173,3 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
{ "LOADI4", OP_UNDEF },
{ "LOADP4", OP_UNDEF },
{ "LOADU4", OP_UNDEF },
-
-
diff --git a/src/tools/asm/q3asm.c b/src/tools/asm/q3asm.c
index 0e35246..b18e5e9 100644
--- a/src/tools/asm/q3asm.c
+++ b/src/tools/asm/q3asm.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,15 +17,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
-#include "../../qcommon/q_platform.h"
+#include "qcommon/q_platform.h"
+
#include "cmdlib.h"
#include "mathlib.h"
-#include "../../qcommon/qfiles.h"
+#include "qfiles.h"
/* 19079 total symbols in FI, 2002 Jan 23 */
#define DEFAULT_HASHTABLE_SIZE 2048
@@ -478,7 +480,7 @@ static unsigned int HashString (const char *key)
acc = (acc << 2) | (acc >> 30);
acc &= 0xffffffffU;
}
- return abs((int)acc);
+ return acc;
}
@@ -1645,4 +1647,3 @@ Motivation: not wanting to scrollback for pages to find asm error.
return errorCount;
}
-
diff --git a/src/tools/asm/qfiles.h b/src/tools/asm/qfiles.h
new file mode 100644
index 0000000..6b0070e
--- /dev/null
+++ b/src/tools/asm/qfiles.h
@@ -0,0 +1,480 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+// qfiles.h: quake file formats
+
+#ifndef __QFILES_H__
+#define __QFILES_H__
+
+// This file must be identical in the quake and utils directories
+
+// Ignore __attribute__ on non-gcc platforms
+#ifndef __GNUC__
+#ifndef __attribute__
+#define __attribute__(x)
+#endif
+#endif
+
+// surface geometry should not exceed these limits
+#define SHADER_MAX_VERTEXES 1000
+#define SHADER_MAX_INDEXES (6 * SHADER_MAX_VERTEXES)
+
+// the maximum size of game relative pathnames
+#define MAX_QPATH 64
+
+/*
+========================================================================
+
+QVM files
+
+========================================================================
+*/
+
+#define VM_MAGIC 0x12721444
+#define VM_MAGIC_VER2 0x12721445
+typedef struct {
+ int vmMagic;
+
+ int instructionCount;
+
+ int codeOffset;
+ int codeLength;
+
+ int dataOffset;
+ int dataLength;
+ int litLength; // ( dataLength - litLength ) should be byteswapped on load
+ int bssLength; // zero filled memory appended to datalength
+
+ //!!! below here is VM_MAGIC_VER2 !!!
+ int jtrgLength; // number of jump table targets
+} vmHeader_t;
+
+/*
+========================================================================
+
+.MD3 triangle model file format
+
+========================================================================
+*/
+
+#define MD3_IDENT (('3' << 24) + ('P' << 16) + ('D' << 8) + 'I')
+#define MD3_VERSION 15
+
+// limits
+#define MD3_MAX_LODS 3
+#define MD3_MAX_TRIANGLES 8192 // per surface
+#define MD3_MAX_VERTS 4096 // per surface
+#define MD3_MAX_SHADERS 256 // per surface
+#define MD3_MAX_FRAMES 1024 // per model
+#define MD3_MAX_SURFACES 32 // per model
+#define MD3_MAX_TAGS 16 // per frame
+
+// vertex scales
+#define MD3_XYZ_SCALE (1.0 / 64)
+
+typedef struct md3Frame_s {
+ vec3_t bounds[2];
+ vec3_t localOrigin;
+ float radius;
+ char name[16];
+} md3Frame_t;
+
+typedef struct md3Tag_s {
+ char name[MAX_QPATH]; // tag name
+ vec3_t origin;
+ vec3_t axis[3];
+} md3Tag_t;
+
+/*
+** md3Surface_t
+**
+** CHUNK SIZE
+** header sizeof( md3Surface_t )
+** shaders sizeof( md3Shader_t ) * numShaders
+** triangles[0] sizeof( md3Triangle_t ) * numTriangles
+** st sizeof( md3St_t ) * numVerts
+** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames
+*/
+typedef struct {
+ int ident; //
+
+ char name[MAX_QPATH]; // polyset name
+
+ int flags;
+ int numFrames; // all surfaces in a model should have the same
+
+ int numShaders; // all surfaces in a model should have the same
+ int numVerts;
+
+ int numTriangles;
+ int ofsTriangles;
+
+ int ofsShaders; // offset from start of md3Surface_t
+ int ofsSt; // texture coords are common for all frames
+ int ofsXyzNormals; // numVerts * numFrames
+
+ int ofsEnd; // next surface follows
+} md3Surface_t;
+
+typedef struct {
+ char name[MAX_QPATH];
+ int shaderIndex; // for in-game use
+} md3Shader_t;
+
+typedef struct {
+ int indexes[3];
+} md3Triangle_t;
+
+typedef struct {
+ float st[2];
+} md3St_t;
+
+typedef struct {
+ short xyz[3];
+ short normal;
+} md3XyzNormal_t;
+
+typedef struct {
+ int ident;
+ int version;
+
+ char name[MAX_QPATH]; // model name
+
+ int flags;
+
+ int numFrames;
+ int numTags;
+ int numSurfaces;
+
+ int numSkins;
+
+ int ofsFrames; // offset for first frame
+ int ofsTags; // numFrames * numTags
+ int ofsSurfaces; // first surface, others follow
+
+ int ofsEnd; // end of file
+} md3Header_t;
+
+/*
+==============================================================================
+
+MDR file format
+
+==============================================================================
+*/
+
+/*
+ * Here are the definitions for Ravensoft's model format of md4. Raven stores their
+ * playermodels in .mdr files, in some games, which are pretty much like the md4
+ * format implemented by ID soft. It seems like ID's original md4 stuff is not used at all.
+ * MDR is being used in EliteForce, JediKnight2 and Soldiers of Fortune2 (I think).
+ * So this comes in handy for anyone who wants to make it possible to load player
+ * models from these games.
+ * This format has bone tags, which is similar to the thing you have in md3 I suppose.
+ * Raven has released their version of md3view under GPL enabling me to add support
+ * to this codebase. Thanks to Steven Howes aka Skinner for helping with example
+ * source code.
+ *
+ * - Thilo Schulz (arny@ats.s.bawue.de)
+ */
+
+#define MDR_IDENT (('5' << 24) + ('M' << 16) + ('D' << 8) + 'R')
+#define MDR_VERSION 2
+#define MDR_MAX_BONES 128
+
+typedef struct {
+ int boneIndex; // these are indexes into the boneReferences,
+ float boneWeight; // not the global per-frame bone list
+ vec3_t offset;
+} mdrWeight_t;
+
+typedef struct {
+ vec3_t normal;
+ vec2_t texCoords;
+ int numWeights;
+ mdrWeight_t weights[1]; // variable sized
+} mdrVertex_t;
+
+typedef struct {
+ int indexes[3];
+} mdrTriangle_t;
+
+typedef struct {
+ int ident;
+
+ char name[MAX_QPATH]; // polyset name
+ char shader[MAX_QPATH];
+ int shaderIndex; // for in-game use
+
+ int ofsHeader; // this will be a negative number
+
+ int numVerts;
+ int ofsVerts;
+
+ int numTriangles;
+ int ofsTriangles;
+
+ // Bone references are a set of ints representing all the bones
+ // present in any vertex weights for this surface. This is
+ // needed because a model may have surfaces that need to be
+ // drawn at different sort times, and we don't want to have
+ // to re-interpolate all the bones for each surface.
+ int numBoneReferences;
+ int ofsBoneReferences;
+
+ int ofsEnd; // next surface follows
+} mdrSurface_t;
+
+typedef struct {
+ float matrix[3][4];
+} mdrBone_t;
+
+typedef struct {
+ vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
+ vec3_t localOrigin; // midpoint of bounds, used for sphere cull
+ float radius; // dist from localOrigin to corner
+ char name[16];
+ mdrBone_t bones[1]; // [numBones]
+} mdrFrame_t;
+
+typedef struct {
+ unsigned char Comp[24]; // MC_COMP_BYTES is in MatComp.h, but don't want to couple
+} mdrCompBone_t;
+
+typedef struct {
+ vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
+ vec3_t localOrigin; // midpoint of bounds, used for sphere cull
+ float radius; // dist from localOrigin to corner
+ mdrCompBone_t bones[1]; // [numBones]
+} mdrCompFrame_t;
+
+typedef struct {
+ int numSurfaces;
+ int ofsSurfaces; // first surface, others follow
+ int ofsEnd; // next lod follows
+} mdrLOD_t;
+
+typedef struct {
+ int boneIndex;
+ char name[32];
+} mdrTag_t;
+
+typedef struct {
+ int ident;
+ int version;
+
+ char name[MAX_QPATH]; // model name
+
+ // frames and bones are shared by all levels of detail
+ int numFrames;
+ int numBones;
+ int ofsFrames; // mdrFrame_t[numFrames]
+
+ // each level of detail has completely separate sets of surfaces
+ int numLODs;
+ int ofsLODs;
+
+ int numTags;
+ int ofsTags;
+
+ int ofsEnd; // end of file
+} mdrHeader_t;
+
+/*
+==============================================================================
+
+ .BSP file format
+
+==============================================================================
+*/
+
+#define BSP_IDENT (('P' << 24) + ('S' << 16) + ('B' << 8) + 'I')
+// little-endian "IBSP"
+
+#define BSP_VERSION 46
+
+// there shouldn't be any problem with increasing these values at the
+// expense of more memory allocation in the utilities
+#define MAX_MAP_MODELS 0x400
+#define MAX_MAP_BRUSHES 0x8000
+#define MAX_MAP_ENTITIES 0x800
+#define MAX_MAP_ENTSTRING 0x40000
+#define MAX_MAP_SHADERS 0x400
+
+#define MAX_MAP_AREAS 0x100 // MAX_MAP_AREA_BYTES in q_shared must match!
+#define MAX_MAP_FOGS 0x100
+#define MAX_MAP_PLANES 0x20000
+#define MAX_MAP_NODES 0x20000
+#define MAX_MAP_BRUSHSIDES 0x20000
+#define MAX_MAP_LEAFS 0x20000
+#define MAX_MAP_LEAFFACES 0x20000
+#define MAX_MAP_LEAFBRUSHES 0x40000
+#define MAX_MAP_PORTALS 0x20000
+#define MAX_MAP_LIGHTING 0x800000
+#define MAX_MAP_LIGHTGRID 0x800000
+#define MAX_MAP_VISIBILITY 0x200000
+
+#define MAX_MAP_DRAW_SURFS 0x20000
+#define MAX_MAP_DRAW_VERTS 0x80000
+#define MAX_MAP_DRAW_INDEXES 0x80000
+
+// key / value pair sizes in the entities lump
+#define MAX_KEY 32
+#define MAX_VALUE 1024
+
+// the editor uses these predefined yaw angles to orient entities up or down
+#define ANGLE_UP -1
+#define ANGLE_DOWN -2
+
+#define LIGHTMAP_WIDTH 128
+#define LIGHTMAP_HEIGHT 128
+
+#define MAX_WORLD_COORD (128 * 1024)
+#define MIN_WORLD_COORD (-128 * 1024)
+#define WORLD_SIZE (MAX_WORLD_COORD - MIN_WORLD_COORD)
+
+//=============================================================================
+
+typedef struct {
+ int fileofs, filelen;
+} lump_t;
+
+#define LUMP_ENTITIES 0
+#define LUMP_SHADERS 1
+#define LUMP_PLANES 2
+#define LUMP_NODES 3
+#define LUMP_LEAFS 4
+#define LUMP_LEAFSURFACES 5
+#define LUMP_LEAFBRUSHES 6
+#define LUMP_MODELS 7
+#define LUMP_BRUSHES 8
+#define LUMP_BRUSHSIDES 9
+#define LUMP_DRAWVERTS 10
+#define LUMP_DRAWINDEXES 11
+#define LUMP_FOGS 12
+#define LUMP_SURFACES 13
+#define LUMP_LIGHTMAPS 14
+#define LUMP_LIGHTGRID 15
+#define LUMP_VISIBILITY 16
+#define HEADER_LUMPS 17
+
+typedef struct {
+ int ident;
+ int version;
+
+ lump_t lumps[HEADER_LUMPS];
+} dheader_t;
+
+typedef struct {
+ float mins[3], maxs[3];
+ int firstSurface, numSurfaces;
+ int firstBrush, numBrushes;
+} dmodel_t;
+
+typedef struct {
+ char shader[MAX_QPATH];
+ int surfaceFlags;
+ int contentFlags;
+} dshader_t;
+
+// planes x^1 is allways the opposite of plane x
+
+typedef struct {
+ float normal[3];
+ float dist;
+} dplane_t;
+
+typedef struct {
+ int planeNum;
+ int children[2]; // negative numbers are -(leafs+1), not nodes
+ int mins[3]; // for frustom culling
+ int maxs[3];
+} dnode_t;
+
+typedef struct {
+ int cluster; // -1 = opaque cluster (do I still store these?)
+ int area;
+
+ int mins[3]; // for frustum culling
+ int maxs[3];
+
+ int firstLeafSurface;
+ int numLeafSurfaces;
+
+ int firstLeafBrush;
+ int numLeafBrushes;
+} dleaf_t;
+
+typedef struct {
+ int planeNum; // positive plane side faces out of the leaf
+ int shaderNum;
+} dbrushside_t;
+
+typedef struct {
+ int firstSide;
+ int numSides;
+ int shaderNum; // the shader that determines the contents flags
+} dbrush_t;
+
+typedef struct {
+ char shader[MAX_QPATH];
+ int brushNum;
+ int visibleSide; // the brush side that ray tests need to clip against (-1 == none)
+} dfog_t;
+
+typedef struct {
+ vec3_t xyz;
+ float st[2];
+ float lightmap[2];
+ vec3_t normal;
+ byte color[4];
+} drawVert_t;
+
+#define drawVert_t_cleared(x) drawVert_t(x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}}
+
+typedef enum { MST_BAD, MST_PLANAR, MST_PATCH, MST_TRIANGLE_SOUP, MST_FLARE } mapSurfaceType_t;
+
+typedef struct {
+ int shaderNum;
+ int fogNum;
+ int surfaceType;
+
+ int firstVert;
+ int numVerts;
+
+ int firstIndex;
+ int numIndexes;
+
+ int lightmapNum;
+ int lightmapX, lightmapY;
+ int lightmapWidth, lightmapHeight;
+
+ vec3_t lightmapOrigin;
+ vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds
+
+ int patchWidth;
+ int patchHeight;
+} dsurface_t;
+
+#endif
diff --git a/src/tools/lcc/cpp/cpp.c b/src/tools/lcc/cpp/cpp.c
index 5c0cfd7..c379a72 100644
--- a/src/tools/lcc/cpp/cpp.c
+++ b/src/tools/lcc/cpp/cpp.c
@@ -1,326 +1,339 @@
+#include "cpp.h"
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include <stdarg.h>
-#include "cpp.h"
char rcsid[] = "cpp.c - faked rcsid";
-#define OUTS 16384
-char outbuf[OUTS];
-char *outbufp = outbuf;
-Source *cursource;
-int nerrs;
-struct token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" };
-char *curtime;
-int incdepth;
-int ifdepth;
-int ifsatisfied[NIF];
-int skipping;
-
-
-int
-main(int argc, char **argv)
+#define OUTS 16384
+char outbuf[OUTS];
+char *outbufp = outbuf;
+Source *cursource;
+int nerrs;
+struct token nltoken = {NL, 0, 0, 0, 1, (uchar *)"\n"};
+char *curtime;
+int incdepth;
+int ifdepth;
+int ifsatisfied[NIF];
+int skipping;
+
+int main(int argc, char **argv)
{
- Tokenrow tr;
- time_t t;
- char ebuf[BUFSIZ];
-
- setbuf(stderr, ebuf);
- t = time(NULL);
- curtime = ctime(&t);
- maketokenrow(3, &tr);
- expandlex();
- setup(argc, argv);
- fixlex();
- iniths();
- genline();
- process(&tr);
- flushout();
- fflush(stderr);
- exit(nerrs > 0);
- return 0;
+ Tokenrow tr;
+ time_t t;
+ char ebuf[BUFSIZ];
+
+ setbuf(stderr, ebuf);
+ t = time(NULL);
+ curtime = ctime(&t);
+ maketokenrow(3, &tr);
+ expandlex();
+ setup(argc, argv);
+ fixlex();
+ iniths();
+ genline();
+ process(&tr);
+ flushout();
+ fflush(stderr);
+ exit(nerrs > 0);
+ return 0;
}
-void
-process(Tokenrow *trp)
+void process(Tokenrow *trp)
{
- int anymacros = 0;
-
- for (;;) {
- if (trp->tp >= trp->lp) {
- trp->tp = trp->lp = trp->bp;
- outbufp = outbuf;
- anymacros |= gettokens(trp, 1);
- trp->tp = trp->bp;
- }
- if (trp->tp->type == END) {
- if (--incdepth>=0) {
- if (cursource->ifdepth)
- error(ERROR,
- "Unterminated conditional in #include");
- unsetsource();
- cursource->line += cursource->lineinc;
- trp->tp = trp->lp;
- genline();
- continue;
- }
- if (ifdepth)
- error(ERROR, "Unterminated #if/#ifdef/#ifndef");
- break;
- }
- if (trp->tp->type==SHARP) {
- trp->tp += 1;
- control(trp);
- } else if (!skipping && anymacros)
- expandrow(trp, NULL);
- if (skipping)
- setempty(trp);
- puttokens(trp);
- anymacros = 0;
- cursource->line += cursource->lineinc;
- if (cursource->lineinc>1) {
- genline();
- }
- }
+ int anymacros = 0;
+
+ for (;;)
+ {
+ if (trp->tp >= trp->lp)
+ {
+ trp->tp = trp->lp = trp->bp;
+ outbufp = outbuf;
+ anymacros |= gettokens(trp, 1);
+ trp->tp = trp->bp;
+ }
+ if (trp->tp->type == END)
+ {
+ if (--incdepth >= 0)
+ {
+ if (cursource->ifdepth)
+ error(ERROR, "Unterminated conditional in #include");
+ unsetsource();
+ cursource->line += cursource->lineinc;
+ trp->tp = trp->lp;
+ genline();
+ continue;
+ }
+ if (ifdepth)
+ error(ERROR, "Unterminated #if/#ifdef/#ifndef");
+ break;
+ }
+ if (trp->tp->type == SHARP)
+ {
+ trp->tp += 1;
+ control(trp);
+ }
+ else if (!skipping && anymacros)
+ expandrow(trp, NULL);
+ if (skipping)
+ setempty(trp);
+ puttokens(trp);
+ anymacros = 0;
+ cursource->line += cursource->lineinc;
+ if (cursource->lineinc > 1)
+ {
+ genline();
+ }
+ }
}
-
-void
-control(Tokenrow *trp)
-{
- Nlist *np;
- Token *tp;
-
- tp = trp->tp;
- if (tp->type!=NAME) {
- if (tp->type==NUMBER)
- goto kline;
- if (tp->type != NL)
- error(ERROR, "Unidentifiable control line");
- return; /* else empty line */
- }
- if ((np = lookup(tp, 0))==NULL || ((np->flag&ISKW)==0 && !skipping)) {
- error(WARNING, "Unknown preprocessor control %t", tp);
- return;
- }
- if (skipping) {
- switch (np->val) {
- case KENDIF:
- if (--ifdepth<skipping)
- skipping = 0;
- --cursource->ifdepth;
- setempty(trp);
- return;
-
- case KIFDEF:
- case KIFNDEF:
- case KIF:
- if (++ifdepth >= NIF)
- error(FATAL, "#if too deeply nested");
- ++cursource->ifdepth;
- return;
-
- case KELIF:
- case KELSE:
- if (ifdepth<=skipping)
- break;
- return;
-
- default:
- return;
- }
- }
- switch (np->val) {
- case KDEFINE:
- dodefine(trp);
- break;
-
- case KUNDEF:
- tp += 1;
- if (tp->type!=NAME || trp->lp - trp->bp != 4) {
- error(ERROR, "Syntax error in #undef");
- break;
- }
- if ((np = lookup(tp, 0)) != NULL)
- np->flag &= ~ISDEFINED;
- break;
-
- case KPRAGMA:
- return;
-
- case KIFDEF:
- case KIFNDEF:
- case KIF:
- if (++ifdepth >= NIF)
- error(FATAL, "#if too deeply nested");
- ++cursource->ifdepth;
- ifsatisfied[ifdepth] = 0;
- if (eval(trp, np->val))
- ifsatisfied[ifdepth] = 1;
- else
- skipping = ifdepth;
- break;
- case KELIF:
- if (ifdepth==0) {
- error(ERROR, "#elif with no #if");
- return;
- }
- if (ifsatisfied[ifdepth]==2)
- error(ERROR, "#elif after #else");
- if (eval(trp, np->val)) {
- if (ifsatisfied[ifdepth])
- skipping = ifdepth;
- else {
- skipping = 0;
- ifsatisfied[ifdepth] = 1;
- }
- } else
- skipping = ifdepth;
- break;
-
- case KELSE:
- if (ifdepth==0 || cursource->ifdepth==0) {
- error(ERROR, "#else with no #if");
- return;
- }
- if (ifsatisfied[ifdepth]==2)
- error(ERROR, "#else after #else");
- if (trp->lp - trp->bp != 3)
- error(ERROR, "Syntax error in #else");
- skipping = ifsatisfied[ifdepth]? ifdepth: 0;
- ifsatisfied[ifdepth] = 2;
- break;
-
- case KENDIF:
- if (ifdepth==0 || cursource->ifdepth==0) {
- error(ERROR, "#endif with no #if");
- return;
- }
- --ifdepth;
- --cursource->ifdepth;
- if (trp->lp - trp->bp != 3)
- error(WARNING, "Syntax error in #endif");
- break;
-
- case KWARNING:
- trp->tp = tp+1;
- error(WARNING, "#warning directive: %r", trp);
- break;
-
- case KERROR:
- trp->tp = tp+1;
- error(ERROR, "#error directive: %r", trp);
- break;
-
- case KLINE:
- trp->tp = tp+1;
- expandrow(trp, "<line>");
- tp = trp->bp+2;
- kline:
- if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp
- || ((tp+3==trp->lp && ((tp+1)->type!=STRING))||*(tp+1)->t=='L')){
- error(ERROR, "Syntax error in #line");
- return;
- }
- cursource->line = atol((char*)tp->t)-1;
- if (cursource->line<0 || cursource->line>=32768)
- error(WARNING, "#line specifies number out of range");
- tp = tp+1;
- if (tp+1<trp->lp)
- cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0);
- return;
-
- case KDEFINED:
- error(ERROR, "Bad syntax for control line");
- break;
-
- case KINCLUDE:
- doinclude(trp);
- trp->lp = trp->bp;
- return;
-
- case KEVAL:
- eval(trp, np->val);
- break;
-
- default:
- error(ERROR, "Preprocessor control `%t' not yet implemented", tp);
- break;
- }
- setempty(trp);
+void control(Tokenrow *trp)
+{
+ Nlist *np;
+ Token *tp;
+
+ tp = trp->tp;
+ if (tp->type != NAME)
+ {
+ if (tp->type == NUMBER)
+ goto kline;
+ if (tp->type != NL)
+ error(ERROR, "Unidentifiable control line");
+ return; /* else empty line */
+ }
+ if ((np = lookup(tp, 0)) == NULL || ((np->flag & ISKW) == 0 && !skipping))
+ {
+ error(WARNING, "Unknown preprocessor control %t", tp);
+ return;
+ }
+ if (skipping)
+ {
+ switch (np->val)
+ {
+ case KENDIF:
+ if (--ifdepth < skipping)
+ skipping = 0;
+ --cursource->ifdepth;
+ setempty(trp);
+ return;
+
+ case KIFDEF:
+ case KIFNDEF:
+ case KIF:
+ if (++ifdepth >= NIF)
+ error(FATAL, "#if too deeply nested");
+ ++cursource->ifdepth;
+ return;
+
+ case KELIF:
+ case KELSE:
+ if (ifdepth <= skipping)
+ break;
+ return;
+
+ default:
+ return;
+ }
+ }
+ switch (np->val)
+ {
+ case KDEFINE:
+ dodefine(trp);
+ break;
+
+ case KUNDEF:
+ tp += 1;
+ if (tp->type != NAME || trp->lp - trp->bp != 4)
+ {
+ error(ERROR, "Syntax error in #undef");
+ break;
+ }
+ if ((np = lookup(tp, 0)) != NULL)
+ np->flag &= ~ISDEFINED;
+ break;
+
+ case KPRAGMA:
+ return;
+
+ case KIFDEF:
+ case KIFNDEF:
+ case KIF:
+ if (++ifdepth >= NIF)
+ error(FATAL, "#if too deeply nested");
+ ++cursource->ifdepth;
+ ifsatisfied[ifdepth] = 0;
+ if (eval(trp, np->val))
+ ifsatisfied[ifdepth] = 1;
+ else
+ skipping = ifdepth;
+ break;
+
+ case KELIF:
+ if (ifdepth == 0)
+ {
+ error(ERROR, "#elif with no #if");
+ return;
+ }
+ if (ifsatisfied[ifdepth] == 2)
+ error(ERROR, "#elif after #else");
+ if (eval(trp, np->val))
+ {
+ if (ifsatisfied[ifdepth])
+ skipping = ifdepth;
+ else
+ {
+ skipping = 0;
+ ifsatisfied[ifdepth] = 1;
+ }
+ }
+ else
+ skipping = ifdepth;
+ break;
+
+ case KELSE:
+ if (ifdepth == 0 || cursource->ifdepth == 0)
+ {
+ error(ERROR, "#else with no #if");
+ return;
+ }
+ if (ifsatisfied[ifdepth] == 2)
+ error(ERROR, "#else after #else");
+ if (trp->lp - trp->bp != 3)
+ error(ERROR, "Syntax error in #else");
+ skipping = ifsatisfied[ifdepth] ? ifdepth : 0;
+ ifsatisfied[ifdepth] = 2;
+ break;
+
+ case KENDIF:
+ if (ifdepth == 0 || cursource->ifdepth == 0)
+ {
+ error(ERROR, "#endif with no #if");
+ return;
+ }
+ --ifdepth;
+ --cursource->ifdepth;
+ if (trp->lp - trp->bp != 3)
+ error(WARNING, "Syntax error in #endif");
+ break;
+
+ case KWARNING:
+ trp->tp = tp + 1;
+ error(WARNING, "#warning directive: %r", trp);
+ break;
+
+ case KERROR:
+ trp->tp = tp + 1;
+ error(ERROR, "#error directive: %r", trp);
+ break;
+
+ case KLINE:
+ trp->tp = tp + 1;
+ expandrow(trp, "<line>");
+ tp = trp->bp + 2;
+ kline:
+ if (tp + 1 >= trp->lp || tp->type != NUMBER || tp + 3 < trp->lp ||
+ ((tp + 3 == trp->lp && ((tp + 1)->type != STRING)) || *(tp + 1)->t == 'L'))
+ {
+ error(ERROR, "Syntax error in #line");
+ return;
+ }
+ cursource->line = atol((char *)tp->t) - 1;
+ if (cursource->line < 0 || cursource->line >= 32768)
+ error(WARNING, "#line specifies number out of range");
+ tp = tp + 1;
+ if (tp + 1 < trp->lp)
+ cursource->filename = (char *)newstring(tp->t + 1, tp->len - 2, 0);
+ return;
+
+ case KDEFINED:
+ error(ERROR, "Bad syntax for control line");
+ break;
+
+ case KINCLUDE:
+ doinclude(trp);
+ trp->lp = trp->bp;
+ return;
+
+ case KEVAL:
+ eval(trp, np->val);
+ break;
+
+ default:
+ error(ERROR, "Preprocessor control `%t' not yet implemented", tp);
+ break;
+ }
+ setempty(trp);
}
-void *
-domalloc(int size)
+void *domalloc(int size)
{
- void *p = malloc(size);
+ void *p = malloc(size);
- if (p==NULL)
- error(FATAL, "Out of memory from malloc");
- return p;
+ if (p == NULL)
+ error(FATAL, "Out of memory from malloc");
+ return p;
}
-void
-dofree(void *p)
-{
- free(p);
-}
+void dofree(void *p) { free(p); }
-void
-error(enum errtype type, char *string, ...)
+void error(enum errtype type, char *string, ...)
{
- va_list ap;
- char *cp, *ep;
- Token *tp;
- Tokenrow *trp;
- Source *s;
- int i;
-
- fprintf(stderr, "cpp: ");
- for (s=cursource; s; s=s->next)
- if (*s->filename)
- fprintf(stderr, "%s:%d ", s->filename, s->line);
- va_start(ap, string);
- for (ep=string; *ep; ep++) {
- if (*ep=='%') {
- switch (*++ep) {
-
- case 's':
- cp = va_arg(ap, char *);
- fprintf(stderr, "%s", cp);
- break;
- case 'd':
- i = va_arg(ap, int);
- fprintf(stderr, "%d", i);
- break;
- case 't':
- tp = va_arg(ap, Token *);
- fprintf(stderr, "%.*s", tp->len, tp->t);
- break;
-
- case 'r':
- trp = va_arg(ap, Tokenrow *);
- for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) {
- if (tp>trp->tp && tp->wslen)
- fputc(' ', stderr);
- fprintf(stderr, "%.*s", tp->len, tp->t);
- }
- break;
-
- default:
- fputc(*ep, stderr);
- break;
- }
- } else
- fputc(*ep, stderr);
- }
- va_end(ap);
- fputc('\n', stderr);
- if (type==FATAL)
- exit(1);
- if (type!=WARNING)
- nerrs = 1;
- fflush(stderr);
+ va_list ap;
+ char *cp, *ep;
+ Token *tp;
+ Tokenrow *trp;
+ Source *s;
+ int i;
+
+ fprintf(stderr, "cpp: ");
+ for (s = cursource; s; s = s->next)
+ if (*s->filename)
+ fprintf(stderr, "%s:%d ", s->filename, s->line);
+ va_start(ap, string);
+ for (ep = string; *ep; ep++)
+ {
+ if (*ep == '%')
+ {
+ switch (*++ep)
+ {
+ case 's':
+ cp = va_arg(ap, char *);
+ fprintf(stderr, "%s", cp);
+ break;
+ case 'd':
+ i = va_arg(ap, int);
+ fprintf(stderr, "%d", i);
+ break;
+ case 't':
+ tp = va_arg(ap, Token *);
+ fprintf(stderr, "%.*s", tp->len, tp->t);
+ break;
+
+ case 'r':
+ trp = va_arg(ap, Tokenrow *);
+ for (tp = trp->tp; tp < trp->lp && tp->type != NL; tp++)
+ {
+ if (tp > trp->tp && tp->wslen)
+ fputc(' ', stderr);
+ fprintf(stderr, "%.*s", tp->len, tp->t);
+ }
+ break;
+
+ default:
+ fputc(*ep, stderr);
+ break;
+ }
+ }
+ else
+ fputc(*ep, stderr);
+ }
+ va_end(ap);
+ fputc('\n', stderr);
+ if (type == FATAL)
+ exit(1);
+ if (type != WARNING)
+ nerrs = 1;
+ fflush(stderr);
}
diff --git a/src/tools/lcc/cpp/include.c b/src/tools/lcc/cpp/include.c
index 5ecd8b3..778cea2 100644
--- a/src/tools/lcc/cpp/include.c
+++ b/src/tools/lcc/cpp/include.c
@@ -3,151 +3,171 @@
#include <string.h>
#include "cpp.h"
-Includelist includelist[NINCLUDE];
+Includelist includelist[NINCLUDE];
-extern char *objname;
+extern char *objname;
-void appendDirToIncludeList( char *dir )
+void appendDirToIncludeList(char *dir)
{
- int i;
- char *fqdir;
+ int i;
+ char *fqdir;
- fqdir = (char *)newstring( (uchar *)includelist[NINCLUDE-1].file, 256, 0 );
- strcat( fqdir, "/" );
- strcat( fqdir, dir );
+ fqdir = (char *)newstring((uchar *)includelist[NINCLUDE - 1].file, 256, 0);
+ strcat(fqdir, "/");
+ strcat(fqdir, dir);
- //avoid adding it more than once
- for (i=NINCLUDE-2; i>=0; i--) {
- if (includelist[i].file &&
- !strcmp (includelist[i].file, fqdir)) {
- return;
- }
- }
+ // avoid adding it more than once
+ for (i = NINCLUDE - 2; i >= 0; i--)
+ {
+ if (includelist[i].file && !strcmp(includelist[i].file, fqdir))
+ {
+ return;
+ }
+ }
- for (i=NINCLUDE-2; i>=0; i--) {
- if (includelist[i].file==NULL) {
- includelist[i].always = 1;
- includelist[i].file = fqdir;
- break;
- }
- }
- if (i<0)
- error(FATAL, "Too many -I directives");
+ for (i = NINCLUDE - 2; i >= 0; i--)
+ {
+ if (includelist[i].file == NULL)
+ {
+ includelist[i].always = 1;
+ includelist[i].file = fqdir;
+ break;
+ }
+ }
+ if (i < 0)
+ error(FATAL, "Too many -I directives");
}
-void
-doinclude(Tokenrow *trp)
+void doinclude(Tokenrow *trp)
{
- char fname[256], iname[256];
- Includelist *ip;
- int angled, len, fd, i;
+ char fname[256], iname[256];
+ Includelist *ip;
+ int angled, len, fd, i;
- trp->tp += 1;
- if (trp->tp>=trp->lp)
- goto syntax;
- if (trp->tp->type!=STRING && trp->tp->type!=LT) {
- len = trp->tp - trp->bp;
- expandrow(trp, "<include>");
- trp->tp = trp->bp+len;
- }
- if (trp->tp->type==STRING) {
- len = trp->tp->len-2;
- if (len > sizeof(fname) - 1)
- len = sizeof(fname) - 1;
- strncpy(fname, (char*)trp->tp->t+1, len);
- angled = 0;
- } else if (trp->tp->type==LT) {
- len = 0;
- trp->tp++;
- while (trp->tp->type!=GT) {
- if (trp->tp>trp->lp || len+trp->tp->len+2 >= sizeof(fname))
- goto syntax;
- strncpy(fname+len, (char*)trp->tp->t, trp->tp->len);
- len += trp->tp->len;
- trp->tp++;
- }
- angled = 1;
- } else
- goto syntax;
- trp->tp += 2;
- if (trp->tp < trp->lp || len==0)
- goto syntax;
- fname[len] = '\0';
+ trp->tp += 1;
+ if (trp->tp >= trp->lp)
+ goto syntax;
+ if (trp->tp->type != STRING && trp->tp->type != LT)
+ {
+ len = trp->tp - trp->bp;
+ expandrow(trp, "<include>");
+ trp->tp = trp->bp + len;
+ }
+ if (trp->tp->type == STRING)
+ {
+ len = trp->tp->len - 2;
+ if (len > sizeof(fname) - 1)
+ len = sizeof(fname) - 1;
+ strncpy(fname, (char *)trp->tp->t + 1, len);
+ angled = 0;
+ }
+ else if (trp->tp->type == LT)
+ {
+ len = 0;
+ trp->tp++;
+ while (trp->tp->type != GT)
+ {
+ if (trp->tp > trp->lp || len + trp->tp->len + 2 >= sizeof(fname))
+ goto syntax;
+ strncpy(fname + len, (char *)trp->tp->t, trp->tp->len);
+ len += trp->tp->len;
+ trp->tp++;
+ }
+ angled = 1;
+ }
+ else
+ goto syntax;
+ trp->tp += 2;
+ if (trp->tp < trp->lp || len == 0)
+ goto syntax;
+ fname[len] = '\0';
- appendDirToIncludeList( basepath( fname ) );
+ appendDirToIncludeList(basepath(fname));
- if (fname[0]=='/') {
- fd = open(fname, 0);
- strcpy(iname, fname);
- } else for (fd = -1,i=NINCLUDE-1; i>=0; i--) {
- ip = &includelist[i];
- if (ip->file==NULL || ip->deleted || (angled && ip->always==0))
- continue;
- if (strlen(fname)+strlen(ip->file)+2 > sizeof(iname))
- continue;
- strcpy(iname, ip->file);
- strcat(iname, "/");
- strcat(iname, fname);
- if ((fd = open(iname, 0)) >= 0)
- break;
- }
- if ( Mflag>1 || (!angled&&Mflag==1) ) {
- write(1,objname,strlen(objname));
- write(1,iname,strlen(iname));
- write(1,"\n",1);
- }
- if (fd >= 0) {
- if (++incdepth > 10)
- error(FATAL, "#include too deeply nested");
- setsource((char*)newstring((uchar*)iname, strlen(iname), 0), fd, NULL);
- genline();
- } else {
- trp->tp = trp->bp+2;
- error(ERROR, "Could not find include file %r", trp);
- }
- return;
+ if (fname[0] == '/')
+ {
+ fd = open(fname, 0);
+ strcpy(iname, fname);
+ }
+ else
+ for (fd = -1, i = NINCLUDE - 1; i >= 0; i--)
+ {
+ ip = &includelist[i];
+ if (ip->file == NULL || ip->deleted || (angled && ip->always == 0))
+ continue;
+ if (strlen(fname) + strlen(ip->file) + 2 > sizeof(iname))
+ continue;
+ strcpy(iname, ip->file);
+ strcat(iname, "/");
+ strcat(iname, fname);
+ if ((fd = open(iname, 0)) >= 0)
+ break;
+ }
+ if (Mflag > 1 || (!angled && Mflag == 1))
+ {
+ write(1, objname, strlen(objname));
+ write(1, iname, strlen(iname));
+ write(1, "\n", 1);
+ }
+ if (fd >= 0)
+ {
+ if (++incdepth > 10)
+ error(FATAL, "#include too deeply nested");
+ setsource((char *)newstring((uchar *)iname, strlen(iname), 0), fd, NULL);
+ genline();
+ }
+ else
+ {
+ trp->tp = trp->bp + 2;
+ error(ERROR, "Could not find include file %r", trp);
+ }
+ return;
syntax:
- error(ERROR, "Syntax error in #include");
+ error(ERROR, "Syntax error in #include");
}
/*
* Generate a line directive for cursource
*/
-void
-genline(void)
+void genline(void)
{
- static Token ta = { UNCLASS };
- static Tokenrow tr = { &ta, &ta, &ta+1, 1 };
- uchar *p;
+ static Token ta = {UNCLASS};
+ static Tokenrow tr = {&ta, &ta, &ta + 1, 1};
+ uchar *p;
- ta.t = p = (uchar*)outbufp;
- strcpy((char*)p, "#line ");
- p += sizeof("#line ")-1;
- p = (uchar*)outnum((char*)p, cursource->line);
- *p++ = ' '; *p++ = '"';
- if (cursource->filename[0]!='/' && wd[0]) {
- strcpy((char*)p, wd);
- p += strlen(wd);
- *p++ = '/';
- }
- strcpy((char*)p, cursource->filename);
- p += strlen((char*)p);
- *p++ = '"'; *p++ = '\n';
- ta.len = (char*)p-outbufp;
- outbufp = (char*)p;
- tr.tp = tr.bp;
- puttokens(&tr);
+ ta.t = p = (uchar *)outbufp;
+ strcpy((char *)p, "#line ");
+ p += sizeof("#line ") - 1;
+ p = (uchar *)outnum((char *)p, cursource->line);
+ *p++ = ' ';
+ *p++ = '"';
+ if (cursource->filename[0] != '/' && wd[0])
+ {
+ strcpy((char *)p, wd);
+ p += strlen(wd);
+ *p++ = '/';
+ }
+ strcpy((char *)p, cursource->filename);
+ p += strlen((char *)p);
+ *p++ = '"';
+ *p++ = '\n';
+ ta.len = (char *)p - outbufp;
+ outbufp = (char *)p;
+ tr.tp = tr.bp;
+ puttokens(&tr);
}
-void
-setobjname(char *f)
+void setobjname(char *f)
{
- int n = strlen(f);
- objname = (char*)domalloc(n+5);
- strcpy(objname,f);
- if(objname[n-2]=='.'){
- strcpy(objname+n-1,"$O: ");
- }else{
- strcpy(objname+n,"$O: ");
- }
+ int n = strlen(f);
+ objname = (char *)domalloc(n + 5);
+ strcpy(objname, f);
+ if (objname[n - 2] == '.')
+ {
+ strcpy(objname + n - 1, "$O: ");
+ }
+ else
+ {
+ strcpy(objname + n, "$O: ");
+ }
}
diff --git a/src/tools/lcc/cpp/unix.c b/src/tools/lcc/cpp/unix.c
index ff1496a..ee975aa 100644
--- a/src/tools/lcc/cpp/unix.c
+++ b/src/tools/lcc/cpp/unix.c
@@ -1,134 +1,141 @@
-#include <stdio.h>
#include <stddef.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "cpp.h"
-extern int lcc_getopt(int, char *const *, const char *);
-extern char *optarg, rcsid[];
-extern int optind;
-int verbose;
-int Mflag; /* only print active include files */
-char *objname; /* "src.$O: " */
-int Cplusplus = 1;
+extern int lcc_getopt(int, char *const *, const char *);
+extern char *optarg, rcsid[];
+extern int optind;
+int verbose;
+int Mflag; /* only print active include files */
+char *objname; /* "src.$O: " */
+int Cplusplus = 1;
-void
-setup(int argc, char **argv)
+void setup(int argc, char **argv)
{
- int c, fd, i;
- char *fp, *dp;
- Tokenrow tr;
- extern void setup_kwtab(void);
- uchar *includeDirs[ NINCLUDE ] = { 0 };
- int numIncludeDirs = 0;
+ int c, fd, i;
+ char *fp, *dp;
+ Tokenrow tr;
+ extern void setup_kwtab(void);
+ uchar *includeDirs[NINCLUDE] = {0};
+ int numIncludeDirs = 0;
- setup_kwtab();
- while ((c = lcc_getopt(argc, argv, "MNOVv+I:D:U:F:lg")) != -1)
- switch (c) {
- case 'N':
- for (i=0; i<NINCLUDE; i++)
- if (includelist[i].always==1)
- includelist[i].deleted = 1;
- break;
- case 'I':
- includeDirs[ numIncludeDirs++ ] = newstring( (uchar *)optarg, strlen( optarg ), 0 );
- break;
- case 'D':
- case 'U':
- setsource("<cmdarg>", -1, optarg);
- maketokenrow(3, &tr);
- gettokens(&tr, 1);
- doadefine(&tr, c);
- unsetsource();
- break;
- case 'M':
- Mflag++;
- break;
- case 'v':
- fprintf(stderr, "%s %s\n", argv[0], rcsid);
- break;
- case 'V':
- verbose++;
- break;
- case '+':
- Cplusplus++;
- break;
- default:
- break;
- }
- dp = ".";
- fp = "<stdin>";
- fd = 0;
- if (optind<argc) {
- dp = basepath( argv[optind] );
- fp = (char*)newstring((uchar*)argv[optind], strlen(argv[optind]), 0);
- if ((fd = open(fp, 0)) <= 0)
- error(FATAL, "Can't open input file %s", fp);
- }
- if (optind+1<argc) {
- int fdo;
+ setup_kwtab();
+ while ((c = lcc_getopt(argc, argv, "MNOVv+I:D:U:F:lg")) != -1)
+ switch (c)
+ {
+ case 'N':
+ for (i = 0; i < NINCLUDE; i++)
+ if (includelist[i].always == 1)
+ includelist[i].deleted = 1;
+ break;
+ case 'I':
+ includeDirs[numIncludeDirs++] = newstring((uchar *)optarg, strlen(optarg), 0);
+ break;
+ case 'D':
+ case 'U':
+ setsource("<cmdarg>", -1, optarg);
+ maketokenrow(3, &tr);
+ gettokens(&tr, 1);
+ doadefine(&tr, c);
+ unsetsource();
+ break;
+ case 'M':
+ Mflag++;
+ break;
+ case 'v':
+ fprintf(stderr, "%s %s\n", argv[0], rcsid);
+ break;
+ case 'V':
+ verbose++;
+ break;
+ case '+':
+ Cplusplus++;
+ break;
+ default:
+ break;
+ }
+ dp = ".";
+ fp = "<stdin>";
+ fd = 0;
+ if (optind < argc)
+ {
+ dp = basepath(argv[optind]);
+ fp = (char *)newstring((uchar *)argv[optind], strlen(argv[optind]), 0);
+ if ((fd = open(fp, 0)) <= 0)
+ error(FATAL, "Can't open input file %s", fp);
+ }
+ if (optind + 1 < argc)
+ {
+ int fdo;
#ifdef WIN32
- fdo = creat(argv[optind+1], _S_IREAD | _S_IWRITE);
+ fdo = creat(argv[optind + 1], _S_IREAD | _S_IWRITE);
#else
- fdo = creat(argv[optind+1], 0666);
+ fdo = creat(argv[optind + 1], 0666);
#endif
- if (fdo<0)
- error(FATAL, "Can't open output file %s", argv[optind+1]);
- dup2(fdo, 1);
- }
- if(Mflag)
- setobjname(fp);
- includelist[NINCLUDE-1].always = 0;
- includelist[NINCLUDE-1].file = dp;
+ if (fdo < 0)
+ error(FATAL, "Can't open output file %s", argv[optind + 1]);
+ dup2(fdo, 1);
+ }
+ if (Mflag)
+ setobjname(fp);
+ includelist[NINCLUDE - 1].always = 0;
+ includelist[NINCLUDE - 1].file = dp;
- for( i = 0; i < numIncludeDirs; i++ )
- appendDirToIncludeList( (char *)includeDirs[ i ] );
+ for (i = 0; i < numIncludeDirs; i++)
+ appendDirToIncludeList((char *)includeDirs[i]);
- setsource(fp, fd, NULL);
+ setsource(fp, fd, NULL);
}
-
-char *basepath( char *fname )
+char *basepath(char *fname)
{
- char *dp = ".";
- char *p;
- if ((p = strrchr(fname, '/')) != NULL) {
- int dlen = p - fname;
- dp = (char*)newstring((uchar*)fname, dlen+1, 0);
- dp[dlen] = '\0';
- }
+ char *dp = ".";
+ char *p;
+ if ((p = strrchr(fname, '/')) != NULL)
+ {
+ int dlen = p - fname;
+ dp = (char *)newstring((uchar *)fname, dlen + 1, 0);
+ dp[dlen] = '\0';
+ }
- return dp;
+ return dp;
}
/* memmove is defined here because some vendors don't provide it at
all and others do a terrible job (like calling malloc) */
// -- ouch, that hurts -- ln
-#ifndef __APPLE__ /* always use the system memmove() on Mac OS X. --ryan. */
+/* always use the system memmove() on Mac OS X. --ryan. */
+#if !defined(__APPLE__) && !defined(_MSC_VER)
#ifdef memmove
#undef memmove
#endif
-void *
-memmove(void *dp, const void *sp, size_t n)
+void *memmove(void *dp, const void *sp, size_t n)
{
- unsigned char *cdp, *csp;
+ unsigned char *cdp, *csp;
- if (n<=0)
- return dp;
- cdp = dp;
- csp = (unsigned char *)sp;
- if (cdp < csp) {
- do {
- *cdp++ = *csp++;
- } while (--n);
- } else {
- cdp += n;
- csp += n;
- do {
- *--cdp = *--csp;
- } while (--n);
- }
- return dp;
+ if (n <= 0)
+ return dp;
+ cdp = dp;
+ csp = (unsigned char *)sp;
+ if (cdp < csp)
+ {
+ do
+ {
+ *cdp++ = *csp++;
+ } while (--n);
+ }
+ else
+ {
+ cdp += n;
+ csp += n;
+ do
+ {
+ *--cdp = *--csp;
+ } while (--n);
+ }
+ return dp;
}
#endif
diff --git a/src/tools/lcc/etc/bytecode.c b/src/tools/lcc/etc/bytecode.c
index a5855de..1bbee64 100644
--- a/src/tools/lcc/etc/bytecode.c
+++ b/src/tools/lcc/etc/bytecode.c
@@ -2,7 +2,7 @@
#include <string.h>
#include <stdio.h>
-#include "../../../qcommon/q_platform.h"
+#include "qcommon/q_platform.h"
#ifdef _WIN32
#define BINEXT ".exe"
diff --git a/src/tools/lcc/etc/lcc.c b/src/tools/lcc/etc/lcc.c
index aa3e789..9ebc47f 100644
--- a/src/tools/lcc/etc/lcc.c
+++ b/src/tools/lcc/etc/lcc.c
@@ -4,16 +4,16 @@
*/
static char rcsid[] = "Id: dummy rcsid";
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#ifdef WIN32
-#include <process.h> /* getpid() */
#include <io.h> /* access() */
+#include <process.h> /* getpid() */
#else
#include <unistd.h>
#endif
@@ -23,13 +23,13 @@ static char rcsid[] = "Id: dummy rcsid";
#endif
typedef struct list *List;
-struct list { /* circular list nodes: */
- char *str; /* option or file name */
- List link; /* next list element */
+struct list { /* circular list nodes: */
+ char *str; /* option or file name */
+ List link; /* next list element */
};
static void *alloc(int);
-static List append(char *,List);
+static List append(char *, List);
extern char *basename(char *);
static int callsys(char *[]);
extern char *concat(char *, char *);
@@ -57,228 +57,258 @@ extern char *tempname(char *);
extern int getpid(void);
#endif
-extern char *cpp[], *include[], *com[], *as[],*ld[], inputs[], *suffixes[];
+extern char *cpp[], *include[], *com[], *as[], *ld[], inputs[], *suffixes[];
extern int option(char *);
-static int errcnt; /* number of errors */
-static int Eflag; /* -E specified */
-static int Sflag = 1; /* -S specified */ //for Q3 we always generate asm
-static int cflag; /* -c specified */
-static int verbose; /* incremented for each -v */
-static List llist[2]; /* loader files, flags */
-static List alist; /* assembler flags */
-static List clist; /* compiler flags */
-static List plist; /* preprocessor flags */
-static List ilist; /* list of additional includes from LCCINPUTS */
-static List rmlist; /* list of files to remove */
-static char *outfile; /* ld output file or -[cS] object file */
-static int ac; /* argument count */
-static char **av; /* argument vector */
-char *tempdir = TEMPDIR; /* directory for temporary files */
+static int errcnt; /* number of errors */
+static int Eflag; /* -E specified */
+static int Sflag = 1; /* -S specified */ // for Q3 we always generate asm
+static int cflag; /* -c specified */
+static int verbose; /* incremented for each -v */
+static List llist[2]; /* loader files, flags */
+static List alist; /* assembler flags */
+static List clist; /* compiler flags */
+static List plist; /* preprocessor flags */
+static List ilist; /* list of additional includes from LCCINPUTS */
+static List rmlist; /* list of files to remove */
+static char *outfile; /* ld output file or -[cS] object file */
+static int ac; /* argument count */
+static char **av; /* argument vector */
+char *tempdir = TEMPDIR; /* directory for temporary files */
static char *progname;
-static List lccinputs; /* list of input directories */
+static List lccinputs; /* list of input directories */
-extern void UpdatePaths( const char *lccBinary );
+extern void UpdatePaths(const char *lccBinary);
-int main(int argc, char *argv[]) {
- int i, j, nf;
+int main(int argc, char *argv[])
+{
+ int i, j, nf;
- progname = argv[0];
+ progname = argv[0];
- UpdatePaths( progname );
+ UpdatePaths(progname);
- ac = argc + 50;
- av = alloc(ac*sizeof(char *));
- if (signal(SIGINT, SIG_IGN) != SIG_IGN)
- signal(SIGINT, interrupt);
- if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
- signal(SIGTERM, interrupt);
+ ac = argc + 50;
+ av = alloc(ac * sizeof(char *));
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, interrupt);
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+ signal(SIGTERM, interrupt);
#ifdef SIGHUP
- if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
- signal(SIGHUP, interrupt);
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ signal(SIGHUP, interrupt);
#endif
- if (getenv("TMP"))
- tempdir = getenv("TMP");
- else if (getenv("TEMP"))
- tempdir = getenv("TEMP");
- else if (getenv("TMPDIR"))
- tempdir = getenv("TMPDIR");
- assert(tempdir);
- i = strlen(tempdir);
- for (; (i > 0 && tempdir[i-1] == '/') || tempdir[i-1] == '\\'; i--)
- tempdir[i-1] = '\0';
- if (argc <= 1) {
- help();
- exit(0);
- }
- plist = append("-D__LCC__", 0);
- initinputs();
- if (getenv("LCCDIR"))
- option(stringf("-lccdir=%s", getenv("LCCDIR")));
- for (nf = 0, i = j = 1; i < argc; i++) {
- if (strcmp(argv[i], "-o") == 0) {
- if (++i < argc) {
- if (suffix(argv[i], suffixes, 2) >= 0) {
- error("-o would overwrite %s", argv[i]);
- exit(8);
- }
- outfile = argv[i];
- continue;
- } else {
- error("unrecognized option `%s'", argv[i-1]);
- exit(8);
- }
- } else if (strcmp(argv[i], "-target") == 0) {
- if (argv[i+1] && *argv[i+1] != '-')
- i++;
- continue;
- } else if (*argv[i] == '-' && argv[i][1] != 'l') {
- opt(argv[i]);
- continue;
- } else if (*argv[i] != '-' && suffix(argv[i], suffixes, 3) >= 0)
- nf++;
- argv[j++] = argv[i];
- }
- if ((cflag || Sflag) && outfile && nf != 1) {
- fprintf(stderr, "%s: -o %s ignored\n", progname, outfile);
- outfile = 0;
- }
- argv[j] = 0;
- for (i = 0; include[i]; i++)
- plist = append(include[i], plist);
- if (ilist) {
- List b = ilist;
- do {
- b = b->link;
- plist = append(b->str, plist);
- } while (b != ilist);
- }
- ilist = 0;
- for (i = 1; argv[i]; i++)
- if (*argv[i] == '-')
- opt(argv[i]);
- else {
- char *name = exists(argv[i]);
- if (name) {
- if (strcmp(name, argv[i]) != 0
- || (nf > 1 && suffix(name, suffixes, 3) >= 0))
- fprintf(stderr, "%s:\n", name);
- filename(name, 0);
- } else
- error("can't find `%s'", argv[i]);
- }
- if (errcnt == 0 && !Eflag && !Sflag && !cflag && llist[1]) {
- compose(ld, llist[0], llist[1],
- append(outfile ? outfile : concat("a", first(suffixes[4])), 0));
- if (callsys(av))
- errcnt++;
- }
- rm(rmlist);
- return errcnt ? EXIT_FAILURE : EXIT_SUCCESS;
+ if (getenv("TMP"))
+ tempdir = getenv("TMP");
+ else if (getenv("TEMP"))
+ tempdir = getenv("TEMP");
+ else if (getenv("TMPDIR"))
+ tempdir = getenv("TMPDIR");
+ assert(tempdir);
+ i = strlen(tempdir);
+ for (; (i > 0 && tempdir[i - 1] == '/') || tempdir[i - 1] == '\\'; i--)
+ tempdir[i - 1] = '\0';
+ if (argc <= 1)
+ {
+ help();
+ exit(0);
+ }
+ plist = append("-D__LCC__", 0);
+ initinputs();
+ if (getenv("LCCDIR"))
+ option(stringf("-lccdir=%s", getenv("LCCDIR")));
+ for (nf = 0, i = j = 1; i < argc; i++)
+ {
+ if (strcmp(argv[i], "-o") == 0)
+ {
+ if (++i < argc)
+ {
+ if (suffix(argv[i], suffixes, 2) >= 0)
+ {
+ error("-o would overwrite %s", argv[i]);
+ exit(8);
+ }
+ outfile = argv[i];
+ continue;
+ }
+ else
+ {
+ error("unrecognized option `%s'", argv[i - 1]);
+ exit(8);
+ }
+ }
+ else if (strcmp(argv[i], "-target") == 0)
+ {
+ if (argv[i + 1] && *argv[i + 1] != '-')
+ i++;
+ continue;
+ }
+ else if (*argv[i] == '-' && argv[i][1] != 'l')
+ {
+ opt(argv[i]);
+ continue;
+ }
+ else if (*argv[i] != '-' && suffix(argv[i], suffixes, 3) >= 0)
+ nf++;
+ argv[j++] = argv[i];
+ }
+ if ((cflag || Sflag) && outfile && nf != 1)
+ {
+ fprintf(stderr, "%s: -o %s ignored\n", progname, outfile);
+ outfile = 0;
+ }
+ argv[j] = 0;
+ for (i = 0; include[i]; i++)
+ plist = append(include[i], plist);
+ if (ilist)
+ {
+ List b = ilist;
+ do
+ {
+ b = b->link;
+ plist = append(b->str, plist);
+ } while (b != ilist);
+ }
+ ilist = 0;
+ for (i = 1; argv[i]; i++)
+ if (*argv[i] == '-')
+ opt(argv[i]);
+ else
+ {
+ char *name = exists(argv[i]);
+ if (name)
+ {
+ if (strcmp(name, argv[i]) != 0 || (nf > 1 && suffix(name, suffixes, 3) >= 0))
+ fprintf(stderr, "%s:\n", name);
+ filename(name, 0);
+ }
+ else
+ error("can't find `%s'", argv[i]);
+ }
+ if (errcnt == 0 && !Eflag && !Sflag && !cflag && llist[1])
+ {
+ compose(ld, llist[0], llist[1], append(outfile ? outfile : concat("a", first(suffixes[4])), 0));
+ if (callsys(av))
+ errcnt++;
+ }
+ rm(rmlist);
+ return errcnt ? EXIT_FAILURE : EXIT_SUCCESS;
}
/* alloc - allocate n bytes or die */
-static void *alloc(int n) {
- static char *avail, *limit;
-
- n = (n + sizeof(char *) - 1)&~(sizeof(char *) - 1);
- if (n >= limit - avail) {
- avail = malloc(n + 4*1024);
- assert(avail);
- limit = avail + n + 4*1024;
- }
- avail += n;
- return avail - n;
+static void *alloc(int n)
+{
+ static char *avail, *limit;
+
+ n = (n + sizeof(char *) - 1) & ~(sizeof(char *) - 1);
+ if (n >= limit - avail)
+ {
+ avail = malloc(n + 4 * 1024);
+ assert(avail);
+ limit = avail + n + 4 * 1024;
+ }
+ avail += n;
+ return avail - n;
}
-/* append - append a node with string str onto list, return new list */
-static List append(char *str, List list) {
- List p = alloc(sizeof *p);
-
- p->str = str;
- if (list) {
- p->link = list->link;
- list->link = p;
- } else
- p->link = p;
- return p;
+/* append - append a node with string str onto list, return new list */
+static List append(char *str, List list)
+{
+ List p = alloc(sizeof *p);
+
+ p->str = str;
+ if (list)
+ {
+ p->link = list->link;
+ list->link = p;
+ }
+ else
+ p->link = p;
+ return p;
}
/* basename - return base name for name, e.g. /usr/drh/foo.c => foo */
-char *basename(char *name) {
- char *s, *b, *t = 0;
-
- for (b = s = name; *s; s++)
- if (*s == '/' || *s == '\\') {
- b = s + 1;
- t = 0;
- } else if (*s == '.')
- t = s;
- s = strsave(b);
- if (t)
- s[t-b] = 0;
- return s;
+char *basename(char *name)
+{
+ char *s, *b, *t = 0;
+
+ for (b = s = name; *s; s++)
+ if (*s == '/' || *s == '\\')
+ {
+ b = s + 1;
+ t = 0;
+ }
+ else if (*s == '.')
+ t = s;
+ s = strsave(b);
+ if (t)
+ s[t - b] = 0;
+ return s;
}
#ifdef WIN32
#include <process.h>
-static char *escapeDoubleQuotes(const char *string) {
- int stringLength = strlen(string);
- int bufferSize = stringLength + 1;
- int i, j;
- char *newString;
+static char *escapeDoubleQuotes(const char *string)
+{
+ int stringLength = strlen(string);
+ int bufferSize = stringLength + 1;
+ int i, j;
+ char *newString;
- if (string == NULL)
- return NULL;
+ if (string == NULL)
+ return NULL;
- for (i = 0; i < stringLength; i++) {
- if (string[i] == '"')
- bufferSize++;
- }
+ for (i = 0; i < stringLength; i++)
+ {
+ if (string[i] == '"')
+ bufferSize++;
+ }
- newString = (char*)malloc(bufferSize);
+ newString = (char *)malloc(bufferSize);
- if (newString == NULL)
- return NULL;
+ if (newString == NULL)
+ return NULL;
- for (i = 0, j = 0; i < stringLength; i++) {
- if (string[i] == '"')
- newString[j++] = '\\';
+ for (i = 0, j = 0; i < stringLength; i++)
+ {
+ if (string[i] == '"')
+ newString[j++] = '\\';
- newString[j++] = string[i];
- }
+ newString[j++] = string[i];
+ }
- newString[j] = '\0';
+ newString[j] = '\0';
- return newString;
+ return newString;
}
-static int spawn(const char *cmdname, char **argv) {
- int argc = 0;
- char **newArgv = argv;
- int i;
- intptr_t exitStatus;
+static int spawn(const char *cmdname, char **argv)
+{
+ int argc = 0;
+ char **newArgv = argv;
+ int i;
+ intptr_t exitStatus;
- // _spawnvp removes double quotes from arguments, so we
- // have to escape them manually
- while (*newArgv++ != NULL)
- argc++;
+ // _spawnvp removes double quotes from arguments, so we
+ // have to escape them manually
+ while (*newArgv++ != NULL)
+ argc++;
- newArgv = (char **)malloc(sizeof(char*) * (argc + 1));
+ newArgv = (char **)malloc(sizeof(char *) * (argc + 1));
- for (i = 0; i < argc; i++)
- newArgv[i] = escapeDoubleQuotes(argv[i]);
+ for (i = 0; i < argc; i++)
+ newArgv[i] = escapeDoubleQuotes(argv[i]);
- newArgv[argc] = NULL;
+ newArgv[argc] = NULL;
- exitStatus = _spawnvp(_P_WAIT, cmdname, (const char *const *)newArgv);
+ exitStatus = _spawnvp(_P_WAIT, cmdname, (const char *const *)newArgv);
- for (i = 0; i < argc; i++)
- free(newArgv[i]);
+ for (i = 0; i < argc; i++)
+ free(newArgv[i]);
- free(newArgv);
- return exitStatus;
+ free(newArgv);
+ return exitStatus;
}
#else
@@ -289,569 +319,628 @@ extern int fork(void);
#endif
extern int wait(int *);
-static int spawn(const char *cmdname, char **argv) {
- int pid, n, status;
-
- switch (pid = fork()) {
- case -1:
- fprintf(stderr, "%s: no more processes\n", progname);
- return 100;
- case 0:
- // TTimo removing hardcoded paths, searching in $PATH
- execvp(cmdname, argv);
- fprintf(stderr, "%s: ", progname);
- perror(cmdname);
- fflush(stdout);
- exit(100);
- }
- while ((n = wait(&status)) != pid && n != -1)
- ;
- if (n == -1)
- status = -1;
- if (status&0377) {
- fprintf(stderr, "%s: fatal error in %s\n", progname, cmdname);
- status |= 0400;
- }
- return (status>>8)&0377;
+static int spawn(const char *cmdname, char **argv)
+{
+ int pid, n, status;
+
+ switch (pid = fork())
+ {
+ case -1:
+ fprintf(stderr, "%s: no more processes\n", progname);
+ return 100;
+ case 0:
+ // TTimo removing hardcoded paths, searching in $PATH
+ execvp(cmdname, argv);
+ fprintf(stderr, "%s: ", progname);
+ perror(cmdname);
+ fflush(stdout);
+ exit(100);
+ }
+ while ((n = wait(&status)) != pid && n != -1)
+ ;
+ if (n == -1)
+ status = -1;
+ if (status & 0377)
+ {
+ fprintf(stderr, "%s: fatal error in %s\n", progname, cmdname);
+ status |= 0400;
+ }
+ return (status >> 8) & 0377;
}
#endif
/* callsys - execute the command described by av[0...], return status */
-static int callsys(char **av) {
- int i, status = 0;
- static char **argv;
- static int argc;
- char *executable;
-
- for (i = 0; av[i] != NULL; i++)
- ;
- if (i + 1 > argc) {
- argc = i + 1;
- if (argv == NULL)
- argv = malloc(argc*sizeof *argv);
- else
- argv = realloc(argv, argc*sizeof *argv);
- assert(argv);
- }
- for (i = 0; status == 0 && av[i] != NULL; ) {
- int j = 0;
- char *s = NULL;
- for ( ; av[i] != NULL && (s = strchr(av[i], '\n')) == NULL; i++)
- argv[j++] = av[i];
- if (s != NULL) {
- if (s > av[i])
- argv[j++] = stringf("%.*s", s - av[i], av[i]);
- if (s[1] != '\0')
- av[i] = s + 1;
- else
- i++;
- }
- argv[j] = NULL;
- executable = strsave( argv[0] );
- argv[0] = stringf( "\"%s\"", argv[0] );
- if (verbose > 0) {
- int k;
- fprintf(stderr, "%s", argv[0]);
- for (k = 1; argv[k] != NULL; k++)
- fprintf(stderr, " %s", argv[k]);
- fprintf(stderr, "\n");
- }
- if (verbose < 2)
- status = spawn(executable, argv);
- if (status == -1) {
- fprintf(stderr, "%s: ", progname);
- perror(argv[0]);
- }
- }
- return status;
+static int callsys(char **av)
+{
+ int i, status = 0;
+ static char **argv;
+ static int argc;
+ char *executable;
+
+ for (i = 0; av[i] != NULL; i++)
+ ;
+ if (i + 1 > argc)
+ {
+ argc = i + 1;
+ if (argv == NULL)
+ argv = malloc(argc * sizeof *argv);
+ else
+ argv = realloc(argv, argc * sizeof *argv);
+ assert(argv);
+ }
+ for (i = 0; status == 0 && av[i] != NULL;)
+ {
+ int j = 0;
+ char *s = NULL;
+ for (; av[i] != NULL && (s = strchr(av[i], '\n')) == NULL; i++)
+ argv[j++] = av[i];
+ if (s != NULL)
+ {
+ if (s > av[i])
+ argv[j++] = stringf("%.*s", s - av[i], av[i]);
+ if (s[1] != '\0')
+ av[i] = s + 1;
+ else
+ i++;
+ }
+ argv[j] = NULL;
+ executable = strsave(argv[0]);
+ argv[0] = stringf("\"%s\"", argv[0]);
+ if (verbose > 0)
+ {
+ int k;
+ fprintf(stderr, "%s", argv[0]);
+ for (k = 1; argv[k] != NULL; k++)
+ fprintf(stderr, " %s", argv[k]);
+ fprintf(stderr, "\n");
+ }
+ if (verbose < 2)
+ status = spawn(executable, argv);
+ if (status == -1)
+ {
+ fprintf(stderr, "%s: ", progname);
+ perror(argv[0]);
+ }
+ }
+ return status;
}
/* concat - return concatenation of strings s1 and s2 */
-char *concat(char *s1, char *s2) {
- int n = strlen(s1);
- char *s = alloc(n + strlen(s2) + 1);
-
- strcpy(s, s1);
- strcpy(s + n, s2);
- return s;
+char *concat(char *s1, char *s2)
+{
+ int n = strlen(s1);
+ char *s = alloc(n + strlen(s2) + 1);
+
+ strcpy(s, s1);
+ strcpy(s + n, s2);
+ return s;
}
/* compile - compile src into dst, return status */
-static int compile(char *src, char *dst) {
- compose(com, clist, append(src, 0), append(dst, 0));
- return callsys(av);
+static int compile(char *src, char *dst)
+{
+ compose(com, clist, append(src, 0), append(dst, 0));
+ return callsys(av);
}
/* compose - compose cmd into av substituting a, b, c for $1, $2, $3, resp. */
-static void compose(char *cmd[], List a, List b, List c) {
- int i, j;
- List lists[3];
-
- lists[0] = a;
- lists[1] = b;
- lists[2] = c;
- for (i = j = 0; cmd[i]; i++) {
- char *s = strchr(cmd[i], '$');
- if (s && isdigit(s[1])) {
- int k = s[1] - '0';
- assert(k >=1 && k <= 3);
- if ((b = lists[k-1])) {
- b = b->link;
- av[j] = alloc(strlen(cmd[i]) + strlen(b->str) - 1);
- strncpy(av[j], cmd[i], s - cmd[i]);
- av[j][s-cmd[i]] = '\0';
- strcat(av[j], b->str);
- strcat(av[j++], s + 2);
- while (b != lists[k-1]) {
- b = b->link;
- assert(j < ac);
- av[j++] = b->str;
- };
- }
- } else if (*cmd[i]) {
- assert(j < ac);
- av[j++] = cmd[i];
- }
- }
- av[j] = NULL;
+static void compose(char *cmd[], List a, List b, List c)
+{
+ int i, j;
+ List lists[3];
+
+ lists[0] = a;
+ lists[1] = b;
+ lists[2] = c;
+ for (i = j = 0; cmd[i]; i++)
+ {
+ char *s = strchr(cmd[i], '$');
+ if (s && isdigit(s[1]))
+ {
+ int k = s[1] - '0';
+ assert(k >= 1 && k <= 3);
+ if ((b = lists[k - 1]))
+ {
+ b = b->link;
+ av[j] = alloc(strlen(cmd[i]) + strlen(b->str) - 1);
+ strncpy(av[j], cmd[i], s - cmd[i]);
+ av[j][s - cmd[i]] = '\0';
+ strcat(av[j], b->str);
+ strcat(av[j++], s + 2);
+ while (b != lists[k - 1])
+ {
+ b = b->link;
+ assert(j < ac);
+ av[j++] = b->str;
+ };
+ }
+ }
+ else if (*cmd[i])
+ {
+ assert(j < ac);
+ av[j++] = cmd[i];
+ }
+ }
+ av[j] = NULL;
}
/* error - issue error msg according to fmt, bump error count */
-static void error(char *fmt, char *msg) {
- fprintf(stderr, "%s: ", progname);
- fprintf(stderr, fmt, msg);
- fprintf(stderr, "\n");
- errcnt++;
+static void error(char *fmt, char *msg)
+{
+ fprintf(stderr, "%s: ", progname);
+ fprintf(stderr, fmt, msg);
+ fprintf(stderr, "\n");
+ errcnt++;
}
/* exists - if `name' readable return its path name or return null */
-static char *exists(char *name) {
- List b;
-
- if ( (name[0] == '/' || name[0] == '\\' || name[2] == ':')
- && access(name, 4) == 0)
- return name;
- if (!(name[0] == '/' || name[0] == '\\' || name[2] == ':')
- && (b = lccinputs))
- do {
- b = b->link;
- if (b->str[0]) {
- char buf[1024];
- sprintf(buf, "%s/%s", b->str, name);
- if (access(buf, 4) == 0)
- return strsave(buf);
- } else if (access(name, 4) == 0)
- return name;
- } while (b != lccinputs);
- if (verbose > 1)
- return name;
- return 0;
+static char *exists(char *name)
+{
+ List b;
+
+ if ((name[0] == '/' || name[0] == '\\' || name[2] == ':') && access(name, 4) == 0)
+ return name;
+ if (!(name[0] == '/' || name[0] == '\\' || name[2] == ':') && (b = lccinputs))
+ do
+ {
+ b = b->link;
+ if (b->str[0])
+ {
+ char buf[1024];
+ sprintf(buf, "%s/%s", b->str, name);
+ if (access(buf, 4) == 0)
+ return strsave(buf);
+ }
+ else if (access(name, 4) == 0)
+ return name;
+ } while (b != lccinputs);
+ if (verbose > 1)
+ return name;
+ return 0;
}
/* first - return first component in semicolon separated list */
-static char *first(char *list) {
- char *s = strchr(list, ';');
-
- if (s) {
- char buf[1024];
- strncpy(buf, list, s-list);
- buf[s-list] = '\0';
- return strsave(buf);
- } else
- return list;
+static char *first(char *list)
+{
+ char *s = strchr(list, ';');
+
+ if (s)
+ {
+ char buf[1024];
+ strncpy(buf, list, s - list);
+ buf[s - list] = '\0';
+ return strsave(buf);
+ }
+ else
+ return list;
}
/* filename - process file name argument `name', return status */
-static int filename(char *name, char *base) {
- int status = 0;
- static char *stemp, *itemp;
-
- if (base == 0)
- base = basename(name);
- switch (suffix(name, suffixes, 4)) {
- case 0: /* C source files */
- compose(cpp, plist, append(name, 0), 0);
- if (Eflag) {
- status = callsys(av);
- break;
- }
- if (itemp == NULL)
- itemp = tempname(first(suffixes[1]));
- compose(cpp, plist, append(name, 0), append(itemp, 0));
- status = callsys(av);
- if (status == 0)
- return filename(itemp, base);
- break;
- case 1: /* preprocessed source files */
- if (Eflag)
- break;
- if (Sflag)
- status = compile(name, outfile ? outfile : concat(base, first(suffixes[2])));
- else if ((status = compile(name, stemp?stemp:(stemp=tempname(first(suffixes[2]))))) == 0)
- return filename(stemp, base);
- break;
- case 2: /* assembly language files */
- if (Eflag)
- break;
- if (!Sflag) {
- char *ofile;
- if (cflag && outfile)
- ofile = outfile;
- else if (cflag)
- ofile = concat(base, first(suffixes[3]));
- else
- ofile = tempname(first(suffixes[3]));
- compose(as, alist, append(name, 0), append(ofile, 0));
- status = callsys(av);
- if (!find(ofile, llist[1]))
- llist[1] = append(ofile, llist[1]);
- }
- break;
- case 3: /* object files */
- if (!find(name, llist[1]))
- llist[1] = append(name, llist[1]);
- break;
- default:
- if (Eflag) {
- compose(cpp, plist, append(name, 0), 0);
- status = callsys(av);
- }
- llist[1] = append(name, llist[1]);
- break;
- }
- if (status)
- errcnt++;
- return status;
+static int filename(char *name, char *base)
+{
+ int status = 0;
+ static char *stemp, *itemp;
+
+ if (base == 0)
+ base = basename(name);
+ switch (suffix(name, suffixes, 4))
+ {
+ case 0: /* C source files */
+ compose(cpp, plist, append(name, 0), 0);
+ if (Eflag)
+ {
+ status = callsys(av);
+ break;
+ }
+ if (itemp == NULL)
+ itemp = tempname(first(suffixes[1]));
+ compose(cpp, plist, append(name, 0), append(itemp, 0));
+ status = callsys(av);
+ if (status == 0)
+ return filename(itemp, base);
+ break;
+ case 1: /* preprocessed source files */
+ if (Eflag)
+ break;
+ if (Sflag)
+ status = compile(name, outfile ? outfile : concat(base, first(suffixes[2])));
+ else if ((status = compile(name, stemp ? stemp : (stemp = tempname(first(suffixes[2]))))) == 0)
+ return filename(stemp, base);
+ break;
+ case 2: /* assembly language files */
+ if (Eflag)
+ break;
+ if (!Sflag)
+ {
+ char *ofile;
+ if (cflag && outfile)
+ ofile = outfile;
+ else if (cflag)
+ ofile = concat(base, first(suffixes[3]));
+ else
+ ofile = tempname(first(suffixes[3]));
+ compose(as, alist, append(name, 0), append(ofile, 0));
+ status = callsys(av);
+ if (!find(ofile, llist[1]))
+ llist[1] = append(ofile, llist[1]);
+ }
+ break;
+ case 3: /* object files */
+ if (!find(name, llist[1]))
+ llist[1] = append(name, llist[1]);
+ break;
+ default:
+ if (Eflag)
+ {
+ compose(cpp, plist, append(name, 0), 0);
+ status = callsys(av);
+ }
+ llist[1] = append(name, llist[1]);
+ break;
+ }
+ if (status)
+ errcnt++;
+ return status;
}
/* find - find 1st occurrence of str in list, return list node or 0 */
-static List find(char *str, List list) {
- List b;
-
- if ((b = list))
- do {
- if (strcmp(str, b->str) == 0)
- return b;
- } while ((b = b->link) != list);
- return 0;
+static List find(char *str, List list)
+{
+ List b;
+
+ if ((b = list))
+ do
+ {
+ if (strcmp(str, b->str) == 0)
+ return b;
+ } while ((b = b->link) != list);
+ return 0;
}
/* help - print help message */
-static void help(void) {
- static char *msgs[] = {
-"", " [ option | file ]...\n",
-" except for -l, options are processed left-to-right before files\n",
-" unrecognized options are taken to be linker options\n",
-"-A warn about nonANSI usage; 2nd -A warns more\n",
-"-b emit expression-level profiling code; see bprint(1)\n",
+static void help(void)
+{
+ static char *msgs[] = {"", " [ option | file ]...\n",
+ " except for -l, options are processed left-to-right before files\n",
+ " unrecognized options are taken to be linker options\n",
+ "-A warn about nonANSI usage; 2nd -A warns more\n",
+ "-b emit expression-level profiling code; see bprint(1)\n",
#ifdef sparc
-"-Bstatic -Bdynamic specify static or dynamic libraries\n",
+ "-Bstatic -Bdynamic specify static or dynamic libraries\n",
#endif
-"-Bdir/ use the compiler named `dir/rcc'\n",
-"-c compile only\n",
-"-dn set switch statement density to `n'\n",
-"-Dname -Dname=def define the preprocessor symbol `name'\n",
-"-E run only the preprocessor on the named C programs and unsuffixed files\n",
-"-g produce symbol table information for debuggers\n",
-"-help or -? print this message\n",
-"-Idir add `dir' to the beginning of the list of #include directories\n",
-"-lx search library `x'\n",
-"-N do not search the standard directories for #include files\n",
-"-n emit code to check for dereferencing zero pointers\n",
-"-O is ignored\n",
-"-o file leave the output in `file'\n",
-"-P print ANSI-style declarations for globals\n",
-"-p -pg emit profiling code; see prof(1) and gprof(1)\n",
-"-S compile to assembly language\n",
+ "-Bdir/ use the compiler named `dir/rcc'\n", "-c compile only\n",
+ "-dn set switch statement density to `n'\n",
+ "-Dname -Dname=def define the preprocessor symbol `name'\n",
+ "-E run only the preprocessor on the named C programs and unsuffixed files\n",
+ "-g produce symbol table information for debuggers\n", "-help or -? print this message\n",
+ "-Idir add `dir' to the beginning of the list of #include directories\n", "-lx search library `x'\n",
+ "-N do not search the standard directories for #include files\n",
+ "-n emit code to check for dereferencing zero pointers\n", "-O is ignored\n",
+ "-o file leave the output in `file'\n", "-P print ANSI-style declarations for globals\n",
+ "-p -pg emit profiling code; see prof(1) and gprof(1)\n", "-S compile to assembly language\n",
#ifdef linux
-"-static specify static libraries (default is dynamic)\n",
+ "-static specify static libraries (default is dynamic)\n",
#endif
-"-t -tname emit function tracing calls to printf or to `name'\n",
-"-target name is ignored\n",
-"-tempdir=dir place temporary files in `dir/'", "\n"
-"-Uname undefine the preprocessor symbol `name'\n",
-"-v show commands as they are executed; 2nd -v suppresses execution\n",
-"-w suppress warnings\n",
-"-Woarg specify system-specific `arg'\n",
-"-W[pfal]arg pass `arg' to the preprocessor, compiler, assembler, or linker\n",
- 0 };
- int i;
- char *s;
-
- msgs[0] = progname;
- for (i = 0; msgs[i]; i++) {
- fprintf(stderr, "%s", msgs[i]);
- if (strncmp("-tempdir", msgs[i], 8) == 0 && tempdir)
- fprintf(stderr, "; default=%s", tempdir);
- }
-#define xx(v) if ((s = getenv(#v))) fprintf(stderr, #v "=%s\n", s)
- xx(LCCINPUTS);
- xx(LCCDIR);
+ "-t -tname emit function tracing calls to printf or to `name'\n", "-target name is ignored\n",
+ "-tempdir=dir place temporary files in `dir/'",
+ "\n"
+ "-Uname undefine the preprocessor symbol `name'\n",
+ "-v show commands as they are executed; 2nd -v suppresses execution\n", "-w suppress warnings\n",
+ "-Woarg specify system-specific `arg'\n",
+ "-W[pfal]arg pass `arg' to the preprocessor, compiler, assembler, or linker\n", 0};
+ int i;
+ char *s;
+
+ msgs[0] = progname;
+ for (i = 0; msgs[i]; i++)
+ {
+ fprintf(stderr, "%s", msgs[i]);
+ if (strncmp("-tempdir", msgs[i], 8) == 0 && tempdir)
+ fprintf(stderr, "; default=%s", tempdir);
+ }
+#define xx(v) \
+ if ((s = getenv(#v))) \
+ fprintf(stderr, #v "=%s\n", s)
+ xx(LCCINPUTS);
+ xx(LCCDIR);
#undef xx
}
/* initinputs - if LCCINPUTS or include is defined, use them to initialize various lists */
-static void initinputs(void) {
- char *s = getenv("LCCINPUTS");
- List b;
-
- if (s == 0 || (s = inputs)[0] == 0)
- s = ".";
- if (s) {
- lccinputs = path2list(s);
- if ((b = lccinputs))
- do {
- b = b->link;
- if (strcmp(b->str, ".") != 0) {
- ilist = append(concat("-I", b->str), ilist);
- if (strstr(com[1], "win32") == NULL)
- llist[0] = append(concat("-L", b->str), llist[0]);
- } else
- b->str = "";
- } while (b != lccinputs);
- }
+static void initinputs(void)
+{
+ char *s = getenv("LCCINPUTS");
+ List b;
+
+ if (s == 0 || (s = inputs)[0] == 0)
+ s = ".";
+ if (s)
+ {
+ lccinputs = path2list(s);
+ if ((b = lccinputs))
+ do
+ {
+ b = b->link;
+ if (strcmp(b->str, ".") != 0)
+ {
+ ilist = append(concat("-I", b->str), ilist);
+ if (strstr(com[1], "win32") == NULL)
+ llist[0] = append(concat("-L", b->str), llist[0]);
+ }
+ else
+ b->str = "";
+ } while (b != lccinputs);
+ }
}
/* interrupt - catch interrupt signals */
-static void interrupt(int n) {
- rm(rmlist);
- exit(n = 100);
+static void interrupt(int n)
+{
+ rm(rmlist);
+ exit(n = 100);
}
/* opt - process option in arg */
-static void opt(char *arg) {
- switch (arg[1]) { /* multi-character options */
- case 'W': /* -Wxarg */
- if (arg[2] && arg[3])
- switch (arg[2]) {
- case 'o':
- if (option(&arg[3]))
- return;
- break;
- case 'p':
- plist = append(&arg[3], plist);
- return;
- case 'f':
- if (strcmp(&arg[3], "-C") || option("-b")) {
- clist = append(&arg[3], clist);
- return;
- }
- break; /* and fall thru */
- case 'a':
- alist = append(&arg[3], alist);
- return;
- case 'l':
- llist[0] = append(&arg[3], llist[0]);
- return;
- }
- fprintf(stderr, "%s: %s ignored\n", progname, arg);
- return;
- case 'd': /* -dn */
- arg[1] = 's';
- clist = append(arg, clist);
- return;
- case 't': /* -t -tname -tempdir=dir */
- if (strncmp(arg, "-tempdir=", 9) == 0)
- tempdir = arg + 9;
- else
- clist = append(arg, clist);
- return;
- case 'p': /* -p -pg */
- if (option(arg))
- clist = append(arg, clist);
- else
- fprintf(stderr, "%s: %s ignored\n", progname, arg);
- return;
- case 'D': /* -Dname -Dname=def */
- case 'U': /* -Uname */
- case 'I': /* -Idir */
- plist = append(arg, plist);
- return;
- case 'B': /* -Bdir -Bstatic -Bdynamic */
+static void opt(char *arg)
+{
+ switch (arg[1])
+ { /* multi-character options */
+ case 'W': /* -Wxarg */
+ if (arg[2] && arg[3])
+ switch (arg[2])
+ {
+ case 'o':
+ if (option(&arg[3]))
+ return;
+ break;
+ case 'p':
+ plist = append(&arg[3], plist);
+ return;
+ case 'f':
+ if (strcmp(&arg[3], "-C") || option("-b"))
+ {
+ clist = append(&arg[3], clist);
+ return;
+ }
+ break; /* and fall thru */
+ case 'a':
+ alist = append(&arg[3], alist);
+ return;
+ case 'l':
+ llist[0] = append(&arg[3], llist[0]);
+ return;
+ }
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ case 'd': /* -dn */
+ arg[1] = 's';
+ clist = append(arg, clist);
+ return;
+ case 't': /* -t -tname -tempdir=dir */
+ if (strncmp(arg, "-tempdir=", 9) == 0)
+ tempdir = arg + 9;
+ else
+ clist = append(arg, clist);
+ return;
+ case 'p': /* -p -pg */
+ if (option(arg))
+ clist = append(arg, clist);
+ else
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ case 'D': /* -Dname -Dname=def */
+ case 'U': /* -Uname */
+ case 'I': /* -Idir */
+ plist = append(arg, plist);
+ return;
+ case 'B': /* -Bdir -Bstatic -Bdynamic */
#ifdef sparc
- if (strcmp(arg, "-Bstatic") == 0 || strcmp(arg, "-Bdynamic") == 0)
- llist[1] = append(arg, llist[1]);
- else
-#endif
- {
- static char *path;
- if (path)
- error("-B overwrites earlier option", 0);
- path = arg + 2;
- if (strstr(com[1], "win32") != NULL)
- com[0] = concat(replace(path, '/', '\\'), concat("rcc", first(suffixes[4])));
- else
- com[0] = concat(path, "rcc");
- if (path[0] == 0)
- error("missing directory in -B option", 0);
- }
- return;
- case 'h':
- if (strcmp(arg, "-help") == 0) {
- static int printed = 0;
- case '?':
- if (!printed)
- help();
- printed = 1;
- return;
- }
+ if (strcmp(arg, "-Bstatic") == 0 || strcmp(arg, "-Bdynamic") == 0)
+ llist[1] = append(arg, llist[1]);
+ else
+#endif
+ {
+ static char *path;
+ if (path)
+ error("-B overwrites earlier option", 0);
+ path = arg + 2;
+ if (strstr(com[1], "win32") != NULL)
+ com[0] = concat(replace(path, '/', '\\'), concat("rcc", first(suffixes[4])));
+ else
+ com[0] = concat(path, "rcc");
+ if (path[0] == 0)
+ error("missing directory in -B option", 0);
+ }
+ return;
+ case 'h':
+ if (strcmp(arg, "-help") == 0)
+ {
+ static int printed = 0;
+ case '?':
+ if (!printed)
+ help();
+ printed = 1;
+ return;
+ }
#ifdef linux
- case 's':
- if (strcmp(arg,"-static") == 0) {
- if (!option(arg))
- fprintf(stderr, "%s: %s ignored\n", progname, arg);
- return;
- }
-#endif
- }
- if (arg[2] == 0)
- switch (arg[1]) { /* single-character options */
- case 'S':
- Sflag++;
- return;
- case 'O':
- fprintf(stderr, "%s: %s ignored\n", progname, arg);
- return;
- case 'A': case 'n': case 'w': case 'P':
- clist = append(arg, clist);
- return;
- case 'g': case 'b':
- if (option(arg))
- clist = append(arg[1] == 'g' ? "-g2" : arg, clist);
- else
- fprintf(stderr, "%s: %s ignored\n", progname, arg);
- return;
- case 'G':
- if (option(arg)) {
- clist = append("-g3", clist);
- llist[0] = append("-N", llist[0]);
- } else
- fprintf(stderr, "%s: %s ignored\n", progname, arg);
- return;
- case 'E':
- Eflag++;
- return;
- case 'c':
- cflag++;
- return;
- case 'N':
- if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
- plist = append("-nostdinc", plist);
- include[0] = 0;
- ilist = 0;
- return;
- case 'v':
- if (verbose++ == 0) {
- if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
- plist = append(arg, plist);
- clist = append(arg, clist);
- fprintf(stderr, "%s %s\n", progname, rcsid);
- }
- return;
- }
- if (cflag || Sflag || Eflag)
- fprintf(stderr, "%s: %s ignored\n", progname, arg);
- else
- llist[1] = append(arg, llist[1]);
+ case 's':
+ if (strcmp(arg, "-static") == 0)
+ {
+ if (!option(arg))
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ }
+#endif
+ }
+ if (arg[2] == 0)
+ switch (arg[1])
+ { /* single-character options */
+ case 'S':
+ Sflag++;
+ return;
+ case 'O':
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ case 'A':
+ case 'n':
+ case 'w':
+ case 'P':
+ clist = append(arg, clist);
+ return;
+ case 'g':
+ case 'b':
+ if (option(arg))
+ clist = append(arg[1] == 'g' ? "-g2" : arg, clist);
+ else
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ case 'G':
+ if (option(arg))
+ {
+ clist = append("-g3", clist);
+ llist[0] = append("-N", llist[0]);
+ }
+ else
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ case 'E':
+ Eflag++;
+ return;
+ case 'c':
+ cflag++;
+ return;
+ case 'N':
+ if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
+ plist = append("-nostdinc", plist);
+ include[0] = 0;
+ ilist = 0;
+ return;
+ case 'v':
+ if (verbose++ == 0)
+ {
+ if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
+ plist = append(arg, plist);
+ clist = append(arg, clist);
+ fprintf(stderr, "%s %s\n", progname, rcsid);
+ }
+ return;
+ }
+ if (cflag || Sflag || Eflag)
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ else
+ llist[1] = append(arg, llist[1]);
}
/* path2list - convert a colon- or semicolon-separated list to a list */
-static List path2list(const char *path) {
- List list = NULL;
- char sep = ':';
-
- if (path == NULL)
- return NULL;
- if (strchr(path, ';'))
- sep = ';';
- while (*path) {
- char *p, buf[512];
- if ((p = strchr(path, sep))) {
- assert(p - path < sizeof buf);
- strncpy(buf, path, p - path);
- buf[p-path] = '\0';
- } else {
- assert(strlen(path) < sizeof buf);
- strcpy(buf, path);
- }
- if (!find(buf, list))
- list = append(strsave(buf), list);
- if (p == 0)
- break;
- path = p + 1;
- }
- return list;
+static List path2list(const char *path)
+{
+ List list = NULL;
+ char sep = ':';
+
+ if (path == NULL)
+ return NULL;
+ if (strchr(path, ';'))
+ sep = ';';
+ while (*path)
+ {
+ char *p, buf[512];
+ if ((p = strchr(path, sep)))
+ {
+ assert(p - path < sizeof buf);
+ strncpy(buf, path, p - path);
+ buf[p - path] = '\0';
+ }
+ else
+ {
+ assert(strlen(path) < sizeof buf);
+ strcpy(buf, path);
+ }
+ if (!find(buf, list))
+ list = append(strsave(buf), list);
+ if (p == 0)
+ break;
+ path = p + 1;
+ }
+ return list;
}
/* replace - copy str, then replace occurrences of from with to, return the copy */
-char *replace(const char *str, int from, int to) {
- char *s = strsave(str), *p = s;
+char *replace(const char *str, int from, int to)
+{
+ char *s = strsave(str), *p = s;
- for ( ; (p = strchr(p, from)) != NULL; p++)
- *p = to;
- return s;
+ for (; (p = strchr(p, from)) != NULL; p++)
+ *p = to;
+ return s;
}
/* rm - remove files in list */
-static void rm(List list) {
- if (list) {
- List b = list;
- if (verbose)
- fprintf(stderr, "rm");
- do {
- if (verbose)
- fprintf(stderr, " %s", b->str);
- if (verbose < 2)
- remove(b->str);
- } while ((b = b->link) != list);
- if (verbose)
- fprintf(stderr, "\n");
- }
+static void rm(List list)
+{
+ if (list)
+ {
+ List b = list;
+ if (verbose)
+ fprintf(stderr, "rm");
+ do
+ {
+ if (verbose)
+ fprintf(stderr, " %s", b->str);
+ if (verbose < 2)
+ remove(b->str);
+ } while ((b = b->link) != list);
+ if (verbose)
+ fprintf(stderr, "\n");
+ }
}
/* strsave - return a saved copy of string str */
-char *strsave(const char *str) {
- return strcpy(alloc(strlen(str)+1), str);
-}
+char *strsave(const char *str) { return strcpy(alloc(strlen(str) + 1), str); }
/* stringf - format and return a string */
-char *stringf(const char *fmt, ...) {
- char buf[1024];
- va_list ap;
-
- va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
- va_end(ap);
- return strsave(buf);
+char *stringf(const char *fmt, ...)
+{
+ char buf[1024];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+ return strsave(buf);
}
/* suffix - if one of tails[0..n-1] holds a proper suffix of name, return its index */
-int suffix(char *name, char *tails[], int n) {
- int i, len = strlen(name);
-
- for (i = 0; i < n; i++) {
- char *s = tails[i], *t;
- for ( ; (t = strchr(s, ';')); s = t + 1) {
- int m = t - s;
- if (len > m && strncmp(&name[len-m], s, m) == 0)
- return i;
- }
- if (*s) {
- int m = strlen(s);
- if (len > m && strncmp(&name[len-m], s, m) == 0)
- return i;
- }
- }
- return -1;
+int suffix(char *name, char *tails[], int n)
+{
+ int i, len = strlen(name);
+
+ for (i = 0; i < n; i++)
+ {
+ char *s = tails[i], *t;
+ for (; (t = strchr(s, ';')); s = t + 1)
+ {
+ int m = t - s;
+ if (len > m && strncmp(&name[len - m], s, m) == 0)
+ return i;
+ }
+ if (*s)
+ {
+ int m = strlen(s);
+ if (len > m && strncmp(&name[len - m], s, m) == 0)
+ return i;
+ }
+ }
+ return -1;
}
/* tempname - generate a temporary file name in tempdir with given suffix */
-char *tempname(char *suffix) {
- static int n;
- char *name = stringf("%s/lcc%d%d%s", tempdir, getpid(), n++, suffix);
-
- if (strstr(com[1], "win32") != NULL)
- name = replace(name, '/', '\\');
- rmlist = append(name, rmlist);
- return name;
+char *tempname(char *suffix)
+{
+ static int n;
+ char *name = stringf("%s/lcc%d%d%s", tempdir, getpid(), n++, suffix);
+
+ if (strstr(com[1], "win32") != NULL)
+ name = replace(name, '/', '\\');
+ rmlist = append(name, rmlist);
+ return name;
}
diff --git a/src/tools/lcc/lburg/gram.c b/src/tools/lcc/lburg/gram.c
index f6ee9f9..94fd3b3 100644
--- a/src/tools/lcc/lburg/gram.c
+++ b/src/tools/lcc/lburg/gram.c
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.0.4. */
+/* A Bison parser, made by GNU Bison 3.0.2. */
/* Bison implementation for Yacc-like parsers in C
- Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+ Copyright (C) 1984, 1989-1990, 2000-2013 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
@@ -44,7 +44,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "3.0.4"
+#define YYBISON_VERSION "3.0.2"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -62,11 +62,11 @@
/* Copy the first part of user declarations. */
-#line 1 "src/tools/lcc/lburg/gram.y" /* yacc.c:339 */
+#line 1 "code/tools/lcc/lburg/gram.y" /* yacc.c:339 */
#include <stdio.h>
#include "lburg.h"
-static char rcsid[] = "$Id: gram.y 145 2001-10-17 21:53:10Z timo $";
+//static char rcsid[] = "$Id: gram.y 145 2001-10-17 21:53:10Z timo $";
/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */
static int yylineno = 0;
@@ -122,10 +122,10 @@ extern int yydebug;
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-
+typedef union YYSTYPE YYSTYPE;
union YYSTYPE
{
-#line 8 "src/tools/lcc/lburg/gram.y" /* yacc.c:355 */
+#line 8 "code/tools/lcc/lburg/gram.y" /* yacc.c:355 */
int n;
char *string;
@@ -133,8 +133,6 @@ union YYSTYPE
#line 135 "y.tab.c" /* yacc.c:355 */
};
-
-typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
@@ -143,12 +141,13 @@ typedef union YYSTYPE YYSTYPE;
extern YYSTYPE yylval;
int yyparse (void);
+int yylex(void);
/* Copy the second part of user declarations. */
-#line 152 "y.tab.c" /* yacc.c:358 */
+#line 150 "y.tab.c" /* yacc.c:358 */
#ifdef short
# undef short
@@ -1236,82 +1235,82 @@ yyreduce:
switch (yyn)
{
case 2:
-#line 22 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 22 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{ yylineno = 0; }
-#line 1242 "y.tab.c" /* yacc.c:1646 */
+#line 1240 "y.tab.c" /* yacc.c:1646 */
break;
case 3:
-#line 23 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 23 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{ yylineno = 0; }
-#line 1248 "y.tab.c" /* yacc.c:1646 */
+#line 1246 "y.tab.c" /* yacc.c:1646 */
break;
case 7:
-#line 31 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 31 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{
if (nonterm((yyvsp[-1].string))->number != 1)
yyerror("redeclaration of the start symbol\n");
}
-#line 1257 "y.tab.c" /* yacc.c:1646 */
+#line 1255 "y.tab.c" /* yacc.c:1646 */
break;
case 9:
-#line 36 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 36 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{ yyerrok; }
-#line 1263 "y.tab.c" /* yacc.c:1646 */
+#line 1261 "y.tab.c" /* yacc.c:1646 */
break;
case 11:
-#line 40 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 40 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{ term((yyvsp[-2].string), (yyvsp[0].n)); }
-#line 1269 "y.tab.c" /* yacc.c:1646 */
+#line 1267 "y.tab.c" /* yacc.c:1646 */
break;
case 13:
-#line 44 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 44 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{ rule((yyvsp[-5].string), (yyvsp[-3].tree), (yyvsp[-2].string), (yyvsp[-1].string)); }
-#line 1275 "y.tab.c" /* yacc.c:1646 */
+#line 1273 "y.tab.c" /* yacc.c:1646 */
break;
case 15:
-#line 46 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 46 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{ yyerrok; }
-#line 1281 "y.tab.c" /* yacc.c:1646 */
+#line 1279 "y.tab.c" /* yacc.c:1646 */
break;
case 16:
-#line 49 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 49 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{ nonterm((yyval.string) = (yyvsp[0].string)); }
-#line 1287 "y.tab.c" /* yacc.c:1646 */
+#line 1285 "y.tab.c" /* yacc.c:1646 */
break;
case 17:
-#line 52 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 52 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{ (yyval.tree) = tree((yyvsp[0].string), 0, 0); }
-#line 1293 "y.tab.c" /* yacc.c:1646 */
+#line 1291 "y.tab.c" /* yacc.c:1646 */
break;
case 18:
-#line 53 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 53 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{ (yyval.tree) = tree((yyvsp[-3].string), (yyvsp[-1].tree), 0); }
-#line 1299 "y.tab.c" /* yacc.c:1646 */
+#line 1297 "y.tab.c" /* yacc.c:1646 */
break;
case 19:
-#line 54 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 54 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{ (yyval.tree) = tree((yyvsp[-5].string), (yyvsp[-3].tree), (yyvsp[-1].tree)); }
-#line 1305 "y.tab.c" /* yacc.c:1646 */
+#line 1303 "y.tab.c" /* yacc.c:1646 */
break;
case 20:
-#line 57 "src/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
+#line 57 "code/tools/lcc/lburg/gram.y" /* yacc.c:1646 */
{ if (*(yyvsp[0].string) == 0) (yyval.string) = "0"; }
-#line 1311 "y.tab.c" /* yacc.c:1646 */
+#line 1309 "y.tab.c" /* yacc.c:1646 */
break;
-#line 1315 "y.tab.c" /* yacc.c:1646 */
+#line 1313 "y.tab.c" /* yacc.c:1646 */
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -1539,7 +1538,7 @@ yyreturn:
#endif
return yyresult;
}
-#line 59 "src/tools/lcc/lburg/gram.y" /* yacc.c:1906 */
+#line 59 "code/tools/lcc/lburg/gram.y" /* yacc.c:1906 */
#include <assert.h>
#include <stdarg.h>
@@ -1683,4 +1682,5 @@ void yywarn(char *fmt, ...) {
fprintf(stderr, "line %d: ", yylineno);
fprintf(stderr, "warning: ");
vfprintf(stderr, fmt, ap);
+ va_end(ap);
}
diff --git a/src/tools/lcc/lburg/gram.y b/src/tools/lcc/lburg/gram.y
index 1ecd8a9..c0a9c94 100644
--- a/src/tools/lcc/lburg/gram.y
+++ b/src/tools/lcc/lburg/gram.y
@@ -199,4 +199,5 @@ void yywarn(char *fmt, ...) {
fprintf(stderr, "line %d: ", yylineno);
fprintf(stderr, "warning: ");
vfprintf(stderr, fmt, ap);
+ va_end(ap);
}
diff --git a/src/tools/lcc/src/dag.c b/src/tools/lcc/src/dag.c
index 420cbe7..ad0ea1c 100644
--- a/src/tools/lcc/src/dag.c
+++ b/src/tools/lcc/src/dag.c
@@ -1,15 +1,13 @@
#include "c.h"
-
-#define iscall(op) (generic(op) == CALL \
- || (IR->mulops_calls \
- && (generic(op)==DIV||generic(op)==MOD||generic(op)==MUL) \
- && ( optype(op)==U || optype(op)==I)))
+#define iscall(op) \
+ (generic(op) == CALL || (IR->mulops_calls && (generic(op) == DIV || generic(op) == MOD || generic(op) == MUL) && \
+ (optype(op) == U || optype(op) == I)))
static Node forest;
static struct dag {
- struct node node;
- struct dag *hlink;
-} *buckets[16];
+ struct node node;
+ struct dag *hlink;
+} * buckets[16];
int nodecount;
static Tree firstarg;
int assignargs = 1;
@@ -35,702 +33,884 @@ static void typestab(Symbol, void *);
static Node undag(Node);
static Node visit(Node, int);
static void unlist(void);
-void walk(Tree tp, int tlab, int flab) {
- listnodes(tp, tlab, flab);
- if (forest) {
- Node list = forest->link;
- forest->link = NULL;
- if (!IR->wants_dag)
- list = undag(list);
- code(Gen)->u.forest = list;
- forest = NULL;
- }
- reset();
- deallocate(STMT);
+void walk(Tree tp, int tlab, int flab)
+{
+ listnodes(tp, tlab, flab);
+ if (forest)
+ {
+ Node list = forest->link;
+ forest->link = NULL;
+ if (!IR->wants_dag) list = undag(list);
+ code(Gen)->u.forest = list;
+ forest = NULL;
+ }
+ reset();
+ deallocate(STMT);
}
-static Node node(int op, Node l, Node r, Symbol sym) {
- int i;
- struct dag *p;
+static Node node(int op, Node l, Node r, Symbol sym)
+{
+ int i;
+ struct dag *p;
- i = (opindex(op)^((unsigned long)sym>>2))&(NELEMS(buckets)-1);
- for (p = buckets[i]; p; p = p->hlink)
- if (p->node.op == op && p->node.syms[0] == sym
- && p->node.kids[0] == l && p->node.kids[1] == r)
- return &p->node;
- p = dagnode(op, l, r, sym);
- p->hlink = buckets[i];
- buckets[i] = p;
- ++nodecount;
- return &p->node;
+ i = (opindex(op) ^ ((unsigned long)sym >> 2)) & (NELEMS(buckets) - 1);
+ for (p = buckets[i]; p; p = p->hlink)
+ if (p->node.op == op && p->node.syms[0] == sym && p->node.kids[0] == l && p->node.kids[1] == r) return &p->node;
+ p = dagnode(op, l, r, sym);
+ p->hlink = buckets[i];
+ buckets[i] = p;
+ ++nodecount;
+ return &p->node;
}
-static struct dag *dagnode(int op, Node l, Node r, Symbol sym) {
- struct dag *p;
- NEW0(p, FUNC);
- p->node.op = op;
- if ((p->node.kids[0] = l) != NULL)
- ++l->count;
- if ((p->node.kids[1] = r) != NULL)
- ++r->count;
- p->node.syms[0] = sym;
- return p;
+static Node constnode(int op, Symbol sym)
+{
+ struct dag *p;
+ p = dagnode(op, NULL, NULL, sym);
+ ++nodecount;
+ return &p->node;
}
-Node newnode(int op, Node l, Node r, Symbol sym) {
- return &dagnode(op, l, r, sym)->node;
+
+static struct dag *dagnode(int op, Node l, Node r, Symbol sym)
+{
+ struct dag *p;
+
+ NEW0(p, FUNC);
+ p->node.op = op;
+ if ((p->node.kids[0] = l) != NULL) ++l->count;
+ if ((p->node.kids[1] = r) != NULL) ++r->count;
+ p->node.syms[0] = sym;
+ return p;
}
-static void kill(Symbol p) {
- int i;
- struct dag **q;
+Node newnode(int op, Node l, Node r, Symbol sym) { return &dagnode(op, l, r, sym)->node; }
+static void kill(Symbol p)
+{
+ int i;
+ struct dag **q;
- for (i = 0; i < NELEMS(buckets); i++)
- for (q = &buckets[i]; *q; )
- if (generic((*q)->node.op) == INDIR &&
- (!isaddrop((*q)->node.kids[0]->op)
- || (*q)->node.kids[0]->syms[0] == p)) {
- *q = (*q)->hlink;
- --nodecount;
- } else
- q = &(*q)->hlink;
+ for (i = 0; i < NELEMS(buckets); i++)
+ for (q = &buckets[i]; *q;)
+ if (generic((*q)->node.op) == INDIR &&
+ (!isaddrop((*q)->node.kids[0]->op) || (*q)->node.kids[0]->syms[0] == p))
+ {
+ *q = (*q)->hlink;
+ --nodecount;
+ }
+ else
+ q = &(*q)->hlink;
}
-static void reset(void) {
- if (nodecount > 0)
- memset(buckets, 0, sizeof buckets);
- nodecount = 0;
+static void reset(void)
+{
+ if (nodecount > 0) memset(buckets, 0, sizeof buckets);
+ nodecount = 0;
}
-Node listnodes(Tree tp, int tlab, int flab) {
- Node p = NULL, l, r;
- int op;
+Node listnodes(Tree tp, int tlab, int flab)
+{
+ Node p = NULL, l, r;
+ int op;
- assert(tlab || flab || (tlab == 0 && flab == 0));
- if (tp == NULL)
- return NULL;
- if (tp->node)
- return tp->node;
- op = tp->op + sizeop(tp->type->size);
- switch (generic(tp->op)) {
- case AND: { if (depth++ == 0) reset();
- if (flab) {
- listnodes(tp->kids[0], 0, flab);
- listnodes(tp->kids[1], 0, flab);
- } else {
- listnodes(tp->kids[0], 0, flab = genlabel(1));
- listnodes(tp->kids[1], tlab, 0);
- labelnode(flab);
- }
- depth--; } break;
- case OR: { if (depth++ == 0)
- reset();
- if (tlab) {
- listnodes(tp->kids[0], tlab, 0);
- listnodes(tp->kids[1], tlab, 0);
- } else {
- tlab = genlabel(1);
- listnodes(tp->kids[0], tlab, 0);
- listnodes(tp->kids[1], 0, flab);
- labelnode(tlab);
- }
- depth--;
- } break;
- case NOT: { return listnodes(tp->kids[0], flab, tlab); }
- case COND: { Tree q = tp->kids[1];
- assert(tlab == 0 && flab == 0);
- if (tp->u.sym)
- addlocal(tp->u.sym);
- flab = genlabel(2);
- listnodes(tp->kids[0], 0, flab);
- assert(q && q->op == RIGHT);
- reset();
- listnodes(q->kids[0], 0, 0);
- if (forest->op == LABEL+V) {
- equatelab(forest->syms[0], findlabel(flab + 1));
- unlist();
- }
- list(jump(flab + 1));
- labelnode(flab);
- listnodes(q->kids[1], 0, 0);
- if (forest->op == LABEL+V) {
- equatelab(forest->syms[0], findlabel(flab + 1));
- unlist();
- }
- labelnode(flab + 1);
+ assert(tlab || flab || (tlab == 0 && flab == 0));
+ if (tp == NULL) return NULL;
+ if (tp->node) return tp->node;
+ op = tp->op + sizeop(tp->type->size);
+ switch (generic(tp->op))
+ {
+ case AND:
+ {
+ if (depth++ == 0) reset();
+ if (flab)
+ {
+ listnodes(tp->kids[0], 0, flab);
+ listnodes(tp->kids[1], 0, flab);
+ }
+ else
+ {
+ listnodes(tp->kids[0], 0, flab = genlabel(1));
+ listnodes(tp->kids[1], tlab, 0);
+ labelnode(flab);
+ }
+ depth--;
+ }
+ break;
+ case OR:
+ {
+ if (depth++ == 0) reset();
+ if (tlab)
+ {
+ listnodes(tp->kids[0], tlab, 0);
+ listnodes(tp->kids[1], tlab, 0);
+ }
+ else
+ {
+ tlab = genlabel(1);
+ listnodes(tp->kids[0], tlab, 0);
+ listnodes(tp->kids[1], 0, flab);
+ labelnode(tlab);
+ }
+ depth--;
+ }
+ break;
+ case NOT:
+ {
+ return listnodes(tp->kids[0], flab, tlab);
+ }
+ case COND:
+ {
+ Tree q = tp->kids[1];
+ assert(tlab == 0 && flab == 0);
+ if (tp->u.sym) addlocal(tp->u.sym);
+ flab = genlabel(2);
+ listnodes(tp->kids[0], 0, flab);
+ assert(q && q->op == RIGHT);
+ reset();
+ listnodes(q->kids[0], 0, 0);
+ if (forest->op == LABEL + V)
+ {
+ equatelab(forest->syms[0], findlabel(flab + 1));
+ unlist();
+ }
+ list(jump(flab + 1));
+ labelnode(flab);
+ listnodes(q->kids[1], 0, 0);
+ if (forest->op == LABEL + V)
+ {
+ equatelab(forest->syms[0], findlabel(flab + 1));
+ unlist();
+ }
+ labelnode(flab + 1);
- if (tp->u.sym)
- p = listnodes(idtree(tp->u.sym), 0, 0); } break;
- case CNST: { Type ty = unqual(tp->type);
- assert(ty->u.sym);
- if (tlab || flab) {
- assert(ty == inttype);
- if (tlab && tp->u.v.i != 0)
- list(jump(tlab));
- else if (flab && tp->u.v.i == 0)
- list(jump(flab));
- }
- else if (ty->u.sym->addressed)
- p = listnodes(cvtconst(tp), 0, 0);
- else
- p = node(op, NULL, NULL, constant(ty, tp->u.v)); } break;
- case RIGHT: { if ( tp->kids[0] && tp->kids[1]
- && generic(tp->kids[1]->op) == ASGN
- && ((generic(tp->kids[0]->op) == INDIR
- && tp->kids[0]->kids[0] == tp->kids[1]->kids[0])
- || (tp->kids[0]->op == FIELD
- && tp->kids[0] == tp->kids[1]->kids[0]))) {
- assert(tlab == 0 && flab == 0);
- if (generic(tp->kids[0]->op) == INDIR) {
- p = listnodes(tp->kids[0], 0, 0);
- list(p);
- listnodes(tp->kids[1], 0, 0);
- }
- else {
- assert(generic(tp->kids[0]->kids[0]->op) == INDIR);
- list(listnodes(tp->kids[0]->kids[0], 0, 0));
- p = listnodes(tp->kids[0], 0, 0);
- listnodes(tp->kids[1], 0, 0);
- }
- } else if (tp->kids[1]) {
- listnodes(tp->kids[0], 0, 0);
- p = listnodes(tp->kids[1], tlab, flab);
- } else
- p = listnodes(tp->kids[0], tlab, flab); } break;
- case JUMP: { assert(tlab == 0 && flab == 0);
- assert(tp->u.sym == 0);
- assert(tp->kids[0]);
- l = listnodes(tp->kids[0], 0, 0);
- list(newnode(JUMP+V, l, NULL, NULL));
- reset(); } break;
- case CALL: { Tree save = firstarg;
- firstarg = NULL;
- assert(tlab == 0 && flab == 0);
- if (tp->op == CALL+B && !IR->wants_callb) {
- Tree arg0 = tree(ARG+P, tp->kids[1]->type,
- tp->kids[1], NULL);
- if (IR->left_to_right)
- firstarg = arg0;
- l = listnodes(tp->kids[0], 0, 0);
- if (!IR->left_to_right || firstarg) {
- firstarg = NULL;
- listnodes(arg0, 0, 0);
- }
- p = newnode(CALL+V, l, NULL, NULL);
- } else {
- l = listnodes(tp->kids[0], 0, 0);
- r = listnodes(tp->kids[1], 0, 0);
- p = newnode(tp->op == CALL+B ? tp->op : op, l, r, NULL);
- }
- NEW0(p->syms[0], FUNC);
- assert(isptr(tp->kids[0]->type));
- assert(isfunc(tp->kids[0]->type->type));
- p->syms[0]->type = tp->kids[0]->type->type;
- list(p);
- reset();
- cfunc->u.f.ncalls++;
- firstarg = save;
- } break;
- case ARG: { assert(tlab == 0 && flab == 0);
- if (IR->left_to_right)
- listnodes(tp->kids[1], 0, 0);
- if (firstarg) {
- Tree arg = firstarg;
- firstarg = NULL;
- listnodes(arg, 0, 0);
- }
- l = listnodes(tp->kids[0], 0, 0);
- list(newnode(tp->op == ARG+B ? tp->op : op, l, NULL, NULL));
- forest->syms[0] = intconst(tp->type->size);
- forest->syms[1] = intconst(tp->type->align);
- if (!IR->left_to_right)
- listnodes(tp->kids[1], 0, 0); } break;
- case EQ: case NE: case GT: case GE: case LE:
- case LT: { assert(tp->u.sym == 0);
- assert(errcnt || tlab || flab);
- l = listnodes(tp->kids[0], 0, 0);
- r = listnodes(tp->kids[1], 0, 0);
- assert(errcnt || opkind(l->op) == opkind(r->op));
- assert(errcnt || optype(op) == optype(l->op));
- if (tlab)
- assert(flab == 0),
- list(newnode(generic(tp->op) + opkind(l->op), l, r, findlabel(tlab)));
- else if (flab) {
- switch (generic(tp->op)) {
- case EQ: op = NE; break;
- case NE: op = EQ; break;
- case GT: op = LE; break;
- case LT: op = GE; break;
- case GE: op = LT; break;
- case LE: op = GT; break;
- default: assert(0);
- }
- list(newnode(op + opkind(l->op), l, r, findlabel(flab)));
- }
- if (forest && forest->syms[0])
- forest->syms[0]->ref++; } break;
- case ASGN: { assert(tlab == 0 && flab == 0);
- if (tp->kids[0]->op == FIELD) {
- Tree x = tp->kids[0]->kids[0];
- Field f = tp->kids[0]->u.field;
- assert(generic(x->op) == INDIR);
- reset();
- l = listnodes(lvalue(x), 0, 0);
- if (fieldsize(f) < 8*f->type->size) {
- unsigned int fmask = fieldmask(f);
- unsigned int mask = fmask<<fieldright(f);
- Tree q = tp->kids[1];
- if ((q->op == CNST+I && q->u.v.i == 0)
- || (q->op == CNST+U && q->u.v.u == 0))
- q = bittree(BAND, x, cnsttree(unsignedtype, (unsigned long)~mask));
- else if ((q->op == CNST+I && (q->u.v.i&fmask) == fmask)
- || (q->op == CNST+U && (q->u.v.u&fmask) == fmask))
- q = bittree(BOR, x, cnsttree(unsignedtype, (unsigned long)mask));
- else {
- listnodes(q, 0, 0);
- q = bittree(BOR,
- bittree(BAND, rvalue(lvalue(x)),
- cnsttree(unsignedtype, (unsigned long)~mask)),
- bittree(BAND, shtree(LSH, cast(q, unsignedtype),
- cnsttree(unsignedtype, (unsigned long)fieldright(f))),
- cnsttree(unsignedtype, (unsigned long)mask)));
- }
- r = listnodes(q, 0, 0);
- op = ASGN + ttob(q->type);
- } else {
- r = listnodes(tp->kids[1], 0, 0);
- op = ASGN + ttob(tp->kids[1]->type);
- }
- } else {
- l = listnodes(tp->kids[0], 0, 0);
- r = listnodes(tp->kids[1], 0, 0);
- }
- list(newnode(tp->op == ASGN+B ? tp->op : op, l, r, NULL));
- forest->syms[0] = intconst(tp->kids[1]->type->size);
- forest->syms[1] = intconst(tp->kids[1]->type->align);
- if (isaddrop(tp->kids[0]->op)
- && !tp->kids[0]->u.sym->computed)
- kill(tp->kids[0]->u.sym);
- else
- reset();
- p = listnodes(tp->kids[1], 0, 0); } break;
- case BOR: case BAND: case BXOR:
- case ADD: case SUB: case RSH:
- case LSH: { assert(tlab == 0 && flab == 0);
- l = listnodes(tp->kids[0], 0, 0);
- r = listnodes(tp->kids[1], 0, 0);
- p = node(op, l, r, NULL); } break;
- case DIV: case MUL:
- case MOD: { assert(tlab == 0 && flab == 0);
- l = listnodes(tp->kids[0], 0, 0);
- r = listnodes(tp->kids[1], 0, 0);
- p = node(op, l, r, NULL);
- if (IR->mulops_calls && isint(tp->type)) {
- list(p);
- cfunc->u.f.ncalls++;
- } } break;
- case RET: { assert(tlab == 0 && flab == 0);
- l = listnodes(tp->kids[0], 0, 0);
- list(newnode(op, l, NULL, NULL)); } break;
- case CVF: case CVI: case CVP:
- case CVU: { assert(tlab == 0 && flab == 0);
- assert(optype(tp->kids[0]->op) != optype(tp->op) || tp->kids[0]->type->size != tp->type->size);
- l = listnodes(tp->kids[0], 0, 0);
- p = node(op, l, NULL, intconst(tp->kids[0]->type->size));
- } break;
- case BCOM:
- case NEG: { assert(tlab == 0 && flab == 0);
- l = listnodes(tp->kids[0], 0, 0);
- p = node(op, l, NULL, NULL); } break;
- case INDIR: { Type ty = tp->kids[0]->type;
- assert(tlab == 0 && flab == 0);
- l = listnodes(tp->kids[0], 0, 0);
- if (isptr(ty))
- ty = unqual(ty)->type;
- if (isvolatile(ty)
- || (isstruct(ty) && unqual(ty)->u.sym->u.s.vfields))
- p = newnode(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL);
- else
- p = node(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL); } break;
- case FIELD: { Tree q = tp->kids[0];
- if (tp->type == inttype) {
- long n = fieldleft(tp->u.field);
- q = shtree(RSH,
- shtree(LSH, q, cnsttree(inttype, n)),
- cnsttree(inttype, n + fieldright(tp->u.field)));
- } else if (fieldsize(tp->u.field) < 8*tp->u.field->type->size)
- q = bittree(BAND,
- shtree(RSH, q, cnsttree(inttype, (long)fieldright(tp->u.field))),
- cnsttree(unsignedtype, (unsigned long)fieldmask(tp->u.field)));
- assert(tlab == 0 && flab == 0);
- p = listnodes(q, 0, 0); } break;
- case ADDRG:
- case ADDRF: { assert(tlab == 0 && flab == 0);
- p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym);
- } break;
- case ADDRL: { assert(tlab == 0 && flab == 0);
- if (tp->u.sym->temporary)
- addlocal(tp->u.sym);
- p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym); } break;
- default:assert(0);
- }
- tp->node = p;
- return p;
+ if (tp->u.sym) p = listnodes(idtree(tp->u.sym), 0, 0);
+ }
+ break;
+ case CNST:
+ {
+ Type ty = unqual(tp->type);
+ assert(ty->u.sym);
+ if (tlab || flab)
+ {
+ assert(ty == inttype);
+ if (tlab && tp->u.v.i != 0)
+ list(jump(tlab));
+ else if (flab && tp->u.v.i == 0)
+ list(jump(flab));
+ }
+ else if (ty->u.sym->addressed)
+ p = listnodes(cvtconst(tp), 0, 0);
+ else
+ /* always generate new node for constants */
+ if (isscalar(ty))
+ p = constnode(op, constant(ty, tp->u.v));
+ else
+ p = node(op, NULL, NULL, constant(ty, tp->u.v));
+ }
+ break;
+ case RIGHT:
+ {
+ if (tp->kids[0] && tp->kids[1] && generic(tp->kids[1]->op) == ASGN &&
+ ((generic(tp->kids[0]->op) == INDIR && tp->kids[0]->kids[0] == tp->kids[1]->kids[0]) ||
+ (tp->kids[0]->op == FIELD && tp->kids[0] == tp->kids[1]->kids[0])))
+ {
+ assert(tlab == 0 && flab == 0);
+ if (generic(tp->kids[0]->op) == INDIR)
+ {
+ p = listnodes(tp->kids[0], 0, 0);
+ list(p);
+ listnodes(tp->kids[1], 0, 0);
+ }
+ else
+ {
+ assert(generic(tp->kids[0]->kids[0]->op) == INDIR);
+ list(listnodes(tp->kids[0]->kids[0], 0, 0));
+ p = listnodes(tp->kids[0], 0, 0);
+ listnodes(tp->kids[1], 0, 0);
+ }
+ }
+ else if (tp->kids[1])
+ {
+ listnodes(tp->kids[0], 0, 0);
+ p = listnodes(tp->kids[1], tlab, flab);
+ }
+ else
+ p = listnodes(tp->kids[0], tlab, flab);
+ }
+ break;
+ case JUMP:
+ {
+ assert(tlab == 0 && flab == 0);
+ assert(tp->u.sym == 0);
+ assert(tp->kids[0]);
+ l = listnodes(tp->kids[0], 0, 0);
+ list(newnode(JUMP + V, l, NULL, NULL));
+ reset();
+ }
+ break;
+ case CALL:
+ {
+ Tree save = firstarg;
+ firstarg = NULL;
+ assert(tlab == 0 && flab == 0);
+ if (tp->op == CALL + B && !IR->wants_callb)
+ {
+ Tree arg0 = tree(ARG + P, tp->kids[1]->type, tp->kids[1], NULL);
+ if (IR->left_to_right) firstarg = arg0;
+ l = listnodes(tp->kids[0], 0, 0);
+ if (!IR->left_to_right || firstarg)
+ {
+ firstarg = NULL;
+ listnodes(arg0, 0, 0);
+ }
+ p = newnode(CALL + V, l, NULL, NULL);
+ }
+ else
+ {
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ p = newnode(tp->op == CALL + B ? tp->op : op, l, r, NULL);
+ }
+ NEW0(p->syms[0], FUNC);
+ assert(isptr(tp->kids[0]->type));
+ assert(isfunc(tp->kids[0]->type->type));
+ p->syms[0]->type = tp->kids[0]->type->type;
+ list(p);
+ reset();
+ cfunc->u.f.ncalls++;
+ firstarg = save;
+ }
+ break;
+ case ARG:
+ {
+ assert(tlab == 0 && flab == 0);
+ if (IR->left_to_right) listnodes(tp->kids[1], 0, 0);
+ if (firstarg)
+ {
+ Tree arg = firstarg;
+ firstarg = NULL;
+ listnodes(arg, 0, 0);
+ }
+ l = listnodes(tp->kids[0], 0, 0);
+ list(newnode(tp->op == ARG + B ? tp->op : op, l, NULL, NULL));
+ forest->syms[0] = intconst(tp->type->size);
+ forest->syms[1] = intconst(tp->type->align);
+ if (!IR->left_to_right) listnodes(tp->kids[1], 0, 0);
+ }
+ break;
+ case EQ:
+ case NE:
+ case GT:
+ case GE:
+ case LE:
+ case LT:
+ {
+ assert(tp->u.sym == 0);
+ assert(errcnt || tlab || flab);
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ assert(errcnt || opkind(l->op) == opkind(r->op));
+ assert(errcnt || optype(op) == optype(l->op));
+ if (tlab)
+ assert(flab == 0), list(newnode(generic(tp->op) + opkind(l->op), l, r, findlabel(tlab)));
+ else if (flab)
+ {
+ switch (generic(tp->op))
+ {
+ case EQ:
+ op = NE;
+ break;
+ case NE:
+ op = EQ;
+ break;
+ case GT:
+ op = LE;
+ break;
+ case LT:
+ op = GE;
+ break;
+ case GE:
+ op = LT;
+ break;
+ case LE:
+ op = GT;
+ break;
+ default:
+ assert(0);
+ }
+ list(newnode(op + opkind(l->op), l, r, findlabel(flab)));
+ }
+ if (forest && forest->syms[0]) forest->syms[0]->ref++;
+ }
+ break;
+ case ASGN:
+ {
+ assert(tlab == 0 && flab == 0);
+ if (tp->kids[0]->op == FIELD)
+ {
+ Tree x = tp->kids[0]->kids[0];
+ Field f = tp->kids[0]->u.field;
+ assert(generic(x->op) == INDIR);
+ reset();
+ l = listnodes(lvalue(x), 0, 0);
+ if (fieldsize(f) < 8 * f->type->size)
+ {
+ unsigned int fmask = fieldmask(f);
+ unsigned int mask = fmask << fieldright(f);
+ Tree q = tp->kids[1];
+ if ((q->op == CNST + I && q->u.v.i == 0) || (q->op == CNST + U && q->u.v.u == 0))
+ q = bittree(BAND, x, cnsttree(unsignedtype, (unsigned long)~mask));
+ else if ((q->op == CNST + I && (q->u.v.i & fmask) == fmask) ||
+ (q->op == CNST + U && (q->u.v.u & fmask) == fmask))
+ q = bittree(BOR, x, cnsttree(unsignedtype, (unsigned long)mask));
+ else
+ {
+ listnodes(q, 0, 0);
+ q = bittree(BOR, bittree(BAND, rvalue(lvalue(x)), cnsttree(unsignedtype, (unsigned long)~mask)),
+ bittree(BAND, shtree(LSH, cast(q, unsignedtype),
+ cnsttree(unsignedtype, (unsigned long)fieldright(f))),
+ cnsttree(unsignedtype, (unsigned long)mask)));
+ }
+ r = listnodes(q, 0, 0);
+ op = ASGN + ttob(q->type);
+ }
+ else
+ {
+ r = listnodes(tp->kids[1], 0, 0);
+ op = ASGN + ttob(tp->kids[1]->type);
+ }
+ }
+ else
+ {
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ }
+ list(newnode(tp->op == ASGN + B ? tp->op : op, l, r, NULL));
+ forest->syms[0] = intconst(tp->kids[1]->type->size);
+ forest->syms[1] = intconst(tp->kids[1]->type->align);
+ if (isaddrop(tp->kids[0]->op) && !tp->kids[0]->u.sym->computed)
+ kill(tp->kids[0]->u.sym);
+ else
+ reset();
+ p = listnodes(tp->kids[1], 0, 0);
+ }
+ break;
+ case BOR:
+ case BAND:
+ case BXOR:
+ case ADD:
+ case SUB:
+ case RSH:
+ case LSH:
+ {
+ assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ p = node(op, l, r, NULL);
+ }
+ break;
+ case DIV:
+ case MUL:
+ case MOD:
+ {
+ assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ p = node(op, l, r, NULL);
+ if (IR->mulops_calls && isint(tp->type))
+ {
+ list(p);
+ cfunc->u.f.ncalls++;
+ }
+ }
+ break;
+ case RET:
+ {
+ assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ list(newnode(op, l, NULL, NULL));
+ }
+ break;
+ case CVF:
+ case CVI:
+ case CVP:
+ case CVU:
+ {
+ assert(tlab == 0 && flab == 0);
+ assert(optype(tp->kids[0]->op) != optype(tp->op) || tp->kids[0]->type->size != tp->type->size);
+ l = listnodes(tp->kids[0], 0, 0);
+ p = node(op, l, NULL, intconst(tp->kids[0]->type->size));
+ }
+ break;
+ case BCOM:
+ case NEG:
+ {
+ assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ p = node(op, l, NULL, NULL);
+ }
+ break;
+ case INDIR:
+ {
+ Type ty = tp->kids[0]->type;
+ assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ if (isptr(ty)) ty = unqual(ty)->type;
+ if (isvolatile(ty) || (isstruct(ty) && unqual(ty)->u.sym->u.s.vfields))
+ p = newnode(tp->op == INDIR + B ? tp->op : op, l, NULL, NULL);
+ else
+ p = node(tp->op == INDIR + B ? tp->op : op, l, NULL, NULL);
+ }
+ break;
+ case FIELD:
+ {
+ Tree q = tp->kids[0];
+ if (tp->type == inttype)
+ {
+ long n = fieldleft(tp->u.field);
+ q = shtree(RSH, shtree(LSH, q, cnsttree(inttype, n)), cnsttree(inttype, n + fieldright(tp->u.field)));
+ }
+ else if (fieldsize(tp->u.field) < 8 * tp->u.field->type->size)
+ q = bittree(BAND, shtree(RSH, q, cnsttree(inttype, (long)fieldright(tp->u.field))),
+ cnsttree(unsignedtype, (unsigned long)fieldmask(tp->u.field)));
+ assert(tlab == 0 && flab == 0);
+ p = listnodes(q, 0, 0);
+ }
+ break;
+ case ADDRG:
+ case ADDRF:
+ {
+ assert(tlab == 0 && flab == 0);
+ p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym);
+ }
+ break;
+ case ADDRL:
+ {
+ assert(tlab == 0 && flab == 0);
+ if (tp->u.sym->temporary) addlocal(tp->u.sym);
+ p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym);
+ }
+ break;
+ default:
+ assert(0);
+ }
+ tp->node = p;
+ return p;
}
-static void list(Node p) {
- if (p && p->link == NULL) {
- if (forest) {
- p->link = forest->link;
- forest->link = p;
- } else
- p->link = p;
- forest = p;
- }
+static void list(Node p)
+{
+ if (p && p->link == NULL)
+ {
+ if (forest)
+ {
+ p->link = forest->link;
+ forest->link = p;
+ }
+ else
+ p->link = p;
+ forest = p;
+ }
}
-static void labelnode(int lab) {
- assert(lab);
- if (forest && forest->op == LABEL+V)
- equatelab(findlabel(lab), forest->syms[0]);
- else
- list(newnode(LABEL+V, NULL, NULL, findlabel(lab)));
- reset();
+static void labelnode(int lab)
+{
+ assert(lab);
+ if (forest && forest->op == LABEL + V)
+ equatelab(findlabel(lab), forest->syms[0]);
+ else
+ list(newnode(LABEL + V, NULL, NULL, findlabel(lab)));
+ reset();
}
-static void unlist(void) {
- Node p;
+static void unlist(void)
+{
+ Node p;
- assert(forest);
- assert(forest != forest->link);
- p = forest->link;
- while (p->link != forest)
- p = p->link;
- p->link = forest->link;
- forest = p;
+ assert(forest);
+ assert(forest != forest->link);
+ p = forest->link;
+ while (p->link != forest) p = p->link;
+ p->link = forest->link;
+ forest = p;
}
-Tree cvtconst(Tree p) {
- Symbol q = constant(p->type, p->u.v);
- Tree e;
+Tree cvtconst(Tree p)
+{
+ Symbol q = constant(p->type, p->u.v);
+ Tree e;
- if (q->u.c.loc == NULL)
- q->u.c.loc = genident(STATIC, p->type, GLOBAL);
- if (isarray(p->type)) {
- e = simplify(ADDRG, atop(p->type), NULL, NULL);
- e->u.sym = q->u.c.loc;
- } else
- e = idtree(q->u.c.loc);
- return e;
+ if (q->u.c.loc == NULL) q->u.c.loc = genident(STATIC, p->type, GLOBAL);
+ if (isarray(p->type))
+ {
+ e = simplify(ADDRG, atop(p->type), NULL, NULL);
+ e->u.sym = q->u.c.loc;
+ }
+ else
+ e = idtree(q->u.c.loc);
+ return e;
}
-void gencode(Symbol caller[], Symbol callee[]) {
- Code cp;
- Coordinate save;
+void gencode(Symbol caller[], Symbol callee[])
+{
+ Code cp;
+ Coordinate save;
- if (prunetemps == -1)
- prunetemps = !IR->wants_dag;
- save = src;
- if (assignargs) {
- int i;
- Symbol p, q;
- cp = codehead.next->next;
- codelist = codehead.next;
- for (i = 0; (p = callee[i]) != NULL
- && (q = caller[i]) != NULL; i++)
- if (p->sclass != q->sclass || p->type != q->type)
- walk(asgn(p, idtree(q)), 0, 0);
- codelist->next = cp;
- cp->prev = codelist;
- }
- if (glevel && IR->stabsym) {
- int i;
- Symbol p, q;
- for (i = 0; (p = callee[i]) != NULL
- && (q = caller[i]) != NULL; i++) {
- (*IR->stabsym)(p);
- if (p->sclass != q->sclass || p->type != q->type)
- (*IR->stabsym)(q);
- }
- swtoseg(CODE);
- }
- cp = codehead.next;
- for ( ; errcnt <= 0 && cp; cp = cp->next)
- switch (cp->kind) {
- case Address: (*IR->address)(cp->u.addr.sym, cp->u.addr.base,
- cp->u.addr.offset); break;
- case Blockbeg: {
- Symbol *p = cp->u.block.locals;
- (*IR->blockbeg)(&cp->u.block.x);
- for ( ; *p; p++)
- if ((*p)->ref != 0.0)
- (*IR->local)(*p);
- else if (glevel) (*IR->local)(*p);
- }
- break;
- case Blockend: (*IR->blockend)(&cp->u.begin->u.block.x); break;
- case Defpoint: src = cp->u.point.src; break;
- case Gen: case Jump:
- case Label: if (prunetemps)
- cp->u.forest = prune(cp->u.forest);
- fixup(cp->u.forest);
- cp->u.forest = (*IR->gen)(cp->u.forest); break;
- case Local: (*IR->local)(cp->u.var); break;
- case Switch: break;
- default: assert(0);
- }
- src = save;
+ if (prunetemps == -1) prunetemps = !IR->wants_dag;
+ save = src;
+ if (assignargs)
+ {
+ int i;
+ Symbol p, q;
+ cp = codehead.next->next;
+ codelist = codehead.next;
+ for (i = 0; (p = callee[i]) != NULL && (q = caller[i]) != NULL; i++)
+ if (p->sclass != q->sclass || p->type != q->type) walk(asgn(p, idtree(q)), 0, 0);
+ codelist->next = cp;
+ cp->prev = codelist;
+ }
+ if (glevel && IR->stabsym)
+ {
+ int i;
+ Symbol p, q;
+ for (i = 0; (p = callee[i]) != NULL && (q = caller[i]) != NULL; i++)
+ {
+ (*IR->stabsym)(p);
+ if (p->sclass != q->sclass || p->type != q->type) (*IR->stabsym)(q);
+ }
+ swtoseg(CODE);
+ }
+ cp = codehead.next;
+ for (; errcnt <= 0 && cp; cp = cp->next) switch (cp->kind)
+ {
+ case Address:
+ (*IR->address)(cp->u.addr.sym, cp->u.addr.base, cp->u.addr.offset);
+ break;
+ case Blockbeg:
+ {
+ Symbol *p = cp->u.block.locals;
+ (*IR->blockbeg)(&cp->u.block.x);
+ for (; *p; p++)
+ if ((*p)->ref != 0.0)
+ (*IR->local)(*p);
+ else if (glevel)
+ (*IR->local)(*p);
+ }
+ break;
+ case Blockend:
+ (*IR->blockend)(&cp->u.begin->u.block.x);
+ break;
+ case Defpoint:
+ src = cp->u.point.src;
+ break;
+ case Gen:
+ case Jump:
+ case Label:
+ if (prunetemps) cp->u.forest = prune(cp->u.forest);
+ fixup(cp->u.forest);
+ cp->u.forest = (*IR->gen)(cp->u.forest);
+ break;
+ case Local:
+ (*IR->local)(cp->u.var);
+ break;
+ case Switch:
+ break;
+ default:
+ assert(0);
+ }
+ src = save;
}
-static void fixup(Node p) {
- for ( ; p; p = p->link)
- switch (generic(p->op)) {
- case JUMP:
- if (specific(p->kids[0]->op) == ADDRG+P)
- p->kids[0]->syms[0] =
- equated(p->kids[0]->syms[0]);
- break;
- case LABEL: assert(p->syms[0] == equated(p->syms[0])); break;
- case EQ: case GE: case GT: case LE: case LT: case NE:
- assert(p->syms[0]);
- p->syms[0] = equated(p->syms[0]);
- }
+static void fixup(Node p)
+{
+ for (; p; p = p->link) switch (generic(p->op))
+ {
+ case JUMP:
+ if (specific(p->kids[0]->op) == ADDRG + P) p->kids[0]->syms[0] = equated(p->kids[0]->syms[0]);
+ break;
+ case LABEL:
+ assert(p->syms[0] == equated(p->syms[0]));
+ break;
+ case EQ:
+ case GE:
+ case GT:
+ case LE:
+ case LT:
+ case NE:
+ assert(p->syms[0]);
+ p->syms[0] = equated(p->syms[0]);
+ }
}
-static Symbol equated(Symbol p) {
- { Symbol q; for (q = p->u.l.equatedto; q; q = q->u.l.equatedto) assert(p != q); }
- while (p->u.l.equatedto)
- p = p->u.l.equatedto;
- return p;
+static Symbol equated(Symbol p)
+{
+ {
+ Symbol q;
+ for (q = p->u.l.equatedto; q; q = q->u.l.equatedto) assert(p != q);
+ }
+ while (p->u.l.equatedto) p = p->u.l.equatedto;
+ return p;
}
-void emitcode(void) {
- Code cp;
- Coordinate save;
+void emitcode(void)
+{
+ Code cp;
+ Coordinate save;
- save = src;
- cp = codehead.next;
- for ( ; errcnt <= 0 && cp; cp = cp->next)
- switch (cp->kind) {
- case Address: break;
- case Blockbeg: if (glevel && IR->stabblock) {
- (*IR->stabblock)('{', cp->u.block.level - LOCAL, cp->u.block.locals);
- swtoseg(CODE);
- }
- break;
- case Blockend: if (glevel && IR->stabblock) {
- Code bp = cp->u.begin;
- foreach(bp->u.block.identifiers, bp->u.block.level, typestab, NULL);
- foreach(bp->u.block.types, bp->u.block.level, typestab, NULL);
- (*IR->stabblock)('}', bp->u.block.level - LOCAL, bp->u.block.locals);
- swtoseg(CODE);
- }
- break;
- case Defpoint: src = cp->u.point.src;
- if (glevel > 0 && IR->stabline) {
- (*IR->stabline)(&cp->u.point.src); swtoseg(CODE); } break;
- case Gen: case Jump:
- case Label: if (cp->u.forest)
- (*IR->emit)(cp->u.forest); break;
- case Local: if (glevel && IR->stabsym) {
- (*IR->stabsym)(cp->u.var);
- swtoseg(CODE);
- } break;
- case Switch: { int i;
- defglobal(cp->u.swtch.table, LIT);
- (*IR->defaddress)(equated(cp->u.swtch.labels[0]));
- for (i = 1; i < cp->u.swtch.size; i++) {
- long k = cp->u.swtch.values[i-1];
- while (++k < cp->u.swtch.values[i])
- assert(k < LONG_MAX),
- (*IR->defaddress)(equated(cp->u.swtch.deflab));
- (*IR->defaddress)(equated(cp->u.swtch.labels[i]));
- }
- swtoseg(CODE);
- } break;
- default: assert(0);
- }
- src = save;
+ save = src;
+ cp = codehead.next;
+ for (; errcnt <= 0 && cp; cp = cp->next) switch (cp->kind)
+ {
+ case Address:
+ break;
+ case Blockbeg:
+ if (glevel && IR->stabblock)
+ {
+ (*IR->stabblock)('{', cp->u.block.level - LOCAL, cp->u.block.locals);
+ swtoseg(CODE);
+ }
+ break;
+ case Blockend:
+ if (glevel && IR->stabblock)
+ {
+ Code bp = cp->u.begin;
+ foreach (bp->u.block.identifiers, bp->u.block.level, typestab, NULL)
+ ;
+ foreach (bp->u.block.types, bp->u.block.level, typestab, NULL)
+ ;
+ (*IR->stabblock)('}', bp->u.block.level - LOCAL, bp->u.block.locals);
+ swtoseg(CODE);
+ }
+ break;
+ case Defpoint:
+ src = cp->u.point.src;
+ if (glevel > 0 && IR->stabline)
+ {
+ (*IR->stabline)(&cp->u.point.src);
+ swtoseg(CODE);
+ }
+ break;
+ case Gen:
+ case Jump:
+ case Label:
+ if (cp->u.forest) (*IR->emit)(cp->u.forest);
+ break;
+ case Local:
+ if (glevel && IR->stabsym)
+ {
+ (*IR->stabsym)(cp->u.var);
+ swtoseg(CODE);
+ }
+ break;
+ case Switch:
+ {
+ int i;
+ defglobal(cp->u.swtch.table, LIT);
+ (*IR->defaddress)(equated(cp->u.swtch.labels[0]));
+ for (i = 1; i < cp->u.swtch.size; i++)
+ {
+ long k = cp->u.swtch.values[i - 1];
+ while (++k < cp->u.swtch.values[i])
+ assert(k < LONG_MAX), (*IR->defaddress)(equated(cp->u.swtch.deflab));
+ (*IR->defaddress)(equated(cp->u.swtch.labels[i]));
+ }
+ swtoseg(CODE);
+ }
+ break;
+ default:
+ assert(0);
+ }
+ src = save;
}
-static Node undag(Node forest) {
- Node p;
+static Node undag(Node forest)
+{
+ Node p;
- tail = &forest;
- for (p = forest; p; p = p->link)
- if (generic(p->op) == INDIR) {
- assert(p->count >= 1);
- visit(p, 1);
- if (p->syms[2]) {
- assert(p->syms[2]->u.t.cse);
- p->syms[2]->u.t.cse = NULL;
- addlocal(p->syms[2]);
- }
- } else if (iscall(p->op) && p->count >= 1)
- visit(p, 1);
- else {
- assert(p->count == 0),
- visit(p, 1);
- *tail = p;
- tail = &p->link;
- }
- *tail = NULL;
- return forest;
+ tail = &forest;
+ for (p = forest; p; p = p->link)
+ if (generic(p->op) == INDIR)
+ {
+ assert(p->count >= 1);
+ visit(p, 1);
+ if (p->syms[2])
+ {
+ assert(p->syms[2]->u.t.cse);
+ p->syms[2]->u.t.cse = NULL;
+ addlocal(p->syms[2]);
+ }
+ }
+ else if (iscall(p->op) && p->count >= 1)
+ visit(p, 1);
+ else
+ {
+ assert(p->count == 0), visit(p, 1);
+ *tail = p;
+ tail = &p->link;
+ }
+ *tail = NULL;
+ return forest;
}
-static Node replace(Node p) {
- if (p && ( generic(p->op) == INDIR
- && generic(p->kids[0]->op) == ADDRL
- && p->kids[0]->syms[0]->temporary
- && p->kids[0]->syms[0]->u.t.replace)) {
- p = p->kids[0]->syms[0]->u.t.cse;
- if (generic(p->op) == INDIR && isaddrop(p->kids[0]->op))
- p = newnode(p->op, newnode(p->kids[0]->op, NULL, NULL,
- p->kids[0]->syms[0]), NULL, NULL);
- else if (generic(p->op) == ADDRG)
- p = newnode(p->op, NULL, NULL, p->syms[0]);
- else
- assert(0);
- p->count = 1;
- } else if (p) {
- p->kids[0] = replace(p->kids[0]);
- p->kids[1] = replace(p->kids[1]);
- }
- return p;
+static Node replace(Node p)
+{
+ if (p && (generic(p->op) == INDIR && generic(p->kids[0]->op) == ADDRL && p->kids[0]->syms[0]->temporary &&
+ p->kids[0]->syms[0]->u.t.replace))
+ {
+ p = p->kids[0]->syms[0]->u.t.cse;
+ if (generic(p->op) == INDIR && isaddrop(p->kids[0]->op))
+ p = newnode(p->op, newnode(p->kids[0]->op, NULL, NULL, p->kids[0]->syms[0]), NULL, NULL);
+ else if (generic(p->op) == ADDRG)
+ p = newnode(p->op, NULL, NULL, p->syms[0]);
+ else
+ assert(0);
+ p->count = 1;
+ }
+ else if (p)
+ {
+ p->kids[0] = replace(p->kids[0]);
+ p->kids[1] = replace(p->kids[1]);
+ }
+ return p;
}
-static Node prune(Node forest) {
- Node p, *tail = &forest;
- int count = 0;
+static Node prune(Node forest)
+{
+ Node p, *tail = &forest;
+ int count = 0;
- for (p = forest; p; p = p->link) {
- if (count > 0) {
- p->kids[0] = replace(p->kids[0]);
- p->kids[1] = replace(p->kids[1]);
- }
- if (( generic(p->op) == ASGN
- && generic(p->kids[0]->op) == ADDRL
- && p->kids[0]->syms[0]->temporary
- && p->kids[0]->syms[0]->u.t.cse == p->kids[1])) {
- Symbol tmp = p->kids[0]->syms[0];
- if (!tmp->defined)
- (*IR->local)(tmp);
- tmp->defined = 1;
- if (( generic(p->kids[1]->op) == INDIR
- && isaddrop(p->kids[1]->kids[0]->op)
- && p->kids[1]->kids[0]->syms[0]->sclass == REGISTER)
- || (( generic(p->kids[1]->op) == INDIR
- && isaddrop(p->kids[1]->kids[0]->op)) && tmp->sclass == AUTO)
- || (generic(p->kids[1]->op) == ADDRG && tmp->sclass == AUTO)) {
- tmp->u.t.replace = 1;
- count++;
- continue; /* and omit the assignment */
- }
- }
- /* keep the assignment and other roots */
- *tail = p;
- tail = &(*tail)->link;
- }
- assert(*tail == NULL);
- return forest;
+ for (p = forest; p; p = p->link)
+ {
+ if (count > 0)
+ {
+ p->kids[0] = replace(p->kids[0]);
+ p->kids[1] = replace(p->kids[1]);
+ }
+ if ((generic(p->op) == ASGN && generic(p->kids[0]->op) == ADDRL && p->kids[0]->syms[0]->temporary &&
+ p->kids[0]->syms[0]->u.t.cse == p->kids[1]))
+ {
+ Symbol tmp = p->kids[0]->syms[0];
+ if (!tmp->defined) (*IR->local)(tmp);
+ tmp->defined = 1;
+ if ((generic(p->kids[1]->op) == INDIR && isaddrop(p->kids[1]->kids[0]->op) &&
+ p->kids[1]->kids[0]->syms[0]->sclass == REGISTER) ||
+ ((generic(p->kids[1]->op) == INDIR && isaddrop(p->kids[1]->kids[0]->op)) && tmp->sclass == AUTO) ||
+ (generic(p->kids[1]->op) == ADDRG && tmp->sclass == AUTO))
+ {
+ tmp->u.t.replace = 1;
+ count++;
+ continue; /* and omit the assignment */
+ }
+ }
+ /* keep the assignment and other roots */
+ *tail = p;
+ tail = &(*tail)->link;
+ }
+ assert(*tail == NULL);
+ return forest;
}
-static Node visit(Node p, int listed) {
- if (p) {
- if (p->syms[2])
- p = tmpnode(p);
- else if ((p->count <= 1 && !iscall(p->op))
- || (p->count == 0 && iscall(p->op))) {
- p->kids[0] = visit(p->kids[0], 0);
- p->kids[1] = visit(p->kids[1], 0);
- }
+static Node visit(Node p, int listed)
+{
+ if (p)
+ {
+ if (p->syms[2])
+ p = tmpnode(p);
+ else if ((p->count <= 1 && !iscall(p->op)) || (p->count == 0 && iscall(p->op)))
+ {
+ p->kids[0] = visit(p->kids[0], 0);
+ p->kids[1] = visit(p->kids[1], 0);
+ }
- else if (specific(p->op) == ADDRL+P || specific(p->op) == ADDRF+P) {
- assert(!listed);
- p = newnode(p->op, NULL, NULL, p->syms[0]);
- p->count = 1;
- }
- else if (p->op == INDIR+B) {
- p = newnode(p->op, p->kids[0], NULL, NULL);
- p->count = 1;
- p->kids[0] = visit(p->kids[0], 0);
- p->kids[1] = visit(p->kids[1], 0);
- }
- else {
- p->kids[0] = visit(p->kids[0], 0);
- p->kids[1] = visit(p->kids[1], 0);
- p->syms[2] = temporary(REGISTER, btot(p->op, opsize(p->op)));
- assert(!p->syms[2]->defined);
- p->syms[2]->ref = 1;
- p->syms[2]->u.t.cse = p;
+ else if (specific(p->op) == ADDRL + P || specific(p->op) == ADDRF + P)
+ {
+ assert(!listed);
+ p = newnode(p->op, NULL, NULL, p->syms[0]);
+ p->count = 1;
+ }
+ else if (p->op == INDIR + B)
+ {
+ p = newnode(p->op, p->kids[0], NULL, NULL);
+ p->count = 1;
+ p->kids[0] = visit(p->kids[0], 0);
+ p->kids[1] = visit(p->kids[1], 0);
+ }
+ else
+ {
+ p->kids[0] = visit(p->kids[0], 0);
+ p->kids[1] = visit(p->kids[1], 0);
+ p->syms[2] = temporary(REGISTER, btot(p->op, opsize(p->op)));
+ assert(!p->syms[2]->defined);
+ p->syms[2]->ref = 1;
+ p->syms[2]->u.t.cse = p;
- *tail = asgnnode(p->syms[2], p);
- tail = &(*tail)->link;
- if (!listed)
- p = tmpnode(p);
- };
- }
- return p;
+ *tail = asgnnode(p->syms[2], p);
+ tail = &(*tail)->link;
+ if (!listed) p = tmpnode(p);
+ };
+ }
+ return p;
}
-static Node tmpnode(Node p) {
- Symbol tmp = p->syms[2];
+static Node tmpnode(Node p)
+{
+ Symbol tmp = p->syms[2];
- assert(tmp);
- if (--p->count == 0)
- p->syms[2] = NULL;
- p = newnode(INDIR + ttob(tmp->type),
- newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), NULL, NULL);
- p->count = 1;
- return p;
+ assert(tmp);
+ if (--p->count == 0) p->syms[2] = NULL;
+ p = newnode(INDIR + ttob(tmp->type), newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), NULL, NULL);
+ p->count = 1;
+ return p;
}
-static Node asgnnode(Symbol tmp, Node p) {
- p = newnode(ASGN + ttob(tmp->type),
- newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), p, NULL);
- p->syms[0] = intconst(tmp->type->size);
- p->syms[1] = intconst(tmp->type->align);
- return p;
+static Node asgnnode(Symbol tmp, Node p)
+{
+ p = newnode(ASGN + ttob(tmp->type), newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), p, NULL);
+ p->syms[0] = intconst(tmp->type->size);
+ p->syms[1] = intconst(tmp->type->align);
+ return p;
}
/* printdag - print dag p on fd, or the node list if p == 0 */
-void printdag(Node p, int fd) {
- FILE *f = fd == 1 ? stdout : stderr;
+void printdag(Node p, int fd)
+{
+ FILE *f = fd == 1 ? stdout : stderr;
- printed(0);
- if (p == 0) {
- if ((p = forest) != NULL)
- do {
- p = p->link;
- printdag1(p, fd, 0);
- } while (p != forest);
- } else if (*printed(nodeid((Tree)p)))
- fprint(f, "node'%d printed above\n", nodeid((Tree)p));
- else
- printdag1(p, fd, 0);
+ printed(0);
+ if (p == 0)
+ {
+ if ((p = forest) != NULL) do
+ {
+ p = p->link;
+ printdag1(p, fd, 0);
+ } while (p != forest);
+ }
+ else if (*printed(nodeid((Tree)p)))
+ fprint(f, "node'%d printed above\n", nodeid((Tree)p));
+ else
+ printdag1(p, fd, 0);
}
/* printdag1 - recursively print dag p */
-static void printdag1(Node p, int fd, int lev) {
- int id, i;
+static void printdag1(Node p, int fd, int lev)
+{
+ int id, i;
- if (p == 0 || *printed(id = nodeid((Tree)p)))
- return;
- *printed(id) = 1;
- for (i = 0; i < NELEMS(p->kids); i++)
- printdag1(p->kids[i], fd, lev + 1);
- printnode(p, fd, lev);
+ if (p == 0 || *printed(id = nodeid((Tree)p))) return;
+ *printed(id) = 1;
+ for (i = 0; i < NELEMS(p->kids); i++) printdag1(p->kids[i], fd, lev + 1);
+ printnode(p, fd, lev);
}
/* printnode - print fields of dag p */
-static void printnode(Node p, int fd, int lev) {
- if (p) {
- FILE *f = fd == 1 ? stdout : stderr;
- int i, id = nodeid((Tree)p);
- fprint(f, "%c%d%s", lev == 0 ? '\'' : '#', id,
- &" "[id < 10 ? 0 : id < 100 ? 1 : 2]);
- fprint(f, "%s count=%d", opname(p->op), p->count);
- for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++)
- fprint(f, " #%d", nodeid((Tree)p->kids[i]));
- if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
- fprint(f, " {%t}", p->syms[0]->type);
- else
- for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++)
- if (p->syms[i]->name)
- fprint(f, " %s", p->syms[i]->name);
- else
- fprint(f, " %p", p->syms[i]);
- fprint(f, "\n");
- }
+static void printnode(Node p, int fd, int lev)
+{
+ if (p)
+ {
+ FILE *f = fd == 1 ? stdout : stderr;
+ int i, id = nodeid((Tree)p);
+ fprint(f, "%c%d%s", lev == 0 ? '\'' : '#', id, &" "[id < 10 ? 0 : id < 100 ? 1 : 2]);
+ fprint(f, "%s count=%d", opname(p->op), p->count);
+ for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++) fprint(f, " #%d", nodeid((Tree)p->kids[i]));
+ if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
+ fprint(f, " {%t}", p->syms[0]->type);
+ else
+ for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++)
+ if (p->syms[i]->name)
+ fprint(f, " %s", p->syms[i]->name);
+ else
+ fprint(f, " %p", p->syms[i]);
+ fprint(f, "\n");
+ }
}
/* typestab - emit stab entries for p */
-static void typestab(Symbol p, void *cl) {
- if (!isfunc(p->type) && (p->sclass == EXTERN || p->sclass == STATIC) && IR->stabsym)
- (*IR->stabsym)(p);
- else if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype)
- (*IR->stabtype)(p);
+static void typestab(Symbol p, void *cl)
+{
+ if (!isfunc(p->type) && (p->sclass == EXTERN || p->sclass == STATIC) && IR->stabsym)
+ (*IR->stabsym)(p);
+ else if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype)
+ (*IR->stabtype)(p);
}
-
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
new file mode 100644
index 0000000..18ddfe1
--- /dev/null
+++ b/src/ui/CMakeLists.txt
@@ -0,0 +1,67 @@
+#
+## _ _ ___ ____ _
+## | | | |_ _| / ___|___ __| | ___
+## | | | || | | | / _ \ / _` |/ _ \
+## | |_| || | | |__| (_) | (_| | __/
+## \___/|___| \____\___/ \__,_|\___|
+##
+#
+
+set(CMAKE_INSTALL_NAME_DIR ${PROJECT_BINARY_DIR}/gpp)
+
+set(BG_SOURCE_DIR ../game)
+set(QC_SOURCE_DIR ../qcommon)
+set(RC_SOURCE_DIR ../renderercommon)
+set(CLIENT_SOURCE_DIR ../client)
+
+add_definitions( -DUI )
+
+#add_custom_command(
+# OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/menudef.h
+# COMMAND ${CMAKE_COMMAND}
+# ARGS -E copy ${CMAKE_BINARY_DIR}/assets/ui/menudef.h ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/menudef.h
+# DEPENDS ${CMAKE_BINARY_DIR}/assets/ui/menudef.h
+# )
+#set_source_files_properties(menudef.h PROPERTIES GENERATED TRUE)
+
+set(UI_SOURCES
+ ui_main.c # Must be listed first!
+ ui_atoms.c
+ ui_gameinfo.c
+ ui_local.h
+ ui_shared.c
+ ui_shared.h
+ ${CMAKE_SOURCE_DIR}/assets/ui/menudef.h
+ ${BG_SOURCE_DIR}/bg_lib.h
+ ${BG_SOURCE_DIR}/bg_public.h
+ ${BG_SOURCE_DIR}/bg_alloc.c
+ ${BG_SOURCE_DIR}/bg_lib.c
+ ${BG_SOURCE_DIR}/bg_misc.c
+ ${BG_SOURCE_DIR}/bg_voice.c
+ ${QC_SOURCE_DIR}/q_shared.h
+ ${QC_SOURCE_DIR}/q_shared.c
+ ${QC_SOURCE_DIR}/q_math.c
+ ${RC_SOURCE_DIR}/tr_types.h
+ ${CLIENT_SOURCE_DIR}/keycodes.h
+ )
+
+add_library(
+ ui SHARED
+ ${UI_SOURCES}
+ ui_syscalls.c
+ )
+
+target_include_directories(
+ ui PUBLIC
+ ${QC_SOURCE_DIR}
+ ${BG_SOURCE_DIR}
+ )
+
+include(${CMAKE_SOURCE_DIR}/cmake/AddQVM.cmake)
+add_qvm( ui ${UI_SOURCES} ui_syscalls.asm )
+
+add_custom_command(
+ TARGET ui POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${CMAKE_CURRENT_BINARY_DIR}/libui${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpp/ui${CMAKE_SHARED_LIBRARY_SUFFIX}
+ )
diff --git a/src/ui/menudef.h b/src/ui/menudef.h
deleted file mode 100644
index dbd0996..0000000
--- a/src/ui/menudef.h
+++ /dev/null
@@ -1,363 +0,0 @@
-
-#define ITEM_TYPE_TEXT 0 // simple text
-#define ITEM_TYPE_BUTTON 1 // button, basically text with a border
-#define ITEM_TYPE_RADIOBUTTON 2 // toggle button, may be grouped
-#define ITEM_TYPE_CHECKBOX 3 // check box
-#define ITEM_TYPE_EDITFIELD 4 // editable text, associated with a cvar
-#define ITEM_TYPE_SAYFIELD 5 // the chat field
-#define ITEM_TYPE_COMBO 6 // drop down list
-#define ITEM_TYPE_LISTBOX 7 // scrollable list
-#define ITEM_TYPE_MODEL 8 // model
-#define ITEM_TYPE_OWNERDRAW 9 // owner draw, name specs what it is
-#define ITEM_TYPE_NUMERICFIELD 10 // editable text, associated with a cvar
-#define ITEM_TYPE_SLIDER 11 // mouse speed, volume, etc.
-#define ITEM_TYPE_YESNO 12 // yes no cvar setting
-#define ITEM_TYPE_MULTI 13 // multiple list setting, enumerated
-#define ITEM_TYPE_BIND 14 // multiple list setting, enumerated
-
-#define ITEM_ALIGN_LEFT 0 // left alignment
-#define ITEM_ALIGN_CENTER 1 // center alignment
-#define ITEM_ALIGN_RIGHT 2 // right alignment
-
-#define ITEM_TEXTSTYLE_NORMAL 0 // normal text
-#define ITEM_TEXTSTYLE_BLINK 1 // fast blinking
-#define ITEM_TEXTSTYLE_PULSE 2 // slow pulsing
-#define ITEM_TEXTSTYLE_SHADOWED 3 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_OUTLINED 4 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_OUTLINESHADOWED 5 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_SHADOWEDMORE 6 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_NEON 7 // drop shadow ( need a color for this )
-
-#define WINDOW_BORDER_NONE 0 // no border
-#define WINDOW_BORDER_FULL 1 // full border based on border color ( single pixel )
-#define WINDOW_BORDER_HORZ 2 // horizontal borders only
-#define WINDOW_BORDER_VERT 3 // vertical borders only
-#define WINDOW_BORDER_KCGRADIENT 4 // horizontal border using the gradient bars
-
-#define WINDOW_STYLE_EMPTY 0 // no background
-#define WINDOW_STYLE_FILLED 1 // filled with background color
-#define WINDOW_STYLE_GRADIENT 2 // gradient bar based on background color
-#define WINDOW_STYLE_SHADER 3 // gradient bar based on background color
-#define WINDOW_STYLE_TEAMCOLOR 4 // team color
-#define WINDOW_STYLE_CINEMATIC 5 // cinematic
-
-#define MENU_TRUE 1 // uh.. true
-#define MENU_FALSE 0 // and false
-
-#define HUD_VERTICAL 0x00
-#define HUD_HORIZONTAL 0x01
-
-// list box element types
-#define LISTBOX_TEXT 0x00
-#define LISTBOX_IMAGE 0x01
-
-// list feeders
-#define FEEDER_HEADS 0x00 // model heads
-#define FEEDER_MAPS 0x01 // text maps based on game type
-#define FEEDER_SERVERS 0x02 // servers
-#define FEEDER_CLANS 0x03 // clan names
-#define FEEDER_ALLMAPS 0x04 // all maps available, in graphic format
-#define FEEDER_ALIENTEAM_LIST 0x05 // red team members
-#define FEEDER_HUMANTEAM_LIST 0x06 // blue team members
-#define FEEDER_PLAYER_LIST 0x07 // players
-#define FEEDER_TEAM_LIST 0x08 // team members for team voting
-#define FEEDER_MODS 0x09 // team members for team voting
-#define FEEDER_DEMOS 0x0a // team members for team voting
-#define FEEDER_SCOREBOARD 0x0b // team members for team voting
-#define FEEDER_Q3HEADS 0x0c // model heads
-#define FEEDER_SERVERSTATUS 0x0d // server status
-#define FEEDER_FINDPLAYER 0x0e // find player
-#define FEEDER_CINEMATICS 0x0f // cinematics
-
-//TA: tremulous menus
-#define FEEDER_TREMTEAMS 0x10 //teams
-#define FEEDER_TREMALIENCLASSES 0x11 //alien classes
-#define FEEDER_TREMHUMANITEMS 0x12 //human items
-#define FEEDER_TREMHUMANARMOURYBUY 0x13 //human buy
-#define FEEDER_TREMHUMANARMOURYSELL 0x14 //human sell
-#define FEEDER_TREMALIENUPGRADE 0x15 //alien upgrade
-#define FEEDER_TREMALIENBUILD 0x16 //alien buildables
-#define FEEDER_TREMHUMANBUILD 0x17 //human buildables
-//TA: tremulous menus
-#define FEEDER_IGNORE_LIST 0x18 //ignored players
-
-// display flags
-#define CG_SHOW_BLUE_TEAM_HAS_REDFLAG 0x00000001
-#define CG_SHOW_RED_TEAM_HAS_BLUEFLAG 0x00000002
-#define CG_SHOW_ANYTEAMGAME 0x00000004
-#define CG_SHOW_HARVESTER 0x00000008
-#define CG_SHOW_ONEFLAG 0x00000010
-#define CG_SHOW_CTF 0x00000020
-#define CG_SHOW_OBELISK 0x00000040
-#define CG_SHOW_HEALTHCRITICAL 0x00000080
-#define CG_SHOW_SINGLEPLAYER 0x00000100
-#define CG_SHOW_TOURNAMENT 0x00000200
-#define CG_SHOW_DURINGINCOMINGVOICE 0x00000400
-#define CG_SHOW_IF_PLAYER_HAS_FLAG 0x00000800
-#define CG_SHOW_LANPLAYONLY 0x00001000
-#define CG_SHOW_MINED 0x00002000
-#define CG_SHOW_HEALTHOK 0x00004000
-#define CG_SHOW_TEAMINFO 0x00008000
-#define CG_SHOW_NOTEAMINFO 0x00010000
-#define CG_SHOW_OTHERTEAMHASFLAG 0x00020000
-#define CG_SHOW_YOURTEAMHASENEMYFLAG 0x00040000
-#define CG_SHOW_ANYNONTEAMGAME 0x00080000
-#define CG_SHOW_2DONLY 0x10000000
-
-
-#define UI_SHOW_LEADER 0x00000001
-#define UI_SHOW_NOTLEADER 0x00000002
-#define UI_SHOW_FAVORITESERVERS 0x00000004
-#define UI_SHOW_ANYNONTEAMGAME 0x00000008
-#define UI_SHOW_ANYTEAMGAME 0x00000010
-#define UI_SHOW_NEWHIGHSCORE 0x00000020
-#define UI_SHOW_DEMOAVAILABLE 0x00000040
-#define UI_SHOW_NEWBESTTIME 0x00000080
-#define UI_SHOW_FFA 0x00000100
-#define UI_SHOW_NOTFFA 0x00000200
-#define UI_SHOW_NETANYNONTEAMGAME 0x00000400
-#define UI_SHOW_NETANYTEAMGAME 0x00000800
-#define UI_SHOW_NOTFAVORITESERVERS 0x00001000
-
-#define UI_SHOW_VOTEACTIVE 0x00002000
-#define UI_SHOW_CANVOTE 0x00004000
-#define UI_SHOW_TEAMVOTEACTIVE 0x00008000
-#define UI_SHOW_CANTEAMVOTE 0x00010000
-
-#define UI_SHOW_NOTSPECTATING 0x00020000
-
-// owner draw types
-// ideally these should be done outside of this file but
-// this makes it much easier for the macro expansion to
-// convert them for the designers ( from the .menu files )
-#define CG_OWNERDRAW_BASE 1
-#define CG_PLAYER_ARMOR_ICON 1
-#define CG_PLAYER_ARMOR_VALUE 2
-#define CG_PLAYER_HEAD 3
-#define CG_PLAYER_HEALTH 4
-#define CG_PLAYER_HEALTH_BAR 92
-#define CG_PLAYER_HEALTH_CROSS 99
-#define CG_PLAYER_AMMO_ICON 5
-#define CG_PLAYER_AMMO_VALUE 6
-#define CG_PLAYER_CLIPS_VALUE 70
-#define CG_PLAYER_BUILD_TIMER 115
-#define CG_PLAYER_CREDITS_VALUE 71
-#define CG_PLAYER_BANK_VALUE 72
-#define CG_PLAYER_CREDITS_VALUE_NOPAD 106
-#define CG_PLAYER_BANK_VALUE_NOPAD 107
-#define CG_PLAYER_STAMINA 73
-#define CG_PLAYER_STAMINA_1 93
-#define CG_PLAYER_STAMINA_2 94
-#define CG_PLAYER_STAMINA_3 95
-#define CG_PLAYER_STAMINA_4 96
-#define CG_PLAYER_STAMINA_BOLT 97
-#define CG_PLAYER_BOOST_BOLT 112
-#define CG_PLAYER_CLIPS_RING 98
-#define CG_PLAYER_BUILD_TIMER_RING 113
-#define CG_PLAYER_SELECT 74
-#define CG_PLAYER_SELECTTEXT 75
-#define CG_PLAYER_WEAPONICON 111
-#define CG_PLAYER_WALLCLIMBING 103
-#define CG_PLAYER_BOOSTED 104
-#define CG_PLAYER_POISON_BARBS 105
-#define CG_PLAYER_ALIEN_SENSE 108
-#define CG_PLAYER_HUMAN_SCANNER 109
-#define CG_PLAYER_USABLE_BUILDABLE 110
-#define CG_SELECTEDPLAYER_HEAD 7
-#define CG_SELECTEDPLAYER_NAME 8
-#define CG_SELECTEDPLAYER_LOCATION 9
-#define CG_SELECTEDPLAYER_STATUS 10
-#define CG_SELECTEDPLAYER_WEAPON 11
-#define CG_SELECTEDPLAYER_POWERUP 12
-
-#define CG_FLAGCARRIER_HEAD 13
-#define CG_FLAGCARRIER_NAME 14
-#define CG_FLAGCARRIER_LOCATION 15
-#define CG_FLAGCARRIER_STATUS 16
-#define CG_FLAGCARRIER_WEAPON 17
-#define CG_FLAGCARRIER_POWERUP 18
-
-#define CG_PLAYER_ITEM 19
-#define CG_PLAYER_SCORE 20
-
-#define CG_BLUE_FLAGHEAD 21
-#define CG_BLUE_FLAGSTATUS 22
-#define CG_BLUE_FLAGNAME 23
-#define CG_RED_FLAGHEAD 24
-#define CG_RED_FLAGSTATUS 25
-#define CG_RED_FLAGNAME 26
-
-#define CG_BLUE_SCORE 27
-#define CG_RED_SCORE 28
-#define CG_RED_NAME 29
-#define CG_BLUE_NAME 30
-#define CG_HARVESTER_SKULLS 31 // only shows in harvester
-#define CG_ONEFLAG_STATUS 32 // only shows in one flag
-#define CG_PLAYER_LOCATION 33
-#define CG_TEAM_COLOR 34
-#define CG_CTF_POWERUP 35
-
-#define CG_AREA_POWERUP 36
-#define CG_AREA_LAGOMETER 37 // painted with old system
-#define CG_PLAYER_HASFLAG 38
-#define CG_GAME_TYPE 39 // not done
-
-#define CG_SELECTEDPLAYER_ARMOR 40
-#define CG_SELECTEDPLAYER_HEALTH 41
-#define CG_PLAYER_STATUS 42
-#define CG_FRAGGED_MSG 43 // painted with old system
-#define CG_PROXMINED_MSG 44 // painted with old system
-#define CG_AREA_FPSINFO 45 // painted with old system
-#define CG_GAME_STATUS 49
-#define CG_KILLER 50
-#define CG_PLAYER_ARMOR_ICON2D 51
-#define CG_PLAYER_AMMO_ICON2D 52
-#define CG_ACCURACY 53
-#define CG_ASSISTS 54
-#define CG_DEFEND 55
-#define CG_EXCELLENT 56
-#define CG_IMPRESSIVE 57
-#define CG_PERFECT 58
-#define CG_GAUNTLET 59
-#define CG_SPECTATORS 60
-#define CG_TEAMINFO 61
-#define CG_VOICE_HEAD 62
-#define CG_VOICE_NAME 63
-#define CG_PLAYER_HASFLAG2D 64
-#define CG_HARVESTER_SKULLS2D 65 // only shows in harvester
-#define CG_CAPFRAGLIMIT 66
-#define CG_1STPLACE 67
-#define CG_2NDPLACE 68
-#define CG_CAPTURES 69
-
-//TA: loading screen
-#define CG_LOAD_LEVELSHOT 76
-#define CG_LOAD_MEDIA 77
-#define CG_LOAD_MEDIA_LABEL 78
-#define CG_LOAD_BUILDABLES 79
-#define CG_LOAD_BUILDABLES_LABEL 80
-#define CG_LOAD_CHARMODEL 81
-#define CG_LOAD_CHARMODEL_LABEL 82
-#define CG_LOAD_OVERALL 83
-#define CG_LOAD_LEVELNAME 84
-#define CG_LOAD_MOTD 85
-#define CG_LOAD_HOSTNAME 86
-
-#define CG_FPS 87
-#define CG_FPS_FIXED 100
-#define CG_TIMER 88
-#define CG_TIMER_MINS 101
-#define CG_TIMER_SECS 102
-#define CG_SNAPSHOT 89
-#define CG_LAGOMETER 90
-#define CG_PLAYER_CROSSHAIRNAMES 114
-#define CG_STAGE_REPORT_TEXT 116
-#define CG_DEMO_PLAYBACK 117
-#define CG_DEMO_RECORDING 118
-
-#define CG_CONSOLE 91
-#define CG_TUTORIAL 119
-#define CG_CLOCK 120
-
-
-
-#define UI_OWNERDRAW_BASE 200
-#define UI_HANDICAP 200
-#define UI_PLAYERMODEL 202
-#define UI_CLANNAME 203
-#define UI_CLANLOGO 204
-#define UI_GAMETYPE 205
-#define UI_MAPPREVIEW 206
-#define UI_SKILL 207
-#define UI_BLUETEAMNAME 208
-#define UI_REDTEAMNAME 209
-#define UI_BLUETEAM1 210
-#define UI_BLUETEAM2 211
-#define UI_BLUETEAM3 212
-#define UI_BLUETEAM4 213
-#define UI_BLUETEAM5 214
-#define UI_REDTEAM1 215
-#define UI_REDTEAM2 216
-#define UI_REDTEAM3 217
-#define UI_REDTEAM4 218
-#define UI_REDTEAM5 219
-#define UI_NETSOURCE 220
-#define UI_NETMAPPREVIEW 221
-#define UI_NETFILTER 222
-#define UI_TIER 223
-#define UI_OPPONENTMODEL 224
-#define UI_TIERMAP1 225
-#define UI_TIERMAP2 226
-#define UI_TIERMAP3 227
-#define UI_PLAYERLOGO 228
-#define UI_OPPONENTLOGO 229
-#define UI_PLAYERLOGO_METAL 230
-#define UI_OPPONENTLOGO_METAL 231
-#define UI_PLAYERLOGO_NAME 232
-#define UI_OPPONENTLOGO_NAME 233
-#define UI_TIER_MAPNAME 234
-#define UI_TIER_GAMETYPE 235
-#define UI_ALLMAPS_SELECTION 236
-#define UI_OPPONENT_NAME 237
-#define UI_VOTE_KICK 238
-#define UI_BOTNAME 239
-#define UI_BOTSKILL 240
-#define UI_REDBLUE 241
-#define UI_SELECTEDPLAYER 243
-#define UI_MAPCINEMATIC 244
-#define UI_NETGAMETYPE 245
-#define UI_NETMAPCINEMATIC 246
-#define UI_SERVERREFRESHDATE 247
-#define UI_SERVERMOTD 248
-#define UI_GLINFO 249
-#define UI_KEYBINDSTATUS 250
-#define UI_CLANCINEMATIC 251
-#define UI_MAP_TIMETOBEAT 252
-#define UI_JOINGAMETYPE 253
-#define UI_PREVIEWCINEMATIC 254
-#define UI_STARTMAPCINEMATIC 255
-#define UI_MAPS_SELECTION 256
-
-//TA:
-//#define UI_DIALOG 257
-#define UI_TEAMINFOPANE 258
-#define UI_ACLASSINFOPANE 259
-#define UI_AUPGRADEINFOPANE 260
-#define UI_HITEMINFOPANE 261
-#define UI_HBUYINFOPANE 262
-#define UI_HSELLINFOPANE 263
-#define UI_ABUILDINFOPANE 264
-#define UI_HBUILDINFOPANE 265
-
-#define UI_PLAYERLIST_SELECTION 266
-#define UI_TEAMLIST_SELECTION 267
-
-#define VOICECHAT_GETFLAG "getflag" // command someone to get the flag
-#define VOICECHAT_OFFENSE "offense" // command someone to go on offense
-#define VOICECHAT_DEFEND "defend" // command someone to go on defense
-#define VOICECHAT_DEFENDFLAG "defendflag" // command someone to defend the flag
-#define VOICECHAT_PATROL "patrol" // command someone to go on patrol (roam)
-#define VOICECHAT_CAMP "camp" // command someone to camp (we don't have sounds for this one)
-#define VOICECHAT_FOLLOWME "followme" // command someone to follow you
-#define VOICECHAT_RETURNFLAG "returnflag" // command someone to return our flag
-#define VOICECHAT_FOLLOWFLAGCARRIER "followflagcarrier" // command someone to follow the flag carrier
-#define VOICECHAT_YES "yes" // yes, affirmative, etc.
-#define VOICECHAT_NO "no" // no, negative, etc.
-#define VOICECHAT_ONGETFLAG "ongetflag" // I'm getting the flag
-#define VOICECHAT_ONOFFENSE "onoffense" // I'm on offense
-#define VOICECHAT_ONDEFENSE "ondefense" // I'm on defense
-#define VOICECHAT_ONPATROL "onpatrol" // I'm on patrol (roaming)
-#define VOICECHAT_ONCAMPING "oncamp" // I'm camping somewhere
-#define VOICECHAT_ONFOLLOW "onfollow" // I'm following
-#define VOICECHAT_ONFOLLOWCARRIER "onfollowcarrier" // I'm following the flag carrier
-#define VOICECHAT_ONRETURNFLAG "onreturnflag" // I'm returning our flag
-#define VOICECHAT_INPOSITION "inposition" // I'm in position
-#define VOICECHAT_IHAVEFLAG "ihaveflag" // I have the flag
-#define VOICECHAT_BASEATTACK "baseattack" // the base is under attack
-#define VOICECHAT_ENEMYHASFLAG "enemyhasflag" // the enemy has our flag (CTF)
-#define VOICECHAT_STARTLEADER "startleader" // I'm the leader
-#define VOICECHAT_STOPLEADER "stopleader" // I resign leadership
-#define VOICECHAT_TRASH "trash" // lots of trash talk
-#define VOICECHAT_WHOISLEADER "whoisleader" // who is the team leader
-#define VOICECHAT_WANTONDEFENSE "wantondefense" // I want to be on defense
-#define VOICECHAT_WANTONOFFENSE "wantonoffense" // I want to be on offense
diff --git a/src/ui/ui_atoms.c b/src/ui/ui_atoms.c
index a3033c4..b70d34d 100644
--- a/src/ui/ui_atoms.c
+++ b/src/ui/ui_atoms.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -28,43 +29,46 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
**********************************************************************/
#include "ui_local.h"
-qboolean m_entersound; // after a frame, so caching won't disrupt the sound
+qboolean m_entersound; // after a frame, so caching won't disrupt the sound
-void QDECL Com_Error( int level, const char *error, ... ) {
- va_list argptr;
- char text[1024];
+void QDECL Com_Error(int level, const char *error, ...)
+{
+ va_list argptr;
+ char text[1024];
- va_start (argptr, error);
- vsprintf (text, error, argptr);
- va_end (argptr);
+ va_start(argptr, error);
+ Q_vsnprintf(text, sizeof(text), error, argptr);
+ va_end(argptr);
- trap_Error( va("%s", text) );
+ trap_Error(text);
}
-void QDECL Com_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
+void QDECL Com_Printf(const char *msg, ...)
+{
+ va_list argptr;
+ char text[1024];
- va_start (argptr, msg);
- vsprintf (text, msg, argptr);
- va_end (argptr);
+ va_start(argptr, msg);
+ Q_vsnprintf(text, sizeof(text), msg, argptr);
+ va_end(argptr);
- trap_Print( va("%s", text) );
+ trap_Print(text);
}
-qboolean newUI = qfalse;
-
-
/*
=================
UI_ClampCvar
=================
*/
-float UI_ClampCvar( float min, float max, float value )
+float UI_ClampCvar(float min, float max, float value)
{
- if ( value < min ) return min;
- if ( value > max ) return max;
- return value;
+ if (value < min)
+ return min;
+
+ if (value > max)
+ return max;
+
+ return value;
}
/*
@@ -72,418 +76,196 @@ float UI_ClampCvar( float min, float max, float value )
UI_StartDemoLoop
=================
*/
-void UI_StartDemoLoop( void ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "d1\n" );
-}
+void UI_StartDemoLoop(void) { trap_Cmd_ExecuteText(EXEC_APPEND, "d1\n"); }
-char *UI_Argv( int arg ) {
- static char buffer[MAX_STRING_CHARS];
+char *UI_Argv(int arg)
+{
+ static char buffer[MAX_STRING_CHARS];
- trap_Argv( arg, buffer, sizeof( buffer ) );
+ trap_Argv(arg, buffer, sizeof(buffer));
- return buffer;
+ return buffer;
}
+char *UI_ConcatArgs(int arg, char *buf, int len)
+{
+ char *p;
+ int c;
-char *UI_Cvar_VariableString( const char *var_name ) {
- static char buffer[MAX_STRING_CHARS];
+ if (len <= 0)
+ return buf;
- trap_Cvar_VariableStringBuffer( var_name, buffer, sizeof( buffer ) );
+ p = buf;
+ c = trap_Argc();
- return buffer;
-}
+ for (; arg < c; arg++)
+ {
+ char *argp = UI_Argv(arg);
+ while (*argp && p < &buf[len - 1])
+ *p++ = *argp++;
+ if (p < &buf[len - 2])
+ *p++ = ' ';
+ else
+ break;
+ }
-void UI_SetBestScores(postGameInfo_t *newInfo, qboolean postGame) {
- trap_Cvar_Set("ui_scoreAccuracy", va("%i%%", newInfo->accuracy));
- trap_Cvar_Set("ui_scoreImpressives", va("%i", newInfo->impressives));
- trap_Cvar_Set("ui_scoreExcellents", va("%i", newInfo->excellents));
- trap_Cvar_Set("ui_scoreDefends", va("%i", newInfo->defends));
- trap_Cvar_Set("ui_scoreAssists", va("%i", newInfo->assists));
- trap_Cvar_Set("ui_scoreGauntlets", va("%i", newInfo->gauntlets));
- trap_Cvar_Set("ui_scoreScore", va("%i", newInfo->score));
- trap_Cvar_Set("ui_scorePerfect", va("%i", newInfo->perfects));
- trap_Cvar_Set("ui_scoreTeam", va("%i to %i", newInfo->redScore, newInfo->blueScore));
- trap_Cvar_Set("ui_scoreBase", va("%i", newInfo->baseScore));
- trap_Cvar_Set("ui_scoreTimeBonus", va("%i", newInfo->timeBonus));
- trap_Cvar_Set("ui_scoreSkillBonus", va("%i", newInfo->skillBonus));
- trap_Cvar_Set("ui_scoreShutoutBonus", va("%i", newInfo->shutoutBonus));
- trap_Cvar_Set("ui_scoreTime", va("%02i:%02i", newInfo->time / 60, newInfo->time % 60));
- trap_Cvar_Set("ui_scoreCaptures", va("%i", newInfo->captures));
- if (postGame) {
- trap_Cvar_Set("ui_scoreAccuracy2", va("%i%%", newInfo->accuracy));
- trap_Cvar_Set("ui_scoreImpressives2", va("%i", newInfo->impressives));
- trap_Cvar_Set("ui_scoreExcellents2", va("%i", newInfo->excellents));
- trap_Cvar_Set("ui_scoreDefends2", va("%i", newInfo->defends));
- trap_Cvar_Set("ui_scoreAssists2", va("%i", newInfo->assists));
- trap_Cvar_Set("ui_scoreGauntlets2", va("%i", newInfo->gauntlets));
- trap_Cvar_Set("ui_scoreScore2", va("%i", newInfo->score));
- trap_Cvar_Set("ui_scorePerfect2", va("%i", newInfo->perfects));
- trap_Cvar_Set("ui_scoreTeam2", va("%i to %i", newInfo->redScore, newInfo->blueScore));
- trap_Cvar_Set("ui_scoreBase2", va("%i", newInfo->baseScore));
- trap_Cvar_Set("ui_scoreTimeBonus2", va("%i", newInfo->timeBonus));
- trap_Cvar_Set("ui_scoreSkillBonus2", va("%i", newInfo->skillBonus));
- trap_Cvar_Set("ui_scoreShutoutBonus2", va("%i", newInfo->shutoutBonus));
- trap_Cvar_Set("ui_scoreTime2", va("%02i:%02i", newInfo->time / 60, newInfo->time % 60));
- trap_Cvar_Set("ui_scoreCaptures2", va("%i", newInfo->captures));
- }
-}
+ *p = '\0';
-void UI_LoadBestScores(const char *map, int game) {
- char fileName[MAX_QPATH];
- fileHandle_t f;
- postGameInfo_t newInfo;
- memset(&newInfo, 0, sizeof(postGameInfo_t));
- Com_sprintf(fileName, MAX_QPATH, "games/%s_%i.game", map, game);
- if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
- int size = 0;
- trap_FS_Read(&size, sizeof(int), f);
- if (size == sizeof(postGameInfo_t)) {
- trap_FS_Read(&newInfo, sizeof(postGameInfo_t), f);
- }
- trap_FS_FCloseFile(f);
- }
- UI_SetBestScores(&newInfo, qfalse);
-
- Com_sprintf(fileName, MAX_QPATH, "demos/%s_%d.dm_%d", map, game, (int)trap_Cvar_VariableValue("protocol"));
- uiInfo.demoAvailable = qfalse;
- if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
- uiInfo.demoAvailable = qtrue;
- trap_FS_FCloseFile(f);
- }
+ return buf;
}
-/*
-===============
-UI_ClearScores
-===============
-*/
-void UI_ClearScores( void ) {
- char gameList[4096];
- char *gameFile;
- int i, len, count, size;
- fileHandle_t f;
- postGameInfo_t newInfo;
-
- count = trap_FS_GetFileList( "games", "game", gameList, sizeof(gameList) );
-
- size = sizeof(postGameInfo_t);
- memset(&newInfo, 0, size);
-
- if (count > 0) {
- gameFile = gameList;
- for ( i = 0; i < count; i++ ) {
- len = strlen(gameFile);
- if (trap_FS_FOpenFile(va("games/%s",gameFile), &f, FS_WRITE) >= 0) {
- trap_FS_Write(&size, sizeof(int), f);
- trap_FS_Write(&newInfo, size, f);
- trap_FS_FCloseFile(f);
- }
- gameFile += len + 1;
- }
- }
+char *UI_Cvar_VariableString(const char *var_name)
+{
+ static char buffer[MAX_STRING_CHARS];
- UI_SetBestScores(&newInfo, qfalse);
+ trap_Cvar_VariableStringBuffer(var_name, buffer, sizeof(buffer));
+ return buffer;
}
+static void UI_Cache_f(void) { Display_CacheAll(); }
-
-static void UI_Cache_f( void ) {
- Display_CacheAll();
+static void UI_Menu_f(void)
+{
+ if (Menu_Count() > 0)
+ {
+ trap_Key_SetCatcher(KEYCATCH_UI);
+ Menus_ActivateByName(UI_Argv(1));
+ }
}
-/*
-=======================
-UI_CalcPostGameStats
-=======================
-*/
-static void UI_CalcPostGameStats( void ) {
- char map[MAX_QPATH];
- char fileName[MAX_QPATH];
- char info[MAX_INFO_STRING];
- fileHandle_t f;
- int size, game, time, adjustedTime;
- postGameInfo_t oldInfo;
- postGameInfo_t newInfo;
- qboolean newHigh = qfalse;
-
- trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
- Q_strncpyz( map, Info_ValueForKey( info, "mapname" ), sizeof(map) );
- game = atoi(Info_ValueForKey(info, "g_gametype"));
-
- // compose file name
- Com_sprintf(fileName, MAX_QPATH, "games/%s_%i.game", map, game);
- // see if we have one already
- memset(&oldInfo, 0, sizeof(postGameInfo_t));
- if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
- // if so load it
- size = 0;
- trap_FS_Read(&size, sizeof(int), f);
- if (size == sizeof(postGameInfo_t)) {
- trap_FS_Read(&oldInfo, sizeof(postGameInfo_t), f);
- }
- trap_FS_FCloseFile(f);
- }
-
- newInfo.accuracy = atoi(UI_Argv(3));
- newInfo.impressives = atoi(UI_Argv(4));
- newInfo.excellents = atoi(UI_Argv(5));
- newInfo.defends = atoi(UI_Argv(6));
- newInfo.assists = atoi(UI_Argv(7));
- newInfo.gauntlets = atoi(UI_Argv(8));
- newInfo.baseScore = atoi(UI_Argv(9));
- newInfo.perfects = atoi(UI_Argv(10));
- newInfo.redScore = atoi(UI_Argv(11));
- newInfo.blueScore = atoi(UI_Argv(12));
- time = atoi(UI_Argv(13));
- newInfo.captures = atoi(UI_Argv(14));
-
- newInfo.time = (time - trap_Cvar_VariableValue("ui_matchStartTime")) / 1000;
- adjustedTime = uiInfo.mapList[ui_currentMap.integer].timeToBeat[game];
- if (newInfo.time < adjustedTime) {
- newInfo.timeBonus = (adjustedTime - newInfo.time) * 10;
- } else {
- newInfo.timeBonus = 0;
- }
-
- if (newInfo.redScore > newInfo.blueScore && newInfo.blueScore <= 0) {
- newInfo.shutoutBonus = 100;
- } else {
- newInfo.shutoutBonus = 0;
- }
-
- newInfo.skillBonus = trap_Cvar_VariableValue("g_spSkill");
- if (newInfo.skillBonus <= 0) {
- newInfo.skillBonus = 1;
- }
- newInfo.score = newInfo.baseScore + newInfo.shutoutBonus + newInfo.timeBonus;
- newInfo.score *= newInfo.skillBonus;
-
- // see if the score is higher for this one
- newHigh = (newInfo.redScore > newInfo.blueScore && newInfo.score > oldInfo.score);
-
- if (newHigh) {
- // if so write out the new one
- uiInfo.newHighScoreTime = uiInfo.uiDC.realTime + 20000;
- if (trap_FS_FOpenFile(fileName, &f, FS_WRITE) >= 0) {
- size = sizeof(postGameInfo_t);
- trap_FS_Write(&size, sizeof(int), f);
- trap_FS_Write(&newInfo, sizeof(postGameInfo_t), f);
- trap_FS_FCloseFile(f);
+static void UI_CloseMenus_f(void)
+{
+ if (Menu_Count() > 0)
+ {
+ trap_Key_SetCatcher(trap_Key_GetCatcher() & ~KEYCATCH_UI);
+ trap_Key_ClearStates();
+ trap_Cvar_Set("cl_paused", "0");
+ Menus_CloseAll();
}
- }
+}
- if (newInfo.time < oldInfo.time) {
- uiInfo.newBestTime = uiInfo.uiDC.realTime + 20000;
- }
+static void UI_MessageMode_f(void)
+{
+ char *arg = UI_Argv(0);
- // put back all the ui overrides
- trap_Cvar_Set("capturelimit", UI_Cvar_VariableString("ui_saveCaptureLimit"));
- trap_Cvar_Set("fraglimit", UI_Cvar_VariableString("ui_saveFragLimit"));
- trap_Cvar_Set("cg_drawTimer", UI_Cvar_VariableString("ui_drawTimer"));
- trap_Cvar_Set("g_doWarmup", UI_Cvar_VariableString("ui_doWarmup"));
- trap_Cvar_Set("g_Warmup", UI_Cvar_VariableString("ui_Warmup"));
- trap_Cvar_Set("sv_pure", UI_Cvar_VariableString("ui_pure"));
- trap_Cvar_Set("g_friendlyFire", UI_Cvar_VariableString("ui_friendlyFire"));
+ trap_Cvar_Set("ui_sayBuffer", "");
- UI_SetBestScores(&newInfo, qtrue);
- UI_ShowPostGame(newHigh);
+ switch (arg[11])
+ {
+ default:
+ case '\0':
+ // Global
+ uiInfo.chatTeam = qfalse;
+ break;
+
+ case '2':
+ // Team
+ uiInfo.chatTeam = qtrue;
+ break;
+ }
+ trap_Key_SetCatcher(KEYCATCH_UI);
+ Menus_CloseByName("say");
+ Menus_CloseByName("say_team");
+ if (uiInfo.chatTeam)
+ Menus_ActivateByName("say_team");
+ else
+ Menus_ActivateByName("say");
}
-static void UI_MessageMode_f( void )
+static void UI_Me_f(void)
{
- char *arg = UI_Argv( 0 );
-
- trap_Cvar_Set( "ui_sayBuffer", "" );
-
- switch( arg[ 11 ] )
- {
- default:
- case '\0':
- // Global
- uiInfo.chatTeam = qfalse;
- break;
-
- case '2':
- // Team
- uiInfo.chatTeam = qtrue;
- break;
- }
-
- trap_Key_SetCatcher( KEYCATCH_UI );
- Menus_CloseByName( "say" );
- Menus_CloseByName( "say_team" );
-
- if( uiInfo.chatTeam )
- Menus_ActivateByName( "say_team" );
- else
- Menus_ActivateByName( "say" );
+ char buf[MAX_SAY_TEXT - 4];
+
+ UI_ConcatArgs(1, buf, sizeof(buf));
+
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("say \"/me %s\"\n", buf));
}
+struct uicmd {
+ char *cmd;
+ void (*function)(void);
+} commands[] =
+{
+ {"closemenus", UI_CloseMenus_f},
+ {"me", UI_Me_f},
+ {"menu", UI_Menu_f},
+ {"messagemode", UI_MessageMode_f},
+ {"messagemode2", UI_MessageMode_f},
+ {"ui_cache", UI_Cache_f},
+ {"ui_load", UI_Load},
+ {"ui_report", UI_Report}
+};
/*
=================
UI_ConsoleCommand
=================
*/
-qboolean UI_ConsoleCommand( int realTime )
+qboolean UI_ConsoleCommand(int realTime)
{
- char *cmd;
- char *arg1;
-
- uiInfo.uiDC.frameTime = realTime - uiInfo.uiDC.realTime;
- uiInfo.uiDC.realTime = realTime;
-
- cmd = UI_Argv( 0 );
-
- // ensure minimum menu data is available
- //Menu_Cache();
-
- if ( Q_stricmp (cmd, "ui_test") == 0 ) {
- UI_ShowPostGame(qtrue);
- }
-
- if ( Q_stricmp (cmd, "ui_report") == 0 ) {
- UI_Report();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_load") == 0 ) {
- UI_Load();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "remapShader") == 0 ) {
- if (trap_Argc() == 4) {
- char shader1[MAX_QPATH];
- char shader2[MAX_QPATH];
- Q_strncpyz(shader1, UI_Argv(1), sizeof(shader1));
- Q_strncpyz(shader2, UI_Argv(2), sizeof(shader2));
- trap_R_RemapShader(shader1, shader2, UI_Argv(3));
- return qtrue;
- }
- }
-
- if ( Q_stricmp (cmd, "postgame") == 0 ) {
- UI_CalcPostGameStats();
- return qtrue;
- }
+ struct uicmd *cmd = bsearch(UI_Argv(0), commands, ARRAY_LEN(commands), sizeof(commands[0]), cmdcmp);
- if ( Q_stricmp (cmd, "ui_cache") == 0 ) {
- UI_Cache_f();
- return qtrue;
- }
+ uiInfo.uiDC.frameTime = realTime - uiInfo.uiDC.realTime;
+ uiInfo.uiDC.realTime = realTime;
- if ( Q_stricmp (cmd, "ui_teamOrders") == 0 ) {
- //UI_TeamOrdersMenu_f();
- return qtrue;
- }
-
- if( Q_stricmp ( cmd, "menu" ) == 0 )
- {
- arg1 = UI_Argv( 1 );
-
- if( Menu_Count( ) > 0 )
+ if (cmd)
{
- trap_Key_SetCatcher( KEYCATCH_UI );
- Menus_ActivateByName( arg1 );
- return qtrue;
+ cmd->function();
+ return qtrue;
}
- }
-
- if( Q_stricmp ( cmd, "closemenus" ) == 0 )
- {
- if( Menu_Count( ) > 0 )
- {
- trap_Key_SetCatcher( trap_Key_GetCatcher( ) & ~KEYCATCH_UI );
- trap_Key_ClearStates( );
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll( );
- return qtrue;
- }
- }
-
- if( Q_stricmp ( cmd, "messagemode" ) == 0 ||
- Q_stricmp ( cmd, "messagemode2" ) == 0 )
- {
- UI_MessageMode_f();
- return qtrue;
- }
-
- return qfalse;
-}
-/*
-=================
-UI_Shutdown
-=================
-*/
-void UI_Shutdown( void ) {
+ return qfalse;
}
-/*
-================
-UI_AdjustFrom640
-
-Adjusted for resolution and screen aspect ratio
-================
-*/
-void UI_AdjustFrom640( float *x, float *y, float *w, float *h ) {
- // expect valid pointers
-#if 0
- *x = *x * uiInfo.uiDC.scale + uiInfo.uiDC.bias;
- *y *= uiInfo.uiDC.scale;
- *w *= uiInfo.uiDC.scale;
- *h *= uiInfo.uiDC.scale;
-#endif
-
- *x *= uiInfo.uiDC.xscale;
- *y *= uiInfo.uiDC.yscale;
- *w *= uiInfo.uiDC.xscale;
- *h *= uiInfo.uiDC.yscale;
+void UI_DrawNamedPic(float x, float y, float width, float height, const char *picname)
+{
+ qhandle_t hShader;
+ hShader = trap_R_RegisterShaderNoMip(picname);
+ UI_AdjustFrom640(&x, &y, &width, &height);
+ trap_R_DrawStretchPic(x, y, width, height, 0, 0, 1, 1, hShader);
}
-void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
- qhandle_t hShader;
+void UI_DrawHandlePic(float x, float y, float w, float h, qhandle_t hShader)
+{
+ float s0;
+ float s1;
+ float t0;
+ float t1;
+
+ if (w < 0)
+ {
+ // flip about vertical
+ w = -w;
+ s0 = 1;
+ s1 = 0;
+ }
+ else
+ {
+ s0 = 0;
+ s1 = 1;
+ }
- hShader = trap_R_RegisterShaderNoMip( picname );
- UI_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
-}
+ if (h < 0)
+ {
+ // flip about horizontal
+ h = -h;
+ t0 = 1;
+ t1 = 0;
+ }
+ else
+ {
+ t0 = 0;
+ t1 = 1;
+ }
-void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ) {
- float s0;
- float s1;
- float t0;
- float t1;
-
- if( w < 0 ) { // flip about vertical
- w = -w;
- s0 = 1;
- s1 = 0;
- }
- else {
- s0 = 0;
- s1 = 1;
- }
-
- if( h < 0 ) { // flip about horizontal
- h = -h;
- t0 = 1;
- t1 = 0;
- }
- else {
- t0 = 0;
- t1 = 1;
- }
-
- UI_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, h, s0, t0, s1, t1, hShader );
+ UI_AdjustFrom640(&x, &y, &w, &h);
+ trap_R_DrawStretchPic(x, y, w, h, s0, t0, s1, t1, hShader);
}
/*
@@ -493,64 +275,14 @@ UI_FillRect
Coordinates are 640*480 virtual values
=================
*/
-void UI_FillRect( float x, float y, float width, float height, const float *color ) {
- trap_R_SetColor( color );
-
- UI_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
-
- trap_R_SetColor( NULL );
-}
-
-void UI_DrawSides(float x, float y, float w, float h) {
- UI_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, 1, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
- trap_R_DrawStretchPic( x + w - 1, y, 1, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
-}
-
-void UI_DrawTopBottom(float x, float y, float w, float h) {
- UI_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, 1, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
- trap_R_DrawStretchPic( x, y + h - 1, w, 1, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
-}
-/*
-================
-UI_DrawRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void UI_DrawRect( float x, float y, float width, float height, const float *color ) {
- trap_R_SetColor( color );
-
- UI_DrawTopBottom(x, y, width, height);
- UI_DrawSides(x, y, width, height);
-
- trap_R_SetColor( NULL );
-}
-
-void UI_SetColor( const float *rgba ) {
- trap_R_SetColor( rgba );
-}
-
-void UI_UpdateScreen( void ) {
- trap_UpdateScreen();
-}
-
-
-void UI_DrawTextBox (int x, int y, int width, int lines)
+void UI_FillRect(float x, float y, float width, float height, const float *color)
{
- UI_FillRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorBlack );
- UI_DrawRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorWhite );
-}
+ trap_R_SetColor(color);
-qboolean UI_CursorInRect (int x, int y, int width, int height)
-{
- if (uiInfo.uiDC.cursorx < x ||
- uiInfo.uiDC.cursory < y ||
- uiInfo.uiDC.cursorx > x+width ||
- uiInfo.uiDC.cursory > y+height)
- return qfalse;
+ UI_AdjustFrom640(&x, &y, &width, &height);
+ trap_R_DrawStretchPic(x, y, width, height, 0, 0, 0, 0, uiInfo.uiDC.whiteShader);
- return qtrue;
+ trap_R_SetColor(NULL);
}
+
+void UI_SetColor(const float *rgba) { trap_R_SetColor(rgba); }
diff --git a/src/ui/ui_gameinfo.c b/src/ui/ui_gameinfo.c
index 43639e5..92c8a7b 100644
--- a/src/ui/ui_gameinfo.c
+++ b/src/ui/ui_gameinfo.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -27,72 +28,85 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "ui_local.h"
-
//
// arena and bot info
//
+int ui_numBots;
+static char *ui_botInfos[MAX_BOTS];
-int ui_numBots;
-static char *ui_botInfos[MAX_BOTS];
-
-static int ui_numArenas;
-static char *ui_arenaInfos[MAX_ARENAS];
+static int ui_numArenas;
+static char *ui_arenaInfos[MAX_ARENAS];
/*
===============
UI_ParseInfos
===============
*/
-int UI_ParseInfos( char *buf, int max, char *infos[] ) {
- char *token;
- int count;
- char key[MAX_TOKEN_CHARS];
- char info[MAX_INFO_STRING];
-
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &buf );
- if ( !token[0] ) {
- break;
- }
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in info file\n" );
- break;
- }
+int UI_ParseInfos(char *buf, int max, char *infos[])
+{
+ char *token;
+ int count;
+ char key[MAX_TOKEN_CHARS];
+ char info[MAX_INFO_STRING];
- if ( count == max ) {
- Com_Printf( "Max infos exceeded\n" );
- break;
- }
+ count = 0;
- info[0] = '\0';
- while ( 1 ) {
- token = COM_ParseExt( &buf, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &buf, qfalse );
- if ( !token[0] ) {
- strcpy( token, "<NULL>" );
- }
- Info_SetValueForKey( info, key, token );
- }
- //NOTE: extra space for arena number
- infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
- if (infos[count]) {
- strcpy(infos[count], info);
- count++;
+ while (1)
+ {
+ token = COM_Parse(&buf);
+
+ if (!token[0])
+ break;
+
+ if (strcmp(token, "{"))
+ {
+ Com_Printf("Missing { in info file\n");
+ break;
+ }
+
+ if (count == max)
+ {
+ Com_Printf("Max infos exceeded\n");
+ break;
+ }
+
+ info[0] = '\0';
+
+ while (1)
+ {
+ token = COM_ParseExt(&buf, qtrue);
+
+ if (!token[0])
+ {
+ Com_Printf("Unexpected end of info file\n");
+ break;
+ }
+
+ if (!strcmp(token, "}"))
+ break;
+
+ Q_strncpyz(key, token, sizeof(key));
+
+ token = COM_ParseExt(&buf, qfalse);
+
+ if (!token[0])
+ strcpy(token, "<NULL>");
+
+ Info_SetValueForKey(info, key, token);
+ }
+
+ // NOTE: extra space for arena number
+ infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
+
+ if (infos[count])
+ {
+ strcpy(infos[count], info);
+ count++;
+ }
}
- }
- return count;
+
+ return count;
}
/*
@@ -100,27 +114,32 @@ int UI_ParseInfos( char *buf, int max, char *infos[] ) {
UI_LoadArenasFromFile
===============
*/
-static void UI_LoadArenasFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_ARENAS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_ARENAS_TEXT ) {
- trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
+static void UI_LoadArenasFromFile(char *filename)
+{
+ int len;
+ fileHandle_t f;
+ char buf[MAX_ARENAS_TEXT];
+
+ len = trap_FS_FOpenFile(filename, &f, FS_READ);
+
+ if (!f)
+ {
+ trap_Print(va(S_COLOR_RED "file not found: %s\n", filename));
+ return;
+ }
+
+ if (len >= MAX_ARENAS_TEXT)
+ {
+ trap_Print(va(S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT));
+ trap_FS_FCloseFile(f);
+ return;
+ }
+
+ trap_FS_Read(buf, len, f);
+ buf[len] = 0;
+ trap_FS_FCloseFile(f);
+
+ ui_numArenas += UI_ParseInfos(buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas]);
}
/*
@@ -128,12 +147,12 @@ static void UI_LoadArenasFromFile( char *filename ) {
UI_MapNameCompare
=================
*/
-static int UI_MapNameCompare( const void *a, const void *b )
+static int UI_MapNameCompare(const void *a, const void *b)
{
- mapInfo *A = (mapInfo *)a;
- mapInfo *B = (mapInfo *)b;
+ mapInfo *A = (mapInfo *)a;
+ mapInfo *B = (mapInfo *)b;
- return Q_stricmp( A->mapName, B->mapName );
+ return Q_stricmp(A->mapName, B->mapName);
}
/*
@@ -141,86 +160,86 @@ static int UI_MapNameCompare( const void *a, const void *b )
UI_LoadArenas
===============
*/
-void UI_LoadArenas( void ) {
- int numdirs;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i, n;
- int dirlen;
- char *type;
-
- ui_numArenas = 0;
- uiInfo.mapCount = 0;
-
- // get all arenas from .arena files
- numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- UI_LoadArenasFromFile(filename);
- }
- trap_Print( va( "[skipnotify]%i arenas parsed\n", ui_numArenas ) );
- if (UI_OutOfMemory()) {
- trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all arenas\n");
- }
-
- for( n = 0; n < ui_numArenas; n++ )
- {
- // determine type
- type = Info_ValueForKey( ui_arenaInfos[ n ], "type" );
- // if no type specified, it will be treated as "ffa"
-
- if( *type && strstr( type, "tremulous" ) )
- uiInfo.mapList[ uiInfo.mapCount ].typeBits |= ( 1 << 0 );
- else
- continue; //not a trem map
+void UI_LoadArenas(void)
+{
+ int numdirs;
+ char filename[128];
+ char dirlist[1024];
+ char *dirptr;
+ int i, n;
+ int dirlen;
+
+ ui_numArenas = 0;
+ uiInfo.mapCount = 0;
+
+ // get all arenas from .arena files
+ numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024);
+ dirptr = dirlist;
+
+ for (i = 0; i < numdirs; i++, dirptr += dirlen + 1)
+ {
+ dirlen = strlen(dirptr);
+ strcpy(filename, "scripts/");
+ strcat(filename, dirptr);
+ UI_LoadArenasFromFile(filename);
+ }
- uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
- uiInfo.mapList[uiInfo.mapCount].mapLoadName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "map"));
- uiInfo.mapList[uiInfo.mapCount].mapName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "longname"));
- uiInfo.mapList[uiInfo.mapCount].levelShot = -1;
- uiInfo.mapList[uiInfo.mapCount].imageName = String_Alloc(va("levelshots/%s", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
+ trap_Print(va("[skipnotify]%i arenas parsed\n", ui_numArenas));
- uiInfo.mapCount++;
- if( uiInfo.mapCount >= MAX_MAPS )
- break;
- }
+ if (UI_OutOfMemory())
+ trap_Print(S_COLOR_YELLOW "WARNING: not anough memory in pool to load all arenas\n");
- qsort( uiInfo.mapList, uiInfo.mapCount, sizeof( mapInfo ), UI_MapNameCompare );
-}
+ for (n = 0; n < ui_numArenas; n++)
+ {
+ uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
+ uiInfo.mapList[uiInfo.mapCount].mapLoadName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "map"));
+ uiInfo.mapList[uiInfo.mapCount].mapName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "longname"));
+ uiInfo.mapList[uiInfo.mapCount].levelShot = -1;
+ uiInfo.mapList[uiInfo.mapCount].imageName =
+ String_Alloc(va("levelshots/%s", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
+
+ uiInfo.mapCount++;
+ if (uiInfo.mapCount >= MAX_MAPS)
+ break;
+ }
+
+ qsort(uiInfo.mapList, uiInfo.mapCount, sizeof(mapInfo), UI_MapNameCompare);
+}
/*
===============
UI_LoadBotsFromFile
===============
*/
-static void UI_LoadBotsFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_BOTS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_BOTS_TEXT ) {
- trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- COM_Compress(buf);
-
- ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
+static void UI_LoadBotsFromFile(char *filename)
+{
+ int len;
+ fileHandle_t f;
+ char buf[MAX_BOTS_TEXT];
+
+ len = trap_FS_FOpenFile(filename, &f, FS_READ);
+
+ if (!f)
+ {
+ trap_Print(va(S_COLOR_RED "file not found: %s\n", filename));
+ return;
+ }
+
+ if (len >= MAX_BOTS_TEXT)
+ {
+ trap_Print(va(S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT));
+ trap_FS_FCloseFile(f);
+ return;
+ }
+
+ trap_FS_Read(buf, len, f);
+ buf[len] = 0;
+ trap_FS_FCloseFile(f);
+
+ COM_Compress(buf);
+
+ ui_numBots += UI_ParseInfos(buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots]);
}
/*
@@ -228,106 +247,109 @@ static void UI_LoadBotsFromFile( char *filename ) {
UI_LoadBots
===============
*/
-void UI_LoadBots( void ) {
- vmCvar_t botsFile;
- int numdirs;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i;
- int dirlen;
-
- ui_numBots = 0;
-
- trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
- if( *botsFile.string ) {
- UI_LoadBotsFromFile(botsFile.string);
- }
- else {
- UI_LoadBotsFromFile("scripts/bots.txt");
- }
-
- // get all bots from .bot files
- numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- UI_LoadBotsFromFile(filename);
- }
- trap_Print( va( "%i bots parsed\n", ui_numBots ) );
-}
+void UI_LoadBots(void)
+{
+ vmCvar_t botsFile;
+ int numdirs;
+ char filename[128];
+ char dirlist[1024];
+ char *dirptr;
+ int i;
+ int dirlen;
+
+ ui_numBots = 0;
+ trap_Cvar_Register(&botsFile, "g_botsFile", "", CVAR_INIT | CVAR_ROM);
+
+ if (*botsFile.string)
+ UI_LoadBotsFromFile(botsFile.string);
+ else
+ UI_LoadBotsFromFile("scripts/bots.txt");
+
+ // get all bots from .bot files
+ numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024);
+
+ dirptr = dirlist;
+
+ for (i = 0; i < numdirs; i++, dirptr += dirlen + 1)
+ {
+ dirlen = strlen(dirptr);
+ strcpy(filename, "scripts/");
+ strcat(filename, dirptr);
+ UI_LoadBotsFromFile(filename);
+ }
+
+ trap_Print(va("%i bots parsed\n", ui_numBots));
+}
/*
===============
UI_GetBotInfoByNumber
===============
*/
-char *UI_GetBotInfoByNumber( int num ) {
- if( num < 0 || num >= ui_numBots ) {
- trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
- return NULL;
- }
- return ui_botInfos[num];
-}
+char *UI_GetBotInfoByNumber(int num)
+{
+ if (num < 0 || num >= ui_numBots)
+ {
+ trap_Print(va(S_COLOR_RED "Invalid bot number: %i\n", num));
+ return NULL;
+ }
+ return ui_botInfos[num];
+}
/*
===============
UI_GetBotInfoByName
===============
*/
-char *UI_GetBotInfoByName( const char *name ) {
- int n;
- char *value;
-
- for ( n = 0; n < ui_numBots ; n++ ) {
- value = Info_ValueForKey( ui_botInfos[n], "name" );
- if ( !Q_stricmp( value, name ) ) {
- return ui_botInfos[n];
+char *UI_GetBotInfoByName(const char *name)
+{
+ int n;
+ char *value;
+
+ for (n = 0; n < ui_numBots; n++)
+ {
+ value = Info_ValueForKey(ui_botInfos[n], "name");
+
+ if (!Q_stricmp(value, name))
+ return ui_botInfos[n];
}
- }
- return NULL;
+ return NULL;
}
-int UI_GetNumBots() {
- return ui_numBots;
-}
+int UI_GetNumBots(void) { return ui_numBots; }
+
+char *UI_GetBotNameByNumber(int num)
+{
+ char *info = UI_GetBotInfoByNumber(num);
+ if (info)
+ return Info_ValueForKey(info, "name");
-char *UI_GetBotNameByNumber( int num ) {
- char *info = UI_GetBotInfoByNumber(num);
- if (info) {
- return Info_ValueForKey( info, "name" );
- }
- return "Sarge";
+ return "";
}
-void UI_ServerInfo( void )
+void UI_ServerInfo(void)
{
- char info[ MAX_INFO_VALUE ];
-
- info[0] = '\0';
- if( trap_GetConfigString( CS_SERVERINFO, info, sizeof( info ) ) )
- {
- trap_Cvar_Set( "ui_serverinfo_mapname",
- Info_ValueForKey( info, "mapname" ) );
- trap_Cvar_Set( "ui_serverinfo_timelimit",
- Info_ValueForKey( info, "timelimit" ) );
- trap_Cvar_Set( "ui_serverinfo_sd",
- Info_ValueForKey( info, "g_suddenDeathTime" ) );
- trap_Cvar_Set( "ui_serverinfo_hostname",
- Info_ValueForKey( info, "sv_hostname" ) );
- trap_Cvar_Set( "ui_serverinfo_maxclients",
- Info_ValueForKey( info, "sv_maxclients" ) );
- trap_Cvar_Set( "ui_serverinfo_version",
- Info_ValueForKey( info, "version" ) );
- trap_Cvar_Set( "ui_serverinfo_unlagged",
- Info_ValueForKey( info, "g_unlagged" ) );
- trap_Cvar_Set( "ui_serverinfo_ff",
- Info_ValueForKey( info, "ff" ) );
- }
+ char info[MAX_INFO_VALUE];
+ char hostname[MAX_HOSTNAME_LENGTH];
+
+ info[0] = '\0';
+
+ if (trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)))
+ {
+ trap_Cvar_Set("ui_serverinfo_mapname", Info_ValueForKey(info, "mapname"));
+ trap_Cvar_Set("ui_serverinfo_timelimit", Info_ValueForKey(info, "timelimit"));
+ trap_Cvar_Set("ui_serverinfo_sd", Info_ValueForKey(info, "g_suddenDeathTime"));
+ UI_EscapeEmoticons(hostname, Info_ValueForKey(info, "sv_hostname"), sizeof(hostname));
+ trap_Cvar_Set("ui_serverinfo_hostname", hostname);
+ trap_Cvar_Set("ui_serverinfo_maxclients", Info_ValueForKey(info, "sv_maxclients"));
+ trap_Cvar_Set("ui_serverinfo_version", Info_ValueForKey(info, "version"));
+ trap_Cvar_Set("ui_serverinfo_unlagged", Info_ValueForKey(info, "g_unlagged"));
+ trap_Cvar_Set("ui_serverinfo_friendlyFire", Info_ValueForKey(info, "g_friendlyFire"));
+ trap_Cvar_Set("ui_serverinfo_friendlyBuildableFire", Info_ValueForKey(info, "g_friendlyBuildableFire"));
+ trap_Cvar_Set("ui_serverinfo_allowdl", Info_ValueForKey(info, "sv_allowdownload"));
+ }
}
diff --git a/src/ui/ui_local.h b/src/ui/ui_local.h
index 0066593..936c414 100644
--- a/src/ui/ui_local.h
+++ b/src/ui/ui_local.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,1195 +17,381 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
-#ifndef __UI_LOCAL_H__
-#define __UI_LOCAL_H__
+#ifndef UI_LOCAL_H
+#define UI_LOCAL_H
-#include "../qcommon/q_shared.h"
-#include "../renderer/tr_types.h"
+#include "client/keycodes.h"
+#include "game/bg_public.h"
+#include "qcommon/q_shared.h"
+#include "renderercommon/tr_types.h"
#include "ui_public.h"
-#include "../client/keycodes.h"
-#include "../game/bg_public.h"
#include "ui_shared.h"
-// global display context
-
-extern vmCvar_t ui_ffa_fraglimit;
-extern vmCvar_t ui_ffa_timelimit;
-
-extern vmCvar_t ui_tourney_fraglimit;
-extern vmCvar_t ui_tourney_timelimit;
-
-extern vmCvar_t ui_team_fraglimit;
-extern vmCvar_t ui_team_timelimit;
-extern vmCvar_t ui_team_friendly;
-
-extern vmCvar_t ui_ctf_capturelimit;
-extern vmCvar_t ui_ctf_timelimit;
-extern vmCvar_t ui_ctf_friendly;
-
-extern vmCvar_t ui_arenasFile;
-extern vmCvar_t ui_botsFile;
-extern vmCvar_t ui_spScores1;
-extern vmCvar_t ui_spScores2;
-extern vmCvar_t ui_spScores3;
-extern vmCvar_t ui_spScores4;
-extern vmCvar_t ui_spScores5;
-extern vmCvar_t ui_spAwards;
-extern vmCvar_t ui_spVideos;
-extern vmCvar_t ui_spSkill;
-
-extern vmCvar_t ui_spSelection;
-
-extern vmCvar_t ui_browserMaster;
-extern vmCvar_t ui_browserGameType;
-extern vmCvar_t ui_browserSortKey;
-extern vmCvar_t ui_browserShowFull;
-extern vmCvar_t ui_browserShowEmpty;
-
-extern vmCvar_t ui_brassTime;
-extern vmCvar_t ui_drawCrosshair;
-extern vmCvar_t ui_drawCrosshairNames;
-extern vmCvar_t ui_marks;
-
-extern vmCvar_t ui_server1;
-extern vmCvar_t ui_server2;
-extern vmCvar_t ui_server3;
-extern vmCvar_t ui_server4;
-extern vmCvar_t ui_server5;
-extern vmCvar_t ui_server6;
-extern vmCvar_t ui_server7;
-extern vmCvar_t ui_server8;
-extern vmCvar_t ui_server9;
-extern vmCvar_t ui_server10;
-extern vmCvar_t ui_server11;
-extern vmCvar_t ui_server12;
-extern vmCvar_t ui_server13;
-extern vmCvar_t ui_server14;
-extern vmCvar_t ui_server15;
-extern vmCvar_t ui_server16;
-
-extern vmCvar_t ui_captureLimit;
-extern vmCvar_t ui_fragLimit;
-extern vmCvar_t ui_gameType;
-extern vmCvar_t ui_netGameType;
-extern vmCvar_t ui_actualNetGameType;
-extern vmCvar_t ui_joinGameType;
-extern vmCvar_t ui_netSource;
-extern vmCvar_t ui_serverFilterType;
-extern vmCvar_t ui_dedicated;
-extern vmCvar_t ui_opponentName;
-extern vmCvar_t ui_menuFiles;
-extern vmCvar_t ui_currentTier;
-extern vmCvar_t ui_currentMap;
-extern vmCvar_t ui_currentNetMap;
-extern vmCvar_t ui_mapIndex;
-extern vmCvar_t ui_currentOpponent;
-extern vmCvar_t ui_selectedPlayer;
-extern vmCvar_t ui_selectedPlayerName;
-extern vmCvar_t ui_lastServerRefresh_0;
-extern vmCvar_t ui_lastServerRefresh_1;
-extern vmCvar_t ui_lastServerRefresh_2;
-extern vmCvar_t ui_lastServerRefresh_3;
-extern vmCvar_t ui_singlePlayerActive;
-extern vmCvar_t ui_scoreAccuracy;
-extern vmCvar_t ui_scoreImpressives;
-extern vmCvar_t ui_scoreExcellents;
-extern vmCvar_t ui_scoreDefends;
-extern vmCvar_t ui_scoreAssists;
-extern vmCvar_t ui_scoreGauntlets;
-extern vmCvar_t ui_scoreScore;
-extern vmCvar_t ui_scorePerfect;
-extern vmCvar_t ui_scoreTeam;
-extern vmCvar_t ui_scoreBase;
-extern vmCvar_t ui_scoreTimeBonus;
-extern vmCvar_t ui_scoreSkillBonus;
-extern vmCvar_t ui_scoreShutoutBonus;
-extern vmCvar_t ui_scoreTime;
-extern vmCvar_t ui_smallFont;
-extern vmCvar_t ui_bigFont;
-extern vmCvar_t ui_serverStatusTimeOut;
-
-//TA: bank values
-extern vmCvar_t ui_bank;
-
-extern vmCvar_t ui_chatCommands;
-
-//
-// ui_qmenu.c
-//
-
-#define RCOLUMN_OFFSET ( BIGCHAR_WIDTH )
-#define LCOLUMN_OFFSET (-BIGCHAR_WIDTH )
-
-#define SLIDER_RANGE 10
-#define MAX_EDIT_LINE 256
-
-#define MAX_MENUDEPTH 8
-#define MAX_MENUITEMS 128
-
-#define MTYPE_NULL 0
-#define MTYPE_SLIDER 1
-#define MTYPE_ACTION 2
-#define MTYPE_SPINCONTROL 3
-#define MTYPE_FIELD 4
-#define MTYPE_RADIOBUTTON 5
-#define MTYPE_BITMAP 6
-#define MTYPE_TEXT 7
-#define MTYPE_SCROLLLIST 8
-#define MTYPE_PTEXT 9
-#define MTYPE_BTEXT 10
-
-#define QMF_BLINK 0x00000001
-#define QMF_SMALLFONT 0x00000002
-#define QMF_LEFT_JUSTIFY 0x00000004
-#define QMF_CENTER_JUSTIFY 0x00000008
-#define QMF_RIGHT_JUSTIFY 0x00000010
-#define QMF_NUMBERSONLY 0x00000020 // edit field is only numbers
-#define QMF_HIGHLIGHT 0x00000040
-#define QMF_HIGHLIGHT_IF_FOCUS 0x00000080 // steady focus
-#define QMF_PULSEIFFOCUS 0x00000100 // pulse if focus
-#define QMF_HASMOUSEFOCUS 0x00000200
-#define QMF_NOONOFFTEXT 0x00000400
-#define QMF_MOUSEONLY 0x00000800 // only mouse input allowed
-#define QMF_HIDDEN 0x00001000 // skips drawing
-#define QMF_GRAYED 0x00002000 // grays and disables
-#define QMF_INACTIVE 0x00004000 // disables any input
-#define QMF_NODEFAULTINIT 0x00008000 // skip default initialization
-#define QMF_OWNERDRAW 0x00010000
-#define QMF_PULSE 0x00020000
-#define QMF_LOWERCASE 0x00040000 // edit field is all lower case
-#define QMF_UPPERCASE 0x00080000 // edit field is all upper case
-#define QMF_SILENT 0x00100000
-
-// callback notifications
-#define QM_GOTFOCUS 1
-#define QM_LOSTFOCUS 2
-#define QM_ACTIVATED 3
-
-typedef struct _tag_menuframework
-{
- int cursor;
- int cursor_prev;
-
- int nitems;
- void *items[MAX_MENUITEMS];
-
- void (*draw) (void);
- sfxHandle_t (*key) (int key);
-
- qboolean wrapAround;
- qboolean fullscreen;
- qboolean showlogo;
-} menuframework_s;
-
-typedef struct
-{
- int type;
- const char *name;
- int id;
- int x, y;
- int left;
- int top;
- int right;
- int bottom;
- menuframework_s *parent;
- int menuPosition;
- unsigned flags;
-
- void (*callback)( void *self, int event );
- void (*statusbar)( void *self );
- void (*ownerdraw)( void *self );
-} menucommon_s;
-
-typedef struct {
- int cursor;
- int scroll;
- int widthInChars;
- char buffer[MAX_EDIT_LINE];
- int maxchars;
-} mfield_t;
-
-typedef struct
-{
- menucommon_s generic;
- mfield_t field;
-} menufield_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- float minvalue;
- float maxvalue;
- float curvalue;
-
- float range;
-} menuslider_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- int oldvalue;
- int curvalue;
- int numitems;
- int top;
-
- const char **itemnames;
-
- int width;
- int height;
- int columns;
- int seperation;
-} menulist_s;
-
-typedef struct
-{
- menucommon_s generic;
-} menuaction_s;
-
-typedef struct
-{
- menucommon_s generic;
- int curvalue;
-} menuradiobutton_s;
-
-typedef struct
-{
- menucommon_s generic;
- char* focuspic;
- char* errorpic;
- qhandle_t shader;
- qhandle_t focusshader;
- int width;
- int height;
- float* focuscolor;
-} menubitmap_s;
-
-typedef struct
-{
- menucommon_s generic;
- char* string;
- int style;
- float* color;
-} menutext_s;
-
-extern void Menu_Cache( void );
-extern void Menu_Focus( menucommon_s *m );
-extern void Menu_AddItem( menuframework_s *menu, void *item );
-extern void Menu_AdjustCursor( menuframework_s *menu, int dir );
-extern void Menu_Draw( menuframework_s *menu );
-extern void *Menu_ItemAtCursor( menuframework_s *m );
-extern sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item );
-extern void Menu_SetCursor( menuframework_s *s, int cursor );
-extern void Menu_SetCursorToItem( menuframework_s *m, void* ptr );
-extern sfxHandle_t Menu_DefaultKey( menuframework_s *s, int key );
-extern void Bitmap_Init( menubitmap_s *b );
-extern void Bitmap_Draw( menubitmap_s *b );
-extern void ScrollList_Draw( menulist_s *l );
-extern sfxHandle_t ScrollList_Key( menulist_s *l, int key );
-extern sfxHandle_t menu_in_sound;
-extern sfxHandle_t menu_move_sound;
-extern sfxHandle_t menu_out_sound;
-extern sfxHandle_t menu_buzz_sound;
-extern sfxHandle_t menu_null_sound;
-extern sfxHandle_t weaponChangeSound;
-extern vec4_t menu_text_color;
-extern vec4_t menu_grayed_color;
-extern vec4_t menu_dark_color;
-extern vec4_t menu_highlight_color;
-extern vec4_t menu_red_color;
-extern vec4_t menu_black_color;
-extern vec4_t menu_dim_color;
-extern vec4_t color_black;
-extern vec4_t color_white;
-extern vec4_t color_yellow;
-extern vec4_t color_blue;
-extern vec4_t color_orange;
-extern vec4_t color_red;
-extern vec4_t color_dim;
-extern vec4_t name_color;
-extern vec4_t list_color;
-extern vec4_t listbar_color;
-extern vec4_t text_color_disabled;
-extern vec4_t text_color_normal;
-extern vec4_t text_color_highlight;
-
-extern char *ui_medalNames[];
-extern char *ui_medalPicNames[];
-extern char *ui_medalSounds[];
-
-//
-// ui_mfield.c
-//
-extern void MField_Clear( mfield_t *edit );
-extern void MField_KeyDownEvent( mfield_t *edit, int key );
-extern void MField_CharEvent( mfield_t *edit, int ch );
-extern void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color );
-extern void MenuField_Init( menufield_s* m );
-extern void MenuField_Draw( menufield_s *f );
-extern sfxHandle_t MenuField_Key( menufield_s* m, int* key );
-
//
// ui_main.c
//
-void UI_Report( void );
-void UI_Load( void );
+void UI_Report(void);
+void UI_Load(void);
void UI_LoadMenus(const char *menuFile, qboolean reset);
-void _UI_SetActiveMenu( uiMenuCommand_t menu );
int UI_AdjustTimeByGame(int time);
-void UI_ShowPostGame(qboolean newHigh);
-void UI_ClearScores( void );
+void UI_ClearScores(void);
void UI_LoadArenas(void);
void UI_ServerInfo(void);
+void UI_UpdateNews(qboolean);
+void UI_UpdateGithubRelease(void);
-//
-// ui_menu.c
-//
-extern void MainMenu_Cache( void );
-extern void UI_MainMenu(void);
-extern void UI_RegisterCvars( void );
-extern void UI_UpdateCvars( void );
-
-//
-// ui_credits.c
-//
-extern void UI_CreditMenu( void );
-
-//
-// ui_ingame.c
-//
-extern void InGame_Cache( void );
-extern void UI_InGameMenu(void);
-
-//
-// ui_confirm.c
-//
-extern void ConfirmMenu_Cache( void );
-extern void UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) );
-
-//
-// ui_setup.c
-//
-extern void UI_SetupMenu_Cache( void );
-extern void UI_SetupMenu(void);
-
-//
-// ui_team.c
-//
-extern void UI_TeamMainMenu( void );
-extern void TeamMain_Cache( void );
-
-//
-// ui_connect.c
-//
-extern void UI_DrawConnectScreen( qboolean overlay );
-
-//
-// ui_controls2.c
-//
-extern void UI_ControlsMenu( void );
-extern void Controls_Cache( void );
-
-//
-// ui_demo2.c
-//
-extern void UI_DemosMenu( void );
-extern void Demos_Cache( void );
-
-//
-// ui_cinematics.c
-//
-extern void UI_CinematicsMenu( void );
-extern void UI_CinematicsMenu_f( void );
-extern void UI_CinematicsMenu_Cache( void );
-
-//
-// ui_mods.c
-//
-extern void UI_ModsMenu( void );
-extern void UI_ModsMenu_Cache( void );
-
-//
-// ui_playermodel.c
-//
-extern void UI_PlayerModelMenu( void );
-extern void PlayerModel_Cache( void );
-
-//
-// ui_playersettings.c
-//
-extern void UI_PlayerSettingsMenu( void );
-extern void PlayerSettings_Cache( void );
-
-//
-// ui_preferences.c
-//
-extern void UI_PreferencesMenu( void );
-extern void Preferences_Cache( void );
-
-//
-// ui_specifyleague.c
-//
-extern void UI_SpecifyLeagueMenu( void );
-extern void SpecifyLeague_Cache( void );
-
-//
-// ui_specifyserver.c
-//
-extern void UI_SpecifyServerMenu( void );
-extern void SpecifyServer_Cache( void );
-
-//
-// ui_servers2.c
-//
-#define MAX_FAVORITESERVERS 16
-
-extern void UI_ArenaServersMenu( void );
-extern void ArenaServers_Cache( void );
-
-//
-// ui_startserver.c
-//
-extern void UI_StartServerMenu( qboolean multiplayer );
-extern void StartServer_Cache( void );
-extern void ServerOptions_Cache( void );
-extern void UI_BotSelectMenu( char *bot );
-extern void UI_BotSelectMenu_Cache( void );
-
-//
-// ui_serverinfo.c
-//
-extern void UI_ServerInfoMenu( void );
-extern void ServerInfo_Cache( void );
-
-//
-// ui_video.c
-//
-extern void UI_GraphicsOptionsMenu( void );
-extern void GraphicsOptions_Cache( void );
-extern void DriverInfo_Cache( void );
-
-//
-// ui_players.c
-//
-
-//FIXME ripped from cg_local.h
-typedef struct {
- int oldFrame;
- int oldFrameTime; // time when ->oldFrame was exactly on
-
- int frame;
- int frameTime; // time when ->frame will be exactly on
-
- float backlerp;
-
- float yawAngle;
- qboolean yawing;
- float pitchAngle;
- qboolean pitching;
-
- int animationNumber; // may include ANIM_TOGGLEBIT
- animation_t *animation;
- int animationTime; // time when the first frame of the animation will be exact
-} lerpFrame_t;
-
-typedef struct {
- // model info
- qhandle_t legsModel;
- qhandle_t legsSkin;
- lerpFrame_t legs;
-
- qhandle_t torsoModel;
- qhandle_t torsoSkin;
- lerpFrame_t torso;
-
- qhandle_t headModel;
- qhandle_t headSkin;
-
- animation_t animations[MAX_PLAYER_TOTALANIMATIONS];
-
- qhandle_t weaponModel;
- qhandle_t barrelModel;
- qhandle_t flashModel;
- vec3_t flashDlightColor;
- int muzzleFlashTime;
-
- // currently in use drawing parms
- vec3_t viewAngles;
- vec3_t moveAngles;
- weapon_t currentWeapon;
- int legsAnim;
- int torsoAnim;
-
- // animation vars
- weapon_t weapon;
- weapon_t lastWeapon;
- weapon_t pendingWeapon;
- int weaponTimer;
- int pendingLegsAnim;
- int torsoAnimationTimer;
-
- int pendingTorsoAnim;
- int legsAnimationTimer;
-
- qboolean chat;
- qboolean newModel;
-
- qboolean barrelSpinning;
- float barrelAngle;
- int barrelTime;
-
- int realWeapon;
-} playerInfo_t;
-
-void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time );
-void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model, const char *headmodel, char *teamName );
-void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNum, qboolean chat );
-qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName , const char *headName, const char *teamName);
-
-//
-// ui_atoms.c
-//
-// this is only used in the old ui, the new ui has it's own version
-typedef struct {
- int frametime;
- int realtime;
- int cursorx;
- int cursory;
- glconfig_t glconfig;
- qboolean debug;
- qhandle_t whiteShader;
- qhandle_t charset;
- qhandle_t charsetProp;
- qhandle_t charsetPropGlow;
- qhandle_t charsetPropB;
- qhandle_t cursor;
- qhandle_t rb_on;
- qhandle_t rb_off;
- float scale;
- float bias;
- qboolean demoversion;
- qboolean firstdraw;
-} uiStatic_t;
-
+void UI_RegisterCvars(void);
+void UI_UpdateCvars(void);
+void UI_DrawConnectScreen(void);
// new ui stuff
-#define UI_NUMFX 7
-#define MAX_HEADS 64
-#define MAX_ALIASES 64
-#define MAX_HEADNAME 32
-#define MAX_TEAMS 64
-#define MAX_GAMETYPES 16
#define MAX_MAPS 128
-#define MAX_SPMAPS 16
-#define PLAYERS_PER_TEAM 5
-#define MAX_PINGREQUESTS 32
-#define MAX_ADDRESSLENGTH 64
-#define MAX_HOSTNAMELENGTH 22
-#define MAX_MAPNAMELENGTH 16
-#define MAX_STATUSLENGTH 64
-#define MAX_LISTBOXWIDTH 59
-#define UI_FONT_THRESHOLD 0.1
-#define MAX_DISPLAY_SERVERS 2048
-#define MAX_SERVERSTATUS_LINES 128
-#define MAX_SERVERSTATUS_TEXT 1024
-#define MAX_FOUNDPLAYER_SERVERS 16
-#define TEAM_MEMBERS 5
-#define GAMES_ALL 0
-#define GAMES_FFA 1
-#define GAMES_TEAMPLAY 2
-#define GAMES_TOURNEY 3
-#define GAMES_CTF 4
-#define MAPS_PER_TIER 3
-#define MAX_TIERS 16
+#define MAX_PINGREQUESTS 32
+#define MAX_ADDRESSLENGTH 64
+#define MAX_DISPLAY_SERVERS 2048
+#define MAX_SERVERSTATUS_LINES 128
+#define MAX_SERVERSTATUS_TEXT 1024
+#define MAX_NEWS_LINES 50
+#define MAX_NEWS_LINEWIDTH 85
+#define MAX_FOUNDPLAYER_SERVERS 16
#define MAX_MODS 64
#define MAX_DEMOS 256
#define MAX_MOVIES 256
-#define MAX_PLAYERMODELS 256
-
-
-typedef struct {
- const char *name;
- const char *imageName;
- qhandle_t headImage;
- const char *base;
- qboolean active;
- int reference;
-} characterInfo;
-
-typedef struct {
- const char *name;
- const char *ai;
- const char *action;
-} aliasInfo;
-
-typedef struct {
- const char *teamName;
- const char *imageName;
- const char *teamMembers[TEAM_MEMBERS];
- qhandle_t teamIcon;
- qhandle_t teamIcon_Metal;
- qhandle_t teamIcon_Name;
- int cinematic;
-} teamInfo;
-
-typedef struct {
- const char *gameType;
- int gtEnum;
-} gameTypeInfo;
+#define MAX_HELP_INFOPANES 32
+#define MAX_RESOLUTIONS 32
typedef struct {
- const char *mapName;
- const char *mapLoadName;
- const char *imageName;
- const char *opponentName;
- int teamMembers;
- int typeBits;
- int cinematic;
- int timeToBeat[MAX_GAMETYPES];
- qhandle_t levelShot;
- qboolean active;
+ const char *mapName;
+ const char *mapLoadName;
+ const char *imageName;
+ int cinematic;
+ qhandle_t levelShot;
} mapInfo;
-typedef struct {
- const char *tierName;
- const char *maps[MAPS_PER_TIER];
- int gameTypes[MAPS_PER_TIER];
- qhandle_t mapHandles[MAPS_PER_TIER];
-} tierInfo;
-
typedef struct serverFilter_s {
- const char *description;
- const char *basedir;
+ const char *description;
+ const char *basedir;
} serverFilter_t;
typedef struct {
- char adrstr[MAX_ADDRESSLENGTH];
- int start;
+ char adrstr[MAX_ADDRESSLENGTH];
+ int start;
} pinglist_t;
-
typedef struct serverStatus_s {
- pinglist_t pingList[MAX_PINGREQUESTS];
- int numqueriedservers;
- int currentping;
- int nextpingtime;
- int maxservers;
- int refreshtime;
- int numServers;
- int sortKey;
- int sortDir;
- qboolean sorted;
- int lastCount;
- qboolean refreshActive;
- int currentServer;
- int displayServers[MAX_DISPLAY_SERVERS];
- int numDisplayServers;
- int numPlayersOnServers;
- int nextDisplayRefresh;
- int nextSortTime;
- qhandle_t currentServerPreview;
- int currentServerCinematic;
- int motdLen;
- int motdWidth;
- int motdPaintX;
- int motdPaintX2;
- int motdOffset;
- int motdTime;
- char motd[MAX_STRING_CHARS];
+ pinglist_t pingList[MAX_PINGREQUESTS];
+ int numqueriedservers;
+ int currentping;
+ int nextpingtime;
+ int maxservers;
+ int refreshtime;
+ int numServers;
+ int sortKey;
+ int sortDir;
+ qboolean sorted;
+ int lastCount;
+ qboolean refreshActive;
+ int currentServer;
+ int displayServers[MAX_DISPLAY_SERVERS];
+ int numDisplayServers;
+ int numDuplicateMultiprotocolServers;
+ int numDuplicateMultiprotocolServerClients;
+ int numPlayersOnServers;
+ int nextDisplayRefresh;
+ int nextSortTime;
+ qhandle_t currentServerPreview;
+ int currentServerCinematic;
+ int motdLen;
+ int motdWidth;
+ int motdPaintX;
+ int motdPaintX2;
+ int motdOffset;
+ int motdTime;
+ char motd[MAX_STRING_CHARS];
} serverStatus_t;
-
typedef struct {
- char adrstr[MAX_ADDRESSLENGTH];
- char name[MAX_ADDRESSLENGTH];
- int startTime;
- int serverNum;
- qboolean valid;
+ char adrstr[MAX_ADDRESSLENGTH];
+ char name[MAX_ADDRESSLENGTH];
+ int startTime;
+ int serverNum;
+ qboolean valid;
} pendingServer_t;
typedef struct {
- int num;
- pendingServer_t server[MAX_SERVERSTATUSREQUESTS];
+ int num;
+ pendingServer_t server[MAX_SERVERSTATUSREQUESTS];
} pendingServerStatus_t;
typedef struct {
- char address[MAX_ADDRESSLENGTH];
- char *lines[MAX_SERVERSTATUS_LINES][4];
- char text[MAX_SERVERSTATUS_TEXT];
- char pings[MAX_CLIENTS * 3];
- int numLines;
+ char address[MAX_ADDRESSLENGTH];
+ char *lines[MAX_SERVERSTATUS_LINES][4];
+ char text[MAX_SERVERSTATUS_TEXT];
+ char pings[MAX_CLIENTS * 3];
+ int numLines;
} serverStatusInfo_t;
typedef struct {
- const char *modName;
- const char *modDescr;
-} modInfo_t;
-
-//TA: tremulous menus
-#define MAX_INFOPANE_TEXT 4096
-#define MAX_INFOPANE_GRAPHICS 16
-#define MAX_INFOPANES 128
-
-typedef enum
-{
- INFOPANE_TOP,
- INFOPANE_BOTTOM,
- INFOPANE_LEFT,
- INFOPANE_RIGHT
-} tremIPSide_t;
-
-typedef struct
-{
- qhandle_t graphic;
-
- tremIPSide_t side;
- int offset;
-
- int width, height;
-} tremIPGraphic_t;
-
-typedef struct
-{
- const char *name;
- char text[ MAX_INFOPANE_TEXT ];
- int align;
-
- tremIPGraphic_t graphics[ MAX_INFOPANE_GRAPHICS ];
- int numGraphics;
-} tremInfoPane_t;
-
-typedef struct
-{
- const char *text;
- const char *cmd;
- tremInfoPane_t *infopane;
-} tremMenuItem_t;
-//TA: tremulous menus
+ char text[MAX_NEWS_LINES][MAX_NEWS_LINEWIDTH];
+ int numLines;
+ qboolean refreshActive;
+ int refreshtime;
+} newsInfo_t;
typedef struct {
- displayContextDef_t uiDC;
- int newHighScoreTime;
- int newBestTime;
- int showPostGameTime;
- qboolean newHighScore;
- qboolean demoAvailable;
- qboolean soundHighScore;
+ char text[MAX_NEWS_LINES][MAX_NEWS_LINEWIDTH];
+ int numLines;
+ qboolean refreshActive;
+ int nextTime;
+} githubRelease_t;
- int characterCount;
- int botIndex;
- characterInfo characterList[MAX_HEADS];
-
- int aliasCount;
- aliasInfo aliasList[MAX_ALIASES];
-
- int teamCount;
- teamInfo teamList[MAX_TEAMS];
-
- int numGameTypes;
- gameTypeInfo gameTypes[MAX_GAMETYPES];
-
- int numJoinGameTypes;
- gameTypeInfo joinGameTypes[MAX_GAMETYPES];
-
- int redBlue;
- int playerCount;
- int myTeamCount;
- int teamIndex;
- int playerRefresh;
- int playerIndex;
- int playerNumber;
- int myPlayerIndex;
- int ignoreIndex;
- qboolean teamLeader;
- char playerNames[MAX_CLIENTS][MAX_NAME_LENGTH];
- char rawPlayerNames[MAX_CLIENTS][MAX_NAME_LENGTH];
- char teamNames[MAX_CLIENTS][MAX_NAME_LENGTH];
- char rawTeamNames[MAX_CLIENTS][MAX_NAME_LENGTH];
- int clientNums[MAX_CLIENTS];
- int teamClientNums[MAX_CLIENTS];
- clientList_t ignoreList[MAX_CLIENTS];
-
- int mapCount;
- mapInfo mapList[MAX_MAPS];
-
-
- int tierCount;
- tierInfo tierList[MAX_TIERS];
-
- int skillIndex;
-
- modInfo_t modList[MAX_MODS];
- int modCount;
- int modIndex;
-
- const char *demoList[MAX_DEMOS];
- int demoCount;
- int demoIndex;
-
- const char *movieList[MAX_MOVIES];
- int movieCount;
- int movieIndex;
- int previewMovie;
-
- tremInfoPane_t tremInfoPanes[ MAX_INFOPANES ];
- int tremInfoPaneCount;
-
-//TA: tremulous menus
- tremMenuItem_t tremTeamList[ 4 ];
- int tremTeamCount;
- int tremTeamIndex;
-
- tremMenuItem_t tremAlienClassList[ 3 ];
- int tremAlienClassCount;
- int tremAlienClassIndex;
-
- tremMenuItem_t tremHumanItemList[ 3 ];
- int tremHumanItemCount;
- int tremHumanItemIndex;
-
- tremMenuItem_t tremHumanArmouryBuyList[ 32 ];
- int tremHumanArmouryBuyCount;
- int tremHumanArmouryBuyIndex;
-
- tremMenuItem_t tremHumanArmourySellList[ 32 ];
- int tremHumanArmourySellCount;
- int tremHumanArmourySellIndex;
-
- tremMenuItem_t tremAlienUpgradeList[ 16 ];
- int tremAlienUpgradeCount;
- int tremAlienUpgradeIndex;
-
- tremMenuItem_t tremAlienBuildList[ 32 ];
- int tremAlienBuildCount;
- int tremAlienBuildIndex;
-
- tremMenuItem_t tremHumanBuildList[ 32 ];
- int tremHumanBuildCount;
- int tremHumanBuildIndex;
-//TA: tremulous menus
-
- serverStatus_t serverStatus;
-
- // for the showing the status of a server
- char serverStatusAddress[MAX_ADDRESSLENGTH];
- serverStatusInfo_t serverStatusInfo;
- int nextServerStatusRefresh;
-
- // to retrieve the status of server to find a player
- pendingServerStatus_t pendingServerStatus;
- char findPlayerName[MAX_STRING_CHARS];
- char foundPlayerServerAddresses[MAX_FOUNDPLAYER_SERVERS][MAX_ADDRESSLENGTH];
- char foundPlayerServerNames[MAX_FOUNDPLAYER_SERVERS][MAX_ADDRESSLENGTH];
- int currentFoundPlayerServer;
- int numFoundPlayerServers;
- int nextFindPlayerRefresh;
-
- int currentCrosshair;
- int startPostGameTime;
- sfxHandle_t newHighScoreSound;
+typedef struct {
+ const char *modName;
+ const char *modDescr;
+} modInfo_t;
- int q3HeadCount;
- char q3HeadNames[MAX_PLAYERMODELS][64];
- qhandle_t q3HeadIcons[MAX_PLAYERMODELS];
- int q3SelectedHead;
+typedef enum {
+ INFOTYPE_TEXT,
+ INFOTYPE_BUILDABLE,
+ INFOTYPE_CLASS,
+ INFOTYPE_WEAPON,
+ INFOTYPE_UPGRADE,
+ INFOTYPE_VOICECMD
+} infoType_t;
- int effectsColor;
+typedef struct {
+ const char *text;
+ const char *cmd;
+ infoType_t type;
+ union {
+ const char *text;
+ buildable_t buildable;
+ class_t pclass;
+ weapon_t weapon;
+ upgrade_t upgrade;
+ } v;
+} menuItem_t;
- qboolean inGameLoad;
+typedef struct {
+ int w;
+ int h;
+} resolution_t;
- qboolean chatTeam;
-} uiInfo_t;
+typedef struct {
+ displayContextDef_t uiDC;
+
+ int playerCount;
+ int myTeamCount;
+ int teamPlayerIndex;
+ int playerRefresh;
+ int playerIndex;
+ int playerNumber;
+ int myPlayerIndex;
+ int ignoreIndex;
+ char playerNames[MAX_CLIENTS][MAX_NAME_LENGTH];
+ char rawPlayerNames[MAX_CLIENTS][MAX_NAME_LENGTH];
+ char teamNames[MAX_CLIENTS][MAX_NAME_LENGTH];
+ char rawTeamNames[MAX_CLIENTS][MAX_NAME_LENGTH];
+ int clientNums[MAX_CLIENTS];
+ int teamClientNums[MAX_CLIENTS];
+ clientList_t ignoreList[MAX_CLIENTS];
+
+ int mapCount;
+ mapInfo mapList[MAX_MAPS];
+
+ modInfo_t modList[MAX_MODS];
+ int modCount;
+ int modIndex;
+
+ const char *demoList[MAX_DEMOS];
+ int demoCount;
+ int demoIndex;
+
+ const char *movieList[MAX_MOVIES];
+ int movieCount;
+ int movieIndex;
+ int previewMovie;
+
+ menuItem_t teamList[4];
+ int teamCount;
+ int teamIndex;
+
+ menuItem_t alienClassList[3];
+ int alienClassCount;
+ int alienClassIndex;
+
+ menuItem_t humanItemList[3];
+ int humanItemCount;
+ int humanItemIndex;
+
+ menuItem_t humanArmouryBuyList[32];
+ int humanArmouryBuyCount;
+ int humanArmouryBuyIndex;
+
+ menuItem_t humanArmourySellList[32];
+ int humanArmourySellCount;
+ int humanArmourySellIndex;
+
+ menuItem_t alienUpgradeList[16];
+ int alienUpgradeCount;
+ int alienUpgradeIndex;
+
+ menuItem_t alienBuildList[32];
+ int alienBuildCount;
+ int alienBuildIndex;
+
+ menuItem_t humanBuildList[32];
+ int humanBuildCount;
+ int humanBuildIndex;
+
+ menuItem_t voiceCmdList[32];
+ int voiceCmdCount;
+ int voiceCmdIndex;
+
+ menuItem_t helpList[MAX_HELP_INFOPANES];
+ int helpCount;
+ int helpIndex;
+
+ int weapons;
+ int upgrades;
+
+ serverStatus_t serverStatus;
+
+ // for showing the game news window
+ newsInfo_t newsInfo;
+
+ githubRelease_t githubRelease;
+
+ // for the showing the status of a server
+ char serverStatusAddress[MAX_ADDRESSLENGTH];
+ serverStatusInfo_t serverStatusInfo;
+ int nextServerStatusRefresh;
+
+ // to retrieve the status of server to find a player
+ pendingServerStatus_t pendingServerStatus;
+ char findPlayerName[MAX_STRING_CHARS];
+ char foundPlayerServerAddresses[MAX_FOUNDPLAYER_SERVERS][MAX_ADDRESSLENGTH];
+ char foundPlayerServerNames[MAX_FOUNDPLAYER_SERVERS][MAX_ADDRESSLENGTH];
+ int currentFoundPlayerServer;
+ int numFoundPlayerServers;
+ int nextFindPlayerRefresh;
+
+ resolution_t resolutions[MAX_RESOLUTIONS];
+ int numResolutions;
+ int resolutionIndex;
+
+ voice_t *voices;
+
+ qboolean inGameLoad;
+
+ qboolean chatTeam;
+ qboolean voiceCmd;
+} uiInfo_t;
extern uiInfo_t uiInfo;
-
-extern void UI_Init( void );
-extern void UI_Shutdown( void );
-extern void UI_KeyEvent( int key );
-extern void UI_MouseEvent( int dx, int dy );
-extern void UI_Refresh( int realtime );
-extern qboolean UI_ConsoleCommand( int realTime );
-extern float UI_ClampCvar( float min, float max, float value );
-extern void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname );
-extern void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader );
-extern void UI_FillRect( float x, float y, float width, float height, const float *color );
-extern void UI_DrawRect( float x, float y, float width, float height, const float *color );
-extern void UI_DrawTopBottom(float x, float y, float w, float h);
-extern void UI_DrawSides(float x, float y, float w, float h);
-extern void UI_UpdateScreen( void );
-extern void UI_SetColor( const float *rgba );
-extern void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);
-extern void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color );
-extern float UI_ProportionalSizeScale( int style );
-extern void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
-extern int UI_ProportionalStringWidth( const char* str );
-extern void UI_DrawString( int x, int y, const char* str, int style, vec4_t color );
-extern void UI_DrawChar( int x, int y, int ch, int style, vec4_t color );
-extern qboolean UI_CursorInRect (int x, int y, int width, int height);
-extern void UI_AdjustFrom640( float *x, float *y, float *w, float *h );
-extern void UI_DrawTextBox (int x, int y, int width, int lines);
-extern qboolean UI_IsFullscreen( void );
-extern void UI_SetActiveMenu( uiMenuCommand_t menu );
-extern void UI_PushMenu ( menuframework_s *menu );
-extern void UI_PopMenu (void);
-extern void UI_ForceMenuOff (void);
-extern char *UI_Argv( int arg );
-extern char *UI_Cvar_VariableString( const char *var_name );
-extern void UI_Refresh( int time );
-extern void UI_KeyEvent( int key );
-extern void UI_StartDemoLoop( void );
-extern qboolean m_entersound;
-void UI_LoadBestScores(const char *map, int game);
-extern uiStatic_t uis;
-
-//
-// ui_spLevel.c
-//
-void UI_SPLevelMenu_Cache( void );
-void UI_SPLevelMenu( void );
-void UI_SPLevelMenu_f( void );
-void UI_SPLevelMenu_ReInit( void );
-
-//
-// ui_spArena.c
-//
-void UI_SPArena_Start( const char *arenaInfo );
-
-//
-// ui_spPostgame.c
-//
-void UI_SPPostgameMenu_Cache( void );
-void UI_SPPostgameMenu_f( void );
-
-//
-// ui_spSkill.c
-//
-void UI_SPSkillMenu( const char *arenaInfo );
-void UI_SPSkillMenu_Cache( void );
+qboolean UI_ConsoleCommand(int realTime);
+char *UI_Cvar_VariableString(const char *var_name);
+void UI_SetColor(const float *rgba);
+void UI_AdjustFrom640(float *x, float *y, float *w, float *h);
+void UI_Refresh(int time);
+void UI_DrawHandlePic(float x, float y, float w, float h, qhandle_t hShader);
+void UI_FillRect(float x, float y, float width, float height, const float *color);
//
// ui_syscalls.c
//
-void trap_Print( const char *string );
-void trap_Error( const char *string );
-int trap_Milliseconds( void );
-void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
-void trap_Cvar_Update( vmCvar_t *vmCvar );
-void trap_Cvar_Set( const char *var_name, const char *value );
-float trap_Cvar_VariableValue( const char *var_name );
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-void trap_Cvar_SetValue( const char *var_name, float value );
-void trap_Cvar_Reset( const char *name );
-void trap_Cvar_Create( const char *var_name, const char *var_value, int flags );
-void trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize );
-int trap_Argc( void );
-void trap_Argv( int n, char *buffer, int bufferLength );
-void trap_Cmd_ExecuteText( int exec_when, const char *text ); // don't use EXEC_NOW!
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
-void trap_FS_Read( void *buffer, int len, fileHandle_t f );
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
-void trap_FS_FCloseFile( fileHandle_t f );
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
-qhandle_t trap_R_RegisterModel( const char *name );
-qhandle_t trap_R_RegisterSkin( const char *name );
-qhandle_t trap_R_RegisterShaderNoMip( const char *name );
-void trap_R_ClearScene( void );
-void trap_R_AddRefEntityToScene( const refEntity_t *re );
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-void trap_R_RenderScene( const refdef_t *fd );
-void trap_R_SetColor( const float *rgba );
-void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
-void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
-void trap_UpdateScreen( void );
-int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName );
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed );
-void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen );
-void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen );
-void trap_Key_SetBinding( int keynum, const char *binding );
-qboolean trap_Key_IsDown( int keynum );
-qboolean trap_Key_GetOverstrikeMode( void );
-void trap_Key_SetOverstrikeMode( qboolean state );
-void trap_Key_ClearStates( void );
-int trap_Key_GetCatcher( void );
-void trap_Key_SetCatcher( int catcher );
-void trap_GetClipboardData( char *buf, int bufsize );
-void trap_GetClientState( uiClientState_t *state );
-void trap_GetGlconfig( glconfig_t *glconfig );
-int trap_GetConfigString( int index, char* buff, int buffsize );
-int trap_LAN_GetServerCount( int source );
-void trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen );
-void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen );
-int trap_LAN_GetServerPing( int source, int n );
-int trap_LAN_GetPingQueueCount( void );
-void trap_LAN_ClearPing( int n );
-void trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime );
-void trap_LAN_GetPingInfo( int n, char *buf, int buflen );
-void trap_LAN_LoadCachedServers( void );
-void trap_LAN_SaveCachedServers( void );
-void trap_LAN_MarkServerVisible(int source, int n, qboolean visible);
-int trap_LAN_ServerIsVisible( int source, int n);
-qboolean trap_LAN_UpdateVisiblePings( int source );
-int trap_LAN_AddServer(int source, const char *name, const char *addr);
-void trap_LAN_RemoveServer(int source, const char *addr);
-void trap_LAN_ResetPings(int n);
-int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen );
-int trap_LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 );
-int trap_MemoryRemaining( void );
-void trap_R_RegisterFont(const char *pFontname, int pointSize, fontInfo_t *font);
-void trap_S_StopBackgroundTrack( void );
-void trap_S_StartBackgroundTrack( const char *intro, const char *loop);
-int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);
-e_status trap_CIN_StopCinematic(int handle);
-e_status trap_CIN_RunCinematic (int handle);
-void trap_CIN_DrawCinematic (int handle);
-void trap_CIN_SetExtents (int handle, int x, int y, int w, int h);
-int trap_RealTime(qtime_t *qtime);
-void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset );
-
-void trap_SetPbClStatus( int status );
-
-//
-// ui_addbots.c
-//
-void UI_AddBots_Cache( void );
-void UI_AddBotsMenu( void );
-
-//
-// ui_removebots.c
-//
-void UI_RemoveBots_Cache( void );
-void UI_RemoveBotsMenu( void );
-
-//
-// ui_teamorders.c
-//
-extern void UI_TeamOrdersMenu( void );
-extern void UI_TeamOrdersMenu_f( void );
-extern void UI_TeamOrdersMenu_Cache( void );
-
-//
-// ui_loadconfig.c
-//
-void UI_LoadConfig_Cache( void );
-void UI_LoadConfigMenu( void );
-
-//
-// ui_saveconfig.c
-//
-void UI_SaveConfigMenu_Cache( void );
-void UI_SaveConfigMenu( void );
-
-//
-// ui_display.c
-//
-void UI_DisplayOptionsMenu_Cache( void );
-void UI_DisplayOptionsMenu( void );
-
-//
-// ui_sound.c
-//
-void UI_SoundOptionsMenu_Cache( void );
-void UI_SoundOptionsMenu( void );
-
-//
-// ui_network.c
-//
-void UI_NetworkOptionsMenu_Cache( void );
-void UI_NetworkOptionsMenu( void );
-
-//
-// ui_gameinfo.c
-//
-typedef enum {
- AWARD_ACCURACY,
- AWARD_IMPRESSIVE,
- AWARD_EXCELLENT,
- AWARD_GAUNTLET,
- AWARD_FRAGS,
- AWARD_PERFECT
-} awardType_t;
-
-const char *UI_GetArenaInfoByNumber( int num );
-const char *UI_GetArenaInfoByMap( const char *map );
-const char *UI_GetSpecialArenaInfo( const char *tag );
-int UI_GetNumArenas( void );
-int UI_GetNumSPArenas( void );
-int UI_GetNumSPTiers( void );
-
-char *UI_GetBotInfoByNumber( int num );
-char *UI_GetBotInfoByName( const char *name );
-int UI_GetNumBots( void );
-void UI_LoadBots( void );
-char *UI_GetBotNameByNumber( int num );
-
-void UI_GetBestScore( int level, int *score, int *skill );
-void UI_SetBestScore( int level, int score );
-int UI_TierCompleted( int levelWon );
-qboolean UI_ShowTierVideo( int tier );
-qboolean UI_CanShowTierVideo( int tier );
-int UI_GetCurrentGame( void );
-void UI_NewGame( void );
-void UI_LogAwardData( int award, int data );
-int UI_GetAwardLevel( int award );
-
-void UI_SPUnlock_f( void );
-void UI_SPUnlockMedals_f( void );
-
-void UI_InitGameinfo( void );
-
-//
-// ui_login.c
-//
-void Login_Cache( void );
-void UI_LoginMenu( void );
-
-//
-// ui_signup.c
-//
-void Signup_Cache( void );
-void UI_SignupMenu( void );
-
-//
-// ui_rankstatus.c
-//
-void RankStatus_Cache( void );
-void UI_RankStatusMenu( void );
-
-
-// new ui
-
-#define ASSET_BACKGROUND "uiBackground"
-
-// for tracking sp game info in Team Arena
-typedef struct postGameInfo_s {
- int score;
- int redScore;
- int blueScore;
- int perfects;
- int accuracy;
- int impressives;
- int excellents;
- int defends;
- int assists;
- int gauntlets;
- int captures;
- int time;
- int timeBonus;
- int shutoutBonus;
- int skillBonus;
- int baseScore;
-} postGameInfo_t;
-
-
+void trap_Print(const char *string);
+void trap_Error(const char *string) __attribute__((noreturn));
+int trap_Milliseconds(void);
+void trap_Cvar_Register(vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags);
+void trap_Cvar_Update(vmCvar_t *vmCvar);
+void trap_Cvar_Set(const char *var_name, const char *value);
+float trap_Cvar_VariableValue(const char *var_name);
+void trap_Cvar_VariableStringBuffer(const char *var_name, char *buffer, int bufsize);
+void trap_Cvar_SetValue(const char *var_name, float value);
+void trap_Cvar_Reset(const char *name);
+void trap_Cvar_Create(const char *var_name, const char *var_value, int flags);
+void trap_Cvar_InfoStringBuffer(int bit, char *buffer, int bufsize);
+int trap_Argc(void);
+void trap_Argv(int n, char *buffer, int bufferLength);
+void trap_Cmd_ExecuteText(int exec_when, const char *text); // don't use EXEC_NOW!
+int trap_FS_FOpenFile(const char *qpath, fileHandle_t *f, enum FS_Mode mode);
+void trap_FS_Read(void *buffer, int len, fileHandle_t f);
+void trap_FS_Write(const void *buffer, int len, fileHandle_t f);
+void trap_FS_FCloseFile(fileHandle_t f);
+int trap_FS_GetFileList(const char *path, const char *extension, char *listbuf, int bufsize);
+int trap_FS_Seek(fileHandle_t f, long offset, enum FS_Mode origin); // fsOrigin_t
+qhandle_t trap_R_RegisterModel(const char *name);
+qhandle_t trap_R_RegisterSkin(const char *name);
+qhandle_t trap_R_RegisterShaderNoMip(const char *name);
+void trap_R_ClearScene(void);
+void trap_R_AddRefEntityToScene(const refEntity_t *re);
+void trap_R_AddPolyToScene(qhandle_t hShader, int numVerts, const polyVert_t *verts);
+void trap_R_AddLightToScene(const vec3_t org, float intensity, float r, float g, float b);
+void trap_R_RenderScene(const refdef_t *fd);
+void trap_R_SetColor(const float *rgba);
+void trap_R_SetClipRegion(const float *region);
+void trap_R_DrawStretchPic(
+ float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader);
+void trap_R_ModelBounds(clipHandle_t model, vec3_t mins, vec3_t maxs);
+void trap_UpdateScreen(void);
+int trap_CM_LerpTag(
+ orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName);
+void trap_S_StartLocalSound(sfxHandle_t sfx, int channelNum);
+sfxHandle_t trap_S_RegisterSound(const char *sample, qboolean compressed);
+void trap_Key_KeynumToStringBuf(int keynum, char *buf, int buflen);
+void trap_Key_GetBindingBuf(int keynum, char *buf, int buflen);
+void trap_Key_SetBinding(int keynum, const char *binding);
+qboolean trap_Key_IsDown(int keynum);
+qboolean trap_Key_GetOverstrikeMode(void);
+void trap_Key_SetOverstrikeMode(qboolean state);
+void trap_Key_ClearStates(void);
+int trap_Key_GetCatcher(void);
+void trap_Key_SetCatcher(int catcher);
+void trap_GetClipboardData(char *buf, int bufsize);
+void trap_GetClientState(uiClientState_t *state);
+void trap_GetGlconfig(glconfig_t *glconfig);
+int trap_GetConfigString(int index, char *buff, int buffsize);
+int trap_LAN_GetServerCount(int source);
+void trap_LAN_GetServerAddressString(int source, int n, char *buf, int buflen);
+void trap_LAN_GetServerInfo(int source, int n, char *buf, int buflen);
+int trap_LAN_GetServerPing(int source, int n);
+int trap_LAN_GetPingQueueCount(void);
+void trap_LAN_ClearPing(int n);
+void trap_LAN_GetPing(int n, char *buf, int buflen, int *pingtime);
+void trap_LAN_GetPingInfo(int n, char *buf, int buflen);
+void trap_LAN_LoadCachedServers(void);
+void trap_LAN_SaveCachedServers(void);
+void trap_LAN_MarkServerVisible(int source, int n, qboolean visible);
+int trap_LAN_ServerIsVisible(int source, int n);
+qboolean trap_LAN_UpdateVisiblePings(int source);
+int trap_LAN_AddServer(int source, const char *name, const char *addr);
+void trap_LAN_RemoveServer(int source, const char *addr);
+void trap_LAN_ResetPings(int n);
+int trap_LAN_ServerStatus(const char *serverAddress, char *serverStatus, int maxLen);
+qboolean trap_GetNews(qboolean force);
+int trap_LAN_CompareServers(int source, int sortKey, int sortDir, int s1, int s2);
+int trap_MemoryRemaining(void);
+void trap_R_RegisterFont(const char *pFontname, int pointSize, fontInfo_t *font);
+void trap_S_StopBackgroundTrack(void);
+void trap_S_StartBackgroundTrack(const char *intro, const char *loop);
+int trap_CIN_PlayCinematic(const char *arg0, int xpos, int ypos, int width, int height, int bits);
+e_status trap_CIN_StopCinematic(int handle);
+e_status trap_CIN_RunCinematic(int handle);
+void trap_CIN_DrawCinematic(int handle);
+void trap_CIN_SetExtents(int handle, int x, int y, int w, int h);
+int trap_RealTime(qtime_t *qtime);
+void trap_R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset);
+
+void trap_SetPbClStatus(int status);
+
+int trap_CheckForUpdate(int script);
+int trap_InstallUpdate(int script);
#endif
diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c
index e2396a9..ec7c0aa 100644
--- a/src/ui/ui_main.c
+++ b/src/ui/ui_main.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -29,9 +30,6 @@ USER INTERFACE MAIN
=======================================================================
*/
-// use this to get a demo build without an explicit demo build, i.e. to get the demo ui files to build
-//#define PRE_RELEASE_TADEMO
-
#include "ui_local.h"
uiInfo_t uiInfo;
@@ -39,80 +37,84 @@ uiInfo_t uiInfo;
#ifdef MODULE_INTERFACE_11
#undef AS_GLOBAL
#undef AS_LOCAL
-#define AS_GLOBAL 2
-#define AS_LOCAL 0
+#define AS_GLOBAL 2
+#define AS_LOCAL 0
#endif
-static const char *MonthAbbrev[] = {
- "Jan","Feb","Mar",
- "Apr","May","Jun",
- "Jul","Aug","Sep",
- "Oct","Nov","Dec"
-};
-
-
-static const char *skillLevels[] = {
- "I Can Win",
- "Bring It On",
- "Hurt Me Plenty",
- "Hardcore",
- "Nightmare"
-};
-
-static const int numSkillLevels = sizeof(skillLevels) / sizeof(const char*);
-
-
static const char *netSources[] = {
#ifdef MODULE_INTERFACE_11
- "LAN",
- "Mplayer",
- "Internet",
+ "LAN", "Mplayer", "Internet",
#else
- "Internet",
- "Mplayer",
- "LAN",
+ "Internet", "Mplayer", "LAN",
#endif
- "Favorites"
-};
-static const int numNetSources = sizeof(netSources) / sizeof(const char*);
-
-static const serverFilter_t serverFilters[] = {
- {"All", "" },
- {"Quake 3 Arena", "" },
- {"Team Arena", "missionpack" },
- {"Rocket Arena", "arena" },
- {"Alliance", "alliance20" },
- {"Weapons Factory Arena", "wfa" },
- {"OSP", "osp" },
-};
-
-static const int numServerFilters = sizeof(serverFilters) / sizeof(serverFilter_t);
-
-static char* netnames[] = {
- "???",
- "UDP",
- "IPX",
- NULL
-};
-
-static int gamecodetoui[] = {4,2,3,0,5,1,6};
-
-
-static void UI_StartServerRefresh(qboolean full);
-static void UI_StopServerRefresh( void );
-static void UI_DoServerRefresh( void );
-static void UI_FeederSelection(float feederID, int index);
-static void UI_BuildServerDisplayList(int force);
-static void UI_BuildServerStatus(qboolean force);
-static void UI_BuildFindPlayerList(qboolean force);
-static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 );
-static int UI_MapCountByGameType(qboolean singlePlayer);
-static int UI_HeadCountByTeam( void );
-static const char *UI_SelectedMap(int index, int *actual);
-static const char *UI_SelectedHead(int index, int *actual);
-static int UI_GetIndexFromSelection(int actual);
-
-int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 );
+ "Favorites"};
+
+static const size_t numNetSources = ARRAY_LEN(netSources);
+
+static const char *netnames[] = {"???", "UDP", "IPX", NULL};
+
+/*
+================
+cvars
+================
+*/
+
+typedef struct {
+ vmCvar_t *vmCvar;
+ char *cvarName;
+ char *defaultString;
+ int cvarFlags;
+}
+
+cvarTable_t;
+
+vmCvar_t ui_browserShowFull;
+vmCvar_t ui_browserShowEmpty;
+
+vmCvar_t ui_dedicated;
+vmCvar_t ui_netSource;
+vmCvar_t ui_selectedMap;
+vmCvar_t ui_lastServerRefresh_0;
+vmCvar_t ui_lastServerRefresh_1;
+vmCvar_t ui_lastServerRefresh_2;
+vmCvar_t ui_lastServerRefresh_3;
+vmCvar_t ui_lastServerRefresh_0_time;
+vmCvar_t ui_lastServerRefresh_1_time;
+vmCvar_t ui_lastServerRefresh_2_time;
+vmCvar_t ui_lastServerRefresh_3_time;
+vmCvar_t ui_smallFont;
+vmCvar_t ui_bigFont;
+vmCvar_t ui_findPlayer;
+vmCvar_t ui_serverStatusTimeOut;
+vmCvar_t ui_textWrapCache;
+vmCvar_t ui_developer;
+
+vmCvar_t ui_emoticons;
+vmCvar_t ui_winner;
+vmCvar_t ui_chatCommands;
+
+static cvarTable_t cvarTable[] = {{&ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE},
+ {&ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE},
+
+ {&ui_dedicated, "ui_dedicated", "0", CVAR_ARCHIVE}, {&ui_netSource, "ui_netSource", "0", CVAR_ARCHIVE},
+ {&ui_selectedMap, "ui_selectedMap", "0", CVAR_ARCHIVE},
+ {&ui_lastServerRefresh_0, "ui_lastServerRefresh_0", "", CVAR_ARCHIVE},
+ {&ui_lastServerRefresh_1, "ui_lastServerRefresh_1", "", CVAR_ARCHIVE},
+ {&ui_lastServerRefresh_2, "ui_lastServerRefresh_2", "", CVAR_ARCHIVE},
+ {&ui_lastServerRefresh_3, "ui_lastServerRefresh_3", "", CVAR_ARCHIVE},
+ {&ui_lastServerRefresh_0, "ui_lastServerRefresh_0_time", "", CVAR_ARCHIVE},
+ {&ui_lastServerRefresh_1, "ui_lastServerRefresh_1_time", "", CVAR_ARCHIVE},
+ {&ui_lastServerRefresh_2, "ui_lastServerRefresh_2_time", "", CVAR_ARCHIVE},
+ {&ui_lastServerRefresh_3, "ui_lastServerRefresh_3_time", "", CVAR_ARCHIVE},
+ {&ui_smallFont, "ui_smallFont", "0.2", CVAR_ARCHIVE | CVAR_LATCH},
+ {&ui_bigFont, "ui_bigFont", "0.5", CVAR_ARCHIVE | CVAR_LATCH}, {&ui_findPlayer, "ui_findPlayer", "", CVAR_ARCHIVE},
+ {&ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE},
+ {&ui_textWrapCache, "ui_textWrapCache", "1", CVAR_ARCHIVE},
+ {&ui_developer, "ui_developer", "0", CVAR_ARCHIVE | CVAR_CHEAT},
+ {&ui_emoticons, "cg_emoticons", "1", CVAR_LATCH | CVAR_ARCHIVE}, {&ui_winner, "ui_winner", "", CVAR_ROM},
+ {&ui_chatCommands, "ui_chatCommands", "1", CVAR_ARCHIVE}};
+
+static size_t cvarTableSize = ARRAY_LEN(cvarTable);
/*
================
@@ -122,100 +124,118 @@ This is the only way control passes into the module.
This must be the very first function compiled into the .qvm file
================
*/
-vmCvar_t ui_new;
-vmCvar_t ui_debug;
-vmCvar_t ui_initialized;
-vmCvar_t ui_teamArenaFirstRun;
-
-void _UI_Init( qboolean );
-void _UI_Shutdown( void );
-void _UI_KeyEvent( int key, qboolean down );
-void _UI_MouseEvent( int dx, int dy );
-int _UI_MousePosition( void );
-void _UI_SetMousePosition( int x, int y );
-void _UI_Refresh( int realtime );
-qboolean _UI_IsFullscreen( void );
-Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3,
- int arg4, int arg5, int arg6, int arg7,
- int arg8, int arg9, int arg10, int arg11 ) {
- switch ( command ) {
- case UI_GETAPIVERSION:
- return UI_API_VERSION;
-
- case UI_INIT:
- _UI_Init(arg0);
- return 0;
-
- case UI_SHUTDOWN:
- _UI_Shutdown();
- return 0;
-
- case UI_KEY_EVENT:
- _UI_KeyEvent( arg0, arg1 );
- return 0;
-
- case UI_MOUSE_EVENT:
- _UI_MouseEvent( arg0, arg1 );
- return 0;
+void UI_Init(qboolean);
+void UI_Shutdown(void);
+void UI_KeyEvent(int key, qboolean down);
+void UI_MouseEvent(int dx, int dy);
+int UI_MousePosition(void);
+void UI_SetMousePosition(int x, int y);
+void UI_Refresh(int realtime);
+qboolean UI_IsFullscreen(void);
+void UI_SetActiveMenu(uiMenuCommand_t menu);
+
+Q_EXPORT intptr_t vmMain(int command, int arg0, int arg1, int arg2)
+{
+ switch (command)
+ {
+ case UI_GETAPIVERSION:
+ return UI_API_VERSION;
+
+ case UI_INIT:
+ UI_Init(arg0);
+ return 0;
+
+ case UI_SHUTDOWN:
+ UI_Shutdown();
+ return 0;
+
+ case UI_KEY_EVENT:
+ UI_KeyEvent(arg0, arg1);
+ return 0;
+
+ case UI_MOUSE_EVENT:
+ UI_MouseEvent(arg0, arg1);
+ return 0;
#ifndef MODULE_INTERFACE_11
- case UI_MOUSE_POSITION:
- return _UI_MousePosition( );
+ case UI_MOUSE_POSITION:
+ return UI_MousePosition();
- case UI_SET_MOUSE_POSITION:
- _UI_SetMousePosition( arg0, arg1 );
- return 0;
+ case UI_SET_MOUSE_POSITION:
+ UI_SetMousePosition(arg0, arg1);
+ return 0;
#endif
- case UI_REFRESH:
- _UI_Refresh( arg0 );
- return 0;
+ case UI_REFRESH:
+ UI_Refresh(arg0);
+ return 0;
- case UI_IS_FULLSCREEN:
- return _UI_IsFullscreen();
+ case UI_IS_FULLSCREEN:
+ return UI_IsFullscreen();
- case UI_SET_ACTIVE_MENU:
- _UI_SetActiveMenu( arg0 );
- return 0;
+ case UI_SET_ACTIVE_MENU:
+ UI_SetActiveMenu(arg0);
+ return 0;
- case UI_CONSOLE_COMMAND:
- return UI_ConsoleCommand(arg0);
+ case UI_CONSOLE_COMMAND:
+ return UI_ConsoleCommand(arg0);
- case UI_DRAW_CONNECT_SCREEN:
- UI_DrawConnectScreen( arg0 );
- return 0;
- }
+ case UI_DRAW_CONNECT_SCREEN:
+ UI_DrawConnectScreen();
+ return 0;
+ }
- return -1;
+ return -1;
}
+void AssetCache(void)
+{
+ int i;
+ uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(ASSET_GRADIENTBAR);
+ uiInfo.uiDC.Assets.scrollBar = trap_R_RegisterShaderNoMip(ASSET_SCROLLBAR);
+ uiInfo.uiDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip(ASSET_SCROLLBAR_ARROWDOWN);
+ uiInfo.uiDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip(ASSET_SCROLLBAR_ARROWUP);
+ uiInfo.uiDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip(ASSET_SCROLLBAR_ARROWLEFT);
+ uiInfo.uiDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip(ASSET_SCROLLBAR_ARROWRIGHT);
+ uiInfo.uiDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip(ASSET_SCROLL_THUMB);
+ uiInfo.uiDC.Assets.sliderBar = trap_R_RegisterShaderNoMip(ASSET_SLIDER_BAR);
+ uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip(ASSET_SLIDER_THUMB);
+
+ if (ui_emoticons.integer)
+ {
+ uiInfo.uiDC.Assets.emoticonCount = BG_LoadEmoticons(uiInfo.uiDC.Assets.emoticons, MAX_EMOTICONS);
+ }
+ else
+ uiInfo.uiDC.Assets.emoticonCount = 0;
-void AssetCache( void ) {
- uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
- uiInfo.uiDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
- uiInfo.uiDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
- uiInfo.uiDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
- uiInfo.uiDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
- uiInfo.uiDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
- uiInfo.uiDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
- uiInfo.uiDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
- uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
+ for (i = 0; i < uiInfo.uiDC.Assets.emoticonCount; i++)
+ {
+ uiInfo.uiDC.Assets.emoticons[i].shader = trap_R_RegisterShaderNoMip(
+ va("emoticons/%s_%dx1.tga", uiInfo.uiDC.Assets.emoticons[i].name, uiInfo.uiDC.Assets.emoticons[i].width));
+ }
}
-void _UI_DrawSides(float x, float y, float w, float h, float size) {
- UI_AdjustFrom640( &x, &y, &w, &h );
- size *= uiInfo.uiDC.xscale;
- trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
- trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
+void UI_DrawSides(float x, float y, float w, float h, float size)
+{
+ float sizeY;
+
+ UI_AdjustFrom640(&x, &y, &w, &h);
+ sizeY = size * uiInfo.uiDC.yscale;
+ size *= uiInfo.uiDC.xscale;
+
+ trap_R_DrawStretchPic(x, y + sizeY, size, h - (sizeY * 2.0f), 0, 0, 0, 0, uiInfo.uiDC.whiteShader);
+ trap_R_DrawStretchPic(x + w - size, y + sizeY, size, h - (sizeY * 2.0f), 0, 0, 0, 0, uiInfo.uiDC.whiteShader);
}
-void _UI_DrawTopBottom(float x, float y, float w, float h, float size) {
- UI_AdjustFrom640( &x, &y, &w, &h );
- size *= uiInfo.uiDC.yscale;
- trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
- trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
+void UI_DrawTopBottom(float x, float y, float w, float h, float size)
+{
+ UI_AdjustFrom640(&x, &y, &w, &h);
+ size *= uiInfo.uiDC.yscale;
+ trap_R_DrawStretchPic(x, y, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader);
+ trap_R_DrawStretchPic(x, y + h - size, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader);
}
+
/*
================
UI_DrawRect
@@ -223,2884 +243,2077 @@ UI_DrawRect
Coordinates are 640*480 virtual values
=================
*/
-void _UI_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
- trap_R_SetColor( color );
+void UI_DrawRect(float x, float y, float width, float height, float size, const float *color)
+{
+ trap_R_SetColor(color);
- _UI_DrawTopBottom(x, y, width, height, size);
- _UI_DrawSides(x, y, width, height, size);
+ UI_DrawTopBottom(x, y, width, height, size);
+ UI_DrawSides(x, y, width, height, size);
- trap_R_SetColor( NULL );
+ trap_R_SetColor(NULL);
}
+/*
+==================
+UI_ServerInfoIsValid
+Return false if the infostring contains nonprinting characters,
+ or if the hostname is blank/undefined
+==================
+*/
+static qboolean UI_ServerInfoIsValid(char *info)
+{
+ char *c;
+ int len = 0;
-
-int Text_Width(const char *text, float scale, int limit) {
- int count,len;
- float out;
- glyphInfo_t *glyph;
- float useScale;
- const char *s = text;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- out = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s];
- out += glyph->xSkip;
- s++;
- count++;
- }
+ for (c = info; *c; c++)
+ {
+ if (!isprint(*c))
+ return qfalse;
}
- }
- return out * useScale;
-}
-int Text_Height(const char *text, float scale, int limit) {
- int len, count;
- float max;
- glyphInfo_t *glyph;
- float useScale;
- const char *s = text; // bk001206 - unsigned
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- max = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s];
- if (max < glyph->height) {
- max = glyph->height;
- }
- s++;
- count++;
- }
+ for (c = Info_ValueForKey(info, "hostname"); *c; c++)
+ {
+ if (isgraph(*c))
+ len++;
}
- }
- return max * useScale;
-}
-void Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
- float w, h;
- w = width * scale;
- h = height * scale;
- UI_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
+ if (len)
+ return qtrue;
+ else
+ return qfalse;
}
-void Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- float useScale;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- if (text) {
- const char *s = text; // bk001206 - unsigned
- trap_R_SetColor( color );
- memcpy(&newColor[0], &color[0], sizeof(vec4_t));
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s];
- //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
- //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- float yadj = useScale * glyph->top;
- if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
- int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
- colorBlack[3] = newColor[3];
- trap_R_SetColor( colorBlack );
- Text_PaintChar(x + ofs, y - yadj + ofs,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- trap_R_SetColor( newColor );
- colorBlack[3] = 1.0;
- }
- else if( style == ITEM_TEXTSTYLE_NEON )
- {
- vec4_t glow, outer, inner, white;
-
- glow[ 0 ] = newColor[ 0 ] * 0.5;
- glow[ 1 ] = newColor[ 1 ] * 0.5;
- glow[ 2 ] = newColor[ 2 ] * 0.5;
- glow[ 3 ] = newColor[ 3 ] * 0.2;
-
- outer[ 0 ] = newColor[ 0 ];
- outer[ 1 ] = newColor[ 1 ];
- outer[ 2 ] = newColor[ 2 ];
- outer[ 3 ] = newColor[ 3 ];
-
- inner[ 0 ] = newColor[ 0 ] * 1.5 > 1.0f ? 1.0f : newColor[ 0 ] * 1.5;
- inner[ 1 ] = newColor[ 1 ] * 1.5 > 1.0f ? 1.0f : newColor[ 1 ] * 1.5;
- inner[ 2 ] = newColor[ 2 ] * 1.5 > 1.0f ? 1.0f : newColor[ 2 ] * 1.5;
- inner[ 3 ] = newColor[ 3 ];
-
- white[ 0 ] = white[ 1 ] = white[ 2 ] = white[ 3 ] = 1.0f;
-
- trap_R_SetColor( glow );
- Text_PaintChar( x - 1.5, y - yadj - 1.5,
- glyph->imageWidth + 3,
- glyph->imageHeight + 3,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
-
- trap_R_SetColor( outer );
- Text_PaintChar( x - 1, y - yadj - 1,
- glyph->imageWidth + 2,
- glyph->imageHeight + 2,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
-
- trap_R_SetColor( inner );
- Text_PaintChar( x - 0.5, y - yadj - 0.5,
- glyph->imageWidth + 1,
- glyph->imageHeight + 1,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
-
- trap_R_SetColor( white );
- }
-
- Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
-
- x += (glyph->xSkip * useScale) + adjust;
- s++;
- count++;
- }
+/*
+==================
+UI_SanitiseString
+
+Remove color codes and non-alphanumeric characters from a string
+==================
+*/
+void UI_SanitiseString( char *in, char *out, int len )
+{
+ len--;
+
+ while( *in && len > 0 )
+ {
+ if( Q_IsColorString( in ) )
+ {
+ in += 2; // skip color code
+ continue;
+ }
+
+ if( isalnum( *in ) )
+ {
+ *out++ = tolower( *in );
+ len--;
+ }
+ in++;
}
- trap_R_SetColor( NULL );
- }
+ *out = 0;
}
-void Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph, *glyph2;
- float yadj;
- float useScale;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- if (text) {
- const char *s = text; // bk001206 - unsigned
- trap_R_SetColor( color );
- memcpy(&newColor[0], &color[0], sizeof(vec4_t));
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- glyph2 = &font->glyphs[ (int) cursor]; // bk001206 - possible signed char
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s];
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- yadj = useScale * glyph->top;
- if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
- int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
- colorBlack[3] = newColor[3];
- trap_R_SetColor( colorBlack );
- Text_PaintChar(x + ofs, y - yadj + ofs,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- colorBlack[3] = 1.0;
- trap_R_SetColor( newColor );
- }
- else if( style == ITEM_TEXTSTYLE_NEON )
- {
- vec4_t glow, outer, inner, white;
-
- glow[ 0 ] = newColor[ 0 ] * 0.5;
- glow[ 1 ] = newColor[ 1 ] * 0.5;
- glow[ 2 ] = newColor[ 2 ] * 0.5;
- glow[ 3 ] = newColor[ 3 ] * 0.2;
-
- outer[ 0 ] = newColor[ 0 ];
- outer[ 1 ] = newColor[ 1 ];
- outer[ 2 ] = newColor[ 2 ];
- outer[ 3 ] = newColor[ 3 ];
-
- inner[ 0 ] = newColor[ 0 ] * 1.5 > 1.0f ? 1.0f : newColor[ 0 ] * 1.5;
- inner[ 1 ] = newColor[ 1 ] * 1.5 > 1.0f ? 1.0f : newColor[ 1 ] * 1.5;
- inner[ 2 ] = newColor[ 2 ] * 1.5 > 1.0f ? 1.0f : newColor[ 2 ] * 1.5;
- inner[ 3 ] = newColor[ 3 ];
-
- white[ 0 ] = white[ 1 ] = white[ 2 ] = white[ 3 ] = 1.0f;
-
- trap_R_SetColor( glow );
- Text_PaintChar( x - 1.5, y - yadj - 1.5,
- glyph->imageWidth + 3,
- glyph->imageHeight + 3,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
-
- trap_R_SetColor( outer );
- Text_PaintChar( x - 1, y - yadj - 1,
- glyph->imageWidth + 2,
- glyph->imageHeight + 2,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
-
- trap_R_SetColor( inner );
- Text_PaintChar( x - 0.5, y - yadj - 0.5,
- glyph->imageWidth + 1,
- glyph->imageHeight + 1,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph );
-
- trap_R_SetColor( white );
- }
-
- Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
-
- // CG_DrawPic(x, y - yadj, scale * uiDC.Assets.textFont.glyphs[text[i]].imageWidth, scale * uiDC.Assets.textFont.glyphs[text[i]].imageHeight, uiDC.Assets.textFont.glyphs[text[i]].glyph);
- yadj = useScale * glyph2->top;
- if (count == cursorPos && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
- Text_PaintChar(x, y - yadj,
- glyph2->imageWidth,
- glyph2->imageHeight,
- useScale,
- glyph2->s,
- glyph2->t,
- glyph2->s2,
- glyph2->t2,
- glyph2->glyph);
- }
-
- x += (glyph->xSkip * useScale);
- s++;
- count++;
- }
- }
- // need to paint cursor at end of text
- if (cursorPos == len && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
- yadj = useScale * glyph2->top;
- Text_PaintChar(x, y - yadj,
- glyph2->imageWidth,
- glyph2->imageHeight,
- useScale,
- glyph2->s,
- glyph2->t,
- glyph2->s2,
- glyph2->t2,
- glyph2->glyph);
+/*
+==================
+UI_PortFromAddress
+==================
+*/
+static int UI_PortFromAddress(const char *adrStr) {
+ int i;
+ int portLength = 0;
+ char portStr[MAX_ADDRESSLENGTH] = "";
+ qboolean foundPort = qfalse;
+ if (!adrStr || !adrStr[0]) {
+ return -1;
}
+ for (i = 0; adrStr[i] && (adrStr[i] != ' '); i++) {
+ if (!foundPort) {
+ if (adrStr[i] == ':') {
+ foundPort = qtrue;
+ }
- trap_R_SetColor( NULL );
- }
+ continue;
+ }
+
+ portStr[portLength] = adrStr[i];
+ portLength++;
+ }
+
+ if (portLength) {
+ return atoi(portStr);
+ } else {
+ return -1;
+ }
}
+/*
+==================
+UI_ProtocolFromAddress
-static void Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- if (text) {
- const char *s = text; // bk001206 - unsigned
- float max = *maxX;
- float useScale;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale > ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- trap_R_SetColor( color );
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s];
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- float yadj = useScale * glyph->top;
- if (Text_Width(s, useScale, 1) + x > max) {
- *maxX = 0;
- break;
- }
- Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- x += (glyph->xSkip * useScale) + adjust;
- *maxX = x;
- count++;
- s++;
- }
+returns 2 if 1.1 is detected, returns 1 if gpp is detected, otherwise returns 0
+==================
+*/
+static int UI_ProtocolFromAddress(const char *adrStr) {
+ int i;
+
+ if (!adrStr || !adrStr[0]) {
+ return 0;
}
- trap_R_SetColor( NULL );
- }
-}
+ for (i = 0; adrStr[i]; i++) {
+ if (adrStr[i] == '-') {
+ if (adrStr[i+1]) {
+ switch (adrStr[i+1]) {
+ case '1':
+ return 2;
+ case 'g':
+ return 1;
-void UI_ShowPostGame(qboolean newHigh) {
- trap_Cvar_Set ("cg_cameraOrbit", "0");
- trap_Cvar_Set("cg_thirdPerson", "0");
- trap_Cvar_Set( "sv_killserver", "1" );
- uiInfo.soundHighScore = newHigh;
- _UI_SetActiveMenu(UIMENU_POSTGAME);
+ default:
+ return 0;
+ }
+ }
+ }
+ }
+
+ return 0;
}
+
/*
-=================
-_UI_Refresh
-=================
+==================
+UI_RemoveServerFromDisplayList
+==================
*/
+static void UI_RemoveServerFromDisplayList(int num)
+{
+ int i, j;
+ static char info[MAX_STRING_CHARS];
-void UI_DrawCenteredPic(qhandle_t image, int w, int h) {
- int x, y;
- x = (SCREEN_WIDTH - w) / 2;
- y = (SCREEN_HEIGHT - h) / 2;
- UI_DrawHandlePic(x, y, w, h, image);
-}
+ for (i = 0; i < uiInfo.serverStatus.numDisplayServers; i++)
+ {
+ if (uiInfo.serverStatus.displayServers[i] == num)
+ {
+ uiInfo.serverStatus.numDisplayServers--;
-int frameCount = 0;
-int startTime;
+ trap_LAN_GetServerInfo(ui_netSource.integer, num, info, MAX_STRING_CHARS);
-#define UI_FPS_FRAMES 4
-void _UI_Refresh( int realtime )
-{
- static int index;
- static int previousTimes[UI_FPS_FRAMES];
-
- //if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
- // return;
- //}
-
- uiInfo.uiDC.frameTime = realtime - uiInfo.uiDC.realTime;
- uiInfo.uiDC.realTime = realtime;
-
- previousTimes[index % UI_FPS_FRAMES] = uiInfo.uiDC.frameTime;
- index++;
- if ( index > UI_FPS_FRAMES ) {
- int i, total;
- // average multiple frames together to smooth changes out a bit
- total = 0;
- for ( i = 0 ; i < UI_FPS_FRAMES ; i++ ) {
- total += previousTimes[i];
- }
- if ( !total ) {
- total = 1;
- }
- uiInfo.uiDC.FPS = 1000 * UI_FPS_FRAMES / total;
- }
-
-
-
- UI_UpdateCvars();
-
- if (Menu_Count() > 0) {
- // paint all the menus
- Menu_PaintAll();
- // refresh server browser list
- UI_DoServerRefresh();
- // refresh server status
- UI_BuildServerStatus(qfalse);
- // refresh find player list
- UI_BuildFindPlayerList(qfalse);
- }
-
- // draw cursor
- UI_SetColor( NULL );
-
- //TA: don't draw the cursor whilst loading
- if( Menu_Count( ) > 0 && !trap_Cvar_VariableValue( "ui_loading" ) && !trap_Cvar_VariableValue( "ui_hideCursor" ) )
- UI_DrawHandlePic( uiInfo.uiDC.cursorx-16, uiInfo.uiDC.cursory-16, 32, 32, uiInfo.uiDC.Assets.cursor);
-
-#ifndef NDEBUG
- if (uiInfo.uiDC.debug)
- {
- // cursor coordinates
- //FIXME
- //UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );
- }
-#endif
+ for (j = i; j < uiInfo.serverStatus.numDisplayServers; j++)
+ uiInfo.serverStatus.displayServers[j] = uiInfo.serverStatus.displayServers[j+1];
+ return;
+ }
+ }
}
/*
-=================
-_UI_Shutdown
-=================
+==================
+UI_InsertServerIntoDisplayList
+==================
*/
-void _UI_Shutdown( void ) {
- trap_LAN_SaveCachedServers();
-}
+static qboolean UI_InsertServerIntoDisplayList(int num, int position)
+{
+ int i;
+ int hostnameLen;
+ int protocol;
+ int port;
+ char adrstr[MAX_ADDRESSLENGTH];
+ char hostname[MAX_HOSTNAME_LENGTH];
+ char basehostname[MAX_HOSTNAME_LENGTH];
+ static char info[MAX_STRING_CHARS];
+
+ if (position < 0 || position > uiInfo.serverStatus.numDisplayServers)
+ return qfalse;
-char *defaultMenu = NULL;
-
-char *GetMenuBuffer(const char *filename) {
- int len;
- fileHandle_t f;
- static char buf[MAX_MENUFILE];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
- return defaultMenu;
- }
- if ( len >= MAX_MENUFILE ) {
- trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
- trap_FS_FCloseFile( f );
- return defaultMenu;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
- //COM_Compress(buf);
- return buf;
+ trap_LAN_GetServerInfo(ui_netSource.integer, num, info, MAX_STRING_CHARS);
-}
+ if (!UI_ServerInfoIsValid(info)) // don't list servers with invalid info
+ return qfalse;
-qboolean Asset_Parse(int handle) {
- pc_token_t token;
- const char *tempStr;
+ Q_strncpyz(hostname, Info_ValueForKey(info, "hostname"), MAX_HOSTNAME_LENGTH);
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
- if (Q_stricmp(token.string, "{") != 0) {
- return qfalse;
- }
+ hostnameLen = strlen(hostname);
- while ( 1 ) {
+ trap_LAN_GetServerAddressString(
+ ui_netSource.integer, num, adrstr, MAX_ADDRESSLENGTH);
- memset(&token, 0, sizeof(pc_token_t));
+ protocol = UI_ProtocolFromAddress(adrstr);
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
+ port = UI_PortFromAddress(adrstr);
- if (Q_stricmp(token.string, "}") == 0) {
- return qtrue;
+ if (protocol && hostnameLen > 6) {
+ // strip the protocol tags from the hostname
+ hostname[hostnameLen - 6] = '\0';
}
- // font
- if (Q_stricmp(token.string, "font") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
- return qfalse;
- }
- trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.textFont);
- uiInfo.uiDC.Assets.fontRegistered = qtrue;
- continue;
- }
+ UI_SanitiseString(hostname, basehostname, sizeof(basehostname));
- if (Q_stricmp(token.string, "smallFont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
- return qfalse;
- }
- trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.smallFont);
- continue;
- }
+ // check if this is a duplicate listing of a multiprotocol server
+ for (i = 0; i < uiInfo.serverStatus.numDisplayServers; i++) {
+ int j;
+ int clients;
+ int protocol2;
+ int port2;
+ char info2[MAX_STRING_CHARS];
+ char adrstr2[MAX_ADDRESSLENGTH];
- if (Q_stricmp(token.string, "bigFont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
- return qfalse;
- }
- trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.bigFont);
- continue;
- }
+ trap_LAN_GetServerAddressString(
+ ui_netSource.integer,
+ uiInfo.serverStatus.displayServers[i], adrstr2, MAX_ADDRESSLENGTH);
+ protocol2 = UI_ProtocolFromAddress(adrstr2);
- // gradientbar
- if (Q_stricmp(token.string, "gradientbar") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
- continue;
- }
+ port2 = UI_PortFromAddress(adrstr2);
- // enterMenuSound
- if (Q_stricmp(token.string, "menuEnterSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
+ //compare the addresses
+ if (adrstr[0] != adrstr2[0]) {
+ continue;
+ } else {
+ qboolean skip = qfalse;
+
+ for (j = 1; adrstr[j] && adrstr2[j]; j++) {
+ if(adrstr[j] != adrstr2[j]) {
+ skip = qtrue;
+ break;
+ }
+
+ //don't compare ports
+ if (adrstr[j] == ':') {
+ break;
+ }
+ }
- // exitMenuSound
- if (Q_stricmp(token.string, "menuExitSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
+ if (skip) {
+ continue;
+ }
+ }
- // itemFocusSound
- if (Q_stricmp(token.string, "itemFocusSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
+ trap_LAN_GetServerInfo(
+ ui_netSource.integer,
+ uiInfo.serverStatus.displayServers[i], info2, MAX_STRING_CHARS);
- // menuBuzzSound
- if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
+ // if the ports are not the same, check to see if the host names are the
+ // same for older multiprotocol servers
+ if(port != port2) {
+ int hostnameLen2;
+ char hostname2[MAX_HOSTNAME_LENGTH];
+ char basehostname2[MAX_HOSTNAME_LENGTH];
- if (Q_stricmp(token.string, "cursor") == 0) {
- if (!PC_String_Parse(handle, &uiInfo.uiDC.Assets.cursorStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.cursor = trap_R_RegisterShaderNoMip( uiInfo.uiDC.Assets.cursorStr);
- continue;
- }
+ Q_strncpyz(hostname2, Info_ValueForKey(info2, "hostname"), MAX_HOSTNAME_LENGTH);
- if (Q_stricmp(token.string, "fadeClamp") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeClamp)) {
- return qfalse;
- }
- continue;
- }
+ hostnameLen2 = strlen(hostname2);
- if (Q_stricmp(token.string, "fadeCycle") == 0) {
- if (!PC_Int_Parse(handle, &uiInfo.uiDC.Assets.fadeCycle)) {
- return qfalse;
- }
- continue;
- }
+ if (protocol2 && hostnameLen2 > 6) {
+ // strip the protocol tags from the hostname
+ hostname2[hostnameLen2 - 7] = '\0';
+ }
- if (Q_stricmp(token.string, "fadeAmount") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeAmount)) {
- return qfalse;
- }
- continue;
- }
+ UI_SanitiseString(hostname2, basehostname2, sizeof(basehostname2));
- if (Q_stricmp(token.string, "shadowX") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowX)) {
- return qfalse;
- }
- continue;
- }
+ //compare the hostnames
+ if (Q_stricmp(basehostname, basehostname2)) {
+ continue;
+ }
+ }
- if (Q_stricmp(token.string, "shadowY") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowY)) {
- return qfalse;
- }
- continue;
- }
+ uiInfo.serverStatus.numDuplicateMultiprotocolServers++;
- if (Q_stricmp(token.string, "shadowColor") == 0) {
- if (!PC_Color_Parse(handle, &uiInfo.uiDC.Assets.shadowColor)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.shadowFadeClamp = uiInfo.uiDC.Assets.shadowColor[3];
- continue;
+ //show only the most recent protocol for a given server
+ if (protocol >= protocol2) {
+ clients = atoi(Info_ValueForKey(info, "clients"));
+ uiInfo.serverStatus.numDuplicateMultiprotocolServerClients += clients;
+ return qfalse;
+ } else {
+ clients = atoi(Info_ValueForKey(info2, "clients"));
+ uiInfo.serverStatus.numDuplicateMultiprotocolServerClients += clients;
+ UI_RemoveServerFromDisplayList(uiInfo.serverStatus.displayServers[i]);
+ i--;
+ continue;
+ }
}
- }
- return qfalse;
-}
+ //insert the server
+ uiInfo.serverStatus.numDisplayServers++;
-void Font_Report( void ) {
- int i;
- Com_Printf("Font Info\n");
- Com_Printf("=========\n");
- for ( i = 32; i < 96; i++) {
- Com_Printf("Glyph handle %i: %i\n", i, uiInfo.uiDC.Assets.textFont.glyphs[i].glyph);
- }
-}
+ for (i = uiInfo.serverStatus.numDisplayServers; i > position; i--)
+ uiInfo.serverStatus.displayServers[i] = uiInfo.serverStatus.displayServers[i - 1];
-void UI_Report( void ) {
- String_Report();
- //Font_Report();
+ uiInfo.serverStatus.displayServers[position] = num;
+ return qtrue;
}
-void UI_ParseMenu(const char *menuFile) {
- int handle;
- pc_token_t token;
-
- /*Com_Printf("Parsing menu file:%s\n", menuFile);*/
+/*
+==================
+UI_BinaryServerInsertion
+==================
+*/
+static qboolean UI_BinaryServerInsertion(int num)
+{
+ int mid, offset, res, len;
- handle = trap_Parse_LoadSource(menuFile);
- if (!handle) {
- return;
- }
+ // use binary search to insert server
+ len = uiInfo.serverStatus.numDisplayServers;
+ mid = len;
+ offset = 0;
+ res = 0;
- while ( 1 ) {
- memset(&token, 0, sizeof(pc_token_t));
- if (!trap_Parse_ReadToken( handle, &token )) {
- break;
- }
+ while (mid > 0)
+ {
+ mid = len >> 1;
+ //
+ res = trap_LAN_CompareServers(ui_netSource.integer, uiInfo.serverStatus.sortKey, uiInfo.serverStatus.sortDir,
+ num, uiInfo.serverStatus.displayServers[offset + mid]);
+ // if equal
- //if ( Q_stricmp( token, "{" ) ) {
- // Com_Printf( "Missing { in menu file\n" );
- // break;
- //}
+ if (res == 0)
+ {
+ return UI_InsertServerIntoDisplayList(num, offset + mid);
+ }
- //if ( menuCount == MAX_MENUS ) {
- // Com_Printf( "Too many menus!\n" );
- // break;
- //}
+ // if larger
+ else if (res == 1)
+ {
+ offset += mid;
+ len -= mid;
+ }
- if ( token.string[0] == '}' ) {
- break;
+ // if smaller
+ else
+ len -= mid;
}
- if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
- if (Asset_Parse(handle)) {
- continue;
- } else {
- break;
- }
- }
+ if (res == 1)
+ offset++;
- if (Q_stricmp(token.string, "menudef") == 0) {
- // start a new menu
- Menu_New(handle);
- }
- }
- trap_Parse_FreeSource(handle);
+ return UI_InsertServerIntoDisplayList(num, offset);
+}
+
+typedef struct {
+ char *name, *altName;
}
+serverStatusCvar_t;
+
+serverStatusCvar_t serverStatusCvars[] = {{"sv_hostname", "Name"}, {"Address", ""}, {"gamename", "Game name"},
+ {"mapname", "Map"}, {"version", ""}, {"protocol", ""}, {"timelimit", ""}, {NULL, NULL}};
+
/*
-===============
-UI_FindInfoPaneByName
-===============
+==================
+UI_SortServerStatusInfo
+==================
*/
-tremInfoPane_t *UI_FindInfoPaneByName( const char *name )
+
+static int UI_SortServerStatusCompare(const void *a, const void *b)
+{
+ const char **la = (const char **)a;
+ const char **lb = (const char **)b;
+
+ return strcmp(la[0], lb[0]);
+}
+
+static void UI_SortServerStatusInfo(serverStatusInfo_t *info)
{
- int i;
+ int i, j, index;
+ char *tmp1, *tmp2;
- for( i = 0; i < uiInfo.tremInfoPaneCount; i++ )
- {
- if( !Q_stricmp( uiInfo.tremInfoPanes[ i ].name, name ) )
- return &uiInfo.tremInfoPanes[ i ];
- }
+ index = 0;
- //create a dummy infopane demanding the user write the infopane
- uiInfo.tremInfoPanes[ i ].name = String_Alloc( name );
- strncpy( uiInfo.tremInfoPanes[ i ].text, "Not implemented.\n\nui/infopanes.def\n", MAX_INFOPANE_TEXT );
- Q_strcat( uiInfo.tremInfoPanes[ i ].text, MAX_INFOPANE_TEXT, String_Alloc( name ) );
+ for (i = 0; serverStatusCvars[i].name; i++)
+ {
+ for (j = 0; j < info->numLines; j++)
+ {
+ if (!info->lines[j][1] || info->lines[j][1][0])
+ continue;
- uiInfo.tremInfoPaneCount++;
+ if (!Q_stricmp(serverStatusCvars[i].name, info->lines[j][0]))
+ {
+ // swap lines
+ tmp1 = info->lines[index][0];
+ tmp2 = info->lines[index][3];
+ info->lines[index][0] = info->lines[j][0];
+ info->lines[index][3] = info->lines[j][3];
+ info->lines[j][0] = tmp1;
+ info->lines[j][3] = tmp2;
+ //
+
+ if (strlen(serverStatusCvars[i].altName))
+ info->lines[index][0] = serverStatusCvars[i].altName;
+
+ index++;
+ }
+ }
+ }
- return &uiInfo.tremInfoPanes[ i ];
+ // sort remaining cvars
+ qsort(info->lines + index, info->numLines - index, sizeof(info->lines[0]), UI_SortServerStatusCompare);
}
/*
-===============
-UI_LoadInfoPane
-===============
+==================
+UI_GetServerStatusInfo
+==================
*/
-qboolean UI_LoadInfoPane( int handle )
+static int UI_GetServerStatusInfo(const char *serverAddress, serverStatusInfo_t *info)
{
- pc_token_t token;
- qboolean valid = qfalse;
+ char *p, *score, *ping, *name;
+ int i, len;
- while( 1 )
- {
- memset( &token, 0, sizeof( pc_token_t ) );
+ if (!info)
+ {
+ trap_LAN_ServerStatus(serverAddress, NULL, 0);
+ return qfalse;
+ }
- if( !trap_Parse_ReadToken( handle, &token ) )
- break;
+ memset(info, 0, sizeof(*info));
- if( !Q_stricmp( token.string, "name" ) )
+ if (trap_LAN_ServerStatus(serverAddress, info->text, sizeof(info->text)))
{
- memset( &token, 0, sizeof( pc_token_t ) );
+ Q_strncpyz(info->address, serverAddress, sizeof(info->address));
+ p = info->text;
+ info->numLines = 0;
+ info->lines[info->numLines][0] = "Address";
+ info->lines[info->numLines][1] = "";
+ info->lines[info->numLines][2] = "";
+ info->lines[info->numLines][3] = info->address;
+ info->numLines++;
+ // get the cvars
- if( !trap_Parse_ReadToken( handle, &token ) )
- break;
+ while (p && *p)
+ {
+ p = strchr(p, '\\');
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].name = String_Alloc( token.string );
- valid = qtrue;
- }
- else if( !Q_stricmp( token.string, "graphic" ) )
- {
- int *graphic;
+ if (!p)
+ break;
- memset( &token, 0, sizeof( pc_token_t ) );
+ *p++ = '\0';
- if( !trap_Parse_ReadToken( handle, &token ) )
- break;
+ if (*p == '\\')
+ break;
- graphic = &uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].numGraphics;
+ info->lines[info->numLines][0] = p;
+ info->lines[info->numLines][1] = "";
+ info->lines[info->numLines][2] = "";
- if( !Q_stricmp( token.string, "top" ) )
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].side = INFOPANE_TOP;
- else if( !Q_stricmp( token.string, "bottom" ) )
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].side = INFOPANE_BOTTOM;
- else if( !Q_stricmp( token.string, "left" ) )
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].side = INFOPANE_LEFT;
- else if( !Q_stricmp( token.string, "right" ) )
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].side = INFOPANE_RIGHT;
- else
- break;
+ p = strchr(p, '\\');
- memset( &token, 0, sizeof( pc_token_t ) );
+ if (!p)
+ break;
- if( !trap_Parse_ReadToken( handle, &token ) )
- break;
+ *p++ = '\0';
- if( !Q_stricmp( token.string, "center" ) )
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].offset = -1;
- else
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].offset = token.intvalue;
+ info->lines[info->numLines][3] = p;
+ info->numLines++;
- memset( &token, 0, sizeof( pc_token_t ) );
+ if (info->numLines >= MAX_SERVERSTATUS_LINES)
+ break;
+ }
- if( !trap_Parse_ReadToken( handle, &token ) )
- break;
+ UI_SortServerStatusInfo(info);
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].graphic =
- trap_R_RegisterShaderNoMip( token.string );
+ // get the player list
+ if (info->numLines < MAX_SERVERSTATUS_LINES - 3)
+ {
+ // empty line
+ info->lines[info->numLines][0] = "";
+ info->lines[info->numLines][1] = "";
+ info->lines[info->numLines][2] = "";
+ info->lines[info->numLines][3] = "";
+ info->numLines++;
+ // header
+ info->lines[info->numLines][0] = "num";
+ info->lines[info->numLines][1] = "score";
+ info->lines[info->numLines][2] = "ping";
+ info->lines[info->numLines][3] = "name";
+ info->numLines++;
+ // parse players
+ i = 0;
+ len = 0;
+
+ while (p && *p)
+ {
+ if (*p == '\\')
+ *p++ = '\0';
- memset( &token, 0, sizeof( pc_token_t ) );
+ if (!p)
+ break;
- if( !trap_Parse_ReadToken( handle, &token ) )
- break;
+ score = p;
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].width = token.intvalue;
+ p = strchr(p, ' ');
- memset( &token, 0, sizeof( pc_token_t ) );
+ if (!p)
+ break;
- if( !trap_Parse_ReadToken( handle, &token ) )
- break;
+ *p++ = '\0';
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].height = token.intvalue;
+ ping = p;
- //increment graphics
- (*graphic)++;
+ p = strchr(p, ' ');
- if( *graphic == MAX_INFOPANE_GRAPHICS )
- break;
- }
- else if( !Q_stricmp( token.string, "text" ) )
- {
- memset( &token, 0, sizeof( pc_token_t ) );
+ if (!p)
+ break;
- if( !trap_Parse_ReadToken( handle, &token ) )
- break;
+ *p++ = '\0';
- Q_strcat( uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].text, MAX_INFOPANE_TEXT, token.string );
- }
- else if( !Q_stricmp( token.string, "align" ) )
- {
- memset( &token, 0, sizeof( pc_token_t ) );
+ name = p;
- if( !trap_Parse_ReadToken( handle, &token ) )
- break;
+ Com_sprintf(&info->pings[len], sizeof(info->pings) - len, "%d", i);
- if( !Q_stricmp( token.string, "left" ) )
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].align = ITEM_ALIGN_LEFT;
- else if( !Q_stricmp( token.string, "right" ) )
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].align = ITEM_ALIGN_RIGHT;
- else if( !Q_stricmp( token.string, "center" ) )
- uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].align = ITEM_ALIGN_CENTER;
- }
- else if( token.string[ 0 ] == '}' )
- {
- //reached the end, break
- break;
+ info->lines[info->numLines][0] = &info->pings[len];
+
+ len += strlen(&info->pings[len]) + 1;
+
+ info->lines[info->numLines][1] = score;
+ info->lines[info->numLines][2] = ping;
+ info->lines[info->numLines][3] = name;
+ info->numLines++;
+
+ if (info->numLines >= MAX_SERVERSTATUS_LINES)
+ break;
+
+ p = strchr(p, '\\');
+
+ if (!p)
+ break;
+
+ *p++ = '\0';
+
+ //
+ i++;
+ }
+ }
+
+ return qtrue;
}
- else
- break;
- }
- if( valid )
- {
- uiInfo.tremInfoPaneCount++;
- return qtrue;
- }
- else
- {
return qfalse;
- }
}
/*
-===============
-UI_LoadInfoPanes
-===============
+==================
+stristr
+==================
*/
-void UI_LoadInfoPanes( const char *file )
+static char *stristr(char *str, char *charset)
{
- pc_token_t token;
- int handle;
- int count;
+ int i;
- uiInfo.tremInfoPaneCount = count = 0;
+ while (*str)
+ {
+ for (i = 0; charset[i] && str[i]; i++)
+ if (toupper(charset[i]) != toupper(str[i]))
+ break;
- handle = trap_Parse_LoadSource( file );
+ if (!charset[i])
+ return str;
- if( !handle )
- {
- trap_Error( va( S_COLOR_YELLOW "infopane file not found: %s\n", file ) );
- return;
- }
+ str++;
+ }
- while( 1 )
- {
- if( !trap_Parse_ReadToken( handle, &token ) )
- break;
+ return NULL;
+}
- if( token.string[ 0 ] == 0 )
- break;
+/*
+==================
+UI_BuildFindPlayerList
+==================
+*/
+static void UI_FeederSelection(int feederID, int index);
- if( token.string[ 0 ] == '{' )
+static void UI_BuildFindPlayerList(qboolean force)
+{
+ static int numFound, numTimeOuts;
+ int i, j, k, resend;
+ serverStatusInfo_t info;
+ char name[MAX_NAME_LENGTH + 2];
+ char infoString[MAX_STRING_CHARS];
+ qboolean duplicate;
+
+ if (!force)
{
- if( UI_LoadInfoPane( handle ) )
- count++;
-
- if( count == MAX_INFOPANES )
- break;
+ if (!uiInfo.nextFindPlayerRefresh || uiInfo.nextFindPlayerRefresh > uiInfo.uiDC.realTime)
+ return;
}
- }
+ else
+ {
+ memset(&uiInfo.pendingServerStatus, 0, sizeof(uiInfo.pendingServerStatus));
+ uiInfo.numFoundPlayerServers = 0;
+ uiInfo.currentFoundPlayerServer = 0;
+ trap_Cvar_VariableStringBuffer("ui_findPlayer", uiInfo.findPlayerName, sizeof(uiInfo.findPlayerName));
+ Q_CleanStr(uiInfo.findPlayerName);
+ // should have a string of some length
+
+ if (!strlen(uiInfo.findPlayerName))
+ {
+ uiInfo.nextFindPlayerRefresh = 0;
+ return;
+ }
- trap_Parse_FreeSource( handle );
-}
+ // set resend time
+ resend = ui_serverStatusTimeOut.integer / 2 - 10;
-qboolean Load_Menu(int handle) {
- pc_token_t token;
+ if (resend < 50)
+ resend = 50;
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
- if (token.string[0] != '{') {
- return qfalse;
- }
+ trap_Cvar_Set("cl_serverStatusResendTime", va("%d", resend));
+ // reset all server status requests
+ trap_LAN_ServerStatus(NULL, NULL, 0);
+ //
+ uiInfo.numFoundPlayerServers = 1;
+ Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1],
+ sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1]), "searching %d...",
+ uiInfo.pendingServerStatus.num);
+ numFound = 0;
+ numTimeOuts++;
+ }
- while ( 1 ) {
+ for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++)
+ {
+ // if this pending server is valid
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
+ if (uiInfo.pendingServerStatus.server[i].valid)
+ {
+ // try to get the server status for this server
- if ( token.string[0] == 0 ) {
- return qfalse;
- }
+ if (UI_GetServerStatusInfo(uiInfo.pendingServerStatus.server[i].adrstr, &info))
+ {
+ //
+ numFound++;
+ // parse through the server status lines
+
+ for (j = 0; j < info.numLines; j++)
+ {
+ // should have ping info
+
+ if (!info.lines[j][2] || !info.lines[j][2][0])
+ continue;
+
+ // clean string first
+ Q_strncpyz(name, info.lines[j][3], sizeof(name));
+
+ Q_CleanStr(name);
+
+ duplicate = qfalse;
+
+ for (k = 0; k < uiInfo.numFoundPlayerServers - 1; k++)
+ {
+ if (Q_strncmp(uiInfo.foundPlayerServerAddresses[k], uiInfo.pendingServerStatus.server[i].adrstr,
+ MAX_ADDRESSLENGTH) == 0)
+ duplicate = qtrue;
+ }
+
+ // if the player name is a substring
+ if (stristr(name, uiInfo.findPlayerName) && !duplicate)
+ {
+ // add to found server list if we have space (always leave space for a line with the number
+ // found)
+
+ if (uiInfo.numFoundPlayerServers < MAX_FOUNDPLAYER_SERVERS - 1)
+ {
+ //
+ Q_strncpyz(uiInfo.foundPlayerServerAddresses[uiInfo.numFoundPlayerServers - 1],
+ uiInfo.pendingServerStatus.server[i].adrstr,
+ sizeof(uiInfo.foundPlayerServerAddresses[0]));
+ Q_strncpyz(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1],
+ uiInfo.pendingServerStatus.server[i].name, sizeof(uiInfo.foundPlayerServerNames[0]));
+ uiInfo.numFoundPlayerServers++;
+ }
+ else
+ {
+ // can't add any more so we're done
+ uiInfo.pendingServerStatus.num = uiInfo.serverStatus.numDisplayServers;
+ }
+ }
+ }
+
+ Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1],
+ sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1]), "searching %d/%d...",
+ numFound, uiInfo.pendingServerStatus.num);
+ // retrieved the server status so reuse this spot
+ uiInfo.pendingServerStatus.server[i].valid = qfalse;
+ }
+ }
- if ( token.string[0] == '}' ) {
- return qtrue;
- }
+ // if empty pending slot or timed out
+ if (!uiInfo.pendingServerStatus.server[i].valid ||
+ uiInfo.pendingServerStatus.server[i].startTime < uiInfo.uiDC.realTime - ui_serverStatusTimeOut.integer)
+ {
+ if (uiInfo.pendingServerStatus.server[i].valid)
+ numTimeOuts++;
- UI_ParseMenu(token.string);
- }
- return qfalse;
-}
+ // reset server status request for this address
+ UI_GetServerStatusInfo(uiInfo.pendingServerStatus.server[i].adrstr, NULL);
-void UI_LoadMenus(const char *menuFile, qboolean reset) {
- pc_token_t token;
- int handle;
- int start;
+ // reuse pending slot
+ uiInfo.pendingServerStatus.server[i].valid = qfalse;
- start = trap_Milliseconds();
+ // if we didn't try to get the status of all servers in the main browser yet
+ if (uiInfo.pendingServerStatus.num < uiInfo.serverStatus.numDisplayServers)
+ {
+ uiInfo.pendingServerStatus.server[i].startTime = uiInfo.uiDC.realTime;
+ trap_LAN_GetServerAddressString(ui_netSource.integer,
+ uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num],
+ uiInfo.pendingServerStatus.server[i].adrstr, sizeof(uiInfo.pendingServerStatus.server[i].adrstr));
+
+ trap_LAN_GetServerInfo(ui_netSource.integer,
+ uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num], infoString, sizeof(infoString));
+
+ Q_strncpyz(uiInfo.pendingServerStatus.server[i].name, Info_ValueForKey(infoString, "hostname"),
+ sizeof(uiInfo.pendingServerStatus.server[0].name));
+
+ uiInfo.pendingServerStatus.server[i].valid = qtrue;
+ uiInfo.pendingServerStatus.num++;
+ Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1],
+ sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1]), "searching %d/%d...",
+ numFound, uiInfo.pendingServerStatus.num);
+ }
+ }
+ }
- handle = trap_Parse_LoadSource( menuFile );
- if (!handle) {
- trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
- handle = trap_Parse_LoadSource( "ui/menus.txt" );
- if (!handle) {
- trap_Error( va( S_COLOR_RED "default menu file not found: ui/menus.txt, unable to continue!\n" ) );
+ for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++)
+ {
+ if (uiInfo.pendingServerStatus.server[i].valid)
+ break;
}
- }
- ui_new.integer = 1;
+ // if still trying to retrieve server status info
+ if (i < MAX_SERVERSTATUSREQUESTS)
+ uiInfo.nextFindPlayerRefresh = uiInfo.uiDC.realTime + 25;
+ else
+ {
+ // add a line that shows the number of servers found
- if (reset) {
- Menu_Reset();
- }
+ if (!uiInfo.numFoundPlayerServers)
+ {
+ Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1],
+ sizeof(uiInfo.foundPlayerServerAddresses[0]), "no servers found");
+ }
+ else
+ {
+ Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1],
+ sizeof(uiInfo.foundPlayerServerAddresses[0]), "%d server%s found with player %s",
+ uiInfo.numFoundPlayerServers - 1, uiInfo.numFoundPlayerServers == 2 ? "" : "s", uiInfo.findPlayerName);
+ }
- while ( 1 ) {
- if (!trap_Parse_ReadToken(handle, &token))
- break;
- if( token.string[0] == 0 || token.string[0] == '}') {
- break;
+ uiInfo.nextFindPlayerRefresh = 0;
+ // show the server status info for the selected server
+ UI_FeederSelection(FEEDER_FINDPLAYER, uiInfo.currentFoundPlayerServer);
}
+}
- if ( token.string[0] == '}' ) {
- break;
- }
+/*
+==================
+UI_BuildServerStatus
+==================
+*/
+static void UI_BuildServerStatus(qboolean force)
+{
+ if (uiInfo.nextFindPlayerRefresh)
+ return;
- if (Q_stricmp(token.string, "loadmenu") == 0) {
- if (Load_Menu(handle)) {
- continue;
- } else {
- break;
- }
+ if (!force)
+ {
+ if (!uiInfo.nextServerStatusRefresh || uiInfo.nextServerStatusRefresh > uiInfo.uiDC.realTime)
+ return;
+ }
+ else
+ {
+ Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
+ uiInfo.serverStatusInfo.numLines = 0;
+ // reset all server status requests
+ trap_LAN_ServerStatus(NULL, NULL, 0);
}
- }
- Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
+ if (uiInfo.serverStatus.currentServer < 0 ||
+ uiInfo.serverStatus.currentServer > uiInfo.serverStatus.numDisplayServers ||
+ uiInfo.serverStatus.numDisplayServers == 0)
+ return;
- trap_Parse_FreeSource( handle );
+ if (UI_GetServerStatusInfo(uiInfo.serverStatusAddress, &uiInfo.serverStatusInfo))
+ {
+ uiInfo.nextServerStatusRefresh = 0;
+ UI_GetServerStatusInfo(uiInfo.serverStatusAddress, NULL);
+ }
+ else
+ uiInfo.nextServerStatusRefresh = uiInfo.uiDC.realTime + 500;
}
-void UI_Load( void ) {
- char lastName[1024];
- menuDef_t *menu = Menu_GetFocused();
- char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
- if (menu && menu->window.name) {
- strcpy(lastName, menu->window.name);
- }
- if (menuSet == NULL || menuSet[0] == '\0') {
- menuSet = "ui/menus.txt";
- }
+/*
+==================
+UI_BuildServerDisplayList
+==================
+*/
+static void UI_BuildServerDisplayList(int force)
+{
+ int i, count, clients, maxClients, ping, len, visible;
+ char info[MAX_STRING_CHARS];
+ static int numinvisible;
- String_Init();
+ if (!(force || uiInfo.uiDC.realTime > uiInfo.serverStatus.nextDisplayRefresh))
+ return;
-/* UI_ParseGameInfo("gameinfo.txt");
- UI_LoadArenas();*/
+ // if we shouldn't reset
+ if (force == 2)
+ force = 0;
- UI_LoadMenus(menuSet, qtrue);
- Menus_CloseAll();
- Menus_ActivateByName(lastName);
+ // do motd updates here too
+ trap_Cvar_VariableStringBuffer("cl_motdString", uiInfo.serverStatus.motd, sizeof(uiInfo.serverStatus.motd));
-}
+ len = strlen(uiInfo.serverStatus.motd);
-static const char *handicapValues[] = {"None","95","90","85","80","75","70","65","60","55","50","45","40","35","30","25","20","15","10","5",NULL};
+ if (len != uiInfo.serverStatus.motdLen)
+ {
+ uiInfo.serverStatus.motdLen = len;
+ uiInfo.serverStatus.motdWidth = -1;
+ }
-static void UI_DrawHandicap(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i, h;
+ if (force)
+ {
+ numinvisible = 0;
+ // clear number of displayed servers
+ uiInfo.serverStatus.numDisplayServers = 0;
+ uiInfo.serverStatus.numPlayersOnServers = 0;
+ uiInfo.serverStatus.numDuplicateMultiprotocolServers = 0;
+ uiInfo.serverStatus.numDuplicateMultiprotocolServerClients = 0;
+ // set list box index to zero
+ Menu_SetFeederSelection(NULL, FEEDER_SERVERS, 0, NULL);
+ // mark all servers as visible so we store ping updates for them
+ trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
+ }
+
+ // get the server count (comes from the master)
+ count = trap_LAN_GetServerCount(ui_netSource.integer);
+
+ if (count == -1 || (ui_netSource.integer == AS_LOCAL && count == 0))
+ {
+ // still waiting on a response from the master
+ uiInfo.serverStatus.numDisplayServers = 0;
+ uiInfo.serverStatus.numPlayersOnServers = 0;
+ uiInfo.serverStatus.numDuplicateMultiprotocolServers = 0;
+ uiInfo.serverStatus.numDuplicateMultiprotocolServerClients = 0;
+ uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 500;
+ return;
+ }
- h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
- i = 20 - h / 5;
+ visible = qfalse;
- Text_Paint(rect->x, rect->y, scale, color, handicapValues[i], 0, 0, textStyle);
-}
+ for (i = 0; i < count; i++)
+ {
+ // if we already got info for this server
-static void UI_DrawClanName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_teamName"), 0, 0, textStyle);
-}
+ if (!trap_LAN_ServerIsVisible(ui_netSource.integer, i))
+ continue;
+ visible = qtrue;
+ // get the ping for this server
+ ping = trap_LAN_GetServerPing(ui_netSource.integer, i);
-static void UI_SetCapFragLimits(qboolean uiVars) {
- int cap = 5;
- int frag = 10;
- if (uiVars) {
- trap_Cvar_Set("ui_captureLimit", va("%d", cap));
- trap_Cvar_Set("ui_fragLimit", va("%d", frag));
- } else {
- trap_Cvar_Set("capturelimit", va("%d", cap));
- trap_Cvar_Set("fraglimit", va("%d", frag));
- }
-}
-// ui_gameType assumes gametype 0 is -1 ALL and will not show
-static void UI_DrawGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_gameType.integer].gameType, 0, 0, textStyle);
-}
+ if (ping > 0 || ui_netSource.integer == AS_FAVORITES)
+ {
+ trap_LAN_GetServerInfo(ui_netSource.integer, i, info, MAX_STRING_CHARS);
-static void UI_DrawNetGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_netGameType.integer < 0 || ui_netGameType.integer > uiInfo.numGameTypes) {
- trap_Cvar_Set("ui_netGameType", "0");
- trap_Cvar_Set("ui_actualNetGameType", "0");
- }
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_netGameType.integer].gameType , 0, 0, textStyle);
-}
+ clients = atoi(Info_ValueForKey(info, "clients"));
+ uiInfo.serverStatus.numPlayersOnServers += clients;
-static void UI_DrawJoinGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_joinGameType.integer < 0 || ui_joinGameType.integer > uiInfo.numJoinGameTypes) {
- trap_Cvar_Set("ui_joinGameType", "0");
- }
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.joinGameTypes[ui_joinGameType.integer].gameType , 0, 0, textStyle);
-}
+ if (ui_browserShowEmpty.integer == 0)
+ {
+ if (clients == 0)
+ {
+ trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
+ continue;
+ }
+ }
+ if (ui_browserShowFull.integer == 0)
+ {
+ maxClients = atoi(Info_ValueForKey(info, "sv_maxclients"));
+ if (clients == maxClients)
+ {
+ trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
+ continue;
+ }
+ }
-static int UI_TeamIndexFromName(const char *name) {
- int i;
+ // make sure we never add a favorite server twice
+ if (ui_netSource.integer == AS_FAVORITES)
+ UI_RemoveServerFromDisplayList(i);
- if (name && *name) {
- for (i = 0; i < uiInfo.teamCount; i++) {
- if (Q_stricmp(name, uiInfo.teamList[i].teamName) == 0) {
- return i;
- }
+ // insert the server into the list
+ UI_BinaryServerInsertion(i);
+
+ // done with this server
+ if (ping > 0)
+ {
+ trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
+ numinvisible++;
+ }
+ }
}
- }
- return 0;
+ uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime;
+
+ // if there were no servers visible for ping updates
+ if (!visible)
+ {
+ // UI_StopServerRefresh();
+ // uiInfo.serverStatus.nextDisplayRefresh = 0;
+ }
}
-static void UI_DrawClanLogo(rectDef_t *rect, float scale, vec4_t color) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (i >= 0 && i < uiInfo.teamCount) {
- trap_R_SetColor( color );
+/*
+=================
+UI_StopServerRefresh
+=================
+*/
+static void UI_StopServerRefresh(void)
+{
+ int count;
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
+ if (!uiInfo.serverStatus.refreshActive)
+ {
+ // not currently refreshing
+ return;
}
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
- trap_R_SetColor(NULL);
- }
+ uiInfo.serverStatus.refreshActive = qfalse;
+ Com_Printf("%d servers listed in browser with %d players.\n", uiInfo.serverStatus.numDisplayServers,
+ uiInfo.serverStatus.numPlayersOnServers -
+ uiInfo.serverStatus.numDuplicateMultiprotocolServerClients);
+ count = trap_LAN_GetServerCount(ui_netSource.integer);
+
+ if (count - uiInfo.serverStatus.numDisplayServers - uiInfo.serverStatus.numDuplicateMultiprotocolServers > 0)
+ {
+ Com_Printf(
+ "%d servers not listed due to packet loss, invalid info,"
+ " or pings higher than %d\n",
+ count - uiInfo.serverStatus.numDisplayServers - uiInfo.serverStatus.numDuplicateMultiprotocolServers,
+ (int)trap_Cvar_VariableValue("cl_maxPing"));
+ }
}
-static void UI_DrawClanCinematic(rectDef_t *rect, float scale, vec4_t color) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (i >= 0 && i < uiInfo.teamCount) {
+/*
+=================
+UI_DoServerRefresh
+=================
+*/
+static void UI_DoServerRefresh(void)
+{
+ qboolean wait = qfalse;
+
+ if (!uiInfo.serverStatus.refreshActive)
+ return;
- if (uiInfo.teamList[i].cinematic >= -2) {
- if (uiInfo.teamList[i].cinematic == -1) {
- uiInfo.teamList[i].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.teamList[i].imageName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- }
- if (uiInfo.teamList[i].cinematic >= 0) {
- trap_CIN_RunCinematic(uiInfo.teamList[i].cinematic);
- trap_CIN_SetExtents(uiInfo.teamList[i].cinematic, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.teamList[i].cinematic);
- } else {
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal);
- trap_R_SetColor(NULL);
- uiInfo.teamList[i].cinematic = -2;
- }
- } else {
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
- trap_R_SetColor(NULL);
+ if (ui_netSource.integer != AS_FAVORITES)
+ {
+ if (ui_netSource.integer == AS_LOCAL)
+ {
+ if (!trap_LAN_GetServerCount(ui_netSource.integer))
+ wait = qtrue;
+ }
+ else
+ {
+ if (trap_LAN_GetServerCount(ui_netSource.integer) < 0)
+ wait = qtrue;
+ }
}
- }
-}
+ if (uiInfo.uiDC.realTime < uiInfo.serverStatus.refreshtime)
+ {
+ if (wait)
+ return;
+ }
-static void UI_DrawPreviewCinematic(rectDef_t *rect, float scale, vec4_t color) {
- if (uiInfo.previewMovie > -2) {
- uiInfo.previewMovie = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.movieList[uiInfo.movieIndex]), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- if (uiInfo.previewMovie >= 0) {
- trap_CIN_RunCinematic(uiInfo.previewMovie);
- trap_CIN_SetExtents(uiInfo.previewMovie, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.previewMovie);
- } else {
- uiInfo.previewMovie = -2;
+ // if still trying to retrieve pings
+ if (trap_LAN_UpdateVisiblePings(ui_netSource.integer))
+ uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
+ else if (!wait)
+ {
+ // get the last servers in the list
+ UI_BuildServerDisplayList(2);
+ // stop the refresh
+ UI_StopServerRefresh();
}
- }
+ //
+ UI_BuildServerDisplayList(qfalse);
}
+/*
+=================
+UI_UpdatePendingPings
+=================
+*/
+static void UI_UpdatePendingPings(void)
+{
+ trap_LAN_ResetPings(ui_netSource.integer);
+ uiInfo.serverStatus.refreshActive = qtrue;
+ uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
+}
-#define GRAPHIC_BWIDTH 8.0f
/*
-===============
-UI_DrawInfoPane
-===============
+=================
+UI_StartServerRefresh
+=================
*/
-static void UI_DrawInfoPane( tremInfoPane_t *pane, rectDef_t *rect, float text_x, float text_y,
- float scale, vec4_t color, int textStyle )
+static void UI_StartServerRefresh(qboolean full)
{
- int i;
- float maxLeft = 0, maxTop = 0;
- float maxRight = 0, maxBottom = 0;
- float x = rect->x - text_x, y = rect->y - text_y, w, h;
- float xoffset = 0, yoffset = 0;
- menuDef_t dummyParent;
- itemDef_t textItem;
+ int time;
+ qtime_t q;
- //iterate through graphics
- for( i = 0; i < pane->numGraphics; i++ )
- {
- float width = pane->graphics[ i ].width;
- float height = pane->graphics[ i ].height;
- qhandle_t graphic = pane->graphics[ i ].graphic;
+ time = trap_RealTime(&q);
+ trap_Cvar_Set(va("ui_lastServerRefresh_%i_time", ui_netSource.integer), va("%i", time));
+ trap_Cvar_Set(va("ui_lastServerRefresh_%i", ui_netSource.integer),
+ va("%04i-%02i-%02i %02i:%02i:%02i", q.tm_year + 1900, q.tm_mon + 1, q.tm_mday, q.tm_hour, q.tm_min, q.tm_sec));
- if( pane->graphics[ i ].side == INFOPANE_TOP || pane->graphics[ i ].side == INFOPANE_BOTTOM )
+ if (!full)
{
- //set horizontal offset of graphic
- if( pane->graphics[ i ].offset < 0 )
- xoffset = ( rect->w / 2 ) - ( pane->graphics[ i ].width / 2 );
- else
- xoffset = pane->graphics[ i ].offset + GRAPHIC_BWIDTH;
+ UI_UpdatePendingPings();
+ return;
}
- else if( pane->graphics[ i ].side == INFOPANE_LEFT || pane->graphics[ i ].side == INFOPANE_RIGHT )
+
+ uiInfo.serverStatus.refreshActive = qtrue;
+ uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 1000;
+ // clear number of displayed servers
+ uiInfo.serverStatus.numDisplayServers = 0;
+ uiInfo.serverStatus.numPlayersOnServers = 0;
+ uiInfo.serverStatus.numDuplicateMultiprotocolServers = 0;
+ uiInfo.serverStatus.numDuplicateMultiprotocolServerClients = 0;
+ // mark all servers as visible so we store ping updates for them
+ trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
+ // reset all the pings
+ trap_LAN_ResetPings(ui_netSource.integer);
+ //
+
+ if (ui_netSource.integer == AS_LOCAL)
{
- //set vertical offset of graphic
- if( pane->graphics[ i ].offset < 0 )
- yoffset = ( rect->h / 2 ) - ( pane->graphics[ i ].height / 2 );
- else
- yoffset = pane->graphics[ i ].offset + GRAPHIC_BWIDTH;
+ trap_Cmd_ExecuteText(EXEC_APPEND, "localservers\n");
+ uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
+ return;
}
- if( pane->graphics[ i ].side == INFOPANE_LEFT )
- {
- //set the horizontal offset of the text
- if( pane->graphics[ i ].width > maxLeft )
- maxLeft = pane->graphics[ i ].width + GRAPHIC_BWIDTH;
+ uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000;
- xoffset = GRAPHIC_BWIDTH;
- }
- else if( pane->graphics[ i ].side == INFOPANE_RIGHT )
+ if (ui_netSource.integer == AS_GLOBAL || ui_netSource.integer == AS_MPLAYER)
{
- if( pane->graphics[ i ].width > maxRight )
- maxRight = pane->graphics[ i ].width + GRAPHIC_BWIDTH;
+ qboolean global = ui_netSource.integer == AS_GLOBAL;
- xoffset = rect->w - width - GRAPHIC_BWIDTH;
+#ifdef MODULE_INTERFACE_11
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("globalservers %d 69 full empty\n",
+#else
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("globalservers %d 70 full empty\n",
+#endif
+ global ? 0 : 1));
}
- else if( pane->graphics[ i ].side == INFOPANE_TOP )
+}
+
+int frameCount = 0;
+int startTime;
+
+#define UI_FPS_FRAMES 4
+void UI_Refresh(int realtime)
+{
+ static int index;
+ static int previousTimes[UI_FPS_FRAMES];
+
+ // if( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
+ // return;
+ //}
+
+ uiInfo.uiDC.frameTime = realtime - uiInfo.uiDC.realTime;
+ uiInfo.uiDC.realTime = realtime;
+
+ previousTimes[index % UI_FPS_FRAMES] = uiInfo.uiDC.frameTime;
+ index++;
+
+ if (index > UI_FPS_FRAMES)
{
- //set the vertical offset of the text
- if( pane->graphics[ i ].height > maxTop )
- maxTop = pane->graphics[ i ].height + GRAPHIC_BWIDTH;
+ int i, total;
+ // average multiple frames together to smooth changes out a bit
+ total = 0;
+
+ for (i = 0; i < UI_FPS_FRAMES; i++)
+ total += previousTimes[i];
- yoffset = GRAPHIC_BWIDTH;
+ if (!total)
+ total = 1;
+
+ uiInfo.uiDC.FPS = 1000 * UI_FPS_FRAMES / total;
}
- else if( pane->graphics[ i ].side == INFOPANE_BOTTOM )
- {
- if( pane->graphics[ i ].height > maxBottom )
- maxBottom = pane->graphics[ i ].height + GRAPHIC_BWIDTH;
- yoffset = rect->h - height - GRAPHIC_BWIDTH;
+ UI_UpdateCvars();
+
+ if (Menu_Count() > 0)
+ {
+ Menu_UpdateAll();
+ Menu_PaintAll();
+ UI_DoServerRefresh();
+ UI_BuildServerStatus(qfalse);
+ UI_BuildFindPlayerList(qfalse);
+ UI_UpdateNews(qfalse);
+ // FIXME: CHECK FOR "AUTOMATICALLLY CHECK FOR UPDATES == true"
+ // UI_UpdateGithubRelease( );
}
- //draw the graphic
- UI_DrawHandlePic( x + xoffset, y + yoffset, width, height, graphic );
- }
+ // draw cursor
+ UI_SetColor(NULL);
- //offset the text
- x = rect->x + maxLeft;
- y = rect->y + maxTop;
- w = rect->w - ( maxLeft + maxRight + 16 + ( 2 * text_x ) ); //16 to ensure text within frame
- h = rect->h - ( maxTop + maxBottom );
+ if (trap_Key_GetCatcher() == KEYCATCH_UI && !trap_Cvar_VariableValue("ui_hideCursor"))
+ {
+ UI_DrawHandlePic(uiInfo.uiDC.cursorx - (16.0f * uiInfo.uiDC.aspectScale), uiInfo.uiDC.cursory - 16.0f,
+ 32.0f * uiInfo.uiDC.aspectScale, 32.0f, uiInfo.uiDC.Assets.cursor);
+ }
+}
- textItem.text = pane->text;
+/*
+=================
+UI_Shutdown
+=================
+*/
+void UI_Shutdown(void) { trap_LAN_SaveCachedServers(); }
- textItem.parent = &dummyParent;
- memcpy( textItem.window.foreColor, color, sizeof( vec4_t ) );
- textItem.window.flags = 0;
+qboolean Asset_Parse(int handle)
+{
+ pc_token_t token;
+ const char *tempStr;
- switch( pane->align )
- {
- case ITEM_ALIGN_LEFT:
- textItem.window.rect.x = x;
- break;
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
- case ITEM_ALIGN_RIGHT:
- textItem.window.rect.x = x + w;
- break;
+ if (Q_stricmp(token.string, "{") != 0)
+ return qfalse;
- case ITEM_ALIGN_CENTER:
- textItem.window.rect.x = x + ( w / 2 );
- break;
+ while (1)
+ {
+ memset(&token, 0, sizeof(pc_token_t));
- default:
- textItem.window.rect.x = x;
- break;
- }
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
- textItem.window.rect.y = y;
- textItem.window.rect.w = w;
- textItem.window.rect.h = h;
- textItem.window.borderSize = 0;
- textItem.textRect.x = 0;
- textItem.textRect.y = 0;
- textItem.textRect.w = 0;
- textItem.textRect.h = 0;
- textItem.textalignment = pane->align;
- textItem.textalignx = text_x;
- textItem.textaligny = text_y;
- textItem.textscale = scale;
- textItem.textStyle = textStyle;
+ if (Q_stricmp(token.string, "}") == 0)
+ return qtrue;
- textItem.enableCvar = NULL;
- textItem.cvarTest = NULL;
+ // font
+ if (Q_stricmp(token.string, "font") == 0)
+ {
+ int pointSize;
- //hack to utilise existing autowrap code
- Item_Text_AutoWrapped_Paint( &textItem );
-}
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize))
+ return qfalse;
+ trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.textFont);
+ uiInfo.uiDC.Assets.fontRegistered = qtrue;
+ continue;
+ }
-static void UI_DrawSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i;
- i = trap_Cvar_VariableValue( "g_spSkill" );
- if (i < 1 || i > numSkillLevels) {
- i = 1;
- }
- Text_Paint(rect->x, rect->y, scale, color, skillLevels[i-1],0, 0, textStyle);
-}
+ if (Q_stricmp(token.string, "smallFont") == 0)
+ {
+ int pointSize;
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize))
+ return qfalse;
-static void UI_DrawTeamName(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int textStyle) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
- if (i >= 0 && i < uiInfo.teamCount) {
- Text_Paint(rect->x, rect->y, scale, color, va("%s: %s", (blue) ? "Blue" : "Red", uiInfo.teamList[i].teamName),0, 0, textStyle);
- }
-}
+ trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.smallFont);
+ continue;
+ }
-static void UI_DrawTeamMember(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int num, int textStyle) {
- // 0 - None
- // 1 - Human
- // 2..NumCharacters - Bot
- int value = trap_Cvar_VariableValue(va(blue ? "ui_blueteam%i" : "ui_redteam%i", num));
- const char *text;
- if (value <= 0) {
- text = "Closed";
- } else if (value == 1) {
- text = "Human";
- } else {
- value -= 2;
-
- if( value >= UI_GetNumBots( ) )
- value = 0;
-
- text = UI_GetBotNameByNumber(value);
- }
- Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
-}
+ if (Q_stricmp(token.string, "bigFont") == 0)
+ {
+ int pointSize;
-static void UI_DrawMapPreview(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
- int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (map < 0 || map > uiInfo.mapCount) {
- if (net) {
- ui_currentNetMap.integer = 0;
- trap_Cvar_Set("ui_currentNetMap", "0");
- } else {
- ui_currentMap.integer = 0;
- trap_Cvar_Set("ui_currentMap", "0");
- }
- map = 0;
- }
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize))
+ return qfalse;
- if (uiInfo.mapList[map].levelShot == -1) {
- uiInfo.mapList[map].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[map].imageName);
- }
+ trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.bigFont);
+ continue;
+ }
- if (uiInfo.mapList[map].levelShot > 0) {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.mapList[map].levelShot);
- } else {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("gfx/2d/load_screen"));
- }
-}
+ // gradientbar
+ if (Q_stricmp(token.string, "gradientbar") == 0)
+ {
+ if (!PC_String_Parse(handle, &tempStr))
+ return qfalse;
+ uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
+ continue;
+ }
-static void UI_DrawMapTimeToBeat(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int minutes, seconds, time;
- if (ui_currentMap.integer < 0 || ui_currentMap.integer > uiInfo.mapCount) {
- ui_currentMap.integer = 0;
- trap_Cvar_Set("ui_currentMap", "0");
- }
+ // enterMenuSound
+ if (Q_stricmp(token.string, "menuEnterSound") == 0)
+ {
+ if (!PC_String_Parse(handle, &tempStr))
+ return qfalse;
- time = uiInfo.mapList[ui_currentMap.integer].timeToBeat[uiInfo.gameTypes[ui_gameType.integer].gtEnum];
+ uiInfo.uiDC.Assets.menuEnterSound = trap_S_RegisterSound(tempStr, qfalse);
+ continue;
+ }
- minutes = time / 60;
- seconds = time % 60;
+ // exitMenuSound
+ if (Q_stricmp(token.string, "menuExitSound") == 0)
+ {
+ if (!PC_String_Parse(handle, &tempStr))
+ return qfalse;
- Text_Paint(rect->x, rect->y, scale, color, va("%02i:%02i", minutes, seconds), 0, 0, textStyle);
-}
+ uiInfo.uiDC.Assets.menuExitSound = trap_S_RegisterSound(tempStr, qfalse);
+ continue;
+ }
+ // itemFocusSound
+ if (Q_stricmp(token.string, "itemFocusSound") == 0)
+ {
+ if (!PC_String_Parse(handle, &tempStr))
+ return qfalse;
+ uiInfo.uiDC.Assets.itemFocusSound = trap_S_RegisterSound(tempStr, qfalse);
+ continue;
+ }
-static void UI_DrawMapCinematic(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
+ // menuBuzzSound
+ if (Q_stricmp(token.string, "menuBuzzSound") == 0)
+ {
+ if (!PC_String_Parse(handle, &tempStr))
+ return qfalse;
- int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (map < 0 || map > uiInfo.mapCount) {
- if (net) {
- ui_currentNetMap.integer = 0;
- trap_Cvar_Set("ui_currentNetMap", "0");
- } else {
- ui_currentMap.integer = 0;
- trap_Cvar_Set("ui_currentMap", "0");
- }
- map = 0;
- }
+ uiInfo.uiDC.Assets.menuBuzzSound = trap_S_RegisterSound(tempStr, qfalse);
+ continue;
+ }
- if (uiInfo.mapList[map].cinematic >= -1) {
- if (uiInfo.mapList[map].cinematic == -1) {
- uiInfo.mapList[map].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[map].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- }
- if (uiInfo.mapList[map].cinematic >= 0) {
- trap_CIN_RunCinematic(uiInfo.mapList[map].cinematic);
- trap_CIN_SetExtents(uiInfo.mapList[map].cinematic, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.mapList[map].cinematic);
- } else {
- uiInfo.mapList[map].cinematic = -2;
- }
- } else {
- UI_DrawMapPreview(rect, scale, color, net);
- }
-}
+ if (Q_stricmp(token.string, "cursor") == 0)
+ {
+ if (!PC_String_Parse(handle, &uiInfo.uiDC.Assets.cursorStr))
+ return qfalse;
+ uiInfo.uiDC.Assets.cursor = trap_R_RegisterShaderNoMip(uiInfo.uiDC.Assets.cursorStr);
+ continue;
+ }
+ if (Q_stricmp(token.string, "fadeClamp") == 0)
+ {
+ if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeClamp))
+ return qfalse;
-static qboolean updateModel = qtrue;
-static qboolean q3Model = qfalse;
-
-static void UI_DrawPlayerModel(rectDef_t *rect) {
- static playerInfo_t info;
- char model[MAX_QPATH];
- char team[256];
- char head[256];
- vec3_t viewangles;
- vec3_t moveangles;
-
- if (trap_Cvar_VariableValue("ui_Q3Model")) {
- strcpy(model, UI_Cvar_VariableString("model"));
- strcpy(head, UI_Cvar_VariableString("headmodel"));
- if (!q3Model) {
- q3Model = qtrue;
- updateModel = qtrue;
- }
- team[0] = '\0';
- } else {
-
- strcpy(team, UI_Cvar_VariableString("ui_teamName"));
- strcpy(model, UI_Cvar_VariableString("team_model"));
- strcpy(head, UI_Cvar_VariableString("team_headmodel"));
- if (q3Model) {
- q3Model = qfalse;
- updateModel = qtrue;
- }
- }
- if (updateModel) {
- memset( &info, 0, sizeof(playerInfo_t) );
- viewangles[YAW] = 180 - 10;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
- VectorClear( moveangles );
- UI_PlayerInfo_SetModel( &info, model, head, team);
- UI_PlayerInfo_SetInfo( &info, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
-// UI_RegisterClientModelname( &info, model, head, team);
- updateModel = qfalse;
- }
-
- UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info, uiInfo.uiDC.realTime / 2);
+ continue;
+ }
-}
+ if (Q_stricmp(token.string, "fadeCycle") == 0)
+ {
+ if (!PC_Int_Parse(handle, &uiInfo.uiDC.Assets.fadeCycle))
+ return qfalse;
-static void UI_DrawNetSource(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_netSource.integer < 0 || ui_netSource.integer > numNetSources) {
- ui_netSource.integer = 0;
- }
- Text_Paint(rect->x, rect->y, scale, color, va("Source: %s", netSources[ui_netSource.integer]), 0, 0, textStyle);
-}
+ continue;
+ }
-static void UI_DrawNetMapPreview(rectDef_t *rect, float scale, vec4_t color) {
+ if (Q_stricmp(token.string, "fadeAmount") == 0)
+ {
+ if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeAmount))
+ return qfalse;
- if (uiInfo.serverStatus.currentServerPreview > 0) {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.serverStatus.currentServerPreview);
- } else {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("gfx/2d/load_screen"));
- }
-}
+ continue;
+ }
-static void UI_DrawNetMapCinematic(rectDef_t *rect, float scale, vec4_t color) {
- if (ui_currentNetMap.integer < 0 || ui_currentNetMap.integer > uiInfo.mapCount) {
- ui_currentNetMap.integer = 0;
- trap_Cvar_Set("ui_currentNetMap", "0");
- }
-
- if (uiInfo.serverStatus.currentServerCinematic >= 0) {
- trap_CIN_RunCinematic(uiInfo.serverStatus.currentServerCinematic);
- trap_CIN_SetExtents(uiInfo.serverStatus.currentServerCinematic, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.serverStatus.currentServerCinematic);
- } else {
- UI_DrawNetMapPreview(rect, scale, color);
- }
-}
+ if (Q_stricmp(token.string, "shadowX") == 0)
+ {
+ if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowX))
+ return qfalse;
+
+ continue;
+ }
+ if (Q_stricmp(token.string, "shadowY") == 0)
+ {
+ if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowY))
+ return qfalse;
+ continue;
+ }
-static void UI_DrawNetFilter(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
- ui_serverFilterType.integer = 0;
- }
- Text_Paint(rect->x, rect->y, scale, color, va("Filter: %s", serverFilters[ui_serverFilterType.integer].description), 0, 0, textStyle);
-}
+ if (Q_stricmp(token.string, "shadowColor") == 0)
+ {
+ if (!PC_Color_Parse(handle, &uiInfo.uiDC.Assets.shadowColor))
+ return qfalse;
+ uiInfo.uiDC.Assets.shadowFadeClamp = uiInfo.uiDC.Assets.shadowColor[3];
+ continue;
+ }
+ }
-static void UI_DrawTier(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
- Text_Paint(rect->x, rect->y, scale, color, va("Tier: %s", uiInfo.tierList[i].tierName),0, 0, textStyle);
+ return qfalse;
}
-static void UI_DrawTierMap(rectDef_t *rect, int index) {
- int i;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
+void UI_Report(void) { String_Report(); }
- if (uiInfo.tierList[i].mapHandles[index] == -1) {
- uiInfo.tierList[i].mapHandles[index] = trap_R_RegisterShaderNoMip(va("levelshots/%s", uiInfo.tierList[i].maps[index]));
- }
+void UI_ParseMenu(const char *menuFile)
+{
+ int handle;
+ pc_token_t token;
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.tierList[i].mapHandles[index]);
-}
+ handle = trap_Parse_LoadSource(menuFile);
-static const char *UI_EnglishMapName(const char *map) {
- int i;
- for (i = 0; i < uiInfo.mapCount; i++) {
- if (Q_stricmp(map, uiInfo.mapList[i].mapLoadName) == 0) {
- return uiInfo.mapList[i].mapName;
+ if (!handle)
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: Menu file %s not found\n", menuFile);
+ return;
}
- }
- return "";
-}
-static void UI_DrawTierMapName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i, j;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
- j = trap_Cvar_VariableValue("ui_currentMap");
- if (j < 0 || j > MAPS_PER_TIER) {
- j = 0;
- }
-
- Text_Paint(rect->x, rect->y, scale, color, UI_EnglishMapName(uiInfo.tierList[i].maps[j]), 0, 0, textStyle);
-}
+ while (1)
+ {
+ memset(&token, 0, sizeof(pc_token_t));
-static void UI_DrawTierGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i, j;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
- j = trap_Cvar_VariableValue("ui_currentMap");
- if (j < 0 || j > MAPS_PER_TIER) {
- j = 0;
- }
-
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[uiInfo.tierList[i].gameTypes[j]].gameType , 0, 0, textStyle);
-}
+ if (!trap_Parse_ReadToken(handle, &token))
+ break;
+
+ // if( Q_stricmp( token, "{" ) ) {
+ // Com_Printf( "Missing { in menu file\n" );
+ // break;
+ //}
+ // if( menuCount == MAX_MENUS ) {
+ // Com_Printf( "Too many menus!\n" );
+ // break;
+ //}
-static const char *UI_AIFromName(const char *name) {
- int j;
- for (j = 0; j < uiInfo.aliasCount; j++) {
- if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
- return uiInfo.aliasList[j].ai;
+ if (token.string[0] == '}')
+ break;
+
+ if (Q_stricmp(token.string, "assetGlobalDef") == 0)
+ {
+ if (Asset_Parse(handle))
+ continue;
+ else
+ break;
+ }
+
+ if (Q_stricmp(token.string, "menudef") == 0)
+ {
+ // start a new menu
+ Menu_New(handle);
+ }
}
- }
- return "James";
+
+ trap_Parse_FreeSource(handle);
}
-static qboolean updateOpponentModel = qtrue;
-static void UI_DrawOpponent(rectDef_t *rect) {
- static playerInfo_t info2;
- char model[MAX_QPATH];
- char headmodel[MAX_QPATH];
- char team[256];
- vec3_t viewangles;
- vec3_t moveangles;
-
- if (updateOpponentModel) {
-
- strcpy(model, UI_Cvar_VariableString("ui_opponentModel"));
- strcpy(headmodel, UI_Cvar_VariableString("ui_opponentModel"));
- team[0] = '\0';
-
- memset( &info2, 0, sizeof(playerInfo_t) );
- viewangles[YAW] = 180 - 10;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
- VectorClear( moveangles );
- UI_PlayerInfo_SetModel( &info2, model, headmodel, "");
- UI_PlayerInfo_SetInfo( &info2, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
- UI_RegisterClientModelname( &info2, model, headmodel, team);
- updateOpponentModel = qfalse;
- }
-
- UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info2, uiInfo.uiDC.realTime / 2);
+qboolean Load_Menu(int handle)
+{
+ pc_token_t token;
+
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
-}
+ if (token.string[0] != '{')
+ return qfalse;
-static void UI_NextOpponent( void ) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- i++;
- if (i >= uiInfo.teamCount) {
- i = 0;
- }
- if (i == j) {
- i++;
- if ( i >= uiInfo.teamCount) {
- i = 0;
- }
- }
- trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
-}
+ while (1)
+ {
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
-static void UI_PriorOpponent( void ) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- i--;
- if (i < 0) {
- i = uiInfo.teamCount - 1;
- }
- if (i == j) {
- i--;
- if ( i < 0) {
- i = uiInfo.teamCount - 1;
- }
- }
- trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
-}
+ if (token.string[0] == 0)
+ return qfalse;
-static void UI_DrawPlayerLogo(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ if (token.string[0] == '}')
+ return qtrue;
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
+ UI_ParseMenu(token.string);
+ }
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
- trap_R_SetColor( NULL );
+ return qfalse;
}
-static void UI_DrawPlayerLogoMetal(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
- trap_R_SetColor( NULL );
-}
+void UI_LoadMenus(const char *menuFile, qboolean reset)
+{
+ pc_token_t token;
+ int handle;
+ int start;
-static void UI_DrawPlayerLogoName(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
- trap_R_SetColor( NULL );
-}
+ start = trap_Milliseconds();
-static void UI_DrawOpponentLogo(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
- trap_R_SetColor( NULL );
-}
+ handle = trap_Parse_LoadSource(menuFile);
-static void UI_DrawOpponentLogoMetal(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
- trap_R_SetColor( NULL );
-}
+ if (!handle)
+ trap_Error(va(S_COLOR_RED "menu list '%s' not found, unable to continue!", menuFile));
-static void UI_DrawOpponentLogoName(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
- trap_R_SetColor( NULL );
-}
+ if (reset)
+ Menu_Reset();
-static void UI_DrawAllMapsSelection(rectDef_t *rect, float scale, vec4_t color, int textStyle, qboolean net) {
- int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (map >= 0 && map < uiInfo.mapCount) {
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.mapList[map].mapName, 0, 0, textStyle);
- }
-}
+ while (1)
+ {
+ if (!trap_Parse_ReadToken(handle, &token))
+ break;
-static void UI_DrawPlayerListSelection( rectDef_t *rect, float scale,
- vec4_t color, int textStyle )
-{
- if( uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount )
- {
- Text_Paint(rect->x, rect->y, scale, color,
- uiInfo.rawPlayerNames[ uiInfo.playerIndex ],
- 0, 0, textStyle);
- }
+ if (token.string[0] == 0 || token.string[0] == '}')
+ break;
+
+ if (token.string[0] == '}')
+ break;
+
+ if (Q_stricmp(token.string, "loadmenu") == 0)
+ {
+ if (Load_Menu(handle))
+ continue;
+ else
+ break;
+ }
+ }
+
+ Com_Printf("UI menu file '%s' loaded in %d msec\n", menuFile, trap_Milliseconds() - start);
+
+ trap_Parse_FreeSource(handle);
}
-static void UI_DrawTeamListSelection( rectDef_t *rect, float scale,
- vec4_t color, int textStyle )
+void UI_LoadHelp(const char *helpFile)
{
- if( uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount )
- {
- Text_Paint(rect->x, rect->y, scale, color,
- uiInfo.rawTeamNames[ uiInfo.teamIndex ],
- 0, 0, textStyle);
- }
-}
+ pc_token_t token;
+ int handle, start;
+ char title[32], buffer[1024];
-static void UI_DrawOpponentName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_opponentName"), 0, 0, textStyle);
-}
+ start = trap_Milliseconds();
+ handle = trap_Parse_LoadSource(helpFile);
+ if (!handle)
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: help file '%s' not found!\n", helpFile);
+ return;
+ }
-static int UI_OwnerDrawWidth(int ownerDraw, float scale) {
- int i, h, value;
- const char *text;
- const char *s = NULL;
-
- switch( ownerDraw )
- {
- case UI_HANDICAP:
- h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
- i = 20 - h / 5;
- s = handicapValues[i];
- break;
- case UI_CLANNAME:
- s = UI_Cvar_VariableString("ui_teamName");
- break;
- case UI_GAMETYPE:
- s = uiInfo.gameTypes[ui_gameType.integer].gameType;
- break;
- case UI_SKILL:
- i = trap_Cvar_VariableValue( "g_spSkill" );
- if (i < 1 || i > numSkillLevels) {
- i = 1;
- }
- s = skillLevels[i-1];
- break;
- case UI_BLUETEAMNAME:
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_blueTeam"));
- if (i >= 0 && i < uiInfo.teamCount) {
- s = va("%s: %s", "Blue", uiInfo.teamList[i].teamName);
- }
- break;
- case UI_REDTEAMNAME:
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_redTeam"));
- if (i >= 0 && i < uiInfo.teamCount) {
- s = va("%s: %s", "Red", uiInfo.teamList[i].teamName);
- }
- break;
- case UI_BLUETEAM1:
- case UI_BLUETEAM2:
- case UI_BLUETEAM3:
- case UI_BLUETEAM4:
- case UI_BLUETEAM5:
- value = trap_Cvar_VariableValue(va("ui_blueteam%i", ownerDraw-UI_BLUETEAM1 + 1));
- if (value <= 0) {
- text = "Closed";
- } else if (value == 1) {
- text = "Human";
- } else {
- value -= 2;
- if (value >= uiInfo.aliasCount) {
- value = 0;
- }
- text = uiInfo.aliasList[value].name;
- }
- s = va("%i. %s", ownerDraw-UI_BLUETEAM1 + 1, text);
- break;
- case UI_REDTEAM1:
- case UI_REDTEAM2:
- case UI_REDTEAM3:
- case UI_REDTEAM4:
- case UI_REDTEAM5:
- value = trap_Cvar_VariableValue(va("ui_redteam%i", ownerDraw-UI_REDTEAM1 + 1));
- if (value <= 0) {
- text = "Closed";
- } else if (value == 1) {
- text = "Human";
- } else {
- value -= 2;
- if (value >= uiInfo.aliasCount) {
- value = 0;
- }
- text = uiInfo.aliasList[value].name;
- }
- s = va("%i. %s", ownerDraw-UI_REDTEAM1 + 1, text);
- break;
- case UI_NETSOURCE:
- if (ui_netSource.integer < 0 || ui_netSource.integer > uiInfo.numJoinGameTypes) {
- ui_netSource.integer = 0;
- }
- s = va("Source: %s", netSources[ui_netSource.integer]);
- break;
- case UI_NETFILTER:
- if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
- ui_serverFilterType.integer = 0;
- }
- s = va("Filter: %s", serverFilters[ui_serverFilterType.integer].description );
- break;
- case UI_TIER:
- break;
- case UI_TIER_MAPNAME:
- break;
- case UI_TIER_GAMETYPE:
- break;
- case UI_ALLMAPS_SELECTION:
- break;
- case UI_PLAYERLIST_SELECTION:
- break;
- case UI_TEAMLIST_SELECTION:
- break;
- case UI_OPPONENT_NAME:
- break;
- case UI_KEYBINDSTATUS:
- if (Display_KeyBindPending()) {
- s = "Waiting for new key... Press ESCAPE to cancel";
- } else {
- s = "Press ENTER or CLICK to change, Press BACKSPACE to clear";
- }
- break;
- case UI_SERVERREFRESHDATE:
- s = UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer));
- break;
- default:
- break;
- }
-
- if (s) {
- return Text_Width(s, scale, 0);
- }
- return 0;
-}
+ if (!trap_Parse_ReadToken(handle, &token) || token.string[0] == 0 || token.string[0] != '{')
+ {
+ Com_Printf(S_COLOR_YELLOW
+ "WARNING: help file '%s' does not start with "
+ "'{'\n",
+ helpFile);
+ return;
+ }
-static void UI_DrawBotName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int value = uiInfo.botIndex;
- const char *text = "";
+ uiInfo.helpCount = 0;
+ title[0] = 0;
+ while (1)
+ {
+ if (!trap_Parse_ReadToken(handle, &token) || token.string[0] == 0 || token.string[0] == '}')
+ break;
- if( value >= UI_GetNumBots( ) )
- value = 0;
+ if (token.string[0] == '{')
+ {
+ buffer[0] = 0;
+ Q_strcat(buffer, sizeof(buffer), title);
+ Q_strcat(buffer, sizeof(buffer), "\n\n");
+ while (trap_Parse_ReadToken(handle, &token) && token.string[0] != 0 && token.string[0] != '}')
+ {
+ Q_strcat(buffer, sizeof(buffer), token.string);
+ }
- text = UI_GetBotNameByNumber( value );
+ uiInfo.helpList[uiInfo.helpCount].text = String_Alloc(title);
+ uiInfo.helpList[uiInfo.helpCount].v.text = String_Alloc(buffer);
+ uiInfo.helpList[uiInfo.helpCount].type = INFOTYPE_TEXT;
+ uiInfo.helpCount++;
+ title[0] = 0;
+ }
+ else
+ Q_strcat(title, sizeof(title), token.string);
+ }
- Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
-}
+ trap_Parse_FreeSource(handle);
-static void UI_DrawBotSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (uiInfo.skillIndex >= 0 && uiInfo.skillIndex < numSkillLevels) {
- Text_Paint(rect->x, rect->y, scale, color, skillLevels[uiInfo.skillIndex], 0, 0, textStyle);
- }
+ Com_Printf("UI help file '%s' loaded in %d msec (%d infopanes)\n", helpFile, trap_Milliseconds() - start,
+ uiInfo.helpCount);
}
-static void UI_DrawRedBlue(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, (uiInfo.redBlue == 0) ? "Red" : "Blue", 0, 0, textStyle);
+void UI_Load(void)
+{
+ char lastName[1024];
+ menuDef_t *menu = Menu_GetFocused();
+
+ if (menu && menu->window.name)
+ strcpy(lastName, menu->window.name);
+
+ String_Init();
+
+ UI_LoadMenus("ui/menus.txt", qtrue);
+ UI_LoadMenus("ui/ingame.txt", qfalse);
+ UI_LoadMenus("ui/tremulous.txt", qfalse);
+ UI_LoadHelp("ui/help.txt");
+ Menus_CloseAll();
+ Menus_ActivateByName(lastName);
}
/*
===============
-UI_BuildPlayerList
+UI_GetCurrentAlienStage
===============
*/
-static void UI_BuildPlayerList( void ) {
- uiClientState_t cs;
- int n, count, team, team2, playerTeamNumber;
- char info[MAX_INFO_STRING];
-
- trap_GetClientState( &cs );
- trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
- uiInfo.playerNumber = cs.clientNum;
- uiInfo.teamLeader = atoi(Info_ValueForKey(info, "tl"));
- team = atoi(Info_ValueForKey(info, "t"));
- trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
- count = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
- uiInfo.playerCount = 0;
- uiInfo.myTeamCount = 0;
- uiInfo.myPlayerIndex = 0;
- playerTeamNumber = 0;
- for( n = 0; n < count; n++ ) {
- trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );
-
- if (info[0]) {
- BG_ClientListParse( &uiInfo.ignoreList[ uiInfo.playerCount ],
- Info_ValueForKey( info, "ig" ) );
- Q_strncpyz( uiInfo.rawPlayerNames[uiInfo.playerCount],
- Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
- Q_strncpyz( uiInfo.playerNames[uiInfo.playerCount],
- Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
- Q_CleanStr( uiInfo.playerNames[uiInfo.playerCount] );
- uiInfo.clientNums[uiInfo.playerCount] = n;
- if( n == uiInfo.playerNumber )
- uiInfo.myPlayerIndex = uiInfo.playerCount;
- uiInfo.playerCount++;
- team2 = atoi(Info_ValueForKey(info, "t"));
- if (team2 == team) {
- Q_strncpyz( uiInfo.rawTeamNames[uiInfo.myTeamCount],
- Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
- Q_strncpyz( uiInfo.teamNames[uiInfo.myTeamCount],
- Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
- Q_CleanStr( uiInfo.teamNames[uiInfo.myTeamCount] );
- uiInfo.teamClientNums[uiInfo.myTeamCount] = n;
- if (uiInfo.playerNumber == n) {
- playerTeamNumber = uiInfo.myTeamCount;
- }
- uiInfo.myTeamCount++;
- }
- }
- }
+static stage_t UI_GetCurrentAlienStage(void)
+{
+ char buffer[MAX_TOKEN_CHARS];
+ stage_t stage, dummy;
- if (!uiInfo.teamLeader) {
- trap_Cvar_Set("cg_selectedPlayer", va("%d", playerTeamNumber));
- }
+ trap_Cvar_VariableStringBuffer("ui_stages", buffer, sizeof(buffer));
+ sscanf(buffer, "%d %d", (int *)&stage, (int *)&dummy);
- n = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (n < 0 || n > uiInfo.myTeamCount) {
- n = 0;
- }
- if (n < uiInfo.myTeamCount) {
- trap_Cvar_Set("cg_selectedPlayerName", uiInfo.teamNames[n]);
- }
+ return stage;
}
+/*
+===============
+UI_GetCurrentHumanStage
+===============
+*/
+static stage_t UI_GetCurrentHumanStage(void)
+{
+ char buffer[MAX_TOKEN_CHARS];
+ stage_t stage, dummy;
-static void UI_DrawSelectedPlayer(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- char name[ MAX_NAME_LENGTH ];
- char *s;
-
- if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
- uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
- UI_BuildPlayerList();
- }
- if( uiInfo.teamLeader )
- s = UI_Cvar_VariableString("cg_selectedPlayerName");
- else
- s = UI_Cvar_VariableString("name");
- Q_strncpyz( name, s, sizeof( name ) );
- Text_Paint(rect->x, rect->y, scale, color, name, 0, 0, textStyle);
-}
+ trap_Cvar_VariableStringBuffer("ui_stages", buffer, sizeof(buffer));
+ sscanf(buffer, "%d %d", (int *)&dummy, (int *)&stage);
-static void UI_DrawServerRefreshDate(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (uiInfo.serverStatus.refreshActive) {
- vec4_t lowLight, newColor;
- lowLight[0] = 0.8 * color[0];
- lowLight[1] = 0.8 * color[1];
- lowLight[2] = 0.8 * color[2];
- lowLight[3] = 0.8 * color[3];
- LerpColor(color,lowLight,newColor,0.5+0.5*sin(uiInfo.uiDC.realTime / PULSE_DIVISOR));
- Text_Paint(rect->x, rect->y, scale, newColor, va("Getting info for %d servers (ESC to cancel)", trap_LAN_GetServerCount(ui_netSource.integer)), 0, 0, textStyle);
- } else {
- char buff[64];
- Q_strncpyz(buff, UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer)), 64);
- Text_Paint(rect->x, rect->y, scale, color, va("Refresh Time: %s", buff), 0, 0, textStyle);
- }
+ return stage;
}
-static void UI_DrawServerMOTD(rectDef_t *rect, float scale, vec4_t color) {
- if (uiInfo.serverStatus.motdLen) {
- float maxX;
+/*
+===============
+UI_DrawInfoPane
+===============
+*/
+static void UI_DrawInfoPane(menuItem_t *item, rectDef_t *rect, float text_x, float text_y, float scale, int textalign,
+ int textvalign, vec4_t color, int textStyle)
+{
+ int value = 0;
+ const char *s = "";
+ char *string = "";
- if (uiInfo.serverStatus.motdWidth == -1) {
- uiInfo.serverStatus.motdWidth = 0;
- uiInfo.serverStatus.motdPaintX = rect->x + 1;
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
+ int class, credits;
+ char ui_currentClass[MAX_STRING_CHARS];
- if (uiInfo.serverStatus.motdOffset > uiInfo.serverStatus.motdLen) {
- uiInfo.serverStatus.motdOffset = 0;
- uiInfo.serverStatus.motdPaintX = rect->x + 1;
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
+ trap_Cvar_VariableStringBuffer("ui_currentClass", ui_currentClass, MAX_STRING_CHARS);
- if (uiInfo.uiDC.realTime > uiInfo.serverStatus.motdTime) {
- uiInfo.serverStatus.motdTime = uiInfo.uiDC.realTime + 10;
- if (uiInfo.serverStatus.motdPaintX <= rect->x + 2) {
- if (uiInfo.serverStatus.motdOffset < uiInfo.serverStatus.motdLen) {
- uiInfo.serverStatus.motdPaintX += Text_Width(&uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], scale, 1) - 1;
- uiInfo.serverStatus.motdOffset++;
- } else {
- uiInfo.serverStatus.motdOffset = 0;
- if (uiInfo.serverStatus.motdPaintX2 >= 0) {
- uiInfo.serverStatus.motdPaintX = uiInfo.serverStatus.motdPaintX2;
- } else {
- uiInfo.serverStatus.motdPaintX = rect->x + rect->w - 2;
- }
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
- } else {
- //serverStatus.motdPaintX--;
- uiInfo.serverStatus.motdPaintX -= 2;
- if (uiInfo.serverStatus.motdPaintX2 >= 0) {
- //serverStatus.motdPaintX2--;
- uiInfo.serverStatus.motdPaintX2 -= 2;
- }
- }
- }
+ sscanf(ui_currentClass, "%d %d", &class, &credits);
- maxX = rect->x + rect->w - 2;
- Text_Paint_Limit(&maxX, uiInfo.serverStatus.motdPaintX, rect->y + rect->h - 3, scale, color, &uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], 0, 0);
- if (uiInfo.serverStatus.motdPaintX2 >= 0) {
- float maxX2 = rect->x + rect->w - 2;
- Text_Paint_Limit(&maxX2, uiInfo.serverStatus.motdPaintX2, rect->y + rect->h - 3, scale, color, uiInfo.serverStatus.motd, 0, uiInfo.serverStatus.motdOffset);
- }
- if (uiInfo.serverStatus.motdOffset && maxX > 0) {
- // if we have an offset ( we are skipping the first part of the string ) and we fit the string
- if (uiInfo.serverStatus.motdPaintX2 == -1) {
- uiInfo.serverStatus.motdPaintX2 = rect->x + rect->w - 2;
- }
- } else {
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
+ switch (item->type)
+ {
+ case INFOTYPE_TEXT:
+ case INFOTYPE_VOICECMD:
+ s = item->v.text;
+ break;
- }
-}
+ case INFOTYPE_CLASS:
+ value = (BG_ClassCanEvolveFromTo(class, item->v.pclass, credits, UI_GetCurrentAlienStage(), 0) +
+ ALIEN_CREDITS_PER_KILL - 1) /
+ ALIEN_CREDITS_PER_KILL;
-static void UI_DrawKeyBindStatus(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
-// int ofs = 0; TTimo: unused
- if (Display_KeyBindPending()) {
- Text_Paint(rect->x, rect->y, scale, color, "Waiting for new key... Press ESCAPE to cancel", 0, 0, textStyle);
- } else {
- Text_Paint(rect->x, rect->y, scale, color, "Press ENTER or CLICK to change, Press BACKSPACE to clear", 0, 0, textStyle);
- }
-}
+ if (value < 1)
+ {
+ s = va("%s\n\n%s", BG_ClassConfig(item->v.pclass)->humanName, BG_Class(item->v.pclass)->info);
+ }
+ else
+ {
+ s = va("%s\n\n%s\n\nFrags: %d", BG_ClassConfig(item->v.pclass)->humanName,
+ BG_Class(item->v.pclass)->info, value);
+ }
-static void UI_DrawGLInfo(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- char * eptr;
- char buff[1024];
- const char *lines[64];
- int y, numLines, i;
+ break;
- Text_Paint(rect->x + 2, rect->y, scale, color, va("VENDOR: %s", uiInfo.uiDC.glconfig.vendor_string), 0, 30, textStyle);
- Text_Paint(rect->x + 2, rect->y + 15, scale, color, va("VERSION: %s: %s", uiInfo.uiDC.glconfig.version_string,uiInfo.uiDC.glconfig.renderer_string), 0, 30, textStyle);
- Text_Paint(rect->x + 2, rect->y + 30, scale, color, va ("PIXELFORMAT: color(%d-bits) Z(%d-bits) stencil(%d-bits)", uiInfo.uiDC.glconfig.colorBits, uiInfo.uiDC.glconfig.depthBits, uiInfo.uiDC.glconfig.stencilBits), 0, 30, textStyle);
+ case INFOTYPE_WEAPON:
+ value = BG_Weapon(item->v.weapon)->price;
- // build null terminated extension strings
- // TTimo: https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
- // in TA this was not directly crashing, but displaying a nasty broken shader right in the middle
- // brought down the string size to 1024, there's not much that can be shown on the screen anyway
- Q_strncpyz(buff, uiInfo.uiDC.glconfig.extensions_string, 1024);
- eptr = buff;
- y = rect->y + 45;
- numLines = 0;
- while ( y < rect->y + rect->h && *eptr )
- {
- while ( *eptr && *eptr == ' ' )
- *eptr++ = '\0';
+ if (value == 0)
+ {
+ s = va(
+ "%s\n\n%s\n\nCredits: Free", BG_Weapon(item->v.weapon)->humanName, BG_Weapon(item->v.weapon)->info);
+ }
+ else
+ {
+ s = va("%s\n\n%s\n\nCredits: %d", BG_Weapon(item->v.weapon)->humanName, BG_Weapon(item->v.weapon)->info,
+ value);
+ }
- // track start of valid string
- if (*eptr && *eptr != ' ') {
- lines[numLines++] = eptr;
- }
+ break;
- while ( *eptr && *eptr != ' ' )
- eptr++;
- }
+ case INFOTYPE_UPGRADE:
+ value = BG_Upgrade(item->v.upgrade)->price;
- i = 0;
- while (i < numLines) {
- Text_Paint(rect->x + 2, y, scale, color, lines[i++], 0, 20, textStyle);
- if (i < numLines) {
- Text_Paint(rect->x + rect->w / 2, y, scale, color, lines[i++], 0, 20, textStyle);
- }
- y += 10;
- if (y > rect->y + rect->h - 11) {
- break;
- }
- }
+ if (value == 0)
+ {
+ s = va("%s\n\n%s\n\nCredits: Free", BG_Upgrade(item->v.upgrade)->humanName,
+ BG_Upgrade(item->v.upgrade)->info);
+ }
+ else
+ {
+ s = va("%s\n\n%s\n\nCredits: %d", BG_Upgrade(item->v.upgrade)->humanName,
+ BG_Upgrade(item->v.upgrade)->info, value);
+ }
+ break;
-}
+ case INFOTYPE_BUILDABLE:
+ value = BG_Buildable(item->v.buildable)->buildPoints;
-// FIXME: table drive
-//
-static void UI_OwnerDraw( float x, float y, float w, float h,
- float text_x, float text_y, int ownerDraw,
- int ownerDrawFlags, int align, float special,
- float scale, vec4_t color, qhandle_t shader, int textStyle )
-{
- rectDef_t rect;
- tremInfoPane_t *pane = NULL;
-
- rect.x = x + text_x;
- rect.y = y + text_y;
- rect.w = w;
- rect.h = h;
-
- switch( ownerDraw )
- {
- case UI_TEAMINFOPANE:
- if( ( pane = uiInfo.tremTeamList[ uiInfo.tremTeamIndex ].infopane ) )
- UI_DrawInfoPane( pane, &rect, text_x, text_y, scale, color, textStyle );
- break;
-
- case UI_ACLASSINFOPANE:
- if( ( pane = uiInfo.tremAlienClassList[ uiInfo.tremAlienClassIndex ].infopane ) )
- UI_DrawInfoPane( pane, &rect, text_x, text_y, scale, color, textStyle );
- break;
-
- case UI_AUPGRADEINFOPANE:
- if( ( pane = uiInfo.tremAlienUpgradeList[ uiInfo.tremAlienUpgradeIndex ].infopane ) )
- UI_DrawInfoPane( pane, &rect, text_x, text_y, scale, color, textStyle );
- break;
-
- case UI_HITEMINFOPANE:
- if( ( pane = uiInfo.tremHumanItemList[ uiInfo.tremHumanItemIndex ].infopane ) )
- UI_DrawInfoPane( pane, &rect, text_x, text_y, scale, color, textStyle );
- break;
-
- case UI_HBUYINFOPANE:
- if( ( pane = uiInfo.tremHumanArmouryBuyList[ uiInfo.tremHumanArmouryBuyIndex ].infopane ) )
- UI_DrawInfoPane( pane, &rect, text_x, text_y, scale, color, textStyle );
- break;
-
- case UI_HSELLINFOPANE:
- if( ( pane = uiInfo.tremHumanArmourySellList[ uiInfo.tremHumanArmourySellIndex ].infopane ) )
- UI_DrawInfoPane( pane, &rect, text_x, text_y, scale, color, textStyle );
- break;
-
- case UI_ABUILDINFOPANE:
- if( ( pane = uiInfo.tremAlienBuildList[ uiInfo.tremAlienBuildIndex ].infopane ) )
- UI_DrawInfoPane( pane, &rect, text_x, text_y, scale, color, textStyle );
- break;
-
- case UI_HBUILDINFOPANE:
- if( ( pane = uiInfo.tremHumanBuildList[ uiInfo.tremHumanBuildIndex ].infopane ) )
- UI_DrawInfoPane( pane, &rect, text_x, text_y, scale, color, textStyle );
- break;
-
- case UI_HANDICAP:
- UI_DrawHandicap(&rect, scale, color, textStyle);
- break;
- case UI_PLAYERMODEL:
- UI_DrawPlayerModel(&rect);
- break;
- case UI_CLANNAME:
- UI_DrawClanName(&rect, scale, color, textStyle);
- break;
- case UI_CLANLOGO:
- UI_DrawClanLogo(&rect, scale, color);
- break;
- case UI_CLANCINEMATIC:
- UI_DrawClanCinematic(&rect, scale, color);
- break;
- case UI_PREVIEWCINEMATIC:
- UI_DrawPreviewCinematic(&rect, scale, color);
- break;
- case UI_GAMETYPE:
- UI_DrawGameType(&rect, scale, color, textStyle);
- break;
- case UI_NETGAMETYPE:
- UI_DrawNetGameType(&rect, scale, color, textStyle);
- break;
- case UI_JOINGAMETYPE:
- UI_DrawJoinGameType(&rect, scale, color, textStyle);
- break;
- case UI_MAPPREVIEW:
- UI_DrawMapPreview(&rect, scale, color, qtrue);
- break;
- case UI_MAP_TIMETOBEAT:
- UI_DrawMapTimeToBeat(&rect, scale, color, textStyle);
- break;
- case UI_MAPCINEMATIC:
- UI_DrawMapCinematic(&rect, scale, color, qfalse);
- break;
- case UI_STARTMAPCINEMATIC:
- UI_DrawMapCinematic(&rect, scale, color, qtrue);
- break;
- case UI_SKILL:
- UI_DrawSkill(&rect, scale, color, textStyle);
- break;
- case UI_BLUETEAMNAME:
- UI_DrawTeamName(&rect, scale, color, qtrue, textStyle);
- break;
- case UI_REDTEAMNAME:
- UI_DrawTeamName(&rect, scale, color, qfalse, textStyle);
- break;
- case UI_BLUETEAM1:
- case UI_BLUETEAM2:
- case UI_BLUETEAM3:
- case UI_BLUETEAM4:
- case UI_BLUETEAM5:
- UI_DrawTeamMember(&rect, scale, color, qtrue, ownerDraw - UI_BLUETEAM1 + 1, textStyle);
- break;
- case UI_REDTEAM1:
- case UI_REDTEAM2:
- case UI_REDTEAM3:
- case UI_REDTEAM4:
- case UI_REDTEAM5:
- UI_DrawTeamMember(&rect, scale, color, qfalse, ownerDraw - UI_REDTEAM1 + 1, textStyle);
- break;
- case UI_NETSOURCE:
- UI_DrawNetSource(&rect, scale, color, textStyle);
- break;
- case UI_NETMAPPREVIEW:
- UI_DrawNetMapPreview(&rect, scale, color);
- break;
- case UI_NETMAPCINEMATIC:
- UI_DrawNetMapCinematic(&rect, scale, color);
- break;
- case UI_NETFILTER:
- UI_DrawNetFilter(&rect, scale, color, textStyle);
- break;
- case UI_TIER:
- UI_DrawTier(&rect, scale, color, textStyle);
- break;
- case UI_OPPONENTMODEL:
- UI_DrawOpponent(&rect);
- break;
- case UI_TIERMAP1:
- UI_DrawTierMap(&rect, 0);
- break;
- case UI_TIERMAP2:
- UI_DrawTierMap(&rect, 1);
- break;
- case UI_TIERMAP3:
- UI_DrawTierMap(&rect, 2);
- break;
- case UI_PLAYERLOGO:
- UI_DrawPlayerLogo(&rect, color);
- break;
- case UI_PLAYERLOGO_METAL:
- UI_DrawPlayerLogoMetal(&rect, color);
- break;
- case UI_PLAYERLOGO_NAME:
- UI_DrawPlayerLogoName(&rect, color);
- break;
- case UI_OPPONENTLOGO:
- UI_DrawOpponentLogo(&rect, color);
- break;
- case UI_OPPONENTLOGO_METAL:
- UI_DrawOpponentLogoMetal(&rect, color);
- break;
- case UI_OPPONENTLOGO_NAME:
- UI_DrawOpponentLogoName(&rect, color);
- break;
- case UI_TIER_MAPNAME:
- UI_DrawTierMapName(&rect, scale, color, textStyle);
- break;
- case UI_TIER_GAMETYPE:
- UI_DrawTierGameType(&rect, scale, color, textStyle);
- break;
- case UI_ALLMAPS_SELECTION:
- UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qtrue);
- break;
- case UI_MAPS_SELECTION:
- UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qfalse);
- break;
- case UI_PLAYERLIST_SELECTION:
- UI_DrawPlayerListSelection(&rect, scale, color, textStyle);
- break;
- case UI_TEAMLIST_SELECTION:
- UI_DrawTeamListSelection(&rect, scale, color, textStyle);
- break;
- case UI_OPPONENT_NAME:
- UI_DrawOpponentName(&rect, scale, color, textStyle);
- break;
- case UI_BOTNAME:
- UI_DrawBotName(&rect, scale, color, textStyle);
- break;
- case UI_BOTSKILL:
- UI_DrawBotSkill(&rect, scale, color, textStyle);
- break;
- case UI_REDBLUE:
- UI_DrawRedBlue(&rect, scale, color, textStyle);
- break;
- case UI_SELECTEDPLAYER:
- UI_DrawSelectedPlayer(&rect, scale, color, textStyle);
- break;
- case UI_SERVERREFRESHDATE:
- UI_DrawServerRefreshDate(&rect, scale, color, textStyle);
- break;
- case UI_SERVERMOTD:
- UI_DrawServerMOTD(&rect, scale, color);
- break;
- case UI_GLINFO:
- UI_DrawGLInfo(&rect,scale, color, textStyle);
- break;
- case UI_KEYBINDSTATUS:
- UI_DrawKeyBindStatus(&rect,scale, color, textStyle);
- break;
- default:
- break;
- }
+ switch (BG_Buildable(item->v.buildable)->team)
+ {
+ case TEAM_ALIENS:
+ string = "Sentience";
+ break;
-}
+ case TEAM_HUMANS:
+ string = "Power";
+ break;
-static qboolean UI_OwnerDrawVisible(int flags) {
- qboolean vis = qtrue;
- uiClientState_t cs;
- pTeam_t team;
- char info[ MAX_INFO_STRING ];
+ default:
+ break;
+ }
- trap_GetClientState( &cs );
- trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
- team = atoi( Info_ValueForKey( info, "t" ) );
+ if (value == 0)
+ {
+ s = va("%s\n\n%s", BG_Buildable(item->v.buildable)->humanName, BG_Buildable(item->v.buildable)->info);
+ }
+ else
+ {
+ s = va("%s\n\n%s\n\n%s: %d", BG_Buildable(item->v.buildable)->humanName,
+ BG_Buildable(item->v.buildable)->info, string, value);
+ }
+ break;
+ }
- while (flags) {
+ UI_DrawTextBlock(rect, text_x, text_y, color, scale, textalign, textvalign, textStyle, s);
+}
- if( flags & UI_SHOW_NOTSPECTATING )
+static void UI_DrawServerMapPreview(rectDef_t *rect, float scale, vec4_t color)
+{
+ if (uiInfo.serverStatus.currentServerCinematic >= 0)
{
- if( team == PTE_NONE )
- vis = qfalse;
-
- flags &= ~UI_SHOW_NOTSPECTATING;
+ trap_CIN_RunCinematic(uiInfo.serverStatus.currentServerCinematic);
+ trap_CIN_SetExtents(uiInfo.serverStatus.currentServerCinematic, rect->x, rect->y, rect->w, rect->h);
+ trap_CIN_DrawCinematic(uiInfo.serverStatus.currentServerCinematic);
}
+ else if (uiInfo.serverStatus.currentServerPreview > 0)
+ UI_DrawHandlePic(rect->x, rect->y, rect->w, rect->h, uiInfo.serverStatus.currentServerPreview);
+ else
+ UI_DrawHandlePic(rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("gfx/2d/load_screen"));
+}
- if( flags & UI_SHOW_VOTEACTIVE )
- {
- if( !trap_Cvar_VariableValue( "ui_voteActive" ) )
- vis = qfalse;
-
- flags &= ~UI_SHOW_VOTEACTIVE;
- }
+static void UI_DrawSelectedMapPreview(rectDef_t *rect, float scale, vec4_t color)
+{
+ int map = ui_selectedMap.integer;
- if( flags & UI_SHOW_CANVOTE )
+ if (map < 0 || map > uiInfo.mapCount)
{
- if( trap_Cvar_VariableValue( "ui_voteActive" ) )
- vis = qfalse;
-
- flags &= ~UI_SHOW_CANVOTE;
+ ui_selectedMap.integer = 0;
+ trap_Cvar_Set("ui_selectedMap", "0");
+ map = 0;
}
- if( flags & UI_SHOW_TEAMVOTEACTIVE )
+ if (uiInfo.mapList[map].cinematic >= -1)
{
- if( team == PTE_ALIENS )
- {
- if( !trap_Cvar_VariableValue( "ui_alienTeamVoteActive" ) )
- vis = qfalse;
- }
- else if( team == PTE_HUMANS )
- {
- if( !trap_Cvar_VariableValue( "ui_humanTeamVoteActive" ) )
- vis = qfalse;
- }
+ if (uiInfo.mapList[map].cinematic == -1)
+ uiInfo.mapList[map].cinematic = trap_CIN_PlayCinematic(
+ va("%s.roq", uiInfo.mapList[map].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent));
- flags &= ~UI_SHOW_TEAMVOTEACTIVE;
+ if (uiInfo.mapList[map].cinematic >= 0)
+ {
+ trap_CIN_RunCinematic(uiInfo.mapList[map].cinematic);
+ trap_CIN_SetExtents(uiInfo.mapList[map].cinematic, rect->x, rect->y, rect->w, rect->h);
+ trap_CIN_DrawCinematic(uiInfo.mapList[map].cinematic);
+ }
+ else
+ uiInfo.mapList[map].cinematic = -2;
}
-
- if( flags & UI_SHOW_CANTEAMVOTE )
+ else
{
- if( team == PTE_ALIENS )
- {
- if( trap_Cvar_VariableValue( "ui_alienTeamVoteActive" ) )
- vis = qfalse;
- }
- else if( team == PTE_HUMANS )
- {
- if( trap_Cvar_VariableValue( "ui_humanTeamVoteActive" ) )
- vis = qfalse;
- }
-
- flags &= ~UI_SHOW_CANTEAMVOTE;
- }
+ if (uiInfo.mapList[map].levelShot == -1)
+ uiInfo.mapList[map].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[map].imageName);
- if (flags & UI_SHOW_LEADER) {
- // these need to show when this client can give orders to a player or a group
- if (!uiInfo.teamLeader) {
- vis = qfalse;
- } else {
- // if showing yourself
- if (ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber) {
- vis = qfalse;
- }
- }
- flags &= ~UI_SHOW_LEADER;
- }
- if (flags & UI_SHOW_NOTLEADER) {
- // these need to show when this client is assigning their own status or they are NOT the leader
- if (uiInfo.teamLeader) {
- // if not showing yourself
- if (!(ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber)) {
- vis = qfalse;
- }
- // these need to show when this client can give orders to a player or a group
- }
- flags &= ~UI_SHOW_NOTLEADER;
- }
- if (flags & UI_SHOW_FAVORITESERVERS) {
- // this assumes you only put this type of display flag on something showing in the proper context
- if (ui_netSource.integer != AS_FAVORITES) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_FAVORITESERVERS;
- }
- if (flags & UI_SHOW_NOTFAVORITESERVERS) {
- // this assumes you only put this type of display flag on something showing in the proper context
- if (ui_netSource.integer == AS_FAVORITES) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NOTFAVORITESERVERS;
- }
- if (flags & UI_SHOW_NEWHIGHSCORE) {
- if (uiInfo.newHighScoreTime < uiInfo.uiDC.realTime) {
- vis = qfalse;
- } else {
- if (uiInfo.soundHighScore) {
- if (trap_Cvar_VariableValue("sv_killserver") == 0) {
- // wait on server to go down before playing sound
- trap_S_StartLocalSound(uiInfo.newHighScoreSound, CHAN_ANNOUNCER);
- uiInfo.soundHighScore = qfalse;
- }
- }
- }
- flags &= ~UI_SHOW_NEWHIGHSCORE;
- }
- if (flags & UI_SHOW_NEWBESTTIME) {
- if (uiInfo.newBestTime < uiInfo.uiDC.realTime) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NEWBESTTIME;
- }
- if (flags & UI_SHOW_DEMOAVAILABLE) {
- if (!uiInfo.demoAvailable) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_DEMOAVAILABLE;
- } else {
- flags = 0;
+ if (uiInfo.mapList[map].levelShot > 0)
+ UI_DrawHandlePic(rect->x, rect->y, rect->w, rect->h, uiInfo.mapList[map].levelShot);
+ else
+ UI_DrawHandlePic(rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("gfx/2d/load_screen"));
}
- }
- return vis;
}
-static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int h;
- h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
- if (key == K_MOUSE2) {
- h -= 5;
- } else {
- h += 5;
- }
- if (h > 100) {
- h = 5;
- } else if (h < 0) {
- h = 100;
- }
- trap_Cvar_Set( "handicap", va( "%i", h) );
- return qtrue;
- }
- return qfalse;
-}
+static void UI_DrawSelectedMapName(rectDef_t *rect, float scale, vec4_t color, int textStyle)
+{
+ int map = ui_selectedMap.integer;
-static qboolean UI_ClanName_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (uiInfo.teamList[i].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
- uiInfo.teamList[i].cinematic = -1;
- }
- if (key == K_MOUSE2) {
- i--;
- } else {
- i++;
- }
- if (i >= uiInfo.teamCount) {
- i = 0;
- } else if (i < 0) {
- i = uiInfo.teamCount - 1;
- }
- trap_Cvar_Set( "ui_teamName", uiInfo.teamList[i].teamName);
- UI_HeadCountByTeam();
- UI_FeederSelection(FEEDER_HEADS, 0);
- updateModel = qtrue;
- return qtrue;
- }
- return qfalse;
+ if (map >= 0 && map < uiInfo.mapCount)
+ UI_Text_Paint(rect->x, rect->y, scale, color, uiInfo.mapList[map].mapName, 0, 0, textStyle);
}
-static qboolean UI_GameType_HandleKey(int flags, float *special, int key, qboolean resetMap) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int oldCount = UI_MapCountByGameType(qtrue);
-
- // hard coded mess here
- if (key == K_MOUSE2) {
- ui_gameType.integer--;
- if (ui_gameType.integer == 2) {
- ui_gameType.integer = 1;
- } else if (ui_gameType.integer < 2) {
- ui_gameType.integer = uiInfo.numGameTypes - 1;
- }
- } else {
- ui_gameType.integer++;
- if (ui_gameType.integer >= uiInfo.numGameTypes) {
- ui_gameType.integer = 1;
- } else if (ui_gameType.integer == 2) {
- ui_gameType.integer = 3;
- }
- }
+static const char *UI_OwnerDrawText(int ownerDraw)
+{
+ const char *s = NULL;
- trap_Cvar_Set("ui_Q3Model", "0");
+ switch (ownerDraw)
+ {
+ case UI_NETSOURCE:
+ if (ui_netSource.integer < 0 || ui_netSource.integer >= numNetSources)
+ ui_netSource.integer = 0;
- trap_Cvar_Set("ui_gameType", va("%d", ui_gameType.integer));
- UI_SetCapFragLimits(qtrue);
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
- if (resetMap && oldCount != UI_MapCountByGameType(qtrue)) {
- trap_Cvar_Set( "ui_currentMap", "0");
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, NULL);
- }
- return qtrue;
- }
- return qfalse;
-}
+ s = netSources[ui_netSource.integer];
+ break;
-static qboolean UI_NetGameType_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ case UI_KEYBINDSTATUS:
+ if (Display_KeyBindPending())
+ s = "Waiting for new key... Press ESCAPE to cancel";
+ else
+ s = "Press ENTER or CLICK to change, Press BACKSPACE to clear";
- if (key == K_MOUSE2) {
- ui_netGameType.integer--;
- } else {
- ui_netGameType.integer++;
- }
+ break;
- if (ui_netGameType.integer < 0) {
- ui_netGameType.integer = uiInfo.numGameTypes - 1;
- } else if (ui_netGameType.integer >= uiInfo.numGameTypes) {
- ui_netGameType.integer = 0;
- }
+ case UI_SERVERREFRESHDATE:
+ if (uiInfo.serverStatus.refreshActive)
+ {
+#define MAX_DOTS 5
+ int numServers = trap_LAN_GetServerCount(ui_netSource.integer);
+ int numDots = (uiInfo.uiDC.realTime / 500) % (MAX_DOTS + 1);
+ char dots[MAX_DOTS + 1];
+ int i;
- trap_Cvar_Set( "ui_netGameType", va("%d", ui_netGameType.integer));
- trap_Cvar_Set( "ui_actualnetGameType", va("%d", uiInfo.gameTypes[ui_netGameType.integer].gtEnum));
- trap_Cvar_Set( "ui_currentNetMap", "0");
- UI_MapCountByGameType(qfalse);
- Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, NULL);
- return qtrue;
- }
- return qfalse;
-}
+ for (i = 0; i < numDots; i++)
+ dots[i] = '.';
-static qboolean UI_JoinGameType_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ dots[i] = '\0';
- if (key == K_MOUSE2) {
- ui_joinGameType.integer--;
- } else {
- ui_joinGameType.integer++;
- }
+ s = numServers < 0 ? va("Waiting for response%s", dots)
+ : va("Getting info for %d servers (ESC to cancel)%s", numServers, dots);
+ }
+ else
+ s = va("Refresh Time: %s", UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer)));
- if (ui_joinGameType.integer < 0) {
- ui_joinGameType.integer = uiInfo.numJoinGameTypes - 1;
- } else if (ui_joinGameType.integer >= uiInfo.numJoinGameTypes) {
- ui_joinGameType.integer = 0;
+ break;
+
+ case UI_SERVERMOTD:
+ s = uiInfo.serverStatus.motd;
+ break;
+
+ default:
+ break;
}
- trap_Cvar_Set( "ui_joinGameType", va("%d", ui_joinGameType.integer));
- UI_BuildServerDisplayList(qtrue);
- return qtrue;
- }
- return qfalse;
+ return s;
}
+static int UI_OwnerDrawWidth(int ownerDraw, float scale)
+{
+ const char *s = NULL;
+ switch (ownerDraw)
+ {
+ case UI_NETSOURCE:
+ case UI_KEYBINDSTATUS:
+ case UI_SERVERREFRESHDATE:
+ case UI_SERVERMOTD:
+ s = UI_OwnerDrawText(ownerDraw);
+ break;
-static qboolean UI_Skill_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int i = trap_Cvar_VariableValue( "g_spSkill" );
-
- if (key == K_MOUSE2) {
- i--;
- } else {
- i++;
+ default:
+ break;
}
- if (i < 1) {
- i = numSkillLevels;
- } else if (i > numSkillLevels) {
- i = 1;
- }
+ if (s)
+ return UI_Text_Width(s, scale);
- trap_Cvar_Set("g_spSkill", va("%i", i));
- return qtrue;
- }
- return qfalse;
+ return 0;
}
-static qboolean UI_TeamName_HandleKey(int flags, float *special, int key, qboolean blue) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
+/*
+===============
+UI_BuildPlayerList
+===============
+*/
+static void UI_BuildPlayerList(void)
+{
+ uiClientState_t cs;
+ int n, count, team, team2;
+ char info[MAX_INFO_STRING];
+
+ trap_GetClientState(&cs);
+ trap_GetConfigString(CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING);
+ uiInfo.playerNumber = cs.clientNum;
+ team = atoi(Info_ValueForKey(info, "t"));
+ trap_GetConfigString(CS_SERVERINFO, info, sizeof(info));
+ count = atoi(Info_ValueForKey(info, "sv_maxclients"));
+ uiInfo.playerCount = 0;
+ uiInfo.myTeamCount = 0;
+ uiInfo.myPlayerIndex = 0;
+
+ for (n = 0; n < count; n++)
+ {
+ trap_GetConfigString(CS_PLAYERS + n, info, MAX_INFO_STRING);
- if (key == K_MOUSE2) {
- i--;
- } else {
- i++;
- }
+ if (info[0])
+ {
+ Com_ClientListParse(&uiInfo.ignoreList[uiInfo.playerCount], Info_ValueForKey(info, "ig"));
+ Q_strncpyz(uiInfo.rawPlayerNames[uiInfo.playerCount], Info_ValueForKey(info, "n"), MAX_NAME_LENGTH);
+ Q_strncpyz(uiInfo.playerNames[uiInfo.playerCount], Info_ValueForKey(info, "n"), MAX_NAME_LENGTH);
+ Q_CleanStr(uiInfo.playerNames[uiInfo.playerCount]);
+ uiInfo.clientNums[uiInfo.playerCount] = n;
- if (i >= uiInfo.teamCount) {
- i = 0;
- } else if (i < 0) {
- i = uiInfo.teamCount - 1;
- }
+ if (n == uiInfo.playerNumber)
+ uiInfo.myPlayerIndex = uiInfo.playerCount;
- trap_Cvar_Set( (blue) ? "ui_blueTeam" : "ui_redTeam", uiInfo.teamList[i].teamName);
+ uiInfo.playerCount++;
- return qtrue;
- }
- return qfalse;
-}
+ team2 = atoi(Info_ValueForKey(info, "t"));
-static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboolean blue, int num) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- // 0 - None
- // 1 - Human
- // 2..NumCharacters - Bot
- char *cvar = va(blue ? "ui_blueteam%i" : "ui_redteam%i", num);
- int value = trap_Cvar_VariableValue(cvar);
+ if (team2 == team)
+ {
+ Q_strncpyz(uiInfo.rawTeamNames[uiInfo.myTeamCount], Info_ValueForKey(info, "n"), MAX_NAME_LENGTH);
+ Q_strncpyz(uiInfo.teamNames[uiInfo.myTeamCount], Info_ValueForKey(info, "n"), MAX_NAME_LENGTH);
+ Q_CleanStr(uiInfo.teamNames[uiInfo.myTeamCount]);
+ uiInfo.teamClientNums[uiInfo.myTeamCount] = n;
- if (key == K_MOUSE2) {
- value--;
- } else {
- value++;
+ uiInfo.myTeamCount++;
+ }
+ }
}
+}
- if( value >= UI_GetNumBots( ) + 2 )
- value = 0;
- else if( value < 0 )
- value = UI_GetNumBots( ) + 2 - 1;
+static void UI_DrawGLInfo(rectDef_t *rect, float scale, int textalign, int textvalign, vec4_t color, int textStyle,
+ float text_x, float text_y)
+{
+ char buffer[4096];
- trap_Cvar_Set(cvar, va("%i", value));
- return qtrue;
- }
- return qfalse;
+ Com_sprintf(buffer, sizeof(buffer),
+ "VENDOR: %s\nVERSION: %s\n"
+ "PIXELFORMAT: color(%d-bits) Z(%d-bits) stencil(%d-bits)\n%s",
+ uiInfo.uiDC.glconfig.vendor_string, uiInfo.uiDC.glconfig.renderer_string, uiInfo.uiDC.glconfig.colorBits,
+ uiInfo.uiDC.glconfig.depthBits, uiInfo.uiDC.glconfig.stencilBits, uiInfo.uiDC.glconfig.extensions_string);
+
+ UI_DrawTextBlock(rect, text_x, text_y, color, scale, textalign, textvalign, textStyle, buffer);
}
-static qboolean UI_NetSource_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+// FIXME: table drive
+//
+static void UI_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw,
+ int ownerDrawFlags, int align, int textalign, int textvalign, float borderSize, float scale, vec4_t foreColor,
+ vec4_t backColor, qhandle_t shader, int textStyle)
+{
+ rectDef_t rect;
- if (key == K_MOUSE2) {
- ui_netSource.integer--;
- if (ui_netSource.integer == AS_MPLAYER)
- ui_netSource.integer--;
- } else {
- ui_netSource.integer++;
- if (ui_netSource.integer == AS_MPLAYER)
- ui_netSource.integer++;
- }
+ rect.x = x;
+ rect.y = y;
+ rect.w = w;
+ rect.h = h;
- if (ui_netSource.integer >= numNetSources) {
- ui_netSource.integer = 0;
- } else if (ui_netSource.integer < 0) {
- ui_netSource.integer = numNetSources - 1;
- }
+ switch (ownerDraw)
+ {
+ case UI_TEAMINFOPANE:
+ UI_DrawInfoPane(&uiInfo.teamList[uiInfo.teamIndex], &rect, text_x, text_y, scale, textalign, textvalign,
+ foreColor, textStyle);
+ break;
+
+ case UI_VOICECMDINFOPANE:
+ UI_DrawInfoPane(&uiInfo.voiceCmdList[uiInfo.voiceCmdIndex], &rect, text_x, text_y, scale, textalign,
+ textvalign, foreColor, textStyle);
+ break;
+
+ case UI_ACLASSINFOPANE:
+ UI_DrawInfoPane(&uiInfo.alienClassList[uiInfo.alienClassIndex], &rect, text_x, text_y, scale, textalign,
+ textvalign, foreColor, textStyle);
+ break;
+
+ case UI_AUPGRADEINFOPANE:
+ UI_DrawInfoPane(&uiInfo.alienUpgradeList[uiInfo.alienUpgradeIndex], &rect, text_x, text_y, scale, textalign,
+ textvalign, foreColor, textStyle);
+ break;
+
+ case UI_HITEMINFOPANE:
+ UI_DrawInfoPane(&uiInfo.humanItemList[uiInfo.humanItemIndex], &rect, text_x, text_y, scale, textalign,
+ textvalign, foreColor, textStyle);
+ break;
+
+ case UI_HBUYINFOPANE:
+ UI_DrawInfoPane(&uiInfo.humanArmouryBuyList[uiInfo.humanArmouryBuyIndex], &rect, text_x, text_y, scale,
+ textalign, textvalign, foreColor, textStyle);
+ break;
+
+ case UI_HSELLINFOPANE:
+ UI_DrawInfoPane(&uiInfo.humanArmourySellList[uiInfo.humanArmourySellIndex], &rect, text_x, text_y, scale,
+ textalign, textvalign, foreColor, textStyle);
+ break;
+
+ case UI_ABUILDINFOPANE:
+ UI_DrawInfoPane(&uiInfo.alienBuildList[uiInfo.alienBuildIndex], &rect, text_x, text_y, scale, textalign,
+ textvalign, foreColor, textStyle);
+ break;
+
+ case UI_HBUILDINFOPANE:
+ UI_DrawInfoPane(&uiInfo.humanBuildList[uiInfo.humanBuildIndex], &rect, text_x, text_y, scale, textalign,
+ textvalign, foreColor, textStyle);
+ break;
+
+ case UI_HELPINFOPANE:
+ UI_DrawInfoPane(&uiInfo.helpList[uiInfo.helpIndex], &rect, text_x, text_y, scale, textalign, textvalign,
+ foreColor, textStyle);
+ break;
+
+ case UI_NETMAPPREVIEW:
+ UI_DrawServerMapPreview(&rect, scale, foreColor);
+ break;
+
+ case UI_SELECTEDMAPPREVIEW:
+ UI_DrawSelectedMapPreview(&rect, scale, foreColor);
+ break;
+
+ case UI_SELECTEDMAPNAME:
+ UI_DrawSelectedMapName(&rect, scale, foreColor, textStyle);
+ break;
+
+ case UI_GLINFO:
+ UI_DrawGLInfo(&rect, scale, textalign, textvalign, foreColor, textStyle, text_x, text_y);
+ break;
- UI_BuildServerDisplayList(qtrue);
- if (ui_netSource.integer != AS_GLOBAL) {
- UI_StartServerRefresh(qtrue);
+ default:
+ break;
}
- trap_Cvar_Set( "ui_netSource", va("%d", ui_netSource.integer));
- return qtrue;
- }
- return qfalse;
}
-static qboolean UI_NetFilter_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+static qboolean UI_OwnerDrawVisible(int flags)
+{
+ qboolean vis = qtrue;
+ uiClientState_t cs;
+ team_t team;
+ char info[MAX_INFO_STRING];
- if (key == K_MOUSE2) {
- ui_serverFilterType.integer--;
- } else {
- ui_serverFilterType.integer++;
- }
+ trap_GetClientState(&cs);
+ trap_GetConfigString(CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING);
+ team = atoi(Info_ValueForKey(info, "t"));
- if (ui_serverFilterType.integer >= numServerFilters) {
- ui_serverFilterType.integer = 0;
- } else if (ui_serverFilterType.integer < 0) {
- ui_serverFilterType.integer = numServerFilters - 1;
- }
- UI_BuildServerDisplayList(qtrue);
- return qtrue;
- }
- return qfalse;
-}
+ while (flags)
+ {
+ if (flags & UI_SHOW_NOTSPECTATING)
+ {
+ if (team == TEAM_NONE)
+ vis = qfalse;
-static qboolean UI_OpponentName_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- if (key == K_MOUSE2) {
- UI_PriorOpponent();
- } else {
- UI_NextOpponent();
- }
- return qtrue;
- }
- return qfalse;
-}
+ flags &= ~UI_SHOW_NOTSPECTATING;
+ }
-static qboolean UI_BotName_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int value = uiInfo.botIndex;
+ if (flags & UI_SHOW_VOTEACTIVE)
+ {
+ if (!trap_Cvar_VariableValue("ui_voteActive"))
+ vis = qfalse;
- if (key == K_MOUSE2) {
- value--;
- } else {
- value++;
- }
+ flags &= ~UI_SHOW_VOTEACTIVE;
+ }
+ if (flags & UI_SHOW_CANVOTE)
+ {
+ if (trap_Cvar_VariableValue("ui_voteActive"))
+ vis = qfalse;
- if( value >= UI_GetNumBots( ) + 2 )
- value = 0;
- else if( value < 0 )
- value = UI_GetNumBots( ) + 2 - 1;
+ flags &= ~UI_SHOW_CANVOTE;
+ }
- uiInfo.botIndex = value;
- return qtrue;
- }
- return qfalse;
-}
+ if (flags & UI_SHOW_TEAMVOTEACTIVE)
+ {
+ if (team == TEAM_ALIENS)
+ {
+ if (!trap_Cvar_VariableValue("ui_alienTeamVoteActive"))
+ vis = qfalse;
+ }
+ else if (team == TEAM_HUMANS)
+ {
+ if (!trap_Cvar_VariableValue("ui_humanTeamVoteActive"))
+ vis = qfalse;
+ }
-static qboolean UI_BotSkill_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- if (key == K_MOUSE2) {
- uiInfo.skillIndex--;
- } else {
- uiInfo.skillIndex++;
- }
- if (uiInfo.skillIndex >= numSkillLevels) {
- uiInfo.skillIndex = 0;
- } else if (uiInfo.skillIndex < 0) {
- uiInfo.skillIndex = numSkillLevels-1;
- }
- return qtrue;
- }
- return qfalse;
-}
+ flags &= ~UI_SHOW_TEAMVOTEACTIVE;
+ }
-static qboolean UI_RedBlue_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- uiInfo.redBlue ^= 1;
- return qtrue;
- }
- return qfalse;
-}
+ if (flags & UI_SHOW_CANTEAMVOTE)
+ {
+ if (team == TEAM_ALIENS)
+ {
+ if (trap_Cvar_VariableValue("ui_alienTeamVoteActive"))
+ vis = qfalse;
+ }
+ else if (team == TEAM_HUMANS)
+ {
+ if (trap_Cvar_VariableValue("ui_humanTeamVoteActive"))
+ vis = qfalse;
+ }
+ flags &= ~UI_SHOW_CANTEAMVOTE;
+ }
+ if (flags & UI_SHOW_FAVORITESERVERS)
+ {
+ // this assumes you only put this type of display flag on something showing in the proper context
-static qboolean UI_SelectedPlayer_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int selected;
+ if (ui_netSource.integer != AS_FAVORITES)
+ vis = qfalse;
- UI_BuildPlayerList();
- if (!uiInfo.teamLeader) {
- return qfalse;
- }
- selected = trap_Cvar_VariableValue("cg_selectedPlayer");
+ flags &= ~UI_SHOW_FAVORITESERVERS;
+ }
- if (key == K_MOUSE2) {
- selected--;
- } else {
- selected++;
- }
+ if (flags & UI_SHOW_NOTFAVORITESERVERS)
+ {
+ // this assumes you only put this type of display flag on something showing in the proper context
- if (selected > uiInfo.myTeamCount) {
- selected = 0;
- } else if (selected < 0) {
- selected = uiInfo.myTeamCount;
- }
+ if (ui_netSource.integer == AS_FAVORITES)
+ vis = qfalse;
- if (selected == uiInfo.myTeamCount) {
- trap_Cvar_Set( "cg_selectedPlayerName", "Everyone");
- } else {
- trap_Cvar_Set( "cg_selectedPlayerName", uiInfo.teamNames[selected]);
+ flags &= ~UI_SHOW_NOTFAVORITESERVERS;
+ }
+ else
+ flags = 0;
}
- trap_Cvar_Set( "cg_selectedPlayer", va("%d", selected));
- }
- return qfalse;
+
+ return vis;
}
+static qboolean UI_NetSource_HandleKey(int key)
+{
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER)
+ {
+ if (key == K_MOUSE2)
+ {
+ ui_netSource.integer--;
-static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
- switch (ownerDraw) {
- case UI_HANDICAP:
- return UI_Handicap_HandleKey(flags, special, key);
- break;
- case UI_CLANNAME:
- return UI_ClanName_HandleKey(flags, special, key);
- break;
- case UI_GAMETYPE:
- return UI_GameType_HandleKey(flags, special, key, qtrue);
- break;
- case UI_NETGAMETYPE:
- return UI_NetGameType_HandleKey(flags, special, key);
- break;
- case UI_JOINGAMETYPE:
- return UI_JoinGameType_HandleKey(flags, special, key);
- break;
- case UI_SKILL:
- return UI_Skill_HandleKey(flags, special, key);
- break;
- case UI_BLUETEAMNAME:
- return UI_TeamName_HandleKey(flags, special, key, qtrue);
- break;
- case UI_REDTEAMNAME:
- return UI_TeamName_HandleKey(flags, special, key, qfalse);
- break;
- case UI_BLUETEAM1:
- case UI_BLUETEAM2:
- case UI_BLUETEAM3:
- case UI_BLUETEAM4:
- case UI_BLUETEAM5:
- UI_TeamMember_HandleKey(flags, special, key, qtrue, ownerDraw - UI_BLUETEAM1 + 1);
- break;
- case UI_REDTEAM1:
- case UI_REDTEAM2:
- case UI_REDTEAM3:
- case UI_REDTEAM4:
- case UI_REDTEAM5:
- UI_TeamMember_HandleKey(flags, special, key, qfalse, ownerDraw - UI_REDTEAM1 + 1);
- break;
- case UI_NETSOURCE:
- UI_NetSource_HandleKey(flags, special, key);
- break;
- case UI_NETFILTER:
- UI_NetFilter_HandleKey(flags, special, key);
- break;
- case UI_OPPONENT_NAME:
- UI_OpponentName_HandleKey(flags, special, key);
- break;
- case UI_BOTNAME:
- return UI_BotName_HandleKey(flags, special, key);
- break;
- case UI_BOTSKILL:
- return UI_BotSkill_HandleKey(flags, special, key);
- break;
- case UI_REDBLUE:
- UI_RedBlue_HandleKey(flags, special, key);
- break;
- case UI_SELECTEDPLAYER:
- UI_SelectedPlayer_HandleKey(flags, special, key);
- break;
- default:
- break;
- }
-
- return qfalse;
+ if (ui_netSource.integer == AS_MPLAYER)
+ ui_netSource.integer--;
+ }
+ else
+ {
+ ui_netSource.integer++;
+
+ if (ui_netSource.integer == AS_MPLAYER)
+ ui_netSource.integer++;
+ }
+
+ if (ui_netSource.integer < 0)
+ ui_netSource.integer = numNetSources - 1;
+ else if (ui_netSource.integer >= numNetSources)
+ ui_netSource.integer = 0;
+
+ UI_BuildServerDisplayList(qtrue);
+
+ if (ui_netSource.integer != AS_GLOBAL)
+ UI_StartServerRefresh(qtrue);
+
+ trap_Cvar_Set("ui_netSource", va("%d", ui_netSource.integer));
+ return qtrue;
+ }
+
+ return qfalse;
}
+static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int key)
+{
+ switch (ownerDraw)
+ {
+ case UI_NETSOURCE:
+ UI_NetSource_HandleKey(key);
+ break;
-static float UI_GetValue(int ownerDraw) {
- return 0;
+ default:
+ break;
+ }
+
+ return qfalse;
}
/*
@@ -3108,446 +2321,462 @@ static float UI_GetValue(int ownerDraw) {
UI_ServersQsortCompare
=================
*/
-static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ) {
- return trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey, uiInfo.serverStatus.sortDir, *(int*)arg1, *(int*)arg2);
+static int QDECL UI_ServersQsortCompare(const void *arg1, const void *arg2)
+{
+ return trap_LAN_CompareServers(
+ ui_netSource.integer, uiInfo.serverStatus.sortKey, uiInfo.serverStatus.sortDir, *(int *)arg1, *(int *)arg2);
}
-
/*
=================
UI_ServersSort
=================
*/
-void UI_ServersSort(int column, qboolean force) {
-
- if ( !force ) {
- if ( uiInfo.serverStatus.sortKey == column ) {
- return;
+void UI_ServersSort(int column, qboolean force)
+{
+ if (!force)
+ {
+ if (uiInfo.serverStatus.sortKey == column)
+ return;
}
- }
- uiInfo.serverStatus.sortKey = column;
- qsort( &uiInfo.serverStatus.displayServers[0], uiInfo.serverStatus.numDisplayServers, sizeof(int), UI_ServersQsortCompare);
+ uiInfo.serverStatus.sortKey = column;
+ qsort(&uiInfo.serverStatus.displayServers[0], uiInfo.serverStatus.numDisplayServers, sizeof(int),
+ UI_ServersQsortCompare);
}
-
/*
===============
-UI_GetCurrentAlienStage
+UI_LoadTeams
===============
*/
-static stage_t UI_GetCurrentAlienStage( void )
+static void UI_LoadTeams(void)
{
- char buffer[ MAX_TOKEN_CHARS ];
- stage_t stage, dummy;
-
- trap_Cvar_VariableStringBuffer( "ui_stages", buffer, sizeof( buffer ) );
- sscanf( buffer, "%d %d", (int *)&stage , (int *)&dummy );
-
- return stage;
+ uiInfo.teamCount = 4;
+
+ uiInfo.teamList[0].text = "Aliens";
+ uiInfo.teamList[0].cmd = "cmd team aliens\n";
+ uiInfo.teamList[0].type = INFOTYPE_TEXT;
+ uiInfo.teamList[0].v.text =
+ "The Alien Team\n\n"
+ "The Aliens' strengths are in movement and the ability to "
+ "quickly construct new bases quickly. They possess a range "
+ "of abilities including basic melee attacks, movement-"
+ "crippling poisons and more.";
+
+ uiInfo.teamList[1].text = "Humans";
+ uiInfo.teamList[1].cmd = "cmd team humans\n";
+ uiInfo.teamList[1].type = INFOTYPE_TEXT;
+ uiInfo.teamList[1].v.text =
+ "The Human Team\n\n"
+ "The humans are the masters of technology. Although their "
+ "bases take long to construct, their automated defense "
+ "ensures they stay built. A wide range of upgrades and "
+ "weapons are available to the humans, each contributing "
+ "to eradicate the alien threat.";
+
+ uiInfo.teamList[2].text = "Spectate";
+ uiInfo.teamList[2].cmd = "cmd team spectate\n";
+ uiInfo.teamList[2].type = INFOTYPE_TEXT;
+ uiInfo.teamList[2].v.text = "Watch the game without playing.";
+
+ uiInfo.teamList[3].text = "Auto select";
+ uiInfo.teamList[3].cmd = "cmd team auto\n";
+ uiInfo.teamList[3].type = INFOTYPE_TEXT;
+ uiInfo.teamList[3].v.text = "Join the team with the least players.";
}
/*
===============
-UI_GetCurrentHumanStage
+UI_AddClass
===============
*/
-static stage_t UI_GetCurrentHumanStage( void )
+
+static void UI_AddClass(class_t class)
{
- char buffer[ MAX_TOKEN_CHARS ];
- stage_t stage, dummy;
+ uiInfo.alienClassList[uiInfo.alienClassCount].text = BG_ClassConfig(class)->humanName;
+ uiInfo.alienClassList[uiInfo.alienClassCount].cmd = String_Alloc(va("cmd class %s\n", BG_Class(class)->name));
+ uiInfo.alienClassList[uiInfo.alienClassCount].type = INFOTYPE_CLASS;
- trap_Cvar_VariableStringBuffer( "ui_stages", buffer, sizeof( buffer ) );
- sscanf( buffer, "%d %d", (int *)&dummy, (int *)&stage );
+ uiInfo.alienClassList[uiInfo.alienClassCount].v.pclass = class;
- return stage;
+ uiInfo.alienClassCount++;
}
/*
===============
-UI_LoadTremTeams
+UI_LoadAlienClasses
===============
*/
-static void UI_LoadTremTeams( void )
+static void UI_LoadAlienClasses(void)
{
- uiInfo.tremTeamCount = 4;
+ uiInfo.alienClassCount = 0;
- uiInfo.tremTeamList[ 0 ].text = String_Alloc( "Aliens" );
- uiInfo.tremTeamList[ 0 ].cmd = String_Alloc( "cmd team aliens\n" );
- uiInfo.tremTeamList[ 0 ].infopane = UI_FindInfoPaneByName( "alienteam" );
+ if (BG_ClassIsAllowed(PCL_ALIEN_LEVEL0))
+ UI_AddClass(PCL_ALIEN_LEVEL0);
- uiInfo.tremTeamList[ 1 ].text = String_Alloc( "Humans" );
- uiInfo.tremTeamList[ 1 ].cmd = String_Alloc( "cmd team humans\n" );
- uiInfo.tremTeamList[ 1 ].infopane = UI_FindInfoPaneByName( "humanteam" );
-
- uiInfo.tremTeamList[ 2 ].text = String_Alloc( "Spectate" );
- uiInfo.tremTeamList[ 2 ].cmd = String_Alloc( "cmd team spectate\n" );
- uiInfo.tremTeamList[ 2 ].infopane = UI_FindInfoPaneByName( "spectateteam" );
-
- uiInfo.tremTeamList[ 3 ].text = String_Alloc( "Auto select" );
- uiInfo.tremTeamList[ 3 ].cmd = String_Alloc( "cmd team auto\n" );
- uiInfo.tremTeamList[ 3 ].infopane = UI_FindInfoPaneByName( "autoteam" );
+ if (BG_ClassIsAllowed(PCL_ALIEN_BUILDER0_UPG) &&
+ BG_ClassAllowedInStage(PCL_ALIEN_BUILDER0_UPG, UI_GetCurrentAlienStage()))
+ UI_AddClass(PCL_ALIEN_BUILDER0_UPG);
+ else if (BG_ClassIsAllowed(PCL_ALIEN_BUILDER0))
+ UI_AddClass(PCL_ALIEN_BUILDER0);
}
/*
===============
-UI_AddClass
+UI_AddItem
===============
*/
-static void UI_AddClass( pClass_t class )
+static void UI_AddItem(weapon_t weapon)
{
- uiInfo.tremAlienClassList[ uiInfo.tremAlienClassCount ].text =
- String_Alloc( BG_FindHumanNameForClassNum( class ) );
- uiInfo.tremAlienClassList[ uiInfo.tremAlienClassCount ].cmd =
- String_Alloc( va( "cmd class %s\n", BG_FindNameForClassNum( class ) ) );
- uiInfo.tremAlienClassList[ uiInfo.tremAlienClassCount ].infopane =
- UI_FindInfoPaneByName( va( "%sclass", BG_FindNameForClassNum( class ) ) );
-
- uiInfo.tremAlienClassCount++;
+ uiInfo.humanItemList[uiInfo.humanItemCount].text = BG_Weapon(weapon)->humanName;
+ uiInfo.humanItemList[uiInfo.humanItemCount].cmd = String_Alloc(va("cmd class %s\n", BG_Weapon(weapon)->name));
+ uiInfo.humanItemList[uiInfo.humanItemCount].type = INFOTYPE_WEAPON;
+ uiInfo.humanItemList[uiInfo.humanItemCount].v.weapon = weapon;
+
+ uiInfo.humanItemCount++;
}
/*
===============
-UI_LoadTremAlienClasses
+UI_LoadHumanItems
===============
*/
-static void UI_LoadTremAlienClasses( void )
+static void UI_LoadHumanItems(void)
{
- uiInfo.tremAlienClassCount = 0;
+ uiInfo.humanItemCount = 0;
- if( BG_ClassIsAllowed( PCL_ALIEN_LEVEL0 ) )
- UI_AddClass( PCL_ALIEN_LEVEL0 );
+ if (BG_WeaponIsAllowed(WP_MACHINEGUN))
+ UI_AddItem(WP_MACHINEGUN);
- if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0_UPG ) &&
- BG_FindStagesForClass( PCL_ALIEN_BUILDER0_UPG, UI_GetCurrentAlienStage( ) ) )
- UI_AddClass( PCL_ALIEN_BUILDER0_UPG );
- else if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0 ) )
- UI_AddClass( PCL_ALIEN_BUILDER0 );
+ if (BG_WeaponIsAllowed(WP_HBUILD))
+ UI_AddItem(WP_HBUILD);
}
/*
===============
-UI_AddItem
+UI_ParseCarriageList
===============
*/
-static void UI_AddItem( weapon_t weapon )
+static void UI_ParseCarriageList(void)
{
- uiInfo.tremHumanItemList[ uiInfo.tremHumanItemCount ].text =
- String_Alloc( BG_FindHumanNameForWeapon( weapon ) );
- uiInfo.tremHumanItemList[ uiInfo.tremHumanItemCount ].cmd =
- String_Alloc( va( "cmd class %s\n", BG_FindNameForWeapon( weapon ) ) );
- uiInfo.tremHumanItemList[ uiInfo.tremHumanItemCount ].infopane =
- UI_FindInfoPaneByName( va( "%sitem", BG_FindNameForWeapon( weapon ) ) );
-
- uiInfo.tremHumanItemCount++;
-}
+ int i;
+ char carriageCvar[MAX_TOKEN_CHARS];
+ char *iterator;
+ char buffer[MAX_TOKEN_CHARS];
+ char *bufPointer;
-/*
-===============
-UI_LoadTremHumanItems
-===============
-*/
-static void UI_LoadTremHumanItems( void )
-{
- uiInfo.tremHumanItemCount = 0;
+ trap_Cvar_VariableStringBuffer("ui_carriage", carriageCvar, sizeof(carriageCvar));
+ iterator = carriageCvar;
- if( BG_WeaponIsAllowed( WP_MACHINEGUN ) )
- UI_AddItem( WP_MACHINEGUN );
+ uiInfo.weapons = 0;
+ uiInfo.upgrades = 0;
+
+ // simple parser to give rise to weapon/upgrade list
+
+ while (iterator && iterator[0] != '$')
+ {
+ bufPointer = buffer;
+
+ if (iterator[0] == 'W')
+ {
+ iterator++;
+
+ while (iterator[0] != ' ')
+ *bufPointer++ = *iterator++;
+
+ *bufPointer++ = '\n';
+
+ i = atoi(buffer);
+
+ uiInfo.weapons |= (1 << i);
+ }
+ else if (iterator[0] == 'U')
+ {
+ iterator++;
+
+ while (iterator[0] != ' ')
+ *bufPointer++ = *iterator++;
+
+ *bufPointer++ = '\n';
+
+ i = atoi(buffer);
+
+ uiInfo.upgrades |= (1 << i);
+ }
- if( BG_WeaponIsAllowed( WP_HBUILD2 ) &&
- BG_FindStagesForWeapon( WP_HBUILD2, UI_GetCurrentHumanStage( ) ) )
- UI_AddItem( WP_HBUILD2 );
- else if( BG_WeaponIsAllowed( WP_HBUILD ) )
- UI_AddItem( WP_HBUILD );
+ iterator++;
+ }
}
/*
===============
-UI_ParseCarriageList
+UI_LoadHumanArmouryBuys
===============
*/
-static void UI_ParseCarriageList( int *weapons, int *upgrades )
+static void UI_LoadHumanArmouryBuys(void)
{
- int i;
- char carriageCvar[ MAX_TOKEN_CHARS ];
- char *iterator;
- char buffer[ MAX_TOKEN_CHARS ];
- char *bufPointer;
+ int i, j = 0;
+ stage_t stage = UI_GetCurrentHumanStage();
+ int slots = 0;
- trap_Cvar_VariableStringBuffer( "ui_carriage", carriageCvar, sizeof( carriageCvar ) );
- iterator = carriageCvar;
+ UI_ParseCarriageList();
- if( weapons )
- *weapons = 0;
+ for (i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++)
+ {
+ if (uiInfo.weapons & (1 << i))
+ slots |= BG_Weapon(i)->slots;
+ }
- if( upgrades )
- *upgrades = 0;
+ for (i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++)
+ {
+ if (uiInfo.upgrades & (1 << i))
+ slots |= BG_Upgrade(i)->slots;
+ }
- //simple parser to give rise to weapon/upgrade list
- while( iterator && iterator[ 0 ] != '$' )
- {
- bufPointer = buffer;
+ uiInfo.humanArmouryBuyCount = 0;
- if( iterator[ 0 ] == 'W' )
+ for (i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++)
{
- iterator++;
+ if (BG_Weapon(i)->team == TEAM_HUMANS && BG_Weapon(i)->purchasable && BG_WeaponAllowedInStage(i, stage) &&
+ BG_WeaponIsAllowed(i) && !(BG_Weapon(i)->slots & slots) && !(uiInfo.weapons & (1 << i)))
+ {
+ uiInfo.humanArmouryBuyList[j].text = BG_Weapon(i)->humanName;
+ uiInfo.humanArmouryBuyList[j].cmd = String_Alloc(va("cmd buy %s\n", BG_Weapon(i)->name));
+ uiInfo.humanArmouryBuyList[j].type = INFOTYPE_WEAPON;
+ uiInfo.humanArmouryBuyList[j].v.weapon = i;
- while( iterator[ 0 ] != ' ' )
- *bufPointer++ = *iterator++;
+ j++;
- *bufPointer++ = '\n';
+ uiInfo.humanArmouryBuyCount++;
+ }
+ }
- i = atoi( buffer );
+ for (i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++)
+ {
+ if (BG_Upgrade(i)->team == TEAM_HUMANS && BG_Upgrade(i)->purchasable && BG_UpgradeAllowedInStage(i, stage) &&
+ BG_UpgradeIsAllowed(i) && !(BG_Upgrade(i)->slots & slots) && !(uiInfo.upgrades & (1 << i)))
+ {
+ uiInfo.humanArmouryBuyList[j].text = BG_Upgrade(i)->humanName;
+ uiInfo.humanArmouryBuyList[j].cmd = String_Alloc(va("cmd buy %s\n", BG_Upgrade(i)->name));
+ uiInfo.humanArmouryBuyList[j].type = INFOTYPE_UPGRADE;
+ uiInfo.humanArmouryBuyList[j].v.upgrade = i;
- if( weapons )
- *weapons |= ( 1 << i );
+ j++;
+
+ uiInfo.humanArmouryBuyCount++;
+ }
}
- else if( iterator[ 0 ] == 'U' )
- {
- iterator++;
+}
- while( iterator[ 0 ] != ' ' )
- *bufPointer++ = *iterator++;
+/*
+===============
+UI_LoadHumanArmourySells
+===============
+*/
+static void UI_LoadHumanArmourySells(void)
+{
+ int i, j = 0;
- *bufPointer++ = '\n';
+ uiInfo.humanArmourySellCount = 0;
+ UI_ParseCarriageList();
- i = atoi( buffer );
+ for (i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++)
+ {
+ if (uiInfo.weapons & (1 << i))
+ {
+ uiInfo.humanArmourySellList[j].text = BG_Weapon(i)->humanName;
+ uiInfo.humanArmourySellList[j].cmd = String_Alloc(va("cmd sell %s\n", BG_Weapon(i)->name));
+ uiInfo.humanArmourySellList[j].type = INFOTYPE_WEAPON;
+ uiInfo.humanArmourySellList[j].v.weapon = i;
+
+ j++;
- if( upgrades )
- *upgrades |= ( 1 << i );
+ uiInfo.humanArmourySellCount++;
+ }
}
- iterator++;
- }
+ for (i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++)
+ {
+ if (uiInfo.upgrades & (1 << i))
+ {
+ uiInfo.humanArmourySellList[j].text = BG_Upgrade(i)->humanName;
+ uiInfo.humanArmourySellList[j].cmd = String_Alloc(va("cmd sell %s\n", BG_Upgrade(i)->name));
+ uiInfo.humanArmourySellList[j].type = INFOTYPE_UPGRADE;
+ uiInfo.humanArmourySellList[j].v.upgrade = i;
+
+ j++;
+
+ uiInfo.humanArmourySellCount++;
+ }
+ }
}
/*
===============
-UI_LoadTremHumanArmouryBuys
+UI_ArmouryRefreshCb
===============
*/
-static void UI_LoadTremHumanArmouryBuys( void )
+static void UI_ArmouryRefreshCb(void *data)
{
- int i, j = 0;
- stage_t stage = UI_GetCurrentHumanStage( );
- int weapons, upgrades;
- int slots = 0;
-
- UI_ParseCarriageList( &weapons, &upgrades );
-
- for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
- {
- if( weapons & ( 1 << i ) )
- slots |= BG_FindSlotsForWeapon( i );
- }
-
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- {
- if( upgrades & ( 1 << i ) )
- slots |= BG_FindSlotsForUpgrade( i );
- }
-
- uiInfo.tremHumanArmouryBuyCount = 0;
-
- for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
- {
- if( BG_FindTeamForWeapon( i ) == WUT_HUMANS &&
- BG_FindPurchasableForWeapon( i ) &&
- BG_FindStagesForWeapon( i, stage ) &&
- BG_WeaponIsAllowed( i ) &&
- !( BG_FindSlotsForWeapon( i ) & slots ) &&
- !( weapons & ( 1 << i ) ) )
- {
- uiInfo.tremHumanArmouryBuyList[ j ].text =
- String_Alloc( BG_FindHumanNameForWeapon( i ) );
- uiInfo.tremHumanArmouryBuyList[ j ].cmd =
- String_Alloc( va( "cmd buy %s retrigger\n", BG_FindNameForWeapon( i ) ) );
- uiInfo.tremHumanArmouryBuyList[ j ].infopane =
- UI_FindInfoPaneByName( va( "%sitem", BG_FindNameForWeapon( i ) ) );
-
- j++;
-
- uiInfo.tremHumanArmouryBuyCount++;
- }
- }
-
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- {
- if( BG_FindTeamForUpgrade( i ) == WUT_HUMANS &&
- BG_FindPurchasableForUpgrade( i ) &&
- BG_FindStagesForUpgrade( i, stage ) &&
- BG_UpgradeIsAllowed( i ) &&
- !( BG_FindSlotsForUpgrade( i ) & slots ) &&
- !( upgrades & ( 1 << i ) ) )
- {
- uiInfo.tremHumanArmouryBuyList[ j ].text =
- String_Alloc( BG_FindHumanNameForUpgrade( i ) );
- uiInfo.tremHumanArmouryBuyList[ j ].cmd =
- String_Alloc( va( "cmd buy %s retrigger\n", BG_FindNameForUpgrade( i ) ) );
- uiInfo.tremHumanArmouryBuyList[ j ].infopane =
- UI_FindInfoPaneByName( va( "%sitem", BG_FindNameForUpgrade( i ) ) );
-
- j++;
-
- uiInfo.tremHumanArmouryBuyCount++;
- }
- }
+ int oldWeapons = uiInfo.weapons;
+ int oldUpgrades = uiInfo.upgrades;
+
+ UI_ParseCarriageList();
+
+ if (uiInfo.weapons != oldWeapons || uiInfo.upgrades != oldUpgrades)
+ {
+ UI_LoadHumanArmouryBuys();
+ UI_LoadHumanArmourySells();
+ UI_RemoveCaptureFunc();
+ }
}
/*
===============
-UI_LoadTremHumanArmourySells
+UI_LoadAlienUpgrades
===============
*/
-static void UI_LoadTremHumanArmourySells( void )
+static void UI_LoadAlienUpgrades(void)
{
- int weapons, upgrades;
- int i, j = 0;
+ int i, j = 0;
- uiInfo.tremHumanArmourySellCount = 0;
- UI_ParseCarriageList( &weapons, &upgrades );
+ int class, credits;
+ char ui_currentClass[MAX_STRING_CHARS];
+ stage_t stage = UI_GetCurrentAlienStage();
- for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
- {
- if( weapons & ( 1 << i ) )
- {
- uiInfo.tremHumanArmourySellList[ j ].text = String_Alloc( BG_FindHumanNameForWeapon( i ) );
- uiInfo.tremHumanArmourySellList[ j ].cmd =
- String_Alloc( va( "cmd sell %s retrigger\n", BG_FindNameForWeapon( i ) ) );
- uiInfo.tremHumanArmourySellList[ j ].infopane =
- UI_FindInfoPaneByName( va( "%sitem", BG_FindNameForWeapon( i ) ) );
+ trap_Cvar_VariableStringBuffer("ui_currentClass", ui_currentClass, MAX_STRING_CHARS);
- j++;
+ sscanf(ui_currentClass, "%d %d", &class, &credits);
- uiInfo.tremHumanArmourySellCount++;
- }
- }
+ uiInfo.alienUpgradeCount = 0;
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- {
- if( upgrades & ( 1 << i ) )
+ for (i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++)
{
- uiInfo.tremHumanArmourySellList[ j ].text = String_Alloc( BG_FindHumanNameForUpgrade( i ) );
- uiInfo.tremHumanArmourySellList[ j ].cmd =
- String_Alloc( va( "cmd sell %s retrigger\n", BG_FindNameForUpgrade( i ) ) );
- uiInfo.tremHumanArmourySellList[ j ].infopane =
- UI_FindInfoPaneByName( va( "%sitem", BG_FindNameForUpgrade( i ) ) );
+ if (BG_ClassCanEvolveFromTo(class, i, credits, stage, 0) >= 0)
+ {
+ uiInfo.alienUpgradeList[j].text = BG_ClassConfig(i)->humanName;
+ uiInfo.alienUpgradeList[j].cmd = String_Alloc(va("cmd class %s\n", BG_Class(i)->name));
+ uiInfo.alienUpgradeList[j].type = INFOTYPE_CLASS;
+ uiInfo.alienUpgradeList[j].v.pclass = i;
- j++;
+ j++;
- uiInfo.tremHumanArmourySellCount++;
+ uiInfo.alienUpgradeCount++;
+ }
}
- }
}
/*
===============
-UI_LoadTremAlienUpgrades
+UI_LoadAlienBuilds
===============
*/
-static void UI_LoadTremAlienUpgrades( void )
+static void UI_LoadAlienBuilds(void)
{
- int i, j = 0;
- int class, credits;
- char ui_currentClass[ MAX_STRING_CHARS ];
- stage_t stage = UI_GetCurrentAlienStage( );
+ int i, j = 0;
+ stage_t stage;
- trap_Cvar_VariableStringBuffer( "ui_currentClass", ui_currentClass, MAX_STRING_CHARS );
- sscanf( ui_currentClass, "%d %d", &class, &credits );
+ UI_ParseCarriageList();
+ stage = UI_GetCurrentAlienStage();
- uiInfo.tremAlienUpgradeCount = 0;
+ uiInfo.alienBuildCount = 0;
- for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ )
- {
- if( BG_ClassCanEvolveFromTo( class, i, credits, 0 ) >= 0 &&
- BG_FindStagesForClass( i, stage ) &&
- BG_ClassIsAllowed( i ) )
+ for (i = BA_NONE + 1; i < BA_NUM_BUILDABLES; i++)
{
- uiInfo.tremAlienUpgradeList[ j ].text = String_Alloc( BG_FindHumanNameForClassNum( i ) );
- uiInfo.tremAlienUpgradeList[ j ].cmd =
- String_Alloc( va( "cmd class %s\n", BG_FindNameForClassNum( i ) ) );
- uiInfo.tremAlienUpgradeList[ j ].infopane =
- UI_FindInfoPaneByName( va( "%sclass", BG_FindNameForClassNum( i ) ) );
+ if (BG_Buildable(i)->team == TEAM_ALIENS && BG_Buildable(i)->buildWeapon & uiInfo.weapons &&
+ BG_BuildableAllowedInStage(i, stage) && BG_BuildableIsAllowed(i))
+ {
+ uiInfo.alienBuildList[j].text = BG_Buildable(i)->humanName;
+ uiInfo.alienBuildList[j].cmd = String_Alloc(va("cmd build %s\n", BG_Buildable(i)->name));
+ uiInfo.alienBuildList[j].type = INFOTYPE_BUILDABLE;
+ uiInfo.alienBuildList[j].v.buildable = i;
- j++;
+ j++;
- uiInfo.tremAlienUpgradeCount++;
+ uiInfo.alienBuildCount++;
+ }
}
- }
}
/*
===============
-UI_LoadTremAlienBuilds
+UI_LoadHumanBuilds
===============
*/
-static void UI_LoadTremAlienBuilds( void )
+static void UI_LoadHumanBuilds(void)
{
- int weapons;
- int i, j = 0;
- stage_t stage;
+ int i, j = 0;
+ stage_t stage;
- UI_ParseCarriageList( &weapons, NULL );
- stage = UI_GetCurrentAlienStage( );
+ UI_ParseCarriageList();
+ stage = UI_GetCurrentHumanStage();
- uiInfo.tremAlienBuildCount = 0;
+ uiInfo.humanBuildCount = 0;
- for( i = BA_NONE +1; i < BA_NUM_BUILDABLES; i++ )
- {
- if( BG_FindTeamForBuildable( i ) == BIT_ALIENS &&
- BG_FindBuildWeaponForBuildable( i ) & weapons &&
- BG_FindStagesForBuildable( i, stage ) &&
- BG_BuildableIsAllowed( i ) )
+ for (i = BA_NONE + 1; i < BA_NUM_BUILDABLES; i++)
{
- uiInfo.tremAlienBuildList[ j ].text =
- String_Alloc( BG_FindHumanNameForBuildable( i ) );
- uiInfo.tremAlienBuildList[ j ].cmd =
- String_Alloc( va( "cmd build %s\n", BG_FindNameForBuildable( i ) ) );
- uiInfo.tremAlienBuildList[ j ].infopane =
- UI_FindInfoPaneByName( va( "%sbuild", BG_FindNameForBuildable( i ) ) );
+ if (BG_Buildable(i)->team == TEAM_HUMANS && BG_Buildable(i)->buildWeapon & uiInfo.weapons &&
+ BG_BuildableAllowedInStage(i, stage) && BG_BuildableIsAllowed(i))
+ {
+ uiInfo.humanBuildList[j].text = BG_Buildable(i)->humanName;
+ uiInfo.humanBuildList[j].cmd = String_Alloc(va("cmd build %s\n", BG_Buildable(i)->name));
+ uiInfo.humanBuildList[j].type = INFOTYPE_BUILDABLE;
+ uiInfo.humanBuildList[j].v.buildable = i;
- j++;
+ j++;
- uiInfo.tremAlienBuildCount++;
+ uiInfo.humanBuildCount++;
+ }
}
- }
}
/*
===============
-UI_LoadTremHumanBuilds
+UI_LoadVoiceCmds
===============
*/
-static void UI_LoadTremHumanBuilds( void )
+static void UI_LoadVoiceCmds(void)
{
- int weapons;
- int i, j = 0;
- stage_t stage;
+ voice_t *v;
+ voiceCmd_t *c;
+
+ const char *cmd;
+ char mode[2];
+ char ui_voice[MAX_VOICE_CMD_LEN];
- UI_ParseCarriageList( &weapons, NULL );
- stage = UI_GetCurrentHumanStage( );
+ trap_Cvar_VariableStringBuffer("ui_voicemenu", mode, sizeof(mode));
+ trap_Cvar_VariableStringBuffer("voice", ui_voice, sizeof(ui_voice));
- uiInfo.tremHumanBuildCount = 0;
+ uiInfo.voiceCmdCount = 0;
- for( i = BA_NONE +1; i < BA_NUM_BUILDABLES; i++ )
- {
- if( BG_FindTeamForBuildable( i ) == BIT_HUMANS &&
- BG_FindBuildWeaponForBuildable( i ) & weapons &&
- BG_FindStagesForBuildable( i, stage ) &&
- BG_BuildableIsAllowed( i ) )
+ switch (mode[0])
{
- uiInfo.tremHumanBuildList[ j ].text =
- String_Alloc( BG_FindHumanNameForBuildable( i ) );
- uiInfo.tremHumanBuildList[ j ].cmd =
- String_Alloc( va( "cmd build %s\n", BG_FindNameForBuildable( i ) ) );
- uiInfo.tremHumanBuildList[ j ].infopane =
- UI_FindInfoPaneByName( va( "%sbuild", BG_FindNameForBuildable( i ) ) );
+ default:
+ case '1':
+ cmd = "vsay";
+ break;
+ case '2':
+ cmd = "vsay_team";
+ break;
+ case '3':
+ cmd = "vsay_local";
+ break;
+ };
+
+ v = BG_VoiceByName(uiInfo.voices, ui_voice);
+ if (!v)
+ return;
- j++;
+ for (c = v->cmds; c; c = c->next)
+ {
+ uiInfo.voiceCmdList[uiInfo.voiceCmdCount].text = c->cmd;
+ uiInfo.voiceCmdList[uiInfo.voiceCmdCount].cmd = String_Alloc(va("cmd %s %s\n", cmd, c->cmd));
+ uiInfo.voiceCmdList[uiInfo.voiceCmdCount].type = INFOTYPE_VOICECMD;
+ uiInfo.voiceCmdList[uiInfo.voiceCmdCount].v.text = c->tracks[0].text;
- uiInfo.tremHumanBuildCount++;
+ uiInfo.voiceCmdCount++;
}
- }
}
/*
@@ -3555,2156 +2784,1545 @@ static void UI_LoadTremHumanBuilds( void )
UI_LoadMods
===============
*/
-static void UI_LoadMods( void ) {
- int numdirs;
- char dirlist[2048];
- char *dirptr;
- char *descptr;
- int i;
- int dirlen;
-
- uiInfo.modCount = 0;
- numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
- dirptr = dirlist;
- for( i = 0; i < numdirs; i++ ) {
- dirlen = strlen( dirptr ) + 1;
- descptr = dirptr + dirlen;
- uiInfo.modList[uiInfo.modCount].modName = String_Alloc(dirptr);
- uiInfo.modList[uiInfo.modCount].modDescr = String_Alloc(descptr);
- dirptr += dirlen + strlen(descptr) + 1;
- uiInfo.modCount++;
- if (uiInfo.modCount >= MAX_MODS) {
- break;
- }
- }
+static void UI_LoadMods(void)
+{
+ int numdirs;
+ char dirlist[2048];
+ char *dirptr;
+ char *descptr;
+ int i;
+ int dirlen;
-}
+ uiInfo.modCount = 0;
+ numdirs = trap_FS_GetFileList("$modlist", "", dirlist, sizeof(dirlist));
+ dirptr = dirlist;
+
+ for (i = 0; i < numdirs; i++)
+ {
+ dirlen = strlen(dirptr) + 1;
+ uiInfo.modList[uiInfo.modCount].modName = String_Alloc(dirptr);
+ dirptr += dirlen;
+ uiInfo.modCount++;
+ if (uiInfo.modCount >= MAX_MODS)
+ break;
+ }
+}
/*
===============
UI_LoadMovies
===============
*/
-static void UI_LoadMovies( void ) {
- char movielist[4096];
- char *moviename;
- int i, len;
-
- uiInfo.movieCount = trap_FS_GetFileList( "video", "roq", movielist, 4096 );
-
- if (uiInfo.movieCount) {
- if (uiInfo.movieCount > MAX_MOVIES) {
- uiInfo.movieCount = MAX_MOVIES;
- }
- moviename = movielist;
- for ( i = 0; i < uiInfo.movieCount; i++ ) {
- len = strlen( moviename );
- if (!Q_stricmp(moviename + len - 4,".roq")) {
- moviename[len-4] = '\0';
- }
- Q_strupr(moviename);
- uiInfo.movieList[i] = String_Alloc(moviename);
- moviename += len + 1;
- }
- }
+static void UI_LoadMovies(void)
+{
+ char movielist[4096];
+ char *moviename;
+ int i, len;
-}
+ uiInfo.movieCount = trap_FS_GetFileList("video", "roq", movielist, 4096);
+
+ if (uiInfo.movieCount)
+ {
+ if (uiInfo.movieCount > MAX_MOVIES)
+ uiInfo.movieCount = MAX_MOVIES;
+
+ moviename = movielist;
+
+ for (i = 0; i < uiInfo.movieCount; i++)
+ {
+ len = strlen(moviename);
+ if (!Q_stricmp(moviename + len - 4, ".roq"))
+ moviename[len - 4] = '\0';
+ Q_strupr(moviename);
+ uiInfo.movieList[i] = String_Alloc(moviename);
+ moviename += len + 1;
+ }
+ }
+}
/*
===============
UI_LoadDemos
===============
*/
-static void UI_LoadDemos( void ) {
- char demolist[4096];
- char demoExt[32];
- char *demoname;
- int i, len;
+static void UI_LoadDemos(void)
+{
+ char demolist[4096];
+ char demoExt[32];
+ char *demoname;
+ int i = 0;
+ int len, protocol;
- Com_sprintf(demoExt, sizeof(demoExt), "dm_%d", (int)trap_Cvar_VariableValue("protocol"));
+ uiInfo.demoCount = 0;
- uiInfo.demoCount = trap_FS_GetFileList( "demos", demoExt, demolist, 4096 );
+ for(protocol = 0; protocol < 3; protocol++) {
+ Com_sprintf(
+ demoExt, sizeof(demoExt), "%s%d", DEMOEXT,
+ protocol == 2 ? 69 : protocol == 1 ? 70 : 71);
- Com_sprintf(demoExt, sizeof(demoExt), ".dm_%d", (int)trap_Cvar_VariableValue("protocol"));
+ uiInfo.demoCount += trap_FS_GetFileList("demos", demoExt, demolist, 4096);
- if (uiInfo.demoCount) {
- if (uiInfo.demoCount > MAX_DEMOS) {
- uiInfo.demoCount = MAX_DEMOS;
- }
- demoname = demolist;
- for ( i = 0; i < uiInfo.demoCount; i++ ) {
- len = strlen( demoname );
- if (!Q_stricmp(demoname + len - strlen(demoExt), demoExt)) {
- demoname[len-strlen(demoExt)] = '\0';
- }
- Q_strupr(demoname);
- uiInfo.demoList[i] = String_Alloc(demoname);
- demoname += len + 1;
- }
- }
+ Com_sprintf(
+ demoExt, sizeof(demoExt), ".%s%d", DEMOEXT,
+ protocol == 2 ? 69 : protocol == 1 ? 70 : 71);
-}
+ if (uiInfo.demoCount)
+ {
+ if (uiInfo.demoCount > MAX_DEMOS)
+ uiInfo.demoCount = MAX_DEMOS;
+ demoname = demolist;
-static qboolean UI_SetNextMap(int actual, int index) {
- int i;
- for (i = actual + 1; i < uiInfo.mapCount; i++) {
- if (uiInfo.mapList[i].active) {
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, index + 1, "skirmish");
- return qtrue;
- }
- }
- return qfalse;
-}
-
+ for (; i < uiInfo.demoCount; i++)
+ {
+ len = strlen(demoname);
-static void UI_StartSkirmish(qboolean next) {
- int i, k, g, delay, temp;
- float skill;
- char buff[MAX_STRING_CHARS];
+ if (!Q_stricmp(demoname + len - strlen(demoExt), demoExt))
+ demoname[len - strlen(demoExt)] = '\0';
- if (next) {
- int actual;
- int index = trap_Cvar_VariableValue("ui_mapIndex");
- UI_MapCountByGameType(qtrue);
- UI_SelectedMap(index, &actual);
- if (UI_SetNextMap(actual, index)) {
- } else {
- UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
- UI_MapCountByGameType(qtrue);
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, "skirmish");
- }
- }
-
- g = uiInfo.gameTypes[ui_gameType.integer].gtEnum;
- trap_Cvar_SetValue( "g_gametype", g );
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName) );
- skill = trap_Cvar_VariableValue( "g_spSkill" );
- trap_Cvar_Set("ui_scoreMap", uiInfo.mapList[ui_currentMap.integer].mapName);
-
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
-
- trap_Cvar_Set("ui_singlePlayerActive", "1");
-
- // set up sp overrides, will be replaced on postgame
- temp = trap_Cvar_VariableValue( "capturelimit" );
- trap_Cvar_Set("ui_saveCaptureLimit", va("%i", temp));
- temp = trap_Cvar_VariableValue( "fraglimit" );
- trap_Cvar_Set("ui_saveFragLimit", va("%i", temp));
-
- UI_SetCapFragLimits(qfalse);
-
- temp = trap_Cvar_VariableValue( "cg_drawTimer" );
- trap_Cvar_Set("ui_drawTimer", va("%i", temp));
- temp = trap_Cvar_VariableValue( "g_doWarmup" );
- trap_Cvar_Set("ui_doWarmup", va("%i", temp));
- temp = trap_Cvar_VariableValue( "g_friendlyFire" );
- trap_Cvar_Set("ui_friendlyFire", va("%i", temp));
- temp = trap_Cvar_VariableValue( "sv_maxClients" );
- trap_Cvar_Set("ui_maxClients", va("%i", temp));
- temp = trap_Cvar_VariableValue( "g_warmup" );
- trap_Cvar_Set("ui_Warmup", va("%i", temp));
- temp = trap_Cvar_VariableValue( "sv_pure" );
- trap_Cvar_Set("ui_pure", va("%i", temp));
-
- trap_Cvar_Set("cg_cameraOrbit", "0");
- trap_Cvar_Set("cg_thirdPerson", "0");
- trap_Cvar_Set("cg_drawTimer", "1");
- trap_Cvar_Set("g_doWarmup", "1");
- trap_Cvar_Set("g_warmup", "15");
- trap_Cvar_Set("sv_pure", "0");
- trap_Cvar_Set("g_friendlyFire", "0");
- trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
- trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
-
- if (trap_Cvar_VariableValue("ui_recordSPDemo")) {
- Com_sprintf(buff, MAX_STRING_CHARS, "%s_%i", uiInfo.mapList[ui_currentMap.integer].mapLoadName, g);
- trap_Cvar_Set("ui_recordSPDemoName", buff);
- }
-
- delay = 500;
-
- {
- temp = uiInfo.mapList[ui_currentMap.integer].teamMembers * 2;
- trap_Cvar_Set("sv_maxClients", va("%d", temp));
- for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers; i++) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f %s %i %s\n", UI_AIFromName(uiInfo.teamList[k].teamMembers[i]), skill, "", delay, uiInfo.teamList[k].teamMembers[i]);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- delay += 500;
- }
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers-1; i++) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f %s %i %s\n", UI_AIFromName(uiInfo.teamList[k].teamMembers[i]), skill, "", delay, uiInfo.teamList[k].teamMembers[i]);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- delay += 500;
- }
- }
-}
-
-static void UI_Update(const char *name) {
- int val = trap_Cvar_VariableValue(name);
-
- if (Q_stricmp(name, "ui_SetName") == 0) {
- trap_Cvar_Set( "name", UI_Cvar_VariableString("ui_Name"));
- } else if (Q_stricmp(name, "ui_setRate") == 0) {
- float rate = trap_Cvar_VariableValue("rate");
- if (rate >= 5000) {
- trap_Cvar_Set("cl_maxpackets", "30");
- trap_Cvar_Set("cl_packetdup", "1");
- } else if (rate >= 4000) {
- trap_Cvar_Set("cl_maxpackets", "15");
- trap_Cvar_Set("cl_packetdup", "2"); // favor less prediction errors when there's packet loss
- } else {
- trap_Cvar_Set("cl_maxpackets", "15");
- trap_Cvar_Set("cl_packetdup", "1"); // favor lower bandwidth
- }
- } else if (Q_stricmp(name, "ui_GetName") == 0) {
- trap_Cvar_Set( "ui_Name", UI_Cvar_VariableString("name"));
- } else if (Q_stricmp(name, "r_colorbits") == 0) {
- switch (val) {
- case 0:
- trap_Cvar_SetValue( "r_depthbits", 0 );
- trap_Cvar_SetValue( "r_stencilbits", 0 );
- break;
- case 16:
- trap_Cvar_SetValue( "r_depthbits", 16 );
- trap_Cvar_SetValue( "r_stencilbits", 0 );
- break;
- case 32:
- trap_Cvar_SetValue( "r_depthbits", 24 );
- break;
- }
- } else if (Q_stricmp(name, "r_lodbias") == 0) {
- switch (val) {
- case 0:
- trap_Cvar_SetValue( "r_subdivisions", 4 );
- break;
- case 1:
- trap_Cvar_SetValue( "r_subdivisions", 12 );
- break;
- case 2:
- trap_Cvar_SetValue( "r_subdivisions", 20 );
- break;
- }
- } else if (Q_stricmp(name, "ui_glCustom") == 0) {
- switch (val) {
- case 0: // high quality
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 4 );
- trap_Cvar_SetValue( "r_vertexlight", 0 );
- trap_Cvar_SetValue( "r_lodbias", 0 );
- trap_Cvar_SetValue( "r_colorbits", 32 );
- trap_Cvar_SetValue( "r_depthbits", 24 );
- trap_Cvar_SetValue( "r_picmip", 0 );
- trap_Cvar_SetValue( "r_mode", 4 );
- trap_Cvar_SetValue( "r_texturebits", 32 );
- trap_Cvar_SetValue( "r_fastSky", 0 );
- trap_Cvar_SetValue( "r_inGameVideo", 1 );
- trap_Cvar_SetValue( "cg_shadows", 1 );
- trap_Cvar_SetValue( "cg_brassTime", 2500 );
- trap_Cvar_SetValue( "cg_bounceParticles", 1 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
- break;
- case 1: // normal
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 12 );
- trap_Cvar_SetValue( "r_vertexlight", 0 );
- trap_Cvar_SetValue( "r_lodbias", 0 );
- trap_Cvar_SetValue( "r_colorbits", 0 );
- trap_Cvar_SetValue( "r_depthbits", 24 );
- trap_Cvar_SetValue( "r_picmip", 1 );
- trap_Cvar_SetValue( "r_mode", 3 );
- trap_Cvar_SetValue( "r_texturebits", 0 );
- trap_Cvar_SetValue( "r_fastSky", 0 );
- trap_Cvar_SetValue( "r_inGameVideo", 1 );
- trap_Cvar_SetValue( "cg_brassTime", 2500 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
- trap_Cvar_SetValue( "cg_shadows", 0 );
- trap_Cvar_SetValue( "cg_bounceParticles", 0 );
- break;
- case 2: // fast
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 8 );
- trap_Cvar_SetValue( "r_vertexlight", 0 );
- trap_Cvar_SetValue( "r_lodbias", 1 );
- trap_Cvar_SetValue( "r_colorbits", 0 );
- trap_Cvar_SetValue( "r_depthbits", 0 );
- trap_Cvar_SetValue( "r_picmip", 1 );
- trap_Cvar_SetValue( "r_mode", 3 );
- trap_Cvar_SetValue( "r_texturebits", 0 );
- trap_Cvar_SetValue( "cg_shadows", 0 );
- trap_Cvar_SetValue( "r_fastSky", 1 );
- trap_Cvar_SetValue( "r_inGameVideo", 0 );
- trap_Cvar_SetValue( "cg_brassTime", 0 );
- trap_Cvar_SetValue( "cg_bounceParticles", 0 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
- break;
- case 3: // fastest
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 20 );
- trap_Cvar_SetValue( "r_vertexlight", 1 );
- trap_Cvar_SetValue( "r_lodbias", 2 );
- trap_Cvar_SetValue( "r_colorbits", 16 );
- trap_Cvar_SetValue( "r_depthbits", 16 );
- trap_Cvar_SetValue( "r_mode", 3 );
- trap_Cvar_SetValue( "r_picmip", 2 );
- trap_Cvar_SetValue( "r_texturebits", 16 );
- trap_Cvar_SetValue( "cg_shadows", 0 );
- trap_Cvar_SetValue( "cg_brassTime", 0 );
- trap_Cvar_SetValue( "r_fastSky", 1 );
- trap_Cvar_SetValue( "r_inGameVideo", 0 );
- trap_Cvar_SetValue( "cg_bounceParticles", 0 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
- break;
- }
- } else if (Q_stricmp(name, "ui_mousePitch") == 0) {
- if (val == 0) {
- trap_Cvar_SetValue( "m_pitch", 0.022f );
- } else {
- trap_Cvar_SetValue( "m_pitch", -0.022f );
+ uiInfo.demoList[i] = String_Alloc(demoname);
+ demoname += len + 1;
+ }
+ }
}
- }
}
-static void UI_RunMenuScript(char **args) {
- const char *name, *name2;
- char buff[1024];
- const char *cmd;
-
- if (String_Parse(args, &name)) {
- if (Q_stricmp(name, "StartServer") == 0) {
- int i, clients, oldclients;
- float skill;
- trap_Cvar_Set("cg_thirdPerson", "0");
- trap_Cvar_Set("cg_cameraOrbit", "0");
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, ui_dedicated.integer ) );
- trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 8, uiInfo.gameTypes[ui_netGameType.integer].gtEnum ) );
- trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
- trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ) );
- skill = trap_Cvar_VariableValue( "g_spSkill" );
- // set max clients based on spots
- oldclients = trap_Cvar_VariableValue( "sv_maxClients" );
- clients = 0;
- for (i = 0; i < PLAYERS_PER_TEAM; i++) {
- int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
- if (bot >= 0) {
- clients++;
- }
- bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
- if (bot >= 0) {
- clients++;
- }
- }
- if (clients == 0) {
- clients = 8;
- }
-
- if (oldclients > clients) {
- clients = oldclients;
- }
+static void UI_Update(const char *name)
+{
+ int val = trap_Cvar_VariableValue(name);
- trap_Cvar_Set("sv_maxClients", va("%d",clients));
+ if (Q_stricmp(name, "ui_SetName") == 0)
+ trap_Cvar_Set("name", UI_Cvar_VariableString("ui_Name"));
+ else if (Q_stricmp(name, "ui_setRate") == 0)
+ {
+ float rate = trap_Cvar_VariableValue("rate");
- for (i = 0; i < PLAYERS_PER_TEAM; i++) {
- int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
- if (bot > 1) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
+ if (rate >= 5000)
+ {
+ trap_Cvar_Set("cl_maxpackets", "30");
+ trap_Cvar_Set("cl_packetdup", "1");
}
- bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
- if (bot > 1) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
+ else if (rate >= 4000)
+ {
+ trap_Cvar_Set("cl_maxpackets", "15");
+ trap_Cvar_Set("cl_packetdup", "2"); // favor less prediction errors when there's packet loss
+ }
+ else
+ {
+ trap_Cvar_Set("cl_maxpackets", "15");
+ trap_Cvar_Set("cl_packetdup", "1"); // favor lower bandwidth
}
- }
- } else if (Q_stricmp(name, "updateSPMenu") == 0) {
- UI_SetCapFragLimits(qtrue);
- UI_MapCountByGameType(qtrue);
- ui_mapIndex.integer = UI_GetIndexFromSelection(ui_currentMap.integer);
- trap_Cvar_Set("ui_mapIndex", va("%d", ui_mapIndex.integer));
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, ui_mapIndex.integer, "skirmish");
- UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
- UI_GameType_HandleKey(0, NULL, K_MOUSE2, qfalse);
- } else if (Q_stricmp(name, "resetDefaults") == 0) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n");
- trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n");
- Controls_SetDefaults();
- trap_Cvar_Set("com_introPlayed", "1" );
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
- } else if (Q_stricmp(name, "loadArenas") == 0) {
- UI_LoadArenas();
- UI_MapCountByGameType(qfalse);
- Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, "createserver");
- } else if (Q_stricmp(name, "loadServerInfo") == 0) {
- UI_ServerInfo();
- } else if (Q_stricmp(name, "saveControls") == 0) {
- Controls_SetConfig(qtrue);
- } else if (Q_stricmp(name, "loadControls") == 0) {
- Controls_GetConfig();
- } else if (Q_stricmp(name, "clearError") == 0) {
- trap_Cvar_Set("com_errorMessage", "");
- } else if (Q_stricmp(name, "loadGameInfo") == 0) {
-/* UI_ParseGameInfo("gameinfo.txt");
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);*/
- } else if (Q_stricmp(name, "resetScores") == 0) {
- UI_ClearScores();
- } else if (Q_stricmp(name, "RefreshServers") == 0) {
- UI_StartServerRefresh(qtrue);
- UI_BuildServerDisplayList(qtrue);
- } else if (Q_stricmp(name, "InitServerList") == 0) {
- int time = trap_RealTime( NULL );
- int last;
- int sortColumn;
-
- // set up default sorting
- if(!uiInfo.serverStatus.sorted && Int_Parse(args, &sortColumn))
- {
- uiInfo.serverStatus.sortKey = sortColumn;
- uiInfo.serverStatus.sortDir = 0;
- }
-
- // refresh if older than 3 days or if list is empty
- last = atoi( UI_Cvar_VariableString( va( "ui_lastServerRefresh_%i_time",
- ui_netSource.integer ) ) );
- if( trap_LAN_GetServerCount( ui_netSource.integer ) < 1 ||
- ( time - last ) > 3600 )
- {
- UI_StartServerRefresh(qtrue);
- UI_BuildServerDisplayList(qtrue);
- }
- } else if (Q_stricmp(name, "RefreshFilter") == 0) {
- UI_StartServerRefresh(qfalse);
- UI_BuildServerDisplayList(qtrue);
- } else if (Q_stricmp(name, "RunSPDemo") == 0) {
- if (uiInfo.demoAvailable) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s_%i\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum));
- }
- } else if (Q_stricmp(name, "LoadDemos") == 0) {
- UI_LoadDemos();
- } else if (Q_stricmp(name, "LoadMovies") == 0) {
- UI_LoadMovies();
- } else if (Q_stricmp(name, "LoadMods") == 0) {
- UI_LoadMods();
- }
-
-//TA: tremulous menus
- else if( Q_stricmp( name, "LoadTeams" ) == 0 )
- UI_LoadTremTeams( );
- else if( Q_stricmp( name, "JoinTeam" ) == 0 )
- {
- if( ( cmd = uiInfo.tremTeamList[ uiInfo.tremTeamIndex ].cmd ) )
- trap_Cmd_ExecuteText( EXEC_APPEND, cmd );
- }
- else if( Q_stricmp( name, "LoadHumanItems" ) == 0 )
- UI_LoadTremHumanItems( );
- else if( Q_stricmp( name, "SpawnWithHumanItem" ) == 0 )
- {
- if( ( cmd = uiInfo.tremHumanItemList[ uiInfo.tremHumanItemIndex ].cmd ) )
- trap_Cmd_ExecuteText( EXEC_APPEND, cmd );
- }
- else if( Q_stricmp( name, "LoadAlienClasses" ) == 0 )
- UI_LoadTremAlienClasses( );
- else if( Q_stricmp( name, "SpawnAsAlienClass" ) == 0 )
- {
- if( ( cmd = uiInfo.tremAlienClassList[ uiInfo.tremAlienClassIndex ].cmd ) )
- trap_Cmd_ExecuteText( EXEC_APPEND, cmd );
- }
- else if( Q_stricmp( name, "LoadHumanArmouryBuys" ) == 0 )
- UI_LoadTremHumanArmouryBuys( );
- else if( Q_stricmp( name, "BuyFromArmoury" ) == 0 )
- {
- if( ( cmd = uiInfo.tremHumanArmouryBuyList[ uiInfo.tremHumanArmouryBuyIndex ].cmd ) )
- trap_Cmd_ExecuteText( EXEC_APPEND, cmd );
}
- else if( Q_stricmp( name, "LoadHumanArmourySells" ) == 0 )
- UI_LoadTremHumanArmourySells( );
- else if( Q_stricmp( name, "SellToArmoury" ) == 0 )
+ else if (Q_stricmp(name, "ui_GetName") == 0)
+ trap_Cvar_Set("ui_Name", UI_Cvar_VariableString("name"));
+ else if (Q_stricmp(name, "r_colorbits") == 0)
{
- if( ( cmd = uiInfo.tremHumanArmourySellList[ uiInfo.tremHumanArmourySellIndex ].cmd ) )
- trap_Cmd_ExecuteText( EXEC_APPEND, cmd );
+ switch (val)
+ {
+ case 0:
+ trap_Cvar_SetValue("r_depthbits", 0);
+ trap_Cvar_SetValue("r_stencilbits", 0);
+ break;
+
+ case 16:
+ trap_Cvar_SetValue("r_depthbits", 16);
+ trap_Cvar_SetValue("r_stencilbits", 0);
+ break;
+
+ case 32:
+ trap_Cvar_SetValue("r_depthbits", 24);
+ break;
+ }
}
- else if( Q_stricmp( name, "LoadAlienUpgrades" ) == 0 )
+ else if (Q_stricmp(name, "r_lodbias") == 0)
{
- UI_LoadTremAlienUpgrades( );
+ switch (val)
+ {
+ case 0:
+ trap_Cvar_SetValue("r_subdivisions", 4);
+ break;
- //disallow the menu if it would be empty
- if( uiInfo.tremAlienUpgradeCount <= 0 )
- Menus_CloseAll( );
- }
- else if( Q_stricmp( name, "UpgradeToNewClass" ) == 0 )
- {
- if( ( cmd = uiInfo.tremAlienUpgradeList[ uiInfo.tremAlienUpgradeIndex ].cmd ) )
- trap_Cmd_ExecuteText( EXEC_APPEND, cmd );
+ case 1:
+ trap_Cvar_SetValue("r_subdivisions", 12);
+ break;
+
+ case 2:
+ trap_Cvar_SetValue("r_subdivisions", 20);
+ break;
+ }
}
- else if( Q_stricmp( name, "LoadAlienBuilds" ) == 0 )
- UI_LoadTremAlienBuilds( );
- else if( Q_stricmp( name, "BuildAlienBuildable" ) == 0 )
+ else if (Q_stricmp(name, "ui_glCustom") == 0)
{
- if( ( cmd = uiInfo.tremAlienBuildList[ uiInfo.tremAlienBuildIndex ].cmd ) )
- trap_Cmd_ExecuteText( EXEC_APPEND, cmd );
+ switch (val)
+ {
+ case 0: // high quality
+ trap_Cvar_SetValue("r_subdivisions", 4);
+ trap_Cvar_SetValue("r_vertexlight", 0);
+ trap_Cvar_SetValue("r_lodbias", 0);
+ trap_Cvar_SetValue("r_colorbits", 32);
+ trap_Cvar_SetValue("r_depthbits", 24);
+ trap_Cvar_SetValue("r_picmip", 0);
+ trap_Cvar_SetValue("r_texturebits", 32);
+ trap_Cvar_SetValue("r_fastSky", 0);
+ trap_Cvar_SetValue("r_inGameVideo", 1);
+ trap_Cvar_SetValue("cg_shadows", 1);
+ trap_Cvar_SetValue("cg_bounceParticles", 1);
+ trap_Cvar_Set("r_texturemode", "GL_LINEAR_MIPMAP_LINEAR");
+ break;
+
+ case 1: // normal
+ trap_Cvar_SetValue("r_subdivisions", 12);
+ trap_Cvar_SetValue("r_vertexlight", 0);
+ trap_Cvar_SetValue("r_lodbias", 0);
+ trap_Cvar_SetValue("r_colorbits", 0);
+ trap_Cvar_SetValue("r_depthbits", 24);
+ trap_Cvar_SetValue("r_picmip", 1);
+ trap_Cvar_SetValue("r_texturebits", 0);
+ trap_Cvar_SetValue("r_fastSky", 0);
+ trap_Cvar_SetValue("r_inGameVideo", 1);
+ trap_Cvar_Set("r_texturemode", "GL_LINEAR_MIPMAP_LINEAR");
+ trap_Cvar_SetValue("cg_shadows", 0);
+ trap_Cvar_SetValue("cg_bounceParticles", 0);
+ break;
+
+ case 2: // fast
+ trap_Cvar_SetValue("r_subdivisions", 8);
+ trap_Cvar_SetValue("r_vertexlight", 0);
+ trap_Cvar_SetValue("r_lodbias", 1);
+ trap_Cvar_SetValue("r_colorbits", 0);
+ trap_Cvar_SetValue("r_depthbits", 0);
+ trap_Cvar_SetValue("r_picmip", 1);
+ trap_Cvar_SetValue("r_texturebits", 0);
+ trap_Cvar_SetValue("cg_shadows", 0);
+ trap_Cvar_SetValue("r_fastSky", 1);
+ trap_Cvar_SetValue("r_inGameVideo", 0);
+ trap_Cvar_SetValue("cg_bounceParticles", 0);
+ trap_Cvar_Set("r_texturemode", "GL_LINEAR_MIPMAP_NEAREST");
+ break;
+
+ case 3: // fastest
+ trap_Cvar_SetValue("r_subdivisions", 20);
+ trap_Cvar_SetValue("r_vertexlight", 1);
+ trap_Cvar_SetValue("r_lodbias", 2);
+ trap_Cvar_SetValue("r_colorbits", 16);
+ trap_Cvar_SetValue("r_depthbits", 16);
+ trap_Cvar_SetValue("r_picmip", 2);
+ trap_Cvar_SetValue("r_texturebits", 16);
+ trap_Cvar_SetValue("cg_shadows", 0);
+ trap_Cvar_SetValue("r_fastSky", 1);
+ trap_Cvar_SetValue("r_inGameVideo", 0);
+ trap_Cvar_SetValue("cg_bounceParticles", 0);
+ trap_Cvar_Set("r_texturemode", "GL_LINEAR_MIPMAP_NEAREST");
+ break;
+ }
}
- else if( Q_stricmp( name, "LoadHumanBuilds" ) == 0 )
- UI_LoadTremHumanBuilds( );
- else if( Q_stricmp( name, "BuildHumanBuildable" ) == 0 )
+ else if (Q_stricmp(name, "ui_mousePitch") == 0)
{
- if( ( cmd = uiInfo.tremHumanBuildList[ uiInfo.tremHumanBuildIndex ].cmd ) )
- trap_Cmd_ExecuteText( EXEC_APPEND, cmd );
+ if (val == 0)
+ trap_Cvar_SetValue("m_pitch", 0.022f);
+ else
+ trap_Cvar_SetValue("m_pitch", -0.022f);
}
- else if( Q_stricmp( name, "Say" ) == 0 )
- {
- char buffer[ MAX_CVAR_VALUE_STRING ];
- trap_Cvar_VariableStringBuffer( "ui_sayBuffer", buffer, sizeof( buffer ) );
+}
- if( !buffer[ 0 ] )
- ;
- else if( ui_chatCommands.integer && ( buffer[ 0 ] == '/' ||
- buffer[ 0 ] == '\\' ) )
- {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "%s\n", buffer + 1 ) );
- }
- else if( uiInfo.chatTeam )
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "say_team \"%s\"\n", buffer ) );
- else
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "say \"%s\"\n", buffer ) );
- }
- else if( Q_stricmp( name, "PTRCRestore" ) == 0 )
+// FIXME: lookup table
+static void UI_RunMenuScript(char **args)
+{
+ const char *name, *name2;
+ char buff[1024];
+ const char *cmd;
+
+ if (String_Parse(args, &name))
{
- int len;
- char text[ 16 ];
- fileHandle_t f;
- char command[ 32 ];
+ if (Q_stricmp(name, "StartServer") == 0)
+ {
+ trap_Cvar_SetValue("dedicated", Com_Clamp(0, 2, ui_dedicated.integer));
+ trap_Cmd_ExecuteText(
+ EXEC_APPEND, va("wait ; wait ; map \"%s\"\n", uiInfo.mapList[ui_selectedMap.integer].mapLoadName));
+ }
+ else if (Q_stricmp(name, "resetDefaults") == 0)
+ {
+ trap_Cmd_ExecuteText(EXEC_APPEND, "exec default.cfg\n");
+ trap_Cmd_ExecuteText(EXEC_APPEND, "cvar_restart\n");
+ Controls_SetDefaults();
+ trap_Cvar_Set("com_introPlayed", "1");
+ trap_Cmd_ExecuteText(EXEC_APPEND, "vid_restart\n");
+ }
+ else if (Q_stricmp(name, "loadArenas") == 0)
+ {
+ UI_LoadArenas();
+ Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, "createserver");
+ }
+ else if (Q_stricmp(name, "loadServerInfo") == 0)
+ UI_ServerInfo();
+ else if (Q_stricmp(name, "getNews") == 0)
+ UI_UpdateNews(qtrue);
+ else if (Q_stricmp(name, "checkForUpdate") == 0)
+ UI_UpdateGithubRelease();
+ else if (Q_stricmp(name, "downloadUpdate") == 0)
+ trap_Cmd_ExecuteText(EXEC_APPEND, "downloadUpdate");
+ else if (Q_stricmp(name, "installUpdate") == 0)
+ trap_Cmd_ExecuteText(EXEC_APPEND, "installUpdate");
+ else if (Q_stricmp(name, "saveControls") == 0)
+ Controls_SetConfig(qtrue);
+ else if (Q_stricmp(name, "loadControls") == 0)
+ Controls_GetConfig();
+ else if (Q_stricmp(name, "clearError") == 0)
+ {
+ trap_Cvar_Set("com_errorMessage", "");
+ }
+ else if (Q_stricmp(name, "clearDemoError") == 0)
+ {
+ trap_Cvar_Set("com_demoErrorMessage", "");
+ }
+ else if (Q_stricmp(name, "downloadIgnore") == 0)
+ {
+ trap_Cvar_Set("com_downloadPrompt", va("%d", DLP_IGNORE));
+ }
+ else if (Q_stricmp(name, "downloadCURL") == 0)
+ {
+ trap_Cvar_Set("com_downloadPrompt", va("%d", DLP_CURL));
+ }
+ else if (Q_stricmp(name, "downloadUDP") == 0)
+ {
+ trap_Cvar_Set("com_downloadPrompt", va("%d", DLP_UDP));
+ }
+ else if (Q_stricmp(name, "RefreshServers") == 0)
+ {
+ UI_StartServerRefresh(qtrue);
+ UI_BuildServerDisplayList(qtrue);
+ }
+ else if (Q_stricmp(name, "InitServerList") == 0)
+ {
+ int time = trap_RealTime(NULL);
+ int last;
+ int sortColumn;
- // load the file
- len = trap_FS_FOpenFile( "ptrc.cfg", &f, FS_READ );
+ // set up default sorting
- if( len > 0 && ( len < sizeof( text ) - 1 ) )
- {
- trap_FS_Read( text, len, f );
- text[ len ] = 0;
- trap_FS_FCloseFile( f );
+ if (!uiInfo.serverStatus.sorted && Int_Parse(args, &sortColumn))
+ {
+ uiInfo.serverStatus.sortKey = sortColumn;
+ uiInfo.serverStatus.sortDir = 0;
+ }
- Com_sprintf( command, 32, "ptrcrestore %s", text );
+ // refresh if older than 3 days or if list is empty
+ last = atoi(UI_Cvar_VariableString(va("ui_lastServerRefresh_%i_time", ui_netSource.integer)));
- trap_Cmd_ExecuteText( EXEC_APPEND, command );
- }
- }
-//TA: tremulous menus
+ if (trap_LAN_GetServerCount(ui_netSource.integer) < 1 || (time - last) > 3600)
+ {
+ UI_StartServerRefresh(qtrue);
+ UI_BuildServerDisplayList(qtrue);
+ }
+ }
+ else if (Q_stricmp(name, "RefreshFilter") == 0)
+ {
+ UI_StartServerRefresh(qfalse);
+ UI_BuildServerDisplayList(qtrue);
+ }
+ else if (Q_stricmp(name, "LoadDemos") == 0)
+ UI_LoadDemos();
+ else if (Q_stricmp(name, "LoadMovies") == 0)
+ UI_LoadMovies();
+ else if (Q_stricmp(name, "LoadMods") == 0)
+ UI_LoadMods();
+ else if (Q_stricmp(name, "LoadTeams") == 0)
+ UI_LoadTeams();
+ else if (Q_stricmp(name, "JoinTeam") == 0)
+ {
+ if ((cmd = uiInfo.teamList[uiInfo.teamIndex].cmd))
+ trap_Cmd_ExecuteText(EXEC_APPEND, cmd);
+ }
+ else if (Q_stricmp(name, "LoadHumanItems") == 0)
+ UI_LoadHumanItems();
+ else if (Q_stricmp(name, "SpawnWithHumanItem") == 0)
+ {
+ if ((cmd = uiInfo.humanItemList[uiInfo.humanItemIndex].cmd))
+ trap_Cmd_ExecuteText(EXEC_APPEND, cmd);
+ }
+ else if (Q_stricmp(name, "LoadAlienClasses") == 0)
+ UI_LoadAlienClasses();
+ else if (Q_stricmp(name, "SpawnAsAlienClass") == 0)
+ {
+ if ((cmd = uiInfo.alienClassList[uiInfo.alienClassIndex].cmd))
+ trap_Cmd_ExecuteText(EXEC_APPEND, cmd);
+ }
+ else if (Q_stricmp(name, "LoadHumanArmouryBuys") == 0)
+ UI_LoadHumanArmouryBuys();
+ else if (Q_stricmp(name, "BuyFromArmoury") == 0)
+ {
+ if ((cmd = uiInfo.humanArmouryBuyList[uiInfo.humanArmouryBuyIndex].cmd))
+ trap_Cmd_ExecuteText(EXEC_APPEND, cmd);
- else if (Q_stricmp(name, "playMovie") == 0) {
- if (uiInfo.previewMovie >= 0) {
- trap_CIN_StopCinematic(uiInfo.previewMovie);
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, va("cinematic %s.roq 2\n", uiInfo.movieList[uiInfo.movieIndex]));
- } else if (Q_stricmp(name, "RunMod") == 0) {
- trap_Cvar_Set( "fs_game", uiInfo.modList[uiInfo.modIndex].modName);
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
- } else if (Q_stricmp(name, "RunDemo") == 0) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s\n", uiInfo.demoList[uiInfo.demoIndex]));
- } else if (Q_stricmp(name, "Tremulous") == 0) {
- trap_Cvar_Set( "fs_game", "");
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
- } else if (Q_stricmp(name, "closeJoin") == 0) {
- if (uiInfo.serverStatus.refreshActive) {
- UI_StopServerRefresh();
- uiInfo.serverStatus.nextDisplayRefresh = 0;
- uiInfo.nextServerStatusRefresh = 0;
- uiInfo.nextFindPlayerRefresh = 0;
- UI_BuildServerDisplayList(qtrue);
- } else {
- Menus_CloseByName("joinserver");
- Menus_OpenByName("main");
- }
- } else if (Q_stricmp(name, "StopRefresh") == 0) {
- UI_StopServerRefresh();
- uiInfo.serverStatus.nextDisplayRefresh = 0;
- uiInfo.nextServerStatusRefresh = 0;
- uiInfo.nextFindPlayerRefresh = 0;
- } else if (Q_stricmp(name, "UpdateFilter") == 0) {
- if (ui_netSource.integer == AS_LOCAL) {
- UI_StartServerRefresh(qtrue);
- }
- UI_BuildServerDisplayList(qtrue);
- UI_FeederSelection(FEEDER_SERVERS, 0);
- } else if (Q_stricmp(name, "ServerStatus") == 0) {
- trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], uiInfo.serverStatusAddress, sizeof(uiInfo.serverStatusAddress));
- UI_BuildServerStatus(qtrue);
- } else if (Q_stricmp(name, "FoundPlayerServerStatus") == 0) {
- Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
- UI_BuildServerStatus(qtrue);
- Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
- } else if (Q_stricmp(name, "FindPlayer") == 0) {
- UI_BuildFindPlayerList(qtrue);
- // clear the displayed server status info
- uiInfo.serverStatusInfo.numLines = 0;
- Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
- } else if (Q_stricmp(name, "JoinServer") == 0) {
- trap_Cvar_Set("cg_thirdPerson", "0");
- trap_Cvar_Set("cg_cameraOrbit", "0");
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- if (uiInfo.serverStatus.currentServer >= 0 && uiInfo.serverStatus.currentServer < uiInfo.serverStatus.numDisplayServers) {
- trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, 1024);
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", buff ) );
- }
- } else if (Q_stricmp(name, "FoundPlayerJoinServer") == 0) {
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- if (uiInfo.currentFoundPlayerServer >= 0 && uiInfo.currentFoundPlayerServer < uiInfo.numFoundPlayerServers) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer] ) );
- }
- } else if (Q_stricmp(name, "Quit") == 0) {
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- trap_Cmd_ExecuteText( EXEC_NOW, "quit");
- } else if (Q_stricmp(name, "Controls") == 0) {
- trap_Cvar_Set( "cl_paused", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- Menus_CloseAll();
- Menus_ActivateByName("setup_menu2");
- } else if (Q_stricmp(name, "Leave") == 0) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- Menus_CloseAll();
- Menus_ActivateByName("main");
- } else if (Q_stricmp(name, "ServerSort") == 0) {
- int sortColumn;
- if (Int_Parse(args, &sortColumn)) {
- // if same column we're already sorting on then flip the direction
- if (sortColumn == uiInfo.serverStatus.sortKey) {
- uiInfo.serverStatus.sortDir = !uiInfo.serverStatus.sortDir;
- }
- // make sure we sort again
- UI_ServersSort(sortColumn, qtrue);
- uiInfo.serverStatus.sorted = qtrue;
- }
- } else if (Q_stricmp(name, "nextSkirmish") == 0) {
- UI_StartSkirmish(qtrue);
- } else if (Q_stricmp(name, "SkirmishStart") == 0) {
- UI_StartSkirmish(qfalse);
- } else if (Q_stricmp(name, "closeingame") == 0) {
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- } else if (Q_stricmp(name, "voteMap") == 0) {
- if (ui_currentNetMap.integer >=0 && ui_currentNetMap.integer < uiInfo.mapCount) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote map %s\n",uiInfo.mapList[ui_currentNetMap.integer].mapLoadName) );
- }
- }
- else if( Q_stricmp( name, "voteKick" ) == 0 )
- {
- if( uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount )
- {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "callvote kick %d\n",
- uiInfo.clientNums[ uiInfo.playerIndex ] ) );
- }
- }
- else if( Q_stricmp( name, "voteMute" ) == 0 )
- {
- if( uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount )
- {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "callvote mute %d\n",
- uiInfo.clientNums[ uiInfo.playerIndex ] ) );
- }
- }
- else if( Q_stricmp( name, "voteUnMute" ) == 0 )
- {
- if( uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount )
- {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "callvote unmute %d\n",
- uiInfo.clientNums[ uiInfo.playerIndex ] ) );
- }
- }
- else if( Q_stricmp( name, "voteTeamKick" ) == 0 )
- {
- if( uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount )
- {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "callteamvote kick %d\n",
- uiInfo.teamClientNums[ uiInfo.teamIndex ] ) );
- }
- }
- else if( Q_stricmp( name, "voteTeamDenyBuild" ) == 0 )
- {
- if( uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount )
- {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "callteamvote denybuild %d\n",
- uiInfo.teamClientNums[ uiInfo.teamIndex ] ) );
- }
- }
- else if( Q_stricmp( name, "voteTeamAllowBuild" ) == 0 )
- {
- if( uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount )
- {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "callteamvote allowbuild %d\n",
- uiInfo.teamClientNums[ uiInfo.teamIndex ] ) );
- }
- }
- else if (Q_stricmp(name, "addFavorite") == 0) {
- if (ui_netSource.integer != AS_FAVORITES) {
- char name[MAX_NAME_LENGTH];
- char addr[MAX_NAME_LENGTH];
- int res;
-
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
- name[0] = addr[0] = '\0';
- Q_strncpyz(name, Info_ValueForKey(buff, "hostname"), MAX_NAME_LENGTH);
- Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
- if (strlen(name) > 0 && strlen(addr) > 0) {
- res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
- if (res == 0) {
- // server already in the list
- Com_Printf("Favorite already in list\n");
- }
- else if (res == -1) {
- // list full
- Com_Printf("Favorite list full\n");
- }
- else {
- // successfully added
- Com_Printf("Added favorite server %s\n", addr);
- }
+ UI_InstallCaptureFunc(UI_ArmouryRefreshCb, NULL, 1000);
}
- }
- } else if (Q_stricmp(name, "deleteFavorite") == 0) {
- if (ui_netSource.integer == AS_FAVORITES) {
- char addr[MAX_NAME_LENGTH];
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
- addr[0] = '\0';
- Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
- if (strlen(addr) > 0) {
- trap_LAN_RemoveServer(AS_FAVORITES, addr);
+ else if (Q_stricmp(name, "LoadHumanArmourySells") == 0)
+ UI_LoadHumanArmourySells();
+ else if (Q_stricmp(name, "SellToArmoury") == 0)
+ {
+ if ((cmd = uiInfo.humanArmourySellList[uiInfo.humanArmourySellIndex].cmd))
+ trap_Cmd_ExecuteText(EXEC_APPEND, cmd);
+
+ UI_InstallCaptureFunc(UI_ArmouryRefreshCb, NULL, 1000);
}
- }
- } else if (Q_stricmp(name, "createFavorite") == 0) {
- if (ui_netSource.integer == AS_FAVORITES) {
- char name[MAX_NAME_LENGTH];
- char addr[MAX_NAME_LENGTH];
- int res;
-
- name[0] = addr[0] = '\0';
- Q_strncpyz(name, UI_Cvar_VariableString("ui_favoriteName"), MAX_NAME_LENGTH);
- Q_strncpyz(addr, UI_Cvar_VariableString("ui_favoriteAddress"), MAX_NAME_LENGTH);
- if (strlen(name) > 0 && strlen(addr) > 0) {
- res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
- if (res == 0) {
- // server already in the list
- Com_Printf("Favorite already in list\n");
- }
- else if (res == -1) {
- // list full
- Com_Printf("Favorite list full\n");
- }
- else {
- // successfully added
- Com_Printf("Added favorite server %s\n", addr);
- }
+ else if (Q_stricmp(name, "LoadAlienUpgrades") == 0)
+ {
+ UI_LoadAlienUpgrades();
}
- }
- } else if (Q_stricmp(name, "orders") == 0) {
- const char *orders;
- if (String_Parse(args, &orders)) {
- int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (selectedPlayer < uiInfo.myTeamCount) {
- strcpy(buff, orders);
- trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- } else {
- int i;
- for (i = 0; i < uiInfo.myTeamCount; i++) {
- if (Q_stricmp(UI_Cvar_VariableString("name"), uiInfo.teamNames[i]) == 0) {
- continue;
- }
- strcpy(buff, orders);
- trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamNames[i]) );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- }
+ else if (Q_stricmp(name, "UpgradeToNewClass") == 0)
+ {
+ if ((cmd = uiInfo.alienUpgradeList[uiInfo.alienUpgradeIndex].cmd))
+ trap_Cmd_ExecuteText(EXEC_APPEND, cmd);
}
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- }
- } else if (Q_stricmp(name, "voiceOrdersTeam") == 0) {
- const char *orders;
- if (String_Parse(args, &orders)) {
- int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (selectedPlayer == uiInfo.myTeamCount) {
- trap_Cmd_ExecuteText( EXEC_APPEND, orders );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- }
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- }
- } else if (Q_stricmp(name, "voiceOrders") == 0) {
- const char *orders;
- if (String_Parse(args, &orders)) {
- int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (selectedPlayer < uiInfo.myTeamCount) {
- strcpy(buff, orders);
- trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- }
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- }
- } else if (Q_stricmp(name, "glCustom") == 0) {
- trap_Cvar_Set("ui_glCustom", "4");
- } else if (Q_stricmp(name, "update") == 0) {
- if (String_Parse(args, &name2))
- UI_Update(name2);
- } else if (Q_stricmp(name, "InitIgnoreList") == 0) {
- UI_BuildPlayerList();
- } else if (Q_stricmp(name, "ToggleIgnore") == 0) {
- if( uiInfo.ignoreIndex >= 0 && uiInfo.ignoreIndex < uiInfo.playerCount )
- {
- if( BG_ClientListTest( &uiInfo.ignoreList[ uiInfo.myPlayerIndex ],
- uiInfo.clientNums[ uiInfo.ignoreIndex ] ) )
+ else if (Q_stricmp(name, "LoadAlienBuilds") == 0)
+ UI_LoadAlienBuilds();
+ else if (Q_stricmp(name, "BuildAlienBuildable") == 0)
{
- BG_ClientListRemove( &uiInfo.ignoreList[ uiInfo.myPlayerIndex ],
- uiInfo.clientNums[ uiInfo.ignoreIndex ] );
- trap_Cmd_ExecuteText( EXEC_NOW, va( "unignore %i\n",
- uiInfo.clientNums[ uiInfo.ignoreIndex ] ) );
+ if ((cmd = uiInfo.alienBuildList[uiInfo.alienBuildIndex].cmd))
+ trap_Cmd_ExecuteText(EXEC_APPEND, cmd);
}
- else
+ else if (Q_stricmp(name, "LoadHumanBuilds") == 0)
+ UI_LoadHumanBuilds();
+ else if (Q_stricmp(name, "BuildHumanBuildable") == 0)
{
- BG_ClientListAdd( &uiInfo.ignoreList[ uiInfo.myPlayerIndex ],
- uiInfo.clientNums[ uiInfo.ignoreIndex ] );
- trap_Cmd_ExecuteText( EXEC_NOW, va( "ignore %i\n",
- uiInfo.clientNums[ uiInfo.ignoreIndex ] ) );
+ if ((cmd = uiInfo.humanBuildList[uiInfo.humanBuildIndex].cmd))
+ trap_Cmd_ExecuteText(EXEC_APPEND, cmd);
}
- }
- } else if (Q_stricmp(name, "IgnorePlayer") == 0) {
- if( uiInfo.ignoreIndex >= 0 && uiInfo.ignoreIndex < uiInfo.playerCount )
- {
- if( !BG_ClientListTest( &uiInfo.ignoreList[ uiInfo.myPlayerIndex ],
- uiInfo.clientNums[ uiInfo.ignoreIndex ] ) )
+ else if (Q_stricmp(name, "LoadVoiceCmds") == 0)
{
- BG_ClientListAdd( &uiInfo.ignoreList[ uiInfo.myPlayerIndex ],
- uiInfo.clientNums[ uiInfo.ignoreIndex ] );
- trap_Cmd_ExecuteText( EXEC_NOW, va( "ignore %i\n",
- uiInfo.clientNums[ uiInfo.ignoreIndex ] ) );
+ UI_LoadVoiceCmds();
}
- }
- } else if (Q_stricmp(name, "UnIgnorePlayer") == 0) {
- if( uiInfo.ignoreIndex >= 0 && uiInfo.ignoreIndex < uiInfo.playerCount )
- {
- if( BG_ClientListTest( &uiInfo.ignoreList[ uiInfo.myPlayerIndex ],
- uiInfo.clientNums[ uiInfo.ignoreIndex ] ) )
+ else if (Q_stricmp(name, "ExecuteVoiceCmd") == 0)
{
- BG_ClientListRemove( &uiInfo.ignoreList[ uiInfo.myPlayerIndex ],
- uiInfo.clientNums[ uiInfo.ignoreIndex ] );
- trap_Cmd_ExecuteText( EXEC_NOW, va( "unignore %i\n",
- uiInfo.clientNums[ uiInfo.ignoreIndex ] ) );
+ if ((cmd = uiInfo.voiceCmdList[uiInfo.voiceCmdIndex].cmd))
+ trap_Cmd_ExecuteText(EXEC_APPEND, cmd);
}
- }
- } else if (Q_stricmp(name, "setPbClStatus") == 0) {
- int stat;
- if ( Int_Parse( args, &stat ) )
- trap_SetPbClStatus( stat );
- }
- else {
- Com_Printf("unknown UI script %s\n", name);
- }
- }
-}
+ else if (Q_stricmp(name, "Say") == 0)
+ {
+ char buffer[MAX_CVAR_VALUE_STRING];
+ trap_Cvar_VariableStringBuffer("ui_sayBuffer", buffer, sizeof(buffer));
-static void UI_GetTeamColor(vec4_t *color) {
-}
+ if (!buffer[0])
+ ;
+ else if (ui_chatCommands.integer && (buffer[0] == '/' || buffer[0] == '\\'))
+ {
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("%s\n", buffer + 1));
+ }
+ else if (uiInfo.chatTeam)
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("say_team \"%s\"\n", buffer));
+ else
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("say \"%s\"\n", buffer));
+ }
+ else if (Q_stricmp(name, "SayKeydown") == 0)
+ {
+ if (ui_chatCommands.integer)
+ {
+ char buffer[MAX_CVAR_VALUE_STRING];
+ trap_Cvar_VariableStringBuffer("ui_sayBuffer", buffer, sizeof(buffer));
+
+ if (buffer[0] == '/' || buffer[0] == '\\')
+ Menus_ReplaceActiveByName("say_command");
+ else if (uiInfo.chatTeam)
+ Menus_ReplaceActiveByName("say_team");
+ else
+ Menus_ReplaceActiveByName("say");
+ }
+ }
+ else if (Q_stricmp(name, "playMovie") == 0)
+ {
+ if (uiInfo.previewMovie >= 0)
+ trap_CIN_StopCinematic(uiInfo.previewMovie);
-/*
-==================
-UI_MapCountByGameType
-==================
-*/
-static int UI_MapCountByGameType(qboolean singlePlayer) {
- int i, c, game;
- c = 0;
- game = singlePlayer ? uiInfo.gameTypes[ui_gameType.integer].gtEnum : uiInfo.gameTypes[ui_netGameType.integer].gtEnum;
-
- for (i = 0; i < uiInfo.mapCount; i++) {
- uiInfo.mapList[i].active = qfalse;
- if ( uiInfo.mapList[i].typeBits & (1 << game)) {
- if (singlePlayer) {
- if (!(uiInfo.mapList[i].typeBits & (1 << 2))) {
- continue;
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("cinematic \"%s.roq\" 2\n", uiInfo.movieList[uiInfo.movieIndex]));
}
- }
- c++;
- uiInfo.mapList[i].active = qtrue;
- }
- }
- return c;
-}
+ else if (Q_stricmp(name, "RunMod") == 0)
+ {
+ trap_Cvar_Set("fs_game", uiInfo.modList[uiInfo.modIndex].modName);
+ trap_Cmd_ExecuteText(EXEC_APPEND, "vid_restart\n");
+ }
+ else if (Q_stricmp(name, "RunDemo") == 0)
+ {
+ if(uiInfo.demoList[uiInfo.demoIndex])
+ {
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("demo \"%s\"\n", uiInfo.demoList[uiInfo.demoIndex]));
+ } else {
+ trap_Cvar_Set("com_demoErrorMessage", "No demo selected.");
+ Menus_ActivateByName("demo_error_popmenu");
+ }
+ }
+ else if (Q_stricmp(name, "Tremulous") == 0)
+ {
+ trap_Cvar_Set("fs_game", "");
+ trap_Cmd_ExecuteText(EXEC_APPEND, "vid_restart\n");
+ }
+ else if (Q_stricmp(name, "closeJoin") == 0)
+ {
+ if (uiInfo.serverStatus.refreshActive)
+ {
+ UI_StopServerRefresh();
+ uiInfo.serverStatus.nextDisplayRefresh = 0;
+ uiInfo.nextServerStatusRefresh = 0;
+ uiInfo.nextFindPlayerRefresh = 0;
+ UI_BuildServerDisplayList(qtrue);
+ }
+ else
+ {
+ Menus_CloseByName("joinserver");
+ Menus_ActivateByName("main");
+ }
+ }
+ else if (Q_stricmp(name, "StopRefresh") == 0)
+ {
+ UI_StopServerRefresh();
+ uiInfo.serverStatus.nextDisplayRefresh = 0;
+ uiInfo.nextServerStatusRefresh = 0;
+ uiInfo.nextFindPlayerRefresh = 0;
+ }
+ else if (Q_stricmp(name, "UpdateFilter") == 0)
+ {
+ if (ui_netSource.integer == AS_LOCAL)
+ UI_StartServerRefresh(qtrue);
-qboolean UI_hasSkinForBase(const char *base, const char *team) {
- char test[1024];
+ UI_BuildServerDisplayList(qtrue);
+ UI_FeederSelection(FEEDER_SERVERS, 0);
+ }
+ else if (Q_stricmp(name, "ServerStatus") == 0)
+ {
+ trap_LAN_GetServerAddressString(ui_netSource.integer,
+ uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], uiInfo.serverStatusAddress,
+ sizeof(uiInfo.serverStatusAddress));
+ UI_BuildServerStatus(qtrue);
+ }
+ else if (Q_stricmp(name, "FoundPlayerServerStatus") == 0)
+ {
+ Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer],
+ sizeof(uiInfo.serverStatusAddress));
+ UI_BuildServerStatus(qtrue);
+ Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
+ }
+ else if (Q_stricmp(name, "FindPlayer") == 0)
+ {
+ UI_BuildFindPlayerList(qtrue);
+ // clear the displayed server status info
+ uiInfo.serverStatusInfo.numLines = 0;
+ Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
+ }
+ else if (Q_stricmp(name, "JoinServer") == 0)
+ {
+ if (uiInfo.serverStatus.currentServer >= 0 &&
+ uiInfo.serverStatus.currentServer < uiInfo.serverStatus.numDisplayServers)
+ {
+ trap_LAN_GetServerAddressString(ui_netSource.integer,
+ uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, 1024);
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("connect %s\n", buff));
+ }
+ }
+ else if (Q_stricmp(name, "FoundPlayerJoinServer") == 0)
+ {
+ if (uiInfo.currentFoundPlayerServer >= 0 && uiInfo.currentFoundPlayerServer < uiInfo.numFoundPlayerServers)
+ {
+ trap_Cmd_ExecuteText(EXEC_APPEND,
+ va("connect %s\n", uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer]));
+ }
+ }
+ else if (Q_stricmp(name, "Quit") == 0)
+ trap_Cmd_ExecuteText(EXEC_APPEND, "quit\n");
+ else if (Q_stricmp(name, "Leave") == 0)
+ {
+ trap_Cmd_ExecuteText(EXEC_APPEND, "disconnect\n");
+ trap_Key_SetCatcher(KEYCATCH_UI);
+ Menus_CloseAll();
+ Menus_ActivateByName("main");
+ }
+ else if (Q_stricmp(name, "ServerSort") == 0)
+ {
+ int sortColumn;
- Com_sprintf( test, sizeof( test ), "models/players/%s/%s/lower_default.skin", base, team );
+ if (Int_Parse(args, &sortColumn))
+ {
+ // if same column we're already sorting on then flip the direction
- if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
- return qtrue;
- }
- Com_sprintf( test, sizeof( test ), "models/players/characters/%s/%s/lower_default.skin", base, team );
+ if (sortColumn == uiInfo.serverStatus.sortKey)
+ uiInfo.serverStatus.sortDir = !uiInfo.serverStatus.sortDir;
- if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
- return qtrue;
- }
- return qfalse;
-}
+ // make sure we sort again
+ UI_ServersSort(sortColumn, qtrue);
-/*
-==================
-UI_MapCountByTeam
-==================
-*/
-static int UI_HeadCountByTeam( void ) {
- static int init = 0;
- int i, j, k, c, tIndex;
-
- c = 0;
- if (!init) {
- for (i = 0; i < uiInfo.characterCount; i++) {
- uiInfo.characterList[i].reference = 0;
- for (j = 0; j < uiInfo.teamCount; j++) {
- if (UI_hasSkinForBase(uiInfo.characterList[i].base, uiInfo.teamList[j].teamName)) {
- uiInfo.characterList[i].reference |= (1<<j);
+ uiInfo.serverStatus.sorted = qtrue;
+ }
}
- }
- }
- init = 1;
- }
+ else if (Q_stricmp(name, "closeingame") == 0)
+ {
+ trap_Key_SetCatcher(trap_Key_GetCatcher() & ~KEYCATCH_UI);
+ trap_Key_ClearStates();
+ trap_Cvar_Set("cl_paused", "0");
+ Menus_CloseAll();
+ }
+ else if (Q_stricmp(name, "voteMap") == 0)
+ {
+ if (ui_selectedMap.integer >= 0 && ui_selectedMap.integer < uiInfo.mapCount)
+ {
+ trap_Cmd_ExecuteText(
+ EXEC_APPEND, va("callvote map \"%s\"\n", uiInfo.mapList[ui_selectedMap.integer].mapLoadName));
+ }
+ }
+ else if (Q_stricmp(name, "voteNextMap") == 0)
+ {
+ if (ui_selectedMap.integer >= 0 && ui_selectedMap.integer < uiInfo.mapCount)
+ {
+ trap_Cmd_ExecuteText(
+ EXEC_APPEND, va("callvote nextmap \"%s\"\n", uiInfo.mapList[ui_selectedMap.integer].mapLoadName));
+ }
+ }
+ else if (Q_stricmp(name, "voteKick") == 0)
+ {
+ if (uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount)
+ {
+ char buffer[MAX_CVAR_VALUE_STRING];
+ trap_Cvar_VariableStringBuffer("ui_reason", buffer, sizeof(buffer));
- tIndex = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("callvote kick %d%s\n", uiInfo.clientNums[uiInfo.playerIndex],
+ (buffer[0] ? va(" \"%s\"", buffer) : "")));
+ trap_Cvar_Set("ui_reason", "");
+ }
+ }
+ else if (Q_stricmp(name, "voteMute") == 0)
+ {
+ if (uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount)
+ {
+ char buffer[MAX_CVAR_VALUE_STRING];
+ trap_Cvar_VariableStringBuffer("ui_reason", buffer, sizeof(buffer));
- // do names
- for (i = 0; i < uiInfo.characterCount; i++) {
- uiInfo.characterList[i].active = qfalse;
- for(j = 0; j < TEAM_MEMBERS; j++) {
- if (uiInfo.teamList[tIndex].teamMembers[j] != NULL) {
- if (uiInfo.characterList[i].reference&(1<<tIndex)) {// && Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.characterList[i].name)==0) {
- uiInfo.characterList[i].active = qtrue;
- c++;
- break;
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("callvote mute %d%s\n", uiInfo.clientNums[uiInfo.playerIndex],
+ (buffer[0] ? va(" \"%s\"", buffer) : "")));
+ trap_Cvar_Set("ui_reason", "");
+ }
}
- }
- }
- }
-
- // and then aliases
- for(j = 0; j < TEAM_MEMBERS; j++) {
- for(k = 0; k < uiInfo.aliasCount; k++) {
- if (uiInfo.aliasList[k].name != NULL) {
- if (Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.aliasList[k].name)==0) {
- for (i = 0; i < uiInfo.characterCount; i++) {
- if (uiInfo.characterList[i].headImage != -1 && uiInfo.characterList[i].reference&(1<<tIndex) && Q_stricmp(uiInfo.aliasList[k].ai, uiInfo.characterList[i].name)==0) {
- if (uiInfo.characterList[i].active == qfalse) {
- uiInfo.characterList[i].active = qtrue;
- c++;
- }
- break;
+ else if (Q_stricmp(name, "voteUnMute") == 0)
+ {
+ if (uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount)
+ {
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("callvote unmute %d\n", uiInfo.clientNums[uiInfo.playerIndex]));
}
- }
}
- }
- }
- }
- return c;
-}
+ else if (Q_stricmp(name, "voteTeamKick") == 0)
+ {
+ if (uiInfo.teamPlayerIndex >= 0 && uiInfo.teamPlayerIndex < uiInfo.myTeamCount)
+ {
+ char buffer[MAX_CVAR_VALUE_STRING];
+ trap_Cvar_VariableStringBuffer("ui_reason", buffer, sizeof(buffer));
-/*
-==================
-UI_InsertServerIntoDisplayList
-==================
-*/
-static void UI_InsertServerIntoDisplayList(int num, int position) {
- int i;
-
- if (position < 0 || position > uiInfo.serverStatus.numDisplayServers ) {
- return;
- }
- //
- uiInfo.serverStatus.numDisplayServers++;
- for (i = uiInfo.serverStatus.numDisplayServers; i > position; i--) {
- uiInfo.serverStatus.displayServers[i] = uiInfo.serverStatus.displayServers[i-1];
- }
- uiInfo.serverStatus.displayServers[position] = num;
-}
+ trap_Cmd_ExecuteText(
+ EXEC_APPEND, va("callteamvote kick %d%s\n", uiInfo.teamClientNums[uiInfo.teamPlayerIndex],
+ (buffer[0] ? va(" \"%s\"", buffer) : "")));
+ trap_Cvar_Set("ui_reason", "");
+ }
+ }
+ else if (Q_stricmp(name, "voteTeamDenyBuild") == 0)
+ {
+ if (uiInfo.teamPlayerIndex >= 0 && uiInfo.teamPlayerIndex < uiInfo.myTeamCount)
+ {
+ char buffer[MAX_CVAR_VALUE_STRING];
+ trap_Cvar_VariableStringBuffer("ui_reason", buffer, sizeof(buffer));
-/*
-==================
-UI_RemoveServerFromDisplayList
-==================
-*/
-static void UI_RemoveServerFromDisplayList(int num) {
- int i, j;
-
- for (i = 0; i < uiInfo.serverStatus.numDisplayServers; i++) {
- if (uiInfo.serverStatus.displayServers[i] == num) {
- uiInfo.serverStatus.numDisplayServers--;
- for (j = i; j < uiInfo.serverStatus.numDisplayServers; j++) {
- uiInfo.serverStatus.displayServers[j] = uiInfo.serverStatus.displayServers[j+1];
- }
- return;
+ trap_Cmd_ExecuteText(
+ EXEC_APPEND, va("callteamvote denybuild %d%s\n", uiInfo.teamClientNums[uiInfo.teamPlayerIndex],
+ (buffer[0] ? va(" \"%s\"", buffer) : "")));
+ trap_Cvar_Set("ui_reason", "");
+ }
+ }
+ else if (Q_stricmp(name, "voteTeamAllowBuild") == 0)
+ {
+ if (uiInfo.teamPlayerIndex >= 0 && uiInfo.teamPlayerIndex < uiInfo.myTeamCount)
+ {
+ trap_Cmd_ExecuteText(
+ EXEC_APPEND, va("callteamvote allowbuild %d\n", uiInfo.teamClientNums[uiInfo.teamPlayerIndex]));
+ }
+ }
+ else if (Q_stricmp(name, "addFavorite") == 0)
+ {
+ if (ui_netSource.integer != AS_FAVORITES)
+ {
+ char name[MAX_NAME_LENGTH];
+ char addr[MAX_NAME_LENGTH];
+ int res;
+
+ trap_LAN_GetServerInfo(ui_netSource.integer,
+ uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
+ name[0] = addr[0] = '\0';
+ Q_strncpyz(name, Info_ValueForKey(buff, "hostname"), MAX_NAME_LENGTH);
+ Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
+
+ if (strlen(name) > 0 && strlen(addr) > 0)
+ {
+ res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
+
+ if (res == 0)
+ {
+ // server already in the list
+ Com_Printf("Favorite already in list\n");
+ }
+ else if (res == -1)
+ {
+ // list full
+ Com_Printf("Favorite list full\n");
+ }
+ else
+ {
+ // successfully added
+ Com_Printf("Added favorite server %s\n", addr);
+ }
+ }
+ }
+ }
+ else if (Q_stricmp(name, "deleteFavorite") == 0)
+ {
+ if (ui_netSource.integer == AS_FAVORITES)
+ {
+ char addr[MAX_NAME_LENGTH];
+ trap_LAN_GetServerInfo(ui_netSource.integer,
+ uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
+ addr[0] = '\0';
+ Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
+
+ if (strlen(addr) > 0)
+ trap_LAN_RemoveServer(AS_FAVORITES, addr);
+ }
+ }
+ else if (Q_stricmp(name, "createFavorite") == 0)
+ {
+ if (ui_netSource.integer == AS_FAVORITES)
+ {
+ char name[MAX_NAME_LENGTH];
+ char addr[MAX_NAME_LENGTH];
+ int res;
+
+ name[0] = addr[0] = '\0';
+ Q_strncpyz(name, UI_Cvar_VariableString("ui_favoriteName"), MAX_NAME_LENGTH);
+ Q_strncpyz(addr, UI_Cvar_VariableString("ui_favoriteAddress"), MAX_NAME_LENGTH);
+
+ if (strlen(name) > 0 && strlen(addr) > 0)
+ {
+ res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
+
+ if (res == 0)
+ {
+ // server already in the list
+ Com_Printf("Favorite already in list\n");
+ }
+ else if (res == -1)
+ {
+ // list full
+ Com_Printf("Favorite list full\n");
+ }
+ else
+ {
+ // successfully added
+ Com_Printf("Added favorite server %s\n", addr);
+ }
+ }
+ }
+ }
+ else if (Q_stricmp(name, "glCustom") == 0)
+ trap_Cvar_Set("ui_glCustom", "4");
+ else if (Q_stricmp(name, "update") == 0)
+ {
+ if (String_Parse(args, &name2))
+ UI_Update(name2);
+ }
+ else if (Q_stricmp(name, "InitIgnoreList") == 0)
+ UI_BuildPlayerList();
+ else if (Q_stricmp(name, "ToggleIgnore") == 0)
+ {
+ if (uiInfo.ignoreIndex >= 0 && uiInfo.ignoreIndex < uiInfo.playerCount)
+ {
+ if (Com_ClientListContains(
+ &uiInfo.ignoreList[uiInfo.myPlayerIndex], uiInfo.clientNums[uiInfo.ignoreIndex]))
+ {
+ Com_ClientListRemove(
+ &uiInfo.ignoreList[uiInfo.myPlayerIndex], uiInfo.clientNums[uiInfo.ignoreIndex]);
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("unignore %i\n", uiInfo.clientNums[uiInfo.ignoreIndex]));
+ }
+ else
+ {
+ Com_ClientListAdd(&uiInfo.ignoreList[uiInfo.myPlayerIndex], uiInfo.clientNums[uiInfo.ignoreIndex]);
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("ignore %i\n", uiInfo.clientNums[uiInfo.ignoreIndex]));
+ }
+ }
+ }
+ else if (Q_stricmp(name, "IgnorePlayer") == 0)
+ {
+ if (uiInfo.ignoreIndex >= 0 && uiInfo.ignoreIndex < uiInfo.playerCount)
+ {
+ if (!Com_ClientListContains(
+ &uiInfo.ignoreList[uiInfo.myPlayerIndex], uiInfo.clientNums[uiInfo.ignoreIndex]))
+ {
+ Com_ClientListAdd(&uiInfo.ignoreList[uiInfo.myPlayerIndex], uiInfo.clientNums[uiInfo.ignoreIndex]);
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("ignore %i\n", uiInfo.clientNums[uiInfo.ignoreIndex]));
+ }
+ }
+ }
+ else if (Q_stricmp(name, "UnIgnorePlayer") == 0)
+ {
+ if (uiInfo.ignoreIndex >= 0 && uiInfo.ignoreIndex < uiInfo.playerCount)
+ {
+ if (Com_ClientListContains(
+ &uiInfo.ignoreList[uiInfo.myPlayerIndex], uiInfo.clientNums[uiInfo.ignoreIndex]))
+ {
+ Com_ClientListRemove(
+ &uiInfo.ignoreList[uiInfo.myPlayerIndex], uiInfo.clientNums[uiInfo.ignoreIndex]);
+ trap_Cmd_ExecuteText(EXEC_APPEND, va("unignore %i\n", uiInfo.clientNums[uiInfo.ignoreIndex]));
+ }
+ }
+ }
+ else
+ Com_Printf("unknown UI script %s\n", name);
}
- }
}
-/*
-==================
-UI_BinaryServerInsertion
-==================
-*/
-static void UI_BinaryServerInsertion(int num) {
- int mid, offset, res, len;
-
- // use binary search to insert server
- len = uiInfo.serverStatus.numDisplayServers;
- mid = len;
- offset = 0;
- res = 0;
- while(mid > 0) {
- mid = len >> 1;
- //
- res = trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey,
- uiInfo.serverStatus.sortDir, num, uiInfo.serverStatus.displayServers[offset+mid]);
- // if equal
- if (res == 0) {
- UI_InsertServerIntoDisplayList(num, offset+mid);
- return;
- }
- // if larger
- else if (res == 1) {
- offset += mid;
- len -= mid;
- }
- // if smaller
- else {
- len -= mid;
- }
- }
- if (res == 1) {
- offset++;
- }
- UI_InsertServerIntoDisplayList(num, offset);
-}
+static int UI_FeederInitialise(int feederID);
/*
==================
-UI_BuildServerDisplayList
+UI_FeederCount
==================
*/
-static void UI_BuildServerDisplayList(int force) {
- int i, count, clients, maxClients, ping, game, len, visible;
- char info[MAX_STRING_CHARS];
-// qboolean startRefresh = qtrue; TTimo: unused
- static int numinvisible;
-
- if (!(force || uiInfo.uiDC.realTime > uiInfo.serverStatus.nextDisplayRefresh)) {
- return;
- }
- // if we shouldn't reset
- if ( force == 2 ) {
- force = 0;
- }
-
- // do motd updates here too
- trap_Cvar_VariableStringBuffer( "cl_motdString", uiInfo.serverStatus.motd, sizeof(uiInfo.serverStatus.motd) );
- len = strlen(uiInfo.serverStatus.motd);
- if (len != uiInfo.serverStatus.motdLen) {
- uiInfo.serverStatus.motdLen = len;
- uiInfo.serverStatus.motdWidth = -1;
- }
-
- if (force) {
- numinvisible = 0;
- // clear number of displayed servers
- uiInfo.serverStatus.numDisplayServers = 0;
- uiInfo.serverStatus.numPlayersOnServers = 0;
- // set list box index to zero
- Menu_SetFeederSelection(NULL, FEEDER_SERVERS, 0, NULL);
- // mark all servers as visible so we store ping updates for them
- trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
- }
+static int UI_FeederCount(int feederID)
+{
+ if (feederID == FEEDER_CINEMATICS)
+ return uiInfo.movieCount;
+ else if (feederID == FEEDER_MAPS)
+ return uiInfo.mapCount;
+ else if (feederID == FEEDER_SERVERS)
+ return uiInfo.serverStatus.numDisplayServers;
+ else if (feederID == FEEDER_SERVERSTATUS)
+ return uiInfo.serverStatusInfo.numLines;
+ else if (feederID == FEEDER_NEWS)
+ return uiInfo.newsInfo.numLines;
+ else if (feederID == FEEDER_GITHUB_RELEASE)
+ return uiInfo.githubRelease.numLines;
+ else if (feederID == FEEDER_FINDPLAYER)
+ return uiInfo.numFoundPlayerServers;
+ else if (feederID == FEEDER_PLAYER_LIST)
+ {
+ if (uiInfo.uiDC.realTime > uiInfo.playerRefresh)
+ {
+ uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
+ UI_BuildPlayerList();
+ }
- // get the server count (comes from the master)
- count = trap_LAN_GetServerCount(ui_netSource.integer);
- if (count == -1 || (ui_netSource.integer == AS_LOCAL && count == 0) ) {
- // still waiting on a response from the master
- uiInfo.serverStatus.numDisplayServers = 0;
- uiInfo.serverStatus.numPlayersOnServers = 0;
- uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 500;
- return;
- }
+ return uiInfo.playerCount;
+ }
+ else if (feederID == FEEDER_TEAM_LIST)
+ {
+ if (uiInfo.uiDC.realTime > uiInfo.playerRefresh)
+ {
+ uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
+ UI_BuildPlayerList();
+ }
- visible = qfalse;
- for (i = 0; i < count; i++) {
- // if we already got info for this server
- if (!trap_LAN_ServerIsVisible(ui_netSource.integer, i)) {
- continue;
+ return uiInfo.myTeamCount;
+ }
+ else if (feederID == FEEDER_IGNORE_LIST)
+ return uiInfo.playerCount;
+ else if (feederID == FEEDER_HELP_LIST)
+ return uiInfo.helpCount;
+ else if (feederID == FEEDER_MODS)
+ return uiInfo.modCount;
+ else if (feederID == FEEDER_DEMOS)
+ return uiInfo.demoCount;
+ else if (feederID == FEEDER_TREMTEAMS)
+ return uiInfo.teamCount;
+ else if (feederID == FEEDER_TREMHUMANITEMS)
+ return uiInfo.humanItemCount;
+ else if (feederID == FEEDER_TREMALIENCLASSES)
+ return uiInfo.alienClassCount;
+ else if (feederID == FEEDER_TREMHUMANARMOURYBUY)
+ return uiInfo.humanArmouryBuyCount;
+ else if (feederID == FEEDER_TREMHUMANARMOURYSELL)
+ return uiInfo.humanArmourySellCount;
+ else if (feederID == FEEDER_TREMALIENUPGRADE)
+ return uiInfo.alienUpgradeCount;
+ else if (feederID == FEEDER_TREMALIENBUILD)
+ return uiInfo.alienBuildCount;
+ else if (feederID == FEEDER_TREMHUMANBUILD)
+ return uiInfo.humanBuildCount;
+ else if (feederID == FEEDER_RESOLUTIONS)
+ {
+ if (UI_FeederInitialise(feederID) == uiInfo.numResolutions)
+ return uiInfo.numResolutions + 1;
+ else
+ return uiInfo.numResolutions;
}
- visible = qtrue;
- // get the ping for this server
- ping = trap_LAN_GetServerPing(ui_netSource.integer, i);
- if (ping > 0 || ui_netSource.integer == AS_FAVORITES) {
+ else if (feederID == FEEDER_TREMVOICECMD)
+ return uiInfo.voiceCmdCount;
- trap_LAN_GetServerInfo(ui_netSource.integer, i, info, MAX_STRING_CHARS);
+ return 0;
+}
- clients = atoi(Info_ValueForKey(info, "clients"));
- uiInfo.serverStatus.numPlayersOnServers += clients;
+static const char *UI_SelectedMap(int index, int *actual)
+{
+ int i, c;
+ c = 0;
+ *actual = 0;
- if (ui_browserShowEmpty.integer == 0) {
- if (clients == 0) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- continue;
+ for (i = 0; i < uiInfo.mapCount; i++)
+ {
+ if (c == index)
+ {
+ *actual = i;
+ return uiInfo.mapList[i].mapName;
}
- }
+ else
+ c++;
+ }
- if (ui_browserShowFull.integer == 0) {
- maxClients = atoi(Info_ValueForKey(info, "sv_maxclients"));
- if (clients == maxClients) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- continue;
- }
- }
+ return "";
+}
- if (uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum != -1) {
- game = atoi(Info_ValueForKey(info, "gametype"));
- if (game != uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- continue;
- }
- }
+static int GCD(int a, int b)
+{
+ int c;
- // make sure we never add a favorite server twice
- if (ui_netSource.integer == AS_FAVORITES) {
- UI_RemoveServerFromDisplayList(i);
- }
- // insert the server into the list
- UI_BinaryServerInsertion(i);
- // done with this server
- if (ping > 0) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- numinvisible++;
- }
+ while (b != 0)
+ {
+ c = a % b;
+ a = b;
+ b = c;
}
- }
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime;
-
- // if there were no servers visible for ping updates
- if (!visible) {
-// UI_StopServerRefresh();
-// uiInfo.serverStatus.nextDisplayRefresh = 0;
- }
+ return a;
}
-typedef struct
+static const char *UI_DisplayAspectString(int w, int h)
{
- char *name, *altName;
-} serverStatusCvar_t;
-
-serverStatusCvar_t serverStatusCvars[] = {
- {"sv_hostname", "Name"},
- {"Address", ""},
- {"gamename", "Game name"},
- {"g_gametype", "Game type"},
- {"mapname", "Map"},
- {"version", ""},
- {"protocol", ""},
- {"timelimit", ""},
- {"fraglimit", ""},
- {NULL, NULL}
-};
+ int gcd = GCD(w, h);
-/*
-==================
-UI_SortServerStatusInfo
-==================
-*/
-static void UI_SortServerStatusInfo( serverStatusInfo_t *info ) {
- int i, j, index;
- char *tmp1, *tmp2;
-
- // FIXME: if "gamename" == "baseq3" or "missionpack" then
- // replace the gametype number by FFA, CTF etc.
- //
- index = 0;
- for (i = 0; serverStatusCvars[i].name; i++) {
- for (j = 0; j < info->numLines; j++) {
- if ( !info->lines[j][1] || info->lines[j][1][0] ) {
- continue;
- }
- if ( !Q_stricmp(serverStatusCvars[i].name, info->lines[j][0]) ) {
- // swap lines
- tmp1 = info->lines[index][0];
- tmp2 = info->lines[index][3];
- info->lines[index][0] = info->lines[j][0];
- info->lines[index][3] = info->lines[j][3];
- info->lines[j][0] = tmp1;
- info->lines[j][3] = tmp2;
- //
- if ( strlen(serverStatusCvars[i].altName) ) {
- info->lines[index][0] = serverStatusCvars[i].altName;
- }
- index++;
- }
+ w /= gcd;
+ h /= gcd;
+
+ // For some reason 8:5 is usually referred to as 16:10
+ if (w == 8 && h == 5)
+ {
+ w = 16;
+ h = 10;
}
- }
+
+ return va("%d:%d", w, h);
}
-/*
-==================
-UI_GetServerStatusInfo
-==================
-*/
-static int UI_GetServerStatusInfo( const char *serverAddress, serverStatusInfo_t *info ) {
- char *p, *score, *ping, *name;
- int i, len;
+static const char *UI_FeederItemText(int feederID, int index, int column, qhandle_t *handle)
+{
+ if (handle)
+ *handle = -1;
- if (!info) {
- trap_LAN_ServerStatus( serverAddress, NULL, 0);
- return qfalse;
- }
- memset(info, 0, sizeof(*info));
- if ( trap_LAN_ServerStatus( serverAddress, info->text, sizeof(info->text)) ) {
- Q_strncpyz(info->address, serverAddress, sizeof(info->address));
- p = info->text;
- info->numLines = 0;
- info->lines[info->numLines][0] = "Address";
- info->lines[info->numLines][1] = "";
- info->lines[info->numLines][2] = "";
- info->lines[info->numLines][3] = info->address;
- info->numLines++;
- // get the cvars
- while (p && *p) {
- p = strchr(p, '\\');
- if (!p) break;
- *p++ = '\0';
- if (*p == '\\')
- break;
- info->lines[info->numLines][0] = p;
- info->lines[info->numLines][1] = "";
- info->lines[info->numLines][2] = "";
- p = strchr(p, '\\');
- if (!p) break;
- *p++ = '\0';
- info->lines[info->numLines][3] = p;
-
- info->numLines++;
- if (info->numLines >= MAX_SERVERSTATUS_LINES)
- break;
- }
- // get the player list
- if (info->numLines < MAX_SERVERSTATUS_LINES-3) {
- // empty line
- info->lines[info->numLines][0] = "";
- info->lines[info->numLines][1] = "";
- info->lines[info->numLines][2] = "";
- info->lines[info->numLines][3] = "";
- info->numLines++;
- // header
- info->lines[info->numLines][0] = "num";
- info->lines[info->numLines][1] = "score";
- info->lines[info->numLines][2] = "ping";
- info->lines[info->numLines][3] = "name";
- info->numLines++;
- // parse players
- i = 0;
- len = 0;
- while (p && *p) {
- if (*p == '\\')
- *p++ = '\0';
- if (!p)
- break;
- score = p;
- p = strchr(p, ' ');
- if (!p)
- break;
- *p++ = '\0';
- ping = p;
- p = strchr(p, ' ');
- if (!p)
- break;
- *p++ = '\0';
- name = p;
- Com_sprintf(&info->pings[len], sizeof(info->pings)-len, "%d", i);
- info->lines[info->numLines][0] = &info->pings[len];
- len += strlen(&info->pings[len]) + 1;
- info->lines[info->numLines][1] = score;
- info->lines[info->numLines][2] = ping;
- info->lines[info->numLines][3] = name;
- info->numLines++;
- if (info->numLines >= MAX_SERVERSTATUS_LINES)
- break;
- p = strchr(p, '\\');
- if (!p)
- break;
- *p++ = '\0';
- //
- i++;
- }
+ if (feederID == FEEDER_MAPS)
+ {
+ int actual;
+ return UI_SelectedMap(index, &actual);
}
- UI_SortServerStatusInfo( info );
- return qtrue;
- }
- return qfalse;
-}
+ else if (feederID == FEEDER_SERVERS)
+ {
+ if (index >= 0 && index < UI_FeederCount(feederID))
+ {
+ static char info[MAX_STRING_CHARS];
+ static char clientBuff[32];
+ static char cleaned[MAX_STRING_CHARS];
+ static int lastColumn = -1;
+ static int lastTime = 0;
+ int ping;
+
+ if (lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000)
+ {
+ trap_LAN_GetServerInfo(
+ ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
+ lastColumn = column;
+ lastTime = uiInfo.uiDC.realTime;
+ }
-/*
-==================
-stristr
-==================
-*/
-static char *stristr(char *str, char *charset) {
- int i;
+ ping = atoi(Info_ValueForKey(info, "ping"));
- while(*str) {
- for (i = 0; charset[i] && str[i]; i++) {
- if (toupper(charset[i]) != toupper(str[i])) break;
- }
- if (!charset[i]) return str;
- str++;
- }
- return NULL;
-}
+ UI_EscapeEmoticons(cleaned, Info_ValueForKey(info, "hostname"), sizeof(cleaned));
-/*
-==================
-UI_BuildFindPlayerList
-==================
-*/
-static void UI_BuildFindPlayerList(qboolean force) {
- static int numFound, numTimeOuts;
- int i, j, resend;
- serverStatusInfo_t info;
- char name[MAX_NAME_LENGTH+2];
- char infoString[MAX_STRING_CHARS];
-
- if (!force) {
- if (!uiInfo.nextFindPlayerRefresh || uiInfo.nextFindPlayerRefresh > uiInfo.uiDC.realTime) {
- return;
- }
- }
- else {
- memset(&uiInfo.pendingServerStatus, 0, sizeof(uiInfo.pendingServerStatus));
- uiInfo.numFoundPlayerServers = 0;
- uiInfo.currentFoundPlayerServer = 0;
- trap_Cvar_VariableStringBuffer( "ui_findPlayer", uiInfo.findPlayerName, sizeof(uiInfo.findPlayerName));
- Q_CleanStr(uiInfo.findPlayerName);
- // should have a string of some length
- if (!strlen(uiInfo.findPlayerName)) {
- uiInfo.nextFindPlayerRefresh = 0;
- return;
- }
- // set resend time
- resend = ui_serverStatusTimeOut.integer / 2 - 10;
- if (resend < 50) {
- resend = 50;
- }
- trap_Cvar_Set("cl_serverStatusResendTime", va("%d", resend));
- // reset all server status requests
- trap_LAN_ServerStatus( NULL, NULL, 0);
- //
- uiInfo.numFoundPlayerServers = 1;
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
- "searching %d...", uiInfo.pendingServerStatus.num);
- numFound = 0;
- numTimeOuts++;
- }
- for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
- // if this pending server is valid
- if (uiInfo.pendingServerStatus.server[i].valid) {
- // try to get the server status for this server
- if (UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, &info ) ) {
- //
- numFound++;
- // parse through the server status lines
- for (j = 0; j < info.numLines; j++) {
- // should have ping info
- if ( !info.lines[j][2] || !info.lines[j][2][0] ) {
- continue;
- }
- // clean string first
- Q_strncpyz(name, info.lines[j][3], sizeof(name));
- Q_CleanStr(name);
- // if the player name is a substring
- if (stristr(name, uiInfo.findPlayerName)) {
- // add to found server list if we have space (always leave space for a line with the number found)
- if (uiInfo.numFoundPlayerServers < MAX_FOUNDPLAYER_SERVERS-1) {
- //
- Q_strncpyz(uiInfo.foundPlayerServerAddresses[uiInfo.numFoundPlayerServers-1],
- uiInfo.pendingServerStatus.server[i].adrstr,
- sizeof(uiInfo.foundPlayerServerAddresses[0]));
- Q_strncpyz(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- uiInfo.pendingServerStatus.server[i].name,
- sizeof(uiInfo.foundPlayerServerNames[0]));
- uiInfo.numFoundPlayerServers++;
+ switch (column)
+ {
+ case SORT_HOST:
+ if (ping <= 0)
+ return Info_ValueForKey(info, "addr");
+ else
+ {
+ static char hostname[1024];
+
+ if (ui_netSource.integer == AS_LOCAL)
+ {
+ Com_sprintf(hostname, sizeof(hostname), "%s [%s]", cleaned,
+ netnames[atoi(Info_ValueForKey(info, "nettype"))]);
+ return hostname;
+ }
+ else
+ {
+ char *text;
+ char *label;
+
+ label = Info_ValueForKey(info, "label");
+ if (label[0])
+ {
+ // First char of the label response is a sorting tag. Skip it.
+ label += 1;
+
+ Com_sprintf(hostname, sizeof(hostname), "%s %s", label, cleaned);
+ }
+ else
+ {
+ Com_sprintf(hostname, sizeof(hostname), "%s", cleaned);
+ }
+
+ // Strip leading whitespace
+ text = hostname;
+
+ while (*text != '\0' && *text == ' ')
+ text++;
+
+ return text;
+ }
+ }
+
+ case SORT_GAME:
+ return Info_ValueForKey(info, "game");
+
+ case SORT_MAP:
+ return Info_ValueForKey(info, "mapname");
+
+ case SORT_CLIENTS:
+ Com_sprintf(clientBuff, sizeof(clientBuff), "%s (%s)", Info_ValueForKey(info, "clients"),
+ Info_ValueForKey(info, "sv_maxclients"));
+ return clientBuff;
+
+ case SORT_PING:
+ if (ping <= 0)
+ return "...";
+ else
+ return Info_ValueForKey(info, "ping");
}
- else {
- // can't add any more so we're done
- uiInfo.pendingServerStatus.num = uiInfo.serverStatus.numDisplayServers;
+ }
+ }
+ else if (feederID == FEEDER_SERVERSTATUS)
+ {
+ if (index >= 0 && index < uiInfo.serverStatusInfo.numLines)
+ {
+ if (column >= 0 && column < 4)
+ return uiInfo.serverStatusInfo.lines[index][column];
+ }
+ }
+ else if (feederID == FEEDER_NEWS)
+ {
+ if (index >= 0 && index < uiInfo.newsInfo.numLines)
+ return uiInfo.newsInfo.text[index];
+ }
+ else if (feederID == FEEDER_GITHUB_RELEASE)
+ {
+ if (index >= 0 && index < uiInfo.githubRelease.numLines)
+ return uiInfo.githubRelease.text[index];
+ }
+ else if (feederID == FEEDER_FINDPLAYER)
+ {
+ if (index >= 0 && index < uiInfo.numFoundPlayerServers)
+ return uiInfo.foundPlayerServerNames[index];
+ }
+ else if (feederID == FEEDER_PLAYER_LIST)
+ {
+ if (index >= 0 && index < uiInfo.playerCount)
+ return uiInfo.playerNames[index];
+ }
+ else if (feederID == FEEDER_TEAM_LIST)
+ {
+ if (index >= 0 && index < uiInfo.myTeamCount)
+ return uiInfo.teamNames[index];
+ }
+ else if (feederID == FEEDER_IGNORE_LIST)
+ {
+ if (index >= 0 && index < uiInfo.playerCount)
+ {
+ switch (column)
+ {
+ case 1:
+ // am I ignoring him
+ return Com_ClientListContains(&uiInfo.ignoreList[uiInfo.myPlayerIndex], uiInfo.clientNums[index])
+ ? "X"
+ : "";
+
+ case 2:
+ // is he ignoring me
+ return Com_ClientListContains(&uiInfo.ignoreList[index], uiInfo.playerNumber) ? "X" : "";
+
+ default:
+ return uiInfo.playerNames[index];
}
- }
}
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
- "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
- // retrieved the server status so reuse this spot
- uiInfo.pendingServerStatus.server[i].valid = qfalse;
- }
}
- // if empty pending slot or timed out
- if (!uiInfo.pendingServerStatus.server[i].valid ||
- uiInfo.pendingServerStatus.server[i].startTime < uiInfo.uiDC.realTime - ui_serverStatusTimeOut.integer) {
- if (uiInfo.pendingServerStatus.server[i].valid) {
- numTimeOuts++;
- }
- // reset server status request for this address
- UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, NULL );
- // reuse pending slot
- uiInfo.pendingServerStatus.server[i].valid = qfalse;
- // if we didn't try to get the status of all servers in the main browser yet
- if (uiInfo.pendingServerStatus.num < uiInfo.serverStatus.numDisplayServers) {
- uiInfo.pendingServerStatus.server[i].startTime = uiInfo.uiDC.realTime;
- trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num],
- uiInfo.pendingServerStatus.server[i].adrstr, sizeof(uiInfo.pendingServerStatus.server[i].adrstr));
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num], infoString, sizeof(infoString));
- Q_strncpyz(uiInfo.pendingServerStatus.server[i].name, Info_ValueForKey(infoString, "hostname"), sizeof(uiInfo.pendingServerStatus.server[0].name));
- uiInfo.pendingServerStatus.server[i].valid = qtrue;
- uiInfo.pendingServerStatus.num++;
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
- "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
- }
+ else if (feederID == FEEDER_HELP_LIST)
+ {
+ if (index >= 0 && index < uiInfo.helpCount)
+ return uiInfo.helpList[index].text;
}
- }
- for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
- if (uiInfo.pendingServerStatus.server[i].valid) {
- break;
- }
- }
- // if still trying to retrieve server status info
- if (i < MAX_SERVERSTATUSREQUESTS) {
- uiInfo.nextFindPlayerRefresh = uiInfo.uiDC.realTime + 25;
- }
- else {
- // add a line that shows the number of servers found
- if (!uiInfo.numFoundPlayerServers) {
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]), "no servers found");
- }
- else {
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]),
- "%d server%s found with player %s", uiInfo.numFoundPlayerServers-1,
- uiInfo.numFoundPlayerServers == 2 ? "":"s", uiInfo.findPlayerName);
- }
- uiInfo.nextFindPlayerRefresh = 0;
- // show the server status info for the selected server
- UI_FeederSelection(FEEDER_FINDPLAYER, uiInfo.currentFoundPlayerServer);
- }
-}
+ else if (feederID == FEEDER_MODS)
+ {
+ if (index >= 0 && index < uiInfo.modCount)
+ {
+ if (uiInfo.modList[index].modDescr && *uiInfo.modList[index].modDescr)
+ return uiInfo.modList[index].modDescr;
+ else
+ return uiInfo.modList[index].modName;
+ }
+ }
+ else if (feederID == FEEDER_CINEMATICS)
+ {
+ if (index >= 0 && index < uiInfo.movieCount)
+ return uiInfo.movieList[index];
+ }
+ else if (feederID == FEEDER_DEMOS)
+ {
+ if (index >= 0 && index < uiInfo.demoCount)
+ return uiInfo.demoList[index];
+ }
+ else if (feederID == FEEDER_TREMTEAMS)
+ {
+ if (index >= 0 && index < uiInfo.teamCount)
+ return uiInfo.teamList[index].text;
+ }
+ else if (feederID == FEEDER_TREMHUMANITEMS)
+ {
+ if (index >= 0 && index < uiInfo.humanItemCount)
+ return uiInfo.humanItemList[index].text;
+ }
+ else if (feederID == FEEDER_TREMALIENCLASSES)
+ {
+ if (index >= 0 && index < uiInfo.alienClassCount)
+ return uiInfo.alienClassList[index].text;
+ }
+ else if (feederID == FEEDER_TREMHUMANARMOURYBUY)
+ {
+ if (index >= 0 && index < uiInfo.humanArmouryBuyCount)
+ return uiInfo.humanArmouryBuyList[index].text;
+ }
+ else if (feederID == FEEDER_TREMHUMANARMOURYSELL)
+ {
+ if (index >= 0 && index < uiInfo.humanArmourySellCount)
+ return uiInfo.humanArmourySellList[index].text;
+ }
+ else if (feederID == FEEDER_TREMALIENUPGRADE)
+ {
+ if (index >= 0 && index < uiInfo.alienUpgradeCount)
+ return uiInfo.alienUpgradeList[index].text;
+ }
+ else if (feederID == FEEDER_TREMALIENBUILD)
+ {
+ if (index >= 0 && index < uiInfo.alienBuildCount)
+ return uiInfo.alienBuildList[index].text;
+ }
+ else if (feederID == FEEDER_TREMHUMANBUILD)
+ {
+ if (index >= 0 && index < uiInfo.humanBuildCount)
+ return uiInfo.humanBuildList[index].text;
+ }
+ else if (feederID == FEEDER_RESOLUTIONS)
+ {
+ static char resolution[MAX_STRING_CHARS];
+ int w, h;
-/*
-==================
-UI_BuildServerStatus
-==================
-*/
-static void UI_BuildServerStatus(qboolean force) {
-
- if (uiInfo.nextFindPlayerRefresh) {
- return;
- }
- if (!force) {
- if (!uiInfo.nextServerStatusRefresh || uiInfo.nextServerStatusRefresh > uiInfo.uiDC.realTime) {
- return;
- }
- }
- else {
- Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
- uiInfo.serverStatusInfo.numLines = 0;
- // reset all server status requests
- trap_LAN_ServerStatus( NULL, NULL, 0);
- }
- if (uiInfo.serverStatus.currentServer < 0 || uiInfo.serverStatus.currentServer > uiInfo.serverStatus.numDisplayServers || uiInfo.serverStatus.numDisplayServers == 0) {
- return;
- }
- if (UI_GetServerStatusInfo( uiInfo.serverStatusAddress, &uiInfo.serverStatusInfo ) ) {
- uiInfo.nextServerStatusRefresh = 0;
- UI_GetServerStatusInfo( uiInfo.serverStatusAddress, NULL );
- }
- else {
- uiInfo.nextServerStatusRefresh = uiInfo.uiDC.realTime + 500;
- }
-}
+ if (index >= 0 && index < uiInfo.numResolutions)
+ {
+ w = uiInfo.resolutions[index].w;
+ h = uiInfo.resolutions[index].h;
-/*
-==================
-UI_FeederCount
-==================
-*/
-static int UI_FeederCount(float feederID) {
-
- if (feederID == FEEDER_HEADS) {
- return UI_HeadCountByTeam();
- } else if (feederID == FEEDER_Q3HEADS) {
- return uiInfo.q3HeadCount;
- } else if (feederID == FEEDER_CINEMATICS) {
- return uiInfo.movieCount;
- } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
- return UI_MapCountByGameType(feederID == FEEDER_MAPS ? qtrue : qfalse);
- } else if (feederID == FEEDER_SERVERS) {
- return uiInfo.serverStatus.numDisplayServers;
- } else if (feederID == FEEDER_SERVERSTATUS) {
- return uiInfo.serverStatusInfo.numLines;
- } else if (feederID == FEEDER_FINDPLAYER) {
- return uiInfo.numFoundPlayerServers;
- } else if (feederID == FEEDER_PLAYER_LIST) {
- if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
- uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
- UI_BuildPlayerList();
- }
- return uiInfo.playerCount;
- } else if (feederID == FEEDER_TEAM_LIST) {
- if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
- uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
- UI_BuildPlayerList();
- }
- return uiInfo.myTeamCount;
- } else if (feederID == FEEDER_IGNORE_LIST) {
- return uiInfo.playerCount;
- } else if (feederID == FEEDER_MODS) {
- return uiInfo.modCount;
- } else if (feederID == FEEDER_DEMOS) {
- return uiInfo.demoCount;
- }
-
-//TA: tremulous menus
- else if( feederID == FEEDER_TREMTEAMS )
- return uiInfo.tremTeamCount;
- else if( feederID == FEEDER_TREMHUMANITEMS )
- return uiInfo.tremHumanItemCount;
- else if( feederID == FEEDER_TREMALIENCLASSES )
- return uiInfo.tremAlienClassCount;
- else if( feederID == FEEDER_TREMHUMANARMOURYBUY )
- return uiInfo.tremHumanArmouryBuyCount;
- else if( feederID == FEEDER_TREMHUMANARMOURYSELL )
- return uiInfo.tremHumanArmourySellCount;
- else if( feederID == FEEDER_TREMALIENUPGRADE )
- return uiInfo.tremAlienUpgradeCount;
- else if( feederID == FEEDER_TREMALIENBUILD )
- return uiInfo.tremAlienBuildCount;
- else if( feederID == FEEDER_TREMHUMANBUILD )
- return uiInfo.tremHumanBuildCount;
-//TA: tremulous menus
-
- return 0;
-}
+ Com_sprintf(resolution, sizeof(resolution), "%dx%d (%s)", w, h, UI_DisplayAspectString(w, h));
-static const char *UI_SelectedMap(int index, int *actual) {
- int i, c;
- c = 0;
- *actual = 0;
- for (i = 0; i < uiInfo.mapCount; i++) {
- if (uiInfo.mapList[i].active) {
- if (c == index) {
- *actual = i;
- return uiInfo.mapList[i].mapName;
- } else {
- c++;
- }
- }
- }
- return "";
-}
+ return resolution;
+ }
-static const char *UI_SelectedHead(int index, int *actual) {
- int i, c;
- c = 0;
- *actual = 0;
- for (i = 0; i < uiInfo.characterCount; i++) {
- if (uiInfo.characterList[i].active) {
- if (c == index) {
- *actual = i;
- return uiInfo.characterList[i].name;
- } else {
- c++;
- }
- }
- }
- return "";
-}
+ w = (int)trap_Cvar_VariableValue("r_width");
+ h = (int)trap_Cvar_VariableValue("r_height");
+ Com_sprintf(resolution, sizeof(resolution), "Custom (%dx%d)", w, h);
-static int UI_GetIndexFromSelection(int actual) {
- int i, c;
- c = 0;
- for (i = 0; i < uiInfo.mapCount; i++) {
- if (uiInfo.mapList[i].active) {
- if (i == actual) {
- return c;
- }
- c++;
+ return resolution;
}
- }
- return 0;
+ else if (feederID == FEEDER_TREMVOICECMD)
+ {
+ if (index >= 0 && index < uiInfo.voiceCmdCount)
+ return uiInfo.voiceCmdList[index].text;
+ }
+
+ return "";
}
-static void UI_UpdatePendingPings( void ) {
- trap_LAN_ResetPings(ui_netSource.integer);
- uiInfo.serverStatus.refreshActive = qtrue;
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
+static qhandle_t UI_FeederItemImage(int feederID, int index)
+{
+ if (feederID == FEEDER_MAPS)
+ {
+ int actual;
+ UI_SelectedMap(index, &actual);
+ index = actual;
+
+ if (index >= 0 && index < uiInfo.mapCount)
+ {
+ if (uiInfo.mapList[index].levelShot == -1)
+ uiInfo.mapList[index].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[index].imageName);
+
+ return uiInfo.mapList[index].levelShot;
+ }
+ }
+ return 0;
}
-static const char *UI_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
- static char info[MAX_STRING_CHARS];
- static char hostname[1024];
- static char clientBuff[32];
- static int lastColumn = -1;
- static int lastTime = 0;
- *handle = -1;
- if (feederID == FEEDER_HEADS) {
- int actual;
- return UI_SelectedHead(index, &actual);
- } else if (feederID == FEEDER_Q3HEADS) {
- if (index >= 0 && index < uiInfo.q3HeadCount) {
- return uiInfo.q3HeadNames[index];
- }
- } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
- int actual;
- return UI_SelectedMap(index, &actual);
- } else if (feederID == FEEDER_SERVERS) {
- if (index >= 0 && index < uiInfo.serverStatus.numDisplayServers) {
- int ping;
- if (lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000) {
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
- lastColumn = column;
- lastTime = uiInfo.uiDC.realTime;
- }
+static void UI_FeederSelection(int feederID, int index)
+{
+ static char info[MAX_STRING_CHARS];
- ping = atoi(Info_ValueForKey(info, "ping"));
- if (ping == -1) {
- // if we ever see a ping that is out of date, do a server refresh
- // UI_UpdatePendingPings();
- }
- switch (column) {
- case SORT_HOST :
- if (ping <= 0) {
- return Info_ValueForKey(info, "addr");
- } else {
- if ( ui_netSource.integer == AS_LOCAL ) {
- Com_sprintf( hostname, sizeof(hostname), "%s [%s]",
- Info_ValueForKey(info, "hostname"),
- netnames[atoi(Info_ValueForKey(info, "nettype"))] );
- return hostname;
- }
- else
- {
- char *text;
+ if (feederID == FEEDER_MAPS)
+ {
+ int actual, map;
+ map = ui_selectedMap.integer;
- Com_sprintf( hostname, sizeof(hostname), "%s", Info_ValueForKey(info, "hostname"));
+ if (uiInfo.mapList[map].cinematic >= 0)
+ {
+ trap_CIN_StopCinematic(uiInfo.mapList[map].cinematic);
+ uiInfo.mapList[map].cinematic = -1;
+ }
- // Strip leading whitespace
- text = hostname;
- while( *text != '\0' && *text == ' ' )
- text++;
+ UI_SelectedMap(index, &actual);
- return text;
- }
- }
- case SORT_MAP :
- return Info_ValueForKey(info, "mapname");
- case SORT_CLIENTS :
- Com_sprintf( clientBuff, sizeof(clientBuff), "%s (%s)", Info_ValueForKey(info, "clients"), Info_ValueForKey(info, "sv_maxclients"));
- return clientBuff;
- case SORT_PING :
- if (ping <= 0) {
- return "...";
- } else {
- return Info_ValueForKey(info, "ping");
- }
- }
- }
- } else if (feederID == FEEDER_SERVERSTATUS) {
- if ( index >= 0 && index < uiInfo.serverStatusInfo.numLines ) {
- if ( column >= 0 && column < 4 ) {
- return uiInfo.serverStatusInfo.lines[index][column];
- }
- }
- } else if (feederID == FEEDER_FINDPLAYER) {
- if ( index >= 0 && index < uiInfo.numFoundPlayerServers ) {
- //return uiInfo.foundPlayerServerAddresses[index];
- return uiInfo.foundPlayerServerNames[index];
+ ui_selectedMap.integer = actual;
+ trap_Cvar_Set("ui_selectedMap", va("%d", actual));
+ uiInfo.mapList[ui_selectedMap.integer].cinematic = trap_CIN_PlayCinematic(
+ va("%s.roq", uiInfo.mapList[ui_selectedMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent));
}
- } else if (feederID == FEEDER_PLAYER_LIST) {
- if (index >= 0 && index < uiInfo.playerCount) {
- return uiInfo.playerNames[index];
+ else if (feederID == FEEDER_SERVERS)
+ {
+ const char *mapName = NULL;
+
+ uiInfo.serverStatus.currentServer = index;
+ trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
+ uiInfo.serverStatus.currentServerPreview =
+ trap_R_RegisterShaderNoMip(va("levelshots/%s", Info_ValueForKey(info, "mapname")));
+
+ if (uiInfo.serverStatus.currentServerCinematic >= 0)
+ {
+ trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
+ uiInfo.serverStatus.currentServerCinematic = -1;
+ }
+
+ mapName = Info_ValueForKey(info, "mapname");
+
+ if (mapName && *mapName)
+ {
+ uiInfo.serverStatus.currentServerCinematic =
+ trap_CIN_PlayCinematic(va("%s.roq", mapName), 0, 0, 0, 0, (CIN_loop | CIN_silent));
+ }
}
- } else if (feederID == FEEDER_TEAM_LIST) {
- if (index >= 0 && index < uiInfo.myTeamCount) {
- return uiInfo.teamNames[index];
+ else if (feederID == FEEDER_SERVERSTATUS)
+ {
}
- } else if (feederID == FEEDER_IGNORE_LIST) {
- if (index >= 0 && index < uiInfo.playerCount) {
- switch( column )
- {
- case 1:
- // am I ignoring him
- return ( BG_ClientListTest(&uiInfo.ignoreList[ uiInfo.myPlayerIndex ],
- uiInfo.clientNums[ index ] ) ) ? "X" : "";
- case 2:
- // is he ignoring me
- return ( BG_ClientListTest( &uiInfo.ignoreList[ index ],
- uiInfo.playerNumber ) ) ? "X" : "";
- default:
- return uiInfo.playerNames[index];
- }
+ else if (feederID == FEEDER_FINDPLAYER)
+ {
+ uiInfo.currentFoundPlayerServer = index;
+ //
+
+ if (index < uiInfo.numFoundPlayerServers - 1)
+ {
+ // build a new server status for this server
+ Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer],
+ sizeof(uiInfo.serverStatusAddress));
+ Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
+ UI_BuildServerStatus(qtrue);
+ }
}
- } else if (feederID == FEEDER_MODS) {
- if (index >= 0 && index < uiInfo.modCount) {
- if (uiInfo.modList[index].modDescr && *uiInfo.modList[index].modDescr) {
- return uiInfo.modList[index].modDescr;
- } else {
- return uiInfo.modList[index].modName;
- }
+ else if (feederID == FEEDER_PLAYER_LIST)
+ uiInfo.playerIndex = index;
+ else if (feederID == FEEDER_TEAM_LIST)
+ uiInfo.teamPlayerIndex = index;
+ else if (feederID == FEEDER_IGNORE_LIST)
+ uiInfo.ignoreIndex = index;
+ else if (feederID == FEEDER_HELP_LIST)
+ uiInfo.helpIndex = index;
+ else if (feederID == FEEDER_MODS)
+ uiInfo.modIndex = index;
+ else if (feederID == FEEDER_CINEMATICS)
+ {
+ uiInfo.movieIndex = index;
+
+ if (uiInfo.previewMovie >= 0)
+ trap_CIN_StopCinematic(uiInfo.previewMovie);
+
+ uiInfo.previewMovie = -1;
+ }
+ else if (feederID == FEEDER_DEMOS)
+ uiInfo.demoIndex = index;
+ else if (feederID == FEEDER_TREMTEAMS)
+ uiInfo.teamIndex = index;
+ else if (feederID == FEEDER_TREMHUMANITEMS)
+ uiInfo.humanItemIndex = index;
+ else if (feederID == FEEDER_TREMALIENCLASSES)
+ uiInfo.alienClassIndex = index;
+ else if (feederID == FEEDER_TREMHUMANARMOURYBUY)
+ uiInfo.humanArmouryBuyIndex = index;
+ else if (feederID == FEEDER_TREMHUMANARMOURYSELL)
+ uiInfo.humanArmourySellIndex = index;
+ else if (feederID == FEEDER_TREMALIENUPGRADE)
+ uiInfo.alienUpgradeIndex = index;
+ else if (feederID == FEEDER_TREMALIENBUILD)
+ uiInfo.alienBuildIndex = index;
+ else if (feederID == FEEDER_TREMHUMANBUILD)
+ uiInfo.humanBuildIndex = index;
+ else if (feederID == FEEDER_RESOLUTIONS)
+ {
+ if (index >= 0 && index < uiInfo.numResolutions)
+ {
+ trap_Cvar_Set("r_width", va("%d", uiInfo.resolutions[index].w));
+ trap_Cvar_Set("r_height", va("%d", uiInfo.resolutions[index].h));
+ }
+
+ uiInfo.resolutionIndex = index;
}
- } else if (feederID == FEEDER_CINEMATICS) {
- if (index >= 0 && index < uiInfo.movieCount) {
- return uiInfo.movieList[index];
- }
- } else if (feederID == FEEDER_DEMOS) {
- if (index >= 0 && index < uiInfo.demoCount) {
- return uiInfo.demoList[index];
- }
- }
-
-//TA: tremulous menus
- else if( feederID == FEEDER_TREMTEAMS )
- {
- if( index >= 0 && index < uiInfo.tremTeamCount )
- return uiInfo.tremTeamList[ index ].text;
- }
- else if( feederID == FEEDER_TREMHUMANITEMS )
- {
- if( index >= 0 && index < uiInfo.tremHumanItemCount )
- return uiInfo.tremHumanItemList[ index ].text;
- }
- else if( feederID == FEEDER_TREMALIENCLASSES )
- {
- if( index >= 0 && index < uiInfo.tremAlienClassCount )
- return uiInfo.tremAlienClassList[ index ].text;
- }
- else if( feederID == FEEDER_TREMHUMANARMOURYBUY )
- {
- if( index >= 0 && index < uiInfo.tremHumanArmouryBuyCount )
- return uiInfo.tremHumanArmouryBuyList[ index ].text;
- }
- else if( feederID == FEEDER_TREMHUMANARMOURYSELL )
- {
- if( index >= 0 && index < uiInfo.tremHumanArmourySellCount )
- return uiInfo.tremHumanArmourySellList[ index ].text;
- }
- else if( feederID == FEEDER_TREMALIENUPGRADE )
- {
- if( index >= 0 && index < uiInfo.tremAlienUpgradeCount )
- return uiInfo.tremAlienUpgradeList[ index ].text;
- }
- else if( feederID == FEEDER_TREMALIENBUILD )
- {
- if( index >= 0 && index < uiInfo.tremAlienBuildCount )
- return uiInfo.tremAlienBuildList[ index ].text;
- }
- else if( feederID == FEEDER_TREMHUMANBUILD )
- {
- if( index >= 0 && index < uiInfo.tremHumanBuildCount )
- return uiInfo.tremHumanBuildList[ index ].text;
- }
-//TA: tremulous menus
-
- return "";
+ else if (feederID == FEEDER_TREMVOICECMD)
+ uiInfo.voiceCmdIndex = index;
}
+static int UI_FeederInitialise(int feederID)
+{
+ if (feederID == FEEDER_RESOLUTIONS)
+ {
+ int i;
+ int w = trap_Cvar_VariableValue("r_width");
+ int h = trap_Cvar_VariableValue("r_height");
-static qhandle_t UI_FeederItemImage(float feederID, int index) {
- if (feederID == FEEDER_HEADS) {
- int actual;
- UI_SelectedHead(index, &actual);
- index = actual;
- if (index >= 0 && index < uiInfo.characterCount) {
- if (uiInfo.characterList[index].headImage == -1) {
- uiInfo.characterList[index].headImage = trap_R_RegisterShaderNoMip(uiInfo.characterList[index].imageName);
- }
- return uiInfo.characterList[index].headImage;
- }
- } else if (feederID == FEEDER_Q3HEADS) {
- if (index >= 0 && index < uiInfo.q3HeadCount) {
- return uiInfo.q3HeadIcons[index];
- }
- } else if (feederID == FEEDER_ALLMAPS || feederID == FEEDER_MAPS) {
- int actual;
- UI_SelectedMap(index, &actual);
- index = actual;
- if (index >= 0 && index < uiInfo.mapCount) {
- if (uiInfo.mapList[index].levelShot == -1) {
- uiInfo.mapList[index].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[index].imageName);
- }
- return uiInfo.mapList[index].levelShot;
- }
- }
- return 0;
-}
+ for (i = 0; i < uiInfo.numResolutions; i++)
+ {
+ if (w == uiInfo.resolutions[i].w && h == uiInfo.resolutions[i].h)
+ return i;
+ }
-static void UI_FeederSelection(float feederID, int index) {
- static char info[MAX_STRING_CHARS];
- if (feederID == FEEDER_HEADS) {
- int actual;
- UI_SelectedHead(index, &actual);
- index = actual;
- if (index >= 0 && index < uiInfo.characterCount) {
- trap_Cvar_Set( "team_model", va("%s", uiInfo.characterList[index].base));
- trap_Cvar_Set( "team_headmodel", va("*%s", uiInfo.characterList[index].name));
- updateModel = qtrue;
- }
- } else if (feederID == FEEDER_Q3HEADS) {
- if (index >= 0 && index < uiInfo.q3HeadCount) {
- trap_Cvar_Set( "model", uiInfo.q3HeadNames[index]);
- trap_Cvar_Set( "headmodel", uiInfo.q3HeadNames[index]);
- updateModel = qtrue;
- }
- } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
- int actual, map;
- map = (feederID == FEEDER_ALLMAPS) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (uiInfo.mapList[map].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.mapList[map].cinematic);
- uiInfo.mapList[map].cinematic = -1;
- }
- UI_SelectedMap(index, &actual);
- trap_Cvar_Set("ui_mapIndex", va("%d", index));
- ui_mapIndex.integer = index;
-
- if (feederID == FEEDER_MAPS) {
- ui_currentMap.integer = actual;
- trap_Cvar_Set("ui_currentMap", va("%d", actual));
- uiInfo.mapList[ui_currentMap.integer].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[ui_currentMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
- trap_Cvar_Set("ui_opponentModel", uiInfo.mapList[ui_currentMap.integer].opponentName);
- updateOpponentModel = qtrue;
- } else {
- ui_currentNetMap.integer = actual;
- trap_Cvar_Set("ui_currentNetMap", va("%d", actual));
- uiInfo.mapList[ui_currentNetMap.integer].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
+ return uiInfo.numResolutions;
}
- } else if (feederID == FEEDER_SERVERS) {
- const char *mapName = NULL;
- uiInfo.serverStatus.currentServer = index;
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
- uiInfo.serverStatus.currentServerPreview = trap_R_RegisterShaderNoMip(va("levelshots/%s", Info_ValueForKey(info, "mapname")));
- if (uiInfo.serverStatus.currentServerCinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
- uiInfo.serverStatus.currentServerCinematic = -1;
- }
- mapName = Info_ValueForKey(info, "mapname");
- if (mapName && *mapName) {
- uiInfo.serverStatus.currentServerCinematic = trap_CIN_PlayCinematic(va("%s.roq", mapName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
+ return 0;
+}
+
+static void UI_Pause(qboolean b)
+{
+ if (b)
+ {
+ // pause the game and set the ui keycatcher
+ trap_Cvar_Set("cl_paused", "1");
+ trap_Key_SetCatcher(KEYCATCH_UI);
}
- } else if (feederID == FEEDER_SERVERSTATUS) {
- //
- } else if (feederID == FEEDER_FINDPLAYER) {
- uiInfo.currentFoundPlayerServer = index;
- //
- if ( index < uiInfo.numFoundPlayerServers-1) {
- // build a new server status for this server
- Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
- Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
- UI_BuildServerStatus(qtrue);
- }
- } else if (feederID == FEEDER_PLAYER_LIST) {
- uiInfo.playerIndex = index;
- } else if (feederID == FEEDER_TEAM_LIST) {
- uiInfo.teamIndex = index;
- } else if (feederID == FEEDER_IGNORE_LIST) {
- uiInfo.ignoreIndex = index;
- } else if (feederID == FEEDER_MODS) {
- uiInfo.modIndex = index;
- } else if (feederID == FEEDER_CINEMATICS) {
- uiInfo.movieIndex = index;
- if (uiInfo.previewMovie >= 0) {
- trap_CIN_StopCinematic(uiInfo.previewMovie);
+ else
+ {
+ // unpause the game and clear the ui keycatcher
+ trap_Key_SetCatcher(trap_Key_GetCatcher() & ~KEYCATCH_UI);
+ trap_Key_ClearStates();
+ trap_Cvar_Set("cl_paused", "0");
}
- uiInfo.previewMovie = -1;
- } else if (feederID == FEEDER_DEMOS) {
- uiInfo.demoIndex = index;
- }
-
-//TA: tremulous menus
- else if( feederID == FEEDER_TREMTEAMS )
- uiInfo.tremTeamIndex = index;
- else if( feederID == FEEDER_TREMHUMANITEMS )
- uiInfo.tremHumanItemIndex = index;
- else if( feederID == FEEDER_TREMALIENCLASSES )
- uiInfo.tremAlienClassIndex = index;
- else if( feederID == FEEDER_TREMHUMANARMOURYBUY )
- uiInfo.tremHumanArmouryBuyIndex = index;
- else if( feederID == FEEDER_TREMHUMANARMOURYSELL )
- uiInfo.tremHumanArmourySellIndex = index;
- else if( feederID == FEEDER_TREMALIENUPGRADE )
- uiInfo.tremAlienUpgradeIndex = index;
- else if( feederID == FEEDER_TREMALIENBUILD )
- uiInfo.tremAlienBuildIndex = index;
- else if( feederID == FEEDER_TREMHUMANBUILD )
- uiInfo.tremHumanBuildIndex = index;
-//TA: tremulous menus
}
-static void UI_Pause(qboolean b) {
- if (b) {
- // pause the game and set the ui keycatcher
- trap_Cvar_Set( "cl_paused", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- } else {
- // unpause the game and clear the ui keycatcher
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- }
+static int UI_PlayCinematic(const char *name, float x, float y, float w, float h)
+{
+ return trap_CIN_PlayCinematic(name, x, y, w, h, (CIN_loop | CIN_silent));
}
-static int UI_PlayCinematic(const char *name, float x, float y, float w, float h) {
- return trap_CIN_PlayCinematic(name, x, y, w, h, (CIN_loop | CIN_silent));
-}
+static void UI_StopCinematic(int handle)
+{
+ if (handle >= 0)
+ trap_CIN_StopCinematic(handle);
+ else
+ {
+ handle = abs(handle);
-static void UI_StopCinematic(int handle) {
- if (handle >= 0) {
- trap_CIN_StopCinematic(handle);
- } else {
- handle = abs(handle);
- if (handle == UI_MAPCINEMATIC) {
- if (uiInfo.mapList[ui_currentMap.integer].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.mapList[ui_currentMap.integer].cinematic);
- uiInfo.mapList[ui_currentMap.integer].cinematic = -1;
- }
- } else if (handle == UI_NETMAPCINEMATIC) {
- if (uiInfo.serverStatus.currentServerCinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
- uiInfo.serverStatus.currentServerCinematic = -1;
- }
- } else if (handle == UI_CLANCINEMATIC) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (i >= 0 && i < uiInfo.teamCount) {
- if (uiInfo.teamList[i].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
- uiInfo.teamList[i].cinematic = -1;
+ if (handle == UI_NETMAPCINEMATIC)
+ {
+ if (uiInfo.serverStatus.currentServerCinematic >= 0)
+ {
+ trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
+ uiInfo.serverStatus.currentServerCinematic = -1;
+ }
}
- }
}
- }
}
-static void UI_DrawCinematic(int handle, float x, float y, float w, float h) {
- trap_CIN_SetExtents(handle, x, y, w, h);
- trap_CIN_DrawCinematic(handle);
+static void UI_DrawCinematic(int handle, float x, float y, float w, float h)
+{
+ trap_CIN_SetExtents(handle, x, y, w, h);
+ trap_CIN_DrawCinematic(handle);
}
-static void UI_RunCinematicFrame(int handle) {
- trap_CIN_RunCinematic(handle);
-}
+static void UI_RunCinematicFrame(int handle) { trap_CIN_RunCinematic(handle); }
+static float UI_GetValue(int ownerDraw) { return 0.0f; }
/*
=================
-UI_Init
+UI_ParseResolutions
=================
*/
-void _UI_Init( qboolean inGameLoad ) {
- const char *menuSet;
- int start;
-
- BG_InitClassOverrides( );
- BG_InitAllowedGameElements( );
-
- //uiInfo.inGameLoad = inGameLoad;
-
- UI_RegisterCvars();
- UI_InitMemory();
-
- // cache redundant calulations
- trap_GetGlconfig( &uiInfo.uiDC.glconfig );
-
- // for 640x480 virtualized screen
- uiInfo.uiDC.yscale = uiInfo.uiDC.glconfig.vidHeight * (1.0/480.0);
- uiInfo.uiDC.xscale = uiInfo.uiDC.glconfig.vidWidth * (1.0/640.0);
- if ( uiInfo.uiDC.glconfig.vidWidth * 480 > uiInfo.uiDC.glconfig.vidHeight * 640 ) {
- // wide screen
- uiInfo.uiDC.bias = 0.5 * ( uiInfo.uiDC.glconfig.vidWidth - ( uiInfo.uiDC.glconfig.vidHeight * (640.0/480.0) ) );
- }
- else {
- // no wide screen
- uiInfo.uiDC.bias = 0;
- }
-
-
- //UI_Load();
- uiInfo.uiDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
- uiInfo.uiDC.setColor = &UI_SetColor;
- uiInfo.uiDC.drawHandlePic = &UI_DrawHandlePic;
- uiInfo.uiDC.drawStretchPic = &trap_R_DrawStretchPic;
- uiInfo.uiDC.drawText = &Text_Paint;
- uiInfo.uiDC.textWidth = &Text_Width;
- uiInfo.uiDC.textHeight = &Text_Height;
- uiInfo.uiDC.registerModel = &trap_R_RegisterModel;
- uiInfo.uiDC.modelBounds = &trap_R_ModelBounds;
- uiInfo.uiDC.fillRect = &UI_FillRect;
- uiInfo.uiDC.drawRect = &_UI_DrawRect;
- uiInfo.uiDC.drawSides = &_UI_DrawSides;
- uiInfo.uiDC.drawTopBottom = &_UI_DrawTopBottom;
- uiInfo.uiDC.clearScene = &trap_R_ClearScene;
- uiInfo.uiDC.drawSides = &_UI_DrawSides;
- uiInfo.uiDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
- uiInfo.uiDC.renderScene = &trap_R_RenderScene;
- uiInfo.uiDC.registerFont = &trap_R_RegisterFont;
- uiInfo.uiDC.ownerDrawItem = &UI_OwnerDraw;
- uiInfo.uiDC.getValue = &UI_GetValue;
- uiInfo.uiDC.ownerDrawVisible = &UI_OwnerDrawVisible;
- uiInfo.uiDC.runScript = &UI_RunMenuScript;
- uiInfo.uiDC.getTeamColor = &UI_GetTeamColor;
- uiInfo.uiDC.setCVar = trap_Cvar_Set;
- uiInfo.uiDC.getCVarString = trap_Cvar_VariableStringBuffer;
- uiInfo.uiDC.getCVarValue = trap_Cvar_VariableValue;
- uiInfo.uiDC.drawTextWithCursor = &Text_PaintWithCursor;
- uiInfo.uiDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
- uiInfo.uiDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
- uiInfo.uiDC.startLocalSound = &trap_S_StartLocalSound;
- uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey;
- uiInfo.uiDC.feederCount = &UI_FeederCount;
- uiInfo.uiDC.feederItemImage = &UI_FeederItemImage;
- uiInfo.uiDC.feederItemText = &UI_FeederItemText;
- uiInfo.uiDC.feederSelection = &UI_FeederSelection;
- uiInfo.uiDC.setBinding = &trap_Key_SetBinding;
- uiInfo.uiDC.getBindingBuf = &trap_Key_GetBindingBuf;
- uiInfo.uiDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
- uiInfo.uiDC.executeText = &trap_Cmd_ExecuteText;
- uiInfo.uiDC.Error = &Com_Error;
- uiInfo.uiDC.Print = &Com_Printf;
- uiInfo.uiDC.Pause = &UI_Pause;
- uiInfo.uiDC.ownerDrawWidth = &UI_OwnerDrawWidth;
- uiInfo.uiDC.registerSound = &trap_S_RegisterSound;
- uiInfo.uiDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
- uiInfo.uiDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
- uiInfo.uiDC.playCinematic = &UI_PlayCinematic;
- uiInfo.uiDC.stopCinematic = &UI_StopCinematic;
- uiInfo.uiDC.drawCinematic = &UI_DrawCinematic;
- uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame;
-
- Init_Display(&uiInfo.uiDC);
-
- String_Init();
-
- uiInfo.uiDC.whiteShader = trap_R_RegisterShaderNoMip( "white" );
-
- AssetCache();
-
- start = trap_Milliseconds();
-
- uiInfo.teamCount = 0;
- uiInfo.characterCount = 0;
- uiInfo.aliasCount = 0;
-
-/* UI_ParseTeamInfo("teaminfo.txt");
- UI_LoadTeams();
- UI_ParseGameInfo("gameinfo.txt");*/
-
- menuSet = UI_Cvar_VariableString("ui_menuFiles");
- if (menuSet == NULL || menuSet[0] == '\0') {
- menuSet = "ui/menus.txt";
- }
-
-#if 0
- if (uiInfo.inGameLoad) {
- UI_LoadMenus("ui/ingame.txt", qtrue);
- } else { // bk010222: left this: UI_LoadMenus(menuSet, qtrue);
- }
-#else
- UI_LoadMenus(menuSet, qtrue);
- UI_LoadMenus("ui/ingame.txt", qfalse);
- UI_LoadMenus("ui/tremulous.txt", qfalse);
-
- UI_LoadInfoPanes( "ui/infopanes.def" );
+void UI_ParseResolutions(void)
+{
+ char buf[MAX_STRING_CHARS];
+ char w[16], h[16];
+ char *p;
+ const char *out;
+ char *s = NULL;
- if( uiInfo.uiDC.debug )
- {
- int i, j;
+ trap_Cvar_VariableStringBuffer("r_availableModes", buf, sizeof(buf));
+ p = buf;
+ uiInfo.numResolutions = 0;
- for( i = 0; i < uiInfo.tremInfoPaneCount; i++ )
+ while (uiInfo.numResolutions < MAX_RESOLUTIONS && String_Parse(&p, &out))
{
- Com_Printf( "name: %s\n", uiInfo.tremInfoPanes[ i ].name );
+ Q_strncpyz(w, out, sizeof(w));
+ s = strchr(w, 'x');
+ if (!s)
+ return;
- Com_Printf( "text: %s\n", uiInfo.tremInfoPanes[ i ].text );
+ *s++ = '\0';
+ Q_strncpyz(h, s, sizeof(h));
- for( j = 0; j < uiInfo.tremInfoPanes[ i ].numGraphics; j++ )
- Com_Printf( "graphic %d: %d %d %d %d\n", j, uiInfo.tremInfoPanes[ i ].graphics[ j ].side,
- uiInfo.tremInfoPanes[ i ].graphics[ j ].offset,
- uiInfo.tremInfoPanes[ i ].graphics[ j ].width,
- uiInfo.tremInfoPanes[ i ].graphics[ j ].height );
+ uiInfo.resolutions[uiInfo.numResolutions].w = atoi(w);
+ uiInfo.resolutions[uiInfo.numResolutions].h = atoi(h);
+ uiInfo.numResolutions++;
}
- }
-#endif
+}
- Menus_CloseAll();
+/*
+=================
+UI_Init
+=================
+*/
+void UI_Init(qboolean inGameLoad)
+{
+ BG_InitClassConfigs();
+ BG_InitAllowedGameElements();
- trap_LAN_LoadCachedServers();
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
+ uiInfo.inGameLoad = inGameLoad;
- // sets defaults for ui temp cvars
- uiInfo.effectsColor = gamecodetoui[(int)trap_Cvar_VariableValue("color1")-1];
- uiInfo.currentCrosshair = (int)trap_Cvar_VariableValue("cg_drawCrosshair");
- trap_Cvar_Set("ui_mousePitch", (trap_Cvar_VariableValue("m_pitch") >= 0) ? "0" : "1");
+ UI_RegisterCvars();
+ UI_InitMemory();
+ BG_InitMemory(); // FIXIT-M: Merge with UI_InitMemory or something
- uiInfo.serverStatus.currentServerCinematic = -1;
- uiInfo.previewMovie = -1;
+ // cache redundant calulations
+ trap_GetGlconfig(&uiInfo.uiDC.glconfig);
- if (trap_Cvar_VariableValue("ui_TeamArenaFirstRun") == 0) {
- trap_Cvar_Set("s_volume", "0.8");
- trap_Cvar_Set("s_musicvolume", "0.5");
- trap_Cvar_Set("ui_TeamArenaFirstRun", "1");
- }
+ // for 640x480 virtualized screen
+ uiInfo.uiDC.yscale = uiInfo.uiDC.glconfig.vidHeight * (1.0f / 480.0f);
+ uiInfo.uiDC.xscale = uiInfo.uiDC.glconfig.vidWidth * (1.0f / 640.0f);
- trap_Cvar_Register(NULL, "debug_protocol", "", 0 );
+ // wide screen
+ uiInfo.uiDC.aspectScale = ((640.0f * uiInfo.uiDC.glconfig.vidHeight) / (480.0f * uiInfo.uiDC.glconfig.vidWidth));
+
+ uiInfo.uiDC.smallFontScale = trap_Cvar_VariableValue("ui_smallFont");
+ uiInfo.uiDC.bigFontScale = trap_Cvar_VariableValue("ui_bigFont");
+
+ uiInfo.uiDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
+ uiInfo.uiDC.setColor = &UI_SetColor;
+ uiInfo.uiDC.drawHandlePic = &UI_DrawHandlePic;
+ uiInfo.uiDC.drawStretchPic = &trap_R_DrawStretchPic;
+ uiInfo.uiDC.registerModel = &trap_R_RegisterModel;
+ uiInfo.uiDC.modelBounds = &trap_R_ModelBounds;
+ uiInfo.uiDC.fillRect = &UI_FillRect;
+ uiInfo.uiDC.drawRect = &UI_DrawRect;
+ uiInfo.uiDC.drawSides = &UI_DrawSides;
+ uiInfo.uiDC.drawTopBottom = &UI_DrawTopBottom;
+ uiInfo.uiDC.clearScene = &trap_R_ClearScene;
+ uiInfo.uiDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
+ uiInfo.uiDC.renderScene = &trap_R_RenderScene;
+ uiInfo.uiDC.registerFont = &trap_R_RegisterFont;
+ uiInfo.uiDC.ownerDrawItem = &UI_OwnerDraw;
+ uiInfo.uiDC.getValue = &UI_GetValue;
+ uiInfo.uiDC.ownerDrawVisible = &UI_OwnerDrawVisible;
+ uiInfo.uiDC.runScript = &UI_RunMenuScript;
+ uiInfo.uiDC.setCVar = trap_Cvar_Set;
+ uiInfo.uiDC.getCVarString = trap_Cvar_VariableStringBuffer;
+ uiInfo.uiDC.getCVarValue = trap_Cvar_VariableValue;
+ uiInfo.uiDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
+ uiInfo.uiDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
+ uiInfo.uiDC.startLocalSound = &trap_S_StartLocalSound;
+ uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey;
+ uiInfo.uiDC.feederCount = &UI_FeederCount;
+ uiInfo.uiDC.feederItemImage = &UI_FeederItemImage;
+ uiInfo.uiDC.feederItemText = &UI_FeederItemText;
+ uiInfo.uiDC.feederSelection = &UI_FeederSelection;
+ uiInfo.uiDC.feederInitialise = &UI_FeederInitialise;
+ uiInfo.uiDC.setBinding = &trap_Key_SetBinding;
+ uiInfo.uiDC.getBindingBuf = &trap_Key_GetBindingBuf;
+ uiInfo.uiDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
+ uiInfo.uiDC.executeText = &trap_Cmd_ExecuteText;
+ uiInfo.uiDC.Error = &Com_Error;
+ uiInfo.uiDC.Print = &Com_Printf;
+ uiInfo.uiDC.Pause = &UI_Pause;
+ uiInfo.uiDC.ownerDrawWidth = &UI_OwnerDrawWidth;
+ uiInfo.uiDC.ownerDrawText = &UI_OwnerDrawText;
+ uiInfo.uiDC.registerSound = &trap_S_RegisterSound;
+ uiInfo.uiDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
+ uiInfo.uiDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
+ uiInfo.uiDC.playCinematic = &UI_PlayCinematic;
+ uiInfo.uiDC.stopCinematic = &UI_StopCinematic;
+ uiInfo.uiDC.drawCinematic = &UI_DrawCinematic;
+ uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame;
+
+ Init_Display(&uiInfo.uiDC);
+
+ String_Init();
+
+ uiInfo.uiDC.whiteShader = trap_R_RegisterShaderNoMip("white");
+
+ AssetCache();
+
+ UI_LoadMenus("ui/menus.txt", qtrue);
+ UI_LoadMenus("ui/ingame.txt", qfalse);
+ UI_LoadMenus("ui/tremulous.txt", qfalse);
+ UI_LoadHelp("ui/help.txt");
+
+ Menus_CloseAll();
+
+ trap_LAN_LoadCachedServers();
+
+ // sets defaults for ui temp cvars
+ trap_Cvar_Set("ui_mousePitch", (trap_Cvar_VariableValue("m_pitch") >= 0) ? "0" : "1");
+
+ uiInfo.serverStatus.currentServerCinematic = -1;
+ uiInfo.previewMovie = -1;
- trap_Cvar_Set("ui_actualNetGameType", va("%d", ui_netGameType.integer));
+ UI_ParseResolutions();
+ uiInfo.voices = BG_VoiceInit();
}
-
/*
=================
UI_KeyEvent
=================
*/
-void _UI_KeyEvent( int key, qboolean down ) {
+void UI_KeyEvent(int key, qboolean down)
+{
+ if (Menu_Count() > 0)
+ {
+ menuDef_t *menu = Menu_GetFocused();
- if (Menu_Count() > 0) {
- menuDef_t *menu = Menu_GetFocused();
- if (menu) {
- if (key == K_ESCAPE && down && !Menus_AnyFullScreenVisible()) {
- Menus_CloseAll();
- } else {
- Menu_HandleKey(menu, key, down );
- }
- } else {
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
+ if (menu)
+ {
+ if (key == K_ESCAPE && down && !Menus_AnyFullScreenVisible())
+ Menus_CloseAll();
+ else
+ Menu_HandleKey(menu, key, down);
+ }
+ else
+ {
+ trap_Key_SetCatcher(trap_Key_GetCatcher() & ~KEYCATCH_UI);
+ trap_Key_ClearStates();
+ trap_Cvar_Set("cl_paused", "0");
+ }
}
- }
-
- //if ((s > 0) && (s != menu_null_sound)) {
- // trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );
- //}
}
/*
@@ -5712,27 +4330,25 @@ void _UI_KeyEvent( int key, qboolean down ) {
UI_MouseEvent
=================
*/
-void _UI_MouseEvent( int dx, int dy )
+void UI_MouseEvent(int dx, int dy)
{
- // update mouse screen position
- uiInfo.uiDC.cursorx += dx;
- if (uiInfo.uiDC.cursorx < 0)
- uiInfo.uiDC.cursorx = 0;
- else if (uiInfo.uiDC.cursorx > SCREEN_WIDTH)
- uiInfo.uiDC.cursorx = SCREEN_WIDTH;
-
- uiInfo.uiDC.cursory += dy;
- if (uiInfo.uiDC.cursory < 0)
- uiInfo.uiDC.cursory = 0;
- else if (uiInfo.uiDC.cursory > SCREEN_HEIGHT)
- uiInfo.uiDC.cursory = SCREEN_HEIGHT;
-
- if (Menu_Count() > 0) {
- //menuDef_t *menu = Menu_GetFocused();
- //Menu_HandleMouseMove(menu, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
- Display_MouseMove(NULL, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
- }
+ // update mouse screen position
+ uiInfo.uiDC.cursorx += (dx * uiInfo.uiDC.aspectScale);
+
+ if (uiInfo.uiDC.cursorx < 0)
+ uiInfo.uiDC.cursorx = 0;
+ else if (uiInfo.uiDC.cursorx > SCREEN_WIDTH)
+ uiInfo.uiDC.cursorx = SCREEN_WIDTH;
+
+ uiInfo.uiDC.cursory += dy;
+
+ if (uiInfo.uiDC.cursory < 0)
+ uiInfo.uiDC.cursory = 0;
+ else if (uiInfo.uiDC.cursory > SCREEN_HEIGHT)
+ uiInfo.uiDC.cursory = SCREEN_HEIGHT;
+ if (Menu_Count() > 0)
+ Display_MouseMove(NULL, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
}
/*
@@ -5740,791 +4356,523 @@ void _UI_MouseEvent( int dx, int dy )
UI_MousePosition
=================
*/
-int _UI_MousePosition( void )
-{
- return (int)rint( uiInfo.uiDC.cursorx ) |
- (int)rint( uiInfo.uiDC.cursory ) << 16;
-}
+int UI_MousePosition(void) { return (int)rint(uiInfo.uiDC.cursorx) | (int)rint(uiInfo.uiDC.cursory) << 16; }
/*
=================
UI_SetMousePosition
=================
*/
-void _UI_SetMousePosition( int x, int y )
+void UI_SetMousePosition(int x, int y)
{
- uiInfo.uiDC.cursorx = x;
- uiInfo.uiDC.cursory = y;
+ uiInfo.uiDC.cursorx = x;
+ uiInfo.uiDC.cursory = y;
- if( Menu_Count( ) > 0 )
- Display_MouseMove( NULL, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory );
+ if (Menu_Count() > 0)
+ Display_MouseMove(NULL, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
}
-void UI_LoadNonIngame( void ) {
- const char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
- if (menuSet == NULL || menuSet[0] == '\0') {
- menuSet = "ui/menus.txt";
- }
- UI_LoadMenus(menuSet, qfalse);
- uiInfo.inGameLoad = qfalse;
-}
+void UI_SetActiveMenu(uiMenuCommand_t menu)
+{
+ char buf[256];
-void _UI_SetActiveMenu( uiMenuCommand_t menu ) {
- char buf[256];
-
- // this should be the ONLY way the menu system is brought up
- // enusure minumum menu data is cached
- if (Menu_Count() > 0) {
- vec3_t v;
- v[0] = v[1] = v[2] = 0;
- switch ( menu ) {
- case UIMENU_NONE:
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
-
- return;
- case UIMENU_MAIN:
- //trap_Cvar_Set( "sv_killserver", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- //trap_S_StartLocalSound( trap_S_RegisterSound("sound/misc/menu_background.wav", qfalse) , CHAN_LOCAL_SOUND );
- //trap_S_StartBackgroundTrack("sound/misc/menu_background.wav", NULL);
- if (uiInfo.inGameLoad) {
- UI_LoadNonIngame();
- }
- Menus_CloseAll();
- Menus_ActivateByName("main");
- trap_Cvar_Set( "ui_loading", "0" );
- trap_Cvar_VariableStringBuffer("com_errorMessage", buf, sizeof(buf));
- if (strlen(buf)) {
- if (!ui_singlePlayerActive.integer) {
- if( trap_Cvar_VariableValue( "com_errorCode" ) == ERR_SERVERDISCONNECT )
- Menus_ActivateByName("drop_popmenu");
- else
- Menus_ActivateByName("error_popmenu");
- } else {
- trap_Cvar_Set("com_errorMessage", "");
- }
- }
- return;
- case UIMENU_TEAM:
- trap_Key_SetCatcher( KEYCATCH_UI );
- Menus_ActivateByName("team");
- return;
- case UIMENU_POSTGAME:
- //trap_Cvar_Set( "sv_killserver", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- if (uiInfo.inGameLoad) {
- UI_LoadNonIngame();
- }
- Menus_CloseAll();
- Menus_ActivateByName("endofgame");
- return;
- case UIMENU_INGAME:
- trap_Cvar_Set( "cl_paused", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- UI_BuildPlayerList();
- Menus_CloseAll();
- Menus_ActivateByName("ingame");
- return;
- }
- }
-}
+ // this should be the ONLY way the menu system is brought up
+ // enusure minumum menu data is cached
-qboolean _UI_IsFullscreen( void ) {
- return Menus_AnyFullScreenVisible();
-}
+ if (Menu_Count() > 0)
+ {
+ vec3_t v;
+ v[0] = v[1] = v[2] = 0;
+ switch (menu)
+ {
+ case UIMENU_NONE:
+ trap_Key_SetCatcher(trap_Key_GetCatcher() & ~KEYCATCH_UI);
+ trap_Key_ClearStates();
+ trap_Cvar_Set("cl_paused", "0");
+ Menus_CloseAll();
+ return;
+
+ case UIMENU_MAIN:
+ trap_Cvar_Set("sv_killserver", "1");
+ trap_Key_SetCatcher(KEYCATCH_UI);
+ Menus_CloseAll();
+ Menus_ActivateByName("main");
+ trap_Cvar_VariableStringBuffer("com_errorMessage", buf, sizeof(buf));
+
+ if (strlen(buf))
+ {
+ if (trap_Cvar_VariableValue("com_errorCode") == ERR_SERVERDISCONNECT)
+ Menus_ActivateByName("drop_popmenu");
+ else
+ Menus_ActivateByName("error_popmenu");
+ }
+ return;
+
+ case UIMENU_INGAME:
+ trap_Cvar_Set("cl_paused", "1");
+ trap_Key_SetCatcher(KEYCATCH_UI);
+ UI_BuildPlayerList();
+ Menus_CloseAll();
+ Menus_ActivateByName("ingame");
+ return;
+ }
+ }
+}
+qboolean UI_IsFullscreen(void) { return Menus_AnyFullScreenVisible(); }
-static connstate_t lastConnState;
-static char lastLoadingText[MAX_INFO_VALUE];
+static connstate_t lastConnState;
+static char lastLoadingText[MAX_INFO_VALUE];
-static void UI_ReadableSize ( char *buf, int bufsize, int value )
+static void UI_ReadableSize(char *buf, int bufsize, int value)
{
- if (value > 1024*1024*1024 ) { // gigs
- Com_sprintf( buf, bufsize, "%d", value / (1024*1024*1024) );
- Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d GB",
- (value % (1024*1024*1024))*100 / (1024*1024*1024) );
- } else if (value > 1024*1024 ) { // megs
- Com_sprintf( buf, bufsize, "%d", value / (1024*1024) );
- Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d MB",
- (value % (1024*1024))*100 / (1024*1024) );
- } else if (value > 1024 ) { // kilos
- Com_sprintf( buf, bufsize, "%d KB", value / 1024 );
- } else { // bytes
- Com_sprintf( buf, bufsize, "%d bytes", value );
- }
+ if (value > 1024 * 1024 * 1024)
+ { // gigs
+ Com_sprintf(buf, bufsize, "%d", value / (1024 * 1024 * 1024));
+ Com_sprintf(buf + strlen(buf), bufsize - strlen(buf), ".%02d GB",
+ (value % (1024 * 1024 * 1024)) * 100 / (1024 * 1024 * 1024));
+ }
+ else if (value > 1024 * 1024)
+ { // megs
+ Com_sprintf(buf, bufsize, "%d", value / (1024 * 1024));
+ Com_sprintf(
+ buf + strlen(buf), bufsize - strlen(buf), ".%02d MB", (value % (1024 * 1024)) * 100 / (1024 * 1024));
+ }
+ else if (value > 1024)
+ { // kilos
+ Com_sprintf(buf, bufsize, "%d KB", value / 1024);
+ }
+ else
+ { // bytes
+ Com_sprintf(buf, bufsize, "%d bytes", value);
+ }
}
// Assumes time is in msec
-static void UI_PrintTime ( char *buf, int bufsize, int time ) {
- time /= 1000; // change to seconds
-
- if (time > 3600) { // in the hours range
- Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60 );
- } else if (time > 60) { // mins
- Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 );
- } else { // secs
- Com_sprintf( buf, bufsize, "%d sec", time );
- }
-}
-
-void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *text, float adjust) {
- int len = Text_Width(text, scale, 0);
- Text_Paint(x - len / 2, y, scale, color, text, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-}
+static void UI_PrintTime(char *buf, int bufsize, int time)
+{
+ time /= 1000; // change to seconds
-void Text_PaintCenter_AutoWrapped(float x, float y, float xmax, float ystep, float scale, vec4_t color, const char *str, float adjust) {
- int width;
- char *s1,*s2,*s3;
- char c_bcp;
- char buf[1024];
-
- if (!str || str[0]=='\0')
- return;
-
- Q_strncpyz(buf, str, sizeof(buf));
- s1 = s2 = s3 = buf;
-
- while (1) {
- do {
- s3++;
- } while (*s3!=' ' && *s3!='\0');
- c_bcp = *s3;
- *s3 = '\0';
- width = Text_Width(s1, scale, 0);
- *s3 = c_bcp;
- if (width > xmax) {
- if (s1==s2)
- {
- // fuck, don't have a clean cut, we'll overflow
- s2 = s3;
- }
- *s2 = '\0';
- Text_PaintCenter(x, y, scale, color, s1, adjust);
- y += ystep;
- if (c_bcp == '\0')
- {
- // that was the last word
- // we could start a new loop, but that wouldn't be much use
- // even if the word is too long, we would overflow it (see above)
- // so just print it now if needed
- s2++;
- if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3
- Text_PaintCenter(x, y, scale, color, s2, adjust);
- break;
- }
- s2++;
- s1 = s2;
- s3 = s2;
+ if (time > 3600)
+ { // in the hours range
+ Com_sprintf(buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60);
+ }
+ else if (time > 60)
+ { // mins
+ Com_sprintf(buf, bufsize, "%d min %d sec", time / 60, time % 60);
}
else
- {
- s2 = s3;
- if (c_bcp == '\0') // we reached the end
- {
- Text_PaintCenter(x, y, scale, color, s1, adjust);
- break;
- }
+ { // secs
+ Com_sprintf(buf, bufsize, "%d sec", time);
}
- }
}
+// FIXME: move to ui_shared.c?
+void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *text, float adjust)
+{
+ int len = UI_Text_Width(text, scale);
+ UI_Text_Paint(x - len / 2, y, scale, color, text, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
+}
-static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, float yStart, float scale ) {
- static char dlText[] = "Downloading:";
- static char etaText[] = "Estimated time left:";
- static char xferText[] = "Transfer rate:";
+void Text_PaintCenter_AutoWrapped(
+ float x, float y, float xmax, float ystep, float scale, vec4_t color, const char *str, float adjust)
+{
+ int width;
+ char *s1, *s2, *s3;
+ char c_bcp;
+ char buf[1024];
- int downloadSize, downloadCount, downloadTime;
- char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];
- int xferRate;
- int leftWidth;
- const char *s;
+ if (!str || str[0] == '\0')
+ return;
+
+ Q_strncpyz(buf, str, sizeof(buf));
- downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" );
- downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" );
- downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" );
+ s1 = s2 = s3 = buf;
- leftWidth = 320;
+ while (1)
+ {
+ do
+ s3++;
+ while (*s3 != ' ' && *s3 != '\0');
- UI_SetColor(colorWhite);
- Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, dlText, 0);
- Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, etaText, 0);
- Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, xferText, 0);
+ c_bcp = *s3;
- if (downloadSize > 0) {
- s = va( "%s (%d%%)", downloadName, downloadCount * 100 / downloadSize );
- } else {
- s = downloadName;
- }
+ *s3 = '\0';
- Text_PaintCenter(centerPoint, yStart+136, scale, colorWhite, s, 0);
+ width = UI_Text_Width(s1, scale);
- UI_ReadableSize( dlSizeBuf, sizeof dlSizeBuf, downloadCount );
- UI_ReadableSize( totalSizeBuf, sizeof totalSizeBuf, downloadSize );
+ *s3 = c_bcp;
- if (downloadCount < 4096 || !downloadTime) {
- Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
- } else {
- if ((uiInfo.uiDC.realTime - downloadTime) / 1000) {
- xferRate = downloadCount / ((uiInfo.uiDC.realTime - downloadTime) / 1000);
- } else {
- xferRate = 0;
+ if (width > xmax)
+ {
+ if (s1 == s2)
+ {
+ // fuck, don't have a clean cut, we'll overflow
+ s2 = s3;
+ }
+
+ *s2 = '\0';
+ Text_PaintCenter(x, y, scale, color, s1, adjust);
+ y += ystep;
+
+ if (c_bcp == '\0')
+ {
+ // that was the last word
+ // we could start a new loop, but that wouldn't be much use
+ // even if the word is too long, we would overflow it (see above)
+ // so just print it now if needed
+ s2++;
+
+ if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3
+ Text_PaintCenter(x, y, scale, color, s2, adjust);
+
+ break;
+ }
+
+ s2++;
+ s1 = s2;
+ s3 = s2;
+ }
+ else
+ {
+ s2 = s3;
+
+ if (c_bcp == '\0') // we reached the end
+ {
+ Text_PaintCenter(x, y, scale, color, s1, adjust);
+ break;
+ }
+ }
}
- UI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate );
+}
- // Extrapolate estimated completion time
- if (downloadSize && xferRate) {
- int n = downloadSize / xferRate; // estimated time for entire d/l in secs
+static void UI_DisplayDownloadInfo(const char *downloadName, float centerPoint, float yStart, float scale)
+{
+ static char dlText[] = "Downloading:";
+ static char etaText[] = "Estimated time left:";
+ static char xferText[] = "Transfer rate:";
- // We do it in K (/1024) because we'd overflow around 4MB
- UI_PrintTime ( dlTimeBuf, sizeof dlTimeBuf,
- (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000);
+ int downloadSize, downloadCount, downloadTime;
+ char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];
+ int xferRate;
+ int leftWidth;
+ const char *s;
- Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, dlTimeBuf, 0);
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
- } else {
- Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
- if (downloadSize) {
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
- } else {
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s copied)", dlSizeBuf), 0);
- }
+ downloadSize = trap_Cvar_VariableValue("cl_downloadSize");
+ downloadCount = trap_Cvar_VariableValue("cl_downloadCount");
+ downloadTime = trap_Cvar_VariableValue("cl_downloadTime");
+
+ leftWidth = 320;
+
+ UI_SetColor(colorWhite);
+ Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, dlText, 0);
+ Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, etaText, 0);
+ Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, xferText, 0);
+
+ if (downloadSize > 0)
+ s = va("%s (%d%%)", downloadName, (int)((float)downloadCount * 100.0f / downloadSize));
+ else
+ s = downloadName;
+
+ Text_PaintCenter(centerPoint, yStart + 136, scale, colorWhite, s, 0);
+
+ UI_ReadableSize(dlSizeBuf, sizeof dlSizeBuf, downloadCount);
+ UI_ReadableSize(totalSizeBuf, sizeof totalSizeBuf, downloadSize);
+
+ if (downloadCount < 4096 || !downloadTime)
+ {
+ Text_PaintCenter(leftWidth, yStart + 216, scale, colorWhite, "estimating", 0);
+ Text_PaintCenter(
+ leftWidth, yStart + 160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
}
+ else
+ {
+ if ((uiInfo.uiDC.realTime - downloadTime) / 1000)
+ xferRate = downloadCount / ((uiInfo.uiDC.realTime - downloadTime) / 1000);
+ else
+ xferRate = 0;
+
+ UI_ReadableSize(xferRateBuf, sizeof xferRateBuf, xferRate);
+
+ // Extrapolate estimated completion time
+
+ if (downloadSize && xferRate)
+ {
+ int n = downloadSize / xferRate; // estimated time for entire d/l in secs
- if (xferRate) {
- Text_PaintCenter(leftWidth, yStart+272, scale, colorWhite, va("%s/Sec", xferRateBuf), 0);
+ // We do it in K (/1024) because we'd overflow around 4MB
+ UI_PrintTime(
+ dlTimeBuf, sizeof dlTimeBuf, (n - (((downloadCount / 1024) * n) / (downloadSize / 1024))) * 1000);
+
+ Text_PaintCenter(leftWidth, yStart + 216, scale, colorWhite, dlTimeBuf, 0);
+ Text_PaintCenter(
+ leftWidth, yStart + 160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
+ }
+ else
+ {
+ Text_PaintCenter(leftWidth, yStart + 216, scale, colorWhite, "estimating", 0);
+
+ if (downloadSize)
+ Text_PaintCenter(
+ leftWidth, yStart + 160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
+ else
+ Text_PaintCenter(leftWidth, yStart + 160, scale, colorWhite, va("(%s copied)", dlSizeBuf), 0);
+ }
+
+ if (xferRate)
+ Text_PaintCenter(leftWidth, yStart + 272, scale, colorWhite, va("%s/Sec", xferRateBuf), 0);
}
- }
}
/*
========================
UI_DrawConnectScreen
-
-This will also be overlaid on the cgame info screen during loading
-to prevent it from blinking away too rapidly on local or lan games.
========================
*/
-void UI_DrawConnectScreen( qboolean overlay ) {
- char *s;
- uiClientState_t cstate;
- char info[MAX_INFO_VALUE];
- char text[256];
- float centerPoint, yStart, scale;
-
- menuDef_t *menu = Menus_FindByName("Connect");
-
-
- if ( !overlay && menu ) {
- Menu_Paint(menu, qtrue);
- }
-
- if (!overlay) {
- centerPoint = 320;
- yStart = 130;
- scale = 0.5f;
- } else {
- centerPoint = 320;
- yStart = 32;
- scale = 0.6f;
- return;
- }
-
- // see what information we should display
- trap_GetClientState( &cstate );
-
- info[0] = '\0';
- if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) {
- Text_PaintCenter(centerPoint, yStart, scale, colorWhite, va( "Loading %s", Info_ValueForKey( info, "mapname" )), 0);
- }
-
- if (!Q_stricmp(cstate.servername,"localhost")) {
- Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, va("Starting up..."), ITEM_TEXTSTYLE_SHADOWEDMORE);
- } else {
- strcpy(text, va("Connecting to %s", cstate.servername));
- Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite,text , ITEM_TEXTSTYLE_SHADOWEDMORE);
- }
-
-
- // display global MOTD at bottom
- Text_PaintCenter(centerPoint, 600, scale, colorWhite, Info_ValueForKey( cstate.updateInfoString, "motd" ), 0);
- // print any server info (server full, bad version, etc)
- if ( cstate.connState < CA_CONNECTED ) {
- Text_PaintCenter_AutoWrapped(centerPoint, yStart + 176, 630, 20, scale, colorWhite, cstate.messageString, 0);
- }
-
- if ( lastConnState > cstate.connState ) {
- lastLoadingText[0] = '\0';
- }
- lastConnState = cstate.connState;
-
- switch ( cstate.connState ) {
- case CA_CONNECTING:
- s = va("Awaiting connection...%i", cstate.connectPacketCount);
- break;
- case CA_CHALLENGING:
- s = va("Awaiting challenge...%i", cstate.connectPacketCount);
- break;
- case CA_CONNECTED: {
- char downloadName[MAX_INFO_VALUE];
-
- trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) );
- if (*downloadName) {
- UI_DisplayDownloadInfo( downloadName, centerPoint, yStart, scale );
- return;
- }
+void UI_DrawConnectScreen()
+{
+ const char *s;
+ uiClientState_t cstate;
+ char info[MAX_INFO_VALUE];
+ char text[256];
+ float centerPoint = 320, yStart = 130, scale = 0.5f;
+
+ menuDef_t *menu = Menus_FindByName("Connect");
+
+ if ( menu )
+ Menu_Paint(menu, qtrue);
+
+ // see what information we should display
+ trap_GetClientState(&cstate);
+
+ info[0] = '\0';
+
+ if (trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)))
+ Text_PaintCenter(
+ centerPoint, yStart, scale, colorWhite, va("Loading %s", Info_ValueForKey(info, "mapname")), 0);
+
+ if (!Q_stricmp(cstate.servername, "localhost"))
+ Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, "Starting up...", ITEM_TEXTSTYLE_SHADOWEDMORE);
+ else
+ {
+ Com_sprintf(text, sizeof(text), "Connecting to %s", cstate.servername);
+ Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, text, ITEM_TEXTSTYLE_SHADOWEDMORE);
}
- s = "Awaiting gamestate...";
- break;
- case CA_LOADING:
- return;
- case CA_PRIMED:
- return;
- default:
- return;
- }
+ // display global MOTD at bottom
+ Text_PaintCenter(centerPoint, 600, scale, colorWhite, Info_ValueForKey(cstate.updateInfoString, "motd"), 0);
- if (Q_stricmp(cstate.servername,"localhost")) {
- Text_PaintCenter(centerPoint, yStart + 80, scale, colorWhite, s, 0);
- }
+ // print any server info (server full, bad version, etc)
+ if (cstate.connState < CA_CONNECTED)
+ Text_PaintCenter(centerPoint, yStart + 176, scale, colorWhite, cstate.messageString, 0);
- // password required / connection rejected information goes here
-}
+ if (lastConnState > cstate.connState)
+ lastLoadingText[0] = '\0';
+ lastConnState = cstate.connState;
-/*
-================
-cvars
-================
-*/
+ switch (cstate.connState)
+ {
+ case CA_CONNECTING:
+ s = va("Awaiting connection...%i", cstate.connectPacketCount);
+ break;
-typedef struct {
- vmCvar_t *vmCvar;
- char *cvarName;
- char *defaultString;
- int cvarFlags;
-} cvarTable_t;
-
-vmCvar_t ui_ffa_fraglimit;
-vmCvar_t ui_ffa_timelimit;
-
-vmCvar_t ui_tourney_fraglimit;
-vmCvar_t ui_tourney_timelimit;
-
-vmCvar_t ui_team_fraglimit;
-vmCvar_t ui_team_timelimit;
-vmCvar_t ui_team_friendly;
-
-vmCvar_t ui_ctf_capturelimit;
-vmCvar_t ui_ctf_timelimit;
-vmCvar_t ui_ctf_friendly;
-
-vmCvar_t ui_arenasFile;
-vmCvar_t ui_botsFile;
-vmCvar_t ui_spScores1;
-vmCvar_t ui_spScores2;
-vmCvar_t ui_spScores3;
-vmCvar_t ui_spScores4;
-vmCvar_t ui_spScores5;
-vmCvar_t ui_spAwards;
-vmCvar_t ui_spVideos;
-vmCvar_t ui_spSkill;
-
-vmCvar_t ui_spSelection;
-
-vmCvar_t ui_browserMaster;
-vmCvar_t ui_browserGameType;
-vmCvar_t ui_browserSortKey;
-vmCvar_t ui_browserShowFull;
-vmCvar_t ui_browserShowEmpty;
-
-vmCvar_t ui_brassTime;
-vmCvar_t ui_drawCrosshair;
-vmCvar_t ui_drawCrosshairNames;
-vmCvar_t ui_marks;
-
-vmCvar_t ui_server1;
-vmCvar_t ui_server2;
-vmCvar_t ui_server3;
-vmCvar_t ui_server4;
-vmCvar_t ui_server5;
-vmCvar_t ui_server6;
-vmCvar_t ui_server7;
-vmCvar_t ui_server8;
-vmCvar_t ui_server9;
-vmCvar_t ui_server10;
-vmCvar_t ui_server11;
-vmCvar_t ui_server12;
-vmCvar_t ui_server13;
-vmCvar_t ui_server14;
-vmCvar_t ui_server15;
-vmCvar_t ui_server16;
-
-vmCvar_t ui_redteam;
-vmCvar_t ui_redteam1;
-vmCvar_t ui_redteam2;
-vmCvar_t ui_redteam3;
-vmCvar_t ui_redteam4;
-vmCvar_t ui_redteam5;
-vmCvar_t ui_blueteam;
-vmCvar_t ui_blueteam1;
-vmCvar_t ui_blueteam2;
-vmCvar_t ui_blueteam3;
-vmCvar_t ui_blueteam4;
-vmCvar_t ui_blueteam5;
-vmCvar_t ui_teamName;
-vmCvar_t ui_dedicated;
-vmCvar_t ui_gameType;
-vmCvar_t ui_netGameType;
-vmCvar_t ui_actualNetGameType;
-vmCvar_t ui_joinGameType;
-vmCvar_t ui_netSource;
-vmCvar_t ui_serverFilterType;
-vmCvar_t ui_opponentName;
-vmCvar_t ui_menuFiles;
-vmCvar_t ui_currentTier;
-vmCvar_t ui_currentMap;
-vmCvar_t ui_currentNetMap;
-vmCvar_t ui_mapIndex;
-vmCvar_t ui_currentOpponent;
-vmCvar_t ui_selectedPlayer;
-vmCvar_t ui_selectedPlayerName;
-vmCvar_t ui_lastServerRefresh_0;
-vmCvar_t ui_lastServerRefresh_1;
-vmCvar_t ui_lastServerRefresh_2;
-vmCvar_t ui_lastServerRefresh_3;
-vmCvar_t ui_lastServerRefresh_0_time;
-vmCvar_t ui_lastServerRefresh_1_time;
-vmCvar_t ui_lastServerRefresh_2_time;
-vmCvar_t ui_lastServerRefresh_3_time;
-vmCvar_t ui_singlePlayerActive;
-vmCvar_t ui_scoreAccuracy;
-vmCvar_t ui_scoreImpressives;
-vmCvar_t ui_scoreExcellents;
-vmCvar_t ui_scoreCaptures;
-vmCvar_t ui_scoreDefends;
-vmCvar_t ui_scoreAssists;
-vmCvar_t ui_scoreGauntlets;
-vmCvar_t ui_scoreScore;
-vmCvar_t ui_scorePerfect;
-vmCvar_t ui_scoreTeam;
-vmCvar_t ui_scoreBase;
-vmCvar_t ui_scoreTimeBonus;
-vmCvar_t ui_scoreSkillBonus;
-vmCvar_t ui_scoreShutoutBonus;
-vmCvar_t ui_scoreTime;
-vmCvar_t ui_captureLimit;
-vmCvar_t ui_fragLimit;
-vmCvar_t ui_smallFont;
-vmCvar_t ui_bigFont;
-vmCvar_t ui_findPlayer;
-vmCvar_t ui_Q3Model;
-vmCvar_t ui_hudFiles;
-vmCvar_t ui_recordSPDemo;
-vmCvar_t ui_realCaptureLimit;
-vmCvar_t ui_realWarmUp;
-vmCvar_t ui_serverStatusTimeOut;
-
-//TA: bank values
-vmCvar_t ui_bank;
-vmCvar_t ui_winner;
-
-vmCvar_t ui_chatCommands;
-
-
-// bk001129 - made static to avoid aliasing
-static cvarTable_t cvarTable[] = {
- { &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE },
- { &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE },
-
- { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE },
- { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE },
-
- { &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE },
- { &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE },
- { &ui_team_friendly, "ui_team_friendly", "1", CVAR_ARCHIVE },
-
- { &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE },
- { &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE },
- { &ui_ctf_friendly, "ui_ctf_friendly", "0", CVAR_ARCHIVE },
-
- { &ui_arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM },
- { &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM },
- { &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE },
-
- { &ui_spSelection, "ui_spSelection", "", CVAR_ROM },
- { &ui_winner, "ui_winner", "", CVAR_ROM },
-
- { &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE },
- { &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE },
- { &ui_browserSortKey, "ui_browserSortKey", "4", CVAR_ARCHIVE },
- { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE },
- { &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE },
-
- { &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
- { &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
- { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
- { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE },
-
- { &ui_server1, "server1", "", CVAR_ARCHIVE },
- { &ui_server2, "server2", "", CVAR_ARCHIVE },
- { &ui_server3, "server3", "", CVAR_ARCHIVE },
- { &ui_server4, "server4", "", CVAR_ARCHIVE },
- { &ui_server5, "server5", "", CVAR_ARCHIVE },
- { &ui_server6, "server6", "", CVAR_ARCHIVE },
- { &ui_server7, "server7", "", CVAR_ARCHIVE },
- { &ui_server8, "server8", "", CVAR_ARCHIVE },
- { &ui_server9, "server9", "", CVAR_ARCHIVE },
- { &ui_server10, "server10", "", CVAR_ARCHIVE },
- { &ui_server11, "server11", "", CVAR_ARCHIVE },
- { &ui_server12, "server12", "", CVAR_ARCHIVE },
- { &ui_server13, "server13", "", CVAR_ARCHIVE },
- { &ui_server14, "server14", "", CVAR_ARCHIVE },
- { &ui_server15, "server15", "", CVAR_ARCHIVE },
- { &ui_server16, "server16", "", CVAR_ARCHIVE },
- { &ui_new, "ui_new", "0", CVAR_TEMP },
- { &ui_debug, "ui_debug", "0", CVAR_TEMP },
- { &ui_initialized, "ui_initialized", "0", CVAR_TEMP },
- { &ui_teamName, "ui_teamName", "Pagans", CVAR_ARCHIVE },
- { &ui_opponentName, "ui_opponentName", "Stroggs", CVAR_ARCHIVE },
- { &ui_redteam, "ui_redteam", "Pagans", CVAR_ARCHIVE },
- { &ui_blueteam, "ui_blueteam", "Stroggs", CVAR_ARCHIVE },
- { &ui_dedicated, "ui_dedicated", "0", CVAR_ARCHIVE },
- { &ui_gameType, "ui_gametype", "3", CVAR_ARCHIVE },
- { &ui_joinGameType, "ui_joinGametype", "0", CVAR_ARCHIVE },
- { &ui_netGameType, "ui_netGametype", "3", CVAR_ARCHIVE },
- { &ui_actualNetGameType, "ui_actualNetGametype", "3", CVAR_ARCHIVE },
- { &ui_redteam1, "ui_redteam1", "0", CVAR_ARCHIVE },
- { &ui_redteam2, "ui_redteam2", "0", CVAR_ARCHIVE },
- { &ui_redteam3, "ui_redteam3", "0", CVAR_ARCHIVE },
- { &ui_redteam4, "ui_redteam4", "0", CVAR_ARCHIVE },
- { &ui_redteam5, "ui_redteam5", "0", CVAR_ARCHIVE },
- { &ui_blueteam1, "ui_blueteam1", "0", CVAR_ARCHIVE },
- { &ui_blueteam2, "ui_blueteam2", "0", CVAR_ARCHIVE },
- { &ui_blueteam3, "ui_blueteam3", "0", CVAR_ARCHIVE },
- { &ui_blueteam4, "ui_blueteam4", "0", CVAR_ARCHIVE },
- { &ui_blueteam5, "ui_blueteam5", "0", CVAR_ARCHIVE },
- { &ui_netSource, "ui_netSource", "0", CVAR_ARCHIVE },
- { &ui_menuFiles, "ui_menuFiles", "ui/menus.txt", CVAR_ARCHIVE },
- { &ui_currentTier, "ui_currentTier", "0", CVAR_ARCHIVE },
- { &ui_currentMap, "ui_currentMap", "0", CVAR_ARCHIVE },
- { &ui_currentNetMap, "ui_currentNetMap", "0", CVAR_ARCHIVE },
- { &ui_mapIndex, "ui_mapIndex", "0", CVAR_ARCHIVE },
- { &ui_currentOpponent, "ui_currentOpponent", "0", CVAR_ARCHIVE },
- { &ui_selectedPlayer, "cg_selectedPlayer", "0", CVAR_ARCHIVE},
- { &ui_selectedPlayerName, "cg_selectedPlayerName", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_0, "ui_lastServerRefresh_0", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_1, "ui_lastServerRefresh_1", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_2, "ui_lastServerRefresh_2", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_3, "ui_lastServerRefresh_3", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_0, "ui_lastServerRefresh_0_time", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_1, "ui_lastServerRefresh_1_time", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_2, "ui_lastServerRefresh_2_time", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_3, "ui_lastServerRefresh_3_time", "", CVAR_ARCHIVE},
- { &ui_singlePlayerActive, "ui_singlePlayerActive", "0", 0},
- { &ui_scoreAccuracy, "ui_scoreAccuracy", "0", CVAR_ARCHIVE},
- { &ui_scoreImpressives, "ui_scoreImpressives", "0", CVAR_ARCHIVE},
- { &ui_scoreExcellents, "ui_scoreExcellents", "0", CVAR_ARCHIVE},
- { &ui_scoreCaptures, "ui_scoreCaptures", "0", CVAR_ARCHIVE},
- { &ui_scoreDefends, "ui_scoreDefends", "0", CVAR_ARCHIVE},
- { &ui_scoreAssists, "ui_scoreAssists", "0", CVAR_ARCHIVE},
- { &ui_scoreGauntlets, "ui_scoreGauntlets", "0",CVAR_ARCHIVE},
- { &ui_scoreScore, "ui_scoreScore", "0", CVAR_ARCHIVE},
- { &ui_scorePerfect, "ui_scorePerfect", "0", CVAR_ARCHIVE},
- { &ui_scoreTeam, "ui_scoreTeam", "0 to 0", CVAR_ARCHIVE},
- { &ui_scoreBase, "ui_scoreBase", "0", CVAR_ARCHIVE},
- { &ui_scoreTime, "ui_scoreTime", "00:00", CVAR_ARCHIVE},
- { &ui_scoreTimeBonus, "ui_scoreTimeBonus", "0", CVAR_ARCHIVE},
- { &ui_scoreSkillBonus, "ui_scoreSkillBonus", "0", CVAR_ARCHIVE},
- { &ui_scoreShutoutBonus, "ui_scoreShutoutBonus", "0", CVAR_ARCHIVE},
- { &ui_fragLimit, "ui_fragLimit", "10", 0},
- { &ui_captureLimit, "ui_captureLimit", "5", 0},
- { &ui_smallFont, "ui_smallFont", "0.2", CVAR_ARCHIVE},
- { &ui_bigFont, "ui_bigFont", "0.5", CVAR_ARCHIVE},
- { &ui_findPlayer, "ui_findPlayer", "Sarge", CVAR_ARCHIVE},
- { &ui_Q3Model, "ui_q3model", "0", CVAR_ARCHIVE},
- { &ui_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
- { &ui_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
- { &ui_teamArenaFirstRun, "ui_teamArenaFirstRun", "0", CVAR_ARCHIVE},
- { &ui_realWarmUp, "g_warmup", "20", CVAR_ARCHIVE},
- { &ui_realCaptureLimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART},
- { &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE},
-
- { &ui_bank, "ui_bank", "0", 0 },
-
- { &ui_chatCommands, "ui_chatCommands", "1", CVAR_ARCHIVE},
-};
-
-// bk001129 - made static to avoid aliasing
-static int cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]);
+ case CA_CHALLENGING:
+ s = va("Awaiting challenge...%i", cstate.connectPacketCount);
+ break;
+ case CA_CONNECTED:
+ {
+ char downloadName[MAX_INFO_VALUE];
+ int prompt = trap_Cvar_VariableValue("com_downloadPrompt");
-/*
-=================
-UI_RegisterCvars
-=================
-*/
-void UI_RegisterCvars( void ) {
- int i;
- cvarTable_t *cv;
+ if (prompt & DLP_SHOW)
+ {
+ trap_Key_SetCatcher(KEYCATCH_UI);
+ Menus_ActivateByName("download_popmenu");
+ trap_Cvar_Set("com_downloadPrompt", "0");
+ }
+
+ trap_Cvar_VariableStringBuffer("cl_downloadName", downloadName, sizeof(downloadName));
+
+ if (*downloadName)
+ {
+ UI_DisplayDownloadInfo(downloadName, centerPoint, yStart, scale);
+ return;
+ }
+ }
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
- }
+ s = "Awaiting gamestate...";
+ break;
+
+ case CA_LOADING:
+ return;
+
+ case CA_PRIMED:
+ return;
+
+ default:
+ return;
+ }
+
+ if (Q_stricmp(cstate.servername, "localhost"))
+ Text_PaintCenter(centerPoint, yStart + 80, scale, colorWhite, s, 0);
+
+ // password required / connection rejected information goes here
}
/*
=================
-UI_UpdateCvars
+UI_RegisterCvars
=================
*/
-void UI_UpdateCvars( void ) {
- int i;
- cvarTable_t *cv;
+void UI_RegisterCvars(void)
+{
+ size_t i;
+ cvarTable_t *cv;
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Update( cv->vmCvar );
- }
+ for (i = 0, cv = cvarTable; i < cvarTableSize; i++, cv++)
+ trap_Cvar_Register(cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags);
}
-
/*
=================
-ArenaServers_StopRefresh
+UI_UpdateCvars
=================
*/
-static void UI_StopServerRefresh( void )
+void UI_UpdateCvars(void)
{
- int count;
-
- if (!uiInfo.serverStatus.refreshActive) {
- // not currently refreshing
- return;
- }
- uiInfo.serverStatus.refreshActive = qfalse;
- Com_Printf("%d servers listed in browser with %d players.\n",
- uiInfo.serverStatus.numDisplayServers,
- uiInfo.serverStatus.numPlayersOnServers);
- count = trap_LAN_GetServerCount(ui_netSource.integer);
- if (count - uiInfo.serverStatus.numDisplayServers > 0) {
- Com_Printf("%d servers not listed due to packet loss or pings higher than %d\n",
- count - uiInfo.serverStatus.numDisplayServers,
- (int) trap_Cvar_VariableValue("cl_maxPing"));
- }
+ size_t i;
+ cvarTable_t *cv;
+ for (i = 0, cv = cvarTable; i < cvarTableSize; i++, cv++)
+ trap_Cvar_Update(cv->vmCvar);
}
/*
=================
-UI_DoServerRefresh
+UI_UpdateNews
=================
*/
-static void UI_DoServerRefresh( void )
+void UI_UpdateNews(qboolean begin)
{
- qboolean wait = qfalse;
-
- if (!uiInfo.serverStatus.refreshActive) {
- return;
- }
- if (ui_netSource.integer != AS_FAVORITES) {
- if (ui_netSource.integer == AS_LOCAL) {
- if (!trap_LAN_GetServerCount(ui_netSource.integer)) {
- wait = qtrue;
- }
- } else {
- if (trap_LAN_GetServerCount(ui_netSource.integer) < 0) {
- wait = qtrue;
- }
+ char newsString[MAX_NEWS_STRING];
+ const char *c;
+ const char *wrapped;
+ int line = 0;
+ int linePos = 0;
+ qboolean finished;
+
+ if (begin && !uiInfo.newsInfo.refreshActive)
+ {
+ uiInfo.newsInfo.refreshtime = uiInfo.uiDC.realTime + 10000;
+ uiInfo.newsInfo.refreshActive = qtrue;
+ }
+ else if (!uiInfo.newsInfo.refreshActive) // do nothing
+ {
+ return;
}
- }
+ else if (uiInfo.uiDC.realTime > uiInfo.newsInfo.refreshtime)
+ {
+ strcpy(uiInfo.newsInfo.text[0], "^1Error: Timed out while contacting the server.");
+ uiInfo.newsInfo.numLines = 1;
+ return;
+ }
+
+ // start the news fetching
+ finished = trap_GetNews(begin);
- if (uiInfo.uiDC.realTime < uiInfo.serverStatus.refreshtime) {
- if (wait) {
- return;
+ // parse what comes back. Parse newlines and otherwise chop when necessary
+ trap_Cvar_VariableStringBuffer("cl_newsString", newsString, sizeof(newsString));
+
+ // FIXME remove magic width constant
+ wrapped = Item_Text_Wrap(newsString, 0.25f, 325 * uiInfo.uiDC.aspectScale);
+
+ for (c = wrapped; *c != '\0'; ++c)
+ {
+ if (linePos == (MAX_NEWS_LINEWIDTH - 1) || *c == '\n')
+ {
+ uiInfo.newsInfo.text[line][linePos] = '\0';
+
+ if (line == (MAX_NEWS_LINES - 1))
+ break;
+
+ linePos = 0;
+ line++;
+
+ if (*c != '\n')
+ {
+ uiInfo.newsInfo.text[line][linePos] = *c;
+ linePos++;
+ }
+ }
+ else if (isprint(*c))
+ {
+ uiInfo.newsInfo.text[line][linePos] = *c;
+ linePos++;
+ }
}
- }
- // if still trying to retrieve pings
- if (trap_LAN_UpdateVisiblePings(ui_netSource.integer)) {
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
- } else if (!wait) {
- // get the last servers in the list
- UI_BuildServerDisplayList(2);
- // stop the refresh
- UI_StopServerRefresh();
- }
- //
- UI_BuildServerDisplayList(qfalse);
+ uiInfo.newsInfo.text[line][linePos] = '\0';
+ uiInfo.newsInfo.numLines = line + 1;
+
+ if (finished)
+ uiInfo.newsInfo.refreshActive = qfalse;
}
-/*
-=================
-UI_StartServerRefresh
-=================
-*/
-static void UI_StartServerRefresh(qboolean full)
+void UI_UpdateGithubRelease()
{
- int i;
- char *ptr;
- int time;
- qtime_t q;
-
- time = trap_RealTime(&q);
- trap_Cvar_Set( va("ui_lastServerRefresh_%i_time", ui_netSource.integer ),
- va( "%i", time ) );
- trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer),
- va("%s-%i, %i at %i:%02i", MonthAbbrev[q.tm_mon],q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min));
-
- if (!full) {
- UI_UpdatePendingPings();
- return;
- }
-
- uiInfo.serverStatus.refreshActive = qtrue;
- uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 1000;
- // clear number of displayed servers
- uiInfo.serverStatus.numDisplayServers = 0;
- uiInfo.serverStatus.numPlayersOnServers = 0;
- // mark all servers as visible so we store ping updates for them
- trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
- // reset all the pings
- trap_LAN_ResetPings(ui_netSource.integer);
- //
- if( ui_netSource.integer == AS_LOCAL ) {
- trap_Cmd_ExecuteText( EXEC_NOW, "localservers\n" );
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
- return;
- }
+ char newsString[MAX_NEWS_STRING];
+ const char *c;
+ const char *wrapped;
+ int line = 0, linePos = 0;
+ int nexttime = uiInfo.githubRelease.nextTime;
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000;
- if( ui_netSource.integer == AS_GLOBAL || ui_netSource.integer == AS_MPLAYER ) {
- if( ui_netSource.integer == AS_GLOBAL ) {
- i = 0;
- }
- else {
- i = 1;
- }
+ if (nexttime && !(nexttime > uiInfo.uiDC.realTime))
+ return;
- ptr = UI_Cvar_VariableString("debug_protocol");
- if (strlen(ptr)) {
- trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers %d %s full empty\n", i, ptr));
- }
- else {
- trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers %d %d full empty\n", i, (int)trap_Cvar_VariableValue( "protocol" ) ) );
+ // Limit checks to 1x every 10seconds
+ uiInfo.githubRelease.nextTime = uiInfo.uiDC.realTime + 10000;
+ trap_Cmd_ExecuteText(EXEC_INSERT, "checkForUpdate");
+
+ // parse what comes back. Parse newlines and otherwise chop when necessary
+ trap_Cvar_VariableStringBuffer("cl_latestRelease", newsString, sizeof(newsString));
+
+ // FIXME remove magic width constant
+ wrapped = Item_Text_Wrap(newsString, 0.33f, 450 * uiInfo.uiDC.aspectScale);
+
+ for (c = wrapped; *c != '\0'; ++c)
+ {
+ if (linePos == (MAX_NEWS_LINEWIDTH - 1) || *c == '\n')
+ {
+ uiInfo.githubRelease.text[line][linePos] = '\0';
+
+ if (line == (MAX_NEWS_LINES - 1))
+ break;
+
+ linePos = 0;
+ line++;
+
+ if (*c != '\n')
+ {
+ uiInfo.githubRelease.text[line][linePos] = *c;
+ linePos++;
+ }
+ }
+ else if (isprint(*c))
+ {
+ uiInfo.githubRelease.text[line][linePos] = *c;
+ linePos++;
+ }
}
- }
+
+ uiInfo.githubRelease.text[line][linePos] = '\0';
+ uiInfo.githubRelease.numLines = line + 1;
}
+#ifdef MODULE_INTERFACE_11
+void trap_R_SetClipRegion(const float *region) {}
+
+qboolean trap_GetNews(qboolean force) { return qtrue; }
+#endif
diff --git a/src/ui/ui_players.c b/src/ui/ui_players.c
deleted file mode 100644
index 55fce51..0000000
--- a/src/ui/ui_players.c
+++ /dev/null
@@ -1,1369 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
-
-This file is part of Tremulous.
-
-Tremulous is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Tremulous is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-// ui_players.c
-
-#include "ui_local.h"
-
-
-#define UI_TIMER_GESTURE 2300
-#define UI_TIMER_JUMP 1000
-#define UI_TIMER_LAND 130
-#define UI_TIMER_WEAPON_SWITCH 300
-#define UI_TIMER_ATTACK 500
-#define UI_TIMER_MUZZLE_FLASH 20
-#define UI_TIMER_WEAPON_DELAY 250
-
-#define JUMP_HEIGHT 56
-
-#define SWINGSPEED 0.3f
-
-#define SPIN_SPEED 0.9f
-#define COAST_TIME 1000
-
-
-static int dp_realtime;
-static float jumpHeight;
-sfxHandle_t weaponChangeSound;
-
-
-/*
-===============
-UI_PlayerInfo_SetWeapon
-===============
-*/
-static void UI_PlayerInfo_SetWeapon( playerInfo_t *pi, weapon_t weaponNum )
-{
- //TA: FIXME: this is probably useless for trem
-/* gitem_t * item;
- char path[MAX_QPATH];
-
- pi->currentWeapon = weaponNum;
-tryagain:
- pi->realWeapon = weaponNum;
- pi->weaponModel = 0;
- pi->barrelModel = 0;
- pi->flashModel = 0;
-
- if ( weaponNum == WP_NONE ) {
- return;
- }
-
- if ( item->classname ) {
- pi->weaponModel = trap_R_RegisterModel( item->world_model[0] );
- }
-
- if( pi->weaponModel == 0 ) {
- if( weaponNum == WP_MACHINEGUN ) {
- weaponNum = WP_NONE;
- goto tryagain;
- }
- weaponNum = WP_MACHINEGUN;
- goto tryagain;
- }
-
- if ( weaponNum == WP_MACHINEGUN ) {
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path );
- strcat( path, "_barrel.md3" );
- pi->barrelModel = trap_R_RegisterModel( path );
- }
-
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path );
- strcat( path, "_flash.md3" );
- pi->flashModel = trap_R_RegisterModel( path );
-
- switch( weaponNum ) {
- case WP_GAUNTLET:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_MACHINEGUN:
- MAKERGB( pi->flashDlightColor, 1, 1, 0 );
- break;
-
- case WP_SHOTGUN:
- MAKERGB( pi->flashDlightColor, 1, 1, 0 );
- break;
-
- case WP_GRENADE_LAUNCHER:
- MAKERGB( pi->flashDlightColor, 1, 0.7f, 0.5f );
- break;
-
- case WP_ROCKET_LAUNCHER:
- MAKERGB( pi->flashDlightColor, 1, 0.75f, 0 );
- break;
-
- case WP_TESLAGEN:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_RAILGUN:
- MAKERGB( pi->flashDlightColor, 1, 0.5f, 0 );
- break;
-
- case WP_BFG:
- MAKERGB( pi->flashDlightColor, 1, 0.7f, 1 );
- break;
-
- case WP_GRAPPLING_HOOK:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- default:
- MAKERGB( pi->flashDlightColor, 1, 1, 1 );
- break;
- }*/
-}
-
-
-/*
-===============
-UI_ForceLegsAnim
-===============
-*/
-static void UI_ForceLegsAnim( playerInfo_t *pi, int anim ) {
- pi->legsAnim = ( ( pi->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- if ( anim == LEGS_JUMP ) {
- pi->legsAnimationTimer = UI_TIMER_JUMP;
- }
-}
-
-
-/*
-===============
-UI_SetLegsAnim
-===============
-*/
-static void UI_SetLegsAnim( playerInfo_t *pi, int anim ) {
- if ( pi->pendingLegsAnim ) {
- anim = pi->pendingLegsAnim;
- pi->pendingLegsAnim = 0;
- }
- UI_ForceLegsAnim( pi, anim );
-}
-
-
-/*
-===============
-UI_ForceTorsoAnim
-===============
-*/
-static void UI_ForceTorsoAnim( playerInfo_t *pi, int anim ) {
- pi->torsoAnim = ( ( pi->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- if ( anim == TORSO_GESTURE ) {
- pi->torsoAnimationTimer = UI_TIMER_GESTURE;
- }
-
- if ( anim == TORSO_ATTACK || anim == TORSO_ATTACK2 ) {
- pi->torsoAnimationTimer = UI_TIMER_ATTACK;
- }
-}
-
-
-/*
-===============
-UI_SetTorsoAnim
-===============
-*/
-static void UI_SetTorsoAnim( playerInfo_t *pi, int anim ) {
- if ( pi->pendingTorsoAnim ) {
- anim = pi->pendingTorsoAnim;
- pi->pendingTorsoAnim = 0;
- }
-
- UI_ForceTorsoAnim( pi, anim );
-}
-
-
-/*
-===============
-UI_TorsoSequencing
-===============
-*/
-static void UI_TorsoSequencing( playerInfo_t *pi ) {
- int currentAnim;
-
- currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
-
- if ( pi->weapon != pi->currentWeapon ) {
- if ( currentAnim != TORSO_DROP ) {
- pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
- UI_ForceTorsoAnim( pi, TORSO_DROP );
- }
- }
-
- if ( pi->torsoAnimationTimer > 0 ) {
- return;
- }
-
- if( currentAnim == TORSO_GESTURE ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-
- if( currentAnim == TORSO_ATTACK || currentAnim == TORSO_ATTACK2 ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-
- if ( currentAnim == TORSO_DROP ) {
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
- pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
- UI_ForceTorsoAnim( pi, TORSO_RAISE );
- return;
- }
-
- if ( currentAnim == TORSO_RAISE ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-}
-
-
-/*
-===============
-UI_LegsSequencing
-===============
-*/
-static void UI_LegsSequencing( playerInfo_t *pi ) {
- int currentAnim;
-
- currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
-
- if ( pi->legsAnimationTimer > 0 ) {
- if ( currentAnim == LEGS_JUMP ) {
- jumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP );
- }
- return;
- }
-
- if ( currentAnim == LEGS_JUMP ) {
- UI_ForceLegsAnim( pi, LEGS_LAND );
- pi->legsAnimationTimer = UI_TIMER_LAND;
- jumpHeight = 0;
- return;
- }
-
- if ( currentAnim == LEGS_LAND ) {
- UI_SetLegsAnim( pi, LEGS_IDLE );
- return;
- }
-}
-
-
-/*
-======================
-UI_PositionEntityOnTag
-======================
-*/
-static void UI_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- clipHandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
-
- // lerp the tag
- trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // cast away const because of compiler problems
- MatrixMultiply( lerped.axis, ((refEntity_t*)parent)->axis, entity->axis );
- entity->backlerp = parent->backlerp;
-}
-
-
-/*
-======================
-UI_PositionRotatedEntityOnTag
-======================
-*/
-static void UI_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- clipHandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
- vec3_t tempAxis[3];
-
- // lerp the tag
- trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // cast away const because of compiler problems
- MatrixMultiply( entity->axis, ((refEntity_t *)parent)->axis, tempAxis );
- MatrixMultiply( lerped.axis, tempAxis, entity->axis );
-}
-
-
-/*
-===============
-UI_SetLerpFrameAnimation
-===============
-*/
-static void UI_SetLerpFrameAnimation( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- animation_t *anim;
-
- lf->animationNumber = newAnimation;
- newAnimation &= ~ANIM_TOGGLEBIT;
-
- if ( newAnimation < 0 || newAnimation >= MAX_PLAYER_ANIMATIONS ) {
- trap_Error( va("Bad animation number: %i", newAnimation) );
- }
-
- anim = &ci->animations[ newAnimation ];
-
- lf->animation = anim;
- lf->animationTime = lf->frameTime + anim->initialLerp;
-}
-
-
-/*
-===============
-UI_RunLerpFrame
-===============
-*/
-static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- int f;
- animation_t *anim;
-
- // see if the animation sequence is switching
- if ( newAnimation != lf->animationNumber || !lf->animation ) {
- UI_SetLerpFrameAnimation( ci, lf, newAnimation );
- }
-
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if ( dp_realtime >= lf->frameTime ) {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
-
- // get the next frame based on the animation
- anim = lf->animation;
- if ( dp_realtime < lf->animationTime ) {
- lf->frameTime = lf->animationTime; // initial lerp
- } else {
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
- }
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- if ( f >= anim->numFrames ) {
- f -= anim->numFrames;
- if ( anim->loopFrames ) {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- } else {
- f = anim->numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = dp_realtime;
- }
- }
- lf->frame = anim->firstFrame + f;
- if ( dp_realtime > lf->frameTime ) {
- lf->frameTime = dp_realtime;
- }
- }
-
- if ( lf->frameTime > dp_realtime + 200 ) {
- lf->frameTime = dp_realtime;
- }
-
- if ( lf->oldFrameTime > dp_realtime ) {
- lf->oldFrameTime = dp_realtime;
- }
- // calculate current lerp value
- if ( lf->frameTime == lf->oldFrameTime ) {
- lf->backlerp = 0;
- } else {
- lf->backlerp = 1.0 - (float)( dp_realtime - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
- }
-}
-
-
-/*
-===============
-UI_PlayerAnimation
-===============
-*/
-static void UI_PlayerAnimation( playerInfo_t *pi, int *legsOld, int *legs, float *legsBackLerp,
- int *torsoOld, int *torso, float *torsoBackLerp ) {
-
- // legs animation
- pi->legsAnimationTimer -= uiInfo.uiDC.frameTime;
- if ( pi->legsAnimationTimer < 0 ) {
- pi->legsAnimationTimer = 0;
- }
-
- UI_LegsSequencing( pi );
-
- if ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
- UI_RunLerpFrame( pi, &pi->legs, LEGS_TURN );
- } else {
- UI_RunLerpFrame( pi, &pi->legs, pi->legsAnim );
- }
- *legsOld = pi->legs.oldFrame;
- *legs = pi->legs.frame;
- *legsBackLerp = pi->legs.backlerp;
-
- // torso animation
- pi->torsoAnimationTimer -= uiInfo.uiDC.frameTime;
- if ( pi->torsoAnimationTimer < 0 ) {
- pi->torsoAnimationTimer = 0;
- }
-
- UI_TorsoSequencing( pi );
-
- UI_RunLerpFrame( pi, &pi->torso, pi->torsoAnim );
- *torsoOld = pi->torso.oldFrame;
- *torso = pi->torso.frame;
- *torsoBackLerp = pi->torso.backlerp;
-}
-
-
-/*
-==================
-UI_SwingAngles
-==================
-*/
-static void UI_SwingAngles( float destination, float swingTolerance, float clampTolerance,
- float speed, float *angle, qboolean *swinging ) {
- float swing;
- float move;
- float scale;
-
- if ( !*swinging ) {
- // see if a swing should be started
- swing = AngleSubtract( *angle, destination );
- if ( swing > swingTolerance || swing < -swingTolerance ) {
- *swinging = qtrue;
- }
- }
-
- if ( !*swinging ) {
- return;
- }
-
- // modify the speed depending on the delta
- // so it doesn't seem so linear
- swing = AngleSubtract( destination, *angle );
- scale = fabs( swing );
- if ( scale < swingTolerance * 0.5 ) {
- scale = 0.5;
- } else if ( scale < swingTolerance ) {
- scale = 1.0;
- } else {
- scale = 2.0;
- }
-
- // swing towards the destination angle
- if ( swing >= 0 ) {
- move = uiInfo.uiDC.frameTime * scale * speed;
- if ( move >= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- } else if ( swing < 0 ) {
- move = uiInfo.uiDC.frameTime * scale * -speed;
- if ( move <= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- }
-
- // clamp to no more than tolerance
- swing = AngleSubtract( destination, *angle );
- if ( swing > clampTolerance ) {
- *angle = AngleMod( destination - (clampTolerance - 1) );
- } else if ( swing < -clampTolerance ) {
- *angle = AngleMod( destination + (clampTolerance - 1) );
- }
-}
-
-
-/*
-======================
-UI_MovedirAdjustment
-======================
-*/
-static float UI_MovedirAdjustment( playerInfo_t *pi ) {
- vec3_t relativeAngles;
- vec3_t moveVector;
-
- VectorSubtract( pi->viewAngles, pi->moveAngles, relativeAngles );
- AngleVectors( relativeAngles, moveVector, NULL, NULL );
- if ( Q_fabs( moveVector[0] ) < 0.01 ) {
- moveVector[0] = 0.0;
- }
- if ( Q_fabs( moveVector[1] ) < 0.01 ) {
- moveVector[1] = 0.0;
- }
-
- if ( moveVector[1] == 0 && moveVector[0] > 0 ) {
- return 0;
- }
- if ( moveVector[1] < 0 && moveVector[0] > 0 ) {
- return 22;
- }
- if ( moveVector[1] < 0 && moveVector[0] == 0 ) {
- return 45;
- }
- if ( moveVector[1] < 0 && moveVector[0] < 0 ) {
- return -22;
- }
- if ( moveVector[1] == 0 && moveVector[0] < 0 ) {
- return 0;
- }
- if ( moveVector[1] > 0 && moveVector[0] < 0 ) {
- return 22;
- }
- if ( moveVector[1] > 0 && moveVector[0] == 0 ) {
- return -45;
- }
-
- return -22;
-}
-
-
-/*
-===============
-UI_PlayerAngles
-===============
-*/
-static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
- vec3_t legsAngles, torsoAngles, headAngles;
- float dest;
- float adjust;
-
- VectorCopy( pi->viewAngles, headAngles );
- headAngles[YAW] = AngleMod( headAngles[YAW] );
- VectorClear( legsAngles );
- VectorClear( torsoAngles );
-
- // --------- yaw -------------
-
- // allow yaw to drift a bit
- if ( ( pi->legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
- || ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) {
- // if not standing still, always point all in the same direction
- pi->torso.yawing = qtrue; // always center
- pi->torso.pitching = qtrue; // always center
- pi->legs.yawing = qtrue; // always center
- }
-
- // adjust legs for movement dir
- adjust = UI_MovedirAdjustment( pi );
- legsAngles[YAW] = headAngles[YAW] + adjust;
- torsoAngles[YAW] = headAngles[YAW] + 0.25 * adjust;
-
-
- // torso
- UI_SwingAngles( torsoAngles[YAW], 25, 90, SWINGSPEED, &pi->torso.yawAngle, &pi->torso.yawing );
- UI_SwingAngles( legsAngles[YAW], 40, 90, SWINGSPEED, &pi->legs.yawAngle, &pi->legs.yawing );
-
- torsoAngles[YAW] = pi->torso.yawAngle;
- legsAngles[YAW] = pi->legs.yawAngle;
-
- // --------- pitch -------------
-
- // only show a fraction of the pitch angle in the torso
- if ( headAngles[PITCH] > 180 ) {
- dest = (-360 + headAngles[PITCH]) * 0.75;
- } else {
- dest = headAngles[PITCH] * 0.75;
- }
- UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching );
- torsoAngles[PITCH] = pi->torso.pitchAngle;
-
- // pull the angles back out of the hierarchial chain
- AnglesSubtract( headAngles, torsoAngles, headAngles );
- AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
- AnglesToAxis( legsAngles, legs );
- AnglesToAxis( torsoAngles, torso );
- AnglesToAxis( headAngles, head );
-}
-
-
-/*
-===============
-UI_PlayerFloatSprite
-===============
-*/
-static void UI_PlayerFloatSprite( playerInfo_t *pi, vec3_t origin, qhandle_t shader ) {
- refEntity_t ent;
-
- memset( &ent, 0, sizeof( ent ) );
- VectorCopy( origin, ent.origin );
- ent.origin[2] += 48;
- ent.reType = RT_SPRITE;
- ent.customShader = shader;
- ent.radius = 10;
- ent.renderfx = 0;
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-/*
-======================
-UI_MachinegunSpinAngle
-======================
-*/
-float UI_MachinegunSpinAngle( playerInfo_t *pi ) {
- int delta;
- float angle;
- float speed;
- int torsoAnim;
-
- delta = dp_realtime - pi->barrelTime;
- if ( pi->barrelSpinning ) {
- angle = pi->barrelAngle + delta * SPIN_SPEED;
- } else {
- if ( delta > COAST_TIME ) {
- delta = COAST_TIME;
- }
-
- speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
- angle = pi->barrelAngle + delta * speed;
- }
-
- torsoAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
- if( torsoAnim == TORSO_ATTACK2 ) {
- torsoAnim = TORSO_ATTACK;
- }
- if ( pi->barrelSpinning == !(torsoAnim == TORSO_ATTACK) ) {
- pi->barrelTime = dp_realtime;
- pi->barrelAngle = AngleMod( angle );
- pi->barrelSpinning = !!(torsoAnim == TORSO_ATTACK);
- }
-
- return angle;
-}
-
-
-/*
-===============
-UI_DrawPlayer
-===============
-*/
-void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) {
- refdef_t refdef;
- refEntity_t legs;
- refEntity_t torso;
- refEntity_t head;
- refEntity_t gun;
- refEntity_t barrel;
- refEntity_t flash;
- vec3_t origin;
- int renderfx;
- vec3_t mins = {-16, -16, -24};
- vec3_t maxs = {16, 16, 32};
- float len;
- float xx;
-
- if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) {
- return;
- }
-
- // this allows the ui to cache the player model on the main menu
- if (w == 0 || h == 0) {
- return;
- }
-
- dp_realtime = time;
-
- if ( pi->pendingWeapon != WP_NUM_WEAPONS && dp_realtime > pi->weaponTimer ) {
- pi->weapon = pi->pendingWeapon;
- pi->lastWeapon = pi->pendingWeapon;
- pi->pendingWeapon = WP_NUM_WEAPONS;
- pi->weaponTimer = 0;
- if( pi->currentWeapon != pi->weapon ) {
- trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );
- }
- }
-
- UI_AdjustFrom640( &x, &y, &w, &h );
-
- y -= jumpHeight;
-
- memset( &refdef, 0, sizeof( refdef ) );
- memset( &legs, 0, sizeof(legs) );
- memset( &torso, 0, sizeof(torso) );
- memset( &head, 0, sizeof(head) );
-
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- AxisClear( refdef.viewaxis );
-
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
- xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
- refdef.fov_y = atan2( refdef.height, xx );
- refdef.fov_y *= ( 360 / (float)M_PI );
-
- // calculate distance so the player nearly fills the box
- len = 0.7 * ( maxs[2] - mins[2] );
- origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
-
- refdef.time = dp_realtime;
-
- trap_R_ClearScene();
-
- // get the rotation information
- UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );
-
- // get the animation state (after rotation, to allow feet shuffle)
- UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,
- &torso.oldframe, &torso.frame, &torso.backlerp );
-
- renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
-
- //
- // add the legs
- //
- legs.hModel = pi->legsModel;
- legs.customSkin = pi->legsSkin;
-
- VectorCopy( origin, legs.origin );
-
- VectorCopy( origin, legs.lightingOrigin );
- legs.renderfx = renderfx;
- VectorCopy (legs.origin, legs.oldorigin);
-
- trap_R_AddRefEntityToScene( &legs );
-
- if (!legs.hModel) {
- return;
- }
-
- //
- // add the torso
- //
- torso.hModel = pi->torsoModel;
- if (!torso.hModel) {
- return;
- }
-
- torso.customSkin = pi->torsoSkin;
-
- VectorCopy( origin, torso.lightingOrigin );
-
- UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso");
-
- torso.renderfx = renderfx;
-
- trap_R_AddRefEntityToScene( &torso );
-
- //
- // add the head
- //
- head.hModel = pi->headModel;
- if (!head.hModel) {
- return;
- }
- head.customSkin = pi->headSkin;
-
- VectorCopy( origin, head.lightingOrigin );
-
- UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head");
-
- head.renderfx = renderfx;
-
- trap_R_AddRefEntityToScene( &head );
-
- //
- // add the gun
- //
- if ( pi->currentWeapon != WP_NONE ) {
- memset( &gun, 0, sizeof(gun) );
- gun.hModel = pi->weaponModel;
- VectorCopy( origin, gun.lightingOrigin );
- UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon");
- gun.renderfx = renderfx;
- trap_R_AddRefEntityToScene( &gun );
- }
-
- //
- // add the spinning barrel
- //
- if ( pi->realWeapon == WP_MACHINEGUN ) {
- vec3_t angles;
-
- memset( &barrel, 0, sizeof(barrel) );
- VectorCopy( origin, barrel.lightingOrigin );
- barrel.renderfx = renderfx;
-
- barrel.hModel = pi->barrelModel;
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = UI_MachinegunSpinAngle( pi );
-/* if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
- angles[PITCH] = angles[ROLL];
- angles[ROLL] = 0;
- }*/
- AnglesToAxis( angles, barrel.axis );
-
- UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel");
-
- trap_R_AddRefEntityToScene( &barrel );
- }
-
- //
- // add muzzle flash
- //
- if ( dp_realtime <= pi->muzzleFlashTime ) {
- if ( pi->flashModel ) {
- memset( &flash, 0, sizeof(flash) );
- flash.hModel = pi->flashModel;
- VectorCopy( origin, flash.lightingOrigin );
- UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash");
- flash.renderfx = renderfx;
- trap_R_AddRefEntityToScene( &flash );
- }
-
- // make a dlight for the flash
- if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
- trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0],
- pi->flashDlightColor[1], pi->flashDlightColor[2] );
- }
- }
-
- //
- // add the chat icon
- //
- if ( pi->chat ) {
- UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
- }
-
- //
- // add an accent light
- //
- origin[0] -= 100; // + = behind, - = in front
- origin[1] += 100; // + = left, - = right
- origin[2] += 100; // + = above, - = below
- trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 );
-
- origin[0] -= 100;
- origin[1] -= 100;
- origin[2] -= 100;
- trap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 );
-
- trap_R_RenderScene( &refdef );
-}
-
-/*
-==========================
-UI_FileExists
-==========================
-*/
-static qboolean UI_FileExists(const char *filename) {
- int len;
-
- len = trap_FS_FOpenFile( filename, NULL, FS_READ );
- if (len>0) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==========================
-UI_FindClientHeadFile
-==========================
-*/
-static qboolean UI_FindClientHeadFile( char *filename, int length, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) {
- char *team, *headsFolder;
- int i;
-
- team = "default";
-
- if ( headModelName[0] == '*' ) {
- headsFolder = "heads/";
- headModelName++;
- }
- else {
- headsFolder = "";
- }
- while(1) {
- for ( i = 0; i < 2; i++ ) {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext );
- }
- if ( UI_FileExists( filename ) ) {
- return qtrue;
- }
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext );
- }
- if ( UI_FileExists( filename ) ) {
- return qtrue;
- }
- if ( !teamName || !*teamName ) {
- break;
- }
- }
- // if tried the heads folder first
- if ( headsFolder[0] ) {
- break;
- }
- headsFolder = "heads/";
- }
-
- return qfalse;
-}
-
-/*
-==========================
-UI_RegisterClientSkin
-==========================
-*/
-static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName , const char *teamName) {
- char filename[MAX_QPATH*2];
-
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/lower_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName );
- }
- pi->legsSkin = trap_R_RegisterSkin( filename );
- if (!pi->legsSkin) {
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/lower_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower_%s.skin", modelName, skinName );
- }
- pi->legsSkin = trap_R_RegisterSkin( filename );
- }
-
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/upper_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName );
- }
- pi->torsoSkin = trap_R_RegisterSkin( filename );
- if (!pi->torsoSkin) {
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/upper_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper_%s.skin", modelName, skinName );
- }
- pi->torsoSkin = trap_R_RegisterSkin( filename );
- }
-
- if ( UI_FindClientHeadFile( filename, sizeof(filename), teamName, headModelName, headSkinName, "head", "skin" ) ) {
- pi->headSkin = trap_R_RegisterSkin( filename );
- }
-
- if ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-======================
-UI_ParseAnimationFile
-======================
-*/
-static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) {
- char *text_p, *prev;
- int len;
- int i;
- char *token;
- float fps;
- int skip;
- char text[20000];
- fileHandle_t f;
-
- memset( animations, 0, sizeof( animation_t ) * MAX_PLAYER_ANIMATIONS );
-
- // load the file
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 ) {
- return qfalse;
- }
- if ( len >= ( sizeof( text ) - 1 ) ) {
- Com_Printf( "File %s too long\n", filename );
- trap_FS_FCloseFile( f );
- return qfalse;
- }
- trap_FS_Read( text, len, f );
- text[len] = 0;
- trap_FS_FCloseFile( f );
-
- COM_Compress(text);
-
- // parse the text
- text_p = text;
- skip = 0; // quite the compiler warning
-
- // read optional parameters
- while ( 1 ) {
- prev = text_p; // so we can unget
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( !Q_stricmp( token, "footsteps" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- continue;
- } else if ( !Q_stricmp( token, "headoffset" ) ) {
- for ( i = 0 ; i < 3 ; i++ ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- }
- continue;
- } else if ( !Q_stricmp( token, "sex" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- continue;
- }
-
- // if it is a number, start parsing animations
- if ( token[0] >= '0' && token[0] <= '9' ) {
- text_p = prev; // unget the token
- break;
- }
-
- Com_Printf( "unknown token '%s' is %s\n", token, filename );
- }
-
- // read information for each frame
- for ( i = 0 ; i < MAX_PLAYER_ANIMATIONS ; i++ ) {
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].firstFrame = atoi( token );
- // leg only frames are adjusted to not count the upper body only frames
- if ( i == LEGS_WALKCR ) {
- skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
- }
- if ( i >= LEGS_WALKCR ) {
- animations[i].firstFrame -= skip;
- }
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].numFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].loopFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- fps = atof( token );
- if ( fps == 0 ) {
- fps = 1;
- }
- animations[i].frameLerp = 1000 / fps;
- animations[i].initialLerp = 1000 / fps;
- }
-
- if ( i != MAX_PLAYER_ANIMATIONS ) {
- Com_Printf( "Error parsing animation file: %s", filename );
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-==========================
-UI_RegisterClientModelname
-==========================
-*/
-qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName, const char *headModelSkinName, const char *teamName ) {
- char modelName[MAX_QPATH];
- char skinName[MAX_QPATH];
- char headModelName[MAX_QPATH];
- char headSkinName[MAX_QPATH];
- char filename[MAX_QPATH];
- char *slash;
-
- pi->torsoModel = 0;
- pi->headModel = 0;
-
- if ( !modelSkinName[0] ) {
- return qfalse;
- }
-
- Q_strncpyz( modelName, modelSkinName, sizeof( modelName ) );
-
- slash = strchr( modelName, '/' );
- if ( !slash ) {
- // modelName did not include a skin name
- Q_strncpyz( skinName, "default", sizeof( skinName ) );
- } else {
- Q_strncpyz( skinName, slash + 1, sizeof( skinName ) );
- *slash = '\0';
- }
-
- Q_strncpyz( headModelName, headModelSkinName, sizeof( headModelName ) );
- slash = strchr( headModelName, '/' );
- if ( !slash ) {
- // modelName did not include a skin name
- Q_strncpyz( headSkinName, "default", sizeof( skinName ) );
- } else {
- Q_strncpyz( headSkinName, slash + 1, sizeof( skinName ) );
- *slash = '\0';
- }
-
- // load cmodels before models so filecache works
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
- pi->legsModel = trap_R_RegisterModel( filename );
- if ( !pi->legsModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName );
- pi->legsModel = trap_R_RegisterModel( filename );
- if ( !pi->legsModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
- pi->torsoModel = trap_R_RegisterModel( filename );
- if ( !pi->torsoModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName );
- pi->torsoModel = trap_R_RegisterModel( filename );
- if ( !pi->torsoModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- if (headModelName[0] == '*' ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] );
- }
- else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headModelName );
- }
- pi->headModel = trap_R_RegisterModel( filename );
- if ( !pi->headModel && headModelName[0] != '*') {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName );
- pi->headModel = trap_R_RegisterModel( filename );
- }
-
- if (!pi->headModel) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- // if any skins failed to load, fall back to default
- if ( !UI_RegisterClientSkin( pi, modelName, skinName, headModelName, headSkinName, teamName) ) {
- if ( !UI_RegisterClientSkin( pi, modelName, "default", headModelName, "default", teamName ) ) {
- Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName );
- return qfalse;
- }
- }
-
- // load the animations
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
- if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName );
- if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
- Com_Printf( "Failed to load animation file %s\n", filename );
- return qfalse;
- }
- }
-
- return qtrue;
-}
-
-
-/*
-===============
-UI_PlayerInfo_SetModel
-===============
-*/
-void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model, const char *headmodel, char *teamName ) {
- memset( pi, 0, sizeof(*pi) );
- UI_RegisterClientModelname( pi, model, headmodel, teamName );
- pi->weapon = WP_MACHINEGUN;
- pi->currentWeapon = pi->weapon;
- pi->lastWeapon = pi->weapon;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- pi->chat = qfalse;
- pi->newModel = qtrue;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
-}
-
-
-/*
-===============
-UI_PlayerInfo_SetInfo
-===============
-*/
-void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) {
- int currentAnim;
- weapon_t weaponNum;
-
- pi->chat = chat;
-
- // view angles
- VectorCopy( viewAngles, pi->viewAngles );
-
- // move angles
- VectorCopy( moveAngles, pi->moveAngles );
-
- if ( pi->newModel ) {
- pi->newModel = qfalse;
-
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
- pi->legs.yawAngle = viewAngles[YAW];
- pi->legs.yawing = qfalse;
-
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
- pi->torso.yawAngle = viewAngles[YAW];
- pi->torso.yawing = qfalse;
-
- if ( weaponNumber != WP_NUM_WEAPONS ) {
- pi->weapon = weaponNumber;
- pi->currentWeapon = weaponNumber;
- pi->lastWeapon = weaponNumber;
- pi->pendingWeapon = WP_NUM_WEAPONS;
- pi->weaponTimer = 0;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
- }
-
- return;
- }
-
- // weapon
- if ( weaponNumber == WP_NUM_WEAPONS ) {
- pi->pendingWeapon = WP_NUM_WEAPONS;
- pi->weaponTimer = 0;
- }
- else if ( weaponNumber != WP_NONE ) {
- pi->pendingWeapon = weaponNumber;
- pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY;
- }
- weaponNum = pi->lastWeapon;
- pi->weapon = weaponNum;
-
- if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) {
- torsoAnim = legsAnim = BOTH_DEATH1;
- pi->weapon = pi->currentWeapon = WP_NONE;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
-
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
-
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
-
- return;
- }
-
- // leg animation
- currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
- if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) {
- pi->pendingLegsAnim = legsAnim;
- }
- else if ( legsAnim != currentAnim ) {
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
- }
-
- // torso animation
- if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) {
- if ( weaponNum == WP_NONE ) {
- torsoAnim = TORSO_STAND2;
- }
- else {
- torsoAnim = TORSO_STAND;
- }
- }
-
- if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) {
- if ( weaponNum == WP_NONE ) {
- torsoAnim = TORSO_ATTACK2;
- }
- else {
- torsoAnim = TORSO_ATTACK;
- }
- pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH;
- //FIXME play firing sound here
- }
-
- currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
-
- if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) {
- pi->pendingTorsoAnim = torsoAnim;
- }
- else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) {
- pi->pendingTorsoAnim = torsoAnim;
- }
- else if ( torsoAnim != currentAnim ) {
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
- }
-}
diff --git a/src/ui/ui_public.h b/src/ui/ui_public.h
index f62b8b9..2f85e10 100644
--- a/src/ui/ui_public.h
+++ b/src/ui/ui_public.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,195 +17,189 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
-#ifndef __UI_PUBLIC_H__
-#define __UI_PUBLIC_H__
+#ifndef UI_PUBLIC_H
+#define UI_PUBLIC_H
+
+#include "qcommon/q_shared.h"
-#define UI_API_VERSION 6
+#define UI_API_VERSION 6
typedef struct {
- connstate_t connState;
- int connectPacketCount;
- int clientNum;
- char servername[MAX_STRING_CHARS];
- char updateInfoString[MAX_STRING_CHARS];
- char messageString[MAX_STRING_CHARS];
+ connstate_t connState;
+ int connectPacketCount;
+ int clientNum;
+ char servername[MAX_STRING_CHARS];
+ char updateInfoString[MAX_STRING_CHARS];
+ char messageString[MAX_STRING_CHARS];
} uiClientState_t;
typedef enum {
- UI_ERROR,
- UI_PRINT,
- UI_MILLISECONDS,
- UI_CVAR_SET,
- UI_CVAR_VARIABLEVALUE,
- UI_CVAR_VARIABLESTRINGBUFFER,
- UI_CVAR_SETVALUE,
- UI_CVAR_RESET,
- UI_CVAR_CREATE,
- UI_CVAR_INFOSTRINGBUFFER,
- UI_ARGC,
- UI_ARGV,
- UI_CMD_EXECUTETEXT,
- UI_FS_FOPENFILE,
- UI_FS_READ,
- UI_FS_WRITE,
- UI_FS_FCLOSEFILE,
- UI_FS_GETFILELIST,
- UI_R_REGISTERMODEL,
- UI_R_REGISTERSKIN,
- UI_R_REGISTERSHADERNOMIP,
- UI_R_CLEARSCENE,
- UI_R_ADDREFENTITYTOSCENE,
- UI_R_ADDPOLYTOSCENE,
- UI_R_ADDLIGHTTOSCENE,
- UI_R_RENDERSCENE,
- UI_R_SETCOLOR,
+ UI_ERROR,
+ UI_PRINT,
+ UI_MILLISECONDS,
+ UI_CVAR_SET,
+ UI_CVAR_VARIABLEVALUE,
+ UI_CVAR_VARIABLESTRINGBUFFER,
+ UI_CVAR_SETVALUE,
+ UI_CVAR_RESET,
+ UI_CVAR_CREATE,
+ UI_CVAR_INFOSTRINGBUFFER,
+ UI_ARGC,
+ UI_ARGV,
+ UI_CMD_EXECUTETEXT,
+ UI_FS_FOPENFILE,
+ UI_FS_READ,
+ UI_FS_WRITE,
+ UI_FS_FCLOSEFILE,
+ UI_FS_GETFILELIST,
+ UI_R_REGISTERMODEL,
+ UI_R_REGISTERSKIN,
+ UI_R_REGISTERSHADERNOMIP,
+ UI_R_CLEARSCENE,
+ UI_R_ADDREFENTITYTOSCENE,
+ UI_R_ADDPOLYTOSCENE,
+ UI_R_ADDLIGHTTOSCENE,
+ UI_R_RENDERSCENE,
+ UI_R_SETCOLOR,
#ifndef MODULE_INTERFACE_11
- UI_R_SETCLIPREGION,
+ UI_R_SETCLIPREGION,
#endif
- UI_R_DRAWSTRETCHPIC,
- UI_UPDATESCREEN,
- UI_CM_LERPTAG,
- UI_CM_LOADMODEL,
- UI_S_REGISTERSOUND,
- UI_S_STARTLOCALSOUND,
- UI_KEY_KEYNUMTOSTRINGBUF,
- UI_KEY_GETBINDINGBUF,
- UI_KEY_SETBINDING,
- UI_KEY_ISDOWN,
- UI_KEY_GETOVERSTRIKEMODE,
- UI_KEY_SETOVERSTRIKEMODE,
- UI_KEY_CLEARSTATES,
- UI_KEY_GETCATCHER,
- UI_KEY_SETCATCHER,
- UI_GETCLIPBOARDDATA,
- UI_GETGLCONFIG,
- UI_GETCLIENTSTATE,
- UI_GETCONFIGSTRING,
- UI_LAN_GETPINGQUEUECOUNT,
- UI_LAN_CLEARPING,
- UI_LAN_GETPING,
- UI_LAN_GETPINGINFO,
- UI_CVAR_REGISTER,
- UI_CVAR_UPDATE,
- UI_MEMORY_REMAINING,
- UI_R_REGISTERFONT,
- UI_R_MODELBOUNDS,
+ UI_R_DRAWSTRETCHPIC,
+ UI_UPDATESCREEN,
+ UI_CM_LERPTAG,
+ UI_CM_LOADMODEL,
+ UI_S_REGISTERSOUND,
+ UI_S_STARTLOCALSOUND,
+ UI_KEY_KEYNUMTOSTRINGBUF,
+ UI_KEY_GETBINDINGBUF,
+ UI_KEY_SETBINDING,
+ UI_KEY_ISDOWN,
+ UI_KEY_GETOVERSTRIKEMODE,
+ UI_KEY_SETOVERSTRIKEMODE,
+ UI_KEY_CLEARSTATES,
+ UI_KEY_GETCATCHER,
+ UI_KEY_SETCATCHER,
+ UI_GETCLIPBOARDDATA,
+ UI_GETGLCONFIG,
+ UI_GETCLIENTSTATE,
+ UI_GETCONFIGSTRING,
+ UI_LAN_GETPINGQUEUECOUNT,
+ UI_LAN_CLEARPING,
+ UI_LAN_GETPING,
+ UI_LAN_GETPINGINFO,
+ UI_CVAR_REGISTER,
+ UI_CVAR_UPDATE,
+ UI_MEMORY_REMAINING,
+ UI_R_REGISTERFONT,
+ UI_R_MODELBOUNDS,
#ifdef MODULE_INTERFACE_11
- UI_PARSE_ADD_GLOBAL_DEFINE,
- UI_PARSE_LOAD_SOURCE,
- UI_PARSE_FREE_SOURCE,
- UI_PARSE_READ_TOKEN,
- UI_PARSE_SOURCE_FILE_AND_LINE,
+ UI_PARSE_ADD_GLOBAL_DEFINE,
+ UI_PARSE_LOAD_SOURCE,
+ UI_PARSE_FREE_SOURCE,
+ UI_PARSE_READ_TOKEN,
+ UI_PARSE_SOURCE_FILE_AND_LINE,
#endif
- UI_S_STOPBACKGROUNDTRACK,
- UI_S_STARTBACKGROUNDTRACK,
- UI_REAL_TIME,
- UI_LAN_GETSERVERCOUNT,
- UI_LAN_GETSERVERADDRESSSTRING,
- UI_LAN_GETSERVERINFO,
- UI_LAN_MARKSERVERVISIBLE,
- UI_LAN_UPDATEVISIBLEPINGS,
- UI_LAN_RESETPINGS,
- UI_LAN_LOADCACHEDSERVERS,
- UI_LAN_SAVECACHEDSERVERS,
- UI_LAN_ADDSERVER,
- UI_LAN_REMOVESERVER,
- UI_CIN_PLAYCINEMATIC,
- UI_CIN_STOPCINEMATIC,
- UI_CIN_RUNCINEMATIC,
- UI_CIN_DRAWCINEMATIC,
- UI_CIN_SETEXTENTS,
- UI_R_REMAP_SHADER,
- UI_LAN_SERVERSTATUS,
- UI_LAN_GETSERVERPING,
- UI_LAN_SERVERISVISIBLE,
- UI_LAN_COMPARESERVERS,
- // 1.32
- UI_FS_SEEK,
- UI_SET_PBCLSTATUS,
+ UI_S_STOPBACKGROUNDTRACK,
+ UI_S_STARTBACKGROUNDTRACK,
+ UI_REAL_TIME,
+ UI_LAN_GETSERVERCOUNT,
+ UI_LAN_GETSERVERADDRESSSTRING,
+ UI_LAN_GETSERVERINFO,
+ UI_LAN_MARKSERVERVISIBLE,
+ UI_LAN_UPDATEVISIBLEPINGS,
+ UI_LAN_RESETPINGS,
+ UI_LAN_LOADCACHEDSERVERS,
+ UI_LAN_SAVECACHEDSERVERS,
+ UI_LAN_ADDSERVER,
+ UI_LAN_REMOVESERVER,
+ UI_CIN_PLAYCINEMATIC,
+ UI_CIN_STOPCINEMATIC,
+ UI_CIN_RUNCINEMATIC,
+ UI_CIN_DRAWCINEMATIC,
+ UI_CIN_SETEXTENTS,
+ UI_R_REMAP_SHADER,
+ UI_LAN_SERVERSTATUS,
+ UI_LAN_GETSERVERPING,
+ UI_LAN_SERVERISVISIBLE,
+ UI_LAN_COMPARESERVERS,
+ // 1.32
+ UI_FS_SEEK,
+ UI_SET_PBCLSTATUS,
#ifndef MODULE_INTERFACE_11
- UI_PARSE_ADD_GLOBAL_DEFINE,
- UI_PARSE_LOAD_SOURCE,
- UI_PARSE_FREE_SOURCE,
- UI_PARSE_READ_TOKEN,
- UI_PARSE_SOURCE_FILE_AND_LINE,
- UI_GETNEWS,
+ UI_PARSE_ADD_GLOBAL_DEFINE,
+ UI_PARSE_LOAD_SOURCE,
+ UI_PARSE_FREE_SOURCE,
+ UI_PARSE_READ_TOKEN,
+ UI_PARSE_SOURCE_FILE_AND_LINE,
+ UI_GETNEWS,
#endif
- UI_MEMSET = 100,
- UI_MEMCPY,
- UI_STRNCPY,
- UI_SIN,
- UI_COS,
- UI_ATAN2,
- UI_SQRT,
- UI_FLOOR,
- UI_CEIL
+ // XXX THERE IS ROOM FOR _1_ (or 2? Did i count from 0?)
+ // SYSCALL BETWEEN UI_GETNEWS and UI_MEMSET
+ // UI_RESERVED_SYSCALL = 99,
+
+ UI_MEMSET = 100,
+ UI_MEMCPY,
+ UI_STRNCPY,
+ UI_SIN,
+ UI_COS,
+ UI_ATAN2,
+ UI_SQRT,
+ UI_FLOOR,
+ UI_CEIL,
} uiImport_t;
-typedef enum {
- UIMENU_NONE,
- UIMENU_MAIN,
- UIMENU_INGAME,
- UIMENU_TEAM,
- UIMENU_POSTGAME
-} uiMenuCommand_t;
-
-typedef enum
-{
- SORT_HOST,
- SORT_MAP,
- SORT_CLIENTS,
- SORT_PING
-} serverSortField_t;
+typedef enum { UIMENU_NONE, UIMENU_MAIN, UIMENU_INGAME } uiMenuCommand_t;
+
+typedef enum { SORT_HOST, SORT_GAME, SORT_MAP, SORT_CLIENTS, SORT_PING } serverSortField_t;
typedef enum {
- UI_GETAPIVERSION = 0, // system reserved
+ UI_GETAPIVERSION = 0, // system reserved
- UI_INIT,
-// void UI_Init( void );
+ UI_INIT,
+ // void UI_Init( void );
- UI_SHUTDOWN,
-// void UI_Shutdown( void );
+ UI_SHUTDOWN,
+ // void UI_Shutdown( void );
- UI_KEY_EVENT,
-// void UI_KeyEvent( int key );
+ UI_KEY_EVENT,
+ // void UI_KeyEvent( int key );
- UI_MOUSE_EVENT,
+ UI_MOUSE_EVENT,
// void UI_MouseEvent( int dx, int dy );
#ifndef MODULE_INTERFACE_11
- UI_MOUSE_POSITION,
-// int UI_MousePosition( void );
+ UI_MOUSE_POSITION,
+ // int UI_MousePosition( void );
- UI_SET_MOUSE_POSITION,
+ UI_SET_MOUSE_POSITION,
// void UI_SetMousePosition( int x, int y );
#endif
- UI_REFRESH,
-// void UI_Refresh( int time );
+ UI_REFRESH,
+ // void UI_Refresh( int time );
- UI_IS_FULLSCREEN,
-// qboolean UI_IsFullscreen( void );
+ UI_IS_FULLSCREEN,
+ // qboolean UI_IsFullscreen( void );
- UI_SET_ACTIVE_MENU,
-// void UI_SetActiveMenu( uiMenuCommand_t menu );
+ UI_SET_ACTIVE_MENU,
+ // void UI_SetActiveMenu( uiMenuCommand_t menu );
- UI_CONSOLE_COMMAND,
-// qboolean UI_ConsoleCommand( int realTime );
+ UI_CONSOLE_COMMAND,
+ // qboolean UI_ConsoleCommand( int realTime );
- UI_DRAW_CONNECT_SCREEN
-// void UI_DrawConnectScreen( qboolean overlay );
+ UI_DRAW_CONNECT_SCREEN
+ // void UI_DrawConnectScreen( qboolean overlay );
-// if !overlay, the background will be drawn, otherwise it will be
-// overlayed over whatever the cgame has drawn.
-// a GetClientState syscall will be made to get the current strings
+ // if !overlay, the background will be drawn, otherwise it will be
+ // overlayed over whatever the cgame has drawn.
+ // a GetClientState syscall will be made to get the current strings
} uiExport_t;
#endif
diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c
index 5640e0e..8b6225e 100644
--- a/src/ui/ui_shared.c
+++ b/src/ui/ui_shared.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,38 +17,40 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
#include "ui_shared.h"
-#define SCROLL_TIME_START 500
-#define SCROLL_TIME_ADJUST 150
-#define SCROLL_TIME_ADJUSTOFFSET 40
-#define SCROLL_TIME_FLOOR 20
-
-typedef struct scrollInfo_s {
- int nextScrollTime;
- int nextAdjustTime;
- int adjustValue;
- int scrollKey;
- float xStart;
- float yStart;
- itemDef_t *item;
- qboolean scrollDir;
+#define SCROLL_TIME_START 500
+#define SCROLL_TIME_ADJUST 150
+#define SCROLL_TIME_ADJUSTOFFSET 40
+#define SCROLL_TIME_FLOOR 20
+
+typedef struct {
+ int nextScrollTime;
+ int nextAdjustTime;
+ int adjustValue;
+ int scrollKey;
+ float xStart;
+ float yStart;
+ itemDef_t *item;
+ qboolean scrollDir;
} scrollInfo_t;
static scrollInfo_t scrollInfo;
-//TA: hack to prevent compiler warnings
-void voidFunction( void *var ) { return; }
-qboolean voidFunction2( itemDef_t *var1, int var2 ) { return qfalse; }
+// prevent compiler warnings
+void voidFunction(void *var) { return; }
-static void (*captureFunc) (void *p) = voidFunction;
+qboolean voidFunction2(itemDef_t *var1, int var2) { return qfalse; }
+
+static CaptureFunc *captureFunc = voidFunction;
+static int captureFuncExpiry = 0;
static void *captureData = NULL;
-static itemDef_t *itemCapture = NULL; // item that has the mouse captured ( if any )
+static itemDef_t *itemCapture = NULL; // item that has the mouse captured ( if any )
displayContextDef_t *DC = NULL;
@@ -56,20 +59,23 @@ static qboolean g_editingField = qfalse;
static itemDef_t *g_bindItem = NULL;
static itemDef_t *g_editItem = NULL;
+static itemDef_t *g_comboBoxItem = NULL;
-menuDef_t Menus[MAX_MENUS]; // defined menus
-int menuCount = 0; // how many
+menuDef_t Menus[MAX_MENUS]; // defined menus
+int menuCount = 0; // how many
menuDef_t *menuStack[MAX_OPEN_MENUS];
int openMenuCount = 0;
-static qboolean debugMode = qfalse;
-
#define DOUBLE_CLICK_DELAY 300
static int lastListBoxClickTime = 0;
+itemDataType_t Item_DataType(itemDef_t *item);
void Item_RunScript(itemDef_t *item, const char *s);
void Item_SetupKeywordHash(void);
+static ID_INLINE qboolean Item_IsEditField(itemDef_t *item);
+static ID_INLINE qboolean Item_IsListBox(itemDef_t *item);
+static void Item_ListBox_SetStartPos(itemDef_t *item, int startPos);
void Menu_SetupKeywordHash(void);
int BindingIDFromName(const char *name);
qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down);
@@ -77,40 +83,68 @@ itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu);
itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu);
static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y);
+/*
+===============
+UI_InstallCaptureFunc
+===============
+*/
+void UI_InstallCaptureFunc(CaptureFunc *f, void *data, int timeout)
+{
+ captureFunc = f;
+ captureData = data;
+
+ if (timeout > 0)
+ captureFuncExpiry = DC->realTime + timeout;
+ else
+ captureFuncExpiry = 0;
+}
+
+/*
+===============
+UI_RemoveCaptureFunc
+===============
+*/
+void UI_RemoveCaptureFunc(void)
+{
+ captureFunc = voidFunction;
+ captureData = NULL;
+ captureFuncExpiry = 0;
+}
+
#ifdef CGAME
-#define MEM_POOL_SIZE 128 * 1024
+#define MEM_POOL_SIZE 128 * 1024
#else
-#define MEM_POOL_SIZE 1024 * 1024
+#define MEM_POOL_SIZE 1024 * 1024
#endif
-//TA: hacked variable name to avoid conflict with new cgame Alloc
-static char UI_memoryPool[MEM_POOL_SIZE];
-static int allocPoint, outOfMemory;
+static char UI_memoryPool[MEM_POOL_SIZE];
+static int allocPoint, outOfMemory;
/*
===============
UI_Alloc
===============
*/
-void *UI_Alloc( int size )
+void *UI_Alloc(int size)
{
- char *p;
+ char *p;
+
+ if (allocPoint + size > MEM_POOL_SIZE)
+ {
+ outOfMemory = qtrue;
- if( allocPoint + size > MEM_POOL_SIZE )
- {
- outOfMemory = qtrue;
+ if (DC->Print)
+ DC->Print("UI_Alloc: Failure. Out of memory!\n");
- if( DC->Print )
- DC->Print( "UI_Alloc: Failure. Out of memory!\n" );
- //DC->trap_Print(S_COLOR_YELLOW"WARNING: UI Out of Memory!\n");
- return NULL;
- }
+ // DC->trap_Print(S_COLOR_YELLOW"WARNING: UI Out of Memory!\n");
+ return NULL;
+ }
- p = &UI_memoryPool[ allocPoint ];
+ p = &UI_memoryPool[allocPoint];
- allocPoint += ( size + 15 ) & ~15;
+ allocPoint += (size + 15) & ~15;
- return p;
+ return p;
}
/*
@@ -118,20 +152,13 @@ void *UI_Alloc( int size )
UI_InitMemory
===============
*/
-void UI_InitMemory( void )
+void UI_InitMemory(void)
{
- allocPoint = 0;
- outOfMemory = qfalse;
+ allocPoint = 0;
+ outOfMemory = qfalse;
}
-qboolean UI_OutOfMemory( )
-{
- return outOfMemory;
-}
-
-
-
-
+qboolean UI_OutOfMemory() { return outOfMemory; }
#define HASH_TABLE_SIZE 2048
/*
@@ -139,25 +166,29 @@ qboolean UI_OutOfMemory( )
return a hash value for the string
================
*/
-static long hashForString(const char *str) {
- int i;
- long hash;
- char letter;
-
- hash = 0;
- i = 0;
- while (str[i] != '\0') {
- letter = tolower(str[i]);
- hash+=(long)(letter)*(i+119);
- i++;
- }
- hash &= (HASH_TABLE_SIZE-1);
- return hash;
+static long hashForString(const char *str)
+{
+ int i;
+ long hash;
+ char letter;
+
+ hash = 0;
+ i = 0;
+
+ while (str[i] != '\0')
+ {
+ letter = tolower(str[i]);
+ hash += (long)(letter) * (i + 119);
+ i++;
+ }
+
+ hash &= (HASH_TABLE_SIZE - 1);
+ return hash;
}
typedef struct stringDef_s {
- struct stringDef_s *next;
- const char *str;
+ struct stringDef_s *next;
+ const char *str;
} stringDef_t;
static int strPoolIndex = 0;
@@ -166,69 +197,81 @@ static char strPool[STRING_POOL_SIZE];
static int strHandleCount = 0;
static stringDef_t *strHandle[HASH_TABLE_SIZE];
+// Make a copy of a string for later use. Can safely be called on the
+// same string repeatedly. Redundant on string literals or global
+// constants.
+const char *String_Alloc(const char *p)
+{
+ int len;
+ long hash;
+ stringDef_t *str, *last;
-const char *String_Alloc(const char *p) {
- int len;
- long hash;
- stringDef_t *str, *last;
- static const char *staticNULL = "";
+ if (p == NULL)
+ return NULL;
- if (p == NULL) {
- return NULL;
- }
+ if (*p == 0)
+ return "";
- if (*p == 0) {
- return staticNULL;
- }
+ hash = hashForString(p);
- hash = hashForString(p);
+ str = strHandle[hash];
+
+ while (str)
+ {
+ if (strcmp(p, str->str) == 0)
+ return str->str;
- str = strHandle[hash];
- while (str) {
- if (strcmp(p, str->str) == 0) {
- return str->str;
+ str = str->next;
}
- str = str->next;
- }
- len = strlen(p);
- if (len + strPoolIndex + 1 < STRING_POOL_SIZE) {
- int ph = strPoolIndex;
- strcpy(&strPool[strPoolIndex], p);
- strPoolIndex += len + 1;
+ len = strlen(p);
- str = strHandle[hash];
- last = str;
- while (str && str->next) {
- last = str;
- str = str->next;
- }
-
- str = UI_Alloc(sizeof(stringDef_t));
- str->next = NULL;
- str->str = &strPool[ph];
- if (last) {
- last->next = str;
- } else {
- strHandle[hash] = str;
- }
- return &strPool[ph];
- }
- return NULL;
-}
-
-void String_Report( void ) {
- float f;
- Com_Printf("Memory/String Pool Info\n");
- Com_Printf("----------------\n");
- f = strPoolIndex;
- f /= STRING_POOL_SIZE;
- f *= 100;
- Com_Printf("String Pool is %.1f%% full, %i bytes out of %i used.\n", f, strPoolIndex, STRING_POOL_SIZE);
- f = allocPoint;
- f /= MEM_POOL_SIZE;
- f *= 100;
- Com_Printf("Memory Pool is %.1f%% full, %i bytes out of %i used.\n", f, allocPoint, MEM_POOL_SIZE);
+ if (len + strPoolIndex + 1 < STRING_POOL_SIZE)
+ {
+ int ph = strPoolIndex;
+ strcpy(&strPool[strPoolIndex], p);
+ strPoolIndex += len + 1;
+
+ str = strHandle[hash];
+ last = str;
+
+ while (str && str->next)
+ {
+ last = str;
+ str = str->next;
+ }
+
+ str = UI_Alloc(sizeof(stringDef_t));
+ str->next = NULL;
+ str->str = &strPool[ph];
+
+ if (last)
+ last->next = str;
+ else
+ strHandle[hash] = str;
+
+ return &strPool[ph];
+ }
+ else
+ {
+ Com_Error(ERR_DROP, "String_Alloc( %s ): string pool full!", p);
+ return NULL; // not that we return at all
+ }
+}
+
+void String_Report(void)
+{
+ float f;
+ Com_Printf("Memory/String Pool Info\n");
+ Com_Printf("----------------\n");
+ f = strPoolIndex;
+ f /= STRING_POOL_SIZE;
+ f *= 100;
+ Com_Printf("String Pool is %.1f%% full, %i bytes out of %i used.\n", f, strPoolIndex, STRING_POOL_SIZE);
+ f = allocPoint;
+ f /= MEM_POOL_SIZE;
+ f *= 100;
+ Com_Printf("Memory Pool is %.1f%% full, %i bytes out of %i used.\n", f, allocPoint, MEM_POOL_SIZE);
}
/*
@@ -236,22 +279,29 @@ void String_Report( void ) {
String_Init
=================
*/
-void String_Init( void )
+void String_Init(void)
{
- int i;
- for( i = 0; i < HASH_TABLE_SIZE; i++ )
- strHandle[ i ] = 0;
+ int i;
- strHandleCount = 0;
- strPoolIndex = 0;
- menuCount = 0;
- openMenuCount = 0;
- UI_InitMemory( );
- Item_SetupKeywordHash( );
- Menu_SetupKeywordHash( );
+ for (i = 0; i < HASH_TABLE_SIZE; i++)
+ strHandle[i] = 0;
- if( DC && DC->getBindingBuf )
- Controls_GetConfig( );
+ strHandleCount = 0;
+
+ strPoolIndex = 0;
+
+ menuCount = 0;
+
+ openMenuCount = 0;
+
+ UI_InitMemory();
+
+ Item_SetupKeywordHash();
+
+ Menu_SetupKeywordHash();
+
+ if (DC && DC->getBindingBuf)
+ Controls_GetConfig();
}
/*
@@ -259,21 +309,22 @@ void String_Init( void )
PC_SourceWarning
=================
*/
-void PC_SourceWarning(int handle, char *format, ...) {
- int line;
- char filename[128];
- va_list argptr;
- static char string[4096];
+__attribute__((format(printf, 2, 3))) void PC_SourceWarning(int handle, char *format, ...)
+{
+ int line;
+ char filename[128];
+ va_list argptr;
+ static char string[4096];
- va_start (argptr, format);
- vsprintf (string, format, argptr);
- va_end (argptr);
+ va_start(argptr, format);
+ Q_vsnprintf(string, sizeof(string), format, argptr);
+ va_end(argptr);
- filename[0] = '\0';
- line = 0;
- trap_Parse_SourceFileAndLine(handle, filename, &line);
+ filename[0] = '\0';
+ line = 0;
+ trap_Parse_SourceFileAndLine(handle, filename, &line);
- Com_Printf(S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string);
+ Com_Printf(S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string);
}
/*
@@ -281,21 +332,22 @@ void PC_SourceWarning(int handle, char *format, ...) {
PC_SourceError
=================
*/
-void PC_SourceError(int handle, char *format, ...) {
- int line;
- char filename[128];
- va_list argptr;
- static char string[4096];
+__attribute__((format(printf, 2, 3))) void PC_SourceError(int handle, char *format, ...)
+{
+ int line;
+ char filename[128];
+ va_list argptr;
+ static char string[4096];
- va_start (argptr, format);
- vsprintf (string, format, argptr);
- va_end (argptr);
+ va_start(argptr, format);
+ Q_vsnprintf(string, sizeof(string), format, argptr);
+ va_end(argptr);
- filename[0] = '\0';
- line = 0;
- trap_Parse_SourceFileAndLine(handle, filename, &line);
+ filename[0] = '\0';
+ line = 0;
+ trap_Parse_SourceFileAndLine(handle, filename, &line);
- Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string);
+ Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string);
}
/*
@@ -305,17 +357,19 @@ LerpColor
*/
void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
{
- int i;
+ int i;
- // lerp and clamp each component
- for (i=0; i<4; i++)
- {
- c[i] = a[i] + t*(b[i]-a[i]);
- if (c[i] < 0)
- c[i] = 0;
- else if (c[i] > 1.0)
- c[i] = 1.0;
- }
+ // lerp and clamp each component
+
+ for (i = 0; i < 4; i++)
+ {
+ c[i] = a[i] + t * (b[i] - a[i]);
+
+ if (c[i] < 0)
+ c[i] = 0;
+ else if (c[i] > 1.0)
+ c[i] = 1.0;
+ }
}
/*
@@ -323,15 +377,271 @@ void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
Float_Parse
=================
*/
-qboolean Float_Parse(char **p, float *f) {
- char *token;
- token = COM_ParseExt(p, qfalse);
- if (token && token[0] != 0) {
- *f = atof(token);
+qboolean Float_Parse(char **p, float *f)
+{
+ char *token;
+ token = COM_ParseExt(p, qfalse);
+
+ if (token && token[0] != 0)
+ {
+ *f = atof(token);
+ return qtrue;
+ }
+ else
+ return qfalse;
+}
+
+#define MAX_EXPR_ELEMENTS 32
+
+typedef enum { EXPR_OPERATOR, EXPR_VALUE } exprType_t;
+
+typedef struct exprToken_s {
+ exprType_t type;
+ union {
+ char op;
+ float val;
+ } u;
+} exprToken_t;
+
+typedef struct exprList_s {
+ exprToken_t l[MAX_EXPR_ELEMENTS];
+ int f, b;
+} exprList_t;
+
+/*
+=================
+OpPrec
+
+Return a value reflecting operator precedence
+=================
+*/
+static ID_INLINE int OpPrec(char op)
+{
+ switch (op)
+ {
+ case '*':
+ return 4;
+
+ case '/':
+ return 3;
+
+ case '+':
+ return 2;
+
+ case '-':
+ return 1;
+
+ case '(':
+ return 0;
+
+ default:
+ return -1;
+ }
+}
+
+/*
+=================
+PC_Expression_Parse
+=================
+*/
+static qboolean PC_Expression_Parse(int handle, float *f)
+{
+ pc_token_t token;
+ int unmatchedParentheses = 0;
+ exprList_t stack, fifo;
+ exprToken_t value;
+ qboolean expectingNumber = qtrue;
+
+#define FULL(a) (a.b >= (MAX_EXPR_ELEMENTS - 1))
+#define EMPTY(a) (a.f > a.b)
+
+#define PUSH_VAL(a, v) \
+ { \
+ if (FULL(a)) \
+ return qfalse; \
+ a.b++; \
+ a.l[a.b].type = EXPR_VALUE; \
+ a.l[a.b].u.val = v; \
+ }
+
+#define PUSH_OP(a, o) \
+ { \
+ if (FULL(a)) \
+ return qfalse; \
+ a.b++; \
+ a.l[a.b].type = EXPR_OPERATOR; \
+ a.l[a.b].u.op = o; \
+ }
+
+#define POP_STACK(a) \
+ { \
+ if (EMPTY(a)) \
+ return qfalse; \
+ value = a.l[a.b]; \
+ a.b--; \
+ }
+
+#define PEEK_STACK_OP(a) (a.l[a.b].u.op)
+#define PEEK_STACK_VAL(a) (a.l[a.b].u.val)
+
+#define POP_FIFO(a) \
+ { \
+ if (EMPTY(a)) \
+ return qfalse; \
+ value = a.l[a.f]; \
+ a.f++; \
+ }
+
+ stack.f = fifo.f = 0;
+ stack.b = fifo.b = -1;
+
+ while (trap_Parse_ReadToken(handle, &token))
+ {
+ if (!unmatchedParentheses && token.string[0] == ')')
+ break;
+
+ // Special case to catch negative numbers
+ if (expectingNumber && token.string[0] == '-')
+ {
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
+
+ token.floatvalue = -token.floatvalue;
+ }
+
+ if (token.type == TT_NUMBER)
+ {
+ if (!expectingNumber)
+ return qfalse;
+
+ expectingNumber = !expectingNumber;
+
+ PUSH_VAL(fifo, token.floatvalue);
+ }
+ else
+ {
+ switch (token.string[0])
+ {
+ case '(':
+ unmatchedParentheses++;
+ PUSH_OP(stack, '(');
+ break;
+
+ case ')':
+ unmatchedParentheses--;
+
+ if (unmatchedParentheses < 0)
+ return qfalse;
+
+ while (!EMPTY(stack) && PEEK_STACK_OP(stack) != '(')
+ {
+ POP_STACK(stack);
+ PUSH_OP(fifo, value.u.op);
+ }
+
+ // Pop the '('
+ POP_STACK(stack);
+
+ break;
+
+ case '*':
+ case '/':
+ case '+':
+ case '-':
+ if (expectingNumber)
+ return qfalse;
+
+ expectingNumber = !expectingNumber;
+
+ if (EMPTY(stack))
+ {
+ PUSH_OP(stack, token.string[0]);
+ }
+ else
+ {
+ while (!EMPTY(stack) && OpPrec(token.string[0]) < OpPrec(PEEK_STACK_OP(stack)))
+ {
+ POP_STACK(stack);
+ PUSH_OP(fifo, value.u.op);
+ }
+
+ PUSH_OP(stack, token.string[0]);
+ }
+
+ break;
+
+ default:
+ // Unknown token
+ return qfalse;
+ }
+ }
+ }
+
+ while (!EMPTY(stack))
+ {
+ POP_STACK(stack);
+ PUSH_OP(fifo, value.u.op);
+ }
+
+ while (!EMPTY(fifo))
+ {
+ POP_FIFO(fifo);
+
+ if (value.type == EXPR_VALUE)
+ {
+ PUSH_VAL(stack, value.u.val);
+ }
+ else if (value.type == EXPR_OPERATOR)
+ {
+ char op = value.u.op;
+ float operand1, operand2, result;
+
+ POP_STACK(stack);
+ operand2 = value.u.val;
+ POP_STACK(stack);
+ operand1 = value.u.val;
+
+ switch (op)
+ {
+ case '*':
+ result = operand1 * operand2;
+ break;
+
+ case '/':
+ result = operand1 / operand2;
+ break;
+
+ case '+':
+ result = operand1 + operand2;
+ break;
+
+ case '-':
+ result = operand1 - operand2;
+ break;
+
+ default:
+ Com_Error(ERR_FATAL, "Unknown operator '%c' in postfix string", op);
+ return qfalse;
+ }
+
+ PUSH_VAL(stack, result);
+ }
+ }
+
+ POP_STACK(stack);
+
+ *f = value.u.val;
+
return qtrue;
- } else {
- return qfalse;
- }
+
+#undef FULL
+#undef EMPTY
+#undef PUSH_VAL
+#undef PUSH_OP
+#undef POP_STACK
+#undef PEEK_STACK_OP
+#undef PEEK_STACK_VAL
+#undef POP_FIFO
}
/*
@@ -339,26 +649,37 @@ qboolean Float_Parse(char **p, float *f) {
PC_Float_Parse
=================
*/
-qboolean PC_Float_Parse(int handle, float *f) {
- pc_token_t token;
- int negative = qfalse;
+qboolean PC_Float_Parse(int handle, float *f)
+{
+ pc_token_t token;
+ int negative = qfalse;
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
- if (token.string[0] == '-') {
if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
- negative = qtrue;
- }
- if (token.type != TT_NUMBER) {
- PC_SourceError(handle, "expected float but found %s\n", token.string);
- return qfalse;
- }
- if (negative)
- *f = -token.floatvalue;
- else
- *f = token.floatvalue;
- return qtrue;
+ return qfalse;
+
+ if (token.string[0] == '(')
+ return PC_Expression_Parse(handle, f);
+
+ if (token.string[0] == '-')
+ {
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
+
+ negative = qtrue;
+ }
+
+ if (token.type != TT_NUMBER)
+ {
+ PC_SourceError(handle, "expected float but found %s\n", token.string);
+ return qfalse;
+ }
+
+ if (negative)
+ *f = -token.floatvalue;
+ else
+ *f = token.floatvalue;
+
+ return qtrue;
}
/*
@@ -366,17 +687,20 @@ qboolean PC_Float_Parse(int handle, float *f) {
Color_Parse
=================
*/
-qboolean Color_Parse(char **p, vec4_t *c) {
- int i;
- float f;
+qboolean Color_Parse(char **p, vec4_t *c)
+{
+ int i;
+ float f;
- for (i = 0; i < 4; i++) {
- if (!Float_Parse(p, &f)) {
- return qfalse;
+ for (i = 0; i < 4; i++)
+ {
+ if (!Float_Parse(p, &f))
+ return qfalse;
+
+ (*c)[i] = f;
}
- (*c)[i] = f;
- }
- return qtrue;
+
+ return qtrue;
}
/*
@@ -384,17 +708,20 @@ qboolean Color_Parse(char **p, vec4_t *c) {
PC_Color_Parse
=================
*/
-qboolean PC_Color_Parse(int handle, vec4_t *c) {
- int i;
- float f;
+qboolean PC_Color_Parse(int handle, vec4_t *c)
+{
+ int i;
+ float f;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (!PC_Float_Parse(handle, &f))
+ return qfalse;
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
+ (*c)[i] = f;
}
- (*c)[i] = f;
- }
- return qtrue;
+
+ return qtrue;
}
/*
@@ -402,16 +729,18 @@ qboolean PC_Color_Parse(int handle, vec4_t *c) {
Int_Parse
=================
*/
-qboolean Int_Parse(char **p, int *i) {
- char *token;
- token = COM_ParseExt(p, qfalse);
+qboolean Int_Parse(char **p, int *i)
+{
+ char *token;
+ token = COM_ParseExt(p, qfalse);
- if (token && token[0] != 0) {
- *i = atoi(token);
- return qtrue;
- } else {
- return qfalse;
- }
+ if (token && token[0] != 0)
+ {
+ *i = atoi(token);
+ return qtrue;
+ }
+ else
+ return qfalse;
}
/*
@@ -419,25 +748,47 @@ qboolean Int_Parse(char **p, int *i) {
PC_Int_Parse
=================
*/
-qboolean PC_Int_Parse(int handle, int *i) {
- pc_token_t token;
- int negative = qfalse;
+qboolean PC_Int_Parse(int handle, int *i)
+{
+ pc_token_t token;
+ int negative = qfalse;
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
- if (token.string[0] == '-') {
if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
- negative = qtrue;
- }
- if (token.type != TT_NUMBER) {
- PC_SourceError(handle, "expected integer but found %s\n", token.string);
- return qfalse;
- }
- *i = token.intvalue;
- if (negative)
- *i = - *i;
- return qtrue;
+ return qfalse;
+
+ if (token.string[0] == '(')
+ {
+ float f;
+
+ if (PC_Expression_Parse(handle, &f))
+ {
+ *i = (int)f;
+ return qtrue;
+ }
+ else
+ return qfalse;
+ }
+
+ if (token.string[0] == '-')
+ {
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
+
+ negative = qtrue;
+ }
+
+ if (token.type != TT_NUMBER)
+ {
+ PC_SourceError(handle, "expected integer but found %s\n", token.string);
+ return qfalse;
+ }
+
+ *i = token.intvalue;
+
+ if (negative)
+ *i = -*i;
+
+ return qtrue;
}
/*
@@ -445,17 +796,21 @@ qboolean PC_Int_Parse(int handle, int *i) {
Rect_Parse
=================
*/
-qboolean Rect_Parse(char **p, rectDef_t *r) {
- if (Float_Parse(p, &r->x)) {
- if (Float_Parse(p, &r->y)) {
- if (Float_Parse(p, &r->w)) {
- if (Float_Parse(p, &r->h)) {
- return qtrue;
+qboolean Rect_Parse(char **p, rectDef_t *r)
+{
+ if (Float_Parse(p, &r->x))
+ {
+ if (Float_Parse(p, &r->y))
+ {
+ if (Float_Parse(p, &r->w))
+ {
+ if (Float_Parse(p, &r->h))
+ return qtrue;
+ }
}
- }
}
- }
- return qfalse;
+
+ return qfalse;
}
/*
@@ -463,17 +818,21 @@ qboolean Rect_Parse(char **p, rectDef_t *r) {
PC_Rect_Parse
=================
*/
-qboolean PC_Rect_Parse(int handle, rectDef_t *r) {
- if (PC_Float_Parse(handle, &r->x)) {
- if (PC_Float_Parse(handle, &r->y)) {
- if (PC_Float_Parse(handle, &r->w)) {
- if (PC_Float_Parse(handle, &r->h)) {
- return qtrue;
+qboolean PC_Rect_Parse(int handle, rectDef_t *r)
+{
+ if (PC_Float_Parse(handle, &r->x))
+ {
+ if (PC_Float_Parse(handle, &r->y))
+ {
+ if (PC_Float_Parse(handle, &r->w))
+ {
+ if (PC_Float_Parse(handle, &r->h))
+ return qtrue;
+ }
}
- }
}
- }
- return qfalse;
+
+ return qfalse;
}
/*
@@ -481,15 +840,19 @@ qboolean PC_Rect_Parse(int handle, rectDef_t *r) {
String_Parse
=================
*/
-qboolean String_Parse(char **p, const char **out) {
- char *token;
+qboolean String_Parse(char **p, const char **out)
+{
+ char *token;
- token = COM_ParseExt(p, qfalse);
- if (token && token[0] != 0) {
- *(out) = String_Alloc(token);
- return qtrue;
- }
- return qfalse;
+ token = COM_ParseExt(p, qfalse);
+
+ if (token && token[0] != 0)
+ {
+ *(out) = String_Alloc(token);
+ return qtrue;
+ }
+
+ return qfalse;
}
/*
@@ -497,13 +860,15 @@ qboolean String_Parse(char **p, const char **out) {
PC_String_Parse
=================
*/
-qboolean PC_String_Parse(int handle, const char **out) {
- pc_token_t token;
+qboolean PC_String_Parse(int handle, const char **out)
+{
+ pc_token_t token;
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
+
+ *(out) = String_Alloc(token.string);
- *(out) = String_Alloc(token.string);
return qtrue;
}
@@ -512,37 +877,41 @@ qboolean PC_String_Parse(int handle, const char **out) {
PC_Script_Parse
=================
*/
-qboolean PC_Script_Parse(int handle, const char **out) {
- char script[1024];
- pc_token_t token;
-
- memset(script, 0, sizeof(script));
- // scripts start with { and have ; separated command lists.. commands are command, arg..
- // basically we want everything between the { } as it will be interpreted at run time
+qboolean PC_Script_Parse(int handle, const char **out)
+{
+ char script[1024];
+ pc_token_t token;
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
- if (Q_stricmp(token.string, "{") != 0) {
- return qfalse;
- }
+ memset(script, 0, sizeof(script));
+ // scripts start with { and have ; separated command lists.. commands are command, arg..
+ // basically we want everything between the { } as it will be interpreted at run time
- while ( 1 ) {
if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
+ return qfalse;
- if (Q_stricmp(token.string, "}") == 0) {
- *out = String_Alloc(script);
- return qtrue;
- }
+ if (Q_stricmp(token.string, "{") != 0)
+ return qfalse;
+
+ while (1)
+ {
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
- if (token.string[1] != '\0') {
- Q_strcat(script, 1024, va("\"%s\"", token.string));
- } else {
- Q_strcat(script, 1024, token.string);
+ if (Q_stricmp(token.string, "}") == 0)
+ {
+ *out = String_Alloc(script);
+ return qtrue;
+ }
+
+ if (token.string[1] != '\0')
+ Q_strcat(script, 1024, va("\"%s\"", token.string));
+ else
+ Q_strcat(script, 1024, token.string);
+
+ Q_strcat(script, 1024, " ");
}
- Q_strcat(script, 1024, " ");
- }
- return qfalse; // bk001105 - LCC missing return value
+
+ return qfalse;
}
// display, window, menu, item code
@@ -555,4123 +924,5279 @@ Init_Display
Initializes the display with a structure to all the drawing routines
==================
*/
-void Init_Display( displayContextDef_t *dc )
-{
- DC = dc;
-}
-
-
+void Init_Display(displayContextDef_t *dc) { DC = dc; }
// type and style painting
-void GradientBar_Paint( rectDef_t *rect, vec4_t color )
+void GradientBar_Paint(rectDef_t *rect, vec4_t color)
{
- // gradient bar takes two paints
- DC->setColor( color );
- DC->drawHandlePic( rect->x, rect->y, rect->w, rect->h, DC->Assets.gradientBar );
- DC->setColor( NULL );
+ // gradient bar takes two paints
+ DC->setColor(color);
+ DC->drawHandlePic(rect->x, rect->y, rect->w, rect->h, DC->Assets.gradientBar);
+ DC->setColor(NULL);
}
-
/*
==================
Window_Init
-Initializes a window structure ( windowDef_t ) with defaults
-
+Initializes a window structure ( Window ) with defaults
==================
*/
-void Window_Init(Window *w) {
- memset(w, 0, sizeof(windowDef_t));
- w->borderSize = 1;
- w->foreColor[0] = w->foreColor[1] = w->foreColor[2] = w->foreColor[3] = 1.0;
- w->cinematic = -1;
-}
-
-void Fade(int *flags, float *f, float clamp, int *nextTime, int offsetTime, qboolean bFlags, float fadeAmount) {
- if (*flags & (WINDOW_FADINGOUT | WINDOW_FADINGIN)) {
- if (DC->realTime > *nextTime) {
- *nextTime = DC->realTime + offsetTime;
- if (*flags & WINDOW_FADINGOUT) {
- *f -= fadeAmount;
- if (bFlags && *f <= 0.0) {
- *flags &= ~(WINDOW_FADINGOUT | WINDOW_VISIBLE);
- }
- } else {
- *f += fadeAmount;
- if (*f >= clamp) {
- *f = clamp;
- if (bFlags) {
- *flags &= ~WINDOW_FADINGIN;
- }
- }
- }
- }
- }
-}
-
-
-
-void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle) {
- //float bordersize = 0;
- vec4_t color;
- rectDef_t fillRect = w->rect;
-
-
- if (debugMode) {
- color[0] = color[1] = color[2] = color[3] = 1;
- DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, 1, color);
- }
-
- if (w == NULL || (w->style == 0 && w->border == 0)) {
- return;
- }
-
- if (w->border != 0) {
- fillRect.x += w->borderSize;
- fillRect.y += w->borderSize;
- fillRect.w -= w->borderSize + 1;
- fillRect.h -= w->borderSize + 1;
- }
-
- if (w->style == WINDOW_STYLE_FILLED) {
- // box, but possible a shader that needs filled
- if (w->background) {
- Fade(&w->flags, &w->backColor[3], fadeClamp, &w->nextTime, fadeCycle, qtrue, fadeAmount);
- DC->setColor(w->backColor);
- DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
- DC->setColor(NULL);
- } else {
- DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->backColor);
- }
- } else if (w->style == WINDOW_STYLE_GRADIENT) {
- GradientBar_Paint(&fillRect, w->backColor);
- // gradient bar
- } else if (w->style == WINDOW_STYLE_SHADER) {
- if (w->flags & WINDOW_FORECOLORSET) {
- DC->setColor(w->foreColor);
- }
- DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
- DC->setColor(NULL);
- } else if (w->style == WINDOW_STYLE_TEAMCOLOR) {
- if (DC->getTeamColor) {
- DC->getTeamColor(&color);
- DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, color);
- }
- } else if (w->style == WINDOW_STYLE_CINEMATIC) {
- if (w->cinematic == -1) {
- w->cinematic = DC->playCinematic(w->cinematicName, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
- if (w->cinematic == -1) {
- w->cinematic = -2;
- }
- }
- if (w->cinematic >= 0) {
- DC->runCinematicFrame(w->cinematic);
- DC->drawCinematic(w->cinematic, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
- }
- }
-
- if (w->border == WINDOW_BORDER_FULL) {
- // full
- // HACK HACK HACK
- if (w->style == WINDOW_STYLE_TEAMCOLOR) {
- if (color[0] > 0) {
- // red
- color[0] = 1;
- color[1] = color[2] = .5;
-
- } else {
- color[2] = 1;
- color[0] = color[1] = .5;
- }
- color[3] = 1;
- DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, color);
- } else {
- DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, w->borderColor);
- }
- } else if (w->border == WINDOW_BORDER_HORZ) {
- // top/bottom
- DC->setColor(w->borderColor);
- DC->drawTopBottom(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
- DC->setColor( NULL );
- } else if (w->border == WINDOW_BORDER_VERT) {
- // left right
- DC->setColor(w->borderColor);
- DC->drawSides(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
- DC->setColor( NULL );
- } else if (w->border == WINDOW_BORDER_KCGRADIENT) {
- // this is just two gradient bars along each horz edge
- rectDef_t r = w->rect;
- r.h = w->borderSize;
- GradientBar_Paint(&r, w->borderColor);
- r.y = w->rect.y + w->rect.h - 1;
- GradientBar_Paint(&r, w->borderColor);
- }
-
-}
-
-
-void Item_SetScreenCoords(itemDef_t *item, float x, float y) {
-
- if (item == NULL) {
- return;
- }
-
- if (item->window.border != 0) {
- x += item->window.borderSize;
- y += item->window.borderSize;
- }
-
- item->window.rect.x = x + item->window.rectClient.x;
- item->window.rect.y = y + item->window.rectClient.y;
- item->window.rect.w = item->window.rectClient.w;
- item->window.rect.h = item->window.rectClient.h;
-
- // force the text rects to recompute
- item->textRect.w = 0;
- item->textRect.h = 0;
+void Window_Init(Window *w)
+{
+ memset(w, 0, sizeof(Window));
+ w->borderSize = 1;
+ w->foreColor[0] = w->foreColor[1] = w->foreColor[2] = w->foreColor[3] = 1.0;
+ w->cinematic = -1;
}
-// FIXME: consolidate this with nearby stuff
-void Item_UpdatePosition(itemDef_t *item) {
- float x, y;
- menuDef_t *menu;
+void Fade(int *flags, float *f, float clamp, int *nextTime, int offsetTime, qboolean bFlags, float fadeAmount)
+{
+ if (*flags & (WINDOW_FADINGOUT | WINDOW_FADINGIN))
+ {
+ if (DC->realTime > *nextTime)
+ {
+ *nextTime = DC->realTime + offsetTime;
- if (item == NULL || item->parent == NULL) {
- return;
- }
+ if (*flags & WINDOW_FADINGOUT)
+ {
+ *f -= fadeAmount;
- menu = item->parent;
+ if (bFlags && *f <= 0.0)
+ *flags &= ~(WINDOW_FADINGOUT | WINDOW_VISIBLE);
+ }
+ else
+ {
+ *f += fadeAmount;
- x = menu->window.rect.x;
- y = menu->window.rect.y;
+ if (*f >= clamp)
+ {
+ *f = clamp;
- if (menu->window.border != 0) {
- x += menu->window.borderSize;
- y += menu->window.borderSize;
- }
+ if (bFlags)
+ *flags &= ~WINDOW_FADINGIN;
+ }
+ }
+ }
+ }
+}
- Item_SetScreenCoords(item, x, y);
+static void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle)
+{
+ vec4_t color;
+ rectDef_t fillRect = w->rect;
-}
+ if (DC->getCVarValue("ui_developer"))
+ {
+ color[0] = color[1] = color[2] = color[3] = 1;
+ DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, 1, color);
+ }
-// menus
-void Menu_UpdatePosition(menuDef_t *menu) {
- int i;
- float x, y;
-
- if (menu == NULL) {
- return;
- }
-
- x = menu->window.rect.x;
- y = menu->window.rect.y;
- if (menu->window.border != 0) {
- x += menu->window.borderSize;
- y += menu->window.borderSize;
- }
-
- for (i = 0; i < menu->itemCount; i++) {
- Item_SetScreenCoords(menu->items[i], x, y);
- }
-}
-
-void Menu_PostParse(menuDef_t *menu) {
- if (menu == NULL) {
- return;
- }
- if (menu->fullScreen) {
- menu->window.rect.x = 0;
- menu->window.rect.y = 0;
- menu->window.rect.w = 640;
- menu->window.rect.h = 480;
- }
- Menu_UpdatePosition(menu);
-}
-
-itemDef_t *Menu_ClearFocus(menuDef_t *menu) {
- int i;
- itemDef_t *ret = NULL;
-
- if (menu == NULL) {
- return NULL;
- }
+ if (w == NULL || (w->style == 0 && w->border == 0))
+ return;
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
- ret = menu->items[i];
+ if (w->border != 0)
+ {
+ fillRect.x += w->borderSize;
+ fillRect.y += w->borderSize;
+ fillRect.w -= w->borderSize + 1;
+ fillRect.h -= w->borderSize + 1;
}
- menu->items[i]->window.flags &= ~WINDOW_HASFOCUS;
- if (menu->items[i]->leaveFocus) {
- Item_RunScript(menu->items[i], menu->items[i]->leaveFocus);
+
+ if (w->style == WINDOW_STYLE_FILLED)
+ {
+ // box, but possible a shader that needs filled
+
+ if (w->background)
+ {
+ Fade(&w->flags, &w->backColor[3], fadeClamp, &w->nextTime, fadeCycle, qtrue, fadeAmount);
+ DC->setColor(w->backColor);
+ DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
+ DC->setColor(NULL);
+ }
+ else
+ DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->backColor);
}
- }
+ else if (w->style == WINDOW_STYLE_GRADIENT)
+ {
+ GradientBar_Paint(&fillRect, w->backColor);
+ // gradient bar
+ }
+ else if (w->style == WINDOW_STYLE_SHADER)
+ {
+ if (w->flags & WINDOW_FORECOLORSET)
+ DC->setColor(w->foreColor);
+
+ DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
+ DC->setColor(NULL);
+ }
+ else if (w->style == WINDOW_STYLE_CINEMATIC)
+ {
+ if (w->cinematic == -1)
+ {
+ w->cinematic = DC->playCinematic(w->cinematicName, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
- return ret;
+ if (w->cinematic == -1)
+ w->cinematic = -2;
+ }
+
+ if (w->cinematic >= 0)
+ {
+ DC->runCinematicFrame(w->cinematic);
+ DC->drawCinematic(w->cinematic, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
+ }
+ }
}
-qboolean IsVisible(int flags) {
- return (flags & WINDOW_VISIBLE && !(flags & WINDOW_FADINGOUT));
+static void Border_Paint(Window *w)
+{
+ if (w == NULL || (w->style == 0 && w->border == 0))
+ return;
+
+ if (w->border == WINDOW_BORDER_FULL)
+ {
+ // full
+ DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, w->borderColor);
+ }
+ else if (w->border == WINDOW_BORDER_HORZ)
+ {
+ // top/bottom
+ DC->setColor(w->borderColor);
+ DC->drawTopBottom(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
+ DC->setColor(NULL);
+ }
+ else if (w->border == WINDOW_BORDER_VERT)
+ {
+ // left right
+ DC->setColor(w->borderColor);
+ DC->drawSides(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
+ DC->setColor(NULL);
+ }
+ else if (w->border == WINDOW_BORDER_KCGRADIENT)
+ {
+ // this is just two gradient bars along each horz edge
+ rectDef_t r = w->rect;
+ r.h = w->borderSize;
+ GradientBar_Paint(&r, w->borderColor);
+ r.y = w->rect.y + w->rect.h - 1;
+ GradientBar_Paint(&r, w->borderColor);
+ }
}
-qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) {
- if (rect) {
- if (x > rect->x && x < rect->x + rect->w && y > rect->y && y < rect->y + rect->h) {
- return qtrue;
+void Item_SetScreenCoords(itemDef_t *item, float x, float y)
+{
+ if (item == NULL)
+ return;
+
+ if (item->window.border != 0)
+ {
+ x += item->window.borderSize;
+ y += item->window.borderSize;
}
- }
- return qfalse;
+
+ item->window.rect.x = x + item->window.rectClient.x;
+ item->window.rect.y = y + item->window.rectClient.y;
+ item->window.rect.w = item->window.rectClient.w;
+ item->window.rect.h = item->window.rectClient.h;
+
+ // force the text rects to recompute
+ item->textRect.w = 0;
+ item->textRect.h = 0;
}
-int Menu_ItemsMatchingGroup(menuDef_t *menu, const char *name) {
- int i;
- int count = 0;
- for (i = 0; i < menu->itemCount; i++) {
- if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
- count++;
+// FIXME: consolidate this with nearby stuff
+void Item_UpdatePosition(itemDef_t *item)
+{
+ float x, y;
+ menuDef_t *menu;
+
+ if (item == NULL || item->parent == NULL)
+ return;
+
+ menu = item->parent;
+
+ x = menu->window.rect.x;
+ y = menu->window.rect.y;
+
+ if (menu->window.border != 0)
+ {
+ x += menu->window.borderSize;
+ y += menu->window.borderSize;
}
- }
- return count;
+
+ Item_SetScreenCoords(item, x, y);
}
-itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name) {
- int i;
- int count = 0;
- for (i = 0; i < menu->itemCount; i++) {
- if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
- if (count == index) {
- return menu->items[i];
- }
- count++;
+// menus
+void Menu_UpdatePosition(menuDef_t *menu)
+{
+ int i;
+ float x, y;
+
+ if (menu == NULL)
+ return;
+
+ x = menu->window.rect.x;
+ y = menu->window.rect.y;
+
+ if (menu->window.border != 0)
+ {
+ x += menu->window.borderSize;
+ y += menu->window.borderSize;
}
- }
- return NULL;
+
+ for (i = 0; i < menu->itemCount; i++)
+ Item_SetScreenCoords(menu->items[i], x, y);
}
+static void Menu_AspectiseRect(int bias, Rectangle *rect)
+{
+ switch (bias)
+ {
+ case ALIGN_LEFT:
+ rect->x *= DC->aspectScale;
+ rect->w *= DC->aspectScale;
+ break;
+ case ALIGN_CENTER:
+ rect->x = (rect->x * DC->aspectScale) + (320.0f - (320.0f * DC->aspectScale));
+ rect->w *= DC->aspectScale;
+ break;
-void Script_SetColor(itemDef_t *item, char **args) {
- const char *name;
- int i;
- float f;
- vec4_t *out;
- // expecting type of color to set and 4 args for the color
- if (String_Parse(args, &name)) {
- out = NULL;
- if (Q_stricmp(name, "backcolor") == 0) {
- out = &item->window.backColor;
- item->window.flags |= WINDOW_BACKCOLORSET;
- } else if (Q_stricmp(name, "forecolor") == 0) {
- out = &item->window.foreColor;
- item->window.flags |= WINDOW_FORECOLORSET;
- } else if (Q_stricmp(name, "bordercolor") == 0) {
- out = &item->window.borderColor;
- }
+ case ALIGN_RIGHT:
+ rect->x = 640.0f - ((640.0f - rect->x) * DC->aspectScale);
+ rect->w *= DC->aspectScale;
+ break;
- if (out) {
- for (i = 0; i < 4; i++) {
- if (!Float_Parse(args, &f)) {
- return;
- }
- (*out)[i] = f;
+ default:
+
+ case ASPECT_NONE:
+ break;
+ }
+}
+
+void Menu_AspectCompensate(menuDef_t *menu)
+{
+ int i;
+
+ if (menu->window.aspectBias != ASPECT_NONE)
+ {
+ Menu_AspectiseRect(menu->window.aspectBias, &menu->window.rect);
+
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ menu->items[i]->window.rectClient.x *= DC->aspectScale;
+ menu->items[i]->window.rectClient.w *= DC->aspectScale;
+ menu->items[i]->textalignx *= DC->aspectScale;
}
- }
- }
+ }
+ else
+ {
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ Menu_AspectiseRect(menu->items[i]->window.aspectBias, &menu->items[i]->window.rectClient);
+
+ if (menu->items[i]->window.aspectBias != ASPECT_NONE)
+ menu->items[i]->textalignx *= DC->aspectScale;
+ }
+ }
}
-void Script_SetAsset(itemDef_t *item, char **args) {
- const char *name;
- // expecting name to set asset to
- if (String_Parse(args, &name)) {
- // check for a model
- if (item->type == ITEM_TYPE_MODEL) {
+void Menu_PostParse(menuDef_t *menu)
+{
+ int i, j;
+
+ if (menu == NULL)
+ return;
+
+ if (menu->fullScreen)
+ {
+ menu->window.rect.x = 0;
+ menu->window.rect.y = 0;
+ menu->window.rect.w = 640;
+ menu->window.rect.h = 480;
+ }
+
+ Menu_AspectCompensate(menu);
+ Menu_UpdatePosition(menu);
+
+ // Push lists to the end of the array as they can potentially be drawn on top
+ // of other elements
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ itemDef_t *item = menu->items[i];
+
+ if (Item_IsListBox(item))
+ {
+ for (j = i; j < menu->itemCount - 1; j++)
+ menu->items[j] = menu->items[j + 1];
+
+ menu->items[j] = item;
+ }
}
- }
}
-void Script_SetBackground(itemDef_t *item, char **args) {
- const char *name;
- // expecting name to set asset to
- if (String_Parse(args, &name)) {
- item->window.background = DC->registerShaderNoMip(name);
- }
+itemDef_t *Menu_ClearFocus(menuDef_t *menu)
+{
+ int i;
+ itemDef_t *ret = NULL;
+
+ if (menu == NULL)
+ return NULL;
+
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ if (menu->items[i]->window.flags & WINDOW_HASFOCUS)
+ ret = menu->items[i];
+
+ menu->items[i]->window.flags &= ~WINDOW_HASFOCUS;
+
+ if (menu->items[i]->leaveFocus)
+ Item_RunScript(menu->items[i], menu->items[i]->leaveFocus);
+ }
+
+ return ret;
}
+qboolean IsVisible(int flags) { return (flags & WINDOW_VISIBLE && !(flags & WINDOW_FADINGOUT)); }
+qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y)
+{
+ if (rect)
+ {
+ if (x > rect->x && x < rect->x + rect->w && y > rect->y && y < rect->y + rect->h)
+ return qtrue;
+ }
+ return qfalse;
+}
-itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) {
- int i;
- if (menu == NULL || p == NULL) {
- return NULL;
- }
+int Menu_ItemsMatchingGroup(menuDef_t *menu, const char *name)
+{
+ int i;
+ int count = 0;
- for (i = 0; i < menu->itemCount; i++) {
- if (Q_stricmp(p, menu->items[i]->window.name) == 0) {
- return menu->items[i];
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ if (Q_stricmp(menu->items[i]->window.name, name) == 0 ||
+ (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0))
+ {
+ count++;
+ }
}
- }
- return NULL;
+ return count;
}
-void Script_SetTeamColor(itemDef_t *item, char **args) {
- if (DC->getTeamColor) {
+itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name)
+{
int i;
- vec4_t color;
- DC->getTeamColor(&color);
- for (i = 0; i < 4; i++) {
- item->window.backColor[i] = color[i];
- }
- }
-}
-
-void Script_SetItemColor(itemDef_t *item, char **args) {
- const char *itemname;
- const char *name;
- vec4_t color;
- int i;
- vec4_t *out;
- // expecting type of color to set and 4 args for the color
- if (String_Parse(args, &itemname) && String_Parse(args, &name)) {
- itemDef_t *item2;
- int j;
- int count = Menu_ItemsMatchingGroup(item->parent, itemname);
+ int count = 0;
+
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ if (Q_stricmp(menu->items[i]->window.name, name) == 0 ||
+ (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0))
+ {
+ if (count == index)
+ return menu->items[i];
- if (!Color_Parse(args, &color)) {
- return;
+ count++;
+ }
}
- for (j = 0; j < count; j++) {
- item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname);
- if (item2 != NULL) {
+ return NULL;
+}
+
+void Script_SetColor(itemDef_t *item, char **args)
+{
+ const char *name;
+ int i;
+ float f;
+ vec4_t *out;
+ // expecting type of color to set and 4 args for the color
+
+ if (String_Parse(args, &name))
+ {
out = NULL;
- if (Q_stricmp(name, "backcolor") == 0) {
- out = &item2->window.backColor;
- } else if (Q_stricmp(name, "forecolor") == 0) {
- out = &item2->window.foreColor;
- item2->window.flags |= WINDOW_FORECOLORSET;
- } else if (Q_stricmp(name, "bordercolor") == 0) {
- out = &item2->window.borderColor;
+
+ if (Q_stricmp(name, "backcolor") == 0)
+ {
+ out = &item->window.backColor;
+ item->window.flags |= WINDOW_BACKCOLORSET;
+ }
+ else if (Q_stricmp(name, "forecolor") == 0)
+ {
+ out = &item->window.foreColor;
+ item->window.flags |= WINDOW_FORECOLORSET;
}
+ else if (Q_stricmp(name, "bordercolor") == 0)
+ out = &item->window.borderColor;
+
+ if (out)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ if (!Float_Parse(args, &f))
+ return;
- if (out) {
- for (i = 0; i < 4; i++) {
- (*out)[i] = color[i];
- }
+ (*out)[i] = f;
+ }
}
- }
}
- }
}
+void Script_SetAsset(itemDef_t *item, char **args)
+{
+ const char *name;
+ // expecting name to set asset to
-void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- if (bShow) {
- item->window.flags |= WINDOW_VISIBLE;
- } else {
- item->window.flags &= ~WINDOW_VISIBLE;
- // stop cinematics playing in the window
- if (item->window.cinematic >= 0) {
- DC->stopCinematic(item->window.cinematic);
- item->window.cinematic = -1;
+ if (String_Parse(args, &name))
+ {
+ // check for a model
+ if (item->type == ITEM_TYPE_MODEL)
+ {
}
- }
}
- }
}
-void Menu_FadeItemByName(menuDef_t *menu, const char *p, qboolean fadeOut) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- if (fadeOut) {
- item->window.flags |= (WINDOW_FADINGOUT | WINDOW_VISIBLE);
- item->window.flags &= ~WINDOW_FADINGIN;
- } else {
- item->window.flags |= (WINDOW_VISIBLE | WINDOW_FADINGIN);
- item->window.flags &= ~WINDOW_FADINGOUT;
- }
+void Script_SetBackground(itemDef_t *item, char **args)
+{
+ const char *name;
+ // expecting name to set asset to
+
+ if (String_Parse(args, &name))
+ item->window.background = DC->registerShaderNoMip(name);
+}
+
+itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p)
+{
+ int i;
+
+ if (menu == NULL || p == NULL)
+ return NULL;
+
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ if (Q_stricmp(p, menu->items[i]->window.name) == 0)
+ return menu->items[i];
}
- }
+
+ return NULL;
}
-menuDef_t *Menus_FindByName(const char *p) {
- int i;
- for (i = 0; i < menuCount; i++) {
- if (Q_stricmp(Menus[i].window.name, p) == 0) {
- return &Menus[i];
+void Script_SetItemColor(itemDef_t *item, char **args)
+{
+ const char *itemname;
+ const char *name;
+ vec4_t color;
+ int i;
+ vec4_t *out;
+ // expecting type of color to set and 4 args for the color
+
+ if (String_Parse(args, &itemname) && String_Parse(args, &name))
+ {
+ itemDef_t *item2;
+ int j;
+ int count = Menu_ItemsMatchingGroup(item->parent, itemname);
+
+ if (!Color_Parse(args, &color))
+ return;
+
+ for (j = 0; j < count; j++)
+ {
+ item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname);
+
+ if (item2 != NULL)
+ {
+ out = NULL;
+
+ if (Q_stricmp(name, "backcolor") == 0)
+ out = &item2->window.backColor;
+ else if (Q_stricmp(name, "forecolor") == 0)
+ {
+ out = &item2->window.foreColor;
+ item2->window.flags |= WINDOW_FORECOLORSET;
+ }
+ else if (Q_stricmp(name, "bordercolor") == 0)
+ out = &item2->window.borderColor;
+
+ if (out)
+ {
+ for (i = 0; i < 4; i++)
+ (*out)[i] = color[i];
+ }
+ }
+ }
}
- }
- return NULL;
}
-void Menus_ShowByName(const char *p) {
- menuDef_t *menu = Menus_FindByName(p);
- if (menu) {
- Menus_Activate(menu);
- }
+void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow)
+{
+ itemDef_t *item;
+ int i;
+ int count = Menu_ItemsMatchingGroup(menu, p);
+
+ for (i = 0; i < count; i++)
+ {
+ item = Menu_GetMatchingItemByNumber(menu, i, p);
+
+ if (item != NULL)
+ {
+ if (bShow)
+ item->window.flags |= WINDOW_VISIBLE;
+ else
+ {
+ item->window.flags &= ~WINDOW_VISIBLE;
+ // stop cinematics playing in the window
+
+ if (item->window.cinematic >= 0)
+ {
+ DC->stopCinematic(item->window.cinematic);
+ item->window.cinematic = -1;
+ }
+ }
+ }
+ }
}
-void Menus_OpenByName(const char *p) {
- Menus_ActivateByName(p);
+void Menu_FadeItemByName(menuDef_t *menu, const char *p, qboolean fadeOut)
+{
+ itemDef_t *item;
+ int i;
+ int count = Menu_ItemsMatchingGroup(menu, p);
+
+ for (i = 0; i < count; i++)
+ {
+ item = Menu_GetMatchingItemByNumber(menu, i, p);
+
+ if (item != NULL)
+ {
+ if (fadeOut)
+ {
+ item->window.flags |= (WINDOW_FADINGOUT | WINDOW_VISIBLE);
+ item->window.flags &= ~WINDOW_FADINGIN;
+ }
+ else
+ {
+ item->window.flags |= (WINDOW_VISIBLE | WINDOW_FADINGIN);
+ item->window.flags &= ~WINDOW_FADINGOUT;
+ }
+ }
+ }
}
-static void Menu_RunCloseScript(menuDef_t *menu) {
- if (menu && menu->window.flags & WINDOW_VISIBLE && menu->onClose) {
- itemDef_t item;
- item.parent = menu;
- Item_RunScript(&item, menu->onClose);
- }
+menuDef_t *Menus_FindByName(const char *p)
+{
+ int i;
+
+ for (i = 0; i < menuCount; i++)
+ {
+ if (Q_stricmp(Menus[i].window.name, p) == 0)
+ return &Menus[i];
+ }
+
+ return NULL;
}
-void Menus_CloseByName(const char *p) {
- menuDef_t *menu = Menus_FindByName(p);
- if (menu != NULL) {
- Menu_RunCloseScript(menu);
- menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS);
- }
+static void Menu_RunCloseScript(menuDef_t *menu)
+{
+ if (menu && menu->window.flags & WINDOW_VISIBLE && menu->onClose)
+ {
+ itemDef_t item;
+ item.parent = menu;
+ Item_RunScript(&item, menu->onClose);
+ }
}
-void Menus_CloseAll( void ) {
- int i;
- for (i = 0; i < menuCount; i++) {
- Menu_RunCloseScript(&Menus[i]);
- Menus[i].window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
- }
+static void Menus_Close(menuDef_t *menu)
+{
+ if (menu != NULL)
+ {
+ Menu_RunCloseScript(menu);
+ menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS);
- g_editingField = qfalse;
- g_waitingForKey = qfalse;
+ if (openMenuCount > 0)
+ openMenuCount--;
+
+ if (openMenuCount > 0)
+ Menus_Activate(menuStack[openMenuCount - 1]);
+ }
}
+void Menus_CloseByName(const char *p) { Menus_Close(Menus_FindByName(p)); }
-void Script_Show(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_ShowItemByName(item->parent, name, qtrue);
- }
+void Menus_CloseAll(void)
+{
+ int i;
+
+ // Close any menus on the stack first
+ if (openMenuCount > 0)
+ {
+ for (i = openMenuCount; i > 0; i--)
+ Menus_Close(menuStack[i - 1]);
+
+ openMenuCount = 0;
+ }
+
+ // Close all other menus
+ for (i = 0; i < menuCount; i++)
+ Menus_Close(&Menus[i]);
+
+ g_editingField = qfalse;
+ g_waitingForKey = qfalse;
+ g_comboBoxItem = NULL;
}
-void Script_Hide(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_ShowItemByName(item->parent, name, qfalse);
- }
+void Script_Show(itemDef_t *item, char **args)
+{
+ const char *name;
+
+ if (String_Parse(args, &name))
+ Menu_ShowItemByName(item->parent, name, qtrue);
}
-void Script_FadeIn(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_FadeItemByName(item->parent, name, qfalse);
- }
+void Script_Hide(itemDef_t *item, char **args)
+{
+ const char *name;
+
+ if (String_Parse(args, &name))
+ Menu_ShowItemByName(item->parent, name, qfalse);
}
-void Script_FadeOut(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_FadeItemByName(item->parent, name, qtrue);
- }
+void Script_FadeIn(itemDef_t *item, char **args)
+{
+ const char *name;
+
+ if (String_Parse(args, &name))
+ Menu_FadeItemByName(item->parent, name, qfalse);
}
+void Script_FadeOut(itemDef_t *item, char **args)
+{
+ const char *name;
+ if (String_Parse(args, &name))
+ Menu_FadeItemByName(item->parent, name, qtrue);
+}
-void Script_Open(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menus_OpenByName(name);
- }
+void Script_Open(itemDef_t *item, char **args)
+{
+ const char *name;
+
+ if (String_Parse(args, &name))
+ Menus_ActivateByName(name);
}
-void Script_ConditionalOpen(itemDef_t *item, char **args) {
- const char *cvar;
- const char *name1;
- const char *name2;
- float val;
+void Script_ConditionalOpen(itemDef_t *item, char **args)
+{
+ const char *cvar;
+ const char *name1;
+ const char *name2;
+ float val;
+
+ if (String_Parse(args, &cvar) && String_Parse(args, &name1) && String_Parse(args, &name2))
+ {
+ val = DC->getCVarValue(cvar);
- if ( String_Parse(args, &cvar) && String_Parse(args, &name1) && String_Parse(args, &name2) ) {
- val = DC->getCVarValue( cvar );
- if ( val == 0.f ) {
- Menus_OpenByName(name2);
- } else {
- Menus_OpenByName(name1);
+ if (val == 0.0f)
+ Menus_ActivateByName(name2);
+ else
+ Menus_ActivateByName(name1);
}
- }
}
-void Script_Close(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menus_CloseByName(name);
- }
+void Script_Close(itemDef_t *item, char **args)
+{
+ const char *name;
+
+ (void)item;
+
+ if (String_Parse(args, &name))
+ Menus_CloseByName(name);
}
-void Menu_TransitionItemByName(menuDef_t *menu, const char *p, rectDef_t rectFrom, rectDef_t rectTo, int time, float amt) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- item->window.flags |= (WINDOW_INTRANSITION | WINDOW_VISIBLE);
- item->window.offsetTime = time;
- memcpy(&item->window.rectClient, &rectFrom, sizeof(rectDef_t));
- memcpy(&item->window.rectEffects, &rectTo, sizeof(rectDef_t));
- item->window.rectEffects2.x = fabs(rectTo.x - rectFrom.x) / amt;
- item->window.rectEffects2.y = fabs(rectTo.y - rectFrom.y) / amt;
- item->window.rectEffects2.w = fabs(rectTo.w - rectFrom.w) / amt;
- item->window.rectEffects2.h = fabs(rectTo.h - rectFrom.h) / amt;
- Item_UpdatePosition(item);
+void Menu_TransitionItemByName(
+ menuDef_t *menu, const char *p, rectDef_t rectFrom, rectDef_t rectTo, int time, float amt)
+{
+ itemDef_t *item;
+ int i;
+ int count = Menu_ItemsMatchingGroup(menu, p);
+
+ for (i = 0; i < count; i++)
+ {
+ item = Menu_GetMatchingItemByNumber(menu, i, p);
+
+ if (item != NULL)
+ {
+ item->window.flags |= (WINDOW_INTRANSITION | WINDOW_VISIBLE);
+ item->window.offsetTime = time;
+ memcpy(&item->window.rectClient, &rectFrom, sizeof(rectDef_t));
+ memcpy(&item->window.rectEffects, &rectTo, sizeof(rectDef_t));
+ item->window.rectEffects2.x = fabs(rectTo.x - rectFrom.x) / amt;
+ item->window.rectEffects2.y = fabs(rectTo.y - rectFrom.y) / amt;
+ item->window.rectEffects2.w = fabs(rectTo.w - rectFrom.w) / amt;
+ item->window.rectEffects2.h = fabs(rectTo.h - rectFrom.h) / amt;
+ Item_UpdatePosition(item);
+ }
+ }
+}
+
+void Script_Transition(itemDef_t *item, char **args)
+{
+ const char *name;
+ rectDef_t rectFrom, rectTo;
+ int time;
+ float amt;
+
+ if (String_Parse(args, &name))
+ {
+ if (Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) &&
+ Float_Parse(args, &amt))
+ {
+ Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt);
+ }
}
- }
}
+void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time)
+{
+ itemDef_t *item;
+ int i;
+ int count = Menu_ItemsMatchingGroup(menu, p);
-void Script_Transition(itemDef_t *item, char **args) {
- const char *name;
- rectDef_t rectFrom, rectTo;
- int time;
- float amt;
+ for (i = 0; i < count; i++)
+ {
+ item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (String_Parse(args, &name)) {
- if ( Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) && Float_Parse(args, &amt)) {
- Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt);
+ if (item != NULL)
+ {
+ item->window.flags |= (WINDOW_ORBITING | WINDOW_VISIBLE);
+ item->window.offsetTime = time;
+ item->window.rectEffects.x = cx;
+ item->window.rectEffects.y = cy;
+ item->window.rectClient.x = x;
+ item->window.rectClient.y = y;
+ Item_UpdatePosition(item);
+ }
}
- }
}
+void Script_Orbit(itemDef_t *item, char **args)
+{
+ const char *name;
+ float cx, cy, x, y;
+ int time;
-void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- item->window.flags |= (WINDOW_ORBITING | WINDOW_VISIBLE);
- item->window.offsetTime = time;
- item->window.rectEffects.x = cx;
- item->window.rectEffects.y = cy;
- item->window.rectClient.x = x;
- item->window.rectClient.y = y;
- Item_UpdatePosition(item);
+ if (String_Parse(args, &name))
+ {
+ if (Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) &&
+ Int_Parse(args, &time))
+ {
+ Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time);
+ }
}
- }
}
+void Script_SetFocus(itemDef_t *item, char **args)
+{
+ const char *name;
+ itemDef_t *focusItem;
+
+ if (String_Parse(args, &name))
+ {
+ focusItem = Menu_FindItemByName(item->parent, name);
+
+ if (focusItem && !(focusItem->window.flags & WINDOW_DECORATION))
+ {
+ Menu_ClearFocus(item->parent);
+ focusItem->window.flags |= WINDOW_HASFOCUS;
-void Script_Orbit(itemDef_t *item, char **args) {
- const char *name;
- float cx, cy, x, y;
- int time;
+ if (focusItem->onFocus)
+ Item_RunScript(focusItem, focusItem->onFocus);
- if (String_Parse(args, &name)) {
- if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) {
- Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time);
+ // Edit fields get activated too
+ if (Item_IsEditField(focusItem))
+ {
+ g_editingField = qtrue;
+ g_editItem = focusItem;
+ }
+
+ if (DC->Assets.itemFocusSound)
+ DC->startLocalSound(DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND);
+ }
}
- }
}
+void Script_Reset(itemDef_t *item, char **args)
+{
+ const char *name;
+ itemDef_t *resetItem;
+ if (String_Parse(args, &name))
+ {
+ resetItem = Menu_FindItemByName(item->parent, name);
-void Script_SetFocus(itemDef_t *item, char **args) {
- const char *name;
- itemDef_t *focusItem;
-
- if (String_Parse(args, &name)) {
- focusItem = Menu_FindItemByName(item->parent, name);
- if (focusItem && !(focusItem->window.flags & WINDOW_DECORATION)) {
- Menu_ClearFocus(item->parent);
- focusItem->window.flags |= WINDOW_HASFOCUS;
- if (focusItem->onFocus) {
- Item_RunScript(focusItem, focusItem->onFocus);
- }
- if (focusItem->type == ITEM_TYPE_EDITFIELD || focusItem->type == ITEM_TYPE_SAYFIELD || focusItem->type == ITEM_TYPE_NUMERICFIELD) {
- focusItem->cursorPos = 0;
- g_editingField = qtrue;
- g_editItem = focusItem;
- if (focusItem->type == ITEM_TYPE_SAYFIELD) {
- DC->setOverstrikeMode(qfalse);
+ if (resetItem)
+ {
+ if (Item_IsListBox(resetItem))
+ {
+ resetItem->cursorPos = DC->feederInitialise(resetItem->feederID);
+ Item_ListBox_SetStartPos(resetItem, 0);
+ DC->feederSelection(resetItem->feederID, resetItem->cursorPos);
+ }
}
- }
- if (DC->Assets.itemFocusSound) {
- DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND );
- }
}
- }
-}
-
-void Script_SetPlayerModel(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- DC->setCVar("team_model", name);
- }
-}
-
-void Script_SetPlayerHead(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- DC->setCVar("team_headmodel", name);
- }
}
-void Script_SetCvar(itemDef_t *item, char **args) {
- const char *cvar, *val;
- if (String_Parse(args, &cvar) && String_Parse(args, &val)) {
- DC->setCVar(cvar, val);
- }
+void Script_SetPlayerModel(itemDef_t *item, char **args)
+{
+ const char *name;
+ (void)item;
+
+ if (String_Parse(args, &name))
+ DC->setCVar("model", name);
}
-void Script_Exec(itemDef_t *item, char **args) {
- const char *val;
- if (String_Parse(args, &val)) {
- DC->executeText(EXEC_APPEND, va("%s ; ", val));
- }
+void Script_SetPlayerHead(itemDef_t *item, char **args)
+{
+ const char *name;
+
+ (void)item;
+
+ if (String_Parse(args, &name))
+ DC->setCVar("headmodel", name);
}
-void Script_Play(itemDef_t *item, char **args) {
- const char *val;
- if (String_Parse(args, &val)) {
- DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_LOCAL_SOUND);
- }
+void Script_SetCvar(itemDef_t *item, char **args)
+{
+ const char *cvar, *val;
+
+ (void)item;
+
+ if (String_Parse(args, &cvar) && String_Parse(args, &val))
+ DC->setCVar(cvar, val);
}
-void Script_playLooped(itemDef_t *item, char **args) {
- const char *val;
- if (String_Parse(args, &val)) {
- DC->stopBackgroundTrack();
- DC->startBackgroundTrack(val, val);
- }
-}
-
-
-commandDef_t commandList[] =
+void Script_Exec(itemDef_t *item, char **args)
{
- {"fadein", &Script_FadeIn}, // group/name
- {"fadeout", &Script_FadeOut}, // group/name
- {"show", &Script_Show}, // group/name
- {"hide", &Script_Hide}, // group/name
- {"setcolor", &Script_SetColor}, // works on this
- {"open", &Script_Open}, // menu
- {"conditionalopen", &Script_ConditionalOpen}, // menu
- {"close", &Script_Close}, // menu
- {"setasset", &Script_SetAsset}, // works on this
- {"setbackground", &Script_SetBackground}, // works on this
- {"setitemcolor", &Script_SetItemColor}, // group/name
- {"setteamcolor", &Script_SetTeamColor}, // sets this background color to team color
- {"setfocus", &Script_SetFocus}, // sets this background color to team color
- {"setplayermodel", &Script_SetPlayerModel}, // sets this background color to team color
- {"setplayerhead", &Script_SetPlayerHead}, // sets this background color to team color
- {"transition", &Script_Transition}, // group/name
- {"setcvar", &Script_SetCvar}, // group/name
- {"exec", &Script_Exec}, // group/name
- {"play", &Script_Play}, // group/name
- {"playlooped", &Script_playLooped}, // group/name
- {"orbit", &Script_Orbit} // group/name
-};
+ const char *val;
-int scriptCommandCount = sizeof(commandList) / sizeof(commandDef_t);
-
-
-void Item_RunScript(itemDef_t *item, const char *s) {
- char script[1024], *p;
- int i;
- qboolean bRan;
- memset(script, 0, sizeof(script));
- if (item && s && s[0]) {
- Q_strcat(script, 1024, s);
- p = script;
- while (1) {
- const char *command;
- // expect command then arguments, ; ends command, NULL ends script
- if (!String_Parse(&p, &command)) {
- return;
- }
+ (void)item;
- if (command[0] == ';' && command[1] == '\0') {
- continue;
- }
+ if (String_Parse(args, &val))
+ DC->executeText(EXEC_APPEND, va("%s\n", val));
+}
- bRan = qfalse;
- for (i = 0; i < scriptCommandCount; i++) {
- if (Q_stricmp(command, commandList[i].name) == 0) {
- (commandList[i].handler(item, &p));
- bRan = qtrue;
- break;
- }
- }
- // not in our auto list, pass to handler
- if (!bRan) {
- DC->runScript(&p);
- }
+void Script_Play(itemDef_t *item, char **args)
+{
+ const char *val;
+
+ (void)item;
+
+ if (String_Parse(args, &val))
+ DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_LOCAL_SOUND);
+}
+
+void Script_playLooped(itemDef_t *item, char **args)
+{
+ const char *val;
+
+ (void)item;
+
+ if (String_Parse(args, &val))
+ {
+ DC->stopBackgroundTrack();
+ DC->startBackgroundTrack(val, val);
}
- }
}
+static ID_INLINE float UI_EmoticonHeight(fontInfo_t *font, float scale)
+{
+ return font->glyphs[(int)'['].height * scale * font->glyphScale;
+}
-qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) {
- char script[1024], *p;
- memset(script, 0, sizeof(script));
- if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
- char buff[1024];
- DC->getCVarString(item->cvarTest, buff, sizeof(buff));
-
- Q_strcat(script, 1024, item->enableCvar);
- p = script;
- while (1) {
- const char *val;
- // expect value then ; or NULL, NULL ends list
- if (!String_Parse(&p, &val)) {
- return (item->cvarFlags & flag) ? qfalse : qtrue;
- }
+static ID_INLINE float UI_EmoticonWidth(fontInfo_t *font, float scale)
+{
+ return UI_EmoticonHeight(font, scale) * DC->aspectScale;
+}
- if (val[0] == ';' && val[1] == '\0') {
- continue;
- }
+void UI_EscapeEmoticons(char *dest, const char *src, int destsize)
+{
+ int len;
+ qboolean escaped;
- // enable it if any of the values are true
- if (item->cvarFlags & flag) {
- if (Q_stricmp(buff, val) == 0) {
- return qtrue;
- }
- } else {
- // disable it if any of the values are true
- if (Q_stricmp(buff, val) == 0) {
- return qfalse;
+ for (; *src && destsize > 1; src++, destsize--)
+ {
+ if (UI_Text_IsEmoticon(src, &escaped, &len, NULL, NULL) && !escaped)
+ {
+ *dest++ = '[';
+ destsize--;
}
- }
+ *dest++ = *src;
}
- return (item->cvarFlags & flag) ? qfalse : qtrue;
- }
- return qtrue;
+
+ *dest++ = '\0';
}
+qboolean UI_Text_IsEmoticon(const char *s, qboolean *escaped, int *length, qhandle_t *h, int *width)
+{
+ const char *p = s;
+ char emoticon[MAX_EMOTICON_NAME_LEN];
+ int i;
-// will optionaly set focus to this item
-qboolean Item_SetFocus(itemDef_t *item, float x, float y) {
- int i;
- itemDef_t *oldFocus;
- sfxHandle_t *sfx = &DC->Assets.itemFocusSound;
- qboolean playSound = qfalse;
- menuDef_t *parent; // bk001206: = (menuDef_t*)item->parent;
- // sanity check, non-null, not a decoration and does not already have the focus
- if (item == NULL || item->window.flags & WINDOW_DECORATION || item->window.flags & WINDOW_HASFOCUS || !(item->window.flags & WINDOW_VISIBLE)) {
- return qfalse;
- }
+ if (*p != '[')
+ return qfalse;
+ p++;
- // bk001206 - this can be NULL.
- parent = (menuDef_t*)item->parent;
+ if (*p == '[')
+ {
+ *escaped = qtrue;
+ p++;
+ }
+ else
+ *escaped = qfalse;
- // items can be enabled and disabled based on cvars
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- return qfalse;
- }
+ for (*length = 0; p[*length] != ']'; (*length)++)
+ {
+ if (!p[*length] || *length == MAX_EMOTICON_NAME_LEN - 1)
+ return qfalse;
- if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
- return qfalse;
- }
+ emoticon[*length] = p[*length];
+ }
+ emoticon[*length] = '\0';
- oldFocus = Menu_ClearFocus(item->parent);
+ for (i = 0; i < DC->Assets.emoticonCount; i++)
+ if (!Q_stricmp(DC->Assets.emoticons[i].name, emoticon))
+ break;
- if (item->type == ITEM_TYPE_TEXT) {
- rectDef_t r;
- r = item->textRect;
- r.y -= r.h;
- if (Rect_ContainsPoint(&r, x, y)) {
- item->window.flags |= WINDOW_HASFOCUS;
- if (item->focusSound) {
- sfx = &item->focusSound;
- }
- playSound = qtrue;
- } else {
- if (oldFocus) {
- oldFocus->window.flags |= WINDOW_HASFOCUS;
- if (oldFocus->onFocus) {
- Item_RunScript(oldFocus, oldFocus->onFocus);
- }
- }
- }
- } else {
- item->window.flags |= WINDOW_HASFOCUS;
- if (item->onFocus) {
- Item_RunScript(item, item->onFocus);
- }
- if (item->focusSound) {
- sfx = &item->focusSound;
- }
- playSound = qtrue;
- }
-
- if (playSound && sfx) {
- DC->startLocalSound( *sfx, CHAN_LOCAL_SOUND );
- }
-
- for (i = 0; i < parent->itemCount; i++) {
- if (parent->items[i] == item) {
- parent->cursorItem = i;
- break;
- }
- }
-
- return qtrue;
-}
-
-int Item_ListBox_MaxScroll(itemDef_t *item) {
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
- int count = DC->feederCount(item->special);
- int max;
-
- if (item->window.flags & WINDOW_HORIZONTAL) {
- max = count - (item->window.rect.w / listPtr->elementWidth) + 1;
- }
- else {
- max = count - (item->window.rect.h / listPtr->elementHeight) + 1;
- }
- if (max < 0) {
- return 0;
- }
- return max;
-}
-
-int Item_ListBox_ThumbPosition(itemDef_t *item) {
- float max, pos, size;
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
-
- max = Item_ListBox_MaxScroll(item);
- if (item->window.flags & WINDOW_HORIZONTAL) {
- size = item->window.rect.w - (SCROLLBAR_SIZE * 2) - 2;
- if (max > 0) {
- pos = (size-SCROLLBAR_SIZE) / (float) max;
- } else {
- pos = 0;
- }
- pos *= listPtr->startPos;
- return item->window.rect.x + 1 + SCROLLBAR_SIZE + pos;
- }
- else {
- size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2;
- if (max > 0) {
- pos = (size-SCROLLBAR_SIZE) / (float) max;
- } else {
- pos = 0;
- }
- pos *= listPtr->startPos;
- return item->window.rect.y + 1 + SCROLLBAR_SIZE + pos;
- }
-}
-
-int Item_ListBox_ThumbDrawPosition(itemDef_t *item) {
- int min, max;
-
- if (itemCapture == item) {
- if (item->window.flags & WINDOW_HORIZONTAL) {
- min = item->window.rect.x + SCROLLBAR_SIZE + 1;
- max = item->window.rect.x + item->window.rect.w - 2*SCROLLBAR_SIZE - 1;
- if (DC->cursorx >= min + SCROLLBAR_SIZE/2 && DC->cursorx <= max + SCROLLBAR_SIZE/2) {
- return DC->cursorx - SCROLLBAR_SIZE/2;
- }
- else {
- return Item_ListBox_ThumbPosition(item);
- }
- }
- else {
- min = item->window.rect.y + SCROLLBAR_SIZE + 1;
- max = item->window.rect.y + item->window.rect.h - 2*SCROLLBAR_SIZE - 1;
- if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) {
- return DC->cursory - SCROLLBAR_SIZE/2;
- }
- else {
- return Item_ListBox_ThumbPosition(item);
- }
- }
- }
- else {
- return Item_ListBox_ThumbPosition(item);
- }
+ if (i == DC->Assets.emoticonCount)
+ return qfalse;
+
+ if (h)
+ *h = DC->Assets.emoticons[i].shader;
+ if (width)
+ *width = DC->Assets.emoticons[i].width;
+
+ (*length) += 2;
+
+ if (*escaped)
+ (*length)++;
+
+ return qtrue;
}
-float Item_Slider_ThumbPosition(itemDef_t *item) {
- float value, range, x;
- editFieldDef_t *editDef = item->typeData;
+static float UI_Parse_Indent(const char **text)
+{
+ char indentWidth[32];
+ char *indentWidthPtr;
+ const char *p = *text;
+ int numDigits;
+ float pixels;
- if (item->text) {
- x = item->textRect.x + item->textRect.w + 8;
- } else {
- x = item->window.rect.x;
- }
+ while (isdigit(*p) || *p == '.')
+ p++;
- if (editDef == NULL && item->cvar) {
- return x;
- }
-
- value = DC->getCVarValue(item->cvar);
-
- if (value < editDef->minVal) {
- value = editDef->minVal;
- } else if (value > editDef->maxVal) {
- value = editDef->maxVal;
- }
-
- range = editDef->maxVal - editDef->minVal;
- value -= editDef->minVal;
- value /= range;
- //value /= (editDef->maxVal - editDef->minVal);
- value *= SLIDER_WIDTH;
- x += value;
- // vm fuckage
- //x = x + (((float)value / editDef->maxVal) * SLIDER_WIDTH);
- return x;
-}
-
-int Item_Slider_OverSlider(itemDef_t *item, float x, float y) {
- rectDef_t r;
-
- r.x = Item_Slider_ThumbPosition(item) - (SLIDER_THUMB_WIDTH / 2);
- r.y = item->window.rect.y - 2;
- r.w = SLIDER_THUMB_WIDTH;
- r.h = SLIDER_THUMB_HEIGHT;
-
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_THUMB;
- }
- return 0;
-}
-
-int Item_ListBox_OverLB(itemDef_t *item, float x, float y) {
- rectDef_t r;
- listBoxDef_t *listPtr;
- int thumbstart;
- int count;
-
- count = DC->feederCount(item->special);
- listPtr = (listBoxDef_t*)item->typeData;
- if (item->window.flags & WINDOW_HORIZONTAL) {
- // check if on left arrow
- r.x = item->window.rect.x;
- r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
- r.h = r.w = SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_LEFTARROW;
- }
- // check if on right arrow
- r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_RIGHTARROW;
- }
- // check if on thumb
- thumbstart = Item_ListBox_ThumbPosition(item);
- r.x = thumbstart;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_THUMB;
- }
- r.x = item->window.rect.x + SCROLLBAR_SIZE;
- r.w = thumbstart - r.x;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGUP;
- }
- r.x = thumbstart + SCROLLBAR_SIZE;
- r.w = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGDN;
- }
- } else {
- r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
- r.y = item->window.rect.y;
- r.h = r.w = SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_LEFTARROW;
- }
- r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_RIGHTARROW;
- }
- thumbstart = Item_ListBox_ThumbPosition(item);
- r.y = thumbstart;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_THUMB;
- }
- r.y = item->window.rect.y + SCROLLBAR_SIZE;
- r.h = thumbstart - r.y;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGUP;
- }
- r.y = thumbstart + SCROLLBAR_SIZE;
- r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGDN;
- }
- }
- return 0;
+ if (*p != INDENT_MARKER)
+ return 0.0f;
+
+ numDigits = (p - *text);
+
+ if (numDigits > sizeof(indentWidth) - 1)
+ return 0.0f;
+
+ strncpy(indentWidth, *text, numDigits);
+
+ indentWidth[numDigits] = '\0';
+ indentWidthPtr = indentWidth;
+
+ if (!Float_Parse(&indentWidthPtr, &pixels))
+ return 0.0f;
+
+ (*text) += (numDigits + 1);
+
+ return pixels;
}
+static ID_INLINE fontInfo_t *UI_FontForScale(float scale)
+{
+ if (scale <= DC->smallFontScale)
+ return &DC->Assets.smallFont;
+ else if (scale >= DC->bigFontScale)
+ return &DC->Assets.bigFont;
+ else
+ return &DC->Assets.textFont;
+}
-void Item_ListBox_MouseEnter(itemDef_t *item, float x, float y)
+float UI_Char_Width(const char **text, float scale)
{
- rectDef_t r;
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
-
- item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN);
- item->window.flags |= Item_ListBox_OverLB(item, x, y);
-
- if (item->window.flags & WINDOW_HORIZONTAL) {
- if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
- // check for selection hit as we have exausted buttons and thumb
- if (listPtr->elementStyle == LISTBOX_IMAGE) {
- r.x = item->window.rect.x;
- r.y = item->window.rect.y;
- r.h = item->window.rect.h - SCROLLBAR_SIZE;
- r.w = item->window.rect.w - listPtr->drawPadding;
- if (Rect_ContainsPoint(&r, x, y)) {
- listPtr->cursorPos = (int)((x - r.x) / listPtr->elementWidth) + listPtr->startPos;
- if (listPtr->cursorPos >= listPtr->endPos) {
- listPtr->cursorPos = listPtr->endPos;
- }
- }
- } else {
- // text hit..
- }
- }
- } else if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
- r.x = item->window.rect.x;
- r.y = item->window.rect.y;
- r.w = item->window.rect.w - SCROLLBAR_SIZE;
- r.h = item->window.rect.h - listPtr->drawPadding;
- if (Rect_ContainsPoint(&r, x, y)) {
- listPtr->cursorPos = (int)((y - 2 - r.y) / listPtr->elementHeight) + listPtr->startPos;
- if (listPtr->cursorPos > listPtr->endPos) {
- listPtr->cursorPos = listPtr->endPos;
- }
- }
- }
-}
-
-void Item_MouseEnter(itemDef_t *item, float x, float y) {
- rectDef_t r;
- if (item) {
- r = item->textRect;
- r.y -= r.h;
- // in the text rect?
+ glyphInfo_t *glyph;
+ fontInfo_t *font;
+ int emoticonLen;
+ qboolean emoticonEscaped;
+ int emoticonWidth;
- // items can be enabled and disabled based on cvars
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- return;
- }
+ if (text && *text)
+ {
+ if (Q_IsColorString(*text))
+ {
+ *text += 2;
+ return 0.0f;
+ }
- if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
- return;
- }
+ if (**text == INDENT_MARKER)
+ {
+ (*text)++;
+ return 0.0f;
+ }
- if (Rect_ContainsPoint(&r, x, y)) {
- if (!(item->window.flags & WINDOW_MOUSEOVERTEXT)) {
- Item_RunScript(item, item->mouseEnterText);
- item->window.flags |= WINDOW_MOUSEOVERTEXT;
- }
- if (!(item->window.flags & WINDOW_MOUSEOVER)) {
- Item_RunScript(item, item->mouseEnter);
- item->window.flags |= WINDOW_MOUSEOVER;
- }
+ font = UI_FontForScale(scale);
- } else {
- // not in the text rect
- if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
- // if we were
- Item_RunScript(item, item->mouseExitText);
- item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
- }
- if (!(item->window.flags & WINDOW_MOUSEOVER)) {
- Item_RunScript(item, item->mouseEnter);
- item->window.flags |= WINDOW_MOUSEOVER;
- }
+ if (UI_Text_IsEmoticon(*text, &emoticonEscaped, &emoticonLen, NULL, &emoticonWidth))
+ {
+ if (emoticonEscaped)
+ (*text)++;
+ else
+ {
+ *text += emoticonLen;
+ return emoticonWidth * UI_EmoticonWidth(font, scale);
+ }
+ }
+
+ (*text)++;
- if (item->type == ITEM_TYPE_LISTBOX) {
- Item_ListBox_MouseEnter(item, x, y);
- }
+ glyph = &font->glyphs[(int)**text];
+ return glyph->xSkip * DC->aspectScale * scale * font->glyphScale;
}
- }
+
+ return 0.0f;
}
-void Item_MouseLeave(itemDef_t *item) {
- if (item) {
- if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
- Item_RunScript(item, item->mouseExitText);
- item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
+float UI_Text_Width(const char *text, float scale)
+{
+ float out;
+ const char *s = text;
+ float indentWidth = 0.0f;
+
+ out = 0.0f;
+
+ if (text)
+ {
+ indentWidth = UI_Parse_Indent(&s);
+
+ while (*s)
+ out += UI_Char_Width(&s, scale);
}
- Item_RunScript(item, item->mouseExit);
- item->window.flags &= ~(WINDOW_LB_RIGHTARROW | WINDOW_LB_LEFTARROW);
- }
+
+ return out + indentWidth;
}
-itemDef_t *Menu_HitTest(menuDef_t *menu, float x, float y) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
- return menu->items[i];
+float UI_Text_Height(const char *text, float scale)
+{
+ float max;
+ glyphInfo_t *glyph;
+ float useScale;
+ const char *s = text;
+ fontInfo_t *font = UI_FontForScale(scale);
+
+ useScale = scale * font->glyphScale;
+ max = 0;
+
+ if (text)
+ {
+ while (s && *s)
+ {
+ if (Q_IsColorString(s))
+ {
+ s += 2;
+ continue;
+ }
+ else
+ {
+ glyph = &font->glyphs[(int)*s];
+
+ if (max < glyph->height)
+ max = glyph->height;
+
+ s++;
+ }
+ }
}
- }
- return NULL;
+
+ return max * useScale;
}
-void Item_SetMouseOver(itemDef_t *item, qboolean focus) {
- if (item) {
- if (focus) {
- item->window.flags |= WINDOW_MOUSEOVER;
- } else {
- item->window.flags &= ~WINDOW_MOUSEOVER;
- }
- }
+float UI_Text_EmWidth(float scale) { return UI_Text_Width("M", scale); }
+
+float UI_Text_EmHeight(float scale) { return UI_Text_Height("M", scale); }
+
+/*
+================
+UI_AdjustFrom640
+
+Adjusted for resolution and screen aspect ratio
+================
+*/
+void UI_AdjustFrom640(float *x, float *y, float *w, float *h)
+{
+ *x *= DC->xscale;
+ *y *= DC->yscale;
+ *w *= DC->xscale;
+ *h *= DC->yscale;
}
+/*
+================
+UI_SetClipRegion
+=================
+*/
+void UI_SetClipRegion(float x, float y, float w, float h)
+{
+ vec4_t clip;
+
+ UI_AdjustFrom640(&x, &y, &w, &h);
-qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key) {
- if (item && DC->ownerDrawHandleKey) {
- return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key);
- }
- return qfalse;
+ clip[0] = x;
+ clip[1] = y;
+ clip[2] = x + w;
+ clip[3] = y + h;
+
+ trap_R_SetClipRegion(clip);
}
-qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force) {
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
- int count = DC->feederCount(item->special);
- int max, viewmax;
+/*
+================
+UI_ClearClipRegion
+=================
+*/
+void UI_ClearClipRegion(void) { trap_R_SetClipRegion(NULL); }
- if (force || (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS)) {
- max = Item_ListBox_MaxScroll(item);
- if (item->window.flags & WINDOW_HORIZONTAL) {
- viewmax = (item->window.rect.w / listPtr->elementWidth);
- if ( key == K_LEFTARROW || key == K_KP_LEFTARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos--;
- if (listPtr->cursorPos < 0) {
- listPtr->cursorPos = 0;
- }
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos--;
- if (listPtr->startPos < 0)
- listPtr->startPos = 0;
+static void UI_Text_PaintChar(float x, float y, float scale, glyphInfo_t *glyph, float size)
+{
+ float w, h;
+
+ w = glyph->imageWidth;
+ h = glyph->imageHeight;
+
+ if (size > 0.0f)
+ {
+ float half = size * 0.5f * scale;
+ x -= half;
+ y -= half;
+ w += size;
+ h += size;
+ }
+
+ w *= (DC->aspectScale * scale);
+ h *= scale;
+ y -= (glyph->top * scale);
+ UI_AdjustFrom640(&x, &y, &w, &h);
+
+ DC->drawStretchPic(x, y, w, h, glyph->s, glyph->t, glyph->s2, glyph->t2, glyph->glyph);
+}
+
+static void UI_Text_Paint_Generic(float x, float y, float scale, float gapAdjust, const char *text, vec4_t color,
+ int style, int limit, float *maxX, int cursorPos, char cursor)
+{
+ const char *s = text;
+ int len;
+ int count = 0;
+ vec4_t newColor;
+ fontInfo_t *font = UI_FontForScale(scale);
+ glyphInfo_t *glyph;
+ float useScale;
+ qhandle_t emoticonHandle = 0;
+ float emoticonH, emoticonW;
+ qboolean emoticonEscaped;
+ int emoticonLen = 0;
+ int emoticonWidth;
+ int cursorX = -1;
+
+ if (!text)
+ return;
+
+ useScale = scale * font->glyphScale;
+
+ emoticonH = UI_EmoticonHeight(font, scale);
+ emoticonW = UI_EmoticonWidth(font, scale);
+
+ len = strlen(text);
+ if (limit > 0 && len > limit)
+ len = limit;
+
+ DC->setColor(color);
+ memcpy(&newColor[0], &color[0], sizeof(vec4_t));
+
+ x += UI_Parse_Indent(&s);
+
+ while (s && *s && count < len)
+ {
+ const char *t = s;
+ float charWidth = UI_Char_Width(&t, scale);
+ glyph = &font->glyphs[(int)*s];
+
+ if (maxX && charWidth + x > *maxX)
+ {
+ *maxX = 0;
+ break;
}
- return qtrue;
- }
- if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos++;
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= count) {
- listPtr->cursorPos = count-1;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos++;
- if (listPtr->startPos >= count)
- listPtr->startPos = count-1;
+
+ if (cursorPos < 0)
+ {
+ if (Q_IsColorString(s))
+ {
+ memcpy(newColor, g_color_table[ColorIndex(*(s + 1))], sizeof(newColor));
+ newColor[3] = color[3];
+ DC->setColor(newColor);
+ s += 2;
+ continue;
+ }
+
+ if (*s == INDENT_MARKER)
+ {
+ s++;
+ continue;
+ }
+
+ if (UI_Text_IsEmoticon(s, &emoticonEscaped, &emoticonLen, &emoticonHandle, &emoticonWidth))
+ {
+ if (emoticonEscaped)
+ s++;
+ else
+ {
+ float yadj = useScale * glyph->top;
+
+ DC->setColor(NULL);
+ DC->drawHandlePic(x, y - yadj, (emoticonW * emoticonWidth), emoticonH, emoticonHandle);
+ DC->setColor(newColor);
+ x += (emoticonW * emoticonWidth) + gapAdjust;
+ s += emoticonLen;
+ count += emoticonWidth;
+ continue;
+ }
+ }
}
- return qtrue;
- }
- }
- else {
- viewmax = (item->window.rect.h / listPtr->elementHeight);
- if ( key == K_UPARROW || key == K_KP_UPARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos--;
- if (listPtr->cursorPos < 0) {
- listPtr->cursorPos = 0;
- }
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos--;
- if (listPtr->startPos < 0)
- listPtr->startPos = 0;
+
+ if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE)
+ {
+ int ofs;
+
+ if (style == ITEM_TEXTSTYLE_SHADOWED)
+ ofs = 1;
+ else
+ ofs = 2;
+ colorBlack[3] = newColor[3];
+ DC->setColor(colorBlack);
+ UI_Text_PaintChar(x + ofs, y + ofs, useScale, glyph, 0.0f);
+ DC->setColor(newColor);
+ colorBlack[3] = 1.0f;
}
- return qtrue;
- }
- if ( key == K_DOWNARROW || key == K_KP_DOWNARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos++;
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= count) {
- listPtr->cursorPos = count-1;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos++;
- if (listPtr->startPos > max)
- listPtr->startPos = max;
+ else if (style == ITEM_TEXTSTYLE_NEON)
+ {
+ vec4_t glow;
+
+ memcpy(&glow[0], &newColor[0], sizeof(vec4_t));
+ glow[3] *= 0.2f;
+
+ DC->setColor(glow);
+ UI_Text_PaintChar(x, y, useScale, glyph, 6.0f);
+ UI_Text_PaintChar(x, y, useScale, glyph, 4.0f);
+ DC->setColor(newColor);
+ UI_Text_PaintChar(x, y, useScale, glyph, 2.0f);
+
+ DC->setColor(colorWhite);
}
- return qtrue;
- }
- }
- // mouse hit
- if (key == K_MOUSE1 || key == K_MOUSE2) {
- if (item->window.flags & WINDOW_LB_LEFTARROW) {
- listPtr->startPos--;
- if (listPtr->startPos < 0) {
- listPtr->startPos = 0;
- }
- } else if (item->window.flags & WINDOW_LB_RIGHTARROW) {
- // one down
- listPtr->startPos++;
- if (listPtr->startPos > max) {
- listPtr->startPos = max;
- }
- } else if (item->window.flags & WINDOW_LB_PGUP) {
- // page up
- listPtr->startPos -= viewmax;
- if (listPtr->startPos < 0) {
- listPtr->startPos = 0;
- }
- } else if (item->window.flags & WINDOW_LB_PGDN) {
- // page down
- listPtr->startPos += viewmax;
- if (listPtr->startPos > max) {
- listPtr->startPos = max;
- }
- } else if (item->window.flags & WINDOW_LB_THUMB) {
- // Display_SetCaptureItem(item);
- } else {
- // select an item
- if (DC->realTime < lastListBoxClickTime && listPtr->doubleClick) {
- Item_RunScript(item, listPtr->doubleClick);
- }
- lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY;
- if (item->cursorPos != listPtr->cursorPos) {
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- }
- return qtrue;
- }
-
- // Scroll wheel
- if (key == K_MWHEELUP) {
- listPtr->startPos--;
- if (listPtr->startPos < 0) {
- listPtr->startPos = 0;
- }
- return qtrue;
+
+ UI_Text_PaintChar(x, y, useScale, glyph, 0.0f);
+
+ if (count == cursorPos)
+ cursorX = x;
+
+ x += (glyph->xSkip * DC->aspectScale * useScale) + gapAdjust;
+ s++;
+ count++;
}
- if (key == K_MWHEELDOWN) {
- listPtr->startPos++;
- if (listPtr->startPos > max) {
- listPtr->startPos = max;
- }
- return qtrue;
+
+ if (maxX)
+ *maxX = x;
+
+ // paint cursor
+ if (cursorPos >= 0)
+ {
+ if (cursorPos == len)
+ cursorX = x;
+
+ if (cursorX >= 0 && !((DC->realTime / BLINK_DIVISOR) & 1))
+ {
+ glyph = &font->glyphs[(int)cursor];
+ UI_Text_PaintChar(cursorX, y, useScale, glyph, 0.0f);
+ }
}
- // Invoke the doubleClick handler when enter is pressed
- if( key == K_ENTER )
+ DC->setColor(NULL);
+}
+
+void UI_Text_Paint_Limit(
+ float *maxX, float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit)
+{
+ UI_Text_Paint_Generic(x, y, scale, adjust, text, color, ITEM_TEXTSTYLE_NORMAL, limit, maxX, -1, 0);
+}
+
+void UI_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style)
+{
+ UI_Text_Paint_Generic(x, y, scale, adjust, text, color, style, limit, NULL, -1, 0);
+}
+
+void UI_Text_PaintWithCursor(
+ float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style)
+{
+ UI_Text_Paint_Generic(x, y, scale, 0.0, text, color, style, limit, NULL, cursorPos, cursor);
+}
+
+commandDef_t commandList[] = {
+ {"close", &Script_Close}, // menu
+ {"conditionalopen", &Script_ConditionalOpen}, // menu
+ {"exec", &Script_Exec}, // group/name
+ {"fadein", &Script_FadeIn}, // group/name
+ {"fadeout", &Script_FadeOut}, // group/name
+ {"hide", &Script_Hide}, // group/name
+ {"open", &Script_Open}, // menu
+ {"orbit", &Script_Orbit}, // group/name
+ {"play", &Script_Play}, // group/name
+ {"playlooped", &Script_playLooped}, // group/name
+ {"reset", &Script_Reset}, // resets the state of the item argument
+ {"setasset", &Script_SetAsset}, // works on this
+ {"setbackground", &Script_SetBackground}, // works on this
+ {"setcolor", &Script_SetColor}, // works on this
+ {"setcvar", &Script_SetCvar}, // group/name
+ {"setfocus", &Script_SetFocus}, // sets this background color to team color
+ {"setitemcolor", &Script_SetItemColor}, // group/name
+ {"setplayerhead", &Script_SetPlayerHead}, // sets this background color to team color
+ {"setplayermodel", &Script_SetPlayerModel}, // sets this background color to team color
+ {"show", &Script_Show}, // group/name
+ {"transition", &Script_Transition}, // group/name
+};
+
+static size_t scriptCommandCount = ARRAY_LEN(commandList);
+
+// despite what lcc thinks, we do not get cmdcmp here
+static int commandComp(const void *a, const void *b) { return Q_stricmp((const char *)a, ((commandDef_t *)b)->name); }
+
+void Item_RunScript(itemDef_t *item, const char *s)
+{
+ char script[1024], *p;
+ commandDef_t *cmd;
+ memset(script, 0, sizeof(script));
+
+ if (item && s && s[0])
{
- if( listPtr->doubleClick )
- Item_RunScript( item, listPtr->doubleClick );
+ Q_strcat(script, 1024, s);
+ p = script;
+
+ while (1)
+ {
+ const char *command;
+ // expect command then arguments, ; ends command, NULL ends script
+
+ if (!String_Parse(&p, &command))
+ return;
+
+ if (command[0] == ';' && command[1] == '\0')
+ continue;
- return qtrue;
+ cmd = bsearch(command, commandList, scriptCommandCount, sizeof(commandDef_t), commandComp);
+ if (cmd)
+ cmd->handler(item, &p);
+ else
+ // not in our auto list, pass to handler
+ DC->runScript(&p);
+ }
}
+}
- if ( key == K_HOME || key == K_KP_HOME) {
- // home
- listPtr->startPos = 0;
- return qtrue;
+qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag)
+{
+ char script[1024], *p;
+ memset(script, 0, sizeof(script));
+
+ if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest)
+ {
+ char buff[1024];
+ DC->getCVarString(item->cvarTest, buff, sizeof(buff));
+
+ Q_strcat(script, 1024, item->enableCvar);
+ p = script;
+
+ while (1)
+ {
+ const char *val;
+ // expect value then ; or NULL, NULL ends list
+
+ if (!String_Parse(&p, &val))
+ return (item->cvarFlags & flag) ? qfalse : qtrue;
+
+ if (val[0] == ';' && val[1] == '\0')
+ continue;
+
+ // enable it if any of the values are true
+ if (item->cvarFlags & flag)
+ {
+ if (Q_stricmp(buff, val) == 0)
+ return qtrue;
+ }
+ else
+ {
+ // disable it if any of the values are true
+
+ if (Q_stricmp(buff, val) == 0)
+ return qfalse;
+ }
+ }
+
+ return (item->cvarFlags & flag) ? qfalse : qtrue;
}
- if ( key == K_END || key == K_KP_END) {
- // end
- listPtr->startPos = max;
- return qtrue;
+
+ return qtrue;
+}
+
+// will optionaly set focus to this item
+qboolean Item_SetFocus(itemDef_t *item, float x, float y)
+{
+ int i;
+ itemDef_t *oldFocus;
+ sfxHandle_t *sfx = &DC->Assets.itemFocusSound;
+ qboolean playSound = qfalse;
+ menuDef_t *parent;
+ // sanity check, non-null, not a decoration and does not already have the focus
+
+ if (item == NULL || item->window.flags & WINDOW_DECORATION || item->window.flags & WINDOW_HASFOCUS ||
+ !(item->window.flags & WINDOW_VISIBLE))
+ {
+ return qfalse;
}
- if (key == K_PGUP || key == K_KP_PGUP ) {
- // page up
- if (!listPtr->notselectable) {
- listPtr->cursorPos -= viewmax;
- if (listPtr->cursorPos < 0) {
- listPtr->cursorPos = 0;
- }
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
+
+ parent = (menuDef_t *)item->parent;
+
+ // items can be enabled and disabled based on cvars
+
+ if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE))
+ return qfalse;
+
+ if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW))
+ return qfalse;
+
+ oldFocus = Menu_ClearFocus(item->parent);
+
+ if (item->type == ITEM_TYPE_TEXT)
+ {
+ rectDef_t r;
+ r = item->textRect;
+ r.y -= r.h;
+
+ if (Rect_ContainsPoint(&r, x, y))
+ {
+ item->window.flags |= WINDOW_HASFOCUS;
+
+ if (item->focusSound)
+ sfx = &item->focusSound;
+
+ playSound = qtrue;
}
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
+ else
+ {
+ if (oldFocus)
+ {
+ oldFocus->window.flags |= WINDOW_HASFOCUS;
+
+ if (oldFocus->onFocus)
+ Item_RunScript(oldFocus, oldFocus->onFocus);
+ }
}
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos -= viewmax;
- if (listPtr->startPos < 0) {
- listPtr->startPos = 0;
+ }
+ else
+ {
+ item->window.flags |= WINDOW_HASFOCUS;
+
+ if (item->onFocus)
+ Item_RunScript(item, item->onFocus);
+
+ if (item->focusSound)
+ sfx = &item->focusSound;
+
+ playSound = qtrue;
+ }
+
+ if (playSound && sfx)
+ DC->startLocalSound(*sfx, CHAN_LOCAL_SOUND);
+
+ for (i = 0; i < parent->itemCount; i++)
+ {
+ if (parent->items[i] == item)
+ {
+ parent->cursorItem = i;
+ break;
}
- }
- return qtrue;
}
- if ( key == K_PGDN || key == K_KP_PGDN ) {
- // page down
- if (!listPtr->notselectable) {
- listPtr->cursorPos += viewmax;
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
+
+ return qtrue;
+}
+
+static float Item_ListBox_HeightForNumItems(itemDef_t *item, int numItems)
+{
+ listBoxDef_t *listPtr = item->typeData.list;
+
+ return (listPtr->elementHeight * numItems) + 2.0f;
+}
+
+static int Item_ListBox_NumItemsForItemHeight(itemDef_t *item)
+{
+ listBoxDef_t *listPtr = item->typeData.list;
+
+ if (item->type == ITEM_TYPE_COMBOBOX)
+ return listPtr->dropItems;
+ else
+ return ((item->window.rect.h - 2.0f) / listPtr->elementHeight);
+}
+
+int Item_ListBox_MaxScroll(itemDef_t *item)
+{
+ int total = DC->feederCount(item->feederID);
+ int max = total - Item_ListBox_NumItemsForItemHeight(item);
+
+ if (max < 0)
+ return 0;
+
+ return max;
+}
+
+static float oldComboBoxY;
+static float oldComboBoxH;
+
+static qboolean Item_ComboBox_MaybeCastToListBox(itemDef_t *item)
+{
+ listBoxDef_t *listPtr = item->typeData.list;
+ qboolean cast = g_comboBoxItem != NULL && (item->type == ITEM_TYPE_COMBOBOX);
+
+ if (cast)
+ {
+ oldComboBoxY = item->window.rect.y;
+ oldComboBoxH = item->window.rect.h;
+
+ item->window.rect.y += item->window.rect.h;
+ item->window.rect.h = Item_ListBox_HeightForNumItems(item, listPtr->dropItems);
+ item->type = ITEM_TYPE_LISTBOX;
+ }
+
+ return cast;
+}
+
+static void Item_ComboBox_MaybeUnCastFromListBox(itemDef_t *item, qboolean unCast)
+{
+ if (unCast)
+ {
+ item->window.rect.y = oldComboBoxY;
+ item->window.rect.h = oldComboBoxH;
+ item->type = ITEM_TYPE_COMBOBOX;
+ }
+}
+
+static void Item_ListBox_SetStartPos(itemDef_t *item, int startPos)
+{
+ listBoxDef_t *listPtr = item->typeData.list;
+ int total = DC->feederCount(item->feederID);
+ int max = Item_ListBox_MaxScroll(item);
+
+ if (startPos < 0)
+ listPtr->startPos = 0;
+ else if (startPos > max)
+ listPtr->startPos = max;
+ else
+ listPtr->startPos = startPos;
+
+ listPtr->endPos = listPtr->startPos + MIN((total - listPtr->startPos), Item_ListBox_NumItemsForItemHeight(item));
+}
+
+float Item_ListBox_ThumbPosition(itemDef_t *item)
+{
+ float max, pos, size;
+ float startPos = (float)item->typeData.list->startPos;
+
+ max = Item_ListBox_MaxScroll(item);
+ size = SCROLLBAR_SLIDER_HEIGHT(item);
+
+ if (max > 0.0f)
+ pos = (size - SCROLLBAR_ARROW_HEIGHT) / max;
+ else
+ pos = 0.0f;
+
+ pos *= startPos;
+
+ return SCROLLBAR_SLIDER_Y(item) + pos;
+}
+
+float Item_ListBox_ThumbDrawPosition(itemDef_t *item)
+{
+ if (itemCapture == item)
+ {
+ float min = SCROLLBAR_SLIDER_Y(item);
+ float max = min + SCROLLBAR_SLIDER_HEIGHT(item) - SCROLLBAR_ARROW_HEIGHT;
+ float halfThumbSize = SCROLLBAR_ARROW_HEIGHT / 2.0f;
+
+ if (DC->cursory >= min + halfThumbSize && DC->cursory <= max + halfThumbSize)
+ return DC->cursory - halfThumbSize;
+ }
+
+ return Item_ListBox_ThumbPosition(item);
+}
+
+float Item_Slider_ThumbPosition(itemDef_t *item)
+{
+ float value, range, x;
+ editFieldDef_t *editDef = item->typeData.edit;
+
+ if (item->text)
+ x = item->textRect.x + item->textRect.w + ITEM_VALUE_OFFSET;
+ else
+ x = item->window.rect.x;
+
+ if (editDef == NULL && item->cvar)
+ return x;
+
+ value = DC->getCVarValue(item->cvar);
+
+ if (value < editDef->minVal)
+ value = editDef->minVal;
+ else if (value > editDef->maxVal)
+ value = editDef->maxVal;
+
+ range = editDef->maxVal - editDef->minVal;
+ value -= editDef->minVal;
+ value /= range;
+ value *= SLIDER_WIDTH;
+ x += value;
+
+ return x;
+}
+
+static float Item_Slider_VScale(itemDef_t *item)
+{
+ if (SLIDER_THUMB_HEIGHT > item->window.rect.h)
+ return item->window.rect.h / SLIDER_THUMB_HEIGHT;
+ else
+ return 1.0f;
+}
+
+int Item_Slider_OverSlider(itemDef_t *item, float x, float y)
+{
+ rectDef_t r;
+ float vScale = Item_Slider_VScale(item);
+
+ r.x = Item_Slider_ThumbPosition(item) - (SLIDER_THUMB_WIDTH / 2);
+ r.y = item->textRect.y - item->textRect.h + ((item->textRect.h - (SLIDER_THUMB_HEIGHT * vScale)) / 2.0f);
+ r.w = SLIDER_THUMB_WIDTH;
+ r.h = SLIDER_THUMB_HEIGHT * vScale;
+
+ if (Rect_ContainsPoint(&r, x, y))
+ return WINDOW_LB_THUMB;
+
+ return 0;
+}
+
+int Item_ListBox_OverLB(itemDef_t *item, float x, float y)
+{
+ rectDef_t r;
+ int thumbstart;
+
+ r.x = SCROLLBAR_SLIDER_X(item);
+ r.y = SCROLLBAR_Y(item);
+ r.w = SCROLLBAR_ARROW_WIDTH;
+ r.h = SCROLLBAR_ARROW_HEIGHT;
+
+ if (Rect_ContainsPoint(&r, x, y))
+ return WINDOW_LB_UPARROW;
+
+ r.y = SCROLLBAR_SLIDER_Y(item) + SCROLLBAR_SLIDER_HEIGHT(item);
+
+ if (Rect_ContainsPoint(&r, x, y))
+ return WINDOW_LB_DOWNARROW;
+
+ thumbstart = Item_ListBox_ThumbPosition(item);
+ r.y = thumbstart;
+
+ if (Rect_ContainsPoint(&r, x, y))
+ return WINDOW_LB_THUMB;
+
+ r.y = SCROLLBAR_SLIDER_Y(item);
+ r.h = thumbstart - r.y;
+
+ if (Rect_ContainsPoint(&r, x, y))
+ return WINDOW_LB_PGUP;
+
+ r.y = thumbstart + SCROLLBAR_ARROW_HEIGHT;
+ r.h = (SCROLLBAR_SLIDER_Y(item) + SCROLLBAR_SLIDER_HEIGHT(item)) - r.y;
+
+ if (Rect_ContainsPoint(&r, x, y))
+ return WINDOW_LB_PGDN;
+
+ return 0;
+}
+
+void Item_ListBox_MouseEnter(itemDef_t *item, float x, float y)
+{
+ rectDef_t r;
+ listBoxDef_t *listPtr = item->typeData.list;
+ int listBoxFlags = (WINDOW_LB_UPARROW | WINDOW_LB_DOWNARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN);
+ int total = DC->feederCount(item->feederID);
+
+ item->window.flags &= ~listBoxFlags;
+ item->window.flags |= Item_ListBox_OverLB(item, x, y);
+
+ if (!(item->window.flags & listBoxFlags))
+ {
+ r.x = SCROLLBAR_X(item);
+ r.y = SCROLLBAR_Y(item);
+ r.w = SCROLLBAR_W(item);
+ r.h = listPtr->elementHeight * MIN(Item_ListBox_NumItemsForItemHeight(item), total);
+
+ if (Rect_ContainsPoint(&r, x, y))
+ {
+ listPtr->cursorPos = (int)((y - r.y) / listPtr->elementHeight) + listPtr->startPos;
+
+ if (listPtr->cursorPos >= listPtr->endPos)
+ listPtr->cursorPos = listPtr->endPos - 1;
}
- if (listPtr->cursorPos >= count) {
- listPtr->cursorPos = count-1;
+ else
+ listPtr->cursorPos = -1;
+ }
+}
+
+void Item_MouseEnter(itemDef_t *item, float x, float y)
+{
+ rectDef_t r;
+
+ if (item)
+ {
+ r = item->textRect;
+ r.y -= r.h;
+ // in the text rect?
+
+ // items can be enabled and disabled based on cvars
+
+ if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE))
+ return;
+
+ if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW))
+ return;
+
+ if (Rect_ContainsPoint(&r, x, y))
+ {
+ if (!(item->window.flags & WINDOW_MOUSEOVERTEXT))
+ {
+ Item_RunScript(item, item->mouseEnterText);
+ item->window.flags |= WINDOW_MOUSEOVERTEXT;
+ }
+
+ if (!(item->window.flags & WINDOW_MOUSEOVER))
+ {
+ Item_RunScript(item, item->mouseEnter);
+ item->window.flags |= WINDOW_MOUSEOVER;
+ }
}
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
+ else
+ {
+ // not in the text rect
+
+ if (item->window.flags & WINDOW_MOUSEOVERTEXT)
+ {
+ // if we were
+ Item_RunScript(item, item->mouseExitText);
+ item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
+ }
+
+ if (!(item->window.flags & WINDOW_MOUSEOVER))
+ {
+ Item_RunScript(item, item->mouseEnter);
+ item->window.flags |= WINDOW_MOUSEOVER;
+ }
+
+ if (item->type == ITEM_TYPE_LISTBOX)
+ Item_ListBox_MouseEnter(item, x, y);
}
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos += viewmax;
- if (listPtr->startPos > max) {
- listPtr->startPos = max;
+ }
+}
+
+void Item_MouseLeave(itemDef_t *item)
+{
+ if (item)
+ {
+ if (item->window.flags & WINDOW_MOUSEOVERTEXT)
+ {
+ Item_RunScript(item, item->mouseExitText);
+ item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
}
- }
- return qtrue;
+
+ Item_RunScript(item, item->mouseExit);
+ item->window.flags &= ~(WINDOW_LB_DOWNARROW | WINDOW_LB_UPARROW);
}
- }
- return qfalse;
}
-qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) {
+itemDef_t *Menu_HitTest(menuDef_t *menu, float x, float y)
+{
+ int i;
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
- if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
- DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar)));
- return qtrue;
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y))
+ return menu->items[i];
}
- }
- return qfalse;
+ return NULL;
+}
+void Item_SetMouseOver(itemDef_t *item, qboolean focus)
+{
+ if (item)
+ {
+ if (focus)
+ item->window.flags |= WINDOW_MOUSEOVER;
+ else
+ item->window.flags &= ~WINDOW_MOUSEOVER;
+ }
}
-int Item_Multi_CountSettings(itemDef_t *item) {
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr == NULL) {
- return 0;
- }
- return multiPtr->count;
-}
-
-int Item_Multi_FindCvarByValue(itemDef_t *item) {
- char buff[1024];
- float value = 0;
- int i;
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr) {
- if (multiPtr->strDef) {
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- } else {
- value = DC->getCVarValue(item->cvar);
- }
- for (i = 0; i < multiPtr->count; i++) {
- if (multiPtr->strDef) {
- if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
- return i;
- }
- } else {
- if (multiPtr->cvarValue[i] == value) {
- return i;
- }
- }
- }
- }
- return 0;
-}
-
-const char *Item_Multi_Setting(itemDef_t *item) {
- char buff[1024];
- float value = 0;
- int i;
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr) {
- if (multiPtr->strDef) {
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- } else {
- value = DC->getCVarValue(item->cvar);
- }
- for (i = 0; i < multiPtr->count; i++) {
- if (multiPtr->strDef) {
- if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
- return multiPtr->cvarList[i];
- }
- } else {
- if (multiPtr->cvarValue[i] == value) {
- return multiPtr->cvarList[i];
- }
- }
- }
- }
- return "";
-}
-
-qboolean Item_Multi_HandleKey(itemDef_t *item, int key) {
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr) {
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
- if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
- int current = Item_Multi_FindCvarByValue(item) + 1;
- int max = Item_Multi_CountSettings(item);
- if ( current < 0 || current >= max ) {
- current = 0;
- }
- if (multiPtr->strDef) {
- DC->setCVar(item->cvar, multiPtr->cvarStr[current]);
- } else {
- float value = multiPtr->cvarValue[current];
- if (((float)((int) value)) == value) {
- DC->setCVar(item->cvar, va("%i", (int) value ));
- }
- else {
- DC->setCVar(item->cvar, va("%f", value ));
- }
+qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key)
+{
+ if (item && DC->ownerDrawHandleKey)
+ return DC->ownerDrawHandleKey(item->window.ownerDraw, key);
+
+ return qfalse;
+}
+
+qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force)
+{
+ listBoxDef_t *listPtr = item->typeData.list;
+ int count = DC->feederCount(item->feederID);
+ int viewmax;
+
+ if (force ||
+ (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS))
+ {
+ viewmax = Item_ListBox_NumItemsForItemHeight(item);
+
+ switch (key)
+ {
+ case K_MOUSE1:
+ case K_MOUSE2:
+ if (item->window.flags & WINDOW_LB_UPARROW)
+ Item_ListBox_SetStartPos(item, listPtr->startPos - 1);
+ else if (item->window.flags & WINDOW_LB_DOWNARROW)
+ Item_ListBox_SetStartPos(item, listPtr->startPos + 1);
+ else if (item->window.flags & WINDOW_LB_PGUP)
+ Item_ListBox_SetStartPos(item, listPtr->startPos - viewmax);
+ else if (item->window.flags & WINDOW_LB_PGDN)
+ Item_ListBox_SetStartPos(item, listPtr->startPos + viewmax);
+ else if (item->window.flags & WINDOW_LB_THUMB)
+ break; // Handled by capture function
+ else
+ {
+ // Select an item
+ qboolean runDoubleClick = qfalse;
+
+ // Mouse isn't over an item
+ if (listPtr->cursorPos < 0)
+ break;
+
+ if (item->cursorPos != listPtr->cursorPos)
+ {
+ item->cursorPos = listPtr->cursorPos;
+ DC->feederSelection(item->feederID, item->cursorPos);
+ }
+
+ runDoubleClick = DC->realTime < lastListBoxClickTime && listPtr->doubleClick;
+ lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY;
+
+ // Made a selection, so close combobox
+ if (g_comboBoxItem != NULL)
+ {
+ if (listPtr->doubleClick)
+ runDoubleClick = qtrue;
+
+ g_comboBoxItem = NULL;
+ }
+
+ if (runDoubleClick)
+ Item_RunScript(item, listPtr->doubleClick);
+ }
+
+ break;
+
+ case K_MWHEELUP:
+ Item_ListBox_SetStartPos(item, listPtr->startPos - 1);
+ break;
+
+ case K_MWHEELDOWN:
+ Item_ListBox_SetStartPos(item, listPtr->startPos + 1);
+ break;
+
+ case K_ENTER:
+ // Invoke the doubleClick handler when enter is pressed
+ if (listPtr->doubleClick)
+ Item_RunScript(item, listPtr->doubleClick);
+
+ break;
+
+ case K_PGUP:
+ case K_KP_PGUP:
+ if (!listPtr->notselectable)
+ {
+ listPtr->cursorPos -= viewmax;
+
+ if (listPtr->cursorPos < 0)
+ listPtr->cursorPos = 0;
+
+ if (listPtr->cursorPos < listPtr->startPos)
+ Item_ListBox_SetStartPos(item, listPtr->cursorPos);
+
+ if (listPtr->cursorPos >= listPtr->startPos + viewmax)
+ Item_ListBox_SetStartPos(item, listPtr->cursorPos - viewmax + 1);
+
+ item->cursorPos = listPtr->cursorPos;
+ DC->feederSelection(item->feederID, item->cursorPos);
+ }
+ else
+ Item_ListBox_SetStartPos(item, listPtr->startPos - viewmax);
+
+ break;
+
+ case K_PGDN:
+ case K_KP_PGDN:
+ if (!listPtr->notselectable)
+ {
+ listPtr->cursorPos += viewmax;
+
+ if (listPtr->cursorPos < listPtr->startPos)
+ Item_ListBox_SetStartPos(item, listPtr->cursorPos);
+
+ if (listPtr->cursorPos >= count)
+ listPtr->cursorPos = count - 1;
+
+ if (listPtr->cursorPos >= listPtr->startPos + viewmax)
+ Item_ListBox_SetStartPos(item, listPtr->cursorPos - viewmax + 1);
+
+ item->cursorPos = listPtr->cursorPos;
+ DC->feederSelection(item->feederID, item->cursorPos);
+ }
+ else
+ Item_ListBox_SetStartPos(item, listPtr->startPos + viewmax);
+
+ break;
+
+ default:
+ // Not handled
+ return qfalse;
}
+
return qtrue;
- }
}
- }
- return qfalse;
+
+ return qfalse;
}
-qboolean Item_TextField_HandleKey(itemDef_t *item, int key) {
- char buff[1024];
- int len;
- itemDef_t *newItem = NULL;
- editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
+qboolean Item_ComboBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force)
+{
+ if (g_comboBoxItem != NULL)
+ {
+ qboolean result;
- if (item->cvar) {
+ qboolean cast = Item_ComboBox_MaybeCastToListBox(item);
+ result = Item_ListBox_HandleKey(item, key, down, force);
+ Item_ComboBox_MaybeUnCastFromListBox(item, cast);
- memset(buff, 0, sizeof(buff));
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- len = strlen(buff);
- if (editPtr->maxChars && len > editPtr->maxChars) {
- len = editPtr->maxChars;
- }
- if ( key & K_CHAR_FLAG ) {
- key &= ~K_CHAR_FLAG;
+ if (!result)
+ g_comboBoxItem = NULL;
+ return result;
+ }
+ else
+ {
+ if (force ||
+ (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS))
+ {
+ if (key == K_MOUSE1 || key == K_MOUSE2)
+ {
+ g_comboBoxItem = item;
- if (key == 'h' - 'a' + 1 ) { // ctrl-h is backspace
- if ( item->cursorPos > 0 ) {
- memmove( &buff[item->cursorPos - 1], &buff[item->cursorPos], len + 1 - item->cursorPos);
- item->cursorPos--;
- if (item->cursorPos < editPtr->paintOffset) {
- editPtr->paintOffset--;
- }
+ return qtrue;
+ }
}
- DC->setCVar(item->cvar, buff);
- return qtrue;
- }
+ }
+ return qfalse;
+}
- //
- // ignore any non printable chars
- //
- if ( key < 32 || !item->cvar) {
- return qtrue;
+qboolean Item_YesNo_HandleKey(itemDef_t *item, int key)
+{
+ if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS &&
+ item->cvar)
+ {
+ if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3)
+ {
+ DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar)));
+ return qtrue;
}
+ }
+
+ return qfalse;
+}
+
+int Item_Multi_CountSettings(itemDef_t *item)
+{
+ if (item->typeData.multi == NULL)
+ return 0;
+
+ return item->typeData.multi->count;
+}
+
+int Item_Multi_FindCvarByValue(itemDef_t *item)
+{
+ char buff[1024];
+ float value = 0;
+ int i;
+ multiDef_t *multiPtr = item->typeData.multi;
+
+ if (multiPtr)
+ {
+ if (multiPtr->strDef)
+ DC->getCVarString(item->cvar, buff, sizeof(buff));
+ else
+ value = DC->getCVarValue(item->cvar);
- if (item->type == ITEM_TYPE_NUMERICFIELD) {
- if (key < '0' || key > '9') {
- return qfalse;
+ for (i = 0; i < multiPtr->count; i++)
+ {
+ if (multiPtr->strDef)
+ {
+ if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0)
+ return i;
+ }
+ else
+ {
+ if (multiPtr->cvarValue[i] == value)
+ return i;
+ }
}
- }
+ }
- if (!DC->getOverstrikeMode()) {
- if (( len == MAX_EDITFIELD - 1 ) || (editPtr->maxChars && len >= editPtr->maxChars)) {
- return qtrue;
+ return 0;
+}
+
+const char *Item_Multi_Setting(itemDef_t *item)
+{
+ char buff[1024];
+ float value = 0;
+ int i;
+ multiDef_t *multiPtr = item->typeData.multi;
+
+ if (multiPtr)
+ {
+ if (multiPtr->strDef)
+ DC->getCVarString(item->cvar, buff, sizeof(buff));
+ else
+ value = DC->getCVarValue(item->cvar);
+
+ for (i = 0; i < multiPtr->count; i++)
+ {
+ if (multiPtr->strDef)
+ {
+ if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0)
+ return multiPtr->cvarList[i];
+ }
+ else
+ {
+ if (multiPtr->cvarValue[i] == value)
+ return multiPtr->cvarList[i];
+ }
}
- memmove( &buff[item->cursorPos + 1], &buff[item->cursorPos], len + 1 - item->cursorPos );
- } else {
- if (editPtr->maxChars && item->cursorPos >= editPtr->maxChars) {
- return qtrue;
+ }
+
+ return "";
+}
+
+qboolean Item_Cycle_HandleKey(itemDef_t *item, int key)
+{
+ cycleDef_t *cyclePtr = item->typeData.cycle;
+ qboolean mouseOver = Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory);
+ int count = DC->feederCount(item->feederID);
+
+ if (cyclePtr)
+ {
+ if (item->window.flags & WINDOW_HASFOCUS)
+ {
+ if ((mouseOver && key == K_MOUSE1) || key == K_ENTER || key == K_RIGHTARROW || key == K_DOWNARROW)
+ {
+ if (count > 0)
+ cyclePtr->cursorPos = (cyclePtr->cursorPos + 1) % count;
+
+ DC->feederSelection(item->feederID, cyclePtr->cursorPos);
+
+ return qtrue;
+ }
+ else if ((mouseOver && key == K_MOUSE2) || key == K_LEFTARROW || key == K_UPARROW)
+ {
+ if (count > 0)
+ cyclePtr->cursorPos = (count + cyclePtr->cursorPos - 1) % count;
+
+ DC->feederSelection(item->feederID, cyclePtr->cursorPos);
+
+ return qtrue;
+ }
}
- }
+ }
+
+ return qfalse;
+}
- buff[item->cursorPos] = key;
+qboolean Item_Multi_HandleKey(itemDef_t *item, int key)
+{
+ qboolean mouseOver = Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory);
+ int max = Item_Multi_CountSettings(item);
+ qboolean changed = qfalse;
- DC->setCVar(item->cvar, buff);
+ if (item->typeData.multi)
+ {
+ if (item->window.flags & WINDOW_HASFOCUS && item->cvar && max > 0)
+ {
+ int current;
+
+ if ((mouseOver && key == K_MOUSE1) || key == K_ENTER || key == K_RIGHTARROW || key == K_DOWNARROW)
+ {
+ current = (Item_Multi_FindCvarByValue(item) + 1) % max;
+ changed = qtrue;
+ }
+ else if ((mouseOver && key == K_MOUSE2) || key == K_LEFTARROW || key == K_UPARROW)
+ {
+ current = (Item_Multi_FindCvarByValue(item) + max - 1) % max;
+ changed = qtrue;
+ }
- if (item->cursorPos < len + 1) {
- item->cursorPos++;
- if (editPtr->maxPaintChars && item->cursorPos > editPtr->maxPaintChars) {
- editPtr->paintOffset++;
+ if (changed)
+ {
+ if (item->typeData.multi->strDef)
+ DC->setCVar(item->cvar, item->typeData.multi->cvarStr[current]);
+ else
+ {
+ float value = item->typeData.multi->cvarValue[current];
+
+ if (((float)((int)value)) == value)
+ DC->setCVar(item->cvar, va("%i", (int)value));
+ else
+ DC->setCVar(item->cvar, va("%f", value));
+ }
+
+ return qtrue;
+ }
}
- }
+ }
+
+ return qfalse;
+}
- } else {
+#define MIN_FIELD_WIDTH 10
+#define EDIT_CURSOR_WIDTH 10
+
+static void Item_TextField_CalcPaintOffset(itemDef_t *item, char *buff)
+{
+ editFieldDef_t *editPtr = item->typeData.edit;
+
+ if (item->cursorPos < editPtr->paintOffset)
+ editPtr->paintOffset = item->cursorPos;
+ else
+ {
+ // If there is a maximum field width
- if ( key == K_DEL || key == K_KP_DEL ) {
- if ( item->cursorPos < len ) {
- memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos);
- DC->setCVar(item->cvar, buff);
+ if (editPtr->maxFieldWidth > 0)
+ {
+ // If the cursor is at the end of the string, maximise the amount of the
+ // string that's visible
+
+ if (buff[item->cursorPos + 1] == '\0')
+ {
+ while (UI_Text_Width(&buff[editPtr->paintOffset], item->textscale) <=
+ (editPtr->maxFieldWidth - EDIT_CURSOR_WIDTH) &&
+ editPtr->paintOffset > 0)
+ editPtr->paintOffset--;
+ }
+
+ buff[item->cursorPos + 1] = '\0';
+
+ // Shift paintOffset so that the cursor is visible
+
+ while (UI_Text_Width(&buff[editPtr->paintOffset], item->textscale) >
+ (editPtr->maxFieldWidth - EDIT_CURSOR_WIDTH))
+ editPtr->paintOffset++;
}
- return qtrue;
- }
+ }
+}
- if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
- {
- if (editPtr->maxPaintChars && item->cursorPos >= editPtr->maxPaintChars && item->cursorPos < len) {
- item->cursorPos++;
- editPtr->paintOffset++;
- return qtrue;
+qboolean Item_TextField_HandleKey(itemDef_t *item, int key)
+{
+ char buff[1024];
+ int len;
+ itemDef_t *newItem = NULL;
+ editFieldDef_t *editPtr = item->typeData.edit;
+ qboolean releaseFocus = qtrue;
+
+ if (item->cvar)
+ {
+ Com_Memset(buff, 0, sizeof(buff));
+ DC->getCVarString(item->cvar, buff, sizeof(buff));
+ len = strlen(buff);
+
+ if (len < item->cursorPos)
+ item->cursorPos = len;
+
+ if (editPtr->maxChars && len > editPtr->maxChars)
+ len = editPtr->maxChars;
+
+ if (key & K_CHAR_FLAG)
+ {
+ key &= ~K_CHAR_FLAG;
+
+ if (key == 'h' - 'a' + 1)
+ {
+ // ctrl-h is backspace
+
+ if (item->cursorPos > 0)
+ {
+ memmove(&buff[item->cursorPos - 1], &buff[item->cursorPos], len + 1 - item->cursorPos);
+ item->cursorPos--;
+ }
+
+ DC->setCVar(item->cvar, buff);
+ }
+ else if (key < 32 || !item->cvar)
+ {
+ // Ignore any non printable chars
+ releaseFocus = qfalse;
+ goto exit;
+ }
+ else if (item->type == ITEM_TYPE_NUMERICFIELD && (key < '0' || key > '9'))
+ {
+ // Ignore non-numeric characters
+ releaseFocus = qfalse;
+ goto exit;
+ }
+ else
+ {
+ if (!DC->getOverstrikeMode())
+ {
+ if ((len == MAX_EDITFIELD - 1) || (editPtr->maxChars && len >= editPtr->maxChars))
+ {
+ // Reached maximum field length
+ releaseFocus = qfalse;
+ goto exit;
+ }
+
+ memmove(&buff[item->cursorPos + 1], &buff[item->cursorPos], len + 1 - item->cursorPos);
+ }
+ else
+ {
+ // Reached maximum field length
+ if (editPtr->maxChars && item->cursorPos >= editPtr->maxChars)
+ {
+ releaseFocus = qfalse;
+ goto exit;
+ }
+ }
+
+ buff[item->cursorPos] = key;
+
+ DC->setCVar(item->cvar, buff);
+
+ if (item->cursorPos < len + 1)
+ item->cursorPos++;
+ }
}
- if (item->cursorPos < len) {
- item->cursorPos++;
+ else
+ {
+ switch (key)
+ {
+ case K_DEL:
+ case K_KP_DEL:
+ if (item->cursorPos < len)
+ {
+ memmove(buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos);
+ DC->setCVar(item->cvar, buff);
+ }
+
+ break;
+
+ case K_RIGHTARROW:
+ case K_KP_RIGHTARROW:
+ if (item->cursorPos < len)
+ item->cursorPos++;
+
+ break;
+
+ case K_LEFTARROW:
+ case K_KP_LEFTARROW:
+ if (item->cursorPos > 0)
+ item->cursorPos--;
+
+ break;
+
+ case K_HOME:
+ case K_KP_HOME:
+ item->cursorPos = 0;
+
+ break;
+
+ case K_END:
+ case K_KP_END:
+ item->cursorPos = len;
+
+ break;
+
+ case K_INS:
+ case K_KP_INS:
+ DC->setOverstrikeMode(!DC->getOverstrikeMode());
+
+ break;
+
+ case K_TAB:
+ case K_DOWNARROW:
+ case K_KP_DOWNARROW:
+ case K_UPARROW:
+ case K_KP_UPARROW:
+ // Ignore these keys from the say field
+ if (item->type == ITEM_TYPE_SAYFIELD)
+ break;
+
+ newItem = Menu_SetNextCursorItem(item->parent);
+
+ if (newItem && Item_IsEditField(newItem))
+ {
+ g_editItem = newItem;
+ }
+ else
+ {
+ releaseFocus = qtrue;
+ goto exit;
+ }
+
+ break;
+
+ case K_MOUSE1:
+ case K_MOUSE2:
+ case K_MOUSE3:
+ case K_MOUSE4:
+ // Ignore these buttons from the say field
+ if (item->type == ITEM_TYPE_SAYFIELD)
+ break;
+ // FALLTHROUGH
+ case K_ENTER:
+ case K_KP_ENTER:
+ case K_ESCAPE:
+ releaseFocus = qtrue;
+ goto exit;
+
+ default:
+ break;
+ }
}
- return qtrue;
- }
- if ( key == K_LEFTARROW || key == K_KP_LEFTARROW )
- {
- if ( item->cursorPos > 0 ) {
- item->cursorPos--;
+ releaseFocus = qfalse;
+ }
+
+exit:
+ Item_TextField_CalcPaintOffset(item, buff);
+
+ return !releaseFocus;
+}
+
+static void _Scroll_ListBox_AutoFunc(scrollInfo_t *si)
+{
+ if (DC->realTime > si->nextScrollTime)
+ {
+ // need to scroll which is done by simulating a click to the item
+ // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
+ // so it calls it directly
+ Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
+
+ si->nextScrollTime = DC->realTime + si->adjustValue;
+ }
+
+ if (DC->realTime > si->nextAdjustTime)
+ {
+ si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
+
+ if (si->adjustValue > SCROLL_TIME_FLOOR)
+ si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
+ }
+}
+
+static void Scroll_ListBox_AutoFunc(void *p)
+{
+ scrollInfo_t *si = (scrollInfo_t *)p;
+
+ qboolean cast = Item_ComboBox_MaybeCastToListBox(si->item);
+ _Scroll_ListBox_AutoFunc(si);
+ Item_ComboBox_MaybeUnCastFromListBox(si->item, cast);
+}
+
+static void _Scroll_ListBox_ThumbFunc(scrollInfo_t *si)
+{
+ rectDef_t r;
+ int pos, max;
+
+ if (DC->cursory != si->yStart)
+ {
+ r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_ARROW_WIDTH - 1;
+ r.y = si->item->window.rect.y + SCROLLBAR_ARROW_HEIGHT + 1;
+ r.w = SCROLLBAR_ARROW_WIDTH;
+ r.h = si->item->window.rect.h - (SCROLLBAR_ARROW_HEIGHT * 2) - 2;
+ max = Item_ListBox_MaxScroll(si->item);
+ //
+ pos = (DC->cursory - r.y - SCROLLBAR_ARROW_HEIGHT / 2) * max / (r.h - SCROLLBAR_ARROW_HEIGHT);
+
+ if (pos < 0)
+ pos = 0;
+ else if (pos > max)
+ pos = max;
+
+ Item_ListBox_SetStartPos(si->item, pos);
+ si->yStart = DC->cursory;
+ }
+
+ if (DC->realTime > si->nextScrollTime)
+ {
+ // need to scroll which is done by simulating a click to the item
+ // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
+ // so it calls it directly
+ Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
+
+ si->nextScrollTime = DC->realTime + si->adjustValue;
+ }
+
+ if (DC->realTime > si->nextAdjustTime)
+ {
+ si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
+
+ if (si->adjustValue > SCROLL_TIME_FLOOR)
+ si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
+ }
+}
+
+static void Scroll_ListBox_ThumbFunc(void *p)
+{
+ scrollInfo_t *si = (scrollInfo_t *)p;
+
+ qboolean cast = Item_ComboBox_MaybeCastToListBox(si->item);
+ _Scroll_ListBox_ThumbFunc(si);
+ Item_ComboBox_MaybeUnCastFromListBox(si->item, cast);
+}
+
+static void Scroll_Slider_ThumbFunc(void *p)
+{
+ float x, value, cursorx;
+ scrollInfo_t *si = (scrollInfo_t *)p;
+
+ if (si->item->text)
+ x = si->item->textRect.x + si->item->textRect.w + ITEM_VALUE_OFFSET;
+ else
+ x = si->item->window.rect.x;
+
+ cursorx = DC->cursorx;
+
+ if (cursorx < x)
+ cursorx = x;
+ else if (cursorx > x + SLIDER_WIDTH)
+ cursorx = x + SLIDER_WIDTH;
+
+ value = cursorx - x;
+ value /= SLIDER_WIDTH;
+ value *= si->item->typeData.edit->maxVal - si->item->typeData.edit->minVal;
+ value += si->item->typeData.edit->minVal;
+ DC->setCVar(si->item->cvar, va("%f", value));
+}
+
+void Item_StartCapture(itemDef_t *item, int key)
+{
+ int flags;
+
+ // Don't allow captureFunc to be overridden
+
+ if (captureFunc != voidFunction)
+ return;
+
+ switch (item->type)
+ {
+ case ITEM_TYPE_LISTBOX:
+ case ITEM_TYPE_COMBOBOX:
+ {
+ qboolean cast = Item_ComboBox_MaybeCastToListBox(item);
+ flags = Item_ListBox_OverLB(item, DC->cursorx, DC->cursory);
+ Item_ComboBox_MaybeUnCastFromListBox(item, cast);
+
+ if (flags & (WINDOW_LB_UPARROW | WINDOW_LB_DOWNARROW))
+ {
+ scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START;
+ scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
+ scrollInfo.adjustValue = SCROLL_TIME_START;
+ scrollInfo.scrollKey = key;
+ scrollInfo.scrollDir = (flags & WINDOW_LB_UPARROW) ? qtrue : qfalse;
+ scrollInfo.item = item;
+ UI_InstallCaptureFunc(Scroll_ListBox_AutoFunc, &scrollInfo, 0);
+ itemCapture = item;
+ }
+ else if (flags & WINDOW_LB_THUMB)
+ {
+ scrollInfo.scrollKey = key;
+ scrollInfo.item = item;
+ scrollInfo.xStart = DC->cursorx;
+ scrollInfo.yStart = DC->cursory;
+ UI_InstallCaptureFunc(Scroll_ListBox_ThumbFunc, &scrollInfo, 0);
+ itemCapture = item;
+ }
+
+ break;
}
- if (item->cursorPos < editPtr->paintOffset) {
- editPtr->paintOffset--;
+
+ case ITEM_TYPE_SLIDER:
+ {
+ flags = Item_Slider_OverSlider(item, DC->cursorx, DC->cursory);
+
+ if (flags & WINDOW_LB_THUMB)
+ {
+ scrollInfo.scrollKey = key;
+ scrollInfo.item = item;
+ scrollInfo.xStart = DC->cursorx;
+ scrollInfo.yStart = DC->cursory;
+ UI_InstallCaptureFunc(Scroll_Slider_ThumbFunc, &scrollInfo, 0);
+ itemCapture = item;
+ }
+
+ break;
}
- return qtrue;
- }
+ }
+}
- if ( key == K_HOME || key == K_KP_HOME) {// || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
- item->cursorPos = 0;
- editPtr->paintOffset = 0;
- return qtrue;
- }
+void Item_StopCapture(itemDef_t *item) {}
+
+qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down)
+{
+ float x, value, width;
- if ( key == K_END || key == K_KP_END) {// ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
- item->cursorPos = len;
- if(item->cursorPos > editPtr->maxPaintChars) {
- editPtr->paintOffset = len - editPtr->maxPaintChars;
+ if (item->window.flags & WINDOW_HASFOCUS && item->cvar &&
+ Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory))
+ {
+ if (item->typeData.edit && (key == K_ENTER || key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3))
+ {
+ rectDef_t testRect;
+ width = SLIDER_WIDTH;
+
+ if (item->text)
+ x = item->textRect.x + item->textRect.w + ITEM_VALUE_OFFSET;
+ else
+ x = item->window.rect.x;
+
+ testRect = item->window.rect;
+ value = (float)SLIDER_THUMB_WIDTH / 2;
+ testRect.x = x - value;
+ testRect.w = SLIDER_WIDTH + value;
+
+ if (Rect_ContainsPoint(&testRect, DC->cursorx, DC->cursory))
+ {
+ value = (float)(DC->cursorx - x) / width;
+ value *= (item->typeData.edit->maxVal - item->typeData.edit->minVal);
+ value += item->typeData.edit->minVal;
+ DC->setCVar(item->cvar, va("%f", value));
+ return qtrue;
+ }
}
- return qtrue;
- }
+ }
- if ( key == K_INS || key == K_KP_INS ) {
- DC->setOverstrikeMode(!DC->getOverstrikeMode());
- return qtrue;
- }
+ return qfalse;
+}
+
+qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down)
+{
+ if (itemCapture)
+ {
+ Item_StopCapture(itemCapture);
+ itemCapture = NULL;
+ UI_RemoveCaptureFunc();
+ }
+ else
+ {
+ if (down && (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3))
+ Item_StartCapture(item, key);
}
- if (key == K_TAB || key == K_DOWNARROW || key == K_KP_DOWNARROW) {
- if (item->type == ITEM_TYPE_SAYFIELD) {
- return qtrue;
- }
+ if (!down)
+ return qfalse;
+
+ // Edit fields are handled specially
+ if (Item_IsEditField(item))
+ return qfalse;
+
+ switch (item->type)
+ {
+ case ITEM_TYPE_BUTTON:
+ return qfalse;
+
+ case ITEM_TYPE_RADIOBUTTON:
+ return qfalse;
+
+ case ITEM_TYPE_CHECKBOX:
+ return qfalse;
+
+ case ITEM_TYPE_CYCLE:
+ return Item_Cycle_HandleKey(item, key);
- newItem = Menu_SetNextCursorItem(item->parent);
- if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_SAYFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
- g_editItem = newItem;
- }
+ case ITEM_TYPE_LISTBOX:
+ return Item_ListBox_HandleKey(item, key, down, qfalse);
+
+ case ITEM_TYPE_COMBOBOX:
+ return Item_ComboBox_HandleKey(item, key, down, qfalse);
+
+ case ITEM_TYPE_YESNO:
+ return Item_YesNo_HandleKey(item, key);
+
+ case ITEM_TYPE_MULTI:
+ return Item_Multi_HandleKey(item, key);
+
+ case ITEM_TYPE_OWNERDRAW:
+ return Item_OwnerDraw_HandleKey(item, key);
+
+ case ITEM_TYPE_BIND:
+ return Item_Bind_HandleKey(item, key, down);
+
+ case ITEM_TYPE_SLIDER:
+ return Item_Slider_HandleKey(item, key, down);
+
+ default:
+ return qfalse;
}
+}
- if (key == K_UPARROW || key == K_KP_UPARROW) {
- if (item->type == ITEM_TYPE_SAYFIELD) {
- return qtrue;
- }
+void Item_Action(itemDef_t *item)
+{
+ if (item)
+ Item_RunScript(item, item->action);
+}
+
+itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu)
+{
+ qboolean wrapped = qfalse;
+ int oldCursor = menu->cursorItem;
- newItem = Menu_SetPrevCursorItem(item->parent);
- if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_SAYFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
- g_editItem = newItem;
- }
+ if (menu->cursorItem < 0)
+ {
+ menu->cursorItem = menu->itemCount - 1;
+ wrapped = qtrue;
}
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 || key == K_MOUSE4) {
- if (item->type == ITEM_TYPE_SAYFIELD) {
- return qtrue;
- }
- return qfalse;
+ while (menu->cursorItem > -1)
+ {
+ menu->cursorItem--;
+
+ if (menu->cursorItem < 0 && !wrapped)
+ {
+ wrapped = qtrue;
+ menu->cursorItem = menu->itemCount - 1;
+ }
+
+ if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory))
+ {
+ Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1,
+ menu->items[menu->cursorItem]->window.rect.y + 1);
+ return menu->items[menu->cursorItem];
+ }
}
- if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE) {
- return qfalse;
+ menu->cursorItem = oldCursor;
+ return NULL;
+}
+
+itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu)
+{
+ qboolean wrapped = qfalse;
+ int oldCursor = menu->cursorItem;
+
+ if (menu->cursorItem == -1)
+ {
+ menu->cursorItem = 0;
+ wrapped = qtrue;
}
- return qtrue;
- }
- return qfalse;
-
-}
-
-static void Scroll_ListBox_AutoFunc(void *p) {
- scrollInfo_t *si = (scrollInfo_t*)p;
- if (DC->realTime > si->nextScrollTime) {
- // need to scroll which is done by simulating a click to the item
- // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
- // so it calls it directly
- Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
- si->nextScrollTime = DC->realTime + si->adjustValue;
- }
-
- if (DC->realTime > si->nextAdjustTime) {
- si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
- if (si->adjustValue > SCROLL_TIME_FLOOR) {
- si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
- }
- }
-}
-
-static void Scroll_ListBox_ThumbFunc(void *p) {
- scrollInfo_t *si = (scrollInfo_t*)p;
- rectDef_t r;
- int pos, max;
-
- listBoxDef_t *listPtr = (listBoxDef_t*)si->item->typeData;
- if (si->item->window.flags & WINDOW_HORIZONTAL) {
- if (DC->cursorx == si->xStart) {
- return;
- }
- r.x = si->item->window.rect.x + SCROLLBAR_SIZE + 1;
- r.y = si->item->window.rect.y + si->item->window.rect.h - SCROLLBAR_SIZE - 1;
- r.h = SCROLLBAR_SIZE;
- r.w = si->item->window.rect.w - (SCROLLBAR_SIZE*2) - 2;
- max = Item_ListBox_MaxScroll(si->item);
- //
- pos = (DC->cursorx - r.x - SCROLLBAR_SIZE/2) * max / (r.w - SCROLLBAR_SIZE);
- if (pos < 0) {
- pos = 0;
- }
- else if (pos > max) {
- pos = max;
- }
- listPtr->startPos = pos;
- si->xStart = DC->cursorx;
- }
- else if (DC->cursory != si->yStart) {
-
- r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1;
- r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1;
- r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2;
- r.w = SCROLLBAR_SIZE;
- max = Item_ListBox_MaxScroll(si->item);
- //
- pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE);
- if (pos < 0) {
- pos = 0;
- }
- else if (pos > max) {
- pos = max;
- }
- listPtr->startPos = pos;
- si->yStart = DC->cursory;
- }
-
- if (DC->realTime > si->nextScrollTime) {
- // need to scroll which is done by simulating a click to the item
- // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
- // so it calls it directly
- Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
- si->nextScrollTime = DC->realTime + si->adjustValue;
- }
-
- if (DC->realTime > si->nextAdjustTime) {
- si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
- if (si->adjustValue > SCROLL_TIME_FLOOR) {
- si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
- }
- }
-}
-
-static void Scroll_Slider_ThumbFunc(void *p) {
- float x, value, cursorx;
- scrollInfo_t *si = (scrollInfo_t*)p;
- editFieldDef_t *editDef = si->item->typeData;
-
- if (si->item->text) {
- x = si->item->textRect.x + si->item->textRect.w + 8;
- } else {
- x = si->item->window.rect.x;
- }
-
- cursorx = DC->cursorx;
-
- if (cursorx < x) {
- cursorx = x;
- } else if (cursorx > x + SLIDER_WIDTH) {
- cursorx = x + SLIDER_WIDTH;
- }
- value = cursorx - x;
- value /= SLIDER_WIDTH;
- value *= (editDef->maxVal - editDef->minVal);
- value += editDef->minVal;
- DC->setCVar(si->item->cvar, va("%f", value));
-}
-
-void Item_StartCapture(itemDef_t *item, int key) {
- int flags;
- switch (item->type) {
- case ITEM_TYPE_EDITFIELD:
- case ITEM_TYPE_SAYFIELD:
- case ITEM_TYPE_NUMERICFIELD:
-
- case ITEM_TYPE_LISTBOX:
- {
- flags = Item_ListBox_OverLB(item, DC->cursorx, DC->cursory);
- if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) {
- scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START;
- scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
- scrollInfo.adjustValue = SCROLL_TIME_START;
- scrollInfo.scrollKey = key;
- scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse;
- scrollInfo.item = item;
- captureData = &scrollInfo;
- captureFunc = &Scroll_ListBox_AutoFunc;
- itemCapture = item;
- } else if (flags & WINDOW_LB_THUMB) {
- scrollInfo.scrollKey = key;
- scrollInfo.item = item;
- scrollInfo.xStart = DC->cursorx;
- scrollInfo.yStart = DC->cursory;
- captureData = &scrollInfo;
- captureFunc = &Scroll_ListBox_ThumbFunc;
- itemCapture = item;
- }
- break;
- }
- case ITEM_TYPE_SLIDER:
- {
- flags = Item_Slider_OverSlider(item, DC->cursorx, DC->cursory);
- if (flags & WINDOW_LB_THUMB) {
- scrollInfo.scrollKey = key;
- scrollInfo.item = item;
- scrollInfo.xStart = DC->cursorx;
- scrollInfo.yStart = DC->cursory;
- captureData = &scrollInfo;
- captureFunc = &Scroll_Slider_ThumbFunc;
- itemCapture = item;
- }
- break;
- }
- }
-}
-
-void Item_StopCapture(itemDef_t *item) {
-
-}
-
-qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down) {
- float x, value, width, work;
-
- if (item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
- if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
- editFieldDef_t *editDef = item->typeData;
- if (editDef) {
- rectDef_t testRect;
- width = SLIDER_WIDTH;
- if (item->text) {
- x = item->textRect.x + item->textRect.w + 8;
- } else {
- x = item->window.rect.x;
- }
-
- testRect = item->window.rect;
- testRect.x = x;
- value = (float)SLIDER_THUMB_WIDTH / 2;
- testRect.x -= value;
- testRect.w = (SLIDER_WIDTH + (float)SLIDER_THUMB_WIDTH / 2);
- if (Rect_ContainsPoint(&testRect, DC->cursorx, DC->cursory)) {
- work = DC->cursorx - x;
- value = work / width;
- value *= (editDef->maxVal - editDef->minVal);
- // vm fuckage
- // value = (((float)(DC->cursorx - x)/ SLIDER_WIDTH) * (editDef->maxVal - editDef->minVal));
- value += editDef->minVal;
- DC->setCVar(item->cvar, va("%f", value));
- return qtrue;
- }
- }
- }
- }
- return qfalse;
-}
-
-
-qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) {
-
- if (itemCapture) {
- Item_StopCapture(itemCapture);
- itemCapture = NULL;
- captureFunc = voidFunction;
- captureData = NULL;
- } else {
- // bk001206 - parentheses
- if ( down && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
- Item_StartCapture(item, key);
+ while (menu->cursorItem < menu->itemCount)
+ {
+ menu->cursorItem++;
+
+ if (menu->cursorItem >= menu->itemCount && !wrapped)
+ {
+ wrapped = qtrue;
+ menu->cursorItem = 0;
+ }
+
+ if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory))
+ {
+ Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1,
+ menu->items[menu->cursorItem]->window.rect.y + 1);
+ return menu->items[menu->cursorItem];
+ }
}
- }
- if (!down) {
- return qfalse;
- }
-
- switch (item->type) {
- case ITEM_TYPE_BUTTON:
- return qfalse;
- break;
- case ITEM_TYPE_RADIOBUTTON:
- return qfalse;
- break;
- case ITEM_TYPE_CHECKBOX:
- return qfalse;
- break;
- case ITEM_TYPE_EDITFIELD:
- case ITEM_TYPE_SAYFIELD:
- case ITEM_TYPE_NUMERICFIELD:
- //return Item_TextField_HandleKey(item, key);
- return qfalse;
- break;
- case ITEM_TYPE_COMBO:
- return qfalse;
- break;
- case ITEM_TYPE_LISTBOX:
- return Item_ListBox_HandleKey(item, key, down, qfalse);
- break;
- case ITEM_TYPE_YESNO:
- return Item_YesNo_HandleKey(item, key);
- break;
- case ITEM_TYPE_MULTI:
- return Item_Multi_HandleKey(item, key);
- break;
- case ITEM_TYPE_OWNERDRAW:
- return Item_OwnerDraw_HandleKey(item, key);
- break;
- case ITEM_TYPE_BIND:
- return Item_Bind_HandleKey(item, key, down);
- break;
- case ITEM_TYPE_SLIDER:
- return Item_Slider_HandleKey(item, key, down);
- break;
- //case ITEM_TYPE_IMAGE:
- // Item_Image_Paint(item);
- // break;
- default:
- return qfalse;
- break;
- }
-
- //return qfalse;
-}
-
-void Item_Action(itemDef_t *item) {
- if (item) {
- Item_RunScript(item, item->action);
- }
-}
-
-itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu) {
- qboolean wrapped = qfalse;
- int oldCursor = menu->cursorItem;
-
- if (menu->cursorItem < 0) {
- menu->cursorItem = menu->itemCount-1;
- wrapped = qtrue;
- }
-
- while (menu->cursorItem > -1) {
-
- menu->cursorItem--;
- if (menu->cursorItem < 0 && !wrapped) {
- wrapped = qtrue;
- menu->cursorItem = menu->itemCount -1;
- }
-
- if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
- Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
- return menu->items[menu->cursorItem];
- }
- }
- menu->cursorItem = oldCursor;
- return NULL;
-
-}
-
-itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu) {
-
- qboolean wrapped = qfalse;
- int oldCursor = menu->cursorItem;
-
-
- if (menu->cursorItem == -1) {
- menu->cursorItem = 0;
- wrapped = qtrue;
- }
-
- while (menu->cursorItem < menu->itemCount) {
-
- menu->cursorItem++;
- if (menu->cursorItem >= menu->itemCount && !wrapped) {
- wrapped = qtrue;
- menu->cursorItem = 0;
- }
- if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
- Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
- return menu->items[menu->cursorItem];
- }
-
- }
-
- menu->cursorItem = oldCursor;
- return NULL;
+ menu->cursorItem = oldCursor;
+ return NULL;
}
-static void Window_CloseCinematic(windowDef_t *window) {
- if (window->style == WINDOW_STYLE_CINEMATIC && window->cinematic >= 0) {
- DC->stopCinematic(window->cinematic);
- window->cinematic = -1;
- }
+static void Window_CloseCinematic(Window *window)
+{
+ if (window->style == WINDOW_STYLE_CINEMATIC && window->cinematic >= 0)
+ {
+ DC->stopCinematic(window->cinematic);
+ window->cinematic = -1;
+ }
}
-static void Menu_CloseCinematics(menuDef_t *menu) {
- if (menu) {
- int i;
- Window_CloseCinematic(&menu->window);
- for (i = 0; i < menu->itemCount; i++) {
- Window_CloseCinematic(&menu->items[i]->window);
- if (menu->items[i]->type == ITEM_TYPE_OWNERDRAW) {
- DC->stopCinematic(0-menu->items[i]->window.ownerDraw);
- }
+static void Menu_CloseCinematics(menuDef_t *menu)
+{
+ if (menu)
+ {
+ int i;
+ Window_CloseCinematic(&menu->window);
+
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ Window_CloseCinematic(&menu->items[i]->window);
+
+ if (menu->items[i]->type == ITEM_TYPE_OWNERDRAW)
+ DC->stopCinematic(0 - menu->items[i]->window.ownerDraw);
+ }
}
- }
}
-static void Display_CloseCinematics( void ) {
- int i;
- for (i = 0; i < menuCount; i++) {
- Menu_CloseCinematics(&Menus[i]);
- }
+static void Display_CloseCinematics(void)
+{
+ int i;
+
+ for (i = 0; i < menuCount; i++)
+ Menu_CloseCinematics(&Menus[i]);
}
-void Menus_Activate(menuDef_t *menu) {
- menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE);
- if (menu->onOpen) {
- itemDef_t item;
- item.parent = menu;
- Item_RunScript(&item, menu->onOpen);
- }
+void Menus_Activate(menuDef_t *menu)
+{
+ int i;
+ qboolean onTopOfMenuStack = qfalse;
- if (menu->soundName && *menu->soundName) {
-// DC->stopBackgroundTrack(); // you don't want to do this since it will reset s_rawend
- DC->startBackgroundTrack(menu->soundName, menu->soundName);
- }
+ if (openMenuCount > 0 && menuStack[openMenuCount - 1] == menu)
+ onTopOfMenuStack = qtrue;
- Display_CloseCinematics();
+ menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE);
-}
+ // If being opened for the first time
+ if (!onTopOfMenuStack)
+ {
+ if (menu->onOpen)
+ {
+ itemDef_t item;
+ item.parent = menu;
+ Item_RunScript(&item, menu->onOpen);
+ }
+
+ if (menu->soundName && *menu->soundName)
+ DC->startBackgroundTrack(menu->soundName, menu->soundName);
+
+ Display_CloseCinematics();
-int Display_VisibleMenuCount( void ) {
- int i, count;
- count = 0;
- for (i = 0; i < menuCount; i++) {
- if (Menus[i].window.flags & (WINDOW_FORCED | WINDOW_VISIBLE)) {
- count++;
+ Menu_HandleMouseMove(menu, DC->cursorx, DC->cursory); // force the item under the cursor to focus
+
+ for (i = 0; i < menu->itemCount; i++) // reset selection in listboxes when opened
+ {
+ if (Item_IsListBox(menu->items[i]))
+ {
+ menu->items[i]->cursorPos = DC->feederInitialise(menu->items[i]->feederID);
+ Item_ListBox_SetStartPos(menu->items[i], 0);
+ DC->feederSelection(menu->items[i]->feederID, menu->items[i]->cursorPos);
+ }
+ else if (menu->items[i]->type == ITEM_TYPE_CYCLE)
+ {
+ menu->items[i]->typeData.cycle->cursorPos = DC->feederInitialise(menu->items[i]->feederID);
+ }
+ }
+
+ if (openMenuCount < MAX_OPEN_MENUS)
+ menuStack[openMenuCount++] = menu;
}
- }
- return count;
}
-void Menus_HandleOOBClick(menuDef_t *menu, int key, qboolean down) {
- if (menu) {
+qboolean Menus_ReplaceActive(menuDef_t *menu)
+{
int i;
- // basically the behaviour we are looking for is if there are windows in the stack.. see if
- // the cursor is within any of them.. if not close them otherwise activate them and pass the
- // key on.. force a mouse move to activate focus and script stuff
- if (down && menu->window.flags & WINDOW_OOB_CLICK) {
- Menu_RunCloseScript(menu);
- menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
+ menuDef_t *active;
+
+ if (openMenuCount < 1)
+ return qfalse;
+
+ active = menuStack[openMenuCount - 1];
+
+ if (!(active->window.flags & WINDOW_HASFOCUS) || !(active->window.flags & WINDOW_VISIBLE))
+ {
+ return qfalse;
}
- for (i = 0; i < menuCount; i++) {
- if (Menu_OverActiveItem(&Menus[i], DC->cursorx, DC->cursory)) {
- Menu_RunCloseScript(menu);
- menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
- Menus_Activate(&Menus[i]);
- Menu_HandleMouseMove(&Menus[i], DC->cursorx, DC->cursory);
- Menu_HandleKey(&Menus[i], key, down);
- }
+ if (menu == active)
+ return qfalse;
+
+ if (menu->itemCount != active->itemCount)
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: Menus_ReplaceActive: expecting %i menu items, found %i\n", menu->itemCount,
+ active->itemCount);
+ return qfalse;
}
- if (Display_VisibleMenuCount() == 0) {
- if (DC->Pause) {
- DC->Pause(qfalse);
- }
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ if (menu->items[i]->type != active->items[i]->type)
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: Menus_ReplaceActive: type mismatch on item %i\n", i + 1);
+ return qfalse;
+ }
}
- Display_CloseCinematics();
- }
+
+ active->window.flags &= ~(WINDOW_FADINGOUT | WINDOW_VISIBLE);
+ menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE);
+
+ menuStack[openMenuCount - 1] = menu;
+ if (menu->onOpen)
+ {
+ itemDef_t item;
+ item.parent = menu;
+ Item_RunScript(&item, menu->onOpen);
+ }
+
+ // set the cursor position on the new menu to match the active one
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ menu->items[i]->cursorPos = active->items[i]->cursorPos;
+ menu->items[i]->feederID = active->items[i]->feederID;
+ switch (Item_DataType(menu->items[i]))
+ {
+ case TYPE_LIST:
+ menu->items[i]->typeData.list->startPos = active->items[i]->typeData.list->startPos;
+ menu->items[i]->typeData.list->cursorPos = active->items[i]->typeData.list->cursorPos;
+ break;
+ case TYPE_COMBO:
+ menu->items[i]->typeData.cycle->cursorPos = active->items[i]->typeData.cycle->cursorPos;
+ break;
+ default:
+ break;
+ }
+ }
+ return qtrue;
}
-static rectDef_t *Item_CorrectedTextRect(itemDef_t *item) {
- static rectDef_t rect;
- memset(&rect, 0, sizeof(rectDef_t));
- if (item) {
- rect = item->textRect;
- if (rect.w) {
- rect.y -= rect.h;
+int Display_VisibleMenuCount(void)
+{
+ int i, count;
+ count = 0;
+
+ for (i = 0; i < menuCount; i++)
+ {
+ if (Menus[i].window.flags & (WINDOW_FORCED | WINDOW_VISIBLE))
+ count++;
}
- }
- return &rect;
+
+ return count;
}
-void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) {
- int i;
- itemDef_t *item = NULL;
- qboolean inHandler = qfalse;
+void Menus_HandleOOBClick(menuDef_t *menu, int key, qboolean down)
+{
+ if (menu)
+ {
+ int i;
+ // basically the behaviour we are looking for is if there are windows in the stack.. see if
+ // the cursor is within any of them.. if not close them otherwise activate them and pass the
+ // key on.. force a mouse move to activate focus and script stuff
+
+ if (down && menu->window.flags & WINDOW_OOB_CLICK)
+ Menus_Close(menu);
- if (inHandler) {
- return;
- }
+ for (i = 0; i < menuCount; i++)
+ {
+ if (Menu_OverActiveItem(&Menus[i], DC->cursorx, DC->cursory))
+ {
+ Menus_Close(menu);
+ Menus_Activate(&Menus[i]);
+ Menu_HandleMouseMove(&Menus[i], DC->cursorx, DC->cursory);
+ Menu_HandleKey(&Menus[i], key, down);
+ }
+ }
- inHandler = qtrue;
- if (g_waitingForKey && down) {
- Item_Bind_HandleKey(g_bindItem, key, down);
- inHandler = qfalse;
- return;
- }
+ if (Display_VisibleMenuCount() == 0)
+ {
+ if (DC->Pause)
+ DC->Pause(qfalse);
+ }
- if (g_editingField && down) {
- if (!Item_TextField_HandleKey(g_editItem, key)) {
- g_editingField = qfalse;
- Item_RunScript(g_editItem, g_editItem->onTextEntry);
- g_editItem = NULL;
- inHandler = qfalse;
- return;
+ Display_CloseCinematics();
}
- }
+}
- if (menu == NULL) {
- inHandler = qfalse;
- return;
- }
+static rectDef_t *Item_CorrectedTextRect(itemDef_t *item)
+{
+ static rectDef_t rect;
+ memset(&rect, 0, sizeof(rectDef_t));
- // see if the mouse is within the window bounds and if so is this a mouse click
- if (down && !(menu->window.flags & WINDOW_POPUP) && !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory)) {
- static qboolean inHandleKey = qfalse;
- // bk001206 - parentheses
- if (!inHandleKey && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
- inHandleKey = qtrue;
- Menus_HandleOOBClick(menu, key, down);
- inHandleKey = qfalse;
- inHandler = qfalse;
- return;
- }
- }
-
- // get the item with focus
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
- item = menu->items[i];
- }
- }
-
- if (item != NULL) {
- if (Item_HandleKey(item, key, down)) {
- Item_Action(item);
- inHandler = qfalse;
- return;
- }
- }
-
- if (!down) {
- inHandler = qfalse;
- return;
- }
-
- // default handling
- switch ( key ) {
-
- case K_F11:
- if (DC->getCVarValue("developer")) {
- debugMode ^= 1;
- }
- break;
-
- case K_F12:
- if (DC->getCVarValue("developer")) {
- DC->executeText(EXEC_APPEND, "screenshot\n");
- }
- break;
- case K_KP_UPARROW:
- case K_UPARROW:
- Menu_SetPrevCursorItem(menu);
- break;
-
- case K_ESCAPE:
- if (!g_waitingForKey && menu->onESC) {
- itemDef_t it;
- it.parent = menu;
- Item_RunScript(&it, menu->onESC);
- }
- break;
- case K_TAB:
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- Menu_SetNextCursorItem(menu);
- break;
-
- case K_MOUSE1:
- case K_MOUSE2:
- if (item) {
- if (item->type == ITEM_TYPE_TEXT) {
- if (Rect_ContainsPoint(Item_CorrectedTextRect(item), DC->cursorx, DC->cursory)) {
- Item_Action(item);
- }
- } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
- item->cursorPos = 0;
- g_editingField = qtrue;
- g_editItem = item;
- DC->setOverstrikeMode(qtrue);
- }
- } else if (item->type == ITEM_TYPE_SAYFIELD) {
- // do nothing
- } else {
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
- Item_Action(item);
- }
- }
- }
- break;
-
- case K_JOY1:
- case K_JOY2:
- case K_JOY3:
- case K_JOY4:
- case K_AUX1:
- case K_AUX2:
- case K_AUX3:
- case K_AUX4:
- case K_AUX5:
- case K_AUX6:
- case K_AUX7:
- case K_AUX8:
- case K_AUX9:
- case K_AUX10:
- case K_AUX11:
- case K_AUX12:
- case K_AUX13:
- case K_AUX14:
- case K_AUX15:
- case K_AUX16:
- break;
- case K_KP_ENTER:
- case K_ENTER:
- if (item) {
- if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_SAYFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
- item->cursorPos = 0;
- g_editingField = qtrue;
- g_editItem = item;
- DC->setOverstrikeMode(qtrue);
- } else {
- Item_Action(item);
- }
- }
- break;
- }
- inHandler = qfalse;
-}
-
-void ToWindowCoords(float *x, float *y, windowDef_t *window) {
- if (window->border != 0) {
- *x += window->borderSize;
- *y += window->borderSize;
- }
- *x += window->rect.x;
- *y += window->rect.y;
-}
-
-void Rect_ToWindowCoords(rectDef_t *rect, windowDef_t *window) {
- ToWindowCoords(&rect->x, &rect->y, window);
-}
-
-void Item_SetTextExtents(itemDef_t *item, int *width, int *height, const char *text) {
- const char *textPtr = (text) ? text : item->text;
-
- if (textPtr == NULL ) {
- return;
- }
-
- *width = item->textRect.w;
- *height = item->textRect.h;
-
- // keeps us from computing the widths and heights more than once
- if (*width == 0 || (item->type == ITEM_TYPE_OWNERDRAW && item->textalignment == ITEM_ALIGN_CENTER)) {
- int originalWidth = DC->textWidth(item->text, item->textscale, 0);
-
- if (item->type == ITEM_TYPE_OWNERDRAW && (item->textalignment == ITEM_ALIGN_CENTER || item->textalignment == ITEM_ALIGN_RIGHT)) {
- originalWidth += DC->ownerDrawWidth(item->window.ownerDraw, item->textscale);
- } else if (item->type == ITEM_TYPE_EDITFIELD && item->textalignment == ITEM_ALIGN_CENTER && item->cvar) {
- char buff[256];
- DC->getCVarString(item->cvar, buff, 256);
- originalWidth += DC->textWidth(buff, item->textscale, 0);
- }
-
- *width = DC->textWidth(textPtr, item->textscale, 0);
- *height = DC->textHeight(textPtr, item->textscale, 0);
- item->textRect.w = *width;
- item->textRect.h = *height;
- item->textRect.x = item->textalignx;
- item->textRect.y = item->textaligny;
- if (item->textalignment == ITEM_ALIGN_RIGHT) {
- item->textRect.x = item->textalignx - originalWidth;
- } else if (item->textalignment == ITEM_ALIGN_CENTER) {
- item->textRect.x = item->textalignx - originalWidth / 2;
- }
-
- ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
- }
-}
-
-void Item_TextColor(itemDef_t *item, vec4_t *newColor) {
- vec4_t lowLight;
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
-
- if (item->window.flags & WINDOW_HASFOCUS) {
-/* lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
- //TA:
- memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
- } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
- lowLight[0] = 0.8 * item->window.foreColor[0];
- lowLight[1] = 0.8 * item->window.foreColor[1];
- lowLight[2] = 0.8 * item->window.foreColor[2];
- lowLight[3] = 0.8 * item->window.foreColor[3];
- LerpColor(item->window.foreColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(newColor, &item->window.foreColor, sizeof(vec4_t));
- // items can be enabled and disabled based on cvars
- }
+ if (item)
+ {
+ rect = item->textRect;
- if (item->enableCvar != NULL && *item->enableCvar && item->cvarTest != NULL && *item->cvarTest) {
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- memcpy(newColor, &parent->disableColor, sizeof(vec4_t));
+ if (rect.w)
+ rect.y -= rect.h;
}
- }
+
+ return &rect;
}
-int Item_Text_AutoWrapped_Lines( itemDef_t *item )
+void Menu_HandleKey(menuDef_t *menu, int key, qboolean down)
{
- char text[ 1024 ];
- const char *p, *textPtr, *newLinePtr;
- char buff[ 1024 ];
- int len, textWidth, newLine;
- int lines = 0;
+ int i;
+ itemDef_t *item = NULL;
- textWidth = 0;
- newLinePtr = NULL;
+ if (g_waitingForKey && down)
+ {
+ Item_Bind_HandleKey(g_bindItem, key, down);
+ return;
+ }
- if( item->text == NULL )
- {
- if( item->cvar == NULL )
- return 0;
- else
+ if (g_editingField && down)
{
- DC->getCVarString( item->cvar, text, sizeof( text ) );
- textPtr = text;
+ if (!Item_TextField_HandleKey(g_editItem, key))
+ {
+ g_editingField = qfalse;
+ Item_RunScript(g_editItem, g_editItem->onTextEntry);
+ g_editItem = NULL;
+ return;
+ }
+ else
+ {
+ Item_RunScript(g_editItem, g_editItem->onCharEntry);
+ }
}
- }
- else
- textPtr = item->text;
- if( *textPtr == '\0' )
- return 0;
+ if (menu == NULL)
+ return;
- len = 0;
- buff[ 0 ] = '\0';
- newLine = 0;
- p = textPtr;
+ // see if the mouse is within the window bounds and if so is this a mouse click
+ if (down && !(menu->window.flags & WINDOW_POPUP) &&
+ !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory))
+ {
+ static qboolean inHandleKey = qfalse;
- while( p )
- {
- textWidth = DC->textWidth( buff, item->textscale, 0 );
+ if (!inHandleKey && (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3))
+ {
+ inHandleKey = qtrue;
+ Menus_HandleOOBClick(menu, key, down);
+ inHandleKey = qfalse;
+ return;
+ }
+ }
- if( *p == ' ' || *p == '\t' || *p == '\n' || *p == '\0' )
+ if (g_comboBoxItem == NULL)
{
- newLine = len;
- newLinePtr = p + 1;
+ // get the item with focus
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ if (menu->items[i]->window.flags & WINDOW_HASFOCUS)
+ item = menu->items[i];
+ }
}
+ else
+ item = g_comboBoxItem;
- //TA: forceably split lines that are too long (where normal splitage has failed)
- if( textWidth > item->window.rect.w && newLine == 0 && *p != '\n' )
+ if (item != NULL)
{
- newLine = len;
- newLinePtr = p;
+ if (Item_HandleKey(item, key, down))
+ {
+ Item_Action(item);
+ return;
+ }
}
- if( ( newLine && textWidth > item->window.rect.w ) || *p == '\n' || *p == '\0' )
- {
- if( len )
- buff[ newLine ] = '\0';
+ if (!down)
+ return;
- if( !( *p == '\n' && !*( p + 1 ) ) )
- lines++;
+ // default handling
+ switch (key)
+ {
+ case K_F12:
+ if (DC->getCVarValue("developer"))
+ DC->executeText(EXEC_APPEND, "screenshot\n");
+
+ break;
+
+ case K_KP_UPARROW:
+ case K_UPARROW:
+ Menu_SetPrevCursorItem(menu);
+ break;
+
+ case K_ESCAPE:
+ if (!g_waitingForKey && menu->onESC)
+ {
+ itemDef_t it;
+ it.parent = menu;
+ Item_RunScript(&it, menu->onESC);
+ }
- if( *p == '\0' )
- break;
+ break;
+
+ case K_TAB:
+ case K_KP_DOWNARROW:
+ case K_DOWNARROW:
+ Menu_SetNextCursorItem(menu);
+ break;
+
+ case K_MOUSE1:
+ case K_MOUSE2:
+ if (item)
+ {
+ if (item->type == ITEM_TYPE_TEXT)
+ {
+ if (Rect_ContainsPoint(Item_CorrectedTextRect(item), DC->cursorx, DC->cursory))
+ Item_Action(item);
+ }
+ else if (Item_IsEditField(item))
+ {
+ if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory))
+ {
+ char buffer[MAX_STRING_CHARS] = {0};
+
+ if (item->cvar)
+ DC->getCVarString(item->cvar, buffer, sizeof(buffer));
+
+ item->cursorPos = strlen(buffer);
+
+ Item_TextField_CalcPaintOffset(item, buffer);
+
+ g_editingField = qtrue;
+
+ g_editItem = item;
+ }
+ }
+ else
+ {
+ if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory))
+ Item_Action(item);
+ }
+ }
- //
- p = newLinePtr;
- len = 0;
- newLine = 0;
+ break;
+
+ case K_JOY1:
+ case K_JOY2:
+ case K_JOY3:
+ case K_JOY4:
+ case K_AUX1:
+ case K_AUX2:
+ case K_AUX3:
+ case K_AUX4:
+ case K_AUX5:
+ case K_AUX6:
+ case K_AUX7:
+ case K_AUX8:
+ case K_AUX9:
+ case K_AUX10:
+ case K_AUX11:
+ case K_AUX12:
+ case K_AUX13:
+ case K_AUX14:
+ case K_AUX15:
+ case K_AUX16:
+ break;
+
+ case K_KP_ENTER:
+ case K_ENTER:
+ if (item)
+ {
+ if (Item_IsEditField(item))
+ {
+ char buffer[MAX_STRING_CHARS] = {0};
+
+ if (item->cvar)
+ DC->getCVarString(item->cvar, buffer, sizeof(buffer));
+
+ item->cursorPos = strlen(buffer);
+
+ Item_TextField_CalcPaintOffset(item, buffer);
+
+ g_editingField = qtrue;
+
+ g_editItem = item;
+ }
+ else
+ Item_Action(item);
+ }
- continue;
+ break;
}
+}
- buff[ len++ ] = *p++;
- buff[ len ] = '\0';
- }
+void ToWindowCoords(float *x, float *y, Window *window)
+{
+ if (window->border != 0)
+ {
+ *x += window->borderSize;
+ *y += window->borderSize;
+ }
- return lines;
+ *x += window->rect.x;
+ *y += window->rect.y;
}
-#define MAX_AUTOWRAP_CACHE 16
-#define MAX_AUTOWRAP_LINES 32
-#define MAX_AUTOWRAP_TEXT 512
+void Rect_ToWindowCoords(rectDef_t *rect, Window *window) { ToWindowCoords(&rect->x, &rect->y, window); }
-typedef struct
+void Item_SetTextExtents(itemDef_t *item, const char *text)
{
- //this is used purely for checking for cache hits
- char text[ MAX_AUTOWRAP_TEXT * MAX_AUTOWRAP_LINES ];
- rectDef_t rect;
- int textWidth, textHeight;
- char lines[ MAX_AUTOWRAP_LINES ][ MAX_AUTOWRAP_TEXT ];
- int lineOffsets[ MAX_AUTOWRAP_LINES ][ 2 ];
- int numLines;
-} autoWrapCache_t;
+ const char *textPtr = (text) ? text : item->text;
+ qboolean cvarContent;
-static int cacheIndex = 0;
-static autoWrapCache_t awc[ MAX_AUTOWRAP_CACHE ];
+ // It's hard to make a policy on what should be aligned statically and what
+ // should be aligned dynamically; there are reasonable cases for both. If
+ // it continues to be a problem then there should probably be an item keyword
+ // for it; but for the moment only adjusting the alignment of ITEM_TYPE_TEXT
+ // seems to suffice.
+ cvarContent = (item->cvar && item->textalignment != ALIGN_LEFT && item->type == ITEM_TYPE_TEXT);
-static int checkCache( const char *text, rectDef_t *rect, int width, int height )
-{
- int i;
+ if (textPtr == NULL)
+ return;
- for( i = 0; i < MAX_AUTOWRAP_CACHE; i++ )
- {
- if( Q_stricmp( text, awc[ i ].text ) )
- continue;
+ // as long as the item isn't dynamic content (ownerdraw or cvar), this
+ // keeps us from computing the widths and heights more than once
+ if (item->textRect.w == 0.0f || cvarContent ||
+ (item->type == ITEM_TYPE_OWNERDRAW && item->textalignment != ALIGN_LEFT))
+ {
+ float originalWidth = 0.0f;
+
+ if (item->textalignment == ALIGN_CENTER || item->textalignment == ALIGN_RIGHT)
+ {
+ if (cvarContent)
+ {
+ char buff[MAX_CVAR_VALUE_STRING];
+ DC->getCVarString(item->cvar, buff, sizeof(buff));
+ originalWidth = UI_Text_Width(item->text, item->textscale) + UI_Text_Width(buff, item->textscale);
+ }
+ else
+ originalWidth = UI_Text_Width(item->text, item->textscale);
+ }
- if( rect->x != awc[ i ].rect.x ||
- rect->y != awc[ i ].rect.y ||
- rect->w != awc[ i ].rect.w ||
- rect->h != awc[ i ].rect.h )
- continue;
+ item->textRect.w = UI_Text_Width(textPtr, item->textscale);
+ item->textRect.h = UI_Text_Height(textPtr, item->textscale);
- if( awc[ i ].textWidth != width || awc[ i ].textHeight != height )
- continue;
+ if (item->textvalignment == VALIGN_BOTTOM)
+ item->textRect.y = item->textaligny + item->window.rect.h;
+ else if (item->textvalignment == VALIGN_CENTER)
+ item->textRect.y = item->textaligny + ((item->textRect.h + item->window.rect.h) / 2.0f);
+ else if (item->textvalignment == VALIGN_TOP)
+ item->textRect.y = item->textaligny + item->textRect.h;
- //this is a match
- return i;
- }
+ if (item->textalignment == ALIGN_LEFT)
+ item->textRect.x = item->textalignx;
+ else if (item->textalignment == ALIGN_CENTER)
+ item->textRect.x = item->textalignx + ((item->window.rect.w - originalWidth) / 2.0f);
+ else if (item->textalignment == ALIGN_RIGHT)
+ item->textRect.x = item->textalignx + item->window.rect.w - originalWidth;
- //no match - autowrap isn't cached
- return -1;
+ ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
+ }
}
-void Item_Text_AutoWrapped_Paint( itemDef_t *item )
+void Item_TextColor(itemDef_t *item, vec4_t *newColor)
{
- char text[ 1024 ];
- const char *p, *textPtr, *newLinePtr;
- char buff[ 1024 ];
- char lastCMod[ 2 ] = { 0, 0 };
- qboolean forwardColor = qfalse;
- int width, height, len, textWidth, newLine, newLineWidth;
- int skipLines, totalLines, lineNum = 0;
- float y, totalY, diffY;
- vec4_t color;
- int cache, i;
+ vec4_t lowLight;
+ menuDef_t *parent = (menuDef_t *)item->parent;
- textWidth = 0;
- newLinePtr = NULL;
+ Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle,
+ qtrue, parent->fadeAmount);
- if( item->text == NULL )
- {
- if( item->cvar == NULL )
- return;
+ if (item->window.flags & WINDOW_HASFOCUS)
+ memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
+ else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime / BLINK_DIVISOR) & 1))
+ {
+ lowLight[0] = 0.8 * item->window.foreColor[0];
+ lowLight[1] = 0.8 * item->window.foreColor[1];
+ lowLight[2] = 0.8 * item->window.foreColor[2];
+ lowLight[3] = 0.8 * item->window.foreColor[3];
+ LerpColor(item->window.foreColor, lowLight, *newColor, 0.5 + 0.5 * sin(DC->realTime / PULSE_DIVISOR));
+ }
else
{
- DC->getCVarString( item->cvar, text, sizeof( text ) );
- textPtr = text;
+ memcpy(newColor, &item->window.foreColor, sizeof(vec4_t));
+ // items can be enabled and disabled based on cvars
}
- }
- else
- textPtr = item->text;
- if( *textPtr == '\0' )
- return;
-
- Item_TextColor( item, &color );
- Item_SetTextExtents( item, &width, &height, textPtr );
+ if (item->enableCvar != NULL && *item->enableCvar && item->cvarTest != NULL && *item->cvarTest)
+ {
+ if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE))
+ memcpy(newColor, &parent->disableColor, sizeof(vec4_t));
+ }
+}
- //check if this block is cached
- cache = checkCache( textPtr, &item->window.rect, width, height );
- if( cache >= 0 )
- {
- lineNum = awc[ cache ].numLines;
+static void SkipColorCodes(const char **text, char *lastColor)
+{
+ while (Q_IsColorString(*text))
+ {
+ lastColor[0] = (*text)[0];
+ lastColor[1] = (*text)[1];
+ (*text) += 2;
+ }
+}
- for( i = 0; i < lineNum; i++ )
+static void SkipWhiteSpace(const char **text, char *lastColor)
+{
+ while (**text)
{
- item->textRect.x = awc[ cache ].lineOffsets[ i ][ 0 ];
- item->textRect.y = awc[ cache ].lineOffsets[ i ][ 1 ];
+ SkipColorCodes(text, lastColor);
- DC->drawText( item->textRect.x, item->textRect.y, item->textscale, color,
- awc[ cache ].lines[ i ], 0, 0, item->textStyle );
+ if (**text != '\n' && isspace(**text))
+ (*text)++;
+ else
+ break;
}
- }
- else
- {
- y = item->textaligny;
- len = 0;
- buff[ 0 ] = '\0';
- newLine = 0;
- newLineWidth = 0;
- p = textPtr;
+}
- totalLines = Item_Text_AutoWrapped_Lines( item );
+const char *Item_Text_Wrap(const char *text, float scale, float width)
+{
+ static char out[8192] = "";
+ char *paint = out;
+ char c[3] = "";
+ const char *p;
+ const char *eos;
+ float indentWidth = 0.0f;
- totalY = totalLines * ( height + 5 );
- diffY = totalY - item->window.rect.h;
+ if (!text)
+ return NULL;
- if( diffY > 0.0f )
- skipLines = (int)( diffY / ( (float)height + 5.0f ) );
- else
- skipLines = 0;
-
- //set up a cache entry
- strcpy( awc[ cacheIndex ].text, textPtr );
- awc[ cacheIndex ].rect.x = item->window.rect.x;
- awc[ cacheIndex ].rect.y = item->window.rect.y;
- awc[ cacheIndex ].rect.w = item->window.rect.w;
- awc[ cacheIndex ].rect.h = item->window.rect.h;
- awc[ cacheIndex ].textWidth = width;
- awc[ cacheIndex ].textHeight = height;
-
- while( p )
- {
- textWidth = DC->textWidth( buff, item->textscale, 0 );
-
- if( *p == '^' )
- {
- lastCMod[ 0 ] = p[ 0 ];
- lastCMod[ 1 ] = p[ 1 ];
- }
-
- if( *p == ' ' || *p == '\t' || *p == '\n' || *p == '\0' )
- {
- newLine = len;
- newLinePtr = p+1;
- newLineWidth = textWidth;
-
- if( *p == '\n' ) //don't forward colours past deilberate \n's
- lastCMod[ 0 ] = lastCMod[ 1 ] = 0;
- else
- forwardColor = qtrue;
- }
+ p = text;
+ eos = p + strlen(p);
+
+ if ((eos - p) >= sizeof(out))
+ return NULL;
- //TA: forceably split lines that are too long (where normal splitage has failed)
- if( textWidth > item->window.rect.w && newLine == 0 && *p != '\n' )
- {
- newLine = len;
- newLinePtr = p;
- newLineWidth = textWidth;
+ *paint = '\0';
+
+ while (*p)
+ {
+ float textWidth = 0.0f;
+ const char *eol = p;
+ const char *q = p;
+ float testWidth = width - indentWidth;
- forwardColor = qtrue;
- }
+ SkipColorCodes(&q, c);
- if( ( newLine && textWidth > item->window.rect.w ) || *p == '\n' || *p == '\0' )
- {
- if( len )
+ while (q && textWidth < testWidth)
{
- if( item->textalignment == ITEM_ALIGN_LEFT )
- item->textRect.x = item->textalignx;
- else if( item->textalignment == ITEM_ALIGN_RIGHT )
- item->textRect.x = item->textalignx - newLineWidth;
- else if( item->textalignment == ITEM_ALIGN_CENTER )
- item->textRect.x = item->textalignx - newLineWidth / 2;
+ qboolean previousCharIsSpace = qfalse;
+
+ // Remaining string is too short to wrap
+ if (q >= eos)
+ {
+ eol = eos;
+ break;
+ }
+
+ if (q > p && *q == INDENT_MARKER)
+ {
+ indentWidth = textWidth;
+ eol = p;
+ }
- item->textRect.y = y;
- ToWindowCoords( &item->textRect.x, &item->textRect.y, &item->window );
- //
- buff[ newLine ] = '\0';
+ // Some color escapes might still be present
+ SkipColorCodes(&q, c);
- if( !skipLines )
- {
- DC->drawText( item->textRect.x, item->textRect.y, item->textscale, color, buff, 0, 0, item->textStyle );
+ // Manual line break
+ if (*q == '\n')
+ {
+ eol = q + 1;
+ break;
+ }
- strcpy( awc[ cacheIndex ].lines[ lineNum ], buff );
- awc[ cacheIndex ].lineOffsets[ lineNum ][ 0 ] = item->textRect.x;
- awc[ cacheIndex ].lineOffsets[ lineNum ][ 1 ] = item->textRect.y;
+ if (!previousCharIsSpace && isspace(*q))
+ eol = q;
- lineNum++;
- }
+ textWidth += UI_Char_Width(&q, scale);
}
- if( *p == '\0' )
- break;
- //
- if( !skipLines )
- y += height + 5;
+ // No split has taken place, so just split mid-word
+ if (eol == p)
+ eol = q;
+
+ // Note that usage of strcat and strlen is deliberately being
+ // avoided here as it becomes surprisingly expensive on larger
+ // blocks of text
- if( skipLines )
- skipLines--;
-
- p = newLinePtr;
- len = 0;
- newLine = 0;
- newLineWidth = 0;
+ // Copy text
+ strncpy(paint, p, eol - p);
+ paint += (eol - p);
+ *paint = '\0';
- if( forwardColor && lastCMod[ 0 ] != 0 )
- {
- buff[ len++ ] = lastCMod[ 0 ];
- buff[ len++ ] = lastCMod[ 1 ];
- buff[ len ] = '\0';
+ p = eol;
- forwardColor = qfalse;
+ if (paint - out > 0 && *(paint - 1) == '\n')
+ {
+ // The line is deliberately broken, clear the color and
+ // any current indent
+ c[0] = '\0';
+ indentWidth = 0.0f;
}
+ else
+ {
+ // Add a \n if it's not there already
+ *paint++ = '\n';
+ *paint = '\0';
+
+ // Insert a pixel indent on the next line
+ if (indentWidth > 0.0f)
+ {
+ const char *indentMarkerText = va("%f%c", indentWidth, INDENT_MARKER);
+ int indentMarkerTextLength = strlen(indentMarkerText);
+
+ strncpy(paint, indentMarkerText, indentMarkerTextLength);
+ paint += indentMarkerTextLength;
+ *paint = '\0';
+ }
- continue;
- }
+ // Skip leading whitespace on next line and save the
+ // last color code
+ SkipWhiteSpace(&p, c);
+ }
- buff[ len++ ] = *p++;
- buff[ len ] = '\0';
+ if (c[0])
+ {
+ *paint++ = c[0];
+ *paint++ = c[1];
+ *paint = '\0';
+ }
}
- //mark the end of the lines list
- awc[ cacheIndex ].numLines = lineNum;
+ return out;
+}
+
+#define MAX_WRAP_CACHE 16
+#define MAX_WRAP_LINES 32
+#define MAX_WRAP_TEXT 512
+
+typedef struct {
+ char text[MAX_WRAP_TEXT * MAX_WRAP_LINES];
+ rectDef_t rect;
+ float scale;
+ char lines[MAX_WRAP_LINES][MAX_WRAP_TEXT];
+ float lineCoords[MAX_WRAP_LINES][2];
+ int numLines;
+} wrapCache_t;
+
+static wrapCache_t wrapCache[MAX_WRAP_CACHE];
+static qboolean cacheCreationFailed = qfalse;
+static int cacheWriteIndex = 0;
+static int cacheReadIndex = 0;
+static int cacheReadLineNum = 0;
+
+static void UI_CreateCacheEntry(const char *text, const rectDef_t *rect, float scale)
+{
+ wrapCache_t *cacheEntry = &wrapCache[cacheWriteIndex];
- //increment cacheIndex
- cacheIndex = ( cacheIndex + 1 ) % MAX_AUTOWRAP_CACHE;
- }
+ if (strlen(text) >= sizeof(cacheEntry->text))
+ {
+ cacheCreationFailed = qtrue;
+ return;
+ }
+
+ strcpy(cacheEntry->text, text);
+ cacheEntry->rect = *rect;
+ cacheEntry->scale = scale;
+ cacheEntry->numLines = 0;
}
-void Item_Text_Wrapped_Paint(itemDef_t *item) {
- char text[1024];
- const char *p, *start, *textPtr;
- char buff[1024];
- int width, height;
- float x, y;
- vec4_t color;
+static void UI_AddCacheEntryLine(const char *text, float x, float y)
+{
+ wrapCache_t *cacheEntry = &wrapCache[cacheWriteIndex];
- // now paint the text and/or any optional images
- // default to left
+ if (cacheCreationFailed)
+ return;
- if (item->text == NULL) {
- if (item->cvar == NULL) {
- return;
+ if (cacheEntry->numLines >= MAX_WRAP_LINES || strlen(text) >= sizeof(cacheEntry->lines[0]))
+ {
+ cacheCreationFailed = qtrue;
+ return;
}
- else {
- DC->getCVarString(item->cvar, text, sizeof(text));
- textPtr = text;
+
+ strcpy(cacheEntry->lines[cacheEntry->numLines], text);
+ cacheEntry->lineCoords[cacheEntry->numLines][0] = x;
+ cacheEntry->lineCoords[cacheEntry->numLines][1] = y;
+ cacheEntry->numLines++;
+}
+
+static void UI_FinishCacheEntry(void)
+{
+ if (cacheCreationFailed)
+ {
+ wrapCache[cacheWriteIndex].text[0] = '\0';
+ wrapCache[cacheWriteIndex].numLines = 0;
+ cacheCreationFailed = qfalse;
}
- }
- else {
- textPtr = item->text;
- }
- if (*textPtr == '\0') {
- return;
- }
+ else
+ cacheWriteIndex = (cacheWriteIndex + 1) % MAX_WRAP_CACHE;
+}
- Item_TextColor(item, &color);
- Item_SetTextExtents(item, &width, &height, textPtr);
+static qboolean UI_CheckWrapCache(const char *text, const rectDef_t *rect, float scale)
+{
+ int i;
+
+ for (i = 0; i < MAX_WRAP_CACHE; i++)
+ {
+ wrapCache_t *cacheEntry = &wrapCache[i];
+
+ if (rect->x != cacheEntry->rect.x || rect->y != cacheEntry->rect.y || rect->w != cacheEntry->rect.w ||
+ rect->h != cacheEntry->rect.h)
+ continue;
+
+ if (strcmp(text, cacheEntry->text))
+ continue;
+
+ if (cacheEntry->scale != scale)
+ continue;
+
+ cacheReadIndex = i;
+ cacheReadLineNum = 0;
+
+ return qtrue;
+ }
- x = item->textRect.x;
- y = item->textRect.y;
- start = textPtr;
- p = strchr(textPtr, '\r');
- while (p && *p) {
- strncpy(buff, start, p-start+1);
- buff[p-start] = '\0';
- DC->drawText(x, y, item->textscale, color, buff, 0, 0, item->textStyle);
- y += height + 5;
- start += p - start + 1;
- p = strchr(p+1, '\r');
- }
- DC->drawText(x, y, item->textscale, color, start, 0, 0, item->textStyle);
+ return qfalse;
}
-void Item_Text_Paint(itemDef_t *item) {
- char text[1024];
- const char *textPtr;
- int height, width;
- vec4_t color;
+static qboolean UI_NextWrapLine(const char **text, float *x, float *y)
+{
+ wrapCache_t *cacheEntry = &wrapCache[cacheReadIndex];
+
+ if (cacheReadLineNum >= cacheEntry->numLines)
+ return qfalse;
+
+ *text = cacheEntry->lines[cacheReadLineNum];
+ *x = cacheEntry->lineCoords[cacheReadLineNum][0];
+ *y = cacheEntry->lineCoords[cacheReadLineNum][1];
- if (item->window.flags & WINDOW_WRAPPED) {
- Item_Text_Wrapped_Paint(item);
- return;
- }
- if (item->window.flags & WINDOW_AUTOWRAPPED) {
- Item_Text_AutoWrapped_Paint(item);
- return;
- }
+ cacheReadLineNum++;
+
+ return qtrue;
+}
+
+void Item_Text_Wrapped_Paint(itemDef_t *item)
+{
+ char text[1024];
+ const char *p, *textPtr;
+ float x, y, w, h;
+ vec4_t color;
+ qboolean useWrapCache = (qboolean)DC->getCVarValue("ui_textWrapCache");
- if (item->text == NULL) {
- if (item->cvar == NULL) {
- return;
+ if (item->text == NULL)
+ {
+ if (item->cvar == NULL)
+ return;
+ else
+ {
+ DC->getCVarString(item->cvar, text, sizeof(text));
+ textPtr = text;
+ }
}
- else {
- DC->getCVarString(item->cvar, text, sizeof(text));
- textPtr = text;
+ else
+ textPtr = item->text;
+
+ if (*textPtr == '\0')
+ return;
+
+ Item_TextColor(item, &color);
+
+ // Check if this block is cached
+ if (useWrapCache && UI_CheckWrapCache(textPtr, &item->window.rect, item->textscale))
+ {
+ while (UI_NextWrapLine(&p, &x, &y))
+ {
+ UI_Text_Paint(x, y, item->textscale, color, p, 0, 0, item->textStyle);
+ }
}
- }
- else {
- textPtr = item->text;
- }
+ else
+ {
+ char buff[1024];
+ float fontHeight = UI_Text_EmHeight(item->textscale);
+ const float lineSpacing = fontHeight * 0.4f;
+ float lineHeight = fontHeight + lineSpacing;
+ float textHeight;
+ int textLength;
+ int firstLine, paintLines, totalLines, lineNum;
+ float paintY;
+ int i;
+
+ if (useWrapCache)
+ UI_CreateCacheEntry(textPtr, &item->window.rect, item->textscale);
+
+ x = item->window.rect.x + item->textalignx;
+ y = item->window.rect.y + item->textaligny;
+ w = item->window.rect.w - (2.0f * item->textalignx);
+ h = item->window.rect.h - (2.0f * item->textaligny);
+
+ textPtr = Item_Text_Wrap(textPtr, item->textscale, w);
+ textLength = strlen(textPtr);
+
+ // Count lines
+ totalLines = 0;
+
+ for (i = 0; i < textLength; i++)
+ {
+ if (textPtr[i] == '\n')
+ totalLines++;
+ }
+ if (textLength && textPtr[textLength - 1] != '\n')
+ {
+ totalLines++; // count the last, non-newline-terminated line
+ textLength++; // a '\0' will mark the end of the last line
+ }
- // this needs to go here as it sets extents for cvar types as well
- Item_SetTextExtents(item, &width, &height, textPtr);
+ paintLines = (int)floor((h + lineSpacing) / lineHeight);
- if (*textPtr == '\0') {
- return;
- }
+ if (totalLines > paintLines)
+ firstLine = totalLines - paintLines;
+ else
+ {
+ firstLine = 0;
+ paintLines = totalLines;
+ }
+
+ textHeight = (paintLines * lineHeight) - lineSpacing;
+
+ switch (item->textvalignment)
+ {
+ default:
+
+ case VALIGN_BOTTOM:
+ paintY = y + (h - textHeight);
+ break;
+
+ case VALIGN_CENTER:
+ paintY = y + ((h - textHeight) / 2.0f);
+ break;
+
+ case VALIGN_TOP:
+ paintY = y;
+ break;
+ }
+
+ p = textPtr;
+ // skip the first few lines
+ for (lineNum = 0; lineNum < firstLine; lineNum++)
+ p = strchr(p, '\n') + 1;
- Item_TextColor(item, &color);
+ for (i = p - textPtr; i < textLength && lineNum < firstLine + paintLines; i++)
+ {
+ unsigned long lineLength = &textPtr[i] - p;
+
+ if (lineLength >= sizeof(buff))
+ break;
+
+ if (textPtr[i] == '\n' || textPtr[i] == '\0')
+ {
+ itemDef_t lineItem;
+
+ memset(&lineItem, 0, sizeof(itemDef_t));
+ strncpy(buff, p, lineLength);
+ buff[lineLength] = '\0';
+ p = &textPtr[i + 1];
+
+ lineItem.type = ITEM_TYPE_TEXT;
+ lineItem.textscale = item->textscale;
+ lineItem.textStyle = item->textStyle;
+ lineItem.text = buff;
+ lineItem.textalignment = item->textalignment;
+ lineItem.textvalignment = VALIGN_TOP;
+ lineItem.textalignx = 0.0f;
+ lineItem.textaligny = 0.0f;
+
+ lineItem.textRect.w = 0.0f;
+ lineItem.textRect.h = 0.0f;
+ lineItem.window.rect.x = x;
+ lineItem.window.rect.y = paintY + ((lineNum - firstLine) * lineHeight);
+ lineItem.window.rect.w = w;
+ lineItem.window.rect.h = lineHeight;
+ lineItem.window.border = item->window.border;
+ lineItem.window.borderSize = item->window.borderSize;
+
+ if (DC->getCVarValue("ui_developer"))
+ {
+ vec4_t color;
+ color[0] = color[2] = color[3] = 1.0f;
+ color[1] = 0.0f;
+ DC->drawRect(lineItem.window.rect.x, lineItem.window.rect.y, lineItem.window.rect.w,
+ lineItem.window.rect.h, 1, color);
+ }
+
+ Item_SetTextExtents(&lineItem, buff);
+ UI_Text_Paint(lineItem.textRect.x, lineItem.textRect.y, lineItem.textscale, color, buff, 0, 0,
+ lineItem.textStyle);
+
+ if (useWrapCache)
+ UI_AddCacheEntryLine(buff, lineItem.textRect.x, lineItem.textRect.y);
+
+ lineNum++;
+ }
+ }
+
+ if (useWrapCache)
+ UI_FinishCacheEntry();
+ }
+}
- //FIXME: this is a fucking mess
/*
- adjust = 0;
- if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
- adjust = 0.5;
- }
-
- if (item->textStyle == ITEM_TEXTSTYLE_SHADOWED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
- Fade(&item->window.flags, &DC->Assets.shadowColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
- DC->drawText(item->textRect.x + DC->Assets.shadowX, item->textRect.y + DC->Assets.shadowY, item->textscale, DC->Assets.shadowColor, textPtr, adjust);
- }
+==============
+UI_DrawTextBlock
+==============
*/
+void UI_DrawTextBlock(rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int textalign,
+ int textvalign, int textStyle, const char *text)
+{
+ static menuDef_t dummyParent;
+ static itemDef_t textItem;
+
+ textItem.text = text;
+
+ textItem.parent = &dummyParent;
+ memcpy(textItem.window.foreColor, color, sizeof(vec4_t));
+ textItem.window.flags = 0;
+
+ textItem.window.rect.x = rect->x;
+ textItem.window.rect.y = rect->y;
+ textItem.window.rect.w = rect->w;
+ textItem.window.rect.h = rect->h;
+ textItem.window.border = 0;
+ textItem.window.borderSize = 0.0f;
+ textItem.textRect.x = 0.0f;
+ textItem.textRect.y = 0.0f;
+ textItem.textRect.w = 0.0f;
+ textItem.textRect.h = 0.0f;
+ textItem.textalignment = textalign;
+ textItem.textvalignment = textvalign;
+ textItem.textalignx = text_x;
+ textItem.textaligny = text_y;
+ textItem.textscale = scale;
+ textItem.textStyle = textStyle;
+
+ // Utilise existing wrap code
+ Item_Text_Wrapped_Paint(&textItem);
+}
+
+void Item_Text_Paint(itemDef_t *item)
+{
+ char text[1024];
+ const char *textPtr;
+ vec4_t color;
+
+ if (item->window.flags & WINDOW_WRAPPED)
+ {
+ Item_Text_Wrapped_Paint(item);
+ return;
+ }
+ if (item->text == NULL)
+ {
+ if (item->cvar == NULL)
+ return;
+ else
+ {
+ DC->getCVarString(item->cvar, text, sizeof(text));
+ textPtr = text;
+ }
+ }
+ else
+ textPtr = item->text;
-// if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
-// Fade(&item->window.flags, &item->window.outlineColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
-// /*
-// Text_Paint(item->textRect.x-1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x+1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x-1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x+1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x-1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x+1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
-// */
-// DC->drawText(item->textRect.x - 1, item->textRect.y + 1, item->textscale * 1.02, item->window.outlineColor, textPtr, adjust);
-// }
-
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, textPtr, 0, 0, item->textStyle);
-}
-
-
-
-//float trap_Cvar_VariableValue( const char *var_name );
-//void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-
-void Item_TextField_Paint(itemDef_t *item) {
- char buff[1024];
- vec4_t newColor;
- int offset;
- menuDef_t *parent = (menuDef_t*)item->parent;
- editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
-
- Item_Text_Paint(item);
-
- buff[0] = '\0';
-
- if (item->cvar) {
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- }
-
- parent = (menuDef_t*)item->parent;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
-/* lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
- //TA:
- memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- offset = (item->text && *item->text) ? 8 : 0;
- if (item->window.flags & WINDOW_HASFOCUS && g_editingField) {
- char cursor = DC->getOverstrikeMode() ? '_' : '|';
- DC->drawTextWithCursor(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, item->cursorPos - editPtr->paintOffset , cursor, editPtr->maxPaintChars, item->textStyle);
- } else {
- DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, 0, editPtr->maxPaintChars, item->textStyle);
- }
-
-}
-
-void Item_YesNo_Paint(itemDef_t *item) {
- vec4_t newColor;
- float value;
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
-/* lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
- //TA:
- memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- if (item->text) {
- Item_Text_Paint(item);
- DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
- } else {
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
- }
-}
-
-void Item_Multi_Paint(itemDef_t *item) {
- vec4_t newColor;
- const char *text = "";
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
-/* lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
- //TA:
- memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- text = Item_Multi_Setting(item);
-
- if (item->text) {
+ // this needs to go here as it sets extents for cvar types as well
+ Item_SetTextExtents(item, textPtr);
+
+ if (*textPtr == '\0')
+ return;
+
+ Item_TextColor(item, &color);
+
+ UI_Text_Paint(item->textRect.x, item->textRect.y, item->textscale, color, textPtr, 0, 0, item->textStyle);
+}
+
+void Item_TextField_Paint(itemDef_t *item)
+{
+ char buff[1024];
+ vec4_t newColor;
+ menuDef_t *parent;
+ int offset = (item->text && *item->text) ? ITEM_VALUE_OFFSET : 0;
+ editFieldDef_t *editPtr = item->typeData.edit;
+ char cursor = DC->getOverstrikeMode() ? '|' : '_';
+ qboolean editing = (item->window.flags & WINDOW_HASFOCUS && g_editingField);
+ const int cursorWidth = editing ? EDIT_CURSOR_WIDTH : 0;
+
+ // FIXME: causes duplicate printing if item->text is not set (NULL)
Item_Text_Paint(item);
- DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
- } else {
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
- }
+
+ buff[0] = '\0';
+
+ if (item->cvar)
+ DC->getCVarString(item->cvar, buff, sizeof(buff));
+
+ // maxFieldWidth hasn't been set, so use the item's rect
+ if (editPtr->maxFieldWidth == 0)
+ {
+ editPtr->maxFieldWidth =
+ item->window.rect.w - (item->textRect.w + offset + (item->textRect.x - item->window.rect.x));
+
+ if (editPtr->maxFieldWidth < MIN_FIELD_WIDTH)
+ editPtr->maxFieldWidth = MIN_FIELD_WIDTH;
+ }
+
+ if (!editing)
+ editPtr->paintOffset = 0;
+
+ // Shorten string to max viewable
+ while (UI_Text_Width(buff + editPtr->paintOffset, item->textscale) > (editPtr->maxFieldWidth - cursorWidth) &&
+ strlen(buff) > 0)
+ buff[strlen(buff) - 1] = '\0';
+
+ parent = (menuDef_t *)item->parent;
+
+ if (item->window.flags & WINDOW_HASFOCUS)
+ memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
+ else
+ memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
+
+ if (editing)
+ {
+ UI_Text_PaintWithCursor(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale,
+ newColor, buff + editPtr->paintOffset, item->cursorPos - editPtr->paintOffset, cursor,
+ editPtr->maxPaintChars, item->textStyle);
+ }
+ else
+ {
+ UI_Text_Paint(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor,
+ buff + editPtr->paintOffset, 0, editPtr->maxPaintChars, item->textStyle);
+ }
}
+void Item_YesNo_Paint(itemDef_t *item)
+{
+ vec4_t newColor;
+ float value;
+ int offset;
+ menuDef_t *parent = (menuDef_t *)item->parent;
-typedef struct {
- char *command;
- int id;
- int defaultbind1;
- int defaultbind2;
- int bind1;
- int bind2;
-} bind_t;
+ value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
-typedef struct
-{
- char* name;
- float defaultvalue;
- float value;
-} configcvar_t;
-
-
-static bind_t g_bindings[] =
-{
- { "+scores", K_TAB, -1, -1, -1 },
- { "+button2", K_ENTER, -1, -1, -1 },
- { "+speed", K_SHIFT, -1, -1, -1 },
- { "boost", 'x', -1, -1, -1 }, //TA: human sprinting
- { "+forward", K_UPARROW, -1, -1, -1 },
- { "+back", K_DOWNARROW, -1, -1, -1 },
- { "+moveleft", ',', -1, -1, -1 },
- { "+moveright", '.', -1, -1, -1 },
- { "+moveup", K_SPACE, -1, -1, -1 },
- { "+movedown", 'c', -1, -1, -1 },
- { "+left", K_LEFTARROW, -1, -1, -1 },
- { "+right", K_RIGHTARROW, -1, -1, -1 },
- { "+strafe", K_ALT, -1, -1, -1 },
- { "+lookup", K_PGDN, -1, -1, -1 },
- { "+lookdown", K_DEL, -1, -1, -1 },
- { "+mlook", '/', -1, -1, -1 },
- { "centerview", K_END, -1, -1, -1 },
- { "+zoom", -1, -1, -1, -1 },
- { "weapon 1", '1', -1, -1, -1 },
- { "weapon 2", '2', -1, -1, -1 },
- { "weapon 3", '3', -1, -1, -1 },
- { "weapon 4", '4', -1, -1, -1 },
- { "weapon 5", '5', -1, -1, -1 },
- { "weapon 6", '6', -1, -1, -1 },
- { "weapon 7", '7', -1, -1, -1 },
- { "weapon 8", '8', -1, -1, -1 },
- { "weapon 9", '9', -1, -1, -1 },
- { "weapon 10", '0', -1, -1, -1 },
- { "weapon 11", -1, -1, -1, -1 },
- { "weapon 12", -1, -1, -1, -1 },
- { "weapon 13", -1, -1, -1, -1 },
- { "+attack", K_MOUSE1, -1, -1, -1 },
- { "+button5", K_MOUSE2, -1, -1, -1 }, //TA: secondary attack
- { "reload", 'r', -1, -1, -1 }, //TA: reload
- { "buy ammo", 'b', -1, -1, -1 }, //TA: buy ammo
- { "itemact medkit", 'm', -1, -1, -1 }, //TA: use medkit
- { "+button7", 'q', -1, -1, -1 }, //TA: buildable use
- { "deconstruct", 'e', -1, -1, -1 }, //TA: buildable destroy
- { "weapprev", '[', -1, -1, -1 },
- { "weapnext", ']', -1, -1, -1 },
- { "+button3", K_MOUSE3, -1, -1, -1 },
- { "+button4", K_MOUSE4, -1, -1, -1 },
- { "vote yes", K_F1, -1, -1, -1 },
- { "vote no", K_F2, -1, -1, -1 },
- { "teamvote yes", K_F3, -1, -1, -1 },
- { "teamvote no", K_F4, -1, -1, -1 },
- { "scoresUp", K_KP_PGUP, -1, -1, -1 },
- { "scoresDown", K_KP_PGDN, -1, -1, -1 },
- // bk001205 - this one below was: '-1'
- { "messagemode", -1, -1, -1, -1 },
- { "messagemode2", -1, -1, -1, -1 },
- { "messagemode3", -1, -1, -1, -1 },
- { "messagemode4", -1, -1, -1, -1 }
-};
+ if (item->window.flags & WINDOW_HASFOCUS)
+ memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
+ else
+ memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
+ offset = (item->text && *item->text) ? ITEM_VALUE_OFFSET : 0;
-static const int g_bindCount = sizeof(g_bindings) / sizeof(bind_t);
+ if (item->text)
+ {
+ Item_Text_Paint(item);
+ UI_Text_Paint(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor,
+ (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
+ }
+ else
+ UI_Text_Paint(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0,
+ item->textStyle);
+}
+
+void Item_Multi_Paint(itemDef_t *item)
+{
+ vec4_t newColor;
+ const char *text = "";
+ menuDef_t *parent = (menuDef_t *)item->parent;
+
+ if (item->window.flags & WINDOW_HASFOCUS)
+ memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
+ else
+ memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
+
+ text = Item_Multi_Setting(item);
+
+ if (item->text)
+ {
+ Item_Text_Paint(item);
+ UI_Text_Paint(item->textRect.x + item->textRect.w + ITEM_VALUE_OFFSET, item->textRect.y, item->textscale,
+ newColor, text, 0, 0, item->textStyle);
+ }
+ else
+ UI_Text_Paint(item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
+}
+
+void Item_Cycle_Paint(itemDef_t *item)
+{
+ vec4_t newColor;
+ const char *text = "";
+ menuDef_t *parent = (menuDef_t *)item->parent;
+
+ if (item->window.flags & WINDOW_HASFOCUS)
+ memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
+ else
+ memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
+
+ if (item->typeData.cycle)
+ text = DC->feederItemText(item->feederID, item->typeData.cycle->cursorPos, 0, NULL);
+
+ if (item->text)
+ {
+ Item_Text_Paint(item);
+ UI_Text_Paint(item->textRect.x + item->textRect.w + ITEM_VALUE_OFFSET, item->textRect.y, item->textscale,
+ newColor, text, 0, 0, item->textStyle);
+ }
+ else
+ UI_Text_Paint(item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
+}
+
+typedef struct {
+ char *command;
+ int id;
+ int defaultbind1;
+ int defaultbind2;
+ int bind1;
+ int bind2;
+} bind_t;
+
+static bind_t g_bindings[] = {{"+scores", K_TAB, -1, -1, -1, -1}, {"+button2", K_ENTER, -1, -1, -1, -1},
+ {"+speed", K_SHIFT, -1, -1, -1, -1}, {"+button6", 'z', -1, -1, -1, -1}, // human dodging
+ {"+button8", 'x', -1, -1, -1, -1}, {"+forward", K_UPARROW, -1, -1, -1, -1}, {"+back", K_DOWNARROW, -1, -1, -1, -1},
+ {"+moveleft", ',', -1, -1, -1, -1}, {"+moveright", '.', -1, -1, -1, -1}, {"+moveup", K_SPACE, -1, -1, -1, -1},
+ {"+movedown", 'c', -1, -1, -1, -1}, {"+left", K_LEFTARROW, -1, -1, -1, -1},
+ {"+right", K_RIGHTARROW, -1, -1, -1, -1}, {"+strafe", K_ALT, -1, -1, -1, -1}, {"+lookup", K_PGDN, -1, -1, -1, -1},
+ {"+lookdown", K_DEL, -1, -1, -1, -1}, {"+mlook", '/', -1, -1, -1, -1}, {"centerview", K_END, -1, -1, -1, -1},
+ {"+zoom", -1, -1, -1, -1, -1}, {"weapon 1", '1', -1, -1, -1, -1}, {"weapon 2", '2', -1, -1, -1, -1},
+ {"weapon 3", '3', -1, -1, -1, -1}, {"weapon 4", '4', -1, -1, -1, -1}, {"weapon 5", '5', -1, -1, -1, -1},
+ {"weapon 6", '6', -1, -1, -1, -1}, {"weapon 7", '7', -1, -1, -1, -1}, {"weapon 8", '8', -1, -1, -1, -1},
+ {"weapon 9", '9', -1, -1, -1, -1}, {"weapon 10", '0', -1, -1, -1, -1}, {"weapon 11", -1, -1, -1, -1, -1},
+ {"weapon 12", -1, -1, -1, -1, -1}, {"weapon 13", -1, -1, -1, -1, -1}, {"+attack", K_MOUSE1, -1, -1, -1, -1},
+ {"+button5", K_MOUSE2, -1, -1, -1, -1}, // secondary attack
+ {"reload", 'r', -1, -1, -1, -1}, // reload
+ {"buy ammo", 'b', -1, -1, -1, -1}, // buy ammo
+ {"itemact medkit", 'm', -1, -1, -1, -1}, // use medkit
+ {"+button7", 'q', -1, -1, -1, -1}, // buildable use
+ {"deconstruct", 'e', -1, -1, -1, -1}, // buildable destroy
+ {"weapprev", '[', -1, -1, -1, -1}, {"weapnext", ']', -1, -1, -1, -1}, {"+button3", K_MOUSE3, -1, -1, -1, -1},
+ {"+button4", K_MOUSE4, -1, -1, -1, -1}, {"vote yes", K_F1, -1, -1, -1, -1}, {"vote no", K_F2, -1, -1, -1, -1},
+ {"teamvote yes", K_F3, -1, -1, -1, -1}, {"teamvote no", K_F4, -1, -1, -1, -1},
+ {"scoresUp", K_KP_PGUP, -1, -1, -1, -1}, {"scoresDown", K_KP_PGDN, -1, -1, -1, -1},
+ {"screenshotJPEG", -1, -1, -1, -1, -1}, {"messagemode", -1, -1, -1, -1, -1}, {"messagemode2", -1, -1, -1, -1, -1}};
+
+static const size_t g_bindCount = ARRAY_LEN(g_bindings);
/*
=================
Controls_GetKeyAssignment
=================
*/
-static void Controls_GetKeyAssignment (char *command, int *twokeys)
+static void Controls_GetKeyAssignment(char *command, int *twokeys)
{
- int count;
- int j;
- char b[256];
+ int count;
+ int j;
+ char b[256];
- twokeys[0] = twokeys[1] = -1;
- count = 0;
+ twokeys[0] = twokeys[1] = -1;
+ count = 0;
- for ( j = 0; j < 256; j++ )
- {
- DC->getBindingBuf( j, b, 256 );
- if ( *b == 0 ) {
- continue;
- }
- if ( !Q_stricmp( b, command ) ) {
- twokeys[count] = j;
- count++;
- if (count == 2) {
- break;
- }
+ for (j = 0; j < 256; j++)
+ {
+ DC->getBindingBuf(j, b, 256);
+
+ if (*b == 0)
+ continue;
+
+ if (!Q_stricmp(b, command))
+ {
+ twokeys[count] = j;
+ count++;
+
+ if (count == 2)
+ break;
+ }
}
- }
}
/*
=================
Controls_GetConfig
+
+Iterate each command, get its numeric binding
=================
*/
-void Controls_GetConfig( void )
+void Controls_GetConfig(void)
{
- int i;
- int twokeys[ 2 ];
-
- // iterate each command, get its numeric binding
- for( i = 0; i < g_bindCount; i++ )
- {
- Controls_GetKeyAssignment( g_bindings[ i ].command, twokeys );
+ size_t i;
+ int twokeys[2];
- g_bindings[ i ].bind1 = twokeys[ 0 ];
- g_bindings[ i ].bind2 = twokeys[ 1 ];
- }
+ for (i = 0; i < g_bindCount; i++)
+ {
+ Controls_GetKeyAssignment(g_bindings[i].command, twokeys);
- //s_controls.invertmouse.curvalue = DC->getCVarValue( "m_pitch" ) < 0;
- //s_controls.smoothmouse.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) );
- //s_controls.alwaysrun.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) );
- //s_controls.autoswitch.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) );
- //s_controls.sensitivity.curvalue = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) );
- //s_controls.joyenable.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) );
- //s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05, 0.75, Controls_GetCvarValue( "joy_threshold" ) );
- //s_controls.freelook.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) );
+ g_bindings[i].bind1 = twokeys[0];
+ g_bindings[i].bind2 = twokeys[1];
+ }
}
/*
=================
Controls_SetConfig
+
+Iterate each command, get its numeric binding
=================
*/
void Controls_SetConfig(qboolean restart)
{
- int i;
+ unsigned int i;
- // iterate each command, get its numeric binding
- for (i=0; i < g_bindCount; i++)
- {
+ (void)restart;
- if (g_bindings[i].bind1 != -1)
+ for (i = 0; i < g_bindCount; i++)
{
- DC->setBinding( g_bindings[i].bind1, g_bindings[i].command );
-
- if (g_bindings[i].bind2 != -1)
- DC->setBinding( g_bindings[i].bind2, g_bindings[i].command );
+ if (g_bindings[i].bind1 != -1)
+ {
+ DC->setBinding(g_bindings[i].bind1, g_bindings[i].command);
+ if (g_bindings[i].bind2 != -1)
+ DC->setBinding(g_bindings[i].bind2, g_bindings[i].command);
+ }
}
- }
-
- //if ( s_controls.invertmouse.curvalue )
- // DC->setCVar("m_pitch", va("%f),-fabs( DC->getCVarValue( "m_pitch" ) ) );
- //else
- // trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
- //trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
- //trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
- //trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
- //trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
- //trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
- //trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
- //trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
- DC->executeText(EXEC_APPEND, "in_restart\n");
- //trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
+ DC->executeText(EXEC_APPEND, "in_restart\n");
}
/*
=================
Controls_SetDefaults
+
+Iterate each command, set its default binding
=================
*/
-void Controls_SetDefaults( void )
+void Controls_SetDefaults(void)
{
- int i;
-
- // iterate each command, set its default binding
- for (i=0; i < g_bindCount; i++)
- {
- g_bindings[i].bind1 = g_bindings[i].defaultbind1;
- g_bindings[i].bind2 = g_bindings[i].defaultbind2;
- }
-
- //s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0;
- //s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" );
- //s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" );
- //s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" );
- //s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" );
- //s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" );
- //s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
- //s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" );
+ unsigned int i;
+ for (i = 0; i < g_bindCount; i++)
+ {
+ g_bindings[i].bind1 = g_bindings[i].defaultbind1;
+ g_bindings[i].bind2 = g_bindings[i].defaultbind2;
+ }
}
-int BindingIDFromName(const char *name) {
- int i;
- for (i=0; i < g_bindCount; i++)
- {
- if (Q_stricmp(name, g_bindings[i].command) == 0) {
- return i;
+int BindingIDFromName(const char *name)
+{
+ size_t i;
+ for (i = 0; i < g_bindCount; i++)
+ {
+ if (Q_stricmp(name, g_bindings[i].command) == 0)
+ return i;
}
- }
- return -1;
+
+ return -1;
}
char g_nameBind1[32];
char g_nameBind2[32];
-void BindingFromName(const char *cvar) {
- int i, b1, b2;
-
- // iterate each command, set its default binding
- for (i=0; i < g_bindCount; i++)
- {
- if (Q_stricmp(cvar, g_bindings[i].command) == 0) {
- b1 = g_bindings[i].bind1;
- if (b1 == -1) {
- break;
- }
- DC->keynumToStringBuf( b1, g_nameBind1, 32 );
- Q_strupr(g_nameBind1);
-
- b2 = g_bindings[i].bind2;
- if (b2 != -1)
- {
- DC->keynumToStringBuf( b2, g_nameBind2, 32 );
- Q_strupr(g_nameBind2);
- strcat( g_nameBind1, " or " );
- strcat( g_nameBind1, g_nameBind2 );
- }
- return;
- }
- }
- strcpy(g_nameBind1, "???");
-}
-
-void Item_Slider_Paint(itemDef_t *item) {
- vec4_t newColor;
- float x, y, value;
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
-/* lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
- //TA:
- memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- y = item->window.rect.y;
- if (item->text) {
- Item_Text_Paint(item);
- x = item->textRect.x + item->textRect.w + 8;
- } else {
- x = item->window.rect.x;
- }
- DC->setColor(newColor);
- DC->drawHandlePic( x, y, SLIDER_WIDTH, SLIDER_HEIGHT, DC->Assets.sliderBar );
-
- x = Item_Slider_ThumbPosition(item);
- DC->drawHandlePic( x - (SLIDER_THUMB_WIDTH / 2), y - 2, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb );
-
-}
-
-void Item_Bind_Paint(itemDef_t *item) {
- vec4_t newColor, lowLight;
- float value;
- int maxChars = 0;
- menuDef_t *parent = (menuDef_t*)item->parent;
- editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
- if (editPtr) {
- maxChars = editPtr->maxPaintChars;
- }
-
- value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- if (g_bindItem == item) {
- lowLight[0] = 0.8f * 1.0f;
- lowLight[1] = 0.8f * 0.0f;
- lowLight[2] = 0.8f * 0.0f;
- lowLight[3] = 0.8f * 1.0f;
- } else {
- lowLight[0] = 0.8f * parent->focusColor[0];
- lowLight[1] = 0.8f * parent->focusColor[1];
- lowLight[2] = 0.8f * parent->focusColor[2];
- lowLight[3] = 0.8f * parent->focusColor[3];
- }
- /*LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
- //TA:
- memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- if (item->text) {
- Item_Text_Paint(item);
- BindingFromName(item->cvar);
- DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, g_nameBind1, 0, maxChars, item->textStyle);
- } else {
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "FIXME" : "FIXME", 0, maxChars, item->textStyle);
- }
-}
+void BindingFromName(const char *cvar)
+{
+ int i, b1, b2;
+
+ // iterate each command, set its default binding
+
+ for (i = 0; i < g_bindCount; i++)
+ {
+ if (Q_stricmp(cvar, g_bindings[i].command) == 0)
+ {
+ b1 = g_bindings[i].bind1;
-qboolean Display_KeyBindPending( void ) {
- return g_waitingForKey;
+ if (b1 == -1)
+ break;
+
+ DC->keynumToStringBuf(b1, g_nameBind1, 32);
+ Q_strupr(g_nameBind1);
+
+ b2 = g_bindings[i].bind2;
+
+ if (b2 != -1)
+ {
+ DC->keynumToStringBuf(b2, g_nameBind2, 32);
+ Q_strupr(g_nameBind2);
+ strcat(g_nameBind1, " or ");
+ strcat(g_nameBind1, g_nameBind2);
+ }
+
+ return;
+ }
+ }
+
+ strcpy(g_nameBind1, "???");
}
-qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) {
- int id;
- int i;
+void Item_Slider_Paint(itemDef_t *item)
+{
+ vec4_t newColor;
+ float x, y;
+
+ menuDef_t *parent = (menuDef_t *)item->parent;
+ float vScale = Item_Slider_VScale(item);
+
+ if (item->window.flags & WINDOW_HASFOCUS)
+ memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
+ else
+ memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey)
- {
- if (down && (key == K_MOUSE1 || key == K_ENTER)) {
- g_waitingForKey = qtrue;
- g_bindItem = item;
+ if (item->text)
+ {
+ Item_Text_Paint(item);
+ x = item->textRect.x + item->textRect.w + ITEM_VALUE_OFFSET;
+ y = item->textRect.y - item->textRect.h + ((item->textRect.h - (SLIDER_HEIGHT * vScale)) / 2.0f);
}
- return qtrue;
- }
- else
- {
- if (!g_waitingForKey || g_bindItem == NULL) {
- return qtrue;
+ else
+ {
+ x = item->window.rect.x;
+ y = item->window.rect.y;
}
- if (key & K_CHAR_FLAG) {
- return qtrue;
+ DC->setColor(newColor);
+ DC->drawHandlePic(x, y, SLIDER_WIDTH, SLIDER_HEIGHT * vScale, DC->Assets.sliderBar);
+
+ y = item->textRect.y - item->textRect.h + ((item->textRect.h - (SLIDER_THUMB_HEIGHT * vScale)) / 2.0f);
+
+ x = Item_Slider_ThumbPosition(item);
+ DC->drawHandlePic(
+ x - (SLIDER_THUMB_WIDTH / 2), y, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT * vScale, DC->Assets.sliderThumb);
+}
+
+void Item_Bind_Paint(itemDef_t *item)
+{
+ vec4_t newColor, lowLight;
+ float value;
+ int maxChars = 0;
+ menuDef_t *parent = (menuDef_t *)item->parent;
+
+ if (item->typeData.edit)
+ maxChars = item->typeData.edit->maxPaintChars;
+
+ value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
+
+ if (item->window.flags & WINDOW_HASFOCUS)
+ {
+ if (g_bindItem == item)
+ {
+ lowLight[0] = 0.8f * parent->focusColor[0];
+ lowLight[1] = 0.8f * parent->focusColor[1];
+ lowLight[2] = 0.8f * parent->focusColor[2];
+ lowLight[3] = 0.8f * parent->focusColor[3];
+
+ LerpColor(parent->focusColor, lowLight, newColor, 0.5 + 0.5 * sin(DC->realTime / PULSE_DIVISOR));
+ }
+ else
+ memcpy(&newColor, &parent->focusColor, sizeof(vec4_t));
}
+ else
+ memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- switch (key)
+ if (item->text)
{
- case K_ESCAPE:
- g_waitingForKey = qfalse;
- return qtrue;
+ Item_Text_Paint(item);
- case K_BACKSPACE:
- id = BindingIDFromName(item->cvar);
- if (id != -1) {
- g_bindings[id].bind1 = -1;
- g_bindings[id].bind2 = -1;
+ if (g_bindItem == item && g_waitingForKey)
+ {
+ UI_Text_Paint(item->textRect.x + item->textRect.w + ITEM_VALUE_OFFSET, item->textRect.y, item->textscale,
+ newColor, "Press key", 0, maxChars, item->textStyle);
+ }
+ else
+ {
+ BindingFromName(item->cvar);
+ UI_Text_Paint(item->textRect.x + item->textRect.w + ITEM_VALUE_OFFSET, item->textRect.y, item->textscale,
+ newColor, g_nameBind1, 0, maxChars, item->textStyle);
+ }
+ }
+ else
+ UI_Text_Paint(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "FIXME" : "FIXME",
+ 0, maxChars, item->textStyle);
+}
+
+qboolean Display_KeyBindPending(void) { return g_waitingForKey; }
+
+qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down)
+{
+ int id;
+
+ if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey)
+ {
+ if (down && (key == K_MOUSE1 || key == K_ENTER))
+ {
+ g_waitingForKey = qtrue;
+ g_bindItem = item;
}
- Controls_SetConfig(qtrue);
- g_waitingForKey = qfalse;
- g_bindItem = NULL;
- return qtrue;
- case '`':
return qtrue;
}
- }
+ else
+ {
+ if (!g_waitingForKey || g_bindItem == NULL)
+ return qtrue;
- if (key != -1)
- {
+ if (key & K_CHAR_FLAG)
+ return qtrue;
- for (i=0; i < g_bindCount; i++)
- {
+ switch (key)
+ {
+ case K_ESCAPE:
+ g_waitingForKey = qfalse;
+ return qtrue;
+
+ case K_BACKSPACE:
+ id = BindingIDFromName(item->cvar);
+
+ if (id != -1)
+ {
+ g_bindings[id].bind1 = -1;
+ g_bindings[id].bind2 = -1;
+ }
+
+ Controls_SetConfig(qtrue);
+ g_waitingForKey = qfalse;
+ g_bindItem = NULL;
+ return qtrue;
+
+ case '`':
+ return qtrue;
+ }
+ }
- if (g_bindings[i].bind2 == key) {
- g_bindings[i].bind2 = -1;
- }
+ if (key != -1)
+ {
+ unsigned int i;
+ for (i = 0; i < g_bindCount; i++)
+ {
+ if (g_bindings[i].bind2 == key)
+ g_bindings[i].bind2 = -1;
- if (g_bindings[i].bind1 == key)
- {
- g_bindings[i].bind1 = g_bindings[i].bind2;
- g_bindings[i].bind2 = -1;
- }
+ if (g_bindings[i].bind1 == key)
+ {
+ g_bindings[i].bind1 = g_bindings[i].bind2;
+ g_bindings[i].bind2 = -1;
+ }
+ }
}
- }
+ id = BindingIDFromName(item->cvar);
- id = BindingIDFromName(item->cvar);
+ if (id != -1)
+ {
+ if (key == -1)
+ {
+ if (g_bindings[id].bind1 != -1)
+ {
+ DC->setBinding(g_bindings[id].bind1, "");
+ g_bindings[id].bind1 = -1;
+ }
- if (id != -1) {
- if (key == -1) {
- if( g_bindings[id].bind1 != -1 ) {
- DC->setBinding( g_bindings[id].bind1, "" );
- g_bindings[id].bind1 = -1;
- }
- if( g_bindings[id].bind2 != -1 ) {
- DC->setBinding( g_bindings[id].bind2, "" );
- g_bindings[id].bind2 = -1;
- }
- }
- else if (g_bindings[id].bind1 == -1) {
- g_bindings[id].bind1 = key;
+ if (g_bindings[id].bind2 != -1)
+ {
+ DC->setBinding(g_bindings[id].bind2, "");
+ g_bindings[id].bind2 = -1;
+ }
+ }
+ else if (g_bindings[id].bind1 == -1)
+ g_bindings[id].bind1 = key;
+ else if (g_bindings[id].bind1 != key && g_bindings[id].bind2 == -1)
+ g_bindings[id].bind2 = key;
+ else
+ {
+ DC->setBinding(g_bindings[id].bind1, "");
+ DC->setBinding(g_bindings[id].bind2, "");
+ g_bindings[id].bind1 = key;
+ g_bindings[id].bind2 = -1;
+ }
}
- else if (g_bindings[id].bind1 != key && g_bindings[id].bind2 == -1) {
- g_bindings[id].bind2 = key;
+
+ Controls_SetConfig(qtrue);
+ g_waitingForKey = qfalse;
+
+ return qtrue;
+}
+
+void Item_Model_Paint(itemDef_t *item)
+{
+ float x, y, w, h;
+ refdef_t refdef;
+ refEntity_t ent;
+ vec3_t mins, maxs, origin;
+ vec3_t angles;
+
+ modelDef_t *modelPtr = item->typeData.model;
+ if (modelPtr == NULL)
+ return;
+
+ // setup the refdef
+ memset(&refdef, 0, sizeof(refdef));
+
+ refdef.rdflags = RDF_NOWORLDMODEL;
+
+ AxisClear(refdef.viewaxis);
+
+ x = item->window.rect.x + 1;
+ y = item->window.rect.y + 1;
+ w = item->window.rect.w - 2;
+ h = item->window.rect.h - 2;
+
+ UI_AdjustFrom640(&x, &y, &w, &h);
+
+ refdef.x = x;
+ refdef.y = y;
+ refdef.width = w;
+ refdef.height = h;
+
+ DC->modelBounds(item->asset, mins, maxs);
+
+ origin[2] = -0.5 * (mins[2] + maxs[2]);
+ origin[1] = 0.5 * (mins[1] + maxs[1]);
+
+ // calculate distance so the model nearly fills the box
+ if (qtrue)
+ {
+ float len = 0.5 * (maxs[2] - mins[2]);
+ origin[0] = len / 0.268; // len / tan( fov/2 )
+ // origin[0] = len / tan(w/2);
}
- else {
- DC->setBinding( g_bindings[id].bind1, "" );
- DC->setBinding( g_bindings[id].bind2, "" );
- g_bindings[id].bind1 = key;
- g_bindings[id].bind2 = -1;
+ else
+ origin[0] = item->textscale;
+
+ refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : w;
+ refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : h;
+
+ // refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
+ // xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
+ // refdef.fov_y = atan2( refdef.height, xx );
+ // refdef.fov_y *= ( 360 / M_PI );
+
+ DC->clearScene();
+
+ refdef.time = DC->realTime;
+
+ // add the model
+
+ memset(&ent, 0, sizeof(ent));
+
+ // adjust = 5.0 * sin( (float)uis.realtime / 500 );
+ // adjust = 360 % (int)((float)uis.realtime / 1000);
+ // VectorSet( angles, 0, 0, 1 );
+
+ // use item storage to track
+
+ if (modelPtr->rotationSpeed)
+ {
+ if (DC->realTime > item->window.nextTime)
+ {
+ item->window.nextTime = DC->realTime + modelPtr->rotationSpeed;
+ modelPtr->angle = (int)(modelPtr->angle + 1) % 360;
+ }
}
- }
- Controls_SetConfig(qtrue);
- g_waitingForKey = qfalse;
+ VectorSet(angles, 0, modelPtr->angle, 0);
+ AnglesToAxis(angles, ent.axis);
+
+ ent.hModel = item->asset;
+ VectorCopy(origin, ent.origin);
+ VectorCopy(origin, ent.lightingOrigin);
+ ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
+ VectorCopy(ent.origin, ent.oldorigin);
- return qtrue;
+ DC->addRefEntityToScene(&ent);
+ DC->renderScene(&refdef);
}
+void Item_ListBoxRow_Paint(itemDef_t *item, int row, int renderPos, qboolean highlight, qboolean scrollbar)
+{
+ float x, y, w;
+ listBoxDef_t *listPtr = item->typeData.list;
+ menuDef_t *menu = (menuDef_t *)item->parent;
+ float one, two;
+ one = 1.0f * DC->aspectScale;
+ two = 2.0f * DC->aspectScale;
-void AdjustFrom640(float *x, float *y, float *w, float *h) {
- //*x = *x * DC->scale + DC->bias;
- *x *= DC->xscale;
- *y *= DC->yscale;
- *w *= DC->xscale;
- *h *= DC->yscale;
-}
+ x = SCROLLBAR_X(item);
+ y = SCROLLBAR_Y(item) + (listPtr->elementHeight * renderPos);
+ w = item->window.rect.w - (two * item->window.borderSize);
-void Item_Model_Paint(itemDef_t *item) {
- float x, y, w, h;
- refdef_t refdef;
- refEntity_t ent;
- vec3_t mins, maxs, origin;
- vec3_t angles;
- modelDef_t *modelPtr = (modelDef_t*)item->typeData;
+ if (scrollbar)
+ w -= SCROLLBAR_ARROW_WIDTH;
- if (modelPtr == NULL) {
- return;
- }
+ if (listPtr->elementStyle == LISTBOX_IMAGE)
+ {
+ qhandle_t image = DC->feederItemImage(item->feederID, row);
- // setup the refdef
- memset( &refdef, 0, sizeof( refdef ) );
- refdef.rdflags = RDF_NOWORLDMODEL;
- AxisClear( refdef.viewaxis );
- x = item->window.rect.x+1;
- y = item->window.rect.y+1;
- w = item->window.rect.w-2;
- h = item->window.rect.h-2;
+ UI_SetClipRegion(x, y, listPtr->elementWidth, listPtr->elementHeight);
- AdjustFrom640( &x, &y, &w, &h );
+ if (image)
+ DC->drawHandlePic(x + one, y + 1.0f, listPtr->elementWidth - two, listPtr->elementHeight - 2.0f, image);
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
+ if (highlight && row == item->cursorPos)
+ {
+ DC->drawRect(
+ x, y, listPtr->elementWidth, listPtr->elementHeight, item->window.borderSize, item->window.borderColor);
+ }
- DC->modelBounds( item->asset, mins, maxs );
+ UI_ClearClipRegion();
+ }
+ else
+ {
+ const float m = UI_Text_EmHeight(item->textscale);
+ char text[MAX_STRING_CHARS];
+ qhandle_t optionalImage;
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
+ if (listPtr->numColumns > 0)
+ {
+ int j;
+
+ for (j = 0; j < listPtr->numColumns; j++)
+ {
+ float columnPos;
+ float width, height, yOffset;
+
+ if (menu->window.aspectBias != ASPECT_NONE || item->window.aspectBias != ASPECT_NONE)
+ {
+ columnPos = (listPtr->columnInfo[j].pos + 4.0f) * DC->aspectScale;
+ width = listPtr->columnInfo[j].width * DC->aspectScale;
+ }
+ else
+ {
+ columnPos = (listPtr->columnInfo[j].pos + 4.0f);
+ width = listPtr->columnInfo[j].width;
+ }
+
+ height = listPtr->columnInfo[j].width;
+ yOffset = y + ((listPtr->elementHeight - height) / 2.0f);
+
+ Q_strncpyz(text, DC->feederItemText(item->feederID, row, j, &optionalImage), sizeof(text));
+
+ UI_SetClipRegion(x + columnPos, yOffset, width, height);
+
+ if (optionalImage >= 0)
+ DC->drawHandlePic(x + columnPos, yOffset, width, height, optionalImage);
+ else if (text[0])
+ {
+ float alignOffset = 0.0f, tw;
+
+ tw = UI_Text_Width(text, item->textscale);
+
+ switch (listPtr->columnInfo[j].align)
+ {
+ case ALIGN_LEFT:
+ alignOffset = 0.0f;
+ break;
+
+ case ALIGN_RIGHT:
+ alignOffset = width - tw;
+ break;
+
+ case ALIGN_CENTER:
+ alignOffset = (width / 2.0f) - (tw / 2.0f);
+ break;
+
+ default:
+ alignOffset = 0.0f;
+ }
+
+ UI_Text_Paint(x + columnPos + alignOffset, y + m + ((listPtr->elementHeight - m) / 2.0f),
+ item->textscale, item->window.foreColor, text, 0, 0, item->textStyle);
+ }
+
+ UI_ClearClipRegion();
+ }
+ }
+ else
+ {
+ float offset;
- // calculate distance so the model nearly fills the box
- if (qtrue) {
- float len = 0.5 * ( maxs[2] - mins[2] );
- origin[0] = len / 0.268; // len / tan( fov/2 )
- //origin[0] = len / tan(w/2);
- } else {
- origin[0] = item->textscale;
- }
- refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : w;
- refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : h;
+ if (menu->window.aspectBias != ASPECT_NONE || item->window.aspectBias != ASPECT_NONE)
+ offset = 4.0f * DC->aspectScale;
+ else
+ offset = 4.0f;
- //refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
- //xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
- //refdef.fov_y = atan2( refdef.height, xx );
- //refdef.fov_y *= ( 360 / M_PI );
+ Q_strncpyz(text, DC->feederItemText(item->feederID, row, 0, &optionalImage), sizeof(text));
- DC->clearScene();
+ UI_SetClipRegion(x, y, w, listPtr->elementHeight);
- refdef.time = DC->realTime;
+ if (optionalImage >= 0)
+ DC->drawHandlePic(x + offset, y, listPtr->elementHeight, listPtr->elementHeight, optionalImage);
+ else if (text[0])
+ {
+ UI_Text_Paint(x + offset, y + m + ((listPtr->elementHeight - m) / 2.0f), item->textscale,
+ item->window.foreColor, text, 0, 0, item->textStyle);
+ }
+
+ UI_ClearClipRegion();
+ }
- // add the model
+ if (highlight && row == item->cursorPos)
+ DC->fillRect(x, y, w, listPtr->elementHeight, item->window.outlineColor);
+ }
+}
- memset( &ent, 0, sizeof(ent) );
+void Item_ListBox_Paint(itemDef_t *item)
+{
+ float size;
+ int i;
+ listBoxDef_t *listPtr = item->typeData.list;
+ int count = DC->feederCount(item->feederID);
+ qboolean scrollbar = !(listPtr->noscrollbar && count > Item_ListBox_NumItemsForItemHeight(item));
+ if (scrollbar)
+ {
+ float x = SCROLLBAR_SLIDER_X(item);
+ float y = SCROLLBAR_Y(item);
+ float thumbY = Item_ListBox_ThumbDrawPosition(item);
- //adjust = 5.0 * sin( (float)uis.realtime / 500 );
- //adjust = 360 % (int)((float)uis.realtime / 1000);
- //VectorSet( angles, 0, 0, 1 );
+ // Up arrow
+ DC->drawHandlePic(x, y, SCROLLBAR_ARROW_WIDTH, SCROLLBAR_ARROW_HEIGHT, DC->Assets.scrollBarArrowUp);
+ y = SCROLLBAR_SLIDER_Y(item);
- // use item storage to track
- if (modelPtr->rotationSpeed) {
- if (DC->realTime > item->window.nextTime) {
- item->window.nextTime = DC->realTime + modelPtr->rotationSpeed;
- modelPtr->angle = (int)(modelPtr->angle + 1) % 360;
+ // Scroll bar
+ size = SCROLLBAR_SLIDER_HEIGHT(item);
+ DC->drawHandlePic(x, y, SCROLLBAR_ARROW_WIDTH, size, DC->Assets.scrollBar);
+ y = SCROLLBAR_SLIDER_Y(item) + size;
+
+ // Down arrow
+ DC->drawHandlePic(x, y, SCROLLBAR_ARROW_WIDTH, SCROLLBAR_ARROW_HEIGHT, DC->Assets.scrollBarArrowDown);
+
+ // Thumb
+ DC->drawHandlePic(x, thumbY, SCROLLBAR_ARROW_WIDTH, SCROLLBAR_ARROW_HEIGHT, DC->Assets.scrollBarThumb);
}
- }
- VectorSet( angles, 0, modelPtr->angle, 0 );
- AnglesToAxis( angles, ent.axis );
- ent.hModel = item->asset;
- VectorCopy( origin, ent.origin );
- VectorCopy( origin, ent.lightingOrigin );
- ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
- VectorCopy( ent.origin, ent.oldorigin );
+ // Paint rows
+ for (i = listPtr->startPos; i < listPtr->endPos; i++)
+ Item_ListBoxRow_Paint(item, i, i - listPtr->startPos, qtrue, scrollbar);
+}
+
+void Item_Paint(itemDef_t *item);
+
+void Item_ComboBox_Paint(itemDef_t *item)
+{
+ float x, y, h;
- DC->addRefEntityToScene( &ent );
- DC->renderScene( &refdef );
+ x = SCROLLBAR_SLIDER_X(item);
+ y = SCROLLBAR_Y(item);
+ h = item->window.rect.h - 2.0f;
+ // Down arrow
+ DC->drawHandlePic(x, y, SCROLLBAR_ARROW_WIDTH, h, DC->Assets.scrollBarArrowDown);
+ Item_ListBoxRow_Paint(item, item->cursorPos, 0, qfalse, qtrue);
+ if (g_comboBoxItem != NULL)
+ {
+ qboolean cast = Item_ComboBox_MaybeCastToListBox(item);
+ Item_Paint(item);
+ Item_ComboBox_MaybeUnCastFromListBox(item, cast);
+ }
}
+void Item_ListBox_Update(itemDef_t *item)
+{
+ listBoxDef_t *listPtr = item->typeData.list;
+ int feederCount = DC->feederCount(item->feederID);
+
+ if (listPtr->lastFeederCount != feederCount)
+ {
+ if (listPtr->resetonfeederchange)
+ {
+ item->cursorPos = DC->feederInitialise(item->feederID);
+ Item_ListBox_SetStartPos(item, 0);
+ DC->feederSelection(item->feederID, item->cursorPos);
+ }
+ else
+ {
+ // Make sure endPos is up-to-date
+ Item_ListBox_SetStartPos(item, listPtr->startPos);
-void Item_Image_Paint(itemDef_t *item) {
- if (item == NULL) {
- return;
- }
- DC->drawHandlePic(item->window.rect.x+1, item->window.rect.y+1, item->window.rect.w-2, item->window.rect.h-2, item->asset);
+ // If the selection is off the end now, select the last element
+ if (item->cursorPos >= feederCount)
+ item->cursorPos = feederCount - 1;
+ }
+ }
+
+ listPtr->lastFeederCount = feederCount;
}
-void Item_ListBox_Paint(itemDef_t *item) {
- float x, y, size, thumb;
- int i, count;
- qhandle_t image;
- qhandle_t optionalImage;
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
-
- // the listbox is horizontal or vertical and has a fixed size scroll bar going either direction
- // elements are enumerated from the DC and either text or image handles are acquired from the DC as well
- // textscale is used to size the text, textalignx and textaligny are used to size image elements
- // there is no clipping available so only the last completely visible item is painted
- count = DC->feederCount(item->special);
- // default is vertical if horizontal flag is not here
- if (item->window.flags & WINDOW_HORIZONTAL) {
- // draw scrollbar in bottom of the window
- // bar
- x = item->window.rect.x + 1;
- y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE - 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowLeft);
- x += SCROLLBAR_SIZE - 1;
- size = item->window.rect.w - (SCROLLBAR_SIZE * 2);
- DC->drawHandlePic(x, y, size+1, SCROLLBAR_SIZE, DC->Assets.scrollBar);
- x += size - 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowRight);
- // thumb
- thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
- if (thumb > x - SCROLLBAR_SIZE - 1) {
- thumb = x - SCROLLBAR_SIZE - 1;
- }
- DC->drawHandlePic(thumb, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
- //
- listPtr->endPos = listPtr->startPos;
- size = item->window.rect.w - 2;
- // items
- // size contains max available space
- if (listPtr->elementStyle == LISTBOX_IMAGE) {
- // fit = 0;
- x = item->window.rect.x + 1;
- y = item->window.rect.y + 1;
- for (i = listPtr->startPos; i < count; i++) {
- // always draw at least one
- // which may overdraw the box if it is too small for the element
- image = DC->feederItemImage(item->special, i);
- if (image) {
- DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
- }
-
- if (i == item->cursorPos) {
- DC->drawRect(x, y, listPtr->elementWidth-1, listPtr->elementHeight-1, item->window.borderSize, item->window.borderColor);
- }
-
- listPtr->endPos++;
- size -= listPtr->elementWidth;
- if (size < listPtr->elementWidth) {
- listPtr->drawPadding = size; //listPtr->elementWidth - size;
- break;
- }
- x += listPtr->elementWidth;
- // fit++;
- }
- } else {
- //
- }
- } else {
- // draw scrollbar to right side of the window
- x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1;
- y = item->window.rect.y + 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp);
- y += SCROLLBAR_SIZE - 1;
-
- listPtr->endPos = listPtr->startPos;
- size = item->window.rect.h - (SCROLLBAR_SIZE * 2);
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar);
- y += size - 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown);
- // thumb
- thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
- if (thumb > y - SCROLLBAR_SIZE - 1) {
- thumb = y - SCROLLBAR_SIZE - 1;
- }
- DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
-
- // adjust size for item painting
- size = item->window.rect.h - 2;
- if (listPtr->elementStyle == LISTBOX_IMAGE) {
- // fit = 0;
- x = item->window.rect.x + 1;
- y = item->window.rect.y + 1;
- for (i = listPtr->startPos; i < count; i++) {
- // always draw at least one
- // which may overdraw the box if it is too small for the element
- image = DC->feederItemImage(item->special, i);
- if (image) {
- DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
- }
-
- if (i == item->cursorPos) {
- DC->drawRect(x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.borderColor);
- }
-
- listPtr->endPos++;
- size -= listPtr->elementWidth;
- if (size < listPtr->elementHeight) {
- listPtr->drawPadding = listPtr->elementHeight - size;
- break;
- }
- y += listPtr->elementHeight;
- // fit++;
- }
- } else {
- x = item->window.rect.x + 1;
- y = item->window.rect.y + 1;
- for (i = listPtr->startPos; i < count; i++) {
- const char *text;
- // always draw at least one
- // which may overdraw the box if it is too small for the element
-
- if (listPtr->numColumns > 0) {
- int j;
- for (j = 0; j < listPtr->numColumns; j++) {
- text = DC->feederItemText(item->special, i, j, &optionalImage);
- if (optionalImage >= 0) {
- DC->drawHandlePic(x + 4 + listPtr->columnInfo[j].pos, y - 1 + listPtr->elementHeight / 2, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
- } else if (text) {
- //TA:
- int alignOffset = 0.0f, tw;
-
- tw = DC->textWidth( text, item->textscale, 0 );
-
- switch( listPtr->columnInfo[ j ].align )
- {
- case ITEM_ALIGN_LEFT:
- alignOffset = 0.0f;
- break;
-
- case ITEM_ALIGN_RIGHT:
- alignOffset = listPtr->columnInfo[ j ].width - tw;
- break;
-
- case ITEM_ALIGN_CENTER:
- alignOffset = ( listPtr->columnInfo[ j ].width / 2.0f ) - ( tw / 2.0f );
- break;
+void Item_OwnerDraw_Paint(itemDef_t *item)
+{
+ menuDef_t *parent;
+ const char *text;
- default:
- alignOffset = 0.0f;
- }
+ if (item == NULL)
+ return;
+
+ parent = (menuDef_t *)item->parent;
+
+ if (DC->ownerDrawItem)
+ {
+ vec4_t color, lowLight;
+ Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime,
+ parent->fadeCycle, qtrue, parent->fadeAmount);
+ memcpy(&color, &item->window.foreColor, sizeof(color));
- DC->drawText( x + 4 + listPtr->columnInfo[j].pos + alignOffset, y + listPtr->elementHeight,
- item->textscale, item->window.foreColor, text, 0,
- listPtr->columnInfo[j].maxChars, item->textStyle );
+ if (item->numColors > 0 && DC->getValue)
+ {
+ // if the value is within one of the ranges then set color to that, otherwise leave at default
+ int i;
+ float f = DC->getValue(item->window.ownerDraw);
+
+ for (i = 0; i < item->numColors; i++)
+ {
+ if (f >= item->colorRanges[i].low && f <= item->colorRanges[i].high)
+ {
+ memcpy(&color, &item->colorRanges[i].color, sizeof(color));
+ break;
+ }
}
- }
- } else {
- text = DC->feederItemText(item->special, i, 0, &optionalImage);
- if (optionalImage >= 0) {
- //DC->drawHandlePic(x + 4 + listPtr->elementHeight, y, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
- } else if (text) {
- DC->drawText(x + 4, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, 0, item->textStyle);
- }
}
- if (i == item->cursorPos) {
- DC->fillRect(x + 2, y + 2, item->window.rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight, item->window.outlineColor);
- }
-
- listPtr->endPos++;
- size -= listPtr->elementHeight;
- if (size < listPtr->elementHeight) {
- listPtr->drawPadding = listPtr->elementHeight - size;
- break;
- }
- y += listPtr->elementHeight;
- // fit++;
- }
+ if (item->window.flags & WINDOW_HASFOCUS)
+ memcpy(color, &parent->focusColor, sizeof(vec4_t));
+ else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime / BLINK_DIVISOR) & 1))
+ {
+ lowLight[0] = 0.8 * item->window.foreColor[0];
+ lowLight[1] = 0.8 * item->window.foreColor[1];
+ lowLight[2] = 0.8 * item->window.foreColor[2];
+ lowLight[3] = 0.8 * item->window.foreColor[3];
+ LerpColor(item->window.foreColor, lowLight, color, 0.5 + 0.5 * sin(DC->realTime / PULSE_DIVISOR));
+ }
+
+ if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE))
+ Com_Memcpy(color, parent->disableColor, sizeof(vec4_t));
+
+ if (DC->ownerDrawText && (text = DC->ownerDrawText(item->window.ownerDraw)))
+ {
+ if (item->text && *item->text)
+ {
+ Item_Text_Paint(item);
+
+ UI_Text_Paint(item->textRect.x + item->textRect.w + ITEM_VALUE_OFFSET, item->textRect.y,
+ item->textscale, color, text, 0, 0, item->textStyle);
+ }
+ else
+ {
+ item->text = text;
+ Item_Text_Paint(item);
+ item->text = NULL;
+ }
+ }
+ else
+ {
+ DC->ownerDrawItem(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h,
+ item->textalignx, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags,
+ item->alignment, item->textalignment, item->textvalignment, item->window.borderSize, item->textscale,
+ color, item->window.backColor, item->window.background, item->textStyle);
+ }
}
- }
+}
- //TA: FIXME: hacky fix to off-by-one bug
- listPtr->endPos--;
-}
-
-
-void Item_OwnerDraw_Paint(itemDef_t *item) {
- menuDef_t *parent;
-
- if (item == NULL) {
- return;
- }
- parent = (menuDef_t*)item->parent;
-
- if (DC->ownerDrawItem) {
- vec4_t color, lowLight;
- menuDef_t *parent = (menuDef_t*)item->parent;
- Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
- memcpy(&color, &item->window.foreColor, sizeof(color));
- if (item->numColors > 0 && DC->getValue) {
- // if the value is within one of the ranges then set color to that, otherwise leave at default
- int i;
- float f = DC->getValue(item->window.ownerDraw);
- for (i = 0; i < item->numColors; i++) {
- if (f >= item->colorRanges[i].low && f <= item->colorRanges[i].high) {
- memcpy(&color, &item->colorRanges[i].color, sizeof(color));
- break;
- }
- }
- }
-
- if (item->window.flags & WINDOW_HASFOCUS) {
-/* lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
- //TA:
- memcpy(color, &parent->focusColor, sizeof(vec4_t));
- } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
- lowLight[0] = 0.8 * item->window.foreColor[0];
- lowLight[1] = 0.8 * item->window.foreColor[1];
- lowLight[2] = 0.8 * item->window.foreColor[2];
- lowLight[3] = 0.8 * item->window.foreColor[3];
- LerpColor(item->window.foreColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- }
-
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- memcpy(color, parent->disableColor, sizeof(vec4_t)); // bk001207 - FIXME: Com_Memcpy
- }
-
- if (item->text) {
- Item_Text_Paint(item);
- if (item->text[0]) {
- // +8 is an offset kludge to properly align owner draw items that have text combined with them
- DC->ownerDrawItem(item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
- } else {
- DC->ownerDrawItem(item->textRect.x + item->textRect.w, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
- }
- } else {
- DC->ownerDrawItem(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, item->textalignx, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
- }
- }
-}
-
-
-void Item_Paint(itemDef_t *item) {
- vec4_t red;
- menuDef_t *parent = (menuDef_t*)item->parent;
- red[0] = red[3] = 1;
- red[1] = red[2] = 0;
-
- if (item == NULL) {
- return;
- }
-
- if (item->window.flags & WINDOW_ORBITING) {
- if (DC->realTime > item->window.nextTime) {
- float rx, ry, a, c, s, w, h;
-
- item->window.nextTime = DC->realTime + item->window.offsetTime;
- // translate
- w = item->window.rectClient.w / 2;
- h = item->window.rectClient.h / 2;
- rx = item->window.rectClient.x + w - item->window.rectEffects.x;
- ry = item->window.rectClient.y + h - item->window.rectEffects.y;
- a = 3 * M_PI / 180;
- c = cos(a);
- s = sin(a);
- item->window.rectClient.x = (rx * c - ry * s) + item->window.rectEffects.x - w;
- item->window.rectClient.y = (rx * s + ry * c) + item->window.rectEffects.y - h;
- Item_UpdatePosition(item);
-
- }
- }
-
-
- if (item->window.flags & WINDOW_INTRANSITION) {
- if (DC->realTime > item->window.nextTime) {
- int done = 0;
- item->window.nextTime = DC->realTime + item->window.offsetTime;
- // transition the x,y
- if (item->window.rectClient.x == item->window.rectEffects.x) {
- done++;
- } else {
- if (item->window.rectClient.x < item->window.rectEffects.x) {
- item->window.rectClient.x += item->window.rectEffects2.x;
- if (item->window.rectClient.x > item->window.rectEffects.x) {
- item->window.rectClient.x = item->window.rectEffects.x;
- done++;
- }
- } else {
- item->window.rectClient.x -= item->window.rectEffects2.x;
- if (item->window.rectClient.x < item->window.rectEffects.x) {
- item->window.rectClient.x = item->window.rectEffects.x;
- done++;
- }
- }
- }
- if (item->window.rectClient.y == item->window.rectEffects.y) {
- done++;
- } else {
- if (item->window.rectClient.y < item->window.rectEffects.y) {
- item->window.rectClient.y += item->window.rectEffects2.y;
- if (item->window.rectClient.y > item->window.rectEffects.y) {
- item->window.rectClient.y = item->window.rectEffects.y;
- done++;
- }
- } else {
- item->window.rectClient.y -= item->window.rectEffects2.y;
- if (item->window.rectClient.y < item->window.rectEffects.y) {
- item->window.rectClient.y = item->window.rectEffects.y;
- done++;
- }
- }
- }
- if (item->window.rectClient.w == item->window.rectEffects.w) {
- done++;
- } else {
- if (item->window.rectClient.w < item->window.rectEffects.w) {
- item->window.rectClient.w += item->window.rectEffects2.w;
- if (item->window.rectClient.w > item->window.rectEffects.w) {
- item->window.rectClient.w = item->window.rectEffects.w;
- done++;
- }
- } else {
- item->window.rectClient.w -= item->window.rectEffects2.w;
- if (item->window.rectClient.w < item->window.rectEffects.w) {
- item->window.rectClient.w = item->window.rectEffects.w;
- done++;
- }
- }
- }
- if (item->window.rectClient.h == item->window.rectEffects.h) {
- done++;
- } else {
- if (item->window.rectClient.h < item->window.rectEffects.h) {
- item->window.rectClient.h += item->window.rectEffects2.h;
- if (item->window.rectClient.h > item->window.rectEffects.h) {
- item->window.rectClient.h = item->window.rectEffects.h;
- done++;
- }
- } else {
- item->window.rectClient.h -= item->window.rectEffects2.h;
- if (item->window.rectClient.h < item->window.rectEffects.h) {
- item->window.rectClient.h = item->window.rectEffects.h;
- done++;
- }
- }
- }
-
- Item_UpdatePosition(item);
-
- if (done == 4) {
- item->window.flags &= ~WINDOW_INTRANSITION;
- }
-
- }
- }
-
- if (item->window.ownerDrawFlags && DC->ownerDrawVisible) {
- if (!DC->ownerDrawVisible(item->window.ownerDrawFlags)) {
- item->window.flags &= ~WINDOW_VISIBLE;
- } else {
- item->window.flags |= WINDOW_VISIBLE;
- }
- }
-
- if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE)) {
- if (!Item_EnableShowViaCvar(item, CVAR_SHOW)) {
- return;
- }
- }
-
- if (item->window.flags & WINDOW_TIMEDVISIBLE) {
-
- }
-
- if (!(item->window.flags & WINDOW_VISIBLE)) {
- return;
- }
-
- // paint the rect first..
- Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle);
-
- if (debugMode) {
- vec4_t color;
- rectDef_t *r = Item_CorrectedTextRect(item);
- color[1] = color[3] = 1;
- color[0] = color[2] = 0;
- DC->drawRect(r->x, r->y, r->w, r->h, 1, color);
- }
-
- //DC->drawRect(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, red);
-
- switch (item->type) {
- case ITEM_TYPE_OWNERDRAW:
- Item_OwnerDraw_Paint(item);
- break;
- case ITEM_TYPE_TEXT:
- case ITEM_TYPE_BUTTON:
- Item_Text_Paint(item);
- break;
- case ITEM_TYPE_RADIOBUTTON:
- break;
- case ITEM_TYPE_CHECKBOX:
- break;
- case ITEM_TYPE_EDITFIELD:
- case ITEM_TYPE_SAYFIELD:
- case ITEM_TYPE_NUMERICFIELD:
- Item_TextField_Paint(item);
- break;
- case ITEM_TYPE_COMBO:
- break;
- case ITEM_TYPE_LISTBOX:
- Item_ListBox_Paint(item);
- break;
- //case ITEM_TYPE_IMAGE:
- // Item_Image_Paint(item);
- // break;
- case ITEM_TYPE_MODEL:
- Item_Model_Paint(item);
- break;
- case ITEM_TYPE_YESNO:
- Item_YesNo_Paint(item);
- break;
- case ITEM_TYPE_MULTI:
- Item_Multi_Paint(item);
- break;
- case ITEM_TYPE_BIND:
- Item_Bind_Paint(item);
- break;
- case ITEM_TYPE_SLIDER:
- Item_Slider_Paint(item);
- break;
- default:
- break;
- }
-
-}
-
-void Menu_Init(menuDef_t *menu) {
- memset(menu, 0, sizeof(menuDef_t));
- menu->cursorItem = -1;
- menu->fadeAmount = DC->Assets.fadeAmount;
- menu->fadeClamp = DC->Assets.fadeClamp;
- menu->fadeCycle = DC->Assets.fadeCycle;
- Window_Init(&menu->window);
-}
-
-itemDef_t *Menu_GetFocusedItem(menuDef_t *menu) {
- int i;
- if (menu) {
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
- return menu->items[i];
- }
- }
- }
- return NULL;
-}
-
-menuDef_t *Menu_GetFocused( void ) {
- int i;
- for (i = 0; i < menuCount; i++) {
- if (Menus[i].window.flags & WINDOW_HASFOCUS && Menus[i].window.flags & WINDOW_VISIBLE) {
- return &Menus[i];
- }
- }
- return NULL;
-}
-
-void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down) {
- if (menu) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->special == feeder) {
- Item_ListBox_HandleKey(menu->items[i], (down) ? K_DOWNARROW : K_UPARROW, qtrue, qtrue);
+void Item_Update(itemDef_t *item)
+{
+ if (item == NULL)
return;
- }
- }
- }
+
+ if (Item_IsListBox(item))
+ Item_ListBox_Update(item);
}
+void Item_Paint(itemDef_t *item)
+{
+ vec4_t red;
+ menuDef_t *parent = (menuDef_t *)item->parent;
+ red[0] = red[3] = 1;
+ red[1] = red[2] = 0;
+ if (item == NULL)
+ return;
-void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name) {
- if (menu == NULL) {
- if (name == NULL) {
- menu = Menu_GetFocused();
- } else {
- menu = Menus_FindByName(name);
+ if (item->window.flags & WINDOW_ORBITING)
+ {
+ if (DC->realTime > item->window.nextTime)
+ {
+ float rx, ry, a, c, s, w, h;
+
+ item->window.nextTime = DC->realTime + item->window.offsetTime;
+ // translate
+ w = item->window.rectClient.w / 2;
+ h = item->window.rectClient.h / 2;
+ rx = item->window.rectClient.x + w - item->window.rectEffects.x;
+ ry = item->window.rectClient.y + h - item->window.rectEffects.y;
+ a = 3 * M_PI / 180;
+ c = cos(a);
+ s = sin(a);
+ item->window.rectClient.x = (rx * c - ry * s) + item->window.rectEffects.x - w;
+ item->window.rectClient.y = (rx * s + ry * c) + item->window.rectEffects.y - h;
+ Item_UpdatePosition(item);
+ }
}
- }
- if (menu) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->special == feeder) {
- if (index == 0) {
- listBoxDef_t *listPtr = (listBoxDef_t*)menu->items[i]->typeData;
- listPtr->cursorPos = 0;
- listPtr->startPos = 0;
- }
- menu->items[i]->cursorPos = index;
- DC->feederSelection(menu->items[i]->special, menu->items[i]->cursorPos);
+ if (item->window.flags & WINDOW_INTRANSITION)
+ {
+ if (DC->realTime > item->window.nextTime)
+ {
+ int done = 0;
+ item->window.nextTime = DC->realTime + item->window.offsetTime;
+ // transition the x,y
+
+ if (item->window.rectClient.x == item->window.rectEffects.x)
+ done++;
+ else
+ {
+ if (item->window.rectClient.x < item->window.rectEffects.x)
+ {
+ item->window.rectClient.x += item->window.rectEffects2.x;
+
+ if (item->window.rectClient.x > item->window.rectEffects.x)
+ {
+ item->window.rectClient.x = item->window.rectEffects.x;
+ done++;
+ }
+ }
+ else
+ {
+ item->window.rectClient.x -= item->window.rectEffects2.x;
+
+ if (item->window.rectClient.x < item->window.rectEffects.x)
+ {
+ item->window.rectClient.x = item->window.rectEffects.x;
+ done++;
+ }
+ }
+ }
+
+ if (item->window.rectClient.y == item->window.rectEffects.y)
+ done++;
+ else
+ {
+ if (item->window.rectClient.y < item->window.rectEffects.y)
+ {
+ item->window.rectClient.y += item->window.rectEffects2.y;
+
+ if (item->window.rectClient.y > item->window.rectEffects.y)
+ {
+ item->window.rectClient.y = item->window.rectEffects.y;
+ done++;
+ }
+ }
+ else
+ {
+ item->window.rectClient.y -= item->window.rectEffects2.y;
+
+ if (item->window.rectClient.y < item->window.rectEffects.y)
+ {
+ item->window.rectClient.y = item->window.rectEffects.y;
+ done++;
+ }
+ }
+ }
+
+ if (item->window.rectClient.w == item->window.rectEffects.w)
+ done++;
+ else
+ {
+ if (item->window.rectClient.w < item->window.rectEffects.w)
+ {
+ item->window.rectClient.w += item->window.rectEffects2.w;
+
+ if (item->window.rectClient.w > item->window.rectEffects.w)
+ {
+ item->window.rectClient.w = item->window.rectEffects.w;
+ done++;
+ }
+ }
+ else
+ {
+ item->window.rectClient.w -= item->window.rectEffects2.w;
+
+ if (item->window.rectClient.w < item->window.rectEffects.w)
+ {
+ item->window.rectClient.w = item->window.rectEffects.w;
+ done++;
+ }
+ }
+ }
+
+ if (item->window.rectClient.h == item->window.rectEffects.h)
+ done++;
+ else
+ {
+ if (item->window.rectClient.h < item->window.rectEffects.h)
+ {
+ item->window.rectClient.h += item->window.rectEffects2.h;
+
+ if (item->window.rectClient.h > item->window.rectEffects.h)
+ {
+ item->window.rectClient.h = item->window.rectEffects.h;
+ done++;
+ }
+ }
+ else
+ {
+ item->window.rectClient.h -= item->window.rectEffects2.h;
+
+ if (item->window.rectClient.h < item->window.rectEffects.h)
+ {
+ item->window.rectClient.h = item->window.rectEffects.h;
+ done++;
+ }
+ }
+ }
+
+ Item_UpdatePosition(item);
+
+ if (done == 4)
+ item->window.flags &= ~WINDOW_INTRANSITION;
+ }
+ }
+
+ if (item->window.ownerDrawFlags && DC->ownerDrawVisible)
+ {
+ if (!DC->ownerDrawVisible(item->window.ownerDrawFlags))
+ item->window.flags &= ~WINDOW_VISIBLE;
+ else
+ item->window.flags |= WINDOW_VISIBLE;
+ }
+
+ if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE))
+ {
+ if (!Item_EnableShowViaCvar(item, CVAR_SHOW))
+ return;
+ }
+
+ if (item->window.flags & WINDOW_TIMEDVISIBLE)
+ {
+ }
+
+ if (!(item->window.flags & WINDOW_VISIBLE))
return;
- }
+
+ Window_Paint(&item->window, parent->fadeAmount, parent->fadeClamp, parent->fadeCycle);
+
+ if (DC->getCVarValue("ui_developer"))
+ {
+ vec4_t color;
+ rectDef_t *r = Item_CorrectedTextRect(item);
+ color[1] = color[3] = 1;
+ color[0] = color[2] = 0;
+ DC->drawRect(r->x, r->y, r->w, r->h, 1, color);
}
- }
+
+ switch (item->type)
+ {
+ case ITEM_TYPE_OWNERDRAW:
+ Item_OwnerDraw_Paint(item);
+ break;
+
+ case ITEM_TYPE_TEXT:
+ case ITEM_TYPE_BUTTON:
+ Item_Text_Paint(item);
+ break;
+
+ case ITEM_TYPE_RADIOBUTTON:
+ break;
+
+ case ITEM_TYPE_CHECKBOX:
+ break;
+
+ case ITEM_TYPE_CYCLE:
+ Item_Cycle_Paint(item);
+ break;
+
+ case ITEM_TYPE_LISTBOX:
+ Item_ListBox_Paint(item);
+ break;
+
+ case ITEM_TYPE_COMBOBOX:
+ Item_ComboBox_Paint(item);
+ break;
+
+ case ITEM_TYPE_MODEL:
+ Item_Model_Paint(item);
+ break;
+
+ case ITEM_TYPE_YESNO:
+ Item_YesNo_Paint(item);
+ break;
+
+ case ITEM_TYPE_MULTI:
+ Item_Multi_Paint(item);
+ break;
+
+ case ITEM_TYPE_BIND:
+ Item_Bind_Paint(item);
+ break;
+
+ case ITEM_TYPE_SLIDER:
+ Item_Slider_Paint(item);
+ break;
+
+ default:
+ if (Item_IsEditField(item))
+ Item_TextField_Paint(item);
+
+ break;
+ }
+
+ Border_Paint(&item->window);
+}
+
+void Menu_Init(menuDef_t *menu)
+{
+ memset(menu, 0, sizeof(menuDef_t));
+ menu->cursorItem = -1;
+ menu->fadeAmount = DC->Assets.fadeAmount;
+ menu->fadeClamp = DC->Assets.fadeClamp;
+ menu->fadeCycle = DC->Assets.fadeCycle;
+ Window_Init(&menu->window);
+ menu->window.aspectBias = ALIGN_CENTER;
}
-qboolean Menus_AnyFullScreenVisible( void ) {
- int i;
- for (i = 0; i < menuCount; i++) {
- if (Menus[i].window.flags & WINDOW_VISIBLE && Menus[i].fullScreen) {
- return qtrue;
+itemDef_t *Menu_GetFocusedItem(menuDef_t *menu)
+{
+ int i;
+
+ if (menu)
+ {
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ if (menu->items[i]->window.flags & WINDOW_HASFOCUS)
+ return menu->items[i];
+ }
}
- }
- return qfalse;
+
+ return NULL;
}
-menuDef_t *Menus_ActivateByName(const char *p) {
- int i, j;
- menuDef_t *m = NULL;
- menuDef_t *focus = Menu_GetFocused();
+menuDef_t *Menu_GetFocused(void)
+{
+ int i;
- for (i = 0; i < menuCount; i++) {
- if (Q_stricmp(Menus[i].window.name, p) == 0) {
- m = &Menus[i];
- Menus_Activate(m);
- Menu_HandleMouseMove( m, DC->cursorx, DC->cursory ); //TA: force the item under the cursor to focus
+ for (i = 0; i < menuCount; i++)
+ {
+ if (Menus[i].window.flags & WINDOW_HASFOCUS && Menus[i].window.flags & WINDOW_VISIBLE)
+ return &Menus[i];
+ }
- for( j = 0; j < m->itemCount; j++ ) //TA: reset selection in listboxes when opened
- {
- if( m->items[ j ]->type == ITEM_TYPE_LISTBOX )
+ return NULL;
+}
+
+void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down)
+{
+ if (menu)
+ {
+ int i;
+
+ for (i = 0; i < menu->itemCount; i++)
{
- listBoxDef_t *listPtr = (listBoxDef_t*)m->items[ j ]->typeData;
- m->items[ j ]->cursorPos = 0;
- listPtr->startPos = 0;
- DC->feederSelection( m->items[ j ]->special, 0 );
+ itemDef_t *item = menu->items[i];
+
+ if (item->feederID == feeder)
+ {
+ qboolean cast = Item_ComboBox_MaybeCastToListBox(item);
+ Item_ListBox_HandleKey(item, down ? K_DOWNARROW : K_UPARROW, qtrue, qtrue);
+ Item_ComboBox_MaybeUnCastFromListBox(item, cast);
+
+ return;
+ }
}
- }
+ }
+}
- if (openMenuCount < MAX_OPEN_MENUS && focus != NULL) {
- menuStack[openMenuCount++] = focus;
- }
- } else {
- Menus[i].window.flags &= ~WINDOW_HASFOCUS;
+void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name)
+{
+ if (menu == NULL)
+ {
+ if (name == NULL)
+ menu = Menu_GetFocused();
+ else
+ menu = Menus_FindByName(name);
+ }
+
+ if (menu)
+ {
+ int i;
+
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ if (menu->items[i]->feederID == feeder)
+ {
+ if (Item_IsListBox(menu->items[i]) && index == 0)
+ {
+ menu->items[i]->typeData.list->cursorPos = 0;
+ Item_ListBox_SetStartPos(menu->items[i], 0);
+ }
+
+ menu->items[i]->cursorPos = index;
+ DC->feederSelection(menu->items[i]->feederID, menu->items[i]->cursorPos);
+ return;
+ }
+ }
}
- }
- Display_CloseCinematics();
- return m;
}
+qboolean Menus_AnyFullScreenVisible(void)
+{
+ int i;
+
+ for (i = 0; i < menuCount; i++)
+ {
+ if (Menus[i].window.flags & WINDOW_VISIBLE && Menus[i].fullScreen)
+ return qtrue;
+ }
-void Item_Init(itemDef_t *item) {
- memset(item, 0, sizeof(itemDef_t));
- item->textscale = 0.55f;
- Window_Init(&item->window);
+ return qfalse;
}
-void Menu_HandleMouseMove(menuDef_t *menu, float x, float y) {
- int i, pass;
- qboolean focusSet = qfalse;
+menuDef_t *Menus_ActivateByName(const char *p)
+{
+ int i;
+ menuDef_t *m = NULL;
- itemDef_t *overItem;
- if (menu == NULL) {
- return;
- }
+ // Activate one menu
- if (!(menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
- return;
- }
+ for (i = 0; i < menuCount; i++)
+ {
+ if (Q_stricmp(Menus[i].window.name, p) == 0)
+ {
+ m = &Menus[i];
+ Menus_Activate(m);
+ break;
+ }
+ }
- if (itemCapture) {
- //Item_MouseMove(itemCapture, x, y);
- return;
- }
+ // Defocus the others
+ for (i = 0; i < menuCount; i++)
+ {
+ if (Q_stricmp(Menus[i].window.name, p) != 0)
+ Menus[i].window.flags &= ~WINDOW_HASFOCUS;
+ }
- if (g_waitingForKey || g_editingField) {
- return;
- }
+ return m;
+}
- // FIXME: this is the whole issue of focus vs. mouse over..
- // need a better overall solution as i don't like going through everything twice
- for (pass = 0; pass < 2; pass++) {
- for (i = 0; i < menu->itemCount; i++) {
- // turn off focus each item
- // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
+menuDef_t *Menus_ReplaceActiveByName(const char *p)
+{
+ int i;
+ menuDef_t *m = NULL;
- if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
- continue;
- }
+ // Activate one menu
- // items can be enabled and disabled based on cvars
- if (menu->items[i]->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_ENABLE)) {
- continue;
- }
+ for (i = 0; i < menuCount; i++)
+ {
+ if (Q_stricmp(Menus[i].window.name, p) == 0)
+ {
+ m = &Menus[i];
+ if (!Menus_ReplaceActive(m))
+ return NULL;
+ break;
+ }
+ }
+ return m;
+}
- if (menu->items[i]->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_SHOW)) {
- continue;
- }
+void Item_Init(itemDef_t *item)
+{
+ memset(item, 0, sizeof(itemDef_t));
+ item->textscale = 0.55f;
+ Window_Init(&item->window);
+ item->window.aspectBias = ASPECT_NONE;
+}
+static qboolean Item_HandleMouseMove(itemDef_t *item, float x, float y, int pass, qboolean focusSet)
+{
+ if (Rect_ContainsPoint(&item->window.rect, x, y))
+ {
+ if (pass == 1)
+ {
+ if (item->type == ITEM_TYPE_TEXT && item->text)
+ {
+ if (!Rect_ContainsPoint(Item_CorrectedTextRect(item), x, y))
+ return qtrue;
+ }
+ // if we are over an item
+ if (IsVisible(item->window.flags))
+ {
+ // different one
+ Item_MouseEnter(item, x, y);
- if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
- if (pass == 1) {
- overItem = menu->items[i];
- if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
- if (!Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
- continue;
+ if (!focusSet)
+ focusSet = Item_SetFocus(item, x, y);
}
- }
- // if we are over an item
- if (IsVisible(overItem->window.flags)) {
- // different one
- Item_MouseEnter(overItem, x, y);
- // Item_SetMouseOver(overItem, qtrue);
-
- // if item is not a decoration see if it can take focus
- if (!focusSet) {
- focusSet = Item_SetFocus(overItem, x, y);
+ }
+
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+void Menu_HandleMouseMove(menuDef_t *menu, float x, float y)
+{
+ int i, pass;
+ qboolean focusSet = qfalse;
+ qboolean result;
+ qboolean cast;
+
+ if (menu == NULL)
+ return;
+
+ if (!(menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)))
+ return;
+
+ if (itemCapture)
+ {
+ // Item_MouseMove(itemCapture, x, y);
+ return;
+ }
+
+ if (g_waitingForKey || g_editingField)
+ return;
+
+ if (g_comboBoxItem != NULL)
+ {
+ Item_SetFocus(g_comboBoxItem, x, y);
+ focusSet = qtrue;
+ }
+
+ // FIXME: this is the whole issue of focus vs. mouse over..
+ // need a better overall solution as i don't like going through everything twice
+ for (pass = 0; pass < 2; pass++)
+ {
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ itemDef_t *item = menu->items[i];
+
+ // turn off focus each item
+ // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
+
+ if (!(item->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)))
+ continue;
+
+ // items can be enabled and disabled based on cvars
+ if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE))
+ continue;
+
+ if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW))
+ continue;
+
+ cast = Item_ComboBox_MaybeCastToListBox(item);
+ result = Item_HandleMouseMove(item, x, y, pass, focusSet);
+ Item_ComboBox_MaybeUnCastFromListBox(item, cast);
+
+ if (!result && item->window.flags & WINDOW_MOUSEOVER)
+ {
+ Item_MouseLeave(item);
+ Item_SetMouseOver(item, qfalse);
}
- }
}
- } else if (menu->items[i]->window.flags & WINDOW_MOUSEOVER) {
- Item_MouseLeave(menu->items[i]);
- Item_SetMouseOver(menu->items[i], qfalse);
- }
}
- }
+}
+void Menu_Update(menuDef_t *menu)
+{
+ int i;
+
+ if (menu == NULL)
+ return;
+
+ for (i = 0; i < menu->itemCount; i++)
+ Item_Update(menu->items[i]);
}
-void Menu_Paint(menuDef_t *menu, qboolean forcePaint) {
- int i;
+void Menu_Paint(menuDef_t *menu, qboolean forcePaint)
+{
+ int i;
- if (menu == NULL) {
- return;
- }
+ if (menu == NULL)
+ return;
- if (!(menu->window.flags & WINDOW_VISIBLE) && !forcePaint) {
- return;
- }
+ if (!(menu->window.flags & WINDOW_VISIBLE) && !forcePaint)
+ return;
- if (menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible(menu->window.ownerDrawFlags)) {
- return;
- }
+ if (menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible(menu->window.ownerDrawFlags))
+ return;
- if (forcePaint) {
- menu->window.flags |= WINDOW_FORCED;
- }
+ if (forcePaint)
+ menu->window.flags |= WINDOW_FORCED;
- // draw the background if necessary
- if (menu->fullScreen) {
- // implies a background shader
- // FIXME: make sure we have a default shader if fullscreen is set with no background
- DC->drawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background );
- } else if (menu->window.background) {
- // this allows a background shader without being full screen
- //UI_DrawHandlePic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader);
- }
+ // draw the background if necessary
+ if (menu->fullScreen)
+ {
+ // implies a background shader
+ // FIXME: make sure we have a default shader if fullscreen is set with no background
+ DC->drawHandlePic(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background);
+ }
- // paint the background and or border
- Window_Paint(&menu->window, menu->fadeAmount, menu->fadeClamp, menu->fadeCycle );
+ // paint the background and or border
+ Window_Paint(&menu->window, menu->fadeAmount, menu->fadeClamp, menu->fadeCycle);
- for (i = 0; i < menu->itemCount; i++) {
- Item_Paint(menu->items[i]);
- }
+ Border_Paint(&menu->window);
- if (debugMode) {
- vec4_t color;
- color[0] = color[2] = color[3] = 1;
- color[1] = 0;
- DC->drawRect(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, 1, color);
- }
+ for (i = 0; i < menu->itemCount; i++)
+ Item_Paint(menu->items[i]);
+
+ if (DC->getCVarValue("ui_developer"))
+ {
+ vec4_t color;
+ color[0] = color[2] = color[3] = 1;
+ color[1] = 0;
+ DC->drawRect(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, 1, color);
+ }
}
-/*
-===============
-Item_ValidateTypeData
-===============
-*/
-void Item_ValidateTypeData(itemDef_t *item) {
- if (item->typeData) {
- return;
- }
-
- if (item->type == ITEM_TYPE_LISTBOX) {
- item->typeData = UI_Alloc(sizeof(listBoxDef_t));
- memset(item->typeData, 0, sizeof(listBoxDef_t));
- } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_SAYFIELD || item->type == ITEM_TYPE_NUMERICFIELD || item->type == ITEM_TYPE_YESNO || item->type == ITEM_TYPE_BIND || item->type == ITEM_TYPE_SLIDER || item->type == ITEM_TYPE_TEXT) {
- item->typeData = UI_Alloc(sizeof(editFieldDef_t));
- memset(item->typeData, 0, sizeof(editFieldDef_t));
- if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_SAYFIELD) {
- if (!((editFieldDef_t *) item->typeData)->maxPaintChars) {
- ((editFieldDef_t *) item->typeData)->maxPaintChars = MAX_EDITFIELD;
- }
- }
- } else if (item->type == ITEM_TYPE_MULTI) {
- item->typeData = UI_Alloc(sizeof(multiDef_t));
- } else if (item->type == ITEM_TYPE_MODEL) {
- item->typeData = UI_Alloc(sizeof(modelDef_t));
- }
+ /*
+ ===============
+ Keyword Hash
+ ===============
+ */
+
+#define KEYWORDHASH_SIZE 512
+
+typedef struct keywordHash_s {
+ char *keyword;
+ qboolean (*func)(itemDef_t *item, int handle);
+ int param;
+ struct keywordHash_s *next;
+} keywordHash_t;
+
+int KeywordHash_Key(char *keyword)
+{
+ int register hash, i;
+
+ hash = 0;
+
+ for (i = 0; keyword[i] != '\0'; i++)
+ {
+ if (keyword[i] >= 'A' && keyword[i] <= 'Z')
+ hash += (keyword[i] + ('a' - 'A')) * (119 + i);
+ else
+ hash += keyword[i] * (119 + i);
+ }
+
+ hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (KEYWORDHASH_SIZE - 1);
+ return hash;
+}
+
+void KeywordHash_Add(keywordHash_t *table[], keywordHash_t *key)
+{
+ int hash;
+
+ hash = KeywordHash_Key(key->keyword);
+ /*
+ if(table[hash]) int collision = qtrue;
+ */
+ key->next = table[hash];
+ table[hash] = key;
+}
+
+keywordHash_t *KeywordHash_Find(keywordHash_t *table[], char *keyword)
+{
+ keywordHash_t *key;
+ int hash;
+
+ hash = KeywordHash_Key(keyword);
+
+ for (key = table[hash]; key; key = key->next)
+ {
+ if (!Q_stricmp(key->keyword, keyword))
+ return key;
+ }
+
+ return NULL;
}
/*
===============
-Keyword Hash
+Item_DataType
+
+Give a numeric representation of which typeData union element this item uses
===============
*/
+itemDataType_t Item_DataType(itemDef_t *item)
+{
+ switch (item->type)
+ {
+ default:
+ case ITEM_TYPE_NONE:
+ return TYPE_NONE;
-#define KEYWORDHASH_SIZE 512
+ case ITEM_TYPE_LISTBOX:
+ case ITEM_TYPE_COMBOBOX:
+ return TYPE_LIST;
-typedef struct keywordHash_s
-{
- char *keyword;
- qboolean (*func)(itemDef_t *item, int handle);
- struct keywordHash_s *next;
-} keywordHash_t;
+ case ITEM_TYPE_CYCLE:
+ return TYPE_COMBO;
-int KeywordHash_Key(char *keyword) {
- int register hash, i;
+ case ITEM_TYPE_EDITFIELD:
+ case ITEM_TYPE_NUMERICFIELD:
+ case ITEM_TYPE_SAYFIELD:
+ case ITEM_TYPE_YESNO:
+ case ITEM_TYPE_BIND:
+ case ITEM_TYPE_SLIDER:
+ case ITEM_TYPE_TEXT:
+ return TYPE_EDIT;
- hash = 0;
- for (i = 0; keyword[i] != '\0'; i++) {
- if (keyword[i] >= 'A' && keyword[i] <= 'Z')
- hash += (keyword[i] + ('a' - 'A')) * (119 + i);
- else
- hash += keyword[i] * (119 + i);
- }
- hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (KEYWORDHASH_SIZE-1);
- return hash;
-}
+ case ITEM_TYPE_MULTI:
+ return TYPE_MULTI;
-void KeywordHash_Add(keywordHash_t *table[], keywordHash_t *key) {
- int hash;
+ case ITEM_TYPE_MODEL:
+ return TYPE_MODEL;
+ }
+}
- hash = KeywordHash_Key(key->keyword);
/*
- if (table[hash]) {
- int collision = qtrue;
- }
+===============
+Item_IsEditField
+===============
*/
- key->next = table[hash];
- table[hash] = key;
+static ID_INLINE qboolean Item_IsEditField(itemDef_t *item)
+{
+ switch (item->type)
+ {
+ case ITEM_TYPE_EDITFIELD:
+ case ITEM_TYPE_NUMERICFIELD:
+ case ITEM_TYPE_SAYFIELD:
+ return qtrue;
+
+ default:
+ return qfalse;
+ }
}
-keywordHash_t *KeywordHash_Find(keywordHash_t *table[], char *keyword)
+/*
+===============
+Item_IsListBox
+===============
+*/
+static ID_INLINE qboolean Item_IsListBox(itemDef_t *item)
{
- keywordHash_t *key;
- int hash;
+ switch (item->type)
+ {
+ case ITEM_TYPE_LISTBOX:
+ case ITEM_TYPE_COMBOBOX:
+ return qtrue;
- hash = KeywordHash_Key(keyword);
- for (key = table[hash]; key; key = key->next) {
- if (!Q_stricmp(key->keyword, keyword))
- return key;
- }
- return NULL;
+ default:
+ return qfalse;
+ }
}
/*
@@ -4681,787 +6206,827 @@ Item Keyword Parse functions
*/
// name <string>
-qboolean ItemParse_name( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->window.name)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_name(itemDef_t *item, int handle)
+{
+ if (!PC_String_Parse(handle, &item->window.name))
+ return qfalse;
+
+ return qtrue;
}
// name <string>
-qboolean ItemParse_focusSound( itemDef_t *item, int handle ) {
- const char *temp;
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->focusSound = DC->registerSound(temp, qfalse);
- return qtrue;
-}
+qboolean ItemParse_focusSound(itemDef_t *item, int handle)
+{
+ const char *temp;
+ if (!PC_String_Parse(handle, &temp))
+ return qfalse;
+
+ item->focusSound = DC->registerSound(temp, qfalse);
+ return qtrue;
+}
// text <string>
-qboolean ItemParse_text( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->text)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_text(itemDef_t *item, int handle)
+{
+ if (!PC_String_Parse(handle, &item->text))
+ return qfalse;
+
+ return qtrue;
}
// group <string>
-qboolean ItemParse_group( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->window.group)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_group(itemDef_t *item, int handle)
+{
+ if (!PC_String_Parse(handle, &item->window.group))
+ return qfalse;
+
+ return qtrue;
}
// asset_model <string>
-qboolean ItemParse_asset_model( itemDef_t *item, int handle ) {
- const char *temp;
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
+qboolean ItemParse_asset_model(itemDef_t *item, int handle)
+{
+ const char *temp;
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->asset = DC->registerModel(temp);
- modelPtr->angle = rand() % 360;
- return qtrue;
+ if (!PC_String_Parse(handle, &temp))
+ return qfalse;
+
+ item->asset = DC->registerModel(temp);
+ item->typeData.model->angle = rand() % 360;
+ return qtrue;
}
// asset_shader <string>
-qboolean ItemParse_asset_shader( itemDef_t *item, int handle ) {
- const char *temp;
+qboolean ItemParse_asset_shader(itemDef_t *item, int handle)
+{
+ const char *temp;
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->asset = DC->registerShaderNoMip(temp);
- return qtrue;
+ if (!PC_String_Parse(handle, &temp))
+ return qfalse;
+
+ item->asset = DC->registerShaderNoMip(temp);
+ return qtrue;
}
// model_origin <number> <number> <number>
-qboolean ItemParse_model_origin( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (PC_Float_Parse(handle, &modelPtr->origin[0])) {
- if (PC_Float_Parse(handle, &modelPtr->origin[1])) {
- if (PC_Float_Parse(handle, &modelPtr->origin[2])) {
- return qtrue;
- }
- }
- }
- return qfalse;
+qboolean ItemParse_model_origin(itemDef_t *item, int handle)
+{
+ return (PC_Float_Parse(handle, &item->typeData.model->origin[0]) &&
+ PC_Float_Parse(handle, &item->typeData.model->origin[1]) &&
+ PC_Float_Parse(handle, &item->typeData.model->origin[2]));
}
// model_fovx <number>
-qboolean ItemParse_model_fovx( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Float_Parse(handle, &modelPtr->fov_x)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_model_fovx(itemDef_t *item, int handle)
+{
+ return PC_Float_Parse(handle, &item->typeData.model->fov_x);
}
// model_fovy <number>
-qboolean ItemParse_model_fovy( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Float_Parse(handle, &modelPtr->fov_y)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_model_fovy(itemDef_t *item, int handle)
+{
+ return PC_Float_Parse(handle, &item->typeData.model->fov_y);
}
// model_rotation <integer>
-qboolean ItemParse_model_rotation( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Int_Parse(handle, &modelPtr->rotationSpeed)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_model_rotation(itemDef_t *item, int handle)
+{
+ return PC_Int_Parse(handle, &item->typeData.model->rotationSpeed);
}
// model_angle <integer>
-qboolean ItemParse_model_angle( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Int_Parse(handle, &modelPtr->angle)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_model_angle(itemDef_t *item, int handle)
+{
+ return PC_Int_Parse(handle, &item->typeData.model->angle);
}
// rect <rectangle>
-qboolean ItemParse_rect( itemDef_t *item, int handle ) {
- if (!PC_Rect_Parse(handle, &item->window.rectClient)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_rect(itemDef_t *item, int handle)
+{
+ if (!PC_Rect_Parse(handle, &item->window.rectClient))
+ return qfalse;
+
+ return qtrue;
+}
+
+// aspectBias <bias>
+qboolean ItemParse_aspectBias(itemDef_t *item, int handle)
+{
+ if (!PC_Int_Parse(handle, &item->window.aspectBias))
+ return qfalse;
+
+ return qtrue;
}
// style <integer>
-qboolean ItemParse_style( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->window.style)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_style(itemDef_t *item, int handle)
+{
+ if (!PC_Int_Parse(handle, &item->window.style))
+ return qfalse;
+
+ return qtrue;
}
// decoration
-qboolean ItemParse_decoration( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_DECORATION;
- return qtrue;
+qboolean ItemParse_decoration(itemDef_t *item, int handle)
+{
+ (void)handle;
+
+ item->window.flags |= WINDOW_DECORATION;
+ return qtrue;
}
// notselectable
-qboolean ItemParse_notselectable( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
- Item_ValidateTypeData(item);
- listPtr = (listBoxDef_t*)item->typeData;
- if (item->type == ITEM_TYPE_LISTBOX && listPtr) {
- listPtr->notselectable = qtrue;
- }
- return qtrue;
+qboolean ItemParse_notselectable(itemDef_t *item, int handle)
+{
+ (void)handle;
+
+ item->typeData.list->notselectable = qtrue;
+ return qtrue;
}
-// manually wrapped
-qboolean ItemParse_wrapped( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_WRAPPED;
- return qtrue;
+// noscrollbar
+qboolean ItemParse_noscrollbar(itemDef_t *item, int handle)
+{
+ (void)handle;
+
+ item->typeData.list->noscrollbar = qtrue;
+ return qtrue;
}
-// auto wrapped
-qboolean ItemParse_autowrapped( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_AUTOWRAPPED;
- return qtrue;
+// resetonfeederchange
+qboolean ItemParse_resetonfeederchange(itemDef_t *item, int handle)
+{
+ (void)handle;
+
+ item->typeData.list->resetonfeederchange = qtrue;
+ return qtrue;
}
+// auto wrapped
+qboolean ItemParse_wrapped(itemDef_t *item, int handle)
+{
+ (void)handle;
-// horizontalscroll
-qboolean ItemParse_horizontalscroll( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_HORIZONTAL;
- return qtrue;
+ item->window.flags |= WINDOW_WRAPPED;
+ return qtrue;
}
// type <integer>
-qboolean ItemParse_type( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->type)) {
- return qfalse;
- }
- Item_ValidateTypeData(item);
- return qtrue;
+qboolean ItemParse_type(itemDef_t *item, int handle)
+{
+ if (item->type != ITEM_TYPE_NONE)
+ {
+ PC_SourceError(handle, "item already has a type");
+ return qfalse;
+ }
+
+ if (!PC_Int_Parse(handle, &item->type))
+ return qfalse;
+
+ if (item->type == ITEM_TYPE_NONE)
+ {
+ PC_SourceError(handle, "type must not be none");
+ return qfalse;
+ }
+
+ // allocate the relevant type data
+ switch (item->type)
+ {
+ case ITEM_TYPE_LISTBOX:
+ case ITEM_TYPE_COMBOBOX:
+ item->typeData.list = UI_Alloc(sizeof(listBoxDef_t));
+ memset(item->typeData.list, 0, sizeof(listBoxDef_t));
+ break;
+
+ case ITEM_TYPE_CYCLE:
+ item->typeData.cycle = UI_Alloc(sizeof(cycleDef_t));
+ memset(item->typeData.cycle, 0, sizeof(cycleDef_t));
+ break;
+
+ case ITEM_TYPE_EDITFIELD:
+ case ITEM_TYPE_SAYFIELD:
+ case ITEM_TYPE_NUMERICFIELD:
+ case ITEM_TYPE_YESNO:
+ case ITEM_TYPE_BIND:
+ case ITEM_TYPE_SLIDER:
+ case ITEM_TYPE_TEXT:
+ item->typeData.edit = UI_Alloc(sizeof(editFieldDef_t));
+ memset(item->typeData.edit, 0, sizeof(editFieldDef_t));
+
+ if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_SAYFIELD)
+ item->typeData.edit->maxPaintChars = MAX_EDITFIELD;
+ break;
+
+ case ITEM_TYPE_MULTI:
+ item->typeData.multi = UI_Alloc(sizeof(multiDef_t));
+ memset(item->typeData.multi, 0, sizeof(multiDef_t));
+ break;
+
+ case ITEM_TYPE_MODEL:
+ item->typeData.model = UI_Alloc(sizeof(modelDef_t));
+ memset(item->typeData.model, 0, sizeof(modelDef_t));
+ break;
+
+ default:
+ break;
+ }
+
+ return qtrue;
}
// elementwidth, used for listbox image elements
-// uses textalignx for storage
-qboolean ItemParse_elementwidth( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- listPtr = (listBoxDef_t*)item->typeData;
- if (!PC_Float_Parse(handle, &listPtr->elementWidth)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_elementwidth(itemDef_t *item, int handle)
+{
+ return PC_Float_Parse(handle, &item->typeData.list->elementWidth);
}
// elementheight, used for listbox image elements
-// uses textaligny for storage
-qboolean ItemParse_elementheight( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
+qboolean ItemParse_elementheight(itemDef_t *item, int handle)
+{
+ return PC_Float_Parse(handle, &item->typeData.list->elementHeight);
+}
- Item_ValidateTypeData(item);
- listPtr = (listBoxDef_t*)item->typeData;
- if (!PC_Float_Parse(handle, &listPtr->elementHeight)) {
- return qfalse;
- }
- return qtrue;
+// dropitems, number of items to drop from a combobox
+qboolean ItemParse_dropitems(itemDef_t *item, int handle)
+{
+ return PC_Int_Parse(handle, &item->typeData.list->dropItems);
}
-// feeder <float>
-qboolean ItemParse_feeder( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->special)) {
- return qfalse;
- }
- return qtrue;
+// feeder <int>
+qboolean ItemParse_feeder(itemDef_t *item, int handle)
+{
+ if (!PC_Int_Parse(handle, &item->feederID))
+ return qfalse;
+
+ return qtrue;
}
// elementtype, used to specify what type of elements a listbox contains
// uses textstyle for storage
-qboolean ItemParse_elementtype( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- listPtr = (listBoxDef_t*)item->typeData;
- if (!PC_Int_Parse(handle, &listPtr->elementStyle)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_elementtype(itemDef_t *item, int handle)
+{
+ return PC_Int_Parse(handle, &item->typeData.list->elementStyle);
}
// columns sets a number of columns and an x pos and width per..
-qboolean ItemParse_columns( itemDef_t *item, int handle ) {
- int num, i;
- listBoxDef_t *listPtr;
+qboolean ItemParse_columns(itemDef_t *item, int handle)
+{
+ int i;
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- listPtr = (listBoxDef_t*)item->typeData;
- if (PC_Int_Parse(handle, &num)) {
- if (num > MAX_LB_COLUMNS) {
- num = MAX_LB_COLUMNS;
- }
- listPtr->numColumns = num;
- for (i = 0; i < num; i++) {
- int pos, width, maxChars, align;
-
- if( PC_Int_Parse( handle, &pos ) &&
- PC_Int_Parse( handle, &width ) &&
- PC_Int_Parse( handle, &maxChars ) &&
- PC_Int_Parse( handle, &align ) )
- {
- listPtr->columnInfo[i].pos = pos;
- listPtr->columnInfo[i].width = width;
- listPtr->columnInfo[i].maxChars = maxChars;
- listPtr->columnInfo[i].align = align;
- } else {
+ if (!PC_Int_Parse(handle, &item->typeData.list->numColumns))
+ return qfalse;
+
+ if (item->typeData.list->numColumns > MAX_LB_COLUMNS)
+ {
+ PC_SourceError(handle, "exceeded maximum allowed columns (%d)", MAX_LB_COLUMNS);
return qfalse;
- }
}
- } else {
- return qfalse;
- }
- return qtrue;
+
+ for (i = 0; i < item->typeData.list->numColumns; i++)
+ {
+ int pos, width, align;
+
+ if (!PC_Int_Parse(handle, &pos) || !PC_Int_Parse(handle, &width) || !PC_Int_Parse(handle, &align))
+ return qfalse;
+
+ item->typeData.list->columnInfo[i].pos = pos;
+ item->typeData.list->columnInfo[i].width = width;
+ item->typeData.list->columnInfo[i].align = align;
+ }
+
+ return qtrue;
}
-qboolean ItemParse_border( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->window.border)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_border(itemDef_t *item, int handle)
+{
+ if (!PC_Int_Parse(handle, &item->window.border))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_bordersize( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->window.borderSize)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_bordersize(itemDef_t *item, int handle)
+{
+ if (!PC_Float_Parse(handle, &item->window.borderSize))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_visible( itemDef_t *item, int handle ) {
- int i;
+// FIXME: why does this require a parameter? visible MENU_FALSE does nothing
+qboolean ItemParse_visible(itemDef_t *item, int handle)
+{
+ int i;
- if (!PC_Int_Parse(handle, &i)) {
- return qfalse;
- }
- if (i) {
- item->window.flags |= WINDOW_VISIBLE;
- }
- return qtrue;
+ if (!PC_Int_Parse(handle, &i))
+ return qfalse;
+
+ if (i)
+ item->window.flags |= WINDOW_VISIBLE;
+
+ return qtrue;
}
-qboolean ItemParse_ownerdraw( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->window.ownerDraw)) {
- return qfalse;
- }
- item->type = ITEM_TYPE_OWNERDRAW;
- return qtrue;
+// ownerdraw <number>, implies ITEM_TYPE_OWNERDRAW
+qboolean ItemParse_ownerdraw(itemDef_t *item, int handle)
+{
+ if (!PC_Int_Parse(handle, &item->window.ownerDraw))
+ return qfalse;
+
+ if (item->type != ITEM_TYPE_NONE && item->type != ITEM_TYPE_OWNERDRAW)
+ {
+ PC_SourceError(handle, "ownerdraws cannot have an item type");
+ return qfalse;
+ }
+
+ item->type = ITEM_TYPE_OWNERDRAW;
+
+ return qtrue;
}
-qboolean ItemParse_align( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->alignment)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_align(itemDef_t *item, int handle)
+{
+ if (!PC_Int_Parse(handle, &item->alignment))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_textalign( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->textalignment)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_textalign(itemDef_t *item, int handle)
+{
+ if (!PC_Int_Parse(handle, &item->textalignment))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_textalignx( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->textalignx)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_textvalign(itemDef_t *item, int handle)
+{
+ if (!PC_Int_Parse(handle, &item->textvalignment))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_textaligny( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->textaligny)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_textalignx(itemDef_t *item, int handle)
+{
+ if (!PC_Float_Parse(handle, &item->textalignx))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_textscale( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->textscale)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_textaligny(itemDef_t *item, int handle)
+{
+ if (!PC_Float_Parse(handle, &item->textaligny))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_textstyle( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->textStyle)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_textscale(itemDef_t *item, int handle)
+{
+ if (!PC_Float_Parse(handle, &item->textscale))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_backcolor( itemDef_t *item, int handle ) {
- int i;
- float f;
+qboolean ItemParse_textstyle(itemDef_t *item, int handle)
+{
+ if (!PC_Int_Parse(handle, &item->textStyle))
+ return qfalse;
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- item->window.backColor[i] = f;
- }
- return qtrue;
+ return qtrue;
}
-qboolean ItemParse_forecolor( itemDef_t *item, int handle ) {
- int i;
- float f;
+qboolean ItemParse_backcolor(itemDef_t *item, int handle)
+{
+ int i;
+ float f;
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
+ for (i = 0; i < 4; i++)
+ {
+ if (!PC_Float_Parse(handle, &f))
+ return qfalse;
+
+ item->window.backColor[i] = f;
}
- item->window.foreColor[i] = f;
- item->window.flags |= WINDOW_FORECOLORSET;
- }
- return qtrue;
+
+ return qtrue;
}
-qboolean ItemParse_bordercolor( itemDef_t *item, int handle ) {
- int i;
- float f;
+qboolean ItemParse_forecolor(itemDef_t *item, int handle)
+{
+ int i;
+ float f;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (!PC_Float_Parse(handle, &f))
+ return qfalse;
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
+ item->window.foreColor[i] = f;
+ item->window.flags |= WINDOW_FORECOLORSET;
}
- item->window.borderColor[i] = f;
- }
- return qtrue;
-}
-qboolean ItemParse_outlinecolor( itemDef_t *item, int handle ) {
- if (!PC_Color_Parse(handle, &item->window.outlineColor)){
- return qfalse;
- }
- return qtrue;
+ return qtrue;
}
-qboolean ItemParse_background( itemDef_t *item, int handle ) {
- const char *temp;
+qboolean ItemParse_bordercolor(itemDef_t *item, int handle)
+{
+ int i;
+ float f;
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->window.background = DC->registerShaderNoMip(temp);
- return qtrue;
-}
+ for (i = 0; i < 4; i++)
+ {
+ if (!PC_Float_Parse(handle, &f))
+ return qfalse;
-qboolean ItemParse_cinematic( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->window.cinematicName)) {
- return qfalse;
- }
- return qtrue;
+ item->window.borderColor[i] = f;
+ }
+
+ return qtrue;
}
-qboolean ItemParse_doubleClick( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
+qboolean ItemParse_outlinecolor(itemDef_t *item, int handle)
+{
+ if (!PC_Color_Parse(handle, &item->window.outlineColor))
+ return qfalse;
- Item_ValidateTypeData(item);
- if (!item->typeData) {
- return qfalse;
- }
+ return qtrue;
+}
- listPtr = (listBoxDef_t*)item->typeData;
+qboolean ItemParse_background(itemDef_t *item, int handle)
+{
+ const char *temp;
- if (!PC_Script_Parse(handle, &listPtr->doubleClick)) {
- return qfalse;
- }
- return qtrue;
+ if (!PC_String_Parse(handle, &temp))
+ return qfalse;
+
+ item->window.background = DC->registerShaderNoMip(temp);
+ return qtrue;
}
-qboolean ItemParse_onFocus( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->onFocus)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_cinematic(itemDef_t *item, int handle)
+{
+ if (!PC_String_Parse(handle, &item->window.cinematicName))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_leaveFocus( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->leaveFocus)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_doubleClick(itemDef_t *item, int handle)
+{
+ return (item->typeData.list && PC_Script_Parse(handle, &item->typeData.list->doubleClick));
}
-qboolean ItemParse_mouseEnter( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseEnter)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_onFocus(itemDef_t *item, int handle)
+{
+ if (!PC_Script_Parse(handle, &item->onFocus))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_mouseExit( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseExit)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_leaveFocus(itemDef_t *item, int handle)
+{
+ if (!PC_Script_Parse(handle, &item->leaveFocus))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_mouseEnterText( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseEnterText)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_mouseEnter(itemDef_t *item, int handle)
+{
+ if (!PC_Script_Parse(handle, &item->mouseEnter))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_mouseExitText( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseExitText)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_mouseExit(itemDef_t *item, int handle)
+{
+ if (!PC_Script_Parse(handle, &item->mouseExit))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_onTextEntry( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->onTextEntry)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_mouseEnterText(itemDef_t *item, int handle)
+{
+ if (!PC_Script_Parse(handle, &item->mouseEnterText))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_action( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->action)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_mouseExitText(itemDef_t *item, int handle)
+{
+ if (!PC_Script_Parse(handle, &item->mouseExitText))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_special( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->special)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_onTextEntry(itemDef_t *item, int handle)
+{
+ if (!PC_Script_Parse(handle, &item->onTextEntry))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_cvarTest( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->cvarTest)) {
- return qfalse;
- }
- return qtrue;
+qboolean ItemParse_onCharEntry(itemDef_t *item, int handle)
+{
+ if (!PC_Script_Parse(handle, &item->onCharEntry))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_cvar( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
+qboolean ItemParse_action(itemDef_t *item, int handle)
+{
+ if (!PC_Script_Parse(handle, &item->action))
+ return qfalse;
- Item_ValidateTypeData(item);
- if (!PC_String_Parse(handle, &item->cvar)) {
- return qfalse;
- }
- if (item->typeData) {
- editPtr = (editFieldDef_t*)item->typeData;
- editPtr->minVal = -1;
- editPtr->maxVal = -1;
- editPtr->defVal = -1;
- }
- return qtrue;
-}
-
-qboolean ItemParse_maxChars( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
- int maxChars;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
+ return qtrue;
+}
- if (!PC_Int_Parse(handle, &maxChars)) {
- return qfalse;
- }
- editPtr = (editFieldDef_t*)item->typeData;
- editPtr->maxChars = maxChars;
- return qtrue;
+qboolean ItemParse_cvarTest(itemDef_t *item, int handle)
+{
+ if (!PC_String_Parse(handle, &item->cvarTest))
+ return qfalse;
+
+ return qtrue;
}
-qboolean ItemParse_maxPaintChars( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
- int maxChars;
+qboolean ItemParse_cvar(itemDef_t *item, int handle)
+{
+ if (!PC_String_Parse(handle, &item->cvar))
+ return qfalse;
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
+ if (Item_DataType(item) == TYPE_EDIT)
+ {
+ item->typeData.edit->minVal = -1;
+ item->typeData.edit->maxVal = -1;
+ item->typeData.edit->defVal = -1;
+ }
- if (!PC_Int_Parse(handle, &maxChars)) {
- return qfalse;
- }
- editPtr = (editFieldDef_t*)item->typeData;
- editPtr->maxPaintChars = maxChars;
- return qtrue;
+ return qtrue;
+}
+
+qboolean ItemParse_maxChars(itemDef_t *item, int handle)
+{
+ return PC_Int_Parse(handle, &item->typeData.edit->maxChars);
}
+qboolean ItemParse_maxPaintChars(itemDef_t *item, int handle)
+{
+ return PC_Int_Parse(handle, &item->typeData.edit->maxPaintChars);
+}
+qboolean ItemParse_maxFieldWidth(itemDef_t *item, int handle)
+{
+ if (!PC_Int_Parse(handle, &item->typeData.edit->maxFieldWidth))
+ return qfalse;
-qboolean ItemParse_cvarFloat( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
+ if (item->typeData.edit->maxFieldWidth < MIN_FIELD_WIDTH)
+ {
+ PC_SourceError(handle, "max field width must be at least %d", MIN_FIELD_WIDTH);
+ return qfalse;
+ }
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- editPtr = (editFieldDef_t*)item->typeData;
- if (PC_String_Parse(handle, &item->cvar) &&
- PC_Float_Parse(handle, &editPtr->defVal) &&
- PC_Float_Parse(handle, &editPtr->minVal) &&
- PC_Float_Parse(handle, &editPtr->maxVal)) {
return qtrue;
- }
- return qfalse;
}
-qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) {
- pc_token_t token;
- multiDef_t *multiPtr;
- int pass;
+qboolean ItemParse_cvarFloat(itemDef_t *item, int handle)
+{
+ return (PC_String_Parse(handle, &item->cvar) && PC_Float_Parse(handle, &item->typeData.edit->defVal) &&
+ PC_Float_Parse(handle, &item->typeData.edit->minVal) &&
+ PC_Float_Parse(handle, &item->typeData.edit->maxVal));
+}
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- multiPtr = (multiDef_t*)item->typeData;
- multiPtr->count = 0;
- multiPtr->strDef = qtrue;
+qboolean ItemParse_cvarStrList(itemDef_t *item, int handle)
+{
+ pc_token_t token;
+ multiDef_t *multiPtr;
+ int pass;
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
+ multiPtr = item->typeData.multi;
+ multiPtr->count = 0;
+ multiPtr->strDef = qtrue;
- pass = 0;
- while ( 1 ) {
- if (!trap_Parse_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu item\n");
- return qfalse;
- }
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
- if (*token.string == '}') {
- return qtrue;
- }
+ if (*token.string != '{')
+ return qfalse;
- if (*token.string == ',' || *token.string == ';') {
- continue;
- }
+ pass = 0;
- if (pass == 0) {
- multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
- pass = 1;
- } else {
- multiPtr->cvarStr[multiPtr->count] = String_Alloc(token.string);
- pass = 0;
- multiPtr->count++;
- if (multiPtr->count >= MAX_MULTI_CVARS) {
- return qfalse;
- }
+ while (1)
+ {
+ if (!trap_Parse_ReadToken(handle, &token))
+ {
+ PC_SourceError(handle, "end of file inside menu item\n");
+ return qfalse;
+ }
+
+ if (*token.string == '}')
+ return qtrue;
+
+ if (*token.string == ',' || *token.string == ';')
+ continue;
+
+ if (pass == 0)
+ {
+ multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
+ pass = 1;
+ }
+ else
+ {
+ multiPtr->cvarStr[multiPtr->count] = String_Alloc(token.string);
+ pass = 0;
+ multiPtr->count++;
+
+ if (multiPtr->count >= MAX_MULTI_CVARS)
+ {
+ PC_SourceError(handle, "cvar string list may not exceed %d cvars", MAX_MULTI_CVARS);
+ return qfalse;
+ }
+ }
}
- }
- return qfalse; // bk001205 - LCC missing return value
+ return qfalse;
}
-qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) {
- pc_token_t token;
- multiDef_t *multiPtr;
+qboolean ItemParse_cvarFloatList(itemDef_t *item, int handle)
+{
+ pc_token_t token;
+ multiDef_t *multiPtr;
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- multiPtr = (multiDef_t*)item->typeData;
- multiPtr->count = 0;
- multiPtr->strDef = qfalse;
+ multiPtr = item->typeData.multi;
+ multiPtr->count = 0;
+ multiPtr->strDef = qfalse;
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
- while ( 1 ) {
- if (!trap_Parse_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu item\n");
- return qfalse;
- }
+ if (*token.string != '{')
+ return qfalse;
- if (*token.string == '}') {
- return qtrue;
- }
+ while (1)
+ {
+ if (!trap_Parse_ReadToken(handle, &token))
+ {
+ PC_SourceError(handle, "end of file inside menu item\n");
+ return qfalse;
+ }
- if (*token.string == ',' || *token.string == ';') {
- continue;
- }
+ if (*token.string == '}')
+ return qtrue;
- multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
- if (!PC_Float_Parse(handle, &multiPtr->cvarValue[multiPtr->count])) {
- return qfalse;
- }
+ if (*token.string == ',' || *token.string == ';')
+ continue;
- multiPtr->count++;
- if (multiPtr->count >= MAX_MULTI_CVARS) {
- return qfalse;
+ multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
+
+ if (!PC_Float_Parse(handle, &multiPtr->cvarValue[multiPtr->count]))
+ return qfalse;
+
+ multiPtr->count++;
+
+ if (multiPtr->count >= MAX_MULTI_CVARS)
+ {
+ PC_SourceError(handle, "cvar string list may not exceed %d cvars", MAX_MULTI_CVARS);
+ return qfalse;
+ }
}
- }
- return qfalse; // bk001205 - LCC missing return value
+ return qfalse;
}
+qboolean ItemParse_addColorRange(itemDef_t *item, int handle)
+{
+ colorRangeDef_t color;
+ if (PC_Float_Parse(handle, &color.low) && PC_Float_Parse(handle, &color.high) &&
+ PC_Color_Parse(handle, &color.color))
+ {
+ if (item->numColors < MAX_COLOR_RANGES)
+ {
+ memcpy(&item->colorRanges[item->numColors], &color, sizeof(color));
+ item->numColors++;
+ }
+ else
+ {
+ PC_SourceError(handle, "may not exceed %d color ranges", MAX_COLOR_RANGES);
+ return qfalse;
+ }
-qboolean ItemParse_addColorRange( itemDef_t *item, int handle ) {
- colorRangeDef_t color;
-
- if (PC_Float_Parse(handle, &color.low) &&
- PC_Float_Parse(handle, &color.high) &&
- PC_Color_Parse(handle, &color.color) ) {
- if (item->numColors < MAX_COLOR_RANGES) {
- memcpy(&item->colorRanges[item->numColors], &color, sizeof(color));
- item->numColors++;
+ return qtrue;
}
+
+ return qfalse;
+}
+
+qboolean ItemParse_ownerdrawFlag(itemDef_t *item, int handle)
+{
+ int i;
+
+ if (!PC_Int_Parse(handle, &i))
+ return qfalse;
+
+ item->window.ownerDrawFlags |= i;
return qtrue;
- }
- return qfalse;
}
-qboolean ItemParse_ownerdrawFlag( itemDef_t *item, int handle ) {
- int i;
- if (!PC_Int_Parse(handle, &i)) {
+qboolean ItemParse_enableCvar(itemDef_t *item, int handle)
+{
+ if (PC_Script_Parse(handle, &item->enableCvar))
+ {
+ item->cvarFlags = CVAR_ENABLE;
+ return qtrue;
+ }
+
return qfalse;
- }
- item->window.ownerDrawFlags |= i;
- return qtrue;
}
-qboolean ItemParse_enableCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_ENABLE;
- return qtrue;
- }
- return qfalse;
+qboolean ItemParse_disableCvar(itemDef_t *item, int handle)
+{
+ if (PC_Script_Parse(handle, &item->enableCvar))
+ {
+ item->cvarFlags = CVAR_DISABLE;
+ return qtrue;
+ }
+
+ return qfalse;
}
-qboolean ItemParse_disableCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_DISABLE;
- return qtrue;
- }
- return qfalse;
+qboolean ItemParse_showCvar(itemDef_t *item, int handle)
+{
+ if (PC_Script_Parse(handle, &item->enableCvar))
+ {
+ item->cvarFlags = CVAR_SHOW;
+ return qtrue;
+ }
+
+ return qfalse;
}
-qboolean ItemParse_showCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_SHOW;
- return qtrue;
- }
- return qfalse;
+qboolean ItemParse_hideCvar(itemDef_t *item, int handle)
+{
+ if (PC_Script_Parse(handle, &item->enableCvar))
+ {
+ item->cvarFlags = CVAR_HIDE;
+ return qtrue;
+ }
+
+ return qfalse;
}
-qboolean ItemParse_hideCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_HIDE;
- return qtrue;
- }
- return qfalse;
-}
-
-
-keywordHash_t itemParseKeywords[] = {
- {"name", ItemParse_name, NULL},
- {"text", ItemParse_text, NULL},
- {"group", ItemParse_group, NULL},
- {"asset_model", ItemParse_asset_model, NULL},
- {"asset_shader", ItemParse_asset_shader, NULL},
- {"model_origin", ItemParse_model_origin, NULL},
- {"model_fovx", ItemParse_model_fovx, NULL},
- {"model_fovy", ItemParse_model_fovy, NULL},
- {"model_rotation", ItemParse_model_rotation, NULL},
- {"model_angle", ItemParse_model_angle, NULL},
- {"rect", ItemParse_rect, NULL},
- {"style", ItemParse_style, NULL},
- {"decoration", ItemParse_decoration, NULL},
- {"notselectable", ItemParse_notselectable, NULL},
- {"wrapped", ItemParse_wrapped, NULL},
- {"autowrapped", ItemParse_autowrapped, NULL},
- {"horizontalscroll", ItemParse_horizontalscroll, NULL},
- {"type", ItemParse_type, NULL},
- {"elementwidth", ItemParse_elementwidth, NULL},
- {"elementheight", ItemParse_elementheight, NULL},
- {"feeder", ItemParse_feeder, NULL},
- {"elementtype", ItemParse_elementtype, NULL},
- {"columns", ItemParse_columns, NULL},
- {"border", ItemParse_border, NULL},
- {"bordersize", ItemParse_bordersize, NULL},
- {"visible", ItemParse_visible, NULL},
- {"ownerdraw", ItemParse_ownerdraw, NULL},
- {"align", ItemParse_align, NULL},
- {"textalign", ItemParse_textalign, NULL},
- {"textalignx", ItemParse_textalignx, NULL},
- {"textaligny", ItemParse_textaligny, NULL},
- {"textscale", ItemParse_textscale, NULL},
- {"textstyle", ItemParse_textstyle, NULL},
- {"backcolor", ItemParse_backcolor, NULL},
- {"forecolor", ItemParse_forecolor, NULL},
- {"bordercolor", ItemParse_bordercolor, NULL},
- {"outlinecolor", ItemParse_outlinecolor, NULL},
- {"background", ItemParse_background, NULL},
- {"onFocus", ItemParse_onFocus, NULL},
- {"leaveFocus", ItemParse_leaveFocus, NULL},
- {"mouseEnter", ItemParse_mouseEnter, NULL},
- {"mouseExit", ItemParse_mouseExit, NULL},
- {"mouseEnterText", ItemParse_mouseEnterText, NULL},
- {"mouseExitText", ItemParse_mouseExitText, NULL},
- {"onTextEntry", ItemParse_onTextEntry, NULL},
- {"action", ItemParse_action, NULL},
- {"special", ItemParse_special, NULL},
- {"cvar", ItemParse_cvar, NULL},
- {"maxChars", ItemParse_maxChars, NULL},
- {"maxPaintChars", ItemParse_maxPaintChars, NULL},
- {"focusSound", ItemParse_focusSound, NULL},
- {"cvarFloat", ItemParse_cvarFloat, NULL},
- {"cvarStrList", ItemParse_cvarStrList, NULL},
- {"cvarFloatList", ItemParse_cvarFloatList, NULL},
- {"addColorRange", ItemParse_addColorRange, NULL},
- {"ownerdrawFlag", ItemParse_ownerdrawFlag, NULL},
- {"enableCvar", ItemParse_enableCvar, NULL},
- {"cvarTest", ItemParse_cvarTest, NULL},
- {"disableCvar", ItemParse_disableCvar, NULL},
- {"showCvar", ItemParse_showCvar, NULL},
- {"hideCvar", ItemParse_hideCvar, NULL},
- {"cinematic", ItemParse_cinematic, NULL},
- {"doubleclick", ItemParse_doubleClick, NULL},
- {NULL, voidFunction2, NULL}
-};
+keywordHash_t itemParseKeywords[] = {{"name", ItemParse_name, TYPE_ANY, NULL}, {"type", ItemParse_type, TYPE_ANY, NULL},
+ {"text", ItemParse_text, TYPE_ANY, NULL}, {"group", ItemParse_group, TYPE_ANY, NULL},
+ {"asset_model", ItemParse_asset_model, TYPE_MODEL, NULL},
+ {"asset_shader", ItemParse_asset_shader, TYPE_ANY, NULL}, // ?
+ {"model_origin", ItemParse_model_origin, TYPE_MODEL, NULL}, {"model_fovx", ItemParse_model_fovx, TYPE_MODEL, NULL},
+ {"model_fovy", ItemParse_model_fovy, TYPE_MODEL, NULL},
+ {"model_rotation", ItemParse_model_rotation, TYPE_MODEL, NULL},
+ {"model_angle", ItemParse_model_angle, TYPE_MODEL, NULL}, {"rect", ItemParse_rect, TYPE_ANY, NULL},
+ {"aspectBias", ItemParse_aspectBias, TYPE_ANY, NULL}, {"style", ItemParse_style, TYPE_ANY, NULL},
+ {"decoration", ItemParse_decoration, TYPE_ANY, NULL}, {"notselectable", ItemParse_notselectable, TYPE_LIST, NULL},
+ {"noscrollbar", ItemParse_noscrollbar, TYPE_LIST, NULL},
+ {"resetonfeederchange", ItemParse_resetonfeederchange, TYPE_LIST, NULL},
+ {"wrapped", ItemParse_wrapped, TYPE_ANY, NULL}, {"elementwidth", ItemParse_elementwidth, TYPE_LIST, NULL},
+ {"elementheight", ItemParse_elementheight, TYPE_LIST, NULL}, {"dropitems", ItemParse_dropitems, TYPE_LIST, NULL},
+ {"feeder", ItemParse_feeder, TYPE_ANY, NULL}, {"elementtype", ItemParse_elementtype, TYPE_LIST, NULL},
+ {"columns", ItemParse_columns, TYPE_LIST, NULL}, {"border", ItemParse_border, TYPE_ANY, NULL},
+ {"bordersize", ItemParse_bordersize, TYPE_ANY, NULL}, {"visible", ItemParse_visible, TYPE_ANY, NULL},
+ {"ownerdraw", ItemParse_ownerdraw, TYPE_ANY, NULL}, {"align", ItemParse_align, TYPE_ANY, NULL},
+ {"textalign", ItemParse_textalign, TYPE_ANY, NULL}, {"textvalign", ItemParse_textvalign, TYPE_ANY, NULL},
+ {"textalignx", ItemParse_textalignx, TYPE_ANY, NULL}, {"textaligny", ItemParse_textaligny, TYPE_ANY, NULL},
+ {"textscale", ItemParse_textscale, TYPE_ANY, NULL}, {"textstyle", ItemParse_textstyle, TYPE_ANY, NULL},
+ {"backcolor", ItemParse_backcolor, TYPE_ANY, NULL}, {"forecolor", ItemParse_forecolor, TYPE_ANY, NULL},
+ {"bordercolor", ItemParse_bordercolor, TYPE_ANY, NULL}, {"outlinecolor", ItemParse_outlinecolor, TYPE_ANY, NULL},
+ {"background", ItemParse_background, TYPE_ANY, NULL}, {"onFocus", ItemParse_onFocus, TYPE_ANY, NULL},
+ {"leaveFocus", ItemParse_leaveFocus, TYPE_ANY, NULL}, {"mouseEnter", ItemParse_mouseEnter, TYPE_ANY, NULL},
+ {"mouseExit", ItemParse_mouseExit, TYPE_ANY, NULL}, {"mouseEnterText", ItemParse_mouseEnterText, TYPE_ANY, NULL},
+ {"mouseExitText", ItemParse_mouseExitText, TYPE_ANY, NULL}, {"onTextEntry", ItemParse_onTextEntry, TYPE_ANY, NULL},
+ {"onCharEntry", ItemParse_onCharEntry, TYPE_ANY, NULL}, {"action", ItemParse_action, TYPE_ANY, NULL},
+ {"cvar", ItemParse_cvar, TYPE_ANY, NULL}, {"maxChars", ItemParse_maxChars, TYPE_EDIT, NULL},
+ {"maxPaintChars", ItemParse_maxPaintChars, TYPE_EDIT, NULL},
+ {"maxFieldWidth", ItemParse_maxFieldWidth, TYPE_EDIT, NULL}, {"focusSound", ItemParse_focusSound, TYPE_ANY, NULL},
+ {"cvarFloat", ItemParse_cvarFloat, TYPE_EDIT, NULL}, {"cvarStrList", ItemParse_cvarStrList, TYPE_MULTI, NULL},
+ {"cvarFloatList", ItemParse_cvarFloatList, TYPE_MULTI, NULL},
+ {"addColorRange", ItemParse_addColorRange, TYPE_ANY, NULL},
+ {"ownerdrawFlag", ItemParse_ownerdrawFlag, TYPE_ANY, NULL}, // hm.
+ {"enableCvar", ItemParse_enableCvar, TYPE_ANY, NULL}, {"cvarTest", ItemParse_cvarTest, TYPE_ANY, NULL},
+ {"disableCvar", ItemParse_disableCvar, TYPE_ANY, NULL}, {"showCvar", ItemParse_showCvar, TYPE_ANY, NULL},
+ {"hideCvar", ItemParse_hideCvar, TYPE_ANY, NULL}, {"cinematic", ItemParse_cinematic, TYPE_ANY, NULL},
+ {"doubleclick", ItemParse_doubleClick, TYPE_LIST, NULL}, {NULL, voidFunction2, 0, NULL}};
keywordHash_t *itemParseKeywordHash[KEYWORDHASH_SIZE];
@@ -5470,14 +7035,14 @@ keywordHash_t *itemParseKeywordHash[KEYWORDHASH_SIZE];
Item_SetupKeywordHash
===============
*/
-void Item_SetupKeywordHash( void )
+void Item_SetupKeywordHash(void)
{
- int i;
+ int i;
- memset( itemParseKeywordHash, 0, sizeof( itemParseKeywordHash ) );
+ memset(itemParseKeywordHash, 0, sizeof(itemParseKeywordHash));
- for( i = 0; itemParseKeywords[ i ].keyword; i++ )
- KeywordHash_Add( itemParseKeywordHash, &itemParseKeywords[ i ] );
+ for (i = 0; itemParseKeywords[i].keyword; i++)
+ KeywordHash_Add(itemParseKeywordHash, &itemParseKeywords[i]);
}
/*
@@ -5485,56 +7050,85 @@ void Item_SetupKeywordHash( void )
Item_Parse
===============
*/
-qboolean Item_Parse(int handle, itemDef_t *item) {
- pc_token_t token;
- keywordHash_t *key;
+qboolean Item_Parse(int handle, itemDef_t *item)
+{
+ pc_token_t token;
+ keywordHash_t *key;
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
- while ( 1 ) {
- if (!trap_Parse_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu item\n");
- return qfalse;
- }
+ if (*token.string != '{')
+ return qfalse;
- if (*token.string == '}') {
- return qtrue;
- }
+ while (1)
+ {
+ if (!trap_Parse_ReadToken(handle, &token))
+ {
+ PC_SourceError(handle, "end of file inside menu item\n");
+ return qfalse;
+ }
- key = KeywordHash_Find(itemParseKeywordHash, token.string);
- if (!key) {
- PC_SourceError(handle, "unknown menu item keyword %s", token.string);
- continue;
- }
- if ( !key->func(item, handle) ) {
- PC_SourceError(handle, "couldn't parse menu item keyword %s", token.string);
- return qfalse;
+ if (*token.string == '}')
+ return qtrue;
+
+ key = KeywordHash_Find(itemParseKeywordHash, token.string);
+
+ if (!key)
+ {
+ PC_SourceError(handle, "unknown menu item keyword %s", token.string);
+ continue;
+ }
+
+ // do type-checks
+ if (key->param != TYPE_ANY)
+ {
+ itemDataType_t test = Item_DataType(item);
+
+ if (test != key->param)
+ {
+ if (test == TYPE_NONE)
+ PC_SourceError(handle,
+ "menu item keyword %s requires "
+ "type specification",
+ token.string);
+ else
+ PC_SourceError(handle,
+ "menu item keyword %s is incompatible with "
+ "specified item type",
+ token.string);
+ continue;
+ }
+ }
+
+ if (!key->func(item, handle))
+ {
+ PC_SourceError(handle, "couldn't parse menu item keyword %s", token.string);
+ return qfalse;
+ }
}
- }
- return qfalse; // bk001205 - LCC missing return value
-}
+ return qfalse;
+}
// Item_InitControls
// init's special control types
-void Item_InitControls(itemDef_t *item) {
- if (item == NULL) {
- return;
- }
- if (item->type == ITEM_TYPE_LISTBOX) {
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
- item->cursorPos = 0;
- if (listPtr) {
- listPtr->cursorPos = 0;
- listPtr->startPos = 0;
- listPtr->endPos = 0;
- listPtr->cursorPos = 0;
- }
- }
+void Item_InitControls(itemDef_t *item)
+{
+ if (item == NULL)
+ return;
+
+ if (Item_IsListBox(item))
+ {
+ item->cursorPos = 0;
+
+ if (item->typeData.list)
+ {
+ item->typeData.list->cursorPos = 0;
+ Item_ListBox_SetStartPos(item, 0);
+ item->typeData.list->cursorPos = 0;
+ }
+ }
}
/*
@@ -5543,327 +7137,376 @@ Menu Keyword Parse functions
===============
*/
-qboolean MenuParse_font( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_String_Parse(handle, &menu->font)) {
- return qfalse;
- }
- if (!DC->Assets.fontRegistered) {
- DC->registerFont(menu->font, 48, &DC->Assets.textFont);
- DC->Assets.fontRegistered = qtrue;
- }
- return qtrue;
+qboolean MenuParse_font(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (!PC_String_Parse(handle, &menu->font))
+ return qfalse;
+
+ if (!DC->Assets.fontRegistered)
+ {
+ DC->registerFont(menu->font, 48, &DC->Assets.textFont);
+ DC->Assets.fontRegistered = qtrue;
+ }
+
+ return qtrue;
}
-qboolean MenuParse_name( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_String_Parse(handle, &menu->window.name)) {
- return qfalse;
- }
- if (Q_stricmp(menu->window.name, "main") == 0) {
- // default main as having focus
- //menu->window.flags |= WINDOW_HASFOCUS;
- }
- return qtrue;
+qboolean MenuParse_name(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (!PC_String_Parse(handle, &menu->window.name))
+ return qfalse;
+
+ return qtrue;
}
-qboolean MenuParse_fullscreen( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Int_Parse(handle, (int*) &menu->fullScreen)) { // bk001206 - cast qboolean
- return qfalse;
- }
- return qtrue;
+qboolean MenuParse_fullscreen(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (!PC_Int_Parse(handle, (int *)&menu->fullScreen))
+ return qfalse;
+
+ return qtrue;
}
-qboolean MenuParse_rect( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Rect_Parse(handle, &menu->window.rect)) {
- return qfalse;
- }
- return qtrue;
+qboolean MenuParse_rect(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (!PC_Rect_Parse(handle, &menu->window.rect))
+ return qfalse;
+
+ return qtrue;
}
-qboolean MenuParse_style( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Int_Parse(handle, &menu->window.style)) {
- return qfalse;
- }
- return qtrue;
+qboolean MenuParse_aspectBias(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (!PC_Int_Parse(handle, &menu->window.aspectBias))
+ return qfalse;
+
+ return qtrue;
}
-qboolean MenuParse_visible( itemDef_t *item, int handle ) {
- int i;
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_style(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
- if (!PC_Int_Parse(handle, &i)) {
- return qfalse;
- }
- if (i) {
- menu->window.flags |= WINDOW_VISIBLE;
- }
- return qtrue;
+ if (!PC_Int_Parse(handle, &menu->window.style))
+ return qfalse;
+
+ return qtrue;
}
-qboolean MenuParse_onOpen( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Script_Parse(handle, &menu->onOpen)) {
- return qfalse;
- }
- return qtrue;
+qboolean MenuParse_visible(itemDef_t *item, int handle)
+{
+ int i;
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (!PC_Int_Parse(handle, &i))
+ return qfalse;
+
+ if (i)
+ menu->window.flags |= WINDOW_VISIBLE;
+
+ return qtrue;
}
-qboolean MenuParse_onClose( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Script_Parse(handle, &menu->onClose)) {
- return qfalse;
- }
- return qtrue;
+qboolean MenuParse_onOpen(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (!PC_Script_Parse(handle, &menu->onOpen))
+ return qfalse;
+
+ return qtrue;
}
-qboolean MenuParse_onESC( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Script_Parse(handle, &menu->onESC)) {
- return qfalse;
- }
- return qtrue;
+qboolean MenuParse_onClose(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (!PC_Script_Parse(handle, &menu->onClose))
+ return qfalse;
+
+ return qtrue;
}
+qboolean MenuParse_onESC(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+ if (!PC_Script_Parse(handle, &menu->onESC))
+ return qfalse;
-qboolean MenuParse_border( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Int_Parse(handle, &menu->window.border)) {
- return qfalse;
- }
- return qtrue;
+ return qtrue;
}
-qboolean MenuParse_borderSize( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Float_Parse(handle, &menu->window.borderSize)) {
- return qfalse;
- }
- return qtrue;
+qboolean MenuParse_border(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (!PC_Int_Parse(handle, &menu->window.border))
+ return qfalse;
+
+ return qtrue;
}
-qboolean MenuParse_backcolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_borderSize(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (!PC_Float_Parse(handle, &menu->window.borderSize))
+ return qfalse;
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- menu->window.backColor[i] = f;
- }
- return qtrue;
+ return qtrue;
}
-qboolean MenuParse_forecolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_backcolor(itemDef_t *item, int handle)
+{
+ int i;
+ float f;
+ menuDef_t *menu = (menuDef_t *)item;
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
+ for (i = 0; i < 4; i++)
+ {
+ if (!PC_Float_Parse(handle, &f))
+ return qfalse;
+
+ menu->window.backColor[i] = f;
}
- menu->window.foreColor[i] = f;
- menu->window.flags |= WINDOW_FORECOLORSET;
- }
- return qtrue;
+
+ return qtrue;
}
-qboolean MenuParse_bordercolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_forecolor(itemDef_t *item, int handle)
+{
+ int i;
+ float f;
+ menuDef_t *menu = (menuDef_t *)item;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (!PC_Float_Parse(handle, &f))
+ return qfalse;
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
+ menu->window.foreColor[i] = f;
+ menu->window.flags |= WINDOW_FORECOLORSET;
}
- menu->window.borderColor[i] = f;
- }
- return qtrue;
+
+ return qtrue;
}
-qboolean MenuParse_focuscolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_bordercolor(itemDef_t *item, int handle)
+{
+ int i;
+ float f;
+ menuDef_t *menu = (menuDef_t *)item;
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
+ for (i = 0; i < 4; i++)
+ {
+ if (!PC_Float_Parse(handle, &f))
+ return qfalse;
+
+ menu->window.borderColor[i] = f;
}
- menu->focusColor[i] = f;
- }
- return qtrue;
+
+ return qtrue;
}
-qboolean MenuParse_disablecolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
+qboolean MenuParse_focuscolor(itemDef_t *item, int handle)
+{
+ int i;
+ float f;
+ menuDef_t *menu = (menuDef_t *)item;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (!PC_Float_Parse(handle, &f))
+ return qfalse;
+
+ menu->focusColor[i] = f;
}
- menu->disableColor[i] = f;
- }
- return qtrue;
+
+ return qtrue;
}
+qboolean MenuParse_disablecolor(itemDef_t *item, int handle)
+{
+ int i;
+ float f;
+ menuDef_t *menu = (menuDef_t *)item;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (!PC_Float_Parse(handle, &f))
+ return qfalse;
-qboolean MenuParse_outlinecolor( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Color_Parse(handle, &menu->window.outlineColor)){
- return qfalse;
- }
- return qtrue;
+ menu->disableColor[i] = f;
+ }
+
+ return qtrue;
}
-qboolean MenuParse_background( itemDef_t *item, int handle ) {
- const char *buff;
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_outlinecolor(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
- if (!PC_String_Parse(handle, &buff)) {
- return qfalse;
- }
- menu->window.background = DC->registerShaderNoMip(buff);
- return qtrue;
+ if (!PC_Color_Parse(handle, &menu->window.outlineColor))
+ return qfalse;
+
+ return qtrue;
}
-qboolean MenuParse_cinematic( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_background(itemDef_t *item, int handle)
+{
+ const char *buff;
+ menuDef_t *menu = (menuDef_t *)item;
- if (!PC_String_Parse(handle, &menu->window.cinematicName)) {
- return qfalse;
- }
- return qtrue;
+ if (!PC_String_Parse(handle, &buff))
+ return qfalse;
+
+ menu->window.background = DC->registerShaderNoMip(buff);
+ return qtrue;
}
-qboolean MenuParse_ownerdrawFlag( itemDef_t *item, int handle ) {
- int i;
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_cinematic(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
- if (!PC_Int_Parse(handle, &i)) {
- return qfalse;
- }
- menu->window.ownerDrawFlags |= i;
- return qtrue;
+ if (!PC_String_Parse(handle, &menu->window.cinematicName))
+ return qfalse;
+
+ return qtrue;
}
-qboolean MenuParse_ownerdraw( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_ownerdrawFlag(itemDef_t *item, int handle)
+{
+ int i;
+ menuDef_t *menu = (menuDef_t *)item;
- if (!PC_Int_Parse(handle, &menu->window.ownerDraw)) {
- return qfalse;
- }
- return qtrue;
+ if (!PC_Int_Parse(handle, &i))
+ return qfalse;
+
+ menu->window.ownerDrawFlags |= i;
+ return qtrue;
}
+qboolean MenuParse_ownerdraw(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (!PC_Int_Parse(handle, &menu->window.ownerDraw))
+ return qfalse;
+
+ return qtrue;
+}
// decoration
-qboolean MenuParse_popup( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- menu->window.flags |= WINDOW_POPUP;
- return qtrue;
+qboolean MenuParse_popup(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+ menu->window.flags |= WINDOW_POPUP;
+
+ (void)handle;
+
+ return qtrue;
}
+qboolean MenuParse_outOfBounds(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+ menu->window.flags |= WINDOW_OOB_CLICK;
-qboolean MenuParse_outOfBounds( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
+ (void)handle;
- menu->window.flags |= WINDOW_OOB_CLICK;
- return qtrue;
+ return qtrue;
}
-qboolean MenuParse_soundLoop( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_soundLoop(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
- if (!PC_String_Parse(handle, &menu->soundName)) {
- return qfalse;
- }
- return qtrue;
+ if (!PC_String_Parse(handle, &menu->soundName))
+ return qfalse;
+
+ return qtrue;
}
-qboolean MenuParse_fadeClamp( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_fadeClamp(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
- if (!PC_Float_Parse(handle, &menu->fadeClamp)) {
- return qfalse;
- }
- return qtrue;
+ if (!PC_Float_Parse(handle, &menu->fadeClamp))
+ return qfalse;
+
+ return qtrue;
}
-qboolean MenuParse_fadeAmount( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
+qboolean MenuParse_fadeAmount(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
- if (!PC_Float_Parse(handle, &menu->fadeAmount)) {
- return qfalse;
- }
- return qtrue;
+ if (!PC_Float_Parse(handle, &menu->fadeAmount))
+ return qfalse;
+
+ return qtrue;
}
+qboolean MenuParse_fadeCycle(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
-qboolean MenuParse_fadeCycle( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_Int_Parse(handle, &menu->fadeCycle))
+ return qfalse;
- if (!PC_Int_Parse(handle, &menu->fadeCycle)) {
- return qfalse;
- }
- return qtrue;
-}
-
-
-qboolean MenuParse_itemDef( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (menu->itemCount < MAX_MENUITEMS) {
- menu->items[menu->itemCount] = UI_Alloc(sizeof(itemDef_t));
- Item_Init(menu->items[menu->itemCount]);
- if (!Item_Parse(handle, menu->items[menu->itemCount])) {
- return qfalse;
- }
- Item_InitControls(menu->items[menu->itemCount]);
- menu->items[menu->itemCount++]->parent = menu;
- }
- return qtrue;
-}
-
-keywordHash_t menuParseKeywords[] = {
- {"font", MenuParse_font, NULL},
- {"name", MenuParse_name, NULL},
- {"fullscreen", MenuParse_fullscreen, NULL},
- {"rect", MenuParse_rect, NULL},
- {"style", MenuParse_style, NULL},
- {"visible", MenuParse_visible, NULL},
- {"onOpen", MenuParse_onOpen, NULL},
- {"onClose", MenuParse_onClose, NULL},
- {"onESC", MenuParse_onESC, NULL},
- {"border", MenuParse_border, NULL},
- {"borderSize", MenuParse_borderSize, NULL},
- {"backcolor", MenuParse_backcolor, NULL},
- {"forecolor", MenuParse_forecolor, NULL},
- {"bordercolor", MenuParse_bordercolor, NULL},
- {"focuscolor", MenuParse_focuscolor, NULL},
- {"disablecolor", MenuParse_disablecolor, NULL},
- {"outlinecolor", MenuParse_outlinecolor, NULL},
- {"background", MenuParse_background, NULL},
- {"ownerdraw", MenuParse_ownerdraw, NULL},
- {"ownerdrawFlag", MenuParse_ownerdrawFlag, NULL},
- {"outOfBoundsClick", MenuParse_outOfBounds, NULL},
- {"soundLoop", MenuParse_soundLoop, NULL},
- {"itemDef", MenuParse_itemDef, NULL},
- {"cinematic", MenuParse_cinematic, NULL},
- {"popup", MenuParse_popup, NULL},
- {"fadeClamp", MenuParse_fadeClamp, NULL},
- {"fadeCycle", MenuParse_fadeCycle, NULL},
- {"fadeAmount", MenuParse_fadeAmount, NULL},
- {NULL, voidFunction2, NULL}
-};
+ return qtrue;
+}
+
+qboolean MenuParse_itemDef(itemDef_t *item, int handle)
+{
+ menuDef_t *menu = (menuDef_t *)item;
+
+ if (menu->itemCount < MAX_MENUITEMS)
+ {
+ menu->items[menu->itemCount] = UI_Alloc(sizeof(itemDef_t));
+ Item_Init(menu->items[menu->itemCount]);
+
+ if (!Item_Parse(handle, menu->items[menu->itemCount]))
+ return qfalse;
+
+ Item_InitControls(menu->items[menu->itemCount]);
+ menu->items[menu->itemCount++]->parent = menu;
+ }
+ else
+ {
+ PC_SourceError(handle, "itemDefs per menu may not exceed %d", MAX_MENUITEMS);
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+keywordHash_t menuParseKeywords[] = {{"font", MenuParse_font, 0, NULL}, {"name", MenuParse_name, 0, NULL},
+ {"fullscreen", MenuParse_fullscreen, 0, NULL}, {"rect", MenuParse_rect, 0, NULL},
+ {"aspectBias", MenuParse_aspectBias, 0, NULL}, {"style", MenuParse_style, 0, NULL},
+ {"visible", MenuParse_visible, 0, NULL}, {"onOpen", MenuParse_onOpen, 0, NULL},
+ {"onClose", MenuParse_onClose, 0, NULL}, {"onESC", MenuParse_onESC, 0, NULL}, {"border", MenuParse_border, 0, NULL},
+ {"borderSize", MenuParse_borderSize, 0, NULL}, {"backcolor", MenuParse_backcolor, 0, NULL},
+ {"forecolor", MenuParse_forecolor, 0, NULL}, {"bordercolor", MenuParse_bordercolor, 0, NULL},
+ {"focuscolor", MenuParse_focuscolor, 0, NULL}, {"disablecolor", MenuParse_disablecolor, 0, NULL},
+ {"outlinecolor", MenuParse_outlinecolor, 0, NULL}, {"background", MenuParse_background, 0, NULL},
+ {"ownerdraw", MenuParse_ownerdraw, 0, NULL}, {"ownerdrawFlag", MenuParse_ownerdrawFlag, 0, NULL},
+ {"outOfBoundsClick", MenuParse_outOfBounds, 0, NULL}, {"soundLoop", MenuParse_soundLoop, 0, NULL},
+ {"itemDef", MenuParse_itemDef, 0, NULL}, {"cinematic", MenuParse_cinematic, 0, NULL},
+ {"popup", MenuParse_popup, 0, NULL}, {"fadeClamp", MenuParse_fadeClamp, 0, NULL},
+ {"fadeCycle", MenuParse_fadeCycle, 0, NULL}, {"fadeAmount", MenuParse_fadeAmount, 0, NULL},
+ {NULL, voidFunction2, 0, NULL}};
keywordHash_t *menuParseKeywordHash[KEYWORDHASH_SIZE];
@@ -5872,14 +7515,14 @@ keywordHash_t *menuParseKeywordHash[KEYWORDHASH_SIZE];
Menu_SetupKeywordHash
===============
*/
-void Menu_SetupKeywordHash( void )
+void Menu_SetupKeywordHash(void)
{
- int i;
+ int i;
- memset( menuParseKeywordHash, 0, sizeof( menuParseKeywordHash ) );
+ memset(menuParseKeywordHash, 0, sizeof(menuParseKeywordHash));
- for(i = 0; menuParseKeywords[ i ].keyword; i++ )
- KeywordHash_Add( menuParseKeywordHash, &menuParseKeywords[ i ] );
+ for (i = 0; menuParseKeywords[i].keyword; i++)
+ KeywordHash_Add(menuParseKeywordHash, &menuParseKeywords[i]);
}
/*
@@ -5887,39 +7530,46 @@ void Menu_SetupKeywordHash( void )
Menu_Parse
===============
*/
-qboolean Menu_Parse(int handle, menuDef_t *menu) {
- pc_token_t token;
- keywordHash_t *key;
+qboolean Menu_Parse(int handle, menuDef_t *menu)
+{
+ pc_token_t token;
+ keywordHash_t *key;
- if (!trap_Parse_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
+ if (!trap_Parse_ReadToken(handle, &token))
+ return qfalse;
+
+ if (*token.string != '{')
+ return qfalse;
- while ( 1 ) {
+ while (1)
+ {
+ memset(&token, 0, sizeof(pc_token_t));
- memset(&token, 0, sizeof(pc_token_t));
- if (!trap_Parse_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu\n");
- return qfalse;
- }
+ if (!trap_Parse_ReadToken(handle, &token))
+ {
+ PC_SourceError(handle, "end of file inside menu\n");
+ return qfalse;
+ }
- if (*token.string == '}') {
- return qtrue;
- }
+ if (*token.string == '}')
+ return qtrue;
- key = KeywordHash_Find(menuParseKeywordHash, token.string);
- if (!key) {
- PC_SourceError(handle, "unknown menu keyword %s", token.string);
- continue;
- }
- if ( !key->func((itemDef_t*)menu, handle) ) {
- PC_SourceError(handle, "couldn't parse menu keyword %s", token.string);
- return qfalse;
+ key = KeywordHash_Find(menuParseKeywordHash, token.string);
+
+ if (!key)
+ {
+ PC_SourceError(handle, "unknown menu keyword %s", token.string);
+ continue;
+ }
+
+ if (!key->func((itemDef_t *)menu, handle))
+ {
+ PC_SourceError(handle, "couldn't parse menu keyword %s", token.string);
+ return qfalse;
+ }
}
- }
- return qfalse; // bk001205 - LCC missing return value
+
+ return qfalse;
}
/*
@@ -5927,189 +7577,211 @@ qboolean Menu_Parse(int handle, menuDef_t *menu) {
Menu_New
===============
*/
-void Menu_New(int handle) {
- menuDef_t *menu = &Menus[menuCount];
+void Menu_New(int handle)
+{
+ menuDef_t *menu = &Menus[menuCount];
+
+ if (menuCount < MAX_MENUS)
+ {
+ Menu_Init(menu);
- if (menuCount < MAX_MENUS) {
- Menu_Init(menu);
- if (Menu_Parse(handle, menu)) {
- Menu_PostParse(menu);
- menuCount++;
+ if (Menu_Parse(handle, menu))
+ {
+ Menu_PostParse(menu);
+ menuCount++;
+ }
}
- }
}
-int Menu_Count( void ) {
- return menuCount;
+int Menu_Count(void) { return menuCount; }
+
+void Menu_UpdateAll(void)
+{
+ int i;
+
+ for (i = 0; i < openMenuCount; i++)
+ Menu_Update(menuStack[i]);
}
-void Menu_PaintAll( void ) {
- int i;
+void Menu_PaintAll(void)
+{
+ int i;
- if( g_editingField || g_waitingForKey )
- DC->setCVar( "ui_hideCursor", "1" );
- else
- DC->setCVar( "ui_hideCursor", "0" );
+ if (g_editingField || g_waitingForKey)
+ DC->setCVar("ui_hideCursor", "1");
+ else
+ DC->setCVar("ui_hideCursor", "0");
- if (captureFunc) {
- captureFunc(captureData);
- }
+ if (captureFunc != voidFunction)
+ {
+ if (captureFuncExpiry > 0 && DC->realTime > captureFuncExpiry)
+ UI_RemoveCaptureFunc();
+ else
+ captureFunc(captureData);
+ }
- for (i = 0; i < Menu_Count(); i++) {
- Menu_Paint(&Menus[i], qfalse);
- }
+ for (i = 0; i < openMenuCount; i++)
+ Menu_Paint(menuStack[i], qfalse);
- if (debugMode) {
- vec4_t v = {1, 1, 1, 1};
- DC->drawText(5, 25, .5, v, va("fps: %f", DC->FPS), 0, 0, 0);
- }
+ if (DC->getCVarValue("ui_developer"))
+ {
+ vec4_t v = {1, 1, 1, 1};
+ UI_Text_Paint(5, 25, .5, v, va("fps: %f", DC->FPS), 0, 0, 0);
+ }
}
-void Menu_Reset( void )
-{
- menuCount = 0;
-}
+void Menu_Reset(void) { menuCount = 0; }
-displayContextDef_t *Display_GetContext( void ) {
- return DC;
-}
+displayContextDef_t *Display_GetContext(void) { return DC; }
-void *Display_CaptureItem(int x, int y) {
- int i;
+void *Display_CaptureItem(int x, int y)
+{
+ int i;
- for (i = 0; i < menuCount; i++) {
- // turn off focus each item
- // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
- if (Rect_ContainsPoint(&Menus[i].window.rect, x, y)) {
- return &Menus[i];
+ for (i = 0; i < menuCount; i++)
+ {
+ if (Rect_ContainsPoint(&Menus[i].window.rect, x, y))
+ return &Menus[i];
}
- }
- return NULL;
-}
+ return NULL;
+}
// FIXME:
-qboolean Display_MouseMove(void *p, int x, int y) {
- int i;
- menuDef_t *menu = p;
-
- if (menu == NULL) {
- menu = Menu_GetFocused();
- if (menu) {
- if (menu->window.flags & WINDOW_POPUP) {
- Menu_HandleMouseMove(menu, x, y);
- return qtrue;
- }
- }
- for (i = 0; i < menuCount; i++) {
- Menu_HandleMouseMove(&Menus[i], x, y);
- }
- } else {
- menu->window.rect.x += x;
- menu->window.rect.y += y;
- Menu_UpdatePosition(menu);
- }
- return qtrue;
+qboolean Display_MouseMove(void *p, float x, float y)
+{
+ int i;
+ menuDef_t *menu = p;
-}
+ if (menu == NULL)
+ {
+ menu = Menu_GetFocused();
+
+ if (menu)
+ {
+ if (menu->window.flags & WINDOW_POPUP)
+ {
+ Menu_HandleMouseMove(menu, x, y);
+ return qtrue;
+ }
+ }
-int Display_CursorType(int x, int y) {
- int i;
- for (i = 0; i < menuCount; i++) {
- rectDef_t r2;
- r2.x = Menus[i].window.rect.x - 3;
- r2.y = Menus[i].window.rect.y - 3;
- r2.w = r2.h = 7;
- if (Rect_ContainsPoint(&r2, x, y)) {
- return CURSOR_SIZER;
+ for (i = 0; i < menuCount; i++)
+ Menu_HandleMouseMove(&Menus[i], x, y);
+ }
+ else
+ {
+ menu->window.rect.x += x;
+ menu->window.rect.y += y;
+ Menu_UpdatePosition(menu);
}
- }
- return CURSOR_ARROW;
+
+ return qtrue;
}
+int Display_CursorType(int x, int y)
+{
+ int i;
-void Display_HandleKey(int key, qboolean down, int x, int y) {
- menuDef_t *menu = Display_CaptureItem(x, y);
- if (menu == NULL) {
- menu = Menu_GetFocused();
- }
- if (menu) {
- Menu_HandleKey(menu, key, down );
- }
-}
+ for (i = 0; i < menuCount; i++)
+ {
+ rectDef_t r2;
+ r2.x = Menus[i].window.rect.x - 3;
+ r2.y = Menus[i].window.rect.y - 3;
+ r2.w = r2.h = 7;
-static void Window_CacheContents(windowDef_t *window) {
- if (window) {
- if (window->cinematicName) {
- int cin = DC->playCinematic(window->cinematicName, 0, 0, 0, 0);
- DC->stopCinematic(cin);
+ if (Rect_ContainsPoint(&r2, x, y))
+ return CURSOR_SIZER;
}
- }
+
+ return CURSOR_ARROW;
}
+void Display_HandleKey(int key, qboolean down, int x, int y)
+{
+ menuDef_t *menu = Display_CaptureItem(x, y);
-static void Item_CacheContents(itemDef_t *item) {
- if (item) {
- Window_CacheContents(&item->window);
- }
+ if (menu == NULL)
+ menu = Menu_GetFocused();
+ if (menu)
+ Menu_HandleKey(menu, key, down);
}
-static void Menu_CacheContents(menuDef_t *menu) {
- if (menu) {
- int i;
- Window_CacheContents(&menu->window);
- for (i = 0; i < menu->itemCount; i++) {
- Item_CacheContents(menu->items[i]);
- }
-
- if (menu->soundName && *menu->soundName) {
- DC->registerSound(menu->soundName, qfalse);
+static void Window_CacheContents(Window *window)
+{
+ if (window)
+ {
+ if (window->cinematicName)
+ {
+ int cin = DC->playCinematic(window->cinematicName, 0, 0, 0, 0);
+ DC->stopCinematic(cin);
+ }
}
- }
-
}
-void Display_CacheAll( void ) {
- int i;
- for (i = 0; i < menuCount; i++) {
- Menu_CacheContents(&Menus[i]);
- }
+static void Item_CacheContents(itemDef_t *item)
+{
+ if (item)
+ Window_CacheContents(&item->window);
}
+static void Menu_CacheContents(menuDef_t *menu)
+{
+ if (menu)
+ {
+ int i;
+ Window_CacheContents(&menu->window);
-static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y) {
- if (menu && menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)) {
- if (Rect_ContainsPoint(&menu->window.rect, x, y)) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- // turn off focus each item
- // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
+ for (i = 0; i < menu->itemCount; i++)
+ Item_CacheContents(menu->items[i]);
- if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
- continue;
- }
+ if (menu->soundName && *menu->soundName)
+ DC->registerSound(menu->soundName, qfalse);
+ }
+}
- if (menu->items[i]->window.flags & WINDOW_DECORATION) {
- continue;
- }
+void Display_CacheAll(void)
+{
+ int i;
- if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
- itemDef_t *overItem = menu->items[i];
- if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
- if (Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
- return qtrue;
- } else {
- continue;
+ for (i = 0; i < menuCount; i++)
+ Menu_CacheContents(&Menus[i]);
+}
+
+static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y)
+{
+ if (menu && menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))
+ {
+ if (Rect_ContainsPoint(&menu->window.rect, x, y))
+ {
+ int i;
+
+ for (i = 0; i < menu->itemCount; i++)
+ {
+ if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)))
+ continue;
+
+ if (menu->items[i]->window.flags & WINDOW_DECORATION)
+ continue;
+
+ if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y))
+ {
+ itemDef_t *overItem = menu->items[i];
+
+ if (overItem->type == ITEM_TYPE_TEXT && overItem->text)
+ {
+ if (Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y))
+ return qtrue;
+ else
+ continue;
+ }
+ else
+ return qtrue;
+ }
}
- } else {
- return qtrue;
- }
}
- }
-
}
- }
- return qfalse;
-}
+ return qfalse;
+}
diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h
index 210899e..470792c 100644
--- a/src/ui/ui_shared.h
+++ b/src/ui/ui_shared.h
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,20 +17,19 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
#ifndef __UI_SHARED_H
#define __UI_SHARED_H
+#include "client/keycodes.h"
+#include "qcommon/q_shared.h"
+#include "renderercommon/tr_types.h"
-#include "../qcommon/q_shared.h"
-#include "../renderer/tr_types.h"
-#include "../client/keycodes.h"
-
-#include "../ui/menudef.h"
+#include "../../assets/ui/menudef.h"
#define MAX_MENUNAME 32
#define MAX_ITEMTEXT 64
@@ -41,118 +41,128 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define MAX_COLOR_RANGES 10
#define MAX_OPEN_MENUS 16
-#define WINDOW_MOUSEOVER 0x00000001 // mouse is over it, non exclusive
-#define WINDOW_HASFOCUS 0x00000002 // has cursor focus, exclusive
-#define WINDOW_VISIBLE 0x00000004 // is visible
-#define WINDOW_GREY 0x00000008 // is visible but grey ( non-active )
-#define WINDOW_DECORATION 0x00000010 // for decoration only, no mouse, keyboard, etc..
-#define WINDOW_FADINGOUT 0x00000020 // fading out, non-active
-#define WINDOW_FADINGIN 0x00000040 // fading in
-#define WINDOW_MOUSEOVERTEXT 0x00000080 // mouse is over it, non exclusive
-#define WINDOW_INTRANSITION 0x00000100 // window is in transition
-#define WINDOW_FORECOLORSET 0x00000200 // forecolor was explicitly set ( used to color alpha images or not )
-#define WINDOW_HORIZONTAL 0x00000400 // for list boxes and sliders, vertical is default this is set of horizontal
-#define WINDOW_LB_LEFTARROW 0x00000800 // mouse is over left/up arrow
-#define WINDOW_LB_RIGHTARROW 0x00001000 // mouse is over right/down arrow
-#define WINDOW_LB_THUMB 0x00002000 // mouse is over thumb
-#define WINDOW_LB_PGUP 0x00004000 // mouse is over page up
-#define WINDOW_LB_PGDN 0x00008000 // mouse is over page down
-#define WINDOW_ORBITING 0x00010000 // item is in orbit
-#define WINDOW_OOB_CLICK 0x00020000 // close on out of bounds click
-#define WINDOW_WRAPPED 0x00040000 // manually wrap text
-#define WINDOW_AUTOWRAPPED 0x00080000 // auto wrap text
-#define WINDOW_FORCED 0x00100000 // forced open
-#define WINDOW_POPUP 0x00200000 // popup
-#define WINDOW_BACKCOLORSET 0x00400000 // backcolor was explicitly set
-#define WINDOW_TIMEDVISIBLE 0x00800000 // visibility timing ( NOT implemented )
-
+#define WINDOW_MOUSEOVER 0x00000001 // mouse is over it, non exclusive
+#define WINDOW_HASFOCUS 0x00000002 // has cursor focus, exclusive
+#define WINDOW_VISIBLE 0x00000004 // is visible
+#define WINDOW_GREY 0x00000008 // is visible but grey ( non-active )
+#define WINDOW_DECORATION 0x00000010 // for decoration only, no mouse, keyboard, etc..
+#define WINDOW_FADINGOUT 0x00000020 // fading out, non-active
+#define WINDOW_FADINGIN 0x00000040 // fading in
+#define WINDOW_MOUSEOVERTEXT 0x00000080 // mouse is over it, non exclusive
+#define WINDOW_INTRANSITION 0x00000100 // window is in transition
+#define WINDOW_FORECOLORSET 0x00000200 // forecolor was explicitly set ( used to color alpha images or not )
+#define WINDOW_HORIZONTAL 0x00000400 // for list boxes and sliders, vertical is default this is set of horizontal
+#define WINDOW_LB_UPARROW 0x00000800 // mouse is over up arrow
+#define WINDOW_LB_DOWNARROW 0x00001000 // mouse is over down arrow
+#define WINDOW_LB_THUMB 0x00002000 // mouse is over thumb
+#define WINDOW_LB_PGUP 0x00004000 // mouse is over page up
+#define WINDOW_LB_PGDN 0x00008000 // mouse is over page down
+#define WINDOW_ORBITING 0x00010000 // item is in orbit
+#define WINDOW_OOB_CLICK 0x00020000 // close on out of bounds click
+#define WINDOW_WRAPPED 0x00080000 // wrap text
+#define WINDOW_FORCED 0x00100000 // forced open
+#define WINDOW_POPUP 0x00200000 // popup
+#define WINDOW_BACKCOLORSET 0x00400000 // backcolor was explicitly set
+#define WINDOW_TIMEDVISIBLE 0x00800000 // visibility timing ( NOT implemented )
// CGAME cursor type bits
-#define CURSOR_NONE 0x00000001
-#define CURSOR_ARROW 0x00000002
-#define CURSOR_SIZER 0x00000004
+#define CURSOR_NONE 0x00000001
+#define CURSOR_ARROW 0x00000002
+#define CURSOR_SIZER 0x00000004
#ifdef CGAME
-#define STRING_POOL_SIZE 128*1024
+#define STRING_POOL_SIZE 128 * 1024
#else
-#define STRING_POOL_SIZE 384*1024
+#define STRING_POOL_SIZE 384 * 1024
#endif
#define MAX_STRING_HANDLES 4096
#define MAX_SCRIPT_ARGS 12
#define MAX_EDITFIELD 256
+#define ITEM_VALUE_OFFSET 8
-#define ART_FX_BASE "menu/art/fx_base"
-#define ART_FX_BLUE "menu/art/fx_blue"
-#define ART_FX_CYAN "menu/art/fx_cyan"
-#define ART_FX_GREEN "menu/art/fx_grn"
-#define ART_FX_RED "menu/art/fx_red"
-#define ART_FX_TEAL "menu/art/fx_teal"
-#define ART_FX_WHITE "menu/art/fx_white"
-#define ART_FX_YELLOW "menu/art/fx_yel"
+#define ART_FX_BASE "menu/art/fx_base"
+#define ART_FX_BLUE "menu/art/fx_blue"
+#define ART_FX_CYAN "menu/art/fx_cyan"
+#define ART_FX_GREEN "menu/art/fx_grn"
+#define ART_FX_RED "menu/art/fx_red"
+#define ART_FX_TEAL "menu/art/fx_teal"
+#define ART_FX_WHITE "menu/art/fx_white"
+#define ART_FX_YELLOW "menu/art/fx_yel"
#define ASSET_GRADIENTBAR "ui/assets/gradientbar2.tga"
-#define ASSET_SCROLLBAR "ui/assets/scrollbar.tga"
-#define ASSET_SCROLLBAR_ARROWDOWN "ui/assets/scrollbar_arrow_dwn_a.tga"
-#define ASSET_SCROLLBAR_ARROWUP "ui/assets/scrollbar_arrow_up_a.tga"
-#define ASSET_SCROLLBAR_ARROWLEFT "ui/assets/scrollbar_arrow_left.tga"
-#define ASSET_SCROLLBAR_ARROWRIGHT "ui/assets/scrollbar_arrow_right.tga"
-#define ASSET_SCROLL_THUMB "ui/assets/scrollbar_thumb.tga"
-#define ASSET_SLIDER_BAR "ui/assets/slider2.tga"
-#define ASSET_SLIDER_THUMB "ui/assets/sliderbutt_1.tga"
-#define SCROLLBAR_SIZE 16.0
-#define SLIDER_WIDTH 96.0
-#define SLIDER_HEIGHT 16.0
-#define SLIDER_THUMB_WIDTH 12.0
-#define SLIDER_THUMB_HEIGHT 20.0
-#define NUM_CROSSHAIRS 10
+#define ASSET_SCROLLBAR "ui/assets/scrollbar.tga"
+#define ASSET_SCROLLBAR_ARROWDOWN "ui/assets/scrollbar_arrow_dwn_a.tga"
+#define ASSET_SCROLLBAR_ARROWUP "ui/assets/scrollbar_arrow_up_a.tga"
+#define ASSET_SCROLLBAR_ARROWLEFT "ui/assets/scrollbar_arrow_left.tga"
+#define ASSET_SCROLLBAR_ARROWRIGHT "ui/assets/scrollbar_arrow_right.tga"
+#define ASSET_SCROLL_THUMB "ui/assets/scrollbar_thumb.tga"
+#define ASSET_SLIDER_BAR "ui/assets/slider2.tga"
+#define ASSET_SLIDER_THUMB "ui/assets/sliderbutt_1.tga"
+
+#define SCROLLBAR_ARROW_SIZE 16.0f
+#define SCROLLBAR_ARROW_WIDTH (SCROLLBAR_ARROW_SIZE * DC->aspectScale)
+#define SCROLLBAR_ARROW_HEIGHT SCROLLBAR_ARROW_SIZE
+#define SCROLLBAR_SLIDER_X(_item) \
+ (_item->window.rect.x + _item->window.rect.w - SCROLLBAR_ARROW_WIDTH - DC->aspectScale)
+#define SCROLLBAR_SLIDER_Y(_item) (SCROLLBAR_Y(_item) + SCROLLBAR_ARROW_HEIGHT)
+#define SCROLLBAR_SLIDER_HEIGHT(_item) (_item->window.rect.h - (SCROLLBAR_ARROW_HEIGHT * 2.0f) - 2.0f)
+#define SCROLLBAR_X(_item) (_item->window.rect.x + DC->aspectScale)
+#define SCROLLBAR_Y(_item) (_item->window.rect.y + 1.0f)
+#define SCROLLBAR_W(_item) (SCROLLBAR_SLIDER_X(_item) - SCROLLBAR_X(_item))
+#define SCROLLBAR_H(_item) (_item->window.rect.h - 2.0f)
+
+#define SLIDER_WIDTH (96.0f * DC->aspectScale)
+#define SLIDER_HEIGHT 16.0f
+#define SLIDER_THUMB_WIDTH (12.0f * DC->aspectScale)
+#define SLIDER_THUMB_HEIGHT 20.0f
+#define NUM_CROSSHAIRS 10
typedef struct {
- const char *command;
- const char *args[MAX_SCRIPT_ARGS];
+ const char *command;
+ const char *args[MAX_SCRIPT_ARGS];
} scriptDef_t;
-
typedef struct {
- float x; // horiz position
- float y; // vert position
- float w; // width
- float h; // height;
+ float x; // horiz position
+ float y; // vert position
+ float w; // width
+ float h; // height;
} rectDef_t;
typedef rectDef_t Rectangle;
// FIXME: do something to separate text vs window stuff
+
typedef struct {
- Rectangle rect; // client coord rectangle
- Rectangle rectClient; // screen coord rectangle
- const char *name; //
- const char *group; // if it belongs to a group
- const char *cinematicName; // cinematic name
- int cinematic; // cinematic handle
- int style; //
- int border; //
- int ownerDraw; // ownerDraw style
- int ownerDrawFlags; // show flags for ownerdraw items
- float borderSize; //
- int flags; // visible, focus, mouseover, cursor
- Rectangle rectEffects; // for various effects
- Rectangle rectEffects2; // for various effects
- int offsetTime; // time based value for various effects
- int nextTime; // time next effect should cycle
- vec4_t foreColor; // text color
- vec4_t backColor; // border color
- vec4_t borderColor; // border color
- vec4_t outlineColor; // border color
- qhandle_t background; // background asset
-} windowDef_t;
-
-typedef windowDef_t Window;
+ Rectangle rect; // client coord rectangle
+ int aspectBias; // direction in which to aspect compensate
+ Rectangle rectClient; // screen coord rectangle
+ const char *name; //
+ const char *group; // if it belongs to a group
+ const char *cinematicName; // cinematic name
+ int cinematic; // cinematic handle
+ int style; //
+ int border; //
+ int ownerDraw; // ownerDraw style
+ int ownerDrawFlags; // show flags for ownerdraw items
+ float borderSize; //
+ int flags; // visible, focus, mouseover, cursor
+ Rectangle rectEffects; // for various effects
+ Rectangle rectEffects2; // for various effects
+ int offsetTime; // time based value for various effects
+ int nextTime; // time next effect should cycle
+ vec4_t foreColor; // text color
+ vec4_t backColor; // border color
+ vec4_t borderColor; // border color
+ vec4_t outlineColor; // border color
+ qhandle_t background; // background asset
+} Window;
typedef struct {
- vec4_t color;
- float low;
- float high;
+ vec4_t color;
+ float low;
+ float high;
} colorRangeDef_t;
// FIXME: combine flags into bitfields to save space
@@ -168,231 +178,259 @@ typedef struct {
#define MAX_LB_COLUMNS 16
typedef struct columnInfo_s {
- int pos;
- int width;
- int maxChars;
- int align;
+ int pos;
+ int width;
+ int align;
} columnInfo_t;
typedef struct listBoxDef_s {
- int startPos;
- int endPos;
- int drawPadding;
- int cursorPos;
- float elementWidth;
- float elementHeight;
- int elementStyle;
- int numColumns;
- columnInfo_t columnInfo[MAX_LB_COLUMNS];
- const char *doubleClick;
- qboolean notselectable;
+ int startPos;
+ int endPos;
+ int cursorPos;
+
+ float elementWidth;
+ float elementHeight;
+ int elementStyle;
+ int dropItems;
+
+ int numColumns;
+ columnInfo_t columnInfo[MAX_LB_COLUMNS];
+
+ const char *doubleClick;
+
+ qboolean notselectable;
+ qboolean noscrollbar;
+
+ qboolean resetonfeederchange;
+ int lastFeederCount;
} listBoxDef_t;
+typedef struct cycleDef_s {
+ int cursorPos;
+} cycleDef_t;
+
typedef struct editFieldDef_s {
- float minVal; // edit field limits
- float maxVal; //
- float defVal; //
- float range; //
- int maxChars; // for edit fields
- int maxPaintChars; // for edit fields
- int paintOffset; //
+ float minVal; // edit field limits
+ float maxVal; //
+ float defVal; //
+ float range; //
+ int maxChars; // for edit fields
+ int maxPaintChars; // for edit fields
+ int maxFieldWidth; // for edit fields
+ int paintOffset; //
} editFieldDef_t;
#define MAX_MULTI_CVARS 32
typedef struct multiDef_s {
- const char *cvarList[MAX_MULTI_CVARS];
- const char *cvarStr[MAX_MULTI_CVARS];
- float cvarValue[MAX_MULTI_CVARS];
- int count;
- qboolean strDef;
+ const char *cvarList[MAX_MULTI_CVARS];
+ const char *cvarStr[MAX_MULTI_CVARS];
+ float cvarValue[MAX_MULTI_CVARS];
+ int count;
+ qboolean strDef;
} multiDef_t;
typedef struct modelDef_s {
- int angle;
- vec3_t origin;
- float fov_x;
- float fov_y;
- int rotationSpeed;
+ int angle;
+ vec3_t origin;
+ float fov_x;
+ float fov_y;
+ int rotationSpeed;
} modelDef_t;
-#define CVAR_ENABLE 0x00000001
-#define CVAR_DISABLE 0x00000002
-#define CVAR_SHOW 0x00000004
-#define CVAR_HIDE 0x00000008
+#define CVAR_ENABLE 0x00000001
+#define CVAR_DISABLE 0x00000002
+#define CVAR_SHOW 0x00000004
+#define CVAR_HIDE 0x00000008
+
+typedef enum { TYPE_ANY = -1, TYPE_NONE, TYPE_LIST, TYPE_EDIT, TYPE_MULTI, TYPE_COMBO, TYPE_MODEL } itemDataType_t;
typedef struct itemDef_s {
- Window window; // common positional, border, style, layout info
- Rectangle textRect; // rectangle the text ( if any ) consumes
- int type; // text, button, radiobutton, checkbox, textfield, listbox, combo
- int alignment; // left center right
- int textalignment; // ( optional ) alignment for text within rect based on text width
- float textalignx; // ( optional ) text alignment x coord
- float textaligny; // ( optional ) text alignment x coord
- float textscale; // scale percentage from 72pts
- int textStyle; // ( optional ) style, normal and shadowed are it for now
- const char *text; // display text
- void *parent; // menu owner
- qhandle_t asset; // handle to asset
- const char *mouseEnterText; // mouse enter script
- const char *mouseExitText; // mouse exit script
- const char *mouseEnter; // mouse enter script
- const char *mouseExit; // mouse exit script
- const char *action; // select script
- const char *onFocus; // select script
- const char *leaveFocus; // select script
- const char *onTextEntry; // called when text entered
- const char *cvar; // associated cvar
- const char *cvarTest; // associated cvar for enable actions
- const char *enableCvar; // enable, disable, show, or hide based on value, this can contain a list
- int cvarFlags; // what type of action to take on cvarenables
- sfxHandle_t focusSound;
- int numColors; // number of color ranges
- colorRangeDef_t colorRanges[MAX_COLOR_RANGES];
- float special; // used for feeder id's etc.. diff per type
- int cursorPos; // cursor position in characters
- void *typeData; // type specific data ptr's
+ Window window; // common positional, border, style, layout info
+ Rectangle textRect; // rectangle the text ( if any ) consumes
+ int type; // text, button, radiobutton, checkbox, textfield, listbox, combo
+ int alignment; // left center right
+ int textalignment; // ( optional ) alignment for text within rect based on text width
+ int textvalignment; // ( optional ) alignment for text within rect based on text width
+ float textalignx; // ( optional ) text alignment x coord
+ float textaligny; // ( optional ) text alignment x coord
+ float textscale; // scale percentage from 72pts
+ int textStyle; // ( optional ) style, normal and shadowed are it for now
+ const char *text; // display text
+ void *parent; // menu owner
+ qhandle_t asset; // handle to asset
+ const char *mouseEnterText; // mouse enter script
+ const char *mouseExitText; // mouse exit script
+ const char *mouseEnter; // mouse enter script
+ const char *mouseExit; // mouse exit script
+ const char *action; // select script
+ const char *onFocus; // select script
+ const char *leaveFocus; // select script
+ const char *onTextEntry; // called when text entered
+ const char *onCharEntry; // called when text entered
+ const char *cvar; // associated cvar
+ const char *cvarTest; // associated cvar for enable actions
+ const char *enableCvar; // enable, disable, show, or hide based on value, this can contain a list
+ int cvarFlags; // what type of action to take on cvarenables
+ sfxHandle_t focusSound;
+ int numColors; // number of color ranges
+ colorRangeDef_t colorRanges[MAX_COLOR_RANGES];
+ int feederID; // where to get data for this item
+ int cursorPos; // cursor position in characters
+ union {
+ void *data;
+ listBoxDef_t *list;
+ editFieldDef_t *edit;
+ multiDef_t *multi;
+ cycleDef_t *cycle;
+ modelDef_t *model;
+ } typeData; // type specific data pointers
} itemDef_t;
typedef struct {
- Window window;
- const char *font; // font
- qboolean fullScreen; // covers entire screen
- int itemCount; // number of items;
- int fontIndex; //
- int cursorItem; // which item as the cursor
- int fadeCycle; //
- float fadeClamp; //
- float fadeAmount; //
- const char *onOpen; // run when the menu is first opened
- const char *onClose; // run when the menu is closed
- const char *onESC; // run when the menu is closed
- const char *soundName; // background loop sound for menu
-
- vec4_t focusColor; // focus color for items
- vec4_t disableColor; // focus color for items
- itemDef_t *items[MAX_MENUITEMS]; // items this menu contains
+ Window window;
+ const char *font; // font
+ qboolean fullScreen; // covers entire screen
+ int itemCount; // number of items;
+ int fontIndex; //
+ int cursorItem; // which item as the cursor
+ int fadeCycle; //
+ float fadeClamp; //
+ float fadeAmount; //
+ const char *onOpen; // run when the menu is first opened
+ const char *onClose; // run when the menu is closed
+ const char *onESC; // run when the menu is closed
+ const char *soundName; // background loop sound for menu
+
+ vec4_t focusColor; // focus color for items
+ vec4_t disableColor; // focus color for items
+ itemDef_t *items[MAX_MENUITEMS]; // items this menu contains
} menuDef_t;
typedef struct {
- const char *fontStr;
- const char *cursorStr;
- const char *gradientStr;
- fontInfo_t textFont;
- fontInfo_t smallFont;
- fontInfo_t bigFont;
- qhandle_t cursor;
- qhandle_t gradientBar;
- qhandle_t scrollBarArrowUp;
- qhandle_t scrollBarArrowDown;
- qhandle_t scrollBarArrowLeft;
- qhandle_t scrollBarArrowRight;
- qhandle_t scrollBar;
- qhandle_t scrollBarThumb;
- qhandle_t buttonMiddle;
- qhandle_t buttonInside;
- qhandle_t solidBox;
- qhandle_t sliderBar;
- qhandle_t sliderThumb;
- sfxHandle_t menuEnterSound;
- sfxHandle_t menuExitSound;
- sfxHandle_t menuBuzzSound;
- sfxHandle_t itemFocusSound;
- float fadeClamp;
- int fadeCycle;
- float fadeAmount;
- float shadowX;
- float shadowY;
- vec4_t shadowColor;
- float shadowFadeClamp;
- qboolean fontRegistered;
-
+ const char *fontStr;
+ const char *cursorStr;
+ const char *gradientStr;
+ fontInfo_t textFont;
+ fontInfo_t smallFont;
+ fontInfo_t bigFont;
+ qhandle_t cursor;
+ qhandle_t gradientBar;
+ qhandle_t scrollBarArrowUp;
+ qhandle_t scrollBarArrowDown;
+ qhandle_t scrollBarArrowLeft;
+ qhandle_t scrollBarArrowRight;
+ qhandle_t scrollBar;
+ qhandle_t scrollBarThumb;
+ qhandle_t buttonMiddle;
+ qhandle_t buttonInside;
+ qhandle_t solidBox;
+ qhandle_t sliderBar;
+ qhandle_t sliderThumb;
+ sfxHandle_t menuEnterSound;
+ sfxHandle_t menuExitSound;
+ sfxHandle_t menuBuzzSound;
+ sfxHandle_t itemFocusSound;
+ float fadeClamp;
+ int fadeCycle;
+ float fadeAmount;
+ float shadowX;
+ float shadowY;
+ vec4_t shadowColor;
+ float shadowFadeClamp;
+ qboolean fontRegistered;
+ emoticon_t emoticons[MAX_EMOTICONS];
+ int emoticonCount;
} cachedAssets_t;
typedef struct {
- const char *name;
- void (*handler) (itemDef_t *item, char** args);
+ const char *name;
+ void (*handler)(itemDef_t *item, char **args);
} commandDef_t;
typedef struct {
- qhandle_t (*registerShaderNoMip) (const char *p);
- void (*setColor) (const vec4_t v);
- void (*drawHandlePic) (float x, float y, float w, float h, qhandle_t asset);
- void (*drawStretchPic) (float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
- void (*drawText) (float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style );
- int (*textWidth) (const char *text, float scale, int limit);
- int (*textHeight) (const char *text, float scale, int limit);
- qhandle_t (*registerModel) (const char *p);
- void (*modelBounds) (qhandle_t model, vec3_t min, vec3_t max);
- void (*fillRect) ( float x, float y, float w, float h, const vec4_t color);
- void (*drawRect) ( float x, float y, float w, float h, float size, const vec4_t color);
- void (*drawSides) (float x, float y, float w, float h, float size);
- void (*drawTopBottom) (float x, float y, float w, float h, float size);
- void (*clearScene) (void);
- void (*addRefEntityToScene) (const refEntity_t *re );
- void (*renderScene) ( const refdef_t *fd );
- void (*registerFont) (const char *pFontname, int pointSize, fontInfo_t *font);
- void (*ownerDrawItem) (float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle);
- float (*getValue) (int ownerDraw);
- qboolean (*ownerDrawVisible) (int flags);
- void (*runScript)(char **p);
- void (*getTeamColor)(vec4_t *color);
- void (*getCVarString)(const char *cvar, char *buffer, int bufsize);
- float (*getCVarValue)(const char *cvar);
- void (*setCVar)(const char *cvar, const char *value);
- void (*drawTextWithCursor)(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style);
- void (*setOverstrikeMode)(qboolean b);
- qboolean (*getOverstrikeMode)( void );
- void (*startLocalSound)( sfxHandle_t sfx, int channelNum );
- qboolean (*ownerDrawHandleKey)(int ownerDraw, int flags, float *special, int key);
- int (*feederCount)(float feederID);
- const char *(*feederItemText)(float feederID, int index, int column, qhandle_t *handle);
- qhandle_t (*feederItemImage)(float feederID, int index);
- void (*feederSelection)(float feederID, int index);
- void (*keynumToStringBuf)( int keynum, char *buf, int buflen );
- void (*getBindingBuf)( int keynum, char *buf, int buflen );
- void (*setBinding)( int keynum, const char *binding );
- void (*executeText)(int exec_when, const char *text );
- void (*Error)(int level, const char *error, ...);
- void (*Print)(const char *msg, ...);
- void (*Pause)(qboolean b);
- int (*ownerDrawWidth)(int ownerDraw, float scale);
- sfxHandle_t (*registerSound)(const char *name, qboolean compressed);
- void (*startBackgroundTrack)( const char *intro, const char *loop);
- void (*stopBackgroundTrack)( void );
- int (*playCinematic)(const char *name, float x, float y, float w, float h);
- void (*stopCinematic)(int handle);
- void (*drawCinematic)(int handle, float x, float y, float w, float h);
- void (*runCinematicFrame)(int handle);
-
- float yscale;
- float xscale;
- float bias;
- int realTime;
- int frameTime;
- int cursorx;
- int cursory;
- qboolean debug;
-
- cachedAssets_t Assets;
-
- glconfig_t glconfig;
- qhandle_t whiteShader;
- qhandle_t gradientImage;
- qhandle_t cursor;
- float FPS;
+ qhandle_t (*registerShaderNoMip)(const char *p);
+ void (*setColor)(const vec4_t v);
+ void (*drawHandlePic)(float x, float y, float w, float h, qhandle_t asset);
+ void (*drawStretchPic)(
+ float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader);
+ qhandle_t (*registerModel)(const char *p);
+ void (*modelBounds)(qhandle_t model, vec3_t min, vec3_t max);
+ void (*fillRect)(float x, float y, float w, float h, const vec4_t color);
+ void (*drawRect)(float x, float y, float w, float h, float size, const vec4_t color);
+ void (*drawSides)(float x, float y, float w, float h, float size);
+ void (*drawTopBottom)(float x, float y, float w, float h, float size);
+ void (*clearScene)(void);
+ void (*addRefEntityToScene)(const refEntity_t *re);
+ void (*renderScene)(const refdef_t *fd);
+ void (*registerFont)(const char *pFontname, int pointSize, fontInfo_t *font);
+ void (*ownerDrawItem)(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw,
+ int ownerDrawFlags, int align, int textalign, int textvalign, float borderSize, float scale, vec4_t foreColor,
+ vec4_t backColor, qhandle_t shader, int textStyle);
+ float (*getValue)(int ownerDraw);
+ qboolean (*ownerDrawVisible)(int flags);
+ void (*runScript)(char **p);
+ void (*getCVarString)(const char *cvar, char *buffer, int bufsize);
+ float (*getCVarValue)(const char *cvar);
+ void (*setCVar)(const char *cvar, const char *value);
+ void (*drawTextWithCursor)(float x, float y, float scale, vec4_t color, const char *text, int cursorPos,
+ char cursor, int limit, int style);
+ void (*setOverstrikeMode)(qboolean b);
+ qboolean (*getOverstrikeMode)(void);
+ void (*startLocalSound)(sfxHandle_t sfx, int channelNum);
+ qboolean (*ownerDrawHandleKey)(int ownerDraw, int key);
+ int (*feederCount)(int feederID);
+ const char *(*feederItemText)(int feederID, int index, int column, qhandle_t *handle);
+ qhandle_t (*feederItemImage)(int feederID, int index);
+ void (*feederSelection)(int feederID, int index);
+ int (*feederInitialise)(int feederID);
+ void (*keynumToStringBuf)(int keynum, char *buf, int buflen);
+ void (*getBindingBuf)(int keynum, char *buf, int buflen);
+ void (*setBinding)(int keynum, const char *binding);
+ void (*executeText)(int exec_when, const char *text);
+ void (*Error)(int level, const char *error, ...) __attribute__((noreturn, format(printf, 2, 3)));
+ void (*Print)(const char *msg, ...) __attribute__((format(printf, 1, 2)));
+ void (*Pause)(qboolean b);
+ int (*ownerDrawWidth)(int ownerDraw, float scale);
+ const char *(*ownerDrawText)(int ownerDraw);
+ sfxHandle_t (*registerSound)(const char *name, qboolean compressed);
+ void (*startBackgroundTrack)(const char *intro, const char *loop);
+ void (*stopBackgroundTrack)(void);
+ int (*playCinematic)(const char *name, float x, float y, float w, float h);
+ void (*stopCinematic)(int handle);
+ void (*drawCinematic)(int handle, float x, float y, float w, float h);
+ void (*runCinematicFrame)(int handle);
+
+ float yscale;
+ float xscale;
+ float aspectScale;
+ int realTime;
+ int frameTime;
+ float cursorx;
+ float cursory;
+ float smallFontScale;
+ float bigFontScale;
+ qboolean debug;
+
+ cachedAssets_t Assets;
+
+ glconfig_t glconfig;
+ qhandle_t whiteShader;
+ qhandle_t gradientImage;
+ qhandle_t cursor;
+ float FPS;
} displayContextDef_t;
const char *String_Alloc(const char *p);
-void String_Init( void );
-void String_Report( void );
+void String_Init(void);
+void String_Report(void);
void Init_Display(displayContextDef_t *dc);
-void Display_ExpandMacros(char * buff);
+void Display_ExpandMacros(char *buff);
void Menu_Init(menuDef_t *menu);
void Item_Init(itemDef_t *item);
void Menu_PostParse(menuDef_t *menu);
-menuDef_t *Menu_GetFocused( void );
+menuDef_t *Menu_GetFocused(void);
void Menu_HandleKey(menuDef_t *menu, int key, qboolean down);
void Menu_HandleMouseMove(menuDef_t *menu, float x, float y);
void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down);
@@ -408,48 +446,69 @@ qboolean PC_Int_Parse(int handle, int *i);
qboolean PC_Rect_Parse(int handle, rectDef_t *r);
qboolean PC_String_Parse(int handle, const char **out);
qboolean PC_Script_Parse(int handle, const char **out);
-int Menu_Count( void );
+int Menu_Count(void);
void Menu_New(int handle);
-void Menu_PaintAll( void );
+void Menu_UpdateAll(void);
+void Menu_PaintAll(void);
menuDef_t *Menus_ActivateByName(const char *p);
-void Menu_Reset( void );
-qboolean Menus_AnyFullScreenVisible( void );
-void Menus_Activate(menuDef_t *menu);
+menuDef_t *Menus_ReplaceActiveByName(const char *p);
+void Menu_Reset(void);
+qboolean Menus_AnyFullScreenVisible(void);
+void Menus_Activate(menuDef_t *menu);
+qboolean Menus_ReplaceActive(menuDef_t *menu);
-displayContextDef_t *Display_GetContext( void );
+displayContextDef_t *Display_GetContext(void);
void *Display_CaptureItem(int x, int y);
-qboolean Display_MouseMove(void *p, int x, int y);
+qboolean Display_MouseMove(void *p, float x, float y);
int Display_CursorType(int x, int y);
-qboolean Display_KeyBindPending( void );
-void Menus_OpenByName(const char *p);
+qboolean Display_KeyBindPending(void);
menuDef_t *Menus_FindByName(const char *p);
-void Menus_ShowByName(const char *p);
void Menus_CloseByName(const char *p);
void Display_HandleKey(int key, qboolean down, int x, int y);
void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);
-void Menus_CloseAll( void );
+void Menus_CloseAll(void);
+void Menu_Update(menuDef_t *menu);
void Menu_Paint(menuDef_t *menu, qboolean forcePaint);
void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name);
-void Display_CacheAll( void );
-
-void *UI_Alloc( int size );
-void UI_InitMemory( void );
-qboolean UI_OutOfMemory( void );
+void Display_CacheAll(void);
-void Controls_GetConfig( void );
-void Controls_SetConfig(qboolean restart);
-void Controls_SetDefaults( void );
+typedef void(CaptureFunc)(void *p);
-//for cg_draw.c
-void Item_Text_AutoWrapped_Paint( itemDef_t *item );
+void UI_InstallCaptureFunc(CaptureFunc *f, void *data, int timeout);
+void UI_RemoveCaptureFunc(void);
-int trap_Parse_AddGlobalDefine( char *define );
-int trap_Parse_LoadSource( const char *filename );
-int trap_Parse_FreeSource( int handle );
-int trap_Parse_ReadToken( int handle, pc_token_t *pc_token );
-int trap_Parse_SourceFileAndLine( int handle, char *filename, int *line );
+void *UI_Alloc(int size);
+void UI_InitMemory(void);
+qboolean UI_OutOfMemory(void);
-void BindingFromName( const char *cvar );
-extern char g_nameBind1[ 32 ];
-extern char g_nameBind2[ 32 ];
+void Controls_GetConfig(void);
+void Controls_SetConfig(qboolean restart);
+void Controls_SetDefaults(void);
+
+void trap_R_SetClipRegion(const float *region);
+
+// for cg_draw.c
+void Item_Text_Wrapped_Paint(itemDef_t *item);
+const char *Item_Text_Wrap(const char *text, float scale, float width);
+void UI_DrawTextBlock(rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int textalign,
+ int textvalign, int textStyle, const char *text);
+void UI_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style);
+void UI_Text_Paint_Limit(
+ float *maxX, float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit);
+float UI_Text_Width(const char *text, float scale);
+float UI_Text_Height(const char *text, float scale);
+float UI_Text_EmWidth(float scale);
+float UI_Text_EmHeight(float scale);
+qboolean UI_Text_IsEmoticon(const char *s, qboolean *escaped, int *length, qhandle_t *h, int *width);
+void UI_EscapeEmoticons(char *dest, const char *src, int destsize);
+
+int trap_Parse_AddGlobalDefine(char *define);
+int trap_Parse_LoadSource(const char *filename);
+int trap_Parse_FreeSource(int handle);
+int trap_Parse_ReadToken(int handle, pc_token_t *pc_token);
+int trap_Parse_SourceFileAndLine(int handle, char *filename, int *line);
+
+void BindingFromName(const char *cvar);
+extern char g_nameBind1[32];
+extern char g_nameBind2[32];
#endif
diff --git a/src/ui/ui_syscalls.asm b/src/ui/ui_syscalls.asm
index 1e797a9..b566800 100644
--- a/src/ui/ui_syscalls.asm
+++ b/src/ui/ui_syscalls.asm
@@ -42,7 +42,7 @@ equ trap_Key_GetOverstrikeMode -39
equ trap_Key_SetOverstrikeMode -40
equ trap_Key_ClearStates -41
equ trap_Key_GetCatcher -42
-equ trap_Key_SetCatcher -43
+equ trap_Key_SetCatcher -43
equ trap_GetClipboardData -44
equ trap_GetGlconfig -45
equ trap_GetClientState -46
@@ -99,4 +99,3 @@ equ atan2 -106
equ sqrt -107
equ floor -108
equ ceil -109
-
diff --git a/src/ui/ui_syscalls.c b/src/ui/ui_syscalls.c
index a27e573..11bd93a 100644
--- a/src/ui/ui_syscalls.c
+++ b/src/ui/ui_syscalls.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -26,362 +27,284 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// this file is only included when building a dll
// syscalls.asm is included instead when building a qvm
-static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;
+static intptr_t(QDECL *syscall)(intptr_t arg, ...) = (intptr_t(QDECL *)(intptr_t, ...)) - 1;
-Q_EXPORT void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) {
- syscall = syscallptr;
-}
+Q_EXPORT void dllEntry(intptr_t(QDECL *syscallptr)(intptr_t arg, ...)) { syscall = syscallptr; }
-int PASSFLOAT( float x ) {
- float floatTemp;
- floatTemp = x;
- return *(int *)&floatTemp;
+int PASSFLOAT(float x)
+{
+ floatint_t fi;
+ fi.f = x;
+ return fi.i;
}
-void trap_Print( const char *string ) {
- syscall( UI_PRINT, string );
-}
+void trap_Print(const char *string) { syscall(UI_PRINT, string); }
-void trap_Error( const char *string ) {
- syscall( UI_ERROR, string );
+void trap_Error(const char *string)
+{
+ syscall(UI_ERROR, string);
+ // shut up GCC warning about returning functions, because we know better
+ exit(1);
}
-int trap_Milliseconds( void ) {
- return syscall( UI_MILLISECONDS );
-}
+int trap_Milliseconds(void) { return syscall(UI_MILLISECONDS); }
-void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags ) {
- syscall( UI_CVAR_REGISTER, cvar, var_name, value, flags );
+void trap_Cvar_Register(vmCvar_t *cvar, const char *var_name, const char *value, int flags)
+{
+ syscall(UI_CVAR_REGISTER, cvar, var_name, value, flags);
}
-void trap_Cvar_Update( vmCvar_t *cvar ) {
- syscall( UI_CVAR_UPDATE, cvar );
-}
+void trap_Cvar_Update(vmCvar_t *cvar) { syscall(UI_CVAR_UPDATE, cvar); }
-void trap_Cvar_Set( const char *var_name, const char *value ) {
- syscall( UI_CVAR_SET, var_name, value );
-}
+void trap_Cvar_Set(const char *var_name, const char *value) { syscall(UI_CVAR_SET, var_name, value); }
-float trap_Cvar_VariableValue( const char *var_name ) {
- int temp;
- temp = syscall( UI_CVAR_VARIABLEVALUE, var_name );
- return (*(float*)&temp);
+float trap_Cvar_VariableValue(const char *var_name)
+{
+ floatint_t fi;
+ fi.i = syscall(UI_CVAR_VARIABLEVALUE, var_name);
+ return fi.f;
}
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
- syscall( UI_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize );
+void trap_Cvar_VariableStringBuffer(const char *var_name, char *buffer, int bufsize)
+{
+ syscall(UI_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize);
}
-void trap_Cvar_SetValue( const char *var_name, float value ) {
- syscall( UI_CVAR_SETVALUE, var_name, PASSFLOAT( value ) );
-}
+void trap_Cvar_SetValue(const char *var_name, float value) { syscall(UI_CVAR_SETVALUE, var_name, PASSFLOAT(value)); }
-void trap_Cvar_Reset( const char *name ) {
- syscall( UI_CVAR_RESET, name );
-}
+void trap_Cvar_Reset(const char *name) { syscall(UI_CVAR_RESET, name); }
-void trap_Cvar_Create( const char *var_name, const char *var_value, int flags ) {
- syscall( UI_CVAR_CREATE, var_name, var_value, flags );
+void trap_Cvar_Create(const char *var_name, const char *var_value, int flags)
+{
+ syscall(UI_CVAR_CREATE, var_name, var_value, flags);
}
-void trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize ) {
- syscall( UI_CVAR_INFOSTRINGBUFFER, bit, buffer, bufsize );
+void trap_Cvar_InfoStringBuffer(int bit, char *buffer, int bufsize)
+{
+ syscall(UI_CVAR_INFOSTRINGBUFFER, bit, buffer, bufsize);
}
-int trap_Argc( void ) {
- return syscall( UI_ARGC );
-}
+int trap_Argc(void) { return syscall(UI_ARGC); }
-void trap_Argv( int n, char *buffer, int bufferLength ) {
- syscall( UI_ARGV, n, buffer, bufferLength );
-}
+void trap_Argv(int n, char *buffer, int bufferLength) { syscall(UI_ARGV, n, buffer, bufferLength); }
-void trap_Cmd_ExecuteText( int exec_when, const char *text ) {
- syscall( UI_CMD_EXECUTETEXT, exec_when, text );
-}
+void trap_Cmd_ExecuteText(int exec_when, const char *text) { syscall(UI_CMD_EXECUTETEXT, exec_when, text); }
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
- return syscall( UI_FS_FOPENFILE, qpath, f, mode );
+int trap_FS_FOpenFile(const char *qpath, fileHandle_t *f, enum FS_Mode mode)
+{
+ return syscall(UI_FS_FOPENFILE, qpath, f, mode);
}
-void trap_FS_Read( void *buffer, int len, fileHandle_t f ) {
- syscall( UI_FS_READ, buffer, len, f );
-}
+void trap_FS_Read(void *buffer, int len, fileHandle_t f) { syscall(UI_FS_READ, buffer, len, f); }
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {
- syscall( UI_FS_WRITE, buffer, len, f );
-}
+void trap_FS_Write(const void *buffer, int len, fileHandle_t f) { syscall(UI_FS_WRITE, buffer, len, f); }
-void trap_FS_FCloseFile( fileHandle_t f ) {
- syscall( UI_FS_FCLOSEFILE, f );
-}
+void trap_FS_FCloseFile(fileHandle_t f) { syscall(UI_FS_FCLOSEFILE, f); }
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ) {
- return syscall( UI_FS_GETFILELIST, path, extension, listbuf, bufsize );
+int trap_FS_GetFileList(const char *path, const char *extension, char *listbuf, int bufsize)
+{
+ return syscall(UI_FS_GETFILELIST, path, extension, listbuf, bufsize);
}
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ) {
- return syscall( UI_FS_SEEK, f, offset, origin );
-}
+int trap_FS_Seek(fileHandle_t f, long offset, enum FS_Mode origin) { return syscall(UI_FS_SEEK, f, offset, origin); }
-qhandle_t trap_R_RegisterModel( const char *name ) {
- return syscall( UI_R_REGISTERMODEL, name );
-}
+qhandle_t trap_R_RegisterModel(const char *name) { return syscall(UI_R_REGISTERMODEL, name); }
-qhandle_t trap_R_RegisterSkin( const char *name ) {
- return syscall( UI_R_REGISTERSKIN, name );
-}
+qhandle_t trap_R_RegisterSkin(const char *name) { return syscall(UI_R_REGISTERSKIN, name); }
-void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {
- syscall( UI_R_REGISTERFONT, fontName, pointSize, font );
+void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font)
+{
+ syscall(UI_R_REGISTERFONT, fontName, pointSize, font);
}
-qhandle_t trap_R_RegisterShaderNoMip( const char *name ) {
- return syscall( UI_R_REGISTERSHADERNOMIP, name );
-}
+qhandle_t trap_R_RegisterShaderNoMip(const char *name) { return syscall(UI_R_REGISTERSHADERNOMIP, name); }
-void trap_R_ClearScene( void ) {
- syscall( UI_R_CLEARSCENE );
-}
+void trap_R_ClearScene(void) { syscall(UI_R_CLEARSCENE); }
-void trap_R_AddRefEntityToScene( const refEntity_t *re ) {
- syscall( UI_R_ADDREFENTITYTOSCENE, re );
-}
+void trap_R_AddRefEntityToScene(const refEntity_t *re) { syscall(UI_R_ADDREFENTITYTOSCENE, re); }
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) {
- syscall( UI_R_ADDPOLYTOSCENE, hShader, numVerts, verts );
+void trap_R_AddPolyToScene(qhandle_t hShader, int numVerts, const polyVert_t *verts)
+{
+ syscall(UI_R_ADDPOLYTOSCENE, hShader, numVerts, verts);
}
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- syscall( UI_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
+void trap_R_AddLightToScene(const vec3_t org, float intensity, float r, float g, float b)
+{
+ syscall(UI_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b));
}
-void trap_R_RenderScene( const refdef_t *fd ) {
- syscall( UI_R_RENDERSCENE, fd );
-}
+void trap_R_RenderScene(const refdef_t *fd) { syscall(UI_R_RENDERSCENE, fd); }
-void trap_R_SetColor( const float *rgba ) {
- syscall( UI_R_SETCOLOR, rgba );
-}
+void trap_R_SetColor(const float *rgba) { syscall(UI_R_SETCOLOR, rgba); }
-void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader ) {
- syscall( UI_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader );
-}
+#ifndef MODULE_INTERFACE_11
+void trap_R_SetClipRegion(const float *region) { syscall(UI_R_SETCLIPREGION, region); }
+#endif
-void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {
- syscall( UI_R_MODELBOUNDS, model, mins, maxs );
+void trap_R_DrawStretchPic(
+ float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader)
+{
+ syscall(UI_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1),
+ PASSFLOAT(s2), PASSFLOAT(t2), hShader);
}
-void trap_UpdateScreen( void ) {
- syscall( UI_UPDATESCREEN );
-}
+void trap_R_ModelBounds(clipHandle_t model, vec3_t mins, vec3_t maxs) { syscall(UI_R_MODELBOUNDS, model, mins, maxs); }
-int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName ) {
- return syscall( UI_CM_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName );
-}
+void trap_UpdateScreen(void) { syscall(UI_UPDATESCREEN); }
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) {
- syscall( UI_S_STARTLOCALSOUND, sfx, channelNum );
+int trap_CM_LerpTag(orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName)
+{
+ return syscall(UI_CM_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName);
}
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ) {
- return syscall( UI_S_REGISTERSOUND, sample, compressed );
-}
+void trap_S_StartLocalSound(sfxHandle_t sfx, int channelNum) { syscall(UI_S_STARTLOCALSOUND, sfx, channelNum); }
-void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) {
- syscall( UI_KEY_KEYNUMTOSTRINGBUF, keynum, buf, buflen );
+sfxHandle_t trap_S_RegisterSound(const char *sample, qboolean compressed)
+{
+ return syscall(UI_S_REGISTERSOUND, sample, compressed);
}
-void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen ) {
- syscall( UI_KEY_GETBINDINGBUF, keynum, buf, buflen );
+void trap_Key_KeynumToStringBuf(int keynum, char *buf, int buflen)
+{
+ syscall(UI_KEY_KEYNUMTOSTRINGBUF, keynum, buf, buflen);
}
-void trap_Key_SetBinding( int keynum, const char *binding ) {
- syscall( UI_KEY_SETBINDING, keynum, binding );
-}
+void trap_Key_GetBindingBuf(int keynum, char *buf, int buflen) { syscall(UI_KEY_GETBINDINGBUF, keynum, buf, buflen); }
-qboolean trap_Key_IsDown( int keynum ) {
- return syscall( UI_KEY_ISDOWN, keynum );
-}
+void trap_Key_SetBinding(int keynum, const char *binding) { syscall(UI_KEY_SETBINDING, keynum, binding); }
-qboolean trap_Key_GetOverstrikeMode( void ) {
- return syscall( UI_KEY_GETOVERSTRIKEMODE );
-}
+qboolean trap_Key_IsDown(int keynum) { return syscall(UI_KEY_ISDOWN, keynum); }
-void trap_Key_SetOverstrikeMode( qboolean state ) {
- syscall( UI_KEY_SETOVERSTRIKEMODE, state );
-}
+qboolean trap_Key_GetOverstrikeMode(void) { return syscall(UI_KEY_GETOVERSTRIKEMODE); }
-void trap_Key_ClearStates( void ) {
- syscall( UI_KEY_CLEARSTATES );
-}
+void trap_Key_SetOverstrikeMode(qboolean state) { syscall(UI_KEY_SETOVERSTRIKEMODE, state); }
-int trap_Key_GetCatcher( void ) {
- return syscall( UI_KEY_GETCATCHER );
-}
+void trap_Key_ClearStates(void) { syscall(UI_KEY_CLEARSTATES); }
-void trap_Key_SetCatcher( int catcher ) {
- syscall( UI_KEY_SETCATCHER, catcher );
-}
+int trap_Key_GetCatcher(void) { return syscall(UI_KEY_GETCATCHER); }
-void trap_GetClipboardData( char *buf, int bufsize ) {
- syscall( UI_GETCLIPBOARDDATA, buf, bufsize );
-}
+void trap_Key_SetCatcher(int catcher) { syscall(UI_KEY_SETCATCHER, catcher); }
-void trap_GetClientState( uiClientState_t *state ) {
- syscall( UI_GETCLIENTSTATE, state );
-}
+void trap_GetClipboardData(char *buf, int bufsize) { syscall(UI_GETCLIPBOARDDATA, buf, bufsize); }
-void trap_GetGlconfig( glconfig_t *glconfig ) {
- syscall( UI_GETGLCONFIG, glconfig );
-}
+void trap_GetClientState(uiClientState_t *state) { syscall(UI_GETCLIENTSTATE, state); }
-int trap_GetConfigString( int index, char* buff, int buffsize ) {
- return syscall( UI_GETCONFIGSTRING, index, buff, buffsize );
-}
+void trap_GetGlconfig(glconfig_t *glconfig) { syscall(UI_GETGLCONFIG, glconfig); }
-int trap_LAN_GetServerCount( int source ) {
- return syscall( UI_LAN_GETSERVERCOUNT, source );
+int trap_GetConfigString(int index, char *buff, int buffsize)
+{
+ return syscall(UI_GETCONFIGSTRING, index, buff, buffsize);
}
-void trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen ) {
- syscall( UI_LAN_GETSERVERADDRESSSTRING, source, n, buf, buflen );
-}
+int trap_LAN_GetServerCount(int source) { return syscall(UI_LAN_GETSERVERCOUNT, source); }
-void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen ) {
- syscall( UI_LAN_GETSERVERINFO, source, n, buf, buflen );
+void trap_LAN_GetServerAddressString(int source, int n, char *buf, int buflen)
+{
+ syscall(UI_LAN_GETSERVERADDRESSSTRING, source, n, buf, buflen);
}
-int trap_LAN_GetServerPing( int source, int n ) {
- return syscall( UI_LAN_GETSERVERPING, source, n );
+void trap_LAN_GetServerInfo(int source, int n, char *buf, int buflen)
+{
+ syscall(UI_LAN_GETSERVERINFO, source, n, buf, buflen);
}
-int trap_LAN_GetPingQueueCount( void ) {
- return syscall( UI_LAN_GETPINGQUEUECOUNT );
-}
+int trap_LAN_GetServerPing(int source, int n) { return syscall(UI_LAN_GETSERVERPING, source, n); }
-int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen ) {
- return syscall( UI_LAN_SERVERSTATUS, serverAddress, serverStatus, maxLen );
-}
+int trap_LAN_GetPingQueueCount(void) { return syscall(UI_LAN_GETPINGQUEUECOUNT); }
-void trap_LAN_SaveCachedServers( void ) {
- syscall( UI_LAN_SAVECACHEDSERVERS );
+int trap_LAN_ServerStatus(const char *serverAddress, char *serverStatus, int maxLen)
+{
+ return syscall(UI_LAN_SERVERSTATUS, serverAddress, serverStatus, maxLen);
}
-void trap_LAN_LoadCachedServers( void ) {
- syscall( UI_LAN_LOADCACHEDSERVERS );
-}
+#ifndef MODULE_INTERFACE_11
+qboolean trap_GetNews(qboolean force) { return syscall(UI_GETNEWS, force); }
+#endif
-void trap_LAN_ResetPings(int n) {
- syscall( UI_LAN_RESETPINGS, n );
-}
+void trap_LAN_SaveCachedServers(void) { syscall(UI_LAN_SAVECACHEDSERVERS); }
-void trap_LAN_ClearPing( int n ) {
- syscall( UI_LAN_CLEARPING, n );
-}
+void trap_LAN_LoadCachedServers(void) { syscall(UI_LAN_LOADCACHEDSERVERS); }
-void trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime ) {
- syscall( UI_LAN_GETPING, n, buf, buflen, pingtime );
-}
+void trap_LAN_ResetPings(int n) { syscall(UI_LAN_RESETPINGS, n); }
-void trap_LAN_GetPingInfo( int n, char *buf, int buflen ) {
- syscall( UI_LAN_GETPINGINFO, n, buf, buflen );
-}
+void trap_LAN_ClearPing(int n) { syscall(UI_LAN_CLEARPING, n); }
-void trap_LAN_MarkServerVisible( int source, int n, qboolean visible ) {
- syscall( UI_LAN_MARKSERVERVISIBLE, source, n, visible );
+void trap_LAN_GetPing(int n, char *buf, int buflen, int *pingtime)
+{
+ syscall(UI_LAN_GETPING, n, buf, buflen, pingtime);
}
-int trap_LAN_ServerIsVisible( int source, int n) {
- return syscall( UI_LAN_SERVERISVISIBLE, source, n );
-}
+void trap_LAN_GetPingInfo(int n, char *buf, int buflen) { syscall(UI_LAN_GETPINGINFO, n, buf, buflen); }
-qboolean trap_LAN_UpdateVisiblePings( int source ) {
- return syscall( UI_LAN_UPDATEVISIBLEPINGS, source );
+void trap_LAN_MarkServerVisible(int source, int n, qboolean visible)
+{
+ syscall(UI_LAN_MARKSERVERVISIBLE, source, n, visible);
}
-int trap_LAN_AddServer(int source, const char *name, const char *addr) {
- return syscall( UI_LAN_ADDSERVER, source, name, addr );
-}
+int trap_LAN_ServerIsVisible(int source, int n) { return syscall(UI_LAN_SERVERISVISIBLE, source, n); }
-void trap_LAN_RemoveServer(int source, const char *addr) {
- syscall( UI_LAN_REMOVESERVER, source, addr );
-}
+qboolean trap_LAN_UpdateVisiblePings(int source) { return syscall(UI_LAN_UPDATEVISIBLEPINGS, source); }
-int trap_LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 ) {
- return syscall( UI_LAN_COMPARESERVERS, source, sortKey, sortDir, s1, s2 );
+int trap_LAN_AddServer(int source, const char *name, const char *addr)
+{
+ return syscall(UI_LAN_ADDSERVER, source, name, addr);
}
-int trap_MemoryRemaining( void ) {
- return syscall( UI_MEMORY_REMAINING );
-}
+void trap_LAN_RemoveServer(int source, const char *addr) { syscall(UI_LAN_REMOVESERVER, source, addr); }
-int trap_Parse_AddGlobalDefine( char *define ) {
- return syscall( UI_PARSE_ADD_GLOBAL_DEFINE, define );
+int trap_LAN_CompareServers(int source, int sortKey, int sortDir, int s1, int s2)
+{
+ return syscall(UI_LAN_COMPARESERVERS, source, sortKey, sortDir, s1, s2);
}
-int trap_Parse_LoadSource( const char *filename ) {
- return syscall( UI_PARSE_LOAD_SOURCE, filename );
-}
+int trap_MemoryRemaining(void) { return syscall(UI_MEMORY_REMAINING); }
-int trap_Parse_FreeSource( int handle ) {
- return syscall( UI_PARSE_FREE_SOURCE, handle );
-}
+int trap_Parse_AddGlobalDefine(char *define) { return syscall(UI_PARSE_ADD_GLOBAL_DEFINE, define); }
-int trap_Parse_ReadToken( int handle, pc_token_t *pc_token ) {
- return syscall( UI_PARSE_READ_TOKEN, handle, pc_token );
-}
+int trap_Parse_LoadSource(const char *filename) { return syscall(UI_PARSE_LOAD_SOURCE, filename); }
-int trap_Parse_SourceFileAndLine( int handle, char *filename, int *line ) {
- return syscall( UI_PARSE_SOURCE_FILE_AND_LINE, handle, filename, line );
-}
+int trap_Parse_FreeSource(int handle) { return syscall(UI_PARSE_FREE_SOURCE, handle); }
-void trap_S_StopBackgroundTrack( void ) {
- syscall( UI_S_STOPBACKGROUNDTRACK );
-}
+int trap_Parse_ReadToken(int handle, pc_token_t *pc_token) { return syscall(UI_PARSE_READ_TOKEN, handle, pc_token); }
-void trap_S_StartBackgroundTrack( const char *intro, const char *loop) {
- syscall( UI_S_STARTBACKGROUNDTRACK, intro, loop );
+int trap_Parse_SourceFileAndLine(int handle, char *filename, int *line)
+{
+ return syscall(UI_PARSE_SOURCE_FILE_AND_LINE, handle, filename, line);
}
-int trap_RealTime(qtime_t *qtime) {
- return syscall( UI_REAL_TIME, qtime );
+void trap_S_StopBackgroundTrack(void) { syscall(UI_S_STOPBACKGROUNDTRACK); }
+
+void trap_S_StartBackgroundTrack(const char *intro, const char *loop)
+{
+ syscall(UI_S_STARTBACKGROUNDTRACK, intro, loop);
}
-// this returns a handle. arg0 is the name in the format "idlogo.roq", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate)
-int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits) {
- return syscall(UI_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits);
+int trap_RealTime(qtime_t *qtime) { return syscall(UI_REAL_TIME, qtime); }
+
+// this returns a handle. arg0 is the name in the format "idlogo.roq", set arg1 to NULL, alteredstates to qfalse (do
+// not alter gamestate)
+int trap_CIN_PlayCinematic(const char *arg0, int xpos, int ypos, int width, int height, int bits)
+{
+ return syscall(UI_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits);
}
// stops playing the cinematic and ends it. should always return FMV_EOF
// cinematics must be stopped in reverse order of when they are started
-e_status trap_CIN_StopCinematic(int handle) {
- return syscall(UI_CIN_STOPCINEMATIC, handle);
-}
-
-
-// will run a frame of the cinematic but will not draw it. Will return FMV_EOF if the end of the cinematic has been reached.
-e_status trap_CIN_RunCinematic (int handle) {
- return syscall(UI_CIN_RUNCINEMATIC, handle);
-}
+e_status trap_CIN_StopCinematic(int handle) { return syscall(UI_CIN_STOPCINEMATIC, handle); }
+// will run a frame of the cinematic but will not draw it. Will return FMV_EOF if the end of the cinematic has been
+// reached.
+e_status trap_CIN_RunCinematic(int handle) { return syscall(UI_CIN_RUNCINEMATIC, handle); }
// draws the current frame
-void trap_CIN_DrawCinematic (int handle) {
- syscall(UI_CIN_DRAWCINEMATIC, handle);
-}
-
+void trap_CIN_DrawCinematic(int handle) { syscall(UI_CIN_DRAWCINEMATIC, handle); }
// allows you to resize the animation dynamically
-void trap_CIN_SetExtents (int handle, int x, int y, int w, int h) {
- syscall(UI_CIN_SETEXTENTS, handle, x, y, w, h);
-}
+void trap_CIN_SetExtents(int handle, int x, int y, int w, int h) { syscall(UI_CIN_SETEXTENTS, handle, x, y, w, h); }
-
-void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) {
- syscall( UI_R_REMAP_SHADER, oldShader, newShader, timeOffset );
+void trap_R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset)
+{
+ syscall(UI_R_REMAP_SHADER, oldShader, newShader, timeOffset);
}
-void trap_SetPbClStatus( int status ) {
- syscall( UI_SET_PBCLSTATUS, status );
-}
+void trap_SetPbClStatus(int status) { syscall(UI_SET_PBCLSTATUS, status); }
diff --git a/src/ui/ui_syscalls_11.asm b/src/ui/ui_syscalls_11.asm
index 64d2ca3..a7a01f2 100644
--- a/src/ui/ui_syscalls_11.asm
+++ b/src/ui/ui_syscalls_11.asm
@@ -96,3 +96,5 @@ equ sqrt -107
equ floor -108
equ ceil -109
+equ trap_CheckForUpdate -200
+equ trap_InstallUpdate -201
diff --git a/ui/assets/alien/buildstat/frame.tga b/ui/assets/alien/buildstat/frame.tga
deleted file mode 100644
index 3b1e1f5..0000000
--- a/ui/assets/alien/buildstat/frame.tga
+++ /dev/null
Binary files differ
diff --git a/ui/assets/alien/buildstat/mark.tga b/ui/assets/alien/buildstat/mark.tga
deleted file mode 100644
index ef9123c..0000000
--- a/ui/assets/alien/buildstat/mark.tga
+++ /dev/null
Binary files differ
diff --git a/ui/assets/alien/buildstat/nopower.tga b/ui/assets/alien/buildstat/nopower.tga
deleted file mode 100644
index a0c66c2..0000000
--- a/ui/assets/alien/buildstat/nopower.tga
+++ /dev/null
Binary files differ
diff --git a/ui/assets/alien/buildstat/overlay.tga b/ui/assets/alien/buildstat/overlay.tga
deleted file mode 100644
index 64a2358..0000000
--- a/ui/assets/alien/buildstat/overlay.tga
+++ /dev/null
Binary files differ
diff --git a/ui/assets/human/buildstat/frame.tga b/ui/assets/human/buildstat/frame.tga
deleted file mode 100644
index 3b1e1f5..0000000
--- a/ui/assets/human/buildstat/frame.tga
+++ /dev/null
Binary files differ
diff --git a/ui/assets/human/buildstat/mark.tga b/ui/assets/human/buildstat/mark.tga
deleted file mode 100644
index ef9123c..0000000
--- a/ui/assets/human/buildstat/mark.tga
+++ /dev/null
Binary files differ
diff --git a/ui/assets/human/buildstat/nopower.tga b/ui/assets/human/buildstat/nopower.tga
deleted file mode 100644
index 4d70384..0000000
--- a/ui/assets/human/buildstat/nopower.tga
+++ /dev/null
Binary files differ
diff --git a/ui/drop.menu b/ui/drop.menu
deleted file mode 100644
index 0db2264..0000000
--- a/ui/drop.menu
+++ /dev/null
@@ -1,126 +0,0 @@
-#include "ui/menudef.h"
-
-{
- \\ ERROR \\
-
- menuDef
- {
- name "drop_popmenu"
- visible 0
- fullscreen 0
- rect 158 80 320 320
- focusColor 1 .75 0 1
- style 1
- border 1
- popup
- onClose { uiScript clearError }
- onOpen { }
- onESC
- {
- play "sound/misc/menu1.wav";
- close drop_popmenu;
- open main
- }
-
-
- itemDef
- {
- name window
- rect 10 15 300 320
- style WINDOW_STYLE_FILLED
- backcolor 0 0 0 1
- visible 1
- decoration
-
- border WINDOW_BORDER_FULL
- borderSize 1.0
- borderColor 0.5 0.5 0.5 1
- }
-
- itemDef
- {
- name dropinfo
- rect 0 50 320 20
- text "Disconnected:"
- textalign 1
- textstyle 6
- textscale .333
- textalignx 160
- textaligny 23
- forecolor 1 1 1 1
- visible 1
- decoration
- }
-
- itemDef
- {
- name dropinfo
- rect 60 80 200 270
- type ITEM_TYPE_TEXT
- style 1
- textstyle 3
- autowrapped
- cvar "com_errorMessage"
- textalign ITEM_ALIGN_CENTER
- textalignx 100
- textaligny 23
- textscale .25
- forecolor 1 1 1 1
- visible 1
- decoration
- }
-
-
- // BUTTON //
-
-
- itemDef
- {
- name exit
- text "OK"
- type 1
- textscale .25
- group grpControlbutton
- type ITEM_TYPE_BUTTON
- style WINDOW_STYLE_EMPTY
- rect 120 295 35 26
- textalign 1
- textalignx 22
- textaligny 20
- forecolor 1 1 1 1
- backcolor .37 .1 .1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- close drop_popmenu;
- open main
- }
- }
-
- itemDef
- {
- name reconnect
- text "Reconnect"
- type 1
- textscale .25
- group grpControlbutton
- type ITEM_TYPE_BUTTON
- style WINDOW_STYLE_EMPTY
- rect 165 295 55 26
- textalign 1
- textalignx 22
- textaligny 20
- forecolor 1 1 1 1
- backcolor .37 .1 .1 1
- visible 1
- action
- {
- close drop_popmenu;
- exec "reconnect";
- }
- }
- }
-}
-
-
diff --git a/ui/ingame_game.menu b/ui/ingame_game.menu
deleted file mode 100644
index 0200ed9..0000000
--- a/ui/ingame_game.menu
+++ /dev/null
@@ -1,3206 +0,0 @@
-#include "ui/menudef.h"
-
-{
- \\ INGAME GAME BOX \\
-
- menuDef
- {
- name "ingame_game"
- visible 0
- fullscreen 0
- outOfBoundsClick // this closes the window if it gets a click out of the rectangle
- rect 10 56 292 280
- focusColor 1 .75 0 1
- onopen
- {
- uiScript InitIgnoreList;
- uiScript loadArenas;
- uiScript loadServerInfo;
- hide gameGrp;
- show vote;
- show mapvote;
-
- setitemcolor voteBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0
- }
-
- itemDef
- {
- name window
- rect 10 5 292 270
- style WINDOW_STYLE_FILLED
- backcolor 0 0 0 1
- visible 1
- decoration
-
- border WINDOW_BORDER_KCGRADIENT
- borderSize 2.0
- borderColor 0.5 0.5 0.5 1
- }
-
- //Section menus
- itemDef
- {
- name voteBtn
- text "Vote"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 35 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show vote;
- show mapvote;
-
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor voteBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0
- }
- }
-
- itemDef
- {
- name ignoreBtn
- text "Ignore"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 100 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show ignore;
-
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor voteBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor ignoreBtn forecolor 0.2 0.2 0.2 1.0
- }
- }
-
- itemDef
- {
- name infoBtn
- text "Info"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 165 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show info;
-
- setitemcolor infoBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor voteBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0
- }
- }
-
-
-//////// INFO
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 55 256 20
- type 4
- style 0
- text "Server Name:"
- cvar ui_serverinfo_hostname
- maxPaintChars 32
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 70 256 20
- type 4
- style 0
- text "Time Limit:"
- maxPaintChars 12
- cvar ui_serverinfo_timelimit
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 85 256 20
- type 4
- style 0
- text "Sudden Death Time:"
- cvar ui_serverinfo_sd
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 100 256 20
- type 4
- style 0
- text "Max Clients:"
- cvar ui_serverinfo_maxclients
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 115 256 20
- type 4
- style 0
- text "Map Name:"
- cvar ui_serverinfo_mapname
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 130 256 20
- type 11
- style 0
- text "Lag Correction:"
- cvar ui_serverinfo_unlagged
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 145 256 20
- type ITEM_TYPE_MULTI
- style 0
- text "Friendly Fire:"
- cvarFloat ui_serverinfo_ff 0 0 7
- cvarFloatList { "Off" 0 "Humans Only" 1 "Aliens Only" 2 "Both Teams" 3 "Buildables Only" 4 "Humans and Buildables" 5 "Aliens and Buildables" 6 "Both Teams and Buildables" 7 }
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 160 256 20
- type 4
- style 0
- text "Version:"
- cvar ui_serverinfo_version
- maxPaintChars 45
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
-//////// VOTE
-
- //Vote menu
- itemDef
- {
- name vote
- text "Map"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 60 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show mapvote;
- show vote;
- }
- }
-
- itemDef
- {
- name vote
- text "Players"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 85 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show playervote;
- show vote;
- }
- }
-
- itemDef
- {
- name vote
- text "Team"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 110 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show teamvote;
- show vote;
- }
- }
-
-///// Map Vote
- itemDef
- {
- name mapvote
- group gameGrp
- style 0
- ownerdraw UI_STARTMAPCINEMATIC
- rect 111 61 80 60
- border 1
- bordercolor .5 .5 .5 .5
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- style WINDOW_STYLE_FILLED
- rect 110 60 82 62
- border 1
- bordercolor .5 .5 .5 .5
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text ""
- ownerdraw UI_ALLMAPS_SELECTION
- textscale .225
- rect 200 80 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- rect 110 122 150 85
- type ITEM_TYPE_LISTBOX
- style WINDOW_STYLE_EMPTY
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_ALLMAPS
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- doubleclick
- {
- play "sound/misc/menu1.wav";
- uiScript voteMap;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "Load Selected Map"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 210 80 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteMap;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "Restart Current Map"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 230 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callvote map_restart";
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "End Match In Draw"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 250 110 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callvote draw";
- uiScript closeingame
- }
- }
-
-///// Player Vote
- itemDef
- {
- name playervote
- group gameGrp
- text "Selected Player:"
- ownerdraw UI_PLAYERLIST_SELECTION
- textscale .225
- rect 110 60 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- rect 110 80 170 85
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_LISTBOX
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_PLAYER_LIST
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Kick Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 175 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteKick;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Mute Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 195 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteMute;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Un-Mute Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 215 100 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteUnMute;
- uiScript closeingame
- }
- }
-
-
-///// Team Vote
- itemDef
- {
- name teamvote
- group gameGrp
- text "Selected Teammate:"
- ownerdraw UI_TEAMLIST_SELECTION
- textscale .225
- rect 110 60 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- rect 110 80 170 85
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_LISTBOX
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_TEAM_LIST
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Kick Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 175 100 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamKick;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Deny Building For Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 195 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamDenyBuild;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Allow Building For Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 215 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamAllowBuild;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Admit Defeat"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 235 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callteamvote admitdefeat";
- uiScript closeingame
- }
- }
-
-//////// IGNORE
- itemDef
- {
- name ignore
- group gameGrp
- rect 45 70 40 5
- text "Player Name"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 190 70 40 5
- text "Ignored"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 230 70 40 5
- text "Ignoring You"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 35 75 240 130
- type ITEM_TYPE_LISTBOX
- style WINDOW_STYLE_EMPTY
- elementwidth 120
- elementheight 16
- textscale .225
- border 1
- bordersize 1
- bordercolor .5 .5 .5 1
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- elementtype LISTBOX_TEXT
- feeder FEEDER_IGNORE_LIST
- visible 0
- columns 3
- 2 40 32 ITEM_ALIGN_LEFT
- 150 15 1 ITEM_ALIGN_LEFT
- 190 15 1 ITEM_ALIGN_LEFT
- doubleClick {
- play "sound/misc/menu1.wav";
- uiScript ToggleIgnore
- }
- }
-
- itemDef
- {
- name ignore
- text "Ignore Player"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 60 210 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript IgnorePlayer
- }
- }
-
- itemDef
- {
- name ignore
- text "Stop Ignoring Player"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 190 210 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript UnIgnorePlayer
- }
- }
-
- }
-}
-#include "ui/menudef.h"
-
-{
- \\ INGAME GAME BOX \\
-
- menuDef
- {
- name "ingame_game"
- visible 0
- fullscreen 0
- outOfBoundsClick // this closes the window if it gets a click out of the rectangle
- rect 10 56 292 280
- focusColor 1 .75 0 1
- onopen
- {
- uiScript InitIgnoreList;
- uiScript loadArenas;
- uiScript loadServerInfo;
- hide gameGrp;
- show vote;
- show mapvote;
-
- setitemcolor voteBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0
- }
-
- itemDef
- {
- name window
- rect 10 5 292 270
- style WINDOW_STYLE_FILLED
- backcolor 0 0 0 1
- visible 1
- decoration
-
- border WINDOW_BORDER_KCGRADIENT
- borderSize 2.0
- borderColor 0.5 0.5 0.5 1
- }
-
- //Section menus
- itemDef
- {
- name voteBtn
- text "Vote"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 35 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show vote;
- show mapvote;
-
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor voteBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0
- }
- }
-
- itemDef
- {
- name ignoreBtn
- text "Ignore"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 100 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show ignore;
-
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor voteBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor ignoreBtn forecolor 0.2 0.2 0.2 1.0
- }
- }
-
- itemDef
- {
- name infoBtn
- text "Info"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 165 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show info;
-
- setitemcolor infoBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor voteBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0
- }
- }
-
-
-//////// INFO
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 55 256 20
- type 4
- style 0
- text "Server Name:"
- cvar ui_serverinfo_hostname
- maxPaintChars 32
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 70 256 20
- type 4
- style 0
- text "Time Limit:"
- maxPaintChars 12
- cvar ui_serverinfo_timelimit
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 85 256 20
- type 4
- style 0
- text "Sudden Death Time:"
- cvar ui_serverinfo_sd
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 100 256 20
- type 4
- style 0
- text "Max Clients:"
- cvar ui_serverinfo_maxclients
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 115 256 20
- type 4
- style 0
- text "Map Name:"
- cvar ui_serverinfo_mapname
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 130 256 20
- type 11
- style 0
- text "Lag Correction:"
- cvar ui_serverinfo_unlagged
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 145 256 20
- type 11
- style 0
- text "Friendly Fire:"
- cvar ui_serverinfo_ff
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 160 256 20
- type 4
- style 0
- text "Version:"
- cvar version
- maxPaintChars 45
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
-//////// VOTE
-
- //Vote menu
- itemDef
- {
- name vote
- text "Map"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 60 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show mapvote;
- show vote;
- }
- }
-
- itemDef
- {
- name vote
- text "Players"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 85 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show playervote;
- show vote;
- }
- }
-
- itemDef
- {
- name vote
- text "Team"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 110 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show teamvote;
- show vote;
- }
- }
-
-///// Map Vote
- itemDef
- {
- name mapvote
- group gameGrp
- style 0
- ownerdraw UI_STARTMAPCINEMATIC
- rect 111 61 80 60
- border 1
- bordercolor .5 .5 .5 .5
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- style WINDOW_STYLE_FILLED
- rect 110 60 82 62
- border 1
- bordercolor .5 .5 .5 .5
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text ""
- ownerdraw UI_ALLMAPS_SELECTION
- textscale .225
- rect 200 80 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- rect 110 122 150 85
- type ITEM_TYPE_LISTBOX
- style WINDOW_STYLE_EMPTY
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_ALLMAPS
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- doubleclick
- {
- play "sound/misc/menu1.wav";
- uiScript voteMap;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "Load Selected Map"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 210 80 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteMap;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "Restart Current Map"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 230 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callvote map_restart";
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "End Match In Draw"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 250 110 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callvote draw";
- uiScript closeingame
- }
- }
-
-///// Player Vote
- itemDef
- {
- name playervote
- group gameGrp
- text "Selected Player:"
- ownerdraw UI_PLAYERLIST_SELECTION
- textscale .225
- rect 110 60 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- rect 110 80 170 85
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_LISTBOX
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_PLAYER_LIST
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Kick Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 175 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteKick;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Mute Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 195 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteMute;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Un-Mute Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 215 100 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteUnMute;
- uiScript closeingame
- }
- }
-
-
-///// Team Vote
- itemDef
- {
- name teamvote
- group gameGrp
- text "Selected Teammate:"
- ownerdraw UI_TEAMLIST_SELECTION
- textscale .225
- rect 110 60 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- rect 110 80 170 85
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_LISTBOX
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_TEAM_LIST
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Kick Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 175 100 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamKick;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Deny Building For Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 195 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamDenyBuild;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Allow Building For Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 215 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamAllowBuild;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Admit Defeat"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 235 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callteamvote admitdefeat";
- uiScript closeingame
- }
- }
-
-//////// IGNORE
- itemDef
- {
- name ignore
- group gameGrp
- rect 45 70 40 5
- text "Player Name"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 190 70 40 5
- text "Ignored"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 230 70 40 5
- text "Ignoring You"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 35 75 240 130
- type ITEM_TYPE_LISTBOX
- style WINDOW_STYLE_EMPTY
- elementwidth 120
- elementheight 16
- textscale .225
- border 1
- bordersize 1
- bordercolor .5 .5 .5 1
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- elementtype LISTBOX_TEXT
- feeder FEEDER_IGNORE_LIST
- visible 0
- columns 3
- 2 40 32 ITEM_ALIGN_LEFT
- 150 15 1 ITEM_ALIGN_LEFT
- 190 15 1 ITEM_ALIGN_LEFT
- doubleClick {
- play "sound/misc/menu1.wav";
- uiScript ToggleIgnore
- }
- }
-
- itemDef
- {
- name ignore
- text "Ignore Player"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 60 210 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript IgnorePlayer
- }
- }
-
- itemDef
- {
- name ignore
- text "Stop Ignoring Player"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 190 210 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript UnIgnorePlayer
- }
- }
-
- }
-}
-#include "ui/menudef.h"
-
-{
- \\ INGAME GAME BOX \\
-
- menuDef
- {
- name "ingame_game"
- visible 0
- fullscreen 0
- outOfBoundsClick // this closes the window if it gets a click out of the rectangle
- rect 10 56 292 280
- focusColor 1 .75 0 1
- onopen
- {
- uiScript InitIgnoreList;
- uiScript loadArenas;
- uiScript loadServerInfo;
- hide gameGrp;
- show vote;
- show mapvote;
-
- setitemcolor voteBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0
- }
-
- itemDef
- {
- name window
- rect 10 5 292 270
- style WINDOW_STYLE_FILLED
- backcolor 0 0 0 1
- visible 1
- decoration
-
- border WINDOW_BORDER_KCGRADIENT
- borderSize 2.0
- borderColor 0.5 0.5 0.5 1
- }
-
- //Section menus
- itemDef
- {
- name voteBtn
- text "Vote"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 35 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show vote;
- show mapvote;
-
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor voteBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0
- }
- }
-
- itemDef
- {
- name ignoreBtn
- text "Ignore"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 100 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show ignore;
-
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor voteBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor ignoreBtn forecolor 0.2 0.2 0.2 1.0
- }
- }
-
- itemDef
- {
- name infoBtn
- text "Info"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 165 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show info;
-
- setitemcolor infoBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor voteBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0
- }
- }
-
-
-//////// INFO
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 55 256 20
- type 4
- style 0
- text "Server Name:"
- cvar ui_serverinfo_hostname
- maxPaintChars 32
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 70 256 20
- type 4
- style 0
- text "Time Limit:"
- maxPaintChars 12
- cvar ui_serverinfo_timelimit
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 85 256 20
- type 4
- style 0
- text "Sudden Death Time:"
- cvar ui_serverinfo_sd
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 100 256 20
- type 4
- style 0
- text "Max Clients:"
- cvar ui_serverinfo_maxclients
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 115 256 20
- type 4
- style 0
- text "Map Name:"
- cvar ui_serverinfo_mapname
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 130 256 20
- type 11
- style 0
- text "Lag Correction:"
- cvar ui_serverinfo_unlagged
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 145 256 20
- type 11
- style 0
- text "Friendly Fire:"
- cvar ui_serverinfo_ff
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 160 256 20
- type 4
- style 0
- text "Version:"
- cvar version
- maxPaintChars 45
- textalign ITEM_ALIGN_RIGHT
- textaligny 12
- textalignx 75
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
-//////// VOTE
-
- //Vote menu
- itemDef
- {
- name vote
- text "Map"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 60 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show mapvote;
- show vote;
- }
- }
-
- itemDef
- {
- name vote
- text "Players"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 85 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show playervote;
- show vote;
- }
- }
-
- itemDef
- {
- name vote
- text "Team"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 110 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show teamvote;
- show vote;
- }
- }
-
-///// Map Vote
- itemDef
- {
- name mapvote
- group gameGrp
- style 0
- ownerdraw UI_STARTMAPCINEMATIC
- rect 111 61 80 60
- border 1
- bordercolor .5 .5 .5 .5
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- style WINDOW_STYLE_FILLED
- rect 110 60 82 62
- border 1
- bordercolor .5 .5 .5 .5
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text ""
- ownerdraw UI_ALLMAPS_SELECTION
- textscale .225
- rect 200 80 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- rect 110 122 150 85
- type ITEM_TYPE_LISTBOX
- style WINDOW_STYLE_EMPTY
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_ALLMAPS
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- doubleclick
- {
- play "sound/misc/menu1.wav";
- uiScript voteMap;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "Load Selected Map"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 210 80 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteMap;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "Restart Current Map"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 230 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callvote map_restart";
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "End Match In Draw"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 250 110 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callvote draw";
- uiScript closeingame
- }
- }
-
-///// Player Vote
- itemDef
- {
- name playervote
- group gameGrp
- text "Selected Player:"
- ownerdraw UI_PLAYERLIST_SELECTION
- textscale .225
- rect 110 60 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- rect 110 80 170 85
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_LISTBOX
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_PLAYER_LIST
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Kick Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 175 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteKick;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Mute Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 195 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteMute;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Un-Mute Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 215 100 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteUnMute;
- uiScript closeingame
- }
- }
-
-
-///// Team Vote
- itemDef
- {
- name teamvote
- group gameGrp
- text "Selected Teammate:"
- ownerdraw UI_TEAMLIST_SELECTION
- textscale .225
- rect 110 60 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- rect 110 80 170 85
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_LISTBOX
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_TEAM_LIST
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Kick Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 175 100 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamKick;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Deny Building For Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 195 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamDenyBuild;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Allow Building For Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 215 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamAllowBuild;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Admit Defeat"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 235 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callteamvote admitdefeat";
- uiScript closeingame
- }
- }
-
-//////// IGNORE
- itemDef
- {
- name ignore
- group gameGrp
- rect 45 70 40 5
- text "Player Name"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 190 70 40 5
- text "Ignored"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 230 70 40 5
- text "Ignoring You"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 35 75 240 130
- type ITEM_TYPE_LISTBOX
- style WINDOW_STYLE_EMPTY
- elementwidth 120
- elementheight 16
- textscale .225
- border 1
- bordersize 1
- bordercolor .5 .5 .5 1
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- elementtype LISTBOX_TEXT
- feeder FEEDER_IGNORE_LIST
- visible 0
- columns 3
- 2 40 32 ITEM_ALIGN_LEFT
- 150 15 1 ITEM_ALIGN_LEFT
- 190 15 1 ITEM_ALIGN_LEFT
- doubleClick {
- play "sound/misc/menu1.wav";
- uiScript ToggleIgnore
- }
- }
-
- itemDef
- {
- name ignore
- text "Ignore Player"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 60 210 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript IgnorePlayer
- }
- }
-
- itemDef
- {
- name ignore
- text "Stop Ignoring Player"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 190 210 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript UnIgnorePlayer
- }
- }
-
- }
-}
-#include "ui/menudef.h"
-
-{
- \\ INGAME GAME BOX \\
-
- menuDef
- {
- name "ingame_game"
- visible 0
- fullscreen 0
- outOfBoundsClick // this closes the window if it gets a click out of the rectangle
- rect 10 56 292 280
- focusColor 1 .75 0 1
- onopen
- {
- uiScript InitIgnoreList;
- uiScript loadArenas;
- uiScript loadServerInfo;
- hide gameGrp;
- show vote;
- show mapvote;
-
- setitemcolor voteBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0
- }
-
- itemDef
- {
- name window
- rect 10 5 292 270
- style WINDOW_STYLE_FILLED
- backcolor 0 0 0 1
- visible 1
- decoration
-
- border WINDOW_BORDER_KCGRADIENT
- borderSize 2.0
- borderColor 0.5 0.5 0.5 1
- }
-
- //Section menus
- itemDef
- {
- name voteBtn
- text "Vote"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 35 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show vote;
- show mapvote;
-
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor voteBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0
- }
- }
-
- itemDef
- {
- name ignoreBtn
- text "Ignore"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 100 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show ignore;
-
- setitemcolor infoBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor voteBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor ignoreBtn forecolor 0.2 0.2 0.2 1.0
- }
- }
-
- itemDef
- {
- name infoBtn
- text "Info"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 165 22 40 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show info;
-
- setitemcolor infoBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor voteBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor ignoreBtn forecolor 1.0 1.0 1.0 1.0
- }
- }
-
-
-//////// ABOUT
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 55 256 20
- type 4
- style 0
- text "Server Name:"
- cvar ui_serverinfo_hostname
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 70 256 20
- type 4
- style 0
- text "Time Limit:"
- maxPaintChars 12
- cvar ui_serverinfo_timelimit
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 85 256 20
- type 4
- style 0
- text "Sudden Death Time:"
- cvar ui_serverinfo_sd
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 100 256 20
- type 4
- style 0
- text "Max Clients:"
- cvar ui_serverinfo_maxclients
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 115 256 20
- type 4
- style 0
- text "Map Name:"
- cvar ui_serverinfo_mapname
- maxPaintChars 12
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 130 256 20
- type 11
- style 0
- text "Lag Correction:"
- cvar ui_serverinfo_unlagged
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 145 256 20
- type 11
- style 0
- text "Friendly Fire:"
- cvar ui_serverinfo_ff
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name info
- group gameGrp
- rect 30 160 256 20
- type 4
- style 0
- text "Version:"
- cvar version
- maxPaintChars 45
- textalign ITEM_ALIGN_LEFT
- textalignx 128
- textaligny 12
- textalign 1
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
-//////// VOTE
-
- //Vote menu
- itemDef
- {
- name vote
- text "Map"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 60 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show mapvote;
- show vote;
- }
- }
-
- itemDef
- {
- name vote
- text "Players"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 85 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show playervote;
- show vote;
- }
- }
-
- itemDef
- {
- name vote
- text "Team"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 20 110 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide gameGrp;
- show teamvote;
- show vote;
- }
- }
-
-///// Map Vote
- itemDef
- {
- name mapvote
- group gameGrp
- style 0
- ownerdraw UI_STARTMAPCINEMATIC
- rect 111 61 80 60
- border 1
- bordercolor .5 .5 .5 .5
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- style WINDOW_STYLE_FILLED
- rect 110 60 82 62
- border 1
- bordercolor .5 .5 .5 .5
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text ""
- ownerdraw UI_ALLMAPS_SELECTION
- textscale .225
- rect 200 80 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- rect 110 122 150 85
- type ITEM_TYPE_LISTBOX
- style WINDOW_STYLE_EMPTY
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_ALLMAPS
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- doubleclick
- {
- play "sound/misc/menu1.wav";
- uiScript voteMap;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "Load Selected Map"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 210 80 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteMap;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "Restart Current Map"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 230 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callvote map_restart";
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name mapvote
- group gameGrp
- text "End Match In Draw"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 250 110 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callvote draw";
- uiScript closeingame
- }
- }
-
-///// Player Vote
- itemDef
- {
- name playervote
- group gameGrp
- text "Selected Player:"
- ownerdraw UI_PLAYERLIST_SELECTION
- textscale .225
- rect 110 60 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- rect 110 80 170 85
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_LISTBOX
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_PLAYER_LIST
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Kick Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 175 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteKick;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Mute Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 195 90 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteMute;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name playervote
- group gameGrp
- text "Un-Mute Selected Player"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 215 100 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteUnMute;
- uiScript closeingame
- }
- }
-
-
-///// Team Vote
- itemDef
- {
- name teamvote
- group gameGrp
- text "Selected Teammate:"
- ownerdraw UI_TEAMLIST_SELECTION
- textscale .225
- rect 110 60 110 20
- textalign 0
- textalignx 0
- textaligny 16
- forecolor 1 1 1 1
- decoration
- visible 0
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- rect 110 80 170 85
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_LISTBOX
- elementwidth 120
- elementheight 15
- textscale .225
- elementtype LISTBOX_TEXT
- feeder FEEDER_TEAM_LIST
- border 1
- bordercolor 0.5 0.5 0.5 0.5
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 0
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Kick Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 175 100 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamKick;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Deny Building For Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 195 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamDenyBuild;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Allow Building For Selected Teammate"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 215 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript voteTeamAllowBuild;
- uiScript closeingame
- }
- }
-
- itemDef
- {
- name teamvote
- group gameGrp
- text "Admit Defeat"
- type ITEM_TYPE_BUTTON
- textscale .25
- rect 110 235 150 20
- textalign ITEM_ALIGN_LEFT
- textalignx 5
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "cmd callteamvote admitdefeat";
- uiScript closeingame
- }
- }
-
-//////// IGNORE
- itemDef
- {
- name ignore
- group gameGrp
- rect 45 70 40 5
- text "Player Name"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 190 70 40 5
- text "Ignored"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 230 70 40 5
- text "Ignoring You"
- visible 0
- type ITEM_TYPE_TEXT
- textscale .225
- }
- itemDef
- {
- name ignore
- group gameGrp
- rect 35 75 240 130
- type ITEM_TYPE_LISTBOX
- style WINDOW_STYLE_EMPTY
- elementwidth 120
- elementheight 16
- textscale .225
- border 1
- bordersize 1
- bordercolor .5 .5 .5 1
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- elementtype LISTBOX_TEXT
- feeder FEEDER_IGNORE_LIST
- visible 0
- columns 3
- 2 40 32 ITEM_ALIGN_LEFT
- 150 15 1 ITEM_ALIGN_LEFT
- 190 15 1 ITEM_ALIGN_LEFT
- doubleClick {
- play "sound/misc/menu1.wav";
- uiScript ToggleIgnore
- }
- }
-
- itemDef
- {
- name ignore
- text "Ignore Player"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 60 210 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript IgnorePlayer
- }
- }
-
- itemDef
- {
- name ignore
- text "Stop Ignoring Player"
- group gameGrp
- style WINDOW_STYLE_EMPTY
- rect 190 210 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript UnIgnorePlayer
- }
- }
-
- }
-}
diff --git a/ui/ingame_options.menu b/ui/ingame_options.menu
deleted file mode 100644
index e0f08aa..0000000
--- a/ui/ingame_options.menu
+++ /dev/null
@@ -1,2180 +0,0 @@
-#include "ui/menudef.h"
-
-{
- \\ INGAME OPTIONS BOX \\
-
- menuDef
- {
- name "ingame_options"
- visible 0
- fullscreen 0
- outOfBoundsClick // this closes the window if it gets a click out of the rectangle
- rect 10 56 292 280
- focusColor 1 .75 0 1
- onopen
- {
- hide optionsGrp;
- show game;
-
- setitemcolor gameBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor controlsBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor systemBtn forecolor 1.0 1.0 1.0 1.0
- }
-
- itemDef
- {
- name window
- rect 10 5 292 270
- style WINDOW_STYLE_FILLED
- backcolor 0 0 0 1
- visible 1
- decoration
-
- border WINDOW_BORDER_KCGRADIENT
- borderSize 2.0
- borderColor 0.5 0.5 0.5 1
- }
-
- //Section menus
- itemDef
- {
- name GameBtn
- text "Game"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 80 20 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_CENTER
- textalignx 34
- textaligny 18
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide optionsGrp;
- show game;
-
- setitemcolor gameBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor controlsBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor systemBtn forecolor 1.0 1.0 1.0 1.0
- }
- }
-
- itemDef
- {
- name controlsBtn
- text "Controls"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 160 20 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_CENTER
- textalignx 34
- textaligny 18
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide optionsGrp;
- show controls;
- show look;
-
- setitemcolor gameBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor controlsBtn forecolor 0.2 0.2 0.2 1.0;
- setitemcolor systemBtn forecolor 1.0 1.0 1.0 1.0
- }
- }
-
- itemDef
- {
- name systemBtn
- text "System"
- group menuGrp
- style WINDOW_STYLE_EMPTY
- rect 230 20 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_CENTER
- textalignx 34
- textaligny 18
- textscale .35
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- hide optionsGrp;
- show system;
- show ghardware;
-
- setitemcolor gameBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor controlsBtn forecolor 1.0 1.0 1.0 1.0;
- setitemcolor systemBtn forecolor 0.2 0.2 0.2 1.0
- }
- }
-
-//////// GAME
-
- itemDef
- {
- name game
- group optionsGrp
- type ITEM_TYPE_EDITFIELD
- style 0
- text "Name:"
- cvar "name"
- maxchars 31
- maxPaintChars 31
- rect 50 85 220 15
- textalign ITEM_ALIGN_LEFT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- }
-
- itemDef
- {
- name game
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Auto Download:"
- cvar "cl_allowDownload"
- rect 80 115 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name game
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Taunts Sounds Off:"
- cvar "cg_noTaunt"
- rect 80 130 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name game
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Team Chats Only:"
- cvar "cg_teamChatsOnly"
- rect 80 145 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name game
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Auto Wallwalk Pitching:"
- cvar "cg_wwFollow"
- rect 80 160 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name game
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Wallwalking Speed:"
- cvarfloat "cg_wwSmoothTime" 300 0 1000
- cvarFloatList { "Medium" 300 "Fast" 150 "Instant" 0 "Slow" 600 }
- rect 80 175 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name game
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Wallwalk Control Toggles:"
- cvar "cg_wwToggle"
- rect 80 190 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name game
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Disable Warning Dialogs:"
- cvar "cg_disableWarningDialogs"
- rect 80 205 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name game
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Tutorial Mode:"
- cvar "cg_tutorial"
- rect 80 220 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name game
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Show Clock:"
- cvar "cg_drawClock"
- cvarFloatList { "No" 0 "12 Hour" 1 "24 Hour" 2 }
- rect 80 235 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name game
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Draw Crosshair:"
- cvar "cg_drawCrosshair"
- cvarFloatList { "Never" 0 "Ranged Weapons Only" 1 "Always" 2 }
- rect 80 250 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
-//////// CONTROLS
-
- //Controls menu
- itemDef
- {
- name controls
- text "Look"
- group optionsGrp
- style WINDOW_STYLE_EMPTY
- rect 20 60 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide optionsGrp;
- show controls;
- show look
- }
- }
-
-//////// LOOK
-
- itemDef
- {
- name look
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Lookup:"
- cvar "+lookup"
- rect 96 85 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name look
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Look Down:"
- cvar "+lookdown"
- rect 96 100 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name look
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Mouse Look:"
- cvar "+mlook"
- rect 96 115 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name look
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Centerview:"
- cvar "centerview"
- rect 96 130 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name look
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Free Look:"
- cvar "cl_freelook"
- rect 96 145 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name look
- group optionsGrp
- type ITEM_TYPE_SLIDER
- text "Mouse Sensitivity:"
- cvarfloat "sensitivity" 5 1 30
- rect 96 160 192 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 15
- textscale .25
- forecolor 1 1 1 1
- visible 0
- }
-
- itemDef
- {
- name look
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Invert Mouse:"
- cvar "ui_mousePitch"
- rect 96 180 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript update ui_mousePitch
- }
- }
-
- itemDef
- {
- name look
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Smooth Mouse:"
- cvar "m_filter"
- rect 96 195 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
-//////// MOVE
-
- itemDef
- {
- name controls
- text "Move"
- group optionsGrp
- style WINDOW_STYLE_EMPTY
- rect 20 80 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide optionsGrp;
- show controls;
- show move
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Always Run:"
- cvar "cl_run"
- rect 96 65 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Run / Walk:"
- cvar "+speed"
- rect 96 80 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Sprint:"
- cvar "boost"
- rect 96 95 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Forward:"
- cvar "+forward"
- rect 96 110 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Backpedal:"
- cvar "+back"
- rect 96 125 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Move Left:"
- cvar "+moveleft"
- rect 96 140 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Move Right:"
- cvar "+moveright"
- rect 96 155 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Jump:"
- cvar "+moveup"
- rect 96 170 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Crouch:"
- cvar "+movedown"
- rect 96 185 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Turn Left:"
- cvar "+left"
- rect 96 200 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Turn Right:"
- cvar "+right"
- rect 96 215 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name move
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Strafe:"
- cvar "+strafe"
- rect 96 230 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
-
-
-//////// UPGRADES
-
- itemDef
- {
- name controls
- text "Upgrades"
- group optionsGrp
- style WINDOW_STYLE_EMPTY
- rect 20 100 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide optionsGrp;
- show controls;
- show upgrades
- }
- }
-
- itemDef
- {
- name upgrades
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Primary Attack:"
- cvar "+attack"
- rect 96 90 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name upgrades
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Secondary Attack:"
- cvar "+button5"
- rect 96 105 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name upgrades
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Previous Upgrade:"
- cvar "weapprev"
- rect 96 120 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name upgrades
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Next Upgrade:"
- cvar "weapnext"
- rect 96 135 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name upgrades
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Activate Upgrade:"
- cvar "+button2"
- rect 96 150 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name upgrades
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Reload:"
- cvar "reload"
- rect 96 165 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name upgrades
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Buy Ammo:"
- cvar "buy ammo"
- rect 96 180 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name upgrades
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Use Medkit:"
- cvar "itemact medkit"
- rect 96 195 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
-//////// MISC
-
- itemDef
- {
- name controls
- text "Misc"
- group optionsGrp
- style WINDOW_STYLE_EMPTY
- rect 20 120 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide optionsGrp;
- show controls;
- show misc
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Show Scores:"
- cvar "+scores"
- rect 96 65 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Scroll Scores Up:"
- cvar "scoresUp"
- rect 96 80 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Scroll Scores Down:"
- cvar "scoresDown"
- rect 96 95 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Use Structure/Evolve:"
- cvar "+button7"
- rect 96 110 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Deconstruct Structure:"
- cvar "deconstruct"
- rect 96 125 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Gesture:"
- cvar "+button3"
- rect 96 140 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Chat:"
- cvar "messagemode"
- rect 96 155 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Team Chat:"
- cvar "messagemode2"
- rect 96 170 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Target Chat:"
- cvar "messagemode3"
- rect 96 185 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Attack Chat:"
- cvar "messagemode4"
- rect 96 200 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Vote Yes:"
- cvar "vote yes"
- rect 96 215 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Vote No:"
- cvar "vote no"
- rect 96 230 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Team Vote Yes:"
- cvar "teamvote yes"
- rect 96 245 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name misc
- group optionsGrp
- type ITEM_TYPE_BIND
- text "Team Vote No:"
- cvar "teamvote no"
- rect 96 260 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- maxPaintChars 20
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
-
-
-//////// SYSTEM
-
- //System menu
- itemDef
- {
- name system
- text "GFX Hardware"
- group optionsGrp
- style WINDOW_STYLE_EMPTY
- rect 20 60 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide optionsGrp;
- show system;
- show ghardware
- }
- }
-
-//////// GFX HARDWARE
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Quality:"
- cvar "ui_glCustom"
- cvarFloatList { "High Quality" 0 "Normal" 1 "Fast" 2 "Fastest" 3 "Custom" 4 }
- rect 96 50 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript update "ui_glCustom"
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_EDITFIELD
- text "GL Driver:"
- cvar "r_gldriver"
- //cvarFloatList { }
- rect 96 65 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "GL Extensions:"
- cvar "r_allowExtensions"
- rect 96 80 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript glCuston
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Video Mode:"
- cvar "r_mode"
- cvarFloatList { "320x240" 0 "400x300" 1 "512x384" 2 "640x480" 3
- "800x600" 4 "960x720" 5 "1024x768" 6 "1152x864" 7
- "1280x1024" 8 "1600x1200" 9 "2048x1536" 10 "856x480 wide screen" 11 }
- rect 96 95 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript glCustom
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Color Depth:"
- cvar "r_colorbits"
- cvarFloatList { "Default" 0 "16 bit" 16 "32 bit" 32 }
- rect 96 110 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript glCustom;
- uiScript update "r_colorbits"
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Fullscreen:"
- cvar "r_fullscreen"
- rect 96 125 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript glCustom
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Lighting:"
- cvar "r_vertexlight"
- cvarFloatList { "Light Map (high)" 0 "Vertex (low)" 1 }
- rect 96 140 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript glCustom
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Geometric Detail:"
- cvar "r_lodbias"
- cvarFloatList { "High" 0 "Medium" 1 "Low" 2 }
- rect 96 155 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript glCustom;
- uiScript update "r_lodbias"
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Texture Detail:"
- cvar "r_picmip"
- cvarFloatList { "Low" 2 "Normal" 1 "High" 0 }
- rect 96 170 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript glCustom
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Texture Quality:"
- cvar "r_texturebits"
- cvarFloatList { "Default" 0 "16 bit" 16 "32 bit" 32 }
- rect 96 185 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Texture Filter:"
- cvar "r_texturemode"
- cvarStrList { "Bilinear", "GL_LINEAR_MIPMAP_NEAREST", "Trilinear", "GL_LINEAR_MIPMAP_LINEAR" }
- rect 96 200 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript glCustom
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Anisotropic Filtering:"
- cvar "r_ext_texture_filter_anisotropic"
- rect 96 215 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript glCustom
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Compress Textures:"
- cvar "r_ext_compressed_textures "
- rect 96 230 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- uiScript glCustom
- }
- }
-
- itemDef
- {
- name ghardware
- group optionsGrp
- type ITEM_TYPE_BUTTON
- text "APPLY"
- textscale .25
- style WINDOW_STYLE_EMPTY
- rect 144 245 75 20
- textalign ITEM_ALIGN_CENTER
- textalignx 37
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "vid_restart"
- }
- }
-
-//////// GFX SOFTWARE
-
- itemDef
- {
- name system
- text "GFX Software"
- group optionsGrp
- style WINDOW_STYLE_EMPTY
- rect 20 80 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide optionsGrp;
- show system;
- show gsoftware
- }
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_SLIDER
- text "Brightness:"
- cvarfloat "r_gamma" 1 .5 2
- rect 96 60 192 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 80
- textaligny 17
- textscale .25
- forecolor 1 1 1 1
- visible 0
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_SLIDER
- text "Screen Size:"
- cvarfloat "cg_viewsize" 100 30 100
- //cvarFloatList { }
- rect 96 80 192 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 80
- textaligny 17
- textscale .25
- forecolor 1 1 1 1
- visible 0
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Simple Items:"
- cvar "cg_simpleItems"
- rect 96 100 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Marks On Walls:"
- cvar "cg_marks"
- rect 96 115 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Dynamic Lights:"
- cvar "r_dynamiclight"
- rect 96 130 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Draw Gun:"
- cvar "cg_drawGun"
- rect 96 145 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Low Quality Sky:"
- cvar "r_fastsky"
- rect 96 160 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Sync Every Frame:"
- cvar "weapon 5"
- rect 96 175 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Show Time:"
- cvar "cg_drawTimer"
- rect 96 190 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "In Game Videos:"
- cvar "r_inGameVideo"
- rect 96 205 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Depth Sort Particles:"
- cvar "cg_depthSortParticles"
- rect 96 220 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Particle Physics:"
- cvar "cg_bounceParticles"
- cvarFloatList { "Low Quality" 0 "High Quality" 1 }
- rect 96 235 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name gsoftware
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Light Flares:"
- cvar "cg_lightFlare"
- cvarFloatList { "Off" 0 "No Fade" 1 "Timed Fade" 2 "Real Fade" 3 }
- rect 96 250 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
-//////// GL INFO
-
- itemDef
- {
- name system
- text "GL Info"
- group optionsGrp
- style WINDOW_STYLE_EMPTY
- rect 20 100 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide optionsGrp;
- show system;
- show glinfo
- }
- }
-
- itemDef
- {
- name glinfo
- group optionsGrp
- rect 104 35 230 230
- ownerdraw UI_GLINFO
- textalign 1
- textscale .15
- textalignx 0
- textaligny 17
- forecolor 1 1 1 1
- visible 0
- decoration
- }
-
-//////// NET & SOUND
-
- itemDef
- {
- name system
- text "Net & Sound"
- group optionsGrp
- style WINDOW_STYLE_EMPTY
- rect 20 120 64 20
- type ITEM_TYPE_BUTTON
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 16
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- hide optionsGrp;
- show system;
- show netsound
- }
- }
-
- itemDef
- {
- name netsound
- group optionsGrp
- style 1
- text "Sound"
- rect 96 50 192 20
- textalign ITEM_ALIGN_CENTER
- textalignx 80
- textaligny 17
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name netsound
- group optionsGrp
- type ITEM_TYPE_SLIDER
- text "Effects Volume:"
- cvarfloat "s_volume" 0.7 0 1
- rect 96 70 192 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- textaligny 17
- textscale .25
- forecolor 1 1 1 1
- visible 0
- }
-
- itemDef
- {
- name netsound
- group optionsGrp
- type ITEM_TYPE_SLIDER
- text "Music Volume:"
- cvarfloat "s_musicvolume" 0.25 0 1
- rect 96 90 192 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 90
- textaligny 17
- textscale .25
- forecolor 1 1 1 1
- visible 0
- }
-
- itemDef
- {
- name netsound
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "OpenAL:"
- cvar "s_useOpenAL"
- rect 96 120 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name netsound
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Sound Quality:"
- cvar "s_khz"
- cvarFloatList { "44 khz (very high)" 44 "22 khz (high)" 22 "11 khz (low)" 11 }
- rect 96 135 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name netsound
- group optionsGrp
- type ITEM_TYPE_YESNO
- text "Doppler Sound:"
- cvar "s_doppler"
- rect 96 150 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name netsound
- group optionsGrp
- type ITEM_TYPE_BUTTON
- text "APPLY"
- textscale .25
- style WINDOW_STYLE_EMPTY
- rect 155 170 75 20
- textalign ITEM_ALIGN_CENTER
- textalignx 37
- textaligny 15
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- exec "snd_restart"
- }
- }
-
-
- itemDef
- {
- name netsound
- group optionsGrp
- style 1
- text "Network"
- rect 96 200 192 20
- textalign ITEM_ALIGN_CENTER
- textalignx 80
- textaligny 17
- textscale .25
- forecolor 1 1 1 1
- visible 0
- decoration
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- name netsound
- group optionsGrp
- type ITEM_TYPE_MULTI
- text "Net Data Rate:"
- cvar "rate"
- cvarFloatList { "<=28.8k" 2500 "33.6k" 3000 "56k" 4000 "ISDN" 5000 "LAN/CABLE/xDSl" 25000 }
- rect 96 220 192 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 100
- textaligny 17
- textscale .25
- forecolor 1 1 1 1
- visible 0
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
- }
-}
diff --git a/ui/joinserver.menu b/ui/joinserver.menu
deleted file mode 100644
index 35439e1..0000000
--- a/ui/joinserver.menu
+++ /dev/null
@@ -1,687 +0,0 @@
-#include "ui/menudef.h"
-
-{
-
- \\ Server Join \\
-
- menuDef
- {
- name "joinserver"
- visible 0
- fullscreen 1
- rect 0 0 640 480
- focusColor 1 .75 0 1
- outOfBoundsClick
- style 0
- onOpen
- {
- uiScript InitServerList 3;
- hide accept_alt;
- show accept;
- hide back_alt;
- show back;
- hide grpmessage;
- uiScript UpdateFilter
- }
-
- onEsc { uiScript closeJoin }
-
- itemDef
- {
- name background
- rect 0 0 640 480
- style WINDOW_STYLE_FILLED
- backcolor 0 0 0 1
- visible 1
- decoration
- }
-
- // DATE AND MESSAGE OF THE DAY //
-
- itemDef
- {
- name datewindow
- rect 10 365 265 25
- style WINDOW_STYLE_FILLED
- border 1
- bordercolor .5 .5 .5 1
- backcolor 0 0 0 .15
- visible 1
- }
-
- itemDef
- {
- name messagewindow
- rect 275 365 355 25
- style WINDOW_STYLE_FILLED
- border 1
- bordercolor .5 .5 .5 1
- backcolor 0 0 0 .15
- visible 1
- }
-
- itemDef
- {
- name refreshdate
- ownerdraw UI_SERVERREFRESHDATE
- textscale .33
- rect 10 365 265 25
- textalign 0
- textalignx 10
- textaligny 20
- forecolor 1 1 1 1
- visible 1
- decoration
- }
-
- itemDef
- {
- name messageoftheday
- ownerdraw UI_SERVERMOTD
- textscale .33
- rect 280 365 345 25
- forecolor 1 1 1 1
- visible 1
- decoration
- }
-
-
- // VIEW OPTIONS //
-
- itemDef
- {
- name gametypefield
- style WINDOW_STYLE_EMPTY
- ownerdraw UI_NETSOURCE
- rect 26 20 128 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 22
- textscale .4
- forecolor 1 1 1 1
- backcolor .5 .5 .5 .5
- visible 1
- action
- {
- play "sound/misc/menu1.wav"
- }
- }
-
- // BUTTONS //
-
- itemDef
- {
- name refreshSource
- text "Get New List"
- type ITEM_TYPE_BUTTON
- textscale .4
- style WINDOW_STYLE_EMPTY
- rect 190 20 128 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 22
- backcolor .5 .5 .5 .5
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript RefreshServers
- }
- }
-
- itemDef
- {
- name refreshFilter
- text "Refresh List"
- textscale .4
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_BUTTON
- rect 354 20 128 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 22
- backcolor .5 .5 .5 .5
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript RefreshFilter
- }
- }
-
- itemDef
- {
- name viewEmpty
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_YESNO
- text "View Empty:"
- cvar "ui_browserShowEmpty"
- textscale .4
- rect 26 50 128 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 22
- forecolor 1 1 1 1
- backcolor .5 .5 .5 .5
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript RefreshFilter
- }
- }
-
- itemDef
- {
- name viewFull
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_YESNO
- text "View Full:"
- cvar "ui_browserShowFull"
- textscale .4
- rect 190 50 128 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 22
- forecolor 1 1 1 1
- backcolor .5 .5 .5 .5
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript RefreshFilter
- }
- }
-
-
- // map selection
-
- itemDef
- {
- name mappreview
- style 0
- ownerdraw UI_NETMAPCINEMATIC
- rect 502 5 128 96
- border 1
- bordercolor 0 .5 0 .5
- visible 1
- }
-
- itemDef
- {
- name mappreview
- style WINDOW_STYLE_FILLED
- rect 502 5 128 96
- border 1
- bordercolor .5 .5 .5 .5
- visible 1
- }
-
- // COLUMNS //
-
- itemDef
- {
- name serverColumn
- group grpColumn
- rect 10 130 365 232
- style WINDOW_STYLE_FILLED
- border 1
- backcolor 0 0 0 0
- bordersize 1
- bordercolor .5 .5 .5 1
- visible 1
- decoration
- }
-
- itemDef
- {
- name mapColumn
- group grpColumn
- rect 375 130 125 232
- style WINDOW_STYLE_FILLED
- border 1
- backcolor 0 0 0 0
- bordersize 1
- bordercolor .5 .5 .5 1
- visible 1
- decoration
- }
-
- itemDef
- {
- name playerColumn
- group grpColumn
- rect 500 130 60 232
- style WINDOW_STYLE_FILLED
- border 1
- backcolor 0 0 0 0
- bordersize 1
- bordercolor .5 .5 .5 1
- visible 1
- decoration
- }
-
- itemDef
- {
- name pingColumn
- group grpColumn
- rect 560 130 52 232
- style WINDOW_STYLE_FILLED
- border 1
- backcolor 0 0 0 0
- bordersize 1
- bordercolor .5 .5 .5 1
- visible 1
- decoration
- }
-
- itemDef
- {
- name serverlist
- rect 10 130 620 232
- type ITEM_TYPE_LISTBOX
- style WINDOW_STYLE_EMPTY
- elementwidth 120
- elementheight 20
- textscale .33
- elementtype LISTBOX_TEXT
- feeder FEEDER_SERVERS
- border 1
- bordercolor 0.5 0.5 0.5 1
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 1
- columns 4
- 2 40 80 ITEM_ALIGN_LEFT
- 375 40 20 ITEM_ALIGN_LEFT
- 500 5 10 ITEM_ALIGN_LEFT
- 560 20 20 ITEM_ALIGN_LEFT
-
- doubleClick { uiScript JoinServer }
- }
-
-
- // SORT TABS //
-
- itemDef
- {
- name server
- group grpTabs
- text "Server Name"
- type ITEM_TYPE_BUTTON
- textscale .33
- style WINDOW_STYLE_EMPTY
- rect 10 103 365 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 18
- border 1
- bordercolor 0.5 0.5 0.5 1
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript ServerSort 0;
-
- setitemcolor grpColumn backcolor 0 0 0 0;
- setitemcolor serverColumn backcolor 0.3 1 1 0.5
- }
- }
-
- itemDef
- {
- name map
- group grpTabs
- type ITEM_TYPE_BUTTON
- text "Map Name"
- textscale .33
- style WINDOW_STYLE_EMPTY
- rect 375 103 125 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 18
- border 1
- bordercolor 0.5 0.5 0.5 1
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript ServerSort 1;
-
- setitemcolor grpColumn backcolor 0 0 0 0;
- setitemcolor mapColumn backcolor 0.3 1 1 0.5
- }
- }
-
- itemDef
- {
- name Players
- group grpTabs
- text "Players"
- type ITEM_TYPE_BUTTON
- textscale .33
- style WINDOW_STYLE_EMPTY
- rect 500 103 60 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 18
- border 1
- bordercolor 0.5 0.5 0.5 1
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript ServerSort 2;
-
- setitemcolor grpColumn backcolor 0 0 0 0;
- setitemcolor playerColumn backcolor 0.3 1 1 0.5
- }
- }
-
-
- itemDef
- {
- name Ping
- group grpTabs
- text "Ping"
- type ITEM_TYPE_BUTTON
- textscale .33
- style WINDOW_STYLE_EMPTY
- rect 560 103 70 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 18
- border 1
- bordercolor 0.5 0.5 0.5 1
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript ServerSort 3;
-
- setitemcolor grpColumn backcolor 0 0 0 0;
- setitemcolor pingColumn backcolor 0.3 1 1 0.5
- }
- }
-
-
- itemDef
- {
- name password
- text "Password"
- type ITEM_TYPE_BUTTON
- textscale .4
- style WINDOW_STYLE_FILLED
- rect 20 395 92 26
- textalign 1
- textalignx 46 // center
- textaligny 22
- backcolor 0 0 0 1
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- open password_popmenu
- }
- }
-
- itemDef
- {
- name createFavorite
- text "New Favorite"
- type ITEM_TYPE_BUTTON
- textscale .4
- style WINDOW_STYLE_FILLED
- rect 148 395 92 26
- textalign 1
- textalignx 46 // center
- textaligny 22
- backcolor 0 0 0 1
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- open createfavorite_popmenu
- }
- }
-
- itemDef
- {
- name addFavorite
- text "Add Favorite"
- type ITEM_TYPE_BUTTON
- textscale .4
- style WINDOW_STYLE_FILLED
- ownerdrawFlag UI_SHOW_NOTFAVORITESERVERS
- rect 276 395 92 26
- textalign 1
- textalignx 46 // center
- textaligny 22
- backcolor 0 0 0 1
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript addFavorite
- }
- }
-
- itemDef
- {
- name delfavorite
- text "Del. Favorite"
- type ITEM_TYPE_BUTTON
- textscale .4
- style WINDOW_STYLE_FILLED
- ownerdrawFlag UI_SHOW_FAVORITESERVERS
- rect 276 395 92 26
- textalign 1
- textalignx 46 // center
- textaligny 22
- backcolor 0 0 0 1
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript DeleteFavorite;
- uiScript UpdateFilter
- }
- }
-
- itemDef
- {
- name serverinfo
- text "Server Info"
- type ITEM_TYPE_BUTTON
- textscale .4
- style WINDOW_STYLE_FILLED
- rect 404 395 92 26
- textalign 1
- textalignx 46 // center
- textaligny 22
- backcolor 0 0 0 1
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- open serverinfo_popmenu
- }
- }
-
- itemDef
- {
- name findplayer
- text "Find Friend"
- type ITEM_TYPE_BUTTON
- textscale .4
- style WINDOW_STYLE_FILLED
- rect 532 395 92 26
- textalign 1
- textalignx 46 // center
- textaligny 22
- backcolor 0 0 0 1
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- open findplayer_popmenu
- }
- }
-
-
-
- itemDef
- {
- name createServer
- text "Create Server"
- textscale .5
- style WINDOW_STYLE_EMPTY
- type ITEM_TYPE_BUTTON
- rect 254 436 128 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 24
- backcolor .5 .5 .5 .5
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- close joinserver;
- open createserver
- }
- }
-
-
- // BACK BAR //
-
- itemDef
- {
- name back
- style 3
- background "ui/assets/backarrow.tga"
- rect 16 424 50 50
- visible 1
- action
- {
- play "sound/misc/menu4.wav";
- close joinserver;
- open main
- }
-
- mouseEnter
- {
- hide back;
- show back_alt
- }
- }
-
- itemDef
- {
- name back_alt
- style WINDOW_STYLE_SHADER
- background "ui/assets/backarrow_alt.tga"
- rect 16 424 50 50
- backcolor 0 0 0 0
- forecolor 1 1 1 1
- visible 0
- type ITEM_TYPE_BUTTON
-
- text "Back"
- textalign ITEM_ALIGN_LEFT
- textaligny 36
- textalignx 60
- textscale .6
-
- mouseExit
- {
- hide back_alt;
- show back
- }
-
- action
- {
- play "sound/misc/menu4.wav";
- close joinserver;
- open main
- }
- }
-
-
-
-
- itemDef
- {
- name accept
- style 3
- rect 574 424 50 50
- background "ui/assets/forwardarrow.tga"
- backcolor 0 0 0 0
- forecolor 1 1 1 1
- visible 1
- mouseEnter
- {
- hide accept;
- show accept_alt
- }
-
- action
- {
- play "sound/misc/menu1.wav";
- uiScript JoinServer
- }
- }
-
- itemDef
- {
- name accept_alt
- style WINDOW_STYLE_SHADER
- rect 574 424 50 50
- background "ui/assets/forwardarrow_alt.tga"
- backcolor 0 0 0 0
- type ITEM_TYPE_BUTTON
- forecolor 1 1 1 1
- visible 0
- type ITEM_TYPE_BUTTON
-
- text "Join"
- textalign ITEM_ALIGN_LEFT
- textaligny 36
- textalignx -55
- textscale .6
-
- mouseExit
- {
- hide accept_alt;
- show accept
- }
-
- action
- {
- play "sound/misc/menu1.wav";
- uiScript JoinServer
- }
- }
- }
-}
diff --git a/ui/main.menu b/ui/main.menu
deleted file mode 100644
index 488fe69..0000000
--- a/ui/main.menu
+++ /dev/null
@@ -1,163 +0,0 @@
-#include "ui/menudef.h"
-
-{
- assetGlobalDef
- {
- font "fonts/font" 26 // font
- smallFont "fonts/smallfont" 20 // font
- bigFont "fonts/bigfont" 34 // font
- cursor "ui/assets/3_cursor3" // cursor
- gradientBar "ui/assets/gradientbar2.tga" // gradient bar
- itemFocusSound "sound/misc/menu2.wav" // sound for item getting focus (via keyboard or mouse )
-
- fadeClamp 1.0 // sets the fadeup alpha
- fadeCycle 1 // how often fade happens in milliseconds
- fadeAmount 0.1 // amount to adjust alpha per cycle
-
- shadowColor 0.1 0.1 0.1 0.25 // shadow color
- }
-
-
-
-
-
- menuDef
- {
- name main
- fullScreen MENU_TRUE
- rect 0 0 640 480 // Size and position of the menu
- visible MENU_TRUE // Visible on open
- focusColor 1 .75 0 1 // Menu focus color for text and items
-
- onOpen { uiScript stopRefresh ; playlooped "sound/ui/heartbeat.wav" }
- onESC { open quit_popmenu }
-
- itemDef
- {
- name background
- rect 0 0 640 480
- style WINDOW_STYLE_SHADER
- backcolor 0 0 0 1
- visible 1
- decoration
- background "ui/assets/mainmenu.jpg"
- }
-
- itemDef
- {
- name splashmodel
- rect 0 0 640 480
- type ITEM_TYPE_MODEL
- style WINDOW_STYLE_EMPTY
- asset_model "models/splash/splash_screen.md3"
- model_fovx 32.0
- model_fovy 24.0
- model_angle 180
- visible 1
- decoration
- }
-
- itemDef
- {
- name mainmenu
- text "Play"
- type ITEM_TYPE_BUTTON
- style WINDOW_STYLE_EMPTY
- textstyle ITEM_TEXTSTYLE_NORMAL
- rect 472 20 128 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 128
- textaligny 20
- textscale .416
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- close main;
- open joinserver
- }
- }
-
- itemDef
- {
- name mainmenu
- text "Options"
- type ITEM_TYPE_BUTTON
- style WINDOW_STYLE_EMPTY
- textstyle ITEM_TEXTSTYLE_NORMAL
- textscale .416
- rect 472 40 128 20
- textalignx 128
- textaligny 20
- textalign ITEM_ALIGN_RIGHT
- backcolor 0 0 0 0
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- open simple_options
- }
- }
-
- itemDef
- {
- name mainmenu
- text "Mods"
- type ITEM_TYPE_BUTTON
- style WINDOW_STYLE_EMPTY
- textstyle ITEM_TEXTSTYLE_NORMAL
- textscale .416
- rect 472 60 128 20
- textalignx 128
- textaligny 20
- textalign ITEM_ALIGN_RIGHT
- backcolor 0 0 0 0
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- open mod
- }
- }
-
- itemDef
- {
- name mainmenu
- text "Quit"
- type ITEM_TYPE_BUTTON
- style WINDOW_STYLE_EMPTY
- textstyle ITEM_TEXTSTYLE_NORMAL
- rect 472 80 128 20
- textalignx 128
- textaligny 20
- textscale .416
- textalign ITEM_ALIGN_RIGHT
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- open quit_popmenu
- }
- }
-
- itemDef
- {
- name copyright
- text "Tremulous (C) 2005-2006 darklegion development"
- style WINDOW_STYLE_EMPTY
- textstyle ITEM_TEXTSTYLE_NORMAL
- textscale .25
- rect 0 440 640 40
- textalign 1
- textaligny 32
- textalignx 320
- forecolor .75 .75 .75 .75
- visible 1
- decoration
- }
- }
-}
diff --git a/ui/menudef.h b/ui/menudef.h
deleted file mode 100644
index dbd0996..0000000
--- a/ui/menudef.h
+++ /dev/null
@@ -1,363 +0,0 @@
-
-#define ITEM_TYPE_TEXT 0 // simple text
-#define ITEM_TYPE_BUTTON 1 // button, basically text with a border
-#define ITEM_TYPE_RADIOBUTTON 2 // toggle button, may be grouped
-#define ITEM_TYPE_CHECKBOX 3 // check box
-#define ITEM_TYPE_EDITFIELD 4 // editable text, associated with a cvar
-#define ITEM_TYPE_SAYFIELD 5 // the chat field
-#define ITEM_TYPE_COMBO 6 // drop down list
-#define ITEM_TYPE_LISTBOX 7 // scrollable list
-#define ITEM_TYPE_MODEL 8 // model
-#define ITEM_TYPE_OWNERDRAW 9 // owner draw, name specs what it is
-#define ITEM_TYPE_NUMERICFIELD 10 // editable text, associated with a cvar
-#define ITEM_TYPE_SLIDER 11 // mouse speed, volume, etc.
-#define ITEM_TYPE_YESNO 12 // yes no cvar setting
-#define ITEM_TYPE_MULTI 13 // multiple list setting, enumerated
-#define ITEM_TYPE_BIND 14 // multiple list setting, enumerated
-
-#define ITEM_ALIGN_LEFT 0 // left alignment
-#define ITEM_ALIGN_CENTER 1 // center alignment
-#define ITEM_ALIGN_RIGHT 2 // right alignment
-
-#define ITEM_TEXTSTYLE_NORMAL 0 // normal text
-#define ITEM_TEXTSTYLE_BLINK 1 // fast blinking
-#define ITEM_TEXTSTYLE_PULSE 2 // slow pulsing
-#define ITEM_TEXTSTYLE_SHADOWED 3 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_OUTLINED 4 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_OUTLINESHADOWED 5 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_SHADOWEDMORE 6 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_NEON 7 // drop shadow ( need a color for this )
-
-#define WINDOW_BORDER_NONE 0 // no border
-#define WINDOW_BORDER_FULL 1 // full border based on border color ( single pixel )
-#define WINDOW_BORDER_HORZ 2 // horizontal borders only
-#define WINDOW_BORDER_VERT 3 // vertical borders only
-#define WINDOW_BORDER_KCGRADIENT 4 // horizontal border using the gradient bars
-
-#define WINDOW_STYLE_EMPTY 0 // no background
-#define WINDOW_STYLE_FILLED 1 // filled with background color
-#define WINDOW_STYLE_GRADIENT 2 // gradient bar based on background color
-#define WINDOW_STYLE_SHADER 3 // gradient bar based on background color
-#define WINDOW_STYLE_TEAMCOLOR 4 // team color
-#define WINDOW_STYLE_CINEMATIC 5 // cinematic
-
-#define MENU_TRUE 1 // uh.. true
-#define MENU_FALSE 0 // and false
-
-#define HUD_VERTICAL 0x00
-#define HUD_HORIZONTAL 0x01
-
-// list box element types
-#define LISTBOX_TEXT 0x00
-#define LISTBOX_IMAGE 0x01
-
-// list feeders
-#define FEEDER_HEADS 0x00 // model heads
-#define FEEDER_MAPS 0x01 // text maps based on game type
-#define FEEDER_SERVERS 0x02 // servers
-#define FEEDER_CLANS 0x03 // clan names
-#define FEEDER_ALLMAPS 0x04 // all maps available, in graphic format
-#define FEEDER_ALIENTEAM_LIST 0x05 // red team members
-#define FEEDER_HUMANTEAM_LIST 0x06 // blue team members
-#define FEEDER_PLAYER_LIST 0x07 // players
-#define FEEDER_TEAM_LIST 0x08 // team members for team voting
-#define FEEDER_MODS 0x09 // team members for team voting
-#define FEEDER_DEMOS 0x0a // team members for team voting
-#define FEEDER_SCOREBOARD 0x0b // team members for team voting
-#define FEEDER_Q3HEADS 0x0c // model heads
-#define FEEDER_SERVERSTATUS 0x0d // server status
-#define FEEDER_FINDPLAYER 0x0e // find player
-#define FEEDER_CINEMATICS 0x0f // cinematics
-
-//TA: tremulous menus
-#define FEEDER_TREMTEAMS 0x10 //teams
-#define FEEDER_TREMALIENCLASSES 0x11 //alien classes
-#define FEEDER_TREMHUMANITEMS 0x12 //human items
-#define FEEDER_TREMHUMANARMOURYBUY 0x13 //human buy
-#define FEEDER_TREMHUMANARMOURYSELL 0x14 //human sell
-#define FEEDER_TREMALIENUPGRADE 0x15 //alien upgrade
-#define FEEDER_TREMALIENBUILD 0x16 //alien buildables
-#define FEEDER_TREMHUMANBUILD 0x17 //human buildables
-//TA: tremulous menus
-#define FEEDER_IGNORE_LIST 0x18 //ignored players
-
-// display flags
-#define CG_SHOW_BLUE_TEAM_HAS_REDFLAG 0x00000001
-#define CG_SHOW_RED_TEAM_HAS_BLUEFLAG 0x00000002
-#define CG_SHOW_ANYTEAMGAME 0x00000004
-#define CG_SHOW_HARVESTER 0x00000008
-#define CG_SHOW_ONEFLAG 0x00000010
-#define CG_SHOW_CTF 0x00000020
-#define CG_SHOW_OBELISK 0x00000040
-#define CG_SHOW_HEALTHCRITICAL 0x00000080
-#define CG_SHOW_SINGLEPLAYER 0x00000100
-#define CG_SHOW_TOURNAMENT 0x00000200
-#define CG_SHOW_DURINGINCOMINGVOICE 0x00000400
-#define CG_SHOW_IF_PLAYER_HAS_FLAG 0x00000800
-#define CG_SHOW_LANPLAYONLY 0x00001000
-#define CG_SHOW_MINED 0x00002000
-#define CG_SHOW_HEALTHOK 0x00004000
-#define CG_SHOW_TEAMINFO 0x00008000
-#define CG_SHOW_NOTEAMINFO 0x00010000
-#define CG_SHOW_OTHERTEAMHASFLAG 0x00020000
-#define CG_SHOW_YOURTEAMHASENEMYFLAG 0x00040000
-#define CG_SHOW_ANYNONTEAMGAME 0x00080000
-#define CG_SHOW_2DONLY 0x10000000
-
-
-#define UI_SHOW_LEADER 0x00000001
-#define UI_SHOW_NOTLEADER 0x00000002
-#define UI_SHOW_FAVORITESERVERS 0x00000004
-#define UI_SHOW_ANYNONTEAMGAME 0x00000008
-#define UI_SHOW_ANYTEAMGAME 0x00000010
-#define UI_SHOW_NEWHIGHSCORE 0x00000020
-#define UI_SHOW_DEMOAVAILABLE 0x00000040
-#define UI_SHOW_NEWBESTTIME 0x00000080
-#define UI_SHOW_FFA 0x00000100
-#define UI_SHOW_NOTFFA 0x00000200
-#define UI_SHOW_NETANYNONTEAMGAME 0x00000400
-#define UI_SHOW_NETANYTEAMGAME 0x00000800
-#define UI_SHOW_NOTFAVORITESERVERS 0x00001000
-
-#define UI_SHOW_VOTEACTIVE 0x00002000
-#define UI_SHOW_CANVOTE 0x00004000
-#define UI_SHOW_TEAMVOTEACTIVE 0x00008000
-#define UI_SHOW_CANTEAMVOTE 0x00010000
-
-#define UI_SHOW_NOTSPECTATING 0x00020000
-
-// owner draw types
-// ideally these should be done outside of this file but
-// this makes it much easier for the macro expansion to
-// convert them for the designers ( from the .menu files )
-#define CG_OWNERDRAW_BASE 1
-#define CG_PLAYER_ARMOR_ICON 1
-#define CG_PLAYER_ARMOR_VALUE 2
-#define CG_PLAYER_HEAD 3
-#define CG_PLAYER_HEALTH 4
-#define CG_PLAYER_HEALTH_BAR 92
-#define CG_PLAYER_HEALTH_CROSS 99
-#define CG_PLAYER_AMMO_ICON 5
-#define CG_PLAYER_AMMO_VALUE 6
-#define CG_PLAYER_CLIPS_VALUE 70
-#define CG_PLAYER_BUILD_TIMER 115
-#define CG_PLAYER_CREDITS_VALUE 71
-#define CG_PLAYER_BANK_VALUE 72
-#define CG_PLAYER_CREDITS_VALUE_NOPAD 106
-#define CG_PLAYER_BANK_VALUE_NOPAD 107
-#define CG_PLAYER_STAMINA 73
-#define CG_PLAYER_STAMINA_1 93
-#define CG_PLAYER_STAMINA_2 94
-#define CG_PLAYER_STAMINA_3 95
-#define CG_PLAYER_STAMINA_4 96
-#define CG_PLAYER_STAMINA_BOLT 97
-#define CG_PLAYER_BOOST_BOLT 112
-#define CG_PLAYER_CLIPS_RING 98
-#define CG_PLAYER_BUILD_TIMER_RING 113
-#define CG_PLAYER_SELECT 74
-#define CG_PLAYER_SELECTTEXT 75
-#define CG_PLAYER_WEAPONICON 111
-#define CG_PLAYER_WALLCLIMBING 103
-#define CG_PLAYER_BOOSTED 104
-#define CG_PLAYER_POISON_BARBS 105
-#define CG_PLAYER_ALIEN_SENSE 108
-#define CG_PLAYER_HUMAN_SCANNER 109
-#define CG_PLAYER_USABLE_BUILDABLE 110
-#define CG_SELECTEDPLAYER_HEAD 7
-#define CG_SELECTEDPLAYER_NAME 8
-#define CG_SELECTEDPLAYER_LOCATION 9
-#define CG_SELECTEDPLAYER_STATUS 10
-#define CG_SELECTEDPLAYER_WEAPON 11
-#define CG_SELECTEDPLAYER_POWERUP 12
-
-#define CG_FLAGCARRIER_HEAD 13
-#define CG_FLAGCARRIER_NAME 14
-#define CG_FLAGCARRIER_LOCATION 15
-#define CG_FLAGCARRIER_STATUS 16
-#define CG_FLAGCARRIER_WEAPON 17
-#define CG_FLAGCARRIER_POWERUP 18
-
-#define CG_PLAYER_ITEM 19
-#define CG_PLAYER_SCORE 20
-
-#define CG_BLUE_FLAGHEAD 21
-#define CG_BLUE_FLAGSTATUS 22
-#define CG_BLUE_FLAGNAME 23
-#define CG_RED_FLAGHEAD 24
-#define CG_RED_FLAGSTATUS 25
-#define CG_RED_FLAGNAME 26
-
-#define CG_BLUE_SCORE 27
-#define CG_RED_SCORE 28
-#define CG_RED_NAME 29
-#define CG_BLUE_NAME 30
-#define CG_HARVESTER_SKULLS 31 // only shows in harvester
-#define CG_ONEFLAG_STATUS 32 // only shows in one flag
-#define CG_PLAYER_LOCATION 33
-#define CG_TEAM_COLOR 34
-#define CG_CTF_POWERUP 35
-
-#define CG_AREA_POWERUP 36
-#define CG_AREA_LAGOMETER 37 // painted with old system
-#define CG_PLAYER_HASFLAG 38
-#define CG_GAME_TYPE 39 // not done
-
-#define CG_SELECTEDPLAYER_ARMOR 40
-#define CG_SELECTEDPLAYER_HEALTH 41
-#define CG_PLAYER_STATUS 42
-#define CG_FRAGGED_MSG 43 // painted with old system
-#define CG_PROXMINED_MSG 44 // painted with old system
-#define CG_AREA_FPSINFO 45 // painted with old system
-#define CG_GAME_STATUS 49
-#define CG_KILLER 50
-#define CG_PLAYER_ARMOR_ICON2D 51
-#define CG_PLAYER_AMMO_ICON2D 52
-#define CG_ACCURACY 53
-#define CG_ASSISTS 54
-#define CG_DEFEND 55
-#define CG_EXCELLENT 56
-#define CG_IMPRESSIVE 57
-#define CG_PERFECT 58
-#define CG_GAUNTLET 59
-#define CG_SPECTATORS 60
-#define CG_TEAMINFO 61
-#define CG_VOICE_HEAD 62
-#define CG_VOICE_NAME 63
-#define CG_PLAYER_HASFLAG2D 64
-#define CG_HARVESTER_SKULLS2D 65 // only shows in harvester
-#define CG_CAPFRAGLIMIT 66
-#define CG_1STPLACE 67
-#define CG_2NDPLACE 68
-#define CG_CAPTURES 69
-
-//TA: loading screen
-#define CG_LOAD_LEVELSHOT 76
-#define CG_LOAD_MEDIA 77
-#define CG_LOAD_MEDIA_LABEL 78
-#define CG_LOAD_BUILDABLES 79
-#define CG_LOAD_BUILDABLES_LABEL 80
-#define CG_LOAD_CHARMODEL 81
-#define CG_LOAD_CHARMODEL_LABEL 82
-#define CG_LOAD_OVERALL 83
-#define CG_LOAD_LEVELNAME 84
-#define CG_LOAD_MOTD 85
-#define CG_LOAD_HOSTNAME 86
-
-#define CG_FPS 87
-#define CG_FPS_FIXED 100
-#define CG_TIMER 88
-#define CG_TIMER_MINS 101
-#define CG_TIMER_SECS 102
-#define CG_SNAPSHOT 89
-#define CG_LAGOMETER 90
-#define CG_PLAYER_CROSSHAIRNAMES 114
-#define CG_STAGE_REPORT_TEXT 116
-#define CG_DEMO_PLAYBACK 117
-#define CG_DEMO_RECORDING 118
-
-#define CG_CONSOLE 91
-#define CG_TUTORIAL 119
-#define CG_CLOCK 120
-
-
-
-#define UI_OWNERDRAW_BASE 200
-#define UI_HANDICAP 200
-#define UI_PLAYERMODEL 202
-#define UI_CLANNAME 203
-#define UI_CLANLOGO 204
-#define UI_GAMETYPE 205
-#define UI_MAPPREVIEW 206
-#define UI_SKILL 207
-#define UI_BLUETEAMNAME 208
-#define UI_REDTEAMNAME 209
-#define UI_BLUETEAM1 210
-#define UI_BLUETEAM2 211
-#define UI_BLUETEAM3 212
-#define UI_BLUETEAM4 213
-#define UI_BLUETEAM5 214
-#define UI_REDTEAM1 215
-#define UI_REDTEAM2 216
-#define UI_REDTEAM3 217
-#define UI_REDTEAM4 218
-#define UI_REDTEAM5 219
-#define UI_NETSOURCE 220
-#define UI_NETMAPPREVIEW 221
-#define UI_NETFILTER 222
-#define UI_TIER 223
-#define UI_OPPONENTMODEL 224
-#define UI_TIERMAP1 225
-#define UI_TIERMAP2 226
-#define UI_TIERMAP3 227
-#define UI_PLAYERLOGO 228
-#define UI_OPPONENTLOGO 229
-#define UI_PLAYERLOGO_METAL 230
-#define UI_OPPONENTLOGO_METAL 231
-#define UI_PLAYERLOGO_NAME 232
-#define UI_OPPONENTLOGO_NAME 233
-#define UI_TIER_MAPNAME 234
-#define UI_TIER_GAMETYPE 235
-#define UI_ALLMAPS_SELECTION 236
-#define UI_OPPONENT_NAME 237
-#define UI_VOTE_KICK 238
-#define UI_BOTNAME 239
-#define UI_BOTSKILL 240
-#define UI_REDBLUE 241
-#define UI_SELECTEDPLAYER 243
-#define UI_MAPCINEMATIC 244
-#define UI_NETGAMETYPE 245
-#define UI_NETMAPCINEMATIC 246
-#define UI_SERVERREFRESHDATE 247
-#define UI_SERVERMOTD 248
-#define UI_GLINFO 249
-#define UI_KEYBINDSTATUS 250
-#define UI_CLANCINEMATIC 251
-#define UI_MAP_TIMETOBEAT 252
-#define UI_JOINGAMETYPE 253
-#define UI_PREVIEWCINEMATIC 254
-#define UI_STARTMAPCINEMATIC 255
-#define UI_MAPS_SELECTION 256
-
-//TA:
-//#define UI_DIALOG 257
-#define UI_TEAMINFOPANE 258
-#define UI_ACLASSINFOPANE 259
-#define UI_AUPGRADEINFOPANE 260
-#define UI_HITEMINFOPANE 261
-#define UI_HBUYINFOPANE 262
-#define UI_HSELLINFOPANE 263
-#define UI_ABUILDINFOPANE 264
-#define UI_HBUILDINFOPANE 265
-
-#define UI_PLAYERLIST_SELECTION 266
-#define UI_TEAMLIST_SELECTION 267
-
-#define VOICECHAT_GETFLAG "getflag" // command someone to get the flag
-#define VOICECHAT_OFFENSE "offense" // command someone to go on offense
-#define VOICECHAT_DEFEND "defend" // command someone to go on defense
-#define VOICECHAT_DEFENDFLAG "defendflag" // command someone to defend the flag
-#define VOICECHAT_PATROL "patrol" // command someone to go on patrol (roam)
-#define VOICECHAT_CAMP "camp" // command someone to camp (we don't have sounds for this one)
-#define VOICECHAT_FOLLOWME "followme" // command someone to follow you
-#define VOICECHAT_RETURNFLAG "returnflag" // command someone to return our flag
-#define VOICECHAT_FOLLOWFLAGCARRIER "followflagcarrier" // command someone to follow the flag carrier
-#define VOICECHAT_YES "yes" // yes, affirmative, etc.
-#define VOICECHAT_NO "no" // no, negative, etc.
-#define VOICECHAT_ONGETFLAG "ongetflag" // I'm getting the flag
-#define VOICECHAT_ONOFFENSE "onoffense" // I'm on offense
-#define VOICECHAT_ONDEFENSE "ondefense" // I'm on defense
-#define VOICECHAT_ONPATROL "onpatrol" // I'm on patrol (roaming)
-#define VOICECHAT_ONCAMPING "oncamp" // I'm camping somewhere
-#define VOICECHAT_ONFOLLOW "onfollow" // I'm following
-#define VOICECHAT_ONFOLLOWCARRIER "onfollowcarrier" // I'm following the flag carrier
-#define VOICECHAT_ONRETURNFLAG "onreturnflag" // I'm returning our flag
-#define VOICECHAT_INPOSITION "inposition" // I'm in position
-#define VOICECHAT_IHAVEFLAG "ihaveflag" // I have the flag
-#define VOICECHAT_BASEATTACK "baseattack" // the base is under attack
-#define VOICECHAT_ENEMYHASFLAG "enemyhasflag" // the enemy has our flag (CTF)
-#define VOICECHAT_STARTLEADER "startleader" // I'm the leader
-#define VOICECHAT_STOPLEADER "stopleader" // I resign leadership
-#define VOICECHAT_TRASH "trash" // lots of trash talk
-#define VOICECHAT_WHOISLEADER "whoisleader" // who is the team leader
-#define VOICECHAT_WANTONDEFENSE "wantondefense" // I want to be on defense
-#define VOICECHAT_WANTONOFFENSE "wantonoffense" // I want to be on offense
diff --git a/ui/menus.txt b/ui/menus.txt
deleted file mode 100644
index 3fa3dcf..0000000
--- a/ui/menus.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-// menu defs
-//
-{
- loadMenu { "ui/main.menu" }
- loadMenu { "ui/joinserver.menu" }
- loadMenu { "ui/options.menu" }
- loadMenu { "ui/createserver.menu" }
- loadMenu { "ui/mod.menu" }
- loadMenu { "ui/credit.menu" }
- loadMenu { "ui/connect.menu" }
- loadMenu { "ui/password.menu" }
- loadMenu { "ui/quit.menu" }
- loadMenu { "ui/addfilter.menu" }
- loadMenu { "ui/error.menu" }
- loadMenu { "ui/drop.menu" }
- loadMenu { "ui/serverinfo.menu" }
- loadMenu { "ui/findplayer.menu" }
- loadMenu { "ui/quitcredit.menu" }
- loadMenu { "ui/createfavorite.menu" }
-}
diff --git a/ui/options.menu b/ui/options.menu
deleted file mode 100644
index c6cc01c..0000000
--- a/ui/options.menu
+++ /dev/null
@@ -1,287 +0,0 @@
-#include "ui/menudef.h"
-
-{
- \\ FRONT END OPTIONS BOX \\
-
- menuDef
- {
- name "simple_options"
- visible 0
- fullscreen 0
- rect 200 80 240 320
- focusColor 1 .75 0 1
- style 1
- border 1
- popup
- onEsc
- {
- close simple_options;
- open main
- }
-
- itemDef
- {
- name window
- rect 0 0 240 320
- style WINDOW_STYLE_FILLED
- backcolor 0 0 0 1
- visible 1
- decoration
-
- border WINDOW_BORDER_FULL
- borderSize 1.0
- borderColor 0.5 0.5 0.5 1
- }
-
-
-
- itemDef
- {
- type ITEM_TYPE_EDITFIELD
- style 0
- text "Name:"
- cvar "name"
- maxchars 26
- rect 50 20 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- }
-
- itemDef
- {
- type ITEM_TYPE_MULTI
- text "Video Quality:"
- cvar "ui_glCustom"
- cvarFloatList { "High Quality" 0 "Normal" 1 "Fast" 2 "Fastest" 3 "Custom" 4 }
- rect 50 45 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript update "ui_glCustom"
- }
- }
-
- itemDef
- {
- type ITEM_TYPE_MULTI
- text "Video Mode:"
- cvar "r_mode"
- cvarFloatList { "320x240" 0 "400x300" 1 "512x384" 2 "640x480" 3
- "800x600" 4 "960x720" 5 "1024x768" 6 "1152x864" 7
- "1280x1024" 8 "1600x1200" 9 "2048x1536" 10 "856x480 wide screen" 11 }
- rect 50 60 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript glCustom
- }
- }
-
- itemDef
- {
- type ITEM_TYPE_SLIDER
- text "Video Brightness:"
- cvarfloat "r_gamma" 1 .5 2
- rect 50 75 192 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- }
-
-
-
- itemDef
- {
- type ITEM_TYPE_SLIDER
- text "Effects Volume:"
- cvarfloat "s_volume" 0.7 0 1
- rect 50 110 192 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- }
-
- itemDef
- {
- type ITEM_TYPE_SLIDER
- text "Music Volume:"
- cvarfloat "s_musicvolume" 0.25 0 1
- rect 50 130 192 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- }
-
- itemDef
- {
- type ITEM_TYPE_YESNO
- text "OpenAL Sound:"
- cvar "s_useOpenAL"
- rect 50 145 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
-
-
- itemDef
- {
- type ITEM_TYPE_SLIDER
- text "Mouse Sensitivity:"
- cvarfloat "sensitivity" 5 1 30
- rect 50 175 192 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- }
-
- itemDef
- {
- type ITEM_TYPE_YESNO
- text "Invert Mouse:"
- cvar "ui_mousePitch"
- rect 50 190 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript update ui_mousePitch
- }
- }
-
-
-
- itemDef
- {
- type ITEM_TYPE_MULTI
- text "Network Connection:"
- cvar "rate"
- cvarFloatList { "<=28.8k" 2500 "33.6k" 3000 "56k" 4000 "ISDN" 5000 "LAN/CABLE/xDSl" 25000 }
- rect 50 220 192 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
- itemDef
- {
- type ITEM_TYPE_YESNO
- text "Allow Auto Download:"
- cvar "cl_allowDownload"
- rect 50 235 192 15
- textalign ITEM_ALIGN_RIGHT
- textalignx 64
- textaligny 12
- textscale .25
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- }
- }
-
-
- itemDef
- {
- text "APPLY"
- type ITEM_TYPE_BUTTON
- textscale .25
- style WINDOW_STYLE_EMPTY
- rect 95 255 30 20
- textalign ITEM_ALIGN_CENTER
- textalignx 15
- textaligny 15
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- exec "snd_restart" // includes vid_restart
- }
- }
-
- itemDef
- {
- text "OK"
- type ITEM_TYPE_BUTTON
- textscale .25
- style WINDOW_STYLE_EMPTY
- rect 125 255 20 20
- textalign ITEM_ALIGN_CENTER
- textalignx 10
- textaligny 15
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- close simple_options;
- }
- }
-
-
- itemDef
- {
- text "For further options please use the in-game options menu"
- style WINDOW_STYLE_EMPTY
- textstyle ITEM_TEXTSTYLE_NORMAL
- textscale .25
- rect 0 300 240 40
- textalign ITEM_ALIGN_CENTER
- textaligny 0
- textalignx 120
- forecolor 1 1 1 1
- visible 1
- decoration
- }
- }
-}
diff --git a/ui/say.menu b/ui/say.menu
deleted file mode 100644
index f6de3f9..0000000
--- a/ui/say.menu
+++ /dev/null
@@ -1,91 +0,0 @@
-#include "ui/menudef.h"
-
-{
-
-#define BORDER 10
-
-#define X BORDER
-#define Y BORDER
-//#define W (600-(2*BORDER))
-//#define H (480-(2*BORDER))
-#define W 580
-#define H 460
-
- // Say to All
- menuDef
- {
- name say
- fullScreen MENU_FALSE
- visible MENU_FALSE
- rect X Y W H
- //aspectBias ALIGN_LEFT
- focusColor 1 1 1 1
- style WINDOW_STYLE_EMPTY
- onOpen
- {
- setfocus say_field;
- }
-
- itemDef
- {
- name say_field
- type ITEM_TYPE_SAYFIELD
- style WINDOW_STYLE_EMPTY
- text "Say:"
- cvar "ui_sayBuffer"
- maxchars 128
- //rect 0 0 W H
- rect 0 230 W 20
- //textalign ALIGN_LEFT
- //textvalign VALIGN_CENTER
- textstyle ITEM_TEXTSTYLE_SHADOWED
- textscale .4
- forecolor 0.93 0.93 0.92 1
- visible MENU_TRUE
- onTextEntry
- {
- uiScript Say;
- close say;
- }
- }
- }
-
- // Say to Team
- menuDef
- {
- name say_team
- fullScreen MENU_FALSE
- visible MENU_FALSE
- rect X Y W H
- //aspectBias ALIGN_LEFT
- focusColor 1 1 1 1
- style WINDOW_STYLE_EMPTY
- onOpen
- {
- setfocus say_field
- }
-
- itemDef
- {
- name say_field
- type ITEM_TYPE_SAYFIELD
- style WINDOW_STYLE_EMPTY
- text "Say to team:"
- cvar "ui_sayBuffer"
- maxchars 128
- //rect 0 0 W H
- rect 0 230 W 20
- //textalign ALIGN_LEFT
- //textvalign VALIGN_CENTER
- textstyle ITEM_TEXTSTYLE_SHADOWED
- textscale .4
- forecolor 0.93 0.93 0.92 1
- visible MENU_TRUE
- onTextEntry
- {
- uiScript Say;
- close say_team;
- }
- }
- }
-}
diff --git a/ui/teamscore.menu b/ui/teamscore.menu
deleted file mode 100644
index a0dad01..0000000
--- a/ui/teamscore.menu
+++ /dev/null
@@ -1,305 +0,0 @@
-#include "ui/menudef.h"
-
-{
- \\ score_menu \\
-
- menuDef
- {
- name "teamscore_menu"
- visible 0
- fullscreen 0
- rect 0 0 640 480
- focusColor 1 .75 0 1
- style 0
- border 1
-
- // GAMETYPE BAR //
-
- // TEAM NAME //
-
- itemDef
- {
- name teamNameWindow
- rect 14 78 612 30
- style WINDOW_STYLE_FILLED
- border 1
- bordercolor .5 .5 .5 1
- forecolor 1 1 1 1
- backcolor 0 0 0 .5
- visible 1
- decoration
- }
-
- itemDef
- {
- name alienteamname
- text "Aliens"
- textalign ITEM_ALIGN_LEFT
- textscale .5
- textaligny 26
- rect 20 78 306 23
- forecolor 1 1 1 1
- decoration
- visible 1
- }
-
- itemDef
- {
- name stagereport
- align ITEM_ALIGN_CENTER
- textscale 0.4
- textaligny 24
- rect 14 78 612 23
- forecolor 1 1 1 1
- decoration
- visible 1
- ownerdraw CG_STAGE_REPORT_TEXT
- }
-
- itemDef
- {
- name humanteamname
- text "Humans"
- textalign ITEM_ALIGN_RIGHT
- textscale .5
- textaligny 26
- rect 620 78 0 23
- forecolor 1 1 1 1
- decoration
- visible 1
- }
-
- // TEAM BARS //
-
- itemDef
- {
- name leftteambar
- rect 14 112 307 25
- style WINDOW_STYLE_FILLED
- border 1
- bordercolor .5 .5 .5 1
- forecolor 1 1 1 1
- backcolor 0 0 0 .5
- visible 1
- decoration
- }
-
- itemDef
- {
- name rightteambar
- rect 320 112 306 25
- style WINDOW_STYLE_FILLED
- border 1
- bordercolor .5 .5 .5 1
- forecolor 1 1 1 1
- backcolor 0 0 0 .5
- visible 1
- decoration
- }
-
-
- // TEAM HEADINGS //
-
- itemDef
- {
- name leftteamheadings
- text "Status Name Kills Time Ping"
- textscale .25
- style 0
- rect 25 112 128 30
- textalign 0
- textalignx 0 // x alignment point for text
- // use it to offset left/right text from the edge
- // or to center the text on a different point
- textaligny 18
- backcolor 0 0 0 0
- forecolor 1 .75 0 1
- decoration
- visible 1
- }
-
- itemDef
- {
- name rightteamheadings
- text "Status Name Kills Time Ping"
- textscale .25
- style 0
- rect 331 112 128 30
- textalign 0
- textalignx 0 // x alignment point for text
- // use it to offset left/right text from the edge
- // or to center the text on a different point
- textaligny 18
- backcolor 0 0 0 0
- forecolor 1 .75 0 1
- decoration
- visible 1
- }
-
-
- // GRADIENT BACKGROUNDS //
-
- itemDef
- {
- name window
- rect 320 142 1 220
- style WINDOW_STYLE_FILLED
- border 1
- bordercolor .5 .5 .5 1
- forecolor 1 1 1 1
- backcolor 0 0 0 1
- visible 1
- decoration
- }
-
- itemDef
- {
- name window
- rect 300 142 1 220
- style WINDOW_STYLE_FILLED
- border 1
- bordercolor .5 .5 .5 1
- visible 1
- decoration
- }
-
- itemDef
- {
- name window
- rect 606 142 1 220
- style WINDOW_STYLE_FILLED
- border 1
- bordercolor .5 .5 .5 1
- visible 1
- decoration
- }
-
-
- // LIST //
-
- itemDef
- {
- name leftlist
- rect 14 136 306 222
- forecolor .75 .75 .75 1
- visible 1
- type ITEM_TYPE_LISTBOX
- elementwidth 135
- elementheight 20
- textscale .25
- elementtype LISTBOX_TEXT
- feeder FEEDER_ALIENTEAM_LIST
- notselectable
- columns 7
- 5 15 1 ITEM_ALIGN_LEFT
- 21 15 1 ITEM_ALIGN_LEFT
- 7 30 5 ITEM_ALIGN_LEFT
- 45 100 24 ITEM_ALIGN_LEFT
- 172 20 4 ITEM_ALIGN_RIGHT
- 209 20 4 ITEM_ALIGN_RIGHT
- 247 20 4 ITEM_ALIGN_RIGHT
- }
-
- itemDef
- {
- name rightlist
- rect 320 136 306 222
- forecolor 1 1 1 1
- visible 1
- type ITEM_TYPE_LISTBOX
- elementwidth 135
- elementheight 20
- textscale .25
- elementtype LISTBOX_TEXT
- feeder FEEDER_HUMANTEAM_LIST
- notselectable
- columns 7
- 5 15 1 ITEM_ALIGN_LEFT
- 21 15 1 ITEM_ALIGN_LEFT
- 7 30 5 ITEM_ALIGN_LEFT
- 45 100 24 ITEM_ALIGN_LEFT
- 172 20 4 ITEM_ALIGN_RIGHT
- 209 20 4 ITEM_ALIGN_RIGHT
- 247 20 4 ITEM_ALIGN_RIGHT
- }
-
-
- // PLAYER LIST BORDER //
-
- itemDef
- {
- name window
- rect 14 141 612 221
- style WINDOW_STYLE_EMPTY
- border 1
- bordercolor .5 .5 .5 1
- forecolor 1 1 1 1
- backcolor 0 0 0 .5
- visible 1
- decoration
- }
-
-
- // spectators //
-
- itemDef
- {
- name window
- rect 14 366 612 24
- style WINDOW_STYLE_FILLED
- border 1
- bordercolor .5 .5 .5 1
- forecolor 1 1 1 .7
- backcolor 0 0 0 .5
- textscale .33
- visible 1
- decoration
- }
-
- itemDef
- {
- name window
- text "Spectating:"
- textaligny 20
- rect 19 366 82 24
- style WINDOW_STYLE_FILLED
- forecolor 1 1 1 1
- textscale .33
- textalignx 3
- visible 1
- decoration
- }
-
- itemDef
- {
- name window
- rect 100 366 520 24
- style WINDOW_STYLE_FILLED
- forecolor 1 1 1 1
- textscale .33
- visible 1
- ownerdraw CG_SPECTATORS
- decoration
- }
-
- // WINNAR //
-
- itemDef
- {
- name winner
- rect 310 400 612 40
- type 4
- style 0
- text ""
- cvar ui_winner
- maxPaintChars 24
- textalign ITEM_ALIGN_CENTER
- textaligny 20
- textscale .5
- forecolor 1 1 1 1
- visible 1
- decoration
- }
-
- }
-}
diff --git a/ui/tremulous_alien_builder_hud.menu b/ui/tremulous_alien_builder_hud.menu
deleted file mode 100644
index bf75327..0000000
--- a/ui/tremulous_alien_builder_hud.menu
+++ /dev/null
@@ -1,371 +0,0 @@
-#include "ui/menudef.h"
-
-// team menu
-//
-// defines from ui_shared.h
-
-{
- menuDef
- {
- name "alien_builder_hud"
- fullScreen MENU_FALSE
- visible MENU_TRUE
- rect 0 0 640 480
-
- //CONSOLE
- itemDef
- {
- name "console"
- rect 8 8 560 180
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- align ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 18
- textscale 0.4
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_CONSOLE
- }
-
- //TUTORIAL
- itemDef
- {
- name "tutorial"
- rect 8 250 640 180
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 0.35
- align ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_TUTORIAL
- }
-
- //LAGOMETER
- itemDef
- {
- name "lagometer"
- rect 596 68 32 20
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 0 0 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_LAGOMETER
- }
-
- //DEMO STATE
- itemDef
- {
- name "demoRecording"
- rect 596 120 32 32
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 0 0 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_DEMO_RECORDING
- background "ui/assets/neutral/circle.tga"
- }
- itemDef
- {
- name "demoPlayback"
- rect 596 120 32 32
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_DEMO_PLAYBACK
- background "ui/assets/forwardarrow.tga"
- }
-
- //SELECT
- itemDef
- {
- name "select"
- rect 240 435 160 32
- visible 0
- decoration
- ownerdraw CG_PLAYER_SELECT
- }
-
- //////////////////
- //STATIC OBJECTS//
- //////////////////
-
- //LEFT RING CIRCLE
- itemDef
- {
- name "left-ring-circle"
- rect 47.5 410 25 25
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/neutral/circle.tga"
- }
-
- //LEFT ARM
- itemDef
- {
- name "left-arm"
- rect 77 404.75 104 52.5
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/alien/left-arm.tga"
- }
-
- //LEFT ARM CIRCLE
- itemDef
- {
- name "left-arm-circle"
- rect 150 417.5 25 25
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/neutral/circle.tga"
- }
-
- //RIGHT RING CIRCLE
- itemDef
- {
- name "right-ring-circle"
- rect 567 410 25 25
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/neutral/circle.tga"
- }
-
- //RIGHT ARM
- itemDef
- {
- name "right-arm"
- rect 459 404.75 104 52.5
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/alien/right-arm.tga"
- }
-
- ///////////////////
- //DYNAMIC OBJECTS//
- ///////////////////
-
- //BOLT
- itemDef
- {
- name "bolt"
- rect 52.5 412.5 15 20
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.5
- background "ui/assets/alien/bolt.tga"
- ownerdraw CG_PLAYER_BOOST_BOLT
- }
-
- //CROSS
- itemDef
- {
- name "cross"
- rect 155 422.5 15 15
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.5
- style WINDOW_STYLE_SHADER
- background "ui/assets/neutral/cross.tga"
- }
-
- //LEFT RING
- itemDef
- {
- name "left-ring"
- rect 7.25 369.5 90.5 106
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.5
- background "ui/assets/alien/left-ring.tga"
- ownerdraw CG_PLAYER_BOOSTED
- }
-
- //LEFT SPIKES
- itemDef
- {
- name "left-spikes"
- rect 18.5 381 59 83
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 1.0
- background "ui/assets/alien/left-spikes.tga"
- ownerdraw CG_PLAYER_WALLCLIMBING
- }
-
- //RIGHT RING
- itemDef
- {
- name "right-ring"
- rect 542.25 369.5 90.5 106
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.5
- background "ui/assets/alien/right-ring.tga"
- ownerdraw CG_PLAYER_BOOSTED
- }
-
- //RIGHT SPIKES
- itemDef
- {
- name "right-spikes"
- rect 562.5 381 59 83
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 1.0
- background "ui/assets/alien/right-spikes.tga"
- ownerdraw CG_PLAYER_WALLCLIMBING
- }
-
- //HEALTH
- itemDef
- {
- name "health"
- rect 78.5 421.5 60 15
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 .5
- ownerdraw CG_PLAYER_HEALTH
- }
-
- //ALIEN CLASS ICON
- itemDef
- {
- name "alien-icon"
- rect 465 417.5 25 25
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.6
- ownerdraw CG_PLAYER_WEAPONICON
- }
-
- //ORGANS
- itemDef
- {
- name "organs"
- rect 570.5 415.95 15 15
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 .5
- ownerdraw CG_PLAYER_CREDITS_VALUE_NOPAD
- }
-
- //BUILD TIMER
- itemDef
- {
- name "buildtimer"
- rect 567 410 25 25
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 .5
- ownerdraw CG_PLAYER_BUILD_TIMER
- }
-
- //BUILD POINTS
- itemDef
- {
- name "build-points"
- rect 483.5 421.5 60 15
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 .5
- ownerdraw CG_PLAYER_AMMO_VALUE
- }
-
- //FPS
- itemDef
- {
- name "fps"
- rect 572 8 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_FPS
- }
-
- //TIMER
- itemDef
- {
- name "timer"
- rect 572 38 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_TIMER
- }
-
- //CLOCK
- itemDef
- {
- name "clock"
- rect 572 90 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.25
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_CLOCK
- }
-
- //ALIENSENSE
- itemDef
- {
- name "aliensense"
- rect 20 20 600 400
- visible 1
- decoration
- ownerdraw CG_PLAYER_ALIEN_SENSE
- }
-
- //PLAYER NAME
- itemDef
- {
- name "playername"
- rect 200 275 240 25
- visible 1
- decoration
- textScale .5
- ownerdraw CG_PLAYER_CROSSHAIRNAMES
- }
- }
-}
diff --git a/ui/tremulous_alien_general_hud.menu b/ui/tremulous_alien_general_hud.menu
deleted file mode 100644
index cc81600..0000000
--- a/ui/tremulous_alien_general_hud.menu
+++ /dev/null
@@ -1,360 +0,0 @@
-#include "ui/menudef.h"
-
-// team menu
-//
-// defines from ui_shared.h
-
-{
- menuDef
- {
- name "alien_general_hud"
- fullScreen MENU_FALSE
- visible MENU_TRUE
- rect 0 0 640 480
-
- //CONSOLE
- itemDef
- {
- name "console"
- rect 8 8 560 180
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- align ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 18
- textscale 0.4
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_CONSOLE
- }
-
- //TUTORIAL
- itemDef
- {
- name "tutorial"
- rect 8 250 640 180
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 0.35
- align ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_TUTORIAL
- }
-
- //LAGOMETER
- itemDef
- {
- name "lagometer"
- rect 596 68 32 20
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 0 0 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_LAGOMETER
- }
-
- //DEMO STATE
- itemDef
- {
- name "demoRecording"
- rect 596 120 32 32
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 0 0 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_DEMO_RECORDING
- background "ui/assets/neutral/circle.tga"
- }
- itemDef
- {
- name "demoPlayback"
- rect 596 120 32 32
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_DEMO_PLAYBACK
- background "ui/assets/forwardarrow.tga"
- }
-
- //SELECT
- itemDef
- {
- name "select"
- rect 240 435 160 32
- visible 0
- decoration
- ownerdraw CG_PLAYER_SELECT
- }
-
- //////////////////
- //STATIC OBJECTS//
- //////////////////
-
- //LEFT RING CIRCLE
- itemDef
- {
- name "left-ring-circle"
- rect 47.5 410 25 25
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/neutral/circle.tga"
- }
-
- //LEFT ARM
- itemDef
- {
- name "left-arm"
- rect 77 404.75 104 52.5
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/alien/left-arm.tga"
- }
-
- //LEFT ARM CIRCLE
- itemDef
- {
- name "left-arm-circle"
- rect 150 417.5 25 25
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/neutral/circle.tga"
- }
-
- //RIGHT RING CIRCLE
- itemDef
- {
- name "right-ring-circle"
- rect 567 410 25 25
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/neutral/circle.tga"
- }
-
- //RIGHT ARM
- itemDef
- {
- name "right-arm"
- rect 459 404.75 104 52.5
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/alien/right-arm.tga"
- }
-
- ///////////////////
- //DYNAMIC OBJECTS//
- ///////////////////
-
- //BLOB
- itemDef
- {
- name "blob"
- rect 479 419 57 18
- visible 1
- forecolor 1.0 0.0 0.0 0.5
- background "ui/assets/alien/tremublob.tga"
- ownerdraw CG_PLAYER_POISON_BARBS
- }
-
- //BOLT
- itemDef
- {
- name "bolt"
- rect 52.5 412.5 15 20
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.5
- background "ui/assets/alien/bolt.tga"
- ownerdraw CG_PLAYER_BOOST_BOLT
- }
-
- //CROSS
- itemDef
- {
- name "cross"
- rect 155 422.5 15 15
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.5
- style WINDOW_STYLE_SHADER
- background "ui/assets/neutral/cross.tga"
- }
-
- //LEFT RING
- itemDef
- {
- name "left-ring"
- rect 7.25 369.5 90.5 106
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.5
- background "ui/assets/alien/left-ring.tga"
- ownerdraw CG_PLAYER_BOOSTED
- }
-
- //LEFT SPIKES
- itemDef
- {
- name "left-spikes"
- rect 18.5 381 59 83
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 1.0
- background "ui/assets/alien/left-spikes.tga"
- ownerdraw CG_PLAYER_WALLCLIMBING
- }
-
- //RIGHT RING
- itemDef
- {
- name "right-ring"
- rect 542.25 369.5 90.5 106
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.5
- background "ui/assets/alien/right-ring.tga"
- ownerdraw CG_PLAYER_BOOSTED
- }
-
- //RIGHT SPIKES
- itemDef
- {
- name "right-spikes"
- rect 562.5 381 59 83
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 1.0
- background "ui/assets/alien/right-spikes.tga"
- ownerdraw CG_PLAYER_WALLCLIMBING
- }
-
- //HEALTH
- itemDef
- {
- name "health"
- rect 78.5 421.5 60 15
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 .5
- ownerdraw CG_PLAYER_HEALTH
- }
-
- //ALIEN CLASS ICON
- itemDef
- {
- name "alien-icon"
- rect 465 417.5 25 25
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 0.6
- ownerdraw CG_PLAYER_WEAPONICON
- }
-
- //ORGANS
- itemDef
- {
- name "organs"
- rect 570.5 415.95 15 15
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 .5
- ownerdraw CG_PLAYER_CREDITS_VALUE_NOPAD
- }
-
- //FPS
- itemDef
- {
- name "fps"
- rect 572 8 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_FPS
- }
-
- //TIMER
- itemDef
- {
- name "timer"
- rect 572 38 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_TIMER
- }
-
- //CLOCK
- itemDef
- {
- name "clock"
- rect 572 90 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1.0 0.0 0.0 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.25
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_CLOCK
- }
-
- //ALIENSENSE
- itemDef
- {
- name "aliensense"
- rect 20 20 600 400
- visible 1
- decoration
- ownerdraw CG_PLAYER_ALIEN_SENSE
- }
-
- //PLAYER NAME
- itemDef
- {
- name "playername"
- rect 200 275 240 25
- visible 1
- decoration
- textScale .5
- ownerdraw CG_PLAYER_CROSSHAIRNAMES
- }
- }
-}
diff --git a/ui/tremulous_default_hud.menu b/ui/tremulous_default_hud.menu
deleted file mode 100644
index 0eed640..0000000
--- a/ui/tremulous_default_hud.menu
+++ /dev/null
@@ -1,165 +0,0 @@
-#include "ui/menudef.h"
-
-{
- menuDef
- {
- name "default_hud"
- fullScreen MENU_FALSE
- visible MENU_TRUE
- rect 0 0 640 480
-
- //CONSOLE
- itemDef
- {
- name "console"
- rect 8 8 560 180
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- align ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 18
- textscale 0.4
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_CONSOLE
- }
-
- //TUTORIAL
- itemDef
- {
- name "tutorial"
- rect 8 250 640 180
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 0.35
- align ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_TUTORIAL
- }
-
- //FPS
- itemDef
- {
- name "fps"
- rect 572 8 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_FPS
- }
- //TIMER
- itemDef
- {
- name "timer"
- rect 572 38 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_TIMER
- }
- //CLOCK
- itemDef
- {
- name "clock"
- rect 572 90 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.25
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_CLOCK
- }
-
- //SNAPSHOT
- itemDef
- {
- name "snapshot"
- rect 8 196 200 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.4
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_SNAPSHOT
- }
- //LAGOMETER
- itemDef
- {
- name "lagometer"
- rect 596 68 32 20
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_LAGOMETER
- }
- //DEMO STATE
- itemDef
- {
- name "demoRecording"
- rect 596 120 32 32
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 0 0 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_DEMO_RECORDING
- background "ui/assets/neutral/circle.tga"
- }
- itemDef
- {
- name "demoPlayback"
- rect 596 120 32 32
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_DEMO_PLAYBACK
- background "ui/assets/forwardarrow.tga"
- }
-
- //PLAYER NAME
- itemDef
- {
- name "playername"
- rect 200 275 240 25
- visible 1
- decoration
- textScale .5
- ownerdraw CG_PLAYER_CROSSHAIRNAMES
- }
- }
-}
diff --git a/ui/tremulous_human_hud.menu b/ui/tremulous_human_hud.menu
deleted file mode 100644
index 8fe0095..0000000
--- a/ui/tremulous_human_hud.menu
+++ /dev/null
@@ -1,462 +0,0 @@
-#include "ui/menudef.h"
-
-// team menu
-//
-// defines from ui_shared.h
-
-{
- menuDef
- {
- name "human_hud"
- fullScreen MENU_FALSE
- visible MENU_TRUE
- rect 0 0 640 480
-
- //CONSOLE
- itemDef
- {
- name "console"
- rect 8 8 560 180
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- align ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 18
- textscale 0.4
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_CONSOLE
- }
-
- //TUTORIAL
- itemDef
- {
- name "tutorial"
- rect 8 250 640 180
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 0.35
- align ITEM_ALIGN_LEFT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_TUTORIAL
- }
-
- //LAGOMETER
- itemDef
- {
- name "lagometer"
- rect 596 68 32 20
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 0 0.8 1 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_LAGOMETER
- }
-
- //DEMO STATE
- itemDef
- {
- name "demoRecording"
- rect 596 120 32 32
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 0 0 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_DEMO_RECORDING
- background "ui/assets/neutral/circle.tga"
- }
- itemDef
- {
- name "demoPlayback"
- rect 596 120 32 32
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- textscale 0.3
- textalignx 1
- textaligny 0.5
- ownerdraw CG_DEMO_PLAYBACK
- background "ui/assets/forwardarrow.tga"
- }
-
- //FPS
- itemDef
- {
- name "fps"
- rect 572 8 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_FPS
- }
-
- //TIMER
- itemDef
- {
- name "timer"
- rect 572 38 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.3
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_TIMER
- }
-
- //CLOCK
- itemDef
- {
- name "clock"
- rect 572 90 56 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.25
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_CLOCK
- }
-
- //SNAPSHOT
- itemDef
- {
- name "snapshot"
- rect 8 196 200 22
- style WINDOW_STYLE_EMPTY
- visible 1
- decoration
- forecolor 1 1 1 1
- align ITEM_ALIGN_RIGHT
- textalignx 0
- textaligny 18
- textscale 0.4
- textstyle ITEM_TEXTSTYLE_NORMAL
- ownerdraw CG_SNAPSHOT
- }
-
- //////////////////
- //STATIC OBJECTS//
- //////////////////
-
- //LEFT CIRCLE
- itemDef
- {
- name "left-circle"
- rect 35 417.5 25 25
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/neutral/circle.tga"
- }
-
- //LEFT ARM
- itemDef
- {
- name "left-arm"
- rect 68.25 420 94.5 35
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/human/left-arm.tga"
- }
-
- //CREDITS LABEL
- itemDef
- {
- name "credits-label"
- rect 508 403 7 7.5
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.5
- style WINDOW_STYLE_SHADER
- background "ui/assets/human/credits.tga"
- }
-
- //RIGHT CIRCLE
- itemDef
- {
- name "right-circle"
- rect 580 417.5 25 25
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/neutral/circle.tga"
- }
-
- //RIGHT ARM
- itemDef
- {
- name "right-arm"
- rect 477.25 420 94.5 35
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/human/right-arm.tga"
- }
-
- //RIGHT CAP
- itemDef
- {
- name "right-cap"
- rect 500 400 80 15
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/human/right-cap.tga"
- }
-
- ///////////////////
- //DYNAMIC OBJECTS//
- ///////////////////
-
- //BOLT
- itemDef
- {
- name "bolt"
- rect 40 420 15 20
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.5
- background "ui/assets/human/bolt.tga"
- ownerdraw CG_PLAYER_STAMINA_BOLT
- }
-
- //CROSS
- itemDef
- {
- name "cross"
- rect 137.5 430 15 15
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.5
- background "ui/assets/neutral/cross.tga"
- ownerdraw CG_PLAYER_HEALTH_CROSS
- }
-
- //STAMINA 1
- itemDef
- {
- name "stamina1"
- rect 34.5 403.5 9 11.5
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.5
- background "ui/assets/human/stamina1.tga"
- ownerdraw CG_PLAYER_STAMINA_1
- }
-
- //STAMINA 2
- itemDef
- {
- name "stamina2"
- rect 24 410.75 11.5 10.5
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.5
- background "ui/assets/human/stamina2.tga"
- ownerdraw CG_PLAYER_STAMINA_2
- }
-
- //STAMINA 3
- itemDef
- {
- name "stamina3"
- rect 20.75 423.5 10.5 7
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.5
- background "ui/assets/human/stamina3.tga"
- ownerdraw CG_PLAYER_STAMINA_3
- }
-
- //STAMINA 4
- itemDef
- {
- name "stamina4"
- rect 21 402.5 54 55
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.5
- background "ui/assets/human/stamina4.tga"
- ownerdraw CG_PLAYER_STAMINA_4
- }
-
- //RING
- itemDef
- {
- name "ring"
- // rect 20 402.5 55 55 // Guide for Stamina alignment
- rect 565 402.5 55 55
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.5
- background "ui/assets/human/ring.tga"
- ownerdraw CG_PLAYER_CLIPS_RING
- }
-
- //CREDITS
- itemDef
- {
- name "credits"
- rect 515 402 45 11.25
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.5
- ownerdraw CG_PLAYER_CREDITS_VALUE
- }
-
- //HEALTH
- itemDef
- {
- name "health"
- rect 67 430 60 15
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 .5
- ownerdraw CG_PLAYER_HEALTH
- }
-
- //WEAPON ICON
- itemDef
- {
- name "weapon"
- rect 482.5 425 25 25
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.5
- ownerdraw CG_PLAYER_WEAPONICON
- }
-
- //WEAPON SELECT TEXT
- itemDef
- {
- name "selecttext"
- rect 200 300 240 25
- visible 1
- decoration
- textScale .5
- ownerdraw CG_PLAYER_SELECTTEXT
- }
-
- //AMMO
- itemDef
- {
- name "ammo"
- rect 494 430 60 15
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 .5
- ownerdraw CG_PLAYER_AMMO_VALUE
- }
-
- //CLIPS
- itemDef
- {
- name "clips"
- rect 538 423 60 15
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 .5
- ownerdraw CG_PLAYER_CLIPS_VALUE
- }
-
- //BUILD TIMER
- itemDef
- {
- name "buildtimer"
- rect 580 417.5 25 25
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 .5
- ownerdraw CG_PLAYER_BUILD_TIMER
- }
-
- //USABLE
- itemDef
- {
- name "usable"
- rect 307.5 380 25 25
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 .5
- background "ui/assets/neutral/use.tga"
- ownerdraw CG_PLAYER_USABLE_BUILDABLE
- }
-
- //SCANNER
- itemDef
- {
- name "scanner"
- rect 164 340 312 72
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 .5
- background "ui/assets/human/scanner.tga"
- ownerdraw CG_PLAYER_HUMAN_SCANNER
- }
-
- //INVENTORY
- itemDef
- {
- name "inventory"
- rect 232.5 425 175 25
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.5
- ownerdraw CG_PLAYER_SELECT
- }
-
- //SELECTED
- itemDef
- {
- name "selected"
- rect 306 424 27 27
- visible 1
- decoration
- forecolor 0.0 0.8 1.0 0.25
- style WINDOW_STYLE_SHADER
- background "ui/assets/neutral/selected.tga"
- }
-
- //PLAYER NAME
- itemDef
- {
- name "playername"
- rect 200 275 240 25
- visible 1
- decoration
- textScale .5
- ownerdraw CG_PLAYER_CROSSHAIRNAMES
- }
- }
-}